I have a dll that exports a function returning an Interface.
I created a wrapper for the LoadLibrary, GetProcAddress and FreeLibrary functions used to invoke the exported function.
TInterfaceGetter = class
private
...
public
constructor Create;
destructor Destroy; override;
function GetInterface: IMyInterface;
end;
This wrapper lazy loads the dll and caches the module handle and proc address of the exported function when GetInterface is called for the first time. The call to FreeLibrary happens in the wrapper's destructor.
Everything works splendidly except if the client code hangs onto the interface reference after freeing the wrapper. When the interface reference eventually goes out of scope the resulting call to _IntfClear raises an access violation because the dll as well as any memory it was using has already been unloaded from the client's memory space.
How can I handle this gracefully? How does a full blown COM implementation handle this scenario?
COM handles this problem by shifting responsibility to the DLL. The DLL needs to implement and export a function named DllCanUnloadNow
. COM calls it occasionally, and if it returns true, the DLL may be unloaded.
So how does the function know? The DLL keeps track of how many objects it gives out through calls to DllGetClassObject
, and it knows how many of those objects are still alive. In Delphi's default COM DLL implementation, it maintains a global object count, much the way each object maintains its own reference count. See the implementation in ComServ.pas, for example.
You can employ the same technique. Track what your GetInterface
function gives out, and what's been released. Export another function so host programs can ask whether it's safe to unload your library.
An alternative would be to change your DLL into a real COM DLL
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With