发布的接口属性错误和解决方法
我写了一组通过发布的接口属性相互链接的组件。 他们被注册并安装在一个devise包中。
在Delphi中使用已发布的接口属性并不常见,因此毫不奇怪,似乎并不能很好地工作。
当组件驻留在同一个表单上时它工作正常,但是不同表单上的组件之间的接口属性链接会导致问题。
与另一个表单上组件的对象链接不同,接口链接似乎无法被IDE识别。 我的意思是最好用一个例子来描述,当你在IDE中打开两个窗体,并在它们之间有组件之间的链接,然后尝试切换到窗体视图为文本(Alt + F12)将导致IDE正确地抱怨:
Module 'UnitXXX.pas' has open descendents or linked modules. Cannot close.
但是,如果属性是一个接口,那么这不会发生,反而会发生链接被切断(当使用Notification机制来清除引用时,这是最好的情况,否则你会留下一个无效的指针)
另一个问题,可能是由于相同的错误造成的结果是,当您在IDE中打开一个项目时,表单将被重新打开的顺序是未定义的,因此IDE可以尝试打开一个窗体,其中包含组件的接口链接另一种forms,但其他forms尚未重新创build。 所以这有效地导致AV或切断的链接。
早在90年代,当我使用Datasets
和Datasources
我记得类似的问题与表单之间的链接消失,所以这有些类似。
作为临时替代方法,我添加了重复的发布属性,对于每个接口属性,我添加了另一个声明为TComponent
。 这使delphi意识到forms之间有联系,但至less可以说是一个丑陋的解决方法。
所以我想知道我能做些什么来解决这个问题? 这是一个IDE错误,可能无法直接解决,但也许我可以重写某些东西或以其他方式挂接到stream式机制,以更有效地解决此问题。
我从来没有深入到stream式机制,但我怀疑Fixup机制应该处理这个问题。 有一个csFixups
所以我希望有一个解决方法是可能的。
编辑:使用D2007 。
更新:
新的更新可重复的例子上传到http://www.filedropper.com/fixupbugproject2
添加了property ComponentReference: TComponent
以便于比较和跟踪接口与组件stream。
我把问题缩小到汇编层面,这有点超出我的深度。
在它调用的classes
单位过程GlobalFixupReferences
中:
(GetOrdProp(FInstance, FPropInfo) <> 0)
最终执行:
function TInterfacedComponent.GetInterfaceReference: IInterface; begin // uncomment the code bellow to avoid exception { if (csLoading in ComponentState) and (FInterfaceReference = nil) then // leave result unassigned to avoid exception else } result := FInterfaceReference; // <----- Exception happens here end;
正如你从注释中看到的,我发现避免exception的唯一方法是将结果保留为未赋值,但由于GetOrdProp <> 0
,导致GlobalFixupReferences
比较失败,从而导致function中断。
更深入地追踪exception的更确切位置
procedure _IntfCopy(var Dest: IInterface; const Source: IInterface);
在system
单元中
这条线特别引起read of address 0x80000000
的read of address 0x80000000
{ Now we're into the less common cases. } @@NilSource: MOV ECX, [EAX] // get current value
那么,为什么MOV
失败, ECX
或EAX
有什么问题我不知道。
总而言之,问题只发生在具有getter方法的发布接口属性上,并且该属性指向另一个表单/模块上的组件(并且该表单/模块尚未重新创build)。 在这种情况下,恢复formsDFM导致AV。
我很确定这个错误是在GetOrdProp
的ASM代码中,但是我无法修复,所以最简单的解决方法是使用Field而不是getter方法,直接在属性中读取。 幸运的是,目前我的情况已经够好了。
或者,可以将属性声明为TComponent
而不是接口,然后编写TComponentProperty
后代,重写ComponentMayBeSetTo
以过滤不支持所需接口的组件。 当然,使用RegisterPropertyEditor
进行RegisterPropertyEditor