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.

433 lines
11 KiB

  1. /*++
  2. Copyright (c) 1993-2001 Microsoft Corporation
  3. Module Name:
  4. process.cpp
  5. Abstract:
  6. This code provides access to the task list.
  7. Author:
  8. Wesley Witt (wesw) 16-June-1993
  9. Environment:
  10. User Mode
  11. --*/
  12. #include "pch.cpp"
  13. #include <winperf.h>
  14. //
  15. // task list structure returned from GetTaskList()
  16. //
  17. typedef struct _TASK_LIST {
  18. DWORD dwProcessId;
  19. _TCHAR ProcessName[MAX_PATH];
  20. } TASK_LIST, *PTASK_LIST;
  21. //
  22. // defines
  23. //
  24. #define INITIAL_SIZE 51200
  25. #define EXTEND_SIZE 25600
  26. #define REGKEY_PERF _T("software\\microsoft\\windows nt\\currentversion\\perflib")
  27. #define REGSUBKEY_COUNTERS _T("Counters")
  28. #define PROCESS_COUNTER _T("process")
  29. #define PROCESSID_COUNTER _T("id process")
  30. #define UNKNOWN_TASK _T("unknown")
  31. //
  32. // prototypes
  33. //
  34. PTASK_LIST
  35. GetTaskList(
  36. LPLONG pNumTasks
  37. );
  38. void
  39. GetTaskName(
  40. ULONG pid,
  41. _TCHAR *szTaskName,
  42. LPDWORD pdwSize
  43. )
  44. /*++
  45. Routine Description:
  46. Gets the task name for a given process id.
  47. Arguments:
  48. pid - Process id to look for.
  49. szTaskName - Buffer to put the task name into.
  50. lpdwSize - Pointer to a dword. On entry it contains the
  51. size of the szTaskName buffer in characters.
  52. On exit it contains the number of characters
  53. in the buffer.
  54. Return Value:
  55. None.
  56. --*/
  57. {
  58. PTASK_LIST pTask;
  59. PTASK_LIST pTaskBegin;
  60. LONG NumTasks;
  61. pTask = pTaskBegin = GetTaskList( &NumTasks );
  62. if (pTask == NULL) {
  63. if (szTaskName) {
  64. _tcsncpy( szTaskName, _T("unknown"), *pdwSize );
  65. szTaskName[(*pdwSize) -1] = 0;
  66. }
  67. *pdwSize = min( 7, *pdwSize );
  68. } else {
  69. while (NumTasks--) {
  70. if (pTask->dwProcessId == pid) {
  71. if (szTaskName) {
  72. _tcsncpy( szTaskName, pTask->ProcessName, *pdwSize );
  73. szTaskName[(*pdwSize) -1] = 0;
  74. }
  75. *pdwSize = min( _tcslen(pTask->ProcessName), *pdwSize );
  76. break;
  77. }
  78. pTask++;
  79. }
  80. if (NumTasks < 0) {
  81. if (szTaskName) {
  82. _tcsncpy( szTaskName, LoadRcString(IDS_APP_ALREADY_EXITED), *pdwSize );
  83. szTaskName[(*pdwSize) -1] = 0;
  84. }
  85. *pdwSize = min( 8, *pdwSize );
  86. }
  87. free( pTaskBegin );
  88. }
  89. }
  90. PTASK_LIST
  91. GetTaskList(
  92. LPLONG pNumTasks
  93. )
  94. /*++
  95. Routine Description:
  96. Provides an API for getting a list of tasks running at the time of the
  97. API call. This function uses the registry performance data to get the
  98. task list and is therefor straight WIN32 calls that anyone can call.
  99. Arguments:
  100. pNumTasks - pointer to a dword that will be set to the
  101. number of tasks returned.
  102. Return Value:
  103. PTASK_LIST - pointer to an array of TASK_LIST records.
  104. --*/
  105. {
  106. DWORD rc;
  107. HKEY hKeyNames;
  108. DWORD dwType;
  109. DWORD dwSize;
  110. DWORD dwSizeOffered;
  111. PTSTR buf = NULL;
  112. _TCHAR szSubKey[1024];
  113. LANGID lid;
  114. PTSTR p;
  115. PTSTR p2;
  116. PPERF_DATA_BLOCK pPerf;
  117. PPERF_OBJECT_TYPE pObj;
  118. PPERF_INSTANCE_DEFINITION pInst;
  119. PPERF_COUNTER_BLOCK pCounter;
  120. PPERF_COUNTER_DEFINITION pCounterDef;
  121. DWORD i;
  122. DWORD dwProcessIdTitle;
  123. DWORD dwProcessIdCounter;
  124. PTASK_LIST pTask;
  125. PTASK_LIST pTaskReturn = NULL;
  126. #ifndef UNICODE
  127. _TCHAR szProcessName[MAX_PATH];
  128. #endif
  129. //
  130. // set the number of tasks to zero until we get some
  131. //
  132. *pNumTasks = 0;
  133. //
  134. // Look for the list of counters. Always use the neutral
  135. // English version, regardless of the local language. We
  136. // are looking for some particular keys, and we are always
  137. // going to do our looking in English. We are not going
  138. // to show the user the counter names, so there is no need
  139. // to go find the corresponding name in the local language.
  140. //
  141. lid = MAKELANGID( LANG_ENGLISH, SUBLANG_NEUTRAL );
  142. _stprintf( szSubKey, _T("%s\\%03x"), REGKEY_PERF, lid );
  143. rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  144. szSubKey,
  145. 0,
  146. KEY_READ,
  147. &hKeyNames
  148. );
  149. if (rc != ERROR_SUCCESS) {
  150. goto exit;
  151. }
  152. //
  153. // get the buffer size for the counter names
  154. //
  155. rc = RegQueryValueEx( hKeyNames,
  156. REGSUBKEY_COUNTERS,
  157. NULL,
  158. &dwType,
  159. NULL,
  160. &dwSize
  161. );
  162. if (rc != ERROR_SUCCESS) {
  163. goto exit;
  164. }
  165. //
  166. // allocate the counter names buffer
  167. //
  168. buf = (PTSTR) calloc( dwSize, sizeof(BYTE) );
  169. if (buf == NULL) {
  170. goto exit;
  171. }
  172. //
  173. // read the counter names from the registry
  174. //
  175. rc = RegQueryValueEx( hKeyNames,
  176. REGSUBKEY_COUNTERS,
  177. NULL,
  178. &dwType,
  179. (PBYTE) buf,
  180. &dwSize
  181. );
  182. if (rc != ERROR_SUCCESS) {
  183. goto exit;
  184. }
  185. //
  186. // now loop thru the counter names looking for the following counters:
  187. //
  188. // 1. "Process" process name
  189. // 2. "ID Process" process id
  190. //
  191. // the buffer contains multiple null terminated strings and then
  192. // finally null terminated at the end. the strings are in pairs of
  193. // counter number and counter name.
  194. //
  195. p = buf;
  196. while (*p) {
  197. if (_tcsicmp(p, PROCESS_COUNTER) == 0) {
  198. //
  199. // look backwards for the counter number
  200. //
  201. for ( p2=p-2; isdigit(*p2); p2--) {
  202. ;
  203. }
  204. _tcscpy( szSubKey, p2+1 );
  205. }
  206. else
  207. if (_tcsicmp(p, PROCESSID_COUNTER) == 0) {
  208. //
  209. // look backwards for the counter number
  210. //
  211. for( p2=p-2; isdigit(*p2); p2--) {
  212. ;
  213. }
  214. dwProcessIdTitle = _ttol( p2+1 );
  215. }
  216. //
  217. // next string
  218. //
  219. p += (_tcslen(p) + 1);
  220. }
  221. //
  222. // free the counter names buffer
  223. //
  224. free( buf );
  225. //
  226. // allocate the initial buffer for the performance data
  227. //
  228. dwSize = INITIAL_SIZE;
  229. buf = (PTSTR) calloc( dwSize, sizeof(BYTE) );
  230. if (buf == NULL) {
  231. goto exit;
  232. }
  233. while (TRUE) {
  234. dwSizeOffered = dwSize;
  235. rc = RegQueryValueEx( HKEY_PERFORMANCE_DATA,
  236. szSubKey,
  237. NULL,
  238. &dwType,
  239. (PBYTE) buf,
  240. &dwSizeOffered
  241. );
  242. pPerf = (PPERF_DATA_BLOCK) buf;
  243. //
  244. // check for success and valid perf data block signature
  245. //
  246. if ((rc == ERROR_SUCCESS) &&
  247. (dwSize > 0) &&
  248. (pPerf)->Signature[0] == (WCHAR)_T('P') &&
  249. (pPerf)->Signature[1] == (WCHAR)_T('E') &&
  250. (pPerf)->Signature[2] == (WCHAR)_T('R') &&
  251. (pPerf)->Signature[3] == (WCHAR)_T('F') ) {
  252. break;
  253. }
  254. //
  255. // if buffer is not big enough, reallocate and try again
  256. //
  257. if (rc == ERROR_MORE_DATA) {
  258. dwSize += EXTEND_SIZE;
  259. buf = (PTSTR) realloc( buf, dwSize );
  260. memset( buf, 0, dwSize );
  261. }
  262. else {
  263. goto exit;
  264. }
  265. }
  266. //
  267. // set the perf_object_type pointer
  268. //
  269. pObj = (PPERF_OBJECT_TYPE) ((DWORD_PTR)pPerf + pPerf->HeaderLength);
  270. //
  271. // loop thru the performance counter definition records looking
  272. // for the process id counter and then save its offset
  273. //
  274. pCounterDef = (PPERF_COUNTER_DEFINITION) ((DWORD_PTR)pObj + pObj->HeaderLength);
  275. for (i=0; i<(DWORD)pObj->NumCounters; i++) {
  276. if (pCounterDef->CounterNameTitleIndex == dwProcessIdTitle) {
  277. dwProcessIdCounter = pCounterDef->CounterOffset;
  278. break;
  279. }
  280. pCounterDef++;
  281. }
  282. //
  283. // allocate a buffer for the returned task list
  284. //
  285. dwSize = pObj->NumInstances * sizeof(TASK_LIST);
  286. pTask = pTaskReturn = (PTASK_LIST) calloc( dwSize, sizeof(BYTE) );
  287. if (pTask == NULL) {
  288. goto exit;
  289. }
  290. //
  291. // loop thru the performance instance data extracting each process name
  292. // and process id
  293. //
  294. *pNumTasks = pObj->NumInstances;
  295. pInst = (PPERF_INSTANCE_DEFINITION) ((DWORD_PTR)pObj + pObj->DefinitionLength);
  296. for (i=0; i<(DWORD)pObj->NumInstances; i++) {
  297. //
  298. // pointer to the process name
  299. //
  300. p = (PTSTR) ((DWORD_PTR)pInst + pInst->NameOffset);
  301. #ifdef UNICODE
  302. if (*p) {
  303. Assert( (_tcslen(p)+4) * sizeof(_TCHAR) < sizeof(pTask->ProcessName));
  304. _tcscpy( pTask->ProcessName, p );
  305. _tcscat( pTask->ProcessName, _T(".exe") );
  306. } else {
  307. //
  308. // if we cant convert the string then use a bogus value
  309. //
  310. _tcscpy( pTask->ProcessName, UNKNOWN_TASK );
  311. }
  312. #else
  313. //
  314. // convert it to ascii
  315. //
  316. rc = WideCharToMultiByte( CP_ACP,
  317. 0,
  318. (LPCWSTR)p,
  319. -1,
  320. szProcessName,
  321. sizeof(szProcessName) / sizeof(_TCHAR),
  322. NULL,
  323. NULL
  324. );
  325. if (!rc) {
  326. //
  327. // if we cant convert the string then use a bogus value
  328. //
  329. _tcscpy( pTask->ProcessName, UNKNOWN_TASK );
  330. }
  331. if ( (_tcslen(szProcessName)+4) * sizeof(_TCHAR) < sizeof(pTask->ProcessName)) {
  332. _tcscpy( pTask->ProcessName, szProcessName );
  333. _tcscat( pTask->ProcessName, _T(".exe") );
  334. }
  335. #endif
  336. //
  337. // get the process id
  338. //
  339. pCounter = (PPERF_COUNTER_BLOCK) ((DWORD_PTR)pInst + pInst->ByteLength);
  340. pTask->dwProcessId = *((LPDWORD) ((DWORD_PTR)pCounter + dwProcessIdCounter));
  341. //
  342. // next process
  343. //
  344. pTask++;
  345. pInst = (PPERF_INSTANCE_DEFINITION) ((DWORD_PTR)pCounter + pCounter->ByteLength);
  346. }
  347. exit:
  348. if (buf) {
  349. free( buf );
  350. }
  351. RegCloseKey( hKeyNames );
  352. return pTaskReturn;
  353. }