Changing The Default File Open/save Dialogs In An Mfc Doc/view Application

Published on: October 27, 2000
Last Updated: October 27, 2000

Changing The Default File Open/save Dialogs In An Mfc Doc/view Application

Published on: October 27, 2000
Last Updated: October 27, 2000

Before I tell you how to change the default behavior, lets understand how MFC displays the file open and file save dialogs.

When you select the menu File Open, the command message is routed to CWinApp::OnFileOpen, which calls CDocManager::OnFileOpen through its member m_pDocManager (a pointer to a CDocManager object).

This last function calls the CDocManager virtual member DoPromptFileName, and on success calls CWinApp::OpenDocumentFile, with the selected document path. The file open dialog is displayed in the DoPromptFileName virtual function.

When saving, the File Save (or Save As) command message is routed to the CDocument::OnFileSave (or CDocument::OnFileSaveAs). In boths cases the CDocument::DoSave function gets called, either with a file name (we are saving an opened document) or NULL parameter (new document or saving as).

At last, if the file name is NULL, CDocument::DoSave calls CWinApp::DoPromptFileName, that validates the m_pDocManager member and calls CDocManager::DoPromptFileName to display the Save As dialog.

As we see, the CDocManager::DoPromptFileName function (which is virtual!) is responsible for displaying the standard open and save dialogs (a boolean parameter decides which one).

It seems trivial now, that to change default behaviour, you have to override the DoPromptFileName function in the CDocManager class, and somehow tell the application class to use your own modified CDocManager, instead of the original class. Below is the code for a custom CDocManager that displays a dialog descending from CFileDialog:

// CDocManager class declaration

class CDocManagerEx : public CDocManager

// Construction

// Attributes

// Operations

// Overrides
	// helper for standard commdlg dialogs
	virtual BOOL DoPromptFileName(CString& fileName, UINT nIDSTitle,
			DWORD lFlags, BOOL bOpenFileDialog, CDocTemplate* pTemplate);

// Implementation
	virtual ~CDocManagerEx();

// DocManager.cpp : implementation file

#include "stdafx.h"
#include "PreviewFileDlg.h"
#include "DocManager.h" // the header with the class declaration

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;

static void AppendFilterSuffix(CString& filter, OPENFILENAME& ofn,
	CDocTemplate* pTemplate, CString* pstrDefaultExt)
	ASSERT_KINDOF(CDocTemplate, pTemplate);

	CString strFilterExt, strFilterName;
	if (pTemplate->GetDocString(strFilterExt, CDocTemplate::filterExt) &&
	 !strFilterExt.IsEmpty() &&
	 pTemplate->GetDocString(strFilterName, CDocTemplate::filterName) &&
		// a file based document template - add to filter list
#ifndef _MAC
		ASSERT(strFilterExt[0] == '.');
		if (pstrDefaultExt != NULL)
			// set the default extension
#ifndef _MAC
			*pstrDefaultExt = ((LPCTSTR)strFilterExt) + 1;  // skip the '.'
			*pstrDefaultExt = strFilterExt;
			ofn.lpstrDefExt = (LPTSTR)(LPCTSTR)(*pstrDefaultExt);
			ofn.nFilterIndex = ofn.nMaxCustFilter + 1;  // 1 based number

		// add to filter
		filter += strFilterName;
		ASSERT(!filter.IsEmpty());  // must have a file type name
		filter += (TCHAR)'\0';  // next string please
#ifndef _MAC
		filter += (TCHAR)'*';
		filter += strFilterExt;
		filter += (TCHAR)'\0';  // next string please

// CDocManagerEx




BOOL CDocManagerEx::DoPromptFileName(CString& fileName, UINT nIDSTitle, DWORD lFlags, BOOL bOpenFileDialog, CDocTemplate* pTemplate)
	CPreviewFileDlg dlgFile(bOpenFileDialog); // this is the only modified line! 

	CString title;

	dlgFile.m_ofn.Flags |= lFlags;

	CString strFilter;
	CString strDefault;
	if (pTemplate != NULL)
		AppendFilterSuffix(strFilter, dlgFile.m_ofn, pTemplate, &strDefault;);
		// 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;
	strFilter += allFilter;
	strFilter += (TCHAR)'\0';   // next string please
#ifndef _MAC
	strFilter += _T("*.*");
	strFilter += _T("****");
	strFilter += (TCHAR)'\0';   // last string

	dlgFile.m_ofn.lpstrFilter = strFilter;
#ifndef _MAC
	dlgFile.m_ofn.lpstrTitle = title;
	dlgFile.m_ofn.lpstrPrompt = title;
	dlgFile.m_ofn.lpstrFile = fileName.GetBuffer(_MAX_PATH);

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

The code was borrowed completely from original MFC sources, only one line had to be modified: the dialog declaration (of course, this is because the example dialog is a CFileDialog descendant, otherwise you would have to make some more modifications).

For a standard dialog with preview look in the dialogs section.

The AppendFilterSuffix function was called from our DoPromptFileName function and was copied verbatim from the MFC sources.

The only thing that remains to be said about this class is that if you want to use different dialogs for opening and saving, then you can do so using the bOpenFileDialog parameter, which is TRUE when opening and FALSE otherwise.

We still have to make our application class to use the new CDocManagerEx, instead of the default CDocManager.

The CWinApp uses the document manager through its m_pDocManager member, so all we have to do is initializate this member correctly.

A closer look to the MFC code shows that CWinApp creates the object to which this member points only in the CWinApp::AddDocTemplate, a function that normally is called only in our override of the CWinApp::InitInstance function.

The CWinApp::AddDocTemplate function only creates the CDocManager object if the m_pDocManager member is NULL, thus once the m_pDocManager pointer is correctly initialized, the CWinApp::AddDocTemplate function can be safely called.

So, the final step is to initialize the m_pDocManager member in our InitInstance override before we call CWinApp::AddDocTemplate (you can choose not to call CWinApp::AddDocTemplate at all and call directly m_pDocManager->AddDocTemplate).
Here is the code to do that:

BOOL COurApp::InitInstance()
	// Standard initialization
	// If you are not using these features and wish to reduce the size
	//  of your final executable, you should remove from the following
	//  the specific initialization routines you do not need.

#ifdef _AFXDLL
	Enable3dControls();			// Call this when using MFC in a shared DLL
	Enable3dControlsStatic();	// Call this when linking to MFC statically

	// Change the registry key under which our settings are stored.
	// You should modify this string to be something appropriate
	// such as the name of your company or organization.
	SetRegistryKey(_T("Local AppWizard-Generated Applications"));

	LoadStdProfileSettings();  // Load standard INI file options (including MRU)

	// Register the application's document templates.  Document templates
	//  serve as the connection between documents, frame windows and views.

	CMultiDocTemplate* pDocTemplate;
	pDocTemplate = new CMultiDocTemplate(
		RUNTIME_CLASS(CChildFrame), // custom MDI child frame
	ASSERT(m_pDocManager == NULL);
	m_pDocManager = new CDocManagerEx;
	m_pDocManager->AddDocTemplate(pDocTemplate); // or just AddDocTemplate(pDocTemplate);
	// create main MDI Frame window
	CMainFrame* pMainFrame = new CMainFrame;
	if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
		return FALSE;
	m_pMainWnd = pMainFrame;

	// Enable drag/drop open

	// Enable DDE Execute open

	// Parse command line for standard shell commands, DDE, file open
	CCommandLineInfo cmdInfo;

	// Dispatch commands specified on the command line
	if (!ProcessShellCommand(cmdInfo))
		return FALSE;

	// The main window has been initialized, so show and update it.

	return TRUE;

It was all we needed to change the default file open and file save dialogs. In the samples section you can find an enhanced DIBLOOK sample that uses this technique to show standard file dialogs with preview.

Stay on top of the latest technology trends — delivered directly to your inbox, free!

Subscription Form Posts

Don't worry, we don't spam

Written by Bobby

Bobby Lawson is a seasoned technology writer with over a decade of experience in the industry. He has written extensively on topics such as cybersecurity, cloud computing, and data analytics. His articles have been featured in several prominent publications, and he is known for his ability to distill complex technical concepts into easily digestible content.