/*++ Copyright (c) 2000 Microsoft Corporation All rights reserved Module Name: checkpoint.cxx Abstract: This file implements a class (or for 'C' handle based) calls to set and restore system breakpoints. Author: Mark Lawrence (mlawrenc). Environment: User Mode -Win32 Revision History: --*/ #include "spllibp.hxx" #pragma hdrstop #include "checkpoint.hxx" #include "safewrap.hxx" TSystemRestorePoint:: TSystemRestorePoint( VOID ) : m_hLibrary(NULL), m_pfnSetRestorePoint(NULL), m_bSystemRestoreSet(FALSE), m_hr(E_FAIL) { memset(&m_RestorePointInfo, 0, sizeof(m_RestorePointInfo)); m_hr = Initialize(); } TSystemRestorePoint:: ~TSystemRestorePoint( VOID ) { if (m_hLibrary) { FreeLibrary(m_hLibrary); } } HRESULT TSystemRestorePoint:: IsValid( VOID ) const { return m_hr; } /*++ Routine Name: StartSystemRestorePoint Routine Description: This routine starts a system restore point in the AddPrinterDriver code. Arguments: pszServer - The server name on which we are setting the restore point. pszDriverName - The driver name of which we are trying to install. hInst - The hInstance of the resource library. ResId - The resource id to use for the message string. Return Value: An HRESULT. --*/ HRESULT TSystemRestorePoint:: StartSystemRestorePoint( IN PCWSTR pszServer, IN PCWSTR pszDriverName, IN HINSTANCE hInst, IN UINT ResId ) { HRESULT hRetval = E_FAIL; STATEMGRSTATUS SMgrStatus; WCHAR szDriverName[MAX_DESC]; WCHAR szMessage[MAX_DESC]; hRetval = pszDriverName && hInst ? S_OK : HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); // // We only set system restore points on the local machine for now. // if (SUCCEEDED(hRetval) && !pszServer) { if (SUCCEEDED(hRetval)) { if (LoadString(hInst, ResId, szMessage, COUNTOF(szMessage))) { // // We have to check here if the length of the message // is at least two (because of the string terminator and // at least one format specifier) // if (lstrlen(szMessage) > 2) { hRetval = S_OK; } else { hRetval = HResultFromWin32(ERROR_RESOURCE_DATA_NOT_FOUND); } } else { hRetval = GetLastErrorAsHResult(); } } if (SUCCEEDED(hRetval)) { PWSTR pszArray[1]; // // Now we calculate how much of the driver name we can fit into the // message (which is only 64 characters). This is // MAX_DESC - (strlen(szMessage) - 2) - 1. // StringCchCopyW(szDriverName, MAX_DESC - wcslen(szMessage) + 2, pszDriverName); pszArray[0] = szDriverName; hRetval = FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, szMessage, 0, 0, m_RestorePointInfo.szDescription, COUNTOF(m_RestorePointInfo.szDescription), (va_list *)pszArray) ? S_OK : GetLastErrorAsHResult(); } // // Now that we have the system restore point, set it. // if (SUCCEEDED(hRetval)) { m_RestorePointInfo.dwEventType = BEGIN_NESTED_SYSTEM_CHANGE; m_RestorePointInfo.dwRestorePtType = DEVICE_DRIVER_INSTALL; m_RestorePointInfo.llSequenceNumber = 0; hRetval = m_pfnSetRestorePoint(&m_RestorePointInfo, &SMgrStatus) ? S_OK : HRESULT_FROM_WIN32(SMgrStatus.nStatus); } if (SUCCEEDED(hRetval)) { m_bSystemRestoreSet = TRUE; } else { // // Failing to set the system restore point should not stop us adding // the printer driver. // hRetval = S_OK; } } return hRetval; } /*++ Routine Name: EndSystemRestorePoint Routine Description: This function either completes the system restore point or it cancels it if whoever was doing the installation tells us to. Arguments: bCancel - If TRUE, the restore point should be cancelled. Return Value: An HRESULT. --*/ HRESULT TSystemRestorePoint:: EndSystemRestorePoint( IN BOOL bCancel ) { HRESULT hRetval = S_OK; STATEMGRSTATUS SMgrStatus; if (m_bSystemRestoreSet) { m_RestorePointInfo.dwEventType = END_NESTED_SYSTEM_CHANGE; m_RestorePointInfo.dwRestorePtType = bCancel ? CANCELLED_OPERATION : DEVICE_DRIVER_INSTALL; hRetval = m_pfnSetRestorePoint(&m_RestorePointInfo, &SMgrStatus) ? S_OK : HRESULT_FROM_WIN32(SMgrStatus.nStatus); } return hRetval; } /****************************************************************************** Private Methods ******************************************************************************/ /*++ Routine Name: Initialize Routine Description: Load the system restore library and get the address of the system restore function. Arguments: None Return Value: An HRESULT --*/ HRESULT TSystemRestorePoint:: Initialize( VOID ) { HRESULT hRetval = E_FAIL; m_hLibrary = LoadLibraryFromSystem32(L"srclient.dll"); hRetval = m_hLibrary ? S_OK : GetLastErrorAsHResult(); if (SUCCEEDED(hRetval)) { m_pfnSetRestorePoint = reinterpret_cast(GetProcAddress(m_hLibrary, "SRSetRestorePointW")); hRetval = m_pfnSetRestorePoint ? S_OK : GetLastErrorAsHResult(); } return hRetval; } /*++ Routine Name: StartSystemRestorePoint Routine Description: This form of the function is for C callers, it is handle based. Arguments: pszServer - The server on which we are doing the restore point. pszDriverName - The driver name we are installing. hInst - The instance in which the resource which we want to load is. ResId - The Resource Id. Return Value: An HRESULT --*/ extern "C" HANDLE StartSystemRestorePoint( IN PCWSTR pszServer, IN PCWSTR pszDriverName, IN HINSTANCE hInst, IN UINT ResId ) { HRESULT hRetval = E_FAIL; HANDLE hRestorePoint = NULL; #ifdef _WIN64 return NULL; #endif TSystemRestorePoint *pSystemRestorePoint = new TSystemRestorePoint; hRetval = pSystemRestorePoint ? pSystemRestorePoint->IsValid() : E_OUTOFMEMORY; if (SUCCEEDED(hRetval)) { hRetval = pSystemRestorePoint->StartSystemRestorePoint(pszServer, pszDriverName, hInst, ResId); } if (SUCCEEDED(hRetval)) { hRestorePoint = pSystemRestorePoint; pSystemRestorePoint = NULL; } else { SetLastError(HRESULT_CODE(hRetval)); } delete pSystemRestorePoint; return hRestorePoint; } /*++ Routine Name: EndSystemRestorePoint Routine Description: This form of the function is for C callers, it is handle based. Note: This also closes the handle. Arguments: hRestorePoint - The system restore point. bCancel - If TRUE, the system restore point should be cancelled and not completed. Return Value: An HRESULT --*/ extern "C" BOOL EndSystemRestorePoint( IN HANDLE hRestorePoint, IN BOOL bCancel ) { HRESULT hRetval = E_FAIL; TSystemRestorePoint *pRestorePoint = reinterpret_cast(hRestorePoint); #ifdef _WIN64 return SUCCEEDED( E_FAIL ); #endif hRetval = pRestorePoint ? S_OK : HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); if (SUCCEEDED(hRetval)) { hRetval = pRestorePoint->EndSystemRestorePoint(bCancel); delete pRestorePoint; } if (FAILED(hRetval)) { SetLastError(HRESULT_CODE(hRetval)); } return SUCCEEDED(hRetval); }