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.

3789 lines
104 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // TaskMan - NT TaskManager
  4. // Copyright (C) Microsoft
  5. //
  6. // File: Main.CPP
  7. //
  8. // History: Nov-10-95 DavePl Created
  9. //
  10. //--------------------------------------------------------------------------
  11. #include "precomp.h"
  12. #include <winsta.h>
  13. #include <htmlhelp.h>
  14. #define DECL_CRTFREE
  15. #include <crtfree.h>
  16. #include <lmcons.h>
  17. #include "TokenUtil.h"
  18. #include <sspi.h>
  19. #include <secext.h> // for GetUserNameEx
  20. static UINT g_msgTaskbarCreated = 0;
  21. static const UINT idTrayIcons[] =
  22. {
  23. IDI_TRAY0, IDI_TRAY1, IDI_TRAY2, IDI_TRAY3, IDI_TRAY4, IDI_TRAY5,
  24. IDI_TRAY6, IDI_TRAY7, IDI_TRAY8, IDI_TRAY9, IDI_TRAY10, IDI_TRAY11
  25. };
  26. HICON g_aTrayIcons[ARRAYSIZE(idTrayIcons)];
  27. UINT g_cTrayIcons = ARRAYSIZE(idTrayIcons);
  28. #define MIN_MEMORY_REQUIRED 8 // If the system has less than 8 megs of memory only load the first two tabs.
  29. //
  30. // Control IDs
  31. //
  32. #define IDC_STATUSWND 100
  33. //
  34. // Globals - this app is (effectively) single threaded and these values
  35. // are used by all pages
  36. //
  37. const TCHAR cszStartupMutex[] = TEXT("NTShell Taskman Startup Mutex");
  38. #define FINDME_TIMEOUT 10000 // Wait to to 10 seconds for a response
  39. typedef BOOLEAN (*PFNSETSUSPENDSTATE)(BOOLEAN, BOOLEAN, BOOLEAN);
  40. void MainWnd_OnSize(HWND hwnd, UINT state, int cx, int cy);
  41. HANDLE g_hStartupMutex = NULL;
  42. BOOL g_fMenuTracking = FALSE;
  43. HWND g_hMainWnd = NULL;
  44. HDESK g_hMainDesktop = NULL;
  45. HWND g_hStatusWnd = NULL;
  46. HINSTANCE g_hInstance = NULL;
  47. HACCEL g_hAccel = NULL;
  48. BYTE g_cProcessors = (BYTE) 0;
  49. HMENU g_hMenu = NULL;
  50. BOOL g_fCantHide = FALSE;
  51. BOOL g_fInPopup = FALSE;
  52. DWORD g_idTrayThread = 0;
  53. HANDLE g_hTrayThread = NULL;
  54. LONG g_minWidth = 0;
  55. LONG g_minHeight = 0;
  56. LONG g_DefSpacing = 0;
  57. LONG g_InnerSpacing = 0;
  58. LONG g_TopSpacing = 0;
  59. LONG g_cxEdge = 0;
  60. HRGN g_hrgnView = NULL;
  61. HRGN g_hrgnClip = NULL;
  62. HBRUSH g_hbrWindow = NULL;
  63. COptions g_Options;
  64. static BOOL fAlreadySetPos = FALSE;
  65. BOOL g_bMirroredOS = FALSE;
  66. #define SHORTSTRLEN 32
  67. //
  68. // Global strings - short strings used too often to be LoadString'd
  69. // every time
  70. //
  71. TCHAR g_szRealtime [SHORTSTRLEN];
  72. TCHAR g_szNormal [SHORTSTRLEN];
  73. TCHAR g_szHigh [SHORTSTRLEN];
  74. TCHAR g_szLow [SHORTSTRLEN];
  75. TCHAR g_szUnknown [SHORTSTRLEN];
  76. TCHAR g_szAboveNormal [SHORTSTRLEN];
  77. TCHAR g_szBelowNormal [SHORTSTRLEN];
  78. TCHAR g_szHung [SHORTSTRLEN];
  79. TCHAR g_szRunning [SHORTSTRLEN];
  80. TCHAR g_szfmtTasks [SHORTSTRLEN];
  81. TCHAR g_szfmtProcs [SHORTSTRLEN];
  82. TCHAR g_szfmtCPU [SHORTSTRLEN];
  83. TCHAR g_szfmtMEMK [SHORTSTRLEN];
  84. TCHAR g_szfmtMEMM [SHORTSTRLEN];
  85. TCHAR g_szfmtCPUNum [SHORTSTRLEN];
  86. TCHAR g_szTotalCPU [SHORTSTRLEN];
  87. TCHAR g_szKernelCPU [SHORTSTRLEN];
  88. TCHAR g_szMemUsage [SHORTSTRLEN];
  89. TCHAR g_szBytes [SHORTSTRLEN];
  90. TCHAR g_szPackets [SHORTSTRLEN];
  91. TCHAR g_szBitsPerSec [SHORTSTRLEN];
  92. TCHAR g_szScaleFont [SHORTSTRLEN];
  93. TCHAR g_szPercent [SHORTSTRLEN];
  94. TCHAR g_szZero [SHORTSTRLEN];
  95. TCHAR g_szNonOperational [SHORTSTRLEN];
  96. TCHAR g_szUnreachable [SHORTSTRLEN];
  97. TCHAR g_szDisconnected [SHORTSTRLEN];
  98. TCHAR g_szConnecting [SHORTSTRLEN];
  99. TCHAR g_szConnected [SHORTSTRLEN];
  100. TCHAR g_szOperational [SHORTSTRLEN];
  101. TCHAR g_szUnknownStatus [SHORTSTRLEN];
  102. TCHAR g_szTimeSep [SHORTSTRLEN];
  103. TCHAR g_szGroupThousSep [SHORTSTRLEN];
  104. TCHAR g_szDecimal [SHORTSTRLEN];
  105. ULONG g_ulGroupSep;
  106. TCHAR g_szG[10]; // Localized "G"igabyte symbol
  107. TCHAR g_szM[10]; // Localized "M"egabyte symbol
  108. TCHAR g_szK[10]; // Localized "K"ilobyte symbol
  109. // Page Array
  110. //
  111. // Each of the page objects is delcared here, and g_pPages is an array
  112. // of pointers to those instantiated objects (at global scope). The main
  113. // window code can call through the base members of the CPage class to
  114. // do things like sizing, etc., without worrying about whatever specific
  115. // stuff each page might do
  116. int g_nPageCount = 0;
  117. CPage * g_pPages[NUM_PAGES] = { NULL };
  118. typedef DWORD (WINAPI * PFNCM_REQUEST_EJECT_PC) (void);
  119. PFNCM_REQUEST_EJECT_PC gpfnCM_Request_Eject_PC = NULL;
  120. // Terminal Services
  121. BOOL g_fIsTSEnabled = FALSE;
  122. BOOL g_fIsSingleUserTS = FALSE;
  123. BOOL g_fIsTSServer = FALSE;
  124. DWORD g_dwMySessionId = 0;
  125. /*
  126. Superclass of GROUPBOX
  127. We need to turn on clipchildren for our dialog which contains the
  128. history graphs, so they don't get erased during the repaint cycle.
  129. Unfortunately, group boxes don't erase their backgrounds, so we
  130. have to superclass them and provide a control that does.
  131. This is a lot of extra work, but the painting is several orders of
  132. magnitude nicer with it...
  133. */
  134. /*++ DavesFrameWndProc
  135. Routine Description:
  136. WndProc for the custom group box class. Primary difference from
  137. standard group box is that this one knows how to erase its own
  138. background, and doesn't rely on the parent to do it for it.
  139. These controls also have CLIPSIBLINGS turn on so as not to stomp
  140. on the ownderdraw graphs they surround.
  141. Arguments:
  142. standard wndproc fare
  143. Revision History:
  144. Nov-29-95 Davepl Created
  145. --*/
  146. WNDPROC oldButtonWndProc = NULL;
  147. LRESULT DavesFrameWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  148. {
  149. if (msg == WM_CREATE)
  150. {
  151. //
  152. // Turn on clipsiblings for the frame
  153. //
  154. DWORD dwStyle = GetWindowLong(hWnd, GWL_STYLE);
  155. dwStyle |= WS_CLIPSIBLINGS;
  156. SetWindowLong(hWnd, GWL_STYLE, dwStyle);
  157. }
  158. else if (msg == WM_ERASEBKGND)
  159. {
  160. return DefWindowProc( hWnd, msg, wParam, lParam );
  161. }
  162. // For anything else, we defer to the standard button class code
  163. return CallWindowProc(oldButtonWndProc, hWnd, msg, wParam, lParam);
  164. }
  165. /*++ COptions::Save
  166. Routine Description:
  167. Saves current options to the registy
  168. Arguments:
  169. Returns:
  170. HRESULT
  171. Revision History:
  172. Jan-01-95 Davepl Created
  173. --*/
  174. const TCHAR szTaskmanKey[] = TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\TaskManager");
  175. const TCHAR szOptionsKey[] = TEXT("Preferences");
  176. HRESULT COptions::Save()
  177. {
  178. DWORD dwDisposition;
  179. HKEY hkSave;
  180. if (ERROR_SUCCESS != RegCreateKeyEx(HKEY_CURRENT_USER,
  181. szTaskmanKey,
  182. 0,
  183. TEXT("REG_BINARY"),
  184. REG_OPTION_NON_VOLATILE,
  185. KEY_WRITE,
  186. NULL,
  187. &hkSave,
  188. &dwDisposition))
  189. {
  190. return GetLastHRESULT();
  191. }
  192. if (ERROR_SUCCESS != RegSetValueEx(hkSave,
  193. szOptionsKey,
  194. 0,
  195. REG_BINARY,
  196. (LPBYTE) this,
  197. sizeof(COptions)))
  198. {
  199. RegCloseKey(hkSave);
  200. return GetLastHRESULT();
  201. }
  202. RegCloseKey(hkSave);
  203. return S_OK;
  204. }
  205. /*++ COptions::Load
  206. Routine Description:
  207. Loads current options to the registy
  208. Arguments:
  209. Returns:
  210. HRESULT
  211. Revision History:
  212. Jan-01-95 Davepl Created
  213. --*/
  214. HRESULT COptions::Load()
  215. {
  216. HKEY hkSave;
  217. // If ctrl-alt-shift is down at startup, "forget" registry settings
  218. if (GetKeyState(VK_SHIFT) < 0 &&
  219. GetKeyState(VK_MENU) < 0 &&
  220. GetKeyState(VK_CONTROL) < 0)
  221. {
  222. SetDefaultValues();
  223. return S_FALSE;
  224. }
  225. if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_CURRENT_USER,
  226. szTaskmanKey,
  227. 0,
  228. KEY_READ,
  229. &hkSave))
  230. {
  231. return S_FALSE;
  232. }
  233. DWORD dwType;
  234. DWORD dwSize = sizeof(COptions);
  235. if (ERROR_SUCCESS != RegQueryValueEx(hkSave,
  236. szOptionsKey,
  237. 0,
  238. &dwType,
  239. (LPBYTE) this,
  240. &dwSize)
  241. // Validate type and size of options info we got from the registry
  242. || dwType != REG_BINARY
  243. || dwSize != sizeof(COptions)
  244. // Validate options, revert to default if any are invalid (like if
  245. // the window would be offscreen)
  246. || MonitorFromRect(&m_rcWindow, MONITOR_DEFAULTTONULL) == NULL
  247. //number of available pages might be less than NUM_PAGES
  248. || m_iCurrentPage > g_nPageCount - 1)
  249. {
  250. // Reset to default values
  251. SetDefaultValues();
  252. RegCloseKey(hkSave);
  253. return S_FALSE;
  254. }
  255. RegCloseKey(hkSave);
  256. return S_OK;
  257. }
  258. /*++ COptions::SetDefaultValues
  259. Routine Description:
  260. Used to init the options to a default state when the saved copy
  261. cannot be found, is damaged, or is not the correct version
  262. Arguments:
  263. Returns:
  264. nothing
  265. Revision History:
  266. Dec-06-00 jeffreys Moved from taskmgr.h
  267. --*/
  268. BOOL IsUserAdmin();
  269. // Columns which are visible, by default, in the process view
  270. const COLUMNID g_aDefaultCols[] = { COL_IMAGENAME, COL_USERNAME, COL_CPU, COL_MEMUSAGE, (COLUMNID)-1 };
  271. const COLUMNID g_aTSCols[] = { COL_IMAGENAME, COL_USERNAME, COL_SESSIONID, COL_CPU, COL_MEMUSAGE, (COLUMNID)-1 };
  272. const NETCOLUMNID g_aNetDefaultCols[] = { COL_ADAPTERNAME, COL_NETWORKUTIL, COL_LINKSPEED, COL_STATE, (NETCOLUMNID)-1 };
  273. void COptions::SetDefaultValues()
  274. {
  275. ZeroMemory(this, sizeof(COptions));
  276. m_cbSize = sizeof(COptions);
  277. BOOL bScreenReader = FALSE;
  278. if (SystemParametersInfo(SPI_GETSCREENREADER, 0, (PVOID) &bScreenReader, 0) && bScreenReader)
  279. {
  280. // No automatic updates for machines with screen readers
  281. m_dwTimerInterval = 0;
  282. }
  283. else
  284. {
  285. m_dwTimerInterval = 1000;
  286. }
  287. m_vmViewMode = VM_DETAILS;
  288. m_cmHistMode = CM_PANES;
  289. m_usUpdateSpeed = US_NORMAL;
  290. m_fMinimizeOnUse = TRUE;
  291. m_fConfirmations = TRUE;
  292. m_fAlwaysOnTop = TRUE;
  293. m_fShow16Bit = TRUE;
  294. m_iCurrentPage = -1;
  295. m_rcWindow.top = 10;
  296. m_rcWindow.left = 10;
  297. m_rcWindow.bottom = 10 + g_minHeight;
  298. m_rcWindow.right = 10 + g_minWidth;
  299. m_bShowAllProcess = (g_fIsTSEnabled && !g_fIsSingleUserTS && IsUserAdmin());
  300. const COLUMNID *pcol = (g_fIsTSEnabled && !g_fIsSingleUserTS) ? g_aTSCols : g_aDefaultCols;
  301. for (int i = 0; i < NUM_COLUMN + 1 ; i++, pcol++)
  302. {
  303. m_ActiveProcCol[i] = *pcol;
  304. if ((COLUMNID)-1 == *pcol)
  305. break;
  306. }
  307. // Set all of the columns widths to -1
  308. FillMemory(m_ColumnWidths, sizeof(m_ColumnWidths), 0xFF);
  309. FillMemory(m_ColumnPositions, sizeof(m_ColumnPositions), 0xFF);
  310. // Set the Network default values
  311. //
  312. const NETCOLUMNID *pnetcol = g_aNetDefaultCols;
  313. for (int i = 0; i < NUM_NETCOLUMN + 1 ; i++, pnetcol++)
  314. {
  315. m_ActiveNetCol[i] = *pnetcol;
  316. if ((NETCOLUMNID)-1 == *pnetcol)
  317. break;
  318. }
  319. // Set all of the columns widths to -1
  320. //
  321. FillMemory(m_NetColumnWidths, sizeof(m_NetColumnWidths), 0xFF);
  322. FillMemory(m_NetColumnPositions, sizeof(m_NetColumnPositions), 0xFF);
  323. m_bAutoSize = TRUE;
  324. m_bGraphBytesSent = FALSE;
  325. m_bGraphBytesReceived = FALSE;
  326. m_bGraphBytesTotal = TRUE;
  327. m_bNetShowAll = FALSE;
  328. m_bShowScale = TRUE;
  329. m_bTabAlwaysActive = FALSE;
  330. }
  331. BOOL FPalette(void)
  332. {
  333. HDC hdc = GetDC(NULL);
  334. BOOL fPalette = (GetDeviceCaps(hdc, NUMCOLORS) != -1);
  335. ReleaseDC(NULL, hdc);
  336. return fPalette;
  337. }
  338. /*++ InitDavesControls
  339. Routine Description:
  340. Superclasses GroupBox for better drawing
  341. Note that I'm not very concerned about failure here, since it
  342. something goes wrong the dialog creation will fail awayway, and
  343. it will be handled there
  344. Arguments:
  345. Revision History:
  346. Nov-29-95 Davepl Created
  347. --*/
  348. void InitDavesControls()
  349. {
  350. static const TCHAR szControlName[] = TEXT("DavesFrameClass");
  351. WNDCLASS wndclass;
  352. //
  353. // Get the class info for the Button class (which is what group
  354. // boxes really are) and create a new class based on it
  355. //
  356. if (!GetClassInfo(g_hInstance, TEXT("Button"), &wndclass))
  357. return; // Ungraceful exit, but better than random unit'd lpfnWndProc
  358. oldButtonWndProc = wndclass.lpfnWndProc;
  359. wndclass.hInstance = g_hInstance;
  360. wndclass.lpfnWndProc = DavesFrameWndProc;
  361. wndclass.lpszClassName = szControlName;
  362. wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
  363. (ATOM)RegisterClass(&wndclass);
  364. return;
  365. }
  366. /*++ SetTitle
  367. Routine Description:
  368. Sets the app's title in the title bar (we do this on startup and
  369. when coming out of notitle mode).
  370. Arguments:
  371. none
  372. Return Value:
  373. none
  374. Revision History:
  375. Jan-24-95 Davepl Created
  376. --*/
  377. void SetTitle()
  378. {
  379. TCHAR szTitle[MAX_PATH];
  380. LoadString(g_hInstance, IDS_APPTITLE, szTitle, MAX_PATH);
  381. SetWindowText(g_hMainWnd, szTitle);
  382. }
  383. /*++ UpdateMenuStates
  384. Routine Description:
  385. Updates the menu checks / ghosting based on the
  386. current settings and options
  387. Arguments:
  388. Return Value:
  389. Revision History:
  390. Nov-29-95 Davepl Created
  391. --*/
  392. void UpdateMenuStates()
  393. {
  394. HMENU hMenu = GetMenu(g_hMainWnd);
  395. if (hMenu)
  396. {
  397. CheckMenuRadioItem(hMenu, VM_FIRST, VM_LAST, VM_FIRST + (UINT) g_Options.m_vmViewMode, MF_BYCOMMAND);
  398. CheckMenuRadioItem(hMenu, CM_FIRST, CM_LAST, CM_FIRST + (UINT) g_Options.m_cmHistMode, MF_BYCOMMAND);
  399. CheckMenuRadioItem(hMenu, US_FIRST, US_LAST, US_FIRST + (UINT) g_Options.m_usUpdateSpeed, MF_BYCOMMAND);
  400. // REVIEW (davepl) could be table driven
  401. CheckMenuItem(hMenu, IDM_ALWAYSONTOP, MF_BYCOMMAND | (g_Options.m_fAlwaysOnTop ? MF_CHECKED : MF_UNCHECKED));
  402. CheckMenuItem(hMenu, IDM_MINIMIZEONUSE, MF_BYCOMMAND | (g_Options.m_fMinimizeOnUse ? MF_CHECKED : MF_UNCHECKED));
  403. CheckMenuItem(hMenu, IDM_KERNELTIMES, MF_BYCOMMAND | (g_Options.m_fKernelTimes ? MF_CHECKED : MF_UNCHECKED));
  404. CheckMenuItem(hMenu, IDM_NOTITLE, MF_BYCOMMAND | (g_Options.m_fNoTitle ? MF_CHECKED : MF_UNCHECKED));
  405. CheckMenuItem(hMenu, IDM_HIDEWHENMIN, MF_BYCOMMAND | (g_Options.m_fHideWhenMin ? MF_CHECKED : MF_UNCHECKED));
  406. CheckMenuItem(hMenu, IDM_SHOW16BIT, MF_BYCOMMAND | (g_Options.m_fShow16Bit ? MF_CHECKED : MF_UNCHECKED));
  407. CheckMenuItem(hMenu, IDM_SHOWDOMAINNAMES, MF_BYCOMMAND | (g_Options.m_fShowDomainNames ? MF_CHECKED : MF_UNCHECKED));
  408. // Remove the CPU history style options on single processor machines
  409. if (g_cProcessors < 2)
  410. {
  411. DeleteMenu(hMenu, IDM_ALLCPUS, MF_BYCOMMAND);
  412. }
  413. CheckMenuItem(hMenu,IDM_SHOWSCALE, g_Options.m_bShowScale ? MF_CHECKED:MF_UNCHECKED);
  414. CheckMenuItem(hMenu,IDM_AUTOSIZE, g_Options.m_bAutoSize ? MF_CHECKED:MF_UNCHECKED);
  415. CheckMenuItem(hMenu,IDM_BYTESSENT, g_Options.m_bGraphBytesSent ? MF_CHECKED:MF_UNCHECKED);
  416. CheckMenuItem(hMenu,IDM_BYTESRECEIVED, g_Options.m_bGraphBytesReceived ? MF_CHECKED:MF_UNCHECKED);
  417. CheckMenuItem(hMenu,IDM_BYTESTOTAL, g_Options.m_bGraphBytesTotal ? MF_CHECKED:MF_UNCHECKED);
  418. CheckMenuItem(hMenu,IDM_SHOWALLDATA, g_Options.m_bNetShowAll ? MF_CHECKED:MF_UNCHECKED);
  419. CheckMenuItem(hMenu,IDM_TABALWAYSACTIVE, g_Options.m_bTabAlwaysActive ? MF_CHECKED:MF_UNCHECKED);
  420. }
  421. }
  422. /*++ SizeChildPage
  423. Routine Description:
  424. Size the active child page based on the tab control
  425. Arguments:
  426. hwndMain - Main window
  427. Return Value:
  428. Revision History:
  429. Nov-29-95 Davepl Created
  430. --*/
  431. void SizeChildPage(HWND hwndMain)
  432. {
  433. if (g_Options.m_iCurrentPage >= 0)
  434. {
  435. // If we are in maximum viewing mode, the page gets the whole
  436. // window area
  437. HWND hwndPage = g_pPages[g_Options.m_iCurrentPage]->GetPageWindow();
  438. DWORD dwStyle = GetWindowLong (g_hMainWnd, GWL_STYLE);
  439. if (g_Options.m_fNoTitle)
  440. {
  441. RECT rcMainWnd;
  442. GetClientRect(g_hMainWnd, &rcMainWnd);
  443. SetWindowPos(hwndPage, HWND_TOP, rcMainWnd.left, rcMainWnd.top,
  444. rcMainWnd.right - rcMainWnd.left,
  445. rcMainWnd.bottom - rcMainWnd.top, SWP_NOZORDER | SWP_NOACTIVATE);
  446. // remove caption & menu bar, etc.
  447. dwStyle &= ~(WS_DLGFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX);
  448. // SetWindowLong (g_hMainWnd, GWL_ID, 0);
  449. SetWindowLong (g_hMainWnd, GWL_STYLE, dwStyle);
  450. SetMenu(g_hMainWnd, NULL);
  451. }
  452. else
  453. {
  454. // If we have a page being displayed, we need to size it also
  455. // put menu bar & caption back in
  456. dwStyle = WS_TILEDWINDOW | dwStyle;
  457. SetWindowLong (g_hMainWnd, GWL_STYLE, dwStyle);
  458. if (g_hMenu)
  459. {
  460. SetMenu(g_hMainWnd, g_hMenu);
  461. UpdateMenuStates();
  462. }
  463. SetTitle();
  464. if (hwndPage)
  465. {
  466. RECT rcCtl;
  467. HWND hwndCtl = GetDlgItem(hwndMain, IDC_TABS);
  468. GetClientRect(hwndCtl, &rcCtl);
  469. MapWindowPoints(hwndCtl, hwndMain, (LPPOINT)&rcCtl, 2);
  470. TabCtrl_AdjustRect(hwndCtl, FALSE, &rcCtl);
  471. SetWindowPos(hwndPage, HWND_TOP, rcCtl.left, rcCtl.top,
  472. rcCtl.right - rcCtl.left, rcCtl.bottom - rcCtl.top, SWP_NOZORDER | SWP_NOACTIVATE);
  473. }
  474. }
  475. if( g_Options.m_iCurrentPage == NET_PAGE )
  476. {
  477. // The network page is dynamic adapters can be added and removed. If taskmgr is minimized and
  478. // a Adapter is added or removed. When taskmgr is maximized/restored again the netpage must be
  479. // resized so the change is reflected. Thus the size change must be reported to the adapter.
  480. //
  481. ((CNetPage *)g_pPages[g_Options.m_iCurrentPage])->SizeNetPage();
  482. }
  483. }
  484. }
  485. /*++ UpdateStatusBar
  486. Routine Description:
  487. Draws the status bar with test based on data accumulated by all of
  488. the various pages (basically a summary of most important info)
  489. Arguments:
  490. Return Value:
  491. Revision History:
  492. Nov-29-95 Davepl Created
  493. --*/
  494. void UpdateStatusBar()
  495. {
  496. //
  497. // If we're in menu-tracking mode (sticking help text in the stat
  498. // bar), we don't draw our standard text
  499. //
  500. if (FALSE == g_fMenuTracking)
  501. {
  502. TCHAR szText[MAX_PATH];
  503. wsprintf(szText, g_szfmtProcs, g_cProcesses);
  504. SendMessage(g_hStatusWnd, SB_SETTEXT, 0, (LPARAM) szText);
  505. wsprintf(szText, g_szfmtCPU, g_CPUUsage);
  506. SendMessage(g_hStatusWnd, SB_SETTEXT, 1, (LPARAM) szText);
  507. //
  508. // If more than 900 megs are in the machine switch to M mode.
  509. //
  510. if ( g_MEMMax > 900 * 1024 )
  511. {
  512. wsprintf(szText, g_szfmtMEMM, g_MEMUsage / 1024, g_MEMMax / 1024);
  513. }
  514. else
  515. {
  516. wsprintf(szText, g_szfmtMEMK, g_MEMUsage, g_MEMMax);
  517. }
  518. SendMessage(g_hStatusWnd, SB_SETTEXT, 2, (LPARAM) szText);
  519. }
  520. }
  521. /*++ MainWnd_OnTimer
  522. Routine Description:
  523. Called when the refresh timer fires, we pass a timer event on to
  524. each of the child pages.
  525. Arguments:
  526. hwnd - window timer was received at
  527. id - id of timer that was received
  528. Return Value:
  529. Revision History:
  530. Nov-30-95 Davepl Created
  531. --*/
  532. void MainWnd_OnTimer(HWND hwnd, UINT id)
  533. {
  534. static const cchTipTextSize = (2 * SHORTSTRLEN);
  535. if (GetForegroundWindow() == hwnd && GetKeyState(VK_CONTROL) < 0)
  536. {
  537. // CTRL alone means pause
  538. return;
  539. }
  540. // Notify each of the pages in turn that they need to updatre
  541. for (int i = 0; i < g_nPageCount; i++)
  542. {
  543. g_pPages[i]->TimerEvent();
  544. }
  545. // Update the tray icon
  546. UINT iIconIndex = (g_CPUUsage * g_cTrayIcons) / 100;
  547. if (iIconIndex >= g_cTrayIcons)
  548. {
  549. iIconIndex = g_cTrayIcons - 1; // Handle 100% case
  550. }
  551. LPWSTR pszTipText = (LPWSTR) HeapAlloc( GetProcessHeap( ), 0, cchTipTextSize * sizeof(WCHAR) );
  552. if ( NULL != pszTipText )
  553. {
  554. wnsprintf( pszTipText, cchTipTextSize, g_szfmtCPU, g_CPUUsage );
  555. }
  556. BOOL b = PostThreadMessage( g_idTrayThread, PM_NOTIFYWAITING, iIconIndex, (LPARAM) pszTipText );
  557. if ( !b )
  558. {
  559. HeapFree( GetProcessHeap( ), 0, pszTipText );
  560. }
  561. UpdateStatusBar();
  562. }
  563. /*++ MainWnd_OnInitDialog
  564. Routine Description:
  565. Processes WM_INITDIALOG for the main window (a modeless dialog)
  566. Revision History:
  567. Nov-29-95 Davepl Created
  568. --*/
  569. BOOL MainWnd_OnInitDialog(HWND hwnd, HWND hwndFocus, LPARAM lParam)
  570. {
  571. RECT rcMain;
  572. GetWindowRect(hwnd, &rcMain);
  573. g_minWidth = rcMain.right - rcMain.left;
  574. g_minHeight = rcMain.bottom - rcMain.top;
  575. g_DefSpacing = (DEFSPACING_BASE * LOWORD(GetDialogBaseUnits())) / DLG_SCALE_X;
  576. g_InnerSpacing = (INNERSPACING_BASE * LOWORD(GetDialogBaseUnits())) / DLG_SCALE_X;
  577. g_TopSpacing = (TOPSPACING_BASE * HIWORD(GetDialogBaseUnits())) / DLG_SCALE_Y;
  578. // Load the user's defaults
  579. g_Options.Load();
  580. //
  581. // On init, save away the window handle for all to see
  582. //
  583. g_hMainWnd = hwnd;
  584. g_hMainDesktop = GetThreadDesktop(GetCurrentThreadId());
  585. // init some globals
  586. g_cxEdge = GetSystemMetrics(SM_CXEDGE);
  587. g_hrgnView = CreateRectRgn(0, 0, 0, 0);
  588. g_hrgnClip = CreateRectRgn(0, 0, 0, 0);
  589. g_hbrWindow = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
  590. // If we're supposed to be TOPMOST, start out that way
  591. if (g_Options.m_fAlwaysOnTop)
  592. {
  593. SetWindowPos(hwnd, HWND_TOPMOST, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE);
  594. }
  595. //
  596. // Create the status window
  597. //
  598. g_hStatusWnd = CreateStatusWindow(WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | SBARS_SIZEGRIP,
  599. NULL,
  600. hwnd,
  601. IDC_STATUSWND);
  602. if (NULL == g_hStatusWnd)
  603. {
  604. return FALSE;
  605. }
  606. //
  607. // Base the panes in the status bar off of the LOGPIXELSX system metric
  608. //
  609. HDC hdc = GetDC(NULL);
  610. INT nInch = GetDeviceCaps(hdc, LOGPIXELSX);
  611. ReleaseDC(NULL, hdc);
  612. int ciParts[] = { nInch,
  613. ciParts[0] + (nInch * 5) / 4,
  614. ciParts[1] + (nInch * 5) / 2,
  615. -1};
  616. if (g_hStatusWnd)
  617. {
  618. SendMessage(g_hStatusWnd, SB_SETPARTS, ARRAYSIZE(ciParts), (LPARAM)ciParts);
  619. }
  620. //
  621. // Load our app icon
  622. //
  623. HICON hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_MAIN));
  624. if (hIcon)
  625. {
  626. SendMessage(hwnd, WM_SETICON, TRUE, LPARAM(hIcon));
  627. }
  628. //
  629. // Add the tray icons using the tray thread.
  630. //
  631. PostThreadMessage( g_idTrayThread, PM_INITIALIZEICONS, 0, 0 );
  632. //
  633. // Turn on TOPMOST for the status bar so it doesn't slide under the
  634. // tab control
  635. //
  636. SetWindowPos(g_hStatusWnd,
  637. HWND_TOPMOST,
  638. 0,0,0,0,
  639. SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW);
  640. //
  641. // Intialize each of the the pages in turn
  642. //
  643. HWND hwndTabs = GetDlgItem(hwnd, IDC_TABS);
  644. // OMILLER Need to add my stuff to this for my page to init (insert tab)
  645. //
  646. for (int i = 0; i < g_nPageCount; i++)
  647. {
  648. HRESULT hr;
  649. hr = g_pPages[i]->Initialize(hwndTabs);
  650. if (SUCCEEDED(hr))
  651. {
  652. //
  653. // Get the title of the new page, and use it as the title of
  654. // the page which we insert into the tab control
  655. //
  656. TCHAR szTitle[MAX_PATH];
  657. g_pPages[i]->GetTitle(szTitle, ARRAYSIZE(szTitle));
  658. TC_ITEM tcitem =
  659. {
  660. TCIF_TEXT, // value specifying which members to retrieve or set
  661. NULL, // reserved; do not use
  662. NULL, // reserved; do not use
  663. szTitle, // pointer to string containing tab text
  664. ARRAYSIZE(szTitle), // size of buffer pointed to by the pszText member
  665. 0, // index to tab control's image
  666. NULL // application-defined data associated with tab
  667. };
  668. if (- 1 == TabCtrl_InsertItem(hwndTabs, i, &tcitem))
  669. {
  670. hr = E_FAIL;
  671. }
  672. }
  673. //
  674. // If a page failed to init, destroy the pages we have created up to this point
  675. // We don't remove the tabs, on the assumption that the app is going away anyway
  676. //
  677. if (FAILED(hr))
  678. {
  679. for (int j = i; j >= 0; j--)
  680. {
  681. g_pPages[i]->Destroy();
  682. }
  683. return FALSE;
  684. }
  685. else
  686. {
  687. }
  688. }
  689. //
  690. // Set the inital menu states
  691. //
  692. UpdateMenuStates();
  693. //
  694. // Activate a page (pick page 0 if no preference is set)
  695. //
  696. if (g_Options.m_iCurrentPage < 0)
  697. {
  698. g_Options.m_iCurrentPage = 0;
  699. }
  700. TabCtrl_SetCurSel(GetDlgItem(g_hMainWnd, IDC_TABS), g_Options.m_iCurrentPage);
  701. g_pPages[g_Options.m_iCurrentPage]->Activate();
  702. RECT rcMainClient;
  703. GetClientRect(hwnd, &rcMainClient);
  704. MainWnd_OnSize(g_hMainWnd, 0, rcMainClient.right - rcMainClient.left, rcMainClient.bottom - rcMainClient.top);
  705. //
  706. // Create the update timer
  707. //
  708. if (g_Options.m_dwTimerInterval) // 0 == paused
  709. {
  710. SetTimer(g_hMainWnd, 0, g_Options.m_dwTimerInterval, NULL);
  711. }
  712. // Force at least one intial update so that we don't need to wait
  713. // for the first timed update to come through
  714. MainWnd_OnTimer(g_hMainWnd, 0);
  715. //
  716. // Disable the MP-specific menu items
  717. //
  718. if (g_cProcessors <= 1)
  719. {
  720. HMENU hMenu = GetMenu(g_hMainWnd);
  721. EnableMenuItem(hMenu, IDM_MULTIGRAPH, MF_BYCOMMAND | MF_GRAYED);
  722. }
  723. return TRUE;
  724. }
  725. //
  726. // Draw an edge just below menu bar
  727. //
  728. void MainWnd_Draw(HWND hwnd, HDC hdc)
  729. {
  730. RECT rc;
  731. GetClientRect(hwnd, &rc);
  732. DrawEdge(hdc, &rc, EDGE_ETCHED, BF_TOP);
  733. }
  734. void MainWnd_OnPrintClient(HWND hwnd, HDC hdc)
  735. {
  736. MainWnd_Draw(hwnd, hdc);
  737. }
  738. /*++ MainWnd_OnPaint
  739. Routine Description:
  740. Just draws a thin edge just below the main menu bar
  741. Arguments:
  742. hwnd - Main window
  743. Return Value:
  744. Revision History:
  745. Nov-29-95 Davepl Created
  746. --*/
  747. void MainWnd_OnPaint(HWND hwnd)
  748. {
  749. PAINTSTRUCT ps;
  750. //
  751. // Don't waste our time if we're minimized
  752. //
  753. if (FALSE == IsIconic(hwnd))
  754. {
  755. BeginPaint(hwnd, &ps);
  756. MainWnd_Draw(hwnd, ps.hdc);
  757. EndPaint(hwnd, &ps);
  758. }
  759. else
  760. {
  761. FORWARD_WM_PAINT(hwnd, DefWindowProc);
  762. }
  763. }
  764. /*++ MainWnd_OnMenuSelect
  765. Routine Description:
  766. As the user browses menus in the app, writes help text to the
  767. status bar. Also temporarily sets it to be a plain status bar
  768. with no panes
  769. Arguments:
  770. Return Value:
  771. Revision History:
  772. Nov-29-95 Davepl Created
  773. --*/
  774. void MainWnd_OnMenuSelect(HWND hwnd, HMENU hmenu, int item, HMENU hmenuPopup, UINT flags)
  775. {
  776. //
  777. // If menu is dismissed, restore the panes in the status bar, turn off the
  778. // global "menu tracking" flag, and redraw the status bar with normal info
  779. //
  780. if ((0xFFFF == LOWORD(flags) && NULL == hmenu) || // dismissed the menu
  781. (flags & (MF_SYSMENU | MF_SEPARATOR))) // sysmenu or separator
  782. {
  783. SendMessage(g_hStatusWnd, SB_SIMPLE, FALSE, 0L); // Restore sb panes
  784. g_fMenuTracking = FALSE;
  785. g_fCantHide = FALSE;
  786. UpdateStatusBar();
  787. return;
  788. }
  789. else
  790. {
  791. //
  792. // If its a popup, go get the submenu item that is selected instead
  793. //
  794. if (flags & MF_POPUP)
  795. {
  796. MENUITEMINFO miiSubMenu;
  797. miiSubMenu.cbSize = sizeof(MENUITEMINFO);
  798. miiSubMenu.fMask = MIIM_ID;
  799. miiSubMenu.cch = 0;
  800. if (FALSE == GetMenuItemInfo(hmenu, item, TRUE, &miiSubMenu))
  801. {
  802. return;
  803. }
  804. //
  805. // Change the parameters to simulate a "normal" menu item
  806. //
  807. item = miiSubMenu.wID;
  808. flags &= ~MF_POPUP;
  809. }
  810. //
  811. // Our menus always have the same IDs as the strings that describe
  812. // their functions...
  813. //
  814. TCHAR szStatusText[MAX_PATH];
  815. LoadString(g_hInstance, item, szStatusText, ARRAYSIZE(szStatusText));
  816. g_fMenuTracking = TRUE;
  817. SendMessage(g_hStatusWnd, SB_SETTEXT, SBT_NOBORDERS | 255, (LPARAM)szStatusText);
  818. SendMessage(g_hStatusWnd, SB_SIMPLE, TRUE, 0L); // Remove sb panes
  819. SendMessage(g_hStatusWnd, SB_SETTEXT, SBT_NOBORDERS | 0, (LPARAM) szStatusText);
  820. }
  821. }
  822. /*++ MainWnd_OnTabCtrlNotify
  823. Routine Description:
  824. Handles WM_NOTIFY messages sent to the main window on behalf of the
  825. tab control
  826. Arguments:
  827. pnmhdr - ptr to the notification block's header
  828. Return Value:
  829. BOOL - depends on message
  830. Revision History:
  831. Nov-29-95 Davepl Created
  832. --*/
  833. BOOL MainWnd_OnTabCtrlNotify(LPNMHDR pnmhdr)
  834. {
  835. HWND hwndTab = pnmhdr->hwndFrom;
  836. //
  837. // Selection is changing (new page coming to the front), so activate
  838. // the appropriate page
  839. //
  840. if (TCN_SELCHANGE == pnmhdr->code)
  841. {
  842. INT iTab = TabCtrl_GetCurSel(hwndTab);
  843. if (-1 != iTab)
  844. {
  845. if (-1 != g_Options.m_iCurrentPage)
  846. {
  847. g_pPages[g_Options.m_iCurrentPage]->Deactivate();
  848. }
  849. if (FAILED(g_pPages[iTab]->Activate()))
  850. {
  851. // If we weren't able to activate the new page,
  852. // reactivate the old page just to be sure
  853. if (-1 != g_Options.m_iCurrentPage)
  854. {
  855. g_pPages[iTab]->Activate();
  856. SizeChildPage(g_hMainWnd);
  857. }
  858. }
  859. else
  860. {
  861. g_Options.m_iCurrentPage = iTab;
  862. SizeChildPage(g_hMainWnd);
  863. return TRUE;
  864. }
  865. }
  866. }
  867. return FALSE;
  868. }
  869. /*++ MainWnd_OnSize
  870. Routine Description:
  871. Sizes the children of the main window as the size of the main
  872. window itself changes
  873. Arguments:
  874. hwnd - main window
  875. state - window state (not used here)
  876. cx - new x size
  877. cy - new y size
  878. Return Value:
  879. BOOL - depends on message
  880. Revision History:
  881. Nov-29-95 Davepl Created
  882. --*/
  883. void MainWnd_OnSize(HWND hwnd, UINT state, int cx, int cy)
  884. {
  885. if (state == SIZE_MINIMIZED)
  886. {
  887. // If there's a tray, we can just hide since we have a
  888. // tray icon anyway.
  889. if (GetShellWindow() && g_Options.m_fHideWhenMin)
  890. {
  891. ShowWindow(hwnd, SW_HIDE);
  892. }
  893. }
  894. //
  895. // Let the status bar adjust itself first, and we will work back
  896. // from its new position
  897. //
  898. HDWP hdwp = BeginDeferWindowPos(20);
  899. FORWARD_WM_SIZE(g_hStatusWnd, state, cx, cy, SendMessage);
  900. if (hdwp)
  901. {
  902. RECT rcStatus;
  903. GetClientRect(g_hStatusWnd, &rcStatus);
  904. MapWindowPoints(g_hStatusWnd, g_hMainWnd, (LPPOINT) &rcStatus, 2);
  905. //
  906. // Size the tab controls based on where the status bar is
  907. //
  908. HWND hwndTabs = GetDlgItem(hwnd, IDC_TABS);
  909. RECT rcTabs;
  910. GetWindowRect(hwndTabs, &rcTabs);
  911. MapWindowPoints(HWND_DESKTOP, g_hMainWnd, (LPPOINT) &rcTabs, 2);
  912. INT dx = cx - 2 * rcTabs.left;
  913. DeferWindowPos(hdwp, hwndTabs, NULL, 0, 0,
  914. dx,
  915. cy - (cy - rcStatus.top) - rcTabs.top * 2,
  916. SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  917. EndDeferWindowPos(hdwp);
  918. }
  919. //
  920. // Now size the front page and its children
  921. //
  922. if (cx || cy) // Don't size in minimized case
  923. SizeChildPage(hwnd);
  924. }
  925. /*++ RunDlg
  926. Routine Description:
  927. Loads shell32.dll and invokes its Run dialog
  928. Arguments:
  929. Return Value:
  930. Revision History:
  931. Nov-30-95 Davepl Created
  932. --*/
  933. DWORD RunDlg()
  934. {
  935. //
  936. // Put up the RUN dialog for the user
  937. //
  938. HICON hIcon = (HICON) LoadImage(g_hInstance, MAKEINTRESOURCE(IDI_MAIN), IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR | LR_DEFAULTSIZE);
  939. if (hIcon)
  940. {
  941. WCHAR szCurDir[MAX_PATH];
  942. WCHAR szTitle [MAX_PATH];
  943. WCHAR szPrompt[MAX_PATH];
  944. LoadStringW(g_hInstance, IDS_RUNTITLE, szTitle, MAX_PATH);
  945. LoadStringW(g_hInstance, IDS_RUNTEXT, szPrompt, MAX_PATH);
  946. GetCurrentDirectoryW(MAX_PATH, szCurDir);
  947. RunFileDlg(g_hMainWnd, hIcon, (LPTSTR) szCurDir,
  948. (LPTSTR) szTitle,
  949. (LPTSTR) szPrompt, RFD_USEFULLPATHDIR | RFD_WOW_APP);
  950. DestroyIcon(hIcon);
  951. }
  952. return TRUE;
  953. }
  954. // --------------------------------------------------------------------------
  955. // DeterminePowerCapabilities
  956. //
  957. // Arguments: pfHasHibernate = Has hibernate capability.
  958. // pfHasSleep = Has sleep capability.
  959. // pfHasPowerOff = Has power off capability.
  960. //
  961. // Returns: <none>
  962. //
  963. // Purpose: Returns whether power capabilities are present. Specify NULL
  964. // for power capabilities not required.
  965. //
  966. // History: 2000-02-29 vtan created
  967. // --------------------------------------------------------------------------
  968. void DeterminePowerCapabilities (BOOL *pfHasHibernate, BOOL *pfHasSleep, BOOL *pfHasPowerOff)
  969. {
  970. static BOOL s_fHasHibernate = FALSE;
  971. static BOOL s_fHasSleep = FALSE;
  972. static BOOL s_fHasPowerOff = FALSE;
  973. SYSTEM_POWER_CAPABILITIES spc;
  974. CPrivilegeEnable privilege(SE_SHUTDOWN_NAME);
  975. (NTSTATUS)NtPowerInformation(SystemPowerCapabilities,
  976. NULL,
  977. 0,
  978. &spc,
  979. sizeof(spc));
  980. if (pfHasHibernate != NULL)
  981. {
  982. *pfHasHibernate = spc.SystemS4 && spc.HiberFilePresent;
  983. }
  984. if (pfHasSleep != NULL)
  985. {
  986. *pfHasSleep = spc.SystemS1 || spc.SystemS2 || spc.SystemS3;
  987. }
  988. if (pfHasPowerOff != NULL)
  989. {
  990. *pfHasPowerOff = spc.SystemS5;
  991. }
  992. }
  993. // --------------------------------------------------------------------------
  994. // LoadEjectFunction
  995. //
  996. // Arguments: <none>
  997. //
  998. // Returns: <none>
  999. //
  1000. // Purpose: Loads cfgmgr32 and gets the address of CM_Request_Eject_PC.
  1001. // It does NOT free the library intentionally.
  1002. //
  1003. // History: 2000-04-03 vtan created
  1004. // --------------------------------------------------------------------------
  1005. void LoadEjectFunction (void)
  1006. {
  1007. static BOOL s_fAttempted = FALSE;
  1008. if ((gpfnCM_Request_Eject_PC == NULL) && (s_fAttempted == FALSE))
  1009. {
  1010. HMODULE hModule;
  1011. s_fAttempted = TRUE;
  1012. hModule = LoadLibrary(TEXT("cfgmgr32"));
  1013. if (hModule != NULL)
  1014. {
  1015. gpfnCM_Request_Eject_PC = reinterpret_cast<PFNCM_REQUEST_EJECT_PC>(GetProcAddress(hModule, "CM_Request_Eject_PC"));
  1016. }
  1017. }
  1018. }
  1019. // --------------------------------------------------------------------------
  1020. // AdjustMenuBar
  1021. //
  1022. // Arguments: hMenu = Handle to the main menu.
  1023. //
  1024. // Returns: <none>
  1025. //
  1026. // Purpose: Removes the shutdown menu in the case of classic GINA logon.
  1027. //
  1028. // History: 2000-02-29 vtan created (split AdjustShutdownMenu)
  1029. // 2000-04-24 vtan split RemoveShutdownMenu
  1030. // --------------------------------------------------------------------------
  1031. void AdjustMenuBar (HMENU hMenu)
  1032. {
  1033. if( !IsOS(OS_FRIENDLYLOGONUI))
  1034. {
  1035. // Classic GINA UI - Find the "shutdown" menu and remove it.
  1036. BOOL fFound;
  1037. int i, iMenuItemCount;
  1038. MENUITEMINFO mii;
  1039. ZeroMemory(&mii, sizeof(mii));
  1040. mii.cbSize = sizeof(mii);
  1041. mii.fMask = MIIM_ID;
  1042. iMenuItemCount = GetMenuItemCount(hMenu);
  1043. for (fFound = FALSE, i = 0; !fFound && (i < iMenuItemCount); ++i)
  1044. {
  1045. if (GetMenuItemInfo(hMenu, i, TRUE, &mii) != FALSE)
  1046. {
  1047. fFound = mii.wID == IDM_MENU_SHUTDOWN;
  1048. if (fFound)
  1049. {
  1050. (BOOL)RemoveMenu(hMenu, i, MF_BYPOSITION);
  1051. }
  1052. }
  1053. }
  1054. }
  1055. }
  1056. // --------------------------------------------------------------------------
  1057. // AdjustShutdownMenu
  1058. //
  1059. // Arguments: hMenu = Handle to the main menu.
  1060. //
  1061. // Returns: <none>
  1062. //
  1063. // Purpose: Dynamically replaces the entire contents of the "Shut Down"
  1064. // popup menu and adjusts the enabled items based on user token
  1065. // privileges as well as machine capabilities. This is done
  1066. // dynamically to allow console disconnect and remoting to be
  1067. // correctly reflected in the state without restarting taskmgr.
  1068. //
  1069. // History: 2000-02-29 vtan created
  1070. // 2000-03-29 vtan reworked for new menu
  1071. // --------------------------------------------------------------------------
  1072. void AdjustShutdownMenu (HMENU hMenu)
  1073. // Adjusts the shutdown menu in the menu bar to reflect the machine
  1074. // capabilities and user privileges. Items that aren't accessible
  1075. // are disabled or removed. The menu contains the following:
  1076. // MENUITEM "Stand &By" IDM_STANDBY SE_SHUTDOWN_PRIVILEGE && S1-S3 !NoClose
  1077. // MENUITEM "&Hibernate" IDM_HIBERNATE SE_SHUTDOWN_PRIVILEGE && S4 !NoClose
  1078. // MENUITEM "Sh&ut Down" IDM_SHUTDOWN SE_SHUTDOWN_PRIVILEGE !NoClose
  1079. // MENUITEM "&Restart" IDM_RESTART SE_SHUTDOWN_PRIVILEGE !NoClose
  1080. // MENUITEM "&Log Off <user>" IDM_LOGOFF_CURRENTUSER <everyone> !NoClose && !NoLogoff
  1081. // MENUITEM "&Switch User" IDM_SWITCHUSER <everyone> !Remote && !NoDisconnect
  1082. // MENUITEM "&Disconnect" IDM_DISCONNECT_CURRENTUSER <everyone> Remote && !NoDisconnect
  1083. // MENUITEM "&Eject Computer" IDM_EJECT SE_UNDOCK_PRIVILEGE
  1084. // MENUITEM "Loc&k Computer" IDM_LOCKWORKSTATION <everyone> !DisableLockWorkstation
  1085. {
  1086. int i, iMenuItemCount;
  1087. BOOL fFound;
  1088. MENUITEMINFO mii;
  1089. // First find the "Shut Down" menu item in the given menu bar.
  1090. ZeroMemory(&mii, sizeof(mii));
  1091. mii.cbSize = sizeof(mii);
  1092. iMenuItemCount = GetMenuItemCount(hMenu);
  1093. for (fFound = FALSE, i = 0; !fFound && (i < iMenuItemCount); ++i)
  1094. {
  1095. mii.fMask = MIIM_ID;
  1096. if (GetMenuItemInfo(hMenu, i, TRUE, &mii) != FALSE)
  1097. {
  1098. fFound = (mii.wID == IDM_MENU_SHUTDOWN);
  1099. if (fFound)
  1100. {
  1101. // Once found get the submenu currently in place for it.
  1102. mii.fMask = MIIM_SUBMENU;
  1103. if (GetMenuItemInfo(hMenu, i, TRUE, &mii) != FALSE)
  1104. {
  1105. // If one exists then remove it.
  1106. if (mii.hSubMenu != NULL)
  1107. {
  1108. (BOOL)DestroyMenu(mii.hSubMenu);
  1109. }
  1110. // Now replace it with the freshly loaded menu.
  1111. mii.hSubMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(IDR_POPUP_SHUTDOWN));
  1112. if ( NULL != mii.hSubMenu )
  1113. {
  1114. BOOL b = (BOOL) SetMenuItemInfo(hMenu, i, TRUE, &mii);
  1115. if ( !b )
  1116. {
  1117. b = DestroyMenu( mii.hSubMenu );
  1118. // what happens if this fails?
  1119. }
  1120. }
  1121. }
  1122. }
  1123. }
  1124. }
  1125. // Now adjust the options based on privilege and availability if the
  1126. // menu was replaced with a fresh menu. Otherwise this menu has been
  1127. // removed because the machine is in classic GINA mode.
  1128. if (fFound)
  1129. {
  1130. BOOL fHasHibernate, fHasSleep, fHasShutdownPrivilege, fIsRemote, fIsDocked,
  1131. fPolicyDisableLockWorkstation, fPolicyNoLogoff, fPolicyNoClose, fPolicyNoDisconnect;
  1132. TCHAR szMenuString[256];
  1133. // Friendly UI is active - adjust shutdown menu enabled/disabled items.
  1134. // This can be more efficient but for making the logic clear and easy to
  1135. // understand it is multiple tests.
  1136. DeterminePowerCapabilities(&fHasHibernate, &fHasSleep, NULL);
  1137. LoadEjectFunction();
  1138. fHasShutdownPrivilege = (SHTestTokenPrivilege(NULL, SE_SHUTDOWN_NAME) != FALSE);
  1139. fIsRemote = GetSystemMetrics(SM_REMOTESESSION);
  1140. fIsDocked = (SHGetMachineInfo(GMI_DOCKSTATE) == GMID_DOCKED);
  1141. // System/Explorer policies to be respected.
  1142. fPolicyDisableLockWorkstation = fPolicyNoLogoff = fPolicyNoClose = fPolicyNoDisconnect = FALSE;
  1143. {
  1144. HKEY hKey;
  1145. DWORD dwValue, dwValueSize;
  1146. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1147. TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\system"),
  1148. 0,
  1149. KEY_QUERY_VALUE,
  1150. &hKey))
  1151. {
  1152. dwValueSize = sizeof(dwValue);
  1153. if (ERROR_SUCCESS == RegQueryValueEx(hKey,
  1154. TEXT("DisableLockWorkstation"),
  1155. NULL,
  1156. NULL,
  1157. reinterpret_cast<LPBYTE>(&dwValue),
  1158. &dwValueSize))
  1159. {
  1160. fPolicyDisableLockWorkstation = (dwValue != 0);
  1161. }
  1162. (LONG)RegCloseKey(hKey);
  1163. }
  1164. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER,
  1165. TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer"),
  1166. 0,
  1167. KEY_QUERY_VALUE,
  1168. &hKey))
  1169. {
  1170. dwValueSize = sizeof(dwValue);
  1171. if (ERROR_SUCCESS == RegQueryValueEx(hKey,
  1172. TEXT("DisableLockWorkstation"),
  1173. NULL,
  1174. NULL,
  1175. reinterpret_cast<LPBYTE>(&dwValue),
  1176. &dwValueSize))
  1177. {
  1178. fPolicyDisableLockWorkstation = fPolicyDisableLockWorkstation || (dwValue != 0);
  1179. }
  1180. dwValueSize = sizeof(dwValue);
  1181. if (ERROR_SUCCESS == RegQueryValueEx(hKey,
  1182. TEXT("NoLogoff"),
  1183. NULL,
  1184. NULL,
  1185. reinterpret_cast<LPBYTE>(&dwValue),
  1186. &dwValueSize))
  1187. {
  1188. fPolicyNoLogoff = (dwValue != 0);
  1189. }
  1190. dwValueSize = sizeof(dwValue);
  1191. if (ERROR_SUCCESS == RegQueryValueEx(hKey,
  1192. TEXT("NoClose"),
  1193. NULL,
  1194. NULL,
  1195. reinterpret_cast<LPBYTE>(&dwValue),
  1196. &dwValueSize))
  1197. {
  1198. fPolicyNoClose = (dwValue != 0);
  1199. }
  1200. dwValueSize = sizeof(dwValue);
  1201. if (ERROR_SUCCESS == RegQueryValueEx(hKey,
  1202. TEXT("NoDisconnect"),
  1203. NULL,
  1204. NULL,
  1205. reinterpret_cast<LPBYTE>(&dwValue),
  1206. &dwValueSize))
  1207. {
  1208. fPolicyNoDisconnect = (dwValue != 0);
  1209. }
  1210. (LONG)RegCloseKey(hKey);
  1211. }
  1212. }
  1213. // IDM_STANDBY
  1214. if (!fHasShutdownPrivilege || !fHasSleep || fIsRemote || fPolicyNoClose)
  1215. {
  1216. (BOOL)EnableMenuItem(hMenu, IDM_STANDBY, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
  1217. }
  1218. // IDM_HIBERNATE
  1219. if (!fHasShutdownPrivilege || !fHasHibernate || fIsRemote || fPolicyNoClose)
  1220. {
  1221. (BOOL)EnableMenuItem(hMenu, IDM_HIBERNATE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
  1222. }
  1223. // IDM_SHUTDOWN
  1224. if (!fHasShutdownPrivilege || fPolicyNoClose)
  1225. {
  1226. (BOOL)EnableMenuItem(hMenu, IDM_SHUTDOWN, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
  1227. }
  1228. // IDM_RESTART
  1229. if (!fHasShutdownPrivilege || fPolicyNoClose)
  1230. {
  1231. (BOOL)EnableMenuItem(hMenu, IDM_RESTART, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
  1232. }
  1233. // IDM_LOGOFF_CURRENTUSER
  1234. // This expects "Log Off %s and End Session". It will fill in the
  1235. // %s with the display name. If no display name is present then it
  1236. // will use the login name. If the string insertions fail for some
  1237. // reason then it will remove the "%s" by searching for it and
  1238. // copying the rest of the string over it.
  1239. mii.fMask = MIIM_TYPE;
  1240. mii.dwTypeData = szMenuString;
  1241. mii.cch = ARRAYSIZE(szMenuString);
  1242. if (GetMenuItemInfo(hMenu, IDM_LOGOFF_CURRENTUSER, MF_BYCOMMAND ,&mii) != FALSE)
  1243. {
  1244. TCHAR szDisplayName[UNLEN + sizeof('\0')],
  1245. szTemp[256 + UNLEN + sizeof('\0')];
  1246. *szDisplayName = TEXT('\0');
  1247. ULONG uLen = ARRAYSIZE(szDisplayName);
  1248. SHGetUserDisplayName(szDisplayName, &uLen); // Ignore errors.
  1249. if (wnsprintf(szTemp, ARRAYSIZE(szTemp), szMenuString, szDisplayName) > 0)
  1250. {
  1251. lstrcpyn(szMenuString, szTemp, ARRAYSIZE(szMenuString));
  1252. }
  1253. else
  1254. {
  1255. TCHAR *pszSubString;
  1256. pszSubString = StrStrI(szMenuString, TEXT("%s"));
  1257. if (pszSubString != NULL)
  1258. {
  1259. lstrcpy(pszSubString, pszSubString + 3);
  1260. }
  1261. }
  1262. (BOOL)SetMenuItemInfo(hMenu, IDM_LOGOFF_CURRENTUSER, MF_BYCOMMAND, &mii);
  1263. }
  1264. if ((SHRestricted(REST_STARTMENULOGOFF) == 1) || fPolicyNoClose || fPolicyNoLogoff)
  1265. {
  1266. (BOOL)EnableMenuItem(hMenu, IDM_LOGOFF_CURRENTUSER, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
  1267. }
  1268. // IDM_SWITCHUSER
  1269. if (fIsRemote || !IsOS(OS_FASTUSERSWITCHING) || fPolicyNoDisconnect)
  1270. {
  1271. (BOOL)DeleteMenu(hMenu, IDM_SWITCHUSER, MF_BYCOMMAND);
  1272. }
  1273. // IDM_DISCONNECT_CURRENTUSER
  1274. if (!fIsRemote || !IsOS(OS_FASTUSERSWITCHING) || fPolicyNoDisconnect)
  1275. {
  1276. (BOOL)DeleteMenu(hMenu, IDM_DISCONNECT_CURRENTUSER, MF_BYCOMMAND);
  1277. }
  1278. // IDM_EJECT
  1279. if (!fIsDocked || (SHTestTokenPrivilege(NULL, SE_UNDOCK_NAME) == FALSE) || (gpfnCM_Request_Eject_PC == NULL))
  1280. {
  1281. (BOOL)DeleteMenu(hMenu, IDM_EJECT, MF_BYCOMMAND);
  1282. }
  1283. // IDM_LOCKWORKSTATION
  1284. if (fIsRemote || IsOS(OS_FASTUSERSWITCHING) || fPolicyDisableLockWorkstation)
  1285. {
  1286. (BOOL)DeleteMenu(hMenu, IDM_LOCKWORKSTATION, MF_BYCOMMAND);
  1287. }
  1288. }
  1289. }
  1290. // --------------------------------------------------------------------------
  1291. // PowerActionThreadProc
  1292. //
  1293. // Arguments: pv = POWER_ACTION to invoke
  1294. //
  1295. // Returns: DWORD
  1296. //
  1297. // Purpose: Invokes NtInitiatePowerAction on a different thread so that
  1298. // the UI thread is not blocked.
  1299. //
  1300. // History: 2000-04-05 vtan created
  1301. // --------------------------------------------------------------------------
  1302. DWORD WINAPI PowerActionThreadProc (void* pv)
  1303. {
  1304. POWER_ACTION pa = (POWER_ACTION)PtrToInt(pv);
  1305. CPrivilegeEnable privilege(SE_SHUTDOWN_NAME);
  1306. NTSTATUS status = NtInitiatePowerAction(pa,
  1307. PowerSystemSleeping1,
  1308. POWER_ACTION_QUERY_ALLOWED | POWER_ACTION_UI_ALLOWED,
  1309. FALSE);
  1310. return NT_SUCCESS(status);
  1311. }
  1312. // --------------------------------------------------------------------------
  1313. // CreatePowerActionThread
  1314. //
  1315. // Arguments: paPowerAction = POWER_ACTION to invoke.
  1316. //
  1317. // Returns: <none>
  1318. //
  1319. // Purpose: Creates the thread that invokes NtInitiatePowerAction on a
  1320. // different thread. If thread creation fails then do the code
  1321. // inline. It can't be invoked because the memory allocation
  1322. // could fail so the code is copied.
  1323. //
  1324. // History: 2000-04-05 vtan created
  1325. // --------------------------------------------------------------------------
  1326. void CreatePowerActionThread (POWER_ACTION paPowerAction)
  1327. {
  1328. DWORD dwThreadID = 0;
  1329. HANDLE hThread = CreateThread(NULL,
  1330. 0,
  1331. PowerActionThreadProc,
  1332. (void*)paPowerAction,
  1333. 0,
  1334. &dwThreadID);
  1335. if (hThread != NULL)
  1336. {
  1337. (BOOL)CloseHandle(hThread);
  1338. }
  1339. else
  1340. {
  1341. CPrivilegeEnable privilege(SE_SHUTDOWN_NAME);
  1342. (NTSTATUS)NtInitiatePowerAction(paPowerAction,
  1343. PowerSystemSleeping1,
  1344. POWER_ACTION_QUERY_ALLOWED | POWER_ACTION_UI_ALLOWED,
  1345. FALSE);
  1346. }
  1347. }
  1348. // --------------------------------------------------------------------------
  1349. // ExitWindowsThreadProc
  1350. //
  1351. // Arguments: pv = uiFlags
  1352. //
  1353. // Returns: DWORD
  1354. //
  1355. // Purpose: Invokes ExitWindowsEx on a different thread so that
  1356. // the UI thread is not blocked.
  1357. //
  1358. // History: 2000-04-05 vtan created
  1359. // --------------------------------------------------------------------------
  1360. DWORD WINAPI ExitWindowsThreadProc (void *pv)
  1361. {
  1362. UINT uiFlags = PtrToUint(pv);
  1363. CPrivilegeEnable privilege(SE_SHUTDOWN_NAME);
  1364. BOOL bRet = ExitWindowsEx(uiFlags, 0);
  1365. return (DWORD)bRet;
  1366. }
  1367. // --------------------------------------------------------------------------
  1368. // CreateExitWindowsThread
  1369. //
  1370. // Arguments: uiFlags = EWX_ flag to pass to ExitWindowsEx.
  1371. //
  1372. // Returns: <none>
  1373. //
  1374. // Purpose: Creates the thread that invokes ExitWindowsEx on a
  1375. // different thread. If thread creation fails then do the code
  1376. // inline. It can't be invoked because the memory allocation
  1377. // could fail so the code is copied.
  1378. //
  1379. // History: 2000-04-05 vtan created
  1380. // --------------------------------------------------------------------------
  1381. void CreateExitWindowsThread (UINT uiFlags)
  1382. {
  1383. DWORD dwThreadID;
  1384. HANDLE hThread;
  1385. dwThreadID = 0;
  1386. hThread = NULL;
  1387. hThread = CreateThread(NULL,
  1388. 0,
  1389. ExitWindowsThreadProc,
  1390. UintToPtr(uiFlags),
  1391. 0,
  1392. &dwThreadID);
  1393. if (hThread != NULL)
  1394. {
  1395. (BOOL)CloseHandle(hThread);
  1396. }
  1397. else
  1398. {
  1399. CPrivilegeEnable privilege(SE_SHUTDOWN_NAME);
  1400. (BOOL)ExitWindowsEx(uiFlags, 0);
  1401. }
  1402. }
  1403. // --------------------------------------------------------------------------
  1404. // ExecuteShutdownMenuOption
  1405. //
  1406. // Arguments: hwnd = Parent HWND if a dialog is required.
  1407. // iID = ID of menu item to execute.
  1408. //
  1409. // Returns: <none>
  1410. //
  1411. // Purpose: Executes the given shut down menu option doing the right
  1412. // thing if prompting is required.
  1413. //
  1414. // History: 2000-03-29 vtan created
  1415. // --------------------------------------------------------------------------
  1416. void ExecuteShutdownMenuOption (HWND hwnd, int iID)
  1417. {
  1418. BOOL fIsRemote;
  1419. fIsRemote = GetSystemMetrics(SM_REMOTESESSION);
  1420. switch (iID)
  1421. {
  1422. BOOL fControlKey;
  1423. case IDM_STANDBY:
  1424. {
  1425. CreatePowerActionThread(PowerActionSleep);
  1426. break;
  1427. }
  1428. case IDM_HIBERNATE:
  1429. {
  1430. CreatePowerActionThread(PowerActionHibernate);
  1431. break;
  1432. }
  1433. case IDM_SHUTDOWN:
  1434. {
  1435. BOOL fHasPowerOff;
  1436. UINT uiFlags;
  1437. fControlKey = (GetAsyncKeyState(VK_CONTROL) < 0);
  1438. if (fControlKey)
  1439. {
  1440. CPrivilegeEnable privilege(SE_SHUTDOWN_NAME);
  1441. (NTSTATUS)NtShutdownSystem(ShutdownPowerOff);
  1442. }
  1443. else
  1444. {
  1445. DeterminePowerCapabilities(NULL, NULL, &fHasPowerOff);
  1446. if (fHasPowerOff != FALSE)
  1447. {
  1448. uiFlags = EWX_POWEROFF;
  1449. }
  1450. else
  1451. {
  1452. uiFlags = EWX_SHUTDOWN;
  1453. }
  1454. CreateExitWindowsThread(uiFlags);
  1455. }
  1456. break;
  1457. }
  1458. case IDM_RESTART:
  1459. {
  1460. fControlKey = (GetAsyncKeyState(VK_CONTROL) < 0);
  1461. if (fControlKey)
  1462. {
  1463. CPrivilegeEnable privilege(SE_SHUTDOWN_NAME);
  1464. (NTSTATUS)NtShutdownSystem(ShutdownReboot);
  1465. }
  1466. else
  1467. {
  1468. CreateExitWindowsThread(EWX_REBOOT);
  1469. }
  1470. break;
  1471. }
  1472. case IDM_LOGOFF_CURRENTUSER:
  1473. {
  1474. (BOOL)ExitWindowsEx(EWX_LOGOFF, 0);
  1475. break;
  1476. }
  1477. case IDM_SWITCHUSER:
  1478. case IDM_DISCONNECT_CURRENTUSER:
  1479. {
  1480. (DWORD)ShellSwitchUser(FALSE);
  1481. break;
  1482. }
  1483. case IDM_EJECT:
  1484. {
  1485. gpfnCM_Request_Eject_PC();
  1486. break;
  1487. }
  1488. case IDM_LOCKWORKSTATION:
  1489. {
  1490. (BOOL)LockWorkStation();
  1491. break;
  1492. }
  1493. }
  1494. }
  1495. /*++ MainWnd_OnCommand
  1496. Routine Description:
  1497. Processes WM_COMMAND messages received at the main window
  1498. Revision History:
  1499. Nov-30-95 Davepl Created
  1500. --*/
  1501. void MainWnd_OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
  1502. {
  1503. switch (id)
  1504. {
  1505. case IDM_HIDE:
  1506. {
  1507. ShowWindow(hwnd, SW_MINIMIZE);
  1508. break;
  1509. }
  1510. case IDM_HELP:
  1511. {
  1512. HtmlHelpA(GetDesktopWindow(), "taskmgr.chm", HH_DISPLAY_TOPIC, 0);
  1513. break;
  1514. }
  1515. case IDCANCEL:
  1516. case IDM_EXIT:
  1517. {
  1518. DestroyWindow(hwnd);
  1519. break;
  1520. }
  1521. case IDM_RESTORETASKMAN:
  1522. {
  1523. ShowRunningInstance();
  1524. break;
  1525. }
  1526. // these guys need to get forwarded to the page for handling
  1527. case IDC_SWITCHTO:
  1528. case IDC_BRINGTOFRONT:
  1529. case IDC_ENDTASK:
  1530. {
  1531. switch (g_Options.m_iCurrentPage)
  1532. {
  1533. case PROC_PAGE:
  1534. {
  1535. // procpage only deals with ENDTASK, but will ignore the others
  1536. CProcPage * pPage = ((CProcPage *) (g_pPages[PROC_PAGE]));
  1537. pPage->HandleWMCOMMAND(LOWORD(id), NULL);
  1538. break;
  1539. }
  1540. case TASK_PAGE:
  1541. {
  1542. CTaskPage * pPage = ((CTaskPage *) (g_pPages[TASK_PAGE]));
  1543. pPage->HandleWMCOMMAND(id);
  1544. break;
  1545. }
  1546. }
  1547. break;
  1548. }
  1549. case IDC_NEXTTAB:
  1550. case IDC_PREVTAB:
  1551. {
  1552. INT iPage = g_Options.m_iCurrentPage;
  1553. iPage += (id == IDC_NEXTTAB) ? 1 : -1;
  1554. iPage = iPage < 0 ? g_nPageCount - 1 : iPage;
  1555. iPage = iPage >= g_nPageCount ? 0 : iPage;
  1556. // Activate the new page. If it fails, revert to the current
  1557. TabCtrl_SetCurSel(GetDlgItem(g_hMainWnd, IDC_TABS), iPage);
  1558. // SetCurSel doesn't do the page change (that would make too much
  1559. // sense), so we have to fake up a TCN_SELCHANGE notification
  1560. NMHDR nmhdr;
  1561. nmhdr.hwndFrom = GetDlgItem(g_hMainWnd, IDC_TABS);
  1562. nmhdr.idFrom = IDC_TABS;
  1563. nmhdr.code = TCN_SELCHANGE;
  1564. if (MainWnd_OnTabCtrlNotify(&nmhdr))
  1565. {
  1566. g_Options.m_iCurrentPage = iPage;
  1567. }
  1568. break;
  1569. }
  1570. case IDM_ALWAYSONTOP:
  1571. {
  1572. g_Options.m_fAlwaysOnTop = !g_Options.m_fAlwaysOnTop;
  1573. SetWindowPos(hwnd, g_Options.m_fAlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
  1574. 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE);
  1575. UpdateMenuStates();
  1576. break;
  1577. }
  1578. case IDM_HIDEWHENMIN:
  1579. {
  1580. g_Options.m_fHideWhenMin = !g_Options.m_fHideWhenMin;
  1581. UpdateMenuStates();
  1582. break;
  1583. }
  1584. case IDM_MINIMIZEONUSE:
  1585. {
  1586. g_Options.m_fMinimizeOnUse = !g_Options.m_fMinimizeOnUse;
  1587. UpdateMenuStates();
  1588. break;
  1589. }
  1590. case IDM_NOTITLE:
  1591. {
  1592. g_Options.m_fNoTitle = !g_Options.m_fNoTitle;
  1593. UpdateMenuStates();
  1594. SizeChildPage(hwnd);
  1595. break;
  1596. }
  1597. case IDM_SHOW16BIT:
  1598. {
  1599. g_Options.m_fShow16Bit = !g_Options.m_fShow16Bit;
  1600. UpdateMenuStates();
  1601. if (g_pPages[PROC_PAGE])
  1602. {
  1603. g_pPages[PROC_PAGE]->TimerEvent();
  1604. }
  1605. break;
  1606. }
  1607. case IDM_SHOWDOMAINNAMES:
  1608. {
  1609. g_Options.m_fShowDomainNames = !g_Options.m_fShowDomainNames;
  1610. UpdateMenuStates();
  1611. if (g_pPages[USER_PAGE])
  1612. {
  1613. g_pPages[USER_PAGE]->TimerEvent();
  1614. }
  1615. break;
  1616. }
  1617. case IDM_HIBERNATE:
  1618. case IDM_SHUTDOWN:
  1619. case IDM_STANDBY:
  1620. case IDM_RESTART:
  1621. case IDM_LOGOFF_CURRENTUSER:
  1622. case IDM_SWITCHUSER:
  1623. case IDM_DISCONNECT_CURRENTUSER:
  1624. case IDM_EJECT:
  1625. case IDM_LOCKWORKSTATION:
  1626. {
  1627. ExecuteShutdownMenuOption(hwnd, id);
  1628. break;
  1629. }
  1630. case IDM_KERNELTIMES:
  1631. {
  1632. g_Options.m_fKernelTimes = !g_Options.m_fKernelTimes;
  1633. UpdateMenuStates();
  1634. if (g_pPages[PERF_PAGE])
  1635. {
  1636. g_pPages[PERF_PAGE]->TimerEvent();
  1637. }
  1638. break;
  1639. }
  1640. case IDM_RUN:
  1641. {
  1642. if (GetKeyState(VK_CONTROL) >= 0)
  1643. {
  1644. RunDlg();
  1645. }
  1646. else
  1647. {
  1648. // 2000-06-21 vtan
  1649. // What an ugly hack! Hold down the CONTROL key and choose
  1650. // File -> Run. You get a command prompt not the shell
  1651. // "Run" dialog which if shell32.dll is busted will not work.
  1652. STARTUPINFO startupInfo = { 0 };
  1653. PROCESS_INFORMATION processInformation = { 0 };
  1654. TCHAR szCommandLine[MAX_PATH];
  1655. startupInfo.cb = sizeof(startupInfo);
  1656. startupInfo.dwFlags = STARTF_USESHOWWINDOW;
  1657. startupInfo.wShowWindow = SW_SHOWNORMAL;
  1658. if (ExpandEnvironmentStrings(TEXT("%ComSpec%"), szCommandLine, ARRAYSIZE(szCommandLine)) == 0)
  1659. {
  1660. (TCHAR*)lstrcpy(szCommandLine, TEXT("cmd.exe"));
  1661. }
  1662. if (CreateProcess(NULL,
  1663. szCommandLine,
  1664. NULL,
  1665. NULL,
  1666. FALSE,
  1667. CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_PROCESS_GROUP,
  1668. NULL,
  1669. NULL,
  1670. &startupInfo,
  1671. &processInformation) != FALSE)
  1672. {
  1673. (BOOL)CloseHandle(processInformation.hThread);
  1674. (BOOL)CloseHandle(processInformation.hProcess);
  1675. }
  1676. }
  1677. break;
  1678. }
  1679. case IDM_SMALLICONS:
  1680. case IDM_DETAILS:
  1681. case IDM_LARGEICONS:
  1682. {
  1683. g_Options.m_vmViewMode = (VIEWMODE) (id - VM_FIRST);
  1684. UpdateMenuStates();
  1685. if (g_pPages[TASK_PAGE])
  1686. {
  1687. g_pPages[TASK_PAGE]->TimerEvent();
  1688. }
  1689. break;
  1690. }
  1691. // The following few messages get deferred off to the task page
  1692. case IDM_TASK_CASCADE:
  1693. case IDM_TASK_MINIMIZE:
  1694. case IDM_TASK_MAXIMIZE:
  1695. case IDM_TASK_TILEHORZ:
  1696. case IDM_TASK_TILEVERT:
  1697. case IDM_TASK_BRINGTOFRONT:
  1698. {
  1699. SendMessage(g_pPages[TASK_PAGE]->GetPageWindow(), WM_COMMAND, id, NULL);
  1700. break;
  1701. }
  1702. case IDM_PROCCOLS:
  1703. {
  1704. if (g_pPages[PROC_PAGE])
  1705. {
  1706. ((CProcPage *) (g_pPages[PROC_PAGE]))->PickColumns();
  1707. }
  1708. break;
  1709. }
  1710. case IDM_NETCOL:
  1711. {
  1712. if (g_pPages[NET_PAGE])
  1713. {
  1714. ((CNetPage *) (g_pPages[NET_PAGE]))->PickColumns();
  1715. }
  1716. break;
  1717. }
  1718. case IDM_USERCOLS:
  1719. {
  1720. if (g_pPages[USER_PAGE])
  1721. {
  1722. SendMessage(g_pPages[USER_PAGE]->GetPageWindow(), WM_COMMAND, id, NULL);
  1723. }
  1724. break;
  1725. }
  1726. case IDM_ALLCPUS:
  1727. case IDM_MULTIGRAPH:
  1728. {
  1729. g_Options.m_cmHistMode = (CPUHISTMODE) (id - CM_FIRST);
  1730. UpdateMenuStates();
  1731. if (g_pPages[PERF_PAGE])
  1732. {
  1733. ((CPerfPage *)(g_pPages[PERF_PAGE]))->UpdateGraphs();
  1734. g_pPages[PERF_PAGE]->TimerEvent();
  1735. }
  1736. break;
  1737. }
  1738. case IDM_REFRESH:
  1739. {
  1740. if (g_pPages[NET_PAGE] && g_Options.m_iCurrentPage == NET_PAGE)
  1741. {
  1742. ((CNetPage *)(g_pPages[NET_PAGE]))->Refresh();
  1743. }
  1744. MainWnd_OnTimer(hwnd, 0);
  1745. break;
  1746. }
  1747. case IDM_SHOWALLDATA:
  1748. {
  1749. g_Options.m_bNetShowAll = !g_Options.m_bNetShowAll;
  1750. UpdateMenuStates();
  1751. break;
  1752. }
  1753. case IDM_TABALWAYSACTIVE:
  1754. {
  1755. g_Options.m_bTabAlwaysActive = !g_Options.m_bTabAlwaysActive;
  1756. UpdateMenuStates();
  1757. break;
  1758. }
  1759. case IDM_BYTESSENT:
  1760. {
  1761. g_Options.m_bGraphBytesSent = !g_Options.m_bGraphBytesSent;
  1762. UpdateMenuStates();
  1763. MainWnd_OnTimer(hwnd, 0);
  1764. break;
  1765. }
  1766. case IDM_NETRESET:
  1767. {
  1768. if (g_pPages[NET_PAGE])
  1769. {
  1770. ((CNetPage *)(g_pPages[NET_PAGE]))->Reset();
  1771. MainWnd_OnTimer(hwnd, 0);
  1772. }
  1773. break;
  1774. }
  1775. case IDM_SHOWSCALE:
  1776. {
  1777. g_Options.m_bShowScale = !g_Options.m_bShowScale;
  1778. UpdateMenuStates();
  1779. if (g_pPages[NET_PAGE])
  1780. {
  1781. ((CNetPage *)(g_pPages[NET_PAGE]))->SizeNetPage();
  1782. }
  1783. break;
  1784. }
  1785. case IDM_AUTOSIZE:
  1786. {
  1787. g_Options.m_bAutoSize = !g_Options.m_bAutoSize;
  1788. UpdateMenuStates();
  1789. break;
  1790. }
  1791. case IDM_BYTESRECEIVED:
  1792. {
  1793. g_Options.m_bGraphBytesReceived = !g_Options.m_bGraphBytesReceived;
  1794. UpdateMenuStates();
  1795. break;
  1796. }
  1797. case IDM_BYTESTOTAL:
  1798. {
  1799. g_Options.m_bGraphBytesTotal = !g_Options.m_bGraphBytesTotal;
  1800. UpdateMenuStates();
  1801. break;
  1802. }
  1803. case IDM_HIGH:
  1804. case IDM_NORMAL:
  1805. case IDM_LOW:
  1806. case IDM_PAUSED:
  1807. {
  1808. static const int TimerDelays[] = { 500, 2000, 4000, 0, 0xFFFFFFFF };
  1809. g_Options.m_usUpdateSpeed = (UPDATESPEED) (id - US_FIRST);
  1810. ASSERT(g_Options.m_usUpdateSpeed <= ARRAYSIZE(TimerDelays));
  1811. int cTicks = TimerDelays[ (INT) g_Options.m_usUpdateSpeed ];
  1812. g_Options.m_dwTimerInterval = cTicks;
  1813. KillTimer(g_hMainWnd, 0);
  1814. if (cTicks)
  1815. {
  1816. SetTimer(g_hMainWnd, 0, g_Options.m_dwTimerInterval, NULL);
  1817. }
  1818. UpdateMenuStates();
  1819. break;
  1820. }
  1821. case IDM_ABOUT:
  1822. {
  1823. //
  1824. // Display the "About Task Manager" dialog
  1825. //
  1826. HICON hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_MAIN));
  1827. if (hIcon)
  1828. {
  1829. TCHAR szTitle[MAX_PATH];
  1830. LoadString(g_hInstance, IDS_APPTITLE, szTitle, MAX_PATH);
  1831. ShellAbout(hwnd, szTitle, NULL, hIcon);
  1832. DestroyIcon(hIcon);
  1833. }
  1834. }
  1835. }
  1836. }
  1837. /*++ CheckParentDeferrals
  1838. Routine Description:
  1839. Called by the child pages, each child gives the main parent the
  1840. opportunity to handle certain messages on its behalf
  1841. Arguments:
  1842. MSG, WPARAM, LPARAM
  1843. Return Value:
  1844. TRUE if parent handle the message on the childs behalf
  1845. Revision History:
  1846. Jan-24-95 Davepl Created
  1847. --*/
  1848. BOOL CheckParentDeferrals(UINT uMsg, WPARAM wParam, LPARAM lParam)
  1849. {
  1850. switch(uMsg)
  1851. {
  1852. case WM_RBUTTONDOWN:
  1853. case WM_NCRBUTTONDOWN:
  1854. case WM_RBUTTONUP:
  1855. case WM_NCRBUTTONUP:
  1856. case WM_NCLBUTTONDBLCLK:
  1857. case WM_LBUTTONDBLCLK:
  1858. {
  1859. SendMessage(g_hMainWnd, uMsg, wParam, lParam);
  1860. return TRUE;
  1861. }
  1862. default:
  1863. return FALSE;
  1864. }
  1865. }
  1866. /*++ ShowRunningInstance
  1867. Routine Description:
  1868. Brings this running instance to the top, and out of icon state
  1869. Revision History:
  1870. Jan-27-95 Davepl Created
  1871. --*/
  1872. void ShowRunningInstance()
  1873. {
  1874. OpenIcon(g_hMainWnd);
  1875. SetForegroundWindow(g_hMainWnd);
  1876. SetWindowPos(g_hMainWnd, g_Options.m_fAlwaysOnTop ? HWND_TOPMOST : HWND_TOP,
  1877. 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE);
  1878. }
  1879. /*++ MainWindowProc
  1880. Routine Description:
  1881. Initializes the gloab setting variables. Everytime the settings change this function is called.
  1882. Arguments:
  1883. void
  1884. Return Value:
  1885. Revision History:
  1886. created April 23, 2001 omiller
  1887. --*/
  1888. void OnSettingsChange()
  1889. {
  1890. WCHAR wszGroupSep[8];
  1891. GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIME, g_szTimeSep, ARRAYSIZE(g_szTimeSep));
  1892. GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, g_szGroupThousSep, ARRAYSIZE(g_szGroupThousSep));
  1893. GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL , g_szDecimal, ARRAYSIZE(g_szDecimal));
  1894. GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, wszGroupSep, ARRAYSIZE(wszGroupSep));
  1895. g_ulGroupSep = wcstol(wszGroupSep,NULL,10);
  1896. }
  1897. /*++ MainWindowProc
  1898. Routine Description:
  1899. WNDPROC for the main window
  1900. Arguments:
  1901. Standard wndproc fare
  1902. Return Value:
  1903. Revision History:
  1904. Nov-30-95 Davepl Created
  1905. --*/
  1906. INT_PTR CALLBACK MainWindowProc(
  1907. HWND hwnd, // handle to dialog box
  1908. UINT uMsg, // message
  1909. WPARAM wParam, // first message parameter
  1910. LPARAM lParam // second message parameter
  1911. )
  1912. {
  1913. static BOOL fIsHidden = FALSE;
  1914. // If this is a size or a move, update the position in the user's options
  1915. if (uMsg == WM_SIZE || uMsg == WM_MOVE)
  1916. {
  1917. // We don't want to start recording the window pos until we've had
  1918. // a chance to set it to the intialial position, or we'll lose the
  1919. // user's preferences
  1920. if (fAlreadySetPos)
  1921. if (!IsIconic(hwnd) && !IsZoomed(hwnd))
  1922. GetWindowRect(hwnd, &g_Options.m_rcWindow);
  1923. }
  1924. if (uMsg == g_msgTaskbarCreated)
  1925. {
  1926. // This is done async do taskmgr doesn't hand when the shell
  1927. // is hung
  1928. PostThreadMessage( g_idTrayThread, PM_NOTIFYWAITING, 0, 0 );
  1929. }
  1930. switch(uMsg)
  1931. {
  1932. case WM_PAINT:
  1933. MainWnd_OnPaint(hwnd);
  1934. return TRUE;
  1935. HANDLE_MSG(hwnd, WM_INITDIALOG, MainWnd_OnInitDialog);
  1936. HANDLE_MSG(hwnd, WM_MENUSELECT, MainWnd_OnMenuSelect);
  1937. HANDLE_MSG(hwnd, WM_SIZE, MainWnd_OnSize);
  1938. HANDLE_MSG(hwnd, WM_COMMAND, MainWnd_OnCommand);
  1939. HANDLE_MSG(hwnd, WM_TIMER, MainWnd_OnTimer);
  1940. case WM_PRINTCLIENT:
  1941. MainWnd_OnPrintClient(hwnd, (HDC)wParam);
  1942. break;
  1943. // Don't let the window get too small when the title and
  1944. // menu bars are ON
  1945. case WM_GETMINMAXINFO:
  1946. {
  1947. if (FALSE == g_Options.m_fNoTitle)
  1948. {
  1949. LPMINMAXINFO lpmmi = (LPMINMAXINFO) lParam;
  1950. lpmmi->ptMinTrackSize.x = g_minWidth;
  1951. lpmmi->ptMinTrackSize.y = g_minHeight;
  1952. return FALSE;
  1953. }
  1954. break;
  1955. }
  1956. // Handle notifications from out tray icon
  1957. case PWM_TRAYICON:
  1958. {
  1959. Tray_Notify(hwnd, wParam, lParam);
  1960. break;
  1961. }
  1962. // Someone externally is asking us to wake up and be shown
  1963. case PWM_ACTIVATE:
  1964. {
  1965. ShowRunningInstance();
  1966. // Return PWM_ACTIVATE to the caller as just a little
  1967. // more assurance that we really did handle this
  1968. // message correctly.
  1969. SetWindowLongPtr(hwnd, DWLP_MSGRESULT, PWM_ACTIVATE);
  1970. return TRUE;
  1971. }
  1972. case WM_INITMENU:
  1973. {
  1974. AdjustShutdownMenu(reinterpret_cast<HMENU>(wParam));
  1975. // Don't let the right button hide the window during
  1976. // menu operations
  1977. g_fCantHide = TRUE;
  1978. break;
  1979. }
  1980. // If we're in always-on-top mode, the right mouse button will
  1981. // temporarily hide us so that the user can see whats under us
  1982. case WM_RBUTTONDOWN:
  1983. case WM_NCRBUTTONDOWN:
  1984. {
  1985. #ifdef ENABLE_HIDING
  1986. if (!g_fInPopup && !fIsHidden && !g_fCantHide && g_Options.m_fAlwaysOnTop)
  1987. {
  1988. ShowWindow (hwnd, SW_HIDE);
  1989. // We take the capture so that we're guaranteed to get
  1990. // the right button up even if its off our window
  1991. SetCapture (hwnd);
  1992. fIsHidden = TRUE;
  1993. }
  1994. #endif
  1995. break;
  1996. }
  1997. // On right button up, if we were hidden, unhide us. We have
  1998. // to use the correct state (min/max/restore)
  1999. case WM_RBUTTONUP:
  2000. case WM_NCRBUTTONUP:
  2001. {
  2002. #ifdef ENABLE_HIDING
  2003. if (fIsHidden)
  2004. {
  2005. ReleaseCapture();
  2006. if (IsIconic(hwnd))
  2007. ShowWindow (hwnd, SW_SHOWMINNOACTIVE);
  2008. else if (IsZoomed (hwnd))
  2009. {
  2010. ShowWindow (hwnd, SW_SHOWMAXIMIZED);
  2011. SetForegroundWindow (hwnd);
  2012. }
  2013. else
  2014. {
  2015. ShowWindow (hwnd, SW_SHOWNOACTIVATE);
  2016. SetForegroundWindow (hwnd);
  2017. }
  2018. fIsHidden = FALSE;
  2019. }
  2020. #endif
  2021. break;
  2022. }
  2023. case WM_NCHITTEST:
  2024. {
  2025. // If we have no title/menu bar, clicking and dragging the client
  2026. // area moves the window. To do this, return HTCAPTION.
  2027. // Note dragging not allowed if window maximized, or if caption
  2028. // bar is present.
  2029. //
  2030. wParam = DefWindowProc(hwnd, uMsg, wParam, lParam);
  2031. if (g_Options.m_fNoTitle && (wParam == HTCLIENT) && !IsZoomed(g_hMainWnd))
  2032. {
  2033. SetWindowLongPtr(hwnd, DWLP_MSGRESULT, HTCAPTION);
  2034. return TRUE;
  2035. }
  2036. else
  2037. {
  2038. return FALSE; // Not handled
  2039. }
  2040. }
  2041. case WM_NCLBUTTONDBLCLK:
  2042. {
  2043. // If we have no title, an NC dbl click means we should turn
  2044. // them back on
  2045. if (FALSE == g_Options.m_fNoTitle)
  2046. {
  2047. break;
  2048. }
  2049. // Else, fall though
  2050. }
  2051. case WM_LBUTTONDBLCLK:
  2052. {
  2053. g_Options.m_fNoTitle = ~g_Options.m_fNoTitle;
  2054. RECT rcMainWnd;
  2055. GetWindowRect(g_hMainWnd, &rcMainWnd);
  2056. if (g_pPages[PERF_PAGE])
  2057. {
  2058. ((CPerfPage *)(g_pPages[PERF_PAGE]))->UpdateGraphs();
  2059. g_pPages[PERF_PAGE]->TimerEvent();
  2060. }
  2061. if (g_pPages[NET_PAGE])
  2062. {
  2063. ((CNetPage *)(g_pPages[NET_PAGE]))->UpdateGraphs();
  2064. g_pPages[NET_PAGE]->TimerEvent();
  2065. }
  2066. // Force a WM_SIZE event so that the window checks the min size
  2067. // when coming out of notitle mode
  2068. MoveWindow(g_hMainWnd,
  2069. rcMainWnd.left,
  2070. rcMainWnd.top,
  2071. rcMainWnd.right - rcMainWnd.left,
  2072. rcMainWnd.bottom - rcMainWnd.top,
  2073. TRUE);
  2074. SizeChildPage(hwnd);
  2075. break;
  2076. }
  2077. // Someone (the task page) wants us to look up a process in the
  2078. // process view. Switch to that page and send it the FINDPROC
  2079. // message
  2080. case WM_FINDPROC:
  2081. {
  2082. if (-1 != TabCtrl_SetCurSel(GetDlgItem(hwnd, IDC_TABS), PROC_PAGE))
  2083. {
  2084. // SetCurSel doesn't do the page change (that would make too much
  2085. // sense), so we have to fake up a TCN_SELCHANGE notification
  2086. NMHDR nmhdr;
  2087. nmhdr.hwndFrom = GetDlgItem(hwnd, IDC_TABS);
  2088. nmhdr.idFrom = IDC_TABS;
  2089. nmhdr.code = TCN_SELCHANGE;
  2090. if (MainWnd_OnTabCtrlNotify(&nmhdr))
  2091. {
  2092. if ( g_Options.m_iCurrentPage != -1 )
  2093. {
  2094. SendMessage( g_pPages[g_Options.m_iCurrentPage]->GetPageWindow(), WM_FINDPROC, wParam, lParam );
  2095. }
  2096. }
  2097. }
  2098. else
  2099. {
  2100. MessageBeep(0);
  2101. }
  2102. break;
  2103. }
  2104. case WM_NOTIFY:
  2105. {
  2106. switch(wParam)
  2107. {
  2108. case IDC_TABS:
  2109. return MainWnd_OnTabCtrlNotify((LPNMHDR) lParam);
  2110. default:
  2111. break;
  2112. }
  2113. break;
  2114. }
  2115. case WM_ENDSESSION:
  2116. {
  2117. if (wParam)
  2118. {
  2119. DestroyWindow(g_hMainWnd);
  2120. }
  2121. break;
  2122. }
  2123. case WM_CLOSE:
  2124. {
  2125. DestroyWindow(g_hMainWnd);
  2126. break;
  2127. }
  2128. case WM_NCDESTROY:
  2129. // If there's a tray thread, tell is to exit
  2130. if (g_idTrayThread)
  2131. {
  2132. PostThreadMessage(g_idTrayThread, PM_QUITTRAYTHREAD, 0, 0);
  2133. }
  2134. // Wait around for some period of time for the tray thread to
  2135. // do its cleanup work. If the wait times out, worst case we
  2136. // orphan the tray icon.
  2137. if (g_hTrayThread)
  2138. {
  2139. #define TRAY_THREAD_WAIT 3000
  2140. WaitForSingleObject(g_hTrayThread, TRAY_THREAD_WAIT);
  2141. CloseHandle(g_hTrayThread);
  2142. }
  2143. break;
  2144. case WM_SYSCOLORCHANGE:
  2145. case WM_SETTINGCHANGE:
  2146. {
  2147. // Initialzie the global variables, i.e. comma, decimal time etc
  2148. //
  2149. OnSettingsChange();
  2150. // pass these to the status bar
  2151. SendMessage(g_hStatusWnd, uMsg, wParam, lParam);
  2152. // also pass along to the pages
  2153. for (int i = 0; i < g_nPageCount; i++)
  2154. {
  2155. if (g_pPages[i])
  2156. {
  2157. SendMessage(g_pPages[i]->GetPageWindow(), uMsg, wParam, lParam);
  2158. }
  2159. }
  2160. if (uMsg == WM_SETTINGCHANGE)
  2161. {
  2162. // force a resizing of the main dialog
  2163. RECT rcMainClient;
  2164. GetClientRect(g_hMainWnd, &rcMainClient);
  2165. MainWnd_OnSize(g_hMainWnd, 0, rcMainClient.right - rcMainClient.left, rcMainClient.bottom - rcMainClient.top);
  2166. }
  2167. break;
  2168. }
  2169. case WM_DESTROY:
  2170. {
  2171. // Before shutting down, deactivate the current page, then
  2172. // destroy all pages
  2173. if (g_Options.m_iCurrentPage && g_Options.m_iCurrentPage != -1 && g_pPages[g_Options.m_iCurrentPage])
  2174. {
  2175. g_pPages[g_Options.m_iCurrentPage]->Deactivate();
  2176. }
  2177. for (int i = 0; i < g_nPageCount; i++)
  2178. {
  2179. if (g_pPages[i])
  2180. {
  2181. g_pPages[i]->Destroy();
  2182. }
  2183. }
  2184. // Save the current options
  2185. g_Options.Save();
  2186. PostQuitMessage(0);
  2187. }
  2188. default:
  2189. return FALSE; // Not handled here
  2190. }
  2191. return FALSE;
  2192. }
  2193. /*++ LoadGlobalResources
  2194. Routine Description:
  2195. Loads those resources that are used frequently or that are expensive to
  2196. load a single time at program startup
  2197. Return Value:
  2198. BOOLEAN success value
  2199. Revision History:
  2200. Nov-30-95 Davepl Created
  2201. --*/
  2202. static const struct
  2203. {
  2204. LPTSTR psz;
  2205. size_t len;
  2206. UINT id;
  2207. }
  2208. g_aStrings[] =
  2209. {
  2210. { g_szG, ARRAYSIZE(g_szG), IDS_G },
  2211. { g_szM, ARRAYSIZE(g_szM), IDS_M },
  2212. { g_szK, ARRAYSIZE(g_szK), IDS_K },
  2213. { g_szBitsPerSec, ARRAYSIZE(g_szBitsPerSec), IDS_BITSPERSEC },
  2214. { g_szPercent, ARRAYSIZE(g_szScaleFont), IDS_PERCENT },
  2215. { g_szRealtime, ARRAYSIZE(g_szRealtime), IDS_REALTIME },
  2216. { g_szNormal, ARRAYSIZE(g_szNormal), IDS_NORMAL },
  2217. { g_szLow, ARRAYSIZE(g_szLow), IDS_LOW },
  2218. { g_szHigh, ARRAYSIZE(g_szHigh), IDS_HIGH },
  2219. { g_szUnknown, ARRAYSIZE(g_szUnknown), IDS_UNKNOWN },
  2220. { g_szAboveNormal,ARRAYSIZE(g_szAboveNormal),IDS_ABOVENORMAL},
  2221. { g_szBelowNormal,ARRAYSIZE(g_szBelowNormal),IDS_BELOWNORMAL},
  2222. { g_szRunning, ARRAYSIZE(g_szRunning), IDS_RUNNING },
  2223. { g_szHung, ARRAYSIZE(g_szHung), IDS_HUNG },
  2224. { g_szfmtTasks, ARRAYSIZE(g_szfmtTasks), IDS_FMTTASKS },
  2225. { g_szfmtProcs, ARRAYSIZE(g_szfmtProcs), IDS_FMTPROCS },
  2226. { g_szfmtCPU, ARRAYSIZE(g_szfmtCPU), IDS_FMTCPU },
  2227. { g_szfmtMEMK, ARRAYSIZE(g_szfmtMEMK), IDS_FMTMEMK },
  2228. { g_szfmtMEMM, ARRAYSIZE(g_szfmtMEMM), IDS_FMTMEMM },
  2229. { g_szfmtCPUNum, ARRAYSIZE(g_szfmtCPUNum), IDS_FMTCPUNUM },
  2230. { g_szTotalCPU, ARRAYSIZE(g_szTotalCPU), IDS_TOTALTIME },
  2231. { g_szKernelCPU, ARRAYSIZE(g_szKernelCPU), IDS_KERNELTIME },
  2232. { g_szMemUsage, ARRAYSIZE(g_szMemUsage), IDS_MEMUSAGE },
  2233. { g_szZero, ARRAYSIZE(g_szG), IDS_ZERO },
  2234. { g_szScaleFont, ARRAYSIZE(g_szScaleFont), IDS_SCALEFONT },
  2235. { g_szNonOperational, ARRAYSIZE(g_szNonOperational), IDS_NONOPERATIONAL },
  2236. { g_szUnreachable, ARRAYSIZE(g_szUnreachable), IDS_UNREACHABLE },
  2237. { g_szDisconnected, ARRAYSIZE(g_szDisconnected), IDS_DISCONNECTED },
  2238. { g_szConnecting, ARRAYSIZE(g_szConnecting), IDS_CONNECTING },
  2239. { g_szConnected, ARRAYSIZE(g_szConnected), IDS_CONNECTED },
  2240. { g_szOperational, ARRAYSIZE(g_szOperational), IDS_OPERATIONAL },
  2241. { g_szUnknownStatus, ARRAYSIZE(g_szUnknownStatus), IDS_UNKNOWNSTATUS },
  2242. };
  2243. BOOL LoadGlobalResources()
  2244. {
  2245. // If we don't get accelerators, its not worth failing the load
  2246. g_hAccel = (HACCEL) LoadAccelerators(g_hInstance, MAKEINTRESOURCE(IDR_ACCELERATORS));
  2247. Assert(g_hAccel);
  2248. for (UINT i = 0; i < g_cTrayIcons; i++)
  2249. {
  2250. g_aTrayIcons[i] = (HICON) LoadImage(g_hInstance,
  2251. MAKEINTRESOURCE(idTrayIcons[i]),
  2252. IMAGE_ICON,
  2253. 0, 0,
  2254. LR_DEFAULTCOLOR);
  2255. VERIFY( g_aTrayIcons[i] );
  2256. }
  2257. for (i = 0; i < ARRAYSIZE(g_aStrings); i++)
  2258. {
  2259. if (FALSE == LoadString(g_hInstance,
  2260. g_aStrings[i].id,
  2261. g_aStrings[i].psz,
  2262. static_cast<int>(g_aStrings[i].len)))
  2263. {
  2264. return FALSE;
  2265. }
  2266. }
  2267. return TRUE;
  2268. }
  2269. //
  2270. // IsTerminalServicesEnabled
  2271. //
  2272. //
  2273. void IsTerminalServicesEnabled( LPBOOL pfIsTSEnabled, LPBOOL pfIsSingleUserTS, LPBOOL pfIsTSServer )
  2274. {
  2275. *pfIsTSEnabled = FALSE;
  2276. *pfIsSingleUserTS = FALSE;
  2277. *pfIsTSServer = FALSE;
  2278. OSVERSIONINFOEX osVersionInfo;
  2279. ZeroMemory(&osVersionInfo, sizeof(OSVERSIONINFOEX));
  2280. osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  2281. if(GetVersionEx((OSVERSIONINFO*)&osVersionInfo))
  2282. {
  2283. if(osVersionInfo.wSuiteMask & (VER_SUITE_TERMINAL | VER_SUITE_SINGLEUSERTS))
  2284. {
  2285. *pfIsTSEnabled = TRUE;
  2286. if(osVersionInfo.wProductType == VER_NT_SERVER ||
  2287. osVersionInfo.wProductType == VER_NT_DOMAIN_CONTROLLER)
  2288. {
  2289. *pfIsTSServer = TRUE;
  2290. return;
  2291. }
  2292. if(osVersionInfo.wProductType == VER_NT_WORKSTATION &&
  2293. osVersionInfo.wSuiteMask == VER_SUITE_SINGLEUSERTS)
  2294. {
  2295. BOOL fIsMultipleSessionsAllowed;
  2296. HKEY hKey = NULL;
  2297. DWORD dwType, dwValue, dwValueSize = sizeof(dwValue);
  2298. fIsMultipleSessionsAllowed = ((ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  2299. TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"),
  2300. 0,
  2301. KEY_QUERY_VALUE,
  2302. &hKey)) &&
  2303. (ERROR_SUCCESS == RegQueryValueEx(hKey,
  2304. TEXT("AllowMultipleTSSessions"),
  2305. NULL,
  2306. &dwType,
  2307. reinterpret_cast<LPBYTE>(&dwValue),
  2308. &dwValueSize)) &&
  2309. (REG_DWORD == dwType) &&
  2310. (dwValue != 0));
  2311. if (hKey != NULL)
  2312. {
  2313. (LONG)RegCloseKey(hKey);
  2314. }
  2315. *pfIsSingleUserTS = !fIsMultipleSessionsAllowed;
  2316. }
  2317. }
  2318. }
  2319. }
  2320. /*++
  2321. Routine Description:
  2322. Determines if the system is low on memory. If the system has less than8 Mbytes of
  2323. memory than the system is low on memory.
  2324. Arguments:
  2325. void
  2326. Return Value:
  2327. TRUE -- System is low on memory
  2328. FALSE -- System is not low on memory
  2329. Revision History:
  2330. 1-6-2000 Created by omiller
  2331. --*/
  2332. BOOLEAN IsMemoryLow()
  2333. {
  2334. SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
  2335. SYSTEM_BASIC_INFORMATION Basic;
  2336. ULONG ulPagesPerMeg;
  2337. ULONG ulPageSize;
  2338. NTSTATUS Status;
  2339. BOOLEAN bMemoryLow = TRUE;
  2340. // Get the page size
  2341. //
  2342. Status = NtQuerySystemInformation( SystemBasicInformation,
  2343. &Basic,
  2344. sizeof(Basic),
  2345. 0 );
  2346. if ( SUCCEEDED(Status) )
  2347. {
  2348. ulPagesPerMeg = 1024*1024 / Basic.PageSize;
  2349. ulPageSize = Basic.PageSize;
  2350. // Determine if we are low on memory
  2351. //
  2352. Status = NtQuerySystemInformation( SystemPerformanceInformation,
  2353. &PerfInfo,
  2354. sizeof(PerfInfo),
  2355. 0 );
  2356. if ( SUCCEEDED(Status) )
  2357. {
  2358. // Compute the number of free megs.
  2359. //
  2360. ULONG ulFreeMeg = (PerfInfo.CommitLimit - PerfInfo.CommittedPages) / ulPagesPerMeg;
  2361. if ( ulFreeMeg > MIN_MEMORY_REQUIRED )
  2362. {
  2363. // We are not low on memory we have about 8 megs of memory.
  2364. // We could get this value from Reg key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\ContentIndex
  2365. // Value MinWordlistMemory
  2366. //
  2367. bMemoryLow = FALSE;
  2368. }
  2369. }
  2370. }
  2371. return bMemoryLow;
  2372. }
  2373. /*++ WinMain
  2374. Routine Description:
  2375. Windows app startup. Does basic initialization and creates the main window
  2376. Arguments:
  2377. Standard winmain
  2378. Return Value:
  2379. App exit code
  2380. Revision History:
  2381. Nov-30-95 Davepl Created
  2382. --*/
  2383. int WINAPI WinMainT(
  2384. HINSTANCE hInstance, // handle to current instance
  2385. HINSTANCE hPrevInstance, // handle to previous instance (n/a)
  2386. LPTSTR lpCmdLine, // pointer to command line
  2387. int nShowCmd // show state of window
  2388. )
  2389. {
  2390. g_hInstance = hInstance;
  2391. int retval = TRUE;
  2392. HKEY hKeyPolicy;
  2393. DWORD dwType, dwData = 0, dwSize;
  2394. int cx, cy;
  2395. g_msgTaskbarCreated = RegisterWindowMessage(TEXT("TaskbarCreated"));
  2396. // Try to create or grab the startup mutex. Only in the case
  2397. // where everything goes well and the mutex already existed AND
  2398. // we were able to grab it do we deem ourselves to be a secondary instance
  2399. g_hStartupMutex = CreateMutex(NULL, TRUE, cszStartupMutex);
  2400. if (g_hStartupMutex && GetLastError() == ERROR_ALREADY_EXISTS)
  2401. {
  2402. // Give the other instance (the one that owns the startup mutex) 10
  2403. // seconds to do its thing
  2404. WaitForSingleObject(g_hStartupMutex, FINDME_TIMEOUT);
  2405. }
  2406. // Determine if Terminal Services is Enabled and if so,
  2407. // find out on what session we're running.
  2408. IsTerminalServicesEnabled(&g_fIsTSEnabled, &g_fIsSingleUserTS, &g_fIsTSServer);
  2409. if (g_fIsTSEnabled)
  2410. {
  2411. ProcessIdToSessionId( GetCurrentProcessId(), &g_dwMySessionId );
  2412. }
  2413. //
  2414. // Locate and activate a running instance if it exists.
  2415. //
  2416. TCHAR szTitle[MAX_PATH];
  2417. if (LoadString(hInstance, IDS_APPTITLE, szTitle, ARRAYSIZE(szTitle)))
  2418. {
  2419. HWND hwndOld = FindWindow(WC_DIALOG, szTitle);
  2420. if (hwndOld)
  2421. {
  2422. // Send the other copy of ourselves a PWM_ACTIVATE message. If that
  2423. // succeeds, and it returns PWM_ACTIVATE back as the return code, it's
  2424. // up and alive and we can exit this instance.
  2425. DWORD dwPid = 0;
  2426. GetWindowThreadProcessId(hwndOld, &dwPid);
  2427. AllowSetForegroundWindow(dwPid);
  2428. ULONG_PTR dwResult;
  2429. if (SendMessageTimeout(hwndOld,
  2430. PWM_ACTIVATE,
  2431. 0, 0,
  2432. SMTO_ABORTIFHUNG,
  2433. FINDME_TIMEOUT,
  2434. &dwResult))
  2435. {
  2436. if (dwResult == PWM_ACTIVATE)
  2437. {
  2438. goto cleanup;
  2439. }
  2440. }
  2441. }
  2442. }
  2443. if (RegOpenKeyEx (HKEY_CURRENT_USER,
  2444. TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System"),
  2445. 0, KEY_READ, &hKeyPolicy) == ERROR_SUCCESS)
  2446. {
  2447. dwSize = sizeof(dwData);
  2448. RegQueryValueEx (hKeyPolicy, TEXT("DisableTaskMgr"), NULL,
  2449. &dwType, (LPBYTE) &dwData, &dwSize);
  2450. RegCloseKey (hKeyPolicy);
  2451. if (dwData)
  2452. {
  2453. TCHAR szTitle[25];
  2454. TCHAR szMessage[200];
  2455. LoadString (hInstance, IDS_TASKMGR, szTitle, ARRAYSIZE(szTitle));
  2456. LoadString (hInstance, IDS_TASKMGRDISABLED , szMessage, ARRAYSIZE(szMessage));
  2457. MessageBox (NULL, szMessage, szTitle, MB_OK | MB_ICONSTOP);
  2458. retval = FALSE;
  2459. goto cleanup;
  2460. }
  2461. }
  2462. // No running instance found, so we run as normal
  2463. InitCommonControls();
  2464. InitDavesControls();
  2465. // Start the worker thread. If it fails, you just don't
  2466. // get tray icons
  2467. g_hTrayThread = CreateThread(NULL, 0, TrayThreadMessageLoop, NULL, 0, &g_idTrayThread);
  2468. ASSERT(g_hTrayThread);
  2469. // Init the page table
  2470. g_nPageCount = ARRAYSIZE(g_pPages);
  2471. g_pPages[0] = new CTaskPage;
  2472. if (NULL == g_pPages[0])
  2473. {
  2474. retval = FALSE;
  2475. goto cleanup;
  2476. }
  2477. g_pPages[1] = new CProcPage;
  2478. if (NULL == g_pPages[1])
  2479. {
  2480. retval = FALSE;
  2481. goto cleanup;
  2482. }
  2483. if( !IsMemoryLow() )
  2484. {
  2485. g_pPages[2] = new CPerfPage;
  2486. if (NULL == g_pPages[2])
  2487. {
  2488. retval = FALSE;
  2489. goto cleanup;
  2490. }
  2491. // The networking opage is put before the User page. (omiller) add page to global page list
  2492. //
  2493. g_pPages[3] = new CNetPage;
  2494. if (NULL == g_pPages[3])
  2495. {
  2496. retval = FALSE;
  2497. goto cleanup;
  2498. }
  2499. if (g_fIsTSEnabled && !g_fIsSingleUserTS)
  2500. {
  2501. // Net page is 3 user page is 4
  2502. //
  2503. g_pPages[4] = new CUserPage;
  2504. if (NULL == g_pPages[4])
  2505. {
  2506. retval = FALSE;
  2507. goto cleanup;
  2508. }
  2509. }
  2510. else
  2511. {
  2512. --g_nPageCount; // Decrement count if users pane is disabled
  2513. }
  2514. }
  2515. else
  2516. {
  2517. // We are low on memory, only load the first two tabs.
  2518. //
  2519. g_nPageCount = 2;
  2520. }
  2521. // Load whatever resources that we need available globally
  2522. if (FALSE == LoadGlobalResources())
  2523. {
  2524. retval = FALSE;
  2525. goto cleanup;
  2526. }
  2527. // Initialize the history buffers
  2528. if (0 == InitPerfInfo())
  2529. {
  2530. retval = FALSE;
  2531. goto cleanup;
  2532. }
  2533. if (0 == InitNetInfo())
  2534. {
  2535. retval = FALSE;
  2536. goto cleanup;
  2537. }
  2538. // Create the main window (it's a modeless dialog, to be precise)
  2539. g_hMainWnd = CreateDialog(hInstance,
  2540. MAKEINTRESOURCE(IDD_MAINWND),
  2541. NULL,
  2542. MainWindowProc);
  2543. if (NULL == g_hMainWnd)
  2544. {
  2545. retval = FALSE;
  2546. goto cleanup;
  2547. }
  2548. else
  2549. {
  2550. // Initialize the gloabl setting variables, Comma, decimal point, group seperation etc
  2551. //
  2552. OnSettingsChange();
  2553. fAlreadySetPos = TRUE;
  2554. cx = g_Options.m_rcWindow.right-g_Options.m_rcWindow.left;
  2555. cy = g_Options.m_rcWindow.bottom-g_Options.m_rcWindow.top;
  2556. SetWindowPos(g_hMainWnd, NULL,
  2557. g_Options.m_rcWindow.left,
  2558. g_Options.m_rcWindow.top,
  2559. cx,
  2560. cy,
  2561. SWP_NOZORDER);
  2562. ShowWindow(g_hMainWnd, nShowCmd);
  2563. }
  2564. // We're out of the "starting up" phase so release the startup mutex
  2565. if (g_hStartupMutex)
  2566. {
  2567. ReleaseMutex(g_hStartupMutex);
  2568. CloseHandle(g_hStartupMutex);
  2569. g_hStartupMutex = NULL;
  2570. }
  2571. // If we're the one, true, task manager, we can hang around till the
  2572. // bitter end in case the user has problems during shutdown
  2573. SetProcessShutdownParameters(1, SHUTDOWN_NORETRY);
  2574. MSG msg;
  2575. while (GetMessage(&msg, NULL, 0, 0))
  2576. {
  2577. if (!TranslateAccelerator(g_hMainWnd, g_hAccel, &msg))
  2578. {
  2579. if (!IsDialogMessage(g_hMainWnd, &msg))
  2580. {
  2581. TranslateMessage(&msg); // Translates virtual key codes
  2582. DispatchMessage(&msg); // Dispatches message to window
  2583. }
  2584. }
  2585. }
  2586. cleanup:
  2587. // We're no longer "starting up"
  2588. if (g_hStartupMutex)
  2589. {
  2590. ReleaseMutex(g_hStartupMutex);
  2591. CloseHandle(g_hStartupMutex);
  2592. g_hStartupMutex = NULL;
  2593. }
  2594. // Yes, I could use virtual destructors, but I could also poke
  2595. // myself in the eye with a sharp stick. Either way you wouldn't
  2596. // be able to see what's going on.
  2597. if (g_pPages[TASK_PAGE])
  2598. delete (CTaskPage *) g_pPages[TASK_PAGE];
  2599. if (g_pPages[PROC_PAGE])
  2600. delete (CProcPage *) g_pPages[PROC_PAGE];
  2601. if (g_pPages[PERF_PAGE])
  2602. delete (CPerfPage *) g_pPages[PERF_PAGE];
  2603. if (g_pPages[NET_PAGE])
  2604. delete (CNetPage *) g_pPages[NET_PAGE];
  2605. if (g_fIsTSEnabled)
  2606. {
  2607. if (g_pPages[USER_PAGE])
  2608. delete (CUserPage *) g_pPages[USER_PAGE];
  2609. }
  2610. ReleasePerfInfo();
  2611. return (retval);
  2612. }
  2613. //
  2614. // And now the magic begins. The normal C++ CRT code walks a set of vectors
  2615. // and calls through them to perform global initializations. Those vectors
  2616. // are always in data segments with a particular naming scheme. By delcaring
  2617. // the variables below, I can determine where in my code they get stuck, and
  2618. // then call them myself
  2619. //
  2620. typedef void (__cdecl *_PVFV)(void);
  2621. // This is all ridiculous.
  2622. #ifdef _M_IA64
  2623. #pragma section(".CRT$XIA",long,read)
  2624. #pragma section(".CRT$XIZ",long,read)
  2625. #pragma section(".CRT$XCA",long,read)
  2626. #pragma section(".CRT$XCZ",long,read)
  2627. #define _CRTALLOC(x) __declspec(allocate(x))
  2628. #else /* _M_IA64 */
  2629. #define _CRTALLOC(x)
  2630. #endif /* _M_IA64 */
  2631. #pragma data_seg(".CRT$XIA")
  2632. _CRTALLOC(".CRT$XIA") _PVFV __xi_a[] = { NULL };
  2633. #pragma data_seg(".CRT$XIZ")
  2634. _CRTALLOC(".CRT$XIZ") _PVFV __xi_z[] = { NULL };
  2635. #pragma data_seg(".CRT$XCA")
  2636. _CRTALLOC(".CRT$XCA") _PVFV __xc_a[] = { NULL };
  2637. #pragma data_seg(".CRT$XCZ")
  2638. _CRTALLOC(".CRT$XCZ") _PVFV __xc_z[] = { NULL };
  2639. #pragma data_seg(".data")
  2640. /*++ _initterm
  2641. Routine Description:
  2642. Walk the table of function pointers from the bottom up, until
  2643. the end is encountered. Do not skip the first entry. The initial
  2644. value of pfbegin points to the first valid entry. Do not try to
  2645. execute what pfend points to. Only entries before pfend are valid.
  2646. Arguments:
  2647. pfbegin - first pointer
  2648. pfend - last pointer
  2649. Revision History:
  2650. Nov-30-95 Davepl Created
  2651. --*/
  2652. static void __cdecl _initterm ( _PVFV * pfbegin, _PVFV * pfend )
  2653. {
  2654. while ( pfbegin < pfend )
  2655. {
  2656. // if current table entry is non-NULL, call thru it.
  2657. if ( *pfbegin != NULL )
  2658. {
  2659. (**pfbegin)();
  2660. }
  2661. ++pfbegin;
  2662. }
  2663. }
  2664. /*++ WinMain
  2665. Routine Description:
  2666. Windows app startup. Does basic initialization and creates the main window
  2667. Arguments:
  2668. Standard winmain
  2669. Return Value:
  2670. App exit code
  2671. Revision History:
  2672. Nov-30-95 Davepl Created
  2673. --*/
  2674. void _stdcall ModuleEntry(void)
  2675. {
  2676. int i;
  2677. STARTUPINFO si;
  2678. SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
  2679. //
  2680. // Do runtime startup initializers.
  2681. //
  2682. _initterm( __xi_a, __xi_z );
  2683. //
  2684. // do C++ constructors (initializers) specific to this EXE
  2685. //
  2686. _initterm( __xc_a, __xc_z );
  2687. LPTSTR pszCmdLine = GetCommandLine();
  2688. if ( *pszCmdLine == TEXT('\"') ) {
  2689. /*
  2690. * Scan, and skip over, subsequent characters until
  2691. * another double-quote or a null is encountered.
  2692. */
  2693. while ( *++pszCmdLine && (*pszCmdLine
  2694. != TEXT('\"')) );
  2695. /*
  2696. * If we stopped on a double-quote (usual case), skip
  2697. * over it.
  2698. */
  2699. if ( *pszCmdLine == TEXT('\"') )
  2700. pszCmdLine++;
  2701. }
  2702. else {
  2703. while (*pszCmdLine > TEXT(' '))
  2704. pszCmdLine++;
  2705. }
  2706. /*
  2707. * Skip past any white space preceeding the second token.
  2708. */
  2709. while (*pszCmdLine && (*pszCmdLine <= TEXT(' '))) {
  2710. pszCmdLine++;
  2711. }
  2712. si.dwFlags = 0;
  2713. GetStartupInfo(&si);
  2714. g_bMirroredOS = IS_MIRRORING_ENABLED();
  2715. i = WinMainT(GetModuleHandle(NULL), NULL, pszCmdLine,
  2716. si.dwFlags & STARTF_USESHOWWINDOW ? si.wShowWindow : SW_SHOWDEFAULT);
  2717. ExitProcess(i);
  2718. }
  2719. // DisplayFailureMsg
  2720. //
  2721. // Displays a generic error message based on the error code
  2722. // and message box title provided
  2723. void DisplayFailureMsg(HWND hWnd, UINT idTitle, DWORD dwError)
  2724. {
  2725. TCHAR szTitle[MAX_PATH];
  2726. TCHAR szMsg[MAX_PATH * 2];
  2727. TCHAR szError[MAX_PATH];
  2728. if (0 == LoadString(g_hInstance, idTitle, szTitle, ARRAYSIZE(szTitle)))
  2729. {
  2730. return;
  2731. }
  2732. if (0 == LoadString(g_hInstance, IDS_GENFAILURE, szMsg, ARRAYSIZE(szMsg)))
  2733. {
  2734. return;
  2735. }
  2736. // "incorrect paramter" doesn't make a lot of sense for the user, so
  2737. // massage it to be "Operation not allowed on this process".
  2738. if (dwError == ERROR_INVALID_PARAMETER)
  2739. {
  2740. if (0 == LoadString(g_hInstance, IDS_BADPROC, szError, ARRAYSIZE(szError)))
  2741. {
  2742. return;
  2743. }
  2744. }
  2745. else if (0 == FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
  2746. NULL,
  2747. dwError,
  2748. LANG_USER_DEFAULT,
  2749. szError,
  2750. ARRAYSIZE(szError),
  2751. NULL))
  2752. {
  2753. return;
  2754. }
  2755. lstrcat(szMsg, szError);
  2756. MessageBox(hWnd, szMsg, szTitle, MB_OK | MB_ICONERROR);
  2757. }
  2758. /*++ NewDeskDlgProc
  2759. Routine Description:
  2760. Dialog proc for the NewDesktop dialog
  2761. Arguments:
  2762. Return Value:
  2763. BOOL, TRUE == success
  2764. Revision History:
  2765. Nov-29-95 Davepl Created
  2766. --*/
  2767. typedef struct _NewDesktopInfo
  2768. {
  2769. TCHAR m_szName[MAX_PATH];
  2770. BOOL m_fStartExplorer;
  2771. } NewDesktopInfo;
  2772. BOOL CALLBACK NewDeskDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  2773. {
  2774. NewDesktopInfo * pndi = (NewDesktopInfo *) GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
  2775. switch (uMsg)
  2776. {
  2777. case WM_INITDIALOG:
  2778. {
  2779. pndi = (NewDesktopInfo *) lParam;
  2780. SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
  2781. CheckDlgButton(hwndDlg, IDC_STARTEXPLORER, pndi->m_fStartExplorer);
  2782. SetWindowText(GetDlgItem(hwndDlg, IDC_DESKTOPNAME), pndi->m_szName);
  2783. return TRUE;
  2784. }
  2785. case WM_COMMAND:
  2786. {
  2787. switch(LOWORD(wParam))
  2788. {
  2789. case IDCANCEL:
  2790. {
  2791. EndDialog(hwndDlg, IDCANCEL);
  2792. break;
  2793. }
  2794. case IDOK:
  2795. {
  2796. pndi->m_fStartExplorer = IsDlgButtonChecked(hwndDlg, IDC_STARTEXPLORER);
  2797. GetWindowText(GetDlgItem(hwndDlg, IDC_DESKTOPNAME), pndi->m_szName, ARRAYSIZE(pndi->m_szName));
  2798. EndDialog(hwndDlg, IDOK);
  2799. break;
  2800. }
  2801. default:
  2802. break;
  2803. }
  2804. }
  2805. default:
  2806. {
  2807. return FALSE;
  2808. }
  2809. }
  2810. }
  2811. #ifdef DESKTOP_SUPPORT
  2812. /*++ CreateNewDesktop
  2813. Routine Description:
  2814. Prompts the user for options and starts a new desktop
  2815. Arguments:
  2816. Return Value:
  2817. BOOL, TRUE == success
  2818. Revision History:
  2819. Nov-29-95 Davepl Created
  2820. --*/
  2821. BOOL CreateNewDesktop()
  2822. {
  2823. NewDesktopInfo ndi;
  2824. ndi.m_fStartExplorer = TRUE;
  2825. TryAgain:
  2826. //
  2827. // Look for a desktop name that's not in use yet
  2828. //
  2829. for (int i = 0; ; i++)
  2830. {
  2831. wsprintf( ndi.m_szName, TEXT("Desktop%d"), i );
  2832. HDESK hdesk = OpenDesktop( ndi.m_szName, 0, FALSE, DESKTOP_SWITCHDESKTOP );
  2833. if (hdesk)
  2834. {
  2835. CloseDesktop(hdesk);
  2836. }
  2837. else
  2838. {
  2839. break;
  2840. }
  2841. }
  2842. //
  2843. // Allow the user to modify the options
  2844. //
  2845. int iRet = DialogBoxParam(g_hInstance,
  2846. MAKEINTRESOURCE(IDD_CREATEDESKTOP),
  2847. g_hMainWnd,
  2848. NewDeskDlgProc,
  2849. (LPARAM) &ndi);
  2850. if (iRet != IDOK)
  2851. {
  2852. return FALSE;
  2853. }
  2854. //
  2855. // Create the new desktop
  2856. //
  2857. HDESK hdesk = CreateDesktop( ndi.m_szName, NULL, NULL, 0, MAXIMUM_ALLOWED, NULL );
  2858. if (NULL == hdesk)
  2859. {
  2860. DWORD dwError = GetLastError();
  2861. DisplayFailureMsg(g_hMainWnd, IDS_CANTCREATEDESKTOP, dwError);
  2862. goto TryAgain;
  2863. }
  2864. return S_OK;
  2865. }
  2866. #endif //DESKTOP_SUPPORT
  2867. /*++ LoadPopupMenu
  2868. Routine Description:
  2869. Loads a popup menu from a resource. Needed because USER
  2870. does not support popup menus (yes, really)
  2871. Arguments:
  2872. hinst - module instance to look for resource in
  2873. id - resource id of popup menu
  2874. Return Value:
  2875. Revision History:
  2876. Nov-22-95 Davepl Created
  2877. --*/
  2878. HMENU LoadPopupMenu(HINSTANCE hinst, UINT id)
  2879. {
  2880. HMENU hmenuParent = LoadMenu(hinst, MAKEINTRESOURCE(id));
  2881. if (hmenuParent)
  2882. {
  2883. HMENU hpopup = GetSubMenu(hmenuParent, 0);
  2884. RemoveMenu(hmenuParent, 0, MF_BYPOSITION);
  2885. DestroyMenu(hmenuParent);
  2886. return hpopup;
  2887. }
  2888. return NULL;
  2889. }
  2890. /*++ SubclassListView, ListViewWndProc, LV_GetViewRect
  2891. Routine Description:
  2892. Routines for flicker-free painting of listview controls.
  2893. Revision History:
  2894. Dec-23-96 vadimg Created
  2895. --*/
  2896. typedef LRESULT (CALLBACK *ListView)(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  2897. ListView gfnListView;
  2898. void inline _SetRectRgnIndirect(HRGN hrgn, LPRECT prc)
  2899. {
  2900. SetRectRgn(hrgn, prc->left, prc->top, prc->right, prc->bottom);
  2901. }
  2902. void LV_GetViewRgn(HWND hwnd)
  2903. {
  2904. RECT rcItem;
  2905. int nCount, i;
  2906. SetRectRgn(g_hrgnView, 0, 0, 0, 0);
  2907. nCount = ListView_GetItemCount(hwnd);
  2908. for (i = 0; i < nCount; i++) {
  2909. // exclude the selected item, listview does not erase it
  2910. if (ListView_GetItemState(hwnd, i, LVIS_SELECTED))
  2911. continue;
  2912. ListView_GetItemRect(hwnd, i, &rcItem, LVIR_BOUNDS);
  2913. // listview leaves off SM_CXEDGE when painting first column
  2914. rcItem.left += g_cxEdge;
  2915. _SetRectRgnIndirect(g_hrgnClip, &rcItem);
  2916. CombineRgn(g_hrgnView, g_hrgnView, g_hrgnClip, RGN_OR);
  2917. }
  2918. }
  2919. LRESULT CALLBACK ListViewWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  2920. {
  2921. switch (msg) {
  2922. case WM_SYSCOLORCHANGE:
  2923. if (g_hbrWindow)
  2924. DeleteObject(g_hbrWindow);
  2925. g_hbrWindow = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
  2926. InvalidateRect(hwnd, NULL, TRUE);
  2927. break;
  2928. case WM_ERASEBKGND:
  2929. {
  2930. // To achieve the flicker-free effect only erase the area not
  2931. // taken up by the items. The items will be filled by listview.
  2932. RECT rcAll;
  2933. HDC hdc = (HDC)wParam;
  2934. LV_GetViewRgn(hwnd);
  2935. GetClientRect(hwnd, &rcAll);
  2936. _SetRectRgnIndirect(g_hrgnClip, &rcAll);
  2937. CombineRgn(g_hrgnClip, g_hrgnClip, g_hrgnView, RGN_DIFF);
  2938. FillRgn(hdc, g_hrgnClip, g_hbrWindow);
  2939. }
  2940. return TRUE;
  2941. }
  2942. return CallWindowProc(gfnListView, hwnd, msg, wParam, lParam);
  2943. }
  2944. void SubclassListView(HWND hwnd)
  2945. {
  2946. gfnListView = (ListView)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)ListViewWndProc);
  2947. }