我正在开发一个动态加载DLL作为插件的程序。我正在使用Microsoft Visual C ++ 2008编译程序。但是,我们假设应该支持任何与Qt一起工作的Visual C ++版本。程序目录布局如下:
| plugins/
| plugin1.dll
| plugin2.dll
| QtCore4.dll
| QtGui4.dll
| program.exe
program.exe
发现所有插件DLL文件,对它们执行LoadLibrary()并调用某个签名函数以查明它是否实际上是一个插件。这对于安装了MSVC90的vcredist的计算机非常有效。当然,要使程序在所有计算机上运行,我必须使用msvc * .dll文件和相应的清单文件重新分发它。 Qt DLL还需要redist才能运行。
现在,我已经设置了cmake来根据所选的Visual Studio版本自动复制适当的redist DLL和manifest。为了简单起见,让我们继续假设我正在使用MSVC90。当redist被复制到程序目录时,布局如下所示:
| 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
关于清单文件中的错误:http://www.cmake.org/pipermail/cmake/2008-September/023822.html
具有此布局的程序现在适用于未安装redist的计算机,但插件未加载。为了让插件加载,我必须执行以下操作之一:
plugins/
目录。从清单文件中删除对msvc * .dll文件的所有引用。这有效,但它并不好,因为我必须支持不同版本的已编辑清单文件,具体取决于使用的MSVC的版本。此外,我不知道这是否会在2008年以外的Visual Studio中出现。plugins/
目录。这不需要对清单文件进行任何修改,但现在program.exe
愚蠢地尝试加载msvc * .dll文件,认为它们是插件。当然,这会优雅地失败,所以不会造成太大的伤害。另一个缺点是程序包的大小增加了1 MB以上。不过,这两个问题都是我可以忍受的。program.exe
都是/ MD,它将来是否会破坏。什么是最好的解决方案?什么是正确的解决方案?如果有多个正确的解决方案,那么这是最佳做法?我是第一个尝试这样做的人吗?
虽然问题仍然没有答案,但我决定选择导致头痛最少的路线。到目前为止,我一直在使用1号解决方案,我决定坚持下去。如果CMake检测到用户使用的MSVC版本与2008年不同,则会显示一条警告消息,指出不完全支持自动打包。
答案 0 :(得分:1)
您可以提供" LoadLibrary"的完整文件路径,以便您可以使用其路径加载插件。我已经使用这个确切的布局从Visual Studio 2005中当前dll的子目录加载同一个库的多个版本。
首先需要使用以下方法获取当前dll的当前路径:
static LPSTR strDLLPath1 = new TCHAR[_MAX_PATH+1];
::GetModuleFileName((HINSTANCE)&__ImageBase, strDLLPath1, _MAX_PATH);
虽然如果你的program.exe已经发现了这些插件文件,我认为你已经可以访问它们的完整路径了。
答案 1 :(得分:0)
如果你的目标操作系统有_WIN32_WINNT> = 0x0502,你可以使用功能
SetDllDirectory()
在加载插件之前。
将路径放到主程序文件夹中。
该调用会覆盖系统加载顺序:
因此,您可以在应用程序启动后调用该函数。在所有情况下都是安全的。祝你好运!
答案 2 :(得分:0)
您可以在安装过程中使用CreateHardLink()函数创建VC dll的硬链接。使用您所描述的方法(1),VCRT dll的不同副本可能存在一些问题。硬链接或SetDllDirectory()似乎是最好的解决方案。
不要在单个进程中混合使用静态和动态链接到MSVCRT - 它总是会给你带来问题!