Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

1941 lines
47 KiB

//---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1995
//
// File: cserv.cxx
//
// Contents: Contains methods for the following objects
// CWinNTService,
//
// History: 12/11/95 ramv (Ram Viswanathan) Created.
//
//----------------------------------------------------------------------------
#include "winnt.hxx"
#pragma hdrstop
#define INITGUID
//
// class CWinNTService methods
//
DEFINE_IDispatch_ExtMgr_Implementation(CWinNTService);
DEFINE_IADsExtension_ExtMgr_Implementation(CWinNTService);
DEFINE_IADs_TempImplementation(CWinNTService);
DEFINE_IADs_PutGetImplementation(CWinNTService,ServiceClass,gdwServiceTableSize);
DEFINE_IADsPropertyList_Implementation(CWinNTService, ServiceClass,gdwServiceTableSize)
CWinNTService::CWinNTService()
{
_pDispMgr = NULL;
_pExtMgr = NULL;
_pPropertyCache = NULL;
_pszServiceName = NULL;
_pszServerName = NULL;
_pszPath = NULL;
_schSCManager = NULL;
_schService = NULL;
_dwWaitHint = 0;
_dwCheckPoint = 0;
_fValidHandle = FALSE;
ENLIST_TRACKING(CWinNTService);
}
CWinNTService::~CWinNTService()
{
if(_fValidHandle){
//
// an open handle exists, blow it away
//
WinNTCloseService();
_fValidHandle = FALSE;
}
if(_pszServiceName){
FreeADsStr(_pszServiceName);
}
if(_pszServerName){
FreeADsStr(_pszServerName);
}
if(_pszPath){
FreeADsStr(_pszPath);
}
delete _pExtMgr; // created last, destroyed first
delete _pDispMgr;
delete _pPropertyCache;
return;
}
//+---------------------------------------------------------------------------
//
// Function: CWinNTService::Create
//
// Synopsis: Static function used to create a Service object. This
// will be called by BindToObject
//
// Arguments: [ppWinNTService] -- Ptr to a ptr to a new Service object.
//
// Returns: HRESULT.
//
// Modifies:
//
// History: 12-11-95 RamV Created.
//
//----------------------------------------------------------------------------
HRESULT
CWinNTService::Create(LPTSTR pszADsParent,
LPTSTR pszDomainName,
LPTSTR pszServerName,
LPTSTR pszServiceName,
DWORD dwObjectState,
REFIID riid,
CWinNTCredentials& Credentials,
LPVOID * ppvoid
)
{
CWinNTService FAR * pCWinNTService = NULL;
HRESULT hr;
//
// Create the Service Object
//
hr = AllocateServiceObject(pszServerName,
pszServiceName,
&pCWinNTService);
BAIL_ON_FAILURE(hr);
ADsAssert(pCWinNTService->_pDispMgr);
hr = pCWinNTService->InitializeCoreObject(pszADsParent,
pszServiceName,
SERVICE_CLASS_NAME,
SERVICE_SCHEMA_NAME,
CLSID_WinNTService,
dwObjectState);
BAIL_ON_FAILURE(hr);
hr = SetLPTSTRPropertyInCache(pCWinNTService->_pPropertyCache,
TEXT("HostComputer"),
pCWinNTService->_Parent,
TRUE
);
BAIL_ON_FAILURE(hr);
pCWinNTService->_Credentials = Credentials;
hr = pCWinNTService->_Credentials.RefServer(pszServerName);
BAIL_ON_FAILURE(hr);
//
// Load ext mgr and extensions
//
hr = ADSILoadExtensionManager(
SERVICE_CLASS_NAME,
(IADsService *) pCWinNTService,
pCWinNTService->_pDispMgr,
Credentials,
&pCWinNTService->_pExtMgr
);
BAIL_ON_FAILURE(hr);
ADsAssert(pCWinNTService->_pExtMgr);
// check if the call is from UMI
if(Credentials.GetFlags() & ADS_AUTH_RESERVED) {
//
// we do not pass riid to InitUmiObject below. This is because UMI object
// does not support IDispatch. There are several places in ADSI code where
// riid passed into this function is defaulted to IID_IDispatch -
// IADsContainer::Create for example. To handle these cases, we always
// request IID_IUnknown from the UMI object. Subsequent code within UMI
// will QI for the appropriate interface.
//
if(3 == pCWinNTService->_dwNumComponents) {
pCWinNTService->_CompClasses[0] = L"Domain";
pCWinNTService->_CompClasses[1] = L"Computer";
pCWinNTService->_CompClasses[2] = L"Service";
}
else if(2 == pCWinNTService->_dwNumComponents) {
// no workstation services
pCWinNTService->_CompClasses[0] = L"Computer";
pCWinNTService->_CompClasses[1] = L"Service";
}
else
BAIL_ON_FAILURE(hr = UMI_E_FAIL);
hr = pCWinNTService->InitUmiObject(
pCWinNTService->_Credentials,
ServiceClass,
gdwServiceTableSize,
pCWinNTService->_pPropertyCache,
(IUnknown *)(INonDelegatingUnknown *) pCWinNTService,
pCWinNTService->_pExtMgr,
IID_IUnknown,
ppvoid
);
BAIL_ON_FAILURE(hr);
//
// UMI object was created and the interface was obtained successfully.
// UMI object now has a reference to the inner unknown of IADs, since
// the call to Release() below is not going to be made in this case.
//
RRETURN(hr);
}
hr = pCWinNTService->QueryInterface(riid, (void **)ppvoid);
BAIL_ON_FAILURE(hr);
pCWinNTService->Release();
RRETURN(hr);
error:
delete pCWinNTService;
RRETURN_EXP_IF_ERR(hr);
}
HRESULT
CWinNTService::AllocateServiceObject(
LPTSTR pszServerName,
LPTSTR pszServiceName,
CWinNTService ** ppService
)
{
CWinNTService FAR * pService = NULL;
HRESULT hr = S_OK;
pService = new CWinNTService();
if (pService == NULL) {
hr = E_OUTOFMEMORY;
}
BAIL_ON_FAILURE(hr);
pService->_pDispMgr = new CAggregatorDispMgr;
if (pService->_pDispMgr == NULL) {
hr = E_OUTOFMEMORY;
}
BAIL_ON_FAILURE(hr);
pService->_pszServerName =
AllocADsStr(pszServerName);
if(!(pService->_pszServerName)){
hr = E_OUTOFMEMORY;
goto error;
}
pService->_pszServiceName =
AllocADsStr(pszServiceName);
if(!(pService->_pszServiceName)){
hr = E_OUTOFMEMORY;
goto error;
}
hr = LoadTypeInfoEntry(pService->_pDispMgr,
LIBID_ADs,
IID_IADsService,
(IADsService *)pService,
DISPID_REGULAR
);
BAIL_ON_FAILURE(hr);
hr = LoadTypeInfoEntry(pService->_pDispMgr,
LIBID_ADs,
IID_IADsServiceOperations,
(IADsServiceOperations *)pService,
DISPID_REGULAR
);
BAIL_ON_FAILURE(hr);
hr = CPropertyCache::createpropertycache(
ServiceClass,
gdwServiceTableSize,
(CCoreADsObject *)pService,
&(pService->_pPropertyCache)
);
BAIL_ON_FAILURE(hr);
(pService->_pDispMgr)->RegisterPropertyCache(
pService->_pPropertyCache
);
*ppService = pService;
RRETURN(hr);
error:
//
// direct memeber assignement assignement at pt of creation, so
// do NOT delete _pPropertyCache or _pDisMgr here to avoid attempt
// of deletion again in pPrintJob destructor and AV
//
delete pService;
RRETURN(hr);
}
/* IUnknown methods for service object */
//----------------------------------------------------------------------------
// Function: QueryInterface
//
// Synopsis: If this object is aggregated within another object, then
// all calls will delegate to the outer object. Otherwise, the
// non-delegating QI is called
//
// Arguments:
//
// iid interface requested
// ppInterface Returns pointer to interface requested. NULL if interface
// is not supported.
//
// Returns: S_OK on success. Error code otherwise.
//
// Modifies: *ppInterface to return interface pointer
//
//----------------------------------------------------------------------------
STDMETHODIMP CWinNTService::QueryInterface(
REFIID iid,
LPVOID *ppInterface
)
{
if(_pUnkOuter != NULL)
RRETURN(_pUnkOuter->QueryInterface(
iid,
ppInterface
));
RRETURN(NonDelegatingQueryInterface(
iid,
ppInterface
));
}
//----------------------------------------------------------------------------
// Function: AddRef
//
// Synopsis: IUnknown::AddRef. If this object is aggregated within
// another, all calls will delegate to the outer object.
// Otherwise, the non-delegating AddRef is called
//
// Arguments:
//
// None
//
// Returns: New reference count
//
// Modifies: Nothing
//
//----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CWinNTService::AddRef(void)
{
if(_pUnkOuter != NULL)
RRETURN(_pUnkOuter->AddRef());
RRETURN(NonDelegatingAddRef());
}
//----------------------------------------------------------------------------
// Function: Release
//
// Synopsis: IUnknown::Release. If this object is aggregated within
// another, all calls will delegate to the outer object.
// Otherwise, the non-delegating Release is called
//
// Arguments:
//
// None
//
// Returns: New reference count
//
// Modifies: Nothing
//
//----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CWinNTService::Release(void)
{
if(_pUnkOuter != NULL)
RRETURN(_pUnkOuter->Release());
RRETURN(NonDelegatingRelease());
}
//----------------------------------------------------------------------------
STDMETHODIMP
CWinNTService::NonDelegatingQueryInterface(REFIID riid, LPVOID FAR* ppvObj)
{
HRESULT hr = S_OK;
if(!ppvObj){
RRETURN(E_POINTER);
}
if (IsEqualIID(riid, IID_IUnknown))
{
*ppvObj = (IADsService *)this;
}
else if (IsEqualIID(riid, IID_IDispatch))
{
*ppvObj = (IADsService *)this;
}
else if (IsEqualIID(riid, IID_ISupportErrorInfo))
{
*ppvObj = (ISupportErrorInfo FAR *)this;
}
else if (IsEqualIID(riid, IID_IADsPropertyList))
{
*ppvObj = (IADsPropertyList *)this;
}
else if (IsEqualIID(riid, IID_IADs))
{
*ppvObj = (IADsService FAR *) this;
}
else if (IsEqualIID(riid, IID_IADsService))
{
*ppvObj = (IADsService FAR *) this;
}
else if (IsEqualIID(riid, IID_IADsServiceOperations))
{
*ppvObj = (IADsServiceOperations FAR *) this;
}
else if( (_pDispatch != NULL) &&
IsEqualIID(riid, IID_IADsExtension) )
{
*ppvObj = (IADsExtension *) this;
}
else if (_pExtMgr)
{
RRETURN( _pExtMgr->QueryInterface(riid, ppvObj));
}
else
{
*ppvObj = NULL;
RRETURN(E_NOINTERFACE);
}
((LPUNKNOWN)*ppvObj)->AddRef();
RRETURN(S_OK);
}
/* ISupportErrorInfo method */
STDMETHODIMP
CWinNTService::InterfaceSupportsErrorInfo(
THIS_ REFIID riid
)
{
if (IsEqualIID(riid, IID_IADs) ||
IsEqualIID(riid, IID_IADsService) ||
IsEqualIID(riid, IID_IADsServiceOperations) ||
IsEqualIID(riid, IID_IADsPropertyList)) {
RRETURN(S_OK);
} else {
RRETURN(S_FALSE);
}
}
//+---------------------------------------------------------------------------
//
// Function: SetInfo
//
// Synopsis:
//
// Arguments: void
//
// Returns: HRESULT.
//
// Modifies:
//
// History: RamV Created
//----------------------------------------------------------------------------
STDMETHODIMP
CWinNTService::SetInfo(THIS)
{
HRESULT hr = S_OK;
DWORD dwServiceType;
DWORD dwStartType;
DWORD dwErrorControl;
LPTSTR pszPath = NULL;
LPTSTR pszLoadOrderGroup = NULL;
LPTSTR pszServiceStartName = NULL;
LPTSTR pszDependencies = NULL;
LPTSTR pszDisplayName = NULL;
SC_LOCK sclLock = NULL;
BOOL fRetval = FALSE;
LPQUERY_SERVICE_CONFIG lpqServiceConfig = NULL;
if (GetObjectState() == ADS_OBJECT_UNBOUND) {
hr = WinNTAddService();
BAIL_IF_ERROR(hr);
SetObjectState(ADS_OBJECT_BOUND);
}
hr = WinNTOpenService(SC_MANAGER_ALL_ACCESS,
SERVICE_ALL_ACCESS);
BAIL_IF_ERROR(hr);
hr = GetServiceConfigInfo(&lpqServiceConfig);
BAIL_IF_ERROR(hr);
hr = GetLPTSTRPropertyFromCache(
_pPropertyCache,
TEXT("Path"),
&pszPath
);
if(SUCCEEDED(hr)){
lpqServiceConfig->lpBinaryPathName = pszPath;
}
hr = GetLPTSTRPropertyFromCache(
_pPropertyCache,
TEXT("LoadOrderGroup"),
&pszLoadOrderGroup
);
if(SUCCEEDED(hr)){
lpqServiceConfig->lpLoadOrderGroup = pszLoadOrderGroup;
}
hr = GetNulledStringPropertyFromCache(
_pPropertyCache,
TEXT("Dependencies"),
&pszDependencies
);
if(SUCCEEDED(hr)){
lpqServiceConfig->lpDependencies = pszDependencies;
}
//
// Issue: Service Account Name property has been disabled from being a
// writeable property because ChangeServiceConfig AVs services.exe
// on the server machine when this property is changed
// RamV - Aug-11-96.
/*
hr = GetLPTSTRPropertyFromCache(
_pPropertyCache,
TEXT("ServiceAccountName"),
&pszServiceStartName
);
if(SUCCEEDED(hr)){
lpqServiceConfig->lpServiceStartName = pszServiceStartName;
}
*/
hr = GetLPTSTRPropertyFromCache(
_pPropertyCache,
TEXT("DisplayName"),
&pszDisplayName
);
if(SUCCEEDED(hr)){
lpqServiceConfig->lpDisplayName = pszDisplayName;
}
hr = GetDWORDPropertyFromCache(
_pPropertyCache,
TEXT("ServiceType"),
&dwServiceType
);
if(SUCCEEDED(hr)){
lpqServiceConfig->dwServiceType = dwServiceType;
}
hr = GetDWORDPropertyFromCache(
_pPropertyCache,
TEXT("StartType"),
&dwStartType
);
if(SUCCEEDED(hr)){
lpqServiceConfig->dwStartType = dwStartType;
}
hr = GetDWORDPropertyFromCache(
_pPropertyCache,
TEXT("ErrorControl"),
&dwErrorControl
);
if(SUCCEEDED(hr)){
lpqServiceConfig->dwErrorControl = dwErrorControl;
}
//
// set hr to S_OK. why? we dont care about the errors we hit so far
//
hr = S_OK;
//
// put a lock on the database corresponding to this service
//
sclLock = LockServiceDatabase(_schSCManager);
if(sclLock == NULL){
//
// Exit if database cannot be locked
//
hr = HRESULT_FROM_WIN32(GetLastError());
goto cleanup;
}
//
// change the service configuration. Pass in all the changed parameters.
// Since there is but one info level for services, use the
// internal values as parameters.
//
fRetval = ChangeServiceConfig(_schService,
lpqServiceConfig->dwServiceType,
lpqServiceConfig->dwStartType,
lpqServiceConfig->dwErrorControl,
lpqServiceConfig->lpBinaryPathName,
lpqServiceConfig->lpLoadOrderGroup,
NULL,
lpqServiceConfig->lpDependencies,
lpqServiceConfig->lpServiceStartName,
NULL,
lpqServiceConfig->lpDisplayName
);
if (fRetval == FALSE) {
hr = HRESULT_FROM_WIN32(GetLastError());
}
if(SUCCEEDED(hr))
_pPropertyCache->ClearModifiedFlags();
cleanup:
if(lpqServiceConfig){
FreeADsMem(lpqServiceConfig);
}
if(sclLock){
UnlockServiceDatabase(sclLock);
}
WinNTCloseService();
if(pszPath){
FreeADsStr(pszPath);
}
if(pszLoadOrderGroup){
FreeADsStr(pszLoadOrderGroup);
}
if(pszServiceStartName){
FreeADsStr(pszServiceStartName);
}
if(pszDependencies){
FreeADsStr(pszDependencies);
}
if(pszDisplayName){
FreeADsStr(pszDisplayName);
}
RRETURN_EXP_IF_ERR(hr);
}
//+---------------------------------------------------------------------------
//
// Function: GetInfo
//
// Synopsis: Currently implemented
//
// Arguments: void
//
// Returns: HRESULT.
//
// Modifies:
//
// History: 12/11/95 RamV Created
//
//----------------------------------------------------------------------------
STDMETHODIMP
CWinNTService::GetInfo(THIS)
{
RRETURN (GetInfo(1, TRUE));
}
STDMETHODIMP
CWinNTService::ImplicitGetInfo(THIS)
{
RRETURN (GetInfo(1, FALSE));
}
//+---------------------------------------------------------------------------
//
// Function: CWinNTService::GetInfo
//
// Synopsis: Binds to real Service as specified in _ServiceName and
// attempts to refresh the Service object from the real Service.
//
// Arguments: dwApiLevel (ignored), fExplicit (ignored)
//
// Returns: HRESULT.
//
// Modifies:
//
// History: 01/08/96 RamV Created
//
//----------------------------------------------------------------------------
STDMETHODIMP
CWinNTService::GetInfo(THIS_ DWORD dwApiLevel, BOOL fExplicit)
{
HRESULT hr;
LPQUERY_SERVICE_CONFIG pMem = NULL;
BYTE FastConfigInfo[256];
SERVICE_STATUS ssStatusInfo;
DWORD dwBufAllocated = 256;
DWORD dwBufNeeded;
DWORD dwLastError;
BOOL fRetval;
//
// GETTING NT SERVICE INFO
//
// Getting information about an NT service requires three calls.
// One to get configuration information, and one to get current
// status information, and one to get security information.
//
//
// Open the service
//
hr = WinNTOpenService(SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS,
GENERIC_READ );
if (FAILED(hr)) {
RRETURN_EXP_IF_ERR(hr);
}
//
// Query for Service Status first.
//
fRetval = QueryServiceStatus(_schService,
&ssStatusInfo );
if (fRetval == FALSE) {
hr = HRESULT_FROM_WIN32(GetLastError());
WinNTCloseService();
goto cleanup;
}
fRetval = QueryServiceConfig(_schService,
(LPQUERY_SERVICE_CONFIG)(&FastConfigInfo),
dwBufAllocated,
&dwBufNeeded
);
if (fRetval == FALSE) {
dwLastError = GetLastError();
switch (dwLastError) {
case ERROR_INSUFFICIENT_BUFFER:
//
// Allocate more memory and try again.
//
dwBufAllocated = dwBufNeeded;
pMem = (LPQUERY_SERVICE_CONFIG)AllocADsMem(dwBufAllocated);
if (pMem == NULL) {
hr = E_OUTOFMEMORY;
break;
}
fRetval = QueryServiceConfig(_schService,
pMem,
dwBufAllocated,
&dwBufNeeded
);
if (fRetval == FALSE) {
WinNTCloseService();
hr = HRESULT_FROM_WIN32(GetLastError());
break;
}
break;
default:
hr = HRESULT_FROM_WIN32(GetLastError());
break;
}
if(FAILED(hr)){
WinNTCloseService();
goto cleanup;
}
}
WinNTCloseService();
//
// clear all properties from cache first if explicit GetInfo
//
if (fExplicit) {
_pPropertyCache->flushpropcache();
}
if(pMem){
hr = UnMarshall(pMem, fExplicit);
BAIL_IF_ERROR(hr);
}else{
hr = UnMarshall((LPQUERY_SERVICE_CONFIG) FastConfigInfo, fExplicit);
BAIL_IF_ERROR(hr);
}
cleanup:
if(pMem)
FreeADsMem(pMem);
RRETURN_EXP_IF_ERR(hr);
}
STDMETHODIMP
CWinNTService::UnMarshall(THIS_ LPQUERY_SERVICE_CONFIG lpConfigInfo,
BOOL fExplicit)
{
DWORD dwADsServiceType;
DWORD dwADsStartType;
DWORD dwADsErrorControl;
HRESULT hr;
hr = SetLPTSTRPropertyInCache(_pPropertyCache,
TEXT("Path"),
lpConfigInfo->lpBinaryPathName,
fExplicit
);
hr = SetLPTSTRPropertyInCache(_pPropertyCache,
TEXT("LoadOrderGroup"),
lpConfigInfo->lpLoadOrderGroup,
fExplicit
);
hr = SetNulledStringPropertyInCache(_pPropertyCache,
TEXT("Dependencies"),
lpConfigInfo->lpDependencies,
fExplicit
);
hr = SetLPTSTRPropertyInCache(_pPropertyCache,
TEXT("ServiceAccountName"),
lpConfigInfo->lpServiceStartName,
fExplicit
);
hr = SetLPTSTRPropertyInCache(_pPropertyCache,
TEXT("DisplayName"),
lpConfigInfo->lpDisplayName,
fExplicit
);
//
// 0x133 is the bit mask for valid values of ADs ServiceTypes
//
dwADsServiceType = lpConfigInfo->dwServiceType & 0x133;
hr = SetDWORDPropertyInCache(_pPropertyCache,
TEXT("ServiceType"),
dwADsServiceType ,
fExplicit
);
hr = SetDWORDPropertyInCache(_pPropertyCache,
TEXT("StartType"),
lpConfigInfo->dwStartType,
fExplicit
);
hr = SetDWORDPropertyInCache(_pPropertyCache,
TEXT("ErrorControl"),
lpConfigInfo->dwErrorControl,
fExplicit
);
hr = SetLPTSTRPropertyInCache(
_pPropertyCache,
TEXT("Name"),
_Name,
fExplicit
);
RRETURN_EXP_IF_ERR(hr);
}
//
// helper function WinNTAddService
//
HRESULT
CWinNTService::WinNTAddService(void)
{
HRESULT hr = S_OK;
SC_HANDLE schService = NULL;
SC_HANDLE schSCManager = NULL;
TCHAR szServerName[MAX_PATH];
BOOL fRetval;
LPTSTR pszDisplayName = NULL;
LPTSTR pszPath = NULL;
LPTSTR pszLoadOrderGroup = NULL;
DWORD dwServiceType;
DWORD dwStartType;
DWORD dwErrorControl;
hr = GetServerFromPath(_ADsPath,szServerName);
BAIL_IF_ERROR(hr);
//
// open the SCM for this server
//
schSCManager = OpenSCManager(szServerName,
NULL,
SC_MANAGER_ALL_ACCESS);
if(schSCManager == NULL){
hr = HRESULT_FROM_WIN32(GetLastError());
goto cleanup;
}
hr = GetLPTSTRPropertyFromCache(
_pPropertyCache,
TEXT("DisplayName"),
&pszDisplayName
);
BAIL_IF_ERROR(hr);
hr = GetDWORDPropertyFromCache(
_pPropertyCache,
TEXT("ServiceType"),
&dwServiceType
);
BAIL_IF_ERROR(hr);
hr = GetDWORDPropertyFromCache(
_pPropertyCache,
TEXT("StartType"),
&dwStartType
);
BAIL_IF_ERROR(hr);
hr = GetDWORDPropertyFromCache(
_pPropertyCache,
TEXT("ErrorControl"),
&dwErrorControl
);
BAIL_IF_ERROR(hr);
hr = GetLPTSTRPropertyFromCache(
_pPropertyCache,
TEXT("Path"),
&pszPath
);
BAIL_IF_ERROR(hr);
schService = CreateService(schSCManager,
_pszServiceName,
pszDisplayName,
SERVICE_ALL_ACCESS,
dwServiceType,
dwStartType,
dwErrorControl,
pszPath,
NULL,
NULL,
NULL,
NULL,
NULL );
if(schService == NULL){
hr = HRESULT_FROM_WIN32(GetLastError());
goto cleanup;
}
cleanup:
if(schSCManager){
fRetval = CloseServiceHandle(schSCManager);
if(!fRetval && SUCCEEDED(hr)){
RRETURN(HRESULT_FROM_WIN32(GetLastError()));
}
}
if(schService){
fRetval = CloseServiceHandle(schService);
if(!fRetval && SUCCEEDED(hr)){
RRETURN(HRESULT_FROM_WIN32(GetLastError()));
}
}
if(pszDisplayName){
FreeADsStr(pszDisplayName);
}
if(pszPath){
FreeADsStr(pszPath);
}
if(pszLoadOrderGroup){
FreeADsStr(pszLoadOrderGroup);
}
RRETURN(hr);
}
STDMETHODIMP
CWinNTService::get_HostComputer(THIS_ BSTR FAR* retval)
{
HRESULT hr;
if(!retval){
RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
}
hr = ADsAllocString(_Parent, retval);
RRETURN_EXP_IF_ERR(hr);
}
STDMETHODIMP
CWinNTService::put_HostComputer(THIS_ BSTR bstrHostComputer)
{
RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED);
}
STDMETHODIMP
CWinNTService::get_DisplayName(THIS_ BSTR FAR* retval)
{
GET_PROPERTY_BSTR((IADsService *)this, DisplayName);
}
STDMETHODIMP
CWinNTService::put_DisplayName(THIS_ BSTR bstrDisplayName)
{
PUT_PROPERTY_BSTR((IADsService *)this, DisplayName);
}
STDMETHODIMP
CWinNTService::get_Version(THIS_ BSTR FAR* retval)
{
GET_PROPERTY_BSTR((IADsService *)this, Version);
}
STDMETHODIMP
CWinNTService::put_Version(THIS_ BSTR bstrVersion)
{
PUT_PROPERTY_BSTR((IADsService *)this, Version);
}
STDMETHODIMP
CWinNTService::get_ServiceType(THIS_ long FAR* retval)
{
GET_PROPERTY_LONG((IADsService *)this, ServiceType);
}
STDMETHODIMP
CWinNTService::put_ServiceType(THIS_ long lServiceType)
{
PUT_PROPERTY_LONG((IADsService *)this, ServiceType);
}
STDMETHODIMP
CWinNTService::get_StartType(THIS_ LONG FAR* retval)
{
GET_PROPERTY_LONG((IADsService *)this, StartType);
}
STDMETHODIMP
CWinNTService::put_StartType(THIS_ LONG lStartType)
{
PUT_PROPERTY_LONG((IADsService *)this, StartType);
}
STDMETHODIMP
CWinNTService::get_Path(THIS_ BSTR FAR* retval)
{
GET_PROPERTY_BSTR((IADsService *)this, Path);
}
STDMETHODIMP
CWinNTService::put_Path(THIS_ BSTR bstrPath)
{
PUT_PROPERTY_BSTR((IADsService *)this, Path);
}
STDMETHODIMP
CWinNTService::get_StartupParameters(THIS_ BSTR FAR* retval)
{
GET_PROPERTY_BSTR((IADsService *)this, StartupParameters);
}
STDMETHODIMP
CWinNTService::put_StartupParameters(THIS_ BSTR bstrStartupParameters) {
PUT_PROPERTY_BSTR((IADsService *)this, StartupParameters);
}
STDMETHODIMP
CWinNTService::get_ErrorControl(THIS_ LONG FAR* retval)
{
GET_PROPERTY_LONG((IADsService *)this, ErrorControl);
}
STDMETHODIMP
CWinNTService::put_ErrorControl(THIS_ LONG lErrorControl)
{
PUT_PROPERTY_LONG((IADsService *)this, ErrorControl);
}
STDMETHODIMP
CWinNTService::get_LoadOrderGroup(THIS_ BSTR FAR* retval)
{
GET_PROPERTY_BSTR((IADsService *)this, LoadOrderGroup);
}
STDMETHODIMP
CWinNTService::put_LoadOrderGroup(THIS_ BSTR bstrLoadOrderGroup)
{
PUT_PROPERTY_BSTR((IADsService *)this, LoadOrderGroup);
}
STDMETHODIMP
CWinNTService::get_ServiceAccountName(THIS_ BSTR FAR* retval)
{
GET_PROPERTY_BSTR((IADsService *)this, ServiceAccountName);
}
STDMETHODIMP
CWinNTService::put_ServiceAccountName(THIS_ BSTR bstrServiceAccountName)
{
RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED);
}
STDMETHODIMP
CWinNTService::get_ServiceAccountPath(THIS_ BSTR FAR* retval)
{
RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED);
}
STDMETHODIMP
CWinNTService::put_ServiceAccountPath(THIS_ BSTR bstrServiceAccountName)
{
RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED);
}
STDMETHODIMP
CWinNTService::get_Dependencies(THIS_ VARIANT FAR* retval)
{
GET_PROPERTY_VARIANT((IADsService *)this, Dependencies);
}
STDMETHODIMP
CWinNTService::put_Dependencies(THIS_ VARIANT vDependencies)
{
PUT_PROPERTY_VARIANT((IADsService *)this, Dependencies);
}
STDMETHODIMP
CWinNTService::SetPassword(THIS_ BSTR bstrNewPassword)
{
//
// This routine should merely change password. Even if any other
// properties are set in the configuration functional set then they
// will not be touched.
// Therefore we do a QueryServiceConfig and get all the configuration
// related information, merely change the password and send it back.
// For this reason, it is not possible to reuse GetInfo or SetInfo
// because they change service config properties.
//
BOOL fRetval;
LPQUERY_SERVICE_CONFIG pMem = NULL;
HRESULT hr;
hr = WinNTOpenService(SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS,
SERVICE_ALL_ACCESS);
BAIL_IF_ERROR(hr);
hr = GetServiceConfigInfo(&pMem);
BAIL_IF_ERROR(hr);
//
// just change the field corresponding to password.
//
fRetval = ChangeServiceConfig(_schService,
pMem->dwServiceType,
pMem->dwStartType,
pMem->dwErrorControl,
pMem->lpBinaryPathName,
pMem->lpLoadOrderGroup,
NULL,
pMem->lpDependencies,
pMem->lpServiceStartName,
(LPTSTR)bstrNewPassword,
pMem->lpDisplayName
);
if(!fRetval){
hr = HRESULT_FROM_WIN32(GetLastError());
goto cleanup;
}
cleanup:
if(pMem){
FreeADsMem(pMem);
}
WinNTCloseService();
RRETURN_EXP_IF_ERR(hr);
}
//+---------------------------------------------------------------------------
//
// Function: CWinNTService::Start
//
// Synopsis: Attempts to start the service specified in _bstrServiceName on
// the server named in _bstrPath.
//
// Arguments:
//
// Returns: HRESULT.
//
// Modifies:
//
// History: 01/04/96 RamV Created
//
// Notes:
//----------------------------------------------------------------------------
STDMETHODIMP
CWinNTService::Start(THIS)
{
HRESULT hr;
hr = WinNTControlService(WINNT_START_SERVICE);
RRETURN_EXP_IF_ERR(hr);
}
//+---------------------------------------------------------------------------
//
// Function: CWinNTService::Stop
//
// Synopsis: Attempts to stop the service specified in _bstrServiceName on
// the server named in _bstrPath.
//
// Arguments:
//
// Returns: HRESULT.
//
// Modifies:
//
// History: 01/04/96 RamV Created
//
//----------------------------------------------------------------------------
STDMETHODIMP
CWinNTService::Stop(THIS)
{
HRESULT hr;
hr = WinNTControlService(WINNT_STOP_SERVICE);
RRETURN_EXP_IF_ERR(hr);
}
//+---------------------------------------------------------------------------
//
// Function: CWinNTService::Pause
//
// Synopsis: Attempts to pause the service named _bstrServiceName on the
// server named in _bstrPath.
//
// Arguments:
//
// Returns: HRESULT.
//
// Modifies:
//
// History: 01-04-96 RamV Created
//
//----------------------------------------------------------------------------
STDMETHODIMP
CWinNTService::Pause(THIS)
{
HRESULT hr;
hr = WinNTControlService(WINNT_PAUSE_SERVICE);
RRETURN_EXP_IF_ERR(hr);
}
//+---------------------------------------------------------------------------
//
// Function: CWinNTService::Continue
//
// Synopsis: Attempts to "unpause" the service specified in _bstrServiceName
// on the server named in _bstrPath.
//
// Arguments:
//
// Returns: HRESULT.
//
// Modifies:
//
// History: 01/04/96 RamV Created
//
//----------------------------------------------------------------------------
STDMETHODIMP
CWinNTService::Continue(THIS)
{
HRESULT hr;
hr = WinNTControlService(WINNT_CONTINUE_SERVICE);
RRETURN_EXP_IF_ERR(hr);
}
//
// Helper Functions
//
HRESULT
CWinNTService::GetServiceConfigInfo(LPQUERY_SERVICE_CONFIG *ppMem)
{
//
//gets the service configuration information into ppMem
//
BOOL fRetval;
DWORD dwBufAllocated = 0;
DWORD dwBufNeeded = 0;
DWORD dwLastError;
HRESULT hr = S_OK;
ADsAssert(ppMem);
*ppMem = (LPQUERY_SERVICE_CONFIG)AllocADsMem(dwBufAllocated);
if (*ppMem == NULL){
hr = E_OUTOFMEMORY;
goto cleanup;
}
ADsAssert(_schService);
fRetval = QueryServiceConfig(_schService,
(LPQUERY_SERVICE_CONFIG)(*ppMem),
dwBufAllocated,
&dwBufNeeded);
if (fRetval == FALSE) {
dwLastError = GetLastError();
switch (dwLastError) {
case ERROR_INSUFFICIENT_BUFFER:
//
// Allocate more memory and try again.
//
FreeADsMem(*ppMem);
*ppMem = NULL;
dwBufAllocated = dwBufNeeded;
*ppMem = (LPQUERY_SERVICE_CONFIG)AllocADsMem(dwBufAllocated);
if (*ppMem == NULL) {
BAIL_IF_ERROR(hr = E_OUTOFMEMORY);
}
fRetval = QueryServiceConfig(_schService,
*ppMem,
dwBufAllocated,
&dwBufNeeded);
if (fRetval == FALSE) {
hr = HRESULT_FROM_WIN32(GetLastError());
break;
}
break;
default:
hr = HRESULT_FROM_WIN32(GetLastError());
break;
}
BAIL_IF_ERROR(hr);
}
if(*ppMem){
RRETURN(S_OK);
}
cleanup:
RRETURN(hr);
}
HRESULT
CWinNTService::WinNTControlService( DWORD dwControl)
{
//
// abstracts out the common code of Start,Stop,Pause and Resume
//
HRESULT hr =S_OK, hrclose=S_OK, hrcontrol=S_OK;
SERVICE_STATUS ssStatusInfo;
BOOL fRetval;
if(_fValidHandle){
//
// an open handle exists, blow it away
//
hrclose = WinNTCloseService();
BAIL_ON_FAILURE(hrclose);
_fValidHandle = FALSE;
}
hr = WinNTOpenService(SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS,
GENERIC_EXECUTE| SERVICE_INTERROGATE
);
BAIL_ON_FAILURE(hr);
_fValidHandle = TRUE;
switch(dwControl){
case WINNT_START_SERVICE:
fRetval = StartService(_schService,
0,
NULL );
if(!fRetval){
hrcontrol = HRESULT_FROM_WIN32(GetLastError());
goto error;
}
_dwOpPending = PENDING_START;
break;
case WINNT_STOP_SERVICE:
fRetval = ControlService(_schService,
SERVICE_CONTROL_STOP,
&ssStatusInfo);
if(!fRetval){
hrcontrol = HRESULT_FROM_WIN32(GetLastError());
goto error;
}
_dwOpPending = PENDING_STOP;
break;
case WINNT_PAUSE_SERVICE:
fRetval = ControlService(_schService,
SERVICE_CONTROL_PAUSE,
&ssStatusInfo);
if(!fRetval){
hrcontrol = HRESULT_FROM_WIN32(GetLastError());
goto error;
}
_dwOpPending = PENDING_PAUSE;
break;
case WINNT_CONTINUE_SERVICE:
fRetval = ControlService(_schService,
SERVICE_CONTROL_CONTINUE,
&ssStatusInfo);
if(!fRetval){
hrcontrol = HRESULT_FROM_WIN32(GetLastError());
goto error;
}
_dwOpPending = PENDING_CONTINUE;
break;
default:
hrcontrol = E_FAIL;
goto error;
}
_dwTimeStarted = GetTickCount();
_dwWaitHint = 10000; //10 seconds
_dwCheckPoint = 0;
RRETURN(S_OK);
error:
if(FAILED(hrcontrol)){
_fValidHandle = FALSE;
RRETURN(hrcontrol);
}
else if(FAILED(hrclose)){
RRETURN(hrclose);
}
else{
RRETURN(hr);
}
}
//+---------------------------------------------------------------------------
//
// Function: CWinNTService::WinNTOpenService
//
// Synopsis: Opens the Service Control Manager on the machine specified in
// _bstrPath, then opens the Service specified in _bstrServiceName.
// The handle to the SCM is placed in _schSCManager, and the
// handle to the service is placed in _schService.
//
// Arguments: [dwSCMDesiredAccess] -- type of SCM access needed
// [dwSvrDesiredAccess] -- type of Service access required
//
// Returns: HRESULT.
//
// Modifies:
//
// History: 03-17-95 t-skwan Created
// 01/04/96 RamV Modified
//
//----------------------------------------------------------------------------
HRESULT
CWinNTService::WinNTOpenService(
DWORD dwSCMDesiredAccess,
DWORD dwSvrDesiredAccess
)
{
HRESULT hr;
DWORD dwLastError;
//
// Open the Service Control Manager.
//
//
// OpenSCManager(
// LPCTSTR lpszMachineName,
// LPCTSTR lpszDatabaseName.
// DWORD fdwDesiredAccess)
//
_schSCManager = OpenSCManager(_pszServerName,
NULL,
dwSCMDesiredAccess);
if (_schSCManager == NULL) {
dwLastError = GetLastError();
hr = HRESULT_FROM_WIN32(dwLastError);
RRETURN(hr);
}
//
// Get a handle to the specified service.
//
_schService = OpenService(_schSCManager,
_pszServiceName,
dwSvrDesiredAccess);
if(_schService == NULL) {
hr = HRESULT_FROM_WIN32(GetLastError());
CloseServiceHandle(_schSCManager);
_schSCManager = NULL;
RRETURN(hr);
}
RRETURN(S_OK);
}
//+---------------------------------------------------------------------------
//
// Function: CWinNTService::WinNTCloseService
//
// Synopsis: Closes the Service handle and the Service Control Manager
// handle.
//
// Arguments:
//
// Returns: HRESULT.
//
// Modifies:
//
// History: 03-17-95 t-skwan Created
// 01/04/96 RamV Modified
//
//----------------------------------------------------------------------------
HRESULT
CWinNTService::WinNTCloseService()
{
BOOL fRetval = TRUE;
//
// Close the Service handle.
//
if(_schService){
fRetval = CloseServiceHandle(_schService);
_schService = NULL;
}
if (!fRetval) {
//
// Ack. What do we do if there is an error closing a service?
//
RRETURN(HRESULT_FROM_WIN32(GetLastError()));
}
//
// Close the Service Control Manager.
//
if(_schSCManager){
fRetval = CloseServiceHandle(_schSCManager);
_schSCManager = NULL;
}
if (!fRetval) {
//
// Ack. What do we do if there is an error closing an SCM?
//
RRETURN(HRESULT_FROM_WIN32(GetLastError()));
}
RRETURN(S_OK);
}
STDMETHODIMP
CWinNTService::get_Status(THIS_ long FAR* plStatusCode)
{
HRESULT hr = S_OK;
BOOL fRetval = FALSE, found = FALSE;
SERVICE_STATUS Status;
DWORD dwStatus = 0;
if(plStatusCode == NULL){
RRETURN_EXP_IF_ERR(E_POINTER);
}
*plStatusCode = -1; //-1 is an invalid code
if(!(_fValidHandle)){
//
// currently not waiting on any service
//
hr = WinNTOpenService(SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS,
GENERIC_EXECUTE|SERVICE_INTERROGATE);
BAIL_IF_ERROR(hr);
fRetval = ControlService(_schService,
SERVICE_CONTROL_INTERROGATE,
&Status);
if(!fRetval){
hr = HRESULT_FROM_WIN32(GetLastError());
if(hr == HRESULT_FROM_WIN32(ERROR_SERVICE_NOT_ACTIVE)){
dwStatus = SERVICE_STOPPED;
hr = S_OK;
}
goto cleanup;
}
dwStatus = Status.dwCurrentState;
hr = WinNTCloseService();
goto cleanup;
}
//
// if you are here
// you are waiting for a service to complete
//
//
// NOTE: QueryServiceStatus queries the SCM rather than
// the service directly so to get a more upto date answer
// we need to use control service with interrogate option
//
hr = WinNTOpenService(SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS,
GENERIC_EXECUTE|SERVICE_INTERROGATE);
BAIL_IF_ERROR(hr);
fRetval = ControlService(_schService,
SERVICE_CONTROL_INTERROGATE,
&Status);
if(!fRetval){
hr = HRESULT_FROM_WIN32(GetLastError());
if(hr == HRESULT_FROM_WIN32(ERROR_SERVICE_NOT_ACTIVE)){
dwStatus = SERVICE_STOPPED;
hr = S_OK;
}
goto cleanup;
}
hr = EvalPendingOperation(PENDING_START,
SERVICE_RUNNING,
SERVICE_START_PENDING,
&Status,
&dwStatus
);
BAIL_IF_ERROR(hr);
if(dwStatus != 0){
//
// the correct scenario was found
//
goto cleanup;
}
hr = EvalPendingOperation(PENDING_STOP,
SERVICE_STOPPED,
SERVICE_STOP_PENDING,
&Status,
&dwStatus
);
BAIL_IF_ERROR(hr);
if(dwStatus != 0){
//
// the correct scenario was found
//
goto cleanup;
}
hr = EvalPendingOperation(PENDING_PAUSE,
SERVICE_PAUSED,
SERVICE_PAUSE_PENDING,
&Status,
&dwStatus
);
BAIL_IF_ERROR(hr);
if(dwStatus != 0){
//
// the correct scenario was found
//
goto cleanup;
}
hr = EvalPendingOperation(PENDING_CONTINUE,
SERVICE_RUNNING,
SERVICE_CONTINUE_PENDING,
&Status,
&dwStatus
);
BAIL_IF_ERROR(hr);
ADsAssert(dwStatus != 0); //we must find the appropriate scenario
cleanup:
if(SUCCEEDED(hr)){
//
// instead of a conversion routine, we return WinNT Status Code
//
*plStatusCode = dwStatus;
}
RRETURN_EXP_IF_ERR(hr);
}
HRESULT
CWinNTService::EvalPendingOperation(
THIS_ DWORD dwOpPending,
DWORD dwStatusDone,
DWORD dwStatusPending,
LPSERVICE_STATUS pStatus,
DWORD *pdwRetval
)
{
DWORD dwCurrentStatus;
BOOL fRetval;
HRESULT hr =S_OK;
DWORD dwNow;
dwCurrentStatus = pStatus->dwCurrentState;
if(_dwOpPending == dwOpPending){
if(dwCurrentStatus == dwStatusDone){
//
//was pending, is now completed
//
_dwOpPending = NOTPENDING;
*pdwRetval = dwStatusDone;
hr = WinNTCloseService();
BAIL_ON_FAILURE(hr);
_fValidHandle = FALSE;
RRETURN(S_OK);
}
else if(dwCurrentStatus = dwStatusPending){
//
//see if progress has been made since the last time we checked
//
if(pStatus->dwCheckPoint !=_dwCheckPoint){
//
// progress was made
//
*pdwRetval = dwStatusPending;
_dwCheckPoint = pStatus->dwCheckPoint;
_dwWaitHint = pStatus->dwWaitHint;
_dwTimeStarted = GetTickCount();
RRETURN(S_OK);
}
dwNow = GetTickCount();
if(2*_dwWaitHint < TickCountDiff(dwNow,_dwTimeStarted)){
//
// you can still wait
//
*pdwRetval = dwStatusPending;
RRETURN(S_OK);
}
else{
//
// took too long without signs of progress
//
*pdwRetval = SERVICE_ERROR;
_dwOpPending = NOTPENDING;
hr = WinNTCloseService();
BAIL_ON_FAILURE(hr);
_fValidHandle = FALSE;
RRETURN(S_OK);
}
}
else{
//
// an operation is pending but we arent going anywhere
// recover gracefully
//
_dwOpPending = NOTPENDING;
hr = WinNTCloseService();
BAIL_ON_FAILURE(hr);
_fValidHandle = FALSE;
*pdwRetval = SERVICE_ERROR;
RRETURN(S_OK);
}
}
error:
RRETURN(hr);
}