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



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

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

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

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

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

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

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

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

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

另一种选择是将DLL更改为真正的COM DLL

最新更新