具有相同名称的非托管C ++ DLL在同一进程中共存

时间:2013-01-11 15:17:36

标签: c++ visual-studio dll

使用Visual Studio c ++ V10,我试图弄清楚如何构建DLL并解决DLL命名冲突。以下是详细信息。

公司S运送名为M.EXE的产品。假设M.EXE中安装了\S\BIN\M.EXE。公司S静态链接到名为U.DLL的DLL,该DLL安装在\S\BIN\U.DLL中。 U.DLL包含开源代码,并使用Visual C ++编译器选项/Zc:wchar_t-构建,该选项不将wchar识别为本机类型。

公司C发布了一个名为O.DLL的DLL,并发布了此DLL的API,并为O.DLL发布了一个导入库。假设O.DLL中安装了\C\BIN\O.DLLO.DLL静态链接到名为U.DLL的DLL,该DLL安装在\C\BIN\U.DLL中。 U.DLL构建于相同的开源代码之上,但是使用Visual C ++编译器选项/Zc:wchar_t构建,它将wchar_t识别为本机类型。

理想情况下,公司C和公司S同意使用相同的Visual C ++选项构建U.DLL,但这是不可能的。

公司S的

M.EXE是可扩展的,因为我可以在非托管C ++中构建我自己的DLL,如果我正确设置了所有内容,则调用NODE.DLL M.EXE将调用它。我想构建NODE.DLL,以便它静态链接到公司C的O.DLL。但问题是,一旦M.EXE正在运行,它就会加载U.DLL\S\BIN\S\BIN\U.DLL中的符号与\C\BIN\U.DLL中的符号略有不同,因为每个公司都建立了U.DLL。因此,当M.EXE尝试加载NODE.DLL时,它会失败,因为当NODE.DLL加载需要O.DLL的{​​{1}}时,U.DLL需要符号不存在,因为Windows将\C\BIN\U.DLL视为已加载。

情况图如下:

U.DLL

实际上,我需要M.EXE static link to -> \S\BIN\U.DLL M.EXE dynamic link to -> NODE.DLL NODE.DLL static link to O.DLL O.DLL static link to \C\BIN\U.DLL \S\BIN\U.DLL共存于同一个流程空间,并\C\BIN\U.DLL使用其版本M.EXEU.DLL使用其O.DLL版本。

请注意,我无法重建U.DLLM.EXE来更改每次加载O.DLL的方式。它们来自第三方,因此无法更改静态链接。我也没有在U.DLL上使用LoadLibrary的选项,因为它是一个C ++库,提供了一个导入库。

我相信可以使用清单,这样当我构建静态链接到O.DLL的O.DLL时,我会在NODE.DLL的清单中进行设置,以便NODE.DLL加载它自己的O.DLL副本安装在U.DLL中。我只是无法弄清楚如何做到这一点。理想情况下,我不想修改\C\BIN\U.DLL的清单,但如果这是唯一的解决方案,我会接受它。

4 个答案:

答案 0 :(得分:3)

通过使用绝对路径加载其中一个或多个DLL,可以在同一进程中拥有多个具有相同文件名的DLL。这确实需要动态加载DLL,但行为相同。

您需要std::string moduleName = appPath + "\s\bin\u.dll"; LoadModule(moduleName.c_str()),而不是在构建过程中进行链接。因为这对于加载哪个DLL是明确的,所以它允许您使用“相同”名称加载多个DLL。

加载模块后,您可以将每个必要的函数分配给函数指针,然后将它们包装起来或使用合法但很少使用的syntax of calling functions pointers as normal functionsfuncPtr(params))。

如果您使用的是更新版本的Windows,则可以使用DLL清单来加强模块周围的版本控制/命名,并使EXE加载与通常不同的DLL。我不熟悉这将如何完成,虽然它已在MSDN上记录(也可能在这里)。

答案 1 :(得分:1)

您可以使用/ delayload链接器选项(VS项目属性中的链接器/输入/延迟加载的DLL)以及自定义挂钩,在runtiome上以编程方式解析源DLL。在您的一个源文件中,您需要定义并注册delayload挂钩函数。在钩子函数的dliNotePreLoadLibrary通知处理程序中,只需使用指向所需DLL的显式路径调用LoadLibrary,然后将DLL的HMODULE传递回delayload代码。 delayload代码会将导入的函数解析为您提供给它的DLL,无论是否已将另一个同名的DLL加载到进程中。

离开我的头顶,你的钩子看起来像这样(MyCustomLoadLibrary需要替换为调用LoadLibrary的代码,其中包含冲突情况下所需DLL的完整路径,否则只需要非限定文件名):

#include <delayimp.h>
FARPROC WINAPI MyDliNotifyHook( unsigned dliNotify, PDelayLoadInfo pdli )
{
  if( dliNotify == dliNotePreLoadLibrary )
    return (FARPROC)MyCustomLoadLibrary( pdli->szDll );
  return NULL;
}
extern "C" PfnDliHook __pfnDliNotifyHook2 = MyDliNotifyHook;

答案 2 :(得分:0)

尝试使用LoadLibrary和GetProcAddress。这将需要重构您的代码,以便在任何地方使用函数指针。参见:

MSDN web page for LoadLibrary

答案 3 :(得分:0)

你很幸运U.DLL是开源的。您需要构建一个支持 /Zc:wchar_t-/Zc:wchar_t函数的版本。第一个选项仅将wchar_t-定义为unsigned short。对于没有wchar_t参数的每个函数,你会得到大量重复符号的链接器警告,否则你最终会得到一个更胖的DLL。

请注意,如果使用static存在任何全局或wchar_t变量,那么您也将拥有这两个变量的副本。但是,如果你在一个过程中将U.DLL的两个副本用作软件,你就会有同样的效果。