Multiple File Selection Dialog

I wanted to open a number of files at the same time from a Visual C++/MFC application. However, a ClassWizard generated application (with file support) only allows for the opening of a single file at a time. Therefore, I derived my own custom class from CFileDialog called MFileDlg. Using this class, I can now specify multiple files to be opened from the Open File dialog.

Class Declaration:


class MFileDlg : public CFileDialog
{
DECLARE_DYNAMIC(MFileDlg)

public:
 MFileDlg(BOOL bOpenFileDialog, LPCTSTR lpszDefExt = NULL , LPCTSTR lpszFileName = NULL,
  DWORD dwFlags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_ALLOWMULTISELECT,
  LPCTSTR lpszFilter = NULL, CWnd* pParentWnd = NULL) ;

 int DoModal();
 virtual ~MFileDlg();

protected:
 //{{AFX_MSG(MFileDlg)
 // NOTE - the ClassWizard will add and remove member functions here.
 //}}AFX_MSG

 TCHAR* m_pszFile;
 DECLARE_MESSAGE_MAP()
};

Class Implementation:


IMPLEMENT_DYNAMIC(MFileDlg, CFileDialog)

MFileDlg::MFileDlg(BOOL bOpenFileDialog, LPCTSTR lpszDefExt, LPCTSTR lpszFileName,
 DWORD dwFlags, LPCTSTR lpszFilter, CWnd* pParentWnd) :
 CFileDialog(bOpenFileDialog, lpszDefExt, lpszFileName, dwFlags, lpszFilter, pParentWnd)
{
 m_pszFile = new TCHAR[2048]; //set a 2K buffer to hold selected files
 m_pszFile[0] = '\0'; //initialize pointer;
}

BEGIN_MESSAGE_MAP(MFileDlg, CFileDialog)
//{{AFX_MSG_MAP(MFileDlg)
// NOTE - the ClassWizard will add and remove mapping macros here.
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

MFileDlg::~MFileDlg()
{
 if (m_pszFile != NULL)
 delete [] m_pszFile; //cleanup
}

int MFileDlg::DoModal()
{
 ASSERT_VALID(this);
 ASSERT(m_ofn.Flags & OFN_ALLOWMULTISELECT); //make sure multiple file selection is on

 m_ofn.lpstrFile = m_pszFile; //initialize the OPENFILENAME structure
 m_ofn.nMaxFile = 2048;

 return CFileDialog::DoModal();
}

How to Use:

1. On your CwinApp-derived class, override the OnOpenFile() function.


void CDigilogApp::OnFileOpen() 
{
// TODO: Add your command handler code here
 MFileDlg dlgFile(TRUE);

 CString title, strFilter, strDefault;
 VERIFY(title.LoadString(AFX_IDS_OPENFILE));

 // do for all doc template
 POSITION pos = GetFirstDocTemplatePosition();
 BOOL bFirst = TRUE;
 while (pos != NULL)
 {
  CDocTemplate* pTemplate = GetNextDocTemplate(pos);
  AppendFilterSuffix (strFilter, dlgFile.m_ofn, pTemplate, 
  bFirst ? &strDefault : NULL);
  bFirst = FALSE;
 }

 // append the "*.*" all files filter
 CString allFilter;
 VERIFY(allFilter.LoadString(AFX_IDS_ALLFILTER));
 strFilter += allFilter;
 strFilter += (TCHAR)'\0';   // next string please
 strFilter += _T("*.*");
 strFilter += (TCHAR)'\0';   // last string
 dlgFile.m_ofn.nMaxCustFilter++;

 dlgFile.m_ofn.lpstrFilter = strFilter;
 dlgFile.m_ofn.lpstrTitle = title;
 dlgFile.m_ofn.hwndOwner = AfxGetMainWnd()->GetSafeHwnd();

 if (dlgFile.DoModal() == IDOK)
 {
  POSITION pos = dlgFile.GetStartPosition();
  while (pos != NULL)
  {
   CString strPath = dlgFile.GetNextPathName(pos);
   if (strPath.Find(":\\\\") == 1 && strPath.GetLength() > 4)
   {
    // this means we have an invalid path that looks like this:
    // C:\\cda.dgl
    // get rid of extra slash
    CString temp;
    temp = strPath.Left(3);
    temp += strPath.Mid(4);
    strPath = temp;
   }
   OpenDocumentFile(strPath);
  }
 }
} 
2. Add this declaration and function to your CwinApp- derived class .


static void AppendFilterSuffix(CString& filter, OPENFILENAME& ofn,
CDocTemplate* pTemplate, CString* pstrDefaultExt); 

static void AppendFilterSuffix(CString& filter, OPENFILENAME& ofn, 
CDocTemplate* pTemplate, CString* pstrDefaultExt)
{
 ASSERT_VALID(pTemplate);
 ASSERT_KINDOF(CDocTemplate, pTemplate);

 CString strFilterExt, strFilterName;
 if (pTemplate->GetDocString(strFilterExt, CDocTemplate::filterExt) &&
  !strFilterExt.IsEmpty() &&
  pTemplate->GetDocString(strFilterName, CDocTemplate::filterName) &&
  !strFilterName.IsEmpty())
 {
  // a file based document template - add to filter list
  ASSERT(strFilterExt[0] == '.');
  if (pstrDefaultExt != NULL)
  {
   // set the default extension
   *pstrDefaultExt = ((LPCTSTR)strFilterExt) + 1;  // skip the '.'
   ofn.lpstrDefExt = (LPTSTR)(LPCTSTR)(*pstrDefaultExt);
   ofn.nFilterIndex = ofn.nMaxCustFilter + 1;  // 1 based number
  }

  // add to filter
  filter += strFilterName;
  ASSERT(!filter.IsEmpty());  // must have a file type name
  filter += (TCHAR)'\0';  // next string please
  filter += (TCHAR)'*';
  filter += strFilterExt;
  filter += (TCHAR)'\0';  // next string please
  ofn.nMaxCustFilter++;
 }
}

History