delphi – 发布的接口属性bug和解决方法

我写了一组通过已发布的接口属性相互链接的组件。它们已注册并安装在设计包中。

使用已发布的接口属性在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我不知道。

解决方法

总之,只有具有getter方法的已发布接口属性才会出现问题,并且属性指向另一个表单/模块上的组件(并且该表单/模块尚未重新创建)。在这种情况下,恢复形式DFM导致AV。

我很确定错误是在GetOrdProp的ASM代码,但它超出了我的能力,所以
最简单的解决方法是使用字段而不是getter方法,并直接在属性中读取它。这是,幸运的是足够好我的情况。

或者,您可以将属性声明为TComponent而不是interface,然后写入TComponentProperty后代,重写ComponentMayBeSetTo以过滤不支持所需接口的组件。当然,使用RegisterPropertyEditor注册

相关文章

ffmpeg 是一套强大的开源的多媒体库 一般都是用 c/c++ 调用, 抽空研究了一下该库的最新版 ,把...
32位CPU所含有的寄存器有:4个数据寄存器(EAX、EBX、ECX和EDX)2个变址和指针寄存器(ESI和EDI) 2个指针寄...
1 mov dst, src dst是目的操作数,src是源操作数,指令实现的功能是:将源操作数送到目的操作数中,即:...
有三个API函数可以运行可执行文件WinExec、ShellExecute和CreateProcess。 1.CreateProcess因为使用复杂...
API原型: Declare Function MoveFileEx& Lib "kernel32" Alias "MoveFileExA" (By...