From fe04dab216ada021b81a3465ba94ad00a8694c10 Mon Sep 17 00:00:00 2001 From: wj32 Date: Mon, 2 Aug 2010 08:13:43 +0000 Subject: [PATCH] added handle statistics window git-svn-id: svn://svn.code.sf.net/p/processhacker/code@3464 21ef857c-d57f-4fe0-8362-d861dc6d29cd --- 2.x/trunk/CHANGELOG.txt | 1 + 2.x/trunk/ProcessHacker/ProcessHacker.rc | 20 +- 2.x/trunk/ProcessHacker/ProcessHacker.vcproj | 4 + 2.x/trunk/ProcessHacker/hndlprv.c | 4 +- 2.x/trunk/ProcessHacker/hndlstat.c | 235 +++++++++++++++++++ 2.x/trunk/ProcessHacker/include/phapp.h | 7 + 2.x/trunk/ProcessHacker/include/providers.h | 7 + 2.x/trunk/ProcessHacker/procprp.c | 12 + 2.x/trunk/ProcessHacker/resource.h | 6 +- 2.x/trunk/phlib/hndlinfo.c | 7 +- 2.x/trunk/phlib/include/ph.h | 2 + 11 files changed, 296 insertions(+), 9 deletions(-) create mode 100644 2.x/trunk/ProcessHacker/hndlstat.c diff --git a/2.x/trunk/CHANGELOG.txt b/2.x/trunk/CHANGELOG.txt index 0b485a367..5f9d63f14 100644 --- a/2.x/trunk/CHANGELOG.txt +++ b/2.x/trunk/CHANGELOG.txt @@ -6,6 +6,7 @@ Process Hacker * Can now unload 32-bit modules on 64-bit systems * Tasks are shown in tooltips for taskeng.exe/taskhost.exe processes * Run As can now start processes elevated + * Handle count by type * CSV export * Relative start times * FIXED: diff --git a/2.x/trunk/ProcessHacker/ProcessHacker.rc b/2.x/trunk/ProcessHacker/ProcessHacker.rc index b4d8bbe96..d73a1763a 100644 --- a/2.x/trunk/ProcessHacker/ProcessHacker.rc +++ b/2.x/trunk/ProcessHacker/ProcessHacker.rc @@ -1219,13 +1219,14 @@ BEGIN RTEXT "Static",IDC_ZIOOTHER_V,184,57,63,8,SS_ENDELLIPSIS RTEXT "Static",IDC_ZIOOTHERBYTES_V,184,67,63,8,SS_ENDELLIPSIS RTEXT "Static",IDC_ZIOPRIORITY_V,184,77,63,8,SS_ENDELLIPSIS - GROUPBOX "Other",IDC_STATIC,131,92,122,43 + GROUPBOX "Other",IDC_STATIC,131,92,122,60 LTEXT "Handles",IDC_STATIC,138,102,26,8 LTEXT "GDI Handles",IDC_STATIC,138,112,40,8 LTEXT "USER Handles",IDC_STATIC,138,122,46,8 RTEXT "Static",IDC_ZHANDLES_V,193,102,54,8,SS_ENDELLIPSIS RTEXT "Static",IDC_ZGDIHANDLES_V,193,112,54,8,SS_ENDELLIPSIS RTEXT "Static",IDC_ZUSERHANDLES_V,193,122,54,8,SS_ENDELLIPSIS + PUSHBUTTON "Details",IDC_DETAILS,137,133,50,14 END IDD_OPTADVANCED DIALOGEX 0, 0, 250, 85 @@ -1457,6 +1458,15 @@ BEGIN PUSHBUTTON "Cleanup",IDC_CLEANUP,7,239,50,14 END +IDD_HANDLESTATS DIALOGEX 0, 0, 219, 175 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Handle Statistics" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + DEFPUSHBUTTON "Close",IDOK,162,154,50,14 + CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,205,143 +END + ///////////////////////////////////////////////////////////////////////////// // @@ -1881,6 +1891,14 @@ BEGIN TOPMARGIN, 7 BOTTOMMARGIN, 253 END + + IDD_HANDLESTATS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 212 + TOPMARGIN, 7 + BOTTOMMARGIN, 168 + END END #endif // APSTUDIO_INVOKED diff --git a/2.x/trunk/ProcessHacker/ProcessHacker.vcproj b/2.x/trunk/ProcessHacker/ProcessHacker.vcproj index 2298a2348..df3e0d1d5 100644 --- a/2.x/trunk/ProcessHacker/ProcessHacker.vcproj +++ b/2.x/trunk/ProcessHacker/ProcessHacker.vcproj @@ -720,6 +720,10 @@ RelativePath=".\hndlprv.c" > + + diff --git a/2.x/trunk/ProcessHacker/hndlprv.c b/2.x/trunk/ProcessHacker/hndlprv.c index efa8d3245..210d85a8b 100644 --- a/2.x/trunk/ProcessHacker/hndlprv.c +++ b/2.x/trunk/ProcessHacker/hndlprv.c @@ -257,7 +257,7 @@ __assumeLocked VOID PhpRemoveHandleItem( PhDereferenceObject(HandleItem); } -NTSTATUS PhpEnumHandlesGeneric( +NTSTATUS PhEnumHandlesGeneric( __in HANDLE ProcessId, __in HANDLE ProcessHandle, __out PSYSTEM_HANDLE_INFORMATION_EX *Handles, @@ -399,7 +399,7 @@ VOID PhHandleProviderUpdate( if (!handleProvider->ProcessHandle) return; - if (!NT_SUCCESS(PhpEnumHandlesGeneric( + if (!NT_SUCCESS(PhEnumHandlesGeneric( handleProvider->ProcessId, handleProvider->ProcessHandle, &handleInfo, diff --git a/2.x/trunk/ProcessHacker/hndlstat.c b/2.x/trunk/ProcessHacker/hndlstat.c new file mode 100644 index 000000000..85cfbccf1 --- /dev/null +++ b/2.x/trunk/ProcessHacker/hndlstat.c @@ -0,0 +1,235 @@ +/* + * Process Hacker - + * handle statistics window + * + * 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 + +typedef struct _HANDLE_STATISTICS_ENTRY +{ + PPH_STRING Name; + ULONG Count; +} HANDLE_STATISTICS_ENTRY, *PHANDLE_STATISTICS_ENTRY; + +typedef struct _HANDLE_STATISTICS_CONTEXT +{ + HANDLE ProcessId; + HANDLE ProcessHandle; + + PSYSTEM_HANDLE_INFORMATION_EX Handles; + HANDLE_STATISTICS_ENTRY Entries[MAX_OBJECT_TYPE_NUMBER]; +} HANDLE_STATISTICS_CONTEXT, *PHANDLE_STATISTICS_CONTEXT; + +INT_PTR CALLBACK PhpHandleStatisticsDlgProc( + __in HWND hwndDlg, + __in UINT uMsg, + __in WPARAM wParam, + __in LPARAM lParam + ); + +VOID PhShowHandleStatisticsDialog( + __in HWND ParentWindowHandle, + __in HANDLE ProcessId + ) +{ + NTSTATUS status; + HANDLE_STATISTICS_CONTEXT context; + BOOLEAN filterNeeded; + ULONG i; + + context.ProcessId = ProcessId; + + if (!NT_SUCCESS(status = PhOpenProcess( + &context.ProcessHandle, + PROCESS_DUP_HANDLE, + ProcessId + ))) + { + PhShowStatus(ParentWindowHandle, L"Unable to open the process", status, 0); + return; + } + + status = PhEnumHandlesGeneric( + context.ProcessId, + context.ProcessHandle, + &context.Handles, + &filterNeeded + ); + + if (!NT_SUCCESS(status)) + { + NtClose(context.ProcessHandle); + PhShowStatus(ParentWindowHandle, L"Unable to enumerate process handles", status, 0); + return; + } + + memset(&context.Entries, 0, sizeof(context.Entries)); + + DialogBoxParam( + PhInstanceHandle, + MAKEINTRESOURCE(IDD_HANDLESTATS), + ParentWindowHandle, + PhpHandleStatisticsDlgProc, + (LPARAM)&context + ); + + for (i = 0; i < MAX_OBJECT_TYPE_NUMBER; i++) + { + if (context.Entries[i].Name) + PhDereferenceObject(context.Entries[i].Name); + } + + PhFree(context.Handles); + NtClose(context.ProcessHandle); +} + +static INT NTAPI PhpTypeCountCompareFunction( + __in PVOID Item1, + __in PVOID Item2, + __in PVOID Context + ) +{ + PHANDLE_STATISTICS_ENTRY entry1 = Item1; + PHANDLE_STATISTICS_ENTRY entry2 = Item2; + + return uintcmp(entry1->Count, entry2->Count); +} + +INT_PTR CALLBACK PhpHandleStatisticsDlgProc( + __in HWND hwndDlg, + __in UINT uMsg, + __in WPARAM wParam, + __in LPARAM lParam + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + PHANDLE_STATISTICS_CONTEXT context = (PHANDLE_STATISTICS_CONTEXT)lParam; + HANDLE processId; + ULONG_PTR i; + HWND lvHandle; + + processId = context->ProcessId; + + for (i = 0; i < context->Handles->NumberOfHandles; i++) + { + PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handleInfo; + PHANDLE_STATISTICS_ENTRY entry; + PPH_STRING typeName; + + handleInfo = &context->Handles->Handles[i]; + + if (handleInfo->UniqueProcessId != (ULONG_PTR)processId) + continue; + if (handleInfo->ObjectTypeIndex >= MAX_OBJECT_TYPE_NUMBER) + continue; + + entry = &context->Entries[handleInfo->ObjectTypeIndex]; + + if (!entry->Name) + { + typeName = NULL; + PhGetHandleInformation( + context->ProcessHandle, + (HANDLE)handleInfo->HandleValue, + handleInfo->ObjectTypeIndex, + NULL, + &typeName, + NULL, + NULL + ); + entry->Name = typeName; + } + + entry->Count++; + } + + lvHandle = GetDlgItem(hwndDlg, IDC_LIST); + PhSetListViewStyle(lvHandle, FALSE, TRUE); + PhSetControlTheme(lvHandle, L"explorer"); + PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 140, L"Type"); + PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 100, L"Count"); + + PhSetExtendedListView(lvHandle); + ExtendedListView_SetCompareFunction(lvHandle, 1, PhpTypeCountCompareFunction); + + for (i = 0; i < MAX_OBJECT_TYPE_NUMBER; i++) + { + PHANDLE_STATISTICS_ENTRY entry; + PPH_STRING unknownType; + PPH_STRING countString; + INT lvItemIndex; + + entry = &context->Entries[i]; + + if (entry->Count == 0) + continue; + + unknownType = NULL; + + if (!entry->Name) + unknownType = PhFormatString(L"(unknown: %u)", i); + + countString = PhFormatUInt64(entry->Count, TRUE); + + lvItemIndex = PhAddListViewItem( + lvHandle, + MAXINT, + entry->Name ? entry->Name->Buffer : unknownType->Buffer, + entry + ); + PhSetListViewSubItem(lvHandle, lvItemIndex, 1, countString->Buffer); + + PhDereferenceObject(countString); + + if (unknownType) + PhDereferenceObject(unknownType); + } + + ExtendedListView_SortItems(lvHandle); + } + break; + case WM_DESTROY: + { + // Nothing + } + break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDCANCEL: + case IDOK: + EndDialog(hwndDlg, IDOK); + break; + } + } + break; + case WM_NOTIFY: + { + PhHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST)); + } + break; + } + + return FALSE; +} diff --git a/2.x/trunk/ProcessHacker/include/phapp.h b/2.x/trunk/ProcessHacker/include/phapp.h index 3501054bd..1d8e3ceb7 100644 --- a/2.x/trunk/ProcessHacker/include/phapp.h +++ b/2.x/trunk/ProcessHacker/include/phapp.h @@ -1210,6 +1210,13 @@ VOID PhShowHandleProperties( __in PPH_HANDLE_ITEM HandleItem ); +// hndlstat + +VOID PhShowHandleStatisticsDialog( + __in HWND ParentWindowHandle, + __in HANDLE ProcessId + ); + // infodlg VOID PhShowInformationDialog( diff --git a/2.x/trunk/ProcessHacker/include/providers.h b/2.x/trunk/ProcessHacker/include/providers.h index 4acd54809..2368d2a81 100644 --- a/2.x/trunk/ProcessHacker/include/providers.h +++ b/2.x/trunk/ProcessHacker/include/providers.h @@ -629,6 +629,13 @@ VOID PhDereferenceAllHandleItems( __in PPH_HANDLE_PROVIDER HandleProvider ); +NTSTATUS PhEnumHandlesGeneric( + __in HANDLE ProcessId, + __in HANDLE ProcessHandle, + __out PSYSTEM_HANDLE_INFORMATION_EX *Handles, + __out PBOOLEAN FilterNeeded + ); + VOID PhHandleProviderUpdate( __in PVOID Object ); diff --git a/2.x/trunk/ProcessHacker/procprp.c b/2.x/trunk/ProcessHacker/procprp.c index 7825e2714..0718de54c 100644 --- a/2.x/trunk/ProcessHacker/procprp.c +++ b/2.x/trunk/ProcessHacker/procprp.c @@ -1195,6 +1195,18 @@ INT_PTR CALLBACK PhpProcessStatisticsDlgProc( } } break; + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + case IDC_DETAILS: + { + PhShowHandleStatisticsDialog(hwndDlg, processItem->ProcessId); + } + break; + } + } + break; case WM_NOTIFY: { LPNMHDR header = (LPNMHDR)lParam; diff --git a/2.x/trunk/ProcessHacker/resource.h b/2.x/trunk/ProcessHacker/resource.h index 73cdbe32c..d0ec0fced 100644 --- a/2.x/trunk/ProcessHacker/resource.h +++ b/2.x/trunk/ProcessHacker/resource.h @@ -101,6 +101,7 @@ #define IDD_MEMSTRING 185 #define IDD_OPTGRAPHS 186 #define IDD_PLUGINS 187 +#define IDD_HANDLESTATS 188 #define IDC_TERMINATE 1003 #define IDC_FILEICON 1005 #define IDC_FILE 1006 @@ -192,6 +193,7 @@ #define IDC_CLEAR 1079 #define IDC_GOTO 1079 #define IDC_OPTIONS 1079 +#define IDC_DETAILS 1079 #define IDC_EDITDEP 1080 #define IDC_VIEWPARENTPROCESS 1081 #define IDC_OPENFILENAME 1082 @@ -610,9 +612,9 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 188 +#define _APS_NEXT_RESOURCE_VALUE 189 #define _APS_NEXT_COMMAND_VALUE 40232 -#define _APS_NEXT_CONTROL_VALUE 1260 +#define _APS_NEXT_CONTROL_VALUE 1261 #define _APS_NEXT_SYMED_VALUE 131 #endif #endif diff --git a/2.x/trunk/phlib/hndlinfo.c b/2.x/trunk/phlib/hndlinfo.c index 721cc3d95..43f5fa615 100644 --- a/2.x/trunk/phlib/hndlinfo.c +++ b/2.x/trunk/phlib/hndlinfo.c @@ -55,8 +55,7 @@ HANDLE PhQueryObjectStartEvent = NULL; HANDLE PhQueryObjectCompletedEvent = NULL; PH_QUERY_OBJECT_CONTEXT PhQueryObjectContext; -#define MAX_OBJECT_TYPE_NUMBER 256 -PPH_STRING PhObjectTypeNames[MAX_OBJECT_TYPE_NUMBER + 1]; +PPH_STRING PhObjectTypeNames[MAX_OBJECT_TYPE_NUMBER]; PPH_GET_CLIENT_ID_NAME PhHandleGetClientIdName = PhStdGetClientIdName; static PPH_STRING HkcuPrefix; @@ -171,7 +170,7 @@ NTSTATUS PhpGetObjectTypeName( // If the cache contains the object type name, use it. Otherwise, // query the type name. - if (ObjectTypeNumber != -1 && ObjectTypeNumber <= MAX_OBJECT_TYPE_NUMBER) + if (ObjectTypeNumber != -1 && ObjectTypeNumber < MAX_OBJECT_TYPE_NUMBER) typeName = PhObjectTypeNames[ObjectTypeNumber]; if (typeName) @@ -928,7 +927,7 @@ NTSTATUS PhGetHandleInformation( if (Handle == NULL || Handle == NtCurrentProcess() || Handle == NtCurrentThread()) return STATUS_INVALID_HANDLE; - if (ObjectTypeNumber != -1 && ObjectTypeNumber > MAX_OBJECT_TYPE_NUMBER) + if (ObjectTypeNumber != -1 && ObjectTypeNumber >= MAX_OBJECT_TYPE_NUMBER) return STATUS_INVALID_PARAMETER_3; // Duplicate the handle if we're not using KPH. diff --git a/2.x/trunk/phlib/include/ph.h b/2.x/trunk/phlib/include/ph.h index 1d0314865..f1888f3c7 100644 --- a/2.x/trunk/phlib/include/ph.h +++ b/2.x/trunk/phlib/include/ph.h @@ -1074,6 +1074,8 @@ NTSTATUS PhEnumAccounts( // hndlinfo +#define MAX_OBJECT_TYPE_NUMBER 257 + VOID PhHandleInfoInitialization(); typedef PPH_STRING (NTAPI *PPH_GET_CLIENT_ID_NAME)(