C++程序操作文件對(duì)話框的方法
在C++程序中有時(shí)需要通過系統(tǒng)的文件對(duì)話框去操作文件或者文件夾,我們有必要熟練掌握操作文件對(duì)話框的細(xì)節(jié),去更好的為我們軟件服務(wù)。本文我們就來講述一下C++在操作文件夾對(duì)話框的相關(guān)細(xì)節(jié),給大家借鑒和參考。
1、調(diào)用GetOpenFileName接口啟動(dòng)打開文件對(duì)話框

當(dāng)我們需要使用文件對(duì)話框打開一個(gè)文件時(shí),我們可以調(diào)用系統(tǒng)API函數(shù)GetOpenFileName來啟動(dòng)系統(tǒng)的打開文件對(duì)話框。調(diào)用該API函數(shù)時(shí)需要傳入OPENFILENAME結(jié)構(gòu)體對(duì)象,通過該結(jié)構(gòu)體給打開文件對(duì)話框設(shè)置一些屬性參數(shù)。
1.1、OPENFILENAME結(jié)構(gòu)體說明
結(jié)構(gòu)體OPENFILENAME的定義有兩個(gè)版本,一個(gè)Unicode版本的OPENFILENAMEW,一個(gè)ANSI版本的OPENFILENAMEA,這個(gè)地方我們以Unicode版本的OPENFILENAMEW來說明,該結(jié)構(gòu)體的定義如下:
typedef struct tagOFNW {
DWORDlStructSize;
HWND hwndOwner;
HINSTANCEhInstance;
LPCWSTR lpstrFilter;
LPWSTR lpstrCustomFilter;
DWORDnMaxCustFilter;
DWORDnFilterIndex;
LPWSTR lpstrFile;
DWORDnMaxFile;
LPWSTR lpstrFileTitle;
DWORDnMaxFileTitle;
LPCWSTR lpstrInitialDir;
LPCWSTR lpstrTitle;
DWORDFlags;
WORD nFileOffset;
WORD nFileExtension;
LPCWSTR lpstrDefExt;
LPARAM lCustData;
LPOFNHOOKPROC lpfnHook;
LPCWSTR lpTemplateName;
#ifdef _MAC
LPEDITMENU lpEditInfo;
LPCSTR lpstrPrompt;
#endif
#if (_WIN32_WINNT >= 0x0500)
void *pvReserved;
DWORDdwReserved;
DWORDFlagsEx;
#endif // (_WIN32_WINNT >= 0x0500)
} OPENFILENAMEW, *LPOPENFILENAMEW;這個(gè)地方我們講一下幾個(gè)我們使用到的字段:
- lStructSize字段[in]:用來存放當(dāng)前結(jié)構(gòu)體的長(zhǎng)度。
- hwndOwner字段[in]:用來指定文件對(duì)話框的父窗口。
- lpstrFilter字段[in]:用來設(shè)置選擇的文件類型,如果要選擇所有文件,則設(shè)置“All Files(*.*)\0*.*\0\0”;如果選擇的是常用的圖片文件,則可以設(shè)置“圖片文件(*.bmp;*.jpg;*.jpeg;*.gif;*.png)\0*.bmp;*.jpg;*.jpeg;*.gif;*.png\0\0”。
- lpstrFile字段[out]:該字段用來傳出用戶選擇的文件信息,存放選擇的文件信息的buffer是需要外部申請(qǐng)內(nèi)存的,然后將buffer地址賦值給該字段,然后在GetOpenFileName調(diào)用完成后通過該字段指定的buffer輸出用戶選擇的文件信息。
- nMaxFile字段[in]:用來指定設(shè)置給lpstrFile字段對(duì)應(yīng)的buffer長(zhǎng)度的。
- lpstrInitialDir字段[in]:用來指定打開文件對(duì)話框時(shí)的初始顯示路徑。
- Flags字段[in]:用來設(shè)定文件對(duì)話框支持的屬性,比如支持多選的OFN_ALLOWMULTISELECT、選擇的文件必須存在OFN_FILEMUSTEXIST等。
1.2、設(shè)置支持文件多選,控制選擇文件的個(gè)數(shù)上限
要支持文件多選,需要給OPENFILENAME結(jié)構(gòu)體的Flags字段添加OFN_ALLOWMULTISELECT選項(xiàng)。如果要控制選擇文件的個(gè)數(shù)上限,比如我們?cè)贗M聊天框中限制用戶插入圖片的個(gè)數(shù)(比如我們此處限制為5個(gè)圖片文件):

我可以在給OPENFILENAME結(jié)構(gòu)體參數(shù)設(shè)置lpstrFilter字段指定接收用戶選擇信息時(shí)指定buffer的長(zhǎng)度最多存放5張圖片的路徑。
如果選擇多個(gè)文件時(shí)的文件信息超過buffer的長(zhǎng)度,則GetOpenFileName會(huì)返回失敗,此時(shí)可以調(diào)用CommDlgExtendedError獲取錯(cuò)誤碼,如果錯(cuò)誤碼是FNERR_BUFFERTOOSMALL,則表示buffer太小存不下選擇的多個(gè)圖片文件信息,此時(shí)可以彈出提示框,相關(guān)代碼如下:
// 設(shè)置最多選擇5個(gè)文件的buffer長(zhǎng)度
int nBufLen = 5*(MAX_PATH+1) + 1;
TCHAR* pBuf = new TCHAR[nBufLen];
memset( pBuf, 0, nBufLen*sizeof(TCHAR) );
OPENFILENAME ofn;
memset( &ofn, 0 ,sizeof(ofn) );
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = m_hParentWnd;
ofn.lpstrFile = pBuf;
ofn.nMaxFile = nBufLen;
ofn.lpstrFilter = _T("All Files(*.*)\0*.*\0\0");
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_EXPLORER|OFN_ALLOWMULTISELECT|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
// 打開文件打開對(duì)話框
BOOL bRet = ::GetOpenFileName( &ofn );
if ( !bRet )
{
// 上面的ofn.lpstrFile buffer的長(zhǎng)度設(shè)置存放3個(gè)圖片路徑,選擇較多文件時(shí)
// 會(huì)超出給定的buffer長(zhǎng)度,所以此處要判斷一下這樣的情況,并給出提示5
DWORD dwErr = CommDlgExtendedError();
if ( dwErr == FNERR_BUFFERTOOSMALL )
{
// FNERR_BUFFERTOOSMALL - The buffer pointed to by the lpstrFile member
// of the OPENFILENAME structure is too small
::MessageBox( NULL, _T("最多只允許選擇5個(gè)文件,請(qǐng)重新選擇"), _T("提示"), MB_OK );
}
delete []pBuf;
return;
}
// 再檢查一下用戶選擇的文件個(gè)數(shù),檢測(cè)是否達(dá)到上限
int nPicTotal = 0;
UIPOSITION pos = (UIPOSITION)ofn.lpstrFile;
while ( pos != NULL )
{
// 獲取用戶選擇的每個(gè)文件的路徑,此處可以將文件的路徑保存下來
strPicPath = GetNextPathName( pos, ofn );
++nPicTotal;
}
if ( nPicTotal > 5 )
{
::MessageBox( NULL, _T("最多只允許選擇5個(gè)文件,請(qǐng)重新選擇"), _T("提示"), MB_OK );
delete []pBuf;
return;
}當(dāng)然,我們僅僅通過FNERR_BUFFERTOOSMALL錯(cuò)誤判斷文件個(gè)數(shù)超限了,是不夠的??赡苡脩暨x擇了6個(gè)文件時(shí),總的buffer不會(huì)超限,所以還要在解析出來用戶選擇的每個(gè)文件后計(jì)算一下選擇的文件個(gè)數(shù)。
1.3、從OPENFILENAME結(jié)構(gòu)體的lpstrFile字段解析出用戶選擇的文件的完整路徑
上面我們講了,用戶在選擇完多個(gè)文件后,點(diǎn)擊確定,API函數(shù)GetOpenFileName返回,傳給該API函數(shù)的OPENFILENAME結(jié)構(gòu)體對(duì)象參數(shù)的lpstrFile字段中存放這用戶選擇的文件信息,比如我選擇了3個(gè)文件(docker.png、linux.png、running.png),lpstrFile中存放的數(shù)據(jù)格式會(huì)是:
C:\Users\Administrator\Desktop\CSDN文章圖集\docker.png\0linux.png\0running.png
因?yàn)檫@段字串中包含\0,所以我們不能把lpstrFile當(dāng)成字符串來處理。我們專門封裝了接口GetNextPathName,該接口負(fù)責(zé)將每個(gè)文件的完整路徑解析:
// 主要用于文件打開對(duì)話框選中多個(gè)文件時(shí),解析出多個(gè)文件名(絕對(duì)路徑),從MFC庫中的CFileDialog類的GetNextPathName函數(shù)中剝離出來的
CUIString GetNextPathName( UIPOSITION& pos, OPENFILENAME& ofn )
{
BOOL bExplorer = ofn.Flags & OFN_EXPLORER;
TCHAR chDelimiter;
if ( bExplorer )
{
chDelimiter = '\0';
}
else
{
// For old-style dialog boxes, the strings are space separated and the function uses
// short file names for file names with spaces.
chDelimiter = ' ';
}
LPTSTR lpsz = (LPTSTR)pos;
if ( lpsz == ofn.lpstrFile ) // first time
{
if ( (ofn.Flags & OFN_ALLOWMULTISELECT) == 0 )
{
pos = NULL;
return ofn.lpstrFile;
}
// find char pos after first Delimiter
while( *lpsz != chDelimiter && *lpsz != '\0' )
lpsz = _tcsinc( lpsz );
lpsz = _tcsinc( lpsz );
// if single selection then return only selection
if ( *lpsz == 0 )
{
pos = NULL;
return ofn.lpstrFile;
}
}
CString strPath = ofn.lpstrFile;
if ( !bExplorer )
{
LPTSTR lpszPath = ofn.lpstrFile;
while( *lpszPath != chDelimiter )
lpszPath = _tcsinc(lpszPath);
strPath = strPath.Left( lpszPath - ofn.lpstrFile );
}
LPTSTR lpszFileName = lpsz;
CString strFileName = lpsz;
// find char pos at next Delimiter
while( *lpsz != chDelimiter && *lpsz != '\0' )
lpsz = _tcsinc(lpsz);
if ( !bExplorer && *lpsz == '\0' )
pos = NULL;
else
{
if ( !bExplorer )
strFileName = strFileName.Left( lpsz - lpszFileName );
lpsz = _tcsinc( lpsz );
if ( *lpsz == '\0' ) // if double terminated then done
pos = NULL;
else
pos = (UIPOSITION)lpsz;
}
// only add '\\' if it is needed
if ( !strPath.IsEmpty() )
{
// check for last back-slash or forward slash (handles DBCS)
LPCTSTR lpsz = _tcsrchr( strPath, '\\' );
if ( lpsz == NULL )
lpsz = _tcsrchr( strPath, '/' );
// if it is also the last character, then we don't need an extra
if ( lpsz != NULL &&
(lpsz - (LPCTSTR)strPath) == strPath.GetLength()-1 )
{
ASSERT( *lpsz == '\\' || *lpsz == '/' );
return strPath + strFileName;
}
}
return strPath + '\\' + strFileName;
}我們?cè)谕獠垦h(huán)調(diào)用GetNextPathName函數(shù)即可:
UIPOSITION pos = (UIPOSITION)ofn.lpstrFile;
while ( pos != NULL )
{
// 獲取用戶選擇的每個(gè)文件的路徑,此處可以將文件的路徑保存下來
strPicPath = GetNextPathName( pos, ofn );
++nPicTotal;
}2、調(diào)用GetSaveFileName接口啟動(dòng)保存文件對(duì)話框

當(dāng)我們需要使用保存文件對(duì)話框保存一個(gè)文件時(shí),我們可以調(diào)用系統(tǒng)API函數(shù)GetSaveFileName來啟動(dòng)系統(tǒng)的保存文件對(duì)話框。調(diào)用該函數(shù)時(shí)也是傳入OPENFILENAME結(jié)構(gòu)體對(duì)象的,通過該結(jié)構(gòu)體給打開文件對(duì)話框設(shè)置一些屬性參數(shù)。
對(duì)于GetSaveFileName接口,OPENFILENAME結(jié)構(gòu)體中的lpstrFile字段的含義是不同的,此處用來設(shè)置保存文件的默認(rèn)名字的。調(diào)用函數(shù)的示例代碼如下:
TCHAR szFile[3*MAX_PATH] = { 0 };
_tcscpy( szFile, strFileName );
OPENFILENAME ofn;
memset( &ofn, 0 ,sizeof(ofn) );
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = NULL;
ofn.lpstrFilter = _T("All Files(*.*)|0*.*||");
ofn.lpstrFile = szFile;
ofn.nMaxFile = sizeof(szFile)/sizeof(TCHAR);
ofn.lpstrDefExt = (LPCTSTR)strExt;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_EXPLORER|OFN_PATHMUSTEXIST|OFN_HIDEREADONLY|OFN_NOCHANGEDIR|OFN_OVERWRITEPROMPT|OFN_ENABLEHOOK;
ofn.lpfnHook = FileSaveAs_OFNHookProc; // 設(shè)置回調(diào)函數(shù),添加額外的處理機(jī)制if ( ::GetSaveFileName( &ofn ) )
{
// 用戶最終輸入的文件名的完整路徑
CString strPathName = ofn.lpstrFile;
}在上述代碼中,我們添加了OFN_OVERWRITEPROMPT屬性,用來指定覆蓋同名文件時(shí)給出提示;我們還添加了OFN_ENABLEHOOK屬性,用來指定設(shè)置回調(diào)函數(shù),在函數(shù)中添加額外的處理機(jī)制。在本例中,我們的HOOK回調(diào)函數(shù)如下:
// 文件對(duì)話框回調(diào)函數(shù)
UINT_PTR CALLBACK FileSaveAs_OFNHookProc(
HWND hdlg, // handle to child dialog box
UINT uiMsg, // message identifier
WPARAM wParam, // message parameter
LPARAM lParam // message parameter
)
{
if( uiMsg == WM_NOTIFY)
{
LPOFNOTIFY pofn = (LPOFNOTIFY)lParam;
if( pofn->hdr.code == CDN_FILEOK )
{
HWND hFileDlg = ::GetParent( hdlg );
// 獲取用戶選擇保存路徑
TCHAR achCurPath[MAX_PATH*3] = { 0 };
int nRet = ::SendMessage( hFileDlg, CDM_GETFOLDERPATH, sizeof(achCurPath)/sizeof(TCHAR),
(LPARAM)achCurPath );
if ( nRet < 0 )
{
return 0;
}
// 判斷當(dāng)前程序?qū)x擇的目錄是否有寫權(quán)限
BOOL bCanWrite = CanAccessFile( achCurPath, GENERIC_WRITE );
if ( !bCanWrite )
{
::MessageBox( hFileDlg, STRING_HAVE_NO_RIGHT_SAVE_FILE, STRING_TIP, MB_OK|MB_ICONWARNING );
::SetWindowLong( hdlg, DWL_MSGRESULT, 1 );
return 1;
}
}
}
return 0;
}在HOOK回調(diào)函數(shù)中我們攔截了點(diǎn)擊確定的消息,判斷一下用戶當(dāng)前選擇的路徑有沒有權(quán)限保存文件。因?yàn)樵赪in7及以上系統(tǒng)中,如果程序沒有管理員權(quán)限,是沒有權(quán)利向C:\Windows、C:\Program Files等系統(tǒng)關(guān)鍵路徑中寫入文件的。
判斷程序是否對(duì)某個(gè)路徑有寫權(quán)限,我們封裝了專門的判斷函數(shù),如下所示:
// 將要檢測(cè)的權(quán)限GENERIC_XXXXXX傳遞給dwGenericAccessMask,可檢測(cè)對(duì)
// 文件或者文件夾的權(quán)限
BOOL CanAccessFile( CString strPath, DWORD dwGenericAccessMask )
{
CString strLog;
strLog.Format( _T("[CanAccessFile] strPath: %s, dwGenericAccessMask: %d"), strPath, dwGenericAccessMask );
WriteUpdateLog( strLog );
DWORD dwSize = 0;
PSECURITY_DESCRIPTOR psd = NULL;
SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION |
GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
WriteLog( _T("[CanAccessFile] GetFileSecurity - NULL") );
// 獲取文件權(quán)限信息結(jié)構(gòu)體大小
BOOL bRet = GetFileSecurity( strPath, si, psd, 0, &dwSize );
if ( bRet || GetLastError() != ERROR_INSUFFICIENT_BUFFER )
{
strLog.Format( _T("[CanAccessFile] GetFileSecurity - NULL failed, GetLastError: %d"), GetLastError() );
WriteLog( strLog );
return FALSE;
}
char* pBuf = new char[dwSize];
ZeroMemory( pBuf, dwSize );
psd = (PSECURITY_DESCRIPTOR)pBuf;
strLog.Format( _T("[CanAccessFile] GetFileSecurity - dwSize: %d"), dwSize );
WriteLog( strLog );
// 獲取文件權(quán)限信息結(jié)構(gòu)體大小
bRet = GetFileSecurity( strPath, si, psd, dwSize, &dwSize );
if ( !bRet )
{
strLog.Format( _T("[CanAccessFile] GetFileSecurity - dwSize failed, GetLastError: %d"), GetLastError() );
WriteLog( strLog );
delete []pBuf;
return FALSE;
}
WriteLog( _T("[CanAccessFile] OpenProcessToken") );
HANDLE hToken = NULL;
if ( !OpenProcessToken( GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken ) )
{
strLog.Format( _T("[CanAccessFile] OpenProcessToken failed, GetLastError: %d"), GetLastError() );
WriteLog( strLog );
delete []pBuf;
return FALSE;
}
WriteLog( _T("[CanAccessFile] DuplicateToken") );
// 模擬令牌
HANDLE hImpersonatedToken = NULL;
if( !DuplicateToken( hToken, SecurityImpersonation, &hImpersonatedToken ) )
{
strLog.Format( _T("[CanAccessFile] DuplicateToken failed, GetLastError: %d"), GetLastError() );
WriteLog( strLog );
delete []pBuf;
CloseHandle( hToken );
return FALSE;
}
WriteLog( _T("[CanAccessFile] MapGenericMask") );
// 在檢測(cè)是否有某個(gè)權(quán)限時(shí),將GENERIC_WRITE等值傳給本函數(shù)的第二個(gè)參數(shù)dwGenericAccessMask
// GENERIC_WRITE等參數(shù)在調(diào)用CreateFile創(chuàng)建文件時(shí)會(huì)使用到,下面調(diào)用MapGenericMask將
// GENERIC_WRITE等轉(zhuǎn)換成FILE_GENERIC_WRITE等
// 將GENERIC_XXXXXX轉(zhuǎn)換成FILE_GENERIC_XXXXXX
GENERIC_MAPPING genMap;
genMap.GenericRead = FILE_GENERIC_READ;
genMap.GenericWrite = FILE_GENERIC_WRITE;
genMap.GenericExecute = FILE_GENERIC_EXECUTE;
genMap.GenericAll = FILE_ALL_ACCESS;
MapGenericMask( &dwGenericAccessMask, &genMap );
WriteLog( _T("[CanAccessFile] AccessCheck") );
// 調(diào)用AccessCheck來檢測(cè)是否有指定的權(quán)限
PRIVILEGE_SET privileges = { 0 };
DWORD dwGrantedAccess = 0;
DWORD privLength = sizeof(privileges);
BOOL bGrantedAccess = FALSE;
if( AccessCheck( psd, hImpersonatedToken, dwGenericAccessMask,
&genMap, &privileges, &privLength, &dwGrantedAccess, &bGrantedAccess ) )
{
strLog.Format( _T("[CanAccessFile] AccessCheck succeed, dwGenericAccessMask: %d, dwGrantedAccess: %d, bGrantedAccess: %d, "),
dwGenericAccessMask, dwGrantedAccess, bGrantedAccess );
WriteLog( strLog );
if ( bGrantedAccess )
{
if ( dwGenericAccessMask == dwGrantedAccess )
{
bGrantedAccess = TRUE;
}
else
{
bGrantedAccess = FALSE;
}
}
else
{
bGrantedAccess = FALSE;
}
}
else
{
strLog.Format( _T("[CanAccessFile] AccessCheck failed, GetLastError: %d"), GetLastError() );
WriteLog( strLog );
bGrantedAccess = FALSE;
}
strLog.Format( _T("[CanAccessFile] bGrantedAccess: %d"), bGrantedAccess );
WriteLog( strLog );
delete []pBuf;
CloseHandle( hImpersonatedToken );
CloseHandle( hToken );
return bGrantedAccess;
} 另外,我們可以在HOOK回調(diào)函數(shù)中調(diào)整文件對(duì)話框相對(duì)于父窗口的彈出位置,攔截WM_INITDIALOG消息,代碼如下:
// 通過該回調(diào)函數(shù)移動(dòng)文件保存對(duì)話框的位置,解決win32 文件對(duì)話框默認(rèn)顯示在屏幕左上方的問題
UINT_PTR CALLBACK OFNHookProc(
HWND hdlg, // handle to child dialog box
UINT uiMsg, // message identifier
WPARAM wParam, // message parameter
LPARAM lParam // message parameter
)
{
if ( uiMsg == WM_INITDIALOG )
{
HWND hFileDlg = ::GetParent( hdlg );
HWND hParent = ::GetParent( hFileDlg );
RECT rcParent;
::GetWindowRect( hParent, &rcParent );
RECT rcFileDlg;
::GetWindowRect( hFileDlg, &rcFileDlg );
int nFileDlgWdith = rcFileDlg.right - rcFileDlg.left;
int nFileDlgHeight = rcFileDlg.bottom - rcFileDlg.top;
RECT rcDst;
rcDst.left = rcParent.left + ( (rcParent.right - rcParent.left) - nFileDlgWdith )/2;
rcDst.right = rcDst.left + nFileDlgWdith;
rcDst.bottom = rcParent.bottom + 1;
rcDst.top = rcDst.bottom - nFileDlgHeight;
// 下面保證文件對(duì)話框處于屏幕可視區(qū)域內(nèi)
if ( rcDst.left < 0 )
{
rcDst.left = 0;
rcDst.right = rcDst.left + nFileDlgWdith;
}
if ( rcDst.top < 0 )
{
rcDst.top = 0;
rcDst.bottom = rcDst.top + nFileDlgHeight;
}
int nXScreen = ::GetSystemMetrics( SM_CXSCREEN );
int nYScreen = ::GetSystemMetrics( SM_CYSCREEN );
if ( rcDst.right > nXScreen )
{
rcDst.right = nXScreen;
rcDst.left = rcDst.right - nFileDlgWdith;
}
if ( rcDst.bottom > nYScreen )
{
rcDst.bottom = nYScreen;
rcDst.top = rcDst.bottom - nFileDlgHeight;
}
// 重新設(shè)置文件對(duì)話框位置
::SetWindowPos( hFileDlg, NULL, rcDst.left, rcDst.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER );
return 1;
}
return 0;
} 3、調(diào)用SHBrowseForFolder接口打開瀏覽文件夾對(duì)話框

當(dāng)我們?cè)贗M聊天框中發(fā)起文件傳輸時(shí),我們要發(fā)送的是一個(gè)文件夾,可能就需要使用到系統(tǒng)的瀏覽文件夾對(duì)話框來選擇要發(fā)送的文件夾。當(dāng)我們?cè)诮邮盏蕉鄠€(gè)文件時(shí),可以選擇全部另存為,此時(shí)也需要使用系統(tǒng)的瀏覽文件夾對(duì)話框來選擇要另存為的路徑。
我們調(diào)用SHBrowseForFolder接口即可打開瀏覽文件夾對(duì)話框,相關(guān)代碼如下所示:
// 打開目錄選擇對(duì)話框
::CoInitialize( NULL );
LPMALLOC lpMalloc = NULL;
TCHAR pchSelDir[MAX_PATH] = {0};
pchSelDir[0] = _T('\0');
if( E_FAIL == ::SHGetMalloc(&lpMalloc) )
{
::CoUninitialize();
return;
}
BROWSEINFO browseInfo;
browseInfo.hwndOwner = m_hParentWnd;
browseInfo.pidlRoot = NULL;
browseInfo.pszDisplayName = NULL;
browseInfo.lpszTitle = STRING_SEL_FOLDER_TO_SEND;
browseInfo.ulFlags= BIF_RETURNONLYFSDIRS;
browseInfo.lpfn = NULL;
browseInfo.lParam = 0;
// 打開瀏覽文件夾對(duì)話框
LPITEMIDLIST lpItemIDList = NULL;
if ( ( lpItemIDList = ::SHBrowseForFolder(&browseInfo) ) != NULL )
{
// 獲取用戶選擇的文件夾
::SHGetPathFromIDList( lpItemIDList, pchSelDir );
lpMalloc->Free( lpItemIDList );
lpMalloc->Release();
}
else
{
lpMalloc->Free( lpItemIDList );
lpMalloc->Release();
::CoUninitialize();
return;
}
::CoUninitialize();4、最后
到此這篇關(guān)于C++如何操作文件對(duì)話框的文章就介紹到這了,更多相關(guān)C++文件對(duì)話框內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解C++值多態(tài)中的傳統(tǒng)多態(tài)與類型擦除
值多態(tài)是一種介于傳統(tǒng)多態(tài)與類型擦除之間的多態(tài)實(shí)現(xiàn)方式,借鑒了值語義,保留了繼承,在單繼承的適用范圍內(nèi),程序和程序員都能從中受益。這篇文章主要介紹了C++值多態(tài)中的傳統(tǒng)多態(tài)與類型擦除,需要的朋友可以參考下2020-04-04
C++實(shí)現(xiàn)將簡(jiǎn)單密碼譯回原文的方法
這篇文章主要介紹了C++實(shí)現(xiàn)將簡(jiǎn)單密碼譯回原文的方法,可實(shí)現(xiàn)將簡(jiǎn)單的字母位移類型的密碼譯回原文的功能,涉及C++簡(jiǎn)單字符串操作相關(guān)技巧,需要的朋友可以參考下2016-05-05
C語言之?dāng)?shù)組名與數(shù)組起始地址的關(guān)系解析
這篇文章主要介紹了C語言之?dāng)?shù)組名與數(shù)組起始地址的關(guān)系,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07
C++中可以接受任意多個(gè)參數(shù)的函數(shù)定義方法(詳解)
下面小編就為大家?guī)硪黄狢++中可以接受任意多個(gè)參數(shù)的函數(shù)定義方法(詳解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-10-10

