在调用FreeLibrary之前,如何确保释放Interface实例

时间:2013-08-13 22:14:43

标签: delphi memory-management reference-counting

我有一个dll导出一个返回接口的函数。

我为LoadLibrary,GetProcAddress和FreeLibrary函数创建了一个包装器,用于调用导出的函数。

TInterfaceGetter = class
private
...
public
  constructor Create;
  destructor Destroy; override;
  function GetInterface: IMyInterface;
end;

当第一次调用GetInterface时,这个包装器延迟加载dll并缓存模块句柄和导出函数的proc地址。对FreeLibrary的调用发生在包装器的析构函数中。

除非客户端代码在释放包装器后挂起到接口引用上,否则一切都会很好地工作。当接口引用最终超出范围时,对_IntfClear的结果调用会引发访问冲突,因为dll以及它正在使用的任何内存已经从客户端的内存空间中卸载。

我怎样才能优雅地处理这件事?完整的COM实现如何处理这种情况?

1 个答案:

答案 0 :(得分:6)

COM通过将责任转移到DLL来处理此问题。 DLL需要实现并导出名为DllCanUnloadNow的函数。 COM偶尔会调用它,如果它返回true,则可以卸载DLL。

那么这个功能怎么知道呢? DLL通过调用DllGetClassObject来跟踪它给出的对象数量,并且它知道有多少对象仍处于活动状态。在Delphi的默认COM DLL实现中,它维护一个全局对象计数,就像每个对象维护自己的引用计数一样。例如,请参阅 ComServ.pas 中的实现。

您可以采用相同的技术。跟踪GetInterface函数发布的内容以及已发布的内容。导出另一个函数,以便主程序可以询问卸载库是否安全。

另一种方法是将您的DLL更改为真正的COM DLL