调用GetProcAddress获取的DLL函数后代码无法执行,如何异步处理?
问题描述
- 已创建包含导出函数
GameStart的game.dll,该函数内部包含无限游戏循环及其他逻辑 - 在Windows控制台程序中通过
GetProcAddress获取并调用GameStart后,调用语句之后的代码完全无法执行 - 关闭游戏窗口时,控制台程序会随之终止,尝试解锁控制台未找到可行方法
- 需求:实现异步调用或其他解决方案,让控制台程序能正常执行后续代码,且游戏窗口关闭不影响控制台程序
原代码示例
#include <stdio.h> #include <windows.h> typedef int (*MYPROC)(LPTSTR); VOID main(VOID) { HINSTANCE hinstLib; MYPROC ProcAdd; BOOL fFreeResult, fRunTimeLinkSuccess = FALSE; hinstLib = LoadLibrary(TEXT("Game")); if (hinstLib != NULL) { ProcAdd = (MYPROC) GetProcAddress(hinstLib, TEXT("GameStart")); if (NULL != ProcAdd) { fRunTimeLinkSuccess = TRUE; ProcAdd(); } // 这段代码永远无法执行,因为GameStart内部是无限循环 fFreeResult = FreeLibrary(hinstLib); } if (! fRunTimeLinkSuccess) printf("Message via alternative method\n"); }
解决方案
1. 使用CreateThread异步调用GameStart
把GameStart放到单独线程中执行,主线程即可正常运行后续代码。注意调整函数指针类型以匹配线程入口要求:
#include <stdio.h> #include <windows.h> // 匹配线程入口函数的签名要求 typedef DWORD(*GAME_START_PROC)(LPVOID); VOID main(VOID) { HINSTANCE hinstLib; GAME_START_PROC GameStart; BOOL fFreeResult, fRunTimeLinkSuccess = FALSE; HANDLE hGameThread = NULL; hinstLib = LoadLibrary(TEXT("Game")); if (hinstLib != NULL) { GameStart = (GAME_START_PROC) GetProcAddress(hinstLib, TEXT("GameStart")); if (NULL != GameStart) { fRunTimeLinkSuccess = TRUE; // 创建独立线程执行GameStart hGameThread = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)GameStart, NULL, 0, NULL ); } // 现在这段代码可以正常执行 printf("Game thread started, main thread continues...\n"); fFreeResult = FreeLibrary(hinstLib); } if (! fRunTimeLinkSuccess) printf("Message via alternative method\n"); // 可选:等待游戏线程结束(注释则主线程直接继续) // WaitForSingleObject(hGameThread, INFINITE); // CloseHandle(hGameThread); // 保持控制台窗口打开 printf("Press any key to exit...\n"); getchar(); }
注意事项
- 若
GameStart的签名与线程入口(返回DWORD、参数为LPVOID)不匹配,需修改dll中的函数定义,或在控制台端做适配包装 - 若主线程与游戏线程有共享数据,需用
CreateMutex等同步机制保证线程安全
2. 修改GameStart函数,添加退出控制
如果有权限修改game.dll,可以给GameStart加退出逻辑,让函数能主动返回,主线程即可继续执行:
// game.dll中的修改 volatile BOOL g_bGameExit = FALSE; // 导出函数,调整签名匹配线程要求 DWORD GameStart(LPVOID param) { while (!g_bGameExit) { // 处理窗口消息,捕获关闭事件 MSG msg; if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_CLOSE) { g_bGameExit = TRUE; DestroyWindow(msg.hwnd); // 不调用PostQuitMessage,避免终止整个进程 } TranslateMessage(&msg); DispatchMessage(&msg); } // 其他游戏循环逻辑 } return 0; } // 额外导出函数,用于外部触发退出 __declspec(dllexport) void StopGame() { g_bGameExit = TRUE; }
控制台端可通过调用StopGame主动终止游戏循环,同时避免游戏窗口关闭时连带终止控制台进程。
3. 分离游戏与控制台为独立进程
如果希望游戏窗口关闭完全不影响控制台,可将game.dll封装成独立EXE,控制台通过CreateProcess启动游戏进程:
#include <stdio.h> #include <windows.h> VOID main(VOID) { STARTUPINFO si = {0}; PROCESS_INFORMATION pi = {0}; si.cb = sizeof(si); // 启动独立的游戏EXE if (CreateProcess(TEXT("Game.exe"), NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { printf("Game process started successfully\n"); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } else { printf("Failed to start game, error: %d\n", GetLastError()); } printf("Main thread continues running...\n"); printf("Press any key to exit...\n"); getchar(); }
关键注意点
- 游戏窗口默认与控制台进程关联,关闭时会发送
WM_QUIT终止整个进程,可通过在窗口过程中拦截WM_CLOSE、不调用PostQuitMessage解决 - 跨线程/进程的资源访问必须保证线程安全
内容的提问来源于stack exchange,提问作者Леонид Русаков
相关产品推荐
相关产品推荐

