在 MFC 開發中,CFile::Open 若未指定完整路徑,預設會在進程目前工作目錄尋找檔案。然而,一旦呼叫過 CFileDialog 並由使用者選取檔案,進程的工作目錄就會被切換至該檔案所在資料夾,導致後續相對路徑開啟檔案行為改變。本文說明此現象並提供因應對策。
GetCurrentDirectory 回傳專案執行檔目錄(如 D:\MyApp\)。CFileDialog 選取 C:\Program Files\desktop.ini → 關閉對話框後,GetCurrentDirectory 變為 C:\Program Files\。CFile::Open("data.dat"),實際會去 C:\Program Files\data.dat 而非專案目錄。CString strPath;
GetCurrentDirectory(MAX_PATH, strPath.GetBuffer(MAX_PATH));
strPath.ReleaseBuffer();
AfxMessageBox(_T("目前工作目錄:\n") + strPath);
CFileDialog 內部呼叫 GetOpenFileName,該 API 預設會將進程工作目錄設為使用者最後瀏覽的資料夾(除非指定 OFN_NOCHANGEDIR 標旗,但 MFC 封裝未暴露此選項)。
// 專案啟動時
CString g_strAppPath;
GetCurrentDirectory(MAX_PATH, g_strAppPath.GetBuffer(MAX_PATH));
g_strAppPath.ReleaseBuffer();
// 後續開檔
CFile file;
file.Open(g_strAppPath + _T("\\data.dat"), CFile::modeRead);
配合 CFileDialog::GetPathName() 取得完整路徑傳給 CFile::Open,避免相對路徑歧義。
CFileDialog 關閉後呼叫 SetCurrentDirectory(g_strAppPath),但不建議,因多執行緒環境下會互相干擾。
Get/SetCurrentDirectory 成對保護(需考慮執行緒安全)。這是 MFC 開發中常見卻易被忽略的坑,理解機制後即可輕鬆規避。