使用已发布的接口属性在Delphi中并不常见,因此,不出所料,似乎没有那么好。
当组件位于同一表单上时,它工作正常,但是不同表单上组件之间的接口属性链接会导致问题。
与对象链接到另一个表单上的组件不同,IDE似乎无法识别接口链接。我的意思是最好的一个例子,当你有两个窗体在IDE中打开,并有组件之间的链接,然后试图切换到文本形式视图(Alt F12)将导致IDE正确地抱怨:
模块“UnitXXX.pas”具有打开的后代或链接的模块。无法关闭。
但是如果属性是一个接口,这不会发生,而是发生了什么,是链接被切断(这是最好的情况下,当你使用通知机制来清除引用,否则你留下一个无效的指针)
另一个问题,可能是由于同一个错误的结果,当你在IDE中打开一个项目时,窗体将重新打开的顺序是未定义的,因此IDE可以尝试打开一个包含组件的组件的组件,另一种形式,但是其他形式没有重新创建。所以这有效地导致AV或切断链接。
回到90年代,当我使用数据集和数据源我记得类似的问题之间的链接消失,所以这有点类似。
作为临时解决方法,我添加了重复的已发布属性,对于每个接口属性,我添加了另一个声明为TComponent。这使得Delphi意识到在表单之间有一个链接,但是是一个丑陋的解决方法,至少说。
所以我不知道有没有什么我可以做的来解决这个问题?这是一个IDE错误,可能无法直接修复,但也许我可以重写一些东西,否则钩到流机制,以更有效地解决这个错误。
我从来没有这么深入流机制,但我怀疑Fixup机制应该处理这一点。有一个csFixups TComponentState所以我希望一个解决方法是可能的。
编辑:使用D2007。
更新:
新更新的可重复示例已上传到http://www.filedropper.com/fixupbugproject2
添加了属性ComponentReference:TComponent,以便于比较和跟踪接口与组件流。
我把问题缩小到了我的深度以外的汇编水平。
在过程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;
正如你可以从注释中看到的,我发现避免异常的唯一方法是保留结果未分配,但打破了功能,因为上面的比较GlobalFixupReferences失败,由于GetOrdProp<> 0,它断开了链接。
跟踪更准确的位置的异常是在
procedure _IntfCopy(var Dest:IInterface; const Source:IInterface);在系统单元中
这一行特别引发读地址0x80000000
{ Now we're into the less common cases. } @@NilSource: MOV ECX,[EAX] // get current value
所以,为什么MOV失败,什么错误ECX或EAX我不知道。