home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sdktools / image / drwatson / process.c < prev    next >
C/C++ Source or Header  |  1996-07-11  |  11KB  |  447 lines

  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( LPLONG pNumTasks );
  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.     LONG         NumTasks;
  83.  
  84.  
  85.     lprintf( MSG_TASK_LIST );
  86.  
  87.     pTask = pTaskBegin = GetTaskList( &NumTasks );
  88.  
  89.     if (pTask == NULL) {
  90.         printf( "ERROR: could not get the task list\n" );
  91.     }
  92.  
  93.     while (NumTasks--) {
  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.     LONG         NumTasks;
  129.  
  130.  
  131.     pTask = pTaskBegin = GetTaskList( &NumTasks );
  132.  
  133.     if (pTask == NULL) {
  134.         if (szTaskName) {
  135.             strncpy( szTaskName, "unknown", *pdwSize );
  136.         }
  137.         *pdwSize = min( 7, *pdwSize );
  138.  
  139.     } else {
  140.  
  141.         while (NumTasks--) {
  142.             if (pTask->dwProcessId == pid) {
  143.                 if (szTaskName) {
  144.                     strncpy( szTaskName, pTask->ProcessName, *pdwSize );
  145.                 }
  146.                 *pdwSize = min( strlen(pTask->ProcessName), *pdwSize );
  147.                 break;
  148.             }
  149.             pTask++;
  150.         }
  151.  
  152.         if (NumTasks < 0) {
  153.             if (szTaskName) {
  154.                 strncpy( szTaskName, "<exited>", *pdwSize );
  155.             }
  156.             *pdwSize = min( 8, *pdwSize );
  157.         }
  158.  
  159.         free( pTaskBegin );
  160.     }
  161. }
  162.  
  163. PTASK_LIST
  164. GetTaskList( LPLONG pNumTasks )
  165.  
  166. /*++
  167.  
  168. Routine Description:
  169.  
  170.     Provides an API for getting a list of tasks running at the time of the
  171.     API call.  This function uses the registry performance data to get the
  172.     task list and is therefor straight WIN32 calls that anyone can call.
  173.  
  174. Arguments:
  175.  
  176.     pNumTasks      - pointer to a dword that will be set to the
  177.                        number of tasks returned.
  178.  
  179. Return Value:
  180.  
  181.     PTASK_LIST       - pointer to an array of TASK_LIST records.
  182.  
  183. --*/
  184.  
  185. {
  186.     DWORD                        rc;
  187.     HKEY                         hKeyNames;
  188.     DWORD                        dwType;
  189.     DWORD                        dwSize;
  190.     LPBYTE                       buf = NULL;
  191.     char                         szSubKey[1024];
  192.     LANGID                       lid;
  193.     LPSTR                        p;
  194.     LPSTR                        p2;
  195.     PPERF_DATA_BLOCK             pPerf;
  196.     PPERF_OBJECT_TYPE            pObj;
  197.     PPERF_INSTANCE_DEFINITION    pInst;
  198.     PPERF_COUNTER_BLOCK          pCounter;
  199.     PPERF_COUNTER_DEFINITION     pCounterDef;
  200.     DWORD                        i;
  201.     DWORD                        dwProcessIdTitle;
  202.     DWORD                        dwProcessIdCounter;
  203.     PTASK_LIST                   pTask;
  204.     PTASK_LIST                   pTaskReturn = NULL;
  205.     char                         szProcessName[MAX_PATH];
  206.  
  207.  
  208.     //
  209.     // set the number of tasks to zero until we get some
  210.     //
  211.     *pNumTasks = 0;
  212.  
  213.     //
  214.     // Look for the list of counters.  Always use the neutral
  215.     // English version, regardless of the local language.  We
  216.     // are looking for some particular keys, and we are always
  217.     // going to do our looking in English.  We are not going
  218.     // to show the user the counter names, so there is no need
  219.     // to go find the corresponding name in the local language.
  220.     //
  221.     lid = MAKELANGID( LANG_ENGLISH, SUBLANG_NEUTRAL );
  222.     sprintf( szSubKey, "%s\\%03x", REGKEY_PERF, lid );
  223.     rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  224.                        szSubKey,
  225.                        0,
  226.                        KEY_READ,
  227.                        &hKeyNames
  228.                      );
  229.     if (rc != ERROR_SUCCESS) {
  230.         goto exit;
  231.     }
  232.  
  233.     //
  234.     // get the buffer size for the counter names
  235.     //
  236.     rc = RegQueryValueEx( hKeyNames,
  237.                           REGSUBKEY_COUNTERS,
  238.                           NULL,
  239.                           &dwType,
  240.                           NULL,
  241.                           &dwSize
  242.                         );
  243.  
  244.     if (rc != ERROR_SUCCESS) {
  245.         goto exit;
  246.     }
  247.  
  248.     //
  249.     // allocate the counter names buffer
  250.     //
  251.     buf = (LPBYTE) malloc( dwSize );
  252.     if (buf == NULL) {
  253.         goto exit;
  254.     }
  255.     memset( buf, 0, dwSize );
  256.  
  257.     //
  258.     // read the counter names from the registry
  259.     //
  260.     rc = RegQueryValueEx( hKeyNames,
  261.                           REGSUBKEY_COUNTERS,
  262.                           NULL,
  263.                           &dwType,
  264.                           buf,
  265.                           &dwSize
  266.                         );
  267.  
  268.     if (rc != ERROR_SUCCESS) {
  269.         goto exit;
  270.     }
  271.  
  272.     //
  273.     // now loop thru the counter names looking for the following counters:
  274.     //
  275.     //      1.  "Process"           process name
  276.     //      2.  "ID Process"        process id
  277.     //
  278.     // the buffer contains multiple null terminated strings and then
  279.     // finally null terminated at the end.  the strings are in pairs of
  280.     // counter number and counter name.
  281.     //
  282.  
  283.     p = buf;
  284.     while (*p) {
  285.         if (_stricmp(p, PROCESS_COUNTER) == 0) {
  286.             //
  287.             // look backwards for the counter number
  288.             //
  289.             for( p2=p-2; isdigit(*p2); p2--) ;
  290.             strcpy( szSubKey, p2+1 );
  291.         }
  292.         else
  293.         if (_stricmp(p, PROCESSID_COUNTER) == 0) {
  294.             //
  295.             // look backwards for the counter number
  296.             //
  297.             for( p2=p-2; isdigit(*p2); p2--) ;
  298.             dwProcessIdTitle = atol( p2+1 );
  299.         }
  300.         //
  301.         // next string
  302.         //
  303.         p += (strlen(p) + 1);
  304.     }
  305.  
  306.     //
  307.     // free the counter names buffer
  308.     //
  309.     free( buf );
  310.  
  311.  
  312.     //
  313.     // allocate the initial buffer for the performance data
  314.     //
  315.     dwSize = INITIAL_SIZE;
  316.     buf = malloc( dwSize );
  317.     if (buf == NULL) {
  318.         goto exit;
  319.     }
  320.     memset( buf, 0, dwSize );
  321.  
  322.  
  323.     while (TRUE) {
  324.  
  325.         rc = RegQueryValueEx( HKEY_PERFORMANCE_DATA,
  326.                               szSubKey,
  327.                               NULL,
  328.                               &dwType,
  329.                               buf,
  330.                               &dwSize
  331.                             );
  332.  
  333.         pPerf = (PPERF_DATA_BLOCK) buf;
  334.  
  335.         //
  336.         // check for success and valid perf data block signature
  337.         //
  338.         if ((rc == ERROR_SUCCESS) &&
  339.             (dwSize > 0) &&
  340.             (pPerf)->Signature[0] == (WCHAR)'P' &&
  341.             (pPerf)->Signature[1] == (WCHAR)'E' &&
  342.             (pPerf)->Signature[2] == (WCHAR)'R' &&
  343.             (pPerf)->Signature[3] == (WCHAR)'F' ) {
  344.             break;
  345.         }
  346.  
  347.         //
  348.         // if buffer is not big enough, reallocate and try again
  349.         //
  350.         if (rc == ERROR_MORE_DATA) {
  351.             dwSize += EXTEND_SIZE;
  352.             buf = realloc( buf, dwSize );
  353.             memset( buf, 0, dwSize );
  354.         }
  355.         else {
  356.             goto exit;
  357.         }
  358.     }
  359.  
  360.     //
  361.     // set the perf_object_type pointer
  362.     //
  363.     pObj = (PPERF_OBJECT_TYPE) ((DWORD)pPerf + pPerf->HeaderLength);
  364.  
  365.     //
  366.     // loop thru the performance counter definition records looking
  367.     // for the process id counter and then save its offset
  368.     //
  369.     pCounterDef = (PPERF_COUNTER_DEFINITION) ((DWORD)pObj + pObj->HeaderLength);
  370.     for (i=0; i<(DWORD)pObj->NumCounters; i++) {
  371.         if (pCounterDef->CounterNameTitleIndex == dwProcessIdTitle) {
  372.             dwProcessIdCounter = pCounterDef->CounterOffset;
  373.             break;
  374.         }
  375.         pCounterDef++;
  376.     }
  377.  
  378.     //
  379.     // allocate a buffer for the returned task list
  380.     //
  381.     dwSize = pObj->NumInstances * sizeof(TASK_LIST);
  382.     pTask = pTaskReturn = (PTASK_LIST) malloc( dwSize );
  383.     if (pTask == NULL) {
  384.         goto exit;
  385.     }
  386.     memset( pTask, 0, dwSize);
  387.  
  388.     //
  389.     // loop thru the performance instance data extracting each process name
  390.     // and process id
  391.     //
  392.     *pNumTasks = pObj->NumInstances;
  393.     pInst = (PPERF_INSTANCE_DEFINITION) ((DWORD)pObj + pObj->DefinitionLength);
  394.     for (i=0; i<(DWORD)pObj->NumInstances; i++) {
  395.         //
  396.         // pointer to the process name
  397.         //
  398.         p = (LPSTR) ((DWORD)pInst + pInst->NameOffset);
  399.  
  400.         //
  401.         // convert it to ascii
  402.         //
  403.         rc = WideCharToMultiByte( CP_ACP,
  404.                                   0,
  405.                                   (LPCWSTR)p,
  406.                                   -1,
  407.                                   szProcessName,
  408.                                   sizeof(szProcessName),
  409.                                   NULL,
  410.                                   NULL
  411.                                 );
  412.  
  413.         if (!rc) {
  414.             //
  415.             // if we cant convert the string then use a bogus value
  416.             //
  417.             strcpy( pTask->ProcessName, UNKNOWN_TASK );
  418.         }
  419.  
  420.         if (strlen(szProcessName)+4 <= sizeof(pTask->ProcessName)) {
  421.             strcpy( pTask->ProcessName, szProcessName );
  422.             strcat( pTask->ProcessName, ".exe" );
  423.         }
  424.  
  425.         //
  426.         // get the process id
  427.         //
  428.         pCounter = (PPERF_COUNTER_BLOCK) ((DWORD)pInst + pInst->ByteLength);
  429.         pTask->dwProcessId = *((LPDWORD) ((DWORD)pCounter + dwProcessIdCounter));
  430.  
  431.         //
  432.         // next process
  433.         //
  434.         pTask++;
  435.         pInst = (PPERF_INSTANCE_DEFINITION) ((DWORD)pCounter + pCounter->ByteLength);
  436.     }
  437.  
  438. exit:
  439.     if (buf) {
  440.         free( buf );
  441.     }
  442.  
  443.     RegCloseKey( hKeyNames );
  444.  
  445.     return pTaskReturn;
  446. }
  447.