Click here to Skip to main content
Click here to Skip to main content

Opening multipe documents of several types at once

By , 15 May 2004
 

Open dialog showing multiple files types and two selected files

Introduction

If you have a MDI application, it is not uncommon to also have several document classes. The MFC's default implementation of the open file dialog has two shortcomings that your users may find annoying: it only shows one file type at a time, and does not allow to open multiple files at once. The class explained in this article solves these issues.

Using the code

  • Add the four files included in the source code to your project.
  • Add a new string to your string table called IDS_ALLDOCSFILTER, this will be the string shown as the filter name.

    the string table of your app

  • Include the extended doc manager header in your CWinApp.cpp file:
    #include "DocManager2.h"
  • Create the doc manager in the first line of your InitInstance CWinApp. Notice that m_pDocManager is a member of the base class.
    BOOL CMyApp::InitInstance()
    {
        m_pDocManager= new CDocManager2();
        ... the rest of your code ...
    }
  • That is it! That was easy! Compile and try to open a file to test the new functionality.

Inside the class

If you take a peek under the CWinApp hood, you will find that it delegates file related functions to an instance of the undocumented class CDocManager (Roger Allen has a nice explanation about CDocManager here). This class is actually responsible for showing the open file dialog and for opening the document, so it is the ideal candidate for our task at hand. So let's get into work.

Showing all file types at once

The first step is to override the CDocManager::DoPromptFileName function. This function was not really made to be overridden, so in order to make a slight change, you have to copy the base class code and tweak it a little. The following code adds a new filter to the filter list:

BOOL CDocManager2::DoPromptFileName(CString& fileName, 
    UINT nIDSTitle, DWORD lFlags,
    BOOL bOpenFileDialog, CDocTemplate* pTemplate)
{
    ... original code ...
    if (pTemplate != NULL)
    {
        ASSERT_VALID(pTemplate);
        _AfxAppendFilterSuffix(strFilter, 
                dlgFile.m_ofn, pTemplate, &strDefault);
    }
    else
    {
        // append all docs filter
        CString strFilters;
        POSITION pos = m_templateList.GetHeadPosition();
        // for each doc template
        while (pos != NULL)
        {
            CDocTemplate* pTemplate = 
                    (CDocTemplate*)m_templateList.GetNext(pos);
            CString strFilterExt;
            // append its extension to the filter list
            pTemplate->GetDocString(strFilterExt,CDocTemplate::filterExt);
            if(!strFilterExt.IsEmpty())
                strFilters+=_T('*')+strFilterExt+_T(';');
        }
        // delete the trailing ;
        strFilters.Delete(strFilters.GetLength()-1,1);

        CString allDocsFilter;
        VERIFY(allDocsFilter.LoadString(IDS_ALLDOCSFILTER));
        strFilter += allDocsFilter;
        strFilter += (TCHAR)'\0';   // next string please
        strFilter += strFilters;
        strFilter += (TCHAR)'\0';   // last string
        dlgFile.m_ofn.nMaxCustFilter++;
        
    ... original code ...
    // select the all documents filter as the default filter
    dlgFile.m_ofn.nFilterIndex=0;
    INT_PTR nResult = dlgFile.DoModal();
    fileName.ReleaseBuffer();
    return nResult == IDOK;
}

Unfortunately, this code uses the internal MFC function _AfxAppendFilterSuffix. To make the code compile, the only solution I found was to copy the code verbatim from MFC source files. Let's hope it does not change a lot in future versions of MFC!

Opening multiple files at once

To open multiple files at once, we must override CDocManager::OnFileOpen. Apart from adding the obvious OFN_ALLOWMULTISELECT flag, we must add code to iterate the selected files list and open the documents one by one:

void CDocManager2::OnFileOpen()
{
    // prompt the user (with all document templates)
    CString newName;
    if (!DoPromptFileName(newName, AFX_IDS_OPENFILE,
      OFN_HIDEREADONLY | OFN_FILEMUSTEXIST 
      | OFN_ALLOWMULTISELECT, TRUE, NULL))
        return; // open cancelled
    LPSTR szName=newName.GetBuffer();
    // replace all the embebbed nulls, CString can not handle them well
    for(int i=0;i<newName.GetAllocLength();i++)
    {
        if(_T('\0')==szName[i])
            if(_T('\0')!=szName[i+1])
            szName[i]=_T('*');
    }
    newName.ReleaseBuffer();

    // get a vector of all names
    std::vector<CString> vectorFiles=split(newName,_T("*"));

    CString strPath=vectorFiles[0];
    if(1==vectorFiles.size())
        AfxGetApp()->OpenDocumentFile(strPath);
    else
    {
        for(std::vector<CString>::iterator i=vectorFiles.begin()+1;
                                                  i!=vectorFiles.end();i++)
        {
            AfxGetApp()->OpenDocumentFile(strPath+_T('\\')+*i);
        }
    }
}

Now, we have a class that behaves as we want. Happy coding!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Ernesto Perales Soto
Web Developer
Mexico Mexico
@Work : Doing UML modelling for food
@Home : Still coding for fun!

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Generalcompiles with Visual Studio 2010 on Windows Server 2008 64-bit but ...memberRedDK23-May-11 8:59 
There are several articles at code project that address the issue of OpenFileDialog and multi-select. The list goes back through many versions of Visual Studio, through many years. Always good to know that code compiles using the latest one.
 
One issue which might have been addressed back in 2004 is this character string size limit on the "selection" of 200-odd or so.
 
This is still apparent.
 
And just a note to the "fix" -> doesn't make the issue any better.
 
In fact the http://www.codeproject.com/dialog/pja_multiselect.asp project fails with a crash where this project fairs substantially more gracefully.
 
Thanks
GeneralRe: compiles with Visual Studio 2010 on Windows Server 2008 64-bit but ...memberErnesto Perales Soto23-May-11 14:33 
RedDK,
 
Thanks for your feedback. If you have any code to fix this bug that has manage to survive all this years I'll gladly merge it and republish the code.
 
cheers!

GeneralRe: compiles with Visual Studio 2010 on Windows Server 2008 64-bit but ...memberRedDK24-May-11 5:45 
yes,
 
Our concord ...
QuestionThe Code an not be compiled [modified]memberwoodyzhang21-Jun-06 16:42 
There is an error occurs when I compile the project.
 
error C2039: 'Tokenize' : is not a member of 'CString'
 
I can not handle the problem. So help me!
-- modified at 22:42 Wednesday 21st June, 2006
QuestionRe: The Code an not be compiledmemberErnesto Perales Soto22-Jun-06 3:45 
Hi Woody,
 
I donwloaded the demo project and compiled it using Visual Studio 2003 and it compiled fine. I no longer have Visual Studio 2002, but I'm sure it compiled there too. Maybe you are using an earlier version?
 
Confused | :confused:
 
eperales
AnswerRe: The Code an not be compiledmemberhu496382820-May-09 6:31 
I test it successfully.
GeneralMultiple SelectionmemberPJ Arends30-May-04 14:15 
In your sample multiple file selection will fail if the selection is too large (more than 260 chracters). See http://www.codeproject.com/dialog/pja_multiselect.asp[^] for a method on how to get around this problem.
 






Sonork 100.11743 Chicken Little
 
"You're obviously a superstar." - Christian Graus about me - 12 Feb '03
 
Within you lies the power for good - Use it!
GeneralGood catch....memberErnesto Perales Soto31-May-04 20:09 
Since CDocManager2::DoPromptFileName uses the original implementation of CFileDialog it will fail as described in your article.
 
This can be fixed by changing the first line of this function to use your CFECFileDialog class.
 
Thanks for pointing this out!
 
eperales
GeneralVery handy !memberWREY16-May-04 15:57 
There are times indeed, when being able to open more than one file at once (in both SDI amd MDI type applications) is desirable, and this article is a trailblazing example of how it can be done.
 
It is something good to have around to know when next you need such a feature, that it is doable.
 
The author has explained himself clearly on how to achieve just such a job. GOOD WORK!!
 
(The only thing I would ask, is whether it has been tried on VC6 ?)
 
Smile | :)
 
William
 
Fortes in fide et opere!
GeneralThanks for your words!memberErnesto Perales Soto17-May-04 3:46 
I no longer have VC6 around to test the code. Since it uses an undocumented class and an internal MFC function there is a chance of failure.
 
To be on the safe side, first I would compare the three functions against the MFC source code.
 
Smile | :)
 
adiós!
 
eperales

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130617.1 | Last Updated 16 May 2004
Article Copyright 2004 by Ernesto Perales Soto
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid