As told in the previous article, if the Open File dialog has Vista style, it’s not possible to use common dialog box messages like CDM_GETFOLDERPATH and CDM_GETSPEC in order to calculate the necessary buffer size, for multiple selection.
Instead, we can use Common Item Dialog API, in our case IFileOpenDialog interface.
Using IFileOpenDialog interface
Here are the main steps:
- call CFileDialog::GetIFileOpenDialog to get ponter to IFileOpenDialog interface;
- use IFileOpenDialog::GetSelectedItems; it gets a IShellItemArray* containing currently selected items (an array of IShellItem* elements);
- for each item call IShellItem::GetDisplayName; use the name length in order to calculate the necessary buffer size.
Example 4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
DWORD CMultiFileOpenDialog::_CalcRequiredBuffSizeVistaStyle() { DWORD dwRet = 0; IFileOpenDialog* pFileOpen = GetIFileOpenDialog(); ASSERT(NULL != pFileOpen); CComPtr<IShellItemArray> pIItemArray; HRESULT hr = pFileOpen->GetSelectedItems(&pIItemArray); DWORD dwItemCount = 0; if(SUCCEEDED(hr)) { hr = pIItemArray->GetCount(&dwItemCount); if(SUCCEEDED(hr)) { for(DWORD dwItem = 0; dwItem < dwItemCount; dwItem++) { CComPtr<IShellItem> pItem; hr = pIItemArray->GetItemAt(dwItem, &pItem); if(SUCCEEDED(hr)) { LPWSTR pszName = NULL; if(dwItem == 0) { // get full path and file name hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszName); } else { // get file name hr = pItem->GetDisplayName(SIGDN_NORMALDISPLAY, &pszName); } if(SUCCEEDED(hr)) { dwRet += wcslen(pszName) + 1; ::CoTaskMemFree(pszName); } } } } } dwRet += 1; // add an extra character // release the IFileOpenDialog pointer pFileOpen->Release(); return dwRet; } |
Further, we can use the returned value to set the OPENFILENAME buffer, if necessary, in CFileDialog::OnFileNameChange overridden function (see the previous article).
Anyway, more implementation details can be found in the attached demo application.
Demo application
The demo application contains the complete implementation of a CFileDialog-derived class, that fixes the multiple selection issues described in this article. It can be used either for Vista or old style file dialogs. Also, to see what happens if use the default buffer, just uncheck “Use ext. buffer” then push “Open…” and finally, select a large number of items from the open file dialog list.
Demo project download: File Open Dialog with Multiple Selection (1435)
Notes
- Common Item Dialog API is supported on Windows Vista and newer.
- CFileDialog with Vista style is implemented in Visual Studio 2008 and newer.
Resources
- MSDN: CFileDialog::GetIFileOpenDialog
- Windows Dev Center: Common Item Dialog
- Windows Dev Center: IFileOpenDialog::GetSelectedItems
- Windows Dev Center: IShellItem::GetDisplayName
See also
- Codexpert blog: File Open Dialog with Multiple Selection – Part 1: Old Style
- Codexpert blog: File Open Dialog with Multiple Selection – Part 3: Cutting the Dog Tail