Search code examples
visual-c++mfcsmart-pointersopenfiledialog

How do we use smart pointers with CFileDialog and multi-file selection?


How about modernizing our code that uses the common CFileDialog dialog?

Sample code:

void CExportSettingsDlg::OnBnClickedMfcbuttonImportXsl()
{
    CString strFilter;                                  // This will be used to display the right type of template files
    CString strTargetFolder = theApp.GetWorkingPath();  // Default
    TCHAR* pszFile = new TCHAR[32767];                  // Buffer for the files selected by the user
    TCHAR szTabText[_MAX_PATH] = { 0 };                 // Buffer for the selected tab text (we use it for the filter description)

    // Initialise the filter string
    strFilter = _T("Styles|SRRSchedule*.xsl;SRRSchedule*.css||");

    // Initialise the file dialog
    CFileDialog dlgImport(TRUE,
        _T(".XSL"), _T(""), OFN_ALLOWMULTISELECT | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY, strFilter, this);
    ZeroMemory(pszFile, 32767 * sizeof(TCHAR));
    dlgImport.m_ofn.lpstrFile = pszFile;
    dlgImport.m_ofn.nMaxFile = 32767;
    dlgImport.m_ofn.nFileOffset = 0;

    if (dlgImport.DoModal() != IDOK)
    {
        // User did not select any files so tidy up the memory
        delete[] pszFile;
        return;
    }

    // Iterate the selected files
    POSITION pos = dlgImport.GetStartPosition();
    CString strSourceFilePath, strTargetFilePath, strSourceFileName, strSourceFileTitle, strSourceExtension, strFileName;

    while (pos)
    {
        strSourceFilePath = dlgImport.GetNextPathName(pos);
        // ...
    }

    // Tidy memory
    delete[] pszFile;
}

How can we turn this into using a smart pointer? The lpstrFile variable is of type LPWSTR.


Solution

  • Whenever you need an automatically managed, heap-allocated array, std::vector is the go-to solution. All new[]'s and delete[]'s will miraculously disappear, and the parameters set in the OPENFILENAME structure will match, as a bonus.

    Something like this:

    void CExportSettingsDlg::OnBnClickedMfcbuttonImportXsl()
    {
        // ...
        // The controlled sequence is default-initialized (i.e. zeroed out)
        auto pszFile = std::vector<TCHAR>(32767);
    
        // ...
    
        // Initialise the file dialog
        CFileDialog dlgImport(TRUE,
            _T(".XSL"), _T(""), OFN_ALLOWMULTISELECT | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY, strFilter, this);
        dlgImport.m_ofn.lpstrFile = pszFile.data();
        // Without the cast this would raise a signed/unsigned mismatch warning
        // depending on the target architecture
        dlgImport.m_ofn.nMaxFile = static_cast<uint32_t>(pszFile.size());
        dlgImport.m_ofn.nFileOffset = 0;
    
        if (dlgImport.DoModal() != IDOK)
        {
            // User did not select any files so simply return
            // Memory is cleaned up by vector's d'tor
            return;
        }
    
        // ...
    
        // No need to clean up
    }