Visual Studio 2015 Windows 窗体应用程序中的 afxwin.h 问题

Posted

技术标签:

【中文标题】Visual Studio 2015 Windows 窗体应用程序中的 afxwin.h 问题【英文标题】:afxwin.h issues in Visual Studio 2015 Windows Form App 【发布时间】:2016-02-23 11:04:31 【问题描述】:

前段时间,我编写了一个 C++ CLI Windows Form 应用程序,它在 Visual Studio 2013 中编译得很好。现在我想在 Visual Studio 2015 Update 1 中重新编译它,但我遇到了一个问题,经过数小时的测试我发现罪魁祸首是afxwin.h


TL;DR - 有什么方法可以在使用 Visual Studio 2015 编译的 Windows 窗体应用程序中使用 stdafx.h(所以 afxwin.h 和所有其他导入)而不需要启动时应用崩溃?


这是重现我在应用中遇到的相同问题的方法。

由于 Windows 窗体在 VS2015 中不再可用作项目模板,我创建了一个名为 Test

CLR 空项目

Ctrl-Shift-A 添加一个 UI > Windows 窗体 称为 MyForm

MyForm.cpp 我添加了这个:

#include "MyForm.h"

using namespace System;
using namespace System::Windows::Forms;

[STAThread]
int main(cli::array<System::String^>^ args)

    Application::EnableVisualStyles();
    Application::SetCompatibleTextRenderingDefault(false);
    Test::MyForm form;
    Application::Run(%form);

Configuration Properties > Linker > Advanced 我将 Entry Point 设置为 ma​​in

Configuration Properties > Linker > System 我将 SubSystem 设置为 Windows (/SUBSYSTEM/窗口)

编译(调试配置):编译时没有错误/警告

RUN:运行没有任何问题。

现在让我们尝试将 afxwin.h 添加到 MyForm.cpp

#include <afxwin.h>

配置属性 > 常规我将使用MFC设置为在共享DLL中使用MFC

编译(调试配置):编译时没有错误/警告

RUN:应用程序甚至无法启动,它只是在表达式 _CrtIsValidHeapPointer(block)

中显示 Debug Assertion Failed 错误

现在要修复这个错误,我发现有必要删除 Entry Point,所以:

Configuration Properties > Linker > Advanced 我删除了 Entry Point 值(我之前设置为 主要)

编译(调试配置):编译时没有错误/警告

RUN:应用程序再次无法启动,它不再显示Debug Assertion Failed,而是显示System.AccessViolationException in an unknown module和“试图读取或写入受保护的内存。这通常表明其他内存已损坏。"

这些是我在我的应用程序中遇到的错误,我想知道简单地包含afxwin.h 怎么可能在 VS2015 中出现所有这些问题,而在 VS2013 中却没有。

在不回到 VS2013 的情况下,我可以做些什么来修复它?

【问题讨论】:

【参考方案1】:

James McNellis 为 VS2015 重写了 C 运行时库。他是 C++ 的忠实粉丝,他编写的新代码遭受了 C++ 程序中常见的慢性 SIOF 问题。 Static Initialization Order Fiasco 肯定也存在于您的 VS2013 项目中,但碰巧没有字节,原始 CRT 代码已暴露于 SIOF 多年,因此可能表现得更好。

在这种情况下非常难以调试,失败的代码来自名为 thread_safe_statics.cpp 的安装中未包含的 CRT 源代码文件。鉴于没有可查看的源代码,但无法 100% 确定它的作用,但文件名几乎没有想象空间。

MFC 具有静态状态,需要在它可用之前进行初始化。特别是,程序必须有一个静态 CWinApp 变量,该变量在恰到好处的时间初始化。这要求入口点是 WinMain(),在 MFC 中实现,并在源代码中显式声明 CWinApp 实例。像这样:

[STAThread]
int main(cli::array<System::String^>^ args)

    Application::EnableVisualStyles();
    Application::SetCompatibleTextRenderingDefault(false);
    Application::Run(gcnew Test::MyForm);


class MyMfcApp : public CWinApp 
public:
    virtual int Run() override 
        return main(__nullptr);
    
 MyApp;

将链接器的 EntryPoint 设置重置为其默认值(空白),以便首先初始化 CRT,然后运行 ​​MFC 的 WinMain 函数。小心我走捷径,你不会得到args。我修复了你的 main() 函数中的一个错误,它错误地使用了 堆栈语义

这个 hack 让你的程序再次运行。它是否实际上正确是相当值得怀疑的。这受到与大框架相关的“谁是老板”综合症的困扰。不要依赖任何 MFC 窗口来正常工作,因为它是 Winforms 正在发送消息。但是你应该在 VS2013 中也遇到过这个问题。 “不要这样做”是唯一可靠的建议。

【讨论】:

感谢您的详细解释,您提供的代码解决了问题,我的应用程序恢复了工作!请注意:Linker > Advanced 配置中的Entry Point 字段empty 是必要的,否则Debug Assertion Failed再次出现错误。 对不起,你是对的,我确实使用默认值进行了测试。 CRT 初始化必须在前,MFC 的 WinMain 必须在后。

以上是关于Visual Studio 2015 Windows 窗体应用程序中的 afxwin.h 问题的主要内容,如果未能解决你的问题,请参考以下文章

在 Visual Studio Window Form 的面板上使用不透明度的任何技巧?

如何在使用WIN10 Visual Studio 2015 编译FlightGear源码(2020.1.1版本)

如何在使用WIN10 Visual Studio 2015 编译FlightGear源码(2020.1.1版本)

Visual Studio 2015 各个版本有啥区别

Visual Studio 2015 各个版本有啥区别

如何在 Windows 10 上使用 Visual Studio 2015 x64 配置和构建 Tesseract OCR C++