.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
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:
AFX_RESTART_MANAGER_AUTOSAVE_AT_RESTART | . The
final option of Support application recovery will set the
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
//inside CWinApp-derived class //auto-save every minute GetDataRecoveryHandler()->SetAutosaveInterval(60*1000);
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
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.