Creating an Open/SaveAs That Stores the MRUD

Environment: MFC4.2; sample written in MSVC++5.0 on Win98

The Problem

Basically, I got sick of having to navigate from "MyDocuments" 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 (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 behaviors 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());
  dlgExport.m_ofn.lpstrTitle = "Export to file"; // window title

  // IMPORT setup
  // static char szFilter[] = "ABC Files (*.abc)|*.abc; *.abc||";
  // CFileDialog dlgImport(true, "abc", NULL, // no preset filename
  //      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 article "Changing the default file open/save dialogs in an MFC doc/view application" pointed me in the right direction.

Downloads

Download demo project - 21 Kb
Download demo EXE - 8 Kb
Download source - 6 Kb



Comments

  • Thanks, I like this.

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

    Originally posted by: Bill Dickinson

    Thanks, I like this, but have been too lazy to do it.

    Reply
  • Good Work!

    Posted by Legacy on 08/29/2002 12:00am

    Originally posted by: DaFu Chen

    Good Work, This feature simplifies the operation

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

Top White Papers and Webcasts

  • You probably have several goals for your patient portal of choice. Is "community" one of them? With a bevy of vendors offering portal solutions, it can be challenging for a hospital to know where to start. Fortunately, YourCareCommunity helps ease the decision-making process. Read this white paper to learn more. "3 Ways Clinicians can Leverage a Patient Portal to Craft a Healthcare Community" is a published document owned by www.medhost.com

  • Live Event Date: May 6, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT While you likely have very good reasons for remaining on WinXP after end of support -- an estimated 20-30% of worldwide devices still are -- the bottom line is your security risk is now significant. In the absence of security patches, attackers will certainly turn their attention to this new opportunity. Join Lumension Vice President Paul Zimski in this one-hour webcast to discuss risk and, more importantly, 5 pragmatic risk mitigation techniques …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds