Process Hacker
hndlstat.c
Go to the documentation of this file.
1 /*
2  * Process Hacker -
3  * handle statistics window
4  *
5  * Copyright (C) 2010 wj32
6  *
7  * This file is part of Process Hacker.
8  *
9  * Process Hacker is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * Process Hacker is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include <phapp.h>
24 
25 typedef struct _HANDLE_STATISTICS_ENTRY
26 {
27  PPH_STRING Name;
28  ULONG Count;
30 
31 typedef struct _HANDLE_STATISTICS_CONTEXT
32 {
33  HANDLE ProcessId;
34  HANDLE ProcessHandle;
35 
39 
40 INT_PTR CALLBACK PhpHandleStatisticsDlgProc(
41  _In_ HWND hwndDlg,
42  _In_ UINT uMsg,
43  _In_ WPARAM wParam,
44  _In_ LPARAM lParam
45  );
46 
48  _In_ HWND ParentWindowHandle,
49  _In_ HANDLE ProcessId
50  )
51 {
52  NTSTATUS status;
54  BOOLEAN filterNeeded;
55  ULONG i;
56 
57  context.ProcessId = ProcessId;
58 
59  if (!NT_SUCCESS(status = PhOpenProcess(
60  &context.ProcessHandle,
61  PROCESS_DUP_HANDLE,
62  ProcessId
63  )))
64  {
65  PhShowStatus(ParentWindowHandle, L"Unable to open the process", status, 0);
66  return;
67  }
68 
69  status = PhEnumHandlesGeneric(
70  context.ProcessId,
71  context.ProcessHandle,
72  &context.Handles,
73  &filterNeeded
74  );
75 
76  if (!NT_SUCCESS(status))
77  {
78  NtClose(context.ProcessHandle);
79  PhShowStatus(ParentWindowHandle, L"Unable to enumerate process handles", status, 0);
80  return;
81  }
82 
83  memset(&context.Entries, 0, sizeof(context.Entries));
84 
85  DialogBoxParam(
87  MAKEINTRESOURCE(IDD_HANDLESTATS),
88  ParentWindowHandle,
90  (LPARAM)&context
91  );
92 
93  for (i = 0; i < MAX_OBJECT_TYPE_NUMBER; i++)
94  {
95  if (context.Entries[i].Name)
96  PhDereferenceObject(context.Entries[i].Name);
97  }
98 
99  PhFree(context.Handles);
100  NtClose(context.ProcessHandle);
101 }
102 
103 static INT NTAPI PhpTypeCountCompareFunction(
104  _In_ PVOID Item1,
105  _In_ PVOID Item2,
106  _In_opt_ PVOID Context
107  )
108 {
109  PHANDLE_STATISTICS_ENTRY entry1 = Item1;
110  PHANDLE_STATISTICS_ENTRY entry2 = Item2;
111 
112  return uintcmp(entry1->Count, entry2->Count);
113 }
114 
115 INT_PTR CALLBACK PhpHandleStatisticsDlgProc(
116  _In_ HWND hwndDlg,
117  _In_ UINT uMsg,
118  _In_ WPARAM wParam,
119  _In_ LPARAM lParam
120  )
121 {
122  switch (uMsg)
123  {
124  case WM_INITDIALOG:
125  {
127  HANDLE processId;
128  ULONG_PTR i;
129  HWND lvHandle;
130 
131  processId = context->ProcessId;
132 
133  for (i = 0; i < context->Handles->NumberOfHandles; i++)
134  {
137  PPH_STRING typeName;
138 
139  handleInfo = &context->Handles->Handles[i];
140 
141  if (handleInfo->UniqueProcessId != (ULONG_PTR)processId)
142  continue;
143  if (handleInfo->ObjectTypeIndex >= MAX_OBJECT_TYPE_NUMBER)
144  continue;
145 
146  entry = &context->Entries[handleInfo->ObjectTypeIndex];
147 
148  if (!entry->Name)
149  {
150  typeName = NULL;
152  context->ProcessHandle,
153  (HANDLE)handleInfo->HandleValue,
154  handleInfo->ObjectTypeIndex,
155  NULL,
156  &typeName,
157  NULL,
158  NULL
159  );
160  entry->Name = typeName;
161  }
162 
163  entry->Count++;
164  }
165 
166  lvHandle = GetDlgItem(hwndDlg, IDC_LIST);
167  PhSetListViewStyle(lvHandle, FALSE, TRUE);
168  PhSetControlTheme(lvHandle, L"explorer");
169  PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 140, L"Type");
170  PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 100, L"Count");
171 
172  PhSetExtendedListView(lvHandle);
173  ExtendedListView_SetCompareFunction(lvHandle, 1, PhpTypeCountCompareFunction);
174 
175  for (i = 0; i < MAX_OBJECT_TYPE_NUMBER; i++)
176  {
178  PPH_STRING unknownType;
179  PPH_STRING countString;
180  INT lvItemIndex;
181 
182  entry = &context->Entries[i];
183 
184  if (entry->Count == 0)
185  continue;
186 
187  unknownType = NULL;
188 
189  if (!entry->Name)
190  unknownType = PhFormatString(L"(unknown: %u)", i);
191 
192  countString = PhFormatUInt64(entry->Count, TRUE);
193 
194  lvItemIndex = PhAddListViewItem(
195  lvHandle,
196  MAXINT,
197  entry->Name ? entry->Name->Buffer : unknownType->Buffer,
198  entry
199  );
200  PhSetListViewSubItem(lvHandle, lvItemIndex, 1, countString->Buffer);
201 
202  PhDereferenceObject(countString);
203 
204  if (unknownType)
205  PhDereferenceObject(unknownType);
206  }
207 
208  ExtendedListView_SortItems(lvHandle);
209  }
210  break;
211  case WM_DESTROY:
212  {
213  // Nothing
214  }
215  break;
216  case WM_COMMAND:
217  {
218  switch (LOWORD(wParam))
219  {
220  case IDCANCEL:
221  case IDOK:
222  EndDialog(hwndDlg, IDOK);
223  break;
224  }
225  }
226  break;
227  case WM_NOTIFY:
228  {
229  PhHandleListViewNotifyForCopy(lParam, GetDlgItem(hwndDlg, IDC_LIST));
230  }
231  break;
232  }
233 
234  return FALSE;
235 }