Selecting multiple files in File Open dialog

Many professional MDI applications support selecting more than one file in the File Open dialog. It is easy to add this support to MFC applications.

Opening files (and other document mamangement activities) is implemented in MFC's CDocMananger class (see source file docmgr.cpp). CWinApp contains a member variable m_pDocManager poining to the CDocManager object to use. If you want to modify the standard MFC behaviour, simply provide your own CDocManager-derived object.

For adding the "multi open" support, I derived a class CMultiOpenDocManager from CDocManager and overrode the OnFileOpen function. A new DoPromptFileNames function is a utility function similar to the existing DoPromptFileName function but capable of returning more than one file name.

class CMultiOpenDocManager : public CDocManager
{
public:
	CMultiOpenDocManager() { }
	virtual void OnFileOpen();
	virtual BOOL DoPromptFileNames(CStringList& fileNames, UINT nIDSTitle, DWORD lFlags, BOOL bOpenFileDialog, CDocTemplate* pTemplate);
};

Using the feature is as simple as adding the following line in your app's InitInstance function:

	m_pDocManager = new CMultiOpenDocManager;

The implementation of the OnFileOpen function is very similar to the original implementation. I just replaced the call to DoPromptFileName with a call to my new function DoPromptFileNames, added the OFN_ALLOWMULTISELECT flag and introduced a loop around the OpenDocumentFile call:

void CMultiOpenDocManager::OnFileOpen()
{
	CStringList newNames;
	if (!DoPromptFileNames(newNames, AFX_IDS_OPENFILE,
	  OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT, TRUE, NULL))
		return; // open cancelled

	POSITION pos = newNames.GetHeadPosition();
	while (pos)
	{
		CString newName = newNames.GetNext(pos);
		AfxGetApp()->OpenDocumentFile(newName);
	}
}

Now for the DoPromptFileNames function: It is a nearly perfect copy of the original function. I marked the modifications by a comment. The implementation uses a function AppendFilterSuffix which is defines as a file local (static) function in docmgr.cpp. You will have to copy the function into the file where CMultiOpenDocManager::DoPromptFileNames is implemented.

BOOL CMultiOpenDocManager::DoPromptFileNames(CStringList& fileNames, UINT nIDSTitle, DWORD lFlags, BOOL bOpenFileDialog, CDocTemplate* pTemplate)
{
	CFileDialog dlgFile(bOpenFileDialog);

	CString title;
	VERIFY(title.LoadString(nIDSTitle));

	dlgFile.m_ofn.Flags |= lFlags;

	CString strFilter;
	CString strDefault;
	if (pTemplate != NULL)
	{
		ASSERT_VALID(pTemplate);
		AppendFilterSuffix(strFilter, dlgFile.m_ofn, pTemplate, &strDefault);
	}
	else
	{
		// do for all doc template
		POSITION pos = m_templateList.GetHeadPosition();
		BOOL bFirst = TRUE;
		while (pos != NULL)
		{
			CDocTemplate* pTemplate = (CDocTemplate*)m_templateList.GetNext(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
#ifndef _MAC
	strFilter += _T("*.*");
#else
	strFilter += _T("****");
#endif
	strFilter += (TCHAR)'\0';   // last string
	dlgFile.m_ofn.nMaxCustFilter++;

	dlgFile.m_ofn.lpstrFilter = strFilter;
#ifndef _MAC
	dlgFile.m_ofn.lpstrTitle = title;
#else
	dlgFile.m_ofn.lpstrPrompt = title;
#endif
	// --- Begin modifications ---
	// - use a big buffer for the file names 
	// (note that pre-SP2 versions of NT 4.0 will nevertheless
	// truncate the result)
	CString strFileNames;
	dlgFile.m_ofn.lpstrFile = strFileNames.GetBuffer(2048);
	dlgFile.m_ofn.nMaxFile = 2048;

	BOOL bResult = dlgFile.DoModal() == IDOK ? TRUE : FALSE;
	strFileNames.ReleaseBuffer();

	if (!bResult)
		return FALSE; // open cancelled

	// - copy the file names to a string list
	POSITION pos = dlgFile.GetStartPosition();
	while (pos)
	{
		fileNames.AddTail(dlgFile.GetNextPathName(pos));
	}
	return TRUE;
	// --- End modifications ---
}



Comments

  • Whoops!

    Posted by Legacy on 12/06/2002 12:00am

    Originally posted by: Kirk Munro

    Um, I think you may have made a little mistake in your call to ReleaseBuffer.

    Since you don't specify the length, then CString's size is set to the string length. Since this is a string containing nulls, your CString's string length is set to be shorter than the actual length. Doesn't this mean the memory following the first null is free to use, so your calls to GetNextPathName are not guaranteed to work without having access violations?

    Reply
  • AppendFilterSuffix & _AfxAppendFilterSuffix

    Posted by Legacy on 11/20/1998 12:00am

    Originally posted by: Lee Lorenz

    Perhaps it is because I am using VC++ 6.0, but I had to include the static function defined in the MFC source
    DOCMGR.CPP "_AfxAppendFilterSuffix" and replace the references.
    
    

    Otherwise, it allowed me to neatly replace the standard file open dialog for my project. Thanks!

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • The mobile market is white hot. Building a well-crafted product development plan that addresses market research, strategy, design, and development will provide the greatest chance for success. Each phase of an app's lifecycle is critical to the its overall success and feeds into the next step of the process of product development for the app. This white paper examines the five key phases of mobile app creation, one by one, to understand how they work together to help create a successful mobile app.

  • Remember getting your first box of LEGOS as a kid? How fun it was putting the pieces together, collaborating with your friends to create something new? Now, as an IT professional, assembling and maintaining a Lego-like collaboration infrastructure isn't what you signed up for. Piecing together disparate systems of record for email, web meetings and other applications is about as painful as stepping on a pile of Legos. Download the e-book to learn how implementing a collaboration system connects systems of …

Most Popular Programming Stories

More for Developers

RSS Feeds

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