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

这个问题受到这个讨论的启发。
看起来DllMain(或者全局variablesctor)的C ++运行时调用的恐惧显得过时了。 我经常在dll中使用全局初始化函数,没有任何错误,现在我运行了一个特殊的testing程序(使用VC2010 Express w / o SP编译),包含带有静态运行时链接的exe模块和dynamic链接的dll。 Dll是通过LoadLibrary()从exe中手动加载的。
Dll在全局初始化期间创build并填充映射对象(因此使用运行时库,至less是内存分配函数)。 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 am[i].data(); } } 

Exe代码(用于发布configuration;将运行时库名称更改为MSVCR100D.DLL以进行debugging):

 #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 

没有失败,空指针,页面错误等

使用DependencyWalker进行分析也证实,运行时库(MSVCR100.DLL)仅在LoadLibrary调用(并且未预加载并由exe初始化)后才加载。

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

有什么想法吗?

PS。 我不鼓励将任何重量级初始化代码移到全局初始化阶段; 但我想这个简单的内存分配代码是足够安全的(?)。

加载DLL时初始化CRT是非常常见的情况,例如发生在任何COM服务器上。 因此,只要您不需要使用代码来初始化变量,而代码又依赖于危险的API调用,则您可以依靠CRT来明确支持该场景。 初始化获取托管对象是一个着名的失败模式,CLR不能在装载器锁定时被初始化。 死锁是非常丑陋的诊断,但很容易检测。 一般来说,真的,你没有任何问题发现你有问题。 只找到一个解决方法。

然而,通过使用不同的CRT实例来获得主程序和多个DLL之一,还是有很多的麻烦。 测试程序中发生了什么? 你必须非常仔细地制作DLL的导出函数,不返回任何指针或C ++对象。 你将得到返回const char *,调用者不应该获得该指针的所有权。 想必。

这一切都取决于你在DLLMain里面做什么。 由于文件拒绝说明可以做什么,不能做什么,由于CRT没有作出任何承诺,这总是感觉像一个危险的领域。

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