home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sdktools / tlist / common.c next >
C/C++ Source or Header  |  1996-10-08  |  19KB  |  727 lines

  1.  
  2. /******************************************************************************\
  3. *       This is a part of the Microsoft Source Code Samples. 
  4. *       Copyright (C) 1994-1996 Microsoft Corporation.
  5. *       All rights reserved.
  6. *       This source code is only intended as a supplement to 
  7. *       Microsoft Development Tools and/or WinHelp documentation.
  8. *       See these sources for detailed information regarding the 
  9. *       Microsoft samples programs.
  10. \******************************************************************************/
  11.  
  12.  
  13. /*++
  14.  
  15. Module Name:
  16.  
  17.     common.c
  18.  
  19. Abstract:
  20.  
  21.     This module contains common apis used by tlist & kill.
  22.  
  23. --*/
  24.  
  25.  
  26. #include <windows.h>
  27. #include <winperf.h>   // for Windows NT
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <tlhelp32.h>  // for Windows 95
  32.  
  33. #include "common.h"
  34.  
  35.  
  36. //
  37. // manafest constants
  38. //
  39. #define INITIAL_SIZE        51200
  40. #define EXTEND_SIZE         25600
  41. #define REGKEY_PERF         "software\\microsoft\\windows nt\\currentversion\\perflib"
  42. #define REGSUBKEY_COUNTERS  "Counters"
  43. #define PROCESS_COUNTER     "process"
  44. #define PROCESSID_COUNTER   "id process"
  45. #define UNKNOWN_TASK        "unknown"
  46.  
  47.  
  48. //
  49. // Function pointer types for accessing Toolhelp32 functions dynamically.
  50. // By dynamically accessing these functions, we can do so only on Windows
  51. // 95 and still run on Windows NT, which does not have these functions.
  52. //
  53. typedef BOOL (WINAPI *PROCESSWALK)(HANDLE hSnapshot, LPPROCESSENTRY32 lppe);
  54. typedef HANDLE (WINAPI *CREATESNAPSHOT)(DWORD dwFlags, DWORD th32ProcessID);
  55.  
  56.  
  57. //
  58. // prototypes
  59. //
  60. BOOL CALLBACK
  61. EnumWindowsProc(
  62.     HWND    hwnd,
  63.     DWORD   lParam
  64.     );
  65.  
  66.  
  67.  
  68. DWORD
  69. GetTaskList95(
  70.     PTASK_LIST  pTask,
  71.     DWORD       dwNumTasks
  72.     )
  73.  
  74. /*++
  75.  
  76. Routine Description:
  77.  
  78.     Provides an API for getting a list of tasks running at the time of the
  79.     API call.  This function uses Toolhelp32to get the task list and is 
  80.     therefore straight WIN32 calls that anyone can call.
  81.  
  82. Arguments:
  83.  
  84.     dwNumTasks       - maximum number of tasks that the pTask array can hold
  85.  
  86. Return Value:
  87.  
  88.     Number of tasks placed into the pTask array.
  89.  
  90. --*/
  91.  
  92. {
  93.    CREATESNAPSHOT pCreateToolhelp32Snapshot = NULL;
  94.    PROCESSWALK    pProcess32First           = NULL;
  95.    PROCESSWALK    pProcess32Next            = NULL;
  96.  
  97.    HANDLE         hKernel        = NULL;
  98.    HANDLE         hProcessSnap   = NULL;
  99.    PROCESSENTRY32 pe32           = {0};
  100.    DWORD          dwTaskCount    = 0;
  101.  
  102.  
  103.    // Guarantee to the code later on that we'll enum at least one task.
  104.    if (dwNumTasks == 0)
  105.       return 0;
  106.  
  107.     // Obtain a module handle to KERNEL so that we can get the addresses of
  108.     // the 32-bit Toolhelp functions we need.
  109.     hKernel = GetModuleHandle("KERNEL32.DLL");
  110.  
  111.     if (hKernel)
  112.     {
  113.         pCreateToolhelp32Snapshot =
  114.           (CREATESNAPSHOT)GetProcAddress(hKernel, "CreateToolhelp32Snapshot");
  115.  
  116.         pProcess32First = (PROCESSWALK)GetProcAddress(hKernel,
  117.                                                       "Process32First");
  118.         pProcess32Next  = (PROCESSWALK)GetProcAddress(hKernel,
  119.                                                       "Process32Next");
  120.     }
  121.     
  122.     // make sure we got addresses of all needed Toolhelp functions.
  123.     if (!(pProcess32First && pProcess32Next && pCreateToolhelp32Snapshot))
  124.        return 0;
  125.        
  126.  
  127.     // Take a snapshot of all processes currently in the system.
  128.     hProcessSnap = pCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  129.     if (hProcessSnap == (HANDLE)-1)
  130.         return 0;
  131.  
  132.     // Walk the snapshot of processes and for each process, get information
  133.     // to display.
  134.     dwTaskCount = 0;
  135.     pe32.dwSize = sizeof(PROCESSENTRY32);   // must be filled out before use
  136.     if (pProcess32First(hProcessSnap, &pe32))
  137.     {
  138.         do
  139.         {
  140.             LPSTR pCurChar;
  141.  
  142.             // strip path and leave executabe filename splitpath
  143.             for (pCurChar = (pe32.szExeFile + lstrlen (pe32.szExeFile));
  144.                  *pCurChar != '\\' && pCurChar != pe32.szExeFile; 
  145.                  --pCurChar)
  146.  
  147.             lstrcpy(pTask -> ProcessName, pCurChar);
  148.             pTask -> flags = 0;
  149.             pTask -> dwProcessId = pe32.th32ProcessID;
  150.  
  151.             ++dwTaskCount;   // keep track of how many tasks we've got so far
  152.             ++pTask;         // get to next task info block.
  153.         }
  154.         while (dwTaskCount < dwNumTasks && pProcess32Next(hProcessSnap, &pe32));
  155.     }
  156.     else
  157.         dwTaskCount = 0;    // Couldn't walk the list of processes.
  158.  
  159.     // Don't forget to clean up the snapshot object...
  160.     CloseHandle (hProcessSnap);
  161.  
  162.     return dwTaskCount;
  163. }
  164.  
  165.  
  166. DWORD
  167. GetTaskListNT(
  168.     PTASK_LIST  pTask,
  169.     DWORD       dwNumTasks
  170.     )
  171.  
  172. /*++
  173.  
  174. Routine Description:
  175.  
  176.     Provides an API for getting a list of tasks running at the time of the
  177.     API call.  This function uses the registry performance data to get the
  178.     task list and is therefore straight WIN32 calls that anyone can call.
  179.  
  180. Arguments:
  181.  
  182.     dwNumTasks       - maximum number of tasks that the pTask array can hold
  183.  
  184. Return Value:
  185.  
  186.     Number of tasks placed into the pTask array.
  187.  
  188. --*/
  189.  
  190. {
  191.     DWORD                        rc;
  192.     HKEY                         hKeyNames;
  193.     DWORD                        dwType;
  194.     DWORD                        dwSize;
  195.     LPBYTE                       buf = NULL;
  196.     CHAR                         szSubKey[1024];
  197.     LANGID                       lid;
  198.     LPSTR                        p;
  199.     LPSTR                        p2;
  200.     PPERF_DATA_BLOCK             pPerf;
  201.     PPERF_OBJECT_TYPE            pObj;
  202.     PPERF_INSTANCE_DEFINITION    pInst;
  203.     PPERF_COUNTER_BLOCK          pCounter;
  204.     PPERF_COUNTER_DEFINITION     pCounterDef;
  205.     DWORD                        i;
  206.     DWORD                        dwProcessIdTitle;
  207.     DWORD                        dwProcessIdCounter;
  208.     CHAR                         szProcessName[MAX_PATH];
  209.     DWORD                        dwLimit = dwNumTasks - 1;
  210.  
  211.  
  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 (p > buf) {
  286.             for( p2=p-2; isdigit(*p2); p2--) ;
  287.             }
  288.         if (stricmp(p, PROCESS_COUNTER) == 0) {
  289.             //
  290.             // look backwards for the counter number
  291.             //
  292.             for( p2=p-2; isdigit(*p2); p2--) ;
  293.             strcpy( szSubKey, p2+1 );
  294.         }
  295.         else
  296.         if (stricmp(p, PROCESSID_COUNTER) == 0) {
  297.             //
  298.             // look backwards for the counter number
  299.             //
  300.             for( p2=p-2; isdigit(*p2); p2--) ;
  301.             dwProcessIdTitle = atol( p2+1 );
  302.         }
  303.         //
  304.         // next string
  305.         //
  306.         p += (strlen(p) + 1);
  307.     }
  308.  
  309.     //
  310.     // free the counter names buffer
  311.     //
  312.     free( buf );
  313.  
  314.  
  315.     //
  316.     // allocate the initial buffer for the performance data
  317.     //
  318.     dwSize = INITIAL_SIZE;
  319.     buf = malloc( dwSize );
  320.     if (buf == NULL) {
  321.         goto exit;
  322.     }
  323.     memset( buf, 0, dwSize );
  324.  
  325.  
  326.     while (TRUE) {
  327.  
  328.         rc = RegQueryValueEx( HKEY_PERFORMANCE_DATA,
  329.                               szSubKey,
  330.                               NULL,
  331.                               &dwType,
  332.                               buf,
  333.                               &dwSize
  334.                             );
  335.  
  336.         pPerf = (PPERF_DATA_BLOCK) buf;
  337.  
  338.         //
  339.         // check for success and valid perf data block signature
  340.         //
  341.         if ((rc == ERROR_SUCCESS) &&
  342.             (dwSize > 0) &&
  343.             (pPerf)->Signature[0] == (WCHAR)'P' &&
  344.             (pPerf)->Signature[1] == (WCHAR)'E' &&
  345.             (pPerf)->Signature[2] == (WCHAR)'R' &&
  346.             (pPerf)->Signature[3] == (WCHAR)'F' ) {
  347.             break;
  348.         }
  349.  
  350.         //
  351.         // if buffer is not big enough, reallocate and try again
  352.         //
  353.         if (rc == ERROR_MORE_DATA) {
  354.             dwSize += EXTEND_SIZE;
  355.             buf = realloc( buf, dwSize );
  356.             memset( buf, 0, dwSize );
  357.         }
  358.         else {
  359.             goto exit;
  360.         }
  361.     }
  362.  
  363.     //
  364.     // set the perf_object_type pointer
  365.     //
  366.     pObj = (PPERF_OBJECT_TYPE) ((DWORD)pPerf + pPerf->HeaderLength);
  367.  
  368.     //
  369.     // loop thru the performance counter definition records looking
  370.     // for the process id counter and then save its offset
  371.     //
  372.     pCounterDef = (PPERF_COUNTER_DEFINITION) ((DWORD)pObj + pObj->HeaderLength);
  373.     for (i=0; i<(DWORD)pObj->NumCounters; i++) {
  374.         if (pCounterDef->CounterNameTitleIndex == dwProcessIdTitle) {
  375.             dwProcessIdCounter = pCounterDef->CounterOffset;
  376.             break;
  377.         }
  378.         pCounterDef++;
  379.     }
  380.  
  381.     dwNumTasks = min( dwLimit, (DWORD)pObj->NumInstances );
  382.  
  383.     pInst = (PPERF_INSTANCE_DEFINITION) ((DWORD)pObj + pObj->DefinitionLength);
  384.  
  385.     //
  386.     // loop thru the performance instance data extracting each process name
  387.     // and process id
  388.     //
  389.     for (i=0; i<dwNumTasks; i++) {
  390.         //
  391.         // pointer to the process name
  392.         //
  393.         p = (LPSTR) ((DWORD)pInst + pInst->NameOffset);
  394.  
  395.         //
  396.         // convert it to ascii
  397.         //
  398.         rc = WideCharToMultiByte( CP_ACP,
  399.                                   0,
  400.                                   (LPCWSTR)p,
  401.                                   -1,
  402.                                   szProcessName,
  403.                                   sizeof(szProcessName),
  404.                                   NULL,
  405.                                   NULL
  406.                                 );
  407.  
  408.         if (!rc) {
  409.             //
  410.         // if we cant convert the string then use a default value
  411.             //
  412.             strcpy( pTask->ProcessName, UNKNOWN_TASK );
  413.         }
  414.  
  415.         if (strlen(szProcessName)+4 <= sizeof(pTask->ProcessName)) {
  416.             strcpy( pTask->ProcessName, szProcessName );
  417.             strcat( pTask->ProcessName, ".exe" );
  418.         }
  419.  
  420.         //
  421.         // get the process id
  422.         //
  423.         pCounter = (PPERF_COUNTER_BLOCK) ((DWORD)pInst + pInst->ByteLength);
  424.         pTask->flags = 0;
  425.         pTask->dwProcessId = *((LPDWORD) ((DWORD)pCounter + dwProcessIdCounter));
  426.         if (pTask->dwProcessId == 0) {
  427.             pTask->dwProcessId = (DWORD)-2;
  428.         }
  429.  
  430.         //
  431.         // next process
  432.         //
  433.         pTask++;
  434.         pInst = (PPERF_INSTANCE_DEFINITION) ((DWORD)pCounter + pCounter->ByteLength);
  435.     }
  436.  
  437. exit:
  438.     if (buf) {
  439.         free( buf );
  440.     }
  441.  
  442.     RegCloseKey( hKeyNames );
  443.     RegCloseKey( HKEY_PERFORMANCE_DATA );
  444.  
  445.     return dwNumTasks;
  446. }
  447.  
  448.  
  449.  
  450. BOOL
  451. EnableDebugPriv95(
  452.     VOID
  453.     )
  454.  
  455. /*++
  456.  
  457. Routine Description:
  458.  
  459.     Changes the process's privilege so that kill works properly.
  460.  
  461. Arguments:
  462.  
  463.  
  464. Return Value:
  465.  
  466.     TRUE             - success
  467.     FALSE            - failure
  468.  
  469. Comments: 
  470.     Always returns TRUE
  471.  
  472. --*/
  473.  
  474. {
  475.    return TRUE;
  476. }
  477.  
  478.  
  479.  
  480. BOOL
  481. EnableDebugPrivNT(
  482.     VOID
  483.     )
  484.  
  485. /*++
  486.  
  487. Routine Description:
  488.  
  489.     Changes the process's privilege so that kill works properly.
  490.  
  491. Arguments:
  492.  
  493.  
  494. Return Value:
  495.  
  496.     TRUE             - success
  497.     FALSE            - failure
  498.  
  499. --*/
  500.  
  501. {
  502.     HANDLE hToken;
  503.     LUID DebugValue;
  504.     TOKEN_PRIVILEGES tkp;
  505.  
  506.  
  507.     //
  508.     // Retrieve a handle of the access token
  509.     //
  510.     if (!OpenProcessToken(GetCurrentProcess(),
  511.             TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  512.             &hToken)) {
  513.         printf("OpenProcessToken failed with %d\n", GetLastError());
  514.         return FALSE;
  515.     }
  516.  
  517.     //
  518.     // Enable the SE_DEBUG_NAME privilege
  519.     //
  520.     if (!LookupPrivilegeValue((LPSTR) NULL,
  521.             SE_DEBUG_NAME,
  522.             &DebugValue)) {
  523.         printf("LookupPrivilegeValue failed with %d\n", GetLastError());
  524.         return FALSE;
  525.     }
  526.  
  527.     tkp.PrivilegeCount = 1;
  528.     tkp.Privileges[0].Luid = DebugValue;
  529.     tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  530.  
  531.     AdjustTokenPrivileges(hToken,
  532.         FALSE,
  533.         &tkp,
  534.         sizeof(TOKEN_PRIVILEGES),
  535.         (PTOKEN_PRIVILEGES) NULL,
  536.         (PDWORD) NULL);
  537.  
  538.     //
  539.     // The return value of AdjustTokenPrivileges can't be tested
  540.     //
  541.     if (GetLastError() != ERROR_SUCCESS) {
  542.         printf("AdjustTokenPrivileges failed with %d\n", GetLastError());
  543.         return FALSE;
  544.     }
  545.  
  546.     return TRUE;
  547. }
  548.  
  549. BOOL
  550. KillProcess(
  551.     PTASK_LIST tlist,
  552.     BOOL       fForce
  553.     )
  554. {
  555.     HANDLE            hProcess;
  556.  
  557.  
  558.     if (fForce || !tlist->hwnd) {
  559.         hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, tlist->dwProcessId );
  560.         if (hProcess) {
  561.             hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, tlist->dwProcessId );
  562.             if (hProcess == NULL) {
  563.                 return FALSE;
  564.             }
  565.  
  566.             if (!TerminateProcess( hProcess, 1 )) {
  567.                 CloseHandle( hProcess );
  568.                 return FALSE;
  569.             }
  570.  
  571.             CloseHandle( hProcess );
  572.             return TRUE;
  573.         }
  574.     }
  575.  
  576.     //
  577.     // kill the process
  578.     //
  579.     PostMessage( tlist->hwnd, WM_CLOSE, 0, 0 );
  580.  
  581.     return TRUE;
  582. }
  583.  
  584.  
  585. VOID
  586. GetWindowTitles(
  587.     PTASK_LIST_ENUM te
  588.     )
  589. {
  590.     //
  591.     // enumerate all windows
  592.     //
  593.     EnumWindows( EnumWindowsProc, (LPARAM) te );
  594. }
  595.  
  596.  
  597.  
  598. BOOL CALLBACK
  599. EnumWindowsProc(
  600.     HWND    hwnd,
  601.     DWORD   lParam
  602.     )
  603.  
  604. /*++
  605.  
  606. Routine Description:
  607.  
  608.     Callback function for window enumeration.
  609.  
  610. Arguments:
  611.  
  612.     hwnd             - window handle
  613.     lParam           - ** not used **
  614.  
  615. Return Value:
  616.  
  617.     TRUE  - continues the enumeration
  618.  
  619. --*/
  620.  
  621. {
  622.     DWORD             pid = 0;
  623.     DWORD             i;
  624.     CHAR              buf[TITLE_SIZE];
  625.     PTASK_LIST_ENUM   te = (PTASK_LIST_ENUM)lParam;
  626.     PTASK_LIST        tlist = te->tlist;
  627.     DWORD             numTasks = te->numtasks;
  628.  
  629.  
  630.     //
  631.     // get the processid for this window
  632.     //
  633.     if (!GetWindowThreadProcessId( hwnd, &pid )) {
  634.         return TRUE;
  635.     }
  636.  
  637.     //
  638.     // look for the task in the task list for this window
  639.     //
  640.     for (i=0; i<numTasks; i++) {
  641.         if (tlist[i].dwProcessId == pid) {
  642.             tlist[i].hwnd = hwnd;
  643.             //
  644.         // we found the task so lets try to get the
  645.             // window text
  646.             //
  647.             if (GetWindowText( tlist[i].hwnd, buf, sizeof(buf) )) {
  648.                 //
  649.         // got it, so lets save it
  650.                 //
  651.                 strcpy( tlist[i].WindowTitle, buf );
  652.             }
  653.             break;
  654.         }
  655.     }
  656.  
  657.     //
  658.     // continue the enumeration
  659.     //
  660.     return TRUE;
  661. }
  662.  
  663.  
  664. BOOL
  665. MatchPattern(
  666.     PUCHAR String,
  667.     PUCHAR Pattern
  668.     )
  669. {
  670.     UCHAR   c, p, l;
  671.  
  672.     for (; ;) {
  673.         switch (p = *Pattern++) {
  674.             case 0:                             // end of pattern
  675.                 return *String ? FALSE : TRUE;  // if end of string TRUE
  676.  
  677.             case '*':
  678.                 while (*String) {               // match zero or more char
  679.                     if (MatchPattern (String++, Pattern))
  680.                         return TRUE;
  681.                 }
  682.                 return MatchPattern (String, Pattern);
  683.  
  684.             case '?':
  685.                 if (*String++ == 0)             // match any one char
  686.                     return FALSE;                   // not end of string
  687.                 break;
  688.  
  689.             case '[':
  690.                 if ( (c = *String++) == 0)      // match char set
  691.                     return FALSE;                   // syntax
  692.  
  693.                 c = toupper(c);
  694.                 l = 0;
  695.                 while (p = *Pattern++) {
  696.                     if (p == ']')               // if end of char set, then
  697.                         return FALSE;           // no match found
  698.  
  699.                     if (p == '-') {             // check a range of chars?
  700.                         p = *Pattern;           // get high limit of range
  701.                         if (p == 0  ||  p == ']')
  702.                             return FALSE;           // syntax
  703.  
  704.                         if (c >= l  &&  c <= p)
  705.                             break;              // if in range, move on
  706.                     }
  707.  
  708.                     l = p;
  709.                     if (c == p)                 // if char matches this element
  710.                         break;                  // move on
  711.                 }
  712.  
  713.                 while (p  &&  p != ']')         // got a match in char set
  714.                     p = *Pattern++;             // skip to end of set
  715.  
  716.                 break;
  717.  
  718.             default:
  719.                 c = *String++;
  720.                 if (toupper(c) != p)            // check for exact char
  721.                     return FALSE;                   // not a match
  722.  
  723.                 break;
  724.         }
  725.     }
  726. }
  727.