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.

1016 lines
24 KiB

  1. /*++
  2. Copyright (c) 1994-1998 Microsoft Corporation
  3. Module Name:
  4. tlist.c
  5. Abstract:
  6. This module implements a task list application.
  7. Author:
  8. Wesley Witt (wesw) 20-May-1994
  9. Mike Sartain (mikesart) 28-Oct-1994 Added detailed task information
  10. Julian Jiggins (julianj) 19-Mar-1998 Added list processes using specific module feature
  11. Shaun Cox (shaunco) 9-Jul-1998 Display services running in processes
  12. Environment:
  13. User Mode
  14. --*/
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include <dbghelp.h>
  18. #include "psapi.h"
  19. #define BAD_PID ((DWORD)-1)
  20. DWORD numTasks;
  21. TASK_LIST tlist[MAX_TASKS];
  22. BOOL fShowServices;
  23. BOOL fShowMtsPackages;
  24. const char *Blanks = " ";
  25. VOID Usage(VOID);
  26. VOID PrintThreadInfo(PTASK_LIST pTaskList);
  27. BOOL FMatchTaskName(LPTSTR szPN, LPTSTR szWindowTitle, LPTSTR szProcessName);
  28. VOID GetFirstPidWithName(LPTSTR szTask);
  29. VOID
  30. PrintTask(
  31. DWORD i
  32. )
  33. {
  34. BOOL NameShown = FALSE;
  35. printf( "%4d %-16s", tlist[i].dwProcessId, tlist[i].ProcessName );
  36. if (fShowServices && tlist[i].ServiceNames[0]) {
  37. printf( "Svcs: %s", tlist[i].ServiceNames);
  38. NameShown = TRUE;
  39. }
  40. if (fShowMtsPackages && tlist[i].MtsPackageNames[0]) {
  41. printf( "%sMts: %s", NameShown ? " " : "",
  42. tlist[i].MtsPackageNames);
  43. NameShown = TRUE;
  44. }
  45. if (!NameShown && tlist[i].hwnd) {
  46. if (fShowServices || fShowMtsPackages) {
  47. printf( "Title: %s", tlist[i].WindowTitle );
  48. }
  49. else {
  50. printf( " %s", tlist[i].WindowTitle );
  51. }
  52. }
  53. printf( "\n" );
  54. }
  55. VOID
  56. PrintTaskTree(
  57. DWORD level,
  58. DWORD id
  59. )
  60. {
  61. DWORD i;
  62. DetectOrphans( tlist, numTasks );
  63. for (i=0; i<numTasks; i++) {
  64. if (tlist[i].flags) {
  65. continue;
  66. }
  67. // NOTE: The format of the output below should stay fixed forever. There are tools
  68. // at MS that depend on it.
  69. if (level == 0 || tlist[i].dwInheritedFromProcessId == id) {
  70. printf( "%.*s", level*2, Blanks );
  71. printf( "%s (%d)", tlist[i].ProcessName, tlist[i].dwProcessId );
  72. if (tlist[i].hwnd) {
  73. printf( " %s", tlist[i].WindowTitle );
  74. }
  75. printf( "\n" );
  76. tlist[i].flags = TRUE;
  77. if (tlist[i].dwProcessId != 0) {
  78. PrintTaskTree( level+1, tlist[i].dwProcessId );
  79. }
  80. }
  81. }
  82. }
  83. int __cdecl
  84. main(
  85. int argc,
  86. char *argv[]
  87. )
  88. /*++
  89. Routine Description:
  90. Main entrypoint for the TLIST application. This app prints
  91. a task list to stdout. The task list include the process id,
  92. task name, ant the window title.
  93. Arguments:
  94. argc - argument count
  95. argv - array of pointers to arguments
  96. Return Value:
  97. 0 - success
  98. --*/
  99. {
  100. DWORD i;
  101. TASK_LIST_ENUM te;
  102. BOOL fTree;
  103. BOOL fFindTasksUsingModule;
  104. BOOL fPidOnly = FALSE;
  105. DWORD cchPN = 0;
  106. LPSTR szPN = NULL;
  107. DWORD dwPID = BAD_PID;
  108. DWORD dwNumServices = 0;
  109. LPENUM_SERVICE_STATUS_PROCESS pServiceInfo = NULL;
  110. if (argc > 1 && (argv[1][0] == '-' || argv[1][0] == '/') && argv[1][1] == '?') {
  111. Usage();
  112. }
  113. fTree = FALSE;
  114. fFindTasksUsingModule = FALSE;
  115. if (argc > 1) {
  116. if ((argv[1][0] == '-' || argv[1][0] == '/') && (argv[1][1] == 't' || argv[1][1] == 'T')) {
  117. fTree = TRUE;
  118. } else if ((argv[1][0] == '-' || argv[1][0] == '/') && (argv[1][1] == 's' || argv[1][1] == 'S')) {
  119. fShowServices = TRUE;
  120. } else if ((argv[1][0] == '-' || argv[1][0] == '/') && (argv[1][1] == 'k' || argv[1][1] == 'K')) {
  121. fShowMtsPackages = TRUE;
  122. } else if ((argv[1][0] == '-' || argv[1][0] == '/') && (argv[1][1] == 'p' || argv[1][1] == 'P') && argc == 3) {
  123. _strlwr(argv[2]);
  124. if (!strcmp(argv[2], "system process")) {
  125. printf("0\n");
  126. return 0;
  127. }
  128. fPidOnly = TRUE;
  129. } else if ((argv[1][0] == '-' || argv[1][0] == '/') && (argv[1][1] == 'p' || argv[1][1] == 'P') && argc == 4) {
  130. _strlwr(argv[2]);
  131. if (!strcmp(argv[2], "system")) {
  132. _strlwr(argv[3]);
  133. if (!strcmp(argv[3], "process")) {
  134. printf("0\n");
  135. return 0;
  136. }
  137. }
  138. Usage();
  139. } else if ((argv[1][0] == '-' || argv[1][0] == '/') && (argv[1][1] == 'm' || argv[1][1] == 'M') && argc == 3) {
  140. fFindTasksUsingModule = TRUE;
  141. } else {
  142. szPN = argv[1];
  143. if (!(dwPID = atol(szPN)) && szPN[0] != '0' && szPN[1] != 0) {
  144. dwPID = BAD_PID;
  145. cchPN = strlen(szPN);
  146. _strupr(szPN);
  147. }
  148. }
  149. }
  150. //
  151. // lets be god
  152. //
  153. EnableDebugPriv();
  154. //#if 0 // XXX olegk - enable the block after RI with debugger tree
  155. //
  156. // Include 32bit modules in enumeration
  157. //
  158. {
  159. DWORD SymOpt = SymGetOptions();
  160. SymOpt |= SYMOPT_INCLUDE_32BIT_MODULES;
  161. SymSetOptions(SYMOPT_INCLUDE_32BIT_MODULES);
  162. }
  163. //#endif // XXX olegk
  164. //
  165. // get the task list for the system
  166. //
  167. //
  168. // Get the process information for all active Win32 services.
  169. // This allows us to print the service names next to the processes
  170. // that host them.
  171. //
  172. dwNumServices = GetServiceProcessInfo( &pServiceInfo );
  173. numTasks = GetTaskListEx(
  174. tlist,
  175. MAX_TASKS,
  176. cchPN || (dwPID != BAD_PID),
  177. dwNumServices,
  178. pServiceInfo);
  179. free( pServiceInfo );
  180. if (fShowMtsPackages) {
  181. AddMtsPackageNames(tlist, numTasks);
  182. }
  183. //
  184. // enumerate all windows and try to get the window
  185. // titles for each task
  186. //
  187. te.tlist = tlist;
  188. te.numtasks = numTasks;
  189. GetWindowTitles( &te );
  190. //
  191. // print the task list
  192. //
  193. if (fTree) {
  194. PrintTaskTree( 0, 0 );
  195. } else if (fFindTasksUsingModule) {
  196. PrintTasksUsingModule(argv[2]);
  197. } else if (fPidOnly) {
  198. GetFirstPidWithName(argv[2]);
  199. } else {
  200. for (i=0; i<numTasks; i++) {
  201. if ((dwPID == BAD_PID) && (!cchPN)) {
  202. PrintTask( i );
  203. }
  204. else
  205. if ((dwPID == tlist[i].dwProcessId) ||
  206. (cchPN && FMatchTaskName(szPN, tlist[i].WindowTitle, tlist[i].ProcessName))) {
  207. PrintTask( i );
  208. PrintThreadInfo(tlist + i);
  209. }
  210. if (tlist[i].pThreadInfo) {
  211. free(tlist[i].pThreadInfo);
  212. }
  213. }
  214. }
  215. //
  216. // end of program
  217. //
  218. return 0;
  219. }
  220. VOID
  221. GetFirstPidWithName(
  222. LPTSTR szTask
  223. )
  224. /*++
  225. Routine Description:
  226. Returns the PID of the first task with a Name matching the specified
  227. Name. IF no task is found -1 is returned
  228. Arguments:
  229. szTask - module name to search for
  230. --*/
  231. {
  232. DWORD i;
  233. CHAR szPName[PROCESS_SIZE + 1];
  234. CHAR szNameWExe[PROCESS_SIZE + 1];
  235. strcpy(szNameWExe, szTask);
  236. strcat(szNameWExe, ".exe");
  237. for (i=0; i<numTasks; i++) {
  238. strcpy(szPName, tlist[i].ProcessName);
  239. _strlwr(szPName);
  240. if ((!strcmp(szPName, szTask))||(!strcmp(szPName, szNameWExe))) {
  241. if (tlist[i].dwProcessId != 0) {
  242. printf("%d\n", tlist[i].dwProcessId);
  243. return;
  244. }
  245. }
  246. }
  247. printf("-1\n");
  248. }
  249. VOID
  250. Usage(
  251. VOID
  252. )
  253. /*++
  254. Routine Description:
  255. Prints usage text for this tool.
  256. Arguments:
  257. None.
  258. Return Value:
  259. None.
  260. --*/
  261. {
  262. fprintf( stderr,
  263. "Microsoft (R) Windows NT (TM) Version 5.1 TLIST\n"
  264. VER_LEGALCOPYRIGHT_STR
  265. "\n\n"
  266. "usage: TLIST"
  267. " <<-m <pattern>> | <-t> | <pid> | <pattern> | <-p <processname>>> | <-k> | <-s>\n"
  268. " [options]:\n"
  269. " -t\n"
  270. " Print Task Tree\n\n"
  271. " <pid>\n"
  272. " List module information for this task.\n\n"
  273. " <pattern>\n"
  274. " The pattern can be a complete task\n"
  275. " name or a regular expression pattern\n"
  276. " to use as a match. Tlist matches the\n"
  277. " supplied pattern against the task names\n"
  278. " and the window titles.\n\n"
  279. " -k\n"
  280. " Show MTS packages active in each process.\n\n"
  281. " -m <pattern>\n"
  282. " Lists all tasks that have DLL modules loaded\n"
  283. " in them that match the given pattern name\n\n"
  284. " -s\n"
  285. " Show services active in each process.\n\n"
  286. " -p <processname>\n"
  287. " Returns the PID of the process specified or -1\n"
  288. " if the specified process doesn't exist. If there\n"
  289. " are multiple instances of the process running only\n"
  290. " the instance with the first PID value is returned.\n\n"
  291. "\n");
  292. ExitProcess(0);
  293. }
  294. //
  295. // Routines used to list all processes that have a specific module in use
  296. //
  297. BOOL
  298. FindSpecificModuleCallback(
  299. LPSTR Name,
  300. DWORD_PTR Base,
  301. DWORD Size,
  302. PVOID Context
  303. )
  304. /*++
  305. Routine Description:
  306. Callback function for module enumeration to find a specific module
  307. Arguments:
  308. Name - Module name
  309. Base - Base address
  310. Size - Size of image
  311. Context - User context pointer
  312. Return Value:
  313. TRUE - Continue enumeration
  314. FALSE - Stop enumeration
  315. --*/
  316. {
  317. PFIND_MODULE_INFO pFindModuleInfo;
  318. pFindModuleInfo = (PFIND_MODULE_INFO)Context;
  319. if (MatchPattern(Name, pFindModuleInfo->szModuleToFind))
  320. {
  321. pFindModuleInfo->fFound = TRUE;
  322. strcpy(pFindModuleInfo->szMatchingModuleName, Name);
  323. return FALSE; // Found Module so stop enumerating
  324. }
  325. return TRUE;
  326. }
  327. BOOL
  328. IsTaskUsingModule(
  329. PTASK_LIST pTask,
  330. LPTSTR szModuleName,
  331. LPTSTR szMatchingModuleName
  332. )
  333. /*++
  334. Routine Description:
  335. Checks if the given task has the given module loaded
  336. Arguments:
  337. pTaskList - task to search for module
  338. szModule - module name to search for
  339. Return Value:
  340. TRUE - if the module is loaded in the task
  341. FALSE - if the module is not loaded in the task
  342. --*/
  343. {
  344. FIND_MODULE_INFO FindModuleInfo;
  345. FindModuleInfo.fFound = FALSE;
  346. FindModuleInfo.szModuleToFind = szModuleName;
  347. FindModuleInfo.szMatchingModuleName = szMatchingModuleName;
  348. EnumerateLoadedModules(
  349. (HANDLE) UlongToPtr(pTask->dwProcessId),
  350. FindSpecificModuleCallback,
  351. &FindModuleInfo
  352. );
  353. return FindModuleInfo.fFound;
  354. }
  355. void
  356. PrintTasksUsingModule(
  357. LPTSTR szModuleName
  358. )
  359. /*++
  360. Routine Description:
  361. Enumerates through all the tasks in the system looking for those that
  362. have loaded modules of the given name.
  363. Arguments:
  364. szModule - module name to search for
  365. Return Value:
  366. None
  367. --*/
  368. {
  369. BOOL fUsed = FALSE;
  370. DWORD i;
  371. CHAR szMatchingModuleName[64];
  372. _strupr(szModuleName); // Needed for wildcarding
  373. for (i=0; i<numTasks; i++) {
  374. if (IsTaskUsingModule(tlist + i, szModuleName, szMatchingModuleName)) {
  375. printf("%s - ", szMatchingModuleName);
  376. PrintTask( i );
  377. fUsed = TRUE;
  378. }
  379. }
  380. if (!fUsed) {
  381. printf( "No tasks found using %s\n", szModuleName );
  382. }
  383. }
  384. BOOL
  385. GetVersionStuff(
  386. LPTSTR szFileName,
  387. VS_FIXEDFILEINFO *pvsRet
  388. )
  389. /*++
  390. Routine Description:
  391. Get fixedfileinfo for szFileName.
  392. Arguments:
  393. szFileName - name of file
  394. pvsRet - fixedfileinfo return struct
  395. Return Value:
  396. TRUE - success
  397. FALSE - failure
  398. --*/
  399. {
  400. DWORD dwHandle;
  401. DWORD dwLength;
  402. BOOL fRet = FALSE;
  403. LPVOID lpvData = NULL;
  404. if (!(dwLength = GetFileVersionInfoSize(szFileName, &dwHandle))) {
  405. goto err;
  406. }
  407. if (lpvData = malloc(dwLength)) {
  408. if (GetFileVersionInfo(szFileName, 0, dwLength, lpvData)) {
  409. UINT uLen;
  410. VS_FIXEDFILEINFO *pvs;
  411. DWORD *pdwTranslation;
  412. DWORD dwDefLang = 0x409;
  413. if (!VerQueryValue(lpvData, "\\VarFileInfo\\Translation",
  414. &pdwTranslation, &uLen)) {
  415. // if we can't get the langid, default to usa
  416. pdwTranslation = &dwDefLang;
  417. uLen = sizeof(DWORD);
  418. }
  419. if (VerQueryValue(lpvData, "\\", (LPVOID *)&pvs, &uLen)) {
  420. *pvsRet = *pvs;
  421. fRet = TRUE;
  422. }
  423. }
  424. }
  425. err:
  426. if (lpvData)
  427. free(lpvData);
  428. return fRet;
  429. }
  430. BOOL
  431. EnumLoadedModulesCallback(
  432. LPSTR Name,
  433. DWORD_PTR Base,
  434. DWORD Size,
  435. PVOID Context
  436. )
  437. /*++
  438. Routine Description:
  439. Callback function for module enumeration
  440. Arguments:
  441. Name - Module name
  442. Base - Base address
  443. Size - Size of image
  444. Context - User context pointer
  445. Return Value:
  446. TRUE - Continue enumeration
  447. FALSE - Stop enumeration
  448. --*/
  449. {
  450. VS_FIXEDFILEINFO vs;
  451. CHAR szBuffer[100];
  452. szBuffer[0] = 0;
  453. if (GetVersionStuff( Name, &vs )) {
  454. wsprintf( szBuffer, "%u.%u.%u.%u %s",
  455. HIWORD(vs.dwFileVersionMS),
  456. LOWORD(vs.dwFileVersionMS),
  457. HIWORD(vs.dwFileVersionLS),
  458. LOWORD(vs.dwFileVersionLS),
  459. vs.dwFileFlags & VS_FF_DEBUG ? "dbg" : "shp"
  460. );
  461. }
  462. printf( " %18.18s 0x%08x %s\n", szBuffer, Base, Name );
  463. return TRUE;
  464. }
  465. BOOL
  466. PrintModuleList(
  467. ULONG ProcessId
  468. )
  469. /*++
  470. Routine Description:
  471. Prints list of modules in ProcessId
  472. Arguments:
  473. ProcessID - process id
  474. Return Value:
  475. TRUE - success
  476. FALSE - failure
  477. --*/
  478. {
  479. EnumerateLoadedModules(
  480. (HANDLE) UlongToPtr(ProcessId),
  481. EnumLoadedModulesCallback,
  482. NULL
  483. );
  484. return TRUE;
  485. }
  486. DWORD
  487. GetWin32StartAddress(
  488. HANDLE hThread
  489. )
  490. /*++
  491. Routine Description:
  492. Get starting address for thread
  493. Arguments:
  494. hThread
  495. Return Value:
  496. Starting Thread address or 0
  497. --*/
  498. {
  499. NTSTATUS Status;
  500. DWORD ThreadInformation;
  501. // make sure we have a handle
  502. if (!hThread)
  503. return 0;
  504. // get the threadinfo
  505. Status = NtQueryInformationThread(hThread, ThreadQuerySetWin32StartAddress,
  506. &ThreadInformation, sizeof(ThreadInformation), NULL);
  507. if (!NT_SUCCESS(Status))
  508. return 0;
  509. return ThreadInformation;
  510. }
  511. ULONG
  512. GetLastThreadErr(
  513. HANDLE hThread
  514. )
  515. /*++
  516. Routine Description:
  517. Get Last Error for a Thread
  518. Arguments:
  519. hThread
  520. Return Value:
  521. LastError or 0
  522. --*/
  523. {
  524. TEB Teb;
  525. NTSTATUS Status;
  526. HANDLE hProcess;
  527. ULONG LastErrorValue;
  528. THREAD_BASIC_INFORMATION ThreadInformation;
  529. // make sure we have a handle
  530. if (!hThread)
  531. return 0;
  532. // query for basic thread info
  533. Status = NtQueryInformationThread(hThread, ThreadBasicInformation,
  534. &ThreadInformation, sizeof(ThreadInformation), NULL);
  535. if (!NT_SUCCESS(Status))
  536. return 0;
  537. // get handle to process
  538. if (!(hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE,
  539. (DWORD)(DWORD_PTR)ThreadInformation.ClientId.UniqueProcess))) {
  540. return 0;
  541. }
  542. __try {
  543. // read the TEB from the process and get the last error value
  544. if (ReadProcessMemory(hProcess,
  545. ThreadInformation.TebBaseAddress, &Teb, sizeof(TEB), NULL)) {
  546. LastErrorValue = Teb.LastErrorValue;
  547. }
  548. }
  549. __except(EXCEPTION_EXECUTE_HANDLER) {
  550. }
  551. // close the hProcess
  552. CloseHandle(hProcess);
  553. return LastErrorValue;
  554. }
  555. BOOL
  556. FPrintPEBInfo(
  557. HANDLE hProcess
  558. )
  559. /*++
  560. Routine Description:
  561. Prints cmdline and cwd of hProcess
  562. Arguments:
  563. hProcess.
  564. Return Value:
  565. TRUE - success
  566. FALSE - failure
  567. --*/
  568. {
  569. PEB Peb;
  570. NTSTATUS Status;
  571. PROCESS_BASIC_INFORMATION BasicInfo;
  572. BOOL fRet = FALSE;
  573. WCHAR szT[MAX_PATH * 2];
  574. RTL_USER_PROCESS_PARAMETERS ProcessParameters;
  575. Status = NtQueryInformationProcess(hProcess, ProcessBasicInformation,
  576. &BasicInfo, sizeof(BasicInfo), NULL);
  577. if (!NT_SUCCESS(Status)) {
  578. SetLastError(RtlNtStatusToDosError(Status));
  579. return fRet;
  580. }
  581. __try {
  582. // get the PEB
  583. if (ReadProcessMemory(hProcess, BasicInfo.PebBaseAddress, &Peb,
  584. sizeof(PEB), NULL)) {
  585. // get the processparameters
  586. if (ReadProcessMemory(hProcess, Peb.ProcessParameters,
  587. &ProcessParameters, sizeof(ProcessParameters), NULL)) {
  588. // get the CWD
  589. if (ReadProcessMemory(hProcess,
  590. ProcessParameters.CurrentDirectory.DosPath.Buffer, szT,
  591. sizeof(szT), NULL)) {
  592. wprintf(L" CWD: %s\n", szT);
  593. }
  594. // get cmdline
  595. if (ReadProcessMemory(hProcess, ProcessParameters.CommandLine.Buffer,
  596. szT, sizeof(szT), NULL)) {
  597. wprintf(L" CmdLine: %s\n", szT);
  598. }
  599. fRet = TRUE;
  600. }
  601. }
  602. }
  603. __except(EXCEPTION_EXECUTE_HANDLER) {
  604. }
  605. return fRet;
  606. }
  607. // copied from the win32 API code since we need to run on NT 4 and this is a
  608. // new API to NT 5
  609. HANDLE
  610. TlistOpenThread(
  611. DWORD dwDesiredAccess,
  612. BOOL bInheritHandle,
  613. DWORD dwThreadId
  614. )
  615. /*++
  616. Routine Description:
  617. A handle to a thread object may be created using OpenThread.
  618. Opening a thread creates a handle to the specified thread.
  619. Associated with the thread handle is a set of access rights that
  620. may be performed using the thread handle. The caller specifies the
  621. desired access to the thread using the DesiredAccess parameter.
  622. Arguments:
  623. mDesiredAccess - Supplies the desired access to the thread object.
  624. For NT/Win32, this access is checked against any security
  625. descriptor on the target thread. The following object type
  626. specific access flags can be specified in addition to the
  627. STANDARD_RIGHTS_REQUIRED access flags.
  628. DesiredAccess Flags:
  629. THREAD_TERMINATE - This access is required to terminate the
  630. thread using TerminateThread.
  631. THREAD_SUSPEND_RESUME - This access is required to suspend and
  632. resume the thread using SuspendThread and ResumeThread.
  633. THREAD_GET_CONTEXT - This access is required to use the
  634. GetThreadContext API on a thread object.
  635. THREAD_SET_CONTEXT - This access is required to use the
  636. SetThreadContext API on a thread object.
  637. THREAD_SET_INFORMATION - This access is required to set certain
  638. information in the thread object.
  639. THREAD_SET_THREAD_TOKEN - This access is required to set the
  640. thread token using SetTokenInformation.
  641. THREAD_QUERY_INFORMATION - This access is required to read
  642. certain information from the thread object.
  643. SYNCHRONIZE - This access is required to wait on a thread object.
  644. THREAD_ALL_ACCESS - This set of access flags specifies all of the
  645. possible access flags for a thread object.
  646. bInheritHandle - Supplies a flag that indicates whether or not the
  647. returned handle is to be inherited by a new process during
  648. process creation. A value of TRUE indicates that the new
  649. process will inherit the handle.
  650. dwThreadId - Supplies the thread id of the thread to open.
  651. Return Value:
  652. NON-NULL - Returns an open handle to the specified thread. The
  653. handle may be used by the calling process in any API that
  654. requires a handle to a thread. If the open is successful, the
  655. handle is granted access to the thread object only to the
  656. extent that it requested access through the DesiredAccess
  657. parameter.
  658. NULL - The operation failed. Extended error status is available
  659. using GetLastError.
  660. --*/
  661. {
  662. NTSTATUS Status;
  663. OBJECT_ATTRIBUTES Obja;
  664. HANDLE Handle;
  665. CLIENT_ID ClientId;
  666. ClientId.UniqueThread = (HANDLE)LongToHandle(dwThreadId);
  667. ClientId.UniqueProcess = (HANDLE)NULL;
  668. InitializeObjectAttributes(
  669. &Obja,
  670. NULL,
  671. (bInheritHandle ? OBJ_INHERIT : 0),
  672. NULL,
  673. NULL
  674. );
  675. Status = NtOpenThread(
  676. &Handle,
  677. (ACCESS_MASK)dwDesiredAccess,
  678. &Obja,
  679. &ClientId
  680. );
  681. if ( NT_SUCCESS(Status) ) {
  682. return Handle;
  683. }
  684. else {
  685. return NULL;
  686. }
  687. }
  688. VOID
  689. PrintThreadInfo(
  690. PTASK_LIST pTaskList
  691. )
  692. /*++
  693. Routine Description:
  694. Prints all kinds of info about a task
  695. Arguments:
  696. PTASK_LIST of task to print
  697. Return Value:
  698. None.
  699. --*/
  700. {
  701. UINT nThread;
  702. HANDLE hProcess;
  703. // from \\kernel\razzle2\src\ntos\inc\ke.h
  704. #define MAX_THREADSTATE (sizeof(szThreadState) / sizeof(TCHAR *))
  705. static const TCHAR *szThreadState[] = {
  706. "Initialized",
  707. "Ready ",
  708. "Running ",
  709. "Standby ",
  710. "Terminated",
  711. "Waiting ",
  712. "Transition",
  713. "??? " };
  714. // get a handle to the process
  715. hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pTaskList->dwProcessId);
  716. if (!hProcess)
  717. return;
  718. // print the CWD and CmdLine
  719. FPrintPEBInfo(hProcess);
  720. printf( " VirtualSize: %6ld KB"
  721. " PeakVirtualSize: %6ld KB\n",
  722. pTaskList->VirtualSize / 1024,
  723. pTaskList->PeakVirtualSize / 1024);
  724. printf( " WorkingSetSize:%6ld KB"
  725. " PeakWorkingSetSize:%6ld KB\n",
  726. pTaskList->WorkingSetSize / 1024,
  727. pTaskList->PeakWorkingSetSize / 1024);
  728. printf( " NumberOfThreads: %ld\n",
  729. pTaskList->NumberOfThreads);
  730. // if we got any threadinfo, spit it out
  731. if (pTaskList->pThreadInfo) {
  732. for (nThread = 0; nThread < pTaskList->NumberOfThreads; nThread++) {
  733. PTHREAD_INFO pThreadInfo = &pTaskList->pThreadInfo[nThread];
  734. HANDLE hThread = TlistOpenThread(THREAD_QUERY_INFORMATION, FALSE,
  735. (DWORD)(DWORD_PTR)pThreadInfo->UniqueThread);
  736. printf(" %4d Win32StartAddr:0x%08x LastErr:0x%08x State:%s\n",
  737. HandleToUlong(pThreadInfo->UniqueThread),
  738. GetWin32StartAddress(hThread),
  739. GetLastThreadErr(hThread),
  740. szThreadState[min(pThreadInfo->ThreadState, MAX_THREADSTATE - 1)]);
  741. if (hThread)
  742. NtClose(hThread);
  743. }
  744. }
  745. // print the modules
  746. PrintModuleList( pTaskList->dwProcessId );
  747. // close the hProcess
  748. CloseHandle(hProcess);
  749. }
  750. BOOL
  751. FMatchTaskName(
  752. LPTSTR szPN,
  753. LPTSTR szWindowTitle,
  754. LPTSTR szProcessName
  755. )
  756. {
  757. LPTSTR szT;
  758. TCHAR szTName[PROCESS_SIZE];
  759. strncpy( szTName, szProcessName, PROCESS_SIZE );
  760. if (szT = strchr( szTName, '.' ))
  761. szT[0] = '\0';
  762. if (MatchPattern( szTName, szPN ) ||
  763. MatchPattern( szProcessName, szPN ) ||
  764. MatchPattern( szWindowTitle, szPN )) {
  765. return TRUE;
  766. }
  767. return FALSE;
  768. }