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.

1202 lines
32 KiB

  1. // *********************************************************************************
  2. //
  3. // Copyright (c) Microsoft Corporation
  4. //
  5. // Module Name:
  6. //
  7. // TaskList.cpp
  8. //
  9. // Abstract:
  10. //
  11. // This module implements the command-line parsing the displaying the tasks
  12. // information current running on local and remote systems
  13. //
  14. // Syntax:
  15. // ------
  16. // TaskList.exe [-s server [-u username [-p password]]]
  17. // [-fo format] [-fi filter] [-nh] [-v | -svc | -m]
  18. //
  19. // Author:
  20. //
  21. // Sunil G.V.N. Murali ([email protected]) 24-Sep-2000
  22. //
  23. // Revision History:
  24. //
  25. // Sunil G.V.N. Murali ([email protected]) 24-Sep-2000 : Created It.
  26. //
  27. // *********************************************************************************
  28. #include "pch.h"
  29. #include "wmi.h"
  30. #include "TaskList.h"
  31. //
  32. // local structures
  33. //
  34. typedef struct __tagWindowTitles
  35. {
  36. LPWSTR lpDesk;
  37. LPWSTR lpWinsta;
  38. BOOL bFirstLoop;
  39. TARRAY arrWindows;
  40. } TWINDOWTITLES, *PTWINDOWTITLES;
  41. //
  42. // private functions ... prototypes
  43. //
  44. BOOL CALLBACK EnumWindowsProc( HWND hWnd, LPARAM lParam );
  45. BOOL CALLBACK EnumDesktopsFunc( LPWSTR lpstr, LPARAM lParam );
  46. BOOL CALLBACK EnumWindowStationsFunc( LPWSTR lpstr, LPARAM lParam );
  47. BOOL CALLBACK EnumMessageWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam );
  48. BOOL GetPerfDataBlock( HKEY hKey, LPWSTR szObjectIndex, PPERF_DATA_BLOCK* ppdb );
  49. // ***************************************************************************
  50. // Routine Description:
  51. // This the entry point to this utility.
  52. //
  53. // Arguments:
  54. // [ in ] argc : argument(s) count specified at the command prompt
  55. // [ in ] argv : argument(s) specified at the command prompt
  56. //
  57. // Return Value:
  58. // The below are actually not return values but are the exit values
  59. // returned to the OS by this application
  60. // 0 : utility is successfull
  61. // 1 : utility failed
  62. // ***************************************************************************
  63. DWORD __cdecl _tmain( DWORD argc, LPCWSTR argv[] )
  64. {
  65. // local variables
  66. CTaskList tasklist;
  67. // initialize the tasklist utility
  68. if ( tasklist.Initialize() == FALSE )
  69. {
  70. SHOW_MESSAGE_EX( TAG_ERROR, GetReason() );
  71. EXIT_PROCESS( 1 );
  72. }
  73. // now do parse the command line options
  74. if ( tasklist.ProcessOptions( argc, argv ) == FALSE )
  75. {
  76. SHOW_MESSAGE_EX( TAG_ERROR, GetReason() );
  77. EXIT_PROCESS( 1 );
  78. }
  79. // check whether usage has to be displayed or not
  80. if ( tasklist.m_bUsage == TRUE )
  81. {
  82. // show the usage of the utility
  83. tasklist.Usage();
  84. // quit from the utility
  85. EXIT_PROCESS( 0 );
  86. }
  87. // now validate the filters and check the result of the filter validation
  88. if ( tasklist.ValidateFilters() == FALSE )
  89. {
  90. // invalid filter
  91. SHOW_MESSAGE_EX( TAG_ERROR, GetReason() );
  92. // quit from the utility
  93. EXIT_PROCESS( 1 );
  94. }
  95. // connect to the server
  96. if ( tasklist.Connect() == FALSE )
  97. {
  98. // show the error message
  99. SHOW_MESSAGE_EX( TAG_ERROR, GetReason() );
  100. EXIT_PROCESS( 1 );
  101. }
  102. // load the data and check
  103. if ( tasklist.LoadTasks() == FALSE )
  104. {
  105. // show the error message
  106. SHOW_MESSAGE_EX( TAG_ERROR, GetReason() );
  107. // exit
  108. EXIT_PROCESS( 1 );
  109. }
  110. // now show the tasks running on the machine
  111. if ( tasklist.Show() == 0 )
  112. {
  113. //
  114. // no tasks were shown ... display the message
  115. // check if this is because of any error
  116. if ( GetLastError() != NO_ERROR )
  117. {
  118. SHOW_MESSAGE_EX( TAG_ERROR, GetReason() );
  119. EXIT_PROCESS( 1 );
  120. }
  121. else
  122. {
  123. DISPLAY_MESSAGE( stderr, ERROR_NODATA_AVAILABLE );
  124. }
  125. }
  126. // clean exit
  127. EXIT_PROCESS( 0 );
  128. }
  129. // ***************************************************************************
  130. // Routine Description:
  131. // connects to the remote as well as remote system's WMI
  132. //
  133. // Arguments:
  134. // [ in ] pszServer : remote server name
  135. //
  136. // Return Value:
  137. // TRUE : if connection is successful
  138. // FALSE : if connection is unsuccessful
  139. //
  140. // ***************************************************************************
  141. BOOL CTaskList::Connect()
  142. {
  143. // local variables
  144. BOOL bResult = FALSE;
  145. // release the existing auth identity structure
  146. m_bUseRemote = FALSE;
  147. WbemFreeAuthIdentity( &m_pAuthIdentity );
  148. // connect to WMI
  149. bResult = ConnectWmiEx( m_pWbemLocator,
  150. &m_pWbemServices, m_strServer, m_strUserName, m_strPassword,
  151. &m_pAuthIdentity, m_bNeedPassword, WMI_NAMESPACE_CIMV2, &m_bLocalSystem );
  152. // check the result of connection
  153. if ( bResult == FALSE )
  154. return FALSE;
  155. #ifndef _WIN64
  156. // determine the type of the platform if modules info is required
  157. if ( m_bLocalSystem == TRUE && m_bNeedModulesInfo == TRUE )
  158. {
  159. // sub-local variables
  160. DWORD dwPlatform = 0;
  161. // get the platform type
  162. dwPlatform = GetTargetPlatformEx( m_pWbemServices, m_pAuthIdentity );
  163. // if the platform is not 32-bit, error
  164. if ( dwPlatform != PLATFORM_X86 )
  165. {
  166. // let the tool use WMI calls instead of Win32 API
  167. m_bUseRemote = TRUE;
  168. }
  169. }
  170. #endif
  171. try
  172. {
  173. // check the local credentials and if need display warning
  174. if ( GetLastError() == WBEM_E_LOCAL_CREDENTIALS )
  175. {
  176. CHString str;
  177. WMISaveError( WBEM_E_LOCAL_CREDENTIALS );
  178. str.Format( L"\n%s %s", TAG_WARNING, GetReason() );
  179. ShowMessage( stdout, str );
  180. // get the next cursor position
  181. if ( m_hOutput != NULL )
  182. GetConsoleScreenBufferInfo( m_hOutput, &m_csbi );
  183. }
  184. // check the remote system version and its compatiblity
  185. if ( m_bLocalSystem == FALSE )
  186. {
  187. // check the version compatibility
  188. DWORD dwVersion = 0;
  189. dwVersion = GetTargetVersionEx( m_pWbemServices, m_pAuthIdentity );
  190. if ( IsCompatibleOperatingSystem( dwVersion ) == FALSE )
  191. {
  192. SetReason( ERROR_OS_INCOMPATIBLE );
  193. return FALSE;
  194. }
  195. }
  196. // save the server name
  197. m_strUNCServer = L"";
  198. if ( m_strServer.GetLength() != 0 )
  199. {
  200. // check whether the server name is in UNC format or not .. if not prepare it
  201. m_strUNCServer = m_strServer;
  202. if ( IsUNCFormat( m_strServer ) == FALSE )
  203. m_strUNCServer.Format( L"\\\\%s", m_strServer );
  204. }
  205. }
  206. catch( _com_error& e )
  207. {
  208. WMISaveError( e );
  209. return FALSE;
  210. }
  211. // return the result
  212. return TRUE;
  213. }
  214. // ***************************************************************************
  215. // Routine Description:
  216. // initiate the enumeration
  217. //
  218. // Arguments:
  219. // NONE
  220. //
  221. // Return Value:
  222. // TRUE : if successful
  223. // FALSE : if unsuccessful
  224. //
  225. // ***************************************************************************
  226. BOOL CTaskList::LoadTasks()
  227. {
  228. // local variables
  229. HRESULT hr;
  230. try
  231. {
  232. // check the services object
  233. if ( m_pWbemServices == NULL )
  234. {
  235. SetLastError( STG_E_UNKNOWN );
  236. SaveLastError();
  237. return FALSE;
  238. }
  239. // load the tasks from WMI based on generated query
  240. SAFE_RELEASE( m_pEnumObjects );
  241. hr = m_pWbemServices->ExecQuery( _bstr_t( WMI_QUERY_TYPE ), _bstr_t( m_strQuery ),
  242. WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, &m_pEnumObjects );
  243. // check the result of the ExecQuery
  244. if ( FAILED( hr ) )
  245. {
  246. WMISaveError( hr );
  247. return FALSE;
  248. }
  249. // set the interface security and check the result
  250. hr = SetInterfaceSecurity( m_pEnumObjects, m_pAuthIdentity );
  251. if ( FAILED( hr ) )
  252. {
  253. WMISaveError( hr );
  254. return FALSE;
  255. }
  256. // remove the current window titles information
  257. DynArrayRemoveAll( m_arrWindowTitles );
  258. // for the local system, enumerate the window titles of the processes
  259. // there is no provision for collecting the window titles of remote processes
  260. if ( m_bLocalSystem == TRUE && m_bNeedWindowTitles == TRUE )
  261. {
  262. // prepare the tasks list info
  263. TWINDOWTITLES windowtitles;
  264. windowtitles.lpDesk = NULL;
  265. windowtitles.lpWinsta = NULL;
  266. windowtitles.bFirstLoop = FALSE;
  267. windowtitles.arrWindows = m_arrWindowTitles;
  268. EnumWindowStations( EnumWindowStationsFunc, ( LPARAM ) &windowtitles );
  269. // free the memory allocated with _tcsdup string function
  270. if ( windowtitles.lpDesk != NULL )
  271. free( windowtitles.lpDesk );
  272. if ( windowtitles.lpWinsta != NULL )
  273. free( windowtitles.lpWinsta );
  274. }
  275. // load the extended tasks information
  276. LoadTasksEx(); // NOTE: here we are not much bothered abt the return value
  277. // erase the status messages
  278. PrintProgressMsg( m_hOutput, NULL, m_csbi );
  279. }
  280. catch( _com_error& e )
  281. {
  282. WMISaveError( e );
  283. return FALSE;
  284. }
  285. // return success
  286. return TRUE;
  287. }
  288. // ***************************************************************************
  289. // Routine Description:
  290. //
  291. // Arguments:
  292. //
  293. // Return Value:
  294. //
  295. // ***************************************************************************
  296. BOOL CTaskList::LoadTasksEx()
  297. {
  298. // local variables
  299. BOOL bResult = FALSE;
  300. // init
  301. m_bCloseConnection = FALSE;
  302. // we need to use NET API only in case connecting to the remote system
  303. // with credentials information i.e; m_pAuthIdentity is not NULL
  304. if ( m_bLocalSystem == FALSE && m_pAuthIdentity != NULL )
  305. {
  306. // sub-local variables
  307. DWORD dwConnect = 0;
  308. LPCWSTR pwszUser = NULL;
  309. LPCWSTR pwszPassword = NULL;
  310. // identify the password to connect to the remote system
  311. pwszPassword = m_pAuthIdentity->Password;
  312. if ( m_strUserName.GetLength() != 0 )
  313. pwszUser = m_strUserName;
  314. // establish connection to the remote system using NET API
  315. // this we need to do only for remote system
  316. dwConnect = NO_ERROR;
  317. m_bCloseConnection = TRUE;
  318. dwConnect = ConnectServer( m_strUNCServer, pwszUser, pwszPassword );
  319. if ( dwConnect != NO_ERROR )
  320. {
  321. // connection should not be closed .. this is because we didn't establish the connection
  322. m_bCloseConnection = FALSE;
  323. // this might be 'coz of the conflict in the credentials ... check that
  324. if ( dwConnect != ERROR_SESSION_CREDENTIAL_CONFLICT )
  325. {
  326. // return failure
  327. return FALSE;
  328. }
  329. }
  330. // check the whether we need to close the connection or not
  331. // if user name is NULL (or) password is NULL then don't close the connection
  332. if ( pwszUser == NULL || pwszPassword == NULL )
  333. m_bCloseConnection = FALSE;
  334. }
  335. try
  336. {
  337. // connect to the remote system's winstation
  338. bResult = TRUE;
  339. m_hServer = SERVERNAME_CURRENT;
  340. if ( m_bLocalSystem == FALSE )
  341. {
  342. // sub-local variables
  343. LPWSTR pwsz = NULL;
  344. // connect to the winsta and check the result
  345. pwsz = m_strUNCServer.GetBuffer( m_strUNCServer.GetLength() );
  346. m_hServer = WinStationOpenServerW( pwsz );
  347. // proceed furthur only if winstation of the remote system is successfully opened
  348. if ( m_hServer == NULL )
  349. bResult = FALSE;
  350. }
  351. }
  352. catch( ... )
  353. {
  354. SetLastError( E_OUTOFMEMORY );
  355. SaveLastError();
  356. return FALSE;
  357. }
  358. // prepare to get the user context info .. if needed
  359. if ( m_bNeedUserContextInfo == TRUE && bResult == TRUE )
  360. {
  361. // get all the process details
  362. m_bIsHydra = FALSE;
  363. bResult = WinStationGetAllProcesses( m_hServer,
  364. GAP_LEVEL_BASIC, &m_ulNumberOfProcesses, (PVOID*) &m_pProcessInfo );
  365. // check the result
  366. if ( bResult == FALSE )
  367. {
  368. // Maybe a Hydra 4 server ?
  369. // Check the return code indicating that the interface is not available.
  370. if ( GetLastError() == RPC_S_PROCNUM_OUT_OF_RANGE )
  371. {
  372. // The new interface is not known
  373. // It must be a Hydra 4 server
  374. // try with the old interface
  375. bResult = WinStationEnumerateProcesses( m_hServer, (PVOID*) &m_pProcessInfo );
  376. // check the result of enumeration
  377. if ( bResult == TRUE )
  378. m_bIsHydra = TRUE;
  379. }
  380. }
  381. }
  382. // check whether we need services info or not
  383. if ( m_bNeedServicesInfo == TRUE )
  384. {
  385. // load the services
  386. bResult = LoadServicesInfo();
  387. // check the result
  388. if ( bResult == FALSE )
  389. return FALSE;
  390. }
  391. // check whether we need modules info or not
  392. if ( m_bNeedModulesInfo == TRUE )
  393. {
  394. // load the modules information
  395. bResult = LoadModulesInfo();
  396. // check the result
  397. if ( bResult == FALSE )
  398. return FALSE;
  399. }
  400. // return
  401. return TRUE;
  402. }
  403. // ***************************************************************************
  404. // Routine Description:
  405. //
  406. // Arguments:
  407. //
  408. // Return Value:
  409. //
  410. // ***************************************************************************
  411. BOOL CTaskList::LoadModulesInfo()
  412. {
  413. // local variables
  414. HKEY hKey;
  415. LONG lReturn = 0;
  416. BOOL bResult = FALSE;
  417. BOOL bImagesObject = FALSE;
  418. BOOL bAddressSpaceObject = FALSE;
  419. PPERF_OBJECT_TYPE pot = NULL;
  420. PPERF_COUNTER_DEFINITION pcd = NULL;
  421. // check whether we need the modules infor or not
  422. // NOTE: we need to load the performance data only in case if user is querying for remote system only
  423. if ( m_bNeedModulesInfo == FALSE || m_bLocalSystem == TRUE )
  424. return TRUE;
  425. // display the status message
  426. PrintProgressMsg( m_hOutput, MSG_MODULESINFO, m_csbi );
  427. // open the remote system performance data key
  428. lReturn = RegConnectRegistry( m_strUNCServer, HKEY_PERFORMANCE_DATA, &hKey );
  429. if ( lReturn != ERROR_SUCCESS )
  430. {
  431. SetLastError( lReturn );
  432. SaveLastError();
  433. return FALSE;
  434. }
  435. // get the performance object ( images )
  436. bResult = GetPerfDataBlock( hKey, L"740", &m_pdb );
  437. if ( bResult == FALSE )
  438. {
  439. // close the registry key and return
  440. RegCloseKey( hKey );
  441. return FALSE;
  442. }
  443. // check the validity of the perf block
  444. if ( StringCompare( m_pdb->Signature, L"PERF", FALSE, 4 ) != 0 )
  445. {
  446. // close the registry key and return
  447. RegCloseKey( hKey );
  448. // set the error message
  449. SetLastError( ERROR_ACCESS_DENIED );
  450. SaveLastError();
  451. return FALSE;
  452. }
  453. // close the registry key and return
  454. RegCloseKey( hKey );
  455. //
  456. // check whether we got both 740 and 786 blocks or not
  457. //
  458. bImagesObject = FALSE;
  459. bAddressSpaceObject = FALSE;
  460. pot = (PPERF_OBJECT_TYPE) ( (LPBYTE) m_pdb + m_pdb->HeaderLength );
  461. for( DWORD dw = 0; dw < m_pdb->NumObjectTypes; dw++ )
  462. {
  463. if ( pot->ObjectNameTitleIndex == 740 )
  464. bImagesObject = TRUE;
  465. else if ( pot->ObjectNameTitleIndex == 786 )
  466. bAddressSpaceObject = TRUE;
  467. // move to the next object
  468. if( pot->TotalByteLength != 0 )
  469. pot = ( (PPERF_OBJECT_TYPE) ((PBYTE) pot + pot->TotalByteLength));
  470. }
  471. // check whether we got the needed objects or not
  472. if ( bImagesObject == FALSE || bAddressSpaceObject == FALSE )
  473. {
  474. SetLastError( ERROR_ACCESS_DENIED );
  475. SaveLastError();
  476. return FALSE;
  477. }
  478. // return
  479. return TRUE;
  480. }
  481. // ***************************************************************************
  482. // Routine Description:
  483. //
  484. // Arguments:
  485. //
  486. // Return Value:
  487. //
  488. // ***************************************************************************
  489. BOOL CTaskList::LoadUserNameFromWinsta( CHString& strDomain, CHString& strUserName )
  490. {
  491. // local variables
  492. PSID pSid = NULL;
  493. BOOL bResult = FALSE;
  494. LPWSTR pwszUser = NULL;
  495. LPWSTR pwszDomain = NULL;
  496. LPCWSTR pwszServer = NULL;
  497. DWORD dwUserLength = 0;
  498. DWORD dwDomainLength = 0;
  499. SID_NAME_USE siduse;
  500. // check whether winsta data exists or not
  501. if ( m_pProcessInfo == NULL )
  502. return FALSE;
  503. try
  504. {
  505. // allocate buffers
  506. dwUserLength = 128;
  507. dwDomainLength = 128;
  508. pwszUser = strUserName.GetBufferSetLength( dwUserLength );
  509. pwszDomain = strDomain.GetBufferSetLength( dwDomainLength );
  510. }
  511. catch( ... )
  512. {
  513. SetLastError( E_OUTOFMEMORY );
  514. SaveLastError();
  515. return FALSE;
  516. }
  517. //
  518. // find for the appropriate the process
  519. pSid = NULL;
  520. if ( m_bIsHydra == FALSE )
  521. {
  522. // sub-local variables
  523. PTS_ALL_PROCESSES_INFO ptsallpi = NULL;
  524. PTS_SYSTEM_PROCESS_INFORMATION pspi = NULL;
  525. // loop ...
  526. ptsallpi = (PTS_ALL_PROCESSES_INFO) m_pProcessInfo;
  527. for( ULONG ul = 0; ul < m_ulNumberOfProcesses; ul++ )
  528. {
  529. pspi = ( PTS_SYSTEM_PROCESS_INFORMATION )( ptsallpi[ ul ].pspiProcessInfo );
  530. if ( pspi->UniqueProcessId == m_dwProcessId )
  531. {
  532. // get the SID and convert it into
  533. pSid = ptsallpi[ ul ].pSid;
  534. break; // break from the loop
  535. }
  536. }
  537. }
  538. else
  539. {
  540. //
  541. // HYDRA ...
  542. //
  543. // sub-local variables
  544. DWORD dwTotalOffset = 0;
  545. PTS_SYSTEM_PROCESS_INFORMATION pspi = NULL;
  546. PCITRIX_PROCESS_INFORMATION pcpi = NULL;
  547. // traverse thru the process info and find the process id
  548. dwTotalOffset = 0;
  549. pspi = ( PTS_SYSTEM_PROCESS_INFORMATION ) m_pProcessInfo;
  550. for( ;; )
  551. {
  552. // check the processid
  553. if ( pspi->UniqueProcessId == m_dwProcessId )
  554. break;
  555. // check whether any more processes exist or not
  556. if( pspi->NextEntryOffset == 0 )
  557. break;
  558. // position to the next process info
  559. dwTotalOffset += pspi->NextEntryOffset;
  560. pspi = (PTS_SYSTEM_PROCESS_INFORMATION) &m_pProcessInfo[ dwTotalOffset ];
  561. }
  562. // get the citrix_information which follows the threads
  563. pcpi = (PCITRIX_PROCESS_INFORMATION)
  564. ( ((PUCHAR) pspi) + sizeof( TS_SYSTEM_PROCESS_INFORMATION ) +
  565. (sizeof( SYSTEM_THREAD_INFORMATION ) * pspi->NumberOfThreads) );
  566. // check the magic number .. if it is not valid ... we haven't got SID
  567. if( pcpi->MagicNumber == CITRIX_PROCESS_INFO_MAGIC )
  568. pSid = pcpi->ProcessSid;
  569. }
  570. // check the sid value
  571. if ( pSid == NULL )
  572. {
  573. // SPECIAL CASE:
  574. // -------------
  575. // PID -> 0 will have a special hard coded user name info
  576. if ( m_dwProcessId == 0 )
  577. {
  578. bResult = TRUE;
  579. lstrcpynW( pwszUser, PID_0_USERNAME, dwUserLength );
  580. lstrcpynW( pwszDomain, PID_0_DOMAIN, dwDomainLength );
  581. }
  582. // release the buffer
  583. strDomain.ReleaseBuffer();
  584. strUserName.ReleaseBuffer();
  585. return bResult;
  586. }
  587. // determine the server
  588. pwszServer = NULL;
  589. if ( m_bLocalSystem == FALSE )
  590. pwszServer = m_strUNCServer;
  591. // map the sid to the user name
  592. bResult = LookupAccountSid( pwszServer, pSid,
  593. pwszUser, &dwUserLength, pwszDomain, &dwDomainLength, &siduse );
  594. // release the buffer
  595. strDomain.ReleaseBuffer();
  596. strUserName.ReleaseBuffer();
  597. // return the result
  598. return bResult;
  599. }
  600. // ***************************************************************************
  601. // Routine Description:
  602. //
  603. // Arguments:
  604. //
  605. // Return Value:
  606. //
  607. // ***************************************************************************
  608. BOOL CTaskList::LoadServicesInfo()
  609. {
  610. // local variables
  611. DWORD dw = 0; // looping variable
  612. DWORD dwSize = 0; // used in memory allocation
  613. DWORD dwResume = 0; // used in EnumServicesStatusEx
  614. BOOL bResult = FALSE; // captures the result of EnumServicesStatusEx
  615. SC_HANDLE hScm = NULL; // holds the handle to the service
  616. DWORD dwExtraNeeded = 0; // used in EnumServicesStatusEx and memory allocation
  617. LPCWSTR pwszServer = NULL;
  618. LPENUM_SERVICE_STATUS_PROCESS pInfo = NULL; // holds the services info
  619. // Initialize the output parameter(s).
  620. m_dwServicesCount = 0;
  621. m_pServicesInfo = NULL;
  622. // check whether we need to load the services info or not
  623. if ( m_bNeedServicesInfo == FALSE )
  624. return TRUE;
  625. // display the status message
  626. PrintProgressMsg( m_hOutput, MSG_SERVICESINFO, m_csbi );
  627. // determine the server
  628. pwszServer = NULL;
  629. if ( m_bLocalSystem == FALSE )
  630. pwszServer = m_strUNCServer;
  631. // Connect to the service controller and check the result
  632. hScm = OpenSCManager( pwszServer, NULL, SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE );
  633. if ( hScm == NULL)
  634. {
  635. // set the reason for the failure and return from here itself
  636. SaveLastError();
  637. return FALSE;
  638. }
  639. // enumerate the names of the active win32 services
  640. // for this, first pass through the loop and allocate memory from an initial guess. (4K)
  641. // if that isn't sufficient, we make another pass and allocate
  642. // what is actually needed.
  643. // (we only go through the loop a maximum of two times)
  644. dw = 0; // no. of loops
  645. dwResume = 0; // reset / initialize variables
  646. dwSize = 4 * 1024; // reset / initialize variables
  647. while ( ++dw <= 2 )
  648. {
  649. // set the size
  650. dwSize += dwExtraNeeded;
  651. // allocate memory for storing services information
  652. pInfo = ( LPENUM_SERVICE_STATUS_PROCESS ) __calloc( 1, dwSize );
  653. if ( pInfo == NULL )
  654. {
  655. // failed in allocating needed memory ... error
  656. SetLastError( E_OUTOFMEMORY );
  657. SaveLastError();
  658. return FALSE;
  659. }
  660. // enumerate services, the process identifier and additional flags for the service
  661. dwResume = 0; // lets get all the services again
  662. bResult = EnumServicesStatusEx( hScm, SC_ENUM_PROCESS_INFO, SERVICE_WIN32,
  663. SERVICE_ACTIVE, ( LPBYTE ) pInfo, dwSize, &dwExtraNeeded, &m_dwServicesCount, &dwResume, NULL );
  664. // check the result of the enumeration
  665. if ( bResult )
  666. {
  667. // successfully enumerated all the services information
  668. break; // jump out of the loop
  669. }
  670. // first free the allocated memory
  671. __free( pInfo );
  672. // now lets look at what is the error
  673. if ( GetLastError() == ERROR_MORE_DATA )
  674. {
  675. // some more services are not listed because of less memory
  676. // allocate some more memory and enumerate the remaining services info
  677. continue;
  678. }
  679. else
  680. {
  681. // some strange error occured ... inform the same to the caller
  682. SaveLastError(); // set the reason for the failure
  683. CloseServiceHandle( hScm ); // close the handle to the service
  684. return FALSE; // inform failure
  685. }
  686. }
  687. // check whether there any services or not ... if services count is zero, free the memory
  688. if ( m_dwServicesCount == 0 )
  689. {
  690. // no services exists
  691. __free( pInfo );
  692. }
  693. else
  694. {
  695. // set the local pointer to the out parameter
  696. m_pServicesInfo = pInfo;
  697. }
  698. // inform success
  699. return TRUE;
  700. }
  701. // ***************************************************************************
  702. // Routine Description:
  703. //
  704. // Arguments:
  705. //
  706. // Return Value:
  707. //
  708. // ***************************************************************************
  709. BOOL GetPerfDataBlock( HKEY hKey, LPWSTR pwszObjectIndex, PPERF_DATA_BLOCK* ppdb )
  710. {
  711. // local variables
  712. LONG lReturn = 0;
  713. DWORD dwBytes = 0;
  714. BOOL bResult = FALSE;
  715. // check the input parameters
  716. if ( pwszObjectIndex == NULL || ppdb == NULL )
  717. return FALSE;
  718. // allocate memory for PERF_DATA_BLOCK
  719. dwBytes = 32 * 1024; // initially allocate for 32 K
  720. *ppdb = (PPERF_DATA_BLOCK) HeapAlloc( GetProcessHeap(), 0, dwBytes );
  721. if( *ppdb == NULL )
  722. {
  723. SetLastError( E_OUTOFMEMORY );
  724. SaveLastError();
  725. return FALSE;
  726. }
  727. // get performance data on passed Object
  728. lReturn = RegQueryValueEx( hKey, pwszObjectIndex, NULL, NULL, (LPBYTE) *ppdb, &dwBytes );
  729. while( lReturn == ERROR_MORE_DATA )
  730. {
  731. // increase memory by 8 K
  732. dwBytes += 8192;
  733. // allocated memory is too small reallocate new memory
  734. *ppdb = (PPERF_DATA_BLOCK) HeapReAlloc( GetProcessHeap(), 0, *ppdb, dwBytes );
  735. if( *ppdb == NULL )
  736. {
  737. SetLastError( E_OUTOFMEMORY );
  738. SaveLastError();
  739. return FALSE;
  740. }
  741. // try to get the info again
  742. lReturn = RegQueryValueEx( hKey, pwszObjectIndex, NULL, NULL, (LPBYTE) *ppdb, &dwBytes );
  743. }
  744. // check the reason for coming out of the loop
  745. bResult = TRUE;
  746. if ( lReturn != ERROR_SUCCESS )
  747. {
  748. if ( *ppdb != NULL)
  749. {
  750. HeapFree( GetProcessHeap(), 0, *ppdb );
  751. *ppdb = NULL;
  752. }
  753. // save the error info
  754. bResult = FALSE;
  755. SetLastError( lReturn );
  756. SaveLastError();
  757. }
  758. // return the result
  759. return bResult;
  760. }
  761. // ***************************************************************************
  762. // Routine Description:
  763. // Enumerates the desktops available on a particular window station
  764. // This is a CALLBACK function ... called by EnumWindowStations API function
  765. //
  766. // Arguments:
  767. // [ in ] lpstr : window station name
  768. // [ in ] lParam : user supplied parameter to this function
  769. // in this function, this points to TTASKSLIST structure variable
  770. //
  771. // Return Value:
  772. // TRUE upon success and FALSE on failure
  773. //
  774. // ***************************************************************************
  775. BOOL CALLBACK EnumWindowStationsFunc( LPTSTR lpstr, LPARAM lParam )
  776. {
  777. // local variables
  778. HWINSTA hWinSta = NULL;
  779. HWINSTA hwinstaSave = NULL;
  780. PTWINDOWTITLES pWndTitles = ( PTWINDOWTITLES ) lParam;
  781. // check the input arguments
  782. if ( lpstr == NULL || lParam == NULL )
  783. return FALSE;
  784. // get and save the current window station
  785. hwinstaSave = GetProcessWindowStation();
  786. // open current tasks window station and change the context to the new workstation
  787. hWinSta = OpenWindowStation( lpstr, FALSE, WINSTA_ENUMERATE | WINSTA_ENUMDESKTOPS );
  788. if ( hWinSta == NULL )
  789. {
  790. // failed in getting the process window station
  791. SaveLastError();
  792. return FALSE;
  793. }
  794. else
  795. {
  796. // change the context to the new workstation
  797. if ( hWinSta != hwinstaSave && SetProcessWindowStation( hWinSta ) == FALSE )
  798. {
  799. // failed in changing the context
  800. SaveLastError();
  801. return FALSE;
  802. }
  803. // release the memory allocated for earlier window station
  804. if ( pWndTitles->lpWinsta != NULL )
  805. {
  806. free( pWndTitles->lpWinsta );
  807. pWndTitles->lpWinsta = NULL;
  808. }
  809. // store the window station name
  810. pWndTitles->lpWinsta = _tcsdup( lpstr );
  811. if ( pWndTitles->lpWinsta == NULL )
  812. {
  813. SetLastError( E_OUTOFMEMORY );
  814. SaveLastError();
  815. return FALSE;
  816. }
  817. }
  818. // enumerate all the desktops for this windowstation
  819. EnumDesktops( hWinSta, EnumDesktopsFunc, lParam );
  820. // restore the context to the previous windowstation
  821. if (hWinSta != hwinstaSave)
  822. {
  823. SetProcessWindowStation( hwinstaSave );
  824. CloseWindowStation( hWinSta );
  825. }
  826. // continue the enumeration
  827. return TRUE;
  828. }
  829. // ***************************************************************************
  830. // Routine Description:
  831. // Enumerates the windows on a particular desktop
  832. // This is a CALLBACK function ... called by EnumDesktops API function
  833. //
  834. // Arguments:
  835. // [ in ] lpstr : desktop name
  836. // [ in ] lParam : user supplied parameter to this function
  837. // in this function, this points to TTASKSLIST structure variable
  838. //
  839. // Return Value:
  840. // TRUE upon success and FALSE on failure
  841. //
  842. // ***************************************************************************
  843. BOOL CALLBACK EnumDesktopsFunc( LPTSTR lpstr, LPARAM lParam )
  844. {
  845. // local variables
  846. HDESK hDesk = NULL;
  847. HDESK hdeskSave = NULL;
  848. PTWINDOWTITLES pWndTitles = ( PTWINDOWTITLES )lParam;
  849. // check the input arguments
  850. if ( lpstr == NULL || lParam == NULL )
  851. return FALSE;
  852. // get and save the current desktop
  853. hdeskSave = GetThreadDesktop( GetCurrentThreadId() );
  854. // open the tasks desktop and change the context to the new desktop
  855. hDesk = OpenDesktop( lpstr, 0, FALSE, DESKTOP_ENUMERATE );
  856. if ( hDesk == NULL )
  857. {
  858. // failed in getting the process desktop
  859. SaveLastError();
  860. return FALSE;
  861. }
  862. else
  863. {
  864. // change the context to the new desktop
  865. if ( hDesk != hdeskSave && SetThreadDesktop( hDesk ) == FALSE )
  866. {
  867. // failed in changing the context
  868. SaveLastError();
  869. // ?? return FALSE; -- needs to uncommented
  870. }
  871. // release the memory allocated for earlier window station
  872. if ( pWndTitles->lpDesk != NULL )
  873. {
  874. free( pWndTitles->lpDesk );
  875. pWndTitles->lpDesk = NULL;
  876. }
  877. // store the desktop name
  878. pWndTitles->lpDesk = _tcsdup( lpstr );
  879. if ( pWndTitles->lpDesk == NULL )
  880. {
  881. SetLastError( E_OUTOFMEMORY );
  882. SaveLastError();
  883. return FALSE;
  884. }
  885. }
  886. // enumerate all windows in the new desktop
  887. // first try to get only the top level windows and visible windows only
  888. ( ( PTWINDOWTITLES ) lParam )->bFirstLoop = TRUE;
  889. EnumWindows( ( WNDENUMPROC ) EnumWindowsProc, lParam );
  890. EnumMessageWindows( ( WNDENUMPROC ) EnumWindowsProc, lParam );
  891. // enumerate all windows in the new desktop
  892. // now try to get window titles of all those processes whose we ignored earlier while
  893. // looping first time
  894. ( ( PTWINDOWTITLES ) lParam )->bFirstLoop = FALSE;
  895. EnumWindows( ( WNDENUMPROC ) EnumWindowsProc, lParam );
  896. EnumMessageWindows( ( WNDENUMPROC ) EnumWindowsProc, lParam );
  897. // restore the previous desktop
  898. if (hDesk != hdeskSave)
  899. {
  900. SetThreadDesktop( hdeskSave );
  901. CloseDesktop( hDesk );
  902. }
  903. // continue enumeration
  904. return TRUE;
  905. }
  906. // ***************************************************************************
  907. // Routine Description:
  908. // Enumerates the message windows
  909. //
  910. // Arguments:
  911. // [ in ] lpEnumFunc : address of call back function that has to be called for
  912. // each message window found
  913. // [ in ] lParam : user supplied parameter to this function
  914. // in this function, this points to TTASKSLIST structure variable
  915. //
  916. // Return Value:
  917. // TRUE upon success and FALSE on failure
  918. // ***************************************************************************
  919. BOOL CALLBACK EnumMessageWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam )
  920. {
  921. // local variables
  922. HWND hWnd = NULL;
  923. BOOL bResult = FALSE;
  924. // check the input arguments
  925. if ( lpEnumFunc == NULL || lParam == NULL )
  926. return FALSE;
  927. // enumerate all the message windows
  928. do
  929. {
  930. // find the message window
  931. hWnd = FindWindowEx( HWND_MESSAGE, hWnd, NULL, NULL );
  932. // check whether we got the handle to the message window or not
  933. if ( hWnd != NULL )
  934. {
  935. // explicitly call the windows enumerators call back function for this window
  936. bResult = ( *lpEnumFunc )( hWnd, lParam );
  937. // check the result of the enumeator call back function
  938. if ( bResult == FALSE )
  939. {
  940. // terminate the enumeration
  941. break;
  942. }
  943. }
  944. } while ( hWnd != NULL );
  945. // return the enumeration result
  946. return bResult;
  947. }
  948. // ***************************************************************************
  949. // Routine Description:
  950. // call back called by the API for each window
  951. // retrives the window title and updates the accordingly
  952. //
  953. // Arguments:
  954. // [ in ] hWnd : handle to the window
  955. // [ in ] lParam : user supplied parameter to this function
  956. // in this function, this points to TTASKSLIST structure variable
  957. //
  958. // Return Value:
  959. // TRUE upon success and FALSE on failure
  960. // ***************************************************************************
  961. BOOL CALLBACK EnumWindowsProc( HWND hWnd, LPARAM lParam )
  962. {
  963. // local variables
  964. LONG lIndex = 0;
  965. DWORD dwPID = 0;
  966. BOOL bVisible = FALSE;
  967. TARRAY arrWindows = NULL;
  968. PTWINDOWTITLES pWndTitles = NULL;
  969. __MAX_SIZE_STRING szWindowTitle = NULL_STRING;
  970. // check the input arguments
  971. if ( hWnd == NULL || lParam == NULL )
  972. return FALSE;
  973. // get the values from the lParam
  974. pWndTitles = ( PTWINDOWTITLES ) lParam;
  975. arrWindows = pWndTitles->arrWindows;
  976. // get the processid for this window
  977. if ( GetWindowThreadProcessId( hWnd, &dwPID ) == 0 )
  978. {
  979. // failed in getting the process id
  980. return TRUE; // return but, proceed enumerating other window handle
  981. }
  982. // get the visibility state of the window
  983. // if the window is not visible, and if this is the first we are enumerating the
  984. // window titles, ignore this process
  985. bVisible = GetWindowLong( hWnd, GWL_STYLE ) & WS_VISIBLE;
  986. if ( bVisible == FALSE && pWndTitles->bFirstLoop == TRUE )
  987. return TRUE; // return but, proceed enumerating other window handle
  988. // check whether the current window ( for which we have the handle )
  989. // is main window or not. we don't need child windows
  990. if ( GetWindow(hWnd, GW_OWNER) != NULL )
  991. {
  992. // the current window handle is not for a top level window
  993. return TRUE; // return but, proceed enumerating other window handle
  994. }
  995. // check if we are already got the window handle for the curren process or not
  996. // save it only if we are not having it
  997. lIndex = DynArrayFindDWORDEx( arrWindows, CTaskList::twiProcessId, dwPID );
  998. if ( lIndex == -1 )
  999. {
  1000. // window for this process is not there ... save it
  1001. lIndex = DynArrayAppendRow( arrWindows, CTaskList::twiCOUNT );
  1002. }
  1003. else
  1004. {
  1005. // check whether window details already exists or not
  1006. if ( DynArrayItemAsHandle2( arrWindows, lIndex, CTaskList::twiHandle ) != NULL )
  1007. lIndex = -1; // window details already exists
  1008. }
  1009. // check if window details has to be saved or not ... if needed save them
  1010. if ( lIndex != -1 )
  1011. {
  1012. DynArraySetDWORD2( arrWindows, lIndex, CTaskList::twiProcessId, dwPID );
  1013. DynArraySetHandle2( arrWindows, lIndex, CTaskList::twiHandle, hWnd );
  1014. DynArraySetString2( arrWindows, lIndex,
  1015. CTaskList::twiWinSta, pWndTitles->lpWinsta, 0 );
  1016. DynArraySetString2( arrWindows, lIndex,
  1017. CTaskList::twiDesktop, pWndTitles->lpDesk, 0 );
  1018. // get and save the window title
  1019. if ( GetWindowText( hWnd, szWindowTitle, SIZE_OF_ARRAY( szWindowTitle ) ) != 0 )
  1020. DynArraySetString2( arrWindows, lIndex, CTaskList::twiTitle, szWindowTitle, 0 );
  1021. }
  1022. // continue the enumeration
  1023. return TRUE;
  1024. }
  1025. // ***************************************************************************
  1026. // Routine Description:
  1027. //
  1028. // Arguments:
  1029. //
  1030. // Return Value:
  1031. //
  1032. // ***************************************************************************
  1033. VOID PrintProgressMsg( HANDLE hOutput, LPCWSTR pwszMsg, const CONSOLE_SCREEN_BUFFER_INFO& csbi )
  1034. {
  1035. // local variables
  1036. COORD coord;
  1037. DWORD dwSize = 0;
  1038. WCHAR wszSpaces[ 80 ] = L"";
  1039. // check the handle. if it is null, it means that output is being redirected. so return
  1040. if ( hOutput == NULL )
  1041. return;
  1042. // set the cursor position
  1043. coord.X = 0;
  1044. coord.Y = csbi.dwCursorPosition.Y;
  1045. // first erase contents on the current line
  1046. ZeroMemory( wszSpaces, 80 );
  1047. SetConsoleCursorPosition( hOutput, coord );
  1048. WriteConsoleW( hOutput, Replicate( wszSpaces, L"", 79 ), 79, &dwSize, NULL );
  1049. // now display the message ( if exists )
  1050. SetConsoleCursorPosition( hOutput, coord );
  1051. if ( pwszMsg != NULL )
  1052. WriteConsoleW( hOutput, pwszMsg, lstrlen( pwszMsg ), &dwSize, NULL );
  1053. }