CFileDialog选择多文件出错返回FNERR_BUFFERTOOSMALL
在使用CFileDialog类打开文件中,若要同时选择多个文件,需要设置OFN_ALLOWMULTISELECT属性,如下代码所示:
CFileDialog fileDlg(true, NULL, NULL, OFN_ALLOWMULTISELECT); fileDlg.m_ofn.lpstrFilter = _T("ZV File(*.zv)\0 *.zv\0MPG File(*.mpg)\0 *.mpg\0MPEG4 File(*.mpeg4)\0 *.mpeg4\0H264 File(*.264)\0 *.264\0All File(*.*)\0 *.*\0"); if (IDOK == fileDlg.DoModal()) { POSITION pos = fileDlg.GetStartPosition(); while(pos) { CString strPathName = fileDlg.GetNextPathName(pos); AfxMessageBox(strPathName); } }
但在实际使用过程中,如何同时选择的文件过多,fileDlg.GetNextPathName(pos)返回的文件名不正确,获取到的错误号为FNERR_BUFFERTOOSMALL,即缓存太小。
在MSDN关于CFileDialog多文件的描述中则说明了这种情况
When the user allocates their own buffer to accommodate OFN_ALLOWMULTISELECT, the buffer cannot be larger than 2048 or else everything gets corrupted (2048 is the maximum size). Additionally, you must set m_ofn.nMaxFile with the number of characters in the buffer pointed to by m_ofn.lpstrFile. If you set the maximum number of files to be selected to n, the necessary buffer size is n*(_MAX_PATH + 1) + 1. For example:
CFileDialog dlgFile(TRUE); CString fileName; const int c_cMaxFiles = 100; const int c_cbBuffSize = (c_cMaxFiles * (MAX_PATH + 1)) + 1; dlgFile.GetOFN().lpstrFile = fileName.GetBuffer(c_cbBuffSize); dlgFile.GetOFN().nMaxFile = c_cMaxFiles; dlgFile.DoModal(); fileName.ReleaseBuffer();
也就是说需要重新指定缓存大小,如果最大文件数量是100,那么缓存大小为100 * (MAX_PATH + 1) + 1,需要改变m_ofn中lpstrFile及nMaxFile的值,经调试发现m_ofn的nMaxFile默认大小为260。上述代码修改后为:
CFileDialog fileDlg(true, NULL, NULL, OFN_ALLOWMULTISELECT); int nMaxFiles = 2600; //修改此处大小容纳更多文件 int nBuffSize = (nMaxFiles * (MAX_PATH + 1)) + 1; fileDlg.m_ofn.nMaxFile = nMaxFiles; char* fileBuff = new char[nBuffSize]; memset(fileBuff, 0, sizeof(fileBuff)); fileDlg.m_ofn.lpstrFile = (LPWSTR)fileBuff; fileDlg.m_ofn.lpstrFilter = _T("ZV File(*.zv)\0 *.zv\0MPG File(*.mpg)\0 *.mpg\0MPEG4 File(*.mpeg4)\0 *.mpeg4\0H264 File(*.264)\0 *.264\0All File(*.*)\0 *.*\0"); if (IDOK == fileDlg.DoModal()) { //m_strSrcFile = dlg.GetPathName(); POSITION pos = fileDlg.GetStartPosition();; while(pos) { CString strPathName = fileDlg.GetNextPathName(pos); AfxMessageBox(strPathName); } } delete[] fileBuff;