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.

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