Leaked source code of windows server 2003
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.

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