如何将第三方 Windows DLL 组织到应用程序文件夹的子文件夹中?

发布于 2024-09-29 13:15:56 字数 1711 浏览 1 评论 0原文

我们有一个应用程序依赖于许多第三方 DLL 组。不幸的是,这些第三方 DLL 的编写者都没有对它们进行非常一致的命名,因此很难看出哪个 DLL 属于哪个组。

为了尝试管理这个问题,我们希望将第三方 DLL 组放入应用程序文件夹中的一个文件夹中,而不是像这样放在应用程序旁边。

--> Application Folder
    --> Application.exe
    --> MyDLL1.dll
    --> MyDLL2.dll
    --> Third Party 1 DLL folder
        --> Third Party 1 DLL 1.dll
        --> Third Party 1 DLL 2.dll
        --> Third Party 1 DLL 3.dll
    --> Third Party 2 DLL folder
        --> Third Party 2 DLL 1.dll
        --> Third Party 2 DLL 2.dll
        --> Third Party 2 DLL 3.dll

我的问题是如何让动态链接器找到它们并加载它们?

我们可以使用 LoadLibrary() 和 GetProcAddress() 手动完成此操作,但这非常乏味。看起来我们可以通过清单和“探测”来做到这一点,但这似乎仅限于 Windows 7(我们需要在 XP 及更高版本上工作)。

更新

我们最终使用清单来完成此操作(感谢@Chris) - 我们还必须跳过其他一些障碍,以防有人正在寻找解决方案!

首先,我们的“程序集”实际上有几个 DLL,我们先链接到一个 DLL,然后再链接到其他 DLL。所有这些 DLL 都需要将程序集依赖项添加到其清单中(您可以使用 mt.exe 来执行此操作,而无需访问这些 DLL 的源代码)。

其次,程序集需要与 DLL 一起运行,而不是与 EXE 一起运行 - 我们的 DLL 实际上是一个插件,已经位于应用程序的子文件夹中。

这是我们的最终布局:

--> Application Folder
    --> Application.exe
    --> Plugins folder
        --> MyDLL1.dll
        --> Third Party 1
            --> Third Party 1.manifest
            --> A.dll
            --> B.dll
            --> C.dll

如果MyDLL1.dll是链接到A.dll的插件,并且A.dll同时链接到B.dll和C.dll,那么:

  1. “Third Party 1.manifest”需要包含所有A.dll 、B.dll 和 C.dll 作为程序集
  2. “MyDLL1.dll”需要在其清单中添加对“第三方 1”的依赖项,否则动态链接器将找不到 A.dll
  3. A.dll 需要在其清单中添加依赖项到“Third Party 1”,否则动态链接器将找不到 B.dll 和 C.dll
  4. “Third Party 1”文件夹需要与“MyDLL1.dll”并排,而不是与“Application.exe”

对我来说,(3 )有点烦人。您可能会认为链接器会在程序集中查找依赖的 DLL。

We have an application that depends on a number of groups of third-party DLLs. Unfortunately, none of the writers of these third-party DLLs have named them very consistently so it is hard to see which DLL is part of what group.

To try and manage this, we would like to put groups of third-party DLLs in a folder in our application folder rather than along-side the application something like this.

--> Application Folder
    --> Application.exe
    --> MyDLL1.dll
    --> MyDLL2.dll
    --> Third Party 1 DLL folder
        --> Third Party 1 DLL 1.dll
        --> Third Party 1 DLL 2.dll
        --> Third Party 1 DLL 3.dll
    --> Third Party 2 DLL folder
        --> Third Party 2 DLL 1.dll
        --> Third Party 2 DLL 2.dll
        --> Third Party 2 DLL 3.dll

My question is how to get the dynamic linker to find them and load them?

We could do this manually with LoadLibrary() and GetProcAddress(), however this is intensely tedious. It looks like we might be able to do this with manifests and "probing", but this seems to be Windows 7 only (we need to work on XP and above).

Update

We used manifests to do this in the end (thanks @Chris) - there were a couple of other hoops we had to jump through in case anyone is looking for a solution!

First, our "assembly" actually has several DLLs, one that we link to that then links to others. All of these DLLs will need the assembly dependency adding to their manifests (you can use mt.exe to do this without having access to the the source code of these DLLs).

Second, the assembly needs to go alongside the DLL, not alongside the EXE - our DLL was actually a plugin that was already in a subfolder of the app.

Here is our final layout:

--> Application Folder
    --> Application.exe
    --> Plugins folder
        --> MyDLL1.dll
        --> Third Party 1
            --> Third Party 1.manifest
            --> A.dll
            --> B.dll
            --> C.dll

If MyDLL1.dll is a plugin that links to A.dll, and A.dll links to both B.dll and C.dll then:

  1. "Third Party 1.manifest" needs to include all A.dll, B.dll and C.dll as an assembly
  2. "MyDLL1.dll" needs a dependency entry in its manifest to "Third Party 1" or the dynamic linker won't find A.dll
  3. A.dll needs a dependency entry in its manifest to "Third Party 1" or the dynamic linker won't find B.dll and C.dll
  4. The "Third Party 1" folder needs to go alongside "MyDLL1.dll", not alongside "Application.exe"

For me, (3) is a bit irritating. You would think that the linker would look in the assembly for dependent DLLs.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

忘你却要生生世世 2024-10-06 13:15:56

您可以使用清单来完成此操作,而无需进行探测。
创建“假”程序集 - 通过定义包含 dll 的 .manifests。 (为此,不需要对 dll 进行任何更改)
由于 NT 5.1 (Windows XP) 中添加了程序集支持,Windows 加载程序首先通过扫描具有程序集名称的文件夹来查找程序集。

因此,举例来说,如果您需要将 Visual C 2008 的 Microsoft Visual C 运行时与您的应用程序一起分发,则可以创建如下所示的文件夹结构:

--> Application Folder
  --> Application.exe
  --> MyDll1.dll
  --> MyDll2.dll
  --> Microsoft.VC90.CRT
    --> Microsoft.VC90.CRT.manifest
    --> msvcr90.dll
    --> msvcp90.dll
    --> msvcm90.dll

此相同方案适用于您的第 3 方 dll。
然后,您需要做的就是将“假”程序集作为依赖程序集添加到应用程序的清单中(如果您的 dll 有清单,(并且它们访问第 3 方 dll),那么它们的清单也必须有条目

。描述程序集的清单文件需要 assemblyIdentity 和每个 dll 的文件节点:

<assembly manifestVersion="1.0">
  <assemblyIdentity type="Win32" name="Assembly Name" version="1.0.0.0" processorArchitecture="x86" />
  <file name="dll1.dll" />
  <file name="dll2.dll" />
</assembly>

并且您的应用程序和 dll 是使用 MS Visual Studio 2005 或更高版本构建的,以下 pragma 指令将使您的应用程序在程序集中查找 dll:

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

You can do it with manifests without probing.
Create "fake" assemblies - by defining .manifests, that contain the dlls. (No change is requried in the dll's for this)
Since assembly support was added to NT 5.1 (Windows XP) the windows loader first looks for assemblies by scanning for a folder with the assemblies name.

So, for example, if you need to distribute the Microsoft Visual C runtime for Visual C 2008 with your application, you could create a folder structure that looks like this:

--> Application Folder
  --> Application.exe
  --> MyDll1.dll
  --> MyDll2.dll
  --> Microsoft.VC90.CRT
    --> Microsoft.VC90.CRT.manifest
    --> msvcr90.dll
    --> msvcp90.dll
    --> msvcm90.dll

This same scheme would work for your 3rd party dlls.
All you would then need to do would be to add the "fake" assemblies as dependent assemblies to your application's manifest (if your dlls have manifests, (and they access the 3rd party dlls) then their manifests will have to have entries too.

The manifest files describing the assemblies need an assemblyIdentity, and a file node per dll:

<assembly manifestVersion="1.0">
  <assemblyIdentity type="Win32" name="Assembly Name" version="1.0.0.0" processorArchitecture="x86" />
  <file name="dll1.dll" />
  <file name="dll2.dll" />
</assembly>

And your application, and dlls are built with MS Visual Studio 2005 or later, the following pragma directive would make your app look for the dlls in the assemblies:

 #pragma comment(linker, "/manifestDependency:\"name='Assembly Name' processorArchitecture='*' version='1.0.0.0' type='win32' \"")
情域 2024-10-06 13:15:56

您可以使用 SetDLLDirectory 函数来指定路径( s) 用于您的 DLL。或者阅读有关使用应用程序特定路径的信息。

You can use SetDLLDirectory function to specify path(s) for your DLLs. Alternatively read information about using application-specific paths.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文