Files
mirror-processhacker/2.x/trunk/ProcessHacker/sysinfo.c
T
wj32 c7ec10ae09 fixed sign extension of fake process IDs for max. CPU history
git-svn-id: svn://svn.code.sf.net/p/processhacker/code@4677 21ef857c-d57f-4fe0-8362-d861dc6d29cd
2011-09-15 12:16:26 +00:00

1358 lines
51 KiB
C

/*
* Process Hacker -
* system information
*
* Copyright (C) 2010 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
#include <phapp.h>
#include <kphuser.h>
#include <settings.h>
#include <windowsx.h>
#define WM_PH_SYSINFO_ACTIVATE (WM_APP + 150)
#define WM_PH_SYSINFO_UPDATE (WM_APP + 151)
#define WM_PH_SYSINFO_PANEL_UPDATE (WM_APP + 160)
NTSTATUS PhpSysInfoThreadStart(
__in PVOID Parameter
);
INT_PTR CALLBACK PhpSysInfoDlgProc(
__in HWND hwndDlg,
__in UINT uMsg,
__in WPARAM wParam,
__in LPARAM lParam
);
INT_PTR CALLBACK PhpSysInfoPanelDlgProc(
__in HWND hwndDlg,
__in UINT uMsg,
__in WPARAM wParam,
__in LPARAM lParam
);
HANDLE PhSysInfoThreadHandle = NULL;
HWND PhSysInfoWindowHandle = NULL;
HWND PhSysInfoPanelWindowHandle = NULL;
static PH_EVENT InitializedEvent = PH_EVENT_INIT;
static PH_LAYOUT_MANAGER WindowLayoutManager;
static RECT MinimumSize;
static PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration;
static BOOLEAN InInitDialog;
static BOOLEAN OneGraphPerCpu;
static BOOLEAN AlwaysOnTop;
static HWND CpuGraphHandle;
static HWND IoGraphHandle;
static HWND PhysicalGraphHandle;
static HWND *CpusGraphHandle;
static PH_GRAPH_STATE CpuGraphState;
static PH_GRAPH_STATE IoGraphState;
static PH_GRAPH_STATE PhysicalGraphState;
static PPH_GRAPH_STATE CpusGraphState;
static BOOLEAN MmAddressesInitialized = FALSE;
static PSIZE_T MmSizeOfPagedPoolInBytes = NULL;
static PSIZE_T MmMaximumNonPagedPoolInBytes = NULL;
VOID PhShowSystemInformationDialog(
VOID
)
{
if (!PhSysInfoWindowHandle)
{
if (!(PhSysInfoThreadHandle = PhCreateThread(0, PhpSysInfoThreadStart, NULL)))
{
PhShowStatus(PhMainWndHandle, L"Unable to create the system information window", 0, GetLastError());
return;
}
PhWaitForEvent(&InitializedEvent, NULL);
}
SendMessage(PhSysInfoWindowHandle, WM_PH_SYSINFO_ACTIVATE, 0, 0);
}
static NTSTATUS PhpLoadMmAddresses(
__in PVOID Parameter
)
{
PRTL_PROCESS_MODULES kernelModules;
PPH_SYMBOL_PROVIDER symbolProvider;
PPH_STRING kernelFileName;
PPH_STRING newFileName;
PH_SYMBOL_INFORMATION symbolInfo;
if (NT_SUCCESS(PhEnumKernelModules(&kernelModules)))
{
if (kernelModules->NumberOfModules >= 1)
{
symbolProvider = PhCreateSymbolProvider(NULL);
PhLoadSymbolProviderOptions(symbolProvider);
kernelFileName = PhCreateStringFromAnsi(kernelModules->Modules[0].FullPathName);
newFileName = PhGetFileName(kernelFileName);
PhDereferenceObject(kernelFileName);
PhLoadModuleSymbolProvider(
symbolProvider,
newFileName->Buffer,
(ULONG64)kernelModules->Modules[0].ImageBase,
kernelModules->Modules[0].ImageSize
);
PhDereferenceObject(newFileName);
if (PhGetSymbolFromName(
symbolProvider,
L"MmSizeOfPagedPoolInBytes",
&symbolInfo
))
{
MmSizeOfPagedPoolInBytes = (PSIZE_T)symbolInfo.Address;
}
if (PhGetSymbolFromName(
symbolProvider,
L"MmMaximumNonPagedPoolInBytes",
&symbolInfo
))
{
MmMaximumNonPagedPoolInBytes = (PSIZE_T)symbolInfo.Address;
}
PhDereferenceObject(symbolProvider);
}
PhFree(kernelModules);
}
return STATUS_SUCCESS;
}
static NTSTATUS PhpSysInfoThreadStart(
__in PVOID Parameter
)
{
PH_AUTO_POOL autoPool;
BOOL result;
MSG message;
PhInitializeAutoPool(&autoPool);
if (!MmAddressesInitialized && KphIsConnected())
{
PhQueueItemGlobalWorkQueue(PhpLoadMmAddresses, NULL);
MmAddressesInitialized = TRUE;
}
PhSysInfoWindowHandle = CreateDialog(
PhInstanceHandle,
MAKEINTRESOURCE(IDD_SYSINFO),
NULL,
PhpSysInfoDlgProc
);
PhSetEvent(&InitializedEvent);
while (result = GetMessage(&message, NULL, 0, 0))
{
if (result == -1)
break;
if (!IsDialogMessage(PhSysInfoWindowHandle, &message))
{
TranslateMessage(&message);
DispatchMessage(&message);
}
PhDrainAutoPool(&autoPool);
}
PhDeleteAutoPool(&autoPool);
PhResetEvent(&InitializedEvent);
NtClose(PhSysInfoThreadHandle);
PhSysInfoWindowHandle = NULL;
PhSysInfoPanelWindowHandle = NULL;
PhSysInfoThreadHandle = NULL;
return STATUS_SUCCESS;
}
static VOID PhpSetAlwaysOnTop(
VOID
)
{
SetWindowPos(PhSysInfoWindowHandle, AlwaysOnTop ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
}
static VOID PhpSetOneGraphPerCpu(
VOID
)
{
ULONG i;
ShowWindow(CpuGraphHandle, !OneGraphPerCpu ? SW_SHOW : SW_HIDE);
for (i = 0; i < (ULONG)PhSystemBasicInformation.NumberOfProcessors; i++)
{
ShowWindow(CpusGraphHandle[i], OneGraphPerCpu ? SW_SHOW : SW_HIDE);
}
}
static VOID NTAPI SysInfoUpdateHandler(
__in_opt PVOID Parameter,
__in_opt PVOID Context
)
{
PostMessage(PhSysInfoWindowHandle, WM_PH_SYSINFO_UPDATE, 0, 0);
}
static PPH_PROCESS_RECORD PhpReferenceMaxCpuRecord(
__in LONG Index
)
{
LARGE_INTEGER time;
ULONG maxProcessId;
// Find the process record for the max. CPU process for the particular time.
maxProcessId = PhGetItemCircularBuffer_ULONG(&PhMaxCpuHistory, Index);
if (!maxProcessId)
return NULL;
// Note that the time we get has its components beyond seconds cleared.
// For example:
// * At 2.5 seconds a process is started.
// * At 2.75 seconds our process provider is fired, and the process is determined
// to have 75% CPU usage, which happens to be the maximum CPU usage.
// * However the 2.75 seconds is recorded as 2 seconds due to
// RtlTimeToSecondsSince1980.
// * If we call PhFindProcessRecord, it cannot find the process because it was
// started at 2.5 seconds, not 2 seconds or older.
//
// This mean we must add one second minus one tick (100ns) to the time, giving us
// 2.9999999 seconds. This will then make sure we find the process.
PhGetStatisticsTime(NULL, Index, &time);
time.QuadPart += PH_TICKS_PER_SEC - 1;
return PhFindProcessRecord(LongToHandle(maxProcessId), &time);
}
static PPH_STRING PhapGetMaxCpuString(
__in LONG Index
)
{
PPH_PROCESS_RECORD maxProcessRecord;
#ifdef PH_RECORD_MAX_USAGE
FLOAT maxCpuUsage;
#endif
PPH_STRING maxUsageString = NULL;
if (maxProcessRecord = PhpReferenceMaxCpuRecord(Index))
{
// We found the process record, so now we construct the max. usage string.
#ifdef PH_RECORD_MAX_USAGE
maxCpuUsage = PhGetItemCircularBuffer_FLOAT(&PhMaxCpuUsageHistory, Index);
// Make sure we don't try to display the PID of DPCs or Interrupts.
if (!PH_IS_FAKE_PROCESS_ID(maxProcessRecord->ProcessId))
{
maxUsageString = PhaFormatString(
L"\n%s (%u): %.2f%%",
maxProcessRecord->ProcessName->Buffer,
(ULONG)maxProcessRecord->ProcessId,
maxCpuUsage * 100
);
}
else
{
maxUsageString = PhaFormatString(
L"\n%s: %.2f%%",
maxProcessRecord->ProcessName->Buffer,
maxCpuUsage * 100
);
}
#else
maxUsageString = PhaConcatStrings2(L"\n", maxProcessRecord->ProcessName->Buffer);
#endif
PhDereferenceProcessRecord(maxProcessRecord);
}
return maxUsageString;
}
static PPH_PROCESS_RECORD PhpReferenceMaxIoRecord(
__in LONG Index
)
{
LARGE_INTEGER time;
ULONG maxProcessId;
// Find the process record for the max. I/O process for the particular time.
maxProcessId = PhGetItemCircularBuffer_ULONG(&PhMaxIoHistory, Index);
if (!maxProcessId)
return NULL;
// See above for the explanation.
PhGetStatisticsTime(NULL, Index, &time);
time.QuadPart += PH_TICKS_PER_SEC - 1;
return PhFindProcessRecord((HANDLE)maxProcessId, &time);
}
static PPH_STRING PhapGetMaxIoString(
__in LONG Index
)
{
PPH_PROCESS_RECORD maxProcessRecord;
#ifdef PH_RECORD_MAX_USAGE
ULONG64 maxIoReadOther;
ULONG64 maxIoWrite;
#endif
PPH_STRING maxUsageString = NULL;
if (maxProcessRecord = PhpReferenceMaxIoRecord(Index))
{
// We found the process record, so now we construct the max. usage string.
#ifdef PH_RECORD_MAX_USAGE
maxIoReadOther = PhGetItemCircularBuffer_ULONG64(&PhMaxIoReadOtherHistory, Index);
maxIoWrite = PhGetItemCircularBuffer_ULONG64(&PhMaxIoWriteHistory, Index);
if (!PH_IS_FAKE_PROCESS_ID(maxProcessRecord->ProcessId))
{
maxUsageString = PhaFormatString(
L"\n%s (%u): R+O: %s, W: %s",
maxProcessRecord->ProcessName->Buffer,
(ULONG)maxProcessRecord->ProcessId,
PhaFormatSize(maxIoReadOther, -1)->Buffer,
PhaFormatSize(maxIoWrite, -1)->Buffer
);
}
else
{
maxUsageString = PhaFormatString(
L"\n%s: R+O: %s, W: %s",
maxProcessRecord->ProcessName->Buffer,
PhaFormatSize(maxIoReadOther, -1)->Buffer,
PhaFormatSize(maxIoWrite, -1)->Buffer
);
}
#else
maxUsageString = PhaConcatStrings2(L"\n", maxProcessRecord->ProcessName->Buffer);
#endif
PhDereferenceProcessRecord(maxProcessRecord);
}
return maxUsageString;
}
INT_PTR CALLBACK PhpSysInfoDlgProc(
__in HWND hwndDlg,
__in UINT uMsg,
__in WPARAM wParam,
__in LPARAM lParam
)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
ULONG processors;
ULONG i;
// Perform the allocations early or else in other message handlers we may
// be doing null dereferences.
processors = (ULONG)PhSystemBasicInformation.NumberOfProcessors;
CpusGraphState = PhAllocate(sizeof(PH_GRAPH_STATE) * processors);
CpusGraphHandle = PhAllocate(sizeof(HWND) * processors);
memset(CpusGraphHandle, 0, sizeof(HWND) * processors);
// We have already set the group boxes to have WS_EX_TRANSPARENT to fix
// the drawing issue that arises when using WS_CLIPCHILDREN. However
// in removing the flicker from the graphs the group boxes will now flicker.
// It's a good tradeoff since no one stares at the group boxes.
PhSetWindowStyle(hwndDlg, WS_CLIPCHILDREN, WS_CLIPCHILDREN);
PhInitializeLayoutManager(&WindowLayoutManager, hwndDlg);
PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_ONEGRAPHPERCPU), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT);
PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_ALWAYSONTOP), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
MinimumSize.left = 0;
MinimumSize.top = 0;
MinimumSize.right = 413;
MinimumSize.bottom = 360;
MapDialogRect(hwndDlg, &MinimumSize);
PhInitializeGraphState(&CpuGraphState);
PhInitializeGraphState(&IoGraphState);
PhInitializeGraphState(&PhysicalGraphState);
CpuGraphHandle = CreateWindow(
PH_GRAPH_CLASSNAME,
NULL,
WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS,
0,
0,
3,
3,
hwndDlg,
(HMENU)IDC_CPU,
PhInstanceHandle,
NULL
);
Graph_SetTooltip(CpuGraphHandle, TRUE);
BringWindowToTop(CpuGraphHandle);
IoGraphHandle = CreateWindow(
PH_GRAPH_CLASSNAME,
NULL,
WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS,
0,
0,
3,
3,
hwndDlg,
(HMENU)IDC_IO,
PhInstanceHandle,
NULL
);
Graph_SetTooltip(IoGraphHandle, TRUE);
BringWindowToTop(IoGraphHandle);
PhysicalGraphHandle = CreateWindow(
PH_GRAPH_CLASSNAME,
NULL,
WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS,
0,
0,
3,
3,
hwndDlg,
(HMENU)IDC_PHYSICAL,
PhInstanceHandle,
NULL
);
Graph_SetTooltip(PhysicalGraphHandle, TRUE);
BringWindowToTop(PhysicalGraphHandle);
for (i = 0; i < processors; i++)
{
PhInitializeGraphState(&CpusGraphState[i]);
CpusGraphHandle[i] = CreateWindow(
PH_GRAPH_CLASSNAME,
NULL,
WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS,
0,
0,
3,
3,
hwndDlg,
(HMENU)(IDC_CPU0 + i),
PhInstanceHandle,
NULL
);
Graph_SetTooltip(CpusGraphHandle[i], TRUE);
BringWindowToTop(CpusGraphHandle[i]);
}
PhRegisterCallback(
&PhProcessesUpdatedEvent,
SysInfoUpdateHandler,
NULL,
&ProcessesUpdatedRegistration
);
InInitDialog = TRUE;
PhLoadWindowPlacementFromSetting(L"SysInfoWindowPosition", L"SysInfoWindowSize", hwndDlg);
InInitDialog = FALSE;
}
break;
case WM_DESTROY:
{
ULONG i;
PhUnregisterCallback(
&PhProcessesUpdatedEvent,
&ProcessesUpdatedRegistration
);
PhFree(CpusGraphHandle);
CpusGraphHandle = NULL;
for (i = 0; i < (ULONG)PhSystemBasicInformation.NumberOfProcessors; i++)
PhDeleteGraphState(&CpusGraphState[i]);
PhFree(CpusGraphState);
CpusGraphState = NULL;
PhDeleteGraphState(&CpuGraphState);
PhDeleteGraphState(&IoGraphState);
PhDeleteGraphState(&PhysicalGraphState);
PhSetIntegerSetting(L"SysInfoWindowAlwaysOnTop", AlwaysOnTop);
PhSetIntegerSetting(L"SysInfoWindowOneGraphPerCpu", OneGraphPerCpu);
PhSaveWindowPlacementToSetting(L"SysInfoWindowPosition", L"SysInfoWindowSize", hwndDlg);
PhDeleteLayoutManager(&WindowLayoutManager);
PostQuitMessage(0);
}
break;
case WM_SHOWWINDOW:
{
RECT margin;
PhSysInfoPanelWindowHandle = CreateDialog(
PhInstanceHandle,
MAKEINTRESOURCE(IDD_SYSINFO_PANEL),
PhSysInfoWindowHandle,
PhpSysInfoPanelDlgProc
);
SetWindowPos(PhSysInfoPanelWindowHandle, NULL, 10, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSIZE | SWP_NOZORDER);
ShowWindow(PhSysInfoPanelWindowHandle, SW_SHOW);
AlwaysOnTop = (BOOLEAN)PhGetIntegerSetting(L"SysInfoWindowAlwaysOnTop");
Button_SetCheck(GetDlgItem(hwndDlg, IDC_ALWAYSONTOP), AlwaysOnTop ? BST_CHECKED : BST_UNCHECKED);
PhpSetAlwaysOnTop();
if (PhSystemBasicInformation.NumberOfProcessors != 1)
{
OneGraphPerCpu = (BOOLEAN)PhGetIntegerSetting(L"SysInfoWindowOneGraphPerCpu");
Button_SetCheck(GetDlgItem(hwndDlg, IDC_ONEGRAPHPERCPU), OneGraphPerCpu ? BST_CHECKED : BST_UNCHECKED);
PhpSetOneGraphPerCpu();
}
else
{
OneGraphPerCpu = FALSE;
EnableWindow(GetDlgItem(hwndDlg, IDC_ONEGRAPHPERCPU), FALSE);
PhpSetOneGraphPerCpu();
}
margin.left = 0;
margin.top = 0;
margin.right = 0;
margin.bottom = 25;
MapDialogRect(hwndDlg, &margin);
PhAddLayoutItemEx(&WindowLayoutManager, PhSysInfoPanelWindowHandle, NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT, margin);
SendMessage(hwndDlg, WM_SIZE, 0, 0);
SendMessage(hwndDlg, WM_PH_SYSINFO_UPDATE, 0, 0);
}
break;
case WM_SIZE:
{
HDWP deferHandle;
HWND cpuGroupBox = GetDlgItem(hwndDlg, IDC_GROUPCPU);
HWND ioGroupBox = GetDlgItem(hwndDlg, IDC_GROUPIO);
HWND physicalGroupBox = GetDlgItem(hwndDlg, IDC_GROUPPHYSICAL);
RECT clientRect;
RECT panelRect;
RECT margin = { 13, 13, 13, 13 };
RECT innerMargin = { 10, 20, 10, 10 };
LONG between = 3;
LONG width;
LONG height;
// PhLoadWindowPlacementFromSetting in WM_INITDIALOG causes WM_SIZE to be sent, but this seems
// to cause major lag. Ignore the message if it's from WM_INITDIALOG.
if (InInitDialog)
break;
PhLayoutManagerLayout(&WindowLayoutManager);
CpuGraphState.Valid = FALSE;
IoGraphState.Valid = FALSE;
PhysicalGraphState.Valid = FALSE;
GetClientRect(hwndDlg, &clientRect);
// Limit the rectangle bottom to the top of the panel.
GetWindowRect(PhSysInfoPanelWindowHandle, &panelRect);
MapWindowPoints(NULL, hwndDlg, (POINT *)&panelRect, 2);
clientRect.bottom = panelRect.top;
width = clientRect.right - margin.left - margin.right;
height = (clientRect.bottom - margin.top - margin.bottom - between * 2) / 3;
deferHandle = BeginDeferWindowPos(6);
deferHandle = DeferWindowPos(deferHandle, cpuGroupBox, NULL, margin.left, margin.top,
width, height, SWP_NOACTIVATE | SWP_NOZORDER);
if (!OneGraphPerCpu)
{
deferHandle = DeferWindowPos(
deferHandle,
CpuGraphHandle,
NULL,
margin.left + innerMargin.left,
margin.top + innerMargin.top,
width - innerMargin.left - innerMargin.right,
height - innerMargin.top - innerMargin.bottom,
SWP_NOACTIVATE | SWP_NOZORDER
);
}
else
{
ULONG i;
ULONG processors;
ULONG graphBetween = 5;
ULONG graphWidth;
ULONG x;
processors = (ULONG)PhSystemBasicInformation.NumberOfProcessors;
graphWidth = (width - innerMargin.left - innerMargin.right - graphBetween * (processors - 1)) / processors;
x = margin.left + innerMargin.left;
for (i = 0; i < processors; i++)
{
// Give the last graph the remaining space; the width we calculated might be off by a few
// pixels due to integer division.
if (i == processors - 1)
{
graphWidth = clientRect.right - margin.right - innerMargin.right - x;
}
deferHandle = DeferWindowPos(
deferHandle,
CpusGraphHandle[i],
NULL,
x,
margin.top + innerMargin.top,
graphWidth,
height - innerMargin.top - innerMargin.bottom,
SWP_NOACTIVATE | SWP_NOZORDER
);
x += graphWidth + graphBetween;
}
}
deferHandle = DeferWindowPos(deferHandle, ioGroupBox, NULL, margin.left, margin.top + height + between,
width, height, SWP_NOACTIVATE | SWP_NOZORDER);
deferHandle = DeferWindowPos(
deferHandle,
IoGraphHandle,
NULL,
margin.left + innerMargin.left,
margin.top + height + between + innerMargin.top,
width - innerMargin.left - innerMargin.right,
height - innerMargin.top - innerMargin.bottom,
SWP_NOACTIVATE | SWP_NOZORDER
);
deferHandle = DeferWindowPos(deferHandle, physicalGroupBox, NULL, margin.left, margin.top + (height + between) * 2,
width, height, SWP_NOACTIVATE | SWP_NOZORDER);
deferHandle = DeferWindowPos(
deferHandle,
PhysicalGraphHandle,
NULL,
margin.left + innerMargin.left,
margin.top + (height + between) * 2 + innerMargin.top,
width - innerMargin.left - innerMargin.right,
height - innerMargin.top - innerMargin.bottom,
SWP_NOACTIVATE | SWP_NOZORDER
);
EndDeferWindowPos(deferHandle);
}
break;
case WM_SIZING:
{
PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom);
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDCANCEL:
case IDOK:
DestroyWindow(hwndDlg);
break;
case IDC_ALWAYSONTOP:
{
AlwaysOnTop = Button_GetCheck(GetDlgItem(hwndDlg, IDC_ALWAYSONTOP)) == BST_CHECKED;
PhpSetAlwaysOnTop();
}
break;
case IDC_ONEGRAPHPERCPU:
{
OneGraphPerCpu = Button_GetCheck(GetDlgItem(hwndDlg, IDC_ONEGRAPHPERCPU)) == BST_CHECKED;
PhpSetOneGraphPerCpu();
SendMessage(hwndDlg, WM_SIZE, 0, 0);
}
break;
}
}
break;
case WM_NOTIFY:
{
LPNMHDR header = (LPNMHDR)lParam;
switch (header->code)
{
case GCN_GETDRAWINFO:
{
PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)header;
PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;
ULONG i;
if (header->hwndFrom == CpuGraphHandle)
{
if (PhCsGraphShowText)
{
HDC hdc;
PhSwapReference2(&CpuGraphState.TooltipText,
PhFormatString(L"%.2f%%",
(PhCpuKernelUsage + PhCpuUserUsage) * 100
));
hdc = Graph_GetBufferedContext(CpuGraphHandle);
SelectObject(hdc, PhApplicationFont);
PhSetGraphText(hdc, drawInfo, &CpuGraphState.TooltipText->sr,
&PhNormalGraphTextMargin, &PhNormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT);
}
else
{
drawInfo->Text.Buffer = NULL;
}
drawInfo->Flags = PH_GRAPH_USE_GRID | PH_GRAPH_USE_LINE_2;
drawInfo->LineColor1 = PhCsColorCpuKernel;
drawInfo->LineColor2 = PhCsColorCpuUser;
drawInfo->LineBackColor1 = PhHalveColorBrightness(PhCsColorCpuKernel);
drawInfo->LineBackColor2 = PhHalveColorBrightness(PhCsColorCpuUser);
PhGraphStateGetDrawInfo(
&CpuGraphState,
getDrawInfo,
PhCpuKernelHistory.Count
);
if (!CpuGraphState.Valid)
{
PhCopyCircularBuffer_FLOAT(&PhCpuKernelHistory,
CpuGraphState.Data1, drawInfo->LineDataCount);
PhCopyCircularBuffer_FLOAT(&PhCpuUserHistory,
CpuGraphState.Data2, drawInfo->LineDataCount);
CpuGraphState.Valid = TRUE;
}
}
else if (header->hwndFrom == IoGraphHandle)
{
if (PhCsGraphShowText)
{
HDC hdc;
PhSwapReference2(&IoGraphState.TooltipText,
PhFormatString(
L"R+O: %s, W: %s",
PhaFormatSize(PhIoReadDelta.Delta + PhIoOtherDelta.Delta, -1)->Buffer,
PhaFormatSize(PhIoWriteDelta.Delta, -1)->Buffer
));
hdc = Graph_GetBufferedContext(IoGraphHandle);
SelectObject(hdc, PhApplicationFont);
PhSetGraphText(hdc, drawInfo, &IoGraphState.TooltipText->sr,
&PhNormalGraphTextMargin, &PhNormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT);
}
else
{
drawInfo->Text.Buffer = NULL;
}
drawInfo->Flags = PH_GRAPH_USE_GRID | PH_GRAPH_USE_LINE_2;
drawInfo->LineColor1 = PhCsColorIoReadOther;
drawInfo->LineColor2 = PhCsColorIoWrite;
drawInfo->LineBackColor1 = PhHalveColorBrightness(PhCsColorIoReadOther);
drawInfo->LineBackColor2 = PhHalveColorBrightness(PhCsColorIoWrite);
PhGraphStateGetDrawInfo(
&IoGraphState,
getDrawInfo,
PhIoReadHistory.Count
);
if (!IoGraphState.Valid)
{
FLOAT max = 0;
for (i = 0; i < drawInfo->LineDataCount; i++)
{
FLOAT data1;
FLOAT data2;
IoGraphState.Data1[i] = data1 =
(FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoReadHistory, i) +
(FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoOtherHistory, i);
IoGraphState.Data2[i] = data2 =
(FLOAT)PhGetItemCircularBuffer_ULONG64(&PhIoWriteHistory, i);
if (max < data1 + data2)
max = data1 + data2;
}
if (max != 0)
{
// Scale the data.
PhxfDivideSingle2U(
IoGraphState.Data1,
max,
drawInfo->LineDataCount
);
PhxfDivideSingle2U(
IoGraphState.Data2,
max,
drawInfo->LineDataCount
);
}
IoGraphState.Valid = TRUE;
}
}
else if (header->hwndFrom == PhysicalGraphHandle)
{
ULONG totalPages;
ULONG usedPages;
totalPages = PhSystemBasicInformation.NumberOfPhysicalPages;
usedPages = totalPages - PhPerfInformation.AvailablePages;
if (PhCsGraphShowText)
{
HDC hdc;
PhSwapReference2(&PhysicalGraphState.TooltipText,
PhFormatString(
L"%s / %s (%.2f%%)",
PhaFormatSize(UInt32x32To64(usedPages, PAGE_SIZE), -1)->Buffer,
PhaFormatSize(UInt32x32To64(totalPages, PAGE_SIZE), -1)->Buffer,
(FLOAT)usedPages * 100 / totalPages
));
hdc = Graph_GetBufferedContext(PhysicalGraphHandle);
SelectObject(hdc, PhApplicationFont);
PhSetGraphText(hdc, drawInfo, &PhysicalGraphState.TooltipText->sr,
&PhNormalGraphTextMargin, &PhNormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT);
}
else
{
drawInfo->Text.Buffer = NULL;
}
drawInfo->Flags = PH_GRAPH_USE_GRID;
drawInfo->LineColor1 = PhCsColorPhysical;
drawInfo->LineBackColor1 = PhHalveColorBrightness(PhCsColorPhysical);
PhGraphStateGetDrawInfo(
&PhysicalGraphState,
getDrawInfo,
PhPhysicalHistory.Count
);
if (!PhysicalGraphState.Valid)
{
for (i = 0; i < drawInfo->LineDataCount; i++)
{
PhysicalGraphState.Data1[i] =
(FLOAT)PhGetItemCircularBuffer_ULONG(&PhPhysicalHistory, i);
}
if (PhSystemBasicInformation.NumberOfPhysicalPages != 0)
{
// Scale the data.
PhxfDivideSingle2U(
PhysicalGraphState.Data1,
(FLOAT)totalPages,
drawInfo->LineDataCount
);
}
PhysicalGraphState.Valid = TRUE;
}
}
else
{
for (i = 0; i < (ULONG)PhSystemBasicInformation.NumberOfProcessors; i++)
{
if (header->hwndFrom != CpusGraphHandle[i])
continue;
if (PhCsGraphShowText)
{
HDC hdc;
PhSwapReference2(&CpusGraphState[i].TooltipText,
PhFormatString(L"%.2f%% (K: %.2f%%, U: %.2f%%)",
(PhCpusKernelUsage[i] + PhCpusUserUsage[i]) * 100,
PhCpusKernelUsage[i] * 100,
PhCpusUserUsage[i] * 100
));
hdc = Graph_GetBufferedContext(CpusGraphHandle[i]);
SelectObject(hdc, PhApplicationFont);
PhSetGraphText(hdc, drawInfo, &CpusGraphState[i].TooltipText->sr,
&PhNormalGraphTextMargin, &PhNormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT);
}
else
{
drawInfo->Text.Buffer = NULL;
}
drawInfo->Flags = PH_GRAPH_USE_GRID | PH_GRAPH_USE_LINE_2;
drawInfo->LineColor1 = RGB(0x00, 0xff, 0x00);
drawInfo->LineColor2 = RGB(0xff, 0x00, 0x00);
drawInfo->LineBackColor1 = RGB(0x00, 0x77, 0x00);
drawInfo->LineBackColor2 = RGB(0x77, 0x00, 0x00);
PhGraphStateGetDrawInfo(
&CpusGraphState[i],
getDrawInfo,
PhCpusKernelHistory[i].Count
);
if (!CpusGraphState[i].Valid)
{
PhCopyCircularBuffer_FLOAT(&PhCpusKernelHistory[i],
CpusGraphState[i].Data1, drawInfo->LineDataCount);
PhCopyCircularBuffer_FLOAT(&PhCpusUserHistory[i],
CpusGraphState[i].Data2, drawInfo->LineDataCount);
CpusGraphState[i].Valid = TRUE;
}
}
}
}
break;
case GCN_GETTOOLTIPTEXT:
{
PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)lParam;
ULONG i;
if (
header->hwndFrom == CpuGraphHandle &&
getTooltipText->Index < getTooltipText->TotalCount
)
{
if (CpuGraphState.TooltipIndex != getTooltipText->Index)
{
FLOAT cpuKernel;
FLOAT cpuUser;
cpuKernel = PhGetItemCircularBuffer_FLOAT(&PhCpuKernelHistory, getTooltipText->Index);
cpuUser = PhGetItemCircularBuffer_FLOAT(&PhCpuUserHistory, getTooltipText->Index);
PhSwapReference2(&CpuGraphState.TooltipText, PhFormatString(
L"%.2f%%%s\n%s",
(cpuKernel + cpuUser) * 100,
PhGetStringOrEmpty(PhapGetMaxCpuString(getTooltipText->Index)),
((PPH_STRING)PHA_DEREFERENCE(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
));
}
getTooltipText->Text = CpuGraphState.TooltipText->sr;
}
else if (
header->hwndFrom == IoGraphHandle &&
getTooltipText->Index < getTooltipText->TotalCount
)
{
if (IoGraphState.TooltipIndex != getTooltipText->Index)
{
ULONG64 ioRead;
ULONG64 ioWrite;
ULONG64 ioOther;
ioRead = PhGetItemCircularBuffer_ULONG64(&PhIoReadHistory, getTooltipText->Index);
ioWrite = PhGetItemCircularBuffer_ULONG64(&PhIoWriteHistory, getTooltipText->Index);
ioOther = PhGetItemCircularBuffer_ULONG64(&PhIoOtherHistory, getTooltipText->Index);
PhSwapReference2(&IoGraphState.TooltipText, PhFormatString(
L"R: %s\nW: %s\nO: %s%s\n%s",
PhaFormatSize(ioRead, -1)->Buffer,
PhaFormatSize(ioWrite, -1)->Buffer,
PhaFormatSize(ioOther, -1)->Buffer,
PhGetStringOrEmpty(PhapGetMaxIoString(getTooltipText->Index)),
((PPH_STRING)PHA_DEREFERENCE(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
));
}
getTooltipText->Text = IoGraphState.TooltipText->sr;
}
else if (
header->hwndFrom == PhysicalGraphHandle &&
getTooltipText->Index < getTooltipText->TotalCount
)
{
if (PhysicalGraphState.TooltipIndex != getTooltipText->Index)
{
ULONG usedPages;
usedPages = PhGetItemCircularBuffer_ULONG(&PhPhysicalHistory, getTooltipText->Index);
PhSwapReference2(&PhysicalGraphState.TooltipText, PhFormatString(
L"Physical Memory: %s\n%s",
PhaFormatSize(UInt32x32To64(usedPages, PAGE_SIZE), -1)->Buffer,
((PPH_STRING)PHA_DEREFERENCE(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
));
}
getTooltipText->Text = PhysicalGraphState.TooltipText->sr;
}
else if (
getTooltipText->Index < getTooltipText->TotalCount
)
{
for (i = 0; i < (ULONG)PhSystemBasicInformation.NumberOfProcessors; i++)
{
if (header->hwndFrom != CpusGraphHandle[i])
continue;
if (CpusGraphState[i].TooltipIndex != getTooltipText->Index)
{
FLOAT cpuKernel;
FLOAT cpuUser;
cpuKernel = PhGetItemCircularBuffer_FLOAT(&PhCpusKernelHistory[i], getTooltipText->Index);
cpuUser = PhGetItemCircularBuffer_FLOAT(&PhCpusUserHistory[i], getTooltipText->Index);
PhSwapReference2(&CpusGraphState[i].TooltipText, PhFormatString(
L"%.2f%% (K: %.2f%%, U: %.2f%%)%s\n%s",
(cpuKernel + cpuUser) * 100,
cpuKernel * 100,
cpuUser * 100,
PhGetStringOrEmpty(PhapGetMaxCpuString(getTooltipText->Index)),
((PPH_STRING)PHA_DEREFERENCE(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
));
}
getTooltipText->Text = CpusGraphState[i].TooltipText->sr;
}
}
}
break;
case GCN_MOUSEEVENT:
{
PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)lParam;
PPH_PROCESS_RECORD record;
ULONG i;
record = NULL;
if (mouseEvent->Message == WM_LBUTTONDBLCLK)
{
if (
header->hwndFrom == CpuGraphHandle &&
mouseEvent->Index < mouseEvent->TotalCount
)
{
record = PhpReferenceMaxCpuRecord(mouseEvent->Index);
}
else if (
header->hwndFrom == IoGraphHandle &&
mouseEvent->Index < mouseEvent->TotalCount
)
{
record = PhpReferenceMaxIoRecord(mouseEvent->Index);
}
else if (
mouseEvent->Index < mouseEvent->TotalCount
)
{
for (i = 0; i < (ULONG)PhSystemBasicInformation.NumberOfProcessors; i++)
{
if (header->hwndFrom != CpusGraphHandle[i])
continue;
record = PhpReferenceMaxCpuRecord(mouseEvent->Index);
}
}
}
if (record)
{
PhShowProcessRecordDialog(PhSysInfoWindowHandle, record);
PhDereferenceProcessRecord(record);
}
}
break;
}
}
break;
case WM_PH_SYSINFO_ACTIVATE:
{
if (IsIconic(hwndDlg))
ShowWindow(hwndDlg, SW_RESTORE);
else
ShowWindow(hwndDlg, SW_SHOW);
SetForegroundWindow(hwndDlg);
}
break;
case WM_PH_SYSINFO_UPDATE:
{
ULONG i;
CpuGraphState.Valid = FALSE;
CpuGraphState.TooltipIndex = -1;
Graph_MoveGrid(CpuGraphHandle, 1);
Graph_Draw(CpuGraphHandle);
Graph_UpdateTooltip(CpuGraphHandle);
InvalidateRect(CpuGraphHandle, NULL, FALSE);
IoGraphState.Valid = FALSE;
IoGraphState.TooltipIndex = -1;
Graph_MoveGrid(IoGraphHandle, 1);
Graph_Draw(IoGraphHandle);
Graph_UpdateTooltip(IoGraphHandle);
InvalidateRect(IoGraphHandle, NULL, FALSE);
PhysicalGraphState.Valid = FALSE;
PhysicalGraphState.TooltipIndex = -1;
Graph_MoveGrid(PhysicalGraphHandle, 1);
Graph_Draw(PhysicalGraphHandle);
Graph_UpdateTooltip(PhysicalGraphHandle);
InvalidateRect(PhysicalGraphHandle, NULL, FALSE);
for (i = 0; i < (ULONG)PhSystemBasicInformation.NumberOfProcessors; i++)
{
CpusGraphState[i].Valid = FALSE;
CpusGraphState[i].TooltipIndex = -1;
Graph_MoveGrid(CpusGraphHandle[i], 1);
Graph_Draw(CpusGraphHandle[i]);
Graph_UpdateTooltip(CpusGraphHandle[i]);
InvalidateRect(CpusGraphHandle[i], NULL, FALSE);
}
SendMessage(PhSysInfoPanelWindowHandle, WM_PH_SYSINFO_PANEL_UPDATE, 0, 0);
}
break;
}
return FALSE;
}
static VOID PhpGetPoolLimits(
__out PSIZE_T Paged,
__out PSIZE_T NonPaged
)
{
SIZE_T paged = 0;
SIZE_T nonPaged = 0;
if (MmSizeOfPagedPoolInBytes)
{
KphReadVirtualMemoryUnsafe(
NtCurrentProcess(),
MmSizeOfPagedPoolInBytes,
&paged,
sizeof(SIZE_T),
NULL
);
}
if (MmMaximumNonPagedPoolInBytes)
{
KphReadVirtualMemoryUnsafe(
NtCurrentProcess(),
MmMaximumNonPagedPoolInBytes,
&nonPaged,
sizeof(SIZE_T),
NULL
);
}
*Paged = paged;
*NonPaged = nonPaged;
}
INT_PTR CALLBACK PhpSysInfoPanelDlgProc(
__in HWND hwndDlg,
__in UINT uMsg,
__in WPARAM wParam,
__in LPARAM lParam
)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
}
break;
case WM_DESTROY:
{
}
break;
case WM_PH_SYSINFO_PANEL_UPDATE:
{
WCHAR timeSpan[PH_TIMESPAN_STR_LEN_1] = L"Unknown";
SYSTEM_TIMEOFDAY_INFORMATION timeOfDayInfo;
SYSTEM_FILECACHE_INFORMATION fileCacheInfo;
PWSTR pagedLimit;
PWSTR nonPagedLimit;
if (!NT_SUCCESS(NtQuerySystemInformation(
SystemFileCacheInformation,
&fileCacheInfo,
sizeof(SYSTEM_FILECACHE_INFORMATION),
NULL
)))
{
memset(&fileCacheInfo, 0, sizeof(SYSTEM_FILECACHE_INFORMATION));
}
// System
SetDlgItemText(hwndDlg, IDC_ZPROCESSES_V, PhaFormatUInt64(PhTotalProcesses, TRUE)->Buffer);
SetDlgItemText(hwndDlg, IDC_ZTHREADS_V, PhaFormatUInt64(PhTotalThreads, TRUE)->Buffer);
SetDlgItemText(hwndDlg, IDC_ZHANDLES_V, PhaFormatUInt64(PhTotalHandles, TRUE)->Buffer);
if (NT_SUCCESS(NtQuerySystemInformation(
SystemTimeOfDayInformation,
&timeOfDayInfo,
sizeof(SYSTEM_TIMEOFDAY_INFORMATION),
NULL
)))
{
PhPrintTimeSpan(
timeSpan,
timeOfDayInfo.CurrentTime.QuadPart - timeOfDayInfo.BootTime.QuadPart,
PH_TIMESPAN_DHMS
);
}
SetDlgItemText(hwndDlg, IDC_ZUPTIME_V, timeSpan);
// Commit Charge
SetDlgItemText(hwndDlg, IDC_ZCOMMITCURRENT_V,
PhaFormatSize(UInt32x32To64(PhPerfInformation.CommittedPages, PAGE_SIZE), -1)->Buffer);
SetDlgItemText(hwndDlg, IDC_ZCOMMITPEAK_V,
PhaFormatSize(UInt32x32To64(PhPerfInformation.PeakCommitment, PAGE_SIZE), -1)->Buffer);
SetDlgItemText(hwndDlg, IDC_ZCOMMITLIMIT_V,
PhaFormatSize(UInt32x32To64(PhPerfInformation.CommitLimit, PAGE_SIZE), -1)->Buffer);
// Physical Memory
SetDlgItemText(hwndDlg, IDC_ZPHYSICALCURRENT_V,
PhaFormatSize(UInt32x32To64(PhSystemBasicInformation.NumberOfPhysicalPages - PhPerfInformation.AvailablePages, PAGE_SIZE), -1)->Buffer);
SetDlgItemText(hwndDlg, IDC_ZPHYSICALSYSTEMCACHE_V,
PhaFormatSize(UInt32x32To64(fileCacheInfo.CurrentSizeIncludingTransitionInPages, PAGE_SIZE), -1)->Buffer);
SetDlgItemText(hwndDlg, IDC_ZPHYSICALTOTAL_V,
PhaFormatSize(UInt32x32To64(PhSystemBasicInformation.NumberOfPhysicalPages, PAGE_SIZE), -1)->Buffer);
// Kernel Pools
SetDlgItemText(hwndDlg, IDC_ZPAGEDPHYSICAL_V,
PhaFormatSize(UInt32x32To64(PhPerfInformation.ResidentPagedPoolPage, PAGE_SIZE), -1)->Buffer);
SetDlgItemText(hwndDlg, IDC_ZPAGEDVIRTUAL_V,
PhaFormatSize(UInt32x32To64(PhPerfInformation.PagedPoolPages, PAGE_SIZE), -1)->Buffer);
SetDlgItemText(hwndDlg, IDC_ZPAGEDALLOCS_V,
PhaFormatUInt64(PhPerfInformation.PagedPoolAllocs, TRUE)->Buffer);
SetDlgItemText(hwndDlg, IDC_ZPAGEDFREES_V,
PhaFormatUInt64(PhPerfInformation.PagedPoolFrees, TRUE)->Buffer);
SetDlgItemText(hwndDlg, IDC_ZNONPAGEDUSAGE_V,
PhaFormatSize(UInt32x32To64(PhPerfInformation.NonPagedPoolPages, PAGE_SIZE), -1)->Buffer);
SetDlgItemText(hwndDlg, IDC_ZNONPAGEDALLOCS_V,
PhaFormatUInt64(PhPerfInformation.NonPagedPoolAllocs, TRUE)->Buffer);
SetDlgItemText(hwndDlg, IDC_ZNONPAGEDFREES_V,
PhaFormatUInt64(PhPerfInformation.NonPagedPoolFrees, TRUE)->Buffer);
if (MmAddressesInitialized && (MmSizeOfPagedPoolInBytes || MmMaximumNonPagedPoolInBytes))
{
SIZE_T paged;
SIZE_T nonPaged;
PhpGetPoolLimits(&paged, &nonPaged);
pagedLimit = PhaFormatSize(paged, -1)->Buffer;
nonPagedLimit = PhaFormatSize(nonPaged, -1)->Buffer;
}
else
{
if (!KphIsConnected())
{
pagedLimit = nonPagedLimit = L"no driver";
}
else
{
pagedLimit = nonPagedLimit = L"no symbols";
}
}
SetDlgItemText(hwndDlg, IDC_ZPAGEDLIMIT_V, pagedLimit);
SetDlgItemText(hwndDlg, IDC_ZNONPAGEDLIMIT_V, nonPagedLimit);
// Page Faults
SetDlgItemText(hwndDlg, IDC_ZPAGEFAULTSTOTAL_V,
PhaFormatUInt64(PhPerfInformation.PageFaultCount, TRUE)->Buffer);
SetDlgItemText(hwndDlg, IDC_ZPAGEFAULTSCOPYONWRITE_V,
PhaFormatUInt64(PhPerfInformation.CopyOnWriteCount, TRUE)->Buffer);
SetDlgItemText(hwndDlg, IDC_ZPAGEFAULTSTRANSITION_V,
PhaFormatUInt64(PhPerfInformation.TransitionCount, TRUE)->Buffer);
SetDlgItemText(hwndDlg, IDC_ZPAGEFAULTSCACHE_V,
PhaFormatUInt64(fileCacheInfo.PageFaultCount, TRUE)->Buffer);
// I/O
SetDlgItemText(hwndDlg, IDC_ZIOREADS_V,
PhaFormatUInt64(PhPerfInformation.IoReadOperationCount, TRUE)->Buffer);
SetDlgItemText(hwndDlg, IDC_ZIOREADBYTES_V,
PhaFormatSize(PhPerfInformation.IoReadTransferCount.QuadPart, -1)->Buffer);
SetDlgItemText(hwndDlg, IDC_ZIOWRITES_V,
PhaFormatUInt64(PhPerfInformation.IoWriteOperationCount, TRUE)->Buffer);
SetDlgItemText(hwndDlg, IDC_ZIOWRITEBYTES_V,
PhaFormatSize(PhPerfInformation.IoWriteTransferCount.QuadPart, -1)->Buffer);
SetDlgItemText(hwndDlg, IDC_ZIOOTHER_V,
PhaFormatUInt64(PhPerfInformation.IoOtherOperationCount, TRUE)->Buffer);
SetDlgItemText(hwndDlg, IDC_ZIOOTHERBYTES_V,
PhaFormatSize(PhPerfInformation.IoOtherTransferCount.QuadPart, -1)->Buffer);
// CPU
SetDlgItemText(hwndDlg, IDC_ZCONTEXTSWITCHES_V,
PhaFormatUInt64(PhPerfInformation.ContextSwitches, TRUE)->Buffer);
SetDlgItemText(hwndDlg, IDC_ZINTERRUPTS_V,
PhaFormatUInt64(PhCpuTotals.InterruptCount, TRUE)->Buffer);
SetDlgItemText(hwndDlg, IDC_ZSYSTEMCALLS_V,
PhaFormatUInt64(PhPerfInformation.SystemCalls, TRUE)->Buffer);
}
break;
}
return FALSE;
}