Process Hacker
procprp.c
Go to the documentation of this file.
1 /*
2  * Process Hacker -
3  * process properties
4  *
5  * Copyright (C) 2009-2015 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 #include <secedit.h>
25 #include <kphuser.h>
26 #include <settings.h>
27 #include <cpysave.h>
28 #include <emenu.h>
29 #include <phplug.h>
30 #include <extmgri.h>
31 #include <verify.h>
32 #include <procprpp.h>
33 #include <windowsx.h>
34 
35 #define SET_BUTTON_BITMAP(Id, Bitmap) \
36  SendMessage(GetDlgItem(hwndDlg, (Id)), BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)(Bitmap))
37 
40 
41 static RECT MinimumSize = { -1, -1, -1, -1 };
42 static PWSTR ProtectedSignerStrings[] = { L"", L" (Authenticode)", L" (CodeGen)", L" (Antimalware)", L" (Lsa)", L" (Windows)", L" (WinTcb)" };
43 
44 static PH_STRINGREF LoadingText = PH_STRINGREF_INIT(L"Loading...");
45 static PH_STRINGREF EmptyThreadsText = PH_STRINGREF_INIT(L"There are no threads to display.");
46 static PH_STRINGREF EmptyModulesText = PH_STRINGREF_INIT(L"There are no modules to display.");
47 static PH_STRINGREF EmptyMemoryText = PH_STRINGREF_INIT(L"There are no memory regions to display.");
48 static PH_STRINGREF EmptyHandlesText = PH_STRINGREF_INIT(L"There are no handles to display.");
49 
51  VOID
52  )
53 {
54  PhpProcessPropContextType = PhCreateObjectType(L"ProcessPropContext", 0, PhpProcessPropContextDeleteProcedure);
55  PhpProcessPropPageContextType = PhCreateObjectType(L"ProcessPropPageContext", 0, PhpProcessPropPageContextDeleteProcedure);
56 
57  return TRUE;
58 }
59 
61  _In_ HWND ParentWindowHandle,
62  _In_ PPH_PROCESS_ITEM ProcessItem
63  )
64 {
65  PPH_PROCESS_PROPCONTEXT propContext;
66  PROPSHEETHEADER propSheetHeader;
67 
68  propContext = PhCreateObject(sizeof(PH_PROCESS_PROPCONTEXT), PhpProcessPropContextType);
69  memset(propContext, 0, sizeof(PH_PROCESS_PROPCONTEXT));
70 
71  propContext->PropSheetPages = PhAllocate(sizeof(HPROPSHEETPAGE) * PH_PROCESS_PROPCONTEXT_MAXPAGES);
72 
73  if (!PH_IS_FAKE_PROCESS_ID(ProcessItem->ProcessId))
74  {
75  propContext->Title = PhFormatString(
76  L"%s (%u)",
77  ProcessItem->ProcessName->Buffer,
78  (ULONG)ProcessItem->ProcessId
79  );
80  }
81  else
82  {
83  PhSetReference(&propContext->Title, ProcessItem->ProcessName);
84  }
85 
86  memset(&propSheetHeader, 0, sizeof(PROPSHEETHEADER));
87  propSheetHeader.dwSize = sizeof(PROPSHEETHEADER);
88  propSheetHeader.dwFlags =
89  PSH_MODELESS |
90  PSH_NOAPPLYNOW |
91  PSH_NOCONTEXTHELP |
92  PSH_PROPTITLE |
93  PSH_USECALLBACK |
94  PSH_USEHICON;
95  propSheetHeader.hwndParent = ParentWindowHandle;
96  propSheetHeader.hIcon = ProcessItem->SmallIcon;
97  propSheetHeader.pszCaption = propContext->Title->Buffer;
98  propSheetHeader.pfnCallback = PhpPropSheetProc;
99 
100  propSheetHeader.nPages = 0;
101  propSheetHeader.nStartPage = 0;
102  propSheetHeader.phpage = propContext->PropSheetPages;
103 
104  if (PhCsForceNoParent)
105  propSheetHeader.hwndParent = NULL;
106 
107  memcpy(&propContext->PropSheetHeader, &propSheetHeader, sizeof(PROPSHEETHEADER));
108 
109  PhSetReference(&propContext->ProcessItem, ProcessItem);
110  PhInitializeEvent(&propContext->CreatedEvent);
111 
112  return propContext;
113 }
114 
116  _In_ PVOID Object,
117  _In_ ULONG Flags
118  )
119 {
120  PPH_PROCESS_PROPCONTEXT propContext = (PPH_PROCESS_PROPCONTEXT)Object;
121 
122  PhFree(propContext->PropSheetPages);
123  PhDereferenceObject(propContext->Title);
124  PhDereferenceObject(propContext->ProcessItem);
125 }
126 
128  _Inout_ PPH_PROCESS_PROPCONTEXT PropContext
129  )
130 {
131  PropContext->PropSheetHeader.hIcon = PropContext->ProcessItem->SmallIcon;
132 }
133 
135  _Inout_ PPH_PROCESS_PROPCONTEXT PropContext,
136  _In_ HANDLE ThreadId
137  )
138 {
139  PropContext->SelectThreadId = ThreadId;
140 }
141 
142 INT CALLBACK PhpPropSheetProc(
143  _In_ HWND hwndDlg,
144  _In_ UINT uMsg,
145  _In_ LPARAM lParam
146  )
147 {
148 #define PROPSHEET_ADD_STYLE (WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME);
149 
150  switch (uMsg)
151  {
152  case PSCB_PRECREATE:
153  {
154  if (lParam)
155  {
156  if (((DLGTEMPLATEEX *)lParam)->signature == 0xffff)
157  {
158  ((DLGTEMPLATEEX *)lParam)->style |= PROPSHEET_ADD_STYLE;
159  }
160  else
161  {
162  ((DLGTEMPLATE *)lParam)->style |= PROPSHEET_ADD_STYLE;
163  }
164  }
165  }
166  break;
167  case PSCB_INITIALIZED:
168  {
169  PPH_PROCESS_PROPSHEETCONTEXT propSheetContext;
170 
171  propSheetContext = PhAllocate(sizeof(PH_PROCESS_PROPSHEETCONTEXT));
172  memset(propSheetContext, 0, sizeof(PH_PROCESS_PROPSHEETCONTEXT));
173 
174  PhInitializeLayoutManager(&propSheetContext->LayoutManager, hwndDlg);
175 
176  propSheetContext->OldWndProc = (WNDPROC)GetWindowLongPtr(hwndDlg, GWLP_WNDPROC);
177  SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)PhpPropSheetWndProc);
178 
179  SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)propSheetContext);
180 
181  if (MinimumSize.left == -1)
182  {
183  RECT rect;
184 
185  rect.left = 0;
186  rect.top = 0;
187  rect.right = 290;
188  rect.bottom = 320;
189  MapDialogRect(hwndDlg, &rect);
190  MinimumSize = rect;
191  MinimumSize.left = 0;
192  }
193  }
194  break;
195  }
196 
197  return 0;
198 }
199 
201  _In_ HWND hwnd
202  )
203 {
204  return (PPH_PROCESS_PROPSHEETCONTEXT)GetProp(hwnd, PhMakeContextAtom());
205 }
206 
207 LRESULT CALLBACK PhpPropSheetWndProc(
208  _In_ HWND hwnd,
209  _In_ UINT uMsg,
210  _In_ WPARAM wParam,
211  _In_ LPARAM lParam
212  )
213 {
214  PPH_PROCESS_PROPSHEETCONTEXT propSheetContext = PhpGetPropSheetContext(hwnd);
215  WNDPROC oldWndProc = propSheetContext->OldWndProc;
216 
217  switch (uMsg)
218  {
219  case WM_DESTROY:
220  {
221  HWND tabControl;
222  TCITEM tabItem;
223  WCHAR text[128];
224 
225  // Save the window position and size.
226 
227  PhSaveWindowPlacementToSetting(L"ProcPropPosition", L"ProcPropSize", hwnd);
228 
229  // Save the selected tab.
230 
231  tabControl = PropSheet_GetTabControl(hwnd);
232 
233  tabItem.mask = TCIF_TEXT;
234  tabItem.pszText = text;
235  tabItem.cchTextMax = sizeof(text) / 2 - 1;
236 
237  if (TabCtrl_GetItem(tabControl, TabCtrl_GetCurSel(tabControl), &tabItem))
238  {
239  PhSetStringSetting(L"ProcPropPage", text);
240  }
241  }
242  break;
243  case WM_NCDESTROY:
244  {
245  SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc);
246  PhDeleteLayoutManager(&propSheetContext->LayoutManager);
247 
248  RemoveProp(hwnd, PhMakeContextAtom());
249  PhFree(propSheetContext);
250  }
251  break;
252  case WM_COMMAND:
253  {
254  switch (LOWORD(wParam))
255  {
256  case IDOK:
257  // Prevent the OK button from working (even though
258  // it's already hidden). This prevents the Enter
259  // key from closing the dialog box.
260  return 0;
261  }
262  }
263  break;
264  case WM_SIZE:
265  {
266  if (!IsIconic(hwnd))
267  {
268  PhLayoutManagerLayout(&propSheetContext->LayoutManager);
269  }
270  }
271  break;
272  case WM_SIZING:
273  {
274  PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom);
275  }
276  break;
277  }
278 
279  return CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam);
280 }
281 
283  _In_ HWND hwnd
284  )
285 {
286  PPH_PROCESS_PROPSHEETCONTEXT propSheetContext = PhpGetPropSheetContext(hwnd);
287 
288  if (!propSheetContext->LayoutInitialized)
289  {
290  HWND tabControlHandle;
291  PPH_LAYOUT_ITEM tabControlItem;
292  PPH_LAYOUT_ITEM tabPageItem;
293 
294  tabControlHandle = PropSheet_GetTabControl(hwnd);
295  tabControlItem = PhAddLayoutItem(&propSheetContext->LayoutManager, tabControlHandle,
297  tabPageItem = PhAddLayoutItem(&propSheetContext->LayoutManager, tabControlHandle,
298  NULL, PH_LAYOUT_TAB_CONTROL); // dummy item to fix multiline tab control
299 
300  propSheetContext->TabPageItem = tabPageItem;
301 
302  PhAddLayoutItem(&propSheetContext->LayoutManager, GetDlgItem(hwnd, IDCANCEL),
304 
305  // Hide the OK button.
306  ShowWindow(GetDlgItem(hwnd, IDOK), SW_HIDE);
307  // Set the Cancel button's text to "Close".
308  SetDlgItemText(hwnd, IDCANCEL, L"Close");
309 
310  propSheetContext->LayoutInitialized = TRUE;
311 
312  return TRUE;
313  }
314 
315  return FALSE;
316 }
317 
319  _In_ HWND hwnd
320  )
321 {
322  PH_RECTANGLE windowRectangle;
323 
324  windowRectangle.Position = PhGetIntegerPairSetting(L"ProcPropPosition");
325  windowRectangle.Size = PhGetIntegerPairSetting(L"ProcPropSize");
326 
327  if (windowRectangle.Size.X < MinimumSize.right)
328  windowRectangle.Size.X = MinimumSize.right;
329  if (windowRectangle.Size.Y < MinimumSize.bottom)
330  windowRectangle.Size.Y = MinimumSize.bottom;
331 
332  PhAdjustRectangleToWorkingArea(hwnd, &windowRectangle);
333 
334  MoveWindow(hwnd, windowRectangle.Left, windowRectangle.Top,
335  windowRectangle.Width, windowRectangle.Height, FALSE);
336 
337  // Implement cascading by saving an offsetted rectangle.
338  windowRectangle.Left += 20;
339  windowRectangle.Top += 20;
340 
341  PhSetIntegerPairSetting(L"ProcPropPosition", windowRectangle.Position);
342 }
343 
345  _Inout_ PPH_PROCESS_PROPCONTEXT PropContext,
346  _In_ _Assume_refs_(1) PPH_PROCESS_PROPPAGECONTEXT PropPageContext
347  )
348 {
349  HPROPSHEETPAGE propSheetPageHandle;
350 
351  if (PropContext->PropSheetHeader.nPages == PH_PROCESS_PROPCONTEXT_MAXPAGES)
352  return FALSE;
353 
354  propSheetPageHandle = CreatePropertySheetPage(
355  &PropPageContext->PropSheetPage
356  );
357  // CreatePropertySheetPage would have sent PSPCB_ADDREF,
358  // which would have added a reference.
359  PhDereferenceObject(PropPageContext);
360 
361  PropPageContext->PropContext = PropContext;
362  PhReferenceObject(PropContext);
363 
364  PropContext->PropSheetPages[PropContext->PropSheetHeader.nPages] =
365  propSheetPageHandle;
366  PropContext->PropSheetHeader.nPages++;
367 
368  return TRUE;
369 }
370 
372  _Inout_ PPH_PROCESS_PROPCONTEXT PropContext,
373  _In_ HPROPSHEETPAGE PropSheetPageHandle
374  )
375 {
376  if (PropContext->PropSheetHeader.nPages == PH_PROCESS_PROPCONTEXT_MAXPAGES)
377  return FALSE;
378 
379  PropContext->PropSheetPages[PropContext->PropSheetHeader.nPages] =
380  PropSheetPageHandle;
381  PropContext->PropSheetHeader.nPages++;
382 
383  return TRUE;
384 }
385 
387  _In_ LPCWSTR Template,
388  _In_ DLGPROC DlgProc,
389  _In_opt_ PVOID Context
390  )
391 {
392  return PhCreateProcessPropPageContextEx(NULL, Template, DlgProc, Context);
393 }
394 
396  _In_opt_ PVOID InstanceHandle,
397  _In_ LPCWSTR Template,
398  _In_ DLGPROC DlgProc,
399  _In_opt_ PVOID Context
400  )
401 {
402  PPH_PROCESS_PROPPAGECONTEXT propPageContext;
403 
404  propPageContext = PhCreateObject(sizeof(PH_PROCESS_PROPPAGECONTEXT), PhpProcessPropPageContextType);
405  memset(propPageContext, 0, sizeof(PH_PROCESS_PROPPAGECONTEXT));
406 
407  propPageContext->PropSheetPage.dwSize = sizeof(PROPSHEETPAGE);
408  propPageContext->PropSheetPage.dwFlags =
409  PSP_USECALLBACK;
410  propPageContext->PropSheetPage.hInstance = InstanceHandle;
411  propPageContext->PropSheetPage.pszTemplate = Template;
412  propPageContext->PropSheetPage.pfnDlgProc = DlgProc;
413  propPageContext->PropSheetPage.lParam = (LPARAM)propPageContext;
414  propPageContext->PropSheetPage.pfnCallback = PhpStandardPropPageProc;
415 
416  propPageContext->Context = Context;
417 
418  return propPageContext;
419 }
420 
422  _In_ PVOID Object,
423  _In_ ULONG Flags
424  )
425 {
427 
428  if (propPageContext->PropContext)
429  PhDereferenceObject(propPageContext->PropContext);
430 }
431 
433  _In_ HWND hwnd,
434  _In_ UINT uMsg,
435  _In_ LPPROPSHEETPAGE ppsp
436  )
437 {
438  PPH_PROCESS_PROPPAGECONTEXT propPageContext;
439 
440  propPageContext = (PPH_PROCESS_PROPPAGECONTEXT)ppsp->lParam;
441 
442  if (uMsg == PSPCB_ADDREF)
443  PhReferenceObject(propPageContext);
444  else if (uMsg == PSPCB_RELEASE)
445  PhDereferenceObject(propPageContext);
446 
447  return 1;
448 }
449 
450 FORCEINLINE BOOLEAN PhpPropPageDlgProcHeader(
451  _In_ HWND hwndDlg,
452  _In_ UINT uMsg,
453  _In_ LPARAM lParam,
454  _Out_ LPPROPSHEETPAGE *PropSheetPage,
455  _Out_ PPH_PROCESS_PROPPAGECONTEXT *PropPageContext,
456  _Out_ PPH_PROCESS_ITEM *ProcessItem
457  )
458 {
459  LPPROPSHEETPAGE propSheetPage;
460  PPH_PROCESS_PROPPAGECONTEXT propPageContext;
461 
462  if (uMsg == WM_INITDIALOG)
463  {
464  // Save the context.
465  SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)lParam);
466  }
467 
468  propSheetPage = (LPPROPSHEETPAGE)GetProp(hwndDlg, PhMakeContextAtom());
469 
470  if (!propSheetPage)
471  return FALSE;
472 
473  *PropSheetPage = propSheetPage;
474  *PropPageContext = propPageContext = (PPH_PROCESS_PROPPAGECONTEXT)propSheetPage->lParam;
475  *ProcessItem = propPageContext->PropContext->ProcessItem;
476 
477  return TRUE;
478 }
479 
481  _In_ HWND hwndDlg,
482  _In_ UINT uMsg,
483  _In_ LPARAM lParam,
484  _Out_ LPPROPSHEETPAGE *PropSheetPage,
485  _Out_ PPH_PROCESS_PROPPAGECONTEXT *PropPageContext,
486  _Out_ PPH_PROCESS_ITEM *ProcessItem
487  )
488 {
489  return PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam, PropSheetPage, PropPageContext, ProcessItem);
490 }
491 
493  _In_ HWND hwndDlg
494  )
495 {
496  RemoveProp(hwndDlg, PhMakeContextAtom());
497 }
498 
500  _In_ HWND hwndDlg
501  )
502 {
503  PhpPropPageDlgProcDestroy(hwndDlg);
504 }
505 
507  _In_ HWND hwnd,
508  _In_ HWND Handle,
509  _In_ PPH_LAYOUT_ITEM ParentItem,
510  _In_ ULONG Anchor
511  )
512 {
513  HWND parent;
514  PPH_PROCESS_PROPSHEETCONTEXT propSheetContext;
515  PPH_LAYOUT_MANAGER layoutManager;
516  PPH_LAYOUT_ITEM realParentItem;
517  BOOLEAN doLayoutStage2;
518  PPH_LAYOUT_ITEM item;
519 
520  parent = GetParent(hwnd);
521  propSheetContext = PhpGetPropSheetContext(parent);
522  layoutManager = &propSheetContext->LayoutManager;
523 
524  doLayoutStage2 = PhpInitializePropSheetLayoutStage1(parent);
525 
526  if (ParentItem != PH_PROP_PAGE_TAB_CONTROL_PARENT)
527  realParentItem = ParentItem;
528  else
529  realParentItem = propSheetContext->TabPageItem;
530 
531  // Use the HACK if the control is a direct child of the dialog.
532  if (ParentItem && ParentItem != PH_PROP_PAGE_TAB_CONTROL_PARENT &&
533  // We detect if ParentItem is the layout item for the dialog
534  // by looking at its parent.
535  (ParentItem->ParentItem == &layoutManager->RootItem ||
536  (ParentItem->ParentItem->Anchor & PH_LAYOUT_TAB_CONTROL)))
537  {
538  RECT dialogRect;
539  RECT dialogSize;
540  RECT margin;
541 
542  // MAKE SURE THESE NUMBERS ARE CORRECT.
543  dialogSize.right = 260;
544  dialogSize.bottom = 260;
545  MapDialogRect(hwnd, &dialogSize);
546 
547  // Get the original dialog rectangle.
548  GetWindowRect(hwnd, &dialogRect);
549  dialogRect.right = dialogRect.left + dialogSize.right;
550  dialogRect.bottom = dialogRect.top + dialogSize.bottom;
551 
552  // Calculate the margin from the original rectangle.
553  GetWindowRect(Handle, &margin);
554  margin = PhMapRect(margin, dialogRect);
555  PhConvertRect(&margin, &dialogRect);
556 
557  item = PhAddLayoutItemEx(layoutManager, Handle, realParentItem, Anchor, margin);
558  }
559  else
560  {
561  item = PhAddLayoutItem(layoutManager, Handle, realParentItem, Anchor);
562  }
563 
564  if (doLayoutStage2)
566 
567  return item;
568 }
569 
571  _In_ HWND hwnd
572  )
573 {
574  HWND parent;
575  PPH_PROCESS_PROPSHEETCONTEXT propSheetContext;
576 
577  parent = GetParent(hwnd);
578  propSheetContext = PhpGetPropSheetContext(parent);
579  PhLayoutManagerLayout(&propSheetContext->LayoutManager);
580 }
581 
583  _Out_ PHANDLE Handle,
584  _In_ ACCESS_MASK DesiredAccess,
585  _In_opt_ PVOID Context
586  )
587 {
588  return PhOpenProcess(Handle, DesiredAccess, (HANDLE)Context);
589 }
590 
591 FORCEINLINE PWSTR PhpGetStringOrNa(
592  _In_ PPH_STRING String
593  )
594 {
595  if (String)
596  return String->Buffer;
597  else
598  return L"N/A";
599 }
600 
602  _In_ HWND hwndDlg,
603  _In_ PPH_PROCESS_ITEM ProcessItem
604  )
605 {
606  HANDLE processHandle;
607  ULONG depStatus;
608 
609 #ifdef _WIN64
610  if (ProcessItem->IsWow64)
611 #else
612  if (TRUE)
613 #endif
614  {
615  SetDlgItemText(hwndDlg, IDC_DEP, L"N/A");
616 
618  &processHandle,
620  ProcessItem->ProcessId
621  )))
622  {
623  if (NT_SUCCESS(PhGetProcessDepStatus(processHandle, &depStatus)))
624  {
625  PPH_STRING depString;
626 
627  if (depStatus & PH_PROCESS_DEP_ENABLED)
628  depString = PhaCreateString(L"Enabled");
629  else
630  depString = PhaCreateString(L"Disabled");
631 
632  if ((depStatus & PH_PROCESS_DEP_ENABLED) &&
634  {
635  depString = PhaConcatStrings2(depString->Buffer, L", DEP-ATL thunk emulation disabled");
636  }
637 
638  if (depStatus & PH_PROCESS_DEP_PERMANENT)
639  {
640  depString = PhaConcatStrings2(depString->Buffer, L", Permanent");
641  }
642 
643  SetDlgItemText(hwndDlg, IDC_DEP, depString->Buffer);
644  EnableWindow(GetDlgItem(hwndDlg, IDC_EDITDEP), !(depStatus & PH_PROCESS_DEP_PERMANENT));
645  }
646 
647  NtClose(processHandle);
648  }
649  }
650  else
651  {
652  if (ProcessItem->QueryHandle)
653  SetDlgItemText(hwndDlg, IDC_DEP, L"Enabled, Permanent");
654  else
655  SetDlgItemText(hwndDlg, IDC_DEP, L"N/A");
656  }
657 }
658 
659 INT_PTR CALLBACK PhpProcessGeneralDlgProc(
660  _In_ HWND hwndDlg,
661  _In_ UINT uMsg,
662  _In_ WPARAM wParam,
663  _In_ LPARAM lParam
664  )
665 {
666  LPPROPSHEETPAGE propSheetPage;
667  PPH_PROCESS_PROPPAGECONTEXT propPageContext;
668  PPH_PROCESS_ITEM processItem;
669 
670  if (!PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam,
671  &propSheetPage, &propPageContext, &processItem))
672  return FALSE;
673 
674  switch (uMsg)
675  {
676  case WM_INITDIALOG:
677  {
678  HANDLE processHandle = NULL;
679  PPH_STRING curdir = NULL;
680  PROCESS_BASIC_INFORMATION basicInfo;
681 #ifdef _WIN64
682  PVOID peb32;
683 #endif
684  PPH_PROCESS_ITEM parentProcess;
685  CLIENT_ID clientId;
686 
687  {
688  HBITMAP folder;
689  HBITMAP magnifier;
690  HBITMAP pencil;
691 
692  folder = PH_LOAD_SHARED_IMAGE(MAKEINTRESOURCE(IDB_FOLDER), IMAGE_BITMAP);
693  magnifier = PH_LOAD_SHARED_IMAGE(MAKEINTRESOURCE(IDB_MAGNIFIER), IMAGE_BITMAP);
694  pencil = PH_LOAD_SHARED_IMAGE(MAKEINTRESOURCE(IDB_PENCIL), IMAGE_BITMAP);
695 
696  SET_BUTTON_BITMAP(IDC_INSPECT, magnifier);
700  }
701 
702  // File
703 
704  SendMessage(GetDlgItem(hwndDlg, IDC_FILEICON), STM_SETICON,
705  (WPARAM)processItem->LargeIcon, 0);
706 
707  if (PH_IS_REAL_PROCESS_ID(processItem->ProcessId))
708  {
709  SetDlgItemText(hwndDlg, IDC_NAME, PhpGetStringOrNa(processItem->VersionInfo.FileDescription));
710  }
711  else
712  {
713  SetDlgItemText(hwndDlg, IDC_NAME, processItem->ProcessName->Buffer);
714  }
715 
716  SetDlgItemText(hwndDlg, IDC_VERSION, PhpGetStringOrNa(processItem->VersionInfo.FileVersion));
717  SetDlgItemText(hwndDlg, IDC_FILENAME, PhpGetStringOrNa(processItem->FileName));
718 
719  if (!processItem->FileName)
720  EnableWindow(GetDlgItem(hwndDlg, IDC_OPENFILENAME), FALSE);
721 
722  {
723  PPH_STRING inspectExecutables;
724 
725  inspectExecutables = PhGetStringSetting(L"ProgramInspectExecutables");
726 
727  if (!processItem->FileName || inspectExecutables->Length == 0)
728  {
729  EnableWindow(GetDlgItem(hwndDlg, IDC_INSPECT), FALSE);
730  }
731 
732  PhDereferenceObject(inspectExecutables);
733  }
734 
735  if (processItem->VerifyResult == VrTrusted)
736  {
737  if (processItem->VerifySignerName)
738  {
739  SetDlgItemText(hwndDlg, IDC_COMPANYNAME_LINK,
740  PhaFormatString(L"<a>(Verified) %s</a>", processItem->VerifySignerName->Buffer)->Buffer);
741  ShowWindow(GetDlgItem(hwndDlg, IDC_COMPANYNAME), SW_HIDE);
742  ShowWindow(GetDlgItem(hwndDlg, IDC_COMPANYNAME_LINK), SW_SHOW);
743  }
744  else
745  {
746  SetDlgItemText(hwndDlg, IDC_COMPANYNAME,
748  L"(Verified) ",
750  )->Buffer);
751  }
752  }
753  else if (processItem->VerifyResult != VrUnknown)
754  {
755  SetDlgItemText(hwndDlg, IDC_COMPANYNAME,
757  L"(UNVERIFIED) ",
759  )->Buffer);
760  }
761  else
762  {
763  SetDlgItemText(hwndDlg, IDC_COMPANYNAME,
765  }
766 
767  // Command Line
768 
769  SetDlgItemText(hwndDlg, IDC_CMDLINE, PhpGetStringOrNa(processItem->CommandLine));
770 
771  // Current Directory
772 
774  &processHandle,
776  processItem->ProcessId
777  )))
778  {
779  PH_PEB_OFFSET pebOffset;
780 
781  pebOffset = PhpoCurrentDirectory;
782 
783 #ifdef _WIN64
784  // Tell the function to get the WOW64 current directory, because that's
785  // the one that actually gets updated.
786  if (processItem->IsWow64)
787  pebOffset |= PhpoWow64;
788 #endif
789 
791  processHandle,
792  pebOffset,
793  &curdir
794  );
795 
796  NtClose(processHandle);
797  processHandle = NULL;
798  }
799 
800  SetDlgItemText(hwndDlg, IDC_CURDIR,
801  PhpGetStringOrNa(curdir));
802 
803  if (curdir)
804  PhDereferenceObject(curdir);
805 
806  // Started
807 
808  if (processItem->CreateTime.QuadPart != 0)
809  {
810  LARGE_INTEGER startTime;
811  LARGE_INTEGER currentTime;
812  SYSTEMTIME startTimeFields;
813  PPH_STRING startTimeRelativeString;
814  PPH_STRING startTimeString;
815 
816  startTime = processItem->CreateTime;
817  PhQuerySystemTime(&currentTime);
818  startTimeRelativeString = PhAutoDereferenceObject(PhFormatTimeSpanRelative(currentTime.QuadPart - startTime.QuadPart));
819 
820  PhLargeIntegerToLocalSystemTime(&startTimeFields, &startTime);
821  startTimeString = PhaFormatDateTime(&startTimeFields);
822 
823  SetDlgItemText(hwndDlg, IDC_STARTED,
824  PhaFormatString(L"%s ago (%s)", startTimeRelativeString->Buffer, startTimeString->Buffer)->Buffer);
825  }
826  else
827  {
828  SetDlgItemText(hwndDlg, IDC_STARTED, L"N/A");
829  }
830 
831  // Parent
832 
833  if (parentProcess = PhReferenceProcessItemForParent(
834  processItem->ParentProcessId,
835  processItem->ProcessId,
836  &processItem->CreateTime
837  ))
838  {
839  clientId.UniqueProcess = parentProcess->ProcessId;
840  clientId.UniqueThread = NULL;
841 
842  SetDlgItemText(hwndDlg, IDC_PARENTPROCESS,
843  ((PPH_STRING)PhAutoDereferenceObject(PhGetClientIdNameEx(&clientId, parentProcess->ProcessName)))->Buffer);
844 
845  PhDereferenceObject(parentProcess);
846  }
847  else
848  {
849  SetDlgItemText(hwndDlg, IDC_PARENTPROCESS,
850  PhaFormatString(L"Non-existent process (%u)", (ULONG)processItem->ParentProcessId)->Buffer);
851  EnableWindow(GetDlgItem(hwndDlg, IDC_VIEWPARENTPROCESS), FALSE);
852  }
853 
854  // DEP
855 
856  PhpUpdateProcessDep(hwndDlg, processItem);
857 
858  // PEB address
859 
860  SetDlgItemText(hwndDlg, IDC_PEBADDRESS, L"N/A");
861 
863  &processHandle,
865  processItem->ProcessId
866  );
867 
868  if (processHandle)
869  {
870  PhGetProcessBasicInformation(processHandle, &basicInfo);
871 #ifdef _WIN64
872  if (processItem->IsWow64)
873  {
874  PhGetProcessPeb32(processHandle, &peb32);
875  SetDlgItemText(hwndDlg, IDC_PEBADDRESS,
876  PhaFormatString(L"0x%Ix (32-bit: 0x%x)", basicInfo.PebBaseAddress, (ULONG)peb32)->Buffer);
877  }
878  else
879  {
880 #endif
881 
882  SetDlgItemText(hwndDlg, IDC_PEBADDRESS,
883  PhaFormatString(L"0x%Ix", basicInfo.PebBaseAddress)->Buffer);
884 #ifdef _WIN64
885  }
886 #endif
887  }
888 
889  // Protection
890 
891  SetDlgItemText(hwndDlg, IDC_PROTECTION, L"N/A");
892 
893  if (WINDOWS_HAS_LIMITED_ACCESS && processHandle)
894  {
896  {
897  PS_PROTECTION protection;
898 
899  if (NT_SUCCESS(NtQueryInformationProcess(
900  processHandle,
901  ProcessProtectionInformation,
902  &protection,
903  sizeof(PS_PROTECTION),
904  NULL
905  )))
906  {
907  PWSTR type;
908  PWSTR signer;
909 
910  switch (protection.Type)
911  {
912  case PsProtectedTypeNone:
913  type = L"None";
914  break;
915  case PsProtectedTypeProtectedLight:
916  type = L"Light";
917  break;
918  case PsProtectedTypeProtected:
919  type = L"Full";
920  break;
921  default:
922  type = L"Unknown";
923  break;
924  }
925 
926  if (protection.Signer < sizeof(ProtectedSignerStrings) / sizeof(PWSTR))
927  signer = ProtectedSignerStrings[protection.Signer];
928  else
929  signer = L"";
930 
931  SetDlgItemText(hwndDlg, IDC_PROTECTION, PhaConcatStrings2(type, signer)->Buffer);
932  }
933  }
934  else if (KphIsConnected())
935  {
936  KPH_PROCESS_PROTECTION_INFORMATION protectionInfo;
937 
939  processHandle,
941  &protectionInfo,
943  NULL
944  )))
945  {
946  SetDlgItemText(hwndDlg, IDC_PROTECTION, protectionInfo.IsProtectedProcess ? L"Yes" : L"None");
947  EnableWindow(GetDlgItem(hwndDlg, IDC_EDITPROTECTION), TRUE);
948  }
949  }
950  else
951  {
952  PROCESS_EXTENDED_BASIC_INFORMATION extendedBasicInfo;
953 
955  processHandle,
956  &extendedBasicInfo
957  )))
958  {
959  SetDlgItemText(hwndDlg, IDC_PROTECTION, extendedBasicInfo.IsProtectedProcess ? L"Yes" : L"None");
960  }
961  }
962  }
963 
964  if (processHandle)
965  NtClose(processHandle);
966 
967  if (WindowsVersion >= WINDOWS_8)
968  {
969  PROCESS_MITIGATION_POLICY_INFORMATION policyInfo;
970 
971  SetDlgItemText(hwndDlg, IDC_ASLR, L"N/A");
972 
973  policyInfo.Policy = ProcessASLRPolicy;
974 
976  &processHandle,
978  processItem->ProcessId
979  )))
980  {
981  if (NT_SUCCESS(NtQueryInformationProcess(
982  processHandle,
983  ProcessMitigationPolicy,
984  &policyInfo,
985  sizeof(PROCESS_MITIGATION_POLICY_INFORMATION),
986  NULL
987  )))
988  {
990 
991  PhInitializeStringBuilder(&sb, 40);
992 
993  if (policyInfo.ASLRPolicy.EnableBottomUpRandomization)
994  PhAppendStringBuilder2(&sb, L"Bottom up randomization, ");
995  if (policyInfo.ASLRPolicy.EnableForceRelocateImages)
996  PhAppendStringBuilder2(&sb, L"Force relocate images, ");
997  if (policyInfo.ASLRPolicy.EnableHighEntropy)
998  PhAppendStringBuilder2(&sb, L"High entropy, ");
999  if (policyInfo.ASLRPolicy.DisallowStrippedImages)
1000  PhAppendStringBuilder2(&sb, L"Disallow stripped images, ");
1001  if (sb.String->Length != 0)
1002  PhRemoveEndStringBuilder(&sb, 2);
1003 
1004  if (sb.String->Length == 0)
1005  SetDlgItemText(hwndDlg, IDC_ASLR, L"Disabled");
1006  else
1007  SetDlgItemText(hwndDlg, IDC_ASLR, sb.String->Buffer);
1008 
1009  PhDeleteStringBuilder(&sb);
1010  }
1011 
1012  NtClose(processHandle);
1013  }
1014  }
1015  else
1016  {
1017  ShowWindow(GetDlgItem(hwndDlg, IDC_ASLRLABEL), SW_HIDE);
1018  ShowWindow(GetDlgItem(hwndDlg, IDC_ASLR), SW_HIDE);
1019  }
1020 
1021 #ifdef _WIN64
1022  if (processItem->IsWow64Valid)
1023  {
1024  if (processItem->IsWow64)
1025  SetDlgItemText(hwndDlg, IDC_PROCESSTYPETEXT, L"32-bit");
1026  else
1027  SetDlgItemText(hwndDlg, IDC_PROCESSTYPETEXT, L"64-bit");
1028  }
1029  else
1030  {
1031  SetDlgItemText(hwndDlg, IDC_PROCESSTYPETEXT, L"N/A");
1032  }
1033 
1034  ShowWindow(GetDlgItem(hwndDlg, IDC_PROCESSTYPELABEL), SW_SHOW);
1035  ShowWindow(GetDlgItem(hwndDlg, IDC_PROCESSTYPETEXT), SW_SHOW);
1036 #endif
1037  }
1038  break;
1039  case WM_DESTROY:
1040  {
1041  PhpPropPageDlgProcDestroy(hwndDlg);
1042  }
1043  break;
1044  case WM_SHOWWINDOW:
1045  {
1046  if (!propPageContext->LayoutInitialized)
1047  {
1048  PPH_LAYOUT_ITEM dialogItem;
1049 
1050  dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg,
1052  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_FILE),
1053  dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
1054  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_NAME),
1055  dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
1056  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_COMPANYNAME),
1057  dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
1058  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_COMPANYNAME_LINK),
1059  dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
1060  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_VERSION),
1061  dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
1062  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_FILENAME),
1063  dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
1064  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_INSPECT),
1065  dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
1066  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_OPENFILENAME),
1067  dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
1068  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_CMDLINE),
1069  dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
1070  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_CURDIR),
1071  dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
1072  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_STARTED),
1073  dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
1074  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PEBADDRESS),
1075  dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
1076  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PARENTPROCESS),
1077  dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
1078  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_VIEWPARENTPROCESS),
1079  dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
1080  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_DEP),
1081  dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
1082  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_EDITDEP),
1083  dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
1084  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_ASLR),
1085  dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
1086  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_TERMINATE),
1087  dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_TOP);
1088  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PERMISSIONS),
1089  dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_TOP);
1090  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PROCESS),
1091  dialogItem, PH_ANCHOR_ALL);
1092 
1093  PhDoPropPageLayout(hwndDlg);
1094 
1095  propPageContext->LayoutInitialized = TRUE;
1096  }
1097  }
1098  break;
1099  case WM_COMMAND:
1100  {
1101  INT id = LOWORD(wParam);
1102 
1103  switch (id)
1104  {
1105  case IDC_INSPECT:
1106  {
1107  if (processItem->FileName)
1108  {
1110  hwndDlg,
1111  L"ProgramInspectExecutables",
1112  processItem->FileName->Buffer,
1113  FALSE,
1114  L"Make sure the PE Viewer executable file is present."
1115  );
1116  }
1117  }
1118  break;
1119  case IDC_OPENFILENAME:
1120  {
1121  if (processItem->FileName)
1122  PhShellExploreFile(hwndDlg, processItem->FileName->Buffer);
1123  }
1124  break;
1125  case IDC_VIEWPARENTPROCESS:
1126  {
1127  PPH_PROCESS_ITEM parentProcessItem;
1128 
1129  if (parentProcessItem = PhReferenceProcessItem(processItem->ParentProcessId))
1130  {
1132  PhDereferenceObject(parentProcessItem);
1133  }
1134  else
1135  {
1136  PhShowError(hwndDlg, L"The process does not exist.");
1137  }
1138  }
1139  break;
1140  case IDC_EDITDEP:
1141  {
1142  if (PhUiSetDepStatusProcess(hwndDlg, processItem))
1143  PhpUpdateProcessDep(hwndDlg, processItem);
1144  }
1145  break;
1146  case IDC_TERMINATE:
1147  {
1149  hwndDlg,
1150  &processItem,
1151  1
1152  );
1153  }
1154  break;
1155  case IDC_PERMISSIONS:
1156  {
1157  PH_STD_OBJECT_SECURITY stdObjectSecurity;
1158  PPH_ACCESS_ENTRY accessEntries;
1159  ULONG numberOfAccessEntries;
1160 
1161  stdObjectSecurity.OpenObject = PhpProcessGeneralOpenProcess;
1162  stdObjectSecurity.ObjectType = L"Process";
1163  stdObjectSecurity.Context = processItem->ProcessId;
1164 
1165  if (PhGetAccessEntries(L"Process", &accessEntries, &numberOfAccessEntries))
1166  {
1168  hwndDlg,
1169  processItem->ProcessName->Buffer,
1172  &stdObjectSecurity,
1173  accessEntries,
1174  numberOfAccessEntries
1175  );
1176  PhFree(accessEntries);
1177  }
1178  }
1179  break;
1180  }
1181  }
1182  break;
1183  case WM_NOTIFY:
1184  {
1185  LPNMHDR header = (LPNMHDR)lParam;
1186 
1187  switch (header->code)
1188  {
1189  case NM_CLICK:
1190  {
1191  switch (header->idFrom)
1192  {
1193  case IDC_COMPANYNAME_LINK:
1194  {
1195  if (processItem->FileName)
1196  {
1197  PH_VERIFY_FILE_INFO info;
1198 
1199  memset(&info, 0, sizeof(PH_VERIFY_FILE_INFO));
1200  info.FileName = processItem->FileName->Buffer;
1202  info.hWnd = hwndDlg;
1204  &info,
1205  PhGetString(processItem->PackageFullName),
1206  NULL
1207  );
1208  }
1209  }
1210  break;
1211  }
1212  }
1213  break;
1214  }
1215  }
1216  break;
1217  }
1218 
1219  return FALSE;
1220 }
1221 
1222 static VOID NTAPI StatisticsUpdateHandler(
1223  _In_opt_ PVOID Parameter,
1224  _In_opt_ PVOID Context
1225  )
1226 {
1227  PPH_STATISTICS_CONTEXT statisticsContext = (PPH_STATISTICS_CONTEXT)Context;
1228 
1229  if (statisticsContext->Enabled)
1230  PostMessage(statisticsContext->WindowHandle, WM_PH_STATISTICS_UPDATE, 0, 0);
1231 }
1232 
1234  _In_ HWND hwndDlg,
1235  _In_ PPH_PROCESS_ITEM ProcessItem,
1236  _In_ PPH_STATISTICS_CONTEXT Context
1237  )
1238 {
1239  WCHAR timeSpan[PH_TIMESPAN_STR_LEN_1];
1240 
1241  SetDlgItemInt(hwndDlg, IDC_ZPRIORITY_V, ProcessItem->BasePriority, TRUE); // priority
1242  PhPrintTimeSpan(timeSpan, ProcessItem->KernelTime.QuadPart, PH_TIMESPAN_HMSM); // kernel time
1243  SetDlgItemText(hwndDlg, IDC_ZKERNELTIME_V, timeSpan);
1244  PhPrintTimeSpan(timeSpan, ProcessItem->UserTime.QuadPart, PH_TIMESPAN_HMSM); // user time
1245  SetDlgItemText(hwndDlg, IDC_ZUSERTIME_V, timeSpan);
1246  PhPrintTimeSpan(timeSpan,
1247  ProcessItem->KernelTime.QuadPart + ProcessItem->UserTime.QuadPart, PH_TIMESPAN_HMSM); // total time
1248  SetDlgItemText(hwndDlg, IDC_ZTOTALTIME_V, timeSpan);
1249 
1250  SetDlgItemText(hwndDlg, IDC_ZPRIVATEBYTES_V,
1251  PhaFormatSize(ProcessItem->VmCounters.PagefileUsage, -1)->Buffer); // private bytes (same as PrivateUsage)
1252  SetDlgItemText(hwndDlg, IDC_ZPEAKPRIVATEBYTES_V,
1253  PhaFormatSize(ProcessItem->VmCounters.PeakPagefileUsage, -1)->Buffer); // peak private bytes
1254  SetDlgItemText(hwndDlg, IDC_ZVIRTUALSIZE_V,
1255  PhaFormatSize(ProcessItem->VmCounters.VirtualSize, -1)->Buffer); // virtual size
1256  SetDlgItemText(hwndDlg, IDC_ZPEAKVIRTUALSIZE_V,
1257  PhaFormatSize(ProcessItem->VmCounters.PeakVirtualSize, -1)->Buffer); // peak virtual size
1258  SetDlgItemText(hwndDlg, IDC_ZPAGEFAULTS_V,
1259  PhaFormatUInt64(ProcessItem->VmCounters.PageFaultCount, TRUE)->Buffer); // page faults
1260  SetDlgItemText(hwndDlg, IDC_ZWORKINGSET_V,
1261  PhaFormatSize(ProcessItem->VmCounters.WorkingSetSize, -1)->Buffer); // working set
1262  SetDlgItemText(hwndDlg, IDC_ZPEAKWORKINGSET_V,
1263  PhaFormatSize(ProcessItem->VmCounters.PeakWorkingSetSize, -1)->Buffer); // peak working set
1264 
1265  SetDlgItemText(hwndDlg, IDC_ZIOREADS_V,
1266  PhaFormatUInt64(ProcessItem->IoCounters.ReadOperationCount, TRUE)->Buffer); // reads
1267  SetDlgItemText(hwndDlg, IDC_ZIOREADBYTES_V,
1268  PhaFormatSize(ProcessItem->IoCounters.ReadTransferCount, -1)->Buffer); // read bytes
1269  SetDlgItemText(hwndDlg, IDC_ZIOWRITES_V,
1270  PhaFormatUInt64(ProcessItem->IoCounters.WriteOperationCount, TRUE)->Buffer); // writes
1271  SetDlgItemText(hwndDlg, IDC_ZIOWRITEBYTES_V,
1272  PhaFormatSize(ProcessItem->IoCounters.WriteTransferCount, -1)->Buffer); // write bytes
1273  SetDlgItemText(hwndDlg, IDC_ZIOOTHER_V,
1274  PhaFormatUInt64(ProcessItem->IoCounters.OtherOperationCount, TRUE)->Buffer); // other
1275  SetDlgItemText(hwndDlg, IDC_ZIOOTHERBYTES_V,
1276  PhaFormatSize(ProcessItem->IoCounters.OtherTransferCount, -1)->Buffer); // read bytes
1277 
1278  SetDlgItemText(hwndDlg, IDC_ZHANDLES_V,
1279  PhaFormatUInt64(ProcessItem->NumberOfHandles, TRUE)->Buffer); // handles
1280 
1281  // Optional information
1282  if (!PH_IS_FAKE_PROCESS_ID(ProcessItem->ProcessId))
1283  {
1284  PPH_STRING peakHandles = NULL;
1285  PPH_STRING gdiHandles = NULL;
1286  PPH_STRING userHandles = NULL;
1287  PPH_STRING cycles = NULL;
1288  ULONG pagePriority = -1;
1289  ULONG ioPriority = -1;
1290  PPH_STRING privateWs = NULL;
1291  PPH_STRING shareableWs = NULL;
1292  PPH_STRING sharedWs = NULL;
1293  BOOLEAN gotCycles = FALSE;
1294  BOOLEAN gotWsCounters = FALSE;
1295 
1296  if (ProcessItem->QueryHandle)
1297  {
1298  ULONG64 cycleTime;
1299 
1300  if (WindowsVersion >= WINDOWS_7)
1301  {
1302  PROCESS_HANDLE_INFORMATION handleInfo;
1303 
1304  if (NT_SUCCESS(NtQueryInformationProcess(
1305  ProcessItem->QueryHandle,
1306  ProcessHandleCount,
1307  &handleInfo,
1309  NULL
1310  )))
1311  {
1312  peakHandles = PhaFormatUInt64(handleInfo.HandleCountHighWatermark, TRUE);
1313  }
1314  }
1315 
1316  gdiHandles = PhaFormatUInt64(GetGuiResources(ProcessItem->QueryHandle, GR_GDIOBJECTS), TRUE); // GDI handles
1317  userHandles = PhaFormatUInt64(GetGuiResources(ProcessItem->QueryHandle, GR_USEROBJECTS), TRUE); // USER handles
1318 
1319  if (WINDOWS_HAS_CYCLE_TIME &&
1320  NT_SUCCESS(PhGetProcessCycleTime(ProcessItem->QueryHandle, &cycleTime)))
1321  {
1322  cycles = PhaFormatUInt64(cycleTime, TRUE);
1323  gotCycles = TRUE;
1324  }
1325 
1327  {
1328  PhGetProcessPagePriority(ProcessItem->QueryHandle, &pagePriority);
1329  PhGetProcessIoPriority(ProcessItem->QueryHandle, &ioPriority);
1330  }
1331  }
1332 
1333  if (Context->ProcessHandle)
1334  {
1335  PH_PROCESS_WS_COUNTERS wsCounters;
1336 
1337  if (NT_SUCCESS(PhGetProcessWsCounters(Context->ProcessHandle, &wsCounters)))
1338  {
1339  privateWs = PhaFormatSize((ULONG64)wsCounters.NumberOfPrivatePages * PAGE_SIZE, -1);
1340  shareableWs = PhaFormatSize((ULONG64)wsCounters.NumberOfShareablePages * PAGE_SIZE, -1);
1341  sharedWs = PhaFormatSize((ULONG64)wsCounters.NumberOfSharedPages * PAGE_SIZE, -1);
1342  gotWsCounters = TRUE;
1343  }
1344  }
1345 
1346  if (WindowsVersion >= WINDOWS_7)
1347  {
1348  if (!gotCycles)
1349  cycles = PhaFormatUInt64(ProcessItem->CycleTimeDelta.Value, TRUE);
1350  if (!gotWsCounters)
1351  privateWs = PhaFormatSize(ProcessItem->WorkingSetPrivateSize, -1);
1352  }
1353 
1354  if (WindowsVersion >= WINDOWS_7)
1355  SetDlgItemText(hwndDlg, IDC_ZPEAKHANDLES_V, PhGetStringOrDefault(peakHandles, L"Unknown"));
1356  else
1357  SetDlgItemText(hwndDlg, IDC_ZPEAKHANDLES_V, L"N/A");
1358 
1359  SetDlgItemText(hwndDlg, IDC_ZGDIHANDLES_V, PhGetStringOrDefault(gdiHandles, L"Unknown"));
1360  SetDlgItemText(hwndDlg, IDC_ZUSERHANDLES_V, PhGetStringOrDefault(userHandles, L"Unknown"));
1361  SetDlgItemText(hwndDlg, IDC_ZCYCLES_V,
1362  PhGetStringOrDefault(cycles, WINDOWS_HAS_CYCLE_TIME ? L"Unknown" : L"N/A"));
1363 
1365  {
1366  if (pagePriority != -1)
1367  SetDlgItemInt(hwndDlg, IDC_ZPAGEPRIORITY_V, pagePriority, FALSE);
1368  else
1369  SetDlgItemText(hwndDlg, IDC_ZPAGEPRIORITY_V, L"Unknown");
1370 
1371  if (ioPriority != -1 && ioPriority < MaxIoPriorityTypes)
1372  SetDlgItemText(hwndDlg, IDC_ZIOPRIORITY_V, PhIoPriorityHintNames[ioPriority]);
1373  else
1374  SetDlgItemText(hwndDlg, IDC_ZIOPRIORITY_V, L"Unknown");
1375  }
1376  else
1377  {
1378  SetDlgItemText(hwndDlg, IDC_ZPAGEPRIORITY_V, L"N/A");
1379  SetDlgItemText(hwndDlg, IDC_ZIOPRIORITY_V, L"N/A");
1380  }
1381 
1382  SetDlgItemText(hwndDlg, IDC_ZPRIVATEWS_V, PhGetStringOrDefault(privateWs, L"Unknown"));
1383  SetDlgItemText(hwndDlg, IDC_ZSHAREABLEWS_V, PhGetStringOrDefault(shareableWs, L"Unknown"));
1384  SetDlgItemText(hwndDlg, IDC_ZSHAREDWS_V, PhGetStringOrDefault(sharedWs, L"Unknown"));
1385  }
1386  else
1387  {
1388  SetDlgItemText(hwndDlg, IDC_ZPEAKHANDLES_V, L"N/A");
1389  SetDlgItemText(hwndDlg, IDC_ZGDIHANDLES_V, L"N/A");
1390  SetDlgItemText(hwndDlg, IDC_ZUSERHANDLES_V, L"N/A");
1391  SetDlgItemText(hwndDlg, IDC_ZCYCLES_V, L"N/A");
1392  SetDlgItemText(hwndDlg, IDC_ZPAGEPRIORITY_V, L"N/A");
1393  SetDlgItemText(hwndDlg, IDC_ZIOPRIORITY_V, L"N/A");
1394  SetDlgItemText(hwndDlg, IDC_ZPRIVATEWS_V, L"N/A");
1395  SetDlgItemText(hwndDlg, IDC_ZSHAREABLEWS_V, L"N/A");
1396  SetDlgItemText(hwndDlg, IDC_ZSHAREDWS_V, L"N/A");
1397  }
1398 }
1399 
1401  _In_ HWND hwndDlg,
1402  _In_ UINT uMsg,
1403  _In_ WPARAM wParam,
1404  _In_ LPARAM lParam
1405  )
1406 {
1407  LPPROPSHEETPAGE propSheetPage;
1408  PPH_PROCESS_PROPPAGECONTEXT propPageContext;
1409  PPH_PROCESS_ITEM processItem;
1410  PPH_STATISTICS_CONTEXT statisticsContext;
1411 
1412  if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam,
1413  &propSheetPage, &propPageContext, &processItem))
1414  {
1415  statisticsContext = (PPH_STATISTICS_CONTEXT)propPageContext->Context;
1416  }
1417  else
1418  {
1419  return FALSE;
1420  }
1421 
1422  switch (uMsg)
1423  {
1424  case WM_INITDIALOG:
1425  {
1426  statisticsContext = propPageContext->Context =
1427  PhAllocate(sizeof(PH_STATISTICS_CONTEXT));
1428 
1429  statisticsContext->WindowHandle = hwndDlg;
1430  statisticsContext->Enabled = TRUE;
1431  statisticsContext->ProcessHandle = NULL;
1432 
1433  // Try to open a process handle with PROCESS_QUERY_INFORMATION access for
1434  // WS information.
1435  PhOpenProcess(
1436  &statisticsContext->ProcessHandle,
1438  processItem->ProcessId
1439  );
1440 
1443  StatisticsUpdateHandler,
1444  statisticsContext,
1445  &statisticsContext->ProcessesUpdatedRegistration
1446  );
1447 
1448  PhpUpdateProcessStatistics(hwndDlg, processItem, statisticsContext);
1449  }
1450  break;
1451  case WM_DESTROY:
1452  {
1455  &statisticsContext->ProcessesUpdatedRegistration
1456  );
1457 
1458  if (statisticsContext->ProcessHandle)
1459  NtClose(statisticsContext->ProcessHandle);
1460 
1461  PhFree(statisticsContext);
1462 
1463  PhpPropPageDlgProcDestroy(hwndDlg);
1464  }
1465  break;
1466  case WM_SHOWWINDOW:
1467  {
1468  if (!propPageContext->LayoutInitialized)
1469  {
1470  PPH_LAYOUT_ITEM dialogItem;
1471 
1472  dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg,
1474 
1475  PhDoPropPageLayout(hwndDlg);
1476 
1477  propPageContext->LayoutInitialized = TRUE;
1478  }
1479  }
1480  break;
1481  case WM_COMMAND:
1482  {
1483  switch (LOWORD(wParam))
1484  {
1485  case IDC_DETAILS:
1486  {
1487  PhShowHandleStatisticsDialog(hwndDlg, processItem->ProcessId);
1488  }
1489  break;
1490  }
1491  }
1492  break;
1493  case WM_NOTIFY:
1494  {
1495  LPNMHDR header = (LPNMHDR)lParam;
1496 
1497  switch (header->code)
1498  {
1499  case PSN_SETACTIVE:
1500  statisticsContext->Enabled = TRUE;
1501  break;
1502  case PSN_KILLACTIVE:
1503  statisticsContext->Enabled = FALSE;
1504  break;
1505  }
1506  }
1507  break;
1509  {
1510  PhpUpdateProcessStatistics(hwndDlg, processItem, statisticsContext);
1511  }
1512  break;
1513  }
1514 
1515  return FALSE;
1516 }
1517 
1518 static VOID NTAPI PerformanceUpdateHandler(
1519  _In_opt_ PVOID Parameter,
1520  _In_opt_ PVOID Context
1521  )
1522 {
1523  PPH_PERFORMANCE_CONTEXT performanceContext = (PPH_PERFORMANCE_CONTEXT)Context;
1524 
1525  PostMessage(performanceContext->WindowHandle, WM_PH_PERFORMANCE_UPDATE, 0, 0);
1526 }
1527 
1529  _In_ HWND hwndDlg,
1530  _In_ UINT uMsg,
1531  _In_ WPARAM wParam,
1532  _In_ LPARAM lParam
1533  )
1534 {
1535  LPPROPSHEETPAGE propSheetPage;
1536  PPH_PROCESS_PROPPAGECONTEXT propPageContext;
1537  PPH_PROCESS_ITEM processItem;
1538  PPH_PERFORMANCE_CONTEXT performanceContext;
1539 
1540  if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam,
1541  &propSheetPage, &propPageContext, &processItem))
1542  {
1543  performanceContext = (PPH_PERFORMANCE_CONTEXT)propPageContext->Context;
1544  }
1545  else
1546  {
1547  return FALSE;
1548  }
1549 
1550  switch (uMsg)
1551  {
1552  case WM_INITDIALOG:
1553  {
1554  performanceContext = propPageContext->Context =
1555  PhAllocate(sizeof(PH_PERFORMANCE_CONTEXT));
1556 
1557  performanceContext->WindowHandle = hwndDlg;
1558 
1561  PerformanceUpdateHandler,
1562  performanceContext,
1563  &performanceContext->ProcessesUpdatedRegistration
1564  );
1565 
1566  // We have already set the group boxes to have WS_EX_TRANSPARENT to fix
1567  // the drawing issue that arises when using WS_CLIPCHILDREN. However
1568  // in removing the flicker from the graphs the group boxes will now flicker.
1569  // It's a good tradeoff since no one stares at the group boxes.
1570  PhSetWindowStyle(hwndDlg, WS_CLIPCHILDREN, WS_CLIPCHILDREN);
1571 
1572  PhInitializeGraphState(&performanceContext->CpuGraphState);
1573  PhInitializeGraphState(&performanceContext->PrivateGraphState);
1574  PhInitializeGraphState(&performanceContext->IoGraphState);
1575 
1576  performanceContext->CpuGraphHandle = GetDlgItem(hwndDlg, IDC_CPU);
1577  PhSetWindowStyle(performanceContext->CpuGraphHandle, WS_BORDER, WS_BORDER);
1578  Graph_SetTooltip(performanceContext->CpuGraphHandle, TRUE);
1579  BringWindowToTop(performanceContext->CpuGraphHandle);
1580 
1581  performanceContext->PrivateGraphHandle = GetDlgItem(hwndDlg, IDC_PRIVATEBYTES);
1582  PhSetWindowStyle(performanceContext->PrivateGraphHandle, WS_BORDER, WS_BORDER);
1583  Graph_SetTooltip(performanceContext->PrivateGraphHandle, TRUE);
1584  BringWindowToTop(performanceContext->PrivateGraphHandle);
1585 
1586  performanceContext->IoGraphHandle = GetDlgItem(hwndDlg, IDC_IO);
1587  PhSetWindowStyle(performanceContext->IoGraphHandle, WS_BORDER, WS_BORDER);
1588  Graph_SetTooltip(performanceContext->IoGraphHandle, TRUE);
1589  BringWindowToTop(performanceContext->IoGraphHandle);
1590  }
1591  break;
1592  case WM_DESTROY:
1593  {
1594  PhDeleteGraphState(&performanceContext->CpuGraphState);
1595  PhDeleteGraphState(&performanceContext->PrivateGraphState);
1596  PhDeleteGraphState(&performanceContext->IoGraphState);
1597 
1600  &performanceContext->ProcessesUpdatedRegistration
1601  );
1602  PhFree(performanceContext);
1603 
1604  PhpPropPageDlgProcDestroy(hwndDlg);
1605  }
1606  break;
1607  case WM_SHOWWINDOW:
1608  {
1609  if (!propPageContext->LayoutInitialized)
1610  {
1611  PPH_LAYOUT_ITEM dialogItem;
1612 
1613  dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg,
1615 
1616  PhDoPropPageLayout(hwndDlg);
1617 
1618  propPageContext->LayoutInitialized = TRUE;
1619  }
1620  }
1621  break;
1622  case WM_NOTIFY:
1623  {
1624  LPNMHDR header = (LPNMHDR)lParam;
1625 
1626  switch (header->code)
1627  {
1628  case GCN_GETDRAWINFO:
1629  {
1630  PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)header;
1631  PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;
1632 
1633  if (header->hwndFrom == performanceContext->CpuGraphHandle)
1634  {
1635  if (PhCsGraphShowText)
1636  {
1637  HDC hdc;
1638 
1639  PhMoveReference(&performanceContext->CpuGraphState.Text,
1640  PhFormatString(L"%.2f%%",
1641  (processItem->CpuKernelUsage + processItem->CpuUserUsage) * 100
1642  ));
1643 
1644  hdc = Graph_GetBufferedContext(performanceContext->CpuGraphHandle);
1645  SelectObject(hdc, PhApplicationFont);
1646  PhSetGraphText(hdc, drawInfo, &performanceContext->CpuGraphState.Text->sr,
1648  }
1649  else
1650  {
1651  drawInfo->Text.Buffer = NULL;
1652  }
1653 
1656 
1658  &performanceContext->CpuGraphState,
1659  getDrawInfo,
1660  processItem->CpuKernelHistory.Count
1661  );
1662 
1663  if (!performanceContext->CpuGraphState.Valid)
1664  {
1665  PhCopyCircularBuffer_FLOAT(&processItem->CpuKernelHistory,
1666  performanceContext->CpuGraphState.Data1, drawInfo->LineDataCount);
1667  PhCopyCircularBuffer_FLOAT(&processItem->CpuUserHistory,
1668  performanceContext->CpuGraphState.Data2, drawInfo->LineDataCount);
1669  performanceContext->CpuGraphState.Valid = TRUE;
1670  }
1671  }
1672  else if (header->hwndFrom == performanceContext->PrivateGraphHandle)
1673  {
1674  if (PhCsGraphShowText)
1675  {
1676  HDC hdc;
1677 
1678  PhMoveReference(&performanceContext->PrivateGraphState.Text,
1680  L"Private Bytes: ",
1681  PhaFormatSize(processItem->VmCounters.PagefileUsage, -1)->Buffer
1682  ));
1683 
1684  hdc = Graph_GetBufferedContext(performanceContext->PrivateGraphHandle);
1685  SelectObject(hdc, PhApplicationFont);
1686  PhSetGraphText(hdc, drawInfo, &performanceContext->PrivateGraphState.Text->sr,
1688  }
1689  else
1690  {
1691  drawInfo->Text.Buffer = NULL;
1692  }
1693 
1694  drawInfo->Flags = PH_GRAPH_USE_GRID;
1696 
1698  &performanceContext->PrivateGraphState,
1699  getDrawInfo,
1700  processItem->PrivateBytesHistory.Count
1701  );
1702 
1703  if (!performanceContext->PrivateGraphState.Valid)
1704  {
1705  ULONG i;
1706 
1707  for (i = 0; i < drawInfo->LineDataCount; i++)
1708  {
1709  performanceContext->PrivateGraphState.Data1[i] =
1710  (FLOAT)PhGetItemCircularBuffer_SIZE_T(&processItem->PrivateBytesHistory, i);
1711  }
1712 
1713  if (processItem->VmCounters.PeakPagefileUsage != 0)
1714  {
1715  // Scale the data.
1717  performanceContext->PrivateGraphState.Data1,
1718  (FLOAT)processItem->VmCounters.PeakPagefileUsage,
1719  drawInfo->LineDataCount
1720  );
1721  }
1722 
1723  performanceContext->PrivateGraphState.Valid = TRUE;
1724  }
1725  }
1726  else if (header->hwndFrom == performanceContext->IoGraphHandle)
1727  {
1728  if (PhCsGraphShowText)
1729  {
1730  HDC hdc;
1731 
1732  PhMoveReference(&performanceContext->IoGraphState.Text,
1734  L"R+O: %s, W: %s",
1735  PhaFormatSize(processItem->IoReadDelta.Delta + processItem->IoOtherDelta.Delta, -1)->Buffer,
1736  PhaFormatSize(processItem->IoWriteDelta.Delta, -1)->Buffer
1737  ));
1738 
1739  hdc = Graph_GetBufferedContext(performanceContext->IoGraphHandle);
1740  SelectObject(hdc, PhApplicationFont);
1741  PhSetGraphText(hdc, drawInfo, &performanceContext->IoGraphState.Text->sr,
1743  }
1744  else
1745  {
1746  drawInfo->Text.Buffer = NULL;
1747  }
1748 
1751 
1753  &performanceContext->IoGraphState,
1754  getDrawInfo,
1755  processItem->IoReadHistory.Count
1756  );
1757 
1758  if (!performanceContext->IoGraphState.Valid)
1759  {
1760  ULONG i;
1761  FLOAT max = 0;
1762 
1763  for (i = 0; i < drawInfo->LineDataCount; i++)
1764  {
1765  FLOAT data1;
1766  FLOAT data2;
1767 
1768  performanceContext->IoGraphState.Data1[i] = data1 =
1769  (FLOAT)PhGetItemCircularBuffer_ULONG64(&processItem->IoReadHistory, i) +
1770  (FLOAT)PhGetItemCircularBuffer_ULONG64(&processItem->IoOtherHistory, i);
1771  performanceContext->IoGraphState.Data2[i] = data2 =
1772  (FLOAT)PhGetItemCircularBuffer_ULONG64(&processItem->IoWriteHistory, i);
1773 
1774  if (max < data1 + data2)
1775  max = data1 + data2;
1776  }
1777 
1778  if (max != 0)
1779  {
1780  // Scale the data.
1781 
1783  performanceContext->IoGraphState.Data1,
1784  max,
1785  drawInfo->LineDataCount
1786  );
1788  performanceContext->IoGraphState.Data2,
1789  max,
1790  drawInfo->LineDataCount
1791  );
1792  }
1793 
1794  performanceContext->IoGraphState.Valid = TRUE;
1795  }
1796  }
1797  }
1798  break;
1799  case GCN_GETTOOLTIPTEXT:
1800  {
1801  PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)lParam;
1802 
1803  if (
1804  header->hwndFrom == performanceContext->CpuGraphHandle &&
1805  getTooltipText->Index < getTooltipText->TotalCount
1806  )
1807  {
1808  if (performanceContext->CpuGraphState.TooltipIndex != getTooltipText->Index)
1809  {
1810  FLOAT cpuKernel;
1811  FLOAT cpuUser;
1812 
1813  cpuKernel = PhGetItemCircularBuffer_FLOAT(&processItem->CpuKernelHistory, getTooltipText->Index);
1814  cpuUser = PhGetItemCircularBuffer_FLOAT(&processItem->CpuUserHistory, getTooltipText->Index);
1815 
1817  L"%.2f%%\n%s",
1818  (cpuKernel + cpuUser) * 100,
1819  ((PPH_STRING)PhAutoDereferenceObject(PhGetStatisticsTimeString(processItem, getTooltipText->Index)))->Buffer
1820  ));
1821  }
1822 
1823  getTooltipText->Text = performanceContext->CpuGraphState.TooltipText->sr;
1824  }
1825  else if (
1826  header->hwndFrom == performanceContext->PrivateGraphHandle &&
1827  getTooltipText->Index < getTooltipText->TotalCount
1828  )
1829  {
1830  if (performanceContext->PrivateGraphState.TooltipIndex != getTooltipText->Index)
1831  {
1832  SIZE_T privateBytes;
1833 
1834  privateBytes = PhGetItemCircularBuffer_SIZE_T(&processItem->PrivateBytesHistory, getTooltipText->Index);
1835 
1837  L"Private Bytes: %s\n%s",
1838  PhaFormatSize(privateBytes, -1)->Buffer,
1839  ((PPH_STRING)PhAutoDereferenceObject(PhGetStatisticsTimeString(processItem, getTooltipText->Index)))->Buffer
1840  ));
1841  }
1842 
1843  getTooltipText->Text = performanceContext->PrivateGraphState.TooltipText->sr;
1844  }
1845  else if (
1846  header->hwndFrom == performanceContext->IoGraphHandle &&
1847  getTooltipText->Index < getTooltipText->TotalCount
1848  )
1849  {
1850  if (performanceContext->IoGraphState.TooltipIndex != getTooltipText->Index)
1851  {
1852  ULONG64 ioRead;
1853  ULONG64 ioWrite;
1854  ULONG64 ioOther;
1855 
1856  ioRead = PhGetItemCircularBuffer_ULONG64(&processItem->IoReadHistory, getTooltipText->Index);
1857  ioWrite = PhGetItemCircularBuffer_ULONG64(&processItem->IoWriteHistory, getTooltipText->Index);
1858  ioOther = PhGetItemCircularBuffer_ULONG64(&processItem->IoOtherHistory, getTooltipText->Index);
1859 
1861  L"R: %s\nW: %s\nO: %s\n%s",
1862  PhaFormatSize(ioRead, -1)->Buffer,
1863  PhaFormatSize(ioWrite, -1)->Buffer,
1864  PhaFormatSize(ioOther, -1)->Buffer,
1865  ((PPH_STRING)PhAutoDereferenceObject(PhGetStatisticsTimeString(processItem, getTooltipText->Index)))->Buffer
1866  ));
1867  }
1868 
1869  getTooltipText->Text = performanceContext->IoGraphState.TooltipText->sr;
1870  }
1871  }
1872  break;
1873  }
1874  }
1875  break;
1876  case WM_SIZE:
1877  {
1878  HDWP deferHandle;
1879  HWND cpuGroupBox = GetDlgItem(hwndDlg, IDC_GROUPCPU);
1880  HWND privateBytesGroupBox = GetDlgItem(hwndDlg, IDC_GROUPPRIVATEBYTES);
1881  HWND ioGroupBox = GetDlgItem(hwndDlg, IDC_GROUPIO);
1882  RECT clientRect;
1883  RECT margin = { 13, 13, 13, 13 };
1884  RECT innerMargin = { 10, 20, 10, 10 };
1885  LONG between = 3;
1886  LONG width;
1887  LONG height;
1888 
1889  performanceContext->CpuGraphState.Valid = FALSE;
1890  performanceContext->CpuGraphState.TooltipIndex = -1;
1891  performanceContext->PrivateGraphState.Valid = FALSE;
1892  performanceContext->PrivateGraphState.TooltipIndex = -1;
1893  performanceContext->IoGraphState.Valid = FALSE;
1894  performanceContext->IoGraphState.TooltipIndex = -1;
1895 
1896  GetClientRect(hwndDlg, &clientRect);
1897  width = clientRect.right - margin.left - margin.right;
1898  height = (clientRect.bottom - margin.top - margin.bottom - between * 2) / 3;
1899 
1900  deferHandle = BeginDeferWindowPos(6);
1901 
1902  deferHandle = DeferWindowPos(deferHandle, cpuGroupBox, NULL, margin.left, margin.top,
1903  width, height, SWP_NOACTIVATE | SWP_NOZORDER);
1904  deferHandle = DeferWindowPos(
1905  deferHandle,
1906  performanceContext->CpuGraphHandle,
1907  NULL,
1908  margin.left + innerMargin.left,
1909  margin.top + innerMargin.top,
1910  width - innerMargin.left - innerMargin.right,
1911  height - innerMargin.top - innerMargin.bottom,
1912  SWP_NOACTIVATE | SWP_NOZORDER
1913  );
1914 
1915  deferHandle = DeferWindowPos(deferHandle, privateBytesGroupBox, NULL, margin.left, margin.top + height + between,
1916  width, height, SWP_NOACTIVATE | SWP_NOZORDER);
1917  deferHandle = DeferWindowPos(
1918  deferHandle,
1919  performanceContext->PrivateGraphHandle,
1920  NULL,
1921  margin.left + innerMargin.left,
1922  margin.top + height + between + innerMargin.top,
1923  width - innerMargin.left - innerMargin.right,
1924  height - innerMargin.top - innerMargin.bottom,
1925  SWP_NOACTIVATE | SWP_NOZORDER
1926  );
1927 
1928  deferHandle = DeferWindowPos(deferHandle, ioGroupBox, NULL, margin.left, margin.top + (height + between) * 2,
1929  width, height, SWP_NOACTIVATE | SWP_NOZORDER);
1930  deferHandle = DeferWindowPos(
1931  deferHandle,
1932  performanceContext->IoGraphHandle,
1933  NULL,
1934  margin.left + innerMargin.left,
1935  margin.top + (height + between) * 2 + innerMargin.top,
1936  width - innerMargin.left - innerMargin.right,
1937  height - innerMargin.top - innerMargin.bottom,
1938  SWP_NOACTIVATE | SWP_NOZORDER
1939  );
1940 
1941  EndDeferWindowPos(deferHandle);
1942  }
1943  break;
1945  {
1946  if (!(processItem->State & PH_PROCESS_ITEM_REMOVED))
1947  {
1948  performanceContext->CpuGraphState.Valid = FALSE;
1949  Graph_MoveGrid(performanceContext->CpuGraphHandle, 1);
1950  Graph_Draw(performanceContext->CpuGraphHandle);
1951  Graph_UpdateTooltip(performanceContext->CpuGraphHandle);
1952  InvalidateRect(performanceContext->CpuGraphHandle, NULL, FALSE);
1953 
1954  performanceContext->PrivateGraphState.Valid = FALSE;
1955  Graph_MoveGrid(performanceContext->PrivateGraphHandle, 1);
1956  Graph_Draw(performanceContext->PrivateGraphHandle);
1957  Graph_UpdateTooltip(performanceContext->PrivateGraphHandle);
1958  InvalidateRect(performanceContext->PrivateGraphHandle, NULL, FALSE);
1959 
1960  performanceContext->IoGraphState.Valid = FALSE;
1961  Graph_MoveGrid(performanceContext->IoGraphHandle, 1);
1962  Graph_Draw(performanceContext->IoGraphHandle);
1963  Graph_UpdateTooltip(performanceContext->IoGraphHandle);
1964  InvalidateRect(performanceContext->IoGraphHandle, NULL, FALSE);
1965  }
1966  }
1967  break;
1968  }
1969 
1970  return FALSE;
1971 }
1972 
1973 static VOID NTAPI ThreadAddedHandler(
1974  _In_opt_ PVOID Parameter,
1975  _In_opt_ PVOID Context
1976  )
1977 {
1978  PPH_THREADS_CONTEXT threadsContext = (PPH_THREADS_CONTEXT)Context;
1979 
1980  // Parameter contains a pointer to the added thread item.
1981  PhReferenceObject(Parameter);
1982  PostMessage(
1983  threadsContext->WindowHandle,
1985  threadsContext->Provider->RunId == 1,
1986  (LPARAM)Parameter
1987  );
1988 }
1989 
1990 static VOID NTAPI ThreadModifiedHandler(
1991  _In_opt_ PVOID Parameter,
1992  _In_opt_ PVOID Context
1993  )
1994 {
1995  PPH_THREADS_CONTEXT threadsContext = (PPH_THREADS_CONTEXT)Context;
1996 
1997  PostMessage(threadsContext->WindowHandle, WM_PH_THREAD_MODIFIED, 0, (LPARAM)Parameter);
1998 }
1999 
2000 static VOID NTAPI ThreadRemovedHandler(
2001  _In_opt_ PVOID Parameter,
2002  _In_opt_ PVOID Context
2003  )
2004 {
2005  PPH_THREADS_CONTEXT threadsContext = (PPH_THREADS_CONTEXT)Context;
2006 
2007  PostMessage(threadsContext->WindowHandle, WM_PH_THREAD_REMOVED, 0, (LPARAM)Parameter);
2008 }
2009 
2010 static VOID NTAPI ThreadsUpdatedHandler(
2011  _In_opt_ PVOID Parameter,
2012  _In_opt_ PVOID Context
2013  )
2014 {
2015  PPH_THREADS_CONTEXT threadsContext = (PPH_THREADS_CONTEXT)Context;
2016 
2017  PostMessage(threadsContext->WindowHandle, WM_PH_THREADS_UPDATED, 0, 0);
2018 }
2019 
2020 static VOID NTAPI ThreadsLoadingStateChangedHandler(
2021  _In_opt_ PVOID Parameter,
2022  _In_opt_ PVOID Context
2023  )
2024 {
2025  PPH_THREADS_CONTEXT threadsContext = (PPH_THREADS_CONTEXT)Context;
2026 
2027  PostMessage(
2028  threadsContext->ListContext.TreeNewHandle,
2029  TNM_SETCURSOR,
2030  0,
2031  // Parameter contains TRUE if loading symbols
2032  (LPARAM)(Parameter ? LoadCursor(NULL, IDC_APPSTARTING) : NULL)
2033  );
2034 }
2035 
2037  _In_ PPH_EMENU Menu,
2038  _In_ HANDLE ProcessId,
2039  _In_ PPH_THREAD_ITEM *Threads,
2040  _In_ ULONG NumberOfThreads
2041  )
2042 {
2043  PPH_EMENU_ITEM item;
2044 
2045  if (NumberOfThreads == 0)
2046  {
2048  }
2049  else if (NumberOfThreads == 1)
2050  {
2051  // All menu items are enabled by default.
2052  }
2053  else
2054  {
2055  ULONG menuItemsMultiEnabled[] =
2056  {
2062  };
2063  ULONG i;
2064 
2066 
2067  // These menu items are capable of manipulating
2068  // multiple threads.
2069  for (i = 0; i < sizeof(menuItemsMultiEnabled) / sizeof(ULONG); i++)
2070  {
2071  PhEnableEMenuItem(Menu, menuItemsMultiEnabled[i], TRUE);
2072  }
2073  }
2074 
2075  // Remove irrelevant menu items.
2076 
2078  {
2079  // Remove I/O priority.
2080  if (item = PhFindEMenuItem(Menu, 0, L"I/O Priority", 0))
2081  PhDestroyEMenuItem(item);
2082  // Remove page priority.
2083  if (item = PhFindEMenuItem(Menu, 0, L"Page Priority", 0))
2084  PhDestroyEMenuItem(item);
2085  }
2086 
2087 #ifndef _WIN64
2088  if (!KphIsConnected())
2089  {
2090 #endif
2091  // Remove Force Terminate (this is always done on x64).
2092  if (item = PhFindEMenuItem(Menu, 0, NULL, ID_THREAD_FORCETERMINATE))
2093  PhDestroyEMenuItem(item);
2094 #ifndef _WIN64
2095  }
2096  else
2097  {
2098  if (ProcessId == SYSTEM_PROCESS_ID)
2099  {
2100  // Remove Force Terminate because Terminate does
2101  // the same job.
2102  if (item = PhFindEMenuItem(Menu, 0, NULL, ID_THREAD_FORCETERMINATE))
2103  PhDestroyEMenuItem(item);
2104  }
2105  }
2106 #endif
2107 
2109 
2110  // Priority
2111  if (NumberOfThreads == 1)
2112  {
2113  HANDLE threadHandle;
2114  ULONG ioPriority = -1;
2115  ULONG pagePriority = -1;
2116  ULONG threadPriority = THREAD_PRIORITY_ERROR_RETURN;
2117  ULONG id = 0;
2118 
2120  &threadHandle,
2122  Threads[0]->ThreadId
2123  )))
2124  {
2125  threadPriority = GetThreadPriority(threadHandle);
2126 
2128  {
2130  threadHandle,
2131  &ioPriority
2132  )))
2133  {
2134  ioPriority = -1;
2135  }
2136 
2138  threadHandle,
2139  &pagePriority
2140  )))
2141  {
2142  pagePriority = -1;
2143  }
2144  }
2145 
2146  // Token
2147  {
2148  HANDLE tokenHandle;
2149 
2151  &tokenHandle,
2152  TOKEN_QUERY,
2153  threadHandle,
2154  TRUE
2155  )))
2156  {
2158  NtClose(tokenHandle);
2159  }
2160  }
2161 
2162  NtClose(threadHandle);
2163  }
2164 
2165  switch (threadPriority)
2166  {
2167  case THREAD_PRIORITY_TIME_CRITICAL:
2169  break;
2170  case THREAD_PRIORITY_HIGHEST:
2171  id = ID_PRIORITY_HIGHEST;
2172  break;
2173  case THREAD_PRIORITY_ABOVE_NORMAL:
2175  break;
2176  case THREAD_PRIORITY_NORMAL:
2177  id = ID_PRIORITY_NORMAL;
2178  break;
2179  case THREAD_PRIORITY_BELOW_NORMAL:
2181  break;
2182  case THREAD_PRIORITY_LOWEST:
2183  id = ID_PRIORITY_LOWEST;
2184  break;
2185  case THREAD_PRIORITY_IDLE:
2186  id = ID_PRIORITY_IDLE;
2187  break;
2188  }
2189 
2190  if (id != 0)
2191  {
2192  PhSetFlagsEMenuItem(Menu, id,
2195  }
2196 
2197  if (ioPriority != -1)
2198  {
2199  id = 0;
2200 
2201  switch (ioPriority)
2202  {
2203  case 0:
2204  id = ID_I_0;
2205  break;
2206  case 1:
2207  id = ID_I_1;
2208  break;
2209  case 2:
2210  id = ID_I_2;
2211  break;
2212  case 3:
2213  id = ID_I_3;
2214  break;
2215  }
2216 
2217  if (id != 0)
2218  {
2219  PhSetFlagsEMenuItem(Menu, id,
2222  }
2223  }
2224 
2225  if (pagePriority != -1)
2226  {
2227  id = 0;
2228 
2229  switch (pagePriority)
2230  {
2231  case 1:
2232  id = ID_PAGEPRIORITY_1;
2233  break;
2234  case 2:
2235  id = ID_PAGEPRIORITY_2;
2236  break;
2237  case 3:
2238  id = ID_PAGEPRIORITY_3;
2239  break;
2240  case 4:
2241  id = ID_PAGEPRIORITY_4;
2242  break;
2243  case 5:
2244  id = ID_PAGEPRIORITY_5;
2245  break;
2246  }
2247 
2248  if (id != 0)
2249  {
2250  PhSetFlagsEMenuItem(Menu, id,
2253  }
2254  }
2255  }
2256 }
2257 
2258 static NTSTATUS NTAPI PhpThreadPermissionsOpenThread(
2259  _Out_ PHANDLE Handle,
2260  _In_ ACCESS_MASK DesiredAccess,
2261  _In_opt_ PVOID Context
2262  )
2263 {
2264  return PhOpenThread(Handle, DesiredAccess, (HANDLE)Context);
2265 }
2266 
2267 static NTSTATUS NTAPI PhpOpenThreadTokenObject(
2268  _Out_ PHANDLE Handle,
2269  _In_ ACCESS_MASK DesiredAccess,
2270  _In_opt_ PVOID Context
2271  )
2272 {
2273  return PhOpenThreadToken(
2274  Handle,
2275  DesiredAccess,
2276  (HANDLE)Context,
2277  TRUE
2278  );
2279 }
2280 
2282  _In_ HWND hwndDlg,
2283  _In_ PPH_THREADS_CONTEXT Context,
2284  _In_ BOOLEAN Force
2285  )
2286 {
2287  PPH_THREAD_ITEM *threads;
2288  ULONG numberOfThreads;
2289  PPH_THREAD_ITEM threadItem;
2290  PPH_STRING startModule = NULL;
2291  PPH_STRING started = NULL;
2292  WCHAR kernelTime[PH_TIMESPAN_STR_LEN_1] = L"N/A";
2293  WCHAR userTime[PH_TIMESPAN_STR_LEN_1] = L"N/A";
2294  PPH_STRING contextSwitches = NULL;
2295  PPH_STRING cycles = NULL;
2296  PPH_STRING state = NULL;
2297  WCHAR priority[PH_INT32_STR_LEN_1] = L"N/A";
2298  WCHAR basePriority[PH_INT32_STR_LEN_1] = L"N/A";
2299  PWSTR ioPriority = L"N/A";
2300  WCHAR pagePriority[PH_INT32_STR_LEN_1] = L"N/A";
2301  WCHAR idealProcessor[PH_INT32_STR_LEN + 1 + PH_INT32_STR_LEN + 1] = L"N/A";
2302  HANDLE threadHandle;
2303  SYSTEMTIME time;
2304  ULONG ioPriorityInteger;
2305  ULONG pagePriorityInteger;
2306  PROCESSOR_NUMBER idealProcessorNumber;
2307  ULONG suspendCount;
2308 
2309  PhGetSelectedThreadItems(&Context->ListContext, &threads, &numberOfThreads);
2310 
2311  if (numberOfThreads == 1)
2312  threadItem = threads[0];
2313  else
2314  threadItem = NULL;
2315 
2316  PhFree(threads);
2317 
2318  if (numberOfThreads != 1 && !Force)
2319  return;
2320 
2321  if (numberOfThreads == 1)
2322  {
2323  startModule = threadItem->StartAddressFileName;
2324 
2325  PhLargeIntegerToLocalSystemTime(&time, &threadItem->CreateTime);
2326  started = PhaFormatDateTime(&time);
2327 
2328  PhPrintTimeSpan(kernelTime, threadItem->KernelTime.QuadPart, PH_TIMESPAN_HMSM);
2329  PhPrintTimeSpan(userTime, threadItem->UserTime.QuadPart, PH_TIMESPAN_HMSM);
2330 
2331  contextSwitches = PhaFormatUInt64(threadItem->ContextSwitchesDelta.Value, TRUE);
2332 
2334  cycles = PhaFormatUInt64(threadItem->CyclesDelta.Value, TRUE);
2335 
2336  if (threadItem->State != Waiting)
2337  {
2338  if ((ULONG)threadItem->State < MaximumThreadState)
2339  state = PhaCreateString(PhKThreadStateNames[(ULONG)threadItem->State]);
2340  else
2341  state = PhaCreateString(L"Unknown");
2342  }
2343  else
2344  {
2345  if ((ULONG)threadItem->WaitReason < MaximumWaitReason)
2346  state = PhaConcatStrings2(L"Wait:", PhKWaitReasonNames[(ULONG)threadItem->WaitReason]);
2347  else
2348  state = PhaCreateString(L"Waiting");
2349  }
2350 
2351  PhPrintInt32(priority, threadItem->Priority);
2352  PhPrintInt32(basePriority, threadItem->BasePriority);
2353 
2354  if (NT_SUCCESS(PhOpenThread(&threadHandle, ThreadQueryAccess, threadItem->ThreadId)))
2355  {
2356  if (NT_SUCCESS(PhGetThreadIoPriority(threadHandle, &ioPriorityInteger)) &&
2357  ioPriorityInteger < MaxIoPriorityTypes)
2358  {
2359  ioPriority = PhIoPriorityHintNames[ioPriorityInteger];
2360  }
2361 
2362  if (NT_SUCCESS(PhGetThreadPagePriority(threadHandle, &pagePriorityInteger)))
2363  {
2364  PhPrintUInt32(pagePriority, pagePriorityInteger);
2365  }
2366 
2367  if (NT_SUCCESS(NtQueryInformationThread(threadHandle, ThreadIdealProcessorEx, &idealProcessorNumber, sizeof(PROCESSOR_NUMBER), NULL)))
2368  {
2369  PH_FORMAT format[3];
2370 
2371  PhInitFormatU(&format[0], idealProcessorNumber.Group);
2372  PhInitFormatC(&format[1], ':');
2373  PhInitFormatU(&format[2], idealProcessorNumber.Number);
2374  PhFormatToBuffer(format, 3, idealProcessor, sizeof(idealProcessor), NULL);
2375  }
2376 
2377  if (threadItem->WaitReason == Suspended && NT_SUCCESS(NtQueryInformationThread(threadHandle, ThreadSuspendCount, &suspendCount, sizeof(ULONG), NULL)))
2378  {
2379  PH_FORMAT format[4];
2380 
2381  PhInitFormatSR(&format[0], state->sr);
2382  PhInitFormatS(&format[1], L" (");
2383  PhInitFormatU(&format[2], suspendCount);
2384  PhInitFormatS(&format[3], L")");
2385  state = PhAutoDereferenceObject(PhFormat(format, 4, 30));
2386  }
2387 
2388  NtClose(threadHandle);
2389  }
2390  }
2391 
2392  if (Force)
2393  {
2394  // These don't change...
2395 
2396  SetDlgItemText(hwndDlg, IDC_STARTMODULE, PhGetStringOrEmpty(startModule));
2397  EnableWindow(GetDlgItem(hwndDlg, IDC_OPENSTARTMODULE), !!startModule);
2398 
2399  SetDlgItemText(hwndDlg, IDC_STARTED, PhGetStringOrDefault(started, L"N/A"));
2400  }
2401 
2402  SetDlgItemText(hwndDlg, IDC_KERNELTIME, kernelTime);
2403  SetDlgItemText(hwndDlg, IDC_USERTIME, userTime);
2404  SetDlgItemText(hwndDlg, IDC_CONTEXTSWITCHES, PhGetStringOrDefault(contextSwitches, L"N/A"));
2405  SetDlgItemText(hwndDlg, IDC_CYCLES, PhGetStringOrDefault(cycles, L"N/A"));
2406  SetDlgItemText(hwndDlg, IDC_STATE, PhGetStringOrDefault(state, L"N/A"));
2407  SetDlgItemText(hwndDlg, IDC_PRIORITY, priority);
2408  SetDlgItemText(hwndDlg, IDC_BASEPRIORITY, basePriority);
2409  SetDlgItemText(hwndDlg, IDC_IOPRIORITY, ioPriority);
2410  SetDlgItemText(hwndDlg, IDC_PAGEPRIORITY, pagePriority);
2411  SetDlgItemText(hwndDlg, IDC_IDEALPROCESSOR, idealProcessor);
2412 }
2413 
2415  _In_ HWND hwndDlg,
2416  _In_ PPH_PROCESS_ITEM ProcessItem,
2417  _In_ PPH_THREADS_CONTEXT Context,
2418  _In_ PPH_TREENEW_CONTEXT_MENU ContextMenu
2419  )
2420 {
2421  PPH_THREAD_ITEM *threads;
2422  ULONG numberOfThreads;
2423 
2424  PhGetSelectedThreadItems(&Context->ListContext, &threads, &numberOfThreads);
2425 
2426  if (numberOfThreads != 0)
2427  {
2428  PPH_EMENU menu;
2429  PPH_EMENU_ITEM item;
2430  PH_PLUGIN_MENU_INFORMATION menuInfo;
2431 
2432  menu = PhCreateEMenu();
2433  PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_THREAD), 0);
2435 
2436  PhpInitializeThreadMenu(menu, ProcessItem->ProcessId, threads, numberOfThreads);
2437  PhInsertCopyCellEMenuItem(menu, ID_THREAD_COPY, Context->ListContext.TreeNewHandle, ContextMenu->Column);
2438 
2439  if (PhPluginsEnabled)
2440  {
2441  PhPluginInitializeMenuInfo(&menuInfo, menu, hwndDlg, 0);
2442  menuInfo.u.Thread.ProcessId = ProcessItem->ProcessId;
2443  menuInfo.u.Thread.Threads = threads;
2444  menuInfo.u.Thread.NumberOfThreads = numberOfThreads;
2445 
2447  }
2448 
2449  item = PhShowEMenu(
2450  menu,
2451  hwndDlg,
2454  ContextMenu->Location.x,
2455  ContextMenu->Location.y
2456  );
2457 
2458  if (item)
2459  {
2460  BOOLEAN handled = FALSE;
2461 
2462  handled = PhHandleCopyCellEMenuItem(item);
2463 
2464  if (!handled && PhPluginsEnabled)
2465  handled = PhPluginTriggerEMenuItem(&menuInfo, item);
2466 
2467  if (!handled)
2468  SendMessage(hwndDlg, WM_COMMAND, item->Id, 0);
2469  }
2470 
2471  PhDestroyEMenu(menu);
2472  }
2473 
2474  PhFree(threads);
2475 }
2476 
2477 INT_PTR CALLBACK PhpProcessThreadsDlgProc(
2478  _In_ HWND hwndDlg,
2479  _In_ UINT uMsg,
2480  _In_ WPARAM wParam,
2481  _In_ LPARAM lParam
2482  )
2483 {
2484  LPPROPSHEETPAGE propSheetPage;
2485  PPH_PROCESS_PROPPAGECONTEXT propPageContext;
2486  PPH_PROCESS_ITEM processItem;
2487  PPH_THREADS_CONTEXT threadsContext;
2488  HWND tnHandle;
2489 
2490  if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam,
2491  &propSheetPage, &propPageContext, &processItem))
2492  {
2493  threadsContext = (PPH_THREADS_CONTEXT)propPageContext->Context;
2494 
2495  if (threadsContext)
2496  tnHandle = threadsContext->ListContext.TreeNewHandle;
2497  }
2498  else
2499  {
2500  return FALSE;
2501  }
2502 
2503  switch (uMsg)
2504  {
2505  case WM_INITDIALOG:
2506  {
2507  threadsContext = propPageContext->Context =
2509 
2510  // The thread provider has a special registration mechanism.
2511  threadsContext->Provider = PhCreateThreadProvider(
2512  processItem->ProcessId
2513  );
2515  &threadsContext->Provider->ThreadAddedEvent,
2516  ThreadAddedHandler,
2517  threadsContext,
2518  &threadsContext->AddedEventRegistration
2519  );
2521  &threadsContext->Provider->ThreadModifiedEvent,
2522  ThreadModifiedHandler,
2523  threadsContext,
2524  &threadsContext->ModifiedEventRegistration
2525  );
2527  &threadsContext->Provider->ThreadRemovedEvent,
2528  ThreadRemovedHandler,
2529  threadsContext,
2530  &threadsContext->RemovedEventRegistration
2531  );
2533  &threadsContext->Provider->UpdatedEvent,
2534  ThreadsUpdatedHandler,
2535  threadsContext,
2536  &threadsContext->UpdatedEventRegistration
2537  );
2539  &threadsContext->Provider->LoadingStateChangedEvent,
2540  ThreadsLoadingStateChangedHandler,
2541  threadsContext,
2542  &threadsContext->LoadingStateChangedEventRegistration
2543  );
2544  threadsContext->WindowHandle = hwndDlg;
2545 
2546  // Initialize the list.
2547  tnHandle = GetDlgItem(hwndDlg, IDC_LIST);
2548  BringWindowToTop(tnHandle);
2549  PhInitializeThreadList(hwndDlg, tnHandle, &threadsContext->ListContext);
2550  TreeNew_SetEmptyText(tnHandle, &EmptyThreadsText, 0);
2551  threadsContext->NeedsRedraw = FALSE;
2552 
2553  // Use Cycles instead of Context Switches on Vista and above, but only when we can
2554  // open the process, since cycle time information requires sufficient access to the
2555  // threads.
2557  {
2558  HANDLE processHandle;
2559  PROCESS_EXTENDED_BASIC_INFORMATION extendedBasicInfo;
2560 
2561  // We make a distinction between PROCESS_QUERY_INFORMATION and PROCESS_QUERY_LIMITED_INFORMATION since
2562  // the latter can be used when opening audiodg.exe even though we can't access its threads using
2563  // THREAD_QUERY_LIMITED_INFORMATION.
2564 
2565  if (processItem->ProcessId == SYSTEM_IDLE_PROCESS_ID)
2566  {
2567  threadsContext->ListContext.UseCycleTime = TRUE;
2568  }
2569  else if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_INFORMATION, processItem->ProcessId)))
2570  {
2571  threadsContext->ListContext.UseCycleTime = TRUE;
2572  NtClose(processHandle);
2573  }
2574  else if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, processItem->ProcessId)))
2575  {
2576  threadsContext->ListContext.UseCycleTime = TRUE;
2577 
2578  // We can't use cycle time for protected processes (without KProcessHacker).
2579  if (NT_SUCCESS(PhGetProcessExtendedBasicInformation(processHandle, &extendedBasicInfo)) && extendedBasicInfo.IsProtectedProcess)
2580  {
2581  threadsContext->ListContext.UseCycleTime = FALSE;
2582  }
2583 
2584  NtClose(processHandle);
2585  }
2586  }
2587 
2588  if (processItem->ServiceList && processItem->ServiceList->Count != 0 && WINDOWS_HAS_SERVICE_TAGS)
2589  threadsContext->ListContext.HasServices = TRUE;
2590 
2592 
2593  if (PhPluginsEnabled)
2594  {
2595  PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;
2596 
2597  treeNewInfo.TreeNewHandle = tnHandle;
2598  treeNewInfo.CmData = &threadsContext->ListContext.Cm;
2599  treeNewInfo.SystemContext = threadsContext;
2601  }
2602 
2603  PhLoadSettingsThreadList(&threadsContext->ListContext);
2604 
2605  PhThreadProviderInitialUpdate(threadsContext->Provider);
2606  PhRegisterThreadProvider(threadsContext->Provider, &threadsContext->ProviderRegistration);
2607 
2609  PH_LOAD_SHARED_IMAGE(MAKEINTRESOURCE(IDB_FOLDER), IMAGE_BITMAP));
2610  }
2611  break;
2612  case WM_DESTROY:
2613  {
2615 
2617  &threadsContext->Provider->ThreadAddedEvent,
2618  &threadsContext->AddedEventRegistration
2619  );
2621  &threadsContext->Provider->ThreadModifiedEvent,
2622  &threadsContext->ModifiedEventRegistration
2623  );
2625  &threadsContext->Provider->ThreadRemovedEvent,
2626  &threadsContext->RemovedEventRegistration
2627  );
2629  &threadsContext->Provider->UpdatedEvent,
2630  &threadsContext->UpdatedEventRegistration
2631  );
2633  &threadsContext->Provider->LoadingStateChangedEvent,
2634  &threadsContext->LoadingStateChangedEventRegistration
2635  );
2636  PhUnregisterThreadProvider(threadsContext->Provider, &threadsContext->ProviderRegistration);
2637  PhSetTerminatingThreadProvider(threadsContext->Provider);
2638  PhDereferenceObject(threadsContext->Provider);
2639 
2640  if (PhPluginsEnabled)
2641  {
2642  PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;
2643 
2644  treeNewInfo.TreeNewHandle = tnHandle;
2645  treeNewInfo.CmData = &threadsContext->ListContext.Cm;
2647  }
2648 
2649  PhSaveSettingsThreadList(&threadsContext->ListContext);
2650  PhDeleteThreadList(&threadsContext->ListContext);
2651 
2652  PhFree(threadsContext);
2653 
2654  PhpPropPageDlgProcDestroy(hwndDlg);
2655  }
2656  break;
2657  case WM_SHOWWINDOW:
2658  {
2659  if (!propPageContext->LayoutInitialized)
2660  {
2661  PPH_LAYOUT_ITEM dialogItem;
2662 
2663  dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg,
2665  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST),
2666  dialogItem, PH_ANCHOR_ALL);
2667 
2668 #define ADD_BL_ITEM(Id) \
2669  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, Id), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM)
2670 
2671  // Thread details area
2672  {
2673  ULONG id;
2674 
2675  for (id = IDC_STATICBL1; id <= IDC_STATICBL11; id++)
2676  ADD_BL_ITEM(id);
2677 
2678  // Not in sequence
2680  }
2681 
2682  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_STARTMODULE),
2684  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_OPENSTARTMODULE),
2685  dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
2697 
2698  PhDoPropPageLayout(hwndDlg);
2699 
2700  propPageContext->LayoutInitialized = TRUE;
2701  }
2702  }
2703  break;
2704  case WM_COMMAND:
2705  {
2706  INT id = LOWORD(wParam);
2707 
2708  switch (id)
2709  {
2710  case ID_SHOWCONTEXTMENU:
2711  {
2712  PhShowThreadContextMenu(hwndDlg, processItem, threadsContext, (PPH_TREENEW_CONTEXT_MENU)lParam);
2713  }
2714  break;
2715  case ID_THREAD_INSPECT:
2716  {
2717  PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);
2718 
2719  if (threadItem)
2720  {
2721  PhReferenceObject(threadsContext->Provider);
2723  hwndDlg,
2724  threadsContext->Provider->ProcessId,
2725  threadItem->ThreadId,
2726  threadsContext->Provider
2727  );
2728  PhDereferenceObject(threadsContext->Provider);
2729  }
2730  }
2731  break;
2732  case ID_THREAD_TERMINATE:
2733  {
2734  PPH_THREAD_ITEM *threads;
2735  ULONG numberOfThreads;
2736 
2737  PhGetSelectedThreadItems(&threadsContext->ListContext, &threads, &numberOfThreads);
2738  PhReferenceObjects(threads, numberOfThreads);
2739 
2740  if (
2741  processItem->ProcessId != SYSTEM_PROCESS_ID ||
2742  !KphIsConnected()
2743  )
2744  {
2745  if (PhUiTerminateThreads(hwndDlg, threads, numberOfThreads))
2746  PhDeselectAllThreadNodes(&threadsContext->ListContext);
2747  }
2748  else
2749  {
2750  if (PhUiForceTerminateThreads(hwndDlg, processItem->ProcessId, threads, numberOfThreads))
2751  PhDeselectAllThreadNodes(&threadsContext->ListContext);
2752  }
2753 
2754  PhDereferenceObjects(threads, numberOfThreads);
2755  PhFree(threads);
2756  }
2757  break;
2759  {
2760  PPH_THREAD_ITEM *threads;
2761  ULONG numberOfThreads;
2762 
2763  PhGetSelectedThreadItems(&threadsContext->ListContext, &threads, &numberOfThreads);
2764  PhReferenceObjects(threads, numberOfThreads);
2765 
2766  if (PhUiForceTerminateThreads(hwndDlg, processItem->ProcessId, threads, numberOfThreads))
2767  PhDeselectAllThreadNodes(&threadsContext->ListContext);
2768 
2769  PhDereferenceObjects(threads, numberOfThreads);
2770  PhFree(threads);
2771  }
2772  break;
2773  case ID_THREAD_SUSPEND:
2774  {
2775  PPH_THREAD_ITEM *threads;
2776  ULONG numberOfThreads;
2777 
2778  PhGetSelectedThreadItems(&threadsContext->ListContext, &threads, &numberOfThreads);
2779  PhReferenceObjects(threads, numberOfThreads);
2780  PhUiSuspendThreads(hwndDlg, threads, numberOfThreads);
2781  PhDereferenceObjects(threads, numberOfThreads);
2782  PhFree(threads);
2783  }
2784  break;
2785  case ID_THREAD_RESUME:
2786  {
2787  PPH_THREAD_ITEM *threads;
2788  ULONG numberOfThreads;
2789 
2790  PhGetSelectedThreadItems(&threadsContext->ListContext, &threads, &numberOfThreads);
2791  PhReferenceObjects(threads, numberOfThreads);
2792  PhUiResumeThreads(hwndDlg, threads, numberOfThreads);
2793  PhDereferenceObjects(threads, numberOfThreads);
2794  PhFree(threads);
2795  }
2796  break;
2797  case ID_THREAD_AFFINITY:
2798  {
2799  PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);
2800 
2801  if (threadItem)
2802  {
2803  PhReferenceObject(threadItem);
2804  PhShowProcessAffinityDialog(hwndDlg, NULL, threadItem);
2805  PhDereferenceObject(threadItem);
2806  }
2807  }
2808  break;
2809  case ID_THREAD_PERMISSIONS:
2810  {
2811  PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);
2812  PH_STD_OBJECT_SECURITY stdObjectSecurity;
2813  PPH_ACCESS_ENTRY accessEntries;
2814  ULONG numberOfAccessEntries;
2815 
2816  if (threadItem)
2817  {
2818  stdObjectSecurity.OpenObject = PhpThreadPermissionsOpenThread;
2819  stdObjectSecurity.ObjectType = L"Thread";
2820  stdObjectSecurity.Context = threadItem->ThreadId;
2821 
2822  if (PhGetAccessEntries(L"Thread", &accessEntries, &numberOfAccessEntries))
2823  {
2825  hwndDlg,
2826  PhaFormatString(L"Thread %u", (ULONG)threadItem->ThreadId)->Buffer,
2829  &stdObjectSecurity,
2830  accessEntries,
2831  numberOfAccessEntries
2832  );
2833  PhFree(accessEntries);
2834  }
2835  }
2836  }
2837  break;
2838  case ID_THREAD_TOKEN:
2839  {
2840  NTSTATUS status;
2841  PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);
2842  HANDLE threadHandle;
2843 
2844  if (threadItem)
2845  {
2846  if (NT_SUCCESS(status = PhOpenThread(
2847  &threadHandle,
2849  threadItem->ThreadId
2850  )))
2851  {
2853  hwndDlg,
2854  PhpOpenThreadTokenObject,
2855  (PVOID)threadHandle,
2856  NULL
2857  );
2858 
2859  NtClose(threadHandle);
2860  }
2861  else
2862  {
2863  PhShowStatus(hwndDlg, L"Unable to open the thread", status, 0);
2864  }
2865  }
2866  }
2867  break;
2868  case ID_ANALYZE_WAIT:
2869  {
2870  PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);
2871 
2872  if (threadItem)
2873  {
2874  PhReferenceObject(threadsContext->Provider->SymbolProvider);
2876  hwndDlg,
2877  processItem->ProcessId,
2878  threadItem->ThreadId,
2879  threadsContext->Provider->SymbolProvider
2880  );
2881  PhDereferenceObject(threadsContext->Provider->SymbolProvider);
2882  }
2883  }
2884  break;
2886  case ID_PRIORITY_HIGHEST:
2888  case ID_PRIORITY_NORMAL:
2890  case ID_PRIORITY_LOWEST:
2891  case ID_PRIORITY_IDLE:
2892  {
2893  PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);
2894 
2895  if (threadItem)
2896  {
2897  ULONG threadPriorityWin32;
2898 
2899  switch (id)
2900  {
2902  threadPriorityWin32 = THREAD_PRIORITY_TIME_CRITICAL;
2903  break;
2904  case ID_PRIORITY_HIGHEST:
2905  threadPriorityWin32 = THREAD_PRIORITY_HIGHEST;
2906  break;
2908  threadPriorityWin32 = THREAD_PRIORITY_ABOVE_NORMAL;
2909  break;
2910  case ID_PRIORITY_NORMAL:
2911  threadPriorityWin32 = THREAD_PRIORITY_NORMAL;
2912  break;
2914  threadPriorityWin32 = THREAD_PRIORITY_BELOW_NORMAL;
2915  break;
2916  case ID_PRIORITY_LOWEST:
2917  threadPriorityWin32 = THREAD_PRIORITY_LOWEST;
2918  break;
2919  case ID_PRIORITY_IDLE:
2920  threadPriorityWin32 = THREAD_PRIORITY_IDLE;
2921  break;
2922  }
2923 
2924  PhReferenceObject(threadItem);
2925  PhUiSetPriorityThread(hwndDlg, threadItem, threadPriorityWin32);
2926  PhDereferenceObject(threadItem);
2927  }
2928  }
2929  break;
2930  case ID_I_0:
2931  case ID_I_1:
2932  case ID_I_2:
2933  case ID_I_3:
2934  {
2935  PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);
2936 
2937  if (threadItem)
2938  {
2939  ULONG ioPriority;
2940 
2941  switch (id)
2942  {
2943  case ID_I_0:
2944  ioPriority = 0;
2945  break;
2946  case ID_I_1:
2947  ioPriority = 1;
2948  break;
2949  case ID_I_2:
2950  ioPriority = 2;
2951  break;
2952  case ID_I_3:
2953  ioPriority = 3;
2954  break;
2955  }
2956 
2957  PhReferenceObject(threadItem);
2958  PhUiSetIoPriorityThread(hwndDlg, threadItem, ioPriority);
2959  PhDereferenceObject(threadItem);
2960  }
2961  }
2962  break;
2963  case ID_PAGEPRIORITY_1:
2964  case ID_PAGEPRIORITY_2:
2965  case ID_PAGEPRIORITY_3:
2966  case ID_PAGEPRIORITY_4:
2967  case ID_PAGEPRIORITY_5:
2968  {
2969  PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);
2970 
2971  if (threadItem)
2972  {
2973  ULONG pagePriority;
2974 
2975  switch (id)
2976  {
2977  case ID_PAGEPRIORITY_1:
2978  pagePriority = 1;
2979  break;
2980  case ID_PAGEPRIORITY_2:
2981  pagePriority = 2;
2982  break;
2983  case ID_PAGEPRIORITY_3:
2984  pagePriority = 3;
2985  break;
2986  case ID_PAGEPRIORITY_4:
2987  pagePriority = 4;
2988  break;
2989  case ID_PAGEPRIORITY_5:
2990  pagePriority = 5;
2991  break;
2992  }
2993 
2994  PhReferenceObject(threadItem);
2995  PhUiSetPagePriorityThread(hwndDlg, threadItem, pagePriority);
2996  PhDereferenceObject(threadItem);
2997  }
2998  }
2999  break;
3000  case ID_THREAD_COPY:
3001  {
3002  PPH_STRING text;
3003 
3004  text = PhGetTreeNewText(tnHandle, 0);
3005  PhSetClipboardString(tnHandle, &text->sr);
3006  PhDereferenceObject(text);
3007  }
3008  break;
3009  case IDC_OPENSTARTMODULE:
3010  {
3011  PPH_THREAD_ITEM threadItem = PhGetSelectedThreadItem(&threadsContext->ListContext);
3012 
3013  if (threadItem && threadItem->StartAddressFileName)
3014  {
3015  PhShellExploreFile(hwndDlg, threadItem->StartAddressFileName->Buffer);
3016  }
3017  }
3018  break;
3019  }
3020  }
3021  break;
3022  case WM_NOTIFY:
3023  {
3024  LPNMHDR header = (LPNMHDR)lParam;
3025 
3026  switch (header->code)
3027  {
3028  case PSN_SETACTIVE:
3029  break;
3030  case PSN_KILLACTIVE:
3031  // Can't disable, it screws up the deltas.
3032  break;
3033  }
3034  }
3035  break;
3036  case WM_PH_THREAD_ADDED:
3037  {
3038  BOOLEAN firstRun = (BOOLEAN)wParam;
3039  PPH_THREAD_ITEM threadItem = (PPH_THREAD_ITEM)lParam;
3040 
3041  if (!threadsContext->NeedsRedraw)
3042  {
3043  // Disable redraw. It will be re-enabled later.
3044  TreeNew_SetRedraw(tnHandle, FALSE);
3045  threadsContext->NeedsRedraw = TRUE;
3046  }
3047 
3048  PhAddThreadNode(&threadsContext->ListContext, threadItem, firstRun);
3049  PhDereferenceObject(threadItem);
3050  }
3051  break;
3052  case WM_PH_THREAD_MODIFIED:
3053  {
3054  PPH_THREAD_ITEM threadItem = (PPH_THREAD_ITEM)lParam;
3055 
3056  if (!threadsContext->NeedsRedraw)
3057  {
3058  TreeNew_SetRedraw(tnHandle, FALSE);
3059  threadsContext->NeedsRedraw = TRUE;
3060  }
3061 
3062  PhUpdateThreadNode(&threadsContext->ListContext, PhFindThreadNode(&threadsContext->ListContext, threadItem->ThreadId));
3063  }
3064  break;
3065  case WM_PH_THREAD_REMOVED:
3066  {
3067  PPH_THREAD_ITEM threadItem = (PPH_THREAD_ITEM)lParam;
3068 
3069  if (!threadsContext->NeedsRedraw)
3070  {
3071  TreeNew_SetRedraw(tnHandle, FALSE);
3072  threadsContext->NeedsRedraw = TRUE;
3073  }
3074 
3075  PhRemoveThreadNode(&threadsContext->ListContext, PhFindThreadNode(&threadsContext->ListContext, threadItem->ThreadId));
3076  }
3077  break;
3078  case WM_PH_THREADS_UPDATED:
3079  {
3080  PhTickThreadNodes(&threadsContext->ListContext);
3081 
3082  if (threadsContext->NeedsRedraw)
3083  {
3084  TreeNew_SetRedraw(tnHandle, TRUE);
3085  threadsContext->NeedsRedraw = FALSE;
3086  }
3087 
3088  if (propPageContext->PropContext->SelectThreadId)
3089  {
3090  PPH_THREAD_NODE threadNode;
3091 
3092  if (threadNode = PhFindThreadNode(&threadsContext->ListContext, propPageContext->PropContext->SelectThreadId))
3093  {
3094  if (threadNode->Node.Visible)
3095  {
3096  TreeNew_SetFocusNode(tnHandle, &threadNode->Node);
3097  TreeNew_SetMarkNode(tnHandle, &threadNode->Node);
3098  TreeNew_SelectRange(tnHandle, threadNode->Node.Index, threadNode->Node.Index);
3099  TreeNew_EnsureVisible(tnHandle, &threadNode->Node);
3100  }
3101  }
3102 
3103  propPageContext->PropContext->SelectThreadId = NULL;
3104  }
3105 
3106  PhpUpdateThreadDetails(hwndDlg, threadsContext, FALSE);
3107  }
3108  break;
3110  {
3111  PhpUpdateThreadDetails(hwndDlg, threadsContext, TRUE);
3112  }
3113  break;
3114  }
3115 
3116  return FALSE;
3117 }
3118 
3119 static NTSTATUS NTAPI PhpOpenProcessToken(
3120  _Out_ PHANDLE Handle,
3121  _In_ ACCESS_MASK DesiredAccess,
3122  _In_opt_ PVOID Context
3123  )
3124 {
3125  NTSTATUS status;
3126  HANDLE processHandle;
3127 
3128  if (!NT_SUCCESS(status = PhOpenProcess(
3129  &processHandle,
3131  (HANDLE)Context
3132  )))
3133  return status;
3134 
3135  status = PhOpenProcessToken(Handle, DesiredAccess, processHandle);
3136  NtClose(processHandle);
3137 
3138  return status;
3139 }
3140 
3141 INT_PTR CALLBACK PhpProcessTokenHookProc(
3142  _In_ HWND hwndDlg,
3143  _In_ UINT uMsg,
3144  _In_ WPARAM wParam,
3145  _In_ LPARAM lParam
3146  )
3147 {
3148  switch (uMsg)
3149  {
3150  case WM_DESTROY:
3151  {
3152  RemoveProp(hwndDlg, PhMakeContextAtom());
3153  }
3154  break;
3155  case WM_SHOWWINDOW:
3156  {
3157  if (!GetProp(hwndDlg, PhMakeContextAtom())) // LayoutInitialized
3158  {
3159  PPH_LAYOUT_ITEM dialogItem;
3160  HWND groupsLv;
3161  HWND privilegesLv;
3162 
3163  // This is a big violation of abstraction...
3164 
3165  dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg,
3167  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_USER),
3168  dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
3169  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_USERSID),
3170  dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
3171  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_VIRTUALIZED),
3172  dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
3173  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_APPCONTAINERSID),
3174  dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
3175  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_GROUPS),
3176  dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
3177  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PRIVILEGES),
3178  dialogItem, PH_ANCHOR_ALL);
3179  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_INSTRUCTION),
3180  dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM);
3181  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_INTEGRITY),
3182  dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
3183  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_ADVANCED),
3184  dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
3185 
3186  PhDoPropPageLayout(hwndDlg);
3187 
3188  groupsLv = GetDlgItem(hwndDlg, IDC_GROUPS);
3189  privilegesLv = GetDlgItem(hwndDlg, IDC_PRIVILEGES);
3190 
3191  if (ListView_GetItemCount(groupsLv) != 0)
3192  {
3193  ListView_SetColumnWidth(groupsLv, 0, LVSCW_AUTOSIZE);
3195  }
3196 
3197  if (ListView_GetItemCount(privilegesLv) != 0)
3198  {
3199  ListView_SetColumnWidth(privilegesLv, 0, LVSCW_AUTOSIZE);
3200  ListView_SetColumnWidth(privilegesLv, 1, LVSCW_AUTOSIZE);
3202  }
3203 
3204  SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)TRUE);
3205  }
3206  }
3207  break;
3208  }
3209 
3210  return FALSE;
3211 }
3212 
3213 static VOID NTAPI ModuleAddedHandler(
3214  _In_opt_ PVOID Parameter,
3215  _In_opt_ PVOID Context
3216  )
3217 {
3218  PPH_MODULES_CONTEXT modulesContext = (PPH_MODULES_CONTEXT)Context;
3219 
3220  // Parameter contains a pointer to the added module item.
3221  PhReferenceObject(Parameter);
3222  PostMessage(
3223  modulesContext->WindowHandle,
3225  PhGetRunIdProvider(&modulesContext->ProviderRegistration),
3226  (LPARAM)Parameter
3227  );
3228 }
3229 
3230 static VOID NTAPI ModuleModifiedHandler(
3231  _In_opt_ PVOID Parameter,
3232  _In_opt_ PVOID Context
3233  )
3234 {
3235  PPH_MODULES_CONTEXT modulesContext = (PPH_MODULES_CONTEXT)Context;
3236 
3237  PostMessage(modulesContext->WindowHandle, WM_PH_MODULE_MODIFIED, 0, (LPARAM)Parameter);
3238 }
3239 
3240 static VOID NTAPI ModuleRemovedHandler(
3241  _In_opt_ PVOID Parameter,
3242  _In_opt_ PVOID Context
3243  )
3244 {
3245  PPH_MODULES_CONTEXT modulesContext = (PPH_MODULES_CONTEXT)Context;
3246 
3247  PostMessage(modulesContext->WindowHandle, WM_PH_MODULE_REMOVED, 0, (LPARAM)Parameter);
3248 }
3249 
3250 static VOID NTAPI ModulesUpdatedHandler(
3251  _In_opt_ PVOID Parameter,
3252  _In_opt_ PVOID Context
3253  )
3254 {
3255  PPH_MODULES_CONTEXT modulesContext = (PPH_MODULES_CONTEXT)Context;
3256 
3257  PostMessage(modulesContext->WindowHandle, WM_PH_MODULES_UPDATED, 0, 0);
3258 }
3259 
3261  _In_ PPH_EMENU Menu,
3262  _In_ HANDLE ProcessId,
3263  _In_ PPH_MODULE_ITEM *Modules,
3264  _In_ ULONG NumberOfModules
3265  )
3266 {
3267  PPH_EMENU_ITEM item;
3268  PPH_STRING inspectExecutables;
3269 
3270  inspectExecutables = PhGetStringSetting(L"ProgramInspectExecutables");
3271 
3272  if (inspectExecutables->Length == 0)
3273  {
3274  if (item = PhFindEMenuItem(Menu, 0, NULL, ID_MODULE_INSPECT))
3275  PhDestroyEMenuItem(item);
3276  }
3277 
3278  PhDereferenceObject(inspectExecutables);
3279 
3280  if (NumberOfModules == 0)
3281  {
3283  }
3284  else if (NumberOfModules == 1)
3285  {
3286  // Nothing
3287  }
3288  else
3289  {
3292  }
3293 }
3294 
3296  _In_ HWND hwndDlg,
3297  _In_ PPH_PROCESS_ITEM ProcessItem,
3298  _In_ PPH_MODULES_CONTEXT Context,
3299  _In_ PPH_TREENEW_CONTEXT_MENU ContextMenu
3300  )
3301 {
3302  PPH_MODULE_ITEM *modules;
3303  ULONG numberOfModules;
3304 
3305  PhGetSelectedModuleItems(&Context->ListContext, &modules, &numberOfModules);
3306 
3307  if (numberOfModules != 0)
3308  {
3309  PPH_EMENU menu;
3310  PPH_EMENU_ITEM item;
3311  PH_PLUGIN_MENU_INFORMATION menuInfo;
3312 
3313  menu = PhCreateEMenu();
3314  PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_MODULE), 0);
3316 
3317  PhpInitializeModuleMenu(menu, ProcessItem->ProcessId, modules, numberOfModules);
3318  PhInsertCopyCellEMenuItem(menu, ID_MODULE_COPY, Context->ListContext.TreeNewHandle, ContextMenu->Column);
3319 
3320  if (PhPluginsEnabled)
3321  {
3322  PhPluginInitializeMenuInfo(&menuInfo, menu, hwndDlg, 0);
3323  menuInfo.u.Module.ProcessId = ProcessItem->ProcessId;
3324  menuInfo.u.Module.Modules = modules;
3325  menuInfo.u.Module.NumberOfModules = numberOfModules;
3326 
3328  }
3329 
3330  item = PhShowEMenu(
3331  menu,
3332  hwndDlg,
3335  ContextMenu->Location.x,
3336  ContextMenu->Location.y
3337  );
3338 
3339  if (item)
3340  {
3341  BOOLEAN handled = FALSE;
3342 
3343  handled = PhHandleCopyCellEMenuItem(item);
3344 
3345  if (!handled && PhPluginsEnabled)
3346  handled = PhPluginTriggerEMenuItem(&menuInfo, item);
3347 
3348  if (!handled)
3349  SendMessage(hwndDlg, WM_COMMAND, item->Id, 0);
3350  }
3351 
3352  PhDestroyEMenu(menu);
3353  }
3354 
3355  PhFree(modules);
3356 }
3357 
3358 INT_PTR CALLBACK PhpProcessModulesDlgProc(
3359  _In_ HWND hwndDlg,
3360  _In_ UINT uMsg,
3361  _In_ WPARAM wParam,
3362  _In_ LPARAM lParam
3363  )
3364 {
3365  LPPROPSHEETPAGE propSheetPage;
3366  PPH_PROCESS_PROPPAGECONTEXT propPageContext;
3367  PPH_PROCESS_ITEM processItem;
3368  PPH_MODULES_CONTEXT modulesContext;
3369  HWND tnHandle;
3370 
3371  if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam,
3372  &propSheetPage, &propPageContext, &processItem))
3373  {
3374  modulesContext = (PPH_MODULES_CONTEXT)propPageContext->Context;
3375 
3376  if (modulesContext)
3377  tnHandle = modulesContext->ListContext.TreeNewHandle;
3378  }
3379  else
3380  {
3381  return FALSE;
3382  }
3383 
3384  switch (uMsg)
3385  {
3386  case WM_INITDIALOG:
3387  {
3388  // Lots of boilerplate code...
3389 
3390  modulesContext = propPageContext->Context =
3392 
3393  modulesContext->Provider = PhCreateModuleProvider(
3394  processItem->ProcessId
3395  );
3399  modulesContext->Provider,
3400  &modulesContext->ProviderRegistration
3401  );
3403  &modulesContext->Provider->ModuleAddedEvent,
3404  ModuleAddedHandler,
3405  modulesContext,
3406  &modulesContext->AddedEventRegistration
3407  );
3409  &modulesContext->Provider->ModuleModifiedEvent,
3410  ModuleModifiedHandler,
3411  modulesContext,
3412  &modulesContext->ModifiedEventRegistration
3413  );
3415  &modulesContext->Provider->ModuleRemovedEvent,
3416  ModuleRemovedHandler,
3417  modulesContext,
3418  &modulesContext->RemovedEventRegistration
3419  );
3421  &modulesContext->Provider->UpdatedEvent,
3422  ModulesUpdatedHandler,
3423  modulesContext,
3424  &modulesContext->UpdatedEventRegistration
3425  );
3426  modulesContext->WindowHandle = hwndDlg;
3427 
3428  // Initialize the list.
3429  tnHandle = GetDlgItem(hwndDlg, IDC_LIST);
3430  BringWindowToTop(tnHandle);
3431  PhInitializeModuleList(hwndDlg, tnHandle, &modulesContext->ListContext);
3432  TreeNew_SetEmptyText(tnHandle, &LoadingText, 0);
3433  modulesContext->NeedsRedraw = FALSE;
3434  modulesContext->LastRunStatus = -1;
3435  modulesContext->ErrorMessage = NULL;
3436 
3438 
3439  if (PhPluginsEnabled)
3440  {
3441  PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;
3442 
3443  treeNewInfo.TreeNewHandle = tnHandle;
3444  treeNewInfo.CmData = &modulesContext->ListContext.Cm;
3445  treeNewInfo.SystemContext = modulesContext;
3447  }
3448 
3449  PhLoadSettingsModuleList(&modulesContext->ListContext);
3450 
3451  PhSetEnabledProvider(&modulesContext->ProviderRegistration, TRUE);
3452  PhBoostProvider(&modulesContext->ProviderRegistration, NULL);
3453  }
3454  break;
3455  case WM_DESTROY:
3456  {
3458 
3460  &modulesContext->Provider->ModuleAddedEvent,
3461  &modulesContext->AddedEventRegistration
3462  );
3464  &modulesContext->Provider->ModuleModifiedEvent,
3465  &modulesContext->ModifiedEventRegistration
3466  );
3468  &modulesContext->Provider->ModuleRemovedEvent,
3469  &modulesContext->RemovedEventRegistration
3470  );
3472  &modulesContext->Provider->UpdatedEvent,
3473  &modulesContext->UpdatedEventRegistration
3474  );
3475  PhUnregisterProvider(&modulesContext->ProviderRegistration);
3476  PhDereferenceObject(modulesContext->Provider);
3477 
3478  if (PhPluginsEnabled)
3479  {
3480  PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;
3481 
3482  treeNewInfo.TreeNewHandle = tnHandle;
3483  treeNewInfo.CmData = &modulesContext->ListContext.Cm;
3485  }
3486 
3487  PhSaveSettingsModuleList(&modulesContext->ListContext);
3488  PhDeleteModuleList(&modulesContext->ListContext);
3489 
3490  PhClearReference(&modulesContext->ErrorMessage);
3491  PhFree(modulesContext);
3492 
3493  PhpPropPageDlgProcDestroy(hwndDlg);
3494  }
3495  break;
3496  case WM_SHOWWINDOW:
3497  {
3498  if (!propPageContext->LayoutInitialized)
3499  {
3500  PPH_LAYOUT_ITEM dialogItem;
3501 
3502  dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg,
3504  PhAddPropPageLayoutItem(hwndDlg, modulesContext->ListContext.TreeNewHandle,
3505  dialogItem, PH_ANCHOR_ALL);
3506 
3507  PhDoPropPageLayout(hwndDlg);
3508 
3509  propPageContext->LayoutInitialized = TRUE;
3510  }
3511  }
3512  break;
3513  case WM_COMMAND:
3514  {
3515  switch (LOWORD(wParam))
3516  {
3517  case ID_SHOWCONTEXTMENU:
3518  {
3519  PhShowModuleContextMenu(hwndDlg, processItem, modulesContext, (PPH_TREENEW_CONTEXT_MENU)lParam);
3520  }
3521  break;
3522  case ID_MODULE_UNLOAD:
3523  {
3524  PPH_MODULE_ITEM moduleItem = PhGetSelectedModuleItem(&modulesContext->ListContext);
3525 
3526  if (moduleItem)
3527  {
3528  PhReferenceObject(moduleItem);
3529 
3530  if (PhUiUnloadModule(hwndDlg, processItem->ProcessId, moduleItem))
3531  PhDeselectAllModuleNodes(&modulesContext->ListContext);
3532 
3533  PhDereferenceObject(moduleItem);
3534  }
3535  }
3536  break;
3537  case ID_MODULE_INSPECT:
3538  {
3539  PPH_MODULE_ITEM moduleItem = PhGetSelectedModuleItem(&modulesContext->ListContext);
3540 
3541  if (moduleItem)
3542  {
3544  hwndDlg,
3545  L"ProgramInspectExecutables",
3546  moduleItem->FileName->Buffer,
3547  FALSE,
3548  L"Make sure the PE Viewer executable file is present."
3549  );
3550  }
3551  }
3552  break;
3554  {
3555  PPH_MODULE_ITEM moduleItem = PhGetSelectedModuleItem(&modulesContext->ListContext);
3556 
3557  if (moduleItem)
3558  {
3559  PhSearchOnlineString(hwndDlg, moduleItem->Name->Buffer);
3560  }
3561  }
3562  break;
3564  {
3565  PPH_MODULE_ITEM moduleItem = PhGetSelectedModuleItem(&modulesContext->ListContext);
3566 
3567  if (moduleItem)
3568  {
3569  PhShellExploreFile(hwndDlg, moduleItem->FileName->Buffer);
3570  }
3571  }
3572  break;
3573  case ID_MODULE_PROPERTIES:
3574  {
3575  PPH_MODULE_ITEM moduleItem = PhGetSelectedModuleItem(&modulesContext->ListContext);
3576 
3577  if (moduleItem)
3578  {
3579  PhShellProperties(hwndDlg, moduleItem->FileName->Buffer);
3580  }
3581  }
3582  break;
3583  case ID_MODULE_COPY:
3584  {
3585  PPH_STRING text;
3586 
3587  text = PhGetTreeNewText(tnHandle, 0);
3588  PhSetClipboardString(tnHandle, &text->sr);
3589  PhDereferenceObject(text);
3590  }
3591  break;
3592  }
3593  }
3594  break;
3595  case WM_NOTIFY:
3596  {
3597  LPNMHDR header = (LPNMHDR)lParam;
3598 
3599  switch (header->code)
3600  {
3601  case PSN_SETACTIVE:
3602  PhSetEnabledProvider(&modulesContext->ProviderRegistration, TRUE);
3603  break;
3604  case PSN_KILLACTIVE:
3605  PhSetEnabledProvider(&modulesContext->ProviderRegistration, FALSE);
3606  break;
3607  }
3608  }
3609  break;
3610  case WM_PH_MODULE_ADDED:
3611  {
3612  ULONG runId = (ULONG)wParam;
3613  PPH_MODULE_ITEM moduleItem = (PPH_MODULE_ITEM)lParam;
3614 
3615  if (!modulesContext->NeedsRedraw)
3616  {
3617  TreeNew_SetRedraw(tnHandle, FALSE);
3618  modulesContext->NeedsRedraw = TRUE;
3619  }
3620 
3621  PhAddModuleNode(&modulesContext->ListContext, moduleItem, runId);
3622  PhDereferenceObject(moduleItem);
3623  }
3624  break;
3625  case WM_PH_MODULE_MODIFIED:
3626  {
3627  PPH_MODULE_ITEM moduleItem = (PPH_MODULE_ITEM)lParam;
3628 
3629  if (!modulesContext->NeedsRedraw)
3630  {
3631  TreeNew_SetRedraw(tnHandle, FALSE);
3632  modulesContext->NeedsRedraw = TRUE;
3633  }
3634 
3635  PhUpdateModuleNode(&modulesContext->ListContext, PhFindModuleNode(&modulesContext->ListContext, moduleItem));
3636  }
3637  break;
3638  case WM_PH_MODULE_REMOVED:
3639  {
3640  PPH_MODULE_ITEM moduleItem = (PPH_MODULE_ITEM)lParam;
3641 
3642  if (!modulesContext->NeedsRedraw)
3643  {
3644  TreeNew_SetRedraw(tnHandle, FALSE);
3645  modulesContext->NeedsRedraw = TRUE;
3646  }
3647 
3648  PhRemoveModuleNode(&modulesContext->ListContext, PhFindModuleNode(&modulesContext->ListContext, moduleItem));
3649  }
3650  break;
3651  case WM_PH_MODULES_UPDATED:
3652  {
3653  PhTickModuleNodes(&modulesContext->ListContext);
3654 
3655  if (modulesContext->LastRunStatus != modulesContext->Provider->RunStatus)
3656  {
3657  NTSTATUS status;
3658  PPH_STRING message;
3659 
3660  status = modulesContext->Provider->RunStatus;
3661  modulesContext->LastRunStatus = status;
3662 
3663  if (!PH_IS_REAL_PROCESS_ID(processItem->ProcessId))
3664  status = STATUS_SUCCESS;
3665 
3666  if (NT_SUCCESS(status))
3667  {
3668  TreeNew_SetEmptyText(tnHandle, &EmptyModulesText, 0);
3669  }
3670  else
3671  {
3672  message = PhGetStatusMessage(status, 0);
3673  PhMoveReference(&modulesContext->ErrorMessage, PhFormatString(L"Unable to query module information:\n%s", PhGetStringOrDefault(message, L"Unknown error.")));
3674  PhClearReference(&message);
3675  TreeNew_SetEmptyText(tnHandle, &modulesContext->ErrorMessage->sr, 0);
3676  }
3677 
3678  InvalidateRect(tnHandle, NULL, FALSE);
3679  }
3680 
3681  if (modulesContext->NeedsRedraw)
3682  {
3683  TreeNew_SetRedraw(tnHandle, TRUE);
3684  modulesContext->NeedsRedraw = FALSE;
3685  }
3686  }
3687  break;
3688  }
3689 
3690  return FALSE;
3691 }
3692 
3694  _In_ HWND hwndDlg,
3695  _In_ PPH_PROCESS_PROPPAGECONTEXT PropPageContext
3696  )
3697 {
3698  PPH_MEMORY_CONTEXT memoryContext = PropPageContext->Context;
3699 
3700  if (memoryContext->MemoryItemListValid)
3701  {
3702  PhDeleteMemoryItemList(&memoryContext->MemoryItemList);
3703  memoryContext->MemoryItemListValid = FALSE;
3704  }
3705 
3706  memoryContext->LastRunStatus = PhQueryMemoryItemList(
3707  memoryContext->ProcessId,
3709  &memoryContext->MemoryItemList
3710  );
3711 
3712  if (NT_SUCCESS(memoryContext->LastRunStatus))
3713  {
3714  if (PhPluginsEnabled)
3715  {
3717 
3719  control.u.Initialized.List = &memoryContext->MemoryItemList;
3720 
3722  }
3723 
3724  memoryContext->MemoryItemListValid = TRUE;
3725  TreeNew_SetEmptyText(memoryContext->ListContext.TreeNewHandle, &EmptyMemoryText, 0);
3726  PhReplaceMemoryList(&memoryContext->ListContext, &memoryContext->MemoryItemList);
3727  }
3728  else
3729  {
3730  PPH_STRING message;
3731 
3732  message = PhGetStatusMessage(memoryContext->LastRunStatus, 0);
3733  PhMoveReference(&memoryContext->ErrorMessage, PhFormatString(L"Unable to query memory information:\n%s", PhGetStringOrDefault(message, L"Unknown error.")));
3734  PhClearReference(&message);
3735  TreeNew_SetEmptyText(memoryContext->ListContext.TreeNewHandle, &memoryContext->ErrorMessage->sr, 0);
3736 
3737  PhReplaceMemoryList(&memoryContext->ListContext, NULL);
3738  }
3739 }
3740 
3742  _In_ PPH_EMENU Menu,
3743  _In_ HANDLE ProcessId,
3744  _In_ PPH_MEMORY_NODE *MemoryNodes,
3745  _In_ ULONG NumberOfMemoryNodes
3746  )
3747 {
3748  if (NumberOfMemoryNodes == 0)
3749  {
3751  }
3752  else if (NumberOfMemoryNodes == 1 && !MemoryNodes[0]->IsAllocationBase)
3753  {
3754  if (MemoryNodes[0]->MemoryItem->State & MEM_FREE)
3755  {
3759  }
3760  else if (MemoryNodes[0]->MemoryItem->Type & (MEM_MAPPED | MEM_IMAGE))
3761  {
3763  }
3764  }
3765  else
3766  {
3767  ULONG i;
3768  ULONG numberOfAllocationBase = 0;
3769 
3772 
3773  for (i = 0; i < NumberOfMemoryNodes; i++)
3774  {
3775  if (MemoryNodes[i]->IsAllocationBase)
3776  numberOfAllocationBase++;
3777  }
3778 
3779  if (numberOfAllocationBase == 0 || numberOfAllocationBase == NumberOfMemoryNodes)
3781  }
3782 
3784 }
3785 
3787  _In_ HWND hwndDlg,
3788  _In_ PPH_PROCESS_ITEM ProcessItem,
3789  _In_ PPH_MEMORY_CONTEXT Context,
3790  _In_ PPH_TREENEW_CONTEXT_MENU ContextMenu
3791  )
3792 {
3793  PPH_MEMORY_NODE *memoryNodes;
3794  ULONG numberOfMemoryNodes;
3795 
3796  PhGetSelectedMemoryNodes(&Context->ListContext, &memoryNodes, &numberOfMemoryNodes);
3797 
3798  //if (numberOfMemoryNodes != 0)
3799  {
3800  PPH_EMENU menu;
3801  PPH_EMENU_ITEM item;
3802  PH_PLUGIN_MENU_INFORMATION menuInfo;
3803 
3804  menu = PhCreateEMenu();
3805  PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_MEMORY), 0);
3807 
3808  PhpInitializeMemoryMenu(menu, ProcessItem->ProcessId, memoryNodes, numberOfMemoryNodes);
3809  PhInsertCopyCellEMenuItem(menu, ID_MEMORY_COPY, Context->ListContext.TreeNewHandle, ContextMenu->Column);
3810 
3811  if (PhPluginsEnabled)
3812  {
3813  PhPluginInitializeMenuInfo(&menuInfo, menu, hwndDlg, 0);
3814  menuInfo.u.Memory.ProcessId = ProcessItem->ProcessId;
3815  menuInfo.u.Memory.MemoryNodes = memoryNodes;
3816  menuInfo.u.Memory.NumberOfMemoryNodes = numberOfMemoryNodes;
3817 
3819  }
3820 
3821  item = PhShowEMenu(
3822  menu,
3823  hwndDlg,
3826  ContextMenu->Location.x,
3827  ContextMenu->Location.y
3828  );
3829 
3830  if (item)
3831  {
3832  BOOLEAN handled = FALSE;
3833 
3834  handled = PhHandleCopyCellEMenuItem(item);
3835 
3836  if (!handled && PhPluginsEnabled)
3837  handled = PhPluginTriggerEMenuItem(&menuInfo, item);
3838 
3839  if (!handled)
3840  SendMessage(hwndDlg, WM_COMMAND, item->Id, 0);
3841  }
3842 
3843  PhDestroyEMenu(menu);
3844  }
3845 
3846  PhFree(memoryNodes);
3847 }
3848 
3849 INT_PTR CALLBACK PhpProcessMemoryDlgProc(
3850  _In_ HWND hwndDlg,
3851  _In_ UINT uMsg,
3852  _In_ WPARAM wParam,
3853  _In_ LPARAM lParam
3854  )
3855 {
3856  LPPROPSHEETPAGE propSheetPage;
3857  PPH_PROCESS_PROPPAGECONTEXT propPageContext;
3858  PPH_PROCESS_ITEM processItem;
3859  PPH_MEMORY_CONTEXT memoryContext;
3860  HWND tnHandle;
3861 
3862  if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam,
3863  &propSheetPage, &propPageContext, &processItem))
3864  {
3865  memoryContext = (PPH_MEMORY_CONTEXT)propPageContext->Context;
3866 
3867  if (memoryContext)
3868  tnHandle = memoryContext->ListContext.TreeNewHandle;
3869  }
3870  else
3871  {
3872  return FALSE;
3873  }
3874 
3875  switch (uMsg)
3876  {
3877  case WM_INITDIALOG:
3878  {
3879  memoryContext = propPageContext->Context =
3881  memset(memoryContext, 0, sizeof(PH_MEMORY_CONTEXT));
3882  memoryContext->ProcessId = processItem->ProcessId;
3883 
3884  // Initialize the list.
3885  tnHandle = GetDlgItem(hwndDlg, IDC_LIST);
3886  BringWindowToTop(tnHandle);
3887  PhInitializeMemoryList(hwndDlg, tnHandle, &memoryContext->ListContext);
3888  TreeNew_SetEmptyText(tnHandle, &LoadingText, 0);
3889  memoryContext->LastRunStatus = -1;
3890  memoryContext->ErrorMessage = NULL;
3891 
3893 
3894  if (PhPluginsEnabled)
3895  {
3896  PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;
3897 
3898  treeNewInfo.TreeNewHandle = tnHandle;
3899  treeNewInfo.CmData = &memoryContext->ListContext.Cm;
3900  treeNewInfo.SystemContext = memoryContext;
3902  }
3903 
3904  PhLoadSettingsMemoryList(&memoryContext->ListContext);
3905  PhSetOptionsMemoryList(&memoryContext->ListContext, TRUE);
3906  Button_SetCheck(GetDlgItem(hwndDlg, IDC_HIDEFREEREGIONS),
3907  memoryContext->ListContext.HideFreeRegions ? BST_CHECKED : BST_UNCHECKED);
3908 
3909  PhpRefreshProcessMemoryList(hwndDlg, propPageContext);
3910  }
3911  break;
3912  case WM_DESTROY:
3913  {
3915 
3916  if (PhPluginsEnabled)
3917  {
3918  PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;
3919 
3920  treeNewInfo.TreeNewHandle = tnHandle;
3921  treeNewInfo.CmData = &memoryContext->ListContext.Cm;
3923  }
3924 
3925  PhSaveSettingsMemoryList(&memoryContext->ListContext);
3926  PhDeleteMemoryList(&memoryContext->ListContext);
3927 
3928  if (memoryContext->MemoryItemListValid)
3929  PhDeleteMemoryItemList(&memoryContext->MemoryItemList);
3930 
3931  PhClearReference(&memoryContext->ErrorMessage);
3932  PhFree(memoryContext);
3933 
3934  PhpPropPageDlgProcDestroy(hwndDlg);
3935  }
3936  break;
3937  case WM_SHOWWINDOW:
3938  {
3939  if (!propPageContext->LayoutInitialized)
3940  {
3941  PPH_LAYOUT_ITEM dialogItem;
3942 
3943  dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg,
3945  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_STRINGS),
3946  dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
3947  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_REFRESH),
3948  dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
3949  PhAddPropPageLayoutItem(hwndDlg, memoryContext->ListContext.TreeNewHandle,
3950  dialogItem, PH_ANCHOR_ALL);
3951 
3952  PhDoPropPageLayout(hwndDlg);
3953 
3954  propPageContext->LayoutInitialized = TRUE;
3955  }
3956  }
3957  break;
3958  case WM_COMMAND:
3959  {
3960  switch (LOWORD(wParam))
3961  {
3962  case ID_SHOWCONTEXTMENU:
3963  {
3964  PhShowMemoryContextMenu(hwndDlg, processItem, memoryContext, (PPH_TREENEW_CONTEXT_MENU)lParam);
3965  }
3966  break;
3968  {
3969  PPH_MEMORY_NODE memoryNode = PhGetSelectedMemoryNode(&memoryContext->ListContext);
3970 
3971  if (memoryNode && !memoryNode->IsAllocationBase)
3972  {
3973  if (memoryNode->MemoryItem->State & MEM_COMMIT)
3974  {
3975  PPH_SHOWMEMORYEDITOR showMemoryEditor = PhAllocate(sizeof(PH_SHOWMEMORYEDITOR));
3976 
3977  memset(showMemoryEditor, 0, sizeof(PH_SHOWMEMORYEDITOR));
3978  showMemoryEditor->ProcessId = processItem->ProcessId;
3979  showMemoryEditor->BaseAddress = memoryNode->MemoryItem->BaseAddress;
3980  showMemoryEditor->RegionSize = memoryNode->MemoryItem->RegionSize;
3981  showMemoryEditor->SelectOffset = -1;
3982  showMemoryEditor->SelectLength = 0;
3984  }
3985  else
3986  {
3987  PhShowError(hwndDlg, L"Unable to edit the memory region because it is not committed.");
3988  }
3989  }
3990  }
3991  break;
3992  case ID_MEMORY_SAVE:
3993  {
3994  NTSTATUS status;
3995  HANDLE processHandle;
3996  PPH_MEMORY_NODE *memoryNodes;
3997  ULONG numberOfMemoryNodes;
3998 
3999  if (!NT_SUCCESS(status = PhOpenProcess(
4000  &processHandle,
4002  processItem->ProcessId
4003  )))
4004  {
4005  PhShowStatus(hwndDlg, L"Unable to open the process", status, 0);
4006  break;
4007  }
4008 
4009  PhGetSelectedMemoryNodes(&memoryContext->ListContext, &memoryNodes, &numberOfMemoryNodes);
4010 
4011  if (numberOfMemoryNodes != 0)
4012  {
4013  static PH_FILETYPE_FILTER filters[] =
4014  {
4015  { L"Binary files (*.bin)", L"*.bin" },
4016  { L"All files (*.*)", L"*.*" }
4017  };
4018  PVOID fileDialog;
4019 
4020  fileDialog = PhCreateSaveFileDialog();
4021 
4022  PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER));
4023  PhSetFileDialogFileName(fileDialog, PhaConcatStrings2(processItem->ProcessName->Buffer, L".bin")->Buffer);
4024 
4025  if (PhShowFileDialog(hwndDlg, fileDialog))
4026  {
4027  PPH_STRING fileName;
4028  PPH_FILE_STREAM fileStream;
4029  PVOID buffer;
4030  ULONG i;
4031  ULONG_PTR offset;
4032 
4033  fileName = PhGetFileDialogFileName(fileDialog);
4034  PhAutoDereferenceObject(fileName);
4035 
4036  if (NT_SUCCESS(status = PhCreateFileStream(
4037  &fileStream,
4038  fileName->Buffer,
4039  FILE_GENERIC_WRITE,
4040  FILE_SHARE_READ,
4042  0
4043  )))
4044  {
4045  buffer = PhAllocatePage(PAGE_SIZE, NULL);
4046 
4047  // Go through each selected memory item and append the region contents
4048  // to the file.
4049  for (i = 0; i < numberOfMemoryNodes; i++)
4050  {
4051  PPH_MEMORY_NODE memoryNode = memoryNodes[i];
4052  PPH_MEMORY_ITEM memoryItem = memoryNode->MemoryItem;
4053 
4054  if (!memoryNode->IsAllocationBase && !(memoryItem->State & MEM_COMMIT))
4055  continue;
4056 
4057  for (offset = 0; offset < memoryItem->RegionSize; offset += PAGE_SIZE)
4058  {
4060  processHandle,
4061  PTR_ADD_OFFSET(memoryItem->BaseAddress, offset),
4062  buffer,
4063  PAGE_SIZE,
4064  NULL
4065  )))
4066  {
4067  PhWriteFileStream(fileStream, buffer, PAGE_SIZE);
4068  }
4069  }
4070  }
4071 
4072  PhFreePage(buffer);
4073 
4074  PhDereferenceObject(fileStream);
4075  }
4076 
4077  if (!NT_SUCCESS(status))
4078  PhShowStatus(hwndDlg, L"Unable to create the file", status, 0);
4079  }
4080 
4081  PhFreeFileDialog(fileDialog);
4082  }
4083 
4084  PhFree(memoryNodes);
4085  NtClose(processHandle);
4086  }
4087  break;
4089  {
4090  PPH_MEMORY_NODE memoryNode = PhGetSelectedMemoryNode(&memoryContext->ListContext);
4091 
4092  if (memoryNode)
4093  {
4094  PhReferenceObject(memoryNode->MemoryItem);
4095 
4096  PhShowMemoryProtectDialog(hwndDlg, processItem, memoryNode->MemoryItem);
4097  PhUpdateMemoryNode(&memoryContext->ListContext, memoryNode);
4098 
4099  PhDereferenceObject(memoryNode->MemoryItem);
4100  }
4101  }
4102  break;
4103  case ID_MEMORY_FREE:
4104  {
4105  PPH_MEMORY_NODE memoryNode = PhGetSelectedMemoryNode(&memoryContext->ListContext);
4106 
4107  if (memoryNode)
4108  {
4109  PhReferenceObject(memoryNode->MemoryItem);
4110  PhUiFreeMemory(hwndDlg, processItem->ProcessId, memoryNode->MemoryItem, TRUE);
4111  PhDereferenceObject(memoryNode->MemoryItem);
4112  // TODO: somehow update the list
4113  }
4114  }
4115  break;
4116  case ID_MEMORY_DECOMMIT:
4117  {
4118  PPH_MEMORY_NODE memoryNode = PhGetSelectedMemoryNode(&memoryContext->ListContext);
4119 
4120  if (memoryNode)
4121  {
4122  PhReferenceObject(memoryNode->MemoryItem);
4123  PhUiFreeMemory(hwndDlg, processItem->ProcessId, memoryNode->MemoryItem, FALSE);
4124  PhDereferenceObject(memoryNode->MemoryItem);
4125  }
4126  }
4127  break;
4129  {
4130  PPH_STRING selectedChoice = NULL;
4131 
4132  if (!memoryContext->MemoryItemListValid)
4133  break;
4134 
4135  while (PhaChoiceDialog(
4136  hwndDlg,
4137  L"Read/Write Address",
4138  L"Enter an address:",
4139  NULL,
4140  0,
4141  NULL,
4143  &selectedChoice,
4144  NULL,
4145  L"MemoryReadWriteAddressChoices"
4146  ))
4147  {
4148  ULONG64 address64;
4149  PVOID address;
4150 
4151  if (selectedChoice->Length == 0)
4152  continue;
4153 
4154  if (PhStringToInteger64(&selectedChoice->sr, 0, &address64))
4155  {
4156  PPH_MEMORY_ITEM memoryItem;
4157 
4158  address = (PVOID)address64;
4159  memoryItem = PhLookupMemoryItemList(&memoryContext->MemoryItemList, address);
4160 
4161  if (memoryItem)
4162  {
4163  PPH_SHOWMEMORYEDITOR showMemoryEditor = PhAllocate(sizeof(PH_SHOWMEMORYEDITOR));
4164 
4165  memset(showMemoryEditor, 0, sizeof(PH_SHOWMEMORYEDITOR));
4166  showMemoryEditor->ProcessId = processItem->ProcessId;
4167  showMemoryEditor->BaseAddress = memoryItem->BaseAddress;
4168  showMemoryEditor->RegionSize = memoryItem->RegionSize;
4169  showMemoryEditor->SelectOffset = (ULONG)((ULONG_PTR)address - (ULONG_PTR)memoryItem->BaseAddress);
4170  showMemoryEditor->SelectLength = 0;
4172  break;
4173  }
4174  else
4175  {
4176  PhShowError(hwndDlg, L"Unable to find the memory region for the selected address.");
4177  }
4178  }
4179  }
4180  }
4181  break;
4182  case ID_MEMORY_COPY:
4183  {
4184  PPH_STRING text;
4185 
4186  text = PhGetTreeNewText(tnHandle, 0);
4187  PhSetClipboardString(tnHandle, &text->sr);
4188  PhDereferenceObject(text);
4189  }
4190  break;
4191  case IDC_HIDEFREEREGIONS:
4192  {
4193  BOOLEAN hide;
4194 
4195  hide = Button_GetCheck(GetDlgItem(hwndDlg, IDC_HIDEFREEREGIONS)) == BST_CHECKED;
4196  PhSetOptionsMemoryList(&memoryContext->ListContext, hide);
4197  }
4198  break;
4199  case IDC_STRINGS:
4200  PhShowMemoryStringDialog(hwndDlg, processItem);
4201  break;
4202  case IDC_REFRESH:
4203  PhpRefreshProcessMemoryList(hwndDlg, propPageContext);
4204  break;
4205  }
4206  }
4207  break;
4208  }
4209 
4210  return FALSE;
4211 }
4212 
4214  _In_ HWND hwndDlg,
4215  _In_ UINT uMsg,
4216  _In_ WPARAM wParam,
4217  _In_ LPARAM lParam
4218  )
4219 {
4220  LPPROPSHEETPAGE propSheetPage;
4221  PPH_PROCESS_PROPPAGECONTEXT propPageContext;
4222  PPH_PROCESS_ITEM processItem;
4223 
4224  if (!PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam,
4225  &propSheetPage, &propPageContext, &processItem))
4226  return FALSE;
4227 
4228  switch (uMsg)
4229  {
4230  case WM_INITDIALOG:
4231  {
4232  HANDLE processHandle;
4233  PVOID environment;
4234  ULONG environmentLength;
4235  ULONG enumerationKey;
4236  PH_ENVIRONMENT_VARIABLE variable;
4237  HWND lvHandle = GetDlgItem(hwndDlg, IDC_LIST);
4238 
4239  PhSetListViewStyle(lvHandle, TRUE, TRUE);
4240  PhSetControlTheme(lvHandle, L"explorer");
4241  PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 140, L"Name");
4242  PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 200, L"Value");
4243 
4244  PhSetExtendedListView(lvHandle);
4245  PhLoadListViewColumnsFromSetting(L"EnvironmentListViewColumns", lvHandle);
4246 
4248  &processHandle,
4250  processItem->ProcessId
4251  )))
4252  {
4253  ULONG flags;
4254 
4255  flags = 0;
4256 
4257 #ifdef _WIN64
4258  if (processItem->IsWow64)
4260 #endif
4261 
4263  processHandle,
4264  flags,
4265  &environment,
4266  &environmentLength
4267  )))
4268  {
4269  enumerationKey = 0;
4270 
4271  while (PhEnumProcessEnvironmentVariables(environment, environmentLength, &enumerationKey, &variable))
4272  {
4273  INT lvItemIndex;
4274  PPH_STRING nameString;
4275  PPH_STRING valueString;
4276 
4277  // Don't display pairs with no name.
4278  if (variable.Name.Length == 0)
4279  continue;
4280 
4281  // The strings are not guaranteed to be null-terminated, so we need to create some temporary strings.
4282  nameString = PhCreateString2(&variable.Name);
4283  valueString = PhCreateString2(&variable.Value);
4284 
4285  lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, nameString->Buffer, NULL);
4286  PhSetListViewSubItem(lvHandle, lvItemIndex, 1, valueString->Buffer);
4287 
4288  PhDereferenceObject(nameString);
4289  PhDereferenceObject(valueString);
4290  }
4291 
4292  PhFreePage(environment);
4293  }
4294 
4295  NtClose(processHandle);
4296  }
4297  }
4298  break;
4299  case WM_DESTROY:
4300  {
4301  PhSaveListViewColumnsToSetting(L"EnvironmentListViewColumns", GetDlgItem(hwndDlg, IDC_LIST));
4302  PhpPropPageDlgProcDestroy(hwndDlg);
4303  }
4304  break;
4305  case WM_SHOWWINDOW:
4306  {
4307  if (!propPageContext->LayoutInitialized)
4308  {
4309  PPH_LAYOUT_ITEM dialogItem;
4310 
4311  dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg,
4313  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST),
4314  dialogItem, PH_ANCHOR_ALL);
4315 
4316  PhDoPropPageLayout(hwndDlg);
4317 
4318  propPageContext->LayoutInitialized = TRUE;
4319  }
4320  }
4321  break;
4322  case WM_NOTIFY:
4323  {
4325  }
4326  break;
4327  }
4328 
4329  return FALSE;
4330 }
4331 
4332 static VOID NTAPI HandleAddedHandler(
4333  _In_opt_ PVOID Parameter,
4334  _In_opt_ PVOID Context
4335  )
4336 {
4337  PPH_HANDLES_CONTEXT handlesContext = (PPH_HANDLES_CONTEXT)Context;
4338 
4339  // Parameter contains a pointer to the added handle item.
4340  PhReferenceObject(Parameter);
4341  PostMessage(
4342  handlesContext->WindowHandle,
4344  PhGetRunIdProvider(&handlesContext->ProviderRegistration),
4345  (LPARAM)Parameter
4346  );
4347 }
4348 
4349 static VOID NTAPI HandleModifiedHandler(
4350  _In_opt_ PVOID Parameter,
4351  _In_opt_ PVOID Context
4352  )
4353 {
4354  PPH_HANDLES_CONTEXT handlesContext = (PPH_HANDLES_CONTEXT)Context;
4355 
4356  PostMessage(handlesContext->WindowHandle, WM_PH_HANDLE_MODIFIED, 0, (LPARAM)Parameter);
4357 }
4358 
4359 static VOID NTAPI HandleRemovedHandler(
4360  _In_opt_ PVOID Parameter,
4361  _In_opt_ PVOID Context
4362  )
4363 {
4364  PPH_HANDLES_CONTEXT handlesContext = (PPH_HANDLES_CONTEXT)Context;
4365 
4366  PostMessage(handlesContext->WindowHandle, WM_PH_HANDLE_REMOVED, 0, (LPARAM)Parameter);
4367 }
4368 
4369 static VOID NTAPI HandlesUpdatedHandler(
4370  _In_opt_ PVOID Parameter,
4371  _In_opt_ PVOID Context
4372  )
4373 {
4374  PPH_HANDLES_CONTEXT handlesContext = (PPH_HANDLES_CONTEXT)Context;
4375 
4376  PostMessage(handlesContext->WindowHandle, WM_PH_HANDLES_UPDATED, 0, 0);
4377 }
4378 
4379 static NTSTATUS PhpDuplicateHandleFromProcessItem(
4380  _Out_ PHANDLE NewHandle,
4381  _In_ ACCESS_MASK DesiredAccess,
4382  _In_ HANDLE ProcessId,
4383  _In_ HANDLE Handle
4384  )
4385 {
4386  NTSTATUS status;
4387  HANDLE processHandle;
4388 
4389  if (!NT_SUCCESS(status = PhOpenProcess(
4390  &processHandle,
4391  PROCESS_DUP_HANDLE,
4392  ProcessId
4393  )))
4394  return status;
4395 
4396  status = PhDuplicateObject(
4397  processHandle,
4398  Handle,
4399  NtCurrentProcess(),
4400  NewHandle,
4401  DesiredAccess,
4402  0,
4403  0
4404  );
4405  NtClose(processHandle);
4406 
4407  return status;
4408 }
4409 
4410 static VOID PhpShowProcessPropContext(
4411  _In_ PVOID Parameter
4412  )
4413 {
4414  PhShowProcessProperties(Parameter);
4415  PhDereferenceObject(Parameter);
4416 }
4417 
4419  _In_ struct _PH_EMENU_ITEM *Menu,
4420  _In_ ULONG InsertBeforeId,
4421  _In_ BOOLEAN EnableShortcut,
4422  _In_ PPH_HANDLE_ITEM_INFO Info
4423  )
4424 {
4425  PPH_EMENU_ITEM parentItem;
4426  ULONG indexInParent;
4427 
4428  if (!PhFindEMenuItemEx(Menu, 0, NULL, InsertBeforeId, &parentItem, &indexInParent))
4429  return;
4430 
4431  if (PhEqualString2(Info->TypeName, L"File", TRUE) || PhEqualString2(Info->TypeName, L"DLL", TRUE) ||
4432  PhEqualString2(Info->TypeName, L"Mapped File", TRUE) || PhEqualString2(Info->TypeName, L"Mapped Image", TRUE))
4433  {
4434  if (PhEqualString2(Info->TypeName, L"File", TRUE))
4435  PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES2, L"File Properties", NULL, NULL), indexInParent);
4436 
4437  PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES1, PhaAppendCtrlEnter(L"Open &File Location", EnableShortcut), NULL, NULL), indexInParent);
4438  }
4439  else if (PhEqualString2(Info->TypeName, L"Key", TRUE))
4440  {
4441  PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES1, PhaAppendCtrlEnter(L"Open Key", EnableShortcut), NULL, NULL), indexInParent);
4442  }
4443  else if (PhEqualString2(Info->TypeName, L"Process", TRUE))
4444  {
4445  PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES1, PhaAppendCtrlEnter(L"Process Properties", EnableShortcut), NULL, NULL), indexInParent);
4446  }
4447  else if (PhEqualString2(Info->TypeName, L"Section", TRUE))
4448  {
4449  PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES1, PhaAppendCtrlEnter(L"Read/Write Memory", EnableShortcut), NULL, NULL), indexInParent);
4450  }
4451  else if (PhEqualString2(Info->TypeName, L"Thread", TRUE))
4452  {
4453  PhInsertEMenuItem(parentItem, PhCreateEMenuItem(0, ID_HANDLE_OBJECTPROPERTIES1, PhaAppendCtrlEnter(L"Go to Thread", EnableShortcut), NULL, NULL), indexInParent);
4454  }
4455 }
4456 
4458  _In_ HWND hWnd,
4459  _In_ PPH_HANDLE_ITEM_INFO Info
4460  )
4461 {
4462  if (PhEqualString2(Info->TypeName, L"File", TRUE) || PhEqualString2(Info->TypeName, L"DLL", TRUE) ||
4463  PhEqualString2(Info->TypeName, L"Mapped File", TRUE) || PhEqualString2(Info->TypeName, L"Mapped Image", TRUE))
4464  {
4465  if (Info->BestObjectName)
4466  PhShellExploreFile(hWnd, Info->BestObjectName->Buffer);
4467  else
4468  PhShowError(hWnd, L"Unable to open file location because the object is unnamed.");
4469  }
4470  else if (PhEqualString2(Info->TypeName, L"Key", TRUE))
4471  {
4472  if (Info->BestObjectName)
4473  PhShellOpenKey2(hWnd, Info->BestObjectName);
4474  else
4475  PhShowError(hWnd, L"Unable to open key because the object is unnamed.");
4476  }
4477  else if (PhEqualString2(Info->TypeName, L"Process", TRUE))
4478  {
4479  HANDLE processHandle;
4480  HANDLE processId;
4481  PPH_PROCESS_ITEM targetProcessItem;
4482 
4483  processId = NULL;
4484 
4485  if (KphIsConnected())
4486  {
4488  &processHandle,
4490  Info->ProcessId
4491  )))
4492  {
4493  PROCESS_BASIC_INFORMATION basicInfo;
4494 
4496  processHandle,
4497  Info->Handle,
4499  &basicInfo,
4500  sizeof(PROCESS_BASIC_INFORMATION),
4501  NULL
4502  )))
4503  {
4504  processId = basicInfo.UniqueProcessId;
4505  }
4506 
4507  NtClose(processHandle);
4508  }
4509  }
4510  else
4511  {
4512  HANDLE handle;
4513  PROCESS_BASIC_INFORMATION basicInfo;
4514 
4515  if (NT_SUCCESS(PhpDuplicateHandleFromProcessItem(
4516  &handle,
4518  Info->ProcessId,
4519  Info->Handle
4520  )))
4521  {
4522  if (NT_SUCCESS(PhGetProcessBasicInformation(handle, &basicInfo)))
4523  processId = basicInfo.UniqueProcessId;
4524 
4525  NtClose(handle);
4526  }
4527  }
4528 
4529  if (processId)
4530  {
4531  targetProcessItem = PhReferenceProcessItem(processId);
4532 
4533  if (targetProcessItem)
4534  {
4536  PhDereferenceObject(targetProcessItem);
4537  }
4538  else
4539  {
4540  PhShowError(hWnd, L"The process does not exist.");
4541  }
4542  }
4543  }
4544  else if (PhEqualString2(Info->TypeName, L"Section", TRUE))
4545  {
4546  HANDLE handle = NULL;
4547  BOOLEAN readOnly = FALSE;
4548 
4549  if (!NT_SUCCESS(PhpDuplicateHandleFromProcessItem(
4550  &handle,
4551  SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_WRITE,
4552  Info->ProcessId,
4553  Info->Handle
4554  )))
4555  {
4556  PhpDuplicateHandleFromProcessItem(
4557  &handle,
4558  SECTION_QUERY | SECTION_MAP_READ,
4559  Info->ProcessId,
4560  Info->Handle
4561  );
4562  readOnly = TRUE;
4563  }
4564 
4565  if (handle)
4566  {
4567  NTSTATUS status;
4568  PPH_STRING sectionName = NULL;
4569  SECTION_BASIC_INFORMATION basicInfo;
4570  SIZE_T viewSize = PH_MAX_SECTION_EDIT_SIZE;
4571  PVOID viewBase = NULL;
4572  BOOLEAN tooBig = FALSE;
4573 
4574  PhGetHandleInformation(NtCurrentProcess(), handle, -1, NULL, NULL, NULL, &sectionName);
4575 
4576  if (NT_SUCCESS(PhGetSectionBasicInformation(handle, &basicInfo)))
4577  {
4578  if (basicInfo.MaximumSize.QuadPart <= PH_MAX_SECTION_EDIT_SIZE)
4579  viewSize = (SIZE_T)basicInfo.MaximumSize.QuadPart;
4580  else
4581  tooBig = TRUE;
4582 
4583  status = NtMapViewOfSection(
4584  handle,
4585  NtCurrentProcess(),
4586  &viewBase,
4587  0,
4588  0,
4589  NULL,
4590  &viewSize,
4591  ViewShare,
4592  0,
4593  readOnly ? PAGE_READONLY : PAGE_READWRITE
4594  );
4595 
4596  if (status == STATUS_SECTION_PROTECTION && !readOnly)
4597  {
4598  status = NtMapViewOfSection(
4599  handle,
4600  NtCurrentProcess(),
4601  &viewBase,
4602  0,
4603  0,
4604  NULL,
4605  &viewSize,
4606  ViewShare,
4607  0,
4608  PAGE_READONLY
4609  );
4610  }
4611 
4612  if (NT_SUCCESS(status))
4613  {
4614  PPH_SHOWMEMORYEDITOR showMemoryEditor = PhAllocate(sizeof(PH_SHOWMEMORYEDITOR));
4615 
4616  if (tooBig)
4617  PhShowWarning(hWnd, L"The section size is greater than 32 MB. Only the first 32 MB will be available for editing.");
4618 
4619  memset(showMemoryEditor, 0, sizeof(PH_SHOWMEMORYEDITOR));
4620  showMemoryEditor->ProcessId = NtCurrentProcessId();
4621  showMemoryEditor->BaseAddress = viewBase;
4622  showMemoryEditor->RegionSize = viewSize;
4623  showMemoryEditor->SelectOffset = -1;
4624  showMemoryEditor->SelectLength = 0;
4625  showMemoryEditor->Title = sectionName ? PhConcatStrings2(L"Section - ", sectionName->Buffer) : PhCreateString(L"Section");
4626  showMemoryEditor->Flags = PH_MEMORY_EDITOR_UNMAP_VIEW_OF_SECTION;
4628  }
4629  else
4630  {
4631  PhShowStatus(hWnd, L"Unable to map a view of the section", status, 0);
4632  }
4633  }
4634 
4635  PhClearReference(&sectionName);
4636 
4637  NtClose(handle);
4638  }
4639  }
4640  else if (PhEqualString2(Info->TypeName, L"Thread", TRUE))
4641  {
4642  HANDLE processHandle;
4643  CLIENT_ID clientId;
4644  PPH_PROCESS_ITEM targetProcessItem;
4645  PPH_PROCESS_PROPCONTEXT propContext;
4646 
4647  clientId.UniqueProcess = NULL;
4648  clientId.UniqueThread = NULL;
4649 
4650  if (KphIsConnected())
4651  {
4653  &processHandle,
4655  Info->ProcessId
4656  )))
4657  {
4658  THREAD_BASIC_INFORMATION basicInfo;
4659 
4661  processHandle,
4662  Info->Handle,
4664  &basicInfo,
4665  sizeof(THREAD_BASIC_INFORMATION),
4666  NULL
4667  )))
4668  {
4669  clientId = basicInfo.ClientId;
4670  }
4671 
4672  NtClose(processHandle);
4673  }
4674  }
4675  else
4676  {
4677  HANDLE handle;
4678  THREAD_BASIC_INFORMATION basicInfo;
4679 
4680  if (NT_SUCCESS(PhpDuplicateHandleFromProcessItem(
4681  &handle,
4683  Info->ProcessId,
4684  Info->Handle
4685  )))
4686  {
4687  if (NT_SUCCESS(PhGetThreadBasicInformation(handle, &basicInfo)))
4688  clientId = basicInfo.ClientId;
4689 
4690  NtClose(handle);
4691  }
4692  }
4693 
4694  if (clientId.UniqueProcess)
4695  {
4696  targetProcessItem = PhReferenceProcessItem(clientId.UniqueProcess);
4697 
4698  if (targetProcessItem)
4699  {
4700  propContext = PhCreateProcessPropContext(PhMainWndHandle, targetProcessItem);
4701  PhDereferenceObject(targetProcessItem);
4702  PhSetSelectThreadIdProcessPropContext(propContext, clientId.UniqueThread);
4703  ProcessHacker_Invoke(PhMainWndHandle, PhpShowProcessPropContext, propContext);
4704  }
4705  else
4706  {
4707  PhShowError(hWnd, L"The process does not exist.");
4708  }
4709  }
4710  }
4711 }
4712 
4714  _In_ HWND hWnd,
4715  _In_ PPH_HANDLE_ITEM_INFO Info
4716  )
4717 {
4718  if (PhEqualString2(Info->TypeName, L"File", TRUE) || PhEqualString2(Info->TypeName, L"DLL", TRUE) ||
4719  PhEqualString2(Info->TypeName, L"Mapped File", TRUE) || PhEqualString2(Info->TypeName, L"Mapped Image", TRUE))
4720  {
4721  if (Info->BestObjectName)
4722  PhShellProperties(hWnd, Info->BestObjectName->Buffer);
4723  else
4724  PhShowError(hWnd, L"Unable to open file properties because the object is unnamed.");
4725  }
4726 }
4727 
4729  _In_ PPH_EMENU Menu,
4730  _In_ HANDLE ProcessId,
4731  _In_ PPH_HANDLE_ITEM *Handles,
4732  _In_ ULONG NumberOfHandles,
4733  _Inout_ PPH_HANDLES_CONTEXT HandlesContext
4734  )
4735 {
4736  PPH_EMENU_ITEM item;
4737 
4738  if (NumberOfHandles == 0)
4739  {
4741  }
4742  else if (NumberOfHandles == 1)
4743  {
4744  PH_HANDLE_ITEM_INFO info;
4745 
4746  info.ProcessId = ProcessId;
4747  info.Handle = Handles[0]->Handle;
4748  info.TypeName = Handles[0]->TypeName;
4749  info.BestObjectName = Handles[0]->BestObjectName;
4751  }
4752  else
4753  {
4755 
4758  }
4759 
4760  // Remove irrelevant menu items.
4761 
4762  if (!KphIsConnected())
4763  {
4764  if (item = PhFindEMenuItem(Menu, 0, NULL, ID_HANDLE_PROTECTED))
4765  PhDestroyEMenuItem(item);
4766  if (item = PhFindEMenuItem(Menu, 0, NULL, ID_HANDLE_INHERIT))
4767  PhDestroyEMenuItem(item);
4768  }
4769 
4770  // Protected, Inherit
4771  if (NumberOfHandles == 1 && KphIsConnected())
4772  {
4773  HandlesContext->SelectedHandleProtected = FALSE;
4774  HandlesContext->SelectedHandleInherit = FALSE;
4775 
4776  if (Handles[0]->Attributes & OBJ_PROTECT_CLOSE)
4777  {
4778  HandlesContext->SelectedHandleProtected = TRUE;
4780  }
4781 
4782  if (Handles[0]->Attributes & OBJ_INHERIT)
4783  {
4784  HandlesContext->SelectedHandleInherit = TRUE;
4786  }
4787  }
4788 }
4789 
4791  _In_ HWND hwndDlg,
4792  _In_ PPH_PROCESS_ITEM ProcessItem,
4793  _In_ PPH_HANDLES_CONTEXT Context,
4794  _In_ PPH_TREENEW_CONTEXT_MENU ContextMenu
4795  )
4796 {
4797  PPH_HANDLE_ITEM *handles;
4798  ULONG numberOfHandles;
4799 
4800  PhGetSelectedHandleItems(&Context->ListContext, &handles, &numberOfHandles);
4801 
4802  if (numberOfHandles != 0)
4803  {
4804  PPH_EMENU menu;
4805  PPH_EMENU_ITEM item;
4806  PH_PLUGIN_MENU_INFORMATION menuInfo;
4807 
4808  menu = PhCreateEMenu();
4809  PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_HANDLE), 0);
4811 
4812  PhpInitializeHandleMenu(menu, ProcessItem->ProcessId, handles, numberOfHandles, Context);
4813  PhInsertCopyCellEMenuItem(menu, ID_HANDLE_COPY, Context->ListContext.TreeNewHandle, ContextMenu->Column);
4814 
4815  if (PhPluginsEnabled)
4816  {
4817  PhPluginInitializeMenuInfo(&menuInfo, menu, hwndDlg, 0);
4818  menuInfo.u.Handle.ProcessId = ProcessItem->ProcessId;
4819  menuInfo.u.Handle.Handles = handles;
4820  menuInfo.u.Handle.NumberOfHandles = numberOfHandles;
4821 
4823  }
4824 
4825  item = PhShowEMenu(
4826  menu,
4827  hwndDlg,
4830  ContextMenu->Location.x,
4831  ContextMenu->Location.y
4832  );
4833 
4834  if (item)
4835  {
4836  BOOLEAN handled = FALSE;
4837 
4838  handled = PhHandleCopyCellEMenuItem(item);
4839 
4840  if (!handled && PhPluginsEnabled)
4841  handled = PhPluginTriggerEMenuItem(&menuInfo, item);
4842 
4843  if (!handled)
4844  SendMessage(hwndDlg, WM_COMMAND, item->Id, 0);
4845  }
4846 
4847  PhDestroyEMenu(menu);
4848  }
4849 
4850  PhFree(handles);
4851 }
4852 
4853 INT_PTR CALLBACK PhpProcessHandlesDlgProc(
4854  _In_ HWND hwndDlg,
4855  _In_ UINT uMsg,
4856  _In_ WPARAM wParam,
4857  _In_ LPARAM lParam
4858  )
4859 {
4860  LPPROPSHEETPAGE propSheetPage;
4861  PPH_PROCESS_PROPPAGECONTEXT propPageContext;
4862  PPH_PROCESS_ITEM processItem;
4863  PPH_HANDLES_CONTEXT handlesContext;
4864  HWND tnHandle;
4865 
4866  if (PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam,
4867  &propSheetPage, &propPageContext, &processItem))
4868  {
4869  handlesContext = (PPH_HANDLES_CONTEXT)propPageContext->Context;
4870 
4871  if (handlesContext)
4872  tnHandle = handlesContext->ListContext.TreeNewHandle;
4873  }
4874  else
4875  {
4876  return FALSE;
4877  }
4878 
4879  switch (uMsg)
4880  {
4881  case WM_INITDIALOG:
4882  {
4883  handlesContext = propPageContext->Context =
4885 
4886  handlesContext->Provider = PhCreateHandleProvider(
4887  processItem->ProcessId
4888  );
4892  handlesContext->Provider,
4893  &handlesContext->ProviderRegistration
4894  );
4896  &handlesContext->Provider->HandleAddedEvent,
4897  HandleAddedHandler,
4898  handlesContext,
4899  &handlesContext->AddedEventRegistration
4900  );
4902  &handlesContext->Provider->HandleModifiedEvent,
4903  HandleModifiedHandler,
4904  handlesContext,
4905  &handlesContext->ModifiedEventRegistration
4906  );
4908  &handlesContext->Provider->HandleRemovedEvent,
4909  HandleRemovedHandler,
4910  handlesContext,
4911  &handlesContext->RemovedEventRegistration
4912  );
4914  &handlesContext->Provider->UpdatedEvent,
4915  HandlesUpdatedHandler,
4916  handlesContext,
4917  &handlesContext->UpdatedEventRegistration
4918  );
4919  handlesContext->WindowHandle = hwndDlg;
4920 
4921  // Initialize the list.
4922  tnHandle = GetDlgItem(hwndDlg, IDC_LIST);
4923  BringWindowToTop(tnHandle);
4924  PhInitializeHandleList(hwndDlg, tnHandle, &handlesContext->ListContext);
4925  TreeNew_SetEmptyText(tnHandle, &LoadingText, 0);
4926  handlesContext->NeedsRedraw = FALSE;
4927  handlesContext->LastRunStatus = -1;
4928  handlesContext->ErrorMessage = NULL;
4929 
4931 
4932  if (PhPluginsEnabled)
4933  {
4934  PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;
4935 
4936  treeNewInfo.TreeNewHandle = tnHandle;
4937  treeNewInfo.CmData = &handlesContext->ListContext.Cm;
4938  treeNewInfo.SystemContext = handlesContext;
4940  }
4941 
4942  PhLoadSettingsHandleList(&handlesContext->ListContext);
4943 
4944  PhSetOptionsHandleList(&handlesContext->ListContext, !!PhGetIntegerSetting(L"HideUnnamedHandles"));
4945  Button_SetCheck(GetDlgItem(hwndDlg, IDC_HIDEUNNAMEDHANDLES),
4946  handlesContext->ListContext.HideUnnamedHandles ? BST_CHECKED : BST_UNCHECKED);
4947 
4948  PhSetEnabledProvider(&handlesContext->ProviderRegistration, TRUE);
4949  PhBoostProvider(&handlesContext->ProviderRegistration, NULL);
4950  }
4951  break;
4952  case WM_DESTROY:
4953  {
4955 
4957  &handlesContext->Provider->HandleAddedEvent,
4958  &handlesContext->AddedEventRegistration
4959  );
4961  &handlesContext->Provider->HandleModifiedEvent,
4962  &handlesContext->ModifiedEventRegistration
4963  );
4965  &handlesContext->Provider->HandleRemovedEvent,
4966  &handlesContext->RemovedEventRegistration
4967  );
4969  &handlesContext->Provider->UpdatedEvent,
4970  &handlesContext->UpdatedEventRegistration
4971  );
4972  PhUnregisterProvider(&handlesContext->ProviderRegistration);
4973  PhDereferenceObject(handlesContext->Provider);
4974 
4975  if (PhPluginsEnabled)
4976  {
4977  PH_PLUGIN_TREENEW_INFORMATION treeNewInfo;
4978 
4979  treeNewInfo.TreeNewHandle = tnHandle;
4980  treeNewInfo.CmData = &handlesContext->ListContext.Cm;
4982  }
4983 
4984  PhSaveSettingsHandleList(&handlesContext->ListContext);
4985  PhDeleteHandleList(&handlesContext->ListContext);
4986 
4987  PhFree(handlesContext);
4988 
4989  PhpPropPageDlgProcDestroy(hwndDlg);
4990  }
4991  break;
4992  case WM_SHOWWINDOW:
4993  {
4994  if (!propPageContext->LayoutInitialized)
4995  {
4996  PPH_LAYOUT_ITEM dialogItem;
4997 
4998  dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg,
5000  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIST),
5001  dialogItem, PH_ANCHOR_ALL);
5002 
5003  PhDoPropPageLayout(hwndDlg);
5004 
5005  propPageContext->LayoutInitialized = TRUE;
5006  }
5007  }
5008  break;
5009  case WM_COMMAND:
5010  {
5011  INT id = LOWORD(wParam);
5012 
5013  switch (id)
5014  {
5015  case ID_SHOWCONTEXTMENU:
5016  {
5017  PhShowHandleContextMenu(hwndDlg, processItem, handlesContext, (PPH_TREENEW_CONTEXT_MENU)lParam);
5018  }
5019  break;
5020  case ID_HANDLE_CLOSE:
5021  {
5022  PPH_HANDLE_ITEM *handles;
5023  ULONG numberOfHandles;
5024 
5025  PhGetSelectedHandleItems(&handlesContext->ListContext, &handles, &numberOfHandles);
5026  PhReferenceObjects(handles, numberOfHandles);
5027 
5028  if (PhUiCloseHandles(hwndDlg, processItem->ProcessId, handles, numberOfHandles, !!lParam))
5029  PhDeselectAllHandleNodes(&handlesContext->ListContext);
5030 
5031  PhDereferenceObjects(handles, numberOfHandles);
5032  PhFree(handles);
5033  }
5034  break;
5035  case ID_HANDLE_PROTECTED:
5036  case ID_HANDLE_INHERIT:
5037  {
5038  PPH_HANDLE_ITEM handleItem = PhGetSelectedHandleItem(&handlesContext->ListContext);
5039 
5040  if (handleItem)
5041  {
5042  ULONG attributes = 0;
5043 
5044  // Re-create the attributes.
5045 
5046  if (handlesContext->SelectedHandleProtected)
5047  attributes |= OBJ_PROTECT_CLOSE;
5048  if (handlesContext->SelectedHandleInherit)
5049  attributes |= OBJ_INHERIT;
5050 
5051  // Toggle the appropriate bit.
5052 
5053  if (id == ID_HANDLE_PROTECTED)
5054  attributes ^= OBJ_PROTECT_CLOSE;
5055  else if (id == ID_HANDLE_INHERIT)
5056  attributes ^= OBJ_INHERIT;
5057 
5058  PhReferenceObject(handleItem);
5059  PhUiSetAttributesHandle(hwndDlg, processItem->ProcessId, handleItem, attributes);
5060  PhDereferenceObject(handleItem);
5061  }
5062  }
5063  break;
5066  {
5067  PPH_HANDLE_ITEM handleItem = PhGetSelectedHandleItem(&handlesContext->ListContext);
5068 
5069  if (handleItem)
5070  {
5071  PH_HANDLE_ITEM_INFO info;
5072 
5073  info.ProcessId = processItem->ProcessId;
5074  info.Handle = handleItem->Handle;
5075  info.TypeName = handleItem->TypeName;
5076  info.BestObjectName = handleItem->BestObjectName;
5077 
5078  if (id == ID_HANDLE_OBJECTPROPERTIES1)
5079  PhShowHandleObjectProperties1(hwndDlg, &info);
5080  else
5081  PhShowHandleObjectProperties2(hwndDlg, &info);
5082  }
5083  }
5084  break;
5085  case ID_HANDLE_PROPERTIES:
5086  {
5087  PPH_HANDLE_ITEM handleItem = PhGetSelectedHandleItem(&handlesContext->ListContext);
5088 
5089  if (handleItem)
5090  {
5091  PhReferenceObject(handleItem);
5092  PhShowHandleProperties(hwndDlg, processItem->ProcessId, handleItem);
5093  PhDereferenceObject(handleItem);
5094  }
5095  }
5096  break;
5097  case ID_HANDLE_COPY:
5098  {
5099  PPH_STRING text;
5100 
5101  text = PhGetTreeNewText(tnHandle, 0);
5102  PhSetClipboardString(tnHandle, &text->sr);
5103  PhDereferenceObject(text);
5104  }
5105  break;
5107  {
5108  BOOLEAN hide;
5109 
5110  hide = Button_GetCheck(GetDlgItem(hwndDlg, IDC_HIDEUNNAMEDHANDLES)) == BST_CHECKED;
5111  PhSetOptionsHandleList(&handlesContext->ListContext, hide);
5112  }
5113  break;
5114  }
5115  }
5116  break;
5117  case WM_NOTIFY:
5118  {
5119  LPNMHDR header = (LPNMHDR)lParam;
5120 
5121  switch (header->code)
5122  {
5123  case PSN_SETACTIVE:
5124  PhSetEnabledProvider(&handlesContext->ProviderRegistration, TRUE);
5125  break;
5126  case PSN_KILLACTIVE:
5127  PhSetEnabledProvider(&handlesContext->ProviderRegistration, FALSE);
5128  break;
5129  }
5130  }
5131  break;
5132  case WM_PH_HANDLE_ADDED:
5133  {
5134  ULONG runId = (ULONG)wParam;
5135  PPH_HANDLE_ITEM handleItem = (PPH_HANDLE_ITEM)lParam;
5136 
5137  if (!handlesContext->NeedsRedraw)
5138  {
5139  TreeNew_SetRedraw(tnHandle, FALSE);
5140  handlesContext->NeedsRedraw = TRUE;
5141  }
5142 
5143  PhAddHandleNode(&handlesContext->ListContext, handleItem, runId);
5144  PhDereferenceObject(handleItem);
5145  }
5146  break;
5147  case WM_PH_HANDLE_MODIFIED:
5148  {
5149  PPH_HANDLE_ITEM handleItem = (PPH_HANDLE_ITEM)lParam;
5150 
5151  if (!handlesContext->NeedsRedraw)
5152  {
5153  TreeNew_SetRedraw(tnHandle, FALSE);
5154  handlesContext->NeedsRedraw = TRUE;
5155  }
5156 
5157  PhUpdateHandleNode(&handlesContext->ListContext, PhFindHandleNode(&handlesContext->ListContext, handleItem->Handle));
5158  }
5159  break;
5160  case WM_PH_HANDLE_REMOVED:
5161  {
5162  PPH_HANDLE_ITEM handleItem = (PPH_HANDLE_ITEM)lParam;
5163 
5164  if (!handlesContext->NeedsRedraw)
5165  {
5166  TreeNew_SetRedraw(tnHandle, FALSE);
5167  handlesContext->NeedsRedraw = TRUE;
5168  }
5169 
5170  PhRemoveHandleNode(&handlesContext->ListContext, PhFindHandleNode(&handlesContext->ListContext, handleItem->Handle));
5171  }
5172  break;
5173  case WM_PH_HANDLES_UPDATED:
5174  {
5175  PhTickHandleNodes(&handlesContext->ListContext);
5176 
5177  if (handlesContext->LastRunStatus != handlesContext->Provider->RunStatus)
5178  {
5179  NTSTATUS status;
5180  PPH_STRING message;
5181 
5182  status = handlesContext->Provider->RunStatus;
5183  handlesContext->LastRunStatus = status;
5184 
5185  if (!PH_IS_REAL_PROCESS_ID(processItem->ProcessId))
5186  status = STATUS_SUCCESS;
5187 
5188  if (NT_SUCCESS(status))
5189  {
5190  TreeNew_SetEmptyText(tnHandle, &EmptyHandlesText, 0);
5191  }
5192  else
5193  {
5194  message = PhGetStatusMessage(status, 0);
5195  PhMoveReference(&handlesContext->ErrorMessage, PhFormatString(L"Unable to query handle information:\n%s", PhGetStringOrDefault(message, L"Unknown error.")));
5196  PhClearReference(&message);
5197  TreeNew_SetEmptyText(tnHandle, &handlesContext->ErrorMessage->sr, 0);
5198  }
5199 
5200  InvalidateRect(tnHandle, NULL, FALSE);
5201  }
5202 
5203  if (handlesContext->NeedsRedraw)
5204  {
5205  TreeNew_SetRedraw(tnHandle, TRUE);
5206  handlesContext->NeedsRedraw = FALSE;
5207  }
5208  }
5209  break;
5210  }
5211 
5212  return FALSE;
5213 }
5214 
5215 static NTSTATUS NTAPI PhpOpenProcessJob(
5216  _Out_ PHANDLE Handle,
5217  _In_ ACCESS_MASK DesiredAccess,
5218  _In_opt_ PVOID Context
5219  )
5220 {
5221  NTSTATUS status;
5222  HANDLE processHandle;
5223  HANDLE jobHandle = NULL;
5224 
5225  if (!NT_SUCCESS(status = PhOpenProcess(
5226  &processHandle,
5228  (HANDLE)Context
5229  )))
5230  return status;
5231 
5232  status = KphOpenProcessJob(processHandle, DesiredAccess, &jobHandle);
5233  NtClose(processHandle);
5234 
5235  if (NT_SUCCESS(status) && status != STATUS_PROCESS_NOT_IN_JOB && jobHandle)
5236  {
5237  *Handle = jobHandle;
5238  }
5239  else if (NT_SUCCESS(status))
5240  {
5241  status = STATUS_UNSUCCESSFUL;
5242  }
5243 
5244  return status;
5245 }
5246 
5247 INT_PTR CALLBACK PhpProcessJobHookProc(
5248  _In_ HWND hwndDlg,
5249  _In_ UINT uMsg,
5250  _In_ WPARAM wParam,
5251  _In_ LPARAM lParam
5252  )
5253 {
5254  switch (uMsg)
5255  {
5256  case WM_DESTROY:
5257  {
5258  RemoveProp(hwndDlg, PhMakeContextAtom());
5259  }
5260  break;
5261  case WM_SHOWWINDOW:
5262  {
5263  if (!GetProp(hwndDlg, PhMakeContextAtom())) // LayoutInitialized
5264  {
5265  PPH_LAYOUT_ITEM dialogItem;
5266 
5267  // This is a big violation of abstraction...
5268 
5269  dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg,
5271  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_NAME),
5272  dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
5273  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_TERMINATE),
5274  dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
5275  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_PROCESSES),
5276  dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
5277  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_ADD),
5278  dialogItem, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
5279  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_LIMITS),
5280  dialogItem, PH_ANCHOR_ALL);
5281  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_ADVANCED),
5282  dialogItem, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
5283 
5284  PhDoPropPageLayout(hwndDlg);
5285 
5286  SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)TRUE);
5287  }
5288  }
5289  break;
5290  }
5291 
5292  return FALSE;
5293 }
5294 
5295 static VOID PhpLayoutServiceListControl(
5296  _In_ HWND hwndDlg,
5297  _In_ HWND ServiceListHandle
5298  )
5299 {
5300  RECT rect;
5301 
5302  GetWindowRect(GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), &rect);
5303  MapWindowPoints(NULL, hwndDlg, (POINT *)&rect, 2);
5304 
5305  MoveWindow(
5306  ServiceListHandle,
5307  rect.left,
5308  rect.top,
5309  rect.right - rect.left,
5310  rect.bottom - rect.top,
5311  TRUE
5312  );
5313 }
5314 
5315 INT_PTR CALLBACK PhpProcessServicesDlgProc(
5316  _In_ HWND hwndDlg,
5317  _In_ UINT uMsg,
5318  _In_ WPARAM wParam,
5319  _In_ LPARAM lParam
5320  )
5321 {
5322  LPPROPSHEETPAGE propSheetPage;
5323  PPH_PROCESS_PROPPAGECONTEXT propPageContext;
5324  PPH_PROCESS_ITEM processItem;
5325 
5326  if (!PhpPropPageDlgProcHeader(hwndDlg, uMsg, lParam,
5327  &propSheetPage, &propPageContext, &processItem))
5328  {
5329  return FALSE;
5330  }
5331 
5332  switch (uMsg)
5333  {
5334  case WM_INITDIALOG:
5335  {
5336  PPH_SERVICE_ITEM *services;
5337  ULONG numberOfServices;
5338  ULONG i;
5339  HWND serviceListHandle;
5340 
5341  // Get a copy of the process' service list.
5342 
5344 
5345  numberOfServices = processItem->ServiceList->Count;
5346  services = PhAllocate(numberOfServices * sizeof(PPH_SERVICE_ITEM));
5347 
5348  {
5349  ULONG enumerationKey = 0;
5350  PPH_SERVICE_ITEM serviceItem;
5351 
5352  i = 0;
5353 
5354  while (PhEnumPointerList(processItem->ServiceList, &enumerationKey, &serviceItem))
5355  {
5356  PhReferenceObject(serviceItem);
5357  services[i++] = serviceItem;
5358  }
5359  }
5360 
5362 
5363  serviceListHandle = PhCreateServiceListControl(
5364  hwndDlg,
5365  services,
5366  numberOfServices
5367  );
5368  SendMessage(serviceListHandle, WM_PH_SET_LIST_VIEW_SETTINGS, 0, (LPARAM)L"ProcessServiceListViewColumns");
5369  ShowWindow(serviceListHandle, SW_SHOW);
5370 
5371  propPageContext->Context = serviceListHandle;
5372  }
5373  break;
5374  case WM_DESTROY:
5375  {
5376  PhpPropPageDlgProcDestroy(hwndDlg);
5377  }
5378  break;
5379  case WM_SHOWWINDOW:
5380  {
5381  if (!propPageContext->LayoutInitialized)
5382  {
5383  PPH_LAYOUT_ITEM dialogItem;
5384 
5385  dialogItem = PhAddPropPageLayoutItem(hwndDlg, hwndDlg,
5387  PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT),
5388  dialogItem, PH_ANCHOR_ALL);
5389 
5390  PhDoPropPageLayout(hwndDlg);
5391  PhpLayoutServiceListControl(hwndDlg, (HWND)propPageContext->Context);
5392 
5393  propPageContext->LayoutInitialized = TRUE;
5394  }
5395  }
5396  break;
5397  case WM_SIZE:
5398  {
5399  PhpLayoutServiceListControl(hwndDlg, (HWND)propPageContext->Context);
5400  }
5401  break;
5402  }
5403 
5404  return FALSE;
5405 }
5406 
5408  _In_ PVOID Parameter
5409  )
5410 {
5411  PH_AUTO_POOL autoPool;
5412  PPH_PROCESS_PROPCONTEXT PropContext = (PPH_PROCESS_PROPCONTEXT)Parameter;
5414  PPH_STRING startPage;
5415  HWND hwnd;
5416  BOOL result;
5417  MSG message;
5418 
5419  PhInitializeAutoPool(&autoPool);
5420 
5421  // Wait for stage 1 to be processed.
5422  PhWaitForEvent(&PropContext->ProcessItem->Stage1Event, NULL);
5423  // Refresh the icon which may have been updated due to
5424  // stage 1.
5425  PhRefreshProcessPropContext(PropContext);
5426 
5427  // Add the pages...
5428 
5429  // General
5431  MAKEINTRESOURCE(IDD_PROCGENERAL),
5433  NULL
5434  );
5435  PhAddProcessPropPage(PropContext, newPage);
5436 
5437  // Statistics
5439  MAKEINTRESOURCE(IDD_PROCSTATISTICS),
5441  NULL
5442  );
5443  PhAddProcessPropPage(PropContext, newPage);
5444 
5445  // Performance
5447  MAKEINTRESOURCE(IDD_PROCPERFORMANCE),
5449  NULL
5450  );
5451  PhAddProcessPropPage(PropContext, newPage);
5452 
5453  // Threads
5455  MAKEINTRESOURCE(IDD_PROCTHREADS),
5457  NULL
5458  );
5459  PhAddProcessPropPage(PropContext, newPage);
5460 
5461  // Token
5463  PropContext,
5464  PhCreateTokenPage(PhpOpenProcessToken, (PVOID)PropContext->ProcessItem->ProcessId, PhpProcessTokenHookProc)
5465  );
5466 
5467  // Modules
5469  MAKEINTRESOURCE(IDD_PROCMODULES),
5471  NULL
5472  );
5473  PhAddProcessPropPage(PropContext, newPage);
5474 
5475  // Memory
5477  MAKEINTRESOURCE(IDD_PROCMEMORY),
5479  NULL
5480  );
5481  PhAddProcessPropPage(PropContext, newPage);
5482 
5483  // Environment
5485  MAKEINTRESOURCE(IDD_PROCENVIRONMENT),
5487  NULL
5488  );
5489  PhAddProcessPropPage(PropContext, newPage);
5490 
5491  // Handles
5493  MAKEINTRESOURCE(IDD_PROCHANDLES),
5495  NULL
5496  );
5497  PhAddProcessPropPage(PropContext, newPage);
5498 
5499  // Job
5500  if (
5501  PropContext->ProcessItem->IsInJob &&
5502  // There's no way the job page can function without KPH since it needs
5503  // to open a handle to the job.
5504  KphIsConnected()
5505  )
5506  {
5508  PropContext,
5509  PhCreateJobPage(PhpOpenProcessJob, (PVOID)PropContext->ProcessItem->ProcessId, PhpProcessJobHookProc)
5510  );
5511  }
5512 
5513  // Services
5514  if (PropContext->ProcessItem->ServiceList && PropContext->ProcessItem->ServiceList->Count != 0)
5515  {
5517  MAKEINTRESOURCE(IDD_PROCSERVICES),
5519  NULL
5520  );
5521  PhAddProcessPropPage(PropContext, newPage);
5522  }
5523 
5524  // Plugin-supplied pages
5525  if (PhPluginsEnabled)
5526  {
5527  PH_PLUGIN_PROCESS_PROPCONTEXT pluginProcessPropContext;
5528 
5529  pluginProcessPropContext.PropContext = PropContext;
5530  pluginProcessPropContext.ProcessItem = PropContext->ProcessItem;
5531 
5533  }
5534 
5535  // Create the property sheet
5536 
5537  if (PropContext->SelectThreadId)
5538  PhSetStringSetting(L"ProcPropPage", L"Threads");
5539 
5540  startPage = PhGetStringSetting(L"ProcPropPage");
5541  PropContext->PropSheetHeader.dwFlags |= PSH_USEPSTARTPAGE;
5542  PropContext->PropSheetHeader.pStartPage = startPage->Buffer;
5543 
5544  hwnd = (HWND)PropertySheet(&PropContext->PropSheetHeader);
5545 
5546  PhDereferenceObject(startPage);
5547 
5548  PropContext->WindowHandle = hwnd;
5549  PhSetEvent(&PropContext->CreatedEvent);
5550 
5551  // Main event loop
5552 
5553  while (result = GetMessage(&message, NULL, 0, 0))
5554  {
5555  if (result == -1)
5556  break;
5557 
5558  if (!PropSheet_IsDialogMessage(hwnd, &message))
5559  {
5560  TranslateMessage(&message);
5561  DispatchMessage(&message);
5562  }
5563 
5564  PhDrainAutoPool(&autoPool);
5565 
5566  // Destroy the window when necessary.
5567  if (!PropSheet_GetCurrentPageHwnd(hwnd))
5568  {
5569  DestroyWindow(hwnd);
5570  break;
5571  }
5572  }
5573 
5574  PhDereferenceObject(PropContext);
5575 
5576  PhDeleteAutoPool(&autoPool);
5577 
5578  return STATUS_SUCCESS;
5579 }
5580 
5582  _In_ PPH_PROCESS_PROPCONTEXT Context
5583  )
5584 {
5585  HANDLE threadHandle;
5586 
5587  PhReferenceObject(Context);