Process Hacker
main.c
Go to the documentation of this file.
1 /*
2  * Process Hacker ToolStatus -
3  * main program
4  *
5  * Copyright (C) 2011-2015 dmex
6  * Copyright (C) 2010-2013 wj32
7  *
8  * This file is part of Process Hacker.
9  *
10  * Process Hacker is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * Process Hacker is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
22  */
23 
24 #include "toolstatus.h"
25 
27  VOID
28  );
29 
31  _In_ INT TabIndex,
32  _In_ PWSTR BannerText
33  );
34 
36  _In_ INT TabIndex
37  );
38 
43 BOOLEAN EnableToolBar = FALSE;
49 HWND RebarHandle = NULL;
50 HWND ToolBarHandle = NULL;
51 HWND SearchboxHandle = NULL;
52 HACCEL AcceleratorTable = NULL;
54 PH_CALLBACK_DECLARE(SearchChangedEvent);
61 {
66  &SearchChangedEvent,
68 };
69 
70 static ULONG TargetingMode = 0;
71 static BOOLEAN TargetingWindow = FALSE;
72 static BOOLEAN TargetingCurrentWindowDraw = FALSE;
73 static BOOLEAN TargetingCompleted = FALSE;
74 static HWND TargetingCurrentWindow = NULL;
79 static PH_CALLBACK_REGISTRATION LayoutPaddingCallbackRegistration;
80 static PH_CALLBACK_REGISTRATION TabPageCallbackRegistration;
84 
86  VOID
87  )
88 {
89  return SearchboxText;
90 }
91 
92 static VOID NTAPI ProcessesUpdatedCallback(
93  _In_opt_ PVOID Parameter,
94  _In_opt_ PVOID Context
95  )
96 {
98 
99  if (EnableStatusBar)
100  UpdateStatusBar();
101 }
102 
104  _In_opt_ PVOID Parameter,
105  _In_opt_ PVOID Context
106  )
107 {
108  *(HWND *)Context = ((PPH_PLUGIN_TREENEW_INFORMATION)Parameter)->TreeNewHandle;
109 }
110 
112  _In_ INT TabIndex,
113  _In_ PWSTR BannerText
114  )
115 {
116  PTOOLSTATUS_TAB_INFO tabInfo;
117 
118  tabInfo = RegisterTabInfo(TabIndex);
119  tabInfo->BannerText = BannerText;
120 }
121 
123  _In_ INT TabIndex
124  )
125 {
126  PTOOLSTATUS_TAB_INFO tabInfoCopy;
127  PVOID *entry;
128 
129  tabInfoCopy = PhCreateAlloc(sizeof(TOOLSTATUS_TAB_INFO));
130  memset(tabInfoCopy, 0, sizeof(TOOLSTATUS_TAB_INFO));
131 
132  if (!PhAddItemSimpleHashtable(TabInfoHashtable, (PVOID)TabIndex, tabInfoCopy))
133  {
134  PhClearReference(&tabInfoCopy);
135 
136  if (entry = PhFindItemSimpleHashtable(TabInfoHashtable, (PVOID)TabIndex))
137  tabInfoCopy = *entry;
138  }
139 
140  return tabInfoCopy;
141 }
142 
144  _In_ INT TabIndex
145  )
146 {
147  PVOID *entry;
148 
149  if (entry = PhFindItemSimpleHashtable(TabInfoHashtable, (PVOID)TabIndex))
150  return *entry;
151  else
152  return NULL;
153 }
154 
156  VOID
157  )
158 {
159  HWND treeNewHandle = NULL;
160 
161  switch (SelectedTabIndex)
162  {
163  case 0:
164  treeNewHandle = ProcessTreeNewHandle;
165  break;
166  case 1:
167  treeNewHandle = ServiceTreeNewHandle;
168  break;
169  case 2:
170  treeNewHandle = NetworkTreeNewHandle;
171  break;
172  default:
173  {
174  PTOOLSTATUS_TAB_INFO tabInfo;
175 
176  if ((tabInfo = FindTabInfo(SelectedTabIndex)) && tabInfo->GetTreeNewHandle)
177  {
178  treeNewHandle = tabInfo->GetTreeNewHandle();
179  }
180  }
181  break;
182  }
183 
184  return treeNewHandle;
185 }
186 
187 static VOID NTAPI TabPageUpdatedCallback(
188  _In_opt_ PVOID Parameter,
189  _In_opt_ PVOID Context
190  )
191 {
192  INT tabIndex = (INT)Parameter;
193 
194  SelectedTabIndex = tabIndex;
195 
196  if (!SearchboxHandle)
197  return;
198 
199  switch (tabIndex)
200  {
201  case 0:
202  Edit_SetCueBannerText(SearchboxHandle, L"Search Processes (Ctrl+K)");
203  break;
204  case 1:
205  Edit_SetCueBannerText(SearchboxHandle, L"Search Services (Ctrl+K)");
206  break;
207  case 2:
208  Edit_SetCueBannerText(SearchboxHandle, L"Search Network (Ctrl+K)");
209  break;
210  default:
211  {
212  PTOOLSTATUS_TAB_INFO tabInfo;
213 
214  if ((tabInfo = FindTabInfo(tabIndex)) && tabInfo->BannerText)
215  {
216  Edit_SetCueBannerText(SearchboxHandle, PhaConcatStrings2(tabInfo->BannerText, L" (Ctrl+K)")->Buffer);
217  }
218  else
219  {
220  // Disable the textbox if we're on an unsupported tab.
221  Edit_SetCueBannerText(SearchboxHandle, L"Search Disabled");
222  }
223  }
224  break;
225  }
226 }
227 
228 static VOID NTAPI LayoutPaddingCallback(
229  _In_opt_ PVOID Parameter,
230  _In_opt_ PVOID Context
231  )
232 {
234 
235  if (RebarHandle && EnableToolBar)
236  {
237  RECT rebarRect;
238 
239  SendMessage(RebarHandle, WM_SIZE, 0, 0);
240 
241  GetClientRect(RebarHandle, &rebarRect);
242 
243  // Adjust the PH client area and exclude the rebar width.
244  data->Padding.top += rebarRect.bottom;
245 
246  //if (SearchBoxDisplayStyle == SearchBoxDisplayAutoHide)
247  //{
248  // static BOOLEAN isSearchboxVisible = FALSE;
249  // SIZE idealWidth;
250  //
251  // // Query the the Toolbar ideal width
252  // SendMessage(ToolBarHandle, TB_GETIDEALSIZE, FALSE, (LPARAM)&idealWidth);
253  //
254  // // Hide the Searcbox band if the window size is too small...
255  // if (rebarRect.right > idealWidth.cx)
256  // {
257  // if (isSearchboxVisible)
258  // {
259  // if (!RebarBandExists(BandID_SearchBox))
260  // RebarBandInsert(BandID_SearchBox, SearchboxHandle, 20, 180);
261  //
262  // isSearchboxVisible = FALSE;
263  // }
264  // }
265  // else
266  // {
267  // if (!isSearchboxVisible)
268  // {
269  // if (RebarBandExists(BandID_SearchBox))
270  // RebarBandRemove(BandID_SearchBox);
271  //
272  // isSearchboxVisible = TRUE;
273  // }
274  // }
275  //}
276  }
277 
279  {
280  RECT statusBarRect;
281 
282  SendMessage(StatusBarHandle, WM_SIZE, 0, 0);
283 
284  GetClientRect(StatusBarHandle, &statusBarRect);
285 
286  // Adjust the PH client area and exclude the StatusBar width.
287  data->Padding.bottom += statusBarRect.bottom;
288  }
289 }
290 
291 static BOOLEAN NTAPI MessageLoopFilter(
292  _In_ PMSG Message,
293  _In_ PVOID Context
294  )
295 {
296  if (
297  Message->hwnd == PhMainWndHandle ||
298  IsChild(PhMainWndHandle, Message->hwnd)
299  )
300  {
301  if (TranslateAccelerator(PhMainWndHandle, AcceleratorTable, Message))
302  return TRUE;
303  }
304 
305  return FALSE;
306 }
307 
308 static VOID DrawWindowBorderForTargeting(
309  _In_ HWND hWnd
310  )
311 {
312  RECT rect;
313  HDC hdc;
314 
315  GetWindowRect(hWnd, &rect);
316  hdc = GetWindowDC(hWnd);
317 
318  if (hdc)
319  {
320  ULONG penWidth = GetSystemMetrics(SM_CXBORDER) * 3;
321  INT oldDc;
322  HPEN pen;
323  HBRUSH brush;
324 
325  oldDc = SaveDC(hdc);
326 
327  // Get an inversion effect.
328  SetROP2(hdc, R2_NOT);
329 
330  pen = CreatePen(PS_INSIDEFRAME, penWidth, RGB(0x00, 0x00, 0x00));
331  SelectObject(hdc, pen);
332 
333  brush = GetStockObject(NULL_BRUSH);
334  SelectObject(hdc, brush);
335 
336  // Draw the rectangle.
337  Rectangle(hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top);
338 
339  // Cleanup.
340  DeleteObject(pen);
341 
342  RestoreDC(hdc, oldDc);
343  ReleaseDC(hWnd, hdc);
344  }
345 }
346 
347 static LRESULT CALLBACK MainWndSubclassProc(
348  _In_ HWND hWnd,
349  _In_ UINT uMsg,
350  _In_ WPARAM wParam,
351  _In_ LPARAM lParam,
352  _In_ UINT_PTR uIdSubclass,
353  _In_ ULONG_PTR dwRefData
354  )
355 {
356  switch (uMsg)
357  {
358  case WM_COMMAND:
359  {
360  switch (GET_WM_COMMAND_CMD(wParam, lParam))
361  {
362  case EN_CHANGE:
363  {
364  // Cache the current search text for our callback.
366 
367  // Expand the nodes so we can search them
371 
375  PhInvokeCallback(&SearchChangedEvent, SearchboxText);
376 
377  goto DefaultWndProc;
378  }
379  break;
380  case EN_KILLFOCUS:
381  {
383  break;
384 
385  if ((HWND)lParam != SearchboxHandle)
386  break;
387 
388  if (SearchboxText->Length == 0)
389  {
392  }
393  }
394  break;
395  }
396 
397  switch (GET_WM_COMMAND_ID(wParam, lParam))
398  {
399  case PHAPP_ID_ESC_EXIT:
400  {
401  // If we're targeting and the user presses the Esc key, cancel the targeting.
402  // We also make sure the window doesn't get closed, by filtering out the message.
403  if (TargetingWindow)
404  {
405  TargetingWindow = FALSE;
406  ReleaseCapture();
407 
408  goto DefaultWndProc;
409  }
410  }
411  break;
412  case ID_SEARCH:
413  {
414  // handle keybind Ctrl + K
416  {
417  SetFocus(SearchboxHandle);
418  Edit_SetSel(SearchboxHandle, 0, -1);
419  }
420 
421  goto DefaultWndProc;
422  }
423  break;
424  case ID_SEARCH_CLEAR:
425  {
427  {
428  SetFocus(SearchboxHandle);
429  Static_SetText(SearchboxHandle, L"");
430  }
431 
432  goto DefaultWndProc;
433  }
434  break;
435  case PHAPP_ID_VIEW_ALWAYSONTOP:
436  {
437  // Let Process Hacker perform the default processing.
438  DefSubclassProc(hWnd, uMsg, wParam, lParam);
439 
440  // Query the settings.
441  BOOLEAN isAlwaysOnTopEnabled = (BOOLEAN)PhGetIntegerSetting(L"MainWindowAlwaysOnTop");
442 
443  // Set the pressed button state.
444  SendMessage(ToolBarHandle, TB_PRESSBUTTON, (WPARAM)PHAPP_ID_VIEW_ALWAYSONTOP, (LPARAM)(MAKELONG(isAlwaysOnTopEnabled, 0)));
445 
446  goto DefaultWndProc;
447  }
448  break;
449  }
450  }
451  break;
452  case WM_NOTIFY:
453  {
454  LPNMHDR hdr = (LPNMHDR)lParam;
455 
456  if (hdr->hwndFrom == RebarHandle)
457  {
458  switch (hdr->code)
459  {
460  case RBN_HEIGHTCHANGE:
461  {
462  // Invoke the LayoutPaddingCallback.
463  PostMessage(PhMainWndHandle, WM_SIZE, 0, 0);
464  }
465  break;
466  case RBN_CHEVRONPUSHED:
467  {
468  LPNMREBARCHEVRON rebar;
469  ULONG index = 0;
470  ULONG buttonCount = 0;
471  RECT toolbarRect;
472  PPH_EMENU menu;
473  PPH_EMENU_ITEM selectedItem;
474 
475  rebar = (LPNMREBARCHEVRON)lParam;
476  menu = PhCreateEMenu();
477 
478  GetClientRect(ToolBarHandle, &toolbarRect);
479 
480  buttonCount = (ULONG)SendMessage(ToolBarHandle, TB_BUTTONCOUNT, 0, 0);
481 
482  for (index = 0; index < buttonCount; index++)
483  {
484  RECT buttonRect;
485  TBBUTTONINFO button = { sizeof(TBBUTTONINFO) };
486  button.dwMask = TBIF_BYINDEX | TBIF_STYLE | TBIF_COMMAND | TBIF_IMAGE;
487 
488  // Get the client coordinates of the button.
489  if (SendMessage(ToolBarHandle, TB_GETITEMRECT, index, (LPARAM)&buttonRect) == -1)
490  break;
491 
492  if (buttonRect.right <= toolbarRect.right)
493  continue;
494 
495  // Get extended button information.
496  if (SendMessage(ToolBarHandle, TB_GETBUTTONINFO, index, (LPARAM)&button) == -1)
497  break;
498 
499  if (button.fsStyle == BTNS_SEP)
500  {
501  // Add separators to menu.
502  PhInsertEMenuItem(menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, NULL, NULL, NULL), -1);
503  }
504  else
505  {
506  PPH_EMENU_ITEM menuItem;
507  HICON menuIcon;
508 
509  // Add buttons to menu.
510  menuItem = PhCreateEMenuItem(0, button.idCommand, ToolbarGetText(button.idCommand), NULL, NULL);
511 
512  menuIcon = ImageList_GetIcon(ToolBarImageList, button.iImage, ILD_NORMAL);
513  menuItem->Flags |= PH_EMENU_BITMAP_OWNED;
514  menuItem->Bitmap = PhIconToBitmap(menuIcon, 16, 16);
515  DestroyIcon(menuIcon);
516 
517  if (button.idCommand == PHAPP_ID_VIEW_ALWAYSONTOP)
518  {
519  // Set the pressed state.
520  if (PhGetIntegerSetting(L"MainWindowAlwaysOnTop"))
521  menuItem->Flags |= PH_EMENU_CHECKED;
522  }
523 
524  // TODO: Temporarily disable some unsupported buttons.
525  if (button.idCommand == TIDC_FINDWINDOW ||
526  button.idCommand == TIDC_FINDWINDOWTHREAD ||
527  button.idCommand == TIDC_FINDWINDOWKILL)
528  {
529  menuItem->Flags |= PH_EMENU_DISABLED;
530  }
531 
532  PhInsertEMenuItem(menu, menuItem, -1);
533  }
534  }
535 
536  MapWindowPoints(RebarHandle, NULL, (LPPOINT)&rebar->rc, 2);
537 
538  selectedItem = PhShowEMenu(
539  menu,
540  hWnd,
543  rebar->rc.left,
544  rebar->rc.bottom
545  );
546 
547  if (selectedItem && selectedItem->Id != -1)
548  {
549  SendMessage(PhMainWndHandle, WM_COMMAND, MAKEWPARAM(selectedItem->Id, 0), 0);
550  }
551 
552  PhDestroyEMenu(menu);
553  }
554  break;
555  }
556 
557  goto DefaultWndProc;
558  }
559  else if (hdr->hwndFrom == ToolBarHandle)
560  {
561  switch (hdr->code)
562  {
563  case TBN_BEGINDRAG:
564  {
565  LPNMTOOLBAR toolbar = (LPNMTOOLBAR)hdr;
566  ULONG id;
567 
568  id = (ULONG)toolbar->iItem;
569 
570  if (id == TIDC_FINDWINDOW || id == TIDC_FINDWINDOWTHREAD || id == TIDC_FINDWINDOWKILL)
571  {
572  // Direct all mouse events to this window.
573  SetCapture(hWnd);
574 
575  // Send the window to the bottom.
576  SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
577 
578  TargetingWindow = TRUE;
579  TargetingCurrentWindow = NULL;
580  TargetingCurrentWindowDraw = FALSE;
581  TargetingCompleted = FALSE;
582  TargetingMode = id;
583 
584  SendMessage(hWnd, WM_MOUSEMOVE, 0, 0);
585  }
586  }
587  break;
588  case TBN_INITCUSTOMIZE:
589  {
590  struct
591  {
592  NMHDR hdr;
593  HWND hDlg; // handle of the customization dialog.
594  } *initcustomize = (PVOID)lParam;
595  }
596  return TBNRF_HIDEHELP;
597  case TBN_QUERYINSERT:
598  case TBN_QUERYDELETE:
599  return TRUE;
600  case TBN_GETBUTTONINFO:
601  {
602  LPTBNOTIFY tbNotify = (LPTBNOTIFY)lParam;
603 
604  if (tbNotify->iItem < _countof(ToolbarButtons))
605  {
606  tbNotify->tbButton = ToolbarButtons[tbNotify->iItem];
607  return TRUE;
608  }
609  }
610  return FALSE;
611  case TBN_ENDADJUST:
612  {
613  if (!ToolbarInitialized)
614  break;
615 
616  // Save the customization settings.
617  SendMessage(ToolBarHandle, TB_SAVERESTORE, TRUE, (LPARAM)&ToolbarSaveParams);
618 
620  InvalidateRect(ToolBarHandle, NULL, TRUE);
621  }
622  break;
623  case TBN_RESET:
624  {
626 
627  // Re-load the original button settings.
629 
630  InvalidateRect(ToolBarHandle, NULL, TRUE);
631 
632  // Save the new settings as defaults.
633  SendMessage(ToolBarHandle, TB_SAVERESTORE, TRUE, (LPARAM)&ToolbarSaveParams);
634  }
635  return TBNRF_ENDCUSTOMIZE;
636  }
637 
638  goto DefaultWndProc;
639  }
640  else if (hdr->hwndFrom == StatusBarHandle)
641  {
642  switch (hdr->code)
643  {
644  case NM_RCLICK:
645  {
646  POINT cursorPos;
647 
648  GetCursorPos(&cursorPos);
649 
650  ShowStatusMenu(&cursorPos);
651  }
652  break;
653  }
654 
655  goto DefaultWndProc;
656  }
657  }
658  break;
659  case WM_MOUSEMOVE:
660  {
661  if (TargetingWindow)
662  {
663  POINT cursorPos;
664  HWND windowOverMouse;
665  ULONG processId;
666  ULONG threadId;
667 
668  GetCursorPos(&cursorPos);
669  windowOverMouse = WindowFromPoint(cursorPos);
670 
671  if (TargetingCurrentWindow != windowOverMouse)
672  {
673  if (TargetingCurrentWindow && TargetingCurrentWindowDraw)
674  {
675  // Invert the old border (to remove it).
676  DrawWindowBorderForTargeting(TargetingCurrentWindow);
677  }
678 
679  if (windowOverMouse)
680  {
681  threadId = GetWindowThreadProcessId(windowOverMouse, &processId);
682 
683  // Draw a rectangle over the current window (but not if it's one of our own).
684  if (UlongToHandle(processId) != NtCurrentProcessId())
685  {
686  DrawWindowBorderForTargeting(windowOverMouse);
687  TargetingCurrentWindowDraw = TRUE;
688  }
689  else
690  {
691  TargetingCurrentWindowDraw = FALSE;
692  }
693  }
694 
695  TargetingCurrentWindow = windowOverMouse;
696  }
697 
698  goto DefaultWndProc;
699  }
700  }
701  break;
702  case WM_LBUTTONUP:
703  case WM_RBUTTONUP:
704  case WM_MBUTTONUP:
705  {
706  if (TargetingWindow)
707  {
708  ULONG processId;
709  ULONG threadId;
710 
711  TargetingCompleted = TRUE;
712 
713  // Bring the window back to the top, and preserve the Always on Top setting.
714  SetWindowPos(PhMainWndHandle, PhGetIntegerSetting(L"MainWindowAlwaysOnTop") ? HWND_TOPMOST : HWND_TOP,
715  0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
716 
717  TargetingWindow = FALSE;
718  ReleaseCapture();
719 
720  if (TargetingCurrentWindow)
721  {
722  if (TargetingCurrentWindowDraw)
723  {
724  // Remove the border on the window we found.
725  DrawWindowBorderForTargeting(TargetingCurrentWindow);
726  }
727 
729  {
730  // This is an undocumented function exported by user32.dll that
731  // retrieves the hung window represented by a ghost window.
732  static HWND (WINAPI *HungWindowFromGhostWindow_I)(
733  _In_ HWND hWnd
734  );
735 
736  if (!HungWindowFromGhostWindow_I)
737  HungWindowFromGhostWindow_I = PhGetModuleProcAddress(L"user32.dll", "HungWindowFromGhostWindow");
738 
739  if (HungWindowFromGhostWindow_I)
740  {
741  HWND hungWindow = HungWindowFromGhostWindow_I(TargetingCurrentWindow);
742 
743  // The call will have failed if the window wasn't actually a ghost
744  // window.
745  if (hungWindow)
746  TargetingCurrentWindow = hungWindow;
747  }
748  }
749 
750  threadId = GetWindowThreadProcessId(TargetingCurrentWindow, &processId);
751 
752  if (threadId && processId && UlongToHandle(processId) != NtCurrentProcessId())
753  {
754  PPH_PROCESS_NODE processNode;
755 
756  processNode = PhFindProcessNode(UlongToHandle(processId));
757 
758  if (processNode)
759  {
761  ProcessHacker_SelectProcessNode(hWnd, processNode);
762  }
763 
764  switch (TargetingMode)
765  {
767  {
768  PPH_PROCESS_PROPCONTEXT propContext;
769  PPH_PROCESS_ITEM processItem;
770 
771  if (processItem = PhReferenceProcessItem(UlongToHandle(processId)))
772  {
773  if (propContext = PhCreateProcessPropContext(hWnd, processItem))
774  {
775  PhSetSelectThreadIdProcessPropContext(propContext, UlongToHandle(threadId));
776  PhShowProcessProperties(propContext);
777  PhDereferenceObject(propContext);
778  }
779 
780  PhDereferenceObject(processItem);
781  }
782  else
783  {
784  PhShowError(hWnd, L"The process (PID %lu) does not exist.", processId);
785  }
786  }
787  break;
788  case TIDC_FINDWINDOWKILL:
789  {
790  PPH_PROCESS_ITEM processItem;
791 
792  if (processItem = PhReferenceProcessItem(UlongToHandle(processId)))
793  {
794  PhUiTerminateProcesses(hWnd, &processItem, 1);
795  PhDereferenceObject(processItem);
796  }
797  else
798  {
799  PhShowError(hWnd, L"The process (PID %lu) does not exist.", processId);
800  }
801  }
802  break;
803  }
804  }
805  }
806 
807  goto DefaultWndProc;
808  }
809  }
810  break;
811  case WM_CAPTURECHANGED:
812  {
813  if (!TargetingCompleted)
814  {
815  // The user cancelled the targeting, probably by pressing the Esc key.
816 
817  // Remove the border on the currently selected window.
818  if (TargetingCurrentWindow)
819  {
820  if (TargetingCurrentWindowDraw)
821  {
822  // Remove the border on the window we found.
823  DrawWindowBorderForTargeting(TargetingCurrentWindow);
824  }
825  }
826 
827  SetWindowPos(PhMainWndHandle, PhGetIntegerSetting(L"MainWindowAlwaysOnTop") ? HWND_TOPMOST : HWND_TOP,
828  0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
829 
830  TargetingCompleted = TRUE;
831  }
832  }
833  break;
834  case WM_SIZE:
835  // Resize PH main window client-area.
837  break;
838  case WM_SETTINGCHANGE:
839  // Forward to the Searchbox so we can reinitialize the settings...
840  SendMessage(SearchboxHandle, WM_SETTINGCHANGE, 0, 0);
841  break;
842  }
843 
844  return DefSubclassProc(hWnd, uMsg, wParam, lParam);
845 
846 DefaultWndProc:
847  return DefWindowProc(hWnd, uMsg, wParam, lParam);
848 }
849 
850 static VOID NTAPI MainWindowShowingCallback(
851  _In_opt_ PVOID Parameter,
852  _In_opt_ PVOID Context
853  )
854 {
855  PhRegisterMessageLoopFilter(MessageLoopFilter, NULL);
858  LayoutPaddingCallback,
859  NULL,
860  &LayoutPaddingCallbackRegistration
861  );
862  SetWindowSubclass(PhMainWndHandle, MainWndSubclassProc, 0, 0);
863 
865 }
866 
867 static VOID NTAPI LoadCallback(
868  _In_opt_ PVOID Parameter,
869  _In_opt_ PVOID Context
870  )
871 {
875 
879 }
880 
881 static VOID NTAPI ShowOptionsCallback(
882  _In_opt_ PVOID Parameter,
883  _In_opt_ PVOID Context
884  )
885 {
886  DialogBox(
887  PluginInstance->DllBase,
888  MAKEINTRESOURCE(IDD_OPTIONS),
889  (HWND)Parameter,
891  );
892 }
893 
895  _In_ HINSTANCE Instance,
896  _In_ ULONG Reason,
897  _Reserved_ PVOID Reserved
898  )
899 {
900  switch (Reason)
901  {
902  case DLL_PROCESS_ATTACH:
903  {
905  PH_SETTING_CREATE settings[] =
906  {
914  };
915 
916  PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info);
917 
918  if (!PluginInstance)
919  return FALSE;
920 
921  info->DisplayName = L"Toolbar and Status Bar";
922  info->Author = L"dmex, wj32";
923  info->Description = L"Adds a toolbar and a status bar.";
924  info->Url = L"http://processhacker.sf.net/forums/viewtopic.php?t=1119";
925  info->HasOptions = TRUE;
926  info->Interface = &PluginInterface;
927 
929  PhGetPluginCallback(PluginInstance, PluginCallbackLoad),
930  LoadCallback,
931  NULL,
932  &PluginLoadCallbackRegistration
933  );
937  NULL,
938  &PluginShowOptionsCallbackRegistration
939  );
943  NULL,
944  &MainWindowShowingCallbackRegistration
945  );
949  NULL,
950  &ProcessesUpdatedCallbackRegistration
951  );
954  TabPageUpdatedCallback,
955  NULL,
956  &TabPageCallbackRegistration
957  );
962  &ProcessTreeNewInitializingCallbackRegistration
963  );
968  &ServiceTreeNewInitializingCallbackRegistration
969  );
974  &NetworkTreeNewInitializingCallbackRegistration
975  );
976 
977  PhAddSettings(settings, _countof(settings));
978 
979  AcceleratorTable = LoadAccelerators(
980  Instance,
981  MAKEINTRESOURCE(IDR_MAINWND_ACCEL)
982  );
983 
984  TabInfoHashtable = PhCreateSimpleHashtable(3);
985  }
986  break;
987  }
988 
989  return TRUE;
990 }