Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

860 lines
24 KiB

/******************************************************************************
Copyright (c) 2000 Microsoft Corporation
Module Name:
api.cpp
Abstract:
This file contains the top level APIs, InitiateRestore and ResumeRestore.
Revision History:
Seong Kook Khang (SKKhang) 06/20/00
created
******************************************************************************/
#include "stdwin.h"
#include "rstrcore.h"
#include "resource.h"
extern CSRClientLoader g_CSRClientLoader;
/////////////////////////////////////////////////////////////////////////////
//
// EnsureTrace
//
/////////////////////////////////////////////////////////////////////////////
//static BOOL s_fTraceEnabled = FALSE;
static DWORD s_dwTraceCount = 0;
void EnsureTrace()
{
if ( s_dwTraceCount++ == 0 )
{
::InitAsyncTrace();
}
}
void ReleaseTrace()
{
if ( --s_dwTraceCount == 0 )
{
::TermAsyncTrace();
}
}
/////////////////////////////////////////////////////////////////////////////
//
// CRestoreContext
//
/////////////////////////////////////////////////////////////////////////////
class CRestoreContext : public IRestoreContext
{
public:
CRestoreContext();
protected:
~CRestoreContext();
// operations - IRestoreContext methods
public:
BOOL IsAnyDriveOfflineOrDisabled( LPWSTR szOffline );
void SetSilent();
void SetUndo();
BOOL Release();
// attributes
public:
int m_nRP;
CRDIArray m_aryDrv;
BOOL m_fSilent;
BOOL m_fUndo;
};
/////////////////////////////////////////////////////////////////////////////
// CRestoreContext - construction / destruction
CRestoreContext::CRestoreContext()
{
m_nRP = -1;
m_fSilent = FALSE;
m_fUndo = FALSE;
}
CRestoreContext::~CRestoreContext()
{
m_aryDrv.DeleteAll();
}
/////////////////////////////////////////////////////////////////////////////
// CRestoreContext - IRestoreContext methods
BOOL
CRestoreContext::IsAnyDriveOfflineOrDisabled( LPWSTR szOffline )
{
TraceFunctEnter("CRestoreContext::IsAnyDriveOffline");
BOOL fRet = FALSE;
szOffline[0] = L'\0';
for ( int i = m_aryDrv.GetUpperBound(); i >= 0; i-- )
{
if ( m_aryDrv[i]->IsOffline() || m_aryDrv[i]->IsExcluded())
{
::lstrcat( szOffline, L" " );
::lstrcat( szOffline, m_aryDrv[i]->GetMount() );
fRet = TRUE;
}
}
TraceFunctLeave();
return( fRet );
}
/////////////////////////////////////////////////////////////////////////////
void
CRestoreContext::SetSilent()
{
TraceFunctEnter("CRestoreContext::SetSilent");
m_fSilent = TRUE;
TraceFunctLeave();
}
/////////////////////////////////////////////////////////////////////////////
void
CRestoreContext::SetUndo()
{
TraceFunctEnter("CRestoreContext::SetUndo");
m_fUndo = TRUE;
TraceFunctLeave();
}
/////////////////////////////////////////////////////////////////////////////
BOOL
CRestoreContext::Release()
{
TraceFunctEnter("CRestoreContext::Release");
delete this;
TraceFunctLeave();
return( TRUE );
}
/////////////////////////////////////////////////////////////////////////////
//
// Helper Functions
//
/////////////////////////////////////////////////////////////////////////////
BOOL
IsAdminUser()
{
TraceFunctEnter("IsAdminUser");
BOOL fRet = FALSE;
LPCWSTR cszErr;
PSID pSidAdmin = NULL;
SID_IDENTIFIER_AUTHORITY cSIA = SECURITY_NT_AUTHORITY;
BOOL fRes;
if ( !::AllocateAndInitializeSid( &cSIA, 2,
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0, &pSidAdmin ) )
{
cszErr = ::GetSysErrStr();
ErrorTrace(0, "::AllocateAndInitializeSid failed - %ls", cszErr);
goto Exit;
}
if ( !::CheckTokenMembership( NULL, pSidAdmin, &fRes ) )
{
cszErr = ::GetSysErrStr();
ErrorTrace(0, "::CheckMembership failed - %ls", cszErr);
goto Exit;
}
DebugTrace(0, "IsAdminUser = %d", fRes);
fRet = fRes;
Exit:
if ( pSidAdmin != NULL )
::FreeSid( pSidAdmin );
TraceFunctLeave();
return( fRet );
}
//
// NOTE: 7/28/00 - skkhang
// Behavior of AdjustTokenPrivilege is a little bit confusing.
// It returns TRUE if given privilege does not exist at all, so you need to
// call GetLastError to see if it's ERROR_SUCCESS or ERROR_NOT_ALL_ASSIGNED
// (meaning the privilege does not exist.)
// Also, if the privilege was already enabled, tpOld will be empty. You
// don't need to restore the privilege in that case.
//
BOOL
CheckPrivilege( LPCWSTR szPriv, BOOL fCheckOnly )
{
TraceFunctEnter("CheckPrivilege");
BOOL fRet = FALSE;
LPCWSTR cszErr;
HANDLE hToken = NULL;
LUID luid;
TOKEN_PRIVILEGES tpNew;
TOKEN_PRIVILEGES tpOld;
DWORD dwRes;
// Prepare Process Token
if ( !::OpenProcessToken( ::GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&hToken ) )
{
cszErr = ::GetSysErrStr();
ErrorTrace(0, "::OpenProcessToken failed - %ls", cszErr);
goto Exit;
}
// Get Luid
if ( !::LookupPrivilegeValue( NULL, szPriv, &luid ) )
{
cszErr = ::GetSysErrStr();
ErrorTrace(0, "::LookupPrivilegeValue failed - %ls", cszErr);
goto Exit;
}
// Try to enable the privilege
tpNew.PrivilegeCount = 1;
tpNew.Privileges[0].Luid = luid;
tpNew.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if ( !::AdjustTokenPrivileges( hToken, FALSE, &tpNew, sizeof(tpNew), &tpOld, &dwRes ) )
{
cszErr = ::GetSysErrStr();
ErrorTrace(0, "::AdjustTokenPrivileges(ENABLE) failed - %ls", cszErr);
goto Exit;
}
if ( ::GetLastError() == ERROR_NOT_ALL_ASSIGNED )
{
// This means process does not even have the privilege so
// AdjustTokenPrivilege simply ignored the request.
ErrorTrace(0, "Privilege '%ls' does not exist, probably user is not an admin.", szPriv);
goto Exit;
}
if ( fCheckOnly )
{
// Restore the privilege if it was not enabled
if ( tpOld.PrivilegeCount > 0 )
{
if ( !::AdjustTokenPrivileges( hToken, FALSE, &tpOld, sizeof(tpOld), NULL, NULL ) )
{
cszErr = ::GetSysErrStr();
ErrorTrace(0, "::AdjustTokenPrivileges(RESTORE) failed - %ls", cszErr);
goto Exit;
}
}
}
fRet = TRUE;
Exit:
if ( hToken != NULL )
::CloseHandle( hToken );
return( fRet );
}
/////////////////////////////////////////////////////////////////////////////
//
// IsSRFrozen
//
// This routine checks if SR is frozen. If any error happens during Drive
// Table creation or System Drive does not exist (broken drive table???),
// return value is FALSE.
//
/////////////////////////////////////////////////////////////////////////////
BOOL APIENTRY
IsSRFrozen()
{
EnsureTrace();
TraceFunctEnter("IsSRFrozen");
BOOL fRet = FALSE;
CRDIArray aryDrv;
int i;
// Load SRClient
g_CSRClientLoader.LoadSrClient();
if ( !::CreateDriveList( 0, aryDrv, TRUE ) )
goto Exit;
for ( i = aryDrv.GetUpperBound(); i >= 0; i-- )
{
if ( aryDrv[i]->IsSystem() )
{
fRet = aryDrv[i]->IsFrozen();
goto Exit;
}
}
Exit:
TraceFunctLeave();
ReleaseTrace();
return( fRet );
}
/////////////////////////////////////////////////////////////////////////////
//
// CheckPrivilegesForRestore
//
// This routine checks if necessary privileges can be set, to verify if
// logon user has necessary credential (Administrators or Backup Operators.)
//
/////////////////////////////////////////////////////////////////////////////
BOOL APIENTRY
CheckPrivilegesForRestore()
{
EnsureTrace();
TraceFunctEnter("CheckPrivilegesForRestore");
BOOL fRet = FALSE;
// Load SRClient
g_CSRClientLoader.LoadSrClient();
// NOTE: 8/17/00 - skkhang
//
// Backup operator does not have below two privileges... SE_SECURITY_NAME
// is enabled by default for SYSTEM so probably can simply removed, but
// SE_TAKE_OWNERSHIP is off for SYSTEM and needs to be turned on. To solve
// the problem, this routine should accept parameter to distinguish
// "Check"(from UI) and "Set"(from ResumeRestore.)
//
if ( !::CheckPrivilege( SE_SECURITY_NAME, FALSE ) )
{
ErrorTrace(0, "Cannot enable SE_SECURITY_NAME privilege...");
goto Exit;
}
if ( !::CheckPrivilege( SE_TAKE_OWNERSHIP_NAME, FALSE ) )
{
ErrorTrace(0, "Cannot enable SE_SHUTDOWN_NAME privilege...");
goto Exit;
}
if ( !::CheckPrivilege( SE_BACKUP_NAME, FALSE ) )
{
ErrorTrace(0, "Cannot enable SE_BACKUP_NAME privilege...");
goto Exit;
}
if ( !::CheckPrivilege( SE_RESTORE_NAME, FALSE ) )
{
ErrorTrace(0, "Cannot enable SE_RESTORE_NAME privilege...");
goto Exit;
}
if ( !::CheckPrivilege( SE_SHUTDOWN_NAME, FALSE ) )
{
ErrorTrace(0, "Cannot enable SE_SHUTDOWN_NAME privilege...");
goto Exit;
}
fRet = TRUE;
Exit:
TraceFunctLeave();
ReleaseTrace();
return( fRet );
}
/////////////////////////////////////////////////////////////////////////////
//
// InvokeDiskCleanup
//
// This routine invokes Disk Cleanup Utility. A specific drive can be
// provided.
//
/////////////////////////////////////////////////////////////////////////////
static LPCWSTR s_cszDCUPath = L"%windir%\\system32\\cleanmgr.exe";
static LPCWSTR s_cszDCUName = L"cleanmgr.exe";
static LPCWSTR s_cszDCUOptDrv = L" /d ";
BOOL APIENTRY
InvokeDiskCleanup( LPCWSTR cszDrive )
{
TraceFunctEnter("InvokeDiskCleanup");
// Load SRClient
g_CSRClientLoader.LoadSrClient();
BOOL fRet = FALSE;
LPCWSTR cszErr;
WCHAR szCmdLine[MAX_PATH];
STARTUPINFO sSI;
PROCESS_INFORMATION sPI;
if ( ::ExpandEnvironmentStrings( s_cszDCUPath, szCmdLine, MAX_PATH ) == 0 )
{
cszErr = ::GetSysErrStr();
ErrorTrace(0, "::GetFullPathName failed - %ls", cszErr);
::lstrcpy( szCmdLine, s_cszDCUName );
}
if ( cszDrive != NULL && cszDrive[0] != L'\0' )
{
::lstrcat( szCmdLine, s_cszDCUOptDrv );
::lstrcat( szCmdLine, cszDrive );
}
DebugTrace(0, "szCmdLine='%s'", szCmdLine);
::ZeroMemory( &sSI, sizeof(sSI ) );
sSI.cb = sizeof(sSI);
if ( !::CreateProcess( NULL, szCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &sSI, &sPI ) )
{
cszErr = ::GetSysErrStr();
ErrorTrace(0, "::CreateProcess failed - %ls", cszErr);
goto Exit;
}
::CloseHandle( sPI.hThread );
::CloseHandle( sPI.hProcess );
// Should I wait for DCU to finish???
fRet = TRUE;
Exit:
TraceFunctLeave();
return( TRUE );
}
#ifdef DBG
/////////////////////////////////////////////////////////////////////////////
//
// TestRestore
//
// This routine performs core restoration functionality, without reboot or
// snapshot restoration.
//
/////////////////////////////////////////////////////////////////////////////
extern "C" __declspec(dllexport)
BOOL APIENTRY
TestRestore( int nRP )
{
EnsureTrace();
TraceFunctEnter("TestRestore");
BOOL fRet = FALSE;
CRDIArray aryDrv;
RESTOREPOINTINFO sRPI;
STATEMGRSTATUS sStatus;
SRstrLogHdrV3 sLogHdr;
CRestoreOperationManager *pROMgr = NULL;
// Load SRClient
g_CSRClientLoader.LoadSrClient();
if ( !::CheckPrivilegesForRestore() )
goto Exit;
// Create Drive Table
if ( !::CreateDriveList( nRP, aryDrv, FALSE ) )
goto Exit;
// Create Restore Point
sRPI.dwEventType = BEGIN_SYSTEM_CHANGE;
sRPI.dwRestorePtType = RESTORE;
sRPI.llSequenceNumber = 0;
::LoadString( g_hInst, IDS_RESTORE_POINT_TEXT, sRPI.szDescription, MAX_DESC );
if ( !::SRSetRestorePoint( &sRPI, &sStatus ) )
{
ErrorTrace(0, "::SRSetRestorePoint failed, nStatus=%d", sStatus.nStatus);
goto Exit;
}
// Create the log file
sLogHdr.dwRPNum = nRP;
sLogHdr.dwRPNew = sStatus.llSequenceNumber;
sLogHdr.dwDrives = aryDrv.GetSize();
if ( !::CreateRestoreLogFile( &sLogHdr, aryDrv ) )
goto Exit;
// also call TS folks to get them to preserve RA keys on restore
_VERIFY(TRUE==RemoteAssistancePrepareSystemRestore(SERVERNAME_CURRENT));
// Create CRestoreOperationManager object
if ( !::CreateRestoreOperationManager( &pROMgr ) )
goto Exit;
// Perform the Restore Operation.
if ( !pROMgr->Run( FALSE ) )
goto Exit;
fRet = TRUE;
Exit:
SAFE_RELEASE(pROMgr);
TraceFunctLeave();
ReleaseTrace();
return( fRet );
}
#endif
#ifdef DBG
#define TIMEOUT_PROGRESSTHREAD 5000
#define TESTPROG_COUNT_CHGLOG 300
#define TESTPROG_TIME_PREPARE 1
#define TESTPROG_COUNT_RESTORE 100
#define TESTPROG_TIME_RESTORE 1
#define TESTPROG_TIME_SNAPSHOT 2000
DWORD WINAPI
TestProgressWindowThreadProc( LPVOID lpParam )
{
CRestoreProgressWindow *pProgress = (CRestoreProgressWindow*)lpParam;
int i, j;
// Stage 1. Prepare (change log enumeration)
pProgress->SetStage( RPS_PREPARE, 0 );
for ( i = 0; i < TESTPROG_COUNT_CHGLOG; i++ )
{
::Sleep( TESTPROG_TIME_PREPARE );
for ( j = 0; j < 10; j++ )
pProgress->Increment();
}
// Stage 2. Restore
pProgress->SetStage( RPS_RESTORE, TESTPROG_COUNT_RESTORE );
for ( i = 0; i < TESTPROG_COUNT_RESTORE; i++ )
{
::Sleep( TESTPROG_TIME_RESTORE );
pProgress->Increment();
}
// Stage 3. Snapshot
pProgress->SetStage( RPS_SNAPSHOT, 0 );
::Sleep( TESTPROG_TIME_SNAPSHOT );
pProgress->Close();
return( 0 );
}
/////////////////////////////////////////////////////////////////////////////
//
// TestProgressWindow
//
// This routine invokes Progress Window and simulates progress change
//
/////////////////////////////////////////////////////////////////////////////
extern "C" __declspec(dllexport)
BOOL APIENTRY
TestProgressWindow()
{
EnsureTrace();
TraceFunctEnter("TestProgressWindow");
BOOL fRet = FALSE;
CRestoreProgressWindow *pProgress = NULL;
HANDLE hThread = NULL;
DWORD dwRet;
// Load SRClient
g_CSRClientLoader.LoadSrClient();
// Create progress window object
if ( !::CreateRestoreProgressWindow( &pProgress ) )
goto Exit;
// Create progress window
if ( !pProgress->Create() )
goto Exit;
// Create secondary thread for main restore operation
hThread = ::CreateThread( NULL, 0, TestProgressWindowThreadProc, pProgress, 0, NULL );
if ( hThread == NULL )
{
LPCWSTR cszErr = ::GetSysErrStr();
ErrorTrace(0, "::CreateThread failed - %ls", cszErr);
goto Exit;
}
// Message loop, wait until restore thread closes progress window
if ( !pProgress->Run() )
goto Exit;
// Double check if thread has been terminated
dwRet = ::WaitForSingleObject( hThread, TIMEOUT_PROGRESSTHREAD );
if ( dwRet == WAIT_FAILED )
{
LPCWSTR cszErr = ::GetSysErrStr();
ErrorTrace(0, "::WaitForSingleObject failed - %ls", cszErr);
goto Exit;
}
else if ( dwRet == WAIT_TIMEOUT )
{
ErrorTrace(0, "Timeout while waiting for the restore thread finishes...");
goto Exit;
}
pProgress->Close();
fRet = TRUE;
Exit:
if ( hThread != NULL )
::CloseHandle( hThread );
SAFE_RELEASE(pProgress);
TraceFunctLeave();
ReleaseTrace();
return( fRet );
}
#endif
/////////////////////////////////////////////////////////////////////////////
//
// PrepareRestore
//
// This routine creates a IRestoreContext for use by InitiateRestore.
// IRestoreContext contains chosen restore point ID, drive list, etc.
//
/////////////////////////////////////////////////////////////////////////////
BOOL APIENTRY
PrepareRestore( int nRP, IRestoreContext **ppCtx )
{
EnsureTrace();
TraceFunctEnter("PrepareRestore");
BOOL fRet = FALSE;
CRestoreContext *pRC = NULL;
// Load SRClient
g_CSRClientLoader.LoadSrClient();
if ( ppCtx == NULL )
{
ErrorTrace(0, "Invalid parameter, ppCtx is NULL.");
goto Exit;
}
*ppCtx = NULL;
if ( !::IsAdminUser() )
{
ErrorTrace(0, "Not an admin user");
goto Exit;
}
pRC = new CRestoreContext;
if ( pRC == NULL )
{
ErrorTrace(0, "Insufficient memory...");
goto Exit;
}
pRC->m_nRP = nRP;
if ( !::CreateDriveList( nRP, pRC->m_aryDrv, FALSE ) )
{
ErrorTrace(0, "Creating drive list failed");
goto Exit;
}
*ppCtx = pRC;
fRet = TRUE;
Exit:
if ( !fRet )
SAFE_RELEASE(pRC);
TraceFunctLeave();
ReleaseTrace();
return( fRet );
}
/////////////////////////////////////////////////////////////////////////////
//
// InitiateRestore
//
// This routine creates a temporary persistent storage with informations
// like restore point ID. The storage will be used by ResumeRestore later.
//
/////////////////////////////////////////////////////////////////////////////
static LPCWSTR s_cszRunOnceValueName = L"*Restore";
static LPCWSTR s_cszRestoreUIPath = L"%SystemRoot%\\system32\\restore\\rstrui.exe";
static LPCWSTR s_cszRunOnceOptInterrupted = L" -i";
BOOL APIENTRY
InitiateRestore( IRestoreContext *pCtx, DWORD *pdwNewRP )
{
EnsureTrace();
TraceFunctEnter("InitiateRestore");
// Load SRClient
g_CSRClientLoader.LoadSrClient();
BOOL fRet = FALSE;
HCURSOR hCursor = NULL;
RESTOREPOINTINFO sRPI;
STATEMGRSTATUS sStatus;
SRstrLogHdrV3 sLogHdr;
CRestoreContext *pRC;
DWORD dwVal;
WCHAR szUIPath[MAX_PATH];
BOOL fCreatedRp = FALSE;
if ( !::IsAdminUser() )
goto Exit;
// Set RunOnce key for interrupted case...
// Doing this here before anything else so result screen would appear.
::ExpandEnvironmentStrings( s_cszRestoreUIPath, szUIPath, MAX_PATH );
::lstrcat( szUIPath, s_cszRunOnceOptInterrupted );
if ( !::SRSetRegStr( HKEY_LOCAL_MACHINE, REGSTR_PATH_RUNONCE, s_cszRunOnceValueName, szUIPath ) )
goto Exit;
// similarly, set RestoreStatus key in SystemRestore
// so that test tools can know status of silent restores
// set this to indicate interrrupted status
// if restore succeeds or reverts, this value will be updated
if ( !::SRSetRegDword( HKEY_LOCAL_MACHINE, s_cszSRRegKey, s_cszRestoreStatus, 2 ) )
goto Exit;
// Create Restore Point
hCursor = ::SetCursor( ::LoadCursor( NULL, IDC_WAIT ) );
// make this a nested restore point so that
// no other app can create a restore point between here and a reboot
sRPI.dwEventType = BEGIN_NESTED_SYSTEM_CHANGE;
if (0 != GetSystemMetrics(SM_CLEANBOOT)) // safe mode
{
sRPI.dwRestorePtType = CANCELLED_OPERATION;
}
else // normal mode
{
sRPI.dwRestorePtType = RESTORE;
}
sRPI.llSequenceNumber = 0;
::LoadString( g_hInst, IDS_RESTORE_POINT_TEXT, sRPI.szDescription, MAX_DESC );
if ( !::SRSetRestorePoint( &sRPI, &sStatus ) )
{
ErrorTrace(0, "::SRSetRestorePoint failed, nStatus=%d", sStatus.nStatus);
goto Exit;
}
if ( pdwNewRP != NULL )
*pdwNewRP = sStatus.llSequenceNumber;
fCreatedRp = TRUE;
// Create the log file
pRC = (CRestoreContext*)pCtx;
sLogHdr.dwFlags = pRC->m_fSilent ? RLHF_SILENT : 0;
sLogHdr.dwFlags |= pRC->m_fUndo ? RLHF_UNDO : 0;
sLogHdr.dwRPNum = pRC->m_nRP;
sLogHdr.dwRPNew = sStatus.llSequenceNumber;
sLogHdr.dwDrives = pRC->m_aryDrv.GetSize();
if ( !::CreateRestoreLogFile( &sLogHdr, pRC->m_aryDrv ) )
goto Exit;
// also call TS folks to get them to preserve RA keys on restore
_VERIFY(TRUE==RemoteAssistancePrepareSystemRestore(SERVERNAME_CURRENT));
// Set RestoreInProgress registry key so winlogon would invoke us
if ( !::SRSetRegDword( HKEY_LOCAL_MACHINE, s_cszSRRegKey, s_cszRestoreInProgress, 1 ) )
goto Exit;
fRet = TRUE;
Exit:
if (fRet == FALSE)
{
// if something failed and we had set a nested restore point,
// end the nesting now
if (fCreatedRp == TRUE)
{
sRPI.dwRestorePtType = RESTORE;
sRPI.dwEventType = END_NESTED_SYSTEM_CHANGE;
SRSetRestorePoint( &sRPI, &sStatus );
}
// delete the runonce key
SHDeleteValue(HKEY_LOCAL_MACHINE, REGSTR_PATH_RUNONCE, s_cszRunOnceValueName);
}
if ( hCursor != NULL )
::SetCursor( hCursor );
TraceFunctLeave();
ReleaseTrace();
return( fRet );
}
/////////////////////////////////////////////////////////////////////////////
//
// ResumeRestore
//
// This routine is the main routine to run the restore operation.
//
/////////////////////////////////////////////////////////////////////////////
BOOL APIENTRY
ResumeRestore()
{
EnsureTrace();
TraceFunctEnter("ResumeRestore");
// Load SRClient
g_CSRClientLoader.LoadSrClient();
BOOL fRet = FALSE;
LPCWSTR cszErr;
DWORD dwInRestore, dwType, dwSize, dwRes;
CRestoreOperationManager *pROMgr = NULL;
if ( !::CheckPrivilegesForRestore() )
goto Exit;
// 1. Even though winlogon would check the registry before calling this
// API, double check the registry key and then delete it.
dwType = REG_DWORD;
dwSize = sizeof(DWORD);
dwRes = ::SHGetValue( HKEY_LOCAL_MACHINE, s_cszSRRegKey, s_cszRestoreInProgress, &dwType, &dwInRestore, &dwSize );
if ( dwRes != ERROR_SUCCESS )
{
cszErr = ::GetSysErrStr();
DebugTrace(0, "::SHGetValue failed - %ls", cszErr);
goto Exit;
}
dwRes = ::SHDeleteValue( HKEY_LOCAL_MACHINE, s_cszSRRegKey, s_cszRestoreInProgress );
if ( dwRes != ERROR_SUCCESS )
{
cszErr = ::GetSysErrStr();
ErrorTrace(0, "::SHDeleteValue failed - %ls", cszErr);
goto Exit;
}
if ( dwInRestore == 0 )
{
DebugTrace(0, "RestoreInProgress is 0");
goto Exit;
}
// 1. Create CRestoreOperationManager object.
if ( !::CreateRestoreOperationManager( &pROMgr ) )
goto Exit;
// 2. Perform the Restore Operation.
if ( !pROMgr->Run( TRUE ) )
goto Exit;
fRet = TRUE;
Exit:
SAFE_RELEASE(pROMgr);
TraceFunctLeave();
ReleaseTrace();
return( fRet );
}
// end of file