Process Hacker
statusbar.c
Go to the documentation of this file.
1 /*
2  * Process Hacker ToolStatus -
3  * statusbar main
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 ULONG StatusMask;
29 static ULONG StatusBarMaxWidths[STATUS_COUNT];
30 
32  _In_ PPOINT Point
33  )
34 {
35  HMENU menu;
36  HMENU subMenu;
37  ULONG i;
38  ULONG id;
39  ULONG bit;
40 
41  menu = LoadMenu(
43  MAKEINTRESOURCE(IDR_STATUS)
44  );
45 
46  subMenu = GetSubMenu(menu, 0);
47 
48  // Check the enabled items.
49  for (i = STATUS_MINIMUM; i != STATUS_MAXIMUM; i <<= 1)
50  {
51  if (StatusMask & i)
52  {
53  switch (i)
54  {
55  case STATUS_CPUUSAGE:
56  id = ID_STATUS_CPUUSAGE;
57  break;
58  case STATUS_COMMIT:
60  break;
61  case STATUS_PHYSICAL:
63  break;
66  break;
69  break;
72  break;
73  case STATUS_IOREADOTHER:
74  id = ID_STATUS_IO_RO;
75  break;
76  case STATUS_IOWRITE:
77  id = ID_STATUS_IO_W;
78  break;
81  break;
84  break;
87  break;
90  break;
91  }
92 
93  CheckMenuItem(subMenu, id, MF_CHECKED);
94  }
95  }
96 
97  id = (ULONG)TrackPopupMenu(
98  subMenu,
99  TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RIGHTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD,
100  Point->x,
101  Point->y,
102  0,
104  NULL
105  );
106 
107  DestroyMenu(menu);
108 
109  switch (id)
110  {
111  case ID_STATUS_CPUUSAGE:
112  bit = STATUS_CPUUSAGE;
113  break;
115  bit = STATUS_COMMIT;
116  break;
118  bit = STATUS_PHYSICAL;
119  break;
122  break;
125  break;
128  break;
129  case ID_STATUS_IO_RO:
130  bit = STATUS_IOREADOTHER;
131  break;
132  case ID_STATUS_IO_W:
133  bit = STATUS_IOWRITE;
134  break;
136  bit = STATUS_MAXCPUPROCESS;
137  break;
139  bit = STATUS_MAXIOPROCESS;
140  break;
142  bit = STATUS_VISIBLEITEMS;
143  break;
145  bit = STATUS_SELECTEDITEMS;
146  break;
147  default:
148  return;
149  }
150 
151  StatusMask ^= bit;
153 
154  UpdateStatusBar();
155 }
156 
158  VOID
159  )
160 {
161  static ULONG lastTickCount = 0;
162 
163  PPH_STRING text[STATUS_COUNT];
164  ULONG widths[STATUS_COUNT];
165  ULONG i;
166  ULONG index;
167  ULONG count;
168  HDC hdc;
169  PH_PLUGIN_SYSTEM_STATISTICS statistics;
170  BOOLEAN resetMaxWidths = FALSE;
171 
172  if (ProcessesUpdatedCount < 2)
173  return;
174 
175  if (!(StatusMask & (STATUS_MAXIMUM - 1)))
176  {
177  // The status bar doesn't cope well with 0 parts.
178  widths[0] = -1;
179  SendMessage(StatusBarHandle, SB_SETPARTS, 1, (LPARAM)widths);
180  SendMessage(StatusBarHandle, SB_SETTEXT, 0, (LPARAM)L"");
181  return;
182  }
183 
184  PhPluginGetSystemStatistics(&statistics);
185 
186  hdc = GetDC(StatusBarHandle);
187  SelectObject(hdc, (HFONT)SendMessage(StatusBarHandle, WM_GETFONT, 0, 0));
188 
189  // Reset max. widths for Max. CPU Process and Max. I/O Process parts once in a while.
190  {
191  ULONG tickCount;
192 
193  tickCount = GetTickCount();
194 
195  if (tickCount - lastTickCount >= 10000)
196  {
197  resetMaxWidths = TRUE;
198  lastTickCount = tickCount;
199  }
200  }
201 
202  count = 0;
203  index = 0;
204 
205  for (i = STATUS_MINIMUM; i != STATUS_MAXIMUM; i <<= 1)
206  {
207  if (StatusMask & i)
208  {
209  SIZE size;
210  PPH_PROCESS_ITEM processItem;
211  ULONG width;
212 
213  switch (i)
214  {
215  case STATUS_CPUUSAGE:
216  {
217  text[count] = PhFormatString(
218  L"CPU Usage: %.2f%%",
219  (statistics.CpuKernelUsage + statistics.CpuUserUsage) * 100
220  );
221  }
222  break;
223  case STATUS_COMMIT:
224  {
225  text[count] = PhFormatString(
226  L"Commit Charge: %.2f%%",
227  (FLOAT)statistics.CommitPages * 100 / statistics.Performance->CommitLimit
228  );
229  }
230  break;
231  case STATUS_PHYSICAL:
232  {
233  text[count] = PhFormatString(
234  L"Physical Memory: %.2f%%",
236  );
237  }
238  break;
240  {
241  text[count] = PhConcatStrings2(
242  L"Processes: ",
243  PhaFormatUInt64(statistics.NumberOfProcesses, TRUE)->Buffer
244  );
245  }
246  break;
248  {
249  text[count] = PhConcatStrings2(
250  L"Threads: ",
251  PhaFormatUInt64(statistics.NumberOfThreads, TRUE)->Buffer
252  );
253  }
254  break;
256  {
257  text[count] = PhConcatStrings2(
258  L"Handles: ",
259  PhaFormatUInt64(statistics.NumberOfHandles, TRUE)->Buffer
260  );
261  }
262  break;
263  case STATUS_IOREADOTHER:
264  {
265  text[count] = PhConcatStrings2(
266  L"I/O R+O: ",
267  PhaFormatSize(statistics.IoReadDelta.Delta + statistics.IoOtherDelta.Delta, -1)->Buffer
268  );
269  }
270  break;
271  case STATUS_IOWRITE:
272  {
273  text[count] = PhConcatStrings2(
274  L"I/O W: ",
275  PhaFormatSize(statistics.IoWriteDelta.Delta, -1)->Buffer
276  );
277  }
278  break;
280  {
281  if (statistics.MaxCpuProcessId && (processItem = PhReferenceProcessItem(statistics.MaxCpuProcessId)))
282  {
283  if (!PH_IS_FAKE_PROCESS_ID(processItem->ProcessId))
284  {
285  text[count] = PhFormatString(
286  L"%s (%lu): %.2f%%",
287  processItem->ProcessName->Buffer,
288  HandleToUlong(processItem->ProcessId),
289  processItem->CpuUsage * 100
290  );
291  }
292  else
293  {
294  text[count] = PhFormatString(
295  L"%s: %.2f%%",
296  processItem->ProcessName->Buffer,
297  processItem->CpuUsage * 100
298  );
299  }
300 
301  PhDereferenceObject(processItem);
302  }
303  else
304  {
305  text[count] = PhCreateString(L"-");
306  }
307 
308  if (resetMaxWidths)
309  StatusBarMaxWidths[index] = 0;
310  }
311  break;
312  case STATUS_MAXIOPROCESS:
313  {
314  if (statistics.MaxIoProcessId && (processItem = PhReferenceProcessItem(statistics.MaxIoProcessId)))
315  {
316  if (!PH_IS_FAKE_PROCESS_ID(processItem->ProcessId))
317  {
318  text[count] = PhFormatString(
319  L"%s (%lu): %s",
320  processItem->ProcessName->Buffer,
321  HandleToUlong(processItem->ProcessId),
322  PhaFormatSize(processItem->IoReadDelta.Delta + processItem->IoWriteDelta.Delta + processItem->IoOtherDelta.Delta, -1)->Buffer
323  );
324  }
325  else
326  {
327  text[count] = PhFormatString(
328  L"%s: %s",
329  processItem->ProcessName->Buffer,
330  PhaFormatSize(processItem->IoReadDelta.Delta + processItem->IoWriteDelta.Delta + processItem->IoOtherDelta.Delta, -1)->Buffer
331  );
332  }
333 
334  PhDereferenceObject(processItem);
335  }
336  else
337  {
338  text[count] = PhCreateString(L"-");
339  }
340 
341  if (resetMaxWidths)
342  StatusBarMaxWidths[index] = 0;
343  }
344  break;
345  case STATUS_VISIBLEITEMS:
346  {
347  HWND tnHandle = NULL;
348 
349  tnHandle = GetCurrentTreeNewHandle();
350 
351  if (tnHandle)
352  {
353  ULONG visibleCount = 0;
354 
355  visibleCount = TreeNew_GetFlatNodeCount(tnHandle);
356 
357  text[count] = PhFormatString(
358  L"Visible: %lu",
359  visibleCount
360  );
361  }
362  else
363  {
364  text[count] = PhFormatString(
365  L"Visible: N/A"
366  );
367  }
368  }
369  break;
371  {
372  HWND tnHandle = NULL;
373 
374  tnHandle = GetCurrentTreeNewHandle();
375 
376  if (tnHandle)
377  {
378  ULONG visibleCount = 0;
379  ULONG selectedCount = 0;
380 
381  visibleCount = TreeNew_GetFlatNodeCount(tnHandle);
382 
383  for (ULONG i = 0; i < visibleCount; i++)
384  {
385  if (TreeNew_GetFlatNode(tnHandle, i)->Selected)
386  selectedCount++;
387  }
388 
389  text[count] = PhFormatString(
390  L"Selected: %lu",
391  selectedCount
392  );
393  }
394  else
395  {
396  text[count] = PhFormatString(
397  L"Selected: N/A"
398  );
399  }
400  }
401  break;
402  }
403 
404  if (!GetTextExtentPoint32(hdc, text[count]->Buffer, (ULONG)text[count]->Length / 2, &size))
405  size.cx = 200;
406 
407  if (count != 0)
408  widths[count] = widths[count - 1];
409  else
410  widths[count] = 0;
411 
412  width = size.cx + 10;
413 
414  if (width <= StatusBarMaxWidths[index])
415  width = StatusBarMaxWidths[index];
416  else
417  StatusBarMaxWidths[index] = width;
418 
419  widths[count] += width;
420 
421  count++;
422  }
423  else
424  {
425  StatusBarMaxWidths[index] = 0;
426  }
427 
428  index++;
429  }
430 
431  ReleaseDC(StatusBarHandle, hdc);
432 
433  SendMessage(StatusBarHandle, SB_SETPARTS, count, (LPARAM)widths);
434 
435  for (i = 0; i < count; i++)
436  {
437  SendMessage(StatusBarHandle, SB_SETTEXT, i, (LPARAM)text[i]->Buffer);
438  PhDereferenceObject(text[i]);
439  }
440 }