如何确保接口实例在调用FreeLibrary之前被释放?

5

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

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

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

这个包装器会在首次调用GetInterface时懒加载dll并缓存模块句柄和导出函数的过程地址。在包装器的析构函数中调用FreeLibrary。
一切都很好,除非客户端代码在释放包装器后仍然保留接口引用。当接口引用最终超出作用域时,对_IntfClear的调用会引发访问冲突,因为dll以及它使用的任何内存已经从客户端的内存空间卸载了。
如何优雅地处理这种情况?完整的COM实现如何处理这种情况?
1个回答

5
COM通过将责任转移到DLL来解决这个问题。 DLL需要实现并导出一个名为DllCanUnloadNow的函数。 COM偶尔调用它,如果返回true,则可以卸载DLL。
那么这个函数如何知道呢? DLL通过调用DllGetClassObject跟踪它提供的对象数量,并且知道其中有多少对象仍然存在。在Delphi的默认COM DLL实现中,它维护全局对象计数,方式与每个对象维护其自己的引用计数类似。例如,可以查看ComServ.pas中的实现。
您可以采用相同的技术。跟踪您的GetInterface函数发放的内容以及已释放的内容。导出另一个函数,以便宿主程序可以询问是否安全卸载您的库。
另一种选择是将您的DLL更改为真正的COM DLL。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接