本文介绍了Visual Studio 2015 Windows 窗体应用程序中的 afxwin.h 问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

以下是重现我在应用中遇到的相同问题的方法.

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

Ctrl-Shift-A 添加一个名为 MyForm

UI > Windows Form

MyForm.cpp 中我添加了这个:

#include "MyForm.h"使用命名空间系统;使用命名空间 System::Windows::Forms;[STAThread]int main(cli::array^ args){Application::EnableVisualStyles();Application::SetCompatibleTextRenderingDefault(false);测试::MyForm 表单;应用::运行(%form);}

配置属性 > 链接器 > 高级下,我将入口点设置为ma​​in

Configuration Properties > Linker > System 下,我将 SubSystem 设置为 Windows (/SUBSYSTEM/WINDOWS)

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

运行:运行没有任何问题.

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

#include 现在要修复此错误,我发现有必要删除 Entry Point,因此:

配置属性 > 链接器 > 高级下我删除了入口点值(我之前设置为主要)

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

运行:该应用程序甚至无法再次启动,它不再显示调试断言失败而是未知模块中的System.AccessViolationException和尝试读取或写入受保护的内存.这通常表明其他内存已损坏."

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

我可以做些什么来修复它,而无需返回 VS2013?

解决方案

James McNellis 为 VS2015 显着重写了 C 运行时库.他是 C++ 的忠实粉丝,他编写的新代码存在慢性 SIOF 问题,这在 C++ 程序中很常见.静态初始化顺序 Fiasco 肯定也存在于您的 VS2013 项目中,但碰巧不是字节,原始 CRT 代码暴露于 SIOF 多年,因此可能表现得更好.

在这种情况下调试非常困难,失败的代码来自名为 thread_safe_statics.cpp 的安装中未包含的 CRT 源代码文件.由于没有可查看的源代码,因此不能 100% 确定它的作用,但文件名几乎没有想象力.

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

[STAThread]int main(cli::array^ args){Application::EnableVisualStyles();Application::SetCompatibleTextRenderingDefault(false);应用程序::运行(gcnew测试::MyForm);}类 MyMfcApp:公共 CWinApp {上市:虚拟 int Run() 覆盖 {返回主(__nullptr);}我的应用程序;

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

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

A while ago i wrote a C++ CLI Windows Form app, which compiled fine in Visual Studio 2013. Now i wanted to recompile it in Visual Studio 2015 Update 1 but i'm facing a problem, and after hours of tests i figured out the culprit is afxwin.h.


TL;DR - Is there any way i can use stdafx.h (so afxwin.h and all other imports coming with it) in a Windows Form app compiled with Visual Studio 2015 without having the app crash upon start?


Here's how to reproduce the same issues i'm facing in my app.

Since Windows Form is no longer available as project template in VS2015, i created a CLR Empty Project called Test

Ctrl-Shift-A to add a UI > Windows Form called MyForm

In MyForm.cpp i added this:

#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);
}

Under Configuration Properties > Linker > Advanced i set Entry Point to main

Under Configuration Properties > Linker > System i set SubSystem to Windows (/SUBSYSTEM/WINDOWS)

COMPILE (DEBUG CONFIGURATION): compiles with no errors/warnings

RUN: runs without any problem.

Now lets try adding afxwin.h to MyForm.cpp:

#include <afxwin.h>

Under Configuration Properties > General i set Use of MFC to Use MFC in a shared DLL

COMPILE (DEBUG CONFIGURATION): compiles with no errors/warnings

RUN: the app wont even start, it just shows Debug Assertion Failed error in expression _CrtIsValidHeapPointer(block)

Now to fix this error i found that it's necessary to remove the Entry Point, so:

Under Configuration Properties > Linker > Advanced i removed Entry Point value (which i previously set to main)

COMPILE (DEBUG CONFIGURATION): compiles with no errors/warnings

RUN: the app again wont even start, it no longer shows Debug Assertion Failed but System.AccessViolationException in an unknown module and "Attempted to read or write protected memory. This is often an indication that other memory is corrupt."

These are the errors i get in my app, and i'm wondering how is it possible that simply including afxwin.h gives all these problems in VS2015 while it didnt in VS2013.

Is there anything i can do to fix it, without going back to VS2013?

解决方案

The C runtime library was significantly rewritten for VS2015 by James McNellis. He's a big C++ fan, the new code he's written suffers from the chronic SIOF problem that's so common in a C++ program. The Static Initialization Order Fiasco was surely present in your VS2013 project as well but happened not to byte, the original CRT code was exposed to SIOF for many years so likely to behave better.

Excessively hard to debug in this case, the code that fails comes from a CRT source code file that is not included in the install named thread_safe_statics.cpp. Not 100% sure what it does given that there's no source code to look at but the name of the file leaves little to the imagination.

MFC has static state that needs to be initialized before it is usable. In particular, the program must have a static CWinApp variable that is initialized at Just the Right Time. That requires the entrypoint to be WinMain(), implemented in MFC, and an explicit declaration of a CWinApp instance in your source code. Like this:

[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;

Reset the linker's EntryPoint setting back to its default (blank) so the CRT is initialized first and MFC's WinMain function runs next. And beware I took a shortcut, you get no args. And I fixed a bug in your main() function, it used stack semantics incorrectly.

This hack gets your program running again. Whether it is actually correct is rather doubtful. This suffers from the "Who is the Boss" syndrome that's associated with big frameworks. Don't depend on any MFC window to work correctly since it is Winforms that is dispatching messages. But you should have had that problem in VS2013 as well. "Don't do it" is the only solid advice.

这篇关于Visual Studio 2015 Windows 窗体应用程序中的 afxwin.h 问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-03 07:24