這兩天發現了一個小問題,經過一上午的排查終於找到了問題的原因——Windows 7的API函數GetOpenFileName竟然有BUG!
請參考下面的MFC代碼:
CFileDialog dlg(TRUE); dlg.m_ofn.lpstrInitialDir = _T("c:\\"); dlg.DoModal(); |
這段代碼的含義是通過"文件選擇對話框"選擇一個文件,並且"文件選擇對話框"的初始目錄是C:\。
使用VC++2010編譯上面的代碼,在64位Windows 7上的運行結果一切正常——"文件選擇對話框"的初始目錄一定是C:\
使用VC++6.0編譯上面的代碼,在64位Windows 7上的運行結果為:"文件選擇對話框"的初始目錄並不一定是C:\,而是上次選擇文件的目錄!
查看MFC代碼,就知道問題的所在了:VC++6.0的CFileDialog會調用GetOpenFileName或GetSaveFileName打開"文件選擇對話框";而VC++2010會判斷Windows的版本。如果是Vista以下(不含Vista)版本則會調用GetOpenFileName或GetSaveFileName;如果是Vista以上(含Vista)版本則會通過COM接口IFileOpenDialog或IFileSaveDialog打開"文件選擇對話框"。
為了驗證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.0的MFC類CFileDialog通過GetOpenFileName或GetSaveFileName顯示"文件選擇對話框"。但是這兩個函數在Windows 7的實現有BUG,導致初始目錄不是設定的值。解決這個問題有兩個辦法:一是舍棄VC++6.0,改用VC++2010。這樣處理最簡單,美中不足就是程序只能運行在Windows XP及其以上版本的Windows下,無法在Windows 98/Me/2000上運行;二是改進VC++2010的CFileDialog代碼,使得VC++6.0能夠編譯、使用。
另一個BUG:在Windows 7上使用GetOpenFileName選擇一個文件后,該文件所在目錄即被鎖定。目錄被鎖定就無法被刪除了,退出整個程序后目錄鎖定才會被解除。