mirror of
https://github.com/mirror/processhacker
synced 2026-06-08 16:03:24 +00:00
52f9e7a948
git-svn-id: svn://svn.code.sf.net/p/processhacker/code@6329 21ef857c-d57f-4fe0-8362-d861dc6d29cd
5608 lines
198 KiB
C
5608 lines
198 KiB
C
/*
|
|
* Process Hacker -
|
|
* process properties
|
|
*
|
|
* Copyright (C) 2009-2015 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/>.
|
|
*/
|
|
|
|
#include <phapp.h>
|
|
#include <secedit.h>
|
|
#include <kphuser.h>
|
|
#include <settings.h>
|
|
#include <cpysave.h>
|
|
#include <emenu.h>
|
|
#include <phplug.h>
|
|
#include <extmgri.h>
|
|
#include <verify.h>
|
|
#include <procprpp.h>
|
|
#include <windowsx.h>
|
|
|
|
#define SET_BUTTON_BITMAP(Id, Bitmap) \
|
|
SendMessage(GetDlgItem(hwndDlg, (Id)), BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)(Bitmap))
|
|
|
|
PPH_OBJECT_TYPE PhpProcessPropContextType;
|
|
PPH_OBJECT_TYPE PhpProcessPropPageContextType;
|
|
|
|
static RECT MinimumSize = { -1, -1, -1, -1 };
|
|
static PWSTR ProtectedSignerStrings[] = { L"", L" (Authenticode)", L" (CodeGen)", L" (Antimalware)", L" (Lsa)", L" (Windows)", L" (WinTcb)" };
|
|
|
|
static PH_STRINGREF LoadingText = PH_STRINGREF_INIT(L"Loading...");
|
|
static PH_STRINGREF EmptyThreadsText = PH_STRINGREF_INIT(L"There are no threads to display.");
|
|
static PH_STRINGREF EmptyModulesText = PH_STRINGREF_INIT(L"There are no modules to display.");
|
|
static PH_STRINGREF EmptyMemoryText = PH_STRINGREF_INIT(L"There are no memory regions to display.");
|
|
static PH_STRINGREF EmptyHandlesText = PH_STRINGREF_INIT(L"There are no handles to display.");
|
|
|
|
BOOLEAN PhProcessPropInitialization(
|
|
VOID
|
|
)
|
|
{
|
|
PhpProcessPropContextType = PhCreateObjectType(L"ProcessPropContext", 0, PhpProcessPropContextDeleteProcedure);
|
|
PhpProcessPropPageContextType = PhCreateObjectType(L"ProcessPropPageContext", 0, PhpProcessPropPageContextDeleteProcedure);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
PPH_PROCESS_PROPCONTEXT PhCreateProcessPropContext(
|
|
_In_ HWND ParentWindowHandle,
|
|
_In_ PPH_PROCESS_ITEM ProcessItem
|
|
)
|
|
{
|
|
PPH_PROCESS_PROPCONTEXT propContext;
|
|
PROPSHEETHEADER propSheetHeader;
|
|
|
|
propContext = PhCreateObject(sizeof(PH_PROCESS_PROPCONTEXT), PhpProcessPropContextType);
|
|
memset(propContext, 0, sizeof(PH_PROCESS_PROPCONTEXT));
|
|
|
|
propContext->PropSheetPages = PhAllocate(sizeof(HPROPSHEETPAGE) * PH_PROCESS_PROPCONTEXT_MAXPAGES);
|
|
|
|
if (!PH_IS_FAKE_PROCESS_ID(ProcessItem->ProcessId))
|
|
{
|
|
propContext->Title = PhFormatString(
|
|
L"%s (%u)",
|
|
ProcessItem->ProcessName->Buffer,
|
|
HandleToUlong(ProcessItem->ProcessId)
|
|
);
|
|
}
|
|
else
|
|
{
|
|
PhSetReference(&propContext->Title, ProcessItem->ProcessName);
|
|
}
|
|
|
|
memset(&propSheetHeader, 0, sizeof(PROPSHEETHEADER));
|
|
propSheetHeader.dwSize = sizeof(PROPSHEETHEADER);
|
|
propSheetHeader.dwFlags =
|
|
PSH_MODELESS |
|
|
PSH_NOAPPLYNOW |
|
|
PSH_NOCONTEXTHELP |
|
|
PSH_PROPTITLE |
|
|
PSH_USECALLBACK |
|
|
PSH_USEHICON;
|
|
propSheetHeader.hwndParent = ParentWindowHandle;
|
|
propSheetHeader.hIcon = ProcessItem->SmallIcon;
|
|
propSheetHeader.pszCaption = propContext->Title->Buffer;
|
|
propSheetHeader.pfnCallback = PhpPropSheetProc;
|
|
|
|
propSheetHeader.nPages = 0;
|
|
propSheetHeader.nStartPage = 0;
|
|
propSheetHeader.phpage = propContext->PropSheetPages;
|
|
|
|
if (PhCsForceNoParent)
|
|
propSheetHeader.hwndParent = NULL;
|
|
|
|
memcpy(&propContext->PropSheetHeader, &propSheetHeader, sizeof(PROPSHEETHEADER));
|
|
|
|
PhSetReference(&propContext->ProcessItem, ProcessItem);
|
|
PhInitializeEvent(&propContext->CreatedEvent);
|
|
|
|
return propContext;
|
|
}
|
|
|
|
VOID NTAPI PhpProcessPropContextDeleteProcedure(
|
|
_In_ PVOID Object,
|
|
_In_ ULONG Flags
|
|
)
|
|
{
|
|
PPH_PROCESS_PROPCONTEXT propContext = (PPH_PROCESS_PROPCONTEXT)Object;
|
|
|
|
PhFree(propContext->PropSheetPages);
|
|
PhDereferenceObject(propContext->Title);
|
|
PhDereferenceObject(propContext->ProcessItem);
|
|
}
|
|
|
|
VOID PhRefreshProcessPropContext(
|
|
_Inout_ PPH_PROCESS_PROPCONTEXT PropContext
|
|
)
|
|
{
|
|
PropContext->PropSheetHeader.hIcon = PropContext->ProcessItem->SmallIcon;
|
|
}
|
|
|
|
VOID PhSetSelectThreadIdProcessPropContext(
|
|
_Inout_ PPH_PROCESS_PROPCONTEXT PropContext,
|
|
_In_ HANDLE ThreadId
|
|
)
|
|
{
|
|
PropContext->SelectThreadId = ThreadId;
|
|
}
|
|
|
|
INT CALLBACK PhpPropSheetProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ LPARAM lParam
|
|
)
|
|
{
|
|
#define PROPSHEET_ADD_STYLE (WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME);
|
|
|
|
switch (uMsg)
|
|
{
|
|
case PSCB_PRECREATE:
|
|
{
|
|
if (lParam)
|
|
{
|
|
if (((DLGTEMPLATEEX *)lParam)->signature == 0xffff)
|
|
{
|
|
((DLGTEMPLATEEX *)lParam)->style |= PROPSHEET_ADD_STYLE;
|
|
}
|
|
else
|
|
{
|
|
((DLGTEMPLATE *)lParam)->style |= PROPSHEET_ADD_STYLE;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case PSCB_INITIALIZED:
|
|
{
|
|
PPH_PROCESS_PROPSHEETCONTEXT propSheetContext;
|
|
|
|
propSheetContext = PhAllocate(sizeof(PH_PROCESS_PROPSHEETCONTEXT));
|
|
memset(propSheetContext, 0, sizeof(PH_PROCESS_PROPSHEETCONTEXT));
|
|
|
|
PhInitializeLayoutManager(&propSheetContext->LayoutManager, hwndDlg);
|
|
|
|
propSheetContext->OldWndProc = (WNDPROC)GetWindowLongPtr(hwndDlg, GWLP_WNDPROC);
|
|
SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)PhpPropSheetWndProc);
|
|
|
|
SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)propSheetContext);
|
|
|
|
if (MinimumSize.left == -1)
|
|
{
|
|
RECT rect;
|
|
|
|
rect.left = 0;
|
|
rect.top = 0;
|
|
rect.right = 290;
|
|
rect.bottom = 320;
|
|
MapDialogRect(hwndDlg, &rect);
|
|
MinimumSize = rect;
|
|
MinimumSize.left = 0;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
PPH_PROCESS_PROPSHEETCONTEXT PhpGetPropSheetContext(
|
|
_In_ HWND hwnd
|
|
)
|
|
{
|
|
return (PPH_PROCESS_PROPSHEETCONTEXT)GetProp(hwnd, PhMakeContextAtom());
|
|
}
|
|
|
|
LRESULT CALLBACK PhpPropSheetWndProc(
|
|
_In_ HWND hwnd,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
)
|
|
{
|
|
PPH_PROCESS_PROPSHEETCONTEXT propSheetContext = PhpGetPropSheetContext(hwnd);
|
|
WNDPROC oldWndProc = propSheetContext->OldWndProc;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_DESTROY:
|
|
{
|
|
HWND tabControl;
|
|
TCITEM tabItem;
|
|
WCHAR text[128];
|
|
|
|
// Save the window position and size.
|
|
|
|
PhSaveWindowPlacementToSetting(L"ProcPropPosition", L"ProcPropSize", hwnd);
|
|
|
|
// Save the selected tab.
|
|
|
|
tabControl = PropSheet_GetTabControl(hwnd);
|
|
|
|
tabItem.mask = TCIF_TEXT;
|
|
tabItem.pszText = text;
|
|
tabItem.cchTextMax = sizeof(text) / 2 - 1;
|
|
|
|
if (TabCtrl_GetItem(tabControl, TabCtrl_GetCurSel(tabControl), &tabItem))
|
|
{
|
|
PhSetStringSetting(L"ProcPropPage", text);
|
|
}
|
|
}
|
|
break;
|
|
case WM_NCDESTROY:
|
|
{
|
|
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc);
|
|
PhDeleteLayoutManager(&propSheetContext->LayoutManager);
|
|
|
|
RemoveProp(hwnd, PhMakeContextAtom());
|
|
PhFree(propSheetContext);
|
|
}
|
|
break;
|
|
case WM_COMMAND:
|
|
{
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDOK:
|
|
// Prevent the OK button from working (even though
|
|
// it's already hidden). This prevents the Enter
|
|
// key from closing the dialog box.
|
|
return 0;
|
|
}
|
|
}
|
|
break;
|
|
case WM_SIZE:
|
|
{
|
|
if (!IsIconic(hwnd))
|
|
{
|
|
PhLayoutManagerLayout(&propSheetContext->LayoutManager);
|
|
}
|
|
}
|
|
break;
|
|
case WM_SIZING:
|
|
{
|
|
PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam);
|
|
}
|
|
|
|
BOOLEAN PhpInitializePropSheetLayoutStage1(
|
|
_In_ HWND hwnd
|
|
)
|
|
{
|
|
PPH_PROCESS_PROPSHEETCONTEXT propSheetContext = PhpGetPropSheetContext(hwnd);
|
|
|
|
if (!propSheetContext->LayoutInitialized)
|
|
{
|
|
HWND tabControlHandle;
|
|
PPH_LAYOUT_ITEM tabControlItem;
|
|
PPH_LAYOUT_ITEM tabPageItem;
|
|
|
|
tabControlHandle = PropSheet_GetTabControl(hwnd);
|
|
tabControlItem = PhAddLayoutItem(&propSheetContext->LayoutManager, tabControlHandle,
|
|
NULL, PH_ANCHOR_ALL | PH_LAYOUT_IMMEDIATE_RESIZE);
|
|
tabPageItem = PhAddLayoutItem(&propSheetContext->LayoutManager, tabControlHandle,
|
|
NULL, PH_LAYOUT_TAB_CONTROL); // dummy item to fix multiline tab control
|
|
|
|
propSheetContext->TabPageItem = tabPageItem;
|
|
|
|
PhAddLayoutItem(&propSheetContext->LayoutManager, GetDlgItem(hwnd, IDCANCEL),
|
|
NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
|
|
|
|
// Hide the OK button.
|
|
ShowWindow(GetDlgItem(hwnd, IDOK), SW_HIDE);
|
|
// Set the Cancel button's text to "Close".
|
|
SetDlgItemText(hwnd, IDCANCEL, L"Close");
|
|
|
|
propSheetContext->LayoutInitialized = TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
VOID PhpInitializePropSheetLayoutStage2(
|
|
_In_ HWND hwnd
|
|
)
|
|
{
|
|
PH_RECTANGLE windowRectangle;
|
|
|
|
windowRectangle.Position = PhGetIntegerPairSetting(L"ProcPropPosition");
|
|
windowRectangle.Size = PhGetIntegerPairSetting(L"ProcPropSize");
|
|
|
|
if (windowRectangle.Size.X < MinimumSize.right)
|
|
windowRectangle.Size.X = MinimumSize.right;
|
|
if (windowRectangle.Size.Y < MinimumSize.bottom)
|
|
windowRectangle.Size.Y = MinimumSize.bottom;
|
|
|
|
PhAdjustRectangleToWorkingArea(hwnd, &windowRectangle);
|
|
|
|
MoveWindow(hwnd, windowRectangle.Left, windowRectangle.Top,
|
|
windowRectangle.Width, windowRectangle.Height, FALSE);
|
|
|
|
// Implement cascading by saving an offsetted rectangle.
|
|
windowRectangle.Left += 20;
|
|
windowRectangle.Top += 20;
|
|
|
|
PhSetIntegerPairSetting(L"ProcPropPosition", windowRectangle.Position);
|
|
}
|
|
|
|
BOOLEAN PhAddProcessPropPage(
|
|
_Inout_ PPH_PROCESS_PROPCONTEXT PropContext,
|
|
_In_ _Assume_refs_(1) PPH_PROCESS_PROPPAGECONTEXT PropPageContext
|
|
)
|
|
{
|
|
HPROPSHEETPAGE propSheetPageHandle;
|
|
|
|
if (PropContext->PropSheetHeader.nPages == PH_PROCESS_PROPCONTEXT_MAXPAGES)
|
|
return FALSE;
|
|
|
|
propSheetPageHandle = CreatePropertySheetPage(
|
|
&PropPageContext->PropSheetPage
|
|
);
|
|
// CreatePropertySheetPage would have sent PSPCB_ADDREF,
|
|
// which would have added a reference.
|
|
PhDereferenceObject(PropPageContext);
|
|
|
|
PropPageContext->PropContext = PropContext;
|
|
PhReferenceObject(PropContext);
|
|
|
|
PropContext->PropSheetPages[PropContext->PropSheetHeader.nPages] =
|
|
propSheetPageHandle;
|
|
PropContext->PropSheetHeader.nPages++;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN PhAddProcessPropPage2(
|
|
_Inout_ PPH_PROCESS_PROPCONTEXT PropContext,
|
|
_In_ HPROPSHEETPAGE PropSheetPageHandle
|
|
)
|
|
{
|
|
if (PropContext->PropSheetHeader.nPages == PH_PROCESS_PROPCONTEXT_MAXPAGES)
|
|
return FALSE;
|
|
|
|
PropContext->PropSheetPages[PropContext->PropSheetHeader.nPages] =
|
|
PropSheetPageHandle;
|
|
PropContext->PropSheetHeader.nPages++;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
PPH_PROCESS_PROPPAGECONTEXT PhCreateProcessPropPageContext(
|
|
_In_ LPCWSTR Template,
|
|
_In_ DLGPROC DlgProc,
|
|
_In_opt_ PVOID Context
|
|
)
|
|
{
|
|
return PhCreateProcessPropPageContextEx(NULL, Template, DlgProc, Context);
|
|
}
|
|
|
|
PPH_PROCESS_PROPPAGECONTEXT PhCreateProcessPropPageContextEx(
|
|
_In_opt_ PVOID InstanceHandle,
|
|
_In_ LPCWSTR Template,
|
|
_In_ DLGPROC DlgProc,
|
|
_In_opt_ PVOID Context
|
|
)
|
|
{
|
|
PPH_PROCESS_PROPPAGECONTEXT propPageContext;
|
|
|
|
propPageContext = PhCreateObject(sizeof(PH_PROCESS_PROPPAGECONTEXT), PhpProcessPropPageContextType);
|
|
memset(propPageContext, 0, sizeof(PH_PROCESS_PROPPAGECONTEXT));
|
|
|
|
propPageContext->PropSheetPage.dwSize = sizeof(PROPSHEETPAGE);
|
|
propPageContext->PropSheetPage.dwFlags =
|
|
PSP_USECALLBACK;
|
|
propPageContext->PropSheetPage.hInstance = InstanceHandle;
|
|
propPageContext->PropSheetPage.pszTemplate = Template;
|
|
propPageContext->PropSheetPage.pfnDlgProc = DlgProc;
|
|
propPageContext->PropSheetPage.lParam = (LPARAM)propPageContext;
|
|
propPageContext->PropSheetPage.pfnCallback = PhpStandardPropPageProc;
|
|
|
|
propPageContext->Context = Context;
|
|
|
|
return propPageContext;
|
|
}
|
|
|
|
VOID NTAPI PhpProcessPropPageContextDeleteProcedure(
|
|
_In_ PVOID Object,
|
|
_In_ ULONG Flags
|
|
)
|
|
{
|
|
PPH_PROCESS_PROPPAGECONTEXT propPageContext = (PPH_PROCESS_PROPPAGECONTEXT)Object;
|
|
|
|
if (propPageContext->PropContext)
|
|
PhDereferenceObject(propPageContext->PropContext);
|
|
}
|
|
|
|
INT CALLBACK PhpStandardPropPageProc(
|
|
_In_ HWND hwnd,
|
|
_In_ UINT uMsg,
|
|
_In_ LPPROPSHEETPAGE ppsp
|
|
)
|
|
{
|
|
PPH_PROCESS_PROPPAGECONTEXT propPageContext;
|
|
|
|
propPageContext = (PPH_PROCESS_PROPPAGECONTEXT)ppsp->lParam;
|
|
|
|
if (uMsg == PSPCB_ADDREF)
|
|
PhReferenceObject(propPageContext);
|
|
else if (uMsg == PSPCB_RELEASE)
|
|
PhDereferenceObject(propPageContext);
|
|
|
|
return 1;
|
|
}
|
|
|
|
FORCEINLINE BOOLEAN PhpPropPageDlgProcHeader(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ LPARAM lParam,
|
|
_Out_ LPPROPSHEETPAGE *PropSheetPage,
|
|
_Out_ PPH_PROCESS_PROPPAGECONTEXT *PropPageContext,
|
|
_Out_ PPH_PROCESS_ITEM *ProcessItem
|
|
)
|
|
{
|
|
LPPROPSHEETPAGE propSheetPage;
|
|
PPH_PROCESS_PROPPAGECONTEXT propPageContext;
|
|
|
|
if (uMsg == WM_INITDIALOG)
|
|
{
|
|
// Save the context.
|
|
SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)lParam);
|
|
}
|
|
|
|
propSheetPage = (LPPROPSHEETPAGE)GetProp(hwndDlg, PhMakeContextAtom());
|
|
|
|
if (!propSheetPage)
|
|
return FALSE;
|
|
|
|
*PropSheetPage = propSheetPage;
|
|
*PropPageContext = propPageContext = (PPH_PROCESS_PROPPAGECONTEXT)propSheetPage->lParam;
|
|
*ProcessItem = propPageContext->PropContext->ProcessItem;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN PhPropPageDlgProcHeader(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ LPARAM lParam,
|
|
_Out_ LPPROPSHEETPAGE *PropSheetPage,
|
|
_Out_ PPH_PROCESS_PROPPAGECONTEXT *PropPageContext,
|
|
_Out_ PPH_PROCESS_ITEM *ProcessItem
|
|
)
|
|
{
|
|
return PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam, PropSheetPage, PropPageContext, ProcessItem);
|
|
}
|
|
|
|
VOID PhpPropPageDlgProcDestroy(
|
|
_In_ HWND hwndDlg
|
|
)
|
|
{
|
|
RemoveProp(hwndDlg, PhMakeContextAtom());
|
|
}
|
|
|
|
VOID PhPropPageDlgProcDestroy(
|
|
_In_ HWND hwndDlg
|
|
)
|
|
{
|
|
PhpPropPageDlgProcDestroy(hwndDlg);
|
|
}
|
|
|
|
PPH_LAYOUT_ITEM PhAddPropPageLayoutItem(
|
|
_In_ HWND hwnd,
|
|
_In_ HWND Handle,
|
|
_In_ PPH_LAYOUT_ITEM ParentItem,
|
|
_In_ ULONG Anchor
|
|
)
|
|
{
|
|
HWND parent;
|
|
PPH_PROCESS_PROPSHEETCONTEXT propSheetContext;
|
|
PPH_LAYOUT_MANAGER layoutManager;
|
|
PPH_LAYOUT_ITEM realParentItem;
|
|
BOOLEAN doLayoutStage2;
|
|
PPH_LAYOUT_ITEM item;
|
|
|
|
parent = GetParent(hwnd);
|
|
propSheetContext = PhpGetPropSheetContext(parent);
|
|
layoutManager = &propSheetContext->LayoutManager;
|
|
|
|
doLayoutStage2 = PhpInitializePropSheetLayoutStage1(parent);
|
|
|
|
if (ParentItem != PH_PROP_PAGE_TAB_CONTROL_PARENT)
|
|
realParentItem = ParentItem;
|
|
else
|
|
realParentItem = propSheetContext->TabPageItem;
|
|
|
|
// Use the HACK if the control is a direct child of the dialog.
|
|
if (ParentItem && ParentItem != PH_PROP_PAGE_TAB_CONTROL_PARENT &&
|
|
// We detect if ParentItem is the layout item for the dialog
|
|
// by looking at its parent.
|
|
(ParentItem->ParentItem == &layoutManager->RootItem ||
|
|
(ParentItem->ParentItem->Anchor & PH_LAYOUT_TAB_CONTROL)))
|
|
{
|
|
RECT dialogRect;
|
|
RECT dialogSize;
|
|
RECT margin;
|
|
|
|
// MAKE SURE THESE NUMBERS ARE CORRECT.
|
|
dialogSize.right = 260;
|
|
dialogSize.bottom = 260;
|
|
MapDialogRect(hwnd, &dialogSize);
|
|
|
|
// Get the original dialog rectangle.
|
|
GetWindowRect(hwnd, &dialogRect);
|
|
dialogRect.right = dialogRect.left + dialogSize.right;
|
|
dialogRect.bottom = dialogRect.top + dialogSize.bottom;
|
|
|
|
// Calculate the margin from the original rectangle.
|
|
GetWindowRect(Handle, &margin);
|
|
margin = PhMapRect(margin, dialogRect);
|
|
PhConvertRect(&margin, &dialogRect);
|
|
|
|
item = PhAddLayoutItemEx(layoutManager, Handle, realParentItem, Anchor, margin);
|
|
}
|
|
else
|
|
{
|
|
item = PhAddLayoutItem(layoutManager, Handle, realParentItem, Anchor);
|
|
}
|
|
|
|
if (doLayoutStage2)
|
|
PhpInitializePropSheetLayoutStage2(parent);
|
|
|
|
return item;
|
|
}
|
|
|
|
VOID PhDoPropPageLayout(
|
|
_In_ HWND hwnd
|
|
)
|
|
{
|
|
HWND parent;
|
|
PPH_PROCESS_PROPSHEETCONTEXT propSheetContext;
|
|
|
|
parent = GetParent(hwnd);
|
|
propSheetContext = PhpGetPropSheetContext(parent);
|
|
PhLayoutManagerLayout(&propSheetContext->LayoutManager);
|
|
}
|
|
|
|
NTSTATUS PhpProcessGeneralOpenProcess(
|
|
_Out_ PHANDLE Handle,
|
|
_In_ ACCESS_MASK DesiredAccess,
|
|
_In_opt_ PVOID Context
|
|
)
|
|
{
|
|
return PhOpenProcess(Handle, DesiredAccess, (HANDLE)Context);
|
|
}
|
|
|
|
FORCEINLINE PWSTR PhpGetStringOrNa(
|
|
_In_ PPH_STRING String
|
|
)
|
|
{
|
|
if (String)
|
|
return String->Buffer;
|
|
else
|
|
return L"N/A";
|
|
}
|
|
|
|
VOID PhpUpdateProcessDep(
|
|
_In_ HWND hwndDlg,
|
|
_In_ PPH_PROCESS_ITEM ProcessItem
|
|
)
|
|
{
|
|
HANDLE processHandle;
|
|
ULONG depStatus;
|
|
|
|
#ifdef _WIN64
|
|
if (ProcessItem->IsWow64)
|
|
#else
|
|
if (TRUE)
|
|
#endif
|
|
{
|
|
SetDlgItemText(hwndDlg, IDC_DEP, L"N/A");
|
|
|
|
if (NT_SUCCESS(PhOpenProcess(
|
|
&processHandle,
|
|
PROCESS_QUERY_INFORMATION,
|
|
ProcessItem->ProcessId
|
|
)))
|
|
{
|
|
if (NT_SUCCESS(PhGetProcessDepStatus(processHandle, &depStatus)))
|
|
{
|
|
PPH_STRING depString;
|
|
|
|
if (depStatus & PH_PROCESS_DEP_ENABLED)
|
|
depString = PhaCreateString(L"Enabled");
|
|
else
|
|
depString = PhaCreateString(L"Disabled");
|
|
|
|
if ((depStatus & PH_PROCESS_DEP_ENABLED) &&
|
|
(depStatus & PH_PROCESS_DEP_ATL_THUNK_EMULATION_DISABLED))
|
|
{
|
|
depString = PhaConcatStrings2(depString->Buffer, L", DEP-ATL thunk emulation disabled");
|
|
}
|
|
|
|
if (depStatus & PH_PROCESS_DEP_PERMANENT)
|
|
{
|
|
depString = PhaConcatStrings2(depString->Buffer, L", Permanent");
|
|
}
|
|
|
|
SetDlgItemText(hwndDlg, IDC_DEP, depString->Buffer);
|
|
EnableWindow(GetDlgItem(hwndDlg, IDC_EDITDEP), !(depStatus & PH_PROCESS_DEP_PERMANENT));
|
|
}
|
|
|
|
NtClose(processHandle);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ProcessItem->QueryHandle)
|
|
SetDlgItemText(hwndDlg, IDC_DEP, L"Enabled, Permanent");
|
|
else
|
|
SetDlgItemText(hwndDlg, IDC_DEP, L"N/A");
|
|
}
|
|
}
|
|
|
|
INT_PTR CALLBACK PhpProcessGeneralDlgProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
)
|
|
{
|
|
LPPROPSHEETPAGE propSheetPage;
|
|
PPH_PROCESS_PROPPAGECONTEXT propPageContext;
|
|
PPH_PROCESS_ITEM processItem;
|
|
|
|
if (!PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam,
|
|
&propSheetPage, &propPageContext, &processItem))
|
|
return FALSE;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
HANDLE processHandle = NULL;
|
|
PPH_STRING curdir = NULL;
|
|
PROCESS_BASIC_INFORMATION basicInfo;
|
|
#ifdef _WIN64
|
|
PVOID peb32;
|
|
#endif
|
|
PPH_PROCESS_ITEM parentProcess;
|
|
CLIENT_ID clientId;
|
|
|
|
{
|
|
HBITMAP folder;
|
|
HBITMAP magnifier;
|
|
HBITMAP pencil;
|
|
|
|
folder = PH_LOAD_SHARED_IMAGE(MAKEINTRESOURCE(IDB_FOLDER), IMAGE_BITMAP);
|
|
magnifier = PH_LOAD_SHARED_IMAGE(MAKEINTRESOURCE(IDB_MAGNIFIER), IMAGE_BITMAP);
|
|
pencil = PH_LOAD_SHARED_IMAGE(MAKEINTRESOURCE(IDB_PENCIL), IMAGE_BITMAP);
|
|
|
|
SET_BUTTON_BITMAP(IDC_INSPECT, magnifier);
|
|
SET_BUTTON_BITMAP(IDC_OPENFILENAME, folder);
|
|
SET_BUTTON_BITMAP(IDC_VIEWPARENTPROCESS, magnifier);
|
|
SET_BUTTON_BITMAP(IDC_EDITDEP, pencil);
|
|
}
|
|
|
|
// File
|
|
|
|
SendMessage(GetDlgItem(hwndDlg, IDC_FILEICON), STM_SETICON,
|
|
(WPARAM)processItem->LargeIcon, 0);
|
|
|
|
if (PH_IS_REAL_PROCESS_ID(processItem->ProcessId))
|
|
{
|
|
SetDlgItemText(hwndDlg, IDC_NAME, PhpGetStringOrNa(processItem->VersionInfo.FileDescription));
|
|
}
|
|
else
|
|
{
|
|
SetDlgItemText(hwndDlg, IDC_NAME, processItem->ProcessName->Buffer);
|
|
}
|
|
|
|
SetDlgItemText(hwndDlg, IDC_VERSION, PhpGetStringOrNa(processItem->VersionInfo.FileVersion));
|
|
SetDlgItemText(hwndDlg, IDC_FILENAME, PhpGetStringOrNa(processItem->FileName));
|
|
|
|
if (!processItem->FileName)
|
|
EnableWindow(GetDlgItem(hwndDlg, IDC_OPENFILENAME), FALSE);
|
|
|
|
{
|
|
PPH_STRING inspectExecutables;
|
|
|
|
inspectExecutables = PhGetStringSetting(L"ProgramInspectExecutables");
|
|
|
|
if (!processItem->FileName || inspectExecutables->Length == 0)
|
|
{
|
|
EnableWindow(GetDlgItem(hwndDlg, IDC_INSPECT), FALSE);
|
|
}
|
|
|
|
PhDereferenceObject(inspectExecutables);
|
|
}
|
|
|
|
if (processItem->VerifyResult == VrTrusted)
|
|
{
|
|
if (processItem->VerifySignerName)
|
|
{
|
|
SetDlgItemText(hwndDlg, IDC_COMPANYNAME_LINK,
|
|
PhaFormatString(L"<a>(Verified) %s</a>", processItem->VerifySignerName->Buffer)->Buffer);
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_COMPANYNAME), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_COMPANYNAME_LINK), SW_SHOW);
|
|
}
|
|
else
|
|
{
|
|
SetDlgItemText(hwndDlg, IDC_COMPANYNAME,
|
|
PhaConcatStrings2(
|
|
L"(Verified) ",
|
|
PhGetStringOrEmpty(processItem->VersionInfo.CompanyName)
|
|
)->Buffer);
|
|
}
|
|
}
|
|
else if (processItem->VerifyResult != VrUnknown)
|
|
{
|
|
SetDlgItemText(hwndDlg, IDC_COMPANYNAME,
|
|
PhaConcatStrings2(
|
|
L"(UNVERIFIED) ",
|
|
PhGetStringOrEmpty(processItem->VersionInfo.CompanyName)
|
|
)->Buffer);
|
|
}
|
|
else
|
|
{
|
|
SetDlgItemText(hwndDlg, IDC_COMPANYNAME,
|
|
PhpGetStringOrNa(processItem->VersionInfo.CompanyName));
|
|
}
|
|
|
|
// Command Line
|
|
|
|
SetDlgItemText(hwndDlg, IDC_CMDLINE, PhpGetStringOrNa(processItem->CommandLine));
|
|
|
|
// Current Directory
|
|
|
|
if (NT_SUCCESS(PhOpenProcess(
|
|
&processHandle,
|
|
ProcessQueryAccess | PROCESS_VM_READ,
|
|
processItem->ProcessId
|
|
)))
|
|
{
|
|
PH_PEB_OFFSET pebOffset;
|
|
|
|
pebOffset = PhpoCurrentDirectory;
|
|
|
|
#ifdef _WIN64
|
|
// Tell the function to get the WOW64 current directory, because that's
|
|
// the one that actually gets updated.
|
|
if (processItem->IsWow64)
|
|
pebOffset |= PhpoWow64;
|
|
#endif
|
|
|
|
PhGetProcessPebString(
|
|
processHandle,
|
|
pebOffset,
|
|
&curdir
|
|
);
|
|
|
|
NtClose(processHandle);
|
|
processHandle = NULL;
|
|
}
|
|
|
|
SetDlgItemText(hwndDlg, IDC_CURDIR,
|
|
PhpGetStringOrNa(curdir));
|
|
|
|
if (curdir)
|
|
PhDereferenceObject(curdir);
|
|
|
|
// Started
|
|
|
|
if (processItem->CreateTime.QuadPart != 0)
|
|
{
|
|
LARGE_INTEGER startTime;
|
|
LARGE_INTEGER currentTime;
|
|
SYSTEMTIME startTimeFields;
|
|
PPH_STRING startTimeRelativeString;
|
|
PPH_STRING startTimeString;
|
|
|
|
startTime = processItem->CreateTime;
|
|
PhQuerySystemTime(¤tTime);
|
|
startTimeRelativeString = PhAutoDereferenceObject(PhFormatTimeSpanRelative(currentTime.QuadPart - startTime.QuadPart));
|
|
|
|
PhLargeIntegerToLocalSystemTime(&startTimeFields, &startTime);
|
|
startTimeString = PhaFormatDateTime(&startTimeFields);
|
|
|
|
SetDlgItemText(hwndDlg, IDC_STARTED,
|
|
PhaFormatString(L"%s ago (%s)", startTimeRelativeString->Buffer, startTimeString->Buffer)->Buffer);
|
|
}
|
|
else
|
|
{
|
|
SetDlgItemText(hwndDlg, IDC_STARTED, L"N/A");
|
|
}
|
|
|
|
// Parent
|
|
|
|
if (parentProcess = PhReferenceProcessItemForParent(
|
|
processItem->ParentProcessId,
|
|
processItem->ProcessId,
|
|
&processItem->CreateTime
|
|
))
|
|
{
|
|
clientId.UniqueProcess = parentProcess->ProcessId;
|
|
clientId.UniqueThread = NULL;
|
|
|
|
SetDlgItemText(hwndDlg, IDC_PARENTPROCESS,
|
|
((PPH_STRING)PhAutoDereferenceObject(PhGetClientIdNameEx(&clientId, parentProcess->ProcessName)))->Buffer);
|
|
|
|
PhDereferenceObject(parentProcess);
|
|
}
|
|
else
|
|
{
|
|
SetDlgItemText(hwndDlg, IDC_PARENTPROCESS,
|
|
PhaFormatString(L"Non-existent process (%u)", HandleToUlong(processItem->ParentProcessId))->Buffer);
|
|
EnableWindow(GetDlgItem(hwndDlg, IDC_VIEWPARENTPROCESS), FALSE);
|
|
}
|
|
|
|
// DEP
|
|
|
|
PhpUpdateProcessDep(hwndDlg, processItem);
|
|
|
|
// PEB address
|
|
|
|
SetDlgItemText(hwndDlg, IDC_PEBADDRESS, L"N/A");
|
|
|
|
PhOpenProcess(
|
|
&processHandle,
|
|
ProcessQueryAccess,
|
|
processItem->ProcessId
|
|
);
|
|
|
|
if (processHandle)
|
|
{
|
|
PhGetProcessBasicInformation(processHandle, &basicInfo);
|
|
#ifdef _WIN64
|
|
if (processItem->IsWow64)
|
|
{
|
|
PhGetProcessPeb32(processHandle, &peb32);
|
|
SetDlgItemText(hwndDlg, IDC_PEBADDRESS,
|
|
PhaFormatString(L"0x%Ix (32-bit: 0x%x)", basicInfo.PebBaseAddress, PtrToUlong(peb32))->Buffer);
|
|
}
|
|
else
|
|
{
|
|
#endif
|
|
|
|
SetDlgItemText(hwndDlg, IDC_PEBADDRESS,
|
|
PhaFormatString(L"0x%Ix", basicInfo.PebBaseAddress)->Buffer);
|
|
#ifdef _WIN64
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// Protection
|
|
|
|
SetDlgItemText(hwndDlg, IDC_PROTECTION, L"N/A");
|
|
|
|
if (WINDOWS_HAS_LIMITED_ACCESS && processHandle)
|
|
{
|
|
if (WindowsVersion >= WINDOWS_8_1)
|
|
{
|
|
PS_PROTECTION protection;
|
|
|
|
if (NT_SUCCESS(NtQueryInformationProcess(
|
|
processHandle,
|
|
ProcessProtectionInformation,
|
|
&protection,
|
|
sizeof(PS_PROTECTION),
|
|
NULL
|
|
)))
|
|
{
|
|
PWSTR type;
|
|
PWSTR signer;
|
|
|
|
switch (protection.Type)
|
|
{
|
|
case PsProtectedTypeNone:
|
|
type = L"None";
|
|
break;
|
|
case PsProtectedTypeProtectedLight:
|
|
type = L"Light";
|
|
break;
|
|
case PsProtectedTypeProtected:
|
|
type = L"Full";
|
|
break;
|
|
default:
|
|
type = L"Unknown";
|
|
break;
|
|
}
|
|
|
|
if (protection.Signer < sizeof(ProtectedSignerStrings) / sizeof(PWSTR))
|
|
signer = ProtectedSignerStrings[protection.Signer];
|
|
else
|
|
signer = L"";
|
|
|
|
SetDlgItemText(hwndDlg, IDC_PROTECTION, PhaConcatStrings2(type, signer)->Buffer);
|
|
}
|
|
}
|
|
else if (KphIsConnected())
|
|
{
|
|
KPH_PROCESS_PROTECTION_INFORMATION protectionInfo;
|
|
|
|
if (NT_SUCCESS(KphQueryInformationProcess(
|
|
processHandle,
|
|
KphProcessProtectionInformation,
|
|
&protectionInfo,
|
|
sizeof(KPH_PROCESS_PROTECTION_INFORMATION),
|
|
NULL
|
|
)))
|
|
{
|
|
SetDlgItemText(hwndDlg, IDC_PROTECTION, protectionInfo.IsProtectedProcess ? L"Yes" : L"None");
|
|
EnableWindow(GetDlgItem(hwndDlg, IDC_EDITPROTECTION), TRUE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PROCESS_EXTENDED_BASIC_INFORMATION extendedBasicInfo;
|
|
|
|
if (NT_SUCCESS(PhGetProcessExtendedBasicInformation(
|
|
processHandle,
|
|
&extendedBasicInfo
|
|
)))
|
|
{
|
|
SetDlgItemText(hwndDlg, IDC_PROTECTION, extendedBasicInfo.IsProtectedProcess ? L"Yes" : L"None");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (processHandle)
|
|
NtClose(processHandle);
|
|
|
|
if (WindowsVersion >= WINDOWS_8)
|
|
{
|
|
PROCESS_MITIGATION_POLICY_INFORMATION policyInfo;
|
|
|
|
SetDlgItemText(hwndDlg, IDC_ASLR, L"N/A");
|
|
|
|
policyInfo.Policy = ProcessASLRPolicy;
|
|
|
|
if (NT_SUCCESS(PhOpenProcess(
|
|
&processHandle,
|
|
PROCESS_QUERY_INFORMATION,
|
|
processItem->ProcessId
|
|
)))
|
|
{
|
|
if (NT_SUCCESS(NtQueryInformationProcess(
|
|
processHandle,
|
|
ProcessMitigationPolicy,
|
|
&policyInfo,
|
|
sizeof(PROCESS_MITIGATION_POLICY_INFORMATION),
|
|
NULL
|
|
)))
|
|
{
|
|
PH_STRING_BUILDER sb;
|
|
|
|
PhInitializeStringBuilder(&sb, 40);
|
|
|
|
if (policyInfo.ASLRPolicy.EnableBottomUpRandomization)
|
|
PhAppendStringBuilder2(&sb, L"Bottom up randomization, ");
|
|
if (policyInfo.ASLRPolicy.EnableForceRelocateImages)
|
|
PhAppendStringBuilder2(&sb, L"Force relocate images, ");
|
|
if (policyInfo.ASLRPolicy.EnableHighEntropy)
|
|
PhAppendStringBuilder2(&sb, L"High entropy, ");
|
|
if (policyInfo.ASLRPolicy.DisallowStrippedImages)
|
|
PhAppendStringBuilder2(&sb, L"Disallow stripped images, ");
|
|
if (sb.String->Length != 0)
|
|
PhRemoveEndStringBuilder(&sb, 2);
|
|
|
|
if (sb.String->Length == 0)
|
|
SetDlgItemText(hwndDlg, IDC_ASLR, L"Disabled");
|
|
else
|
|
SetDlgItemText(hwndDlg, IDC_ASLR, sb.String->Buffer);
|
|
|
|
PhDeleteStringBuilder(&sb);
|
|
}
|
|
|
|
NtClose(processHandle);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_ASLRLABEL), SW_HIDE);
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_ASLR), SW_HIDE);
|
|
}
|
|
|
|
#ifdef _WIN64
|
|
if (processItem->IsWow64Valid)
|
|
{
|
|
if (processItem->IsWow64)
|
|
SetDlgItemText(hwndDlg, IDC_PROCESSTYPETEXT, L"32-bit");
|
|
else
|
|
SetDlgItemText(hwndDlg, IDC_PROCESSTYPETEXT, L"64-bit");
|
|
}
|
|
else
|
|
{
|
|
SetDlgItemText(hwndDlg, IDC_PROCESSTYPETEXT, L"N/A");
|
|
}
|
|
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_PROCESSTYPELABEL), SW_SHOW);
|
|
ShowWindow(GetDlgItem(hwndDlg, IDC_PROCESSTYPETEXT), SW_SHOW);
|
|
#endif
|
|
}
|
|
break;
|
|
case WM_DESTROY:
|
|
{
|
|
PhpPropPageDlgProcDestroy(hwndDlg);
|
|
}
|
|
break;
|
|
case WM_SHOWWINDOW:
|
|
{
|
|
if (!propPageContext->LayoutInitialized)
|
|
{
|
|
PPH_LAYOUT_ITEM dialogItem;
|
|
|
|
dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg,
|
|
PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_FILE),
|
|
dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_NAME),
|
|
dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_COMPANYNAME),
|
|
dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_COMPANYNAME_LINK),
|
|
dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_VERSION),
|
|
dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_FILENAME),
|
|
dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_INSPECT),
|
|
dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_OPENFILENAME),
|
|
dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_CMDLINE),
|
|
dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_CURDIR),
|
|
dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_STARTED),
|
|
dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PEBADDRESS),
|
|
dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PARENTPROCESS),
|
|
dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_VIEWPARENTPROCESS),
|
|
dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_DEP),
|
|
dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_EDITDEP),
|
|
dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_ASLR),
|
|
dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_TERMINATE),
|
|
dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_TOP);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PERMISSIONS),
|
|
dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_TOP);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PROCESS),
|
|
dialogItem, PH_ANCHOR_ALL);
|
|
|
|
PhDoPropPageLayout(hwndDlg);
|
|
|
|
propPageContext->LayoutInitialized = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
case WM_COMMAND:
|
|
{
|
|
INT id = LOWORD(wParam);
|
|
|
|
switch (id)
|
|
{
|
|
case IDC_INSPECT:
|
|
{
|
|
if (processItem->FileName)
|
|
{
|
|
PhShellExecuteUserString(
|
|
hwndDlg,
|
|
L"ProgramInspectExecutables",
|
|
processItem->FileName->Buffer,
|
|
FALSE,
|
|
L"Make sure the PE Viewer executable file is present."
|
|
);
|
|
}
|
|
}
|
|
break;
|
|
case IDC_OPENFILENAME:
|
|
{
|
|
if (processItem->FileName)
|
|
PhShellExploreFile(hwndDlg, processItem->FileName->Buffer);
|
|
}
|
|
break;
|
|
case IDC_VIEWPARENTPROCESS:
|
|
{
|
|
PPH_PROCESS_ITEM parentProcessItem;
|
|
|
|
if (parentProcessItem = PhReferenceProcessItem(processItem->ParentProcessId))
|
|
{
|
|
ProcessHacker_ShowProcessProperties(PhMainWndHandle, parentProcessItem);
|
|
PhDereferenceObject(parentProcessItem);
|
|
}
|
|
else
|
|
{
|
|
PhShowError(hwndDlg, L"The process does not exist.");
|
|
}
|
|
}
|
|
break;
|
|
case IDC_EDITDEP:
|
|
{
|
|
if (PhUiSetDepStatusProcess(hwndDlg, processItem))
|
|
PhpUpdateProcessDep(hwndDlg, processItem);
|
|
}
|
|
break;
|
|
case IDC_TERMINATE:
|
|
{
|
|
PhUiTerminateProcesses(
|
|
hwndDlg,
|
|
&processItem,
|
|
1
|
|
);
|
|
}
|
|
break;
|
|
case IDC_PERMISSIONS:
|
|
{
|
|
PH_STD_OBJECT_SECURITY stdObjectSecurity;
|
|
PPH_ACCESS_ENTRY accessEntries;
|
|
ULONG numberOfAccessEntries;
|
|
|
|
stdObjectSecurity.OpenObject = PhpProcessGeneralOpenProcess;
|
|
stdObjectSecurity.ObjectType = L"Process";
|
|
stdObjectSecurity.Context = processItem->ProcessId;
|
|
|
|
if (PhGetAccessEntries(L"Process", &accessEntries, &numberOfAccessEntries))
|
|
{
|
|
PhEditSecurity(
|
|
hwndDlg,
|
|
processItem->ProcessName->Buffer,
|
|
PhStdGetObjectSecurity,
|
|
PhStdSetObjectSecurity,
|
|
&stdObjectSecurity,
|
|
accessEntries,
|
|
numberOfAccessEntries
|
|
);
|
|
PhFree(accessEntries);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case WM_NOTIFY:
|
|
{
|
|
LPNMHDR header = (LPNMHDR)lParam;
|
|
|
|
switch (header->code)
|
|
{
|
|
case NM_CLICK:
|
|
{
|
|
switch (header->idFrom)
|
|
{
|
|
case IDC_COMPANYNAME_LINK:
|
|
{
|
|
if (processItem->FileName)
|
|
{
|
|
PH_VERIFY_FILE_INFO info;
|
|
|
|
memset(&info, 0, sizeof(PH_VERIFY_FILE_INFO));
|
|
info.FileName = processItem->FileName->Buffer;
|
|
info.Flags = PH_VERIFY_VIEW_PROPERTIES;
|
|
info.hWnd = hwndDlg;
|
|
PhVerifyFileWithAdditionalCatalog(
|
|
&info,
|
|
PhGetString(processItem->PackageFullName),
|
|
NULL
|
|
);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static VOID NTAPI StatisticsUpdateHandler(
|
|
_In_opt_ PVOID Parameter,
|
|
_In_opt_ PVOID Context
|
|
)
|
|
{
|
|
PPH_STATISTICS_CONTEXT statisticsContext = (PPH_STATISTICS_CONTEXT)Context;
|
|
|
|
if (statisticsContext->Enabled)
|
|
PostMessage(statisticsContext->WindowHandle, WM_PH_STATISTICS_UPDATE, 0, 0);
|
|
}
|
|
|
|
VOID PhpUpdateProcessStatistics(
|
|
_In_ HWND hwndDlg,
|
|
_In_ PPH_PROCESS_ITEM ProcessItem,
|
|
_In_ PPH_STATISTICS_CONTEXT Context
|
|
)
|
|
{
|
|
WCHAR timeSpan[PH_TIMESPAN_STR_LEN_1];
|
|
|
|
SetDlgItemInt(hwndDlg, IDC_ZPRIORITY_V, ProcessItem->BasePriority, TRUE); // priority
|
|
PhPrintTimeSpan(timeSpan, ProcessItem->KernelTime.QuadPart, PH_TIMESPAN_HMSM); // kernel time
|
|
SetDlgItemText(hwndDlg, IDC_ZKERNELTIME_V, timeSpan);
|
|
PhPrintTimeSpan(timeSpan, ProcessItem->UserTime.QuadPart, PH_TIMESPAN_HMSM); // user time
|
|
SetDlgItemText(hwndDlg, IDC_ZUSERTIME_V, timeSpan);
|
|
PhPrintTimeSpan(timeSpan,
|
|
ProcessItem->KernelTime.QuadPart + ProcessItem->UserTime.QuadPart, PH_TIMESPAN_HMSM); // total time
|
|
SetDlgItemText(hwndDlg, IDC_ZTOTALTIME_V, timeSpan);
|
|
|
|
SetDlgItemText(hwndDlg, IDC_ZPRIVATEBYTES_V,
|
|
PhaFormatSize(ProcessItem->VmCounters.PagefileUsage, -1)->Buffer); // private bytes (same as PrivateUsage)
|
|
SetDlgItemText(hwndDlg, IDC_ZPEAKPRIVATEBYTES_V,
|
|
PhaFormatSize(ProcessItem->VmCounters.PeakPagefileUsage, -1)->Buffer); // peak private bytes
|
|
SetDlgItemText(hwndDlg, IDC_ZVIRTUALSIZE_V,
|
|
PhaFormatSize(ProcessItem->VmCounters.VirtualSize, -1)->Buffer); // virtual size
|
|
SetDlgItemText(hwndDlg, IDC_ZPEAKVIRTUALSIZE_V,
|
|
PhaFormatSize(ProcessItem->VmCounters.PeakVirtualSize, -1)->Buffer); // peak virtual size
|
|
SetDlgItemText(hwndDlg, IDC_ZPAGEFAULTS_V,
|
|
PhaFormatUInt64(ProcessItem->VmCounters.PageFaultCount, TRUE)->Buffer); // page faults
|
|
SetDlgItemText(hwndDlg, IDC_ZWORKINGSET_V,
|
|
PhaFormatSize(ProcessItem->VmCounters.WorkingSetSize, -1)->Buffer); // working set
|
|
SetDlgItemText(hwndDlg, IDC_ZPEAKWORKINGSET_V,
|
|
PhaFormatSize(ProcessItem->VmCounters.PeakWorkingSetSize, -1)->Buffer); // peak working set
|
|
|
|
SetDlgItemText(hwndDlg, IDC_ZIOREADS_V,
|
|
PhaFormatUInt64(ProcessItem->IoCounters.ReadOperationCount, TRUE)->Buffer); // reads
|
|
SetDlgItemText(hwndDlg, IDC_ZIOREADBYTES_V,
|
|
PhaFormatSize(ProcessItem->IoCounters.ReadTransferCount, -1)->Buffer); // read bytes
|
|
SetDlgItemText(hwndDlg, IDC_ZIOWRITES_V,
|
|
PhaFormatUInt64(ProcessItem->IoCounters.WriteOperationCount, TRUE)->Buffer); // writes
|
|
SetDlgItemText(hwndDlg, IDC_ZIOWRITEBYTES_V,
|
|
PhaFormatSize(ProcessItem->IoCounters.WriteTransferCount, -1)->Buffer); // write bytes
|
|
SetDlgItemText(hwndDlg, IDC_ZIOOTHER_V,
|
|
PhaFormatUInt64(ProcessItem->IoCounters.OtherOperationCount, TRUE)->Buffer); // other
|
|
SetDlgItemText(hwndDlg, IDC_ZIOOTHERBYTES_V,
|
|
PhaFormatSize(ProcessItem->IoCounters.OtherTransferCount, -1)->Buffer); // read bytes
|
|
|
|
SetDlgItemText(hwndDlg, IDC_ZHANDLES_V,
|
|
PhaFormatUInt64(ProcessItem->NumberOfHandles, TRUE)->Buffer); // handles
|
|
|
|
// Optional information
|
|
if (!PH_IS_FAKE_PROCESS_ID(ProcessItem->ProcessId))
|
|
{
|
|
PPH_STRING peakHandles = NULL;
|
|
PPH_STRING gdiHandles = NULL;
|
|
PPH_STRING userHandles = NULL;
|
|
PPH_STRING cycles = NULL;
|
|
ULONG pagePriority = -1;
|
|
ULONG ioPriority = -1;
|
|
PPH_STRING privateWs = NULL;
|
|
PPH_STRING shareableWs = NULL;
|
|
PPH_STRING sharedWs = NULL;
|
|
BOOLEAN gotCycles = FALSE;
|
|
BOOLEAN gotWsCounters = FALSE;
|
|
|
|
if (ProcessItem->QueryHandle)
|
|
{
|
|
ULONG64 cycleTime;
|
|
|
|
if (WindowsVersion >= WINDOWS_7)
|
|
{
|
|
PROCESS_HANDLE_INFORMATION handleInfo;
|
|
|
|
if (NT_SUCCESS(NtQueryInformationProcess(
|
|
ProcessItem->QueryHandle,
|
|
ProcessHandleCount,
|
|
&handleInfo,
|
|
sizeof(PROCESS_HANDLE_INFORMATION),
|
|
NULL
|
|
)))
|
|
{
|
|
peakHandles = PhaFormatUInt64(handleInfo.HandleCountHighWatermark, TRUE);
|
|
}
|
|
}
|
|
|
|
gdiHandles = PhaFormatUInt64(GetGuiResources(ProcessItem->QueryHandle, GR_GDIOBJECTS), TRUE); // GDI handles
|
|
userHandles = PhaFormatUInt64(GetGuiResources(ProcessItem->QueryHandle, GR_USEROBJECTS), TRUE); // USER handles
|
|
|
|
if (WINDOWS_HAS_CYCLE_TIME &&
|
|
NT_SUCCESS(PhGetProcessCycleTime(ProcessItem->QueryHandle, &cycleTime)))
|
|
{
|
|
cycles = PhaFormatUInt64(cycleTime, TRUE);
|
|
gotCycles = TRUE;
|
|
}
|
|
|
|
if (WindowsVersion >= WINDOWS_VISTA)
|
|
{
|
|
PhGetProcessPagePriority(ProcessItem->QueryHandle, &pagePriority);
|
|
PhGetProcessIoPriority(ProcessItem->QueryHandle, &ioPriority);
|
|
}
|
|
}
|
|
|
|
if (Context->ProcessHandle)
|
|
{
|
|
PH_PROCESS_WS_COUNTERS wsCounters;
|
|
|
|
if (NT_SUCCESS(PhGetProcessWsCounters(Context->ProcessHandle, &wsCounters)))
|
|
{
|
|
privateWs = PhaFormatSize((ULONG64)wsCounters.NumberOfPrivatePages * PAGE_SIZE, -1);
|
|
shareableWs = PhaFormatSize((ULONG64)wsCounters.NumberOfShareablePages * PAGE_SIZE, -1);
|
|
sharedWs = PhaFormatSize((ULONG64)wsCounters.NumberOfSharedPages * PAGE_SIZE, -1);
|
|
gotWsCounters = TRUE;
|
|
}
|
|
}
|
|
|
|
if (WindowsVersion >= WINDOWS_7)
|
|
{
|
|
if (!gotCycles)
|
|
cycles = PhaFormatUInt64(ProcessItem->CycleTimeDelta.Value, TRUE);
|
|
if (!gotWsCounters)
|
|
privateWs = PhaFormatSize(ProcessItem->WorkingSetPrivateSize, -1);
|
|
}
|
|
|
|
if (WindowsVersion >= WINDOWS_7)
|
|
SetDlgItemText(hwndDlg, IDC_ZPEAKHANDLES_V, PhGetStringOrDefault(peakHandles, L"Unknown"));
|
|
else
|
|
SetDlgItemText(hwndDlg, IDC_ZPEAKHANDLES_V, L"N/A");
|
|
|
|
SetDlgItemText(hwndDlg, IDC_ZGDIHANDLES_V, PhGetStringOrDefault(gdiHandles, L"Unknown"));
|
|
SetDlgItemText(hwndDlg, IDC_ZUSERHANDLES_V, PhGetStringOrDefault(userHandles, L"Unknown"));
|
|
SetDlgItemText(hwndDlg, IDC_ZCYCLES_V,
|
|
PhGetStringOrDefault(cycles, WINDOWS_HAS_CYCLE_TIME ? L"Unknown" : L"N/A"));
|
|
|
|
if (WindowsVersion >= WINDOWS_VISTA)
|
|
{
|
|
if (pagePriority != -1)
|
|
SetDlgItemInt(hwndDlg, IDC_ZPAGEPRIORITY_V, pagePriority, FALSE);
|
|
else
|
|
SetDlgItemText(hwndDlg, IDC_ZPAGEPRIORITY_V, L"Unknown");
|
|
|
|
if (ioPriority != -1 && ioPriority < MaxIoPriorityTypes)
|
|
SetDlgItemText(hwndDlg, IDC_ZIOPRIORITY_V, PhIoPriorityHintNames[ioPriority]);
|
|
else
|
|
SetDlgItemText(hwndDlg, IDC_ZIOPRIORITY_V, L"Unknown");
|
|
}
|
|
else
|
|
{
|
|
SetDlgItemText(hwndDlg, IDC_ZPAGEPRIORITY_V, L"N/A");
|
|
SetDlgItemText(hwndDlg, IDC_ZIOPRIORITY_V, L"N/A");
|
|
}
|
|
|
|
SetDlgItemText(hwndDlg, IDC_ZPRIVATEWS_V, PhGetStringOrDefault(privateWs, L"Unknown"));
|
|
SetDlgItemText(hwndDlg, IDC_ZSHAREABLEWS_V, PhGetStringOrDefault(shareableWs, L"Unknown"));
|
|
SetDlgItemText(hwndDlg, IDC_ZSHAREDWS_V, PhGetStringOrDefault(sharedWs, L"Unknown"));
|
|
}
|
|
else
|
|
{
|
|
SetDlgItemText(hwndDlg, IDC_ZPEAKHANDLES_V, L"N/A");
|
|
SetDlgItemText(hwndDlg, IDC_ZGDIHANDLES_V, L"N/A");
|
|
SetDlgItemText(hwndDlg, IDC_ZUSERHANDLES_V, L"N/A");
|
|
SetDlgItemText(hwndDlg, IDC_ZCYCLES_V, L"N/A");
|
|
SetDlgItemText(hwndDlg, IDC_ZPAGEPRIORITY_V, L"N/A");
|
|
SetDlgItemText(hwndDlg, IDC_ZIOPRIORITY_V, L"N/A");
|
|
SetDlgItemText(hwndDlg, IDC_ZPRIVATEWS_V, L"N/A");
|
|
SetDlgItemText(hwndDlg, IDC_ZSHAREABLEWS_V, L"N/A");
|
|
SetDlgItemText(hwndDlg, IDC_ZSHAREDWS_V, L"N/A");
|
|
}
|
|
}
|
|
|
|
INT_PTR CALLBACK PhpProcessStatisticsDlgProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
)
|
|
{
|
|
LPPROPSHEETPAGE propSheetPage;
|
|
PPH_PROCESS_PROPPAGECONTEXT propPageContext;
|
|
PPH_PROCESS_ITEM processItem;
|
|
PPH_STATISTICS_CONTEXT statisticsContext;
|
|
|
|
if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam,
|
|
&propSheetPage, &propPageContext, &processItem))
|
|
{
|
|
statisticsContext = (PPH_STATISTICS_CONTEXT)propPageContext->Context;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
statisticsContext = propPageContext->Context =
|
|
PhAllocate(sizeof(PH_STATISTICS_CONTEXT));
|
|
|
|
statisticsContext->WindowHandle = hwndDlg;
|
|
statisticsContext->Enabled = TRUE;
|
|
statisticsContext->ProcessHandle = NULL;
|
|
|
|
// Try to open a process handle with PROCESS_QUERY_INFORMATION access for
|
|
// WS information.
|
|
PhOpenProcess(
|
|
&statisticsContext->ProcessHandle,
|
|
PROCESS_QUERY_INFORMATION,
|
|
processItem->ProcessId
|
|
);
|
|
|
|
PhRegisterCallback(
|
|
&PhProcessesUpdatedEvent,
|
|
StatisticsUpdateHandler,
|
|
statisticsContext,
|
|
&statisticsContext->ProcessesUpdatedRegistration
|
|
);
|
|
|
|
PhpUpdateProcessStatistics(hwndDlg, processItem, statisticsContext);
|
|
}
|
|
break;
|
|
case WM_DESTROY:
|
|
{
|
|
PhUnregisterCallback(
|
|
&PhProcessesUpdatedEvent,
|
|
&statisticsContext->ProcessesUpdatedRegistration
|
|
);
|
|
|
|
if (statisticsContext->ProcessHandle)
|
|
NtClose(statisticsContext->ProcessHandle);
|
|
|
|
PhFree(statisticsContext);
|
|
|
|
PhpPropPageDlgProcDestroy(hwndDlg);
|
|
}
|
|
break;
|
|
case WM_SHOWWINDOW:
|
|
{
|
|
if (!propPageContext->LayoutInitialized)
|
|
{
|
|
PPH_LAYOUT_ITEM dialogItem;
|
|
|
|
dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg,
|
|
PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL);
|
|
|
|
PhDoPropPageLayout(hwndDlg);
|
|
|
|
propPageContext->LayoutInitialized = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
case WM_COMMAND:
|
|
{
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case IDC_DETAILS:
|
|
{
|
|
PhShowHandleStatisticsDialog(hwndDlg, processItem->ProcessId);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case WM_NOTIFY:
|
|
{
|
|
LPNMHDR header = (LPNMHDR)lParam;
|
|
|
|
switch (header->code)
|
|
{
|
|
case PSN_SETACTIVE:
|
|
statisticsContext->Enabled = TRUE;
|
|
break;
|
|
case PSN_KILLACTIVE:
|
|
statisticsContext->Enabled = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case WM_PH_STATISTICS_UPDATE:
|
|
{
|
|
PhpUpdateProcessStatistics(hwndDlg, processItem, statisticsContext);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static VOID NTAPI PerformanceUpdateHandler(
|
|
_In_opt_ PVOID Parameter,
|
|
_In_opt_ PVOID Context
|
|
)
|
|
{
|
|
PPH_PERFORMANCE_CONTEXT performanceContext = (PPH_PERFORMANCE_CONTEXT)Context;
|
|
|
|
PostMessage(performanceContext->WindowHandle, WM_PH_PERFORMANCE_UPDATE, 0, 0);
|
|
}
|
|
|
|
INT_PTR CALLBACK PhpProcessPerformanceDlgProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
)
|
|
{
|
|
LPPROPSHEETPAGE propSheetPage;
|
|
PPH_PROCESS_PROPPAGECONTEXT propPageContext;
|
|
PPH_PROCESS_ITEM processItem;
|
|
PPH_PERFORMANCE_CONTEXT performanceContext;
|
|
|
|
if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam,
|
|
&propSheetPage, &propPageContext, &processItem))
|
|
{
|
|
performanceContext = (PPH_PERFORMANCE_CONTEXT)propPageContext->Context;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
performanceContext = propPageContext->Context =
|
|
PhAllocate(sizeof(PH_PERFORMANCE_CONTEXT));
|
|
|
|
performanceContext->WindowHandle = hwndDlg;
|
|
|
|
PhRegisterCallback(
|
|
&PhProcessesUpdatedEvent,
|
|
PerformanceUpdateHandler,
|
|
performanceContext,
|
|
&performanceContext->ProcessesUpdatedRegistration
|
|
);
|
|
|
|
// We have already set the group boxes to have WS_EX_TRANSPARENT to fix
|
|
// the drawing issue that arises when using WS_CLIPCHILDREN. However
|
|
// in removing the flicker from the graphs the group boxes will now flicker.
|
|
// It's a good tradeoff since no one stares at the group boxes.
|
|
PhSetWindowStyle(hwndDlg, WS_CLIPCHILDREN, WS_CLIPCHILDREN);
|
|
|
|
PhInitializeGraphState(&performanceContext->CpuGraphState);
|
|
PhInitializeGraphState(&performanceContext->PrivateGraphState);
|
|
PhInitializeGraphState(&performanceContext->IoGraphState);
|
|
|
|
performanceContext->CpuGraphHandle = GetDlgItem(hwndDlg, IDC_CPU);
|
|
PhSetWindowStyle(performanceContext->CpuGraphHandle, WS_BORDER, WS_BORDER);
|
|
Graph_SetTooltip(performanceContext->CpuGraphHandle, TRUE);
|
|
BringWindowToTop(performanceContext->CpuGraphHandle);
|
|
|
|
performanceContext->PrivateGraphHandle = GetDlgItem(hwndDlg, IDC_PRIVATEBYTES);
|
|
PhSetWindowStyle(performanceContext->PrivateGraphHandle, WS_BORDER, WS_BORDER);
|
|
Graph_SetTooltip(performanceContext->PrivateGraphHandle, TRUE);
|
|
BringWindowToTop(performanceContext->PrivateGraphHandle);
|
|
|
|
performanceContext->IoGraphHandle = GetDlgItem(hwndDlg, IDC_IO);
|
|
PhSetWindowStyle(performanceContext->IoGraphHandle, WS_BORDER, WS_BORDER);
|
|
Graph_SetTooltip(performanceContext->IoGraphHandle, TRUE);
|
|
BringWindowToTop(performanceContext->IoGraphHandle);
|
|
}
|
|
break;
|
|
case WM_DESTROY:
|
|
{
|
|
PhDeleteGraphState(&performanceContext->CpuGraphState);
|
|
PhDeleteGraphState(&performanceContext->PrivateGraphState);
|
|
PhDeleteGraphState(&performanceContext->IoGraphState);
|
|
|
|
PhUnregisterCallback(
|
|
&PhProcessesUpdatedEvent,
|
|
&performanceContext->ProcessesUpdatedRegistration
|
|
);
|
|
PhFree(performanceContext);
|
|
|
|
PhpPropPageDlgProcDestroy(hwndDlg);
|
|
}
|
|
break;
|
|
case WM_SHOWWINDOW:
|
|
{
|
|
if (!propPageContext->LayoutInitialized)
|
|
{
|
|
PPH_LAYOUT_ITEM dialogItem;
|
|
|
|
dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg,
|
|
PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL);
|
|
|
|
PhDoPropPageLayout(hwndDlg);
|
|
|
|
propPageContext->LayoutInitialized = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
case WM_NOTIFY:
|
|
{
|
|
LPNMHDR header = (LPNMHDR)lParam;
|
|
|
|
switch (header->code)
|
|
{
|
|
case GCN_GETDRAWINFO:
|
|
{
|
|
PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)header;
|
|
PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;
|
|
|
|
if (header->hwndFrom == performanceContext->CpuGraphHandle)
|
|
{
|
|
if (PhCsGraphShowText)
|
|
{
|
|
HDC hdc;
|
|
|
|
PhMoveReference(&performanceContext->CpuGraphState.Text,
|
|
PhFormatString(L"%.2f%%",
|
|
(processItem->CpuKernelUsage + processItem->CpuUserUsage) * 100
|
|
));
|
|
|
|
hdc = Graph_GetBufferedContext(performanceContext->CpuGraphHandle);
|
|
SelectObject(hdc, PhApplicationFont);
|
|
PhSetGraphText(hdc, drawInfo, &performanceContext->CpuGraphState.Text->sr,
|
|
&PhNormalGraphTextMargin, &PhNormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT);
|
|
}
|
|
else
|
|
{
|
|
drawInfo->Text.Buffer = NULL;
|
|
}
|
|
|
|
drawInfo->Flags = PH_GRAPH_USE_GRID | PH_GRAPH_USE_LINE_2;
|
|
PhSiSetColorsGraphDrawInfo(drawInfo, PhCsColorCpuKernel, PhCsColorCpuUser);
|
|
|
|
PhGraphStateGetDrawInfo(
|
|
&performanceContext->CpuGraphState,
|
|
getDrawInfo,
|
|
processItem->CpuKernelHistory.Count
|
|
);
|
|
|
|
if (!performanceContext->CpuGraphState.Valid)
|
|
{
|
|
PhCopyCircularBuffer_FLOAT(&processItem->CpuKernelHistory,
|
|
performanceContext->CpuGraphState.Data1, drawInfo->LineDataCount);
|
|
PhCopyCircularBuffer_FLOAT(&processItem->CpuUserHistory,
|
|
performanceContext->CpuGraphState.Data2, drawInfo->LineDataCount);
|
|
performanceContext->CpuGraphState.Valid = TRUE;
|
|
}
|
|
}
|
|
else if (header->hwndFrom == performanceContext->PrivateGraphHandle)
|
|
{
|
|
if (PhCsGraphShowText)
|
|
{
|
|
HDC hdc;
|
|
|
|
PhMoveReference(&performanceContext->PrivateGraphState.Text,
|
|
PhConcatStrings2(
|
|
L"Private Bytes: ",
|
|
PhaFormatSize(processItem->VmCounters.PagefileUsage, -1)->Buffer
|
|
));
|
|
|
|
hdc = Graph_GetBufferedContext(performanceContext->PrivateGraphHandle);
|
|
SelectObject(hdc, PhApplicationFont);
|
|
PhSetGraphText(hdc, drawInfo, &performanceContext->PrivateGraphState.Text->sr,
|
|
&PhNormalGraphTextMargin, &PhNormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT);
|
|
}
|
|
else
|
|
{
|
|
drawInfo->Text.Buffer = NULL;
|
|
}
|
|
|
|
drawInfo->Flags = PH_GRAPH_USE_GRID;
|
|
PhSiSetColorsGraphDrawInfo(drawInfo, PhCsColorPrivate, 0);
|
|
|
|
PhGraphStateGetDrawInfo(
|
|
&performanceContext->PrivateGraphState,
|
|
getDrawInfo,
|
|
processItem->PrivateBytesHistory.Count
|
|
);
|
|
|
|
if (!performanceContext->PrivateGraphState.Valid)
|
|
{
|
|
ULONG i;
|
|
|
|
for (i = 0; i < drawInfo->LineDataCount; i++)
|
|
{
|
|
performanceContext->PrivateGraphState.Data1[i] =
|
|
(FLOAT)PhGetItemCircularBuffer_SIZE_T(&processItem->PrivateBytesHistory, i);
|
|
}
|
|
|
|
if (processItem->VmCounters.PeakPagefileUsage != 0)
|
|
{
|
|
// Scale the data.
|
|
PhDivideSinglesBySingle(
|
|
performanceContext->PrivateGraphState.Data1,
|
|
(FLOAT)processItem->VmCounters.PeakPagefileUsage,
|
|
drawInfo->LineDataCount
|
|
);
|
|
}
|
|
|
|
performanceContext->PrivateGraphState.Valid = TRUE;
|
|
}
|
|
}
|
|
else if (header->hwndFrom == performanceContext->IoGraphHandle)
|
|
{
|
|
if (PhCsGraphShowText)
|
|
{
|
|
HDC hdc;
|
|
|
|
PhMoveReference(&performanceContext->IoGraphState.Text,
|
|
PhFormatString(
|
|
L"R+O: %s, W: %s",
|
|
PhaFormatSize(processItem->IoReadDelta.Delta + processItem->IoOtherDelta.Delta, -1)->Buffer,
|
|
PhaFormatSize(processItem->IoWriteDelta.Delta, -1)->Buffer
|
|
));
|
|
|
|
hdc = Graph_GetBufferedContext(performanceContext->IoGraphHandle);
|
|
SelectObject(hdc, PhApplicationFont);
|
|
PhSetGraphText(hdc, drawInfo, &performanceContext->IoGraphState.Text->sr,
|
|
&PhNormalGraphTextMargin, &PhNormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT);
|
|
}
|
|
else
|
|
{
|
|
drawInfo->Text.Buffer = NULL;
|
|
}
|
|
|
|
drawInfo->Flags = PH_GRAPH_USE_GRID | PH_GRAPH_USE_LINE_2;
|
|
PhSiSetColorsGraphDrawInfo(drawInfo, PhCsColorIoReadOther, PhCsColorIoWrite);
|
|
|
|
PhGraphStateGetDrawInfo(
|
|
&performanceContext->IoGraphState,
|
|
getDrawInfo,
|
|
processItem->IoReadHistory.Count
|
|
);
|
|
|
|
if (!performanceContext->IoGraphState.Valid)
|
|
{
|
|
ULONG i;
|
|
FLOAT max = 0;
|
|
|
|
for (i = 0; i < drawInfo->LineDataCount; i++)
|
|
{
|
|
FLOAT data1;
|
|
FLOAT data2;
|
|
|
|
performanceContext->IoGraphState.Data1[i] = data1 =
|
|
(FLOAT)PhGetItemCircularBuffer_ULONG64(&processItem->IoReadHistory, i) +
|
|
(FLOAT)PhGetItemCircularBuffer_ULONG64(&processItem->IoOtherHistory, i);
|
|
performanceContext->IoGraphState.Data2[i] = data2 =
|
|
(FLOAT)PhGetItemCircularBuffer_ULONG64(&processItem->IoWriteHistory, i);
|
|
|
|
if (max < data1 + data2)
|
|
max = data1 + data2;
|
|
}
|
|
|
|
if (max != 0)
|
|
{
|
|
// Scale the data.
|
|
|
|
PhDivideSinglesBySingle(
|
|
performanceContext->IoGraphState.Data1,
|
|
max,
|
|
drawInfo->LineDataCount
|
|
);
|
|
PhDivideSinglesBySingle(
|
|
performanceContext->IoGraphState.Data2,
|
|
max,
|
|
drawInfo->LineDataCount
|
|
);
|
|
}
|
|
|
|
performanceContext->IoGraphState.Valid = TRUE;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case GCN_GETTOOLTIPTEXT:
|
|
{
|
|
PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)lParam;
|
|
|
|
if (
|
|
header->hwndFrom == performanceContext->CpuGraphHandle &&
|
|
getTooltipText->Index < getTooltipText->TotalCount
|
|
)
|
|
{
|
|
if (performanceContext->CpuGraphState.TooltipIndex != getTooltipText->Index)
|
|
{
|
|
FLOAT cpuKernel;
|
|
FLOAT cpuUser;
|
|
|
|
cpuKernel = PhGetItemCircularBuffer_FLOAT(&processItem->CpuKernelHistory, getTooltipText->Index);
|
|
cpuUser = PhGetItemCircularBuffer_FLOAT(&processItem->CpuUserHistory, getTooltipText->Index);
|
|
|
|
PhMoveReference(&performanceContext->CpuGraphState.TooltipText, PhFormatString(
|
|
L"%.2f%%\n%s",
|
|
(cpuKernel + cpuUser) * 100,
|
|
((PPH_STRING)PhAutoDereferenceObject(PhGetStatisticsTimeString(processItem, getTooltipText->Index)))->Buffer
|
|
));
|
|
}
|
|
|
|
getTooltipText->Text = performanceContext->CpuGraphState.TooltipText->sr;
|
|
}
|
|
else if (
|
|
header->hwndFrom == performanceContext->PrivateGraphHandle &&
|
|
getTooltipText->Index < getTooltipText->TotalCount
|
|
)
|
|
{
|
|
if (performanceContext->PrivateGraphState.TooltipIndex != getTooltipText->Index)
|
|
{
|
|
SIZE_T privateBytes;
|
|
|
|
privateBytes = PhGetItemCircularBuffer_SIZE_T(&processItem->PrivateBytesHistory, getTooltipText->Index);
|
|
|
|
PhMoveReference(&performanceContext->PrivateGraphState.TooltipText, PhFormatString(
|
|
L"Private Bytes: %s\n%s",
|
|
PhaFormatSize(privateBytes, -1)->Buffer,
|
|
((PPH_STRING)PhAutoDereferenceObject(PhGetStatisticsTimeString(processItem, getTooltipText->Index)))->Buffer
|
|
));
|
|
}
|
|
|
|
getTooltipText->Text = performanceContext->PrivateGraphState.TooltipText->sr;
|
|
}
|
|
else if (
|
|
header->hwndFrom == performanceContext->IoGraphHandle &&
|
|
getTooltipText->Index < getTooltipText->TotalCount
|
|
)
|
|
{
|
|
if (performanceContext->IoGraphState.TooltipIndex != getTooltipText->Index)
|
|
{
|
|
ULONG64 ioRead;
|
|
ULONG64 ioWrite;
|
|
ULONG64 ioOther;
|
|
|
|
ioRead = PhGetItemCircularBuffer_ULONG64(&processItem->IoReadHistory, getTooltipText->Index);
|
|
ioWrite = PhGetItemCircularBuffer_ULONG64(&processItem->IoWriteHistory, getTooltipText->Index);
|
|
ioOther = PhGetItemCircularBuffer_ULONG64(&processItem->IoOtherHistory, getTooltipText->Index);
|
|
|
|
PhMoveReference(&performanceContext->IoGraphState.TooltipText, PhFormatString(
|
|
L"R: %s\nW: %s\nO: %s\n%s",
|
|
PhaFormatSize(ioRead, -1)->Buffer,
|
|
PhaFormatSize(ioWrite, -1)->Buffer,
|
|
PhaFormatSize(ioOther, -1)->Buffer,
|
|
((PPH_STRING)PhAutoDereferenceObject(PhGetStatisticsTimeString(processItem, getTooltipText->Index)))->Buffer
|
|
));
|
|
}
|
|
|
|
getTooltipText->Text = performanceContext->IoGraphState.TooltipText->sr;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case WM_SIZE:
|
|
{
|
|
HDWP deferHandle;
|
|
HWND cpuGroupBox = GetDlgItem(hwndDlg, IDC_GROUPCPU);
|
|
HWND privateBytesGroupBox = GetDlgItem(hwndDlg, IDC_GROUPPRIVATEBYTES);
|
|
HWND ioGroupBox = GetDlgItem(hwndDlg, IDC_GROUPIO);
|
|
RECT clientRect;
|
|
RECT margin = { 13, 13, 13, 13 };
|
|
RECT innerMargin = { 10, 20, 10, 10 };
|
|
LONG between = 3;
|
|
LONG width;
|
|
LONG height;
|
|
|
|
performanceContext->CpuGraphState.Valid = FALSE;
|
|
performanceContext->CpuGraphState.TooltipIndex = -1;
|
|
performanceContext->PrivateGraphState.Valid = FALSE;
|
|
performanceContext->PrivateGraphState.TooltipIndex = -1;
|
|
performanceContext->IoGraphState.Valid = FALSE;
|
|
performanceContext->IoGraphState.TooltipIndex = -1;
|
|
|
|
GetClientRect(hwndDlg, &clientRect);
|
|
width = clientRect.right - margin.left - margin.right;
|
|
height = (clientRect.bottom - margin.top - margin.bottom - between * 2) / 3;
|
|
|
|
deferHandle = BeginDeferWindowPos(6);
|
|
|
|
deferHandle = DeferWindowPos(deferHandle, cpuGroupBox, NULL, margin.left, margin.top,
|
|
width, height, SWP_NOACTIVATE | SWP_NOZORDER);
|
|
deferHandle = DeferWindowPos(
|
|
deferHandle,
|
|
performanceContext->CpuGraphHandle,
|
|
NULL,
|
|
margin.left + innerMargin.left,
|
|
margin.top + innerMargin.top,
|
|
width - innerMargin.left - innerMargin.right,
|
|
height - innerMargin.top - innerMargin.bottom,
|
|
SWP_NOACTIVATE | SWP_NOZORDER
|
|
);
|
|
|
|
deferHandle = DeferWindowPos(deferHandle, privateBytesGroupBox, NULL, margin.left, margin.top + height + between,
|
|
width, height, SWP_NOACTIVATE | SWP_NOZORDER);
|
|
deferHandle = DeferWindowPos(
|
|
deferHandle,
|
|
performanceContext->PrivateGraphHandle,
|
|
NULL,
|
|
margin.left + innerMargin.left,
|
|
margin.top + height + between + innerMargin.top,
|
|
width - innerMargin.left - innerMargin.right,
|
|
height - innerMargin.top - innerMargin.bottom,
|
|
SWP_NOACTIVATE | SWP_NOZORDER
|
|
);
|
|
|
|
deferHandle = DeferWindowPos(deferHandle, ioGroupBox, NULL, margin.left, margin.top + (height + between) * 2,
|
|
width, height, SWP_NOACTIVATE | SWP_NOZORDER);
|
|
deferHandle = DeferWindowPos(
|
|
deferHandle,
|
|
performanceContext->IoGraphHandle,
|
|
NULL,
|
|
margin.left + innerMargin.left,
|
|
margin.top + (height + between) * 2 + innerMargin.top,
|
|
width - innerMargin.left - innerMargin.right,
|
|
height - innerMargin.top - innerMargin.bottom,
|
|
SWP_NOACTIVATE | SWP_NOZORDER
|
|
);
|
|
|
|
EndDeferWindowPos(deferHandle);
|
|
}
|
|
break;
|
|
case WM_PH_PERFORMANCE_UPDATE:
|
|
{
|
|
if (!(processItem->State & PH_PROCESS_ITEM_REMOVED))
|
|
{
|
|
performanceContext->CpuGraphState.Valid = FALSE;
|
|
Graph_MoveGrid(performanceContext->CpuGraphHandle, 1);
|
|
Graph_Draw(performanceContext->CpuGraphHandle);
|
|
Graph_UpdateTooltip(performanceContext->CpuGraphHandle);
|
|
InvalidateRect(performanceContext->CpuGraphHandle, NULL, FALSE);
|
|
|
|
performanceContext->PrivateGraphState.Valid = FALSE;
|
|
Graph_MoveGrid(performanceContext->PrivateGraphHandle, 1);
|
|
Graph_Draw(performanceContext->PrivateGraphHandle);
|
|
Graph_UpdateTooltip(performanceContext->PrivateGraphHandle);
|
|
InvalidateRect(performanceContext->PrivateGraphHandle, NULL, FALSE);
|
|
|
|
performanceContext->IoGraphState.Valid = FALSE;
|
|
Graph_MoveGrid(performanceContext->IoGraphHandle, 1);
|
|
Graph_Draw(performanceContext->IoGraphHandle);
|
|
Graph_UpdateTooltip(performanceContext->IoGraphHandle);
|
|
InvalidateRect(performanceContext->IoGraphHandle, NULL, FALSE);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static VOID NTAPI ThreadAddedHandler(
|
|
_In_opt_ PVOID Parameter,
|
|
_In_opt_ PVOID Context
|
|
)
|
|
{
|
|
PPH_THREADS_CONTEXT threadsContext = (PPH_THREADS_CONTEXT)Context;
|
|
|
|
// Parameter contains a pointer to the added thread item.
|
|
PhReferenceObject(Parameter);
|
|
PostMessage(
|
|
threadsContext->WindowHandle,
|
|
WM_PH_THREAD_ADDED,
|
|
threadsContext->Provider->RunId == 1,
|
|
(LPARAM)Parameter
|
|
);
|
|
}
|
|
|
|
static VOID NTAPI ThreadModifiedHandler(
|
|
_In_opt_ PVOID Parameter,
|
|
_In_opt_ PVOID Context
|
|
)
|
|
{
|
|
PPH_THREADS_CONTEXT threadsContext = (PPH_THREADS_CONTEXT)Context;
|
|
|
|
PostMessage(threadsContext->WindowHandle, WM_PH_THREAD_MODIFIED, 0, (LPARAM)Parameter);
|
|
}
|
|
|
|
static VOID NTAPI ThreadRemovedHandler(
|
|
_In_opt_ PVOID Parameter,
|
|
_In_opt_ PVOID Context
|
|
)
|
|
{
|
|
PPH_THREADS_CONTEXT threadsContext = (PPH_THREADS_CONTEXT)Context;
|
|
|
|
PostMessage(threadsContext->WindowHandle, WM_PH_THREAD_REMOVED, 0, (LPARAM)Parameter);
|
|
}
|
|
|
|
static VOID NTAPI ThreadsUpdatedHandler(
|
|
_In_opt_ PVOID Parameter,
|
|
_In_opt_ PVOID Context
|
|
)
|
|
{
|
|
PPH_THREADS_CONTEXT threadsContext = (PPH_THREADS_CONTEXT)Context;
|
|
|
|
PostMessage(threadsContext->WindowHandle, WM_PH_THREADS_UPDATED, 0, 0);
|
|
}
|
|
|
|
static VOID NTAPI ThreadsLoadingStateChangedHandler(
|
|
_In_opt_ PVOID Parameter,
|
|
_In_opt_ PVOID Context
|
|
)
|
|
{
|
|
PPH_THREADS_CONTEXT threadsContext = (PPH_THREADS_CONTEXT)Context;
|
|
|
|
PostMessage(
|
|
threadsContext->ListContext.TreeNewHandle,
|
|
TNM_SETCURSOR,
|
|
0,
|
|
// Parameter contains TRUE if loading symbols
|
|
(LPARAM)(Parameter ? LoadCursor(NULL, IDC_APPSTARTING) : NULL)
|
|
);
|
|
}
|
|
|
|
VOID PhpInitializeThreadMenu(
|
|
_In_ PPH_EMENU Menu,
|
|
_In_ HANDLE ProcessId,
|
|
_In_ PPH_THREAD_ITEM *Threads,
|
|
_In_ ULONG NumberOfThreads
|
|
)
|
|
{
|
|
PPH_EMENU_ITEM item;
|
|
|
|
if (NumberOfThreads == 0)
|
|
{
|
|
PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);
|
|
}
|
|
else if (NumberOfThreads == 1)
|
|
{
|
|
// All menu items are enabled by default.
|
|
}
|
|
else
|
|
{
|
|
ULONG menuItemsMultiEnabled[] =
|
|
{
|
|
ID_THREAD_TERMINATE,
|
|
ID_THREAD_FORCETERMINATE,
|
|
ID_THREAD_SUSPEND,
|
|
ID_THREAD_RESUME,
|
|
ID_THREAD_COPY
|
|
};
|
|
ULONG i;
|
|
|
|
PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);
|
|
|
|
// These menu items are capable of manipulating
|
|
// multiple threads.
|
|
for (i = 0; i < sizeof(menuItemsMultiEnabled) / sizeof(ULONG); i++)
|
|
{
|
|
PhEnableEMenuItem(Menu, menuItemsMultiEnabled[i], TRUE);
|
|
}
|
|
}
|
|
|
|
// Remove irrelevant menu items.
|
|
|
|
if (WindowsVersion < WINDOWS_VISTA)
|
|
{
|
|
// Remove I/O priority.
|
|
if (item = PhFindEMenuItem(Menu, 0, L"I/O Priority", 0))
|
|
PhDestroyEMenuItem(item);
|
|
// Remove page priority.
|
|
if (item = PhFindEMenuItem(Menu, 0, L"Page Priority", 0))
|
|
PhDestroyEMenuItem(item);
|
|
}
|
|
|
|
#ifndef _WIN64
|
|
if (!KphIsConnected())
|
|
{
|
|
#endif
|
|
// Remove Force Terminate (this is always done on x64).
|
|
if (item = PhFindEMenuItem(Menu, 0, NULL, ID_THREAD_FORCETERMINATE))
|
|
PhDestroyEMenuItem(item);
|
|
#ifndef _WIN64
|
|
}
|
|
else
|
|
{
|
|
if (ProcessId == SYSTEM_PROCESS_ID)
|
|
{
|
|
// Remove Force Terminate because Terminate does
|
|
// the same job.
|
|
if (item = PhFindEMenuItem(Menu, 0, NULL, ID_THREAD_FORCETERMINATE))
|
|
PhDestroyEMenuItem(item);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
PhEnableEMenuItem(Menu, ID_THREAD_TOKEN, FALSE);
|
|
|
|
// Priority
|
|
if (NumberOfThreads == 1)
|
|
{
|
|
HANDLE threadHandle;
|
|
ULONG ioPriority = -1;
|
|
ULONG pagePriority = -1;
|
|
ULONG threadPriority = THREAD_PRIORITY_ERROR_RETURN;
|
|
ULONG id = 0;
|
|
|
|
if (NT_SUCCESS(PhOpenThread(
|
|
&threadHandle,
|
|
ThreadQueryAccess,
|
|
Threads[0]->ThreadId
|
|
)))
|
|
{
|
|
threadPriority = GetThreadPriority(threadHandle);
|
|
|
|
if (WindowsVersion >= WINDOWS_VISTA)
|
|
{
|
|
if (!NT_SUCCESS(PhGetThreadIoPriority(
|
|
threadHandle,
|
|
&ioPriority
|
|
)))
|
|
{
|
|
ioPriority = -1;
|
|
}
|
|
|
|
if (!NT_SUCCESS(PhGetThreadPagePriority(
|
|
threadHandle,
|
|
&pagePriority
|
|
)))
|
|
{
|
|
pagePriority = -1;
|
|
}
|
|
}
|
|
|
|
// Token
|
|
{
|
|
HANDLE tokenHandle;
|
|
|
|
if (NT_SUCCESS(PhOpenThreadToken(
|
|
&tokenHandle,
|
|
TOKEN_QUERY,
|
|
threadHandle,
|
|
TRUE
|
|
)))
|
|
{
|
|
PhEnableEMenuItem(Menu, ID_THREAD_TOKEN, TRUE);
|
|
NtClose(tokenHandle);
|
|
}
|
|
}
|
|
|
|
NtClose(threadHandle);
|
|
}
|
|
|
|
switch (threadPriority)
|
|
{
|
|
case THREAD_PRIORITY_TIME_CRITICAL:
|
|
id = ID_PRIORITY_TIMECRITICAL;
|
|
break;
|
|
case THREAD_PRIORITY_HIGHEST:
|
|
id = ID_PRIORITY_HIGHEST;
|
|
break;
|
|
case THREAD_PRIORITY_ABOVE_NORMAL:
|
|
id = ID_PRIORITY_ABOVENORMAL;
|
|
break;
|
|
case THREAD_PRIORITY_NORMAL:
|
|
id = ID_PRIORITY_NORMAL;
|
|
break;
|
|
case THREAD_PRIORITY_BELOW_NORMAL:
|
|
id = ID_PRIORITY_BELOWNORMAL;
|
|
break;
|
|
case THREAD_PRIORITY_LOWEST:
|
|
id = ID_PRIORITY_LOWEST;
|
|
break;
|
|
case THREAD_PRIORITY_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 (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 (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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static NTSTATUS NTAPI PhpThreadPermissionsOpenThread(
|
|
_Out_ PHANDLE Handle,
|
|
_In_ ACCESS_MASK DesiredAccess,
|
|
_In_opt_ PVOID Context
|
|
)
|
|
{
|
|
return PhOpenThread(Handle, DesiredAccess, (HANDLE)Context);
|
|
}
|
|
|
|
static NTSTATUS NTAPI PhpOpenThreadTokenObject(
|
|
_Out_ PHANDLE Handle,
|
|
_In_ ACCESS_MASK DesiredAccess,
|
|
_In_opt_ PVOID Context
|
|
)
|
|
{
|
|
return PhOpenThreadToken(
|
|
Handle,
|
|
DesiredAccess,
|
|
(HANDLE)Context,
|
|
TRUE
|
|
);
|
|
}
|
|
|
|
VOID PhpUpdateThreadDetails(
|
|
_In_ HWND hwndDlg,
|
|
_In_ PPH_THREADS_CONTEXT Context,
|
|
_In_ BOOLEAN Force
|
|
)
|
|
{
|
|
PPH_THREAD_ITEM *threads;
|
|
ULONG numberOfThreads;
|
|
PPH_THREAD_ITEM threadItem;
|
|
PPH_STRING startModule = NULL;
|
|
PPH_STRING started = NULL;
|
|
WCHAR kernelTime[PH_TIMESPAN_STR_LEN_1] = L"N/A";
|
|
WCHAR userTime[PH_TIMESPAN_STR_LEN_1] = L"N/A";
|
|
PPH_STRING contextSwitches = NULL;
|
|
PPH_STRING cycles = NULL;
|
|
PPH_STRING state = NULL;
|
|
WCHAR priority[PH_INT32_STR_LEN_1] = L"N/A";
|
|
WCHAR basePriority[PH_INT32_STR_LEN_1] = L"N/A";
|
|
PWSTR ioPriority = L"N/A";
|
|
WCHAR pagePriority[PH_INT32_STR_LEN_1] = L"N/A";
|
|
WCHAR idealProcessor[PH_INT32_STR_LEN + 1 + PH_INT32_STR_LEN + 1] = L"N/A";
|
|
HANDLE threadHandle;
|
|
SYSTEMTIME time;
|
|
ULONG ioPriorityInteger;
|
|
ULONG pagePriorityInteger;
|
|
PROCESSOR_NUMBER idealProcessorNumber;
|
|
ULONG suspendCount;
|
|
|
|
PhGetSelectedThreadItems(&Context->ListContext, &threads, &numberOfThreads);
|
|
|
|
if (numberOfThreads == 1)
|
|
threadItem = threads[0];
|
|
else
|
|
threadItem = NULL;
|
|
|
|
PhFree(threads);
|
|
|
|
if (numberOfThreads != 1 && !Force)
|
|
return;
|
|
|
|
if (numberOfThreads == 1)
|
|
{
|
|
startModule = threadItem->StartAddressFileName;
|
|
|
|
PhLargeIntegerToLocalSystemTime(&time, &threadItem->CreateTime);
|
|
started = PhaFormatDateTime(&time);
|
|
|
|
PhPrintTimeSpan(kernelTime, threadItem->KernelTime.QuadPart, PH_TIMESPAN_HMSM);
|
|
PhPrintTimeSpan(userTime, threadItem->UserTime.QuadPart, PH_TIMESPAN_HMSM);
|
|
|
|
contextSwitches = PhaFormatUInt64(threadItem->ContextSwitchesDelta.Value, TRUE);
|
|
|
|
if (WINDOWS_HAS_CYCLE_TIME)
|
|
cycles = PhaFormatUInt64(threadItem->CyclesDelta.Value, TRUE);
|
|
|
|
if (threadItem->State != Waiting)
|
|
{
|
|
if ((ULONG)threadItem->State < MaximumThreadState)
|
|
state = PhaCreateString(PhKThreadStateNames[(ULONG)threadItem->State]);
|
|
else
|
|
state = PhaCreateString(L"Unknown");
|
|
}
|
|
else
|
|
{
|
|
if ((ULONG)threadItem->WaitReason < MaximumWaitReason)
|
|
state = PhaConcatStrings2(L"Wait:", PhKWaitReasonNames[(ULONG)threadItem->WaitReason]);
|
|
else
|
|
state = PhaCreateString(L"Waiting");
|
|
}
|
|
|
|
PhPrintInt32(priority, threadItem->Priority);
|
|
PhPrintInt32(basePriority, threadItem->BasePriority);
|
|
|
|
if (NT_SUCCESS(PhOpenThread(&threadHandle, ThreadQueryAccess, threadItem->ThreadId)))
|
|
{
|
|
if (NT_SUCCESS(PhGetThreadIoPriority(threadHandle, &ioPriorityInteger)) &&
|
|
ioPriorityInteger < MaxIoPriorityTypes)
|
|
{
|
|
ioPriority = PhIoPriorityHintNames[ioPriorityInteger];
|
|
}
|
|
|
|
if (NT_SUCCESS(PhGetThreadPagePriority(threadHandle, &pagePriorityInteger)))
|
|
{
|
|
PhPrintUInt32(pagePriority, pagePriorityInteger);
|
|
}
|
|
|
|
if (NT_SUCCESS(NtQueryInformationThread(threadHandle, ThreadIdealProcessorEx, &idealProcessorNumber, sizeof(PROCESSOR_NUMBER), NULL)))
|
|
{
|
|
PH_FORMAT format[3];
|
|
|
|
PhInitFormatU(&format[0], idealProcessorNumber.Group);
|
|
PhInitFormatC(&format[1], ':');
|
|
PhInitFormatU(&format[2], idealProcessorNumber.Number);
|
|
PhFormatToBuffer(format, 3, idealProcessor, sizeof(idealProcessor), NULL);
|
|
}
|
|
|
|
if (threadItem->WaitReason == Suspended && NT_SUCCESS(NtQueryInformationThread(threadHandle, ThreadSuspendCount, &suspendCount, sizeof(ULONG), NULL)))
|
|
{
|
|
PH_FORMAT format[4];
|
|
|
|
PhInitFormatSR(&format[0], state->sr);
|
|
PhInitFormatS(&format[1], L" (");
|
|
PhInitFormatU(&format[2], suspendCount);
|
|
PhInitFormatS(&format[3], L")");
|
|
state = PhAutoDereferenceObject(PhFormat(format, 4, 30));
|
|
}
|
|
|
|
NtClose(threadHandle);
|
|
}
|
|
}
|
|
|
|
if (Force)
|
|
{
|
|
// These don't change...
|
|
|
|
SetDlgItemText(hwndDlg, IDC_STARTMODULE, PhGetStringOrEmpty(startModule));
|
|
EnableWindow(GetDlgItem(hwndDlg, IDC_OPENSTARTMODULE), !!startModule);
|
|
|
|
SetDlgItemText(hwndDlg, IDC_STARTED, PhGetStringOrDefault(started, L"N/A"));
|
|
}
|
|
|
|
SetDlgItemText(hwndDlg, IDC_KERNELTIME, kernelTime);
|
|
SetDlgItemText(hwndDlg, IDC_USERTIME, userTime);
|
|
SetDlgItemText(hwndDlg, IDC_CONTEXTSWITCHES, PhGetStringOrDefault(contextSwitches, L"N/A"));
|
|
SetDlgItemText(hwndDlg, IDC_CYCLES, PhGetStringOrDefault(cycles, L"N/A"));
|
|
SetDlgItemText(hwndDlg, IDC_STATE, PhGetStringOrDefault(state, L"N/A"));
|
|
SetDlgItemText(hwndDlg, IDC_PRIORITY, priority);
|
|
SetDlgItemText(hwndDlg, IDC_BASEPRIORITY, basePriority);
|
|
SetDlgItemText(hwndDlg, IDC_IOPRIORITY, ioPriority);
|
|
SetDlgItemText(hwndDlg, IDC_PAGEPRIORITY, pagePriority);
|
|
SetDlgItemText(hwndDlg, IDC_IDEALPROCESSOR, idealProcessor);
|
|
}
|
|
|
|
VOID PhShowThreadContextMenu(
|
|
_In_ HWND hwndDlg,
|
|
_In_ PPH_PROCESS_ITEM ProcessItem,
|
|
_In_ PPH_THREADS_CONTEXT Context,
|
|
_In_ PPH_TREENEW_CONTEXT_MENU ContextMenu
|
|
)
|
|
{
|
|
PPH_THREAD_ITEM *threads;
|
|
ULONG numberOfThreads;
|
|
|
|
PhGetSelectedThreadItems(&Context->ListContext, &threads, &numberOfThreads);
|
|
|
|
if (numberOfThreads != 0)
|
|
{
|
|
PPH_EMENU menu;
|
|
PPH_EMENU_ITEM item;
|
|
PH_PLUGIN_MENU_INFORMATION menuInfo;
|
|
|
|
menu = PhCreateEMenu();
|
|
PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_THREAD), 0);
|
|
PhSetFlagsEMenuItem(menu, ID_THREAD_INSPECT, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT);
|
|
|
|
PhpInitializeThreadMenu(menu, ProcessItem->ProcessId, threads, numberOfThreads);
|
|
PhInsertCopyCellEMenuItem(menu, ID_THREAD_COPY, Context->ListContext.TreeNewHandle, ContextMenu->Column);
|
|
|
|
if (PhPluginsEnabled)
|
|
{
|
|
PhPluginInitializeMenuInfo(&menuInfo, menu, hwndDlg, 0);
|
|
menuInfo.u.Thread.ProcessId = ProcessItem->ProcessId;
|
|
menuInfo.u.Thread.Threads = threads;
|
|
menuInfo.u.Thread.NumberOfThreads = numberOfThreads;
|
|
|
|
PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadMenuInitializing), &menuInfo);
|
|
}
|
|
|
|
item = PhShowEMenu(
|
|
menu,
|
|
hwndDlg,
|
|
PH_EMENU_SHOW_LEFTRIGHT,
|
|
PH_ALIGN_LEFT | PH_ALIGN_TOP,
|
|
ContextMenu->Location.x,
|
|
ContextMenu->Location.y
|
|
);
|
|
|
|
if (item)
|
|
{
|
|
BOOLEAN handled = FALSE;
|
|
|
|
handled = PhHandleCopyCellEMenuItem(item);
|
|
|
|
if (!handled && PhPluginsEnabled)
|
|
handled = PhPluginTriggerEMenuItem(&menuInfo, item);
|
|
|
|
if (!handled)
|
|
SendMessage(hwndDlg, WM_COMMAND, item->Id, 0);
|
|
}
|
|
|
|
PhDestroyEMenu(menu);
|
|
}
|
|
|
|
PhFree(threads);
|
|
}
|
|
|
|
INT_PTR CALLBACK PhpProcessThreadsDlgProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
)
|
|
{
|
|
LPPROPSHEETPAGE propSheetPage;
|
|
PPH_PROCESS_PROPPAGECONTEXT propPageContext;
|
|
PPH_PROCESS_ITEM processItem;
|
|
PPH_THREADS_CONTEXT threadsContext;
|
|
HWND tnHandle;
|
|
|
|
if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam,
|
|
&propSheetPage, &propPageContext, &processItem))
|
|
{
|
|
threadsContext = (PPH_THREADS_CONTEXT)propPageContext->Context;
|
|
|
|
if (threadsContext)
|
|
tnHandle = threadsContext->ListContext.TreeNewHandle;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
threadsContext = propPageContext->Context =
|
|
PhAllocate(PhEmGetObjectSize(EmThreadsContextType, sizeof(PH_THREADS_CONTEXT)));
|
|
|
|
// The thread provider has a special registration mechanism.
|
|
threadsContext->Provider = PhCreateThreadProvider(
|
|
processItem->ProcessId
|
|
);
|
|
PhRegisterCallback(
|
|
&threadsContext->Provider->ThreadAddedEvent,
|
|
ThreadAddedHandler,
|
|
threadsContext,
|
|
&threadsContext->AddedEventRegistration
|
|
);
|
|
PhRegisterCallback(
|
|
&threadsContext->Provider->ThreadModifiedEvent,
|
|
ThreadModifiedHandler,
|
|
threadsContext,
|
|
&threadsContext->ModifiedEventRegistration
|
|
);
|
|
PhRegisterCallback(
|
|
&threadsContext->Provider->ThreadRemovedEvent,
|
|
ThreadRemovedHandler,
|
|
threadsContext,
|
|
&threadsContext->RemovedEventRegistration
|
|
);
|
|
PhRegisterCallback(
|
|
&threadsContext->Provider->UpdatedEvent,
|
|
ThreadsUpdatedHandler,
|
|
threadsContext,
|
|
&threadsContext->UpdatedEventRegistration
|
|
);
|
|
PhRegisterCallback(
|
|
&threadsContext->Provider->LoadingStateChangedEvent,
|
|
ThreadsLoadingStateChangedHandler,
|
|
threadsContext,
|
|
&threadsContext->LoadingStateChangedEventRegistration
|
|
);
|
|
threadsContext->WindowHandle = hwndDlg;
|
|
|
|
// Initialize the list.
|
|
tnHandle = GetDlgItem(hwndDlg, IDC_LIST);
|
|
BringWindowToTop(tnHandle);
|
|
PhInitializeThreadList(hwndDlg, tnHandle, &threadsContext->ListContext);
|
|
TreeNew_SetEmptyText(tnHandle, &EmptyThreadsText, 0);
|
|
threadsContext->NeedsRedraw = FALSE;
|
|
|
|
// Use Cycles instead of Context Switches on Vista and above, but only when we can
|
|
// open the process, since cycle time information requires sufficient access to the
|
|
// threads.
|
|
if (WINDOWS_HAS_CYCLE_TIME)
|
|
{
|
|
HANDLE processHandle;
|
|
PROCESS_EXTENDED_BASIC_INFORMATION extendedBasicInfo;
|
|
|
|
// We make a distinction between PROCESS_QUERY_INFORMATION and PROCESS_QUERY_LIMITED_INFORMATION since
|
|
// the latter can be used when opening audiodg.exe even though we can't access its threads using
|
|
// THREAD_QUERY_LIMITED_INFORMATION.
|
|
|
|
if (processItem->ProcessId == SYSTEM_IDLE_PROCESS_ID)
|
|
{
|
|
threadsContext->ListContext.UseCycleTime = TRUE;
|
|
}
|
|
else if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_INFORMATION, processItem->ProcessId)))
|
|
{
|
|
threadsContext->ListContext.UseCycleTime = TRUE;
|
|
NtClose(processHandle);
|
|
}
|
|
else if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, processItem->ProcessId)))
|
|
{
|
|
threadsContext->ListContext.UseCycleTime = TRUE;
|
|
|
|
// We can't use cycle time for protected processes (without KProcessHacker).
|
|
if (NT_SUCCESS(PhGetProcessExtendedBasicInformation(processHandle, &extendedBasicInfo)) && extendedBasicInfo.IsProtectedProcess)
|
|
{
|
|
threadsContext->ListContext.UseCycleTime = FALSE;
|
|
}
|
|
|
|
NtClose(processHandle);
|
|
}
|
|
}
|
|
|
|
if (processItem->ServiceList && processItem->ServiceList->Count != 0 && WINDOWS_HAS_SERVICE_TAGS)
|
|
threadsContext->ListContext.HasServices = TRUE;
|
|
|
|
PhEmCallObjectOperation(EmThreadsContextType, threadsContext, EmObjectCreate);
|
|
|
|
if (PhPluginsEnabled)
|
|
{
|
|
PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;
|
|
|
|
treeNewInfo.TreeNewHandle = tnHandle;
|
|
treeNewInfo.CmData = &threadsContext->ListContext.Cm;
|
|
treeNewInfo.SystemContext = threadsContext;
|
|
PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadTreeNewInitializing), &treeNewInfo);
|
|
}
|
|
|
|
PhLoadSettingsThreadList(&threadsContext->ListContext);
|
|
|
|
PhThreadProviderInitialUpdate(threadsContext->Provider);
|
|
PhRegisterThreadProvider(threadsContext->Provider, &threadsContext->ProviderRegistration);
|
|
|
|
SET_BUTTON_BITMAP(IDC_OPENSTARTMODULE,
|
|
PH_LOAD_SHARED_IMAGE(MAKEINTRESOURCE(IDB_FOLDER), IMAGE_BITMAP));
|
|
}
|
|
break;
|
|
case WM_DESTROY:
|
|
{
|
|
PhEmCallObjectOperation(EmThreadsContextType, threadsContext, EmObjectDelete);
|
|
|
|
PhUnregisterCallback(
|
|
&threadsContext->Provider->ThreadAddedEvent,
|
|
&threadsContext->AddedEventRegistration
|
|
);
|
|
PhUnregisterCallback(
|
|
&threadsContext->Provider->ThreadModifiedEvent,
|
|
&threadsContext->ModifiedEventRegistration
|
|
);
|
|
PhUnregisterCallback(
|
|
&threadsContext->Provider->ThreadRemovedEvent,
|
|
&threadsContext->RemovedEventRegistration
|
|
);
|
|
PhUnregisterCallback(
|
|
&threadsContext->Provider->UpdatedEvent,
|
|
&threadsContext->UpdatedEventRegistration
|
|
);
|
|
PhUnregisterCallback(
|
|
&threadsContext->Provider->LoadingStateChangedEvent,
|
|
&threadsContext->LoadingStateChangedEventRegistration
|
|
);
|
|
PhUnregisterThreadProvider(threadsContext->Provider, &threadsContext->ProviderRegistration);
|
|
PhSetTerminatingThreadProvider(threadsContext->Provider);
|
|
PhDereferenceObject(threadsContext->Provider);
|
|
|
|
if (PhPluginsEnabled)
|
|
{
|
|
PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;
|
|
|
|
treeNewInfo.TreeNewHandle = tnHandle;
|
|
treeNewInfo.CmData = &threadsContext->ListContext.Cm;
|
|
PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackThreadTreeNewUninitializing), &treeNewInfo);
|
|
}
|
|
|
|
PhSaveSettingsThreadList(&threadsContext->ListContext);
|
|
PhDeleteThreadList(&threadsContext->ListContext);
|
|
|
|
PhFree(threadsContext);
|
|
|
|
PhpPropPageDlgProcDestroy(hwndDlg);
|
|
}
|
|
break;
|
|
case WM_SHOWWINDOW:
|
|
{
|
|
if (!propPageContext->LayoutInitialized)
|
|
{
|
|
PPH_LAYOUT_ITEM dialogItem;
|
|
|
|
dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg,
|
|
PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST),
|
|
dialogItem, PH_ANCHOR_ALL);
|
|
|
|
#define ADD_BL_ITEM(Id) \
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, Id), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM)
|
|
|
|
// Thread details area
|
|
{
|
|
ULONG id;
|
|
|
|
for (id = IDC_STATICBL1; id <= IDC_STATICBL11; id++)
|
|
ADD_BL_ITEM(id);
|
|
|
|
// Not in sequence
|
|
ADD_BL_ITEM(IDC_STATICBL12);
|
|
}
|
|
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_STARTMODULE),
|
|
dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_OPENSTARTMODULE),
|
|
dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
|
|
ADD_BL_ITEM(IDC_STARTED);
|
|
ADD_BL_ITEM(IDC_KERNELTIME);
|
|
ADD_BL_ITEM(IDC_USERTIME);
|
|
ADD_BL_ITEM(IDC_CONTEXTSWITCHES);
|
|
ADD_BL_ITEM(IDC_CYCLES);
|
|
ADD_BL_ITEM(IDC_STATE);
|
|
ADD_BL_ITEM(IDC_PRIORITY);
|
|
ADD_BL_ITEM(IDC_BASEPRIORITY);
|
|
ADD_BL_ITEM(IDC_IOPRIORITY);
|
|
ADD_BL_ITEM(IDC_PAGEPRIORITY);
|
|
ADD_BL_ITEM(IDC_IDEALPROCESSOR);
|
|
|
|
PhDoPropPageLayout(hwndDlg);
|
|
|
|
propPageContext->LayoutInitialized = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
case WM_COMMAND:
|
|
{
|
|
INT id = LOWORD(wParam);
|
|
|
|
switch (id)
|
|
{
|
|
case ID_SHOWCONTEXTMENU:
|
|
{
|
|
PhShowThreadContextMenu(hwndDlg, processItem, threadsContext, (PPH_TREENEW_CONTEXT_MENU)lParam);
|
|
}
|
|
break;
|
|
case ID_THREAD_INSPECT:
|
|
{
|
|
PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);
|
|
|
|
if (threadItem)
|
|
{
|
|
PhReferenceObject(threadsContext->Provider);
|
|
PhShowThreadStackDialog(
|
|
hwndDlg,
|
|
threadsContext->Provider->ProcessId,
|
|
threadItem->ThreadId,
|
|
threadsContext->Provider
|
|
);
|
|
PhDereferenceObject(threadsContext->Provider);
|
|
}
|
|
}
|
|
break;
|
|
case ID_THREAD_TERMINATE:
|
|
{
|
|
PPH_THREAD_ITEM *threads;
|
|
ULONG numberOfThreads;
|
|
|
|
PhGetSelectedThreadItems(&threadsContext->ListContext, &threads, &numberOfThreads);
|
|
PhReferenceObjects(threads, numberOfThreads);
|
|
|
|
if (
|
|
processItem->ProcessId != SYSTEM_PROCESS_ID ||
|
|
!KphIsConnected()
|
|
)
|
|
{
|
|
if (PhUiTerminateThreads(hwndDlg, threads, numberOfThreads))
|
|
PhDeselectAllThreadNodes(&threadsContext->ListContext);
|
|
}
|
|
else
|
|
{
|
|
if (PhUiForceTerminateThreads(hwndDlg, processItem->ProcessId, threads, numberOfThreads))
|
|
PhDeselectAllThreadNodes(&threadsContext->ListContext);
|
|
}
|
|
|
|
PhDereferenceObjects(threads, numberOfThreads);
|
|
PhFree(threads);
|
|
}
|
|
break;
|
|
case ID_THREAD_FORCETERMINATE:
|
|
{
|
|
PPH_THREAD_ITEM *threads;
|
|
ULONG numberOfThreads;
|
|
|
|
PhGetSelectedThreadItems(&threadsContext->ListContext, &threads, &numberOfThreads);
|
|
PhReferenceObjects(threads, numberOfThreads);
|
|
|
|
if (PhUiForceTerminateThreads(hwndDlg, processItem->ProcessId, threads, numberOfThreads))
|
|
PhDeselectAllThreadNodes(&threadsContext->ListContext);
|
|
|
|
PhDereferenceObjects(threads, numberOfThreads);
|
|
PhFree(threads);
|
|
}
|
|
break;
|
|
case ID_THREAD_SUSPEND:
|
|
{
|
|
PPH_THREAD_ITEM *threads;
|
|
ULONG numberOfThreads;
|
|
|
|
PhGetSelectedThreadItems(&threadsContext->ListContext, &threads, &numberOfThreads);
|
|
PhReferenceObjects(threads, numberOfThreads);
|
|
PhUiSuspendThreads(hwndDlg, threads, numberOfThreads);
|
|
PhDereferenceObjects(threads, numberOfThreads);
|
|
PhFree(threads);
|
|
}
|
|
break;
|
|
case ID_THREAD_RESUME:
|
|
{
|
|
PPH_THREAD_ITEM *threads;
|
|
ULONG numberOfThreads;
|
|
|
|
PhGetSelectedThreadItems(&threadsContext->ListContext, &threads, &numberOfThreads);
|
|
PhReferenceObjects(threads, numberOfThreads);
|
|
PhUiResumeThreads(hwndDlg, threads, numberOfThreads);
|
|
PhDereferenceObjects(threads, numberOfThreads);
|
|
PhFree(threads);
|
|
}
|
|
break;
|
|
case ID_THREAD_AFFINITY:
|
|
{
|
|
PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);
|
|
|
|
if (threadItem)
|
|
{
|
|
PhReferenceObject(threadItem);
|
|
PhShowProcessAffinityDialog(hwndDlg, NULL, threadItem);
|
|
PhDereferenceObject(threadItem);
|
|
}
|
|
}
|
|
break;
|
|
case ID_THREAD_PERMISSIONS:
|
|
{
|
|
PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);
|
|
PH_STD_OBJECT_SECURITY stdObjectSecurity;
|
|
PPH_ACCESS_ENTRY accessEntries;
|
|
ULONG numberOfAccessEntries;
|
|
|
|
if (threadItem)
|
|
{
|
|
stdObjectSecurity.OpenObject = PhpThreadPermissionsOpenThread;
|
|
stdObjectSecurity.ObjectType = L"Thread";
|
|
stdObjectSecurity.Context = threadItem->ThreadId;
|
|
|
|
if (PhGetAccessEntries(L"Thread", &accessEntries, &numberOfAccessEntries))
|
|
{
|
|
PhEditSecurity(
|
|
hwndDlg,
|
|
PhaFormatString(L"Thread %u", HandleToUlong(threadItem->ThreadId))->Buffer,
|
|
PhStdGetObjectSecurity,
|
|
PhStdSetObjectSecurity,
|
|
&stdObjectSecurity,
|
|
accessEntries,
|
|
numberOfAccessEntries
|
|
);
|
|
PhFree(accessEntries);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case ID_THREAD_TOKEN:
|
|
{
|
|
NTSTATUS status;
|
|
PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);
|
|
HANDLE threadHandle;
|
|
|
|
if (threadItem)
|
|
{
|
|
if (NT_SUCCESS(status = PhOpenThread(
|
|
&threadHandle,
|
|
ThreadQueryAccess,
|
|
threadItem->ThreadId
|
|
)))
|
|
{
|
|
PhShowTokenProperties(
|
|
hwndDlg,
|
|
PhpOpenThreadTokenObject,
|
|
(PVOID)threadHandle,
|
|
NULL
|
|
);
|
|
|
|
NtClose(threadHandle);
|
|
}
|
|
else
|
|
{
|
|
PhShowStatus(hwndDlg, L"Unable to open the thread", status, 0);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case ID_ANALYZE_WAIT:
|
|
{
|
|
PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);
|
|
|
|
if (threadItem)
|
|
{
|
|
PhReferenceObject(threadsContext->Provider->SymbolProvider);
|
|
PhUiAnalyzeWaitThread(
|
|
hwndDlg,
|
|
processItem->ProcessId,
|
|
threadItem->ThreadId,
|
|
threadsContext->Provider->SymbolProvider
|
|
);
|
|
PhDereferenceObject(threadsContext->Provider->SymbolProvider);
|
|
}
|
|
}
|
|
break;
|
|
case ID_PRIORITY_TIMECRITICAL:
|
|
case ID_PRIORITY_HIGHEST:
|
|
case ID_PRIORITY_ABOVENORMAL:
|
|
case ID_PRIORITY_NORMAL:
|
|
case ID_PRIORITY_BELOWNORMAL:
|
|
case ID_PRIORITY_LOWEST:
|
|
case ID_PRIORITY_IDLE:
|
|
{
|
|
PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);
|
|
|
|
if (threadItem)
|
|
{
|
|
ULONG threadPriorityWin32;
|
|
|
|
switch (id)
|
|
{
|
|
case ID_PRIORITY_TIMECRITICAL:
|
|
threadPriorityWin32 = THREAD_PRIORITY_TIME_CRITICAL;
|
|
break;
|
|
case ID_PRIORITY_HIGHEST:
|
|
threadPriorityWin32 = THREAD_PRIORITY_HIGHEST;
|
|
break;
|
|
case ID_PRIORITY_ABOVENORMAL:
|
|
threadPriorityWin32 = THREAD_PRIORITY_ABOVE_NORMAL;
|
|
break;
|
|
case ID_PRIORITY_NORMAL:
|
|
threadPriorityWin32 = THREAD_PRIORITY_NORMAL;
|
|
break;
|
|
case ID_PRIORITY_BELOWNORMAL:
|
|
threadPriorityWin32 = THREAD_PRIORITY_BELOW_NORMAL;
|
|
break;
|
|
case ID_PRIORITY_LOWEST:
|
|
threadPriorityWin32 = THREAD_PRIORITY_LOWEST;
|
|
break;
|
|
case ID_PRIORITY_IDLE:
|
|
threadPriorityWin32 = THREAD_PRIORITY_IDLE;
|
|
break;
|
|
}
|
|
|
|
PhReferenceObject(threadItem);
|
|
PhUiSetPriorityThread(hwndDlg, threadItem, threadPriorityWin32);
|
|
PhDereferenceObject(threadItem);
|
|
}
|
|
}
|
|
break;
|
|
case ID_I_0:
|
|
case ID_I_1:
|
|
case ID_I_2:
|
|
case ID_I_3:
|
|
{
|
|
PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);
|
|
|
|
if (threadItem)
|
|
{
|
|
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(threadItem);
|
|
PhUiSetIoPriorityThread(hwndDlg, threadItem, ioPriority);
|
|
PhDereferenceObject(threadItem);
|
|
}
|
|
}
|
|
break;
|
|
case ID_PAGEPRIORITY_1:
|
|
case ID_PAGEPRIORITY_2:
|
|
case ID_PAGEPRIORITY_3:
|
|
case ID_PAGEPRIORITY_4:
|
|
case ID_PAGEPRIORITY_5:
|
|
{
|
|
PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);
|
|
|
|
if (threadItem)
|
|
{
|
|
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(threadItem);
|
|
PhUiSetPagePriorityThread(hwndDlg, threadItem, pagePriority);
|
|
PhDereferenceObject(threadItem);
|
|
}
|
|
}
|
|
break;
|
|
case ID_THREAD_COPY:
|
|
{
|
|
PPH_STRING text;
|
|
|
|
text = PhGetTreeNewText(tnHandle, 0);
|
|
PhSetClipboardString(tnHandle, &text->sr);
|
|
PhDereferenceObject(text);
|
|
}
|
|
break;
|
|
case IDC_OPENSTARTMODULE:
|
|
{
|
|
PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);
|
|
|
|
if (threadItem && threadItem->StartAddressFileName)
|
|
{
|
|
PhShellExploreFile(hwndDlg, threadItem->StartAddressFileName->Buffer);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case WM_NOTIFY:
|
|
{
|
|
LPNMHDR header = (LPNMHDR)lParam;
|
|
|
|
switch (header->code)
|
|
{
|
|
case PSN_SETACTIVE:
|
|
break;
|
|
case PSN_KILLACTIVE:
|
|
// Can't disable, it screws up the deltas.
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case WM_PH_THREAD_ADDED:
|
|
{
|
|
BOOLEAN firstRun = (BOOLEAN)wParam;
|
|
PPH_THREAD_ITEM threadItem = (PPH_THREAD_ITEM)lParam;
|
|
|
|
if (!threadsContext->NeedsRedraw)
|
|
{
|
|
// Disable redraw. It will be re-enabled later.
|
|
TreeNew_SetRedraw(tnHandle, FALSE);
|
|
threadsContext->NeedsRedraw = TRUE;
|
|
}
|
|
|
|
PhAddThreadNode(&threadsContext->ListContext, threadItem, firstRun);
|
|
PhDereferenceObject(threadItem);
|
|
}
|
|
break;
|
|
case WM_PH_THREAD_MODIFIED:
|
|
{
|
|
PPH_THREAD_ITEM threadItem = (PPH_THREAD_ITEM)lParam;
|
|
|
|
if (!threadsContext->NeedsRedraw)
|
|
{
|
|
TreeNew_SetRedraw(tnHandle, FALSE);
|
|
threadsContext->NeedsRedraw = TRUE;
|
|
}
|
|
|
|
PhUpdateThreadNode(&threadsContext->ListContext, PhFindThreadNode(&threadsContext->ListContext, threadItem->ThreadId));
|
|
}
|
|
break;
|
|
case WM_PH_THREAD_REMOVED:
|
|
{
|
|
PPH_THREAD_ITEM threadItem = (PPH_THREAD_ITEM)lParam;
|
|
|
|
if (!threadsContext->NeedsRedraw)
|
|
{
|
|
TreeNew_SetRedraw(tnHandle, FALSE);
|
|
threadsContext->NeedsRedraw = TRUE;
|
|
}
|
|
|
|
PhRemoveThreadNode(&threadsContext->ListContext, PhFindThreadNode(&threadsContext->ListContext, threadItem->ThreadId));
|
|
}
|
|
break;
|
|
case WM_PH_THREADS_UPDATED:
|
|
{
|
|
PhTickThreadNodes(&threadsContext->ListContext);
|
|
|
|
if (threadsContext->NeedsRedraw)
|
|
{
|
|
TreeNew_SetRedraw(tnHandle, TRUE);
|
|
threadsContext->NeedsRedraw = FALSE;
|
|
}
|
|
|
|
if (propPageContext->PropContext->SelectThreadId)
|
|
{
|
|
PPH_THREAD_NODE threadNode;
|
|
|
|
if (threadNode = PhFindThreadNode(&threadsContext->ListContext, propPageContext->PropContext->SelectThreadId))
|
|
{
|
|
if (threadNode->Node.Visible)
|
|
{
|
|
TreeNew_SetFocusNode(tnHandle, &threadNode->Node);
|
|
TreeNew_SetMarkNode(tnHandle, &threadNode->Node);
|
|
TreeNew_SelectRange(tnHandle, threadNode->Node.Index, threadNode->Node.Index);
|
|
TreeNew_EnsureVisible(tnHandle, &threadNode->Node);
|
|
}
|
|
}
|
|
|
|
propPageContext->PropContext->SelectThreadId = NULL;
|
|
}
|
|
|
|
PhpUpdateThreadDetails(hwndDlg, threadsContext, FALSE);
|
|
}
|
|
break;
|
|
case WM_PH_THREAD_SELECTION_CHANGED:
|
|
{
|
|
PhpUpdateThreadDetails(hwndDlg, threadsContext, TRUE);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static NTSTATUS NTAPI PhpOpenProcessToken(
|
|
_Out_ PHANDLE Handle,
|
|
_In_ ACCESS_MASK DesiredAccess,
|
|
_In_opt_ PVOID Context
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
HANDLE processHandle;
|
|
|
|
if (!NT_SUCCESS(status = PhOpenProcess(
|
|
&processHandle,
|
|
ProcessQueryAccess,
|
|
(HANDLE)Context
|
|
)))
|
|
return status;
|
|
|
|
status = PhOpenProcessToken(Handle, DesiredAccess, processHandle);
|
|
NtClose(processHandle);
|
|
|
|
return status;
|
|
}
|
|
|
|
INT_PTR CALLBACK PhpProcessTokenHookProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_DESTROY:
|
|
{
|
|
RemoveProp(hwndDlg, PhMakeContextAtom());
|
|
}
|
|
break;
|
|
case WM_SHOWWINDOW:
|
|
{
|
|
if (!GetProp(hwndDlg, PhMakeContextAtom())) // LayoutInitialized
|
|
{
|
|
PPH_LAYOUT_ITEM dialogItem;
|
|
HWND groupsLv;
|
|
HWND privilegesLv;
|
|
|
|
// This is a big violation of abstraction...
|
|
|
|
dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg,
|
|
PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_USER),
|
|
dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_USERSID),
|
|
dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_VIRTUALIZED),
|
|
dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_APPCONTAINERSID),
|
|
dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_GROUPS),
|
|
dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PRIVILEGES),
|
|
dialogItem, PH_ANCHOR_ALL);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_INSTRUCTION),
|
|
dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_INTEGRITY),
|
|
dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_ADVANCED),
|
|
dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
|
|
|
|
PhDoPropPageLayout(hwndDlg);
|
|
|
|
groupsLv = GetDlgItem(hwndDlg, IDC_GROUPS);
|
|
privilegesLv = GetDlgItem(hwndDlg, IDC_PRIVILEGES);
|
|
|
|
if (ListView_GetItemCount(groupsLv) != 0)
|
|
{
|
|
ListView_SetColumnWidth(groupsLv, 0, LVSCW_AUTOSIZE);
|
|
ExtendedListView_SetColumnWidth(groupsLv, 1, ELVSCW_AUTOSIZE_REMAININGSPACE);
|
|
}
|
|
|
|
if (ListView_GetItemCount(privilegesLv) != 0)
|
|
{
|
|
ListView_SetColumnWidth(privilegesLv, 0, LVSCW_AUTOSIZE);
|
|
ListView_SetColumnWidth(privilegesLv, 1, LVSCW_AUTOSIZE);
|
|
ExtendedListView_SetColumnWidth(privilegesLv, 2, ELVSCW_AUTOSIZE_REMAININGSPACE);
|
|
}
|
|
|
|
SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)TRUE);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static VOID NTAPI ModuleAddedHandler(
|
|
_In_opt_ PVOID Parameter,
|
|
_In_opt_ PVOID Context
|
|
)
|
|
{
|
|
PPH_MODULES_CONTEXT modulesContext = (PPH_MODULES_CONTEXT)Context;
|
|
|
|
// Parameter contains a pointer to the added module item.
|
|
PhReferenceObject(Parameter);
|
|
PostMessage(
|
|
modulesContext->WindowHandle,
|
|
WM_PH_MODULE_ADDED,
|
|
PhGetRunIdProvider(&modulesContext->ProviderRegistration),
|
|
(LPARAM)Parameter
|
|
);
|
|
}
|
|
|
|
static VOID NTAPI ModuleModifiedHandler(
|
|
_In_opt_ PVOID Parameter,
|
|
_In_opt_ PVOID Context
|
|
)
|
|
{
|
|
PPH_MODULES_CONTEXT modulesContext = (PPH_MODULES_CONTEXT)Context;
|
|
|
|
PostMessage(modulesContext->WindowHandle, WM_PH_MODULE_MODIFIED, 0, (LPARAM)Parameter);
|
|
}
|
|
|
|
static VOID NTAPI ModuleRemovedHandler(
|
|
_In_opt_ PVOID Parameter,
|
|
_In_opt_ PVOID Context
|
|
)
|
|
{
|
|
PPH_MODULES_CONTEXT modulesContext = (PPH_MODULES_CONTEXT)Context;
|
|
|
|
PostMessage(modulesContext->WindowHandle, WM_PH_MODULE_REMOVED, 0, (LPARAM)Parameter);
|
|
}
|
|
|
|
static VOID NTAPI ModulesUpdatedHandler(
|
|
_In_opt_ PVOID Parameter,
|
|
_In_opt_ PVOID Context
|
|
)
|
|
{
|
|
PPH_MODULES_CONTEXT modulesContext = (PPH_MODULES_CONTEXT)Context;
|
|
|
|
PostMessage(modulesContext->WindowHandle, WM_PH_MODULES_UPDATED, 0, 0);
|
|
}
|
|
|
|
VOID PhpInitializeModuleMenu(
|
|
_In_ PPH_EMENU Menu,
|
|
_In_ HANDLE ProcessId,
|
|
_In_ PPH_MODULE_ITEM *Modules,
|
|
_In_ ULONG NumberOfModules
|
|
)
|
|
{
|
|
PPH_EMENU_ITEM item;
|
|
PPH_STRING inspectExecutables;
|
|
|
|
inspectExecutables = PhGetStringSetting(L"ProgramInspectExecutables");
|
|
|
|
if (inspectExecutables->Length == 0)
|
|
{
|
|
if (item = PhFindEMenuItem(Menu, 0, NULL, ID_MODULE_INSPECT))
|
|
PhDestroyEMenuItem(item);
|
|
}
|
|
|
|
PhDereferenceObject(inspectExecutables);
|
|
|
|
if (NumberOfModules == 0)
|
|
{
|
|
PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);
|
|
}
|
|
else if (NumberOfModules == 1)
|
|
{
|
|
// Nothing
|
|
}
|
|
else
|
|
{
|
|
PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);
|
|
PhEnableEMenuItem(Menu, ID_MODULE_COPY, TRUE);
|
|
}
|
|
}
|
|
|
|
VOID PhShowModuleContextMenu(
|
|
_In_ HWND hwndDlg,
|
|
_In_ PPH_PROCESS_ITEM ProcessItem,
|
|
_In_ PPH_MODULES_CONTEXT Context,
|
|
_In_ PPH_TREENEW_CONTEXT_MENU ContextMenu
|
|
)
|
|
{
|
|
PPH_MODULE_ITEM *modules;
|
|
ULONG numberOfModules;
|
|
|
|
PhGetSelectedModuleItems(&Context->ListContext, &modules, &numberOfModules);
|
|
|
|
if (numberOfModules != 0)
|
|
{
|
|
PPH_EMENU menu;
|
|
PPH_EMENU_ITEM item;
|
|
PH_PLUGIN_MENU_INFORMATION menuInfo;
|
|
|
|
menu = PhCreateEMenu();
|
|
PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_MODULE), 0);
|
|
PhSetFlagsEMenuItem(menu, ID_MODULE_INSPECT, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT);
|
|
|
|
PhpInitializeModuleMenu(menu, ProcessItem->ProcessId, modules, numberOfModules);
|
|
PhInsertCopyCellEMenuItem(menu, ID_MODULE_COPY, Context->ListContext.TreeNewHandle, ContextMenu->Column);
|
|
|
|
if (PhPluginsEnabled)
|
|
{
|
|
PhPluginInitializeMenuInfo(&menuInfo, menu, hwndDlg, 0);
|
|
menuInfo.u.Module.ProcessId = ProcessItem->ProcessId;
|
|
menuInfo.u.Module.Modules = modules;
|
|
menuInfo.u.Module.NumberOfModules = numberOfModules;
|
|
|
|
PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackModuleMenuInitializing), &menuInfo);
|
|
}
|
|
|
|
item = PhShowEMenu(
|
|
menu,
|
|
hwndDlg,
|
|
PH_EMENU_SHOW_LEFTRIGHT,
|
|
PH_ALIGN_LEFT | PH_ALIGN_TOP,
|
|
ContextMenu->Location.x,
|
|
ContextMenu->Location.y
|
|
);
|
|
|
|
if (item)
|
|
{
|
|
BOOLEAN handled = FALSE;
|
|
|
|
handled = PhHandleCopyCellEMenuItem(item);
|
|
|
|
if (!handled && PhPluginsEnabled)
|
|
handled = PhPluginTriggerEMenuItem(&menuInfo, item);
|
|
|
|
if (!handled)
|
|
SendMessage(hwndDlg, WM_COMMAND, item->Id, 0);
|
|
}
|
|
|
|
PhDestroyEMenu(menu);
|
|
}
|
|
|
|
PhFree(modules);
|
|
}
|
|
|
|
INT_PTR CALLBACK PhpProcessModulesDlgProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
)
|
|
{
|
|
LPPROPSHEETPAGE propSheetPage;
|
|
PPH_PROCESS_PROPPAGECONTEXT propPageContext;
|
|
PPH_PROCESS_ITEM processItem;
|
|
PPH_MODULES_CONTEXT modulesContext;
|
|
HWND tnHandle;
|
|
|
|
if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam,
|
|
&propSheetPage, &propPageContext, &processItem))
|
|
{
|
|
modulesContext = (PPH_MODULES_CONTEXT)propPageContext->Context;
|
|
|
|
if (modulesContext)
|
|
tnHandle = modulesContext->ListContext.TreeNewHandle;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
// Lots of boilerplate code...
|
|
|
|
modulesContext = propPageContext->Context =
|
|
PhAllocate(PhEmGetObjectSize(EmModulesContextType, sizeof(PH_MODULES_CONTEXT)));
|
|
|
|
modulesContext->Provider = PhCreateModuleProvider(
|
|
processItem->ProcessId
|
|
);
|
|
PhRegisterProvider(
|
|
&PhSecondaryProviderThread,
|
|
PhModuleProviderUpdate,
|
|
modulesContext->Provider,
|
|
&modulesContext->ProviderRegistration
|
|
);
|
|
PhRegisterCallback(
|
|
&modulesContext->Provider->ModuleAddedEvent,
|
|
ModuleAddedHandler,
|
|
modulesContext,
|
|
&modulesContext->AddedEventRegistration
|
|
);
|
|
PhRegisterCallback(
|
|
&modulesContext->Provider->ModuleModifiedEvent,
|
|
ModuleModifiedHandler,
|
|
modulesContext,
|
|
&modulesContext->ModifiedEventRegistration
|
|
);
|
|
PhRegisterCallback(
|
|
&modulesContext->Provider->ModuleRemovedEvent,
|
|
ModuleRemovedHandler,
|
|
modulesContext,
|
|
&modulesContext->RemovedEventRegistration
|
|
);
|
|
PhRegisterCallback(
|
|
&modulesContext->Provider->UpdatedEvent,
|
|
ModulesUpdatedHandler,
|
|
modulesContext,
|
|
&modulesContext->UpdatedEventRegistration
|
|
);
|
|
modulesContext->WindowHandle = hwndDlg;
|
|
|
|
// Initialize the list.
|
|
tnHandle = GetDlgItem(hwndDlg, IDC_LIST);
|
|
BringWindowToTop(tnHandle);
|
|
PhInitializeModuleList(hwndDlg, tnHandle, &modulesContext->ListContext);
|
|
TreeNew_SetEmptyText(tnHandle, &LoadingText, 0);
|
|
modulesContext->NeedsRedraw = FALSE;
|
|
modulesContext->LastRunStatus = -1;
|
|
modulesContext->ErrorMessage = NULL;
|
|
|
|
PhEmCallObjectOperation(EmModulesContextType, modulesContext, EmObjectCreate);
|
|
|
|
if (PhPluginsEnabled)
|
|
{
|
|
PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;
|
|
|
|
treeNewInfo.TreeNewHandle = tnHandle;
|
|
treeNewInfo.CmData = &modulesContext->ListContext.Cm;
|
|
treeNewInfo.SystemContext = modulesContext;
|
|
PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackModuleTreeNewInitializing), &treeNewInfo);
|
|
}
|
|
|
|
PhLoadSettingsModuleList(&modulesContext->ListContext);
|
|
|
|
PhSetEnabledProvider(&modulesContext->ProviderRegistration, TRUE);
|
|
PhBoostProvider(&modulesContext->ProviderRegistration, NULL);
|
|
}
|
|
break;
|
|
case WM_DESTROY:
|
|
{
|
|
PhEmCallObjectOperation(EmModulesContextType, modulesContext, EmObjectDelete);
|
|
|
|
PhUnregisterCallback(
|
|
&modulesContext->Provider->ModuleAddedEvent,
|
|
&modulesContext->AddedEventRegistration
|
|
);
|
|
PhUnregisterCallback(
|
|
&modulesContext->Provider->ModuleModifiedEvent,
|
|
&modulesContext->ModifiedEventRegistration
|
|
);
|
|
PhUnregisterCallback(
|
|
&modulesContext->Provider->ModuleRemovedEvent,
|
|
&modulesContext->RemovedEventRegistration
|
|
);
|
|
PhUnregisterCallback(
|
|
&modulesContext->Provider->UpdatedEvent,
|
|
&modulesContext->UpdatedEventRegistration
|
|
);
|
|
PhUnregisterProvider(&modulesContext->ProviderRegistration);
|
|
PhDereferenceObject(modulesContext->Provider);
|
|
|
|
if (PhPluginsEnabled)
|
|
{
|
|
PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;
|
|
|
|
treeNewInfo.TreeNewHandle = tnHandle;
|
|
treeNewInfo.CmData = &modulesContext->ListContext.Cm;
|
|
PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackModuleTreeNewUninitializing), &treeNewInfo);
|
|
}
|
|
|
|
PhSaveSettingsModuleList(&modulesContext->ListContext);
|
|
PhDeleteModuleList(&modulesContext->ListContext);
|
|
|
|
PhClearReference(&modulesContext->ErrorMessage);
|
|
PhFree(modulesContext);
|
|
|
|
PhpPropPageDlgProcDestroy(hwndDlg);
|
|
}
|
|
break;
|
|
case WM_SHOWWINDOW:
|
|
{
|
|
if (!propPageContext->LayoutInitialized)
|
|
{
|
|
PPH_LAYOUT_ITEM dialogItem;
|
|
|
|
dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg,
|
|
PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL);
|
|
PhAddPropPageLayoutItem(hwndDlg, modulesContext->ListContext.TreeNewHandle,
|
|
dialogItem, PH_ANCHOR_ALL);
|
|
|
|
PhDoPropPageLayout(hwndDlg);
|
|
|
|
propPageContext->LayoutInitialized = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
case WM_COMMAND:
|
|
{
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case ID_SHOWCONTEXTMENU:
|
|
{
|
|
PhShowModuleContextMenu(hwndDlg, processItem, modulesContext, (PPH_TREENEW_CONTEXT_MENU)lParam);
|
|
}
|
|
break;
|
|
case ID_MODULE_UNLOAD:
|
|
{
|
|
PPH_MODULE_ITEM moduleItem = PhGetSelectedModuleItem(&modulesContext->ListContext);
|
|
|
|
if (moduleItem)
|
|
{
|
|
PhReferenceObject(moduleItem);
|
|
|
|
if (PhUiUnloadModule(hwndDlg, processItem->ProcessId, moduleItem))
|
|
PhDeselectAllModuleNodes(&modulesContext->ListContext);
|
|
|
|
PhDereferenceObject(moduleItem);
|
|
}
|
|
}
|
|
break;
|
|
case ID_MODULE_INSPECT:
|
|
{
|
|
PPH_MODULE_ITEM moduleItem = PhGetSelectedModuleItem(&modulesContext->ListContext);
|
|
|
|
if (moduleItem)
|
|
{
|
|
PhShellExecuteUserString(
|
|
hwndDlg,
|
|
L"ProgramInspectExecutables",
|
|
moduleItem->FileName->Buffer,
|
|
FALSE,
|
|
L"Make sure the PE Viewer executable file is present."
|
|
);
|
|
}
|
|
}
|
|
break;
|
|
case ID_MODULE_SEARCHONLINE:
|
|
{
|
|
PPH_MODULE_ITEM moduleItem = PhGetSelectedModuleItem(&modulesContext->ListContext);
|
|
|
|
if (moduleItem)
|
|
{
|
|
PhSearchOnlineString(hwndDlg, moduleItem->Name->Buffer);
|
|
}
|
|
}
|
|
break;
|
|
case ID_MODULE_OPENFILELOCATION:
|
|
{
|
|
PPH_MODULE_ITEM moduleItem = PhGetSelectedModuleItem(&modulesContext->ListContext);
|
|
|
|
if (moduleItem)
|
|
{
|
|
PhShellExploreFile(hwndDlg, moduleItem->FileName->Buffer);
|
|
}
|
|
}
|
|
break;
|
|
case ID_MODULE_PROPERTIES:
|
|
{
|
|
PPH_MODULE_ITEM moduleItem = PhGetSelectedModuleItem(&modulesContext->ListContext);
|
|
|
|
if (moduleItem)
|
|
{
|
|
PhShellProperties(hwndDlg, moduleItem->FileName->Buffer);
|
|
}
|
|
}
|
|
break;
|
|
case ID_MODULE_COPY:
|
|
{
|
|
PPH_STRING text;
|
|
|
|
text = PhGetTreeNewText(tnHandle, 0);
|
|
PhSetClipboardString(tnHandle, &text->sr);
|
|
PhDereferenceObject(text);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case WM_NOTIFY:
|
|
{
|
|
LPNMHDR header = (LPNMHDR)lParam;
|
|
|
|
switch (header->code)
|
|
{
|
|
case PSN_SETACTIVE:
|
|
PhSetEnabledProvider(&modulesContext->ProviderRegistration, TRUE);
|
|
break;
|
|
case PSN_KILLACTIVE:
|
|
PhSetEnabledProvider(&modulesContext->ProviderRegistration, FALSE);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case WM_PH_MODULE_ADDED:
|
|
{
|
|
ULONG runId = (ULONG)wParam;
|
|
PPH_MODULE_ITEM moduleItem = (PPH_MODULE_ITEM)lParam;
|
|
|
|
if (!modulesContext->NeedsRedraw)
|
|
{
|
|
TreeNew_SetRedraw(tnHandle, FALSE);
|
|
modulesContext->NeedsRedraw = TRUE;
|
|
}
|
|
|
|
PhAddModuleNode(&modulesContext->ListContext, moduleItem, runId);
|
|
PhDereferenceObject(moduleItem);
|
|
}
|
|
break;
|
|
case WM_PH_MODULE_MODIFIED:
|
|
{
|
|
PPH_MODULE_ITEM moduleItem = (PPH_MODULE_ITEM)lParam;
|
|
|
|
if (!modulesContext->NeedsRedraw)
|
|
{
|
|
TreeNew_SetRedraw(tnHandle, FALSE);
|
|
modulesContext->NeedsRedraw = TRUE;
|
|
}
|
|
|
|
PhUpdateModuleNode(&modulesContext->ListContext, PhFindModuleNode(&modulesContext->ListContext, moduleItem));
|
|
}
|
|
break;
|
|
case WM_PH_MODULE_REMOVED:
|
|
{
|
|
PPH_MODULE_ITEM moduleItem = (PPH_MODULE_ITEM)lParam;
|
|
|
|
if (!modulesContext->NeedsRedraw)
|
|
{
|
|
TreeNew_SetRedraw(tnHandle, FALSE);
|
|
modulesContext->NeedsRedraw = TRUE;
|
|
}
|
|
|
|
PhRemoveModuleNode(&modulesContext->ListContext, PhFindModuleNode(&modulesContext->ListContext, moduleItem));
|
|
}
|
|
break;
|
|
case WM_PH_MODULES_UPDATED:
|
|
{
|
|
PhTickModuleNodes(&modulesContext->ListContext);
|
|
|
|
if (modulesContext->LastRunStatus != modulesContext->Provider->RunStatus)
|
|
{
|
|
NTSTATUS status;
|
|
PPH_STRING message;
|
|
|
|
status = modulesContext->Provider->RunStatus;
|
|
modulesContext->LastRunStatus = status;
|
|
|
|
if (!PH_IS_REAL_PROCESS_ID(processItem->ProcessId))
|
|
status = STATUS_SUCCESS;
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
TreeNew_SetEmptyText(tnHandle, &EmptyModulesText, 0);
|
|
}
|
|
else
|
|
{
|
|
message = PhGetStatusMessage(status, 0);
|
|
PhMoveReference(&modulesContext->ErrorMessage, PhFormatString(L"Unable to query module information:\n%s", PhGetStringOrDefault(message, L"Unknown error.")));
|
|
PhClearReference(&message);
|
|
TreeNew_SetEmptyText(tnHandle, &modulesContext->ErrorMessage->sr, 0);
|
|
}
|
|
|
|
InvalidateRect(tnHandle, NULL, FALSE);
|
|
}
|
|
|
|
if (modulesContext->NeedsRedraw)
|
|
{
|
|
TreeNew_SetRedraw(tnHandle, TRUE);
|
|
modulesContext->NeedsRedraw = FALSE;
|
|
}
|
|
}
|
|
break;
|
|
case WM_CTLCOLORDLG:
|
|
{
|
|
return (INT_PTR)GetSysColorBrush(COLOR_WINDOW);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
VOID PhpRefreshProcessMemoryList(
|
|
_In_ HWND hwndDlg,
|
|
_In_ PPH_PROCESS_PROPPAGECONTEXT PropPageContext
|
|
)
|
|
{
|
|
PPH_MEMORY_CONTEXT memoryContext = PropPageContext->Context;
|
|
|
|
if (memoryContext->MemoryItemListValid)
|
|
{
|
|
PhDeleteMemoryItemList(&memoryContext->MemoryItemList);
|
|
memoryContext->MemoryItemListValid = FALSE;
|
|
}
|
|
|
|
memoryContext->LastRunStatus = PhQueryMemoryItemList(
|
|
memoryContext->ProcessId,
|
|
PH_QUERY_MEMORY_REGION_TYPE | PH_QUERY_MEMORY_WS_COUNTERS,
|
|
&memoryContext->MemoryItemList
|
|
);
|
|
|
|
if (NT_SUCCESS(memoryContext->LastRunStatus))
|
|
{
|
|
if (PhPluginsEnabled)
|
|
{
|
|
PH_PLUGIN_MEMORY_ITEM_LIST_CONTROL control;
|
|
|
|
control.Type = PluginMemoryItemListInitialized;
|
|
control.u.Initialized.List = &memoryContext->MemoryItemList;
|
|
|
|
PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMemoryItemListControl), &control);
|
|
}
|
|
|
|
memoryContext->MemoryItemListValid = TRUE;
|
|
TreeNew_SetEmptyText(memoryContext->ListContext.TreeNewHandle, &EmptyMemoryText, 0);
|
|
PhReplaceMemoryList(&memoryContext->ListContext, &memoryContext->MemoryItemList);
|
|
}
|
|
else
|
|
{
|
|
PPH_STRING message;
|
|
|
|
message = PhGetStatusMessage(memoryContext->LastRunStatus, 0);
|
|
PhMoveReference(&memoryContext->ErrorMessage, PhFormatString(L"Unable to query memory information:\n%s", PhGetStringOrDefault(message, L"Unknown error.")));
|
|
PhClearReference(&message);
|
|
TreeNew_SetEmptyText(memoryContext->ListContext.TreeNewHandle, &memoryContext->ErrorMessage->sr, 0);
|
|
|
|
PhReplaceMemoryList(&memoryContext->ListContext, NULL);
|
|
}
|
|
}
|
|
|
|
VOID PhpInitializeMemoryMenu(
|
|
_In_ PPH_EMENU Menu,
|
|
_In_ HANDLE ProcessId,
|
|
_In_ PPH_MEMORY_NODE *MemoryNodes,
|
|
_In_ ULONG NumberOfMemoryNodes
|
|
)
|
|
{
|
|
if (NumberOfMemoryNodes == 0)
|
|
{
|
|
PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);
|
|
}
|
|
else if (NumberOfMemoryNodes == 1 && !MemoryNodes[0]->IsAllocationBase)
|
|
{
|
|
if (MemoryNodes[0]->MemoryItem->State & MEM_FREE)
|
|
{
|
|
PhEnableEMenuItem(Menu, ID_MEMORY_CHANGEPROTECTION, FALSE);
|
|
PhEnableEMenuItem(Menu, ID_MEMORY_FREE, FALSE);
|
|
PhEnableEMenuItem(Menu, ID_MEMORY_DECOMMIT, FALSE);
|
|
}
|
|
else if (MemoryNodes[0]->MemoryItem->Type & (MEM_MAPPED | MEM_IMAGE))
|
|
{
|
|
PhEnableEMenuItem(Menu, ID_MEMORY_DECOMMIT, FALSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ULONG i;
|
|
ULONG numberOfAllocationBase = 0;
|
|
|
|
PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);
|
|
PhEnableEMenuItem(Menu, ID_MEMORY_COPY, TRUE);
|
|
|
|
for (i = 0; i < NumberOfMemoryNodes; i++)
|
|
{
|
|
if (MemoryNodes[i]->IsAllocationBase)
|
|
numberOfAllocationBase++;
|
|
}
|
|
|
|
if (numberOfAllocationBase == 0 || numberOfAllocationBase == NumberOfMemoryNodes)
|
|
PhEnableEMenuItem(Menu, ID_MEMORY_SAVE, TRUE);
|
|
}
|
|
|
|
PhEnableEMenuItem(Menu, ID_MEMORY_READWRITEADDRESS, TRUE);
|
|
}
|
|
|
|
VOID PhShowMemoryContextMenu(
|
|
_In_ HWND hwndDlg,
|
|
_In_ PPH_PROCESS_ITEM ProcessItem,
|
|
_In_ PPH_MEMORY_CONTEXT Context,
|
|
_In_ PPH_TREENEW_CONTEXT_MENU ContextMenu
|
|
)
|
|
{
|
|
PPH_MEMORY_NODE *memoryNodes;
|
|
ULONG numberOfMemoryNodes;
|
|
|
|
PhGetSelectedMemoryNodes(&Context->ListContext, &memoryNodes, &numberOfMemoryNodes);
|
|
|
|
//if (numberOfMemoryNodes != 0)
|
|
{
|
|
PPH_EMENU menu;
|
|
PPH_EMENU_ITEM item;
|
|
PH_PLUGIN_MENU_INFORMATION menuInfo;
|
|
|
|
menu = PhCreateEMenu();
|
|
PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_MEMORY), 0);
|
|
PhSetFlagsEMenuItem(menu, ID_MEMORY_READWRITEMEMORY, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT);
|
|
|
|
PhpInitializeMemoryMenu(menu, ProcessItem->ProcessId, memoryNodes, numberOfMemoryNodes);
|
|
PhInsertCopyCellEMenuItem(menu, ID_MEMORY_COPY, Context->ListContext.TreeNewHandle, ContextMenu->Column);
|
|
|
|
if (PhPluginsEnabled)
|
|
{
|
|
PhPluginInitializeMenuInfo(&menuInfo, menu, hwndDlg, 0);
|
|
menuInfo.u.Memory.ProcessId = ProcessItem->ProcessId;
|
|
menuInfo.u.Memory.MemoryNodes = memoryNodes;
|
|
menuInfo.u.Memory.NumberOfMemoryNodes = numberOfMemoryNodes;
|
|
|
|
PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMemoryMenuInitializing), &menuInfo);
|
|
}
|
|
|
|
item = PhShowEMenu(
|
|
menu,
|
|
hwndDlg,
|
|
PH_EMENU_SHOW_LEFTRIGHT,
|
|
PH_ALIGN_LEFT | PH_ALIGN_TOP,
|
|
ContextMenu->Location.x,
|
|
ContextMenu->Location.y
|
|
);
|
|
|
|
if (item)
|
|
{
|
|
BOOLEAN handled = FALSE;
|
|
|
|
handled = PhHandleCopyCellEMenuItem(item);
|
|
|
|
if (!handled && PhPluginsEnabled)
|
|
handled = PhPluginTriggerEMenuItem(&menuInfo, item);
|
|
|
|
if (!handled)
|
|
SendMessage(hwndDlg, WM_COMMAND, item->Id, 0);
|
|
}
|
|
|
|
PhDestroyEMenu(menu);
|
|
}
|
|
|
|
PhFree(memoryNodes);
|
|
}
|
|
|
|
INT_PTR CALLBACK PhpProcessMemoryDlgProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
)
|
|
{
|
|
LPPROPSHEETPAGE propSheetPage;
|
|
PPH_PROCESS_PROPPAGECONTEXT propPageContext;
|
|
PPH_PROCESS_ITEM processItem;
|
|
PPH_MEMORY_CONTEXT memoryContext;
|
|
HWND tnHandle;
|
|
|
|
if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam,
|
|
&propSheetPage, &propPageContext, &processItem))
|
|
{
|
|
memoryContext = (PPH_MEMORY_CONTEXT)propPageContext->Context;
|
|
|
|
if (memoryContext)
|
|
tnHandle = memoryContext->ListContext.TreeNewHandle;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
memoryContext = propPageContext->Context =
|
|
PhAllocate(PhEmGetObjectSize(EmMemoryContextType, sizeof(PH_MEMORY_CONTEXT)));
|
|
memset(memoryContext, 0, sizeof(PH_MEMORY_CONTEXT));
|
|
memoryContext->ProcessId = processItem->ProcessId;
|
|
|
|
// Initialize the list.
|
|
tnHandle = GetDlgItem(hwndDlg, IDC_LIST);
|
|
BringWindowToTop(tnHandle);
|
|
PhInitializeMemoryList(hwndDlg, tnHandle, &memoryContext->ListContext);
|
|
TreeNew_SetEmptyText(tnHandle, &LoadingText, 0);
|
|
memoryContext->LastRunStatus = -1;
|
|
memoryContext->ErrorMessage = NULL;
|
|
|
|
PhEmCallObjectOperation(EmMemoryContextType, memoryContext, EmObjectCreate);
|
|
|
|
if (PhPluginsEnabled)
|
|
{
|
|
PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;
|
|
|
|
treeNewInfo.TreeNewHandle = tnHandle;
|
|
treeNewInfo.CmData = &memoryContext->ListContext.Cm;
|
|
treeNewInfo.SystemContext = memoryContext;
|
|
PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMemoryTreeNewInitializing), &treeNewInfo);
|
|
}
|
|
|
|
PhLoadSettingsMemoryList(&memoryContext->ListContext);
|
|
PhSetOptionsMemoryList(&memoryContext->ListContext, TRUE);
|
|
Button_SetCheck(GetDlgItem(hwndDlg, IDC_HIDEFREEREGIONS),
|
|
memoryContext->ListContext.HideFreeRegions ? BST_CHECKED : BST_UNCHECKED);
|
|
|
|
PhpRefreshProcessMemoryList(hwndDlg, propPageContext);
|
|
}
|
|
break;
|
|
case WM_DESTROY:
|
|
{
|
|
PhEmCallObjectOperation(EmMemoryContextType, memoryContext, EmObjectDelete);
|
|
|
|
if (PhPluginsEnabled)
|
|
{
|
|
PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;
|
|
|
|
treeNewInfo.TreeNewHandle = tnHandle;
|
|
treeNewInfo.CmData = &memoryContext->ListContext.Cm;
|
|
PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackMemoryTreeNewUninitializing), &treeNewInfo);
|
|
}
|
|
|
|
PhSaveSettingsMemoryList(&memoryContext->ListContext);
|
|
PhDeleteMemoryList(&memoryContext->ListContext);
|
|
|
|
if (memoryContext->MemoryItemListValid)
|
|
PhDeleteMemoryItemList(&memoryContext->MemoryItemList);
|
|
|
|
PhClearReference(&memoryContext->ErrorMessage);
|
|
PhFree(memoryContext);
|
|
|
|
PhpPropPageDlgProcDestroy(hwndDlg);
|
|
}
|
|
break;
|
|
case WM_SHOWWINDOW:
|
|
{
|
|
if (!propPageContext->LayoutInitialized)
|
|
{
|
|
PPH_LAYOUT_ITEM dialogItem;
|
|
|
|
dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg,
|
|
PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_STRINGS),
|
|
dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_REFRESH),
|
|
dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
|
PhAddPropPageLayoutItem(hwndDlg, memoryContext->ListContext.TreeNewHandle,
|
|
dialogItem, PH_ANCHOR_ALL);
|
|
|
|
PhDoPropPageLayout(hwndDlg);
|
|
|
|
propPageContext->LayoutInitialized = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
case WM_COMMAND:
|
|
{
|
|
switch (LOWORD(wParam))
|
|
{
|
|
case ID_SHOWCONTEXTMENU:
|
|
{
|
|
PhShowMemoryContextMenu(hwndDlg, processItem, memoryContext, (PPH_TREENEW_CONTEXT_MENU)lParam);
|
|
}
|
|
break;
|
|
case ID_MEMORY_READWRITEMEMORY:
|
|
{
|
|
PPH_MEMORY_NODE memoryNode = PhGetSelectedMemoryNode(&memoryContext->ListContext);
|
|
|
|
if (memoryNode && !memoryNode->IsAllocationBase)
|
|
{
|
|
if (memoryNode->MemoryItem->State & MEM_COMMIT)
|
|
{
|
|
PPH_SHOWMEMORYEDITOR showMemoryEditor = PhAllocate(sizeof(PH_SHOWMEMORYEDITOR));
|
|
|
|
memset(showMemoryEditor, 0, sizeof(PH_SHOWMEMORYEDITOR));
|
|
showMemoryEditor->ProcessId = processItem->ProcessId;
|
|
showMemoryEditor->BaseAddress = memoryNode->MemoryItem->BaseAddress;
|
|
showMemoryEditor->RegionSize = memoryNode->MemoryItem->RegionSize;
|
|
showMemoryEditor->SelectOffset = -1;
|
|
showMemoryEditor->SelectLength = 0;
|
|
ProcessHacker_ShowMemoryEditor(PhMainWndHandle, showMemoryEditor);
|
|
}
|
|
else
|
|
{
|
|
PhShowError(hwndDlg, L"Unable to edit the memory region because it is not committed.");
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case ID_MEMORY_SAVE:
|
|
{
|
|
NTSTATUS status;
|
|
HANDLE processHandle;
|
|
PPH_MEMORY_NODE *memoryNodes;
|
|
ULONG numberOfMemoryNodes;
|
|
|
|
if (!NT_SUCCESS(status = PhOpenProcess(
|
|
&processHandle,
|
|
PROCESS_VM_READ,
|
|
processItem->ProcessId
|
|
)))
|
|
{
|
|
PhShowStatus(hwndDlg, L"Unable to open the process", status, 0);
|
|
break;
|
|
}
|
|
|
|
PhGetSelectedMemoryNodes(&memoryContext->ListContext, &memoryNodes, &numberOfMemoryNodes);
|
|
|
|
if (numberOfMemoryNodes != 0)
|
|
{
|
|
static PH_FILETYPE_FILTER filters[] =
|
|
{
|
|
{ L"Binary files (*.bin)", L"*.bin" },
|
|
{ L"All files (*.*)", L"*.*" }
|
|
};
|
|
PVOID fileDialog;
|
|
|
|
fileDialog = PhCreateSaveFileDialog();
|
|
|
|
PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER));
|
|
PhSetFileDialogFileName(fileDialog, PhaConcatStrings2(processItem->ProcessName->Buffer, L".bin")->Buffer);
|
|
|
|
if (PhShowFileDialog(hwndDlg, fileDialog))
|
|
{
|
|
PPH_STRING fileName;
|
|
PPH_FILE_STREAM fileStream;
|
|
PVOID buffer;
|
|
ULONG i;
|
|
ULONG_PTR offset;
|
|
|
|
fileName = PhGetFileDialogFileName(fileDialog);
|
|
PhAutoDereferenceObject(fileName);
|
|
|
|
if (NT_SUCCESS(status = PhCreateFileStream(
|
|
&fileStream,
|
|
fileName->Buffer,
|
|
FILE_GENERIC_WRITE,
|
|
FILE_SHARE_READ,
|
|
FILE_OVERWRITE_IF,
|
|
0
|
|
)))
|
|
{
|
|
buffer = PhAllocatePage(PAGE_SIZE, NULL);
|
|
|
|
// Go through each selected memory item and append the region contents
|
|
// to the file.
|
|
for (i = 0; i < numberOfMemoryNodes; i++)
|
|
{
|
|
PPH_MEMORY_NODE memoryNode = memoryNodes[i];
|
|
PPH_MEMORY_ITEM memoryItem = memoryNode->MemoryItem;
|
|
|
|
if (!memoryNode->IsAllocationBase && !(memoryItem->State & MEM_COMMIT))
|
|
continue;
|
|
|
|
for (offset = 0; offset < memoryItem->RegionSize; offset += PAGE_SIZE)
|
|
{
|
|
if (NT_SUCCESS(PhReadVirtualMemory(
|
|
processHandle,
|
|
PTR_ADD_OFFSET(memoryItem->BaseAddress, offset),
|
|
buffer,
|
|
PAGE_SIZE,
|
|
NULL
|
|
)))
|
|
{
|
|
PhWriteFileStream(fileStream, buffer, PAGE_SIZE);
|
|
}
|
|
}
|
|
}
|
|
|
|
PhFreePage(buffer);
|
|
|
|
PhDereferenceObject(fileStream);
|
|
}
|
|
|
|
if (!NT_SUCCESS(status))
|
|
PhShowStatus(hwndDlg, L"Unable to create the file", status, 0);
|
|
}
|
|
|
|
PhFreeFileDialog(fileDialog);
|
|
}
|
|
|
|
PhFree(memoryNodes);
|
|
NtClose(processHandle);
|
|
}
|
|
break;
|
|
case ID_MEMORY_CHANGEPROTECTION:
|
|
{
|
|
PPH_MEMORY_NODE memoryNode = PhGetSelectedMemoryNode(&memoryContext->ListContext);
|
|
|
|
if (memoryNode)
|
|
{
|
|
PhReferenceObject(memoryNode->MemoryItem);
|
|
|
|
PhShowMemoryProtectDialog(hwndDlg, processItem, memoryNode->MemoryItem);
|
|
PhUpdateMemoryNode(&memoryContext->ListContext, memoryNode);
|
|
|
|
PhDereferenceObject(memoryNode->MemoryItem);
|
|
}
|
|
}
|
|
break;
|
|
case ID_MEMORY_FREE:
|
|
{
|
|
PPH_MEMORY_NODE memoryNode = PhGetSelectedMemoryNode(&memoryContext->ListContext);
|
|
|
|
if (memoryNode)
|
|
{
|
|
PhReferenceObject(memoryNode->MemoryItem);
|
|
PhUiFreeMemory(hwndDlg, processItem->ProcessId, memoryNode->MemoryItem, TRUE);
|
|
PhDereferenceObject(memoryNode->MemoryItem);
|
|
// TODO: somehow update the list
|
|
}
|
|
}
|
|
break;
|
|
case ID_MEMORY_DECOMMIT:
|
|
{
|
|
PPH_MEMORY_NODE memoryNode = PhGetSelectedMemoryNode(&memoryContext->ListContext);
|
|
|
|
if (memoryNode)
|
|
{
|
|
PhReferenceObject(memoryNode->MemoryItem);
|
|
PhUiFreeMemory(hwndDlg, processItem->ProcessId, memoryNode->MemoryItem, FALSE);
|
|
PhDereferenceObject(memoryNode->MemoryItem);
|
|
}
|
|
}
|
|
break;
|
|
case ID_MEMORY_READWRITEADDRESS:
|
|
{
|
|
PPH_STRING selectedChoice = NULL;
|
|
|
|
if (!memoryContext->MemoryItemListValid)
|
|
break;
|
|
|
|
while (PhaChoiceDialog(
|
|
hwndDlg,
|
|
L"Read/Write Address",
|
|
L"Enter an address:",
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
PH_CHOICE_DIALOG_USER_CHOICE,
|
|
&selectedChoice,
|
|
NULL,
|
|
L"MemoryReadWriteAddressChoices"
|
|
))
|
|
{
|
|
ULONG64 address64;
|
|
PVOID address;
|
|
|
|
if (selectedChoice->Length == 0)
|
|
continue;
|
|
|
|
if (PhStringToInteger64(&selectedChoice->sr, 0, &address64))
|
|
{
|
|
PPH_MEMORY_ITEM memoryItem;
|
|
|
|
address = (PVOID)address64;
|
|
memoryItem = PhLookupMemoryItemList(&memoryContext->MemoryItemList, address);
|
|
|
|
if (memoryItem)
|
|
{
|
|
PPH_SHOWMEMORYEDITOR showMemoryEditor = PhAllocate(sizeof(PH_SHOWMEMORYEDITOR));
|
|
|
|
memset(showMemoryEditor, 0, sizeof(PH_SHOWMEMORYEDITOR));
|
|
showMemoryEditor->ProcessId = processItem->ProcessId;
|
|
showMemoryEditor->BaseAddress = memoryItem->BaseAddress;
|
|
showMemoryEditor->RegionSize = memoryItem->RegionSize;
|
|
showMemoryEditor->SelectOffset = (ULONG)((ULONG_PTR)address - (ULONG_PTR)memoryItem->BaseAddress);
|
|
showMemoryEditor->SelectLength = 0;
|
|
ProcessHacker_ShowMemoryEditor(PhMainWndHandle, showMemoryEditor);
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
PhShowError(hwndDlg, L"Unable to find the memory region for the selected address.");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case ID_MEMORY_COPY:
|
|
{
|
|
PPH_STRING text;
|
|
|
|
text = PhGetTreeNewText(tnHandle, 0);
|
|
PhSetClipboardString(tnHandle, &text->sr);
|
|
PhDereferenceObject(text);
|
|
}
|
|
break;
|
|
case IDC_HIDEFREEREGIONS:
|
|
{
|
|
BOOLEAN hide;
|
|
|
|
hide = Button_GetCheck(GetDlgItem(hwndDlg, IDC_HIDEFREEREGIONS)) == BST_CHECKED;
|
|
PhSetOptionsMemoryList(&memoryContext->ListContext, hide);
|
|
}
|
|
break;
|
|
case IDC_STRINGS:
|
|
PhShowMemoryStringDialog(hwndDlg, processItem);
|
|
break;
|
|
case IDC_REFRESH:
|
|
PhpRefreshProcessMemoryList(hwndDlg, propPageContext);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
INT_PTR CALLBACK PhpProcessEnvironmentDlgProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
)
|
|
{
|
|
LPPROPSHEETPAGE propSheetPage;
|
|
PPH_PROCESS_PROPPAGECONTEXT propPageContext;
|
|
PPH_PROCESS_ITEM processItem;
|
|
|
|
if (!PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam,
|
|
&propSheetPage, &propPageContext, &processItem))
|
|
return FALSE;
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
HANDLE processHandle;
|
|
PVOID environment;
|
|
ULONG environmentLength;
|
|
ULONG enumerationKey;
|
|
PH_ENVIRONMENT_VARIABLE variable;
|
|
HWND lvHandle = GetDlgItem(hwndDlg, IDC_LIST);
|
|
|
|
PhSetListViewStyle(lvHandle, TRUE, TRUE);
|
|
PhSetControlTheme(lvHandle, L"explorer");
|
|
PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 140, L"Name");
|
|
PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 200, L"Value");
|
|
|
|
PhSetExtendedListView(lvHandle);
|
|
PhLoadListViewColumnsFromSetting(L"EnvironmentListViewColumns", lvHandle);
|
|
|
|
if (NT_SUCCESS(PhOpenProcess(
|
|
&processHandle,
|
|
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
|
|
processItem->ProcessId
|
|
)))
|
|
{
|
|
ULONG flags;
|
|
|
|
flags = 0;
|
|
|
|
#ifdef _WIN64
|
|
if (processItem->IsWow64)
|
|
flags |= PH_GET_PROCESS_ENVIRONMENT_WOW64;
|
|
#endif
|
|
|
|
if (NT_SUCCESS(PhGetProcessEnvironment(
|
|
processHandle,
|
|
flags,
|
|
&environment,
|
|
&environmentLength
|
|
)))
|
|
{
|
|
enumerationKey = 0;
|
|
|
|
while (PhEnumProcessEnvironmentVariables(environment, environmentLength, &enumerationKey, &variable))
|
|
{
|
|
INT lvItemIndex;
|
|
PPH_STRING nameString;
|
|
PPH_STRING valueString;
|
|
|
|
// Don't display pairs with no name.
|
|
if (variable.Name.Length == 0)
|
|
continue;
|
|
|
|
// The strings are not guaranteed to be null-terminated, so we need to create some temporary strings.
|
|
nameString = PhCreateString2(&variable.Name);
|
|
valueString = PhCreateString2(&variable.Value);
|
|
|
|
lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, nameString->Buffer, NULL);
|
|
PhSetListViewSubItem(lvHandle, lvItemIndex, 1, valueString->Buffer);
|
|
|
|
PhDereferenceObject(nameString);
|
|
PhDereferenceObject(valueString);
|
|
}
|
|
|
|
PhFreePage(environment);
|
|
}
|
|
|
|
NtClose(processHandle);
|
|
}
|
|
}
|
|
break;
|
|
case WM_DESTROY:
|
|
{
|
|
PhSaveListViewColumnsToSetting(L"EnvironmentListViewColumns", GetDlgItem(hwndDlg, IDC_LIST));
|
|
PhpPropPageDlgProcDestroy(hwndDlg);
|
|
}
|
|
break;
|
|
case WM_SHOWWINDOW:
|
|
{
|
|
if (!propPageContext->LayoutInitialized)
|
|
{
|
|
PPH_LAYOUT_ITEM dialogItem;
|
|
|
|
dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg,
|
|
PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST),
|
|
dialogItem, PH_ANCHOR_ALL);
|
|
|
|
PhDoPropPageLayout(hwndDlg);
|
|
|
|
propPageContext->LayoutInitialized = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
case WM_NOTIFY:
|
|
{
|
|
PhHandleListViewNotifyBehaviors(lParam, GetDlgItem(hwndDlg, IDC_LIST), PH_LIST_VIEW_DEFAULT_1_BEHAVIORS);
|
|
}
|
|
break;
|
|
case WM_CTLCOLORDLG:
|
|
{
|
|
return (INT_PTR)GetSysColorBrush(COLOR_WINDOW);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static VOID NTAPI HandleAddedHandler(
|
|
_In_opt_ PVOID Parameter,
|
|
_In_opt_ PVOID Context
|
|
)
|
|
{
|
|
PPH_HANDLES_CONTEXT handlesContext = (PPH_HANDLES_CONTEXT)Context;
|
|
|
|
// Parameter contains a pointer to the added handle item.
|
|
PhReferenceObject(Parameter);
|
|
PostMessage(
|
|
handlesContext->WindowHandle,
|
|
WM_PH_HANDLE_ADDED,
|
|
PhGetRunIdProvider(&handlesContext->ProviderRegistration),
|
|
(LPARAM)Parameter
|
|
);
|
|
}
|
|
|
|
static VOID NTAPI HandleModifiedHandler(
|
|
_In_opt_ PVOID Parameter,
|
|
_In_opt_ PVOID Context
|
|
)
|
|
{
|
|
PPH_HANDLES_CONTEXT handlesContext = (PPH_HANDLES_CONTEXT)Context;
|
|
|
|
PostMessage(handlesContext->WindowHandle, WM_PH_HANDLE_MODIFIED, 0, (LPARAM)Parameter);
|
|
}
|
|
|
|
static VOID NTAPI HandleRemovedHandler(
|
|
_In_opt_ PVOID Parameter,
|
|
_In_opt_ PVOID Context
|
|
)
|
|
{
|
|
PPH_HANDLES_CONTEXT handlesContext = (PPH_HANDLES_CONTEXT)Context;
|
|
|
|
PostMessage(handlesContext->WindowHandle, WM_PH_HANDLE_REMOVED, 0, (LPARAM)Parameter);
|
|
}
|
|
|
|
static VOID NTAPI HandlesUpdatedHandler(
|
|
_In_opt_ PVOID Parameter,
|
|
_In_opt_ PVOID Context
|
|
)
|
|
{
|
|
PPH_HANDLES_CONTEXT handlesContext = (PPH_HANDLES_CONTEXT)Context;
|
|
|
|
PostMessage(handlesContext->WindowHandle, WM_PH_HANDLES_UPDATED, 0, 0);
|
|
}
|
|
|
|
static NTSTATUS PhpDuplicateHandleFromProcessItem(
|
|
_Out_ PHANDLE NewHandle,
|
|
_In_ ACCESS_MASK DesiredAccess,
|
|
_In_ HANDLE ProcessId,
|
|
_In_ HANDLE Handle
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
HANDLE processHandle;
|
|
|
|
if (!NT_SUCCESS(status = PhOpenProcess(
|
|
&processHandle,
|
|
PROCESS_DUP_HANDLE,
|
|
ProcessId
|
|
)))
|
|
return status;
|
|
|
|
status = PhDuplicateObject(
|
|
processHandle,
|
|
Handle,
|
|
NtCurrentProcess(),
|
|
NewHandle,
|
|
DesiredAccess,
|
|
0,
|
|
0
|
|
);
|
|
NtClose(processHandle);
|
|
|
|
return status;
|
|
}
|
|
|
|
static VOID PhpShowProcessPropContext(
|
|
_In_ PVOID Parameter
|
|
)
|
|
{
|
|
PhShowProcessProperties(Parameter);
|
|
PhDereferenceObject(Parameter);
|
|
}
|
|
|
|
VOID PhInsertHandleObjectPropertiesEMenuItems(
|
|
_In_ struct _PH_EMENU_ITEM *Menu,
|
|
_In_ ULONG InsertBeforeId,
|
|
_In_ BOOLEAN EnableShortcut,
|
|
_In_ PPH_HANDLE_ITEM_INFO Info
|
|
)
|
|
{
|
|
PPH_EMENU_ITEM parentItem;
|
|
ULONG indexInParent;
|
|
|
|
if (!PhFindEMenuItemEx(Menu, 0, NULL, InsertBeforeId, &parentItem, &indexInParent))
|
|
return;
|
|
|
|
if (PhEqualString2(Info->TypeName, L"File", TRUE) || PhEqualString2(Info->TypeName, L"DLL", TRUE) ||
|
|
PhEqualString2(Info->TypeName, L"Mapped File", TRUE) || PhEqualString2(Info->TypeName, L"Mapped Image", TRUE))
|
|
{
|
|
if (PhEqualString2(Info->TypeName, L"File", TRUE))
|
|
PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES2, L"File Properties", NULL, NULL), indexInParent);
|
|
|
|
PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES1, PhaAppendCtrlEnter(L"Open &File Location", EnableShortcut), NULL, NULL), indexInParent);
|
|
}
|
|
else if (PhEqualString2(Info->TypeName, L"Key", TRUE))
|
|
{
|
|
PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES1, PhaAppendCtrlEnter(L"Open Key", EnableShortcut), NULL, NULL), indexInParent);
|
|
}
|
|
else if (PhEqualString2(Info->TypeName, L"Process", TRUE))
|
|
{
|
|
PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES1, PhaAppendCtrlEnter(L"Process Properties", EnableShortcut), NULL, NULL), indexInParent);
|
|
}
|
|
else if (PhEqualString2(Info->TypeName, L"Section", TRUE))
|
|
{
|
|
PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES1, PhaAppendCtrlEnter(L"Read/Write Memory", EnableShortcut), NULL, NULL), indexInParent);
|
|
}
|
|
else if (PhEqualString2(Info->TypeName, L"Thread", TRUE))
|
|
{
|
|
PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES1, PhaAppendCtrlEnter(L"Go to Thread", EnableShortcut), NULL, NULL), indexInParent);
|
|
}
|
|
}
|
|
|
|
VOID PhShowHandleObjectProperties1(
|
|
_In_ HWND hWnd,
|
|
_In_ PPH_HANDLE_ITEM_INFO Info
|
|
)
|
|
{
|
|
if (PhEqualString2(Info->TypeName, L"File", TRUE) || PhEqualString2(Info->TypeName, L"DLL", TRUE) ||
|
|
PhEqualString2(Info->TypeName, L"Mapped File", TRUE) || PhEqualString2(Info->TypeName, L"Mapped Image", TRUE))
|
|
{
|
|
if (Info->BestObjectName)
|
|
PhShellExploreFile(hWnd, Info->BestObjectName->Buffer);
|
|
else
|
|
PhShowError(hWnd, L"Unable to open file location because the object is unnamed.");
|
|
}
|
|
else if (PhEqualString2(Info->TypeName, L"Key", TRUE))
|
|
{
|
|
if (Info->BestObjectName)
|
|
PhShellOpenKey2(hWnd, Info->BestObjectName);
|
|
else
|
|
PhShowError(hWnd, L"Unable to open key because the object is unnamed.");
|
|
}
|
|
else if (PhEqualString2(Info->TypeName, L"Process", TRUE))
|
|
{
|
|
HANDLE processHandle;
|
|
HANDLE processId;
|
|
PPH_PROCESS_ITEM targetProcessItem;
|
|
|
|
processId = NULL;
|
|
|
|
if (KphIsConnected())
|
|
{
|
|
if (NT_SUCCESS(PhOpenProcess(
|
|
&processHandle,
|
|
ProcessQueryAccess,
|
|
Info->ProcessId
|
|
)))
|
|
{
|
|
PROCESS_BASIC_INFORMATION basicInfo;
|
|
|
|
if (NT_SUCCESS(KphQueryInformationObject(
|
|
processHandle,
|
|
Info->Handle,
|
|
KphObjectProcessBasicInformation,
|
|
&basicInfo,
|
|
sizeof(PROCESS_BASIC_INFORMATION),
|
|
NULL
|
|
)))
|
|
{
|
|
processId = basicInfo.UniqueProcessId;
|
|
}
|
|
|
|
NtClose(processHandle);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
HANDLE handle;
|
|
PROCESS_BASIC_INFORMATION basicInfo;
|
|
|
|
if (NT_SUCCESS(PhpDuplicateHandleFromProcessItem(
|
|
&handle,
|
|
ProcessQueryAccess,
|
|
Info->ProcessId,
|
|
Info->Handle
|
|
)))
|
|
{
|
|
if (NT_SUCCESS(PhGetProcessBasicInformation(handle, &basicInfo)))
|
|
processId = basicInfo.UniqueProcessId;
|
|
|
|
NtClose(handle);
|
|
}
|
|
}
|
|
|
|
if (processId)
|
|
{
|
|
targetProcessItem = PhReferenceProcessItem(processId);
|
|
|
|
if (targetProcessItem)
|
|
{
|
|
ProcessHacker_ShowProcessProperties(PhMainWndHandle, targetProcessItem);
|
|
PhDereferenceObject(targetProcessItem);
|
|
}
|
|
else
|
|
{
|
|
PhShowError(hWnd, L"The process does not exist.");
|
|
}
|
|
}
|
|
}
|
|
else if (PhEqualString2(Info->TypeName, L"Section", TRUE))
|
|
{
|
|
HANDLE handle = NULL;
|
|
BOOLEAN readOnly = FALSE;
|
|
|
|
if (!NT_SUCCESS(PhpDuplicateHandleFromProcessItem(
|
|
&handle,
|
|
SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_WRITE,
|
|
Info->ProcessId,
|
|
Info->Handle
|
|
)))
|
|
{
|
|
PhpDuplicateHandleFromProcessItem(
|
|
&handle,
|
|
SECTION_QUERY | SECTION_MAP_READ,
|
|
Info->ProcessId,
|
|
Info->Handle
|
|
);
|
|
readOnly = TRUE;
|
|
}
|
|
|
|
if (handle)
|
|
{
|
|
NTSTATUS status;
|
|
PPH_STRING sectionName = NULL;
|
|
SECTION_BASIC_INFORMATION basicInfo;
|
|
SIZE_T viewSize = PH_MAX_SECTION_EDIT_SIZE;
|
|
PVOID viewBase = NULL;
|
|
BOOLEAN tooBig = FALSE;
|
|
|
|
PhGetHandleInformation(NtCurrentProcess(), handle, -1, NULL, NULL, NULL, §ionName);
|
|
|
|
if (NT_SUCCESS(PhGetSectionBasicInformation(handle, &basicInfo)))
|
|
{
|
|
if (basicInfo.MaximumSize.QuadPart <= PH_MAX_SECTION_EDIT_SIZE)
|
|
viewSize = (SIZE_T)basicInfo.MaximumSize.QuadPart;
|
|
else
|
|
tooBig = TRUE;
|
|
|
|
status = NtMapViewOfSection(
|
|
handle,
|
|
NtCurrentProcess(),
|
|
&viewBase,
|
|
0,
|
|
0,
|
|
NULL,
|
|
&viewSize,
|
|
ViewShare,
|
|
0,
|
|
readOnly ? PAGE_READONLY : PAGE_READWRITE
|
|
);
|
|
|
|
if (status == STATUS_SECTION_PROTECTION && !readOnly)
|
|
{
|
|
status = NtMapViewOfSection(
|
|
handle,
|
|
NtCurrentProcess(),
|
|
&viewBase,
|
|
0,
|
|
0,
|
|
NULL,
|
|
&viewSize,
|
|
ViewShare,
|
|
0,
|
|
PAGE_READONLY
|
|
);
|
|
}
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
PPH_SHOWMEMORYEDITOR showMemoryEditor = PhAllocate(sizeof(PH_SHOWMEMORYEDITOR));
|
|
|
|
if (tooBig)
|
|
PhShowWarning(hWnd, L"The section size is greater than 32 MB. Only the first 32 MB will be available for editing.");
|
|
|
|
memset(showMemoryEditor, 0, sizeof(PH_SHOWMEMORYEDITOR));
|
|
showMemoryEditor->ProcessId = NtCurrentProcessId();
|
|
showMemoryEditor->BaseAddress = viewBase;
|
|
showMemoryEditor->RegionSize = viewSize;
|
|
showMemoryEditor->SelectOffset = -1;
|
|
showMemoryEditor->SelectLength = 0;
|
|
showMemoryEditor->Title = sectionName ? PhConcatStrings2(L"Section - ", sectionName->Buffer) : PhCreateString(L"Section");
|
|
showMemoryEditor->Flags = PH_MEMORY_EDITOR_UNMAP_VIEW_OF_SECTION;
|
|
ProcessHacker_ShowMemoryEditor(PhMainWndHandle, showMemoryEditor);
|
|
}
|
|
else
|
|
{
|
|
PhShowStatus(hWnd, L"Unable to map a view of the section", status, 0);
|
|
}
|
|
}
|
|
|
|
PhClearReference(§ionName);
|
|
|
|
NtClose(handle);
|
|
}
|
|
}
|
|
else if (PhEqualString2(Info->TypeName, L"Thread", TRUE))
|
|
{
|
|
HANDLE processHandle;
|
|
CLIENT_ID clientId;
|
|
PPH_PROCESS_ITEM targetProcessItem;
|
|
PPH_PROCESS_PROPCONTEXT propContext;
|
|
|
|
clientId.UniqueProcess = NULL;
|
|
clientId.UniqueThread = NULL;
|
|
|
|
if (KphIsConnected())
|
|
{
|
|
if (NT_SUCCESS(PhOpenProcess(
|
|
&processHandle,
|
|
ProcessQueryAccess,
|
|
Info->ProcessId
|
|
)))
|
|
{
|
|
THREAD_BASIC_INFORMATION basicInfo;
|
|
|
|
if (NT_SUCCESS(KphQueryInformationObject(
|
|
processHandle,
|
|
Info->Handle,
|
|
KphObjectThreadBasicInformation,
|
|
&basicInfo,
|
|
sizeof(THREAD_BASIC_INFORMATION),
|
|
NULL
|
|
)))
|
|
{
|
|
clientId = basicInfo.ClientId;
|
|
}
|
|
|
|
NtClose(processHandle);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
HANDLE handle;
|
|
THREAD_BASIC_INFORMATION basicInfo;
|
|
|
|
if (NT_SUCCESS(PhpDuplicateHandleFromProcessItem(
|
|
&handle,
|
|
ThreadQueryAccess,
|
|
Info->ProcessId,
|
|
Info->Handle
|
|
)))
|
|
{
|
|
if (NT_SUCCESS(PhGetThreadBasicInformation(handle, &basicInfo)))
|
|
clientId = basicInfo.ClientId;
|
|
|
|
NtClose(handle);
|
|
}
|
|
}
|
|
|
|
if (clientId.UniqueProcess)
|
|
{
|
|
targetProcessItem = PhReferenceProcessItem(clientId.UniqueProcess);
|
|
|
|
if (targetProcessItem)
|
|
{
|
|
propContext = PhCreateProcessPropContext(PhMainWndHandle, targetProcessItem);
|
|
PhDereferenceObject(targetProcessItem);
|
|
PhSetSelectThreadIdProcessPropContext(propContext, clientId.UniqueThread);
|
|
ProcessHacker_Invoke(PhMainWndHandle, PhpShowProcessPropContext, propContext);
|
|
}
|
|
else
|
|
{
|
|
PhShowError(hWnd, L"The process does not exist.");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID PhShowHandleObjectProperties2(
|
|
_In_ HWND hWnd,
|
|
_In_ PPH_HANDLE_ITEM_INFO Info
|
|
)
|
|
{
|
|
if (PhEqualString2(Info->TypeName, L"File", TRUE) || PhEqualString2(Info->TypeName, L"DLL", TRUE) ||
|
|
PhEqualString2(Info->TypeName, L"Mapped File", TRUE) || PhEqualString2(Info->TypeName, L"Mapped Image", TRUE))
|
|
{
|
|
if (Info->BestObjectName)
|
|
PhShellProperties(hWnd, Info->BestObjectName->Buffer);
|
|
else
|
|
PhShowError(hWnd, L"Unable to open file properties because the object is unnamed.");
|
|
}
|
|
}
|
|
|
|
VOID PhpInitializeHandleMenu(
|
|
_In_ PPH_EMENU Menu,
|
|
_In_ HANDLE ProcessId,
|
|
_In_ PPH_HANDLE_ITEM *Handles,
|
|
_In_ ULONG NumberOfHandles,
|
|
_Inout_ PPH_HANDLES_CONTEXT HandlesContext
|
|
)
|
|
{
|
|
PPH_EMENU_ITEM item;
|
|
|
|
if (NumberOfHandles == 0)
|
|
{
|
|
PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);
|
|
}
|
|
else if (NumberOfHandles == 1)
|
|
{
|
|
PH_HANDLE_ITEM_INFO info;
|
|
|
|
info.ProcessId = ProcessId;
|
|
info.Handle = Handles[0]->Handle;
|
|
info.TypeName = Handles[0]->TypeName;
|
|
info.BestObjectName = Handles[0]->BestObjectName;
|
|
PhInsertHandleObjectPropertiesEMenuItems(Menu, ID_HANDLE_COPY, TRUE, &info);
|
|
}
|
|
else
|
|
{
|
|
PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);
|
|
|
|
PhEnableEMenuItem(Menu, ID_HANDLE_CLOSE, TRUE);
|
|
PhEnableEMenuItem(Menu, ID_HANDLE_COPY, TRUE);
|
|
}
|
|
|
|
// Remove irrelevant menu items.
|
|
|
|
if (!KphIsConnected())
|
|
{
|
|
if (item = PhFindEMenuItem(Menu, 0, NULL, ID_HANDLE_PROTECTED))
|
|
PhDestroyEMenuItem(item);
|
|
if (item = PhFindEMenuItem(Menu, 0, NULL, ID_HANDLE_INHERIT))
|
|
PhDestroyEMenuItem(item);
|
|
}
|
|
|
|
// Protected, Inherit
|
|
if (NumberOfHandles == 1 && KphIsConnected())
|
|
{
|
|
HandlesContext->SelectedHandleProtected = FALSE;
|
|
HandlesContext->SelectedHandleInherit = FALSE;
|
|
|
|
if (Handles[0]->Attributes & OBJ_PROTECT_CLOSE)
|
|
{
|
|
HandlesContext->SelectedHandleProtected = TRUE;
|
|
PhSetFlagsEMenuItem(Menu, ID_HANDLE_PROTECTED, PH_EMENU_CHECKED, PH_EMENU_CHECKED);
|
|
}
|
|
|
|
if (Handles[0]->Attributes & OBJ_INHERIT)
|
|
{
|
|
HandlesContext->SelectedHandleInherit = TRUE;
|
|
PhSetFlagsEMenuItem(Menu, ID_HANDLE_INHERIT, PH_EMENU_CHECKED, PH_EMENU_CHECKED);
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID PhShowHandleContextMenu(
|
|
_In_ HWND hwndDlg,
|
|
_In_ PPH_PROCESS_ITEM ProcessItem,
|
|
_In_ PPH_HANDLES_CONTEXT Context,
|
|
_In_ PPH_TREENEW_CONTEXT_MENU ContextMenu
|
|
)
|
|
{
|
|
PPH_HANDLE_ITEM *handles;
|
|
ULONG numberOfHandles;
|
|
|
|
PhGetSelectedHandleItems(&Context->ListContext, &handles, &numberOfHandles);
|
|
|
|
if (numberOfHandles != 0)
|
|
{
|
|
PPH_EMENU menu;
|
|
PPH_EMENU_ITEM item;
|
|
PH_PLUGIN_MENU_INFORMATION menuInfo;
|
|
|
|
menu = PhCreateEMenu();
|
|
PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_HANDLE), 0);
|
|
PhSetFlagsEMenuItem(menu, ID_HANDLE_PROPERTIES, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT);
|
|
|
|
PhpInitializeHandleMenu(menu, ProcessItem->ProcessId, handles, numberOfHandles, Context);
|
|
PhInsertCopyCellEMenuItem(menu, ID_HANDLE_COPY, Context->ListContext.TreeNewHandle, ContextMenu->Column);
|
|
|
|
if (PhPluginsEnabled)
|
|
{
|
|
PhPluginInitializeMenuInfo(&menuInfo, menu, hwndDlg, 0);
|
|
menuInfo.u.Handle.ProcessId = ProcessItem->ProcessId;
|
|
menuInfo.u.Handle.Handles = handles;
|
|
menuInfo.u.Handle.NumberOfHandles = numberOfHandles;
|
|
|
|
PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackHandleMenuInitializing), &menuInfo);
|
|
}
|
|
|
|
item = PhShowEMenu(
|
|
menu,
|
|
hwndDlg,
|
|
PH_EMENU_SHOW_LEFTRIGHT,
|
|
PH_ALIGN_LEFT | PH_ALIGN_TOP,
|
|
ContextMenu->Location.x,
|
|
ContextMenu->Location.y
|
|
);
|
|
|
|
if (item)
|
|
{
|
|
BOOLEAN handled = FALSE;
|
|
|
|
handled = PhHandleCopyCellEMenuItem(item);
|
|
|
|
if (!handled && PhPluginsEnabled)
|
|
handled = PhPluginTriggerEMenuItem(&menuInfo, item);
|
|
|
|
if (!handled)
|
|
SendMessage(hwndDlg, WM_COMMAND, item->Id, 0);
|
|
}
|
|
|
|
PhDestroyEMenu(menu);
|
|
}
|
|
|
|
PhFree(handles);
|
|
}
|
|
|
|
INT_PTR CALLBACK PhpProcessHandlesDlgProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
)
|
|
{
|
|
LPPROPSHEETPAGE propSheetPage;
|
|
PPH_PROCESS_PROPPAGECONTEXT propPageContext;
|
|
PPH_PROCESS_ITEM processItem;
|
|
PPH_HANDLES_CONTEXT handlesContext;
|
|
HWND tnHandle;
|
|
|
|
if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam,
|
|
&propSheetPage, &propPageContext, &processItem))
|
|
{
|
|
handlesContext = (PPH_HANDLES_CONTEXT)propPageContext->Context;
|
|
|
|
if (handlesContext)
|
|
tnHandle = handlesContext->ListContext.TreeNewHandle;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
handlesContext = propPageContext->Context =
|
|
PhAllocate(PhEmGetObjectSize(EmHandlesContextType, sizeof(PH_HANDLES_CONTEXT)));
|
|
|
|
handlesContext->Provider = PhCreateHandleProvider(
|
|
processItem->ProcessId
|
|
);
|
|
PhRegisterProvider(
|
|
&PhSecondaryProviderThread,
|
|
PhHandleProviderUpdate,
|
|
handlesContext->Provider,
|
|
&handlesContext->ProviderRegistration
|
|
);
|
|
PhRegisterCallback(
|
|
&handlesContext->Provider->HandleAddedEvent,
|
|
HandleAddedHandler,
|
|
handlesContext,
|
|
&handlesContext->AddedEventRegistration
|
|
);
|
|
PhRegisterCallback(
|
|
&handlesContext->Provider->HandleModifiedEvent,
|
|
HandleModifiedHandler,
|
|
handlesContext,
|
|
&handlesContext->ModifiedEventRegistration
|
|
);
|
|
PhRegisterCallback(
|
|
&handlesContext->Provider->HandleRemovedEvent,
|
|
HandleRemovedHandler,
|
|
handlesContext,
|
|
&handlesContext->RemovedEventRegistration
|
|
);
|
|
PhRegisterCallback(
|
|
&handlesContext->Provider->UpdatedEvent,
|
|
HandlesUpdatedHandler,
|
|
handlesContext,
|
|
&handlesContext->UpdatedEventRegistration
|
|
);
|
|
handlesContext->WindowHandle = hwndDlg;
|
|
|
|
// Initialize the list.
|
|
tnHandle = GetDlgItem(hwndDlg, IDC_LIST);
|
|
BringWindowToTop(tnHandle);
|
|
PhInitializeHandleList(hwndDlg, tnHandle, &handlesContext->ListContext);
|
|
TreeNew_SetEmptyText(tnHandle, &LoadingText, 0);
|
|
handlesContext->NeedsRedraw = FALSE;
|
|
handlesContext->LastRunStatus = -1;
|
|
handlesContext->ErrorMessage = NULL;
|
|
|
|
PhEmCallObjectOperation(EmHandlesContextType, handlesContext, EmObjectCreate);
|
|
|
|
if (PhPluginsEnabled)
|
|
{
|
|
PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;
|
|
|
|
treeNewInfo.TreeNewHandle = tnHandle;
|
|
treeNewInfo.CmData = &handlesContext->ListContext.Cm;
|
|
treeNewInfo.SystemContext = handlesContext;
|
|
PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackHandleTreeNewInitializing), &treeNewInfo);
|
|
}
|
|
|
|
PhLoadSettingsHandleList(&handlesContext->ListContext);
|
|
|
|
PhSetOptionsHandleList(&handlesContext->ListContext, !!PhGetIntegerSetting(L"HideUnnamedHandles"));
|
|
Button_SetCheck(GetDlgItem(hwndDlg, IDC_HIDEUNNAMEDHANDLES),
|
|
handlesContext->ListContext.HideUnnamedHandles ? BST_CHECKED : BST_UNCHECKED);
|
|
|
|
PhSetEnabledProvider(&handlesContext->ProviderRegistration, TRUE);
|
|
PhBoostProvider(&handlesContext->ProviderRegistration, NULL);
|
|
}
|
|
break;
|
|
case WM_DESTROY:
|
|
{
|
|
PhEmCallObjectOperation(EmHandlesContextType, handlesContext, EmObjectDelete);
|
|
|
|
PhUnregisterCallback(
|
|
&handlesContext->Provider->HandleAddedEvent,
|
|
&handlesContext->AddedEventRegistration
|
|
);
|
|
PhUnregisterCallback(
|
|
&handlesContext->Provider->HandleModifiedEvent,
|
|
&handlesContext->ModifiedEventRegistration
|
|
);
|
|
PhUnregisterCallback(
|
|
&handlesContext->Provider->HandleRemovedEvent,
|
|
&handlesContext->RemovedEventRegistration
|
|
);
|
|
PhUnregisterCallback(
|
|
&handlesContext->Provider->UpdatedEvent,
|
|
&handlesContext->UpdatedEventRegistration
|
|
);
|
|
PhUnregisterProvider(&handlesContext->ProviderRegistration);
|
|
PhDereferenceObject(handlesContext->Provider);
|
|
|
|
if (PhPluginsEnabled)
|
|
{
|
|
PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;
|
|
|
|
treeNewInfo.TreeNewHandle = tnHandle;
|
|
treeNewInfo.CmData = &handlesContext->ListContext.Cm;
|
|
PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackHandleTreeNewUninitializing), &treeNewInfo);
|
|
}
|
|
|
|
PhSaveSettingsHandleList(&handlesContext->ListContext);
|
|
PhDeleteHandleList(&handlesContext->ListContext);
|
|
|
|
PhFree(handlesContext);
|
|
|
|
PhpPropPageDlgProcDestroy(hwndDlg);
|
|
}
|
|
break;
|
|
case WM_SHOWWINDOW:
|
|
{
|
|
if (!propPageContext->LayoutInitialized)
|
|
{
|
|
PPH_LAYOUT_ITEM dialogItem;
|
|
|
|
dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg,
|
|
PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST),
|
|
dialogItem, PH_ANCHOR_ALL);
|
|
|
|
PhDoPropPageLayout(hwndDlg);
|
|
|
|
propPageContext->LayoutInitialized = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
case WM_COMMAND:
|
|
{
|
|
INT id = LOWORD(wParam);
|
|
|
|
switch (id)
|
|
{
|
|
case ID_SHOWCONTEXTMENU:
|
|
{
|
|
PhShowHandleContextMenu(hwndDlg, processItem, handlesContext, (PPH_TREENEW_CONTEXT_MENU)lParam);
|
|
}
|
|
break;
|
|
case ID_HANDLE_CLOSE:
|
|
{
|
|
PPH_HANDLE_ITEM *handles;
|
|
ULONG numberOfHandles;
|
|
|
|
PhGetSelectedHandleItems(&handlesContext->ListContext, &handles, &numberOfHandles);
|
|
PhReferenceObjects(handles, numberOfHandles);
|
|
|
|
if (PhUiCloseHandles(hwndDlg, processItem->ProcessId, handles, numberOfHandles, !!lParam))
|
|
PhDeselectAllHandleNodes(&handlesContext->ListContext);
|
|
|
|
PhDereferenceObjects(handles, numberOfHandles);
|
|
PhFree(handles);
|
|
}
|
|
break;
|
|
case ID_HANDLE_PROTECTED:
|
|
case ID_HANDLE_INHERIT:
|
|
{
|
|
PPH_HANDLE_ITEM handleItem = PhGetSelectedHandleItem(&handlesContext->ListContext);
|
|
|
|
if (handleItem)
|
|
{
|
|
ULONG attributes = 0;
|
|
|
|
// Re-create the attributes.
|
|
|
|
if (handlesContext->SelectedHandleProtected)
|
|
attributes |= OBJ_PROTECT_CLOSE;
|
|
if (handlesContext->SelectedHandleInherit)
|
|
attributes |= OBJ_INHERIT;
|
|
|
|
// Toggle the appropriate bit.
|
|
|
|
if (id == ID_HANDLE_PROTECTED)
|
|
attributes ^= OBJ_PROTECT_CLOSE;
|
|
else if (id == ID_HANDLE_INHERIT)
|
|
attributes ^= OBJ_INHERIT;
|
|
|
|
PhReferenceObject(handleItem);
|
|
PhUiSetAttributesHandle(hwndDlg, processItem->ProcessId, handleItem, attributes);
|
|
PhDereferenceObject(handleItem);
|
|
}
|
|
}
|
|
break;
|
|
case ID_HANDLE_OBJECTPROPERTIES1:
|
|
case ID_HANDLE_OBJECTPROPERTIES2:
|
|
{
|
|
PPH_HANDLE_ITEM handleItem = PhGetSelectedHandleItem(&handlesContext->ListContext);
|
|
|
|
if (handleItem)
|
|
{
|
|
PH_HANDLE_ITEM_INFO info;
|
|
|
|
info.ProcessId = processItem->ProcessId;
|
|
info.Handle = handleItem->Handle;
|
|
info.TypeName = handleItem->TypeName;
|
|
info.BestObjectName = handleItem->BestObjectName;
|
|
|
|
if (id == ID_HANDLE_OBJECTPROPERTIES1)
|
|
PhShowHandleObjectProperties1(hwndDlg, &info);
|
|
else
|
|
PhShowHandleObjectProperties2(hwndDlg, &info);
|
|
}
|
|
}
|
|
break;
|
|
case ID_HANDLE_PROPERTIES:
|
|
{
|
|
PPH_HANDLE_ITEM handleItem = PhGetSelectedHandleItem(&handlesContext->ListContext);
|
|
|
|
if (handleItem)
|
|
{
|
|
PhReferenceObject(handleItem);
|
|
PhShowHandleProperties(hwndDlg, processItem->ProcessId, handleItem);
|
|
PhDereferenceObject(handleItem);
|
|
}
|
|
}
|
|
break;
|
|
case ID_HANDLE_COPY:
|
|
{
|
|
PPH_STRING text;
|
|
|
|
text = PhGetTreeNewText(tnHandle, 0);
|
|
PhSetClipboardString(tnHandle, &text->sr);
|
|
PhDereferenceObject(text);
|
|
}
|
|
break;
|
|
case IDC_HIDEUNNAMEDHANDLES:
|
|
{
|
|
BOOLEAN hide;
|
|
|
|
hide = Button_GetCheck(GetDlgItem(hwndDlg, IDC_HIDEUNNAMEDHANDLES)) == BST_CHECKED;
|
|
PhSetOptionsHandleList(&handlesContext->ListContext, hide);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case WM_NOTIFY:
|
|
{
|
|
LPNMHDR header = (LPNMHDR)lParam;
|
|
|
|
switch (header->code)
|
|
{
|
|
case PSN_SETACTIVE:
|
|
PhSetEnabledProvider(&handlesContext->ProviderRegistration, TRUE);
|
|
break;
|
|
case PSN_KILLACTIVE:
|
|
PhSetEnabledProvider(&handlesContext->ProviderRegistration, FALSE);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case WM_PH_HANDLE_ADDED:
|
|
{
|
|
ULONG runId = (ULONG)wParam;
|
|
PPH_HANDLE_ITEM handleItem = (PPH_HANDLE_ITEM)lParam;
|
|
|
|
if (!handlesContext->NeedsRedraw)
|
|
{
|
|
TreeNew_SetRedraw(tnHandle, FALSE);
|
|
handlesContext->NeedsRedraw = TRUE;
|
|
}
|
|
|
|
PhAddHandleNode(&handlesContext->ListContext, handleItem, runId);
|
|
PhDereferenceObject(handleItem);
|
|
}
|
|
break;
|
|
case WM_PH_HANDLE_MODIFIED:
|
|
{
|
|
PPH_HANDLE_ITEM handleItem = (PPH_HANDLE_ITEM)lParam;
|
|
|
|
if (!handlesContext->NeedsRedraw)
|
|
{
|
|
TreeNew_SetRedraw(tnHandle, FALSE);
|
|
handlesContext->NeedsRedraw = TRUE;
|
|
}
|
|
|
|
PhUpdateHandleNode(&handlesContext->ListContext, PhFindHandleNode(&handlesContext->ListContext, handleItem->Handle));
|
|
}
|
|
break;
|
|
case WM_PH_HANDLE_REMOVED:
|
|
{
|
|
PPH_HANDLE_ITEM handleItem = (PPH_HANDLE_ITEM)lParam;
|
|
|
|
if (!handlesContext->NeedsRedraw)
|
|
{
|
|
TreeNew_SetRedraw(tnHandle, FALSE);
|
|
handlesContext->NeedsRedraw = TRUE;
|
|
}
|
|
|
|
PhRemoveHandleNode(&handlesContext->ListContext, PhFindHandleNode(&handlesContext->ListContext, handleItem->Handle));
|
|
}
|
|
break;
|
|
case WM_PH_HANDLES_UPDATED:
|
|
{
|
|
PhTickHandleNodes(&handlesContext->ListContext);
|
|
|
|
if (handlesContext->LastRunStatus != handlesContext->Provider->RunStatus)
|
|
{
|
|
NTSTATUS status;
|
|
PPH_STRING message;
|
|
|
|
status = handlesContext->Provider->RunStatus;
|
|
handlesContext->LastRunStatus = status;
|
|
|
|
if (!PH_IS_REAL_PROCESS_ID(processItem->ProcessId))
|
|
status = STATUS_SUCCESS;
|
|
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
TreeNew_SetEmptyText(tnHandle, &EmptyHandlesText, 0);
|
|
}
|
|
else
|
|
{
|
|
message = PhGetStatusMessage(status, 0);
|
|
PhMoveReference(&handlesContext->ErrorMessage, PhFormatString(L"Unable to query handle information:\n%s", PhGetStringOrDefault(message, L"Unknown error.")));
|
|
PhClearReference(&message);
|
|
TreeNew_SetEmptyText(tnHandle, &handlesContext->ErrorMessage->sr, 0);
|
|
}
|
|
|
|
InvalidateRect(tnHandle, NULL, FALSE);
|
|
}
|
|
|
|
if (handlesContext->NeedsRedraw)
|
|
{
|
|
TreeNew_SetRedraw(tnHandle, TRUE);
|
|
handlesContext->NeedsRedraw = FALSE;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static NTSTATUS NTAPI PhpOpenProcessJob(
|
|
_Out_ PHANDLE Handle,
|
|
_In_ ACCESS_MASK DesiredAccess,
|
|
_In_opt_ PVOID Context
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
HANDLE processHandle;
|
|
HANDLE jobHandle = NULL;
|
|
|
|
if (!NT_SUCCESS(status = PhOpenProcess(
|
|
&processHandle,
|
|
ProcessQueryAccess,
|
|
(HANDLE)Context
|
|
)))
|
|
return status;
|
|
|
|
status = KphOpenProcessJob(processHandle, DesiredAccess, &jobHandle);
|
|
NtClose(processHandle);
|
|
|
|
if (NT_SUCCESS(status) && status != STATUS_PROCESS_NOT_IN_JOB && jobHandle)
|
|
{
|
|
*Handle = jobHandle;
|
|
}
|
|
else if (NT_SUCCESS(status))
|
|
{
|
|
status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
INT_PTR CALLBACK PhpProcessJobHookProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_DESTROY:
|
|
{
|
|
RemoveProp(hwndDlg, PhMakeContextAtom());
|
|
}
|
|
break;
|
|
case WM_SHOWWINDOW:
|
|
{
|
|
if (!GetProp(hwndDlg, PhMakeContextAtom())) // LayoutInitialized
|
|
{
|
|
PPH_LAYOUT_ITEM dialogItem;
|
|
|
|
// This is a big violation of abstraction...
|
|
|
|
dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg,
|
|
PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_NAME),
|
|
dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_TERMINATE),
|
|
dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PROCESSES),
|
|
dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_ADD),
|
|
dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIMITS),
|
|
dialogItem, PH_ANCHOR_ALL);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_ADVANCED),
|
|
dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
|
|
|
|
PhDoPropPageLayout(hwndDlg);
|
|
|
|
SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)TRUE);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static VOID PhpLayoutServiceListControl(
|
|
_In_ HWND hwndDlg,
|
|
_In_ HWND ServiceListHandle
|
|
)
|
|
{
|
|
RECT rect;
|
|
|
|
GetWindowRect(GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), &rect);
|
|
MapWindowPoints(NULL, hwndDlg, (POINT *)&rect, 2);
|
|
|
|
MoveWindow(
|
|
ServiceListHandle,
|
|
rect.left,
|
|
rect.top,
|
|
rect.right - rect.left,
|
|
rect.bottom - rect.top,
|
|
TRUE
|
|
);
|
|
}
|
|
|
|
INT_PTR CALLBACK PhpProcessServicesDlgProc(
|
|
_In_ HWND hwndDlg,
|
|
_In_ UINT uMsg,
|
|
_In_ WPARAM wParam,
|
|
_In_ LPARAM lParam
|
|
)
|
|
{
|
|
LPPROPSHEETPAGE propSheetPage;
|
|
PPH_PROCESS_PROPPAGECONTEXT propPageContext;
|
|
PPH_PROCESS_ITEM processItem;
|
|
|
|
if (!PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam,
|
|
&propSheetPage, &propPageContext, &processItem))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
{
|
|
PPH_SERVICE_ITEM *services;
|
|
ULONG numberOfServices;
|
|
ULONG i;
|
|
HWND serviceListHandle;
|
|
|
|
// Get a copy of the process' service list.
|
|
|
|
PhAcquireQueuedLockShared(&processItem->ServiceListLock);
|
|
|
|
numberOfServices = processItem->ServiceList->Count;
|
|
services = PhAllocate(numberOfServices * sizeof(PPH_SERVICE_ITEM));
|
|
|
|
{
|
|
ULONG enumerationKey = 0;
|
|
PPH_SERVICE_ITEM serviceItem;
|
|
|
|
i = 0;
|
|
|
|
while (PhEnumPointerList(processItem->ServiceList, &enumerationKey, &serviceItem))
|
|
{
|
|
PhReferenceObject(serviceItem);
|
|
services[i++] = serviceItem;
|
|
}
|
|
}
|
|
|
|
PhReleaseQueuedLockShared(&processItem->ServiceListLock);
|
|
|
|
serviceListHandle = PhCreateServiceListControl(
|
|
hwndDlg,
|
|
services,
|
|
numberOfServices
|
|
);
|
|
SendMessage(serviceListHandle, WM_PH_SET_LIST_VIEW_SETTINGS, 0, (LPARAM)L"ProcessServiceListViewColumns");
|
|
ShowWindow(serviceListHandle, SW_SHOW);
|
|
|
|
propPageContext->Context = serviceListHandle;
|
|
}
|
|
break;
|
|
case WM_DESTROY:
|
|
{
|
|
PhpPropPageDlgProcDestroy(hwndDlg);
|
|
}
|
|
break;
|
|
case WM_SHOWWINDOW:
|
|
{
|
|
if (!propPageContext->LayoutInitialized)
|
|
{
|
|
PPH_LAYOUT_ITEM dialogItem;
|
|
|
|
dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg,
|
|
PH_PROP_PAGE_TAB_CONTROL_PARENT, PH_ANCHOR_ALL);
|
|
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT),
|
|
dialogItem, PH_ANCHOR_ALL);
|
|
|
|
PhDoPropPageLayout(hwndDlg);
|
|
PhpLayoutServiceListControl(hwndDlg, (HWND)propPageContext->Context);
|
|
|
|
propPageContext->LayoutInitialized = TRUE;
|
|
}
|
|
}
|
|
break;
|
|
case WM_SIZE:
|
|
{
|
|
PhpLayoutServiceListControl(hwndDlg, (HWND)propPageContext->Context);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
NTSTATUS PhpProcessPropertiesThreadStart(
|
|
_In_ PVOID Parameter
|
|
)
|
|
{
|
|
PH_AUTO_POOL autoPool;
|
|
PPH_PROCESS_PROPCONTEXT PropContext = (PPH_PROCESS_PROPCONTEXT)Parameter;
|
|
PPH_PROCESS_PROPPAGECONTEXT newPage;
|
|
PPH_STRING startPage;
|
|
HWND hwnd;
|
|
BOOL result;
|
|
MSG message;
|
|
|
|
PhInitializeAutoPool(&autoPool);
|
|
|
|
// Wait for stage 1 to be processed.
|
|
PhWaitForEvent(&PropContext->ProcessItem->Stage1Event, NULL);
|
|
// Refresh the icon which may have been updated due to
|
|
// stage 1.
|
|
PhRefreshProcessPropContext(PropContext);
|
|
|
|
// Add the pages...
|
|
|
|
// General
|
|
newPage = PhCreateProcessPropPageContext(
|
|
MAKEINTRESOURCE(IDD_PROCGENERAL),
|
|
PhpProcessGeneralDlgProc,
|
|
NULL
|
|
);
|
|
PhAddProcessPropPage(PropContext, newPage);
|
|
|
|
// Statistics
|
|
newPage = PhCreateProcessPropPageContext(
|
|
MAKEINTRESOURCE(IDD_PROCSTATISTICS),
|
|
PhpProcessStatisticsDlgProc,
|
|
NULL
|
|
);
|
|
PhAddProcessPropPage(PropContext, newPage);
|
|
|
|
// Performance
|
|
newPage = PhCreateProcessPropPageContext(
|
|
MAKEINTRESOURCE(IDD_PROCPERFORMANCE),
|
|
PhpProcessPerformanceDlgProc,
|
|
NULL
|
|
);
|
|
PhAddProcessPropPage(PropContext, newPage);
|
|
|
|
// Threads
|
|
newPage = PhCreateProcessPropPageContext(
|
|
MAKEINTRESOURCE(IDD_PROCTHREADS),
|
|
PhpProcessThreadsDlgProc,
|
|
NULL
|
|
);
|
|
PhAddProcessPropPage(PropContext, newPage);
|
|
|
|
// Token
|
|
PhAddProcessPropPage2(
|
|
PropContext,
|
|
PhCreateTokenPage(PhpOpenProcessToken, (PVOID)PropContext->ProcessItem->ProcessId, PhpProcessTokenHookProc)
|
|
);
|
|
|
|
// Modules
|
|
newPage = PhCreateProcessPropPageContext(
|
|
MAKEINTRESOURCE(IDD_PROCMODULES),
|
|
PhpProcessModulesDlgProc,
|
|
NULL
|
|
);
|
|
PhAddProcessPropPage(PropContext, newPage);
|
|
|
|
// Memory
|
|
newPage = PhCreateProcessPropPageContext(
|
|
MAKEINTRESOURCE(IDD_PROCMEMORY),
|
|
PhpProcessMemoryDlgProc,
|
|
NULL
|
|
);
|
|
PhAddProcessPropPage(PropContext, newPage);
|
|
|
|
// Environment
|
|
newPage = PhCreateProcessPropPageContext(
|
|
MAKEINTRESOURCE(IDD_PROCENVIRONMENT),
|
|
PhpProcessEnvironmentDlgProc,
|
|
NULL
|
|
);
|
|
PhAddProcessPropPage(PropContext, newPage);
|
|
|
|
// Handles
|
|
newPage = PhCreateProcessPropPageContext(
|
|
MAKEINTRESOURCE(IDD_PROCHANDLES),
|
|
PhpProcessHandlesDlgProc,
|
|
NULL
|
|
);
|
|
PhAddProcessPropPage(PropContext, newPage);
|
|
|
|
// Job
|
|
if (
|
|
PropContext->ProcessItem->IsInJob &&
|
|
// There's no way the job page can function without KPH since it needs
|
|
// to open a handle to the job.
|
|
KphIsConnected()
|
|
)
|
|
{
|
|
PhAddProcessPropPage2(
|
|
PropContext,
|
|
PhCreateJobPage(PhpOpenProcessJob, (PVOID)PropContext->ProcessItem->ProcessId, PhpProcessJobHookProc)
|
|
);
|
|
}
|
|
|
|
// Services
|
|
if (PropContext->ProcessItem->ServiceList && PropContext->ProcessItem->ServiceList->Count != 0)
|
|
{
|
|
newPage = PhCreateProcessPropPageContext(
|
|
MAKEINTRESOURCE(IDD_PROCSERVICES),
|
|
PhpProcessServicesDlgProc,
|
|
NULL
|
|
);
|
|
PhAddProcessPropPage(PropContext, newPage);
|
|
}
|
|
|
|
// Plugin-supplied pages
|
|
if (PhPluginsEnabled)
|
|
{
|
|
PH_PLUGIN_PROCESS_PROPCONTEXT pluginProcessPropContext;
|
|
|
|
pluginProcessPropContext.PropContext = PropContext;
|
|
pluginProcessPropContext.ProcessItem = PropContext->ProcessItem;
|
|
|
|
PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackProcessPropertiesInitializing), &pluginProcessPropContext);
|
|
}
|
|
|
|
// Create the property sheet
|
|
|
|
if (PropContext->SelectThreadId)
|
|
PhSetStringSetting(L"ProcPropPage", L"Threads");
|
|
|
|
startPage = PhGetStringSetting(L"ProcPropPage");
|
|
PropContext->PropSheetHeader.dwFlags |= PSH_USEPSTARTPAGE;
|
|
PropContext->PropSheetHeader.pStartPage = startPage->Buffer;
|
|
|
|
hwnd = (HWND)PropertySheet(&PropContext->PropSheetHeader);
|
|
|
|
PhDereferenceObject(startPage);
|
|
|
|
PropContext->WindowHandle = hwnd;
|
|
PhSetEvent(&PropContext->CreatedEvent);
|
|
|
|
// Main event loop
|
|
|
|
while (result = GetMessage(&message, NULL, 0, 0))
|
|
{
|
|
if (result == -1)
|
|
break;
|
|
|
|
if (!PropSheet_IsDialogMessage(hwnd, &message))
|
|
{
|
|
TranslateMessage(&message);
|
|
DispatchMessage(&message);
|
|
}
|
|
|
|
PhDrainAutoPool(&autoPool);
|
|
|
|
if (!PropSheet_GetCurrentPageHwnd(hwnd))
|
|
break;
|
|
}
|
|
|
|
DestroyWindow(hwnd);
|
|
PhDereferenceObject(PropContext);
|
|
|
|
PhDeleteAutoPool(&autoPool);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
BOOLEAN PhShowProcessProperties(
|
|
_In_ PPH_PROCESS_PROPCONTEXT Context
|
|
)
|
|
{
|
|
HANDLE threadHandle;
|
|
|
|
PhReferenceObject(Context);
|
|
threadHandle = PhCreateThread(0, PhpProcessPropertiesThreadStart, Context);
|
|
|
|
if (threadHandle)
|
|
{
|
|
NtClose(threadHandle);
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
PhDereferenceObject(Context);
|
|
return FALSE;
|
|
}
|
|
}
|