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.
667 lines
20 KiB
667 lines
20 KiB
f/*++
|
|
|
|
Copyright (c) 2002 Microsoft Corporation
|
|
|
|
Abstract:
|
|
|
|
@doc
|
|
@module comregdbwriter.cxx | Implementation of the COM+ RegDB Writer
|
|
@end
|
|
|
|
Author:
|
|
|
|
Ran Kalach [rankala] 05/17/2002
|
|
|
|
|
|
Revision History:
|
|
|
|
Name Date Comments
|
|
rankala 05/17/2002 created
|
|
|
|
--*/
|
|
#include "stdafx.h"
|
|
#include "vs_idl.hxx"
|
|
#include "vs_hash.hxx"
|
|
|
|
#include <vswriter.h>
|
|
#include <Sddl.h>
|
|
|
|
#include "vs_seh.hxx"
|
|
#include "vs_trace.hxx"
|
|
#include "vs_debug.hxx"
|
|
#include "vs_reg.hxx"
|
|
#include "comregdbwriter.hxx"
|
|
#include "allerror.h"
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Standard foo for file name aliasing. This code block must be after
|
|
// all includes of VSS header files.
|
|
//
|
|
#ifdef VSS_FILE_ALIAS
|
|
#undef VSS_FILE_ALIAS
|
|
#endif
|
|
#define VSS_FILE_ALIAS "WRTCDBRC"
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
static GUID s_writerId =
|
|
{
|
|
0x542da469, 0xd3e1, 0x473c, 0x9f, 0x4f, 0x78, 0x47, 0xf0, 0x1f, 0xc6, 0x4f
|
|
};
|
|
|
|
// The display name of the Event Log writer.
|
|
static LPCWSTR s_wszWriterName = L"COM+ REGDB Writer";
|
|
|
|
// The file group component name for the Event Log
|
|
static LPCWSTR s_wszComponentName = L"COM+ REGDB";
|
|
|
|
// The original location of the RegDB files
|
|
static CBsString s_cwsSystemComRegDBDir = L"%SystemRoot%\\Registration";
|
|
|
|
// The backup/restore location of the RegDB files
|
|
static CBsString s_cwsComRegDBTargetDir = ROOT_BACKUP_DIR BOOTABLE_STATE_SUBDIR L"\\ComRegistrationDatabase";
|
|
|
|
// The backup/restore file name of the RegDB database
|
|
static CBsString s_cwsBackupFilename = L"\\ComRegDb.bak";
|
|
|
|
// The COM+ System Applicationservice name
|
|
static LPCWSTR s_wszCOMSysAppServiceName = L"COMSysApp";
|
|
|
|
// Class wide member variables
|
|
CComRegDBWriter *CComRegDBWriter::sm_pWriter = NULL;
|
|
|
|
// RegDB function declarations
|
|
typedef HRESULT (*PF_REG_DB_API)(BSTR);
|
|
|
|
//
|
|
// Methods
|
|
//
|
|
|
|
HRESULT STDMETHODCALLTYPE CComRegDBWriter::Initialize()
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_WRITER, L"CComRegDBWriter::Initialize");
|
|
|
|
try
|
|
{
|
|
ft.hr = CVssWriter::Initialize
|
|
(
|
|
s_writerId,
|
|
s_wszWriterName,
|
|
VSS_UT_BOOTABLESYSTEMSTATE,
|
|
VSS_ST_OTHER,
|
|
VSS_APP_SYSTEM,
|
|
60000
|
|
);
|
|
|
|
if (ft.HrFailed())
|
|
ft.TranslateGenericError
|
|
(
|
|
VSSDBG_WRITER,
|
|
ft.hr,
|
|
L"CVssWriter::Initialize(" WSTR_GUID_FMT L", %s)",
|
|
GUID_PRINTF_ARG(s_writerId),
|
|
s_wszWriterName
|
|
);
|
|
|
|
ft.hr = Subscribe();
|
|
if (ft.HrFailed())
|
|
ft.TranslateGenericError
|
|
(
|
|
VSSDBG_WRITER,
|
|
ft.hr,
|
|
L"CVssWriter::Subscribe for" WSTR_GUID_FMT L" %s)",
|
|
GUID_PRINTF_ARG(s_writerId),
|
|
s_wszWriterName
|
|
);
|
|
}
|
|
VSS_STANDARD_CATCH(ft)
|
|
|
|
return ft.hr;
|
|
}
|
|
|
|
HRESULT STDMETHODCALLTYPE CComRegDBWriter::Uninitialize()
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_WRITER, L"CComRegDBWriter::Uninitialize");
|
|
|
|
return Unsubscribe();
|
|
}
|
|
|
|
|
|
// handle request for WRITER_METADATA
|
|
// implements CVssWriter::OnIdentify
|
|
bool STDMETHODCALLTYPE CComRegDBWriter::OnIdentify(IVssCreateWriterMetadata *pMetadata)
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_WRITER, L"CComRegDBWriter::OnIdentify");
|
|
|
|
try
|
|
{
|
|
|
|
// Converted to CUSTOM restore method (see bug# 688278)
|
|
#if 0
|
|
|
|
//
|
|
// Set the restore method for the writer
|
|
//
|
|
ft.hr = pMetadata->SetRestoreMethod
|
|
(
|
|
VSS_RME_RESTORE_IF_CAN_REPLACE,
|
|
NULL,
|
|
NULL,
|
|
VSS_WRE_ALWAYS, // writer always involved
|
|
false
|
|
);
|
|
ft.CheckForErrorInternal(VSSDBG_WRITER, L"IVssCreateWriterMetadata::SetRestoreMethod");
|
|
|
|
#endif
|
|
|
|
//
|
|
// Set the restore method for the writer
|
|
//
|
|
ft.hr = pMetadata->SetRestoreMethod
|
|
(
|
|
VSS_RME_CUSTOM,
|
|
NULL,
|
|
NULL,
|
|
VSS_WRE_NEVER, // writer never involved in restore
|
|
false
|
|
);
|
|
ft.CheckForErrorInternal(VSSDBG_WRITER, L"IVssCreateWriterMetadata::SetRestoreMethod");
|
|
|
|
//
|
|
// Exclude original location of COM+ RegDB files
|
|
//
|
|
ft.hr = pMetadata->AddExcludeFiles
|
|
(
|
|
s_cwsSystemComRegDBDir,
|
|
L"*",
|
|
true
|
|
);
|
|
ft.CheckForErrorInternal(VSSDBG_WRITER, L"IVssCreateWriterMetadata::AddExcludeFiles");
|
|
|
|
//
|
|
// Add the one file-group component
|
|
//
|
|
ft.hr = pMetadata->AddComponent
|
|
(
|
|
VSS_CT_FILEGROUP,
|
|
NULL,
|
|
s_wszComponentName,
|
|
s_wszComponentName,
|
|
NULL, // icon
|
|
0,
|
|
false,
|
|
false,
|
|
true
|
|
);
|
|
ft.CheckForErrorInternal(VSSDBG_WRITER, L"IVssCreateWriterMetadata::AddComponent");
|
|
|
|
//
|
|
// Add files to the file group
|
|
//
|
|
ft.hr = pMetadata->AddFilesToFileGroup
|
|
(
|
|
NULL,
|
|
s_wszComponentName,
|
|
s_cwsComRegDBTargetDir,
|
|
L"*",
|
|
true,
|
|
NULL
|
|
);
|
|
ft.CheckForErrorInternal(VSSDBG_WRITER, L"IVssCreateWriterMetadata::AddFilesToFileGroup");
|
|
|
|
}
|
|
VSS_STANDARD_CATCH(ft)
|
|
|
|
TranslateWriterError(ft.hr);
|
|
|
|
return ft.HrSucceeded();
|
|
}
|
|
|
|
// Check whether the writer component is selected
|
|
// implements CVssWriter::OnPrepareSnapshot
|
|
bool STDMETHODCALLTYPE CComRegDBWriter::OnPrepareBackup(IN IVssWriterComponents *pWriterComponents)
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_WRITER, L"CComRegDBWriter::OnPrepareBackup");
|
|
|
|
|
|
try
|
|
{
|
|
m_bPerformSnapshot = FALSE;
|
|
|
|
if ( AreComponentsSelected() )
|
|
{
|
|
// We are in component selection mode...
|
|
UINT cComponents;
|
|
|
|
ft.hr = pWriterComponents->GetComponentCount( &cComponents );
|
|
ft.CheckForErrorInternal( VSSDBG_WRITER, L"IVssWriterComponents::GetComponentCount" );
|
|
|
|
if (cComponents > 0)
|
|
// This writer has only one component so this means the component is selected
|
|
m_bPerformSnapshot = TRUE;
|
|
}
|
|
|
|
}
|
|
VSS_STANDARD_CATCH( ft );
|
|
|
|
TranslateWriterError(ft.hr);
|
|
|
|
ft.Trace(VSSDBG_WRITER, L"CComRegDBWriter returning with hresult 0x%08lx", ft.hr);
|
|
|
|
return ft.HrSucceeded();
|
|
}
|
|
|
|
// Backup the database
|
|
// implements CVssWriter::OnPrepareSnapshot
|
|
bool STDMETHODCALLTYPE CComRegDBWriter::OnPrepareSnapshot()
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_WRITER, L"CComRegDBWriter::OnPrepareSnapshot");
|
|
|
|
HMODULE hRegDbDll = NULL;
|
|
|
|
try
|
|
{
|
|
CBsString cwsExpanded;
|
|
if (!cwsExpanded.ExpandEnvironmentStrings(s_cwsComRegDBTargetDir))
|
|
{
|
|
ft.TranslateError(VSSDBG_WRITER, HRESULT_FROM_WIN32(::GetLastError()),
|
|
L"CBsString::ExpandEnvironmentStrings");
|
|
}
|
|
|
|
// Make sure that we don't backup up old stuff in the COM+ RegDB backup dir
|
|
// (Do this even if this writer is not supposed to spit such that we don't backup old data)
|
|
ft.hr = ::RemoveDirectoryTree(cwsExpanded);
|
|
ft.CheckForErrorInternal(VSSDBG_WRITER, L"::RemoveDirectoryTree");
|
|
|
|
ft.hr = ::CreateTargetPath(cwsExpanded);
|
|
ft.CheckForErrorInternal(VSSDBG_WRITER, L"::CreateTargetPath");
|
|
|
|
|
|
// Spit only if component is selected or this is a BootableSystemState backup
|
|
if ( !m_bPerformSnapshot && IsBootableSystemStateBackedUp() )
|
|
m_bPerformSnapshot = TRUE;
|
|
|
|
if (m_bPerformSnapshot)
|
|
{
|
|
//
|
|
// Backup the Com+ RegDB
|
|
//
|
|
|
|
// Load DLL and Get backup-func address
|
|
hRegDbDll = LoadLibrary(L"catsrvut.dll");
|
|
if (hRegDbDll == NULL)
|
|
ft.TranslateError(VSSDBG_WRITER, HRESULT_FROM_WIN32(::GetLastError()),
|
|
L"LoadLibrary catsrvut.dll");
|
|
|
|
PF_REG_DB_API pfRegDBBackup;
|
|
pfRegDBBackup = (PF_REG_DB_API)GetProcAddress(hRegDbDll, "RegDBBackup");
|
|
if (pfRegDBBackup == NULL)
|
|
ft.TranslateError(VSSDBG_WRITER, HRESULT_FROM_WIN32(::GetLastError()),
|
|
L"GetProcAddress RegDBBackup catsrvut.dll");
|
|
|
|
// Add file-name to backup path
|
|
cwsExpanded += s_cwsBackupFilename;
|
|
|
|
// Call backup function
|
|
CComBSTR bstrExpanded = cwsExpanded;
|
|
if (bstrExpanded.Length() == 0)
|
|
ft.Throw(VSSDBG_WRITER, E_OUTOFMEMORY, L"Memory allocation error");
|
|
ft.hr = pfRegDBBackup(bstrExpanded);
|
|
if (ft.HrFailed())
|
|
ft.TranslateGenericError
|
|
(
|
|
VSSDBG_WRITER,
|
|
ft.hr,
|
|
L"::RegDBBackup(%s)",
|
|
bstrExpanded
|
|
);
|
|
}
|
|
}
|
|
VSS_STANDARD_CATCH( ft );
|
|
|
|
TranslateWriterError(ft.hr);
|
|
|
|
if (hRegDbDll != NULL) {
|
|
FreeLibrary(hRegDbDll);
|
|
hRegDbDll = NULL;
|
|
}
|
|
|
|
ft.Trace(VSSDBG_WRITER, L"CComRegDBWriter returning with hresult 0x%08lx", ft.hr);
|
|
|
|
return ft.HrSucceeded();
|
|
}
|
|
|
|
|
|
bool STDMETHODCALLTYPE CComRegDBWriter::OnFreeze()
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_WRITER, L"CComRegDBWriter::OnFreeze");
|
|
|
|
return ft.HrSucceeded();
|
|
}
|
|
|
|
|
|
bool STDMETHODCALLTYPE CComRegDBWriter::OnThaw()
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_WRITER, L"CComRegDBWriter::OnThaw");
|
|
|
|
return ft.HrSucceeded();
|
|
}
|
|
|
|
|
|
bool STDMETHODCALLTYPE CComRegDBWriter::OnAbort()
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_WRITER, L"CComRegDBWriter::OnAbort");
|
|
|
|
return ft.HrSucceeded();
|
|
}
|
|
|
|
|
|
// Converted to CUSTOM restore method (see bug# 688278)
|
|
#if 0
|
|
|
|
|
|
// Clean-up restore directory
|
|
// implements CVssWriter::OnPreRestore
|
|
bool STDMETHODCALLTYPE CComRegDBWriter::OnPreRestore(IVssWriterComponents *pComponent)
|
|
{
|
|
UNREFERENCED_PARAMETER(pComponent);
|
|
|
|
CVssFunctionTracer ft(VSSDBG_WRITER, L"CComRegDBWriter::OnPreRestore");
|
|
|
|
try
|
|
{
|
|
//
|
|
// Note: There is no need to check for selected components here since the writer is being
|
|
// called during restore only if its component (there's only one) is being selected
|
|
//
|
|
CBsString cwsExpanded;
|
|
if (!cwsExpanded.ExpandEnvironmentStrings(s_cwsComRegDBTargetDir))
|
|
{
|
|
ft.TranslateError(VSSDBG_WRITER, HRESULT_FROM_WIN32(::GetLastError()),
|
|
L"CBsString::ExpandEnvironmentStrings");
|
|
}
|
|
|
|
// make sure that we don't mix up old stuff with the new restore in the COM+ RegDB backup dir
|
|
ft.hr = ::RemoveDirectoryTree(cwsExpanded);
|
|
ft.CheckForErrorInternal(VSSDBG_WRITER, L"::RemoveDirectoryTree");
|
|
|
|
ft.hr = ::CreateTargetPath(cwsExpanded);
|
|
ft.CheckForErrorInternal(VSSDBG_WRITER, L"::CreateTargetPath");
|
|
|
|
}
|
|
VSS_STANDARD_CATCH( ft );
|
|
|
|
TranslateWriterError(ft.hr);
|
|
|
|
ft.Trace(VSSDBG_WRITER, L"CComRegDBWriter returning with hresult 0x%08lx", ft.hr);
|
|
|
|
return ft.HrSucceeded();
|
|
}
|
|
|
|
// Restore files using a legacy COM+ API
|
|
// implements CVssWriter::OnPostRestore
|
|
bool STDMETHODCALLTYPE CComRegDBWriter::OnPostRestore(IVssWriterComponents *pComponent)
|
|
{
|
|
UNREFERENCED_PARAMETER(pComponent);
|
|
|
|
CVssFunctionTracer ft(VSSDBG_WRITER, L"CComRegDBWriter::OnPostRestore");
|
|
|
|
HMODULE hRegDbDll = NULL;
|
|
|
|
try
|
|
{
|
|
//
|
|
// Note: There is no need to check for selected components here since the writer is being
|
|
// called during restore only if its component (there's only one) is being selected
|
|
//
|
|
CBsString cwsExpanded;
|
|
if (!cwsExpanded.ExpandEnvironmentStrings(s_cwsComRegDBTargetDir))
|
|
{
|
|
ft.TranslateError(VSSDBG_WRITER, HRESULT_FROM_WIN32(::GetLastError()),
|
|
L"CBsString::ExpandEnvironmentStrings");
|
|
}
|
|
|
|
// Add file-name to backup path
|
|
cwsExpanded += s_cwsBackupFilename;
|
|
|
|
CComBSTR bstrExpanded = cwsExpanded;
|
|
if (bstrExpanded.Length() == 0)
|
|
ft.Throw(VSSDBG_WRITER, E_OUTOFMEMORY, L"Memory allocation error");
|
|
|
|
//
|
|
// Restore the Com+ RegDB
|
|
// Use similar approach to ICOMAdminCatalog::RestoreREGDB (implemented by CCatalog2::RestoreREGDB)
|
|
//
|
|
|
|
// Load DLL and Get restore-func address
|
|
hRegDbDll = LoadLibrary(L"catsrvut.dll");
|
|
if (hRegDbDll == NULL)
|
|
ft.TranslateError(VSSDBG_WRITER, HRESULT_FROM_WIN32(::GetLastError()),
|
|
L"LoadLibrary catsrvut.dll");
|
|
|
|
PF_REG_DB_API pfRegDBRestore;
|
|
pfRegDBRestore = (PF_REG_DB_API)GetProcAddress(hRegDbDll, "RegDBRestore");
|
|
if (pfRegDBRestore == NULL)
|
|
ft.TranslateError(VSSDBG_WRITER, HRESULT_FROM_WIN32(::GetLastError()),
|
|
L"GetProcAddress RegDBRestore catsrvut.dll");
|
|
|
|
// Stop the COMSysApp service (best effort - continue if we fail)
|
|
StopCOMSysAppService(); // should we log a warning here?
|
|
|
|
// Call restore function
|
|
for (int iRetry = 0; iRetry < 5; iRetry++) {
|
|
ft.hr = pfRegDBRestore(bstrExpanded);
|
|
if (ft.HrSucceeded())
|
|
break;
|
|
else if (ft.hr != HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS))
|
|
ft.TranslateGenericError
|
|
(
|
|
VSSDBG_WRITER,
|
|
ft.hr,
|
|
L"::RegDBRestore(%s)",
|
|
bstrExpanded
|
|
);
|
|
|
|
Sleep(1000);
|
|
}
|
|
|
|
if (! ft.HrSucceeded())
|
|
ft.TranslateGenericError
|
|
(
|
|
VSSDBG_WRITER,
|
|
ft.hr,
|
|
L"::RegDBRestore(%s)",
|
|
bstrExpanded
|
|
);
|
|
|
|
}
|
|
VSS_STANDARD_CATCH( ft );
|
|
|
|
TranslateWriterError(ft.hr);
|
|
|
|
ft.Trace(VSSDBG_WRITER, L"CComRegDBWriter returning with hresult 0x%08lx", ft.hr);
|
|
|
|
return ft.HrSucceeded();
|
|
}
|
|
#endif
|
|
|
|
|
|
// translate a sql writer error code into a writer error
|
|
void CComRegDBWriter::TranslateWriterError( HRESULT hr )
|
|
{
|
|
//
|
|
// To DO: Check whether the spit backup/restore methods return any "RETRYABLE" errors
|
|
//
|
|
switch(hr)
|
|
{
|
|
default:
|
|
SetWriterFailure(VSS_E_WRITERERROR_NONRETRYABLE);
|
|
break;
|
|
|
|
case S_OK:
|
|
break;
|
|
|
|
case E_OUTOFMEMORY:
|
|
case HRESULT_FROM_WIN32(ERROR_DISK_FULL):
|
|
case HRESULT_FROM_WIN32(ERROR_TOO_MANY_OPEN_FILES):
|
|
case HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY):
|
|
case HRESULT_FROM_WIN32(ERROR_NO_MORE_USER_HANDLES):
|
|
SetWriterFailure(VSS_E_WRITERERROR_OUTOFRESOURCES);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Creates one instance of the Event Log writer class. If one already exists, it simple returns.
|
|
// Note: This method is not MT-safe - it is not expected that it will be called twice at the same time
|
|
HRESULT CComRegDBWriter::CreateWriter()
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_WRITER, L"CComRegDBWriter::CreateWriter");
|
|
|
|
if ( sm_pWriter != NULL )
|
|
return S_OK;
|
|
|
|
//
|
|
// Create and initialize a writer
|
|
//
|
|
try
|
|
{
|
|
sm_pWriter = new CComRegDBWriter;
|
|
if (sm_pWriter == NULL)
|
|
ft.Throw(VSSDBG_WRITER, E_OUTOFMEMORY, L"Allocation of CComRegDBWriter object failed.");
|
|
|
|
ft.hr = sm_pWriter->Initialize();
|
|
if (! ft.HrSucceeded())
|
|
ft.Throw(VSSDBG_WRITER, ft.hr, L"Initialization of CComRegDBWriter object failed.");
|
|
}
|
|
VSS_STANDARD_CATCH(ft);
|
|
|
|
return ft.hr;
|
|
}
|
|
|
|
// static
|
|
void CComRegDBWriter::DestroyWriter()
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_WRITER, L"CComRegDBWriter::DestroyWriter");
|
|
|
|
if (sm_pWriter)
|
|
{
|
|
sm_pWriter->Uninitialize();
|
|
delete sm_pWriter;
|
|
sm_pWriter = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Stop the COMSysApp service if exists
|
|
//
|
|
HRESULT STDMETHODCALLTYPE CComRegDBWriter::StopCOMSysAppService()
|
|
{
|
|
CVssFunctionTracer ft(VSSDBG_WRITER, L"CComRegDBWriter::StopCOMSysAppService");
|
|
|
|
SC_HANDLE hSCM = NULL;
|
|
SC_HANDLE hService = NULL;
|
|
|
|
try
|
|
{
|
|
SERVICE_STATUS svcStatus;
|
|
BOOL bWait = TRUE;
|
|
BOOL bStop = TRUE;
|
|
|
|
hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
|
|
if (hSCM == NULL)
|
|
ft.TranslateError(VSSDBG_WRITER, HRESULT_FROM_WIN32(GetLastError()), L"::OpenSCManager");
|
|
|
|
hService = OpenService(hSCM, s_wszCOMSysAppServiceName, (SERVICE_STOP | SERVICE_QUERY_STATUS));
|
|
if (hService == NULL) {
|
|
DWORD dwErr = GetLastError();
|
|
|
|
switch (dwErr) {
|
|
|
|
case ERROR_SERVICE_DOES_NOT_EXIST:
|
|
// No such service (maybe ASR mode, service is not registered yet), no need to stop or wait
|
|
bStop = FALSE;
|
|
bWait = FALSE;
|
|
break;
|
|
|
|
default:
|
|
// Any other error is unexpected
|
|
ft.TranslateError(VSSDBG_WRITER, HRESULT_FROM_WIN32(dwErr), L"::OpenService");
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Stop the service
|
|
if (bStop) {
|
|
// Retry couple of times if the service caanot accept controls
|
|
for (int iRetry = 0; iRetry < 5; iRetry++) {
|
|
memset(&svcStatus, 0, sizeof(svcStatus));
|
|
if (! ControlService(hService, SERVICE_CONTROL_STOP, &svcStatus)) {
|
|
DWORD dwErr = GetLastError();
|
|
|
|
switch (dwErr) {
|
|
|
|
case ERROR_SERVICE_NOT_ACTIVE:
|
|
// Service is not running, no need to wait
|
|
bWait = FALSE;
|
|
break;
|
|
|
|
case ERROR_SERVICE_CANNOT_ACCEPT_CTRL:
|
|
// Service may be at STOP_PENDING or START_PENDING, retry
|
|
break;
|
|
|
|
default:
|
|
// Any other error is unexpected
|
|
ft.TranslateError(VSSDBG_WRITER, HRESULT_FROM_WIN32(dwErr), L"::ControlService");
|
|
break;
|
|
}
|
|
|
|
if (! bWait)
|
|
// Service not active
|
|
break;
|
|
|
|
// Sleep before retry
|
|
Sleep(2000);
|
|
|
|
} else {
|
|
// Success, no need to retry
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bWait) {
|
|
// Wait till service is stopped. 30 seconds max
|
|
DWORD dwWaitTime = 0;
|
|
while (TRUE) {
|
|
memset(&svcStatus, 0, sizeof(svcStatus));
|
|
if (! QueryServiceStatus(hService, &svcStatus))
|
|
ft.TranslateError(VSSDBG_WRITER, HRESULT_FROM_WIN32(GetLastError()), L"::QueryServiceStatus");
|
|
|
|
if (svcStatus.dwCurrentState == SERVICE_STOPPED)
|
|
break;
|
|
|
|
Sleep(1000);
|
|
dwWaitTime += 1000;
|
|
if (dwWaitTime >= (30 * 1000))
|
|
ft.TranslateGenericError(
|
|
VSSDBG_WRITER,
|
|
HRESULT_FROM_WIN32(ERROR_SERVICE_CANNOT_ACCEPT_CTRL),
|
|
L"ControlService (%s, SERVICE_CONTROL_STOP)",
|
|
s_wszCOMSysAppServiceName
|
|
);
|
|
}
|
|
}
|
|
}
|
|
VSS_STANDARD_CATCH( ft );
|
|
|
|
if (hService != NULL) {
|
|
CloseServiceHandle(hService);
|
|
hService = NULL;
|
|
}
|
|
if (hSCM != NULL) {
|
|
CloseServiceHandle(hSCM);
|
|
hSCM = NULL;
|
|
}
|
|
|
|
return (ft.hr);
|
|
}
|