Process Hacker
mainwnd.c
Go to the documentation of this file.
1 /*
2  * Process Hacker -
3  * main window
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 #define PH_MAINWND_PRIVATE
24 #include <phapp.h>
25 #include <kphuser.h>
26 #include <settings.h>
27 #include <emenu.h>
28 #include <verify.h>
29 #include <phsvccl.h>
30 #include <phplug.h>
31 #include <cpysave.h>
32 #include <notifico.h>
33 #include <memsrch.h>
34 #include <symprv.h>
35 #include <sysinfo.h>
36 #include <miniinfo.h>
37 #include <mainwndp.h>
38 #include <windowsx.h>
39 #include <shlobj.h>
40 #include <winsta.h>
41 #include <iphlpapi.h>
42 
43 #define RUNAS_MODE_ADMIN 1
44 #define RUNAS_MODE_LIMITED 2
45 
46 typedef HRESULT (WINAPI *_LoadIconMetric)(
47  _In_ HINSTANCE hinst,
48  _In_ PCWSTR pszName,
49  _In_ int lims,
50  _Out_ HICON *phico
51  );
52 
56 
57 static BOOLEAN NeedsMaximize = FALSE;
58 static ULONG NeedsSelectPid = 0;
59 static BOOLEAN AlwaysOnTop = FALSE;
60 
61 static BOOLEAN DelayedLoadCompleted = FALSE;
62 static ULONG NotifyIconNotifyMask;
63 
64 static PH_CALLBACK_DECLARE(LayoutPaddingCallback);
65 static RECT LayoutPadding = { 0, 0, 0, 0 };
66 static BOOLEAN LayoutPaddingValid = TRUE;
67 static HWND TabControlHandle;
68 static INT ProcessesTabIndex;
69 static INT ServicesTabIndex;
70 static INT NetworkTabIndex;
71 static INT MaxTabIndex;
72 static INT OldTabIndex;
73 static PPH_LIST AdditionalTabPageList = NULL;
74 static HWND ProcessTreeListHandle;
75 static HWND ServiceTreeListHandle;
76 static HWND NetworkTreeListHandle;
77 static HFONT CurrentCustomFont;
78 
79 static BOOLEAN NetworkFirstTime = TRUE;
80 static BOOLEAN ServiceTreeListLoaded = FALSE;
81 static BOOLEAN NetworkTreeListLoaded = FALSE;
82 static HMENU SubMenuHandles[5];
83 static PPH_EMENU SubMenuObjects[5];
84 static PPH_LIST LegacyAddMenuItemList;
85 static BOOLEAN UsersMenuInitialized = FALSE;
86 static BOOLEAN UpdateAutomatically = TRUE;
87 
88 static PH_CALLBACK_REGISTRATION SymInitRegistration;
89 
90 static PH_PROVIDER_REGISTRATION ProcessProviderRegistration;
91 static PH_CALLBACK_REGISTRATION ProcessAddedRegistration;
92 static PH_CALLBACK_REGISTRATION ProcessModifiedRegistration;
93 static PH_CALLBACK_REGISTRATION ProcessRemovedRegistration;
94 static PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration;
95 static BOOLEAN ProcessesNeedsRedraw = FALSE;
96 static PPH_PROCESS_NODE ProcessToScrollTo = NULL;
97 
98 static PH_PROVIDER_REGISTRATION ServiceProviderRegistration;
99 static PH_CALLBACK_REGISTRATION ServiceAddedRegistration;
100 static PH_CALLBACK_REGISTRATION ServiceModifiedRegistration;
101 static PH_CALLBACK_REGISTRATION ServiceRemovedRegistration;
102 static PH_CALLBACK_REGISTRATION ServicesUpdatedRegistration;
103 static PPH_POINTER_LIST ServicesPendingList;
104 static BOOLEAN ServicesNeedsRedraw = FALSE;
105 
106 static PH_PROVIDER_REGISTRATION NetworkProviderRegistration;
107 static PH_CALLBACK_REGISTRATION NetworkItemAddedRegistration;
108 static PH_CALLBACK_REGISTRATION NetworkItemModifiedRegistration;
109 static PH_CALLBACK_REGISTRATION NetworkItemRemovedRegistration;
110 static PH_CALLBACK_REGISTRATION NetworkItemsUpdatedRegistration;
111 static BOOLEAN NetworkNeedsRedraw = FALSE;
112 
113 static ULONG SelectedRunAsMode;
114 static HWND SelectedProcessWindowHandle;
115 static BOOLEAN SelectedProcessVirtualizationEnabled;
116 static ULONG SelectedUserSessionId;
117 
118 static PPH_TN_FILTER_ENTRY CurrentUserFilterEntry = NULL;
119 static PPH_TN_FILTER_ENTRY SignedFilterEntry = NULL;
120 //static PPH_TN_FILTER_ENTRY CurrentUserNetworkFilterEntry = NULL;
121 //static PPH_TN_FILTER_ENTRY SignedNetworkFilterEntry = NULL;
122 static PPH_TN_FILTER_ENTRY DriverFilterEntry = NULL;
123 
124 static ULONG LastNotificationType;
125 static union
126 {
127  HANDLE ProcessId;
129 } LastNotificationDetails;
130 
132  _In_ INT ShowCommand
133  )
134 {
135  PH_STRING_BUILDER stringBuilder;
136  PH_RECTANGLE windowRectangle;
137 
138  if (PhGetIntegerSetting(L"FirstRun"))
139  {
140  PPH_STRING autoDbghelpPath;
141 
142  // Try to set up the dbghelp path automatically if this is the first run.
143 
144  autoDbghelpPath = PhMwpFindDbghelpPath();
145 
146  if (autoDbghelpPath)
147  {
148  PhSetStringSetting2(L"DbgHelpPath", &autoDbghelpPath->sr);
149  PhDereferenceObject(autoDbghelpPath);
150  }
151 
152  PhSetIntegerSetting(L"FirstRun", FALSE);
153  }
154 
155  // This was added to be able to delay-load dbghelp.dll and symsrv.dll.
156  PhRegisterCallback(&PhSymInitCallback, PhMwpSymInitHandler, NULL, &SymInitRegistration);
157 
159 
161  return FALSE;
162 
163  windowRectangle.Position = PhGetIntegerPairSetting(L"MainWindowPosition");
164  windowRectangle.Size = PhGetIntegerPairSetting(L"MainWindowSize");
165 
166  // Create the window title.
167 
168  PhInitializeStringBuilder(&stringBuilder, 100);
169  PhAppendStringBuilder2(&stringBuilder, L"Process Hacker");
170 
171  if (PhCurrentUserName)
172  {
173  PhAppendStringBuilder2(&stringBuilder, L" [");
174  PhAppendStringBuilder(&stringBuilder, &PhCurrentUserName->sr);
175  PhAppendCharStringBuilder(&stringBuilder, ']');
176  if (KphIsConnected()) PhAppendCharStringBuilder(&stringBuilder, '+');
177  }
178 
179  if (WINDOWS_HAS_UAC && PhElevationType == TokenElevationTypeFull)
180  PhAppendStringBuilder2(&stringBuilder, L" (Administrator)");
181 
182  // Create the window.
183 
184  PhMainWndHandle = CreateWindow(
186  stringBuilder.String->Buffer,
187  WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
188  windowRectangle.Left,
189  windowRectangle.Top,
190  windowRectangle.Width,
191  windowRectangle.Height,
192  NULL,
193  NULL,
195  NULL
196  );
197  PhDeleteStringBuilder(&stringBuilder);
199 
200  if (!PhMainWndHandle)
201  return FALSE;
202 
204 
205  // Choose a more appropriate rectangle for the window.
208  &windowRectangle
209  );
210  MoveWindow(PhMainWndHandle, windowRectangle.Left, windowRectangle.Top,
211  windowRectangle.Width, windowRectangle.Height, FALSE);
212 
213  // Allow WM_PH_ACTIVATE to pass through UIPI.
214  if (WINDOWS_HAS_UAC)
216 
218 
219  // Initialize child controls.
221 
225 
227 
228  // Perform a layout.
229  PhMwpOnSize();
230 
233 
234  // See PhMwpOnTimer for more details.
237 
238  UpdateWindow(PhMainWndHandle);
239 
241  ShowCommand = SW_HIDE;
243  ShowCommand = SW_SHOW;
244 
245  if (PhGetIntegerSetting(L"MainWindowState") == SW_MAXIMIZE)
246  {
247  if (ShowCommand != SW_HIDE)
248  {
249  ShowCommand = SW_MAXIMIZE;
250  }
251  else
252  {
253  // We can't maximize it while having it hidden. Set it as pending.
254  NeedsMaximize = TRUE;
255  }
256  }
257 
258  NeedsSelectPid = PhStartupParameters.SelectPid;
259 
260  if (PhPluginsEnabled)
262 
264  {
266 
267  if (tabIndex != -1)
268  PhMwpSelectTabPage(tabIndex);
269  }
270 
271  if (ShowCommand != SW_HIDE)
272  ShowWindow(PhMainWndHandle, ShowCommand);
273 
274  if (PhGetIntegerSetting(L"MiniInfoWindowPinned"))
276 
277  return TRUE;
278 }
279 
280 LRESULT CALLBACK PhMwpWndProc(
281  _In_ HWND hWnd,
282  _In_ UINT uMsg,
283  _In_ WPARAM wParam,
284  _In_ LPARAM lParam
285  )
286 {
287  switch (uMsg)
288  {
289  case WM_DESTROY:
290  {
291  PhMwpOnDestroy();
292  }
293  break;
294  case WM_ENDSESSION:
295  {
297  }
298  break;
299  case WM_SETTINGCHANGE:
300  {
302  }
303  break;
304  case WM_COMMAND:
305  {
306  PhMwpOnCommand(LOWORD(wParam));
307  }
308  break;
309  case WM_SHOWWINDOW:
310  {
311  PhMwpOnShowWindow(!!wParam, (ULONG)lParam);
312  }
313  break;
314  case WM_SYSCOMMAND:
315  {
316  if (PhMwpOnSysCommand((ULONG)wParam, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)))
317  return 0;
318  }
319  break;
320  case WM_MENUCOMMAND:
321  {
322  PhMwpOnMenuCommand((ULONG)wParam, (HMENU)lParam);
323  }
324  break;
325  case WM_INITMENUPOPUP:
326  {
327  PhMwpOnInitMenuPopup((HMENU)wParam, LOWORD(lParam), !!HIWORD(lParam));
328  }
329  break;
330  case WM_SIZE:
331  {
332  PhMwpOnSize();
333  }
334  break;
335  case WM_SIZING:
336  {
337  PhMwpOnSizing((ULONG)wParam, (PRECT)lParam);
338  }
339  break;
340  case WM_SETFOCUS:
341  {
342  PhMwpOnSetFocus();
343  }
344  break;
345  case WM_TIMER:
346  {
347  PhMwpOnTimer((ULONG)wParam);
348  }
349  break;
350  case WM_NOTIFY:
351  {
352  LRESULT result;
353 
354  if (PhMwpOnNotify((NMHDR *)lParam, &result))
355  return result;
356  }
357  break;
358  case WM_WTSSESSION_CHANGE:
359  {
360  PhMwpOnWtsSessionChange((ULONG)wParam, (ULONG)lParam);
361  }
362  break;
363  }
364 
365  if (uMsg >= WM_PH_FIRST && uMsg <= WM_PH_LAST)
366  {
367  return PhMwpOnUserMessage(uMsg, wParam, lParam);
368  }
369 
370  return DefWindowProc(hWnd, uMsg, wParam, lParam);
371 }
372 
374  VOID
375  )
376 {
377  WNDCLASSEX wcex;
378 
379  memset(&wcex, 0, sizeof(WNDCLASSEX));
380  wcex.cbSize = sizeof(WNDCLASSEX);
381  wcex.style = 0;
382  wcex.lpfnWndProc = PhMwpWndProc;
383  wcex.cbClsExtra = 0;
384  wcex.cbWndExtra = 0;
385  wcex.hInstance = PhInstanceHandle;
386  wcex.hIcon = LoadIcon(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER));
387  wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
388  //wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
389  wcex.lpszMenuName = MAKEINTRESOURCE(IDR_MAINWND);
390  wcex.lpszClassName = PH_MAINWND_CLASSNAME;
391  wcex.hIconSm = (HICON)LoadImage(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER), IMAGE_ICON, 16, 16, 0);
392 
393  if (!RegisterClassEx(&wcex))
394  return FALSE;
395 
396  return TRUE;
397 }
398 
400  VOID
401  )
402 {
403  ULONG interval;
404 
405  interval = PhGetIntegerSetting(L"UpdateInterval");
406 
407  if (interval == 0)
408  {
409  interval = 1000;
410  PH_SET_INTEGER_CACHED_SETTING(UpdateInterval, interval);
411  }
412 
415 
416  PhRegisterProvider(&PhPrimaryProviderThread, PhProcessProviderUpdate, NULL, &ProcessProviderRegistration);
417  PhSetEnabledProvider(&ProcessProviderRegistration, TRUE);
418  PhRegisterProvider(&PhPrimaryProviderThread, PhServiceProviderUpdate, NULL, &ServiceProviderRegistration);
419  PhSetEnabledProvider(&ServiceProviderRegistration, TRUE);
420  PhRegisterProvider(&PhPrimaryProviderThread, PhNetworkProviderUpdate, NULL, &NetworkProviderRegistration);
421 }
422 
424  _In_ ULONG Interval
425  )
426 {
429 
432  else
433  KillTimer(PhMainWndHandle, TIMER_FLUSH_PROCESS_QUERY_DATA); // Might not exist
434 }
435 
437  VOID
438  )
439 {
440  ULONG thinRows;
441 
442  TabControlHandle = CreateWindow(
443  WC_TABCONTROL,
444  NULL,
445  WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | TCS_MULTILINE,
446  0,
447  0,
448  3,
449  3,
451  NULL,
453  NULL
454  );
455  SendMessage(TabControlHandle, WM_SETFONT, (WPARAM)PhApplicationFont, FALSE);
456  BringWindowToTop(TabControlHandle);
457  ProcessesTabIndex = PhAddTabControlTab(TabControlHandle, 0, L"Processes");
458  ServicesTabIndex = PhAddTabControlTab(TabControlHandle, 1, L"Services");
459  NetworkTabIndex = PhAddTabControlTab(TabControlHandle, 2, L"Network");
460  MaxTabIndex = NetworkTabIndex;
461 
462  thinRows = PhGetIntegerSetting(L"ThinRows") ? TN_STYLE_THIN_ROWS : 0;
463 
464  ProcessTreeListHandle = CreateWindow(
466  NULL,
467  WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_BORDER | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED | TN_STYLE_ANIMATE_DIVIDER | thinRows,
468  0,
469  0,
470  3,
471  3,
473  (HMENU)ID_MAINWND_PROCESSTL,
475  NULL
476  );
477  BringWindowToTop(ProcessTreeListHandle);
478 
479  ServiceTreeListHandle = CreateWindow(
481  NULL,
482  WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_BORDER | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED | thinRows,
483  0,
484  0,
485  3,
486  3,
488  (HMENU)ID_MAINWND_SERVICETL,
490  NULL
491  );
492  BringWindowToTop(ServiceTreeListHandle);
493 
494  NetworkTreeListHandle = CreateWindow(
496  NULL,
497  WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_BORDER | TN_STYLE_ICONS | TN_STYLE_DOUBLE_BUFFERED | thinRows,
498  0,
499  0,
500  3,
501  3,
503  (HMENU)ID_MAINWND_NETWORKTL,
505  NULL
506  );
507  BringWindowToTop(NetworkTreeListHandle);
508 
510  PhInitializeProcessTreeList(ProcessTreeListHandle);
511 
513  PhInitializeServiceTreeList(ServiceTreeListHandle);
514 
516  PhInitializeNetworkTreeList(NetworkTreeListHandle);
517 
521  NULL,
522  &ProcessAddedRegistration
523  );
527  NULL,
528  &ProcessModifiedRegistration
529  );
533  NULL,
534  &ProcessRemovedRegistration
535  );
539  NULL,
540  &ProcessesUpdatedRegistration
541  );
542 
546  NULL,
547  &ServiceAddedRegistration
548  );
552  NULL,
553  &ServiceModifiedRegistration
554  );
558  NULL,
559  &ServiceRemovedRegistration
560  );
564  NULL,
565  &ServicesUpdatedRegistration
566  );
567 
571  NULL,
572  &NetworkItemAddedRegistration
573  );
577  NULL,
578  &NetworkItemModifiedRegistration
579  );
583  NULL,
584  &NetworkItemRemovedRegistration
585  );
589  NULL,
590  &NetworkItemsUpdatedRegistration
591  );
592 }
593 
595  _In_ PVOID Parameter
596  )
597 {
598  // Register for window station notifications.
600 
601  PhNfLoadStage2();
602 
603  // Make sure we get closed late in the shutdown process.
604  SetProcessShutdownParameters(0x100, 0);
605 
606  DelayedLoadCompleted = TRUE;
607  //PostMessage(PhMainWndHandle, WM_PH_DELAYED_LOAD_COMPLETED, 0, 0);
608 
609  return STATUS_SUCCESS;
610 }
611 
613  VOID
614  )
615 {
616  static struct
617  {
618  ULONG Folder;
619  PWSTR AppendPath;
620  } locations[] =
621  {
622 #ifdef _WIN64
623  { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\10\\Debuggers\\x64\\dbghelp.dll" },
624  { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.1\\Debuggers\\x64\\dbghelp.dll" },
625  { CSIDL_PROGRAM_FILESX86, L"\\Windows Kits\\8.0\\Debuggers\\x64\\dbghelp.dll" },
626  { CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x64)\\dbghelp.dll" }
627 #else
628  { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\10\\Debuggers\\x86\\dbghelp.dll" },
629  { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.1\\Debuggers\\x86\\dbghelp.dll" },
630  { CSIDL_PROGRAM_FILES, L"\\Windows Kits\\8.0\\Debuggers\\x86\\dbghelp.dll" },
631  { CSIDL_PROGRAM_FILES, L"\\Debugging Tools for Windows (x86)\\dbghelp.dll" }
632 #endif
633  };
634 
635  PPH_STRING path;
636  ULONG i;
637 
638  for (i = 0; i < sizeof(locations) / sizeof(locations[0]); i++)
639  {
640  path = PhGetKnownLocation(locations[i].Folder, locations[i].AppendPath);
641 
642  if (path)
643  {
644  if (RtlDoesFileExists_U(path->Buffer))
645  return path;
646 
647  PhDereferenceObject(path);
648  }
649  }
650 
651  return NULL;
652 }
653 
655  VOID
656  )
657 {
658  // Notify plugins that we are shutting down.
659 
660  if (PhPluginsEnabled)
661  PhUnloadPlugins();
662 
663  if (!PhMainWndExiting)
665 
667 
668  PostQuitMessage(0);
669 }
670 
672  VOID
673  )
674 {
675  PhMwpOnDestroy();
676 }
677 
679  VOID
680  )
681 {
682  if (PhApplicationFont)
683  DeleteObject(PhApplicationFont);
684 
686 
687  SendMessage(TabControlHandle, WM_SETFONT, (WPARAM)PhApplicationFont, FALSE);
688 }
689 
691  _In_ ULONG Id
692  )
693 {
694  switch (Id)
695  {
696  case ID_ESC_EXIT:
697  {
698  if (PhGetIntegerSetting(L"HideOnClose"))
699  {
701  ShowWindow(PhMainWndHandle, SW_HIDE);
702  }
703  else if (PhGetIntegerSetting(L"CloseOnEscape"))
704  {
706  }
707  }
708  break;
709  case ID_HACKER_RUN:
710  {
711  if (RunFileDlg)
712  {
713  SelectedRunAsMode = 0;
714  RunFileDlg(PhMainWndHandle, NULL, NULL, NULL, NULL, 0);
715  }
716  }
717  break;
719  {
720  if (RunFileDlg)
721  {
722  SelectedRunAsMode = RUNAS_MODE_ADMIN;
723  RunFileDlg(
725  NULL,
726  NULL,
727  NULL,
728  L"Type the name of a program that will be opened under alternate credentials.",
729  0
730  );
731  }
732  }
733  break;
735  {
736  if (RunFileDlg)
737  {
738  SelectedRunAsMode = RUNAS_MODE_LIMITED;
739  RunFileDlg(
741  NULL,
742  NULL,
743  NULL,
744  L"Type the name of a program that will be opened under standard user privileges.",
745  0
746  );
747  }
748  }
749  break;
750  case ID_HACKER_RUNAS:
751  {
753  }
754  break;
756  {
758 
761  L"-v",
762  SW_SHOW,
765  0,
766  NULL
767  ))
768  {
770  }
771  else
772  {
774  }
775  }
776  break;
777  case ID_HACKER_SAVE:
778  {
779  static PH_FILETYPE_FILTER filters[] =
780  {
781  { L"Text files (*.txt;*.log)", L"*.txt;*.log" },
782  { L"Comma-separated values (*.csv)", L"*.csv" },
783  { L"All files (*.*)", L"*.*" }
784  };
785  PVOID fileDialog = PhCreateSaveFileDialog();
786  ULONG selectedTab = TabCtrl_GetCurSel(TabControlHandle);
787  PWSTR tabText = L"Output";
788  PPH_ADDITIONAL_TAB_PAGE selectedTabPage = NULL;
789 
790  if (selectedTab == ProcessesTabIndex)
791  {
792  tabText = L"Processes";
793  }
794  else if (selectedTab == ServicesTabIndex)
795  {
796  tabText = L"Services";
797  }
798  else if (selectedTab == NetworkTabIndex)
799  {
800  tabText = L"Network";
801  }
802  else if (AdditionalTabPageList)
803  {
804  ULONG i;
805 
806  for (i = 0; i < AdditionalTabPageList->Count; i++)
807  {
808  PPH_ADDITIONAL_TAB_PAGE tabPage = AdditionalTabPageList->Items[i];
809 
810  if (tabPage->Index == selectedTab)
811  {
812  selectedTabPage = tabPage;
813  tabText = selectedTabPage->Text;
814  break;
815  }
816  }
817  }
818 
819  PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER));
820  PhSetFileDialogFileName(fileDialog, PhaFormatString(L"Process Hacker %s.txt", tabText)->Buffer);
821 
822  if (PhShowFileDialog(PhMainWndHandle, fileDialog))
823  {
824  NTSTATUS status;
825  PPH_STRING fileName;
826  ULONG filterIndex;
827  PPH_FILE_STREAM fileStream;
828 
829  fileName = PhGetFileDialogFileName(fileDialog);
830  PhAutoDereferenceObject(fileName);
831  filterIndex = PhGetFileDialogFilterIndex(fileDialog);
832 
833  if (NT_SUCCESS(status = PhCreateFileStream(
834  &fileStream,
835  fileName->Buffer,
836  FILE_GENERIC_WRITE,
837  FILE_SHARE_READ,
839  0
840  )))
841  {
842  ULONG mode;
843 
844  if (filterIndex == 2)
845  mode = PH_EXPORT_MODE_CSV;
846  else
847  mode = PH_EXPORT_MODE_TABS;
848 
850  PhWritePhTextHeader(fileStream);
851 
852  if (selectedTab == ProcessesTabIndex)
853  {
854  PhWriteProcessTree(fileStream, mode);
855  }
856  else if (selectedTab == ServicesTabIndex)
857  {
858  PhWriteServiceList(fileStream, mode);
859  }
860  else if (selectedTab == NetworkTabIndex)
861  {
862  PhWriteNetworkList(fileStream, mode);
863  }
864  else if (selectedTabPage)
865  {
866  if (selectedTabPage->SaveContentCallback)
867  {
868  selectedTabPage->SaveContentCallback(fileStream, UlongToPtr(mode), NULL, selectedTabPage->Context);
869  }
870  }
871 
872  PhDereferenceObject(fileStream);
873  }
874 
875  if (!NT_SUCCESS(status))
876  PhShowStatus(PhMainWndHandle, L"Unable to create the file", status, 0);
877  }
878 
879  PhFreeFileDialog(fileDialog);
880  }
881  break;
883  {
885  }
886  break;
887  case ID_HACKER_OPTIONS:
888  {
890  }
891  break;
892  case ID_HACKER_PLUGINS:
893  {
895  }
896  break;
897  case ID_COMPUTER_LOCK:
898  case ID_COMPUTER_LOGOFF:
899  case ID_COMPUTER_SLEEP:
901  case ID_COMPUTER_RESTART:
906  break;
907  case ID_HACKER_EXIT:
909  break;
912  break;
918  {
919  ULONG i;
920 
921  switch (Id)
922  {
925  break;
927  i = PH_ICON_CPU_USAGE;
928  break;
930  i = PH_ICON_IO_HISTORY;
931  break;
934  break;
937  break;
938  }
939 
941  }
942  break;
944  {
945  if (!CurrentUserFilterEntry)
946  {
948  }
949  else
950  {
951  PhRemoveTreeNewFilter(PhGetFilterSupportProcessTreeList(), CurrentUserFilterEntry);
952  CurrentUserFilterEntry = NULL;
953  }
954 
956 
957  PhSetIntegerSetting(L"HideOtherUserProcesses", !!CurrentUserFilterEntry);
958  }
959  break;
961  {
962  if (!SignedFilterEntry)
963  {
965  {
968  L"This filter cannot function because digital signature checking is not enabled. "
969  L"Enable it in Options > Advanced and restart Process Hacker."
970  );
971  }
972 
974  }
975  else
976  {
978  SignedFilterEntry = NULL;
979  }
980 
982 
983  PhSetIntegerSetting(L"HideSignedProcesses", !!SignedFilterEntry);
984  }
985  break;
987  {
989  }
990  break;
992  {
995  }
996  break;
998  {
999  if (!DriverFilterEntry)
1000  {
1002  }
1003  else
1004  {
1006  DriverFilterEntry = NULL;
1007  }
1008 
1010 
1011  PhSetIntegerSetting(L"HideDriverServices", !!DriverFilterEntry);
1012  }
1013  break;
1014  case ID_VIEW_ALWAYSONTOP:
1015  {
1016  AlwaysOnTop = !AlwaysOnTop;
1017  SetWindowPos(PhMainWndHandle, AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST,
1018  0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
1019  PhSetIntegerSetting(L"MainWindowAlwaysOnTop", AlwaysOnTop);
1020  }
1021  break;
1022  case ID_OPACITY_10:
1023  case ID_OPACITY_20:
1024  case ID_OPACITY_30:
1025  case ID_OPACITY_40:
1026  case ID_OPACITY_50:
1027  case ID_OPACITY_60:
1028  case ID_OPACITY_70:
1029  case ID_OPACITY_80:
1030  case ID_OPACITY_90:
1031  case ID_OPACITY_OPAQUE:
1032  {
1033  ULONG opacity;
1034 
1035  opacity = PH_ID_TO_OPACITY(Id);
1036  PhSetIntegerSetting(L"MainWindowOpacity", opacity);
1038  }
1039  break;
1040  case ID_VIEW_REFRESH:
1041  {
1042  PhBoostProvider(&ProcessProviderRegistration, NULL);
1043  PhBoostProvider(&ServiceProviderRegistration, NULL);
1044  }
1045  break;
1051  {
1052  ULONG interval;
1053 
1054  switch (Id)
1055  {
1057  interval = 500;
1058  break;
1060  interval = 1000;
1061  break;
1063  interval = 2000;
1064  break;
1066  interval = 5000;
1067  break;
1069  interval = 10000;
1070  break;
1071  }
1072 
1073  PH_SET_INTEGER_CACHED_SETTING(UpdateInterval, interval);
1074  PhMwpApplyUpdateInterval(interval);
1075  }
1076  break;
1078  {
1079  UpdateAutomatically = !UpdateAutomatically;
1080 
1081  PhSetEnabledProvider(&ProcessProviderRegistration, UpdateAutomatically);
1082  PhSetEnabledProvider(&ServiceProviderRegistration, UpdateAutomatically);
1083 
1084  if (TabCtrl_GetCurSel(TabControlHandle) == NetworkTabIndex)
1085  PhSetEnabledProvider(&NetworkProviderRegistration, UpdateAutomatically);
1086  }
1087  break;
1089  {
1091  }
1092  break;
1094  {
1096  }
1097  break;
1099  {
1100  static PH_FILETYPE_FILTER filters[] =
1101  {
1102  { L"Executable files (*.exe;*.dll;*.ocx;*.sys;*.scr;*.cpl)", L"*.exe;*.dll;*.ocx;*.sys;*.scr;*.cpl" },
1103  { L"All files (*.*)", L"*.*" }
1104  };
1105  PVOID fileDialog = PhCreateOpenFileDialog();
1106 
1107  PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER));
1108 
1109  if (PhShowFileDialog(PhMainWndHandle, fileDialog))
1110  {
1111  PPH_STRING fileName;
1112 
1113  fileName = PhGetFileDialogFileName(fileDialog);
1116  L"ProgramInspectExecutables",
1117  fileName->Buffer,
1118  FALSE,
1119  L"Make sure the PE Viewer executable file is present."
1120  );
1121  PhDereferenceObject(fileName);
1122  }
1123 
1124  PhFreeFileDialog(fileDialog);
1125  }
1126  break;
1127  case ID_TOOLS_PAGEFILES:
1128  {
1130  }
1131  break;
1133  {
1134  PPH_STRING systemDirectory;
1135  PPH_STRING taskmgrFileName;
1136 
1137  systemDirectory = PhGetSystemDirectory();
1138  taskmgrFileName = PhConcatStrings2(systemDirectory->Buffer, L"\\taskmgr.exe");
1139  PhDereferenceObject(systemDirectory);
1140 
1141  if (WindowsVersion >= WINDOWS_8 && !PhElevated)
1142  {
1144  {
1147  }
1148  }
1149  else
1150  {
1151  PhCreateProcessIgnoreIfeoDebugger(taskmgrFileName->Buffer);
1152  }
1153 
1154  PhDereferenceObject(taskmgrFileName);
1155  }
1156  break;
1157  case ID_USER_CONNECT:
1158  {
1159  PhUiConnectSession(PhMainWndHandle, SelectedUserSessionId);
1160  }
1161  break;
1162  case ID_USER_DISCONNECT:
1163  {
1164  PhUiDisconnectSession(PhMainWndHandle, SelectedUserSessionId);
1165  }
1166  break;
1167  case ID_USER_LOGOFF:
1168  {
1169  PhUiLogoffSession(PhMainWndHandle, SelectedUserSessionId);
1170  }
1171  break;
1172  case ID_USER_REMOTECONTROL:
1173  {
1174  PhShowSessionShadowDialog(PhMainWndHandle, SelectedUserSessionId);
1175  }
1176  break;
1177  case ID_USER_SENDMESSAGE:
1178  {
1179  PhShowSessionSendMessageDialog(PhMainWndHandle, SelectedUserSessionId);
1180  }
1181  break;
1182  case ID_USER_PROPERTIES:
1183  {
1184  PhShowSessionProperties(PhMainWndHandle, SelectedUserSessionId);
1185  }
1186  break;
1187  case ID_HELP_LOG:
1188  {
1189  PhShowLogDialog();
1190  }
1191  break;
1192  case ID_HELP_DONATE:
1193  {
1194  PhShellExecute(PhMainWndHandle, L"https://sourceforge.net/project/project_donations.php?group_id=242527", NULL);
1195  }
1196  break;
1197  case ID_HELP_DEBUGCONSOLE:
1198  {
1200  }
1201  break;
1202  case ID_HELP_ABOUT:
1203  {
1205  }
1206  break;
1207  case ID_PROCESS_TERMINATE:
1208  {
1209  PPH_PROCESS_ITEM *processes;
1210  ULONG numberOfProcesses;
1211 
1212  PhGetSelectedProcessItems(&processes, &numberOfProcesses);
1213  PhReferenceObjects(processes, numberOfProcesses);
1214 
1215  if (PhUiTerminateProcesses(PhMainWndHandle, processes, numberOfProcesses))
1217 
1218  PhDereferenceObjects(processes, numberOfProcesses);
1219  PhFree(processes);
1220  }
1221  break;
1223  {
1225 
1226  if (processItem)
1227  {
1228  PhReferenceObject(processItem);
1229 
1230  if (PhUiTerminateTreeProcess(PhMainWndHandle, processItem))
1232 
1233  PhDereferenceObject(processItem);
1234  }
1235  }
1236  break;
1237  case ID_PROCESS_SUSPEND:
1238  {
1239  PPH_PROCESS_ITEM *processes;
1240  ULONG numberOfProcesses;
1241 
1242  PhGetSelectedProcessItems(&processes, &numberOfProcesses);
1243  PhReferenceObjects(processes, numberOfProcesses);
1244  PhUiSuspendProcesses(PhMainWndHandle, processes, numberOfProcesses);
1245  PhDereferenceObjects(processes, numberOfProcesses);
1246  PhFree(processes);
1247  }
1248  break;
1249  case ID_PROCESS_RESUME:
1250  {
1251  PPH_PROCESS_ITEM *processes;
1252  ULONG numberOfProcesses;
1253 
1254  PhGetSelectedProcessItems(&processes, &numberOfProcesses);
1255  PhReferenceObjects(processes, numberOfProcesses);
1256  PhUiResumeProcesses(PhMainWndHandle, processes, numberOfProcesses);
1257  PhDereferenceObjects(processes, numberOfProcesses);
1258  PhFree(processes);
1259  }
1260  break;
1261  case ID_PROCESS_RESTART:
1262  {
1264 
1265  if (processItem)
1266  {
1267  PhReferenceObject(processItem);
1268 
1269  if (PhUiRestartProcess(PhMainWndHandle, processItem))
1271 
1272  PhDereferenceObject(processItem);
1273  }
1274  }
1275  break;
1277  {
1279 
1280  if (processItem)
1281  {
1282  PhReferenceObject(processItem);
1284  PhDereferenceObject(processItem);
1285  }
1286  }
1287  break;
1288  case ID_PROCESS_DEBUG:
1289  {
1291 
1292  if (processItem)
1293  {
1294  PhReferenceObject(processItem);
1295  PhUiDebugProcess(PhMainWndHandle, processItem);
1296  PhDereferenceObject(processItem);
1297  }
1298  }
1299  break;
1301  {
1303 
1304  if (processItem)
1305  {
1306  PhReferenceObject(processItem);
1309  processItem,
1310  !SelectedProcessVirtualizationEnabled
1311  );
1312  PhDereferenceObject(processItem);
1313  }
1314  }
1315  break;
1316  case ID_PROCESS_AFFINITY:
1317  {
1319 
1320  if (processItem)
1321  {
1322  PhReferenceObject(processItem);
1323  PhShowProcessAffinityDialog(PhMainWndHandle, processItem, NULL);
1324  PhDereferenceObject(processItem);
1325  }
1326  }
1327  break;
1329  {
1331 
1332  if (processItem)
1333  {
1334  PhReferenceObject(processItem);
1336  PhDereferenceObject(processItem);
1337  }
1338  }
1339  break;
1341  {
1343 
1344  if (processItem)
1345  {
1346  PhReferenceObject(processItem);
1348  PhDereferenceObject(processItem);
1349  }
1350  }
1351  break;
1353  {
1355 
1356  if (processItem)
1357  {
1358  PhReferenceObject(processItem);
1359  PhUiInjectDllProcess(PhMainWndHandle, processItem);
1360  PhDereferenceObject(processItem);
1361  }
1362  }
1363  break;
1364  case ID_PAGEPRIORITY_1:
1365  case ID_PAGEPRIORITY_2:
1366  case ID_PAGEPRIORITY_3:
1367  case ID_PAGEPRIORITY_4:
1368  case ID_PAGEPRIORITY_5:
1369  {
1371 
1372  if (processItem)
1373  {
1374  ULONG pagePriority;
1375 
1376  switch (Id)
1377  {
1378  case ID_PAGEPRIORITY_1:
1379  pagePriority = 1;
1380  break;
1381  case ID_PAGEPRIORITY_2:
1382  pagePriority = 2;
1383  break;
1384  case ID_PAGEPRIORITY_3:
1385  pagePriority = 3;
1386  break;
1387  case ID_PAGEPRIORITY_4:
1388  pagePriority = 4;
1389  break;
1390  case ID_PAGEPRIORITY_5:
1391  pagePriority = 5;
1392  break;
1393  }
1394 
1395  PhReferenceObject(processItem);
1396  PhUiSetPagePriorityProcess(PhMainWndHandle, processItem, pagePriority);
1397  PhDereferenceObject(processItem);
1398  }
1399  }
1400  break;
1402  {
1403  PPH_PROCESS_ITEM *processes;
1404  ULONG numberOfProcesses;
1405 
1406  PhGetSelectedProcessItems(&processes, &numberOfProcesses);
1407  PhReferenceObjects(processes, numberOfProcesses);
1408  PhUiReduceWorkingSetProcesses(PhMainWndHandle, processes, numberOfProcesses);
1409  PhDereferenceObjects(processes, numberOfProcesses);
1410  PhFree(processes);
1411  }
1412  break;
1414  {
1416 
1417  if (processItem && processItem->FileName)
1418  {
1419  PhSetStringSetting2(L"RunAsProgram", &processItem->FileName->sr);
1421  }
1422  }
1423  break;
1425  {
1427 
1428  if (processItem)
1429  {
1431  }
1432  }
1433  break;
1435  {
1437 
1438  if (processItem)
1439  {
1440  // The object relies on the list view reference, which could
1441  // disappear if we don't reference the object here.
1442  PhReferenceObject(processItem);
1444  PhDereferenceObject(processItem);
1445  }
1446  }
1447  break;
1448  case ID_PRIORITY_REALTIME:
1449  case ID_PRIORITY_HIGH:
1451  case ID_PRIORITY_NORMAL:
1453  case ID_PRIORITY_IDLE:
1454  {
1455  PPH_PROCESS_ITEM *processes;
1456  ULONG numberOfProcesses;
1457 
1458  PhGetSelectedProcessItems(&processes, &numberOfProcesses);
1459  PhReferenceObjects(processes, numberOfProcesses);
1460  PhMwpExecuteProcessPriorityCommand(Id, processes, numberOfProcesses);
1461  PhDereferenceObjects(processes, numberOfProcesses);
1462  PhFree(processes);
1463  }
1464  break;
1465  case ID_I_0:
1466  case ID_I_1:
1467  case ID_I_2:
1468  case ID_I_3:
1469  {
1470  PPH_PROCESS_ITEM *processes;
1471  ULONG numberOfProcesses;
1472 
1473  PhGetSelectedProcessItems(&processes, &numberOfProcesses);
1474  PhReferenceObjects(processes, numberOfProcesses);
1475  PhMwpExecuteProcessIoPriorityCommand(Id, processes, numberOfProcesses);
1476  PhDereferenceObjects(processes, numberOfProcesses);
1477  PhFree(processes);
1478  }
1479  break;
1481  {
1482  if (IsWindow(SelectedProcessWindowHandle))
1483  {
1484  WINDOWPLACEMENT placement = { sizeof(placement) };
1485 
1486  GetWindowPlacement(SelectedProcessWindowHandle, &placement);
1487 
1488  if (placement.showCmd == SW_MINIMIZE)
1489  ShowWindowAsync(SelectedProcessWindowHandle, SW_RESTORE);
1490  else
1491  SetForegroundWindow(SelectedProcessWindowHandle);
1492  }
1493  }
1494  break;
1495  case ID_WINDOW_RESTORE:
1496  {
1497  if (IsWindow(SelectedProcessWindowHandle))
1498  {
1499  ShowWindowAsync(SelectedProcessWindowHandle, SW_RESTORE);
1500  }
1501  }
1502  break;
1503  case ID_WINDOW_MINIMIZE:
1504  {
1505  if (IsWindow(SelectedProcessWindowHandle))
1506  {
1507  ShowWindowAsync(SelectedProcessWindowHandle, SW_MINIMIZE);
1508  }
1509  }
1510  break;
1511  case ID_WINDOW_MAXIMIZE:
1512  {
1513  if (IsWindow(SelectedProcessWindowHandle))
1514  {
1515  ShowWindowAsync(SelectedProcessWindowHandle, SW_MAXIMIZE);
1516  }
1517  }
1518  break;
1519  case ID_WINDOW_CLOSE:
1520  {
1521  if (IsWindow(SelectedProcessWindowHandle))
1522  {
1523  PostMessage(SelectedProcessWindowHandle, WM_CLOSE, 0, 0);
1524  }
1525  }
1526  break;
1528  {
1530 
1531  if (processItem && processItem->FileName)
1532  {
1533  PhReferenceObject(processItem);
1535  PhDereferenceObject(processItem);
1536  }
1537  }
1538  break;
1540  {
1542 
1543  if (processItem)
1544  {
1546  }
1547  }
1548  break;
1549  case ID_PROCESS_PROPERTIES:
1550  {
1552 
1553  if (processItem)
1554  {
1555  // No reference needed; no messages pumped.
1556  PhMwpShowProcessProperties(processItem);
1557  }
1558  }
1559  break;
1560  case ID_PROCESS_COPY:
1561  {
1563  }
1564  break;
1566  {
1568  PPH_PROCESS_NODE processNode;
1569 
1570  if (serviceItem)
1571  {
1572  if (processNode = PhFindProcessNode(serviceItem->ProcessId))
1573  {
1574  PhMwpSelectTabPage(ProcessesTabIndex);
1575  SetFocus(ProcessTreeListHandle);
1577  }
1578  }
1579  }
1580  break;
1581  case ID_SERVICE_START:
1582  {
1584 
1585  if (serviceItem)
1586  {
1587  PhReferenceObject(serviceItem);
1588  PhUiStartService(PhMainWndHandle, serviceItem);
1589  PhDereferenceObject(serviceItem);
1590  }
1591  }
1592  break;
1593  case ID_SERVICE_CONTINUE:
1594  {
1596 
1597  if (serviceItem)
1598  {
1599  PhReferenceObject(serviceItem);
1600  PhUiContinueService(PhMainWndHandle, serviceItem);
1601  PhDereferenceObject(serviceItem);
1602  }
1603  }
1604  break;
1605  case ID_SERVICE_PAUSE:
1606  {
1608 
1609  if (serviceItem)
1610  {
1611  PhReferenceObject(serviceItem);
1612  PhUiPauseService(PhMainWndHandle, serviceItem);
1613  PhDereferenceObject(serviceItem);
1614  }
1615  }
1616  break;
1617  case ID_SERVICE_STOP:
1618  {
1620 
1621  if (serviceItem)
1622  {
1623  PhReferenceObject(serviceItem);
1624  PhUiStopService(PhMainWndHandle, serviceItem);
1625  PhDereferenceObject(serviceItem);
1626  }
1627  }
1628  break;
1629  case ID_SERVICE_DELETE:
1630  {
1632 
1633  if (serviceItem)
1634  {
1635  PhReferenceObject(serviceItem);
1636 
1637  if (PhUiDeleteService(PhMainWndHandle, serviceItem))
1639 
1640  PhDereferenceObject(serviceItem);
1641  }
1642  }
1643  break;
1644  case ID_SERVICE_OPENKEY:
1645  {
1646  static PH_STRINGREF servicesKeyName = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Services\\");
1647  static PH_STRINGREF hklm = PH_STRINGREF_INIT(L"HKLM\\");
1648 
1650 
1651  if (serviceItem)
1652  {
1653  HANDLE keyHandle;
1654  PPH_STRING serviceKeyName = PhConcatStringRef2(&servicesKeyName, &serviceItem->Name->sr);
1655 
1656  if (NT_SUCCESS(PhOpenKey(
1657  &keyHandle,
1658  KEY_READ,
1660  &serviceKeyName->sr,
1661  0
1662  )))
1663  {
1664  PPH_STRING hklmServiceKeyName;
1665 
1666  hklmServiceKeyName = PhConcatStringRef2(&hklm, &serviceKeyName->sr);
1667  PhShellOpenKey2(PhMainWndHandle, hklmServiceKeyName);
1668  PhDereferenceObject(hklmServiceKeyName);
1669 
1670  NtClose(keyHandle);
1671  }
1672 
1673  PhDereferenceObject(serviceKeyName);
1674  }
1675  }
1676  break;
1678  {
1680  SC_HANDLE serviceHandle;
1681 
1682  if (serviceItem && (serviceHandle = PhOpenService(serviceItem->Name->Buffer, SERVICE_QUERY_CONFIG)))
1683  {
1684  PPH_STRING fileName;
1685 
1686  if (fileName = PhGetServiceRelevantFileName(&serviceItem->Name->sr, serviceHandle))
1687  {
1689  PhDereferenceObject(fileName);
1690  }
1691 
1692  CloseServiceHandle(serviceHandle);
1693  }
1694  }
1695  break;
1696  case ID_SERVICE_PROPERTIES:
1697  {
1699 
1700  if (serviceItem)
1701  {
1702  // The object relies on the list view reference, which could
1703  // disappear if we don't reference the object here.
1704  PhReferenceObject(serviceItem);
1706  PhDereferenceObject(serviceItem);
1707  }
1708  }
1709  break;
1710  case ID_SERVICE_COPY:
1711  {
1713  }
1714  break;
1716  {
1718  PPH_PROCESS_NODE processNode;
1719 
1720  if (networkItem)
1721  {
1722  if (processNode = PhFindProcessNode(networkItem->ProcessId))
1723  {
1724  PhMwpSelectTabPage(ProcessesTabIndex);
1725  SetFocus(ProcessTreeListHandle);
1727  }
1728  }
1729  }
1730  break;
1732  {
1734  PPH_SERVICE_ITEM serviceItem;
1735 
1736  if (networkItem && networkItem->OwnerName)
1737  {
1738  if (serviceItem = PhReferenceServiceItem(networkItem->OwnerName->Buffer))
1739  {
1740  PhMwpSelectTabPage(ServicesTabIndex);
1741  SetFocus(ServiceTreeListHandle);
1743 
1744  PhDereferenceObject(serviceItem);
1745  }
1746  }
1747  }
1748  break;
1749  case ID_NETWORK_VIEWSTACK:
1750  {
1752 
1753  if (networkItem)
1754  {
1755  PhReferenceObject(networkItem);
1757  PhDereferenceObject(networkItem);
1758  }
1759  }
1760  break;
1761  case ID_NETWORK_CLOSE:
1762  {
1763  PPH_NETWORK_ITEM *networkItems;
1764  ULONG numberOfNetworkItems;
1765 
1766  PhGetSelectedNetworkItems(&networkItems, &numberOfNetworkItems);
1767  PhReferenceObjects(networkItems, numberOfNetworkItems);
1768 
1769  if (PhUiCloseConnections(PhMainWndHandle, networkItems, numberOfNetworkItems))
1771 
1772  PhDereferenceObjects(networkItems, numberOfNetworkItems);
1773  PhFree(networkItems);
1774  }
1775  break;
1776  case ID_NETWORK_COPY:
1777  {
1779  }
1780  break;
1781  case ID_TAB_NEXT:
1782  {
1783  ULONG selectedIndex = TabCtrl_GetCurSel(TabControlHandle);
1784 
1785  if (selectedIndex != MaxTabIndex)
1786  selectedIndex++;
1787  else
1788  selectedIndex = 0;
1789 
1790  PhMwpSelectTabPage(selectedIndex);
1791  }
1792  break;
1793  case ID_TAB_PREV:
1794  {
1795  ULONG selectedIndex = TabCtrl_GetCurSel(TabControlHandle);
1796 
1797  if (selectedIndex != 0)
1798  selectedIndex--;
1799  else
1800  selectedIndex = MaxTabIndex;
1801 
1802  PhMwpSelectTabPage(selectedIndex);
1803  }
1804  break;
1805  }
1806 }
1807 
1809  _In_ BOOLEAN Showing,
1810  _In_ ULONG State
1811  )
1812 {
1813  if (NeedsMaximize)
1814  {
1815  ShowWindow(PhMainWndHandle, SW_MAXIMIZE);
1816  NeedsMaximize = FALSE;
1817  }
1818 }
1819 
1821  _In_ ULONG Type,
1822  _In_ LONG CursorScreenX,
1823  _In_ LONG CursorScreenY
1824  )
1825 {
1826  switch (Type)
1827  {
1828  case SC_CLOSE:
1829  {
1830  if (PhGetIntegerSetting(L"HideOnClose") && PhNfTestIconMask(PH_ICON_ALL))
1831  {
1832  ShowWindow(PhMainWndHandle, SW_HIDE);
1833  return TRUE;
1834  }
1835  }
1836  break;
1837  case SC_MINIMIZE:
1838  {
1839  // Save the current window state because we
1840  // may not have a chance to later.
1842 
1843  if (PhGetIntegerSetting(L"HideOnMinimize") && PhNfTestIconMask(PH_ICON_ALL))
1844  {
1845  ShowWindow(PhMainWndHandle, SW_HIDE);
1846  return TRUE;
1847  }
1848  }
1849  break;
1850  }
1851 
1852  return FALSE;
1853 }
1854 
1856  _In_ ULONG Index,
1857  _In_ HMENU Menu
1858  )
1859 {
1860  MENUITEMINFO menuItemInfo;
1861 
1862  menuItemInfo.cbSize = sizeof(MENUITEMINFO);
1863  menuItemInfo.fMask = MIIM_ID | MIIM_DATA;
1864 
1865  if (GetMenuItemInfo(Menu, Index, TRUE, &menuItemInfo))
1866  {
1867  PhMwpDispatchMenuCommand(Menu, Index, menuItemInfo.wID, menuItemInfo.dwItemData);
1868  }
1869 }
1870 
1872  _In_ HMENU Menu,
1873  _In_ ULONG Index,
1874  _In_ BOOLEAN IsWindowMenu
1875  )
1876 {
1877  ULONG i;
1878  BOOLEAN found;
1879  MENUINFO menuInfo;
1880  PPH_EMENU menu;
1881 
1882  found = FALSE;
1883 
1884  for (i = 0; i < sizeof(SubMenuHandles) / sizeof(HWND); i++)
1885  {
1886  if (Menu == SubMenuHandles[i])
1887  {
1888  found = TRUE;
1889  break;
1890  }
1891  }
1892 
1893  if (!found)
1894  return;
1895 
1896  if (Index == 3)
1897  {
1898  // Special case for Users menu.
1899  if (!UsersMenuInitialized)
1900  {
1902  UsersMenuInitialized = TRUE;
1903  }
1904 
1905  return;
1906  }
1907 
1908  // Delete all items in this submenu.
1909  while (DeleteMenu(Menu, 0, MF_BYPOSITION)) ;
1910 
1911  // Delete the previous EMENU for this submenu.
1912  if (SubMenuObjects[Index])
1913  PhDestroyEMenu(SubMenuObjects[Index]);
1914 
1915  // Make sure the menu style is set correctly.
1916  memset(&menuInfo, 0, sizeof(MENUINFO));
1917  menuInfo.cbSize = sizeof(MENUINFO);
1918  menuInfo.fMask = MIM_STYLE;
1919  menuInfo.dwStyle = MNS_CHECKORBMP;
1920  SetMenuInfo(Menu, &menuInfo);
1921 
1922  menu = PhCreateEMenu();
1923  PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_MAINWND), Index);
1924 
1925  PhMwpInitializeSubMenu(menu, Index);
1926 
1927  if (PhPluginsEnabled)
1928  {
1929  PH_PLUGIN_MENU_INFORMATION menuInfo;
1930 
1932  menuInfo.u.MainMenu.SubMenuIndex = Index;
1934  }
1935 
1936  PhEMenuToHMenu2(Menu, menu, 0, NULL);
1937  SubMenuObjects[Index] = menu;
1938 }
1939 
1941  VOID
1942  )
1943 {
1944  if (!IsIconic(PhMainWndHandle))
1945  {
1946  HDWP deferHandle;
1947 
1948  deferHandle = BeginDeferWindowPos(2);
1949  PhMwpLayout(&deferHandle);
1950  EndDeferWindowPos(deferHandle);
1951  }
1952 }
1953 
1955  _In_ ULONG Edge,
1956  _In_ PRECT DragRectangle
1957  )
1958 {
1959  PhResizingMinimumSize(DragRectangle, Edge, 400, 340);
1960 }
1961 
1963  VOID
1964  )
1965 {
1966  INT selectedIndex = TabCtrl_GetCurSel(TabControlHandle);
1967 
1968  if (selectedIndex == ProcessesTabIndex)
1969  SetFocus(ProcessTreeListHandle);
1970  else if (selectedIndex == ServicesTabIndex)
1971  SetFocus(ServiceTreeListHandle);
1972  else if (selectedIndex == NetworkTabIndex)
1973  SetFocus(NetworkTreeListHandle);
1974 }
1975 
1977  _In_ ULONG Id
1978  )
1979 {
1981  {
1982  static ULONG state = 1;
1983 
1984  // If the update interval is too large, the user might have to wait a while before seeing some types of
1985  // process-related data. Here we force an update.
1986  //
1987  // In addition, we force updates shortly after the program starts up to make things appear more quickly.
1988 
1989  switch (state)
1990  {
1991  case 1:
1992  state = 2;
1993 
1996  else
1998 
1999  break;
2000  case 2:
2001  state = 3;
2002 
2005  else
2007 
2008  break;
2009  default:
2010  NOTHING;
2011  break;
2012  }
2013 
2015  }
2016 }
2017 
2019  _In_ NMHDR *Header,
2020  _Out_ LRESULT *Result
2021  )
2022 {
2023  if (Header->hwndFrom == TabControlHandle)
2024  {
2025  PhMwpNotifyTabControl(Header);
2026  }
2027  else if (Header->code == RFN_VALIDATE)
2028  {
2029  LPNMRUNFILEDLG runFileDlg = (LPNMRUNFILEDLG)Header;
2030 
2031  if (SelectedRunAsMode == RUNAS_MODE_ADMIN)
2032  {
2033  PH_STRINGREF string;
2034  PH_STRINGREF fileName;
2035  PH_STRINGREF arguments;
2036  PPH_STRING fullFileName;
2037  PPH_STRING argumentsString;
2038 
2039  PhInitializeStringRefLongHint(&string, (PWSTR)runFileDlg->lpszFile);
2040  PhParseCommandLineFuzzy(&string, &fileName, &arguments, &fullFileName);
2041 
2042  if (!fullFileName)
2043  fullFileName = PhCreateString2(&fileName);
2044 
2045  argumentsString = PhCreateString2(&arguments);
2046 
2047  if (PhShellExecuteEx(PhMainWndHandle, fullFileName->Buffer, argumentsString->Buffer,
2048  runFileDlg->nShow, PH_SHELL_EXECUTE_ADMIN, 0, NULL))
2049  {
2050  *Result = RF_CANCEL;
2051  }
2052  else
2053  {
2054  *Result = RF_RETRY;
2055  }
2056 
2057  PhDereferenceObject(fullFileName);
2058  PhDereferenceObject(argumentsString);
2059 
2060  return TRUE;
2061  }
2062  else if (SelectedRunAsMode == RUNAS_MODE_LIMITED)
2063  {
2064  NTSTATUS status;
2065  HANDLE tokenHandle;
2066  HANDLE newTokenHandle;
2067 
2068  if (NT_SUCCESS(status = NtOpenProcessToken(
2069  NtCurrentProcess(),
2070  TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY | TOKEN_ADJUST_GROUPS |
2071  TOKEN_ADJUST_DEFAULT | READ_CONTROL | WRITE_DAC,
2072  &tokenHandle
2073  )))
2074  {
2076  tokenHandle,
2077  &newTokenHandle
2078  )))
2079  {
2080  status = PhCreateProcessWin32(
2081  NULL,
2082  (PWSTR)runFileDlg->lpszFile,
2083  NULL,
2084  NULL,
2085  0,
2086  newTokenHandle,
2087  NULL,
2088  NULL
2089  );
2090 
2091  NtClose(newTokenHandle);
2092  }
2093 
2094  NtClose(tokenHandle);
2095  }
2096 
2097  if (NT_SUCCESS(status))
2098  {
2099  *Result = RF_CANCEL;
2100  }
2101  else
2102  {
2103  PhShowStatus(PhMainWndHandle, L"Unable to execute the program", status, 0);
2104  *Result = RF_RETRY;
2105  }
2106 
2107  return TRUE;
2108  }
2109  }
2110 
2111  return FALSE;
2112 }
2113 
2115  _In_ ULONG Reason,
2116  _In_ ULONG SessionId
2117  )
2118 {
2119  if (Reason == WTS_SESSION_LOGON || Reason == WTS_SESSION_LOGOFF)
2120  {
2121  if (UsersMenuInitialized)
2122  {
2124  }
2125  }
2126 }
2127 
2129  _In_ ULONG Message,
2130  _In_ ULONG_PTR WParam,
2131  _In_ ULONG_PTR LParam
2132  )
2133 {
2134  switch (Message)
2135  {
2136  case WM_PH_ACTIVATE:
2137  {
2138  if (!PhMainWndExiting)
2139  {
2140  if (WParam != 0)
2141  {
2142  PPH_PROCESS_NODE processNode;
2143 
2144  if (processNode = PhFindProcessNode((HANDLE)WParam))
2146  }
2147 
2148  if (!IsWindowVisible(PhMainWndHandle))
2149  {
2150  ShowWindow(PhMainWndHandle, SW_SHOW);
2151  }
2152 
2153  if (IsIconic(PhMainWndHandle))
2154  {
2155  ShowWindow(PhMainWndHandle, SW_RESTORE);
2156  }
2157 
2158  return PH_ACTIVATE_REPLY;
2159  }
2160  else
2161  {
2162  return 0;
2163  }
2164  }
2165  break;
2167  {
2169  }
2170  break;
2171  case WM_PH_DESTROY:
2172  {
2173  DestroyWindow(PhMainWndHandle);
2174  }
2175  break;
2177  {
2179  }
2180  break;
2182  {
2185  }
2186  break;
2188  {
2190  }
2191  break;
2193  {
2194  // Nothing
2195  }
2196  break;
2198  {
2199  PhNfForwardMessage(WParam, LParam);
2200  }
2201  break;
2202  case WM_PH_TOGGLE_VISIBLE:
2203  {
2204  PhMwpActivateWindow(!WParam);
2205  }
2206  break;
2208  {
2209  PPH_SHOWMEMORYEDITOR showMemoryEditor = (PPH_SHOWMEMORYEDITOR)LParam;
2210 
2212  showMemoryEditor->ProcessId,
2213  showMemoryEditor->BaseAddress,
2214  showMemoryEditor->RegionSize,
2215  showMemoryEditor->SelectOffset,
2216  showMemoryEditor->SelectLength,
2217  showMemoryEditor->Title,
2218  showMemoryEditor->Flags
2219  );
2220  PhClearReference(&showMemoryEditor->Title);
2221  PhFree(showMemoryEditor);
2222  }
2223  break;
2225  {
2226  PPH_SHOWMEMORYRESULTS showMemoryResults = (PPH_SHOWMEMORYRESULTS)LParam;
2227 
2229  showMemoryResults->ProcessId,
2230  showMemoryResults->Results
2231  );
2233  (PPH_MEMORY_RESULT *)showMemoryResults->Results->Items,
2234  showMemoryResults->Results->Count
2235  );
2236  PhDereferenceObject(showMemoryResults->Results);
2237  PhFree(showMemoryResults);
2238  }
2239  break;
2240  case WM_PH_SELECT_TAB_PAGE:
2241  {
2242  ULONG index = (ULONG)WParam;
2243 
2244  PhMwpSelectTabPage(index);
2245 
2246  if (index == ProcessesTabIndex)
2247  SetFocus(ProcessTreeListHandle);
2248  else if (index == ServicesTabIndex)
2249  SetFocus(ServiceTreeListHandle);
2250  else if (index == NetworkTabIndex)
2251  SetFocus(NetworkTreeListHandle);
2252  }
2253  break;
2255  {
2256  return (ULONG_PTR)&LayoutPaddingCallback;
2257  }
2258  break;
2260  {
2261  LayoutPaddingValid = FALSE;
2262  }
2263  break;
2265  {
2267  }
2268  break;
2270  {
2271  PPH_SERVICE_NODE serviceNode;
2272 
2274 
2275  // For compatibility, LParam is a service item, not node.
2276  if (serviceNode = PhFindServiceNode((PPH_SERVICE_ITEM)LParam))
2277  {
2279  }
2280  }
2281  break;
2283  {
2284  PPH_NETWORK_NODE networkNode;
2285 
2287 
2288  // For compatibility, LParam is a network item, not node.
2289  if (networkNode = PhFindNetworkNode((PPH_NETWORK_ITEM)LParam))
2290  {
2292  }
2293  }
2294  break;
2295  case WM_PH_UPDATE_FONT:
2296  {
2297  PPH_STRING fontHexString;
2298  LOGFONT font;
2299 
2300  fontHexString = PhGetStringSetting(L"Font");
2301 
2302  if (
2303  fontHexString->Length / 2 / 2 == sizeof(LOGFONT) &&
2304  PhHexStringToBuffer(&fontHexString->sr, (PUCHAR)&font)
2305  )
2306  {
2307  HFONT newFont;
2308 
2309  newFont = CreateFontIndirect(&font);
2310 
2311  if (newFont)
2312  {
2313  if (CurrentCustomFont)
2314  DeleteObject(CurrentCustomFont);
2315 
2316  CurrentCustomFont = newFont;
2317 
2318  SendMessage(ProcessTreeListHandle, WM_SETFONT, (WPARAM)newFont, TRUE);
2319  SendMessage(ServiceTreeListHandle, WM_SETFONT, (WPARAM)newFont, TRUE);
2320  SendMessage(NetworkTreeListHandle, WM_SETFONT, (WPARAM)newFont, TRUE);
2321 
2322  if (AdditionalTabPageList)
2323  {
2324  ULONG i;
2325 
2326  for (i = 0; i < AdditionalTabPageList->Count; i++)
2327  {
2328  PPH_ADDITIONAL_TAB_PAGE tabPage = AdditionalTabPageList->Items[i];
2329 
2330  if (tabPage->FontChangedCallback)
2331  {
2332  tabPage->FontChangedCallback((PVOID)newFont, NULL, NULL, tabPage->Context);
2333  }
2334  }
2335  }
2336  }
2337  }
2338 
2339  PhDereferenceObject(fontHexString);
2340  }
2341  break;
2342  case WM_PH_GET_FONT:
2343  return SendMessage(ProcessTreeListHandle, WM_GETFONT, 0, 0);
2344  case WM_PH_INVOKE:
2345  {
2346  VOID (NTAPI *function)(PVOID);
2347 
2348  function = (PVOID)LParam;
2349  function((PVOID)WParam);
2350  }
2351  break;
2352  case WM_PH_ADD_MENU_ITEM:
2353  {
2354  PPH_ADDMENUITEM addMenuItem = (PPH_ADDMENUITEM)LParam;
2355 
2356  return PhMwpLegacyAddPluginMenuItem(addMenuItem);
2357  }
2358  break;
2359  case WM_PH_ADD_TAB_PAGE:
2360  {
2361  return (ULONG_PTR)PhMwpAddTabPage((PPH_ADDITIONAL_TAB_PAGE)LParam);
2362  }
2363  break;
2364  case WM_PH_REFRESH:
2365  {
2366  SendMessage(PhMainWndHandle, WM_COMMAND, ID_VIEW_REFRESH, 0);
2367  }
2368  break;
2370  {
2371  return UpdateAutomatically;
2372  }
2373  break;
2375  {
2376  if (!!WParam != UpdateAutomatically)
2377  {
2378  SendMessage(PhMainWndHandle, WM_COMMAND, ID_VIEW_UPDATEAUTOMATICALLY, 0);
2379  }
2380  }
2381  break;
2382  case WM_PH_ICON_CLICK:
2383  {
2384  PhMwpActivateWindow(!!PhGetIntegerSetting(L"IconTogglesVisibility"));
2385  }
2386  break;
2387  case WM_PH_PROCESS_ADDED:
2388  {
2389  ULONG runId = (ULONG)WParam;
2390  PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)LParam;
2391 
2392  PhMwpOnProcessAdded(processItem, runId);
2393  }
2394  break;
2396  {
2398  }
2399  break;
2400  case WM_PH_PROCESS_REMOVED:
2401  {
2403  }
2404  break;
2406  {
2408  }
2409  break;
2410  case WM_PH_SERVICE_ADDED:
2411  {
2412  ULONG runId = (ULONG)WParam;
2413  PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)LParam;
2414 
2415  PhMwpOnServiceAdded(serviceItem, runId);
2416  }
2417  break;
2419  {
2420  PPH_SERVICE_MODIFIED_DATA serviceModifiedData = (PPH_SERVICE_MODIFIED_DATA)LParam;
2421 
2422  PhMwpOnServiceModified(serviceModifiedData);
2423  PhFree(serviceModifiedData);
2424  }
2425  break;
2426  case WM_PH_SERVICE_REMOVED:
2427  {
2429  }
2430  break;
2432  {
2434  }
2435  break;
2437  {
2438  ULONG runId = (ULONG)WParam;
2439  PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)LParam;
2440 
2441  PhMwpOnNetworkItemAdded(runId, networkItem);
2442  }
2443  break;
2445  {
2447  }
2448  break;
2450  {
2452  }
2453  break;
2455  {
2457  }
2458  break;
2459  }
2460 
2461  return 0;
2462 }
2463 
2465  _In_opt_ PVOID Parameter,
2466  _In_opt_ PVOID Context
2467  )
2468 {
2469  PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)Parameter;
2470 
2471  // Reference the process item so it doesn't get deleted before
2472  // we handle the event in the main thread.
2473  PhReferenceObject(processItem);
2474  PostMessage(
2477  (WPARAM)PhGetRunIdProvider(&ProcessProviderRegistration),
2478  (LPARAM)processItem
2479  );
2480 }
2481 
2483  _In_opt_ PVOID Parameter,
2484  _In_opt_ PVOID Context
2485  )
2486 {
2487  PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)Parameter;
2488 
2489  PostMessage(PhMainWndHandle, WM_PH_PROCESS_MODIFIED, 0, (LPARAM)processItem);
2490 }
2491 
2493  _In_opt_ PVOID Parameter,
2494  _In_opt_ PVOID Context
2495  )
2496 {
2497  PPH_PROCESS_ITEM processItem = (PPH_PROCESS_ITEM)Parameter;
2498 
2499  // We already have a reference to the process item, so we don't need to
2500  // reference it here.
2501  PostMessage(PhMainWndHandle, WM_PH_PROCESS_REMOVED, 0, (LPARAM)processItem);
2502 }
2503 
2505  _In_opt_ PVOID Parameter,
2506  _In_opt_ PVOID Context
2507  )
2508 {
2509  PostMessage(PhMainWndHandle, WM_PH_PROCESSES_UPDATED, 0, 0);
2510 }
2511 
2513  _In_opt_ PVOID Parameter,
2514  _In_opt_ PVOID Context
2515  )
2516 {
2517  PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)Parameter;
2518 
2519  PhReferenceObject(serviceItem);
2520  PostMessage(
2523  PhGetRunIdProvider(&ServiceProviderRegistration),
2524  (LPARAM)serviceItem
2525  );
2526 }
2527 
2529  _In_opt_ PVOID Parameter,
2530  _In_opt_ PVOID Context
2531  )
2532 {
2533  PPH_SERVICE_MODIFIED_DATA serviceModifiedData = (PPH_SERVICE_MODIFIED_DATA)Parameter;
2535 
2536  copy = PhAllocateCopy(serviceModifiedData, sizeof(PH_SERVICE_MODIFIED_DATA));
2537 
2538  PostMessage(PhMainWndHandle, WM_PH_SERVICE_MODIFIED, 0, (LPARAM)copy);
2539 }
2540 
2542  _In_opt_ PVOID Parameter,
2543  _In_opt_ PVOID Context
2544  )
2545 {
2546  PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)Parameter;
2547 
2548  PostMessage(PhMainWndHandle, WM_PH_SERVICE_REMOVED, 0, (LPARAM)serviceItem);
2549 }
2550 
2552  _In_opt_ PVOID Parameter,
2553  _In_opt_ PVOID Context
2554  )
2555 {
2556  PostMessage(PhMainWndHandle, WM_PH_SERVICES_UPDATED, 0, 0);
2557 }
2558 
2560  _In_opt_ PVOID Parameter,
2561  _In_opt_ PVOID Context
2562  )
2563 {
2564  PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)Parameter;
2565 
2566  PhReferenceObject(networkItem);
2567  PostMessage(
2570  PhGetRunIdProvider(&NetworkProviderRegistration),
2571  (LPARAM)networkItem
2572  );
2573 }
2574 
2576  _In_opt_ PVOID Parameter,
2577  _In_opt_ PVOID Context
2578  )
2579 {
2580  PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)Parameter;
2581 
2582  PostMessage(PhMainWndHandle, WM_PH_NETWORK_ITEM_MODIFIED, 0, (LPARAM)networkItem);
2583 }
2584 
2586  _In_opt_ PVOID Parameter,
2587  _In_opt_ PVOID Context
2588  )
2589 {
2590  PPH_NETWORK_ITEM networkItem = (PPH_NETWORK_ITEM)Parameter;
2591 
2592  PostMessage(PhMainWndHandle, WM_PH_NETWORK_ITEM_REMOVED, 0, (LPARAM)networkItem);
2593 }
2594 
2596  _In_opt_ PVOID Parameter,
2597  _In_opt_ PVOID Context
2598  )
2599 {
2600  PostMessage(PhMainWndHandle, WM_PH_NETWORK_ITEMS_UPDATED, 0, 0);
2601 }
2602 
2604  VOID
2605  )
2606 {
2607  ULONG opacity;
2608  PPH_STRING customFont;
2609 
2610  if (PhGetIntegerSetting(L"MainWindowAlwaysOnTop"))
2611  {
2612  AlwaysOnTop = TRUE;
2613  SetWindowPos(PhMainWndHandle, HWND_TOPMOST, 0, 0, 0, 0,
2614  SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE);
2615  }
2616 
2617  opacity = PhGetIntegerSetting(L"MainWindowOpacity");
2618 
2619  if (opacity != 0)
2621 
2622  PhStatisticsSampleCount = PhGetIntegerSetting(L"SampleCount");
2623  PhEnableProcessQueryStage2 = !!PhGetIntegerSetting(L"EnableStage2");
2624  PhEnablePurgeProcessRecords = !PhGetIntegerSetting(L"NoPurgeProcessRecords");
2625  PhEnableCycleCpuUsage = !!PhGetIntegerSetting(L"EnableCycleCpuUsage");
2626  PhEnableServiceNonPoll = !!PhGetIntegerSetting(L"EnableServiceNonPoll");
2627  PhEnableNetworkProviderResolve = !!PhGetIntegerSetting(L"EnableNetworkResolve");
2628 
2629  PhNfLoadStage1();
2630 
2631  NotifyIconNotifyMask = PhGetIntegerSetting(L"IconNotifyMask");
2632 
2633  if (PhGetIntegerSetting(L"HideOtherUserProcesses"))
2634  {
2636  }
2637 
2638  if (PhGetIntegerSetting(L"HideSignedProcesses"))
2639  {
2641  }
2642 
2643  customFont = PhGetStringSetting(L"Font");
2644 
2645  if (customFont->Length / 2 / 2 == sizeof(LOGFONT))
2646  SendMessage(PhMainWndHandle, WM_PH_UPDATE_FONT, 0, 0);
2647 
2648  PhDereferenceObject(customFont);
2649 
2651  // Service and network list settings are loaded on demand.
2652 }
2653 
2655  VOID
2656  )
2657 {
2659  if (ServiceTreeListLoaded)
2661  if (NetworkTreeListLoaded)
2663 
2664  PhNfSaveSettings();
2665 
2666  PhSetIntegerSetting(L"IconNotifyMask", NotifyIconNotifyMask);
2667 
2668  PhSaveWindowPlacementToSetting(L"MainWindowPosition", L"MainWindowSize", PhMainWndHandle);
2669 
2671 
2672  if (PhSettingsFileName)
2674 }
2675 
2677  VOID
2678  )
2679 {
2680  WINDOWPLACEMENT placement = { sizeof(placement) };
2681 
2682  GetWindowPlacement(PhMainWndHandle, &placement);
2683 
2684  if (placement.showCmd == SW_NORMAL)
2685  PhSetIntegerSetting(L"MainWindowState", SW_NORMAL);
2686  else if (placement.showCmd == SW_MAXIMIZE)
2687  PhSetIntegerSetting(L"MainWindowState", SW_MAXIMIZE);
2688 }
2689 
2691  _In_ PWSTR DbgHelpPath
2692  )
2693 {
2694  HMODULE dbghelpModule;
2695 
2696  if (dbghelpModule = LoadLibrary(DbgHelpPath))
2697  {
2698  PPH_STRING fullDbghelpPath;
2699  ULONG indexOfFileName;
2700  PH_STRINGREF dbghelpFolder;
2701  PPH_STRING symsrvPath;
2702 
2703  fullDbghelpPath = PhGetDllFileName(dbghelpModule, &indexOfFileName);
2704 
2705  if (fullDbghelpPath)
2706  {
2707  if (indexOfFileName != 0)
2708  {
2709  static PH_STRINGREF symsrvString = PH_STRINGREF_INIT(L"\\symsrv.dll");
2710 
2711  dbghelpFolder.Buffer = fullDbghelpPath->Buffer;
2712  dbghelpFolder.Length = indexOfFileName * sizeof(WCHAR);
2713 
2714  symsrvPath = PhConcatStringRef2(&dbghelpFolder, &symsrvString);
2715  LoadLibrary(symsrvPath->Buffer);
2716  PhDereferenceObject(symsrvPath);
2717  }
2718 
2719  PhDereferenceObject(fullDbghelpPath);
2720  }
2721  }
2722  else
2723  {
2724  dbghelpModule = LoadLibrary(L"dbghelp.dll");
2725  }
2726 
2728 }
2729 
2731  _In_opt_ PVOID Parameter,
2732  _In_opt_ PVOID Context
2733  )
2734 {
2735  PPH_STRING dbghelpPath;
2736 
2737  dbghelpPath = PhGetStringSetting(L"DbgHelpPath");
2738  PhLoadDbgHelpFromPath(dbghelpPath->Buffer);
2739  PhDereferenceObject(dbghelpPath);
2740 }
2741 
2743  VOID
2744  )
2745 {
2747 
2748  memset(&data, 0, sizeof(PH_LAYOUT_PADDING_DATA));
2749  PhInvokeCallback(&LayoutPaddingCallback, &data);
2750 
2751  LayoutPadding = data.Padding;
2752 }
2753 
2755  _Inout_ PRECT Rect,
2756  _In_ PRECT Padding
2757  )
2758 {
2759  Rect->left += Padding->left;
2760  Rect->top += Padding->top;
2761  Rect->right -= Padding->right;
2762  Rect->bottom -= Padding->bottom;
2763 }
2764 
2766  _Inout_ HDWP *DeferHandle
2767  )
2768 {
2769  RECT rect;
2770 
2771  // Resize the tab control.
2772  // Don't defer the resize. The tab control doesn't repaint properly.
2773 
2774  if (!LayoutPaddingValid)
2775  {
2777  LayoutPaddingValid = TRUE;
2778  }
2779 
2780  GetClientRect(PhMainWndHandle, &rect);
2781  PhMwpApplyLayoutPadding(&rect, &LayoutPadding);
2782 
2783  SetWindowPos(TabControlHandle, NULL,
2784  rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
2785  SWP_NOACTIVATE | SWP_NOZORDER);
2786  UpdateWindow(TabControlHandle);
2787 
2788  PhMwpLayoutTabControl(DeferHandle);
2789 }
2790 
2792  _In_ PPH_EMENU_ITEM Root
2793  )
2794 {
2795  PPH_EMENU_ITEM menuItem;
2796 
2797  if (WindowsVersion < WINDOWS_8)
2798  {
2800  PhDestroyEMenuItem(menuItem);
2802  PhDestroyEMenuItem(menuItem);
2803  }
2804 }
2805 
2807  _In_ ULONG Id
2808  )
2809 {
2810  switch (Id)
2811  {
2812  case ID_COMPUTER_LOCK:
2814  return TRUE;
2815  case ID_COMPUTER_LOGOFF:
2817  return TRUE;
2818  case ID_COMPUTER_SLEEP:
2820  return TRUE;
2821  case ID_COMPUTER_HIBERNATE:
2823  return TRUE;
2824  case ID_COMPUTER_RESTART:
2826  return TRUE;
2828  PhUiRestartComputer(PhMainWndHandle, EWX_BOOTOPTIONS);
2829  return TRUE;
2830  case ID_COMPUTER_SHUTDOWN:
2832  return TRUE;
2834  PhUiShutdownComputer(PhMainWndHandle, EWX_HYBRID_SHUTDOWN);
2835  return TRUE;
2836  }
2837 
2838  return FALSE;
2839 }
2840 
2842  _In_ BOOLEAN Toggle
2843  )
2844 {
2845  if (IsIconic(PhMainWndHandle))
2846  {
2847  ShowWindow(PhMainWndHandle, SW_RESTORE);
2848  SetForegroundWindow(PhMainWndHandle);
2849  }
2850  else if (IsWindowVisible(PhMainWndHandle))
2851  {
2852  if (Toggle)
2853  ShowWindow(PhMainWndHandle, SW_HIDE);
2854  else
2855  SetForegroundWindow(PhMainWndHandle);
2856  }
2857  else
2858  {
2859  ShowWindow(PhMainWndHandle, SW_SHOW);
2860  SetForegroundWindow(PhMainWndHandle);
2861  }
2862 }
2863 
2865  _In_ HMENU Menu
2866  )
2867 {
2868  MENUINFO menuInfo;
2869  ULONG i;
2870 
2871  menuInfo.cbSize = sizeof(MENUINFO);
2872  menuInfo.fMask = MIM_STYLE;
2873  menuInfo.dwStyle = MNS_NOTIFYBYPOS;
2874  SetMenuInfo(Menu, &menuInfo);
2875 
2876  for (i = 0; i < sizeof(SubMenuHandles) / sizeof(HMENU); i++)
2877  {
2878  SubMenuHandles[i] = GetSubMenu(PhMainWndMenuHandle, i);
2879  }
2880 }
2881 
2883  _In_ HMENU MenuHandle,
2884  _In_ ULONG ItemIndex,
2885  _In_ ULONG ItemId,
2886  _In_ ULONG_PTR ItemData
2887  )
2888 {
2889  switch (ItemId)
2890  {
2891  case ID_PLUGIN_MENU_ITEM:
2892  {
2893  PPH_EMENU_ITEM menuItem;
2894  PH_PLUGIN_MENU_INFORMATION menuInfo;
2895 
2896  menuItem = (PPH_EMENU_ITEM)ItemData;
2897 
2898  if (menuItem)
2899  {
2900  PhPluginInitializeMenuInfo(&menuInfo, NULL, PhMainWndHandle, 0);
2901  PhPluginTriggerEMenuItem(&menuInfo, menuItem);
2902  }
2903 
2904  return;
2905  }
2906  break;
2908  {
2909  PPH_EMENU_ITEM menuItem;
2910 
2911  menuItem = (PPH_EMENU_ITEM)ItemData;
2912 
2913  if (menuItem)
2914  {
2915  PPH_NF_ICON icon;
2916 
2917  icon = menuItem->Context;
2919  }
2920 
2921  return;
2922  }
2923  break;
2924  case ID_USER_CONNECT:
2925  case ID_USER_DISCONNECT:
2926  case ID_USER_LOGOFF:
2927  case ID_USER_REMOTECONTROL:
2928  case ID_USER_SENDMESSAGE:
2929  case ID_USER_PROPERTIES:
2930  {
2931  SelectedUserSessionId = (ULONG)ItemData;
2932  }
2933  break;
2934  }
2935 
2936  SendMessage(PhMainWndHandle, WM_COMMAND, ItemId, 0);
2937 }
2938 
2940  _In_ PPH_ADDMENUITEM AddMenuItem
2941  )
2942 {
2943  PPH_ADDMENUITEM addMenuItem;
2944  PPH_PLUGIN_MENU_ITEM pluginMenuItem;
2945 
2946  if (!LegacyAddMenuItemList)
2947  LegacyAddMenuItemList = PhCreateList(8);
2948 
2949  addMenuItem = PhAllocateCopy(AddMenuItem, sizeof(PH_ADDMENUITEM));
2950  PhAddItemList(LegacyAddMenuItemList, addMenuItem);
2951 
2952  pluginMenuItem = PhAllocate(sizeof(PH_PLUGIN_MENU_ITEM));
2953  memset(pluginMenuItem, 0, sizeof(PH_PLUGIN_MENU_ITEM));
2954  pluginMenuItem->Plugin = AddMenuItem->Plugin;
2955  pluginMenuItem->Id = AddMenuItem->Id;
2956  pluginMenuItem->Context = AddMenuItem->Context;
2957 
2958  addMenuItem->Context = pluginMenuItem;
2959 
2960  return TRUE;
2961 }
2962 
2964  VOID
2965  )
2966 {
2967  static HBITMAP shieldBitmap = NULL;
2968 
2969  if (!shieldBitmap)
2970  {
2971  _LoadIconMetric loadIconMetric;
2972  HICON shieldIcon = NULL;
2973 
2974  // It is necessary to use LoadIconMetric because otherwise the icons are at the wrong
2975  // resolution and look very bad when scaled down to the small icon size.
2976 
2977  loadIconMetric = (_LoadIconMetric)PhGetModuleProcAddress(L"comctl32.dll", "LoadIconMetric");
2978 
2979  if (loadIconMetric)
2980  {
2981  if (SUCCEEDED(loadIconMetric(NULL, IDI_SHIELD, LIM_SMALL, &shieldIcon)))
2982  {
2983  shieldBitmap = PhIconToBitmap(shieldIcon, PhSmallIconSize.X, PhSmallIconSize.Y);
2984  DestroyIcon(shieldIcon);
2985  }
2986  }
2987  }
2988 
2989  return shieldBitmap;
2990 }
2991 
2993  _In_ PPH_EMENU Menu,
2994  _In_ ULONG Index
2995  )
2996 {
2997  PPH_EMENU_ITEM menuItem;
2998 
2999  if (Index == 0) // Hacker
3000  {
3001  // Fix some menu items.
3002  if (PhElevated)
3003  {
3004  if (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_HACKER_RUNASADMINISTRATOR))
3005  PhDestroyEMenuItem(menuItem);
3006  if (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_HACKER_SHOWDETAILSFORALLPROCESSES))
3007  PhDestroyEMenuItem(menuItem);
3008  }
3009  else
3010  {
3011  HBITMAP shieldBitmap;
3012 
3013  if (shieldBitmap = PhMwpGetShieldBitmap())
3014  {
3015  if (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_HACKER_SHOWDETAILSFORALLPROCESSES))
3016  menuItem->Bitmap = shieldBitmap;
3017  }
3018  }
3019 
3020  // Fix up the Computer menu.
3021  PhMwpSetupComputerMenu(Menu);
3022  }
3023  else if (Index == 1) // View
3024  {
3025  PPH_EMENU_ITEM trayIconsMenuItem;
3026  ULONG i;
3027  PPH_EMENU_ITEM menuItem;
3028  ULONG id;
3029  ULONG placeholderIndex;
3030 
3031  trayIconsMenuItem = PhMwpFindTrayIconsMenuItem(Menu);
3032 
3033  if (trayIconsMenuItem)
3034  {
3035  ULONG maximum;
3036  PPH_NF_ICON icon;
3037 
3038  // Add menu items for the registered tray icons.
3039 
3041  maximum = PhNfGetMaximumIconId();
3042 
3043  for (; id != maximum; id <<= 1)
3044  {
3045  if (icon = PhNfGetIconById(id))
3046  {
3047  PhInsertEMenuItem(trayIconsMenuItem, PhCreateEMenuItem(0, ID_TRAYICONS_REGISTERED, icon->Text, NULL, icon), -1);
3048  }
3049  }
3050 
3051  // Update the text and check marks on the menu items.
3052 
3053  for (i = 0; i < trayIconsMenuItem->Items->Count; i++)
3054  {
3055  menuItem = trayIconsMenuItem->Items->Items[i];
3056 
3057  id = -1;
3058  icon = NULL;
3059 
3060  switch (menuItem->Id)
3061  {
3063  id = PH_ICON_CPU_HISTORY;
3064  break;
3066  id = PH_ICON_IO_HISTORY;
3067  break;
3070  break;
3073  break;
3074  case ID_TRAYICONS_CPUUSAGE:
3075  id = PH_ICON_CPU_USAGE;
3076  break;
3078  icon = menuItem->Context;
3079  id = icon->IconId;
3080  break;
3081  }
3082 
3083  if (id != -1)
3084  {
3085  if (PhNfTestIconMask(id))
3086  menuItem->Flags |= PH_EMENU_CHECKED;
3087 
3088  if (icon && (icon->Flags & PH_NF_ICON_UNAVAILABLE))
3089  {
3090  PPH_STRING newText;
3091 
3092  newText = PhaConcatStrings2(icon->Text, L" (Unavailable)");
3094  PhAllocateCopy(newText->Buffer, newText->Length + sizeof(WCHAR)), NULL);
3095  }
3096  }
3097  }
3098  }
3099 
3100  if (menuItem = PhFindEMenuItemEx(Menu, 0, NULL, ID_VIEW_SECTIONPLACEHOLDER, NULL, &placeholderIndex))
3101  {
3102  PhDestroyEMenuItem(menuItem);
3103  PhMwpInitializeSectionMenuItems(Menu, placeholderIndex);
3104  }
3105 
3106  if (AlwaysOnTop && (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_VIEW_ALWAYSONTOP)))
3107  menuItem->Flags |= PH_EMENU_CHECKED;
3108 
3109  id = PH_OPACITY_TO_ID(PhGetIntegerSetting(L"MainWindowOpacity"));
3110 
3111  if (menuItem = PhFindEMenuItem(Menu, PH_EMENU_FIND_DESCEND, NULL, id))
3113 
3114  switch (PhGetIntegerSetting(L"UpdateInterval"))
3115  {
3116  case 500:
3118  break;
3119  case 1000:
3121  break;
3122  case 2000:
3124  break;
3125  case 5000:
3127  break;
3128  case 10000:
3130  break;
3131  default:
3132  id = -1;
3133  break;
3134  }
3135 
3136  if (id != -1 && (menuItem = PhFindEMenuItem(Menu, PH_EMENU_FIND_DESCEND, NULL, id)))
3138 
3139  if (UpdateAutomatically && (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_VIEW_UPDATEAUTOMATICALLY)))
3140  menuItem->Flags |= PH_EMENU_CHECKED;
3141  }
3142  else if (Index == 2) // Tools
3143  {
3144 #ifdef _WIN64
3145  if (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_TOOLS_HIDDENPROCESSES))
3146  PhDestroyEMenuItem(menuItem);
3147 #endif
3148 
3149  // Windows 8 Task Manager requires elevation.
3150  if (WindowsVersion >= WINDOWS_8 && !PhElevated)
3151  {
3152  HBITMAP shieldBitmap;
3153 
3154  if (shieldBitmap = PhMwpGetShieldBitmap())
3155  {
3156  if (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_TOOLS_STARTTASKMANAGER))
3157  menuItem->Bitmap = shieldBitmap;
3158  }
3159  }
3160  }
3161 
3162  if (LegacyAddMenuItemList)
3163  {
3164  ULONG i;
3165  PPH_ADDMENUITEM addMenuItem;
3166 
3167  for (i = 0; i < LegacyAddMenuItemList->Count; i++)
3168  {
3169  addMenuItem = LegacyAddMenuItemList->Items[i];
3170 
3171  if (addMenuItem->Location == Index)
3172  {
3173  ULONG insertIndex;
3174 
3175  if (addMenuItem->InsertAfter)
3176  {
3177  for (insertIndex = 0; insertIndex < Menu->Items->Count; insertIndex++)
3178  {
3179  menuItem = Menu->Items->Items[insertIndex];
3180 
3182  addMenuItem->InsertAfter,
3183  menuItem->Text,
3184  TRUE,
3185  TRUE
3186  ) == 0))
3187  {
3188  insertIndex++;
3189  break;
3190  }
3191  }
3192  }
3193  else
3194  {
3195  insertIndex = 0;
3196  }
3197 
3198  if (addMenuItem->Text[0] == '-' && addMenuItem->Text[1] == 0)
3199  PhInsertEMenuItem(Menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, L"", NULL, NULL), insertIndex);
3200  else
3201  PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_PLUGIN_MENU_ITEM, addMenuItem->Text, NULL, addMenuItem->Context), insertIndex);
3202  }
3203  }
3204  }
3205 }
3206 
3208  _In_ PPH_EMENU Menu
3209  )
3210 {
3211  ULONG i;
3212  PPH_EMENU_ITEM menuItem;
3213 
3214  for (i = 0; i < Menu->Items->Count; i++)
3215  {
3216  menuItem = Menu->Items->Items[i];
3217 
3218  if (PhFindEMenuItem(menuItem, 0, NULL, ID_TRAYICONS_CPUHISTORY))
3219  return menuItem;
3220  }
3221 
3222  return NULL;
3223 }
3224 
3226  _In_ PPH_EMENU Menu,
3227  _In_ ULONG StartIndex
3228  )
3229 {
3230  INT selectedIndex;
3231  PPH_EMENU_ITEM menuItem;
3232 
3233  selectedIndex = TabCtrl_GetCurSel(TabControlHandle);
3234 
3235  if (selectedIndex == ProcessesTabIndex)
3236  {
3237  PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_VIEW_HIDEPROCESSESFROMOTHERUSERS, L"Hide Processes From Other Users", NULL, NULL), StartIndex);
3238  PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_VIEW_HIDESIGNEDPROCESSES, L"Hide Signed Processes", NULL, NULL), StartIndex + 1);
3239  PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_VIEW_SCROLLTONEWPROCESSES, L"Scroll to New Processes", NULL, NULL), StartIndex + 2);
3240  PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_VIEW_SHOWCPUBELOW001, L"Show CPU Below 0.01", NULL, NULL), StartIndex + 3);
3241 
3242  if (CurrentUserFilterEntry && (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_VIEW_HIDEPROCESSESFROMOTHERUSERS)))
3243  menuItem->Flags |= PH_EMENU_CHECKED;
3244  if (SignedFilterEntry && (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_VIEW_HIDESIGNEDPROCESSES)))
3245  menuItem->Flags |= PH_EMENU_CHECKED;
3246  if (PhCsScrollToNewProcesses && (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_VIEW_SCROLLTONEWPROCESSES)))
3247  menuItem->Flags |= PH_EMENU_CHECKED;
3248 
3249  if (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_VIEW_SHOWCPUBELOW001))
3250  {
3252  {
3253  if (PhCsShowCpuBelow001)
3254  menuItem->Flags |= PH_EMENU_CHECKED;
3255  }
3256  else
3257  {
3258  menuItem->Flags |= PH_EMENU_DISABLED;
3259  }
3260  }
3261  }
3262  else if (selectedIndex == ServicesTabIndex)
3263  {
3264  PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_VIEW_HIDEDRIVERSERVICES, L"Hide Driver Services", NULL, NULL), StartIndex);
3265 
3266  if (DriverFilterEntry && (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_VIEW_HIDEDRIVERSERVICES)))
3267  menuItem->Flags |= PH_EMENU_CHECKED;
3268  }
3269  else if (selectedIndex == NetworkTabIndex)
3270  {
3271  // Remove the extra separator.
3272  PhRemoveEMenuItem(Menu, NULL, StartIndex);
3273 
3274  // Disabled for now - may cause user confusion.
3275 
3276  //PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_VIEW_HIDEPROCESSESFROMOTHERUSERS, L"Hide Processes From Other Users", NULL, NULL), StartIndex);
3277  //PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_VIEW_HIDESIGNEDPROCESSES, L"Hide Signed Processes", NULL, NULL), StartIndex + 1);
3278 
3279  //if (CurrentUserFilterEntry && (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_VIEW_HIDEPROCESSESFROMOTHERUSERS)))
3280  // menuItem->Flags |= PH_EMENU_CHECKED;
3281  //if (SignedFilterEntry && (menuItem = PhFindEMenuItem(Menu, 0, NULL, ID_VIEW_HIDESIGNEDPROCESSES)))
3282  // menuItem->Flags |= PH_EMENU_CHECKED;
3283  }
3284  else if (AdditionalTabPageList)
3285  {
3286  ULONG i;
3287 
3288  for (i = 0; i < AdditionalTabPageList->Count; i++)
3289  {
3290  PPH_ADDITIONAL_TAB_PAGE tabPage = AdditionalTabPageList->Items[i];
3291 
3292  if (selectedIndex == tabPage->Index)
3293  {
3295  {
3296  tabPage->InitializeSectionMenuItemsCallback(Menu, (PVOID)StartIndex, NULL, tabPage->Context);
3297  }
3298  else
3299  {
3300  // Remove the extra separator.
3301  PhRemoveEMenuItem(Menu, NULL, StartIndex);
3302  }
3303 
3304  break;
3305  }
3306  }
3307  }
3308 }
3309 
3311  _Inout_ HDWP *DeferHandle
3312  )
3313 {
3314  RECT rect;
3315  INT selectedIndex;
3316 
3317  if (!LayoutPaddingValid)
3318  {
3320  LayoutPaddingValid = TRUE;
3321  }
3322 
3323  GetClientRect(PhMainWndHandle, &rect);
3324  PhMwpApplyLayoutPadding(&rect, &LayoutPadding);
3325  TabCtrl_AdjustRect(TabControlHandle, FALSE, &rect);
3326 
3327  selectedIndex = TabCtrl_GetCurSel(TabControlHandle);
3328 
3329  if (selectedIndex == ProcessesTabIndex)
3330  {
3331  *DeferHandle = DeferWindowPos(*DeferHandle, ProcessTreeListHandle, NULL,
3332  rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
3333  SWP_NOACTIVATE | SWP_NOZORDER);
3334  }
3335  else if (selectedIndex == ServicesTabIndex)
3336  {
3337  *DeferHandle = DeferWindowPos(*DeferHandle, ServiceTreeListHandle, NULL,
3338  rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
3339  SWP_NOACTIVATE | SWP_NOZORDER);
3340  }
3341  else if (selectedIndex == NetworkTabIndex)
3342  {
3343  *DeferHandle = DeferWindowPos(*DeferHandle, NetworkTreeListHandle, NULL,
3344  rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
3345  SWP_NOACTIVATE | SWP_NOZORDER);
3346  }
3347  else if (AdditionalTabPageList)
3348  {
3349  ULONG i;
3350 
3351  for (i = 0; i < AdditionalTabPageList->Count; i++)
3352  {
3353  PPH_ADDITIONAL_TAB_PAGE tabPage = AdditionalTabPageList->Items[i];
3354 
3355  if (selectedIndex == tabPage->Index)
3356  {
3357  // Create the tab page window if it doesn't exist.
3358  if (!tabPage->WindowHandle)
3359  {
3360  tabPage->WindowHandle = tabPage->CreateFunction(tabPage->Context);
3361  BringWindowToTop(tabPage->WindowHandle);
3362 
3363  if (CurrentCustomFont && tabPage->FontChangedCallback)
3364  tabPage->FontChangedCallback((PVOID)CurrentCustomFont, NULL, NULL, tabPage->Context);
3365  }
3366 
3367  if (tabPage->WindowHandle)
3368  {
3369  *DeferHandle = DeferWindowPos(*DeferHandle, tabPage->WindowHandle, NULL,
3370  rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
3371  SWP_NOACTIVATE | SWP_NOZORDER);
3372  }
3373 
3374  break;
3375  }
3376  }
3377  }
3378 }
3379 
3381  _In_ NMHDR *Header
3382  )
3383 {
3384  if (Header->code == TCN_SELCHANGING)
3385  {
3386  OldTabIndex = TabCtrl_GetCurSel(TabControlHandle);
3387  }
3388  else if (Header->code == TCN_SELCHANGE)
3389  {
3390  PhMwpSelectionChangedTabControl(OldTabIndex);
3391  }
3392 }
3393 
3395  _In_ ULONG OldIndex
3396  )
3397 {
3398  INT selectedIndex;
3399  HDWP deferHandle;
3400 
3401  selectedIndex = TabCtrl_GetCurSel(TabControlHandle);
3402 
3403  deferHandle = BeginDeferWindowPos(1);
3404  PhMwpLayoutTabControl(&deferHandle);
3405  EndDeferWindowPos(deferHandle);
3406 
3407  // Built-in tabs
3408 
3409  if (selectedIndex == ServicesTabIndex)
3411 
3412  if (selectedIndex == NetworkTabIndex)
3413  {
3415 
3416  PhSetEnabledProvider(&NetworkProviderRegistration, UpdateAutomatically);
3417 
3418  if (UpdateAutomatically || NetworkFirstTime)
3419  {
3420  PhBoostProvider(&NetworkProviderRegistration, NULL);
3421  NetworkFirstTime = FALSE;
3422  }
3423  }
3424  else
3425  {
3426  PhSetEnabledProvider(&NetworkProviderRegistration, FALSE);
3427  }
3428 
3429  ShowWindow(ProcessTreeListHandle, selectedIndex == ProcessesTabIndex ? SW_SHOW : SW_HIDE);
3430  ShowWindow(ServiceTreeListHandle, selectedIndex == ServicesTabIndex ? SW_SHOW : SW_HIDE);
3431  ShowWindow(NetworkTreeListHandle, selectedIndex == NetworkTabIndex ? SW_SHOW : SW_HIDE);
3432 
3433  // Additional tabs
3434 
3435  if (AdditionalTabPageList)
3436  {
3437  ULONG i;
3438 
3439  for (i = 0; i < AdditionalTabPageList->Count; i++)
3440  {
3441  PPH_ADDITIONAL_TAB_PAGE tabPage = AdditionalTabPageList->Items[i];
3442 
3443  if (tabPage->SelectionChangedCallback)
3444  {
3445  if (tabPage->Index == OldIndex)
3446  {
3447  tabPage->SelectionChangedCallback((PVOID)FALSE, 0, 0, tabPage->Context);
3448  }
3449  else if (tabPage->Index == selectedIndex)
3450  {
3451  tabPage->SelectionChangedCallback((PVOID)TRUE, 0, 0, tabPage->Context);
3452  }
3453  }
3454 
3455  ShowWindow(tabPage->WindowHandle, selectedIndex == tabPage->Index ? SW_SHOW : SW_HIDE);
3456  }
3457  }
3458 
3459  if (PhPluginsEnabled)
3461 }
3462 
3464  _In_ PPH_ADDITIONAL_TAB_PAGE TabPage
3465  )
3466 {
3467  PPH_ADDITIONAL_TAB_PAGE newTabPage;
3468  HDWP deferHandle;
3469 
3470  if (!AdditionalTabPageList)
3471  AdditionalTabPageList = PhCreateList(2);
3472 
3473  newTabPage = PhAllocateCopy(TabPage, sizeof(PH_ADDITIONAL_TAB_PAGE));
3474  PhAddItemList(AdditionalTabPageList, newTabPage);
3475 
3476  newTabPage->Index = PhAddTabControlTab(TabControlHandle, MAXINT, newTabPage->Text);
3477  MaxTabIndex = newTabPage->Index;
3478 
3479  if (newTabPage->WindowHandle)
3480  BringWindowToTop(newTabPage->WindowHandle);
3481 
3482  // The tab control might need multiple lines, so we need to refresh the layout.
3483  deferHandle = BeginDeferWindowPos(1);
3484  PhMwpLayoutTabControl(&deferHandle);
3485  EndDeferWindowPos(deferHandle);
3486 
3487  return newTabPage;
3488 }
3489 
3491  _In_ ULONG Index
3492  )
3493 {
3494  INT oldIndex;
3495 
3496  oldIndex = TabCtrl_GetCurSel(TabControlHandle);
3497  TabCtrl_SetCurSel(TabControlHandle, Index);
3499 }
3500 
3502  _In_ PWSTR Text
3503  )
3504 {
3505  if (PhEqualStringZ(Text, L"Processes", TRUE))
3506  {
3507  return ProcessesTabIndex;
3508  }
3509  else if (PhEqualStringZ(Text, L"Services", TRUE))
3510  {
3511  return ServicesTabIndex;
3512  }
3513  else if (PhEqualStringZ(Text, L"Network", TRUE))
3514  {
3515  return NetworkTabIndex;
3516  }
3517  else if (AdditionalTabPageList)
3518  {
3519  ULONG i;
3520 
3521  for (i = 0; i < AdditionalTabPageList->Count; i++)
3522  {
3523  PPH_ADDITIONAL_TAB_PAGE tabPage = AdditionalTabPageList->Items[i];
3524 
3525  if (PhEqualStringZ(tabPage->Text, Text, TRUE))
3526  return tabPage->Index;
3527  }
3528  }
3529 
3530  return -1;
3531 }
3532 
3533 static int __cdecl IconProcessesCpuUsageCompare(
3534  _In_ const void *elem1,
3535  _In_ const void *elem2
3536  )
3537 {
3538  PPH_PROCESS_ITEM processItem1 = *(PPH_PROCESS_ITEM *)elem1;
3539  PPH_PROCESS_ITEM processItem2 = *(PPH_PROCESS_ITEM *)elem2;
3540 
3541  return -singlecmp(processItem1->CpuUsage, processItem2->CpuUsage);
3542 }
3543 
3544 static int __cdecl IconProcessesNameCompare(
3545  _In_ const void *elem1,
3546  _In_ const void *elem2
3547  )
3548 {
3549  PPH_PROCESS_ITEM processItem1 = *(PPH_PROCESS_ITEM *)elem1;
3550  PPH_PROCESS_ITEM processItem2 = *(PPH_PROCESS_ITEM *)elem2;
3551 
3552  return PhCompareString(processItem1->ProcessName, processItem2->ProcessName, TRUE);
3553 }
3554 
3556  _Inout_ struct _PH_EMENU_ITEM *Menu,
3557  _In_ HANDLE ProcessId
3558  )
3559 {
3560  PPH_EMENU_ITEM priorityMenu;
3561  PPH_EMENU_ITEM ioPriorityMenu = NULL;
3562  PPH_PROCESS_ITEM processItem;
3563  BOOLEAN isSuspended = FALSE;
3564  BOOLEAN isPartiallySuspended = TRUE;
3565 
3566  // Priority
3567 
3568  priorityMenu = PhCreateEMenuItem(0, 0, L"Priority", NULL, ProcessId);
3569 
3570  PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_REALTIME, L"Real Time", NULL, ProcessId), -1);
3571  PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_HIGH, L"High", NULL, ProcessId), -1);
3572  PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_ABOVENORMAL, L"Above Normal", NULL, ProcessId), -1);
3573  PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_NORMAL, L"Normal", NULL, ProcessId), -1);
3574  PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_BELOWNORMAL, L"Below Normal", NULL, ProcessId), -1);
3575  PhInsertEMenuItem(priorityMenu, PhCreateEMenuItem(0, ID_PRIORITY_IDLE, L"Idle", NULL, ProcessId), -1);
3576 
3577  // I/O Priority
3578 
3580  {
3581  ioPriorityMenu = PhCreateEMenuItem(0, 0, L"I/O Priority", NULL, ProcessId);
3582 
3583  PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_I_3, L"High", NULL, ProcessId), -1);
3584  PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_I_2, L"Normal", NULL, ProcessId), -1);
3585  PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_I_1, L"Low", NULL, ProcessId), -1);
3586  PhInsertEMenuItem(ioPriorityMenu, PhCreateEMenuItem(0, ID_I_0, L"Very Low", NULL, ProcessId), -1);
3587  }
3588 
3589  // Menu
3590 
3591  PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_PROCESS_TERMINATE, L"T&erminate", NULL, ProcessId), -1);
3592 
3593  if (processItem = PhReferenceProcessItem(ProcessId))
3594  {
3595  isSuspended = (BOOLEAN)processItem->IsSuspended;
3596  isPartiallySuspended = (BOOLEAN)processItem->IsPartiallySuspended;
3597  PhDereferenceObject(processItem);
3598  }
3599 
3600  if (!isSuspended)
3601  PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_PROCESS_SUSPEND, L"&Suspend", NULL, ProcessId), -1);
3602  if (isPartiallySuspended)
3603  PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_PROCESS_RESUME, L"Res&ume", NULL, ProcessId), -1);
3604 
3605  PhInsertEMenuItem(Menu, priorityMenu, -1);
3606 
3607  if (ioPriorityMenu)
3608  PhInsertEMenuItem(Menu, ioPriorityMenu, -1);
3609 
3610  PhMwpSetProcessMenuPriorityChecks(Menu, ProcessId, TRUE, TRUE, FALSE);
3611 
3612  PhInsertEMenuItem(Menu, PhCreateEMenuItem(0, ID_PROCESS_PROPERTIES, L"P&roperties", NULL, ProcessId), -1);
3613 }
3614 
3616  _Inout_ struct _PH_EMENU_ITEM *MenuItem
3617  )
3618 {
3619  switch (MenuItem->Id)
3620  {
3621  case ID_PROCESS_TERMINATE:
3622  case ID_PROCESS_SUSPEND:
3623  case ID_PROCESS_RESUME:
3624  case ID_PROCESS_PROPERTIES:
3625  {
3626  HANDLE processId = MenuItem->Context;
3627  PPH_PROCESS_ITEM processItem;
3628 
3629  if (processItem = PhReferenceProcessItem(processId))
3630  {
3631  switch (MenuItem->Id)
3632  {
3633  case ID_PROCESS_TERMINATE:
3634  PhUiTerminateProcesses(PhMainWndHandle, &processItem, 1);
3635  break;
3636  case ID_PROCESS_SUSPEND:
3637  PhUiSuspendProcesses(PhMainWndHandle, &processItem, 1);
3638  break;
3639  case ID_PROCESS_RESUME:
3640  PhUiResumeProcesses(PhMainWndHandle, &processItem, 1);
3641  break;
3642  case ID_PROCESS_PROPERTIES:
3644  break;
3645  }
3646 
3647  PhDereferenceObject(processItem);
3648  }
3649  else
3650  {
3651  PhShowError(PhMainWndHandle, L"The process does not exist.");
3652  }
3653  }
3654  break;
3655  case ID_PRIORITY_REALTIME:
3656  case ID_PRIORITY_HIGH:
3658  case ID_PRIORITY_NORMAL:
3660  case ID_PRIORITY_IDLE:
3661  {
3662  HANDLE processId = MenuItem->Context;
3663  PPH_PROCESS_ITEM processItem;
3664 
3665  if (processItem = PhReferenceProcessItem(processId))
3666  {
3667  PhMwpExecuteProcessPriorityCommand(MenuItem->Id, &processItem, 1);
3668  PhDereferenceObject(processItem);
3669  }
3670  else
3671  {
3672  PhShowError(PhMainWndHandle, L"The process does not exist.");
3673  }
3674  }
3675  break;
3676  case ID_I_3:
3677  case ID_I_2:
3678  case ID_I_1:
3679  case ID_I_0:
3680  {
3681  HANDLE processId = MenuItem->Context;
3682  PPH_PROCESS_ITEM processItem;
3683 
3684  if (processItem = PhReferenceProcessItem(processId))
3685  {
3686  PhMwpExecuteProcessIoPriorityCommand(MenuItem->Id, &processItem, 1);
3687  PhDereferenceObject(processItem);
3688  }
3689  else
3690  {
3691  PhShowError(PhMainWndHandle, L"The process does not exist.");
3692  }
3693  }
3694  break;
3695  }
3696 
3697  return FALSE;
3698 }
3699 
3701  _In_ PPH_EMENU_ITEM Menu,
3702  _In_ ULONG NumberOfProcesses
3703  )
3704 {
3705  ULONG i;
3706  PPH_PROCESS_ITEM *processItems;
3707  ULONG numberOfProcessItems;
3708  PPH_LIST processList;
3709  PPH_PROCESS_ITEM processItem;
3710 
3711  PhEnumProcessItems(&processItems, &numberOfProcessItems);
3712  processList = PhCreateList(numberOfProcessItems);
3713  PhAddItemsList(processList, processItems, numberOfProcessItems);
3714 
3715  // Remove non-real processes.
3716  for (i = 0; i < processList->Count; i++)
3717  {
3718  processItem = processList->Items[i];
3719 
3720  if (!PH_IS_REAL_PROCESS_ID(processItem->ProcessId))
3721  {
3722  PhRemoveItemList(processList, i);
3723  i--;
3724  }
3725  }
3726 
3727  // Remove processes with zero CPU usage and those running as other users.
3728  for (i = 0; i < processList->Count && processList->Count > NumberOfProcesses; i++)
3729  {
3730  processItem = processList->Items[i];
3731 
3732  if (
3733  processItem->CpuUsage == 0 ||
3734  !processItem->UserName ||
3736  )
3737  {
3738  PhRemoveItemList(processList, i);
3739  i--;
3740  }
3741  }
3742 
3743  // Sort the processes by CPU usage and remove the extra processes at the end of the list.
3744  qsort(processList->Items, processList->Count, sizeof(PVOID), IconProcessesCpuUsageCompare);
3745 
3746  if (processList->Count > NumberOfProcesses)
3747  {
3748  PhRemoveItemsList(processList, NumberOfProcesses, processList->Count - NumberOfProcesses);
3749  }
3750 
3751  // Lastly, sort by name.
3752  qsort(processList->Items, processList->Count, sizeof(PVOID), IconProcessesNameCompare);
3753 
3754  // Delete all menu items.
3755  PhRemoveAllEMenuItems(Menu);
3756 
3757  // Add the processes.
3758 
3759  for (i = 0; i < processList->Count; i++)
3760  {
3761  PPH_EMENU_ITEM subMenu;
3762  HBITMAP iconBitmap;
3763  CLIENT_ID clientId;
3764  PPH_STRING clientIdName;
3765  PPH_STRING escapedName;
3766 
3767  processItem = processList->Items[i];
3768 
3769  // Process
3770 
3771  clientId.UniqueProcess = processItem->ProcessId;
3772  clientId.UniqueThread = NULL;
3773 
3774  clientIdName = PhGetClientIdName(&clientId);
3775  escapedName = PhEscapeStringForMenuPrefix(&clientIdName->sr);
3776  PhDereferenceObject(clientIdName);
3777  PhAutoDereferenceObject(escapedName);
3778 
3779  subMenu = PhCreateEMenuItem(
3780  0,
3781  0,
3782  escapedName->Buffer,
3783  NULL,
3784  processItem->ProcessId
3785  );
3786 
3787  if (processItem->SmallIcon)
3788  {
3789  iconBitmap = PhIconToBitmap(processItem->SmallIcon, PhSmallIconSize.X, PhSmallIconSize.Y);
3790  }
3791  else
3792  {
3793  HICON icon;
3794 
3795  PhGetStockApplicationIcon(&icon, NULL);
3796  iconBitmap = PhIconToBitmap(icon, PhSmallIconSize.X, PhSmallIconSize.Y);
3797  }
3798 
3799  subMenu->Bitmap = iconBitmap;
3800  subMenu->Flags |= PH_EMENU_BITMAP_OWNED; // automatically destroy the bitmap when necessary
3801 
3802  PhAddMiniProcessMenuItems(subMenu, processItem->ProcessId);
3803  PhInsertEMenuItem(Menu, subMenu, -1);
3804  }
3805 
3806  PhDereferenceObject(processList);
3807  PhDereferenceObjects(processItems, numberOfProcessItems);
3808  PhFree(processItems);
3809 }
3810 
3812  _In_ POINT Location
3813  )
3814 {
3815  PPH_EMENU menu;
3816  PPH_EMENU_ITEM item;
3817  PH_PLUGIN_MENU_INFORMATION menuInfo;
3818  ULONG numberOfProcesses;
3819  ULONG id;
3820  ULONG i;
3821 
3822  // This function seems to be called recursively under some circumstances.
3823  // To reproduce:
3824  // 1. Hold right mouse button on tray icon, then left click.
3825  // 2. Make the menu disappear by clicking on the menu then clicking somewhere else.
3826  // So, don't store any global state or bad things will happen.
3827 
3828  menu = PhCreateEMenu();
3829  PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_ICON), 0);
3830 
3831  // Check the Notifications menu items.
3832  for (i = PH_NOTIFY_MINIMUM; i != PH_NOTIFY_MAXIMUM; i <<= 1)
3833  {
3834  if (NotifyIconNotifyMask & i)
3835  {
3836  switch (i)
3837  {
3840  break;
3843  break;
3846  break;
3849  break;
3852  break;
3855  break;
3856  }
3857 
3859  }
3860  }
3861 
3862  // Add processes to the menu.
3863 
3864  numberOfProcesses = PhGetIntegerSetting(L"IconProcesses");
3865  item = PhFindEMenuItem(menu, 0, L"Processes", 0);
3866 
3867  if (item)
3868  PhMwpAddIconProcesses(item, numberOfProcesses);
3869 
3870  // Fix up the Computer menu.
3871  PhMwpSetupComputerMenu(menu);
3872 
3873  // Give plugins a chance to modify the menu.
3874 
3875  if (PhPluginsEnabled)
3876  {
3877  PhPluginInitializeMenuInfo(&menuInfo, menu, PhMainWndHandle, 0);
3879  }
3880 
3881  SetForegroundWindow(PhMainWndHandle); // window must be foregrounded so menu will disappear properly
3882  item = PhShowEMenu(
3883  menu,
3887  Location.x,
3888  Location.y
3889  );
3890 
3891  if (item)
3892  {
3893  BOOLEAN handled = FALSE;
3894 
3895  if (PhPluginsEnabled && !handled)
3896  handled = PhPluginTriggerEMenuItem(&menuInfo, item);
3897 
3898  if (!handled)
3899  handled = PhHandleMiniProcessMenuItem(item);
3900 
3901  if (!handled)
3902  handled = PhMwpExecuteComputerCommand(item->Id);
3903 
3904  if (!handled)
3905  {
3906  switch (item->Id)
3907  {
3909  SendMessage(PhMainWndHandle, WM_PH_TOGGLE_VISIBLE, 0, 0);
3910  break;
3912  SendMessage(PhMainWndHandle, WM_COMMAND, ID_VIEW_SYSTEMINFORMATION, 0);
3913  break;
3915  NotifyIconNotifyMask |= PH_NOTIFY_VALID_MASK;
3916  break;
3918  NotifyIconNotifyMask &= ~PH_NOTIFY_VALID_MASK;
3919  break;
3926  {
3927  ULONG bit;
3928 
3929  switch (item->Id)
3930  {
3933  break;
3936  break;
3939  break;
3942  break;
3944  bit = PH_NOTIFY_SERVICE_STOP;
3945  break;
3948  break;
3949  }
3950 
3951  NotifyIconNotifyMask ^= bit;
3952  }
3953  break;
3954  case ID_ICON_EXIT:
3955  SendMessage(PhMainWndHandle, WM_COMMAND, ID_HACKER_EXIT, 0);
3956  break;
3957  }
3958  }
3959  }
3960 
3961  PhDestroyEMenu(menu);
3962 }
3963 
3965  _In_ PWSTR Title,
3966  _In_ PWSTR Text,
3967  _In_ ULONG Flags
3968  )
3969 {
3970  PhNfShowBalloonTip(0, Title, Text, 10, Flags);
3971 }
3972 
3974  VOID
3975  )
3976 {
3977  switch (LastNotificationType)
3978  {
3980  {
3981  PPH_PROCESS_NODE processNode;
3982 
3983  if (processNode = PhFindProcessNode(LastNotificationDetails.ProcessId))
3984  {
3985  ProcessHacker_SelectTabPage(PhMainWndHandle, ProcessesTabIndex);
3988  }
3989  }
3990  break;
3994  {
3995  PPH_SERVICE_ITEM serviceItem;
3996 
3997  if (LastNotificationDetails.ServiceName &&
3998  (serviceItem = PhReferenceServiceItem(LastNotificationDetails.ServiceName->Buffer)))
3999  {
4000  ProcessHacker_SelectTabPage(PhMainWndHandle, ServicesTabIndex);
4003 
4004  PhDereferenceObject(serviceItem);
4005  }
4006  }
4007  break;
4008  }
4009 }
4010 
4012  VOID
4013  )
4014 {
4015  if (LastNotificationType &
4017  {
4018  PhClearReference(&LastNotificationDetails.ServiceName);
4019  }
4020 
4021  LastNotificationType = 0;
4022  memset(&LastNotificationDetails, 0, sizeof(LastNotificationDetails));
4023 }
4024 
4026  _In_ ULONG Type,
4027  _In_ PVOID Parameter
4028  )
4029 {
4030  PH_PLUGIN_NOTIFY_EVENT notifyEvent;
4031 
4032  notifyEvent.Type = Type;
4033  notifyEvent.Handled = FALSE;
4034  notifyEvent.Parameter = Parameter;
4035 
4037 
4038  return notifyEvent.Handled;
4039 }
4040 
4042  _In_ PPH_PROCESS_ITEM ProcessItem
4043  )
4044 {
4045  PPH_PROCESS_PROPCONTEXT propContext;
4046 
4047  propContext = PhCreateProcessPropContext(
4049  ProcessItem
4050  );
4051 
4052  if (propContext)
4053  {
4054  PhShowProcessProperties(propContext);
4055  PhDereferenceObject(propContext);
4056  }
4057 }
4058 
4060  _In_ PPH_TREENEW_NODE Node,
4061  _In_opt_ PVOID Context
4062  )
4063 {
4064  PPH_PROCESS_NODE processNode = (PPH_PROCESS_NODE)Node;
4065 
4066  if (!processNode->ProcessItem->UserName)
4067  return FALSE;
4068 
4069  if (!PhCurrentUserName)
4070  return FALSE;
4071 
4073  return FALSE;
4074 
4075  return TRUE;
4076 }
4077 
4079  _In_ PPH_TREENEW_NODE Node,
4080  _In_opt_ PVOID Context
4081  )
4082 {
4083  PPH_PROCESS_NODE processNode = (PPH_PROCESS_NODE)Node;
4084 
4085  if (processNode->ProcessItem->VerifyResult == VrTrusted)
4086  return FALSE;
4087 
4088  return TRUE;
4089 }
4090 
4092  _In_ ULONG Id,
4093  _In_ PPH_PROCESS_ITEM *Processes,
4094  _In_ ULONG NumberOfProcesses
4095  )
4096 {
4097  ULONG priorityClass;
4098 
4099  switch (Id)
4100  {
4101  case ID_PRIORITY_REALTIME:
4102  priorityClass = PROCESS_PRIORITY_CLASS_REALTIME;
4103  break;
4104  case ID_PRIORITY_HIGH:
4105  priorityClass = PROCESS_PRIORITY_CLASS_HIGH;
4106  break;
4108  priorityClass = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL;
4109  break;
4110  case ID_PRIORITY_NORMAL:
4111  priorityClass = PROCESS_PRIORITY_CLASS_NORMAL;
4112  break;
4114  priorityClass = PROCESS_PRIORITY_CLASS_BELOW_NORMAL;
4115  break;
4116  case ID_PRIORITY_IDLE:
4117  priorityClass = PROCESS_PRIORITY_CLASS_IDLE;
4118  break;
4119  default:
4120  return FALSE;
4121  }
4122 
4123  PhUiSetPriorityProcesses(PhMainWndHandle, Processes, NumberOfProcesses, priorityClass);
4124 
4125  return TRUE;
4126 }
4127 
4129  _In_ ULONG Id,
4130  _In_ PPH_PROCESS_ITEM *Processes,
4131  _In_ ULONG NumberOfProcesses
4132  )
4133 {
4134  ULONG ioPriority;
4135 
4136  switch (Id)
4137  {
4138  case ID_I_0:
4139  ioPriority = 0;
4140  break;
4141  case ID_I_1:
4142  ioPriority = 1;
4143  break;
4144  case ID_I_2:
4145  ioPriority = 2;
4146  break;
4147  case ID_I_3:
4148  ioPriority = 3;
4149  break;
4150  default:
4151  return FALSE;
4152  }
4153 
4154  PhUiSetIoPriorityProcesses(PhMainWndHandle, Processes, NumberOfProcesses, ioPriority);
4155 
4156  return TRUE;
4157 }
4158 
4160  _In_ PPH_EMENU Menu,
4161  _In_ HANDLE ProcessId,
4162  _In_ BOOLEAN SetPriority,
4163  _In_ BOOLEAN SetIoPriority,
4164  _In_ BOOLEAN SetPagePriority
4165  )
4166 {
4167  HANDLE processHandle;
4168  PROCESS_PRIORITY_CLASS priorityClass = { 0 };
4169  ULONG ioPriority = -1;
4170  ULONG pagePriority = -1;
4171  ULONG id = 0;
4172 
4174  &processHandle,
4176  ProcessId
4177  )))
4178  {
4179  if (SetPriority)
4180  {
4181  NtQueryInformationProcess(processHandle, ProcessPriorityClass, &priorityClass, sizeof(PROCESS_PRIORITY_CLASS), NULL);
4182  }
4183 
4184  if (SetIoPriority && WindowsVersion >= WINDOWS_VISTA)
4185  {
4187  processHandle,
4188  &ioPriority
4189  )))
4190  {
4191  ioPriority = -1;
4192  }
4193  }
4194 
4195  if (SetPagePriority && WindowsVersion >= WINDOWS_VISTA)
4196  {
4198  processHandle,
4199  &pagePriority
4200  )))
4201  {
4202  pagePriority = -1;
4203  }
4204  }
4205 
4206  NtClose(processHandle);
4207  }
4208 
4209  if (SetPriority)
4210  {
4211  switch (priorityClass.PriorityClass)
4212  {
4214  id = ID_PRIORITY_REALTIME;
4215  break;
4217  id = ID_PRIORITY_HIGH;
4218  break;
4221  break;
4223  id = ID_PRIORITY_NORMAL;
4224  break;
4227  break;
4229  id = ID_PRIORITY_IDLE;
4230  break;
4231  }
4232 
4233  if (id != 0)
4234  {
4235  PhSetFlagsEMenuItem(Menu, id,
4238  }
4239  }
4240 
4241  if (SetIoPriority && ioPriority != -1)
4242  {
4243  id = 0;
4244 
4245  switch (ioPriority)
4246  {
4247  case 0:
4248  id = ID_I_0;
4249  break;
4250  case 1:
4251  id = ID_I_1;
4252  break;
4253  case 2:
4254  id = ID_I_2;
4255  break;
4256  case 3:
4257  id = ID_I_3;
4258  break;
4259  }
4260 
4261  if (id != 0)
4262  {
4263  PhSetFlagsEMenuItem(Menu, id,
4266  }
4267  }
4268 
4269  if (SetPagePriority && pagePriority != -1)
4270  {
4271  id = 0;
4272 
4273  switch (pagePriority)
4274  {
4275  case 1:
4276  id = ID_PAGEPRIORITY_1;
4277  break;
4278  case 2:
4279  id = ID_PAGEPRIORITY_2;
4280  break;
4281  case 3:
4282  id = ID_PAGEPRIORITY_3;
4283  break;
4284  case 4:
4285  id = ID_PAGEPRIORITY_4;
4286  break;
4287  case 5:
4288  id = ID_PAGEPRIORITY_5;
4289  break;
4290  }
4291 
4292  if (id != 0)
4293  {
4294  PhSetFlagsEMenuItem(Menu, id,
4297  }
4298  }
4299 }
4300 
4302  _In_ PPH_EMENU Menu,
4303  _In_ PPH_PROCESS_ITEM *Processes,
4304  _In_ ULONG NumberOfProcesses
4305  )
4306 {
4307  PPH_EMENU_ITEM item;
4308 
4309  if (NumberOfProcesses == 0)
4310  {
4312  }
4313  else if (NumberOfProcesses == 1)
4314  {
4315  // All menu items are enabled by default.
4316 
4317  // If the user selected a fake process, disable all but
4318  // a few menu items.
4319  if (PH_IS_FAKE_PROCESS_ID(Processes[0]->ProcessId))
4320  {
4324  }
4325  }
4326  else
4327  {
4328  ULONG menuItemsMultiEnabled[] =
4329  {
4335  };
4336  ULONG i;
4337 
4339 
4340  // Enable the Miscellaneous menu item but disable its children.
4341  if (item = PhFindEMenuItem(Menu, 0, L"Miscellaneous", 0))
4342  {
4343  item->Flags &= ~PH_EMENU_DISABLED;
4345  }
4346 
4347  // Enable the Priority menu item.
4348  if (item = PhFindEMenuItem(Menu, 0, L"Priority", 0))
4349  item->Flags &= ~PH_EMENU_DISABLED;
4350 
4351  // Enable the I/O Priority menu item.
4352  if (item = PhFindEMenuItem(Menu, 0, L"I/O Priority", 0))
4353  item->Flags &= ~PH_EMENU_DISABLED;
4354 
4355  // These menu items are capable of manipulating
4356  // multiple processes.
4357  for (i = 0; i < sizeof(menuItemsMultiEnabled) / sizeof(ULONG); i++)
4358  {
4359  PhSetFlagsEMenuItem(Menu, menuItemsMultiEnabled[i], PH_EMENU_DISABLED, 0);
4360  }
4361  }
4362 
4363  // Remove irrelevant menu items.
4365  {
4366  // Remove I/O priority.
4367  if (item = PhFindEMenuItem(Menu, PH_EMENU_FIND_DESCEND, L"I/O Priority", 0))
4368  PhDestroyEMenuItem(item);
4369  // Remove page priority.
4370  if (item = PhFindEMenuItem(Menu, PH_EMENU_FIND_DESCEND, L"Page Priority", 0))
4371  PhDestroyEMenuItem(item);
4372  }
4373 
4374  // Suspend/Resume
4375  if (NumberOfProcesses == 1)
4376  {
4377  if (Processes[0]->IsSuspended)
4378  {
4379  if (item = PhFindEMenuItem(Menu, 0, NULL, ID_PROCESS_SUSPEND))
4380  PhDestroyEMenuItem(item);
4381  }
4382 
4383  if (!Processes[0]->IsPartiallySuspended)
4384  {
4385  if (item = PhFindEMenuItem(Menu, 0, NULL, ID_PROCESS_RESUME))
4386  PhDestroyEMenuItem(item);
4387  }
4388  }
4389 
4390  // Virtualization
4391  if (NumberOfProcesses == 1)
4392  {
4393  HANDLE processHandle;
4394  HANDLE tokenHandle;
4395  BOOLEAN allowed = FALSE;
4396  BOOLEAN enabled = FALSE;
4397 
4399  &processHandle,
4401  Processes[0]->ProcessId
4402  )))
4403  {
4405  &tokenHandle,
4406  TOKEN_QUERY,
4407  processHandle
4408  )))
4409  {
4410  PhGetTokenIsVirtualizationAllowed(tokenHandle, &allowed);
4411  PhGetTokenIsVirtualizationEnabled(tokenHandle, &enabled);
4412  SelectedProcessVirtualizationEnabled = enabled;
4413 
4414  NtClose(tokenHandle);
4415  }
4416 
4417  NtClose(processHandle);
4418  }
4419 
4420  if (!allowed)
4422  else if (enabled)
4424  }
4425 
4426  // Priority
4427  if (NumberOfProcesses == 1)
4428  {
4429  PhMwpSetProcessMenuPriorityChecks(Menu, Processes[0]->ProcessId, TRUE, TRUE, TRUE);
4430  }
4431 
4432  item = PhFindEMenuItem(Menu, 0, L"Window", 0);
4433 
4434  if (item)
4435  {
4436  // Window menu
4437  if (NumberOfProcesses == 1)
4438  {
4439  WINDOWPLACEMENT placement = { sizeof(placement) };
4440 
4441  // Get a handle to the process' top-level window (if any).
4442  SelectedProcessWindowHandle = PhGetProcessMainWindow(Processes[0]->ProcessId, Processes[0]->QueryHandle);
4443 
4444  if (!SelectedProcessWindowHandle)
4445  item->Flags |= PH_EMENU_DISABLED;
4446 
4447  GetWindowPlacement(SelectedProcessWindowHandle, &placement);
4448 
4449  if (placement.showCmd == SW_MINIMIZE)
4451  else if (placement.showCmd == SW_MAXIMIZE)
4453  else if (placement.showCmd == SW_NORMAL)
4455  }
4456  else
4457  {
4458  item->Flags |= PH_EMENU_DISABLED;
4459  }
4460  }
4461 
4462  // Remove irrelevant menu items (continued)
4463  if (!WINDOWS_HAS_UAC)
4464  {
4465  if (item = PhFindEMenuItem(Menu, 0, NULL, ID_PROCESS_VIRTUALIZATION))
4466  PhDestroyEMenuItem(item);
4467  }
4468 }
4469 
4471  _In_ PPH_TREENEW_CONTEXT_MENU ContextMenu
4472  )
4473 {
4474  PH_PLUGIN_MENU_INFORMATION menuInfo;
4475  PPH_PROCESS_ITEM *processes;
4476  ULONG numberOfProcesses;
4477 
4478  PhGetSelectedProcessItems(&processes, &numberOfProcesses);
4479 
4480  if (numberOfProcesses != 0)
4481  {
4482  PPH_EMENU menu;
4483  PPH_EMENU_ITEM item;
4484 
4485  menu = PhCreateEMenu();
4486  PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_PROCESS), 0);
4488 
4489  PhMwpInitializeProcessMenu(menu, processes, numberOfProcesses);
4490  PhInsertCopyCellEMenuItem(menu, ID_PROCESS_COPY, ProcessTreeListHandle, ContextMenu->Column);
4491 
4492  if (PhPluginsEnabled)
4493  {
4494  PhPluginInitializeMenuInfo(&menuInfo, menu, PhMainWndHandle, 0);
4495  menuInfo.u.Process.Processes = processes;
4496  menuInfo.u.Process.NumberOfProcesses = numberOfProcesses;
4497 
4499  }
4500 
4501  item = PhShowEMenu(
4502  menu,
4506  ContextMenu->Location.x,
4507  ContextMenu->Location.y
4508  );
4509 
4510  if (item)
4511  {
4512  BOOLEAN handled = FALSE;
4513 
4514  handled = PhHandleCopyCellEMenuItem(item);
4515 
4516  if (!handled && PhPluginsEnabled)
4517  handled = PhPluginTriggerEMenuItem(&menuInfo, item);
4518 
4519  if (!handled)
4520  SendMessage(PhMainWndHandle, WM_COMMAND, item->Id, 0);
4521  }
4522 
4523  PhDestroyEMenu(menu);
4524  }
4525 
4526  PhFree(processes);
4527 }
4528 
4530  _In_ _Assume_refs_(1) PPH_PROCESS_ITEM ProcessItem,
4531  _In_ ULONG RunId
4532  )
4533 {
4534  PPH_PROCESS_NODE processNode;
4535 
4536  if (!ProcessesNeedsRedraw)
4537  {
4538  TreeNew_SetRedraw(ProcessTreeListHandle, FALSE);
4539  ProcessesNeedsRedraw = TRUE;
4540  }
4541 
4542  processNode = PhAddProcessNode(ProcessItem, RunId);
4543 
4544  if (RunId != 1)
4545  {
4546  PPH_PROCESS_ITEM parentProcess;
4547  HANDLE parentProcessId = NULL;
4548  PPH_STRING parentName = NULL;
4549 
4550  if (parentProcess = PhReferenceProcessItemForParent(
4551  ProcessItem->ParentProcessId,
4552  ProcessItem->ProcessId,
4553  &ProcessItem->CreateTime
4554  ))
4555  {
4556  parentProcessId = parentProcess->ProcessId;
4557  parentName = parentProcess->ProcessName;
4558  }
4559 
4562  ProcessItem->ProcessId,
4563  ProcessItem->ProcessName,
4564  parentProcessId,
4565  parentName
4566  );
4567 
4568  if (NotifyIconNotifyMask & PH_NOTIFY_PROCESS_CREATE)
4569  {
4570  if (!PhPluginsEnabled || !PhMwpPluginNotifyEvent(PH_NOTIFY_PROCESS_CREATE, ProcessItem))
4571  {
4573  LastNotificationType = PH_NOTIFY_PROCESS_CREATE;
4574  LastNotificationDetails.ProcessId = ProcessItem->ProcessId;
4575 
4576  PhShowIconNotification(L"Process Created", PhaFormatString(
4577  L"The process %s (%u) was created by %s (%u)",
4578  ProcessItem->ProcessName->Buffer,
4579  (ULONG)ProcessItem->ProcessId,
4580  PhGetStringOrDefault(parentName, L"Unknown Process"),
4581  (ULONG)ProcessItem->ParentProcessId
4582  )->Buffer, NIIF_INFO);
4583  }
4584  }
4585 
4586  if (parentProcess)
4587  PhDereferenceObject(parentProcess);
4588 
4590  ProcessToScrollTo = processNode;
4591  }
4592  else
4593  {
4594  if (NeedsSelectPid != 0)
4595  {
4596  if (processNode->ProcessId == UlongToHandle(NeedsSelectPid))
4597  ProcessToScrollTo = processNode;
4598  }
4599  }
4600 
4601  // PhCreateProcessNode has its own reference.
4602  PhDereferenceObject(ProcessItem);
4603 }
4604 
4606  _In_ PPH_PROCESS_ITEM ProcessItem
4607  )
4608 {
4609  PhUpdateProcessNode(PhFindProcessNode(ProcessItem->ProcessId));
4610 
4611  if (SignedFilterEntry)
4613 }
4614 
4616  _In_ PPH_PROCESS_ITEM ProcessItem
4617  )
4618 {
4619  PPH_PROCESS_NODE processNode;
4620 
4621  if (!ProcessesNeedsRedraw)
4622  {
4623  TreeNew_SetRedraw(ProcessTreeListHandle, FALSE);
4624  ProcessesNeedsRedraw = TRUE;
4625  }
4626 
4627  PhLogProcessEntry(PH_LOG_ENTRY_PROCESS_DELETE, ProcessItem->ProcessId, ProcessItem->ProcessName, NULL, NULL);
4628 
4629  if (NotifyIconNotifyMask & PH_NOTIFY_PROCESS_DELETE)
4630  {
4631  if (!PhPluginsEnabled || !PhMwpPluginNotifyEvent(PH_NOTIFY_PROCESS_DELETE, ProcessItem))
4632  {
4634  LastNotificationType = PH_NOTIFY_PROCESS_DELETE;
4635  LastNotificationDetails.ProcessId = ProcessItem->ProcessId;
4636 
4637  PhShowIconNotification(L"Process Terminated", PhaFormatString(
4638  L"The process %s (%u) was terminated.",
4639  ProcessItem->ProcessName->Buffer,
4640  (ULONG)ProcessItem->ProcessId
4641  )->Buffer, NIIF_INFO);
4642  }
4643  }
4644 
4645  processNode = PhFindProcessNode(ProcessItem->ProcessId);
4646  PhRemoveProcessNode(processNode);
4647 
4648  if (ProcessToScrollTo == processNode) // shouldn't happen, but just in case
4649  ProcessToScrollTo = NULL;
4650 }
4651 
4653  VOID
4654  )
4655 {
4656  // The modified notification is only sent for special cases.
4657  // We have to invalidate the text on each update.
4659 
4660  if (PhPluginsEnabled)
4661  {
4663  }
4664 
4665  if (ProcessesNeedsRedraw)
4666  {
4667  TreeNew_SetRedraw(ProcessTreeListHandle, TRUE);
4668  ProcessesNeedsRedraw = FALSE;
4669  }
4670 
4671  if (NeedsSelectPid != 0)
4672  {
4673  if (ProcessToScrollTo)
4674  {
4675  PhSelectAndEnsureVisibleProcessNode(ProcessToScrollTo);
4676  ProcessToScrollTo = NULL;
4677  }
4678 
4679  NeedsSelectPid = 0;
4680  }
4681 
4682  if (ProcessToScrollTo)
4683  {
4684  TreeNew_EnsureVisible(ProcessTreeListHandle, &ProcessToScrollTo->Node);
4685  ProcessToScrollTo = NULL;
4686  }
4687 }
4688 
4690  VOID
4691  )
4692 {
4693  if (!ServiceTreeListLoaded)
4694  {
4695  ServiceTreeListLoaded = TRUE;
4696 
4698 
4699  if (PhGetIntegerSetting(L"HideDriverServices"))
4700  {
4702  }
4703 
4704  if (ServicesPendingList)
4705  {
4706  PPH_SERVICE_ITEM serviceItem;
4707  ULONG enumerationKey = 0;
4708 
4709  while (PhEnumPointerList(ServicesPendingList, &enumerationKey, (PVOID *)&serviceItem))
4710  {
4711  PhMwpOnServiceAdded(serviceItem, 1);
4712  }
4713 
4714  // Force a re-draw.
4716 
4717  PhClearReference(&ServicesPendingList);
4718  }
4719  }
4720 }
4721 
4723  _In_ PPH_TREENEW_NODE Node,
4724  _In_opt_ PVOID Context
4725  )
4726 {
4727  PPH_SERVICE_NODE serviceNode = (PPH_SERVICE_NODE)Node;
4728 
4729  if (serviceNode->ServiceItem->Type & SERVICE_DRIVER)
4730  return FALSE;
4731 
4732  return TRUE;
4733 }
4734 
4736  _In_ PPH_EMENU Menu,
4737  _In_ PPH_SERVICE_ITEM *Services,
4738  _In_ ULONG NumberOfServices
4739  )
4740 {
4741  if (NumberOfServices == 0)
4742  {
4744  }
4745  else if (NumberOfServices == 1)
4746  {
4747  if (!Services[0]->ProcessId)
4749  }
4750  else
4751  {
4754  }
4755 
4756  if (NumberOfServices == 1)
4757  {
4758  switch (Services[0]->State)
4759  {
4760  case SERVICE_RUNNING:
4761  {
4765  Services[0]->ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE);
4767  Services[0]->ControlsAccepted & SERVICE_ACCEPT_STOP);
4768  }
4769  break;
4770  case SERVICE_PAUSED:
4771  {
4774  Services[0]->ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE);
4777  Services[0]->ControlsAccepted & SERVICE_ACCEPT_STOP);
4778  }
4779  break;
4780  case SERVICE_STOPPED:
4781  {
4785  }
4786  break;
4787  case SERVICE_START_PENDING:
4788  case SERVICE_CONTINUE_PENDING:
4789  case SERVICE_PAUSE_PENDING:
4790  case SERVICE_STOP_PENDING:
4791  {
4796  }
4797  break;
4798  }
4799 
4800  if (!(Services[0]->ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE))
4801  {
4802  PPH_EMENU_ITEM item;
4803 
4804  if (item = PhFindEMenuItem(Menu, 0, NULL, ID_SERVICE_CONTINUE))
4805  PhDestroyEMenuItem(item);
4806  if (item = PhFindEMenuItem(Menu, 0, NULL, ID_SERVICE_PAUSE))
4807  PhDestroyEMenuItem(item);
4808  }
4809  }
4810 }
4811 
4813  _In_ PPH_TREENEW_CONTEXT_MENU ContextMenu
4814  )
4815 {
4816  PH_PLUGIN_MENU_INFORMATION menuInfo;
4817  PPH_SERVICE_ITEM *services;
4818  ULONG numberOfServices;
4819 
4820  PhGetSelectedServiceItems(&services, &numberOfServices);
4821 
4822  if (numberOfServices != 0)
4823  {
4824  PPH_EMENU menu;
4825  PPH_EMENU_ITEM item;
4826 
4827  menu = PhCreateEMenu();
4828  PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_SERVICE), 0);
4830 
4831  PhMwpInitializeServiceMenu(menu, services, numberOfServices);
4832  PhInsertCopyCellEMenuItem(menu, ID_SERVICE_COPY, ServiceTreeListHandle, ContextMenu->Column);
4833 
4834  if (PhPluginsEnabled)
4835  {
4836  PhPluginInitializeMenuInfo(&menuInfo, menu, PhMainWndHandle, 0);
4837  menuInfo.u.Service.Services = services;
4838  menuInfo.u.Service.NumberOfServices = numberOfServices;
4839 
4841  }
4842 
4843  item = PhShowEMenu(
4844  menu,
4848  ContextMenu->Location.x,
4849  ContextMenu->Location.y
4850  );
4851 
4852  if (item)
4853  {
4854  BOOLEAN handled = FALSE;
4855 
4856  handled = PhHandleCopyCellEMenuItem(item);
4857 
4858  if (!handled && PhPluginsEnabled)
4859  handled = PhPluginTriggerEMenuItem(&menuInfo, item);
4860 
4861  if (!handled)
4862  SendMessage(PhMainWndHandle, WM_COMMAND, item->Id, 0);
4863  }
4864 
4865  PhDestroyEMenu(menu);
4866  }
4867 
4868  PhFree(services);
4869 }
4870 
4872  _In_ _Assume_refs_(1) PPH_SERVICE_ITEM ServiceItem,
4873  _In_ ULONG RunId
4874  )
4875 {
4876  PPH_SERVICE_NODE serviceNode;
4877 
4878  if (ServiceTreeListLoaded)
4879  {
4880  if (!ServicesNeedsRedraw)
4881  {
4882  TreeNew_SetRedraw(ServiceTreeListHandle, FALSE);
4883  ServicesNeedsRedraw = TRUE;
4884  }
4885 
4886  serviceNode = PhAddServiceNode(ServiceItem, RunId);
4887  // ServiceItem dereferenced below
4888  }
4889  else
4890  {
4891  if (!ServicesPendingList)
4892  ServicesPendingList = PhCreatePointerList(100);
4893 
4894  PhAddItemPointerList(ServicesPendingList, ServiceItem);
4895  }
4896 
4897  if (RunId != 1)
4898  {
4899  PhLogServiceEntry(PH_LOG_ENTRY_SERVICE_CREATE, ServiceItem->Name, ServiceItem->DisplayName);
4900 
4901  if (NotifyIconNotifyMask & PH_NOTIFY_SERVICE_CREATE)
4902  {
4903  if (!PhPluginsEnabled || !PhMwpPluginNotifyEvent(PH_NOTIFY_SERVICE_CREATE, ServiceItem))
4904  {
4906  LastNotificationType = PH_NOTIFY_SERVICE_CREATE;
4907  PhSwapReference(&LastNotificationDetails.ServiceName, ServiceItem->Name);
4908 
4909  PhShowIconNotification(L"Service Created", PhaFormatString(
4910  L"The service %s (%s) has been created.",
4911  ServiceItem->Name->Buffer,
4912  ServiceItem->DisplayName->Buffer
4913  )->Buffer, NIIF_INFO);
4914  }
4915  }
4916  }
4917 
4918  if (ServiceTreeListLoaded)
4919  PhDereferenceObject(ServiceItem);
4920 }
4921 
4923  _In_ PPH_SERVICE_MODIFIED_DATA ServiceModifiedData
4924  )
4925 {
4926  PH_SERVICE_CHANGE serviceChange;
4927  UCHAR logEntryType;
4928 
4929  if (ServiceTreeListLoaded)
4930  {
4931  //if (!ServicesNeedsRedraw)
4932  //{
4933  // TreeNew_SetRedraw(ServiceTreeListHandle, FALSE);
4934  // ServicesNeedsRedraw = TRUE;
4935  //}
4936 
4937  PhUpdateServiceNode(PhFindServiceNode(ServiceModifiedData->Service));
4938 
4939  if (DriverFilterEntry)
4941  }
4942 
4943  serviceChange = PhGetServiceChange(ServiceModifiedData);
4944 
4945  switch (serviceChange)
4946  {
4947  case ServiceStarted:
4948  logEntryType = PH_LOG_ENTRY_SERVICE_START;
4949  break;
4950  case ServiceStopped:
4951  logEntryType = PH_LOG_ENTRY_SERVICE_STOP;
4952  break;
4953  case ServiceContinued:
4954  logEntryType = PH_LOG_ENTRY_SERVICE_CONTINUE;
4955  break;
4956  case ServicePaused:
4957  logEntryType = PH_LOG_ENTRY_SERVICE_PAUSE;
4958  break;
4959  default:
4960  logEntryType = 0;
4961  break;
4962  }
4963 
4964  if (logEntryType != 0)
4965  PhLogServiceEntry(logEntryType, ServiceModifiedData->Service->Name, ServiceModifiedData->Service->DisplayName);
4966 
4967  if (NotifyIconNotifyMask & (PH_NOTIFY_SERVICE_START | PH_NOTIFY_SERVICE_STOP))
4968  {
4969  PPH_SERVICE_ITEM serviceItem;
4970 
4971  serviceItem = ServiceModifiedData->Service;
4972 
4973  if (serviceChange == ServiceStarted && (NotifyIconNotifyMask & PH_NOTIFY_SERVICE_START))
4974  {
4975  if (!PhPluginsEnabled || !PhMwpPluginNotifyEvent(PH_NOTIFY_SERVICE_START, serviceItem))
4976  {
4978  LastNotificationType = PH_NOTIFY_SERVICE_START;
4979  PhSwapReference(&LastNotificationDetails.ServiceName, serviceItem->Name);
4980 
4981  PhShowIconNotification(L"Service Started", PhaFormatString(
4982  L"The service %s (%s) has been started.",
4983  serviceItem->Name->Buffer,
4984  serviceItem->DisplayName->Buffer
4985  )->Buffer, NIIF_INFO);
4986  }
4987  }
4988  else if (serviceChange == ServiceStopped && (NotifyIconNotifyMask & PH_NOTIFY_SERVICE_STOP))
4989  {
4991  LastNotificationType = PH_NOTIFY_SERVICE_STOP;
4992  PhSwapReference(&LastNotificationDetails.ServiceName, serviceItem->Name);
4993 
4994  if (!PhPluginsEnabled || !PhMwpPluginNotifyEvent(PH_NOTIFY_SERVICE_STOP, serviceItem))
4995  {
4996  PhShowIconNotification(L"Service Stopped", PhaFormatString(
4997  L"The service %s (%s) has been stopped.",
4998  serviceItem->Name->Buffer,
4999  serviceItem->DisplayName->Buffer
5000  )->Buffer, NIIF_INFO);
5001  }
5002  }
5003  }
5004 }
5005 
5007  _In_ PPH_SERVICE_ITEM ServiceItem
5008  )
5009 {
5010  if (ServiceTreeListLoaded)
5011  {
5012  if (!ServicesNeedsRedraw)
5013  {
5014  TreeNew_SetRedraw(ServiceTreeListHandle, FALSE);
5015  ServicesNeedsRedraw = TRUE;
5016  }
5017  }
5018 
5019  PhLogServiceEntry(PH_LOG_ENTRY_SERVICE_DELETE, ServiceItem->Name, ServiceItem->DisplayName);
5020 
5021  if (NotifyIconNotifyMask & PH_NOTIFY_SERVICE_CREATE)
5022  {
5024  {
5026  LastNotificationType = PH_NOTIFY_SERVICE_DELETE;
5027  PhSwapReference(&LastNotificationDetails.ServiceName, ServiceItem->Name);
5028 
5029  PhShowIconNotification(L"Service Deleted", PhaFormatString(
5030  L"The service %s (%s) has been deleted.",
5031  ServiceItem->Name->Buffer,
5032  ServiceItem->DisplayName->Buffer
5033  )->Buffer, NIIF_INFO);
5034  }
5035  }
5036 
5037  if (ServiceTreeListLoaded)
5038  {
5039  PhRemoveServiceNode(PhFindServiceNode(ServiceItem));
5040  }
5041  else
5042  {
5043  if (ServicesPendingList)
5044  {
5045  HANDLE pointerHandle;
5046 
5047  // Remove the service from the pending list so we don't try to add it
5048  // later.
5049 
5050  if (pointerHandle = PhFindItemPointerList(ServicesPendingList, ServiceItem))
5051  PhRemoveItemPointerList(ServicesPendingList, pointerHandle);
5052 
5053  PhDereferenceObject(ServiceItem);
5054  }
5055  }
5056 }
5057 
5059  VOID
5060  )
5061 {
5062  if (ServiceTreeListLoaded)
5063  {
5065 
5066  if (ServicesNeedsRedraw)
5067  {
5068  TreeNew_SetRedraw(ServiceTreeListHandle, TRUE);
5069  ServicesNeedsRedraw = FALSE;
5070  }
5071  }
5072 }
5073 
5075  VOID
5076  )
5077 {
5078  if (!NetworkTreeListLoaded)
5079  {
5080  NetworkTreeListLoaded = TRUE;
5081 
5083  }
5084 }
5085 
5087  _In_ PPH_TREENEW_NODE Node,
5088  _In_opt_ PVOID Context
5089  )
5090 {
5091  PPH_NETWORK_NODE networkNode = (PPH_NETWORK_NODE)Node;
5092  PPH_PROCESS_NODE processNode;
5093 
5094  processNode = PhFindProcessNode(networkNode->NetworkItem->ProcessId);
5095 
5096  if (processNode)
5097  return PhMwpCurrentUserProcessTreeFilter(&processNode->Node, NULL);
5098 
5099  return TRUE;
5100 }
5101 
5103  _In_ PPH_TREENEW_NODE Node,
5104  _In_opt_ PVOID Context
5105  )
5106 {
5107  PPH_NETWORK_NODE networkNode = (PPH_NETWORK_NODE)Node;
5108  PPH_PROCESS_NODE processNode;
5109 
5110  processNode = PhFindProcessNode(networkNode->NetworkItem->ProcessId);
5111 
5112  if (processNode)
5113  return PhMwpSignedProcessTreeFilter(&processNode->Node, NULL);
5114 
5115  return TRUE;
5116 }
5117 
5119  _In_ PPH_EMENU Menu,
5120  _In_ PPH_NETWORK_ITEM *NetworkItems,
5121  _In_ ULONG NumberOfNetworkItems
5122  )
5123 {
5124  ULONG i;
5125  PPH_EMENU_ITEM item;
5126 
5127  if (NumberOfNetworkItems == 0)
5128  {
5130  }
5131  else if (NumberOfNetworkItems == 1)
5132  {
5133  if (!NetworkItems[0]->ProcessId)
5135  }
5136  else
5137  {
5141  }
5142 
5144  {
5145  if (item = PhFindEMenuItem(Menu, 0, NULL, ID_NETWORK_VIEWSTACK))
5146  PhDestroyEMenuItem(item);
5147  }
5148 
5149  // Go to Service
5150  if (NumberOfNetworkItems != 1 || !NetworkItems[0]->OwnerName)
5151  {
5152  if (item = PhFindEMenuItem(Menu, 0, NULL, ID_NETWORK_GOTOSERVICE))
5153  PhDestroyEMenuItem(item);
5154  }
5155 
5156  // Close
5157  if (NumberOfNetworkItems != 0)
5158  {
5159  BOOLEAN closeOk = TRUE;
5160 
5161  for (i = 0; i < NumberOfNetworkItems; i++)
5162  {
5163  if (
5164  NetworkItems[i]->ProtocolType != PH_TCP4_NETWORK_PROTOCOL ||
5165  NetworkItems[i]->State != MIB_TCP_STATE_ESTAB
5166  )
5167  {
5168  closeOk = FALSE;
5169  break;
5170  }
5171  }
5172 
5173  if (!closeOk)
5175  }
5176 }
5177 
5179  _In_ PPH_TREENEW_CONTEXT_MENU ContextMenu
5180  )
5181 {
5182  PH_PLUGIN_MENU_INFORMATION menuInfo;
5183  PPH_NETWORK_ITEM *networkItems;
5184  ULONG numberOfNetworkItems;
5185 
5186  PhGetSelectedNetworkItems(&networkItems, &numberOfNetworkItems);
5187 
5188  if (numberOfNetworkItems != 0)
5189  {
5190  PPH_EMENU menu;
5191  PPH_EMENU_ITEM item;
5192 
5193  menu = PhCreateEMenu();
5194  PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_NETWORK), 0);
5196 
5197  PhMwpInitializeNetworkMenu(menu, networkItems, numberOfNetworkItems);
5198  PhInsertCopyCellEMenuItem(menu, ID_NETWORK_COPY, NetworkTreeListHandle, ContextMenu->Column);
5199 
5200  if (PhPluginsEnabled)
5201  {
5202  PhPluginInitializeMenuInfo(&menuInfo, menu, PhMainWndHandle, 0);
5203  menuInfo.u.Network.NetworkItems = networkItems;
5204  menuInfo.u.Network.NumberOfNetworkItems = numberOfNetworkItems;
5205 
5207  }
5208 
5209  item = PhShowEMenu(
5210  menu,
5214  ContextMenu->Location.x,
5215  ContextMenu->Location.y
5216  );
5217 
5218  if (item)
5219  {
5220  BOOLEAN handled = FALSE;
5221 
5222  handled = PhHandleCopyCellEMenuItem(item);
5223 
5224  if (!handled && PhPluginsEnabled)
5225  handled = PhPluginTriggerEMenuItem(&menuInfo, item);
5226 
5227  if (!handled)
5228  SendMessage(PhMainWndHandle, WM_COMMAND, item->Id, 0);
5229  }
5230 
5231  PhDestroyEMenu(menu);
5232  }
5233 
5234  PhFree(networkItems);
5235 }
5236 
5238  _In_ ULONG RunId,
5239  _In_ _Assume_refs_(1) PPH_NETWORK_ITEM NetworkItem
5240  )
5241 {
5242  PPH_NETWORK_NODE networkNode;
5243 
5244  if (!NetworkNeedsRedraw)
5245  {
5246  TreeNew_SetRedraw(NetworkTreeListHandle, FALSE);
5247  NetworkNeedsRedraw = TRUE;
5248  }
5249 
5250  networkNode = PhAddNetworkNode(NetworkItem, RunId);
5251  PhDereferenceObject(NetworkItem);
5252 }
5253 
5255  _In_ PPH_NETWORK_ITEM NetworkItem
5256  )
5257 {
5258  PhUpdateNetworkNode(PhFindNetworkNode(NetworkItem));
5259 }
5260 
5262  _In_ PPH_NETWORK_ITEM NetworkItem
5263  )
5264 {
5265  if (!NetworkNeedsRedraw)
5266  {
5267  TreeNew_SetRedraw(NetworkTreeListHandle, FALSE);
5268  NetworkNeedsRedraw = TRUE;
5269  }
5270 
5271  PhRemoveNetworkNode(PhFindNetworkNode(NetworkItem));
5272 }
5273 
5275  VOID
5276  )
5277 {
5279 
5280  if (NetworkNeedsRedraw)
5281  {
5282  TreeNew_SetRedraw(NetworkTreeListHandle, TRUE);
5283  NetworkNeedsRedraw = FALSE;
5284  }
5285 }
5286 
5288  VOID
5289  )
5290 {
5291  HMENU menu;
5292  PSESSIONIDW sessions;
5293  ULONG numberOfSessions;
5294  ULONG i;
5295  ULONG j;
5296  MENUITEMINFO menuItemInfo = { sizeof(MENUITEMINFO) };
5297 
5298  menu = SubMenuHandles[3];
5299 
5300  // Delete all items in the Users menu.
5301  while (DeleteMenu(menu, 0, MF_BYPOSITION)) ;
5302 
5303  if (WinStationEnumerateW(NULL, &sessions, &numberOfSessions))
5304  {
5305  for (i = 0; i < numberOfSessions; i++)
5306  {
5307  HMENU userMenu;
5308  PPH_STRING menuText;
5309  PPH_STRING escapedMenuText;
5310  WINSTATIONINFORMATION winStationInfo;
5311  ULONG returnLength;
5312  ULONG numberOfItems;
5313 
5315  NULL,
5316  sessions[i].SessionId,
5318  &winStationInfo,
5319  sizeof(WINSTATIONINFORMATION),
5320  &returnLength
5321  ))
5322  {
5323  winStationInfo.Domain[0] = 0;
5324  winStationInfo.UserName[0] = 0;
5325  }
5326 
5327  if (winStationInfo.Domain[0] == 0 || winStationInfo.UserName[0] == 0)
5328  {
5329  // Probably the Services or RDP-Tcp session.
5330  continue;
5331  }
5332 
5333  menuText = PhFormatString(
5334  L"%u: %s\\%s",
5335  sessions[i].SessionId,
5336  winStationInfo.Domain,
5337  winStationInfo.UserName
5338  );
5339  escapedMenuText = PhEscapeStringForMenuPrefix(&menuText->sr);
5340  PhDereferenceObject(menuText);
5341 
5342  userMenu = GetSubMenu(LoadMenu(PhInstanceHandle, MAKEINTRESOURCE(IDR_USER)), 0);
5343  AppendMenu(
5344  menu,
5345  MF_STRING | MF_POPUP,
5346  (UINT_PTR)userMenu,
5347  escapedMenuText->Buffer
5348  );
5349 
5350  PhDereferenceObject(escapedMenuText);
5351 
5352  menuItemInfo.fMask = MIIM_DATA;
5353  menuItemInfo.dwItemData = sessions[i].SessionId;
5354 
5355  numberOfItems = GetMenuItemCount(userMenu);
5356 
5357  if (numberOfItems != -1)
5358  {
5359  for (j = 0; j < numberOfItems; j++)
5360  SetMenuItemInfo(userMenu, j, TRUE, &menuItemInfo);
5361  }
5362  }
5363 
5364  WinStationFreeMemory(sessions);
5365  }
5366 
5367  DrawMenuBar(PhMainWndHandle);
5368 }