c++ - 一种从中央存储库加载 DLL 的方法

标签 c++ c windows dll

我们有很多产品,每个产品的应用程序都有一些通用的 DLL。现在我们将每个公共(public) DLL 复制到每个产品的 bin 目录中,并将它们视为私有(private)程序集。这不必要地增加了每个产品的 msi 大小,并且当 DLL 中出现问题时,我们必须构建每个产品的包含 DLL 的 msi 并部署它。

有没有指示产品应用程序使用一个通用的私有(private)目录来加载 DLL [使用 list 方案..]?
[注意:将私有(private)目录添加到 PATH env 不会提供解决方案,就好像 SYSTEM 目录中存在同名 DLL 一样,这将获得我们私有(private)目录的特权]

-卡特利

最佳答案

您没有指定您的环境是 .NET 还是直接的 Win32。

我假设它的 Win32 是因为如果它是 .NET,那么就全局程序集缓存之类的东西而言,执行此操作的技术都更接近手。

在 Win32 方面,可以通过以下两种方式之一从共享位置加载 Dll:

  • 将 LoadLibrary 与显式完整路径一起使用。这意味着您不能使用静态链接 - 所有产品中使用的所有 dll 函数都必须通过 GetProcAddress 访问。您不能从通过 LoadLibrary 加载的 dll 中导入 c++ 类 - 它们必须静态链接才能工作,因此这种方法可能可行,也可能不可行。编写伪装成 dll 接口(interface)的 shim 头文件并根据每次调用的需要执行及时的 dll 加载和 GetProcAddress 并不是非常困难。
  • 另一种选择是将 dll 转换为所谓的“并行程序集”并将它们安装到 WinSxS 存储中。不要被大牌吓到。 “并行程序集”是指“一个 Dll 文件加上带有版本信息的 list 文件”。
    然后,各种应用程序中的每一个都会将“强名称”(包括版本信息)放入其使用的每个 dll 的应用程序 list 中,Win32 Dll 加载程序将使用它从 WinSxS 存储中选择正确的通用 dll 实例。 MSDN文章Guidelines for Creating Side-by-side Assemblies中描述了基本过程。


  • 在 Windows 6.1 及更高版本(Windows Server 2008 和具有讽刺意味的 Windows 7)上,应用程序配置文件现在支持 Application Configuration Files 中的探测元素

    这意味着您应该能够提供一个路径(相对于您的应用程序)到包含要加载的 dll 程序集的文件夹。

    我在 Windows 7 上做了一些测试,这有效:

    假设您在 \Program Files\App1 中安装了应用程序 app1.exe这取决于一些常见的 dll “thedll.dll”

    在应用程序文件夹 (\Program Files\App1) 中创建一个文件 App1.exe.config 并为其提供以下内容:
    <configuration>   
       <windows>
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
            <probing privatePath="..\AcmeCommon"/>
        </assemblyBinding>
      </windows>
    </configuration>
    

    现在,创建一个名为 \Program Files\AcmeCommon 的文件夹, 里面有一个文件夹 acme.thedll, 然后将 dll.dll 复制到 \Program Files\AcmeCommon\acme.thedll
    同时在 AcmeCommon\acme.thedll 中创建一个名为 acme.thedll.manifest 的文件 - 这将是描述名为“acme.thedll”的程序集的程序集 list

    acme.thedll.manifest 的内容将是:-
    <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
        <assemblyIdentity name="acme.thedll" version="1.2.3.4" processorArchitecture="x86"  type="win32"/>
        <file name="thedll.dll"/>
    </assembly>
    

    现在,我们在一个公共(public)位置拥有了公共(public) dll 作为 native sxs 程序集。我们有一个带有配置文件的应用程序,它会在 Windows 7 和 2008 服务器(及更高版本)上告诉它在公共(public)位置搜索程序集。但是该应用程序仍在尝试将 dll 作为 dll 链接到 dll,而不是通过程序集。

    为了让应用程序加载程序集,我们需要向应用程序添加一个 list 文件。如果您使用的是 Visual Studio,您的应用程序可能已经配置为通过链接器和 list 工具项目设置创建和嵌入 list 。在这种情况下,告诉应用程序有关程序集的最简单方法是在将以下代码添加到项目中的至少一个头文件或 c/cpp 文件后重建它:-
    #pragma comment(linker,"/manifestdependency:\"type='win32' name='acme.thedll' version='1.2.3.4' processorArchitecture='x86' language='*'\"")
    

    如果您使用较旧的构建环境,其中 list 是手工制作的,则需要将以下 xml 与 App1 文件夹中的 app1.exe.manifest 合并:
    <dependency>
      <dependentassembly>
        <assemblyIdentity type="win32" name="acme.thedll" version="1.2.3.4"   processorArchitecture="x86" language="*"/>
      </dependentassembly>
    </dependency>
    

    这应该结束循环:当应用程序加载时,win32 加载器将加载应用程序 list (app1.exe.manifest 或嵌入为 RT_MANIFEST 资源)并了解“acme.thedll”程序集。它还将加载应用程序配置文件 (app1.exe.config) 并了解搜索程序集的私有(private)路径。然后它将加载并将“acme.thedll.manifest”添加到应用程序的“激活上下文”中。然后,当加载器尝试加载“thedll.dll”时,它将搜索激活上下文数据库,发现它在 acme.thedll 程序集中,并从程序集位置加载它。

    关于c++ - 一种从中央存储库加载 DLL 的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1969360/

    相关文章:

    c++ - 优化索引数组求和

    c++ - 重定向 C++ 流

    c - Big Endian 与 Little Endian 填充问题

    windows - 如何在 Windows 批处理脚本或 Perl 中将文件移动到回收站?

    c++ - 在 C++ 中使用 put_time 获取毫秒精度的当前时间

    c++ - boost::trim 和 std::bind2nd

    c - 最大线程数

    c# - 使用P/invoke提高性能,可行还是一厢情愿?

    c++ - 读取硬盘字节

    c++ - 如何在 Visual C++ 中复制文件?