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

  1. //---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1995
  5. //
  6. // File: cserv.cxx
  7. //
  8. // Contents: Contains methods for the following objects
  9. // CWinNTService,
  10. //
  11. // History: 12/11/95 ramv (Ram Viswanathan) Created.
  12. //
  13. //----------------------------------------------------------------------------
  14. #include "winnt.hxx"
  15. #pragma hdrstop
  16. #define INITGUID
  17. //
  18. // class CWinNTService methods
  19. //
  20. DEFINE_IDispatch_ExtMgr_Implementation(CWinNTService);
  21. DEFINE_IADsExtension_ExtMgr_Implementation(CWinNTService);
  22. DEFINE_IADs_TempImplementation(CWinNTService);
  23. DEFINE_IADs_PutGetImplementation(CWinNTService,ServiceClass,gdwServiceTableSize);
  24. DEFINE_IADsPropertyList_Implementation(CWinNTService, ServiceClass,gdwServiceTableSize)
  25. CWinNTService::CWinNTService()
  26. {
  27. _pDispMgr = NULL;
  28. _pExtMgr = NULL;
  29. _pPropertyCache = NULL;
  30. _pszServiceName = NULL;
  31. _pszServerName = NULL;
  32. _pszPath = NULL;
  33. _schSCManager = NULL;
  34. _schService = NULL;
  35. _dwWaitHint = 0;
  36. _dwCheckPoint = 0;
  37. _fValidHandle = FALSE;
  38. ENLIST_TRACKING(CWinNTService);
  39. }
  40. CWinNTService::~CWinNTService()
  41. {
  42. if(_fValidHandle){
  43. //
  44. // an open handle exists, blow it away
  45. //
  46. WinNTCloseService();
  47. _fValidHandle = FALSE;
  48. }
  49. if(_pszServiceName){
  50. FreeADsStr(_pszServiceName);
  51. }
  52. if(_pszServerName){
  53. FreeADsStr(_pszServerName);
  54. }
  55. if(_pszPath){
  56. FreeADsStr(_pszPath);
  57. }
  58. delete _pExtMgr; // created last, destroyed first
  59. delete _pDispMgr;
  60. delete _pPropertyCache;
  61. return;
  62. }
  63. //+---------------------------------------------------------------------------
  64. //
  65. // Function: CWinNTService::Create
  66. //
  67. // Synopsis: Static function used to create a Service object. This
  68. // will be called by BindToObject
  69. //
  70. // Arguments: [ppWinNTService] -- Ptr to a ptr to a new Service object.
  71. //
  72. // Returns: HRESULT.
  73. //
  74. // Modifies:
  75. //
  76. // History: 12-11-95 RamV Created.
  77. //
  78. //----------------------------------------------------------------------------
  79. HRESULT
  80. CWinNTService::Create(LPTSTR pszADsParent,
  81. LPTSTR pszDomainName,
  82. LPTSTR pszServerName,
  83. LPTSTR pszServiceName,
  84. DWORD dwObjectState,
  85. REFIID riid,
  86. CWinNTCredentials& Credentials,
  87. LPVOID * ppvoid
  88. )
  89. {
  90. CWinNTService FAR * pCWinNTService = NULL;
  91. HRESULT hr;
  92. //
  93. // Create the Service Object
  94. //
  95. hr = AllocateServiceObject(pszServerName,
  96. pszServiceName,
  97. &pCWinNTService);
  98. BAIL_ON_FAILURE(hr);
  99. ADsAssert(pCWinNTService->_pDispMgr);
  100. hr = pCWinNTService->InitializeCoreObject(pszADsParent,
  101. pszServiceName,
  102. SERVICE_CLASS_NAME,
  103. SERVICE_SCHEMA_NAME,
  104. CLSID_WinNTService,
  105. dwObjectState);
  106. BAIL_ON_FAILURE(hr);
  107. hr = SetLPTSTRPropertyInCache(pCWinNTService->_pPropertyCache,
  108. TEXT("HostComputer"),
  109. pCWinNTService->_Parent,
  110. TRUE
  111. );
  112. BAIL_ON_FAILURE(hr);
  113. pCWinNTService->_Credentials = Credentials;
  114. hr = pCWinNTService->_Credentials.RefServer(pszServerName);
  115. BAIL_ON_FAILURE(hr);
  116. //
  117. // Load ext mgr and extensions
  118. //
  119. hr = ADSILoadExtensionManager(
  120. SERVICE_CLASS_NAME,
  121. (IADsService *) pCWinNTService,
  122. pCWinNTService->_pDispMgr,
  123. Credentials,
  124. &pCWinNTService->_pExtMgr
  125. );
  126. BAIL_ON_FAILURE(hr);
  127. ADsAssert(pCWinNTService->_pExtMgr);
  128. // check if the call is from UMI
  129. if(Credentials.GetFlags() & ADS_AUTH_RESERVED) {
  130. //
  131. // we do not pass riid to InitUmiObject below. This is because UMI object
  132. // does not support IDispatch. There are several places in ADSI code where
  133. // riid passed into this function is defaulted to IID_IDispatch -
  134. // IADsContainer::Create for example. To handle these cases, we always
  135. // request IID_IUnknown from the UMI object. Subsequent code within UMI
  136. // will QI for the appropriate interface.
  137. //
  138. if(3 == pCWinNTService->_dwNumComponents) {
  139. pCWinNTService->_CompClasses[0] = L"Domain";
  140. pCWinNTService->_CompClasses[1] = L"Computer";
  141. pCWinNTService->_CompClasses[2] = L"Service";
  142. }
  143. else if(2 == pCWinNTService->_dwNumComponents) {
  144. // no workstation services
  145. pCWinNTService->_CompClasses[0] = L"Computer";
  146. pCWinNTService->_CompClasses[1] = L"Service";
  147. }
  148. else
  149. BAIL_ON_FAILURE(hr = UMI_E_FAIL);
  150. hr = pCWinNTService->InitUmiObject(
  151. pCWinNTService->_Credentials,
  152. ServiceClass,
  153. gdwServiceTableSize,
  154. pCWinNTService->_pPropertyCache,
  155. (IUnknown *)(INonDelegatingUnknown *) pCWinNTService,
  156. pCWinNTService->_pExtMgr,
  157. IID_IUnknown,
  158. ppvoid
  159. );
  160. BAIL_ON_FAILURE(hr);
  161. //
  162. // UMI object was created and the interface was obtained successfully.
  163. // UMI object now has a reference to the inner unknown of IADs, since
  164. // the call to Release() below is not going to be made in this case.
  165. //
  166. RRETURN(hr);
  167. }
  168. hr = pCWinNTService->QueryInterface(riid, (void **)ppvoid);
  169. BAIL_ON_FAILURE(hr);
  170. pCWinNTService->Release();
  171. RRETURN(hr);
  172. error:
  173. delete pCWinNTService;
  174. RRETURN_EXP_IF_ERR(hr);
  175. }
  176. HRESULT
  177. CWinNTService::AllocateServiceObject(
  178. LPTSTR pszServerName,
  179. LPTSTR pszServiceName,
  180. CWinNTService ** ppService
  181. )
  182. {
  183. CWinNTService FAR * pService = NULL;
  184. HRESULT hr = S_OK;
  185. pService = new CWinNTService();
  186. if (pService == NULL) {
  187. hr = E_OUTOFMEMORY;
  188. }
  189. BAIL_ON_FAILURE(hr);
  190. pService->_pDispMgr = new CAggregatorDispMgr;
  191. if (pService->_pDispMgr == NULL) {
  192. hr = E_OUTOFMEMORY;
  193. }
  194. BAIL_ON_FAILURE(hr);
  195. pService->_pszServerName =
  196. AllocADsStr(pszServerName);
  197. if(!(pService->_pszServerName)){
  198. hr = E_OUTOFMEMORY;
  199. goto error;
  200. }
  201. pService->_pszServiceName =
  202. AllocADsStr(pszServiceName);
  203. if(!(pService->_pszServiceName)){
  204. hr = E_OUTOFMEMORY;
  205. goto error;
  206. }
  207. hr = LoadTypeInfoEntry(pService->_pDispMgr,
  208. LIBID_ADs,
  209. IID_IADsService,
  210. (IADsService *)pService,
  211. DISPID_REGULAR
  212. );
  213. BAIL_ON_FAILURE(hr);
  214. hr = LoadTypeInfoEntry(pService->_pDispMgr,
  215. LIBID_ADs,
  216. IID_IADsServiceOperations,
  217. (IADsServiceOperations *)pService,
  218. DISPID_REGULAR
  219. );
  220. BAIL_ON_FAILURE(hr);
  221. hr = CPropertyCache::createpropertycache(
  222. ServiceClass,
  223. gdwServiceTableSize,
  224. (CCoreADsObject *)pService,
  225. &(pService->_pPropertyCache)
  226. );
  227. BAIL_ON_FAILURE(hr);
  228. (pService->_pDispMgr)->RegisterPropertyCache(
  229. pService->_pPropertyCache
  230. );
  231. *ppService = pService;
  232. RRETURN(hr);
  233. error:
  234. //
  235. // direct memeber assignement assignement at pt of creation, so
  236. // do NOT delete _pPropertyCache or _pDisMgr here to avoid attempt
  237. // of deletion again in pPrintJob destructor and AV
  238. //
  239. delete pService;
  240. RRETURN(hr);
  241. }
  242. /* IUnknown methods for service object */
  243. //----------------------------------------------------------------------------
  244. // Function: QueryInterface
  245. //
  246. // Synopsis: If this object is aggregated within another object, then
  247. // all calls will delegate to the outer object. Otherwise, the
  248. // non-delegating QI is called
  249. //
  250. // Arguments:
  251. //
  252. // iid interface requested
  253. // ppInterface Returns pointer to interface requested. NULL if interface
  254. // is not supported.
  255. //
  256. // Returns: S_OK on success. Error code otherwise.
  257. //
  258. // Modifies: *ppInterface to return interface pointer
  259. //
  260. //----------------------------------------------------------------------------
  261. STDMETHODIMP CWinNTService::QueryInterface(
  262. REFIID iid,
  263. LPVOID *ppInterface
  264. )
  265. {
  266. if(_pUnkOuter != NULL)
  267. RRETURN(_pUnkOuter->QueryInterface(
  268. iid,
  269. ppInterface
  270. ));
  271. RRETURN(NonDelegatingQueryInterface(
  272. iid,
  273. ppInterface
  274. ));
  275. }
  276. //----------------------------------------------------------------------------
  277. // Function: AddRef
  278. //
  279. // Synopsis: IUnknown::AddRef. If this object is aggregated within
  280. // another, all calls will delegate to the outer object.
  281. // Otherwise, the non-delegating AddRef is called
  282. //
  283. // Arguments:
  284. //
  285. // None
  286. //
  287. // Returns: New reference count
  288. //
  289. // Modifies: Nothing
  290. //
  291. //----------------------------------------------------------------------------
  292. STDMETHODIMP_(ULONG) CWinNTService::AddRef(void)
  293. {
  294. if(_pUnkOuter != NULL)
  295. RRETURN(_pUnkOuter->AddRef());
  296. RRETURN(NonDelegatingAddRef());
  297. }
  298. //----------------------------------------------------------------------------
  299. // Function: Release
  300. //
  301. // Synopsis: IUnknown::Release. If this object is aggregated within
  302. // another, all calls will delegate to the outer object.
  303. // Otherwise, the non-delegating Release is called
  304. //
  305. // Arguments:
  306. //
  307. // None
  308. //
  309. // Returns: New reference count
  310. //
  311. // Modifies: Nothing
  312. //
  313. //----------------------------------------------------------------------------
  314. STDMETHODIMP_(ULONG) CWinNTService::Release(void)
  315. {
  316. if(_pUnkOuter != NULL)
  317. RRETURN(_pUnkOuter->Release());
  318. RRETURN(NonDelegatingRelease());
  319. }
  320. //----------------------------------------------------------------------------
  321. STDMETHODIMP
  322. CWinNTService::NonDelegatingQueryInterface(REFIID riid, LPVOID FAR* ppvObj)
  323. {
  324. HRESULT hr = S_OK;
  325. if(!ppvObj){
  326. RRETURN(E_POINTER);
  327. }
  328. if (IsEqualIID(riid, IID_IUnknown))
  329. {
  330. *ppvObj = (IADsService *)this;
  331. }
  332. else if (IsEqualIID(riid, IID_IDispatch))
  333. {
  334. *ppvObj = (IADsService *)this;
  335. }
  336. else if (IsEqualIID(riid, IID_ISupportErrorInfo))
  337. {
  338. *ppvObj = (ISupportErrorInfo FAR *)this;
  339. }
  340. else if (IsEqualIID(riid, IID_IADsPropertyList))
  341. {
  342. *ppvObj = (IADsPropertyList *)this;
  343. }
  344. else if (IsEqualIID(riid, IID_IADs))
  345. {
  346. *ppvObj = (IADsService FAR *) this;
  347. }
  348. else if (IsEqualIID(riid, IID_IADsService))
  349. {
  350. *ppvObj = (IADsService FAR *) this;
  351. }
  352. else if (IsEqualIID(riid, IID_IADsServiceOperations))
  353. {
  354. *ppvObj = (IADsServiceOperations FAR *) this;
  355. }
  356. else if( (_pDispatch != NULL) &&
  357. IsEqualIID(riid, IID_IADsExtension) )
  358. {
  359. *ppvObj = (IADsExtension *) this;
  360. }
  361. else if (_pExtMgr)
  362. {
  363. RRETURN( _pExtMgr->QueryInterface(riid, ppvObj));
  364. }
  365. else
  366. {
  367. *ppvObj = NULL;
  368. RRETURN(E_NOINTERFACE);
  369. }
  370. ((LPUNKNOWN)*ppvObj)->AddRef();
  371. RRETURN(S_OK);
  372. }
  373. /* ISupportErrorInfo method */
  374. STDMETHODIMP
  375. CWinNTService::InterfaceSupportsErrorInfo(
  376. THIS_ REFIID riid
  377. )
  378. {
  379. if (IsEqualIID(riid, IID_IADs) ||
  380. IsEqualIID(riid, IID_IADsService) ||
  381. IsEqualIID(riid, IID_IADsServiceOperations) ||
  382. IsEqualIID(riid, IID_IADsPropertyList)) {
  383. RRETURN(S_OK);
  384. } else {
  385. RRETURN(S_FALSE);
  386. }
  387. }
  388. //+---------------------------------------------------------------------------
  389. //
  390. // Function: SetInfo
  391. //
  392. // Synopsis:
  393. //
  394. // Arguments: void
  395. //
  396. // Returns: HRESULT.
  397. //
  398. // Modifies:
  399. //
  400. // History: RamV Created
  401. //----------------------------------------------------------------------------
  402. STDMETHODIMP
  403. CWinNTService::SetInfo(THIS)
  404. {
  405. HRESULT hr = S_OK;
  406. DWORD dwServiceType;
  407. DWORD dwStartType;
  408. DWORD dwErrorControl;
  409. LPTSTR pszPath = NULL;
  410. LPTSTR pszLoadOrderGroup = NULL;
  411. LPTSTR pszServiceStartName = NULL;
  412. LPTSTR pszDependencies = NULL;
  413. LPTSTR pszDisplayName = NULL;
  414. SC_LOCK sclLock = NULL;
  415. BOOL fRetval = FALSE;
  416. LPQUERY_SERVICE_CONFIG lpqServiceConfig = NULL;
  417. if (GetObjectState() == ADS_OBJECT_UNBOUND) {
  418. hr = WinNTAddService();
  419. BAIL_IF_ERROR(hr);
  420. SetObjectState(ADS_OBJECT_BOUND);
  421. }
  422. hr = WinNTOpenService(SC_MANAGER_ALL_ACCESS,
  423. SERVICE_ALL_ACCESS);
  424. BAIL_IF_ERROR(hr);
  425. hr = GetServiceConfigInfo(&lpqServiceConfig);
  426. BAIL_IF_ERROR(hr);
  427. hr = GetLPTSTRPropertyFromCache(
  428. _pPropertyCache,
  429. TEXT("Path"),
  430. &pszPath
  431. );
  432. if(SUCCEEDED(hr)){
  433. lpqServiceConfig->lpBinaryPathName = pszPath;
  434. }
  435. hr = GetLPTSTRPropertyFromCache(
  436. _pPropertyCache,
  437. TEXT("LoadOrderGroup"),
  438. &pszLoadOrderGroup
  439. );
  440. if(SUCCEEDED(hr)){
  441. lpqServiceConfig->lpLoadOrderGroup = pszLoadOrderGroup;
  442. }
  443. hr = GetNulledStringPropertyFromCache(
  444. _pPropertyCache,
  445. TEXT("Dependencies"),
  446. &pszDependencies
  447. );
  448. if(SUCCEEDED(hr)){
  449. lpqServiceConfig->lpDependencies = pszDependencies;
  450. }
  451. //
  452. // Issue: Service Account Name property has been disabled from being a
  453. // writeable property because ChangeServiceConfig AVs services.exe
  454. // on the server machine when this property is changed
  455. // RamV - Aug-11-96.
  456. /*
  457. hr = GetLPTSTRPropertyFromCache(
  458. _pPropertyCache,
  459. TEXT("ServiceAccountName"),
  460. &pszServiceStartName
  461. );
  462. if(SUCCEEDED(hr)){
  463. lpqServiceConfig->lpServiceStartName = pszServiceStartName;
  464. }
  465. */
  466. hr = GetLPTSTRPropertyFromCache(
  467. _pPropertyCache,
  468. TEXT("DisplayName"),
  469. &pszDisplayName
  470. );
  471. if(SUCCEEDED(hr)){
  472. lpqServiceConfig->lpDisplayName = pszDisplayName;
  473. }
  474. hr = GetDWORDPropertyFromCache(
  475. _pPropertyCache,
  476. TEXT("ServiceType"),
  477. &dwServiceType
  478. );
  479. if(SUCCEEDED(hr)){
  480. lpqServiceConfig->dwServiceType = dwServiceType;
  481. }
  482. hr = GetDWORDPropertyFromCache(
  483. _pPropertyCache,
  484. TEXT("StartType"),
  485. &dwStartType
  486. );
  487. if(SUCCEEDED(hr)){
  488. lpqServiceConfig->dwStartType = dwStartType;
  489. }
  490. hr = GetDWORDPropertyFromCache(
  491. _pPropertyCache,
  492. TEXT("ErrorControl"),
  493. &dwErrorControl
  494. );
  495. if(SUCCEEDED(hr)){
  496. lpqServiceConfig->dwErrorControl = dwErrorControl;
  497. }
  498. //
  499. // set hr to S_OK. why? we dont care about the errors we hit so far
  500. //
  501. hr = S_OK;
  502. //
  503. // put a lock on the database corresponding to this service
  504. //
  505. sclLock = LockServiceDatabase(_schSCManager);
  506. if(sclLock == NULL){
  507. //
  508. // Exit if database cannot be locked
  509. //
  510. hr = HRESULT_FROM_WIN32(GetLastError());
  511. goto cleanup;
  512. }
  513. //
  514. // change the service configuration. Pass in all the changed parameters.
  515. // Since there is but one info level for services, use the
  516. // internal values as parameters.
  517. //
  518. fRetval = ChangeServiceConfig(_schService,
  519. lpqServiceConfig->dwServiceType,
  520. lpqServiceConfig->dwStartType,
  521. lpqServiceConfig->dwErrorControl,
  522. lpqServiceConfig->lpBinaryPathName,
  523. lpqServiceConfig->lpLoadOrderGroup,
  524. NULL,
  525. lpqServiceConfig->lpDependencies,
  526. lpqServiceConfig->lpServiceStartName,
  527. NULL,
  528. lpqServiceConfig->lpDisplayName
  529. );
  530. if (fRetval == FALSE) {
  531. hr = HRESULT_FROM_WIN32(GetLastError());
  532. }
  533. if(SUCCEEDED(hr))
  534. _pPropertyCache->ClearModifiedFlags();
  535. cleanup:
  536. if(lpqServiceConfig){
  537. FreeADsMem(lpqServiceConfig);
  538. }
  539. if(sclLock){
  540. UnlockServiceDatabase(sclLock);
  541. }
  542. WinNTCloseService();
  543. if(pszPath){
  544. FreeADsStr(pszPath);
  545. }
  546. if(pszLoadOrderGroup){
  547. FreeADsStr(pszLoadOrderGroup);
  548. }
  549. if(pszServiceStartName){
  550. FreeADsStr(pszServiceStartName);
  551. }
  552. if(pszDependencies){
  553. FreeADsStr(pszDependencies);
  554. }
  555. if(pszDisplayName){
  556. FreeADsStr(pszDisplayName);
  557. }
  558. RRETURN_EXP_IF_ERR(hr);
  559. }
  560. //+---------------------------------------------------------------------------
  561. //
  562. // Function: GetInfo
  563. //
  564. // Synopsis: Currently implemented
  565. //
  566. // Arguments: void
  567. //
  568. // Returns: HRESULT.
  569. //
  570. // Modifies:
  571. //
  572. // History: 12/11/95 RamV Created
  573. //
  574. //----------------------------------------------------------------------------
  575. STDMETHODIMP
  576. CWinNTService::GetInfo(THIS)
  577. {
  578. RRETURN (GetInfo(1, TRUE));
  579. }
  580. STDMETHODIMP
  581. CWinNTService::ImplicitGetInfo(THIS)
  582. {
  583. RRETURN (GetInfo(1, FALSE));
  584. }
  585. //+---------------------------------------------------------------------------
  586. //
  587. // Function: CWinNTService::GetInfo
  588. //
  589. // Synopsis: Binds to real Service as specified in _ServiceName and
  590. // attempts to refresh the Service object from the real Service.
  591. //
  592. // Arguments: dwApiLevel (ignored), fExplicit (ignored)
  593. //
  594. // Returns: HRESULT.
  595. //
  596. // Modifies:
  597. //
  598. // History: 01/08/96 RamV Created
  599. //
  600. //----------------------------------------------------------------------------
  601. STDMETHODIMP
  602. CWinNTService::GetInfo(THIS_ DWORD dwApiLevel, BOOL fExplicit)
  603. {
  604. HRESULT hr;
  605. LPQUERY_SERVICE_CONFIG pMem = NULL;
  606. BYTE FastConfigInfo[256];
  607. SERVICE_STATUS ssStatusInfo;
  608. DWORD dwBufAllocated = 256;
  609. DWORD dwBufNeeded;
  610. DWORD dwLastError;
  611. BOOL fRetval;
  612. //
  613. // GETTING NT SERVICE INFO
  614. //
  615. // Getting information about an NT service requires three calls.
  616. // One to get configuration information, and one to get current
  617. // status information, and one to get security information.
  618. //
  619. //
  620. // Open the service
  621. //
  622. hr = WinNTOpenService(SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS,
  623. GENERIC_READ );
  624. if (FAILED(hr)) {
  625. RRETURN_EXP_IF_ERR(hr);
  626. }
  627. //
  628. // Query for Service Status first.
  629. //
  630. fRetval = QueryServiceStatus(_schService,
  631. &ssStatusInfo );
  632. if (fRetval == FALSE) {
  633. hr = HRESULT_FROM_WIN32(GetLastError());
  634. WinNTCloseService();
  635. goto cleanup;
  636. }
  637. fRetval = QueryServiceConfig(_schService,
  638. (LPQUERY_SERVICE_CONFIG)(&FastConfigInfo),
  639. dwBufAllocated,
  640. &dwBufNeeded
  641. );
  642. if (fRetval == FALSE) {
  643. dwLastError = GetLastError();
  644. switch (dwLastError) {
  645. case ERROR_INSUFFICIENT_BUFFER:
  646. //
  647. // Allocate more memory and try again.
  648. //
  649. dwBufAllocated = dwBufNeeded;
  650. pMem = (LPQUERY_SERVICE_CONFIG)AllocADsMem(dwBufAllocated);
  651. if (pMem == NULL) {
  652. hr = E_OUTOFMEMORY;
  653. break;
  654. }
  655. fRetval = QueryServiceConfig(_schService,
  656. pMem,
  657. dwBufAllocated,
  658. &dwBufNeeded
  659. );
  660. if (fRetval == FALSE) {
  661. WinNTCloseService();
  662. hr = HRESULT_FROM_WIN32(GetLastError());
  663. break;
  664. }
  665. break;
  666. default:
  667. hr = HRESULT_FROM_WIN32(GetLastError());
  668. break;
  669. }
  670. if(FAILED(hr)){
  671. WinNTCloseService();
  672. goto cleanup;
  673. }
  674. }
  675. WinNTCloseService();
  676. //
  677. // clear all properties from cache first if explicit GetInfo
  678. //
  679. if (fExplicit) {
  680. _pPropertyCache->flushpropcache();
  681. }
  682. if(pMem){
  683. hr = UnMarshall(pMem, fExplicit);
  684. BAIL_IF_ERROR(hr);
  685. }else{
  686. hr = UnMarshall((LPQUERY_SERVICE_CONFIG) FastConfigInfo, fExplicit);
  687. BAIL_IF_ERROR(hr);
  688. }
  689. cleanup:
  690. if(pMem)
  691. FreeADsMem(pMem);
  692. RRETURN_EXP_IF_ERR(hr);
  693. }
  694. STDMETHODIMP
  695. CWinNTService::UnMarshall(THIS_ LPQUERY_SERVICE_CONFIG lpConfigInfo,
  696. BOOL fExplicit)
  697. {
  698. DWORD dwADsServiceType;
  699. DWORD dwADsStartType;
  700. DWORD dwADsErrorControl;
  701. HRESULT hr;
  702. hr = SetLPTSTRPropertyInCache(_pPropertyCache,
  703. TEXT("Path"),
  704. lpConfigInfo->lpBinaryPathName,
  705. fExplicit
  706. );
  707. hr = SetLPTSTRPropertyInCache(_pPropertyCache,
  708. TEXT("LoadOrderGroup"),
  709. lpConfigInfo->lpLoadOrderGroup,
  710. fExplicit
  711. );
  712. hr = SetNulledStringPropertyInCache(_pPropertyCache,
  713. TEXT("Dependencies"),
  714. lpConfigInfo->lpDependencies,
  715. fExplicit
  716. );
  717. hr = SetLPTSTRPropertyInCache(_pPropertyCache,
  718. TEXT("ServiceAccountName"),
  719. lpConfigInfo->lpServiceStartName,
  720. fExplicit
  721. );
  722. hr = SetLPTSTRPropertyInCache(_pPropertyCache,
  723. TEXT("DisplayName"),
  724. lpConfigInfo->lpDisplayName,
  725. fExplicit
  726. );
  727. //
  728. // 0x133 is the bit mask for valid values of ADs ServiceTypes
  729. //
  730. dwADsServiceType = lpConfigInfo->dwServiceType & 0x133;
  731. hr = SetDWORDPropertyInCache(_pPropertyCache,
  732. TEXT("ServiceType"),
  733. dwADsServiceType ,
  734. fExplicit
  735. );
  736. hr = SetDWORDPropertyInCache(_pPropertyCache,
  737. TEXT("StartType"),
  738. lpConfigInfo->dwStartType,
  739. fExplicit
  740. );
  741. hr = SetDWORDPropertyInCache(_pPropertyCache,
  742. TEXT("ErrorControl"),
  743. lpConfigInfo->dwErrorControl,
  744. fExplicit
  745. );
  746. hr = SetLPTSTRPropertyInCache(
  747. _pPropertyCache,
  748. TEXT("Name"),
  749. _Name,
  750. fExplicit
  751. );
  752. RRETURN_EXP_IF_ERR(hr);
  753. }
  754. //
  755. // helper function WinNTAddService
  756. //
  757. HRESULT
  758. CWinNTService::WinNTAddService(void)
  759. {
  760. HRESULT hr = S_OK;
  761. SC_HANDLE schService = NULL;
  762. SC_HANDLE schSCManager = NULL;
  763. TCHAR szServerName[MAX_PATH];
  764. BOOL fRetval;
  765. LPTSTR pszDisplayName = NULL;
  766. LPTSTR pszPath = NULL;
  767. LPTSTR pszLoadOrderGroup = NULL;
  768. DWORD dwServiceType;
  769. DWORD dwStartType;
  770. DWORD dwErrorControl;
  771. hr = GetServerFromPath(_ADsPath,szServerName);
  772. BAIL_IF_ERROR(hr);
  773. //
  774. // open the SCM for this server
  775. //
  776. schSCManager = OpenSCManager(szServerName,
  777. NULL,
  778. SC_MANAGER_ALL_ACCESS);
  779. if(schSCManager == NULL){
  780. hr = HRESULT_FROM_WIN32(GetLastError());
  781. goto cleanup;
  782. }
  783. hr = GetLPTSTRPropertyFromCache(
  784. _pPropertyCache,
  785. TEXT("DisplayName"),
  786. &pszDisplayName
  787. );
  788. BAIL_IF_ERROR(hr);
  789. hr = GetDWORDPropertyFromCache(
  790. _pPropertyCache,
  791. TEXT("ServiceType"),
  792. &dwServiceType
  793. );
  794. BAIL_IF_ERROR(hr);
  795. hr = GetDWORDPropertyFromCache(
  796. _pPropertyCache,
  797. TEXT("StartType"),
  798. &dwStartType
  799. );
  800. BAIL_IF_ERROR(hr);
  801. hr = GetDWORDPropertyFromCache(
  802. _pPropertyCache,
  803. TEXT("ErrorControl"),
  804. &dwErrorControl
  805. );
  806. BAIL_IF_ERROR(hr);
  807. hr = GetLPTSTRPropertyFromCache(
  808. _pPropertyCache,
  809. TEXT("Path"),
  810. &pszPath
  811. );
  812. BAIL_IF_ERROR(hr);
  813. schService = CreateService(schSCManager,
  814. _pszServiceName,
  815. pszDisplayName,
  816. SERVICE_ALL_ACCESS,
  817. dwServiceType,
  818. dwStartType,
  819. dwErrorControl,
  820. pszPath,
  821. NULL,
  822. NULL,
  823. NULL,
  824. NULL,
  825. NULL );
  826. if(schService == NULL){
  827. hr = HRESULT_FROM_WIN32(GetLastError());
  828. goto cleanup;
  829. }
  830. cleanup:
  831. if(schSCManager){
  832. fRetval = CloseServiceHandle(schSCManager);
  833. if(!fRetval && SUCCEEDED(hr)){
  834. RRETURN(HRESULT_FROM_WIN32(GetLastError()));
  835. }
  836. }
  837. if(schService){
  838. fRetval = CloseServiceHandle(schService);
  839. if(!fRetval && SUCCEEDED(hr)){
  840. RRETURN(HRESULT_FROM_WIN32(GetLastError()));
  841. }
  842. }
  843. if(pszDisplayName){
  844. FreeADsStr(pszDisplayName);
  845. }
  846. if(pszPath){
  847. FreeADsStr(pszPath);
  848. }
  849. if(pszLoadOrderGroup){
  850. FreeADsStr(pszLoadOrderGroup);
  851. }
  852. RRETURN(hr);
  853. }
  854. STDMETHODIMP
  855. CWinNTService::get_HostComputer(THIS_ BSTR FAR* retval)
  856. {
  857. HRESULT hr;
  858. if(!retval){
  859. RRETURN_EXP_IF_ERR(E_ADS_BAD_PARAMETER);
  860. }
  861. hr = ADsAllocString(_Parent, retval);
  862. RRETURN_EXP_IF_ERR(hr);
  863. }
  864. STDMETHODIMP
  865. CWinNTService::put_HostComputer(THIS_ BSTR bstrHostComputer)
  866. {
  867. RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED);
  868. }
  869. STDMETHODIMP
  870. CWinNTService::get_DisplayName(THIS_ BSTR FAR* retval)
  871. {
  872. GET_PROPERTY_BSTR((IADsService *)this, DisplayName);
  873. }
  874. STDMETHODIMP
  875. CWinNTService::put_DisplayName(THIS_ BSTR bstrDisplayName)
  876. {
  877. PUT_PROPERTY_BSTR((IADsService *)this, DisplayName);
  878. }
  879. STDMETHODIMP
  880. CWinNTService::get_Version(THIS_ BSTR FAR* retval)
  881. {
  882. GET_PROPERTY_BSTR((IADsService *)this, Version);
  883. }
  884. STDMETHODIMP
  885. CWinNTService::put_Version(THIS_ BSTR bstrVersion)
  886. {
  887. PUT_PROPERTY_BSTR((IADsService *)this, Version);
  888. }
  889. STDMETHODIMP
  890. CWinNTService::get_ServiceType(THIS_ long FAR* retval)
  891. {
  892. GET_PROPERTY_LONG((IADsService *)this, ServiceType);
  893. }
  894. STDMETHODIMP
  895. CWinNTService::put_ServiceType(THIS_ long lServiceType)
  896. {
  897. PUT_PROPERTY_LONG((IADsService *)this, ServiceType);
  898. }
  899. STDMETHODIMP
  900. CWinNTService::get_StartType(THIS_ LONG FAR* retval)
  901. {
  902. GET_PROPERTY_LONG((IADsService *)this, StartType);
  903. }
  904. STDMETHODIMP
  905. CWinNTService::put_StartType(THIS_ LONG lStartType)
  906. {
  907. PUT_PROPERTY_LONG((IADsService *)this, StartType);
  908. }
  909. STDMETHODIMP
  910. CWinNTService::get_Path(THIS_ BSTR FAR* retval)
  911. {
  912. GET_PROPERTY_BSTR((IADsService *)this, Path);
  913. }
  914. STDMETHODIMP
  915. CWinNTService::put_Path(THIS_ BSTR bstrPath)
  916. {
  917. PUT_PROPERTY_BSTR((IADsService *)this, Path);
  918. }
  919. STDMETHODIMP
  920. CWinNTService::get_StartupParameters(THIS_ BSTR FAR* retval)
  921. {
  922. GET_PROPERTY_BSTR((IADsService *)this, StartupParameters);
  923. }
  924. STDMETHODIMP
  925. CWinNTService::put_StartupParameters(THIS_ BSTR bstrStartupParameters) {
  926. PUT_PROPERTY_BSTR((IADsService *)this, StartupParameters);
  927. }
  928. STDMETHODIMP
  929. CWinNTService::get_ErrorControl(THIS_ LONG FAR* retval)
  930. {
  931. GET_PROPERTY_LONG((IADsService *)this, ErrorControl);
  932. }
  933. STDMETHODIMP
  934. CWinNTService::put_ErrorControl(THIS_ LONG lErrorControl)
  935. {
  936. PUT_PROPERTY_LONG((IADsService *)this, ErrorControl);
  937. }
  938. STDMETHODIMP
  939. CWinNTService::get_LoadOrderGroup(THIS_ BSTR FAR* retval)
  940. {
  941. GET_PROPERTY_BSTR((IADsService *)this, LoadOrderGroup);
  942. }
  943. STDMETHODIMP
  944. CWinNTService::put_LoadOrderGroup(THIS_ BSTR bstrLoadOrderGroup)
  945. {
  946. PUT_PROPERTY_BSTR((IADsService *)this, LoadOrderGroup);
  947. }
  948. STDMETHODIMP
  949. CWinNTService::get_ServiceAccountName(THIS_ BSTR FAR* retval)
  950. {
  951. GET_PROPERTY_BSTR((IADsService *)this, ServiceAccountName);
  952. }
  953. STDMETHODIMP
  954. CWinNTService::put_ServiceAccountName(THIS_ BSTR bstrServiceAccountName)
  955. {
  956. RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED);
  957. }
  958. STDMETHODIMP
  959. CWinNTService::get_ServiceAccountPath(THIS_ BSTR FAR* retval)
  960. {
  961. RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED);
  962. }
  963. STDMETHODIMP
  964. CWinNTService::put_ServiceAccountPath(THIS_ BSTR bstrServiceAccountName)
  965. {
  966. RRETURN_EXP_IF_ERR(E_ADS_PROPERTY_NOT_SUPPORTED);
  967. }
  968. STDMETHODIMP
  969. CWinNTService::get_Dependencies(THIS_ VARIANT FAR* retval)
  970. {
  971. GET_PROPERTY_VARIANT((IADsService *)this, Dependencies);
  972. }
  973. STDMETHODIMP
  974. CWinNTService::put_Dependencies(THIS_ VARIANT vDependencies)
  975. {
  976. PUT_PROPERTY_VARIANT((IADsService *)this, Dependencies);
  977. }
  978. STDMETHODIMP
  979. CWinNTService::SetPassword(THIS_ BSTR bstrNewPassword)
  980. {
  981. //
  982. // This routine should merely change password. Even if any other
  983. // properties are set in the configuration functional set then they
  984. // will not be touched.
  985. // Therefore we do a QueryServiceConfig and get all the configuration
  986. // related information, merely change the password and send it back.
  987. // For this reason, it is not possible to reuse GetInfo or SetInfo
  988. // because they change service config properties.
  989. //
  990. BOOL fRetval;
  991. LPQUERY_SERVICE_CONFIG pMem = NULL;
  992. HRESULT hr;
  993. hr = WinNTOpenService(SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS,
  994. SERVICE_ALL_ACCESS);
  995. BAIL_IF_ERROR(hr);
  996. hr = GetServiceConfigInfo(&pMem);
  997. BAIL_IF_ERROR(hr);
  998. //
  999. // just change the field corresponding to password.
  1000. //
  1001. fRetval = ChangeServiceConfig(_schService,
  1002. pMem->dwServiceType,
  1003. pMem->dwStartType,
  1004. pMem->dwErrorControl,
  1005. pMem->lpBinaryPathName,
  1006. pMem->lpLoadOrderGroup,
  1007. NULL,
  1008. pMem->lpDependencies,
  1009. pMem->lpServiceStartName,
  1010. (LPTSTR)bstrNewPassword,
  1011. pMem->lpDisplayName
  1012. );
  1013. if(!fRetval){
  1014. hr = HRESULT_FROM_WIN32(GetLastError());
  1015. goto cleanup;
  1016. }
  1017. cleanup:
  1018. if(pMem){
  1019. FreeADsMem(pMem);
  1020. }
  1021. WinNTCloseService();
  1022. RRETURN_EXP_IF_ERR(hr);
  1023. }
  1024. //+---------------------------------------------------------------------------
  1025. //
  1026. // Function: CWinNTService::Start
  1027. //
  1028. // Synopsis: Attempts to start the service specified in _bstrServiceName on
  1029. // the server named in _bstrPath.
  1030. //
  1031. // Arguments:
  1032. //
  1033. // Returns: HRESULT.
  1034. //
  1035. // Modifies:
  1036. //
  1037. // History: 01/04/96 RamV Created
  1038. //
  1039. // Notes:
  1040. //----------------------------------------------------------------------------
  1041. STDMETHODIMP
  1042. CWinNTService::Start(THIS)
  1043. {
  1044. HRESULT hr;
  1045. hr = WinNTControlService(WINNT_START_SERVICE);
  1046. RRETURN_EXP_IF_ERR(hr);
  1047. }
  1048. //+---------------------------------------------------------------------------
  1049. //
  1050. // Function: CWinNTService::Stop
  1051. //
  1052. // Synopsis: Attempts to stop the service specified in _bstrServiceName on
  1053. // the server named in _bstrPath.
  1054. //
  1055. // Arguments:
  1056. //
  1057. // Returns: HRESULT.
  1058. //
  1059. // Modifies:
  1060. //
  1061. // History: 01/04/96 RamV Created
  1062. //
  1063. //----------------------------------------------------------------------------
  1064. STDMETHODIMP
  1065. CWinNTService::Stop(THIS)
  1066. {
  1067. HRESULT hr;
  1068. hr = WinNTControlService(WINNT_STOP_SERVICE);
  1069. RRETURN_EXP_IF_ERR(hr);
  1070. }
  1071. //+---------------------------------------------------------------------------
  1072. //
  1073. // Function: CWinNTService::Pause
  1074. //
  1075. // Synopsis: Attempts to pause the service named _bstrServiceName on the
  1076. // server named in _bstrPath.
  1077. //
  1078. // Arguments:
  1079. //
  1080. // Returns: HRESULT.
  1081. //
  1082. // Modifies:
  1083. //
  1084. // History: 01-04-96 RamV Created
  1085. //
  1086. //----------------------------------------------------------------------------
  1087. STDMETHODIMP
  1088. CWinNTService::Pause(THIS)
  1089. {
  1090. HRESULT hr;
  1091. hr = WinNTControlService(WINNT_PAUSE_SERVICE);
  1092. RRETURN_EXP_IF_ERR(hr);
  1093. }
  1094. //+---------------------------------------------------------------------------
  1095. //
  1096. // Function: CWinNTService::Continue
  1097. //
  1098. // Synopsis: Attempts to "unpause" the service specified in _bstrServiceName
  1099. // on the server named in _bstrPath.
  1100. //
  1101. // Arguments:
  1102. //
  1103. // Returns: HRESULT.
  1104. //
  1105. // Modifies:
  1106. //
  1107. // History: 01/04/96 RamV Created
  1108. //
  1109. //----------------------------------------------------------------------------
  1110. STDMETHODIMP
  1111. CWinNTService::Continue(THIS)
  1112. {
  1113. HRESULT hr;
  1114. hr = WinNTControlService(WINNT_CONTINUE_SERVICE);
  1115. RRETURN_EXP_IF_ERR(hr);
  1116. }
  1117. //
  1118. // Helper Functions
  1119. //
  1120. HRESULT
  1121. CWinNTService::GetServiceConfigInfo(LPQUERY_SERVICE_CONFIG *ppMem)
  1122. {
  1123. //
  1124. //gets the service configuration information into ppMem
  1125. //
  1126. BOOL fRetval;
  1127. DWORD dwBufAllocated = 0;
  1128. DWORD dwBufNeeded = 0;
  1129. DWORD dwLastError;
  1130. HRESULT hr = S_OK;
  1131. ADsAssert(ppMem);
  1132. *ppMem = (LPQUERY_SERVICE_CONFIG)AllocADsMem(dwBufAllocated);
  1133. if (*ppMem == NULL){
  1134. hr = E_OUTOFMEMORY;
  1135. goto cleanup;
  1136. }
  1137. ADsAssert(_schService);
  1138. fRetval = QueryServiceConfig(_schService,
  1139. (LPQUERY_SERVICE_CONFIG)(*ppMem),
  1140. dwBufAllocated,
  1141. &dwBufNeeded);
  1142. if (fRetval == FALSE) {
  1143. dwLastError = GetLastError();
  1144. switch (dwLastError) {
  1145. case ERROR_INSUFFICIENT_BUFFER:
  1146. //
  1147. // Allocate more memory and try again.
  1148. //
  1149. FreeADsMem(*ppMem);
  1150. *ppMem = NULL;
  1151. dwBufAllocated = dwBufNeeded;
  1152. *ppMem = (LPQUERY_SERVICE_CONFIG)AllocADsMem(dwBufAllocated);
  1153. if (*ppMem == NULL) {
  1154. BAIL_IF_ERROR(hr = E_OUTOFMEMORY);
  1155. }
  1156. fRetval = QueryServiceConfig(_schService,
  1157. *ppMem,
  1158. dwBufAllocated,
  1159. &dwBufNeeded);
  1160. if (fRetval == FALSE) {
  1161. hr = HRESULT_FROM_WIN32(GetLastError());
  1162. break;
  1163. }
  1164. break;
  1165. default:
  1166. hr = HRESULT_FROM_WIN32(GetLastError());
  1167. break;
  1168. }
  1169. BAIL_IF_ERROR(hr);
  1170. }
  1171. if(*ppMem){
  1172. RRETURN(S_OK);
  1173. }
  1174. cleanup:
  1175. RRETURN(hr);
  1176. }
  1177. HRESULT
  1178. CWinNTService::WinNTControlService( DWORD dwControl)
  1179. {
  1180. //
  1181. // abstracts out the common code of Start,Stop,Pause and Resume
  1182. //
  1183. HRESULT hr =S_OK, hrclose=S_OK, hrcontrol=S_OK;
  1184. SERVICE_STATUS ssStatusInfo;
  1185. BOOL fRetval;
  1186. if(_fValidHandle){
  1187. //
  1188. // an open handle exists, blow it away
  1189. //
  1190. hrclose = WinNTCloseService();
  1191. BAIL_ON_FAILURE(hrclose);
  1192. _fValidHandle = FALSE;
  1193. }
  1194. hr = WinNTOpenService(SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS,
  1195. GENERIC_EXECUTE| SERVICE_INTERROGATE
  1196. );
  1197. BAIL_ON_FAILURE(hr);
  1198. _fValidHandle = TRUE;
  1199. switch(dwControl){
  1200. case WINNT_START_SERVICE:
  1201. fRetval = StartService(_schService,
  1202. 0,
  1203. NULL );
  1204. if(!fRetval){
  1205. hrcontrol = HRESULT_FROM_WIN32(GetLastError());
  1206. goto error;
  1207. }
  1208. _dwOpPending = PENDING_START;
  1209. break;
  1210. case WINNT_STOP_SERVICE:
  1211. fRetval = ControlService(_schService,
  1212. SERVICE_CONTROL_STOP,
  1213. &ssStatusInfo);
  1214. if(!fRetval){
  1215. hrcontrol = HRESULT_FROM_WIN32(GetLastError());
  1216. goto error;
  1217. }
  1218. _dwOpPending = PENDING_STOP;
  1219. break;
  1220. case WINNT_PAUSE_SERVICE:
  1221. fRetval = ControlService(_schService,
  1222. SERVICE_CONTROL_PAUSE,
  1223. &ssStatusInfo);
  1224. if(!fRetval){
  1225. hrcontrol = HRESULT_FROM_WIN32(GetLastError());
  1226. goto error;
  1227. }
  1228. _dwOpPending = PENDING_PAUSE;
  1229. break;
  1230. case WINNT_CONTINUE_SERVICE:
  1231. fRetval = ControlService(_schService,
  1232. SERVICE_CONTROL_CONTINUE,
  1233. &ssStatusInfo);
  1234. if(!fRetval){
  1235. hrcontrol = HRESULT_FROM_WIN32(GetLastError());
  1236. goto error;
  1237. }
  1238. _dwOpPending = PENDING_CONTINUE;
  1239. break;
  1240. default:
  1241. hrcontrol = E_FAIL;
  1242. goto error;
  1243. }
  1244. _dwTimeStarted = GetTickCount();
  1245. _dwWaitHint = 10000; //10 seconds
  1246. _dwCheckPoint = 0;
  1247. RRETURN(S_OK);
  1248. error:
  1249. if(FAILED(hrcontrol)){
  1250. _fValidHandle = FALSE;
  1251. RRETURN(hrcontrol);
  1252. }
  1253. else if(FAILED(hrclose)){
  1254. RRETURN(hrclose);
  1255. }
  1256. else{
  1257. RRETURN(hr);
  1258. }
  1259. }
  1260. //+---------------------------------------------------------------------------
  1261. //
  1262. // Function: CWinNTService::WinNTOpenService
  1263. //
  1264. // Synopsis: Opens the Service Control Manager on the machine specified in
  1265. // _bstrPath, then opens the Service specified in _bstrServiceName.
  1266. // The handle to the SCM is placed in _schSCManager, and the
  1267. // handle to the service is placed in _schService.
  1268. //
  1269. // Arguments: [dwSCMDesiredAccess] -- type of SCM access needed
  1270. // [dwSvrDesiredAccess] -- type of Service access required
  1271. //
  1272. // Returns: HRESULT.
  1273. //
  1274. // Modifies:
  1275. //
  1276. // History: 03-17-95 t-skwan Created
  1277. // 01/04/96 RamV Modified
  1278. //
  1279. //----------------------------------------------------------------------------
  1280. HRESULT
  1281. CWinNTService::WinNTOpenService(
  1282. DWORD dwSCMDesiredAccess,
  1283. DWORD dwSvrDesiredAccess
  1284. )
  1285. {
  1286. HRESULT hr;
  1287. DWORD dwLastError;
  1288. //
  1289. // Open the Service Control Manager.
  1290. //
  1291. //
  1292. // OpenSCManager(
  1293. // LPCTSTR lpszMachineName,
  1294. // LPCTSTR lpszDatabaseName.
  1295. // DWORD fdwDesiredAccess)
  1296. //
  1297. _schSCManager = OpenSCManager(_pszServerName,
  1298. NULL,
  1299. dwSCMDesiredAccess);
  1300. if (_schSCManager == NULL) {
  1301. dwLastError = GetLastError();
  1302. hr = HRESULT_FROM_WIN32(dwLastError);
  1303. RRETURN(hr);
  1304. }
  1305. //
  1306. // Get a handle to the specified service.
  1307. //
  1308. _schService = OpenService(_schSCManager,
  1309. _pszServiceName,
  1310. dwSvrDesiredAccess);
  1311. if(_schService == NULL) {
  1312. hr = HRESULT_FROM_WIN32(GetLastError());
  1313. CloseServiceHandle(_schSCManager);
  1314. _schSCManager = NULL;
  1315. RRETURN(hr);
  1316. }
  1317. RRETURN(S_OK);
  1318. }
  1319. //+---------------------------------------------------------------------------
  1320. //
  1321. // Function: CWinNTService::WinNTCloseService
  1322. //
  1323. // Synopsis: Closes the Service handle and the Service Control Manager
  1324. // handle.
  1325. //
  1326. // Arguments:
  1327. //
  1328. // Returns: HRESULT.
  1329. //
  1330. // Modifies:
  1331. //
  1332. // History: 03-17-95 t-skwan Created
  1333. // 01/04/96 RamV Modified
  1334. //
  1335. //----------------------------------------------------------------------------
  1336. HRESULT
  1337. CWinNTService::WinNTCloseService()
  1338. {
  1339. BOOL fRetval = TRUE;
  1340. //
  1341. // Close the Service handle.
  1342. //
  1343. if(_schService){
  1344. fRetval = CloseServiceHandle(_schService);
  1345. _schService = NULL;
  1346. }
  1347. if (!fRetval) {
  1348. //
  1349. // Ack. What do we do if there is an error closing a service?
  1350. //
  1351. RRETURN(HRESULT_FROM_WIN32(GetLastError()));
  1352. }
  1353. //
  1354. // Close the Service Control Manager.
  1355. //
  1356. if(_schSCManager){
  1357. fRetval = CloseServiceHandle(_schSCManager);
  1358. _schSCManager = NULL;
  1359. }
  1360. if (!fRetval) {
  1361. //
  1362. // Ack. What do we do if there is an error closing an SCM?
  1363. //
  1364. RRETURN(HRESULT_FROM_WIN32(GetLastError()));
  1365. }
  1366. RRETURN(S_OK);
  1367. }
  1368. STDMETHODIMP
  1369. CWinNTService::get_Status(THIS_ long FAR* plStatusCode)
  1370. {
  1371. HRESULT hr = S_OK;
  1372. BOOL fRetval = FALSE, found = FALSE;
  1373. SERVICE_STATUS Status;
  1374. DWORD dwStatus = 0;
  1375. if(plStatusCode == NULL){
  1376. RRETURN_EXP_IF_ERR(E_POINTER);
  1377. }
  1378. *plStatusCode = -1; //-1 is an invalid code
  1379. if(!(_fValidHandle)){
  1380. //
  1381. // currently not waiting on any service
  1382. //
  1383. hr = WinNTOpenService(SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS,
  1384. GENERIC_EXECUTE|SERVICE_INTERROGATE);
  1385. BAIL_IF_ERROR(hr);
  1386. fRetval = ControlService(_schService,
  1387. SERVICE_CONTROL_INTERROGATE,
  1388. &Status);
  1389. if(!fRetval){
  1390. hr = HRESULT_FROM_WIN32(GetLastError());
  1391. if(hr == HRESULT_FROM_WIN32(ERROR_SERVICE_NOT_ACTIVE)){
  1392. dwStatus = SERVICE_STOPPED;
  1393. hr = S_OK;
  1394. }
  1395. goto cleanup;
  1396. }
  1397. dwStatus = Status.dwCurrentState;
  1398. hr = WinNTCloseService();
  1399. goto cleanup;
  1400. }
  1401. //
  1402. // if you are here
  1403. // you are waiting for a service to complete
  1404. //
  1405. //
  1406. // NOTE: QueryServiceStatus queries the SCM rather than
  1407. // the service directly so to get a more upto date answer
  1408. // we need to use control service with interrogate option
  1409. //
  1410. hr = WinNTOpenService(SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS,
  1411. GENERIC_EXECUTE|SERVICE_INTERROGATE);
  1412. BAIL_IF_ERROR(hr);
  1413. fRetval = ControlService(_schService,
  1414. SERVICE_CONTROL_INTERROGATE,
  1415. &Status);
  1416. if(!fRetval){
  1417. hr = HRESULT_FROM_WIN32(GetLastError());
  1418. if(hr == HRESULT_FROM_WIN32(ERROR_SERVICE_NOT_ACTIVE)){
  1419. dwStatus = SERVICE_STOPPED;
  1420. hr = S_OK;
  1421. }
  1422. goto cleanup;
  1423. }
  1424. hr = EvalPendingOperation(PENDING_START,
  1425. SERVICE_RUNNING,
  1426. SERVICE_START_PENDING,
  1427. &Status,
  1428. &dwStatus
  1429. );
  1430. BAIL_IF_ERROR(hr);
  1431. if(dwStatus != 0){
  1432. //
  1433. // the correct scenario was found
  1434. //
  1435. goto cleanup;
  1436. }
  1437. hr = EvalPendingOperation(PENDING_STOP,
  1438. SERVICE_STOPPED,
  1439. SERVICE_STOP_PENDING,
  1440. &Status,
  1441. &dwStatus
  1442. );
  1443. BAIL_IF_ERROR(hr);
  1444. if(dwStatus != 0){
  1445. //
  1446. // the correct scenario was found
  1447. //
  1448. goto cleanup;
  1449. }
  1450. hr = EvalPendingOperation(PENDING_PAUSE,
  1451. SERVICE_PAUSED,
  1452. SERVICE_PAUSE_PENDING,
  1453. &Status,
  1454. &dwStatus
  1455. );
  1456. BAIL_IF_ERROR(hr);
  1457. if(dwStatus != 0){
  1458. //
  1459. // the correct scenario was found
  1460. //
  1461. goto cleanup;
  1462. }
  1463. hr = EvalPendingOperation(PENDING_CONTINUE,
  1464. SERVICE_RUNNING,
  1465. SERVICE_CONTINUE_PENDING,
  1466. &Status,
  1467. &dwStatus
  1468. );
  1469. BAIL_IF_ERROR(hr);
  1470. ADsAssert(dwStatus != 0); //we must find the appropriate scenario
  1471. cleanup:
  1472. if(SUCCEEDED(hr)){
  1473. //
  1474. // instead of a conversion routine, we return WinNT Status Code
  1475. //
  1476. *plStatusCode = dwStatus;
  1477. }
  1478. RRETURN_EXP_IF_ERR(hr);
  1479. }
  1480. HRESULT
  1481. CWinNTService::EvalPendingOperation(
  1482. THIS_ DWORD dwOpPending,
  1483. DWORD dwStatusDone,
  1484. DWORD dwStatusPending,
  1485. LPSERVICE_STATUS pStatus,
  1486. DWORD *pdwRetval
  1487. )
  1488. {
  1489. DWORD dwCurrentStatus;
  1490. BOOL fRetval;
  1491. HRESULT hr =S_OK;
  1492. DWORD dwNow;
  1493. dwCurrentStatus = pStatus->dwCurrentState;
  1494. if(_dwOpPending == dwOpPending){
  1495. if(dwCurrentStatus == dwStatusDone){
  1496. //
  1497. //was pending, is now completed
  1498. //
  1499. _dwOpPending = NOTPENDING;
  1500. *pdwRetval = dwStatusDone;
  1501. hr = WinNTCloseService();
  1502. BAIL_ON_FAILURE(hr);
  1503. _fValidHandle = FALSE;
  1504. RRETURN(S_OK);
  1505. }
  1506. else if(dwCurrentStatus = dwStatusPending){
  1507. //
  1508. //see if progress has been made since the last time we checked
  1509. //
  1510. if(pStatus->dwCheckPoint !=_dwCheckPoint){
  1511. //
  1512. // progress was made
  1513. //
  1514. *pdwRetval = dwStatusPending;
  1515. _dwCheckPoint = pStatus->dwCheckPoint;
  1516. _dwWaitHint = pStatus->dwWaitHint;
  1517. _dwTimeStarted = GetTickCount();
  1518. RRETURN(S_OK);
  1519. }
  1520. dwNow = GetTickCount();
  1521. if(2*_dwWaitHint < TickCountDiff(dwNow,_dwTimeStarted)){
  1522. //
  1523. // you can still wait
  1524. //
  1525. *pdwRetval = dwStatusPending;
  1526. RRETURN(S_OK);
  1527. }
  1528. else{
  1529. //
  1530. // took too long without signs of progress
  1531. //
  1532. *pdwRetval = SERVICE_ERROR;
  1533. _dwOpPending = NOTPENDING;
  1534. hr = WinNTCloseService();
  1535. BAIL_ON_FAILURE(hr);
  1536. _fValidHandle = FALSE;
  1537. RRETURN(S_OK);
  1538. }
  1539. }
  1540. else{
  1541. //
  1542. // an operation is pending but we arent going anywhere
  1543. // recover gracefully
  1544. //
  1545. _dwOpPending = NOTPENDING;
  1546. hr = WinNTCloseService();
  1547. BAIL_ON_FAILURE(hr);
  1548. _fValidHandle = FALSE;
  1549. *pdwRetval = SERVICE_ERROR;
  1550. RRETURN(S_OK);
  1551. }
  1552. }
  1553. error:
  1554. RRETURN(hr);
  1555. }