PDA

View Full Version : Need to unload dependent dlls loaded by QPlugin when I unload the plugin.



jimmaplesong
19th July 2019, 17:10
I've got a large mature app using Qt 5.6 on Windows 10.

It loads a QPlugin which interfaces to an interpreted language, and that may load many dlls.
At some point, I need to Unload this QPlugin and then load a similar but different plugin that lets me use a different version of the interpreted language.

The problem is that if the first instance of QPlugin loads one version of x.dll, y.dll and z.dll, then the second Plugin tries to use that same dlls, instead of unloading it and using a different version of x.dll, y.dll and z.dll.

If I knew which .dlls were going to be loaded, I could pre-load them with QLibrary, and unload them after I unload the QPlugin.... but that's not always going to be the case.

Is there a way I can unload all of the .dlls loaded by my QPlugin?

(In the visual studio output window, I can see that it usually unloads them, but we're definitely getting errors where it can't find a function that exists in a .dll loaded by the the second QPlugin, and the error tells me it's looking in the loaded-by-first-x.dll)

Thanks!

d_stranz
19th July 2019, 17:33
It could be that there isn't any way for one DLL to determine if it is the only one dependent on those DLLs or if there are other parts of the app that are also using them. So it can't arbitrarily unload all of the DLLs it depends on, because that might break the application. Only the OS knows for sure which binaries have loaded which dependent DLLs and can unload those after all of the "parent" DLLs have unloaded.

There might be some Windows-specific API that you can use to determine which DLLs yours has loaded and maybe what the reference counts are for those (if Windows uses reference counting at all to keep track of how many users of a DLL there are), but that's way beyond anything I've ever needed to do.

anda_skoa
20th July 2019, 08:51
Maybe you can interface with the other language through a helper process instead?

E.g. either in that language itself or with Qt write a program that communicates with your main program and runs whatever task you want done in the other language.
The main program can then launch and stop this process when needed, each time triggering a new runtime linking on startup.

Cheers,
_

d_stranz
20th July 2019, 18:08
@jimmaplesong: Welcome to the world of "DLL hell". This was supposed to have been solved by the use of Windows 7 and later technology for "side-by-side" (SxS) deployment and manifests, but that might apply only when separate apps use DLLs of the same name but different versions.

It sounds like you might be dealing with Python 2 / 3 incompatibility problems. Have you looked to see if there are solutions in the Python support community?

tuli
21st July 2019, 22:10
Actually windows does fine unloading dllls from memory, when they are not used anymore. Do you have access to the source code of the plugins? If so check that all libraries are unloaded on exit.

Are you sure that the paths are as you expect? Try loading the library with full path instead of relying on windows to search for it.

Note that dlls are always loaded from the working dir of the executable, not from the dir where the plugin.dll file maybe located.

d_stranz
22nd July 2019, 00:34
Note that dlls are always loaded from the working dir of the executable, not from the dir where the plugin.dll file maybe located.

So you could change the working directory that of the plugin DLL before loading it and it would use whatever DLLs it found there? (That is, Windows will search "." first before searching $PATH)?

jimmaplesong
22nd July 2019, 16:40
There might be some Windows-specific API that you can use to determine which DLLs yours has loaded and maybe what the reference counts are for those (if Windows uses reference counting at all to keep track of how many users of a DLL there are), but that's way beyond anything I've ever needed to do.

Thanks d_. Windows does have hooks so I could be notified whenever a dll loads, and these might be necessary for me to track those dependencies by hand. I hope that's not the case, but it might be a step forward.

I'm reading up on Qt's IPC capabilities to gauge the effort involved. I do think it's the ultimate solution. Google Chrome uses this strategy, and it works well for them.

Added after 4 minutes:

If the dlls that we were using all had good SxS manifests, it would prevent this issue where the 'wrong version' is being utilized. Unfortunately, the pre-SxS dlls are in-the-wild, and the chances of updating the whole infrastructure in any reasonable time-frame are low.

There's no Python in this project.


Actually windows does fine unloading dllls from memory, when they are not used anymore. Do you have access to the source code of the plugins? If so check that all libraries are unloaded on exit.

Are you sure that the paths are as you expect? Try loading the library with full path instead of relying on windows to search for it.

Note that dlls are always loaded from the working dir of the executable, not from the dir where the plugin.dll file maybe located.

In the past, we had a strategy where we would copy most of the the dependencies (copying the .dlls) into the same directory as the QPlugin. Before we load the plugin, we would set the CWD to the plugin's directory. Unfortunately, the duplication (& re-distribution of the core libraries) was unacceptable.