Microsoft & .NETVisual C#Build Build Resilient Applications with Windows Recovery and Restart Applications

Build Build Resilient Applications with Windows Recovery and Restart Applications

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

There are arguably few greater frustrations for end users than programs that crash or hang, especially if the problem causes them to lose work. Microsoft has invested considerable engineering efforts in proprietary applications such as Microsoft Office to ensure that they save data to temporary files periodically, so users’ data can be recovered if the application hangs, crashes, or is forcefully closed by an operating system reboot.

Beginning with Windows Vista, developers can enhance the recovery and restart functionality of their own applications by registering their applications with the Application Recovery and Restart (ARR) APIs. These APIs receive operating system notification prior to an unexpected application exit, allowing them to save a copy of the user’s input, which can then be retrieved the next time the application runs. An application can also register with the operating system for automatic restart using ARR functionality, which results in the application being restarted if it crashes after successfully running for 60 seconds. (This minimum application lifetime prevents applications that crash constantly on start-up from entering an infinite restart cycle.) While you can use the recovery and restart support in ARR independently, it’s generally advisable to take advantage of both feature sets simultaneously.

Registering for application restart is a simple matter of calling the Windows API function RegisterApplicationRestart. The function takes two parameters—the command line to pass to the application if a restart is required, and a flag value that determines whether the application is restarted when it crashes, hangs, crashes during a patch process, or when the operating system restarts as a result of an update. Passing zero (0) as the flag value means that the application will restart in all scenarios (provided it has been running successfully for 60 seconds).

The most convenient place to call RegisterApplicationRestart is usually in the entry point of the application, because that provides the best assurance that the API call will not be missed, and it’s an easy way to ensure that the original command line will be readily available if required. Applications can unregister for restart by calling UnregisterApplicationRestart.

When an exception occurs, users will see a standard Windows error message box (see Figure 1).


Figure 1. Initial Crash Message:
When an application crashes or hangs, users see a standard error dialog.

For restart-registered applications, users will also see a second message box (see Figure 2), and the application will then restart.


Figure 2. Application Restart Message:
When an application has been registered for restart, users will see this second message, informing them that the application is restarting.

Recovering Data

Application Recovery allows an application to register a callback function with Windows that will be called if the application becomes unresponsive (which is defined as failing to respond to Windows messages within five seconds) or experiences an unhandled error. The callback function provides the application with a chance to recover and store user-entered data before the process exits. It is generally a good idea to periodically backup the data a user is entered, because that increases the likelihood that data will be in a good state for recovery in the event of an application error. To register for application recovery, make a simple call to RegisterApplicationRecoveryCallback:

//inside application start-up code
RegisterApplicationRecoveryCallback(SaveData, 
   NULL, 2000, 0);
//elsewhere is application
DWORD WINAPI SaveData(PVOID pContext)
{
   //see sample code download for details
   CreateRestoreLocation(); 
   //check whether the user has cancelled 
   // the restore process
   BOOL canceled = FALSE;
   ApplicationRecoveryInProgress(&canceled);
   if (canceled)
      return 0;
   //save user data
   HANDLE hFile = CreateFile(
      GetRestoreFileName().c_str(), 
      GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 
      FILE_ATTRIBUTE_NORMAL, NULL);
   wstring fileData(
      L"Data that was recovered before crash");
   DWORD bytesWritten;
   WriteFile(hFile, fileData.data(), 
      fileData.length() * 
      sizeof(wchar_t), &bytesWritten, NULL);
   CloseHandle(hFile);
   //tell the operating system that recovery 
   // is complete
   ApplicationRecoveryFinished(TRUE);
 
   return 0;
}

In the preceding code, the call to RegisterApplicationRecoveryCallback specifies the recovery function and lets you provide any parameters that should be passed to the recovery function. The third parameter (2000) is the ping interval of the recovery procedure. During recovery, the recovery procedure must call ApplicationRecoveryInProgress at least once every ping interval to let the operating system know that recovery is still underway.

As shown in the SaveData function above, the ApplicationRecoveryInProgress serves double duty; it’s also used to determine whether the user has cancelled application recovery. When Windows calls the recovery function, it displays a dialog like the one shown in Figure 3.


Figure 3. Recovery Dialog:
Users see this dialog after a crash when an application has been registered for recovery.

Note that users can choose to cancel the recovery process if they decide it is taking too long or that the data they have entered is not worth recovering. After data recovery is complete, the recovery function should call ApplicationRecoveryFinished to inform Windows of the success of the data recovery process.

If an application uses both restart and recovery, the API determines whether an application should recover data that was saved during a recovery operation using the command line parameters passed to RegisterApplicationRestart. By specifying a restart command-line switch, start-up code can easily determine whether an attempt should be made to read recovery data from a file. In the code below, the restart command line switch is /r. When this command-line switch is detected, the application makes an attempt to read recovered data is made.

//check to see if we are recovering from a crash
 const wstring restartSwitch(L"r");
 const wstring commandLine(lpCmdLine);
 if (commandLine.find(restartSwitch) != wstring::npos){
  //recover data saved before crash
  HANDLE hFile = CreateFile(GetRestoreFileName().c_str(),
   GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
  if (hFile){
   const int buffSize = 256;
   wchar_t buff[buffSize];
   ZeroMemory(buff, buffSize * sizeof(wchar_t));
   DWORD bytesRead;
   if (ReadFile(hFile, buff, buffSize * sizeof(wchar_t), 
    &bytesRead, NULL)){
    wstring userMsg(L"Data recovered after recovery:n");
    userMsg.append(buff);
    //display recovered data to user
    MessageBox(NULL, userMsg.c_str(), L"Recovery", MB_OK);
   }
   CloseHandle(hFile);
   DeleteFile(GetRestoreFileName().c_str());
  }
 }
 //register for restart
 RegisterApplicationRestart(restartSwitch.c_str(), 0);

The sample application uses one global file name for storing recovery information, but using a per-process file name can be achieved by using a unique file name for each instance of the application, passing this as a re-start command line to RegisterApplicationRestart, and retrieving and reading this file when the application is restarted by Windows. If application recovery is used without application restart, the recovery file needs to be either stored at a well-known location that is checked each time the application starts, or the recovery function can store the name of the recovery file in the registry and this registry key can be checked on each application start.

Application Restart and Recovery gives application developers a consistent and simple way to deal with reliability and data recovery in the applications they create. Application crashes invariably create a bad impression, but by gracefully recovering the data that the user has entered and restarting the application with the saved data file open and the application ready for use again, you can save your end users from much of the pain and angst associated with application crashes.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories