474 lines
18 KiB
C
474 lines
18 KiB
C
#ifndef _SERVUTIL_H_
|
|
#define _SERVUTIL_H_
|
|
|
|
// forward reference
|
|
HRESULT _StopService (LPTSTR szServiceName, BOOL bIncludeDependentServices = FALSE, LPTSTR szMachineName = NULL );
|
|
|
|
inline HRESULT _ChangeServiceStartType (LPTSTR szServiceName, DWORD dwServiceStartType)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
SC_HANDLE hManager = OpenSCManager(NULL, NULL, STANDARD_RIGHTS_REQUIRED);
|
|
if (hManager == NULL)
|
|
hr = GetLastError();
|
|
else {
|
|
// stop service if it's running
|
|
SC_HANDLE hService = OpenService (hManager, szServiceName, SERVICE_ALL_ACCESS);
|
|
if (!hService)
|
|
hr = GetLastError();
|
|
else {
|
|
if (!ChangeServiceConfig (hService,
|
|
SERVICE_NO_CHANGE, // service type
|
|
dwServiceStartType, // start type
|
|
SERVICE_NO_CHANGE, // error control
|
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL))
|
|
hr = GetLastError();
|
|
CloseServiceHandle (hService);
|
|
}
|
|
CloseServiceHandle (hManager);
|
|
}
|
|
return HRESULT_FROM_WIN32(hr);
|
|
}
|
|
|
|
inline DWORD _GetServiceStatus (LPTSTR szServiceName, LPTSTR szMachineName = NULL)
|
|
{
|
|
DWORD dwStatus = 0;
|
|
SC_HANDLE hSCManager = OpenSCManager (szMachineName,
|
|
NULL, // ServicesActive database
|
|
SC_MANAGER_ALL_ACCESS); // full access rights
|
|
if (hSCManager != NULL) {
|
|
SC_HANDLE hService = OpenService (hSCManager,
|
|
szServiceName,
|
|
SERVICE_QUERY_STATUS);
|
|
if (hService) {
|
|
SERVICE_STATUS ss = {0};
|
|
if (QueryServiceStatus (hService, &ss))
|
|
dwStatus = ss.dwCurrentState;
|
|
CloseServiceHandle (hService);
|
|
}
|
|
CloseServiceHandle (hSCManager);
|
|
}
|
|
return dwStatus;
|
|
}
|
|
|
|
inline BOOL _IsServiceStartType (LPTSTR szServiceName, DWORD dwServiceStartType)
|
|
{
|
|
BOOL b = FALSE;
|
|
SC_HANDLE hSCManager = OpenSCManager (NULL, // local machine
|
|
NULL, // ServicesActive database
|
|
SC_MANAGER_ALL_ACCESS); // full access rights
|
|
if (hSCManager != NULL) {
|
|
SC_HANDLE hService = OpenService (hSCManager,
|
|
szServiceName,
|
|
SERVICE_ALL_ACCESS);
|
|
if (hService) {
|
|
DWORD dwSize = 0;
|
|
if (0 == QueryServiceConfig (hService, NULL, dwSize, &dwSize))
|
|
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
|
QUERY_SERVICE_CONFIG* pQSC = (QUERY_SERVICE_CONFIG*)malloc (dwSize);
|
|
if (pQSC) {
|
|
if (QueryServiceConfig (hService, pQSC, dwSize, &dwSize)) {
|
|
if (pQSC->dwStartType == dwServiceStartType)
|
|
b = TRUE;
|
|
}
|
|
free (pQSC);
|
|
}
|
|
}
|
|
CloseServiceHandle (hService);
|
|
}
|
|
CloseServiceHandle (hSCManager);
|
|
}
|
|
return b;
|
|
}
|
|
|
|
inline BOOL _IsServiceStatus (LPTSTR szServiceName, DWORD dwServiceStatus)
|
|
{
|
|
BOOL b = FALSE;
|
|
SC_HANDLE hSCManager = OpenSCManager (NULL, // local machine
|
|
NULL, // ServicesActive database
|
|
SC_MANAGER_ALL_ACCESS); // full access rights
|
|
if (hSCManager != NULL) {
|
|
SC_HANDLE hService = OpenService (hSCManager,
|
|
szServiceName,
|
|
SERVICE_QUERY_STATUS);
|
|
if (hService) {
|
|
SERVICE_STATUS ss = {0};
|
|
if (QueryServiceStatus (hService, &ss))
|
|
if (ss.dwCurrentState == dwServiceStatus)
|
|
b = TRUE;
|
|
CloseServiceHandle (hService);
|
|
}
|
|
CloseServiceHandle (hSCManager);
|
|
}
|
|
return b;
|
|
}
|
|
|
|
inline BOOL _IsServiceRunning (LPTSTR szServiceName)
|
|
{
|
|
return _IsServiceStatus (szServiceName, SERVICE_RUNNING);
|
|
}
|
|
|
|
inline BOOL _IsServiceInstalled (LPTSTR szServiceName)
|
|
{
|
|
BOOL b = FALSE;
|
|
SC_HANDLE hSCManager = OpenSCManager (NULL, // local machine
|
|
NULL, // ServicesActive database
|
|
SC_MANAGER_ALL_ACCESS); // full access rights
|
|
if (hSCManager != NULL) {
|
|
SC_HANDLE hService = OpenService (hSCManager,
|
|
szServiceName,
|
|
SERVICE_QUERY_STATUS);
|
|
if (hService) {
|
|
b = TRUE;
|
|
CloseServiceHandle (hService);
|
|
}
|
|
CloseServiceHandle (hSCManager);
|
|
}
|
|
return b;
|
|
}
|
|
|
|
// private inline
|
|
inline long __WaitForServiceStatus (SC_HANDLE hService, DWORD dwStatus)
|
|
{
|
|
SetLastError (0);
|
|
int iIOPendingErrors = 0;
|
|
|
|
SERVICE_STATUS ssStatus;
|
|
if (!QueryServiceStatus (hService, &ssStatus))
|
|
return GetLastError();
|
|
if (dwStatus == SERVICE_STOPPED) {
|
|
if (!(ssStatus.dwControlsAccepted & SERVICE_ACCEPT_STOP)) {
|
|
// service doesn't accept stop!
|
|
// return appropriate error
|
|
if (ssStatus.dwCurrentState == dwStatus)
|
|
return S_OK;
|
|
if (ssStatus.dwWin32ExitCode == ERROR_SERVICE_SPECIFIC_ERROR) {
|
|
if (ssStatus.dwServiceSpecificExitCode == 0)
|
|
return ERROR_INVALID_SERVICE_CONTROL;
|
|
return ssStatus.dwServiceSpecificExitCode;
|
|
}
|
|
if (ssStatus.dwWin32ExitCode != 0)
|
|
return ssStatus.dwWin32ExitCode;
|
|
return ERROR_INVALID_SERVICE_CONTROL;
|
|
}
|
|
}
|
|
|
|
DWORD dwOldCheckPoint, dwOldCurrentState;
|
|
while (ssStatus.dwCurrentState != dwStatus) {
|
|
// Save the current checkpoint.
|
|
dwOldCheckPoint = ssStatus.dwCheckPoint;
|
|
dwOldCurrentState = ssStatus.dwCurrentState;
|
|
|
|
// Wait for the specified interval.
|
|
int iSleep = ssStatus.dwWaitHint;
|
|
if (iSleep > 2500)
|
|
iSleep = 2500;
|
|
if (iSleep == 0)
|
|
iSleep = 100;
|
|
Sleep (iSleep);
|
|
|
|
// Check the status again.
|
|
SetLastError (0);
|
|
if (!QueryServiceStatus (hService, &ssStatus))
|
|
return GetLastError();
|
|
|
|
// Break if the checkpoint has not been incremented.
|
|
if (dwOldCheckPoint == ssStatus.dwCheckPoint)
|
|
if (dwOldCurrentState == ssStatus.dwCurrentState) {
|
|
// ok: at this point, we're supposed to be done, or there's an error
|
|
if (ssStatus.dwCurrentState == dwStatus)
|
|
break;
|
|
if (ssStatus.dwWin32ExitCode != 0)
|
|
break;
|
|
|
|
// some kinda screw up: we're not done and no error!
|
|
// so, give 'em one last chance....
|
|
Sleep (1000);
|
|
SetLastError (0);
|
|
if (!QueryServiceStatus (hService, &ssStatus))
|
|
return GetLastError();
|
|
|
|
if (dwOldCheckPoint == ssStatus.dwCheckPoint)
|
|
if (dwOldCurrentState == ssStatus.dwCurrentState) {
|
|
// empirical: I keep getting this when actually everything is ok
|
|
if (GetLastError() == ERROR_IO_PENDING)
|
|
if (iIOPendingErrors++ < 60)
|
|
continue;
|
|
break;
|
|
}
|
|
// if we get here, either the checkpoint or status changed, and we can keep going
|
|
}
|
|
}
|
|
if (ssStatus.dwCurrentState == dwStatus)
|
|
return S_OK;
|
|
|
|
if (ssStatus.dwWin32ExitCode == ERROR_SERVICE_SPECIFIC_ERROR) {
|
|
if (ssStatus.dwServiceSpecificExitCode == 0)
|
|
return E_FAIL;
|
|
return ssStatus.dwServiceSpecificExitCode;
|
|
}
|
|
if (ssStatus.dwWin32ExitCode != 0)
|
|
return ssStatus.dwWin32ExitCode;
|
|
|
|
// we should never get here
|
|
HRESULT hr = GetLastError();
|
|
return ERROR_SERVICE_REQUEST_TIMEOUT;
|
|
|
|
#ifdef BONE_HEADED_WAY
|
|
SERVICE_STATUS ssStatus;
|
|
|
|
// wait for at most 3 minutes
|
|
for (int i=0; i<180; i++) {
|
|
if (!QueryServiceStatus (hService, &ssStatus))
|
|
return HR (GetLastError()); // bad service handle?
|
|
|
|
if (ssStatus.dwCurrentState == dwStatus)
|
|
return S_OK; // all is well
|
|
|
|
Sleep(1000); // wait a second
|
|
}
|
|
return HRESULT_FROM_WIN32(ERROR_SERVICE_REQUEST_TIMEOUT);
|
|
#endif
|
|
}
|
|
|
|
inline HRESULT _RecursiveStop (SC_HANDLE hService)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
DWORD dwBufSize = 1, dwNumServices = 0;
|
|
if (!EnumDependentServices (hService,
|
|
SERVICE_ACTIVE,
|
|
(LPENUM_SERVICE_STATUS)&dwBufSize,
|
|
dwBufSize,
|
|
&dwBufSize,
|
|
&dwNumServices)) {
|
|
// this should fail with ERROR_MORE_DATA, unless there are no dependent services
|
|
hr = GetLastError ();
|
|
if (hr == ERROR_MORE_DATA) {
|
|
hr = S_OK;
|
|
ENUM_SERVICE_STATUS * pBuffer = (ENUM_SERVICE_STATUS *)malloc (dwBufSize);
|
|
if (!pBuffer)
|
|
hr = E_OUTOFMEMORY;
|
|
else {
|
|
if (!EnumDependentServices (hService,
|
|
SERVICE_ACTIVE,
|
|
pBuffer,
|
|
dwBufSize,
|
|
&dwBufSize,
|
|
&dwNumServices))
|
|
hr = GetLastError(); // shouldn't happen!!!
|
|
else {
|
|
_ASSERT (dwNumServices > 0);
|
|
for (DWORD i=0; i<dwNumServices && S_OK == hr; i++) {
|
|
hr = _StopService (pBuffer[i].lpServiceName, FALSE);
|
|
}
|
|
}
|
|
free (pBuffer);
|
|
}
|
|
}
|
|
}
|
|
return HRESULT_FROM_WIN32(hr);
|
|
}
|
|
|
|
inline HRESULT _ControlService (LPTSTR szServiceName, DWORD dwControl, LPTSTR szMachineName = NULL )
|
|
{
|
|
if ( NULL == szServiceName ) return E_INVALIDARG;
|
|
if (( SERVICE_CONTROL_PAUSE != dwControl ) && ( SERVICE_CONTROL_CONTINUE != dwControl )) return E_INVALIDARG;
|
|
|
|
HRESULT hr = S_OK;
|
|
SC_HANDLE hManager;
|
|
LPTSTR psMachineName = szMachineName;
|
|
SERVICE_STATUS ss;
|
|
|
|
if ( NULL != psMachineName )
|
|
{
|
|
psMachineName = new TCHAR[ _tcslen( szMachineName ) + 3];
|
|
if ( NULL == psMachineName )
|
|
return E_OUTOFMEMORY;
|
|
_tcscpy( psMachineName, _T( "\\\\" ));
|
|
_tcscat( psMachineName, szMachineName );
|
|
}
|
|
hManager = OpenSCManager(psMachineName, NULL, STANDARD_RIGHTS_REQUIRED);
|
|
if ( NULL != psMachineName )
|
|
delete [] psMachineName;
|
|
if (hManager == NULL)
|
|
hr = GetLastError();
|
|
else {
|
|
SC_HANDLE hService = OpenService (hManager, szServiceName, SERVICE_ALL_ACCESS);
|
|
if (hService == NULL)
|
|
hr = GetLastError();
|
|
else {
|
|
if (!ControlService( hService, dwControl, &ss ))
|
|
hr = GetLastError();
|
|
else
|
|
{
|
|
if ( SERVICE_CONTROL_PAUSE == dwControl )
|
|
hr = __WaitForServiceStatus(hService, SERVICE_PAUSED);
|
|
if ( SERVICE_CONTROL_CONTINUE == dwControl )
|
|
hr = __WaitForServiceStatus(hService, SERVICE_RUNNING);
|
|
}
|
|
CloseServiceHandle (hService);
|
|
}
|
|
CloseServiceHandle (hManager);
|
|
}
|
|
return HRESULT_FROM_WIN32(hr);
|
|
}
|
|
|
|
inline HRESULT _StopService (LPTSTR szServiceName, BOOL bIncludeDependentServices, LPTSTR szMachineName /*= NULL*/ )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
SC_HANDLE hManager;
|
|
LPTSTR psMachineName = szMachineName;
|
|
|
|
if ( NULL != psMachineName )
|
|
{
|
|
psMachineName = new TCHAR[ _tcslen( szMachineName ) + 3];
|
|
if ( NULL == psMachineName )
|
|
return E_OUTOFMEMORY;
|
|
_tcscpy( psMachineName, _T( "\\\\" ));
|
|
_tcscat( psMachineName, szMachineName );
|
|
}
|
|
hManager = OpenSCManager(psMachineName, NULL, STANDARD_RIGHTS_REQUIRED);
|
|
if ( NULL != psMachineName )
|
|
delete [] psMachineName;
|
|
if (hManager == NULL)
|
|
hr = GetLastError();
|
|
else {
|
|
// stop service if it's running
|
|
SC_HANDLE hService = OpenService (hManager, szServiceName, SERVICE_ALL_ACCESS);
|
|
if (!hService)
|
|
hr = GetLastError();
|
|
else {
|
|
LETS_TRY_AGAIN:
|
|
SERVICE_STATUS st;
|
|
if (!ControlService (hService, SERVICE_CONTROL_STOP, &st)) {
|
|
hr = GetLastError(); // for instance, not running
|
|
if (hr == ERROR_DEPENDENT_SERVICES_RUNNING) {
|
|
if (bIncludeDependentServices == TRUE) {
|
|
hr = _RecursiveStop (hService);
|
|
if (hr == S_OK)
|
|
goto LETS_TRY_AGAIN; // need to stop this service yet
|
|
}
|
|
}
|
|
} else
|
|
hr = __WaitForServiceStatus (hService, SERVICE_STOPPED);
|
|
CloseServiceHandle (hService);
|
|
}
|
|
CloseServiceHandle (hManager);
|
|
}
|
|
return HRESULT_FROM_WIN32(hr);
|
|
}
|
|
|
|
inline HRESULT _StartService (LPTSTR szServiceName, LPTSTR szMachineName = NULL )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
SC_HANDLE hManager;
|
|
LPTSTR psMachineName = szMachineName;
|
|
|
|
if ( NULL != psMachineName )
|
|
{
|
|
psMachineName = new TCHAR[ _tcslen( szMachineName ) + 3];
|
|
if ( NULL == psMachineName )
|
|
return E_OUTOFMEMORY;
|
|
_tcscpy( psMachineName, _T( "\\\\" ));
|
|
_tcscat( psMachineName, szMachineName );
|
|
}
|
|
hManager = OpenSCManager(psMachineName, NULL, STANDARD_RIGHTS_REQUIRED);
|
|
if ( NULL != psMachineName )
|
|
delete [] psMachineName;
|
|
if (hManager == NULL)
|
|
hr = GetLastError();
|
|
else {
|
|
SC_HANDLE hService = OpenService (hManager, szServiceName, SERVICE_ALL_ACCESS);
|
|
if (hService == NULL)
|
|
hr = GetLastError();
|
|
else {
|
|
if (!StartService(hService, 0, NULL))
|
|
hr = GetLastError();
|
|
else
|
|
hr = __WaitForServiceStatus(hService, SERVICE_RUNNING);
|
|
CloseServiceHandle (hService);
|
|
}
|
|
CloseServiceHandle (hManager);
|
|
}
|
|
return HRESULT_FROM_WIN32(hr);
|
|
}
|
|
|
|
inline HRESULT _RestartService (LPTSTR szServiceName, BOOL bIncludeDependentServices = FALSE)
|
|
{
|
|
// easy on first
|
|
if (bIncludeDependentServices == FALSE) {
|
|
_StopService (szServiceName, FALSE);
|
|
return _StartService (szServiceName);
|
|
}
|
|
|
|
// get array of dependent services;
|
|
DWORD dwNumServices = 0;
|
|
ENUM_SERVICE_STATUS * pBuffer = NULL;
|
|
HRESULT hr = S_OK, hr1 = S_OK;
|
|
SC_HANDLE hManager = OpenSCManager(NULL, NULL, STANDARD_RIGHTS_REQUIRED);
|
|
if (hManager == NULL)
|
|
hr = GetLastError();
|
|
else {
|
|
// stop service if it's running
|
|
SC_HANDLE hService = OpenService (hManager, szServiceName, SERVICE_ALL_ACCESS);
|
|
if (!hService)
|
|
hr = GetLastError();
|
|
else {
|
|
DWORD dwBufSize = 1;
|
|
// this should fail with ERROR_MORE_DATA, unless there are no dependent services
|
|
if (!EnumDependentServices (hService,
|
|
SERVICE_ACTIVE,
|
|
(LPENUM_SERVICE_STATUS)&dwBufSize,
|
|
dwBufSize,
|
|
&dwBufSize,
|
|
&dwNumServices)) {
|
|
hr = GetLastError ();
|
|
if (hr == ERROR_MORE_DATA) {
|
|
hr = S_OK;
|
|
pBuffer = (ENUM_SERVICE_STATUS *)malloc (dwBufSize);
|
|
if (!pBuffer)
|
|
hr = E_OUTOFMEMORY;
|
|
else {
|
|
if (!EnumDependentServices (hService,
|
|
SERVICE_ACTIVE,
|
|
pBuffer,
|
|
dwBufSize,
|
|
&dwBufSize,
|
|
&dwNumServices))
|
|
hr = GetLastError(); // shouldn't happen!!!
|
|
}
|
|
}
|
|
}
|
|
CloseServiceHandle (hService);
|
|
}
|
|
CloseServiceHandle (hManager);
|
|
}
|
|
|
|
if (hr == S_OK) {
|
|
// stop dependent services
|
|
if (pBuffer && dwNumServices) {
|
|
for (DWORD i=0; i<dwNumServices && S_OK == hr; i++) {
|
|
hr = _StopService (pBuffer[i].lpServiceName, FALSE);
|
|
}
|
|
}
|
|
if (hr == S_OK) {
|
|
// stop this service
|
|
hr1 = _RestartService (szServiceName, FALSE);
|
|
|
|
// always start dependent services
|
|
if (pBuffer && dwNumServices) {
|
|
for (int i=(int)dwNumServices-1; i>=0 && S_OK == hr; i--) {
|
|
hr = _StartService (pBuffer[i].lpServiceName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (pBuffer != NULL)
|
|
free (pBuffer);
|
|
if FAILED(hr1)
|
|
hr = hr1;
|
|
return HRESULT_FROM_WIN32(hr);
|
|
}
|
|
|
|
#endif
|