使用 /ENTRY:main 和 /MT 运行时库编译为 /SUBSYSTEM:WINDOWS 时应用程序崩溃

Application crashes when compiled as /SUBSYSTEM:WINDOWS with /ENTRY:main and /MT runtime library

我正在尝试创建一个简单的 windows 应用程序,但基于 main() 入口点,因为我需要在其他平台上编译它。

我找到了使用 visual studio 执行此操作的特定指令,但它似乎在使用 /MD 运行时库编译时有效,但在使用 /MT 时崩溃。

这是重现崩溃的完整代码,每次都失败。 ==> 只需使用 main.cpp 文件创建一个空项目并设置:Projet -> Properties -> C/C++ -> Code Generation -> Runtime Library -> /MT

#pragma comment(linker, "/SUBSYSTEM:WINDOWS")
#pragma comment(linker, "/ENTRY:main")
#pragma comment(linker, "/INCLUDE:mainCRTStartup")

int main(int argc, char** argv)
{

    int* a = new int;
    delete a;

    return 0;
}

这会导致以下异常:

ntdll.dll!RtlpWaitOnCriticalSection()   Inconnu
ntdll.dll!RtlpEnterCriticalSectionContended()   Inconnu
ntdll.dll!RtlEnterCriticalSection() Inconnu
Application.exe!__acrt_lock(__acrt_lock_id _Lock) Ligne 55  C++
Application.exe!heap_alloc_dbg_internal(const unsigned __int64 size, const int block_use, const char * const file_name, const int line_number) Ligne 309    C++
Application.exe!heap_alloc_dbg(const unsigned __int64 size, const int block_use, const char * const file_name, const int line_number) Ligne 450 C++
Application.exe!_malloc_dbg(unsigned __int64 size, int block_use, const char * file_name, int line_number) Ligne 496    C++
Application.exe!malloc(unsigned __int64 size) Ligne 27  C++
[Code externe]  
Application.exe!main(int argc, char * * argv) Ligne 9   C++
[Code externe]  

但是如果我使用 WinMain 入口点,它不会失败:

#pragma comment(linker, "/SUBSYSTEM:WINDOWS")

int main(int argc, char** argv)
{

    int* a = new int;
    delete a;

    return 0;
}

INT WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, INT nCmdShow)
{
    return main(1, reinterpret_cast<char**>(&lpCmdLine));
}

我想在没有 MSVCRT 外部依赖的情况下进行编译,这就是我设置 /MT 模式的原因。

你有什么建议吗?我实际上已经在这个问题上工作了好几天....

将链接器选项设置为 CONSOLE(更多信息 here),仅此而已。 如果您不想要控制台,请使用 FreeConsole.

将其分离

另一个简单的解决方案是 WinMain 在 Windows 上调用自定义 main2 并在其他平台上让 main 调用相同的 main2。

#ifdef _WIN32
int __stdcall WinMain(...) { return main2(); }
#else
int main(...) { return main2(); }
#endif

入口点不是 mainWinMain,它是 MS 库中将初始化 CRT 的函数。您 main 示例不起作用,因为您绕过了该初始化。 WinMain 示例之所以有效,是因为此初始化发生在 WinMain 开始执行之前。当链接到运行时的 DLL 版本时,此初始化会在加载 DLL 时发生。

您应该指定 /SUBSYSTEM:CONSOLE,或者干脆不指定,让链接器找出正确的子系统。