Click here to Skip to main content
11,412,833 members (75,754 online)
Click here to Skip to main content

Multiple Selection in a File Dialog

, 23 Nov 2002 CPOL
Rate this:
Please Sign up or sign in to vote.
Shows how to do multiple file selection in a file dialog without having to worry about the size of the buffers

Introduction

When using the Windows FileOpen dialog with multiple selection do you ever wonder how much memory you have to allocate for the buffer. Is one kilobyte going to be enough? Or should you make it ten? How about one Megabyte just to be safe?

It seems that no matter what you choose, you are either going to waste a whole bunch of memory just to be safe, or your user is going to select a bunch of files only to find their selection didn't work because your buffer was too small.

Well no more. If you use the method I am about to describe your problems will be over.

How To

The first and most important thing is that this method will only work with the Explorer style file dialogs because we make use of various messages that the old windows 3.1 style file dialogs do not support.

When you are browsing through your file system using the file dialog, the dialog will send WM_NOTIFY messages to the OFNHook procedure. ( Note: In MFC the hook procedure is set up automatically when you use the CFileDialog class, look up OPENFILENAME in MSDN if you want more information on setting up the OFNHook procedure if you are not using MFC. ) We are interested in trapping the CDN_SELCHANGE notification message. The CDN_SELCHANGE notification message is sent whenever the selection changes in the list box that displays the currently open folder. In MFC you can handle this message by overriding the CFileDialog::OnFileNameChange() function.

Now, in our CDN_SELCHANGE handler, the first thing that is required is to check if the buffer that was allotted using the OPENFILENAME structure is large enough. If it is, then we do not have to bother duplicating the default behaviour. If however, the buffer is too small then we have to take matters into our own hands.

To figure out the required size of the buffer we send two messages to the file dialog. They are the CDM_GETFOLDERPATH and CDM_GETSPEC messages. The CDM_GETFOLDERPATH message will return the required size of a buffer needed to hold the currently selected folder path, and the CDM_GETSPEC will return the required size of the buffer needed to hold all the file names. Now, just add these two values together and if the sum is greater than the nMaxFile member of the OPENFILENAME structure then the supplied buffer is too small.

Now, in order to retrieve the file names from the file dialog, we will have to set up two buffers of our own. One for the folder path and an other for the files. Use the CDM_GETFOLDERPATH message to fill the folder buffer, and use the CDM_GETSPEC message to fill the files buffer. All the files in the files buffer will be enclosed between quotation marks, and separated by spaces. ( In other words, exactly as they are shown in the "File Name" edit box. ) At this point it is also advisable to set some sort of flag to let us know later that we have used our own buffers, and not the default one.

void CFECFileDialog::OnFileNameChange()
{
    TCHAR dummy_buffer;
    
    // Get the required size for the 'files' buffer
    UINT nfiles = CommDlg_OpenSave_GetSpec(GetParent()->m_hWnd, 
        &dummy_buffer, 1);

    // Get the required size for the 'folder' buffer
    UINT nfolder = CommDlg_OpenSave_GetFolderPath(GetParent()->m_hWnd, 
        &dummy_buffer, 1);

    // Check if lpstrFile and nMaxFile are large enough
    if (nfiles + nfolder > m_ofn.nMaxFile)
    {
        bParsed = FALSE;
        if (Files)
            delete[] Files;
        Files = new TCHAR[nfiles + 1];
        CommDlg_OpenSave_GetSpec(GetParent()->m_hWnd, Files, nfiles);

        if (Folder)
            delete[] Folder;
        Folder = new TCHAR[nfolder + 1];
        CommDlg_OpenSave_GetFolderPath(GetParent()->m_hWnd, Folder, 
            nfolder);
    }
    else if (Files)
    {
        delete[] Files;
        Files = NULL;
        delete[] Folder;
        Folder = NULL;
    }

    CFileDialog::OnFileNameChange();
}

Now, another thing we have to handle is when the user clicks the OK button. When the OK button is clicked, the file dialog will return IDOK if there were no errors, however, in our case there will be an error as the default buffer was too small, so the file dialog will return IDCANCEL. What we have to do now is check the error code using the CommDlgExtendedError() function and check if the error was FNERR_BUFFERTOOSMALL ( defined in cderr.h ). If that was the error, and our flag was set to tell us we have used our own buffer, then all is well with the world and we can get the file names from our own buffer.

int CFECFileDialog::DoModal()
{
    if (Files)
    {
        delete[] Files;
        Files = NULL;
        delete[] Folder;
        Folder = NULL;
    }

    int ret = CFileDialog::DoModal();

    if (ret == IDCANCEL)
    {
        DWORD err = CommDlgExtendedError();
        if (err == FNERR_BUFFERTOOSMALL/*0x3003*/ && Files)
            ret = IDOK;
    }
    return ret;
}

All that is left is to extract the names from the buffers. In the supplied demo, I have overridden the GetStartPosition() and GetNextPathName() CFileDialog member functions in order to make this easier.

Using the CFECFileDialog class

If you want to use the supplied class in your own code, just add the FECFileDialog.h and FECFileDialog.cpp files to your project, and use the CFECFileDialog class the same as you would use the CFileDialog class.

That's it. I hope some of you find this useful, because I really hate to waste your time and mine Smile | :)

License

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

Share

About the Author

PJ Arends
President
Canada Canada
No Biography provided

Comments and Discussions

 
GeneralInstant Crash ... VS2010 Pin
RedDK at 22-Apr-11 13:06
memberRedDK22-Apr-11 13:06 
GeneralMy vote of 5 Pin
yenner at 3-Jan-11 17:14
memberyenner3-Jan-11 17:14 
GeneralProblem with GetPathName() Function Pin
dsiyekd at 23-Feb-10 22:34
memberdsiyekd23-Feb-10 22:34 
GeneralCode worked for me Pin
Greg Niswonger at 16-Feb-10 3:00
memberGreg Niswonger16-Feb-10 3:00 
GeneralWindows 7 Pin
Galo Vinueza S. at 6-Apr-09 20:17
memberGalo Vinueza S.6-Apr-09 20:17 
GeneralRe: Windows 7 Pin
aputic at 3-Aug-09 10:20
memberaputic3-Aug-09 10:20 
NewsRe: Windows 7 Bug Pin
ANIL KUMAR SHARMA (INDIA) at 15-Sep-09 23:19
memberANIL KUMAR SHARMA (INDIA)15-Sep-09 23:19 
GeneralRe: Windows 7 [modified] Pin
PJ Arends at 3-Oct-09 14:48
memberPJ Arends3-Oct-09 14:48 
GeneralRe: Windows 7 Pin
Bernd Heusing at 11-Nov-09 5:22
memberBernd Heusing11-Nov-09 5:22 
GeneralRe: Windows 7 Pin
mykel at 8-Jan-10 8:28
membermykel8-Jan-10 8:28 
GeneralRe: Windows 7 Pin
Member 10721127 at 3-Apr-14 0:17
memberMember 107211273-Apr-14 0:17 
GeneralRe: Windows 7 Pin
PJ Arends at 3-Apr-14 10:56
professionalPJ Arends3-Apr-14 10:56 
NewsWindows Template Library now includes CMultiFileDialog Pin
Jim Barry at 28-Jul-07 6:36
memberJim Barry28-Jul-07 6:36 
GeneralOnFileNameOK() warning - return value opposite!!! Pin
BaliDawg at 3-Aug-06 10:12
memberBaliDawg3-Aug-06 10:12 
Generalmicrosoft support says.... Pin
Haroon Sarwar at 30-Jan-06 3:29
memberHaroon Sarwar30-Jan-06 3:29 
GeneralRe: microsoft support says.... Pin
PJ Arends at 30-Jan-06 6:50
memberPJ Arends30-Jan-06 6:50 
QuestionShortCut (*.lnk) files? Pin
Divya Rathore at 12-Jan-06 1:09
memberDivya Rathore12-Jan-06 1:09 
AnswerRe: ShortCut (*.lnk) files? Pin
PJ Arends at 12-Jan-06 13:00
memberPJ Arends12-Jan-06 13:00 
Generalexecution of flash file selecting from filedialog in SDI Pin
abhi rawat at 19-Oct-05 2:07
memberabhi rawat19-Oct-05 2:07 
GeneralAdding Folder Paths Pin
jacob19762000 at 28-Jun-05 1:43
memberjacob1976200028-Jun-05 1:43 
GeneralRe: Adding Folder Paths Pin
PJ Arends at 28-Jun-05 8:25
memberPJ Arends28-Jun-05 8:25 
GeneralCommDlg_OpenSave_GetFolderPath can return < 0 Pin
F Braem at 4-Mar-05 1:56
memberF Braem4-Mar-05 1:56 
QuestionCan we choose multiple files(including folder at the same level) Pin
durbin at 17-Feb-05 10:38
memberdurbin17-Feb-05 10:38 
Generalingenious !!!! Pin
nedo at 25-Dec-04 7:44
membernedo25-Dec-04 7:44 
GeneralGetOpenFileName() Error Pin
Stefan_L_01 at 19-Aug-04 2:26
memberStefan_L_0119-Aug-04 2:26 
Hi

The scenario was already described below (Possible Bug?)

Opening the same Dialog twice may result in a GetOpenFileName Error.

A little bugfix that seems to work very nice is to invalidate the m_ofn.lpstrFile String in DoModal() :


int CFECFileDialog::DoModal()
{
if (Files)
{
delete[] Files;
Files = NULL;
delete[] Folder;
Folder = NULL;
}

m_ofn.lpstrFile[0] = 0;

int ret = CFileDialog::DoModal();

if (ret == IDCANCEL)
{
DWORD err = CommDlgExtendedError();
if (err == FNERR_BUFFERTOOSMALL/*0x3003*/ && Files)
ret = IDOK;
}
return ret;
}




Of course the pointer must be always set to a valid adress.

Stefan
GeneralRe: GetOpenFileName() Error Pin
PJ Arends at 19-Aug-04 8:11
memberPJ Arends19-Aug-04 8:11 
GeneralRe: GetOpenFileName() Error Pin
Stefan_L_01 at 21-Aug-04 4:53
memberStefan_L_0121-Aug-04 4:53 
GeneralRe: GetOpenFileName() Error Pin
PJ Arends at 21-Aug-04 7:23
memberPJ Arends21-Aug-04 7:23 
QuestionObviously ??? Pin
mYkel at 21-Jun-04 9:16
membermYkel21-Jun-04 9:16 
GeneralBrilliant Pin
Rob Manderson at 13-Mar-04 0:39
editorRob Manderson13-Mar-04 0:39 
GeneralIt's all been said... well done and thx! Pin
krutsch at 25-Jan-04 16:10
memberkrutsch25-Jan-04 16:10 
GeneralAnother thank you Pin
clinth at 2-Jan-04 8:54
memberclinth2-Jan-04 8:54 
GeneralThanks very very much Pin
Juergen Klingler at 1-Dec-03 2:12
memberJuergen Klingler1-Dec-03 2:12 
Generalproblem with CDN_FILEOK ( OnFileNameOK ) Pin
petr12345 at 20-Nov-03 13:04
memberpetr1234520-Nov-03 13:04 
Generalcode enhancement & bug fix for single file name selected Pin
petr12345 at 20-Nov-03 12:52
memberpetr1234520-Nov-03 12:52 
QuestionPossible Bug? Pin
defenestration at 16-Oct-03 11:34
memberdefenestration16-Oct-03 11:34 
AnswerRe: Possible Bug? Pin
defenestration at 16-Oct-03 11:55
memberdefenestration16-Oct-03 11:55 
AnswerRe: Possible Bug? Pin
PJ Arends at 16-Oct-03 14:31
memberPJ Arends16-Oct-03 14:31 
GeneralImplementation in Doc/View.. Pin
D.R. at 29-Jul-03 23:03
sussD.R.29-Jul-03 23:03 
GeneralFile Selection Ordering Pin
UKNCDC at 29-Jul-03 2:23
memberUKNCDC29-Jul-03 2:23 
QuestionProblem on XP? Pin
JASchmitz at 16-May-03 8:45
memberJASchmitz16-May-03 8:45 
GeneralOne Question... Pin
Doug Styner at 6-Mar-03 9:16
memberDoug Styner6-Mar-03 9:16 
GeneralRe: One Question... Pin
PJ Arends at 6-Mar-03 9:24
memberPJ Arends6-Mar-03 9:24 
GeneralFolder selection Pin
Tine at 25-Feb-03 23:40
memberTine25-Feb-03 23:40 
GeneralRe: Folder selection Pin
PJ Arends at 26-Feb-03 6:50
memberPJ Arends26-Feb-03 6:50 
Generalgot some problem... Pin
Manikandan at 6-Jan-03 15:58
memberManikandan6-Jan-03 15:58 
GeneralRe: got some problem... Pin
PJ Arends at 7-Jan-03 16:06
memberPJ Arends7-Jan-03 16:06 
GeneralExcellent Pin
Philippe Lhoste at 3-Dec-02 7:26
memberPhilippe Lhoste3-Dec-02 7:26 
GeneralGood job Pin
Shog9 at 24-Nov-02 16:00
memberShog924-Nov-02 16:00 
GeneralRe: Good job Pin
PJ Arends at 25-Nov-02 6:50
memberPJ Arends25-Nov-02 6:50 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.150427.1 | Last Updated 24 Nov 2002
Article Copyright 2002 by PJ Arends
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid