Dll unloading problem

Started by
6 comments, last by Evil Steve 15 years, 2 months ago
How can I ensure a dll is not unloaded while any objects in it exist? The problem is, when I was using explict memory management I could delete the dll objects before freeing the dll, however with smart pointers I have no controll over the order there destroyed, meaning the dll may be freed first causeing a crash when trying to free one of the other objects: FlPtr is a simple refrence counting class thats calls AddRef and Release as needed

ExampleDll *dll = LoadDll(L"bin\\example.dll");
IObject *obj = dll->CreateObject();
...
obj->Release();
delete dll;//fine because all objects already deleted
return 0;



auto_ptr<ExampleDll> dll = LoadDll(L"bin\\example.dll");
FlPtr<IObject> obj = dll->CreateObject();
...
return 0;//crash if dll is destructed before obj since Object::Release needs to call into the dll


I tried making the dll handle unloading itsself, ie only unload after all objects have been deleted. This work by creating a new object IExampleDll which the dll implements. This is like the ExampleDll object from before but lives in the dll rather than the exe and is also refrence counted. Each object in the dll increments this refrence on contruction and deincrements it on destruction. This means the refrence count only reaches zero when the exe has Released its refrences AND all the dlls objects have been destroyed. It then deletes itsself calling FreeLibrary(GetModuleHandle()) in its destructor. This however crashes at the FreeLibrary, im asuming because the thread is still in the dlls code that is being unloaded... I'm at a loss now how to make sure the dll is only unloaded when there are no remaining objects, apart from going back to freeing the dll explicitly after everything else should have been deleted (meaning I cant use smart pointers for them either and alow for automatic destruction :( ) Is there some way to force instances of a certain object to be destroyed last when they go out of scope so that all the dlls objects are cleaned up before the dll is freed? EDIT: Another suggetsion was to poll the dll every so often like COM does. How would I go about doing this without any major impact of proformance? Also is there any diffrent approaches to this problem ive missed?
Advertisement
Quote:Original post by Fire Lancer
It then deletes itsself calling FreeLibrary(GetModuleHandle()) in its destructor.

This however crashes at the FreeLibrary, im asuming because the thread is still in the dlls code that is being unloaded...
GetModuleHandle(NULL) will always give you the handle of the EXE not the DLL, even if called from DLL code - that could well be your problem.

EDIT:
Quote:Original post by Fire Lancer
I'm at a loss now how to make sure the dll is only unloaded when there are no remaining objects, apart from going back to freeing the dll explicitly after everything else should have been deleted (meaning I cant use smart pointers for them either and alow for automatic destruction :( )

Is there some way to force instances of a certain object to be destroyed last when they go out of scope so that all the dlls objects are cleaned up before the dll is freed?
Objects are destroyed in the reverse order they're created in, so if you have a function that declares a smart pointer to the DLL, then to an object in the DLL, then the object will be destroyed first, then the DLL mart pointer.

Quote:Original post by Fire Lancer
EDIT: Another suggetsion was to poll the dll every so often like COM does. How would I go about doing this without any major impact of proformance?

Also is there any diffrent approaches to this problem ive missed?
What do you mean poll the DLL? I'm not aware of COM doing anythung like this?
Quote:
Objects are destroyed in the reverse order they're created in, so if you have a function that declares a smart pointer to the DLL, then to an object in the DLL, then the object will be destroyed first, then the DLL mart pointer.

Isnt the order globals are destroyed undefined though?

Quote:
What do you mean poll the DLL? I'm not aware of COM doing anythung like this?

COM calls a function exported from the dll (CanUnloadNow I think) every now and then, if the method returns true then the dll is unloaded.

Quote:
GetModuleHandle(NULL) will always give you the handle of the EXE not the DLL, even if called from DLL code - that could well be your problem.

In my test application that may be so, but in my actaul app the handle I pass to FreeLibrary is the one origenally returned by LoadLibrary
Quote:Original post by Fire Lancer
Isnt the order globals are destroyed undefined though?
For globals, yes. This is another reason why globals are bad though [smile]

Quote:Original post by Fire Lancer
COM calls a function exported from the dll (CanUnloadNow I think) every now and then, if the method returns true then the dll is unloaded.
Interesting, I wasn't aware of that (MSDN page for DllCanUnloadNow).

To be honest, I think that's likely to be your best bet. Alternatively, it may be better to modify your FlPtr class to call your DLL's version of DllCanUnloadNow() when it destroys an object. The overhead should be minimal, since destruction of an object isn't that common an operation.

Also, when you say that you call FreeLibrary() in your objects destructor, you're not calling FreeLibrary() from within code in your DLL are you? I'm pretty sure that's not going to work (Not like delete this; certainly, you're killing code, not just data here).
Quote:
To be honest, I think that's likely to be your best bet.

The problem is I dont know what to call the function from, it cant be the main app since it needs to be able to unload the dll after the main app has finished. Could I somehow create a diffrent process and give it the handle for the dll(s) and make it loop slowly checking?


Alternatively, it may be better to modify your FlPtr class to call your DLL's version of DllCanUnloadNow() when it destroys an object. The overhead should be minimal, since destruction of an object isn't that common an operation.

So your saying check after every object is destroyed?

eg:
//FlPtr release code...HMODULE handle = ptr->GetDllHandle();if(!ptr->Release())//returns new ref count. 0 = deleted    if(DllCanUnloadNow(handle))        FreeLibrary(handle);


Just how fast will that be? DllCanUnloadNow(handle) will somehow need to obtain a function pointer to the dlls DllCanUnloadNow() from the handle and then call it.

Are HMODULE handles constant if the dll is loaded multiple times, ie could a dll store the handle in a global so all its objects can return it?
Quote:Original post by Fire Lancer
Quote:
To be honest, I think that's likely to be your best bet.

The problem is I dont know what to call the function from, it cant be the main app since it needs to be able to unload the dll after the main app has finished. Could I somehow create a diffrent process and give it the handle for the dll(s) and make it loop slowly checking?
Not really - the DLL has to be unloaded before the EXE ends, if it's not then the OS will unload the DLL as part of the EXE cleanup.

Quote:Original post by Fire Lancer
Quote:
Alternatively, it may be better to modify your FlPtr class to call your DLL's version of DllCanUnloadNow() when it destroys an object. The overhead should be minimal, since destruction of an object isn't that common an operation.

So your saying check after every object is destroyed?

eg:
*** Source Snippet Removed ***

Just how fast will that be? DllCanUnloadNow(handle) will somehow need to obtain a function pointer to the dlls DllCanUnloadNow() from the handle and then call it.

Are HMODULE handles constant if the dll is loaded multiple times, ie could a dll store the handle in a global so all its objects can return it?
Yep, that looks fine to me. If you call LoadLibrary() multiple times without calling FreeLibrary(), then the returned HMODULE will be the same. The problem comes when you load the DLL, unload it, then re-load it - then there's no guarantee that the HMODULE will be the same. However, since we're talking about the DLL being in memory through all of this, it'll be fine.
You can just use GetProcAddress() to get the address of your DllCanUnloadNow() function from the HMODULE, and the DLL can get its own HMODULE by adding a DllMain() function and grabbing the HMODULE in the process attach handler.


EDIT: Also, in case you don't know; every call to LoadLibrary() needs to be matched by a call to FreeLibrary(). The first call to LoadLibrary() will actually load the DLL into memory, the second call will just increase it's reference count. Then the first free will decrease the OS's reference count to the DLL, and the second will decrease it to 0 and free it.
Quote:
Not really - the DLL has to be unloaded before the EXE ends, if it's not then the OS will unload the DLL as part of the EXE cleanup.

Is it garunteed to do this after clearing up any globals etc in the exe and not before?

Quote:
You can just use GetProcAddress() to get the address of your DllCanUnloadNow() function from the HMODULE

Yes thats what I'm doing to get the object factory methods from the dll in the first place. The question is just how fast is getting the address? Is it a simple lookup in a table or does windows go searching though the dll looking from a function with that name (which is something I dont really want to do everytime an object is destroyed).
Quote:Original post by Fire Lancer
Quote:
Not really - the DLL has to be unloaded before the EXE ends, if it's not then the OS will unload the DLL as part of the EXE cleanup.

Is it garunteed to do this after clearing up any globals etc in the exe and not before?
Yes.

Quote:Original post by Fire Lancer
Quote:
You can just use GetProcAddress() to get the address of your DllCanUnloadNow() function from the HMODULE

Yes thats what I'm doing to get the object factory methods from the dll in the first place. The question is just how fast is getting the address? Is it a simple lookup in a table or does windows go searching though the dll looking from a function with that name (which is something I dont really want to do everytime an object is destroyed).
I can't say for sure, I suspect it's a lookup table - LoadLibrary() on XP uses a lookup table internally to see if the library is loaded, and that's called far less frequently that GetProcAddress(). You could always use QueryPerformanceCounter() to check the time taken to call GetProcAddress().

However, you really shouldn't be creating and destroying objects all the time, so the time taken to call GetProcAddress() will be mostly irrelevant.

In fact, since I have the OS symbols on this PC, and I'm bored, I'll go see what I can find from digging around in the dissasembly for GetProcAddress [smile]

EDIT: Ok, it looks like GetProcAddress() is reasonably expensive to call. From what I can see, it doesn't use a hash map like LoadLibrary() does, instead it parses the DLL's function exports table and looks for the named function.
However, as I said above, it shouldn't be that much of a problem. If you profile and find that it is, you can always cache the function address somehow.

[Edited by - Evil Steve on January 20, 2009 5:31:17 PM]

This topic is closed to new replies.

Advertisement