taskpage.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 66k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. //+-------------------------------------------------------------------------
  2. //
  3. //  TaskMan - NT TaskManager
  4. //  Copyright (C) Microsoft
  5. //
  6. //  File:       taskpage.cpp
  7. //
  8. //  History:    Nov-29-95   DavePl  Created
  9. //
  10. //--------------------------------------------------------------------------
  11. #include "precomp.h"
  12. //
  13. // Project-scope globals
  14. //
  15. DWORD       g_cTasks        = 0;
  16. //
  17. // Local file prototypes
  18. //
  19. BOOL CALLBACK EnumWindowStationsFunc(LPTSTR  lpstr, LPARAM lParam);
  20. BOOL CALLBACK EnumDesktopsFunc(LPTSTR  lpstr, LPARAM lParam);
  21. BOOL CALLBACK EnumWindowsProc(HWND    hwnd, LPARAM   lParam);
  22. //
  23. // Column ID enumeration
  24. //
  25. typedef enum TASKCOLUMNID
  26. {
  27.     COL_TASKNAME            = 0,
  28.     COL_TASKSTATUS          = 1,
  29.     COL_TASKWINSTATION      = 2,
  30.     COL_TASKDESKTOP         = 3,
  31. };
  32. #define MAX_TASK_COLUMN      3
  33. #define NUM_TASK_COLUMN      (MAX_TASK_COLUMN + 1)
  34. #define IDS_FIRSTTASKCOL    21000       // 21000 is first column name ID in rc file
  35. //
  36. // Column ID on which to sort in the listview, and for
  37. // compares in general
  38. //
  39. TASKCOLUMNID g_iTaskSortColumnID  = COL_TASKNAME;
  40. INT          g_iTaskSortDirection = 1;          // 1 = asc, -1 = desc
  41. //
  42. // Column Default Info
  43. //
  44. struct 
  45. {
  46.     INT Format;
  47.     INT Width;
  48. } TaskColumnDefaults[NUM_TASK_COLUMN] =
  49. {
  50.     { LVCFMT_LEFT,       250},       // COL_TASKNAME
  51.     { LVCFMT_LEFT,       97 },      // COL_TASKSTATUS       
  52.     { LVCFMT_LEFT,       70 },       // COL_TASKWINSTATION
  53.     { LVCFMT_LEFT,       70 },       // COL_TASKDESKTOP   
  54. };
  55. //
  56. // Active Columns
  57. //
  58. TASKCOLUMNID g_ActiveTaskCol[NUM_TASK_COLUMN + 1] =
  59. {
  60.     COL_TASKNAME,     
  61. //  COL_TASKDESKTOP,
  62.     COL_TASKSTATUS,
  63.     (TASKCOLUMNID) -1
  64. };
  65. /*++ class CTaskInfo
  66. Class Description:
  67.     Represents the last known information about a running task
  68. Arguments:
  69. Return Value:
  70. Revision History:
  71.       Nov-29-95 Davepl  Created
  72. --*/
  73. class CTaskInfo
  74. {
  75. public:
  76.     HWND            m_hwnd;
  77.     LPTSTR          m_pszWindowTitle;
  78.     LPTSTR          m_lpWinsta;
  79.     LPTSTR          m_lpDesktop;
  80.     BOOL            m_fHung;
  81.     LARGE_INTEGER   m_uPassCount;
  82.     INT             m_iSmallIcon;
  83.     HICON           m_hSmallIcon;
  84.     INT             m_iLargeIcon;
  85.     HICON           m_hLargeIcon;
  86.     //
  87.     // This is a union of which attribute is dirty.  You can look at
  88.     // or set any particular column's bit, or just inspect m_fDirty
  89.     // to see if anyone at all is dirty.  Used to optimize listview
  90.     // painting
  91.     //
  92.     union
  93.     {
  94.         DWORD                m_fDirty;
  95.         struct 
  96.         {
  97.             DWORD            m_fDirty_COL_HWND           :1;
  98.             DWORD            m_fDirty_COL_TITLE          :1;
  99.             DWORD            m_fDirty_COL_STATUS         :1;
  100.             DWORD            m_fDirty_COL_WINSTA         :1;
  101.             DWORD            m_fDirty_COL_DESKTOP        :1;
  102.         };                                                
  103.     };
  104.     HRESULT        SetData(HWND                         hwnd,
  105.                            LPTSTR                       lpTitle,
  106.                            LPTSTR                       lpWinsta,
  107.                            LPTSTR                       lpDesktop,
  108.                            LARGE_INTEGER                uPassCount,
  109.                            BOOL                         fUpdateOnly);
  110.     CTaskInfo()
  111.     {
  112.         ZeroMemory(this, sizeof(*this));
  113.     }
  114.     ~CTaskInfo()
  115.     {
  116.         if (m_pszWindowTitle)
  117.         {
  118.             LocalFree(m_pszWindowTitle);
  119.         }
  120.         if (m_lpWinsta)
  121.         {
  122.             LocalFree(m_lpWinsta);
  123.         }
  124.         if (m_lpDesktop)
  125.         {
  126.             LocalFree(m_lpDesktop);
  127.         }
  128.     }
  129.     INT Compare(CTaskInfo * pOther);
  130. };
  131. /*++ class CTaskInfo::Compare
  132. Class Description:
  133.     Compares this CTaskInfo object to another, and returns its ranking
  134.     based on the g_iTaskSortColumnID field.
  135.     Note that if the objects are equal based on the current sort column,
  136.     the HWND is used as a secondary sort key to prevent items from 
  137.     jumping around in the listview
  138. Arguments:
  139.     pOther  - the CTaskInfo object to compare this to
  140. Return Value:
  141.     < 0      - This CTaskInfo is "less" than the other
  142.       0      - Equal (Can't happen, since HWND is secondary sort)
  143.     > 0      - This CTaskInfo is "greater" than the other
  144. Revision History:
  145.       Nov-29-95 Davepl  Created
  146. --*/
  147. INT CTaskInfo::Compare(CTaskInfo * pOther)
  148. {
  149.     INT iRet;
  150.     switch (g_iTaskSortColumnID)
  151.     {
  152.         case COL_TASKNAME:
  153.             iRet = lstrcmpi(this->m_pszWindowTitle, pOther->m_pszWindowTitle);
  154.             break;
  155.         case COL_TASKWINSTATION:
  156.             iRet = lstrcmpi(this->m_lpWinsta, pOther->m_lpWinsta);
  157.             break;
  158.         case COL_TASKDESKTOP:
  159.             iRet = lstrcmpi(this->m_lpDesktop, pOther->m_lpDesktop);
  160.             break;
  161.         case COL_TASKSTATUS:
  162.             iRet = Compare64(this->m_fHung, pOther->m_fHung);
  163.             break;
  164.         default:
  165.             
  166.             Assert(0 && "Invalid task sort column");
  167.             iRet = 0;
  168.     }
  169.     // If objects look equal, compare on HWND as secondary sort column
  170.     // so that items don't jump around in the listview
  171.     if (0 == iRet)
  172.     {
  173.         iRet = Compare64((LPARAM)this->m_hwnd, (LPARAM)pOther->m_hwnd);
  174.     }
  175.     return (iRet * g_iTaskSortDirection);
  176. }
  177. // REVIEW (Davepl) The next three functions have very close parallels
  178. // in the process page code.  Consider generalizing them to eliminate
  179. // duplication
  180. /*++ InsertIntoSortedArray
  181. Class Description:
  182.     Sticks a CTaskInfo ptr into the ptrarray supplied at the
  183.     appropriate location based on the current sort column (which
  184.     is used by the Compare member function)
  185. Arguments:
  186.     pArray      - The CPtrArray to add to
  187.     pProc       - The CTaskInfo object to add to the array
  188. Return Value:
  189.     TRUE if successful, FALSE if fails
  190. Revision History:
  191.       Nov-20-95 Davepl  Created
  192. --*/
  193. // REVIEW (davepl) Use binary insert here, not linear
  194. BOOL InsertIntoSortedArray(CPtrArray * pArray, CTaskInfo * pTask)
  195. {
  196.     
  197.     INT cItems = pArray->GetSize();
  198.     
  199.     for (INT iIndex = 0; iIndex < cItems; iIndex++)
  200.     {
  201.         CTaskInfo * pTmp = (CTaskInfo *) pArray->GetAt(iIndex);
  202.         
  203.         if (pTask->Compare(pTmp) < 0)
  204.         {
  205.             return pArray->InsertAt(iIndex, pTask);
  206.         }
  207.     }
  208.     return pArray->Add(pTask);
  209. }
  210. /*++ ResortTaskArray
  211. Function Description:
  212.     Creates a new ptr array sorted in the current sort order based
  213.     on the old array, and then replaces the old with the new
  214. Arguments:
  215.     ppArray     - The CPtrArray to resort
  216. Return Value:
  217.     TRUE if successful, FALSE if fails
  218. Revision History:
  219.       Nov-21-95 Davepl  Created
  220. --*/
  221. BOOL ResortTaskArray(CPtrArray ** ppArray)
  222. {
  223.     // Create a new array which will be sorted in the new 
  224.     // order and used to replace the existing array
  225.     CPtrArray * pNew = new CPtrArray(GetProcessHeap());
  226.     if (NULL == pNew)
  227.     {
  228.         return FALSE;
  229.     }
  230.     // Insert each of the existing items in the old array into
  231.     // the new array in the correct spot
  232.     INT cItems = (*ppArray)->GetSize();
  233.     for (int i = 0; i < cItems; i++)
  234.     {
  235.         CTaskInfo * pItem = (CTaskInfo *) (*ppArray)->GetAt(i);
  236.         if (FALSE == InsertIntoSortedArray(pNew, pItem))
  237.         {
  238.             delete pNew;
  239.             return FALSE;
  240.         }
  241.     }
  242.     // Kill off the old array, replace it with the new
  243.     delete (*ppArray);
  244.     (*ppArray) = pNew;
  245.     return TRUE;
  246. }
  247. /*++ CTaskPage::~CTaskPage()
  248.      Destructor
  249. */
  250. CTaskPage::~CTaskPage()
  251. {
  252.     RemoveAllTasks();
  253.     delete m_pTaskArray;
  254. }
  255. void CTaskPage::RemoveAllTasks()
  256. {
  257.     if (m_pTaskArray)
  258.     {
  259.         INT c = m_pTaskArray->GetSize();
  260.         while (c)
  261.         {
  262.             delete (CTaskInfo *) (m_pTaskArray->GetAt(c - 1));
  263.             c--;
  264.         }
  265.     }
  266. }
  267. /*++ CTaskPage::UpdateTaskListview
  268. Class Description:
  269.     Walks the listview and checks to see if each line in the
  270.     listview matches the corresponding entry in our process
  271.     array.  Those which differe by HWND are replaced, and those
  272.     that need updating are updated.
  273.     Items are also added and removed to/from the tail of the
  274.     listview as required.
  275.     
  276. Arguments:
  277. Return Value:
  278.     HRESULT
  279. Revision History:
  280.       Nov-29-95 Davepl  Created
  281. --*/
  282. HRESULT CTaskPage::UpdateTaskListview()
  283. {
  284.     HWND hListView = GetDlgItem(m_hPage, IDC_TASKLIST);
  285.     // Stop repaints while we party on the listview
  286.     SendMessage(hListView, WM_SETREDRAW, FALSE, 0);
  287.      // If the view mode has changed, update it now
  288.     if (m_vmViewMode != g_Options.m_vmViewMode)
  289.     {
  290.         m_vmViewMode = g_Options.m_vmViewMode;
  291.         DWORD dwStyle = GetWindowLong(hListView, GWL_STYLE);
  292.         dwStyle &= ~(LVS_TYPEMASK);
  293.         
  294.         if (g_Options.m_vmViewMode == VM_SMALLICON)
  295.         {
  296.             ListView_SetImageList(hListView, m_himlSmall, LVSIL_SMALL);
  297.             dwStyle |= LVS_SMALLICON | LVS_AUTOARRANGE;
  298.         }
  299.         else if (g_Options.m_vmViewMode == VM_DETAILS)
  300.         {
  301.             ListView_SetImageList(hListView, m_himlSmall, LVSIL_SMALL);
  302.             dwStyle |= LVS_REPORT;
  303.         }
  304.         else 
  305.         {
  306.             Assert(g_Options.m_vmViewMode == VM_LARGEICON);
  307.             ListView_SetImageList(hListView, m_himlLarge, LVSIL_NORMAL);
  308.             dwStyle |= LVS_ICON | LVS_AUTOARRANGE;
  309.         }
  310.         ListView_DeleteAllItems(hListView);
  311.         SetWindowLong(hListView, GWL_STYLE, dwStyle);
  312.     }
  313.     INT cListViewItems = ListView_GetItemCount(hListView);
  314.     INT CTaskArrayItems = m_pTaskArray->GetSize();
  315.     
  316.     //
  317.     // Walk the existing lines in the listview and replace/update
  318.     // them as needed
  319.     //
  320.     for (INT iCurrent = 0; 
  321.          iCurrent < cListViewItems && iCurrent < CTaskArrayItems; 
  322.          iCurrent++)
  323.     {
  324.         LV_ITEM lvitem = { 0 };
  325.         lvitem.mask = LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE;
  326.         lvitem.iItem = iCurrent;
  327.         if (FALSE == ListView_GetItem(hListView, &lvitem))
  328.         {
  329.             SendMessage(hListView, WM_SETREDRAW, TRUE, 0);
  330.             return E_FAIL;
  331.         }
  332.         CTaskInfo * pTmp = (CTaskInfo *) lvitem.lParam;
  333.         CTaskInfo * pTask = (CTaskInfo *) m_pTaskArray->GetAt(iCurrent);        
  334.         
  335.         if (pTmp != pTask || pTask->m_fDirty)
  336.         {
  337.             // If the objects aren't the same, we need to replace this line
  338.             lvitem.pszText = pTask->m_pszWindowTitle;
  339.             lvitem.lParam  = (LPARAM) pTask;
  340.             
  341.             if (g_Options.m_vmViewMode == VM_LARGEICON)
  342.             {
  343.                 lvitem.iImage  = pTask->m_iLargeIcon;
  344.             }
  345.             else
  346.             {
  347.                 lvitem.iImage  = pTask->m_iSmallIcon;
  348.             }
  349.             
  350.             ListView_SetItem(hListView, &lvitem);
  351.             ListView_RedrawItems(hListView, iCurrent, iCurrent);
  352.             pTask->m_fDirty = 0;
  353.         }
  354.     }
  355.     // 
  356.     // We've either run out of listview items or run out of Task array
  357.     // entries, so remove/add to the listview as appropriate
  358.     //
  359.     while (iCurrent < cListViewItems)
  360.     {
  361.         // Extra items in the listview (processes gone away), so remove them
  362.         ListView_DeleteItem(hListView, iCurrent);
  363.         cListViewItems--;
  364.     }
  365.     while (iCurrent < CTaskArrayItems)
  366.     {
  367.         // Need to add new items to the listview (new tasks appeared)
  368.         CTaskInfo * pTask = (CTaskInfo *)m_pTaskArray->GetAt(iCurrent);
  369.         LV_ITEM lvitem  = { 0 };
  370.         lvitem.mask     = LVIF_PARAM | LVIF_TEXT | LVIF_IMAGE;
  371.         lvitem.iItem    = iCurrent;
  372.         lvitem.pszText  = pTask->m_pszWindowTitle;
  373.         lvitem.lParam   = (LPARAM) pTask;
  374.         lvitem.iImage   = pTask->m_iLargeIcon;
  375.         // The first item added (actually, every 0 to 1 count transition) gets
  376.         // selected and focused
  377.         if (iCurrent == 0)
  378.         {
  379.             lvitem.state = LVIS_SELECTED | LVIS_FOCUSED;
  380.             lvitem.stateMask = lvitem.state;
  381.             lvitem.mask |= LVIF_STATE;
  382.         }
  383.                 
  384.         ListView_InsertItem(hListView, &lvitem);
  385.         pTask->m_fDirty = 0;
  386.         iCurrent++;        
  387.     }    
  388.     // Let the listview paint again
  389.     SendMessage(hListView, WM_SETREDRAW, TRUE, 0);
  390.     return S_OK;
  391. }
  392. /*++ CTasKPage::EnsureWindowsNotMinimized
  393. Routine Description:
  394.     Walks an array of HWNDS and ensure the windows are not
  395.     minimized, which would prevent them from being 
  396.     cascaded to tiles properly
  397.     
  398. Arguments:
  399.     aHwnds - Array of window handles
  400.     dwCount- Number of HWNDS in table
  401. Return Value:
  402. Revision History:
  403.       Dec-06-95 Davepl  Created
  404. --*/
  405. void CTaskPage::EnsureWindowsNotMinimized(HWND aHwnds[], DWORD dwCount)
  406. {
  407.     for (UINT i = 0; i < dwCount; i++)
  408.     {
  409.         if (IsIconic(aHwnds[i]))
  410.         {
  411.             ShowWindow(aHwnds[i], SW_RESTORE);
  412.         }
  413.     }
  414. }
  415. /*++ CTaslPage::GetSelectedHWNDS
  416. Routine Description:
  417.     Returns a dynamically allocated array of HWNDS based on the
  418.     ones selected in the task list
  419.     
  420. Arguments:
  421.     pdwCount- Number of HWNDS in t`able
  422. Return Value:
  423.     HWND[], or NULL on failure
  424. Revision History:
  425.       Dec-05-95 Davepl  Created
  426. --*/
  427. HWND * CTaskPage::GetHWNDS(BOOL fSelectedOnly, DWORD * pdwCount)
  428. {
  429.     CPtrArray * pArray = NULL;
  430.     if (fSelectedOnly)
  431.     {
  432.         // If we only want selected tasks, go and get the array
  433.         // of selected listview tasks
  434.         pArray = GetSelectedTasks();
  435.         if (NULL == pArray)
  436.         {
  437.             return NULL;
  438.         }
  439.     }
  440.     else
  441.     {
  442.         // If we want everything, just make a copy of the TaskArray
  443.         pArray = new CPtrArray(GetProcessHeap());
  444.         if (FALSE == pArray->Copy(*m_pTaskArray))
  445.         {
  446.             delete pArray;
  447.             *pdwCount = 0;
  448.             return FALSE;
  449.         }
  450.     }
  451.     //
  452.     // No windows to speak of, so bail
  453.     //
  454.     *pdwCount = pArray->GetSize();
  455.     if (*pdwCount == 0)
  456.     {
  457.         delete pArray;
  458.         return NULL;
  459.     }
  460.     HWND * pHwnds = (HWND *) LocalAlloc(0, *pdwCount * sizeof(HWND));
  461.     if (NULL == pHwnds)
  462.     {
  463.         *pdwCount = 0;
  464.     }
  465.     else
  466.     {
  467.         for (UINT i = 0; i < *pdwCount; i++)
  468.         {
  469.             pHwnds[i] = (((CTaskInfo *) (pArray->GetAt(i)) )->m_hwnd);
  470.         }
  471.     }
  472.     delete pArray;
  473.     return pHwnds;
  474. }
  475. /*++ CTaskPage::GetSelectedTasks
  476. Routine Description:
  477.     Returns a CPtrArray of the selected tasks
  478.     
  479. Arguments:
  480. Return Value:
  481.     CPtrArray on success, NULL on failure
  482. Revision History:
  483.       Dec-01-95 Davepl  Created
  484. --*/
  485. CPtrArray * CTaskPage::GetSelectedTasks()
  486. {
  487.     BOOL fSuccess = TRUE;
  488.     //
  489.     // Get the count of selected items
  490.     //
  491.     HWND hTaskList = GetDlgItem(m_hPage, IDC_TASKLIST);
  492.     INT cItems = ListView_GetSelectedCount(hTaskList);
  493.     if (0 == cItems)
  494.     {
  495.         return NULL;
  496.     }
  497.     //
  498.     // Create a CPtrArray to hold the task items
  499.     //
  500.     CPtrArray * pArray = new CPtrArray(GetProcessHeap());
  501.     if (NULL == pArray)
  502.     {
  503.         return NULL;
  504.     }
  505.     INT iLast = -1;
  506.     for (INT i = 0; i < cItems; i++)
  507.     {
  508.         //
  509.         // Get the Nth selected item
  510.         // 
  511.         INT iItem = ListView_GetNextItem(hTaskList, iLast, LVNI_SELECTED);
  512.         if (-1 == iItem)
  513.         {
  514.             fSuccess = FALSE;
  515.             break;
  516.         }
  517.         iLast = iItem;
  518.         //
  519.         // Pull the item from the listview and add it to the selected array
  520.         //
  521.         LV_ITEM lvitem = { LVIF_PARAM };
  522.         lvitem.iItem = iItem;
  523.     
  524.         if (ListView_GetItem(hTaskList, &lvitem))
  525.         {
  526.             LPVOID pTask = (LPVOID) (lvitem.lParam);
  527.             if (FALSE == pArray->Add(pTask))
  528.             {
  529.                 fSuccess = FALSE;
  530.                 break;
  531.             }
  532.         }
  533.         else
  534.         {
  535.             fSuccess = FALSE;
  536.             break;
  537.         }
  538.     }
  539.     //
  540.     // Any errors, clean up the array and bail.  We don't release the
  541.     // tasks in the array, since they are owned by the listview.
  542.     //
  543.     if (FALSE == fSuccess && NULL != pArray)
  544.     {
  545.         delete pArray;
  546.         return NULL;
  547.     }
  548.     return pArray;
  549. }
  550. /*++ CProcPage::HandleTaskListContextMenu
  551. Routine Description:
  552.     Handles right-clicks (context menu) in the task list
  553.     
  554. Arguments:
  555.     xPos, yPos  - coords of where the click occurred
  556. Return Value:
  557. Revision History:
  558.       Dec-01-95 Davepl  Created
  559. --*/
  560. void CTaskPage::HandleTaskListContextMenu(INT xPos, INT yPos)
  561. {
  562.     HWND hTaskList = GetDlgItem(m_hPage, IDC_TASKLIST);
  563.     CPtrArray * pArray = GetSelectedTasks();
  564.     if (pArray)
  565.     {
  566.         // If non-mouse-based context menu, use the currently selected
  567.         // item as the coords
  568.         if (0xFFFF == LOWORD(xPos) && 0xFFFF == LOWORD(yPos))
  569.         {
  570.             int iSel = ListView_GetNextItem(hTaskList, -1, LVNI_SELECTED);
  571.             RECT rcItem;
  572.             ListView_GetItemRect(hTaskList, iSel, &rcItem, LVIR_ICON);
  573.             MapWindowRect(hTaskList, NULL, &rcItem);
  574.             xPos = rcItem.right;
  575.             yPos = rcItem.bottom;
  576.         }
  577.         HMENU hPopup = LoadPopupMenu(g_hInstance, IDR_TASK_CONTEXT);
  578.         if (hPopup)
  579.         {
  580.             SetMenuDefaultItem(hPopup, IDM_TASK_SWITCHTO, FALSE);
  581.             //
  582.             // If single-selection, disable the items that require multiple
  583.             // selections to make sense
  584.             //
  585.             if (pArray->GetSize() < 2)
  586.             {
  587.                 EnableMenuItem(hPopup, IDM_TASK_CASCADE, MF_GRAYED | MF_DISABLED | MF_BYCOMMAND);
  588.                 EnableMenuItem(hPopup, IDM_TASK_TILEHORZ, MF_GRAYED | MF_DISABLED | MF_BYCOMMAND);
  589.                 EnableMenuItem(hPopup, IDM_TASK_TILEVERT, MF_GRAYED | MF_DISABLED | MF_BYCOMMAND);
  590.             }
  591.             EnableMenuItem(hPopup, IDM_TASK_BRINGTOFRONT, MF_BYCOMMAND | ((pArray->GetSize() == 1) ? MF_ENABLED : (MF_DISABLED | MF_GRAYED)));
  592.             Pause();
  593.             g_fInPopup = TRUE;
  594.             TrackPopupMenuEx(hPopup, 0, xPos, yPos, m_hPage, NULL);
  595.             g_fInPopup = FALSE;
  596.             // Note that we don't "unpause" until one of the menu commands (incl CANCEL) is
  597.             // selected or the menu is dismissed
  598.         
  599.             DestroyMenu(hPopup);
  600.         }
  601.         delete pArray;
  602.     }
  603.     else
  604.     {
  605.         HMENU hPopup = LoadPopupMenu(g_hInstance, IDR_TASKVIEW);
  606.         if (hPopup && SHRestricted(REST_NORUN))
  607.         {
  608.             DeleteMenu(hPopup, IDM_RUN, MF_BYCOMMAND);
  609.         }
  610.         UINT id;
  611.         if (m_vmViewMode == VM_LARGEICON)
  612.         {
  613.             id = IDM_LARGEICONS;
  614.         } 
  615.         else if (m_vmViewMode == VM_SMALLICON)
  616.         {
  617.             id = IDM_SMALLICONS;
  618.         }
  619.         else
  620.         {
  621.             Assert(m_vmViewMode == VM_DETAILS);
  622.             id = IDM_DETAILS;
  623.         }
  624.         if (hPopup)
  625.         {
  626.             CheckMenuRadioItem(hPopup, IDM_LARGEICONS, IDM_DETAILS, id, MF_BYCOMMAND);
  627.             g_fInPopup = TRUE;
  628.             TrackPopupMenuEx(hPopup, 0, xPos, yPos, m_hPage, NULL);
  629.             g_fInPopup = FALSE;
  630.             DestroyMenu(hPopup);
  631.         }
  632.     }
  633. }
  634. /*++ CTaskPage::UpdateUIState
  635. Routine Description:
  636.     Updates the enabled/disabled states, etc., of the task UI
  637.     
  638. Arguments:
  639. Return Value:
  640. Revision History:
  641.       Dec-04-95 Davepl  Created
  642. --*/
  643. // Controls which are enabled only for any selection
  644. static const UINT g_aSingleIDs[] =
  645. {
  646.     IDC_ENDTASK,
  647.     IDC_SWITCHTO,
  648. };
  649. void CTaskPage::UpdateUIState()
  650. {
  651.     INT i;
  652.     
  653.     // Set the state for controls which require a selection (1 or more items)
  654.     for (i = 0; i < ARRAYSIZE(g_aSingleIDs); i++)
  655.     {
  656.         EnableWindow(GetDlgItem(m_hPage, g_aSingleIDs[i]), m_cSelected > 0);
  657.     }    
  658.     if (g_Options.m_iCurrentPage == 0)
  659.     {
  660.         CPtrArray * pArray = GetSelectedTasks();
  661.         if (pArray)
  662.         {
  663.             UINT state;
  664.             if (pArray->GetSize() == 1)
  665.             {
  666.                 state = MF_GRAYED | MF_DISABLED;
  667.             }
  668.             else
  669.             {
  670.                 state = MF_ENABLED;
  671.             }
  672.             HMENU hMain  = GetMenu(g_hMainWnd);
  673.             EnableMenuItem(hMain , IDM_TASK_CASCADE, state | MF_BYCOMMAND);
  674.             EnableMenuItem(hMain , IDM_TASK_TILEHORZ, state | MF_BYCOMMAND);
  675.             EnableMenuItem(hMain , IDM_TASK_TILEVERT, state | MF_BYCOMMAND);
  676.             EnableMenuItem(hMain, IDM_TASK_BRINGTOFRONT, MF_BYCOMMAND | ((pArray->GetSize() == 1) ? MF_ENABLED : (MF_DISABLED | MF_GRAYED)));
  677.             delete pArray;
  678.         }
  679.     }
  680. }
  681. /*++ CTaskPage::HandleTaskPageNotify
  682. Routine Description:
  683.     Processes WM_NOTIFY messages received by the taskpage dialog
  684.     
  685. Arguments:
  686.     hWnd    - Control that generated the WM_NOTIFY
  687.     pnmhdr  - Ptr to the NMHDR notification stucture
  688. Return Value:
  689.     BOOL "did we handle it" code
  690. Revision History:
  691.       Nov-29-95 Davepl  Created
  692. --*/
  693. INT CTaskPage::HandleTaskPageNotify(HWND hWnd, LPNMHDR pnmhdr)
  694. {
  695.     switch(pnmhdr->code)
  696.     {
  697.         case NM_DBLCLK:
  698.         {
  699.             SendMessage(m_hPage, WM_COMMAND, IDC_SWITCHTO, 0);
  700.             break;    
  701.         }
  702.         // If the (selection) state of an item is changing, see if
  703.         // the count has changed, and if so, update the UI
  704.         case LVN_ITEMCHANGED:
  705.         {
  706.             const NM_LISTVIEW * pnmv = (const NM_LISTVIEW *) pnmhdr;
  707.             if (pnmv->uChanged & LVIF_STATE)
  708.             {
  709.                 UINT cSelected = ListView_GetSelectedCount(GetDlgItem(m_hPage, IDC_TASKLIST));
  710.                 if (cSelected != m_cSelected)
  711.                 {
  712.                     m_cSelected = cSelected;
  713.                     UpdateUIState();
  714.                 }
  715.             }
  716.             break;
  717.         }
  718.         case LVN_COLUMNCLICK:
  719.         {
  720.             // User clicked a header control, so set the sort column.  If its the
  721.             // same as the current sort column, just invert the sort direction in
  722.             // the column.  Then resort the task array
  723.             const NM_LISTVIEW * pnmv = (const NM_LISTVIEW *) pnmhdr;
  724.             
  725.             if (g_iTaskSortColumnID == g_ActiveTaskCol[pnmv->iSubItem])
  726.             {
  727.                 g_iTaskSortDirection  *= -1;
  728.             }
  729.             else
  730.             {
  731.                 g_iTaskSortColumnID = g_ActiveTaskCol[pnmv->iSubItem];
  732.                 g_iTaskSortDirection  = -1;
  733.             }
  734.             ResortTaskArray(&m_pTaskArray);
  735.             TimerEvent();
  736.             break;
  737.         }
  738.         case LVN_GETDISPINFO:
  739.         {
  740.             LV_ITEM * plvitem = &(((LV_DISPINFO *) pnmhdr)->item);
  741.             
  742.             // Listview needs a text string
  743.             if (plvitem->mask & LVIF_TEXT)
  744.             {
  745.                 TASKCOLUMNID columnid = (TASKCOLUMNID) g_ActiveTaskCol[plvitem->iSubItem];
  746.                 const CTaskInfo  * pTaskInfo   = (const CTaskInfo *)   plvitem->lParam;
  747.                 switch(columnid)
  748.                 {
  749.                     case COL_TASKNAME:
  750.                         lstrcpyn(plvitem->pszText, pTaskInfo->m_pszWindowTitle, plvitem->cchTextMax);
  751.                         plvitem->mask |= LVIF_DI_SETITEM;
  752.                         break;
  753.                     case COL_TASKSTATUS:
  754.                     {
  755.                         if (pTaskInfo->m_fHung)
  756.                         {
  757.                             lstrcpyn(plvitem->pszText, g_szHung, plvitem->cchTextMax);
  758.                         }
  759.                         else
  760.                         {
  761.                             lstrcpyn(plvitem->pszText, g_szRunning, plvitem->cchTextMax);
  762.                         }
  763.                         break;
  764.                     }
  765.                     case COL_TASKWINSTATION:
  766.                         lstrcpyn(plvitem->pszText, pTaskInfo->m_lpWinsta, plvitem->cchTextMax);
  767.                         plvitem->mask |= LVIF_DI_SETITEM;
  768.                         break;
  769.                     case COL_TASKDESKTOP:
  770.                         lstrcpyn(plvitem->pszText, pTaskInfo->m_lpDesktop, plvitem->cchTextMax);
  771.                         plvitem->mask |= LVIF_DI_SETITEM;
  772.                         break;
  773.                     default:
  774.                         Assert( 0 && "Unknown listview subitem" );
  775.                         break;
  776.                 } // end switch(columnid)
  777.             } // end LVIF_TEXT case
  778.         } // end LVN_GETDISPINFO case
  779.     
  780.     } // end switch(pnmhdr->code)
  781.     return 1;
  782. }
  783. /*++ DoEnumWindowStations
  784. Routine Description:
  785.     Does an EnumWindowStations on a new thread, since the thread needs
  786.     to bop around to various window stations, which isn't allow for the
  787.     main thread since it owns windows.
  788.     This app is really single-threaded, and written with assumptions
  789.     based on that, so the calling thread blocks until the new thread
  790.     has completed the job.
  791.     
  792. Arguments:
  793.     Same as EnumWindowStations
  794. Return Value:
  795.     Same as EnumWindowStations
  796. Revision History:
  797.       Nov-29-95 Davepl  Created
  798. --*/
  799. DWORD WorkerThread(LPVOID pv)
  800. {
  801.     THREADPARAM * ptp = (THREADPARAM *) pv;
  802.     while(1)
  803.     {
  804.         // Wait for a signal from the main thread before proceeding
  805.         WaitForSingleObject(ptp->m_hEventChild, INFINITE);
  806.         // If we are flagged for shutdown, exit now.  Main thread will
  807.         // be waiting on the event for us to signal that we are done with
  808.         // the THREADPARAM block
  809.         if (ptp->m_fThreadExit)
  810.         {
  811.             SetEvent(ptp->m_hEventParent);
  812.             return 0;
  813.         }
  814.         ptp->m_fSuccess = EnumWindowStations(ptp->m_lpEnumFunc, ptp->m_lParam);
  815.         SetEvent(ptp->m_hEventParent);
  816.     }
  817. }
  818. BOOL CTaskPage::DoEnumWindowStations(WINSTAENUMPROC lpEnumFunc, LPARAM lParam)
  819. {
  820.     DWORD dwThreadId;
  821.     
  822.     if (NULL == m_hEventChild)
  823.     {
  824.         m_hEventChild = CreateEvent(NULL, FALSE, FALSE, NULL);
  825.         if (NULL == m_hEventChild)
  826.         {
  827.             return FALSE;
  828.         }
  829.     }
  830.     if (NULL == m_hEventParent)
  831.     {
  832.         m_hEventParent = CreateEvent(NULL, FALSE, FALSE, NULL);
  833.         if (NULL == m_hEventParent)
  834.         {
  835.             return FALSE;
  836.         }
  837.     }
  838.     // Save the args away for the worker thread to pick up when it starts
  839.     
  840.     m_tp.m_lpEnumFunc   = lpEnumFunc;
  841.     m_tp.m_lParam       = lParam;
  842.     m_tp.m_hEventChild  = m_hEventChild;
  843.     m_tp.m_hEventParent = m_hEventParent;
  844.     m_tp.m_fThreadExit  = FALSE;
  845.     if (NULL == m_hThread)
  846.     {
  847.         // Run the function call on this new thread, and wait for completion
  848.         m_hThread = CreateThread(NULL, 0, WorkerThread, (LPVOID) &m_tp, 0, &dwThreadId);
  849.         if (NULL == m_hThread)
  850.         {
  851.             return FALSE;
  852.         }
  853.     }
  854.     SetEvent(m_hEventChild);
  855.     WaitForSingleObject(m_hEventParent, INFINITE);
  856.     // Return the result from the worker thread
  857.     return (BOOL) m_tp.m_fSuccess;
  858. }
  859.    
  860. /*++ CTaskPage::TimerEvent
  861. Routine Description:
  862.     Called by main app when the update time fires.  Walks every window
  863.     in the system (on every desktop, in every windowstation) and adds
  864.     or updates it in the task array, then removes any stale processes,
  865.     and filters the results into the listview
  866.     
  867. Arguments:
  868. Return Value:
  869. Revision History:
  870.       Nov-29-95 Davepl  Created
  871. --*/
  872. VOID CTaskPage::TimerEvent()
  873. {
  874.     //
  875.     // If this page is paused (ie: it has a context menu up, etc), we do
  876.     // nothing
  877.     //
  878.     if (m_fPaused)
  879.     {
  880.         return;
  881.     }
  882.     static LARGE_INTEGER uPassCount = {0, 0};
  883.     TASK_LIST_ENUM te;
  884.     
  885.     te.m_pTasks = m_pTaskArray;
  886.     te.m_pPage  = this;
  887.     te.lpWinsta = NULL;
  888.     te.lpDesk   = NULL;
  889.     te.uPassCount.QuadPart = uPassCount.QuadPart;
  890.     //
  891.     // enumerate all windows and try to get the window
  892.     // titles for each task
  893.     //
  894.     
  895.     if ( DoEnumWindowStations( EnumWindowStationsFunc, (LPARAM) &te ))
  896.     {
  897.         INT i = 0;
  898.         while (i < m_pTaskArray->GetSize())
  899.         {
  900.             CTaskInfo * pTaskInfo = (CTaskInfo *)(m_pTaskArray->GetAt(i));
  901.             ASSERT(pTaskInfo);
  902.             //
  903.             // If passcount doesn't match, delete the CTaskInfo instance and remove
  904.             // its pointer from the array.  Note that we _don't_ increment the index
  905.             // if we remove an element, since the next element would now live at
  906.             // the current index after the deletion
  907.             //
  908.             if (pTaskInfo->m_uPassCount.QuadPart != uPassCount.QuadPart)
  909.             {
  910.                 // Find out what icons this task was using
  911.                 INT iLargeIcon = pTaskInfo->m_iLargeIcon;
  912.                 INT iSmallIcon = pTaskInfo->m_iSmallIcon;
  913.                 // Remove the task from the task array
  914.                 delete pTaskInfo;
  915.                 m_pTaskArray->RemoveAt(i, 1);
  916.                 // Remove its images from the imagelist
  917.                 if (iSmallIcon > 0)
  918.                 {
  919.                     VERIFY( ImageList_Remove(m_himlSmall, iSmallIcon) );
  920.                 }
  921.                 if (iLargeIcon > 0)
  922.                 {
  923.                     VERIFY( ImageList_Remove(m_himlLarge, iLargeIcon) );
  924.                 }
  925.                 // Fix up the icon indexes for any other tasks (whose icons were
  926.                 // at a higher index than the deleted process, and hence now shifted)
  927.                 for (int iTmp = 0; iTmp < m_pTaskArray->GetSize(); iTmp++)
  928.                 {
  929.                     CTaskInfo * pTaskTmp = (CTaskInfo *)(m_pTaskArray->GetAt(iTmp));
  930.                     
  931.                     if (iLargeIcon && pTaskTmp->m_iLargeIcon > iLargeIcon)
  932.                     {
  933.                         pTaskTmp->m_iLargeIcon--;
  934.                     }
  935.                     if (iSmallIcon && pTaskTmp->m_iSmallIcon > iSmallIcon)
  936.                     {
  937.                         pTaskTmp->m_iSmallIcon--;
  938.                     }
  939.                 }
  940.             }
  941.             else
  942.             {
  943.                 i++;
  944.             }
  945.         }
  946.         // Selectively filter the new array into the task listview
  947.         UpdateTaskListview();
  948.     }
  949.     if (te.lpWinsta)
  950.     {
  951.         LocalFree(te.lpWinsta);
  952.     }
  953.     if (te.lpDesk)
  954.     {
  955.         LocalFree(te.lpDesk);
  956.     }
  957.     g_cTasks = m_pTaskArray->GetSize();
  958.     uPassCount.QuadPart++;
  959. }
  960. /*++ class CTaskInfo::SetData
  961. Class Description:
  962.     Updates (or initializes) the info about a running task
  963. Arguments:
  964.     hwnd      - taks's hwnd
  965.     lpTitle   - Window title
  966.     uPassCount- Current passcount, used to timestamp the last update of 
  967.                 this object
  968.     lpDesktop - task's current desktop
  969.     lpWinsta  - task's current windowstation
  970.     fUpdate   - only worry about information that can change during a
  971.                 task's lifetime
  972. Return Value:
  973.     HRESULT
  974. Revision History:
  975.       Nov-16-95 Davepl  Created
  976. --*/
  977. HRESULT CTaskInfo::SetData(HWND                         hwnd,
  978.                            LPTSTR                       lpTitle,
  979.                            LPTSTR                       lpWinsta,
  980.                            LPTSTR                       lpDesktop,
  981.                            LARGE_INTEGER                uPassCount,
  982.                            BOOL                         fUpdateOnly)
  983. {
  984.     HRESULT hr = S_OK;
  985.         // Touch this CTaskInfo to indicate that it's still alive
  986.         m_uPassCount.QuadPart = uPassCount.QuadPart;
  987.     //
  988.     // For each of the fields, we check to see if anything has changed, and if
  989.     // so, we mark that particular column as having changed, and update the value.
  990.     // This allows me to opimize which fields of the listview to repaint, since
  991.     // repainting an entire listview column causes flicker and looks bad in
  992.     // general
  993.     //
  994.     // Window Station
  995.     if (!fUpdateOnly || lstrcmp(m_lpWinsta, lpWinsta))
  996.     {
  997.         if (m_lpWinsta)
  998.             LocalFree(m_lpWinsta);
  999.         m_lpWinsta = (LPTSTR) LocalAlloc( 0, (lstrlen(lpWinsta) + 1) * sizeof(TCHAR));
  1000.         if (NULL == m_lpWinsta)
  1001.         {
  1002.             return E_OUTOFMEMORY;
  1003.         }
  1004.         else
  1005.         {
  1006.             lstrcpy(m_lpWinsta, lpWinsta);
  1007.         }
  1008.         m_fDirty_COL_WINSTA = TRUE;
  1009.         // dprintf(TEXT("Winsta changed: %s from %s to %sn"), m_pszWindowTitle, m_lpWinsta, lpWinsta);
  1010.     }
  1011.     // Desktop
  1012.     if (!fUpdateOnly || lstrcmp(m_lpDesktop, lpDesktop))
  1013.     {
  1014.         if (m_lpDesktop)
  1015.             LocalFree(m_lpDesktop);
  1016.         m_lpDesktop = (LPTSTR) LocalAlloc( 0, (lstrlen(lpDesktop) + 1) * sizeof(TCHAR));
  1017.         if (NULL == m_lpDesktop)
  1018.         {
  1019.             return E_OUTOFMEMORY;
  1020.         }
  1021.         else
  1022.         {
  1023.             lstrcpy(m_lpDesktop, lpDesktop);
  1024.         }
  1025.         m_fDirty_COL_DESKTOP = TRUE;
  1026.         // dprintf(TEXT("Desktop changed: %s from %s to %sn"), m_pszWindowTitle, m_lpDesktop, lpDesktop);
  1027.     }
  1028.     // Title
  1029.     if (!fUpdateOnly || lstrcmp(m_pszWindowTitle, lpTitle))
  1030.     {
  1031.         if (m_pszWindowTitle)
  1032.             LocalFree(m_pszWindowTitle);
  1033.         m_pszWindowTitle = (LPTSTR) LocalAlloc( 0, (lstrlen(lpTitle) + 1) * sizeof(TCHAR));
  1034.         if (NULL == m_pszWindowTitle)
  1035.         {
  1036.             return E_OUTOFMEMORY;
  1037.         }
  1038.         else
  1039.         {
  1040.             lstrcpy(m_pszWindowTitle, lpTitle);
  1041.         }
  1042.         m_fDirty_COL_TITLE = TRUE;
  1043.         // dprintf(TEXT("Title changed: %s from %s to %sn"), m_pszWindowTitle, m_pszWindowTitle, lpTitle);
  1044.     }
  1045.     // App status (hung / not hung)
  1046.     BOOL fHung = IsHungAppWindow(hwnd);
  1047.     if (fHung != m_fHung)
  1048.     {
  1049.         m_fHung = fHung;
  1050.         m_fDirty_COL_STATUS = TRUE;
  1051.         // dprintf(TEXT("Status changed: %sn"), m_pszWindowTitle);
  1052.     }
  1053.     // Window handle
  1054.     if (m_hwnd != hwnd)
  1055.     {
  1056.         m_hwnd = hwnd;
  1057.         m_fDirty_COL_HWND = TRUE;
  1058.         // dprintf(TEXT("Handle changed: %sn"), m_pszWindowTitle);
  1059.     }
  1060.     // Icons
  1061.     
  1062.     #define ICON_FETCH_TIMEOUT 100
  1063.     if (!fUpdateOnly)
  1064.     {
  1065.         m_hSmallIcon = NULL;
  1066.         m_hLargeIcon = NULL;
  1067.         if (!SendMessageTimeout(hwnd, WM_GETICON, 0, 0, 
  1068.                 SMTO_BLOCK | SMTO_ABORTIFHUNG, ICON_FETCH_TIMEOUT, (PULONG_PTR) &m_hSmallIcon)
  1069.             || NULL == m_hSmallIcon)
  1070.         {
  1071.             m_hSmallIcon = (HICON) GetClassLongPtr(hwnd, GCLP_HICONSM);
  1072.         }
  1073.         if (!SendMessageTimeout(hwnd, WM_GETICON, 1, 0, 
  1074.                 SMTO_BLOCK | SMTO_ABORTIFHUNG, ICON_FETCH_TIMEOUT, (PULONG_PTR) &m_hLargeIcon)
  1075.             || NULL == m_hLargeIcon)
  1076.         {
  1077.             m_hLargeIcon = (HICON) GetClassLongPtr(hwnd, GCLP_HICON);
  1078.         }
  1079.     }
  1080.     
  1081.     return S_OK;
  1082. }
  1083. /*++
  1084. Routine Description:
  1085.     Callback function for windowstation enumeration.
  1086. Arguments:
  1087.     lpstr            - windowstation name
  1088.     lParam           - ** not used **
  1089. Return Value:
  1090.     TRUE  - continues the enumeration
  1091. --*/
  1092. BOOL CALLBACK EnumWindowStationsFunc(LPTSTR  lpstr, LPARAM lParam)
  1093. {
  1094.     PTASK_LIST_ENUM   te = (PTASK_LIST_ENUM)lParam;
  1095.     HWINSTA           hwinsta;
  1096.     HWINSTA           hwinstaSave;
  1097.     DWORD             ec;
  1098.     //
  1099.     // open the windowstation
  1100.     //
  1101.     hwinsta = OpenWindowStation( lpstr, FALSE, MAXIMUM_ALLOWED );
  1102.     if (!hwinsta) 
  1103.     {
  1104.         // If we fail because we don't have sufficient access to this
  1105.         // desktop, we should continue the enumeration anyway.
  1106.         return TRUE;
  1107.     }
  1108.     //
  1109.     // save the current windowstation
  1110.     //
  1111.     hwinstaSave = GetProcessWindowStation();
  1112.     //
  1113.     // change the context to the new windowstation
  1114.     //
  1115.     if (!SetProcessWindowStation( hwinsta )) 
  1116.     {
  1117.         ec = GetLastError();
  1118.         SetProcessWindowStation( hwinstaSave );
  1119.         CloseWindowStation( hwinsta );
  1120.         
  1121.         if (hwinsta != hwinstaSave)
  1122.                 CloseWindowStation( hwinstaSave );
  1123.         
  1124.         return TRUE;
  1125.     }
  1126.     //
  1127.     // Update the windowstation in the enumerator
  1128.     //
  1129.     if (te->lpWinsta)
  1130.     {
  1131.         LocalFree(te->lpWinsta);
  1132.     }
  1133.     te->lpWinsta = (LPTSTR) LocalAlloc( 0, (lstrlen(lpstr) + 1) * sizeof(TCHAR));
  1134.     if (NULL == te->lpWinsta)
  1135.     {
  1136.         if (hwinsta != hwinstaSave) 
  1137.         {
  1138.             SetProcessWindowStation( hwinstaSave );
  1139.             CloseWindowStation( hwinsta );
  1140.         }
  1141.         CloseWindowStation( hwinstaSave );
  1142.         // We technically could continue, but if we're this strapped for
  1143.         // memory, there's not much point.  Let's bail on the winsta enumeration.
  1144.         return FALSE;
  1145.     }
  1146.     else
  1147.     {
  1148.         lstrcpy(te->lpWinsta, lpstr);
  1149.     }
  1150.     //
  1151.     // enumerate all the desktops for this windowstation
  1152.     //
  1153.     
  1154.     EnumDesktops( hwinsta, EnumDesktopsFunc, lParam );
  1155.     //
  1156.     // restore the context to the previous windowstation
  1157.     //
  1158.     if (hwinsta != hwinstaSave) 
  1159.     {
  1160.         SetProcessWindowStation( hwinstaSave );
  1161.         CloseWindowStation( hwinsta );
  1162.     }
  1163.     //
  1164.     // continue the enumeration
  1165.     //
  1166.     return TRUE;
  1167. }
  1168. /*++
  1169. Routine Description:
  1170.     Callback function for desktop enumeration.
  1171. Arguments:
  1172.     lpstr            - desktop name
  1173.     lParam           - ** not used **
  1174. Return Value:
  1175.     TRUE  - continues the enumeration
  1176. --*/
  1177. BOOL CALLBACK EnumDesktopsFunc(LPTSTR  lpstr, LPARAM lParam)
  1178. {
  1179.     PTASK_LIST_ENUM   te = (PTASK_LIST_ENUM)lParam;
  1180.     HDESK             hdeskSave;
  1181.     HDESK             hdesk;
  1182.     DWORD             ec;
  1183.     //
  1184.     // open the desktop
  1185.     //
  1186.     hdesk = OpenDesktop( lpstr, 0, FALSE, MAXIMUM_ALLOWED );
  1187.     if (!hdesk) 
  1188.     {
  1189.         return FALSE;
  1190.     }
  1191.     //
  1192.     // save the current desktop
  1193.     //
  1194.     hdeskSave = GetThreadDesktop( GetCurrentThreadId() );
  1195.     //
  1196.     // change the context to the new desktop
  1197.     //
  1198.     if (!SetThreadDesktop( hdesk )) 
  1199.     {
  1200.         ec = GetLastError();
  1201.         SetThreadDesktop( hdeskSave );
  1202.         if (g_hMainDesktop != hdesk)
  1203.         {
  1204.             CloseDesktop( hdesk );
  1205.         }
  1206.         if (g_hMainDesktop != hdeskSave)
  1207.         {
  1208.             CloseDesktop( hdeskSave );
  1209.         }
  1210.         return TRUE;
  1211.     }
  1212.     //
  1213.     // Update the desktop in the enumerator
  1214.     //
  1215.     if (te->lpDesk)
  1216.     {
  1217.         LocalFree(te->lpDesk);
  1218.     }
  1219.     te->lpDesk = (LPTSTR) LocalAlloc( 0, (lstrlen(lpstr) + 1) * sizeof(TCHAR));
  1220.     if (NULL == te->lpDesk)
  1221.     {   
  1222.         if (hdesk != hdeskSave) 
  1223.         {
  1224.             SetThreadDesktop( hdeskSave );
  1225.         }
  1226.         if (g_hMainDesktop != hdesk)
  1227.         {
  1228.             CloseDesktop( hdesk );
  1229.         }
  1230.         if (g_hMainDesktop != hdeskSave)
  1231.         {
  1232.             CloseDesktop( hdeskSave );
  1233.         }
  1234.         return FALSE;
  1235.     }
  1236.     else
  1237.     {
  1238.         lstrcpy(te->lpDesk, lpstr);
  1239.     }
  1240.     //
  1241.     // enumerate all windows in the new desktop
  1242.     //
  1243.     EnumWindows( (WNDENUMPROC) EnumWindowsProc, lParam ); 
  1244.     //
  1245.     // restore the previous desktop
  1246.     //
  1247.     if (hdesk != hdeskSave)
  1248.     {
  1249.         SetThreadDesktop( hdeskSave );
  1250.     }
  1251.     
  1252.     if (g_hMainDesktop != hdesk)
  1253.     {
  1254.         CloseDesktop( hdesk );
  1255.     }
  1256.     if (g_hMainDesktop != hdeskSave)
  1257.     {
  1258.         CloseDesktop( hdeskSave );
  1259.     }
  1260.     return TRUE;
  1261. }
  1262. /*++
  1263. Routine Description:
  1264.     Callback function for window enumeration.
  1265. Arguments:
  1266.     hwnd             - window handle
  1267.     lParam           - ** not used **
  1268. Return Value:
  1269.     TRUE  - continues the enumeration
  1270. --*/
  1271. BOOL CALLBACK EnumWindowsProc(HWND    hwnd, LPARAM   lParam)
  1272. {
  1273.     DWORD             pid = 0;
  1274.     DWORD             i;
  1275.     PTASK_LIST_ENUM   te = (PTASK_LIST_ENUM)lParam;
  1276.     DWORD             numTasks = te->m_pTasks->GetSize();
  1277.     TCHAR             szTitle[MAX_PATH];
  1278.     if ((GetWindow( hwnd, GW_OWNER ))   || 
  1279.         (!IsWindowVisible(hwnd)))
  1280.         
  1281.     {
  1282.         //
  1283.         // not a top level window, or not visible
  1284.         //
  1285.         return TRUE;
  1286.     }
  1287.     if (FALSE == InternalGetWindowText(hwnd, szTitle, ARRAYSIZE(szTitle)))
  1288.     {
  1289.         // Can't get the title - something weird going on.. but continue anyway
  1290.         return TRUE;
  1291.     }
  1292.     if (TEXT('') == szTitle[0])
  1293.     {
  1294.         // Empty title - of little value in the task list
  1295.         return TRUE;
  1296.     }
  1297.     if (hwnd == g_hMainWnd)
  1298.     {
  1299.         // Don't show the Task Manager in the list
  1300.         return TRUE;
  1301.     }
  1302.     if (0 == lstrcmpi(szTitle, TEXT("Program Manager")))
  1303.     {
  1304.         // Don't show the Program Manager (explorer) in the list
  1305.         return TRUE;
  1306.     }
  1307.     //
  1308.     // look for the task in the task list for this window
  1309.     //
  1310.     for (i=0; i < numTasks; i++) 
  1311.     {
  1312.         CTaskInfo * pTask = (CTaskInfo *) te->m_pTasks->GetAt(i);
  1313.         if (pTask->m_hwnd == hwnd)
  1314.         {
  1315.             //
  1316.             // Update the task info
  1317.             //
  1318.             if (FAILED(pTask->SetData(hwnd, szTitle, te->lpWinsta, te->lpDesk, te->uPassCount, TRUE)))
  1319.             {
  1320.                 return FALSE;
  1321.             }
  1322.             pTask->m_uPassCount.QuadPart = te->uPassCount.QuadPart;
  1323.             break;
  1324.         }
  1325.     }
  1326.     if (i >= numTasks)
  1327.     {
  1328.         // Didn't find the task, it must be a new one
  1329.         CTaskInfo * pTask = new CTaskInfo;
  1330.         if (NULL == pTask)
  1331.         {
  1332.             return FALSE;
  1333.         }
  1334.         // Init the task data.  If fails, delete and bail
  1335.         if (FAILED(pTask->SetData(hwnd, szTitle, te->lpWinsta, te->lpDesk, te->uPassCount, FALSE)))
  1336.         {
  1337.             delete pTask;
  1338.             return FALSE;
  1339.         }
  1340.         else
  1341.         {
  1342.             // Add the icons to the page's imagelist
  1343.             if (!pTask->m_hLargeIcon && !pTask->m_hSmallIcon)
  1344.             {
  1345.                 pTask->m_iLargeIcon = 0;
  1346.                 pTask->m_iSmallIcon = 0;
  1347.             }
  1348.             else
  1349.             {
  1350.                 // The indices to the small and large icons for a task must
  1351.                 // always be the same; so, if one size is missing, use the icon
  1352.                 // of the other size (stretched).  All the resizing is taken
  1353.                 // care of for us by ImageList_AddIcon(), since it's already
  1354.                 // had a fixed size set on it and will force any added icon
  1355.                 // into that size.                
  1356.                 pTask->m_iLargeIcon = ImageList_AddIcon(te->m_pPage->m_himlLarge, 
  1357.                                                         pTask->m_hLargeIcon ? 
  1358.                                                                 pTask->m_hLargeIcon
  1359.                                                             :   pTask->m_hSmallIcon);
  1360.                 if (-1 == pTask->m_iLargeIcon)
  1361.                 {
  1362.                     delete pTask;
  1363.                     return FALSE;
  1364.                 }
  1365.                 pTask->m_iSmallIcon = ImageList_AddIcon(te->m_pPage->m_himlSmall, 
  1366.                                                         pTask->m_hSmallIcon ? 
  1367.                                                                 pTask->m_hSmallIcon
  1368.                                                             :   pTask->m_hLargeIcon);
  1369.                 if (-1 == pTask->m_iSmallIcon)
  1370.                 {
  1371.                     ImageList_Remove(te->m_pPage->m_himlLarge, pTask->m_iLargeIcon);
  1372.                     delete pTask;
  1373.                     return FALSE;
  1374.                 }           
  1375.             }
  1376.             // All went well, so add it to the array
  1377.             if (!(te->m_pTasks->Add( (LPVOID) pTask)))
  1378.             {
  1379.                 delete pTask;
  1380.                 return FALSE;
  1381.             }
  1382.         }
  1383.     }
  1384.     //
  1385.     // continue the enumeration
  1386.     //
  1387.     return TRUE;
  1388. }
  1389. /*++ CTaskPage::SizeTaskPage
  1390. Routine Description:
  1391.     Sizes its children based on the size of the
  1392.     tab control on which it appears.  
  1393. Arguments:
  1394. Return Value:
  1395. Revision History:
  1396.       Nov-29-95 Davepl  Created
  1397. --*/
  1398. static const INT aTaskControls[] =
  1399. {
  1400.     IDC_SWITCHTO,
  1401.     IDC_ENDTASK,
  1402.     IDM_RUN
  1403. };
  1404. void CTaskPage::SizeTaskPage()
  1405. {
  1406.     // Get the coords of the outer dialog
  1407.     RECT rcParent;
  1408.     GetClientRect(m_hPage, &rcParent);
  1409.     HDWP hdwp = BeginDeferWindowPos(10);
  1410.     // Calc the deltas in the x and y positions that we need to
  1411.     // move each of the child controls
  1412.     RECT rcMaster;
  1413.     HWND hwndMaster = GetDlgItem(m_hPage, IDM_RUN);
  1414.     GetWindowRect(hwndMaster, &rcMaster);
  1415.     MapWindowPoints(HWND_DESKTOP, m_hPage, (LPPOINT) &rcMaster, 2);
  1416.     INT dx = ((rcParent.right - g_DefSpacing * 2) - rcMaster.right);
  1417.     INT dy = ((rcParent.bottom - g_DefSpacing * 2) - rcMaster.bottom);
  1418.     // Size the listbox
  1419.     HWND hwndListbox = GetDlgItem(m_hPage, IDC_TASKLIST);
  1420.     RECT rcListbox;
  1421.     GetWindowRect(hwndListbox, &rcListbox);
  1422.     MapWindowPoints(HWND_DESKTOP, m_hPage, (LPPOINT) &rcListbox, 2);
  1423.     INT lbX = rcMaster.right - rcListbox.left + dx;
  1424.     INT lbY = rcMaster.top - rcListbox.top + dy - g_DefSpacing;
  1425.     DeferWindowPos(hdwp, hwndListbox, NULL,
  1426.                         0, 0,
  1427.                         lbX, 
  1428.                         lbY,
  1429.                         SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  1430. #if 0   // This is handy, but the listview repaint is horrible
  1431.     
  1432.     // Adjust the first column width to be the width of the listbox
  1433.     // less the size of the status column
  1434.     INT cxStatus = ListView_GetColumnWidth(hwndListbox, 1);
  1435.     if (lbX - cxStatus > 0)
  1436.     {
  1437.         ListView_SetColumnWidth(hwndListbox, 0, lbX - cxStatus);
  1438.     }
  1439. #endif
  1440.     // Move each of the child controls by the above delta
  1441.     for (int i = 0; i < ARRAYSIZE(aTaskControls); i++)
  1442.     {
  1443.         HWND hwndCtrl = GetDlgItem(m_hPage, aTaskControls[i]);
  1444.         RECT rcCtrl;
  1445.         GetWindowRect(hwndCtrl, &rcCtrl);
  1446.         MapWindowPoints(HWND_DESKTOP, m_hPage, (LPPOINT) &rcCtrl, 2);
  1447.         DeferWindowPos(hdwp, hwndCtrl, NULL, 
  1448.                          rcCtrl.left + dx, 
  1449.                          rcCtrl.top + dy,
  1450.                          0, 0,
  1451.                          SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
  1452.     }
  1453.     EndDeferWindowPos(hdwp);
  1454. }
  1455. /*++ CTaskPage::HandleWMCOMMAND
  1456. Routine Description:
  1457.     Handles WM_COMMANDS received at the main page dialog
  1458.     
  1459. Arguments:
  1460.     id - Command id of command received
  1461. Return Value:
  1462. Revision History:
  1463.       Dec-01-95 Davepl  Created
  1464. --*/
  1465. void CTaskPage::HandleWMCOMMAND(INT id)
  1466. {
  1467.     switch(id)
  1468.     {
  1469.         case IDM_TASK_FINDPROCESS:
  1470.         {
  1471.             DWORD dwCount;
  1472.             HWND * pHwnds = GetHWNDS(TRUE, &dwCount);
  1473.             // Send a message to the main window telling it to
  1474.             // switch pages and select the process in question in
  1475.             // the process view
  1476.             if (pHwnds)
  1477.             {
  1478.                 DWORD pid = 0;
  1479.                 DWORD tid;
  1480.                 tid = GetWindowThreadProcessId(pHwnds[0], &pid);
  1481.                 if (pid)
  1482.                 {
  1483.                     PostMessage(g_hMainWnd, WM_FINDPROC, tid, pid);
  1484.                 }
  1485.                 LocalFree(pHwnds);
  1486.             }
  1487.             break;
  1488.         }
  1489.         // These menu items (from the popup) have matching ones in the main menu,
  1490.         // so just pass them along to the main menu
  1491.         case IDM_LARGEICONS:
  1492.         case IDM_SMALLICONS:
  1493.         case IDM_DETAILS:
  1494.         case IDM_RUN:
  1495.         {
  1496.             SendMessage(g_hMainWnd, WM_COMMAND, MAKELPARAM(id, 0), 0);
  1497.             break;
  1498.         }
  1499.         case IDM_TASK_SWITCHTO:
  1500.         case IDC_SWITCHTO:
  1501.         {
  1502.             DWORD dwCount;
  1503.             HWND * pHwnds = GetHWNDS(m_cSelected, &dwCount);
  1504.             if (pHwnds)
  1505.             {
  1506.                 // If target is minimized, restore it
  1507.                 if (IsIconic(pHwnds[0]))
  1508.                 {
  1509.                     ShowWindow(pHwnds[0], SW_RESTORE);
  1510.                 }
  1511.                 // Switch to the target window, and if the options dictate,
  1512.                 // minimize the taskmanager
  1513.                 HWND hwndLastActive = GetLastActivePopup(pHwnds[0]);
  1514.                 if (!IsWindow(hwndLastActive)) {
  1515.                     MessageBeep(0);
  1516.                     LocalFree(pHwnds);
  1517.                     break;
  1518.                 }
  1519.                 // Can really only switch if the window is not disabled
  1520.                 LONG lTemp = GetWindowLong(hwndLastActive, GWL_STYLE);
  1521.                 if (0 == (lTemp & WS_DISABLED)) 
  1522.                 {
  1523.                     //  Use SwitchToThisWindow() to bring dialog parents as well.
  1524.                     SwitchToThisWindow(hwndLastActive, TRUE);
  1525.                     if (g_Options.m_fMinimizeOnUse)
  1526.                     {
  1527.                         ShowWindow(g_hMainWnd, SW_MINIMIZE);
  1528.                     }
  1529.                 } 
  1530.                 else 
  1531.                 {
  1532.                     MessageBeep(0);
  1533.                 }
  1534.                 LocalFree(pHwnds);
  1535.             }
  1536.             break;
  1537.         }
  1538.         case IDC_TILEHORZ:
  1539.         case IDM_TASK_TILEHORZ:
  1540.         {
  1541.             DWORD dwCount;
  1542.             HWND * pHwnds = GetHWNDS(m_cSelected, &dwCount);
  1543.             if (pHwnds)
  1544.             {
  1545.                 EnsureWindowsNotMinimized(pHwnds, dwCount);
  1546.             }
  1547.             TileWindows(GetDesktopWindow(),
  1548.                         MDITILE_HORIZONTAL,
  1549.                         NULL,
  1550.                         dwCount,
  1551.                         pHwnds);
  1552.             if (pHwnds)
  1553.             {
  1554.                 LocalFree(pHwnds);
  1555.             }
  1556.             break;
  1557.         }
  1558.         case IDM_TASK_TILEVERT:
  1559.         {
  1560.             DWORD dwCount;
  1561.             HWND * pHwnds = GetHWNDS(m_cSelected, &dwCount);
  1562.             if (pHwnds)
  1563.             {
  1564.                 EnsureWindowsNotMinimized(pHwnds, dwCount);
  1565.             }
  1566.             TileWindows(GetDesktopWindow(),
  1567.                         MDITILE_VERTICAL,
  1568.                         NULL,
  1569.                         dwCount,
  1570.                         pHwnds);
  1571.             if (pHwnds)
  1572.             {
  1573.                 LocalFree(pHwnds);
  1574.             }
  1575.             break;
  1576.         }
  1577.         case IDM_TASK_CASCADE:
  1578.         {
  1579.             DWORD dwCount;
  1580.             HWND * pHwnds = GetHWNDS(m_cSelected, &dwCount);
  1581.             if (pHwnds)
  1582.             {
  1583.                 EnsureWindowsNotMinimized(pHwnds, dwCount);
  1584.             }
  1585.             CascadeWindows(GetDesktopWindow(),
  1586.                    0,
  1587.                    NULL,
  1588.                    dwCount,
  1589.                    pHwnds);
  1590.             if (pHwnds)
  1591.             {
  1592.                 LocalFree(pHwnds);
  1593.             }
  1594.             break;
  1595.         }
  1596.         case IDM_TASK_MINIMIZE:
  1597.         case IDM_TASK_MAXIMIZE:
  1598.         {
  1599.             DWORD dwCount;
  1600.             
  1601.             // If some selected, just get them, else get all
  1602.              
  1603.             HWND * pHwnds = GetHWNDS(m_cSelected, &dwCount);
  1604.             if (pHwnds)
  1605.             {
  1606.                 for (UINT i = 0; i < dwCount; i++)
  1607.                 {
  1608.                     ShowWindowAsync(pHwnds[i], (id == IDC_MINIMIZE || id == IDM_TASK_MINIMIZE) ?
  1609.                                                 SW_MINIMIZE : SW_MAXIMIZE);
  1610.                 }
  1611.                 LocalFree(pHwnds);
  1612.             }
  1613.             break;
  1614.         }
  1615.         case IDM_TASK_BRINGTOFRONT:
  1616.         {
  1617.             DWORD dwCount;
  1618.             HWND * pHwnds = GetHWNDS(TRUE, &dwCount);
  1619.             if (pHwnds)
  1620.             {
  1621.                 EnsureWindowsNotMinimized(pHwnds, dwCount);
  1622.                                 
  1623.                 // Walk backwards through the list so that the first window selected
  1624.                 // in on top
  1625.                 for (INT i = (INT) dwCount - 1; i >= 0 ; i--)
  1626.                 {
  1627.                     SetWindowPos(pHwnds[i], HWND_TOP, 0, 0, 0, 0,
  1628.                                  SWP_NOSIZE | SWP_NOMOVE);
  1629.                 }
  1630.                 DWORD dwProc;
  1631.                 if (GetWindowThreadProcessId(pHwnds[0], &dwProc))
  1632.                     AllowSetForegroundWindow(dwProc);
  1633.                 SetForegroundWindow(pHwnds[0]);
  1634.                 LocalFree(pHwnds);
  1635.             }
  1636.             break;
  1637.             
  1638.         }
  1639.         case IDC_ENDTASK:
  1640.         case IDM_TASK_ENDTASK:
  1641.         {
  1642.             DWORD dwCount;
  1643.             HWND * pHwnds = GetHWNDS(TRUE, &dwCount);
  1644.             if (pHwnds)
  1645.             {
  1646.                 BOOL fForce = GetKeyState(VK_CONTROL) & ( 1 << 16) ? TRUE : FALSE;
  1647.                 for(UINT i = 0; i < dwCount; i++)
  1648.                 {
  1649.                     // SetActiveWindow(aHwnds[i]);
  1650.                     EndTask(pHwnds[i], FALSE, fForce);
  1651.                 }
  1652.                 LocalFree(pHwnds);
  1653.             }
  1654.             break;
  1655.         }
  1656.         default:
  1657.             break;
  1658.     }
  1659.     Unpause();
  1660. }
  1661. /*++ TaskPageProc
  1662. Routine Description:
  1663.     Dialogproc for the task manager page.  
  1664.     
  1665. Arguments:
  1666.     hwnd        - handle to dialog box
  1667.     uMsg        - message
  1668.     wParam      - first message parameter
  1669.     lParam      - second message parameter
  1670. Return Value:
  1671.     
  1672.     For WM_INITDIALOG, TRUE == success
  1673.     For others, TRUE == this proc handles the message
  1674. Revision History:
  1675.       Nov-28-95 Davepl  Created
  1676. --*/
  1677. INT_PTR CALLBACK TaskPageProc(
  1678.                 HWND        hwnd,               // handle to dialog box
  1679.                 UINT        uMsg,                   // message
  1680.                 WPARAM      wParam,                 // first message parameter
  1681.                 LPARAM      lParam                  // second message parameter
  1682.                 )
  1683. {
  1684.     CTaskPage * thispage = (CTaskPage *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
  1685.     // See if the parent wants this message
  1686.     if (TRUE == CheckParentDeferrals(uMsg, wParam, lParam))
  1687.     {
  1688.         return TRUE;
  1689.     }
  1690.     switch(uMsg)
  1691.     {
  1692.         case WM_INITDIALOG:
  1693.         {
  1694.             SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam);
  1695.             CTaskPage * thispage = (CTaskPage *) lParam;
  1696.             thispage->m_hPage = hwnd;
  1697.             HWND hTaskList = GetDlgItem(hwnd, IDC_TASKLIST);
  1698.             ListView_SetImageList(hTaskList, thispage->m_himlSmall, LVSIL_SMALL);
  1699.             // Turn on SHOWSELALWAYS so that the selection is still highlighted even
  1700.             // when focus is lost to one of the buttons (for example)
  1701.             SetWindowLong(hTaskList, GWL_STYLE, GetWindowLong(hTaskList, GWL_STYLE) | LVS_SHOWSELALWAYS);
  1702.             if (SHRestricted(REST_NORUN))
  1703.             {
  1704.                 EnableWindow (GetDlgItem(hwnd, IDM_RUN), FALSE);
  1705.             }
  1706.             
  1707.             SetFocus(GetDlgItem(hwnd, IDC_TASKLIST));
  1708.         SubclassListView(GetDlgItem(hwnd, IDC_PROCLIST));
  1709.         
  1710.             return FALSE;
  1711.         }
  1712.         
  1713.         // We need to fake client mouse clicks in this child to appear as nonclient
  1714.         // (caption) clicks in the parent so that the user can drag the entire app
  1715.         // when the title bar is hidden by dragging the client area of this child
  1716.         case WM_LBUTTONUP:
  1717.         case WM_LBUTTONDOWN:
  1718.         {
  1719.             if (g_Options.m_fNoTitle)
  1720.             {
  1721.                 SendMessage(g_hMainWnd, 
  1722.                             uMsg == WM_LBUTTONUP ? WM_NCLBUTTONUP : WM_NCLBUTTONDOWN, 
  1723.                             HTCAPTION, 
  1724.                             lParam);
  1725.             }
  1726.             break;
  1727.         }
  1728.  
  1729.         case WM_COMMAND:
  1730.         {
  1731.             thispage->HandleWMCOMMAND(LOWORD(wParam));
  1732.             break;
  1733.         }
  1734.         case WM_NOTIFY:
  1735.         {
  1736.             return thispage->HandleTaskPageNotify((HWND) wParam, (LPNMHDR) lParam);
  1737.         }
  1738.         case WM_MENUSELECT:
  1739.         {
  1740.             if ((UINT) HIWORD(wParam) == 0xFFFF)
  1741.             {
  1742.                 // Menu dismissed, resume display
  1743.                 thispage->Unpause();
  1744.             }
  1745.             break;
  1746.         }
  1747.         case WM_CONTEXTMENU:
  1748.         {
  1749.             if ((HWND) wParam == GetDlgItem(hwnd, IDC_TASKLIST))
  1750.             {
  1751.                 thispage->HandleTaskListContextMenu(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
  1752.                 return TRUE;
  1753.             }
  1754.             break;
  1755.         }
  1756.         // Size our kids
  1757.         case WM_SIZE:
  1758.         {
  1759.             thispage->SizeTaskPage();
  1760.             return TRUE;
  1761.         }
  1762.         case WM_SETTINGCHANGE:
  1763.             thispage->OnSettingsChange();
  1764.             // fall through
  1765.         case WM_SYSCOLORCHANGE:
  1766.             SendMessage(GetDlgItem(hwnd, IDC_TASKLIST), uMsg, wParam, lParam);
  1767.             return TRUE;
  1768.         default:
  1769.             return FALSE;
  1770.     }
  1771.     return FALSE;
  1772. }
  1773. void CTaskPage::OnSettingsChange()
  1774. {
  1775.     // in going between large-font settings and normal settings, the size of small 
  1776.     // icons changes; so throw away all our icons and change the size of images in 
  1777.     // our lists
  1778.     
  1779.     BOOL fPaused = m_fPaused; // pause the page so we can get through
  1780.     m_fPaused = TRUE;         // the below without being updated  
  1781.     RemoveAllTasks();
  1782.     m_pTaskArray->RemoveAll();
  1783.     
  1784.     m_vmViewMode = VM_INVALID;      // cause an update to the list view
  1785.     
  1786.     // you'd think that since SetIconSize does a RemoveAll anyway, the
  1787.     // explicit RemoveAll calls are redundant; however, if SetIconSize
  1788.     // gets size parameters which aren't different from what it has,
  1789.     // it fails without doing a RemoveAll!
  1790.     ImageList_RemoveAll(m_himlLarge);
  1791.     ImageList_RemoveAll(m_himlSmall);
  1792.     ImageList_SetIconSize(m_himlLarge, GetSystemMetrics(SM_CXICON),
  1793.                                         GetSystemMetrics(SM_CYICON));
  1794.     ImageList_SetIconSize(m_himlSmall, GetSystemMetrics(SM_CXSMICON),
  1795.                                         GetSystemMetrics(SM_CYSMICON));
  1796.     LoadDefaultIcons();     // this could return an error, but if it does,
  1797.                             // we just have to press on
  1798.     m_fPaused = fPaused;            // restore the paused state
  1799.     TimerEvent();           // even if we're paused, we'll want to redraw
  1800. }
  1801. /*++ CTaskPage::GetTitle
  1802. Routine Description:
  1803.     Copies the title of this page to the caller-supplied buffer
  1804.     
  1805. Arguments:
  1806.     pszText     - the buffer to copy to
  1807.     bufsize     - size of buffer, in characters
  1808. Return Value:
  1809. Revision History:
  1810.       Nov-28-95 Davepl  Created
  1811. --*/
  1812. void CTaskPage::GetTitle(LPTSTR pszText, size_t bufsize)
  1813. {
  1814.     LoadString(g_hInstance, IDS_TASKPAGETITLE, pszText, bufsize);
  1815. }
  1816. /*++ CTaskPage::Activate
  1817. Routine Description:
  1818.     Brings this page to the front, sets its initial position,
  1819.     and shows it
  1820.     
  1821. Arguments:
  1822. Return Value:
  1823.     HRESULT (S_OK on success)
  1824. Revision History:
  1825.       Nov-28-95 Davepl  Created
  1826. --*/
  1827.  
  1828. HRESULT CTaskPage::Activate()
  1829. {
  1830.     // Make this page visible
  1831.     ShowWindow(m_hPage, SW_SHOW);
  1832.     SetWindowPos(m_hPage,
  1833.                  HWND_TOP,
  1834.                  0, 0, 0, 0,
  1835.                  SWP_NOMOVE | SWP_NOSIZE);
  1836.     SetFocus(GetDlgItem(m_hPage, IDC_TASKLIST));
  1837.     // Change the menu bar to be the menu for this page
  1838.     HMENU hMenuOld = GetMenu(g_hMainWnd);
  1839.     HMENU hMenuNew = LoadMenu(g_hInstance, MAKEINTRESOURCE(IDR_MAINMENU_TASK));
  1840.     if (hMenuNew && SHRestricted(REST_NORUN))
  1841.     {
  1842.         DeleteMenu(hMenuNew, IDM_RUN, MF_BYCOMMAND);
  1843.     }
  1844.     g_hMenu = hMenuNew;
  1845.     if (g_Options.m_fNoTitle == FALSE)
  1846.     {
  1847.         SetMenu(g_hMainWnd, hMenuNew);
  1848.     }
  1849.     if (hMenuOld)
  1850.     {
  1851.         DestroyMenu(hMenuOld);
  1852.     }
  1853.     return S_OK;
  1854. }
  1855. /*++ class CTaskPage::SetupColumns
  1856. Class Description:
  1857.     Removes any existing columns from the taskmanager listview and
  1858.     adds all of the columns listed in the g_ActiveTaskCol array.
  1859. Arguments:
  1860. Return Value:
  1861.     HRESULT
  1862. Revision History:
  1863.       Nov-29-95 Davepl  Created
  1864. --*/
  1865. HRESULT CTaskPage::SetupColumns()
  1866. {
  1867.     HWND hwndList = GetDlgItem(m_hPage, IDC_TASKLIST);
  1868.     if (NULL == hwndList)
  1869.     {
  1870.         return E_UNEXPECTED;
  1871.     }    
  1872.     ListView_DeleteAllItems(hwndList);
  1873.     // Remove all existing columns
  1874.     LV_COLUMN lvcolumn;
  1875.     while(ListView_DeleteColumn(hwndList, 0))
  1876.     {
  1877.         NULL;
  1878.     }
  1879.     // Add all of the new columns
  1880.     INT iColumn = 0;
  1881.     while (g_ActiveTaskCol[iColumn] >= 0)
  1882.     {
  1883.         INT idColumn = g_ActiveTaskCol[iColumn];
  1884.         TCHAR szTitle[MAX_PATH];
  1885.         LoadString(g_hInstance, IDS_FIRSTTASKCOL + idColumn, szTitle, ARRAYSIZE(szTitle));
  1886.         lvcolumn.mask       = LVCF_FMT | LVCF_TEXT | LVCF_TEXT | LVCF_WIDTH;
  1887.         lvcolumn.fmt        = TaskColumnDefaults[ idColumn ].Format;
  1888.         lvcolumn.cx         = TaskColumnDefaults[ idColumn ].Width;
  1889.         lvcolumn.pszText    = szTitle;
  1890.         lvcolumn.iSubItem   = iColumn;
  1891.         if (-1 == ListView_InsertColumn(hwndList, iColumn, &lvcolumn))
  1892.         {
  1893.             return E_FAIL;
  1894.         }
  1895.         iColumn++;
  1896.     }
  1897.     return S_OK;
  1898. }
  1899. /*++ CTaskPage::Initialize
  1900. Routine Description:
  1901.     Initializes the task manager page
  1902. Arguments:
  1903.     hwndParent  - Parent on which to base sizing on: not used for creation,
  1904.                   since the main app window is always used as the parent in
  1905.                   order to keep tab order correct
  1906.                   
  1907. Return Value:
  1908. Revision History:
  1909.       Nov-28-95 Davepl  Created
  1910. --*/
  1911. HRESULT CTaskPage::Initialize(HWND hwndParent)
  1912. {
  1913.     HRESULT hr = S_OK;
  1914.     UINT flags = ILC_MASK;
  1915.     //
  1916.     // Create the ptr array used to hold the info on running tasks
  1917.     //
  1918.     m_pTaskArray = new CPtrArray(GetProcessHeap());
  1919.     if (NULL == m_pTaskArray)
  1920.     {
  1921.         hr = E_OUTOFMEMORY;
  1922.     }
  1923.     else
  1924.     {
  1925.         // Our pseudo-parent is the tab contrl, and is what we base our
  1926.         // sizing on.  However, in order to keep tab order right among
  1927.         // the controls, we actually create ourselves with the main
  1928.         // window as the parent
  1929.         m_hwndTabs = hwndParent;
  1930.         //
  1931.         // Create the image lists
  1932.         //
  1933.     if(IS_WINDOW_RTL_MIRRORED(hwndParent))
  1934.     {
  1935.         flags |= ILC_MIRROR;
  1936.     }
  1937.     m_himlSmall = ImageList_Create(
  1938.                     GetSystemMetrics(SM_CXSMICON),
  1939.                     GetSystemMetrics(SM_CYSMICON),
  1940.                     flags,
  1941.                     1,
  1942.                     1
  1943.                     );
  1944.     
  1945.         if (NULL == m_himlSmall)
  1946.         {
  1947.             hr = E_FAIL;    
  1948.         }
  1949.     }
  1950.     if (SUCCEEDED(hr))
  1951.     {
  1952.         m_himlLarge = ImageList_Create(
  1953.                     GetSystemMetrics(SM_CXICON),
  1954.                     GetSystemMetrics(SM_CYICON),
  1955.                     flags,
  1956.                     1,
  1957.                     1
  1958.                     );
  1959.         if (NULL == m_himlLarge)
  1960.         {
  1961.             hr = E_FAIL;
  1962.         }
  1963.     }
  1964.     // Load the default icons
  1965.     hr = LoadDefaultIcons();
  1966.     if (SUCCEEDED(hr))
  1967.     {
  1968.         //
  1969.         // Create the dialog which represents the body of this page
  1970.         //
  1971.         m_hPage = CreateDialogParam(
  1972.                         g_hInstance,                    // handle to application instance
  1973.                         MAKEINTRESOURCE(IDD_TASKPAGE),  // identifies dialog box template name  
  1974.                         g_hMainWnd,                     // handle to owner window
  1975.                         TaskPageProc,                   // pointer to dialog box procedure
  1976.                         (LPARAM) this );                // User data (our this pointer)
  1977.         if (NULL == m_hPage)
  1978.         {
  1979.             hr = GetLastHRESULT();
  1980.         }
  1981.     }
  1982.     if (SUCCEEDED(hr))
  1983.     {
  1984.         // Set up the columns in the listview
  1985.         hr = SetupColumns();
  1986.     }
  1987.     if (SUCCEEDED(hr))
  1988.     {
  1989.         TimerEvent();
  1990.     }
  1991.     //
  1992.     // If any failure along the way, clean up what got allocated
  1993.     // up to that point
  1994.     //
  1995.     if (FAILED(hr))
  1996.     {
  1997.         if (m_hPage)
  1998.         {
  1999.             DestroyWindow(m_hPage);
  2000.         }
  2001.         m_hwndTabs = NULL;
  2002.     }
  2003.     return hr;
  2004. }
  2005. HRESULT CTaskPage::LoadDefaultIcons()
  2006. {
  2007.     HICON   hDefLarge;
  2008.     HICON   hDefSmall;
  2009.     HRESULT hr = S_OK;
  2010.     
  2011.     hDefSmall = (HICON) LoadImage(g_hInstance, MAKEINTRESOURCE(IDI_DEFAULT), IMAGE_ICON, 
  2012.                             GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0);
  2013.     if (!hDefSmall)
  2014.     {
  2015.         return GetLastHRESULT();
  2016.     }
  2017.     if (-1 == ImageList_AddIcon(m_himlSmall, hDefSmall))
  2018.     {
  2019.         hr = E_FAIL;
  2020.     }
  2021.     DestroyIcon(hDefSmall);
  2022.     hDefLarge = (HICON) LoadImage(g_hInstance, MAKEINTRESOURCE(IDI_DEFAULT), IMAGE_ICON, 
  2023.                             GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), 0);
  2024.     if (!hDefLarge)
  2025.     {
  2026.         return GetLastHRESULT();
  2027.     }
  2028.     if (-1 == ImageList_AddIcon(m_himlLarge, hDefLarge))
  2029.     {
  2030.         hr = E_FAIL;
  2031.     }
  2032.     DestroyIcon(hDefLarge);
  2033.     
  2034.     return hr;
  2035. }
  2036. /*++ CTaskPage::Destroy
  2037. Routine Description:
  2038.     Frees whatever has been allocated by the Initialize call
  2039.     
  2040. Arguments:
  2041. Return Value:
  2042. Revision History:
  2043.       Nov-28-95 Davepl  Created
  2044. --*/
  2045. HRESULT CTaskPage::Destroy()
  2046. {
  2047.     if (m_hPage)
  2048.     {
  2049.         DestroyWindow(m_hPage);
  2050.         m_hPage = NULL;
  2051.     }
  2052.     if (m_hThread)
  2053.     {
  2054.         // Signal the child thead to exit, and wait for it to do so
  2055.         m_tp.m_fThreadExit = TRUE;
  2056.         SetEvent(m_hEventChild);
  2057.         WaitForSingleObject(m_hEventParent, INFINITE);
  2058.         CloseHandle(m_hThread);
  2059.         m_hThread = NULL;
  2060.     }
  2061.     if (m_hEventChild)
  2062.     {
  2063.         CloseHandle(m_hEventChild);
  2064.         m_hEventChild = NULL;
  2065.     }
  2066.     if (m_hEventParent)
  2067.     {
  2068.         CloseHandle(m_hEventParent);
  2069.         m_hEventParent = NULL;
  2070.     }
  2071.     // These are freed automatically by listview
  2072.     m_himlSmall = NULL;
  2073.     m_himlLarge = NULL;
  2074.     return S_OK;
  2075. }
  2076. /*++ CTaskPage::Deactivate
  2077. Routine Description:
  2078.     Called when this page is losing its place up front
  2079.     
  2080. Arguments:
  2081. Return Value:
  2082. Revision History:
  2083.       Nov-28-95 Davepl  Created
  2084. --*/
  2085. void CTaskPage::Deactivate()
  2086. {
  2087.     if (m_hPage)
  2088.     {
  2089.         ShowWindow(m_hPage, SW_HIDE);
  2090.     }
  2091. }