如何初始化堆,以便常规 MFC dll 中的静态构造函数可以使用它?

Posted

技术标签:

【中文标题】如何初始化堆,以便常规 MFC dll 中的静态构造函数可以使用它?【英文标题】:How to initialize the heap so it can be used by static constructors in a regular MFC dll? 【发布时间】:2017-05-25 16:48:26 【问题描述】:

背景:我有一个带有 MFC UI 的大型遗留 C++ 应用程序。我正在尝试重构项目并将其迁移到新的 .Net UI。现在,作为第一步,我正在尝试将 Visual Studio 2015 中的 MFC exe 项目重构为可以从 exe 项目中调用的常规 MFC dll。 (见下文)我们计划逐渐将 UI 从 MFC 迁移到 .Net。我们正在尝试在飞机在空中时更换引擎...

无论如何,我在使用旧版 C++ 应用程序中的各种静态和全局变量时遇到了麻烦。当我将新的 dll 加载到 exe 中时,我得到一个访问冲突的异常。结果发现堆没有在 dll 中正确创建,我不明白为什么....

我将问题缩小到一个带有文件级静态变量的非常简单的结构。该变量在正常应用程序逻辑之前调用库加载时的构造函数。

在 MfcDll 项目的 SomeData.cpp 中

struct SomeData 
    SomeData()
    
        ::OutputDebugString("construct data\n");
        char* mem = new char[10]; // nope
        if (mem)
        
            ::OutputDebugString("got mem\n");
        
        else
        
            ::OutputDebugString("no heap\n");
        
    
;

SomeData fileLevelStatic;

输出是:

construct data
no heap

这是我在构造函数断点时的调用堆栈

MfcDll.dll!SomeData::SomeData() Line 57 C++
MfcDll.dll!`dynamic initializer for 'fileLevelStatic''() Line 63    C++
ucrtbased.dll!00007ffdc88f947d()    Unknown
MfcDll.dll!dllmain_crt_process_attach(HINSTANCE__ * const instance, void * const reserved) Line 67  C++
MfcDll.dll!dllmain_crt_dispatch(HINSTANCE__ * const instance, const unsigned long reason, void * const reserved) Line 133   C++
MfcDll.dll!dllmain_dispatch(HINSTANCE__ * const instance, const unsigned long reason, void * const reserved) Line 190   C++
MfcDll.dll!_DllMainCRTStartup(HINSTANCE__ * const instance, const unsigned long reason, void * const reserved) Line 249 C++
ntdll.dll!00007ffe005da35f()    Unknown

那么我在这里做错了什么?我需要做什么以确保我有一个可用于静态对象的堆。旧版应用程序广泛使用静态和全局变量。是的,我们想重构这些,但这是一项艰巨的任务,所以我们需要在我们这样做的同时保持它的工作......

另外,为了验证它不是 .Net 与 MFC 的关系,我正在仅使用 C++ 的解决方案中进行此特定测试。我有 MFCDll、传统的静态链接 C++ 库和一个 C++ 中的股票窗口应用程序项目,它引用了 MFCDll。所以 .Net 目前甚至不在代码中……它都是带有 MFC 和 Windows 的 C++。

【问题讨论】:

您的整个项目是否使用相同的运行时支持版本和内存模型? 什么是静态构造函数 在解决方案项目属性中,所有项目(静态库、dll和exe项目)都使用“多线程调试DLL(/MDd)” dll设置为“在a中使用MFC共享 DLL" “静态构造函数”也许我说错了。静态对象的构造函数,在某些情况下需要做复杂的事情并访问堆,就是问题所在。所以 SomeData fileLevelStatic;在应用程序代码之前调用构造函数 SomeData::SomeData() 【参考方案1】:

事实证明,遗留代码已在本地覆盖 ::operator new() 并且它正在做一些复杂的事情,现在已经被破坏了。这特别令人困惑,因为我在行上有一个断点 char* mem = new char[10];

并且 F11 直到我在 new() 函数中实际放置了一个断点之前,才进入 new 的本地实现。

所以基本上是自制的脚枪...... 叹。谢谢您的帮助。

【讨论】:

【参考方案2】:

在加载 dll 期间调用构造函数。也许到那时堆还没有为 dll 初始化。

初始化代码的正确位置是 InitInstance 和 ExitInstance 或 DllMain,您也可以在其中进行清理。将你的构造函数和析构函数代码移到那里。

【讨论】:

以上是关于如何初始化堆,以便常规 MFC dll 中的静态构造函数可以使用它?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 MFC 常规 DLL 中创建和使用 CFormView? (视觉工作室 2008)

如何静态链接我的 MFC 扩展 DLL?

使用带有共享 mfc dll 的常规 dll

MFC 应用程序中的“仅 Vista”堆损坏

在共享DLL中使用MFC与在静态库中使用MFC的区别

在共享DLL中使用MFC与在静态库中使用MFC的区别