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.

2322 lines
74 KiB

  1. // *********************************************************************************
  2. //
  3. // Copyright (c) Microsoft Corporation
  4. //
  5. // Module Name:
  6. //
  7. // Terminate.cpp
  8. //
  9. // Abstract:
  10. //
  11. // This module implements the actual termination of process
  12. //
  13. // Author:
  14. //
  15. // Sunil G.V.N. Murali ([email protected]) 26-Nov-2000
  16. //
  17. // Revision History:
  18. //
  19. // Sunil G.V.N. Murali ([email protected]) 26-Nov-2000 : Created It.
  20. //
  21. // *********************************************************************************
  22. #include "pch.h"
  23. #include "wmi.h"
  24. #include "TaskKill.h"
  25. //
  26. // define(s) / constants
  27. //
  28. #define MAX_ENUM_TASKS 5
  29. #define MAX_ENUM_SERVICES 10
  30. #define MAX_ENUM_MODULES 10
  31. #define WAIT_TIME_IN_SECS 1000 // 1 second ( 1000 milliseconds )
  32. #define MAX_TIMEOUT_RETRIES 60 // 60 times
  33. #define MAX_TERMINATE_TIMEOUT 1000 // 1 seconds
  34. // We won't allow the following set of critical system processes to be terminated,
  35. // since the system would bug check immediately, no matter who you are.
  36. #define PROCESS_CSRSS_EXE L"csrss.exe"
  37. #define PROCESS_WINLOGON_EXE L"winlogon.exe"
  38. #define PROCESS_SMSS_EXE L"smss.exe"
  39. #define PROCESS_SERVICES_EXE L"services.exe"
  40. //
  41. // function prototypes
  42. //
  43. #ifndef _WIN64
  44. BOOL EnumLoadedModulesProc( LPSTR lpszModuleName, ULONG ulModuleBase, ULONG ulModuleSize, PVOID pUserData );
  45. #else
  46. BOOL EnumLoadedModulesProc64( LPSTR lpszModuleName, DWORD64 ulModuleBase, ULONG ulModuleSize, PVOID pUserData );
  47. #endif
  48. BOOL
  49. CTaskKill::DoTerminate(
  50. OUT DWORD& dwExitCode
  51. )
  52. /*++
  53. Routine Description:
  54. Search for a valid process to terminate and if found terminate.
  55. Arguments:
  56. OUT dwExitcode : Contains number with which to exit process.
  57. Return Value:
  58. TRUE upon successfull and FALSE if failed
  59. --*/
  60. {
  61. // local variables
  62. HRESULT hr = S_OK;
  63. CHString str;
  64. LONG lIndex = -1;
  65. DWORD dwCount = 0;
  66. DWORD dwKilled = 0;
  67. DWORD dwFilters = 0;
  68. DWORD dwTimeOuts = 0;
  69. DWORD dwImageNames = 0;
  70. DWORD dwTasksToKill = 0;
  71. DWORD dwMatchedIndex = 0;
  72. BOOL bCanExit = FALSE;
  73. BOOL bAllTasks = FALSE;
  74. BOOL bImageName = FALSE;
  75. ULONG ulReturned = 0;
  76. TARRAY arrTasks = NULL;
  77. TARRAY arrImageNames = NULL;
  78. LPCWSTR pwszTask = NULL;
  79. IWbemClassObject* pObjects[ MAX_ENUM_TASKS ];
  80. // clear the error
  81. SetLastError( ( DWORD )NO_ERROR );
  82. try
  83. {
  84. //
  85. // prepare ...
  86. bCanExit = FALSE;
  87. dwImageNames = 0;
  88. dwFilters = DynArrayGetCount( m_arrFiltersEx );
  89. dwTasksToKill = DynArrayGetCount( m_arrTasksToKill );
  90. arrTasks = CreateDynamicArray();
  91. arrImageNames = CreateDynamicArray();
  92. if ( ( NULL == arrImageNames ) || ( NULL == arrTasks ) )
  93. {
  94. dwExitCode = 1;
  95. SetLastError( ( DWORD )E_OUTOFMEMORY );
  96. SaveLastError();
  97. // release the allocations
  98. DESTROY_ARRAY( arrTasks );
  99. DESTROY_ARRAY( arrImageNames );
  100. // inform failure
  101. return FALSE;
  102. }
  103. // check if '*' is specified or not
  104. lIndex = DynArrayFindString( m_arrTasksToKill, L"*", TRUE, 0 );
  105. if ( lIndex != -1 )
  106. {
  107. // wild card specified
  108. dwTasksToKill--; // update the counter
  109. bAllTasks = TRUE; // remember
  110. DynArrayRemove( m_arrTasksToKill, lIndex ); // remove the wildcard entry
  111. }
  112. // init all the objects first
  113. for( DWORD dw = 0; dw < MAX_ENUM_TASKS; dw++ )
  114. {
  115. pObjects[ dw ] = NULL;
  116. }
  117. // if -tr is specified, free the already allocated memory for m_arrRecord
  118. if ( TRUE == m_bTree )
  119. {
  120. DESTROY_ARRAY( m_arrRecord );
  121. }
  122. // traverse thru the running processed and terminate the needed
  123. dwCount = 0;
  124. dwKilled = 0;
  125. do
  126. {
  127. // get the object ... time out should not occur
  128. // NOTE: one-by-one
  129. hr = m_pWbemEnumObjects->Next(
  130. WAIT_TIME_IN_SECS, MAX_ENUM_TASKS, pObjects, &ulReturned );
  131. if ( hr == (HRESULT) WBEM_S_FALSE )
  132. {
  133. // we've reached the end of enumeration .. set the flag
  134. bCanExit = TRUE;
  135. }
  136. else if ( hr == (HRESULT) WBEM_S_TIMEDOUT )
  137. {
  138. // update the timeouts occured
  139. dwTimeOuts++;
  140. // check if max. retries have reached ... if yes better stop
  141. if ( dwTimeOuts > MAX_TIMEOUT_RETRIES )
  142. {
  143. dwExitCode = 1;
  144. DESTROY_ARRAY( arrTasks );
  145. DESTROY_ARRAY( arrImageNames );
  146. SetLastError( ( DWORD )ERROR_TIMEOUT );
  147. SaveLastError();
  148. return FALSE;
  149. }
  150. // still we can do some more tries ...
  151. continue;
  152. }
  153. else if ( FAILED( hr ) )
  154. {
  155. // some error has occured ... oooppps
  156. dwExitCode = 1;
  157. DESTROY_ARRAY( arrTasks );
  158. DESTROY_ARRAY( arrImageNames );
  159. WMISaveError( hr );
  160. return FALSE;
  161. }
  162. // reset the timeout counter
  163. dwTimeOuts = 0;
  164. // loop thru the objects and save the info
  165. for( ULONG ul = 0; ul < ulReturned; ul++ )
  166. {
  167. // if tree option is specified, allocate memory for record every we loop
  168. if ( m_bTree == TRUE )
  169. {
  170. // create a new array
  171. m_arrRecord = CreateDynamicArray();
  172. if ( m_arrRecord == NULL )
  173. {
  174. dwExitCode = 1;
  175. SetLastError( ( DWORD )E_OUTOFMEMORY );
  176. SaveLastError();
  177. // release the allocations
  178. DESTROY_ARRAY( arrTasks );
  179. DESTROY_ARRAY( arrImageNames );
  180. // inform failure
  181. return FALSE;
  182. }
  183. }
  184. else
  185. {
  186. // tree option is not specified, so, just remove the contents
  187. DynArrayRemoveAll( m_arrRecord );
  188. }
  189. // add the columns first
  190. DynArrayAddColumns( m_arrRecord, MAX_TASKSINFO );
  191. // retrive and save data
  192. SaveData( pObjects[ ul ] );
  193. // release the object
  194. SAFE_RELEASE( pObjects[ ul ] );
  195. // check if this has to be filtered or not
  196. if ( dwFilters != 0 )
  197. {
  198. BOOL bIgnore = FALSE;
  199. bIgnore = CanFilterRecord( MAX_FILTERS,
  200. m_pfilterConfigs, m_arrRecord, m_arrFiltersEx );
  201. // check if this has to be ignored or not
  202. if ( bIgnore == TRUE )
  203. {
  204. if ( m_bTree == TRUE )
  205. {
  206. // save this record with rank as 0
  207. DynArraySetDWORD( m_arrRecord, TASK_RANK, 0 );
  208. DynArrayAppendEx( arrTasks, m_arrRecord );
  209. }
  210. // continue to the task
  211. continue;
  212. }
  213. }
  214. // crossed from the filter -- update the count
  215. dwCount++;
  216. // find the task that has to be killed
  217. // and check if this task has to be killed or not
  218. lIndex = -1;
  219. pwszTask = NULL;
  220. bImageName = FALSE;
  221. if ( dwTasksToKill != 0 || dwImageNames != 0 )
  222. {
  223. // check if the process is in list
  224. if ( dwTasksToKill != 0 )
  225. lIndex = MatchTaskToKill( dwMatchedIndex );
  226. // if task is not, check if image names exist and if it matches or not
  227. if ( lIndex == -1 && dwImageNames != 0 )
  228. {
  229. // get the image name and search for the same in the image names list
  230. DWORD dwLength = 0;
  231. LPCWSTR pwsz = NULL;
  232. LPCWSTR pwszTemp = NULL;
  233. LPCWSTR pwszImageName = NULL;
  234. pwszImageName = DynArrayItemAsString( m_arrRecord, TASK_IMAGENAME );
  235. if ( pwszImageName == NULL )
  236. {
  237. dwExitCode = 1;
  238. DESTROY_ARRAY( arrTasks );
  239. DESTROY_ARRAY( arrImageNames );
  240. SetLastError( ( DWORD )STG_E_UNKNOWN );
  241. SaveLastError();
  242. return FALSE;
  243. }
  244. // ...
  245. for( DWORD dw = 0; dw < dwImageNames; dw++ )
  246. {
  247. // get the image name from the list
  248. pwszTemp = DynArrayItemAsString( arrImageNames, dw );
  249. if ( pwszTemp == NULL )
  250. {
  251. dwExitCode = 1;
  252. DESTROY_ARRAY( arrTasks );
  253. DESTROY_ARRAY( arrImageNames );
  254. SetLastError( ( DWORD )STG_E_UNKNOWN );
  255. SaveLastError();
  256. return FALSE;
  257. }
  258. // determine the no. of characters to compare
  259. dwLength = 0;
  260. pwsz = FindChar( pwszTemp, L'*', 0 );
  261. if ( pwsz != NULL )
  262. {
  263. // '*' - wildcard is specified in the image name
  264. // so, determine the no. of characters to compare
  265. // but before that check the length of the string pointer from '*'
  266. // it should be 1 - meaning the '*' can be specified only at the end
  267. // but not in the middle
  268. if ( 1 == StringLength( pwsz, 0 ) )
  269. {
  270. dwLength = StringLength( pwszTemp, 0 ) - StringLength( pwsz, 0 );
  271. }
  272. }
  273. // now do the comparision
  274. if ( StringCompare( pwszImageName, pwszTemp, TRUE, dwLength ) == 0 )
  275. {
  276. // image found - has to be terminated
  277. bImageName = TRUE;
  278. pwszTask = pwszTemp;
  279. }
  280. }
  281. }
  282. else if ( lIndex != -1 && dwMatchedIndex == TASK_IMAGENAME )
  283. {
  284. bImageName = TRUE; // image name
  285. pwszTask = DynArrayItemAsString( m_arrTasksToKill, lIndex );
  286. }
  287. }
  288. // check whether attempt to terminate or not to attempt
  289. if ( bAllTasks == FALSE && lIndex == -1 && bImageName == FALSE )
  290. {
  291. if ( m_bTree == TRUE )
  292. {
  293. // save this record with rank as 0
  294. dwCount--;
  295. DynArraySetDWORD( m_arrRecord, TASK_RANK, 0 );
  296. DynArrayAppendEx( arrTasks, m_arrRecord );
  297. }
  298. // continue to the task
  299. continue;
  300. }
  301. // we need to post-pone the killing of the current identified task till we get the
  302. // entire list of processes
  303. if ( m_bTree == TRUE )
  304. {
  305. // mark this as rank 1 process
  306. DynArraySetDWORD( m_arrRecord, TASK_RANK, 1 );
  307. // now add this record to the tasks array
  308. DynArrayAppendEx( arrTasks, m_arrRecord );
  309. }
  310. else
  311. {
  312. // kill the current task
  313. if ( this->Kill() == TRUE )
  314. {
  315. dwKilled++; // updated killed processes counter
  316. // success message will depend on the task info specified by the user
  317. // at the command prompt
  318. if ( bImageName == TRUE )
  319. {
  320. if ( m_bLocalSystem == TRUE && m_bForce == FALSE )
  321. {
  322. str.Format(MSG_KILL_SUCCESS_QUEUED_EX, m_strImageName, m_dwProcessId);
  323. }
  324. else
  325. {
  326. str.Format(MSG_KILL_SUCCESS_EX, m_strImageName, m_dwProcessId);
  327. }
  328. }
  329. else
  330. {
  331. if ( m_bLocalSystem == TRUE && m_bForce == FALSE )
  332. {
  333. str.Format( MSG_KILL_SUCCESS_QUEUED, m_dwProcessId );
  334. }
  335. else
  336. {
  337. str.Format( MSG_KILL_SUCCESS, m_dwProcessId );
  338. }
  339. }
  340. // show the message
  341. ShowMessage( stdout, str );
  342. }
  343. else
  344. {
  345. // failed to kill the process .. save the error message
  346. if ( bImageName == FALSE )
  347. str.Format( ERROR_KILL_FAILED, m_dwProcessId, GetReason() );
  348. else
  349. str.Format( ERROR_KILL_FAILED_EX, m_strImageName, m_dwProcessId, GetReason() );
  350. // show the message
  351. ShowMessage( stderr, str );
  352. }
  353. }
  354. // user might have specified the duplications in the list
  355. // so check for that and remove it
  356. if ( bImageName == TRUE )
  357. {
  358. // sub-local
  359. CHString strProcessId;
  360. LONG lProcessIndex = -1;
  361. strProcessId.Format( L"%ld", m_dwProcessId );
  362. lProcessIndex = DynArrayFindString( m_arrTasksToKill, strProcessId, TRUE, 0 );
  363. if ( lProcessIndex != -1 && lIndex != lProcessIndex )
  364. DynArrayRemove( m_arrTasksToKill, lProcessIndex );
  365. }
  366. else if ( pwszTask != NULL )
  367. {
  368. // sub-local
  369. LONG lProcessIndex = -1;
  370. lProcessIndex = DynArrayFindString( m_arrTasksToKill, pwszTask, TRUE, 0 );
  371. if ( lProcessIndex != -1 && lIndex != lProcessIndex )
  372. {
  373. bImageName = TRUE;
  374. DynArrayRemove( m_arrTasksToKill, lProcessIndex );
  375. }
  376. }
  377. // if this is a image name, all the tasks with this image name
  378. // has to be terminated. so we need to save the image name
  379. // but before doing this, in order to save memory, check if this image name
  380. // already exists in the list .. this will avoid duplication of image names
  381. // in the list and helps in performace
  382. if ( bImageName == TRUE && pwszTask != NULL &&
  383. DynArrayFindString(arrImageNames, pwszTask, TRUE, 0) == -1 )
  384. {
  385. // add to the list
  386. dwImageNames++;
  387. DynArrayAppendString( arrImageNames, pwszTask, 0 );
  388. }
  389. // delete the process info from the arrProcesses ( if needed )
  390. if ( lIndex != -1 )
  391. {
  392. // yes ... current task was killed remove the entry from arrProcess into
  393. // consideration ... so delete it
  394. dwTasksToKill--; // update the counter
  395. DynArrayRemove( m_arrTasksToKill, lIndex );
  396. }
  397. // check whether we need to quit the program or not
  398. if ( m_bTree == FALSE && bAllTasks == FALSE && dwTasksToKill == 0 && dwImageNames == 0 )
  399. {
  400. bCanExit = TRUE;
  401. break;
  402. }
  403. }
  404. } while ( bCanExit == FALSE );
  405. // Check (a) are there any process to kill, (b) If yes, are any process killed.
  406. if( ( 0 != dwCount ) &&( 0 == dwKilled ) )
  407. {
  408. dwExitCode = 1;
  409. }
  410. // if the -tr is specified, reset the m_arrRecord variable to NULL
  411. // this will avoid double free-ing the same heap memory
  412. if ( m_bTree == TRUE )
  413. {
  414. m_arrRecord = NULL;
  415. }
  416. //
  417. // SPECIAL HANDLING FOR TREE TERMINATION STARTS HERE
  418. //
  419. if ( m_bTree == TRUE && dwCount != 0 )
  420. {
  421. //
  422. // prepare the tree
  423. // sub-local variables
  424. LONG lTemp = 0;
  425. DWORD dwTemp = 0;
  426. DWORD dwRank = 0;
  427. DWORD dwIndex = 0;
  428. DWORD dwLastRank = 0;
  429. DWORD dwTasksCount = 0;
  430. DWORD dwProcessId = 0;
  431. DWORD dwParentProcessId = 0;
  432. // Need to set error code to 0.
  433. dwExitCode = 0;
  434. // loop thru the list of processes
  435. dwLastRank = 1;
  436. dwTasksCount = DynArrayGetCount( arrTasks );
  437. for( dwIndex = 0; dwIndex < dwTasksCount; dwIndex++ )
  438. {
  439. // get the rank of the current process
  440. // and check whether the current process is marked for termination or not
  441. dwRank = DynArrayItemAsDWORD2( arrTasks, dwIndex, TASK_RANK );
  442. if ( dwRank == 0 )
  443. continue;
  444. // now loop thru the begining of the tasks and
  445. // assign the ranks to the childs of this process
  446. dwProcessId = DynArrayItemAsDWORD2( arrTasks, dwIndex, TASK_PID );
  447. for( DWORD dw = dwIndex + 1; dw < dwTasksCount; dw++ )
  448. {
  449. // get the process id this process
  450. dwTemp = DynArrayItemAsDWORD2( arrTasks, dw, TASK_PID );
  451. if ( dwTemp == dwProcessId )
  452. continue; // skip this process
  453. // get the parent process id of this process
  454. dwParentProcessId = DynArrayItemAsDWORD2( arrTasks, dw, TASK_CREATINGPROCESSID );
  455. if ( dwTemp == dwParentProcessId )
  456. continue; // skip this process also
  457. // check the process relation
  458. if ( dwProcessId == dwParentProcessId )
  459. {
  460. // set the rank to this process
  461. DynArraySetDWORD2( arrTasks, dw, TASK_RANK, dwRank + 1 );
  462. // update the last rank
  463. if ( dwRank + 1 > dwLastRank )
  464. {
  465. dwLastRank = dwRank + 1;
  466. }
  467. // SPECIAL CONDITION:
  468. // -----------------
  469. // we need to check the index of this task in the list of tasks information we have
  470. // if the index of this task information is above its parent process,
  471. // we need to re-initiate the outter loop once again
  472. // this is a sort of optimization which we are doing here instead of looping the
  473. // outter loop unnecessarily
  474. // if ( dw < dwIndex )
  475. // {
  476. // dwIndex = 0;
  477. // }
  478. // ----------------------------------------------------------
  479. // currently we are assuming that the list of processe we get
  480. // will be in sorting order of creation time
  481. // ----------------------------------------------------------
  482. }
  483. }
  484. }
  485. //
  486. // now start terminating the tasks based on their ranks
  487. dwKilled = 0;
  488. for( dwRank = dwLastRank; dwRank > 0; dwRank-- )
  489. {
  490. // loop thru all the processes and terminate
  491. for ( lIndex = 0; lIndex < (LONG) dwTasksCount; lIndex++ )
  492. {
  493. // get the record
  494. m_arrRecord = (TARRAY) DynArrayItem( arrTasks, lIndex );
  495. if ( m_arrRecord == NULL )
  496. continue;
  497. // check the rank
  498. dwTemp = DynArrayItemAsDWORD( m_arrRecord, TASK_RANK );
  499. if ( dwTemp != dwRank )
  500. {
  501. // OPTIMIZATION:
  502. // ------------
  503. // check the rank. if the rank is zero, delete this task from the list
  504. // this improves the performance when we run for the next loop
  505. if ( dwTemp == 0 )
  506. {
  507. DynArrayRemove( arrTasks, lIndex );
  508. lIndex--;
  509. dwTasksCount--;
  510. }
  511. // skip this task
  512. continue;
  513. }
  514. // get the process id and its parent process id
  515. m_dwProcessId = DynArrayItemAsDWORD( m_arrRecord, TASK_PID );
  516. dwParentProcessId = DynArrayItemAsDWORD( m_arrRecord, TASK_CREATINGPROCESSID );
  517. // ensure that there are no child for this process
  518. // NOTE: Termination of some childs might have failed ( this is needed only if -f is not specified )
  519. if ( m_bForce == FALSE )
  520. {
  521. lTemp = DynArrayFindDWORDEx( arrTasks, TASK_CREATINGPROCESSID, m_dwProcessId );
  522. if ( lTemp != -1 )
  523. {
  524. // set the reason
  525. SetReason( ERROR_TASK_HAS_CHILDS );
  526. // format the error message
  527. str.Format( ERROR_TREE_KILL_FAILED, m_dwProcessId, dwParentProcessId, GetReason() );
  528. // show the message
  529. ShowMessage( stderr, str );
  530. // skip this
  531. continue;
  532. }
  533. }
  534. // kill the current task
  535. if ( this->Kill() == TRUE )
  536. {
  537. dwKilled++; // updated killed processes counter
  538. // prepare the error message
  539. if ( m_bForce == TRUE )
  540. {
  541. str.Format( MSG_TREE_KILL_SUCCESS, m_dwProcessId, dwParentProcessId );
  542. }
  543. else
  544. {
  545. str.Format( MSG_TREE_KILL_SUCCESS_QUEUED, m_dwProcessId, dwParentProcessId );
  546. }
  547. // remove the current task entry from the list and update the indexes accordingly
  548. DynArrayRemove( arrTasks, lIndex );
  549. lIndex--;
  550. dwTasksCount--;
  551. // show the message
  552. ShowMessage( stdout, str );
  553. }
  554. else
  555. {
  556. // prepare the error message
  557. str.Format( ERROR_TREE_KILL_FAILED, m_dwProcessId, dwParentProcessId, GetReason() );
  558. // show the message
  559. ShowMessage( stderr, str );
  560. }
  561. }
  562. }
  563. // reset the value of m_arrRecord
  564. m_arrRecord = NULL;
  565. // determine the exit code
  566. if ( dwTasksCount == dwCount )
  567. dwExitCode = 255; // not even one task got terminated
  568. else if ( dwTasksToKill != 0 || dwTasksCount != 0 )
  569. dwExitCode = 128; // tasks were terminated partially
  570. }
  571. //
  572. // SPECIAL HANDLING FOR TREE TERMINATION ENDS HERE
  573. //
  574. }
  575. catch( CHeap_Exception )
  576. {
  577. // free the memory
  578. DESTROY_ARRAY( arrTasks );
  579. DESTROY_ARRAY( arrImageNames );
  580. SetLastError( ( DWORD )E_OUTOFMEMORY );
  581. return 255;
  582. }
  583. // free the memory
  584. DESTROY_ARRAY( arrTasks );
  585. DESTROY_ARRAY( arrImageNames );
  586. // final check-up ...
  587. if ( ( 0 == dwCount ) &&
  588. ( ( 0 == dwTasksToKill ) ||
  589. ( TRUE == m_bFiltersOptimized ) ||
  590. ( 0 != dwFilters ) ) )
  591. {
  592. dwExitCode = 0;
  593. ShowMessage( stdout, ERROR_NO_PROCESSES ); // no tasks were found
  594. }
  595. else
  596. {
  597. if ( 0 != dwTasksToKill )
  598. {
  599. // some processes which are requested to kill are not found
  600. LPCWSTR pwszTemp = NULL;
  601. for( DWORD dw = 0; dw < dwTasksToKill; dw++ )
  602. {
  603. // get the task name
  604. pwszTemp = DynArrayItemAsString( m_arrTasksToKill, dw );
  605. if ( NULL == pwszTemp )
  606. {
  607. continue; // skip
  608. }
  609. try
  610. {
  611. // prepare and display message ...
  612. str.Format( ERROR_PROCESS_NOTFOUND, pwszTemp );
  613. ShowMessage( stderr, str );
  614. }
  615. catch( CHeap_Exception )
  616. {
  617. SetLastError( ( DWORD )E_OUTOFMEMORY );
  618. return 255;
  619. }
  620. }
  621. // exit code
  622. dwExitCode = 128;
  623. }
  624. }
  625. // return
  626. return TRUE;
  627. }
  628. inline BOOL
  629. CTaskKill::Kill(
  630. void
  631. )
  632. /*++
  633. Routine Description:
  634. Invokes the appropriate kill function based on the mode of termination
  635. Arguments:
  636. NONE
  637. Return Value:
  638. TRUE upon successfull and FALSE if failed
  639. --*/
  640. {
  641. // local variables
  642. BOOL bResult = FALSE;
  643. // check whether task can be terminated or not
  644. if ( FALSE == CanTerminate() )
  645. {
  646. return FALSE;
  647. }
  648. // check whether local system / remote system
  649. if ( TRUE == m_bLocalSystem )
  650. {
  651. //
  652. // process termination on local system
  653. // based on the mode of termination invoke appropriate method
  654. if ( FALSE == m_bForce )
  655. {
  656. bResult = KillProcessOnLocalSystem();
  657. }
  658. else
  659. {
  660. bResult = ForciblyKillProcessOnLocalSystem();
  661. }
  662. }
  663. else
  664. {
  665. //
  666. // process termination on remote system
  667. // silent termination of the process on a remote system is not supported
  668. // it will be always forcible termination
  669. bResult = ForciblyKillProcessOnRemoteSystem();
  670. }
  671. // inform the result
  672. return bResult;
  673. }
  674. BOOL
  675. CTaskKill::KillProcessOnLocalSystem(
  676. void
  677. )
  678. /*++
  679. Routine Description:
  680. Terminates the process in silence mode ... by posting WM_CLOSE message
  681. this is for local system only
  682. Arguments:
  683. NONE
  684. Return Value:
  685. TRUE upon successfull and FALSE if failed
  686. --*/
  687. {
  688. // local variables
  689. HDESK hDesk = NULL;
  690. HDESK hdeskSave = NULL;
  691. HWINSTA hWinSta = NULL;
  692. HWINSTA hwinstaSave = NULL;
  693. HANDLE hProcess = NULL;
  694. BOOL bReturn = FALSE;
  695. // variables which contains data
  696. HWND hWnd = NULL;
  697. LPCWSTR pwszDesktop = NULL;
  698. LPCWSTR pwszWindowStation = NULL;
  699. // clear the reason
  700. SetReason( NULL_STRING );
  701. // Get process handle for termination.
  702. // This is done so as to know whether the logged user has
  703. // adequate permissions to kill the process.
  704. hProcess = OpenProcess( PROCESS_TERMINATE, FALSE, m_dwProcessId );
  705. if( NULL == hProcess )
  706. { // Current user don't have permissions to kill the process.
  707. SaveLastError();
  708. return bReturn;
  709. }
  710. // close the handle to the process
  711. // Current user can kill the process.
  712. CloseHandle( hProcess );
  713. hProcess = NULL;
  714. // get the window station and desktop information
  715. hWnd = ( HWND ) DynArrayItemAsHandle( m_arrRecord, TASK_HWND );
  716. pwszDesktop = DynArrayItemAsString( m_arrRecord, TASK_DESK );
  717. pwszWindowStation = DynArrayItemAsString( m_arrRecord, TASK_WINSTA );
  718. // check whether window window handle exists for this process or not if not, return
  719. if ( hWnd == NULL )
  720. {
  721. SetLastError( ( DWORD )CO_E_NOT_SUPPORTED );
  722. SetReason( ERROR_CANNOT_KILL_SILENTLY );
  723. return bReturn;
  724. }
  725. // get and save the current window station and desktop
  726. hwinstaSave = GetProcessWindowStation();
  727. hdeskSave = GetThreadDesktop( GetCurrentThreadId() );
  728. // open current tasks window station and change the context to the new workstation
  729. if ( NULL != pwszWindowStation )
  730. {
  731. //
  732. // process has window station ... get it
  733. hWinSta = OpenWindowStation( pwszWindowStation,
  734. FALSE, WINSTA_ENUMERATE | WINSTA_ENUMDESKTOPS );
  735. if ( NULL == hWinSta )
  736. {
  737. // failed in getting the process window station
  738. SaveLastError();
  739. return FALSE;
  740. }
  741. else
  742. {
  743. // change the context to the new workstation
  744. if ( ( hWinSta != hwinstaSave ) && ( FALSE == SetProcessWindowStation( hWinSta ) ) )
  745. {
  746. // failed in changing the context
  747. // restore the context to the previous window station
  748. CloseWindowStation( hWinSta );
  749. SaveLastError();
  750. return FALSE;
  751. }
  752. }
  753. }
  754. // open the tasks desktop and change the context to the new desktop
  755. if ( NULL != pwszDesktop )
  756. {
  757. //
  758. // process has desktop ... get it
  759. hDesk = OpenDesktop( pwszDesktop, 0, FALSE, DESKTOP_ENUMERATE );
  760. if ( NULL == hDesk )
  761. {
  762. // failed in getting the process desktop
  763. // restore the context to the previous window station
  764. if ( ( NULL != hWinSta ) && ( hWinSta != hwinstaSave ) )
  765. {
  766. SetProcessWindowStation( hwinstaSave );
  767. CloseWindowStation( hWinSta );
  768. }
  769. SaveLastError();
  770. return FALSE;
  771. }
  772. else
  773. {
  774. // change the context to the new desktop
  775. if ( ( hDesk != hdeskSave ) && ( FALSE == SetThreadDesktop( hDesk ) ) )
  776. {
  777. // failed in changing the context
  778. // restore the context to the previous window station
  779. CloseDesktop( hDesk );
  780. if ( ( NULL != hWinSta ) && ( hWinSta != hwinstaSave ) )
  781. {
  782. SetProcessWindowStation( hwinstaSave );
  783. CloseWindowStation( hWinSta );
  784. }
  785. SaveLastError();
  786. return FALSE;
  787. }
  788. }
  789. }
  790. // atlast ... now kill the process
  791. if ( ( NULL != hWnd ) && ( PostMessage( hWnd, WM_CLOSE, 0, 0 ) == FALSE ) )
  792. {
  793. // failed in posting the message
  794. SaveLastError();
  795. }
  796. else
  797. {
  798. bReturn = TRUE;
  799. }
  800. // restore the previous desktop
  801. if ( ( NULL != hDesk ) && ( hDesk != hdeskSave ) )
  802. {
  803. SetThreadDesktop( hdeskSave );
  804. CloseDesktop( hDesk );
  805. }
  806. // restore the context to the previous window station
  807. if ( ( NULL != hWinSta ) && ( hWinSta != hwinstaSave ) )
  808. {
  809. SetProcessWindowStation( hwinstaSave );
  810. CloseWindowStation( hWinSta );
  811. }
  812. // inform success
  813. return bReturn;
  814. }
  815. BOOL
  816. CTaskKill::ForciblyKillProcessOnLocalSystem(
  817. void
  818. )
  819. /*++
  820. Routine Description:
  821. Terminates the process forcibly ... this is for local system only
  822. Arguments:
  823. NONE
  824. Return Value:
  825. TRUE upon successfull and FALSE if failed
  826. --*/
  827. {
  828. // local variables
  829. DWORD dwExitCode = 0;
  830. HANDLE hProcess = NULL;
  831. // get the handle to the process using the process id
  832. hProcess = OpenProcess(
  833. PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION, FALSE, m_dwProcessId );
  834. // check whether we got the handle successfully or not ... if not error
  835. if ( NULL == hProcess )
  836. {
  837. // failed in getting the process handle ... may be process might have finished
  838. // there is one occassion in which, we get the last error as invalid parameter
  839. // 'coz it doesn't convey proper message to the user, we will check for that error
  840. // and change the message appropriately
  841. if ( GetLastError() == ERROR_INVALID_PARAMETER )
  842. {
  843. SetLastError( ( DWORD )CO_E_NOT_SUPPORTED );
  844. }
  845. // save the error message
  846. SaveLastError();
  847. // return failure
  848. return FALSE;
  849. }
  850. // get the state of the process
  851. if ( FALSE == GetExitCodeProcess( hProcess, &dwExitCode ) )
  852. {
  853. // unknow error has occured ... failed
  854. CloseHandle( hProcess ); // close the process handle
  855. SaveLastError();
  856. return FALSE;
  857. }
  858. // now check whether the process is active or not
  859. if ( STILL_ACTIVE != dwExitCode )
  860. {
  861. // process is not active ... it is already terminated
  862. CloseHandle( hProcess ); // close the process handle
  863. SetLastError( ( DWORD )SCHED_E_TASK_NOT_RUNNING );
  864. SaveLastError();
  865. return FALSE;
  866. }
  867. // now forcibly try to terminate the process ( exit code will be 1 )
  868. if ( TerminateProcess( hProcess, 1 ) == FALSE )
  869. {
  870. // failed in terminating the process
  871. CloseHandle( hProcess ); // close the process handle
  872. // there is one occassion in which, we get the last error as invalid parameter
  873. // 'coz it doesn't convey proper message to the user, we will check for that error
  874. // and change the message appropriately
  875. if ( GetLastError() == ERROR_INVALID_PARAMETER )
  876. {
  877. SetLastError( ( DWORD )CO_E_NOT_SUPPORTED );
  878. }
  879. // save the error message
  880. SaveLastError();
  881. // return failure
  882. return FALSE;
  883. }
  884. // successfully terminated the process with exit code 1
  885. CloseHandle( hProcess ); // close the process handle
  886. return TRUE; // inform success
  887. }
  888. BOOL
  889. CTaskKill::ForciblyKillProcessOnRemoteSystem(
  890. void
  891. )
  892. /*++
  893. Routine Description:
  894. Terminates the process forcibly ... uses WMI for terminating
  895. this is for remote system
  896. Arguments:
  897. NONE
  898. Return Value:
  899. TRUE upon successfull and FALSE if failed
  900. --*/
  901. {
  902. // local variables
  903. HRESULT hr = S_OK;
  904. _variant_t varTemp;
  905. BOOL bResult = FALSE;
  906. LPCWSTR pwszPath = NULL;
  907. IWbemClassObject* pInParams = NULL;
  908. IWbemClassObject* pOutParams = NULL;
  909. IWbemCallResult* pCallResult = NULL;
  910. // get the object path
  911. pwszPath = DynArrayItemAsString( m_arrRecord, TASK_OBJPATH );
  912. if ( NULL == pwszPath )
  913. {
  914. SetLastError( ( DWORD )STG_E_UNKNOWN );
  915. SaveLastError();
  916. return FALSE;
  917. }
  918. try
  919. {
  920. // create an instance for input parameters
  921. SAFE_EXECUTE( m_pWbemTerminateInParams->SpawnInstance( 0, &pInParams ) );
  922. // set the reason ( abnormal termination )
  923. varTemp = 1L;
  924. SAFE_EXECUTE( PropertyPut( pInParams, TERMINATE_INPARAM_REASON, varTemp ) );
  925. // now execute the method ( semi-synchronous call )
  926. SAFE_EXECUTE( m_pWbemServices->ExecMethod(
  927. _bstr_t( pwszPath ), _bstr_t( WIN32_PROCESS_METHOD_TERMINATE ),
  928. WBEM_FLAG_RETURN_IMMEDIATELY, NULL, pInParams, NULL, &pCallResult ) );
  929. // set security info to the interface
  930. SAFE_EXECUTE( SetInterfaceSecurity( pCallResult, m_pAuthIdentity ) );
  931. // keep on retring until we get the control or tries reached max
  932. LONG lStatus = 0;
  933. for ( DWORD dw = 0; dw < MAX_TIMEOUT_RETRIES; dw++ )
  934. {
  935. // get the call status
  936. hr = pCallResult->GetCallStatus( 0, &lStatus );
  937. if ( SUCCEEDED( hr ) )
  938. {
  939. break;
  940. }
  941. else
  942. {
  943. if ( hr == (HRESULT) WBEM_S_TIMEDOUT )
  944. {
  945. continue;
  946. }
  947. else
  948. {
  949. _com_issue_error( hr );
  950. }
  951. }
  952. }
  953. // check if time out max. retries finished
  954. if ( MAX_TIMEOUT_RETRIES == dw )
  955. {
  956. _com_issue_error( hr );
  957. }
  958. // now get the result object
  959. SAFE_EXECUTE( pCallResult->GetResultObject( MAX_TERMINATE_TIMEOUT, &pOutParams ) );
  960. // get the return value of the result object
  961. DWORD dwReturnValue = 0;
  962. if ( PropertyGet( pOutParams, WMI_RETURNVALUE, dwReturnValue ) == FALSE )
  963. {
  964. _com_issue_error( ERROR_INTERNAL_ERROR );
  965. }
  966. // now check the return value
  967. // if should be zero .. if not .. failed
  968. if ( 0 != dwReturnValue )
  969. {
  970. //
  971. // format the message and set the reason
  972. // frame the error error message depending on the error
  973. if ( 2 == dwReturnValue )
  974. {
  975. SetLastError( ( DWORD )STG_E_ACCESSDENIED );
  976. SaveLastError();
  977. }
  978. else
  979. {
  980. if ( 3 == dwReturnValue )
  981. {
  982. SetLastError( ( DWORD )ERROR_DS_INSUFF_ACCESS_RIGHTS );
  983. SaveLastError();
  984. }
  985. else
  986. {
  987. CHString str;
  988. str.Format( ERROR_UNABLE_TO_TERMINATE, dwReturnValue );
  989. SetReason( str );
  990. }
  991. }
  992. }
  993. else
  994. {
  995. // everything went successfully ... process terminated successfully
  996. bResult = TRUE;
  997. }
  998. }
  999. catch( _com_error& e )
  1000. {
  1001. // save the error message and mark as failure
  1002. WMISaveError( e );
  1003. bResult = FALSE;
  1004. }
  1005. catch( CHeap_Exception )
  1006. {
  1007. WMISaveError( E_OUTOFMEMORY );
  1008. bResult = FALSE;
  1009. }
  1010. // release the in and out params references
  1011. SAFE_RELEASE( pInParams );
  1012. SAFE_RELEASE( pOutParams );
  1013. SAFE_RELEASE( pCallResult );
  1014. // return the result
  1015. return bResult;
  1016. }
  1017. LONG
  1018. CTaskKill::MatchTaskToKill(
  1019. OUT DWORD& dwMatchedIndex
  1020. )
  1021. /*++
  1022. Routine Description:
  1023. Matches a task to kill.
  1024. Arguments:
  1025. [ out ] dwMatchedIndex : Process Id that needs to be killed.
  1026. Return Value:
  1027. If found task to delete then index value from dynamic array
  1028. is returned else -1 is returned.
  1029. --*/
  1030. {
  1031. // local variables
  1032. LONG lCount = 0;
  1033. DWORD dwLength = 0;
  1034. LPCWSTR pwsz = NULL;
  1035. LPCWSTR pwszTask = NULL;
  1036. // check if this task has to be killed or not
  1037. lCount = DynArrayGetCount( m_arrTasksToKill );
  1038. for( LONG lIndex = 0; lIndex < lCount; lIndex++ )
  1039. {
  1040. // get the task specified
  1041. pwszTask = DynArrayItemAsString( m_arrTasksToKill, lIndex );
  1042. if ( NULL == pwszTask )
  1043. {
  1044. return -1;
  1045. }
  1046. // check with process id first ( only if task is in numeric format )
  1047. dwMatchedIndex = TASK_PID;
  1048. if ( IsNumeric(pwszTask, 10, FALSE) && (m_dwProcessId == (DWORD) AsLong(pwszTask, 10)) )
  1049. {
  1050. return lIndex; // specified task matched with current process id
  1051. }
  1052. // determine the no. of characters to compare
  1053. dwLength = 0;
  1054. pwsz = FindChar( pwszTask, L'*', 0 );
  1055. if ( NULL != pwsz )
  1056. {
  1057. // '*' - wildcard is specified in the image name
  1058. // so, determine the no. of characters to compare
  1059. // but before that check the length of the string pointer from '*'
  1060. // it should be 1 - meaning the '*' can be specified only at the end
  1061. // but not in the middle
  1062. if ( 1 == StringLength( pwsz, 0 ) )
  1063. {
  1064. dwLength = StringLength( pwszTask, 0 ) - StringLength( pwsz, 0 );
  1065. }
  1066. }
  1067. // check with image name
  1068. dwMatchedIndex = TASK_IMAGENAME;
  1069. if ( StringCompare( m_strImageName, pwszTask, TRUE, dwLength ) == 0 )
  1070. {
  1071. return lIndex; // specified task mathed with the image name
  1072. }
  1073. }
  1074. // return the index
  1075. return -1;
  1076. }
  1077. BOOL
  1078. CTaskKill::CanTerminate(
  1079. void
  1080. )
  1081. /*++
  1082. Routine Description:
  1083. Invokes the appropriate kill function based on the mode of termination
  1084. Arguments:
  1085. NONE
  1086. Return Value:
  1087. TRUE upon successfull and FALSE if failed
  1088. --*/
  1089. {
  1090. // local variables
  1091. DWORD dw = 0;
  1092. DWORD dwCount = 0;
  1093. LPCWSTR pwszTaskToTerminate = NULL;
  1094. //
  1095. // prepare a list of os critical tasks
  1096. LPCWSTR pwszTasks[] = {
  1097. PROCESS_CSRSS_EXE,
  1098. PROCESS_SMSS_EXE,
  1099. PROCESS_SERVICES_EXE,
  1100. PROCESS_WINLOGON_EXE
  1101. };
  1102. // process id with 0 cannot be terminated
  1103. if ( 0 == m_dwProcessId )
  1104. {
  1105. SetReason( ERROR_CRITICAL_SYSTEM_PROCESS );
  1106. return FALSE; // task should not be terminated
  1107. }
  1108. // the process cannot be terminated itself
  1109. if ( m_dwProcessId == m_dwCurrentPid )
  1110. {
  1111. SetReason( ERROR_CANNOT_KILL_ITSELF );
  1112. return FALSE;
  1113. }
  1114. // get the task name which user is trying to terminate
  1115. pwszTaskToTerminate = DynArrayItemAsString( m_arrRecord, TASK_IMAGENAME );
  1116. if ( NULL == pwszTaskToTerminate )
  1117. {
  1118. SetLastError( ( DWORD )STG_E_UNKNOWN );
  1119. SaveLastError();
  1120. return FALSE; // task should not be terminated
  1121. }
  1122. // check if user is trying to terminate the os critical task
  1123. dwCount = SIZE_OF_ARRAY( pwszTasks );
  1124. for( dw = 0; dw < dwCount; dw++ )
  1125. {
  1126. if ( StringCompare( pwszTasks[ dw ], pwszTaskToTerminate, TRUE, 0 ) == 0 )
  1127. {
  1128. SetReason( ERROR_CRITICAL_SYSTEM_PROCESS );
  1129. return FALSE; // task should not be terminated
  1130. }
  1131. }
  1132. // task can be terminated
  1133. return TRUE;
  1134. }
  1135. VOID
  1136. CTaskKill::SaveData(
  1137. IN IWbemClassObject* pWmiObject
  1138. )
  1139. /*++
  1140. Routine Description:
  1141. Saves process and its information.
  1142. Arguments:
  1143. IN pWmiObject : Interface pointer.
  1144. Return Value:
  1145. VOID
  1146. --*/
  1147. {
  1148. // local variables
  1149. CHString str;
  1150. DWORD dwValue = 0;
  1151. try
  1152. {
  1153. // process id
  1154. PropertyGet( pWmiObject, WIN32_PROCESS_PROPERTY_PROCESSID, m_dwProcessId );
  1155. DynArraySetDWORD( m_arrRecord, TASK_PID, m_dwProcessId );
  1156. // image name
  1157. PropertyGet( pWmiObject, WIN32_PROCESS_PROPERTY_IMAGENAME, m_strImageName );
  1158. DynArraySetString( m_arrRecord, TASK_IMAGENAME, m_strImageName, 0 );
  1159. // object path
  1160. PropertyGet( pWmiObject, WIN32_PROCESS_SYSPROPERTY_PATH, str );
  1161. DynArraySetString( m_arrRecord, TASK_OBJPATH, str, 0 );
  1162. // host name
  1163. PropertyGet( pWmiObject, WIN32_PROCESS_PROPERTY_COMPUTER, str );
  1164. DynArraySetString( m_arrRecord, TASK_HOSTNAME, str, 0 );
  1165. // parent process id
  1166. PropertyGet( pWmiObject, WIN32_PROCESS_PROPERTY_PARENTPROCESSID, dwValue, 0 );
  1167. DynArraySetDWORD( m_arrRecord, TASK_CREATINGPROCESSID, dwValue );
  1168. // user context
  1169. SetUserContext( pWmiObject );
  1170. // cpu time
  1171. SetCPUTime( pWmiObject );
  1172. // window title and application / process state
  1173. SetWindowTitle( );
  1174. // services
  1175. SetServicesInfo( );
  1176. // modules
  1177. SetModulesInfo( );
  1178. // check if the tree termination is requested
  1179. if ( TRUE == m_bTree )
  1180. {
  1181. // session id
  1182. PropertyGet( pWmiObject, WIN32_PROCESS_PROPERTY_SESSION, dwValue, 0 );
  1183. DynArraySetDWORD( m_arrRecord, TASK_SESSION, dwValue );
  1184. // mem usage
  1185. SetMemUsage( pWmiObject );
  1186. }
  1187. else
  1188. {
  1189. //
  1190. // status, session id, memory usage
  1191. // property retrieval is built into WMI
  1192. //
  1193. }
  1194. }
  1195. catch( CHeap_Exception )
  1196. {
  1197. SetLastError( ( DWORD )E_OUTOFMEMORY );
  1198. SaveLastError();
  1199. }
  1200. }
  1201. VOID
  1202. CTaskKill::SetUserContext(
  1203. IN IWbemClassObject* pWmiObject
  1204. )
  1205. /*++
  1206. Routine Description:
  1207. Store username property of a process in dynaimc array.
  1208. Arguments:
  1209. [ in ] pWmiObject : Contains interface pointer.
  1210. Return Value:
  1211. VOID
  1212. --*/
  1213. {
  1214. // local variables
  1215. HRESULT hr = S_OK;
  1216. CHString str;
  1217. CHString strPath;
  1218. CHString strDomain;
  1219. CHString strUserName;
  1220. BOOL bResult = FALSE;
  1221. IWbemClassObject* pOutParams = NULL;
  1222. // check if user name has to be retrieved or not
  1223. if ( FALSE == m_bNeedUserContextInfo )
  1224. {
  1225. return;
  1226. }
  1227. try
  1228. {
  1229. //
  1230. // for getting the user first we will try with API
  1231. // it at all API fails, we will try to get the same information from WMI
  1232. //
  1233. // get the user name
  1234. if ( LoadUserNameFromWinsta( strDomain, strUserName ) == TRUE )
  1235. {
  1236. // format the user name
  1237. str.Format( L"%s\\%s", strDomain, strUserName );
  1238. }
  1239. else
  1240. {
  1241. // user name has to be retrieved - get the path of the current object
  1242. bResult = PropertyGet( pWmiObject, WIN32_PROCESS_SYSPROPERTY_PATH, strPath );
  1243. if ( ( FALSE == bResult ) || ( strPath.GetLength() == 0 ) )
  1244. {
  1245. return;
  1246. }
  1247. // execute the GetOwner method and get the user name
  1248. // under which the current process is executing
  1249. hr = m_pWbemServices->ExecMethod( _bstr_t( strPath ),
  1250. _bstr_t( WIN32_PROCESS_METHOD_GETOWNER ), 0, NULL, NULL, &pOutParams, NULL );
  1251. if ( FAILED( hr ) )
  1252. {
  1253. SAFE_RELEASE( pOutParams );
  1254. return;
  1255. }
  1256. // get the domain and user values from out params object
  1257. // NOTE: do not check the results
  1258. PropertyGet( pOutParams, GETOWNER_RETURNVALUE_DOMAIN, strDomain, L"" );
  1259. PropertyGet( pOutParams, GETOWNER_RETURNVALUE_USER, strUserName, L"" );
  1260. // 'pOutParams' is no more required.
  1261. SAFE_RELEASE( pOutParams );
  1262. // get the value
  1263. if ( strDomain.GetLength() != 0 )
  1264. {
  1265. str.Format( L"%s\\%s", strDomain, strUserName );
  1266. }
  1267. else
  1268. {
  1269. if ( strUserName.GetLength() != 0 )
  1270. {
  1271. str = strUserName;
  1272. }
  1273. }
  1274. }
  1275. }
  1276. catch( CHeap_Exception )
  1277. {
  1278. SetLastError( ( DWORD ) E_OUTOFMEMORY );
  1279. return;
  1280. }
  1281. // save the info
  1282. DynArraySetString( m_arrRecord, TASK_USERNAME, str, 0 );
  1283. }
  1284. VOID
  1285. CTaskKill::SetCPUTime(
  1286. IN IWbemClassObject* pWmiObject
  1287. )
  1288. /*++
  1289. Routine Description:
  1290. Store CPUTIME property of a process in dynaimc array.
  1291. Arguments:
  1292. [ in ] pWmiObject : Contains interface pointer.
  1293. Return Value:
  1294. VOID
  1295. --*/
  1296. {
  1297. // local variables
  1298. CHString str;
  1299. ULONGLONG ullCPUTime = 0;
  1300. ULONGLONG ullUserTime = 0;
  1301. ULONGLONG ullKernelTime = 0;
  1302. try
  1303. {
  1304. // get the KernelModeTime value
  1305. PropertyGet( pWmiObject, WIN32_PROCESS_PROPERTY_KERNELMODETIME, ullKernelTime );
  1306. // get the user mode time
  1307. PropertyGet( pWmiObject, WIN32_PROCESS_PROPERTY_USERMODETIME, ullUserTime );
  1308. // calculate the CPU time
  1309. ullCPUTime = ullUserTime + ullKernelTime;
  1310. // now convert the long time into hours format
  1311. TIME_FIELDS time;
  1312. RtlTimeToElapsedTimeFields ( (LARGE_INTEGER* ) &ullCPUTime, &time );
  1313. // convert the days into hours
  1314. time.Hour = static_cast<CSHORT>( time.Hour + static_cast<SHORT>( time.Day * 24 ) );
  1315. // prepare into time format ( user locale specific time seperator )
  1316. str.Format( L"%d:%02d:%02d", time.Hour, time.Minute, time.Second );
  1317. // save the info
  1318. DynArraySetString( m_arrRecord, TASK_CPUTIME, str, 0 );
  1319. }
  1320. catch( CHeap_Exception )
  1321. {
  1322. SetLastError( ( DWORD )E_OUTOFMEMORY );
  1323. SaveLastError();
  1324. }
  1325. }
  1326. VOID
  1327. CTaskKill::SetWindowTitle(
  1328. void
  1329. )
  1330. /*++
  1331. Routine Description:
  1332. Store 'Window Title' property of a process in dynaimc array.
  1333. Arguments:
  1334. NONE
  1335. Return Value:
  1336. VOID
  1337. --*/
  1338. {
  1339. // local variables
  1340. LONG lTemp = 0;
  1341. HWND hWnd = NULL;
  1342. BOOL bHung = FALSE;
  1343. LPCTSTR pszTemp = NULL;
  1344. // get the window details ... window station, desktop, window title
  1345. // NOTE: This will work only for local system
  1346. DynArraySetString( m_arrRecord, TASK_STATUS, VALUE_UNKNOWN, 0 );
  1347. lTemp = DynArrayFindDWORDEx( m_arrWindowTitles, CTaskKill::twiProcessId, m_dwProcessId );
  1348. if ( -1 != lTemp )
  1349. {
  1350. // save the window title
  1351. pszTemp = DynArrayItemAsString2( m_arrWindowTitles, lTemp, CTaskKill::twiTitle );
  1352. if ( NULL != pszTemp )
  1353. {
  1354. DynArraySetString( m_arrRecord, TASK_WINDOWTITLE, pszTemp, 0 );
  1355. }
  1356. // save the window station
  1357. pszTemp = DynArrayItemAsString2( m_arrWindowTitles, lTemp, CTaskKill::twiWinSta );
  1358. if ( NULL != pszTemp )
  1359. {
  1360. DynArraySetString( m_arrRecord, TASK_WINSTA, pszTemp, 0 );
  1361. }
  1362. // save the desktop information
  1363. pszTemp = DynArrayItemAsString2( m_arrWindowTitles, lTemp, CTaskKill::twiDesktop );
  1364. if ( NULL != pszTemp )
  1365. {
  1366. DynArraySetString( m_arrRecord, TASK_DESK, pszTemp, 0 );
  1367. }
  1368. // save the window handle also
  1369. hWnd = (HWND) DynArrayItemAsHandle2( m_arrWindowTitles, lTemp, CTaskKill::twiHandle );
  1370. if ( NULL != hWnd )
  1371. {
  1372. DynArraySetHandle( m_arrRecord, TASK_HWND, hWnd );
  1373. // determine the application / process hung information
  1374. bHung = DynArrayItemAsBOOL2( m_arrWindowTitles, lTemp, CTaskKill::twiHungInfo );
  1375. if ( TRUE == bHung )
  1376. {
  1377. // not responding
  1378. DynArraySetString( m_arrRecord, TASK_STATUS, VALUE_NOTRESPONDING, 0 );
  1379. }
  1380. else
  1381. {
  1382. // running
  1383. DynArraySetString( m_arrRecord, TASK_STATUS, VALUE_RUNNING, 0 );
  1384. }
  1385. }
  1386. }
  1387. }
  1388. VOID
  1389. CTaskKill::SetMemUsage(
  1390. IN IWbemClassObject* pWmiObject
  1391. )
  1392. /*++
  1393. Routine Description:
  1394. Store 'Memory usage' property of a process in dynaimc array.
  1395. Arguments:
  1396. [ in ] pWmiObject : Contains interface pointer.
  1397. Return Value:
  1398. VOID
  1399. --*/
  1400. {
  1401. // local variables
  1402. CHString str;
  1403. NTSTATUS ntstatus;
  1404. ULONGLONG ullMemUsage = 0;
  1405. LARGE_INTEGER liTemp = { 0, 0 };
  1406. CHAR szTempBuffer[ 33 ] = "\0";
  1407. try
  1408. {
  1409. // NOTE:
  1410. // ----
  1411. // The max. value of
  1412. // (2 ^ 64) - 1 = "18,446,744,073,709,600,000 K" (29 chars).
  1413. //
  1414. // so, the buffer size to store the number is fixed as 32 characters
  1415. // which is more than the 29 characters in actuals
  1416. // set the default value
  1417. DynArraySetString( m_arrRecord, TASK_MEMUSAGE, L"0", 0 );
  1418. // get the KernelModeTime value
  1419. if ( PropertyGet( pWmiObject, WIN32_PROCESS_PROPERTY_MEMUSAGE, ullMemUsage ) == FALSE )
  1420. {
  1421. return;
  1422. }
  1423. // convert the value into K Bytes
  1424. ullMemUsage /= 1024;
  1425. // now again convert the value from ULONGLONG to string and check the result
  1426. liTemp.QuadPart = ullMemUsage;
  1427. ntstatus = RtlLargeIntegerToChar( &liTemp, 10, SIZE_OF_ARRAY( szTempBuffer ), szTempBuffer );
  1428. if ( ! NT_SUCCESS( ntstatus ) )
  1429. {
  1430. return;
  1431. }
  1432. // now copy this info into UNICODE buffer
  1433. str = szTempBuffer;
  1434. // save the id
  1435. DynArraySetString( m_arrRecord, TASK_MEMUSAGE, str, 0 );
  1436. }
  1437. catch( CHeap_Exception )
  1438. {
  1439. SetLastError( ( DWORD )E_OUTOFMEMORY );
  1440. SaveLastError();
  1441. }
  1442. }
  1443. VOID
  1444. CTaskKill::SetServicesInfo(
  1445. void
  1446. )
  1447. /*++
  1448. Routine Description:
  1449. Store 'Service' property of a process in dynaimc array.
  1450. Arguments:
  1451. NONE
  1452. Return Value:
  1453. VOID
  1454. --*/
  1455. {
  1456. // local variables
  1457. HRESULT hr = S_OK;
  1458. CHString strQuery;
  1459. CHString strService;
  1460. ULONG ulReturned = 0;
  1461. BOOL bResult = FALSE;
  1462. BOOL bCanExit = FALSE;
  1463. TARRAY arrServices = NULL;
  1464. IEnumWbemClassObject* pEnumServices = NULL;
  1465. IWbemClassObject* pObjects[ MAX_ENUM_SERVICES ];
  1466. // check whether we need to gather services info or not .. if not skip
  1467. if ( FALSE == m_bNeedServicesInfo )
  1468. {
  1469. return;
  1470. }
  1471. // create array
  1472. arrServices = CreateDynamicArray();
  1473. if ( NULL == arrServices )
  1474. {
  1475. SetLastError( ( DWORD )E_OUTOFMEMORY );
  1476. SaveLastError();
  1477. return;
  1478. }
  1479. //
  1480. // for getting the services info first we will try with the one we got from API
  1481. // it at all API fails, we will try to get the same information from WMI
  1482. //
  1483. try
  1484. {
  1485. // check whether API returned services or not
  1486. if ( NULL != m_pServicesInfo )
  1487. {
  1488. // get the service names related to the current process
  1489. // identify all the services related to the current process ( based on the PID )
  1490. // and save the info
  1491. for ( DWORD dw = 0; dw < m_dwServicesCount; dw++ )
  1492. {
  1493. // compare the PID's
  1494. if ( m_dwProcessId == m_pServicesInfo[ dw ].ServiceStatusProcess.dwProcessId )
  1495. {
  1496. // this service is related with the current process ... store service name
  1497. DynArrayAppendString( arrServices, m_pServicesInfo[ dw ].lpServiceName, 0 );
  1498. }
  1499. }
  1500. }
  1501. else
  1502. {
  1503. try
  1504. {
  1505. // init the objects to NULL's
  1506. for( DWORD dw = 0; dw < MAX_ENUM_SERVICES; dw++ )
  1507. {
  1508. pObjects[ dw ] = NULL;
  1509. }
  1510. // prepare the query
  1511. strQuery.Format( WMI_SERVICE_QUERY, m_dwProcessId );
  1512. // execute the query
  1513. hr = m_pWbemServices->ExecQuery( _bstr_t( WMI_QUERY_TYPE ), _bstr_t( strQuery ),
  1514. WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, &pEnumServices );
  1515. // check the result
  1516. if ( FAILED( hr ) )
  1517. {
  1518. _com_issue_error( hr );
  1519. }
  1520. // set the security
  1521. hr = SetInterfaceSecurity( pEnumServices, m_pAuthIdentity );
  1522. if ( FAILED( hr ) )
  1523. {
  1524. _com_issue_error( hr );
  1525. }
  1526. // loop thru the service instances
  1527. do
  1528. {
  1529. // get the object ... wait
  1530. // NOTE: one-by-one
  1531. hr = pEnumServices->Next( WBEM_INFINITE, MAX_ENUM_SERVICES, pObjects, &ulReturned );
  1532. if ( hr == (HRESULT) WBEM_S_FALSE )
  1533. {
  1534. // we've reached the end of enumeration .. set the flag
  1535. bCanExit = TRUE;
  1536. }
  1537. else
  1538. {
  1539. if ( hr == (HRESULT) WBEM_S_TIMEDOUT || FAILED( hr ) )
  1540. {
  1541. //
  1542. // some error has occured ... oooppps
  1543. // exit from the loop
  1544. break;
  1545. }
  1546. }
  1547. // loop thru the objects and save the info
  1548. for( ULONG ul = 0; ul < ulReturned; ul++ )
  1549. {
  1550. // get the value of the property
  1551. bResult = PropertyGet( pObjects[ ul ], WIN32_SERVICE_PROPERTY_NAME, strService );
  1552. if ( TRUE == bResult )
  1553. {
  1554. DynArrayAppendString( arrServices, strService, 0 );
  1555. }
  1556. // release the interface
  1557. SAFE_RELEASE( pObjects[ ul ] );
  1558. }
  1559. } while ( bCanExit == FALSE );
  1560. }
  1561. catch( _com_error& e )
  1562. {
  1563. // save the error
  1564. WMISaveError( e );
  1565. }
  1566. }
  1567. // save and return
  1568. DynArraySetEx( m_arrRecord, TASK_SERVICES, arrServices );
  1569. }
  1570. catch( CHeap_Exception )
  1571. {
  1572. SetLastError( ( DWORD )E_OUTOFMEMORY );
  1573. SaveLastError();
  1574. }
  1575. // release the objects to NULL's
  1576. for( DWORD dw = 0; dw < MAX_ENUM_SERVICES; dw++ )
  1577. {
  1578. // release all the objects
  1579. SAFE_RELEASE( pObjects[ dw ] );
  1580. }
  1581. // now release the enumeration object
  1582. SAFE_RELEASE( pEnumServices );
  1583. }
  1584. BOOL
  1585. CTaskKill::SetModulesInfo(
  1586. void
  1587. )
  1588. /*++
  1589. Routine Description:
  1590. Store 'Modules' property of a process in dynaimc array.
  1591. Arguments:
  1592. [ in ] pWmiObject : Contains interface pointer.
  1593. Return Value:
  1594. TRUE if successful else FALSE.
  1595. --*/
  1596. {
  1597. // local variables
  1598. LONG lPos = 0;
  1599. BOOL bResult = FALSE;
  1600. TARRAY arrModules = NULL;
  1601. // check whether we need to get the modules or not
  1602. if ( FALSE == m_bNeedModulesInfo )
  1603. {
  1604. return TRUE;
  1605. }
  1606. // allocate for memory
  1607. arrModules = CreateDynamicArray();
  1608. if ( NULL == arrModules )
  1609. {
  1610. SetLastError( ( DWORD )E_OUTOFMEMORY );
  1611. SaveLastError();
  1612. return FALSE;
  1613. }
  1614. // the way we get the modules information is different for local remote
  1615. // so depending that call appropriate function
  1616. if ( ( TRUE == m_bLocalSystem ) && ( FALSE == m_bUseRemote ) )
  1617. {
  1618. // enumerate the modules for the current process
  1619. bResult = LoadModulesOnLocal( arrModules );
  1620. }
  1621. else
  1622. {
  1623. // identify the modules information for the current process ... remote system
  1624. bResult = GetModulesOnRemote( arrModules );
  1625. }
  1626. // check the result
  1627. if ( TRUE == bResult )
  1628. {
  1629. // check if the modules list contains the imagename also. If yes remove that entry
  1630. lPos = DynArrayFindString( arrModules, m_strImageName, TRUE, 0 );
  1631. if ( -1 != lPos )
  1632. {
  1633. // remove the entry
  1634. DynArrayRemove( arrModules, lPos );
  1635. }
  1636. }
  1637. // save the modules information to the array
  1638. // NOTE: irrespective of whether enumeration is success or not we will add the array
  1639. DynArraySetEx( m_arrRecord, TASK_MODULES, arrModules );
  1640. // return
  1641. return bResult;
  1642. }
  1643. BOOL
  1644. CTaskKill::LoadModulesOnLocal(
  1645. IN OUT TARRAY arrModules
  1646. )
  1647. /*++
  1648. Routine Description:
  1649. Store 'Modules' property of a process in dynaimc array for local system.
  1650. Arguments:
  1651. [ in out ] arrModules : Contains dynamic array.
  1652. Return Value:
  1653. TRUE if successful else FALSE.
  1654. --*/
  1655. {
  1656. // local variables
  1657. BOOL bResult = FALSE;
  1658. HANDLE hProcess = NULL;
  1659. // check the input values
  1660. if ( NULL == arrModules )
  1661. {
  1662. return FALSE;
  1663. }
  1664. // open the process handle
  1665. hProcess = OpenProcess( PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, m_dwProcessId );
  1666. if ( NULL == hProcess )
  1667. {
  1668. return FALSE; // failed in getting the process handle
  1669. }
  1670. #ifndef _WIN64
  1671. bResult = EnumerateLoadedModules( hProcess, EnumLoadedModulesProc, arrModules );
  1672. #else
  1673. bResult = EnumerateLoadedModules64( hProcess, EnumLoadedModulesProc64, arrModules );
  1674. #endif
  1675. // close the process handle .. we dont need this furthur
  1676. CloseHandle( hProcess );
  1677. hProcess = NULL;
  1678. // return
  1679. return bResult;
  1680. }
  1681. BOOL
  1682. CTaskKill::GetModulesOnRemote(
  1683. IN OUT TARRAY arrModules
  1684. )
  1685. /*++
  1686. Routine Description:
  1687. Store 'Modules' property of a process in dynaimc array for remote system.
  1688. Arguments:
  1689. [ in out ] arrModules : Contains dynamic array.
  1690. Return Value:
  1691. TRUE if successful else FALSE.
  1692. --*/
  1693. {
  1694. // local variables
  1695. DWORD dwOffset = 0;
  1696. DWORD dwInstance = 0;
  1697. PPERF_OBJECT_TYPE pot = NULL;
  1698. PPERF_OBJECT_TYPE potImages = NULL;
  1699. PPERF_INSTANCE_DEFINITION pidImages = NULL;
  1700. PPERF_COUNTER_BLOCK pcbImages = NULL;
  1701. PPERF_OBJECT_TYPE potAddressSpace = NULL;
  1702. PPERF_INSTANCE_DEFINITION pidAddressSpace = NULL;
  1703. PPERF_COUNTER_BLOCK pcbAddressSpace = NULL;
  1704. PPERF_COUNTER_DEFINITION pcd = NULL;
  1705. // check the input values
  1706. if ( NULL == arrModules )
  1707. {
  1708. return FALSE;
  1709. }
  1710. // check whether the performance object exists or not
  1711. // if doesn't exists, get the same using WMI
  1712. if ( NULL == m_pdb )
  1713. {
  1714. // invoke the WMI method
  1715. return GetModulesOnRemoteEx( arrModules );
  1716. }
  1717. // get the perf object types
  1718. pot = (PPERF_OBJECT_TYPE) ( (LPBYTE) m_pdb + m_pdb->HeaderLength );
  1719. for( DWORD dw = 0; dw < m_pdb->NumObjectTypes; dw++ )
  1720. {
  1721. if ( 740 == pot->ObjectNameTitleIndex )
  1722. {
  1723. potImages = pot;
  1724. }
  1725. else
  1726. {
  1727. if ( 786 == pot->ObjectNameTitleIndex )
  1728. {
  1729. potAddressSpace = pot;
  1730. }
  1731. }
  1732. // move to the next object
  1733. dwOffset = pot->TotalByteLength;
  1734. if( 0 != dwOffset )
  1735. {
  1736. pot = ( (PPERF_OBJECT_TYPE) ((PBYTE) pot + dwOffset));
  1737. }
  1738. }
  1739. // check whether we got both the object types or not
  1740. if ( ( NULL == potImages ) || ( NULL == potAddressSpace ) )
  1741. {
  1742. return FALSE;
  1743. }
  1744. // find the offset of the process id in the address space object type
  1745. // get the first counter definition of address space object
  1746. pcd = (PPERF_COUNTER_DEFINITION) ( (LPBYTE) potAddressSpace + potAddressSpace->HeaderLength);
  1747. // loop thru the counters and find the offset
  1748. dwOffset = 0;
  1749. for( DWORD dw = 0; dw < potAddressSpace->NumCounters; dw++)
  1750. {
  1751. // 784 is the counter for process id
  1752. if ( 784 == pcd->CounterNameTitleIndex )
  1753. {
  1754. dwOffset = pcd->CounterOffset;
  1755. break;
  1756. }
  1757. // next counter
  1758. pcd = ( (PPERF_COUNTER_DEFINITION) ( (LPBYTE) pcd + pcd->ByteLength) );
  1759. }
  1760. // check whether we got the offset or not
  1761. // if not, we are unsuccessful
  1762. if ( 0 == dwOffset )
  1763. {
  1764. // set the error message
  1765. SetLastError( ( DWORD )ERROR_ACCESS_DENIED );
  1766. SaveLastError();
  1767. return FALSE;
  1768. }
  1769. // get the instances
  1770. pidImages = (PPERF_INSTANCE_DEFINITION) ( (LPBYTE) potImages + potImages->DefinitionLength );
  1771. pidAddressSpace = (PPERF_INSTANCE_DEFINITION) ( (LPBYTE) potAddressSpace + potAddressSpace->DefinitionLength );
  1772. // counter blocks
  1773. pcbImages = (PPERF_COUNTER_BLOCK) ( (LPBYTE) pidImages + pidImages->ByteLength );
  1774. pcbAddressSpace = (PPERF_COUNTER_BLOCK) ( (LPBYTE) pidAddressSpace + pidAddressSpace->ByteLength );
  1775. // find the instance number of the process which we are looking for
  1776. for( dwInstance = 0; dwInstance < (DWORD) potAddressSpace->NumInstances; dwInstance++ )
  1777. {
  1778. // sub-local variables
  1779. DWORD dwProcessId = 0;
  1780. // get the process id
  1781. dwProcessId = *((DWORD*) ( (LPBYTE) pcbAddressSpace + dwOffset ));
  1782. // now check if this is the process which we are looking for
  1783. if ( dwProcessId == m_dwProcessId )
  1784. {
  1785. break;
  1786. }
  1787. // continue looping thru other instances
  1788. pidAddressSpace = (PPERF_INSTANCE_DEFINITION) ( (LPBYTE) pcbAddressSpace + pcbAddressSpace->ByteLength );
  1789. pcbAddressSpace = (PPERF_COUNTER_BLOCK) ( (LPBYTE) pidAddressSpace + pidAddressSpace->ByteLength );
  1790. }
  1791. // check whether we got the instance or not
  1792. // if not, there are no modules for this process
  1793. if ( dwInstance == ( DWORD )potAddressSpace->NumInstances )
  1794. {
  1795. return TRUE;
  1796. }
  1797. // now based the parent instance, collect all the modules
  1798. for( DWORD dw = 0; (LONG) dw < potImages->NumInstances; dw++)
  1799. {
  1800. // check the parent object instance number
  1801. if ( pidImages->ParentObjectInstance == dwInstance )
  1802. {
  1803. try
  1804. {
  1805. // sub-local variables
  1806. CHString str;
  1807. LPWSTR pwszTemp;
  1808. // get the buffer
  1809. pwszTemp = str.GetBufferSetLength( pidImages->NameLength + 10 ); // +10 to be on safe side
  1810. if ( NULL == pwszTemp )
  1811. {
  1812. SetLastError( ( DWORD )E_OUTOFMEMORY );
  1813. SaveLastError();
  1814. return FALSE;
  1815. }
  1816. // get the instance name
  1817. StringCopy( pwszTemp,
  1818. (LPWSTR) ( (LPBYTE) pidImages + pidImages->NameOffset ),
  1819. pidImages->NameLength + 1 );
  1820. // release buffer
  1821. str.ReleaseBuffer();
  1822. // add the info the userdata ( for us we will get that in the form of an array
  1823. LONG lIndex = DynArrayAppendString( arrModules, str, 0 );
  1824. if ( -1 == lIndex )
  1825. {
  1826. // append is failed .. this could be because of lack of memory .. stop the enumeration
  1827. return FALSE;
  1828. }
  1829. }
  1830. catch( CHeap_Exception )
  1831. {
  1832. SetLastError( ( DWORD )E_OUTOFMEMORY );
  1833. SaveLastError();
  1834. return FALSE;
  1835. }
  1836. }
  1837. // continue looping thru other instances
  1838. pidImages = (PPERF_INSTANCE_DEFINITION) ( (LPBYTE) pcbImages + pcbImages->ByteLength );
  1839. pcbImages = (PPERF_COUNTER_BLOCK) ( (LPBYTE) pidImages + pidImages->ByteLength );
  1840. }
  1841. return TRUE;
  1842. }
  1843. BOOL
  1844. CTaskKill::GetModulesOnRemoteEx(
  1845. IN OUT TARRAY arrModules
  1846. )
  1847. /*++
  1848. Routine Description:
  1849. Store 'Modules' property of a process in dynaimc array for remote system.
  1850. Arguments:
  1851. [ in out ] arrModules : Contains dynamic array.
  1852. Return Value:
  1853. TRUE if successful else FALSE.
  1854. --*/
  1855. {
  1856. // local variables
  1857. HRESULT hr;
  1858. CHString strQuery;
  1859. CHString strModule;
  1860. CHString strFileName;
  1861. CHString strExtension;
  1862. ULONG ulReturned = 0;
  1863. BOOL bRetValue = TRUE;
  1864. BOOL bResult = FALSE;
  1865. BOOL bCanExit = FALSE;
  1866. LPCWSTR pwszPath = NULL;
  1867. IEnumWbemClassObject* pEnumModules = NULL;
  1868. IWbemClassObject* pObjects[ MAX_ENUM_MODULES ];
  1869. // check the input values
  1870. if ( NULL == arrModules )
  1871. {
  1872. return FALSE;
  1873. }
  1874. // get the path of the object from the tasks array
  1875. pwszPath = DynArrayItemAsString( m_arrRecord, TASK_OBJPATH );
  1876. if ( NULL == pwszPath )
  1877. {
  1878. return FALSE;
  1879. }
  1880. //determine the length of the module name ..
  1881. try
  1882. {
  1883. // init the objects to NULL's
  1884. for( DWORD dw = 0; dw < MAX_ENUM_MODULES; dw++ )
  1885. {
  1886. pObjects[ dw ] = NULL;
  1887. }
  1888. // prepare the query
  1889. strQuery.Format( WMI_MODULES_QUERY, pwszPath );
  1890. // execute the query
  1891. hr = m_pWbemServices->ExecQuery( _bstr_t( WMI_QUERY_TYPE ), _bstr_t( strQuery ),
  1892. WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, &pEnumModules );
  1893. // check the result
  1894. if ( FAILED( hr ) )
  1895. {
  1896. _com_issue_error( hr );
  1897. }
  1898. // set the security
  1899. hr = SetInterfaceSecurity( pEnumModules, m_pAuthIdentity );
  1900. if ( FAILED( hr ) )
  1901. {
  1902. _com_issue_error( hr );
  1903. }
  1904. // loop thru the instances
  1905. do
  1906. {
  1907. // get the object ... wait
  1908. // NOTE: one-by-one
  1909. hr = pEnumModules->Next( WBEM_INFINITE, MAX_ENUM_MODULES, pObjects, &ulReturned );
  1910. if ( (HRESULT) WBEM_S_FALSE == hr )
  1911. {
  1912. // we've reached the end of enumeration .. set the flag
  1913. bCanExit = TRUE;
  1914. }
  1915. else
  1916. {
  1917. if ( ( (HRESULT) WBEM_S_TIMEDOUT == hr ) || FAILED( hr ))
  1918. {
  1919. // some error has occured ... oooppps
  1920. WMISaveError( hr );
  1921. SetLastError( ( DWORD )STG_E_UNKNOWN );
  1922. break;
  1923. }
  1924. }
  1925. // loop thru the objects and save the info
  1926. for( ULONG ul = 0; ul < ulReturned; ul++ )
  1927. {
  1928. // get the file name
  1929. bResult = PropertyGet( pObjects[ ul ], CIM_DATAFILE_PROPERTY_FILENAME, strFileName );
  1930. if ( FALSE == bResult )
  1931. {
  1932. // release the interface
  1933. SAFE_RELEASE( pObjects[ ul ] );
  1934. continue;
  1935. }
  1936. // get the extension
  1937. bResult = PropertyGet( pObjects[ ul ], CIM_DATAFILE_PROPERTY_EXTENSION, strExtension );
  1938. if ( FALSE == bResult )
  1939. {
  1940. // release the interface
  1941. SAFE_RELEASE( pObjects[ ul ] );
  1942. continue;
  1943. }
  1944. // format the module name
  1945. strModule.Format( L"%s.%s", strFileName, strExtension );
  1946. // add the info the userdata ( for us we will get that in the form of an array
  1947. LONG lIndex = DynArrayAppendString( arrModules, strModule, 0 );
  1948. if ( lIndex == -1 )
  1949. {
  1950. // append is failed .. this could be because of lack of memory .. stop the enumeration
  1951. // release the objects to NULL's
  1952. for( DWORD dw = 0; dw < MAX_ENUM_MODULES; dw++ )
  1953. {
  1954. // release all the objects
  1955. SAFE_RELEASE( pObjects[ dw ] );
  1956. }
  1957. // now release the enumeration object
  1958. SAFE_RELEASE( pEnumModules );
  1959. return FALSE;
  1960. }
  1961. // release the interface
  1962. SAFE_RELEASE( pObjects[ ul ] );
  1963. }
  1964. } while ( bCanExit == FALSE );
  1965. }
  1966. catch( _com_error& e )
  1967. {
  1968. // save the error
  1969. WMISaveError( e );
  1970. bRetValue = FALSE;
  1971. }
  1972. catch( CHeap_Exception )
  1973. {
  1974. // out of memory
  1975. WMISaveError( E_OUTOFMEMORY );
  1976. bRetValue = FALSE;
  1977. }
  1978. // release the objects to NULL's
  1979. for( DWORD dw = 0; dw < MAX_ENUM_MODULES; dw++ )
  1980. {
  1981. // release all the objects
  1982. SAFE_RELEASE( pObjects[ dw ] );
  1983. }
  1984. // now release the enumeration object
  1985. SAFE_RELEASE( pEnumModules );
  1986. // return
  1987. return bRetValue;
  1988. }
  1989. #ifndef _WIN64
  1990. BOOL
  1991. EnumLoadedModulesProc(
  1992. LPSTR lpszModuleName,
  1993. ULONG ulModuleBase,
  1994. ULONG ulModuleSize,
  1995. PVOID pUserData
  1996. )
  1997. #else
  1998. BOOL
  1999. EnumLoadedModulesProc64(
  2000. LPSTR lpszModuleName,
  2001. DWORD64 ulModuleBase,
  2002. ULONG ulModuleSize,
  2003. PVOID pUserData
  2004. )
  2005. #endif
  2006. /*++
  2007. Routine Description:
  2008. Arguments:
  2009. [ in ] lpszModuleName : Contains module name.
  2010. [ in out ] ulModuleBase :
  2011. [ in ] ulModuleSize :
  2012. [ in ] pUserData : Username information.
  2013. Return Value:
  2014. TRUE if successful else FALSE.
  2015. --*/
  2016. {
  2017. // local variables
  2018. CHString str;
  2019. LONG lIndex = 0;
  2020. TARRAY arrModules = NULL;
  2021. // check the input values
  2022. if ( ( NULL == lpszModuleName ) || ( NULL == pUserData ) )
  2023. {
  2024. return FALSE;
  2025. }
  2026. // get the array pointer into the local variable
  2027. arrModules = (TARRAY) pUserData;
  2028. try
  2029. {
  2030. // copy the module name into the local string variable
  2031. // ( conversion from multibyte to unicode will automatically take place )
  2032. str = lpszModuleName;
  2033. // add the info the userdata ( for us we will get that in the form of an array
  2034. lIndex = DynArrayAppendString( arrModules, str, 0 );
  2035. if ( lIndex == -1 )
  2036. {
  2037. // append is failed .. this could be because of lack of memory .. stop the enumeration
  2038. return FALSE;
  2039. }
  2040. }
  2041. catch( CHeap_Exception )
  2042. {
  2043. // out of memory stop the enumeration
  2044. return FALSE;
  2045. }
  2046. // success .. continue the enumeration
  2047. return TRUE;
  2048. }