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.

445 lines
12 KiB

  1. /*++
  2. Copyright (c) 1993-2002 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 = NULL;
  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 = 0;
  124. PTASK_LIST pTask;
  125. PTASK_LIST pTaskReturn = NULL;
  126. #ifndef UNICODE
  127. _TCHAR szProcessName[MAX_PATH];
  128. #endif
  129. int PrintChars;
  130. //
  131. // set the number of tasks to zero until we get some
  132. //
  133. *pNumTasks = 0;
  134. //
  135. // Look for the list of counters. Always use the neutral
  136. // English version, regardless of the local language. We
  137. // are looking for some particular keys, and we are always
  138. // going to do our looking in English. We are not going
  139. // to show the user the counter names, so there is no need
  140. // to go find the corresponding name in the local language.
  141. //
  142. lid = MAKELANGID( LANG_ENGLISH, SUBLANG_NEUTRAL );
  143. PrintChars = _sntprintf( szSubKey, _tsizeof(szSubKey),
  144. _T("%s\\%03x"), REGKEY_PERF, lid );
  145. szSubKey[_tsizeof(szSubKey) - 1] = 0;
  146. if (PrintChars < 1 || PrintChars == _tsizeof(szSubKey)) {
  147. goto exit;
  148. }
  149. rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  150. szSubKey,
  151. 0,
  152. KEY_READ,
  153. &hKeyNames
  154. );
  155. if (rc != ERROR_SUCCESS) {
  156. goto exit;
  157. }
  158. //
  159. // get the buffer size for the counter names
  160. //
  161. rc = RegQueryValueEx( hKeyNames,
  162. REGSUBKEY_COUNTERS,
  163. NULL,
  164. &dwType,
  165. NULL,
  166. &dwSize
  167. );
  168. if (rc != ERROR_SUCCESS) {
  169. goto exit;
  170. }
  171. //
  172. // allocate the counter names buffer
  173. //
  174. buf = (PTSTR) calloc( dwSize, sizeof(BYTE) );
  175. if (buf == NULL) {
  176. goto exit;
  177. }
  178. //
  179. // read the counter names from the registry
  180. //
  181. rc = RegQueryValueEx( hKeyNames,
  182. REGSUBKEY_COUNTERS,
  183. NULL,
  184. &dwType,
  185. (PBYTE) buf,
  186. &dwSize
  187. );
  188. if (rc != ERROR_SUCCESS) {
  189. goto exit;
  190. }
  191. //
  192. // now loop thru the counter names looking for the following counters:
  193. //
  194. // 1. "Process" process name
  195. // 2. "ID Process" process id
  196. //
  197. // the buffer contains multiple null terminated strings and then
  198. // finally null terminated at the end. the strings are in pairs of
  199. // counter number and counter name.
  200. //
  201. p = buf;
  202. while (*p) {
  203. if (_tcsicmp(p, PROCESS_COUNTER) == 0) {
  204. //
  205. // look backwards for the counter number
  206. //
  207. for ( p2=p-2; isdigit(*p2); p2--) {
  208. ;
  209. }
  210. lstrcpyn( szSubKey, p2+1, _tsizeof(szSubKey) );
  211. }
  212. else
  213. if (_tcsicmp(p, PROCESSID_COUNTER) == 0) {
  214. //
  215. // look backwards for the counter number
  216. //
  217. for( p2=p-2; isdigit(*p2); p2--) {
  218. ;
  219. }
  220. dwProcessIdTitle = _ttol( p2+1 );
  221. }
  222. //
  223. // next string
  224. //
  225. p += (_tcslen(p) + 1);
  226. }
  227. //
  228. // free the counter names buffer
  229. //
  230. free( buf );
  231. //
  232. // allocate the initial buffer for the performance data
  233. //
  234. dwSize = INITIAL_SIZE;
  235. buf = (PTSTR) calloc( dwSize, sizeof(BYTE) );
  236. if (buf == NULL) {
  237. goto exit;
  238. }
  239. while (TRUE) {
  240. dwSizeOffered = dwSize;
  241. rc = RegQueryValueEx( HKEY_PERFORMANCE_DATA,
  242. szSubKey,
  243. NULL,
  244. &dwType,
  245. (PBYTE) buf,
  246. &dwSizeOffered
  247. );
  248. pPerf = (PPERF_DATA_BLOCK) buf;
  249. //
  250. // check for success and valid perf data block signature
  251. //
  252. if ((rc == ERROR_SUCCESS) &&
  253. (dwSize > 0) &&
  254. (pPerf)->Signature[0] == (WCHAR)_T('P') &&
  255. (pPerf)->Signature[1] == (WCHAR)_T('E') &&
  256. (pPerf)->Signature[2] == (WCHAR)_T('R') &&
  257. (pPerf)->Signature[3] == (WCHAR)_T('F') ) {
  258. break;
  259. }
  260. //
  261. // if buffer is not big enough, reallocate and try again
  262. //
  263. if (rc == ERROR_MORE_DATA) {
  264. PTSTR NewBuf;
  265. dwSize += EXTEND_SIZE;
  266. NewBuf = (PTSTR) realloc( buf, dwSize );
  267. if (!NewBuf) {
  268. goto exit;
  269. }
  270. buf = NewBuf;
  271. memset( buf, 0, dwSize );
  272. }
  273. else {
  274. goto exit;
  275. }
  276. }
  277. //
  278. // set the perf_object_type pointer
  279. //
  280. pObj = (PPERF_OBJECT_TYPE) ((DWORD_PTR)pPerf + pPerf->HeaderLength);
  281. //
  282. // loop thru the performance counter definition records looking
  283. // for the process id counter and then save its offset
  284. //
  285. pCounterDef = (PPERF_COUNTER_DEFINITION) ((DWORD_PTR)pObj + pObj->HeaderLength);
  286. for (i=0; i<(DWORD)pObj->NumCounters; i++) {
  287. if (pCounterDef->CounterNameTitleIndex == dwProcessIdTitle) {
  288. dwProcessIdCounter = pCounterDef->CounterOffset;
  289. break;
  290. }
  291. pCounterDef++;
  292. }
  293. //
  294. // allocate a buffer for the returned task list
  295. //
  296. dwSize = pObj->NumInstances * sizeof(TASK_LIST);
  297. pTask = pTaskReturn = (PTASK_LIST) calloc( dwSize, sizeof(BYTE) );
  298. if (pTask == NULL) {
  299. goto exit;
  300. }
  301. //
  302. // loop thru the performance instance data extracting each process name
  303. // and process id
  304. //
  305. *pNumTasks = pObj->NumInstances;
  306. pInst = (PPERF_INSTANCE_DEFINITION) ((DWORD_PTR)pObj + pObj->DefinitionLength);
  307. for (i=0; i<(DWORD)pObj->NumInstances; i++) {
  308. //
  309. // pointer to the process name
  310. //
  311. p = (PTSTR) ((DWORD_PTR)pInst + pInst->NameOffset);
  312. #ifdef UNICODE
  313. if (*p) {
  314. lstrcpyn( pTask->ProcessName, p, _tsizeof(pTask->ProcessName) - 5);
  315. _tcscat( pTask->ProcessName, _T(".exe") );
  316. } else {
  317. //
  318. // if we cant convert the string then use a bogus value
  319. //
  320. _tcscpy( pTask->ProcessName, UNKNOWN_TASK );
  321. }
  322. #else
  323. //
  324. // convert it to ascii
  325. //
  326. rc = WideCharToMultiByte( CP_ACP,
  327. 0,
  328. (LPCWSTR)p,
  329. -1,
  330. szProcessName,
  331. sizeof(szProcessName) / sizeof(_TCHAR),
  332. NULL,
  333. NULL
  334. );
  335. if (!rc) {
  336. //
  337. // if we cant convert the string then use a bogus value
  338. //
  339. _tcscpy( pTask->ProcessName, UNKNOWN_TASK );
  340. }
  341. if ( (_tcslen(szProcessName)+4) * sizeof(_TCHAR) < sizeof(pTask->ProcessName)) {
  342. _tcscpy( pTask->ProcessName, szProcessName );
  343. _tcscat( pTask->ProcessName, _T(".exe") );
  344. }
  345. #endif
  346. //
  347. // get the process id
  348. //
  349. pCounter = (PPERF_COUNTER_BLOCK) ((DWORD_PTR)pInst + pInst->ByteLength);
  350. pTask->dwProcessId = *((LPDWORD) ((DWORD_PTR)pCounter + dwProcessIdCounter));
  351. //
  352. // next process
  353. //
  354. pTask++;
  355. pInst = (PPERF_INSTANCE_DEFINITION) ((DWORD_PTR)pCounter + pCounter->ByteLength);
  356. }
  357. exit:
  358. if (buf) {
  359. free( buf );
  360. }
  361. if (hKeyNames) {
  362. RegCloseKey( hKeyNames );
  363. }
  364. return pTaskReturn;
  365. }