如何在delphi控件中实现接口

use*_*960 4 delphi interface custom-controls

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

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

谢谢你的时间.

Joh*_*ica 6

控件是从这种行为除外,因为它们不从中继承TInterfacedObject.
因此,它们不进行引用计数,它们的引用计数被设计为-1 ).

所有控件的继承TComponent都是这样的:

TComponent = class(TPersistent, IInterface, IInterfaceComponentReference)  
Run Code Online (Sandbox Code Playgroud)

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;
Run Code Online (Sandbox Code Playgroud)

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

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

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

DoesNotRefCount:= Supports(MyObject, IInterfaceComponentReference) 
                  and (TComponent(MyObject).VCLComObject = nil);  
Run Code Online (Sandbox Code Playgroud)

不要调用_AddRef您的对象来测试它是否返回-1,因为这可能会破坏使用ref计数的对象.
如果您的引用计数对象从0开始,然后您执行a _AddRef后跟a,_Release您将销毁该对象,即使Delphi正要_AddRef进一步调用两条指令.

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

INoRefCounting = interface
 ['{CAD60ADF-C49A-46FB-BB5A-CC54BD22C7EB}']
end;
Run Code Online (Sandbox Code Playgroud)

在较新的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;  
Run Code Online (Sandbox Code Playgroud)

最后的注释
如果你想100%确定你的自定义控件没有引用计数,你必须覆盖_AddRef/ _Release方法来删除基于的条件引用计数VCLComObject.

警告
如果控件的生命周期很短,并且您仍然持有对这些控件的接口的引用更长时间,那么您将遇到问题.
如果您遇到这种情况,可能需要将调试代码添加到_AddRef,_Release以及Destroy跟踪引用计数的方法,并在重新计数达到零到迟到或过早时发出信号.