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

IT Offers

Comments

  • Easier Way to Select Multiple Files.

    Posted by Legacy on 09/26/2003 12:00am

    Originally posted by: Sergio A. Hernandez

    It seems that your code needs to be updated.  You can try this code if you want to only Select Multiple files.
    
    

    CString openFileDialogTitle = "Open File(s)";
    CString openFileDialogDefaultExtension = "*.*";
    CString openFileDialogFilterExtension = "All Files (*.*)|*.*||";

    CString file = "";
    CFileDialog * openFileDialog = NULL;
    openFileDialog = ( CFileDialog * )new CFileDialog( TRUE, openFileDialogDefaultExtension,NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT|OFN_FILEMUSTEXIST| OFN_EXPLORER|OFN_ALLOWMULTISELECT|OFN_LONGNAMES|OFN_ENABLESIZING, openFileDialogFilterExtension, this );

    /*--- Assign File Dialog Title. ---*/
    openFileDialog->m_ofn.lpstrTitle = openFileDialogTitle;
    TCHAR * tcharFile = new TCHAR[ 32767 ];
    ZeroMemory( tcharFile, 32767 );
    openFileDialog->m_ofn.lpstrFile = tcharFile;
    openFileDialog->m_ofn.nMaxFile = 32767;
    openFileDialog->m_ofn.nFileOffset = 0;

    /*-- Get Dialog Returned Dialog. ---*/
    int ret = openFileDialog->DoModal( );

    POSITION currentPos;
    if( IDOK == ret ) {

    currentPos = openFileDialog->GetStartPosition( );
    while( currentPos != NULL ) {

    file = openFileDialog->GetNextPathName(
    currentPos );
    AfxMessageBox( file );
    }
    }

    /*--- Clean up Memory. ---*/
    if( openFileDialog != NULL )
    delete openFileDialog;

    delete tcharFile;

    • Why does it lose files if you change directories?

      Posted by Mike Pliam on 01/27/2009 02:13pm

      Your code works nicely but if I change directories, it loses the files from any preceeding directories. Any way to fix that?

      Reply
    Reply
  • I agree this is not a good idea.....

    Posted by Legacy on 03/05/2003 12:00am

    Originally posted by: Richard 'vajuras' Osborne

    I'm sorry but Borland is right. Why not just use OFN_ALLOWMULTISELECT? What codeguru needs is a tut on how to use CFileDialog.....

    Reply
  • Why can not select only one file

    Posted by Legacy on 01/19/2003 12:00am

    Originally posted by: suvn.w

    It works well but when I only select one file, it cann't work properly, why?

    Reply
  • dude this seems pretty silly

    Posted by Legacy on 02/21/2002 12:00am

    Originally posted by: borland

    you do know you can just call CFileDialog with parameters of OFN_ALLOWMULTISELECT, etc and it will let you pick more than one file. Inheriting a class on top of it is kinda silly don't you think?

    Reply
  • Looking for the same

    Posted by Legacy on 04/27/2001 12:00am

    Originally posted by: Shrinivas

    Thanks. I was looking for the same. thanks again - shrini

    Reply
  • Not bad.

    Posted by Legacy on 12/20/2000 12:00am

    Originally posted by: Srinivasa

    Its cool way of overridding CFileDialog behaviour.

    Reply
  • ThanX

    Posted by Legacy on 05/17/2000 12:00am

    Originally posted by: kabir

    thanx for that, it solved a problem in less time than it would have taken

    Reply
  • m_ofn.nMaxFile = 2048; // arbitrary limit?

    Posted by Legacy on 01/11/2000 12:00am

    Originally posted by: Malcolm Ross

    Hi there,

    I see that in your class you assign a buffer of 2048 characters for storing the list of filenames. Is 2048 just an arbitrarily chosen number, or did you choose 2048 for a special reason? I understand that for multiple filenames you'll need more characters than just _MAX_PATH, but is there a limit to how large a buffer you can assign?

    Cheers,

    Mal.

    Reply
  • Override OnFileOpen in CWinApp derived class.

    Posted by Legacy on 06/19/1999 12:00am

    Originally posted by: Gautam N. Lad

    Hi,
    
    Isn't it easier to just override the OnFileOpen in the
    CWinApp derived class? It works just fine for me.
    Here's what I did (with multiple selection):

    void CMyApp::OnFileOpen()
    {
    static char BASED_CODE szFilter[] =
    "Image Files (*.bmp,*.dib)|*.bmp;*.dib||"
    PSZ pszFile=new char[32767];
    CFileDialog cfd(TRUE,".bmp",NULL,
    OFN_HIDEREADONLY|
    OFN_OVERWRITEPROMPT|
    OFN_FILEMUSTEXIST |
    OFN_EXPLORER|
    OFN_ALLOWMULTISELECT|
    OFN_LONGNAMES,
    szFilter);

    ZeroMemory(pszFile,32767);
    cfd.m_ofn.lpstrFile=pszFile;
    cfd.m_ofn.nMaxFile=32767;
    cfd.m_ofn.nFileOffset=0;

    if(cfd.DoModal()==IDOK)
    {
    POSITION pos=cfd.GetStartPosition();
    while(pos!=NULL)
    {
    CString csFile=cfd.GetNextPathName(pos);
    OpenDocumentFile(csFile);
    }
    }
    }

    The code should be self-expalanatory....pretty much. =)
    What is the advantage of your class, compared to
    what I have here?

    Bye!

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Go Deeper

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds