2012-11-04 40 views
8

的我想要实现

我工作的动态加载的DLL以插件的程序长的故事。我正在使用Microsoft Visual C++ 2008编译该程序。但是,让我们假设应该支持任何与Qt一起工作的Visual C++版本。该项目目录布局如下:C++:从不同的目录舱单及动态加载的DLL

| plugins/ 
| plugin1.dll 
| plugin2.dll 
| QtCore4.dll 
| QtGui4.dll 
| program.exe 

program.exe发现所有的插件DLL文件,对它们进行调用LoadLibrary(),并调用某个签名功能,以找出是否它实际上是一个插件或没有。对于安装有MSVC90的vcredist的计算机,此功能非常有效。当然,为了使程序在所有计算机上都能正常工作,我必须使用msvc * .dll文件和相应的清单文件来重新分发它。 Qt DLLs还需要redist才能运行。

现在,我已经设置cmake根据选定的Visual Studio版本自动复制适当的redist dll和清单。为了简单起见,我们假设我正在使用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的电脑,但是插件没有被加载。为了让插件加载,我必须执行以下操作之一:

  1. 将清单文件复制到plugins/目录。从清单文件中删除对msvc * .dll文件的所有引用。这可行,但它不好,因为我必须支持不同版本的编辑清单文件,具体取决于所使用的MSVC的版本。此外,我不知道这是否会与2008年以外的Visual Studio打破。
  2. 将整个redist复制到plugins/目录。这不需要对清单文件进行任何修改,但现在program.exe愚蠢地尝试加载msvc * .dll文件,认为它们是插件。很自然地,这会失败,所以不会有太大的伤害。另一个缺点是程序包的大小增长超过1MB。不过,这两个问题都是我可以接受的。
  3. 使用/ MT开关编译插件。简短的测试表明,这实际上有效,但如果Qt和program.exe都是/ MD,我不确定它将来会不会破坏任何东西。

的问题(S)

什么是最好的解决方案?什么是正确的解决方案?如果有多个正确的解决方案,那么哪一个是最佳实践?我是第一个尝试这样做的人吗?

更新1(2012年11月18日)

虽然这个问题仍然没有答案,我决定去引起头痛最少的路线。到目前为止,我一直在使用第一号解决方案,并决定坚持使用它。如果CMake检测到用户正在使用与2008不同的MSVC版本,则会显示一条警告消息,指出自动打包不完全受支持。

+1

为什么不静态链接你的应用程序和插件的运行时? –

+0

Qt已经需要vcredist,所以我必须包含它。此外,当资源分配在一个静态链接的实体中,然后在另一个实体链接中释放时,会出现资源分配问题 - 这是不安全的,程序可能会崩溃。我不知道如果Qt是/ MD,这将如何与Qt相互作用。 – ZalewaPL

+1

我想你应该让插件的作者决定他们想如何链接到运行时库,而不是试图强制他们动态链接到特定版本的运行时。 至于你提到的分配问题,如果你调用插件来分配资源,那么你应该回到插件来释放资源。 –

回答

0

如果你的目标操作系统有_WIN32_WINNT> = 0x0502比你可以使用函数

SetDllDirectory() 

你加载的插件之前。

将路径放到主程序文件夹中。

呼叫覆盖系统负载顺序:

  1. 从其中加载应用程序的目录。
  2. 由SetDllDirectory()调用中的路径指定的目录。

因此,您可以在应用程序启动后调用该函数。在任何情况下都是安全的。祝你好运!

+0

似乎没有工作。 – ZalewaPL

0

在安装过程中,您可以使用CreateHardLink()函数创建与VC dll的硬链接。通过您所描述的方法(1),VCRT dll的不同副本可能存在一些问题。硬链接或SetDllDirectory()似乎是最好的解决方案。

不要在一个进程中混合静态和动态链接到MSVCRT - 它总是给你提供问题!

1

您可以提供完整的文件路径到“LoadLibrary”,因此您可以加载您的插件与他们的路径。我用这个确切布局加载从目前的dll子目录中的同一个库的多个版本在Visual Studio 2005

首先,您需要使用来获得当前的dll的电流路径:

static LPSTR strDLLPath1 = new TCHAR[_MAX_PATH+1]; 
::GetModuleFileName((HINSTANCE)&__ImageBase, strDLLPath1, _MAX_PATH); 

虽然如果您的program.exe已经发现这些插件文件,我会假设您已经有权访问其完整路径。