慎用GetOpenFileName


這兩天發現了一個小問題,經過一上午的排查終於找到了問題的原因——Windows 7API函數GetOpenFileName竟然有BUG

請參考下面的MFC代碼:

CFileDialog dlg(TRUE);

dlg.m_ofn.lpstrInitialDir = _T("c:\\");

dlg.DoModal();

這段代碼的含義是通過"文件選擇對話框"選擇一個文件,並且"文件選擇對話框"的初始目錄是C:\

使用VC++2010編譯上面的代碼,在64Windows 7上的運行結果一切正常——"文件選擇對話框"的初始目錄一定是C:\

使用VC++6.0編譯上面的代碼,在64Windows 7上的運行結果為:"文件選擇對話框"的初始目錄並不一定是C:\,而是上次選擇文件的目錄!

查看MFC代碼,就知道問題的所在了:VC++6.0CFileDialog會調用GetOpenFileNameGetSaveFileName打開"文件選擇對話框";而VC++2010會判斷Windows的版本。如果是Vista以下(不含Vista)版本則會調用GetOpenFileNameGetSaveFileName;如果是Vista以上(含Vista)版本則會通過COM接口IFileOpenDialogIFileSaveDialog打開"文件選擇對話框"。

為了驗證GetOpenFileName函數的正確性,特編寫了如下代碼:

TCHAR                szFile[MAX_PATH] = {'\0'};

OPENFILENAME    ofn;

memset(&ofn,0,sizeof(ofn));

ofn.lStructSize        =    sizeof(ofn);

ofn.lpstrFile        =    szFile;

ofn.nMaxFile        =    MAX_PATH;

ofn.lpstrInitialDir    =    _T("c:\\");

ofn.Flags        =    OFN_HIDEREADONLY | OFN_EXPLORER

            |    OFN_ENABLESIZING;

GetOpenFileName(&ofn);

使用VC++2010編譯上面的代碼,執行結果也不正常了:"文件選擇對話框"的初始目錄並不一定是C:\,而是上次選擇文件的目錄!這說明:在Windows 7操作系統下,GetOpenFileName函數未能識別參數ofn.lpstrInitialDir,這應該是一個BUG

結論:VC++6.0MFCCFileDialog通過GetOpenFileNameGetSaveFileName顯示"文件選擇對話框"。但是這兩個函數在Windows 7的實現有BUG,導致初始目錄不是設定的值。解決這個問題有兩個辦法:一是舍棄VC++6.0,改用VC++2010。這樣處理最簡單,美中不足就是程序只能運行在Windows XP及其以上版本的Windows下,無法在Windows 98/Me/2000上運行;二是改進VC++2010CFileDialog代碼,使得VC++6.0能夠編譯、使用。

另一個BUG:在Windows 7上使用GetOpenFileName選擇一個文件后,該文件所在目錄即被鎖定。目錄被鎖定就無法被刪除了,退出整個程序后目錄鎖定才會被解除。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM