Process Hacker
toolbar.c
Go to the documentation of this file.
1 /*
2  * Process Hacker ToolStatus -
3  * main toolbar
4  *
5  * Copyright (C) 2011-2015 dmex
6  *
7  * This file is part of Process Hacker.
8  *
9  * Process Hacker is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * Process Hacker is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include "toolstatus.h"
24 
26 HIMAGELIST ToolBarImageList = NULL;
27 
28 TBBUTTON ToolbarButtons[] =
29 {
30  // Default toolbar buttons (displayed)
31  { 0, PHAPP_ID_VIEW_REFRESH, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, { 0 }, 0, 0 },
32  { 1, PHAPP_ID_HACKER_OPTIONS, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, { 0 }, 0, 0 },
33  { 0, 0, 0, BTNS_SEP, { 0 }, 0, 0 },
34  { 2, PHAPP_ID_HACKER_FINDHANDLESORDLLS, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, { 0 }, 0, 0 },
35  { 3, PHAPP_ID_VIEW_SYSTEMINFORMATION, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, { 0 }, 0, 0 },
36  { 0, 0, 0, BTNS_SEP, { 0 }, 0, 0 },
37  { 4, TIDC_FINDWINDOW, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, { 0 }, 0, 0 },
38  { 5, TIDC_FINDWINDOWTHREAD, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, { 0 }, 0, 0 },
39  { 6, TIDC_FINDWINDOWKILL, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, { 0 }, 0, 0 },
40  // Available toolbar buttons (hidden)
41  { 7, PHAPP_ID_VIEW_ALWAYSONTOP, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, { 0 }, 0, 0 }
42 };
43 
44 // NOTE: This Registry key is never created or used unless the Toolbar is customized.
45 TBSAVEPARAMSW ToolbarSaveParams =
46 {
47  HKEY_CURRENT_USER,
48  L"Software\\ProcessHacker",
49  L"ToolbarSettings"
50 };
51 
53  _In_ UINT BandID,
54  _In_ HWND HwndChild,
55  _In_ UINT cyMinChild,
56  _In_ UINT cxMinChild
57  )
58 {
59  REBARBANDINFO rebarBandInfo = { REBARBANDINFO_V6_SIZE };
60  rebarBandInfo.fMask = RBBIM_STYLE | RBBIM_ID | RBBIM_CHILD | RBBIM_CHILDSIZE;
61  rebarBandInfo.fStyle = RBBS_NOGRIPPER | RBBS_USECHEVRON; // | RBBS_HIDETITLE | RBBS_TOPALIGN;
62 
63  rebarBandInfo.wID = BandID;
64  rebarBandInfo.hwndChild = HwndChild;
65  rebarBandInfo.cyMinChild = cyMinChild;
66  rebarBandInfo.cxMinChild = cxMinChild;
67 
68  if (BandID == BandID_SearchBox)
69  {
70  rebarBandInfo.fStyle |= RBBS_FIXEDSIZE;
71  }
72 
73  SendMessage(RebarHandle, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rebarBandInfo);
74 }
75 
77  _In_ UINT BandID
78  )
79 {
80  INT index = (INT)SendMessage(RebarHandle, RB_IDTOINDEX, (WPARAM)BandID, 0);
81 
82  if (index == -1)
83  return;
84 
85  SendMessage(RebarHandle, RB_DELETEBAND, (WPARAM)index, 0);
86 }
87 
89  _In_ UINT BandID
90  )
91 {
92  INT index = (INT)SendMessage(RebarHandle, RB_IDTOINDEX, (WPARAM)BandID, 0);
93 
94  if (index != -1)
95  return TRUE;
96 
97  return FALSE;
98 }
99 
100 static VOID RebarLoadSettings(
101  VOID
102  )
103 {
104  // Initialize the Toolbar Imagelist.
106  {
107  HBITMAP iconBitmap = NULL;
108 
109  // Create the toolbar imagelist
110  ToolBarImageList = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 0, 0);
111  // Set the number of images
112  ImageList_SetImageCount(ToolBarImageList, 8);
113 
114  // Add the images to the imagelist
115  if (iconBitmap = LoadImageFromResources(16, 16, MAKEINTRESOURCE(IDB_ARROW_REFRESH)))
116  {
117  ImageList_Replace(ToolBarImageList, 0, iconBitmap, NULL);
118  DeleteObject(iconBitmap);
119  }
120  else
121  {
123  }
124 
125  if (iconBitmap = LoadImageFromResources(16, 16, MAKEINTRESOURCE(IDB_COG_EDIT)))
126  {
127  ImageList_Replace(ToolBarImageList, 1, iconBitmap, NULL);
128  DeleteObject(iconBitmap);
129  }
130  else
131  {
133  }
134 
135  if (iconBitmap = LoadImageFromResources(16, 16, MAKEINTRESOURCE(IDB_FIND)))
136  {
137  ImageList_Replace(ToolBarImageList, 2, iconBitmap, NULL);
138  DeleteObject(iconBitmap);
139  }
140  else
141  {
143  }
144 
145  if (iconBitmap = LoadImageFromResources(16, 16, MAKEINTRESOURCE(IDB_CHART_LINE)))
146  {
147  ImageList_Replace(ToolBarImageList, 3, iconBitmap, NULL);
148  DeleteObject(iconBitmap);
149  }
150  else
151  {
153  }
154 
155  if (iconBitmap = LoadImageFromResources(16, 16, MAKEINTRESOURCE(IDB_APPLICATION)))
156  {
157  ImageList_Replace(ToolBarImageList, 4, iconBitmap, NULL);
158  DeleteObject(iconBitmap);
159  }
160  else
161  {
163  }
164 
165  if (iconBitmap = LoadImageFromResources(16, 16, MAKEINTRESOURCE(IDB_APPLICATION_GO)))
166  {
167  ImageList_Replace(ToolBarImageList, 5, iconBitmap, NULL);
168  DeleteObject(iconBitmap);
169  }
170  else
171  {
173  }
174 
175  if (iconBitmap = LoadImageFromResources(16, 16, MAKEINTRESOURCE(IDB_CROSS)))
176  {
177  ImageList_Replace(ToolBarImageList, 6, iconBitmap, NULL);
178  DeleteObject(iconBitmap);
179  }
180  else
181  {
183  }
184 
185  if (iconBitmap = LoadImageFromResources(16, 16, MAKEINTRESOURCE(IDB_APPLICATION_GET)))
186  {
187  ImageList_Replace(ToolBarImageList, 7, iconBitmap, NULL);
188  DeleteObject(iconBitmap);
189  }
190  else
191  {
193  }
194  }
195 
196  // Initialize the Rebar and Toolbar controls.
197  if (EnableToolBar && !RebarHandle)
198  {
199  REBARINFO rebarInfo = { sizeof(REBARINFO) };
200 
201  // Create the ReBar window.
202  RebarHandle = CreateWindowEx(
203  WS_EX_TOOLWINDOW,
204  REBARCLASSNAME,
205  NULL,
206  WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CCS_NODIVIDER | CCS_TOP | RBS_VARHEIGHT | RBS_AUTOSIZE, // CCS_NOPARENTALIGN | RBS_FIXEDORDER
207  CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
209  NULL,
210  NULL,
211  NULL
212  );
213 
214  // Set the toolbar info with no imagelist.
215  SendMessage(RebarHandle, RB_SETBARINFO, 0, (LPARAM)&rebarInfo);
216 
217  // Create the ToolBar window.
218  ToolBarHandle = CreateWindowEx(
219  0,
220  TOOLBARCLASSNAME,
221  NULL,
222  WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CCS_NORESIZE | CCS_NOPARENTALIGN | CCS_NODIVIDER | CCS_ADJUSTABLE | TBSTYLE_FLAT | TBSTYLE_LIST | TBSTYLE_TRANSPARENT | TBSTYLE_TOOLTIPS | TBSTYLE_AUTOSIZE, // TBSTYLE_ALTDRAG
223  CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
224  RebarHandle,
225  NULL,
226  NULL,
227  NULL
228  );
229 
230  // Manually add button strings via TB_ADDSTRING.
231  // NOTE: The Toolbar will sometimes decide to free strings hard-coded via (INT_PTR)L"String"
232  // in the ToolbarButtons array causing random crashes unless we manually add the strings
233  // into the Toolbar string pool (this bug only affects 64bit Windows)... WTF???
234  ToolbarButtons[0].iString = SendMessage(ToolBarHandle, TB_ADDSTRING, 0, (LPARAM)L"Refresh");
235  ToolbarButtons[1].iString = SendMessage(ToolBarHandle, TB_ADDSTRING, 0, (LPARAM)L"Options");
236  ToolbarButtons[3].iString = SendMessage(ToolBarHandle, TB_ADDSTRING, 0, (LPARAM)L"Find Handles or DLLs");
237  ToolbarButtons[4].iString = SendMessage(ToolBarHandle, TB_ADDSTRING, 0, (LPARAM)L"System Information");
238  ToolbarButtons[6].iString = SendMessage(ToolBarHandle, TB_ADDSTRING, 0, (LPARAM)L"Find Window");
239  ToolbarButtons[7].iString = SendMessage(ToolBarHandle, TB_ADDSTRING, 0, (LPARAM)L"Find Window and Thread");
240  ToolbarButtons[8].iString = SendMessage(ToolBarHandle, TB_ADDSTRING, 0, (LPARAM)L"Find Window and Kill");
241  ToolbarButtons[9].iString = SendMessage(ToolBarHandle, TB_ADDSTRING, 0, (LPARAM)L"Always on Top");
242 
243  // Set the toolbar struct size.
244  SendMessage(ToolBarHandle, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
245  // Set the toolbar extended toolbar styles.
246  SendMessage(ToolBarHandle, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_DOUBLEBUFFER | TBSTYLE_EX_MIXEDBUTTONS | TBSTYLE_EX_HIDECLIPPEDBUTTONS);
247  // Configure the toolbar imagelist.
248  SendMessage(ToolBarHandle, TB_SETIMAGELIST, 0, (LPARAM)ToolBarImageList);
249  // Add the buttons to the toolbar (also specifying the default number of items to display).
250  SendMessage(ToolBarHandle, TB_ADDBUTTONS, MAX_DEFAULT_TOOLBAR_ITEMS, (LPARAM)ToolbarButtons);
251  // Restore the toolbar settings (Note: This will invoke the TBN_ENDADJUST notification).
252  SendMessage(ToolBarHandle, TB_SAVERESTORE, FALSE, (LPARAM)&ToolbarSaveParams);
253 
254  // Enable theming:
255  //SendMessage(RebarHandle, RB_SETWINDOWTHEME, 0, (LPARAM)L"Media"); //Media/Communications/BrowserTabBar/Help
256  //SendMessage(ToolBarHandle, TB_SETWINDOWTHEME, 0, (LPARAM)L"Media"); //Media/Communications/BrowserTabBar/Help
257 
258  // HACK: Query the toolbar width/height.
259  ULONG toolbarButtonSize = (ULONG)SendMessage(ToolBarHandle, TB_GETBUTTONSIZE, 0, 0);
260 
261  // Inset the toolbar into the rebar control.
262  RebarBandInsert(BandID_ToolBar, ToolBarHandle, HIWORD(toolbarButtonSize), LOWORD(toolbarButtonSize));
263 
265  }
266 
267  // Initialize the Searchbox and TreeNewFilters.
269  {
271 
275 
276  // Create the Searchbox control.
278  }
279 
280  // Initialize the Statusbar control.
282  {
283  // Create the StatusBar window.
284  StatusBarHandle = CreateWindowEx(
285  0,
286  STATUSCLASSNAME,
287  NULL,
288  WS_CHILD | WS_VISIBLE | CCS_BOTTOM | SBARS_SIZEGRIP | SBARS_TOOLTIPS,
289  CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
291  NULL,
292  NULL,
293  NULL
294  );
295  }
296 
297  // Hide or show controls (Note: don't unload or remove at runtime).
298  if (EnableToolBar)
299  {
300  if (RebarHandle && !IsWindowVisible(RebarHandle))
301  ShowWindow(RebarHandle, SW_SHOW);
302  }
303  else
304  {
305  if (RebarHandle && IsWindowVisible(RebarHandle))
306  ShowWindow(RebarHandle, SW_HIDE);
307  }
308 
309  if (EnableSearchBox)
310  {
311  // Add the Searchbox band into the rebar control.
314 
315  if (SearchboxHandle && !IsWindowVisible(SearchboxHandle))
316  ShowWindow(SearchboxHandle, SW_SHOW);
317  }
318  else
319  {
320  // Remove the Searchbox band from the rebar control.
323 
324  if (SearchboxHandle)
325  {
326  // Clear search text and reset search filters.
327  SetFocus(SearchboxHandle);
328  Static_SetText(SearchboxHandle, L"");
329 
330  if (IsWindowVisible(SearchboxHandle))
331  ShowWindow(SearchboxHandle, SW_HIDE);
332  }
333  }
334 
335  // TODO: Fix above code...
337  {
340  }
341  else
342  {
345  }
346 
347  if (EnableStatusBar)
348  {
349  if (StatusBarHandle && !IsWindowVisible(StatusBarHandle))
350  ShowWindow(StatusBarHandle, SW_SHOW);
351  }
352  else
353  {
354  if (StatusBarHandle && IsWindowVisible(StatusBarHandle))
355  ShowWindow(StatusBarHandle, SW_HIDE);
356  }
357 }
358 
360  VOID
361  )
362 {
363  RebarLoadSettings();
364 
366  {
367  ULONG index = 0;
368  ULONG buttonCount = 0;
369 
370  buttonCount = (ULONG)SendMessage(ToolBarHandle, TB_BUTTONCOUNT, 0, 0);
371 
372  for (index = 0; index < buttonCount; index++)
373  {
374  TBBUTTONINFO button = { sizeof(TBBUTTONINFO) };
375  button.dwMask = TBIF_BYINDEX | TBIF_STYLE | TBIF_COMMAND | TBIF_STATE;
376 
377  // Get settings for first button
378  if (SendMessage(ToolBarHandle, TB_GETBUTTONINFO, index, (LPARAM)&button) == -1)
379  break;
380 
381  // Skip separator buttons
382  if (button.fsStyle == BTNS_SEP)
383  continue;
384 
385 
386  // TODO: We manually add the text above using TB_ADDSTRING,
387  // why do we need to set the button text again when changing TBIF_STYLE?
388  button.dwMask |= TBIF_TEXT;
389  button.pszText = ToolbarGetText(button.idCommand);
390 
391 
392  if (button.idCommand == PHAPP_ID_VIEW_ALWAYSONTOP)
393  {
394  // Set the pressed state
395  if (PhGetIntegerSetting(L"MainWindowAlwaysOnTop"))
396  {
397  button.fsState |= TBSTATE_PRESSED;
398  }
399  }
400 
401  switch (DisplayStyle)
402  {
404  button.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE;
405  break;
407  {
408  switch (button.idCommand)
409  {
410  case PHAPP_ID_VIEW_REFRESH:
411  case PHAPP_ID_HACKER_OPTIONS:
412  case PHAPP_ID_HACKER_FINDHANDLESORDLLS:
413  case PHAPP_ID_VIEW_SYSTEMINFORMATION:
414  button.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT;
415  break;
416  default:
417  button.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE;
418  break;
419  }
420  }
421  break;
423  button.fsStyle = BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT;
424  break;
425  }
426 
427  // Set updated button info
428  SendMessage(ToolBarHandle, TB_SETBUTTONINFO, index, (LPARAM)&button);
429  }
430 
431  // Resize the toolbar
432  SendMessage(ToolBarHandle, TB_AUTOSIZE, 0, 0);
433  //InvalidateRect(ToolBarHandle, NULL, TRUE);
434  }
435 
436  if (EnableToolBar && RebarHandle)
437  {
438  INT index;
439  REBARBANDINFO rebarBandInfo = { REBARBANDINFO_V6_SIZE };
440  rebarBandInfo.fMask = RBBIM_IDEALSIZE;
441 
442  index = (INT)SendMessage(RebarHandle, RB_IDTOINDEX, (WPARAM)BandID_ToolBar, 0);
443 
444  // Get settings for Rebar band.
445  if (SendMessage(RebarHandle, RB_GETBANDINFO, index, (LPARAM)&rebarBandInfo) != -1)
446  {
447  SIZE idealWidth;
448 
449  // Reset the cxIdeal for the Chevron
450  SendMessage(ToolBarHandle, TB_GETIDEALSIZE, FALSE, (LPARAM)&idealWidth);
451 
452  rebarBandInfo.cxIdeal = idealWidth.cx;
453 
454  SendMessage(RebarHandle, RB_SETBANDINFO, index, (LPARAM)&rebarBandInfo);
455  }
456  }
457 
458  // Invoke the LayoutPaddingCallback.
459  SendMessage(PhMainWndHandle, WM_SIZE, 0, 0);
460 }
461 
463  VOID
464  )
465 {
466  // Remove all the user customizations.
467  INT buttonCount = (INT)SendMessage(ToolBarHandle, TB_BUTTONCOUNT, 0, 0);
468  while (buttonCount--)
469  SendMessage(ToolBarHandle, TB_DELETEBUTTON, (WPARAM)buttonCount, 0);
470 
471  // Re-add the original buttons.
472  SendMessage(ToolBarHandle, TB_ADDBUTTONS, MAX_DEFAULT_TOOLBAR_ITEMS, (LPARAM)ToolbarButtons);
473 
474 }
475 
477  _In_ INT CommandID
478  )
479 {
480  switch (CommandID)
481  {
482  case PHAPP_ID_VIEW_REFRESH:
483  return L"Refresh";
484  case PHAPP_ID_HACKER_OPTIONS:
485  return L"Options";
486  case PHAPP_ID_HACKER_FINDHANDLESORDLLS:
487  return L"Find Handles or DLLs";
488  case PHAPP_ID_VIEW_SYSTEMINFORMATION:
489  return L"System Information";
490  case TIDC_FINDWINDOW:
491  return L"Find Window";
493  return L"Find Window and Thread";
494  case TIDC_FINDWINDOWKILL:
495  return L"Find Window and Kill";
496  case PHAPP_ID_VIEW_ALWAYSONTOP:
497  return L"Always on Top";
498  }
499 
500  return L"Error";
501 }