|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997 - 1998
//
// File: C S E R V I C E . C P P
//
// Contents: Implementation of non-inline CService and CServiceManager
// methods.
//
// Notes:
//
// Author: mikemi 6 Mar 1997
//
//----------------------------------------------------------------------------
#include "stdafx.h"
#include "cservice.h"
size_t CchMsz(const TCHAR * msz) { TCHAR * pch= (TCHAR *) msz;
while (*pch) { pch += lstrlen(pch)+1; }
return (size_t) (pch-msz+1); }
BOOL FIsSzInMultiSzSafe(LPCTSTR sz, LPCTSTR szMultiSz) { ULONG ulLen;
if (!szMultiSz || !sz) return FALSE;
while (*szMultiSz) { ulLen = lstrlen(szMultiSz); if (lstrcmpi(szMultiSz, sz)==0) return TRUE; szMultiSz += (ulLen + 1); }
return FALSE; }
HRESULT HrAddSzToMultiSz(LPCTSTR sz, LPCTSTR mszIn, LPTSTR * pmszOut) { HRESULT hr = S_OK; Assert(pmszOut); if (!FIsSzInMultiSzSafe(sz, mszIn)) // We need to add the string
{ size_t cchMszIn = CchMsz(mszIn); size_t cchMszOut = cchMszIn + lstrlen(sz) + 1;
TCHAR * mszOut = new TCHAR[(int)cchMszOut]; ZeroMemory(mszOut, cchMszOut * sizeof(TCHAR));
// Copy the existing string
CopyMemory(mszOut, mszIn, (cchMszIn-1) * sizeof(TCHAR) );
// Add the new string
TCHAR * pchOut = mszOut; pchOut += cchMszIn -1; lstrcpy(pchOut, sz);
// Add the last '\0' for the output multisz
pchOut += lstrlen(sz) + 1; *pchOut = '\0';
*pmszOut = mszOut; } else // We just make a copy of the input string
{ size_t cchMszOut = CchMsz(mszIn); TCHAR * mszOut = new TCHAR[(int)cchMszOut]; // Copy the existing string
CopyMemory(mszOut, mszIn, cchMszOut*sizeof(TCHAR) ); *pmszOut = mszOut; }
Trace1("HrAddSzToMultiSz %08lx", hr); return hr; }
//+---------------------------------------------------------------------------
//
// Function: HrRemoveSzFromMultiSz
//
// Purpose: Remove a NULL terminated sz to a double NULL terminated Multi_Sz
//
// Arguments:
// sz [in] The string to remove
// mszIn [in] The Multi_Sz to remove from
// mszOut [out] The result Multi_Sz
//
// Returns: Always return S_OK for now
// Only possible failure is out of memory, which will throw exception
//
// Author: tongl 17 June 1997
//
// Notes: 1) This function only removes the first occurrance of the sz
// 2) The result multi_sz should be released using delete
//
HRESULT HrRemoveSzFromMultiSz(LPCTSTR sz, LPCTSTR mszIn, LPTSTR * pmszOut) { HRESULT hr = S_OK; Assert(pmszOut);
if(FIsSzInMultiSzSafe(sz, mszIn)) // We need to remove the string
{ size_t cchIn = CchMsz(mszIn); size_t cchOut = cchIn - lstrlen(sz)-1; // we assume the can string only appeared once
// Construct the output multi-sz
TCHAR * mszOut = new TCHAR[(int)cchOut]; ZeroMemory(mszOut, cchOut*sizeof(TCHAR));
TCHAR * pchIn = (TCHAR*) mszIn; TCHAR * pchOut = mszOut;
while(*pchIn) // for each substring in mszIn
{ if(lstrcmpi(pchIn, sz) != 0) // if not the same as the string we are removing
{ lstrcpy(pchOut, pchIn); pchIn += lstrlen(pchIn) + 1; pchOut += lstrlen(pchOut) + 1; } else // skip the string we are deleting
{ pchIn += lstrlen(pchIn) + 1; } }
// Add the last '\0' of the multi-sz
*pchOut = '\0';
*pmszOut = mszOut; } else // We simply make a copy of the input string
{ size_t cchMszOut = CchMsz(mszIn); TCHAR * mszOut = new TCHAR[(int)cchMszOut]; // Copy the existing string
CopyMemory(mszOut, mszIn, cchMszOut*sizeof(TCHAR)); *pmszOut = mszOut; }
Trace1("HrRemoveSzFromMultiSz %08lx", hr); return hr; }
//-------------------------------------------------------------------
HRESULT CService::HrMoveOutOfState(DWORD dwState) { HRESULT hr = S_OK; SERVICE_STATUS sStatus;
// Give the service a maximum of 30 seconds to start
UINT cTimeout = 30;
AssertSz((NULL != _schandle), "We don't have a service handle");
do { DWORD dwWait = 0;
// Get the status of the service
if (!::QueryServiceStatus(_schandle, &sStatus)) { hr = HRESULT_FROM_WIN32(GetLastError()); break; }
// We are not longer in the state we were waiting for
if (sStatus.dwCurrentState != dwState) { hr = S_OK; break; }
// Wait a second and or less for the service to start
dwWait = min((sStatus.dwWaitHint / 10), 1*(1000));
::Sleep(dwWait); } while(cTimeout--); // Make sure we don't get in an endless loop.
// Return an error if we timeout
if (0 == cTimeout) { hr = HRESULT_FROM_WIN32(ERROR_NOT_READY);
AssertSz(FALSE, "We timed out on waiting for a service. This is bad."); }
Trace1("CService::HrMoveOutOfState", hr); return hr; }
//-------------------------------------------------------------------
HRESULT CService::HrQueryState( DWORD* pdwState ) { SERVICE_STATUS sStatus;
Assert(_schandle != NULL ); Assert(pdwState != NULL );
if (!::QueryServiceStatus( _schandle, &sStatus )) { *pdwState = 0; return HRESULT_FROM_WIN32(GetLastError()); } *pdwState = sStatus.dwCurrentState; return S_OK; }
//-------------------------------------------------------------------
HRESULT CService::HrQueryStartType( DWORD* pdwStartType ) { LPQUERY_SERVICE_CONFIG pqsConfig = NULL; DWORD cbNeeded = sizeof( QUERY_SERVICE_CONFIG ); DWORD cbSize; BOOL frt;
Assert(_schandle != NULL ); Assert(pdwStartType != NULL );
*pdwStartType = 0; // loop, allocating the needed size
do { delete [] (PBYTE)pqsConfig;
pqsConfig = (LPQUERY_SERVICE_CONFIG) new BYTE[cbNeeded]; if (pqsConfig == NULL) { return E_OUTOFMEMORY; } cbSize = cbNeeded;
frt = ::QueryServiceConfig( _schandle, pqsConfig, cbSize, &cbNeeded ); *pdwStartType = pqsConfig->dwStartType; delete [] (PBYTE)pqsConfig; pqsConfig = NULL;
if (!frt && (cbNeeded == cbSize)) { // error
*pdwStartType = 0; return HRESULT_FROM_WIN32(GetLastError()); }
} while (!frt && (cbNeeded != cbSize));
return S_OK; }
//-------------------------------------------------------------------
HRESULT CService::HrQueryDependencies(OUT LPTSTR * pmszDependencyList) { HRESULT hr = S_OK;
LPQUERY_SERVICE_CONFIG pqsConfig = NULL; DWORD cbNeeded = sizeof( QUERY_SERVICE_CONFIG ); DWORD cbSize; BOOL frt;
Assert(_schandle != NULL ); Assert(pmszDependencyList);
// loop, allocating the needed size
do { delete [] (PBYTE)pqsConfig;
pqsConfig = (LPQUERY_SERVICE_CONFIG) new BYTE[cbNeeded]; if (pqsConfig == NULL) { hr = E_OUTOFMEMORY;
Trace1("CService::HrQueryDependencies", hr); return hr; } cbSize = cbNeeded;
frt = ::QueryServiceConfig( _schandle, pqsConfig, cbSize, &cbNeeded );
if (!frt && (cbNeeded == cbSize)) // error
{ delete [] (PBYTE)pqsConfig; pqsConfig = NULL;
pmszDependencyList = NULL;
hr = HRESULT_FROM_WIN32(GetLastError());
Trace1("CService::HrQueryDependencies", hr); return hr; } else if (frt && (cbNeeded != cbSize)) // We just need more space
{ delete [] (PBYTE)pqsConfig; pqsConfig = NULL; }
} while (!frt && (cbNeeded != cbSize));
// Copy pqsConfig->lpDependencies to *pmszDependencyList
// Allocating space
// int cch = CchMsz(pqsConfig->lpDependencies);
size_t cch=0; TCHAR * pch= pqsConfig->lpDependencies; while (*pch) { pch += lstrlen(pch)+1; } cch = (size_t)(pch - pqsConfig->lpDependencies +1);
TCHAR * mszOut; mszOut = new TCHAR[(int)cch];
if (mszOut == NULL) { hr = E_OUTOFMEMORY;
Trace1("CService::HrQueryDependencies", hr); return hr; } else { ZeroMemory(mszOut, cch * sizeof(TCHAR));
// Copy dependency list to mszOut
*pmszDependencyList = mszOut; pch = pqsConfig->lpDependencies;
while (*pch) { lstrcpy(mszOut, pch); mszOut += lstrlen(pch)+1; pch += lstrlen(pch)+1; } mszOut = '\0'; } delete [] (PBYTE)pqsConfig;
Trace1("CService::HrQueryDependencies", hr); return hr; }
//-------------------------------------------------------------------
HRESULT CServiceManager::HrQueryLocked(BOOL *pfLocked) { LPQUERY_SERVICE_LOCK_STATUS pqslStatus = NULL; DWORD cbNeeded = sizeof( QUERY_SERVICE_LOCK_STATUS ); DWORD cbSize; BOOL frt;
Assert(_schandle != NULL ); Assert(pfLocked != NULL);
*pfLocked = FALSE;
// loop, allocating the needed size
do { pqslStatus = (LPQUERY_SERVICE_LOCK_STATUS) new BYTE[cbNeeded]; if (pqslStatus == NULL) { return E_OUTOFMEMORY; } cbSize = cbNeeded;
frt = ::QueryServiceLockStatus( _schandle, pqslStatus, cbSize, &cbNeeded ); *pfLocked = pqslStatus->fIsLocked; delete [] (PBYTE)pqslStatus; pqslStatus = NULL; if (!frt && (cbNeeded == cbSize)) { // if an error, treat this as a lock
return HRESULT_FROM_WIN32(GetLastError()); }
} while (!frt && (cbNeeded != cbSize));
return S_OK; }
//+---------------------------------------------------------------------------
//
// Member: CServiceManager::HrStartServiceHelper
//
// Purpose: Starts the given service
//
// Arguments:
// szService [in] Name of service to start.
// eCriteria [in] if SERVICE_ONLY_AUTO_START, the service is only
// started if it is configured as auto-start
//
// Returns: S_OK if success, Win32 HRESULT otherwise.
//
// Author: danielwe 13 Jun 1997
//
// Notes:
//
HRESULT CServiceManager::HrStartServiceHelper(LPCTSTR szService, SERVICE_START_CRITERIA eCriteria) { HRESULT hr = S_OK; CService service;
hr = HrOpenService(&service, szService); if (SUCCEEDED(hr)) { BOOL fStart = TRUE;
if (SERVICE_ONLY_AUTO_START == eCriteria) { DWORD dwStartType;
// only start services that are not disabled and not manual
hr = service.HrQueryStartType(&dwStartType); if (FAILED(hr) || (SERVICE_DEMAND_START == dwStartType) || (SERVICE_DISABLED == dwStartType)) { fStart = FALSE; } }
// If everything is okay to start then start it!
if (fStart) { hr = service.HrStart(); if (SUCCEEDED(hr)) { // Make sure the service has started.
hr = service.HrMoveOutOfState(SERVICE_START_PENDING);
// Normalize result
if (SUCCEEDED(hr)) { hr = S_OK; } } else if (HRESULT_FROM_WIN32(ERROR_SERVICE_ALREADY_RUNNING) == hr) { // Ignore error if service is already running
hr = S_OK; } } service.Close(); }
return hr; }
//+---------------------------------------------------------------------------
//
// Member: CServiceManager::HrStopService
//
// Purpose: Stops the given service.
//
// Arguments:
// szService [in] Name of service to stop.
//
// Returns: S_OK if success, Win32 HRESULT otherwise.
//
// Author: danielwe 17 Jun 1997
//
// Notes: If service is not running, this returns S_OK.
//
HRESULT CServiceManager::HrStopService(LPCTSTR szService) { HRESULT hr = S_OK; CService service;
hr = HrOpenService(&service, szService); if (SUCCEEDED(hr)) { hr = service.HrControl(SERVICE_CONTROL_STOP); if (HRESULT_FROM_WIN32(ERROR_SERVICE_NOT_ACTIVE) == hr) { // ignore error if the service is not running
hr = S_OK; }
service.Close(); }
Trace1("CServiceManager::HrStopService", hr); return hr; }
//+---------------------------------------------------------------------------
//
// Member: CServiceManager::HrAddRemoveServiceDependency
//
// Purpose: Add/remove dependency to a service
//
// Arguments:
// szService [in] Name of service
// szDependency [in] Dependency to add
// enumFlag [in] Indicates add or remove
//
// Returns: S_OK if success, Win32 HRESULT otherwise.
//
// Author: tongl 17 Jun 1997
//
// Notes: this function is not for adding/removing group dependency
//
HRESULT CServiceManager::HrAddRemoveServiceDependency(LPCTSTR szServiceName, LPCTSTR szDependency, DEPENDENCY_ADDREMOVE enumFlag) { HRESULT hr = S_OK;
Assert(szServiceName); Assert(szDependency); Assert((enumFlag == DEPENDENCY_ADD) || (enumFlag == DEPENDENCY_REMOVE));
// If either string is empty, do nothing
if ((lstrlen(szDependency)>0) && (lstrlen(szServiceName)>0)) { hr = HrLock(); if (SUCCEEDED(hr)) { LPCTSTR szSrv = szDependency;
CService svc; // Check if the dependency service exists
hr = HrOpenService(&svc, szDependency);
if SUCCEEDED(hr) { svc.Close();
// Open the service we are changing dependency on
szSrv = szServiceName; hr = HrOpenService(&svc, szServiceName); if (SUCCEEDED(hr)) { LPTSTR mszDependencies;
hr = svc.HrQueryDependencies(&mszDependencies); if(SUCCEEDED(hr) && mszDependencies) { TCHAR * mszNewDependencies;
if (enumFlag == DEPENDENCY_ADD) { hr = HrAddSzToMultiSz(szDependency, mszDependencies, &mszNewDependencies); } else if (enumFlag == DEPENDENCY_REMOVE) { hr = HrRemoveSzFromMultiSz(szDependency, mszDependencies, &mszNewDependencies); }
if (SUCCEEDED(hr)) { // Now set the new dependency
hr = svc.HrSetDependencies(const_cast<LPCTSTR>(mszNewDependencies)); delete [] mszNewDependencies; } } delete [] mszDependencies; svc.Close(); } }
if (HRESULT_FROM_WIN32(ERROR_SERVICE_DOES_NOT_EXIST) == hr) // If either services do not exist
{
#ifdef DEBUG
Trace1("CServiceManager::HrAddServiceDependency, Service %s does not exist.", szSrv); #endif
hr = S_OK; } }
Unlock();
} // if szDependency is not empty string
Trace1("CServiceManager::HrAddServiceDependency", hr); return hr; }
|