#pragma once
#include "ProSysLib_i.h"
#include "PSLExceptions.h"
template<class Container, class Child, class ChildInterface>
class CServiceEnumerator
{
protected:
void EnumServices(Container * pContainer, long ServiceType)
{
SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, GENERIC_READ);
if(!hSCM)
{
if(::GetLastError() == ERROR_ACCESS_DENIED)
pContainer->SetException(exAccessDenied);
return;
}
DWORD dwBytesNeeded = 0;
DWORD dwServiceCount = 0;
DWORD dwResumeHandle = 0;
BOOL RetVal = ::EnumServicesStatusEx(hSCM, SC_ENUM_PROCESS_INFO, ServiceType, SERVICE_STATE_ALL, NULL, 0, &dwBytesNeeded, &dwServiceCount, &dwResumeHandle, NULL);
if(RetVal || GetLastError() != ERROR_MORE_DATA)
{
::CloseServiceHandle(hSCM);
return; // This should never happen;
}
LPBYTE pStatusBuffer = new BYTE[dwBytesNeeded];
if(!pStatusBuffer)
{
pContainer->SetException(exLowMemory);
::CloseServiceHandle(hSCM);
return;
}
if(!::EnumServicesStatusEx(hSCM, SC_ENUM_PROCESS_INFO, ServiceType, SERVICE_STATE_ALL, pStatusBuffer, dwBytesNeeded, &dwBytesNeeded, &dwServiceCount, &dwResumeHandle, NULL))
{
if(::GetLastError() == ERROR_ACCESS_DENIED)
pContainer->SetException(exAccessDenied);
delete []pStatusBuffer;
::CloseServiceHandle(hSCM);
return;
}
// Allocating 8Kb of memory to get full service description,
// which is also the supported maximum for a number of Service API-s,
// like QueryServiceConfig, so it cannot be changed.
DWORD dwBufferSize = 8192;
LPBYTE pTempBuffer = new BYTE[dwBufferSize];
if(!pTempBuffer)
{
pContainer->SetException(exLowMemory);
delete []pStatusBuffer;
::CloseServiceHandle(hSCM);
return;
}
LPENUM_SERVICE_STATUS_PROCESS pSSP = (LPENUM_SERVICE_STATUS_PROCESS)pStatusBuffer;
CCritSecLock cs(pContainer->m_csCollection);
pContainer->m_coll.clear();
CComObject<Child> * pService = NULL;
for(DWORD i = 0;i < dwServiceCount;i ++)
{
SC_HANDLE hService = ::OpenService(hSCM, pSSP[i].lpServiceName, GENERIC_READ);
if(!hService)
continue;
CComObject<Child>::CreateInstance(&pService);
pService->Initialize(hService, pSSP[i], pTempBuffer, dwBufferSize);
pContainer->m_coll.push_back(CComPtr<ChildInterface>(pService));
::CloseServiceHandle(hService);
}
cs.Unlock();
delete []pTempBuffer;
delete []pStatusBuffer;
::CloseServiceHandle(hSCM);
}
ChildInterface * FindService(Container * pContainer, BSTR ServiceName)
{
_bstr_t sServiceName(ServiceName);
CCritSecLock cs(pContainer->m_csCollection);
for(vector<CAdapt<CComPtr<ChildInterface> > >::iterator i = pContainer->m_coll.begin();i != pContainer->m_coll.end();i ++)
{
BSTR sName = NULL;
if(i->m_T->get_Name(&sName) == S_OK)
{
_bstr_t s(sName);
if(!::_tcsicmp(s, sServiceName)) // Doing case-insensitive comparison;
{
ChildInterface * pService = i->m_T;
pService->AddRef();
return pService;
}
}
}
return NULL;
}
};
class CServiceInfo
{
public:
CServiceInfo(void);
protected:
void Initialize(SC_HANDLE hSCM, ENUM_SERVICE_STATUS_PROCESS & ssp, LPBYTE pTempBuffer, DWORD dwBufferSize);
long StartService(SAFEARRAY * CmdParams, PSLException & ex);
long StopService(PSLException & ex);
PSLException Update();
_bstr_t m_sName;
_bstr_t m_sDisplayName;
_bstr_t m_sDescription;
_bstr_t m_sPath;
_bstr_t m_sStartName;
_bstr_t m_sDependencies;
PSLServiceState m_CurrentState;
DWORD m_dwServiceType;
DWORD m_dwStartType;
DWORD m_dwProcessID;
private:
DWORD m_dwTickCount;
};