2025-11-28 00:35:46 +09:00

183 lines
4.9 KiB
C

/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
AppRecovery.c
Abstract:
This sample demonstrates how to use the RegisterApplicationRecoveryCallback API.
The RegisterApplicationRecoveryCallback API registers a special callback that Windows Error Reporting will
call prior to terminating the process due to a crash or a hang.
The callback is run in context of the faulting process. The application should use this callback to save
any volatile data or state information to disk or any other non-volatile storage where it can restore the
data from on next restart.
You may also choose to combine application recovery with automatic application restart, as shown in the
AppRestart sample.
--*/
#include <stdio.h>
#include <windows.h>
//
// This is the volatile state information we will be saving to disk during recovery.
//
typedef struct _STATE_BLOCK {
char RandomNumber[16];
} STATE_BLOCK, *PSTATE_BLOCK;
static STATE_BLOCK g_StateBlock;
//
// This is the recovery callback called by WER.
//
static
DWORD WINAPI
MyRecoveryCallback (
PVOID pvParameter
)
{
HRESULT hr = E_FAIL;
BOOL rc;
HANDLE FileHandle;
DWORD BytesWritten;
BOOL RecoveryCancelled;
PSTATE_BLOCK StateBlock = (PSTATE_BLOCK) pvParameter;
//
// Let WER know that we are recovering. In return, WER will let us know if the user has cancelled recovery.
//
hr = ApplicationRecoveryInProgress (&RecoveryCancelled);
if (FAILED (hr)) {
//
// Something bad has happened... bail out of recovery.
//
ApplicationRecoveryFinished (FALSE);
return 0;
}
if (RecoveryCancelled) {
//
// The user has cancelled recovery.
//
return 0;
}
//
// Do the recovery here. Should the following take longer than RECOVERY_DEFAULT_PING_INTERVAL,
// we would need to call ApplicationRecoveryInProgress to let WER know we are still recovering.
// Otherwise, WER will terminate recovery and the process.
//
// We will do the bare minimum to save the state block to disk. We won't create any new threads or
// load any DLLs, as the process state may be too corrupted.
//
FileHandle = CreateFile (L"recovered_data.txt",
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
0,
NULL);
if (INVALID_HANDLE_VALUE != FileHandle) {
//
// Write the whole state block to the file.
//
rc = WriteFile (FileHandle, StateBlock, sizeof (STATE_BLOCK), &BytesWritten, NULL);
if (!rc) {
//
// We couldn't write to the file. Let WER know we are done with recovery, but it had failed.
//
ApplicationRecoveryFinished (FALSE);
return 0;
}
CloseHandle (FileHandle);
//
// For effect's sake, wait a few seconds so the recovery state is visible in the WER UI flow.
// You shouldn't normally do this or take more time for recovery than needed.
//
Sleep (3500);
//
// Let WER know that we successfully completed recovery.
//
ApplicationRecoveryFinished (TRUE);
return 0;
}
else {
//
// We couldn't open the file. Let WER know we are done with recovery, but it had failed.
//
ApplicationRecoveryFinished (FALSE);
return 0;
}
}
int
wmain (
int argc,
const wchar_t* argv[],
const wchar_t* envp[]
)
{
HRESULT hr = E_FAIL;
UNREFERENCED_PARAMETER (argc);
UNREFERENCED_PARAMETER (argv);
UNREFERENCED_PARAMETER (envp);
//
// Register the application for recovery.
//
hr = RegisterApplicationRecoveryCallback (MyRecoveryCallback,
&g_StateBlock,
RECOVERY_DEFAULT_PING_INTERVAL,
0);
if (FAILED (hr)) {
wprintf (L"RegisterApplicationRecoveryCallback failed with 0x%08X\n", hr);
return -1;
}
wprintf (L"Successfully registered this process for recovery.\n");
//
// Save a random number into our state block. This is the block we will be trying to recover later.
//
sprintf_s (g_StateBlock.RandomNumber, sizeof (g_StateBlock.RandomNumber), "%d", rand ());
//
// Crash the application by writing to a NULL pointer.
//
wprintf (L"Crashing the application...\n");
fflush (stdout);
*((int*)NULL) = 0;
return 0;
}