Quantcast
Channel: codexpert blog
Viewing all articles
Browse latest Browse all 85

File Open Dialog with Multiple Selection – Part 1: Old Style

$
0
0

One common beginner’s mistake

Someone may use the following code to show a File Open dialog:

Example 1

   CFileDialog dlgOpenFile(TRUE);
   dlgOpenFile.GetOFN().Flags |= OFN_ALLOWMULTISELECT;
   if(IDOK == dlgOpenFile.DoModal())
   {
      // get selected files
      POSITION pos = dlgOpenFile.GetStartPosition();
      while(NULL != pos)
      {
         CString strFilePath = dlgOpenFile.GetNextPathName(pos);
         // ... do something with strFilePath.
      }
   }

Setting OFN_ALLOWMULTISELECT flag tells to Open File dialog to allow multiple file selection. That works fine as log as the user selects a pretty small number of files. Otherwise, it fails with no warning and no file name (or even worse, some garbage) is retrieved.

What is the cause?

If the first parameter of constructor is TRUE, CFileDialog uses GetOpenFileName Windows API function that takes an OPENFILENAME structure. No matter if multiple selection is set, it retrieves all selected (full path and) file names in one single bufffer, which is poited by lpstrFile member of OPENFILENAME. By default, the size of that buffer is set to MAX_PATH (about 260) characters which is pretty small.

Setting a large enough buffer before DoModal

One solution is to make pstrFile member of OPENFILENAME to point to a large enough buffer, able to keep much more file names. Also, the nMaxFile structure member must be set to actual extended buffer size (in characters).

Example 2

   CFileDialog dlgOpenFile(TRUE);
   // add OFN_ALLOWMULTISELECT flag
   dlgOpenFile.GetOFN().Flags |= OFN_ALLOWMULTISELECT;

   try
   {
      // set a buffer to keep at least 100 full path and file names
      const int nBufferSize = 100 * (MAX_PATH + 1) + 1;
      CString strBuffer;
      LPTSTR pBuffer = strBuffer.GetBufferSetLength(nBufferSize);
      dlgOpenFile.GetOFN().lpstrFile = pBuffer;
      dlgOpenFile.GetOFN().nMaxFile = nBufferSize;

      // show modal Open File dialog
      if(IDOK == dlgOpenFile.DoModal())
      {
         // get selected files
         POSITION pos = dlgOpenFile.GetStartPosition();
         while(NULL != pos)
         {
            CString strFilePath = dlgOpenFile.GetNextPathName(pos);
            // ... do something with strFilePath.
         }
      }
      // release buffer
      strBuffer.ReleaseBuffer();
   }
   catch(CException* e)
   {
      e->ReportError();
      e->Delete();
   }

It works but is not very ellegant because uses a fixed buffer. Next, well show a method which dynamically estimates and allocate the necessary buffer.

Overriding CFileDialog::OnFileNameChange

CFileDialog::OnFileNameChange is a virtual function that is called as a response to CDN_SELCHANGE notification, sent when the user changes the selection. We can override that function in our own CFileDialog-derived class, then send CDM_GETFOLDERPATH and CDM_GETSPEC mesages in order to estimate the required buffer size.

Example 3

class CMyFileDialog : public CFileDialog
{
// Attributes
private:
   LPTSTR m_pFileBuff;
// ...
// Overrides
protected:
   virtual void OnFileNameChange();
// ...
};
void CMyFileDialog::OnFileNameChange()
{  
   ASSERT(GetOFN().Flags & OFN_EXPLORER);
   CWnd* pParent = GetParent();
   ASSERT(NULL != pParent);

   // get required sizes for path and file names buffers
   const UINT nPathSize = (UINT)pParent->SendMessage(CDM_GETFOLDERPATH);
   const UINT nFileSize = (UINT)pParent->SendMessage(CDM_GETSPEC);
   const UINT nMaxFile = GetOFN().nMaxFile;

   if(nPathSize + nFileSize > nMaxFile)
   {
      delete []m_pFileBuff;
      m_pFileBuff = new TCHAR[nPathSize + nFileSize + 1];
      // set new buffer
      GetOFN().lpstrFile = m_pFileBuff;
      GetOFN().nMaxFile = nPathSize + nFileSize + 1;
   }

   CFileDialog::OnFileNameChange();
}

Pretty nice but it works only if CFileDialog has not Vista style. I’ll show how to resolve this, in the next article.

Resources

See also


Viewing all articles
Browse latest Browse all 85

Trending Articles