使用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.DLL
。 O.DLL
静态链接到名为U.DLL
的DLL,该DLL安装在\C\BIN\U.DLL
中。 U.DLL
构建于相同的开源代码之上,但是使用Visual C ++编译器选项/Zc:wchar_t
构建,它将wchar_t
识别为本机类型。
理想情况下,公司C和公司S同意使用相同的Visual C ++选项构建U.DLL
,但这是不可能的。
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.EXE
和U.DLL
使用其O.DLL
版本。
请注意,我无法重建U.DLL
或M.EXE
来更改每次加载O.DLL
的方式。它们来自第三方,因此无法更改静态链接。我也没有在U.DLL
上使用LoadLibrary
的选项,因为它是一个C ++库,提供了一个导入库。
我相信可以使用清单,这样当我构建静态链接到O.DLL的O.DLL
时,我会在NODE.DLL
的清单中进行设置,以便NODE.DLL
加载它自己的O.DLL
副本安装在U.DLL
中。我只是无法弄清楚如何做到这一点。理想情况下,我不想修改\C\BIN\U.DLL
的清单,但如果这是唯一的解决方案,我会接受它。
答案 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 functions(funcPtr(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。这将需要重构您的代码,以便在任何地方使用函数指针。参见:
答案 3 :(得分:0)
你很幸运U.DLL是开源的。您需要构建一个支持 /Zc:wchar_t-
和/Zc:wchar_t
函数的版本。第一个选项仅将wchar_t-
定义为unsigned short
。对于没有wchar_t
参数的每个函数,你会得到大量重复符号的链接器警告,否则你最终会得到一个更胖的DLL。
请注意,如果使用static
存在任何全局或wchar_t
变量,那么您也将拥有这两个变量的副本。但是,如果你在一个过程中将U.DLL
的两个副本用作软件,你就会有同样的效果。