Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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