Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2914 lines
69 KiB

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