当使用Windows可执行文件作为DLL时,如何初始化C运行时

How to initialize the C runtime when using a Windows executable as a DLL

本文关键字:初始化 运行时 DLL Windows 可执行文件      更新时间:2023-10-16

我正在尝试在我的Windows可执行文件中做类和函数的单元/组件测试。我想运行实际编译的代码,而不将测试用例构建到可执行文件*中。微软的工具非常乐意从可执行文件中导出类和函数,我可以链接到它,就好像它是一个DLL。捕获-由于动态加载的可执行文件的入口点没有被调用,并且没有DllMain(从技术上讲,它不是DLL), C运行时没有在"DLL"中初始化,静态量也没有初始化**。

是否有一种方法可以在动态加载的。exe的上下文中调用CRT_INIT并使一切正常工作,或者这是荒谬的?

*如果我在这里遗漏了一些明显的东西,请随时为我指出正确的方向。

**这是我最大的问题

免责声明-我坚持我原来的答案。这应该不能工作。最佳实践是将核心代码编译为LIB或DLL,然后将该库链接到UnitTest代码和主程序代码中。

但是自从OP向我展示了他确实找到了一种使EXE作为DLL工作的方法,我觉得有必要把剩下的方法带给他…

技巧是调用_CRT_INIT。但是,由于没有调用DllMain来获取HINSTANCE句柄,您必须直接调用GetModuleHandle来获取它。然后我保留一个表来跟踪哪些线程为它调用了CRT_INIT。

我采用了他提供的示例代码,并在AppToTest.exe代码中添加了这个数据结构:

bool g_isProcessInitialized = false;
std::map<DWORD, bool>* g_threadmap;
extern "C" BOOL __stdcall _CRT_INIT(HINSTANCE, DWORD, void*);
void ThreadInit()
{
    std::map<DWORD, bool>& themap = *g_threadmap;
    DWORD dwCurrentThreadID = ::GetThreadId(GetCurrentThread());
    if (themap[dwCurrentThreadID] == false)
    {
        _CRT_INIT(GetModuleHandle("AppToTest.exe"), DLL_THREAD_ATTACH, NULL);
        themap[dwCurrentThreadID] = true;
    }
}
void ProcessInit()
{
    if (g_isProcessInitialized == false)
    {
        _CRT_INIT(GetModuleHandle("AppToTest.exe"), DLL_PROCESS_ATTACH, NULL);
        _CRT_INIT(GetModuleHandle("AppToTest.exe"), DLL_THREAD_ATTACH, NULL);
        g_isProcessInitialized = true;
        g_threadmap = new std::map<DWORD, bool>();
        std::map<DWORD, bool>& themap = *g_threadmap;
        themap[GetThreadId(GetCurrentThread())] = true;
    }
}
void APPAPI InitializeCRT()
{
    ProcessInit();
    ThreadInit();
}

然后在TestApp.exe中,我修改了"main"以提前调用InitializeCRT:

int main(int argc, char* argv[])
{
    InitializeCRT();

这似乎是有效的-即使在我取消了对标记有问题的方法的调用的注释之后。如果创建了后续线程,那么这些线程可能需要调用InitializeCRT。(它可能会工作…)

我不敢相信这真的有效。可能不适用于旧版本的Windows。

这行不通。不能像加载DLL一样动态加载EXE。有一些有限的场景涉及从EXE加载资源,但没有导出函数。

你最好把除了WinMain以外的所有东西编译成LIB或DLL。然后链接你的UnitTest.EXE和YourProgram.EXE(每个提供main或WinMain的实现)到这个库。