662 lines
23 KiB
C
662 lines
23 KiB
C
/*
|
|
* Process Hacker ToolStatus -
|
|
* Toolbar Graph Bands
|
|
*
|
|
* Copyright (C) 2015-2016 dmex
|
|
*
|
|
* 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 "toolstatus.h"
|
|
|
|
HWND CpuGraphHandle = NULL;
|
|
HWND MemGraphHandle = NULL;
|
|
HWND CommitGraphHandle = NULL;
|
|
HWND IoGraphHandle = NULL;
|
|
static PH_GRAPH_STATE CpuGraphState;
|
|
static PH_GRAPH_STATE MemGraphState;
|
|
static PH_GRAPH_STATE CommitGraphState;
|
|
static PH_GRAPH_STATE IoGraphState;
|
|
|
|
VOID ToolbarCreateGraphs(VOID)
|
|
{
|
|
UINT height = (UINT)SendMessage(RebarHandle, RB_GETROWHEIGHT, 0, 0);
|
|
|
|
if (ToolStatusConfig.CpuGraphEnabled && !CpuGraphHandle)
|
|
{
|
|
CpuGraphHandle = CreateWindow(
|
|
PH_GRAPH_CLASSNAME,
|
|
NULL,
|
|
WS_VISIBLE | WS_CHILD | WS_BORDER,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
PhMainWndHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
Graph_SetTooltip(CpuGraphHandle, TRUE);
|
|
|
|
PhInitializeGraphState(&CpuGraphState);
|
|
}
|
|
|
|
if (ToolStatusConfig.MemGraphEnabled && !MemGraphHandle)
|
|
{
|
|
MemGraphHandle = CreateWindow(
|
|
PH_GRAPH_CLASSNAME,
|
|
NULL,
|
|
WS_VISIBLE | WS_CHILD | WS_BORDER,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
PhMainWndHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
Graph_SetTooltip(MemGraphHandle, TRUE);
|
|
|
|
PhInitializeGraphState(&MemGraphState);
|
|
}
|
|
|
|
if (ToolStatusConfig.CommitGraphEnabled && !CommitGraphHandle)
|
|
{
|
|
CommitGraphHandle = CreateWindow(
|
|
PH_GRAPH_CLASSNAME,
|
|
NULL,
|
|
WS_VISIBLE | WS_CHILD | WS_BORDER,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
PhMainWndHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
Graph_SetTooltip(CommitGraphHandle, TRUE);
|
|
|
|
PhInitializeGraphState(&CommitGraphState);
|
|
}
|
|
|
|
if (ToolStatusConfig.IoGraphEnabled && !IoGraphHandle)
|
|
{
|
|
IoGraphHandle = CreateWindow(
|
|
PH_GRAPH_CLASSNAME,
|
|
NULL,
|
|
WS_VISIBLE | WS_CHILD | WS_BORDER,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
PhMainWndHandle,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
Graph_SetTooltip(IoGraphHandle, TRUE);
|
|
|
|
PhInitializeGraphState(&IoGraphState);
|
|
}
|
|
|
|
if (ToolStatusConfig.CpuGraphEnabled)
|
|
{
|
|
if (!RebarBandExists(REBAR_BAND_ID_CPUGRAPH))
|
|
RebarBandInsert(REBAR_BAND_ID_CPUGRAPH, CpuGraphHandle, 145, height); // 85
|
|
|
|
if (CpuGraphHandle && !IsWindowVisible(CpuGraphHandle))
|
|
ShowWindow(CpuGraphHandle, SW_SHOW);
|
|
}
|
|
else
|
|
{
|
|
if (RebarBandExists(REBAR_BAND_ID_CPUGRAPH))
|
|
RebarBandRemove(REBAR_BAND_ID_CPUGRAPH);
|
|
|
|
if (CpuGraphHandle)
|
|
{
|
|
PhDeleteGraphState(&CpuGraphState);
|
|
|
|
DestroyWindow(CpuGraphHandle);
|
|
CpuGraphHandle = NULL;
|
|
}
|
|
}
|
|
|
|
if (ToolStatusConfig.MemGraphEnabled)
|
|
{
|
|
if (!RebarBandExists(REBAR_BAND_ID_MEMGRAPH))
|
|
RebarBandInsert(REBAR_BAND_ID_MEMGRAPH, MemGraphHandle, 145, height); // 85
|
|
|
|
if (MemGraphHandle && !IsWindowVisible(MemGraphHandle))
|
|
{
|
|
ShowWindow(MemGraphHandle, SW_SHOW);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (RebarBandExists(REBAR_BAND_ID_MEMGRAPH))
|
|
RebarBandRemove(REBAR_BAND_ID_MEMGRAPH);
|
|
|
|
if (MemGraphHandle)
|
|
{
|
|
PhDeleteGraphState(&MemGraphState);
|
|
|
|
DestroyWindow(MemGraphHandle);
|
|
MemGraphHandle = NULL;
|
|
}
|
|
}
|
|
|
|
if (ToolStatusConfig.CommitGraphEnabled)
|
|
{
|
|
if (!RebarBandExists(REBAR_BAND_ID_COMMITGRAPH))
|
|
RebarBandInsert(REBAR_BAND_ID_COMMITGRAPH, CommitGraphHandle, 145, height); // 85
|
|
|
|
if (CommitGraphHandle && !IsWindowVisible(CommitGraphHandle))
|
|
{
|
|
ShowWindow(CommitGraphHandle, SW_SHOW);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (RebarBandExists(REBAR_BAND_ID_COMMITGRAPH))
|
|
RebarBandRemove(REBAR_BAND_ID_COMMITGRAPH);
|
|
|
|
if (CommitGraphHandle)
|
|
{
|
|
PhDeleteGraphState(&CommitGraphState);
|
|
|
|
DestroyWindow(CommitGraphHandle);
|
|
CommitGraphHandle = NULL;
|
|
}
|
|
}
|
|
|
|
if (ToolStatusConfig.IoGraphEnabled)
|
|
{
|
|
if (!RebarBandExists(REBAR_BAND_ID_IOGRAPH))
|
|
RebarBandInsert(REBAR_BAND_ID_IOGRAPH, IoGraphHandle, 145, height); // 85
|
|
|
|
if (IoGraphHandle && !IsWindowVisible(IoGraphHandle))
|
|
{
|
|
ShowWindow(IoGraphHandle, SW_SHOW);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (RebarBandExists(REBAR_BAND_ID_IOGRAPH))
|
|
RebarBandRemove(REBAR_BAND_ID_IOGRAPH);
|
|
|
|
if (IoGraphHandle)
|
|
{
|
|
PhDeleteGraphState(&IoGraphState);
|
|
|
|
DestroyWindow(IoGraphHandle);
|
|
IoGraphHandle = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID ToolbarUpdateGraphs(VOID)
|
|
{
|
|
if (ToolStatusConfig.CpuGraphEnabled && CpuGraphHandle)
|
|
{
|
|
CpuGraphState.Valid = FALSE;
|
|
CpuGraphState.TooltipIndex = -1;
|
|
Graph_MoveGrid(CpuGraphHandle, 1);
|
|
Graph_Draw(CpuGraphHandle);
|
|
Graph_UpdateTooltip(CpuGraphHandle);
|
|
InvalidateRect(CpuGraphHandle, NULL, FALSE);
|
|
}
|
|
|
|
if (ToolStatusConfig.MemGraphEnabled && MemGraphHandle)
|
|
{
|
|
MemGraphState.Valid = FALSE;
|
|
MemGraphState.TooltipIndex = -1;
|
|
Graph_MoveGrid(MemGraphHandle, 1);
|
|
Graph_Draw(MemGraphHandle);
|
|
Graph_UpdateTooltip(MemGraphHandle);
|
|
InvalidateRect(MemGraphHandle, NULL, FALSE);
|
|
}
|
|
|
|
if (ToolStatusConfig.CommitGraphEnabled && CommitGraphHandle)
|
|
{
|
|
CommitGraphState.Valid = FALSE;
|
|
CommitGraphState.TooltipIndex = -1;
|
|
Graph_MoveGrid(CommitGraphHandle, 1);
|
|
Graph_Draw(CommitGraphHandle);
|
|
Graph_UpdateTooltip(CommitGraphHandle);
|
|
InvalidateRect(CommitGraphHandle, NULL, FALSE);
|
|
}
|
|
|
|
if (ToolStatusConfig.IoGraphEnabled && IoGraphHandle)
|
|
{
|
|
IoGraphState.Valid = FALSE;
|
|
IoGraphState.TooltipIndex = -1;
|
|
Graph_MoveGrid(IoGraphHandle, 1);
|
|
Graph_Draw(IoGraphHandle);
|
|
Graph_UpdateTooltip(IoGraphHandle);
|
|
InvalidateRect(IoGraphHandle, NULL, FALSE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// BEGIN copied from ProcessHacker/sysinfo.c
|
|
//
|
|
|
|
static PPH_PROCESS_RECORD PhSipReferenceMaxCpuRecord(
|
|
_In_ LONG Index
|
|
)
|
|
{
|
|
LARGE_INTEGER time;
|
|
LONG maxProcessIdLong;
|
|
HANDLE maxProcessId;
|
|
|
|
// Find the process record for the max. CPU process for the particular time.
|
|
|
|
maxProcessIdLong = PhGetItemCircularBuffer_ULONG(SystemStatistics.MaxCpuHistory, Index);
|
|
|
|
if (!maxProcessIdLong)
|
|
return NULL;
|
|
|
|
// This must be treated as a signed integer to handle Interrupts correctly.
|
|
maxProcessId = LongToHandle(maxProcessIdLong);
|
|
|
|
// 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(maxProcessId, &time);
|
|
}
|
|
|
|
static PPH_STRING PhSipGetMaxCpuString(
|
|
_In_ LONG Index
|
|
)
|
|
{
|
|
PPH_PROCESS_RECORD maxProcessRecord;
|
|
FLOAT maxCpuUsage;
|
|
PPH_STRING maxUsageString = NULL;
|
|
|
|
if (maxProcessRecord = PhSipReferenceMaxCpuRecord(Index))
|
|
{
|
|
// We found the process record, so now we construct the max. usage string.
|
|
maxCpuUsage = PhGetItemCircularBuffer_FLOAT(SystemStatistics.MaxCpuUsageHistory, 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,
|
|
HandleToUlong(maxProcessRecord->ProcessId),
|
|
maxCpuUsage * 100
|
|
);
|
|
}
|
|
else
|
|
{
|
|
maxUsageString = PhaFormatString(
|
|
L"\n%s: %.2f%%",
|
|
maxProcessRecord->ProcessName->Buffer,
|
|
maxCpuUsage * 100
|
|
);
|
|
}
|
|
|
|
PhDereferenceProcessRecord(maxProcessRecord);
|
|
}
|
|
|
|
return maxUsageString;
|
|
}
|
|
|
|
static PPH_PROCESS_RECORD PhSipReferenceMaxIoRecord(
|
|
_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(SystemStatistics.MaxIoHistory, Index);
|
|
|
|
if (!maxProcessId)
|
|
return NULL;
|
|
|
|
// See above for the explanation.
|
|
PhGetStatisticsTime(NULL, Index, &time);
|
|
time.QuadPart += PH_TICKS_PER_SEC - 1;
|
|
|
|
return PhFindProcessRecord(UlongToHandle(maxProcessId), &time);
|
|
}
|
|
|
|
static PPH_STRING PhSipGetMaxIoString(
|
|
_In_ LONG Index
|
|
)
|
|
{
|
|
PPH_PROCESS_RECORD maxProcessRecord;
|
|
ULONG64 maxIoReadOther;
|
|
ULONG64 maxIoWrite;
|
|
|
|
PPH_STRING maxUsageString = NULL;
|
|
|
|
if (maxProcessRecord = PhSipReferenceMaxIoRecord(Index))
|
|
{
|
|
// We found the process record, so now we construct the max. usage string.
|
|
maxIoReadOther = PhGetItemCircularBuffer_ULONG64(SystemStatistics.MaxIoReadOtherHistory, Index);
|
|
maxIoWrite = PhGetItemCircularBuffer_ULONG64(SystemStatistics.MaxIoWriteHistory, Index);
|
|
|
|
if (!PH_IS_FAKE_PROCESS_ID(maxProcessRecord->ProcessId))
|
|
{
|
|
maxUsageString = PhaFormatString(
|
|
L"\n%s (%u): R+O: %s, W: %s",
|
|
maxProcessRecord->ProcessName->Buffer,
|
|
HandleToUlong(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
|
|
);
|
|
}
|
|
|
|
PhDereferenceProcessRecord(maxProcessRecord);
|
|
}
|
|
|
|
return maxUsageString;
|
|
}
|
|
|
|
//
|
|
// END copied from ProcessHacker/sysinfo.c
|
|
//
|
|
|
|
VOID ToolbarUpdateGraphsInfo(LPNMHDR Header)
|
|
{
|
|
switch (Header->code)
|
|
{
|
|
case GCN_GETDRAWINFO:
|
|
{
|
|
if (ToolStatusConfig.CpuGraphEnabled && Header->hwndFrom == CpuGraphHandle)
|
|
{
|
|
PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header;
|
|
PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;
|
|
|
|
drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_LINE_2;
|
|
PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), PhGetIntegerSetting(L"ColorCpuUser"));
|
|
|
|
if (ProcessesUpdatedCount < 2)
|
|
return;
|
|
|
|
PhGraphStateGetDrawInfo(&CpuGraphState, getDrawInfo, SystemStatistics.CpuUserHistory->Count);
|
|
|
|
if (!CpuGraphState.Valid)
|
|
{
|
|
PhCopyCircularBuffer_FLOAT(SystemStatistics.CpuKernelHistory,
|
|
CpuGraphState.Data1, drawInfo->LineDataCount);
|
|
PhCopyCircularBuffer_FLOAT(SystemStatistics.CpuUserHistory,
|
|
CpuGraphState.Data2, drawInfo->LineDataCount);
|
|
|
|
CpuGraphState.Valid = TRUE;
|
|
}
|
|
}
|
|
else if (ToolStatusConfig.MemGraphEnabled && Header->hwndFrom == MemGraphHandle)
|
|
{
|
|
PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header;
|
|
PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;
|
|
|
|
drawInfo->Flags = PH_GRAPH_USE_GRID_X;
|
|
PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorPhysical"), 0);
|
|
|
|
if (ProcessesUpdatedCount < 2)
|
|
return;
|
|
|
|
PhGraphStateGetDrawInfo(&MemGraphState, getDrawInfo, SystemStatistics.PhysicalHistory->Count);
|
|
|
|
if (!MemGraphState.Valid)
|
|
{
|
|
for (ULONG i = 0; i < drawInfo->LineDataCount; i++)
|
|
{
|
|
MemGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(SystemStatistics.PhysicalHistory, i);
|
|
}
|
|
|
|
PhDivideSinglesBySingle(
|
|
MemGraphState.Data1,
|
|
(FLOAT)PhSystemBasicInformation.NumberOfPhysicalPages,
|
|
drawInfo->LineDataCount
|
|
);
|
|
|
|
MemGraphState.Valid = TRUE;
|
|
}
|
|
}
|
|
else if (ToolStatusConfig.CommitGraphEnabled && Header->hwndFrom == CommitGraphHandle)
|
|
{
|
|
PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header;
|
|
PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;
|
|
|
|
drawInfo->Flags = PH_GRAPH_USE_GRID_X;
|
|
PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorPrivate"), 0);
|
|
|
|
if (ProcessesUpdatedCount < 2)
|
|
return;
|
|
|
|
PhGraphStateGetDrawInfo(&CommitGraphState, getDrawInfo, SystemStatistics.CommitHistory->Count);
|
|
|
|
if (!CommitGraphState.Valid)
|
|
{
|
|
for (ULONG i = 0; i < drawInfo->LineDataCount; i++)
|
|
{
|
|
CommitGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(SystemStatistics.CommitHistory, i);
|
|
}
|
|
|
|
PhDivideSinglesBySingle(
|
|
CommitGraphState.Data1,
|
|
(FLOAT)SystemStatistics.Performance->CommitLimit,
|
|
drawInfo->LineDataCount
|
|
);
|
|
|
|
CommitGraphState.Valid = TRUE;
|
|
}
|
|
}
|
|
else if (ToolStatusConfig.IoGraphEnabled && Header->hwndFrom == IoGraphHandle)
|
|
{
|
|
PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header;
|
|
PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;
|
|
|
|
drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_LINE_2;
|
|
PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite"));
|
|
|
|
if (ProcessesUpdatedCount < 2)
|
|
return;
|
|
|
|
PhGraphStateGetDrawInfo(&IoGraphState, getDrawInfo, SystemStatistics.IoReadHistory->Count);
|
|
|
|
if (!IoGraphState.Valid)
|
|
{
|
|
FLOAT max = 1024 * 1024; // minimum scaling of 1 MB.
|
|
|
|
for (ULONG i = 0; i < drawInfo->LineDataCount; i++)
|
|
{
|
|
IoGraphState.Data1[i] =
|
|
(FLOAT)PhGetItemCircularBuffer_ULONG64(SystemStatistics.IoReadHistory, i) +
|
|
(FLOAT)PhGetItemCircularBuffer_ULONG64(SystemStatistics.IoOtherHistory, i);
|
|
IoGraphState.Data2[i] =
|
|
(FLOAT)PhGetItemCircularBuffer_ULONG64(SystemStatistics.IoWriteHistory, i);
|
|
|
|
if (max < IoGraphState.Data1[i] + IoGraphState.Data2[i])
|
|
max = IoGraphState.Data1[i] + IoGraphState.Data2[i];
|
|
}
|
|
|
|
PhDivideSinglesBySingle(IoGraphState.Data1, max, drawInfo->LineDataCount);
|
|
PhDivideSinglesBySingle(IoGraphState.Data2, max, drawInfo->LineDataCount);
|
|
|
|
IoGraphState.Valid = TRUE;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case GCN_GETTOOLTIPTEXT:
|
|
{
|
|
PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header;
|
|
|
|
if (getTooltipText->Index < getTooltipText->TotalCount)
|
|
{
|
|
if (ToolStatusConfig.CpuGraphEnabled && Header->hwndFrom == CpuGraphHandle)
|
|
{
|
|
if (CpuGraphState.TooltipIndex != getTooltipText->Index)
|
|
{
|
|
FLOAT cpuKernel;
|
|
FLOAT cpuUser;
|
|
|
|
cpuKernel = PhGetItemCircularBuffer_FLOAT(SystemStatistics.CpuKernelHistory, getTooltipText->Index);
|
|
cpuUser = PhGetItemCircularBuffer_FLOAT(SystemStatistics.CpuUserHistory, getTooltipText->Index);
|
|
|
|
PhMoveReference(&CpuGraphState.TooltipText, PhFormatString(
|
|
L"%.2f%%%s\n%s",
|
|
(cpuKernel + cpuUser) * 100,
|
|
PhGetStringOrEmpty(PhSipGetMaxCpuString(getTooltipText->Index)),
|
|
PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer
|
|
));
|
|
}
|
|
|
|
getTooltipText->Text = CpuGraphState.TooltipText->sr;
|
|
}
|
|
else if (ToolStatusConfig.MemGraphEnabled && Header->hwndFrom == MemGraphHandle)
|
|
{
|
|
ULONG physicalUsage;
|
|
|
|
physicalUsage = PhGetItemCircularBuffer_ULONG(SystemStatistics.PhysicalHistory, getTooltipText->Index);
|
|
|
|
PhMoveReference(&MemGraphState.TooltipText, PhFormatString(
|
|
L"Physical memory: %s\n%s",
|
|
PhaFormatSize(UInt32x32To64(physicalUsage, PAGE_SIZE), -1)->Buffer,
|
|
PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer
|
|
));
|
|
getTooltipText->Text = MemGraphState.TooltipText->sr;
|
|
}
|
|
else if (ToolStatusConfig.CommitGraphEnabled && Header->hwndFrom == CommitGraphHandle)
|
|
{
|
|
ULONG commitUsage;
|
|
|
|
commitUsage = PhGetItemCircularBuffer_ULONG(SystemStatistics.CommitHistory, getTooltipText->Index);
|
|
|
|
PhMoveReference(&CommitGraphState.TooltipText, PhFormatString(
|
|
L"Commit charge: %s\n%s",
|
|
PhaFormatSize(UInt32x32To64(commitUsage, PAGE_SIZE), -1)->Buffer,
|
|
PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer
|
|
));
|
|
getTooltipText->Text = CommitGraphState.TooltipText->sr;
|
|
}
|
|
else if (ToolStatusConfig.IoGraphEnabled && Header->hwndFrom == IoGraphHandle)
|
|
{
|
|
ULONG64 ioRead;
|
|
ULONG64 ioWrite;
|
|
ULONG64 ioOther;
|
|
|
|
ioRead = PhGetItemCircularBuffer_ULONG64(SystemStatistics.IoReadHistory, getTooltipText->Index);
|
|
ioWrite = PhGetItemCircularBuffer_ULONG64(SystemStatistics.IoWriteHistory, getTooltipText->Index);
|
|
ioOther = PhGetItemCircularBuffer_ULONG64(SystemStatistics.IoOtherHistory, getTooltipText->Index);
|
|
|
|
PhMoveReference(&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(PhSipGetMaxIoString(getTooltipText->Index)),
|
|
PH_AUTO_T(PH_STRING, PhGetStatisticsTimeString(NULL, getTooltipText->Index))->Buffer
|
|
));
|
|
getTooltipText->Text = IoGraphState.TooltipText->sr;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case GCN_MOUSEEVENT:
|
|
{
|
|
PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Header;
|
|
PPH_PROCESS_RECORD record = NULL;
|
|
|
|
if (ToolStatusConfig.CpuGraphEnabled && Header->hwndFrom == CpuGraphHandle)
|
|
{
|
|
if (mouseEvent->Message == WM_RBUTTONUP)
|
|
{
|
|
ShowCustomizeMenu();
|
|
}
|
|
else
|
|
{
|
|
if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount)
|
|
{
|
|
record = PhSipReferenceMaxCpuRecord(mouseEvent->Index);
|
|
}
|
|
|
|
if (record)
|
|
{
|
|
PhShowProcessRecordDialog(PhMainWndHandle, record);
|
|
PhDereferenceProcessRecord(record);
|
|
}
|
|
}
|
|
}
|
|
else if (ToolStatusConfig.MemGraphEnabled && Header->hwndFrom == MemGraphHandle)
|
|
{
|
|
if (mouseEvent->Message == WM_RBUTTONUP)
|
|
{
|
|
ShowCustomizeMenu();
|
|
}
|
|
}
|
|
else if (ToolStatusConfig.CommitGraphEnabled && Header->hwndFrom == CommitGraphHandle)
|
|
{
|
|
if (mouseEvent->Message == WM_RBUTTONUP)
|
|
{
|
|
ShowCustomizeMenu();
|
|
}
|
|
}
|
|
else if (ToolStatusConfig.IoGraphEnabled && Header->hwndFrom == IoGraphHandle)
|
|
{
|
|
if (mouseEvent->Message == WM_RBUTTONUP)
|
|
{
|
|
ShowCustomizeMenu();
|
|
}
|
|
else
|
|
{
|
|
if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount)
|
|
{
|
|
record = PhSipReferenceMaxIoRecord(mouseEvent->Index);
|
|
}
|
|
|
|
if (record)
|
|
{
|
|
PhShowProcessRecordDialog(PhMainWndHandle, record);
|
|
PhDereferenceProcessRecord(record);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
} |