如何在delphi控件中实现接口

时间:2016-04-20 20:23:43

标签: delphi interface custom-controls

我已经读过,如果一个类实现了一个接口,它现在被引用计数,不应该通过调用free来管理它的内存。

但是,如果您创建自定义控件并使其实现接口,那么如何阻止其owner管理其内存?例如,当您在设计时将其放在表单上时,引用计数和所有者内存管理会不一致?

感谢您的时间。

1 个答案:

答案 0 :(得分:6)

除此行为外,控件不会从TInterfacedObject继承 因此,它们不进行引用计数,它们的引用计数通过设计 *)保持在-1。

所有控件都从TComponent继承,如下所示:

TComponent = class(TPersistent, IInterface, IInterfaceComponentReference)  

TComponent中的引用计数如下所示:

function TComponent._AddRef: Integer;
begin
  if FVCLComObject = nil then Result := -1
       // -1 indicates no reference counting is taking place
  else Result := IVCLComObject(FVCLComObject)._AddRef;
end;

function TComponent._Release: Integer;
begin
  if FVCLComObject = nil then Result := -1   
  // -1 indicates no reference counting is taking place
  else Result := IVCLComObject(FVCLComObject)._Release;
end;

*) 需要注意的是,如果分配了VCLComObject,它们将遵循该对象的引用计数(通常不会卡在-1)。
VCLComObject对于大多数组件都是零 它仅用于IDE生成的组件包装器来包装COM对象 See: TComponent.ComObject

因此,您可以为心脏内容添加界面。只要你记得在完成后释放组件,它就没有任何问题。

您可以通过测试来测试控件是否引用计数:

DoesNotRefCount:= Supports(MyObject, IInterfaceComponentReference) 
                  and (TComponent(MyObject).VCLComObject = nil);  

不要在对象上调用_AddRef来测试它是否返回-1,因为这可能会破坏使用引用计数的对象。 如果您的引用计数对象从0开始并且您执行_AddRef后跟_Release,您将销毁该对象,即使Delphi即将在线下调用_AddRef两条指令。

如果你想让你自己的对象不进行引用计数,那么添加一个标记接口也是一个好主意:

INoRefCounting = interface
 ['{CAD60ADF-C49A-46FB-BB5A-CC54BD22C7EB}']
end;

在较新的Delphi中,您可以从TSingletonImplementation下降,为您进行虚拟无引脚计数。
在较旧的Delphi中从TObject(或TWhatever)下降并实现无引用计数如下:

function TMyObject.QueryInterface(const IID: TGUID; out Obj): HResult; {stdcall;}
begin
  if GetInterface(IID, Obj) then Result := S_OK
  else Result := E_NOINTERFACE;
end;

function TMyObject._AddRef: Integer; {stdcall;}
begin
  Result := -1;
end;

function TMyObject._Release: Integer; {stdcall;}
begin
  Result := -1;
end;  

最终说明
如果您想100%确定自定义控件不进行引用计数,则必须覆盖_AddRef / _Release方法以根据VCLComObject删除条件引用计数。

警告
如果控件的生命周期很短,并且您仍然保持对这些控件的接口的引用时间更长,那么您将遇到问题。
如果您遇到这种情况,可能需要将调试代码添加到_AddRef_ReleaseDestroy方法中,在这些方法中,您可以跟踪引用计数并发信号通知引用计数是否达到零迟到或太早。