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
3423 lines
98 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// TaskMan - NT TaskManager
|
|
// Copyright (C) Microsoft
|
|
//
|
|
// File: Main.CPP
|
|
//
|
|
// History: Nov-10-95 DavePl Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#include "precomp.h"
|
|
#define DECL_CRTFREE
|
|
#include <crtfree.h>
|
|
|
|
static UINT g_msgTaskbarCreated = 0;
|
|
static const UINT idTrayIcons[] =
|
|
{
|
|
IDI_TRAY0, IDI_TRAY1, IDI_TRAY2, IDI_TRAY3, IDI_TRAY4, IDI_TRAY5,
|
|
IDI_TRAY6, IDI_TRAY7, IDI_TRAY8, IDI_TRAY9, IDI_TRAY10, IDI_TRAY11
|
|
};
|
|
|
|
HICON g_aTrayIcons[ARRAYSIZE(idTrayIcons)];
|
|
UINT g_cTrayIcons = ARRAYSIZE(idTrayIcons);
|
|
#define MIN_MEMORY_REQUIRED 8 // If the system has less than 8 megs of memory only load the first two tabs.
|
|
|
|
//
|
|
// Control IDs
|
|
//
|
|
|
|
#define IDC_STATUSWND 100
|
|
|
|
//
|
|
// Globals - this app is (effectively) single threaded and these values
|
|
// are used by all pages
|
|
//
|
|
|
|
const WCHAR cszStartupMutex[] = L"NTShell Taskman Startup Mutex";
|
|
#define FINDME_TIMEOUT 10000 // Wait to to 10 seconds for a response
|
|
typedef BOOLEAN (*PFNSETSUSPENDSTATE)(BOOLEAN, BOOLEAN, BOOLEAN);
|
|
|
|
void MainWnd_OnSize(HWND hwnd, UINT state, int cx, int cy);
|
|
|
|
HANDLE g_hStartupMutex = NULL;
|
|
BOOL g_fMenuTracking = FALSE;
|
|
HWND g_hMainWnd = NULL;
|
|
HDESK g_hMainDesktop = NULL;
|
|
HWND g_hStatusWnd = NULL;
|
|
HINSTANCE g_hInstance = NULL;
|
|
HACCEL g_hAccel = NULL;
|
|
BYTE g_cProcessors = (BYTE) 0;
|
|
HMENU g_hMenu = NULL;
|
|
BOOL g_fCantHide = FALSE;
|
|
BOOL g_fInPopup = FALSE;
|
|
DWORD g_idTrayThread = 0;
|
|
HANDLE g_hTrayThread = NULL;
|
|
LONG g_minWidth = 0;
|
|
LONG g_minHeight = 0;
|
|
LONG g_DefSpacing = 0;
|
|
LONG g_InnerSpacing = 0;
|
|
LONG g_TopSpacing = 0;
|
|
LONG g_cxEdge = 0;
|
|
|
|
LONG g_ControlWidthSpacing = 0;
|
|
LONG g_ControlHeightSpacing = 0;
|
|
|
|
HRGN g_hrgnView = NULL;
|
|
HRGN g_hrgnClip = NULL;
|
|
|
|
HBRUSH g_hbrWindow = NULL;
|
|
|
|
COptions g_Options;
|
|
|
|
static BOOL fAlreadySetPos = FALSE;
|
|
|
|
BOOL g_bMirroredOS = FALSE;
|
|
|
|
//
|
|
// Global strings - short strings used too often to be LoadString'd
|
|
// every time
|
|
//
|
|
WCHAR g_szRealtime [SHORTSTRLEN];
|
|
WCHAR g_szNormal [SHORTSTRLEN];
|
|
WCHAR g_szHigh [SHORTSTRLEN];
|
|
WCHAR g_szLow [SHORTSTRLEN];
|
|
WCHAR g_szUnknown [SHORTSTRLEN];
|
|
WCHAR g_szAboveNormal [SHORTSTRLEN];
|
|
WCHAR g_szBelowNormal [SHORTSTRLEN];
|
|
WCHAR g_szHung [SHORTSTRLEN];
|
|
WCHAR g_szRunning [SHORTSTRLEN];
|
|
WCHAR g_szfmtTasks [SHORTSTRLEN];
|
|
WCHAR g_szfmtProcs [SHORTSTRLEN];
|
|
WCHAR g_szfmtCPU [SHORTSTRLEN];
|
|
WCHAR g_szfmtMEMK [SHORTSTRLEN];
|
|
WCHAR g_szfmtMEMM [SHORTSTRLEN];
|
|
WCHAR g_szfmtCPUNum [SHORTSTRLEN];
|
|
WCHAR g_szTotalCPU [SHORTSTRLEN];
|
|
WCHAR g_szKernelCPU [SHORTSTRLEN];
|
|
WCHAR g_szMemUsage [SHORTSTRLEN];
|
|
WCHAR g_szBytes [SHORTSTRLEN];
|
|
WCHAR g_szPackets [SHORTSTRLEN];
|
|
WCHAR g_szBitsPerSec [SHORTSTRLEN];
|
|
WCHAR g_szScaleFont [SHORTSTRLEN];
|
|
WCHAR g_szPercent [SHORTSTRLEN];
|
|
WCHAR g_szZero [SHORTSTRLEN];
|
|
WCHAR g_szNonOperational [SHORTSTRLEN];
|
|
WCHAR g_szUnreachable [SHORTSTRLEN];
|
|
WCHAR g_szDisconnected [SHORTSTRLEN];
|
|
WCHAR g_szConnecting [SHORTSTRLEN];
|
|
WCHAR g_szConnected [SHORTSTRLEN];
|
|
WCHAR g_szOperational [SHORTSTRLEN];
|
|
WCHAR g_szUnknownStatus [SHORTSTRLEN];
|
|
WCHAR g_szTimeSep [SHORTSTRLEN];
|
|
WCHAR g_szGroupThousSep [SHORTSTRLEN];
|
|
WCHAR g_szDecimal [SHORTSTRLEN];
|
|
ULONG g_ulGroupSep;
|
|
|
|
WCHAR g_szG[10]; // Localized "G"igabyte symbol
|
|
WCHAR g_szM[10]; // Localized "M"egabyte symbol
|
|
WCHAR g_szK[10]; // Localized "K"ilobyte symbol
|
|
|
|
|
|
|
|
// Page Array
|
|
//
|
|
// Each of the page objects is delcared here, and g_pPages is an array
|
|
// of pointers to those instantiated objects (at global scope). The main
|
|
// window code can call through the base members of the CPage class to
|
|
// do things like sizing, etc., without worrying about whatever specific
|
|
// stuff each page might do
|
|
|
|
int g_nPageCount = 0;
|
|
CPage * g_pPages[NUM_PAGES] = { NULL };
|
|
|
|
typedef DWORD (WINAPI * PFNCM_REQUEST_EJECT_PC) (void);
|
|
PFNCM_REQUEST_EJECT_PC gpfnCM_Request_Eject_PC = NULL;
|
|
|
|
// Terminal Services
|
|
BOOL g_fIsTSEnabled = FALSE;
|
|
BOOL g_fIsSingleUserTS = FALSE;
|
|
BOOL g_fIsTSServer = FALSE;
|
|
DWORD g_dwMySessionId = 0;
|
|
|
|
|
|
/*
|
|
Superclass of GROUPBOX
|
|
|
|
We need to turn on clipchildren for our dialog which contains the
|
|
history graphs, so they don't get erased during the repaint cycle.
|
|
Unfortunately, group boxes don't erase their backgrounds, so we
|
|
have to superclass them and provide a control that does.
|
|
|
|
This is a lot of extra work, but the painting is several orders of
|
|
magnitude nicer with it...
|
|
|
|
*/
|
|
|
|
/*++ DavesFrameWndProc
|
|
|
|
Routine Description:
|
|
|
|
WndProc for the custom group box class. Primary difference from
|
|
standard group box is that this one knows how to erase its own
|
|
background, and doesn't rely on the parent to do it for it.
|
|
These controls also have CLIPSIBLINGS turn on so as not to stomp
|
|
on the ownderdraw graphs they surround.
|
|
|
|
Arguments:
|
|
|
|
standard wndproc fare
|
|
|
|
Revision History:
|
|
|
|
Nov-29-95 Davepl Created
|
|
|
|
--*/
|
|
|
|
WNDPROC oldButtonWndProc = NULL;
|
|
|
|
LRESULT DavesFrameWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (msg == WM_CREATE)
|
|
{
|
|
//
|
|
// Turn on clipsiblings for the frame
|
|
//
|
|
|
|
DWORD dwStyle = GetWindowLong(hWnd, GWL_STYLE);
|
|
dwStyle |= WS_CLIPSIBLINGS;
|
|
SetWindowLong(hWnd, GWL_STYLE, dwStyle);
|
|
}
|
|
else if (msg == WM_ERASEBKGND)
|
|
{
|
|
return DefWindowProc( hWnd, msg, wParam, lParam );
|
|
}
|
|
|
|
// For anything else, we defer to the standard button class code
|
|
|
|
return CallWindowProc(oldButtonWndProc, hWnd, msg, wParam, lParam);
|
|
}
|
|
|
|
/*++ COptions::Save
|
|
|
|
Routine Description:
|
|
|
|
Saves current options to the registy
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
HRESULT
|
|
|
|
Revision History:
|
|
|
|
Jan-01-95 Davepl Created
|
|
|
|
--*/
|
|
|
|
const WCHAR szTaskmanKey[] = TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\TaskManager");
|
|
const WCHAR szOptionsKey[] = TEXT("Preferences");
|
|
|
|
HRESULT COptions::Save()
|
|
{
|
|
DWORD dwDisposition;
|
|
HKEY hkSave;
|
|
|
|
if (ERROR_SUCCESS != RegCreateKeyEx(HKEY_CURRENT_USER,
|
|
szTaskmanKey,
|
|
0,
|
|
TEXT("REG_BINARY"),
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_WRITE,
|
|
NULL,
|
|
&hkSave,
|
|
&dwDisposition))
|
|
{
|
|
return GetLastHRESULT();
|
|
}
|
|
|
|
if (ERROR_SUCCESS != RegSetValueEx(hkSave,
|
|
szOptionsKey,
|
|
0,
|
|
REG_BINARY,
|
|
(LPBYTE) this,
|
|
sizeof(COptions)))
|
|
{
|
|
RegCloseKey(hkSave);
|
|
return GetLastHRESULT();
|
|
}
|
|
|
|
RegCloseKey(hkSave);
|
|
return S_OK;
|
|
}
|
|
|
|
/*++ COptions::Load
|
|
|
|
Routine Description:
|
|
|
|
Loads current options to the registy
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
HRESULT
|
|
|
|
Revision History:
|
|
|
|
Jan-01-95 Davepl Created
|
|
|
|
--*/
|
|
|
|
HRESULT COptions::Load()
|
|
{
|
|
HKEY hkSave;
|
|
|
|
// If ctrl-alt-shift is down at startup, "forget" registry settings
|
|
|
|
if (GetKeyState(VK_SHIFT) < 0 &&
|
|
GetKeyState(VK_MENU) < 0 &&
|
|
GetKeyState(VK_CONTROL) < 0)
|
|
{
|
|
SetDefaultValues();
|
|
return S_FALSE;
|
|
}
|
|
|
|
if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_CURRENT_USER,
|
|
szTaskmanKey,
|
|
0,
|
|
KEY_READ,
|
|
&hkSave))
|
|
{
|
|
return S_FALSE;
|
|
}
|
|
|
|
DWORD dwType;
|
|
DWORD dwSize = sizeof(COptions);
|
|
if (ERROR_SUCCESS != RegQueryValueEx(hkSave,
|
|
szOptionsKey,
|
|
0,
|
|
&dwType,
|
|
(LPBYTE) this,
|
|
&dwSize)
|
|
|
|
// Validate type and size of options info we got from the registry
|
|
|
|
|| dwType != REG_BINARY
|
|
|| dwSize != sizeof(COptions)
|
|
|
|
// Validate options, revert to default if any are invalid (like if
|
|
// the window would be offscreen)
|
|
|
|
|| MonitorFromRect(&m_rcWindow, MONITOR_DEFAULTTONULL) == NULL
|
|
//number of available pages might be less than NUM_PAGES
|
|
|| m_iCurrentPage > g_nPageCount - 1)
|
|
|
|
|
|
{
|
|
// Reset to default values
|
|
|
|
SetDefaultValues();
|
|
RegCloseKey(hkSave);
|
|
return S_FALSE;
|
|
}
|
|
|
|
RegCloseKey(hkSave);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/*++ COptions::SetDefaultValues
|
|
|
|
Routine Description:
|
|
|
|
Used to init the options to a default state when the saved copy
|
|
cannot be found, is damaged, or is not the correct version
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
nothing
|
|
|
|
Revision History:
|
|
|
|
Dec-06-00 jeffreys Moved from taskmgr.h
|
|
|
|
--*/
|
|
|
|
BOOL IsUserAdmin();
|
|
|
|
// Columns which are visible, by default, in the process view
|
|
const COLUMNID g_aDefaultCols[] = { COL_IMAGENAME, COL_USERNAME, COL_CPU, COL_MEMUSAGE, (COLUMNID)-1 };
|
|
const COLUMNID g_aTSCols[] = { COL_IMAGENAME, COL_USERNAME, COL_SESSIONID, COL_CPU, COL_MEMUSAGE, (COLUMNID)-1 };
|
|
const NETCOLUMNID g_aNetDefaultCols[] = { COL_ADAPTERNAME, COL_NETWORKUTIL, COL_LINKSPEED, COL_STATE, (NETCOLUMNID)-1 };
|
|
|
|
void COptions::SetDefaultValues()
|
|
{
|
|
ZeroMemory(this, sizeof(COptions));
|
|
|
|
m_cbSize = sizeof(COptions);
|
|
|
|
BOOL bScreenReader = FALSE;
|
|
if (SystemParametersInfo(SPI_GETSCREENREADER, 0, (PVOID) &bScreenReader, 0) && bScreenReader)
|
|
{
|
|
// No automatic updates for machines with screen readers
|
|
m_dwTimerInterval = 0;
|
|
}
|
|
else
|
|
{
|
|
m_dwTimerInterval = 1000;
|
|
}
|
|
|
|
m_vmViewMode = VM_DETAILS;
|
|
m_cmHistMode = CM_PANES;
|
|
m_usUpdateSpeed = US_NORMAL;
|
|
m_fMinimizeOnUse = TRUE;
|
|
m_fConfirmations = TRUE;
|
|
m_fAlwaysOnTop = TRUE;
|
|
m_fShow16Bit = TRUE;
|
|
m_iCurrentPage = -1;
|
|
m_rcWindow.top = 10;
|
|
m_rcWindow.left = 10;
|
|
m_rcWindow.bottom = 10 + g_minHeight;
|
|
m_rcWindow.right = 10 + g_minWidth;
|
|
|
|
m_bShowAllProcess = (g_fIsTSEnabled && !g_fIsSingleUserTS && IsUserAdmin());
|
|
|
|
const COLUMNID *pcol = (g_fIsTSEnabled && !g_fIsSingleUserTS) ? g_aTSCols : g_aDefaultCols;
|
|
|
|
for (int i = 0; i < NUM_COLUMN + 1 ; i++, pcol++)
|
|
{
|
|
m_ActiveProcCol[i] = *pcol;
|
|
|
|
if ((COLUMNID)-1 == *pcol)
|
|
break;
|
|
}
|
|
|
|
// Set all of the columns widths to -1
|
|
|
|
FillMemory(m_ColumnWidths, sizeof(m_ColumnWidths), 0xFF);
|
|
FillMemory(m_ColumnPositions, sizeof(m_ColumnPositions), 0xFF);
|
|
|
|
// Set the Network default values
|
|
//
|
|
const NETCOLUMNID *pnetcol = g_aNetDefaultCols;
|
|
|
|
for (int i = 0; i < NUM_NETCOLUMN + 1 ; i++, pnetcol++)
|
|
{
|
|
m_ActiveNetCol[i] = *pnetcol;
|
|
if ((NETCOLUMNID)-1 == *pnetcol)
|
|
break;
|
|
}
|
|
|
|
// Set all of the columns widths to -1
|
|
//
|
|
FillMemory(m_NetColumnWidths, sizeof(m_NetColumnWidths), 0xFF);
|
|
FillMemory(m_NetColumnPositions, sizeof(m_NetColumnPositions), 0xFF);
|
|
|
|
m_bAutoSize = TRUE;
|
|
m_bGraphBytesSent = FALSE;
|
|
m_bGraphBytesReceived = FALSE;
|
|
m_bGraphBytesTotal = TRUE;
|
|
m_bNetShowAll = FALSE;
|
|
m_bShowScale = TRUE;
|
|
m_bTabAlwaysActive = FALSE;
|
|
|
|
}
|
|
|
|
BOOL FPalette(void)
|
|
{
|
|
HDC hdc = GetDC(NULL);
|
|
BOOL fPalette = (GetDeviceCaps(hdc, NUMCOLORS) != -1);
|
|
ReleaseDC(NULL, hdc);
|
|
return fPalette;
|
|
}
|
|
|
|
/*++ InitDavesControls
|
|
|
|
Routine Description:
|
|
|
|
Superclasses GroupBox for better drawing
|
|
|
|
Note that I'm not very concerned about failure here, since it
|
|
something goes wrong the dialog creation will fail awayway, and
|
|
it will be handled there
|
|
|
|
Arguments:
|
|
|
|
Revision History:
|
|
|
|
Nov-29-95 Davepl Created
|
|
|
|
--*/
|
|
|
|
void InitDavesControls()
|
|
{
|
|
static const WCHAR szControlName[] = TEXT("DavesFrameClass");
|
|
|
|
WNDCLASS wndclass;
|
|
|
|
//
|
|
// Get the class info for the Button class (which is what group
|
|
// boxes really are) and create a new class based on it
|
|
//
|
|
|
|
if (!GetClassInfo(g_hInstance, TEXT("Button"), &wndclass))
|
|
return; // Ungraceful exit, but better than random unit'd lpfnWndProc
|
|
|
|
oldButtonWndProc = wndclass.lpfnWndProc;
|
|
|
|
wndclass.hInstance = g_hInstance;
|
|
wndclass.lpfnWndProc = DavesFrameWndProc;
|
|
wndclass.lpszClassName = szControlName;
|
|
wndclass.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
|
|
|
|
(ATOM)RegisterClass(&wndclass);
|
|
|
|
return;
|
|
}
|
|
|
|
/*++ SetTitle
|
|
|
|
Routine Description:
|
|
|
|
Sets the app's title in the title bar (we do this on startup and
|
|
when coming out of notitle mode).
|
|
|
|
Arguments:
|
|
|
|
none
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
Revision History:
|
|
|
|
Jan-24-95 Davepl Created
|
|
|
|
--*/
|
|
|
|
void SetTitle()
|
|
{
|
|
WCHAR szTitle[MAX_PATH];
|
|
LoadString(g_hInstance, IDS_APPTITLE, szTitle, MAX_PATH);
|
|
SetWindowText(g_hMainWnd, szTitle);
|
|
}
|
|
|
|
/*++ UpdateMenuStates
|
|
|
|
Routine Description:
|
|
|
|
Updates the menu checks / ghosting based on the
|
|
current settings and options
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Revision History:
|
|
|
|
Nov-29-95 Davepl Created
|
|
|
|
--*/
|
|
|
|
void UpdateMenuStates()
|
|
{
|
|
HMENU hMenu = GetMenu(g_hMainWnd);
|
|
if (hMenu)
|
|
{
|
|
CheckMenuRadioItem(hMenu, VM_FIRST, VM_LAST, VM_FIRST + (UINT) g_Options.m_vmViewMode, MF_BYCOMMAND);
|
|
CheckMenuRadioItem(hMenu, CM_FIRST, CM_LAST, CM_FIRST + (UINT) g_Options.m_cmHistMode, MF_BYCOMMAND);
|
|
CheckMenuRadioItem(hMenu, US_FIRST, US_LAST, US_FIRST + (UINT) g_Options.m_usUpdateSpeed, MF_BYCOMMAND);
|
|
|
|
CheckMenuItem(hMenu, IDM_ALWAYSONTOP, MF_BYCOMMAND | (g_Options.m_fAlwaysOnTop ? MF_CHECKED : MF_UNCHECKED));
|
|
CheckMenuItem(hMenu, IDM_MINIMIZEONUSE, MF_BYCOMMAND | (g_Options.m_fMinimizeOnUse ? MF_CHECKED : MF_UNCHECKED));
|
|
CheckMenuItem(hMenu, IDM_KERNELTIMES, MF_BYCOMMAND | (g_Options.m_fKernelTimes ? MF_CHECKED : MF_UNCHECKED));
|
|
CheckMenuItem(hMenu, IDM_NOTITLE, MF_BYCOMMAND | (g_Options.m_fNoTitle ? MF_CHECKED : MF_UNCHECKED));
|
|
CheckMenuItem(hMenu, IDM_HIDEWHENMIN, MF_BYCOMMAND | (g_Options.m_fHideWhenMin ? MF_CHECKED : MF_UNCHECKED));
|
|
CheckMenuItem(hMenu, IDM_SHOW16BIT, MF_BYCOMMAND | (g_Options.m_fShow16Bit ? MF_CHECKED : MF_UNCHECKED));
|
|
CheckMenuItem(hMenu, IDM_SHOWDOMAINNAMES, MF_BYCOMMAND | (g_Options.m_fShowDomainNames ? MF_CHECKED : MF_UNCHECKED));
|
|
|
|
// Remove the CPU history style options on single processor machines
|
|
|
|
if (g_cProcessors < 2)
|
|
{
|
|
DeleteMenu(hMenu, IDM_ALLCPUS, MF_BYCOMMAND);
|
|
}
|
|
|
|
CheckMenuItem(hMenu,IDM_SHOWSCALE, g_Options.m_bShowScale ? MF_CHECKED:MF_UNCHECKED);
|
|
CheckMenuItem(hMenu,IDM_AUTOSIZE, g_Options.m_bAutoSize ? MF_CHECKED:MF_UNCHECKED);
|
|
CheckMenuItem(hMenu,IDM_BYTESSENT, g_Options.m_bGraphBytesSent ? MF_CHECKED:MF_UNCHECKED);
|
|
CheckMenuItem(hMenu,IDM_BYTESRECEIVED, g_Options.m_bGraphBytesReceived ? MF_CHECKED:MF_UNCHECKED);
|
|
CheckMenuItem(hMenu,IDM_BYTESTOTAL, g_Options.m_bGraphBytesTotal ? MF_CHECKED:MF_UNCHECKED);
|
|
CheckMenuItem(hMenu,IDM_SHOWALLDATA, g_Options.m_bNetShowAll ? MF_CHECKED:MF_UNCHECKED);
|
|
CheckMenuItem(hMenu,IDM_TABALWAYSACTIVE, g_Options.m_bTabAlwaysActive ? MF_CHECKED:MF_UNCHECKED);
|
|
}
|
|
|
|
}
|
|
|
|
/*++ SizeChildPage
|
|
|
|
Routine Description:
|
|
|
|
Size the active child page based on the tab control
|
|
|
|
Arguments:
|
|
|
|
hwndMain - Main window
|
|
|
|
Return Value:
|
|
|
|
Revision History:
|
|
|
|
Nov-29-95 Davepl Created
|
|
|
|
--*/
|
|
|
|
void SizeChildPage(HWND hwndMain)
|
|
{
|
|
if (g_Options.m_iCurrentPage >= 0 && g_Options.m_iCurrentPage < g_nPageCount )
|
|
{
|
|
// If we are in maximum viewing mode, the page gets the whole
|
|
// window area
|
|
|
|
HWND hwndPage = g_pPages[g_Options.m_iCurrentPage]->GetPageWindow();
|
|
|
|
DWORD dwStyle = GetWindowLong (g_hMainWnd, GWL_STYLE);
|
|
|
|
if (g_Options.m_fNoTitle)
|
|
{
|
|
RECT rcMainWnd;
|
|
GetClientRect(g_hMainWnd, &rcMainWnd);
|
|
SetWindowPos(hwndPage, HWND_TOP, rcMainWnd.left, rcMainWnd.top,
|
|
rcMainWnd.right - rcMainWnd.left,
|
|
rcMainWnd.bottom - rcMainWnd.top, SWP_NOZORDER | SWP_NOACTIVATE);
|
|
|
|
// remove caption & menu bar, etc.
|
|
|
|
dwStyle &= ~(WS_DLGFRAME | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX);
|
|
// SetWindowLong (g_hMainWnd, GWL_ID, 0);
|
|
SetWindowLong (g_hMainWnd, GWL_STYLE, dwStyle);
|
|
SetMenu(g_hMainWnd, NULL);
|
|
|
|
}
|
|
else
|
|
{
|
|
// If we have a page being displayed, we need to size it also
|
|
// put menu bar & caption back in
|
|
|
|
dwStyle = WS_TILEDWINDOW | dwStyle;
|
|
SetWindowLong (g_hMainWnd, GWL_STYLE, dwStyle);
|
|
|
|
if (g_hMenu)
|
|
{
|
|
SetMenu(g_hMainWnd, g_hMenu);
|
|
UpdateMenuStates();
|
|
}
|
|
|
|
SetTitle();
|
|
|
|
if (hwndPage)
|
|
{
|
|
RECT rcCtl;
|
|
HWND hwndCtl = GetDlgItem(hwndMain, IDC_TABS);
|
|
GetClientRect(hwndCtl, &rcCtl);
|
|
|
|
MapWindowPoints(hwndCtl, hwndMain, (LPPOINT)&rcCtl, 2);
|
|
TabCtrl_AdjustRect(hwndCtl, FALSE, &rcCtl);
|
|
|
|
SetWindowPos(hwndPage, HWND_TOP, rcCtl.left, rcCtl.top,
|
|
rcCtl.right - rcCtl.left, rcCtl.bottom - rcCtl.top, SWP_NOZORDER | SWP_NOACTIVATE);
|
|
}
|
|
}
|
|
if( g_Options.m_iCurrentPage == NET_PAGE )
|
|
{
|
|
// The network page is dynamic adapters can be added and removed. If taskmgr is minimized and
|
|
// a Adapter is added or removed. When taskmgr is maximized/restored again the netpage must be
|
|
// resized so the change is reflected. Thus the size change must be reported to the adapter.
|
|
//
|
|
((CNetPage *)g_pPages[g_Options.m_iCurrentPage])->SizeNetPage();
|
|
}
|
|
}
|
|
}
|
|
|
|
/*++ UpdateStatusBar
|
|
|
|
Routine Description:
|
|
|
|
Draws the status bar with test based on data accumulated by all of
|
|
the various pages (basically a summary of most important info)
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Revision History:
|
|
|
|
Nov-29-95 Davepl Created
|
|
|
|
--*/
|
|
|
|
void UpdateStatusBar()
|
|
{
|
|
//
|
|
// If we're in menu-tracking mode (sticking help text in the stat
|
|
// bar), we don't draw our standard text
|
|
//
|
|
|
|
if (FALSE == g_fMenuTracking)
|
|
{
|
|
WCHAR szText[MAX_PATH];
|
|
|
|
StringCchPrintf(szText, ARRAYSIZE(szText), g_szfmtProcs, g_cProcesses);
|
|
SendMessage(g_hStatusWnd, SB_SETTEXT, 0, (LPARAM) szText);
|
|
|
|
StringCchPrintf(szText, ARRAYSIZE(szText), g_szfmtCPU, g_CPUUsage);
|
|
SendMessage(g_hStatusWnd, SB_SETTEXT, 1, (LPARAM) szText);
|
|
|
|
//
|
|
// If more than 900 megs are in the machine switch to M mode.
|
|
//
|
|
|
|
if ( g_MEMMax > 900 * 1024 )
|
|
{
|
|
StringCchPrintf(szText, ARRAYSIZE(szText), g_szfmtMEMM, g_MEMUsage / 1024, g_MEMMax / 1024);
|
|
}
|
|
else
|
|
{
|
|
StringCchPrintf(szText, ARRAYSIZE(szText), g_szfmtMEMK, g_MEMUsage, g_MEMMax);
|
|
}
|
|
|
|
SendMessage(g_hStatusWnd, SB_SETTEXT, 2, (LPARAM) szText);
|
|
}
|
|
}
|
|
|
|
/*++ MainWnd_OnTimer
|
|
|
|
Routine Description:
|
|
|
|
Called when the refresh timer fires, we pass a timer event on to
|
|
each of the child pages.
|
|
|
|
Arguments:
|
|
|
|
hwnd - window timer was received at
|
|
id - id of timer that was received
|
|
|
|
Return Value:
|
|
|
|
Revision History:
|
|
|
|
Nov-30-95 Davepl Created
|
|
|
|
--*/
|
|
|
|
void MainWnd_OnTimer(HWND hwnd)
|
|
{
|
|
static const cchTipTextSize = (2 * SHORTSTRLEN);
|
|
|
|
if (GetForegroundWindow() == hwnd && GetKeyState(VK_CONTROL) < 0)
|
|
{
|
|
// CTRL alone means pause
|
|
|
|
return;
|
|
}
|
|
|
|
// Notify each of the pages in turn that they need to updatre
|
|
|
|
for (int i = 0; i < g_nPageCount; i++)
|
|
{
|
|
g_pPages[i]->TimerEvent();
|
|
}
|
|
|
|
// Update the tray icon
|
|
|
|
UINT iIconIndex = (g_CPUUsage * g_cTrayIcons) / 100;
|
|
if (iIconIndex >= g_cTrayIcons)
|
|
{
|
|
iIconIndex = g_cTrayIcons - 1; // Handle 100% case
|
|
}
|
|
|
|
|
|
LPWSTR pszTipText = (LPWSTR) HeapAlloc( GetProcessHeap( ), 0, cchTipTextSize * sizeof(WCHAR) );
|
|
if ( NULL != pszTipText )
|
|
{
|
|
// UI only - don't care if it gets truncated
|
|
StringCchPrintf( pszTipText, cchTipTextSize, g_szfmtCPU, g_CPUUsage );
|
|
}
|
|
|
|
BOOL b = PostThreadMessage( g_idTrayThread, PM_NOTIFYWAITING, iIconIndex, (LPARAM) pszTipText );
|
|
if ( !b )
|
|
{
|
|
HeapFree( GetProcessHeap( ), 0, pszTipText );
|
|
}
|
|
|
|
UpdateStatusBar();
|
|
}
|
|
|
|
/*++ MainWnd_OnInitDialog
|
|
|
|
Routine Description:
|
|
|
|
Processes WM_INITDIALOG for the main window (a modeless dialog)
|
|
|
|
Revision History:
|
|
|
|
Nov-29-95 Davepl Created
|
|
|
|
--*/
|
|
|
|
BOOL MainWnd_OnInitDialog(HWND hwnd)
|
|
{
|
|
RECT rcMain;
|
|
GetWindowRect(hwnd, &rcMain);
|
|
|
|
g_minWidth = rcMain.right - rcMain.left;
|
|
g_minHeight = rcMain.bottom - rcMain.top;
|
|
|
|
g_DefSpacing = (DEFSPACING_BASE * LOWORD(GetDialogBaseUnits())) / DLG_SCALE_X;
|
|
g_InnerSpacing = (INNERSPACING_BASE * LOWORD(GetDialogBaseUnits())) / DLG_SCALE_X;
|
|
g_TopSpacing = (TOPSPACING_BASE * HIWORD(GetDialogBaseUnits())) / DLG_SCALE_Y;
|
|
|
|
g_ControlWidthSpacing = (CONTROL_WIDTH_SPACING * LOWORD(GetDialogBaseUnits())) / DLG_SCALE_X;
|
|
g_ControlHeightSpacing = (CONTROL_HEIGHT_SPACING * HIWORD(GetDialogBaseUnits())) / DLG_SCALE_Y;
|
|
|
|
// Load the user's defaults
|
|
|
|
g_Options.Load();
|
|
|
|
//
|
|
// On init, save away the window handle for all to see
|
|
//
|
|
|
|
g_hMainWnd = hwnd;
|
|
g_hMainDesktop = GetThreadDesktop(GetCurrentThreadId());
|
|
|
|
// init some globals
|
|
|
|
g_cxEdge = GetSystemMetrics(SM_CXEDGE);
|
|
g_hrgnView = CreateRectRgn(0, 0, 0, 0);
|
|
g_hrgnClip = CreateRectRgn(0, 0, 0, 0);
|
|
g_hbrWindow = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
|
|
|
|
// If we're supposed to be TOPMOST, start out that way
|
|
|
|
if (g_Options.m_fAlwaysOnTop)
|
|
{
|
|
SetWindowPos(hwnd, HWND_TOPMOST, 0,0,0,0, SWP_NOMOVE | SWP_NOSIZE);
|
|
}
|
|
|
|
//
|
|
// Create the status window
|
|
//
|
|
|
|
g_hStatusWnd = CreateStatusWindow(WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE | SBARS_SIZEGRIP,
|
|
NULL,
|
|
hwnd,
|
|
IDC_STATUSWND);
|
|
if (NULL == g_hStatusWnd)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Base the panes in the status bar off of the LOGPIXELSX system metric
|
|
//
|
|
|
|
HDC hdc = GetDC(NULL);
|
|
INT nInch = GetDeviceCaps(hdc, LOGPIXELSX);
|
|
ReleaseDC(NULL, hdc);
|
|
|
|
int ciParts[] = { nInch,
|
|
ciParts[0] + (nInch * 5) / 4,
|
|
ciParts[1] + (nInch * 5) / 2,
|
|
-1};
|
|
|
|
if (g_hStatusWnd)
|
|
{
|
|
SendMessage(g_hStatusWnd, SB_SETPARTS, ARRAYSIZE(ciParts), (LPARAM)ciParts);
|
|
}
|
|
|
|
//
|
|
// Load our app icon
|
|
//
|
|
|
|
HICON hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_MAIN));
|
|
if (hIcon)
|
|
{
|
|
SendMessage(hwnd, WM_SETICON, TRUE, LPARAM(hIcon));
|
|
}
|
|
|
|
//
|
|
// Add the tray icons using the tray thread.
|
|
//
|
|
|
|
PostThreadMessage( g_idTrayThread, PM_INITIALIZEICONS, 0, 0 );
|
|
|
|
//
|
|
// Turn on TOPMOST for the status bar so it doesn't slide under the
|
|
// tab control
|
|
//
|
|
|
|
SetWindowPos(g_hStatusWnd,
|
|
HWND_TOPMOST,
|
|
0,0,0,0,
|
|
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREDRAW);
|
|
|
|
//
|
|
// Intialize each of the the pages in turn
|
|
//
|
|
|
|
HWND hwndTabs = GetDlgItem(hwnd, IDC_TABS);
|
|
|
|
for (int i = 0; i < g_nPageCount; i++)
|
|
{
|
|
HRESULT hr;
|
|
|
|
hr = g_pPages[i]->Initialize(hwndTabs);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//
|
|
// Get the title of the new page, and use it as the title of
|
|
// the page which we insert into the tab control
|
|
//
|
|
|
|
WCHAR szTitle[MAX_PATH];
|
|
|
|
g_pPages[i]->GetTitle(szTitle, ARRAYSIZE(szTitle));
|
|
|
|
TC_ITEM tcitem =
|
|
{
|
|
TCIF_TEXT, // value specifying which members to retrieve or set
|
|
NULL, // reserved; do not use
|
|
NULL, // reserved; do not use
|
|
szTitle, // pointer to string containing tab text
|
|
ARRAYSIZE(szTitle), // size of buffer pointed to by the pszText member
|
|
0, // index to tab control's image
|
|
NULL // application-defined data associated with tab
|
|
};
|
|
|
|
//
|
|
// If the item doesn't get inserted, no harm - no foul. He just sits out
|
|
// this game.
|
|
//
|
|
TabCtrl_InsertItem(hwndTabs, i, &tcitem);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Bail! All the tabs must at least initialize.
|
|
//
|
|
TerminateProcess( GetCurrentProcess(), 0 );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Set the inital menu states
|
|
//
|
|
|
|
UpdateMenuStates();
|
|
|
|
//
|
|
// Activate a page (pick page 0 if no preference is set)
|
|
//
|
|
|
|
if (g_Options.m_iCurrentPage < 0 || g_Options.m_iCurrentPage >= g_nPageCount )
|
|
{
|
|
g_Options.m_iCurrentPage = 0;
|
|
}
|
|
|
|
TabCtrl_SetCurSel(GetDlgItem(g_hMainWnd, IDC_TABS), g_Options.m_iCurrentPage);
|
|
|
|
g_pPages[g_Options.m_iCurrentPage]->Activate();
|
|
|
|
RECT rcMainClient;
|
|
GetClientRect(hwnd, &rcMainClient);
|
|
MainWnd_OnSize(g_hMainWnd, 0, rcMainClient.right - rcMainClient.left, rcMainClient.bottom - rcMainClient.top);
|
|
|
|
//
|
|
// Create the update timer
|
|
//
|
|
|
|
if (g_Options.m_dwTimerInterval) // 0 == paused
|
|
{
|
|
SetTimer(g_hMainWnd, 0, g_Options.m_dwTimerInterval, NULL);
|
|
}
|
|
|
|
// Force at least one intial update so that we don't need to wait
|
|
// for the first timed update to come through
|
|
|
|
MainWnd_OnTimer(g_hMainWnd);
|
|
|
|
//
|
|
// Disable the MP-specific menu items
|
|
//
|
|
|
|
if (g_cProcessors <= 1)
|
|
{
|
|
HMENU hMenu = GetMenu(g_hMainWnd);
|
|
EnableMenuItem(hMenu, IDM_MULTIGRAPH, MF_BYCOMMAND | MF_GRAYED);
|
|
}
|
|
|
|
return TRUE; // have the system set the default focus.
|
|
}
|
|
|
|
//
|
|
// Draw an edge just below menu bar
|
|
//
|
|
void MainWnd_Draw(HWND hwnd, HDC hdc)
|
|
{
|
|
RECT rc;
|
|
GetClientRect(hwnd, &rc);
|
|
DrawEdge(hdc, &rc, EDGE_ETCHED, BF_TOP);
|
|
}
|
|
|
|
void MainWnd_OnPrintClient(HWND hwnd, HDC hdc)
|
|
{
|
|
MainWnd_Draw(hwnd, hdc);
|
|
}
|
|
|
|
/*++ MainWnd_OnPaint
|
|
|
|
Routine Description:
|
|
|
|
Just draws a thin edge just below the main menu bar
|
|
|
|
Arguments:
|
|
|
|
hwnd - Main window
|
|
|
|
Return Value:
|
|
|
|
Revision History:
|
|
|
|
Nov-29-95 Davepl Created
|
|
|
|
--*/
|
|
|
|
void MainWnd_OnPaint(HWND hwnd)
|
|
{
|
|
PAINTSTRUCT ps;
|
|
|
|
//
|
|
// Don't waste our time if we're minimized
|
|
//
|
|
|
|
if (FALSE == IsIconic(hwnd))
|
|
{
|
|
BeginPaint(hwnd, &ps);
|
|
MainWnd_Draw(hwnd, ps.hdc);
|
|
EndPaint(hwnd, &ps);
|
|
}
|
|
else
|
|
{
|
|
FORWARD_WM_PAINT(hwnd, DefWindowProc);
|
|
}
|
|
}
|
|
|
|
|
|
/*++ MainWnd_OnMenuSelect
|
|
|
|
Routine Description:
|
|
|
|
As the user browses menus in the app, writes help text to the
|
|
status bar. Also temporarily sets it to be a plain status bar
|
|
with no panes
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Revision History:
|
|
|
|
Nov-29-95 Davepl Created
|
|
|
|
--*/
|
|
|
|
void MainWnd_OnMenuSelect(HWND /*hwnd*/, HMENU hmenu, int item, HMENU /*hmenuPopup*/, UINT flags)
|
|
{
|
|
//
|
|
// If menu is dismissed, restore the panes in the status bar, turn off the
|
|
// global "menu tracking" flag, and redraw the status bar with normal info
|
|
//
|
|
|
|
if ((0xFFFF == LOWORD(flags) && NULL == hmenu) || // dismissed the menu
|
|
(flags & (MF_SYSMENU | MF_SEPARATOR))) // sysmenu or separator
|
|
{
|
|
SendMessage(g_hStatusWnd, SB_SIMPLE, FALSE, 0L); // Restore sb panes
|
|
g_fMenuTracking = FALSE;
|
|
g_fCantHide = FALSE;
|
|
UpdateStatusBar();
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If its a popup, go get the submenu item that is selected instead
|
|
//
|
|
|
|
if (flags & MF_POPUP)
|
|
{
|
|
MENUITEMINFO miiSubMenu;
|
|
|
|
miiSubMenu.cbSize = sizeof(MENUITEMINFO);
|
|
miiSubMenu.fMask = MIIM_ID;
|
|
miiSubMenu.cch = 0;
|
|
|
|
if (FALSE == GetMenuItemInfo(hmenu, item, TRUE, &miiSubMenu))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Change the parameters to simulate a "normal" menu item
|
|
//
|
|
|
|
item = miiSubMenu.wID;
|
|
flags &= ~MF_POPUP;
|
|
}
|
|
|
|
//
|
|
// Our menus always have the same IDs as the strings that describe
|
|
// their functions...
|
|
//
|
|
|
|
WCHAR szStatusText[MAX_PATH];
|
|
LoadString(g_hInstance, item, szStatusText, ARRAYSIZE(szStatusText));
|
|
|
|
g_fMenuTracking = TRUE;
|
|
|
|
SendMessage(g_hStatusWnd, SB_SETTEXT, SBT_NOBORDERS | 255, (LPARAM)szStatusText);
|
|
SendMessage(g_hStatusWnd, SB_SIMPLE, TRUE, 0L); // Remove sb panes
|
|
SendMessage(g_hStatusWnd, SB_SETTEXT, SBT_NOBORDERS | 0, (LPARAM) szStatusText);
|
|
}
|
|
}
|
|
|
|
/*++ MainWnd_OnTabCtrlNotify
|
|
|
|
Routine Description:
|
|
|
|
Handles WM_NOTIFY messages sent to the main window on behalf of the
|
|
tab control
|
|
|
|
Arguments:
|
|
|
|
pnmhdr - ptr to the notification block's header
|
|
|
|
Return Value:
|
|
|
|
BOOL - depends on message
|
|
|
|
Revision History:
|
|
|
|
Nov-29-95 Davepl Created
|
|
|
|
--*/
|
|
|
|
BOOL MainWnd_OnTabCtrlNotify(LPNMHDR pnmhdr)
|
|
{
|
|
HWND hwndTab = pnmhdr->hwndFrom;
|
|
|
|
//
|
|
// Selection is changing (new page coming to the front), so activate
|
|
// the appropriate page
|
|
//
|
|
|
|
if (TCN_SELCHANGE == pnmhdr->code)
|
|
{
|
|
INT iTab = TabCtrl_GetCurSel(hwndTab);
|
|
|
|
if (-1 != iTab)
|
|
{
|
|
if (-1 != g_Options.m_iCurrentPage)
|
|
{
|
|
g_pPages[g_Options.m_iCurrentPage]->Deactivate();
|
|
}
|
|
|
|
if (FAILED(g_pPages[iTab]->Activate()))
|
|
{
|
|
// If we weren't able to activate the new page,
|
|
// reactivate the old page just to be sure
|
|
|
|
if (-1 != g_Options.m_iCurrentPage)
|
|
{
|
|
g_pPages[iTab]->Activate();
|
|
SizeChildPage(g_hMainWnd);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
g_Options.m_iCurrentPage = iTab;
|
|
SizeChildPage(g_hMainWnd);
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/*++ MainWnd_OnSize
|
|
|
|
Routine Description:
|
|
|
|
Sizes the children of the main window as the size of the main
|
|
window itself changes
|
|
|
|
Arguments:
|
|
|
|
hwnd - main window
|
|
state - window state (not used here)
|
|
cx - new x size
|
|
cy - new y size
|
|
|
|
Return Value:
|
|
|
|
BOOL - depends on message
|
|
|
|
Revision History:
|
|
|
|
Nov-29-95 Davepl Created
|
|
|
|
--*/
|
|
|
|
void MainWnd_OnSize(HWND hwnd, UINT state, int cx, int cy)
|
|
{
|
|
if (state == SIZE_MINIMIZED)
|
|
{
|
|
// If there's a tray, we can just hide since we have a
|
|
// tray icon anyway.
|
|
|
|
if (GetShellWindow() && g_Options.m_fHideWhenMin)
|
|
{
|
|
ShowWindow(hwnd, SW_HIDE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Let the status bar adjust itself first, and we will work back
|
|
// from its new position
|
|
//
|
|
|
|
HDWP hdwp = BeginDeferWindowPos(20);
|
|
|
|
FORWARD_WM_SIZE(g_hStatusWnd, state, cx, cy, SendMessage);
|
|
|
|
if (hdwp)
|
|
{
|
|
RECT rcStatus;
|
|
GetClientRect(g_hStatusWnd, &rcStatus);
|
|
MapWindowPoints(g_hStatusWnd, g_hMainWnd, (LPPOINT) &rcStatus, 2);
|
|
|
|
//
|
|
// Size the tab controls based on where the status bar is
|
|
//
|
|
|
|
HWND hwndTabs = GetDlgItem(hwnd, IDC_TABS);
|
|
RECT rcTabs;
|
|
GetWindowRect(hwndTabs, &rcTabs);
|
|
MapWindowPoints(HWND_DESKTOP, g_hMainWnd, (LPPOINT) &rcTabs, 2);
|
|
|
|
INT dx = cx - 2 * rcTabs.left;
|
|
|
|
DeferWindowPos(hdwp, hwndTabs, NULL, 0, 0,
|
|
dx,
|
|
cy - (cy - rcStatus.top) - rcTabs.top * 2,
|
|
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
|
|
|
|
EndDeferWindowPos(hdwp);
|
|
}
|
|
|
|
//
|
|
// Now size the front page and its children
|
|
//
|
|
|
|
if (cx || cy) // Don't size in minimized case
|
|
SizeChildPage(hwnd);
|
|
}
|
|
|
|
/*++ RunDlg
|
|
|
|
Routine Description:
|
|
|
|
Loads shell32.dll and invokes its Run dialog
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
Revision History:
|
|
|
|
Nov-30-95 Davepl Created
|
|
|
|
--*/
|
|
void RunDlg()
|
|
{
|
|
//
|
|
// Put up the RUN dialog for the user
|
|
//
|
|
|
|
HICON hIcon = (HICON) LoadImage(g_hInstance, MAKEINTRESOURCE(IDI_MAIN), IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR | LR_DEFAULTSIZE);
|
|
if (hIcon)
|
|
{
|
|
WCHAR szCurDir[MAX_PATH];
|
|
WCHAR szTitle [MAX_PATH];
|
|
WCHAR szPrompt[MAX_PATH];
|
|
|
|
LoadStringW(g_hInstance, IDS_RUNTITLE, szTitle, MAX_PATH);
|
|
LoadStringW(g_hInstance, IDS_RUNTEXT, szPrompt, MAX_PATH);
|
|
GetCurrentDirectoryW(MAX_PATH, szCurDir);
|
|
|
|
RunFileDlg(g_hMainWnd, hIcon, (LPTSTR) szCurDir,
|
|
(LPTSTR) szTitle,
|
|
(LPTSTR) szPrompt, RFD_USEFULLPATHDIR | RFD_WOW_APP);
|
|
|
|
DestroyIcon(hIcon);
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// DeterminePowerCapabilities
|
|
//
|
|
// Arguments: pfHasHibernate = Has hibernate capability.
|
|
// pfHasSleep = Has sleep capability.
|
|
// pfHasPowerOff = Has power off capability.
|
|
//
|
|
// Returns: <none>
|
|
//
|
|
// Purpose: Returns whether power capabilities are present. Specify NULL
|
|
// for power capabilities not required.
|
|
//
|
|
// History: 2000-02-29 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
void DeterminePowerCapabilities (BOOL *pfHasHibernate, BOOL *pfHasSleep, BOOL *pfHasPowerOff)
|
|
|
|
{
|
|
static BOOL s_fHasHibernate = FALSE;
|
|
static BOOL s_fHasSleep = FALSE;
|
|
static BOOL s_fHasPowerOff = FALSE;
|
|
|
|
SYSTEM_POWER_CAPABILITIES spc;
|
|
NTSTATUS status;
|
|
|
|
CPrivilegeEnable privilege(SE_SHUTDOWN_NAME);
|
|
|
|
status = NtPowerInformation( SystemPowerCapabilities, NULL, 0, &spc, sizeof(spc));
|
|
if ( NOERROR == status )
|
|
{
|
|
if (pfHasHibernate != NULL)
|
|
{
|
|
*pfHasHibernate = spc.SystemS4 && spc.HiberFilePresent;
|
|
}
|
|
if (pfHasSleep != NULL)
|
|
{
|
|
*pfHasSleep = spc.SystemS1 || spc.SystemS2 || spc.SystemS3;
|
|
}
|
|
if (pfHasPowerOff != NULL)
|
|
{
|
|
*pfHasPowerOff = spc.SystemS5;
|
|
}
|
|
}
|
|
//
|
|
// otherwize leave out parameters in their "caller initialize" state.
|
|
//
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// LoadEjectFunction
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: <none>
|
|
//
|
|
// Purpose: Loads cfgmgr32 and gets the address of CM_Request_Eject_PC.
|
|
// It does NOT free the library intentionally.
|
|
//
|
|
// History: 2000-04-03 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
void LoadEjectFunction (void)
|
|
|
|
{
|
|
static BOOL s_fAttempted = FALSE;
|
|
|
|
if ((gpfnCM_Request_Eject_PC == NULL) && (s_fAttempted == FALSE))
|
|
{
|
|
s_fAttempted = TRUE;
|
|
|
|
HMODULE hModule = LoadLibrary(L"cfgmgr32");
|
|
if (hModule != NULL)
|
|
{
|
|
gpfnCM_Request_Eject_PC = reinterpret_cast<PFNCM_REQUEST_EJECT_PC>(GetProcAddress(hModule, "CM_Request_Eject_PC"));
|
|
}
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// AdjustMenuBar
|
|
//
|
|
// Arguments: hMenu = Handle to the main menu.
|
|
//
|
|
// Returns: <none>
|
|
//
|
|
// Purpose: Removes the shutdown menu in the case of classic GINA logon.
|
|
//
|
|
// History: 2000-02-29 vtan created (split AdjustShutdownMenu)
|
|
// 2000-04-24 vtan split RemoveShutdownMenu
|
|
// --------------------------------------------------------------------------
|
|
|
|
void AdjustMenuBar (HMENU hMenu)
|
|
|
|
{
|
|
if( !IsOS(OS_FRIENDLYLOGONUI))
|
|
{
|
|
//
|
|
// Classic GINA UI - Find the "shutdown" menu and remove it.
|
|
//
|
|
|
|
MENUITEMINFO mii;
|
|
|
|
ZeroMemory(&mii, sizeof(mii));
|
|
mii.cbSize = sizeof(mii);
|
|
mii.fMask = MIIM_ID;
|
|
|
|
int iMenuItemCount = GetMenuItemCount(hMenu);
|
|
for ( int i = 0; i < iMenuItemCount; i++ )
|
|
{
|
|
if ( GetMenuItemInfo(hMenu, i, TRUE, &mii) != FALSE
|
|
&& IDM_MENU_SHUTDOWN == mii.wID
|
|
)
|
|
{
|
|
RemoveMenu(hMenu, i, MF_BYPOSITION);
|
|
return; // done
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// AdjustShutdownMenu
|
|
//
|
|
// Arguments: hMenu = Handle to the main menu.
|
|
//
|
|
// Returns: <none>
|
|
//
|
|
// Purpose: Dynamically replaces the entire contents of the "Shut Down"
|
|
// popup menu and adjusts the enabled items based on user token
|
|
// privileges as well as machine capabilities. This is done
|
|
// dynamically to allow console disconnect and remoting to be
|
|
// correctly reflected in the state without restarting taskmgr.
|
|
//
|
|
// History: 2000-02-29 vtan created
|
|
// 2000-03-29 vtan reworked for new menu
|
|
// --------------------------------------------------------------------------
|
|
|
|
void AdjustShutdownMenu (HMENU hMenu)
|
|
|
|
// Adjusts the shutdown menu in the menu bar to reflect the machine
|
|
// capabilities and user privileges. Items that aren't accessible
|
|
// are disabled or removed. The menu contains the following:
|
|
|
|
// MENUITEM "Stand &By" IDM_STANDBY SE_SHUTDOWN_PRIVILEGE && S1-S3 !NoClose
|
|
// MENUITEM "&Hibernate" IDM_HIBERNATE SE_SHUTDOWN_PRIVILEGE && S4 !NoClose
|
|
// MENUITEM "Sh&ut Down" IDM_SHUTDOWN SE_SHUTDOWN_PRIVILEGE !NoClose
|
|
// MENUITEM "&Restart" IDM_RESTART SE_SHUTDOWN_PRIVILEGE !NoClose
|
|
// MENUITEM "&Log Off <user>" IDM_LOGOFF_CURRENTUSER <everyone> !NoClose && !NoLogoff
|
|
// MENUITEM "&Switch User" IDM_SWITCHUSER <everyone> !Remote && !NoDisconnect
|
|
// MENUITEM "&Disconnect" IDM_DISCONNECT_CURRENTUSER <everyone> Remote && !NoDisconnect
|
|
// MENUITEM "&Eject Computer" IDM_EJECT SE_UNDOCK_PRIVILEGE
|
|
// MENUITEM "Loc&k Computer" IDM_LOCKWORKSTATION <everyone> !DisableLockWorkstation
|
|
|
|
{
|
|
int i, iMenuItemCount;
|
|
BOOL fFound;
|
|
MENUITEMINFO mii;
|
|
|
|
//
|
|
// First find the "Shut Down" menu item in the given menu bar.
|
|
//
|
|
|
|
ZeroMemory(&mii, sizeof(mii));
|
|
mii.cbSize = sizeof(mii);
|
|
|
|
iMenuItemCount = GetMenuItemCount(hMenu);
|
|
for (fFound = FALSE, i = 0; !fFound && (i < iMenuItemCount); ++i)
|
|
{
|
|
mii.fMask = MIIM_ID;
|
|
if ( GetMenuItemInfo(hMenu, i, TRUE, &mii) != FALSE
|
|
&& IDM_MENU_SHUTDOWN == mii.wID
|
|
)
|
|
{
|
|
fFound = TRUE;
|
|
|
|
//
|
|
// Once found get the submenu currently in place for it.
|
|
//
|
|
|
|
mii.fMask = MIIM_SUBMENU;
|
|
if (GetMenuItemInfo(hMenu, i, TRUE, &mii) != FALSE)
|
|
{
|
|
//
|
|
// If one exists then remove it.
|
|
//
|
|
|
|
if (mii.hSubMenu != NULL)
|
|
{
|
|
DestroyMenu(mii.hSubMenu);
|
|
}
|
|
|
|
//
|
|
// Now replace it with the freshly loaded menu.
|
|
//
|
|
|
|
mii.hSubMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(IDR_POPUP_SHUTDOWN));
|
|
if ( NULL != mii.hSubMenu )
|
|
{
|
|
BOOL b = SetMenuItemInfo(hMenu, i, TRUE, &mii);
|
|
if ( !b )
|
|
{
|
|
b = DestroyMenu( mii.hSubMenu );
|
|
// what happens if this fails?
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now adjust the options based on privilege and availability if the
|
|
// menu was replaced with a fresh menu. Otherwise this menu has been
|
|
// removed because the machine is in classic GINA mode.
|
|
|
|
if (fFound)
|
|
{
|
|
BOOL fHasHibernate, fHasSleep, fHasShutdownPrivilege, fIsRemote, fIsDocked,
|
|
fPolicyDisableLockWorkstation, fPolicyNoLogoff, fPolicyNoClose, fPolicyNoDisconnect;
|
|
WCHAR szMenuString[256];
|
|
|
|
// Friendly UI is active - adjust shutdown menu enabled/disabled items.
|
|
// This can be more efficient but for making the logic clear and easy to
|
|
// understand it is multiple tests.
|
|
|
|
fHasHibernate = FALSE;
|
|
fHasSleep = FALSE;
|
|
|
|
DeterminePowerCapabilities(&fHasHibernate, &fHasSleep, NULL);
|
|
LoadEjectFunction();
|
|
|
|
fHasShutdownPrivilege = (SHTestTokenPrivilege(NULL, SE_SHUTDOWN_NAME) != FALSE);
|
|
fIsRemote = GetSystemMetrics(SM_REMOTESESSION);
|
|
fIsDocked = (SHGetMachineInfo(GMI_DOCKSTATE) == GMID_DOCKED);
|
|
|
|
//
|
|
// System/Explorer policies to be respected.
|
|
//
|
|
|
|
fPolicyDisableLockWorkstation = fPolicyNoLogoff = fPolicyNoClose = fPolicyNoDisconnect = FALSE;
|
|
{
|
|
HKEY hKey;
|
|
DWORD dwValue, dwValueSize;
|
|
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\system"),
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&hKey))
|
|
{
|
|
dwValueSize = sizeof(dwValue);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hKey,
|
|
TEXT("DisableLockWorkstation"),
|
|
NULL,
|
|
NULL,
|
|
reinterpret_cast<LPBYTE>(&dwValue),
|
|
&dwValueSize))
|
|
{
|
|
fPolicyDisableLockWorkstation = (dwValue != 0);
|
|
}
|
|
RegCloseKey(hKey);
|
|
}
|
|
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER,
|
|
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer"),
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&hKey))
|
|
{
|
|
dwValueSize = sizeof(dwValue);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hKey,
|
|
TEXT("DisableLockWorkstation"),
|
|
NULL,
|
|
NULL,
|
|
reinterpret_cast<LPBYTE>(&dwValue),
|
|
&dwValueSize))
|
|
{
|
|
fPolicyDisableLockWorkstation = fPolicyDisableLockWorkstation || (dwValue != 0);
|
|
}
|
|
dwValueSize = sizeof(dwValue);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hKey,
|
|
TEXT("NoLogoff"),
|
|
NULL,
|
|
NULL,
|
|
reinterpret_cast<LPBYTE>(&dwValue),
|
|
&dwValueSize))
|
|
{
|
|
fPolicyNoLogoff = (dwValue != 0);
|
|
}
|
|
dwValueSize = sizeof(dwValue);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hKey,
|
|
TEXT("NoClose"),
|
|
NULL,
|
|
NULL,
|
|
reinterpret_cast<LPBYTE>(&dwValue),
|
|
&dwValueSize))
|
|
{
|
|
fPolicyNoClose = (dwValue != 0);
|
|
}
|
|
dwValueSize = sizeof(dwValue);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hKey,
|
|
TEXT("NoDisconnect"),
|
|
NULL,
|
|
NULL,
|
|
reinterpret_cast<LPBYTE>(&dwValue),
|
|
&dwValueSize))
|
|
{
|
|
fPolicyNoDisconnect = (dwValue != 0);
|
|
}
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
|
|
// IDM_STANDBY
|
|
|
|
if (!fHasShutdownPrivilege || !fHasSleep || fIsRemote || fPolicyNoClose)
|
|
{
|
|
EnableMenuItem(hMenu, IDM_STANDBY, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
|
|
}
|
|
|
|
// IDM_HIBERNATE
|
|
|
|
if (!fHasShutdownPrivilege || !fHasHibernate || fIsRemote || fPolicyNoClose)
|
|
{
|
|
EnableMenuItem(hMenu, IDM_HIBERNATE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
|
|
}
|
|
|
|
// IDM_SHUTDOWN
|
|
|
|
if (!fHasShutdownPrivilege || fPolicyNoClose)
|
|
{
|
|
EnableMenuItem(hMenu, IDM_SHUTDOWN, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
|
|
}
|
|
|
|
// IDM_RESTART
|
|
|
|
if (!fHasShutdownPrivilege || fPolicyNoClose)
|
|
{
|
|
EnableMenuItem(hMenu, IDM_RESTART, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
|
|
}
|
|
|
|
// IDM_LOGOFF_CURRENTUSER
|
|
|
|
// This expects "Log Off %s and End Session". It will fill in the
|
|
// %s with the display name. If no display name is present then it
|
|
// will use the login name. If the string insertions fail for some
|
|
// reason then it will remove the "%s" by searching for it and
|
|
// copying the rest of the string over it.
|
|
|
|
mii.fMask = MIIM_TYPE;
|
|
mii.dwTypeData = szMenuString;
|
|
mii.cch = ARRAYSIZE(szMenuString);
|
|
if (GetMenuItemInfo(hMenu, IDM_LOGOFF_CURRENTUSER, MF_BYCOMMAND ,&mii) != FALSE)
|
|
{
|
|
WCHAR szDisplayName[UNLEN + 1];
|
|
WCHAR szTemp[256 + UNLEN + 1];
|
|
|
|
*szDisplayName = TEXT('\0');
|
|
|
|
ULONG cchLen = ARRAYSIZE(szDisplayName);
|
|
SHGetUserDisplayName(szDisplayName, &cchLen); // Ignore errors.
|
|
|
|
HRESULT hr = StringCchPrintf(szTemp, ARRAYSIZE(szTemp), szMenuString, szDisplayName);
|
|
if (SUCCEEDED( hr ))
|
|
{
|
|
StringCchCopy( szMenuString, ARRAYSIZE(szMenuString), szTemp );
|
|
}
|
|
else
|
|
{
|
|
WCHAR *pszSubString;
|
|
|
|
pszSubString = StrStrI(szMenuString, TEXT("%s "));
|
|
if (pszSubString != NULL)
|
|
{
|
|
*pszSubString = L'\0'; // terminate
|
|
StringCchCopy( szTemp, ARRAYSIZE(szTemp), szMenuString );
|
|
StringCchCat( szTemp, ARRAYSIZE(szTemp), pszSubString + 3 );
|
|
}
|
|
}
|
|
|
|
SetMenuItemInfo(hMenu, IDM_LOGOFF_CURRENTUSER, MF_BYCOMMAND, &mii);
|
|
}
|
|
|
|
if ((SHRestricted(REST_STARTMENULOGOFF) == 1) || fPolicyNoClose || fPolicyNoLogoff)
|
|
{
|
|
EnableMenuItem(hMenu, IDM_LOGOFF_CURRENTUSER, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
|
|
}
|
|
|
|
// IDM_SWITCHUSER
|
|
if (fIsRemote || !IsOS(OS_FASTUSERSWITCHING) || fPolicyNoDisconnect)
|
|
{
|
|
DeleteMenu(hMenu, IDM_SWITCHUSER, MF_BYCOMMAND);
|
|
}
|
|
|
|
// IDM_DISCONNECT_CURRENTUSER
|
|
|
|
if (!fIsRemote || !IsOS(OS_FASTUSERSWITCHING) || fPolicyNoDisconnect)
|
|
{
|
|
DeleteMenu(hMenu, IDM_DISCONNECT_CURRENTUSER, MF_BYCOMMAND);
|
|
}
|
|
|
|
// IDM_EJECT
|
|
|
|
if (!fIsDocked || (SHTestTokenPrivilege(NULL, SE_UNDOCK_NAME) == FALSE) || (gpfnCM_Request_Eject_PC == NULL))
|
|
{
|
|
DeleteMenu(hMenu, IDM_EJECT, MF_BYCOMMAND);
|
|
}
|
|
|
|
// IDM_LOCKWORKSTATION
|
|
|
|
if (fIsRemote || IsOS(OS_FASTUSERSWITCHING) || fPolicyDisableLockWorkstation)
|
|
{
|
|
DeleteMenu(hMenu, IDM_LOCKWORKSTATION, MF_BYCOMMAND);
|
|
}
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// PowerActionThreadProc
|
|
//
|
|
// Arguments: pv = POWER_ACTION to invoke
|
|
//
|
|
// Returns: DWORD
|
|
//
|
|
// Purpose: Invokes NtInitiatePowerAction on a different thread so that
|
|
// the UI thread is not blocked.
|
|
//
|
|
// History: 2000-04-05 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
DWORD WINAPI PowerActionThreadProc (void* pv)
|
|
|
|
{
|
|
POWER_ACTION pa = (POWER_ACTION)PtrToInt(pv);
|
|
|
|
CPrivilegeEnable privilege(SE_SHUTDOWN_NAME);
|
|
|
|
NTSTATUS status = NtInitiatePowerAction(pa,
|
|
PowerSystemSleeping1,
|
|
POWER_ACTION_QUERY_ALLOWED | POWER_ACTION_UI_ALLOWED,
|
|
FALSE);
|
|
|
|
return NT_SUCCESS(status);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CreatePowerActionThread
|
|
//
|
|
// Arguments: paPowerAction = POWER_ACTION to invoke.
|
|
//
|
|
// Returns: <none>
|
|
//
|
|
// Purpose: Creates the thread that invokes NtInitiatePowerAction on a
|
|
// different thread. If thread creation fails then do the code
|
|
// inline. It can't be invoked because the memory allocation
|
|
// could fail so the code is copied.
|
|
//
|
|
// History: 2000-04-05 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
void CreatePowerActionThread (POWER_ACTION paPowerAction)
|
|
{
|
|
DWORD dwThreadID;
|
|
|
|
HANDLE hThread = CreateThread(NULL,
|
|
0,
|
|
PowerActionThreadProc,
|
|
(void*)paPowerAction,
|
|
0,
|
|
&dwThreadID);
|
|
if (hThread != NULL)
|
|
{
|
|
CloseHandle(hThread);
|
|
}
|
|
else
|
|
{
|
|
CPrivilegeEnable privilege(SE_SHUTDOWN_NAME);
|
|
|
|
NtInitiatePowerAction(paPowerAction,
|
|
PowerSystemSleeping1,
|
|
POWER_ACTION_QUERY_ALLOWED | POWER_ACTION_UI_ALLOWED,
|
|
FALSE
|
|
);
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// ExitWindowsThreadProc
|
|
//
|
|
// Arguments: pv = uiFlags
|
|
//
|
|
// Returns: DWORD
|
|
//
|
|
// Purpose: Invokes ExitWindowsEx on a different thread so that
|
|
// the UI thread is not blocked.
|
|
//
|
|
// History: 2000-04-05 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
DWORD WINAPI ExitWindowsThreadProc (void *pv)
|
|
{
|
|
UINT uiFlags = PtrToUint(pv);
|
|
|
|
CPrivilegeEnable privilege(SE_SHUTDOWN_NAME);
|
|
|
|
BOOL bRet = ExitWindowsEx(uiFlags, 0);
|
|
|
|
return (DWORD)bRet;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// CreateExitWindowsThread
|
|
//
|
|
// Arguments: uiFlags = EWX_ flag to pass to ExitWindowsEx.
|
|
//
|
|
// Returns: <none>
|
|
//
|
|
// Purpose: Creates the thread that invokes ExitWindowsEx on a
|
|
// different thread. If thread creation fails then do the code
|
|
// inline. It can't be invoked because the memory allocation
|
|
// could fail so the code is copied.
|
|
//
|
|
// History: 2000-04-05 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
void CreateExitWindowsThread (UINT uiFlags)
|
|
{
|
|
DWORD dwThreadID;
|
|
HANDLE hThread;
|
|
|
|
hThread = CreateThread(NULL,
|
|
0,
|
|
ExitWindowsThreadProc,
|
|
UintToPtr(uiFlags),
|
|
0,
|
|
&dwThreadID);
|
|
if (hThread != NULL)
|
|
{
|
|
CloseHandle(hThread);
|
|
}
|
|
else
|
|
{
|
|
CPrivilegeEnable privilege(SE_SHUTDOWN_NAME);
|
|
|
|
ExitWindowsEx(uiFlags, 0);
|
|
}
|
|
}
|
|
|
|
// --------------------------------------------------------------------------
|
|
// ExecuteShutdownMenuOption
|
|
//
|
|
// Arguments: hwnd = Parent HWND if a dialog is required.
|
|
// iID = ID of menu item to execute.
|
|
//
|
|
// Returns: <none>
|
|
//
|
|
// Purpose: Executes the given shut down menu option doing the right
|
|
// thing if prompting is required.
|
|
//
|
|
// History: 2000-03-29 vtan created
|
|
// --------------------------------------------------------------------------
|
|
|
|
void ExecuteShutdownMenuOption(int iID)
|
|
{
|
|
switch (iID)
|
|
{
|
|
case IDM_STANDBY:
|
|
CreatePowerActionThread(PowerActionSleep);
|
|
break;
|
|
|
|
case IDM_HIBERNATE:
|
|
CreatePowerActionThread(PowerActionHibernate);
|
|
break;
|
|
|
|
case IDM_SHUTDOWN:
|
|
{
|
|
BOOL fControlKey = (GetAsyncKeyState(VK_CONTROL) < 0);
|
|
if (fControlKey)
|
|
{
|
|
CPrivilegeEnable privilege(SE_SHUTDOWN_NAME);
|
|
|
|
NtShutdownSystem(ShutdownPowerOff);
|
|
}
|
|
else
|
|
{
|
|
BOOL fHasPowerOff = FALSE;
|
|
UINT uiFlags;
|
|
|
|
DeterminePowerCapabilities(NULL, NULL, &fHasPowerOff);
|
|
if (fHasPowerOff != FALSE)
|
|
{
|
|
uiFlags = EWX_POWEROFF;
|
|
}
|
|
else
|
|
{
|
|
uiFlags = EWX_SHUTDOWN;
|
|
}
|
|
CreateExitWindowsThread(uiFlags);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDM_RESTART:
|
|
{
|
|
BOOL fControlKey = (GetAsyncKeyState(VK_CONTROL) < 0);
|
|
if (fControlKey)
|
|
{
|
|
CPrivilegeEnable privilege(SE_SHUTDOWN_NAME);
|
|
|
|
NtShutdownSystem(ShutdownReboot);
|
|
}
|
|
else
|
|
{
|
|
CreateExitWindowsThread(EWX_REBOOT);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDM_LOGOFF_CURRENTUSER:
|
|
ExitWindowsEx(EWX_LOGOFF, 0);
|
|
break;
|
|
|
|
case IDM_SWITCHUSER:
|
|
case IDM_DISCONNECT_CURRENTUSER:
|
|
ShellSwitchUser(FALSE);
|
|
break;
|
|
|
|
case IDM_EJECT:
|
|
gpfnCM_Request_Eject_PC();
|
|
break;
|
|
|
|
case IDM_LOCKWORKSTATION:
|
|
LockWorkStation();
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*++ MainWnd_OnCommand
|
|
|
|
Routine Description:
|
|
|
|
Processes WM_COMMAND messages received at the main window
|
|
|
|
Revision History:
|
|
|
|
Nov-30-95 Davepl Created
|
|
|
|
--*/
|
|
|
|
void MainWnd_OnCommand(HWND hwnd, int id)
|
|
{
|
|
switch (id)
|
|
{
|
|
case IDM_HIDE:
|
|
ShowWindow(hwnd, SW_MINIMIZE);
|
|
break;
|
|
|
|
case IDM_HELP:
|
|
HtmlHelpA(GetDesktopWindow(), "taskmgr.chm", HH_DISPLAY_TOPIC, 0);
|
|
break;
|
|
|
|
case IDCANCEL:
|
|
case IDM_EXIT:
|
|
DestroyWindow(hwnd);
|
|
break;
|
|
|
|
case IDM_RESTORETASKMAN:
|
|
ShowRunningInstance();
|
|
break;
|
|
|
|
//
|
|
// these guys need to get forwarded to the page for handling
|
|
//
|
|
|
|
case IDC_SWITCHTO:
|
|
case IDC_BRINGTOFRONT:
|
|
case IDC_ENDTASK:
|
|
switch (g_Options.m_iCurrentPage)
|
|
{
|
|
case PROC_PAGE:
|
|
{
|
|
// procpage only deals with ENDTASK, but will ignore the others
|
|
CProcPage * pPage = ((CProcPage *) (g_pPages[PROC_PAGE]));
|
|
pPage->HandleWMCOMMAND(LOWORD(id), NULL);
|
|
}
|
|
break;
|
|
|
|
case TASK_PAGE:
|
|
{
|
|
CTaskPage * pPage = ((CTaskPage *) (g_pPages[TASK_PAGE]));
|
|
pPage->HandleWMCOMMAND(id);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case IDC_NEXTTAB:
|
|
case IDC_PREVTAB:
|
|
{
|
|
INT iPage = g_Options.m_iCurrentPage;
|
|
iPage += (id == IDC_NEXTTAB) ? 1 : -1;
|
|
|
|
iPage = iPage < 0 ? g_nPageCount - 1 : iPage;
|
|
iPage = iPage >= g_nPageCount ? 0 : iPage;
|
|
|
|
// Activate the new page. If it fails, revert to the current
|
|
|
|
TabCtrl_SetCurSel(GetDlgItem(g_hMainWnd, IDC_TABS), iPage);
|
|
|
|
// SetCurSel doesn't do the page change (that would make too much
|
|
// sense), so we have to fake up a TCN_SELCHANGE notification
|
|
|
|
NMHDR nmhdr;
|
|
nmhdr.hwndFrom = GetDlgItem(g_hMainWnd, IDC_TABS);
|
|
nmhdr.idFrom = IDC_TABS;
|
|
nmhdr.code = TCN_SELCHANGE;
|
|
|
|
if (MainWnd_OnTabCtrlNotify(&nmhdr))
|
|
{
|
|
g_Options.m_iCurrentPage = iPage;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDM_ALWAYSONTOP:
|
|
g_Options.m_fAlwaysOnTop = !g_Options.m_fAlwaysOnTop;
|
|
SetWindowPos(hwnd, g_Options.m_fAlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
|
|
0,0,0,0, SWP_NOMOVE | SWP_NOSIZE);
|
|
UpdateMenuStates();
|
|
break;
|
|
|
|
case IDM_HIDEWHENMIN:
|
|
g_Options.m_fHideWhenMin = !g_Options.m_fHideWhenMin;
|
|
UpdateMenuStates();
|
|
break;
|
|
|
|
case IDM_MINIMIZEONUSE:
|
|
g_Options.m_fMinimizeOnUse = !g_Options.m_fMinimizeOnUse;
|
|
UpdateMenuStates();
|
|
break;
|
|
|
|
case IDM_NOTITLE:
|
|
g_Options.m_fNoTitle = !g_Options.m_fNoTitle;
|
|
UpdateMenuStates();
|
|
SizeChildPage(hwnd);
|
|
break;
|
|
|
|
case IDM_SHOW16BIT:
|
|
g_Options.m_fShow16Bit = !g_Options.m_fShow16Bit;
|
|
UpdateMenuStates();
|
|
if ( PROC_PAGE < g_nPageCount )
|
|
{
|
|
g_pPages[PROC_PAGE]->TimerEvent();
|
|
}
|
|
break;
|
|
|
|
case IDM_SHOWDOMAINNAMES:
|
|
g_Options.m_fShowDomainNames = !g_Options.m_fShowDomainNames;
|
|
UpdateMenuStates();
|
|
if (USER_PAGE < g_nPageCount )
|
|
{
|
|
g_pPages[USER_PAGE]->TimerEvent();
|
|
}
|
|
break;
|
|
|
|
case IDM_HIBERNATE:
|
|
case IDM_SHUTDOWN:
|
|
case IDM_STANDBY:
|
|
case IDM_RESTART:
|
|
case IDM_LOGOFF_CURRENTUSER:
|
|
case IDM_SWITCHUSER:
|
|
case IDM_DISCONNECT_CURRENTUSER:
|
|
case IDM_EJECT:
|
|
case IDM_LOCKWORKSTATION:
|
|
ExecuteShutdownMenuOption(id);
|
|
break;
|
|
|
|
case IDM_KERNELTIMES:
|
|
g_Options.m_fKernelTimes = !g_Options.m_fKernelTimes;
|
|
UpdateMenuStates();
|
|
if (PERF_PAGE < g_nPageCount)
|
|
{
|
|
g_pPages[PERF_PAGE]->TimerEvent();
|
|
}
|
|
break;
|
|
|
|
case IDM_RUN:
|
|
if (GetKeyState(VK_CONTROL) >= 0)
|
|
{
|
|
RunDlg();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Holding down the CONTROL key and click the RUN menu will
|
|
// invoke a CMD prompt. This helps work around low memory situations
|
|
// where trying to load the extra GUI stuff from SHELL32 is too
|
|
// heavy weight.
|
|
//
|
|
|
|
STARTUPINFO startupInfo = { 0 };
|
|
PROCESS_INFORMATION processInformation = { 0 };
|
|
WCHAR szCommandLine[MAX_PATH];
|
|
|
|
startupInfo.cb = sizeof(startupInfo);
|
|
startupInfo.dwFlags = STARTF_USESHOWWINDOW;
|
|
startupInfo.wShowWindow = SW_SHOWNORMAL;
|
|
if (ExpandEnvironmentStrings(TEXT("\"%ComSpec%\""), szCommandLine, ARRAYSIZE(szCommandLine)) == 0)
|
|
{
|
|
if (ExpandEnvironmentStrings(TEXT("\"%windir%\\system32\\cmd.exe\""), szCommandLine, ARRAYSIZE(szCommandLine)) == 0)
|
|
{
|
|
StringCchCopy( szCommandLine, ARRAYSIZE(szCommandLine), TEXT("\"cmd.exe\"") );
|
|
}
|
|
}
|
|
|
|
if (CreateProcess(NULL,
|
|
szCommandLine,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_PROCESS_GROUP,
|
|
NULL,
|
|
NULL,
|
|
&startupInfo,
|
|
&processInformation) != FALSE)
|
|
{
|
|
CloseHandle(processInformation.hThread);
|
|
CloseHandle(processInformation.hProcess);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IDM_SMALLICONS:
|
|
case IDM_DETAILS:
|
|
case IDM_LARGEICONS:
|
|
g_Options.m_vmViewMode = (VIEWMODE) (id - VM_FIRST);
|
|
UpdateMenuStates();
|
|
if (TASK_PAGE < g_nPageCount)
|
|
{
|
|
g_pPages[TASK_PAGE]->TimerEvent();
|
|
}
|
|
break;
|
|
|
|
//
|
|
// The following few messages get deferred off to the task page
|
|
//
|
|
|
|
case IDM_TASK_CASCADE:
|
|
case IDM_TASK_MINIMIZE:
|
|
case IDM_TASK_MAXIMIZE:
|
|
case IDM_TASK_TILEHORZ:
|
|
case IDM_TASK_TILEVERT:
|
|
case IDM_TASK_BRINGTOFRONT:
|
|
SendMessage(g_pPages[TASK_PAGE]->GetPageWindow(), WM_COMMAND, id, NULL);
|
|
break;
|
|
|
|
case IDM_PROCCOLS:
|
|
if (PROC_PAGE < g_nPageCount)
|
|
{
|
|
((CProcPage *) (g_pPages[PROC_PAGE]))->PickColumns();
|
|
}
|
|
break;
|
|
|
|
case IDM_NETCOL:
|
|
if (NET_PAGE < g_nPageCount)
|
|
{
|
|
((CNetPage *) (g_pPages[NET_PAGE]))->PickColumns();
|
|
}
|
|
break;
|
|
|
|
case IDM_USERCOLS:
|
|
if (USER_PAGE < g_nPageCount)
|
|
{
|
|
SendMessage(g_pPages[USER_PAGE]->GetPageWindow(), WM_COMMAND, id, NULL);
|
|
}
|
|
break;
|
|
|
|
case IDM_ALLCPUS:
|
|
case IDM_MULTIGRAPH:
|
|
g_Options.m_cmHistMode = (CPUHISTMODE) (id - CM_FIRST);
|
|
UpdateMenuStates();
|
|
if (PERF_PAGE < g_nPageCount)
|
|
{
|
|
((CPerfPage *)(g_pPages[PERF_PAGE]))->UpdateGraphs();
|
|
g_pPages[PERF_PAGE]->TimerEvent();
|
|
}
|
|
break;
|
|
|
|
case IDM_REFRESH:
|
|
if (NET_PAGE < g_nPageCount && g_Options.m_iCurrentPage == NET_PAGE)
|
|
{
|
|
((CNetPage *)(g_pPages[NET_PAGE]))->Refresh();
|
|
}
|
|
MainWnd_OnTimer(hwnd);
|
|
break;
|
|
|
|
case IDM_SHOWALLDATA:
|
|
g_Options.m_bNetShowAll = !g_Options.m_bNetShowAll;
|
|
UpdateMenuStates();
|
|
break;
|
|
|
|
case IDM_TABALWAYSACTIVE:
|
|
g_Options.m_bTabAlwaysActive = !g_Options.m_bTabAlwaysActive;
|
|
UpdateMenuStates();
|
|
break;
|
|
|
|
case IDM_BYTESSENT:
|
|
g_Options.m_bGraphBytesSent = !g_Options.m_bGraphBytesSent;
|
|
UpdateMenuStates();
|
|
MainWnd_OnTimer(hwnd);
|
|
break;
|
|
|
|
case IDM_NETRESET:
|
|
if ( NET_PAGE < g_nPageCount)
|
|
{
|
|
((CNetPage *)(g_pPages[NET_PAGE]))->Reset();
|
|
MainWnd_OnTimer(hwnd);
|
|
}
|
|
break;
|
|
|
|
case IDM_SHOWSCALE:
|
|
g_Options.m_bShowScale = !g_Options.m_bShowScale;
|
|
UpdateMenuStates();
|
|
if ( NET_PAGE < g_nPageCount )
|
|
{
|
|
((CNetPage *)(g_pPages[NET_PAGE]))->SizeNetPage();
|
|
}
|
|
break;
|
|
|
|
case IDM_AUTOSIZE:
|
|
g_Options.m_bAutoSize = !g_Options.m_bAutoSize;
|
|
UpdateMenuStates();
|
|
break;
|
|
|
|
case IDM_BYTESRECEIVED:
|
|
g_Options.m_bGraphBytesReceived = !g_Options.m_bGraphBytesReceived;
|
|
UpdateMenuStates();
|
|
break;
|
|
|
|
case IDM_BYTESTOTAL:
|
|
g_Options.m_bGraphBytesTotal = !g_Options.m_bGraphBytesTotal;
|
|
UpdateMenuStates();
|
|
break;
|
|
|
|
case IDM_HIGH:
|
|
case IDM_NORMAL:
|
|
case IDM_LOW:
|
|
case IDM_PAUSED:
|
|
{
|
|
static const int TimerDelays[] = { 500, 2000, 4000, 0, 0xFFFFFFFF };
|
|
|
|
g_Options.m_usUpdateSpeed = (UPDATESPEED) (id - US_FIRST);
|
|
ASSERT(g_Options.m_usUpdateSpeed <= ARRAYSIZE(TimerDelays));
|
|
|
|
int cTicks = TimerDelays[ (INT) g_Options.m_usUpdateSpeed ];
|
|
g_Options.m_dwTimerInterval = cTicks;
|
|
|
|
KillTimer(g_hMainWnd, 0);
|
|
if (cTicks)
|
|
{
|
|
SetTimer(g_hMainWnd, 0, g_Options.m_dwTimerInterval, NULL);
|
|
}
|
|
|
|
UpdateMenuStates();
|
|
}
|
|
break;
|
|
|
|
case IDM_ABOUT:
|
|
{
|
|
//
|
|
// Display the "About Task Manager" dialog
|
|
//
|
|
|
|
HICON hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_MAIN));
|
|
if (hIcon)
|
|
{
|
|
WCHAR szTitle[MAX_PATH];
|
|
LoadString(g_hInstance, IDS_APPTITLE, szTitle, MAX_PATH);
|
|
ShellAbout(hwnd, szTitle, NULL, hIcon);
|
|
DestroyIcon(hIcon);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*++ CheckParentDeferrals
|
|
|
|
Routine Description:
|
|
|
|
Called by the child pages, each child gives the main parent the
|
|
opportunity to handle certain messages on its behalf
|
|
|
|
Arguments:
|
|
|
|
MSG, WPARAM, LPARAM
|
|
|
|
Return Value:
|
|
|
|
TRUE if parent handle the message on the childs behalf
|
|
|
|
Revision History:
|
|
|
|
Jan-24-95 Davepl Created
|
|
|
|
--*/
|
|
|
|
BOOL CheckParentDeferrals(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch(uMsg)
|
|
{
|
|
case WM_RBUTTONDOWN:
|
|
case WM_NCRBUTTONDOWN:
|
|
case WM_RBUTTONUP:
|
|
case WM_NCRBUTTONUP:
|
|
case WM_NCLBUTTONDBLCLK:
|
|
case WM_LBUTTONDBLCLK:
|
|
{
|
|
SendMessage(g_hMainWnd, uMsg, wParam, lParam);
|
|
return TRUE;
|
|
}
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/*++ ShowRunningInstance
|
|
|
|
Routine Description:
|
|
|
|
Brings this running instance to the top, and out of icon state
|
|
|
|
Revision History:
|
|
|
|
Jan-27-95 Davepl Created
|
|
|
|
--*/
|
|
|
|
void ShowRunningInstance()
|
|
{
|
|
OpenIcon(g_hMainWnd);
|
|
SetForegroundWindow(g_hMainWnd);
|
|
SetWindowPos(g_hMainWnd, g_Options.m_fAlwaysOnTop ? HWND_TOPMOST : HWND_TOP,
|
|
0,0,0,0, SWP_NOMOVE | SWP_NOSIZE);
|
|
}
|
|
|
|
/*++ MainWindowProc
|
|
|
|
Routine Description:
|
|
|
|
Initializes the gloab setting variables. Everytime the settings change this function is called.
|
|
|
|
Arguments:
|
|
|
|
void
|
|
|
|
Return Value:
|
|
|
|
Revision History:
|
|
|
|
created April 23, 2001 omiller
|
|
|
|
--*/
|
|
void OnSettingsChange()
|
|
{
|
|
WCHAR wszGroupSep[8];
|
|
|
|
GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIME, g_szTimeSep, ARRAYSIZE(g_szTimeSep));
|
|
GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, g_szGroupThousSep, ARRAYSIZE(g_szGroupThousSep));
|
|
GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL , g_szDecimal, ARRAYSIZE(g_szDecimal));
|
|
GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, wszGroupSep, ARRAYSIZE(wszGroupSep));
|
|
g_ulGroupSep = wcstol(wszGroupSep,NULL,10);
|
|
|
|
}
|
|
|
|
/*++ MainWindowProc
|
|
|
|
Routine Description:
|
|
|
|
WNDPROC for the main window
|
|
|
|
Arguments:
|
|
|
|
Standard wndproc fare
|
|
|
|
Return Value:
|
|
|
|
Revision History:
|
|
|
|
Nov-30-95 Davepl Created
|
|
|
|
--*/
|
|
|
|
INT_PTR CALLBACK MainWindowProc(
|
|
HWND hwnd, // handle to dialog box
|
|
UINT uMsg, // message
|
|
WPARAM wParam, // first message parameter
|
|
LPARAM lParam // second message parameter
|
|
)
|
|
{
|
|
static BOOL fIsHidden = FALSE;
|
|
|
|
//
|
|
// If this is a size or a move, update the position in the user's options
|
|
//
|
|
|
|
if (uMsg == WM_SIZE || uMsg == WM_MOVE)
|
|
{
|
|
// We don't want to start recording the window pos until we've had
|
|
// a chance to set it to the intialial position, or we'll lose the
|
|
// user's preferences
|
|
|
|
if (fAlreadySetPos)
|
|
{
|
|
if (!IsIconic(hwnd) && !IsZoomed(hwnd))
|
|
{
|
|
GetWindowRect(hwnd, &g_Options.m_rcWindow);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (uMsg == g_msgTaskbarCreated)
|
|
{
|
|
// This is done async do taskmgr doesn't hand when the shell
|
|
// is hung
|
|
|
|
PostThreadMessage( g_idTrayThread, PM_NOTIFYWAITING, 0, 0 );
|
|
}
|
|
|
|
|
|
switch(uMsg)
|
|
{
|
|
case WM_PAINT:
|
|
MainWnd_OnPaint(hwnd);
|
|
return TRUE;
|
|
|
|
case WM_INITDIALOG:
|
|
return MainWnd_OnInitDialog( hwnd );
|
|
|
|
HANDLE_MSG(hwnd, WM_MENUSELECT, MainWnd_OnMenuSelect);
|
|
HANDLE_MSG(hwnd, WM_SIZE, MainWnd_OnSize);
|
|
|
|
case WM_COMMAND:
|
|
MainWnd_OnCommand( hwnd, LOWORD(wParam) );
|
|
break;
|
|
|
|
case WM_TIMER:
|
|
MainWnd_OnTimer( hwnd );
|
|
break;
|
|
|
|
case WM_PRINTCLIENT:
|
|
MainWnd_OnPrintClient(hwnd, (HDC)wParam);
|
|
break;
|
|
|
|
// Don't let the window get too small when the title and
|
|
// menu bars are ON
|
|
|
|
case WM_GETMINMAXINFO:
|
|
if (FALSE == g_Options.m_fNoTitle)
|
|
{
|
|
LPMINMAXINFO lpmmi = (LPMINMAXINFO) lParam;
|
|
lpmmi->ptMinTrackSize.x = g_minWidth;
|
|
lpmmi->ptMinTrackSize.y = g_minHeight;
|
|
return FALSE;
|
|
}
|
|
break;
|
|
|
|
// Handle notifications from out tray icon
|
|
|
|
case PWM_TRAYICON:
|
|
Tray_Notify(hwnd, lParam);
|
|
break;
|
|
|
|
// Someone externally is asking us to wake up and be shown
|
|
case PWM_ACTIVATE:
|
|
ShowRunningInstance();
|
|
|
|
// Return PWM_ACTIVATE to the caller as just a little
|
|
// more assurance that we really did handle this
|
|
// message correctly.
|
|
|
|
SetWindowLongPtr(hwnd, DWLP_MSGRESULT, PWM_ACTIVATE);
|
|
return TRUE;
|
|
|
|
case WM_INITMENU:
|
|
AdjustShutdownMenu(reinterpret_cast<HMENU>(wParam));
|
|
|
|
// Don't let the right button hide the window during
|
|
// menu operations
|
|
|
|
g_fCantHide = TRUE;
|
|
break;
|
|
|
|
case WM_NCHITTEST:
|
|
// If we have no title/menu bar, clicking and dragging the client
|
|
// area moves the window. To do this, return HTCAPTION.
|
|
// Note dragging not allowed if window maximized, or if caption
|
|
// bar is present.
|
|
//
|
|
|
|
wParam = DefWindowProc(hwnd, uMsg, wParam, lParam);
|
|
if (g_Options.m_fNoTitle && (wParam == HTCLIENT) && !IsZoomed(g_hMainWnd))
|
|
{
|
|
SetWindowLongPtr(hwnd, DWLP_MSGRESULT, HTCAPTION);
|
|
return TRUE;
|
|
}
|
|
return FALSE; // Not handled
|
|
|
|
case WM_NCLBUTTONDBLCLK:
|
|
// If we have no title, an NC dbl click means we should turn
|
|
// them back on
|
|
|
|
if (FALSE == g_Options.m_fNoTitle)
|
|
{
|
|
break;
|
|
}
|
|
// Else, fall though
|
|
|
|
case WM_LBUTTONDBLCLK:
|
|
{
|
|
g_Options.m_fNoTitle = ~g_Options.m_fNoTitle;
|
|
|
|
RECT rcMainWnd;
|
|
GetWindowRect(g_hMainWnd, &rcMainWnd);
|
|
|
|
if ( PERF_PAGE < g_nPageCount )
|
|
{
|
|
((CPerfPage *)(g_pPages[PERF_PAGE]))->UpdateGraphs();
|
|
g_pPages[PERF_PAGE]->TimerEvent();
|
|
}
|
|
|
|
if ( NET_PAGE < g_nPageCount )
|
|
{
|
|
((CNetPage *)(g_pPages[NET_PAGE]))->UpdateGraphs();
|
|
g_pPages[NET_PAGE]->TimerEvent();
|
|
}
|
|
|
|
// Force a WM_SIZE event so that the window checks the min size
|
|
// when coming out of notitle mode
|
|
|
|
MoveWindow(g_hMainWnd,
|
|
rcMainWnd.left,
|
|
rcMainWnd.top,
|
|
rcMainWnd.right - rcMainWnd.left,
|
|
rcMainWnd.bottom - rcMainWnd.top,
|
|
TRUE);
|
|
|
|
SizeChildPage(hwnd);
|
|
}
|
|
break;
|
|
|
|
// Someone (the task page) wants us to look up a process in the
|
|
// process view. Switch to that page and send it the FINDPROC
|
|
// message
|
|
|
|
case WM_FINDPROC:
|
|
if (-1 != TabCtrl_SetCurSel(GetDlgItem(hwnd, IDC_TABS), PROC_PAGE))
|
|
{
|
|
// SetCurSel doesn't do the page change (that would make too much
|
|
// sense), so we have to fake up a TCN_SELCHANGE notification
|
|
|
|
NMHDR nmhdr;
|
|
nmhdr.hwndFrom = GetDlgItem(hwnd, IDC_TABS);
|
|
nmhdr.idFrom = IDC_TABS;
|
|
nmhdr.code = TCN_SELCHANGE;
|
|
|
|
if (MainWnd_OnTabCtrlNotify(&nmhdr))
|
|
{
|
|
if ( g_Options.m_iCurrentPage != -1 )
|
|
{
|
|
SendMessage( g_pPages[g_Options.m_iCurrentPage]->GetPageWindow(), WM_FINDPROC, wParam, lParam );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MessageBeep(0);
|
|
}
|
|
break;
|
|
|
|
case WM_NOTIFY:
|
|
if ( IDC_TABS == wParam)
|
|
{
|
|
return MainWnd_OnTabCtrlNotify((LPNMHDR) lParam);
|
|
}
|
|
break;
|
|
|
|
case WM_ENDSESSION:
|
|
if (wParam)
|
|
{
|
|
DestroyWindow(g_hMainWnd);
|
|
}
|
|
break;
|
|
|
|
case WM_CLOSE:
|
|
DestroyWindow(g_hMainWnd);
|
|
break;
|
|
|
|
case WM_NCDESTROY:
|
|
// If there's a tray thread, tell is to exit
|
|
|
|
if (g_idTrayThread)
|
|
{
|
|
PostThreadMessage(g_idTrayThread, PM_QUITTRAYTHREAD, 0, 0);
|
|
}
|
|
|
|
// Wait around for some period of time for the tray thread to
|
|
// do its cleanup work. If the wait times out, worst case we
|
|
// orphan the tray icon.
|
|
|
|
if (g_hTrayThread)
|
|
{
|
|
WaitForSingleObject(g_hTrayThread, 3000);
|
|
CloseHandle(g_hTrayThread);
|
|
}
|
|
break;
|
|
|
|
case WM_SYSCOLORCHANGE:
|
|
case WM_SETTINGCHANGE:
|
|
{
|
|
// Initialzie the global variables, i.e. comma, decimal time etc
|
|
//
|
|
OnSettingsChange();
|
|
|
|
// pass these to the status bar
|
|
SendMessage(g_hStatusWnd, uMsg, wParam, lParam);
|
|
|
|
// also pass along to the pages
|
|
for (int i = 0; i < g_nPageCount; i++)
|
|
{
|
|
SendMessage(g_pPages[i]->GetPageWindow(), uMsg, wParam, lParam);
|
|
}
|
|
|
|
if (uMsg == WM_SETTINGCHANGE)
|
|
{
|
|
// force a resizing of the main dialog
|
|
RECT rcMainClient;
|
|
GetClientRect(g_hMainWnd, &rcMainClient);
|
|
MainWnd_OnSize(g_hMainWnd, 0, rcMainClient.right - rcMainClient.left, rcMainClient.bottom - rcMainClient.top);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
{
|
|
// Before shutting down, deactivate the current page, then
|
|
// destroy all pages
|
|
|
|
if ( g_Options.m_iCurrentPage >= 0 && g_Options.m_iCurrentPage < g_nPageCount )
|
|
{
|
|
g_pPages[g_Options.m_iCurrentPage]->Deactivate();
|
|
}
|
|
|
|
for (int i = 0; i < g_nPageCount; i++)
|
|
{
|
|
g_pPages[i]->Destroy();
|
|
}
|
|
|
|
// Save the current options
|
|
|
|
g_Options.Save();
|
|
|
|
PostQuitMessage(0);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*++ LoadGlobalResources
|
|
|
|
Routine Description:
|
|
|
|
Loads those resources that are used frequently or that are expensive to
|
|
load a single time at program startup
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN success value
|
|
|
|
Revision History:
|
|
|
|
Nov-30-95 Davepl Created
|
|
|
|
--*/
|
|
|
|
static const struct
|
|
{
|
|
LPTSTR psz;
|
|
DWORD len;
|
|
UINT id;
|
|
}
|
|
g_aStrings[] =
|
|
{
|
|
{ g_szG, ARRAYSIZE(g_szG), IDS_G },
|
|
{ g_szM, ARRAYSIZE(g_szM), IDS_M },
|
|
{ g_szK, ARRAYSIZE(g_szK), IDS_K },
|
|
{ g_szBitsPerSec, ARRAYSIZE(g_szBitsPerSec), IDS_BITSPERSEC },
|
|
{ g_szPercent, ARRAYSIZE(g_szPercent), IDS_PERCENT },
|
|
{ g_szRealtime, ARRAYSIZE(g_szRealtime), IDS_REALTIME },
|
|
{ g_szNormal, ARRAYSIZE(g_szNormal), IDS_NORMAL },
|
|
{ g_szLow, ARRAYSIZE(g_szLow), IDS_LOW },
|
|
{ g_szHigh, ARRAYSIZE(g_szHigh), IDS_HIGH },
|
|
{ g_szUnknown, ARRAYSIZE(g_szUnknown), IDS_UNKNOWN },
|
|
{ g_szAboveNormal,ARRAYSIZE(g_szAboveNormal),IDS_ABOVENORMAL},
|
|
{ g_szBelowNormal,ARRAYSIZE(g_szBelowNormal),IDS_BELOWNORMAL},
|
|
{ g_szRunning, ARRAYSIZE(g_szRunning), IDS_RUNNING },
|
|
{ g_szHung, ARRAYSIZE(g_szHung), IDS_HUNG },
|
|
{ g_szfmtTasks, ARRAYSIZE(g_szfmtTasks), IDS_FMTTASKS },
|
|
{ g_szfmtProcs, ARRAYSIZE(g_szfmtProcs), IDS_FMTPROCS },
|
|
{ g_szfmtCPU, ARRAYSIZE(g_szfmtCPU), IDS_FMTCPU },
|
|
{ g_szfmtMEMK, ARRAYSIZE(g_szfmtMEMK), IDS_FMTMEMK },
|
|
{ g_szfmtMEMM, ARRAYSIZE(g_szfmtMEMM), IDS_FMTMEMM },
|
|
{ g_szfmtCPUNum, ARRAYSIZE(g_szfmtCPUNum), IDS_FMTCPUNUM },
|
|
{ g_szTotalCPU, ARRAYSIZE(g_szTotalCPU), IDS_TOTALTIME },
|
|
{ g_szKernelCPU, ARRAYSIZE(g_szKernelCPU), IDS_KERNELTIME },
|
|
{ g_szMemUsage, ARRAYSIZE(g_szMemUsage), IDS_MEMUSAGE },
|
|
{ g_szZero, ARRAYSIZE(g_szZero), IDS_ZERO },
|
|
{ g_szScaleFont, ARRAYSIZE(g_szScaleFont), IDS_SCALEFONT },
|
|
{ g_szNonOperational, ARRAYSIZE(g_szNonOperational), IDS_NONOPERATIONAL },
|
|
{ g_szUnreachable, ARRAYSIZE(g_szUnreachable), IDS_UNREACHABLE },
|
|
{ g_szDisconnected, ARRAYSIZE(g_szDisconnected), IDS_DISCONNECTED },
|
|
{ g_szConnecting, ARRAYSIZE(g_szConnecting), IDS_CONNECTING },
|
|
{ g_szConnected, ARRAYSIZE(g_szConnected), IDS_CONNECTED },
|
|
{ g_szOperational, ARRAYSIZE(g_szOperational), IDS_OPERATIONAL },
|
|
{ g_szUnknownStatus, ARRAYSIZE(g_szUnknownStatus), IDS_UNKNOWNSTATUS },
|
|
|
|
};
|
|
|
|
//
|
|
//
|
|
//
|
|
void LoadGlobalResources()
|
|
{
|
|
//
|
|
// If we don't get accelerators, its not worth failing the load
|
|
//
|
|
|
|
g_hAccel = LoadAccelerators(g_hInstance, MAKEINTRESOURCE(IDR_ACCELERATORS));
|
|
Assert(g_hAccel); // Missing resource?
|
|
|
|
for (UINT i = 0; i < g_cTrayIcons; i++)
|
|
{
|
|
g_aTrayIcons[i] = (HICON) LoadImage(g_hInstance,
|
|
MAKEINTRESOURCE(idTrayIcons[i]),
|
|
IMAGE_ICON,
|
|
0, 0,
|
|
LR_DEFAULTCOLOR);
|
|
Assert( NULL != g_aTrayIcons[i] ); // missing resource?
|
|
}
|
|
|
|
for (i = 0; i < ARRAYSIZE(g_aStrings); i++)
|
|
{
|
|
int iRet = LoadString( g_hInstance, g_aStrings[i].id, g_aStrings[i].psz, g_aStrings[i].len );
|
|
Assert( 0 != iRet ); // missing string?
|
|
iRet = 0; // silence the compiler warning - this gets optmized out
|
|
}
|
|
}
|
|
|
|
//
|
|
// IsTerminalServicesEnabled
|
|
//
|
|
void IsTerminalServicesEnabled( LPBOOL pfIsTSEnabled, LPBOOL pfIsSingleUserTS, LPBOOL pfIsTSServer )
|
|
{
|
|
*pfIsTSEnabled = FALSE;
|
|
*pfIsSingleUserTS = FALSE;
|
|
*pfIsTSServer = FALSE;
|
|
|
|
OSVERSIONINFOEX osVersionInfo;
|
|
ZeroMemory(&osVersionInfo, sizeof(OSVERSIONINFOEX));
|
|
osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
|
|
|
if(GetVersionEx((OSVERSIONINFO*)&osVersionInfo))
|
|
{
|
|
if(osVersionInfo.wSuiteMask & (VER_SUITE_TERMINAL | VER_SUITE_SINGLEUSERTS))
|
|
{
|
|
*pfIsTSEnabled = TRUE;
|
|
|
|
if(osVersionInfo.wProductType == VER_NT_SERVER ||
|
|
osVersionInfo.wProductType == VER_NT_DOMAIN_CONTROLLER)
|
|
{
|
|
*pfIsTSServer = TRUE;
|
|
return;
|
|
}
|
|
|
|
if(osVersionInfo.wProductType == VER_NT_WORKSTATION &&
|
|
osVersionInfo.wSuiteMask == VER_SUITE_SINGLEUSERTS)
|
|
{
|
|
HKEY hKey;
|
|
|
|
*pfIsSingleUserTS = TRUE; // single user unless overridden.
|
|
|
|
if (ERROR_SUCCESS == RegOpenKeyEx( HKEY_LOCAL_MACHINE
|
|
, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon")
|
|
, 0
|
|
, KEY_QUERY_VALUE
|
|
, &hKey
|
|
) )
|
|
{
|
|
DWORD dwType;
|
|
DWORD dwValue;
|
|
DWORD dwValueSize = sizeof(dwValue);
|
|
|
|
if ( ERROR_SUCCESS == RegQueryValueEx( hKey
|
|
, TEXT("AllowMultipleTSSessions")
|
|
, NULL
|
|
, &dwType
|
|
, reinterpret_cast<LPBYTE>(&dwValue)
|
|
, &dwValueSize
|
|
)
|
|
&& ( REG_DWORD == dwType )
|
|
&& ( 0 != dwValue )
|
|
)
|
|
{
|
|
*pfIsSingleUserTS = FALSE; // multiple users
|
|
}
|
|
|
|
RegCloseKey(hKey);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determines if the system is low on memory. If the system has less than8 Mbytes of
|
|
memory than the system is low on memory.
|
|
|
|
Arguments:
|
|
|
|
void
|
|
|
|
Return Value:
|
|
|
|
TRUE -- System is low on memory
|
|
FALSE -- System is not low on memory
|
|
|
|
Revision History:
|
|
|
|
1-6-2000 Created by omiller
|
|
|
|
--*/
|
|
|
|
BOOLEAN IsMemoryLow()
|
|
{
|
|
|
|
SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
|
|
SYSTEM_BASIC_INFORMATION Basic;
|
|
ULONG ulPagesPerMeg;
|
|
ULONG ulPageSize;
|
|
NTSTATUS Status;
|
|
BOOLEAN bMemoryLow = TRUE;
|
|
|
|
//
|
|
// Get the page size
|
|
//
|
|
Status = NtQuerySystemInformation( SystemBasicInformation,
|
|
&Basic,
|
|
sizeof(Basic),
|
|
0 );
|
|
if ( SUCCEEDED(Status) )
|
|
{
|
|
ulPagesPerMeg = 1024*1024 / Basic.PageSize;
|
|
ulPageSize = Basic.PageSize;
|
|
|
|
//
|
|
// Determine if we are low on memory
|
|
//
|
|
Status = NtQuerySystemInformation( SystemPerformanceInformation,
|
|
&PerfInfo,
|
|
sizeof(PerfInfo),
|
|
0 );
|
|
|
|
if ( SUCCEEDED(Status) )
|
|
{
|
|
//
|
|
// Compute the number of free megs.
|
|
//
|
|
ULONG ulFreeMeg = (ULONG)((PerfInfo.CommitLimit - PerfInfo.CommittedPages) / ulPagesPerMeg);
|
|
|
|
if ( ulFreeMeg > MIN_MEMORY_REQUIRED )
|
|
{
|
|
//
|
|
// We are not low on memory we have about 8 megs of memory.
|
|
// We could get this value from Reg key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\ContentIndex
|
|
// Value MinWordlistMemory
|
|
//
|
|
bMemoryLow = FALSE;
|
|
}
|
|
}
|
|
}
|
|
return bMemoryLow;
|
|
}
|
|
|
|
/*++ WinMain
|
|
|
|
Routine Description:
|
|
|
|
Windows app startup. Does basic initialization and creates the main window
|
|
|
|
Arguments:
|
|
|
|
Standard winmain
|
|
|
|
Return Value:
|
|
|
|
App exit code
|
|
|
|
Revision History:
|
|
|
|
Nov-30-95 Davepl Created
|
|
|
|
--*/
|
|
int WINAPI WinMainT(
|
|
HINSTANCE hInstance, // handle to current instance
|
|
HINSTANCE /*hPrevInstance*/, // handle to previous instance (n/a)
|
|
LPTSTR /*lpCmdLine*/, // pointer to command line
|
|
int nShowCmd // show state of window
|
|
)
|
|
{
|
|
int retval = TRUE;
|
|
HKEY hKeyPolicy;
|
|
DWORD dwType;
|
|
DWORD dwData = 0;
|
|
DWORD dwSize;
|
|
int cx;
|
|
int cy;
|
|
|
|
g_hInstance = hInstance;
|
|
|
|
g_msgTaskbarCreated = RegisterWindowMessage(TEXT("TaskbarCreated"));
|
|
|
|
// Try to create or grab the startup mutex. Only in the case
|
|
// where everything goes well and the mutex already existed AND
|
|
// we were able to grab it do we deem ourselves to be a secondary instance
|
|
|
|
g_hStartupMutex = CreateMutex(NULL, TRUE, cszStartupMutex);
|
|
if (g_hStartupMutex && GetLastError() == ERROR_ALREADY_EXISTS)
|
|
{
|
|
// Give the other instance (the one that owns the startup mutex) 10
|
|
// seconds to do its thing
|
|
|
|
WaitForSingleObject(g_hStartupMutex, FINDME_TIMEOUT);
|
|
}
|
|
|
|
// Determine if Terminal Services is Enabled and if so,
|
|
// find out on what session we're running.
|
|
|
|
IsTerminalServicesEnabled(&g_fIsTSEnabled, &g_fIsSingleUserTS, &g_fIsTSServer);
|
|
if (g_fIsTSEnabled)
|
|
{
|
|
ProcessIdToSessionId( GetCurrentProcessId(), &g_dwMySessionId );
|
|
}
|
|
|
|
//
|
|
// Locate and activate a running instance if it exists.
|
|
//
|
|
|
|
WCHAR szTitle[MAX_PATH];
|
|
if (LoadString(hInstance, IDS_APPTITLE, szTitle, ARRAYSIZE(szTitle)))
|
|
{
|
|
HWND hwndOld = FindWindow(WC_DIALOG, szTitle);
|
|
if (hwndOld)
|
|
{
|
|
// Send the other copy of ourselves a PWM_ACTIVATE message. If that
|
|
// succeeds, and it returns PWM_ACTIVATE back as the return code, it's
|
|
// up and alive and we can exit this instance.
|
|
|
|
DWORD dwPid = 0;
|
|
GetWindowThreadProcessId(hwndOld, &dwPid);
|
|
AllowSetForegroundWindow(dwPid);
|
|
|
|
ULONG_PTR dwResult;
|
|
if (SendMessageTimeout(hwndOld,
|
|
PWM_ACTIVATE,
|
|
0, 0,
|
|
SMTO_ABORTIFHUNG,
|
|
FINDME_TIMEOUT,
|
|
&dwResult))
|
|
{
|
|
if (dwResult == PWM_ACTIVATE)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (RegOpenKeyEx (HKEY_CURRENT_USER,
|
|
TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System"),
|
|
0, KEY_READ, &hKeyPolicy) == ERROR_SUCCESS)
|
|
{
|
|
dwSize = sizeof(dwData);
|
|
|
|
RegQueryValueEx (hKeyPolicy, TEXT("DisableTaskMgr"), NULL, &dwType, (LPBYTE) &dwData, &dwSize);
|
|
|
|
RegCloseKey (hKeyPolicy);
|
|
|
|
if (dwData)
|
|
{
|
|
WCHAR szTitle[25];
|
|
WCHAR szMessage[200];
|
|
int iRet;
|
|
|
|
iRet = LoadString (hInstance, IDS_TASKMGR, szTitle, ARRAYSIZE(szTitle));
|
|
Assert( 0 != iRet ); // missing string?
|
|
|
|
iRet = LoadString (hInstance, IDS_TASKMGRDISABLED , szMessage, ARRAYSIZE(szMessage));
|
|
Assert( 0 != iRet ); // missing string?
|
|
|
|
MessageBox (NULL, szMessage, szTitle, MB_OK | MB_ICONSTOP);
|
|
retval = FALSE;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
//
|
|
// No running instance found, so we run as normal
|
|
//
|
|
|
|
InitCommonControls();
|
|
|
|
InitDavesControls();
|
|
|
|
// Start the worker thread. If it fails, you just don't
|
|
// get tray icons
|
|
|
|
g_hTrayThread = CreateThread(NULL, 0, TrayThreadMessageLoop, NULL, 0, &g_idTrayThread);
|
|
ASSERT( NULL != g_hTrayThread );
|
|
|
|
//
|
|
// Init the page table
|
|
//
|
|
|
|
g_nPageCount = ARRAYSIZE(g_pPages);
|
|
|
|
g_pPages[0] = new CTaskPage;
|
|
if (NULL == g_pPages[0])
|
|
{
|
|
retval = FALSE;
|
|
goto cleanup;
|
|
}
|
|
|
|
g_pPages[1] = new CProcPage;
|
|
if (NULL == g_pPages[1])
|
|
{
|
|
retval = FALSE;
|
|
goto cleanup;
|
|
}
|
|
|
|
if( !IsMemoryLow() )
|
|
{
|
|
g_pPages[2] = new CPerfPage;
|
|
if (NULL == g_pPages[2])
|
|
{
|
|
retval = FALSE;
|
|
goto cleanup;
|
|
}
|
|
|
|
g_pPages[3] = new CNetPage;
|
|
if (NULL == g_pPages[3])
|
|
{
|
|
retval = FALSE;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (g_fIsTSEnabled && !g_fIsSingleUserTS)
|
|
{
|
|
g_pPages[4] = new CUserPage;
|
|
if (NULL == g_pPages[4])
|
|
{
|
|
retval = FALSE;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
--g_nPageCount; // Decrement count if users pane is disabled
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We are low on memory, only load the first two tabs.
|
|
//
|
|
g_nPageCount = 2;
|
|
}
|
|
|
|
//
|
|
// Load whatever resources that we need available globally
|
|
//
|
|
|
|
LoadGlobalResources();
|
|
|
|
//
|
|
// Initialize the history buffers
|
|
//
|
|
|
|
if (0 == InitPerfInfo())
|
|
{
|
|
retval = FALSE;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (0 == InitNetInfo())
|
|
{
|
|
retval = FALSE;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Create the main window (it's a modeless dialog, to be precise)
|
|
//
|
|
|
|
g_hMainWnd = CreateDialog( hInstance, MAKEINTRESOURCE(IDD_MAINWND), NULL, MainWindowProc );
|
|
if (NULL == g_hMainWnd)
|
|
{
|
|
retval = FALSE;
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// Initialize the gloabl setting variables, Comma, decimal point, group seperation etc
|
|
//
|
|
|
|
OnSettingsChange();
|
|
|
|
fAlreadySetPos = TRUE;
|
|
|
|
cx = g_Options.m_rcWindow.right - g_Options.m_rcWindow.left;
|
|
cy = g_Options.m_rcWindow.bottom - g_Options.m_rcWindow.top;
|
|
|
|
SetWindowPos( g_hMainWnd, NULL, g_Options.m_rcWindow.left, g_Options.m_rcWindow.top, cx, cy, SWP_NOZORDER );
|
|
ShowWindow( g_hMainWnd, nShowCmd );
|
|
|
|
//
|
|
// We're out of the "starting up" phase so release the startup mutex
|
|
//
|
|
|
|
if (NULL != g_hStartupMutex)
|
|
{
|
|
ReleaseMutex(g_hStartupMutex);
|
|
CloseHandle(g_hStartupMutex);
|
|
g_hStartupMutex = NULL;
|
|
}
|
|
|
|
//
|
|
// If we're the one, true, task manager, we can hang around till the
|
|
// bitter end in case the user has problems during shutdown
|
|
//
|
|
|
|
SetProcessShutdownParameters(1, SHUTDOWN_NORETRY);
|
|
|
|
MSG msg;
|
|
while (GetMessage(&msg, NULL, 0, 0))
|
|
{
|
|
if (!TranslateAccelerator(g_hMainWnd, g_hAccel, &msg))
|
|
{
|
|
if (!IsDialogMessage(g_hMainWnd, &msg))
|
|
{
|
|
TranslateMessage(&msg); // Translates virtual key codes
|
|
DispatchMessage(&msg); // Dispatches message to window
|
|
}
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
|
|
//
|
|
// We're no longer "starting up"
|
|
//
|
|
|
|
if (g_hStartupMutex)
|
|
{
|
|
ReleaseMutex(g_hStartupMutex);
|
|
CloseHandle(g_hStartupMutex);
|
|
g_hStartupMutex = NULL;
|
|
}
|
|
|
|
// Yes, I could use virtual destructors, but I could also poke
|
|
// myself in the eye with a sharp stick. Either way you wouldn't
|
|
// be able to see what's going on.
|
|
|
|
if (g_pPages[TASK_PAGE])
|
|
delete (CTaskPage *) g_pPages[TASK_PAGE];
|
|
|
|
if (g_pPages[PROC_PAGE])
|
|
delete (CProcPage *) g_pPages[PROC_PAGE];
|
|
|
|
if (g_pPages[PERF_PAGE])
|
|
delete (CPerfPage *) g_pPages[PERF_PAGE];
|
|
|
|
if (g_pPages[NET_PAGE])
|
|
delete (CNetPage *) g_pPages[NET_PAGE];
|
|
|
|
if (g_pPages[USER_PAGE])
|
|
delete (CUserPage *) g_pPages[USER_PAGE];
|
|
|
|
ReleasePerfInfo();
|
|
|
|
return (retval);
|
|
}
|
|
|
|
//
|
|
// And now the magic begins. The normal C++ CRT code walks a set of vectors
|
|
// and calls through them to perform global initializations. Those vectors
|
|
// are always in data segments with a particular naming scheme. By delcaring
|
|
// the variables below, I can determine where in my code they get stuck, and
|
|
// then call them myself
|
|
//
|
|
|
|
typedef void (__cdecl *_PVFV)(void);
|
|
|
|
// This is all ridiculous.
|
|
#ifdef _M_IA64
|
|
#pragma section(".CRT$XIA",long,read)
|
|
#pragma section(".CRT$XIZ",long,read)
|
|
#pragma section(".CRT$XCA",long,read)
|
|
#pragma section(".CRT$XCZ",long,read)
|
|
#define _CRTALLOC(x) __declspec(allocate(x))
|
|
#else /* _M_IA64 */
|
|
#define _CRTALLOC(x)
|
|
#endif /* _M_IA64 */
|
|
|
|
#pragma data_seg(".CRT$XIA")
|
|
_CRTALLOC(".CRT$XIA") _PVFV __xi_a[] = { NULL };
|
|
|
|
#pragma data_seg(".CRT$XIZ")
|
|
_CRTALLOC(".CRT$XIZ") _PVFV __xi_z[] = { NULL };
|
|
|
|
#pragma data_seg(".CRT$XCA")
|
|
_CRTALLOC(".CRT$XCA") _PVFV __xc_a[] = { NULL };
|
|
|
|
#pragma data_seg(".CRT$XCZ")
|
|
_CRTALLOC(".CRT$XCZ") _PVFV __xc_z[] = { NULL };
|
|
|
|
#pragma data_seg(".data")
|
|
|
|
/*++ _initterm
|
|
|
|
Routine Description:
|
|
|
|
Walk the table of function pointers from the bottom up, until
|
|
the end is encountered. Do not skip the first entry. The initial
|
|
value of pfbegin points to the first valid entry. Do not try to
|
|
execute what pfend points to. Only entries before pfend are valid.
|
|
|
|
Arguments:
|
|
|
|
pfbegin - first pointer
|
|
pfend - last pointer
|
|
|
|
Revision History:
|
|
|
|
Nov-30-95 Davepl Created
|
|
|
|
--*/
|
|
|
|
static void __cdecl _initterm ( _PVFV * pfbegin, _PVFV * pfend )
|
|
{
|
|
while ( pfbegin < pfend )
|
|
{
|
|
|
|
// if current table entry is non-NULL, call thru it.
|
|
|
|
if ( *pfbegin != NULL )
|
|
{
|
|
(**pfbegin)();
|
|
}
|
|
++pfbegin;
|
|
}
|
|
}
|
|
|
|
/*++ WinMain
|
|
|
|
Routine Description:
|
|
|
|
Windows app startup. Does basic initialization and creates the main window
|
|
|
|
Arguments:
|
|
|
|
Standard winmain
|
|
|
|
Return Value:
|
|
|
|
App exit code
|
|
|
|
Revision History:
|
|
|
|
Nov-30-95 Davepl Created
|
|
|
|
--*/
|
|
|
|
void _stdcall ModuleEntry(void)
|
|
{
|
|
int i;
|
|
STARTUPINFO si;
|
|
|
|
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
|
|
|
|
//
|
|
// Do runtime startup initializers.
|
|
//
|
|
|
|
_initterm( __xi_a, __xi_z );
|
|
|
|
//
|
|
// do C++ constructors (initializers) specific to this EXE
|
|
//
|
|
|
|
_initterm( __xc_a, __xc_z );
|
|
|
|
LPTSTR pszCmdLine = GetCommandLine();
|
|
|
|
if ( *pszCmdLine == TEXT('\"') ) {
|
|
/*
|
|
* Scan, and skip over, subsequent characters until
|
|
* another double-quote or a null is encountered.
|
|
*/
|
|
while ( *++pszCmdLine && (*pszCmdLine
|
|
!= TEXT('\"')) );
|
|
/*
|
|
* If we stopped on a double-quote (usual case), skip
|
|
* over it.
|
|
*/
|
|
if ( *pszCmdLine == TEXT('\"') )
|
|
pszCmdLine++;
|
|
}
|
|
else {
|
|
while (*pszCmdLine > TEXT(' '))
|
|
pszCmdLine++;
|
|
}
|
|
|
|
/*
|
|
* Skip past any white space preceeding the second token.
|
|
*/
|
|
while (*pszCmdLine && (*pszCmdLine <= TEXT(' '))) {
|
|
pszCmdLine++;
|
|
}
|
|
|
|
si.dwFlags = 0;
|
|
GetStartupInfo(&si);
|
|
|
|
g_bMirroredOS = IS_MIRRORING_ENABLED();
|
|
|
|
i = WinMainT(GetModuleHandle(NULL), NULL, pszCmdLine,
|
|
si.dwFlags & STARTF_USESHOWWINDOW ? si.wShowWindow : SW_SHOWDEFAULT);
|
|
ExitProcess(i);
|
|
}
|
|
|
|
// DisplayFailureMsg
|
|
//
|
|
// Displays a generic error message based on the error code
|
|
// and message box title provided
|
|
|
|
void DisplayFailureMsg(HWND hWnd, UINT idTitle, DWORD dwError)
|
|
{
|
|
WCHAR szTitle[MAX_PATH];
|
|
WCHAR szMsg[MAX_PATH * 2];
|
|
WCHAR szError[MAX_PATH];
|
|
|
|
if (0 == LoadString(g_hInstance, idTitle, szTitle, ARRAYSIZE(szTitle)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (0 == LoadString(g_hInstance, IDS_GENFAILURE, szMsg, ARRAYSIZE(szMsg)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// "incorrect paramter" doesn't make a lot of sense for the user, so
|
|
// massage it to be "Operation not allowed on this process".
|
|
|
|
if (dwError == ERROR_INVALID_PARAMETER)
|
|
{
|
|
if (0 == LoadString(g_hInstance, IDS_BADPROC, szError, ARRAYSIZE(szError)))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
else if (0 == FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
|
|
NULL,
|
|
dwError,
|
|
LANG_USER_DEFAULT,
|
|
szError,
|
|
ARRAYSIZE(szError),
|
|
NULL))
|
|
{
|
|
return;
|
|
}
|
|
|
|
StringCchCat(szMsg, ARRAYSIZE(szMsg), szError);
|
|
|
|
MessageBox(hWnd, szMsg, szTitle, MB_OK | MB_ICONERROR);
|
|
}
|
|
|
|
/*++ LoadPopupMenu
|
|
|
|
Routine Description:
|
|
|
|
Loads a popup menu from a resource. Needed because USER
|
|
does not support popup menus (yes, really)
|
|
|
|
Arguments:
|
|
|
|
hinst - module instance to look for resource in
|
|
id - resource id of popup menu
|
|
|
|
Return Value:
|
|
|
|
Revision History:
|
|
|
|
Nov-22-95 Davepl Created
|
|
|
|
--*/
|
|
|
|
HMENU LoadPopupMenu(HINSTANCE hinst, UINT id)
|
|
{
|
|
HMENU hmenuParent = LoadMenu(hinst, MAKEINTRESOURCE(id));
|
|
if (NULL != hmenuParent)
|
|
{
|
|
HMENU hpopup = GetSubMenu(hmenuParent, 0);
|
|
if ( NULL != hpopup )
|
|
{
|
|
RemoveMenu(hmenuParent, 0, MF_BYPOSITION);
|
|
DestroyMenu(hmenuParent);
|
|
}
|
|
|
|
return hpopup;
|
|
}
|
|
|
|
return NULL;
|
|
}
|