由於各種應用,我們需要調用系統的打開文件對話框或者打開文件夾對話框,或兩者兼有。今遇到這個情況已經解決,特寫下這篇博文。
1.打開文件對話框常用的方法是使用系統的CFileDialog。這里介紹另外一種方法就是使用OPENFILENAME這個結構體和GetOpenFileName()這個函數,可以實現單選文件或者多選文件,代碼如下:
需引入頭文件#include "CommDlg.h"
- TCHAR szBuffer[MAX_PATH] = {0};
- OPENFILENAME ofn= {0};
- ofn.lStructSize = sizeof(ofn);
- ofn.hwndOwner = m_hWnd;
- ofn.lpstrFilter = _T("Exe文件(*.exe)\0*.exe\0所有文件(*.*)\0*.*\0");//要選擇的文件后綴
- ofn.lpstrInitialDir = _T("D:\\Program Files");//默認的文件路徑
- ofn.lpstrFile = szBuffer;//存放文件的緩沖區
- ofn.nMaxFile = sizeof(szBuffer)/sizeof(*szBuffer);
- ofn.nFilterIndex = 0;
- ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER ;//標志如果是多選要加上OFN_ALLOWMULTISELECT
- BOOL bSel = GetOpenFileName(&ofn);
這樣就可以打開選擇文件對話框了。可以選擇需要的文件。szBuffer是存放的選擇的文件路徑。
1.1 多選
#include <windows.h>
{
OPENFILENAME ofn;
TCHAR szOpenFileNames[80*MAX_PATH];
TCHAR szPath[MAX_PATH];
TCHAR szFileName[80*MAX_PATH];
TCHAR* p;
int nLen = 0;
ofn.Flags = OFN_EXPLORER | OFN_ALLOWMULTISELECT;
ofn.lStructSize = sizeof(ofn);
ofn.lpstrFile = szOpenFileNames;
ofn.nMaxFile = sizeof(szOpenFileNames);
ofn.lpstrFile[0] = '/0';
ofn.lpstrFilter = TEXT("All Files(*.*)/0*.*/0");
{
//把第一個文件名前的復制到szPath,即:
//如果只選了一個文件,就復制到最后一個'/'
//如果選了多個文件,就復制到第一個NULL字符
lstrcpyn(szPath, szOpenFileNames, ofn.nFileOffset );
//當只選了一個文件時,下面這個NULL字符是必需的.
//這里不區別對待選了一個和多個文件的情況
szPath[ ofn.nFileOffset ] = '/0';
nLen = lstrlen(szPath);
if( szPath[nLen-1] != '//' ) //如果選了多個文件,則必須加上'//'
{
lstrcat(szPath, TEXT("//"));
}
p = szOpenFileNames + ofn.nFileOffset; //把指針移到第一個文件
ZeroMemory(szFileName, sizeof(szFileName));
while( *p )
{
lstrcat(szFileName, szPath); //給文件名加上路徑
lstrcat(szFileName, p); //加上文件名
lstrcat(szFileName, TEXT("/n")); //換行
p += lstrlen(p) +1; //移至下一個文件
}
MessageBox(NULL, szFileName, TEXT("MultiSelect"), MB_OK);
}
}
2.打開文件夾對話框方法:
需引入頭文件:#include "Shlobj.h"
- TCHAR szBuffer[MAX_PATH] = {0};
- BROWSEINFO bi;
- ZeroMemory(&bi,sizeof(BROWSEINFO));
- bi.hwndOwner = NULL;
- bi.pszDisplayName = szBuffer;
- bi.lpszTitle = _T("從下面選文件夾目錄:");
- bi.ulFlags = BIF_RETURNFSANCESTORS;
- LPITEMIDLIST idl = SHBrowseForFolder(&bi);
- if (NULL == idl)
- {
- return;
- }
- SHGetPathFromIDList(idl,szBuffer);
上面的代碼就可以打開一個選擇文件夾對話框了。
3.選擇文件或文件夾對話框的調用:
- TCHAR szBuffer[MAX_PATH] = {0};
- BROWSEINFO bi;
- ZeroMemory(&bi,sizeof(BROWSEINFO));
- bi.hwndOwner = NULL;
- bi.pszDisplayName = szBuffer;
- bi.lpszTitle = _T("從下面選擇文件或文件夾:");
- bi.ulFlags = BIF_BROWSEINCLUDEFILES;
- LPITEMIDLIST idl = SHBrowseForFolder(&bi);
- if (NULL == idl)
- {
- return;
- }
- SHGetPathFromIDList(idl,szBuffer);
使用了上面的代碼就可以根據需要選擇文件或者文件夾了。
4. 創建一個可以新建文件夾且指定選中初始路徑的瀏覽文件夾對話框
由於我在實際工作中需要的就是一個有新建文件夾功能且指定初始選中路徑的瀏覽文件夾對話框,就把這個需求當做擴展應用吧,由於對話框樣式由ulFlags標記確定,而在系統頭文件SHLOBJ.h頭文件中給出的對話框樣式只有如下幾種
// Browsing for directory.
#define BIF_RETURNONLYFSDIRS 0x0001 // For finding a folder to start document searching
#define BIF_DONTGOBELOWDOMAIN 0x0002 // For starting the Find Computer
#define BIF_STATUSTEXT 0x0004
#define BIF_RETURNFSANCESTORS 0x0008
#define BIF_EDITBOX 0x0010
#define BIF_VALIDATE 0x0020 // insist on valid result (or CANCEL)
#define BIF_BROWSEFORCOMPUTER 0x1000 // Browsing for Computers.
#define BIF_BROWSEFORPRINTER 0x2000 // Browsing for Printers
#define BIF_BROWSEINCLUDEFILES 0x4000 // Browsing for Everything
沒有滿足我需求的樣式,通過csdn查到其實有一個支持新建文件夾功能的樣式值0x40,通常網絡上給出宏為BIF_NEWDIALOGSTYLE和BIF_USENEWUI,由於不知道在具體哪個頭文件中,所以我們可以在代碼中自己定義一下這兩個宏,具體如下
#define BIF_NEWDIALOGSTYLE 0x40
#define BIF_USENEWUI (BIF_NEWDIALOGSTYLE|BIF_EDITBOX)
這樣一來第一個問題解決了,那么如何讓對話框有初始選中的文件夾路徑呢,我起初想着通過pidlRoot,結果撞了一鼻子灰,原來設定初始選中文件夾路徑,是通過那個神奇的回調函數來實現,換句話來說你調用SHBrowseForFolder也就好比你調用了CDialog:: DoModal()函數,具體這個對話框里面的類似初始化,選擇等操作的不同實現就通過lpfn這個回調函數來實現了。
下面給出這個簡單擴展的代碼
#define BIF_NEWDIALOGSTYLE 0x40
int CALLBACK BrowseCallbackProc(HWND hwnd,UINT uMsg,LPARAM lParam,LPARAM lpData)
{
if(uMsg == BFFM_INITIALIZED)
{
SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData);
}
return 0;
}
void CSisAppendMidDlg::OnButtonSisdes()
{
// TODO: Add your control notification handler code here
BROWSEINFO bi;
char Buffer[MAX_PATH];
//初始化入口參數bi開始
bi.hwndOwner = NULL;
bi.pidlRoot =NULL;//初始化制定的root目錄很不容易
bi.pszDisplayName = Buffer;//此參數如為NULL則不能顯示對話框
bi.lpszTitle = "選擇Sis目標文件路徑";
bi.ulFlags = BIF_EDITBOX|BIF_NEWDIALOGSTYLE;
CFileFind finder;
if(finder.FindFile(m_cSisDes)==FALSE)
{
bi.lParam =0;
bi.lpfn = NULL;
}
else
{
bi.lParam = (long)(m_cSisDes.GetBuffer(m_cSisDes.GetLength()));//初始化路徑,形如(_T("c:\\Symbian"));
bi.lpfn = BrowseCallbackProc;
}
finder.Close();
bi.iImage=IDR_MAINFRAME;
//初始化入口參數bi結束
LPITEMIDLIST pIDList = SHBrowseForFolder(&bi);//調用顯示選擇對話框
if(pIDList)
{
SHGetPathFromIDList(pIDList, Buffer);
//取得文件夾路徑到Buffer里
m_cSisDes = Buffer;//將路徑保存在一個CString對象里
}
UpdateData(FALSE);
// free memory used
IMalloc * imalloc = 0;
if ( SUCCEEDED(SHGetMalloc( &imalloc)))
{
imalloc->Free (pIDList);
imalloc->Release();
}
}
以上摘自CSDN,選擇多個文件夾的方式,本人已經在duilib庫中實現,主要是使用GetLogicalDriveStrings等系統API,配合CTreeViewUI實現。
完~