已发布的界面属性错误和变通方法

Dan*_*rić 44 ide delphi design-time interface delphi-2007

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

使用已发布的接口属性在Delphi中并不常见,因此,不出所料,似乎效果不佳.

当组件驻留在同一表单上时,它工作正常,但不同表单上的组件之间的接口属性链接会导致问题.

与指向另一个表单上的组件的对象链接不同,IDE似乎无法识别接口链接.我的意思最好用一个例子来描述,当你在IDE中打开2个表单,并在它们之间有组件之间的链接,然后尝试切换到表单视图时,文本(Alt + F12)将导致IDE正确地抱怨:

Module 'UnitXXX.pas' has open descendents or linked modules. Cannot close.

但是如果属性是一个接口,那么这不会发生,而是发生的事情是链接被切断(当你使用Notification机制清除引用时这是最好的情况,否则你会留下无效的指针)

另一个问题,可能是同一个错误的结果是,当您在IDE中打开项目时,表单将重新打开的顺序是未定义的,因此IDE可以尝试打开包含具有到组件的接口链接的组件的表单另一种形式,但其他形式尚未重新创建.因此,这有效地导致AV或切断链接.

早在90年代,我使用时Datasets,Datasources我记得表格之间的链接消失的类似问题,所以这有点类似.

作为临时解决方法,我添加了重复的已发布属性,对于每个Interface属性,我添加了另一个声明为的属性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;
Run Code Online (Sandbox Code Playgroud)

正如您从注释中看到的那样,我发现避免异常的唯一方法是保留结果未分配,但这会破坏功能,因为上面的比较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
Run Code Online (Sandbox Code Playgroud)

那么,为什么MOV失败,什么是错的ECX或者EAX我不知道.

小智 2

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

我很确定该错误存在于 中的 ASM 代码中GetOrdProp,但它超出了我修复的能力,因此最简单的解决方法是使用 Field 而不是 getter 方法并直接在属性中读取它。幸运的是,这对于我目前的情况来说已经足够好了。

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