C++ 更改静态链接DLL的DLL搜索路径

C++ 更改静态链接DLL的DLL搜索路径,c++,dll,linker,redirect,manifest,C++,Dll,Linker,Redirect,Manifest,我已经搜索过如何实现这一点的任何提示,但我找到的只是如何将SxS DLL重定向到本地应用程序文件夹。 以下是我想要实现的目标: (C++)Application.exe链接到一个DLL Plugin.DLL(依赖项目)。此DLL不放在应用程序目录中,而是放在名为“插件”的子文件夹中。由于DLL是静态链接的,应用程序将尝试从应用程序文件夹加载它 有什么方法可以更改此特定DLL的搜索路径吗?通过清单或VS2008链接器配置?我的第一个想法是,如果静态链接dll,它不是插件。只要把dll放在EXE文件

我已经搜索过如何实现这一点的任何提示,但我找到的只是如何将SxS DLL重定向到本地应用程序文件夹。 以下是我想要实现的目标: (C++)Application.exe链接到一个DLL Plugin.DLL(依赖项目)。此DLL不放在应用程序目录中,而是放在名为“插件”的子文件夹中。由于DLL是静态链接的,应用程序将尝试从应用程序文件夹加载它


有什么方法可以更改此特定DLL的搜索路径吗?通过清单或VS2008链接器配置?

我的第一个想法是,如果静态链接dll,它不是插件。只要把dll放在EXE文件夹中,就可以完成了。这是windows支持的静态加载DLL的部署配置

也就是说,有很多方法可以实现你想要的。但它们大多是愚蠢的,或者毫无理由的复杂:你的选择是:

  • 不要静态链接。使用LoadLibrary(“plugins/Plugin.dll”)&GetProcAddress访问插件内容
  • 将“插件文件夹的路径”添加到系统路径环境变量中
  • 使用延迟加载机制延迟访问插件功能,设置可以使用提供的路径加载dll的
  • 将plugins文件夹转换为程序集(通过在其中创建一个列出plugin.dll的.manifest文件)。将“插件”作为从属程序集添加到应用程序中。现在它将在plugins文件夹中查找
  • 将应用程序拆分为存根exe和动态加载的部分。在stub exe中,调用SetDllDirectory指向plugin文件夹,然后调用LoadLibrary,将完整路径传递到“appstub.dll”

要将具有一个或多个dll的文件夹转换为“程序集”,只需向文件夹中添加一个名为folders.manifest的文件

因此,plugins.manifest:-

<assembly manifestVersion="1.0">
  <assemblyIdentity type="Win32" name="Plugins" version="1.0.0.0" processorArchitecture="x86" />
  <file name="Plugin.dll"/>
</assembly>
展开并删除“assembly”子目录:

#pragma comment(linker, "/manifestdependency:\"name='Plugins' "\
                        "processorArchitecture='*' version='1.0.0.0' "\
                        "type='win32'\"")

旁注:Chris还有两篇关于更多细节的精彩文章:

  • 本章还介绍了如何利用应用程序配置文件中的
    探测privatePath
    ,将DLL置于子文件夹之外


MS docs 这实际上被称为a,MS文档会这样解释:

专用程序集安装在应用程序的 目录结构。通常,这是包含 应用程序的可执行文件。专用程序集可以部署在中 与应用程序相同的文件夹,位于与应用程序同名的文件夹中 程序集,或位于具有相同名称的特定于语言的子文件夹中 作为大会

例如(…)

Appdir\Microsoft.Tools.Pop\Microsoft.Tools.Pop.MANIFEST
:清单作为单独的文件部署在具有程序集名称的子文件夹中

(……)

可以通过任何可以将程序集文件复制到此文件夹中的安装方法安装专用程序集,例如
xcopy
命令

榜样 您在程序文件夹
C:\Test\program\app.exe
中找到了可靠的旧可执行文件,并且您希望----从
Plugins
子文件夹加载DLL文件,即
C:\Test\program\Plugins\tool1.DLL
,而不影响
PATH
或任何其他内容

您需要:

  • 使用以下命令编译app.exe:

    #pragma comment(linker, "/manifestdependency:\"name='Plugins' version='1.0.0.0' type='win32'\"")
    // name, type and version seems to be the minimum info to get away with
    
    注意:在我的测试系统上需要编译/链接这个,而不是使用外部清单(
    app.exe.manifest
    ),我还没有找到原因。(*a)

    但是,使用
    mt
    工具将下面列出的清单文件嵌入/合并到可执行文件中,而不是使用链接器pragma。(
    配置>清单工具>其他清单文件

  • 将tool1.dll介绍放入
    插件
    子文件夹

  • 将plugins.manifest文件添加到plugins子文件夹中,即
    C:\Test\Program\plugins\plugins.manifest
    ,该文件如下所示:
plugins.manifest:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <assemblyIdentity
                            type="win32"
                            name="Plugins"
                            version="1.0.0.0"
            />
    <file name="tool1.dll"/>
</assembly>

就这样。启动app.exe将在加载时自动在子文件夹中找到dll


(*a):合并此清单文件是可行的,但您不能将其用作唯一的外部清单文件,我怀疑这是因为它缺少构建系统已放置到可执行文件中的所有其他清单信息

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <dependency>
        <dependentAssembly>
            <!-- Note: type: The value must be win32 and all in lower case. Required. --> 
            <!-- Note: version: The value must be win32 and all in lower case. Required. --> 
            <assemblyIdentity
                                    type="win32"
                                    name="plugins"
                                    version="1.0.0.0"
            />
        </dependentAssembly>
    </dependency>
</assembly>


谢谢-我现在选择了GetProcAddress方法,因为我不知道清单的外观如何才能使“假汇编”方法工作。幸运的是,这在整个体系结构中运行良好;有一个
\uu pfnDliNotifyHook2
钩子,您可以直接调用
LoadLibrary(“.\\plugins\\PluginX.dll”)
%PATH%
的想法有点脆弱,因为它在要检查的位置列表中排名较低。谢谢。我个人从未使用过延迟加载,所以我只是假设setdldirectory将是调整它的方法。我有一部分不同意。我支持为第三方应用程序提供OCX的应用程序。我们无法控制第三方应用程序。我们可以将OCX安装到与EXE相同的文件夹中。但是,第三方会删除此文件夹,并在升级其应用程序时重新创建它。这意味着我们的OCX需要重新安装。这对于用户群来说是非常有问题的。我们将OCX部署到一个唯一的文件夹中,并将路径添加到path环境变量中。这很复杂,但并不愚蠢。numpy wiki@also是一个很好的总结。外部清单文件只在没有嵌入清单文件的情况下使用。VS编译器现在默认嵌入清单,因此清单的运行时加载