Improve Application Quality with Microsoft Foundation Class (MFC) Restart and Recovery


.NET Developers and users have grown accustomed to applications like Microsoft Word that save temporary copies of a document while it is being created and edited, and offer the user the option of recovering these documents in the event of a crash, hang or system restart caused by patch installation. Windows Vista provides a standard mechanism for providing this support, and a previous article entitled, Build Build Resilient Applications with Windows Recovery and Restart Applications has covered this functionality from a Windows SDK perspective. The good news is that the release of MFC 10 automates most of the interaction with the Windows Application Restart and Recovery (ARR) APIs, and for the most part, makes taking advantage of these features a snap for .NET Developers. It's the simple matter of ticking a few boxes when the AppWizard is first run or adding a line of code in the case of existing MFC applications upgraded to MFC 10.

The simplest part of the Application Restart and Recovery features is the ability for a crashed application to be restarted. For applications that have registered with the ARR functions, Windows will restart an application that crashes if it has successfully run for at least sixty seconds, and for applications that hang, Windows will present a third option of allowing the application to be restarted in addition to the standard two options of closing the program or waiting for it to respond, as shown in Figure 1.

Figure 1. Restart Support for an Application that Hangs

Taking advantage of the basic restart functionality is available for all types of MFC applications, and can be activated by ticking the AppWizard checkbox shown in Figure 2.

Figure 2. Using Application Restart in a MFC Application

Checking this box adds the code below to the CWinApp- derived MFC class. The m_dwRestartManagerSupportFlags member variable is declared as protected in CWinApp, and when it is set in the constructor, code inside CWinApp will register the application for restart. Retro-fitting restart support to an existing MFC application is a simple matter of adding this code into the CWinApp-derived class constructor. The call to the Windows SDK function RegisterApplicationRestart (which instructs Windows to re-start a crashed application) is made from CWinApp::InitInstance, so it is critical that the value of m_dwRestartManagerSupportFlags is set early within an MFC application's startup.

  // support Restart Manager
  m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;

MFC applications that take advantage of Document-View architecture support can take advantage of more extensive restart and recovery support with automated documented saving and recovery available. MDI and SDI MFC Applications will have two further ARR options available when the MFC AppWizard is run, as shown in Figure 3. The first additional option (Reopen previously open documents) simply adds support for prompting the user to re-open documents that have been auto-saved prior to an application crash or hang. The second option (Support application recovery) is dependent on having the first option selected, and leverages MFC to play an active role in safe-guarding the contents of a document by auto-saving temporary copies at regular intervals.

Figure 3. Full Recovery and Restart MFC Options

Selecting the Reopen previously open documents AppWizard option will set the m_dwRestartManagerSupportFlags member variable to AFX_RESTART_MANAGER_SUPPORT_RESTART_ASPECTS, which is a bitwise combination of:
. The final option of Support application recovery will set the flag to AFX_RESTART_MANAGER_SUPPORT_ALL_ASPECTS. All the restart and recovery flags (along with explanations of their meaning) are defined in afxwin.h. MFC introduces a new class called CDataRecoveryHandler to handle the various operations related to automatically saving and recovery documents to supports ARR. CWinApp holds a protected member variable which points to a CDataRecoveryHandler instance, and by default this will be lazily initialized to a new CDataRecoveryHandler object as required. CDataRecoveryHandler, declared in afxdatarecovery.h, is designed to allow sub-classing to customize the behavior of application recovery and restart, with all the public methods declared as virtual, and factored in a way that there is a public method exposed and called by CWinApp for each logical operation. This allows a developer to define a CDataRecoveryHandler-derived class and override the one member function that implements the behavior that requires customization. All calls within the MFC codebase the interact with CDataRecoveryHandler retrieve a pointer via a call to the virtual CWinApp::GetDataRecoveryHandler, allowing a MFC application to override this member function and provide a derived CDataRecoveryHandler containing customizations. A future article will cover a fuller range of the customizations that are possible and how to take advantage of them.

For a lot of MFC applications, the default behavior of CDataRecoveryHandler will be sufficient. Selecting the Reopen previously open documents option when AppWizard runs adds a fairly minimal improvement to the restart experience--the previously--saved documents that are open when the application crashes or hangs are restored when the application restarts are re-opened. CDataRecoveryHandler stores a list of open documents in the registry, and creates a unique registry key in the form of a GUID string for each application instance that crashes to track the particular documents open in that process. The GUID string is also passed to the ARR function RegisterApplicationRestart, so when Windows restarts the crashed application, this GUID string is passed in to the new process by Windows as a command line argument, and the correct documents can be loaded.

The fullest level of application recovery support offered by MFC is the ability to save temporary copies of documents that are currently open and offering the user the option of recovering these documents upon application restart. The frequency of auto-save is controlled by the value returned by the virtual GetAutosaveInterval function of CDataRecoveryHandler. The value returned by this function, which is in number of milliseconds, is currently defaulted to five minutes (300000 milliseconds), but this can be customized in an MFC application with the following code:

  //inside CWinApp-derived class
  //auto-save every minute

Each time an auto-save interval expires, a timer will fire and temporary copies of open documents will be saved. This includes documents that have been created for the first time but have not been explicitly saved before, as long as the SetModifiedFlag has been called at the document-level to let MFC know that the document contains modifications worth saving. The default recovery dialog provided by MFC is shown in Figure 4, and if the end-user elects to recover the saved documents, the document title is annotated to indicate that it has been recovered, as shown in Figure 5.

Figure 4. MFC Application File Recovery

Figure 5. Recovered Documents

The introduction of ARR inside MFC is one of the most elegant examples of framework extensions in the long history of Visual C++. Not only is ARR-support simple and seamless to add to new applications, existing applications can also take advantage of the new features with the addition of a single line of code. The recovery mechanism is simple to customize, and by dividing the functionality into well- defined virtual functions, customization can be achieved without the need to re-implement large sections of framework code.

This article was originally published on February 26th, 2010

Most Popular Programming Stories

More for Developers

RSS Feeds

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