/* * Process Hacker - * process tree list * * Copyright (C) 2010 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 . */ #include #include #include VOID PhpRemoveProcessNode( __in PPH_PROCESS_NODE ProcessNode ); VOID PhpUpdateNeedCyclesInformation(); VOID PhpUpdateProcessNodeCycles( __inout PPH_PROCESS_NODE ProcessNode ); BOOLEAN NTAPI PhpProcessTreeListCallback( __in HWND hwnd, __in PH_TREELIST_MESSAGE Message, __in_opt PVOID Parameter1, __in_opt PVOID Parameter2, __in_opt PVOID Context ); BOOLEAN PhpApplyProcessTreeFiltersToNode( __in PPH_PROCESS_NODE Node ); static HANDLE ProcessTreeListHandle; static ULONG ProcessTreeListSortColumn; static PH_SORT_ORDER ProcessTreeListSortOrder; static PPH_HASH_ENTRY ProcessNodeHashSet[256] = PH_HASH_SET_INIT; // hashtable of all nodes static PPH_LIST ProcessNodeList; // list of all nodes, used when sorting is enabled static PPH_LIST ProcessNodeRootList; // list of root nodes BOOLEAN PhProcessTreeListStateHighlighting = TRUE; static PPH_POINTER_LIST ProcessNodeStateList; // list of nodes which need to be processed static PPH_LIST ProcessTreeFilterList = NULL; static BOOLEAN NeedCyclesInformation = FALSE; VOID PhProcessTreeListInitialization() { ProcessNodeList = PhCreateList(40); ProcessNodeRootList = PhCreateList(10); ProcessNodeStateList = PhCreatePointerList(4); } VOID PhInitializeProcessTreeList( __in HWND hwnd ) { ProcessTreeListHandle = hwnd; SendMessage(ProcessTreeListHandle, WM_SETFONT, (WPARAM)PhIconTitleFont, FALSE); TreeList_SetCallback(hwnd, PhpProcessTreeListCallback); TreeList_SetPlusMinus( hwnd, PH_LOAD_SHARED_IMAGE(MAKEINTRESOURCE(IDB_PLUS), IMAGE_BITMAP), PH_LOAD_SHARED_IMAGE(MAKEINTRESOURCE(IDB_MINUS), IMAGE_BITMAP) ); // Default columns PhAddTreeListColumn(hwnd, PHTLC_NAME, TRUE, L"Name", 200, PH_ALIGN_LEFT, 0, 0); PhAddTreeListColumn(hwnd, PHTLC_PID, TRUE, L"PID", 50, PH_ALIGN_RIGHT, 1, DT_RIGHT); PhAddTreeListColumn(hwnd, PHTLC_CPU, TRUE, L"CPU", 45, PH_ALIGN_RIGHT, 2, DT_RIGHT); PhAddTreeListColumn(hwnd, PHTLC_IOTOTAL, TRUE, L"I/O Total", 70, PH_ALIGN_RIGHT, 3, DT_RIGHT); PhAddTreeListColumn(hwnd, PHTLC_PVTMEMORY, TRUE, L"Pvt. Memory", 70, PH_ALIGN_RIGHT, 4, DT_RIGHT); PhAddTreeListColumn(hwnd, PHTLC_USERNAME, TRUE, L"User Name", 140, PH_ALIGN_LEFT, 5, 0); PhAddTreeListColumn(hwnd, PHTLC_DESCRIPTION, TRUE, L"Description", 180, PH_ALIGN_LEFT, 6, 0); PhAddTreeListColumn(hwnd, PHTLC_COMPANYNAME, FALSE, L"Company Name", 180, PH_ALIGN_LEFT, -1, 0); PhAddTreeListColumn(hwnd, PHTLC_VERSION, FALSE, L"Version", 100, PH_ALIGN_LEFT, -1, 0); PhAddTreeListColumn(hwnd, PHTLC_FILENAME, FALSE, L"File Name", 180, PH_ALIGN_LEFT, -1, DT_PATH_ELLIPSIS); PhAddTreeListColumn(hwnd, PHTLC_COMMANDLINE, FALSE, L"Command Line", 180, PH_ALIGN_LEFT, -1, 0); PhAddTreeListColumn(hwnd, PHTLC_PEAKPVTMEMORY, FALSE, L"Peak Pvt. Memory", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT); PhAddTreeListColumn(hwnd, PHTLC_WORKINGSET, FALSE, L"Working Set", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT); PhAddTreeListColumn(hwnd, PHTLC_PEAKWORKINGSET, FALSE, L"Peak Working Set", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT); PhAddTreeListColumn(hwnd, PHTLC_PRIVATEWS, FALSE, L"Private WS", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT); PhAddTreeListColumn(hwnd, PHTLC_SHAREDWS, FALSE, L"Shared WS", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT); PhAddTreeListColumn(hwnd, PHTLC_SHAREABLEWS, FALSE, L"Shareable WS", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT); PhAddTreeListColumn(hwnd, PHTLC_VIRTUALSIZE, FALSE, L"Virtual Size", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT); PhAddTreeListColumn(hwnd, PHTLC_PEAKVIRTUALSIZE, FALSE, L"Peak Virtual Size", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT); PhAddTreeListColumn(hwnd, PHTLC_PAGEFAULTS, FALSE, L"Page Faults", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT); PhAddTreeListColumn(hwnd, PHTLC_SESSIONID, FALSE, L"Session ID", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT); PhAddTreeListColumn(hwnd, PHTLC_PRIORITYCLASS, FALSE, L"Priority Class", 100, PH_ALIGN_LEFT, -1, 0); PhAddTreeListColumn(hwnd, PHTLC_BASEPRIORITY, FALSE, L"Base Priority", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT); PhAddTreeListColumn(hwnd, PHTLC_THREADS, FALSE, L"Threads", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT); PhAddTreeListColumn(hwnd, PHTLC_HANDLES, FALSE, L"Handles", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT); PhAddTreeListColumn(hwnd, PHTLC_GDIHANDLES, FALSE, L"GDI Handles", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT); PhAddTreeListColumn(hwnd, PHTLC_USERHANDLES, FALSE, L"USER Handles", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT); PhAddTreeListColumn(hwnd, PHTLC_IORO, FALSE, L"I/O R+O", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT); PhAddTreeListColumn(hwnd, PHTLC_IOW, FALSE, L"I/O W", 70, PH_ALIGN_RIGHT, -1, DT_RIGHT); PhAddTreeListColumn(hwnd, PHTLC_INTEGRITY, FALSE, L"Integrity", 100, PH_ALIGN_LEFT, -1, 0); PhAddTreeListColumn(hwnd, PHTLC_IOPRIORITY, FALSE, L"I/O Priority", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT); PhAddTreeListColumn(hwnd, PHTLC_PAGEPRIORITY, FALSE, L"Page Priority", 45, PH_ALIGN_RIGHT, -1, DT_RIGHT); PhAddTreeListColumn(hwnd, PHTLC_STARTTIME, FALSE, L"Start Time", 100, PH_ALIGN_LEFT, -1, 0); PhAddTreeListColumn(hwnd, PHTLC_TOTALCPUTIME, FALSE, L"Total CPU Time", 90, PH_ALIGN_LEFT, -1, 0); PhAddTreeListColumn(hwnd, PHTLC_KERNELCPUTIME, FALSE, L"Kernel CPU Time", 90, PH_ALIGN_RIGHT, -1, DT_RIGHT); PhAddTreeListColumn(hwnd, PHTLC_USERCPUTIME, FALSE, L"User CPU Time", 90, PH_ALIGN_RIGHT, -1, DT_RIGHT); PhAddTreeListColumn(hwnd, PHTLC_VERIFICATIONSTATUS, FALSE, L"Verification Status", 70, PH_ALIGN_LEFT, -1, 0); PhAddTreeListColumn(hwnd, PHTLC_VERIFIEDSIGNER, FALSE, L"Verified Signer", 100, PH_ALIGN_LEFT, -1, 0); PhAddTreeListColumn(hwnd, PHTLC_RELATIVESTARTTIME, FALSE, L"Relative Start Time", 180, PH_ALIGN_LEFT, -1, 0); PhAddTreeListColumn(hwnd, PHTLC_BITS, FALSE, L"Bits", 50, PH_ALIGN_LEFT, -1, 0); PhAddTreeListColumn(hwnd, PHTLC_ELEVATION, FALSE, L"Elevation", 60, PH_ALIGN_LEFT, -1, 0); PhAddTreeListColumn(hwnd, PHTLC_WINDOWTITLE, FALSE, L"Window Title", 120, PH_ALIGN_LEFT, -1, 0); PhAddTreeListColumn(hwnd, PHTLC_WINDOWSTATUS, FALSE, L"Window Status", 60, PH_ALIGN_LEFT, -1, 0); PhAddTreeListColumn(hwnd, PHTLC_CYCLES, FALSE, L"Cycles", 110, PH_ALIGN_RIGHT, -1, DT_RIGHT); PhAddTreeListColumn(hwnd, PHTLC_CYCLESDELTA, FALSE, L"Cycles Delta", 90, PH_ALIGN_RIGHT, -1, DT_RIGHT); TreeList_SetTriState(hwnd, TRUE); TreeList_SetSort(hwnd, 0, NoSortOrder); } VOID PhLoadSettingsProcessTreeList() { ULONG sortColumn; PH_SORT_ORDER sortOrder; PhLoadTreeListColumnsFromSetting(L"ProcessTreeListColumns", ProcessTreeListHandle); sortOrder = PhGetIntegerSetting(L"ProcessTreeListSortOrder"); if (sortOrder != NoSortOrder) { sortColumn = PhGetIntegerSetting(L"ProcessTreeListSortColumn"); TreeList_SetSort(ProcessTreeListHandle, sortColumn, sortOrder); } PhpUpdateNeedCyclesInformation(); } VOID PhSaveSettingsProcessTreeList() { ULONG sortColumn; PH_SORT_ORDER sortOrder; PhSaveTreeListColumnsToSetting(L"ProcessTreeListColumns", ProcessTreeListHandle); TreeList_GetSort(ProcessTreeListHandle, &sortColumn, &sortOrder); PhSetIntegerSetting(L"ProcessTreeListSortColumn", sortColumn); PhSetIntegerSetting(L"ProcessTreeListSortOrder", sortOrder); } FORCEINLINE BOOLEAN PhCompareProcessNode( __in PPH_PROCESS_NODE Value1, __in PPH_PROCESS_NODE Value2 ) { return Value1->ProcessId == Value2->ProcessId; } FORCEINLINE ULONG PhHashProcessNode( __in PPH_PROCESS_NODE Value ) { return (ULONG)Value->ProcessId / 4; } PPH_PROCESS_NODE PhAddProcessNode( __in PPH_PROCESS_ITEM ProcessItem, __in ULONG RunId ) { PPH_PROCESS_NODE processNode; PPH_PROCESS_NODE parentNode; ULONG i; processNode = PhAllocate(sizeof(PH_PROCESS_NODE)); memset(processNode, 0, sizeof(PH_PROCESS_NODE)); PhInitializeTreeListNode(&processNode->Node); if (PhProcessTreeListStateHighlighting && RunId != 1) { processNode->TickCount = GetTickCount(); processNode->Node.UseTempBackColor = TRUE; processNode->Node.TempBackColor = PhCsColorNew; processNode->StateListHandle = PhAddItemPointerList(ProcessNodeStateList, processNode); processNode->State = NewItemState; } else { processNode->State = NormalItemState; } processNode->ProcessId = ProcessItem->ProcessId; processNode->ProcessItem = ProcessItem; PhReferenceObject(ProcessItem); memset(processNode->TextCache, 0, sizeof(PH_STRINGREF) * PHTLC_MAXIMUM); processNode->Node.TextCache = processNode->TextCache; processNode->Node.TextCacheSize = PHTLC_MAXIMUM; processNode->Children = PhCreateList(1); // Find this process' parent and add the process to it if we found it. if ( (parentNode = PhFindProcessNode(ProcessItem->ParentProcessId)) && parentNode->ProcessItem->CreateTime.QuadPart <= ProcessItem->CreateTime.QuadPart ) { PhAddItemList(parentNode->Children, processNode); processNode->Parent = parentNode; } else { // No parent, add to root list. processNode->Parent = NULL; PhAddItemList(ProcessNodeRootList, processNode); } // Find this process' children and move them to this node. for (i = 0; i < ProcessNodeRootList->Count; i++) { PPH_PROCESS_NODE node = ProcessNodeRootList->Items[i]; if ( node != processNode && // for cases where the parent PID = PID (e.g. System Idle Process) node->ProcessItem->ParentProcessId == ProcessItem->ProcessId && ProcessItem->CreateTime.QuadPart <= node->ProcessItem->CreateTime.QuadPart ) { node->Parent = processNode; PhAddItemList(processNode->Children, node); } } for (i = 0; i < processNode->Children->Count; i++) { PhRemoveItemList( ProcessNodeRootList, PhFindItemList(ProcessNodeRootList, processNode->Children->Items[i]) ); } PhAddEntryHashSet( ProcessNodeHashSet, PH_HASH_SET_SIZE(ProcessNodeHashSet), &processNode->HashEntry, PhHashProcessNode(processNode) ); PhAddItemList(ProcessNodeList, processNode); if (PhCsCollapseServicesOnStart) { static PH_STRINGREF servicesBaseName = PH_STRINGREF_INIT(L"\\services.exe"); static BOOLEAN servicesFound = FALSE; static PPH_STRING servicesFileName = NULL; if (!servicesFound) { if (!servicesFileName) { PPH_STRING systemDirectory; systemDirectory = PhGetSystemDirectory(); servicesFileName = PhConcatStringRef2(&systemDirectory->sr, &servicesBaseName); PhDereferenceObject(systemDirectory); } // If this process is services.exe, collapse the node and free the string. if ( ProcessItem->FileName && PhEqualString(ProcessItem->FileName, servicesFileName, TRUE) ) { processNode->Node.Expanded = FALSE; PhDereferenceObject(servicesFileName); servicesFileName = NULL; servicesFound = TRUE; } } } if (ProcessTreeFilterList) processNode->Node.Visible = PhpApplyProcessTreeFiltersToNode(processNode); TreeList_NodesStructured(ProcessTreeListHandle); return processNode; } PPH_PROCESS_NODE PhFindProcessNode( __in HANDLE ProcessId ) { PH_PROCESS_NODE lookupNode; PPH_HASH_ENTRY entry; PPH_PROCESS_NODE node; lookupNode.ProcessId = ProcessId; entry = PhFindEntryHashSet( ProcessNodeHashSet, PH_HASH_SET_SIZE(ProcessNodeHashSet), PhHashProcessNode(&lookupNode) ); for (; entry; entry = entry->Next) { node = CONTAINING_RECORD(entry, PH_PROCESS_NODE, HashEntry); if (PhCompareProcessNode(&lookupNode, node)) return node; } return NULL; } VOID PhRemoveProcessNode( __in PPH_PROCESS_NODE ProcessNode ) { if (PhProcessTreeListStateHighlighting) { ProcessNode->TickCount = GetTickCount(); ProcessNode->Node.UseTempBackColor = TRUE; ProcessNode->Node.TempBackColor = PhCsColorRemoved; if (ProcessNode->State == NormalItemState) ProcessNode->StateListHandle = PhAddItemPointerList(ProcessNodeStateList, ProcessNode); ProcessNode->State = RemovingItemState; TreeList_UpdateNode(ProcessTreeListHandle, &ProcessNode->Node); } else { PhpRemoveProcessNode(ProcessNode); } } VOID PhpRemoveProcessNode( __in PPH_PROCESS_NODE ProcessNode ) { ULONG index; ULONG i; if (ProcessNode->Parent) { // Remove the node from its parent. if ((index = PhFindItemList(ProcessNode->Parent->Children, ProcessNode)) != -1) PhRemoveItemList(ProcessNode->Parent->Children, index); } else { // Remove the node from the root list. if ((index = PhFindItemList(ProcessNodeRootList, ProcessNode)) != -1) PhRemoveItemList(ProcessNodeRootList, index); } // Move the node's children to the root list. for (i = 0; i < ProcessNode->Children->Count; i++) { PPH_PROCESS_NODE node = ProcessNode->Children->Items[i]; node->Parent = NULL; PhAddItemList(ProcessNodeRootList, node); } // Remove from hashtable/list and cleanup. PhRemoveEntryHashSet(ProcessNodeHashSet, PH_HASH_SET_SIZE(ProcessNodeHashSet), &ProcessNode->HashEntry); if ((index = PhFindItemList(ProcessNodeList, ProcessNode)) != -1) PhRemoveItemList(ProcessNodeList, index); PhDereferenceObject(ProcessNode->Children); if (ProcessNode->WindowText) PhDereferenceObject(ProcessNode->WindowText); if (ProcessNode->TooltipText) PhDereferenceObject(ProcessNode->TooltipText); if (ProcessNode->IoTotalText) PhDereferenceObject(ProcessNode->IoTotalText); if (ProcessNode->PrivateMemoryText) PhDereferenceObject(ProcessNode->PrivateMemoryText); if (ProcessNode->PeakPrivateMemoryText) PhDereferenceObject(ProcessNode->PeakPrivateMemoryText); if (ProcessNode->WorkingSetText) PhDereferenceObject(ProcessNode->WorkingSetText); if (ProcessNode->PeakWorkingSetText) PhDereferenceObject(ProcessNode->PeakWorkingSetText); if (ProcessNode->PrivateWsText) PhDereferenceObject(ProcessNode->PrivateWsText); if (ProcessNode->SharedWsText) PhDereferenceObject(ProcessNode->SharedWsText); if (ProcessNode->ShareableWsText) PhDereferenceObject(ProcessNode->ShareableWsText); if (ProcessNode->VirtualSizeText) PhDereferenceObject(ProcessNode->VirtualSizeText); if (ProcessNode->PeakVirtualSizeText) PhDereferenceObject(ProcessNode->PeakVirtualSizeText); if (ProcessNode->PageFaultsText) PhDereferenceObject(ProcessNode->PageFaultsText); if (ProcessNode->IoRoText) PhDereferenceObject(ProcessNode->IoRoText); if (ProcessNode->IoWText) PhDereferenceObject(ProcessNode->IoWText); if (ProcessNode->StartTimeText) PhDereferenceObject(ProcessNode->StartTimeText); if (ProcessNode->RelativeStartTimeText) PhDereferenceObject(ProcessNode->RelativeStartTimeText); if (ProcessNode->WindowTitleText) PhDereferenceObject(ProcessNode->WindowTitleText); if (ProcessNode->CyclesText) PhDereferenceObject(ProcessNode->CyclesText); if (ProcessNode->CyclesDeltaText) PhDereferenceObject(ProcessNode->CyclesDeltaText); PhDereferenceObject(ProcessNode->ProcessItem); PhFree(ProcessNode); TreeList_NodesStructured(ProcessTreeListHandle); } VOID PhUpdateProcessNode( __in PPH_PROCESS_NODE ProcessNode ) { memset(ProcessNode->TextCache, 0, sizeof(PH_STRINGREF) * PHTLC_MAXIMUM); if (ProcessNode->TooltipText) { PhDereferenceObject(ProcessNode->TooltipText); ProcessNode->TooltipText = NULL; } PhInvalidateTreeListNode(&ProcessNode->Node, TLIN_COLOR | TLIN_ICON); } VOID PhTickProcessNodes() { // Text invalidation, node updates { ULONG i; for (i = 0; i < ProcessNodeList->Count; i++) { PPH_PROCESS_NODE node = ProcessNodeList->Items[i]; // The name and PID never change, so we don't invalidate that. memset(&node->TextCache[2], 0, sizeof(PH_STRINGREF) * (PHTLC_MAXIMUM - 2)); node->ValidMask = 0; // Updates cycles if necessary. if (NeedCyclesInformation) PhpUpdateProcessNodeCycles(node); } if (ProcessTreeListSortOrder != NoSortOrder) { // Force a rebuild to sort the items. TreeList_NodesStructured(ProcessTreeListHandle); } InvalidateRect(ProcessTreeListHandle, NULL, FALSE); } // State highlighting if (ProcessNodeStateList->Count != 0) { PPH_PROCESS_NODE node; ULONG enumerationKey = 0; ULONG tickCount; HANDLE stateListHandle; BOOLEAN redrawDisabled = FALSE; tickCount = GetTickCount(); while (PhEnumPointerList(ProcessNodeStateList, &enumerationKey, &node)) { if (PhRoundNumber(tickCount - node->TickCount, 100) < PhCsHighlightingDuration) continue; stateListHandle = node->StateListHandle; if (node->State == NewItemState) { node->State = NormalItemState; node->Node.UseTempBackColor = FALSE; } else if (node->State == RemovingItemState) { if (!redrawDisabled) { TreeList_SetRedraw(ProcessTreeListHandle, FALSE); redrawDisabled = TRUE; } PhpRemoveProcessNode(node); } PhRemoveItemPointerList(ProcessNodeStateList, stateListHandle); } if (redrawDisabled) TreeList_SetRedraw(ProcessTreeListHandle, TRUE); } } static VOID PhpUpdateProcessNodeWsCounters( __inout PPH_PROCESS_NODE ProcessNode ) { if (!(ProcessNode->ValidMask & PHPN_WSCOUNTERS)) { BOOLEAN success = FALSE; HANDLE processHandle; if (NT_SUCCESS(PhOpenProcess( &processHandle, PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, ProcessNode->ProcessItem->ProcessId ))) { if (NT_SUCCESS(PhGetProcessWsCounters( processHandle, &ProcessNode->WsCounters ))) success = TRUE; NtClose(processHandle); } if (!success) memset(&ProcessNode->WsCounters, 0, sizeof(PH_PROCESS_WS_COUNTERS)); ProcessNode->ValidMask |= PHPN_WSCOUNTERS; } } static VOID PhpUpdateProcessNodeGdiUserHandles( __inout PPH_PROCESS_NODE ProcessNode ) { if (!(ProcessNode->ValidMask & PHPN_GDIUSERHANDLES)) { if (ProcessNode->ProcessItem->QueryHandle) { ProcessNode->GdiHandles = GetGuiResources(ProcessNode->ProcessItem->QueryHandle, GR_GDIOBJECTS); ProcessNode->UserHandles = GetGuiResources(ProcessNode->ProcessItem->QueryHandle, GR_USEROBJECTS); } else { ProcessNode->GdiHandles = 0; ProcessNode->UserHandles = 0; } ProcessNode->ValidMask |= PHPN_GDIUSERHANDLES; } } static VOID PhpUpdateProcessNodeIoPagePriority( __inout PPH_PROCESS_NODE ProcessNode ) { if (!(ProcessNode->ValidMask & PHPN_IOPAGEPRIORITY)) { if (ProcessNode->ProcessItem->QueryHandle) { if (!NT_SUCCESS(PhGetProcessIoPriority(ProcessNode->ProcessItem->QueryHandle, &ProcessNode->IoPriority))) ProcessNode->IoPriority = 0; if (!NT_SUCCESS(PhGetProcessPagePriority(ProcessNode->ProcessItem->QueryHandle, &ProcessNode->PagePriority))) ProcessNode->PagePriority = 0; } else { ProcessNode->IoPriority = 0; ProcessNode->PagePriority = 0; } ProcessNode->ValidMask |= PHPN_IOPAGEPRIORITY; } } static BOOL CALLBACK PhpEnumProcessNodeWindowsProc( __in HWND hwnd, __in LPARAM lParam ) { PPH_PROCESS_NODE processNode = (PPH_PROCESS_NODE)lParam; ULONG threadId; ULONG processId; threadId = GetWindowThreadProcessId(hwnd, &processId); if (UlongToHandle(processId) == processNode->ProcessId) { HWND parentWindow; if ( !IsWindowVisible(hwnd) || // skip invisible windows ((parentWindow = GetParent(hwnd)) && IsWindowVisible(parentWindow)) || // skip windows with visible parents GetWindowTextLength(hwnd) == 0 // skip windows with no title ) return TRUE; processNode->WindowHandle = hwnd; return FALSE; } return TRUE; } static VOID PhpUpdateProcessNodeWindow( __inout PPH_PROCESS_NODE ProcessNode ) { if (!(ProcessNode->ValidMask & PHPN_WINDOW)) { ProcessNode->WindowHandle = NULL; EnumWindows(PhpEnumProcessNodeWindowsProc, (LPARAM)ProcessNode); PhSwapReference(&ProcessNode->WindowText, NULL); if (ProcessNode->WindowHandle) { ProcessNode->WindowText = PhGetWindowText(ProcessNode->WindowHandle); ProcessNode->WindowHung = !!IsHungAppWindow(ProcessNode->WindowHandle); } ProcessNode->ValidMask |= PHPN_WINDOW; } } static VOID PhpUpdateNeedCyclesInformation() { PH_TREELIST_COLUMN column; NeedCyclesInformation = FALSE; if (!WINDOWS_HAS_CYCLE_TIME) return; column.Id = PHTLC_CYCLES; TreeList_GetColumn(ProcessTreeListHandle, &column); if (column.Visible) { NeedCyclesInformation = TRUE; return; } column.Id = PHTLC_CYCLESDELTA; TreeList_GetColumn(ProcessTreeListHandle, &column); if (column.Visible) { NeedCyclesInformation = TRUE; return; } } static VOID PhpUpdateProcessNodeCycles( __inout PPH_PROCESS_NODE ProcessNode ) { if (ProcessNode->ProcessId == SYSTEM_IDLE_PROCESS_ID) { PULARGE_INTEGER idleThreadCycleTimes; ULONG64 cycleTime; ULONG i; // System Idle Process requires special treatment. idleThreadCycleTimes = PhAllocate( sizeof(ULARGE_INTEGER) * (ULONG)PhSystemBasicInformation.NumberOfProcessors ); if (NT_SUCCESS(NtQuerySystemInformation( SystemProcessorIdleCycleTimeInformation, idleThreadCycleTimes, sizeof(ULARGE_INTEGER) * (ULONG)PhSystemBasicInformation.NumberOfProcessors, NULL ))) { cycleTime = 0; for (i = 0; i < (ULONG)PhSystemBasicInformation.NumberOfProcessors; i++) cycleTime += idleThreadCycleTimes[i].QuadPart; PhUpdateDelta(&ProcessNode->CyclesDelta, cycleTime); } PhFree(idleThreadCycleTimes); } else if (ProcessNode->ProcessItem->QueryHandle) { ULONG64 cycleTime; if (NT_SUCCESS(PhGetProcessCycleTime(ProcessNode->ProcessItem->QueryHandle, &cycleTime))) { PhUpdateDelta(&ProcessNode->CyclesDelta, cycleTime); } } if (ProcessNode->CyclesDelta.Value != 0) PhSwapReference2(&ProcessNode->CyclesText, PhFormatUInt64(ProcessNode->CyclesDelta.Value, TRUE)); else PhSwapReference2(&ProcessNode->CyclesText, NULL); if (ProcessNode->CyclesDelta.Delta != 0) PhSwapReference2(&ProcessNode->CyclesDeltaText, PhFormatUInt64(ProcessNode->CyclesDelta.Delta, TRUE)); else PhSwapReference2(&ProcessNode->CyclesDeltaText, NULL); } #define SORT_FUNCTION(Column) PhpProcessTreeListCompare##Column #define BEGIN_SORT_FUNCTION(Column) static int __cdecl PhpProcessTreeListCompare##Column( \ __in const void *_elem1, \ __in const void *_elem2 \ ) \ { \ PPH_PROCESS_NODE node1 = *(PPH_PROCESS_NODE *)_elem1; \ PPH_PROCESS_NODE node2 = *(PPH_PROCESS_NODE *)_elem2; \ PPH_PROCESS_ITEM processItem1 = node1->ProcessItem; \ PPH_PROCESS_ITEM processItem2 = node2->ProcessItem; \ int sortResult = 0; #define END_SORT_FUNCTION \ if (sortResult == 0) \ sortResult = intptrcmp((LONG_PTR)processItem1->ProcessId, (LONG_PTR)processItem2->ProcessId); \ \ return PhModifySort(sortResult, ProcessTreeListSortOrder); \ } BEGIN_SORT_FUNCTION(Name) { sortResult = PhCompareString(processItem1->ProcessName, processItem2->ProcessName, TRUE); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(Pid) { // Use signed int so DPCs and Interrupts are placed above System Idle Process. sortResult = intptrcmp((LONG_PTR)processItem1->ProcessId, (LONG_PTR)processItem2->ProcessId); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(Cpu) { sortResult = singlecmp(processItem1->CpuUsage, processItem2->CpuUsage); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(IoTotal) { sortResult = uint64cmp( processItem1->IoReadDelta.Delta + processItem1->IoWriteDelta.Delta + processItem1->IoOtherDelta.Delta, processItem2->IoReadDelta.Delta + processItem2->IoWriteDelta.Delta + processItem2->IoOtherDelta.Delta ); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(PvtMemory) { sortResult = uintptrcmp(processItem1->VmCounters.PagefileUsage, processItem2->VmCounters.PagefileUsage); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(UserName) { sortResult = PhCompareStringWithNull(processItem1->UserName, processItem2->UserName, TRUE); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(Description) { sortResult = PhCompareStringWithNull( processItem1->VersionInfo.FileDescription, processItem2->VersionInfo.FileDescription, TRUE ); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(CompanyName) { sortResult = PhCompareStringWithNull( processItem1->VersionInfo.CompanyName, processItem2->VersionInfo.CompanyName, TRUE ); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(Version) { sortResult = PhCompareStringWithNull( processItem1->VersionInfo.FileVersion, processItem2->VersionInfo.FileVersion, TRUE ); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(FileName) { sortResult = PhCompareStringWithNull( processItem1->FileName, processItem2->FileName, TRUE ); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(CommandLine) { sortResult = PhCompareStringWithNull( processItem1->CommandLine, processItem2->CommandLine, TRUE ); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(PeakPvtMemory) { sortResult = uintptrcmp(processItem1->VmCounters.PeakPagefileUsage, processItem2->VmCounters.PeakPagefileUsage); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(WorkingSet) { sortResult = uintptrcmp(processItem1->VmCounters.WorkingSetSize, processItem2->VmCounters.WorkingSetSize); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(PeakWorkingSet) { sortResult = uintptrcmp(processItem1->VmCounters.PeakWorkingSetSize, processItem2->VmCounters.PeakWorkingSetSize); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(PrivateWs) { PhpUpdateProcessNodeWsCounters(node1); PhpUpdateProcessNodeWsCounters(node2); sortResult = uintcmp(node1->WsCounters.NumberOfPrivatePages, node2->WsCounters.NumberOfPrivatePages); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(SharedWs) { PhpUpdateProcessNodeWsCounters(node1); PhpUpdateProcessNodeWsCounters(node2); sortResult = uintcmp(node1->WsCounters.NumberOfSharedPages, node2->WsCounters.NumberOfSharedPages); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(ShareableWs) { PhpUpdateProcessNodeWsCounters(node1); PhpUpdateProcessNodeWsCounters(node2); sortResult = uintcmp(node1->WsCounters.NumberOfShareablePages, node2->WsCounters.NumberOfShareablePages); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(VirtualSize) { sortResult = uintptrcmp(processItem1->VmCounters.VirtualSize, processItem2->VmCounters.VirtualSize); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(PeakVirtualSize) { sortResult = uintptrcmp(processItem1->VmCounters.PeakVirtualSize, processItem2->VmCounters.PeakVirtualSize); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(PageFaults) { sortResult = uintcmp(processItem1->VmCounters.PageFaultCount, processItem2->VmCounters.PageFaultCount); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(SessionId) { sortResult = uintcmp(processItem1->SessionId, processItem2->SessionId); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(PriorityClass) { sortResult = intcmp(processItem1->BasePriority, processItem2->BasePriority); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(BasePriority) { sortResult = intcmp(processItem1->BasePriority, processItem2->BasePriority); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(Threads) { sortResult = uintcmp(processItem1->NumberOfThreads, processItem2->NumberOfThreads); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(Handles) { sortResult = uintcmp(processItem1->NumberOfHandles, processItem2->NumberOfHandles); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(GdiHandles) { sortResult = uintcmp(node1->GdiHandles, node2->GdiHandles); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(UserHandles) { sortResult = uintcmp(node1->UserHandles, node2->UserHandles); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(IoRo) { sortResult = uint64cmp( processItem1->IoReadDelta.Delta + processItem1->IoOtherDelta.Delta, processItem2->IoReadDelta.Delta + processItem2->IoOtherDelta.Delta ); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(IoW) { sortResult = uint64cmp( processItem1->IoWriteDelta.Delta, processItem2->IoWriteDelta.Delta ); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(Integrity) { sortResult = uintcmp(processItem1->IntegrityLevel, processItem2->IntegrityLevel); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(IoPriority) { sortResult = uintcmp(node1->IoPriority, node2->IoPriority); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(PagePriority) { sortResult = uintcmp(node1->PagePriority, node2->PagePriority); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(StartTime) { sortResult = int64cmp(processItem1->CreateTime.QuadPart, processItem2->CreateTime.QuadPart); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(TotalCpuTime) { sortResult = uint64cmp( processItem1->KernelTime.QuadPart + processItem1->UserTime.QuadPart, processItem2->KernelTime.QuadPart + processItem2->UserTime.QuadPart ); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(KernelCpuTime) { sortResult = uint64cmp( processItem1->KernelTime.QuadPart, processItem2->KernelTime.QuadPart ); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(UserCpuTime) { sortResult = uint64cmp( processItem1->UserTime.QuadPart, processItem2->UserTime.QuadPart ); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(VerificationStatus) { sortResult = intcmp(processItem1->VerifyResult == VrTrusted, processItem2->VerifyResult == VrTrusted); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(VerifiedSigner) { sortResult = PhCompareStringWithNull( processItem1->VerifySignerName, processItem2->VerifySignerName, TRUE ); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(Reserved1) { sortResult = 0; } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(RelativeStartTime) { sortResult = -int64cmp(processItem1->CreateTime.QuadPart, processItem2->CreateTime.QuadPart); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(Bits) { sortResult = intcmp(processItem1->IsWow64, processItem2->IsWow64); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(Elevation) { sortResult = intcmp(processItem1->ElevationType, processItem2->ElevationType); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(WindowTitle) { PhpUpdateProcessNodeWindow(node1); PhpUpdateProcessNodeWindow(node2); sortResult = PhCompareStringWithNull(node1->WindowText, node2->WindowText, TRUE); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(WindowStatus) { PhpUpdateProcessNodeWindow(node1); PhpUpdateProcessNodeWindow(node2); sortResult = intcmp(node1->WindowHung, node2->WindowHung); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(Cycles) { sortResult = uint64cmp(node1->CyclesDelta.Value, node2->CyclesDelta.Value); } END_SORT_FUNCTION BEGIN_SORT_FUNCTION(CyclesDelta) { sortResult = uint64cmp(node1->CyclesDelta.Delta, node2->CyclesDelta.Delta); } END_SORT_FUNCTION BOOLEAN NTAPI PhpProcessTreeListCallback( __in HWND hwnd, __in PH_TREELIST_MESSAGE Message, __in_opt PVOID Parameter1, __in_opt PVOID Parameter2, __in_opt PVOID Context ) { PPH_PROCESS_NODE node; switch (Message) { case TreeListGetChildren: { PPH_TREELIST_GET_CHILDREN getChildren = Parameter1; node = (PPH_PROCESS_NODE)getChildren->Node; if (ProcessTreeListSortOrder == NoSortOrder) { if (!node) { getChildren->Children = (PPH_TREELIST_NODE *)ProcessNodeRootList->Items; getChildren->NumberOfChildren = ProcessNodeRootList->Count; } else { getChildren->Children = (PPH_TREELIST_NODE *)node->Children->Items; getChildren->NumberOfChildren = node->Children->Count; } } else { if (!node) { static PVOID sortFunctions[] = { SORT_FUNCTION(Name), SORT_FUNCTION(Pid), SORT_FUNCTION(Cpu), SORT_FUNCTION(IoTotal), SORT_FUNCTION(PvtMemory), SORT_FUNCTION(UserName), SORT_FUNCTION(Description), SORT_FUNCTION(CompanyName), SORT_FUNCTION(Version), SORT_FUNCTION(FileName), SORT_FUNCTION(CommandLine), SORT_FUNCTION(PeakPvtMemory), SORT_FUNCTION(WorkingSet), SORT_FUNCTION(PeakWorkingSet), SORT_FUNCTION(PrivateWs), SORT_FUNCTION(SharedWs), SORT_FUNCTION(ShareableWs), SORT_FUNCTION(VirtualSize), SORT_FUNCTION(PeakVirtualSize), SORT_FUNCTION(PageFaults), SORT_FUNCTION(SessionId), SORT_FUNCTION(PriorityClass), SORT_FUNCTION(BasePriority), SORT_FUNCTION(Threads), SORT_FUNCTION(Handles), SORT_FUNCTION(GdiHandles), SORT_FUNCTION(UserHandles), SORT_FUNCTION(IoRo), SORT_FUNCTION(IoW), SORT_FUNCTION(Integrity), SORT_FUNCTION(IoPriority), SORT_FUNCTION(PagePriority), SORT_FUNCTION(StartTime), SORT_FUNCTION(TotalCpuTime), SORT_FUNCTION(KernelCpuTime), SORT_FUNCTION(UserCpuTime), SORT_FUNCTION(VerificationStatus), SORT_FUNCTION(VerifiedSigner), SORT_FUNCTION(Reserved1), SORT_FUNCTION(RelativeStartTime), SORT_FUNCTION(Bits), SORT_FUNCTION(Elevation), SORT_FUNCTION(WindowTitle), SORT_FUNCTION(WindowStatus), SORT_FUNCTION(Cycles), SORT_FUNCTION(CyclesDelta) }; int (__cdecl *sortFunction)(const void *, const void *); if (ProcessTreeListSortColumn < PHTLC_MAXIMUM) sortFunction = sortFunctions[ProcessTreeListSortColumn]; else sortFunction = NULL; if (sortFunction) { // Don't use PhSortList to avoid overhead. qsort(ProcessNodeList->Items, ProcessNodeList->Count, sizeof(PVOID), sortFunction); } getChildren->Children = (PPH_TREELIST_NODE *)ProcessNodeList->Items; getChildren->NumberOfChildren = ProcessNodeList->Count; } } } return TRUE; case TreeListIsLeaf: { PPH_TREELIST_IS_LEAF isLeaf = Parameter1; node = (PPH_PROCESS_NODE)isLeaf->Node; if (ProcessTreeListSortOrder == NoSortOrder) isLeaf->IsLeaf = node->Children->Count == 0; else isLeaf->IsLeaf = TRUE; } return TRUE; case TreeListGetNodeText: { PPH_TREELIST_GET_NODE_TEXT getNodeText = Parameter1; PPH_PROCESS_ITEM processItem; node = (PPH_PROCESS_NODE)getNodeText->Node; processItem = node->ProcessItem; switch (getNodeText->Id) { case PHTLC_NAME: getNodeText->Text = processItem->ProcessName->sr; break; case PHTLC_PID: PhInitializeStringRef(&getNodeText->Text, processItem->ProcessIdString); break; case PHTLC_CPU: { FLOAT cpuUsage; cpuUsage = processItem->CpuUsage * 100; if (cpuUsage >= 0.01) { _snwprintf(node->CpuUsageText, PH_INT32_STR_LEN, L"%.2f", cpuUsage); PhInitializeStringRef(&getNodeText->Text, node->CpuUsageText); } else { PhInitializeEmptyStringRef(&getNodeText->Text); } } break; case PHTLC_IOTOTAL: { ULONG64 number; if (processItem->IoReadDelta.Delta != processItem->IoReadDelta.Value) // delta is wrong on first run of process provider { number = processItem->IoReadDelta.Delta + processItem->IoWriteDelta.Delta + processItem->IoOtherDelta.Delta; number *= 1000; number /= PhCsUpdateInterval; } else { number = 0; } if (number != 0) { PH_FORMAT format[2]; PhInitFormatSize(&format[0], number); PhInitFormatS(&format[1], L"/s"); PhSwapReference2(&node->IoTotalText, PhFormat(format, 2, 0)); getNodeText->Text = node->IoTotalText->sr; } else { PhInitializeEmptyStringRef(&getNodeText->Text); } } break; case PHTLC_PVTMEMORY: PhSwapReference2(&node->PrivateMemoryText, PhFormatSize(processItem->VmCounters.PagefileUsage, -1)); getNodeText->Text = node->PrivateMemoryText->sr; break; case PHTLC_USERNAME: getNodeText->Text = PhGetStringRefOrEmpty(processItem->UserName); break; case PHTLC_DESCRIPTION: getNodeText->Text = PhGetStringRefOrEmpty(processItem->VersionInfo.FileDescription); break; case PHTLC_COMPANYNAME: getNodeText->Text = PhGetStringRefOrEmpty(processItem->VersionInfo.CompanyName); break; case PHTLC_VERSION: getNodeText->Text = PhGetStringRefOrEmpty(processItem->VersionInfo.FileVersion); break; case PHTLC_FILENAME: getNodeText->Text = PhGetStringRefOrEmpty(processItem->FileName); break; case PHTLC_COMMANDLINE: getNodeText->Text = PhGetStringRefOrEmpty(processItem->CommandLine); break; case PHTLC_PEAKPVTMEMORY: PhSwapReference2(&node->PeakPrivateMemoryText, PhFormatSize(processItem->VmCounters.PeakPagefileUsage, -1)); getNodeText->Text = node->PeakPrivateMemoryText->sr; break; case PHTLC_WORKINGSET: PhSwapReference2(&node->WorkingSetText, PhFormatSize(processItem->VmCounters.WorkingSetSize, -1)); getNodeText->Text = node->WorkingSetText->sr; break; case PHTLC_PEAKWORKINGSET: PhSwapReference2(&node->PeakWorkingSetText, PhFormatSize(processItem->VmCounters.PeakWorkingSetSize, -1)); getNodeText->Text = node->PeakWorkingSetText->sr; break; case PHTLC_PRIVATEWS: PhpUpdateProcessNodeWsCounters(node); PhSwapReference2(&node->PrivateWsText, PhFormatSize(UInt32x32To64(node->WsCounters.NumberOfPrivatePages, PAGE_SIZE), -1)); getNodeText->Text = node->PrivateWsText->sr; break; case PHTLC_SHAREDWS: PhpUpdateProcessNodeWsCounters(node); PhSwapReference2(&node->SharedWsText, PhFormatSize(UInt32x32To64(node->WsCounters.NumberOfSharedPages, PAGE_SIZE), -1)); getNodeText->Text = node->SharedWsText->sr; break; case PHTLC_SHAREABLEWS: PhpUpdateProcessNodeWsCounters(node); PhSwapReference2(&node->ShareableWsText, PhFormatSize(UInt32x32To64(node->WsCounters.NumberOfShareablePages, PAGE_SIZE), -1)); getNodeText->Text = node->ShareableWsText->sr; break; case PHTLC_VIRTUALSIZE: PhSwapReference2(&node->VirtualSizeText, PhFormatSize(processItem->VmCounters.VirtualSize, -1)); getNodeText->Text = node->VirtualSizeText->sr; break; case PHTLC_PEAKVIRTUALSIZE: PhSwapReference2(&node->PeakVirtualSizeText, PhFormatSize(processItem->VmCounters.PeakVirtualSize, -1)); getNodeText->Text = node->PeakVirtualSizeText->sr; break; case PHTLC_PAGEFAULTS: PhSwapReference2(&node->PageFaultsText, PhFormatUInt64(processItem->VmCounters.PageFaultCount, TRUE)); getNodeText->Text = node->PageFaultsText->sr; break; case PHTLC_SESSIONID: PhInitializeStringRef(&getNodeText->Text, processItem->SessionIdString); break; case PHTLC_PRIORITYCLASS: PhInitializeStringRef(&getNodeText->Text, PhGetProcessPriorityClassWin32String(processItem->PriorityClassWin32)); break; case PHTLC_BASEPRIORITY: PhPrintInt32(node->BasePriorityText, processItem->BasePriority); PhInitializeStringRef(&getNodeText->Text, node->BasePriorityText); break; case PHTLC_THREADS: PhPrintUInt32(node->ThreadsText, processItem->NumberOfThreads); PhInitializeStringRef(&getNodeText->Text, node->ThreadsText); break; case PHTLC_HANDLES: PhPrintUInt32(node->HandlesText, processItem->NumberOfHandles); PhInitializeStringRef(&getNodeText->Text, node->HandlesText); break; case PHTLC_GDIHANDLES: PhpUpdateProcessNodeGdiUserHandles(node); PhPrintUInt32(node->GdiHandlesText, node->GdiHandles); PhInitializeStringRef(&getNodeText->Text, node->GdiHandlesText); break; case PHTLC_USERHANDLES: PhpUpdateProcessNodeGdiUserHandles(node); PhPrintUInt32(node->UserHandlesText, node->UserHandles); PhInitializeStringRef(&getNodeText->Text, node->UserHandlesText); break; case PHTLC_IORO: { ULONG64 number; if (processItem->IoReadDelta.Delta != processItem->IoReadDelta.Value) { number = processItem->IoReadDelta.Delta + processItem->IoOtherDelta.Delta; number *= 1000; number /= PhCsUpdateInterval; } else { number = 0; } if (number != 0) { PH_FORMAT format[2]; PhInitFormatSize(&format[0], number); PhInitFormatS(&format[1], L"/s"); PhSwapReference2(&node->IoRoText, PhFormat(format, 2, 0)); getNodeText->Text = node->IoRoText->sr; } else { PhInitializeEmptyStringRef(&getNodeText->Text); } } break; case PHTLC_IOW: { ULONG64 number; if (processItem->IoReadDelta.Delta != processItem->IoReadDelta.Value) { number = processItem->IoWriteDelta.Delta; number *= 1000; number /= PhCsUpdateInterval; } else { number = 0; } if (number != 0) { PH_FORMAT format[2]; PhInitFormatSize(&format[0], number); PhInitFormatS(&format[1], L"/s"); PhSwapReference2(&node->IoWText, PhFormat(format, 2, 0)); getNodeText->Text = node->IoWText->sr; } else { PhInitializeEmptyStringRef(&getNodeText->Text); } } break; case PHTLC_INTEGRITY: PhInitializeStringRef(&getNodeText->Text, processItem->IntegrityString); break; case PHTLC_IOPRIORITY: PhpUpdateProcessNodeIoPagePriority(node); PhPrintUInt32(node->IoPriorityText, node->IoPriority); PhInitializeStringRef(&getNodeText->Text, node->IoPriorityText); break; case PHTLC_PAGEPRIORITY: PhpUpdateProcessNodeIoPagePriority(node); PhPrintUInt32(node->PagePriorityText, node->PagePriority); PhInitializeStringRef(&getNodeText->Text, node->PagePriorityText); break; case PHTLC_STARTTIME: { SYSTEMTIME systemTime; if (processItem->CreateTime.QuadPart != 0) { PhLargeIntegerToLocalSystemTime(&systemTime, &processItem->CreateTime); PhSwapReference2(&node->StartTimeText, PhFormatDateTime(&systemTime)); getNodeText->Text = node->StartTimeText->sr; } else { PhInitializeEmptyStringRef(&getNodeText->Text); } } break; case PHTLC_TOTALCPUTIME: PhPrintTimeSpan(node->TotalCpuTimeText, processItem->KernelTime.QuadPart + processItem->UserTime.QuadPart, PH_TIMESPAN_HMSM); PhInitializeStringRef(&getNodeText->Text, node->TotalCpuTimeText); break; case PHTLC_KERNELCPUTIME: PhPrintTimeSpan(node->KernelCpuTimeText, processItem->KernelTime.QuadPart, PH_TIMESPAN_HMSM); PhInitializeStringRef(&getNodeText->Text, node->KernelCpuTimeText); break; case PHTLC_USERCPUTIME: PhPrintTimeSpan(node->UserCpuTimeText, processItem->UserTime.QuadPart, PH_TIMESPAN_HMSM); PhInitializeStringRef(&getNodeText->Text, node->UserCpuTimeText); break; case PHTLC_VERIFICATIONSTATUS: PhInitializeStringRef(&getNodeText->Text, processItem->VerifyResult == VrTrusted ? L"Trusted" : L"Not Trusted"); break; case PHTLC_VERIFIEDSIGNER: getNodeText->Text = PhGetStringRefOrEmpty(processItem->VerifySignerName); break; case PHTLC_RELATIVESTARTTIME: { if (processItem->CreateTime.QuadPart != 0) { LARGE_INTEGER currentTime; PhQuerySystemTime(¤tTime); PhSwapReference2(&node->RelativeStartTimeText, PhFormatTimeSpanRelative(currentTime.QuadPart - processItem->CreateTime.QuadPart)); getNodeText->Text = node->RelativeStartTimeText->sr; } else { PhInitializeEmptyStringRef(&getNodeText->Text); } } break; case PHTLC_BITS: #ifdef _M_X64 PhInitializeStringRef(&getNodeText->Text, processItem->IsWow64 ? L"32-bit" : L"64-bit"); #else PhInitializeStringRef(&getNodeText->Text, L"32-bit"); #endif break; case PHTLC_ELEVATION: { PWSTR type; if (WINDOWS_HAS_UAC) { switch (processItem->ElevationType) { case TokenElevationTypeDefault: type = L"N/A"; break; case TokenElevationTypeLimited: type = L"Limited"; break; case TokenElevationTypeFull: type = L"Full"; break; default: type = L"N/A"; break; } } else { type = L""; } PhInitializeStringRef(&getNodeText->Text, type); } break; case PHTLC_WINDOWTITLE: PhpUpdateProcessNodeWindow(node); PhSwapReference(&node->WindowTitleText, node->WindowText); getNodeText->Text = PhGetStringRef(node->WindowTitleText); break; case PHTLC_WINDOWSTATUS: PhpUpdateProcessNodeWindow(node); if (node->WindowHandle) PhInitializeStringRef(&getNodeText->Text, node->WindowHung ? L"Not responding" : L"Running"); else PhInitializeEmptyStringRef(&getNodeText->Text); break; case PHTLC_CYCLES: getNodeText->Text = PhGetStringRef(node->CyclesText); break; case PHTLC_CYCLESDELTA: getNodeText->Text = PhGetStringRef(node->CyclesDeltaText); break; default: return FALSE; } getNodeText->Flags = TLC_CACHE; } return TRUE; case TreeListGetNodeColor: { PPH_TREELIST_GET_NODE_COLOR getNodeColor = Parameter1; PPH_PROCESS_ITEM processItem; node = (PPH_PROCESS_NODE)getNodeColor->Node; processItem = node->ProcessItem; if (PhPluginsEnabled) { PH_PLUGIN_GET_HIGHLIGHTING_COLOR getHighlightingColor; getHighlightingColor.Parameter = processItem; getHighlightingColor.BackColor = RGB(0xff, 0xff, 0xff); getHighlightingColor.Handled = FALSE; getHighlightingColor.Cache = FALSE; PhInvokeCallback(PhGetGeneralCallback(GeneralCallbackGetProcessHighlightingColor), &getHighlightingColor); if (getHighlightingColor.Handled) { getNodeColor->BackColor = getHighlightingColor.BackColor; getNodeColor->Flags = TLGNC_AUTO_FORECOLOR; if (getHighlightingColor.Cache) getNodeColor->Flags |= TLC_CACHE; return TRUE; } } if (!processItem) ; // Dummy else if (PhCsUseColorDebuggedProcesses && processItem->IsBeingDebugged) getNodeColor->BackColor = PhCsColorDebuggedProcesses; else if (PhCsUseColorSuspended && processItem->IsSuspended) getNodeColor->BackColor = PhCsColorSuspended; else if (PhCsUseColorElevatedProcesses && processItem->IsElevated) getNodeColor->BackColor = PhCsColorElevatedProcesses; else if (PhCsUseColorPosixProcesses && processItem->IsPosix) getNodeColor->BackColor = PhCsColorPosixProcesses; else if (PhCsUseColorWow64Processes && processItem->IsWow64) getNodeColor->BackColor = PhCsColorWow64Processes; else if (PhCsUseColorJobProcesses && processItem->IsInSignificantJob) getNodeColor->BackColor = PhCsColorJobProcesses; //else if ( // PhCsUseColorPacked && // (processItem->VerifyResult != VrUnknown && // processItem->VerifyResult != VrNoSignature && // processItem->VerifyResult != VrTrusted // )) // getNodeColor->BackColor = PhCsColorPacked; else if (PhCsUseColorDotNet && processItem->IsDotNet) getNodeColor->BackColor = PhCsColorDotNet; else if (PhCsUseColorPacked && processItem->IsPacked) getNodeColor->BackColor = PhCsColorPacked; else if (PhCsUseColorServiceProcesses && processItem->ServiceList && processItem->ServiceList->Count != 0) getNodeColor->BackColor = PhCsColorServiceProcesses; else if ( PhCsUseColorSystemProcesses && processItem->UserName && PhEqualString(processItem->UserName, PhLocalSystemName, TRUE) ) getNodeColor->BackColor = PhCsColorSystemProcesses; else if ( PhCsUseColorOwnProcesses && processItem->UserName && PhCurrentUserName && PhEqualString(processItem->UserName, PhCurrentUserName, TRUE) ) getNodeColor->BackColor = PhCsColorOwnProcesses; getNodeColor->Flags = TLC_CACHE | TLGNC_AUTO_FORECOLOR; } return TRUE; case TreeListGetNodeIcon: { PPH_TREELIST_GET_NODE_ICON getNodeIcon = Parameter1; node = (PPH_PROCESS_NODE)getNodeIcon->Node; if (node->ProcessItem->SmallIcon) { getNodeIcon->Icon = node->ProcessItem->SmallIcon; } else { PhGetStockApplicationIcon(&getNodeIcon->Icon, NULL); } getNodeIcon->Flags = TLC_CACHE; } return TRUE; case TreeListGetNodeTooltip: { PPH_TREELIST_GET_NODE_TOOLTIP getNodeTooltip = Parameter1; node = (PPH_PROCESS_NODE)getNodeTooltip->Node; if (!node->TooltipText) node->TooltipText = PhGetProcessTooltipText(node->ProcessItem); if (node->TooltipText) getNodeTooltip->Text = node->TooltipText->sr; else return FALSE; } return TRUE; case TreeListSortChanged: { TreeList_GetSort(hwnd, &ProcessTreeListSortColumn, &ProcessTreeListSortOrder); // Force a rebuild to sort the items. TreeList_NodesStructured(hwnd); } return TRUE; case TreeListKeyDown: { switch ((SHORT)Parameter1) { case 'C': if (GetKeyState(VK_CONTROL) < 0) SendMessage(PhMainWndHandle, WM_COMMAND, ID_PROCESS_COPY, 0); break; case VK_DELETE: if (GetKeyState(VK_SHIFT) >= 0) SendMessage(PhMainWndHandle, WM_COMMAND, ID_PROCESS_TERMINATE, 0); else SendMessage(PhMainWndHandle, WM_COMMAND, ID_PROCESS_TERMINATETREE, 0); break; case VK_RETURN: SendMessage(PhMainWndHandle, WM_COMMAND, ID_PROCESS_PROPERTIES, 0); break; } } return TRUE; case TreeListHeaderRightClick: { HMENU menu; HMENU subMenu; POINT point; menu = LoadMenu(PhInstanceHandle, MAKEINTRESOURCE(IDR_PROCESSHEADER)); subMenu = GetSubMenu(menu, 0); GetCursorPos(&point); if ((UINT)TrackPopupMenu( subMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, point.x, point.y, 0, hwnd, NULL ) == ID_HEADER_CHOOSECOLUMNS) { PhShowChooseColumnsDialog(hwnd, hwnd); PhpUpdateNeedCyclesInformation(); // Make sure the column we're sorting by is actually visible, // and if not, don't sort any more. if (ProcessTreeListSortOrder != NoSortOrder) { PH_TREELIST_COLUMN column; column.Id = ProcessTreeListSortColumn; TreeList_GetColumn(ProcessTreeListHandle, &column); if (!column.Visible) TreeList_SetSort(ProcessTreeListHandle, 0, NoSortOrder); } } DestroyMenu(menu); } return TRUE; case TreeListNodeRightClick: { PPH_TREELIST_MOUSE_EVENT mouseEvent = Parameter2; PhShowProcessContextMenu(mouseEvent->Location); } return TRUE; case TreeListNodeLeftDoubleClick: { SendMessage(PhMainWndHandle, WM_COMMAND, ID_PROCESS_PROPERTIES, 0); } return TRUE; } return FALSE; } PPH_PROCESS_ITEM PhGetSelectedProcessItem() { PPH_PROCESS_ITEM processItem = NULL; ULONG i; for (i = 0; i < ProcessNodeList->Count; i++) { PPH_PROCESS_NODE node = ProcessNodeList->Items[i]; if (node->Node.Selected) { processItem = node->ProcessItem; break; } } return processItem; } VOID PhGetSelectedProcessItems( __out PPH_PROCESS_ITEM **Processes, __out PULONG NumberOfProcesses ) { PPH_LIST list; ULONG i; list = PhCreateList(2); for (i = 0; i < ProcessNodeList->Count; i++) { PPH_PROCESS_NODE node = ProcessNodeList->Items[i]; if (node->Node.Selected) { PhAddItemList(list, node->ProcessItem); } } *Processes = PhAllocateCopy(list->Items, sizeof(PVOID) * list->Count); *NumberOfProcesses = list->Count; PhDereferenceObject(list); } VOID PhDeselectAllProcessNodes() { ULONG i; for (i = 0; i < ProcessNodeList->Count; i++) { PPH_PROCESS_NODE node = ProcessNodeList->Items[i]; node->Node.Selected = FALSE; PhInvalidateTreeListNode(&node->Node, TLIN_STATE); } InvalidateRect(ProcessTreeListHandle, NULL, TRUE); } VOID PhInvalidateAllProcessNodes() { ULONG i; for (i = 0; i < ProcessNodeList->Count; i++) { PPH_PROCESS_NODE node = ProcessNodeList->Items[i]; memset(node->TextCache, 0, sizeof(PH_STRINGREF) * PHTLC_MAXIMUM); PhInvalidateTreeListNode(&node->Node, TLIN_COLOR); node->ValidMask = 0; } InvalidateRect(ProcessTreeListHandle, NULL, TRUE); } VOID PhSelectAndEnsureVisibleProcessNode( __in PPH_PROCESS_NODE ProcessNode ) { PPH_PROCESS_NODE processNode; BOOLEAN needsRestructure = FALSE; PhDeselectAllProcessNodes(); if (!ProcessNode->Node.Visible) return; // Expand recursively, upwards. processNode = ProcessNode->Parent; while (processNode) { if (!processNode->Node.Expanded) needsRestructure = TRUE; processNode->Node.Expanded = TRUE; processNode = processNode->Parent; } // ListView_SetItemState is used as well. // To reproduce the bug: // 1. Select and then deselect an item. // 2. Call PhSelectAndEnsureVisibleProcessNode. // 3. Select another item (without Ctrl). The existing item doesn't get deselected. ProcessNode->Node.Selected = TRUE; ProcessNode->Node.Focused = TRUE; PhInvalidateTreeListNode(&ProcessNode->Node, TLIN_STATE); if (needsRestructure) TreeList_NodesStructured(ProcessTreeListHandle); ListView_SetItemState(TreeList_GetListView(ProcessTreeListHandle), ProcessNode->Node.s.ViewIndex, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED); TreeList_EnsureVisible(ProcessTreeListHandle, &ProcessNode->Node, FALSE); } PPH_PROCESS_TREE_FILTER_ENTRY PhAddProcessTreeFilter( __in PPH_PROCESS_TREE_FILTER Filter, __in_opt PVOID Context ) { PPH_PROCESS_TREE_FILTER_ENTRY entry; entry = PhAllocate(sizeof(PH_PROCESS_TREE_FILTER_ENTRY)); entry->Filter = Filter; entry->Context = Context; if (!ProcessTreeFilterList) ProcessTreeFilterList = PhCreateList(2); PhAddItemList(ProcessTreeFilterList, entry); return entry; } VOID PhRemoveProcessTreeFilter( __in PPH_PROCESS_TREE_FILTER_ENTRY Entry ) { ULONG index; if (!ProcessTreeFilterList) return; index = PhFindItemList(ProcessTreeFilterList, Entry); if (index != -1) { PhRemoveItemList(ProcessTreeFilterList, index); PhFree(Entry); } } BOOLEAN PhpApplyProcessTreeFiltersToNode( __in PPH_PROCESS_NODE Node ) { BOOLEAN show; ULONG i; show = TRUE; if (ProcessTreeFilterList) { for (i = 0; i < ProcessTreeFilterList->Count; i++) { PPH_PROCESS_TREE_FILTER_ENTRY entry; entry = ProcessTreeFilterList->Items[i]; if (!entry->Filter(Node, entry->Context)) { show = FALSE; break; } } } return show; } VOID PhApplyProcessTreeFilters() { ULONG i; for (i = 0; i < ProcessNodeList->Count; i++) { PPH_PROCESS_NODE node; node = ProcessNodeList->Items[i]; node->Node.Visible = PhpApplyProcessTreeFiltersToNode(node); if (!node->Node.Visible) node->Node.Selected = FALSE; PhInvalidateTreeListNode(&node->Node, TLIN_STATE); } TreeList_NodesStructured(ProcessTreeListHandle); } VOID PhCopyProcessTree() { PPH_FULL_STRING text; text = PhGetProcessTreeListText(ProcessTreeListHandle); PhSetClipboardStringEx(ProcessTreeListHandle, text->Buffer, text->Length); PhDereferenceObject(text); } VOID PhWriteProcessTree( __inout PPH_FILE_STREAM FileStream, __in ULONG Mode ) { PPH_LIST lines; ULONG i; lines = PhGetProcessTreeListLines( ProcessTreeListHandle, ProcessNodeList->Count, ProcessNodeRootList, Mode ); for (i = 0; i < lines->Count; i++) { PPH_STRING line; line = lines->Items[i]; PhWriteStringAsAnsiFileStream(FileStream, &line->sr); PhDereferenceObject(line); PhWriteStringAsAnsiFileStream2(FileStream, L"\r\n"); } PhDereferenceObject(lines); }