GetModuleFileName()无法获取DLL正确路径的技术咨询
解决GetModuleFileName返回EXE路径而非当前DLL路径的问题
这问题我碰到过好多次了!核心原因很简单:当你调用GetModuleFileName(NULL, ...)时,函数默认返回的是**当前进程的主可执行文件(也就是你的EXE)**的路径,而非当前代码所在DLL的路径。这就导致你拿到的是EXE目录,自然找不到同目录下的目标DLL。
正确的解决思路
要获取当前DLL的路径,关键是要把当前DLL的模块句柄(HMODULE)传给GetModuleFileName。这里有两种可靠的实现方式:
1. 在DllMain中保存模块句柄
每个DLL被加载时,系统都会调用它的DllMain函数,并且会传入该DLL的模块句柄。你可以把这个句柄存为全局变量,后续调用GetModuleFileName时直接用它:
// 全局变量,保存当前DLL的模块句柄 HMODULE g_hCurrentDll = NULL; BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: // 保存模块句柄,后续可用 g_hCurrentDll = hModule; break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } // 获取当前DLL所在目录的函数 std::wstring GetCurrentDllDirectory() { wchar_t szFullPath[MAX_PATH] = {0}; if (g_hCurrentDll != NULL) { GetModuleFileName(g_hCurrentDll, szFullPath, MAX_PATH); // 截掉文件名,只保留目录部分 wchar_t* pLastBackslash = wcsrchr(szFullPath, L'\\'); if (pLastBackslash != NULL) { *pLastBackslash = L'\0'; } } return szFullPath; }
2. 用GetModuleHandleEx反向获取模块句柄
如果不想依赖全局变量,你可以用GetModuleHandleEx,通过当前DLL中任意函数的地址来反向获取模块句柄。比如用当前函数的地址作为参数:
std::wstring GetCurrentDllDirectory() { HMODULE hModule = NULL; // 传入当前函数的地址,获取所在模块的句柄 GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCWSTR)GetCurrentDllDirectory, &hModule); wchar_t szFullPath[MAX_PATH] = {0}; if (hModule != NULL) { GetModuleFileName(hModule, szFullPath, MAX_PATH); wchar_t* pLastBackslash = wcsrchr(szFullPath, L'\\'); if (pLastBackslash != NULL) { *pLastBackslash = L'\0'; } } return szFullPath; }
加载目标DLL的完整流程
拿到DLL目录后,拼接目标DLL的路径再加载就没问题了:
// 获取当前DLL目录 std::wstring dllDir = GetCurrentDllDirectory(); // 拼接目标DLL的完整路径 std::wstring targetDllPath = dllDir + L"\\YourTargetDll.dll"; // 加载DLL HMODULE hTargetDll = LoadLibraryW(targetDllPath.c_str()); if (hTargetDll == NULL) { // 加载失败,可调用GetLastError()获取错误码排查问题 DWORD errorCode = GetLastError(); // 这里可以添加错误处理逻辑 }
重要提醒
- 千万别在
DllMain里直接调用LoadLibrary!这可能引发死锁或者加载顺序冲突,建议把DLL加载逻辑放到DllMain之外的初始化函数中,让EXE主动调用这个初始化函数来完成加载。 - 如果你的DLL是延迟加载的,上面两种方法依然有效,不用担心模块句柄获取不到的问题。
内容的提问来源于stack exchange,提问作者Vipin
相关产品推荐
相关产品推荐

