今天完成一個(gè)需求,就是記住用戶選擇的文件路徑,先是熟悉代碼,然后在網(wǎng)上找解決方法,一開始感覺沒什么,網(wǎng)上的方法差不多,應(yīng)該很容易做出來,結(jié)果真是卡了一半天,到晚上自己才慢慢的搞清楚了。 遇到的問題真不少,記錄一下好多細(xì)節(jié),真是不寫不知道。 2016-08-18 21:35:36補(bǔ)充: 1.基本方法http://blog.csdn.net/shuilan0066/article/details/7302904 http://www.cnblogs.com/Hisin/archive/2012/02/27/2370614.html 這兩篇是比較清楚的。 先認(rèn)識(shí)了 SHBrowseForFolder打開文件夾時(shí),每次都是從根目錄打開。要記住上次的路徑或者設(shè)置默認(rèn)路徑,需要寫個(gè)回掉函數(shù)。 CFileDialog會(huì)自動(dòng)記住上次路徑 int CALLBACK BrowseCallBackFun(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) { switch(uMsg) { case BFFM_INITIALIZED: //選擇文件夾對(duì)話框初始化 //設(shè)置默認(rèn)路徑為lpData即'D:\' ::SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData); //在STATUSTEXT區(qū)域顯示當(dāng)前路徑 ::SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, lpData); //設(shè)置選擇文件夾對(duì)話框的標(biāo)題 ::SetWindowText(hwnd, TEXT("請(qǐng)先設(shè)置個(gè)工作目錄")); break; case BFFM_SELCHANGED: //選擇文件夾變更時(shí) { TCHAR pszPath[MAX_PATH]; //獲取當(dāng)前選擇路徑 SHGetPathFromIDList((LPCITEMIDLIST)lParam, pszPath); //在STATUSTEXT區(qū)域顯示當(dāng)前路徑 ::SendMessage(hwnd, BFFM_SETSTATUSTEXT, TRUE, (LPARAM)pszPath); } break; } return 0; } 回掉函數(shù)首先搞清楚參數(shù)的意義 2.SHBrowseForFolder函數(shù)打開文件目錄對(duì)話框,我找到的方法就是使用SHBrowseForFolder函數(shù),這個(gè)函數(shù)的原型是LPITEMIDLIST SHBrowseForFolder(LPBROWSEINFO lpbi)。函數(shù)很簡單,就一個(gè)返回值和一個(gè)參數(shù)。參數(shù)簡單羅列如下 typedef struct _browseinfo { HWND hwndOwner; // 父窗口句柄 LPCITEMIDLIST pidlRoot; // 要顯示的文件目錄對(duì)話框的根(Root) LPTSTR pszDisplayName; // 保存被選取的文件夾路徑的緩沖區(qū) LPCTSTR lpszTitle; // 顯示位于對(duì)話框左上部的標(biāo)題 UINT ulFlags; // 指定對(duì)話框的外觀和功能的標(biāo)志 BFFCALLBACK lpfn; // 處理事件的回調(diào)函數(shù) LPARAM lParam; // 應(yīng)用程序傳給回調(diào)函數(shù)的參數(shù) int iImage; // 文件夾對(duì)話框的圖片索引 } BROWSEINFO, *PBROWSEINFO, *LPBROWSEINFO 一般而言父窗口句柄(hwndOwner)和根(pidlRoot)設(shè)置為Null就可以了,pszDisplayName設(shè)定一塊MAX_PATH大小的緩沖區(qū),跟顯示相關(guān)的參數(shù)就是對(duì)話框提示標(biāo)題(lpszTitle)、對(duì)話框樣式(ulFlags)、設(shè)定對(duì)話框的缺省路徑的操作(lpfn和lParam)以及對(duì)話框任務(wù)欄上顯示的圖標(biāo)(iImage)。 由于返回值LPITEMIDLIST是一個(gè)指向ITEMIDLIST的指針,這個(gè)ITEMIDLIST涉及到Windows Shell中關(guān)于管理諸如文件、網(wǎng)絡(luò)上的計(jì)算機(jī)、控制面板程序、回收站等等對(duì)象的知識(shí)點(diǎn),Windows Shell為了識(shí)別具體的每一個(gè)對(duì)象,就使用了ITEMID來唯一識(shí)別和區(qū)分,而ITEMIDLIST就是一個(gè)完整的對(duì)象路徑。顯然這個(gè)函數(shù)可以用來瀏覽非文件對(duì)象,比如局域網(wǎng)內(nèi)的電腦等等,在這里這個(gè)LPITEMIDLIST返回的對(duì)象路徑是一個(gè)文件夾的路徑,Windows提供了一個(gè)函數(shù)BOOL SHGetPathFromIDList(LPCITEMIDLIST pidl, LPSTR pszPath)來實(shí)現(xiàn)從對(duì)象路徑轉(zhuǎn)化為文件夾路徑。 弄清楚每個(gè)參數(shù)的意義,然后才能按需求設(shè)定初值。先太盲目了,只知道套別人的,根本就沒有理解。 LPCITEMIDLIST pidl = NULL; BROWSEINFO bi; bi.hwndOwner = AfxGetMainWnd()->GetSafeHwnd(); bi.pidlRoot = NULL; bi.pszDisplayName = folderName; bi.lpszTitle = _T("請(qǐng)選擇用于保存的文件夾"); bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT;; bi.lpfn = BrowseCallbackProc; //回調(diào)函數(shù) bi.iImage = 0; bi.lParam = long(&szPath); //設(shè)置默認(rèn)路徑,傳給回掉函數(shù)的參數(shù) pidl = SHBrowseForFolder(&bi); if (pidl) { SHGetPathFromIDList(pidl, szPath); } 3.回掉函數(shù)先看別人說設(shè)置全局的靜態(tài)變量,然后設(shè)置靜態(tài)變量和靜態(tài)函數(shù),開始編譯通不過,要搞清楚類里面怎么寫這種特殊的靜態(tài)變量和函數(shù)。 靜態(tài)變量初始化,在cpp中,回掉函數(shù)的定義.h中static,cpp不需要了。 感覺回掉函數(shù)只是發(fā)送了一些消息,根本就沒有什么其他的用處,然后有人用lpData設(shè)置初始化路徑,每次將選中的路徑賦值給IpData也可以完成功能。 4.記住路徑在軟件開啟的時(shí)候,設(shè)置全局變量,每個(gè)更新默認(rèn)的路徑即可,但是重新開啟軟件的時(shí)候,采用先寫入注冊(cè)表中,然后再讀注冊(cè)表的路徑,這樣就解決了問題。也可以寫到ini文件中。 5.CString與TCHAR數(shù)組 相互轉(zhuǎn)換TCHAR數(shù)組轉(zhuǎn)到CString很簡單:使用CString的Format就行。 TCHAR m_buf[100] = _T("Hello"); CString str; str.Format(L"%s",m_buf); 現(xiàn)在就來CString轉(zhuǎn)為TCHAR數(shù)組,這個(gè)就有點(diǎn)麻煩了。因?yàn)榫W(wǎng)上有很多的解決方案,但是都不怎么理想。我們使用_tcscpy()宏。 CString str = L"sssssss"; TCHAR m_buf[20]; _tcscpy(m_buf, str); //類型之間的轉(zhuǎn)換真麻煩,知道定義這個(gè)宏的好處了。 自己找了半天,這個(gè)方法很有效!用memcpy,strcpy都不行。。。 TCHAR szDefaultDir[MAX_PATH]; CString strDef(_T("E:\\")); memcpy(szDefaultDir, strDef.GetBuffer(strDef.GetLength() * 2), strDef.GetLength() * 2); strDef.ReleaseBuffer(); szDefaultDir[strDef.GetLength()] = 0; 這樣也是一種方法吧。 |
|