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)(