简体   繁体   English

如何模仿静态库但使用DLL的“应用程序中的全局变量的多个实例”行为?

[英]How to mimic the “multiple instances of global variables within the application” behaviour of a static library but using a DLL?

We have an application written in C/C++ which is broken into a single EXE and multiple DLLs. 我们有一个用C / C ++编写的应用程序,它分为单个EXE和多个DLL。 Each of these DLLs makes use of the same static library ( utilities.lib ). 这些DLL中的每一个都使用相同的静态库( utilities.lib )。

Any global variable in the utility static library will actually have multiple instances at runtime within the application. 实用程序静态库中的任何全局变量实际上都会在应用程序中的运行时具有多个实例。 There will be one copy of the global variable per module (ie DLL or EXE) that utilities.lib has been linked into. 每个模块(即DLL或EXE)的一个全局变量副本将与utilities.lib链接。

(This is all known and good, but it's worth going over some background on how static libraries behave in the context of DLLs.) (这一切都是众所周知的,但是值得讨论一下静态库在DLL上下文中的行为方式。)

Now my question.. We want to change utilities.lib so that it becomes a DLL. 现在我的问题..我们想要更改utilities.lib ,使它成为一个DLL。 It is becoming very large and complex, and we wish to distribute it in DLL form instead of .lib form. 它变得非常庞大和复杂,我们希望以DLL形式而不是.lib形式分发它。 The problem is that for this one application we wish to preserve the current behaviour that each application DLL has it's own copy of the global variables within the utilities library. 问题是,对于这个应用程序,我们希望保留当前行为,即每个应用程序DLL在实用程序库中拥有它自己的全局变量副本。 How would you go about doing this? 你会怎么做呢? Actually we don't need this for all the global variables, only some; 实际上我们并不需要这个全局变量,只有一些; but it wouldn't matter if we got it for all. 但是如果我们得到所有这一点并不重要。


Our thoughts: 我们的想法:

  1. There aren't many global variables within the library that we care about, we could wrap each of them with an accessor that does some funky trick of trying to figure out which DLL is calling it. 我们关心的库中没有很多全局变量,我们可以使用一个访问器来封装每个变量,这些访问器会尝试找出哪个DLL正在调用它。 Presumably we can walk up the call stack and fish out the HMODULE for each function until we find one that isn't utilities.dll . 据推测,我们可以向上走调用堆栈,并为每个函数找出HMODULE ,直到找到一个不是utilities.dll函数。 Then we could return a different version depending on the calling DLL. 然后我们可以根据调用DLL返回不同的版本。
  2. We could mandate that callers set a particular global variable (maybe also thread local) prior to calling any function in utilities.dll . 在调用utilities.dll任何函数之前,我们可以强制调用者设置一个特定的全局变量(也可能是本地线程)。 The utilities DLL could then use this global variable value to determine the calling context. 然后,实用程序DLL可以使用此全局变量值来确定调用上下文。
  3. We could find some way of loading utilities.dll multiple times at runtime. 我们可以找到一些在运行时多次加载utilities.dll方法。 Perhaps we'd need to make multiple renamed copies at build time, so that each application DLL can have it's own copy of the utilities DLL. 也许我们需要在构建时制作多个重命名的副本,以便每个应用程序DLL都可以拥有它自己的实用程序DLL副本。 This negates some of the advantages of using a DLL in the first place, but there are other applications for which this "static library" style behaviour isn't needed and which would still benefit from utilities.lib becoming utilities.dll . 这首先否定了使用DLL的一些优点,但是还有其他应用程序不需要这种“静态库”样式行为,并且仍然可以从utilities.lib成为utilities.dll受益。

You are probably best off simply having utilities.dll export additional functions to allocate and deallocate a structure that contains the variables, and then have each of your other worker DLLs call those functions at runtime when needed, such as in the DLL_ATTACH_PROCESS and DLL_DETACH_PROCESS stages of DllEntryPoint(). 你可能最好只是让utilities.dll导出附加函数来分配和释放包含变量的结构,然后让你的每个其他工作者DLL在运行时在需要时调用这些函数,例如在DLL_ATTACH_PROCESS和DLL_DETACH_PROCESS阶段的DllEntryPoint()。 That way, each DLL gets its own local copy of the variables, and can pass the structure back to utilities.dll functions as an additional parameter. 这样,每个DLL都获得自己的变量本地副本,并可以将结构作为附加参数传递回utilities.dll函数。

The alternative is to simply declare the individual variables locally inside each worker DLL directly, and then pass them into utilities.dll as input/output parameters when needed. 另一种方法是直接在每个worker DLL中本地声明各个变量,然后在需要时将它们作为输入/输出参数传递给utilities.dll。

Either way, do not have utilities.dll try to figure out context information on its own. 无论哪种方式,都没有utilities.dll尝试自己找出上下文信息。 It won't work very well. 它不会很好。

If I were doing this, I'd factor out all stateful global variables - I would export a COM object or a simple C++ class that contains all the necessary state, and each DLL export would become a method on your class. 如果我这样做,我会分解所有有状态的全局变量 - 我会导出一个COM对象或一个包含所有必要状态的简单C ++类,每个DLL导出将成为你的类的一个方法。

Answers to your specific questions: 您的具体问题的答案:

  1. You can't reliably do a stack trace like that - due to optimizations like tail call optimization or FPO you cannot determine who called you in all cases. 您无法可靠地执行类似的堆栈跟踪 - 由于尾部调用优化FPO优化 ,您无法确定在所有情况下谁调用了您。 You'll find that your program will work in debug, work mostly in release but crash occasionally. 您会发现您的程序将在调试中工作,主要是在发布时工作但偶尔会崩溃。
  2. I think you'll find this difficult to manage, and it also puts a demand that your library can't be reentrant with other modules in your process - for instance, if you support callbacks or events into other modules. 我认为您会发现这很难管理,并且还要求您的库不能与您的流程中的其他模块重新进行 - 例如,如果您支持回调或事件到其他模块。
  3. This is possible, but you've completely negated the point of using DLL's. 这是可能的,但你完全否定了使用DLL的意义。 Rather than renaming, you could copy into distinct directories and load via full path. 您可以复制到不同的目录并通过完整路径加载,而不是重命名。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM