C++ 调用c++;从DllMain或全局初始值设定项运行时

C++ 调用c++;从DllMain或全局初始值设定项运行时,c++,windows,visual-c++,dll,C++,Windows,Visual C++,Dll,这个问题的灵感来自。 看来,关于DLLMIN(或来自全局变量Ctos)的C++运行时调用的恐惧是过时的。我经常在dll中使用全局初始值设定项,没有任何错误,现在我运行了一个特殊的测试程序(使用VC2010 Express w/o SP编译),其中包含带有静态运行时链接的exe模块和带有动态链接的dll。Dll由LoadLibrary()从exe手动加载。 Dll在全局初始化期间创建并填充映射对象(因此使用运行时库,至少使用内存分配函数)。 Dll代码: #include <map>

这个问题的灵感来自。
看来,关于DLLMIN(或来自全局变量Ctos)的C++运行时调用的恐惧是过时的。我经常在dll中使用全局初始值设定项,没有任何错误,现在我运行了一个特殊的测试程序(使用VC2010 Express w/o SP编译),其中包含带有静态运行时链接的exe模块和带有动态链接的dll。Dll由LoadLibrary()从exe手动加载。
Dll在全局初始化期间创建并填充映射对象(因此使用运行时库,至少使用内存分配函数)。 Dll代码:

#include <map>
using namespace std;

struct A{
  char* p;
  static const int num=1000;
  map<int,string> m;
  A(){ 
    for(int i=0; i<num; ++i){m[i]= *new string("some text");}
  }
};

A a;

extern "C"{
_declspec(dllexport) const char* getText(int i){ return a.m[i].data(); }
}
无故障、空指针、页面错误等

使用DependencyWalker进行评测还确认运行时库(MSVCR100.DLL)仅在LoadLibrary调用后加载(并且未预加载并由exe初始化)

在全局初始化阶段之前的dll_example.dll加载过程中,动态运行时库似乎已正确加载和初始化

有什么想法吗


另外,我不鼓励将任何重量级初始化代码移动到全局初始化阶段;但我认为简单的内存分配代码足够安全(?)

这一切都取决于您在
DLLMain中做了什么。由于文档拒绝说明什么可以做,什么不可以做,而且因为CRT没有做出任何承诺,这总是让人觉得是一个危险的领域


就我个人而言,我会将所有全局初始化移到一个从DLL导出的例程中,并坚持所有客户端在调用任何其他函数之前都要调用该例程。

在加载DLL时初始化CRT是一种非常常见的情况,例如,任何COM服务器都会发生这种情况。因此,只要不需要CRT使用依赖于危险api调用的代码初始化变量,就可以依赖CRT显式地支持该场景。初始化托管对象是一种著名的故障模式,当加载程序锁定时无法初始化CLR。死锁很难诊断,但很容易检测。这通常是正确的,你不难发现你有问题。只是找到了一个解决办法


然而,如果让主程序和一个或多个DLL使用不同的CRT实例,那就要付出很大的代价。这就是你的测试程序中发生的事情。您必须非常小心地处理DLL的导出函数,以不返回任何指针或C++对象。您可以返回const char*,调用者不应该拥有该指针。大概是吧。

内存泄漏不成问题?@AJG85:你为什么怀疑内存泄漏?当然,在这个简单的例子中没有适当的清理,但是可以添加这样的清理。@用户我只是掌握了显而易见的东西,这是我的幽默感差。更重要的是,没有什么可以说明您不能使用全局初始化,但还有其他方法。快速提示:使用四个空格缩进,而不是
来格式化代码-否则,像
这样的标题将被视为HTML标记并丢失。您可以使用格式化工具栏中的{}按钮快速格式化代码。@bdonlan:谢谢,我已将不平等性从“”返回到“”“@大卫:。。。并为特定库加载提供内联函数,而不是直接调用Winapi LoadLibrary。的确,如果显式加载库,这是一个很好的解决方案。@user我不确定您的意思。如果你能澄清,我相信我能提供一个意见!实际上,这是一个非常常见的解决方案。ComCtrls、COM、WinSock和许多其他库都使用它。@大卫:是的,这是一种常见的做法,我的意思是只内联init函数,以避免为dll创建非平凡的.lib库。@用户确定init函数和其他函数一样只是一个导出函数吗?也许我只是在昏暗——我实际上并没有真正使用C++工具。戴维:我想(自动)在用户调用库初始化函数时加载库。因此函数本身不能放在库中。我想要的不是LoadLibrary+CallInitFunc,而是CallInitFunc,并在init函数的引擎盖下加载库。(我在这里不讨论直接链接到用户exe的.lib的隐式加载情况,仅使用LoadLibrary进行动态加载)因此,如果我使用microsoft的crt(+例如microsoft stl),并且在初始化期间不调用LoadLibrary或任何其他危险的函数,这是相对安全的?(我理解多个运行时问题,尽管这是一个正交的ussue:)是的,这就是我的答案。@user将CRT包含在运行时链接中怎么可能不安全?当您在初始化时执行操作时会出现问题,这实际上是DLLMain的一部分。@David:我们讨论初始化时间,即DLLMain和全局范围初始化器。我的测试程序中的动态链接是一种尽可能延迟crt初始化的方法。我看到了在DllMain之前不初始化crt的唯一原因:可能存在“递归”加载和初始化dll的问题,因此动态crt链接是最危险的情况(我的测试涵盖了这种情况)。
#include <windows.h>
typedef const char* (*pfunc_t)(int idx);

int main(int argc, TCHAR* argv[])
{
  HMODULE h_crt= GetModuleHandle("MSVCR100.DLL");
  // ensure that runtime library is NOT loaded yet:
  MessageBox(NULL,(NULL==h_crt)? "CRT NOT loaded by .exe module": "CRT Loaded by .exe module"  ,"before LoadLibrary",MB_OK);

  HMODULE hlib=LoadLibrary("dll_example.dll");
  h_crt= GetModuleHandle("MSVCR100.DLL");
  MessageBox(NULL,(NULL==h_crt)? "CRT NOT loaded": "CRT Loaded"  ,"after LoadLibrary",MB_OK);

  pfunc_t pfunc= (pfunc_t)(void*)GetProcAddress(hlib,"getText");
  MessageBox(NULL,pfunc(99),"map[99]",MB_OK);

    return 0;
}
before LoadLibrary: CRT NOT loaded by .exe module
after LoadLibrary: CRT Loaded
map[99]: some text