如何在 exe 中手动初始化 c 运行时?

How to manually initialise the c runtime in an exe?

我正在尝试使用 linker 开关“/entry”为可视化 C++ 可执行文件提供我自己的入口点。相关的 Microsoft 文档详细介绍了如何在 dll 中手动初始化 c 运行时,但我无法掌握如何在我的 exe 中初始化它。我得到的最好的是我需要调用 _CRT_init,但我不知道那是一个函数还是一个宏,或者它可能在哪里定义,并且 Visual Studio(和 msbuild)不' 识别标识符,所以那里没有提示。

这里的基本原理是我正在尝试使用 Google Test 对可执行文件进行单元测试,但不会 link 因为 main() 冲突。 GTest FAQ 中提到的两种方法并不是真正通用的,需要对大约 30 个遗留可执行文件进行大量修改才能实现。重命名每个单元测试应用程序的 main() 似乎是一种超级简单的方法,如果我能初始化 c 运行时就好了。

所以我今天下午搜索了C Runtime源码,答案是"no"。如果要使用 C 运行时,则不能提供自己未命名为 main 的可执行入口点。除了 _CRT_INIT() 是 dll 的初始化函数(mainCRTStartup() 是可执行文件的初始化函数之一),mainCRTStartup() 及其类似的名称调用 main()

  • 您可以在独立的包装器模块中初始化 CRT,该模块具有 主要的; obj1
  • 将所有现有的 exe 模块的 main 重命名为 xx_main; obj2, obj3.... objn
  • Link obj1(主要)(obj2, obj3.... objn).

To test a foo.cc file, you need to compile and link it into your unit test program

这个方案有什么问题?

虽然没有具体记录,但可以像在 DLL 中一样在可执行文件中初始化 CRT。

EXTERN_C BOOL WINAPI _CRT_INIT( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved );

// ThreadProc for CreateRemoteThread, a possible use case.
DWORD WINAPI ArbitraryAlternateEntryPoint( LPVOID )
{
    _CRT_INIT( GetModuleHandle( NULL ), DLL_PROCESS_ATTACH, NULL );

    // CRT functions can be used here.

    _CRT_INIT( GetModuleHandle( NULL ), DLL_PROCESS_DETACH, NULL );

    return 0;
}

documentation 建议除了初始调用之外,还应为每个新线程调用 _CRT_INIT,但实际上这不是必需的。