Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

File Open/SaveAs That Stores the MRUD

0.00/5 (No votes)
26 Sep 2002 1  
Tired of having to navigate from MyDocuments every time you open your MFC app? This class will store the MRUD in the Registry and use it every time you open or save your app.

The Problem

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.

The Solution

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 HKEY_CURRENT_USER/MyCompany/MyApp/Settings/MRUD.

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.
...
#include "RegDocMgr.h"

...

... standard InitInstance stuff ...

SetRegistryKey(_T("Your Company Name"));
LoadStdProfileSettings();

// Load standard INI file options (including MRU)

...


  // USE THE NEW DOCUMENT MANAGER

  ASSERT(m_pDocManager == NULL);
  m_pDocManager = new CRegDocMgr;

... and the rest continues ...

// Register document templates

CSingleDocTemplate* pDocTemplate;

"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.

Extended Functions

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.

// MyAppView.cpp : implementation of the

// MyAppView class

...
#include "RegDocMgr.h"

...

void MyAppView::OnExport() 
{
  // setup for the EXPORT file dialog


  // for a probable title

  MyAppDoc* pDoc = GetDocument();
  CString csTitle = pDoc->GetTitle();
  if (csTitle != "Untitled")
    csTitle = csTitle.Left(csTitle.GetLength()-4);

  // file filters

  static char szFilter[] = "ABC Files
      (*.abc)|*.abc; *.abc|All Files (*.*)|*.*||";

  // create the dialog

  CFileDialog dlgExport(false, "abc",
      (LPCTSTR) csTitle, OFN_HIDEREADONLY | 
               OFN_OVERWRITEPROMPT, szFilter,
                                AfxGetMainWnd());
                                
  // window title

  dlgExport.m_ofn.lpstrTitle = "Export to file";

  //	IMPORT setup

  //	static char szFilter[] = "ABC Files

                          (*.abc)|*.abc; *.abc||";
                          
  //   CFileDialog dlgImport(true, "abc", NULL, 
  //     OFN_HIDEREADONLY | OFN_PATHMUSTEXIST |
  //       OFN_FILEMUSTEXIST, szFilter, AfxGetMainWnd());

  ///////////////////////////////////////////////
  // set a starting directory if one exists
  
  CRegDocMgr* pDocMgr = (CRegDocMgr*)
                   AfxGetApp()->m_pDocManager;
  dlgExport.m_ofn.lpstrInitialDir =
                    pDocMgr->GetCurrentMRUD();
  ///////////////////////////////////////////////

  // show the file dialog
  if (dlgExport.DoModal() == IDOK)
  {
    /////////////////////////////////////////////
    // omit this if import/export should not
    // affect document MRUD
    pDocMgr->SetMRUD(dlgExport.m_ofn.lpstrFile);
    /////////////////////////////////////////////
    
    //... proceed with the import/export ... etc

Testing

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.

Miscellaneous

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.

The AppendFilterSuffix function refused to behave unless I included it in RegDocMgr.cpp too.

Thanks

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.

Revision History

26 Sep 2002 - Initial Revision

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here