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;

Comments are closed.