已发布的接口属性错误和解决方法
Posted
技术标签:
【中文标题】已发布的接口属性错误和解决方法【英文标题】:Published interface properties bug and workarounds 【发布时间】:2013-04-21 03:34:30 【问题描述】:我编写了一组通过发布的接口属性相互链接的组件。它们已注册并安装在设计包中。
使用已发布的接口属性在 Delphi 中并不常见,因此,不出所料,似乎效果不佳。
当组件驻留在同一个表单上时它可以正常工作,但是不同表单上的组件之间的接口属性链接会导致问题。
与指向另一个表单上的组件的对象链接不同,IDE 似乎无法识别界面链接。我的意思最好用一个例子来描述,当你在 IDE 中打开了 2 个表单,并且在它们之间有组件之间的链接,然后尝试以文本形式切换到表单视图 (Alt+F12) 会导致 IDE 正确地抱怨:
Module 'UnitXXX.pas' has open descendents or linked modules. Cannot close.
但是,如果属性是一个接口,那么这不会发生,而是会发生链接被切断(这是使用通知机制清除引用时的最佳情况,否则您将得到一个无效的指针)
另一个问题,可能是由于相同的错误,当您在 IDE 中打开项目时,重新打开表单的顺序是未定义的,因此 IDE 可以尝试打开包含具有接口链接的组件的表单到另一个窗体上的组件,但尚未重新创建另一个窗体。因此,这实际上会导致 AV 或断开链接。
早在 90 年代我使用 Datasets
和 Datasources
时,我记得表单之间的链接消失的类似问题,所以这有点相似。
作为临时解决方法,我添加了重复的已发布属性,对于每个接口属性,我添加了另一个声明为TComponent
的属性。这让 Delphi 意识到表单之间存在联系,但至少可以说是一种丑陋的解决方法。
所以我想知道是否有什么办法可以解决这个问题?这是一个 IDE 错误,可能无法直接修复,但也许我可以覆盖某些内容或以其他方式连接到流机制以更有效地解决此错误。
我从来没有深入研究过流媒体机制,但我怀疑 Fixup 机制应该可以解决这个问题。有一个 csFixups
TComponentState
所以我希望有一个解决方法。
编辑:使用 D2007。
更新:
新更新的可重现示例上传到http://www.filedropper.com/fixupbugproject2
添加了property ComponentReference: TComponent
,以便于比较和跟踪接口与组件流。
我将问题缩小到汇编程序级别,这有点超出我的深度。
在过程 GlobalFixupReferences
在它调用的classes
单元中:
(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);
以system
为单位
这一行特别引发了read of address 0x80000000
Now we're into the less common cases.
@@NilSource:
MOV ECX, [EAX] // get current value
那么,为什么 MOV
会失败,ECX
或 EAX
有什么问题我不知道。
【问题讨论】:
这是一个有趣的问题。这感觉有点超出我的个人经验。我怀疑你是否有一个可以帮助任何初露头角的调查员的演示项目。 @DavidHeffernan 这很容易复制,您只需要一个具有 IInterface 类型已发布属性的 TComponent 后代。注册它,安装包并在两个空白表格中的每一个上放一个。话虽如此,我可以自己做,让你们玩它...... 我认为如果你这样做会有所帮助。为我们降低障碍。 您使用的是哪个版本的 Delphi?可能对任何解决方案/解决方法都很重要? 显然GetOrdProp
不喜欢带有getter 函数的属性。如果您将property InterfaceReference ... read GetInterfaceReference
更改为property InterfaceReference ... read FInterfaceReference
,AV 就会消失。
【参考方案1】:
总而言之,该问题仅发生在具有 getter 方法的已发布接口属性中,并且该属性指向另一个表单/模块上的组件(并且该表单/模块尚未重新创建)。在这种情况下,恢复表单 DFM 会导致 AV。
我很确定这个错误出现在 GetOrdProp
的 ASM 代码中,但这超出了我的修复能力,所以
最简单的解决方法是使用 Field 而不是 getter 方法并直接在属性中读取它。幸运的是,这对我目前的情况来说已经足够了。
或者,您可以将属性声明为TComponent
而不是接口,然后编写TComponentProperty
后代,覆盖ComponentMayBeSetTo
以过滤不支持所需接口的组件。当然也可以使用RegisterPropertyEditor
注册它
【讨论】:
这个有 QC 条目吗? 这只会使问题长期存在。如果他们不知道,你不能抱怨它没有修复。如果他们这样做,您可以投诉:)(不是我在指责您抱怨,但您明白我的意思。)以上是关于已发布的接口属性错误和解决方法的主要内容,如果未能解决你的问题,请参考以下文章