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.

1116 lines
32 KiB

  1. // *********************************************************************************
  2. //
  3. // Copyright (c) Microsoft Corporation
  4. //
  5. // Module Name:
  6. //
  7. // parse.cpp
  8. //
  9. // Abstract:
  10. //
  11. // This module implements the command-line parsing and validating the filters
  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 "taskkill.h"
  24. //
  25. // local function prototypes
  26. //
  27. BOOL ValidatePID( LPCWSTR pwszOption, LPCWSTR pwszValue, LPVOID pData );
  28. BOOL TimeFieldsToElapsedTime( LPCWSTR pwszTime, LPCWSTR pwszToken, ULONG& ulElapsedTime );
  29. DWORD FilterMemUsage( LPCWSTR pwszProperty, LPCWSTR pwszOperator,
  30. LPCWSTR pwszValue, LPVOID pData, TARRAY arrRow );
  31. DWORD FilterCPUTime( LPCWSTR pwszProperty, LPCWSTR pwszOperator,
  32. LPCWSTR pwszValue, LPVOID pData, TARRAY arrRow );
  33. DWORD FilterUserName( LPCWSTR pwszProperty, LPCWSTR pwszOperator,
  34. LPCWSTR pwszValue, LPVOID pData, TARRAY arrRow );
  35. DWORD FilterProcessId( LPCWSTR pwszProperty, LPCWSTR pwszOperator,
  36. LPCWSTR pwszValue, LPVOID pData, TARRAY arrRow );
  37. // ***************************************************************************
  38. // Routine Description:
  39. // processes and validates the command line inputs
  40. //
  41. // Arguments:
  42. // [ in ] argc : no. of input arguments specified
  43. // [ in ] argv : input arguments specified at command prompt
  44. //
  45. // Return Value:
  46. // TRUE : if inputs are valid
  47. // FALSE : if inputs were errorneously specified
  48. //
  49. // ***************************************************************************
  50. BOOL CTaskKill::ProcessOptions( DWORD argc, LPCWSTR argv[] )
  51. {
  52. // local variables
  53. BOOL bResult = FALSE;
  54. PTCMDPARSER pcmdOptions = NULL;
  55. // temporary local variables
  56. LPWSTR pwszServer = NULL;
  57. LPWSTR pwszUserName = NULL;
  58. LPWSTR pwszPassword = NULL;
  59. PTCMDPARSER pOption = NULL;
  60. PTCMDPARSER pOptionServer = NULL;
  61. PTCMDPARSER pOptionUserName = NULL;
  62. PTCMDPARSER pOptionPassword = NULL;
  63. //
  64. // prepare the command options
  65. pcmdOptions = new TCMDPARSER[ MAX_OPTIONS ];
  66. if ( pcmdOptions == NULL )
  67. {
  68. SetLastError( E_OUTOFMEMORY );
  69. SaveLastError();
  70. return FALSE;
  71. }
  72. // ...
  73. ZeroMemory( pcmdOptions, MAX_OPTIONS * sizeof( TCMDPARSER ) );
  74. try
  75. {
  76. // get the pointers to the input bufers
  77. pwszServer = m_strServer.GetBufferSetLength( MAX_STRING_LENGTH );
  78. pwszUserName = m_strUserName.GetBufferSetLength( MAX_STRING_LENGTH );
  79. pwszPassword = m_strPassword.GetBufferSetLength( MAX_STRING_LENGTH );
  80. // init the password contents with '*'
  81. lstrcpy( pwszPassword, L"*" );
  82. }
  83. catch( ... )
  84. {
  85. SetLastError( E_OUTOFMEMORY );
  86. SaveLastError();
  87. return FALSE;
  88. }
  89. // -?
  90. pOption = pcmdOptions + OI_USAGE;
  91. pOption->dwCount = 1;
  92. pOption->dwActuals = 0;
  93. pOption->dwFlags = CP_USAGE;
  94. pOption->pValue = &m_bUsage;
  95. pOption->pFunction = NULL;
  96. pOption->pFunctionData = NULL;
  97. lstrcpy( pOption->szValues, NULL_STRING );
  98. lstrcpy( pOption->szOption, OPTION_USAGE );
  99. // -s
  100. pOption = pcmdOptions + OI_SERVER;
  101. pOption->dwCount = 1;
  102. pOption->dwActuals = 0;
  103. pOption->dwFlags = CP_TYPE_TEXT | CP_VALUE_MANDATORY;
  104. pOption->pValue = pwszServer;
  105. pOption->pFunction = NULL;
  106. pOption->pFunctionData = NULL;
  107. lstrcpy( pOption->szValues, NULL_STRING );
  108. lstrcpy( pOption->szOption, OPTION_SERVER );
  109. // -u
  110. pOption = pcmdOptions + OI_USERNAME;
  111. pOption->dwCount = 1;
  112. pOption->dwActuals = 0;
  113. pOption->dwFlags = CP_TYPE_TEXT | CP_VALUE_MANDATORY;
  114. pOption->pValue = pwszUserName;
  115. pOption->pFunction = NULL;
  116. pOption->pFunctionData = NULL;
  117. lstrcpy( pOption->szValues, NULL_STRING );
  118. lstrcpy( pOption->szOption, OPTION_USERNAME );
  119. // -p
  120. pOption = pcmdOptions + OI_PASSWORD;
  121. pOption->dwCount = 1;
  122. pOption->dwActuals = 0;
  123. pOption->dwFlags = CP_TYPE_TEXT | CP_VALUE_OPTIONAL;
  124. pOption->pValue = pwszPassword;
  125. pOption->pFunction = NULL;
  126. pOption->pFunctionData = NULL;
  127. lstrcpy( pOption->szValues, NULL_STRING );
  128. lstrcpy( pOption->szOption, OPTION_PASSWORD );
  129. // -f
  130. pOption = pcmdOptions + OI_FORCE;
  131. pOption->dwCount = 1;
  132. pOption->dwActuals = 0;
  133. pOption->dwFlags = 0;
  134. pOption->pValue = &m_bForce;
  135. pOption->pFunction = NULL;
  136. pOption->pFunctionData = NULL;
  137. lstrcpy( pOption->szValues, NULL_STRING );
  138. lstrcpy( pOption->szOption, OPTION_FORCE );
  139. // -tr
  140. pOption = pcmdOptions + OI_TREE;
  141. pOption->dwCount = 1;
  142. pOption->dwActuals = 0;
  143. pOption->dwFlags = 0;
  144. pOption->pValue = &m_bTree;
  145. pOption->pFunction = NULL;
  146. pOption->pFunctionData = NULL;
  147. lstrcpy( pOption->szValues, NULL_STRING );
  148. lstrcpy( pOption->szOption, OPTION_TREE );
  149. // -fi
  150. pOption = pcmdOptions + OI_FILTER;
  151. pOption->dwCount = 0;
  152. pOption->dwActuals = 0;
  153. pOption->dwFlags = CP_TYPE_TEXT | CP_VALUE_MANDATORY | CP_MODE_ARRAY;
  154. pOption->pValue = &m_arrFilters;
  155. pOption->pFunction = NULL;
  156. pOption->pFunctionData = NULL;
  157. lstrcpy( pOption->szValues, NULL_STRING );
  158. lstrcpy( pOption->szOption, OPTION_FILTER );
  159. // -pid
  160. pOption = pcmdOptions + OI_PID;
  161. pOption->dwCount = 0;
  162. pOption->dwActuals = 0;
  163. pOption->dwFlags = CP_TYPE_TEXT | CP_MODE_ARRAY | CP_VALUE_NODUPLICATES | CP_TYPE_CUSTOM | CP_VALUE_MANDATORY;
  164. pOption->pValue = &m_arrTasksToKill;
  165. pOption->pFunction = ValidatePID;
  166. pOption->pFunctionData = m_arrTasksToKill;
  167. lstrcpy( pOption->szValues, NULL_STRING );
  168. lstrcpy( pOption->szOption, OPTION_PID );
  169. // -im
  170. pOption = pcmdOptions + OI_IMAGENAME;
  171. pOption->dwCount = 0;
  172. pOption->dwActuals = 0;
  173. pOption->dwFlags = CP_TYPE_TEXT | CP_MODE_ARRAY | CP_VALUE_NODUPLICATES | CP_VALUE_MANDATORY;
  174. pOption->pValue = &m_arrTasksToKill;
  175. pOption->pFunction = NULL;
  176. pOption->pFunctionData = NULL;
  177. lstrcpy( pOption->szValues, NULL_STRING );
  178. lstrcpy( pOption->szOption, OPTION_IMAGENAME );
  179. //
  180. // do the parsing
  181. bResult = DoParseParam( argc, argv, MAX_OPTIONS, pcmdOptions );
  182. // release the buffers
  183. m_strServer.ReleaseBuffer();
  184. m_strUserName.ReleaseBuffer();
  185. m_strPassword.ReleaseBuffer();
  186. // now check the result of parsing and decide
  187. if ( bResult == FALSE )
  188. {
  189. delete [] pcmdOptions; // clear memory
  190. pcmdOptions = NULL;
  191. return FALSE; // invalid syntax
  192. }
  193. //
  194. // now, check the mutually exclusive options
  195. pOptionServer = pcmdOptions + OI_SERVER;
  196. pOptionUserName = pcmdOptions + OI_USERNAME;
  197. pOptionPassword = pcmdOptions + OI_PASSWORD;
  198. // check the usage option
  199. if ( m_bUsage && ( argc > 2 ) )
  200. {
  201. // no other options are accepted along with -? option
  202. delete [] pcmdOptions; // clear memory
  203. pcmdOptions = NULL;
  204. SetLastError( MK_E_SYNTAX );
  205. SetReason( ERROR_INVALID_USAGE_REQUEST );
  206. return FALSE;
  207. }
  208. else if ( m_bUsage == TRUE )
  209. {
  210. // should not do the furthur validations
  211. delete [] pcmdOptions; // clear memory
  212. pcmdOptions = NULL;
  213. return TRUE;
  214. }
  215. // "-u" should not be specified without machine names
  216. if ( pOptionServer->dwActuals == 0 && pOptionUserName->dwActuals != 0 )
  217. {
  218. // invalid syntax
  219. SetReason( ERROR_USERNAME_BUT_NOMACHINE );
  220. delete [] pcmdOptions; // clear memory
  221. pcmdOptions = NULL;
  222. return FALSE; // indicate failure
  223. }
  224. // empty user is not valid
  225. if ( pOptionUserName->dwActuals != 0 && m_strUserName.GetLength() == 0 )
  226. {
  227. SetReason( ERROR_USERNAME_EMPTY );
  228. delete [] pcmdOptions; // clear memory
  229. pcmdOptions = NULL;
  230. return FALSE;
  231. }
  232. // empty server name is not valid
  233. if ( pOptionServer->dwActuals != 0 && m_strServer.GetLength() == 0 )
  234. {
  235. SetReason( ERROR_SERVER_EMPTY );
  236. delete [] pcmdOptions; // clear memory
  237. pcmdOptions = NULL;
  238. return FALSE;
  239. }
  240. // "-p" should not be specified without "-u"
  241. if ( pOptionUserName->dwActuals == 0 && pOptionPassword->dwActuals != 0 )
  242. {
  243. // invalid syntax
  244. SetReason( ERROR_PASSWORD_BUT_NOUSERNAME );
  245. delete [] pcmdOptions; // clear memory
  246. pcmdOptions = NULL;
  247. return FALSE; // indicate failure
  248. }
  249. // check whether caller should accept the password or not
  250. // if user has specified -s (or) -u and no "-p", then utility should accept password
  251. // the user will be prompter for the password only if establish connection
  252. // is failed without the credentials information
  253. if ( pOptionPassword->dwActuals != 0 && m_strPassword.Compare( L"*" ) == 0 )
  254. {
  255. // user wants the utility to prompt for the password before trying to connect
  256. m_bNeedPassword = TRUE;
  257. }
  258. else if ( (pOptionPassword->dwActuals == 0 &&
  259. (pOptionServer->dwActuals != 0 || pOptionUserName->dwActuals != 0)) )
  260. {
  261. // utility needs to try to connect first and if it fails then prompt for the password
  262. m_bNeedPassword = TRUE;
  263. m_strPassword.Empty();
  264. }
  265. // either -pid (or) -im are allowed but not both
  266. if ( (pcmdOptions + OI_PID)->dwActuals != 0 && (pcmdOptions + OI_IMAGENAME)->dwActuals != 0 )
  267. {
  268. // invalid syntax
  269. SetReason( ERROR_PID_OR_IM_ONLY );
  270. delete [] pcmdOptions; // clear memory
  271. pcmdOptions = NULL;
  272. return FALSE; // indicate failure
  273. }
  274. else if ( DynArrayGetCount( m_arrTasksToKill ) == 0 )
  275. {
  276. // tasks were not specified .. but user might have specified filters
  277. // check that and if user didn't filters error
  278. if ( DynArrayGetCount( m_arrFilters ) == 0 )
  279. {
  280. // invalid syntax
  281. SetReason( ERROR_NO_PID_AND_IM );
  282. delete [] pcmdOptions; // clear memory
  283. pcmdOptions = NULL;
  284. return FALSE; // indicate failure
  285. }
  286. // user specified filters ... add '*' to the list of task to kill
  287. DynArrayAppendString( m_arrTasksToKill, L"*", 0 );
  288. }
  289. // check if '*' is specified along with the filters or not
  290. // if not specified along with the filters, error
  291. if ( DynArrayGetCount( m_arrFilters ) == 0 )
  292. {
  293. // filters were not specified .. so '*' should not be specified
  294. LONG lIndex = 0;
  295. lIndex = DynArrayFindString( m_arrTasksToKill, L"*", TRUE, 0 );
  296. if ( lIndex != -1 )
  297. {
  298. // error ... '*' is specified even if filters were not specified
  299. SetReason( ERROR_WILDCARD_WITHOUT_FILTERS );
  300. delete [] pcmdOptions; // clear memory
  301. pcmdOptions = NULL;
  302. return FALSE;
  303. }
  304. }
  305. // command-line parsing is successfull
  306. delete [] pcmdOptions; // clear memory
  307. pcmdOptions = NULL;
  308. return TRUE;
  309. }
  310. // ***************************************************************************
  311. // Routine Description:
  312. // validates the filter information specified with -filter option
  313. //
  314. // Arguments:
  315. // NONE
  316. //
  317. // Return Value:
  318. // TRUE : if filters are appropriately specified
  319. // FALSE : if filters are errorneously specified
  320. //
  321. // ***************************************************************************
  322. BOOL CTaskKill::ValidateFilters()
  323. {
  324. // local variables
  325. LONG lIndex = -1;
  326. BOOL bResult = FALSE;
  327. PTFILTERCONFIG pConfig = NULL;
  328. //
  329. // prepare the filter structure
  330. // status
  331. pConfig = m_pfilterConfigs + FI_STATUS;
  332. pConfig->dwColumn = TASK_STATUS;
  333. pConfig->dwFlags = F_TYPE_TEXT | F_MODE_VALUES;
  334. pConfig->pFunction = NULL;
  335. pConfig->pFunctionData = NULL;
  336. lstrcpy( pConfig->szOperators, OPERATORS_STRING );
  337. lstrcpy( pConfig->szProperty, FILTER_STATUS );
  338. lstrcpy( pConfig->szValues, FVALUES_STATUS );
  339. // imagename
  340. pConfig = m_pfilterConfigs + FI_IMAGENAME;
  341. pConfig->dwColumn = TASK_IMAGENAME;
  342. pConfig->dwFlags = F_TYPE_TEXT | F_MODE_PATTERN;
  343. pConfig->pFunction = NULL;
  344. pConfig->pFunctionData = NULL;
  345. lstrcpy( pConfig->szOperators, OPERATORS_STRING );
  346. lstrcpy( pConfig->szProperty, FILTER_IMAGENAME );
  347. lstrcpy( pConfig->szValues, NULL_STRING );
  348. // pid
  349. pConfig = m_pfilterConfigs + FI_PID;
  350. pConfig->dwColumn = TASK_PID;
  351. pConfig->dwFlags = F_TYPE_CUSTOM;
  352. pConfig->pFunction = FilterProcessId;
  353. pConfig->pFunctionData = NULL;
  354. lstrcpy( pConfig->szOperators, OPERATORS_NUMERIC );
  355. lstrcpy( pConfig->szProperty, FILTER_PID );
  356. lstrcpy( pConfig->szValues, NULL_STRING );
  357. // session
  358. pConfig = m_pfilterConfigs + FI_SESSION;
  359. pConfig->dwColumn = TASK_SESSION;
  360. pConfig->dwFlags = F_TYPE_UNUMERIC;
  361. pConfig->pFunction = NULL;
  362. pConfig->pFunctionData = NULL;
  363. lstrcpy( pConfig->szOperators, OPERATORS_NUMERIC );
  364. lstrcpy( pConfig->szProperty, FILTER_SESSION );
  365. lstrcpy( pConfig->szValues, NULL_STRING );
  366. // cputime
  367. pConfig = m_pfilterConfigs + FI_CPUTIME;
  368. pConfig->dwColumn = TASK_CPUTIME;
  369. pConfig->dwFlags = F_TYPE_CUSTOM;
  370. pConfig->pFunction = FilterCPUTime;
  371. pConfig->pFunctionData = NULL;
  372. lstrcpy( pConfig->szOperators, OPERATORS_NUMERIC );
  373. lstrcpy( pConfig->szProperty, FILTER_CPUTIME );
  374. lstrcpy( pConfig->szValues, NULL_STRING );
  375. // memusage
  376. pConfig = m_pfilterConfigs + FI_MEMUSAGE;
  377. pConfig->dwColumn = TASK_MEMUSAGE;
  378. pConfig->dwFlags = F_TYPE_UNUMERIC;
  379. pConfig->pFunction = NULL;
  380. pConfig->pFunctionData = NULL;
  381. lstrcpy( pConfig->szOperators, OPERATORS_NUMERIC );
  382. lstrcpy( pConfig->szProperty, FILTER_MEMUSAGE );
  383. lstrcpy( pConfig->szValues, NULL_STRING );
  384. // username
  385. pConfig = m_pfilterConfigs + FI_USERNAME;
  386. pConfig->dwColumn = TASK_USERNAME;
  387. pConfig->dwFlags = F_TYPE_CUSTOM;
  388. pConfig->pFunction = FilterUserName;
  389. pConfig->pFunctionData = NULL;
  390. lstrcpy( pConfig->szOperators, OPERATORS_STRING );
  391. lstrcpy( pConfig->szProperty, FILTER_USERNAME );
  392. lstrcpy( pConfig->szValues, NULL_STRING );
  393. // services
  394. pConfig = m_pfilterConfigs + FI_SERVICES;
  395. pConfig->dwColumn = TASK_SERVICES;
  396. pConfig->dwFlags = F_TYPE_TEXT | F_MODE_PATTERN | F_MODE_ARRAY;
  397. pConfig->pFunction = NULL;
  398. pConfig->pFunctionData = NULL;
  399. lstrcpy( pConfig->szOperators, OPERATORS_STRING );
  400. lstrcpy( pConfig->szProperty, FILTER_SERVICES );
  401. lstrcpy( pConfig->szValues, NULL_STRING );
  402. // windowtitle
  403. pConfig = m_pfilterConfigs + FI_WINDOWTITLE;
  404. pConfig->dwColumn = TASK_WINDOWTITLE;
  405. pConfig->dwFlags = F_TYPE_TEXT | F_MODE_PATTERN;
  406. pConfig->pFunction = NULL;
  407. pConfig->pFunctionData = NULL;
  408. lstrcpy( pConfig->szOperators, OPERATORS_STRING );
  409. lstrcpy( pConfig->szProperty, FILTER_WINDOWTITLE );
  410. lstrcpy( pConfig->szValues, NULL_STRING );
  411. // modules
  412. pConfig = m_pfilterConfigs + FI_MODULES;
  413. pConfig->dwColumn = TASK_MODULES;
  414. pConfig->dwFlags = F_TYPE_TEXT | F_MODE_PATTERN | F_MODE_ARRAY;
  415. pConfig->pFunction = NULL;
  416. pConfig->pFunctionData = NULL;
  417. lstrcpy( pConfig->szOperators, OPERATORS_STRING );
  418. lstrcpy( pConfig->szProperty, FILTER_MODULES );
  419. lstrcpy( pConfig->szValues, NULL_STRING );
  420. //
  421. // validate the filter
  422. bResult = ParseAndValidateFilter( MAX_FILTERS,
  423. m_pfilterConfigs, m_arrFilters, &m_arrFiltersEx );
  424. // check the filter validation result
  425. if ( bResult == FALSE )
  426. return FALSE;
  427. // find out whether user has requested for the tasks to be filtered
  428. // on user context and/or services are not ... if yes, set the appropriate flags
  429. // this check is being done to increase the performance of the utility
  430. // NOTE: we will be using the parsed filters info for doing this
  431. // user context
  432. if ( m_bNeedUserContextInfo == FALSE )
  433. {
  434. // find out if the filter property exists in this row
  435. // NOTE:-
  436. // filter property do exists in the seperate indexes only.
  437. // refer to the logic of validating the filters in common functionality
  438. lIndex = DynArrayFindStringEx( m_arrFiltersEx,
  439. F_PARSED_INDEX_PROPERTY, FILTER_USERNAME, TRUE, 0 );
  440. if ( lIndex != -1 )
  441. m_bNeedUserContextInfo = TRUE;
  442. }
  443. // services info
  444. if ( m_bNeedServicesInfo == FALSE )
  445. {
  446. // find out if the filter property exists in this row
  447. // NOTE:-
  448. // filter property do exists in the seperate indexes only.
  449. // refer to the logic of validating the filters in common functionality
  450. lIndex = DynArrayFindStringEx( m_arrFiltersEx,
  451. F_PARSED_INDEX_PROPERTY, FILTER_SERVICES, TRUE, 0 );
  452. if ( lIndex != -1 )
  453. m_bNeedServicesInfo = TRUE;
  454. }
  455. // modules info
  456. if ( m_bNeedModulesInfo == FALSE )
  457. {
  458. // find out if the filter property exists in this row
  459. // NOTE:-
  460. // filter property do exists in the seperate indexes only.
  461. // refer to the logic of validating the filters in common functionality
  462. lIndex = DynArrayFindStringEx( m_arrFiltersEx,
  463. F_PARSED_INDEX_PROPERTY, FILTER_MODULES, TRUE, 0 );
  464. if ( lIndex != -1 )
  465. m_bNeedModulesInfo = TRUE;
  466. }
  467. //
  468. // do the filter optimization by adding the wmi properties to the query
  469. //
  470. // NOTE: as the 'handle' property of the Win32_Process class is string type
  471. // we cannot include that in the wmi query for optimization. So make use
  472. // of the ProcessId property
  473. // optimization should not be done if user requested for tree termination
  474. if ( m_bTree == TRUE )
  475. {
  476. try
  477. {
  478. // default query
  479. m_strQuery = WMI_PROCESS_QUERY;
  480. }
  481. catch( ... )
  482. {
  483. SetLastError( E_OUTOFMEMORY );
  484. SaveLastError();
  485. return FALSE;
  486. }
  487. // modify the record filtering type for "memusage" filter from built-in type to custom type
  488. ( m_pfilterConfigs + FI_MEMUSAGE )->dwFlags = F_TYPE_CUSTOM;
  489. ( m_pfilterConfigs + FI_MEMUSAGE )->pFunctionData = NULL;
  490. ( m_pfilterConfigs + FI_MEMUSAGE )->pFunction = FilterMemUsage;
  491. // modify the record filtering type for "pid" filter from custom to built-in type
  492. ( m_pfilterConfigs + FI_PID )->dwFlags = F_TYPE_UNUMERIC;
  493. ( m_pfilterConfigs + FI_PID )->pFunctionData = NULL;
  494. ( m_pfilterConfigs + FI_PID )->pFunction = NULL;
  495. // simply return ... filter validation is complete
  496. return TRUE;
  497. }
  498. // variables needed by optimization logic
  499. LONG lCount = 0;
  500. CHString strBuffer;
  501. BOOL bOptimized = FALSE;
  502. LPCWSTR pwszValue = NULL;
  503. LPCWSTR pwszClause = NULL;
  504. LPCWSTR pwszProperty = NULL;
  505. LPCWSTR pwszOperator = NULL;
  506. try
  507. {
  508. // first clause .. and init
  509. m_strQuery = WMI_PROCESS_QUERY;
  510. pwszClause = WMI_QUERY_FIRST_CLAUSE;
  511. // get the no. of filters
  512. lCount = DynArrayGetCount( m_arrFiltersEx );
  513. // traverse thru all the filters and do the optimization
  514. m_bFiltersOptimized = FALSE;
  515. for( LONG i = 0; i < lCount; i++ )
  516. {
  517. // assume this filter will not be delete / not useful for optimization
  518. bOptimized = FALSE;
  519. // get the property, operator and value
  520. pwszValue = DynArrayItemAsString2( m_arrFiltersEx, i, F_PARSED_INDEX_VALUE );
  521. pwszProperty = DynArrayItemAsString2( m_arrFiltersEx, i, F_PARSED_INDEX_PROPERTY );
  522. pwszOperator = DynArrayItemAsString2( m_arrFiltersEx, i, F_PARSED_INDEX_OPERATOR );
  523. if ( pwszProperty == NULL || pwszOperator == NULL || pwszValue == NULL )
  524. {
  525. SetLastError( STG_E_UNKNOWN );
  526. SaveLastError();
  527. return FALSE;
  528. }
  529. //
  530. // based on the property do optimization needed
  531. // get the mathematically equivalent operator
  532. pwszOperator = FindOperator( pwszOperator );
  533. // process id
  534. if ( StringCompare( FILTER_PID, pwszProperty, TRUE, 0 ) == 0 )
  535. {
  536. // convert the value into numeric
  537. DWORD dwProcessId = AsLong( pwszValue, 10 );
  538. strBuffer.Format( L" %s %s %s %d",
  539. pwszClause, WIN32_PROCESS_PROPERTY_PROCESSID, pwszOperator, dwProcessId );
  540. // need to be optimized
  541. bOptimized = TRUE;
  542. }
  543. // session id
  544. else if ( StringCompare( FILTER_SESSION, pwszProperty, TRUE, 0 ) == 0 )
  545. {
  546. // convert the value into numeric
  547. DWORD dwSession = AsLong( pwszValue, 10 );
  548. strBuffer.Format( L" %s %s %s %d",
  549. pwszClause, WIN32_PROCESS_PROPERTY_SESSION, pwszOperator, dwSession );
  550. // need to be optimized
  551. bOptimized = TRUE;
  552. }
  553. // image name
  554. else if ( StringCompare( FILTER_IMAGENAME, pwszProperty, TRUE, 0 ) == 0 )
  555. {
  556. // check if wild card is specified or not
  557. // if wild card is specified, this filter cannot be optimized
  558. if ( wcschr( pwszValue, L'*' ) == NULL )
  559. {
  560. // no conversions needed
  561. strBuffer.Format( L" %s %s %s '%s'",
  562. pwszClause, WIN32_PROCESS_PROPERTY_IMAGENAME, pwszOperator, pwszValue );
  563. // need to be optimized
  564. bOptimized = TRUE;
  565. }
  566. }
  567. // status
  568. else if ( StringCompare( FILTER_STATUS, pwszProperty, TRUE, 0 ) == 0 )
  569. {
  570. //
  571. // do the value conversions
  572. //
  573. // if OPERATOR is =
  574. // value: RUNNING means OPERATOR is > and VALUE is 0
  575. // NOT RESPONDING means OPERATOR = and VALUE is 0
  576. //
  577. // if OPERATOR is !=
  578. // value: RUNNING means OPERATOR is = and VALUE is 0
  579. // NOT RESPONDING means OPERATOR is > and VALUE is 0
  580. if ( StringCompare( pwszValue, VALUE_RUNNING, TRUE, 0 ) == 0 )
  581. {
  582. if ( StringCompare( pwszOperator, MATH_EQ, TRUE, 0 ) == 0 )
  583. pwszOperator = MATH_GT;
  584. else
  585. pwszOperator = MATH_EQ;
  586. }
  587. else
  588. {
  589. if ( StringCompare( pwszOperator, MATH_EQ, TRUE, 0 ) == 0 )
  590. pwszOperator = MATH_EQ;
  591. else
  592. pwszOperator = MATH_GT;
  593. }
  594. // finally the filter condition
  595. strBuffer.Format( L" %s %s %s 0",
  596. pwszClause, WIN32_PROCESS_PROPERTY_THREADS, pwszOperator );
  597. // need to be optimized
  598. bOptimized = TRUE;
  599. }
  600. // mem usage
  601. else if ( StringCompare( FILTER_MEMUSAGE, pwszProperty, TRUE, 0 ) == 0 )
  602. {
  603. // convert the value into numeric
  604. ULONG ulMemUsage = AsLong( pwszValue, 10 ) * 1024;
  605. strBuffer.Format( L" %s %s %s %lu",
  606. pwszClause, WIN32_PROCESS_PROPERTY_MEMUSAGE, pwszOperator, ulMemUsage );
  607. // need to be optimized
  608. bOptimized = TRUE;
  609. }
  610. // check if property is optimizable ... if yes ... remove
  611. if ( bOptimized == TRUE )
  612. {
  613. // change the clause and append the current query
  614. m_strQuery += strBuffer;
  615. pwszClause = WMI_QUERY_SECOND_CLAUSE;
  616. // remove property and update the iterator variables
  617. m_bFiltersOptimized = TRUE;
  618. DynArrayRemove( m_arrFiltersEx, i );
  619. i--;
  620. lCount--;
  621. }
  622. }
  623. // final touch up to the query
  624. if ( m_bFiltersOptimized == TRUE )
  625. m_strQuery += L" )";
  626. }
  627. catch( ... )
  628. {
  629. SetLastError( E_OUTOFMEMORY );
  630. SaveLastError();
  631. return FALSE;
  632. }
  633. // return the filter validation result
  634. return TRUE;
  635. }
  636. // ***************************************************************************
  637. // Routine Description:
  638. //
  639. // Arguments:
  640. //
  641. // Return Value:
  642. // ***************************************************************************
  643. BOOL TimeFieldsToElapsedTime( LPCWSTR pwszTime, LPCWSTR pwszToken, ULONG& ulElapsedTime )
  644. {
  645. // local variables
  646. ULONG ulValue = 0;
  647. LPCWSTR pwszField = NULL;
  648. __STRING_64 szTemp = NULL_STRING;
  649. DWORD dwNext = 0, dwLength = 0, dwCount = 0;
  650. // check the input
  651. if ( pwszTime == NULL || pwszToken == NULL )
  652. return FALSE;
  653. // start parsing the time info
  654. dwNext = 0;
  655. dwCount = 0;
  656. ulElapsedTime = 0;
  657. do
  658. {
  659. // search for the needed token
  660. pwszField = FindString( pwszTime, pwszToken, dwNext );
  661. if ( pwszField == NULL )
  662. {
  663. // check whether some more text exists in the actual string or not
  664. if ( (LONG) dwNext >= lstrlen( pwszTime ) )
  665. break; // no more info found
  666. // get the last info
  667. lstrcpyn( szTemp, pwszTime + dwNext, SIZE_OF_ARRAY( szTemp ) );
  668. dwLength = lstrlen( szTemp ); // update the length
  669. }
  670. else
  671. {
  672. // determine the length of numeric value and get the numeric value
  673. dwLength = lstrlen( pwszTime ) - lstrlen( pwszField ) - dwNext;
  674. // check the length info
  675. if ( dwLength > SIZE_OF_ARRAY( szTemp ) )
  676. return FALSE;
  677. // get the current info
  678. lstrcpyn( szTemp, pwszTime + dwNext, dwLength + 1 ); // +1 for NULL character
  679. }
  680. // update the count of fields we are getting
  681. dwCount++;
  682. // check whether this field is numeric or not
  683. if ( lstrlen( szTemp ) == 0 || IsNumeric( szTemp, 10, FALSE ) == FALSE )
  684. return FALSE;
  685. // from second token onwards, values greater than 59 are not allowed
  686. ulValue = AsLong( szTemp, 10 );
  687. if ( dwCount > 1 && ulValue > 59 )
  688. return FALSE;
  689. // update the elapsed time
  690. ulElapsedTime = ( ulElapsedTime + ulValue ) * (( dwCount < 3 ) ? 60 : 1);
  691. // position to the next information start
  692. dwNext += dwLength + lstrlen( pwszToken );
  693. } while ( pwszField != NULL && dwCount < 3 );
  694. // check the no. of time field we got .. we should have got 3 .. if not error
  695. if ( pwszField != NULL || dwCount != 3 )
  696. return FALSE;
  697. // so everything went right ... return success
  698. return TRUE;
  699. }
  700. // ***************************************************************************
  701. // Routine Description:
  702. //
  703. // Arguments:
  704. //
  705. // Return Value:
  706. // ***************************************************************************
  707. DWORD FilterCPUTime( LPCWSTR pwszProperty, LPCWSTR pwszOperator,
  708. LPCWSTR pwszValue, LPVOID pData, TARRAY arrRow )
  709. {
  710. // local variables
  711. ULONG ulCPUTime = 0;
  712. ULONG ulElapsedTime = 0;
  713. LPCWSTR pwszCPUTime = NULL;
  714. // check the inputs
  715. if ( pwszProperty == NULL || pwszOperator == NULL || pwszValue == NULL )
  716. return F_FILTER_INVALID;
  717. // if the arrRow parameter is NULL, we need to validate the filter
  718. if ( arrRow == NULL )
  719. {
  720. // validate the filter value and return the result
  721. if ( TimeFieldsToElapsedTime( pwszValue, L":", ulElapsedTime ) == FALSE )
  722. return F_FILTER_INVALID;
  723. else
  724. return F_FILTER_VALID;
  725. }
  726. // get the filter value
  727. TimeFieldsToElapsedTime( pwszValue, L":", ulElapsedTime );
  728. // get the record value
  729. pwszCPUTime = DynArrayItemAsString( arrRow, TASK_CPUTIME );
  730. if ( pwszCPUTime == NULL )
  731. return F_RESULT_REMOVE;
  732. // convert the record value into elapsed time value
  733. TimeFieldsToElapsedTime( pwszCPUTime, L":", ulCPUTime );
  734. // return the result
  735. if ( ulCPUTime == ulElapsedTime )
  736. return MASK_EQ;
  737. else if ( ulCPUTime < ulElapsedTime )
  738. return MASK_LT;
  739. else if ( ulCPUTime > ulElapsedTime )
  740. return MASK_GT;
  741. // no way flow coming here .. still
  742. return F_RESULT_REMOVE;
  743. }
  744. // ***************************************************************************
  745. // Routine Description:
  746. //
  747. // Arguments:
  748. //
  749. // Return Value:
  750. // ***************************************************************************
  751. DWORD FilterMemUsage( LPCWSTR pwszProperty, LPCWSTR pwszOperator,
  752. LPCWSTR pwszValue, LPVOID pData, TARRAY arrRow )
  753. {
  754. // local variables
  755. DWORD dwLength = 0;
  756. ULONGLONG ulValue = 0;
  757. ULONGLONG ulMemUsage = 0;
  758. LPCWSTR pwszMemUsage = NULL;
  759. // check the inputs
  760. if ( pwszProperty == NULL || pwszOperator == NULL || pwszValue == NULL )
  761. return F_FILTER_INVALID;
  762. // check the arrRow parameter
  763. // because this function will not / should not be called except for filtering
  764. if ( arrRow == NULL )
  765. return F_FILTER_INVALID;
  766. // check the inputs
  767. if ( pwszValue == NULL )
  768. return F_RESULT_REMOVE;
  769. // get the memusage value
  770. pwszMemUsage = DynArrayItemAsString( arrRow, TASK_MEMUSAGE );
  771. if ( pwszMemUsage == NULL )
  772. return F_RESULT_REMOVE;
  773. // NOTE: as there is no conversion API as of today we use manual ULONGLONG value
  774. // preparation from string value
  775. ulMemUsage = 0;
  776. dwLength = lstrlen( pwszMemUsage );
  777. for( DWORD dw = 0; dw < dwLength; dw++ )
  778. {
  779. // validate the digit
  780. if ( pwszMemUsage[ dw ] < L'0' || pwszMemUsage[ dw ] > '9' )
  781. return F_RESULT_REMOVE;
  782. // ...
  783. ulMemUsage = ulMemUsage * 10 + ( pwszMemUsage[ dw ] - 48 );
  784. }
  785. // get the user specified value
  786. ulValue = AsLong( pwszValue, 10 );
  787. //
  788. // now determine the result value
  789. if ( ulMemUsage == ulValue )
  790. return MASK_EQ;
  791. else if ( ulMemUsage < ulValue )
  792. return MASK_LT;
  793. else if ( ulMemUsage > ulValue )
  794. return MASK_GT;
  795. // never come across this situation ... still
  796. return F_RESULT_REMOVE;
  797. }
  798. // ***************************************************************************
  799. // Routine Description:
  800. //
  801. // Arguments:
  802. //
  803. // Return Value:
  804. // ***************************************************************************
  805. DWORD FilterUserName( LPCWSTR pwszProperty, LPCWSTR pwszOperator,
  806. LPCWSTR pwszValue, LPVOID pData, TARRAY arrRow )
  807. {
  808. // local variables
  809. LONG lResult = 0;
  810. LONG lWildCardPos = 0;
  811. LPCWSTR pwszTemp = NULL;
  812. LPCWSTR pwszSearch = NULL;
  813. BOOL bOnlyUserName = FALSE;
  814. LPCWSTR pwszUserName = NULL;
  815. // check the inputs
  816. if ( pwszProperty == NULL || pwszOperator == NULL || pwszValue == NULL )
  817. return F_FILTER_INVALID;
  818. // if the arrRow parameter is NULL, we need to validate the filter
  819. if ( arrRow == NULL )
  820. {
  821. // nothing is there to validate ... just check the length
  822. // and ensure that so text is present and the value should not be just '*'
  823. // NOTE: the common functionality will give the value after doing left and right trim
  824. if ( lstrlen( pwszValue ) == 0 || StringCompare( pwszValue, L"*", TRUE, 0 ) == 0 )
  825. return F_FILTER_INVALID;
  826. // the wild card character is allowed only at the end
  827. pwszTemp = _tcschr( pwszValue, L'*' );
  828. if ( pwszTemp != NULL && lstrlen( pwszTemp + 1 ) != 0 )
  829. return F_FILTER_INVALID;
  830. // filter is valid
  831. return F_FILTER_VALID;
  832. }
  833. // find the position of the wild card in the supplied user name
  834. lWildCardPos = 0;
  835. pwszTemp = _tcschr( pwszValue, L'*' );
  836. if ( pwszTemp != NULL )
  837. {
  838. // determine the wild card position
  839. lWildCardPos = lstrlen( pwszValue ) - lstrlen( pwszTemp );
  840. // special case:
  841. // if the pattern is just asterisk, which means that all the
  842. // information needs to passed thru the filter but there is no chance for
  843. // this situation as specifying only '*' is being treated as invalid filter
  844. if ( lWildCardPos == 0 )
  845. return F_FILTER_INVALID;
  846. }
  847. // search for the domain and user name seperator ...
  848. // if domain name is not specified, comparision will be done only with the user name
  849. bOnlyUserName = FALSE;
  850. pwszTemp = _tcschr( pwszValue, L'\\' );
  851. if ( pwszTemp == NULL )
  852. bOnlyUserName = TRUE;
  853. // get the user name from the info
  854. pwszUserName = DynArrayItemAsString( arrRow, TASK_USERNAME );
  855. if ( pwszUserName == NULL )
  856. return F_RESULT_REMOVE;
  857. // based the search criteria .. meaning whether to search along with the domain or
  858. // only user name, the seach string will be decided
  859. pwszSearch = pwszUserName;
  860. if ( bOnlyUserName == TRUE )
  861. {
  862. // search for the domain and user name seperation character
  863. pwszTemp = _tcschr( pwszUserName, L'\\' );
  864. // position to the next character
  865. if ( pwszTemp != NULL )
  866. pwszSearch = pwszTemp + 1;
  867. }
  868. // validate the search string
  869. if ( pwszSearch == NULL )
  870. return F_RESULT_REMOVE;
  871. // now do the comparision
  872. lResult = StringCompare( pwszSearch, pwszValue, TRUE, lWildCardPos );
  873. //
  874. // now determine the result value
  875. if ( lResult == 0 )
  876. return MASK_EQ;
  877. else if ( lResult < 0 )
  878. return MASK_LT;
  879. else if ( lResult > 0 )
  880. return MASK_GT;
  881. // never come across this situation ... still
  882. return F_RESULT_REMOVE;
  883. }
  884. // ***************************************************************************
  885. // Routine Description:
  886. //
  887. // Arguments:
  888. //
  889. // Return Value:
  890. // ***************************************************************************
  891. DWORD FilterProcessId( LPCWSTR pwszProperty, LPCWSTR pwszOperator,
  892. LPCWSTR pwszValue, LPVOID pData, TARRAY arrRow )
  893. {
  894. // local variables
  895. LONG lIndex = 0;
  896. LPWSTR pwsz = NULL;
  897. // check the inputs
  898. if ( pwszProperty == NULL || pwszOperator == NULL || pwszValue == NULL )
  899. return F_FILTER_INVALID;
  900. // check the arrRow parameter
  901. // because this function will not / should not be called except for validation
  902. if ( arrRow != NULL )
  903. return F_RESULT_REMOVE;
  904. // check the inputs ( only needed ones )
  905. if ( pwszValue == NULL )
  906. return F_FILTER_INVALID;
  907. // NOTE: do not call the IsNumeric function. do the numeric validation in this module itself
  908. // also do not check for the overflow (or) underflow.
  909. // just check whether input is numeric or not
  910. wcstoul( pwszValue, &pwsz, 10 );
  911. if ( lstrlen( pwszValue ) == 0 || (pwsz != NULL && lstrlen( pwsz ) > 0 ))
  912. return F_FILTER_INVALID;
  913. // check if overflow (or) undeflow occured
  914. if ( errno == ERANGE )
  915. {
  916. SetReason( ERROR_NO_PROCESSES );
  917. return F_FILTER_INVALID;
  918. }
  919. // return
  920. return F_FILTER_VALID;
  921. }
  922. // ***************************************************************************
  923. // Routine Description:
  924. //
  925. // Arguments:
  926. //
  927. // Return Value:
  928. // ***************************************************************************
  929. BOOL ValidatePID( LPCWSTR pwszOption, LPCWSTR pwszValue, LPVOID pData )
  930. {
  931. // local variable
  932. LONG lIndex = 0;
  933. LPWSTR pwsz = NULL;
  934. TARRAY arrTasks = NULL;
  935. // check the input values
  936. if ( pwszOption == NULL || pwszValue == NULL || pData == NULL )
  937. {
  938. SetLastError( E_OUTOFMEMORY );
  939. SaveLastError();
  940. return FALSE;
  941. }
  942. // NOTE: do not call the IsNumeric function. do the numeric validation in this module itself
  943. // also do not check for the overflow (or) underflow.
  944. // just check whether input is numeric or not
  945. wcstoul( pwszValue, &pwsz, 10 );
  946. if ( lstrlen( pwszValue ) == 0 || (pwsz != NULL && lstrlen( pwsz ) > 0 ))
  947. {
  948. SetReason( ERROR_STRING_FOR_PID );
  949. return FALSE;
  950. }
  951. // check whether current value already exists in the list or not
  952. arrTasks = (TARRAY) pData; // get the array reference
  953. lIndex = DynArrayFindString( arrTasks, pwszValue, TRUE, 0 );
  954. if ( lIndex == -1 && DynArrayAppendString( arrTasks, pwszValue, 0 ) == -1 )
  955. {
  956. SetLastError( E_OUTOFMEMORY );
  957. SaveLastError();
  958. return FALSE;
  959. }
  960. // return the result
  961. return TRUE;
  962. }
  963. // ***************************************************************************
  964. // Routine Description:
  965. // This function fetches usage information from resource file and shows it
  966. //
  967. // Arguments:
  968. // NONE
  969. //
  970. // Return Value:
  971. // NONE
  972. // ***************************************************************************
  973. VOID CTaskKill::Usage()
  974. {
  975. // local variables
  976. DWORD dw = 0;
  977. // start displaying the usage
  978. for( dw = ID_HELP_START; dw <= ID_HELP_END; dw++ )
  979. ShowMessage( stdout, GetResString( dw ) );
  980. }