5

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

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

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

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

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

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

4

1 回答 1

5

COM 通过将责任转移给 DLL 来解决这个问题。DLL 需要实现并导出一个名为DllCanUnloadNow. COM 偶尔会调用它,如果它返回 true,则可能会卸载 DLL。

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

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

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

于 2013-08-14T03:22:56.583 回答