reactos/base/applications/taskmgr/taskmgr.c
Joachim Henze f49cead384 [0.4.7][TASKMGR] Mainly Graph-stuff backports 2023-10-31
This backports the following commits:
0.4.15-dev-6770-g ddd1d19b3f [TASKMGR] Get rid of cplusplus extern c (#5808)
partially 0.4.15-dev-6120-g 6e77747b30 [TASKMGR] Simplify tray icon code
0.4.15-dev-6114-g 9a6c85f68a [TASKMGR] Fix PerfDataDeallocCommandLineCache, part of CORE-18014 (unresolved still)
0.4.15-dev-6113-g 7989e3f26c [TASKMGR] GraphCtrl_Dispose: Delete hdcGraph first, part of CORE-18014 (unresolved still)
0.4.15-dev-6112-g dc14a9f6e0 [TASKMGR] GraphCtrl: Use DeleteDC instead of DeleteObject to delete inst->hdcGraph, part of CORE-18014 (unresolved still)
partially 0.4.15-dev-4994-g 15a0f7adb0 picked a tiny part from PR4657 (I picked only the refactoring to switch-statement, no functional changes. Especially NOT the formatting changes which would require the additional winnls.h-include)
0.4.15-dev-3737-g f8faa0b660 [TASKMGR] Fix a heap corruption bug (#4311), just an addendum to PR4141 which is picked with this backport as well. Older branches were never affected.
partially 0.4.15-dev-3514-g 1c82bf0324 [TASKMGR] Avoid freezing in getting icons, from (PR4180) CORE17894. I picked only the 1000ms->100ms part and the stripping of WM_QUERYDRAGICON call. Therefore I don't consider CORE17894 as fully covered.
0.4.15-dev-3486-g 545e1190f2 [TASKMGR] Avoid hangs as much as possible (#4166) CORE17894
partially 0.4.15-dev-3483-g 403222dd4f [TASKMGR] Preserve graphs history on resizes (#4141). I left aside the structs type renaming and OOM-Handling upon graph creation. Picked all the logical changes though.
0.4.15-dev-3269-g 0ed04e3640 [TASKMGR] Make performance graph grid scroll (#3581)
0.4.15-dev-3268-g a4ab9a1e19 [TASKMGR] Formatting only (#3581). Covers the last bits of that PR.

Main motivation was getting the toggling of ShowKernelTimes in the Performance tab
switch on and off in realtime without introducing gaps in the graph.
It also makes the grid scroll together with the data, like on Windows.

Most other parts I picked solely for their binary-shrinking effect.
I decided to strip the ID_HELP_TOPICS from the rc files, as this was not implemented,
and I would never port that back later. So it is one less non-functional-button in the older branches.
I favored memset() over Zeromemory() in this usermode-app everywhere, and favored for (;;) over while(1).

Binary size shrinks slightly on all branches:

master taskmgr.exe RosBEWin2.2.2 GCC8.4.0dbg             696.832 (0.4.15-dev-6820-gb3194e3)
0.4.14 taskmgr.exe RosBEWin2.1.6 GCC4.7.2dbg  549.888 -> 548.864
0.4.13 taskmgr.exe RosBEWin2.1.6 GCC4.7.2dbg  542.720 -> 542.208
0.4.12 taskmgr.exe RosBEWin2.1.6 GCC4.7.2dbg  545.792 -> 543.232
0.4.11 taskmgr.exe RosBEWin2.1.6 GCC4.7.2dbg  545.792 -> 543.232
0.4.10 taskmgr.exe RosBEWin2.1.6 GCC4.7.2dbg  532.480 -> 530.432
0.4. 9 taskmgr.exe RosBEWin2.1.6 GCC4.7.2dbg  532.480 -> 530.432
0.4. 8 taskmgr.exe RosBEWin2.1.6 GCC4.7.2dbg  532.480 -> 530.432
0.4. 7 taskmgr.exe RosBEWin2.1.6 GCC4.7.2dbg  531.456 -> 529.408

       taskmgr.exe MS XPSP3 german                                           140.800 Bytes
0.4.14 taskmgr.exe RosBEWin2.1.6 MSVC2010SP1rls I18N=de-DE  110.080 Bytes -> 109.056 Bytes (my current taskmgr of choice)
0.4. 8 taskmgr.exe RosBEWin2.1.6 MSVC2010SP1rls I18N=en-US  108.032 Bytes -> 105.984 Bytes
0.4. 7 taskmgr.exe RosBEWin2.1.6 MSVC2010SP1rls I18N=en-US  107.520 Bytes -> 105.472 Bytes
2023-10-31 21:09:58 +01:00

984 lines
32 KiB
C

/*
* PROJECT: ReactOS Task Manager
* LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
* COPYRIGHT: 1999-2001 Brian Palmer <brianp@reactos.org>
* 2005 Klemens Friedl <frik85@reactos.at>
*/
#include "precomp.h"
#include "perfpage.h"
#include "about.h"
#include "affinity.h"
#include "debug.h"
#include "priority.h"
#define STATUS_WINDOW 2001
HINSTANCE hInst; /* current instance */
HWND hMainWnd; /* Main Window */
HWND hStatusWnd; /* Status Bar Window */
HWND hTabWnd; /* Tab Control Window */
HMENU hWindowMenu = NULL;
int nMinimumWidth; /* Minimum width of the dialog (OnSize()'s cx) */
int nMinimumHeight; /* Minimum height of the dialog (OnSize()'s cy) */
int nOldWidth; /* Holds the previous client area width */
int nOldHeight; /* Holds the previous client area height */
BOOL bWasKeyboardInput = FALSE; /* TabChange by Keyboard or Mouse ? */
TASKMANAGER_SETTINGS TaskManagerSettings;
#define ETDT_DISABLE 0x00000001
#define ETDT_ENABLE 0x00000002
#define ETDT_USETABTEXTURE 0x00000004
#define ETDT_ENABLETAB (ETDT_ENABLE | ETDT_USETABTEXTURE)
typedef HRESULT (WINAPI * ETDTProc) (HWND, DWORD);
// Try to call EnableThemeDialogTexture, if uxtheme.dll is present
BOOL EnableDialogTheme(HWND hwnd)
{
HMODULE hUXTheme;
ETDTProc fnEnableThemeDialogTexture;
hUXTheme = LoadLibraryA("uxtheme.dll");
if(hUXTheme)
{
fnEnableThemeDialogTexture =
(ETDTProc)GetProcAddress(hUXTheme, "EnableThemeDialogTexture");
if(fnEnableThemeDialogTexture)
{
fnEnableThemeDialogTexture(hwnd, ETDT_ENABLETAB);
FreeLibrary(hUXTheme);
return TRUE;
}
else
{
// Failed to locate API!
FreeLibrary(hUXTheme);
return FALSE;
}
}
else
{
// Not running under XP? Just fail gracefully
return FALSE;
}
}
int APIENTRY wWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPWSTR lpCmdLine,
int nCmdShow)
{
HANDLE hProcess;
HANDLE hToken;
TOKEN_PRIVILEGES tkp;
HANDLE hMutex;
hMutex = CreateMutexW(NULL, TRUE, L"taskmgrros");
if (hMutex && GetLastError() == ERROR_ALREADY_EXISTS)
{
/* Restore existing taskmanager and bring window to front */
/* Relies on the fact that the application title string and window title are the same */
HWND hTaskMgr;
TCHAR szTaskmgr[128];
LoadString(hInst, IDS_APP_TITLE, szTaskmgr, _countof(szTaskmgr));
hTaskMgr = FindWindow(NULL, szTaskmgr);
if (hTaskMgr != NULL)
{
SendMessage(hTaskMgr, WM_SYSCOMMAND, SC_RESTORE, 0);
SetForegroundWindow(hTaskMgr);
}
CloseHandle(hMutex);
return 0;
}
else if (!hMutex)
{
return 1;
}
/* Initialize global variables */
hInst = hInstance;
/* Change our priority class to HIGH */
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS);
CloseHandle(hProcess);
/* Now lets get the SE_DEBUG_NAME privilege
* so that we can debug processes
*/
/* Get a token for this process. */
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
/* Get the LUID for the debug privilege. */
if (LookupPrivilegeValueW(NULL, SE_DEBUG_NAME, &tkp.Privileges[0].Luid))
{
tkp.PrivilegeCount = 1; /* one privilege to set */
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
/* Get the debug privilege for this process. */
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
}
CloseHandle(hToken);
}
LoadSettings();
if (!PerfDataInitialize())
return -1;
/*
* Set our shutdown parameters: we want to shutdown the very last,
* without displaying any end task dialog if needed.
*/
SetProcessShutdownParameters(1, SHUTDOWN_NORETRY);
DialogBoxW(hInst, (LPCWSTR)IDD_TASKMGR_DIALOG, NULL, TaskManagerWndProc);
SaveSettings();
PerfDataUninitialize();
CloseHandle(hMutex);
if (hWindowMenu)
DestroyMenu(hWindowMenu);
return 0;
}
INT_PTR CALLBACK
TaskManagerWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
LPRECT pRC;
LPNMHDR pnmh;
WINDOWPLACEMENT wp;
switch (message) {
case WM_INITDIALOG:
hMainWnd = hDlg;
return OnCreate(hDlg);
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
/* Process menu commands */
switch (LOWORD(wParam))
{
case ID_FILE_NEW:
TaskManager_OnFileNew();
break;
case ID_OPTIONS_ALWAYSONTOP:
TaskManager_OnOptionsAlwaysOnTop();
break;
case ID_OPTIONS_MINIMIZEONUSE:
TaskManager_OnOptionsMinimizeOnUse();
break;
case ID_OPTIONS_HIDEWHENMINIMIZED:
TaskManager_OnOptionsHideWhenMinimized();
break;
case ID_OPTIONS_SHOW16BITTASKS:
TaskManager_OnOptionsShow16BitTasks();
break;
case ID_RESTORE:
TaskManager_OnRestoreMainWindow();
break;
case ID_VIEW_LARGE:
case ID_VIEW_SMALL:
case ID_VIEW_DETAILS:
ApplicationPage_OnView(LOWORD(wParam));
break;
case ID_VIEW_SHOWKERNELTIMES:
PerformancePage_OnViewShowKernelTimes();
break;
case ID_VIEW_CPUHISTORY_ONEGRAPHALL:
PerformancePage_OnViewCPUHistoryOneGraphAll();
break;
case ID_VIEW_CPUHISTORY_ONEGRAPHPERCPU:
PerformancePage_OnViewCPUHistoryOneGraphPerCPU();
break;
case ID_VIEW_UPDATESPEED_HIGH:
case ID_VIEW_UPDATESPEED_NORMAL:
case ID_VIEW_UPDATESPEED_LOW:
case ID_VIEW_UPDATESPEED_PAUSED:
TaskManager_OnViewUpdateSpeed(LOWORD(wParam));
break;
case ID_VIEW_SELECTCOLUMNS:
ProcessPage_OnViewSelectColumns();
break;
case ID_VIEW_REFRESH:
PostMessageW(hDlg, WM_TIMER, 0, 0);
break;
case ID_WINDOWS_TILEHORIZONTALLY:
ApplicationPage_OnWindowsTile(MDITILE_HORIZONTAL);
break;
case ID_WINDOWS_TILEVERTICALLY:
ApplicationPage_OnWindowsTile(MDITILE_VERTICAL);
break;
case ID_WINDOWS_MINIMIZE:
ApplicationPage_OnWindowsMinimize();
break;
case ID_WINDOWS_MAXIMIZE:
ApplicationPage_OnWindowsMaximize();
break;
case ID_WINDOWS_CASCADE:
ApplicationPage_OnWindowsCascade();
break;
case ID_WINDOWS_BRINGTOFRONT:
ApplicationPage_OnWindowsBringToFront();
break;
case ID_APPLICATION_PAGE_SWITCHTO:
ApplicationPage_OnSwitchTo();
break;
case ID_APPLICATION_PAGE_ENDTASK:
ApplicationPage_OnEndTask();
break;
case ID_APPLICATION_PAGE_GOTOPROCESS:
ApplicationPage_OnGotoProcess();
break;
case ID_PROCESS_PAGE_ENDPROCESS:
ProcessPage_OnEndProcess();
break;
case ID_PROCESS_PAGE_ENDPROCESSTREE:
ProcessPage_OnEndProcessTree();
break;
case ID_PROCESS_PAGE_DEBUG:
ProcessPage_OnDebug();
break;
case ID_PROCESS_PAGE_SETAFFINITY:
ProcessPage_OnSetAffinity();
break;
case ID_PROCESS_PAGE_SETPRIORITY_REALTIME:
DoSetPriority(REALTIME_PRIORITY_CLASS);
break;
case ID_PROCESS_PAGE_SETPRIORITY_HIGH:
DoSetPriority(HIGH_PRIORITY_CLASS);
break;
case ID_PROCESS_PAGE_SETPRIORITY_ABOVENORMAL:
DoSetPriority(ABOVE_NORMAL_PRIORITY_CLASS);
break;
case ID_PROCESS_PAGE_SETPRIORITY_NORMAL:
DoSetPriority(NORMAL_PRIORITY_CLASS);
break;
case ID_PROCESS_PAGE_SETPRIORITY_BELOWNORMAL:
DoSetPriority(BELOW_NORMAL_PRIORITY_CLASS);
break;
case ID_PROCESS_PAGE_SETPRIORITY_LOW:
DoSetPriority(IDLE_PRIORITY_CLASS);
break;
case ID_SHUTDOWN_STANDBY:
ShutDown_StandBy();
break;
case ID_SHUTDOWN_HIBERNATE:
ShutDown_Hibernate();
break;
case ID_SHUTDOWN_POWEROFF:
ShutDown_PowerOff();
break;
case ID_SHUTDOWN_REBOOT:
ShutDown_Reboot();
break;
case ID_SHUTDOWN_LOGOFF:
ShutDown_LogOffUser();
break;
case ID_SHUTDOWN_SWITCHUSER:
ShutDown_SwitchUser();
break;
case ID_SHUTDOWN_LOCKCOMPUTER:
ShutDown_LockComputer();
break;
case ID_SHUTDOWN_DISCONNECT:
ShutDown_Disconnect();
break;
case ID_SHUTDOWN_EJECT_COMPUTER:
ShutDown_EjectComputer();
break;
case ID_HELP_ABOUT:
OnAbout();
break;
case ID_FILE_EXIT:
EndDialog(hDlg, IDOK);
break;
}
break;
case WM_ONTRAYICON:
switch(lParam)
{
case WM_RBUTTONDOWN:
{
POINT pt;
BOOL OnTop;
HMENU hMenu, hPopupMenu;
GetCursorPos(&pt);
OnTop = ((GetWindowLongPtrW(hMainWnd, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0);
hMenu = LoadMenuW(hInst, MAKEINTRESOURCEW(IDR_TRAY_POPUP));
hPopupMenu = GetSubMenu(hMenu, 0);
if(IsWindowVisible(hMainWnd))
DeleteMenu(hPopupMenu, ID_RESTORE, MF_BYCOMMAND);
else
SetMenuDefaultItem(hPopupMenu, ID_RESTORE, FALSE);
if(OnTop)
CheckMenuItem(hPopupMenu, ID_OPTIONS_ALWAYSONTOP, MF_BYCOMMAND | MF_CHECKED);
else
CheckMenuItem(hPopupMenu, ID_OPTIONS_ALWAYSONTOP, MF_BYCOMMAND | MF_UNCHECKED);
SetForegroundWindow(hMainWnd);
TrackPopupMenuEx(hPopupMenu, 0, pt.x, pt.y, hMainWnd, NULL);
DestroyMenu(hMenu);
break;
}
case WM_LBUTTONDBLCLK:
TaskManager_OnRestoreMainWindow();
break;
}
break;
case WM_NOTIFY:
pnmh = (LPNMHDR)lParam;
if ((pnmh->hwndFrom == hTabWnd) &&
(pnmh->idFrom == IDC_TAB))
{
switch (pnmh->code)
{
case TCN_SELCHANGE:
TaskManager_OnTabWndSelChange();
break;
case TCN_KEYDOWN:
bWasKeyboardInput = TRUE;
break;
case NM_CLICK:
bWasKeyboardInput = FALSE;
break;
}
}
break;
case WM_SIZING:
/* Make sure the user is sizing the dialog */
/* in an acceptable range */
pRC = (LPRECT)lParam;
if ((wParam == WMSZ_LEFT) || (wParam == WMSZ_TOPLEFT) || (wParam == WMSZ_BOTTOMLEFT)) {
/* If the width is too small enlarge it to the minimum */
if (nMinimumWidth > (pRC->right - pRC->left))
pRC->left = pRC->right - nMinimumWidth;
} else {
/* If the width is too small enlarge it to the minimum */
if (nMinimumWidth > (pRC->right - pRC->left))
pRC->right = pRC->left + nMinimumWidth;
}
if ((wParam == WMSZ_TOP) || (wParam == WMSZ_TOPLEFT) || (wParam == WMSZ_TOPRIGHT)) {
/* If the height is too small enlarge it to the minimum */
if (nMinimumHeight > (pRC->bottom - pRC->top))
pRC->top = pRC->bottom - nMinimumHeight;
} else {
/* If the height is too small enlarge it to the minimum */
if (nMinimumHeight > (pRC->bottom - pRC->top))
pRC->bottom = pRC->top + nMinimumHeight;
}
return TRUE;
case WM_SIZE:
OnSize(wParam, LOWORD(lParam), HIWORD(lParam));
break;
case WM_DESTROY:
ShowWindow(hDlg, SW_HIDE);
TrayIcon_RemoveIcon();
wp.length = sizeof(WINDOWPLACEMENT);
GetWindowPlacement(hDlg, &wp);
TaskManagerSettings.Left = wp.rcNormalPosition.left;
TaskManagerSettings.Top = wp.rcNormalPosition.top;
TaskManagerSettings.Right = wp.rcNormalPosition.right;
TaskManagerSettings.Bottom = wp.rcNormalPosition.bottom;
if (IsZoomed(hDlg) || (wp.flags & WPF_RESTORETOMAXIMIZED))
TaskManagerSettings.Maximized = TRUE;
else
TaskManagerSettings.Maximized = FALSE;
/* Get rid of the allocated command line cache, if any */
PerfDataDeallocCommandLineCache();
if (hWindowMenu)
DestroyMenu(hWindowMenu);
return DefWindowProcW(hDlg, message, wParam, lParam);
case WM_TIMER:
PerfDataRefresh();
RefreshApplicationPage();
RefreshProcessPage();
RefreshPerformancePage();
TrayIcon_UpdateIcon();
break;
case WM_SYSCOLORCHANGE:
/* Forward WM_SYSCOLORCHANGE to common controls */
SendMessage(hApplicationPageListCtrl, WM_SYSCOLORCHANGE, 0, 0);
SendMessage(hProcessPageListCtrl, WM_SYSCOLORCHANGE, 0, 0);
SendMessage(hProcessPageHeaderCtrl, WM_SYSCOLORCHANGE, 0, 0);
break;
}
return 0;
}
void FillSolidRect(HDC hDC, LPCRECT lpRect, COLORREF clr)
{
SetBkColor(hDC, clr);
ExtTextOutW(hDC, 0, 0, ETO_OPAQUE, lpRect, NULL, 0, NULL);
}
static void SetUpdateSpeed(HWND hWnd)
{
/* Setup update speed (pause=fall down) */
switch (TaskManagerSettings.UpdateSpeed) {
case ID_VIEW_UPDATESPEED_HIGH:
SetTimer(hWnd, 1, 500, NULL);
break;
case ID_VIEW_UPDATESPEED_NORMAL:
SetTimer(hWnd, 1, 2000, NULL);
break;
case ID_VIEW_UPDATESPEED_LOW:
SetTimer(hWnd, 1, 4000, NULL);
break;
}
}
BOOL OnCreate(HWND hWnd)
{
HMENU hMenu;
HMENU hEditMenu;
HMENU hViewMenu;
HMENU hShutMenu;
HMENU hUpdateSpeedMenu;
HMENU hCPUHistoryMenu;
int nActivePage;
int nParts[3];
RECT rc;
WCHAR szTemp[256];
WCHAR szLogOffItem[MAX_PATH];
LPWSTR lpUserName;
TCITEM item;
DWORD len = 0;
SendMessageW(hMainWnd, WM_SETICON, ICON_BIG, (LPARAM)LoadIconW(hInst, MAKEINTRESOURCEW(IDI_TASKMANAGER)));
InitCommonControls();
/* Get the minimum window sizes */
GetWindowRect(hWnd, &rc);
nMinimumWidth = (rc.right - rc.left);
nMinimumHeight = (rc.bottom - rc.top);
/* Create the status bar */
hStatusWnd = CreateStatusWindow(WS_VISIBLE|WS_CHILD|WS_CLIPSIBLINGS|SBT_NOBORDERS, L"", hWnd, STATUS_WINDOW);
if(!hStatusWnd)
return FALSE;
/* Create the status bar panes */
nParts[0] = STATUS_SIZE1;
nParts[1] = STATUS_SIZE2;
nParts[2] = STATUS_SIZE3;
SendMessageW(hStatusWnd, SB_SETPARTS, 3, (LPARAM)(LPINT)nParts);
/* Create tab pages */
hTabWnd = GetDlgItem(hWnd, IDC_TAB);
hApplicationPage = CreateDialogW(hInst, MAKEINTRESOURCEW(IDD_APPLICATION_PAGE), hWnd, ApplicationPageWndProc); EnableDialogTheme(hApplicationPage);
hProcessPage = CreateDialogW(hInst, MAKEINTRESOURCEW(IDD_PROCESS_PAGE), hWnd, ProcessPageWndProc); EnableDialogTheme(hProcessPage);
hPerformancePage = CreateDialogW(hInst, MAKEINTRESOURCEW(IDD_PERFORMANCE_PAGE), hWnd, PerformancePageWndProc); EnableDialogTheme(hPerformancePage);
/* Insert tabs */
LoadStringW(hInst, IDS_TAB_APPS, szTemp, 256);
memset(&item, 0, sizeof(TCITEM));
item.mask = TCIF_TEXT;
item.pszText = szTemp;
(void)TabCtrl_InsertItem(hTabWnd, 0, &item);
LoadStringW(hInst, IDS_TAB_PROCESSES, szTemp, 256);
memset(&item, 0, sizeof(TCITEM));
item.mask = TCIF_TEXT;
item.pszText = szTemp;
(void)TabCtrl_InsertItem(hTabWnd, 1, &item);
LoadStringW(hInst, IDS_TAB_PERFORMANCE, szTemp, 256);
memset(&item, 0, sizeof(TCITEM));
item.mask = TCIF_TEXT;
item.pszText = szTemp;
(void)TabCtrl_InsertItem(hTabWnd, 2, &item);
/* Size everything correctly */
GetClientRect(hWnd, &rc);
nOldWidth = rc.right;
nOldHeight = rc.bottom;
if ((TaskManagerSettings.Left != 0) ||
(TaskManagerSettings.Top != 0) ||
(TaskManagerSettings.Right != 0) ||
(TaskManagerSettings.Bottom != 0))
{
MoveWindow(hWnd, TaskManagerSettings.Left, TaskManagerSettings.Top, TaskManagerSettings.Right - TaskManagerSettings.Left, TaskManagerSettings.Bottom - TaskManagerSettings.Top, TRUE);
}
if (TaskManagerSettings.Maximized)
ShowWindow(hWnd, SW_MAXIMIZE);
/* Set the always on top style */
hMenu = GetMenu(hWnd);
hEditMenu = GetSubMenu(hMenu, 1);
hViewMenu = GetSubMenu(hMenu, 2);
hShutMenu = GetSubMenu(hMenu, 4);
hUpdateSpeedMenu = GetSubMenu(hViewMenu, 1);
hCPUHistoryMenu = GetSubMenu(hViewMenu, 7);
if (TaskManagerSettings.AlwaysOnTop) {
CheckMenuItem(hEditMenu, ID_OPTIONS_ALWAYSONTOP, MF_BYCOMMAND|MF_CHECKED);
SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
} else {
CheckMenuItem(hEditMenu, ID_OPTIONS_ALWAYSONTOP, MF_BYCOMMAND|MF_UNCHECKED);
SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
}
if (TaskManagerSettings.MinimizeOnUse)
CheckMenuItem(hEditMenu, ID_OPTIONS_MINIMIZEONUSE, MF_BYCOMMAND|MF_CHECKED);
else
CheckMenuItem(hEditMenu, ID_OPTIONS_MINIMIZEONUSE, MF_BYCOMMAND|MF_UNCHECKED);
if (TaskManagerSettings.HideWhenMinimized)
CheckMenuItem(hEditMenu, ID_OPTIONS_HIDEWHENMINIMIZED, MF_BYCOMMAND|MF_CHECKED);
else
CheckMenuItem(hEditMenu, ID_OPTIONS_HIDEWHENMINIMIZED, MF_BYCOMMAND|MF_UNCHECKED);
if (TaskManagerSettings.Show16BitTasks)
CheckMenuItem(hEditMenu, ID_OPTIONS_SHOW16BITTASKS, MF_BYCOMMAND|MF_CHECKED);
else
CheckMenuItem(hEditMenu, ID_OPTIONS_SHOW16BITTASKS, MF_BYCOMMAND|MF_UNCHECKED);
/* Set the view mode */
CheckMenuRadioItem(hViewMenu, ID_VIEW_LARGE, ID_VIEW_DETAILS, TaskManagerSettings.ViewMode, MF_BYCOMMAND);
if (TaskManagerSettings.ShowKernelTimes)
CheckMenuItem(hViewMenu, ID_VIEW_SHOWKERNELTIMES, MF_BYCOMMAND|MF_CHECKED);
else
CheckMenuItem(hViewMenu, ID_VIEW_SHOWKERNELTIMES, MF_BYCOMMAND|MF_UNCHECKED);
CheckMenuRadioItem(hUpdateSpeedMenu, ID_VIEW_UPDATESPEED_HIGH, ID_VIEW_UPDATESPEED_PAUSED, TaskManagerSettings.UpdateSpeed, MF_BYCOMMAND);
if (TaskManagerSettings.CPUHistory_OneGraphPerCPU)
CheckMenuRadioItem(hCPUHistoryMenu, ID_VIEW_CPUHISTORY_ONEGRAPHALL, ID_VIEW_CPUHISTORY_ONEGRAPHPERCPU, ID_VIEW_CPUHISTORY_ONEGRAPHPERCPU, MF_BYCOMMAND);
else
CheckMenuRadioItem(hCPUHistoryMenu, ID_VIEW_CPUHISTORY_ONEGRAPHALL, ID_VIEW_CPUHISTORY_ONEGRAPHPERCPU, ID_VIEW_CPUHISTORY_ONEGRAPHALL, MF_BYCOMMAND);
nActivePage = TaskManagerSettings.ActiveTabPage;
TabCtrl_SetCurFocus/*Sel*/(hTabWnd, 0);
TabCtrl_SetCurFocus/*Sel*/(hTabWnd, 1);
TabCtrl_SetCurFocus/*Sel*/(hTabWnd, 2);
TabCtrl_SetCurFocus/*Sel*/(hTabWnd, nActivePage);
/* Set the username in the "Log Off %s" item of the Shutdown menu */
/* 1- Get the menu item text and store it temporarily */
GetMenuStringW(hShutMenu, ID_SHUTDOWN_LOGOFF, szTemp, 256, MF_BYCOMMAND);
/* 2- Retrieve the username length first, then allocate a buffer for it and call it again */
if (!GetUserNameW(NULL, &len) && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
lpUserName = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
if (lpUserName && GetUserNameW(lpUserName, &len))
{
_snwprintf(szLogOffItem, _countof(szLogOffItem), szTemp, lpUserName);
szLogOffItem[_countof(szLogOffItem) - 1] = UNICODE_NULL;
}
else
{
_snwprintf(szLogOffItem, _countof(szLogOffItem), szTemp, L"n/a");
}
if (lpUserName) HeapFree(GetProcessHeap(), 0, lpUserName);
}
else
{
_snwprintf(szLogOffItem, _countof(szLogOffItem), szTemp, L"n/a");
}
/* 3- Set the menu item text to its formatted counterpart */
ModifyMenuW(hShutMenu, ID_SHUTDOWN_LOGOFF, MF_BYCOMMAND | MF_STRING, ID_SHUTDOWN_LOGOFF, szLogOffItem);
SetUpdateSpeed(hWnd);
/*
* Refresh the performance data
* Sample it twice so we can establish
* the delta values & cpu usage
*/
PerfDataRefresh();
PerfDataRefresh();
RefreshApplicationPage();
RefreshProcessPage();
RefreshPerformancePage();
TrayIcon_AddIcon();
return TRUE;
}
/* OnSize()
* This function handles all the sizing events for the application
* It re-sizes every window, and child window that needs re-sizing
*/
void OnSize(WPARAM nType, int cx, int cy)
{
int nParts[3];
int nXDifference;
int nYDifference;
RECT rc;
if (nType == SIZE_MINIMIZED)
{
if (TaskManagerSettings.HideWhenMinimized)
ShowWindow(hMainWnd, SW_HIDE);
return;
}
nXDifference = cx - nOldWidth;
nYDifference = cy - nOldHeight;
nOldWidth = cx;
nOldHeight = cy;
/* Update the status bar size */
GetWindowRect(hStatusWnd, &rc);
SendMessageW(hStatusWnd, WM_SIZE, nType, MAKELPARAM(cx,rc.bottom - rc.top));
/* Update the status bar pane sizes */
nParts[0] = STATUS_SIZE1;
nParts[1] = STATUS_SIZE2;
nParts[2] = cx;
SendMessageW(hStatusWnd, SB_SETPARTS, 3, (LPARAM)(LPINT)nParts);
/* Resize the tab control */
GetWindowRect(hTabWnd, &rc);
cx = (rc.right - rc.left) + nXDifference;
cy = (rc.bottom - rc.top) + nYDifference;
SetWindowPos(hTabWnd, NULL, 0, 0, cx, cy, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOMOVE|SWP_NOZORDER);
/* Resize the application page */
GetWindowRect(hApplicationPage, &rc);
cx = (rc.right - rc.left) + nXDifference;
cy = (rc.bottom - rc.top) + nYDifference;
SetWindowPos(hApplicationPage, NULL, 0, 0, cx, cy, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOMOVE|SWP_NOZORDER);
/* Resize the process page */
GetWindowRect(hProcessPage, &rc);
cx = (rc.right - rc.left) + nXDifference;
cy = (rc.bottom - rc.top) + nYDifference;
SetWindowPos(hProcessPage, NULL, 0, 0, cx, cy, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOMOVE|SWP_NOZORDER);
/* Resize the performance page */
GetWindowRect(hPerformancePage, &rc);
cx = (rc.right - rc.left) + nXDifference;
cy = (rc.bottom - rc.top) + nYDifference;
SetWindowPos(hPerformancePage, NULL, 0, 0, cx, cy, SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOMOVE|SWP_NOZORDER);
}
void LoadSettings(void)
{
HKEY hKey;
WCHAR szSubKey[] = L"Software\\ReactOS\\TaskManager";
int i;
DWORD dwSize;
/* Window size & position settings */
TaskManagerSettings.Maximized = FALSE;
TaskManagerSettings.Left = 0;
TaskManagerSettings.Top = 0;
TaskManagerSettings.Right = 0;
TaskManagerSettings.Bottom = 0;
/* Tab settings */
TaskManagerSettings.ActiveTabPage = 0;
/* Options menu settings */
TaskManagerSettings.AlwaysOnTop = TRUE;
TaskManagerSettings.MinimizeOnUse = TRUE;
TaskManagerSettings.HideWhenMinimized = FALSE;
TaskManagerSettings.Show16BitTasks = TRUE;
/* Update speed settings */
TaskManagerSettings.UpdateSpeed = ID_VIEW_UPDATESPEED_NORMAL;
/* Applications page settings */
TaskManagerSettings.ViewMode = ID_VIEW_DETAILS;
/* Processes page settings */
TaskManagerSettings.ShowProcessesFromAllUsers = FALSE;
for (i = 0; i < COLUMN_NMAX; i++) {
TaskManagerSettings.Columns[i] = ColumnPresets[i].bDefaults;
TaskManagerSettings.ColumnOrderArray[i] = i;
TaskManagerSettings.ColumnSizeArray[i] = ColumnPresets[i].size;
}
TaskManagerSettings.SortColumn = COLUMN_IMAGENAME;
TaskManagerSettings.SortAscending = TRUE;
/* Performance page settings */
TaskManagerSettings.CPUHistory_OneGraphPerCPU = TRUE;
TaskManagerSettings.ShowKernelTimes = FALSE;
/* Open the key */
if (RegOpenKeyExW(HKEY_CURRENT_USER, szSubKey, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
return;
/* Read the settings */
dwSize = sizeof(TASKMANAGER_SETTINGS);
RegQueryValueExW(hKey, L"Preferences", NULL, NULL, (LPBYTE)&TaskManagerSettings, &dwSize);
/*
* ATM, the 'ImageName' column is always visible
* (and grayed in configuration dialog)
* This will avoid troubles if the registry gets corrupted.
*/
TaskManagerSettings.Column_ImageName = TRUE;
/* Close the key */
RegCloseKey(hKey);
}
void SaveSettings(void)
{
HKEY hKey;
WCHAR szSubKey[] = L"Software\\ReactOS\\TaskManager";
/* Open (or create) the key */
if (RegCreateKeyExW(HKEY_CURRENT_USER, szSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS)
return;
/* Save the settings */
RegSetValueExW(hKey, L"Preferences", 0, REG_BINARY, (LPBYTE)&TaskManagerSettings, sizeof(TASKMANAGER_SETTINGS));
/* Close the key */
RegCloseKey(hKey);
}
void TaskManager_OnRestoreMainWindow(void)
{
BOOL OnTop;
OnTop = ((GetWindowLongPtrW(hMainWnd, GWL_EXSTYLE) & WS_EX_TOPMOST) != 0);
OpenIcon(hMainWnd);
SetForegroundWindow(hMainWnd);
SetWindowPos(hMainWnd, (OnTop ? HWND_TOPMOST : HWND_TOP), 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);
}
void TaskManager_OnViewUpdateSpeed(DWORD dwSpeed)
{
HMENU hMenu;
HMENU hViewMenu;
HMENU hUpdateSpeedMenu;
hMenu = GetMenu(hMainWnd);
hViewMenu = GetSubMenu(hMenu, 2);
hUpdateSpeedMenu = GetSubMenu(hViewMenu, 1);
TaskManagerSettings.UpdateSpeed = dwSpeed;
CheckMenuRadioItem(hUpdateSpeedMenu, ID_VIEW_UPDATESPEED_HIGH, ID_VIEW_UPDATESPEED_PAUSED, dwSpeed, MF_BYCOMMAND);
KillTimer(hMainWnd, 1);
SetUpdateSpeed(hMainWnd);
}
void TaskManager_OnTabWndSelChange(void)
{
int i;
HMENU hMenu;
HMENU hOptionsMenu;
HMENU hViewMenu;
HMENU hSubMenu;
WCHAR szTemp[256];
SYSTEM_INFO sysInfo;
hMenu = GetMenu(hMainWnd);
hViewMenu = GetSubMenu(hMenu, 2);
hOptionsMenu = GetSubMenu(hMenu, 1);
TaskManagerSettings.ActiveTabPage = TabCtrl_GetCurSel(hTabWnd);
for (i = GetMenuItemCount(hViewMenu) - 1; i > 2; i--) {
hSubMenu = GetSubMenu(hViewMenu, i);
if (hSubMenu)
DestroyMenu(hSubMenu);
RemoveMenu(hViewMenu, i, MF_BYPOSITION);
}
RemoveMenu(hOptionsMenu, 3, MF_BYPOSITION);
if (hWindowMenu)
DestroyMenu(hWindowMenu);
switch (TaskManagerSettings.ActiveTabPage) {
case 0:
ShowWindow(hApplicationPage, SW_SHOW);
ShowWindow(hProcessPage, SW_HIDE);
ShowWindow(hPerformancePage, SW_HIDE);
BringWindowToTop(hApplicationPage);
LoadStringW(hInst, IDS_MENU_LARGEICONS, szTemp, 256);
AppendMenuW(hViewMenu, MF_STRING, ID_VIEW_LARGE, szTemp);
LoadStringW(hInst, IDS_MENU_SMALLICONS, szTemp, 256);
AppendMenuW(hViewMenu, MF_STRING, ID_VIEW_SMALL, szTemp);
LoadStringW(hInst, IDS_MENU_DETAILS, szTemp, 256);
AppendMenuW(hViewMenu, MF_STRING, ID_VIEW_DETAILS, szTemp);
if (GetMenuItemCount(hMenu) <= 5) {
hWindowMenu = LoadMenuW(hInst, MAKEINTRESOURCEW(IDR_WINDOWSMENU));
LoadStringW(hInst, IDS_MENU_WINDOWS, szTemp, 256);
InsertMenuW(hMenu, 3, MF_BYPOSITION|MF_POPUP, (UINT_PTR) hWindowMenu, szTemp);
DrawMenuBar(hMainWnd);
}
CheckMenuRadioItem(hViewMenu, ID_VIEW_LARGE, ID_VIEW_DETAILS, TaskManagerSettings.ViewMode, MF_BYCOMMAND);
/*
* Give the application list control focus
*/
if (!bWasKeyboardInput)
SetFocus(hApplicationPageListCtrl);
break;
case 1:
ShowWindow(hApplicationPage, SW_HIDE);
ShowWindow(hProcessPage, SW_SHOW);
ShowWindow(hPerformancePage, SW_HIDE);
BringWindowToTop(hProcessPage);
LoadStringW(hInst, IDS_MENU_SELECTCOLUMNS, szTemp, 256);
AppendMenuW(hViewMenu, MF_STRING, ID_VIEW_SELECTCOLUMNS, szTemp);
LoadStringW(hInst, IDS_MENU_16BITTASK, szTemp, 256);
AppendMenuW(hOptionsMenu, MF_STRING, ID_OPTIONS_SHOW16BITTASKS, szTemp);
if (TaskManagerSettings.Show16BitTasks)
CheckMenuItem(hOptionsMenu, ID_OPTIONS_SHOW16BITTASKS, MF_BYCOMMAND|MF_CHECKED);
if (GetMenuItemCount(hMenu) > 5)
{
DeleteMenu(hMenu, 3, MF_BYPOSITION);
DrawMenuBar(hMainWnd);
}
/*
* Give the process list control focus
*/
if (!bWasKeyboardInput)
SetFocus(hProcessPageListCtrl);
break;
case 2:
ShowWindow(hApplicationPage, SW_HIDE);
ShowWindow(hProcessPage, SW_HIDE);
ShowWindow(hPerformancePage, SW_SHOW);
BringWindowToTop(hPerformancePage);
if (GetMenuItemCount(hMenu) > 5) {
DeleteMenu(hMenu, 3, MF_BYPOSITION);
DrawMenuBar(hMainWnd);
}
GetSystemInfo(&sysInfo);
/* Hide CPU graph options on single CPU systems */
if (sysInfo.dwNumberOfProcessors > 1)
{
hSubMenu = CreatePopupMenu();
LoadStringW(hInst, IDS_MENU_ONEGRAPHALLCPUS, szTemp, 256);
AppendMenuW(hSubMenu, MF_STRING, ID_VIEW_CPUHISTORY_ONEGRAPHALL, szTemp);
LoadStringW(hInst, IDS_MENU_ONEGRAPHPERCPU, szTemp, 256);
AppendMenuW(hSubMenu, MF_STRING, ID_VIEW_CPUHISTORY_ONEGRAPHPERCPU, szTemp);
LoadStringW(hInst, IDS_MENU_CPUHISTORY, szTemp, 256);
AppendMenuW(hViewMenu, MF_STRING|MF_POPUP, (UINT_PTR) hSubMenu, szTemp);
if (TaskManagerSettings.CPUHistory_OneGraphPerCPU)
CheckMenuRadioItem(hSubMenu, ID_VIEW_CPUHISTORY_ONEGRAPHALL, ID_VIEW_CPUHISTORY_ONEGRAPHPERCPU, ID_VIEW_CPUHISTORY_ONEGRAPHPERCPU, MF_BYCOMMAND);
else
CheckMenuRadioItem(hSubMenu, ID_VIEW_CPUHISTORY_ONEGRAPHALL, ID_VIEW_CPUHISTORY_ONEGRAPHPERCPU, ID_VIEW_CPUHISTORY_ONEGRAPHALL, MF_BYCOMMAND);
}
LoadStringW(hInst, IDS_MENU_SHOWKERNELTIMES, szTemp, 256);
AppendMenuW(hViewMenu, MF_STRING, ID_VIEW_SHOWKERNELTIMES, szTemp);
if (TaskManagerSettings.ShowKernelTimes)
CheckMenuItem(hViewMenu, ID_VIEW_SHOWKERNELTIMES, MF_BYCOMMAND|MF_CHECKED);
else
CheckMenuItem(hViewMenu, ID_VIEW_SHOWKERNELTIMES, MF_BYCOMMAND|MF_UNCHECKED);
/*
* Give the tab control focus
*/
if (!bWasKeyboardInput)
SetFocus(hTabWnd);
break;
}
}
VOID ShowWin32Error(DWORD dwError)
{
LPWSTR lpMessageBuffer;
if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
dwError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPWSTR)&lpMessageBuffer,
0, NULL) != 0)
{
MessageBoxW(hMainWnd, lpMessageBuffer, NULL, MB_OK | MB_ICONERROR);
if (lpMessageBuffer) LocalFree(lpMessageBuffer);
}
}
LPWSTR GetLastErrorText(LPWSTR lpszBuf, DWORD dwSize)
{
DWORD dwRet;
LPWSTR lpszTemp = NULL;
dwRet = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY,
NULL,
GetLastError(),
LANG_NEUTRAL,
(LPWSTR)&lpszTemp,
0,
NULL);
/* supplied buffer is not long enough */
if (!dwRet || ((long)dwSize < (long)dwRet+14))
lpszBuf[0] = L'\0';
else {
lpszTemp[lstrlenW(lpszTemp)-2] = L'\0'; /*remove cr and newline character */
wsprintfW(lpszBuf, L"%s (0x%x)", lpszTemp, (int)GetLastError());
}
if (lpszTemp)
LocalFree((HLOCAL)lpszTemp);
return lpszBuf;
}
DWORD EndLocalThread(HANDLE *hThread, DWORD dwThread)
{
DWORD dwExitCodeThread = 0;
if (*hThread != NULL) {
PostThreadMessage(dwThread,WM_QUIT,0,0);
for (;;) {
MSG msg;
if (WAIT_OBJECT_0 == WaitForSingleObject(*hThread, 500))
break;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
GetExitCodeThread(*hThread, &dwExitCodeThread);
CloseHandle(*hThread);
*hThread = NULL;
}
return dwExitCodeThread;
}