MFC/控制台程序啟動時,需在可執行文件所在目錄下創建同名文件夾存放數據。例如 D:\KFS\codes\22222\Release\22222.exe → 創建 D:\KFS\codes\22222\Release\22222\。
DWORD GetModuleFileName(
HMODULE hModule, // NULL = 當前進程的 .exe
LPSTR lpFilename, // 接收路徑的緩衝區
DWORD nSize // 緩衝區大小
);
D:\Path\To\Program.exeGetModuleFileNameW,返回 wchar_t*#include <windows.h>
#include <iostream>
#include <io.h>
#include <string>
#include <direct.h> // _mkdir
using namespace std;
int main() {
char exePath[MAX_PATH];
// 獲取可執行文件完整路徑
GetModuleFileNameA(NULL, exePath, MAX_PATH);
cout << "EXE 路徑: " << exePath << endl;
// 提取目錄路徑 + 文件名(不含擴展名)
string fullPath(exePath);
size_t lastSlash = fullPath.find_last_of("\\/");
size_t lastDot = fullPath.find_last_of('.');
string dirPath = fullPath.substr(0, lastSlash + 1); // 目錄(含尾部斜槓)
string exeName = fullPath.substr(lastSlash + 1, lastDot - lastSlash - 1); // 純文件名
string targetDir = dirPath + exeName; // 目標文件夾完整路徑
cout << "目標文件夾: " << targetDir << endl;
// 創建目錄(存在則不報錯)
if (_access(targetDir.c_str(), 0) == -1) {
if (_mkdir(targetDir.c_str()) == 0) {
cout << "創建成功!" << endl;
} else {
cerr << "創建失敗: " << strerror(errno) << endl;
}
} else {
cout << "目錄已存在。" << endl;
}
// 演示:在目標目錄創建測試文件
string testFile = targetDir + "\\test.txt";
FILE* fp = fopen(testFile.c_str(), "w");
if (fp) {
fprintf(fp, "Hello from %s\n", exeName.c_str());
fclose(fp);
cout << "測試文件已寫入。" << endl;
}
return 0;
}
VS 默認 Unicode 字符集,GetModuleFileName 映射為 GetModuleFileNameW,參數需 wchar_t*。解決方案:
GetModuleFileNameW + wstring + _wmkdir / _waccessTCHAR、_T() 宏,配合 GetModuleFileName 自動適配// 更安全的路徑分離(處理無擴展名、根目錄等邊界情況) #include <shlwapi.h> // 需鏈接 Shlwapi.lib #pragma comment(lib, "Shlwapi.lib") char dir[MAX_PATH], fname[MAX_PATH], ext[MAX_PATH]; PathRemoveFileSpecA(exePath); // 就地截取目錄 strcpy_s(dir, exePath); PathStripPathA(exePath); // 就地提取文件名 PathRemoveExtensionA(exePath); // 就地去擴展名 strcpy_s(fname, exePath); // 目標路徑 = dir + "\\" + fname
// C++17 std::filesystem (GCC 8+, MSVC 19.14+, Clang 7+)
#include <filesystem>
namespace fs = std::filesystem;
fs::path exePath = fs::canonical("/proc/self/exe"); // Linux
// fs::path exePath = fs::canonical(GetModuleFileName...); // Windows
fs::path targetDir = exePath.parent_path() / exePath.stem();
fs::create_directories(targetDir);
| 問題 | 原因 | 解決 |
|---|---|---|
| 編譯錯誤 C2664 | Unicode 字符集下 LPSTR/LPWSTR 不匹配 | 改字符集或用 W 版 API |
| 路徑截斷 | MAX_PATH (260) 限制 | 用 GetModuleFileNameW + 大緩衝區或 \\?\ 前綴 |
| 創建失敗 | 權限不足、路徑包含非法字符 | 檢查 errno、轉義路徑 |
| 相對路徑錯誤 | 工作目錄非 EXE 目錄 | 始終用 GetModuleFileName 獲取絕對路徑 |
Windows 下 GetModuleFileName + 字符串處理是標準做法;現代 C++ 首選 std::filesystem 實現跨平台、類型安全、異常安全的路徑操作。理解字符集機制是避免編譯錯誤的關鍵。