Leaked source code of windows server 2003
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.

1100 lines
33 KiB

  1. /////////////////////////////////////////////////////////////////////
  2. //
  3. // SvcEnum.cpp
  4. //
  5. // This file contains routines to enumerate services.
  6. //
  7. // HISTORY
  8. // t-danmo 96.09.13 Creation (split of log.cpp)
  9. // t-danm 96.07.14 Moved member functions Service_* from
  10. // CFileMgmtComponent to CFileMgmtComponentData.
  11. //
  12. /////////////////////////////////////////////////////////////////////
  13. #include "stdafx.h"
  14. #include "cmponent.h"
  15. #include "compdata.h" // QueryComponentDataRef().m_hScManager
  16. #include "safetemp.h"
  17. #include "macros.h"
  18. USE_HANDLE_MACROS("FILEMGMT(SvcEnum.cpp)")
  19. #include "FileSvc.h" // FileServiceProvider
  20. #include "dataobj.h"
  21. #include <comstrm.h>
  22. #ifdef _DEBUG
  23. #define new DEBUG_NEW
  24. #undef THIS_FILE
  25. static char THIS_FILE[] = __FILE__;
  26. #endif
  27. #include "progress.h"
  28. /*
  29. // forward declarations
  30. class CServiceCookieBlock;
  31. /////////////////////////////////////////////////////////////////////
  32. class CServiceCookie : public CFileMgmtResultCookie
  33. {
  34. public:
  35. CString GetServiceDisplaySecurityContext ();
  36. CString GetServiceDisplayStartUpType ();
  37. CString GetServiceDisplayStatus ();
  38. CString GetServiceDescription ();
  39. virtual HRESULT CompareSimilarCookies( CCookie* pOtherCookie, int* pnResult);
  40. CServiceCookie() : CFileMgmtResultCookie( FILEMGMT_SERVICE ) {}
  41. virtual HRESULT GetServiceName( OUT CString& strServiceName );
  42. virtual HRESULT GetServiceDisplayName( OUT CString& strServiceName );
  43. virtual BSTR QueryResultColumnText( int nCol, CFileMgmtComponentData& refcdata );
  44. inline ENUM_SERVICE_STATUS* GetServiceStatus()
  45. {
  46. ASSERT( NULL != m_pobject );
  47. return (ENUM_SERVICE_STATUS*)m_pobject;
  48. }
  49. CString m_strDescription; // Description of service
  50. DWORD m_dwCurrentState;
  51. DWORD m_dwStartType;
  52. CString m_strServiceStartName; // Name of the account which the service process will be logged (eg: ".\\Administrator")
  53. virtual void AddRefCookie();
  54. virtual void ReleaseCookie();
  55. // CHasMachineName
  56. CServiceCookieBlock* m_pCookieBlock;
  57. DECLARE_FORWARDS_MACHINE_NAME(m_pCookieBlock)
  58. };
  59. HRESULT CServiceCookie::GetServiceName(OUT CString& strServiceName )
  60. {
  61. ENUM_SERVICE_STATUS * pESS = (ENUM_SERVICE_STATUS *)m_pobject;
  62. ASSERT( NULL != pESS );
  63. ASSERT( NULL != pESS->lpServiceName );
  64. strServiceName = pESS->lpServiceName;
  65. return S_OK;
  66. }
  67. HRESULT CServiceCookie::GetServiceDisplayName(OUT CString& strServiceDisplayName )
  68. {
  69. ENUM_SERVICE_STATUS * pESS = (ENUM_SERVICE_STATUS *)m_pobject;
  70. ASSERT( NULL != pESS );
  71. ASSERT( NULL != pESS->lpDisplayName );
  72. strServiceDisplayName = pESS->lpDisplayName;
  73. return S_OK;
  74. }
  75. BSTR CServiceCookie::QueryResultColumnText( int nCol, CFileMgmtComponentData& refcdata )
  76. {
  77. switch (nCol)
  78. {
  79. case COLNUM_SERVICES_SERVICENAME:
  80. return GetServiceStatus()->lpDisplayName;
  81. case COLNUM_SERVICES_DESCRIPTION:
  82. return const_cast<BSTR>((LPCTSTR)m_strDescription);
  83. case COLNUM_SERVICES_STATUS:
  84. return const_cast<BSTR>( Service_PszMapStateToName(m_dwCurrentState) );
  85. case COLNUM_SERVICES_STARTUPTYPE:
  86. return const_cast<BSTR>( Service_PszMapStartupTypeToName(m_dwStartType) );
  87. case COLNUM_SERVICES_SECURITYCONTEXT:
  88. return const_cast<BSTR>((LPCTSTR)m_strServiceStartName);
  89. default:
  90. ASSERT(FALSE);
  91. break;
  92. }
  93. return L"";
  94. }
  95. class CServiceCookieBlock : public CCookieBlock<CServiceCookie>,
  96. public CStoresMachineName
  97. {
  98. public:
  99. inline CServiceCookieBlock(
  100. CServiceCookie* aCookies, // use vector ctor, we use vector dtor
  101. INT cCookies,
  102. LPCTSTR lpcszMachineName,
  103. PVOID pvCookieData)
  104. : CCookieBlock<CServiceCookie>( aCookies, cCookies ),
  105. CStoresMachineName( lpcszMachineName ),
  106. m_pvCookieData(pvCookieData)
  107. {
  108. for (int i = 0; i < cCookies; i++)
  109. // {
  110. // aCookies[i].ReadMachineNameFrom( (CHasMachineName*)this );
  111. aCookies[i].m_pCookieBlock = this;
  112. // }
  113. }
  114. virtual ~CServiceCookieBlock();
  115. private:
  116. PVOID m_pvCookieData; // actually ENUM_SERVICE_STATUS*
  117. };
  118. DEFINE_COOKIE_BLOCK(CServiceCookie)
  119. CServiceCookieBlock::~CServiceCookieBlock()
  120. {
  121. if (NULL != m_pvCookieData)
  122. {
  123. delete m_pvCookieData;
  124. m_pvCookieData = NULL;
  125. }
  126. }
  127. void CServiceCookie::AddRefCookie() { m_pCookieBlock->AddRef(); }
  128. void CServiceCookie::ReleaseCookie() { m_pCookieBlock->Release(); }
  129. DEFINE_FORWARDS_MACHINE_NAME( CServiceCookie, m_pCookieBlock )
  130. */
  131. int g_marker;
  132. class CNewServiceCookie
  133. : public CNewResultCookie
  134. {
  135. public:
  136. // 581167-2002/03/05-JonN should initialize DWORD members
  137. CNewServiceCookie()
  138. : CNewResultCookie( (PVOID)&g_marker, FILEMGMT_SERVICE )
  139. , m_dwState( 0 )
  140. , m_dwStartType( 0 )
  141. {}
  142. virtual ~CNewServiceCookie();
  143. virtual BSTR QueryResultColumnText( int nCol, CFileMgmtComponentData& refcdata );
  144. virtual HRESULT CompareSimilarCookies(CCookie * pOtherCookie, int * pnResult);
  145. virtual HRESULT GetServiceName( OUT CString& strServiceName );
  146. virtual HRESULT GetServiceDisplayName( OUT CString& strServiceName );
  147. virtual HRESULT GetExplorerViewDescription( OUT CString& strExplorerViewDescription );
  148. virtual HRESULT SimilarCookieIsSameObject( CNewResultCookie* pOtherCookie, BOOL* pbSame );
  149. virtual BOOL CopySimilarCookie( CNewResultCookie* pcookie );
  150. public:
  151. CString m_strServiceName;
  152. CString m_strDisplayName;
  153. CString m_strDescription;
  154. DWORD m_dwState;
  155. DWORD m_dwStartType;
  156. CString m_strStartName;
  157. }; // CNewServiceCookie
  158. CNewServiceCookie::~CNewServiceCookie()
  159. {
  160. }
  161. BSTR CNewServiceCookie::QueryResultColumnText(
  162. int nCol,
  163. CFileMgmtComponentData& /*refcdata*/ )
  164. {
  165. switch (nCol)
  166. {
  167. case COLNUM_SERVICES_SERVICENAME:
  168. return const_cast<BSTR>((LPCTSTR)m_strDisplayName);
  169. case COLNUM_SERVICES_DESCRIPTION:
  170. return const_cast<BSTR>((LPCTSTR)m_strDescription);
  171. case COLNUM_SERVICES_STATUS:
  172. return const_cast<BSTR>( Service_PszMapStateToName(m_dwState) );
  173. case COLNUM_SERVICES_STARTUPTYPE:
  174. return const_cast<BSTR>( Service_PszMapStartupTypeToName(m_dwStartType) );
  175. case COLNUM_SERVICES_SECURITYCONTEXT:
  176. // JonN 11/14/00 188203 support LocalService/NetworkService
  177. return const_cast<BSTR>(
  178. Service_PszMapStartupAccountToName(m_strStartName) );
  179. default:
  180. ASSERT(FALSE);
  181. break;
  182. }
  183. return L"";
  184. }
  185. HRESULT CNewServiceCookie::CompareSimilarCookies(CCookie * pOtherCookie, int * pnResult)
  186. {
  187. if ( !pOtherCookie || FILEMGMT_SERVICE != QueryObjectType () )
  188. {
  189. ASSERT(FALSE);
  190. return E_FAIL;
  191. }
  192. CNewServiceCookie* pcookie = dynamic_cast <CNewServiceCookie*>(pOtherCookie);
  193. if ( FILEMGMT_SERVICE != pcookie->QueryObjectType ()
  194. || !IsSameType(pcookie) )
  195. {
  196. ASSERT(FALSE);
  197. return E_FAIL;
  198. }
  199. int colNum = *pnResult; // save in case it's overwritten
  200. HRESULT hr = CHasMachineName::CompareMachineNames( *pcookie, pnResult );
  201. if (S_OK != hr || 0 != *pnResult)
  202. return hr;
  203. switch (colNum) // column number
  204. {
  205. case COMPARESIMILARCOOKIE_FULL: // fall through
  206. case COLNUM_SERVICES_SERVICENAME:
  207. *pnResult = lstrcmpi(m_strDisplayName, pcookie->m_strDisplayName);
  208. break;
  209. case COLNUM_SERVICES_DESCRIPTION:
  210. *pnResult = lstrcmpi(m_strDescription, pcookie->m_strDescription);
  211. break;
  212. case COLNUM_SERVICES_STATUS:
  213. {
  214. CString strServiceA = Service_PszMapStateToName(m_dwState);
  215. CString strServiceB = Service_PszMapStateToName(pcookie->m_dwState);
  216. *pnResult = lstrcmpi(strServiceA, strServiceB);
  217. }
  218. break;
  219. case COLNUM_SERVICES_STARTUPTYPE:
  220. {
  221. CString strServiceA = Service_PszMapStartupTypeToName(m_dwStartType);
  222. CString strServiceB = Service_PszMapStartupTypeToName(pcookie->m_dwStartType);
  223. *pnResult = lstrcmpi(strServiceA, strServiceB);
  224. }
  225. break;
  226. case COLNUM_SERVICES_SECURITYCONTEXT:
  227. // JonN 11/14/00 188203 support LocalService/NetworkService
  228. {
  229. CString strServiceA = Service_PszMapStartupAccountToName(m_strStartName);
  230. CString strServiceB = Service_PszMapStartupAccountToName(pcookie->m_strStartName);
  231. *pnResult = lstrcmpi(strServiceA, strServiceB);
  232. }
  233. break;
  234. default:
  235. ASSERT(FALSE);
  236. return E_UNEXPECTED;
  237. }
  238. return S_OK;
  239. }
  240. HRESULT CNewServiceCookie::GetServiceName(OUT CString& strServiceName )
  241. {
  242. strServiceName = m_strServiceName;
  243. return S_OK;
  244. }
  245. HRESULT CNewServiceCookie::GetServiceDisplayName(OUT CString& strServiceDisplayName )
  246. {
  247. strServiceDisplayName = m_strDisplayName;
  248. return S_OK;
  249. }
  250. HRESULT CNewServiceCookie::GetExplorerViewDescription(OUT CString& strExplorerViewDescription )
  251. {
  252. strExplorerViewDescription = m_strDescription;
  253. return S_OK;
  254. }
  255. HRESULT CNewServiceCookie::SimilarCookieIsSameObject(
  256. CNewResultCookie* pOtherCookie,
  257. BOOL* pbSame )
  258. {
  259. if ( !pOtherCookie || !IsSameType(pOtherCookie) )
  260. {
  261. ASSERT(FALSE);
  262. return E_FAIL;
  263. }
  264. int nResult = 0;
  265. HRESULT hr = CHasMachineName::CompareMachineNames( *pOtherCookie, &nResult );
  266. if (S_OK != hr || 0 != nResult)
  267. {
  268. *pbSame = FALSE;
  269. return hr;
  270. }
  271. *pbSame = (0 == lstrcmpi(m_strServiceName,
  272. ((CNewServiceCookie*)pOtherCookie)->m_strServiceName) );
  273. return S_OK;
  274. }
  275. BOOL CNewServiceCookie::CopySimilarCookie( CNewResultCookie* pcookie )
  276. {
  277. if (NULL == pcookie)
  278. {
  279. ASSERT(FALSE);
  280. return FALSE;
  281. }
  282. CNewServiceCookie* pnewcookie = (CNewServiceCookie*)pcookie;
  283. BOOL fChanged = FALSE;
  284. if (m_strServiceName != pnewcookie->m_strServiceName)
  285. {
  286. m_strServiceName = pnewcookie->m_strServiceName;
  287. fChanged = TRUE;
  288. }
  289. if (m_strDisplayName != pnewcookie->m_strDisplayName)
  290. {
  291. m_strDisplayName = pnewcookie->m_strDisplayName;
  292. fChanged = TRUE;
  293. }
  294. if (m_strDescription != pnewcookie->m_strDescription)
  295. {
  296. m_strDescription = pnewcookie->m_strDescription;
  297. fChanged = TRUE;
  298. }
  299. if (m_dwState != pnewcookie->m_dwState)
  300. {
  301. m_dwState = pnewcookie->m_dwState;
  302. fChanged = TRUE;
  303. }
  304. if (m_dwStartType != pnewcookie->m_dwStartType)
  305. {
  306. m_dwStartType = pnewcookie->m_dwStartType;
  307. fChanged = TRUE;
  308. }
  309. if (m_strStartName != pnewcookie->m_strStartName)
  310. {
  311. m_strStartName = pnewcookie->m_strStartName;
  312. fChanged = TRUE;
  313. }
  314. // don't bother with machine name
  315. fChanged |= CNewResultCookie::CopySimilarCookie( pcookie );
  316. return fChanged;
  317. }
  318. /////////////////////////////////////////////////////////////////////
  319. /////////////////////////////////////////////////////////////////////
  320. /////////////////////////////////////////////////////////////////////
  321. // Service_EOpenScManager()
  322. //
  323. // Open the service Service Control Manager database to
  324. // enumerate all available services.
  325. //
  326. // If an error occured, return the error code returned by GetLastError(),
  327. // otherwise return ERROR_SUCCESS.
  328. //
  329. APIERR
  330. CFileMgmtComponentData::Service_EOpenScManager(LPCTSTR pszMachineName)
  331. {
  332. Endorse(pszMachineName == NULL); // TRUE => Local machine
  333. Assert(m_hScManager == NULL && "Service Control Manager should not have been opened yet");
  334. APIERR dwErr = ERROR_SUCCESS;
  335. if (pszMachineName != NULL)
  336. {
  337. // 581209-2002/03/04 JonN handle L"\\" case
  338. if (pszMachineName[0] == _T('\\') && pszMachineName[1] == _T('\\'))
  339. {
  340. // Get rid of the \\ at the beginning of machine name
  341. pszMachineName += 2;
  342. }
  343. if (pszMachineName[0] == _T('\0'))
  344. pszMachineName = NULL; // Empty string == Local Machine
  345. }
  346. CWaitCursor wait;
  347. m_hScManager = ::OpenSCManager(
  348. pszMachineName,
  349. NULL,
  350. SC_MANAGER_ENUMERATE_SERVICE);
  351. if (m_hScManager == NULL)
  352. {
  353. dwErr = ::GetLastError();
  354. TRACE3("CFileMgmtComponentData::Service_OpenScManager() - "
  355. _T("Unable to open Service Control Manager database on machine %s. err=%d (0x%X).\n"),
  356. (pszMachineName != NULL) ? pszMachineName : _T("LocalMachine"), dwErr, dwErr);
  357. }
  358. return dwErr;
  359. } // CFileMgmtComponentData::Service_EOpenScManager()
  360. /////////////////////////////////////////////////////////////////////
  361. void
  362. CFileMgmtComponentData::Service_CloseScManager()
  363. {
  364. if (m_hScManager != NULL)
  365. {
  366. CWaitCursor wait; // Auto-wait cursor
  367. (void)::CloseServiceHandle(m_hScManager);
  368. m_hScManager = NULL;
  369. }
  370. } // CFileMgmtComponentData::Service_CloseScManager()
  371. /////////////////////////////////////////////////////////////////////
  372. // CFileMgmtComponentData::Service_PopulateServices()
  373. //
  374. // Enumerate all available services and display them
  375. // into the listview control.
  376. //
  377. // 12/03/98 JonN With the mark-and-sweep change, this no longer adds the items
  378. // the the view
  379. //
  380. HRESULT
  381. CFileMgmtComponentData::Service_PopulateServices(LPRESULTDATA pResultData, CFileMgmtScopeCookie* pcookie)
  382. {
  383. AFX_MANAGE_STATE(AfxGetStaticModuleState( )); // required for CWaitCursor
  384. TEST_NONNULL_PTR_PARAM(pResultData);
  385. TEST_NONNULL_PTR_PARAM(pcookie);
  386. DWORD cbBytesNeeded = 0; // Number of necessary bytes to return all service entries
  387. DWORD dwServicesReturned = 0; // Number of services returned
  388. DWORD dwResumeHandle = 0;
  389. BOOL fRet;
  390. DWORD dwErr = ERROR_SUCCESS;
  391. if (m_hScManager == NULL)
  392. {
  393. dwErr = Service_EOpenScManager(pcookie->QueryTargetServer());
  394. }
  395. if (m_hScManager == NULL)
  396. {
  397. Assert(dwErr != ERROR_SUCCESS);
  398. DoServicesErrMsgBox(::GetActiveWindow(), MB_OK | MB_ICONEXCLAMATION, dwErr,
  399. IDS_MSG_s_UNABLE_TO_OPEN_SERVICE_DATABASE, pcookie->QueryNonNULLMachineName());
  400. return S_OK;
  401. }
  402. //
  403. // The idea here is to ask the enum Api how much memory is
  404. // needed to enumerate all services.
  405. //
  406. {
  407. CWaitCursor wait; // Auto-wait cursor
  408. fRet = ::EnumServicesStatus(
  409. m_hScManager,
  410. SERVICE_WIN32, // Type of services to enumerate
  411. SERVICE_ACTIVE | SERVICE_INACTIVE, // State of services to enumerate
  412. NULL, // Pointer to service status buffer
  413. 0, // Size of service status buffer
  414. OUT &cbBytesNeeded, // Number of necessary bytes to return the remaining service entries
  415. OUT &dwServicesReturned, // Number returned services
  416. OUT &dwResumeHandle); // Pointer to variable for next entry (unused)
  417. }
  418. Report(fRet == FALSE); // First attempt should fail
  419. Report(cbBytesNeeded > 0);
  420. // Add room for 10 extra services (just in case)
  421. cbBytesNeeded += 10 * sizeof(ENUM_SERVICE_STATUS);
  422. // Allocate memory for the enumeration
  423. ENUM_SERVICE_STATUS * prgESS = (ENUM_SERVICE_STATUS *) new BYTE[cbBytesNeeded];
  424. //
  425. // Now call the enum Api to retreive the services
  426. //
  427. {
  428. CWaitCursor wait; // Auto-wait cursor
  429. fRet = ::EnumServicesStatus(
  430. m_hScManager,
  431. SERVICE_WIN32, // Type of services to enumerate
  432. SERVICE_ACTIVE | SERVICE_INACTIVE, // State of services to enumerate
  433. OUT prgESS, // Pointer to service status buffer
  434. IN cbBytesNeeded, // Size of service status buffer
  435. OUT &cbBytesNeeded, // Number of necessary bytes to return the remaining service entries
  436. OUT &dwServicesReturned, // Number of sercvices returned
  437. OUT &dwResumeHandle); // Pointer to variable for next entry
  438. dwErr = ::GetLastError();
  439. }
  440. if (!fRet)
  441. {
  442. Assert(dwErr != ERROR_SUCCESS);
  443. DoServicesErrMsgBox(::GetActiveWindow(), MB_OK | MB_ICONEXCLAMATION, dwErr,
  444. IDS_MSG_s_UNABLE_TO_READ_SERVICES, pcookie->QueryNonNULLMachineName());
  445. delete prgESS;
  446. return S_OK; // PREFIX ISSUE-2002/04/15-JonN should delete[] as BYTE*
  447. }
  448. {
  449. CWaitCursor wait; // Auto-wait cursor
  450. // Add the services to listview
  451. Service_AddServiceItems(pResultData, pcookie, prgESS, dwServicesReturned);
  452. delete prgESS; // PREFIX ISSUE-2002/04/15-JonN should delete[] as BYTE*
  453. }
  454. return S_OK;
  455. } // CFileMgmtComponentData::Service_PopulateServices()
  456. /////////////////////////////////////////////////////////////////////
  457. // CFileMgmtComponentData::Service_AddServiceItems()
  458. //
  459. // Insert service items to the result pane (listview control).
  460. //
  461. // 12/03/98 JonN With the mark-and-sweep change, this no longer adds the items
  462. // the the view
  463. // 04/07/02 JonN 544137: Rebuilt this function to handle extralong return buffers
  464. //
  465. HRESULT
  466. CFileMgmtComponentData::Service_AddServiceItems(
  467. LPRESULTDATA /*pResultData*/,
  468. CFileMgmtScopeCookie * pParentCookie,
  469. ENUM_SERVICE_STATUS * prgESS, // IN: Array of structures of services
  470. DWORD nDataItems) // IN: Number of structures in prgESS
  471. {
  472. Assert(pParentCookie != NULL);
  473. Assert(prgESS != NULL);
  474. CString str;
  475. BOOL fResult;
  476. ASSERT(m_hScManager != NULL); // Service control manager should be already opened
  477. DWORD cbActiveBufferSize = max(max(sizeof(QUERY_SERVICE_CONFIG),
  478. SERVICE_cbQueryServiceConfigMax),
  479. max(sizeof(SERVICE_DESCRIPTION),
  480. SERVICE_cchDescriptionMax * sizeof(TCHAR) + 16));
  481. LPBYTE pActiveBuffer = new BYTE[cbActiveBufferSize];
  482. if (NULL == pActiveBuffer)
  483. {
  484. ASSERT(FALSE);
  485. return ERROR_NOT_ENOUGH_MEMORY;
  486. }
  487. for ( ; nDataItems > 0; nDataItems--, prgESS++ )
  488. {
  489. /*
  490. ** Add one line per service
  491. */
  492. // Open service to get its configuration
  493. SC_HANDLE hService = ::OpenService(
  494. m_hScManager,
  495. prgESS->lpServiceName,
  496. SERVICE_QUERY_CONFIG);
  497. if (hService == NULL)
  498. {
  499. TRACE2("Failed to open service %s. err=%u.\n",
  500. prgESS->lpServiceName, ::GetLastError());
  501. }
  502. // Query config description
  503. DWORD cbBytesNeeded = 0;
  504. CString strDescription;
  505. if (m_fQueryServiceConfig2 && NULL != hService)
  506. {
  507. // We only call this API if it is supported by target machine
  508. // JonN-2002/04/04-544089 ensure NULL-termination
  509. ::ZeroMemory(pActiveBuffer, cbActiveBufferSize);
  510. fResult = ::MyQueryServiceConfig2(
  511. &m_fQueryServiceConfig2,
  512. hService,
  513. SERVICE_CONFIG_DESCRIPTION,
  514. OUT pActiveBuffer,
  515. cbActiveBufferSize,
  516. OUT &cbBytesNeeded);
  517. if ( !fResult
  518. && m_fQueryServiceConfig2
  519. && ERROR_INSUFFICIENT_BUFFER == ::GetLastError())
  520. {
  521. if (cbBytesNeeded <= cbActiveBufferSize
  522. || cbBytesNeeded > 100000)
  523. {
  524. ASSERT(FALSE); // inappropriate size request
  525. }
  526. else
  527. { // try to reallocate larger buffer
  528. LPBYTE pNewActiveBuffer = new BYTE[cbBytesNeeded+1000];
  529. if (NULL == pNewActiveBuffer)
  530. {
  531. Report("FILEMGMT: Cannot reallocate MyQueryServiceConfig2 buffer: out of memory");
  532. }
  533. else
  534. { // larger buffer allocated, start using it
  535. delete[] pActiveBuffer;
  536. pActiveBuffer = pNewActiveBuffer;
  537. cbActiveBufferSize = cbBytesNeeded+1000;
  538. // retry API
  539. ::ZeroMemory(pActiveBuffer, cbActiveBufferSize);
  540. cbBytesNeeded = 0;
  541. fResult = ::MyQueryServiceConfig2(
  542. &m_fQueryServiceConfig2,
  543. hService,
  544. SERVICE_CONFIG_DESCRIPTION,
  545. OUT pActiveBuffer,
  546. cbActiveBufferSize,
  547. OUT &cbBytesNeeded);
  548. } // larger buffer allocated
  549. } // appropriate size request
  550. } // ERROR_INSUFFICIENT_BUFFER
  551. if (!fResult)
  552. {
  553. if (!m_fQueryServiceConfig2)
  554. {
  555. // the local machine does not support QueryServiceConfig2
  556. // CODEWORK How could we get here anyhow? JonN 1/31/97
  557. }
  558. else
  559. {
  560. // This is probably because the target machine is running
  561. // an older version of NT not supporting this API.
  562. DWORD dwErr = ::GetLastError();
  563. TRACE2("QueryServiceConfig2(%s) failed. err=%u.\n",
  564. prgESS->lpServiceName, dwErr);
  565. TRACE1("INFO: Machine %s does not support QueryServiceConfig2() API.\n",
  566. pParentCookie->QueryTargetServer() ? pParentCookie->QueryTargetServer() : _T("(Local)"));
  567. Report(dwErr == RPC_S_PROCNUM_OUT_OF_RANGE &&
  568. "Unusual Situation: Expected error should be RPC_S_PROCNUM_OUT_OF_RANGE");
  569. Report(m_fQueryServiceConfig2 != FALSE && "How can this happen???");
  570. m_fQueryServiceConfig2 = FALSE;
  571. }
  572. }
  573. else // fResult is true
  574. {
  575. // MyQueryServiceConfig2 succeeded
  576. // We limit the length of the service description to 1000 characters
  577. // otherwise mmc.exe will AV.
  578. // CODEWORK remove this when the bug is fixed in MMC
  579. SERVICE_DESCRIPTION* psd = (SERVICE_DESCRIPTION*)pActiveBuffer;
  580. if (NULL != psd->lpDescription)
  581. {
  582. if (lstrlen(psd->lpDescription) >= 1000)
  583. {
  584. TRACE1("INFO: Description of service %s is too long. Only the first 1000 characters will be displayed.\n", prgESS->lpServiceName);
  585. psd->lpDescription[1000] = _T('\0');
  586. }
  587. strDescription = psd->lpDescription;
  588. } // if (NULL != psd->lpDescription)
  589. } // if (fResult is true)
  590. } // if (m_fQueryServiceConfig2 && NULL != hService)
  591. // Query service config
  592. // This might fail e.g. if insufficient permissions
  593. BOOL fQSCResult = FALSE;
  594. QUERY_SERVICE_CONFIG* pqsc = (QUERY_SERVICE_CONFIG*)pActiveBuffer;
  595. if (NULL != hService)
  596. {
  597. cbBytesNeeded = 0;
  598. ::ZeroMemory(pActiveBuffer, cbActiveBufferSize);
  599. fQSCResult = ::QueryServiceConfig(
  600. hService,
  601. OUT pqsc,
  602. cbActiveBufferSize,
  603. OUT &cbBytesNeeded);
  604. // JonN-2002/04/04-544089 handle long DisplayName value
  605. if (!fQSCResult && ERROR_INSUFFICIENT_BUFFER == ::GetLastError())
  606. {
  607. if (cbBytesNeeded <= cbActiveBufferSize
  608. || cbBytesNeeded > 100000)
  609. {
  610. ASSERT(FALSE); // inappropriate size request
  611. }
  612. else
  613. { // try to reallocate larger buffer
  614. LPBYTE pNewActiveBuffer = new BYTE[cbBytesNeeded+1000];
  615. if (NULL == pNewActiveBuffer)
  616. {
  617. Report("FILEMGMT: Cannot reallocate QueryServiceConfig buffer: out of memory");
  618. }
  619. else
  620. { // larger buffer allocated, start using it
  621. delete[] pActiveBuffer;
  622. pActiveBuffer = pNewActiveBuffer;
  623. cbActiveBufferSize = cbBytesNeeded+1000;
  624. // retry API
  625. ::ZeroMemory(pActiveBuffer, cbActiveBufferSize);
  626. cbBytesNeeded = 0;
  627. pqsc = (QUERY_SERVICE_CONFIG*)pActiveBuffer;
  628. cbBytesNeeded = 0;
  629. ::ZeroMemory(pActiveBuffer, cbActiveBufferSize);
  630. fQSCResult = ::QueryServiceConfig(
  631. hService,
  632. OUT pqsc,
  633. cbActiveBufferSize,
  634. OUT &cbBytesNeeded);
  635. } // larger buffer allocated
  636. } // appropriate size request
  637. } // ERROR_INSUFFICIENT_BUFFER
  638. } // if (NULL != hService)
  639. // Add the first column
  640. CNewServiceCookie * pnewcookie = new CNewServiceCookie;
  641. pnewcookie->m_strServiceName = prgESS->lpServiceName;
  642. pnewcookie->m_strDisplayName = prgESS->lpDisplayName;
  643. pnewcookie->m_strDescription = strDescription;
  644. pnewcookie->m_dwState = prgESS->ServiceStatus.dwCurrentState;
  645. pnewcookie->m_dwStartType =
  646. ((!fQSCResult) ? (DWORD)-1 : pqsc->dwStartType);
  647. // JonN 4/11/00 17756: The description of "Account Run under" is unlocalized.
  648. // Display empty string instead of "LocalSystem"
  649. pnewcookie->m_strStartName =
  650. ((!fQSCResult || !lstrcmpi(L"LocalSystem",pqsc->lpServiceStartName))
  651. ? NULL : pqsc->lpServiceStartName);
  652. pnewcookie->SetMachineName( pParentCookie->QueryTargetServer() );
  653. pParentCookie->ScanAndAddResultCookie( pnewcookie );
  654. if (NULL != hService)
  655. {
  656. VERIFY(::CloseServiceHandle(hService));
  657. }
  658. } // for
  659. if (pActiveBuffer)
  660. delete[] pActiveBuffer;
  661. return S_OK;
  662. } // CFileMgmtComponentData::Service_AddServiceItems()
  663. /////////////////////////////////////////////////////////////////////
  664. // CFileMgmtComponentData::Service_FGetServiceInfoFromIDataObject()
  665. //
  666. // Extract 'machine name', 'service name' and/or 'service display name'
  667. // from the data object.
  668. //
  669. // Return FALSE if data could not be retrived, otherwise return TRUE.
  670. //
  671. BOOL
  672. CFileMgmtComponentData::Service_FGetServiceInfoFromIDataObject(
  673. IDataObject * pDataObject, // IN: Data object
  674. CString * pstrMachineName, // OUT: OPTIONAL: Machine name
  675. CString * pstrServiceName, // OUT: OPTIONAL: Service name
  676. CString * pstrServiceDisplayName) // OUT: OPTIONAL: Service display name
  677. {
  678. // ISSUE-2002/03/05-JonN should handle this case better
  679. Assert(pDataObject != NULL);
  680. Endorse(pstrMachineName == NULL);
  681. Endorse(pstrServiceName == NULL);
  682. Endorse(pstrServiceDisplayName == NULL);
  683. HRESULT hr;
  684. BOOL fSuccess = TRUE;
  685. if (pstrMachineName != NULL)
  686. {
  687. // Get the machine name (computer name) from IDataObject
  688. hr = ::ExtractString(
  689. pDataObject,
  690. CFileMgmtDataObject::m_CFMachineName,
  691. OUT pstrMachineName,
  692. DNS_MAX_NAME_BUFFER_LENGTH);
  693. if (FAILED(hr))
  694. {
  695. TRACE0("CFileMgmtComponentData::Service_FGetServiceInfoFromIDataObject() - Failed to get machine name.\n");
  696. fSuccess = FALSE;
  697. }
  698. } // if
  699. if (pstrServiceName != NULL)
  700. {
  701. // Get the service name from IDataObject
  702. hr = ::ExtractString(
  703. pDataObject,
  704. CFileMgmtDataObject::m_CFServiceName,
  705. OUT pstrServiceName,
  706. 255);
  707. if (FAILED(hr) || pstrServiceName->IsEmpty())
  708. {
  709. TRACE0("CFileMgmtComponentData::Service_FGetServiceInfoFromIDataObject() - Failed to get service name.\n");
  710. fSuccess = FALSE;
  711. }
  712. } // if
  713. if (pstrServiceDisplayName != NULL)
  714. {
  715. // Get the service display name from IDataObject
  716. hr = ::ExtractString(
  717. pDataObject,
  718. CFileMgmtDataObject::m_CFServiceDisplayName,
  719. OUT pstrServiceDisplayName,
  720. 255);
  721. if (FAILED(hr) || pstrServiceDisplayName->IsEmpty())
  722. {
  723. TRACE0("CFileMgmtComponentData::Service_FGetServiceInfoFromIDataObject() - Failed to get service display name\n");
  724. fSuccess = FALSE;
  725. }
  726. } // if
  727. return fSuccess;
  728. } // CFileMgmtComponentData::Service_FGetServiceInfoFromIDataObject()
  729. /////////////////////////////////////////////////////////////////////
  730. // CFileMgmtComponentData::Service_FAddMenuItems()
  731. //
  732. // Add menuitems to the service context menu.
  733. // The same routine will be used to extend context menus of
  734. // others snapins who wants to have "Start", "Stop", "Pause",
  735. // "Resume" and "Restart" menuitems.
  736. //
  737. // Return TRUE if successful, otherwise FALSE.
  738. //
  739. BOOL
  740. CFileMgmtComponentData::Service_FAddMenuItems(
  741. IContextMenuCallback * pContextMenuCallback, // OUT: Object to append menuitems
  742. IDataObject * pDataObject, // IN: Data object
  743. BOOL fIs3rdPartyContextMenuExtension) // IN: TRUE => Add the menu items as a 3rd party extension
  744. {
  745. AFX_MANAGE_STATE(AfxGetStaticModuleState( )); // required for CWaitCursor
  746. Assert(pContextMenuCallback != NULL);
  747. Assert(pDataObject != NULL);
  748. Endorse(m_hScManager == NULL); // TRUE => Network connection was broken
  749. CString strMachineName;
  750. CString strServiceName;
  751. CString strServiceDisplayName;
  752. BOOL fSuccess = TRUE;
  753. if (!Service_FGetServiceInfoFromIDataObject(
  754. pDataObject,
  755. OUT &strMachineName,
  756. OUT &strServiceName,
  757. OUT &strServiceDisplayName))
  758. {
  759. TRACE0("CFileMgmtComponentData::Service_FAddMenuItems() - Unable to query IDataObject for correct clipboard format.\n");
  760. return FALSE;
  761. }
  762. if (fIs3rdPartyContextMenuExtension)
  763. {
  764. Assert(m_hScManager == NULL);
  765. // ISSUE-2002/03/05-JonN should use CWaitCursor
  766. if (m_hScManager == NULL)
  767. (void)Service_EOpenScManager(strMachineName);
  768. }
  769. BOOL rgfMenuFlags[iServiceActionMax];
  770. {
  771. //
  772. // Get the menu flags
  773. //
  774. CWaitCursor wait;
  775. if (!Service_FGetServiceButtonStatus(
  776. m_hScManager,
  777. strServiceName,
  778. OUT rgfMenuFlags,
  779. NULL, // pdwCurrentState
  780. TRUE)) // fSilentError
  781. {
  782. // Nothing to do here
  783. }
  784. }
  785. if (strMachineName.IsEmpty())
  786. strMachineName = g_strLocalMachine;
  787. if (strServiceDisplayName.IsEmpty())
  788. strServiceDisplayName = g_strUnknown;
  789. CString strMenuItem;
  790. CString strStatusBar;
  791. CComQIPtr<IContextMenuCallback2, &IID_IContextMenuCallback2>
  792. spContextMenuCallback2 = pContextMenuCallback;
  793. // Add the menu items
  794. for (INT i = iServiceActionStart; i < iServiceActionMax; i++)
  795. {
  796. LoadStringWithInsertions(IDS_SVC_MENU_SERVICE_START + i, OUT &strMenuItem);
  797. LoadStringWithInsertions(IDS_SVC_STATUSBAR_ss_SERVICE_START + i,
  798. OUT &strStatusBar,
  799. (LPCTSTR)strServiceDisplayName,
  800. (LPCTSTR)strMachineName);
  801. CONTEXTMENUITEM2 contextmenuitem;
  802. ::ZeroMemory(OUT &contextmenuitem, sizeof(contextmenuitem));
  803. // ISSUE-2002/03/05-JonN remote USES_CONVERSION and T2OLE
  804. // I don't trust this, doesn't T2OLE reuse a global buffer?
  805. USES_CONVERSION;
  806. contextmenuitem.strName = T2OLE(const_cast<LPTSTR>((LPCTSTR)strMenuItem));
  807. contextmenuitem.strStatusBarText = T2OLE(const_cast<LPTSTR>((LPCTSTR)strStatusBar));
  808. contextmenuitem.lCommandID = cmServiceStart + i;
  809. contextmenuitem.lInsertionPointID = fIs3rdPartyContextMenuExtension ? CCM_INSERTIONPOINTID_3RDPARTY_TASK : CCM_INSERTIONPOINTID_PRIMARY_TOP;
  810. contextmenuitem.fFlags = rgfMenuFlags[i] ? MF_ENABLED : MF_GRAYED;
  811. // JonN 4/18/00 Explorer View requires Callback2
  812. static LPTSTR astrLanguageIndependentMenuNames[iServiceActionMax] =
  813. { _T("Start"),
  814. _T("Stop"),
  815. _T("Pause"),
  816. _T("Resume"),
  817. _T("Restart")
  818. };
  819. contextmenuitem.strLanguageIndependentName =
  820. astrLanguageIndependentMenuNames[i];
  821. HRESULT hr = S_OK;
  822. if (spContextMenuCallback2)
  823. hr = spContextMenuCallback2->AddItem( &contextmenuitem );
  824. else
  825. hr = pContextMenuCallback->AddItem( (CONTEXTMENUITEM*)(&contextmenuitem) );
  826. ASSERT( SUCCEEDED(hr) && "Unable to add menu item" );
  827. if ( !fIs3rdPartyContextMenuExtension )
  828. {
  829. contextmenuitem.lInsertionPointID = CCM_INSERTIONPOINTID_PRIMARY_TASK;
  830. if (spContextMenuCallback2)
  831. hr = spContextMenuCallback2->AddItem( &contextmenuitem );
  832. else
  833. hr = pContextMenuCallback->AddItem( (CONTEXTMENUITEM*)(&contextmenuitem) );
  834. ASSERT( SUCCEEDED(hr) && "Unable to add menu item" );
  835. }
  836. } // for
  837. return fSuccess;
  838. } // CFileMgmtComponentData::Service_FAddMenuItems()
  839. /////////////////////////////////////////////////////////////////////
  840. // CFileMgmtComponentData::Service_FDispatchMenuCommand()
  841. //
  842. // Dispatch a menu command for a given service
  843. //
  844. // Return TRUE if result pane need to be updated, otherwise FALSE.
  845. //
  846. // We might get a cmStart command on a paused service, if the command
  847. // came from the toolbar. For that matter, we might get a command
  848. // on a non-service, until we fix the toolbar button updating.
  849. //
  850. BOOL
  851. CFileMgmtComponentData::Service_FDispatchMenuCommand(
  852. INT nCommandId,
  853. IDataObject * pDataObject)
  854. {
  855. Assert(pDataObject != NULL);
  856. Endorse(m_hScManager == NULL);
  857. CString strMachineName;
  858. CString strServiceName;
  859. CString strServiceDisplayName;
  860. DWORD dwLastError;
  861. if (!Service_FGetServiceInfoFromIDataObject(
  862. pDataObject,
  863. OUT &strMachineName,
  864. OUT &strServiceName,
  865. OUT &strServiceDisplayName))
  866. {
  867. TRACE0("CFileMgmtComponentData::Service_FDispatchMenuCommand() - Unable to read data from IDataObject.\n");
  868. return FALSE;
  869. }
  870. if (m_hScManager == NULL)
  871. {
  872. TRACE0("CFileMgmtComponentData::Service_FDispatchMenuCommand() - Handle m_hScManager is NULL.\n");
  873. return FALSE;
  874. }
  875. if (nCommandId == cmServiceStart || nCommandId == cmServiceStartTask )
  876. {
  877. dwLastError = CServiceControlProgress::S_EStartService(
  878. ::GetActiveWindow(),
  879. m_hScManager,
  880. strMachineName,
  881. strServiceName,
  882. strServiceDisplayName,
  883. 0,
  884. NULL); // no startup parameters passed from menu command
  885. }
  886. else
  887. {
  888. DWORD dwControlCode;
  889. switch (nCommandId)
  890. {
  891. default:
  892. Assert(FALSE); // fall through
  893. case cmServiceStop:
  894. case cmServiceStopTask:
  895. dwControlCode = SERVICE_CONTROL_STOP;
  896. break;
  897. case cmServicePause:
  898. case cmServicePauseTask:
  899. dwControlCode = SERVICE_CONTROL_PAUSE;
  900. break;
  901. case cmServiceResume:
  902. case cmServiceResumeTask:
  903. dwControlCode = SERVICE_CONTROL_CONTINUE;
  904. break;
  905. case cmServiceRestart:
  906. case cmServiceRestartTask:
  907. dwControlCode = SERVICE_CONTROL_RESTART;
  908. break;
  909. } // switch
  910. dwLastError = CServiceControlProgress::S_EControlService(
  911. ::GetActiveWindow(),
  912. m_hScManager,
  913. strMachineName,
  914. strServiceName,
  915. strServiceDisplayName,
  916. dwControlCode);
  917. } // if...else
  918. // We do want to to keep the connection opened
  919. return (dwLastError != CServiceControlProgress::errUserCancelStopDependentServices);
  920. } // CFileMgmtComponentData::Service_FDispatchMenuCommand()
  921. /////////////////////////////////////////////////////////////////////
  922. // CFileMgmtComponentData::Service_FInsertPropertyPages()
  923. //
  924. // Insert property pages of the data object (service).
  925. //
  926. // Return TRUE if successful, otherwise FALSE.
  927. //
  928. // IMPLEMENTATION NOTES
  929. // The routine allocates a CServicePropertyData object which
  930. // is auto-deleted by the property sheet. The property sheet will
  931. // delete the CServicePropertyData object on its WM_DESTROY message.
  932. //
  933. BOOL
  934. CFileMgmtComponentData::Service_FInsertPropertyPages(
  935. LPPROPERTYSHEETCALLBACK pCallBack, // OUT: Object to append property pages
  936. IDataObject * pDataObject, // IN: Data object
  937. LONG_PTR lNotifyHandle) // IN: Handle to notify the parent
  938. {
  939. Assert(pCallBack != NULL);
  940. Assert(pDataObject != NULL);
  941. Endorse(m_hScManager != NULL);
  942. if (m_hScManager == NULL)
  943. {
  944. // Typically because network connection was broken
  945. TRACE0("INFO: m_hScManager is NULL.\n");
  946. return FALSE;
  947. }
  948. CString strMachineName;
  949. CString strServiceName;
  950. CString strServiceDisplayName;
  951. if (!Service_FGetServiceInfoFromIDataObject(
  952. pDataObject,
  953. OUT &strMachineName,
  954. OUT &strServiceName,
  955. OUT &strServiceDisplayName))
  956. {
  957. Assert(FALSE);
  958. return FALSE;
  959. }
  960. CServicePropertyData * pSPD = new CServicePropertyData;
  961. if (!pSPD->FInit(
  962. pDataObject,
  963. strMachineName,
  964. strServiceName,
  965. strServiceDisplayName,
  966. lNotifyHandle))
  967. {
  968. TRACE1("Failure to query service %s.\n", (LPCTSTR)strServiceName);
  969. delete pSPD;
  970. return FALSE;
  971. }
  972. return pSPD->CreatePropertyPages(pCallBack);
  973. } // CFileMgmtComponentData::Service_FInsertPropertyPages()
  974. #ifdef SNAPIN_PROTOTYPER
  975. #include "protyper.cpp"
  976. #endif