Advertisement
bejiitas_wrath

Windows XP hardcoded unkillable process names.

Jun 1st, 2024 (edited)
689
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 126.99 KB | None | 0 0
  1. //+-------------------------------------------------------------------------
  2. //
  3. //  TaskMan - NT TaskManager
  4. //  Copyright (C) Microsoft
  5. //
  6. //  File:       procpage.cpp
  7. //
  8. //  History:    Nov-16-95   DavePl  Created
  9. //
  10. //--------------------------------------------------------------------------
  11.  
  12. #include "precomp.h"
  13. #include <TokenUtil.h>      // CPrivilegeEnable
  14. #include <winsta.h>         // WinStationGetProcessSid
  15. #include <utildll.h>        // CachedGetUserFromSid
  16. //
  17. // Project-scope globals
  18. //
  19.  
  20. DWORD g_cProcesses = 0;
  21.  
  22. extern TCHAR g_szTimeSep[];
  23. extern TCHAR g_szGroupThousSep[];
  24. extern ULONG g_ulGroupSep;
  25.  
  26. //--------------------------------------------------------------------------
  27. // TERMINAL SERVICES
  28.  
  29. //-- cache this state
  30. BOOL IsUserAdmin( )
  31. {
  32.     // Note that local static initialization is not thread safe,
  33.     // but this function is only called from the process page dialog
  34.     // proc (i.e. single thread).
  35.     static BOOL sbIsUserAdmin = SHTestTokenMembership(NULL, DOMAIN_ALIAS_RID_ADMINS);
  36.    
  37.     return sbIsUserAdmin;
  38. }
  39.  
  40. // get/set current session id.
  41.  
  42. // we use this session id to filter the processes for current session.
  43.  
  44. DWORD        gdwSessionId = static_cast<DWORD>(-1);
  45.  
  46. inline DWORD GetCurrentSessionID( )
  47. {
  48.     return gdwSessionId;
  49. }
  50.  
  51. inline VOID SetCurrentSessionID( DWORD dwSessionId )
  52. {
  53.     gdwSessionId = dwSessionId;
  54. }
  55.  
  56. // END OF TERMINAL SERVICES DECLs
  57. //--------------------------------------------------------------------------
  58.  
  59. //
  60. // File-scope globals
  61. //
  62.  
  63. SYSTEM_BASIC_INFORMATION g_BasicInfo;
  64.  
  65. //
  66. // Table of which resource IDs in the column selection dialog
  67. // correspond to which columns
  68. //
  69.  
  70. const int g_aDlgColIDs[] =
  71. {
  72.     IDC_IMAGENAME,
  73.     IDC_PID,
  74.     IDC_USERNAME,
  75.     IDC_SESSIONID,
  76.     IDC_CPU,
  77.     IDC_CPUTIME,
  78.     IDC_MEMUSAGE,
  79.     IDC_MEMPEAK,
  80.     IDC_MEMUSAGEDIFF,
  81.     IDC_PAGEFAULTS,
  82.     IDC_PAGEFAULTSDIFF,
  83.     IDC_COMMITCHARGE,
  84.     IDC_PAGEDPOOL,
  85.     IDC_NONPAGEDPOOL,
  86.     IDC_BASEPRIORITY,
  87.     IDC_HANDLECOUNT,
  88.     IDC_THREADCOUNT,
  89.     IDC_USEROBJECTS,
  90.     IDC_GDIOBJECTS,
  91.     IDC_READOPERCOUNT,
  92.     IDC_WRITEOPERCOUNT,
  93.     IDC_OTHEROPERCOUNT,
  94.     IDC_READXFERCOUNT,
  95.     IDC_WRITEXFERCOUNT,
  96.     IDC_OTHERXFERCOUNT
  97. };
  98.  
  99. //
  100. // Column ID on which to sort in the listview, and for
  101. // compares in general
  102. //
  103.  
  104. COLUMNID g_iProcSortColumnID = COL_PID;
  105. INT      g_iProcSortDirection = 1;          // 1 = asc, -1 = desc
  106.  
  107. //
  108. // Column Default Info
  109. //
  110.  
  111. struct
  112. {
  113.     INT Format;
  114.     INT Width;
  115. } ColumnDefaults[NUM_COLUMN] =
  116. {
  117.     { LVCFMT_LEFT,     0x6B },       // COL_IMAGENAME
  118.     { LVCFMT_RIGHT,      50 },       // COL_PID
  119.     { LVCFMT_LEFT,     0x6B },       // COL_USERNAME
  120.     { LVCFMT_RIGHT,      70 },       // COL_SESSIONID
  121.     { LVCFMT_RIGHT,      35},        // COL_CPU
  122.     { LVCFMT_RIGHT,      70 },       // COL_CPUTIME
  123.     { LVCFMT_RIGHT,      70 },       // COL_MEMUSAGE
  124.     { LVCFMT_RIGHT,     100 },       // COL_MEMPEAK
  125.     { LVCFMT_RIGHT,      70 },       // COL_MEMUSAGEDIFF
  126.     { LVCFMT_RIGHT,      70 },       // COL_PAGEFAULTS
  127.     { LVCFMT_RIGHT,      70 },       // COL_PAGEFAULTSDIFF
  128.     { LVCFMT_RIGHT,      70 },       // COL_COMMITCHARGE
  129.     { LVCFMT_RIGHT,      70 },       // COL_PAGEDPOOL
  130.     { LVCFMT_RIGHT,      70 },       // COL_NONPAGEDPOOL
  131.     { LVCFMT_RIGHT,      60 },       // COL_BASEPRIORITY
  132.     { LVCFMT_RIGHT,      60 },       // COL_HANDLECOUNT
  133.     { LVCFMT_RIGHT,      60 },       // COL_THREADCOUNT
  134.     { LVCFMT_RIGHT,      60 },       // COL_USEROBJECTS
  135.     { LVCFMT_RIGHT,      60 },       // COL_GDIOBJECTS
  136.     { LVCFMT_RIGHT,      70 },       // COL_READOPERCOUNT
  137.     { LVCFMT_RIGHT,      70 },       // COL_WRITEOPERCOUNT
  138.     { LVCFMT_RIGHT,      70 },       // COL_OTHEROPERCOUNT
  139.     { LVCFMT_RIGHT,      70 },       // COL_READXFERCOUNT
  140.     { LVCFMT_RIGHT,      70 },       // COL_WRITEXFERCOUNT
  141.     { LVCFMT_RIGHT,      70 }        // COL_OTHERXFERCOUNT
  142. };
  143.  
  144.  
  145. /*++ class CProcInfo
  146.  
  147. Class Description:
  148.  
  149.     Represents the last known information about a running process
  150.  
  151. Arguments:
  152.  
  153. Return Value:
  154.  
  155. Revision History:
  156.  
  157.       Nov-16-95 Davepl  Created
  158.  
  159. --*/
  160.  
  161. class CProcInfo
  162. {
  163. public:
  164.  
  165.     LARGE_INTEGER     m_uPassCount;
  166.     DWORD             m_UniqueProcessId;
  167.     LPTSTR            m_pszUserName;
  168.     ULONG             m_SessionId;
  169.     BYTE              m_CPU;
  170.     BYTE              m_DisplayCPU;
  171.     LARGE_INTEGER     m_CPUTime;
  172.     LARGE_INTEGER     m_DisplayCPUTime;
  173.     SIZE_T            m_MemUsage;
  174.     SSIZE_T           m_MemDiff;
  175.     ULONG             m_PageFaults;
  176.     LONG              m_PageFaultsDiff;
  177.     ULONG_PTR         m_CommitCharge;
  178.     ULONG_PTR         m_PagedPool;
  179.     ULONG_PTR         m_NonPagedPool;
  180.     KPRIORITY         m_PriClass;
  181.     ULONG             m_HandleCount;
  182.     ULONG             m_ThreadCount;
  183.     ULONG             m_GDIObjectCount;
  184.     ULONG             m_USERObjectCount;
  185.     LONGLONG          m_IoReadOperCount;
  186.     LONGLONG          m_IoWriteOperCount;
  187.     LONGLONG          m_IoOtherOperCount;
  188.     LONGLONG          m_IoReadXferCount;
  189.     LONGLONG          m_IoWriteXferCount;
  190.     LONGLONG          m_IoOtherXferCount;
  191.     LPTSTR            m_pszImageName;
  192.     CProcInfo *       m_pWowParentProcInfo;    // non-NULL for WOW tasks
  193.     WORD              m_htaskWow;              // non-zero for WOW tasks
  194.     BOOL              m_fWowProcess:1;         // TRUE for real WOW process
  195.     BOOL              m_fWowProcessTested:1;   // TRUE once fWowProcess is valid
  196.     SIZE_T            m_MemPeak;
  197.  
  198.     //
  199.     // This is a union of who (which column) is dirty.  You can look at
  200.     // or set any particular column's bit, or just inspect m_fDirty
  201.     // to see if anyone at all is dirty.  Used to optimize listview
  202.     // painting
  203.     //
  204.  
  205.     union
  206.     {
  207.         DWORD                m_fDirty;
  208.         struct
  209.         {
  210.             DWORD            m_fDirty_COL_CPU            :1;
  211.             DWORD            m_fDirty_COL_CPUTIME        :1;
  212.             DWORD            m_fDirty_COL_MEMUSAGE       :1;
  213.             DWORD            m_fDirty_COL_MEMUSAGEDIFF   :1;
  214.             DWORD            m_fDirty_COL_PAGEFAULTS     :1;
  215.             DWORD            m_fDirty_COL_PAGEFAULTSDIFF :1;
  216.             DWORD            m_fDirty_COL_COMMITCHARGE   :1;
  217.             DWORD            m_fDirty_COL_PAGEDPOOL      :1;
  218.             DWORD            m_fDirty_COL_NONPAGEDPOOL   :1;
  219.             DWORD            m_fDirty_COL_BASEPRIORITY   :1;
  220.             DWORD            m_fDirty_COL_HANDLECOUNT    :1;
  221.             DWORD            m_fDirty_COL_IMAGENAME      :1;
  222.             DWORD            m_fDirty_COL_PID            :1;
  223.             DWORD            m_fDirty_COL_SESSIONID      :1;
  224.             DWORD            m_fDirty_COL_USERNAME       :1;
  225.             DWORD            m_fDirty_COL_THREADCOUNT    :1;
  226.             DWORD            m_fDirty_COL_GDIOBJECTS     :1;
  227.             DWORD            m_fDirty_COL_USEROBJECTS    :1;
  228.             DWORD            m_fDirty_COL_MEMPEAK        :1;
  229.             DWORD            m_fDirty_COL_READOPERCOUNT  :1;
  230.             DWORD            m_fDirty_COL_WRITEOPERCOUNT :1;
  231.             DWORD            m_fDirty_COL_OTHEROPERCOUNT :1;
  232.             DWORD            m_fDirty_COL_READXFERCOUNT  :1;
  233.             DWORD            m_fDirty_COL_WRITEXFERCOUNT :1;
  234.             DWORD            m_fDirty_COL_OTHERXFERCOUNT :1;
  235.         };
  236.     };
  237.  
  238.     HRESULT SetData(LARGE_INTEGER                TotalTime,
  239.                     PSYSTEM_PROCESS_INFORMATION  pInfo,
  240.                     LARGE_INTEGER                uPassCount,
  241.                     CProcPage *                  pProcPage,
  242.                     BOOL                         fUpdateOnly);
  243.  
  244.     HRESULT SetProcessUsername(const FILETIME *CreationTime);
  245.  
  246.     HRESULT SetDataWowTask(LARGE_INTEGER  TotalTime,
  247.                            DWORD          dwThreadId,
  248.                            CHAR *         pszFilePath,
  249.                            LARGE_INTEGER  uPassCount,
  250.                            CProcInfo *    pParentProcInfo,
  251.                            LARGE_INTEGER *pTimeLeft,
  252.                            WORD           htask,
  253.                            BOOL           fUpdateOnly);
  254.  
  255.     CProcInfo()
  256.     {
  257.         ZeroMemory(this, sizeof(*this));
  258.         m_pszUserName = 0;
  259.         m_SessionId = 832;
  260.     }
  261.  
  262.     ~CProcInfo()
  263.     {
  264.         if (m_pszImageName)
  265.         {
  266.             delete [] m_pszImageName;
  267.         }
  268.  
  269.         if( m_pszUserName != NULL )
  270.         {
  271.             delete [] m_pszUserName;
  272.         }
  273.     }
  274.  
  275.     BOOL OkToShowThisProcess ()
  276.     {
  277.         // this function determines if the process should be listed in the view.
  278.  
  279.         return GetCurrentSessionID() == m_SessionId;
  280.     }
  281.  
  282.  
  283.     // Invalidate() marks this proc with a bogus pid so that it is removed
  284.     // on the next cleanup pass
  285.  
  286.     void Invalidate()
  287.     {
  288.         m_UniqueProcessId = PtrToUlong(INVALID_HANDLE_VALUE);
  289.     }
  290.  
  291.     LONGLONG GetCPUTime() const
  292.     {
  293.         return m_CPUTime.QuadPart;
  294.     }
  295.  
  296.     INT Compare(CProcInfo * pOther);
  297.  
  298.     //
  299.     // Is this a WOW task psuedo-process?
  300.     //
  301.  
  302.     INT_PTR IsWowTask(void) const
  303.     {
  304.         return (INT_PTR) m_pWowParentProcInfo;
  305.     }
  306.  
  307.     //
  308.     // Get the Win32 PID for this task
  309.     //
  310.  
  311.     DWORD GetRealPID(void) const
  312.     {
  313.         return m_pWowParentProcInfo
  314.                ? m_pWowParentProcInfo->m_UniqueProcessId
  315.                : m_UniqueProcessId;
  316.     }
  317.  
  318.     void SetCPU(LARGE_INTEGER CPUTimeDelta,
  319.                 LARGE_INTEGER TotalTime,
  320.                 BOOL          fDisplayOnly);
  321. };
  322.  
  323. /*++ ColSelectDlgProc
  324.  
  325. Function Description:
  326.  
  327.     Dialog Procedure for the column selection dialog
  328.  
  329. Arguments:
  330.  
  331.     Standard wndproc stuff
  332.  
  333. Revision History:
  334.  
  335.       Jan-05-96 Davepl  Created
  336.  
  337. --*/
  338.  
  339. INT_PTR CALLBACK ColSelectDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  340. {
  341.     static CProcPage * pPage = NULL;
  342.  
  343.     switch(uMsg)
  344.     {
  345.         case WM_INITDIALOG:
  346.         {
  347.  
  348.  
  349.             // Looks scary, but we're single threaded
  350.  
  351.             pPage = (CProcPage *) lParam;
  352.  
  353.             // Start with none of the boxes checked
  354.  
  355.             for (int i = 0; i < NUM_COLUMN; i++)
  356.             {
  357.                 CheckDlgButton(hwndDlg, g_aDlgColIDs[i], BST_UNCHECKED);
  358.             }
  359.  
  360.             // HIDE the Username and SessionId if its not Terminal Server.
  361.  
  362.             if( !g_fIsTSEnabled )
  363.             {
  364.                 ShowWindow( GetDlgItem( hwndDlg , IDC_USERNAME ) , SW_HIDE );
  365.  
  366.                 ShowWindow( GetDlgItem( hwndDlg , IDC_SESSIONID ) , SW_HIDE );
  367.  
  368.             }
  369.  
  370.             // Then turn on the ones for the columns we have active
  371.  
  372.             for (i = 0; i < NUM_COLUMN + 1; i++)
  373.             {
  374.                 if (g_Options.m_ActiveProcCol[i] == -1)
  375.                 {
  376.                     break;
  377.                 }
  378.  
  379.                 CheckDlgButton(hwndDlg, g_aDlgColIDs[g_Options.m_ActiveProcCol[i]], BST_CHECKED);
  380.             }
  381.  
  382.             return TRUE;
  383.         }
  384.  
  385.         case WM_COMMAND:
  386.         {
  387.             // If user clicked OK, add the columns to the array and reset the listview
  388.  
  389.             if (LOWORD(wParam) == IDOK)
  390.             {
  391.                 // First, make sure the column width array is up to date
  392.  
  393.                 pPage->SaveColumnWidths();
  394.  
  395.                 INT iCol = 1;
  396.  
  397.                 g_Options.m_ActiveProcCol[0] = COL_IMAGENAME;
  398.  
  399.                 for (int i = 1; i < NUM_COLUMN && g_aDlgColIDs[i] >= 0; i++)
  400.                 {
  401.                     if (BST_CHECKED == IsDlgButtonChecked(hwndDlg, g_aDlgColIDs[i]))
  402.                     {
  403.                         // It is checked
  404.  
  405.                         if (g_Options.m_ActiveProcCol[iCol] != (COLUMNID) i)
  406.                         {
  407.                             // If the column wasn't already there, insert its column
  408.                             // width into the column width array
  409.  
  410.                             ShiftArray(g_Options.m_ColumnWidths, iCol, SHIFT_UP);
  411.                             ShiftArray(g_Options.m_ActiveProcCol, iCol, SHIFT_UP);
  412.                             g_Options.m_ColumnWidths[iCol] = ColumnDefaults[ i ].Width;
  413.                             g_Options.m_ActiveProcCol[iCol] = (COLUMNID) i;
  414.                         }
  415.                         iCol++;
  416.                     }
  417.                     else
  418.                     {
  419.                         // Not checked, column not active.  If it used to be active,
  420.                         // remove its column width from the column width array
  421.  
  422.                         if (g_Options.m_ActiveProcCol[iCol] == (COLUMNID) i)
  423.                         {
  424.                             ShiftArray(g_Options.m_ColumnWidths, iCol, SHIFT_DOWN);
  425.                             ShiftArray(g_Options.m_ActiveProcCol, iCol, SHIFT_DOWN);
  426.                         }
  427.                     }
  428.                 }
  429.  
  430.                 // Terminate the column list
  431.                                
  432.                 g_Options.m_ActiveProcCol[iCol] = (COLUMNID) -1;
  433.                 pPage->SetupColumns();
  434.                 pPage->TimerEvent();
  435.                 EndDialog(hwndDlg, IDOK);
  436.  
  437.             }
  438.             else if (LOWORD(wParam) == IDCANCEL)
  439.             {
  440.                 EndDialog(hwndDlg, IDCANCEL);
  441.             }
  442.         }
  443.     }
  444.     return FALSE;
  445. }
  446.  
  447. /*++ CProcPage::~CProcPage()
  448.  
  449.         - Destructor
  450. */
  451.  
  452. CProcPage::~CProcPage()
  453. {
  454.     Destroy( );
  455. }
  456.  
  457. /*++ CProcPage::PickColumns()
  458.  
  459. Function Description:
  460.  
  461.     Puts up UI that lets the user select what columns to display in the
  462.     process page, and then resets the listview with the new column list
  463.  
  464. Arguments:
  465.  
  466.     none
  467.  
  468. Return Value:
  469.  
  470.     none
  471.  
  472. Revision History:
  473.  
  474.     Jan-05-96 Davepl  Created
  475.  
  476. --*/
  477.  
  478. void CProcPage::PickColumns()
  479. {
  480.     DialogBoxParam(g_hInstance,
  481.                    MAKEINTRESOURCE(IDD_SELECTPROCCOLS),
  482.                    g_hMainWnd,
  483.                    ColSelectDlgProc,
  484.                    (LPARAM) this);
  485. }
  486.  
  487. /*++ GetPriRanking
  488.  
  489. Function Description:
  490.  
  491.     Since the priority class defines aren't in order, this helper
  492.     exists to make comparisons between pri classes easier.  It returns
  493.     a larger number for "higher" priority classes
  494.  
  495. Arguments:
  496.  
  497. Return Value:
  498.  
  499.     rank of priority (0 to 5)
  500.  
  501. Revision History:
  502.  
  503.       Nov-27-95 Davepl  Created
  504.  
  505. --*/
  506.  
  507.  
  508. DWORD GetPriRanking(DWORD dwClass)
  509. {
  510.     switch(dwClass)
  511.     {
  512.         case REALTIME_PRIORITY_CLASS:
  513.             return 5;
  514.  
  515.         case HIGH_PRIORITY_CLASS:
  516.             return 4;
  517.  
  518.         case ABOVE_NORMAL_PRIORITY_CLASS:
  519.             return 3;
  520.  
  521.         case NORMAL_PRIORITY_CLASS:
  522.             return 2;
  523.  
  524.         case BELOW_NORMAL_PRIORITY_CLASS:
  525.             return 1;
  526.  
  527.  
  528.         default:
  529.             return 0;
  530.     }
  531. }
  532.  
  533. /*++ QuickConfirm
  534.  
  535. Function Description:
  536.  
  537.     Gets a confirmation for things like terminating/debugging processes
  538.  
  539. Arguments:
  540.  
  541.     idtitle - string ID of title for message box
  542.     idmsg   - string ID of message body
  543.  
  544. Return Value:
  545.  
  546.     IDNO/IDYES, whatever comes back from MessageBox
  547.  
  548. Revision History:
  549.  
  550.       Nov-28-95 Davepl  Created
  551.  
  552. --*/
  553.  
  554. UINT CProcPage::QuickConfirm(UINT idTitle, UINT idBody)
  555. {
  556.     /* We have removed the ability to disable confirmations
  557.  
  558.     if (FALSE == g_Options.m_fConfirmations)
  559.     {
  560.         return IDYES;
  561.     }
  562.     */
  563.  
  564.     // Get confirmation before we dust the process, or something similar
  565.  
  566.     TCHAR szTitle[MAX_PATH];
  567.     TCHAR szBody[MAX_PATH];
  568.  
  569.     if (0 == LoadString(g_hInstance, idTitle, szTitle, ARRAYSIZE(szTitle)) ||
  570.         0 == LoadString(g_hInstance, idBody,    szBody,  ARRAYSIZE(szBody)))
  571.     {
  572.         return IDNO;
  573.     }
  574.  
  575.  
  576.     if (IDYES == MessageBox(m_hPage, szBody, szTitle, MB_ICONEXCLAMATION | MB_YESNO))
  577.     {
  578.         return IDYES;
  579.     }
  580.  
  581.     return IDNO;
  582. }
  583.  
  584. /*++ class CProcPage::SetupColumns
  585.  
  586. Class Description:
  587.  
  588.     Removes any existing columns from the process listview and
  589.     adds all of the columns listed in the g_Options.m_ActiveProcCol array.
  590.  
  591. Arguments:
  592.  
  593. Return Value:
  594.  
  595.     HRESULT
  596.  
  597. Revision History:
  598.  
  599.       Nov-16-95 Davepl  Created
  600.  
  601. --*/
  602.  
  603. static const _aIDColNames[NUM_COLUMN] =
  604. {
  605.     IDS_COL_IMAGENAME,    
  606.     IDS_COL_PID,
  607.     IDS_COL_USERNAME,
  608.     IDS_COL_SESSIONID,
  609.     IDS_COL_CPU,          
  610.     IDS_COL_CPUTIME,      
  611.     IDS_COL_MEMUSAGE,      
  612.     IDS_COL_MEMPEAK,      
  613.     IDS_COL_MEMUSAGEDIFF,  
  614.     IDS_COL_PAGEFAULTS,    
  615.     IDS_COL_PAGEFAULTSDIFF,
  616.     IDS_COL_COMMITCHARGE,  
  617.     IDS_COL_PAGEDPOOL,    
  618.     IDS_COL_NONPAGEDPOOL,  
  619.     IDS_COL_BASEPRIORITY,  
  620.     IDS_COL_HANDLECOUNT,  
  621.     IDS_COL_THREADCOUNT,  
  622.     IDS_COL_USEROBJECTS,  
  623.     IDS_COL_GDIOBJECTS,
  624.     IDS_COL_READOPERCOUNT,
  625.     IDS_COL_WRITEOPERCOUNT,
  626.     IDS_COL_OTHEROPERCOUNT,
  627.     IDS_COL_READXFERCOUNT,
  628.     IDS_COL_WRITEXFERCOUNT,
  629.     IDS_COL_OTHERXFERCOUNT
  630. };
  631.  
  632. HRESULT CProcPage::SetupColumns()
  633. {
  634.     HWND hwndList = GetDlgItem(m_hPage, IDC_PROCLIST);
  635.     if (NULL == hwndList)
  636.     {
  637.         return E_UNEXPECTED;
  638.     }
  639.  
  640.     ListView_DeleteAllItems(hwndList);
  641.  
  642.     // Remove all existing columns
  643.  
  644.     LV_COLUMN lvcolumn;
  645.     while(ListView_DeleteColumn(hwndList, 0))
  646.     {
  647.         NULL;
  648.     }
  649.  
  650.     // Add all of the new columns
  651.  
  652.     INT iColumn = 0;
  653.     while (g_Options.m_ActiveProcCol[iColumn] >= 0)
  654.     {
  655.        
  656.         INT idColumn = g_Options.m_ActiveProcCol[iColumn];
  657.  
  658.         // idc_username or IDC_SESSIONID are available only for terminalserver.
  659.  
  660.         ASSERT((idColumn != COL_USERNAME && idColumn != COL_SESSIONID) || g_fIsTSEnabled);
  661.  
  662.         TCHAR szTitle[MAX_PATH];
  663.         LoadString(g_hInstance, _aIDColNames[idColumn], szTitle, ARRAYSIZE(szTitle));
  664.  
  665.         lvcolumn.mask       = LVCF_FMT | LVCF_TEXT | LVCF_TEXT | LVCF_WIDTH;
  666.         lvcolumn.fmt        = ColumnDefaults[ idColumn ].Format;
  667.  
  668.         // If no width preference has been recorded for this column, use the
  669.         // default
  670.  
  671.         if (-1 == g_Options.m_ColumnWidths[iColumn])
  672.         {
  673.             lvcolumn.cx = ColumnDefaults[ idColumn ].Width;
  674.         }
  675.         else
  676.         {
  677.             lvcolumn.cx = g_Options.m_ColumnWidths[iColumn];
  678.         }
  679.  
  680.         lvcolumn.pszText    = szTitle;
  681.         lvcolumn.iSubItem   = iColumn;
  682.  
  683.         if (-1 == ListView_InsertColumn(hwndList, iColumn, &lvcolumn))
  684.         {
  685.             return E_FAIL;
  686.         }
  687.         iColumn++;
  688.     }
  689.  
  690.     return S_OK;
  691. }
  692.  
  693. //
  694. //  Take two unsigned 64-bit values and compare them in a manner
  695. //  that CProcInfo::Compare likes.
  696. //
  697. int Compare64(unsigned __int64 First, unsigned __int64 Second)
  698. {
  699.     if (First < Second)
  700.         return -1;
  701.     else if (First > Second)
  702.         return 1;
  703.     else
  704.         return 0;
  705. }
  706.  
  707. /*++ class CProcInfo::Compare
  708.  
  709. Class Description:
  710.  
  711.     Compares this CProcInfo object to another, and returns its ranking
  712.     based on the g_iProcSortColumnID field.
  713.  
  714.     Note that if the objects are equal based on the current sort column,
  715.     the PID is used as a secondary sort key to prevent items from
  716.     jumping around in the listview
  717.  
  718.     WOW psuedo-processes always sort directly after their parent
  719.     ntvdm.exe process.  So really the sort order is:
  720.  
  721.     1. WOW task psuedo-processes under parent in alpha order
  722.     2. User's selected order.
  723.     3. PID
  724.  
  725. Arguments:
  726.  
  727.     pOther  - the CProcInfo object to compare this to
  728.  
  729. Return Value:
  730.  
  731.     < 0      - This CProcInfo is "less" than the other
  732.       0      - Equal (Can't happen, since PID is used to sort)
  733.     > 0      - This CProcInfo is "greater" than the other
  734.  
  735. Revision History:
  736.  
  737.       Nov-20-95 Davepl  Created
  738.  
  739. --*/
  740.  
  741. INT CProcInfo::Compare(CProcInfo * pOther)
  742. {
  743.     CProcInfo * pMyThis;
  744.     CProcInfo * pMyOther;
  745.     INT iRet = 0;
  746.  
  747.     //
  748.     // Wow psuedo-processes don't have any performance information,
  749.     // so use the parent "real" ntvdm.exe CProcInfo for sorting.
  750.     //
  751.  
  752.     ASSERT(this != pOther);
  753.  
  754.     pMyThis = this->IsWowTask()
  755.               ? this->m_pWowParentProcInfo
  756.               : this;
  757.  
  758.     pMyOther = pOther->IsWowTask()
  759.                ? pOther->m_pWowParentProcInfo
  760.                : pOther;
  761.  
  762.     if (pMyThis == pMyOther) {
  763.  
  764.         //
  765.         // This implies one or the other or both this and pOther
  766.         // are WOW tasks, and they're in the same WOW VDM.  Sort
  767.         // the "real" process entry first, followed by its associated
  768.         // WOW task entries alphabetical.
  769.         //
  770.  
  771.         if (this->IsWowTask()) {
  772.  
  773.             if (pOther->IsWowTask()) {
  774.  
  775.                 //
  776.                 // They are siblings and we sort by
  777.                 // image name.
  778.                 //
  779.  
  780.                 ASSERT(this->m_pWowParentProcInfo ==
  781.                        pOther->m_pWowParentProcInfo);
  782.  
  783.                 iRet = lstrcmpi(this->m_pszImageName, pOther->m_pszImageName);
  784.  
  785.             } else {
  786.  
  787.                 //
  788.                 // pOther is not a Wow task, it must be ntvdm.exe
  789.                 // the parent of this.  this sorts after pOther.
  790.                 //
  791.  
  792.                 ASSERT(pOther == this->m_pWowParentProcInfo);
  793.  
  794.                 iRet = 1;
  795.             }
  796.         } else {
  797.  
  798.             //
  799.             // this is not a Wow task, pOther must be and
  800.             // this must be pOther's parent.
  801.             //
  802.  
  803.             ASSERT(pOther->IsWowTask());
  804.  
  805.             iRet = -1;
  806.         }
  807.     }
  808.  
  809.  
  810.     if (0 == iRet) {
  811.  
  812.         switch (g_iProcSortColumnID)
  813.         {
  814.             case COL_CPU:
  815.                 iRet = Compare64(pMyThis->m_CPU, pMyOther->m_CPU);
  816.             break;
  817.  
  818.             case COL_CPUTIME:
  819.                 iRet = Compare64(pMyThis->m_CPUTime.QuadPart, pMyOther->m_CPUTime.QuadPart);
  820.                 break;
  821.  
  822.             case COL_MEMUSAGE:
  823.                 iRet = Compare64(pMyThis->m_MemUsage, pMyOther->m_MemUsage);
  824.                 break;
  825.  
  826.             case COL_MEMUSAGEDIFF:
  827.                 iRet = Compare64(pMyThis->m_MemDiff, pMyOther->m_MemDiff);
  828.                 break;
  829.  
  830.             case COL_MEMPEAK:
  831.                 iRet = Compare64(pMyThis->m_MemPeak, pMyOther->m_MemPeak);
  832.                 break;
  833.  
  834.             case COL_PAGEFAULTS:
  835.                 iRet = Compare64(pMyThis->m_PageFaults, pMyOther->m_PageFaults);
  836.                 break;
  837.  
  838.             case COL_PAGEFAULTSDIFF:
  839.                 iRet = Compare64(pMyThis->m_PageFaultsDiff, pMyOther->m_PageFaultsDiff);
  840.                 break;
  841.  
  842.             case COL_COMMITCHARGE:
  843.                 iRet = Compare64(pMyThis->m_CommitCharge, pMyOther->m_CommitCharge);
  844.                 break;
  845.  
  846.             case COL_PAGEDPOOL:
  847.                 iRet = Compare64(pMyThis->m_PagedPool, pMyOther->m_PagedPool);
  848.                 break;
  849.  
  850.             case COL_NONPAGEDPOOL:
  851.                 iRet = Compare64(pMyThis->m_NonPagedPool, pMyOther->m_NonPagedPool);
  852.                 break;
  853.  
  854.             case COL_BASEPRIORITY:
  855.                 iRet = Compare64(GetPriRanking(pMyThis->m_PriClass), GetPriRanking(pMyOther->m_PriClass));
  856.                 break;
  857.  
  858.             case COL_HANDLECOUNT:
  859.                 iRet = Compare64(pMyThis->m_HandleCount, pMyOther->m_HandleCount);
  860.                 break;
  861.  
  862.             case COL_THREADCOUNT:
  863.                 iRet = Compare64(pMyThis->m_ThreadCount, pMyOther->m_ThreadCount);
  864.                 break;
  865.  
  866.             case COL_PID:
  867.                 iRet = Compare64(pMyThis->m_UniqueProcessId, pMyOther->m_UniqueProcessId);
  868.                 break;
  869.  
  870.             case COL_SESSIONID:                
  871.                 iRet = Compare64(pMyThis->m_SessionId, pMyOther->m_SessionId);
  872.                 break;
  873.  
  874.             case COL_USERNAME:                
  875.                 iRet = lstrcmpi( pMyThis->m_pszUserName , pMyOther->m_pszUserName );
  876.                 break;
  877.  
  878.             case COL_IMAGENAME:
  879.                 iRet = lstrcmpi(pMyThis->m_pszImageName, pMyOther->m_pszImageName);
  880.                 break;
  881.  
  882.             case COL_USEROBJECTS:
  883.                 iRet = Compare64(pMyThis->m_USERObjectCount, pMyOther->m_USERObjectCount);
  884.                 break;
  885.  
  886.             case COL_GDIOBJECTS:
  887.                 iRet = Compare64(pMyThis->m_GDIObjectCount, pMyOther->m_GDIObjectCount);
  888.                 break;
  889.  
  890.             case COL_READOPERCOUNT:
  891.                 iRet = Compare64(pMyThis->m_IoReadOperCount, pMyOther->m_IoReadOperCount);
  892.                 break;
  893.  
  894.             case COL_WRITEOPERCOUNT:
  895.                 iRet = Compare64(pMyThis->m_IoWriteOperCount, pMyOther->m_IoWriteOperCount);
  896.                 break;
  897.  
  898.             case COL_OTHEROPERCOUNT:
  899.                 iRet = Compare64(pMyThis->m_IoOtherOperCount, pMyOther->m_IoOtherOperCount);
  900.                 break;
  901.  
  902.             case COL_READXFERCOUNT:
  903.                 iRet = Compare64(pMyThis->m_IoReadXferCount, pMyOther->m_IoReadXferCount);
  904.                 break;
  905.  
  906.             case COL_WRITEXFERCOUNT:
  907.                 iRet = Compare64(pMyThis->m_IoWriteXferCount, pMyOther->m_IoWriteXferCount);
  908.                 break;
  909.  
  910.             case COL_OTHERXFERCOUNT:
  911.                 iRet = Compare64(pMyThis->m_IoOtherXferCount, pMyOther->m_IoOtherXferCount);
  912.                 break;
  913.  
  914.             default:
  915.                 ASSERT(FALSE);
  916.                 iRet = 0;
  917.                 break;
  918.         }
  919.  
  920.         iRet *= g_iProcSortDirection;
  921.     }
  922.  
  923.     // If objects look equal, compare on PID as secondary sort column
  924.     // so that items don't jump around in the listview
  925.  
  926.     if (0 == iRet)
  927.     {
  928.         iRet = Compare64(pMyThis->m_UniqueProcessId,
  929.                       pMyOther->m_UniqueProcessId) *
  930.                      g_iProcSortDirection;
  931.     }
  932.  
  933.     return iRet;
  934. }
  935.  
  936.  
  937. /*++ class CProcInfo::SetCPU
  938.  
  939. Method Description:
  940.  
  941.     Sets the CPU percentage.
  942.  
  943. Arguments:
  944.  
  945.     CPUTime   - Time for this process
  946.     TotalTime - Total elapsed time, used as the denominator in calculations
  947.  
  948. Return Value:
  949.  
  950. Revision History:
  951.  
  952.       19-Feb-96  DaveHart  Created
  953.  
  954. --*/
  955.  
  956. void CProcInfo::SetCPU(LARGE_INTEGER CPUTimeDelta,
  957.                        LARGE_INTEGER TotalTime,
  958.                        BOOL fDisplayOnly)
  959. {
  960.     // Calc CPU time based on this process's ratio of the total process time used
  961.  
  962.     INT cpu = (BYTE) (((CPUTimeDelta.QuadPart / ((TotalTime.QuadPart / 1000) ?
  963.                                                  (TotalTime.QuadPart / 1000) : 1)) + 5)
  964.                                               / 10);
  965.     // ASSERT( cpu <= 105 && "CPU much > 100% - Davepl x69731, 425-836-1939 (res)");
  966.  
  967.     if (cpu > 99)
  968.     {
  969.         cpu = 99;
  970.     }
  971.    
  972.     if (m_DisplayCPU != cpu)
  973.     {
  974.         m_fDirty_COL_CPU = TRUE;
  975.         m_DisplayCPU = (BYTE) cpu;
  976.  
  977.         if ( ! fDisplayOnly )
  978.         {
  979.             m_CPU = (BYTE) cpu;
  980.         }
  981.     }
  982.  
  983. }
  984. /*++ CProcPage::GetProcessInfo
  985.  
  986. Class Description:
  987.  
  988.     Reads the process info table into a virtual alloc'd buffer, resizing
  989.     the buffer if needed
  990.  
  991. Arguments:
  992.  
  993. Return Value:
  994.  
  995. Revision History:
  996.  
  997.       Nov-16-95 Davepl  Created
  998.  
  999. --*/
  1000.  
  1001. static const int PROCBUF_GROWSIZE = 4096;
  1002.  
  1003. HRESULT CProcPage::GetProcessInfo()
  1004. {
  1005.     HRESULT  hr = S_OK;
  1006.     NTSTATUS status;
  1007.  
  1008.     while(hr == S_OK)
  1009.     {
  1010.         if (m_pvBuffer)
  1011.         {
  1012.             status = NtQuerySystemInformation(SystemProcessInformation,
  1013.                                               m_pvBuffer,
  1014.                                               static_cast<ULONG>(m_cbBuffer),
  1015.                                               NULL);
  1016.  
  1017.             //
  1018.             // If we succeeded, great, get outta here.  If not, any error other
  1019.             // than "buffer too small" is fatal, in which case we bail
  1020.             //
  1021.  
  1022.             if (NT_SUCCESS(status))
  1023.             {
  1024.                 break;
  1025.             }
  1026.  
  1027.             if (status != STATUS_INFO_LENGTH_MISMATCH)
  1028.             {
  1029.                 hr = E_FAIL;
  1030.                 break;
  1031.             }
  1032.         }
  1033.  
  1034.         //
  1035.         // Buffer wasn't large enough to hold the process info table, so resize it
  1036.         // to be larger, then retry.
  1037.         //
  1038.  
  1039.         if (m_pvBuffer)
  1040.         {
  1041.             HeapFree( GetProcessHeap( ), 0, m_pvBuffer );
  1042.             m_pvBuffer = NULL;
  1043.         }
  1044.  
  1045.         m_cbBuffer += PROCBUF_GROWSIZE;
  1046.  
  1047.         m_pvBuffer = HeapAlloc( GetProcessHeap( ), 0, m_cbBuffer );
  1048.         if (m_pvBuffer == NULL)
  1049.         {
  1050.             hr = E_OUTOFMEMORY;
  1051.             break;
  1052.         }
  1053.     }
  1054.  
  1055.     return hr;
  1056. }
  1057.  
  1058.  
  1059. /*++ CProcPage::Int64ToCommaSepString
  1060.  
  1061. Class Description:
  1062.  
  1063.     Convert a 64-bit integer to a string with commas.
  1064.  
  1065.     (2^64)-1 = "18,446,744,073,709,600,000"  (27 chars).
  1066.  
  1067. Arguments:
  1068.  
  1069.     n           - 64-bit integer.
  1070.     pszOut      - Destination character buffer.
  1071.     cchOut      - Size of destination buffer in characters.
  1072.  
  1073. Return Value:
  1074.  
  1075.     None.
  1076.  
  1077. Revision History:
  1078.  
  1079.       Jan-11-99 BrianAu  Created
  1080.  
  1081. --*/
  1082.  
  1083. NTSTATUS
  1084. MyMoBettaRtlInt64ToUnicodeString (
  1085.     IN LONGLONG Value,
  1086.     IN ULONG Base OPTIONAL,
  1087.     IN OUT PUNICODE_STRING String
  1088.     )
  1089.  
  1090. {
  1091.  
  1092.     NTSTATUS Status;
  1093.     char ResultBuffer[32];
  1094.     ANSI_STRING AnsiString;
  1095.     LARGE_INTEGER Temp;
  1096.  
  1097.     if (Value < 0)
  1098.     {
  1099.         Temp.QuadPart = -Value;
  1100.         Status = RtlLargeIntegerToChar(&Temp,
  1101.                                        Base,
  1102.                                        sizeof(ResultBuffer) - sizeof(CHAR),
  1103.                                        &ResultBuffer[sizeof(CHAR)]);
  1104.         *(ResultBuffer)=L'-';    
  1105.     }
  1106.     else
  1107.     {
  1108.         Temp.QuadPart = Value;
  1109.         Status = RtlLargeIntegerToChar(&Temp,
  1110.                                        Base,
  1111.                                        sizeof(ResultBuffer),
  1112.                                        ResultBuffer);
  1113.     }
  1114.  
  1115.     if (NT_SUCCESS(Status)) {
  1116.         AnsiString.Buffer = ResultBuffer;
  1117.         AnsiString.MaximumLength = sizeof(ResultBuffer);
  1118.         AnsiString.Length = (USHORT)strlen(ResultBuffer);
  1119.         Status = RtlAnsiStringToUnicodeString(String, &AnsiString, FALSE);
  1120.     }
  1121.  
  1122.     return Status;
  1123. }
  1124. void
  1125. CProcPage::Int64ToCommaSepString(
  1126.     LONGLONG n,
  1127.     LPTSTR pszOut,
  1128.     int cchOut
  1129.     )
  1130. {
  1131.     UNICODE_STRING s;
  1132.     NUMBERFMTW nfmtW;
  1133.     LPWSTR pszFmtOutW;
  1134.     int cchFmtOut;
  1135.     WCHAR szTextW[32];
  1136.     //
  1137.     // Convert the 64-bit int to a text string.
  1138.     //
  1139.     s.Length        = 0;
  1140.     s.MaximumLength = sizeof(szTextW) - sizeof(TCHAR);
  1141.     s.Buffer        = szTextW;
  1142.     MyMoBettaRtlInt64ToUnicodeString(n, 10, &s);
  1143.     //
  1144.     // Format the number with commas according to locale conventions.
  1145.     //
  1146.     nfmtW.NumDigits     = 0;
  1147.     nfmtW.LeadingZero   = 0;
  1148.  
  1149.     nfmtW.Grouping      = UINT(g_ulGroupSep);
  1150.     nfmtW.lpDecimalSep  = nfmtW.lpThousandSep = g_szGroupThousSep;
  1151.     nfmtW.NegativeOrder = 0;
  1152.  
  1153.     pszFmtOutW = pszOut;
  1154.     cchFmtOut  = cchOut;
  1155.  
  1156.     GetNumberFormatW(LOCALE_USER_DEFAULT,
  1157.                      0,
  1158.                      szTextW,
  1159.                      &nfmtW,
  1160.                      pszFmtOutW,
  1161.                      cchFmtOut);
  1162. }
  1163.  
  1164.  
  1165. /*++ CProcPage::Int64ToCommaSepKString
  1166.  
  1167. Class Description:
  1168.  
  1169.     Convert a 64-bit integer to a string with commas appended
  1170.     with the "K" units designator.
  1171.  
  1172.     (2^64)-1 = "18,446,744,073,709,600,000 K"  (29 chars).
  1173.  
  1174. Arguments:
  1175.  
  1176.     n           - 64-bit integer.
  1177.     pszOut      - Destination character buffer.
  1178.  
  1179. Return Value:
  1180.  
  1181.     None.
  1182.  
  1183. Revision History:
  1184.  
  1185.       Jan-11-99 BrianAu  Created
  1186.  
  1187. --*/
  1188.  
  1189. void
  1190. CProcPage::Int64ToCommaSepKString(
  1191.     LONGLONG n,
  1192.     LPTSTR pszOut,
  1193.     int cchOut
  1194.     )
  1195. {
  1196.     TCHAR szText[40];
  1197.  
  1198.     Int64ToCommaSepString(n, szText, ARRAYSIZE(szText));
  1199.  
  1200.     LPTSTR pszEnd = szText + lstrlen(szText);
  1201.  
  1202.     *pszEnd++ = TEXT(' ');
  1203.     lstrcpy(pszEnd, g_szK);
  1204.     lstrcpyn(pszOut, szText, cchOut);
  1205. }
  1206.  
  1207.  
  1208. /*++ CProcPage::RestoreColumnOrder
  1209.  
  1210. Routine Description:
  1211.  
  1212.     Sets the column order from the per-user preference data stored
  1213.     in the global COptions object.
  1214.    
  1215. Arguments:
  1216.  
  1217.     hwndList - Listview window handle.
  1218.  
  1219. Return Value:
  1220.  
  1221. Revision History:
  1222.  
  1223.       Jan-11/99 BrianAu  Created
  1224.  
  1225. --*/
  1226.  
  1227. void
  1228. CProcPage::RestoreColumnOrder(
  1229.     HWND hwndList
  1230.     )
  1231. {
  1232.     INT rgOrder[ARRAYSIZE(g_Options.m_ColumnPositions)];
  1233.     INT cOrder = 0;
  1234.     INT iOrder = 0;
  1235.  
  1236.     for (int i = 0; i < ARRAYSIZE(g_Options.m_ColumnPositions); i++)
  1237.     {
  1238.         iOrder = g_Options.m_ColumnPositions[i];
  1239.         if (-1 == iOrder)
  1240.             break;
  1241.  
  1242.         rgOrder[cOrder++] = iOrder;
  1243.     }
  1244.     if (0 < cOrder)
  1245.     {
  1246.         const HWND hwndHeader = ListView_GetHeader(hwndList);
  1247.         ASSERT(Header_GetItemCount(hwndHeader) == cOrder);
  1248.         Header_SetOrderArray(hwndHeader, Header_GetItemCount(hwndHeader), rgOrder);
  1249.     }
  1250. }
  1251.  
  1252.  
  1253. /*++ CProcPage::RememberColumnOrder
  1254.  
  1255. Routine Description:
  1256.  
  1257.     Saves the current column order to the global COptions object
  1258.     which is later saved to the registry for per-user preferences.
  1259.    
  1260. Arguments:
  1261.  
  1262.     hwndList - Listview window handle.
  1263.  
  1264. Return Value:
  1265.  
  1266. Revision History:
  1267.  
  1268.       Jan-11/99 BrianAu  Created
  1269.  
  1270. --*/
  1271.  
  1272. void
  1273. CProcPage::RememberColumnOrder(
  1274.     HWND hwndList
  1275.     )
  1276. {
  1277.     const HWND hwndHeader = ListView_GetHeader(hwndList);
  1278.  
  1279.     ASSERT(Header_GetItemCount(hwndHeader) <= ARRAYSIZE(g_Options.m_ColumnPositions));
  1280.  
  1281.     FillMemory(&g_Options.m_ColumnPositions, sizeof(g_Options.m_ColumnPositions), 0xFF);
  1282.     Header_GetOrderArray(hwndHeader,
  1283.                          Header_GetItemCount(hwndHeader),
  1284.                          g_Options.m_ColumnPositions);
  1285. }
  1286.  
  1287.  
  1288.  
  1289. /*++ FindProcInArrayByPID
  1290.  
  1291. Class Description:
  1292.  
  1293.     Walks the ptrarray given and looks for the CProcInfo object
  1294.     that has the PID supplied.  If not found, returns NULL
  1295.  
  1296. Arguments:
  1297.  
  1298.     pArray      - The CPtrArray where the CProcInfos could live
  1299.     pid         - The pid to search for
  1300.  
  1301. Return Value:
  1302.  
  1303.     CProcInfo * in the array, if found, or NULL if not
  1304.  
  1305. Revision History:
  1306.  
  1307.       Nov-20-95 Davepl  Created
  1308.  
  1309. --*/
  1310.  
  1311. // REVIEW (DavePl) could provide a static search hint here so
  1312. // that it doesn't always need to start back at zero, or could
  1313. // do a binary search
  1314.  
  1315. CProcInfo * FindProcInArrayByPID(CPtrArray * pArray, DWORD pid)
  1316. {
  1317.     for (int i = 0; i < pArray->GetSize(); i++)
  1318.     {
  1319.         CProcInfo * pTmp = (CProcInfo *) (pArray->GetAt(i));
  1320.        
  1321.         if (pTmp->m_UniqueProcessId == pid)
  1322.         {
  1323.             // Found it
  1324.  
  1325.             return pTmp;
  1326.         }
  1327.     }
  1328.  
  1329.     // Not found
  1330.  
  1331.     return NULL;
  1332. }
  1333.  
  1334. /*++ InsertIntoSortedArray
  1335.  
  1336. Class Description:
  1337.  
  1338.     Sticks a CProcInfo ptr into the ptrarray supplied at the
  1339.     appropriate location based on the current sort column (which
  1340.     is used by the Compare member function)
  1341.  
  1342. Arguments:
  1343.  
  1344.     pArray      - The CPtrArray to add to
  1345.     pProc       - The CProcInfo object to add to the array
  1346.  
  1347. Return Value:
  1348.  
  1349.     TRUE if successful, FALSE if fails
  1350.  
  1351. Revision History:
  1352.  
  1353.       Nov-20-95 Davepl  Created
  1354.  
  1355. --*/
  1356.  
  1357. // REVIEW (davepl) Use binary insert here, not linear
  1358.  
  1359. BOOL InsertIntoSortedArray(CPtrArray * pArray, CProcInfo * pProc)
  1360. {
  1361.    
  1362.     INT cItems = pArray->GetSize();
  1363.    
  1364.     for (INT iIndex = 0; iIndex < cItems; iIndex++)
  1365.     {
  1366.         CProcInfo * pTmp = (CProcInfo *) pArray->GetAt(iIndex);
  1367.        
  1368.         if (pProc->Compare(pTmp) > 0)
  1369.         {
  1370.             return pArray->InsertAt(iIndex, pProc);
  1371.         }
  1372.     }
  1373.  
  1374.     return pArray->Add(pProc);
  1375. }
  1376.  
  1377. /*++ ResortArray
  1378.  
  1379. Function Description:
  1380.  
  1381.     Creates a new ptr array sorted in the current sort order based
  1382.     on the old array, and then replaces the old with the new
  1383.  
  1384. Arguments:
  1385.  
  1386.     ppArray     - The CPtrArray to resort
  1387.  
  1388. Return Value:
  1389.  
  1390.     TRUE if successful, FALSE if fails
  1391.  
  1392. Revision History:
  1393.  
  1394.       Nov-21-95 Davepl  Created
  1395.  
  1396. --*/
  1397.  
  1398. BOOL ResortArray(CPtrArray ** ppArray)
  1399. {
  1400.     // Create a new array which will be sorted in the new
  1401.     // order and used to replace the existing array
  1402.  
  1403.     CPtrArray * pNew = new CPtrArray(GetProcessHeap());
  1404.     if (NULL == pNew)
  1405.     {
  1406.         return FALSE;
  1407.     }
  1408.  
  1409.     // Insert each of the existing items in the old array into
  1410.     // the new array in the correct spot
  1411.  
  1412.     INT cItems = (*ppArray)->GetSize();
  1413.     for (int i = 0; i < cItems; i++)
  1414.     {
  1415.         CProcInfo * pItem = (CProcInfo *) (*ppArray)->GetAt(i);
  1416.      
  1417.         if (FALSE == InsertIntoSortedArray(pNew, pItem))
  1418.         {
  1419.             delete pNew;
  1420.             return FALSE;
  1421.         }
  1422.     }
  1423.  
  1424.     // Kill off the old array, replace it with the new
  1425.  
  1426.     delete (*ppArray);
  1427.     (*ppArray) = pNew;
  1428.     return TRUE;
  1429. }
  1430.  
  1431.  
  1432. typedef struct
  1433. {
  1434.     LARGE_INTEGER               uPassCount;
  1435.     CProcPage *                 pProcPage;
  1436.     CProcInfo *                 pParentProcInfo;
  1437.     LARGE_INTEGER               TotalTime;
  1438.     LARGE_INTEGER               TimeLeft;
  1439. } WOWTASKCALLBACKPARMS, *PWOWTASKCALLBACKPARMS;
  1440.  
  1441.  
  1442. BOOL WINAPI WowTaskCallback(
  1443.     DWORD dwThreadId,
  1444.     WORD hMod16,
  1445.     WORD hTask16,
  1446.     CHAR *pszModName,
  1447.     CHAR *pszFileName,
  1448.     LPARAM lparam
  1449.     )
  1450. {
  1451.     PWOWTASKCALLBACKPARMS pParms = (PWOWTASKCALLBACKPARMS)lparam;
  1452.     HRESULT hr;
  1453.  
  1454.     //
  1455.     // See if this task is already in the list.
  1456.     //
  1457.    
  1458.     CProcInfo * pOldProcInfo;
  1459.     pOldProcInfo = FindProcInArrayByPID(
  1460.                        pParms->pProcPage->m_pProcArray,
  1461.                        dwThreadId);
  1462.  
  1463.     if (NULL == pOldProcInfo)
  1464.     {
  1465.         //
  1466.         // We don't already have this process in our array, so create a new one
  1467.         // and add it to the array
  1468.         //
  1469.  
  1470.         CProcInfo * pNewProcInfo = new CProcInfo;
  1471.         if (NULL == pNewProcInfo)
  1472.         {
  1473.             goto done;
  1474.         }
  1475.  
  1476.         hr = pNewProcInfo->SetDataWowTask(pParms->TotalTime,
  1477.                                                     dwThreadId,
  1478.                                                     pszFileName,
  1479.                                                     pParms->uPassCount,
  1480.                                                     pParms->pParentProcInfo,
  1481.                                                     &pParms->TimeLeft,
  1482.                                                     hTask16,
  1483.                                                     FALSE);
  1484.  
  1485.         if (FAILED(hr) ||
  1486.             FALSE == pParms->pProcPage->m_pProcArray->Add(pNewProcInfo))
  1487.         {
  1488.             delete pNewProcInfo;
  1489.             goto done;
  1490.         }
  1491.     }
  1492.     else
  1493.     {
  1494.         //
  1495.         // This process already existed in our array, so update its info
  1496.         //
  1497.  
  1498.         pOldProcInfo->SetDataWowTask(pParms->TotalTime,
  1499.                                      dwThreadId,
  1500.                                      pszFileName,
  1501.                                      pParms->uPassCount,
  1502.                                      pParms->pParentProcInfo,
  1503.                                      &pParms->TimeLeft,
  1504.                                      hTask16,
  1505.                                      TRUE);
  1506.     }
  1507.  
  1508. done:
  1509.     return FALSE;  // continue enumeration
  1510. }
  1511.  
  1512.  
  1513. /*++ class CProcInfo::SetDataWowTask
  1514.  
  1515. Method Description:
  1516.  
  1517.     Sets up a single CProcInfo object based on the parameters.
  1518.     This is a WOW task pseudo-process entry.
  1519.  
  1520. Arguments:
  1521.  
  1522.     dwThreadId
  1523.  
  1524.     pszFilePath    Fully-qualified path from VDMEnumTaskWOWEx.
  1525.  
  1526. Return Value:
  1527.  
  1528. Revision History:
  1529.  
  1530.       18-Feb-96  DaveHart  created
  1531.  
  1532. --*/
  1533.  
  1534. HRESULT CProcInfo::SetDataWowTask(LARGE_INTEGER  TotalTime,
  1535.                                   DWORD          dwThreadId,
  1536.                                   CHAR *         pszFilePath,
  1537.                                   LARGE_INTEGER  uPassCount,
  1538.                                   CProcInfo *    pParentProcInfo,
  1539.                                   LARGE_INTEGER *pTimeLeft,
  1540.                                   WORD           htask,
  1541.                                   BOOL           fUpdateOnly)
  1542. {
  1543.     CHAR *pchExe;
  1544.  
  1545.     //
  1546.     // Touch this CProcInfo to indicate the process is still alive
  1547.      //
  1548.  
  1549.     m_uPassCount.QuadPart = uPassCount.QuadPart;
  1550.  
  1551.     //
  1552.     // Update the thread's execution times.
  1553.     //
  1554.  
  1555.     HANDLE             hThread;
  1556.     NTSTATUS           Status;
  1557.     OBJECT_ATTRIBUTES  obja;
  1558.     CLIENT_ID          cid;
  1559.  
  1560.     InitializeObjectAttributes(
  1561.             &obja,
  1562.             NULL,
  1563.             0,
  1564.             NULL,
  1565.             0 );
  1566.  
  1567.     cid.UniqueProcess = 0;      // 0 means any process
  1568.     cid.UniqueThread  = IntToPtr(dwThreadId);
  1569.  
  1570.     Status = NtOpenThread(
  1571.                 &hThread,
  1572.                 THREAD_QUERY_INFORMATION,
  1573.                 &obja,
  1574.                 &cid );
  1575.  
  1576.     ULONGLONG ullCreation, ullExit, ullKernel, ullUser;
  1577.     if ( NT_SUCCESS(Status) )
  1578.     {
  1579.         LARGE_INTEGER TimeDelta, Time;
  1580.  
  1581.         if (GetThreadTimes(
  1582.                 hThread,
  1583.                 (LPFILETIME) &ullCreation,
  1584.                 (LPFILETIME) &ullExit,
  1585.                 (LPFILETIME) &ullKernel,
  1586.                 (LPFILETIME) &ullUser
  1587.                 ) )
  1588.         {
  1589.  
  1590.             Time.QuadPart = (LONGLONG)(ullUser + ullKernel);
  1591.  
  1592.             TimeDelta.QuadPart = Time.QuadPart - m_CPUTime.QuadPart;
  1593.  
  1594.             if (TimeDelta.QuadPart < 0)
  1595.             {
  1596.                 ASSERT(0 && "WOW tasks's cpu total usage went DOWN since last refresh - Bug 247473, Shaunp");
  1597.                 Invalidate();
  1598.                 return E_FAIL;
  1599.             }
  1600.  
  1601.             if (TimeDelta.QuadPart)
  1602.             {
  1603.                 m_fDirty_COL_CPUTIME = TRUE;
  1604.                 m_CPUTime.QuadPart = Time.QuadPart;
  1605.             }
  1606.  
  1607.             //
  1608.             // Don't allow sum of WOW child task times to
  1609.             // exceed ntvdm.exe total.  We call GetThreadTimes
  1610.             // substantially after we get process times, so
  1611.             // this can happen.
  1612.             //
  1613.  
  1614.             if (TimeDelta.QuadPart > pTimeLeft->QuadPart)
  1615.             {
  1616.                 TimeDelta.QuadPart = pTimeLeft->QuadPart;
  1617.                 pTimeLeft->QuadPart = 0;
  1618.             }
  1619.             else
  1620.             {
  1621.                 pTimeLeft->QuadPart -= TimeDelta.QuadPart;
  1622.             }
  1623.  
  1624.             SetCPU( TimeDelta, TotalTime, FALSE );
  1625.  
  1626.             //
  1627.             // When WOW tasks are being displayed, the line for ntvdm.exe
  1628.             // should show times only for overhead or historic threads,
  1629.             // not including any active task threads.
  1630.             //
  1631.  
  1632.             if (pParentProcInfo->m_DisplayCPUTime.QuadPart > m_CPUTime.QuadPart)
  1633.             {
  1634.                 pParentProcInfo->m_DisplayCPUTime.QuadPart -= m_CPUTime.QuadPart;
  1635.             }
  1636.             else
  1637.             {
  1638.                 pParentProcInfo->m_DisplayCPUTime.QuadPart = 0;
  1639.             }
  1640.  
  1641.             m_DisplayCPUTime.QuadPart = m_CPUTime.QuadPart;
  1642.         }
  1643.  
  1644.         NtClose(hThread);
  1645.     }
  1646.  
  1647.     if (m_PriClass != pParentProcInfo->m_PriClass) {
  1648.         m_fDirty_COL_BASEPRIORITY = TRUE;
  1649.         m_PriClass = pParentProcInfo->m_PriClass;
  1650.     }
  1651.  
  1652.     if( m_SessionId != pParentProcInfo->m_SessionId )
  1653.     {
  1654.         m_fDirty_COL_SESSIONID = TRUE;
  1655.  
  1656.         m_SessionId = pParentProcInfo->m_SessionId;
  1657.     }
  1658.  
  1659.     if (FALSE == fUpdateOnly)
  1660.     {
  1661.         UINT uLen;
  1662.  
  1663.         //
  1664.         // Set the task's image name, thread ID, thread count,
  1665.         // htask, and parent CProcInfo which do not change over
  1666.         // time.
  1667.         //
  1668.  
  1669.         m_htaskWow = htask;
  1670.  
  1671.         m_fDirty_COL_PID = TRUE;
  1672.         m_fDirty_COL_IMAGENAME = TRUE;
  1673.         m_fDirty_COL_THREADCOUNT = TRUE;
  1674.         m_fDirty_COL_USERNAME = TRUE;
  1675.         m_fDirty_COL_SESSIONID = TRUE;
  1676.         m_UniqueProcessId = dwThreadId;
  1677.         m_ThreadCount = 1;
  1678.  
  1679.         //
  1680.         // We're only interested in the filename of the EXE
  1681.         // with the path stripped.
  1682.         //
  1683.  
  1684.         pchExe = strrchr(pszFilePath, '\\');
  1685.         if (NULL == pchExe) {
  1686.             pchExe = pszFilePath;
  1687.         }
  1688.         else
  1689.         {
  1690.             // skip backslash
  1691.             pchExe++;
  1692.         }
  1693.  
  1694.         uLen = static_cast<UINT>(strlen(pchExe));
  1695.  
  1696.         //
  1697.         // Indent the EXE name by two spaces
  1698.         // so WOW tasks look subordinate to
  1699.         // their ntvdm.exe
  1700.         //
  1701.         m_pszImageName = new TCHAR[uLen + 3];
  1702.         if (NULL == m_pszImageName)
  1703.         {
  1704.             return E_OUTOFMEMORY;
  1705.         }
  1706.  
  1707.         m_pszImageName[0] = m_pszImageName[1] = TEXT(' ');
  1708.  
  1709.         MultiByteToWideChar(
  1710.             CP_ACP,
  1711.             0,
  1712.             pchExe,
  1713.             uLen,
  1714.             &m_pszImageName[2],
  1715.             uLen
  1716.             );
  1717.         m_pszImageName[uLen + 2] = 0;
  1718.  
  1719.         //
  1720.         // WOW EXE filenames are always uppercase, so lowercase it.
  1721.         //
  1722.  
  1723.         CharLowerBuff(&m_pszImageName[2], uLen);
  1724.  
  1725.         m_pWowParentProcInfo = pParentProcInfo;
  1726.        
  1727.         if( g_fIsTSEnabled )
  1728.         {
  1729.             SetProcessUsername( LPFILETIME( &ullCreation ) );
  1730.         }      
  1731.     }
  1732.  
  1733.     return S_OK;
  1734. }
  1735.  
  1736.  
  1737. /*++ class CProcInfo::SetData
  1738.  
  1739. Class Description:
  1740.  
  1741.     Sets up a single CProcInfo object based on the data contained in a
  1742.     SYSTEM_PROCESS_INFORMATION block.
  1743.  
  1744.     If fUpdate is set, the imagename and icon fields are not processed,
  1745.     since they do not change throughout the lifetime of the process
  1746.  
  1747. Arguments:
  1748.  
  1749.     TotalTime - Total elapsed time, used as the denominator in calculations
  1750.                 for the process' CPU usage, etc
  1751.     pInfo     - The SYSTEM_PROCESS_INFORMATION block for this process
  1752.     uPassCount- Current passcount, used to timestamp the last update of
  1753.                 this objectg
  1754.     fUpdate   - See synopsis
  1755.  
  1756. Return Value:
  1757.  
  1758. Revision History:
  1759.  
  1760.       Nov-16-95 Davepl  Created
  1761.  
  1762. --*/
  1763.  
  1764.  
  1765. HRESULT CProcInfo::SetData(LARGE_INTEGER                TotalTime,
  1766.                            PSYSTEM_PROCESS_INFORMATION  pInfo,
  1767.                            LARGE_INTEGER                uPassCount,
  1768.                            CProcPage *                  pProcPage,
  1769.                            BOOL                         fUpdateOnly)
  1770. {
  1771.     HRESULT hr = S_OK;
  1772.     DWORD dwTemp;
  1773.     HANDLE hProcess;
  1774.  
  1775.     // Touch this CProcInfo to indicate the process is still alive
  1776.  
  1777.     m_uPassCount.QuadPart = uPassCount.QuadPart;
  1778.  
  1779.     // Calc this process's total time as the sum of its user and kernel time
  1780.  
  1781.     LARGE_INTEGER TimeDelta;
  1782.     LARGE_INTEGER Time;
  1783.  
  1784.     if (pInfo->UserTime.QuadPart + pInfo->KernelTime.QuadPart < m_CPUTime.QuadPart)
  1785.     {
  1786.         // ASSERT(0 && "Proc's cpu total usage went DOWN since last refresh. - Davepl x69731, 425-836-1939 (res)");
  1787.         Invalidate();
  1788.         return hr = E_FAIL;
  1789.     }
  1790.  
  1791.     Time.QuadPart = pInfo->UserTime.QuadPart +
  1792.                     pInfo->KernelTime.QuadPart;
  1793.  
  1794.     TimeDelta.QuadPart = Time.QuadPart - m_CPUTime.QuadPart;
  1795.  
  1796.     if (TimeDelta.QuadPart)
  1797.     {
  1798.         m_CPUTime.QuadPart = m_DisplayCPUTime.QuadPart = Time.QuadPart;
  1799.         m_fDirty_COL_CPUTIME = TRUE;
  1800.     }
  1801.  
  1802.     SetCPU( TimeDelta, TotalTime, FALSE );
  1803.  
  1804.     //
  1805.     // For each of the fields, we check to see if anything has changed, and if
  1806.     // so, we mark that particular column as having changed, and update the value.
  1807.     // This allows me to opimize which fields of the listview to repaint, since
  1808.     // repainting an entire listview column causes flicker and looks bad in
  1809.     // general
  1810.     //
  1811.  
  1812.     // Miscellaneous fields
  1813.  
  1814.     if (m_UniqueProcessId != PtrToUlong(pInfo->UniqueProcessId))
  1815.     {
  1816.         m_fDirty_COL_PID = TRUE;
  1817.         m_UniqueProcessId = PtrToUlong(pInfo->UniqueProcessId);
  1818.     }
  1819.  
  1820.     if( m_SessionId != pInfo->SessionId )
  1821.     {
  1822.         m_fDirty_COL_SESSIONID = TRUE;
  1823.         m_SessionId = pInfo->SessionId;
  1824.     }
  1825.  
  1826.     if (m_MemDiff != ((SSIZE_T)pInfo->WorkingSetSize / 1024) - (SSIZE_T)m_MemUsage )
  1827.     {
  1828.         m_fDirty_COL_MEMUSAGEDIFF = TRUE;
  1829.         m_MemDiff =  ((SSIZE_T)pInfo->WorkingSetSize / 1024) - (SSIZE_T)m_MemUsage;
  1830.     }
  1831.  
  1832.     if (m_MemPeak != (pInfo->PeakWorkingSetSize / 1024))
  1833.     {
  1834.         m_fDirty_COL_MEMPEAK = TRUE;
  1835.         m_MemPeak = (pInfo->PeakWorkingSetSize / 1024);
  1836.     }
  1837.  
  1838.     if (m_MemUsage != pInfo->WorkingSetSize / 1024)
  1839.     {
  1840.         m_fDirty_COL_MEMUSAGE = TRUE;
  1841.         m_MemUsage = (pInfo->WorkingSetSize / 1024);
  1842.     }
  1843.  
  1844.     if (m_PageFaultsDiff != ((LONG)(pInfo->PageFaultCount) - (LONG)m_PageFaults))
  1845.     {
  1846.         m_fDirty_COL_PAGEFAULTSDIFF = TRUE;
  1847.         m_PageFaultsDiff = ((LONG)(pInfo->PageFaultCount) - (LONG)m_PageFaults);
  1848.     }
  1849.  
  1850.     if (m_PageFaults != (pInfo->PageFaultCount))
  1851.     {
  1852.         m_fDirty_COL_PAGEFAULTS = TRUE;
  1853.         m_PageFaults = (pInfo->PageFaultCount);
  1854.     }
  1855.  
  1856.     if (m_CommitCharge != pInfo->PrivatePageCount / 1024)
  1857.     {
  1858.         m_fDirty_COL_COMMITCHARGE = TRUE;
  1859.         m_CommitCharge = pInfo->PrivatePageCount / 1024;
  1860.     }
  1861.  
  1862.     if (m_PagedPool != pInfo->QuotaPagedPoolUsage / 1024)
  1863.     {
  1864.         m_fDirty_COL_PAGEDPOOL = TRUE;
  1865.         m_PagedPool = pInfo->QuotaPagedPoolUsage / 1024;
  1866.     }
  1867.  
  1868.     if (m_NonPagedPool != pInfo->QuotaNonPagedPoolUsage / 1024)
  1869.     {
  1870.         m_fDirty_COL_NONPAGEDPOOL = TRUE;
  1871.         m_NonPagedPool = pInfo->QuotaNonPagedPoolUsage / 1024;
  1872.     }
  1873.  
  1874.     if (m_PriClass != pInfo->BasePriority)
  1875.     {
  1876.         m_fDirty_COL_BASEPRIORITY = TRUE;
  1877.         m_PriClass = pInfo->BasePriority;
  1878.     }
  1879.  
  1880.     if (m_HandleCount != pInfo->HandleCount)
  1881.     {
  1882.         m_fDirty_COL_HANDLECOUNT = TRUE;
  1883.         m_HandleCount = pInfo->HandleCount;
  1884.     }
  1885.  
  1886.     if (m_ThreadCount != pInfo->NumberOfThreads)
  1887.     {
  1888.         m_fDirty_COL_HANDLECOUNT = TRUE;
  1889.         m_ThreadCount = pInfo->NumberOfThreads;
  1890.     }
  1891.  
  1892.     if (m_IoReadOperCount != pInfo->ReadOperationCount.QuadPart)
  1893.     {
  1894.         m_fDirty_COL_READOPERCOUNT = TRUE;
  1895.         m_IoReadOperCount = pInfo->ReadOperationCount.QuadPart;
  1896.     }
  1897.  
  1898.     if (m_IoWriteOperCount != pInfo->WriteOperationCount.QuadPart)
  1899.     {
  1900.         m_fDirty_COL_WRITEOPERCOUNT = TRUE;
  1901.         m_IoWriteOperCount = pInfo->WriteOperationCount.QuadPart;
  1902.     }
  1903.  
  1904.     if (m_IoOtherOperCount != pInfo->OtherOperationCount.QuadPart)
  1905.     {
  1906.         m_fDirty_COL_OTHEROPERCOUNT = TRUE;
  1907.         m_IoOtherOperCount = pInfo->OtherOperationCount.QuadPart;
  1908.     }
  1909.  
  1910.     if (m_IoReadXferCount != pInfo->ReadTransferCount.QuadPart)
  1911.     {
  1912.         m_fDirty_COL_READXFERCOUNT = TRUE;
  1913.         m_IoReadXferCount = pInfo->ReadTransferCount.QuadPart;
  1914.     }
  1915.  
  1916.     if (m_IoWriteXferCount != pInfo->WriteTransferCount.QuadPart)
  1917.     {
  1918.         m_fDirty_COL_WRITEXFERCOUNT = TRUE;
  1919.         m_IoWriteXferCount = pInfo->WriteTransferCount.QuadPart;
  1920.     }
  1921.  
  1922.     if (m_IoOtherXferCount != pInfo->OtherTransferCount.QuadPart)
  1923.     {
  1924.         m_fDirty_COL_OTHERXFERCOUNT = TRUE;
  1925.         m_IoOtherXferCount = pInfo->OtherTransferCount.QuadPart;
  1926.     }
  1927.  
  1928.     hProcess = OpenProcess( PROCESS_QUERY_INFORMATION , FALSE, m_UniqueProcessId);
  1929.    
  1930.     if (hProcess && (m_USERObjectCount != (dwTemp = GetGuiResources(hProcess, GR_USEROBJECTS))))
  1931.     {
  1932.         m_fDirty_COL_USEROBJECTS = TRUE;
  1933.         m_USERObjectCount = dwTemp;
  1934.     }
  1935.  
  1936.     if (hProcess && (m_GDIObjectCount != (dwTemp = GetGuiResources(hProcess, GR_GDIOBJECTS))))
  1937.     {
  1938.         m_fDirty_COL_GDIOBJECTS = TRUE;
  1939.         m_GDIObjectCount = dwTemp;
  1940.     }
  1941.  
  1942.  
  1943.     if (hProcess)
  1944.         CloseHandle(hProcess);
  1945.  
  1946.     if (FALSE == fUpdateOnly)
  1947.     {
  1948.         //
  1949.         // Set the process' image name.  If its NULL it could be the "Idle Process" or simply
  1950.         // a process whose image name is unknown.  In both cases we load a string resource
  1951.         // with an appropriate replacement name.
  1952.         //
  1953.  
  1954.         m_fDirty_COL_IMAGENAME = TRUE;
  1955.  
  1956.         if (pInfo->ImageName.Buffer == NULL)
  1957.         {
  1958.             // No image name, so replace it with "Unknown"
  1959.  
  1960.             TCHAR szTmp[MAX_PATH];
  1961.             szTmp[0] = TEXT('\0');
  1962.             UINT  uLen = LoadString(g_hInstance, IDS_SYSPROC, szTmp, MAX_PATH);
  1963.  
  1964.  
  1965.             m_pszImageName = new TCHAR[uLen + 1];
  1966.             if (NULL == m_pszImageName)
  1967.             {
  1968.                     return hr = E_OUTOFMEMORY;
  1969.             }
  1970.  
  1971.             lstrcpy(m_pszImageName, szTmp);
  1972.         }
  1973.         else
  1974.         {
  1975.             //
  1976.             // We have a valid image name, so allocate enough space and then
  1977.             // make a copy of it
  1978.             //
  1979.             m_pszImageName = new TCHAR[(pInfo->ImageName.Length / sizeof(WCHAR))+ 1];
  1980.             if (NULL == m_pszImageName)
  1981.             {
  1982.                     return hr = E_OUTOFMEMORY;
  1983.             }
  1984.  
  1985.             lstrcpyn(m_pszImageName, pInfo->ImageName.Buffer, (pInfo->ImageName.Length / sizeof(WCHAR)) + 1);
  1986.             m_pszImageName[(pInfo->ImageName.Length / sizeof(WCHAR))] = TEXT('\0');
  1987.         }
  1988.  
  1989.         if( g_fIsTSEnabled )
  1990.         {
  1991.             SetProcessUsername(LPFILETIME(&(pInfo->CreateTime)));
  1992.         }
  1993.     }
  1994.  
  1995.     //
  1996.     // Check if this process is a WOW process.  There is some latency
  1997.     // between the time a WOW process is created and the time
  1998.     // the shared memory used by VDMEnumTaskWOWEx reflects the new
  1999.     // process and tasks.  However, once a process becomes a WOW
  2000.     // process, it is always a WOW process until it dies.
  2001.     //
  2002.  
  2003.     if (g_Options.m_fShow16Bit)
  2004.     {
  2005.         if ( m_fWowProcess ||
  2006.              ! m_fWowProcessTested)
  2007.         {
  2008. #if !defined (_WIN64)
  2009.  
  2010.             if ( ( m_pszImageName != NULL ) && ( ! _wcsicmp(m_pszImageName, TEXT("ntvdm.exe")) ) )
  2011.             {
  2012.  
  2013.                 WOWTASKCALLBACKPARMS WowTaskCallbackParms;
  2014.  
  2015.                 WowTaskCallbackParms.uPassCount = uPassCount;
  2016.                 WowTaskCallbackParms.pProcPage = pProcPage;
  2017.                 WowTaskCallbackParms.pParentProcInfo = this;
  2018.                 WowTaskCallbackParms.TotalTime.QuadPart = TotalTime.QuadPart;
  2019.                 WowTaskCallbackParms.TimeLeft.QuadPart = TimeDelta.QuadPart;
  2020.  
  2021.                 if (VDMEnumTaskWOWEx(m_UniqueProcessId,
  2022.                                      WowTaskCallback,
  2023.                                      (LPARAM) &WowTaskCallbackParms))
  2024.                 {
  2025.                     if ( ! m_fWowProcess )
  2026.                     {
  2027.                         m_fWowProcessTested =
  2028.                             m_fWowProcess = TRUE;
  2029.                     }
  2030.  
  2031.                     SetCPU( WowTaskCallbackParms.TimeLeft, TotalTime, TRUE );
  2032.                 }
  2033.                 else
  2034.                 {
  2035.                     //
  2036.                     // We avoid calling VDMEnumTaskWOWEx if the process has an
  2037.                     // execution time of more than 10 seconds and has not so
  2038.                     // far been seen as a WOW process.
  2039.                     //
  2040.  
  2041.                     if (GetCPUTime() > (10 * 10 * 1000 * 1000))
  2042.                     {
  2043.                         m_fWowProcessTested = TRUE;
  2044.                     }
  2045.                 }
  2046.             }
  2047.             else
  2048.             {
  2049.                 m_fWowProcessTested = TRUE;
  2050.             }
  2051. #else
  2052.             m_fWowProcessTested = TRUE;
  2053. #endif
  2054.         }
  2055.     }
  2056.  
  2057.  
  2058.     return S_OK;
  2059. }
  2060.  
  2061. //----------------------------------------------------------------
  2062. //
  2063. // No creation info
  2064. //
  2065. // Reviewed by alhen 9 - 3 - 98
  2066. //
  2067. HRESULT CProcInfo::SetProcessUsername(const FILETIME *pCreateTime)
  2068. {
  2069.     DWORD dwError = NO_ERROR;
  2070.    
  2071.     __try
  2072.     {
  2073.         // in case of wow tasks assign username same as its parent process's
  2074.  
  2075.         if( IsWowTask( ) )
  2076.         {
  2077.             if( m_pWowParentProcInfo->m_pszUserName != NULL )
  2078.             {
  2079.                 m_pszUserName = ( LPTSTR )new TCHAR[ lstrlen( m_pWowParentProcInfo->m_pszUserName ) + 1 ];
  2080.  
  2081.                 if( m_pszUserName != NULL )
  2082.                 {
  2083.                     lstrcpy( m_pszUserName , m_pWowParentProcInfo->m_pszUserName );
  2084.  
  2085.                     return S_OK;
  2086.                 }
  2087.                 else
  2088.                 {
  2089.                     return E_OUTOFMEMORY;
  2090.                 }
  2091.             }
  2092.             else
  2093.             {
  2094.  
  2095.                 return E_FAIL;
  2096.             }
  2097.         }
  2098.  
  2099.         if( m_UniqueProcessId == 0 )     // this is a system idle process.
  2100.         {
  2101.             const TCHAR *szIdleProcessOwner = TEXT( "SYSTEM" );
  2102.            
  2103.             m_pszUserName = ( LPTSTR )new TCHAR[ 7 ];
  2104.  
  2105.             if( m_pszUserName != NULL )
  2106.             {
  2107.                 lstrcpy(m_pszUserName, szIdleProcessOwner);
  2108.             }
  2109.         }
  2110.         else
  2111.         {
  2112.            
  2113.             PSID pUserSid = NULL;
  2114.  
  2115.             DWORD dwSize = 0;
  2116.  
  2117.             if( !WinStationGetProcessSid( NULL , GetRealPID( ) , *pCreateTime, ( PBYTE )pUserSid , &dwSize ) )
  2118.             {
  2119.                 pUserSid = ( PSID ) new BYTE[ dwSize ];
  2120.  
  2121.                 if( pUserSid != NULL )
  2122.                 {
  2123.                     if( WinStationGetProcessSid( NULL , GetRealPID( ) , *pCreateTime, ( PBYTE )pUserSid , &dwSize ) )
  2124.                     {
  2125.  
  2126.                         if( IsValidSid( pUserSid ) )
  2127.                         {
  2128.                             TCHAR szTmpName[MAX_PATH];
  2129.  
  2130.                             DWORD dwTmpNameSize = MAX_PATH;
  2131.  
  2132.                             CachedGetUserFromSid( pUserSid , szTmpName , &dwTmpNameSize );
  2133.  
  2134.                             m_pszUserName = ( LPTSTR )new TCHAR[ sizeof( szTmpName ) + 1 ];
  2135.  
  2136.                             if( m_pszUserName != NULL )
  2137.                             {
  2138.                                 lstrcpy(m_pszUserName, szTmpName);
  2139.                             }
  2140.                         }
  2141.                     }
  2142.  
  2143.                     delete [] pUserSid;
  2144.                 }
  2145.                 else
  2146.                 {
  2147.                     dwError = GetLastError();
  2148.                 }
  2149.  
  2150.                
  2151.             } // this would mean that a sid of size zero was returned
  2152.         }
  2153.  
  2154.  
  2155.     }
  2156.     __except (EXCEPTION_EXECUTE_HANDLER)
  2157.     {
  2158.         // dprintf(TEXT("exception occured: %d",), GetExceptionCode());
  2159.         dwError = GetExceptionCode();
  2160.     }
  2161.  
  2162.     return HRESULT_FROM_WIN32(dwError);
  2163.  
  2164. }
  2165.  
  2166.  
  2167. /*++ CProcPage::UpdateProcListview
  2168.  
  2169. Class Description:
  2170.  
  2171.     Walks the listview and checks to see if each line in the
  2172.     listview matches the corresponding entry in our process
  2173.     array.  Those which differe by PID are replaced, and those
  2174.     that need updating are updated.
  2175.  
  2176.     Items are also added and removed to/from the tail of the
  2177.     listview as required.
  2178.  
  2179. Arguments:
  2180.  
  2181. Return Value:
  2182.  
  2183.     HRESULT
  2184.  
  2185. Revision History:
  2186.  
  2187.       Nov-20-95 Davepl  Created
  2188.  
  2189. --*/
  2190.  
  2191. HRESULT CProcPage::UpdateProcListview ()
  2192. {
  2193.     HWND hListView = GetDlgItem(m_hPage, IDC_PROCLIST);
  2194.  
  2195.     // Stop repaints while we party on the listview
  2196.  
  2197.     SendMessage(hListView, WM_SETREDRAW, FALSE, 0);
  2198.  
  2199.     INT cListViewItems = ListView_GetItemCount(hListView);
  2200.     INT cProcArrayItems = m_pProcArray->GetSize();
  2201.  
  2202.     //
  2203.     // Walk the existing lines in the listview and replace/update
  2204.     // them as needed
  2205.     //
  2206.  
  2207.     CProcInfo * pSelected = GetSelectedProcess();
  2208.  
  2209.  
  2210.  
  2211.     for (int iCurrent = 0, iCurrListViewItem = 0;
  2212.           iCurrListViewItem < cListViewItems  && iCurrent < cProcArrayItems;
  2213.          iCurrent++) // for each process
  2214.     {
  2215.  
  2216.         CProcInfo * pProc = (CProcInfo *) m_pProcArray->GetAt(iCurrent);
  2217.        
  2218.         //get only processes we need to show
  2219.         if(g_fIsTSEnabled && !g_Options.m_bShowAllProcess && !pProc->OkToShowThisProcess() ) {
  2220.             continue;
  2221.         }
  2222.        
  2223.         LV_ITEM lvitem = { 0 };
  2224.         lvitem.mask = LVIF_PARAM | LVIF_TEXT | LVIF_STATE;
  2225.         lvitem.iItem = iCurrListViewItem;
  2226.  
  2227.         if (FALSE == ListView_GetItem(hListView, &lvitem))
  2228.         {
  2229.             SendMessage(hListView, WM_SETREDRAW, TRUE, 0);
  2230.             return E_FAIL;
  2231.         }
  2232.  
  2233.         CProcInfo * pTmp = (CProcInfo *) lvitem.lParam;
  2234.  
  2235.         if (pTmp != pProc)
  2236.         {
  2237.             // If the objects aren't the same, we need to replace this line
  2238.  
  2239.             lvitem.pszText = pProc->m_pszImageName;
  2240.             lvitem.lParam = (LPARAM) pProc;
  2241.  
  2242.             if (pProc == pSelected)
  2243.             {
  2244.                 lvitem.state |= LVIS_SELECTED | LVIS_FOCUSED;
  2245.             }
  2246.             else
  2247.             {
  2248.                 lvitem.state &= ~(LVIS_SELECTED | LVIS_FOCUSED);
  2249.             }
  2250.  
  2251.             lvitem.stateMask |= LVIS_SELECTED | LVIS_FOCUSED;
  2252.  
  2253.             ListView_SetItem(hListView, &lvitem);
  2254.             ListView_RedrawItems(hListView, iCurrListViewItem, iCurrListViewItem);
  2255.         }
  2256.         else if (pProc->m_fDirty)
  2257.         {
  2258.             // Same PID, but item needs updating
  2259.  
  2260.             ListView_RedrawItems(hListView, iCurrListViewItem, iCurrListViewItem);
  2261.             pProc->m_fDirty = 0;
  2262.         }
  2263.  
  2264.         iCurrListViewItem++;
  2265.     }
  2266.  
  2267.     //
  2268.     // We've either run out of listview items or run out of proc array
  2269.     // entries, so remove/add to the listview as appropriate
  2270.     //
  2271.  
  2272.     while (iCurrListViewItem < cListViewItems)
  2273.     {
  2274.         // Extra items in the listview (processes gone away), so remove them
  2275.  
  2276.         ListView_DeleteItem(hListView, iCurrListViewItem);
  2277.         cListViewItems--;
  2278.     }
  2279.  
  2280.     while (iCurrent < cProcArrayItems)
  2281.     {
  2282.         // Need to add new items to the listview (new processes appeared)
  2283.  
  2284.         CProcInfo * pProc = (CProcInfo *)m_pProcArray->GetAt(iCurrent++);
  2285.        
  2286.         //get only processes we need to show
  2287.         if(g_fIsTSEnabled && !g_Options.m_bShowAllProcess && !pProc->OkToShowThisProcess() ) {
  2288.             continue;
  2289.         }
  2290.  
  2291.         LV_ITEM lvitem  = { 0 };
  2292.         lvitem.mask     = LVIF_PARAM | LVIF_TEXT;
  2293.         lvitem.iItem    = iCurrListViewItem;
  2294.         lvitem.pszText  = pProc->m_pszImageName;
  2295.         lvitem.lParam   = (LPARAM) pProc;
  2296.  
  2297.         // The first item added (actually, every 0 to 1 count transition) gets
  2298.         // selected and focused
  2299.  
  2300.         if (iCurrListViewItem == 0)
  2301.         {
  2302.             lvitem.state = LVIS_SELECTED | LVIS_FOCUSED;
  2303.             lvitem.stateMask = lvitem.state;
  2304.             lvitem.mask |= LVIF_STATE;
  2305.         }
  2306.    
  2307.         ListView_InsertItem(hListView, &lvitem);
  2308.         iCurrListViewItem++;
  2309.     }
  2310.  
  2311.     ASSERT(iCurrListViewItem == ListView_GetItemCount(hListView));
  2312.     ASSERT(iCurrent == cProcArrayItems);
  2313.  
  2314.     // Let the listview paint again
  2315.  
  2316.     SendMessage(hListView, WM_SETREDRAW, TRUE, 0);
  2317.     return S_OK;
  2318. }
  2319.  
  2320.  
  2321. /*++ class CProcPage::UpdateProcInfoArray
  2322.  
  2323. Class Description:
  2324.  
  2325.     Retrieves the list of process info blocks from the system,
  2326.     and runs through our array of CProcInfo items.  Items which
  2327.     already exist are updated, and those that do not are added.
  2328.     At the end, any process which has not been touched by this
  2329.     itteration of the function are considered to have completed
  2330.     and are removed from the array.
  2331.  
  2332. Arguments:
  2333.  
  2334. Return Value:
  2335.  
  2336. Revision History:
  2337.  
  2338.       Nov-16-95 Davepl  Created
  2339.  
  2340. --*/
  2341.  
  2342. // See comments near the usage of this table below for info on why it exists
  2343.  
  2344. static struct
  2345. {
  2346.     size_t cbOffset;
  2347.     UINT   idString;
  2348. }
  2349. g_OffsetMap[] =
  2350. {
  2351.     { FIELD_OFFSET(CSysInfo, m_cHandles),         IDC_TOTAL_HANDLES   },
  2352.     { FIELD_OFFSET(CSysInfo, m_cThreads),         IDC_TOTAL_THREADS   },
  2353.     { FIELD_OFFSET(CSysInfo, m_cProcesses),       IDC_TOTAL_PROCESSES },
  2354.     { FIELD_OFFSET(CSysInfo, m_dwPhysicalMemory), IDC_TOTAL_PHYSICAL  },
  2355.     { FIELD_OFFSET(CSysInfo, m_dwPhysAvail),      IDC_AVAIL_PHYSICAL  },
  2356.     { FIELD_OFFSET(CSysInfo, m_dwFileCache),      IDC_FILE_CACHE      },
  2357.     { FIELD_OFFSET(CSysInfo, m_dwCommitTotal),    IDC_COMMIT_TOTAL    },
  2358.     { FIELD_OFFSET(CSysInfo, m_dwCommitLimit),    IDC_COMMIT_LIMIT    },
  2359.     { FIELD_OFFSET(CSysInfo, m_dwCommitPeak),     IDC_COMMIT_PEAK     },
  2360.     { FIELD_OFFSET(CSysInfo, m_dwKernelPaged),    IDC_KERNEL_PAGED    },
  2361.     { FIELD_OFFSET(CSysInfo, m_dwKernelNP),       IDC_KERNEL_NONPAGED },
  2362.     { FIELD_OFFSET(CSysInfo, m_dwKernelTotal),    IDC_KERNEL_TOTAL    },
  2363. };
  2364.  
  2365. HRESULT CProcPage::UpdateProcInfoArray()
  2366. {
  2367.     HRESULT  hr;
  2368.     INT      i;
  2369.     INT      iField;
  2370.     ULONG    cbOffset   = 0;
  2371.     CSysInfo SysInfoTemp;
  2372.     NTSTATUS Status;
  2373.  
  2374.     SYSTEM_BASIC_INFORMATION        BasicInfo;
  2375.     PSYSTEM_PROCESS_INFORMATION     pCurrent;
  2376.     SYSTEM_PERFORMANCE_INFORMATION  PerfInfo;
  2377.     SYSTEM_FILECACHE_INFORMATION    FileCache;
  2378.  
  2379.     LARGE_INTEGER TotalTime = {0,0};
  2380.     LARGE_INTEGER LastTotalTime = {0,0};
  2381.  
  2382.     //
  2383.     // Pass-count for this function.  It ain't thread-safe, of course, but I
  2384.     // can't imagine a scenario where we'll have mode than one thread running
  2385.     // through this (the app is currently single threaded anyway).  If we
  2386.     // overflow LARGE_INTEGER updates, I'll already be long gone, so don't bug me.
  2387.     //
  2388.  
  2389.     static LARGE_INTEGER uPassCount = {0,0};
  2390.  
  2391.     //
  2392.     // Get some non-process specific info, like memory status
  2393.     //
  2394.  
  2395.     Status = NtQuerySystemInformation(
  2396.                 SystemBasicInformation,
  2397.                 &BasicInfo,
  2398.                 sizeof(BasicInfo),
  2399.                 NULL
  2400.              );
  2401.  
  2402.     if (!NT_SUCCESS(Status))
  2403.     {
  2404.         return E_FAIL;
  2405.     }
  2406.  
  2407.     SysInfoTemp.m_dwPhysicalMemory = BasicInfo.NumberOfPhysicalPages *
  2408.                                           (BasicInfo.PageSize / 1024);
  2409.  
  2410.     Status = NtQuerySystemInformation(
  2411.                 SystemPerformanceInformation,
  2412.                 &PerfInfo,
  2413.                 sizeof(PerfInfo),
  2414.                 NULL
  2415.                 );
  2416.  
  2417.     if (!NT_SUCCESS(Status))
  2418.     {
  2419.         return E_FAIL;
  2420.     }
  2421.  
  2422.     SysInfoTemp.m_dwPhysAvail   = PerfInfo.AvailablePages    * (g_BasicInfo.PageSize / 1024);
  2423.     SysInfoTemp.m_dwCommitTotal = PerfInfo.CommittedPages    * (g_BasicInfo.PageSize / 1024);
  2424.     SysInfoTemp.m_dwCommitLimit = PerfInfo.CommitLimit       * (g_BasicInfo.PageSize / 1024);
  2425.     SysInfoTemp.m_dwCommitPeak  = PerfInfo.PeakCommitment    * (g_BasicInfo.PageSize / 1024);
  2426.     SysInfoTemp.m_dwKernelPaged = PerfInfo.PagedPoolPages    * (g_BasicInfo.PageSize / 1024);
  2427.     SysInfoTemp.m_dwKernelNP    = PerfInfo.NonPagedPoolPages * (g_BasicInfo.PageSize / 1024);
  2428.     SysInfoTemp.m_dwKernelTotal = SysInfoTemp.m_dwKernelNP + SysInfoTemp.m_dwKernelPaged;
  2429.  
  2430.     g_MEMMax = SysInfoTemp.m_dwCommitLimit;
  2431.  
  2432.     Status = NtQuerySystemInformation(
  2433.                 SystemFileCacheInformation,
  2434.                 &FileCache,
  2435.                 sizeof(FileCache),
  2436.                 NULL
  2437.                 );
  2438.  
  2439.     if (!NT_SUCCESS(Status))
  2440.     {
  2441.         return E_FAIL;
  2442.     }
  2443.  
  2444.     //
  2445.     // The DWORD cast below must be fixed as this value can be greater than
  2446.     // 32 bits.
  2447.     //
  2448.  
  2449.     SysInfoTemp.m_dwFileCache = (DWORD)(FileCache.CurrentSizeIncludingTransitionInPages * (g_BasicInfo.PageSize / 1024));
  2450.  
  2451.     //
  2452.     // Read the process info structures into the flat buffer
  2453.     //
  2454.  
  2455.     hr = GetProcessInfo();
  2456.     if (FAILED(hr))
  2457.     {
  2458.         goto done;
  2459.     }
  2460.  
  2461.     //
  2462.     // First walk all of the process info blocks and sum their times, so that we can
  2463.     // calculate a CPU usage ratio (%) for each individual process
  2464.     //
  2465.  
  2466.     cbOffset = 0;
  2467.     do
  2468.     {
  2469.         CProcInfo * pOldProcInfo;
  2470.         pCurrent = (PSYSTEM_PROCESS_INFORMATION)&((LPBYTE)m_pvBuffer)[cbOffset];
  2471.         ASSERT( FALSE == IsBadReadPtr((LPVOID)pCurrent, sizeof(PSYSTEM_PROCESS_INFORMATION)));
  2472.  
  2473.         if (pCurrent->UniqueProcessId == NULL && pCurrent->NumberOfThreads == 0)
  2474.         {
  2475.             // Zombie process, just skip it
  2476.  
  2477.             goto next;
  2478.         }
  2479.  
  2480.         pOldProcInfo = FindProcInArrayByPID(m_pProcArray, PtrToUlong(pCurrent->UniqueProcessId));
  2481.         if (pOldProcInfo)
  2482.         {
  2483.             if (pOldProcInfo->GetCPUTime() > pCurrent->KernelTime.QuadPart + pCurrent->UserTime.QuadPart)
  2484.             {
  2485.                 // If CPU has gone DOWN, its because the PID has been reused, so invalidate this
  2486.                 // CProcInfo such that it is removed and the new one added
  2487.  
  2488.                 pOldProcInfo->Invalidate();
  2489. //                dprintf(TEXT("Invalidating %08x\n"), pOldProcInfo);
  2490.                 goto next;
  2491.             }
  2492.             else if (pCurrent->UniqueProcessId == 0 &&
  2493.                      pCurrent->KernelTime.QuadPart == 0 &&
  2494.                      pCurrent->UserTime.QuadPart == 0)
  2495.             {
  2496.                 dprintf(TEXT("System idle process has 0 times\n"));
  2497.                 pOldProcInfo->Invalidate();
  2498.                 goto next;
  2499.             }
  2500.             else
  2501.             {
  2502.                 LastTotalTime.QuadPart += pOldProcInfo->GetCPUTime();
  2503.             }
  2504.         }
  2505.  
  2506.         TotalTime.QuadPart += pCurrent->KernelTime.QuadPart + pCurrent->UserTime.QuadPart;
  2507.    
  2508.         SysInfoTemp.m_cHandles += pCurrent->HandleCount;
  2509.         SysInfoTemp.m_cThreads += pCurrent->NumberOfThreads;
  2510.         SysInfoTemp.m_cProcesses++;
  2511.  
  2512.         next:
  2513.  
  2514.         cbOffset += pCurrent->NextEntryOffset;
  2515.  
  2516.         // if current session id is not set yet, set it now
  2517.         //
  2518.         // REVIEWER:  Previous dev didnot document this, but taskmgr session id
  2519.         // is cached so that when the user deselects "show all the processes", only
  2520.         // processes with session id's equal to taskmgr session id are listed
  2521.         // --alhen
  2522.  
  2523.         if( ( GetCurrentSessionID() == -1 ) && ( PtrToUlong(pCurrent->UniqueProcessId) == GetCurrentProcessId( ) ) )
  2524.         {
  2525.             SetCurrentSessionID( ( DWORD )pCurrent->SessionId );
  2526.         }
  2527.  
  2528.     } while (pCurrent->NextEntryOffset);
  2529.  
  2530.  
  2531.     LARGE_INTEGER TimeDelta;
  2532.     TimeDelta.QuadPart = TotalTime.QuadPart - LastTotalTime.QuadPart;
  2533.  
  2534.     ASSERT(TimeDelta.QuadPart >= 0);
  2535.  
  2536.     // Update the global count (visible to the status bar)
  2537.  
  2538.     g_cProcesses = SysInfoTemp.m_cProcesses;
  2539.  
  2540.     //
  2541.     // We have a number of text fields in the dialog that are based on counts we accumulate
  2542.     // here.  Rather than painting all of the time, we only change the ones whose values have
  2543.     // really changed.  We have a table up above of the offsets into the CSysInfo object
  2544.     // where these values live (the same offset in the real g_SysInfo object and the temp
  2545.     // working copy, of course), and what control ID they correspond to.  We then loop through
  2546.     // and compare each real one to the temp working copy, updating as needed.  Hard to
  2547.     // read, but smaller than a dozen if() statements.
  2548.     //
  2549.  
  2550.     extern CPage * g_pPages[];
  2551.  
  2552.     if (g_pPages[PERF_PAGE])
  2553.     {
  2554.         for (iField = 0; iField < ARRAYSIZE(g_OffsetMap); iField++)
  2555.         {
  2556.             DWORD * pdwRealCopy = (DWORD *)(((LPBYTE)&m_SysInfo)   + g_OffsetMap[iField].cbOffset);
  2557.             DWORD * pdwTempCopy = (DWORD *)(((LPBYTE)&SysInfoTemp) + g_OffsetMap[iField].cbOffset);
  2558.  
  2559.             *pdwRealCopy = *pdwTempCopy;
  2560.  
  2561.             TCHAR szText[32];
  2562.             wsprintf(szText, TEXT("%d"), *pdwRealCopy);
  2563.  
  2564.             HWND hPage = g_pPages[PERF_PAGE]->GetPageWindow();
  2565.            
  2566.             // Updates can come through before page is created, so verify
  2567.             // that it exists before we party on its children
  2568.  
  2569.             if (hPage)
  2570.             {
  2571.                 SetWindowText(GetDlgItem(hPage, g_OffsetMap[iField].idString), szText);
  2572.             }
  2573.         }
  2574.     }
  2575.  
  2576.     //
  2577.     // Now walk the process info blocks again and refresh the CProcInfo array for each
  2578.     // individual process
  2579.     //
  2580.  
  2581.     cbOffset = 0;
  2582.     do
  2583.     {
  2584.        
  2585.         //
  2586.         // Grab a PROCESS_INFORMATION struct from the buffer
  2587.         //
  2588.  
  2589.         pCurrent = (PSYSTEM_PROCESS_INFORMATION)&((LPBYTE)m_pvBuffer)[cbOffset];
  2590.         ASSERT( FALSE == IsBadReadPtr((LPVOID)pCurrent, sizeof(PSYSTEM_PROCESS_INFORMATION)));
  2591.  
  2592.         if (pCurrent->UniqueProcessId == NULL && pCurrent->NumberOfThreads == 0)
  2593.         {
  2594.             // Zombie process, just skip it
  2595.  
  2596.             goto nextprocinfo;
  2597.         }
  2598.  
  2599.         //
  2600.         // This is really ugly, but... NtQuerySystemInfo has too much latency, and if you
  2601.         // change a process' priority, you don't see it reflected right away.  And, if you
  2602.         // don't have autoupdate on, you never do.  So, we use GetPriorityClass() to get
  2603.         // the value instead.  This means BasePriority is now the pri class, not the pri value.
  2604.         //
  2605.  
  2606.         if (pCurrent->UniqueProcessId)
  2607.         {
  2608.             HANDLE hProcess;
  2609.             hProcess = OpenProcess( PROCESS_QUERY_INFORMATION, FALSE, PtrToUlong(pCurrent->UniqueProcessId) );
  2610.             DWORD dwPriClass;
  2611.             dwPriClass = 0;
  2612.  
  2613.             if (hProcess)
  2614.             {
  2615.                 dwPriClass = GetPriorityClass(hProcess);
  2616.                 if (dwPriClass)
  2617.                 {
  2618.                     pCurrent->BasePriority = dwPriClass;
  2619.                 }
  2620.                 CloseHandle( hProcess );
  2621.             }
  2622.  
  2623.             if (NULL == hProcess || dwPriClass == 0)
  2624.             {
  2625.                 // We're not allowed to open this process, so convert what NtQuerySystemInfo
  2626.                 // gave us into a priority class... its the next best thing
  2627.  
  2628.                 if (pCurrent->BasePriority <= 4)
  2629.                 {
  2630.                     pCurrent->BasePriority = IDLE_PRIORITY_CLASS;
  2631.                 }
  2632.                 else if (pCurrent->BasePriority <= 6)
  2633.                 {
  2634.                     pCurrent->BasePriority = BELOW_NORMAL_PRIORITY_CLASS;
  2635.                 }
  2636.                 else if (pCurrent->BasePriority <= 8)
  2637.                 {
  2638.                     pCurrent->BasePriority = NORMAL_PRIORITY_CLASS;
  2639.                 }
  2640.                 else if (pCurrent->BasePriority <=  10)
  2641.                 {
  2642.                     pCurrent->BasePriority = ABOVE_NORMAL_PRIORITY_CLASS;
  2643.                 }
  2644.                 else if (pCurrent->BasePriority <=  13)
  2645.                 {
  2646.                     pCurrent->BasePriority = HIGH_PRIORITY_CLASS;
  2647.                 }
  2648.                 else
  2649.                 {
  2650.                     pCurrent->BasePriority = REALTIME_PRIORITY_CLASS;
  2651.                 }
  2652.             }
  2653.         }
  2654.  
  2655.         //
  2656.         // Try to find an existing CProcInfo instance which corresponds to this process
  2657.         //
  2658.  
  2659.         CProcInfo * pProcInfo;
  2660.         pProcInfo = FindProcInArrayByPID(m_pProcArray, PtrToUlong(pCurrent->UniqueProcessId));
  2661.  
  2662.         if (NULL == pProcInfo)
  2663.         {
  2664.             //
  2665.             // We don't already have this process in our array, so create a new one
  2666.             // and add it to the array
  2667.             //
  2668.  
  2669.             pProcInfo = new CProcInfo;
  2670.             if (NULL == pProcInfo)
  2671.             {
  2672.                 hr = E_OUTOFMEMORY;
  2673.                 goto done;
  2674.             }
  2675.  
  2676.             hr = pProcInfo->SetData(TimeDelta,
  2677.                                     pCurrent,
  2678.                                     uPassCount,
  2679.                                     this,
  2680.                                     FALSE);
  2681.  
  2682.             if (FAILED(hr) || FALSE == m_pProcArray->Add(pProcInfo))
  2683.             {
  2684.                 delete pProcInfo;
  2685.                 goto done;
  2686.             }
  2687.         }
  2688.         else
  2689.         {
  2690.             //
  2691.             // This process already existed in our array, so update its info
  2692.             //
  2693.  
  2694.             hr = pProcInfo->SetData(TimeDelta,
  2695.                                     pCurrent,
  2696.                                     uPassCount,
  2697.                                     this,
  2698.                                     TRUE);
  2699.             if (FAILED(hr))
  2700.             {
  2701.                 goto done;
  2702.             }
  2703.         }
  2704.  
  2705.         nextprocinfo:
  2706.  
  2707.         cbOffset += pCurrent->NextEntryOffset;
  2708.  
  2709.     } while (pCurrent->NextEntryOffset);
  2710.  
  2711.     //
  2712.     // Run through the CProcInfo array and remove anyone that hasn't been touched
  2713.     // by this pass through this function (which indicates the process is no
  2714.     // longer alive)
  2715.     //
  2716.  
  2717.     i = 0;
  2718.     while (i < m_pProcArray->GetSize())
  2719.     {
  2720.         CProcInfo * pProcInfo = (CProcInfo *)(m_pProcArray->GetAt(i));
  2721.         ASSERT(pProcInfo);
  2722.  
  2723.         //
  2724.         // If passcount doesn't match, delete the CProcInfo instance and remove
  2725.         // its pointer from the array.  Note that we _don't_ increment the index
  2726.         // if we remove an element, since the next element would now live at
  2727.         // the current index after the deletion
  2728.         //
  2729.  
  2730.         if (pProcInfo->m_uPassCount.QuadPart != uPassCount.QuadPart)
  2731.         {
  2732.             delete pProcInfo;
  2733.             m_pProcArray->RemoveAt(i, 1);
  2734.         }
  2735.         else
  2736.         {
  2737.             i++;
  2738.         }
  2739.     }
  2740.  
  2741. done:
  2742.  
  2743.     ResortArray(&m_pProcArray);
  2744.     uPassCount.QuadPart++;
  2745.  
  2746.     return hr;
  2747. }
  2748.  
  2749. /*++ CPerfPage::SizeProcPage
  2750.  
  2751. Routine Description:
  2752.  
  2753.     Sizes its children based on the size of the
  2754.     tab control on which it appears.  
  2755.  
  2756. Arguments:
  2757.  
  2758. Return Value:
  2759.  
  2760. Revision History:
  2761.  
  2762.       Nov-16-95 Davepl  Created
  2763.  
  2764. --*/
  2765.  
  2766. void CProcPage::SizeProcPage()
  2767. {
  2768.     // Get the coords of the outer dialog
  2769.  
  2770.     RECT rcParent;
  2771.     GetClientRect(m_hPage, &rcParent);
  2772.  
  2773.     HDWP hdwp = BeginDeferWindowPos(10);
  2774.     if (!hdwp)
  2775.         return;
  2776.  
  2777.     // Calc the deltas in the x and y positions that we need to
  2778.     // move each of the child controls
  2779.  
  2780.     RECT rcTerminate;
  2781.     HWND hwndTerminate = GetDlgItem(m_hPage, IDC_TERMINATE);
  2782.     GetWindowRect(hwndTerminate, &rcTerminate);
  2783.     MapWindowPoints(HWND_DESKTOP, m_hPage, (LPPOINT) &rcTerminate, 2);
  2784.  
  2785.     INT dx = ((rcParent.right - g_DefSpacing * 2) - rcTerminate.right);
  2786.     INT dy = ((rcParent.bottom - g_DefSpacing * 2) - rcTerminate.bottom);
  2787.  
  2788.     // Move the EndProcess button
  2789.  
  2790.     DeferWindowPos(hdwp, hwndTerminate, NULL,
  2791.                      rcTerminate.left + dx,
  2792.                      rcTerminate.top + dy,
  2793.                      0, 0,
  2794.                      SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
  2795.  
  2796.     // _HYDRA_
  2797.     HWND hwndShowall = GetDlgItem(m_hPage, IDC_SHOWALL);
  2798.  
  2799.     if( IsWindow( hwndShowall ) )
  2800.     {
  2801.         if( g_fIsTSEnabled )
  2802.         {
  2803.             RECT rcShowall;
  2804.            
  2805.             GetWindowRect(hwndShowall, &rcShowall);
  2806.            
  2807.             MapWindowPoints(HWND_DESKTOP, m_hPage, (LPPOINT) &rcShowall, 2);
  2808.            
  2809.             DeferWindowPos(hdwp, hwndShowall, NULL, rcShowall.left, rcShowall.top + dy, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
  2810.         }
  2811.         else
  2812.         {
  2813.             // this window must be hidden.
  2814.        
  2815.             ShowWindow(hwndShowall, SW_HIDE);
  2816.         }
  2817.     }
  2818.    
  2819.     // _HYDRA_
  2820.  
  2821.     // Size the listbox
  2822.  
  2823.     HWND hwndListbox = GetDlgItem(m_hPage, IDC_PROCLIST);
  2824.     RECT rcListbox;
  2825.     GetWindowRect(hwndListbox, &rcListbox);
  2826.     MapWindowPoints(HWND_DESKTOP, m_hPage, (LPPOINT) &rcListbox, 2);
  2827.     DeferWindowPos(hdwp, hwndListbox, NULL,
  2828.                         0, 0,
  2829.                         rcTerminate.right - rcListbox.left + dx,
  2830.                         rcTerminate.top - rcListbox.top + dy - g_DefSpacing,
  2831.                         SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  2832.  
  2833.     EndDeferWindowPos(hdwp);
  2834. }
  2835.  
  2836. /*++ CProcPage::HandleTaskManNotify
  2837.  
  2838. Routine Description:
  2839.  
  2840.     Processes WM_NOTIFY messages received by the procpage dialog
  2841.    
  2842. Arguments:
  2843.  
  2844.     hWnd    - Control that generated the WM_NOTIFY
  2845.     pnmhdr  - Ptr to the NMHDR notification stucture
  2846.  
  2847. Return Value:
  2848.  
  2849.     BOOL "did we handle it" code
  2850.  
  2851. Revision History:
  2852.  
  2853.       Nov-20-95 Davepl  Created
  2854.  
  2855. --*/
  2856. INT CProcPage::HandleProcPageNotify(HWND hWnd, LPNMHDR pnmhdr)
  2857. {
  2858.     switch(pnmhdr->code)
  2859.     {
  2860.         case LVN_COLUMNCLICK:
  2861.         {
  2862.             // User clicked a header control, so set the sort column.  If its the
  2863.             // same as the current sort column, just invert the sort direction in
  2864.             // the column.  Then resort the task array
  2865.  
  2866.             const NM_LISTVIEW * pnmv = (const NM_LISTVIEW *) pnmhdr;
  2867.            
  2868.             if (g_iProcSortColumnID == g_Options.m_ActiveProcCol[pnmv->iSubItem])
  2869.             {
  2870.                 g_iProcSortDirection  *= -1;
  2871.             }
  2872.             else
  2873.             {
  2874.                 g_iProcSortColumnID = g_Options.m_ActiveProcCol[pnmv->iSubItem];
  2875.                 g_iProcSortDirection  = -1;
  2876.             }
  2877.             ResortArray(&m_pProcArray);
  2878.             TimerEvent();
  2879.             break;
  2880.         }
  2881.  
  2882.         case LVN_ITEMCHANGED:
  2883.         {
  2884.             const NM_LISTVIEW * pnmv = (const NM_LISTVIEW *) pnmhdr;
  2885.             if (pnmv->uChanged & LVIF_STATE)
  2886.             {
  2887.                 UINT cSelected = ListView_GetSelectedCount(GetDlgItem(m_hPage, IDC_PROCLIST));
  2888.                 EnableWindow(GetDlgItem(m_hPage, IDC_TERMINATE), cSelected ? TRUE : FALSE);  
  2889.             }
  2890.             break;
  2891.         }
  2892.  
  2893.         case LVN_GETDISPINFO:
  2894.         {
  2895.             LV_ITEM * plvitem = &(((LV_DISPINFO *) pnmhdr)->item);
  2896.            
  2897.             // Listview needs a text string
  2898.  
  2899.             if (plvitem->mask & LVIF_TEXT)
  2900.             {
  2901.                 COLUMNID columnid = (COLUMNID) g_Options.m_ActiveProcCol[plvitem->iSubItem];
  2902.                 const CProcInfo  * pProcInfo   = (const CProcInfo *)   plvitem->lParam;
  2903.  
  2904.                 //
  2905.                 // Most columns are blank for WOW tasks.
  2906.                 //
  2907.  
  2908.                 if (pProcInfo->IsWowTask() &&
  2909.                     columnid != COL_IMAGENAME &&
  2910.                     columnid != COL_BASEPRIORITY &&
  2911.                     columnid != COL_THREADCOUNT &&
  2912.                     columnid != COL_CPUTIME &&
  2913.                     columnid != COL_USERNAME &&
  2914.                     columnid != COL_SESSIONID &&
  2915.                     columnid != COL_CPU) {
  2916.  
  2917.                     plvitem->pszText[0] = 0;
  2918.                     goto done;
  2919.                 }
  2920.  
  2921.                 switch(columnid)
  2922.                 {
  2923.                     case COL_PID:
  2924.                         wsprintf(plvitem->pszText, TEXT("%d"), (ULONG) (pProcInfo->m_UniqueProcessId));
  2925.                         break;
  2926.  
  2927.                     case COL_USERNAME:
  2928.  
  2929.                         if( pProcInfo->m_pszUserName )
  2930.                         {
  2931.                             lstrcpyn(plvitem->pszText, pProcInfo->m_pszUserName, plvitem->cchTextMax);
  2932.  
  2933.                         }
  2934.                        
  2935.                         break;
  2936.  
  2937.                     case COL_SESSIONID:
  2938.  
  2939.                         wsprintf( plvitem->pszText, TEXT( "%d" ) , pProcInfo->m_SessionId );
  2940.  
  2941.                         break;
  2942.  
  2943. //#endif
  2944.                     case COL_CPU:
  2945.                         wsprintf(plvitem->pszText, TEXT("%02d %"), pProcInfo->m_DisplayCPU);
  2946.                         break;
  2947.  
  2948.                     case COL_IMAGENAME:
  2949.                         lstrcpyn(plvitem->pszText, pProcInfo->m_pszImageName, plvitem->cchTextMax);
  2950.                         //plvitem->mask |= LVIF_DI_SETITEM;
  2951.                         break;
  2952.                    
  2953.                     case COL_CPUTIME:
  2954.                     {
  2955.                         TIME_FIELDS TimeOut;
  2956.                        
  2957.                         RtlTimeToElapsedTimeFields ( (LARGE_INTEGER *)&(pProcInfo->m_DisplayCPUTime), &TimeOut);
  2958.                         TimeOut.Hour = static_cast<CSHORT>(TimeOut.Hour + static_cast<SHORT>(TimeOut.Day * 24));
  2959.                        
  2960.                         wsprintf(plvitem->pszText,
  2961.                                  TEXT("%2d%s%02d%s%02d"),
  2962.                                  TimeOut.Hour,
  2963.                                  g_szTimeSep,
  2964.                                  TimeOut.Minute,
  2965.                                  g_szTimeSep,
  2966.                                  TimeOut.Second);
  2967.                         break;
  2968.                     }
  2969.                     case COL_MEMUSAGE:
  2970.                         Int64ToCommaSepKString(LONGLONG(pProcInfo->m_MemUsage), plvitem->pszText, plvitem->cchTextMax);
  2971.                         break;
  2972.  
  2973.                     case COL_MEMUSAGEDIFF:
  2974.                         Int64ToCommaSepKString(LONGLONG(pProcInfo->m_MemDiff), plvitem->pszText, plvitem->cchTextMax);
  2975.                         break;
  2976.  
  2977.                     case COL_MEMPEAK:
  2978.                         Int64ToCommaSepKString(LONGLONG(pProcInfo->m_MemPeak), plvitem->pszText, plvitem->cchTextMax);
  2979.                         break;
  2980.  
  2981.                     case COL_PAGEFAULTS:
  2982.                         Int64ToCommaSepString(LONGLONG(pProcInfo->m_PageFaults), plvitem->pszText, plvitem->cchTextMax);
  2983.                         break;
  2984.  
  2985.                     case COL_PAGEFAULTSDIFF:
  2986.                         Int64ToCommaSepString(LONGLONG(pProcInfo->m_PageFaultsDiff), plvitem->pszText, plvitem->cchTextMax);
  2987.                         break;
  2988.  
  2989.                     case COL_COMMITCHARGE:
  2990.                         Int64ToCommaSepKString(LONGLONG(pProcInfo->m_CommitCharge), plvitem->pszText, plvitem->cchTextMax);
  2991.                         break;
  2992.  
  2993.                     case COL_PAGEDPOOL:
  2994.                         Int64ToCommaSepKString(LONGLONG(pProcInfo->m_PagedPool), plvitem->pszText, plvitem->cchTextMax);
  2995.                         break;
  2996.                        
  2997.                     case COL_NONPAGEDPOOL:
  2998.                         Int64ToCommaSepKString(LONGLONG(pProcInfo->m_NonPagedPool), plvitem->pszText, plvitem->cchTextMax);
  2999.                         break;
  3000.  
  3001.                     case COL_BASEPRIORITY:
  3002.                     {
  3003.                         LPCTSTR pszClass = NULL;
  3004.  
  3005.                         switch(pProcInfo->m_PriClass)
  3006.                         {
  3007.                             case REALTIME_PRIORITY_CLASS:
  3008.                                 pszClass = g_szRealtime;
  3009.                                 break;
  3010.  
  3011.                             case HIGH_PRIORITY_CLASS:
  3012.                                 pszClass = g_szHigh;
  3013.                                 break;
  3014.  
  3015.                             case ABOVE_NORMAL_PRIORITY_CLASS:
  3016.                                 pszClass = g_szAboveNormal;
  3017.                                 break;
  3018.  
  3019.                             case NORMAL_PRIORITY_CLASS:
  3020.                                 pszClass = g_szNormal;
  3021.                                 break;
  3022.  
  3023.                             case BELOW_NORMAL_PRIORITY_CLASS:
  3024.                                 pszClass = g_szBelowNormal;
  3025.                                 break;
  3026.  
  3027.                             case IDLE_PRIORITY_CLASS:
  3028.                                 pszClass = g_szLow;
  3029.                                 break;
  3030.  
  3031.                             default:
  3032.                                 pszClass = g_szUnknown;
  3033.                                 break;
  3034.                         }
  3035.  
  3036.                         lstrcpyn(plvitem->pszText, pszClass, plvitem->cchTextMax);
  3037.                         break;
  3038.                     }
  3039.  
  3040.                     case COL_HANDLECOUNT:
  3041.                         Int64ToCommaSepString(LONGLONG(pProcInfo->m_HandleCount), plvitem->pszText, plvitem->cchTextMax);
  3042.                         break;
  3043.  
  3044.                     case COL_THREADCOUNT:
  3045.                         Int64ToCommaSepString(LONGLONG(pProcInfo->m_ThreadCount), plvitem->pszText, plvitem->cchTextMax);
  3046.                         break;
  3047.  
  3048.                     case COL_USEROBJECTS:
  3049.                         Int64ToCommaSepString(LONGLONG(pProcInfo->m_USERObjectCount), plvitem->pszText, plvitem->cchTextMax);
  3050.                         break;
  3051.  
  3052.                     case COL_GDIOBJECTS:
  3053.                         Int64ToCommaSepString(LONGLONG(pProcInfo->m_GDIObjectCount), plvitem->pszText, plvitem->cchTextMax);
  3054.                         break;
  3055.  
  3056.                     case COL_READOPERCOUNT:
  3057.                         Int64ToCommaSepString(pProcInfo->m_IoReadOperCount, plvitem->pszText, plvitem->cchTextMax);
  3058.                         break;
  3059.  
  3060.                     case COL_WRITEOPERCOUNT:
  3061.                         Int64ToCommaSepString(pProcInfo->m_IoWriteOperCount, plvitem->pszText, plvitem->cchTextMax);
  3062.                         break;
  3063.  
  3064.                     case COL_OTHEROPERCOUNT:
  3065.                         Int64ToCommaSepString(pProcInfo->m_IoOtherOperCount, plvitem->pszText, plvitem->cchTextMax);
  3066.                         break;
  3067.  
  3068.                     case COL_READXFERCOUNT:
  3069.                         Int64ToCommaSepString(pProcInfo->m_IoReadXferCount, plvitem->pszText, plvitem->cchTextMax);
  3070.                         break;
  3071.  
  3072.                     case COL_WRITEXFERCOUNT:
  3073.                         Int64ToCommaSepString(pProcInfo->m_IoWriteXferCount, plvitem->pszText, plvitem->cchTextMax);
  3074.                         break;
  3075.  
  3076.                     case COL_OTHERXFERCOUNT:
  3077.                         Int64ToCommaSepString(pProcInfo->m_IoOtherXferCount, plvitem->pszText, plvitem->cchTextMax);
  3078.                         break;
  3079.  
  3080.                     default:
  3081.                         Assert( 0 && "Unknown listview subitem" );
  3082.                         break;
  3083.  
  3084.                 } // end switch(columnid)
  3085.  
  3086.             } // end LVIF_TEXT case
  3087.  
  3088.         } // end LVN_GETDISPINFO case
  3089.    
  3090.     } // end switch(pnmhdr->code)
  3091.  
  3092. done:
  3093.     return 1;
  3094. }
  3095.  
  3096.  
  3097.  
  3098. /*++ CProcPage::TimerEvent
  3099.  
  3100. Routine Description:
  3101.  
  3102.     Called by main app when the update time fires
  3103.    
  3104. Arguments:
  3105.  
  3106. Return Value:
  3107.  
  3108. Revision History:
  3109.  
  3110.       Nov-20-95 Davepl  Created
  3111.  
  3112. --*/
  3113.  
  3114. void CProcPage::TimerEvent()
  3115. {
  3116.     // REVIEW (DavePl)
  3117.     // We might want to optimize the amount of calculation we do when
  3118.     // we are iconic, but we still need to track the deltas (mem usage,
  3119.     // faults, etc) so might as well just calc it all.  Listview won't
  3120.     // repaint anyway until its visible, which is the real work
  3121.  
  3122.     if (FALSE == m_fPaused)
  3123.     {
  3124.         // We only process updates when the display is not paused, ie:
  3125.         // not during trackpopupmenu loop
  3126.         UpdateProcInfoArray();
  3127.         UpdateProcListview();
  3128.     }
  3129. }
  3130.  
  3131.  
  3132. /*++ CProcPage::HandleProcListContextMenu
  3133.  
  3134. Routine Description:
  3135.  
  3136.     Handles right-clicks (context menu) in the proc list
  3137.    
  3138. Arguments:
  3139.  
  3140.     xPos, yPos  - coords of where the click occurred
  3141.  
  3142. Return Value:
  3143.  
  3144. Revision History:
  3145.  
  3146.       Nov-22-95 Davepl  Created
  3147.  
  3148. --*/
  3149.  
  3150. void CProcPage::HandleProcListContextMenu(INT xPos, INT yPos)
  3151. {
  3152.     HWND hTaskList = GetDlgItem(m_hPage, IDC_PROCLIST);
  3153.  
  3154.     INT iItem = ListView_GetNextItem(hTaskList, -1, LVNI_SELECTED);
  3155.  
  3156.     if (-1 != iItem)
  3157.     {
  3158.         if (0xFFFF == LOWORD(xPos) && 0xFFFF == LOWORD(yPos))
  3159.         {
  3160.             RECT rcItem;
  3161.             ListView_GetItemRect(hTaskList, iItem, &rcItem, LVIR_ICON);
  3162.             MapWindowRect(hTaskList, NULL, &rcItem);
  3163.             xPos = rcItem.right;
  3164.             yPos = rcItem.bottom;
  3165.         }
  3166.  
  3167.  
  3168.         HMENU hPopup = LoadPopupMenu(g_hInstance, IDR_PROC_CONTEXT);
  3169.         if (hPopup)
  3170.         {
  3171.             if (hPopup && SHRestricted(REST_NORUN))
  3172.             {
  3173.                 DeleteMenu(hPopup, IDM_RUN, MF_BYCOMMAND);
  3174.             }
  3175.  
  3176.             CProcInfo * pProc = GetSelectedProcess();
  3177.             if (NULL == pProc)
  3178.             {
  3179.                 return;
  3180.             }
  3181.  
  3182.             //
  3183.             // If no debugger is installed or it's a 16-bit app
  3184.             // ghost the debug menu item
  3185.             //
  3186.  
  3187.             if (NULL == m_pszDebugger || pProc->IsWowTask())
  3188.             {
  3189.                 EnableMenuItem(hPopup, IDM_PROC_DEBUG, MF_GRAYED | MF_DISABLED | MF_BYCOMMAND);
  3190.             }
  3191.  
  3192.             //
  3193.             // If it's a 16-bit task grey the priority choices
  3194.             //
  3195.  
  3196.             if (pProc->IsWowTask())
  3197.             {
  3198.                 EnableMenuItem(hPopup, IDM_PROC_REALTIME,   MF_GRAYED | MF_DISABLED | MF_BYCOMMAND);
  3199.                 EnableMenuItem(hPopup, IDM_PROC_ABOVENORMAL,MF_GRAYED | MF_DISABLED | MF_BYCOMMAND);
  3200.                 EnableMenuItem(hPopup, IDM_PROC_NORMAL,     MF_GRAYED | MF_DISABLED | MF_BYCOMMAND);
  3201.                 EnableMenuItem(hPopup, IDM_PROC_BELOWNORMAL,MF_GRAYED | MF_DISABLED | MF_BYCOMMAND);
  3202.                 EnableMenuItem(hPopup, IDM_PROC_HIGH,       MF_GRAYED | MF_DISABLED | MF_BYCOMMAND);
  3203.                 EnableMenuItem(hPopup, IDM_PROC_LOW,        MF_GRAYED | MF_DISABLED | MF_BYCOMMAND);
  3204.             }
  3205.  
  3206.             //
  3207.             // If not an MP machine, remove the affinity option
  3208.             //
  3209.  
  3210.             if (1 == g_cProcessors || pProc->IsWowTask())
  3211.             {
  3212.                 DeleteMenu(hPopup, IDM_AFFINITY, MF_BYCOMMAND);
  3213.             }
  3214.                    
  3215.             DWORD dwPri   = pProc->m_PriClass;
  3216.             INT   idCheck = 0;
  3217.  
  3218.             // These constants are listed in the SDK
  3219.  
  3220.             if (dwPri == IDLE_PRIORITY_CLASS)
  3221.             {
  3222.                 idCheck = IDM_PROC_LOW;    
  3223.             }
  3224.             else if (dwPri == BELOW_NORMAL_PRIORITY_CLASS)
  3225.             {
  3226.                 idCheck = IDM_PROC_BELOWNORMAL;
  3227.             }
  3228.             else if (dwPri == NORMAL_PRIORITY_CLASS)
  3229.             {
  3230.                 idCheck = IDM_PROC_NORMAL;
  3231.             }
  3232.             else if (dwPri == ABOVE_NORMAL_PRIORITY_CLASS)
  3233.             {
  3234.                 idCheck = IDM_PROC_ABOVENORMAL;
  3235.             }
  3236.             else if (dwPri == HIGH_PRIORITY_CLASS)
  3237.             {
  3238.                 idCheck = IDM_PROC_HIGH;
  3239.             }
  3240.             else
  3241.             {
  3242.                 Assert(dwPri == REALTIME_PRIORITY_CLASS);
  3243.                 idCheck = IDM_PROC_REALTIME;
  3244.             }
  3245.  
  3246.             // Check the appropriate radio menu for this process' priority class
  3247.  
  3248.             CheckMenuRadioItem(hPopup, IDM_PROC_REALTIME, IDM_PROC_LOW, idCheck, MF_BYCOMMAND);
  3249.  
  3250.             m_fPaused = TRUE;
  3251.             g_fInPopup = TRUE;
  3252.             TrackPopupMenuEx(hPopup, 0, xPos, yPos, m_hPage, NULL);
  3253.             g_fInPopup = FALSE;
  3254.             m_fPaused = FALSE;
  3255.            
  3256.             //
  3257.             // If one of the context menu actions (ie: Kill) requires that the display
  3258.             // get updated, do it now
  3259.             //
  3260.  
  3261.             DestroyMenu(hPopup);
  3262.         }
  3263.     }
  3264. }
  3265.  
  3266. /*++ AffinityDlgProc
  3267.  
  3268. Routine Description:
  3269.  
  3270.     Dialog procedure for the affinity mask dialog.  Basically just tracks 32 check
  3271.     boxes that represent the processors
  3272.    
  3273. Arguments:
  3274.  
  3275.     standard dlgproc fare 0 - initial lParam is pointer to affinity mask
  3276.  
  3277. Revision History:
  3278.  
  3279.       Jan-17-96 Davepl  Created
  3280.  
  3281. --*/
  3282.  
  3283. INT_PTR CALLBACK AffinityDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  3284. {
  3285.     static DWORD * pdwAffinity = NULL;      // One of the joys of single threadedness
  3286.  
  3287.     switch (uMsg)
  3288.     {
  3289.         case WM_INITDIALOG:
  3290.         {
  3291.             pdwAffinity = (DWORD *) lParam;
  3292.  
  3293.             for (int i = 0; i < MAX_PROCESSOR; i++)
  3294.             {
  3295.                 EnableWindow(GetDlgItem(hwndDlg, IDC_CPU0 + i), i < g_cProcessors);
  3296.                 CheckDlgButton(hwndDlg, IDC_CPU0 + i, i < g_cProcessors && ((*pdwAffinity & (1 << i)) != 0));
  3297.             }
  3298.             return TRUE;
  3299.         }
  3300.  
  3301.         case WM_COMMAND:
  3302.         {
  3303.             switch (LOWORD(wParam))
  3304.             {
  3305.                 case IDCANCEL:
  3306.                     EndDialog(hwndDlg, IDCANCEL);
  3307.                     break;
  3308.  
  3309.                 case IDOK:
  3310.                 {
  3311.                     *pdwAffinity = 0;
  3312.                     for (int i = 0; i < g_cProcessors; i++)
  3313.                     {
  3314.                         if (IsDlgButtonChecked(hwndDlg, IDC_CPU0 + i))
  3315.                         {
  3316.                             *pdwAffinity |= 1 << i;
  3317.                         }
  3318.                     }
  3319.  
  3320.                     if (*pdwAffinity == 0)
  3321.                     {
  3322.                         // Can't set affinity to "none"
  3323.  
  3324.                         TCHAR szTitle[MAX_PATH];
  3325.                         TCHAR szBody[MAX_PATH];
  3326.  
  3327.                         if (0 == LoadString(g_hInstance, IDS_INVALIDOPTION, szTitle, ARRAYSIZE(szTitle)) ||
  3328.                             0 == LoadString(g_hInstance, IDS_NOAFFINITYMASK, szBody,  ARRAYSIZE(szBody)))
  3329.                         {
  3330.                             break;
  3331.                         }
  3332.                         MessageBox(hwndDlg, szBody, szTitle, MB_ICONERROR);
  3333.                         break;
  3334.                     }
  3335.                     EndDialog(hwndDlg, IDOK);
  3336.                 }
  3337.             }
  3338.         }
  3339.     }
  3340.     return FALSE;
  3341. }
  3342.  
  3343. /*++ SetAffinity
  3344.  
  3345. Routine Description:
  3346.  
  3347.     Puts up a dialog that lets the user adjust the processor affinity
  3348.     for a process
  3349.    
  3350. Arguments:
  3351.  
  3352.     pid - process Id of process to modify
  3353.  
  3354. Return Value:
  3355.  
  3356.     boolean success
  3357.  
  3358. Revision History:
  3359.  
  3360.       Jan-17-96 Davepl  Created
  3361.  
  3362. --*/
  3363.  
  3364. BOOL CProcPage::SetAffinity(DWORD pid)
  3365. {
  3366.     BOOL fSuccess = FALSE;
  3367.  
  3368.     // REVIEW (Davepl) may only need get/set info access here
  3369.  
  3370.     HANDLE hProcess = OpenProcess( PROCESS_SET_INFORMATION | PROCESS_QUERY_INFORMATION, FALSE, pid );
  3371.     if (hProcess)
  3372.     {
  3373.         DWORD_PTR dwAffinity;
  3374.         DWORD_PTR dwUnusedSysAfin;
  3375.         if (GetProcessAffinityMask(hProcess, &dwAffinity, &dwUnusedSysAfin))
  3376.         {
  3377.             if (IDOK == DialogBoxParam(g_hInstance,
  3378.                                        MAKEINTRESOURCE(IDD_AFFINITY),
  3379.                                        m_hPage,
  3380.                                        AffinityDlgProc,
  3381.                                        (LPARAM) &dwAffinity))
  3382.             {
  3383.                 if (SetProcessAffinityMask(hProcess, dwAffinity))
  3384.                     fSuccess = TRUE;
  3385.             }
  3386.             else
  3387.                 fSuccess = TRUE;        // Cancel, so no failure
  3388.         }
  3389.    
  3390.         CloseHandle(hProcess);
  3391.     }
  3392.  
  3393.     if (!fSuccess)
  3394.     {
  3395.         DWORD dwError = GetLastError();
  3396.         DisplayFailureMsg(m_hPage, IDS_CANTSETAFFINITY, dwError);
  3397.     }
  3398.    
  3399.     return fSuccess;
  3400. }
  3401.  
  3402. BOOL CProcPage::IsSystemProcess(DWORD pid, CProcInfo * pProcInfo)
  3403. {
  3404.     // We don't allow the following set of critical system processes to be terminated,
  3405.     // since the system would bugcheck immediately, no matter who you are.
  3406.  
  3407.     static const LPCTSTR apszCantKill[] =
  3408.     {
  3409.         TEXT("csrss.exe"), TEXT("winlogon.exe"), TEXT("smss.exe"), TEXT("services.exe"), TEXT("lsass.exe")
  3410.     };
  3411.  
  3412.     // if they pass in a pProcInfo we'll use it, otherwise find it ourselves
  3413.     if (!pProcInfo)
  3414.         pProcInfo = FindProcInArrayByPID(m_pProcArray, pid);
  3415.     if (!pProcInfo)
  3416.         return FALSE;
  3417.  
  3418.     for (int i = 0; i < ARRAYSIZE(apszCantKill); ++i)
  3419.     {
  3420.         if (0 == lstrcmpi(pProcInfo->m_pszImageName, apszCantKill[i]))
  3421.         {
  3422.             TCHAR szTitle[MAX_PATH];
  3423.             TCHAR szBody[MAX_PATH];
  3424.  
  3425.             if (0 != LoadString(g_hInstance, IDS_CANTKILL, szTitle, ARRAYSIZE(szTitle)) &&
  3426.                 0 != LoadString(g_hInstance, IDS_KILLSYS,  szBody,  ARRAYSIZE(szBody)))
  3427.             {
  3428.                 MessageBox(m_hPage, szBody, szTitle, MB_ICONEXCLAMATION | MB_OK);
  3429.             }
  3430.             return TRUE;
  3431.         }
  3432.     }
  3433.     return FALSE;
  3434. }
  3435.  
  3436. /*++ KillProcess
  3437.  
  3438. Routine Description:
  3439.  
  3440.     Kills a process
  3441.    
  3442. Arguments:
  3443.  
  3444.     pid - process Id of process to kill
  3445.  
  3446. Return Value:
  3447.  
  3448. Revision History:
  3449.  
  3450.       Nov-22-95 Davepl  Created
  3451.  
  3452. --*/
  3453.  
  3454. BOOL CProcPage::KillProcess(DWORD pid, BOOL bBatchKill)
  3455. {
  3456.     DWORD dwError = ERROR_SUCCESS;
  3457.  
  3458.     //
  3459.     // Special-case killing WOW tasks
  3460.     //
  3461.  
  3462.     CProcInfo * pProcInfo;
  3463.     pProcInfo = FindProcInArrayByPID(m_pProcArray, pid);
  3464.  
  3465.     if (NULL == pProcInfo)
  3466.         return FALSE;
  3467.  
  3468.     if (IsSystemProcess(pid, pProcInfo))
  3469.         return FALSE;
  3470.  
  3471.     // Grab info from pProcInfo (because once we call QuickConfirm(), the
  3472.     // pProcInfo pointer may be invalid)
  3473.     INT_PTR fWowTask = pProcInfo->IsWowTask();
  3474. #if defined (_WIN64)
  3475. #else
  3476.     DWORD dwRealPID = pProcInfo->GetRealPID();
  3477.     WORD hTaskWow = pProcInfo->m_htaskWow;
  3478. #endif
  3479.  
  3480.     // OK so far, now confirm that the user really wants to do this.
  3481.  
  3482.     if (!bBatchKill && (IDYES != QuickConfirm(IDS_WARNING, IDS_KILL)))
  3483.     {
  3484.         return FALSE;
  3485.     }
  3486.  
  3487.     // We can't use this pointer after QuickConfirm() is called.
  3488.     // NULL it out to prevent subtle bugs.
  3489.     pProcInfo = NULL;
  3490.  
  3491.    
  3492.     if (fWowTask) {
  3493.  
  3494. #if defined (_WIN64)
  3495.         return FALSE;
  3496. #else
  3497.         return VDMTerminateTaskWOW(dwRealPID, hTaskWow);
  3498. #endif
  3499.     }
  3500.  
  3501.     //
  3502.     // If possible, enable the Debug privilege. This allows us to kill
  3503.     // processes not owned by the current user, including processes
  3504.     // running in other TS sessions.
  3505.     //
  3506.     // Alternatively, we could first open the process for WRITE_DAC,
  3507.     // grant ourselves PROCESS_TERMINATE access, and then reopen the
  3508.     // process to kill it.
  3509.     //
  3510.     CPrivilegeEnable privilege(SE_DEBUG_NAME);
  3511.  
  3512.     HANDLE hProcess = OpenProcess( PROCESS_TERMINATE, FALSE, pid );
  3513.     if (hProcess)
  3514.     {
  3515.         if (FALSE == TerminateProcess( hProcess, 1 ))
  3516.         {
  3517.             dwError = GetLastError();
  3518.             dprintf(TEXT("Can't terminate process: %08x\n"), dwError);
  3519.         }
  3520.         else
  3521.         {
  3522.             TimerEvent();
  3523.         }
  3524.         CloseHandle( hProcess );
  3525.     }
  3526.     else
  3527.     {
  3528.         dwError = GetLastError();
  3529.     }
  3530.    
  3531.     if (ERROR_SUCCESS != dwError)
  3532.     {
  3533.         DisplayFailureMsg(m_hPage, IDS_CANTKILL, dwError);
  3534.         return FALSE;
  3535.     }
  3536.     else
  3537.     {
  3538.         return TRUE;
  3539.     }
  3540.  
  3541. }
  3542.  
  3543. /*++ AttachDebugger
  3544.  
  3545. Routine Description:
  3546.  
  3547.     Attaches the debugger listed in the AeDebug reg key to the specified
  3548.     running process
  3549.    
  3550. Arguments:
  3551.  
  3552.     pid - process Id of process to debug
  3553.  
  3554. Return Value:
  3555.  
  3556. Revision History:
  3557.  
  3558.       Nov-27-95 Davepl  Created
  3559.  
  3560. --*/
  3561.  
  3562. BOOL CProcPage::AttachDebugger(DWORD pid)
  3563. {
  3564.     DWORD dwError = ERROR_SUCCESS;
  3565.  
  3566.     if (IDYES != QuickConfirm(IDS_WARNING, IDS_DEBUG))
  3567.     {
  3568.         return FALSE;
  3569.     }
  3570.  
  3571.     TCHAR szCmdline[MAX_PATH * 2];
  3572.  
  3573.     wsprintf(szCmdline, TEXT("%s -p %ld"), m_pszDebugger, pid);
  3574.  
  3575.     STARTUPINFO sinfo =
  3576.     {
  3577.         sizeof(STARTUPINFO),
  3578.     };
  3579.     PROCESS_INFORMATION pinfo;
  3580.  
  3581.     if (FALSE == CreateProcess(NULL, //m_pszDebugger,
  3582.                                szCmdline,
  3583.                                NULL,
  3584.                                NULL,
  3585.                                FALSE,
  3586.                                CREATE_NEW_CONSOLE,
  3587.                                NULL,
  3588.                                NULL,
  3589.                                &sinfo,
  3590.                                &pinfo))
  3591.     {
  3592.         dwError = GetLastError();
  3593.     }
  3594.     else
  3595.     {
  3596.         CloseHandle(pinfo.hThread);
  3597.         CloseHandle(pinfo.hProcess);
  3598.     }
  3599.  
  3600.     if (ERROR_SUCCESS != dwError)
  3601.     {
  3602.         DisplayFailureMsg(m_hPage, IDS_CANTDEBUG, dwError);
  3603.         return FALSE;
  3604.     }
  3605.     else
  3606.     {
  3607.         return TRUE;
  3608.     }
  3609. }
  3610.  
  3611. /*++ SetPriority
  3612.  
  3613. Routine Description:
  3614.  
  3615.     Sets a process' priority class
  3616.    
  3617. Arguments:
  3618.  
  3619.     pid - process Id of process to change
  3620.     pri - ID_CMD_XXXXXX menu choice of priority
  3621.  
  3622. Return Value:
  3623.  
  3624. Revision History:
  3625.  
  3626.       Nov-27-95 Davepl  Created
  3627.  
  3628. --*/
  3629.  
  3630. BOOL CProcPage::SetPriority(CProcInfo * pProc, DWORD idCmd)
  3631. {
  3632.     DWORD dwError = ERROR_SUCCESS;
  3633.  
  3634.     DWORD oldPri;
  3635.     DWORD pri;
  3636.  
  3637.     // Determine which priority class we need to use based
  3638.     // on the menu selection
  3639.  
  3640.     switch (idCmd)
  3641.     {
  3642.         case IDM_PROC_LOW:
  3643.             pri = IDLE_PRIORITY_CLASS;
  3644.             break;
  3645.  
  3646.         case IDM_PROC_BELOWNORMAL:
  3647.             pri = BELOW_NORMAL_PRIORITY_CLASS;
  3648.             break;
  3649.  
  3650.         case IDM_PROC_ABOVENORMAL:
  3651.             pri = ABOVE_NORMAL_PRIORITY_CLASS;
  3652.             break;
  3653.  
  3654.         case IDM_PROC_HIGH:
  3655.             pri = HIGH_PRIORITY_CLASS;
  3656.             break;
  3657.  
  3658.         case IDM_PROC_REALTIME:
  3659.             pri = REALTIME_PRIORITY_CLASS;
  3660.             break;
  3661.  
  3662.         default:
  3663.             Assert(idCmd == IDM_PROC_NORMAL);
  3664.             pri = NORMAL_PRIORITY_CLASS;
  3665.     }
  3666.  
  3667.     oldPri = (DWORD) pProc->m_PriClass;
  3668.  
  3669.     if ( oldPri == pri )
  3670.     {
  3671.         return FALSE;   // nothing to do.
  3672.     }
  3673.  
  3674.     // Get confirmation before we change the priority
  3675.  
  3676.     if (IDYES != QuickConfirm(IDS_WARNING, IDS_PRICHANGE))
  3677.     {
  3678.         return FALSE;
  3679.     }
  3680.    
  3681.     HANDLE hProcess = OpenProcess( PROCESS_SET_INFORMATION, FALSE, pProc->m_UniqueProcessId);
  3682.     if (hProcess)
  3683.     {
  3684.    
  3685.         if (FALSE == SetPriorityClass( hProcess, pri ))
  3686.         {
  3687.             dwError = GetLastError();
  3688.             dprintf(TEXT("Cant open process for pri change: %08x\n"), dwError);
  3689.         }
  3690.         else
  3691.         {
  3692.             TimerEvent();
  3693.         }
  3694.  
  3695.         CloseHandle( hProcess );
  3696.     }
  3697.     else
  3698.     {
  3699.         dwError = GetLastError();
  3700.     }
  3701.  
  3702.     if (ERROR_SUCCESS != dwError)
  3703.     {
  3704.         DisplayFailureMsg(m_hPage, IDS_CANTCHANGEPRI, dwError);
  3705.         return FALSE;
  3706.     }
  3707.     else
  3708.     {
  3709.         return TRUE;
  3710.     }
  3711. }
  3712.  
  3713.  
  3714. /*++ CProcPage::GetSelectedProcess
  3715.  
  3716. Routine Description:
  3717.  
  3718.     Returns the CProcInfo * of the currently selected process
  3719.    
  3720. Arguments:
  3721.  
  3722. Return Value:
  3723.  
  3724.     CProcInfo * on success, NULL on error or nothing selected
  3725.  
  3726. Revision History:
  3727.  
  3728.       Nov-22-95 Davepl  Created
  3729.  
  3730. --*/
  3731.  
  3732. CProcInfo * CProcPage::GetSelectedProcess()
  3733. {
  3734.     HWND hTaskList = GetDlgItem(m_hPage, IDC_PROCLIST);
  3735.     INT iItem = ListView_GetNextItem(hTaskList, -1, LVNI_SELECTED);
  3736.  
  3737.     CProcInfo * pProc;
  3738.  
  3739.     if (-1 != iItem)
  3740.     {
  3741.         LV_ITEM lvitem = { LVIF_PARAM };
  3742.         lvitem.iItem = iItem;
  3743.    
  3744.         if (ListView_GetItem(hTaskList, &lvitem))
  3745.         {
  3746.             pProc = (CProcInfo *) (lvitem.lParam);
  3747.         }
  3748.         else
  3749.         {
  3750.             pProc = NULL;
  3751.         }
  3752.     }
  3753.     else
  3754.     {
  3755.         pProc = NULL;
  3756.     }
  3757.  
  3758.     return pProc;
  3759. }
  3760.  
  3761. /*++ CProcPage::HandleWMCOMMAND
  3762.  
  3763. Routine Description:
  3764.  
  3765.     Handles WM_COMMANDS received at the main page dialog
  3766.    
  3767. Arguments:
  3768.  
  3769.     id - Command id of command received
  3770.  
  3771. Return Value:
  3772.  
  3773. Revision History:
  3774.  
  3775.       Nov-22-95 Davepl  Created
  3776.  
  3777. --*/
  3778.  
  3779. void CProcPage::HandleWMCOMMAND( WORD id , HWND hCtrl )
  3780. {
  3781.     CProcInfo * pProc = GetSelectedProcess();
  3782.  
  3783.     switch(id)
  3784.     {
  3785.         case IDC_DEBUG:
  3786.         case IDM_PROC_DEBUG:
  3787.         {
  3788.             if (pProc && m_pszDebugger)
  3789.             {
  3790.                 AttachDebugger( pProc->m_UniqueProcessId);
  3791.             }
  3792.             break;
  3793.         }
  3794.  
  3795.         case IDC_ENDTASK:
  3796.         case IDC_TERMINATE:
  3797.         case IDM_PROC_TERMINATE:
  3798.         {
  3799.             if (pProc)
  3800.             {
  3801.                 KillProcess( pProc->m_UniqueProcessId);
  3802.             }
  3803.             break;
  3804.         }
  3805.  
  3806.         case IDM_ENDTREE:
  3807.         {
  3808.             if (pProc)
  3809.             {
  3810.                 RecursiveKill( pProc->m_UniqueProcessId);
  3811.             }
  3812.             break;
  3813.         }
  3814.  
  3815.         case IDM_AFFINITY:
  3816.         {
  3817.             if (pProc)
  3818.             {
  3819.                 SetAffinity( pProc->m_UniqueProcessId);
  3820.             }
  3821.             break;
  3822.         }
  3823.  
  3824.         case IDM_PROC_REALTIME:
  3825.         case IDM_PROC_HIGH:
  3826.         case IDM_PROC_ABOVENORMAL:
  3827.         case IDM_PROC_NORMAL:
  3828.         case IDM_PROC_BELOWNORMAL:
  3829.         case IDM_PROC_LOW:
  3830.         {
  3831.             if (pProc)
  3832.             {
  3833.                 SetPriority( pProc, id);
  3834.             }
  3835.             break;
  3836.         }
  3837.  
  3838.         case IDC_SHOWALL:
  3839.  
  3840.                 g_Options.m_bShowAllProcess = SendMessage( hCtrl , BM_GETCHECK , 0 , 0 ) == BST_CHECKED;
  3841.  
  3842.                 break;
  3843.     }
  3844. }
  3845.  
  3846.  
  3847.  
  3848. /*++ ProcPageProc
  3849.  
  3850. Routine Description:
  3851.  
  3852.     Dialogproc for the process page.  
  3853.    
  3854. Arguments:
  3855.  
  3856.     hwnd        - handle to dialog box
  3857.     uMsg        - message
  3858.     wParam      - first message parameter
  3859.     lParam      - second message parameter
  3860.  
  3861. Return Value:
  3862.  
  3863.     For WM_INITDIALOG, TRUE == user32 sets focus, FALSE == we set focus
  3864.     For others, TRUE == this proc handles the message
  3865.  
  3866. Revision History:
  3867.  
  3868.       Nov-16-95 Davepl  Created
  3869.  
  3870. --*/
  3871.  
  3872. INT_PTR CALLBACK ProcPageProc(
  3873.                 HWND        hwnd,               // handle to dialog box
  3874.                 UINT        uMsg,                   // message
  3875.                 WPARAM      wParam,                 // first message parameter
  3876.                 LPARAM      lParam                  // second message parameter
  3877.                 )
  3878. {
  3879.     CProcPage * thispage = (CProcPage *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
  3880.  
  3881.     // See if the parent wants this message
  3882.  
  3883.     if (TRUE == CheckParentDeferrals(uMsg, wParam, lParam))
  3884.     {
  3885.         return TRUE;
  3886.     }
  3887.  
  3888.     switch(uMsg)
  3889.     {
  3890.         case WM_INITDIALOG:
  3891.         {
  3892.             SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam);
  3893.             CProcPage * thispage = (CProcPage *) lParam;
  3894.  
  3895.             thispage->m_hPage = hwnd;
  3896.  
  3897.             // Turn on SHOWSELALWAYS so that the selection is still highlighted even
  3898.             // when focus is lost to one of the buttons (for example)
  3899.  
  3900.             HWND hTaskList = GetDlgItem(hwnd, IDC_PROCLIST);
  3901.  
  3902.             SetWindowLong(hTaskList, GWL_STYLE, GetWindowLong(hTaskList, GWL_STYLE) | LVS_SHOWSELALWAYS);
  3903.             ListView_SetExtendedListViewStyle(hTaskList, LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP | LVS_EX_DOUBLEBUFFER);
  3904.  
  3905.             SubclassListView(GetDlgItem(hwnd, IDC_PROCLIST));
  3906.  
  3907.             //
  3908.             // This was removed from CProcPage::Activate
  3909.             //
  3910.             HWND hchk = GetDlgItem( hwnd , IDC_SHOWALL );
  3911.  
  3912.             if( hchk != NULL )
  3913.             {
  3914.                 if( g_fIsTSEnabled )
  3915.                 {
  3916.                     // Disable the IDC_SHOWALL checkbox for non-admin. YufengZ  03/23/98
  3917.  
  3918.                     ShowWindow(hchk, TRUE);
  3919.  
  3920.                     if( !IsUserAdmin( ) )
  3921.                     {
  3922.                         EnableWindow( hchk, FALSE );
  3923.                     }
  3924.                     else
  3925.                     {
  3926.                         WPARAM wp = g_Options.m_bShowAllProcess ? BST_CHECKED : BST_UNCHECKED;
  3927.  
  3928.                         SendMessage( hchk , BM_SETCHECK , wp  , 0 );
  3929.                         //Button_SetCheck( hchk , BST_CHECKED );
  3930.                     }
  3931.                 }
  3932.                 else
  3933.                 {
  3934.                     // hide the IDC_SHOWALL checkbox if its not terminal server.
  3935.  
  3936.                     ShowWindow( hchk , SW_HIDE );
  3937.                 }
  3938.             }
  3939.  
  3940.             // We handle focus during Activate(). Return FALSE here so the
  3941.             // dialog manager doesn't try to set focus.
  3942.             return FALSE;
  3943.         }
  3944.  
  3945.         case WM_DESTROY:
  3946.             thispage->RememberColumnOrder(GetDlgItem(hwnd, IDC_PROCLIST));
  3947.             break;
  3948.  
  3949.         // We need to fake client mouse clicks in this child to appear as nonclient
  3950.         // (caption) clicks in the parent so that the user can drag the entire app
  3951.         // when the title bar is hidden by dragging the client area of this child
  3952.  
  3953.         case WM_LBUTTONUP:
  3954.         case WM_LBUTTONDOWN:
  3955.         {
  3956.             if (g_Options.m_fNoTitle)
  3957.             {
  3958.                 SendMessage(g_hMainWnd,
  3959.                             uMsg == WM_LBUTTONUP ? WM_NCLBUTTONUP : WM_NCLBUTTONDOWN,
  3960.                             HTCAPTION,
  3961.                             lParam);
  3962.             }
  3963.             break;
  3964.         }
  3965.  
  3966.         case WM_NCLBUTTONDBLCLK:
  3967.         case WM_LBUTTONDBLCLK:
  3968.         {
  3969.             SendMessage(g_hMainWnd, uMsg, wParam, lParam);
  3970.             break;
  3971.         }
  3972.  
  3973.         // We have been asked to find and select a process
  3974.  
  3975.         case WM_FINDPROC:
  3976.         {
  3977.             DWORD cProcs = thispage->m_pProcArray->GetSize();
  3978.             DWORD dwProcessId;
  3979.  
  3980.             for (INT iPass = 0; iPass < 2; iPass++)
  3981.             {
  3982.                 //
  3983.                 // On the first pass we try to find a WOW
  3984.                 // task with a thread ID which matches the
  3985.                 // one given in wParam.  If we don't find
  3986.                 // such a task, we look for a process which
  3987.                 // matches the PID in lParam.
  3988.                 //
  3989.  
  3990.                 for (UINT i = 0; i < cProcs; i++)
  3991.                 {
  3992.                     CProcInfo *pProc = (CProcInfo *)thispage->m_pProcArray->GetAt(i);
  3993.                     dwProcessId = pProc->m_UniqueProcessId;
  3994.  
  3995.                     if ((!iPass && wParam == (WPARAM) dwProcessId) ||
  3996.                         ( iPass && lParam == (LPARAM) dwProcessId))
  3997.                     {
  3998.                         // TS filters items out of the view so cannot assume
  3999.                         // that m_pProcArray is in sync with the listview.
  4000.                         HWND hwndLV = GetDlgItem(hwnd, IDC_PROCLIST);
  4001.                         LVFINDINFO fi;
  4002.                         fi.flags = LVFI_PARAM;
  4003.                         fi.lParam = (LPARAM)pProc;
  4004.  
  4005.                         int iItem = ListView_FindItem(hwndLV, -1, &fi);
  4006.                         if (iItem >= 0)
  4007.                         {
  4008.                             ListView_SetItemState (hwndLV,
  4009.                                                    iItem,
  4010.                                                    LVIS_FOCUSED | LVIS_SELECTED,
  4011.                                                    0x000F);
  4012.                             ListView_EnsureVisible(hwndLV, iItem, FALSE);
  4013.                         }
  4014.                         else
  4015.                         {
  4016.                             // We found the process but the user isn't allowed
  4017.                             // to see it; remove the selection
  4018.                             ListView_SetItemState (hwndLV,
  4019.                                                    -1,
  4020.                                                    0,
  4021.                                                    LVIS_FOCUSED | LVIS_SELECTED);
  4022.                         }
  4023.                         goto FoundProc;
  4024.                     }
  4025.                 }
  4026.             }
  4027.  
  4028. FoundProc:
  4029.             break;
  4030.         }
  4031.  
  4032.         case WM_COMMAND:
  4033.         {
  4034.             thispage->HandleWMCOMMAND( LOWORD(wParam) , ( HWND )lParam );
  4035.  
  4036.             break;
  4037.         }
  4038.  
  4039.         case WM_CONTEXTMENU:
  4040.         {
  4041.             CProcInfo * pProc = thispage->GetSelectedProcess();
  4042.             if (pProc && pProc->m_UniqueProcessId)
  4043.             {
  4044.            
  4045.                 if ((HWND) wParam == GetDlgItem(hwnd, IDC_PROCLIST))
  4046.                 {
  4047.                     thispage->HandleProcListContextMenu(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
  4048.                     return TRUE;
  4049.                 }
  4050.             }
  4051.             break;
  4052.         }
  4053.  
  4054.         case WM_NOTIFY:
  4055.         {
  4056.             return thispage->HandleProcPageNotify((HWND) wParam, (LPNMHDR) lParam);
  4057.         }
  4058.  
  4059.         // Size our kids
  4060.  
  4061.         case WM_SIZE:
  4062.         {
  4063.             thispage->SizeProcPage();
  4064.             return TRUE;
  4065.         }
  4066.  
  4067.         case WM_SYSCOLORCHANGE:
  4068.             SendMessage(GetDlgItem(hwnd, IDC_PROCLIST), uMsg, wParam, lParam);
  4069.             return TRUE;
  4070.  
  4071.         default:
  4072.             return FALSE;
  4073.     }
  4074.     return FALSE;
  4075. }
  4076.  
  4077. /*++ CProcPage::GetTitle
  4078.  
  4079. Routine Description:
  4080.  
  4081.     Copies the title of this page to the caller-supplied buffer
  4082.    
  4083. Arguments:
  4084.  
  4085.     pszText     - the buffer to copy to
  4086.     bufsize     - size of buffer, in characters
  4087.  
  4088. Return Value:
  4089.  
  4090. Revision History:
  4091.  
  4092.       Nov-16-95 Davepl  Created
  4093.  
  4094. --*/
  4095.  
  4096. void CProcPage::GetTitle(LPTSTR pszText, size_t bufsize)
  4097. {
  4098.     LoadString(g_hInstance, IDS_PROCPAGETITLE, pszText, static_cast<int>(bufsize));
  4099. }
  4100.  
  4101. /*++ CProcPage::Activate
  4102.  
  4103. Routine Description:
  4104.  
  4105.     Brings this page to the front, sets its initial position,
  4106.     and shows it
  4107.  
  4108. Arguments:
  4109.  
  4110. Return Value:
  4111.  
  4112.     HRESULT (S_OK on success)
  4113.  
  4114. Revision History:
  4115.  
  4116.       Nov-16-95 Davepl  Created
  4117.  
  4118. --*/
  4119.  
  4120. HRESULT CProcPage::Activate()
  4121. {
  4122.     // Make this page visible
  4123.  
  4124.     ShowWindow(m_hPage, SW_SHOW);
  4125.  
  4126.     SetWindowPos(m_hPage,
  4127.                  HWND_TOP,
  4128.                  0, 0, 0, 0,
  4129.                  SWP_NOMOVE | SWP_NOSIZE);
  4130.  
  4131.  
  4132.     // Change the menu bar to be the menu for this page
  4133.  
  4134.     HMENU hMenuOld = GetMenu(g_hMainWnd);
  4135.     HMENU hMenuNew = LoadMenu(g_hInstance, MAKEINTRESOURCE(IDR_MAINMENU_PROC));
  4136.  
  4137.     AdjustMenuBar(hMenuNew);
  4138.  
  4139.     if (hMenuNew && SHRestricted(REST_NORUN))
  4140.     {
  4141.         DeleteMenu(hMenuNew, IDM_RUN, MF_BYCOMMAND);
  4142.     }
  4143.  
  4144.     g_hMenu = hMenuNew;
  4145.     if (g_Options.m_fNoTitle == FALSE)
  4146.     {
  4147.         SetMenu(g_hMainWnd, hMenuNew);
  4148.     }
  4149.  
  4150.     if (hMenuOld)
  4151.     {
  4152.         DestroyMenu(hMenuOld);
  4153.     }
  4154.  
  4155.     // If the tab control has focus, leave it there. Otherwise, set focus
  4156.     // to the listview.  If we don't set focus, it may stay on the previous
  4157.     // page, now hidden, which can confuse the dialog manager and may cause
  4158.     // us to hang.
  4159.     if (GetFocus() != m_hwndTabs)
  4160.     {
  4161.         SetFocus(GetDlgItem(m_hPage, IDC_PROCLIST));
  4162.     }
  4163.  
  4164.     return S_OK;
  4165. }
  4166.  
  4167. /*++ CProcPage::Initialize
  4168.  
  4169. Routine Description:
  4170.  
  4171.     Initializes the process page
  4172.  
  4173. Arguments:
  4174.  
  4175.     hwndParent  - Parent on which to base sizing on: not used for creation,
  4176.                   since the main app window is always used as the parent in
  4177.                   order to keep tab order correct
  4178.                  
  4179. Return Value:
  4180.  
  4181. Revision History:
  4182.  
  4183.       Nov-16-95 Davepl  Created
  4184.  
  4185. --*/
  4186.  
  4187. HRESULT CProcPage::Initialize(HWND hwndParent)
  4188. {
  4189.     //
  4190.     // Find out what debbuger is configured on this system
  4191.     //
  4192.  
  4193.     HKEY hkDebug;
  4194.  
  4195.     if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  4196.                                       TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug"),
  4197.                                       0, KEY_READ, &hkDebug))
  4198.     {
  4199.         TCHAR szDebugger[MAX_PATH * 2];
  4200.         DWORD cbString = sizeof(szDebugger);
  4201.  
  4202.         if (ERROR_SUCCESS == RegQueryValueEx(hkDebug, TEXT("Debugger"), NULL,
  4203.                                              NULL, (LPBYTE) szDebugger, &cbString))
  4204.         {
  4205.             // Find the first token (which is the debugger exe name/path)
  4206.                
  4207.             LPTSTR pszCmdLine = szDebugger;
  4208.            
  4209.             if ( *pszCmdLine == TEXT('\"') )
  4210.             {
  4211.                 //
  4212.                 // Scan, and skip over, subsequent characters until
  4213.                 // another double-quote or a null is encountered.
  4214.                 //
  4215.                
  4216.                 while ( *++pszCmdLine && (*pszCmdLine != TEXT('\"')) )
  4217.                 {
  4218.                     NULL;
  4219.                 }
  4220.  
  4221.                 //
  4222.                 // If we stopped on a double-quote (usual case), skip
  4223.                 // over it.
  4224.                 //
  4225.                
  4226.                 if ( *pszCmdLine == TEXT('\"') )
  4227.                 {
  4228.                     pszCmdLine++;
  4229.                 }
  4230.             }
  4231.             else
  4232.             {
  4233.                 while (*pszCmdLine > TEXT(' '))
  4234.                 {
  4235.                     pszCmdLine++;
  4236.                 }
  4237.             }
  4238.             *pszCmdLine = TEXT('\0');   // Don't need the rest of the args, etc
  4239.  
  4240.             // If the doctor is in, we don't allow the Debug action
  4241.  
  4242.             if (lstrlen(szDebugger) && lstrcmpi(szDebugger, TEXT("drwtsn32")) && lstrcmpi(szDebugger, TEXT("drwtsn32.exe")))
  4243.             {
  4244.                 m_pszDebugger = (LPTSTR) LocalAlloc( 0, (lstrlen(szDebugger) + 1) * sizeof(TCHAR));
  4245.                 if (NULL == m_pszDebugger)
  4246.                 {
  4247.                     return E_OUTOFMEMORY;
  4248.                 }
  4249.                 lstrcpy(m_pszDebugger, szDebugger);
  4250.             }
  4251.         }
  4252.  
  4253.         RegCloseKey(hkDebug);
  4254.     }
  4255.  
  4256.     //
  4257.     // Get basic info like page size, etc.
  4258.     //
  4259.  
  4260.     NTSTATUS Status = NtQuerySystemInformation(
  4261.                 SystemBasicInformation,
  4262.                 &g_BasicInfo,
  4263.                 sizeof(g_BasicInfo),
  4264.                 NULL
  4265.                 );
  4266.  
  4267.     if (!NT_SUCCESS(Status))
  4268.     {
  4269.         return E_FAIL;
  4270.     }
  4271.  
  4272.     //
  4273.     // Create the ptr array used to hold the info on running processes
  4274.     //
  4275.  
  4276.     m_pProcArray = new CPtrArray(GetProcessHeap());
  4277.     if (NULL == m_pProcArray)
  4278.     {
  4279.         return E_OUTOFMEMORY;
  4280.     }
  4281.  
  4282.     // Our pseudo-parent is the tab contrl, and is what we base our
  4283.     // sizing on.  However, in order to keep tab order right among
  4284.     // the controls, we actually create ourselves with the main
  4285.     // window as the parent
  4286.  
  4287.     m_hwndTabs = hwndParent;
  4288.  
  4289.     //
  4290.     // Create the dialog which represents the body of this page
  4291.     //
  4292.  
  4293.     m_hPage = CreateDialogParam(
  4294.                     g_hInstance,                        // handle to application instance
  4295.                     MAKEINTRESOURCE(IDD_PROCPAGE),      // identifies dialog box template name  
  4296.                     g_hMainWnd,                     // handle to owner window
  4297.                     ProcPageProc,                   // pointer to dialog box procedure
  4298.                     (LPARAM) this );                // User data (our this pointer)
  4299.  
  4300.     if (NULL == m_hPage)
  4301.     {
  4302.         return GetLastHRESULT();
  4303.     }
  4304.  
  4305.     // Set up the columns in the listview
  4306.  
  4307.     if (FAILED(SetupColumns()))
  4308.     {
  4309.         DestroyWindow(m_hPage);
  4310.         m_hPage = NULL;
  4311.         return E_FAIL;
  4312.     }
  4313.  
  4314.     // Restore the column positions.
  4315.  
  4316.     RestoreColumnOrder(GetDlgItem(m_hPage, IDC_PROCLIST));
  4317.  
  4318.     // Do one initial calculation
  4319.  
  4320.     TimerEvent();
  4321.  
  4322.     return S_OK;
  4323. }
  4324.  
  4325. /*++ CProcPage::Destroy
  4326.  
  4327. Routine Description:
  4328.  
  4329.     Frees whatever has been allocated by the Initialize call
  4330.    
  4331. Arguments:
  4332.  
  4333. Return Value:
  4334.  
  4335. Revision History:
  4336.  
  4337.       Nov-16-95 Davepl  Created
  4338.  
  4339. --*/
  4340.  
  4341. HRESULT CProcPage::Destroy()
  4342. {
  4343.    if (m_pProcArray)
  4344.     {
  4345.         INT c = m_pProcArray->GetSize();
  4346.  
  4347.         while (c)
  4348.         {
  4349.             delete (CProcInfo *) (m_pProcArray->GetAt(c - 1));
  4350.             c--;
  4351.         }
  4352.  
  4353.         delete m_pProcArray;
  4354.  
  4355.         m_pProcArray = NULL;
  4356.     }
  4357.  
  4358.     if ( m_pvBuffer != NULL )
  4359.     {
  4360.         HeapFree( GetProcessHeap( ), 0, m_pvBuffer );
  4361.         m_pvBuffer = NULL;
  4362.     }
  4363.    
  4364.     if (m_hPage != NULL)
  4365.     {
  4366.         DestroyWindow(m_hPage);
  4367.         m_hPage = NULL;
  4368.     }
  4369.  
  4370.     if (m_pszDebugger != NULL)
  4371.     {
  4372.         LocalFree(m_pszDebugger);
  4373.         m_pszDebugger = NULL;
  4374.     }
  4375.     return S_OK;
  4376. }
  4377.  
  4378. /*++ CProcPage::SaveColumnWidths
  4379.  
  4380. Routine Description:
  4381.  
  4382.     Saves the widths of all of the columns in the global options structure
  4383.    
  4384. Revision History:
  4385.  
  4386.     Jan-26-95 Davepl  Created
  4387.  
  4388. --*/
  4389.  
  4390. void CProcPage::SaveColumnWidths()
  4391. {
  4392.     UINT i = 0;
  4393.     LV_COLUMN col = { 0 };
  4394.  
  4395.     while (g_Options.m_ActiveProcCol[i] != (COLUMNID) -1)
  4396.     {
  4397.         col.mask = LVCF_WIDTH;
  4398.         if (ListView_GetColumn(GetDlgItem(m_hPage, IDC_PROCLIST), i, &col) )
  4399.         {
  4400.             g_Options.m_ColumnWidths[i] = col.cx;
  4401.         }
  4402.         else
  4403.         {
  4404.             ASSERT(0 && "Couldn't get the column width");
  4405.         }
  4406.         i++;
  4407.     }
  4408. }
  4409.  
  4410. /*++ CProcPage::Deactivate
  4411.  
  4412. Routine Description:
  4413.  
  4414.     Called when this page is losing its place up front
  4415.  
  4416. Arguments:
  4417.  
  4418. Return Value:
  4419.  
  4420. Revision History:
  4421.  
  4422.       Nov-16-95 Davepl  Created
  4423.  
  4424. --*/
  4425.  
  4426. void CProcPage::Deactivate()
  4427. {
  4428.  
  4429.     SaveColumnWidths();
  4430.  
  4431.     if (m_hPage)
  4432.     {
  4433.         ShowWindow(m_hPage, SW_HIDE);
  4434.     }
  4435. }
  4436.  
  4437.  
  4438. /*++ CProcPage::KillAllChildren
  4439.  
  4440. Routine Description:
  4441.  
  4442.     Given a pid, recursively kills it and all of its descendants
  4443.    
  4444. Arguments:
  4445.  
  4446. Return Value:
  4447.  
  4448. Revision History:
  4449.  
  4450.       2-26-01 Bretan  Created
  4451.  
  4452. --*/
  4453.  
  4454. BOOL CProcPage::KillAllChildren(
  4455.                                 DWORD dwTaskPid,
  4456.                                 DWORD pid,
  4457.                                 BYTE* pbBuffer,
  4458.                                 LARGE_INTEGER CreateTime
  4459.                                 )
  4460. {
  4461.     ASSERT(pbBuffer);
  4462.  
  4463.     BOOL rval = TRUE;
  4464.     PSYSTEM_PROCESS_INFORMATION ProcessInfo = (PSYSTEM_PROCESS_INFORMATION) pbBuffer;
  4465.     ULONG TotalOffset = 0;
  4466.    
  4467.     for ( ;; ) // ever
  4468.     {
  4469.         // If we are a child of pid and not pid itself
  4470.         // and if we have been created after pid (we can't be a child if we were created first)
  4471.         if (PtrToUlong(ProcessInfo->InheritedFromUniqueProcessId) == pid &&
  4472.             PtrToUlong(ProcessInfo->UniqueProcessId) != pid &&
  4473.             CreateTime.QuadPart < ProcessInfo->CreateTime.QuadPart)
  4474.         {
  4475.             DWORD newpid = PtrToUlong(ProcessInfo->UniqueProcessId);
  4476.            
  4477.             //
  4478.             // Recurse down to the next level
  4479.             //
  4480.             rval = KillAllChildren(dwTaskPid, newpid, pbBuffer, ProcessInfo->CreateTime);
  4481.            
  4482.             // Kill it if it is not task manager
  4483.             if (newpid != dwTaskPid)
  4484.             {
  4485.                 BOOL tval = KillProcess(newpid, TRUE);
  4486.                
  4487.                 //
  4488.                 // If it has failed earlier in the recursion
  4489.                 // we want to keep that failure (not overwrite it)
  4490.                 //
  4491.                 if (rval == TRUE)
  4492.                 {
  4493.                     rval = tval;
  4494.                 }
  4495.             }
  4496.         }
  4497.            
  4498.         if (ProcessInfo->NextEntryOffset == 0)
  4499.         {
  4500.             break;
  4501.         }
  4502.         TotalOffset += ProcessInfo->NextEntryOffset;
  4503.         ProcessInfo = (PSYSTEM_PROCESS_INFORMATION) &pbBuffer[ TotalOffset ];
  4504.     }
  4505.    
  4506.     return rval;
  4507. }
  4508.  
  4509. /*++ CProcPage::RecursiveKill
  4510.  
  4511. Routine Description:
  4512.  
  4513.     Given a pid, starts the recursive function that kills all the pid's descendents
  4514.    
  4515. Arguments:
  4516.  
  4517. Return Value:
  4518.  
  4519. Revision History:
  4520.  
  4521.       8-4-98  Davepl  Created
  4522.       2-26-01 Bretan  Modified
  4523.  
  4524. --*/
  4525.  
  4526. #define MAX_TASKS 4096
  4527.  
  4528. BOOL CProcPage::RecursiveKill(DWORD pid)
  4529. {
  4530.     BYTE* pbBuffer = NULL;
  4531.     BOOL  rval = TRUE;
  4532.     DWORD dwTaskPid = GetCurrentProcessId();
  4533.  
  4534.     if (IsSystemProcess(pid, NULL))
  4535.     {
  4536.         return FALSE;
  4537.     }
  4538.    
  4539.     if (IDYES != QuickConfirm(IDS_WARNING, IDS_KILLTREE))
  4540.     {
  4541.         return FALSE;
  4542.     }
  4543.    
  4544.     //
  4545.     // get the task list for the system
  4546.     //
  4547.     pbBuffer = GetTaskListEx();
  4548.  
  4549.     if (pbBuffer)
  4550.     {
  4551.         PSYSTEM_PROCESS_INFORMATION ProcessInfo = (PSYSTEM_PROCESS_INFORMATION) pbBuffer;
  4552.         ULONG TotalOffset = 0;
  4553.        
  4554.         for ( ;; ) // ever
  4555.         {
  4556.             if (PtrToUlong(ProcessInfo->UniqueProcessId) == pid)
  4557.             {
  4558.                 rval = KillAllChildren(dwTaskPid, pid, pbBuffer, ProcessInfo->CreateTime);
  4559.  
  4560.                 //
  4561.                 // Kill the parent process if it is not task manager
  4562.                 //
  4563.                 if (pid != dwTaskPid)
  4564.                 {
  4565.                     KillProcess(pid, TRUE);
  4566.                 }
  4567.  
  4568.                 // We will not run into this pid again (since its unique)
  4569.                 // so we might as well break outta this for loop
  4570.                 break;
  4571.             }
  4572.            
  4573.             //
  4574.             // Advance to next task
  4575.             //
  4576.             if (ProcessInfo->NextEntryOffset == 0)
  4577.             {
  4578.                 break;
  4579.             }
  4580.             TotalOffset += ProcessInfo->NextEntryOffset;
  4581.             ProcessInfo = (PSYSTEM_PROCESS_INFORMATION) &pbBuffer[ TotalOffset ];
  4582.         }
  4583.     }
  4584.     else
  4585.     {
  4586.         rval = FALSE;
  4587.     }
  4588.  
  4589.     if (rval != TRUE)
  4590.     {
  4591.         // We failed to kill at least one of the processes
  4592.         TCHAR szTitle[MAX_PATH];
  4593.         TCHAR szBody[MAX_PATH];
  4594.  
  4595.         if (0 != LoadString(g_hInstance, IDS_KILLTREEFAIL, szTitle, ARRAYSIZE(szTitle)) &&
  4596.             0 != LoadString(g_hInstance, IDS_KILLTREEFAILBODY, szBody,  ARRAYSIZE(szBody)))
  4597.         {
  4598.             MessageBox(m_hPage, szBody, szTitle, MB_ICONERROR);
  4599.         }
  4600.     }
  4601.  
  4602.     //
  4603.     // Buffer allocated in call to GetTaskListEx
  4604.     //
  4605.     HeapFree( GetProcessHeap( ), 0, pbBuffer );
  4606.  
  4607.     return rval;
  4608. }
  4609.  
  4610. /*++  CProcPage::GetTaskListEx
  4611.  
  4612. Routine Description:
  4613.  
  4614.     Provides an API for getting a list of tasks running at the time of the
  4615.     API call.  This function uses internal NT apis and data structures.  This
  4616.     api is MUCH faster that the non-internal version that uses the registry.
  4617.  
  4618. Arguments:
  4619.  
  4620.     dwNumTasks       - maximum number of tasks that the pTask array can hold
  4621.  
  4622. Return Value:
  4623.  
  4624.     Number of tasks placed into the pTask array.
  4625.  
  4626. --*/
  4627.  
  4628.  
  4629. BYTE* CProcPage::GetTaskListEx()
  4630. {
  4631.     BYTE*       pbBuffer = NULL;
  4632.     NTSTATUS    status;
  4633.    
  4634.     DWORD  dwBufferSize = sizeof(SYSTEM_PROCESS_INFORMATION) * 100; // start with ~100 processes
  4635.  
  4636. retry:
  4637.     ASSERT( NULL == pbBuffer );
  4638.     pbBuffer = (BYTE *) HeapAlloc( GetProcessHeap( ), 0, dwBufferSize );
  4639.     if (pbBuffer == NULL)
  4640.     {
  4641.         return FALSE;
  4642.     }
  4643.  
  4644.     status = NtQuerySystemInformation( SystemProcessInformation
  4645.                                      , pbBuffer
  4646.                                      , dwBufferSize
  4647.                                      , NULL
  4648.                                      );
  4649.     if ( status != ERROR_SUCCESS )
  4650.     {
  4651.         HeapFree( GetProcessHeap( ), 0, pbBuffer );
  4652.         pbBuffer = NULL;
  4653.     }
  4654.  
  4655.     if (status == STATUS_INFO_LENGTH_MISMATCH) {
  4656.         dwBufferSize += 8192;
  4657.         goto retry;
  4658.     }
  4659.  
  4660.     if (!NT_SUCCESS(status))
  4661.     {
  4662.         return FALSE;
  4663.     }
  4664.  
  4665.     return pbBuffer;
  4666. }
  4667.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement