locked
CFileDialog and OFN_ALLOWMULTISELECT RRS feed

  • Question

  • The MSDN page for CFileDialog says in part:

      When the user allocates their own buffer to accommodate OFN_ALLOWMULTISELECT, the buffer cannot be larger than 2048 or else everything gets corrupted (2048 is the maximum size).

      Additionally, you must set m_ofn.nMaxFile with the number of characters in the buffer pointed to by m_ofn.lpstrFile. If you set the maximum number of files to be selected to n, the necessary buffer size is n*(_MAX_PATH + 1) + 1. For example:

      CFileDialog dlgFile(TRUE);
      CString fileName;
      const int c_cMaxFiles = 100;
      const int c_cbBuffSize = (c_cMaxFiles * (MAX_PATH + 1)) + 1;
      dlgFile.GetOFN().lpstrFile = fileName.GetBuffer(c_cbBuffSize);
      dlgFile.GetOFN().nMaxFile = c_cMaxFiles;

    Well, (100 * (260 + 1)) + 1 is larger than 2048, so everything gets corrupted.  Does anyone know the real rules?

    Tuesday, August 25, 2009 6:07 AM

All replies

  • I tried this code its working fine if i selected 100 files.
    ********************************************* 

    // Create dialog to open multiple files.
     CFileDialog dlg(TRUE, _T("txt"), _T("*.txt"), OFN_ALLOWMULTISELECT);

     // Create buffer for file names.
     const DWORD numberOfFileNames = 100;
     const DWORD fileNameMaxLength = MAX_PATH + 1;
     const DWORD bufferSize = (numberOfFileNames * fileNameMaxLength) + 1;
     TCHAR* filenamesBuffer = new TCHAR[bufferSize];

     // Initialize beginning and end of buffer.
     filenamesBuffer[0] = NULL;
     filenamesBuffer[bufferSize-1] = NULL;

     // Attach buffer to OPENFILENAME member.
     dlg.m_ofn.lpstrFile = filenamesBuffer;
     dlg.m_ofn.nMaxFile = bufferSize;

     // Create array for file names.
     CString fileNameArray[numberOfFileNames];
     if(dlg.DoModal() == IDOK)
     {
      // Retrieve file name(s).
      POSITION fileNamesPosition = dlg.GetStartPosition();
      int iCtr = 0;
      while(fileNamesPosition != NULL)
      {
       fileNameArray[iCtr] = dlg.GetNextPathName(fileNamesPosition);
       iCtr++;
      } 
     }
     // Release file names buffer.
     delete[] filenamesBuffer;


    Please mark the post as answer if it is helpfull to you because it boosts the members to answer more and more.
    • Proposed as answer by _SuDhiR_ Tuesday, August 25, 2009 7:10 AM
    Tuesday, August 25, 2009 6:34 AM
  • The MSDN sample seems to be incorrect and has to be changed to “dlgFile.GetOFN().nMaxFile = c_cbBuffSize;

     

    Since the documentation for OPENFILENAME structure does not mention a limitation of 2048 characters, I think that the MFC documentation is outdated.

     

    Tuesday, August 25, 2009 6:40 AM
  • I agree, as far as I can tell, the sentence about the 2048 character limit is ancient history.

    Furthermore it seems that the application doesn't even have to set lpstrFile or nMaxFile at all, as far as I can tell at the moment.  Immediately prior to the section I quoted, MSDN says the following:

      To allow the user to select multiple files, set the OFN_ALLOWMULTISELECT flag before calling DoModal. You must supply your own file name buffer to accommodate the returned list of multiple file names. Do this by replacing m_ofn.lpstrFile with a pointer to a buffer you have allocated, after constructing the CFileDialog, but before calling DoModal.

    Two thirds of that paragraph also seem to be ancient history.

    Tuesday, August 25, 2009 7:09 AM
  • Looking at MFC sources, it seems that the default buffer is limited to _MAX_PATH (260) characters, which can be insufficient in case of multiple selections and therefore has to be replaced.

    Tuesday, August 25, 2009 7:41 AM
  • Rong-Chun Zhang proposed marking Viorel's posting as an answer.

    Viorel's posting is enormously helpful.  Any programmer who uses the MFC class CFileDialog had better be informed that they had better allocate their own buffer, set the CFileDialog's m_ofn.lpstrFile, and set the CFileDialog's m_ofn.nMaxFile.  If a programmer doesn't do this then all the MSDN pages that talk about limits of 32,767 TCHARs or no limits or whatever are useless because MFC defaults to a limit of 260 TCHARs.  I thank Viorel.

    But Viorel's posting doesn't give all of the rules.

    SuDhiR's posting is helpful too.  SuDhiR really helped show how badly this MSDN page needs fixing too.  But SuDhiR's posting also doesn't give all of the rules.

    I'll bet there is no public answer.  No one outside of Microsoft knows the real rules.  Some people very helpfully posted the fractions that they could find.

    By the way I also read other MSDN pages about OpenFileDialog, some in the MFC section and some in other sections of MSDN.  Lots and lots of MSDN pages need fixing.

    • Edited by Norman Diamond Tuesday, September 1, 2009 7:33 AM fixed gypographical bug
    Tuesday, September 1, 2009 7:31 AM
  • Dear Norman,

    Thanks for your feedback.

    I will log this issue to our product designers via internal channel. If you find any issue on our product(document is inclued), It is appreciated that you can submit a ticket and add your supplements into our Connect Portal. 

    https://connect.microsoft.com/VisualStudio

    As we strive to capture any and all product feedback so as to ensure that we are continuously developing Microsoft products to meet customer needs, feedback such as yours is always taken very seriously. It will help us to make our products easier and more powerful to use.

    Thanks,
    Rong-Chun Zhang
    MSDN Subscriber Support in Forum
    If you have any feedback on our support, please contact msdnmg@microsoft.com

    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Friday, September 4, 2009 9:04 AM
  • Maybe the length of the buffer isn't a problem, maybe.  But the lengths of files on disk, in the directory that is currently navigated to in a CFileDialog, is a big problem.

    A directory has 11 files whose names are around 200 characters each, plus a few shorter filenames.  So the total of all the lengths of the filenames is greater than 2048.  If the user navigates the open file dialog to that directory, everything gets corrupted.

    (Windows XP SP3, C++ libraries including MFC for VC++ 2005 SP1.)

    Tuesday, September 8, 2009 8:41 AM
  • Since my application doesn't need the FileTitle members, I took out some code that had declared relevant variables and let CFileDialog use its own member (64 TCHARs long).

    For the File members I improved my code to avoid static limits, so for example if the user selects 20,000 files whose names are all 200 characters long, I compute (20,000 + 1) * MAX_PATH.  MSDN CommDlgExtendedError Function) says I can retrieve the necessary buffer size from the first two bytes of the lpstrFile buffer, but I compute (number of files + 1) * MAX_PATH instead of trying to pull that value out of a two byte integer.

    Result:  If the user navigates to any folder that has more than around 3 files in it, everything gets corrupted.

    I don't know what the actual conditions are, but intuitively it seems like MFC's default 64 character buffer for file titles causes corruption to occur more frequently.

    I might have found an odd workaround.  RedrawWindow removes visible evidence of corruption.  I don't know how to detect if there's any corruption in internal structures of CFileDialog or the underlying APIs.
    Thursday, September 10, 2009 12:34 AM
  • Dear norman,

    I tried the following code on my side,

       CFileDialog dlgFile(TRUE, _T("txt"), _T("*.txt"), OFN_ALLOWMULTISELECT);
       CString fileName;
       const int c_cMaxFiles = 5000;
       const int c_cbBuffSize = (c_cMaxFiles * (MAX_PATH + 1)) + 1;
       dlgFile.GetOFN().lpstrFile = fileName.GetBuffer(c_cbBuffSize);
       dlgFile.GetOFN().nMaxFile = c_cMaxFiles;

       CString fileNames;
       if(dlgFile.DoModal() == IDOK)
      {
        POSITION fileNamesPosition = dlgFile.GetStartPosition();
        int iCtr = 1;
        while(fileNamesPosition != NULL)
        {
            dlgFile.GetNextPathName(fileNamesPosition);      
            iCtr++;
        }

      }

    And the the total length of the selected filenames can be greater than 2048.

    >I don't know how to detect if there's any corruption in internal structures of CFileDialog or the underlying APIs.

    You can try to dig into the source code of MFC project.

    Thanks,
    Rong-Chun Zhang
    MSDN Subscriber Support in Forum
    If you have any feedback on our support, please contact msdnmg@microsoft.com


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Monday, September 14, 2009 11:20 AM
  • Mr. Zhang,

    Thank you for your efforts.  As far as I could tell from the amount of source code that's published for MFC, the default buffer sizes of 260 and 64 are somewhat limited in usability, but I can't see if they cause any internal corruption.  In order to see if corruption is really caused at the limit of 2048, I would need to see source code of the underlying Windows APIs.

    Now, in your test, nMaxFile was assigned 5000.  I would like to see if you can actually select 5000 files with names of say around 200 characters each.  I have a feeling that your code will fail when the total of the lengths of selected filenames reaches 5000, instead of succeeding all the way up to around 5000 * 260.

    [(5000 * (260 + 1)) + 1?  Yet one more doubtful characteristic of that MSDN page is that even if the formula for the buffer size is also assigned to nMaxFile, it still seems wrong.  MAX_FILE already allows room for one null character, and the final + 1 allows room for the doubled trailing null character, but the other + 1 should be positioned to allow room for the containing folder name.]

    Monday, September 14, 2009 11:38 PM
  • Hello Norman,

    By discussing with production team, they confirmed that the limitation of 2048 only existed in Windows 95 and was fixed in NT4 and Windows 98. The Windows SDK documentation for the OPENFILENAME structure does not list any such limitation and current versions of Windows certainly support more than 2048 characters when calling GetOpenFileName to display an Explorer-style file dialog. It means that when the platform is fixed, the MFC docs become wrong.

    By the way, the documentation for Visual Studio 2008 doesn’t have a limitation of 2048.
    http://msdn.microsoft.com/en-us/library/dk77e5e7.aspx

    Thanks,
    Rong-Chun Zhang
    MSDN Subscriber Support in Forum
    If you have any feedback on our support, please contact msdnmg@microsoft.com
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Wednesday, September 16, 2009 3:52 AM
  • Thank you Mr. Zhang.

    I assume that the MSDN page will be corrected regarding the 2048 statement.  Other corrections are also needed, especially since your own example repeated two of MSDN's mistakes.

    dlgFile.GetOFN().nMaxFile should be c_cbBuffSize not c_cMaxFiles.

    c_cbBuffSize and nMaxFile should be ((c_cMaxFiles + 1) * MAX_PATH) + 1 not (c_cMaxFiles * (MAX_PATH + 1)) + 1.

    As Viorel pointed out:  the default buffer is limited to _MAX_PATH (260) characters, which can be insufficient in case of multiple selections and therefore has to be replaced.

    Furthermore, the default buffer for FileTitle is limited to 64 characters and therefore surely always has to be replaced.

    Also the MSDN page on "CommDlgExtendedError Function" says that if the error is that the buffer isn't large enough then the necessary size can be retrieved from the first two bytes of lpstrFile, but that obviously isn't true.  I didn't try to find out if the necessary size might be retrievable from the first four bytes (Win32) or first eight bytes (x64).  One solution might be to estimate and then grow the buffer until the error stops.
    Wednesday, September 16, 2009 4:59 AM
  • Dear Norman,

    Thanks for your feedback and suggestion.

    Thanks,
    Rong-Chun Zhang
    MSDN Subscriber Support in Forum
    If you have any feedback on our support, please contact msdnmg@microsoft.com
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Wednesday, September 16, 2009 8:53 AM
  • That's really important:

    dlgFile.GetOFN().nMaxFile MUST be c_cbBuffSize not c_cMaxFiles.

    Friday, October 7, 2016 1:16 PM