getmodulefilename返回空或乱码主因是缓冲区未初始化或长度传错;须用tchar数组并传入字符数(非字节数),unicode下需sizeof(buf)/sizeof(tchar);接收时应据unicode宏选用std::wstring或std::string。

GetModuleFileName 为什么返回空或乱码?
直接调用 GetModuleFileName 却得不到路径,大概率是缓冲区没初始化或长度传错。这个函数不自动分配内存,必须手动提供足够大的 TCHAR 数组,并把缓冲区首地址和**字符数上限**(不是字节数)一起传进去。Windows 下宽字符编译时,sizeof(buf) 会返回字节数,除以 sizeof(TCHAR) 才是可用字符数 —— 忘了这一步,就容易截断或写越界。
常见错误写法:GetModuleFileName(NULL, buf, sizeof(buf)) —— 这在 Unicode 模式下只给了实际容量的 1/2。
正确做法:
TCHAR szPath[MAX_PATH] = {0};
GetModuleFileName(NULL, szPath, _countof(szPath));
如何安全转成 std::string 或 std::wstring?
获取到 szPath 后别直接丢给 std::string 构造——如果项目是 Unicode 编译(默认),TCHAR 就是 wchar_t,此时 std::string 会按字节逐个截断宽字符,路径瞬间变乱码或提前终止。
判断方式看是否定义了 UNICODE 或 _UNICODE;更稳妥的是统一用 std::wstring 接收:
- Unicode 模式:直接
std::wstring path(szPath) - 多字节模式(少见):用
std::string path(szPath) - 想强制跨模式兼容:用
WideCharToMultiByte转 UTF-8,但通常没必要
GetModuleFileName(NULL, ...) 和 GetModuleFileName(hInstance, ...) 有区别吗?
绝大多数情况下没区别。传 NULL 表示当前进程的主模块(即启动的 EXE),传 hInstance(WinMain 第一个参数)也指向同一个模块。但注意:hInstance 在 DLL 中无效,DLL 应该用 GetModuleHandle(NULL) 配合 GetModuleFileName,否则可能拿到宿主 EXE 的路径而非 DLL 自身路径。
所以关键不是传什么,而是“你到底想拿谁的路径”:
- 拿当前 EXE 路径 →
GetModuleFileName(NULL, ...) - 拿当前 DLL 路径 →
GetModuleFileName(GetModuleHandle(L"xxx.dll"), ...),或先HMODULE hMod = NULL; GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (LPCWSTR)&some_func_in_dll, &hMod)
路径末尾带参数或被重命名怎么办?
GetModuleFileName 返回的是磁盘上真实的 PE 文件路径,不会包含命令行参数,也不受快捷方式“起始位置”影响。但它**无法区分硬链接、符号链接或重命名后的副本**——它只返回打开该模块时系统记录的原始映像路径。比如你把 app.exe 复制为 run.exe 并运行,返回的就是 run.exe 的完整路径,不是原名。
如果需要规范路径(去掉 .、..、重复斜杠),得自己调用 PathCanonicalize 或 C++17 的 std::filesystem::canonical(注意后者在 MinGW 或旧 MSVC 上可能不可用)。
另外,路径中斜杠是反斜杠 ,不是 /;若后续要拼接子路径,别手写 "\subdir",用 std::filesystem::path 更可靠。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











