Basically, I got sick of having to navigate from "My Documents" every time I opened an app. One of my projects requires several instances to be open simultaneously and the extra folder-hopping just got to me.
I created a class to replace the existing
CDocManager class in my MFC Doc/View projects. The new class,
CRegDocMgr (based on
CDocManager), stores the most recently used directory (MRUD) in the Registry—in
HKEY_CURRENT_USER, along with any other information normally stored there by the MFC framework. It adds the string
"MRUD" to the
"Settings" key. So the whole path would be
How It Works
The new doc manager replaces the original in the app's
InitInstance function— after specifying standard Registry settings, but before the app registers its document templates. The constructor of
CRegDocMgr pulls the MRUD from the Registry and keeps it in the
CString m_strInitialMRUD. Each time a file is saved or opened (including MRU/drag-and-drop files),
m_strMRUD (which was initialized to
m_strInitialMRUD) is updated. When the destructor for
CRegDocMgr is called just before the program closes, it writes
m_strMRUD to the registry if it differs from
m_strInitialMRUD (avoiding unnecessary registry access).
How To Use It
Only two lines beyond the normal inclusion of a class are needed for basic usage. First, as is usual, add CRegDocMgr.cpp and CRegDocMgr.h to your project. In the main app implementation file (e.g. MyApp.cpp), be sure to
#include "RegDocMgr.h". Then, in the
InitInstance function for the app, add two lines after the registry init code, but before any document templates are registered.
MyApp.cpp : Defines the class behavioyrs for the application.
... standard InitInstance stuff ...
SetRegistryKey(_T("Your Company Name"));
ASSERT(m_pDocManager == NULL);
m_pDocManager = new CRegDocMgr;
... and the rest continues ...
"That's all there is to it." The Open and SaveAs file dialogs will behave exactly the same as before (including
IDR_MAINFRAME filters), except that they will start in the MRUD.
The class also allows you to access the MRUD from elsewhere in your program. This is useful if you have import or export functions in your app that could benefit from MRUD access. You have access to the MRUD initially loaded from the registry (
CString CRegDocMgr::GetInitialMRUD()) and to the current MRUD (
CString CRegDocMgr::GetCurrentMRUD()). You may also set the MRUD by passing it a complete filename (
CString CRegDocMgr::SetMRUD(CString csFileName)). The class will extract the path and set it as the MRUD.
To use these functions in an import/export, add
CRegDocMgr to your app as noted above; then, in the import/export sections of your code, add a few more lines to access the MRUD before showing your import/export file dialog. Afterward, you may also set the MRUD to reflect the import/export directory used, if you so choose.
MyAppDoc* pDoc = GetDocument();
CString csTitle = pDoc->GetTitle();
if (csTitle != "Untitled")
csTitle = csTitle.Left(csTitle.GetLength()-4);
static char szFilter = "ABC Files
(*.abc)|*.abc; *.abc|All Files (*.*)|*.*||";
CFileDialog dlgExport(false, "abc",
(LPCTSTR) csTitle, OFN_HIDEREADONLY |
dlgExport.m_ofn.lpstrTitle = "Export to file";
// CFileDialog dlgImport(true, "abc", NULL,
// OFN_HIDEREADONLY | OFN_PATHMUSTEXIST |
// OFN_FILEMUSTEXIST, szFilter, AfxGetMainWnd());
// set a starting directory if one exists
CRegDocMgr* pDocMgr = (CRegDocMgr*)
// show the file dialog
if (dlgExport.DoModal() == IDOK)
// omit this if import/export should not
// affect document MRUD
//... proceed with the import/export ... etc
The project includes a small text file named "TestFile.xyz". Copy/Move it to wherever you'd like to test the app—open the app, open the file, close the app, re-open the app, and go to File/Open. The dialog should start in the directory from which you last loaded "TestFile.xyz". There is also an "Export" option on the File menu. It will create a meaningless text file, but you should be able to see that it opens to the MRUD and updates the MRUD, should you save the exported file.
Why It Works
CRegDocMgr is 99%
CDocManager. Only two virtual functions, "
DoPromptFileName" and "
OpenDocumentFile", have been modified from the original MFC code.
DoPromptFileName is called whenever the file dialog is opened for Open/SaveAs and
OpenDocumentFile is used to catch MRU files opened from the menu bar and when files are dropped on the app.
You can remove the "All Files (*.*)" filter from your file dialogs if you define
_HIDEALLFILTER. The class then skips that extra section of code which adds *.* to the filters.
The registry accesses have all been made unicode-safe using the
_T macro, to match the rest of the MFC unicode-enabled code.
I included options for
_MAC, but have no way to test them.
AppendFilterSuffix function refused to behave unless I included it in RegDocMgr.cpp too.
Thanks to Jorge Lodos, whose CodeGuru article "Changing the default file open/save dialogs in an MFC doc/view application" pointed me in the right direction.
26 Sep 2002 - Initial Revision