加载DLL不初始化静态C++类

Ram*_* B. 7 c++ dll winapi static

我有一个在运行时加载的DLL.DLL依赖于内部工作的静态变量(它是一个std :: map),这个变量在DLL中定义.

当我在加载后从DLL调用第一个函数时,我从DLL获得了一个SegFault,从未初始化地图.从我从DLL加载中读取的所有内容,静态和全局数据初始化应该在调用DLLMain之前发生.

为了测试静态初始化,我添加了一个打印出消息的静态结构,甚至还提供了一个断点以便进行测量.

static struct a
{
  a(void) { puts("Constructing\n"); }
}statica;
Run Code Online (Sandbox Code Playgroud)

在DLLMain或函数被调用之前没有消息或中断.

这是我的加载代码:

  dll = LoadLibrary("NetSim");
  //Error Handling

  ChangeReliability   = reinterpret_cast<NetSim::ChangeReliability>
                        (GetProcAddress(dll, "ChangeReliability"));


ChangeReliability(100);
Run Code Online (Sandbox Code Playgroud)

我已经验证了dll版本是正确的,多次重建整个项目,但没有区别.我是新鲜的想法.

Pet*_*ene 9

链接DLL时,是否指定了/ ENTRY开关?如果是这样,它将覆盖链接器的默认值DllMainCRTStartup.因此,不会调用_CRT_INIT,反过来,将不会调用全局初始值设定项,这将导致未初始化的全局(静态)数据.

如果要为自己的入口点指定/ ENTRY,则需要在进程附加和进程分离期间调用_CRT_INIT.

如果未指定/ ENTRY,则链接器应使用CRT的入口点,在调用DllMain之前,在进程附加/分离时调用_CRT_INIT.


atz*_*tzz 9

我想指出应该避免DLL中的复杂静态对象.

请记住,DLL中的静态初始化器是从DllMain调用的,因此对DllMain代码的所有限制都适用于静态对象的构造函数和析构函数.特别是,std :: map可以在构造期间分配动态内存,如果C++运行时尚未初始化(如果您使用动态链接的运行时),则可能导致不可预测的结果.

有一篇关于编写DllMain的好文章:创建DLL的最佳实践.

我建议将静态地图对象更改为静态指针(可以安全地零初始化),并添加单独的DLL导出函数进行初始化,或者使用延迟初始化(即在访问它之前检查指针并创建对象如果它是空的).