首先介紹一個兼容Unicode和多字節的方法,定義如下頭文件:
1 // TString.h; 2 #pragma once 3 #include <string> 4 5 #ifdef UNICODE 6 typedef std::wstring TString; 7 #ifndef _T 8 #define _T(x) L ## x 9 #endif /* END _T */ 10 #else 11 typedef std::string TString; 12 #ifndef _T 13 #define _T(x) x 14 #endif /* END _T */ 15 #endif
下面貼出兩種方式的代碼。
一般使用方法:
1 bool SelectFilePath( TString& strFilePath ) 2 { 3 TCHAR szPathName[MAX_PATH] = {0}; 4 BROWSEINFO bInfo = {0}; 5 bInfo.hwndOwner = GetForegroundWindow(); // 父窗口; 6 bInfo.lpszTitle = _T("選擇目錄"); 7 bInfo.ulFlags = BIF_RETURNONLYFSDIRS | BIF_USENEWUI /*包含一個編輯框 用戶可以手動填寫路徑 對話框可以調整大小之類的..;*/ 8 | BIF_UAHINT /*帶TIPS提示*/ /*| BIF_NONEWFOLDERBUTTON 不帶新建文件夾按鈕*/; 9 // 關於更多的 ulFlags 參考 http://msdn.microsoft.com/en-us/library/bb773205(v=vs.85).aspx; 10 11 LPITEMIDLIST lpDlist; 12 lpDlist = SHBrowseForFolder(&bInfo); 13 if ( nullptr == lpDlist ) // 單擊了確定按鈕; 14 { 15 strFilePath.clear(); 16 return false; 17 } 18 SHGetPathFromIDList(lpDlist, szPathName); 19 strFilePath = szPathName; 20 return true; 21 }
這樣打開的是根目錄,每次都定位到根目錄中, 很是麻煩。
下面介紹可以設置打開時的默認目錄。
1 // 此回調函數為全局函數或靜態函數; 2 int CALLBACK BrowseCallbackProc( HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData ) 3 { 4 switch(uMsg) 5 { 6 case BFFM_INITIALIZED: 7 { 8 ::SendMessage(hwnd, BFFM_SETSELECTION, TRUE, (LPARAM)lpData); 9 } 10 break; 11 default: 12 break; 13 } 14 return 0; 15 } 16 17 bool SelectFilePath( TString& strFilePath ) 18 { 19 TCHAR szPathName[MAX_PATH] = {0}; 20 BROWSEINFO bInfo = {0}; 21 TString strDefaultPath = _T("E:\\"); // 注意路徑中不要帶'\..\'或'\.\'符號,否則設置默認路徑失敗; 22 bInfo.hwndOwner = GetForegroundWindow(); // 父窗口; 23 bInfo.lpszTitle = _T("選擇目錄"); 24 bInfo.ulFlags = BIF_RETURNONLYFSDIRS | BIF_USENEWUI /*包含一個編輯框 用戶可以手動填寫路徑 對話框可以調整大小之類的..;*/ 25 | BIF_UAHINT /*帶TIPS提示*/ /*| BIF_NONEWFOLDERBUTTON 不帶新建文件夾按鈕*/; 26 // 關於更多的 ulFlags 參考 http://msdn.microsoft.com/en-us/library/bb773205(v=vs.85).aspx; 27 bInfo.lpfn = (CDataBackupDlg::BrowseCallbackProc); 28 bInfo.lParam = (LPARAM)(LPCTSTR)(strDefaultPath.c_str()); 29 30 LPITEMIDLIST lpDlist; 31 lpDlist = SHBrowseForFolder(&bInfo); 32 if ( nullptr == lpDlist ) // 單擊了確定按鈕; 33 { 34 strFilePath.clear(); 35 return false; 36 } 37 SHGetPathFromIDList(lpDlist, szPathName); 38 strFilePath = szPathName; 39 return true; 40 }
注意:目錄瀏覽函數不僅可以選擇目錄,也可以用來選擇一個文件。
詳細介紹一下回調函數的相關知識。
//目錄瀏覽對話框可能會像回調函數發送3種消息:
//BFFM_INITIALIZED -- 通知對話框已經初始化結束。
// 回調函數響應此消息時通常是做初始選擇
//BFFM_SELCHANGED -- 目錄瀏覽對話框當前選擇項發生變化時調用此消息。
// 回調函數響應此消息時通常是顯示所選項的相關信息
//BFFM_VALIDATEFAILED -- 表示用戶按確認按鈕時卻發現瀏覽對話框的編輯框內輸入了一個非法名稱
// 回調函數響應此消息時通常是提示客戶選擇項非法,並確定是否繼續顯示該對話框
//回調函數可以發送如下幾個消息給目錄瀏覽對話框,從而改變目錄瀏覽對話框的面目
//BFFM_SETSELECTION -- 改變當前選擇項目
//BFFM_ENABLEOK -- 改變“確認”按鈕的狀態
//BFFM_SETSTATUSTEXT-- 改變目錄瀏覽對話框中狀態行消息,當然前提是目錄瀏覽對話框中有狀態行
1 int CALLBACK BrowseCallbackProc(HWND hwnd,UINT uMsg,LPARAM lParam,LPARAM lpData) 2 { 3 switch (uMsg) 4 { 5 case BFFM_INITIALIZED: 6 { 7 //BFFM_INITIALIZED表示瀏覽對話框已經初化結束,參數lParam為NULL 8 //設置初始選項 ::SendMessage(hwnd,BFFM_SETSELECTION,TRUE,lpData); 9 10 //關於BFFM_SETSELECTION消息的說明 11 //wParam :標記lParam參數包含一個ITEMIDLIST結構(PIDL)還是一個目錄路徑名 12 // 如果為TRUE,lParam內容為路徑名;否則lParam包含一個路徑PIDL。 13 //lParam :內容為瀏覽對話框所選的路徑。如果wParam為TRUE,lParam內容為一個 14 // 以NULL結尾的字符串的指針,否則為PIDL 15 16 break; 17 } 18 case BFFM_SELCHANGED: 19 { 20 //BFFM_SELCHANGED表示選擇項已經發生變化,參數lParam包含列表中最新選中項的條目ID 21 ITEMIDLIST * pidl; 22 char path[MAX_PATH]; 23 //根據條目ID取路徑信息 24 pidl = (ITEMIDLIST*) lParam; 25 if (SHGetPathFromIDList(pidl, path)) 26 { 27 //使得“確認”按鈕生效 28 //關於BFFM_ENABLEOK消息的說明 29 //wParam :無意義,可設置為0 30 //lParam :如果為非0,則使能確認按鈕;否則失效“確認”按鈕 31 ::SendMessage(hwnd,BFFM_ENABLEOK,0,TRUE); 32 33 //讀屬性 34 DWORD attributes = ::GetFileAttributes(path); 35 36 //命令狀態行顯示當前所選項的全路徑名及其文件屬性 37 //關於BFFM_SETSTATUSTEXT消息的說明 38 //wParam :無意義,可設置為0 39 //lParam :指向一個內含狀態行提示信息的字符串 40 CString strText; 41 strText.Format("%s%s%s%s", 42 path, 43 attributes & FILE_ATTRIBUTE_HIDDEN ? ",H":"", 44 attributes & FILE_ATTRIBUTE_READONLY ? ",R":"", 45 attributes & FILE_ATTRIBUTE_SYSTEM ? ",S":"" 46 ); 47 ::SendMessage(hwnd,BFFM_SETSTATUSTEXT,0,(LPARAM)(LPTSTR)(LPCTSTR)strText); 48 } 49 else 50 { 51 //使得“確認”按鈕失效 52 ::SendMessage(hwnd,BFFM_ENABLEOK,0,FALSE); 53 54 //清狀態行信息 55 ::SendMessage(hwnd,BFFM_SETSTATUSTEXT,0,(LPARAM)(LPTSTR)(LPCTSTR)""); 56 } 57 break; 58 } 59 case BFFM_VALIDATEFAILED: 60 { 61 //BFFM_VALIDATEFAILED表示用戶在瀏覽對話框的編輯框內輸入了一個非法名稱 62 //該消息在用戶按“確認”時送出——當然前提是編輯框內輸入的名稱非法 63 //lParam參數包含了非法輸入內容的地址,應用程序可以使用這個消息提示用戶輸入非法。 64 //另外,此消息的回調函數返回0表示目錄瀏覽對話框旋即關閉,返回其他值則允許對話框繼續顯示。 65 //僅當目錄瀏覽對話框中含有編輯框並且設置了BIF_VALIDATE標記才可能出現此消息 66 //即BROWSEINFO結構中ulFlags含有BIF_EDITBOX|BIF_VALIDATE標志 67 CString strTip; 68 strTip.Format("目錄%s非法!",lParam); 69 70 //返回0允許對話框提前關閉,SHBrowseForFolder()返回NULL 71 AfxMessageBox(strTip); 72 return 0; 73 74 //返回1對話框繼續顯示,因為對話框仍繼續顯示,可以在狀態行顯示出錯消息 75 //注意:如果此時仍用AfxMessageBox來顯示提示信息,提示信息框關閉后,要使焦點重返目錄 76 //瀏覽對話框,需要客戶手工移動鼠標激活該對話框才行,這樣會使得后繼操作不是很方便,所以在狀態行顯示提示信息比較好 77 //::SendMessage(hwnd,BFFM_SETSTATUSTEXT,0,(LPARAM)(LPTSTR)(LPCTSTR)strTip); 78 //return 1; 79 break; 80 } 81 default: 82 { 83 ASSERT(FALSE); 84 } 85 } 86 return 0; 87 }
