7

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

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

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

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

M.EXE来自 Company S 的产品是可扩展的,因为我可以在非托管 C++ 中构建自己的 DLL,如果我正确设置所有内容,NODE.DLL调用它将调用它。M.EXE我想构建它NODE.DLL,使其静态链接到O.DLL来自 Company C。但问题是,一旦运行,M.EXE它就U.DLL从公司。因此,当尝试加载时,它会失败,因为当加载时,需要的符号不存在,因为 Windows 认为已经加载。\S\BIN\S\BIN\U.DLL\C\BIN\U.DLLU.DLLM.EXENODE.DLLNODE.DLLO.DLLU.DLL\C\BIN\U.DLLU.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.DLLO.DLL使用其版本U.DLL.

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

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

4

4 回答 4

4

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

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

加载模块后,您可以将每个必要的函数分配给函数指针,然后将它们包装起来,或者使用合法但很少使用的语法将函数指针作为普通函数调用( funcPtr(params))。

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

于 2013-01-11T15:41:08.577 回答
1

您可以在运行时使用 /delayload 链接器选项(VS 项目属性中的链接器/输入/延迟加载的 DLL)和自定义挂钩以编程方式解析源 DLL。在您的一个源文件中,您需要定义和注册一个延迟加载挂钩函数。在钩子函数的 dliNotePreLoadLibrary 通知处理程序中,只需使用所需 DLL 的显式路径调用 LoadLibrary,然后将 DLL 的 HMODULE 传递回延迟加载代码。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;
于 2013-01-14T05:23:13.360 回答
0

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

请注意,如果有任何全局或static变量 using wchar_t,那么您也将拥有这些的两个副本。但是,如果您U.DLL在一个过程中硬塞两个副本,您将获得相同的效果。

于 2013-01-14T07:56:23.943 回答
0

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

LoadLibrary 的 MSDN 网页

于 2013-01-11T15:42:37.273 回答