I'm working on a program that dynamically loads DLLs as plugins. I'm compiling the program using Microsoft Visual C++ 2008. Still, let's assume that any Visual C++ version with which Qt works should be supported. The program directory layout is following:
| plugins/
| plugin1.dll
| plugin2.dll
| QtCore4.dll
| QtGui4.dll
| program.exe
program.exe
discovers all plugins DLL files, performs LoadLibrary() on them and calls a certain signature function to find out if it's actually a plugin or not. This works pretty well on computers which have vcredist for MSVC90 installed. Naturally, to make the program work on all computers I have to redistribute it with the msvc*.dll files and with the appropriate manifest file. Qt DLLs also require the redist to run.
Now, I've set up cmake to automatically copy over appropriate redist DLLs and manifest depending on the selected Visual Studio version. For the sake of simplicity let's keep assuming that I'm working with MSVC90. When the redist gets copied to the program directory the layout looks like this:
| plugins/
| plugin1.dll
| plugin2.dll
| QtCore4.dll
| QtGui4.dll
| msvcm90.dll
| msvcp90.dll
| msvcr90.dll
| Microsoft.VC90.CRT.manifest (I'm also aware that this file is bugged in VS2008)
| program.exe
Regarding the bug in manifest file: http://www.cmake.org/pipermail/cmake/2008-September/023822.html
The program with this layout now works on computers which do not have the redist installed, but the plugins are not getting loaded. In order to get the plugins to load I have to do one of the following:
plugins/
directory. Remove all references to msvc*.dll files from the manifest file. This works but it's not nice because I'd have to support different versions of edited manifest files depending on the version of used MSVC. Also, I have no idea if this won't break with Visual Studio other than 2008.plugins/
directory. This doesn't require any modification to the manifest file, but now program.exe
stupidly tries to load the msvc*.dll files thinking they are plugins. Naturally, this fails gracefully so no big harm is done. The other drawback is that the size of the program package grows by over 1 MB. Both these issues are something that I can live with, though.program.exe
are /MD.What's the best solution? What's the correct solution? If there is more than one correct solution then which is the best practice? Am I the first person to ever try to do this?
While the question remains unanswered I decided to go for the route that causes the least headache. Until now I've been using solution number 1 and I decided to stick with it. If CMake detects that user is using a different MSVC version than 2008 it will display a warning message saying that automatic packaging is not fully supported.
If your target OS has _WIN32_WINNT >= 0x0502 than you can use function
SetDllDirectory()
before you do loading the plugins.
Put path to main program folder.
The call overrides system load order:
So, you may call the function after application starts up. It is safe in all cases. Good luck!
You can provide full file paths to "LoadLibrary", so you can load your plugins with their paths. I've used this exact layout to load multiple versions of the same library from subdirectories of the current dll in Visual Studio 2005.
You first need to get the current path of the current dll using:
static LPSTR strDLLPath1 = new TCHAR[_MAX_PATH+1];
::GetModuleFileName((HINSTANCE)&__ImageBase, strDLLPath1, _MAX_PATH);
Although if your program.exe is already discovering these plugin files, I would assume you already have access to their full paths.
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