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