Process Hacker
notifico.c
Go to the documentation of this file.
1 /*
2  * Process Hacker -
3  * notification icon manager
4  *
5  * Copyright (C) 2011-2013 wj32
6  *
7  * This file is part of Process Hacker.
8  *
9  * Process Hacker is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * Process Hacker is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include <phapp.h>
24 #include <settings.h>
25 #include <extmgri.h>
26 #include <miniinfo.h>
27 #include <phplug.h>
28 #include <notifico.h>
29 #include <windowsx.h>
30 
31 typedef struct _PH_NF_BITMAP
32 {
33  BOOLEAN Initialized;
34  HDC Hdc;
35  BITMAPINFOHEADER Header;
36  HBITMAP Bitmap;
37  PVOID Bits;
39 
40 HICON PhNfpGetBlackIcon(
41  VOID
42  );
43 
44 BOOLEAN PhNfpAddNotifyIcon(
45  _In_ ULONG Id
46  );
47 
48 BOOLEAN PhNfpRemoveNotifyIcon(
49  _In_ ULONG Id
50  );
51 
52 BOOLEAN PhNfpModifyNotifyIcon(
53  _In_ ULONG Id,
54  _In_ ULONG Flags,
55  _In_opt_ PPH_STRING Text,
56  _In_opt_ HICON Icon
57  );
58 
60  _In_opt_ PVOID Parameter,
61  _In_opt_ PVOID Context
62  );
63 
65  _In_ PPH_NF_ICON Icon
66  );
67 
69  _Out_ PULONG Width,
70  _Out_ PULONG Height,
71  _Out_ HBITMAP *Bitmap,
72  _Out_opt_ PVOID *Bits,
73  _Out_ HDC *Hdc,
74  _Out_ HBITMAP *OldBitmap
75  );
76 
78  _Inout_ PPH_NF_BITMAP Context,
79  _Out_ PULONG Width,
80  _Out_ PULONG Height,
81  _Out_ HBITMAP *Bitmap,
82  _Out_opt_ PVOID *Bits,
83  _Out_ HDC *Hdc,
84  _Out_ HBITMAP *OldBitmap
85  );
86 
88  VOID
89  );
90 
92  VOID
93  );
94 
96  VOID
97  );
98 
100  VOID
101  );
102 
104  VOID
105  );
106 
114 
119 HBITMAP PhNfpBlackBitmap = NULL;
120 HICON PhNfpBlackIcon = NULL;
121 
123  VOID
124  )
125 {
126  PPH_STRING iconList;
127  PH_STRINGREF part;
128  PH_STRINGREF remainingPart;
129 
131  PhNfpPointers.BeginBitmap = PhNfpBeginBitmap;
132 
133  // Load settings for default icons.
134  PhNfIconMask = PhGetIntegerSetting(L"IconMask");
135 
136  // Load settings for registered icons.
137 
138  iconList = PhGetStringSetting(L"IconMaskList");
139  remainingPart = iconList->sr;
140 
141  while (remainingPart.Length != 0)
142  {
143  PhSplitStringRefAtChar(&remainingPart, '|', &part, &remainingPart);
144 
145  if (part.Length != 0)
146  {
147  PH_STRINGREF pluginName;
148  ULONG subId;
149  PPH_NF_ICON icon;
150 
151  if (PhEmParseCompoundId(&part, &pluginName, &subId) &&
152  (icon = PhNfFindIcon(&pluginName, subId)))
153  {
154  PhNfIconMask |= icon->IconId;
155  }
156  }
157  }
158 
159  PhDereferenceObject(iconList);
160 }
161 
163  VOID
164  )
165 {
166  ULONG i;
167 
168  for (i = PH_ICON_MINIMUM; i != PhNfMaximumIconId; i <<= 1)
169  {
170  if (PhNfIconMask & i)
172  }
173 
177  NULL,
178  &PhNfpProcessesUpdatedRegistration
179  );
180 }
181 
183  VOID
184  )
185 {
186  ULONG registeredIconMask;
187 
189 
190  registeredIconMask = PhNfIconMask & ~PH_ICON_DEFAULT_ALL;
191 
192  if (registeredIconMask != 0)
193  {
194  PH_STRING_BUILDER iconListBuilder;
195  ULONG i;
196 
197  PhInitializeStringBuilder(&iconListBuilder, 60);
198 
199  for (i = 0; i < sizeof(PhNfRegisteredIcons) / sizeof(PPH_NF_ICON); i++)
200  {
201  if (PhNfRegisteredIcons[i])
202  {
203  if (registeredIconMask & PhNfRegisteredIcons[i]->IconId)
204  {
206  &iconListBuilder,
207  L"+%s+%u|",
208  PhNfRegisteredIcons[i]->Plugin->Name.Buffer,
209  PhNfRegisteredIcons[i]->SubId
210  );
211  }
212  }
213  }
214 
215  if (iconListBuilder.String->Length != 0)
216  PhRemoveEndStringBuilder(&iconListBuilder, 1);
217 
218  PhSetStringSetting2(L"IconMaskList", &iconListBuilder.String->sr);
219  PhDeleteStringBuilder(&iconListBuilder);
220  }
221  else
222  {
223  PhSetStringSetting(L"IconMaskList", L"");
224  }
225 }
226 
228  VOID
229  )
230 {
231  ULONG i;
232 
233  // Remove all icons to prevent them hanging around after we exit.
234 
235  PhNfTerminating = TRUE; // prevent further icon updating
236 
237  for (i = PH_ICON_MINIMUM; i != PhNfMaximumIconId; i <<= 1)
238  {
239  if (PhNfIconMask & i)
241  }
242 }
243 
245  _In_ ULONG_PTR WParam,
246  _In_ ULONG_PTR LParam
247  )
248 {
249  ULONG iconIndex = HIWORD(LParam);
250  PPH_NF_ICON registeredIcon = NULL;
251 
252  if (iconIndex < sizeof(PhNfRegisteredIcons) / sizeof(PPH_NF_ICON) && PhNfRegisteredIcons[iconIndex])
253  {
254  registeredIcon = PhNfRegisteredIcons[iconIndex];
255 
256  if (registeredIcon->MessageCallback)
257  {
258  if (registeredIcon->MessageCallback(
259  registeredIcon,
260  WParam,
261  LParam,
262  registeredIcon->Context
263  ))
264  {
265  return;
266  }
267  }
268  }
269 
270  switch (LOWORD(LParam))
271  {
272  case WM_LBUTTONDOWN:
273  {
274  if (PhGetIntegerSetting(L"IconSingleClick"))
276  }
277  break;
278  case WM_LBUTTONDBLCLK:
279  {
280  if (!PhGetIntegerSetting(L"IconSingleClick"))
282  }
283  break;
284  case WM_RBUTTONUP:
285  case WM_CONTEXTMENU:
286  {
287  POINT location;
288 
289  PhPinMiniInformation(MiniInfoIconPinType, -1, 0, 0, NULL, NULL);
290  GetCursorPos(&location);
291  PhShowIconContextMenu(location);
292  }
293  break;
294  case NIN_KEYSELECT:
295  // HACK: explorer seems to send two NIN_KEYSELECT messages when the user selects the icon and presses ENTER.
296  if (GetForegroundWindow() != PhMainWndHandle)
298  break;
299  case NIN_BALLOONUSERCLICK:
301  break;
302  case NIN_POPUPOPEN:
303  {
304  PH_NF_MSG_SHOWMINIINFOSECTION_DATA showMiniInfoSectionData;
305  BOOLEAN showMiniInfo = FALSE;
306  POINT location;
307 
308  if (registeredIcon)
309  {
310  showMiniInfoSectionData.SectionName = NULL;
311 
312  if (registeredIcon->Flags & PH_NF_ICON_SHOW_MINIINFO)
313  {
314  if (registeredIcon->MessageCallback)
315  {
316  registeredIcon->MessageCallback(
317  registeredIcon,
318  (ULONG_PTR)&showMiniInfoSectionData,
319  MAKELPARAM(PH_NF_MSG_SHOWMINIINFOSECTION, 0),
320  registeredIcon->Context
321  );
322  }
323 
324  showMiniInfo = TRUE;
325  }
326  }
327  else
328  {
329  switch (1 << iconIndex)
330  {
331  case PH_ICON_CPU_HISTORY:
332  case PH_ICON_CPU_USAGE:
333  showMiniInfoSectionData.SectionName = L"CPU";
334  break;
335  case PH_ICON_IO_HISTORY:
336  showMiniInfoSectionData.SectionName = L"I/O";
337  break;
339  showMiniInfoSectionData.SectionName = L"Commit Charge";
340  break;
342  showMiniInfoSectionData.SectionName = L"Physical Memory";
343  break;
344  }
345 
346  showMiniInfo = TRUE;
347  }
348 
349  if (showMiniInfo)
350  {
351  GetCursorPos(&location);
353  showMiniInfoSectionData.SectionName, &location);
354  }
355  }
356  break;
357  case NIN_POPUPCLOSE:
358  PhPinMiniInformation(MiniInfoIconPinType, -1, 350, 0, NULL, NULL);
359  break;
360  }
361 }
362 
364  VOID
365  )
366 {
367  return PhNfMaximumIconId;
368 }
369 
371  _In_ ULONG Id
372  )
373 {
374  return PhNfIconMask & Id;
375 }
376 
378  _In_ ULONG Id,
379  _In_ BOOLEAN Visible
380  )
381 {
382  if (Visible)
383  {
384  PhNfIconMask |= Id;
385  PhNfpAddNotifyIcon(Id);
386  }
387  else
388  {
389  PhNfIconMask &= ~Id;
391  }
392 }
393 
395  _In_opt_ ULONG Id,
396  _In_ PWSTR Title,
397  _In_ PWSTR Text,
398  _In_ ULONG Timeout,
399  _In_ ULONG Flags
400  )
401 {
402  NOTIFYICONDATA notifyIcon = { NOTIFYICONDATA_V3_SIZE };
403 
404  if (Id == 0)
405  {
406  // Choose the first visible icon.
407  Id = PhNfIconMask;
408  }
409 
410  if (!_BitScanForward(&Id, Id))
411  return FALSE;
412 
413  notifyIcon.hWnd = PhMainWndHandle;
414  notifyIcon.uID = Id;
415  notifyIcon.uFlags = NIF_INFO;
416  wcsncpy_s(notifyIcon.szInfoTitle, sizeof(notifyIcon.szInfoTitle) / sizeof(WCHAR), Title, _TRUNCATE);
417  wcsncpy_s(notifyIcon.szInfo, sizeof(notifyIcon.szInfo) / sizeof(WCHAR), Text, _TRUNCATE);
418  notifyIcon.uTimeout = Timeout;
419  notifyIcon.dwInfoFlags = Flags;
420 
421  Shell_NotifyIcon(NIM_MODIFY, &notifyIcon);
422 
423  return TRUE;
424 }
425 
427  _In_ HBITMAP Bitmap
428  )
429 {
430  ICONINFO iconInfo;
431 
433 
434  iconInfo.fIcon = TRUE;
435  iconInfo.xHotspot = 0;
436  iconInfo.yHotspot = 0;
437  iconInfo.hbmMask = PhNfpBlackBitmap;
438  iconInfo.hbmColor = Bitmap;
439 
440  return CreateIconIndirect(&iconInfo);
441 }
442 
444  _In_ struct _PH_PLUGIN *Plugin,
445  _In_ ULONG SubId,
446  _In_opt_ PVOID Context,
447  _In_ PWSTR Text,
448  _In_ ULONG Flags,
449  _In_opt_ PPH_NF_ICON_UPDATE_CALLBACK UpdateCallback,
450  _In_opt_ PPH_NF_ICON_MESSAGE_CALLBACK MessageCallback
451  )
452 {
453  PPH_NF_ICON icon;
454  ULONG iconId;
455  ULONG iconIndex;
456 
458  {
459  // No room for any more icons.
460  return NULL;
461  }
462 
463  iconId = PhNfMaximumIconId;
464 
465  if (!_BitScanReverse(&iconIndex, iconId) ||
466  iconIndex >= sizeof(PhNfRegisteredIcons) / sizeof(PPH_NF_ICON))
467  {
468  // Should never happen.
469  return NULL;
470  }
471 
472  PhNfMaximumIconId <<= 1;
473 
474  icon = PhAllocate(sizeof(PH_NF_ICON));
475  icon->Plugin = Plugin;
476  icon->SubId = SubId;
477  icon->Context = Context;
478  icon->Pointers = &PhNfpPointers;
479  icon->Text = Text;
480  icon->Flags = Flags;
481  icon->IconId = iconId;
482  icon->UpdateCallback = UpdateCallback;
483  icon->MessageCallback = MessageCallback;
484 
485  PhNfRegisteredIcons[iconIndex] = icon;
486 
487  return icon;
488 }
489 
491  _In_ ULONG Id
492  )
493 {
494  ULONG iconIndex;
495 
496  if (!_BitScanReverse(&iconIndex, Id))
497  return NULL;
498 
499  return PhNfRegisteredIcons[iconIndex];
500 }
501 
503  _In_ PPH_STRINGREF PluginName,
504  _In_ ULONG SubId
505  )
506 {
507  ULONG i;
508 
509  for (i = 0; i < sizeof(PhNfRegisteredIcons) / sizeof(PPH_NF_ICON); i++)
510  {
511  if (PhNfRegisteredIcons[i])
512  {
513  if (PhNfRegisteredIcons[i]->SubId == SubId &&
514  PhEqualStringRef(PluginName, &PhNfRegisteredIcons[i]->Plugin->AppContext.AppName, FALSE))
515  {
516  return PhNfRegisteredIcons[i];
517  }
518  }
519  }
520 
521  return NULL;
522 }
523 
525  _In_ BOOLEAN Pinned
526  )
527 {
528  ULONG i;
529  ULONG id;
530 
531  if (PhNfMiniInfoPinned != Pinned)
532  {
533  PhNfMiniInfoPinned = Pinned;
534 
535  // Go through every icon and set/clear the NIF_SHOWTIP flag depending on whether the mini info window is
536  // pinned. If it's pinned then we want to show normal tooltips, because the section doesn't change
537  // automatically when the cursor hovers over an icon.
538  for (i = 0; i < sizeof(PhNfRegisteredIcons) / sizeof(PPH_NF_ICON); i++)
539  {
540  id = 1 << i;
541 
542  if (PhNfIconMask & id)
543  {
544  PhNfpModifyNotifyIcon(id, NIF_TIP, PhNfIconTextCache[i], NULL);
545  }
546  }
547  }
548 }
549 
551  VOID
552  )
553 {
554  if (!PhNfpBlackIcon)
555  {
556  ULONG width;
557  ULONG height;
558  PVOID bits;
559  HDC hdc;
560  HBITMAP oldBitmap;
561  ICONINFO iconInfo;
562 
563  PhNfpBeginBitmap2(&PhNfpBlackBitmapContext, &width, &height, &PhNfpBlackBitmap, &bits, &hdc, &oldBitmap);
564  memset(bits, 0, width * height * sizeof(ULONG));
565 
566  iconInfo.fIcon = TRUE;
567  iconInfo.xHotspot = 0;
568  iconInfo.yHotspot = 0;
569  iconInfo.hbmMask = PhNfpBlackBitmap;
570  iconInfo.hbmColor = PhNfpBlackBitmap;
571  PhNfpBlackIcon = CreateIconIndirect(&iconInfo);
572 
573  SelectObject(hdc, oldBitmap);
574  }
575 
576  return PhNfpBlackIcon;
577 }
578 
580  _In_ ULONG Id
581  )
582 {
583  NOTIFYICONDATA notifyIcon = { sizeof(NOTIFYICONDATA) };
584  PPH_NF_ICON icon;
585 
586  if (PhNfTerminating)
587  return FALSE;
588  if ((icon = PhNfGetIconById(Id)) && (icon->Flags & PH_NF_ICON_UNAVAILABLE))
589  return FALSE;
590 
591  // The IDs we pass to explorer are bit indicies, not the normal mask values.
592 
593  if (!_BitScanForward(&Id, Id))
594  return FALSE;
595 
596  notifyIcon.hWnd = PhMainWndHandle;
597  notifyIcon.uID = Id;
598  notifyIcon.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
599  notifyIcon.uCallbackMessage = WM_PH_NOTIFY_ICON_MESSAGE;
600  wcsncpy_s(
601  notifyIcon.szTip, sizeof(notifyIcon.szTip) / sizeof(WCHAR),
602  PhGetStringOrDefault(PhNfIconTextCache[Id], PhApplicationName),
603  _TRUNCATE
604  );
605  notifyIcon.hIcon = PhNfpGetBlackIcon();
606 
607  if (PhNfMiniInfoPinned || (icon && !(icon->Flags & PH_NF_ICON_SHOW_MINIINFO)))
608  notifyIcon.uFlags |= NIF_SHOWTIP;
609 
610  Shell_NotifyIcon(NIM_ADD, &notifyIcon);
611 
613  {
614  notifyIcon.uVersion = NOTIFYICON_VERSION_4;
615  Shell_NotifyIcon(NIM_SETVERSION, &notifyIcon);
616  }
617 
618  return TRUE;
619 }
620 
622  _In_ ULONG Id
623  )
624 {
625  NOTIFYICONDATA notifyIcon = { sizeof(NOTIFYICONDATA) };
626  PPH_NF_ICON icon;
627 
628  if ((icon = PhNfGetIconById(Id)) && (icon->Flags & PH_NF_ICON_UNAVAILABLE))
629  return FALSE;
630 
631  if (!_BitScanForward(&Id, Id))
632  return FALSE;
633 
634  notifyIcon.hWnd = PhMainWndHandle;
635  notifyIcon.uID = Id;
636 
637  Shell_NotifyIcon(NIM_DELETE, &notifyIcon);
638 
639  return TRUE;
640 }
641 
643  _In_ ULONG Id,
644  _In_ ULONG Flags,
645  _In_opt_ PPH_STRING Text,
646  _In_opt_ HICON Icon
647  )
648 {
649  NOTIFYICONDATA notifyIcon = { sizeof(NOTIFYICONDATA) };
650  PPH_NF_ICON icon;
651  ULONG notifyId;
652 
653  if (PhNfTerminating)
654  return FALSE;
655  if ((icon = PhNfGetIconById(Id)) && (icon->Flags & PH_NF_ICON_UNAVAILABLE))
656  return FALSE;
657 
658  if (!_BitScanForward(&notifyId, Id))
659  return FALSE;
660 
661  notifyIcon.hWnd = PhMainWndHandle;
662  notifyIcon.uID = notifyId;
663  notifyIcon.uFlags = Flags;
664 
665  if (Flags & NIF_TIP)
666  {
667  PhSwapReference(&PhNfIconTextCache[notifyId], Text);
668  wcsncpy_s(
669  notifyIcon.szTip,
670  sizeof(notifyIcon.szTip) / sizeof(WCHAR),
672  _TRUNCATE
673  );
674  }
675 
676  notifyIcon.hIcon = Icon;
677 
678  if (PhNfMiniInfoPinned || (icon && !(icon->Flags & PH_NF_ICON_SHOW_MINIINFO)))
679  notifyIcon.uFlags |= NIF_SHOWTIP;
680 
681  if (!Shell_NotifyIcon(NIM_MODIFY, &notifyIcon))
682  {
683  // Explorer probably died and we lost our icon. Try to add the icon, and try again.
684  PhNfpAddNotifyIcon(Id);
685  Shell_NotifyIcon(NIM_MODIFY, &notifyIcon);
686  }
687 
688  return TRUE;
689 }
690 
692  _In_opt_ PVOID Parameter,
693  _In_opt_ PVOID Context
694  )
695 {
696  ULONG registeredIconMask;
697 
698  // We do icon updating on the provider thread so we don't block the main GUI when
699  // explorer is not responding.
700 
711 
712  registeredIconMask = PhNfIconMask & ~PH_ICON_DEFAULT_ALL;
713 
714  if (registeredIconMask != 0)
715  {
716  ULONG i;
717 
718  for (i = 0; i < sizeof(PhNfRegisteredIcons) / sizeof(PPH_NF_ICON); i++)
719  {
720  if (PhNfRegisteredIcons[i] && (registeredIconMask & PhNfRegisteredIcons[i]->IconId))
721  {
722  PhNfpUpdateRegisteredIcon(PhNfRegisteredIcons[i]);
723  }
724  }
725  }
726 }
727 
729  _In_ PPH_NF_ICON Icon
730  )
731 {
732  PVOID newIconOrBitmap;
733  ULONG updateFlags;
734  PPH_STRING newText;
735  HICON newIcon;
736  ULONG flags;
737 
738  if (!Icon->UpdateCallback)
739  return;
740 
741  newIconOrBitmap = NULL;
742  newText = NULL;
743  newIcon = NULL;
744  flags = 0;
745 
746  Icon->UpdateCallback(
747  Icon,
748  &newIconOrBitmap,
749  &updateFlags,
750  &newText,
751  Icon->Context
752  );
753 
754  if (newIconOrBitmap)
755  {
756  if (updateFlags & PH_NF_UPDATE_IS_BITMAP)
757  newIcon = PhNfBitmapToIcon(newIconOrBitmap);
758  else
759  newIcon = newIconOrBitmap;
760 
761  flags |= NIF_ICON;
762  }
763 
764  if (newText)
765  flags |= NIF_TIP;
766 
767  if (flags != 0)
768  PhNfpModifyNotifyIcon(Icon->IconId, flags, newText, newIcon);
769 
770  if (newIcon && (updateFlags & PH_NF_UPDATE_IS_BITMAP))
771  DestroyIcon(newIcon);
772 
773  if (newIconOrBitmap && (updateFlags & PH_NF_UPDATE_DESTROY_RESOURCE))
774  {
775  if (updateFlags & PH_NF_UPDATE_IS_BITMAP)
776  DeleteObject(newIconOrBitmap);
777  else
778  DestroyIcon(newIconOrBitmap);
779  }
780 
781  if (newText)
782  PhDereferenceObject(newText);
783 }
784 
786  _Out_ PULONG Width,
787  _Out_ PULONG Height,
788  _Out_ HBITMAP *Bitmap,
789  _Out_opt_ PVOID *Bits,
790  _Out_ HDC *Hdc,
791  _Out_ HBITMAP *OldBitmap
792  )
793 {
794  PhNfpBeginBitmap2(&PhNfpDefaultBitmapContext, Width, Height, Bitmap, Bits, Hdc, OldBitmap);
795 }
796 
798  _Inout_ PPH_NF_BITMAP Context,
799  _Out_ PULONG Width,
800  _Out_ PULONG Height,
801  _Out_ HBITMAP *Bitmap,
802  _Out_opt_ PVOID *Bits,
803  _Out_ HDC *Hdc,
804  _Out_ HBITMAP *OldBitmap
805  )
806 {
807  if (!Context->Initialized)
808  {
809  HDC screenHdc;
810 
811  screenHdc = GetDC(NULL);
812  Context->Hdc = CreateCompatibleDC(screenHdc);
813 
814  memset(&Context->Header, 0, sizeof(BITMAPINFOHEADER));
815  Context->Header.biSize = sizeof(BITMAPINFOHEADER);
816  Context->Header.biWidth = PhSmallIconSize.X;
817  Context->Header.biHeight = PhSmallIconSize.Y;
818  Context->Header.biPlanes = 1;
819  Context->Header.biBitCount = 32;
820  Context->Bitmap = CreateDIBSection(screenHdc, (BITMAPINFO *)&Context->Header, DIB_RGB_COLORS, &Context->Bits, NULL, 0);
821 
822  ReleaseDC(NULL, screenHdc);
823 
824  Context->Initialized = TRUE;
825  }
826 
827  *Width = PhSmallIconSize.X;
828  *Height = PhSmallIconSize.Y;
829  *Bitmap = Context->Bitmap;
830  if (Bits) *Bits = Context->Bits;
831  *Hdc = Context->Hdc;
832  *OldBitmap = SelectObject(Context->Hdc, Context->Bitmap);
833 }
834 
836  VOID
837  )
838 {
839  static PH_GRAPH_DRAW_INFO drawInfo =
840  {
841  16,
842  16,
844  2,
845  RGB(0x00, 0x00, 0x00),
846 
847  16,
848  NULL,
849  NULL,
850  0,
851  0,
852  0,
853  0
854  };
855  ULONG maxDataCount;
856  ULONG lineDataCount;
857  PFLOAT lineData1;
858  PFLOAT lineData2;
859  HBITMAP bitmap;
860  PVOID bits;
861  HDC hdc;
862  HBITMAP oldBitmap;
863  HICON icon;
864  HANDLE maxCpuProcessId;
865  PPH_PROCESS_ITEM maxCpuProcessItem;
866  PH_FORMAT format[8];
867  PPH_STRING text;
868 
869  // Icon
870 
871  PhNfpBeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap);
872  maxDataCount = drawInfo.Width / 2 + 1;
873  lineData1 = _alloca(maxDataCount * sizeof(FLOAT));
874  lineData2 = _alloca(maxDataCount * sizeof(FLOAT));
875 
876  lineDataCount = min(maxDataCount, PhCpuKernelHistory.Count);
877  PhCopyCircularBuffer_FLOAT(&PhCpuKernelHistory, lineData1, lineDataCount);
878  PhCopyCircularBuffer_FLOAT(&PhCpuUserHistory, lineData2, lineDataCount);
879 
880  drawInfo.LineDataCount = lineDataCount;
881  drawInfo.LineData1 = lineData1;
882  drawInfo.LineData2 = lineData2;
883  drawInfo.LineColor1 = PhCsColorCpuKernel;
884  drawInfo.LineColor2 = PhCsColorCpuUser;
887 
888  if (bits)
889  PhDrawGraphDirect(hdc, bits, &drawInfo);
890 
891  SelectObject(hdc, oldBitmap);
892  icon = PhNfBitmapToIcon(bitmap);
893 
894  // Text
895 
896  if (PhMaxCpuHistory.Count != 0)
897  maxCpuProcessId = (HANDLE)PhGetItemCircularBuffer_ULONG(&PhMaxCpuHistory, 0);
898  else
899  maxCpuProcessId = NULL;
900 
901  if (maxCpuProcessId)
902  maxCpuProcessItem = PhReferenceProcessItem(maxCpuProcessId);
903  else
904  maxCpuProcessItem = NULL;
905 
906  PhInitFormatS(&format[0], L"CPU Usage: ");
907  PhInitFormatF(&format[1], (PhCpuKernelUsage + PhCpuUserUsage) * 100, 2);
908  PhInitFormatC(&format[2], '%');
909 
910  if (maxCpuProcessItem)
911  {
912  PhInitFormatC(&format[3], '\n');
913  PhInitFormatSR(&format[4], maxCpuProcessItem->ProcessName->sr);
914  PhInitFormatS(&format[5], L": ");
915  PhInitFormatF(&format[6], maxCpuProcessItem->CpuUsage * 100, 2);
916  PhInitFormatC(&format[7], '%');
917  }
918 
919  text = PhFormat(format, maxCpuProcessItem ? 8 : 3, 128);
920  if (maxCpuProcessItem) PhDereferenceObject(maxCpuProcessItem);
921 
922  PhNfpModifyNotifyIcon(PH_ICON_CPU_HISTORY, NIF_TIP | NIF_ICON, text, icon);
923 
924  DestroyIcon(icon);
925  PhDereferenceObject(text);
926 }
927 
929  VOID
930  )
931 {
932  static PH_GRAPH_DRAW_INFO drawInfo =
933  {
934  16,
935  16,
937  2,
938  RGB(0x00, 0x00, 0x00),
939 
940  16,
941  NULL,
942  NULL,
943  0,
944  0,
945  0,
946  0
947  };
948  ULONG maxDataCount;
949  ULONG lineDataCount;
950  PFLOAT lineData1;
951  PFLOAT lineData2;
952  FLOAT max;
953  ULONG i;
954  HBITMAP bitmap;
955  PVOID bits;
956  HDC hdc;
957  HBITMAP oldBitmap;
958  HICON icon;
959  HANDLE maxIoProcessId;
960  PPH_PROCESS_ITEM maxIoProcessItem;
961  PH_FORMAT format[8];
962  PPH_STRING text;
963 
964  // Icon
965 
966  PhNfpBeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap);
967  maxDataCount = drawInfo.Width / 2 + 1;
968  lineData1 = _alloca(maxDataCount * sizeof(FLOAT));
969  lineData2 = _alloca(maxDataCount * sizeof(FLOAT));
970 
971  lineDataCount = min(maxDataCount, PhIoReadHistory.Count);
972  max = 1024 * 1024; // minimum scaling of 1 MB.
973 
974  for (i = 0; i < lineDataCount; i++)
975  {
976  lineData1[i] =
977  (FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoReadHistory, i) +
978  (FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoOtherHistory, i);
979  lineData2[i] =
980  (FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoWriteHistory, i);
981 
982  if (max < lineData1[i] + lineData2[i])
983  max = lineData1[i] + lineData2[i];
984  }
985 
986  PhDivideSinglesBySingle(lineData1, max, lineDataCount);
987  PhDivideSinglesBySingle(lineData2, max, lineDataCount);
988 
989  drawInfo.LineDataCount = lineDataCount;
990  drawInfo.LineData1 = lineData1;
991  drawInfo.LineData2 = lineData2;
992  drawInfo.LineColor1 = PhCsColorIoReadOther;
993  drawInfo.LineColor2 = PhCsColorIoWrite;
996 
997  if (bits)
998  PhDrawGraphDirect(hdc, bits, &drawInfo);
999 
1000  SelectObject(hdc, oldBitmap);
1001  icon = PhNfBitmapToIcon(bitmap);
1002 
1003  // Text
1004 
1005  if (PhMaxIoHistory.Count != 0)
1006  maxIoProcessId = (HANDLE)PhGetItemCircularBuffer_ULONG(&PhMaxIoHistory, 0);
1007  else
1008  maxIoProcessId = NULL;
1009 
1010  if (maxIoProcessId)
1011  maxIoProcessItem = PhReferenceProcessItem(maxIoProcessId);
1012  else
1013  maxIoProcessItem = NULL;
1014 
1015  PhInitFormatS(&format[0], L"I/O\nR: ");
1016  PhInitFormatSize(&format[1], PhIoReadDelta.Delta);
1017  PhInitFormatS(&format[2], L"\nW: ");
1018  PhInitFormatSize(&format[3], PhIoWriteDelta.Delta);
1019  PhInitFormatS(&format[4], L"\nO: ");
1020  PhInitFormatSize(&format[5], PhIoOtherDelta.Delta);
1021 
1022  if (maxIoProcessItem)
1023  {
1024  PhInitFormatC(&format[6], '\n');
1025  PhInitFormatSR(&format[7], maxIoProcessItem->ProcessName->sr);
1026  }
1027 
1028  text = PhFormat(format, maxIoProcessItem ? 8 : 6, 128);
1029  if (maxIoProcessItem) PhDereferenceObject(maxIoProcessItem);
1030 
1031  PhNfpModifyNotifyIcon(PH_ICON_IO_HISTORY, NIF_TIP | NIF_ICON, text, icon);
1032 
1033  DestroyIcon(icon);
1034  PhDereferenceObject(text);
1035 }
1036 
1038  VOID
1039  )
1040 {
1041  static PH_GRAPH_DRAW_INFO drawInfo =
1042  {
1043  16,
1044  16,
1045  0,
1046  2,
1047  RGB(0x00, 0x00, 0x00),
1048 
1049  16,
1050  NULL,
1051  NULL,
1052  0,
1053  0,
1054  0,
1055  0
1056  };
1057  ULONG maxDataCount;
1058  ULONG lineDataCount;
1059  PFLOAT lineData1;
1060  ULONG i;
1061  HBITMAP bitmap;
1062  PVOID bits;
1063  HDC hdc;
1064  HBITMAP oldBitmap;
1065  HICON icon;
1066  DOUBLE commitFraction;
1067  PH_FORMAT format[5];
1068  PPH_STRING text;
1069 
1070  // Icon
1071 
1072  PhNfpBeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap);
1073  maxDataCount = drawInfo.Width / 2 + 1;
1074  lineData1 = _alloca(maxDataCount * sizeof(FLOAT));
1075 
1076  lineDataCount = min(maxDataCount, PhCommitHistory.Count);
1077 
1078  for (i = 0; i < lineDataCount; i++)
1079  lineData1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&PhCommitHistory, i);
1080 
1081  PhDivideSinglesBySingle(lineData1, (FLOAT)PhPerfInformation.CommitLimit, lineDataCount);
1082 
1083  drawInfo.LineDataCount = lineDataCount;
1084  drawInfo.LineData1 = lineData1;
1085  drawInfo.LineColor1 = PhCsColorPrivate;
1087 
1088  if (bits)
1089  PhDrawGraphDirect(hdc, bits, &drawInfo);
1090 
1091  SelectObject(hdc, oldBitmap);
1092  icon = PhNfBitmapToIcon(bitmap);
1093 
1094  // Text
1095 
1097 
1098  PhInitFormatS(&format[0], L"Commit: ");
1099  PhInitFormatSize(&format[1], UInt32x32To64(PhPerfInformation.CommittedPages, PAGE_SIZE));
1100  PhInitFormatS(&format[2], L" (");
1101  PhInitFormatF(&format[3], commitFraction * 100, 2);
1102  PhInitFormatS(&format[4], L"%)");
1103 
1104  text = PhFormat(format, 5, 96);
1105 
1106  PhNfpModifyNotifyIcon(PH_ICON_COMMIT_HISTORY, NIF_TIP | NIF_ICON, text, icon);
1107 
1108  DestroyIcon(icon);
1109  PhDereferenceObject(text);
1110 }
1111 
1113  VOID
1114  )
1115 {
1116  static PH_GRAPH_DRAW_INFO drawInfo =
1117  {
1118  16,
1119  16,
1120  0,
1121  2,
1122  RGB(0x00, 0x00, 0x00),
1123 
1124  16,
1125  NULL,
1126  NULL,
1127  0,
1128  0,
1129  0,
1130  0
1131  };
1132  ULONG maxDataCount;
1133  ULONG lineDataCount;
1134  PFLOAT lineData1;
1135  ULONG i;
1136  HBITMAP bitmap;
1137  PVOID bits;
1138  HDC hdc;
1139  HBITMAP oldBitmap;
1140  HICON icon;
1141  ULONG physicalUsage;
1142  FLOAT physicalFraction;
1143  PH_FORMAT format[5];
1144  PPH_STRING text;
1145 
1146  // Icon
1147 
1148  PhNfpBeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap);
1149  maxDataCount = drawInfo.Width / 2 + 1;
1150  lineData1 = _alloca(maxDataCount * sizeof(FLOAT));
1151 
1152  lineDataCount = min(maxDataCount, PhCommitHistory.Count);
1153 
1154  for (i = 0; i < lineDataCount; i++)
1155  lineData1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&PhPhysicalHistory, i);
1156 
1158 
1159  drawInfo.LineDataCount = lineDataCount;
1160  drawInfo.LineData1 = lineData1;
1161  drawInfo.LineColor1 = PhCsColorPhysical;
1163 
1164  if (bits)
1165  PhDrawGraphDirect(hdc, bits, &drawInfo);
1166 
1167  SelectObject(hdc, oldBitmap);
1168  icon = PhNfBitmapToIcon(bitmap);
1169 
1170  // Text
1171 
1173  physicalFraction = (FLOAT)physicalUsage / PhSystemBasicInformation.NumberOfPhysicalPages;
1174 
1175  PhInitFormatS(&format[0], L"Physical Memory: ");
1176  PhInitFormatSize(&format[1], UInt32x32To64(physicalUsage, PAGE_SIZE));
1177  PhInitFormatS(&format[2], L" (");
1178  PhInitFormatF(&format[3], physicalFraction * 100, 2);
1179  PhInitFormatS(&format[4], L"%)");
1180 
1181  text = PhFormat(format, 5, 96);
1182 
1183  PhNfpModifyNotifyIcon(PH_ICON_PHYSICAL_HISTORY, NIF_TIP | NIF_ICON, text, icon);
1184 
1185  DestroyIcon(icon);
1186  PhDereferenceObject(text);
1187 }
1188 
1190  VOID
1191  )
1192 {
1193  ULONG width;
1194  ULONG height;
1195  HBITMAP bitmap;
1196  HDC hdc;
1197  HBITMAP oldBitmap;
1198  HICON icon;
1199  HANDLE maxCpuProcessId;
1200  PPH_PROCESS_ITEM maxCpuProcessItem;
1201  PPH_STRING maxCpuText = NULL;
1202  PPH_STRING text;
1203 
1204  // Icon
1205 
1206  PhNfpBeginBitmap(&width, &height, &bitmap, NULL, &hdc, &oldBitmap);
1207 
1208  // This stuff is copied from CpuUsageIcon.cs (PH 1.x).
1209  {
1210  COLORREF kColor = PhCsColorCpuKernel;
1211  COLORREF uColor = PhCsColorCpuUser;
1212  COLORREF kbColor = PhHalveColorBrightness(PhCsColorCpuKernel);
1213  COLORREF ubColor = PhHalveColorBrightness(PhCsColorCpuUser);
1214  FLOAT k = PhCpuKernelUsage;
1215  FLOAT u = PhCpuUserUsage;
1216  LONG kl = (LONG)(k * height);
1217  LONG ul = (LONG)(u * height);
1218  RECT rect;
1219  HBRUSH dcBrush;
1220  HBRUSH dcPen;
1221  POINT points[2];
1222 
1223  dcBrush = GetStockObject(DC_BRUSH);
1224  dcPen = GetStockObject(DC_PEN);
1225  rect.left = 0;
1226  rect.top = 0;
1227  rect.right = width;
1228  rect.bottom = height;
1229  SetDCBrushColor(hdc, RGB(0x00, 0x00, 0x00));
1230  FillRect(hdc, &rect, dcBrush);
1231 
1232  // Draw the base line.
1233  if (kl + ul == 0)
1234  {
1235  SelectObject(hdc, dcPen);
1236  SetDCPenColor(hdc, uColor);
1237  points[0].x = 0;
1238  points[0].y = height - 1;
1239  points[1].x = width;
1240  points[1].y = height - 1;
1241  Polyline(hdc, points, 2);
1242  }
1243  else
1244  {
1245  rect.left = 0;
1246  rect.top = height - ul - kl;
1247  rect.right = width;
1248  rect.bottom = height - kl;
1249  SetDCBrushColor(hdc, ubColor);
1250  FillRect(hdc, &rect, dcBrush);
1251 
1252  points[0].x = 0;
1253  points[0].y = height - 1 - ul - kl;
1254  if (points[0].y < 0) points[0].y = 0;
1255  points[1].x = width;
1256  points[1].y = points[0].y;
1257  SelectObject(hdc, dcPen);
1258  SetDCPenColor(hdc, uColor);
1259  Polyline(hdc, points, 2);
1260 
1261  if (kl != 0)
1262  {
1263  rect.left = 0;
1264  rect.top = height - kl;
1265  rect.right = width;
1266  rect.bottom = height;
1267  SetDCBrushColor(hdc, kbColor);
1268  FillRect(hdc, &rect, dcBrush);
1269 
1270  points[0].x = 0;
1271  points[0].y = height - 1 - kl;
1272  if (points[0].y < 0) points[0].y = 0;
1273  points[1].x = width;
1274  points[1].y = points[0].y;
1275  SelectObject(hdc, dcPen);
1276  SetDCPenColor(hdc, kColor);
1277  Polyline(hdc, points, 2);
1278  }
1279  }
1280  }
1281 
1282  SelectObject(hdc, oldBitmap);
1283  icon = PhNfBitmapToIcon(bitmap);
1284 
1285  // Text
1286 
1287  if (PhMaxCpuHistory.Count != 0)
1288  maxCpuProcessId = (HANDLE)PhGetItemCircularBuffer_ULONG(&PhMaxCpuHistory, 0);
1289  else
1290  maxCpuProcessId = NULL;
1291 
1292  if (maxCpuProcessId)
1293  {
1294  if (maxCpuProcessItem = PhReferenceProcessItem(maxCpuProcessId))
1295  {
1296  maxCpuText = PhFormatString(
1297  L"\n%s: %.2f%%",
1298  maxCpuProcessItem->ProcessName->Buffer,
1299  maxCpuProcessItem->CpuUsage * 100
1300  );
1301  PhDereferenceObject(maxCpuProcessItem);
1302  }
1303  }
1304 
1305  text = PhFormatString(L"CPU Usage: %.2f%%%s", (PhCpuKernelUsage + PhCpuUserUsage) * 100, PhGetStringOrEmpty(maxCpuText));
1306  if (maxCpuText) PhDereferenceObject(maxCpuText);
1307 
1308  PhNfpModifyNotifyIcon(PH_ICON_CPU_USAGE, NIF_TIP | NIF_ICON, text, icon);
1309 
1310  DestroyIcon(icon);
1311  PhDereferenceObject(text);
1312 }