在同一进程中加载​​一组 DLL 的多个副本

发布于 2024-08-31 04:26:39 字数 1768 浏览 5 评论 0原文

背景
我正在维护一个应用程序的插件。我使用的是 Visual C++ 2003。

该插件由多个 DLL 组成 - 有一个主 DLL,即应用程序使用 LoadLibrary 加载的 DLL,还有几个由主 DLL 和彼此使用的实用程序 DLL。< br> 依赖关系通常如下所示:

  • plugin.dll -> utilA.dll、utilB.dll
  • utilA.dll -> utilB.dll
  • utilB.dll -> utilA.dll、utilC.dll

您明白了。

DLL 之间的一些依赖关系是加载时的,一些是运行时的。

所有 DLL 文件都存储在可执行文件的目录中(不是必需的,只是现在的工作方式)。

问题
有一个新要求 - 在应用程序中运行插件的多个实例。
应用程序在其自己的线程中运行插件的每个实例,即每个线程调用由plugin.dll 导出的函数。然而,该插件的代码不是线程安全的——有很多全局变量等。

不幸的是,目前还不能修复整个问题,所以我需要一种方法来加载插件的多个(最多 3 个)副本同一进程中的 DLL。

选项 1:不同名称方法
为每个 DLL 文件创建 3 个副本,以便每个文件都有不同的名称。例如plugin1.dll、plugin2.dll、plugin3.dll、utilA1.dll、utilA2.dll、utilA3.dll、utilB1.dll等。应用程序将加载plugin1.dll、plugin2.dll和plugin3.dll。这些文件将位于可执行文件的目录中。

为了让每组 DLL 通过名称相互了解(以便相互依赖起作用),需要在编译时知道名称 - 这意味着 DLL 需要编译多次,只是每次使用不同的输出文件名。

不是很复杂,但我讨厌拥有 3 个 VS 项目文件副本,并且不喜欢一遍又一遍地编译相同的文件。

选项 2:并排装配方法
创建 DLL 文件的 3 个副本,每个组都在自己的目录中,并通过将程序集清单文件放入目录中将每个组定义为程序集,列出插件的 DLL。
每个 DLL 都有一个指向程序集的应用程序清单,以便加载程序找到驻留在同一目录中的实用程序 DLL 的副本。需要嵌入清单,以便在使用 LoadLibrary 加载 DLL 时找到它。我将使用 VS 更高版本中的 mt.exe 来完成这项工作,因为 VS2003 没有内置的清单嵌入支持。

我已经尝试过这种方法,并取得了部分成功 - 在 DLL 加载时发现了依赖关系,但在调用加载另一个 DLL 的 DLL 函数时却找不到依赖关系。
根据这篇文章,这似乎是预期的行为 - DLL 的激活context 仅在 DLL 加载时使用,之后它会被停用并使用进程的激活上下文。

编辑:按预期使用ISOLATION_AWARE_ENABLED - DLL 的运行时加载使用加载 DLL 的原始激活上下文。

问题
还有其他选择吗?任何快速&肮脏的解决方案就可以了。 :-)

ISOLATION_AWARE_ENABLED 是否可以与 VS2003 一起使用? 编辑:确实如此。

评论将不胜感激。

谢谢!

Background
I'm maintaining a plugin for an application. I'm Using Visual C++ 2003.

The plugin is composed of several DLLs - there's the main DLL, that's the one that the application loads using LoadLibrary, and there are several utility DLLs that are used by the main DLL and by each other.
Dependencies generally look like this:

  • plugin.dll -> utilA.dll, utilB.dll
  • utilA.dll -> utilB.dll
  • utilB.dll -> utilA.dll, utilC.dll

You get the picture.

Some of the dependencies between the DLLs are load-time and some run-time.

All the DLL files are stored in the executable's directory (not a requirement, just how it works now).

The problem
There's a new requirement - running multiple instances of the plugin within the application.
The application runs each instance of a plugin in its own thread, i.e. each thread calls functions exported by plugin.dll. The plugin's code, however, is anything but thread-safe - lots of global variables etc..

Unfortunately, fixing the whole thing isn't currently an option, so I need a way to load multiple (at most 3) copies of the plugin's DLLs in the same process.

Option 1: The distinct names approach
Creating 3 copies of each DLL file, so that each file has a distinct name. e.g. plugin1.dll, plugin2.dll, plugin3.dll, utilA1.dll, utilA2.dll, utilA3.dll, utilB1.dll, etc.. The application will load plugin1.dll, plugin2.dll and plugin3.dll. The files will be in the executable's directory.

For each group of DLLs to know each other by name (so the inter-dependencies work), the names need to be known at compilation time - meaning the DLLs need to be compiled multiple times, only each time with different output file names.

Not very complicated, but I'd hate having 3 copies of the VS project files, and don't like having to compile the same files over and over.

Option 2: The side-by-side assemblies approach
Creating 3 copies of the DLL files, each group in its own directory, and defining each group as an assembly by putting an assembly manifest file in the directory, listing the plugin's DLLs.
Each DLL will have an application manifest pointing to the assembly, so that the loader finds the copies of the utility DLLs that reside in the same directory. The manifest needs to be embedded for it to be found when a DLL is loaded using LoadLibrary. I'll use mt.exe from a later VS version for the job, since VS2003 has no built-in manifest embedding support.

I've tried this approach with partial success - dependencies are found during load-time of the DLLs, but not when a DLL function is called that loads another DLL.
This seems to be the expected behavior according to this article - A DLL's activation context is only used at the DLL's load-time, and afterwards it's deactivated and the process's activation context is used.

Edit: Works with ISOLATION_AWARE_ENABLED as expected - runtime loading of DLLs uses the original activation context of the loading DLL.

Questions
Got any other options? Any quick & dirty solution will do. :-)

Will ISOLATION_AWARE_ENABLED even work with VS2003? Edit: It does.

Comments will be greatly appreciated.

Thanks!

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

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

发布评论

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

评论(1

北城孤痞 2024-09-07 04:26:39

ISOLATION_AWARE_ENABLED 是由 Windows SDK 头文件实现的,因此可能根本不值得使用 VS2003。但是,可以下载最新的 Windows 7 SDK 并将其与 VS2003 一起使用。

您不需要使用 MT 链接清单。清单可以作为资源嵌入到没有显式知识的环境中。

将以下内容添加到 dll 的 .rc 文件中以嵌入清单。 (使用足够新的平台 sdk RT_MANIFEST 应该已经定义):

#define RT_MANIFEST 24 
#define APP_MANIFEST 1
#define DLL_MANIFEST 2

DLL_MANIFEST RT_MANIFEST dllName.dll.embed.manifest

ISOLATION_AWARE_ENABLED is implemented by the Windows SDK header files and thus probably wont worth with VS2003 at all. However, it is possible to download the latest Windows 7 SDK and use that with VS2003.

You don't need to use MT to link in manifests. Manifests can be embedded as resources in environments that dont have explicit knowledge.

Add the following to a dll's .rc file to embed a manifest. (With a recent enough platform sdk RT_MANIFEST should already be defined):

#define RT_MANIFEST 24 
#define APP_MANIFEST 1
#define DLL_MANIFEST 2

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