Files
mirror-processhacker/2.x/trunk/ProcessHacker/mainwnd.c
T
wj32 0c6d998ac2 * converted the service tree list to tree new
* fixed tree new tooltip bugs

git-svn-id: svn://svn.code.sf.net/p/processhacker/code@4277 21ef857c-d57f-4fe0-8362-d861dc6d29cd
2011-07-03 09:33:43 +00:00

4850 lines
150 KiB
C

/*
* Process Hacker -
* main window
*
* Copyright (C) 2009-2011 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
#define PH_MAINWND_PRIVATE
#include <phapp.h>
#include <settings.h>
#include <cpysave.h>
#include <memsrch.h>
#include <symprv.h>
#include <emenu.h>
#include <phplug.h>
#include <windowsx.h>
#include <shlobj.h>
#include <winsta.h>
#include <iphlpapi.h>
#define RUNAS_MODE_ADMIN 1
#define RUNAS_MODE_LIMITED 2
typedef HRESULT (WINAPI *_LoadIconMetric)(
__in HINSTANCE hinst,
__in PCWSTR pszName,
__in int lims,
__out HICON *phico
);
VOID PhMainWndOnCreate();
ULONG_PTR PhpMainWndAddMenuItem(
__in PPH_PLUGIN Plugin,
__in HMENU ParentMenu,
__in_opt PWSTR InsertAfter,
__in ULONG Flags,
__in ULONG Id,
__in PWSTR Text,
__in_opt PVOID Context
);
PPH_ADDITIONAL_TAB_PAGE PhpAddTabPage(
__in PPH_ADDITIONAL_TAB_PAGE TabPage
);
VOID PhMainWndOnLayout(
__inout HDWP *deferHandle
);
VOID PhMainWndTabControlOnLayout(
__inout HDWP *deferHandle
);
VOID PhMainWndTabControlOnNotify(
__in LPNMHDR Header
);
VOID PhMainWndTabControlOnSelectionChanged();
VOID PhMainWndNetworkListViewOnNotify(
__in LPNMHDR Header
);
VOID PhMainWndNetworkListViewOnContextMenu(
__in LPARAM lParam
);
VOID PhReloadSysParameters();
VOID PhpInitialLoadSettings();
VOID PhMainSymInitHandler(
__in_opt PVOID Parameter,
__in_opt PVOID Context
);
NTSTATUS PhpDelayedLoadFunction(
__in PVOID Parameter
);
VOID PhpSaveWindowState();
VOID PhpSaveAllSettings();
VOID PhpSetCheckOpacityMenu(
__in BOOLEAN AssumeAllUnchecked,
__in ULONG Opacity
);
VOID PhpSetWindowOpacity(
__in ULONG Opacity
);
VOID PhpSelectTabPage(
__in ULONG Index
);
VOID PhpPrepareForEarlyShutdown();
VOID PhpCancelEarlyShutdown();
VOID PhpNeedServiceTreeList();
BOOLEAN PhpProcessComputerCommand(
__in ULONG Id
);
BOOLEAN PhpProcessProcessPriorityCommand(
__in ULONG Id,
__in PPH_PROCESS_ITEM ProcessItem
);
VOID PhpRefreshUsersMenu();
VOID PhpAddIconProcesses(
__in PPH_EMENU_ITEM Menu,
__in ULONG NumberOfProcesses
);
VOID PhpShowIconContextMenu(
__in POINT Location
);
BOOLEAN PhpCurrentUserProcessTreeFilter(
__in PPH_PROCESS_NODE ProcessNode,
__in_opt PVOID Context
);
BOOLEAN PhpSignedProcessTreeFilter(
__in PPH_PROCESS_NODE ProcessNode,
__in_opt PVOID Context
);
PPH_PROCESS_ITEM PhpGetSelectedProcess();
VOID PhpGetSelectedProcesses(
__out PPH_PROCESS_ITEM **Processes,
__out PULONG NumberOfProcesses
);
PPH_SERVICE_ITEM PhpGetSelectedService();
VOID PhpGetSelectedServices(
__out PPH_SERVICE_ITEM **Services,
__out PULONG NumberOfServices
);
PPH_NETWORK_ITEM PhpGetSelectedNetworkItem();
VOID PhpGetSelectedNetworkItems(
__out PPH_NETWORK_ITEM **NetworkItems,
__out PULONG NumberOfNetworkItems
);
VOID PhpShowProcessProperties(
__in PPH_PROCESS_ITEM ProcessItem
);
VOID PhpSetProcessMenuPriorityChecks(
__in PPH_EMENU Menu,
__in PPH_PROCESS_ITEM Process,
__in BOOLEAN SetPriority,
__in BOOLEAN SetIoPriority,
__in BOOLEAN SetPagePriority
);
VOID PhMainWndOnProcessAdded(
__in __assumeRefs(1) PPH_PROCESS_ITEM ProcessItem,
__in ULONG RunId
);
VOID PhMainWndOnProcessModified(
__in PPH_PROCESS_ITEM ProcessItem
);
VOID PhMainWndOnProcessRemoved(
__in PPH_PROCESS_ITEM ProcessItem
);
VOID PhMainWndOnProcessesUpdated();
VOID PhMainWndOnServiceAdded(
__in __assumeRefs(1) PPH_SERVICE_ITEM ServiceItem,
__in ULONG RunId
);
VOID PhMainWndOnServiceModified(
__in PPH_SERVICE_MODIFIED_DATA ServiceModifiedData
);
VOID PhMainWndOnServiceRemoved(
__in PPH_SERVICE_ITEM ServiceItem
);
VOID PhMainWndOnServicesUpdated();
VOID PhMainWndOnNetworkItemAdded(
__in ULONG RunId,
__in PPH_NETWORK_ITEM NetworkItem
);
VOID PhMainWndOnNetworkItemModified(
__in PPH_NETWORK_ITEM NetworkItem
);
VOID PhMainWndOnNetworkItemRemoved(
__in PPH_NETWORK_ITEM NetworkItem
);
VOID PhMainWndOnNetworkItemsUpdated();
PHAPPAPI HWND PhMainWndHandle;
BOOLEAN PhMainWndExiting = FALSE;
HMENU PhMainWndMenuHandle;
static BOOLEAN NeedsMaximize = FALSE;
static BOOLEAN DelayedLoadCompleted = FALSE;
static ULONG NotifyIconMask;
static ULONG NotifyIconNotifyMask;
static RECT LayoutPadding = { 0, 0, 0, 0 };
static HWND TabControlHandle;
static INT ProcessesTabIndex;
static INT ServicesTabIndex;
static INT NetworkTabIndex;
static INT MaxTabIndex;
static PPH_LIST AdditionalTabPageList = NULL;
static HWND ProcessTreeListHandle;
static HWND ServiceTreeListHandle;
static HWND NetworkListViewHandle;
static HFONT CurrentCustomFont;
static BOOLEAN NetworkFirstTime = TRUE;
static BOOLEAN ServiceTreeListLoaded = FALSE;
static BOOLEAN UpdateAutomatically = TRUE;
static PH_CALLBACK_REGISTRATION SymInitRegistration;
static PH_PROVIDER_REGISTRATION ProcessProviderRegistration;
static PH_CALLBACK_REGISTRATION ProcessAddedRegistration;
static PH_CALLBACK_REGISTRATION ProcessModifiedRegistration;
static PH_CALLBACK_REGISTRATION ProcessRemovedRegistration;
static PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration;
static PH_CALLBACK_REGISTRATION ProcessesUpdatedForIconsRegistration;
static BOOLEAN ProcessesNeedsRedraw = FALSE;
static PH_PROVIDER_REGISTRATION ServiceProviderRegistration;
static PH_CALLBACK_REGISTRATION ServiceAddedRegistration;
static PH_CALLBACK_REGISTRATION ServiceModifiedRegistration;
static PH_CALLBACK_REGISTRATION ServiceRemovedRegistration;
static PH_CALLBACK_REGISTRATION ServicesUpdatedRegistration;
static PPH_POINTER_LIST ServicesPendingList;
static BOOLEAN ServicesNeedsRedraw = FALSE;
static PH_PROVIDER_REGISTRATION NetworkProviderRegistration;
static PH_CALLBACK_REGISTRATION NetworkItemAddedRegistration;
static PH_CALLBACK_REGISTRATION NetworkItemModifiedRegistration;
static PH_CALLBACK_REGISTRATION NetworkItemRemovedRegistration;
static PH_CALLBACK_REGISTRATION NetworkItemsUpdatedRegistration;
static BOOLEAN NetworkNeedsRedraw = FALSE;
static BOOLEAN NetworkNeedsSort = FALSE;
static PH_IMAGE_LIST_WRAPPER NetworkImageListWrapper;
static PPH_PLUGIN_MENU_ITEM SelectedMenuItemPlugin;
static ULONG SelectedRunAsMode;
static HWND SelectedProcessWindowHandle;
static BOOLEAN SelectedProcessVirtualizationEnabled;
static ULONG SelectedUserSessionId;
static PPH_PROCESS_TREE_FILTER_ENTRY CurrentUserFilterEntry = NULL;
static PPH_PROCESS_TREE_FILTER_ENTRY SignedFilterEntry = NULL;
BOOLEAN PhMainWndInitialization(
__in INT ShowCommand
)
{
PH_RECTANGLE windowRectangle;
if (PhGetIntegerSetting(L"FirstRun"))
{
PPH_STRING autoDbghelpPath;
// Try to set up the dbghelp path automatically if this is the first run.
autoDbghelpPath = PHA_DEREFERENCE(PhGetKnownLocation(
CSIDL_PROGRAM_FILES,
#ifdef _M_IX86
L"\\Debugging Tools for Windows (x86)\\dbghelp.dll"
#else
L"\\Debugging Tools for Windows (x64)\\dbghelp.dll"
#endif
));
if (autoDbghelpPath)
{
if (RtlDoesFileExists_U(autoDbghelpPath->Buffer))
{
PhSetStringSetting2(L"DbgHelpPath", &autoDbghelpPath->sr);
}
}
PhSetIntegerSetting(L"FirstRun", FALSE);
}
// This was added to be able to delay-load dbghelp.dll and symsrv.dll.
PhRegisterCallback(&PhSymInitCallback, PhMainSymInitHandler, NULL, &SymInitRegistration);
// Initialize the providers.
{
ULONG interval = PhGetIntegerSetting(L"UpdateInterval");
if (interval == 0)
{
interval = 1000;
PH_SET_INTEGER_CACHED_SETTING(UpdateInterval, interval);
}
PhInitializeProviderThread(&PhPrimaryProviderThread, interval);
PhInitializeProviderThread(&PhSecondaryProviderThread, interval);
}
PhRegisterProvider(&PhPrimaryProviderThread, PhProcessProviderUpdate, NULL, &ProcessProviderRegistration);
PhSetEnabledProvider(&ProcessProviderRegistration, TRUE);
PhRegisterProvider(&PhPrimaryProviderThread, PhServiceProviderUpdate, NULL, &ServiceProviderRegistration);
PhSetEnabledProvider(&ServiceProviderRegistration, TRUE);
PhRegisterProvider(&PhPrimaryProviderThread, PhNetworkProviderUpdate, NULL, &NetworkProviderRegistration);
windowRectangle.Position = PhGetIntegerPairSetting(L"MainWindowPosition");
windowRectangle.Size = PhGetIntegerPairSetting(L"MainWindowSize");
PhMainWndHandle = CreateWindow(
PhWindowClassName,
PhApplicationName,
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
windowRectangle.Left,
windowRectangle.Top,
windowRectangle.Width,
windowRectangle.Height,
NULL,
NULL,
PhInstanceHandle,
NULL
);
PhMainWndMenuHandle = GetMenu(PhMainWndHandle);
if (!PhMainWndHandle)
return FALSE;
// Choose a more appropriate rectangle for the window.
PhAdjustRectangleToWorkingArea(
PhMainWndHandle,
&windowRectangle
);
MoveWindow(PhMainWndHandle, windowRectangle.Left, windowRectangle.Top,
windowRectangle.Width, windowRectangle.Height, FALSE);
// Allow WM_PH_ACTIVATE to pass through UIPI.
if (WINDOWS_HAS_UAC)
ChangeWindowMessageFilter_I(WM_PH_ACTIVATE, MSGFLT_ADD);
// Create the window title.
{
PH_STRING_BUILDER stringBuilder;
PhInitializeStringBuilder(&stringBuilder, 100);
PhAppendStringBuilder2(&stringBuilder, L"Process Hacker");
if (PhCurrentUserName)
{
PhAppendStringBuilder2(&stringBuilder, L" [");
PhAppendStringBuilder(&stringBuilder, PhCurrentUserName);
PhAppendCharStringBuilder(&stringBuilder, ']');
if (PhKphHandle) PhAppendCharStringBuilder(&stringBuilder, '+');
}
if (WINDOWS_HAS_UAC && PhElevationType == TokenElevationTypeFull)
PhAppendStringBuilder2(&stringBuilder, L" (Administrator)");
SetWindowText(PhMainWndHandle, stringBuilder.String->Buffer);
PhDeleteStringBuilder(&stringBuilder);
}
// Fix some menu items.
if (PhElevated)
{
DeleteMenu(PhMainWndMenuHandle, ID_HACKER_RUNASADMINISTRATOR, 0);
DeleteMenu(PhMainWndMenuHandle, ID_HACKER_SHOWDETAILSFORALLPROCESSES, 0);
}
else
{
_LoadIconMetric loadIconMetric;
HICON shieldIcon;
MENUITEMINFO menuItemInfo = { sizeof(menuItemInfo) };
// It is necessary to use LoadIconMetric because otherwise the icons are at the wrong
// resolution and look very bad when scaled down to the small icon size.
loadIconMetric = (_LoadIconMetric)PhGetProcAddress(L"comctl32.dll", "LoadIconMetric");
if (loadIconMetric && SUCCEEDED(loadIconMetric(NULL, IDI_SHIELD, LIM_SMALL, &shieldIcon)))
{
menuItemInfo.fMask = MIIM_BITMAP;
menuItemInfo.hbmpItem = PhIconToBitmap(shieldIcon, PhSmallIconSize.X, PhSmallIconSize.Y);
DestroyIcon(shieldIcon);
SetMenuItemInfo(PhMainWndMenuHandle, ID_HACKER_SHOWDETAILSFORALLPROCESSES, FALSE, &menuItemInfo);
}
}
DrawMenuBar(PhMainWndHandle);
PhReloadSysParameters();
// Initialize child controls.
PhMainWndOnCreate();
PhpInitialLoadSettings();
PhLogInitialization();
PhQueueItemGlobalWorkQueue(PhpDelayedLoadFunction, NULL);
PhMainWndTabControlOnSelectionChanged();
// Perform a layout.
SendMessage(PhMainWndHandle, WM_SIZE, 0, 0);
PhStartProviderThread(&PhPrimaryProviderThread);
PhStartProviderThread(&PhSecondaryProviderThread);
UpdateWindow(PhMainWndHandle);
if ((PhStartupParameters.ShowHidden || PhGetIntegerSetting(L"StartHidden")) && NotifyIconMask != 0)
ShowCommand = SW_HIDE;
if (PhStartupParameters.ShowVisible)
ShowCommand = SW_SHOW;
if (PhGetIntegerSetting(L"MainWindowState") == SW_MAXIMIZE)
{
if (ShowCommand != SW_HIDE)
{
ShowCommand = SW_MAXIMIZE;
}
else
{
// We can't maximize it while having it hidden. Set it as pending.
NeedsMaximize = TRUE;
}
}
if (PhPluginsEnabled)
PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMainWindowShowing), (PVOID)ShowCommand);
if (ShowCommand != SW_HIDE)
ShowWindow(PhMainWndHandle, ShowCommand);
// TS notification registration is done in the delayed load function. It's therefore
// possible that we miss a notification, but it's a trade-off.
PhpRefreshUsersMenu();
return TRUE;
}
LRESULT CALLBACK PhMainWndProc(
__in HWND hWnd,
__in UINT uMsg,
__in WPARAM wParam,
__in LPARAM lParam
)
{
switch (uMsg)
{
case WM_DESTROY:
{
ULONG mask;
ULONG i;
if (!PhMainWndExiting)
ProcessHacker_SaveAllSettings(hWnd);
// Remove all icons to prevent them hanging around after we exit.
mask = NotifyIconMask;
NotifyIconMask = 0; // prevent further icon updating
for (i = PH_ICON_MINIMUM; i != PH_ICON_MAXIMUM; i <<= 1)
{
if (mask & i)
PhRemoveNotifyIcon(i);
}
// Notify plugins that we are shutting down.
if (PhPluginsEnabled)
PhUnloadPlugins();
PostQuitMessage(0);
}
break;
case WM_SETTINGCHANGE:
{
PhReloadSysParameters();
}
break;
case WM_COMMAND:
{
INT id = LOWORD(wParam);
switch (id)
{
case ID_ESC_EXIT:
{
if (PhGetIntegerSetting(L"HideOnClose") && NotifyIconMask != 0)
ShowWindow(hWnd, SW_HIDE);
}
break;
case ID_HACKER_RUN:
{
if (RunFileDlg)
{
SelectedRunAsMode = 0;
RunFileDlg(hWnd, NULL, NULL, NULL, NULL, 0);
}
}
break;
case ID_HACKER_RUNASADMINISTRATOR:
{
if (RunFileDlg)
{
SelectedRunAsMode = RUNAS_MODE_ADMIN;
RunFileDlg(
hWnd,
NULL,
NULL,
NULL,
L"Type the name of a program that will be opened under alternate credentials.",
0
);
}
}
break;
case ID_HACKER_RUNASLIMITEDUSER:
{
if (RunFileDlg)
{
SelectedRunAsMode = RUNAS_MODE_LIMITED;
RunFileDlg(
hWnd,
NULL,
NULL,
NULL,
L"Type the name of a program that will be opened under standard user privileges.",
0
);
}
}
break;
case ID_HACKER_RUNAS:
{
PhShowRunAsDialog(hWnd, NULL);
}
break;
case ID_HACKER_SHOWDETAILSFORALLPROCESSES:
{
ProcessHacker_PrepareForEarlyShutdown(hWnd);
if (PhShellProcessHacker(hWnd, L"-v", SW_SHOW, PH_SHELL_EXECUTE_ADMIN, TRUE, 0, NULL))
{
ProcessHacker_Destroy(hWnd);
}
else
{
ProcessHacker_CancelEarlyShutdown(hWnd);
}
}
break;
case ID_HACKER_SAVE:
{
static PH_FILETYPE_FILTER filters[] =
{
{ L"Text files (*.txt;*.log)", L"*.txt;*.log" },
{ L"Comma-separated values (*.csv)", L"*.csv" },
{ L"All files (*.*)", L"*.*" }
};
PVOID fileDialog = PhCreateSaveFileDialog();
PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER));
PhSetFileDialogFileName(fileDialog, L"Process Hacker.txt");
if (PhShowFileDialog(hWnd, fileDialog))
{
NTSTATUS status;
PPH_STRING fileName;
PPH_FILE_STREAM fileStream;
fileName = PhGetFileDialogFileName(fileDialog);
PhaDereferenceObject(fileName);
if (NT_SUCCESS(status = PhCreateFileStream(
&fileStream,
fileName->Buffer,
FILE_GENERIC_WRITE,
FILE_SHARE_READ,
FILE_OVERWRITE_IF,
0
)))
{
ULONG mode;
ULONG selectedTab;
PPH_LIST lines = NULL;
if (PhEndsWithString2(fileName, L".csv", TRUE))
mode = PH_EXPORT_MODE_CSV;
else
mode = PH_EXPORT_MODE_TABS;
PhWritePhTextHeader(fileStream);
selectedTab = TabCtrl_GetCurSel(TabControlHandle);
if (selectedTab == ProcessesTabIndex)
PhWriteProcessTree(fileStream, mode);
else if (selectedTab == ServicesTabIndex)
PhWriteServiceList(fileStream, mode);
else if (selectedTab == NetworkTabIndex)
lines = PhGetListViewLines(NetworkListViewHandle, mode);
if (lines)
{
ULONG i;
for (i = 0; i < lines->Count; i++)
{
PPH_STRING line;
line = lines->Items[i];
PhWriteStringAsAnsiFileStream(fileStream, &line->sr);
PhDereferenceObject(line);
PhWriteStringAsAnsiFileStream2(fileStream, L"\r\n");
}
PhDereferenceObject(lines);
}
PhDereferenceObject(fileStream);
}
if (!NT_SUCCESS(status))
PhShowStatus(hWnd, L"Unable to create the file", status, 0);
}
PhFreeFileDialog(fileDialog);
}
break;
case ID_HACKER_FINDHANDLESORDLLS:
{
PhShowFindObjectsDialog();
}
break;
case ID_HACKER_OPTIONS:
{
PhShowOptionsDialog(hWnd);
}
break;
case ID_HACKER_PLUGINS:
{
PhShowPluginsDialog(hWnd);
}
break;
case ID_COMPUTER_LOCK:
case ID_COMPUTER_LOGOFF:
case ID_COMPUTER_SLEEP:
case ID_COMPUTER_HIBERNATE:
case ID_COMPUTER_RESTART:
case ID_COMPUTER_SHUTDOWN:
case ID_COMPUTER_POWEROFF:
PhpProcessComputerCommand(LOWORD(wParam));
break;
case ID_HACKER_EXIT:
ProcessHacker_Destroy(hWnd);
break;
case ID_VIEW_SYSTEMINFORMATION:
PhShowSystemInformationDialog();
break;
case ID_TRAYICONS_CPUHISTORY:
case ID_TRAYICONS_CPUUSAGE:
case ID_TRAYICONS_IOHISTORY:
case ID_TRAYICONS_COMMITHISTORY:
case ID_TRAYICONS_PHYSICALMEMORYHISTORY:
{
ULONG i;
BOOLEAN enable;
switch (LOWORD(wParam))
{
case ID_TRAYICONS_CPUHISTORY:
i = PH_ICON_CPU_HISTORY;
break;
case ID_TRAYICONS_CPUUSAGE:
i = PH_ICON_CPU_USAGE;
break;
case ID_TRAYICONS_IOHISTORY:
i = PH_ICON_IO_HISTORY;
break;
case ID_TRAYICONS_COMMITHISTORY:
i = PH_ICON_COMMIT_HISTORY;
break;
case ID_TRAYICONS_PHYSICALMEMORYHISTORY:
i = PH_ICON_PHYSICAL_HISTORY;
break;
}
enable = !(GetMenuState(PhMainWndMenuHandle, LOWORD(wParam), 0) & MF_CHECKED);
if (enable)
{
NotifyIconMask |= i;
PhAddNotifyIcon(i);
}
else
{
NotifyIconMask &= ~i;
PhRemoveNotifyIcon(i);
}
CheckMenuItem(
PhMainWndMenuHandle,
LOWORD(wParam),
enable ? MF_CHECKED : MF_UNCHECKED
);
}
break;
case ID_VIEW_HIDEPROCESSESFROMOTHERUSERS:
{
if (!CurrentUserFilterEntry)
{
CurrentUserFilterEntry = PhAddProcessTreeFilter(PhpCurrentUserProcessTreeFilter, NULL);
}
else
{
PhRemoveProcessTreeFilter(CurrentUserFilterEntry);
CurrentUserFilterEntry = NULL;
}
PhApplyProcessTreeFilters();
PhSetIntegerSetting(L"HideOtherUserProcesses", !!CurrentUserFilterEntry);
CheckMenuItem(
PhMainWndMenuHandle,
ID_VIEW_HIDEPROCESSESFROMOTHERUSERS,
CurrentUserFilterEntry ? MF_CHECKED : MF_UNCHECKED
);
}
break;
case ID_VIEW_HIDESIGNEDPROCESSES:
{
if (!SignedFilterEntry)
{
if (!PhEnableProcessQueryStage2)
{
PhShowInformation(
hWnd,
L"This filter cannot function because digital signature checking is not enabled. "
L"Enable it in Options > Advanced and restart Process Hacker."
);
}
SignedFilterEntry = PhAddProcessTreeFilter(PhpSignedProcessTreeFilter, NULL);
}
else
{
PhRemoveProcessTreeFilter(SignedFilterEntry);
SignedFilterEntry = NULL;
}
PhApplyProcessTreeFilters();
PhSetIntegerSetting(L"HideSignedProcesses", !!SignedFilterEntry);
CheckMenuItem(
PhMainWndMenuHandle,
ID_VIEW_HIDESIGNEDPROCESSES,
SignedFilterEntry ? MF_CHECKED : MF_UNCHECKED
);
}
break;
case ID_VIEW_ALWAYSONTOP:
{
BOOLEAN topMost;
topMost = !(GetMenuState(PhMainWndMenuHandle, ID_VIEW_ALWAYSONTOP, 0) & MF_CHECKED);
SetWindowPos(PhMainWndHandle, topMost ? HWND_TOPMOST : HWND_NOTOPMOST,
0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
PhSetIntegerSetting(L"MainWindowAlwaysOnTop", topMost);
CheckMenuItem(
PhMainWndMenuHandle,
ID_VIEW_ALWAYSONTOP,
topMost ? MF_CHECKED : MF_UNCHECKED
);
}
break;
case ID_OPACITY_10:
case ID_OPACITY_20:
case ID_OPACITY_30:
case ID_OPACITY_40:
case ID_OPACITY_50:
case ID_OPACITY_60:
case ID_OPACITY_70:
case ID_OPACITY_80:
case ID_OPACITY_90:
case ID_OPACITY_OPAQUE:
{
ULONG opacity;
opacity = 100 - (((ULONG)LOWORD(wParam) - ID_OPACITY_10) + 1) * 10;
PhSetIntegerSetting(L"MainWindowOpacity", opacity);
PhpSetWindowOpacity(opacity);
PhpSetCheckOpacityMenu(TRUE, opacity);
}
break;
case ID_VIEW_REFRESH:
{
PhBoostProvider(&ProcessProviderRegistration, NULL);
PhBoostProvider(&ServiceProviderRegistration, NULL);
}
break;
case ID_UPDATEINTERVAL_FAST:
case ID_UPDATEINTERVAL_NORMAL:
case ID_UPDATEINTERVAL_BELOWNORMAL:
case ID_UPDATEINTERVAL_SLOW:
case ID_UPDATEINTERVAL_VERYSLOW:
{
ULONG interval;
switch (LOWORD(wParam))
{
case ID_UPDATEINTERVAL_FAST:
interval = 500;
break;
case ID_UPDATEINTERVAL_NORMAL:
interval = 1000;
break;
case ID_UPDATEINTERVAL_BELOWNORMAL:
interval = 2000;
break;
case ID_UPDATEINTERVAL_SLOW:
interval = 5000;
break;
case ID_UPDATEINTERVAL_VERYSLOW:
interval = 10000;
break;
}
PH_SET_INTEGER_CACHED_SETTING(UpdateInterval, interval);
PhApplyUpdateInterval(interval);
CheckMenuRadioItem(
PhMainWndMenuHandle,
ID_UPDATEINTERVAL_FAST,
ID_UPDATEINTERVAL_VERYSLOW,
LOWORD(wParam),
MF_BYCOMMAND
);
}
break;
case ID_VIEW_UPDATEAUTOMATICALLY:
{
UpdateAutomatically = !UpdateAutomatically;
PhSetEnabledProvider(&ProcessProviderRegistration, UpdateAutomatically);
PhSetEnabledProvider(&ServiceProviderRegistration, UpdateAutomatically);
if (TabCtrl_GetCurSel(TabControlHandle) == NetworkTabIndex)
PhSetEnabledProvider(&NetworkProviderRegistration, UpdateAutomatically);
CheckMenuItem(
PhMainWndMenuHandle,
ID_VIEW_UPDATEAUTOMATICALLY,
UpdateAutomatically ? MF_CHECKED : MF_UNCHECKED
);
}
break;
case ID_TOOLS_CREATESERVICE:
{
PhShowCreateServiceDialog(hWnd);
}
break;
case ID_TOOLS_HIDDENPROCESSES:
{
PhShowHiddenProcessesDialog();
}
break;
case ID_TOOLS_PAGEFILES:
{
PhShowPagefilesDialog(hWnd);
}
break;
case ID_TOOLS_VERIFYFILESIGNATURE:
{
static PH_FILETYPE_FILTER filters[] =
{
{ L"Executable files (*.exe;*.dll;*.ocx;*.sys;*.scr;*.cpl)", L"*.exe;*.dll;*.ocx;*.sys;*.scr;*.cpl" },
{ L"All files (*.*)", L"*.*" }
};
PVOID fileDialog = PhCreateOpenFileDialog();
PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER));
if (PhShowFileDialog(hWnd, fileDialog))
{
PPH_STRING fileName;
VERIFY_RESULT result;
PPH_STRING signerName;
fileName = PhGetFileDialogFileName(fileDialog);
result = PhVerifyFile(fileName->Buffer, &signerName);
if (result == VrTrusted)
{
PhShowInformation(hWnd, L"\"%s\" is trusted and signed by \"%s\".",
fileName->Buffer, signerName->Buffer);
}
else if (result == VrNoSignature)
{
PhShowInformation(hWnd, L"\"%s\" does not have a digital signature.",
fileName->Buffer);
}
else
{
PhShowInformation(hWnd, L"\"%s\" is not trusted.",
fileName->Buffer);
}
if (signerName)
PhDereferenceObject(signerName);
PhDereferenceObject(fileName);
}
PhFreeFileDialog(fileDialog);
}
break;
case ID_USER_CONNECT:
{
PhUiConnectSession(hWnd, SelectedUserSessionId);
}
break;
case ID_USER_DISCONNECT:
{
PhUiDisconnectSession(hWnd, SelectedUserSessionId);
}
break;
case ID_USER_LOGOFF:
{
PhUiLogoffSession(hWnd, SelectedUserSessionId);
}
break;
case ID_USER_REMOTECONTROL:
{
PhShowSessionShadowDialog(hWnd, SelectedUserSessionId);
}
break;
case ID_USER_SENDMESSAGE:
{
PhShowSessionSendMessageDialog(hWnd, SelectedUserSessionId);
}
break;
case ID_USER_PROPERTIES:
{
PhShowSessionProperties(hWnd, SelectedUserSessionId);
}
break;
case ID_HELP_LOG:
{
PhShowLogDialog();
}
break;
case ID_HELP_DONATE:
{
PhShellExecute(hWnd, L"https://sourceforge.net/project/project_donations.php?group_id=242527", NULL);
}
break;
case ID_HELP_DEBUGCONSOLE:
{
PhShowDebugConsole();
}
break;
case ID_HELP_ABOUT:
{
PhShowAboutDialog(hWnd);
}
break;
case ID_PROCESS_TERMINATE:
{
PPH_PROCESS_ITEM *processes;
ULONG numberOfProcesses;
PhpGetSelectedProcesses(&processes, &numberOfProcesses);
PhReferenceObjects(processes, numberOfProcesses);
if (PhUiTerminateProcesses(hWnd, processes, numberOfProcesses))
PhDeselectAllProcessNodes();
PhDereferenceObjects(processes, numberOfProcesses);
PhFree(processes);
}
break;
case ID_PROCESS_TERMINATETREE:
{
PPH_PROCESS_ITEM processItem = PhpGetSelectedProcess();
if (processItem)
{
PhReferenceObject(processItem);
if (PhUiTerminateTreeProcess(hWnd, processItem))
PhDeselectAllProcessNodes();
PhDereferenceObject(processItem);
}
}
break;
case ID_PROCESS_SUSPEND:
{
PPH_PROCESS_ITEM *processes;
ULONG numberOfProcesses;
PhpGetSelectedProcesses(&processes, &numberOfProcesses);
PhReferenceObjects(processes, numberOfProcesses);
PhUiSuspendProcesses(hWnd, processes, numberOfProcesses);
PhDereferenceObjects(processes, numberOfProcesses);
PhFree(processes);
}
break;
case ID_PROCESS_RESUME:
{
PPH_PROCESS_ITEM *processes;
ULONG numberOfProcesses;
PhpGetSelectedProcesses(&processes, &numberOfProcesses);
PhReferenceObjects(processes, numberOfProcesses);
PhUiResumeProcesses(hWnd, processes, numberOfProcesses);
PhDereferenceObjects(processes, numberOfProcesses);
PhFree(processes);
}
break;
case ID_PROCESS_RESTART:
{
PPH_PROCESS_ITEM processItem = PhpGetSelectedProcess();
if (processItem)
{
PhReferenceObject(processItem);
if (PhUiRestartProcess(hWnd, processItem))
PhDeselectAllProcessNodes();
PhDereferenceObject(processItem);
}
}
break;
case ID_PROCESS_DEBUG:
{
PPH_PROCESS_ITEM processItem = PhpGetSelectedProcess();
if (processItem)
{
PhReferenceObject(processItem);
PhUiDebugProcess(hWnd, processItem);
PhDereferenceObject(processItem);
}
}
break;
case ID_PROCESS_REDUCEWORKINGSET:
{
PPH_PROCESS_ITEM *processes;
ULONG numberOfProcesses;
PhpGetSelectedProcesses(&processes, &numberOfProcesses);
PhReferenceObjects(processes, numberOfProcesses);
PhUiReduceWorkingSetProcesses(hWnd, processes, numberOfProcesses);
PhDereferenceObjects(processes, numberOfProcesses);
PhFree(processes);
}
break;
case ID_PROCESS_VIRTUALIZATION:
{
PPH_PROCESS_ITEM processItem = PhpGetSelectedProcess();
if (processItem)
{
PhReferenceObject(processItem);
PhUiSetVirtualizationProcess(
hWnd,
processItem,
!SelectedProcessVirtualizationEnabled
);
PhDereferenceObject(processItem);
}
}
break;
case ID_PROCESS_AFFINITY:
{
PPH_PROCESS_ITEM processItem = PhpGetSelectedProcess();
if (processItem)
{
PhReferenceObject(processItem);
PhShowProcessAffinityDialog(hWnd, processItem, NULL);
PhDereferenceObject(processItem);
}
}
break;
case ID_PROCESS_CREATEDUMPFILE:
{
PPH_PROCESS_ITEM processItem = PhpGetSelectedProcess();
if (processItem)
{
PhReferenceObject(processItem);
PhUiCreateDumpFileProcess(hWnd, processItem);
PhDereferenceObject(processItem);
}
}
break;
case ID_PROCESS_TERMINATOR:
{
PPH_PROCESS_ITEM processItem = PhpGetSelectedProcess();
if (processItem)
{
// The object relies on the list view reference, which could
// disappear if we don't reference the object here.
PhReferenceObject(processItem);
PhShowProcessTerminatorDialog(hWnd, processItem);
PhDereferenceObject(processItem);
}
}
break;
case ID_MISCELLANEOUS_DETACHFROMDEBUGGER:
{
PPH_PROCESS_ITEM processItem = PhpGetSelectedProcess();
if (processItem)
{
PhReferenceObject(processItem);
PhUiDetachFromDebuggerProcess(hWnd, processItem);
PhDereferenceObject(processItem);
}
}
break;
case ID_MISCELLANEOUS_GDIHANDLES:
{
PPH_PROCESS_ITEM processItem = PhpGetSelectedProcess();
if (processItem)
{
PhReferenceObject(processItem);
PhShowGdiHandlesDialog(hWnd, processItem);
PhDereferenceObject(processItem);
}
}
break;
case ID_MISCELLANEOUS_HEAPS:
{
PPH_PROCESS_ITEM processItem = PhpGetSelectedProcess();
if (processItem)
{
PhReferenceObject(processItem);
PhShowProcessHeapsDialog(hWnd, processItem);
PhDereferenceObject(processItem);
}
}
break;
case ID_MISCELLANEOUS_INJECTDLL:
{
PPH_PROCESS_ITEM processItem = PhpGetSelectedProcess();
if (processItem)
{
PhReferenceObject(processItem);
PhUiInjectDllProcess(hWnd, processItem);
PhDereferenceObject(processItem);
}
}
break;
case ID_I_0:
case ID_I_1:
case ID_I_2:
case ID_I_3:
{
PPH_PROCESS_ITEM processItem = PhpGetSelectedProcess();
if (processItem)
{
ULONG ioPriority;
switch (id)
{
case ID_I_0:
ioPriority = 0;
break;
case ID_I_1:
ioPriority = 1;
break;
case ID_I_2:
ioPriority = 2;
break;
case ID_I_3:
ioPriority = 3;
break;
}
PhReferenceObject(processItem);
PhUiSetIoPriorityProcess(hWnd, processItem, ioPriority);
PhDereferenceObject(processItem);
}
}
break;
case ID_PAGEPRIORITY_1:
case ID_PAGEPRIORITY_2:
case ID_PAGEPRIORITY_3:
case ID_PAGEPRIORITY_4:
case ID_PAGEPRIORITY_5:
{
PPH_PROCESS_ITEM processItem = PhpGetSelectedProcess();
if (processItem)
{
ULONG pagePriority;
switch (id)
{
case ID_PAGEPRIORITY_1:
pagePriority = 1;
break;
case ID_PAGEPRIORITY_2:
pagePriority = 2;
break;
case ID_PAGEPRIORITY_3:
pagePriority = 3;
break;
case ID_PAGEPRIORITY_4:
pagePriority = 4;
break;
case ID_PAGEPRIORITY_5:
pagePriority = 5;
break;
}
PhReferenceObject(processItem);
PhUiSetPagePriorityProcess(hWnd, processItem, pagePriority);
PhDereferenceObject(processItem);
}
}
break;
case ID_MISCELLANEOUS_RUNAS:
{
PPH_PROCESS_ITEM processItem = PhpGetSelectedProcess();
if (processItem && processItem->FileName)
{
PhSetStringSetting2(L"RunAsProgram", &processItem->FileName->sr);
PhShowRunAsDialog(hWnd, NULL);
}
}
break;
case ID_MISCELLANEOUS_RUNASTHISUSER:
{
PPH_PROCESS_ITEM processItem = PhpGetSelectedProcess();
if (processItem)
{
PhShowRunAsDialog(hWnd, processItem->ProcessId);
}
}
break;
case ID_PRIORITY_REALTIME:
case ID_PRIORITY_HIGH:
case ID_PRIORITY_ABOVENORMAL:
case ID_PRIORITY_NORMAL:
case ID_PRIORITY_BELOWNORMAL:
case ID_PRIORITY_IDLE:
{
PPH_PROCESS_ITEM processItem = PhpGetSelectedProcess();
if (processItem)
{
PhReferenceObject(processItem);
PhpProcessProcessPriorityCommand(id, processItem);
PhDereferenceObject(processItem);
}
}
break;
case ID_WINDOW_BRINGTOFRONT:
{
if (IsWindow(SelectedProcessWindowHandle))
{
WINDOWPLACEMENT placement = { sizeof(placement) };
GetWindowPlacement(SelectedProcessWindowHandle, &placement);
if (placement.showCmd == SW_MINIMIZE)
ShowWindowAsync(SelectedProcessWindowHandle, SW_RESTORE);
else
SetForegroundWindow(SelectedProcessWindowHandle);
}
}
break;
case ID_WINDOW_RESTORE:
{
if (IsWindow(SelectedProcessWindowHandle))
{
ShowWindowAsync(SelectedProcessWindowHandle, SW_RESTORE);
}
}
break;
case ID_WINDOW_MINIMIZE:
{
if (IsWindow(SelectedProcessWindowHandle))
{
ShowWindowAsync(SelectedProcessWindowHandle, SW_MINIMIZE);
}
}
break;
case ID_WINDOW_MAXIMIZE:
{
if (IsWindow(SelectedProcessWindowHandle))
{
ShowWindowAsync(SelectedProcessWindowHandle, SW_MAXIMIZE);
}
}
break;
case ID_WINDOW_CLOSE:
{
if (IsWindow(SelectedProcessWindowHandle))
{
PostMessage(SelectedProcessWindowHandle, WM_CLOSE, 0, 0);
}
}
break;
case ID_PROCESS_PROPERTIES:
{
PPH_PROCESS_ITEM processItem = PhpGetSelectedProcess();
if (processItem)
{
// No reference needed; no messages pumped.
PhpShowProcessProperties(processItem);
}
}
break;
case ID_PROCESS_SEARCHONLINE:
{
PPH_PROCESS_ITEM processItem = PhpGetSelectedProcess();
if (processItem)
{
PhSearchOnlineString(hWnd, processItem->ProcessName->Buffer);
}
}
break;
case ID_PROCESS_COPY:
{
PhCopyProcessTree();
}
break;
case ID_SERVICE_GOTOPROCESS:
{
PPH_SERVICE_ITEM serviceItem = PhpGetSelectedService();
PPH_PROCESS_NODE processNode;
if (serviceItem)
{
if (processNode = PhFindProcessNode(serviceItem->ProcessId))
{
PhpSelectTabPage(ProcessesTabIndex);
SetFocus(ProcessTreeListHandle);
PhSelectAndEnsureVisibleProcessNode(processNode);
}
}
}
break;
case ID_SERVICE_START:
{
PPH_SERVICE_ITEM serviceItem = PhpGetSelectedService();
if (serviceItem)
{
PhReferenceObject(serviceItem);
PhUiStartService(hWnd, serviceItem);
PhDereferenceObject(serviceItem);
}
}
break;
case ID_SERVICE_CONTINUE:
{
PPH_SERVICE_ITEM serviceItem = PhpGetSelectedService();
if (serviceItem)
{
PhReferenceObject(serviceItem);
PhUiContinueService(hWnd, serviceItem);
PhDereferenceObject(serviceItem);
}
}
break;
case ID_SERVICE_PAUSE:
{
PPH_SERVICE_ITEM serviceItem = PhpGetSelectedService();
if (serviceItem)
{
PhReferenceObject(serviceItem);
PhUiPauseService(hWnd, serviceItem);
PhDereferenceObject(serviceItem);
}
}
break;
case ID_SERVICE_STOP:
{
PPH_SERVICE_ITEM serviceItem = PhpGetSelectedService();
if (serviceItem)
{
PhReferenceObject(serviceItem);
PhUiStopService(hWnd, serviceItem);
PhDereferenceObject(serviceItem);
}
}
break;
case ID_SERVICE_DELETE:
{
PPH_SERVICE_ITEM serviceItem = PhpGetSelectedService();
if (serviceItem)
{
PhReferenceObject(serviceItem);
if (PhUiDeleteService(hWnd, serviceItem))
PhDeselectAllServiceNodes();
PhDereferenceObject(serviceItem);
}
}
break;
case ID_SERVICE_PROPERTIES:
{
PPH_SERVICE_ITEM serviceItem = PhpGetSelectedService();
if (serviceItem)
{
// The object relies on the list view reference, which could
// disappear if we don't reference the object here.
PhReferenceObject(serviceItem);
PhShowServiceProperties(hWnd, serviceItem);
PhDereferenceObject(serviceItem);
}
}
break;
case ID_SERVICE_COPY:
{
PhCopyServiceList();
}
break;
case ID_NETWORK_GOTOPROCESS:
{
PPH_NETWORK_ITEM networkItem = PhpGetSelectedNetworkItem();
PPH_PROCESS_NODE processNode;
if (networkItem)
{
if (processNode = PhFindProcessNode(networkItem->ProcessId))
{
PhpSelectTabPage(ProcessesTabIndex);
SetFocus(ProcessTreeListHandle);
PhSelectAndEnsureVisibleProcessNode(processNode);
}
}
}
break;
case ID_NETWORK_VIEWSTACK:
{
PPH_NETWORK_ITEM networkItem = PhpGetSelectedNetworkItem();
if (networkItem)
{
PhReferenceObject(networkItem);
PhShowNetworkStackDialog(hWnd, networkItem);
PhDereferenceObject(networkItem);
}
}
break;
case ID_NETWORK_CLOSE:
{
PPH_NETWORK_ITEM *networkItems;
ULONG numberOfNetworkItems;
PhpGetSelectedNetworkItems(&networkItems, &numberOfNetworkItems);
PhReferenceObjects(networkItems, numberOfNetworkItems);
if (PhUiCloseConnections(hWnd, networkItems, numberOfNetworkItems))
PhSetStateAllListViewItems(NetworkListViewHandle, 0, LVIS_SELECTED);
PhDereferenceObjects(networkItems, numberOfNetworkItems);
PhFree(networkItems);
}
break;
case ID_NETWORK_COPY:
{
PhCopyListView(NetworkListViewHandle);
}
break;
case ID_TAB_NEXT:
{
ULONG selectedIndex = TabCtrl_GetCurSel(TabControlHandle);
if (selectedIndex != MaxTabIndex)
selectedIndex++;
else
selectedIndex = 0;
PhpSelectTabPage(selectedIndex);
SetFocus(TabControlHandle);
}
break;
case ID_TAB_PREV:
{
ULONG selectedIndex = TabCtrl_GetCurSel(TabControlHandle);
if (selectedIndex != 0)
selectedIndex--;
else
selectedIndex = MaxTabIndex;
PhpSelectTabPage(selectedIndex);
SetFocus(TabControlHandle);
}
break;
}
if (PhPluginsEnabled)
{
if (id >= IDPLUGINS && id < IDPLUGINS_END)
{
if (SelectedMenuItemPlugin && SelectedMenuItemPlugin->RealId == (ULONG)id)
{
SelectedMenuItemPlugin->OwnerWindow = hWnd;
PhInvokeCallback(
PhGetPluginCallback(SelectedMenuItemPlugin->Plugin, PluginCallbackMenuItem),
SelectedMenuItemPlugin
);
}
}
}
}
break;
case WM_SHOWWINDOW:
{
if (NeedsMaximize)
{
ShowWindow(hWnd, SW_MAXIMIZE);
NeedsMaximize = FALSE;
}
}
break;
case WM_SYSCOMMAND:
{
switch (wParam)
{
case SC_CLOSE:
{
if (PhGetIntegerSetting(L"HideOnClose") && NotifyIconMask != 0)
{
ShowWindow(hWnd, SW_HIDE);
return 0;
}
}
break;
case SC_MINIMIZE:
{
// Save the current window state because we
// may not have a chance to later.
PhpSaveWindowState();
if (PhGetIntegerSetting(L"HideOnMinimize") && NotifyIconMask != 0)
{
ShowWindow(hWnd, SW_HIDE);
return 0;
}
}
break;
}
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
case WM_MENUSELECT:
{
switch (LOWORD(wParam))
{
case ID_USER_CONNECT:
case ID_USER_DISCONNECT:
case ID_USER_LOGOFF:
case ID_USER_SENDMESSAGE:
case ID_USER_PROPERTIES:
{
MENUITEMINFO menuItemInfo = { sizeof(menuItemInfo) };
menuItemInfo.fMask = MIIM_DATA;
if (GetMenuItemInfo((HMENU)lParam, LOWORD(wParam), FALSE, &menuItemInfo))
{
SelectedUserSessionId = (ULONG)menuItemInfo.dwItemData;
}
}
break;
}
if (PhPluginsEnabled)
{
USHORT id = LOWORD(wParam);
if (id >= IDPLUGINS && id < IDPLUGINS_END)
{
MENUITEMINFO menuItemInfo = { sizeof(menuItemInfo) };
menuItemInfo.fMask = MIIM_DATA;
if (GetMenuItemInfo((HMENU)lParam, LOWORD(wParam), FALSE, &menuItemInfo))
{
SelectedMenuItemPlugin = (PPH_PLUGIN_MENU_ITEM)menuItemInfo.dwItemData;
}
}
}
}
break;
case WM_SIZE:
{
if (!IsIconic(hWnd))
{
HDWP deferHandle = BeginDeferWindowPos(2);
PhMainWndOnLayout(&deferHandle);
EndDeferWindowPos(deferHandle);
}
}
break;
case WM_SIZING:
{
PhResizingMinimumSize((PRECT)lParam, wParam, 400, 340);
}
break;
case WM_SETFOCUS:
{
INT selectedIndex = TabCtrl_GetCurSel(TabControlHandle);
if (selectedIndex == ProcessesTabIndex)
SetFocus(ProcessTreeListHandle);
else if (selectedIndex == ServicesTabIndex)
SetFocus(ServiceTreeListHandle);
else if (selectedIndex == NetworkTabIndex)
SetFocus(NetworkListViewHandle);
}
break;
case WM_NOTIFY:
{
LPNMHDR header = (LPNMHDR)lParam;
if (header->hwndFrom == TabControlHandle)
{
PhMainWndTabControlOnNotify(header);
}
else if (header->hwndFrom == NetworkListViewHandle)
{
PhMainWndNetworkListViewOnNotify(header);
}
else if (header->code == RFN_VALIDATE)
{
LPNMRUNFILEDLG runFileDlg = (LPNMRUNFILEDLG)header;
if (SelectedRunAsMode == RUNAS_MODE_ADMIN)
{
if (PhShellExecuteEx(hWnd, (PWSTR)runFileDlg->lpszFile,
NULL, runFileDlg->nShow, PH_SHELL_EXECUTE_ADMIN, 0, NULL))
{
return RF_CANCEL;
}
else
{
return RF_RETRY;
}
}
else if (SelectedRunAsMode == RUNAS_MODE_LIMITED)
{
NTSTATUS status;
HANDLE tokenHandle;
HANDLE newTokenHandle;
if (NT_SUCCESS(status = NtOpenProcessToken(
NtCurrentProcess(),
TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY | TOKEN_ADJUST_GROUPS |
TOKEN_ADJUST_DEFAULT | READ_CONTROL | WRITE_DAC,
&tokenHandle
)))
{
if (NT_SUCCESS(status = PhFilterTokenForLimitedUser(
tokenHandle,
&newTokenHandle
)))
{
status = PhCreateProcessWin32(
NULL,
(PWSTR)runFileDlg->lpszFile,
NULL,
NULL,
0,
newTokenHandle,
NULL,
NULL
);
NtClose(newTokenHandle);
}
NtClose(tokenHandle);
}
if (NT_SUCCESS(status))
{
return RF_CANCEL;
}
else
{
PhShowStatus(hWnd, L"Unable to execute the program", status, 0);
return RF_RETRY;
}
}
}
}
break;
case WM_CONTEXTMENU:
{
if ((HWND)wParam == NetworkListViewHandle)
{
PhMainWndNetworkListViewOnContextMenu(lParam);
}
}
break;
case WM_WTSSESSION_CHANGE:
{
if (wParam == WTS_SESSION_LOGON || wParam == WTS_SESSION_LOGOFF)
{
PhpRefreshUsersMenu();
}
}
break;
case WM_PH_ACTIVATE:
{
if (!PhMainWndExiting)
{
if (!IsWindowVisible(hWnd))
{
ShowWindow(hWnd, SW_SHOW);
}
if (IsIconic(hWnd))
{
ShowWindow(hWnd, SW_RESTORE);
}
return PH_ACTIVATE_REPLY;
}
else
{
return 0;
}
}
break;
case WM_PH_SHOW_PROCESS_PROPERTIES:
{
PhpShowProcessProperties((PPH_PROCESS_ITEM)lParam);
}
break;
case WM_PH_DESTROY:
{
DestroyWindow(hWnd);
}
break;
case WM_PH_SAVE_ALL_SETTINGS:
{
PhpSaveAllSettings();
}
break;
case WM_PH_PREPARE_FOR_EARLY_SHUTDOWN:
{
PhpPrepareForEarlyShutdown();
}
break;
case WM_PH_CANCEL_EARLY_SHUTDOWN:
{
PhpCancelEarlyShutdown();
}
break;
case WM_PH_DELAYED_LOAD_COMPLETED:
{
// Nothing
}
break;
case WM_PH_NOTIFY_ICON_MESSAGE:
{
switch (LOWORD(lParam))
{
case WM_LBUTTONDOWN:
{
if (PhGetIntegerSetting(L"IconSingleClick"))
SendMessage(hWnd, WM_PH_TOGGLE_VISIBLE, 0, 0);
}
break;
case WM_LBUTTONDBLCLK:
{
if (!PhGetIntegerSetting(L"IconSingleClick"))
SendMessage(hWnd, WM_PH_TOGGLE_VISIBLE, 0, 0);
}
break;
case WM_RBUTTONUP:
{
POINT location;
GetCursorPos(&location);
PhpShowIconContextMenu(location);
}
break;
}
}
break;
case WM_PH_TOGGLE_VISIBLE:
{
if (IsIconic(PhMainWndHandle))
{
ShowWindow(PhMainWndHandle, SW_RESTORE);
SetForegroundWindow(PhMainWndHandle);
}
else if (IsWindowVisible(PhMainWndHandle))
{
ShowWindow(PhMainWndHandle, SW_HIDE);
}
else
{
ShowWindow(PhMainWndHandle, SW_SHOW);
SetForegroundWindow(PhMainWndHandle);
}
}
break;
case WM_PH_SHOW_MEMORY_EDITOR:
{
PPH_SHOWMEMORYEDITOR showMemoryEditor = (PPH_SHOWMEMORYEDITOR)lParam;
PhShowMemoryEditorDialog(
showMemoryEditor->ProcessId,
showMemoryEditor->BaseAddress,
showMemoryEditor->RegionSize,
showMemoryEditor->SelectOffset,
showMemoryEditor->SelectLength
);
PhFree(showMemoryEditor);
}
break;
case WM_PH_SHOW_MEMORY_RESULTS:
{
PPH_SHOWMEMORYRESULTS showMemoryResults = (PPH_SHOWMEMORYRESULTS)lParam;
PhShowMemoryResultsDialog(
showMemoryResults->ProcessId,
showMemoryResults->Results
);
PhDereferenceMemoryResults(
(PPH_MEMORY_RESULT *)showMemoryResults->Results->Items,
showMemoryResults->Results->Count
);
PhDereferenceObject(showMemoryResults->Results);
PhFree(showMemoryResults);
}
break;
case WM_PH_SELECT_TAB_PAGE:
{
ULONG index = (ULONG)wParam;
PhpSelectTabPage(index);
if (index == ProcessesTabIndex)
SetFocus(ProcessTreeListHandle);
else if (index == ServicesTabIndex)
SetFocus(ServiceTreeListHandle);
else if (index == NetworkTabIndex)
SetFocus(NetworkListViewHandle);
}
break;
case WM_PH_GET_LAYOUT_PADDING:
{
PRECT rect = (PRECT)lParam;
*rect = LayoutPadding;
}
break;
case WM_PH_SET_LAYOUT_PADDING:
{
PRECT rect = (PRECT)lParam;
LayoutPadding = *rect;
}
break;
case WM_PH_SELECT_PROCESS_NODE:
{
PhSelectAndEnsureVisibleProcessNode((PPH_PROCESS_NODE)lParam);
}
break;
case WM_PH_SELECT_SERVICE_ITEM:
{
PPH_SERVICE_NODE serviceNode;
PhpNeedServiceTreeList();
// For compatibility, lParam is a service item, not node.
if (serviceNode = PhFindServiceNode((PPH_SERVICE_ITEM)lParam))
{
PhSelectAndEnsureVisibleServiceNode(serviceNode);
}
}
break;
case WM_PH_SELECT_NETWORK_ITEM:
{
INT lvItemIndex;
PhSetStateAllListViewItems(NetworkListViewHandle, 0, LVIS_SELECTED);
lvItemIndex = PhFindListViewItemByParam(NetworkListViewHandle, -1, (PVOID)lParam);
if (lvItemIndex != -1)
{
ListView_SetItemState(NetworkListViewHandle, lvItemIndex,
LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
}
}
break;
case WM_PH_UPDATE_FONT:
{
PPH_STRING fontHexString;
LOGFONT font;
fontHexString = PhGetStringSetting(L"Font");
if (
fontHexString->Length / 2 / 2 == sizeof(LOGFONT) &&
PhHexStringToBuffer(&fontHexString->sr, (PUCHAR)&font)
)
{
HFONT newFont;
newFont = CreateFontIndirect(&font);
if (newFont)
{
if (CurrentCustomFont)
DeleteObject(CurrentCustomFont);
CurrentCustomFont = newFont;
SendMessage(ProcessTreeListHandle, WM_SETFONT, (WPARAM)newFont, TRUE);
SendMessage(ServiceTreeListHandle, WM_SETFONT, (WPARAM)newFont, TRUE);
SendMessage(NetworkListViewHandle, WM_SETFONT, (WPARAM)newFont, TRUE);
}
}
PhDereferenceObject(fontHexString);
}
break;
case WM_PH_GET_FONT:
return SendMessage(ProcessTreeListHandle, WM_GETFONT, 0, 0);
case WM_PH_INVOKE:
{
VOID (NTAPI *function)(PVOID);
function = (PVOID)lParam;
function((PVOID)wParam);
}
break;
case WM_PH_ADD_MENU_ITEM:
{
PPH_ADDMENUITEM addMenuItem = (PPH_ADDMENUITEM)lParam;
return (LRESULT)PhpMainWndAddMenuItem(
addMenuItem->Plugin,
addMenuItem->ParentMenu,
addMenuItem->InsertAfter,
addMenuItem->Flags,
addMenuItem->Id,
addMenuItem->Text,
addMenuItem->Context
);
}
break;
case WM_PH_ADD_TAB_PAGE:
{
return (LRESULT)PhpAddTabPage((PPH_ADDITIONAL_TAB_PAGE)lParam);
}
break;
case WM_PH_PROCESS_ADDED:
{
ULONG runId = (ULONG)wParam;
PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)lParam;
PhMainWndOnProcessAdded(processItem, runId);
}
break;
case WM_PH_PROCESS_MODIFIED:
{
PhMainWndOnProcessModified((PPH_PROCESS_ITEM)lParam);
}
break;
case WM_PH_PROCESS_REMOVED:
{
PhMainWndOnProcessRemoved((PPH_PROCESS_ITEM)lParam);
}
break;
case WM_PH_PROCESSES_UPDATED:
{
PhMainWndOnProcessesUpdated();
}
break;
case WM_PH_SERVICE_ADDED:
{
ULONG runId = (ULONG)wParam;
PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)lParam;
PhMainWndOnServiceAdded(serviceItem, runId);
}
break;
case WM_PH_SERVICE_MODIFIED:
{
PPH_SERVICE_MODIFIED_DATA serviceModifiedData = (PPH_SERVICE_MODIFIED_DATA)lParam;
PhMainWndOnServiceModified(serviceModifiedData);
PhFree(serviceModifiedData);
}
break;
case WM_PH_SERVICE_REMOVED:
{
PhMainWndOnServiceRemoved((PPH_SERVICE_ITEM)lParam);
}
break;
case WM_PH_SERVICES_UPDATED:
{
PhMainWndOnServicesUpdated();
}
break;
case WM_PH_NETWORK_ITEM_ADDED:
{
ULONG runId = (ULONG)wParam;
PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)lParam;
PhMainWndOnNetworkItemAdded(runId, networkItem);
PhDereferenceObject(networkItem);
}
break;
case WM_PH_NETWORK_ITEM_MODIFIED:
{
PhMainWndOnNetworkItemModified((PPH_NETWORK_ITEM)lParam);
}
break;
case WM_PH_NETWORK_ITEM_REMOVED:
{
PhMainWndOnNetworkItemRemoved((PPH_NETWORK_ITEM)lParam);
}
break;
case WM_PH_NETWORK_ITEMS_UPDATED:
{
PhMainWndOnNetworkItemsUpdated();
}
break;
}
REFLECT_MESSAGE(NetworkListViewHandle, uMsg, wParam, lParam);
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
VOID PhpReloadListViewFont()
{
HFONT fontHandle;
LOGFONT font;
if (NetworkListViewHandle && (fontHandle = (HFONT)SendMessage(NetworkListViewHandle, WM_GETFONT, 0, 0)))
{
if (GetObject(fontHandle, sizeof(LOGFONT), &font))
{
font.lfWeight = FW_BOLD;
fontHandle = CreateFontIndirect(&font);
if (fontHandle)
{
if (PhBoldListViewFont)
DeleteObject(PhBoldListViewFont);
PhBoldListViewFont = fontHandle;
}
}
}
}
VOID PhReloadSysParameters()
{
PhSysWindowColor = GetSysColor(COLOR_WINDOW);
if (PhApplicationFont)
DeleteObject(PhApplicationFont);
if (PhBoldMessageFont)
DeleteObject(PhBoldMessageFont);
PhInitializeFont(PhMainWndHandle);
SendMessage(TabControlHandle, WM_SETFONT, (WPARAM)PhApplicationFont, FALSE);
PhpReloadListViewFont();
}
VOID PhpInitialLoadSettings()
{
ULONG opacity;
ULONG id;
PPH_STRING customFont;
ULONG i;
if (PhGetIntegerSetting(L"MainWindowAlwaysOnTop"))
{
CheckMenuItem(PhMainWndMenuHandle, ID_VIEW_ALWAYSONTOP, MF_CHECKED);
SetWindowPos(PhMainWndHandle, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE);
}
opacity = PhGetIntegerSetting(L"MainWindowOpacity");
if (opacity != 0)
PhpSetWindowOpacity(opacity);
PhpSetCheckOpacityMenu(TRUE, opacity);
switch (PhGetIntegerSetting(L"UpdateInterval"))
{
case 500:
id = ID_UPDATEINTERVAL_FAST;
break;
case 1000:
id = ID_UPDATEINTERVAL_NORMAL;
break;
case 2000:
id = ID_UPDATEINTERVAL_BELOWNORMAL;
break;
case 5000:
id = ID_UPDATEINTERVAL_SLOW;
break;
case 10000:
id = ID_UPDATEINTERVAL_VERYSLOW;
break;
default:
id = -1;
break;
}
if (id != -1)
{
CheckMenuRadioItem(
PhMainWndMenuHandle,
ID_UPDATEINTERVAL_FAST,
ID_UPDATEINTERVAL_VERYSLOW,
id,
MF_BYCOMMAND
);
}
PhStatisticsSampleCount = PhGetIntegerSetting(L"SampleCount");
PhEnableProcessQueryStage2 = !!PhGetIntegerSetting(L"EnableStage2");
PhEnablePurgeProcessRecords = !PhGetIntegerSetting(L"NoPurgeProcessRecords");
PhEnableServiceNonPoll = !!PhGetIntegerSetting(L"EnableServiceNonPoll");
PhEnableNetworkProviderResolve = !!PhGetIntegerSetting(L"EnableNetworkResolve");
NotifyIconMask = PhGetIntegerSetting(L"IconMask");
for (i = PH_ICON_MINIMUM; i != PH_ICON_MAXIMUM; i <<= 1)
{
if (NotifyIconMask & i)
{
switch (i)
{
case PH_ICON_CPU_HISTORY:
id = ID_TRAYICONS_CPUHISTORY;
break;
case PH_ICON_IO_HISTORY:
id = ID_TRAYICONS_IOHISTORY;
break;
case PH_ICON_COMMIT_HISTORY:
id = ID_TRAYICONS_COMMITHISTORY;
break;
case PH_ICON_PHYSICAL_HISTORY:
id = ID_TRAYICONS_PHYSICALMEMORYHISTORY;
break;
case PH_ICON_CPU_USAGE:
id = ID_TRAYICONS_CPUUSAGE;
break;
}
CheckMenuItem(PhMainWndMenuHandle, id, MF_CHECKED);
}
}
NotifyIconNotifyMask = PhGetIntegerSetting(L"IconNotifyMask");
if (PhGetIntegerSetting(L"HideOtherUserProcesses"))
{
CurrentUserFilterEntry = PhAddProcessTreeFilter(PhpCurrentUserProcessTreeFilter, NULL);
CheckMenuItem(PhMainWndMenuHandle, ID_VIEW_HIDEPROCESSESFROMOTHERUSERS, MF_CHECKED);
}
if (PhGetIntegerSetting(L"HideSignedProcesses"))
{
SignedFilterEntry = PhAddProcessTreeFilter(PhpSignedProcessTreeFilter, NULL);
CheckMenuItem(PhMainWndMenuHandle, ID_VIEW_HIDESIGNEDPROCESSES, MF_CHECKED);
}
customFont = PhGetStringSetting(L"Font");
if (customFont->Length / 2 / 2 == sizeof(LOGFONT))
SendMessage(PhMainWndHandle, WM_PH_UPDATE_FONT, 0, 0);
PhDereferenceObject(customFont);
PhLoadSettingsProcessTreeList();
// Service list settings are loaded on demand.
PhLoadListViewColumnsFromSetting(L"NetworkListViewColumns", NetworkListViewHandle);
}
VOID PhMainSymInitHandler(
__in_opt PVOID Parameter,
__in_opt PVOID Context
)
{
PPH_STRING dbghelpPath;
HMODULE dbghelpModule;
dbghelpPath = PhGetStringSetting(L"DbgHelpPath");
if (dbghelpModule = LoadLibrary(dbghelpPath->Buffer))
{
PPH_STRING fullDbghelpPath;
ULONG indexOfFileName;
PH_STRINGREF dbghelpFolder;
PPH_STRING symsrvPath;
fullDbghelpPath = PhGetDllFileName(dbghelpModule, &indexOfFileName);
if (fullDbghelpPath)
{
if (indexOfFileName != -1)
{
static PH_STRINGREF symsrvString = PH_STRINGREF_INIT(L"\\symsrv.dll");
dbghelpFolder.Buffer = fullDbghelpPath->Buffer;
dbghelpFolder.Length = (USHORT)(indexOfFileName * sizeof(WCHAR));
symsrvPath = PhConcatStringRef2(&dbghelpFolder, &symsrvString);
LoadLibrary(symsrvPath->Buffer);
PhDereferenceObject(symsrvPath);
}
PhDereferenceObject(fullDbghelpPath);
}
}
else
{
LoadLibrary(L"dbghelp.dll");
}
PhDereferenceObject(dbghelpPath);
PhSymbolProviderDynamicImport();
}
static NTSTATUS PhpDelayedLoadFunction(
__in PVOID Parameter
)
{
ULONG i;
// Register for window station notifications.
WinStationRegisterConsoleNotification(NULL, PhMainWndHandle, WNOTIFY_ALL_SESSIONS);
for (i = PH_ICON_MINIMUM; i != PH_ICON_MAXIMUM; i <<= 1)
{
if (NotifyIconMask & i)
PhAddNotifyIcon(i);
}
// Make sure we get closed late in the shutdown process.
SetProcessShutdownParameters(0x100, 0);
DelayedLoadCompleted = TRUE;
//PostMessage(PhMainWndHandle, WM_PH_DELAYED_LOAD_COMPLETED, 0, 0);
return STATUS_SUCCESS;
}
VOID PhpSaveWindowState()
{
WINDOWPLACEMENT placement = { sizeof(placement) };
GetWindowPlacement(PhMainWndHandle, &placement);
if (placement.showCmd == SW_NORMAL)
PhSetIntegerSetting(L"MainWindowState", SW_NORMAL);
else if (placement.showCmd == SW_MAXIMIZE)
PhSetIntegerSetting(L"MainWindowState", SW_MAXIMIZE);
}
VOID PhpSaveAllSettings()
{
PhSaveSettingsProcessTreeList();
if (ServiceTreeListLoaded)
PhSaveSettingsServiceTreeList();
PhSaveListViewColumnsToSetting(L"NetworkListViewColumns", NetworkListViewHandle);
PhSetIntegerSetting(L"IconMask", NotifyIconMask);
PhSetIntegerSetting(L"IconNotifyMask", NotifyIconNotifyMask);
PhSaveWindowPlacementToSetting(L"MainWindowPosition", L"MainWindowSize", PhMainWndHandle);
PhpSaveWindowState();
if (PhSettingsFileName)
PhSaveSettings(PhSettingsFileName->Buffer);
}
VOID PhpSetCheckOpacityMenu(
__in BOOLEAN AssumeAllUnchecked,
__in ULONG Opacity
)
{
// The setting is stored backwards - 0 means opaque, 100 means transparent.
CheckMenuRadioItem(
PhMainWndMenuHandle,
ID_OPACITY_10,
ID_OPACITY_OPAQUE,
ID_OPACITY_10 + (10 - Opacity / 10) - 1,
MF_BYCOMMAND
);
}
VOID PhpSetWindowOpacity(
__in ULONG Opacity
)
{
if (Opacity == 0)
{
// Make things a bit faster by removing the WS_EX_LAYERED bit.
PhSetWindowExStyle(PhMainWndHandle, WS_EX_LAYERED, 0);
RedrawWindow(PhMainWndHandle, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);
return;
}
PhSetWindowExStyle(PhMainWndHandle, WS_EX_LAYERED, WS_EX_LAYERED);
// Disallow opacity values of less than 10%.
if (Opacity > 90)
return;
SetLayeredWindowAttributes(
PhMainWndHandle,
0,
(BYTE)(255 * (100 - Opacity) / 100),
LWA_ALPHA
);
}
VOID PhpSelectTabPage(
__in ULONG Index
)
{
TabCtrl_SetCurSel(TabControlHandle, Index);
PhMainWndTabControlOnSelectionChanged();
}
VOID PhpPrepareForEarlyShutdown()
{
PhpSaveAllSettings();
PhMainWndExiting = TRUE;
}
VOID PhpCancelEarlyShutdown()
{
PhMainWndExiting = FALSE;
}
VOID PhpNeedServiceTreeList()
{
if (!ServiceTreeListLoaded)
{
ServiceTreeListLoaded = TRUE;
PhLoadSettingsServiceTreeList();
if (ServicesPendingList)
{
PPH_SERVICE_ITEM serviceItem;
ULONG enumerationKey = 0;
while (PhEnumPointerList(ServicesPendingList, &enumerationKey, (PPVOID)&serviceItem))
{
PhMainWndOnServiceAdded(serviceItem, 1);
}
// Force a re-draw.
PhMainWndOnServicesUpdated();
PhSwapReference(&ServicesPendingList, NULL);
}
}
}
BOOLEAN PhpProcessComputerCommand(
__in ULONG Id
)
{
switch (Id)
{
case ID_COMPUTER_LOCK:
PhUiLockComputer(PhMainWndHandle);
return TRUE;
case ID_COMPUTER_LOGOFF:
PhUiLogoffComputer(PhMainWndHandle);
return TRUE;
case ID_COMPUTER_SLEEP:
PhUiSleepComputer(PhMainWndHandle);
return TRUE;
case ID_COMPUTER_HIBERNATE:
PhUiHibernateComputer(PhMainWndHandle);
return TRUE;
case ID_COMPUTER_RESTART:
PhUiRestartComputer(PhMainWndHandle);
return TRUE;
case ID_COMPUTER_SHUTDOWN:
PhUiShutdownComputer(PhMainWndHandle);
return TRUE;
case ID_COMPUTER_POWEROFF:
PhUiPoweroffComputer(PhMainWndHandle);
return TRUE;
}
return FALSE;
}
BOOLEAN PhpProcessProcessPriorityCommand(
__in ULONG Id,
__in PPH_PROCESS_ITEM ProcessItem
)
{
ULONG priorityClass;
switch (Id)
{
case ID_PRIORITY_REALTIME:
priorityClass = PROCESS_PRIORITY_CLASS_REALTIME;
break;
case ID_PRIORITY_HIGH:
priorityClass = PROCESS_PRIORITY_CLASS_HIGH;
break;
case ID_PRIORITY_ABOVENORMAL:
priorityClass = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL;
break;
case ID_PRIORITY_NORMAL:
priorityClass = PROCESS_PRIORITY_CLASS_NORMAL;
break;
case ID_PRIORITY_BELOWNORMAL:
priorityClass = PROCESS_PRIORITY_CLASS_BELOW_NORMAL;
break;
case ID_PRIORITY_IDLE:
priorityClass = PROCESS_PRIORITY_CLASS_IDLE;
break;
default:
return FALSE;
}
PhUiSetPriorityProcess(PhMainWndHandle, ProcessItem, priorityClass);
return TRUE;
}
VOID PhpRefreshUsersMenu()
{
HMENU menu;
PSESSIONIDW sessions;
ULONG numberOfSessions;
ULONG i;
ULONG j;
MENUITEMINFO menuItemInfo = { sizeof(MENUITEMINFO) };
menu = GetSubMenu(PhMainWndMenuHandle, 3);
// Delete all items in the Users menu.
while (DeleteMenu(menu, 0, MF_BYPOSITION)) ;
if (WinStationEnumerateW(NULL, &sessions, &numberOfSessions))
{
for (i = 0; i < numberOfSessions; i++)
{
HMENU userMenu;
PPH_STRING menuText;
PPH_STRING escapedMenuText;
WINSTATIONINFORMATION winStationInfo;
ULONG returnLength;
ULONG numberOfItems;
if (!WinStationQueryInformationW(
NULL,
sessions[i].SessionId,
WinStationInformation,
&winStationInfo,
sizeof(WINSTATIONINFORMATION),
&returnLength
))
{
winStationInfo.Domain[0] = 0;
winStationInfo.UserName[0] = 0;
}
if (winStationInfo.Domain[0] == 0 || winStationInfo.UserName[0] == 0)
{
// Probably the Services or RDP-Tcp session.
continue;
}
menuText = PhFormatString(
L"%u: %s\\%s",
sessions[i].SessionId,
winStationInfo.Domain,
winStationInfo.UserName
);
escapedMenuText = PhEscapeStringForMenuPrefix(&menuText->sr);
PhDereferenceObject(menuText);
userMenu = GetSubMenu(LoadMenu(PhInstanceHandle, MAKEINTRESOURCE(IDR_USER)), 0);
AppendMenu(
menu,
MF_STRING | MF_POPUP,
(UINT_PTR)userMenu,
escapedMenuText->Buffer
);
PhDereferenceObject(escapedMenuText);
menuItemInfo.fMask = MIIM_DATA;
menuItemInfo.dwItemData = sessions[i].SessionId;
numberOfItems = GetMenuItemCount(userMenu);
if (numberOfItems != -1)
{
for (j = 0; j < numberOfItems; j++)
SetMenuItemInfo(userMenu, j, TRUE, &menuItemInfo);
}
}
WinStationFreeMemory(sessions);
}
DrawMenuBar(PhMainWndHandle);
}
static int __cdecl IconProcessesCpuUsageCompare(
__in const void *elem1,
__in const void *elem2
)
{
PPH_PROCESS_ITEM processItem1 = *(PPH_PROCESS_ITEM *)elem1;
PPH_PROCESS_ITEM processItem2 = *(PPH_PROCESS_ITEM *)elem2;
return -singlecmp(processItem1->CpuUsage, processItem2->CpuUsage);
}
static int __cdecl IconProcessesNameCompare(
__in const void *elem1,
__in const void *elem2
)
{
PPH_PROCESS_ITEM processItem1 = *(PPH_PROCESS_ITEM *)elem1;
PPH_PROCESS_ITEM processItem2 = *(PPH_PROCESS_ITEM *)elem2;
return PhCompareString(processItem1->ProcessName, processItem2->ProcessName, TRUE);
}
VOID PhpAddIconProcesses(
__in PPH_EMENU_ITEM Menu,
__in ULONG NumberOfProcesses
)
{
ULONG i;
PPH_PROCESS_ITEM *processItems;
ULONG numberOfProcessItems;
PPH_LIST processList;
PPH_PROCESS_ITEM processItem;
PhEnumProcessItems(&processItems, &numberOfProcessItems);
processList = PhCreateList(numberOfProcessItems);
PhAddItemsList(processList, processItems, numberOfProcessItems);
// Remove non-real processes.
for (i = 0; i < processList->Count; i++)
{
processItem = processList->Items[i];
if (!PH_IS_REAL_PROCESS_ID(processItem->ProcessId))
{
PhRemoveItemList(processList, i);
i--;
}
}
// Remove processes with zero CPU usage and those running as other users.
for (i = 0; i < processList->Count && processList->Count > NumberOfProcesses; i++)
{
processItem = processList->Items[i];
if (
processItem->CpuUsage == 0 ||
!processItem->UserName ||
(PhCurrentUserName && !PhEqualString(processItem->UserName, PhCurrentUserName, TRUE))
)
{
PhRemoveItemList(processList, i);
i--;
}
}
// Sort the processes by CPU usage and remove the extra processes at the end of the list.
qsort(processList->Items, processList->Count, sizeof(PVOID), IconProcessesCpuUsageCompare);
if (processList->Count > NumberOfProcesses)
{
PhRemoveItemsList(processList, NumberOfProcesses, processList->Count - NumberOfProcesses);
}
// Lastly, sort by name.
qsort(processList->Items, processList->Count, sizeof(PVOID), IconProcessesNameCompare);
// Delete all menu items.
PhRemoveAllEMenuItems(Menu);
// Add the processes.
for (i = 0; i < processList->Count; i++)
{
PPH_EMENU_ITEM subMenu;
PPH_EMENU_ITEM priorityMenu;
HBITMAP iconBitmap;
CLIENT_ID clientId;
PPH_STRING clientIdName;
PPH_STRING escapedName;
processItem = processList->Items[i];
// Priority
priorityMenu = PhCreateEMenuItem(0, 0, L"Priority", NULL, NULL);
PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_REALTIME, L"Real Time", NULL, NULL), -1);
PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_HIGH, L"High", NULL, NULL), -1);
PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_ABOVENORMAL, L"Above Normal", NULL, NULL), -1);
PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_NORMAL, L"Normal", NULL, NULL), -1);
PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_BELOWNORMAL, L"Below Normal", NULL, NULL), -1);
PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_IDLE, L"Idle", NULL, NULL), -1);
PhpSetProcessMenuPriorityChecks(priorityMenu, processItem, TRUE, FALSE, FALSE);
// Process
clientId.UniqueProcess = processItem->ProcessId;
clientId.UniqueThread = NULL;
clientIdName = PhGetClientIdName(&clientId);
escapedName = PhEscapeStringForMenuPrefix(&clientIdName->sr);
PhDereferenceObject(clientIdName);
PhaDereferenceObject(escapedName);
subMenu = PhCreateEMenuItem(
0,
0,
escapedName->Buffer,
NULL,
processItem->ProcessId
);
// Menu icons only work properly on Vista and above.
if (WindowsVersion >= WINDOWS_VISTA)
{
if (processItem->SmallIcon)
{
iconBitmap = PhIconToBitmap(processItem->SmallIcon, PhSmallIconSize.X, PhSmallIconSize.Y);
}
else
{
HICON icon;
PhGetStockApplicationIcon(&icon, NULL);
iconBitmap = PhIconToBitmap(icon, PhSmallIconSize.X, PhSmallIconSize.Y);
}
}
else
{
iconBitmap = NULL;
}
subMenu->Bitmap = iconBitmap;
subMenu->Flags |= PH_EMENU_BITMAP_OWNED; // automatically destroy the bitmap when necessary
PhInsertEMenuItem(subMenu, PhCreateEMenuItem(0, ID_PROCESS_TERMINATE, L"Terminate", NULL, NULL), -1);
PhInsertEMenuItem(subMenu, PhCreateEMenuItem(0, ID_PROCESS_SUSPEND, L"Suspend", NULL, NULL), -1);
PhInsertEMenuItem(subMenu, PhCreateEMenuItem(0, ID_PROCESS_RESUME, L"Resume", NULL, NULL), -1);
PhInsertEMenuItem(subMenu, priorityMenu, -1);
PhInsertEMenuItem(subMenu, PhCreateEMenuItem(0, ID_PROCESS_PROPERTIES, L"Properties", NULL, NULL), -1);
PhInsertEMenuItem(Menu, subMenu, -1);
}
PhDereferenceObject(processList);
PhDereferenceObjects(processItems, numberOfProcessItems);
PhFree(processItems);
}
VOID PhpShowIconContextMenu(
__in POINT Location
)
{
PPH_EMENU menu;
PPH_EMENU_ITEM item;
ULONG numberOfProcesses;
ULONG id;
ULONG i;
// This function seems to be called recursively under some circumstances.
// To reproduce:
// 1. Hold right mouse button on tray icon, then left click.
// 2. Make the menu disappear by clicking on the menu then clicking somewhere else.
// So, don't store any global state or bad things will happen.
menu = PhCreateEMenu();
PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_ICON), 0);
// Check the Notifications menu items.
for (i = PH_NOTIFY_MINIMUM; i != PH_NOTIFY_MAXIMUM; i <<= 1)
{
if (NotifyIconNotifyMask & i)
{
switch (i)
{
case PH_NOTIFY_PROCESS_CREATE:
id = ID_NOTIFICATIONS_NEWPROCESSES;
break;
case PH_NOTIFY_PROCESS_DELETE:
id = ID_NOTIFICATIONS_TERMINATEDPROCESSES;
break;
case PH_NOTIFY_SERVICE_CREATE:
id = ID_NOTIFICATIONS_NEWSERVICES;
break;
case PH_NOTIFY_SERVICE_DELETE:
id = ID_NOTIFICATIONS_DELETEDSERVICES;
break;
case PH_NOTIFY_SERVICE_START:
id = ID_NOTIFICATIONS_STARTEDSERVICES;
break;
case PH_NOTIFY_SERVICE_STOP:
id = ID_NOTIFICATIONS_STOPPEDSERVICES;
break;
}
PhSetFlagsEMenuItem(menu, id, PH_EMENU_CHECKED, PH_EMENU_CHECKED);
}
}
// Add processes to the menu.
numberOfProcesses = PhGetIntegerSetting(L"IconProcesses");
item = PhFindEMenuItem(menu, 0, L"Processes", 0);
if (item)
PhpAddIconProcesses(item, numberOfProcesses);
// Give plugins a chance to modify the menu.
if (PhPluginsEnabled)
{
PH_PLUGIN_MENU_INFORMATION menuInfo;
menuInfo.Menu = menu;
menuInfo.OwnerWindow = PhMainWndHandle;
PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackIconMenuInitializing), &menuInfo);
}
SetForegroundWindow(PhMainWndHandle); // window must be foregrounded so menu will disappear properly
item = PhShowEMenu(
menu,
PhMainWndHandle,
PH_EMENU_SHOW_LEFTRIGHT,
PH_ALIGN_LEFT | PH_ALIGN_TOP,
Location.x,
Location.y
);
if (item)
{
PPH_EMENU_ITEM parentItem;
HANDLE processId;
BOOLEAN handled = FALSE;
parentItem = item->Parent;
while (parentItem)
{
if (parentItem->Context)
processId = parentItem->Context;
parentItem = parentItem->Parent;
}
if (PhPluginsEnabled && !handled)
handled = PhPluginTriggerEMenuItem(PhMainWndHandle, item);
if (!handled)
handled = PhpProcessComputerCommand(item->Id);
if (!handled)
{
switch (item->Id)
{
case ID_ICON_SHOWHIDEPROCESSHACKER:
SendMessage(PhMainWndHandle, WM_PH_TOGGLE_VISIBLE, 0, 0);
break;
case ID_ICON_SYSTEMINFORMATION:
SendMessage(PhMainWndHandle, WM_COMMAND, ID_VIEW_SYSTEMINFORMATION, 0);
break;
case ID_NOTIFICATIONS_ENABLEALL:
NotifyIconNotifyMask |= PH_NOTIFY_VALID_MASK;
break;
case ID_NOTIFICATIONS_DISABLEALL:
NotifyIconNotifyMask &= ~PH_NOTIFY_VALID_MASK;
break;
case ID_NOTIFICATIONS_NEWPROCESSES:
case ID_NOTIFICATIONS_TERMINATEDPROCESSES:
case ID_NOTIFICATIONS_NEWSERVICES:
case ID_NOTIFICATIONS_STARTEDSERVICES:
case ID_NOTIFICATIONS_STOPPEDSERVICES:
case ID_NOTIFICATIONS_DELETEDSERVICES:
{
ULONG bit;
switch (item->Id)
{
case ID_NOTIFICATIONS_NEWPROCESSES:
bit = PH_NOTIFY_PROCESS_CREATE;
break;
case ID_NOTIFICATIONS_TERMINATEDPROCESSES:
bit = PH_NOTIFY_PROCESS_DELETE;
break;
case ID_NOTIFICATIONS_NEWSERVICES:
bit = PH_NOTIFY_SERVICE_CREATE;
break;
case ID_NOTIFICATIONS_STARTEDSERVICES:
bit = PH_NOTIFY_SERVICE_START;
break;
case ID_NOTIFICATIONS_STOPPEDSERVICES:
bit = PH_NOTIFY_SERVICE_STOP;
break;
case ID_NOTIFICATIONS_DELETEDSERVICES:
bit = PH_NOTIFY_SERVICE_DELETE;
break;
}
NotifyIconNotifyMask ^= bit;
}
break;
case ID_PROCESS_TERMINATE:
case ID_PROCESS_SUSPEND:
case ID_PROCESS_RESUME:
case ID_PROCESS_PROPERTIES:
{
PPH_PROCESS_ITEM processItem;
if (processItem = PhReferenceProcessItem(processId))
{
switch (item->Id)
{
case ID_PROCESS_TERMINATE:
PhUiTerminateProcesses(PhMainWndHandle, &processItem, 1);
break;
case ID_PROCESS_SUSPEND:
PhUiSuspendProcesses(PhMainWndHandle, &processItem, 1);
break;
case ID_PROCESS_RESUME:
PhUiResumeProcesses(PhMainWndHandle, &processItem, 1);
break;
case ID_PROCESS_PROPERTIES:
ProcessHacker_ShowProcessProperties(PhMainWndHandle, processItem);
break;
}
PhDereferenceObject(processItem);
}
else
{
PhShowError(PhMainWndHandle, L"The process does not exist.");
}
}
break;
case ID_PRIORITY_REALTIME:
case ID_PRIORITY_HIGH:
case ID_PRIORITY_ABOVENORMAL:
case ID_PRIORITY_NORMAL:
case ID_PRIORITY_BELOWNORMAL:
case ID_PRIORITY_IDLE:
{
PPH_PROCESS_ITEM processItem;
if (processItem = PhReferenceProcessItem(processId))
{
PhpProcessProcessPriorityCommand(item->Id, processItem);
PhDereferenceObject(processItem);
}
else
{
PhShowError(PhMainWndHandle, L"The process does not exist.");
}
}
break;
case ID_ICON_EXIT:
SendMessage(PhMainWndHandle, WM_COMMAND, ID_HACKER_EXIT, 0);
break;
}
}
}
PhDestroyEMenu(menu);
}
VOID PhShowIconNotification(
__in PWSTR Title,
__in PWSTR Text,
__in ULONG Flags
)
{
ULONG i;
// Find a visible icon to display the balloon tip on.
for (i = PH_ICON_MINIMUM; i != PH_ICON_MAXIMUM; i <<= 1)
{
if (NotifyIconMask & i)
{
PhShowBalloonTipNotifyIcon(i, Title, Text, 10, Flags);
break;
}
}
}
BOOLEAN PhpCurrentUserProcessTreeFilter(
__in PPH_PROCESS_NODE ProcessNode,
__in_opt PVOID Context
)
{
if (!ProcessNode->ProcessItem->UserName)
return FALSE;
if (!PhCurrentUserName)
return FALSE;
if (!PhEqualString(ProcessNode->ProcessItem->UserName, PhCurrentUserName, TRUE))
return FALSE;
return TRUE;
}
BOOLEAN PhpSignedProcessTreeFilter(
__in PPH_PROCESS_NODE ProcessNode,
__in_opt PVOID Context
)
{
if (ProcessNode->ProcessItem->VerifyResult == VrTrusted)
return FALSE;
return TRUE;
}
PPH_PROCESS_ITEM PhpGetSelectedProcess()
{
return PhGetSelectedProcessItem();
}
VOID PhpGetSelectedProcesses(
__out PPH_PROCESS_ITEM **Processes,
__out PULONG NumberOfProcesses
)
{
PhGetSelectedProcessItems(Processes, NumberOfProcesses);
}
VOID PhpShowProcessProperties(
__in PPH_PROCESS_ITEM ProcessItem
)
{
PPH_PROCESS_PROPCONTEXT propContext;
propContext = PhCreateProcessPropContext(
PhMainWndHandle,
ProcessItem
);
if (propContext)
{
PhShowProcessProperties(propContext);
PhDereferenceObject(propContext);
}
}
PPH_SERVICE_ITEM PhpGetSelectedService()
{
return PhGetSelectedServiceItem();
}
VOID PhpGetSelectedServices(
__out PPH_SERVICE_ITEM **Services,
__out PULONG NumberOfServices
)
{
PhGetSelectedServiceItems(Services, NumberOfServices);
}
PPH_NETWORK_ITEM PhpGetSelectedNetworkItem()
{
return PhGetSelectedListViewItemParam(
NetworkListViewHandle
);
}
VOID PhpGetSelectedNetworkItems(
__out PPH_NETWORK_ITEM **NetworkItems,
__out PULONG NumberOfNetworkItems
)
{
PhGetSelectedListViewItemParams(
NetworkListViewHandle,
NetworkItems,
NumberOfNetworkItems
);
}
static VOID NTAPI ProcessAddedHandler(
__in_opt PVOID Parameter,
__in_opt PVOID Context
)
{
PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)Parameter;
// Reference the process item so it doesn't get deleted before
// we handle the event in the main thread.
PhReferenceObject(processItem);
PostMessage(
PhMainWndHandle,
WM_PH_PROCESS_ADDED,
(WPARAM)PhGetRunIdProvider(&ProcessProviderRegistration),
(LPARAM)processItem
);
}
static VOID NTAPI ProcessModifiedHandler(
__in_opt PVOID Parameter,
__in_opt PVOID Context
)
{
PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)Parameter;
PostMessage(PhMainWndHandle, WM_PH_PROCESS_MODIFIED, 0, (LPARAM)processItem);
}
static VOID NTAPI ProcessRemovedHandler(
__in_opt PVOID Parameter,
__in_opt PVOID Context
)
{
PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)Parameter;
// We already have a reference to the process item, so we don't need to
// reference it here.
PostMessage(PhMainWndHandle, WM_PH_PROCESS_REMOVED, 0, (LPARAM)processItem);
}
static VOID NTAPI ProcessesUpdatedHandler(
__in_opt PVOID Parameter,
__in_opt PVOID Context
)
{
PostMessage(PhMainWndHandle, WM_PH_PROCESSES_UPDATED, 0, 0);
}
static VOID NTAPI ProcessesUpdatedForIconsHandler(
__in_opt PVOID Parameter,
__in_opt PVOID Context
)
{
// We do icon updating on the provider thread so we don't block the main GUI when
// explorer is not responding.
if (NotifyIconMask & PH_ICON_CPU_HISTORY)
PhUpdateIconCpuHistory();
if (NotifyIconMask & PH_ICON_IO_HISTORY)
PhUpdateIconIoHistory();
if (NotifyIconMask & PH_ICON_COMMIT_HISTORY)
PhUpdateIconCommitHistory();
if (NotifyIconMask & PH_ICON_PHYSICAL_HISTORY)
PhUpdateIconPhysicalHistory();
if (NotifyIconMask & PH_ICON_CPU_USAGE)
PhUpdateIconCpuUsage();
}
static VOID NTAPI ServiceAddedHandler(
__in_opt PVOID Parameter,
__in_opt PVOID Context
)
{
PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)Parameter;
PhReferenceObject(serviceItem);
PostMessage(
PhMainWndHandle,
WM_PH_SERVICE_ADDED,
PhGetRunIdProvider(&ServiceProviderRegistration),
(LPARAM)serviceItem
);
}
static VOID NTAPI ServiceModifiedHandler(
__in_opt PVOID Parameter,
__in_opt PVOID Context
)
{
PPH_SERVICE_MODIFIED_DATA serviceModifiedData = (PPH_SERVICE_MODIFIED_DATA)Parameter;
PPH_SERVICE_MODIFIED_DATA copy;
copy = PhAllocateCopy(serviceModifiedData, sizeof(PH_SERVICE_MODIFIED_DATA));
PostMessage(PhMainWndHandle, WM_PH_SERVICE_MODIFIED, 0, (LPARAM)copy);
}
static VOID NTAPI ServiceRemovedHandler(
__in_opt PVOID Parameter,
__in_opt PVOID Context
)
{
PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)Parameter;
PostMessage(PhMainWndHandle, WM_PH_SERVICE_REMOVED, 0, (LPARAM)serviceItem);
}
static VOID NTAPI ServicesUpdatedHandler(
__in_opt PVOID Parameter,
__in_opt PVOID Context
)
{
PostMessage(PhMainWndHandle, WM_PH_SERVICES_UPDATED, 0, 0);
}
static VOID NTAPI NetworkItemAddedHandler(
__in_opt PVOID Parameter,
__in_opt PVOID Context
)
{
PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)Parameter;
PhReferenceObject(networkItem);
PostMessage(
PhMainWndHandle,
WM_PH_NETWORK_ITEM_ADDED,
PhGetRunIdProvider(&NetworkProviderRegistration),
(LPARAM)networkItem
);
}
static VOID NTAPI NetworkItemModifiedHandler(
__in_opt PVOID Parameter,
__in_opt PVOID Context
)
{
PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)Parameter;
PostMessage(PhMainWndHandle, WM_PH_NETWORK_ITEM_MODIFIED, 0, (LPARAM)networkItem);
}
static VOID NTAPI NetworkItemRemovedHandler(
__in_opt PVOID Parameter,
__in_opt PVOID Context
)
{
PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)Parameter;
PostMessage(PhMainWndHandle, WM_PH_NETWORK_ITEM_REMOVED, 0, (LPARAM)networkItem);
}
static VOID NTAPI NetworkItemsUpdatedHandler(
__in_opt PVOID Parameter,
__in_opt PVOID Context
)
{
PostMessage(PhMainWndHandle, WM_PH_NETWORK_ITEMS_UPDATED, 0, 0);
}
VOID PhMainWndOnCreate()
{
TabControlHandle = CreateWindow(
WC_TABCONTROL,
L"",
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | TCS_MULTILINE,
0,
0,
3,
3,
PhMainWndHandle,
NULL,
PhInstanceHandle,
NULL
);
SendMessage(TabControlHandle, WM_SETFONT, (WPARAM)PhApplicationFont, FALSE);
BringWindowToTop(TabControlHandle);
ProcessesTabIndex = PhAddTabControlTab(TabControlHandle, 0, L"Processes");
ServicesTabIndex = PhAddTabControlTab(TabControlHandle, 1, L"Services");
NetworkTabIndex = PhAddTabControlTab(TabControlHandle, 2, L"Network");
MaxTabIndex = NetworkTabIndex;
ProcessTreeListHandle = CreateWindow(
PH_TREENEW_CLASSNAME,
L"",
WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_BORDER | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED | TN_STYLE_ANIMATE_DIVIDER,
0,
0,
3,
3,
PhMainWndHandle,
(HMENU)ID_MAINWND_PROCESSTL,
PhLibImageBase,
NULL
);
BringWindowToTop(ProcessTreeListHandle);
ServiceTreeListHandle = CreateWindow(
PH_TREENEW_CLASSNAME,
L"",
WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_BORDER | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED,
0,
0,
3,
3,
PhMainWndHandle,
(HMENU)ID_MAINWND_SERVICETL,
PhLibImageBase,
NULL
);
BringWindowToTop(ServiceTreeListHandle);
NetworkListViewHandle = PhCreateListViewControl(PhMainWndHandle, ID_MAINWND_NETWORKLV);
PhSetListViewStyle(NetworkListViewHandle, TRUE, TRUE);
SendMessage(ListView_GetToolTips(NetworkListViewHandle), TTM_SETDELAYTIME, TTDT_AUTOPOP, 0x7fff);
BringWindowToTop(NetworkListViewHandle);
PhpReloadListViewFont();
PhSetControlTheme(NetworkListViewHandle, L"explorer");
PhAddListViewColumn(NetworkListViewHandle, 0, 0, 0, LVCFMT_LEFT, 100, L"Process");
PhAddListViewColumn(NetworkListViewHandle, 1, 1, 1, LVCFMT_LEFT, 120, L"Local Address");
PhAddListViewColumn(NetworkListViewHandle, 2, 2, 2, LVCFMT_RIGHT, 50, L"Local Port");
PhAddListViewColumn(NetworkListViewHandle, 3, 3, 3, LVCFMT_LEFT, 120, L"Remote Address");
PhAddListViewColumn(NetworkListViewHandle, 4, 4, 4, LVCFMT_RIGHT, 50, L"Remote Port");
PhAddListViewColumn(NetworkListViewHandle, 5, 5, 5, LVCFMT_LEFT, 45, L"Protocol");
PhAddListViewColumn(NetworkListViewHandle, 6, 6, 6, LVCFMT_LEFT, 70, L"State");
if (WINDOWS_HAS_SERVICE_TAGS)
PhAddListViewColumn(NetworkListViewHandle, 7, 7, 7, LVCFMT_LEFT, 80, L"Owner");
PhProcessTreeListInitialization();
PhInitializeProcessTreeList(ProcessTreeListHandle);
PhServiceTreeListInitialization();
PhInitializeServiceTreeList(ServiceTreeListHandle);
PhSetExtendedListViewWithSettings(NetworkListViewHandle);
ExtendedListView_SetStateHighlighting(NetworkListViewHandle, TRUE);
PhRegisterCallback(
&PhProcessAddedEvent,
ProcessAddedHandler,
NULL,
&ProcessAddedRegistration
);
PhRegisterCallback(
&PhProcessModifiedEvent,
ProcessModifiedHandler,
NULL,
&ProcessModifiedRegistration
);
PhRegisterCallback(
&PhProcessRemovedEvent,
ProcessRemovedHandler,
NULL,
&ProcessRemovedRegistration
);
PhRegisterCallback(
&PhProcessesUpdatedEvent,
ProcessesUpdatedHandler,
NULL,
&ProcessesUpdatedRegistration
);
PhRegisterCallback(
&PhProcessesUpdatedEvent,
ProcessesUpdatedForIconsHandler,
NULL,
&ProcessesUpdatedForIconsRegistration
);
PhRegisterCallback(
&PhServiceAddedEvent,
ServiceAddedHandler,
NULL,
&ServiceAddedRegistration
);
PhRegisterCallback(
&PhServiceModifiedEvent,
ServiceModifiedHandler,
NULL,
&ServiceModifiedRegistration
);
PhRegisterCallback(
&PhServiceRemovedEvent,
ServiceRemovedHandler,
NULL,
&ServiceRemovedRegistration
);
PhRegisterCallback(
&PhServicesUpdatedEvent,
ServicesUpdatedHandler,
NULL,
&ServicesUpdatedRegistration
);
PhRegisterCallback(
&PhNetworkItemAddedEvent,
NetworkItemAddedHandler,
NULL,
&NetworkItemAddedRegistration
);
PhRegisterCallback(
&PhNetworkItemModifiedEvent,
NetworkItemModifiedHandler,
NULL,
&NetworkItemModifiedRegistration
);
PhRegisterCallback(
&PhNetworkItemRemovedEvent,
NetworkItemRemovedHandler,
NULL,
&NetworkItemRemovedRegistration
);
PhRegisterCallback(
&PhNetworkItemsUpdatedEvent,
NetworkItemsUpdatedHandler,
NULL,
&NetworkItemsUpdatedRegistration
);
}
VOID PhpApplyLayoutPadding(
__inout PRECT Rect,
__in PRECT Padding
)
{
Rect->left += Padding->left;
Rect->top += Padding->top;
Rect->right -= Padding->right;
Rect->bottom -= Padding->bottom;
}
ULONG_PTR PhpMainWndAddMenuItem(
__in PPH_PLUGIN Plugin,
__in HMENU ParentMenu,
__in_opt PWSTR InsertAfter,
__in ULONG Flags,
__in ULONG Id,
__in PWSTR Text,
__in_opt PVOID Context
)
{
PPH_PLUGIN_MENU_ITEM menuItem;
HMENU menu;
ULONG insertIndex;
ULONG textCount;
WCHAR textBuffer[256];
MENUITEMINFO menuItemInfo = { sizeof(menuItemInfo) };
HMENU subMenu;
textCount = (ULONG)wcslen(Text);
if (textCount > 128)
return FALSE;
menuItem = PhAllocate(sizeof(PH_PLUGIN_MENU_ITEM));
memset(menuItem, 0, sizeof(PH_PLUGIN_MENU_ITEM));
menuItem->Plugin = Plugin;
menuItem->Id = Id;
menuItem->Context = Context;
menuItem->ParentMenu = ParentMenu;
menuItem->SubMenu = NULL;
menu = ParentMenu;
if (InsertAfter)
{
ULONG count;
menuItemInfo.fMask = MIIM_STRING;
menuItemInfo.dwTypeData = textBuffer;
menuItemInfo.cch = sizeof(textBuffer) / sizeof(WCHAR);
insertIndex = 0;
count = GetMenuItemCount(menu);
if (count == -1)
return FALSE;
for (insertIndex = 0; insertIndex < count; insertIndex++)
{
if (GetMenuItemInfo(menu, insertIndex, TRUE, &menuItemInfo) && menuItemInfo.dwTypeData)
{
if (PhCompareUnicodeStringZIgnoreMenuPrefix(InsertAfter, menuItemInfo.dwTypeData, TRUE, TRUE) == 0)
{
insertIndex++;
break;
}
}
}
}
else
{
insertIndex = 0;
}
if (textCount == 1 && Text[0] == '-')
{
menuItem->RealId = 0;
menuItemInfo.fMask = 0;
menuItemInfo.fType = MFT_SEPARATOR;
}
else
{
menuItem->RealId = PhPluginReserveIds(1);
menuItemInfo.fMask = MIIM_DATA | MIIM_ID | MIIM_STRING;
menuItemInfo.wID = menuItem->RealId;
menuItemInfo.dwItemData = (ULONG_PTR)menuItem;
menuItemInfo.dwTypeData = Text;
if (Flags & PH_MENU_ITEM_SUB_MENU)
{
subMenu = CreatePopupMenu();
menuItemInfo.fMask |= MIIM_SUBMENU;
menuItemInfo.hSubMenu = subMenu;
menuItem->SubMenu = subMenu;
}
}
InsertMenuItem(menu, insertIndex, TRUE, &menuItemInfo);
if (Flags & PH_MENU_ITEM_RETURN_MENU)
{
return (ULONG_PTR)menuItem;
}
else
{
if (Flags & PH_MENU_ITEM_SUB_MENU)
return (ULONG_PTR)subMenu;
else
return TRUE;
}
}
PPH_ADDITIONAL_TAB_PAGE PhpAddTabPage(
__in PPH_ADDITIONAL_TAB_PAGE TabPage
)
{
PPH_ADDITIONAL_TAB_PAGE newTabPage;
HDWP deferHandle;
if (!AdditionalTabPageList)
AdditionalTabPageList = PhCreateList(2);
newTabPage = PhAllocateCopy(TabPage, sizeof(PH_ADDITIONAL_TAB_PAGE));
PhAddItemList(AdditionalTabPageList, newTabPage);
newTabPage->Index = PhAddTabControlTab(TabControlHandle, MAXINT, newTabPage->Text);
MaxTabIndex = newTabPage->Index;
if (newTabPage->WindowHandle)
BringWindowToTop(newTabPage->WindowHandle);
// The tab control might need multiple lines, so we need to refresh the layout.
deferHandle = BeginDeferWindowPos(1);
PhMainWndTabControlOnLayout(&deferHandle);
EndDeferWindowPos(deferHandle);
return newTabPage;
}
VOID PhMainWndOnLayout(
__inout HDWP *deferHandle
)
{
RECT rect;
// Resize the tab control.
// Don't defer the resize. The tab control doesn't repaint properly.
GetClientRect(PhMainWndHandle, &rect);
PhpApplyLayoutPadding(&rect, &LayoutPadding);
SetWindowPos(TabControlHandle, NULL,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
SWP_NOACTIVATE | SWP_NOZORDER);
UpdateWindow(TabControlHandle);
PhMainWndTabControlOnLayout(deferHandle);
}
VOID PhMainWndTabControlOnLayout(
__inout HDWP *deferHandle
)
{
RECT rect;
INT selectedIndex;
GetClientRect(PhMainWndHandle, &rect);
PhpApplyLayoutPadding(&rect, &LayoutPadding);
TabCtrl_AdjustRect(TabControlHandle, FALSE, &rect);
selectedIndex = TabCtrl_GetCurSel(TabControlHandle);
if (selectedIndex == ProcessesTabIndex)
{
*deferHandle = DeferWindowPos(*deferHandle, ProcessTreeListHandle, NULL,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
SWP_NOACTIVATE | SWP_NOZORDER);
}
else if (selectedIndex == ServicesTabIndex)
{
*deferHandle = DeferWindowPos(*deferHandle, ServiceTreeListHandle, NULL,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
SWP_NOACTIVATE | SWP_NOZORDER);
}
else if (selectedIndex == NetworkTabIndex)
{
*deferHandle = DeferWindowPos(*deferHandle, NetworkListViewHandle, NULL,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
SWP_NOACTIVATE | SWP_NOZORDER);
}
else if (AdditionalTabPageList)
{
ULONG i;
for (i = 0; i < AdditionalTabPageList->Count; i++)
{
PPH_ADDITIONAL_TAB_PAGE tabPage = AdditionalTabPageList->Items[i];
if (selectedIndex == tabPage->Index)
{
// Create the tab page window if it doesn't exist.
if (!tabPage->WindowHandle)
{
tabPage->WindowHandle = tabPage->CreateFunction(tabPage->Context);
BringWindowToTop(tabPage->WindowHandle);
}
if (tabPage->WindowHandle)
{
*deferHandle = DeferWindowPos(*deferHandle, tabPage->WindowHandle, NULL,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
SWP_NOACTIVATE | SWP_NOZORDER);
}
break;
}
}
}
}
VOID PhMainWndTabControlOnNotify(
__in LPNMHDR Header
)
{
if (Header->code == TCN_SELCHANGE)
{
PhMainWndTabControlOnSelectionChanged();
}
}
VOID PhMainWndTabControlOnSelectionChanged()
{
INT selectedIndex;
HDWP deferHandle;
selectedIndex = TabCtrl_GetCurSel(TabControlHandle);
deferHandle = BeginDeferWindowPos(1);
PhMainWndTabControlOnLayout(&deferHandle);
EndDeferWindowPos(deferHandle);
// Built-in tabs
if (selectedIndex == ServicesTabIndex)
PhpNeedServiceTreeList();
if (selectedIndex == NetworkTabIndex)
{
PhSetEnabledProvider(&NetworkProviderRegistration, UpdateAutomatically);
if (UpdateAutomatically || NetworkFirstTime)
{
PhBoostProvider(&NetworkProviderRegistration, NULL);
NetworkFirstTime = FALSE;
}
}
else
{
PhSetEnabledProvider(&NetworkProviderRegistration, FALSE);
}
ShowWindow(ProcessTreeListHandle, selectedIndex == ProcessesTabIndex ? SW_SHOW : SW_HIDE);
ShowWindow(ServiceTreeListHandle, selectedIndex == ServicesTabIndex ? SW_SHOW : SW_HIDE);
ShowWindow(NetworkListViewHandle, selectedIndex == NetworkTabIndex ? SW_SHOW : SW_HIDE);
// Additional tabs
if (AdditionalTabPageList)
{
ULONG i;
for (i = 0; i < AdditionalTabPageList->Count; i++)
{
PPH_ADDITIONAL_TAB_PAGE tabPage = AdditionalTabPageList->Items[i];
ShowWindow(tabPage->WindowHandle, selectedIndex == tabPage->Index ? SW_SHOW : SW_HIDE);
}
}
}
BOOL CALLBACK PhpEnumProcessWindowsProc(
__in HWND hwnd,
__in LPARAM lParam
)
{
ULONG processId;
HWND parentWindow;
if (!IsWindowVisible(hwnd))
return TRUE;
GetWindowThreadProcessId(hwnd, &processId);
if (
processId == (ULONG)lParam &&
!((parentWindow = GetParent(hwnd)) && IsWindowVisible(parentWindow)) && // skip windows with a visible parent
GetWindowTextLength(hwnd) != 0
)
{
SelectedProcessWindowHandle = hwnd;
return FALSE;
}
return TRUE;
}
VOID PhpSetProcessMenuPriorityChecks(
__in PPH_EMENU Menu,
__in PPH_PROCESS_ITEM Process,
__in BOOLEAN SetPriority,
__in BOOLEAN SetIoPriority,
__in BOOLEAN SetPagePriority
)
{
HANDLE processHandle;
PROCESS_PRIORITY_CLASS priorityClass = { 0 };
ULONG ioPriority = -1;
ULONG pagePriority = -1;
ULONG id = 0;
if (NT_SUCCESS(PhOpenProcess(
&processHandle,
ProcessQueryAccess,
Process->ProcessId
)))
{
if (SetPriority)
{
NtQueryInformationProcess(processHandle, ProcessPriorityClass, &priorityClass, sizeof(PROCESS_PRIORITY_CLASS), NULL);
}
if (SetIoPriority && WindowsVersion >= WINDOWS_VISTA)
{
if (!NT_SUCCESS(PhGetProcessIoPriority(
processHandle,
&ioPriority
)))
{
ioPriority = -1;
}
}
if (SetPagePriority && WindowsVersion >= WINDOWS_VISTA)
{
if (!NT_SUCCESS(PhGetProcessPagePriority(
processHandle,
&pagePriority
)))
{
pagePriority = -1;
}
}
NtClose(processHandle);
}
if (SetPriority)
{
switch (priorityClass.PriorityClass)
{
case PROCESS_PRIORITY_CLASS_REALTIME:
id = ID_PRIORITY_REALTIME;
break;
case PROCESS_PRIORITY_CLASS_HIGH:
id = ID_PRIORITY_HIGH;
break;
case PROCESS_PRIORITY_CLASS_ABOVE_NORMAL:
id = ID_PRIORITY_ABOVENORMAL;
break;
case PROCESS_PRIORITY_CLASS_NORMAL:
id = ID_PRIORITY_NORMAL;
break;
case PROCESS_PRIORITY_CLASS_BELOW_NORMAL:
id = ID_PRIORITY_BELOWNORMAL;
break;
case PROCESS_PRIORITY_CLASS_IDLE:
id = ID_PRIORITY_IDLE;
break;
}
if (id != 0)
{
PhSetFlagsEMenuItem(Menu, id,
PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK,
PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK);
}
}
if (SetIoPriority && ioPriority != -1)
{
id = 0;
switch (ioPriority)
{
case 0:
id = ID_I_0;
break;
case 1:
id = ID_I_1;
break;
case 2:
id = ID_I_2;
break;
case 3:
id = ID_I_3;
break;
}
if (id != 0)
{
PhSetFlagsEMenuItem(Menu, id,
PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK,
PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK);
}
}
if (SetPagePriority && pagePriority != -1)
{
id = 0;
switch (pagePriority)
{
case 1:
id = ID_PAGEPRIORITY_1;
break;
case 2:
id = ID_PAGEPRIORITY_2;
break;
case 3:
id = ID_PAGEPRIORITY_3;
break;
case 4:
id = ID_PAGEPRIORITY_4;
break;
case 5:
id = ID_PAGEPRIORITY_5;
break;
}
if (id != 0)
{
PhSetFlagsEMenuItem(Menu, id,
PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK,
PH_EMENU_CHECKED | PH_EMENU_RADIOCHECK);
}
}
}
VOID PhpInitializeProcessMenu(
__in PPH_EMENU Menu,
__in PPH_PROCESS_ITEM *Processes,
__in ULONG NumberOfProcesses
)
{
PPH_EMENU_ITEM item;
if (NumberOfProcesses == 0)
{
PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);
}
else if (NumberOfProcesses == 1)
{
// All menu items are enabled by default.
// If the user selected a fake process, disable all but
// a few menu items.
if (PH_IS_FAKE_PROCESS_ID(Processes[0]->ProcessId))
{
PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);
PhEnableEMenuItem(Menu, ID_PROCESS_PROPERTIES, TRUE);
PhEnableEMenuItem(Menu, ID_PROCESS_SEARCHONLINE, TRUE);
}
}
else
{
ULONG menuItemsMultiEnabled[] =
{
ID_PROCESS_TERMINATE,
ID_PROCESS_SUSPEND,
ID_PROCESS_RESUME,
ID_PROCESS_REDUCEWORKINGSET,
ID_PROCESS_COPY
};
ULONG i;
PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);
// These menu items are capable of manipulating
// multiple processes.
for (i = 0; i < sizeof(menuItemsMultiEnabled) / sizeof(ULONG); i++)
{
PhSetFlagsEMenuItem(Menu, menuItemsMultiEnabled[i], PH_EMENU_DISABLED, 0);
}
}
// Remove irrelevant menu items.
if (WindowsVersion < WINDOWS_VISTA)
{
// Remove I/O priority.
if (item = PhFindEMenuItem(Menu, PH_EMENU_FIND_DESCEND, L"I/O Priority", 0))
PhDestroyEMenuItem(item);
// Remove page priority.
if (item = PhFindEMenuItem(Menu, PH_EMENU_FIND_DESCEND, L"Page Priority", 0))
PhDestroyEMenuItem(item);
}
// Virtualization
if (NumberOfProcesses == 1)
{
HANDLE processHandle;
HANDLE tokenHandle;
BOOLEAN allowed = FALSE;
BOOLEAN enabled = FALSE;
if (NT_SUCCESS(PhOpenProcess(
&processHandle,
ProcessQueryAccess,
Processes[0]->ProcessId
)))
{
if (NT_SUCCESS(PhOpenProcessToken(
&tokenHandle,
TOKEN_QUERY,
processHandle
)))
{
PhGetTokenIsVirtualizationAllowed(tokenHandle, &allowed);
PhGetTokenIsVirtualizationEnabled(tokenHandle, &enabled);
SelectedProcessVirtualizationEnabled = enabled;
NtClose(tokenHandle);
}
NtClose(processHandle);
}
if (!allowed)
PhSetFlagsEMenuItem(Menu, ID_PROCESS_VIRTUALIZATION, PH_EMENU_DISABLED, PH_EMENU_DISABLED);
else if (enabled)
PhSetFlagsEMenuItem(Menu, ID_PROCESS_VIRTUALIZATION, PH_EMENU_CHECKED, PH_EMENU_CHECKED);
}
// Priority
if (NumberOfProcesses == 1)
{
PhpSetProcessMenuPriorityChecks(Menu, Processes[0], TRUE, TRUE, TRUE);
}
item = PhFindEMenuItem(Menu, 0, L"Window", 0);
if (item)
{
// Window menu
if (NumberOfProcesses == 1)
{
WINDOWPLACEMENT placement = { sizeof(placement) };
// Get a handle to the process' top-level window (if any).
SelectedProcessWindowHandle = NULL;
EnumWindows(PhpEnumProcessWindowsProc, (ULONG)Processes[0]->ProcessId);
if (!SelectedProcessWindowHandle)
item->Flags |= PH_EMENU_DISABLED;
GetWindowPlacement(SelectedProcessWindowHandle, &placement);
if (placement.showCmd == SW_MINIMIZE)
PhEnableEMenuItem(item, ID_WINDOW_MINIMIZE, FALSE);
else if (placement.showCmd == SW_MAXIMIZE)
PhEnableEMenuItem(item, ID_WINDOW_MAXIMIZE, FALSE);
else if (placement.showCmd == SW_NORMAL)
PhEnableEMenuItem(item, ID_WINDOW_RESTORE, FALSE);
}
else
{
item->Flags |= PH_EMENU_DISABLED;
}
}
// Remove irrelevant menu items (continued)
if (!WINDOWS_HAS_UAC)
{
if (item = PhFindEMenuItem(Menu, 0, NULL, ID_PROCESS_VIRTUALIZATION))
PhDestroyEMenuItem(item);
}
}
VOID PhShowProcessContextMenu(
__in POINT Location
)
{
PPH_PROCESS_ITEM *processes;
ULONG numberOfProcesses;
PhpGetSelectedProcesses(&processes, &numberOfProcesses);
if (numberOfProcesses != 0)
{
PPH_EMENU menu;
PPH_EMENU_ITEM item;
menu = PhCreateEMenu();
PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_PROCESS), 0);
PhSetFlagsEMenuItem(menu, ID_PROCESS_PROPERTIES, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT);
PhpInitializeProcessMenu(menu, processes, numberOfProcesses);
if (PhPluginsEnabled)
{
PH_PLUGIN_MENU_INFORMATION menuInfo;
menuInfo.Menu = menu;
menuInfo.OwnerWindow = PhMainWndHandle;
menuInfo.u.Process.Processes = processes;
menuInfo.u.Process.NumberOfProcesses = numberOfProcesses;
PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessMenuInitializing), &menuInfo);
}
item = PhShowEMenu(
menu,
PhMainWndHandle,
PH_EMENU_SHOW_LEFTRIGHT,
PH_ALIGN_LEFT | PH_ALIGN_TOP,
Location.x,
Location.y
);
if (item)
{
BOOLEAN handled = FALSE;
if (PhPluginsEnabled)
handled = PhPluginTriggerEMenuItem(PhMainWndHandle, item);
if (!handled)
SendMessage(PhMainWndHandle, WM_COMMAND, item->Id, 0);
}
PhDestroyEMenu(menu);
}
PhFree(processes);
}
VOID PhpInitializeServiceMenu(
__in PPH_EMENU Menu,
__in PPH_SERVICE_ITEM *Services,
__in ULONG NumberOfServices
)
{
if (NumberOfServices == 0)
{
PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);
}
else if (NumberOfServices == 1)
{
if (!Services[0]->ProcessId)
PhEnableEMenuItem(Menu, ID_SERVICE_GOTOPROCESS, FALSE);
}
else
{
PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);
PhEnableEMenuItem(Menu, ID_SERVICE_COPY, TRUE);
}
if (NumberOfServices == 1)
{
switch (Services[0]->State)
{
case SERVICE_RUNNING:
{
PhEnableEMenuItem(Menu, ID_SERVICE_START, FALSE);
PhEnableEMenuItem(Menu, ID_SERVICE_CONTINUE, FALSE);
PhEnableEMenuItem(Menu, ID_SERVICE_PAUSE,
Services[0]->ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE);
PhEnableEMenuItem(Menu, ID_SERVICE_STOP,
Services[0]->ControlsAccepted & SERVICE_ACCEPT_STOP);
}
break;
case SERVICE_PAUSED:
{
PhEnableEMenuItem(Menu, ID_SERVICE_START, FALSE);
PhEnableEMenuItem(Menu, ID_SERVICE_CONTINUE,
Services[0]->ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE);
PhEnableEMenuItem(Menu, ID_SERVICE_PAUSE, FALSE);
PhEnableEMenuItem(Menu, ID_SERVICE_STOP,
Services[0]->ControlsAccepted & SERVICE_ACCEPT_STOP);
}
break;
case SERVICE_STOPPED:
{
PhEnableEMenuItem(Menu, ID_SERVICE_CONTINUE, FALSE);
PhEnableEMenuItem(Menu, ID_SERVICE_PAUSE, FALSE);
PhEnableEMenuItem(Menu, ID_SERVICE_STOP, FALSE);
}
break;
case SERVICE_START_PENDING:
case SERVICE_CONTINUE_PENDING:
case SERVICE_PAUSE_PENDING:
case SERVICE_STOP_PENDING:
{
PhEnableEMenuItem(Menu, ID_SERVICE_START, FALSE);
PhEnableEMenuItem(Menu, ID_SERVICE_CONTINUE, FALSE);
PhEnableEMenuItem(Menu, ID_SERVICE_PAUSE, FALSE);
PhEnableEMenuItem(Menu, ID_SERVICE_STOP, FALSE);
}
break;
}
if (!(Services[0]->ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE))
{
PPH_EMENU_ITEM item;
if (item = PhFindEMenuItem(Menu, 0, NULL, ID_SERVICE_CONTINUE))
PhDestroyEMenuItem(item);
if (item = PhFindEMenuItem(Menu, 0, NULL, ID_SERVICE_PAUSE))
PhDestroyEMenuItem(item);
}
}
}
VOID PhShowServiceContextMenu(
__in POINT Location
)
{
PPH_SERVICE_ITEM *services;
ULONG numberOfServices;
PhpGetSelectedServices(&services, &numberOfServices);
if (numberOfServices != 0)
{
PPH_EMENU menu;
PPH_EMENU_ITEM item;
menu = PhCreateEMenu();
PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_SERVICE), 0);
PhSetFlagsEMenuItem(menu, ID_SERVICE_PROPERTIES, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT);
PhpInitializeServiceMenu(menu, services, numberOfServices);
if (PhPluginsEnabled)
{
PH_PLUGIN_MENU_INFORMATION menuInfo;
menuInfo.Menu = menu;
menuInfo.OwnerWindow = PhMainWndHandle;
menuInfo.u.Service.Services = services;
menuInfo.u.Service.NumberOfServices = numberOfServices;
PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackServiceMenuInitializing), &menuInfo);
}
item = PhShowEMenu(
menu,
PhMainWndHandle,
PH_EMENU_SHOW_LEFTRIGHT,
PH_ALIGN_LEFT | PH_ALIGN_TOP,
Location.x,
Location.y
);
if (item)
{
BOOLEAN handled = FALSE;
if (PhPluginsEnabled)
handled = PhPluginTriggerEMenuItem(PhMainWndHandle, item);
if (!handled)
SendMessage(PhMainWndHandle, WM_COMMAND, item->Id, 0);
}
PhDestroyEMenu(menu);
}
PhFree(services);
}
VOID PhpInitializeNetworkMenu(
__in PPH_EMENU Menu,
__in PPH_NETWORK_ITEM *NetworkItems,
__in ULONG NumberOfNetworkItems
)
{
ULONG i;
PPH_EMENU_ITEM item;
if (NumberOfNetworkItems == 0)
{
PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);
}
else if (NumberOfNetworkItems == 1)
{
if (!NetworkItems[0]->ProcessId)
PhEnableEMenuItem(Menu, ID_NETWORK_GOTOPROCESS, FALSE);
}
else
{
PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);
PhEnableEMenuItem(Menu, ID_NETWORK_CLOSE, TRUE);
PhEnableEMenuItem(Menu, ID_NETWORK_COPY, TRUE);
}
if (WindowsVersion >= WINDOWS_VISTA)
{
if (item = PhFindEMenuItem(Menu, 0, NULL, ID_NETWORK_VIEWSTACK))
PhDestroyEMenuItem(item);
}
// Close
if (NumberOfNetworkItems != 0)
{
BOOLEAN closeOk = TRUE;
for (i = 0; i < NumberOfNetworkItems; i++)
{
if (
NetworkItems[i]->ProtocolType != PH_TCP4_NETWORK_PROTOCOL ||
NetworkItems[i]->State != MIB_TCP_STATE_ESTAB
)
{
closeOk = FALSE;
break;
}
}
if (!closeOk)
PhEnableEMenuItem(Menu, ID_NETWORK_CLOSE, FALSE);
}
}
VOID PhMainWndNetworkListViewOnNotify(
__in LPNMHDR Header
)
{
switch (Header->code)
{
case NM_DBLCLK:
{
SendMessage(PhMainWndHandle, WM_COMMAND, ID_NETWORK_GOTOPROCESS, 0);
}
break;
case LVN_KEYDOWN:
{
LPNMLVKEYDOWN keyDown = (LPNMLVKEYDOWN)Header;
switch (keyDown->wVKey)
{
case 'C':
if (GetKeyState(VK_CONTROL) < 0)
SendMessage(PhMainWndHandle, WM_COMMAND, ID_NETWORK_COPY, 0);
break;
case VK_RETURN:
SendMessage(PhMainWndHandle, WM_COMMAND, ID_NETWORK_GOTOPROCESS, 0);
break;
}
}
break;
case LVN_GETINFOTIP:
{
LPNMLVGETINFOTIP getInfoTip = (LPNMLVGETINFOTIP)Header;
PPH_NETWORK_ITEM networkItem;
if (getInfoTip->iSubItem == 0 && PhGetListViewItemParam(
NetworkListViewHandle,
getInfoTip->iItem,
&networkItem
))
{
PPH_PROCESS_ITEM processItem;
PPH_STRING tip;
if (processItem = PhReferenceProcessItem(networkItem->ProcessId))
{
tip = PhGetProcessTooltipText(processItem);
PhCopyListViewInfoTip(getInfoTip, &tip->sr);
PhDereferenceObject(tip);
PhDereferenceObject(processItem);
}
}
}
break;
}
}
VOID PhMainWndNetworkListViewOnContextMenu(
__in LPARAM lParam
)
{
POINT point;
PPH_NETWORK_ITEM *networkItems;
ULONG numberOfNetworkItems;
point.x = (SHORT)LOWORD(lParam);
point.y = (SHORT)HIWORD(lParam);
if (point.x == -1 && point.y == -1)
PhGetListViewContextMenuPoint(NetworkListViewHandle, &point);
PhpGetSelectedNetworkItems(&networkItems, &numberOfNetworkItems);
if (numberOfNetworkItems != 0)
{
PPH_EMENU menu;
PPH_EMENU_ITEM item;
menu = PhCreateEMenu();
PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_NETWORK), 0);
PhSetFlagsEMenuItem(menu, ID_NETWORK_GOTOPROCESS, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT);
PhpInitializeNetworkMenu(menu, networkItems, numberOfNetworkItems);
if (PhPluginsEnabled)
{
PH_PLUGIN_MENU_INFORMATION menuInfo;
menuInfo.Menu = menu;
menuInfo.OwnerWindow = PhMainWndHandle;
menuInfo.u.Network.NetworkItems = networkItems;
menuInfo.u.Network.NumberOfNetworkItems = numberOfNetworkItems;
PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackNetworkMenuInitializing), &menuInfo);
}
item = PhShowEMenu(
menu,
PhMainWndHandle,
PH_EMENU_SHOW_LEFTRIGHT,
PH_ALIGN_LEFT | PH_ALIGN_TOP,
point.x,
point.y
);
if (item)
{
BOOLEAN handled = FALSE;
if (PhPluginsEnabled)
handled = PhPluginTriggerEMenuItem(PhMainWndHandle, item);
if (!handled)
SendMessage(PhMainWndHandle, WM_COMMAND, item->Id, 0);
}
PhDestroyEMenu(menu);
}
PhFree(networkItems);
}
BOOLEAN PhpPluginNotifyEvent(
__in ULONG Type,
__in PVOID Parameter
)
{
PH_PLUGIN_NOTIFY_EVENT notifyEvent;
notifyEvent.Type = Type;
notifyEvent.Handled = FALSE;
notifyEvent.Parameter = Parameter;
PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackNotifyEvent), &notifyEvent);
return notifyEvent.Handled;
}
VOID PhMainWndOnProcessAdded(
__in __assumeRefs(1) PPH_PROCESS_ITEM ProcessItem,
__in ULONG RunId
)
{
PPH_PROCESS_NODE processNode;
if (!ProcessesNeedsRedraw)
{
TreeNew_SetRedraw(ProcessTreeListHandle, FALSE);
ProcessesNeedsRedraw = TRUE;
}
processNode = PhAddProcessNode(ProcessItem, RunId);
if (RunId != 1)
{
PPH_PROCESS_ITEM parentProcess;
HANDLE parentProcessId = NULL;
PPH_STRING parentName = NULL;
if (parentProcess = PhReferenceProcessItemForParent(
ProcessItem->ParentProcessId,
ProcessItem->ProcessId,
&ProcessItem->CreateTime
))
{
parentProcessId = parentProcess->ProcessId;
parentName = parentProcess->ProcessName;
}
PhLogProcessEntry(
PH_LOG_ENTRY_PROCESS_CREATE,
ProcessItem->ProcessId,
ProcessItem->ProcessName,
parentProcessId,
parentName
);
if (NotifyIconNotifyMask & PH_NOTIFY_PROCESS_CREATE)
{
if (!PhPluginsEnabled || !PhpPluginNotifyEvent(PH_NOTIFY_PROCESS_CREATE, ProcessItem))
{
PhShowIconNotification(L"Process Created", PhaFormatString(
L"The process %s (%u) was created by %s (%u)",
ProcessItem->ProcessName->Buffer,
(ULONG)ProcessItem->ProcessId,
PhGetStringOrDefault(parentName, L"Unknown Process"),
(ULONG)ProcessItem->ParentProcessId
)->Buffer, NIIF_INFO);
}
}
if (parentProcess)
PhDereferenceObject(parentProcess);
}
// PhCreateProcessNode has its own reference.
PhDereferenceObject(ProcessItem);
}
VOID PhMainWndOnProcessModified(
__in PPH_PROCESS_ITEM ProcessItem
)
{
PhUpdateProcessNode(PhFindProcessNode(ProcessItem->ProcessId));
if (SignedFilterEntry)
PhApplyProcessTreeFilters();
}
VOID PhMainWndOnProcessRemoved(
__in PPH_PROCESS_ITEM ProcessItem
)
{
if (!ProcessesNeedsRedraw)
{
TreeNew_SetRedraw(ProcessTreeListHandle, FALSE);
ProcessesNeedsRedraw = TRUE;
}
PhLogProcessEntry(PH_LOG_ENTRY_PROCESS_DELETE, ProcessItem->ProcessId, ProcessItem->ProcessName, NULL, NULL);
if (NotifyIconNotifyMask & PH_NOTIFY_PROCESS_DELETE)
{
if (!PhPluginsEnabled || !PhpPluginNotifyEvent(PH_NOTIFY_PROCESS_DELETE, ProcessItem))
{
PhShowIconNotification(L"Process Terminated", PhaFormatString(
L"The process %s (%u) was terminated.",
ProcessItem->ProcessName->Buffer,
(ULONG)ProcessItem->ProcessId
)->Buffer, NIIF_INFO);
}
}
PhRemoveProcessNode(PhFindProcessNode(ProcessItem->ProcessId));
}
VOID PhMainWndOnProcessesUpdated()
{
// The modified notification is only sent for special cases.
// We have to invalidate the text on each update.
PhTickProcessNodes();
if (PhPluginsEnabled)
{
PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessesUpdated), NULL);
}
if (ProcessesNeedsRedraw)
{
TreeNew_SetRedraw(ProcessTreeListHandle, TRUE);
ProcessesNeedsRedraw = FALSE;
}
}
VOID PhMainWndOnServiceAdded(
__in __assumeRefs(1) PPH_SERVICE_ITEM ServiceItem,
__in ULONG RunId
)
{
PPH_SERVICE_NODE serviceNode;
if (ServiceTreeListLoaded)
{
if (!ServicesNeedsRedraw)
{
TreeNew_SetRedraw(ServiceTreeListHandle, FALSE);
ServicesNeedsRedraw = TRUE;
}
serviceNode = PhAddServiceNode(ServiceItem, RunId);
// ServiceItem dereferenced below
}
else
{
if (!ServicesPendingList)
ServicesPendingList = PhCreatePointerList(100);
PhAddItemPointerList(ServicesPendingList, ServiceItem);
}
if (RunId != 1)
{
PhLogServiceEntry(PH_LOG_ENTRY_SERVICE_CREATE, ServiceItem->Name, ServiceItem->DisplayName);
if (NotifyIconNotifyMask & PH_NOTIFY_SERVICE_CREATE)
{
if (!PhPluginsEnabled || !PhpPluginNotifyEvent(PH_NOTIFY_SERVICE_CREATE, ServiceItem))
{
PhShowIconNotification(L"Service Created", PhaFormatString(
L"The service %s (%s) has been created.",
ServiceItem->Name->Buffer,
ServiceItem->DisplayName->Buffer
)->Buffer, NIIF_INFO);
}
}
}
if (ServiceTreeListLoaded)
PhDereferenceObject(ServiceItem);
}
VOID PhMainWndOnServiceModified(
__in PPH_SERVICE_MODIFIED_DATA ServiceModifiedData
)
{
PH_SERVICE_CHANGE serviceChange;
UCHAR logEntryType;
if (ServiceTreeListLoaded)
{
//if (!ServicesNeedsRedraw)
//{
// TreeNew_SetRedraw(ServiceTreeListHandle, FALSE);
// ServicesNeedsRedraw = TRUE;
//}
PhUpdateServiceNode(PhFindServiceNode(ServiceModifiedData->Service));
}
serviceChange = PhGetServiceChange(ServiceModifiedData);
switch (serviceChange)
{
case ServiceStarted:
logEntryType = PH_LOG_ENTRY_SERVICE_START;
break;
case ServiceStopped:
logEntryType = PH_LOG_ENTRY_SERVICE_STOP;
break;
case ServiceContinued:
logEntryType = PH_LOG_ENTRY_SERVICE_CONTINUE;
break;
case ServicePaused:
logEntryType = PH_LOG_ENTRY_SERVICE_PAUSE;
break;
default:
logEntryType = 0;
break;
}
if (logEntryType != 0)
PhLogServiceEntry(logEntryType, ServiceModifiedData->Service->Name, ServiceModifiedData->Service->DisplayName);
if (NotifyIconNotifyMask & (PH_NOTIFY_SERVICE_START | PH_NOTIFY_SERVICE_STOP))
{
PPH_SERVICE_ITEM serviceItem;
serviceItem = ServiceModifiedData->Service;
if (serviceChange == ServiceStarted && (NotifyIconNotifyMask & PH_NOTIFY_SERVICE_START))
{
if (!PhPluginsEnabled || !PhpPluginNotifyEvent(PH_NOTIFY_SERVICE_START, serviceItem))
{
PhShowIconNotification(L"Service Started", PhaFormatString(
L"The service %s (%s) has been started.",
serviceItem->Name->Buffer,
serviceItem->DisplayName->Buffer
)->Buffer, NIIF_INFO);
}
}
else if (serviceChange == ServiceStopped && (NotifyIconNotifyMask & PH_NOTIFY_SERVICE_STOP))
{
if (!PhPluginsEnabled || !PhpPluginNotifyEvent(PH_NOTIFY_SERVICE_STOP, serviceItem))
{
PhShowIconNotification(L"Service Stopped", PhaFormatString(
L"The service %s (%s) has been stopped.",
serviceItem->Name->Buffer,
serviceItem->DisplayName->Buffer
)->Buffer, NIIF_INFO);
}
}
}
}
VOID PhMainWndOnServiceRemoved(
__in PPH_SERVICE_ITEM ServiceItem
)
{
if (ServiceTreeListLoaded)
{
if (!ServicesNeedsRedraw)
{
TreeNew_SetRedraw(ServiceTreeListHandle, FALSE);
ServicesNeedsRedraw = TRUE;
}
}
PhLogServiceEntry(PH_LOG_ENTRY_SERVICE_DELETE, ServiceItem->Name, ServiceItem->DisplayName);
if (NotifyIconNotifyMask & PH_NOTIFY_SERVICE_CREATE)
{
if (!PhPluginsEnabled || !PhpPluginNotifyEvent(PH_NOTIFY_SERVICE_DELETE, ServiceItem))
{
PhShowIconNotification(L"Service Deleted", PhaFormatString(
L"The service %s (%s) has been deleted.",
ServiceItem->Name->Buffer,
ServiceItem->DisplayName->Buffer
)->Buffer, NIIF_INFO);
}
}
if (ServiceTreeListLoaded)
{
PhRemoveServiceNode(PhFindServiceNode(ServiceItem));
}
else
{
if (ServicesPendingList)
{
HANDLE pointerHandle;
// Remove the service from the pending list so we don't try to add it
// later.
if (pointerHandle = PhFindItemPointerList(ServicesPendingList, ServiceItem))
PhRemoveItemPointerList(ServicesPendingList, pointerHandle);
PhDereferenceObject(ServiceItem);
}
}
}
VOID PhMainWndOnServicesUpdated()
{
if (ServiceTreeListLoaded)
{
PhTickServiceNodes();
if (ServicesNeedsRedraw)
{
TreeNew_SetRedraw(ServiceTreeListHandle, TRUE);
ServicesNeedsRedraw = FALSE;
}
}
}
PWSTR PhpGetNetworkItemProcessName(
__in PPH_NETWORK_ITEM NetworkItem
)
{
PPH_STRING string;
PH_FORMAT format[4];
if (!NetworkItem->ProcessId)
return L"Waiting Connections";
PhInitFormatS(&format[1], L" (");
PhInitFormatU(&format[2], (ULONG)NetworkItem->ProcessId);
PhInitFormatC(&format[3], ')');
if (NetworkItem->ProcessName)
PhInitFormatSR(&format[0], NetworkItem->ProcessName->sr);
else
PhInitFormatS(&format[0], L"Unknown Process");
string = PhFormat(format, 4, 96);
PhaDereferenceObject(string);
return string->Buffer;
}
VOID PhpSetNetworkItemImageIndex(
__in INT ItemIndex,
__in PPH_NETWORK_ITEM NetworkItem
)
{
INT imageIndex;
if (NetworkItem->ProcessIconValid && NetworkItem->ProcessIcon)
{
imageIndex = PhImageListWrapperAddIcon(&NetworkImageListWrapper, NetworkItem->ProcessIcon);
}
else
{
imageIndex = 0;
}
PhSetListViewItemImageIndex(NetworkListViewHandle, ItemIndex, imageIndex);
}
VOID PhMainWndOnNetworkItemAdded(
__in ULONG RunId,
__in PPH_NETWORK_ITEM NetworkItem
)
{
INT lvItemIndex;
if (!NetworkNeedsRedraw)
{
ExtendedListView_SetRedraw(NetworkListViewHandle, FALSE);
NetworkNeedsRedraw = TRUE;
}
// Add a reference for the pointer being stored in the list view item.
PhReferenceObject(NetworkItem);
if (RunId == 1) ExtendedListView_SetStateHighlighting(NetworkListViewHandle, FALSE);
lvItemIndex = PhAddListViewItem(
NetworkListViewHandle,
MAXINT,
PhpGetNetworkItemProcessName(NetworkItem),
NetworkItem
);
if (RunId == 1) ExtendedListView_SetStateHighlighting(NetworkListViewHandle, TRUE);
PhSetListViewSubItem(NetworkListViewHandle, lvItemIndex, 1,
PhGetStringOrDefault(NetworkItem->LocalHostString, NetworkItem->LocalAddressString));
PhSetListViewSubItem(NetworkListViewHandle, lvItemIndex, 2, NetworkItem->LocalPortString);
PhSetListViewSubItem(NetworkListViewHandle, lvItemIndex, 3,
PhGetStringOrDefault(NetworkItem->RemoteHostString, NetworkItem->RemoteAddressString));
PhSetListViewSubItem(NetworkListViewHandle, lvItemIndex, 4, NetworkItem->RemotePortString);
PhSetListViewSubItem(NetworkListViewHandle, lvItemIndex, 5, PhGetProtocolTypeName(NetworkItem->ProtocolType));
PhSetListViewSubItem(NetworkListViewHandle, lvItemIndex, 6,
(NetworkItem->ProtocolType & PH_TCP_PROTOCOL_TYPE) ? PhGetTcpStateName(NetworkItem->State) : NULL);
if (WINDOWS_HAS_SERVICE_TAGS)
PhSetListViewSubItem(NetworkListViewHandle, lvItemIndex, 7, PhGetString(NetworkItem->OwnerName));
if (!NetworkImageListWrapper.Handle)
{
HICON icon;
PhGetStockApplicationIcon(&icon, NULL);
PhInitializeImageListWrapper(&NetworkImageListWrapper, PhSmallIconSize.X, PhSmallIconSize.Y, ILC_COLOR32 | ILC_MASK);
PhImageListWrapperAddIcon(&NetworkImageListWrapper, icon);
ListView_SetImageList(NetworkListViewHandle, NetworkImageListWrapper.Handle, LVSIL_SMALL);
}
PhpSetNetworkItemImageIndex(lvItemIndex, NetworkItem);
NetworkNeedsSort = TRUE;
}
VOID PhMainWndOnNetworkItemModified(
__in PPH_NETWORK_ITEM NetworkItem
)
{
INT lvItemIndex;
INT imageIndex;
if (!NetworkNeedsRedraw)
{
ExtendedListView_SetRedraw(NetworkListViewHandle, FALSE);
NetworkNeedsRedraw = TRUE;
}
lvItemIndex = PhFindListViewItemByParam(NetworkListViewHandle, -1, NetworkItem);
PhSetListViewSubItem(NetworkListViewHandle, lvItemIndex, 0,
PhpGetNetworkItemProcessName(NetworkItem));
PhSetListViewSubItem(NetworkListViewHandle, lvItemIndex, 1,
PhGetStringOrDefault(NetworkItem->LocalHostString, NetworkItem->LocalAddressString));
PhSetListViewSubItem(NetworkListViewHandle, lvItemIndex, 3,
PhGetStringOrDefault(NetworkItem->RemoteHostString, NetworkItem->RemoteAddressString));
PhSetListViewSubItem(NetworkListViewHandle, lvItemIndex, 6,
(NetworkItem->ProtocolType & PH_TCP_PROTOCOL_TYPE) ? PhGetTcpStateName(NetworkItem->State) : NULL);
if (WINDOWS_HAS_SERVICE_TAGS)
PhSetListViewSubItem(NetworkListViewHandle, lvItemIndex, 7, PhGetString(NetworkItem->OwnerName));
// Only set a new icon if we didn't have a proper one before.
if (PhGetListViewItemImageIndex(
NetworkListViewHandle,
lvItemIndex,
&imageIndex
) && imageIndex == 0)
{
PhpSetNetworkItemImageIndex(lvItemIndex, NetworkItem);
}
NetworkNeedsSort = TRUE;
}
VOID PhMainWndOnNetworkItemRemoved(
__in PPH_NETWORK_ITEM NetworkItem
)
{
INT lvItemIndex;
INT imageIndex;
if (!NetworkNeedsRedraw)
{
ExtendedListView_SetRedraw(NetworkListViewHandle, FALSE);
NetworkNeedsRedraw = TRUE;
}
lvItemIndex = PhFindListViewItemByParam(NetworkListViewHandle, -1, NetworkItem);
if (PhGetListViewItemImageIndex(
NetworkListViewHandle,
lvItemIndex,
&imageIndex
) && imageIndex != 0)
{
PhImageListWrapperRemove(&NetworkImageListWrapper, imageIndex);
// Set to a generic icon so we don't get random icons popping up due to
// the delay caused by state highlighting.
PhSetListViewItemImageIndex(NetworkListViewHandle, lvItemIndex, 0);
}
PhRemoveListViewItem(
NetworkListViewHandle,
lvItemIndex
);
// Remove the reference we added in PhMainWndOnNetworkItemAdded.
PhDereferenceObject(NetworkItem);
}
VOID PhMainWndOnNetworkItemsUpdated()
{
ExtendedListView_Tick(NetworkListViewHandle);
if (NetworkNeedsSort)
{
ExtendedListView_SortItems(NetworkListViewHandle);
NetworkNeedsSort = FALSE;
}
if (NetworkNeedsRedraw)
{
ExtendedListView_SetRedraw(NetworkListViewHandle, TRUE);
NetworkNeedsRedraw = FALSE;
}
}