我编写了一组组件,这些组件通过发布的接口属性相互链接。它们在设计包中注册和安装。在 Delphi 中使用发布的接口属性并不常见,因此不出所料,似乎并不起作用。当组件位于同一窗体上时,它可以正常工作,但是在不同窗体之间的接口属性链接会导致问题。与在另一个窗体上链接到组件的对象链接不同,IDE 似乎无法识别界面链接。我的意思最好用一个例子来描述,当你在 IDE 中打开 2 个窗体,并在它们之间链接组件时,尝试切换到窗体视图作为文本(Alt+F12)将导致 IDE 正确地抱怨:
Module 'UnitXXX.pas' has open descendents or linked modules. Cannot close.
,但如果属性是一个接口,则不会发生这种情况,相反,链接将被切断(如果使用通知机制来清除引用,则这是最佳情况,否则您将得到一个无效指针)。另一个问题,很可能是由于同一个 bug 的后果,当你在 IDE 中打开项目时,窗体重新打开的顺序是未定义的,因此 IDE 可能会尝试打开包含链接到另一个窗体上组件的窗体,但该窗体尚未重新创建。因此,这实际上导致 AV 或已切断的链接。Dataset
和 Datasource
在 90 年代使用时,我记得类似问题的链接会消失,因此这有些相似。作为临时解决办法,我添加了重复的发布属性,对于每个接口属性,我添加了另一个声明为 TComponent
的属性。这使 Delphi 意识到窗体之间存在链接,但至少是一个丑陋的解决办法。因此,我想知道是否有什么方法可以解决这个问题?这是一个 IDE bug,很可能无法直接修复,但也许我可以覆盖某些东西或以其他方式钩入流媒体机制,以更有效地解决这个 bug。我从来没有深入研究过流媒体机制,但我怀疑 Fixup 机制应该处理这个问题。有一个 csFixups
TComponentState
,所以我希望有可能进行一些解决办法。更新:在 http://www.filedropper.com/fixupbugproject2 上上传了新的可重现示例。添加了 property ComponentReference: TComponent
,因此可以轻松比较和跟踪接口与组件流。我把问题缩小到了汇编级别,这有点超出我的深度。在 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;
正如您从评论中看到的那样,我发现避免抛出异常的唯一方法是不给结果赋值,但这破坏了功能性,因为在 GlobalFixupReferences
中上面的比较失败了,由于 GetOrdProp <> 0
,这会断开链接。
追踪更深入的异常位置在
system
单元中的 procedure _IntfCopy(var Dest: IInterface; const Source: IInterface);
中
特别是这一行引发了一个 read of address 0x80000000
异常
{ Now we're into the less common cases. }
@@NilSource:
MOV ECX, [EAX] // get current value
所以,为什么MOV
失败了,ECX
或EAX
出了什么问题我不知道。
GetOrdProp
不喜欢带有getter函数的属性。如果你将property InterfaceReference ... read GetInterfaceReference
更改为property InterfaceReference ... read FInterfaceReference
,AV就会消失。 - Jens Mühlenhoff