I ran into an issue today. I had a CFileDialog object set to select multiple files (using OFN_ALLOWMULTISELECT). When I launched the dialog, I selected 24 files. However, after looping through the files using CFileDialog::GetNextPathName(), there were only 10 being returned.
The problem is that there wasn’t an error being set anywhere (that I could find). CFileDialog was being quite sneaky in that it wasn’t giving me any signal that 14 of the selected files were basically being ignored. At first, I thought it was just a bug in Windows. After some thinking, it turns out that there’s an internal buffer used to store these files. This may seem very obvious to some people, but it wasn’t obvious to me.
Part of the OPENFILENAME structure is a buffer for holding (a) the default file when the dialog is opened, and (b) the selected files when the dialog is closed. This member is called lpstrFile. nMaxFile is also used in conjunction to specify the length of the buffer pointed to by lpstrFile.
By default, CFileDialog uses a buffer 260 characters long. In my problem above, 260 characters is basically able to only hold 10 of the selected files. The rest were just dropped quietly.
The workaround is to use a larger buffer. It’s quite easy to do this:
// Create our dialog object
CFileDialog dialog(TRUE, NULL, NULL, OFN_HIDEREADONLY |
OFN_ALLOWMULTISELECT);
// This is the trick
const int nBufferSize = 128*1024; // May be excessive?
TCHAR *szBuffer = new TCHAR[nBufferSize];
memset(szBuffer, 0, sizeof(TCHAR) * nBufferSize);
dialog.m_ofn.lpstrFile = szBuffer;
dialog.m_ofn.nMaxFile = nBufferSize - 1;
// Show the dialog
if (dialog.DoModal() == IDOK)
{
POSITION pos = dialog.GetStartPosition();
while (pos != NULL)
{
CString sFile = dialog.GetNextPathName(pos);
// Process the file
}
}
delete[] szBuffer; // No leaks
The trick is to set lpstrFile and nMaxFile to a larger buffer. 128k may be excessive, but at least it will work. Feel free to use whatever size buffer you want to.
Note: Above, I created the buffer on the heap using ‘new’. If you don’t want to deal with ‘new’ and ‘delete’, you could create it on the stack like:
TCHAR szBuffer[nBufferSize];
and skip the ‘delete’ call. However, this will eat up a good chunk of your stack space. The default stack is 1 MB. So 128k is 10% of your stack. For this reason, I created it on the heap.