In most of the implementations to get the folder path of the selected file from a file dialog, people tend implement their own implementation to find the last “\” character and trim the string. CFileDialog::GetFolderPath in fact it exposes the very same functionality but it shows different behavior across platform and MFC libraries.
The typical usage of a file dialog would be as follows
CFileDialog f (true);
if( IDOK == f.DoModal())
{
CString str = f.GetFolderPath();
}
If you compile this code with Visual Studio 2008 and above the code will succeeds and give you the folder of the filename selected by the user. But if you compile the code with MFC version 8.0 (VS 2005) or the prior version the code you will eventually you will reach in exception.
On stepping in to the code, you can see the following code with the MFC 8.0 implementation.
CString strResult; ASSERT(::IsWindow(m_hWnd)); ASSERT(m_ofn.Flags & OFN_EXPLORER); if (GetParent()->SendMessage(CDM_GETFOLDERPATH, (WPARAM)MAX_PATH, (LPARAM)strResult.GetBuffer(MAX_PATH)) < 0) strResult.Empty(); else strResult.ReleaseBuffer(); return strResult;
The internal implementation uses the typical window messaging system. The return of the message points to the string buffer which will be copied to the CString object and will be returned.
Though GetFolderPath can’t be used in a typical scenario, it can be used when you’ve your own implementation of the CFileDialog. You can use them in the internal callbacks and own implementations of override-able function as long as the window is being displayed.
E.g. see an implementation in a class derived from CFileDialog. Here the window is active. The call CFileDialog::OnOK will destroy the window object in the end.
void MyFileDialog::OnOK()
{
CString str = GetFolderPath();
// Do something like some validation
MessageBox( str );
CFileDialog::OnOK();
}
Changes in Windows Vista
In Windows Vista and above there are there several new shell interfaces introduced with extended functionality. The new changes in the file dialog and the Windows shell are incorporated in the new IFileDialog implementation. These interfaces are nothing but lightweight COM object and not part of MFC library. To provide the backward compatibility while exploiting the new features in the platform, Microsoft has changed the MFC implementation of CFileDialog with the help of using IFileDialog interface.
The constructor of the new CFileDialog now takes a new (default) parameter in the end called bVistaStyle. Inside the constructor of CFileDialog, the m_bVistaStyle parameter is set with this input parameter and the whole implementation of CFileDialog is implemented with condition checks. If it’s Vista Style File dialog, IFileDialog interface will be used throughout the life of the object.
Both the appearance and the functionality of the CFileDialog with Windows Vista differ from the earlier versions of Windows. The default CFileDialog automatically uses the new Windows Vista style without code changes if a program is compiled and run under Windows Vista. Use the bVistaStyle parameter in the constructor to manually override this automatic update.
Obviously the old Open and Save file dialog API based implementations are remained intact and wrapped around with m_bVistaStyle condition check. You can find the implementation in the dlgfile.cpp (located underVC\atlmfc\src\mfc ).
Visual Studio 2008 (MFC 9.0) library has incorporated the above mentioned changes and behave properly.
For instance you can clearly see the code for GetFolderPath with the latest version of MFC library here. You can clearly see it uses m_pIFileDialog member of the class being used to get the folder path. The previous implementation is wrapped in the else case.
CString CFileDialog::GetFolderPath() const
{
CString strResult;
if (m_bVistaStyle == TRUE)
{
IShellItem *psiResult;
HRESULT hr = (static_cast(m_pIFileDialog))->GetFolder(&psiResult);
if (SUCCEEDED(hr))
{
LPWSTR wcFolderPath = NULL;
hr = psiResult->GetDisplayName(SIGDN_FILESYSPATH, &wcFolderPath);
if (SUCCEEDED(hr))
{
strResult = wcFolderPath;
CoTaskMemFree(wcFolderPath);
}
psiResult->Release();
}
}
else
{
ASSERT(::IsWindow(m_hWnd));
ASSERT(m_ofn.Flags & OFN_EXPLORER);
if (GetParent()->SendMessage(CDM_GETFOLDERPATH, (WPARAM)MAX_PATH, (LPARAM)strResult.GetBuffer(MAX_PATH)) < 0)
strResult.Empty();
else
strResult.ReleaseBuffer();
}
return strResult;
}
Conclusion
You can make use of this call if you’re using Visual Studio 2008 (MFC 9.0) and above, you’re passing bVistaStyle as true in the constructor and the platform is Windows Vista and above. Also If it’s not required to provide backward compatibility, you can make use of IFileDialog interface than using CFileDialog class.