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

Introduction

.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:
AFX_RESTART_MANAGER_SUPPORT_RESTART |
AFX_RESTART_MANAGER_AUTOSAVE_AT_RESTART |
AFX_RESTART_MANAGER_REOPEN_PREVIOUS_FILES |
AFX_RESTART_MANAGER_RESTORE_AUTOSAVED_FILES
. 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
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
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.

More by Author

Must Read