3

我们有一个用 C/C++ 编写的应用程序,它被分解为一个 EXE 和多个 DLL。这些 DLL 中的每一个都使用相同的静态库 ( utilities.lib)。

实用程序静态库中的任何全局变量实际上在应用程序的运行时都会有多个实例。每个链接到的模块(即 DLL 或 EXE)将有一份全局变量的副本utilities.lib

(这都是众所周知的,但值得回顾一下静态库在 DLL 上下文中如何表现的背景知识。)

现在我的问题.. 我们想改变utilities.lib它,使它成为一个 DLL。它变得非常庞大和复杂,我们希望以 DLL 形式而不是.lib形式分发它。问题在于,对于这个应用程序,我们希望保留每个应用程序 DLL 在实用程序库中拥有自己的全局变量副本的当前行为。 你会怎么做呢? 实际上我们并不需要所有的全局变量,只有一些;但如果我们得到它并不重要。


我们的想法:

  1. 我们关心的库中的全局变量并不多,我们可以用一个访问器包装它们中的每一个,该访问器执行一些时髦的技巧来试图找出哪个 DLL 正在调用它。大概我们可以遍历调用堆栈并找出HMODULEfor 每个函数,直到找到一个不是utilities.dll. 然后我们可以根据调用 DLL 返回不同的版本。
  2. 我们可以要求调用者在调用utilities.dll. 实用程序 DLL 然后可以使用这个全局变量值来确定调用上下文。
  3. 我们可以找到一些utilities.dll在运行时多次加载的方法。也许我们需要在构建时制作多个重命名的副本,以便每个应用程序 DLL 都可以拥有自己的实用程序 DLL 副本。这首先否定了使用 DLL 的一些优点,但是还有其他应用程序不需要这种“静态库”样式行为,并且仍然可以utilities.libutilities.dll.
4

2 回答 2

4

您最好让utilities.dll 导出额外的函数来分配和取消分配包含变量的结构,然后让您的每个其他工作DLL 在运行时在需要时调用这些函数,例如在DLL_ATTACH_PROCESS 和DLL_DETACH_PROCESS 阶段DllEntryPoint()。这样,每个 DLL 都会获得自己的变量本地副本,并且可以将结构作为附加参数传递回实用程序.dll 函数。

另一种方法是直接在每个工作 DLL 中本地声明各个变量,然后在需要时将它们作为输入/输出参数传递给实用程序.dll。

无论哪种方式,都不要让 utility.dll 尝试自行找出上下文信息。它不会很好地工作。

于 2009-07-02T21:12:58.917 回答
2

如果我这样做,我会排除所有有状态的全局变量——我会导出一个 COM 对象或一个包含所有必要状态的简单 C++ 类,并且每个 DLL 导出都将成为你的类上的一个方法。

回答您的具体问题:

  1. 您不能可靠地进行这样的堆栈跟踪 - 由于尾调用优化FPO等优化,您无法确定在所有情况下谁给您打电话。你会发现你的程序可以在调试中工作,主要是在发布时工作,但偶尔会崩溃。
  2. 我认为您会发现这很难管理,并且它还要求您的库不能与流程中的其他模块重入 - 例如,如果您支持回调或事件进入其他模块。
  3. 这是可能的,但是您完全否定了使用 DLL 的意义。您可以复制到不同的目录并通过完整路径加载,而不是重命名。
于 2009-07-02T21:49:24.647 回答