Process Hacker
sysinfo.c
Go to the documentation of this file.
1 /*
2  * Process Hacker -
3  * system information window
4  *
5  * Copyright (C) 2011-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 /*
24  * This file is divided into two parts:
25  *
26  * System Information framework. The "framework" handles creation, layout
27  * and events for the top-level window itself. It manages the list of
28  * sections.
29  *
30  * Default sections. The CPU, Memory and I/O sections are also implemented
31  * in this file.
32  *
33  * A section is an object that provides information to the user about a
34  * type of system resource. The CPU, Memory and I/O sections are added
35  * automatically to every System Information window. Plugins can also add
36  * sections to the window. There are two views: summary and section. In
37  * summary view, rows of graphs are displayed in the window, one graph for
38  * each section. The section is responsible for providing the graph data
39  * and any text to draw on the left-hand side of the graph. In section view,
40  * the graphs become mini-graphs on the left-hand side of the window. The
41  * section displays its own embedded dialog in the remaining space. Any
42  * controls contained in this dialog, including graphs, are the
43  * responsibility of the section.
44  *
45  * Users can enter section view by:
46  * * Clicking on a graph or mini-graph.
47  * * Pressing a number from 1 to 9.
48  * * Using the tab or arrow keys to select a graph and pressing space or
49  * enter.
50  *
51  * Users can return to summary view by:
52  * * Clicking "Back" on the left-hand side of the window.
53  * * Pressing Backspace.
54  * * Using the tab or arrow keys to select "Back" and pressing space or
55  * enter.
56  */
57 
58 #include <phapp.h>
59 #include <kphuser.h>
60 #include <symprv.h>
61 #include <settings.h>
62 #include <sysinfo.h>
63 #include <phplug.h>
64 #include <windowsx.h>
65 #include <uxtheme.h>
66 #include <vssym32.h>
67 #include <math.h>
68 #include <sysinfop.h>
69 
70 static HANDLE PhSipThread = NULL;
71 static HWND PhSipWindow = NULL;
72 static PPH_LIST PhSipDialogList = NULL;
73 static PH_EVENT InitializedEvent = PH_EVENT_INIT;
74 static PH_LAYOUT_MANAGER WindowLayoutManager;
75 static RECT MinimumSize;
76 static PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration;
77 
78 static PPH_LIST SectionList;
79 static PH_SYSINFO_PARAMETERS CurrentParameters;
80 static PH_SYSINFO_VIEW_TYPE CurrentView;
81 static PPH_SYSINFO_SECTION CurrentSection;
82 static HWND ContainerControl;
83 static HWND SeparatorControl;
84 static HWND RestoreSummaryControl;
85 static WNDPROC RestoreSummaryControlOldWndProc;
86 static BOOLEAN RestoreSummaryControlHot;
87 static BOOLEAN RestoreSummaryControlHasFocus;
88 
89 static _EnableThemeDialogTexture EnableThemeDialogTexture_I;
90 static HTHEME ThemeData;
91 static BOOLEAN ThemeHasItemBackground;
92 
93 static PPH_SYSINFO_SECTION CpuSection;
94 static HWND CpuDialog;
95 static PH_LAYOUT_MANAGER CpuLayoutManager;
96 static RECT CpuGraphMargin;
97 static HWND CpuGraphHandle;
98 static PH_GRAPH_STATE CpuGraphState;
99 static HWND *CpusGraphHandle;
100 static PPH_GRAPH_STATE CpusGraphState;
101 static BOOLEAN OneGraphPerCpu;
102 static HWND CpuPanel;
103 static ULONG CpuTicked;
104 static ULONG NumberOfProcessors;
105 static PSYSTEM_INTERRUPT_INFORMATION InterruptInformation;
106 static PPROCESSOR_POWER_INFORMATION PowerInformation;
107 static PSYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION CurrentPerformanceDistribution;
108 static PSYSTEM_PROCESSOR_PERFORMANCE_DISTRIBUTION PreviousPerformanceDistribution;
109 static PH_UINT32_DELTA ContextSwitchesDelta;
110 static PH_UINT32_DELTA InterruptsDelta;
111 static PH_UINT64_DELTA DpcsDelta;
112 static PH_UINT32_DELTA SystemCallsDelta;
113 
114 static PPH_SYSINFO_SECTION MemorySection;
115 static HWND MemoryDialog;
116 static PH_LAYOUT_MANAGER MemoryLayoutManager;
117 static RECT MemoryGraphMargin;
118 static HWND CommitGraphHandle;
119 static PH_GRAPH_STATE CommitGraphState;
120 static HWND PhysicalGraphHandle;
121 static PH_GRAPH_STATE PhysicalGraphState;
122 static HWND MemoryPanel;
123 static ULONG MemoryTicked;
124 static PH_UINT32_DELTA PagedAllocsDelta;
125 static PH_UINT32_DELTA PagedFreesDelta;
126 static PH_UINT32_DELTA NonPagedAllocsDelta;
127 static PH_UINT32_DELTA NonPagedFreesDelta;
128 static PH_UINT32_DELTA PageFaultsDelta;
129 static PH_UINT32_DELTA PageReadsDelta;
130 static PH_UINT32_DELTA PagefileWritesDelta;
131 static PH_UINT32_DELTA MappedWritesDelta;
132 static BOOLEAN MmAddressesInitialized;
133 static PSIZE_T MmSizeOfPagedPoolInBytes;
134 static PSIZE_T MmMaximumNonPagedPoolInBytes;
135 
136 static PPH_SYSINFO_SECTION IoSection;
137 static HWND IoDialog;
138 static PH_LAYOUT_MANAGER IoLayoutManager;
139 static HWND IoGraphHandle;
140 static PH_GRAPH_STATE IoGraphState;
141 static HWND IoPanel;
142 static ULONG IoTicked;
143 static PH_UINT64_DELTA IoReadDelta;
144 static PH_UINT64_DELTA IoWriteDelta;
145 static PH_UINT64_DELTA IoOtherDelta;
146 
147 static BOOLEAN AlwaysOnTop;
148 
150  _In_opt_ PWSTR SectionName
151  )
152 {
153  if (!PhSipWindow)
154  {
155  if (!(PhSipThread = PhCreateThread(0, PhSipSysInfoThreadStart, NULL)))
156  {
157  PhShowStatus(PhMainWndHandle, L"Unable to create the system information window", 0, GetLastError());
158  return;
159  }
160 
161  PhWaitForEvent(&InitializedEvent, NULL);
162  }
163 
164  SendMessage(PhSipWindow, SI_MSG_SYSINFO_ACTIVATE, 0, 0);
165 }
166 
168  _In_ PVOID Parameter
169  )
170 {
171  PH_AUTO_POOL autoPool;
172  BOOL result;
173  MSG message;
174  HACCEL acceleratorTable;
175  BOOLEAN processed;
176 
177  PhInitializeAutoPool(&autoPool);
178 
179  PhSipWindow = CreateDialog(
181  MAKEINTRESOURCE(IDD_SYSINFO),
182  NULL,
184  );
185 
186  PhSetEvent(&InitializedEvent);
187 
188  acceleratorTable = LoadAccelerators(PhInstanceHandle, MAKEINTRESOURCE(IDR_SYSINFO_ACCEL));
189 
190  while (result = GetMessage(&message, NULL, 0, 0))
191  {
192  if (result == -1)
193  break;
194 
195  processed = FALSE;
196 
197  if (
198  message.hwnd == PhSipWindow ||
199  IsChild(PhSipWindow, message.hwnd)
200  )
201  {
202  if (TranslateAccelerator(PhSipWindow, acceleratorTable, &message))
203  processed = TRUE;
204  }
205 
206  if (!processed && PhSipDialogList)
207  {
208  ULONG i;
209 
210  for (i = 0; i < PhSipDialogList->Count; i++)
211  {
212  if (IsDialogMessage((HWND)PhSipDialogList->Items[i], &message))
213  {
214  processed = TRUE;
215  break;
216  }
217  }
218  }
219 
220  if (!processed)
221  {
222  if (!IsDialogMessage(PhSipWindow, &message))
223  {
224  TranslateMessage(&message);
225  DispatchMessage(&message);
226  }
227  }
228 
229  PhDrainAutoPool(&autoPool);
230  }
231 
232  PhDeleteAutoPool(&autoPool);
233  PhResetEvent(&InitializedEvent);
234  NtClose(PhSipThread);
235 
236  PhSipWindow = NULL;
237  PhSipThread = NULL;
238 
239  if (PhSipDialogList)
240  {
241  PhDereferenceObject(PhSipDialogList);
242  PhSipDialogList = NULL;
243  }
244 
245  return STATUS_SUCCESS;
246 }
247 
248 INT_PTR CALLBACK PhSipSysInfoDialogProc(
249  _In_ HWND hwndDlg,
250  _In_ UINT uMsg,
251  _In_ WPARAM wParam,
252  _In_ LPARAM lParam
253  )
254 {
255  switch (uMsg)
256  {
257  case WM_INITDIALOG:
258  {
259  PhSipWindow = hwndDlg;
261  }
262  break;
263  case WM_DESTROY:
264  {
265  PhSipOnDestroy();
266  }
267  break;
268  case WM_NCDESTROY:
269  {
271  }
272  break;
273  case WM_SHOWWINDOW:
274  {
275  PhSipOnShowWindow(!!wParam, (ULONG)lParam);
276  }
277  break;
278  case WM_SIZE:
279  {
280  PhSipOnSize();
281  }
282  break;
283  case WM_SIZING:
284  {
285  PhSipOnSizing((ULONG)wParam, (PRECT)lParam);
286  }
287  break;
288  case WM_THEMECHANGED:
289  {
291  }
292  break;
293  case WM_COMMAND:
294  {
295  PhSipOnCommand(LOWORD(wParam), HIWORD(wParam));
296  }
297  break;
298  case WM_NOTIFY:
299  {
300  LRESULT result;
301 
302  if (PhSipOnNotify((NMHDR *)lParam, &result))
303  {
304  SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, result);
305  return TRUE;
306  }
307  }
308  break;
309  case WM_DRAWITEM:
310  {
311  if (PhSipOnDrawItem(wParam, (DRAWITEMSTRUCT *)lParam))
312  return TRUE;
313  }
314  break;
315  }
316 
317  if (uMsg >= SI_MSG_SYSINFO_FIRST && uMsg <= SI_MSG_SYSINFO_LAST)
318  {
319  PhSipOnUserMessage(uMsg, wParam, lParam);
320  }
321 
322  return FALSE;
323 }
324 
325 INT_PTR CALLBACK PhSipContainerDialogProc(
326  _In_ HWND hwndDlg,
327  _In_ UINT uMsg,
328  _In_ WPARAM wParam,
329  _In_ LPARAM lParam
330  )
331 {
332  return FALSE;
333 }
334 
336  VOID
337  )
338 {
339  PhInitializeLayoutManager(&WindowLayoutManager, PhSipWindow);
340 
341  PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhSipWindow, IDC_INSTRUCTION), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM);
342  PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhSipWindow, IDC_ALWAYSONTOP), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
343  PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(PhSipWindow, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
344 
348  NULL,
349  &ProcessesUpdatedRegistration
350  );
351 
352  ContainerControl = CreateDialog(
354  MAKEINTRESOURCE(IDD_CONTAINER),
355  PhSipWindow,
357  );
358 
359  if (!EnableThemeDialogTexture_I)
360  EnableThemeDialogTexture_I = PhGetModuleProcAddress(L"uxtheme.dll", "EnableThemeDialogTexture");
361 
362  PhSetControlTheme(PhSipWindow, L"explorer");
364 }
365 
367  VOID
368  )
369 {
372  &ProcessesUpdatedRegistration
373  );
374 
375  if (CurrentSection)
376  PhSetStringSetting2(L"SysInfoWindowSection", &CurrentSection->Name);
377  else
378  PhSetStringSetting(L"SysInfoWindowSection", L"");
379 
380  PhSetIntegerSetting(L"SysInfoWindowAlwaysOnTop", AlwaysOnTop);
381 
382  PhSaveWindowPlacementToSetting(L"SysInfoWindowPosition", L"SysInfoWindowSize", PhSipWindow);
383 }
384 
386  VOID
387  )
388 {
389  ULONG i;
390  PPH_SYSINFO_SECTION section;
391 
392  for (i = 0; i < SectionList->Count; i++)
393  {
394  section = SectionList->Items[i];
395  PhSipDestroySection(section);
396  }
397 
398  PhDereferenceObject(SectionList);
399  SectionList = NULL;
401 
402  if (ThemeData)
403  {
404  CloseThemeData_I(ThemeData);
405  ThemeData = NULL;
406  }
407 
408  PhDeleteLayoutManager(&WindowLayoutManager);
409  PostQuitMessage(0);
410 }
411 
413  _In_ BOOLEAN Showing,
414  _In_ ULONG State
415  )
416 {
417  RECT buttonRect;
418  RECT clientRect;
419  PPH_STRING sectionName;
420  PPH_SYSINFO_SECTION section;
421 
422  if (SectionList)
423  return;
424 
425  SectionList = PhCreateList(8);
427  CurrentView = SysInfoSummaryView;
428  CurrentSection = NULL;
429 
430  CpuSection = PhSipCreateInternalSection(L"CPU", 0, PhSipCpuSectionCallback);
431  MemorySection = PhSipCreateInternalSection(L"Memory", 0, PhSipMemorySectionCallback);
432  IoSection = PhSipCreateInternalSection(L"I/O", 0, PhSipIoSectionCallback);
433 
434  if (PhPluginsEnabled)
435  {
437 
438  pointers.WindowHandle = PhSipWindow;
440  pointers.FindSection = PhSipFindSection;
444  }
445 
446  SeparatorControl = CreateWindow(
447  L"STATIC",
448  NULL,
449  WS_CHILD | SS_OWNERDRAW,
450  0,
451  0,
452  3,
453  3,
454  PhSipWindow,
455  (HMENU)IDC_SEPARATOR,
457  NULL
458  );
459 
460  RestoreSummaryControl = CreateWindow(
461  L"STATIC",
462  NULL,
463  WS_CHILD | WS_TABSTOP | SS_OWNERDRAW | SS_NOTIFY,
464  0,
465  0,
466  3,
467  3,
468  PhSipWindow,
469  (HMENU)IDC_RESET,
471  NULL
472  );
473  RestoreSummaryControlOldWndProc = (WNDPROC)GetWindowLongPtr(RestoreSummaryControl, GWLP_WNDPROC);
474  SetWindowLongPtr(RestoreSummaryControl, GWLP_WNDPROC, (LONG_PTR)PhSipPanelHookWndProc);
475  RestoreSummaryControlHot = FALSE;
476 
477  if (EnableThemeDialogTexture_I)
478  EnableThemeDialogTexture_I(ContainerControl, ETDT_ENABLETAB);
479 
480  GetWindowRect(GetDlgItem(PhSipWindow, IDOK), &buttonRect);
481  MapWindowPoints(NULL, PhSipWindow, (POINT *)&buttonRect, 2);
482  GetClientRect(PhSipWindow, &clientRect);
483 
484  MinimumSize.left = 0;
485  MinimumSize.top = 0;
486  MinimumSize.right = WindowsVersion >= WINDOWS_VISTA ? 430 : 370; // XP doesn't have the Memory Lists group
487  MinimumSize.bottom = 290;
488  MapDialogRect(PhSipWindow, &MinimumSize);
489 
490  MinimumSize.right += CurrentParameters.PanelWidth;
491  MinimumSize.right += GetSystemMetrics(SM_CXFRAME) * 2;
492  MinimumSize.bottom += GetSystemMetrics(SM_CYFRAME) * 2;
493 
494  if (SectionList->Count != 0)
495  {
496  ULONG newMinimumHeight;
497 
498  newMinimumHeight =
499  GetSystemMetrics(SM_CYCAPTION) +
501  CurrentParameters.MinimumGraphHeight * SectionList->Count +
502  CurrentParameters.MinimumGraphHeight + // Back button
503  PH_SYSINFO_GRAPH_PADDING * SectionList->Count +
505  clientRect.bottom - buttonRect.top +
506  GetSystemMetrics(SM_CYFRAME) * 2;
507 
508  if (newMinimumHeight > (ULONG)MinimumSize.bottom)
509  MinimumSize.bottom = newMinimumHeight;
510  }
511 
512  PhLoadWindowPlacementFromSetting(L"SysInfoWindowPosition", L"SysInfoWindowSize", PhSipWindow);
513 
514  sectionName = PhGetStringSetting(L"SysInfoWindowSection");
515 
516  if (sectionName->Length != 0 && (section = PhSipFindSection(&sectionName->sr)))
517  {
518  PhSipEnterSectionView(section);
519  }
520 
521  PhDereferenceObject(sectionName);
522 
523  AlwaysOnTop = (BOOLEAN)PhGetIntegerSetting(L"SysInfoWindowAlwaysOnTop");
524  Button_SetCheck(GetDlgItem(PhSipWindow, IDC_ALWAYSONTOP), AlwaysOnTop ? BST_CHECKED : BST_UNCHECKED);
526 
527  PhSipOnSize();
529 }
530 
532  VOID
533  )
534 {
535  PhLayoutManagerLayout(&WindowLayoutManager);
536 
537  if (SectionList && SectionList->Count != 0)
538  {
539  if (CurrentView == SysInfoSummaryView)
541  else if (CurrentView == SysInfoSectionView)
543  }
544 }
545 
547  _In_ ULONG Edge,
548  _In_ PRECT DragRectangle
549  )
550 {
551  PhResizingMinimumSize(DragRectangle, Edge, MinimumSize.right, MinimumSize.bottom);
552 }
553 
555  VOID
556  )
557 {
559 }
560 
562  _In_ ULONG Id,
563  _In_ ULONG Code
564  )
565 {
566  switch (Id)
567  {
568  case IDCANCEL:
569  case IDOK:
570  DestroyWindow(PhSipWindow);
571  break;
572  case IDC_ALWAYSONTOP:
573  {
574  AlwaysOnTop = Button_GetCheck(GetDlgItem(PhSipWindow, IDC_ALWAYSONTOP)) == BST_CHECKED;
576  }
577  break;
578  case IDC_RESET:
579  {
580  if (Code == STN_CLICKED)
581  {
583  }
584  }
585  break;
586  case IDC_BACK:
587  {
589  }
590  break;
591  case IDC_REFRESH:
592  {
594  }
595  break;
596  case IDC_PAUSE:
597  {
599  }
600  break;
601  }
602 
603  if (SectionList && Id >= ID_DIGIT1 && Id <= ID_DIGIT9)
604  {
605  ULONG index;
606 
607  index = Id - ID_DIGIT1;
608 
609  if (index < SectionList->Count)
610  PhSipEnterSectionView(SectionList->Items[index]);
611  }
612 
613  if (SectionList && Code == STN_CLICKED)
614  {
615  ULONG i;
616  PPH_SYSINFO_SECTION section;
617 
618  for (i = 0; i < SectionList->Count; i++)
619  {
620  section = SectionList->Items[i];
621 
622  if (Id == section->PanelId)
623  {
624  PhSipEnterSectionView(section);
625  break;
626  }
627  }
628  }
629 }
630 
632  _In_ NMHDR *Header,
633  _Out_ LRESULT *Result
634  )
635 {
636  switch (Header->code)
637  {
638  case GCN_GETDRAWINFO:
639  {
640  PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header;
641  PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;
642  ULONG i;
643  PPH_SYSINFO_SECTION section;
644 
645  for (i = 0; i < SectionList->Count; i++)
646  {
647  section = SectionList->Items[i];
648 
649  if (getDrawInfo->Header.hwndFrom == section->GraphHandle)
650  {
651  section->Callback(section, SysInfoGraphGetDrawInfo, drawInfo, 0);
652 
653  if (CurrentView == SysInfoSectionView)
654  drawInfo->Flags &= ~PH_GRAPH_USE_GRID;
655 
656  break;
657  }
658  }
659  }
660  break;
661  case GCN_GETTOOLTIPTEXT:
662  {
663  PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header;
664  ULONG i;
665  PPH_SYSINFO_SECTION section;
666 
667  if (getTooltipText->Index < getTooltipText->TotalCount)
668  {
669  for (i = 0; i < SectionList->Count; i++)
670  {
671  section = SectionList->Items[i];
672 
673  if (getTooltipText->Header.hwndFrom == section->GraphHandle)
674  {
675  PH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT graphGetTooltipText;
676 
677  graphGetTooltipText.Index = getTooltipText->Index;
678  PhInitializeEmptyStringRef(&graphGetTooltipText.Text);
679 
680  section->Callback(section, SysInfoGraphGetTooltipText, &graphGetTooltipText, 0);
681 
682  getTooltipText->Text = graphGetTooltipText.Text;
683 
684  break;
685  }
686  }
687  }
688  }
689  break;
690  case GCN_DRAWPANEL:
691  {
692  PPH_GRAPH_DRAWPANEL drawPanel = (PPH_GRAPH_DRAWPANEL)Header;
693  ULONG i;
694  PPH_SYSINFO_SECTION section;
695 
696  if (CurrentView == SysInfoSummaryView)
697  {
698  for (i = 0; i < SectionList->Count; i++)
699  {
700  section = SectionList->Items[i];
701 
702  if (drawPanel->Header.hwndFrom == section->GraphHandle)
703  {
704  PhSipDrawPanel(section, drawPanel->hdc, &drawPanel->Rect);
705  break;
706  }
707  }
708  }
709  }
710  break;
711  case GCN_MOUSEEVENT:
712  {
713  PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Header;
714  ULONG i;
715  PPH_SYSINFO_SECTION section;
716 
717  for (i = 0; i < SectionList->Count; i++)
718  {
719  section = SectionList->Items[i];
720 
721  if (mouseEvent->Header.hwndFrom == section->GraphHandle)
722  {
723  if (mouseEvent->Message == WM_LBUTTONDOWN)
724  {
725  PhSipEnterSectionView(section);
726  }
727 
728  break;
729  }
730  }
731  }
732  break;
733  }
734 
735  return FALSE;
736 }
737 
739  _In_ ULONG_PTR Id,
740  _In_ DRAWITEMSTRUCT *DrawItemStruct
741  )
742 {
743  ULONG i;
744  PPH_SYSINFO_SECTION section;
745 
746  if (Id == IDC_RESET)
747  {
748  PhSipDrawRestoreSummaryPanel(DrawItemStruct->hDC, &DrawItemStruct->rcItem);
749  return TRUE;
750  }
751  else if (Id == IDC_SEPARATOR)
752  {
753  PhSipDrawSeparator(DrawItemStruct->hDC, &DrawItemStruct->rcItem);
754  return TRUE;
755  }
756 
757  for (i = 0; i < SectionList->Count; i++)
758  {
759  section = SectionList->Items[i];
760 
761  if (Id == section->PanelId)
762  {
763  PhSipDrawPanel(section, DrawItemStruct->hDC, &DrawItemStruct->rcItem);
764  return TRUE;
765  }
766  }
767 
768  return FALSE;
769 }
770 
772  _In_ ULONG Message,
773  _In_ ULONG_PTR WParam,
774  _In_ ULONG_PTR LParam
775  )
776 {
777  switch (Message)
778  {
780  {
781  if (IsIconic(PhSipWindow))
782  ShowWindow(PhSipWindow, SW_RESTORE);
783  else
784  ShowWindow(PhSipWindow, SW_SHOW);
785 
786  SetForegroundWindow(PhSipWindow);
787  }
788  break;
790  {
791  ULONG i;
792  PPH_SYSINFO_SECTION section;
793 
794  if (SectionList)
795  {
796  for (i = 0; i < SectionList->Count; i++)
797  {
798  section = SectionList->Items[i];
799 
800  section->Callback(section, SysInfoTick, NULL, NULL);
801 
802  section->GraphState.Valid = FALSE;
803  section->GraphState.TooltipIndex = -1;
804  Graph_MoveGrid(section->GraphHandle, 1);
805  Graph_Draw(section->GraphHandle);
807  InvalidateRect(section->GraphHandle, NULL, FALSE);
808 
809  InvalidateRect(section->PanelHandle, NULL, FALSE);
810  }
811  }
812  }
813  break;
815  {
816  ULONG i;
817  PPH_SYSINFO_SECTION section;
818  PH_GRAPH_OPTIONS options;
819 
820  if (SectionList)
821  {
822  for (i = 0; i < SectionList->Count; i++)
823  {
824  section = SectionList->Items[i];
825  Graph_GetOptions(section->GraphHandle, &options);
826  options.FadeOutBackColor = CurrentParameters.GraphBackColor;
827  Graph_SetOptions(section->GraphHandle, &options);
828  }
829  }
830 
831  InvalidateRect(PhSipWindow, NULL, TRUE);
832  }
833  break;
834  }
835 }
836 
838  VOID
839  )
840 {
841  HWND window;
842 
844 
845  window = PhSipWindow;
846 
847  if (window)
848  PostMessage(window, SI_MSG_SYSINFO_CHANGE_SETTINGS, 0, 0);
849 }
850 
852  _Out_ PPH_GRAPH_DRAW_INFO DrawInfo,
853  _In_ COLORREF Color1,
854  _In_ COLORREF Color2
855  )
856 {
857  switch (PhCsGraphColorMode)
858  {
859  case 0: // New colors
860  DrawInfo->BackColor = RGB(0xef, 0xef, 0xef);
861  DrawInfo->LineColor1 = PhHalveColorBrightness(Color1);
862  DrawInfo->LineBackColor1 = PhMakeColorBrighter(Color1, 125);
863  DrawInfo->LineColor2 = PhHalveColorBrightness(Color2);
864  DrawInfo->LineBackColor2 = PhMakeColorBrighter(Color2, 125);
865  DrawInfo->GridColor = RGB(0xc7, 0xc7, 0xc7);
866  DrawInfo->TextColor = RGB(0x00, 0x00, 0x00);
867  DrawInfo->TextBoxColor = RGB(0xe7, 0xe7, 0xe7);
868  break;
869  case 1: // Old colors
870  DrawInfo->BackColor = RGB(0x00, 0x00, 0x00);
871  DrawInfo->LineColor1 = Color1;
872  DrawInfo->LineBackColor1 = PhHalveColorBrightness(Color1);
873  DrawInfo->LineColor2 = Color2;
874  DrawInfo->LineBackColor2 = PhHalveColorBrightness(Color2);
875  DrawInfo->GridColor = RGB(0x00, 0x57, 0x00);
876  DrawInfo->TextColor = RGB(0x00, 0xff, 0x00);
877  DrawInfo->TextBoxColor = RGB(0x00, 0x22, 0x00);
878  break;
879  }
880 }
881 
883  _In_ HWND DialogWindowHandle
884  )
885 {
886  if (!PhSipDialogList)
887  PhSipDialogList = PhCreateList(4);
888 
889  PhAddItemList(PhSipDialogList, DialogWindowHandle);
890 }
891 
893  _In_ HWND DialogWindowHandle
894  )
895 {
896  ULONG index;
897 
898  if ((index = PhFindItemList(PhSipDialogList, DialogWindowHandle)) != -1)
899  PhRemoveItemList(PhSipDialogList, index);
900 }
901 
903  VOID
904  )
905 {
906  LOGFONT logFont;
907  HDC hdc;
908  TEXTMETRIC textMetrics;
909  HFONT originalFont;
910 
911  memset(&CurrentParameters, 0, sizeof(PH_SYSINFO_PARAMETERS));
912 
913  CurrentParameters.SysInfoWindowHandle = PhSipWindow;
914  CurrentParameters.ContainerWindowHandle = ContainerControl;
915 
916  if (SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &logFont, 0))
917  {
918  CurrentParameters.Font = CreateFontIndirect(&logFont);
919  }
920  else
921  {
922  CurrentParameters.Font = PhApplicationFont;
923  GetObject(PhApplicationFont, sizeof(LOGFONT), &logFont);
924  }
925 
926  hdc = GetDC(PhSipWindow);
927 
928  logFont.lfHeight -= MulDiv(3, GetDeviceCaps(hdc, LOGPIXELSY), 72);
929  CurrentParameters.MediumFont = CreateFontIndirect(&logFont);
930 
931  logFont.lfHeight -= MulDiv(3, GetDeviceCaps(hdc, LOGPIXELSY), 72);
932  CurrentParameters.LargeFont = CreateFontIndirect(&logFont);
933 
935 
937 
938  originalFont = SelectObject(hdc, CurrentParameters.Font);
939  GetTextMetrics(hdc, &textMetrics);
940  CurrentParameters.FontHeight = textMetrics.tmHeight;
941  CurrentParameters.FontAverageWidth = textMetrics.tmAveCharWidth;
942 
943  SelectObject(hdc, CurrentParameters.MediumFont);
944  GetTextMetrics(hdc, &textMetrics);
945  CurrentParameters.MediumFontHeight = textMetrics.tmHeight;
946  CurrentParameters.MediumFontAverageWidth = textMetrics.tmAveCharWidth;
947 
948  SelectObject(hdc, originalFont);
949 
950  CurrentParameters.MinimumGraphHeight =
952  CurrentParameters.MediumFontHeight +
954 
955  CurrentParameters.SectionViewGraphHeight =
957  CurrentParameters.MediumFontHeight +
959  CurrentParameters.FontHeight +
960  2 +
961  CurrentParameters.FontHeight +
963  2;
964 
965  CurrentParameters.PanelWidth = CurrentParameters.MediumFontAverageWidth * 10;
966 
967  ReleaseDC(PhSipWindow, hdc);
968 }
969 
971  VOID
972  )
973 {
974  if (CurrentParameters.Font)
975  DeleteObject(CurrentParameters.Font);
976  if (CurrentParameters.MediumFont)
977  DeleteObject(CurrentParameters.MediumFont);
978  if (CurrentParameters.LargeFont)
979  DeleteObject(CurrentParameters.LargeFont);
980 }
981 
983  VOID
984  )
985 {
986  switch (PhCsGraphColorMode)
987  {
988  case 0: // New colors
989  CurrentParameters.GraphBackColor = RGB(0xef, 0xef, 0xef);
990  CurrentParameters.PanelForeColor = RGB(0x00, 0x00, 0x00);
991  break;
992  case 1: // Old colors
993  CurrentParameters.GraphBackColor = RGB(0x00, 0x00, 0x00);
994  CurrentParameters.PanelForeColor = RGB(0xff, 0xff, 0xff);
995  break;
996  }
997 }
998 
1000  _In_ PPH_SYSINFO_SECTION Template
1001  )
1002 {
1003  PPH_SYSINFO_SECTION section;
1004  PH_GRAPH_OPTIONS options;
1005 
1006  section = PhAllocate(sizeof(PH_SYSINFO_SECTION));
1007  memset(section, 0, sizeof(PH_SYSINFO_SECTION));
1008 
1009  section->Name = Template->Name;
1010  section->Flags = Template->Flags;
1011  section->Callback = Template->Callback;
1012  section->Context = Template->Context;
1013 
1014  section->GraphHandle = CreateWindow(
1016  NULL,
1017  WS_VISIBLE | WS_CHILD | WS_BORDER | WS_TABSTOP | GC_STYLE_FADEOUT | GC_STYLE_DRAW_PANEL,
1018  0,
1019  0,
1020  3,
1021  3,
1022  PhSipWindow,
1023  (HMENU)(IDDYNAMIC + SectionList->Count * 2 + 1),
1025  NULL
1026  );
1028  section->Parameters = &CurrentParameters;
1029 
1030  Graph_GetOptions(section->GraphHandle, &options);
1031  options.FadeOutBackColor = CurrentParameters.GraphBackColor;
1032  options.FadeOutWidth = CurrentParameters.PanelWidth + PH_SYSINFO_FADE_ADD;
1033  options.DefaultCursor = LoadCursor(NULL, IDC_HAND);
1034  Graph_SetOptions(section->GraphHandle, &options);
1035  Graph_SetTooltip(section->GraphHandle, TRUE);
1036 
1037  section->PanelId = IDDYNAMIC + SectionList->Count * 2 + 2;
1038  section->PanelHandle = CreateWindow(
1039  L"STATIC",
1040  NULL,
1041  WS_CHILD | SS_OWNERDRAW | SS_NOTIFY,
1042  0,
1043  0,
1044  3,
1045  3,
1046  PhSipWindow,
1047  (HMENU)section->PanelId,
1049  NULL
1050  );
1051 
1052  SetProp(section->GraphHandle, PhMakeContextAtom(), section);
1053  section->GraphOldWndProc = (WNDPROC)GetWindowLongPtr(section->GraphHandle, GWLP_WNDPROC);
1054  SetWindowLongPtr(section->GraphHandle, GWLP_WNDPROC, (LONG_PTR)PhSipGraphHookWndProc);
1055 
1056  SetProp(section->PanelHandle, PhMakeContextAtom(), section);
1057  section->PanelOldWndProc = (WNDPROC)GetWindowLongPtr(section->PanelHandle, GWLP_WNDPROC);
1058  SetWindowLongPtr(section->PanelHandle, GWLP_WNDPROC, (LONG_PTR)PhSipPanelHookWndProc);
1059 
1060  PhAddItemList(SectionList, section);
1061 
1062  section->Callback(section, SysInfoCreate, NULL, NULL);
1063 
1064  return section;
1065 }
1066 
1068  _In_ PPH_SYSINFO_SECTION Section
1069  )
1070 {
1071  Section->Callback(Section, SysInfoDestroy, NULL, NULL);
1072 
1073  PhDeleteGraphState(&Section->GraphState);
1074  PhFree(Section);
1075 }
1076 
1078  _In_ PPH_STRINGREF Name
1079  )
1080 {
1081  ULONG i;
1082  PPH_SYSINFO_SECTION section;
1083 
1084  for (i = 0; i < SectionList->Count; i++)
1085  {
1086  section = SectionList->Items[i];
1087 
1088  if (PhEqualStringRef(&section->Name, Name, TRUE))
1089  return section;
1090  }
1091 
1092  return NULL;
1093 }
1094 
1096  _In_ PWSTR Name,
1097  _In_ ULONG Flags,
1098  _In_ PPH_SYSINFO_SECTION_CALLBACK Callback
1099  )
1100 {
1101  PH_SYSINFO_SECTION section;
1102 
1103  memset(&section, 0, sizeof(PH_SYSINFO_SECTION));
1104  PhInitializeStringRef(&section.Name, Name);
1105  section.Flags = Flags;
1106  section.Callback = Callback;
1107 
1108  return PhSipCreateSection(&section);
1109 }
1110 
1112  _In_ HDC hdc,
1113  _In_ PRECT Rect
1114  )
1115 {
1116  FillRect(hdc, Rect, GetSysColorBrush(COLOR_3DFACE));
1117 
1118  if (RestoreSummaryControlHot || RestoreSummaryControlHasFocus)
1119  {
1120  if (ThemeHasItemBackground)
1121  {
1123  ThemeData,
1124  hdc,
1125  TVP_TREEITEM,
1126  TREIS_HOT,
1127  Rect,
1128  Rect
1129  );
1130  }
1131  else
1132  {
1133  FillRect(hdc, Rect, GetSysColorBrush(COLOR_WINDOW));
1134  }
1135  }
1136 
1137  SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
1138  SetBkMode(hdc, TRANSPARENT);
1139 
1140  SelectObject(hdc, CurrentParameters.MediumFont);
1141  DrawText(hdc, L"Back", 4, Rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
1142 }
1143 
1145  _In_ HDC hdc,
1146  _In_ PRECT Rect
1147  )
1148 {
1149  RECT rect;
1150 
1151  rect = *Rect;
1152  FillRect(hdc, &rect, GetSysColorBrush(COLOR_3DHIGHLIGHT));
1153  rect.left += 1;
1154  FillRect(hdc, &rect, GetSysColorBrush(COLOR_3DSHADOW));
1155 }
1156 
1158  _In_ PPH_SYSINFO_SECTION Section,
1159  _In_ HDC hdc,
1160  _In_ PRECT Rect
1161  )
1162 {
1163  PH_SYSINFO_DRAW_PANEL sysInfoDrawPanel;
1164 
1165  if (CurrentView == SysInfoSectionView)
1166  FillRect(hdc, Rect, GetSysColorBrush(COLOR_3DFACE));
1167 
1168  sysInfoDrawPanel.hdc = hdc;
1169  sysInfoDrawPanel.Rect = *Rect;
1170  sysInfoDrawPanel.Rect.right = CurrentParameters.PanelWidth;
1171  sysInfoDrawPanel.CustomDraw = FALSE;
1172 
1173  sysInfoDrawPanel.Title = NULL;
1174  sysInfoDrawPanel.SubTitle = NULL;
1175  sysInfoDrawPanel.SubTitleOverflow = NULL;
1176 
1177  Section->Callback(Section, SysInfoGraphDrawPanel, &sysInfoDrawPanel, NULL);
1178 
1179  if (!sysInfoDrawPanel.CustomDraw)
1180  {
1181  sysInfoDrawPanel.Rect.right = Rect->right;
1182  PhSipDefaultDrawPanel(Section, &sysInfoDrawPanel);
1183  }
1184 
1185  PhClearReference(&sysInfoDrawPanel.Title);
1186  PhClearReference(&sysInfoDrawPanel.SubTitle);
1187  PhClearReference(&sysInfoDrawPanel.SubTitleOverflow);
1188 }
1189 
1191  _In_ PPH_SYSINFO_SECTION Section,
1192  _In_ PPH_SYSINFO_DRAW_PANEL DrawPanel
1193  )
1194 {
1195  HDC hdc;
1196  RECT rect;
1197  ULONG flags;
1198 
1199  hdc = DrawPanel->hdc;
1200 
1201  if (ThemeHasItemBackground)
1202  {
1203  if (CurrentView == SysInfoSectionView)
1204  {
1205  INT stateId;
1206 
1207  stateId = -1;
1208 
1209  if (Section->GraphHot || Section->PanelHot || Section->HasFocus)
1210  {
1211  if (Section == CurrentSection)
1212  stateId = TREIS_HOTSELECTED;
1213  else
1214  stateId = TREIS_HOT;
1215  }
1216  else if (Section == CurrentSection)
1217  {
1218  stateId = TREIS_SELECTED;
1219  }
1220 
1221  if (stateId != -1)
1222  {
1223  RECT themeRect;
1224 
1225  themeRect = DrawPanel->Rect;
1226  themeRect.left -= 2; // remove left edge
1227 
1229  ThemeData,
1230  hdc,
1231  TVP_TREEITEM,
1232  stateId,
1233  &themeRect,
1234  &DrawPanel->Rect
1235  );
1236  }
1237  }
1238  else if (Section->HasFocus)
1239  {
1241  ThemeData,
1242  hdc,
1243  TVP_TREEITEM,
1244  TREIS_HOT,
1245  &DrawPanel->Rect,
1246  &DrawPanel->Rect
1247  );
1248  }
1249  }
1250  else
1251  {
1252  if (CurrentView == SysInfoSectionView)
1253  {
1254  HBRUSH brush;
1255 
1256  brush = NULL;
1257 
1258  if (Section->GraphHot || Section->PanelHot || Section->HasFocus)
1259  {
1260  brush = GetSysColorBrush(COLOR_WINDOW); // TODO: Use a different color
1261  }
1262  else if (Section == CurrentSection)
1263  {
1264  brush = GetSysColorBrush(COLOR_WINDOW);
1265  }
1266 
1267  if (brush)
1268  {
1269  FillRect(hdc, &DrawPanel->Rect, brush);
1270  }
1271  }
1272  }
1273 
1274  if (CurrentView == SysInfoSummaryView)
1275  SetTextColor(hdc, CurrentParameters.PanelForeColor);
1276  else
1277  SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
1278 
1279  SetBkMode(hdc, TRANSPARENT);
1280 
1282  rect.top = PH_SYSINFO_PANEL_PADDING;
1283  rect.right = CurrentParameters.PanelWidth;
1284  rect.bottom = DrawPanel->Rect.bottom;
1285 
1286  flags = DT_NOPREFIX;
1287 
1288  if (CurrentView == SysInfoSummaryView)
1289  rect.right = DrawPanel->Rect.right; // allow the text to overflow
1290  else
1291  flags |= DT_END_ELLIPSIS;
1292 
1293  if (DrawPanel->Title)
1294  {
1295  SelectObject(hdc, CurrentParameters.MediumFont);
1296  DrawText(hdc, DrawPanel->Title->Buffer, (ULONG)DrawPanel->Title->Length / 2, &rect, flags | DT_SINGLELINE);
1297  }
1298 
1299  if (DrawPanel->SubTitle)
1300  {
1301  RECT measureRect;
1302 
1303  rect.top += CurrentParameters.MediumFontHeight + PH_SYSINFO_PANEL_PADDING;
1304  SelectObject(hdc, CurrentParameters.Font);
1305 
1306  measureRect = rect;
1307  DrawText(hdc, DrawPanel->SubTitle->Buffer, (ULONG)DrawPanel->SubTitle->Length / 2, &measureRect, (flags & ~DT_END_ELLIPSIS) | DT_CALCRECT);
1308 
1309  if (measureRect.right <= rect.right || !DrawPanel->SubTitleOverflow)
1310  {
1311  // Text fits; draw normally.
1312  DrawText(hdc, DrawPanel->SubTitle->Buffer, (ULONG)DrawPanel->SubTitle->Length / 2, &rect, flags);
1313  }
1314  else
1315  {
1316  // Text doesn't fit; draw the alternative text.
1317  DrawText(hdc, DrawPanel->SubTitleOverflow->Buffer, (ULONG)DrawPanel->SubTitleOverflow->Length / 2, &rect, flags);
1318  }
1319  }
1320 }
1321 
1323  VOID
1324  )
1325 {
1326  RECT buttonRect;
1327  RECT clientRect;
1328  ULONG availableHeight;
1329  ULONG availableWidth;
1330  ULONG graphHeight;
1331  ULONG i;
1332  PPH_SYSINFO_SECTION section;
1333  HDWP deferHandle;
1334  ULONG y;
1335 
1336  GetWindowRect(GetDlgItem(PhSipWindow, IDOK), &buttonRect);
1337  MapWindowPoints(NULL, PhSipWindow, (POINT *)&buttonRect, 2);
1338  GetClientRect(PhSipWindow, &clientRect);
1339 
1340  availableHeight = buttonRect.top - PH_SYSINFO_WINDOW_PADDING * 2;
1341  availableWidth = clientRect.right - PH_SYSINFO_WINDOW_PADDING * 2;
1342  graphHeight = (availableHeight - PH_SYSINFO_GRAPH_PADDING * (SectionList->Count - 1)) / SectionList->Count;
1343 
1344  deferHandle = BeginDeferWindowPos(SectionList->Count);
1346 
1347  for (i = 0; i < SectionList->Count; i++)
1348  {
1349  section = SectionList->Items[i];
1350 
1351  deferHandle = DeferWindowPos(
1352  deferHandle,
1353  section->GraphHandle,
1354  NULL,
1356  y,
1357  availableWidth,
1358  graphHeight,
1359  SWP_NOACTIVATE | SWP_NOZORDER
1360  );
1361  y += graphHeight + PH_SYSINFO_GRAPH_PADDING;
1362 
1363  section->GraphState.Valid = FALSE;
1364  }
1365 
1366  EndDeferWindowPos(deferHandle);
1367 }
1368 
1370  VOID
1371  )
1372 {
1373  RECT buttonRect;
1374  RECT clientRect;
1375  ULONG availableHeight;
1376  ULONG availableWidth;
1377  ULONG graphHeight;
1378  ULONG i;
1379  PPH_SYSINFO_SECTION section;
1380  HDWP deferHandle;
1381  ULONG y;
1382  ULONG containerLeft;
1383 
1384  GetWindowRect(GetDlgItem(PhSipWindow, IDOK), &buttonRect);
1385  MapWindowPoints(NULL, PhSipWindow, (POINT *)&buttonRect, 2);
1386  GetClientRect(PhSipWindow, &clientRect);
1387 
1388  availableHeight = buttonRect.top - PH_SYSINFO_WINDOW_PADDING * 2;
1389  availableWidth = clientRect.right - PH_SYSINFO_WINDOW_PADDING * 2;
1390  graphHeight = (availableHeight - PH_SYSINFO_SMALL_GRAPH_PADDING * SectionList->Count) / (SectionList->Count + 1);
1391 
1392  if (graphHeight > CurrentParameters.SectionViewGraphHeight)
1393  graphHeight = CurrentParameters.SectionViewGraphHeight;
1394 
1395  deferHandle = BeginDeferWindowPos(SectionList->Count * 2 + 3);
1397 
1398  for (i = 0; i < SectionList->Count; i++)
1399  {
1400  section = SectionList->Items[i];
1401 
1402  deferHandle = DeferWindowPos(
1403  deferHandle,
1404  section->GraphHandle,
1405  NULL,
1407  y,
1409  graphHeight,
1410  SWP_NOACTIVATE | SWP_NOZORDER
1411  );
1412 
1413  deferHandle = DeferWindowPos(
1414  deferHandle,
1415  section->PanelHandle,
1416  NULL,
1418  y,
1419  PH_SYSINFO_SMALL_GRAPH_PADDING + CurrentParameters.PanelWidth,
1420  graphHeight,
1421  SWP_NOACTIVATE | SWP_NOZORDER
1422  );
1423  InvalidateRect(section->PanelHandle, NULL, TRUE);
1424 
1425  y += graphHeight + PH_SYSINFO_SMALL_GRAPH_PADDING;
1426 
1427  section->GraphState.Valid = FALSE;
1428  }
1429 
1430  deferHandle = DeferWindowPos(
1431  deferHandle,
1432  RestoreSummaryControl,
1433  NULL,
1435  y,
1437  graphHeight,
1438  SWP_NOACTIVATE | SWP_NOZORDER
1439  );
1440  InvalidateRect(RestoreSummaryControl, NULL, TRUE);
1441 
1442  deferHandle = DeferWindowPos(
1443  deferHandle,
1444  SeparatorControl,
1445  NULL,
1447  0,
1449  PH_SYSINFO_WINDOW_PADDING + availableHeight,
1450  SWP_NOACTIVATE | SWP_NOZORDER
1451  );
1452 
1454  deferHandle = DeferWindowPos(
1455  deferHandle,
1456  ContainerControl,
1457  NULL,
1458  containerLeft,
1459  0,
1460  clientRect.right - containerLeft,
1461  PH_SYSINFO_WINDOW_PADDING + availableHeight,
1462  SWP_NOACTIVATE | SWP_NOZORDER
1463  );
1464 
1465  EndDeferWindowPos(deferHandle);
1466 
1467  if (CurrentSection && CurrentSection->DialogHandle)
1468  {
1469  SetWindowPos(
1470  CurrentSection->DialogHandle,
1471  NULL,
1474  clientRect.right - containerLeft - PH_SYSINFO_WINDOW_PADDING - PH_SYSINFO_WINDOW_PADDING,
1475  availableHeight,
1476  SWP_NOACTIVATE | SWP_NOZORDER
1477  );
1478  }
1479 }
1480 
1482  _In_ PPH_SYSINFO_SECTION NewSection
1483  )
1484 {
1485  ULONG i;
1486  PPH_SYSINFO_SECTION section;
1487  BOOLEAN fromSummaryView;
1488  PPH_SYSINFO_SECTION oldSection;
1489 
1490  fromSummaryView = CurrentView == SysInfoSummaryView;
1491  CurrentView = SysInfoSectionView;
1492  oldSection = CurrentSection;
1493  CurrentSection = NewSection;
1494 
1495  for (i = 0; i < SectionList->Count; i++)
1496  {
1497  section = SectionList->Items[i];
1498 
1499  section->HasFocus = FALSE;
1500  section->Callback(section, SysInfoViewChanging, (PVOID)CurrentView, CurrentSection);
1501 
1502  if (fromSummaryView)
1503  {
1505  ShowWindow(section->PanelHandle, SW_SHOW);
1506  }
1507 
1508  if (section == CurrentSection && !section->DialogHandle)
1509  PhSipCreateSectionDialog(section);
1510 
1511  if (section->DialogHandle)
1512  {
1513  if (section == CurrentSection)
1514  ShowWindow(section->DialogHandle, SW_SHOW);
1515  else
1516  ShowWindow(section->DialogHandle, SW_HIDE);
1517  }
1518  }
1519 
1520  ShowWindow(ContainerControl, SW_SHOW);
1521  ShowWindow(RestoreSummaryControl, SW_SHOW);
1522  ShowWindow(SeparatorControl, SW_SHOW);
1523  ShowWindow(GetDlgItem(PhSipWindow, IDC_INSTRUCTION), SW_HIDE);
1524 
1525  if (oldSection)
1526  InvalidateRect(oldSection->PanelHandle, NULL, TRUE);
1527 
1528  InvalidateRect(NewSection->PanelHandle, NULL, TRUE);
1529 
1531 }
1532 
1534  VOID
1535  )
1536 {
1537  ULONG i;
1538  PPH_SYSINFO_SECTION section;
1539 
1540  if (CurrentView == SysInfoSummaryView)
1541  return;
1542 
1543  CurrentView = SysInfoSummaryView;
1544  CurrentSection = NULL;
1545 
1546  for (i = 0; i < SectionList->Count; i++)
1547  {
1548  section = SectionList->Items[i];
1549 
1550  section->Callback(section, SysInfoViewChanging, (PVOID)CurrentView, NULL);
1551 
1553  ShowWindow(section->PanelHandle, SW_HIDE);
1554 
1555  if (section->DialogHandle)
1556  ShowWindow(section->DialogHandle, SW_HIDE);
1557  }
1558 
1559  ShowWindow(ContainerControl, SW_HIDE);
1560  ShowWindow(RestoreSummaryControl, SW_HIDE);
1561  ShowWindow(SeparatorControl, SW_HIDE);
1562  ShowWindow(GetDlgItem(PhSipWindow, IDC_INSTRUCTION), SW_SHOW);
1563 
1565 }
1566 
1568  _In_ PPH_SYSINFO_SECTION Section
1569  )
1570 {
1571  PH_SYSINFO_CREATE_DIALOG createDialog;
1572 
1573  memset(&createDialog, 0, sizeof(PH_SYSINFO_CREATE_DIALOG));
1574 
1575  if (Section->Callback(Section, SysInfoCreateDialog, &createDialog, NULL))
1576  {
1577  if (!createDialog.CustomCreate)
1578  {
1579  Section->DialogHandle = PhCreateDialogFromTemplate(
1580  ContainerControl,
1581  DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD,
1582  createDialog.Instance,
1583  createDialog.Template,
1584  createDialog.DialogProc,
1585  createDialog.Parameter
1586  );
1587  }
1588  }
1589 }
1590 
1591 LRESULT CALLBACK PhSipGraphHookWndProc(
1592  _In_ HWND hwnd,
1593  _In_ UINT uMsg,
1594  _In_ WPARAM wParam,
1595  _In_ LPARAM lParam
1596  )
1597 {
1598  WNDPROC oldWndProc;
1599  PPH_SYSINFO_SECTION section;
1600 
1601  section = GetProp(hwnd, PhMakeContextAtom());
1602 
1603  if (!section)
1604  return 0;
1605 
1606  oldWndProc = section->GraphOldWndProc;
1607 
1608  switch (uMsg)
1609  {
1610  case WM_DESTROY:
1611  {
1612  RemoveProp(hwnd, PhMakeContextAtom());
1613  SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc);
1614  }
1615  break;
1616  case WM_SETFOCUS:
1617  section->HasFocus = TRUE;
1618 
1619  if (CurrentView == SysInfoSummaryView)
1620  {
1621  Graph_Draw(section->GraphHandle);
1622  InvalidateRect(section->GraphHandle, NULL, FALSE);
1623  }
1624  else
1625  {
1626  InvalidateRect(section->PanelHandle, NULL, TRUE);
1627  }
1628 
1629  break;
1630  case WM_KILLFOCUS:
1631  section->HasFocus = FALSE;
1632 
1633  if (CurrentView == SysInfoSummaryView)
1634  {
1635  Graph_Draw(section->GraphHandle);
1636  InvalidateRect(section->GraphHandle, NULL, FALSE);
1637  }
1638  else
1639  {
1640  InvalidateRect(section->PanelHandle, NULL, TRUE);
1641  }
1642 
1643  break;
1644  case WM_GETDLGCODE:
1645  if (wParam == VK_SPACE || wParam == VK_RETURN ||
1646  wParam == VK_UP || wParam == VK_DOWN ||
1647  wParam == VK_LEFT || wParam == VK_RIGHT)
1648  return DLGC_WANTALLKEYS;
1649  break;
1650  case WM_KEYDOWN:
1651  {
1652  if (wParam == VK_SPACE || wParam == VK_RETURN)
1653  {
1654  PhSipEnterSectionView(section);
1655  }
1656  else if (wParam == VK_UP || wParam == VK_LEFT ||
1657  wParam == VK_DOWN || wParam == VK_RIGHT)
1658  {
1659  ULONG i;
1660 
1661  for (i = 0; i < SectionList->Count; i++)
1662  {
1663  if (SectionList->Items[i] == section)
1664  {
1665  if ((wParam == VK_UP || wParam == VK_LEFT) && i > 0)
1666  {
1667  SetFocus(((PPH_SYSINFO_SECTION)SectionList->Items[i - 1])->GraphHandle);
1668  }
1669  else if (wParam == VK_DOWN || wParam == VK_RIGHT)
1670  {
1671  if (i < SectionList->Count - 1)
1672  SetFocus(((PPH_SYSINFO_SECTION)SectionList->Items[i + 1])->GraphHandle);
1673  else
1674  SetFocus(RestoreSummaryControl);
1675  }
1676 
1677  break;
1678  }
1679  }
1680  }
1681  }
1682  break;
1683  case WM_MOUSEMOVE:
1684  {
1685  TRACKMOUSEEVENT trackMouseEvent;
1686 
1687  trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
1688  trackMouseEvent.dwFlags = TME_LEAVE;
1689  trackMouseEvent.hwndTrack = hwnd;
1690  trackMouseEvent.dwHoverTime = 0;
1691  TrackMouseEvent(&trackMouseEvent);
1692 
1693  if (!(section->GraphHot || section->PanelHot))
1694  {
1695  section->GraphHot = TRUE;
1696  InvalidateRect(section->PanelHandle, NULL, TRUE);
1697  }
1698  else
1699  {
1700  section->GraphHot = TRUE;
1701  }
1702  }
1703  break;
1704  case WM_MOUSELEAVE:
1705  {
1706  if (!section->PanelHot)
1707  {
1708  section->GraphHot = FALSE;
1709  InvalidateRect(section->PanelHandle, NULL, TRUE);
1710  }
1711  else
1712  {
1713  section->GraphHot = FALSE;
1714  }
1715 
1716  section->HasFocus = FALSE;
1717 
1718  if (CurrentView == SysInfoSummaryView)
1719  {
1720  Graph_Draw(section->GraphHandle);
1721  InvalidateRect(section->GraphHandle, NULL, FALSE);
1722  }
1723  }
1724  break;
1725  case WM_NCLBUTTONDOWN:
1726  {
1727  PhSipEnterSectionView(section);
1728  }
1729  break;
1730  case WM_UPDATEUISTATE:
1731  {
1732  switch (LOWORD(wParam))
1733  {
1734  case UIS_SET:
1735  if (HIWORD(wParam) & UISF_HIDEFOCUS)
1736  section->HideFocus = TRUE;
1737  break;
1738  case UIS_CLEAR:
1739  if (HIWORD(wParam) & UISF_HIDEFOCUS)
1740  section->HideFocus = FALSE;
1741  break;
1742  case UIS_INITIALIZE:
1743  section->HideFocus = !!(HIWORD(wParam) & UISF_HIDEFOCUS);
1744  break;
1745  }
1746  }
1747  break;
1748  }
1749 
1750  return CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam);
1751 }
1752 
1753 LRESULT CALLBACK PhSipPanelHookWndProc(
1754  _In_ HWND hwnd,
1755  _In_ UINT uMsg,
1756  _In_ WPARAM wParam,
1757  _In_ LPARAM lParam
1758  )
1759 {
1760  WNDPROC oldWndProc;
1761  PPH_SYSINFO_SECTION section;
1762 
1763  section = GetProp(hwnd, PhMakeContextAtom());
1764 
1765  if (section)
1766  oldWndProc = section->PanelOldWndProc;
1767  else
1768  oldWndProc = RestoreSummaryControlOldWndProc;
1769 
1770  switch (uMsg)
1771  {
1772  case WM_DESTROY:
1773  {
1774  RemoveProp(hwnd, PhMakeContextAtom());
1775  SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)oldWndProc);
1776  }
1777  break;
1778  case WM_SETFOCUS:
1779  {
1780  if (!section)
1781  {
1782  RestoreSummaryControlHasFocus = TRUE;
1783  InvalidateRect(hwnd, NULL, TRUE);
1784  }
1785  }
1786  break;
1787  case WM_KILLFOCUS:
1788  {
1789  if (!section)
1790  {
1791  RestoreSummaryControlHasFocus = FALSE;
1792  InvalidateRect(hwnd, NULL, TRUE);
1793  }
1794  }
1795  break;
1796  case WM_SETCURSOR:
1797  {
1798  SetCursor(LoadCursor(NULL, IDC_HAND));
1799  }
1800  return TRUE;
1801  case WM_GETDLGCODE:
1802  if (wParam == VK_SPACE || wParam == VK_RETURN ||
1803  wParam == VK_UP || wParam == VK_DOWN ||
1804  wParam == VK_LEFT || wParam == VK_RIGHT)
1805  return DLGC_WANTALLKEYS;
1806  break;
1807  case WM_KEYDOWN:
1808  {
1809  if (wParam == VK_SPACE || wParam == VK_RETURN)
1810  {
1811  if (section)
1812  PhSipEnterSectionView(section);
1813  else
1815  }
1816  else if (wParam == VK_UP || wParam == VK_LEFT)
1817  {
1818  if (!section && SectionList->Count != 0)
1819  {
1820  SetFocus(((PPH_SYSINFO_SECTION)SectionList->Items[SectionList->Count - 1])->GraphHandle);
1821  }
1822  }
1823  }
1824  break;
1825  case WM_MOUSEMOVE:
1826  {
1827  TRACKMOUSEEVENT trackMouseEvent;
1828 
1829  trackMouseEvent.cbSize = sizeof(TRACKMOUSEEVENT);
1830  trackMouseEvent.dwFlags = TME_LEAVE;
1831  trackMouseEvent.hwndTrack = hwnd;
1832  trackMouseEvent.dwHoverTime = 0;
1833  TrackMouseEvent(&trackMouseEvent);
1834 
1835  if (section)
1836  {
1837  if (!(section->GraphHot || section->PanelHot))
1838  {
1839  section->PanelHot = TRUE;
1840  InvalidateRect(section->PanelHandle, NULL, TRUE);
1841  }
1842  else
1843  {
1844  section->PanelHot = TRUE;
1845  }
1846  }
1847  else
1848  {
1849  RestoreSummaryControlHot = TRUE;
1850  InvalidateRect(RestoreSummaryControl, NULL, TRUE);
1851  }
1852  }
1853  break;
1854  case WM_MOUSELEAVE:
1855  {
1856  if (section)
1857  {
1858  section->HasFocus = FALSE;
1859 
1860  if (!section->GraphHot)
1861  {
1862  section->PanelHot = FALSE;
1863  InvalidateRect(section->PanelHandle, NULL, TRUE);
1864  }
1865  else
1866  {
1867  section->PanelHot = FALSE;
1868  }
1869  }
1870  else
1871  {
1872  RestoreSummaryControlHasFocus = FALSE;
1873  RestoreSummaryControlHot = FALSE;
1874  InvalidateRect(RestoreSummaryControl, NULL, TRUE);
1875  }
1876  }
1877  break;
1878  }
1879 
1880  return CallWindowProc(oldWndProc, hwnd, uMsg, wParam, lParam);
1881 }
1882 
1884  VOID
1885  )
1886 {
1887  if (
1888  IsThemeActive_I &&
1889  OpenThemeData_I &&
1890  CloseThemeData_I &&
1893  )
1894  {
1895  if (ThemeData)
1896  {
1897  CloseThemeData_I(ThemeData);
1898  ThemeData = NULL;
1899  }
1900 
1901  ThemeData = OpenThemeData_I(PhSipWindow, L"TREEVIEW");
1902 
1903  if (ThemeData)
1904  {
1905  ThemeHasItemBackground = !!IsThemePartDefined_I(ThemeData, TVP_TREEITEM, 0);
1906  }
1907  else
1908  {
1909  ThemeHasItemBackground = FALSE;
1910  }
1911  }
1912  else
1913  {
1914  ThemeData = NULL;
1915  ThemeHasItemBackground = FALSE;
1916  }
1917 }
1918 
1920  VOID
1921  )
1922 {
1923  SetFocus(PhSipWindow); // HACK - SetWindowPos doesn't work properly without this
1924  SetWindowPos(PhSipWindow, AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0,
1925  SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
1926 }
1927 
1929  _In_opt_ PVOID Parameter,
1930  _In_opt_ PVOID Context
1931  )
1932 {
1933  PostMessage(PhSipWindow, SI_MSG_SYSINFO_UPDATE, 0, 0);
1934 }
1935 
1937  _In_ ULONG64 Size,
1938  _In_ USHORT Precision
1939  )
1940 {
1941  PH_FORMAT format;
1942 
1944  format.Precision = Precision;
1945  format.u.Size = Size;
1946 
1947  return PhAutoDereferenceObject(PhFormat(&format, 1, 0));
1948 }
1949 
1951  _In_ PPH_SYSINFO_SECTION Section,
1952  _In_ PH_SYSINFO_SECTION_MESSAGE Message,
1953  _In_opt_ PVOID Parameter1,
1954  _In_opt_ PVOID Parameter2
1955  )
1956 {
1957  switch (Message)
1958  {
1959  case SysInfoDestroy:
1960  {
1961  if (CpuDialog)
1962  {
1964  CpuDialog = NULL;
1965  }
1966  }
1967  return TRUE;
1968  case SysInfoTick:
1969  {
1970  if (CpuDialog)
1971  {
1973  }
1974  }
1975  return TRUE;
1976  case SysInfoCreateDialog:
1977  {
1978  PPH_SYSINFO_CREATE_DIALOG createDialog = Parameter1;
1979 
1980  createDialog->Instance = PhInstanceHandle;
1981  createDialog->Template = MAKEINTRESOURCE(IDD_SYSINFO_CPU);
1982  createDialog->DialogProc = PhSipCpuDialogProc;
1983  }
1984  return TRUE;
1986  {
1987  PPH_GRAPH_DRAW_INFO drawInfo = Parameter1;
1988 
1990  Section->Parameters->ColorSetupFunction(drawInfo, PhCsColorCpuKernel, PhCsColorCpuUser);
1991  PhGetDrawInfoGraphBuffers(&Section->GraphState.Buffers, drawInfo, PhCpuKernelHistory.Count);
1992 
1993  if (!Section->GraphState.Valid)
1994  {
1995  PhCopyCircularBuffer_FLOAT(&PhCpuKernelHistory, Section->GraphState.Data1, drawInfo->LineDataCount);
1996  PhCopyCircularBuffer_FLOAT(&PhCpuUserHistory, Section->GraphState.Data2, drawInfo->LineDataCount);
1997  Section->GraphState.Valid = TRUE;
1998  }
1999  }
2000  return TRUE;
2002  {
2003  PPH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT getTooltipText = Parameter1;
2004  FLOAT cpuKernel;
2005  FLOAT cpuUser;
2006 
2007  cpuKernel = PhGetItemCircularBuffer_FLOAT(&PhCpuKernelHistory, getTooltipText->Index);
2008  cpuUser = PhGetItemCircularBuffer_FLOAT(&PhCpuUserHistory, getTooltipText->Index);
2009 
2010  PhMoveReference(&Section->GraphState.TooltipText, PhFormatString(
2011  L"%.2f%%%s\n%s",
2012  (cpuKernel + cpuUser) * 100,
2013  PhGetStringOrEmpty(PhSipGetMaxCpuString(getTooltipText->Index)),
2014  ((PPH_STRING)PhAutoDereferenceObject(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
2015  ));
2016  getTooltipText->Text = Section->GraphState.TooltipText->sr;
2017  }
2018  return TRUE;
2019  case SysInfoGraphDrawPanel:
2020  {
2021  PPH_SYSINFO_DRAW_PANEL drawPanel = Parameter1;
2022 
2023  drawPanel->Title = PhCreateString(L"CPU");
2024  drawPanel->SubTitle = PhFormatString(L"%.2f%%", (PhCpuKernelUsage + PhCpuUserUsage) * 100);
2025  }
2026  return TRUE;
2027  }
2028 
2029  return FALSE;
2030 }
2031 
2033  VOID
2034  )
2035 {
2036  ULONG i;
2037 
2038  PhInitializeDelta(&ContextSwitchesDelta);
2039  PhInitializeDelta(&InterruptsDelta);
2040  PhInitializeDelta(&DpcsDelta);
2041  PhInitializeDelta(&SystemCallsDelta);
2042 
2043  NumberOfProcessors = (ULONG)PhSystemBasicInformation.NumberOfProcessors;
2044  CpusGraphHandle = PhAllocate(sizeof(HWND) * NumberOfProcessors);
2045  CpusGraphState = PhAllocate(sizeof(PH_GRAPH_STATE) * NumberOfProcessors);
2046  InterruptInformation = PhAllocate(sizeof(SYSTEM_INTERRUPT_INFORMATION) * NumberOfProcessors);
2047  PowerInformation = PhAllocate(sizeof(PROCESSOR_POWER_INFORMATION) * NumberOfProcessors);
2048 
2049  PhInitializeGraphState(&CpuGraphState);
2050 
2051  for (i = 0; i < NumberOfProcessors; i++)
2052  PhInitializeGraphState(&CpusGraphState[i]);
2053 
2054  CpuTicked = 0;
2055 
2057  ProcessorInformation,
2058  NULL,
2059  0,
2060  PowerInformation,
2061  sizeof(PROCESSOR_POWER_INFORMATION) * NumberOfProcessors
2062  )))
2063  {
2064  memset(PowerInformation, 0, sizeof(PROCESSOR_POWER_INFORMATION) * NumberOfProcessors);
2065  }
2066 
2067  CurrentPerformanceDistribution = NULL;
2068  PreviousPerformanceDistribution = NULL;
2069 
2070  if (WindowsVersion >= WINDOWS_7)
2071  PhSipQueryProcessorPerformanceDistribution(&CurrentPerformanceDistribution);
2072 }
2073 
2075  VOID
2076  )
2077 {
2078  ULONG i;
2079 
2080  PhDeleteGraphState(&CpuGraphState);
2081 
2082  for (i = 0; i < NumberOfProcessors; i++)
2083  PhDeleteGraphState(&CpusGraphState[i]);
2084 
2085  PhFree(CpusGraphHandle);
2086  PhFree(CpusGraphState);
2087  PhFree(InterruptInformation);
2088  PhFree(PowerInformation);
2089 
2090  if (CurrentPerformanceDistribution)
2091  PhFree(CurrentPerformanceDistribution);
2092  if (PreviousPerformanceDistribution)
2093  PhFree(PreviousPerformanceDistribution);
2094 
2095  PhSetIntegerSetting(L"SysInfoWindowOneGraphPerCpu", OneGraphPerCpu);
2096 }
2097 
2099  VOID
2100  )
2101 {
2102  ULONG64 dpcCount;
2103  ULONG i;
2104 
2105  dpcCount = 0;
2106 
2107  if (NT_SUCCESS(NtQuerySystemInformation(
2109  InterruptInformation,
2110  sizeof(SYSTEM_INTERRUPT_INFORMATION) * NumberOfProcessors,
2111  NULL
2112  )))
2113  {
2114  for (i = 0; i < NumberOfProcessors; i++)
2115  dpcCount += InterruptInformation[i].DpcCount;
2116  }
2117 
2118  PhUpdateDelta(&ContextSwitchesDelta, PhPerfInformation.ContextSwitches);
2119  PhUpdateDelta(&InterruptsDelta, PhCpuTotals.InterruptCount);
2120  PhUpdateDelta(&DpcsDelta, dpcCount);
2121  PhUpdateDelta(&SystemCallsDelta, PhPerfInformation.SystemCalls);
2122 
2124  ProcessorInformation,
2125  NULL,
2126  0,
2127  PowerInformation,
2128  sizeof(PROCESSOR_POWER_INFORMATION) * NumberOfProcessors
2129  )))
2130  {
2131  memset(PowerInformation, 0, sizeof(PROCESSOR_POWER_INFORMATION) * NumberOfProcessors);
2132  }
2133 
2134  if (WindowsVersion >= WINDOWS_7)
2135  {
2136  if (PreviousPerformanceDistribution)
2137  PhFree(PreviousPerformanceDistribution);
2138 
2139  PreviousPerformanceDistribution = CurrentPerformanceDistribution;
2140  CurrentPerformanceDistribution = NULL;
2141  PhSipQueryProcessorPerformanceDistribution(&CurrentPerformanceDistribution);
2142  }
2143 
2144  CpuTicked++;
2145 
2146  if (CpuTicked > 2)
2147  CpuTicked = 2;
2148 
2151 }
2152 
2153 INT_PTR CALLBACK PhSipCpuDialogProc(
2154  _In_ HWND hwndDlg,
2155  _In_ UINT uMsg,
2156  _In_ WPARAM wParam,
2157  _In_ LPARAM lParam
2158  )
2159 {
2160  switch (uMsg)
2161  {
2162  case WM_INITDIALOG:
2163  {
2164  PPH_LAYOUT_ITEM graphItem;
2165  PPH_LAYOUT_ITEM panelItem;
2166  WCHAR brandString[49];
2167 
2169 
2170  CpuDialog = hwndDlg;
2171  PhInitializeLayoutManager(&CpuLayoutManager, hwndDlg);
2172  PhAddLayoutItem(&CpuLayoutManager, GetDlgItem(hwndDlg, IDC_CPUNAME), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT | PH_LAYOUT_FORCE_INVALIDATE);
2173  graphItem = PhAddLayoutItem(&CpuLayoutManager, GetDlgItem(hwndDlg, IDC_GRAPH_LAYOUT), NULL, PH_ANCHOR_ALL);
2174  CpuGraphMargin = graphItem->Margin;
2175  panelItem = PhAddLayoutItem(&CpuLayoutManager, GetDlgItem(hwndDlg, IDC_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
2176 
2177  SendMessage(GetDlgItem(hwndDlg, IDC_TITLE), WM_SETFONT, (WPARAM)CurrentParameters.LargeFont, FALSE);
2178  SendMessage(GetDlgItem(hwndDlg, IDC_CPUNAME), WM_SETFONT, (WPARAM)CurrentParameters.MediumFont, FALSE);
2179 
2180  PhSipGetCpuBrandString(brandString);
2181  SetDlgItemText(hwndDlg, IDC_CPUNAME, brandString);
2182 
2183  CpuPanel = CreateDialog(PhInstanceHandle, MAKEINTRESOURCE(IDD_SYSINFO_CPUPANEL), hwndDlg, PhSipCpuPanelDialogProc);
2184  ShowWindow(CpuPanel, SW_SHOW);
2185  PhAddLayoutItemEx(&CpuLayoutManager, CpuPanel, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM, panelItem->Margin);
2186 
2188 
2189  if (NumberOfProcessors != 1)
2190  {
2191  OneGraphPerCpu = (BOOLEAN)PhGetIntegerSetting(L"SysInfoWindowOneGraphPerCpu");
2192  Button_SetCheck(GetDlgItem(CpuPanel, IDC_ONEGRAPHPERCPU), OneGraphPerCpu ? BST_CHECKED : BST_UNCHECKED);
2194  }
2195  else
2196  {
2197  OneGraphPerCpu = FALSE;
2198  EnableWindow(GetDlgItem(CpuPanel, IDC_ONEGRAPHPERCPU), FALSE);
2200  }
2201 
2204  }
2205  break;
2206  case WM_DESTROY:
2207  {
2208  PhDeleteLayoutManager(&CpuLayoutManager);
2209  }
2210  break;
2211  case WM_SIZE:
2212  {
2213  PhLayoutManagerLayout(&CpuLayoutManager);
2215  }
2216  break;
2217  case WM_NOTIFY:
2218  {
2219  NMHDR *header = (NMHDR *)lParam;
2220  ULONG i;
2221 
2222  if (header->hwndFrom == CpuGraphHandle)
2223  {
2224  PhSipNotifyCpuGraph(-1, header);
2225  }
2226  else
2227  {
2228  for (i = 0; i < NumberOfProcessors; i++)
2229  {
2230  if (header->hwndFrom == CpusGraphHandle[i])
2231  {
2232  PhSipNotifyCpuGraph(i, header);
2233  break;
2234  }
2235  }
2236  }
2237  }
2238  break;
2239  }
2240 
2241  return FALSE;
2242 }
2243 
2244 INT_PTR CALLBACK PhSipCpuPanelDialogProc(
2245  _In_ HWND hwndDlg,
2246  _In_ UINT uMsg,
2247  _In_ WPARAM wParam,
2248  _In_ LPARAM lParam
2249  )
2250 {
2251  switch (uMsg)
2252  {
2253  case WM_INITDIALOG:
2254  {
2255  SendMessage(GetDlgItem(hwndDlg, IDC_UTILIZATION), WM_SETFONT, (WPARAM)CurrentParameters.MediumFont, FALSE);
2256  SendMessage(GetDlgItem(hwndDlg, IDC_SPEED), WM_SETFONT, (WPARAM)CurrentParameters.MediumFont, FALSE);
2257  }
2258  break;
2259  case WM_COMMAND:
2260  {
2261  switch (LOWORD(wParam))
2262  {
2263  case IDC_ONEGRAPHPERCPU:
2264  {
2265  OneGraphPerCpu = Button_GetCheck(GetDlgItem(hwndDlg, IDC_ONEGRAPHPERCPU)) == BST_CHECKED;
2268  }
2269  break;
2270  }
2271  }
2272  break;
2273  }
2274 
2275  return FALSE;
2276 }
2277 
2279  VOID
2280  )
2281 {
2282  ULONG i;
2283 
2284  CpuGraphHandle = CreateWindow(
2286  NULL,
2287  WS_CHILD | WS_BORDER,
2288  0,
2289  0,
2290  3,
2291  3,
2292  CpuDialog,
2293  (HMENU)IDC_CPU,
2295  NULL
2296  );
2297  Graph_SetTooltip(CpuGraphHandle, TRUE);
2298 
2299  for (i = 0; i < NumberOfProcessors; i++)
2300  {
2301  CpusGraphHandle[i] = CreateWindow(
2303  NULL,
2304  WS_CHILD | WS_BORDER,
2305  0,
2306  0,
2307  3,
2308  3,
2309  CpuDialog,
2310  (HMENU)(IDC_CPU0 + i),
2312  NULL
2313  );
2314  Graph_SetTooltip(CpusGraphHandle[i], TRUE);
2315  }
2316 }
2317 
2319  VOID
2320  )
2321 {
2322  RECT clientRect;
2323  HDWP deferHandle;
2324 
2325  GetClientRect(CpuDialog, &clientRect);
2326  deferHandle = BeginDeferWindowPos(OneGraphPerCpu ? NumberOfProcessors : 1);
2327 
2328  if (!OneGraphPerCpu)
2329  {
2330  deferHandle = DeferWindowPos(
2331  deferHandle,
2332  CpuGraphHandle,
2333  NULL,
2334  CpuGraphMargin.left,
2335  CpuGraphMargin.top,
2336  clientRect.right - CpuGraphMargin.left - CpuGraphMargin.right,
2337  clientRect.bottom - CpuGraphMargin.top - CpuGraphMargin.bottom,
2338  SWP_NOACTIVATE | SWP_NOZORDER
2339  );
2340  }
2341  else
2342  {
2343  ULONG numberOfRows = 1;
2344  ULONG numberOfColumns = NumberOfProcessors;
2345 
2346  for (ULONG rows = 2; rows <= NumberOfProcessors / rows; rows++)
2347  {
2348  if (NumberOfProcessors % rows != 0)
2349  continue;
2350 
2351  numberOfRows = rows;
2352  numberOfColumns = NumberOfProcessors / rows;
2353  }
2354 
2355  if (numberOfRows == 1)
2356  {
2357  numberOfRows = (ULONG)sqrt(NumberOfProcessors);
2358  numberOfColumns = (NumberOfProcessors + numberOfRows - 1) / numberOfRows;
2359  }
2360 
2361  ULONG numberOfYPaddings = numberOfRows - 1;
2362  ULONG numberOfXPaddings = numberOfColumns - 1;
2363 
2364  ULONG cellHeight = (clientRect.bottom - CpuGraphMargin.top - CpuGraphMargin.bottom - PH_SYSINFO_CPU_PADDING * numberOfYPaddings) / numberOfRows;
2365  ULONG y = CpuGraphMargin.top;
2366  ULONG cellWidth;
2367  ULONG x;
2368  ULONG i = 0;
2369 
2370  for (ULONG row = 0; row < numberOfRows; row++)
2371  {
2372  // Give the last row the remaining space; the height we calculated might be off by a few
2373  // pixels due to integer division.
2374  if (row == numberOfRows - 1)
2375  cellHeight = clientRect.bottom - CpuGraphMargin.bottom - y;
2376 
2377  cellWidth = (clientRect.right - CpuGraphMargin.left - CpuGraphMargin.right - PH_SYSINFO_CPU_PADDING * numberOfXPaddings) / numberOfColumns;
2378  x = CpuGraphMargin.left;
2379 
2380  for (ULONG column = 0; column < numberOfColumns; column++)
2381  {
2382  // Give the last cell the remaining space; the width we calculated might be off by a few
2383  // pixels due to integer division.
2384  if (column == numberOfColumns - 1)
2385  cellWidth = clientRect.right - CpuGraphMargin.right - x;
2386 
2387  if (i < NumberOfProcessors)
2388  {
2389  deferHandle = DeferWindowPos(
2390  deferHandle,
2391  CpusGraphHandle[i],
2392  NULL,
2393  x,
2394  y,
2395  cellWidth,
2396  cellHeight,
2397  SWP_NOACTIVATE | SWP_NOZORDER
2398  );
2399  i++;
2400  }
2401 
2402  x += cellWidth + PH_SYSINFO_CPU_PADDING;
2403  }
2404 
2405  y += cellHeight + PH_SYSINFO_CPU_PADDING;
2406  }
2407  }
2408 
2409  EndDeferWindowPos(deferHandle);
2410 }
2411 
2413  VOID
2414  )
2415 {
2416  ULONG i;
2417 
2418  ShowWindow(CpuGraphHandle, !OneGraphPerCpu ? SW_SHOW : SW_HIDE);
2419 
2420  for (i = 0; i < NumberOfProcessors; i++)
2421  {
2422  ShowWindow(CpusGraphHandle[i], OneGraphPerCpu ? SW_SHOW : SW_HIDE);
2423  }
2424 }
2425 
2427  _In_ ULONG Index,
2428  _In_ NMHDR *Header
2429  )
2430 {
2431  switch (Header->code)
2432  {
2433  case GCN_GETDRAWINFO:
2434  {
2435  PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header;
2436  PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;
2437 
2440 
2441  if (Index == -1)
2442  {
2444  &CpuGraphState,
2445  getDrawInfo,
2446  PhCpuKernelHistory.Count
2447  );
2448 
2449  if (!CpuGraphState.Valid)
2450  {
2451  PhCopyCircularBuffer_FLOAT(&PhCpuKernelHistory, CpuGraphState.Data1, drawInfo->LineDataCount);
2452  PhCopyCircularBuffer_FLOAT(&PhCpuUserHistory, CpuGraphState.Data2, drawInfo->LineDataCount);
2453  CpuGraphState.Valid = TRUE;
2454  }
2455  }
2456  else
2457  {
2459  &CpusGraphState[Index],
2460  getDrawInfo,
2461  PhCpuKernelHistory.Count
2462  );
2463 
2464  if (!CpusGraphState[Index].Valid)
2465  {
2466  PhCopyCircularBuffer_FLOAT(&PhCpusKernelHistory[Index], CpusGraphState[Index].Data1, drawInfo->LineDataCount);
2467  PhCopyCircularBuffer_FLOAT(&PhCpusUserHistory[Index], CpusGraphState[Index].Data2, drawInfo->LineDataCount);
2468  CpusGraphState[Index].Valid = TRUE;
2469  }
2470  }
2471  }
2472  break;
2473  case GCN_GETTOOLTIPTEXT:
2474  {
2475  PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header;
2476 
2477  if (getTooltipText->Index < getTooltipText->TotalCount)
2478  {
2479  if (Index == -1)
2480  {
2481  if (CpuGraphState.TooltipIndex != getTooltipText->Index)
2482  {
2483  FLOAT cpuKernel;
2484  FLOAT cpuUser;
2485 
2486  cpuKernel = PhGetItemCircularBuffer_FLOAT(&PhCpuKernelHistory, getTooltipText->Index);
2487  cpuUser = PhGetItemCircularBuffer_FLOAT(&PhCpuUserHistory, getTooltipText->Index);
2488 
2489  PhMoveReference(&CpuGraphState.TooltipText, PhFormatString(
2490  L"%.2f%%%s\n%s",
2491  (cpuKernel + cpuUser) * 100,
2492  PhGetStringOrEmpty(PhSipGetMaxCpuString(getTooltipText->Index)),
2493  ((PPH_STRING)PhAutoDereferenceObject(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
2494  ));
2495  }
2496 
2497  getTooltipText->Text = CpuGraphState.TooltipText->sr;
2498  }
2499  else
2500  {
2501  if (CpusGraphState[Index].TooltipIndex != getTooltipText->Index)
2502  {
2503  FLOAT cpuKernel;
2504  FLOAT cpuUser;
2505 
2506  cpuKernel = PhGetItemCircularBuffer_FLOAT(&PhCpusKernelHistory[Index], getTooltipText->Index);
2507  cpuUser = PhGetItemCircularBuffer_FLOAT(&PhCpusUserHistory[Index], getTooltipText->Index);
2508 
2509  PhMoveReference(&CpusGraphState[Index].TooltipText, PhFormatString(
2510  L"%.2f%% (K: %.2f%%, U: %.2f%%)%s\n%s",
2511  (cpuKernel + cpuUser) * 100,
2512  cpuKernel * 100,
2513  cpuUser * 100,
2514  PhGetStringOrEmpty(PhSipGetMaxCpuString(getTooltipText->Index)),
2515  ((PPH_STRING)PhAutoDereferenceObject(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
2516  ));
2517  }
2518 
2519  getTooltipText->Text = CpusGraphState[Index].TooltipText->sr;
2520  }
2521  }
2522  }
2523  break;
2524  case GCN_MOUSEEVENT:
2525  {
2526  PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Header;
2527  PPH_PROCESS_RECORD record;
2528 
2529  record = NULL;
2530 
2531  if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount)
2532  {
2533  record = PhSipReferenceMaxCpuRecord(mouseEvent->Index);
2534  }
2535 
2536  if (record)
2537  {
2538  PhShowProcessRecordDialog(CpuDialog, record);
2540  }
2541  }
2542  break;
2543  }
2544 }
2545 
2547  VOID
2548  )
2549 {
2550  ULONG i;
2551 
2552  CpuGraphState.Valid = FALSE;
2553  CpuGraphState.TooltipIndex = -1;
2554  Graph_MoveGrid(CpuGraphHandle, 1);
2555  Graph_Draw(CpuGraphHandle);
2556  Graph_UpdateTooltip(CpuGraphHandle);
2557  InvalidateRect(CpuGraphHandle, NULL, FALSE);
2558 
2559  for (i = 0; i < NumberOfProcessors; i++)
2560  {
2561  CpusGraphState[i].Valid = FALSE;
2562  CpusGraphState[i].TooltipIndex = -1;
2563  Graph_MoveGrid(CpusGraphHandle[i], 1);
2564  Graph_Draw(CpusGraphHandle[i]);
2565  Graph_UpdateTooltip(CpusGraphHandle[i]);
2566  InvalidateRect(CpusGraphHandle[i], NULL, FALSE);
2567  }
2568 }
2569 
2571  VOID
2572  )
2573 {
2574  HWND hwnd = CpuPanel;
2575  DOUBLE cpuFraction;
2576  DOUBLE cpuGhz;
2577  BOOLEAN distributionSucceeded;
2578  SYSTEM_TIMEOFDAY_INFORMATION timeOfDayInfo;
2579  WCHAR uptimeString[PH_TIMESPAN_STR_LEN_1] = L"Unknown";
2580 
2581  SetDlgItemText(hwnd, IDC_UTILIZATION, PhaFormatString(L"%.2f%%", (PhCpuUserUsage + PhCpuKernelUsage) * 100)->Buffer);
2582 
2583  cpuGhz = 0;
2584  distributionSucceeded = FALSE;
2585 
2586  if (WindowsVersion >= WINDOWS_7 && CurrentPerformanceDistribution && PreviousPerformanceDistribution)
2587  {
2588  if (PhSipGetCpuFrequencyFromDistribution(&cpuFraction))
2589  {
2590  cpuGhz = (DOUBLE)PowerInformation[0].MaxMhz * cpuFraction / 1000;
2591  distributionSucceeded = TRUE;
2592  }
2593  }
2594 
2595  if (!distributionSucceeded)
2596  cpuGhz = (DOUBLE)PowerInformation[0].CurrentMhz / 1000;
2597 
2598  SetDlgItemText(hwnd, IDC_SPEED, PhaFormatString(L"%.2f / %.2f GHz", cpuGhz, (DOUBLE)PowerInformation[0].MaxMhz / 1000)->Buffer);
2599 
2600  SetDlgItemText(hwnd, IDC_ZPROCESSES_V, PhaFormatUInt64(PhTotalProcesses, TRUE)->Buffer);
2601  SetDlgItemText(hwnd, IDC_ZTHREADS_V, PhaFormatUInt64(PhTotalThreads, TRUE)->Buffer);
2602  SetDlgItemText(hwnd, IDC_ZHANDLES_V, PhaFormatUInt64(PhTotalHandles, TRUE)->Buffer);
2603 
2604  if (NT_SUCCESS(NtQuerySystemInformation(
2606  &timeOfDayInfo,
2608  NULL
2609  )))
2610  {
2611  PhPrintTimeSpan(uptimeString, timeOfDayInfo.CurrentTime.QuadPart - timeOfDayInfo.BootTime.QuadPart, PH_TIMESPAN_DHMS);
2612  }
2613 
2614  SetDlgItemText(hwnd, IDC_ZUPTIME_V, uptimeString);
2615 
2616  if (CpuTicked > 1)
2617  SetDlgItemText(hwnd, IDC_ZCONTEXTSWITCHESDELTA_V, PhaFormatUInt64(ContextSwitchesDelta.Delta, TRUE)->Buffer);
2618  else
2619  SetDlgItemText(hwnd, IDC_ZCONTEXTSWITCHESDELTA_V, L"-");
2620 
2621  if (CpuTicked > 1)
2622  SetDlgItemText(hwnd, IDC_ZINTERRUPTSDELTA_V, PhaFormatUInt64(InterruptsDelta.Delta, TRUE)->Buffer);
2623  else
2624  SetDlgItemText(hwnd, IDC_ZINTERRUPTSDELTA_V, L"-");
2625 
2626  if (CpuTicked > 1)
2627  SetDlgItemText(hwnd, IDC_ZDPCSDELTA_V, PhaFormatUInt64(DpcsDelta.Delta, TRUE)->Buffer);
2628  else
2629  SetDlgItemText(hwnd, IDC_ZDPCSDELTA_V, L"-");
2630 
2631  if (CpuTicked > 1)
2632  SetDlgItemText(hwnd, IDC_ZSYSTEMCALLSDELTA_V, PhaFormatUInt64(SystemCallsDelta.Delta, TRUE)->Buffer);
2633  else
2634  SetDlgItemText(hwnd, IDC_ZSYSTEMCALLSDELTA_V, L"-");
2635 }
2636 
2638  _In_ LONG Index
2639  )
2640 {
2641  LARGE_INTEGER time;
2642  ULONG maxProcessId;
2643 
2644  // Find the process record for the max. CPU process for the particular time.
2645 
2646  maxProcessId = PhGetItemCircularBuffer_ULONG(&PhMaxCpuHistory, Index);
2647 
2648  if (!maxProcessId)
2649  return NULL;
2650 
2651  // Note that the time we get has its components beyond seconds cleared.
2652  // For example:
2653  // * At 2.5 seconds a process is started.
2654  // * At 2.75 seconds our process provider is fired, and the process is determined
2655  // to have 75% CPU usage, which happens to be the maximum CPU usage.
2656  // * However the 2.75 seconds is recorded as 2 seconds due to
2657  // RtlTimeToSecondsSince1980.
2658  // * If we call PhFindProcessRecord, it cannot find the process because it was
2659  // started at 2.5 seconds, not 2 seconds or older.
2660  //
2661  // This mean we must add one second minus one tick (100ns) to the time, giving us
2662  // 2.9999999 seconds. This will then make sure we find the process.
2663  PhGetStatisticsTime(NULL, Index, &time);
2664  time.QuadPart += PH_TICKS_PER_SEC - 1;
2665 
2666  return PhFindProcessRecord(UlongToHandle(maxProcessId), &time);
2667 }
2668 
2670  _In_ LONG Index
2671  )
2672 {
2673  PPH_PROCESS_RECORD maxProcessRecord;
2674 #ifdef PH_RECORD_MAX_USAGE
2675  FLOAT maxCpuUsage;
2676 #endif
2677  PPH_STRING maxUsageString = NULL;
2678 
2679  if (maxProcessRecord = PhSipReferenceMaxCpuRecord(Index))
2680  {
2681  // We found the process record, so now we construct the max. usage string.
2682 #ifdef PH_RECORD_MAX_USAGE
2683  maxCpuUsage = PhGetItemCircularBuffer_FLOAT(&PhMaxCpuUsageHistory, Index);
2684 
2685  // Make sure we don't try to display the PID of DPCs or Interrupts.
2686  if (!PH_IS_FAKE_PROCESS_ID(maxProcessRecord->ProcessId))
2687  {
2688  maxUsageString = PhaFormatString(
2689  L"\n%s (%u): %.2f%%",
2690  maxProcessRecord->ProcessName->Buffer,
2691  (ULONG)maxProcessRecord->ProcessId,
2692  maxCpuUsage * 100
2693  );
2694  }
2695  else
2696  {
2697  maxUsageString = PhaFormatString(
2698  L"\n%s: %.2f%%",
2699  maxProcessRecord->ProcessName->Buffer,
2700  maxCpuUsage * 100
2701  );
2702  }
2703 #else
2704  maxUsageString = PhaConcatStrings2(L"\n", maxProcessRecord->ProcessName->Buffer);
2705 #endif
2706 
2707  PhDereferenceProcessRecord(maxProcessRecord);
2708  }
2709 
2710  return maxUsageString;
2711 }
2712 
2714  _Out_writes_(49) PWSTR BrandString
2715  )
2716 {
2717  ULONG brandString[4 * 3];
2718 
2719  __cpuid(&brandString[0], 0x80000002);
2720  __cpuid(&brandString[4], 0x80000003);
2721  __cpuid(&brandString[8], 0x80000004);
2722 
2723  PhZeroExtendToUtf16Buffer((PSTR)brandString, 48, BrandString);
2724  BrandString[48] = 0;
2725 }
2726 
2728  _Out_ DOUBLE *Fraction
2729  )
2730 {
2731  ULONG stateSize;
2732  PVOID differences;
2736  ULONG i;
2737  ULONG j;
2738  DOUBLE count;
2739  DOUBLE total;
2740 
2741  // Calculate the differences from the last performance distribution.
2742 
2743  if (CurrentPerformanceDistribution->ProcessorCount != NumberOfProcessors || PreviousPerformanceDistribution->ProcessorCount != NumberOfProcessors)
2744  return FALSE;
2745 
2746  stateSize = FIELD_OFFSET(SYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION, States) + sizeof(SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT) * 2;
2747  differences = PhAllocate(stateSize * NumberOfProcessors);
2748 
2749  for (i = 0; i < NumberOfProcessors; i++)
2750  {
2751  stateDistribution = (PSYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION)((PCHAR)CurrentPerformanceDistribution + CurrentPerformanceDistribution->Offsets[i]);
2752  stateDifference = (PSYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION)((PCHAR)differences + stateSize * i);
2753 
2754  if (stateDistribution->StateCount != 2)
2755  {
2756  PhFree(differences);
2757  return FALSE;
2758  }
2759 
2760  for (j = 0; j < stateDistribution->StateCount; j++)
2761  {
2762  if (WindowsVersion >= WINDOWS_8_1)
2763  {
2764  stateDifference->States[j] = stateDistribution->States[j];
2765  }
2766  else
2767  {
2768  hitcountOld = (PSYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8)((PCHAR)stateDistribution->States + sizeof(SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8) * j);
2769  stateDifference->States[j].Hits.QuadPart = hitcountOld->Hits;
2770  stateDifference->States[j].PercentFrequency = hitcountOld->PercentFrequency;
2771  }
2772  }
2773  }
2774 
2775  for (i = 0; i < NumberOfProcessors; i++)
2776  {
2777  stateDistribution = (PSYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION)((PCHAR)PreviousPerformanceDistribution + PreviousPerformanceDistribution->Offsets[i]);
2778  stateDifference = (PSYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION)((PCHAR)differences + stateSize * i);
2779 
2780  if (stateDistribution->StateCount != 2)
2781  {
2782  PhFree(differences);
2783  return FALSE;
2784  }
2785 
2786  for (j = 0; j < stateDistribution->StateCount; j++)
2787  {
2788  if (WindowsVersion >= WINDOWS_8_1)
2789  {
2790  stateDifference->States[j].Hits.QuadPart -= stateDistribution->States[j].Hits.QuadPart;
2791  }
2792  else
2793  {
2794  hitcountOld = (PSYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8)((PCHAR)stateDistribution->States + sizeof(SYSTEM_PROCESSOR_PERFORMANCE_HITCOUNT_WIN8) * j);
2795  stateDifference->States[j].Hits.QuadPart -= hitcountOld->Hits;
2796  }
2797  }
2798  }
2799 
2800  // Calculate the frequency.
2801 
2802  count = 0;
2803  total = 0;
2804 
2805  for (i = 0; i < NumberOfProcessors; i++)
2806  {
2807  stateDifference = (PSYSTEM_PROCESSOR_PERFORMANCE_STATE_DISTRIBUTION)((PCHAR)differences + stateSize * i);
2808 
2809  for (j = 0; j < 2; j++)
2810  {
2811  count += (ULONGLONG)stateDifference->States[j].Hits.QuadPart;
2812  total += (ULONGLONG)stateDifference->States[j].Hits.QuadPart * stateDifference->States[j].PercentFrequency;
2813  }
2814  }
2815 
2816  PhFree(differences);
2817 
2818  if (count == 0)
2819  return FALSE;
2820 
2821  total /= count;
2822  total /= 100;
2823  *Fraction = total;
2824 
2825  return TRUE;
2826 }
2827 
2829  _Out_ PVOID *Buffer
2830  )
2831 {
2832  NTSTATUS status;
2833  PVOID buffer;
2834  ULONG bufferSize;
2835  ULONG attempts;
2836 
2837  bufferSize = 0x100;
2838  buffer = PhAllocate(bufferSize);
2839 
2840  status = NtQuerySystemInformation(
2842  buffer,
2843  bufferSize,
2844  &bufferSize
2845  );
2846  attempts = 0;
2847 
2848  while (status == STATUS_INFO_LENGTH_MISMATCH && attempts < 8)
2849  {
2850  PhFree(buffer);
2851  buffer = PhAllocate(bufferSize);
2852 
2853  status = NtQuerySystemInformation(
2855  buffer,
2856  bufferSize,
2857  &bufferSize
2858  );
2859  attempts++;
2860  }
2861 
2862  if (NT_SUCCESS(status))
2863  *Buffer = buffer;
2864  else
2865  PhFree(buffer);
2866 
2867  return status;
2868 }
2869 
2871  _In_ PPH_SYSINFO_SECTION Section,
2872  _In_ PH_SYSINFO_SECTION_MESSAGE Message,
2873  _In_opt_ PVOID Parameter1,
2874  _In_opt_ PVOID Parameter2
2875  )
2876 {
2877  switch (Message)
2878  {
2879  case SysInfoDestroy:
2880  {
2881  if (MemoryDialog)
2882  {
2884  MemoryDialog = NULL;
2885  }
2886  }
2887  break;
2888  case SysInfoTick:
2889  {
2890  if (MemoryDialog)
2891  {
2893  }
2894  }
2895  return TRUE;
2896  case SysInfoCreateDialog:
2897  {
2898  PPH_SYSINFO_CREATE_DIALOG createDialog = Parameter1;
2899 
2900  createDialog->Instance = PhInstanceHandle;
2901  createDialog->Template = MAKEINTRESOURCE(IDD_SYSINFO_MEM);
2902  createDialog->DialogProc = PhSipMemoryDialogProc;
2903  }
2904  return TRUE;
2906  {
2907  PPH_GRAPH_DRAW_INFO drawInfo = Parameter1;
2908  ULONG i;
2909 
2910  if (PhGetIntegerSetting(L"ShowCommitInSummary"))
2911  {
2912  drawInfo->Flags = PH_GRAPH_USE_GRID;
2913  Section->Parameters->ColorSetupFunction(drawInfo, PhCsColorPrivate, 0);
2914  PhGetDrawInfoGraphBuffers(&Section->GraphState.Buffers, drawInfo, PhCommitHistory.Count);
2915 
2916  if (!Section->GraphState.Valid)
2917  {
2918  for (i = 0; i < drawInfo->LineDataCount; i++)
2919  {
2920  Section->GraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&PhCommitHistory, i);
2921  }
2922 
2923  if (PhPerfInformation.CommitLimit != 0)
2924  {
2925  // Scale the data.
2927  Section->GraphState.Data1,
2929  drawInfo->LineDataCount
2930  );
2931  }
2932 
2933  Section->GraphState.Valid = TRUE;
2934  }
2935  }
2936  else
2937  {
2938  drawInfo->Flags = PH_GRAPH_USE_GRID;
2939  Section->Parameters->ColorSetupFunction(drawInfo, PhCsColorPhysical, 0);
2940  PhGetDrawInfoGraphBuffers(&Section->GraphState.Buffers, drawInfo, PhPhysicalHistory.Count);
2941 
2942  if (!Section->GraphState.Valid)
2943  {
2944  for (i = 0; i < drawInfo->LineDataCount; i++)
2945  {
2946  Section->GraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&PhPhysicalHistory, i);
2947  }
2948 
2950  {
2951  // Scale the data.
2953  Section->GraphState.Data1,
2955  drawInfo->LineDataCount
2956  );
2957  }
2958 
2959  Section->GraphState.Valid = TRUE;
2960  }
2961  }
2962  }
2963  return TRUE;
2965  {
2966  PPH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT getTooltipText = Parameter1;
2967  ULONG usedPages;
2968 
2969  if (PhGetIntegerSetting(L"ShowCommitInSummary"))
2970  {
2971  usedPages = PhGetItemCircularBuffer_ULONG(&PhCommitHistory, getTooltipText->Index);
2972 
2973  PhMoveReference(&Section->GraphState.TooltipText, PhFormatString(
2974  L"Commit Charge: %s\n%s",
2975  PhaFormatSize(UInt32x32To64(usedPages, PAGE_SIZE), -1)->Buffer,
2976  ((PPH_STRING)PhAutoDereferenceObject(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
2977  ));
2978  getTooltipText->Text = Section->GraphState.TooltipText->sr;
2979  }
2980  else
2981  {
2982  usedPages = PhGetItemCircularBuffer_ULONG(&PhPhysicalHistory, getTooltipText->Index);
2983 
2984  PhMoveReference(&Section->GraphState.TooltipText, PhFormatString(
2985  L"Physical Memory: %s\n%s",
2986  PhaFormatSize(UInt32x32To64(usedPages, PAGE_SIZE), -1)->Buffer,
2987  ((PPH_STRING)PhAutoDereferenceObject(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
2988  ));
2989  getTooltipText->Text = Section->GraphState.TooltipText->sr;
2990  }
2991  }
2992  return TRUE;
2993  case SysInfoGraphDrawPanel:
2994  {
2995  PPH_SYSINFO_DRAW_PANEL drawPanel = Parameter1;
2996  ULONG totalPages;
2997  ULONG usedPages;
2998 
2999  if (PhGetIntegerSetting(L"ShowCommitInSummary"))
3000  {
3001  totalPages = PhPerfInformation.CommitLimit;
3002  usedPages = PhPerfInformation.CommittedPages;
3003  }
3004  else
3005  {
3007  usedPages = totalPages - PhPerfInformation.AvailablePages;
3008  }
3009 
3010  drawPanel->Title = PhCreateString(L"Memory");
3011  drawPanel->SubTitle = PhFormatString(
3012  L"%.0f%%\n%s / %s",
3013  (FLOAT)usedPages * 100 / totalPages,
3014  PhSipFormatSizeWithPrecision(UInt32x32To64(usedPages, PAGE_SIZE), 1)->Buffer,
3015  PhSipFormatSizeWithPrecision(UInt32x32To64(totalPages, PAGE_SIZE), 1)->Buffer
3016  );
3017  drawPanel->SubTitleOverflow = PhFormatString(
3018  L"%.0f%%\n%s",
3019  (FLOAT)usedPages * 100 / totalPages,
3020  PhSipFormatSizeWithPrecision(UInt32x32To64(usedPages, PAGE_SIZE), 1)->Buffer
3021  );
3022  }
3023  return TRUE;
3024  }
3025 
3026  return FALSE;
3027 }
3028 
3030  VOID
3031  )
3032 {
3033  PhInitializeDelta(&PagedAllocsDelta);
3034  PhInitializeDelta(&PagedFreesDelta);
3035  PhInitializeDelta(&NonPagedAllocsDelta);
3036  PhInitializeDelta(&NonPagedFreesDelta);
3037  PhInitializeDelta(&PageFaultsDelta);
3038  PhInitializeDelta(&PageReadsDelta);
3039  PhInitializeDelta(&PagefileWritesDelta);
3040  PhInitializeDelta(&MappedWritesDelta);
3041 
3042  PhInitializeGraphState(&CommitGraphState);
3043  PhInitializeGraphState(&PhysicalGraphState);
3044 
3045  MemoryTicked = 0;
3046 
3047  if (!MmAddressesInitialized && KphIsConnected())
3048  {
3050  MmAddressesInitialized = TRUE;
3051  }
3052 }
3053 
3055  VOID
3056  )
3057 {
3058  PhDeleteGraphState(&CommitGraphState);
3059  PhDeleteGraphState(&PhysicalGraphState);
3060 }
3061 
3063  VOID
3064  )
3065 {
3066  PhUpdateDelta(&PagedAllocsDelta, PhPerfInformation.PagedPoolAllocs);
3067  PhUpdateDelta(&PagedFreesDelta, PhPerfInformation.PagedPoolFrees);
3068  PhUpdateDelta(&NonPagedAllocsDelta, PhPerfInformation.NonPagedPoolAllocs);
3069  PhUpdateDelta(&NonPagedFreesDelta, PhPerfInformation.NonPagedPoolFrees);
3070  PhUpdateDelta(&PageFaultsDelta, PhPerfInformation.PageFaultCount);
3071  PhUpdateDelta(&PageReadsDelta, PhPerfInformation.PageReadCount);
3072  PhUpdateDelta(&PagefileWritesDelta, PhPerfInformation.DirtyPagesWriteCount);
3074 
3075  MemoryTicked++;
3076 
3077  if (MemoryTicked > 2)
3078  MemoryTicked = 2;
3079 
3082 }
3083 
3084 INT_PTR CALLBACK PhSipMemoryDialogProc(
3085  _In_ HWND hwndDlg,
3086  _In_ UINT uMsg,
3087  _In_ WPARAM wParam,
3088  _In_ LPARAM lParam
3089  )
3090 {
3091  switch (uMsg)
3092  {
3093  case WM_INITDIALOG:
3094  {
3095  static BOOL (WINAPI *getPhysicallyInstalledSystemMemory)(PULONGLONG) = NULL;
3096 
3097  PPH_LAYOUT_ITEM graphItem;
3098  PPH_LAYOUT_ITEM panelItem;
3099  ULONGLONG installedMemory;
3100 
3102 
3103  MemoryDialog = hwndDlg;
3104  PhInitializeLayoutManager(&MemoryLayoutManager, hwndDlg);
3105  PhAddLayoutItem(&MemoryLayoutManager, GetDlgItem(hwndDlg, IDC_TOTALPHYSICAL), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT | PH_LAYOUT_FORCE_INVALIDATE);
3106  graphItem = PhAddLayoutItem(&MemoryLayoutManager, GetDlgItem(hwndDlg, IDC_GRAPH_LAYOUT), NULL, PH_ANCHOR_ALL);
3107  MemoryGraphMargin = graphItem->Margin;
3108  panelItem = PhAddLayoutItem(&MemoryLayoutManager, GetDlgItem(hwndDlg, IDC_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
3109 
3110  SendMessage(GetDlgItem(hwndDlg, IDC_TITLE), WM_SETFONT, (WPARAM)CurrentParameters.LargeFont, FALSE);
3111  SendMessage(GetDlgItem(hwndDlg, IDC_TOTALPHYSICAL), WM_SETFONT, (WPARAM)CurrentParameters.MediumFont, FALSE);
3112 
3113  if (!getPhysicallyInstalledSystemMemory)
3114  getPhysicallyInstalledSystemMemory = PhGetModuleProcAddress(L"kernel32.dll", "GetPhysicallyInstalledSystemMemory");
3115 
3116  if (getPhysicallyInstalledSystemMemory && getPhysicallyInstalledSystemMemory(&installedMemory))
3117  {
3118  SetDlgItemText(hwndDlg, IDC_TOTALPHYSICAL,
3119  PhaConcatStrings2(PhaFormatSize(installedMemory * 1024, -1)->Buffer, L" installed")->Buffer);
3120  }
3121  else
3122  {
3123  SetDlgItemText(hwndDlg, IDC_TOTALPHYSICAL,
3125  }
3126 
3127  MemoryPanel = CreateDialog(
3129  WindowsVersion >= WINDOWS_VISTA ? MAKEINTRESOURCE(IDD_SYSINFO_MEMPANEL) : MAKEINTRESOURCE(IDD_SYSINFO_MEMPANELXP),
3130  hwndDlg,
3132  );
3133  ShowWindow(MemoryPanel, SW_SHOW);
3134  PhAddLayoutItemEx(&MemoryLayoutManager, MemoryPanel, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM, panelItem->Margin);
3135 
3136  CommitGraphHandle = CreateWindow(
3138  NULL,
3139  WS_VISIBLE | WS_CHILD | WS_BORDER,
3140  0,
3141  0,
3142  3,
3143  3,
3144  MemoryDialog,
3145  (HMENU)IDC_COMMIT,
3147  NULL
3148  );
3149  Graph_SetTooltip(CommitGraphHandle, TRUE);
3150 
3151  PhysicalGraphHandle = CreateWindow(
3153  NULL,
3154  WS_VISIBLE | WS_CHILD | WS_BORDER,
3155  0,
3156  0,
3157  3,
3158  3,
3159  MemoryDialog,
3160  (HMENU)IDC_PHYSICAL,
3162  NULL
3163  );
3164  Graph_SetTooltip(PhysicalGraphHandle, TRUE);
3165 
3168  }
3169  break;
3170  case WM_DESTROY:
3171  {
3172  PhDeleteLayoutManager(&MemoryLayoutManager);
3173  }
3174  break;
3175  case WM_SIZE:
3176  {
3177  PhLayoutManagerLayout(&MemoryLayoutManager);
3179  }
3180  break;
3181  case WM_NOTIFY:
3182  {
3183  NMHDR *header = (NMHDR *)lParam;
3184 
3185  if (header->hwndFrom == CommitGraphHandle)
3186  {
3187  PhSipNotifyCommitGraph(header);
3188  }
3189  else if (header->hwndFrom == PhysicalGraphHandle)
3190  {
3191  PhSipNotifyPhysicalGraph(header);
3192  }
3193  }
3194  break;
3195  }
3196 
3197  return FALSE;
3198 }
3199 
3201  _In_ HWND hwndDlg,
3202  _In_ UINT uMsg,
3203  _In_ WPARAM wParam,
3204  _In_ LPARAM lParam
3205  )
3206 {
3207  switch (uMsg)
3208  {
3209  case WM_INITDIALOG:
3210  {
3211  NOTHING;
3212  }
3213  break;
3214  case WM_COMMAND:
3215  {
3216  switch (LOWORD(wParam))
3217  {
3218  case IDC_MORE:
3219  {
3221  }
3222  break;
3223  }
3224  }
3225  break;
3226  }
3227 
3228  return FALSE;
3229 }
3230 
3232  VOID
3233  )
3234 {
3235  RECT clientRect;
3236  RECT labelRect;
3237  ULONG graphWidth;
3238  ULONG graphHeight;
3239  HDWP deferHandle;
3240  ULONG y;
3241 
3242  GetClientRect(MemoryDialog, &clientRect);
3243  GetClientRect(GetDlgItem(MemoryDialog, IDC_COMMIT_L), &labelRect);
3244  graphWidth = clientRect.right - MemoryGraphMargin.left - MemoryGraphMargin.right;
3245  graphHeight = (clientRect.bottom - MemoryGraphMargin.top - MemoryGraphMargin.bottom - labelRect.bottom * 2 - PH_SYSINFO_MEMORY_PADDING * 3) / 2;
3246 
3247  deferHandle = BeginDeferWindowPos(4);
3248  y = MemoryGraphMargin.top;
3249 
3250  deferHandle = DeferWindowPos(
3251  deferHandle,
3252  GetDlgItem(MemoryDialog, IDC_COMMIT_L),
3253  NULL,
3254  MemoryGraphMargin.left,
3255  y,
3256  0,
3257  0,
3258  SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER
3259  );
3260  y += labelRect.bottom + PH_SYSINFO_MEMORY_PADDING;
3261 
3262  deferHandle = DeferWindowPos(
3263  deferHandle,
3264  CommitGraphHandle,
3265  NULL,
3266  MemoryGraphMargin.left,
3267  y,
3268  graphWidth,
3269  graphHeight,
3270  SWP_NOACTIVATE | SWP_NOZORDER
3271  );
3272  y += graphHeight + PH_SYSINFO_MEMORY_PADDING;
3273 
3274  deferHandle = DeferWindowPos(
3275  deferHandle,
3276  GetDlgItem(MemoryDialog, IDC_PHYSICAL_L),
3277  NULL,
3278  MemoryGraphMargin.left,
3279  y,
3280  0,
3281  0,
3282  SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER
3283  );
3284  y += labelRect.bottom + PH_SYSINFO_MEMORY_PADDING;
3285 
3286  deferHandle = DeferWindowPos(
3287  deferHandle,
3288  PhysicalGraphHandle,
3289  NULL,
3290  MemoryGraphMargin.left,
3291  y,
3292  graphWidth,
3293  clientRect.bottom - MemoryGraphMargin.bottom - y,
3294  SWP_NOACTIVATE | SWP_NOZORDER
3295  );
3296 
3297  EndDeferWindowPos(deferHandle);
3298 }
3299 
3301  _In_ NMHDR *Header
3302  )
3303 {
3304  switch (Header->code)
3305  {
3306  case GCN_GETDRAWINFO:
3307  {
3308  PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header;
3309  PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;
3310  ULONG i;
3311 
3312  drawInfo->Flags = PH_GRAPH_USE_GRID;
3314 
3316  &CommitGraphState,
3317  getDrawInfo,
3318  PhCommitHistory.Count
3319  );
3320 
3321  if (!CommitGraphState.Valid)
3322  {
3323  for (i = 0; i < drawInfo->LineDataCount; i++)
3324  {
3325  CommitGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&PhCommitHistory, i);
3326  }
3327 
3328  if (PhPerfInformation.CommitLimit != 0)
3329  {
3330  // Scale the data.
3332  CommitGraphState.Data1,
3334  drawInfo->LineDataCount
3335  );
3336  }
3337 
3338  CommitGraphState.Valid = TRUE;
3339  }
3340  }
3341  break;
3342  case GCN_GETTOOLTIPTEXT:
3343  {
3344  PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header;
3345 
3346  if (getTooltipText->Index < getTooltipText->TotalCount)
3347  {
3348  if (CommitGraphState.TooltipIndex != getTooltipText->Index)
3349  {
3350  ULONG usedPages;
3351 
3352  usedPages = PhGetItemCircularBuffer_ULONG(&PhCommitHistory, getTooltipText->Index);
3353 
3354  PhMoveReference(&CommitGraphState.TooltipText, PhFormatString(
3355  L"Commit Charge: %s\n%s",
3356  PhaFormatSize(UInt32x32To64(usedPages, PAGE_SIZE), -1)->Buffer,
3357  ((PPH_STRING)PhAutoDereferenceObject(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
3358  ));
3359  }
3360 
3361  getTooltipText->Text = CommitGraphState.TooltipText->sr;
3362  }
3363  }
3364  break;
3365  }
3366 }
3367 
3369  _In_ NMHDR *Header
3370  )
3371 {
3372  switch (Header->code)
3373  {
3374  case GCN_GETDRAWINFO:
3375  {
3376  PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header;
3377  PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;
3378  ULONG i;
3379 
3380  drawInfo->Flags = PH_GRAPH_USE_GRID;
3382 
3384  &PhysicalGraphState,
3385  getDrawInfo,
3386  PhPhysicalHistory.Count
3387  );
3388 
3389  if (!PhysicalGraphState.Valid)
3390  {
3391  for (i = 0; i < drawInfo->LineDataCount; i++)
3392  {
3393  PhysicalGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&PhPhysicalHistory, i);
3394  }
3395 
3397  {
3398  // Scale the data.
3400  PhysicalGraphState.Data1,
3402  drawInfo->LineDataCount
3403  );
3404  }
3405 
3406  PhysicalGraphState.Valid = TRUE;
3407  }
3408  }
3409  break;
3410  case GCN_GETTOOLTIPTEXT:
3411  {
3412  PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header;
3413 
3414  if (getTooltipText->Index < getTooltipText->TotalCount)
3415  {
3416  if (PhysicalGraphState.TooltipIndex != getTooltipText->Index)
3417  {
3418  ULONG usedPages;
3419 
3420  usedPages = PhGetItemCircularBuffer_ULONG(&PhPhysicalHistory, getTooltipText->Index);
3421 
3422  PhMoveReference(&PhysicalGraphState.TooltipText, PhFormatString(
3423  L"Physical Memory: %s\n%s",
3424  PhaFormatSize(UInt32x32To64(usedPages, PAGE_SIZE), -1)->Buffer,
3425  ((PPH_STRING)PhAutoDereferenceObject(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
3426  ));
3427  }
3428 
3429  getTooltipText->Text = PhysicalGraphState.TooltipText->sr;
3430  }
3431  }
3432  break;
3433  }
3434 }
3435 
3437  VOID
3438  )
3439 {
3440  CommitGraphState.Valid = FALSE;
3441  CommitGraphState.TooltipIndex = -1;
3442  Graph_MoveGrid(CommitGraphHandle, 1);
3443  Graph_Draw(CommitGraphHandle);
3444  Graph_UpdateTooltip(CommitGraphHandle);
3445  InvalidateRect(CommitGraphHandle, NULL, FALSE);
3446 
3447  PhysicalGraphState.Valid = FALSE;
3448  PhysicalGraphState.TooltipIndex = -1;
3449  Graph_MoveGrid(PhysicalGraphHandle, 1);
3450  Graph_Draw(PhysicalGraphHandle);
3451  Graph_UpdateTooltip(PhysicalGraphHandle);
3452  InvalidateRect(PhysicalGraphHandle, NULL, FALSE);
3453 }
3454 
3456  VOID
3457  )
3458 {
3459  PWSTR pagedLimit;
3460  PWSTR nonPagedLimit;
3461  SYSTEM_MEMORY_LIST_INFORMATION memoryListInfo;
3462 
3463  // Commit Charge
3464 
3465  SetDlgItemText(MemoryPanel, IDC_ZCOMMITCURRENT_V,
3466  PhaFormatSize(UInt32x32To64(PhPerfInformation.CommittedPages, PAGE_SIZE), -1)->Buffer);
3467  SetDlgItemText(MemoryPanel, IDC_ZCOMMITPEAK_V,
3468  PhaFormatSize(UInt32x32To64(PhPerfInformation.PeakCommitment, PAGE_SIZE), -1)->Buffer);
3469  SetDlgItemText(MemoryPanel, IDC_ZCOMMITLIMIT_V,
3470  PhaFormatSize(UInt32x32To64(PhPerfInformation.CommitLimit, PAGE_SIZE), -1)->Buffer);
3471 
3472  // Physical Memory
3473 
3474  SetDlgItemText(MemoryPanel, IDC_ZPHYSICALCURRENT_V,
3476  SetDlgItemText(MemoryPanel, IDC_ZPHYSICALTOTAL_V,
3478  SetDlgItemText(MemoryPanel, IDC_ZPHYSICALCACHEWS_V,
3479  PhaFormatSize(UInt32x32To64(PhPerfInformation.ResidentSystemCachePage, PAGE_SIZE), -1)->Buffer);
3480  SetDlgItemText(MemoryPanel, IDC_ZPHYSICALKERNELWS_V,
3481  PhaFormatSize(UInt32x32To64(PhPerfInformation.ResidentSystemCodePage, PAGE_SIZE), -1)->Buffer);
3482  SetDlgItemText(MemoryPanel, IDC_ZPHYSICALDRIVERWS_V,
3483  PhaFormatSize(UInt32x32To64(PhPerfInformation.ResidentSystemDriverPage, PAGE_SIZE), -1)->Buffer);
3484 
3485  // Paged Pool
3486 
3487  SetDlgItemText(MemoryPanel, IDC_ZPAGEDWORKINGSET_V,
3488  PhaFormatSize(UInt32x32To64(PhPerfInformation.ResidentPagedPoolPage, PAGE_SIZE), -1)->Buffer);
3489  SetDlgItemText(MemoryPanel, IDC_ZPAGEDVIRTUALSIZE_V,
3490  PhaFormatSize(UInt32x32To64(PhPerfInformation.PagedPoolPages, PAGE_SIZE), -1)->Buffer);
3491 
3492  if (MemoryTicked > 1)
3493  SetDlgItemText(MemoryPanel, IDC_ZPAGEDALLOCSDELTA_V, PhaFormatUInt64(PagedAllocsDelta.Delta, TRUE)->Buffer);
3494  else
3495  SetDlgItemText(MemoryPanel, IDC_ZPAGEDALLOCSDELTA_V, L"-");
3496 
3497  if (MemoryTicked > 1)
3498  SetDlgItemText(MemoryPanel, IDC_ZPAGEDFREESDELTA_V, PhaFormatUInt64(PagedFreesDelta.Delta, TRUE)->Buffer);
3499  else
3500  SetDlgItemText(MemoryPanel, IDC_ZPAGEDFREESDELTA_V, L"-");
3501 
3502  // Non-Paged Pool
3503 
3504  SetDlgItemText(MemoryPanel, IDC_ZNONPAGEDUSAGE_V,
3505  PhaFormatSize(UInt32x32To64(PhPerfInformation.NonPagedPoolPages, PAGE_SIZE), -1)->Buffer);
3506 
3507  if (MemoryTicked > 1)
3508  SetDlgItemText(MemoryPanel, IDC_ZNONPAGEDALLOCSDELTA_V, PhaFormatUInt64(PagedAllocsDelta.Delta, TRUE)->Buffer);
3509  else
3510  SetDlgItemText(MemoryPanel, IDC_ZNONPAGEDALLOCSDELTA_V, L"-");
3511 
3512  if (MemoryTicked > 1)
3513  SetDlgItemText(MemoryPanel, IDC_ZNONPAGEDFREESDELTA_V, PhaFormatUInt64(NonPagedFreesDelta.Delta, TRUE)->Buffer);
3514  else
3515  SetDlgItemText(MemoryPanel, IDC_ZNONPAGEDFREESDELTA_V, L"-");
3516 
3517  // Pools (KPH)
3518 
3519  if (MmAddressesInitialized && (MmSizeOfPagedPoolInBytes || MmMaximumNonPagedPoolInBytes))
3520  {
3521  SIZE_T paged;
3522  SIZE_T nonPaged;
3523 
3524  PhSipGetPoolLimits(&paged, &nonPaged);
3525  pagedLimit = PhaFormatSize(paged, -1)->Buffer;
3526  nonPagedLimit = PhaFormatSize(nonPaged, -1)->Buffer;
3527  }
3528  else
3529  {
3530  if (!KphIsConnected())
3531  {
3532  pagedLimit = nonPagedLimit = L"no driver";
3533  }
3534  else
3535  {
3536  pagedLimit = nonPagedLimit = L"no symbols";
3537  }
3538  }
3539 
3540  SetDlgItemText(MemoryPanel, IDC_ZPAGEDLIMIT_V, pagedLimit);
3541  SetDlgItemText(MemoryPanel, IDC_ZNONPAGEDLIMIT_V, nonPagedLimit);
3542 
3543  // Paging
3544 
3545  if (MemoryTicked > 1)
3546  SetDlgItemText(MemoryPanel, IDC_ZPAGINGPAGEFAULTSDELTA_V, PhaFormatUInt64(PageFaultsDelta.Delta, TRUE)->Buffer);
3547  else
3548  SetDlgItemText(MemoryPanel, IDC_ZPAGINGPAGEFAULTSDELTA_V, L"-");
3549 
3550  if (MemoryTicked > 1)
3551  SetDlgItemText(MemoryPanel, IDC_ZPAGINGPAGEREADSDELTA_V, PhaFormatUInt64(PageReadsDelta.Delta, TRUE)->Buffer);
3552  else
3553  SetDlgItemText(MemoryPanel, IDC_ZPAGINGPAGEREADSDELTA_V, L"-");
3554 
3555  if (MemoryTicked > 1)
3556  SetDlgItemText(MemoryPanel, IDC_ZPAGINGPAGEFILEWRITESDELTA_V, PhaFormatUInt64(PagefileWritesDelta.Delta, TRUE)->Buffer);
3557  else
3558  SetDlgItemText(MemoryPanel, IDC_ZPAGINGPAGEFILEWRITESDELTA_V, L"-");
3559 
3560  if (MemoryTicked > 1)
3561  SetDlgItemText(MemoryPanel, IDC_ZPAGINGMAPPEDWRITESDELTA_V, PhaFormatUInt64(MappedWritesDelta.Delta, TRUE)->Buffer);
3562  else
3563  SetDlgItemText(MemoryPanel, IDC_ZPAGINGMAPPEDWRITESDELTA_V, L"-");
3564 
3565  // Memory Lists
3566 
3568  {
3569  if (NT_SUCCESS(NtQuerySystemInformation(
3571  &memoryListInfo,
3573  NULL
3574  )))
3575  {
3576  ULONG_PTR standbyPageCount;
3577  ULONG_PTR repurposedPageCount;
3578  ULONG i;
3579 
3580  standbyPageCount = 0;
3581  repurposedPageCount = 0;
3582 
3583  for (i = 0; i < 8; i++)
3584  {
3585  standbyPageCount += memoryListInfo.PageCountByPriority[i];
3586  repurposedPageCount += memoryListInfo.RepurposedPagesByPriority[i];
3587  }
3588 
3589  SetDlgItemText(MemoryPanel, IDC_ZLISTZEROED_V, PhaFormatSize((ULONG64)memoryListInfo.ZeroPageCount * PAGE_SIZE, -1)->Buffer);
3590  SetDlgItemText(MemoryPanel, IDC_ZLISTFREE_V, PhaFormatSize((ULONG64)memoryListInfo.FreePageCount * PAGE_SIZE, -1)->Buffer);
3591  SetDlgItemText(MemoryPanel, IDC_ZLISTMODIFIED_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCount * PAGE_SIZE, -1)->Buffer);
3592  SetDlgItemText(MemoryPanel, IDC_ZLISTMODIFIEDNOWRITE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedNoWritePageCount * PAGE_SIZE, -1)->Buffer);
3593  SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY_V, PhaFormatSize((ULONG64)standbyPageCount * PAGE_SIZE, -1)->Buffer);
3594  SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY0_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[0] * PAGE_SIZE, -1)->Buffer);
3595  SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY1_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[1] * PAGE_SIZE, -1)->Buffer);
3596  SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY2_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[2] * PAGE_SIZE, -1)->Buffer);
3597  SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY3_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[3] * PAGE_SIZE, -1)->Buffer);
3598  SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY4_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[4] * PAGE_SIZE, -1)->Buffer);
3599  SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY5_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[5] * PAGE_SIZE, -1)->Buffer);
3600  SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY6_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[6] * PAGE_SIZE, -1)->Buffer);
3601  SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY7_V, PhaFormatSize((ULONG64)memoryListInfo.PageCountByPriority[7] * PAGE_SIZE, -1)->Buffer);
3602 
3603  if (WindowsVersion >= WINDOWS_8)
3604  SetDlgItemText(MemoryPanel, IDC_ZLISTMODIFIEDPAGEFILE_V, PhaFormatSize((ULONG64)memoryListInfo.ModifiedPageCountPageFile * PAGE_SIZE, -1)->Buffer);
3605  else
3606  SetDlgItemText(MemoryPanel, IDC_ZLISTMODIFIEDPAGEFILE_V, L"N/A");
3607  }
3608  else
3609  {
3610  SetDlgItemText(MemoryPanel, IDC_ZLISTZEROED_V, L"N/A");
3611  SetDlgItemText(MemoryPanel, IDC_ZLISTFREE_V, L"N/A");
3612  SetDlgItemText(MemoryPanel, IDC_ZLISTMODIFIED_V, L"N/A");
3613  SetDlgItemText(MemoryPanel, IDC_ZLISTMODIFIEDNOWRITE_V, L"N/A");
3614  SetDlgItemText(MemoryPanel, IDC_ZLISTMODIFIEDPAGEFILE_V, L"N/A");
3615  SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY_V, L"N/A");
3616  SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY0_V, L"N/A");
3617  SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY1_V, L"N/A");
3618  SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY2_V, L"N/A");
3619  SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY3_V, L"N/A");
3620  SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY4_V, L"N/A");
3621  SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY5_V, L"N/A");
3622  SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY6_V, L"N/A");
3623  SetDlgItemText(MemoryPanel, IDC_ZLISTSTANDBY7_V, L"N/A");
3624  }
3625  }
3626 }
3627 
3629  _In_ PVOID Parameter
3630  )
3631 {
3632  PRTL_PROCESS_MODULES kernelModules;
3633  PPH_SYMBOL_PROVIDER symbolProvider;
3634  PPH_STRING kernelFileName;
3635  PPH_STRING newFileName;
3636  PH_SYMBOL_INFORMATION symbolInfo;
3637 
3638  if (NT_SUCCESS(PhEnumKernelModules(&kernelModules)))
3639  {
3640  if (kernelModules->NumberOfModules >= 1)
3641  {
3642  symbolProvider = PhCreateSymbolProvider(NULL);
3643  PhLoadSymbolProviderOptions(symbolProvider);
3644 
3645  kernelFileName = PhConvertMultiByteToUtf16(kernelModules->Modules[0].FullPathName);
3646  newFileName = PhGetFileName(kernelFileName);
3647  PhDereferenceObject(kernelFileName);
3648 
3650  symbolProvider,
3651  newFileName->Buffer,
3652  (ULONG64)kernelModules->Modules[0].ImageBase,
3653  kernelModules->Modules[0].ImageSize
3654  );
3655  PhDereferenceObject(newFileName);
3656 
3657  if (PhGetSymbolFromName(
3658  symbolProvider,
3659  L"MmSizeOfPagedPoolInBytes",
3660  &symbolInfo
3661  ))
3662  {
3663  MmSizeOfPagedPoolInBytes = (PSIZE_T)symbolInfo.Address;
3664  }
3665 
3666  if (PhGetSymbolFromName(
3667  symbolProvider,
3668  L"MmMaximumNonPagedPoolInBytes",
3669  &symbolInfo
3670  ))
3671  {
3672  MmMaximumNonPagedPoolInBytes = (PSIZE_T)symbolInfo.Address;
3673  }
3674 
3675  PhDereferenceObject(symbolProvider);
3676  }
3677 
3678  PhFree(kernelModules);
3679  }
3680 
3681  return STATUS_SUCCESS;
3682 }
3683 
3685  _Out_ PSIZE_T Paged,
3686  _Out_ PSIZE_T NonPaged
3687  )
3688 {
3689  SIZE_T paged = 0;
3690  SIZE_T nonPaged = 0;
3691 
3692  if (MmSizeOfPagedPoolInBytes)
3693  {
3695  NtCurrentProcess(),
3696  MmSizeOfPagedPoolInBytes,
3697  &paged,
3698  sizeof(SIZE_T),
3699  NULL
3700  );
3701  }
3702 
3703  if (MmMaximumNonPagedPoolInBytes)
3704  {
3706  NtCurrentProcess(),
3707  MmMaximumNonPagedPoolInBytes,
3708  &nonPaged,
3709  sizeof(SIZE_T),
3710  NULL
3711  );
3712  }
3713 
3714  *Paged = paged;
3715  *NonPaged = nonPaged;
3716 }
3717 
3719  _In_ PPH_SYSINFO_SECTION Section,
3720  _In_ PH_SYSINFO_SECTION_MESSAGE Message,
3721  _In_opt_ PVOID Parameter1,
3722  _In_opt_ PVOID Parameter2
3723  )
3724 {
3725  switch (Message)
3726  {
3727  case SysInfoDestroy:
3728  {
3729  if (IoDialog)
3730  {
3732  IoDialog = NULL;
3733  }
3734  }
3735  break;
3736  case SysInfoTick:
3737  {
3738  if (IoDialog)
3739  {
3741  }
3742  }
3743  break;
3744  case SysInfoCreateDialog:
3745  {
3746  PPH_SYSINFO_CREATE_DIALOG createDialog = Parameter1;
3747 
3748  createDialog->Instance = PhInstanceHandle;
3749  createDialog->Template = MAKEINTRESOURCE(IDD_SYSINFO_IO);
3750  createDialog->DialogProc = PhSipIoDialogProc;
3751  }
3752  return TRUE;
3754  {
3755  PPH_GRAPH_DRAW_INFO drawInfo = Parameter1;
3756  ULONG i;
3757  FLOAT max;
3758 
3760  Section->Parameters->ColorSetupFunction(drawInfo, PhCsColorIoReadOther, PhCsColorIoWrite);
3761  PhGetDrawInfoGraphBuffers(&Section->GraphState.Buffers, drawInfo, PhIoReadHistory.Count);
3762 
3763  if (!Section->GraphState.Valid)
3764  {
3765  max = 0;
3766 
3767  for (i = 0; i < drawInfo->LineDataCount; i++)
3768  {
3769  FLOAT data1;
3770  FLOAT data2;
3771 
3772  Section->GraphState.Data1[i] = data1 =
3773  (FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoReadHistory, i) +
3774  (FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoOtherHistory, i);
3775  Section->GraphState.Data2[i] = data2 =
3776  (FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoWriteHistory, i);
3777 
3778  if (max < data1 + data2)
3779  max = data1 + data2;
3780  }
3781 
3782  // Minimum scaling of 1 MB.
3783  if (max < 1024 * 1024)
3784  max = 1024 * 1024;
3785 
3786  // Scale the data.
3787 
3789  Section->GraphState.Data1,
3790  max,
3791  drawInfo->LineDataCount
3792  );
3794  Section->GraphState.Data2,
3795  max,
3796  drawInfo->LineDataCount
3797  );
3798 
3799  Section->GraphState.Valid = TRUE;
3800  }
3801  }
3802  return TRUE;
3804  {
3805  PPH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT getTooltipText = Parameter1;
3806  ULONG64 ioRead;
3807  ULONG64 ioWrite;
3808  ULONG64 ioOther;
3809 
3810  ioRead = PhGetItemCircularBuffer_ULONG64(&PhIoReadHistory, getTooltipText->Index);
3811  ioWrite = PhGetItemCircularBuffer_ULONG64(&PhIoWriteHistory, getTooltipText->Index);
3812  ioOther = PhGetItemCircularBuffer_ULONG64(&PhIoOtherHistory, getTooltipText->Index);
3813 
3814  PhMoveReference(&Section->GraphState.TooltipText, PhFormatString(
3815  L"R: %s\nW: %s\nO: %s%s\n%s",
3816  PhaFormatSize(ioRead, -1)->Buffer,
3817  PhaFormatSize(ioWrite, -1)->Buffer,
3818  PhaFormatSize(ioOther, -1)->Buffer,
3819  PhGetStringOrEmpty(PhSipGetMaxIoString(getTooltipText->Index)),
3820  ((PPH_STRING)PhAutoDereferenceObject(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
3821  ));
3822  getTooltipText->Text = Section->GraphState.TooltipText->sr;
3823  }
3824  return TRUE;
3825  case SysInfoGraphDrawPanel:
3826  {
3827  PPH_SYSINFO_DRAW_PANEL drawPanel = Parameter1;
3828 
3829  drawPanel->Title = PhCreateString(L"I/O");
3830  drawPanel->SubTitle = PhFormatString(
3831  L"R+O: %s\nW: %s",
3834  );
3835  }
3836  return TRUE;
3837  }
3838 
3839  return FALSE;
3840 }
3841 
3843  VOID
3844  )
3845 {
3846  PhInitializeDelta(&IoReadDelta);
3847  PhInitializeDelta(&IoWriteDelta);
3848  PhInitializeDelta(&IoOtherDelta);
3849 
3850  PhInitializeGraphState(&IoGraphState);
3851 
3852  IoTicked = 0;
3853 }
3854 
3856  VOID
3857  )
3858 {
3859  PhDeleteGraphState(&IoGraphState);
3860 }
3861 
3863  VOID
3864  )
3865 {
3869 
3870  IoTicked++;
3871 
3872  if (IoTicked > 2)
3873  IoTicked = 2;
3874 
3877 }
3878 
3879 INT_PTR CALLBACK PhSipIoDialogProc(
3880  _In_ HWND hwndDlg,
3881  _In_ UINT uMsg,
3882  _In_ WPARAM wParam,
3883  _In_ LPARAM lParam
3884  )
3885 {
3886  switch (uMsg)
3887  {
3888  case WM_INITDIALOG:
3889  {
3890  PPH_LAYOUT_ITEM graphItem;
3891  PPH_LAYOUT_ITEM panelItem;
3892 
3894 
3895  IoDialog = hwndDlg;
3896  PhInitializeLayoutManager(&IoLayoutManager, hwndDlg);
3897  graphItem = PhAddLayoutItem(&IoLayoutManager, GetDlgItem(hwndDlg, IDC_GRAPH_LAYOUT), NULL, PH_ANCHOR_ALL);
3898  panelItem = PhAddLayoutItem(&IoLayoutManager, GetDlgItem(hwndDlg, IDC_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
3899 
3900  SendMessage(GetDlgItem(hwndDlg, IDC_TITLE), WM_SETFONT, (WPARAM)CurrentParameters.LargeFont, FALSE);
3901 
3902  IoPanel = CreateDialog(PhInstanceHandle, MAKEINTRESOURCE(IDD_SYSINFO_IOPANEL), hwndDlg, PhSipIoPanelDialogProc);
3903  ShowWindow(IoPanel, SW_SHOW);
3904  PhAddLayoutItemEx(&IoLayoutManager, IoPanel, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM, panelItem->Margin);
3905 
3906  IoGraphHandle = CreateWindow(
3908  NULL,
3909  WS_VISIBLE | WS_CHILD | WS_BORDER,
3910  0,
3911  0,
3912  3,
3913  3,
3914  IoDialog,
3915  (HMENU)IDC_IO,
3917  NULL
3918  );
3919  Graph_SetTooltip(IoGraphHandle, TRUE);
3920 
3921  PhAddLayoutItemEx(&IoLayoutManager, IoGraphHandle, NULL, PH_ANCHOR_ALL, graphItem->Margin);
3922 
3925  }
3926  break;
3927  case WM_DESTROY:
3928  {
3929  PhDeleteLayoutManager(&IoLayoutManager);
3930  }
3931  break;
3932  case WM_SIZE:
3933  {
3934  PhLayoutManagerLayout(&IoLayoutManager);
3935  }
3936  break;
3937  case WM_NOTIFY:
3938  {
3939  NMHDR *header = (NMHDR *)lParam;
3940 
3941  if (header->hwndFrom == IoGraphHandle)
3942  {
3943  PhSipNotifyIoGraph(header);
3944  }
3945  }
3946  break;
3947  }
3948 
3949  return FALSE;
3950 }
3951 
3952 INT_PTR CALLBACK PhSipIoPanelDialogProc(
3953  _In_ HWND hwndDlg,
3954  _In_ UINT uMsg,
3955  _In_ WPARAM wParam,
3956  _In_ LPARAM lParam
3957  )
3958 {
3959  switch (uMsg)
3960  {
3961  case WM_INITDIALOG:
3962  {
3963  NOTHING;
3964  }
3965  break;
3966  }
3967 
3968  return FALSE;
3969 }
3970 
3972  _In_ NMHDR *Header
3973  )
3974 {
3975  switch (Header->code)
3976  {
3977  case GCN_GETDRAWINFO:
3978  {
3979  PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header;
3980  PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;
3981  ULONG i;
3982 
3985 
3987  &IoGraphState,
3988  getDrawInfo,
3989  PhIoReadHistory.Count
3990  );
3991 
3992  if (!IoGraphState.Valid)
3993  {
3994  FLOAT max = 0;
3995 
3996  for (i = 0; i < drawInfo->LineDataCount; i++)
3997  {
3998  FLOAT data1;
3999  FLOAT data2;
4000 
4001  IoGraphState.Data1[i] = data1 =
4002  (FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoReadHistory, i) +
4003  (FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoOtherHistory, i);
4004  IoGraphState.Data2[i] = data2 =
4005  (FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoWriteHistory, i);
4006 
4007  if (max < data1 + data2)
4008  max = data1 + data2;
4009  }
4010 
4011  // Minimum scaling of 1 MB.
4012  if (max < 1024 * 1024)
4013  max = 1024 * 1024;
4014 
4015  // Scale the data.
4016 
4018  IoGraphState.Data1,
4019  max,
4020  drawInfo->LineDataCount
4021  );
4023  IoGraphState.Data2,
4024  max,
4025  drawInfo->LineDataCount
4026  );
4027 
4028  IoGraphState.Valid = TRUE;
4029  }
4030  }
4031  break;
4032  case GCN_GETTOOLTIPTEXT:
4033  {
4034  PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header;
4035 
4036  if (getTooltipText->Index < getTooltipText->TotalCount)
4037  {
4038  if (IoGraphState.TooltipIndex != getTooltipText->Index)
4039  {
4040  ULONG64 ioRead;
4041  ULONG64 ioWrite;
4042  ULONG64 ioOther;
4043 
4044  ioRead = PhGetItemCircularBuffer_ULONG64(&PhIoReadHistory, getTooltipText->Index);
4045  ioWrite = PhGetItemCircularBuffer_ULONG64(&PhIoWriteHistory, getTooltipText->Index);
4046  ioOther = PhGetItemCircularBuffer_ULONG64(&PhIoOtherHistory, getTooltipText->Index);
4047 
4049  L"R: %s\nW: %s\nO: %s%s\n%s",
4050  PhaFormatSize(ioRead, -1)->Buffer,
4051  PhaFormatSize(ioWrite, -1)->Buffer,
4052  PhaFormatSize(ioOther, -1)->Buffer,
4053  PhGetStringOrEmpty(PhSipGetMaxIoString(getTooltipText->Index)),
4054  ((PPH_STRING)PhAutoDereferenceObject(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
4055  ));
4056  }
4057 
4058  getTooltipText->Text = IoGraphState.TooltipText->sr;
4059  }
4060  }
4061  break;
4062  case GCN_MOUSEEVENT:
4063  {
4064  PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Header;
4065  PPH_PROCESS_RECORD record;
4066 
4067  record = NULL;
4068 
4069  if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount)
4070  {
4071  record = PhSipReferenceMaxIoRecord(mouseEvent->Index);
4072  }
4073 
4074  if (record)
4075  {
4076  PhShowProcessRecordDialog(IoDialog, record);
4078  }
4079  }
4080  break;
4081  }
4082 }
4083 
4085  VOID
4086  )
4087 {
4088  IoGraphState.Valid = FALSE;
4089  IoGraphState.TooltipIndex = -1;
4090  Graph_MoveGrid(IoGraphHandle, 1);
4091  Graph_Draw(IoGraphHandle);
4092  Graph_UpdateTooltip(IoGraphHandle);
4093  InvalidateRect(IoGraphHandle, NULL, FALSE);
4094 }
4095 
4097  VOID
4098  )
4099 {
4100  // I/O Deltas
4101 
4102  if (IoTicked > 1)
4103  {
4104  SetDlgItemText(IoPanel, IDC_ZREADSDELTA_V, PhaFormatUInt64(IoReadDelta.Delta, TRUE)->Buffer);
4105  SetDlgItemText(IoPanel, IDC_ZWRITESDELTA_V, PhaFormatUInt64(IoWriteDelta.Delta, TRUE)->Buffer);
4106  SetDlgItemText(IoPanel, IDC_ZOTHERDELTA_V, PhaFormatUInt64(IoOtherDelta.Delta, TRUE)->Buffer);
4107  }
4108  else
4109  {
4110  SetDlgItemText(IoPanel, IDC_ZREADSDELTA_V, L"-");
4111  SetDlgItemText(IoPanel, IDC_ZWRITESDELTA_V, L"-");
4112  SetDlgItemText(IoPanel, IDC_ZOTHERDELTA_V, L"-");
4113  }
4114 
4115  if (PhIoReadHistory.Count != 0)
4116  {
4117  SetDlgItemText(IoPanel, IDC_ZREADBYTESDELTA_V, PhaFormatSize(PhIoReadDelta.Delta, -1)->Buffer);
4118  SetDlgItemText(IoPanel, IDC_ZWRITEBYTESDELTA_V, PhaFormatSize(PhIoWriteDelta.Delta, -1)->Buffer);
4119  SetDlgItemText(IoPanel, IDC_ZOTHERBYTESDELTA_V, PhaFormatSize(PhIoOtherDelta.Delta, -1)->Buffer);
4120  }
4121  else
4122  {
4123  SetDlgItemText(IoPanel, IDC_ZREADBYTESDELTA_V, L"-");
4124  SetDlgItemText(IoPanel, IDC_ZWRITEBYTESDELTA_V, L"-");
4125  SetDlgItemText(IoPanel, IDC_ZOTHERBYTESDELTA_V, L"-");
4126  }
4127 
4128  // I/O Totals
4129 
4130  SetDlgItemText(IoPanel, IDC_ZREADS_V, PhaFormatUInt64(PhPerfInformation.IoReadOperationCount, TRUE)->Buffer);
4131  SetDlgItemText(IoPanel, IDC_ZREADBYTES_V, PhaFormatSize(PhPerfInformation.IoReadTransferCount.QuadPart, -1)->Buffer);
4132  SetDlgItemText(IoPanel, IDC_ZWRITES_V, PhaFormatUInt64(PhPerfInformation.IoWriteOperationCount, TRUE)->Buffer);
4133  SetDlgItemText(IoPanel, IDC_ZWRITEBYTES_V, PhaFormatSize(PhPerfInformation.IoWriteTransferCount.QuadPart, -1)->Buffer);
4134  SetDlgItemText(IoPanel, IDC_ZOTHER_V, PhaFormatUInt64(PhPerfInformation.IoOtherOperationCount, TRUE)->Buffer);
4135  SetDlgItemText(IoPanel, IDC_ZOTHERBYTES_V, PhaFormatSize(PhPerfInformation.IoOtherTransferCount.QuadPart, -1)->Buffer);
4136 }
4137 
4139  _In_ LONG Index
4140  )
4141 {
4142  LARGE_INTEGER time;
4143  ULONG maxProcessId;
4144 
4145  // Find the process record for the max. I/O process for the particular time.
4146 
4147  maxProcessId = PhGetItemCircularBuffer_ULONG(&PhMaxIoHistory, Index);
4148 
4149  if (!maxProcessId)
4150  return NULL;
4151 
4152  // See above for the explanation.
4153  PhGetStatisticsTime(NULL, Index, &time);
4154  time.QuadPart += PH_TICKS_PER_SEC - 1;
4155 
4156  return PhFindProcessRecord(UlongToHandle(maxProcessId), &time);
4157 }
4158 
4160  _In_ LONG Index
4161  )
4162 {
4163  PPH_PROCESS_RECORD maxProcessRecord;
4164 #ifdef PH_RECORD_MAX_USAGE
4165  ULONG64 maxIoReadOther;
4166  ULONG64 maxIoWrite;
4167 #endif
4168  PPH_STRING maxUsageString = NULL;
4169 
4170  if (maxProcessRecord = PhSipReferenceMaxIoRecord(Index))
4171  {
4172  // We found the process record, so now we construct the max. usage string.
4173 #ifdef PH_RECORD_MAX_USAGE
4174  maxIoReadOther = PhGetItemCircularBuffer_ULONG64(&PhMaxIoReadOtherHistory, Index);
4175  maxIoWrite = PhGetItemCircularBuffer_ULONG64(&PhMaxIoWriteHistory, Index);
4176 
4177  if (!PH_IS_FAKE_PROCESS_ID(maxProcessRecord->ProcessId))
4178  {
4179  maxUsageString = PhaFormatString(
4180  L"\n%s (%u): R+O: %s, W: %s",
4181  maxProcessRecord->ProcessName->Buffer,
4182  (ULONG)maxProcessRecord->ProcessId,
4183  PhaFormatSize(maxIoReadOther, -1)->Buffer,
4184  PhaFormatSize(maxIoWrite, -1)->Buffer
4185  );
4186  }
4187  else
4188  {
4189  maxUsageString = PhaFormatString(
4190  L"\n%s: R+O: %s, W: %s",
4191  maxProcessRecord->ProcessName->Buffer,
4192  PhaFormatSize(maxIoReadOther, -1)->Buffer,
4193  PhaFormatSize(maxIoWrite, -1)->Buffer
4194  );
4195  }
4196 #else
4197  maxUsageString = PhaConcatStrings2(L"\n", maxProcessRecord->ProcessName->Buffer);
4198 #endif
4199 
4200  PhDereferenceProcessRecord(maxProcessRecord);
4201  }
4202 
4203  return maxUsageString;
4204 }