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



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.

Top White Papers and Webcasts

  • As all sorts of data becomes available for storage, analysis and retrieval - so called 'Big Data' - there are potentially huge benefits, but equally huge challenges...
  • The agile organization needs knowledge to act on, quickly and effectively. Though many organizations are clamouring for "Big Data", not nearly as many know what to do with it...
  • Cloud-based integration solutions can be confusing. Adding to the confusion are the multiple ways IT departments can deliver such integration...

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date