当一个实现接口的表单没有引用时,它会自动释放吗?

6
如果我在一个表单上实现一个接口,例如 TMyForm = class(TForm, IMyInterface),那么当没有更多的接口引用时,对象会自动释放吗?似乎并不是这样,尽管我无法确定 TForm 是否被引用计数(如果有的话)。我担心当接口引用超出范围时,表单会被释放,但事实并非如此。
我猜这个问题有两个部分,首先是表单是否可能意外释放(真正的问题),其次是表单如何被引用计数。

@TLama TForm 是从 TComponent 继承而来的,TComponent 实现了 IInterface 和 IInterfaceComponentReference。TComponent 确实实现了 _AddRef 和 _Release 两个方法, 但它们似乎只有在某种条件下才会进行引用计数。 - Alister
@Alister: TComponent 会禁用自身的引用计数,但是如果有赋值给VCLCOMObject属性,它会在该属性上执行引用计数。 - Remy Lebeau
@Alister,抱歉,也许我之前误解了你的问题(在多次重新阅读之前),但我原以为你是在问如果添加一个接口(要在TForm类中实现),会发生什么。如果添加该接口会有什么风险,并且是否会给表单添加引用计数。 - TLama
1
@TLama:将接口添加到TForm不会为TForm添加引用计数。编译器仍然会在接口指针上调用_AddRef()_Release(),但由于TComponent,它们将成为无操作。 - Remy Lebeau
这不是那么简单的,@Free。看看其他人在这里写了什么。特别是,在你之前的Remy的评论,Uwe的答案以及问题中报告的那些地方表明它不是那样工作的。 - Rob Kennedy
拍额头 是的,当然,我忘记了什么! - Free Consulting
2个回答

15

TFormTComponent的派生类,TComponent实现了_AddRef()_Release()方法来禁用对自身的引用计数。因此,任何由TComponent派生类(如TForm)实现的接口在释放时默认不会释放其实现的TComponent对象。

然而,如果将IVCLComObject接口分配给TComponent.VCLCOMObject属性,则TComponent将委托引用计数给该对象,以便在该对象的引用计数降至0时可以释放它(TComponent不会增加其IVCLCOMObject引用的引用计数)。

这适用于TComponent的所有后代类,除非它们通过手动重写_AddRef()_Release()来实现任何自己的引用计数。


我更关注的是哪些其他因素可能会设置VCLComObject。 - Alister
@Alister:如果访问了TComponent.ComObject,则会设置TComponent.VCLCOMObject,但只有在项目使用VCLCom单元时才有效(否则访问ComObject属性将引发异常)。 - Remy Lebeau
2
换句话说:只要您不通过COM服务器以某种方式公开表单(其中引用计数似乎是足够的),那么很少有什么东西会在没有您自己干预的情况下设置VCLComObject。 - Uwe Raabe

0
如果你在一个表单中实现了一个接口,它就值得你添加你自己的。
_Release as follows:

    function _Release: Integer; stdcall;

function TMyInterfacedForm._Release: Integer;
begin
  result:=-1; 
end;

我发现可以使用接口来释放一个窗体,然后在局部变量超出作用域时调用_Release。这可能会导致访问冲突,因为Tcomponent实现会检查FVCLComObject是否设置。
  if FVCLComObject = nil then
    Result := -1   // -1 indicates no reference counting is taking place
  else
    Result := IVCLComObject(FVCLComObject)._Release;

由于在这个阶段,FVCLComobject未定义,可能会出现令人烦恼的A/V异常。 通过硬编码-1,可以安全地调用它而不触发异常。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接