go my file uploader

This commit is contained in:
AirDog46
2025-05-13 19:45:22 +03:00
commit c5fab8aa94
708 changed files with 343216 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
1.16
* Fixed "No process" disk event bug
1.15
* Added tray icon mini info window support
* Improved automatic GPU node selection
1.14
* Added Disk and Network graphs for all processes
1.13
* Added GPU graphs for all processes
* Can now use the search box in the Disk tab
* Improved kernel logger handling on Windows 8
1.12
* Improved support for multiple GPUs (again)
* GPU column now respects "Include CPU usage of children" option
1.11
* Fixed network graph scaling
1.10
* Improved support for multiple GPUs
1.9
* Added GPU node selection
* Fixed incorrect GPU usage calculation
1.8
* Added support for new system information window
* Added Disk, Network and GPU tray icons
* Added support for custom fonts in the Disk tab
1.7
* Added GPU monitoring
* Added rate columns for disk and network I/O
1.6
* Updated disk monitoring for Windows 8
* Updated memory list information for Windows 8
1.5
* Added Disk tab
* Added Hard Faults, Hard Faults Delta and Peak Threads columns
to process tree list
* Added Firewall Status column to network list
1.4
* Added ETW columns for processes and network connections
1.3
* Fixed WS Watch refresh bug
1.2
* Added WS Watch
* Added display of standby repurposed pages
* Added Empty commands for memory lists
* Fixed Disk and Network page crash
1.1
* Fixed ETW crash
1.0
* Initial release

View File

@@ -0,0 +1,537 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (Australia) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS
#pragma code_page(1252)
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,16,0,0
PRODUCTVERSION 1,16,0,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "0c0904b0"
BEGIN
VALUE "CompanyName", "wj32"
VALUE "FileDescription", "Extended Tools plugin for Process Hacker"
VALUE "FileVersion", "1.16"
VALUE "InternalName", "ExtendedTools"
VALUE "LegalCopyright", "Licensed under the GNU GPL, v3."
VALUE "OriginalFilename", "ExtendedTools.dll"
VALUE "ProductName", "Extended Tools plugin for Process Hacker"
VALUE "ProductVersion", "1.16"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0xc09, 1200
END
END
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_UNLOADEDDLLS DIALOGEX 0, 0, 342, 265
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Unloaded Modules"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,328,233
PUSHBUTTON "Refresh",IDC_REFRESH,7,244,50,14
DEFPUSHBUTTON "Close",IDOK,285,244,50,14
END
IDD_OBJALPCPORT DIALOGEX 0, 0, 160, 101
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "ALPC Port"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Sequence number: Unknown",IDC_SEQUENCENUMBER,7,7,146,8
LTEXT "Port context: Unknown",IDC_PORTCONTEXT,7,19,146,8
END
IDD_OBJTPWORKERFACTORY DIALOGEX 0, 0, 186, 101
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Worker Factory"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Worker thread start: Unknown",IDC_WORKERTHREADSTART,7,7,172,8,SS_ENDELLIPSIS
LTEXT "Worker thread context: Unknown",IDC_WORKERTHREADCONTEXT,7,18,172,8,SS_ENDELLIPSIS
END
IDD_MODSERVICES DIALOGEX 0, 0, 276, 209
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Services"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Static",IDC_MESSAGE,7,7,262,8
LTEXT "Static",IDC_SERVICES_LAYOUT,7,22,262,162,NOT WS_VISIBLE
DEFPUSHBUTTON "Close",IDOK,219,188,50,14
END
IDD_PROCDISKNET DIALOGEX 0, 0, 265, 158
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Disk and Network"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
GROUPBOX "Disk",IDC_GROUPDISK,7,7,251,69
GROUPBOX "Network",IDC_GROUPNETWORK,7,81,251,69
END
IDD_SYSINFO_DISKPANEL DIALOGEX 0, 0, 146, 58
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
GROUPBOX "Disk I/O",IDC_STATIC,0,0,145,58
LTEXT "Reads delta",IDC_STATIC,8,11,40,8
LTEXT "Read bytes delta",IDC_STATIC,8,22,56,8
LTEXT "Writes delta",IDC_STATIC,8,33,40,8
LTEXT "Write bytes delta",IDC_STATIC,8,44,57,8
RTEXT "Static",IDC_ZREADSDELTA_V,84,11,54,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_ZREADBYTESDELTA_V,78,22,60,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_ZWRITESDELTA_V,84,33,54,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_ZWRITEBYTESDELTA_V,82,44,56,8,SS_ENDELLIPSIS
END
IDD_OPTIONS DIALOGEX 0, 0, 215, 77
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Options"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Changes to settings will require a restart of Process Hacker.",IDC_STATIC,7,7,193,8
CONTROL "Enable Disk and Network monitoring",IDC_ENABLEETWMONITOR,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,20,130,10
CONTROL "Enable GPU monitoring",IDC_ENABLEGPUMONITOR,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,32,88,10
DEFPUSHBUTTON "OK",IDOK,104,56,50,14
PUSHBUTTON "Cancel",IDCANCEL,158,56,50,14
END
IDD_WSWATCH DIALOGEX 0, 0, 325, 266
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "WS Watch"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Working set watch allows you to monitor page faults that occur in a process. You must enable WS watch for the process to start the monitoring. Once WS watch is enabled, it cannot be disabled.",IDC_STATIC,7,7,311,27
PUSHBUTTON "Enable",IDC_ENABLE,7,37,50,14
LTEXT "WS watch is enabled.",IDC_WSWATCHENABLED,63,40,119,8,NOT WS_VISIBLE
LTEXT "Page faults:",IDC_STATIC,7,54,40,8
CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,65,311,175
DEFPUSHBUTTON "Close",IDOK,268,245,50,14
END
IDD_SYSINFO_GPU DIALOGEX 0, 0, 315, 186
STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
CAPTION "GPU"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "GPU",IDC_TITLE,0,0,72,21
RTEXT "GPU name",IDC_GPUNAME,83,4,232,16,SS_WORDELLIPSIS
LTEXT "Panel layout",IDC_PANEL_LAYOUT,0,130,315,55,NOT WS_VISIBLE
LTEXT "Graph layout",IDC_GRAPH_LAYOUT,0,22,315,102,NOT WS_VISIBLE
LTEXT "GPU:",IDC_GPU_L,73,0,17,8
LTEXT "Dedicated memory:",IDC_DEDICATED_L,73,5,63,8
LTEXT "Shared memory:",IDC_SHARED_L,74,11,54,8
END
IDD_SYSINFO_GPUPANEL DIALOGEX 0, 0, 246, 54
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
GROUPBOX "Dedicated memory",IDC_STATIC,0,0,118,36
LTEXT "Current",IDC_STATIC,8,11,26,8
LTEXT "Limit",IDC_STATIC,8,22,15,8
RTEXT "Static",IDC_ZDEDICATEDCURRENT_V,55,11,54,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_ZDEDICATEDLIMIT_V,55,22,54,8,SS_ENDELLIPSIS
GROUPBOX "Shared memory",IDC_STATIC,122,0,124,36
LTEXT "Current",IDC_STATIC,130,11,26,8
LTEXT "Limit",IDC_STATIC,130,23,15,8
RTEXT "Static",IDC_ZSHAREDCURRENT_V,182,11,54,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_ZSHAREDLIMIT_V,182,23,54,8,SS_ENDELLIPSIS
PUSHBUTTON "Nodes",IDC_NODES,152,40,50,14
LTEXT "Select nodes used for GPU usage calculations:",IDC_STATIC,0,43,148,8
END
IDD_PROCGPU DIALOGEX 0, 0, 369, 237
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "GPU"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
GROUPBOX "GPU",IDC_GROUPGPU,7,7,355,69
GROUPBOX "Dedicated memory",IDC_GROUPMEM,7,81,355,69
GROUPBOX "Shared memory",IDC_GROUPSHARED,7,160,355,69
END
IDD_SYSINFO_DISK DIALOGEX 0, 0, 315, 186
STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
CAPTION "Disk"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Disk",IDC_TITLE,0,0,72,21
LTEXT "Panel layout",IDC_PANEL_LAYOUT,0,124,315,61,NOT WS_VISIBLE
LTEXT "Graph layout",IDC_GRAPH_LAYOUT,0,22,315,99,NOT WS_VISIBLE
END
IDD_SYSINFO_NETPANEL DIALOGEX 0, 0, 145, 58
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
GROUPBOX "Network I/O",IDC_STATIC,0,0,145,58
LTEXT "Receives delta",IDC_STATIC,8,11,48,8
LTEXT "Receive bytes delta",IDC_STATIC,8,22,65,8
LTEXT "Sends delta",IDC_STATIC,8,33,39,8
LTEXT "Send bytes delta",IDC_STATIC,8,44,56,8
RTEXT "Static",IDC_ZRECEIVESDELTA_V,84,11,54,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_ZRECEIVEBYTESDELTA_V,78,22,60,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_ZSENDSDELTA_V,84,33,54,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_ZSENDBYTESDELTA_V,82,44,56,8,SS_ENDELLIPSIS
END
IDD_SYSINFO_NET DIALOGEX 0, 0, 315, 186
STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
CAPTION "Network"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Network",IDC_TITLE,0,0,72,21
LTEXT "Panel layout",IDC_PANEL_LAYOUT,0,124,315,61,NOT WS_VISIBLE
LTEXT "Graph layout",IDC_GRAPH_LAYOUT,0,22,315,99,NOT WS_VISIBLE
END
IDD_GPUNODES DIALOGEX 0, 0, 317, 183
STYLE DS_SETFONT | DS_FIXEDSYS | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
CAPTION "GPU Nodes"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Select the nodes that will be included in GPU usage calculations.",IDC_INSTRUCTION,7,7,204,8
LTEXT "Graph layout",IDC_LAYOUT,7,21,303,137,NOT WS_VISIBLE
CONTROL "Example checkbox",IDC_EXAMPLE,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,7,166,75,10
DEFPUSHBUTTON "OK",IDOK,260,162,50,14
END
IDD_PROCGPU_PANEL DIALOGEX 0, 0, 248, 46
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
GROUPBOX "Memory",IDC_STATIC,2,0,118,46
GROUPBOX "Nodes",IDC_STATIC,124,0,124,46
LTEXT "Running time",IDC_STATIC,132,11,44,8
LTEXT "Context switches",IDC_STATIC,132,22,57,8
RTEXT "Static",IDC_ZRUNNINGTIME_V,184,11,54,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_ZCONTEXTSWITCHES_V,200,22,38,8,SS_ENDELLIPSIS
LTEXT "Total segments",IDC_STATIC,10,11,50,8
RTEXT "Static",IDC_ZTOTALSEGMENTS_V,73,11,38,8,SS_ENDELLIPSIS
LTEXT "Total nodes",IDC_STATIC,132,33,39,8
RTEXT "Static",IDC_ZTOTALNODES_V,200,33,38,8,SS_ENDELLIPSIS
PUSHBUTTON "More",IDC_GPUDETAILS,7,27,50,14
END
IDD_DISKTABERROR DIALOGEX 0, 0, 309, 176
STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU
EXSTYLE WS_EX_TRANSPARENT
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Disk monitoring requires Process Hacker to be restarted with administrative privileges.",IDC_ERROR,16,14,275,8
PUSHBUTTON "Restart",IDC_RESTART,20,28,50,14
END
IDD_PROCDISKNET_PANEL DIALOGEX 0, 0, 248, 82
STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
GROUPBOX "Disk I/O",IDC_STATIC,2,0,118,82
LTEXT "Reads",IDC_STATIC,10,11,21,8
LTEXT "Read bytes",IDC_STATIC,10,22,38,8
LTEXT "Read bytes delta",IDC_STATIC,10,33,56,8
LTEXT "Writes",IDC_STATIC,10,44,22,8
LTEXT "Write bytes",IDC_STATIC,10,55,38,8
LTEXT "Write bytes delta",IDC_STATIC,10,66,57,8
RTEXT "Static",IDC_ZREADS_V,57,11,54,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_ZREADBYTES_V,73,22,38,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_ZREADBYTESDELTA_V,73,33,38,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_ZWRITES_V,57,44,54,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_ZWRITEBYTES_V,73,55,38,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_ZWRITEBYTESDELTA_V,73,66,38,8,SS_ENDELLIPSIS
GROUPBOX "Network I/O",IDC_STATIC,123,0,124,82
LTEXT "Receives",IDC_STATIC,132,11,30,8
LTEXT "Receive bytes",IDC_STATIC,132,23,46,8
LTEXT "Receive bytes delta",IDC_STATIC,132,34,65,8
LTEXT "Sends",IDC_STATIC,132,46,20,8
LTEXT "Send bytes",IDC_STATIC,132,56,37,8
LTEXT "Send bytes delta",IDC_STATIC,132,67,56,8
RTEXT "Static",IDC_ZRECEIVES_V,184,11,54,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_ZRECEIVEBYTES_V,200,23,38,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_ZRECEIVEBYTESDELTA_V,200,34,38,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_ZSENDS_V,184,46,54,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_ZSENDBYTES_V,200,56,38,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_ZSENDBYTESDELTA_V,200,67,38,8,SS_ENDELLIPSIS
END
IDD_PROCGPU_DETAILS DIALOGEX 0, 0, 181, 155
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "GPU Details"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "Close",IDCANCEL,124,134,50,14
GROUPBOX "System memory",IDC_STATIC,7,7,167,125
LTEXT "Dedicated",IDC_STATIC,15,19,33,8
LTEXT "Shared",IDC_STATIC,15,30,24,8
RTEXT "Static",IDC_ZDEDICATEDCOMMITTED_V,111,19,54,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_ZSHAREDCOMMITTED_V,127,30,38,8,SS_ENDELLIPSIS
LTEXT "Total allocated",IDC_STATIC,15,41,48,8
LTEXT "Total reserved",IDC_STATIC,15,51,50,8
LTEXT "Write combined allocated",IDC_STATIC,15,62,83,8
LTEXT "Write combined reserved",IDC_STATIC,15,73,84,8
RTEXT "Static",IDC_ZTOTALALLOCATED_V,111,41,54,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_ZTOTALRESERVED_V,111,51,54,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_ZWRITECOMBINEDALLOCATED_V,111,62,54,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_ZWRITECOMBINEDRESERVED_V,111,73,54,8,SS_ENDELLIPSIS
LTEXT "Cached allocated",IDC_STATIC,15,84,56,8
LTEXT "Cached reserved",IDC_STATIC,15,95,58,8
LTEXT "Section allocated",IDC_STATIC,15,106,56,8
LTEXT "Section reserved",IDC_STATIC,15,117,57,8
RTEXT "Static",IDC_ZCACHEDALLOCATED_V,111,84,54,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_ZCACHEDRESERVED_V,111,95,54,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_ZSECTIONALLOCATED_V,111,106,54,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_ZSECTIONRESERVED_V,111,117,54,8,SS_ENDELLIPSIS
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_UNLOADEDDLLS, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 335
TOPMARGIN, 7
BOTTOMMARGIN, 258
END
IDD_OBJALPCPORT, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 153
TOPMARGIN, 7
BOTTOMMARGIN, 94
END
IDD_OBJTPWORKERFACTORY, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 179
TOPMARGIN, 7
BOTTOMMARGIN, 94
END
IDD_MODSERVICES, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 269
TOPMARGIN, 7
BOTTOMMARGIN, 202
END
IDD_PROCDISKNET, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 258
TOPMARGIN, 7
BOTTOMMARGIN, 151
END
IDD_SYSINFO_DISKPANEL, DIALOG
BEGIN
END
IDD_OPTIONS, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 208
TOPMARGIN, 7
BOTTOMMARGIN, 70
END
IDD_WSWATCH, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 318
TOPMARGIN, 7
BOTTOMMARGIN, 259
END
IDD_SYSINFO_GPU, DIALOG
BEGIN
END
IDD_SYSINFO_GPUPANEL, DIALOG
BEGIN
END
IDD_PROCGPU, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 362
TOPMARGIN, 7
BOTTOMMARGIN, 230
END
IDD_SYSINFO_DISK, DIALOG
BEGIN
END
IDD_SYSINFO_NETPANEL, DIALOG
BEGIN
END
IDD_SYSINFO_NET, DIALOG
BEGIN
END
IDD_GPUNODES, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 310
TOPMARGIN, 7
BOTTOMMARGIN, 176
END
IDD_PROCGPU_PANEL, DIALOG
BEGIN
END
IDD_DISKTABERROR, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 302
TOPMARGIN, 7
BOTTOMMARGIN, 169
END
IDD_PROCDISKNET_PANEL, DIALOG
BEGIN
END
IDD_PROCGPU_DETAILS, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 174
TOPMARGIN, 7
BOTTOMMARGIN, 148
END
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Menu
//
IDR_DISK MENU
BEGIN
POPUP "Disk"
BEGIN
MENUITEM "&Go to process", ID_DISK_GOTOPROCESS
MENUITEM SEPARATOR
MENUITEM "Open &file location\aEnter", ID_DISK_OPENFILELOCATION
MENUITEM "P&roperties", ID_DISK_PROPERTIES
MENUITEM "&Copy\aCtrl+C", ID_DISK_COPY
END
END
/////////////////////////////////////////////////////////////////////////////
//
// AFX_DIALOG_LAYOUT
//
IDD_OBJTPWORKERFACTORY AFX_DIALOG_LAYOUT
BEGIN
0
END
IDD_PROCGPU_DETAILS AFX_DIALOG_LAYOUT
BEGIN
0
END
IDD_PROCGPU_PANEL AFX_DIALOG_LAYOUT
BEGIN
0
END
#endif // English (Australia) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@@ -0,0 +1,134 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{3437FD16-A3BF-4938-883A-EB0DF1584A2A}</ProjectGuid>
<RootNamespace>ExtendedTools</RootNamespace>
<Keyword>Win32Proj</Keyword>
<ProjectName>ExtendedTools</ProjectName>
<WindowsTargetPlatformVersion>10.0.10586.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\Plugins.props" />
</ImportGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LibraryPath>$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86;C:\Users\AirDog46\Downloads\processhacker-2.39-src\bin\Debug32</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;C:\Users\AirDog46\Downloads\processhacker-2.39-src\bin\Release64</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LibraryPath>$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;C:\Users\AirDog46\Downloads\processhacker-2.39-src\bin\Release32</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;C:\Users\AirDog46\Downloads\processhacker-2.39-src\bin\Debug64</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Link>
<AdditionalDependencies>cfgmgr32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>cfgmgr32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Link>
<AdditionalDependencies>cfgmgr32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>cfgmgr32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Link>
<AdditionalDependencies>cfgmgr32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>cfgmgr32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Link>
<AdditionalDependencies>cfgmgr32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>cfgmgr32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="disktab.c" />
<ClCompile Include="etwdisk.c" />
<ClCompile Include="etwmini.c" />
<ClCompile Include="etwmon.c" />
<ClCompile Include="gpumini.c" />
<ClCompile Include="gpumon.c" />
<ClCompile Include="gpunodes.c" />
<ClCompile Include="gpuprprp.c" />
<ClCompile Include="gpusys.c" />
<ClCompile Include="iconext.c" />
<ClCompile Include="procicon.c" />
<ClCompile Include="treeext.c" />
<ClCompile Include="etwstat.c" />
<ClCompile Include="etwprprp.c" />
<ClCompile Include="etwsys.c" />
<ClCompile Include="main.c" />
<ClCompile Include="modsrv.c" />
<ClCompile Include="objprp.c" />
<ClCompile Include="options.c" />
<ClCompile Include="thrdact.c" />
<ClCompile Include="unldll.c" />
<ClCompile Include="utils.c" />
<ClCompile Include="wswatch.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="d3dkmt.h" />
<ClInclude Include="disktabp.h" />
<ClInclude Include="etwmini.h" />
<ClInclude Include="etwmon.h" />
<ClInclude Include="etwsys.h" />
<ClInclude Include="exttools.h" />
<ClInclude Include="gpumini.h" />
<ClInclude Include="gpumon.h" />
<ClInclude Include="gpusys.h" />
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<None Include="CHANGELOG.txt" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="ExtendedTools.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

View File

@@ -0,0 +1,128 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="objprp.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="thrdact.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="unldll.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="modsrv.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="etwmon.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="etwstat.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="etwprprp.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="etwsys.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="options.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="wswatch.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="treeext.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="etwdisk.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="disktab.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="procicon.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="gpumon.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="gpusys.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="gpuprprp.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="utils.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="iconext.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="gpunodes.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="etwmini.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="gpumini.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="exttools.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="etwmon.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="disktabp.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="d3dkmt.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="gpumon.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="gpusys.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="etwsys.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="etwmini.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="gpumini.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="CHANGELOG.txt" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="ExtendedTools.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,482 @@
#ifndef _D3DKMT_H
#define _D3DKMT_H
// D3D definitions
typedef ULONG D3DKMT_HANDLE;
typedef struct _D3DKMT_OPENADAPTERFROMDEVICENAME
{
_In_ PCWSTR pDeviceName;
_Out_ D3DKMT_HANDLE hAdapter;
_Out_ LUID AdapterLuid;
} D3DKMT_OPENADAPTERFROMDEVICENAME;
typedef struct _D3DKMT_CLOSEADAPTER
{
_In_ D3DKMT_HANDLE hAdapter;
} D3DKMT_CLOSEADAPTER;
typedef enum _D3DKMT_QUERYRESULT_PREEMPTION_ATTEMPT_RESULT
{
D3DKMT_PreemptionAttempt = 0,
D3DKMT_PreemptionAttemptSuccess = 1,
D3DKMT_PreemptionAttemptMissNoCommand = 2,
D3DKMT_PreemptionAttemptMissNotEnabled = 3,
D3DKMT_PreemptionAttemptMissNextFence = 4,
D3DKMT_PreemptionAttemptMissPagingCommand = 5,
D3DKMT_PreemptionAttemptMissSplittedCommand = 6,
D3DKMT_PreemptionAttemptMissFenceCommand= 7,
D3DKMT_PreemptionAttemptMissRenderPendingFlip = 8,
D3DKMT_PreemptionAttemptMissNotMakingProgress = 9,
D3DKMT_PreemptionAttemptMissLessPriority = 10,
D3DKMT_PreemptionAttemptMissRemainingQuantum = 11,
D3DKMT_PreemptionAttemptMissRemainingPreemptionQuantum = 12,
D3DKMT_PreemptionAttemptMissAlreadyPreempting = 13,
D3DKMT_PreemptionAttemptMissGlobalBlock = 14,
D3DKMT_PreemptionAttemptMissAlreadyRunning = 15,
D3DKMT_PreemptionAttemptStatisticsMax
} D3DKMT_QUERYRESULT_PREEMPTION_ATTEMPT_RESULT;
typedef enum _D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE
{
D3DKMT_ClientRenderBuffer = 0,
D3DKMT_ClientPagingBuffer = 1,
D3DKMT_SystemPagingBuffer = 2,
D3DKMT_SystemPreemptionBuffer = 3,
D3DKMT_DmaPacketTypeMax
} D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE;
typedef enum _D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE
{
D3DKMT_RenderCommandBuffer = 0,
D3DKMT_DeferredCommandBuffer = 1,
D3DKMT_SystemCommandBuffer = 2,
D3DKMT_MmIoFlipCommandBuffer = 3,
D3DKMT_WaitCommandBuffer = 4,
D3DKMT_SignalCommandBuffer = 5,
D3DKMT_DeviceCommandBuffer = 6,
D3DKMT_SoftwareCommandBuffer = 7,
D3DKMT_QueuePacketTypeMax
} D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE;
typedef enum _D3DKMT_QUERYSTATISTICS_ALLOCATION_PRIORITY_CLASS
{
D3DKMT_AllocationPriorityClassMinimum = 0,
D3DKMT_AllocationPriorityClassLow = 1,
D3DKMT_AllocationPriorityClassNormal = 2,
D3DKMT_AllocationPriorityClassHigh = 3,
D3DKMT_AllocationPriorityClassMaximum = 4,
D3DKMT_MaxAllocationPriorityClass
} D3DKMT_QUERYSTATISTICS_ALLOCATION_PRIORITY_CLASS;
#define D3DKMT_QUERYSTATISTICS_SEGMENT_PREFERENCE_MAX 5
typedef struct _D3DKMT_QUERYSTATISTICS_COUNTER
{
ULONG Count;
ULONGLONG Bytes;
} D3DKMT_QUERYSTATISTICS_COUNTER;
typedef struct _D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE_INFORMATION
{
ULONG PacketSubmited;
ULONG PacketCompleted;
ULONG PacketPreempted;
ULONG PacketFaulted;
} D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE_INFORMATION;
typedef struct _D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION
{
ULONG PacketSubmited;
ULONG PacketCompleted;
} D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION;
typedef struct _D3DKMT_QUERYSTATISTICS_PACKET_INFORMATION
{
D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION QueuePacket[D3DKMT_QueuePacketTypeMax];
D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE_INFORMATION DmaPacket[D3DKMT_DmaPacketTypeMax];
} D3DKMT_QUERYSTATISTICS_PACKET_INFORMATION;
typedef struct _D3DKMT_QUERYSTATISTICS_PREEMPTION_INFORMATION
{
ULONG PreemptionCounter[D3DKMT_PreemptionAttemptStatisticsMax];
} D3DKMT_QUERYSTATISTICS_PREEMPTION_INFORMATION;
typedef struct _D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION
{
LARGE_INTEGER RunningTime; // 100ns
ULONG ContextSwitch;
D3DKMT_QUERYSTATISTICS_PREEMPTION_INFORMATION PreemptionStatistics;
D3DKMT_QUERYSTATISTICS_PACKET_INFORMATION PacketStatistics;
ULONG64 Reserved[8];
} D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION;
typedef struct _D3DKMT_QUERYSTATISTICS_NODE_INFORMATION
{
D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION GlobalInformation; // global
D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION SystemInformation; // system thread
ULONG64 Reserved[8];
} D3DKMT_QUERYSTATISTICS_NODE_INFORMATION;
typedef struct _D3DKMT_QUERYSTATISTICS_PROCESS_VIDPNSOURCE_INFORMATION
{
ULONG Frame;
ULONG CancelledFrame;
ULONG QueuedPresent;
ULONG64 Reserved[8];
} D3DKMT_QUERYSTATISTICS_PROCESS_VIDPNSOURCE_INFORMATION;
typedef struct _D3DKMT_QUERYSTATISTICS_VIDPNSOURCE_INFORMATION
{
D3DKMT_QUERYSTATISTICS_PROCESS_VIDPNSOURCE_INFORMATION GlobalInformation; // global
D3DKMT_QUERYSTATISTICS_PROCESS_VIDPNSOURCE_INFORMATION SystemInformation; // system thread
ULONG64 Reserved[8];
} D3DKMT_QUERYSTATISTICS_VIDPNSOURCE_INFORMATION;
typedef struct _D3DKMT_QUERYSTATSTICS_REFERENCE_DMA_BUFFER
{
ULONG NbCall;
ULONG NbAllocationsReferenced;
ULONG MaxNbAllocationsReferenced;
ULONG NbNULLReference;
ULONG NbWriteReference;
ULONG NbRenamedAllocationsReferenced;
ULONG NbIterationSearchingRenamedAllocation;
ULONG NbLockedAllocationReferenced;
ULONG NbAllocationWithValidPrepatchingInfoReferenced;
ULONG NbAllocationWithInvalidPrepatchingInfoReferenced;
ULONG NbDMABufferSuccessfullyPrePatched;
ULONG NbPrimariesReferencesOverflow;
ULONG NbAllocationWithNonPreferredResources;
ULONG NbAllocationInsertedInMigrationTable;
} D3DKMT_QUERYSTATSTICS_REFERENCE_DMA_BUFFER;
typedef struct _D3DKMT_QUERYSTATSTICS_RENAMING
{
ULONG NbAllocationsRenamed;
ULONG NbAllocationsShrinked;
ULONG NbRenamedBuffer;
ULONG MaxRenamingListLength;
ULONG NbFailuresDueToRenamingLimit;
ULONG NbFailuresDueToCreateAllocation;
ULONG NbFailuresDueToOpenAllocation;
ULONG NbFailuresDueToLowResource;
ULONG NbFailuresDueToNonRetiredLimit;
} D3DKMT_QUERYSTATSTICS_RENAMING;
typedef struct _D3DKMT_QUERYSTATSTICS_PREPRATION
{
ULONG BroadcastStall;
ULONG NbDMAPrepared;
ULONG NbDMAPreparedLongPath;
ULONG ImmediateHighestPreparationPass;
D3DKMT_QUERYSTATISTICS_COUNTER AllocationsTrimmed;
} D3DKMT_QUERYSTATSTICS_PREPRATION;
typedef struct _D3DKMT_QUERYSTATSTICS_PAGING_FAULT
{
D3DKMT_QUERYSTATISTICS_COUNTER Faults;
D3DKMT_QUERYSTATISTICS_COUNTER FaultsFirstTimeAccess;
D3DKMT_QUERYSTATISTICS_COUNTER FaultsReclaimed;
D3DKMT_QUERYSTATISTICS_COUNTER FaultsMigration;
D3DKMT_QUERYSTATISTICS_COUNTER FaultsIncorrectResource;
D3DKMT_QUERYSTATISTICS_COUNTER FaultsLostContent;
D3DKMT_QUERYSTATISTICS_COUNTER FaultsEvicted;
D3DKMT_QUERYSTATISTICS_COUNTER AllocationsMEM_RESET;
D3DKMT_QUERYSTATISTICS_COUNTER AllocationsUnresetSuccess;
D3DKMT_QUERYSTATISTICS_COUNTER AllocationsUnresetFail;
ULONG AllocationsUnresetSuccessRead;
ULONG AllocationsUnresetFailRead;
D3DKMT_QUERYSTATISTICS_COUNTER Evictions;
D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToPreparation;
D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToLock;
D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToClose;
D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToPurge;
D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToSuspendCPUAccess;
} D3DKMT_QUERYSTATSTICS_PAGING_FAULT;
typedef struct _D3DKMT_QUERYSTATSTICS_PAGING_TRANSFER
{
ULONGLONG BytesFilled;
ULONGLONG BytesDiscarded;
ULONGLONG BytesMappedIntoAperture;
ULONGLONG BytesUnmappedFromAperture;
ULONGLONG BytesTransferredFromMdlToMemory;
ULONGLONG BytesTransferredFromMemoryToMdl;
ULONGLONG BytesTransferredFromApertureToMemory;
ULONGLONG BytesTransferredFromMemoryToAperture;
} D3DKMT_QUERYSTATSTICS_PAGING_TRANSFER;
typedef struct _D3DKMT_QUERYSTATSTICS_SWIZZLING_RANGE
{
ULONG NbRangesAcquired;
ULONG NbRangesReleased;
} D3DKMT_QUERYSTATSTICS_SWIZZLING_RANGE;
typedef struct _D3DKMT_QUERYSTATSTICS_LOCKS
{
ULONG NbLocks;
ULONG NbLocksWaitFlag;
ULONG NbLocksDiscardFlag;
ULONG NbLocksNoOverwrite;
ULONG NbLocksNoReadSync;
ULONG NbLocksLinearization;
ULONG NbComplexLocks;
} D3DKMT_QUERYSTATSTICS_LOCKS;
typedef struct _D3DKMT_QUERYSTATSTICS_ALLOCATIONS
{
D3DKMT_QUERYSTATISTICS_COUNTER Created;
D3DKMT_QUERYSTATISTICS_COUNTER Destroyed;
D3DKMT_QUERYSTATISTICS_COUNTER Opened;
D3DKMT_QUERYSTATISTICS_COUNTER Closed;
D3DKMT_QUERYSTATISTICS_COUNTER MigratedSuccess;
D3DKMT_QUERYSTATISTICS_COUNTER MigratedFail;
D3DKMT_QUERYSTATISTICS_COUNTER MigratedAbandoned;
} D3DKMT_QUERYSTATSTICS_ALLOCATIONS;
typedef struct _D3DKMT_QUERYSTATSTICS_TERMINATIONS
{
D3DKMT_QUERYSTATISTICS_COUNTER TerminatedShared;
D3DKMT_QUERYSTATISTICS_COUNTER TerminatedNonShared;
D3DKMT_QUERYSTATISTICS_COUNTER DestroyedShared;
D3DKMT_QUERYSTATISTICS_COUNTER DestroyedNonShared;
} D3DKMT_QUERYSTATSTICS_TERMINATIONS;
typedef struct _D3DKMT_QUERYSTATISTICS_ADAPTER_INFORMATION
{
ULONG NbSegments;
ULONG NodeCount;
ULONG VidPnSourceCount;
ULONG VSyncEnabled;
ULONG TdrDetectedCount;
LONGLONG ZeroLengthDmaBuffers;
ULONGLONG RestartedPeriod;
D3DKMT_QUERYSTATSTICS_REFERENCE_DMA_BUFFER ReferenceDmaBuffer;
D3DKMT_QUERYSTATSTICS_RENAMING Renaming;
D3DKMT_QUERYSTATSTICS_PREPRATION Preparation;
D3DKMT_QUERYSTATSTICS_PAGING_FAULT PagingFault;
D3DKMT_QUERYSTATSTICS_PAGING_TRANSFER PagingTransfer;
D3DKMT_QUERYSTATSTICS_SWIZZLING_RANGE SwizzlingRange;
D3DKMT_QUERYSTATSTICS_LOCKS Locks;
D3DKMT_QUERYSTATSTICS_ALLOCATIONS Allocations;
D3DKMT_QUERYSTATSTICS_TERMINATIONS Terminations;
ULONG64 Reserved[8];
} D3DKMT_QUERYSTATISTICS_ADAPTER_INFORMATION;
typedef struct _D3DKMT_QUERYSTATISTICS_SYSTEM_MEMORY
{
ULONGLONG BytesAllocated;
ULONGLONG BytesReserved;
ULONG SmallAllocationBlocks;
ULONG LargeAllocationBlocks;
ULONGLONG WriteCombinedBytesAllocated;
ULONGLONG WriteCombinedBytesReserved;
ULONGLONG CachedBytesAllocated;
ULONGLONG CachedBytesReserved;
ULONGLONG SectionBytesAllocated;
ULONGLONG SectionBytesReserved;
} D3DKMT_QUERYSTATISTICS_SYSTEM_MEMORY;
typedef struct _D3DKMT_QUERYSTATISTICS_PROCESS_INFORMATION
{
ULONG NodeCount;
ULONG VidPnSourceCount;
D3DKMT_QUERYSTATISTICS_SYSTEM_MEMORY SystemMemory;
ULONG64 Reserved[8];
} D3DKMT_QUERYSTATISTICS_PROCESS_INFORMATION;
typedef struct _D3DKMT_QUERYSTATISTICS_DMA_BUFFER
{
D3DKMT_QUERYSTATISTICS_COUNTER Size;
ULONG AllocationListBytes;
ULONG PatchLocationListBytes;
} D3DKMT_QUERYSTATISTICS_DMA_BUFFER;
typedef struct _D3DKMT_QUERYSTATISTICS_COMMITMENT_DATA
{
ULONG64 TotalBytesEvictedFromProcess;
ULONG64 BytesBySegmentPreference[D3DKMT_QUERYSTATISTICS_SEGMENT_PREFERENCE_MAX];
} D3DKMT_QUERYSTATISTICS_COMMITMENT_DATA;
typedef struct _D3DKMT_QUERYSTATISTICS_POLICY
{
ULONGLONG PreferApertureForRead[D3DKMT_MaxAllocationPriorityClass];
ULONGLONG PreferAperture[D3DKMT_MaxAllocationPriorityClass];
ULONGLONG MemResetOnPaging;
ULONGLONG RemovePagesFromWorkingSetOnPaging;
ULONGLONG MigrationEnabled;
} D3DKMT_QUERYSTATISTICS_POLICY;
typedef struct _D3DKMT_QUERYSTATISTICS_PROCESS_ADAPTER_INFORMATION
{
ULONG NbSegments;
ULONG NodeCount;
ULONG VidPnSourceCount;
ULONG VirtualMemoryUsage;
D3DKMT_QUERYSTATISTICS_DMA_BUFFER DmaBuffer;
D3DKMT_QUERYSTATISTICS_COMMITMENT_DATA CommitmentData;
D3DKMT_QUERYSTATISTICS_POLICY _Policy;
ULONG64 Reserved[8];
} D3DKMT_QUERYSTATISTICS_PROCESS_ADAPTER_INFORMATION;
typedef struct _D3DKMT_QUERYSTATISTICS_MEMORY
{
ULONGLONG TotalBytesEvicted;
ULONG AllocsCommitted;
ULONG AllocsResident;
} D3DKMT_QUERYSTATISTICS_MEMORY;
typedef struct _D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION_V1
{
ULONG CommitLimit;
ULONG BytesCommitted;
ULONG BytesResident;
D3DKMT_QUERYSTATISTICS_MEMORY Memory;
ULONG Aperture; // boolean
ULONGLONG TotalBytesEvictedByPriority[D3DKMT_MaxAllocationPriorityClass];
ULONG64 SystemMemoryEndAddress;
struct
{
ULONG64 PreservedDuringStandby : 1;
ULONG64 PreservedDuringHibernate : 1;
ULONG64 PartiallyPreservedDuringHibernate : 1;
ULONG64 Reserved : 61;
} PowerFlags;
ULONG64 Reserved[7];
} D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION_V1;
typedef struct _D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION
{
ULONGLONG CommitLimit;
ULONGLONG BytesCommitted;
ULONGLONG BytesResident;
D3DKMT_QUERYSTATISTICS_MEMORY Memory;
ULONG Aperture; // boolean
ULONGLONG TotalBytesEvictedByPriority[D3DKMT_MaxAllocationPriorityClass];
ULONG64 SystemMemoryEndAddress;
struct
{
ULONG64 PreservedDuringStandby : 1;
ULONG64 PreservedDuringHibernate : 1;
ULONG64 PartiallyPreservedDuringHibernate : 1;
ULONG64 Reserved : 61;
} PowerFlags;
ULONG64 Reserved[6];
} D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION;
typedef struct _D3DKMT_QUERYSTATISTICS_VIDEO_MEMORY
{
ULONG AllocsCommitted;
D3DKMT_QUERYSTATISTICS_COUNTER AllocsResidentInP[D3DKMT_QUERYSTATISTICS_SEGMENT_PREFERENCE_MAX];
D3DKMT_QUERYSTATISTICS_COUNTER AllocsResidentInNonPreferred;
ULONGLONG TotalBytesEvictedDueToPreparation;
} D3DKMT_QUERYSTATISTICS_VIDEO_MEMORY;
typedef struct _D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_POLICY
{
ULONGLONG UseMRU;
} D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_POLICY;
typedef struct _D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_INFORMATION
{
ULONGLONG BytesCommitted;
ULONGLONG MaximumWorkingSet;
ULONGLONG MinimumWorkingSet;
ULONG NbReferencedAllocationEvictedInPeriod;
D3DKMT_QUERYSTATISTICS_VIDEO_MEMORY VideoMemory;
D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_POLICY _Policy;
ULONG64 Reserved[8];
} D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_INFORMATION;
typedef enum _D3DKMT_QUERYSTATISTICS_TYPE
{
D3DKMT_QUERYSTATISTICS_ADAPTER = 0,
D3DKMT_QUERYSTATISTICS_PROCESS = 1,
D3DKMT_QUERYSTATISTICS_PROCESS_ADAPTER = 2,
D3DKMT_QUERYSTATISTICS_SEGMENT = 3,
D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT = 4,
D3DKMT_QUERYSTATISTICS_NODE = 5,
D3DKMT_QUERYSTATISTICS_PROCESS_NODE = 6,
D3DKMT_QUERYSTATISTICS_VIDPNSOURCE = 7,
D3DKMT_QUERYSTATISTICS_PROCESS_VIDPNSOURCE = 8
} D3DKMT_QUERYSTATISTICS_TYPE;
typedef struct _D3DKMT_QUERYSTATISTICS_QUERY_SEGMENT
{
ULONG SegmentId;
} D3DKMT_QUERYSTATISTICS_QUERY_SEGMENT;
typedef struct _D3DKMT_QUERYSTATISTICS_QUERY_NODE
{
ULONG NodeId;
} D3DKMT_QUERYSTATISTICS_QUERY_NODE;
typedef struct _D3DKMT_QUERYSTATISTICS_QUERY_VIDPNSOURCE
{
ULONG VidPnSourceId;
} D3DKMT_QUERYSTATISTICS_QUERY_VIDPNSOURCE;
typedef union _D3DKMT_QUERYSTATISTICS_RESULT
{
D3DKMT_QUERYSTATISTICS_ADAPTER_INFORMATION AdapterInformation;
D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION_V1 SegmentInformationV1; // WIN7
D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION SegmentInformation; // WIN8
D3DKMT_QUERYSTATISTICS_NODE_INFORMATION NodeInformation;
D3DKMT_QUERYSTATISTICS_VIDPNSOURCE_INFORMATION VidPnSourceInformation;
D3DKMT_QUERYSTATISTICS_PROCESS_INFORMATION ProcessInformation;
D3DKMT_QUERYSTATISTICS_PROCESS_ADAPTER_INFORMATION ProcessAdapterInformation;
D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_INFORMATION ProcessSegmentInformation;
D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION ProcessNodeInformation;
D3DKMT_QUERYSTATISTICS_PROCESS_VIDPNSOURCE_INFORMATION ProcessVidPnSourceInformation;
} D3DKMT_QUERYSTATISTICS_RESULT;
typedef struct _D3DKMT_QUERYSTATISTICS
{
_In_ D3DKMT_QUERYSTATISTICS_TYPE Type;
_In_ LUID AdapterLuid;
_In_opt_ HANDLE hProcess;
_Out_ D3DKMT_QUERYSTATISTICS_RESULT QueryResult;
union
{
_In_ D3DKMT_QUERYSTATISTICS_QUERY_SEGMENT QuerySegment;
_In_ D3DKMT_QUERYSTATISTICS_QUERY_SEGMENT QueryProcessSegment;
_In_ D3DKMT_QUERYSTATISTICS_QUERY_NODE QueryNode;
_In_ D3DKMT_QUERYSTATISTICS_QUERY_NODE QueryProcessNode;
_In_ D3DKMT_QUERYSTATISTICS_QUERY_VIDPNSOURCE QueryVidPnSource;
_In_ D3DKMT_QUERYSTATISTICS_QUERY_VIDPNSOURCE QueryProcessVidPnSource;
};
} D3DKMT_QUERYSTATISTICS;
// Function pointers
typedef _Check_return_ NTSTATUS (APIENTRY *PFND3DKMT_OPENADAPTERFROMDEVICENAME)(_Inout_ D3DKMT_OPENADAPTERFROMDEVICENAME *);
typedef _Check_return_ NTSTATUS (APIENTRY *PFND3DKMT_CLOSEADAPTER)(_In_ const D3DKMT_CLOSEADAPTER *);
typedef _Check_return_ NTSTATUS (APIENTRY *PFND3DKMT_QUERYSTATISTICS)(_In_ const D3DKMT_QUERYSTATISTICS *);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,171 @@
#ifndef DISKTABP_H
#define DISKTABP_H
HWND NTAPI EtpDiskTabCreateFunction(
_In_ PVOID Context
);
VOID NTAPI EtpDiskTabSelectionChangedCallback(
_In_ PVOID Parameter1,
_In_ PVOID Parameter2,
_In_ PVOID Parameter3,
_In_ PVOID Context
);
VOID NTAPI EtpDiskTabSaveContentCallback(
_In_ PVOID Parameter1,
_In_ PVOID Parameter2,
_In_ PVOID Parameter3,
_In_ PVOID Context
);
VOID NTAPI EtpDiskTabFontChangedCallback(
_In_ PVOID Parameter1,
_In_ PVOID Parameter2,
_In_ PVOID Parameter3,
_In_ PVOID Context
);
BOOLEAN EtpDiskNodeHashtableEqualFunction(
_In_ PVOID Entry1,
_In_ PVOID Entry2
);
ULONG EtpDiskNodeHashtableHashFunction(
_In_ PVOID Entry
);
VOID EtInitializeDiskTreeList(
_In_ HWND hwnd
);
PET_DISK_NODE EtAddDiskNode(
_In_ PET_DISK_ITEM DiskItem
);
PET_DISK_NODE EtFindDiskNode(
_In_ PET_DISK_ITEM DiskItem
);
VOID EtRemoveDiskNode(
_In_ PET_DISK_NODE DiskNode
);
VOID EtUpdateDiskNode(
_In_ PET_DISK_NODE DiskNode
);
BOOLEAN NTAPI EtpDiskTreeNewCallback(
_In_ HWND hwnd,
_In_ PH_TREENEW_MESSAGE Message,
_In_opt_ PVOID Parameter1,
_In_opt_ PVOID Parameter2,
_In_opt_ PVOID Context
);
PPH_STRING EtpGetDiskItemProcessName(
_In_ PET_DISK_ITEM DiskItem
);
PET_DISK_ITEM EtGetSelectedDiskItem(
VOID
);
VOID EtGetSelectedDiskItems(
_Out_ PET_DISK_ITEM **DiskItems,
_Out_ PULONG NumberOfDiskItems
);
VOID EtDeselectAllDiskNodes(
VOID
);
VOID EtSelectAndEnsureVisibleDiskNode(
_In_ PET_DISK_NODE DiskNode
);
VOID EtCopyDiskList(
VOID
);
VOID EtWriteDiskList(
_Inout_ PPH_FILE_STREAM FileStream,
_In_ ULONG Mode
);
VOID EtHandleDiskCommand(
_In_ ULONG Id
);
VOID EtpInitializeDiskMenu(
_In_ PPH_EMENU Menu,
_In_ PET_DISK_ITEM *DiskItems,
_In_ ULONG NumberOfDiskItems
);
VOID EtShowDiskContextMenu(
_In_ POINT Location
);
VOID NTAPI EtpDiskItemAddedHandler(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
);
VOID NTAPI EtpDiskItemModifiedHandler(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
);
VOID NTAPI EtpDiskItemRemovedHandler(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
);
VOID NTAPI EtpDiskItemsUpdatedHandler(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
);
VOID NTAPI EtpOnDiskItemAdded(
_In_ PVOID Parameter
);
VOID NTAPI EtpOnDiskItemModified(
_In_ PVOID Parameter
);
VOID NTAPI EtpOnDiskItemRemoved(
_In_ PVOID Parameter
);
VOID NTAPI EtpOnDiskItemsUpdated(
_In_ PVOID Parameter
);
VOID NTAPI EtpSearchChangedHandler(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
);
BOOLEAN NTAPI EtpSearchDiskListFilterCallback(
_In_ PPH_TREENEW_NODE Node,
_In_opt_ PVOID Context
);
VOID NTAPI EtpToolStatusActivateContent(
_In_ BOOLEAN Select
);
HWND NTAPI EtpToolStatusGetTreeNewHandle(
VOID
);
INT_PTR CALLBACK EtpDiskTabErrorDialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
#endif

View File

@@ -0,0 +1,536 @@
/*
* Process Hacker Extended Tools -
* ETW disk monitoring
*
* Copyright (C) 2011 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 "exttools.h"
#include "etwmon.h"
typedef struct _ETP_DISK_PACKET
{
SLIST_ENTRY ListEntry;
ET_ETW_DISK_EVENT Event;
PPH_STRING FileName;
} ETP_DISK_PACKET, *PETP_DISK_PACKET;
VOID NTAPI EtpDiskItemDeleteProcedure(
_In_ PVOID Object,
_In_ ULONG Flags
);
BOOLEAN NTAPI EtpDiskHashtableEqualFunction(
_In_ PVOID Entry1,
_In_ PVOID Entry2
);
ULONG NTAPI EtpDiskHashtableHashFunction(
_In_ PVOID Entry
);
VOID NTAPI EtpDiskProcessesUpdatedCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
);
BOOLEAN EtDiskEnabled = FALSE;
PPH_OBJECT_TYPE EtDiskItemType;
PPH_HASHTABLE EtDiskHashtable;
PH_QUEUED_LOCK EtDiskHashtableLock = PH_QUEUED_LOCK_INIT;
LIST_ENTRY EtDiskAgeListHead;
PH_CALLBACK_DECLARE(EtDiskItemAddedEvent);
PH_CALLBACK_DECLARE(EtDiskItemModifiedEvent);
PH_CALLBACK_DECLARE(EtDiskItemRemovedEvent);
PH_CALLBACK_DECLARE(EtDiskItemsUpdatedEvent);
PH_FREE_LIST EtDiskPacketFreeList;
SLIST_HEADER EtDiskPacketListHead;
PPH_HASHTABLE EtFileNameHashtable;
PH_QUEUED_LOCK EtFileNameHashtableLock = PH_QUEUED_LOCK_INIT;
static LARGE_INTEGER EtpPerformanceFrequency;
static PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration;
VOID EtInitializeDiskInformation(
VOID
)
{
LARGE_INTEGER performanceCounter;
EtDiskItemType = PhCreateObjectType(L"DiskItem", 0, EtpDiskItemDeleteProcedure);
EtDiskHashtable = PhCreateHashtable(
sizeof(PET_DISK_ITEM),
EtpDiskHashtableEqualFunction,
EtpDiskHashtableHashFunction,
128
);
InitializeListHead(&EtDiskAgeListHead);
PhInitializeFreeList(&EtDiskPacketFreeList, sizeof(ETP_DISK_PACKET), 64);
RtlInitializeSListHead(&EtDiskPacketListHead);
EtFileNameHashtable = PhCreateSimpleHashtable(128);
NtQueryPerformanceCounter(&performanceCounter, &EtpPerformanceFrequency);
EtDiskEnabled = TRUE;
// Collect all existing file names.
EtStartEtwRundown();
PhRegisterCallback(
&PhProcessesUpdatedEvent,
EtpDiskProcessesUpdatedCallback,
NULL,
&ProcessesUpdatedCallbackRegistration
);
}
PET_DISK_ITEM EtCreateDiskItem(
VOID
)
{
PET_DISK_ITEM diskItem;
diskItem = PhCreateObject(sizeof(ET_DISK_ITEM), EtDiskItemType);
memset(diskItem, 0, sizeof(ET_DISK_ITEM));
return diskItem;
}
VOID NTAPI EtpDiskItemDeleteProcedure(
_In_ PVOID Object,
_In_ ULONG Flags
)
{
PET_DISK_ITEM diskItem = Object;
if (diskItem->FileName) PhDereferenceObject(diskItem->FileName);
if (diskItem->FileNameWin32) PhDereferenceObject(diskItem->FileNameWin32);
if (diskItem->ProcessName) PhDereferenceObject(diskItem->ProcessName);
if (diskItem->ProcessIcon) EtProcIconDereferenceProcessIcon(diskItem->ProcessIcon);
if (diskItem->ProcessRecord) PhDereferenceProcessRecord(diskItem->ProcessRecord);
}
BOOLEAN NTAPI EtpDiskHashtableEqualFunction(
_In_ PVOID Entry1,
_In_ PVOID Entry2
)
{
PET_DISK_ITEM diskItem1 = *(PET_DISK_ITEM *)Entry1;
PET_DISK_ITEM diskItem2 = *(PET_DISK_ITEM *)Entry2;
return diskItem1->ProcessId == diskItem2->ProcessId && PhEqualString(diskItem1->FileName, diskItem2->FileName, TRUE);
}
ULONG NTAPI EtpDiskHashtableHashFunction(
_In_ PVOID Entry
)
{
PET_DISK_ITEM diskItem = *(PET_DISK_ITEM *)Entry;
return (HandleToUlong(diskItem->ProcessId) / 4) ^ PhHashStringRef(&diskItem->FileName->sr, TRUE);
}
PET_DISK_ITEM EtReferenceDiskItem(
_In_ HANDLE ProcessId,
_In_ PPH_STRING FileName
)
{
ET_DISK_ITEM lookupDiskItem;
PET_DISK_ITEM lookupDiskItemPtr = &lookupDiskItem;
PET_DISK_ITEM *diskItemPtr;
PET_DISK_ITEM diskItem;
lookupDiskItem.ProcessId = ProcessId;
lookupDiskItem.FileName = FileName;
PhAcquireQueuedLockShared(&EtDiskHashtableLock);
diskItemPtr = (PET_DISK_ITEM *)PhFindEntryHashtable(
EtDiskHashtable,
&lookupDiskItemPtr
);
if (diskItemPtr)
PhSetReference(&diskItem, *diskItemPtr);
else
diskItem = NULL;
PhReleaseQueuedLockShared(&EtDiskHashtableLock);
return diskItem;
}
VOID EtpRemoveDiskItem(
_In_ PET_DISK_ITEM DiskItem
)
{
RemoveEntryList(&DiskItem->AgeListEntry);
PhRemoveEntryHashtable(EtDiskHashtable, &DiskItem);
PhDereferenceObject(DiskItem);
}
VOID EtDiskProcessDiskEvent(
_In_ PET_ETW_DISK_EVENT Event
)
{
PETP_DISK_PACKET packet;
if (!EtDiskEnabled)
return;
packet = PhAllocateFromFreeList(&EtDiskPacketFreeList);
memcpy(&packet->Event, Event, sizeof(ET_ETW_DISK_EVENT));
packet->FileName = EtFileObjectToFileName(Event->FileObject);
RtlInterlockedPushEntrySList(&EtDiskPacketListHead, &packet->ListEntry);
}
VOID EtDiskProcessFileEvent(
_In_ PET_ETW_FILE_EVENT Event
)
{
PH_KEY_VALUE_PAIR pair;
PPH_KEY_VALUE_PAIR realPair;
if (!EtDiskEnabled)
return;
if (Event->Type == EtEtwFileCreateType || Event->Type == EtEtwFileRundownType)
{
pair.Key = Event->FileObject;
pair.Value = NULL;
PhAcquireQueuedLockExclusive(&EtFileNameHashtableLock);
realPair = PhAddEntryHashtableEx(EtFileNameHashtable, &pair, NULL);
PhMoveReference(&realPair->Value, PhCreateString2(&Event->FileName));
PhReleaseQueuedLockExclusive(&EtFileNameHashtableLock);
}
else if (Event->Type == EtEtwFileDeleteType)
{
pair.Key = Event->FileObject;
PhAcquireQueuedLockExclusive(&EtFileNameHashtableLock);
realPair = PhFindEntryHashtable(EtFileNameHashtable, &pair);
if (realPair)
{
PhDereferenceObject(realPair->Value);
PhRemoveEntryHashtable(EtFileNameHashtable, &pair);
}
PhReleaseQueuedLockExclusive(&EtFileNameHashtableLock);
}
}
PPH_STRING EtFileObjectToFileName(
_In_ PVOID FileObject
)
{
PH_KEY_VALUE_PAIR pair;
PPH_KEY_VALUE_PAIR realPair;
PPH_STRING fileName;
pair.Key = FileObject;
fileName = NULL;
PhAcquireQueuedLockShared(&EtFileNameHashtableLock);
realPair = PhFindEntryHashtable(EtFileNameHashtable, &pair);
if (realPair)
PhSetReference(&fileName, realPair->Value);
PhReleaseQueuedLockShared(&EtFileNameHashtableLock);
return fileName;
}
VOID EtpProcessDiskPacket(
_In_ PETP_DISK_PACKET Packet,
_In_ ULONG RunId
)
{
PET_ETW_DISK_EVENT diskEvent;
PET_DISK_ITEM diskItem;
BOOLEAN added = FALSE;
diskEvent = &Packet->Event;
// We only process non-zero read/write events.
if (diskEvent->Type != EtEtwDiskReadType && diskEvent->Type != EtEtwDiskWriteType)
return;
if (diskEvent->TransferSize == 0)
return;
// Ignore packets with no file name - this is useless to the user.
if (!Packet->FileName)
return;
diskItem = EtReferenceDiskItem(diskEvent->ClientId.UniqueProcess, Packet->FileName);
if (!diskItem)
{
PPH_PROCESS_ITEM processItem;
// Disk item not found (or the address was re-used), create it.
diskItem = EtCreateDiskItem();
diskItem->ProcessId = diskEvent->ClientId.UniqueProcess;
PhSetReference(&diskItem->FileName, Packet->FileName);
diskItem->FileNameWin32 = PhGetFileName(diskItem->FileName);
if (processItem = PhReferenceProcessItem(diskItem->ProcessId))
{
PhSetReference(&diskItem->ProcessName, processItem->ProcessName);
diskItem->ProcessIcon = EtProcIconReferenceSmallProcessIcon(EtGetProcessBlock(processItem));
diskItem->ProcessRecord = processItem->Record;
PhReferenceProcessRecord(diskItem->ProcessRecord);
PhDereferenceObject(processItem);
}
// Add the disk item to the age list.
diskItem->AddTime = RunId;
diskItem->FreshTime = RunId;
InsertHeadList(&EtDiskAgeListHead, &diskItem->AgeListEntry);
// Add the disk item to the hashtable.
PhAcquireQueuedLockExclusive(&EtDiskHashtableLock);
PhAddEntryHashtable(EtDiskHashtable, &diskItem);
PhReleaseQueuedLockExclusive(&EtDiskHashtableLock);
// Raise the disk item added event.
PhInvokeCallback(&EtDiskItemAddedEvent, diskItem);
added = TRUE;
}
// The I/O priority number needs to be decoded.
diskItem->IoPriority = (diskEvent->IrpFlags >> 17) & 7;
if (diskItem->IoPriority == 0)
diskItem->IoPriority = IoPriorityNormal;
else
diskItem->IoPriority--;
// Accumulate statistics for this update period.
if (diskEvent->Type == EtEtwDiskReadType)
diskItem->ReadDelta += diskEvent->TransferSize;
else
diskItem->WriteDelta += diskEvent->TransferSize;
if (EtpPerformanceFrequency.QuadPart != 0)
{
// Convert the response time to milliseconds.
diskItem->ResponseTimeTotal += (FLOAT)diskEvent->HighResResponseTime * 1000 / EtpPerformanceFrequency.QuadPart;
diskItem->ResponseTimeCount++;
}
if (!added)
{
if (diskItem->FreshTime != RunId)
{
diskItem->FreshTime = RunId;
RemoveEntryList(&diskItem->AgeListEntry);
InsertHeadList(&EtDiskAgeListHead, &diskItem->AgeListEntry);
}
PhDereferenceObject(diskItem);
}
}
ULONG64 EtpCalculateAverage(
_In_ PULONG64 Buffer,
_In_ ULONG BufferSize,
_In_ ULONG BufferPosition,
_In_ ULONG BufferCount,
_In_ ULONG NumberToConsider
)
{
ULONG64 sum;
ULONG i;
ULONG count;
sum = 0;
i = BufferPosition;
if (NumberToConsider > BufferCount)
NumberToConsider = BufferCount;
if (NumberToConsider == 0)
return 0;
count = NumberToConsider;
do
{
sum += Buffer[i];
i++;
if (i == BufferSize)
i = 0;
} while (--count != 0);
return sum / NumberToConsider;
}
VOID NTAPI EtpDiskProcessesUpdatedCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
static ULONG runCount = 0;
PSLIST_ENTRY listEntry;
PLIST_ENTRY ageListEntry;
// Process incoming disk event packets.
listEntry = RtlInterlockedFlushSList(&EtDiskPacketListHead);
while (listEntry)
{
PETP_DISK_PACKET packet;
packet = CONTAINING_RECORD(listEntry, ETP_DISK_PACKET, ListEntry);
listEntry = listEntry->Next;
EtpProcessDiskPacket(packet, runCount);
if (packet->FileName)
PhDereferenceObject(packet->FileName);
PhFreeToFreeList(&EtDiskPacketFreeList, packet);
}
// Remove old entries.
ageListEntry = EtDiskAgeListHead.Blink;
while (ageListEntry != &EtDiskAgeListHead)
{
PET_DISK_ITEM diskItem;
diskItem = CONTAINING_RECORD(ageListEntry, ET_DISK_ITEM, AgeListEntry);
ageListEntry = ageListEntry->Blink;
if (runCount - diskItem->FreshTime < HISTORY_SIZE) // must compare like this to avoid overflow/underflow problems
break;
PhInvokeCallback(&EtDiskItemRemovedEvent, diskItem);
PhAcquireQueuedLockExclusive(&EtDiskHashtableLock);
EtpRemoveDiskItem(diskItem);
PhReleaseQueuedLockExclusive(&EtDiskHashtableLock);
}
// Update existing items.
ageListEntry = EtDiskAgeListHead.Flink;
while (ageListEntry != &EtDiskAgeListHead)
{
PET_DISK_ITEM diskItem;
diskItem = CONTAINING_RECORD(ageListEntry, ET_DISK_ITEM, AgeListEntry);
// Update statistics.
if (diskItem->HistoryPosition != 0)
diskItem->HistoryPosition--;
else
diskItem->HistoryPosition = HISTORY_SIZE - 1;
diskItem->ReadHistory[diskItem->HistoryPosition] = diskItem->ReadDelta;
diskItem->WriteHistory[diskItem->HistoryPosition] = diskItem->WriteDelta;
if (diskItem->HistoryCount < HISTORY_SIZE)
diskItem->HistoryCount++;
if (diskItem->ResponseTimeCount != 0)
{
diskItem->ResponseTimeAverage = (FLOAT)diskItem->ResponseTimeTotal / diskItem->ResponseTimeCount;
// Reset the total once in a while to avoid the number getting too large (and thus losing precision).
if (diskItem->ResponseTimeCount >= 1000)
{
diskItem->ResponseTimeTotal = diskItem->ResponseTimeAverage;
diskItem->ResponseTimeCount = 1;
}
}
diskItem->ReadTotal += diskItem->ReadDelta;
diskItem->WriteTotal += diskItem->WriteDelta;
diskItem->ReadDelta = 0;
diskItem->WriteDelta = 0;
diskItem->ReadAverage = EtpCalculateAverage(diskItem->ReadHistory, HISTORY_SIZE, diskItem->HistoryPosition, diskItem->HistoryCount, HISTORY_SIZE);
diskItem->WriteAverage = EtpCalculateAverage(diskItem->WriteHistory, HISTORY_SIZE, diskItem->HistoryPosition, diskItem->HistoryCount, HISTORY_SIZE);
if (diskItem->AddTime != runCount)
{
BOOLEAN modified = FALSE;
PPH_PROCESS_ITEM processItem;
if (!diskItem->ProcessName || !diskItem->ProcessIcon || !diskItem->ProcessRecord)
{
if (processItem = PhReferenceProcessItem(diskItem->ProcessId))
{
if (!diskItem->ProcessName)
{
PhSetReference(&diskItem->ProcessName, processItem->ProcessName);
modified = TRUE;
}
if (!diskItem->ProcessIcon)
{
diskItem->ProcessIcon = EtProcIconReferenceSmallProcessIcon(EtGetProcessBlock(processItem));
if (diskItem->ProcessIcon)
modified = TRUE;
}
if (!diskItem->ProcessRecord)
{
diskItem->ProcessRecord = processItem->Record;
PhReferenceProcessRecord(diskItem->ProcessRecord);
}
PhDereferenceObject(processItem);
}
}
if (modified)
{
// Raise the disk item modified event.
PhInvokeCallback(&EtDiskItemModifiedEvent, diskItem);
}
}
ageListEntry = ageListEntry->Flink;
}
PhInvokeCallback(&EtDiskItemsUpdatedEvent, NULL);
runCount++;
}

View File

@@ -0,0 +1,264 @@
/*
* Process Hacker Extended Tools -
* ETW mini information section
*
* Copyright (C) 2015 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 "exttools.h"
#include "etwmini.h"
VOID EtEtwMiniInformationInitializing(
_In_ PPH_PLUGIN_MINIINFO_POINTERS Pointers
)
{
PH_MINIINFO_LIST_SECTION section;
memset(&section, 0, sizeof(PH_MINIINFO_LIST_SECTION));
section.Callback = EtpDiskListSectionCallback;
Pointers->CreateListSection(L"Disk", 0, &section);
memset(&section, 0, sizeof(PH_MINIINFO_LIST_SECTION));
section.Callback = EtpNetworkListSectionCallback;
Pointers->CreateListSection(L"Network", 0, &section);
}
BOOLEAN EtpDiskListSectionCallback(
_In_ struct _PH_MINIINFO_LIST_SECTION *ListSection,
_In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message,
_In_opt_ PVOID Parameter1,
_In_opt_ PVOID Parameter2
)
{
switch (Message)
{
case MiListSectionTick:
{
PH_FORMAT format[4];
PhInitFormatS(&format[0], L"Disk R: ");
PhInitFormatSize(&format[1], EtDiskReadDelta.Delta);
format[1].Type |= FormatUsePrecision;
format[1].Precision = 0;
PhInitFormatS(&format[2], L" W: ");
PhInitFormatSize(&format[3], EtDiskWriteDelta.Delta);
format[3].Type |= FormatUsePrecision;
format[3].Precision = 0;
ListSection->Section->Parameters->SetSectionText(ListSection->Section,
PH_AUTO(PhFormat(format, 4, 50)));
}
break;
case MiListSectionSortProcessList:
{
PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1;
qsort(sortList->List->Items, sortList->List->Count,
sizeof(PPH_PROCESS_NODE), EtpDiskListSectionProcessCompareFunction);
}
return TRUE;
case MiListSectionAssignSortData:
{
PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA assignSortData = Parameter1;
PPH_LIST processes = assignSortData->ProcessGroup->Processes;
ULONG64 diskReadDelta = 0;
ULONG64 diskWriteDelta = 0;
ULONG i;
for (i = 0; i < processes->Count; i++)
{
PPH_PROCESS_ITEM processItem = processes->Items[i];
PET_PROCESS_BLOCK block = EtGetProcessBlock(processItem);
diskReadDelta += block->DiskReadRawDelta.Delta;
diskWriteDelta += block->DiskWriteRawDelta.Delta;
}
assignSortData->SortData->UserData[0] = diskReadDelta;
assignSortData->SortData->UserData[1] = diskWriteDelta;
}
return TRUE;
case MiListSectionSortGroupList:
{
PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1;
qsort(sortList->List->Items, sortList->List->Count,
sizeof(PPH_MINIINFO_LIST_SECTION_SORT_DATA), EtpDiskListSectionNodeCompareFunction);
}
return TRUE;
case MiListSectionGetUsageText:
{
PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT getUsageText = Parameter1;
PPH_LIST processes = getUsageText->ProcessGroup->Processes;
ULONG64 diskReadDelta = getUsageText->SortData->UserData[0];
ULONG64 diskWriteDelta = getUsageText->SortData->UserData[1];
PH_FORMAT format[1];
PhInitFormatSize(&format[0], diskReadDelta + diskWriteDelta);
PhMoveReference(&getUsageText->Line1, PhFormat(format, 1, 16));
}
return TRUE;
}
return FALSE;
}
int __cdecl EtpDiskListSectionProcessCompareFunction(
_In_ const void *elem1,
_In_ const void *elem2
)
{
int result;
PPH_PROCESS_NODE node1 = *(PPH_PROCESS_NODE *)elem1;
PPH_PROCESS_NODE node2 = *(PPH_PROCESS_NODE *)elem2;
PET_PROCESS_BLOCK block1 = EtGetProcessBlock(node1->ProcessItem);
PET_PROCESS_BLOCK block2 = EtGetProcessBlock(node2->ProcessItem);
ULONG64 total1 = block1->DiskReadRawDelta.Delta + block1->DiskWriteRawDelta.Delta;
ULONG64 total2 = block2->DiskReadRawDelta.Delta + block2->DiskWriteRawDelta.Delta;
result = uint64cmp(total2, total1);
if (result == 0)
result = uint64cmp(block2->DiskReadRaw + block2->DiskWriteRaw, block1->DiskReadRaw + block1->DiskWriteRaw);
if (result == 0)
result = singlecmp(node2->ProcessItem->CpuUsage, node1->ProcessItem->CpuUsage);
return result;
}
int __cdecl EtpDiskListSectionNodeCompareFunction(
_In_ const void *elem1,
_In_ const void *elem2
)
{
PPH_MINIINFO_LIST_SECTION_SORT_DATA data1 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem1;
PPH_MINIINFO_LIST_SECTION_SORT_DATA data2 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem2;
return uint64cmp(data2->UserData[0] + data2->UserData[1], data1->UserData[0] + data1->UserData[1]);
}
BOOLEAN EtpNetworkListSectionCallback(
_In_ struct _PH_MINIINFO_LIST_SECTION *ListSection,
_In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message,
_In_opt_ PVOID Parameter1,
_In_opt_ PVOID Parameter2
)
{
switch (Message)
{
case MiListSectionTick:
{
PH_FORMAT format[4];
PhInitFormatS(&format[0], L"Network R: ");
PhInitFormatSize(&format[1], EtNetworkReceiveDelta.Delta);
format[1].Type |= FormatUsePrecision;
format[1].Precision = 0;
PhInitFormatS(&format[2], L" S: ");
PhInitFormatSize(&format[3], EtNetworkSendDelta.Delta);
format[3].Type |= FormatUsePrecision;
format[3].Precision = 0;
ListSection->Section->Parameters->SetSectionText(ListSection->Section,
PH_AUTO(PhFormat(format, 4, 50)));
}
break;
case MiListSectionSortProcessList:
{
PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1;
qsort(sortList->List->Items, sortList->List->Count,
sizeof(PPH_PROCESS_NODE), EtpNetworkListSectionProcessCompareFunction);
}
return TRUE;
case MiListSectionAssignSortData:
{
PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA assignSortData = Parameter1;
PPH_LIST processes = assignSortData->ProcessGroup->Processes;
ULONG64 networkReceiveDelta = 0;
ULONG64 networkSendDelta = 0;
ULONG i;
for (i = 0; i < processes->Count; i++)
{
PPH_PROCESS_ITEM processItem = processes->Items[i];
PET_PROCESS_BLOCK block = EtGetProcessBlock(processItem);
networkReceiveDelta += block->NetworkReceiveRawDelta.Delta;
networkSendDelta += block->NetworkSendRawDelta.Delta;
}
assignSortData->SortData->UserData[0] = networkReceiveDelta;
assignSortData->SortData->UserData[1] = networkSendDelta;
}
return TRUE;
case MiListSectionSortGroupList:
{
PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1;
qsort(sortList->List->Items, sortList->List->Count,
sizeof(PPH_MINIINFO_LIST_SECTION_SORT_DATA), EtpNetworkListSectionNodeCompareFunction);
}
return TRUE;
case MiListSectionGetUsageText:
{
PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT getUsageText = Parameter1;
PPH_LIST processes = getUsageText->ProcessGroup->Processes;
ULONG64 networkReceiveDelta = getUsageText->SortData->UserData[0];
ULONG64 networkSendDelta = getUsageText->SortData->UserData[1];
PH_FORMAT format[1];
PhInitFormatSize(&format[0], networkReceiveDelta + networkSendDelta);
PhMoveReference(&getUsageText->Line1, PhFormat(format, 1, 16));
}
return TRUE;
}
return FALSE;
}
int __cdecl EtpNetworkListSectionProcessCompareFunction(
_In_ const void *elem1,
_In_ const void *elem2
)
{
int result;
PPH_PROCESS_NODE node1 = *(PPH_PROCESS_NODE *)elem1;
PPH_PROCESS_NODE node2 = *(PPH_PROCESS_NODE *)elem2;
PET_PROCESS_BLOCK block1 = EtGetProcessBlock(node1->ProcessItem);
PET_PROCESS_BLOCK block2 = EtGetProcessBlock(node2->ProcessItem);
ULONG64 total1 = block1->NetworkReceiveRawDelta.Delta + block1->NetworkSendRawDelta.Delta;
ULONG64 total2 = block2->NetworkReceiveRawDelta.Delta + block2->NetworkSendRawDelta.Delta;
result = uint64cmp(total2, total1);
if (result == 0)
result = uint64cmp(block2->NetworkReceiveRaw + block2->NetworkSendRaw, block1->NetworkReceiveRaw + block1->NetworkSendRaw);
if (result == 0)
result = singlecmp(node2->ProcessItem->CpuUsage, node1->ProcessItem->CpuUsage);
return result;
}
int __cdecl EtpNetworkListSectionNodeCompareFunction(
_In_ const void *elem1,
_In_ const void *elem2
)
{
PPH_MINIINFO_LIST_SECTION_SORT_DATA data1 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem1;
PPH_MINIINFO_LIST_SECTION_SORT_DATA data2 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem2;
return uint64cmp(data2->UserData[0] + data2->UserData[1], data1->UserData[0] + data1->UserData[1]);
}

View File

@@ -0,0 +1,38 @@
#ifndef ETWMINI_H
#define ETWMINI_H
BOOLEAN EtpDiskListSectionCallback(
_In_ struct _PH_MINIINFO_LIST_SECTION *ListSection,
_In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message,
_In_opt_ PVOID Parameter1,
_In_opt_ PVOID Parameter2
);
int __cdecl EtpDiskListSectionProcessCompareFunction(
_In_ const void *elem1,
_In_ const void *elem2
);
int __cdecl EtpDiskListSectionNodeCompareFunction(
_In_ const void *elem1,
_In_ const void *elem2
);
BOOLEAN EtpNetworkListSectionCallback(
_In_ struct _PH_MINIINFO_LIST_SECTION *ListSection,
_In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message,
_In_opt_ PVOID Parameter1,
_In_opt_ PVOID Parameter2
);
int __cdecl EtpNetworkListSectionProcessCompareFunction(
_In_ const void *elem1,
_In_ const void *elem2
);
int __cdecl EtpNetworkListSectionNodeCompareFunction(
_In_ const void *elem1,
_In_ const void *elem2
);
#endif

View File

@@ -0,0 +1,562 @@
/*
* Process Hacker Extended Tools -
* ETW monitoring
*
* Copyright (C) 2010-2015 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 "exttools.h"
#include "etwmon.h"
ULONG NTAPI EtpEtwBufferCallback(
_In_ PEVENT_TRACE_LOGFILE Buffer
);
VOID NTAPI EtpEtwEventCallback(
_In_ PEVENT_RECORD EventRecord
);
NTSTATUS EtpEtwMonitorThreadStart(
_In_ PVOID Parameter
);
ULONG EtpStopEtwRundownSession(
VOID
);
ULONG NTAPI EtpRundownEtwBufferCallback(
_In_ PEVENT_TRACE_LOGFILE Buffer
);
VOID NTAPI EtpRundownEtwEventCallback(
_In_ PEVENT_RECORD EventRecord
);
NTSTATUS EtpRundownEtwMonitorThreadStart(
_In_ PVOID Parameter
);
static GUID ProcessHackerGuid = { 0x1288c53b, 0xaf35, 0x481b, { 0xb6, 0xb5, 0xa0, 0x5c, 0x39, 0x87, 0x2e, 0xd } };
static GUID SystemTraceControlGuid_I = { 0x9e814aad, 0x3204, 0x11d2, { 0x9a, 0x82, 0x00, 0x60, 0x08, 0xa8, 0x69, 0x39 } };
static GUID KernelRundownGuid_I = { 0x3b9c9951, 0x3480, 0x4220, { 0x93, 0x77, 0x9c, 0x8e, 0x51, 0x84, 0xf5, 0xcd } };
static GUID DiskIoGuid_I = { 0x3d6fa8d4, 0xfe05, 0x11d0, { 0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c } };
static GUID FileIoGuid_I = { 0x90cbdc39, 0x4a3e, 0x11d1, { 0x84, 0xf4, 0x00, 0x00, 0xf8, 0x04, 0x64, 0xe3 } };
static GUID TcpIpGuid_I = { 0x9a280ac0, 0xc8e0, 0x11d1, { 0x84, 0xe2, 0x00, 0xc0, 0x4f, 0xb9, 0x98, 0xa2 } };
static GUID UdpIpGuid_I = { 0xbf3a50c5, 0xa9c9, 0x4988, { 0xa0, 0x05, 0x2d, 0xf0, 0xb7, 0xc8, 0x0f, 0x80 } };
// ETW tracing layer
BOOLEAN EtEtwEnabled;
static UNICODE_STRING EtpSharedKernelLoggerName = RTL_CONSTANT_STRING(KERNEL_LOGGER_NAME);
static UNICODE_STRING EtpPrivateKernelLoggerName = RTL_CONSTANT_STRING(L"PhEtKernelLogger");
static TRACEHANDLE EtpSessionHandle;
static PUNICODE_STRING EtpActualKernelLoggerName;
static PGUID EtpActualSessionGuid;
static PEVENT_TRACE_PROPERTIES EtpTraceProperties;
static BOOLEAN EtpEtwActive;
static BOOLEAN EtpStartedSession;
static BOOLEAN EtpEtwExiting;
static HANDLE EtpEtwMonitorThreadHandle;
// ETW rundown layer
static UNICODE_STRING EtpRundownLoggerName = RTL_CONSTANT_STRING(L"PhEtRundownLogger");
static TRACEHANDLE EtpRundownSessionHandle;
static PEVENT_TRACE_PROPERTIES EtpRundownTraceProperties;
static BOOLEAN EtpRundownActive;
static HANDLE EtpRundownEtwMonitorThreadHandle;
VOID EtEtwMonitorInitialization(
VOID
)
{
if (PhGetOwnTokenAttributes().Elevated && PhGetIntegerSetting(SETTING_NAME_ENABLE_ETW_MONITOR))
{
EtStartEtwSession();
if (EtEtwEnabled)
EtpEtwMonitorThreadHandle = PhCreateThread(0, EtpEtwMonitorThreadStart, NULL);
}
}
VOID EtEtwMonitorUninitialization(
VOID
)
{
if (EtEtwEnabled)
{
EtpEtwExiting = TRUE;
EtStopEtwSession();
}
if (EtpRundownActive)
{
EtpStopEtwRundownSession();
}
}
VOID EtStartEtwSession(
VOID
)
{
ULONG result;
ULONG bufferSize;
if (WindowsVersion >= WINDOWS_8)
{
EtpActualKernelLoggerName = &EtpPrivateKernelLoggerName;
EtpActualSessionGuid = &ProcessHackerGuid;
}
else
{
EtpActualKernelLoggerName = &EtpSharedKernelLoggerName;
EtpActualSessionGuid = &SystemTraceControlGuid_I;
}
bufferSize = sizeof(EVENT_TRACE_PROPERTIES) + EtpActualKernelLoggerName->Length + sizeof(WCHAR);
if (!EtpTraceProperties)
EtpTraceProperties = PhAllocate(bufferSize);
memset(EtpTraceProperties, 0, sizeof(EVENT_TRACE_PROPERTIES));
EtpTraceProperties->Wnode.BufferSize = bufferSize;
EtpTraceProperties->Wnode.Guid = *EtpActualSessionGuid;
EtpTraceProperties->Wnode.ClientContext = 1;
EtpTraceProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
EtpTraceProperties->MinimumBuffers = 1;
EtpTraceProperties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
EtpTraceProperties->FlushTimer = 1;
EtpTraceProperties->EnableFlags = EVENT_TRACE_FLAG_DISK_IO | EVENT_TRACE_FLAG_DISK_FILE_IO | EVENT_TRACE_FLAG_NETWORK_TCPIP;
EtpTraceProperties->LogFileNameOffset = 0;
EtpTraceProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
if (WindowsVersion >= WINDOWS_8)
EtpTraceProperties->LogFileMode |= EVENT_TRACE_SYSTEM_LOGGER_MODE;
result = StartTrace(&EtpSessionHandle, EtpActualKernelLoggerName->Buffer, EtpTraceProperties);
if (result == ERROR_SUCCESS)
{
EtEtwEnabled = TRUE;
EtpEtwActive = TRUE;
EtpStartedSession = TRUE;
}
else if (result == ERROR_ALREADY_EXISTS)
{
EtEtwEnabled = TRUE;
EtpEtwActive = TRUE;
EtpStartedSession = FALSE;
// The session already exists.
//result = ControlTrace(0, EtpActualKernelLoggerName->Buffer, EtpTraceProperties, EVENT_TRACE_CONTROL_UPDATE);
}
else
{
EtpEtwActive = FALSE;
EtpStartedSession = FALSE;
}
}
ULONG EtpControlEtwSession(
_In_ ULONG ControlCode
)
{
// If we have a session handle, we use that instead of the logger name.
EtpTraceProperties->LogFileNameOffset = 0; // make sure it is 0, otherwise ControlTrace crashes
return ControlTrace(
EtpStartedSession ? EtpSessionHandle : 0,
EtpStartedSession ? NULL : EtpActualKernelLoggerName->Buffer,
EtpTraceProperties,
ControlCode
);
}
VOID EtStopEtwSession(
VOID
)
{
if (EtEtwEnabled)
EtpControlEtwSession(EVENT_TRACE_CONTROL_STOP);
}
VOID EtFlushEtwSession(
VOID
)
{
if (EtEtwEnabled)
EtpControlEtwSession(EVENT_TRACE_CONTROL_FLUSH);
}
ULONG NTAPI EtpEtwBufferCallback(
_In_ PEVENT_TRACE_LOGFILE Buffer
)
{
return !EtpEtwExiting;
}
VOID NTAPI EtpEtwEventCallback(
_In_ PEVENT_RECORD EventRecord
)
{
if (memcmp(&EventRecord->EventHeader.ProviderId, &DiskIoGuid_I, sizeof(GUID)) == 0)
{
// DiskIo
ET_ETW_DISK_EVENT diskEvent;
memset(&diskEvent, 0, sizeof(ET_ETW_DISK_EVENT));
diskEvent.Type = -1;
switch (EventRecord->EventHeader.EventDescriptor.Opcode)
{
case EVENT_TRACE_TYPE_IO_READ:
diskEvent.Type = EtEtwDiskReadType;
break;
case EVENT_TRACE_TYPE_IO_WRITE:
diskEvent.Type = EtEtwDiskWriteType;
break;
default:
break;
}
if (diskEvent.Type != -1)
{
DiskIo_TypeGroup1 *data = EventRecord->UserData;
if (WindowsVersion >= WINDOWS_8)
{
diskEvent.ClientId.UniqueThread = UlongToHandle(data->IssuingThreadId);
diskEvent.ClientId.UniqueProcess = EtThreadIdToProcessId(diskEvent.ClientId.UniqueThread);
}
else
{
if (EventRecord->EventHeader.ProcessId != -1)
{
diskEvent.ClientId.UniqueProcess = UlongToHandle(EventRecord->EventHeader.ProcessId);
diskEvent.ClientId.UniqueThread = UlongToHandle(EventRecord->EventHeader.ThreadId);
}
}
diskEvent.IrpFlags = data->IrpFlags;
diskEvent.TransferSize = data->TransferSize;
diskEvent.FileObject = (PVOID)data->FileObject;
diskEvent.HighResResponseTime = data->HighResResponseTime;
EtProcessDiskEvent(&diskEvent);
EtDiskProcessDiskEvent(&diskEvent);
}
}
else if (memcmp(&EventRecord->EventHeader.ProviderId, &FileIoGuid_I, sizeof(GUID)) == 0)
{
// FileIo
ET_ETW_FILE_EVENT fileEvent;
memset(&fileEvent, 0, sizeof(ET_ETW_FILE_EVENT));
fileEvent.Type = -1;
switch (EventRecord->EventHeader.EventDescriptor.Opcode)
{
case 0: // Name
fileEvent.Type = EtEtwFileNameType;
break;
case 32: // FileCreate
fileEvent.Type = EtEtwFileCreateType;
break;
case 35: // FileDelete
fileEvent.Type = EtEtwFileDeleteType;
break;
default:
break;
}
if (fileEvent.Type != -1)
{
FileIo_Name *data = EventRecord->UserData;
fileEvent.FileObject = (PVOID)data->FileObject;
PhInitializeStringRef(&fileEvent.FileName, data->FileName);
EtDiskProcessFileEvent(&fileEvent);
}
}
else if (
memcmp(&EventRecord->EventHeader.ProviderId, &TcpIpGuid_I, sizeof(GUID)) == 0 ||
memcmp(&EventRecord->EventHeader.ProviderId, &UdpIpGuid_I, sizeof(GUID)) == 0
)
{
// TcpIp/UdpIp
ET_ETW_NETWORK_EVENT networkEvent;
memset(&networkEvent, 0, sizeof(ET_ETW_NETWORK_EVENT));
networkEvent.Type = -1;
switch (EventRecord->EventHeader.EventDescriptor.Opcode)
{
case EVENT_TRACE_TYPE_SEND: // send
networkEvent.Type = EtEtwNetworkSendType;
networkEvent.ProtocolType = PH_IPV4_NETWORK_TYPE;
break;
case EVENT_TRACE_TYPE_RECEIVE: // receive
networkEvent.Type = EtEtwNetworkReceiveType;
networkEvent.ProtocolType = PH_IPV4_NETWORK_TYPE;
break;
case EVENT_TRACE_TYPE_SEND + 16: // send ipv6
networkEvent.Type = EtEtwNetworkSendType;
networkEvent.ProtocolType = PH_IPV6_NETWORK_TYPE;
break;
case EVENT_TRACE_TYPE_RECEIVE + 16: // receive ipv6
networkEvent.Type = EtEtwNetworkReceiveType;
networkEvent.ProtocolType = PH_IPV6_NETWORK_TYPE;
break;
}
if (memcmp(&EventRecord->EventHeader.ProviderId, &TcpIpGuid_I, sizeof(GUID)) == 0)
networkEvent.ProtocolType |= PH_TCP_PROTOCOL_TYPE;
else
networkEvent.ProtocolType |= PH_UDP_PROTOCOL_TYPE;
if (networkEvent.Type != -1)
{
PH_IP_ENDPOINT source;
PH_IP_ENDPOINT destination;
if (networkEvent.ProtocolType & PH_IPV4_NETWORK_TYPE)
{
TcpIpOrUdpIp_IPV4_Header *data = EventRecord->UserData;
networkEvent.ClientId.UniqueProcess = UlongToHandle(data->PID);
networkEvent.TransferSize = data->size;
source.Address.Type = PH_IPV4_NETWORK_TYPE;
source.Address.Ipv4 = data->saddr;
source.Port = _byteswap_ushort(data->sport);
destination.Address.Type = PH_IPV4_NETWORK_TYPE;
destination.Address.Ipv4 = data->daddr;
destination.Port = _byteswap_ushort(data->dport);
}
else if (networkEvent.ProtocolType & PH_IPV6_NETWORK_TYPE)
{
TcpIpOrUdpIp_IPV6_Header *data = EventRecord->UserData;
networkEvent.ClientId.UniqueProcess = UlongToHandle(data->PID);
networkEvent.TransferSize = data->size;
source.Address.Type = PH_IPV6_NETWORK_TYPE;
source.Address.In6Addr = data->saddr;
source.Port = _byteswap_ushort(data->sport);
destination.Address.Type = PH_IPV6_NETWORK_TYPE;
destination.Address.In6Addr = data->daddr;
destination.Port = _byteswap_ushort(data->dport);
}
networkEvent.LocalEndpoint = source;
if (networkEvent.ProtocolType & PH_TCP_PROTOCOL_TYPE)
networkEvent.RemoteEndpoint = destination;
EtProcessNetworkEvent(&networkEvent);
}
}
}
NTSTATUS EtpEtwMonitorThreadStart(
_In_ PVOID Parameter
)
{
ULONG result;
EVENT_TRACE_LOGFILE logFile;
TRACEHANDLE traceHandle;
// See comment in EtEtwProcessesUpdatedCallback.
if (WindowsVersion >= WINDOWS_8)
EtUpdateProcessInformation();
memset(&logFile, 0, sizeof(EVENT_TRACE_LOGFILE));
logFile.LoggerName = EtpActualKernelLoggerName->Buffer;
logFile.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD;
logFile.BufferCallback = EtpEtwBufferCallback;
logFile.EventRecordCallback = EtpEtwEventCallback;
while (TRUE)
{
result = ERROR_SUCCESS;
traceHandle = OpenTrace(&logFile);
if (traceHandle != INVALID_PROCESSTRACE_HANDLE)
{
while (!EtpEtwExiting && (result = ProcessTrace(&traceHandle, 1, NULL, NULL)) == ERROR_SUCCESS)
NOTHING;
CloseTrace(traceHandle);
}
if (EtpEtwExiting)
break;
if (result == ERROR_WMI_INSTANCE_NOT_FOUND)
{
// The session was stopped by another program. Try to start it again.
EtStartEtwSession();
}
// Some error occurred, so sleep for a while before trying again.
// Don't sleep if we just successfully started a session, though.
if (!EtpEtwActive)
Sleep(250);
}
return STATUS_SUCCESS;
}
ULONG EtStartEtwRundown(
VOID
)
{
ULONG result;
ULONG bufferSize;
bufferSize = sizeof(EVENT_TRACE_PROPERTIES) + EtpRundownLoggerName.Length + sizeof(WCHAR);
if (!EtpRundownTraceProperties)
EtpRundownTraceProperties = PhAllocate(bufferSize);
memset(EtpRundownTraceProperties, 0, sizeof(EVENT_TRACE_PROPERTIES));
EtpRundownTraceProperties->Wnode.BufferSize = bufferSize;
EtpRundownTraceProperties->Wnode.ClientContext = 1;
EtpRundownTraceProperties->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
EtpRundownTraceProperties->MinimumBuffers = 1;
EtpRundownTraceProperties->LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
EtpRundownTraceProperties->FlushTimer = 1;
EtpRundownTraceProperties->LogFileNameOffset = 0;
EtpRundownTraceProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
result = StartTrace(&EtpRundownSessionHandle, EtpRundownLoggerName.Buffer, EtpRundownTraceProperties);
if (result == ERROR_ALREADY_EXISTS)
{
EtpStopEtwRundownSession();
// ControlTrace (called from EtpStopEtwRundownSession) screws up the structure.
EtpRundownTraceProperties->Wnode.BufferSize = bufferSize;
EtpRundownTraceProperties->LogFileNameOffset = 0;
EtpRundownTraceProperties->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
result = StartTrace(&EtpRundownSessionHandle, EtpRundownLoggerName.Buffer, EtpRundownTraceProperties);
}
if (result != ERROR_SUCCESS)
return result;
result = EnableTraceEx(&KernelRundownGuid_I, NULL, EtpRundownSessionHandle, 1, 0, 0x10, 0, 0, NULL);
if (result != ERROR_SUCCESS)
{
EtpStopEtwRundownSession();
return result;
}
EtpRundownActive = TRUE;
EtpRundownEtwMonitorThreadHandle = PhCreateThread(0, EtpRundownEtwMonitorThreadStart, NULL);
return result;
}
ULONG EtpStopEtwRundownSession(
VOID
)
{
EtpRundownTraceProperties->LogFileNameOffset = 0;
return ControlTrace(0, EtpRundownLoggerName.Buffer, EtpRundownTraceProperties, EVENT_TRACE_CONTROL_STOP);
}
ULONG NTAPI EtpRundownEtwBufferCallback(
_In_ PEVENT_TRACE_LOGFILE Buffer
)
{
return !EtpEtwExiting;
}
VOID NTAPI EtpRundownEtwEventCallback(
_In_ PEVENT_RECORD EventRecord
)
{
// TODO: Find a way to call CloseTrace when the enumeration finishes so we can
// stop the trace cleanly.
if (memcmp(&EventRecord->EventHeader.ProviderId, &FileIoGuid_I, sizeof(GUID)) == 0)
{
// FileIo
ET_ETW_FILE_EVENT fileEvent;
memset(&fileEvent, 0, sizeof(ET_ETW_FILE_EVENT));
fileEvent.Type = -1;
switch (EventRecord->EventHeader.EventDescriptor.Opcode)
{
case 36: // FileRundown
fileEvent.Type = EtEtwFileRundownType;
break;
default:
break;
}
if (fileEvent.Type != -1)
{
FileIo_Name *data = EventRecord->UserData;
fileEvent.FileObject = (PVOID)data->FileObject;
PhInitializeStringRef(&fileEvent.FileName, data->FileName);
EtDiskProcessFileEvent(&fileEvent);
}
}
}
NTSTATUS EtpRundownEtwMonitorThreadStart(
_In_ PVOID Parameter
)
{
EVENT_TRACE_LOGFILE logFile;
TRACEHANDLE traceHandle;
memset(&logFile, 0, sizeof(EVENT_TRACE_LOGFILE));
logFile.LoggerName = EtpRundownLoggerName.Buffer;
logFile.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD;
logFile.BufferCallback = EtpRundownEtwBufferCallback;
logFile.EventRecordCallback = EtpRundownEtwEventCallback;
logFile.Context = &traceHandle;
traceHandle = OpenTrace(&logFile);
if (traceHandle != INVALID_PROCESSTRACE_HANDLE)
{
ProcessTrace(&traceHandle, 1, NULL, NULL);
if (traceHandle != 0)
CloseTrace(traceHandle);
}
NtClose(EtpRundownEtwMonitorThreadHandle);
EtpRundownEtwMonitorThreadHandle = NULL;
return STATUS_SUCCESS;
}

View File

@@ -0,0 +1,140 @@
#ifndef ETWMON_H
#define ETWMON_H
#include <evntcons.h>
typedef struct
{
ULONG DiskNumber;
ULONG IrpFlags;
ULONG TransferSize;
ULONG ResponseTime;
ULONG64 ByteOffset;
ULONG_PTR FileObject;
ULONG_PTR Irp;
ULONG64 HighResResponseTime;
ULONG IssuingThreadId; // since WIN8 (ETW_DISKIO_READWRITE_V3)
} DiskIo_TypeGroup1;
typedef struct
{
ULONG_PTR FileObject;
WCHAR FileName[1];
} FileIo_Name;
typedef struct
{
ULONG PID;
ULONG size;
ULONG daddr;
ULONG saddr;
USHORT dport;
USHORT sport;
} TcpIpOrUdpIp_IPV4_Header;
typedef struct
{
ULONG PID;
ULONG size;
IN6_ADDR daddr;
IN6_ADDR saddr;
USHORT dport;
USHORT sport;
} TcpIpOrUdpIp_IPV6_Header;
// etwmon
VOID EtEtwMonitorInitialization(
VOID
);
VOID EtEtwMonitorUninitialization(
VOID
);
VOID EtStartEtwSession(
VOID
);
VOID EtStopEtwSession(
VOID
);
VOID EtFlushEtwSession(
VOID
);
ULONG EtStartEtwRundown(
VOID
);
// etwstat
typedef enum _ET_ETW_EVENT_TYPE
{
EtEtwDiskReadType = 1,
EtEtwDiskWriteType,
EtEtwFileNameType,
EtEtwFileCreateType,
EtEtwFileDeleteType,
EtEtwFileRundownType,
EtEtwNetworkReceiveType,
EtEtwNetworkSendType
} ET_ETW_EVENT_TYPE;
typedef struct _ET_ETW_DISK_EVENT
{
ET_ETW_EVENT_TYPE Type;
CLIENT_ID ClientId;
ULONG IrpFlags;
ULONG TransferSize;
PVOID FileObject;
ULONG64 HighResResponseTime;
} ET_ETW_DISK_EVENT, *PET_ETW_DISK_EVENT;
typedef struct _ET_ETW_FILE_EVENT
{
ET_ETW_EVENT_TYPE Type;
PVOID FileObject;
PH_STRINGREF FileName;
} ET_ETW_FILE_EVENT, *PET_ETW_FILE_EVENT;
typedef struct _ET_ETW_NETWORK_EVENT
{
ET_ETW_EVENT_TYPE Type;
CLIENT_ID ClientId;
ULONG ProtocolType;
ULONG TransferSize;
PH_IP_ENDPOINT LocalEndpoint;
PH_IP_ENDPOINT RemoteEndpoint;
} ET_ETW_NETWORK_EVENT, *PET_ETW_NETWORK_EVENT;
// etwstat
VOID EtProcessDiskEvent(
_In_ PET_ETW_DISK_EVENT Event
);
VOID EtProcessNetworkEvent(
_In_ PET_ETW_NETWORK_EVENT Event
);
VOID EtUpdateProcessInformation(
VOID
);
HANDLE EtThreadIdToProcessId(
_In_ HANDLE ThreadId
);
// etwdisk
VOID EtDiskProcessDiskEvent(
_In_ PET_ETW_DISK_EVENT Event
);
VOID EtDiskProcessFileEvent(
_In_ PET_ETW_FILE_EVENT Event
);
#endif

View File

@@ -0,0 +1,615 @@
/*
* Process Hacker Extended Tools -
* ETW process properties page
*
* Copyright (C) 2010-2011 wj32
* Copyright (C) 2015 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 "exttools.h"
static RECT NormalGraphTextMargin = { 5, 5, 5, 5 };
static RECT NormalGraphTextPadding = { 3, 3, 3, 3 };
typedef struct _ET_DISKNET_CONTEXT
{
HWND WindowHandle;
PET_PROCESS_BLOCK Block;
PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration;
BOOLEAN Enabled;
PH_LAYOUT_MANAGER LayoutManager;
HWND DiskGroupBox;
HWND NetworkGroupBox;
HWND DiskGraphHandle;
HWND NetworkGraphHandle;
HWND PanelHandle;
ULONG64 CurrentDiskRead;
ULONG64 CurrentDiskWrite;
ULONG64 CurrentNetworkSend;
ULONG64 CurrentNetworkReceive;
PH_GRAPH_STATE DiskGraphState;
PH_GRAPH_STATE NetworkGraphState;
PH_CIRCULAR_BUFFER_ULONG64 DiskReadHistory;
PH_CIRCULAR_BUFFER_ULONG64 DiskWriteHistory;
PH_CIRCULAR_BUFFER_ULONG64 NetworkSendHistory;
PH_CIRCULAR_BUFFER_ULONG64 NetworkReceiveHistory;
} ET_DISKNET_CONTEXT, *PET_DISKNET_CONTEXT;
INT_PTR CALLBACK EtwDiskNetworkPanelDialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
return FALSE;
}
VOID EtwDiskNetworkCreateGraphs(
_In_ PET_DISKNET_CONTEXT Context
)
{
Context->DiskGraphHandle = CreateWindow(
PH_GRAPH_CLASSNAME,
NULL,
WS_VISIBLE | WS_CHILD | WS_BORDER,
0,
0,
3,
3,
Context->WindowHandle,
NULL,
NULL,
NULL
);
Graph_SetTooltip(Context->DiskGraphHandle, TRUE);
Context->NetworkGraphHandle = CreateWindow(
PH_GRAPH_CLASSNAME,
NULL,
WS_VISIBLE | WS_CHILD | WS_BORDER,
0,
0,
3,
3,
Context->WindowHandle,
NULL,
NULL,
NULL
);
Graph_SetTooltip(Context->NetworkGraphHandle, TRUE);
}
VOID EtwDiskNetworkCreatePanel(
_In_ PET_DISKNET_CONTEXT Context
)
{
RECT margin;
Context->PanelHandle = CreateDialogParam(
PluginInstance->DllBase,
MAKEINTRESOURCE(IDD_PROCDISKNET_PANEL),
Context->WindowHandle,
EtwDiskNetworkPanelDialogProc,
(LPARAM)Context
);
SetWindowPos(
Context->PanelHandle,
NULL,
10, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSIZE | SWP_NOZORDER
);
ShowWindow(Context->PanelHandle, SW_SHOW);
margin.left = 0;
margin.top = 0;
margin.right = 0;
margin.bottom = 10;
MapDialogRect(Context->WindowHandle, &margin);
PhAddLayoutItemEx(
&Context->LayoutManager,
Context->PanelHandle,
NULL,
PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT,
margin
);
SendMessage(Context->WindowHandle, WM_SIZE, 0, 0);
}
VOID EtwDiskNetworkLayoutGraphs(
_In_ PET_DISKNET_CONTEXT Context
)
{
HDWP deferHandle;
RECT clientRect;
RECT panelRect;
RECT margin = { ET_SCALE_DPI(13), ET_SCALE_DPI(13), ET_SCALE_DPI(13), ET_SCALE_DPI(13) };
RECT innerMargin = { ET_SCALE_DPI(10), ET_SCALE_DPI(20), ET_SCALE_DPI(10), ET_SCALE_DPI(10) };
LONG between = ET_SCALE_DPI(3);
ULONG graphWidth;
ULONG graphHeight;
PhLayoutManagerLayout(&Context->LayoutManager);
Context->DiskGraphState.Valid = FALSE;
Context->NetworkGraphState.Valid = FALSE;
GetClientRect(Context->WindowHandle, &clientRect);
// Limit the rectangle bottom to the top of the panel.
GetWindowRect(Context->PanelHandle, &panelRect);
MapWindowPoints(NULL, Context->WindowHandle, (PPOINT)&panelRect, 2);
clientRect.bottom = panelRect.top + 10; // +10 removing extra spacing
graphWidth = clientRect.right - margin.left - margin.right;
graphHeight = (clientRect.bottom - margin.top - margin.bottom - between * 2) / 2;
deferHandle = BeginDeferWindowPos(4);
deferHandle = DeferWindowPos(deferHandle, Context->DiskGroupBox, NULL, margin.left, margin.top, graphWidth, graphHeight, SWP_NOACTIVATE | SWP_NOZORDER);
deferHandle = DeferWindowPos(
deferHandle,
Context->DiskGraphHandle,
NULL,
margin.left + innerMargin.left,
margin.top + innerMargin.top,
graphWidth - innerMargin.left - innerMargin.right,
graphHeight - innerMargin.top - innerMargin.bottom,
SWP_NOACTIVATE | SWP_NOZORDER
);
deferHandle = DeferWindowPos(deferHandle, Context->NetworkGroupBox, NULL, margin.left, margin.top + graphHeight + between, graphWidth, graphHeight, SWP_NOACTIVATE | SWP_NOZORDER);
deferHandle = DeferWindowPos(
deferHandle,
Context->NetworkGraphHandle,
NULL,
margin.left + innerMargin.left,
margin.top + graphHeight + between + innerMargin.top,
graphWidth - innerMargin.left - innerMargin.right,
graphHeight - innerMargin.top - innerMargin.bottom,
SWP_NOACTIVATE | SWP_NOZORDER
);
EndDeferWindowPos(deferHandle);
}
VOID EtwDiskNetworkUpdateGraphs(
_In_ PET_DISKNET_CONTEXT Context
)
{
Context->DiskGraphState.Valid = FALSE;
Context->DiskGraphState.TooltipIndex = -1;
Graph_MoveGrid(Context->DiskGraphHandle, 1);
Graph_Draw(Context->DiskGraphHandle);
Graph_UpdateTooltip(Context->DiskGraphHandle);
InvalidateRect(Context->DiskGraphHandle, NULL, FALSE);
Context->NetworkGraphState.Valid = FALSE;
Context->NetworkGraphState.TooltipIndex = -1;
Graph_MoveGrid(Context->NetworkGraphHandle, 1);
Graph_Draw(Context->NetworkGraphHandle);
Graph_UpdateTooltip(Context->NetworkGraphHandle);
InvalidateRect(Context->NetworkGraphHandle, NULL, FALSE);
}
VOID EtwDiskNetworkUpdatePanel(
_Inout_ PET_DISKNET_CONTEXT Context
)
{
PET_PROCESS_BLOCK block = Context->Block;
SetDlgItemText(Context->PanelHandle, IDC_ZREADS_V, PhaFormatUInt64(block->DiskReadCount, TRUE)->Buffer);
SetDlgItemText(Context->PanelHandle, IDC_ZREADBYTES_V, PhaFormatSize(block->DiskReadRawDelta.Value, -1)->Buffer);
SetDlgItemText(Context->PanelHandle, IDC_ZREADBYTESDELTA_V, PhaFormatSize(block->DiskReadRawDelta.Delta, -1)->Buffer);
SetDlgItemText(Context->PanelHandle, IDC_ZWRITES_V, PhaFormatUInt64(block->DiskWriteCount, TRUE)->Buffer);
SetDlgItemText(Context->PanelHandle, IDC_ZWRITEBYTES_V, PhaFormatSize(block->DiskWriteRawDelta.Value, -1)->Buffer);
SetDlgItemText(Context->PanelHandle, IDC_ZWRITEBYTESDELTA_V, PhaFormatSize(block->DiskWriteRawDelta.Delta, -1)->Buffer);
SetDlgItemText(Context->PanelHandle, IDC_ZRECEIVES_V, PhaFormatUInt64(block->NetworkReceiveCount, TRUE)->Buffer);
SetDlgItemText(Context->PanelHandle, IDC_ZRECEIVEBYTES_V, PhaFormatSize(block->NetworkReceiveRawDelta.Value, -1)->Buffer);
SetDlgItemText(Context->PanelHandle, IDC_ZRECEIVEBYTESDELTA_V, PhaFormatSize(block->NetworkReceiveRawDelta.Delta, -1)->Buffer);
SetDlgItemText(Context->PanelHandle, IDC_ZSENDS_V, PhaFormatUInt64(block->NetworkSendCount, TRUE)->Buffer);
SetDlgItemText(Context->PanelHandle, IDC_ZSENDBYTES_V, PhaFormatSize(block->NetworkSendRawDelta.Value, -1)->Buffer);
SetDlgItemText(Context->PanelHandle, IDC_ZSENDBYTESDELTA_V, PhaFormatSize(block->NetworkSendRawDelta.Delta, -1)->Buffer);
}
VOID EtwDiskNetworkUpdateInfo(
_In_ PET_DISKNET_CONTEXT Context
)
{
PET_PROCESS_BLOCK block = Context->Block;
Context->CurrentDiskRead = block->DiskReadRawDelta.Delta;
Context->CurrentDiskWrite = block->DiskWriteRawDelta.Delta;
Context->CurrentNetworkSend = block->NetworkSendRawDelta.Delta;
Context->CurrentNetworkReceive = block->NetworkReceiveRawDelta.Delta;
PhAddItemCircularBuffer_ULONG64(&Context->DiskReadHistory, Context->CurrentDiskRead);
PhAddItemCircularBuffer_ULONG64(&Context->DiskWriteHistory, Context->CurrentDiskWrite);
PhAddItemCircularBuffer_ULONG64(&Context->NetworkSendHistory, Context->CurrentNetworkSend);
PhAddItemCircularBuffer_ULONG64(&Context->NetworkReceiveHistory, Context->CurrentNetworkReceive);
}
VOID NTAPI EtwDiskNetworkUpdateHandler(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PET_DISKNET_CONTEXT context = Context;
if (!context->Enabled)
return;
if (context->WindowHandle)
{
PostMessage(context->WindowHandle, UPDATE_MSG, 0, 0);
}
}
INT_PTR CALLBACK EtwDiskNetworkPageDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
LPPROPSHEETPAGE propSheetPage;
PPH_PROCESS_PROPPAGECONTEXT propPageContext;
PPH_PROCESS_ITEM processItem;
PET_DISKNET_CONTEXT context;
if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem))
{
context = propPageContext->Context;
}
else
{
return FALSE;
}
switch (uMsg)
{
case WM_INITDIALOG:
{
ULONG sampleCount;
sampleCount = PhGetIntegerSetting(L"SampleCount");
context = PhAllocate(sizeof(ET_DISKNET_CONTEXT));
memset(context, 0, sizeof(ET_DISKNET_CONTEXT));
context->WindowHandle = hwndDlg;
context->Block = EtGetProcessBlock(processItem);
context->Enabled = TRUE;
context->DiskGroupBox = GetDlgItem(hwndDlg, IDC_GROUPDISK);
context->NetworkGroupBox = GetDlgItem(hwndDlg, IDC_GROUPNETWORK);
propPageContext->Context = context;
PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);
PhInitializeGraphState(&context->DiskGraphState);
PhInitializeGraphState(&context->NetworkGraphState);
PhInitializeCircularBuffer_ULONG64(&context->DiskReadHistory, sampleCount);
PhInitializeCircularBuffer_ULONG64(&context->DiskWriteHistory, sampleCount);
PhInitializeCircularBuffer_ULONG64(&context->NetworkSendHistory, sampleCount);
PhInitializeCircularBuffer_ULONG64(&context->NetworkReceiveHistory, sampleCount);
EtwDiskNetworkCreateGraphs(context);
EtwDiskNetworkCreatePanel(context);
EtwDiskNetworkUpdateInfo(context);
EtwDiskNetworkUpdatePanel(context);
PhRegisterCallback(
&PhProcessesUpdatedEvent,
EtwDiskNetworkUpdateHandler,
context,
&context->ProcessesUpdatedRegistration
);
}
break;
case WM_DESTROY:
{
PhDeleteLayoutManager(&context->LayoutManager);
PhDeleteGraphState(&context->DiskGraphState);
PhDeleteGraphState(&context->NetworkGraphState);
PhDeleteCircularBuffer_ULONG64(&context->DiskReadHistory);
PhDeleteCircularBuffer_ULONG64(&context->DiskWriteHistory);
PhDeleteCircularBuffer_ULONG64(&context->NetworkSendHistory);
PhDeleteCircularBuffer_ULONG64(&context->NetworkReceiveHistory);
if (context->DiskGraphHandle)
DestroyWindow(context->DiskGraphHandle);
if (context->NetworkGraphHandle)
DestroyWindow(context->NetworkGraphHandle);
if (context->PanelHandle)
DestroyWindow(context->PanelHandle);
PhUnregisterCallback(&PhProcessesUpdatedEvent, &context->ProcessesUpdatedRegistration);
PhFree(context);
PhPropPageDlgProcDestroy(hwndDlg);
}
break;
case WM_SHOWWINDOW:
{
if (PhBeginPropPageLayout(hwndDlg, propPageContext))
PhEndPropPageLayout(hwndDlg, propPageContext);
}
break;
case WM_NOTIFY:
{
LPNMHDR header = (LPNMHDR)lParam;
switch (header->code)
{
case PSN_SETACTIVE:
context->Enabled = TRUE;
break;
case PSN_KILLACTIVE:
context->Enabled = FALSE;
break;
case GCN_GETDRAWINFO:
{
PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)header;
PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;
if (header->hwndFrom == context->DiskGraphHandle)
{
if (PhGetIntegerSetting(L"GraphShowText"))
{
HDC hdc;
PhMoveReference(&context->DiskGraphState.Text, PhFormatString(
L"R: %s, W: %s",
PhaFormatSize(context->CurrentDiskRead, -1)->Buffer,
PhaFormatSize(context->CurrentDiskWrite, -1)->Buffer
));
hdc = Graph_GetBufferedContext(context->DiskGraphHandle);
SelectObject(hdc, PhApplicationFont);
PhSetGraphText(hdc, drawInfo, &context->DiskGraphState.Text->sr,
&NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT);
}
else
{
drawInfo->Text.Buffer = NULL;
}
drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_LABEL_MAX_Y | PH_GRAPH_USE_LINE_2;
PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite"));
PhGraphStateGetDrawInfo(&context->DiskGraphState, getDrawInfo, context->DiskReadHistory.Count);
if (!context->DiskGraphState.Valid)
{
FLOAT max = 0;
for (ULONG i = 0; i < drawInfo->LineDataCount; i++)
{
FLOAT data1;
FLOAT data2;
context->DiskGraphState.Data1[i] = data1 = (FLOAT)PhGetItemCircularBuffer_ULONG64(&context->DiskReadHistory, i);
context->DiskGraphState.Data2[i] = data2 = (FLOAT)PhGetItemCircularBuffer_ULONG64(&context->DiskWriteHistory, i);
if (max < data1 + data2)
max = data1 + data2;
}
// Minimum scaling of 1 MB.
//if (max < 1024 * 1024)
// max = 1024 * 1024;
if (max != 0)
{
// Scale the data.
PhDivideSinglesBySingle(
context->DiskGraphState.Data1,
max,
drawInfo->LineDataCount
);
PhDivideSinglesBySingle(
context->DiskGraphState.Data2,
max,
drawInfo->LineDataCount
);
}
drawInfo->LabelYFunction = PhSiSizeLabelYFunction;
drawInfo->LabelYFunctionParameter = max;
context->DiskGraphState.Valid = TRUE;
}
}
else if (header->hwndFrom == context->NetworkGraphHandle)
{
if (PhGetIntegerSetting(L"GraphShowText"))
{
HDC hdc;
PhMoveReference(&context->NetworkGraphState.Text, PhFormatString(
L"R: %s, S: %s",
PhaFormatSize(context->CurrentNetworkReceive, -1)->Buffer,
PhaFormatSize(context->CurrentNetworkSend, -1)->Buffer
));
hdc = Graph_GetBufferedContext(context->NetworkGraphHandle);
SelectObject(hdc, PhApplicationFont);
PhSetGraphText(hdc, drawInfo, &context->NetworkGraphState.Text->sr,
&NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT);
}
else
{
drawInfo->Text.Buffer = NULL;
}
drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_LABEL_MAX_Y | PH_GRAPH_USE_LINE_2;
PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite"));
PhGraphStateGetDrawInfo(&context->NetworkGraphState, getDrawInfo, context->NetworkSendHistory.Count);
if (!context->NetworkGraphState.Valid)
{
FLOAT max = 0;
for (ULONG i = 0; i < drawInfo->LineDataCount; i++)
{
FLOAT data1;
FLOAT data2;
context->NetworkGraphState.Data1[i] = data1 = (FLOAT)PhGetItemCircularBuffer_ULONG64(&context->NetworkReceiveHistory, i);
context->NetworkGraphState.Data2[i] = data2 = (FLOAT)PhGetItemCircularBuffer_ULONG64(&context->NetworkSendHistory, i);
if (max < data1 + data2)
max = data1 + data2;
}
// Minimum scaling of 1 MB.
//if (max < 1024 * 1024)
// max = 1024 * 1024;
if (max != 0)
{
// Scale the data.
PhDivideSinglesBySingle(
context->NetworkGraphState.Data1,
max,
drawInfo->LineDataCount
);
PhDivideSinglesBySingle(
context->NetworkGraphState.Data2,
max,
drawInfo->LineDataCount
);
}
drawInfo->LabelYFunction = PhSiSizeLabelYFunction;
drawInfo->LabelYFunctionParameter = max;
context->NetworkGraphState.Valid = TRUE;
}
}
}
break;
case GCN_GETTOOLTIPTEXT:
{
PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)lParam;
if (getTooltipText->Index < getTooltipText->TotalCount)
{
if (header->hwndFrom == context->DiskGraphHandle)
{
if (context->DiskGraphState.TooltipIndex != getTooltipText->Index)
{
ULONG64 diskRead = PhGetItemCircularBuffer_ULONG64(
&context->DiskReadHistory,
getTooltipText->Index
);
ULONG64 diskWrite = PhGetItemCircularBuffer_ULONG64(
&context->DiskWriteHistory,
getTooltipText->Index
);
PhMoveReference(&context->DiskGraphState.TooltipText, PhFormatString(
L"R: %s\nW: %s\n%s",
PhaFormatSize(diskRead, -1)->Buffer,
PhaFormatSize(diskWrite, -1)->Buffer,
((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
));
}
getTooltipText->Text = context->DiskGraphState.TooltipText->sr;
}
else if (header->hwndFrom == context->NetworkGraphHandle)
{
if (context->NetworkGraphState.TooltipIndex != getTooltipText->Index)
{
ULONG64 networkSend = PhGetItemCircularBuffer_ULONG64(
&context->NetworkSendHistory,
getTooltipText->Index
);
ULONG64 networkReceive = PhGetItemCircularBuffer_ULONG64(
&context->NetworkReceiveHistory,
getTooltipText->Index
);
PhMoveReference(&context->NetworkGraphState.TooltipText, PhFormatString(
L"S: %s\nR: %s\n%s",
PhaFormatSize(networkSend, -1)->Buffer,
PhaFormatSize(networkReceive, -1)->Buffer,
((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
));
}
getTooltipText->Text = context->NetworkGraphState.TooltipText->sr;
}
}
}
break;
}
}
break;
case UPDATE_MSG:
{
if (context->Enabled)
{
EtwDiskNetworkUpdateInfo(context);
EtwDiskNetworkUpdateGraphs(context);
EtwDiskNetworkUpdatePanel(context);
}
}
break;
case WM_SIZE:
{
EtwDiskNetworkLayoutGraphs(context);
}
break;
}
return FALSE;
}
VOID EtProcessEtwPropertiesInitializing(
_In_ PVOID Parameter
)
{
PPH_PLUGIN_PROCESS_PROPCONTEXT propContext = Parameter;
if (EtEtwEnabled)
{
PhAddProcessPropPage(
propContext->PropContext,
PhCreateProcessPropPageContextEx(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_PROCDISKNET), EtwDiskNetworkPageDlgProc, NULL)
);
}
}

View File

@@ -0,0 +1,419 @@
/*
* Process Hacker Extended Tools -
* ETW statistics collection
*
* Copyright (C) 2010-2011 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 "exttools.h"
#include "etwmon.h"
VOID NTAPI EtEtwProcessesUpdatedCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
);
VOID NTAPI EtEtwNetworkItemsUpdatedCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
);
static PH_CALLBACK_REGISTRATION EtpProcessesUpdatedCallbackRegistration;
static PH_CALLBACK_REGISTRATION EtpNetworkItemsUpdatedCallbackRegistration;
ULONG EtpDiskReadRaw;
ULONG EtpDiskWriteRaw;
ULONG EtpNetworkReceiveRaw;
ULONG EtpNetworkSendRaw;
ULONG EtDiskReadCount;
ULONG EtDiskWriteCount;
ULONG EtNetworkReceiveCount;
ULONG EtNetworkSendCount;
PH_UINT32_DELTA EtDiskReadDelta;
PH_UINT32_DELTA EtDiskWriteDelta;
PH_UINT32_DELTA EtNetworkReceiveDelta;
PH_UINT32_DELTA EtNetworkSendDelta;
PH_UINT32_DELTA EtDiskReadCountDelta;
PH_UINT32_DELTA EtDiskWriteCountDelta;
PH_UINT32_DELTA EtNetworkReceiveCountDelta;
PH_UINT32_DELTA EtNetworkSendCountDelta;
PH_CIRCULAR_BUFFER_ULONG EtDiskReadHistory;
PH_CIRCULAR_BUFFER_ULONG EtDiskWriteHistory;
PH_CIRCULAR_BUFFER_ULONG EtNetworkReceiveHistory;
PH_CIRCULAR_BUFFER_ULONG EtNetworkSendHistory;
PH_CIRCULAR_BUFFER_ULONG EtMaxDiskHistory; // ID of max. disk usage process
PH_CIRCULAR_BUFFER_ULONG EtMaxNetworkHistory; // ID of max. network usage process
PVOID EtpProcessInformation;
PH_QUEUED_LOCK EtpProcessInformationLock = PH_QUEUED_LOCK_INIT;
VOID EtEtwStatisticsInitialization(
VOID
)
{
EtEtwMonitorInitialization();
if (EtEtwEnabled)
{
ULONG sampleCount;
sampleCount = PhGetIntegerSetting(L"SampleCount");
PhInitializeCircularBuffer_ULONG(&EtDiskReadHistory, sampleCount);
PhInitializeCircularBuffer_ULONG(&EtDiskWriteHistory, sampleCount);
PhInitializeCircularBuffer_ULONG(&EtNetworkReceiveHistory, sampleCount);
PhInitializeCircularBuffer_ULONG(&EtNetworkSendHistory, sampleCount);
PhInitializeCircularBuffer_ULONG(&EtMaxDiskHistory, sampleCount);
PhInitializeCircularBuffer_ULONG(&EtMaxNetworkHistory, sampleCount);
PhRegisterCallback(
&PhProcessesUpdatedEvent,
EtEtwProcessesUpdatedCallback,
NULL,
&EtpProcessesUpdatedCallbackRegistration
);
PhRegisterCallback(
&PhNetworkItemsUpdatedEvent,
EtEtwNetworkItemsUpdatedCallback,
NULL,
&EtpNetworkItemsUpdatedCallbackRegistration
);
}
}
VOID EtEtwStatisticsUninitialization(
VOID
)
{
EtEtwMonitorUninitialization();
}
VOID EtProcessDiskEvent(
_In_ PET_ETW_DISK_EVENT Event
)
{
PPH_PROCESS_ITEM processItem;
PET_PROCESS_BLOCK block;
if (Event->Type == EtEtwDiskReadType)
{
EtpDiskReadRaw += Event->TransferSize;
EtDiskReadCount++;
}
else
{
EtpDiskWriteRaw += Event->TransferSize;
EtDiskWriteCount++;
}
if (processItem = PhReferenceProcessItem(Event->ClientId.UniqueProcess))
{
block = EtGetProcessBlock(processItem);
if (Event->Type == EtEtwDiskReadType)
{
block->DiskReadRaw += Event->TransferSize;
block->DiskReadCount++;
}
else
{
block->DiskWriteRaw += Event->TransferSize;
block->DiskWriteCount++;
}
PhDereferenceObject(processItem);
}
}
VOID EtProcessNetworkEvent(
_In_ PET_ETW_NETWORK_EVENT Event
)
{
PPH_PROCESS_ITEM processItem;
PET_PROCESS_BLOCK block;
PPH_NETWORK_ITEM networkItem;
PET_NETWORK_BLOCK networkBlock;
if (Event->Type == EtEtwNetworkReceiveType)
{
EtpNetworkReceiveRaw += Event->TransferSize;
EtNetworkReceiveCount++;
}
else
{
EtpNetworkSendRaw += Event->TransferSize;
EtNetworkSendCount++;
}
// Note: there is always the possibility of us receiving the event too early,
// before the process item or network item is created. So events may be lost.
if (processItem = PhReferenceProcessItem(Event->ClientId.UniqueProcess))
{
block = EtGetProcessBlock(processItem);
if (Event->Type == EtEtwNetworkReceiveType)
{
block->NetworkReceiveRaw += Event->TransferSize;
block->NetworkReceiveCount++;
}
else
{
block->NetworkSendRaw += Event->TransferSize;
block->NetworkSendCount++;
}
PhDereferenceObject(processItem);
}
if (networkItem = PhReferenceNetworkItem(
Event->ProtocolType,
&Event->LocalEndpoint,
&Event->RemoteEndpoint,
Event->ClientId.UniqueProcess
))
{
networkBlock = EtGetNetworkBlock(networkItem);
if (Event->Type == EtEtwNetworkReceiveType)
{
networkBlock->ReceiveRaw += Event->TransferSize;
networkBlock->ReceiveCount++;
}
else
{
networkBlock->SendRaw += Event->TransferSize;
networkBlock->SendCount++;
}
PhDereferenceObject(networkItem);
}
}
VOID NTAPI EtEtwProcessesUpdatedCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
static ULONG runCount = 0; // MUST keep in sync with runCount in process provider
PLIST_ENTRY listEntry;
ULONG64 maxDiskValue = 0;
PET_PROCESS_BLOCK maxDiskBlock = NULL;
ULONG64 maxNetworkValue = 0;
PET_PROCESS_BLOCK maxNetworkBlock = NULL;
// Since Windows 8, we no longer get the correct process/thread IDs in the
// event headers for disk events. We need to update our process information since
// etwmon uses our EtThreadIdToProcessId function.
if (WindowsVersion >= WINDOWS_8)
EtUpdateProcessInformation();
// ETW is extremely lazy when it comes to flushing buffers, so we must do it
// manually.
EtFlushEtwSession();
// Update global statistics.
PhUpdateDelta(&EtDiskReadDelta, EtpDiskReadRaw);
PhUpdateDelta(&EtDiskWriteDelta, EtpDiskWriteRaw);
PhUpdateDelta(&EtNetworkReceiveDelta, EtpNetworkReceiveRaw);
PhUpdateDelta(&EtNetworkSendDelta, EtpNetworkSendRaw);
PhUpdateDelta(&EtDiskReadCountDelta, EtDiskReadCount);
PhUpdateDelta(&EtDiskWriteCountDelta, EtDiskWriteCount);
PhUpdateDelta(&EtNetworkReceiveCountDelta, EtNetworkReceiveCount);
PhUpdateDelta(&EtNetworkSendCountDelta, EtNetworkSendCount);
// Update per-process statistics.
// Note: no lock is needed because we only ever modify the list on this same thread.
listEntry = EtProcessBlockListHead.Flink;
while (listEntry != &EtProcessBlockListHead)
{
PET_PROCESS_BLOCK block;
block = CONTAINING_RECORD(listEntry, ET_PROCESS_BLOCK, ListEntry);
PhUpdateDelta(&block->DiskReadDelta, block->DiskReadCount);
PhUpdateDelta(&block->DiskReadRawDelta, block->DiskReadRaw);
PhUpdateDelta(&block->DiskWriteDelta, block->DiskWriteCount);
PhUpdateDelta(&block->DiskWriteRawDelta, block->DiskWriteRaw);
PhUpdateDelta(&block->NetworkReceiveDelta, block->NetworkReceiveCount);
PhUpdateDelta(&block->NetworkReceiveRawDelta, block->NetworkReceiveRaw);
PhUpdateDelta(&block->NetworkSendDelta, block->NetworkSendCount);
PhUpdateDelta(&block->NetworkSendRawDelta, block->NetworkSendRaw);
if (maxDiskValue < block->DiskReadRawDelta.Delta + block->DiskWriteRawDelta.Delta)
{
maxDiskValue = block->DiskReadRawDelta.Delta + block->DiskWriteRawDelta.Delta;
maxDiskBlock = block;
}
if (maxNetworkValue < block->NetworkReceiveRawDelta.Delta + block->NetworkSendRawDelta.Delta)
{
maxNetworkValue = block->NetworkReceiveRawDelta.Delta + block->NetworkSendRawDelta.Delta;
maxNetworkBlock = block;
}
listEntry = listEntry->Flink;
}
// Update history buffers.
if (runCount != 0)
{
PhAddItemCircularBuffer_ULONG(&EtDiskReadHistory, EtDiskReadDelta.Delta);
PhAddItemCircularBuffer_ULONG(&EtDiskWriteHistory, EtDiskWriteDelta.Delta);
PhAddItemCircularBuffer_ULONG(&EtNetworkReceiveHistory, EtNetworkReceiveDelta.Delta);
PhAddItemCircularBuffer_ULONG(&EtNetworkSendHistory, EtNetworkSendDelta.Delta);
if (maxDiskBlock)
{
PhAddItemCircularBuffer_ULONG(&EtMaxDiskHistory, HandleToUlong(maxDiskBlock->ProcessItem->ProcessId));
PhReferenceProcessRecordForStatistics(maxDiskBlock->ProcessItem->Record);
}
else
{
PhAddItemCircularBuffer_ULONG(&EtMaxDiskHistory, 0);
}
if (maxNetworkBlock)
{
PhAddItemCircularBuffer_ULONG(&EtMaxNetworkHistory, HandleToUlong(maxNetworkBlock->ProcessItem->ProcessId));
PhReferenceProcessRecordForStatistics(maxNetworkBlock->ProcessItem->Record);
}
else
{
PhAddItemCircularBuffer_ULONG(&EtMaxNetworkHistory, 0);
}
}
runCount++;
}
static VOID NTAPI EtpInvalidateNetworkNode(
_In_ PVOID Parameter
)
{
PPH_NETWORK_ITEM networkItem = Parameter;
PPH_NETWORK_NODE networkNode;
if (networkNode = PhFindNetworkNode(networkItem))
TreeNew_InvalidateNode(NetworkTreeNewHandle, &networkNode->Node);
PhDereferenceObject(networkItem);
}
VOID NTAPI EtEtwNetworkItemsUpdatedCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PLIST_ENTRY listEntry;
// ETW is flushed in the processes-updated callback above. This may cause us the network
// blocks to all fall one update interval behind, however.
// Update per-connection statistics.
// Note: no lock is needed because we only ever modify the list on this same thread.
listEntry = EtNetworkBlockListHead.Flink;
while (listEntry != &EtNetworkBlockListHead)
{
PET_NETWORK_BLOCK block;
PH_UINT64_DELTA oldDeltas[4];
block = CONTAINING_RECORD(listEntry, ET_NETWORK_BLOCK, ListEntry);
memcpy(oldDeltas, block->Deltas, sizeof(block->Deltas));
PhUpdateDelta(&block->ReceiveDelta, block->ReceiveCount);
PhUpdateDelta(&block->ReceiveRawDelta, block->ReceiveRaw);
PhUpdateDelta(&block->SendDelta, block->SendCount);
PhUpdateDelta(&block->SendRawDelta, block->SendRaw);
if (memcmp(oldDeltas, block->Deltas, sizeof(block->Deltas)))
{
// Values have changed. Invalidate the network node.
PhReferenceObject(block->NetworkItem);
ProcessHacker_Invoke(PhMainWndHandle, EtpInvalidateNetworkNode, block->NetworkItem);
}
listEntry = listEntry->Flink;
}
}
VOID EtUpdateProcessInformation(
VOID
)
{
PhAcquireQueuedLockExclusive(&EtpProcessInformationLock);
if (EtpProcessInformation)
{
PhFree(EtpProcessInformation);
EtpProcessInformation = NULL;
}
PhEnumProcesses(&EtpProcessInformation);
PhReleaseQueuedLockExclusive(&EtpProcessInformationLock);
}
HANDLE EtThreadIdToProcessId(
_In_ HANDLE ThreadId
)
{
PSYSTEM_PROCESS_INFORMATION process;
ULONG i;
HANDLE processId;
PhAcquireQueuedLockShared(&EtpProcessInformationLock);
if (!EtpProcessInformation)
{
PhReleaseQueuedLockShared(&EtpProcessInformationLock);
return NULL;
}
process = PH_FIRST_PROCESS(EtpProcessInformation);
do
{
for (i = 0; i < process->NumberOfThreads; i++)
{
if (process->Threads[i].ClientId.UniqueThread == ThreadId)
{
processId = process->UniqueProcessId;
PhReleaseQueuedLockShared(&EtpProcessInformationLock);
return processId;
}
}
} while (process = PH_NEXT_PROCESS(process));
PhReleaseQueuedLockShared(&EtpProcessInformationLock);
return NULL;
}

View File

@@ -0,0 +1,811 @@
/*
* Process Hacker Extended Tools -
* ETW system information section
*
* Copyright (C) 2010-2011 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 "exttools.h"
#include "etwsys.h"
static PPH_SYSINFO_SECTION DiskSection;
static HWND DiskDialog;
static PH_LAYOUT_MANAGER DiskLayoutManager;
static HWND DiskGraphHandle;
static PH_GRAPH_STATE DiskGraphState;
static HWND DiskPanel;
static PPH_SYSINFO_SECTION NetworkSection;
static HWND NetworkDialog;
static PH_LAYOUT_MANAGER NetworkLayoutManager;
static HWND NetworkGraphHandle;
static PH_GRAPH_STATE NetworkGraphState;
static HWND NetworkPanel;
VOID EtEtwSystemInformationInitializing(
_In_ PPH_PLUGIN_SYSINFO_POINTERS Pointers
)
{
PH_SYSINFO_SECTION section;
memset(&section, 0, sizeof(PH_SYSINFO_SECTION));
PhInitializeStringRef(&section.Name, L"Disk");
section.Flags = 0;
section.Callback = EtpDiskSysInfoSectionCallback;
DiskSection = Pointers->CreateSection(&section);
memset(&section, 0, sizeof(PH_SYSINFO_SECTION));
PhInitializeStringRef(&section.Name, L"Network");
section.Flags = 0;
section.Callback = EtpNetworkSysInfoSectionCallback;
NetworkSection = Pointers->CreateSection(&section);
}
BOOLEAN EtpDiskSysInfoSectionCallback(
_In_ PPH_SYSINFO_SECTION Section,
_In_ PH_SYSINFO_SECTION_MESSAGE Message,
_In_opt_ PVOID Parameter1,
_In_opt_ PVOID Parameter2
)
{
switch (Message)
{
case SysInfoDestroy:
{
if (DiskDialog)
{
PhDeleteGraphState(&DiskGraphState);
DiskDialog = NULL;
}
}
return TRUE;
case SysInfoTick:
{
if (DiskDialog)
{
EtpUpdateDiskGraph();
EtpUpdateDiskPanel();
}
}
return TRUE;
case SysInfoCreateDialog:
{
PPH_SYSINFO_CREATE_DIALOG createDialog = Parameter1;
createDialog->Instance = PluginInstance->DllBase;
createDialog->Template = MAKEINTRESOURCE(IDD_SYSINFO_DISK);
createDialog->DialogProc = EtpDiskDialogProc;
}
return TRUE;
case SysInfoGraphGetDrawInfo:
{
PPH_GRAPH_DRAW_INFO drawInfo = Parameter1;
drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_LABEL_MAX_Y | PH_GRAPH_USE_LINE_2;
Section->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite"));
PhGetDrawInfoGraphBuffers(&Section->GraphState.Buffers, drawInfo, EtDiskReadHistory.Count);
if (!Section->GraphState.Valid)
{
ULONG i;
FLOAT max = 1024 * 1024; // Minimum scaling of 1 MB
for (i = 0; i < drawInfo->LineDataCount; i++)
{
FLOAT data1;
FLOAT data2;
Section->GraphState.Data1[i] = data1 =
(FLOAT)PhGetItemCircularBuffer_ULONG(&EtDiskReadHistory, i);
Section->GraphState.Data2[i] = data2 =
(FLOAT)PhGetItemCircularBuffer_ULONG(&EtDiskWriteHistory, i);
if (max < data1 + data2)
max = data1 + data2;
}
if (max != 0)
{
// Scale the data.
PhDivideSinglesBySingle(
Section->GraphState.Data1,
max,
drawInfo->LineDataCount
);
PhDivideSinglesBySingle(
Section->GraphState.Data2,
max,
drawInfo->LineDataCount
);
}
drawInfo->LabelYFunction = PhSiSizeLabelYFunction;
drawInfo->LabelYFunctionParameter = max;
Section->GraphState.Valid = TRUE;
}
}
return TRUE;
case SysInfoGraphGetTooltipText:
{
PPH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT getTooltipText = Parameter1;
ULONG64 diskRead;
ULONG64 diskWrite;
diskRead = PhGetItemCircularBuffer_ULONG(&EtDiskReadHistory, getTooltipText->Index);
diskWrite = PhGetItemCircularBuffer_ULONG(&EtDiskWriteHistory, getTooltipText->Index);
PhMoveReference(&Section->GraphState.TooltipText, PhFormatString(
L"R: %s\nW: %s%s\n%s",
PhaFormatSize(diskRead, -1)->Buffer,
PhaFormatSize(diskWrite, -1)->Buffer,
PhGetStringOrEmpty(EtpGetMaxDiskString(getTooltipText->Index)),
((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
));
getTooltipText->Text = Section->GraphState.TooltipText->sr;
}
return TRUE;
case SysInfoGraphDrawPanel:
{
PPH_SYSINFO_DRAW_PANEL drawPanel = Parameter1;
drawPanel->Title = PhCreateString(L"Disk");
drawPanel->SubTitle = PhFormatString(
L"R: %s\nW: %s",
PhaFormatSize(EtDiskReadDelta.Delta, -1)->Buffer,
PhaFormatSize(EtDiskWriteDelta.Delta, -1)->Buffer
);
}
return TRUE;
}
return FALSE;
}
INT_PTR CALLBACK EtpDiskDialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
PPH_LAYOUT_ITEM graphItem;
PPH_LAYOUT_ITEM panelItem;
PhInitializeGraphState(&DiskGraphState);
DiskDialog = hwndDlg;
PhInitializeLayoutManager(&DiskLayoutManager, hwndDlg);
graphItem = PhAddLayoutItem(&DiskLayoutManager, GetDlgItem(hwndDlg, IDC_GRAPH_LAYOUT), NULL, PH_ANCHOR_ALL);
panelItem = PhAddLayoutItem(&DiskLayoutManager, GetDlgItem(hwndDlg, IDC_PANEL_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
SendMessage(GetDlgItem(hwndDlg, IDC_TITLE), WM_SETFONT, (WPARAM)DiskSection->Parameters->LargeFont, FALSE);
DiskPanel = CreateDialog(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_SYSINFO_DISKPANEL), hwndDlg, EtpDiskPanelDialogProc);
ShowWindow(DiskPanel, SW_SHOW);
PhAddLayoutItemEx(&DiskLayoutManager, DiskPanel, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM, panelItem->Margin);
DiskGraphHandle = CreateWindow(
PH_GRAPH_CLASSNAME,
NULL,
WS_VISIBLE | WS_CHILD | WS_BORDER,
0,
0,
3,
3,
hwndDlg,
NULL,
NULL,
NULL
);
Graph_SetTooltip(DiskGraphHandle, TRUE);
PhAddLayoutItemEx(&DiskLayoutManager, DiskGraphHandle, NULL, PH_ANCHOR_ALL, graphItem->Margin);
EtpUpdateDiskGraph();
EtpUpdateDiskPanel();
}
break;
case WM_DESTROY:
{
PhDeleteLayoutManager(&DiskLayoutManager);
}
break;
case WM_SIZE:
{
PhLayoutManagerLayout(&DiskLayoutManager);
}
break;
case WM_NOTIFY:
{
NMHDR *header = (NMHDR *)lParam;
if (header->hwndFrom == DiskGraphHandle)
{
EtpNotifyDiskGraph(header);
}
}
break;
}
return FALSE;
}
INT_PTR CALLBACK EtpDiskPanelDialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
return FALSE;
}
VOID EtpNotifyDiskGraph(
_In_ NMHDR *Header
)
{
switch (Header->code)
{
case GCN_GETDRAWINFO:
{
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_GRID_Y | PH_GRAPH_LABEL_MAX_Y | PH_GRAPH_USE_LINE_2;
DiskSection->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite"));
PhGraphStateGetDrawInfo(
&DiskGraphState,
getDrawInfo,
EtDiskReadHistory.Count
);
if (!DiskGraphState.Valid)
{
ULONG i;
FLOAT max = 1024 * 1024; // Minimum scaling of 1 MB
for (i = 0; i < drawInfo->LineDataCount; i++)
{
FLOAT data1;
FLOAT data2;
DiskGraphState.Data1[i] = data1 =
(FLOAT)PhGetItemCircularBuffer_ULONG(&EtDiskReadHistory, i);
DiskGraphState.Data2[i] = data2 =
(FLOAT)PhGetItemCircularBuffer_ULONG(&EtDiskWriteHistory, i);
if (max < data1 + data2)
max = data1 + data2;
}
if (max != 0)
{
// Scale the data.
PhDivideSinglesBySingle(
DiskGraphState.Data1,
max,
drawInfo->LineDataCount
);
PhDivideSinglesBySingle(
DiskGraphState.Data2,
max,
drawInfo->LineDataCount
);
}
drawInfo->LabelYFunction = PhSiSizeLabelYFunction;
drawInfo->LabelYFunctionParameter = max;
DiskGraphState.Valid = TRUE;
}
}
break;
case GCN_GETTOOLTIPTEXT:
{
PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header;
if (getTooltipText->Index < getTooltipText->TotalCount)
{
if (DiskGraphState.TooltipIndex != getTooltipText->Index)
{
ULONG64 diskRead;
ULONG64 diskWrite;
diskRead = PhGetItemCircularBuffer_ULONG(&EtDiskReadHistory, getTooltipText->Index);
diskWrite = PhGetItemCircularBuffer_ULONG(&EtDiskWriteHistory, getTooltipText->Index);
PhMoveReference(&DiskGraphState.TooltipText, PhFormatString(
L"R: %s\nW: %s%s\n%s",
PhaFormatSize(diskRead, -1)->Buffer,
PhaFormatSize(diskWrite, -1)->Buffer,
PhGetStringOrEmpty(EtpGetMaxDiskString(getTooltipText->Index)),
((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
));
}
getTooltipText->Text = DiskGraphState.TooltipText->sr;
}
}
break;
case GCN_MOUSEEVENT:
{
PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Header;
PPH_PROCESS_RECORD record;
record = NULL;
if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount)
{
record = EtpReferenceMaxDiskRecord(mouseEvent->Index);
}
if (record)
{
PhShowProcessRecordDialog(DiskDialog, record);
PhDereferenceProcessRecord(record);
}
}
break;
}
}
VOID EtpUpdateDiskGraph(
VOID
)
{
DiskGraphState.Valid = FALSE;
DiskGraphState.TooltipIndex = -1;
Graph_MoveGrid(DiskGraphHandle, 1);
Graph_Draw(DiskGraphHandle);
Graph_UpdateTooltip(DiskGraphHandle);
InvalidateRect(DiskGraphHandle, NULL, FALSE);
}
VOID EtpUpdateDiskPanel(
VOID
)
{
SetDlgItemText(DiskPanel, IDC_ZREADSDELTA_V, PhaFormatUInt64(EtDiskReadCountDelta.Delta, TRUE)->Buffer);
SetDlgItemText(DiskPanel, IDC_ZREADBYTESDELTA_V, PhaFormatSize(EtDiskReadDelta.Delta, -1)->Buffer);
SetDlgItemText(DiskPanel, IDC_ZWRITESDELTA_V, PhaFormatUInt64(EtDiskWriteCountDelta.Delta, TRUE)->Buffer);
SetDlgItemText(DiskPanel, IDC_ZWRITEBYTESDELTA_V, PhaFormatSize(EtDiskWriteDelta.Delta, -1)->Buffer);
}
PPH_PROCESS_RECORD EtpReferenceMaxDiskRecord(
_In_ LONG Index
)
{
LARGE_INTEGER time;
ULONG maxProcessId;
maxProcessId = PhGetItemCircularBuffer_ULONG(&EtMaxDiskHistory, Index);
if (!maxProcessId)
return NULL;
PhGetStatisticsTime(NULL, Index, &time);
time.QuadPart += PH_TICKS_PER_SEC - 1;
return PhFindProcessRecord(UlongToHandle(maxProcessId), &time);
}
PPH_STRING EtpGetMaxDiskString(
_In_ LONG Index
)
{
PPH_PROCESS_RECORD maxProcessRecord;
PPH_STRING maxUsageString = NULL;
if (maxProcessRecord = EtpReferenceMaxDiskRecord(Index))
{
maxUsageString = PhaFormatString(
L"\n%s (%lu)",
maxProcessRecord->ProcessName->Buffer,
HandleToUlong(maxProcessRecord->ProcessId)
);
PhDereferenceProcessRecord(maxProcessRecord);
}
return maxUsageString;
}
BOOLEAN EtpNetworkSysInfoSectionCallback(
_In_ PPH_SYSINFO_SECTION Section,
_In_ PH_SYSINFO_SECTION_MESSAGE Message,
_In_opt_ PVOID Parameter1,
_In_opt_ PVOID Parameter2
)
{
switch (Message)
{
case SysInfoDestroy:
{
if (NetworkDialog)
{
PhDeleteGraphState(&NetworkGraphState);
NetworkDialog = NULL;
}
}
return TRUE;
case SysInfoTick:
{
if (NetworkDialog)
{
EtpUpdateNetworkGraph();
EtpUpdateNetworkPanel();
}
}
return TRUE;
case SysInfoCreateDialog:
{
PPH_SYSINFO_CREATE_DIALOG createDialog = Parameter1;
createDialog->Instance = PluginInstance->DllBase;
createDialog->Template = MAKEINTRESOURCE(IDD_SYSINFO_NET);
createDialog->DialogProc = EtpNetworkDialogProc;
}
return TRUE;
case SysInfoGraphGetDrawInfo:
{
PPH_GRAPH_DRAW_INFO drawInfo = Parameter1;
drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_LABEL_MAX_Y | PH_GRAPH_USE_LINE_2;
Section->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite"));
PhGetDrawInfoGraphBuffers(&Section->GraphState.Buffers, drawInfo, EtNetworkReceiveHistory.Count);
if (!Section->GraphState.Valid)
{
ULONG i;
FLOAT max = 1024 * 1024; // Minimum scaling of 1 MB
for (i = 0; i < drawInfo->LineDataCount; i++)
{
FLOAT data1;
FLOAT data2;
Section->GraphState.Data1[i] = data1 =
(FLOAT)PhGetItemCircularBuffer_ULONG(&EtNetworkReceiveHistory, i);
Section->GraphState.Data2[i] = data2 =
(FLOAT)PhGetItemCircularBuffer_ULONG(&EtNetworkSendHistory, i);
if (max < data1 + data2)
max = data1 + data2;
}
if (max != 0)
{
// Scale the data.
PhDivideSinglesBySingle(
Section->GraphState.Data1,
max,
drawInfo->LineDataCount
);
PhDivideSinglesBySingle(
Section->GraphState.Data2,
max,
drawInfo->LineDataCount
);
}
drawInfo->LabelYFunction = PhSiSizeLabelYFunction;
drawInfo->LabelYFunctionParameter = max;
Section->GraphState.Valid = TRUE;
}
}
return TRUE;
case SysInfoGraphGetTooltipText:
{
PPH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT getTooltipText = Parameter1;
ULONG64 networkReceive;
ULONG64 networkSend;
networkReceive = PhGetItemCircularBuffer_ULONG(&EtNetworkReceiveHistory, getTooltipText->Index);
networkSend = PhGetItemCircularBuffer_ULONG(&EtNetworkSendHistory, getTooltipText->Index);
PhMoveReference(&Section->GraphState.TooltipText, PhFormatString(
L"R: %s\nS: %s%s\n%s",
PhaFormatSize(networkReceive, -1)->Buffer,
PhaFormatSize(networkSend, -1)->Buffer,
PhGetStringOrEmpty(EtpGetMaxNetworkString(getTooltipText->Index)),
((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
));
getTooltipText->Text = Section->GraphState.TooltipText->sr;
}
return TRUE;
case SysInfoGraphDrawPanel:
{
PPH_SYSINFO_DRAW_PANEL drawPanel = Parameter1;
drawPanel->Title = PhCreateString(L"Network");
drawPanel->SubTitle = PhFormatString(
L"R: %s\nS: %s",
PhaFormatSize(EtNetworkReceiveDelta.Delta, -1)->Buffer,
PhaFormatSize(EtNetworkSendDelta.Delta, -1)->Buffer
);
}
return TRUE;
}
return FALSE;
}
INT_PTR CALLBACK EtpNetworkDialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
PPH_LAYOUT_ITEM graphItem;
PPH_LAYOUT_ITEM panelItem;
PhInitializeGraphState(&NetworkGraphState);
NetworkDialog = hwndDlg;
PhInitializeLayoutManager(&NetworkLayoutManager, hwndDlg);
graphItem = PhAddLayoutItem(&NetworkLayoutManager, GetDlgItem(hwndDlg, IDC_GRAPH_LAYOUT), NULL, PH_ANCHOR_ALL);
panelItem = PhAddLayoutItem(&NetworkLayoutManager, GetDlgItem(hwndDlg, IDC_PANEL_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
SendMessage(GetDlgItem(hwndDlg, IDC_TITLE), WM_SETFONT, (WPARAM)NetworkSection->Parameters->LargeFont, FALSE);
NetworkPanel = CreateDialog(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_SYSINFO_NETPANEL), hwndDlg, EtpNetworkPanelDialogProc);
ShowWindow(NetworkPanel, SW_SHOW);
PhAddLayoutItemEx(&NetworkLayoutManager, NetworkPanel, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM, panelItem->Margin);
NetworkGraphHandle = CreateWindow(
PH_GRAPH_CLASSNAME,
NULL,
WS_VISIBLE | WS_CHILD | WS_BORDER,
0,
0,
3,
3,
hwndDlg,
NULL,
NULL,
NULL
);
Graph_SetTooltip(NetworkGraphHandle, TRUE);
PhAddLayoutItemEx(&NetworkLayoutManager, NetworkGraphHandle, NULL, PH_ANCHOR_ALL, graphItem->Margin);
EtpUpdateNetworkGraph();
EtpUpdateNetworkPanel();
}
break;
case WM_DESTROY:
{
PhDeleteLayoutManager(&NetworkLayoutManager);
}
break;
case WM_SIZE:
{
PhLayoutManagerLayout(&NetworkLayoutManager);
}
break;
case WM_NOTIFY:
{
NMHDR *header = (NMHDR *)lParam;
if (header->hwndFrom == NetworkGraphHandle)
{
EtpNotifyNetworkGraph(header);
}
}
break;
}
return FALSE;
}
INT_PTR CALLBACK EtpNetworkPanelDialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
return FALSE;
}
VOID EtpNotifyNetworkGraph(
_In_ NMHDR *Header
)
{
switch (Header->code)
{
case GCN_GETDRAWINFO:
{
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_GRID_Y | PH_GRAPH_LABEL_MAX_Y | PH_GRAPH_USE_LINE_2;
NetworkSection->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite"));
PhGraphStateGetDrawInfo(
&NetworkGraphState,
getDrawInfo,
EtNetworkReceiveHistory.Count
);
if (!NetworkGraphState.Valid)
{
ULONG i;
FLOAT max = 1024 * 1024; // Minimum scaling of 1 MB
for (i = 0; i < drawInfo->LineDataCount; i++)
{
FLOAT data1;
FLOAT data2;
NetworkGraphState.Data1[i] = data1 =
(FLOAT)PhGetItemCircularBuffer_ULONG(&EtNetworkReceiveHistory, i);
NetworkGraphState.Data2[i] = data2 =
(FLOAT)PhGetItemCircularBuffer_ULONG(&EtNetworkSendHistory, i);
if (max < data1 + data2)
max = data1 + data2;
}
if (max != 0)
{
// Scale the data.
PhDivideSinglesBySingle(
NetworkGraphState.Data1,
max,
drawInfo->LineDataCount
);
PhDivideSinglesBySingle(
NetworkGraphState.Data2,
max,
drawInfo->LineDataCount
);
}
drawInfo->LabelYFunction = PhSiSizeLabelYFunction;
drawInfo->LabelYFunctionParameter = max;
NetworkGraphState.Valid = TRUE;
}
}
break;
case GCN_GETTOOLTIPTEXT:
{
PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header;
if (getTooltipText->Index < getTooltipText->TotalCount)
{
if (NetworkGraphState.TooltipIndex != getTooltipText->Index)
{
ULONG64 networkReceive;
ULONG64 networkSend;
networkReceive = PhGetItemCircularBuffer_ULONG(&EtNetworkReceiveHistory, getTooltipText->Index);
networkSend = PhGetItemCircularBuffer_ULONG(&EtNetworkSendHistory, getTooltipText->Index);
PhMoveReference(&NetworkGraphState.TooltipText, PhFormatString(
L"R: %s\nS: %s%s\n%s",
PhaFormatSize(networkReceive, -1)->Buffer,
PhaFormatSize(networkSend, -1)->Buffer,
PhGetStringOrEmpty(EtpGetMaxNetworkString(getTooltipText->Index)),
((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
));
}
getTooltipText->Text = NetworkGraphState.TooltipText->sr;
}
}
break;
case GCN_MOUSEEVENT:
{
PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Header;
PPH_PROCESS_RECORD record;
record = NULL;
if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount)
{
record = EtpReferenceMaxNetworkRecord(mouseEvent->Index);
}
if (record)
{
PhShowProcessRecordDialog(NetworkDialog, record);
PhDereferenceProcessRecord(record);
}
}
break;
}
}
VOID EtpUpdateNetworkGraph(
VOID
)
{
NetworkGraphState.Valid = FALSE;
NetworkGraphState.TooltipIndex = -1;
Graph_MoveGrid(NetworkGraphHandle, 1);
Graph_Draw(NetworkGraphHandle);
Graph_UpdateTooltip(NetworkGraphHandle);
InvalidateRect(NetworkGraphHandle, NULL, FALSE);
}
VOID EtpUpdateNetworkPanel(
VOID
)
{
SetDlgItemText(NetworkPanel, IDC_ZRECEIVESDELTA_V, PhaFormatUInt64(EtNetworkReceiveCountDelta.Delta, TRUE)->Buffer);
SetDlgItemText(NetworkPanel, IDC_ZRECEIVEBYTESDELTA_V, PhaFormatSize(EtNetworkReceiveDelta.Delta, -1)->Buffer);
SetDlgItemText(NetworkPanel, IDC_ZSENDSDELTA_V, PhaFormatUInt64(EtNetworkSendCountDelta.Delta, TRUE)->Buffer);
SetDlgItemText(NetworkPanel, IDC_ZSENDBYTESDELTA_V, PhaFormatSize(EtNetworkSendDelta.Delta, -1)->Buffer);
}
PPH_PROCESS_RECORD EtpReferenceMaxNetworkRecord(
_In_ LONG Index
)
{
LARGE_INTEGER time;
ULONG maxProcessId;
maxProcessId = PhGetItemCircularBuffer_ULONG(&EtMaxNetworkHistory, Index);
if (!maxProcessId)
return NULL;
PhGetStatisticsTime(NULL, Index, &time);
time.QuadPart += PH_TICKS_PER_SEC - 1;
return PhFindProcessRecord(UlongToHandle(maxProcessId), &time);
}
PPH_STRING EtpGetMaxNetworkString(
_In_ LONG Index
)
{
PPH_PROCESS_RECORD maxProcessRecord;
PPH_STRING maxUsageString = NULL;
if (maxProcessRecord = EtpReferenceMaxNetworkRecord(Index))
{
maxUsageString = PhaFormatString(
L"\n%s (%lu)",
maxProcessRecord->ProcessName->Buffer,
HandleToUlong(maxProcessRecord->ProcessId)
);
PhDereferenceProcessRecord(maxProcessRecord);
}
return maxUsageString;
}

View File

@@ -0,0 +1,90 @@
#ifndef ETWSYS_H
#define ETWSYS_H
// Disk section
BOOLEAN EtpDiskSysInfoSectionCallback(
_In_ PPH_SYSINFO_SECTION Section,
_In_ PH_SYSINFO_SECTION_MESSAGE Message,
_In_opt_ PVOID Parameter1,
_In_opt_ PVOID Parameter2
);
INT_PTR CALLBACK EtpDiskDialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
INT_PTR CALLBACK EtpDiskPanelDialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
VOID EtpNotifyDiskGraph(
_In_ NMHDR *Header
);
VOID EtpUpdateDiskGraph(
VOID
);
VOID EtpUpdateDiskPanel(
VOID
);
PPH_PROCESS_RECORD EtpReferenceMaxDiskRecord(
_In_ LONG Index
);
PPH_STRING EtpGetMaxDiskString(
_In_ LONG Index
);
// Network section
BOOLEAN EtpNetworkSysInfoSectionCallback(
_In_ PPH_SYSINFO_SECTION Section,
_In_ PH_SYSINFO_SECTION_MESSAGE Message,
_In_opt_ PVOID Parameter1,
_In_opt_ PVOID Parameter2
);
INT_PTR CALLBACK EtpNetworkDialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
INT_PTR CALLBACK EtpNetworkPanelDialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
VOID EtpNotifyNetworkGraph(
_In_ NMHDR *Header
);
VOID EtpUpdateNetworkGraph(
VOID
);
VOID EtpUpdateNetworkPanel(
VOID
);
PPH_PROCESS_RECORD EtpReferenceMaxNetworkRecord(
_In_ LONG Index
);
PPH_STRING EtpGetMaxNetworkString(
_In_ LONG Index
);
#endif

View File

@@ -0,0 +1,549 @@
#ifndef EXTTOOLS_H
#define EXTTOOLS_H
#define PHNT_VERSION PHNT_VISTA
#include <phdk.h>
#include <windowsx.h>
#include <math.h>
#include "resource.h"
extern PPH_PLUGIN PluginInstance;
extern LIST_ENTRY EtProcessBlockListHead;
extern LIST_ENTRY EtNetworkBlockListHead;
extern HWND ProcessTreeNewHandle;
extern HWND NetworkTreeNewHandle;
#define PLUGIN_NAME L"ProcessHacker.ExtendedTools"
#define SETTING_NAME_DISK_TREE_LIST_COLUMNS (PLUGIN_NAME L".DiskTreeListColumns")
#define SETTING_NAME_DISK_TREE_LIST_SORT (PLUGIN_NAME L".DiskTreeListSort")
#define SETTING_NAME_ENABLE_ETW_MONITOR (PLUGIN_NAME L".EnableEtwMonitor")
#define SETTING_NAME_ENABLE_GPU_MONITOR (PLUGIN_NAME L".EnableGpuMonitor")
#define SETTING_NAME_GPU_NODE_BITMAP (PLUGIN_NAME L".GpuNodeBitmap")
#define SETTING_NAME_GPU_LAST_NODE_COUNT (PLUGIN_NAME L".GpuLastNodeCount")
#define ET_SCALE_DPI(Value) PhMultiplyDivide(Value, PhGlobalDpi, 96)
// Graph update message
#define UPDATE_MSG (WM_APP + 1)
// Process icon
typedef struct _ET_PROCESS_ICON
{
LONG RefCount;
HICON Icon;
} ET_PROCESS_ICON, *PET_PROCESS_ICON;
// Disk item
#define HISTORY_SIZE 60
typedef struct _ET_DISK_ITEM
{
LIST_ENTRY AgeListEntry;
ULONG AddTime;
ULONG FreshTime;
HANDLE ProcessId;
PPH_STRING FileName;
PPH_STRING FileNameWin32;
PPH_STRING ProcessName;
PET_PROCESS_ICON ProcessIcon;
PPH_PROCESS_RECORD ProcessRecord;
ULONG IoPriority;
ULONG ResponseTimeCount;
FLOAT ResponseTimeTotal; // in milliseconds
FLOAT ResponseTimeAverage;
ULONG64 ReadTotal;
ULONG64 WriteTotal;
ULONG64 ReadDelta;
ULONG64 WriteDelta;
ULONG64 ReadAverage;
ULONG64 WriteAverage;
ULONG64 ReadHistory[HISTORY_SIZE];
ULONG64 WriteHistory[HISTORY_SIZE];
ULONG HistoryCount;
ULONG HistoryPosition;
} ET_DISK_ITEM, *PET_DISK_ITEM;
// Disk node
#define ETDSTNC_NAME 0
#define ETDSTNC_FILE 1
#define ETDSTNC_READRATEAVERAGE 2
#define ETDSTNC_WRITERATEAVERAGE 3
#define ETDSTNC_TOTALRATEAVERAGE 4
#define ETDSTNC_IOPRIORITY 5
#define ETDSTNC_RESPONSETIME 6
#define ETDSTNC_MAXIMUM 7
typedef struct _ET_DISK_NODE
{
PH_TREENEW_NODE Node;
PET_DISK_ITEM DiskItem;
PH_STRINGREF TextCache[ETDSTNC_MAXIMUM];
PPH_STRING ProcessNameText;
PPH_STRING ReadRateAverageText;
PPH_STRING WriteRateAverageText;
PPH_STRING TotalRateAverageText;
PPH_STRING ResponseTimeText;
PPH_STRING TooltipText;
} ET_DISK_NODE, *PET_DISK_NODE;
// Process tree columns
#define ETPRTNC_DISKREADS 1
#define ETPRTNC_DISKWRITES 2
#define ETPRTNC_DISKREADBYTES 3
#define ETPRTNC_DISKWRITEBYTES 4
#define ETPRTNC_DISKTOTALBYTES 5
#define ETPRTNC_DISKREADSDELTA 6
#define ETPRTNC_DISKWRITESDELTA 7
#define ETPRTNC_DISKREADBYTESDELTA 8
#define ETPRTNC_DISKWRITEBYTESDELTA 9
#define ETPRTNC_DISKTOTALBYTESDELTA 10
#define ETPRTNC_NETWORKRECEIVES 11
#define ETPRTNC_NETWORKSENDS 12
#define ETPRTNC_NETWORKRECEIVEBYTES 13
#define ETPRTNC_NETWORKSENDBYTES 14
#define ETPRTNC_NETWORKTOTALBYTES 15
#define ETPRTNC_NETWORKRECEIVESDELTA 16
#define ETPRTNC_NETWORKSENDSDELTA 17
#define ETPRTNC_NETWORKRECEIVEBYTESDELTA 18
#define ETPRTNC_NETWORKSENDBYTESDELTA 19
#define ETPRTNC_NETWORKTOTALBYTESDELTA 20
#define ETPRTNC_HARDFAULTS 21
#define ETPRTNC_HARDFAULTSDELTA 22
#define ETPRTNC_PEAKTHREADS 23
#define ETPRTNC_GPU 24
#define ETPRTNC_GPUDEDICATEDBYTES 25
#define ETPRTNC_GPUSHAREDBYTES 26
#define ETPRTNC_DISKREADRATE 27
#define ETPRTNC_DISKWRITERATE 28
#define ETPRTNC_DISKTOTALRATE 29
#define ETPRTNC_NETWORKRECEIVERATE 30
#define ETPRTNC_NETWORKSENDRATE 31
#define ETPRTNC_NETWORKTOTALRATE 32
#define ETPRTNC_MAXIMUM 32
// Network list columns
#define ETNETNC_RECEIVES 1
#define ETNETNC_SENDS 2
#define ETNETNC_RECEIVEBYTES 3
#define ETNETNC_SENDBYTES 4
#define ETNETNC_TOTALBYTES 5
#define ETNETNC_RECEIVESDELTA 6
#define ETNETNC_SENDSDELTA 7
#define ETNETNC_RECEIVEBYTESDELTA 8
#define ETNETNC_SENDBYTESDELTA 9
#define ETNETNC_TOTALBYTESDELTA 10
#define ETNETNC_FIREWALLSTATUS 11
#define ETNETNC_RECEIVERATE 12
#define ETNETNC_SENDRATE 13
#define ETNETNC_TOTALRATE 14
#define ETNETNC_MAXIMUM 14
// Firewall status
typedef enum _ET_FIREWALL_STATUS
{
FirewallUnknownStatus,
FirewallAllowedNotRestricted,
FirewallAllowedRestricted,
FirewallNotAllowedNotRestricted,
FirewallNotAllowedRestricted,
FirewallMaximumStatus
} ET_FIREWALL_STATUS;
// Object extensions
typedef struct _ET_PROCESS_BLOCK
{
LIST_ENTRY ListEntry;
PPH_PROCESS_ITEM ProcessItem;
ULONG64 DiskReadCount;
ULONG64 DiskWriteCount;
ULONG64 NetworkReceiveCount;
ULONG64 NetworkSendCount;
ULONG64 DiskReadRaw;
ULONG64 DiskWriteRaw;
ULONG64 NetworkReceiveRaw;
ULONG64 NetworkSendRaw;
PH_UINT64_DELTA DiskReadDelta;
PH_UINT64_DELTA DiskReadRawDelta;
PH_UINT64_DELTA DiskWriteDelta;
PH_UINT64_DELTA DiskWriteRawDelta;
PH_UINT64_DELTA NetworkReceiveDelta;
PH_UINT64_DELTA NetworkReceiveRawDelta;
PH_UINT64_DELTA NetworkSendDelta;
PH_UINT64_DELTA NetworkSendRawDelta;
PH_UINT64_DELTA GpuRunningTimeDelta;
FLOAT GpuNodeUsage;
ULONG64 GpuDedicatedUsage;
ULONG64 GpuSharedUsage;
PH_UINT32_DELTA HardFaultsDelta;
PH_QUEUED_LOCK TextCacheLock;
PPH_STRING TextCache[ETPRTNC_MAXIMUM + 1];
BOOLEAN TextCacheValid[ETPRTNC_MAXIMUM + 1];
PET_PROCESS_ICON SmallProcessIcon;
} ET_PROCESS_BLOCK, *PET_PROCESS_BLOCK;
typedef struct _ET_NETWORK_BLOCK
{
LIST_ENTRY ListEntry;
PPH_NETWORK_ITEM NetworkItem;
ULONG64 ReceiveCount;
ULONG64 SendCount;
ULONG64 ReceiveRaw;
ULONG64 SendRaw;
union
{
struct
{
PH_UINT64_DELTA ReceiveDelta;
PH_UINT64_DELTA ReceiveRawDelta;
PH_UINT64_DELTA SendDelta;
PH_UINT64_DELTA SendRawDelta;
};
PH_UINT64_DELTA Deltas[4];
};
ET_FIREWALL_STATUS FirewallStatus;
BOOLEAN FirewallStatusValid;
PH_QUEUED_LOCK TextCacheLock;
PPH_STRING TextCache[ETNETNC_MAXIMUM + 1];
BOOLEAN TextCacheValid[ETNETNC_MAXIMUM + 1];
} ET_NETWORK_BLOCK, *PET_NETWORK_BLOCK;
// main
PET_PROCESS_BLOCK EtGetProcessBlock(
_In_ PPH_PROCESS_ITEM ProcessItem
);
PET_NETWORK_BLOCK EtGetNetworkBlock(
_In_ PPH_NETWORK_ITEM NetworkItem
);
// utils
VOID EtFormatRate(
_In_ ULONG64 ValuePerPeriod,
_Inout_ PPH_STRING *Buffer,
_Out_opt_ PPH_STRINGREF String
);
// etwmon
extern BOOLEAN EtEtwEnabled;
// etwstat
extern ULONG EtDiskReadCount;
extern ULONG EtDiskWriteCount;
extern ULONG EtNetworkReceiveCount;
extern ULONG EtNetworkSendCount;
extern PH_UINT32_DELTA EtDiskReadDelta;
extern PH_UINT32_DELTA EtDiskWriteDelta;
extern PH_UINT32_DELTA EtNetworkReceiveDelta;
extern PH_UINT32_DELTA EtNetworkSendDelta;
extern PH_UINT32_DELTA EtDiskReadCountDelta;
extern PH_UINT32_DELTA EtDiskWriteCountDelta;
extern PH_UINT32_DELTA EtNetworkReceiveCountDelta;
extern PH_UINT32_DELTA EtNetworkSendCountDelta;
extern PH_CIRCULAR_BUFFER_ULONG EtDiskReadHistory;
extern PH_CIRCULAR_BUFFER_ULONG EtDiskWriteHistory;
extern PH_CIRCULAR_BUFFER_ULONG EtNetworkReceiveHistory;
extern PH_CIRCULAR_BUFFER_ULONG EtNetworkSendHistory;
extern PH_CIRCULAR_BUFFER_ULONG EtMaxDiskHistory;
extern PH_CIRCULAR_BUFFER_ULONG EtMaxNetworkHistory;
VOID EtEtwStatisticsInitialization(
VOID
);
VOID EtEtwStatisticsUninitialization(
VOID
);
// etwdisk
extern BOOLEAN EtDiskEnabled;
extern PPH_OBJECT_TYPE EtDiskItemType;
extern PH_CALLBACK EtDiskItemAddedEvent;
extern PH_CALLBACK EtDiskItemModifiedEvent;
extern PH_CALLBACK EtDiskItemRemovedEvent;
extern PH_CALLBACK EtDiskItemsUpdatedEvent;
VOID EtInitializeDiskInformation(
VOID
);
PET_DISK_ITEM EtCreateDiskItem(
VOID
);
PET_DISK_ITEM EtReferenceDiskItem(
_In_ HANDLE ProcessId,
_In_ PPH_STRING FileName
);
PPH_STRING EtFileObjectToFileName(
_In_ PVOID FileObject
);
// procicon
PET_PROCESS_ICON EtProcIconCreateProcessIcon(
_In_ HICON Icon
);
VOID EtProcIconReferenceProcessIcon(
_Inout_ PET_PROCESS_ICON ProcessIcon
);
VOID EtProcIconDereferenceProcessIcon(
_Inout_ PET_PROCESS_ICON ProcessIcon
);
PET_PROCESS_ICON EtProcIconReferenceSmallProcessIcon(
_Inout_ PET_PROCESS_BLOCK Block
);
VOID EtProcIconNotifyProcessDelete(
_Inout_ PET_PROCESS_BLOCK Block
);
// etwprprp
VOID EtProcessEtwPropertiesInitializing(
_In_ PVOID Parameter
);
// disktab
VOID EtInitializeDiskTab(
VOID
);
VOID EtLoadSettingsDiskTreeList(
VOID
);
VOID EtSaveSettingsDiskTreeList(
VOID
);
// gpumon
extern BOOLEAN EtGpuEnabled;
extern ULONG EtGpuTotalNodeCount;
extern ULONG EtGpuTotalSegmentCount;
extern ULONG64 EtGpuDedicatedLimit;
extern ULONG64 EtGpuSharedLimit;
extern RTL_BITMAP EtGpuNodeBitMap;
extern PH_UINT64_DELTA EtClockTotalRunningTimeDelta;
extern LARGE_INTEGER EtClockTotalRunningTimeFrequency;
extern PH_UINT64_DELTA EtGpuTotalRunningTimeDelta;
extern PH_UINT64_DELTA EtGpuSystemRunningTimeDelta;
extern FLOAT EtGpuNodeUsage;
extern PH_CIRCULAR_BUFFER_FLOAT EtGpuNodeHistory;
extern PH_CIRCULAR_BUFFER_ULONG EtMaxGpuNodeHistory; // ID of max. GPU usage process
extern PH_CIRCULAR_BUFFER_FLOAT EtMaxGpuNodeUsageHistory;
extern PPH_UINT64_DELTA EtGpuNodesTotalRunningTimeDelta;
extern PPH_CIRCULAR_BUFFER_FLOAT EtGpuNodesHistory;
extern ULONG64 EtGpuDedicatedUsage;
extern ULONG64 EtGpuSharedUsage;
extern PH_CIRCULAR_BUFFER_ULONG EtGpuDedicatedHistory;
extern PH_CIRCULAR_BUFFER_ULONG EtGpuSharedHistory;
VOID EtGpuMonitorInitialization(
VOID
);
typedef struct _ET_PROCESS_GPU_STATISTICS
{
ULONG SegmentCount;
ULONG NodeCount;
ULONG64 DedicatedCommitted;
ULONG64 SharedCommitted;
ULONG64 BytesAllocated;
ULONG64 BytesReserved;
ULONG64 WriteCombinedBytesAllocated;
ULONG64 WriteCombinedBytesReserved;
ULONG64 CachedBytesAllocated;
ULONG64 CachedBytesReserved;
ULONG64 SectionBytesAllocated;
ULONG64 SectionBytesReserved;
ULONG64 RunningTime;
ULONG64 ContextSwitches;
} ET_PROCESS_GPU_STATISTICS, *PET_PROCESS_GPU_STATISTICS;
VOID EtSaveGpuMonitorSettings(
VOID
);
ULONG EtGetGpuAdapterCount(
VOID
);
ULONG EtGetGpuAdapterIndexFromNodeIndex(
_In_ ULONG NodeIndex
);
PPH_STRING EtGetGpuAdapterDescription(
_In_ ULONG Index
);
VOID EtAllocateGpuNodeBitMap(
_Out_ PRTL_BITMAP BitMap
);
VOID EtUpdateGpuNodeBitMap(
_In_ PRTL_BITMAP NewBitMap
);
VOID EtQueryProcessGpuStatistics(
_In_ HANDLE ProcessHandle,
_Out_ PET_PROCESS_GPU_STATISTICS Statistics
);
// gpuprprp
VOID EtProcessGpuPropertiesInitializing(
_In_ PVOID Parameter
);
// treeext
VOID EtProcessTreeNewInitializing(
_In_ PVOID Parameter
);
VOID EtProcessTreeNewMessage(
_In_ PVOID Parameter
);
VOID EtNetworkTreeNewInitializing(
_In_ PVOID Parameter
);
VOID EtNetworkTreeNewMessage(
_In_ PVOID Parameter
);
ET_FIREWALL_STATUS EtQueryFirewallStatus(
_In_ PPH_NETWORK_ITEM NetworkItem
);
// etwsys
VOID EtEtwSystemInformationInitializing(
_In_ PPH_PLUGIN_SYSINFO_POINTERS Pointers
);
// etwmini
VOID EtEtwMiniInformationInitializing(
_In_ PPH_PLUGIN_MINIINFO_POINTERS Pointers
);
// gpunodes
VOID EtShowGpuNodesDialog(
_In_ HWND ParentWindowHandle,
_In_ PPH_SYSINFO_PARAMETERS Parameters
);
// gpusys
VOID EtGpuSystemInformationInitializing(
_In_ PPH_PLUGIN_SYSINFO_POINTERS Pointers
);
// gpumini
VOID EtGpuMiniInformationInitializing(
_In_ PPH_PLUGIN_MINIINFO_POINTERS Pointers
);
// iconext
VOID EtRegisterNotifyIcons(
VOID
);
// modsrv
VOID EtShowModuleServicesDialog(
_In_ HWND ParentWindowHandle,
_In_ HANDLE ProcessId,
_In_ PWSTR ModuleName
);
// objprp
VOID EtHandlePropertiesInitializing(
_In_ PVOID Parameter
);
// options
VOID EtShowOptionsDialog(
_In_ HWND ParentWindowHandle
);
// thrdact
BOOLEAN EtUiCancelIoThread(
_In_ HWND hWnd,
_In_ PPH_THREAD_ITEM Thread
);
// unldll
VOID EtShowUnloadedDllsDialog(
_In_ HWND ParentWindowHandle,
_In_ PPH_PROCESS_ITEM ProcessItem
);
// wswatch
VOID EtShowWsWatchDialog(
_In_ HWND ParentWindowHandle,
_In_ PPH_PROCESS_ITEM ProcessItem
);
#endif

View File

@@ -0,0 +1,129 @@
/*
* Process Hacker Extended Tools -
* GPU mini information section
*
* Copyright (C) 2015 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 "exttools.h"
#include "gpumini.h"
VOID EtGpuMiniInformationInitializing(
_In_ PPH_PLUGIN_MINIINFO_POINTERS Pointers
)
{
PH_MINIINFO_LIST_SECTION section;
memset(&section, 0, sizeof(PH_MINIINFO_LIST_SECTION));
section.Callback = EtpGpuListSectionCallback;
Pointers->CreateListSection(L"GPU", 0, &section);
}
BOOLEAN EtpGpuListSectionCallback(
_In_ struct _PH_MINIINFO_LIST_SECTION *ListSection,
_In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message,
_In_opt_ PVOID Parameter1,
_In_opt_ PVOID Parameter2
)
{
switch (Message)
{
case MiListSectionTick:
{
ListSection->Section->Parameters->SetSectionText(ListSection->Section,
PhaFormatString(L"GPU %.2f%%", EtGpuNodeUsage * 100));
}
break;
case MiListSectionSortProcessList:
{
PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1;
qsort(sortList->List->Items, sortList->List->Count,
sizeof(PPH_PROCESS_NODE), EtpGpuListSectionProcessCompareFunction);
}
return TRUE;
case MiListSectionAssignSortData:
{
PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA assignSortData = Parameter1;
PPH_LIST processes = assignSortData->ProcessGroup->Processes;
FLOAT gpuUsage = 0;
ULONG i;
for (i = 0; i < processes->Count; i++)
{
PPH_PROCESS_ITEM processItem = processes->Items[i];
PET_PROCESS_BLOCK block = EtGetProcessBlock(processItem);
gpuUsage += block->GpuNodeUsage;
}
*(PFLOAT)assignSortData->SortData->UserData = gpuUsage;
}
return TRUE;
case MiListSectionSortGroupList:
{
PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1;
qsort(sortList->List->Items, sortList->List->Count,
sizeof(PPH_MINIINFO_LIST_SECTION_SORT_DATA), EtpGpuListSectionNodeCompareFunction);
}
return TRUE;
case MiListSectionGetUsageText:
{
PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT getUsageText = Parameter1;
PPH_LIST processes = getUsageText->ProcessGroup->Processes;
FLOAT gpuUsage = *(PFLOAT)getUsageText->SortData->UserData;
PhMoveReference(&getUsageText->Line1, PhFormatString(L"%.2f%%", gpuUsage * 100));
}
return TRUE;
}
return FALSE;
}
int __cdecl EtpGpuListSectionProcessCompareFunction(
_In_ const void *elem1,
_In_ const void *elem2
)
{
int result;
PPH_PROCESS_NODE node1 = *(PPH_PROCESS_NODE *)elem1;
PPH_PROCESS_NODE node2 = *(PPH_PROCESS_NODE *)elem2;
PET_PROCESS_BLOCK block1 = EtGetProcessBlock(node1->ProcessItem);
PET_PROCESS_BLOCK block2 = EtGetProcessBlock(node2->ProcessItem);
result = singlecmp(block2->GpuNodeUsage, block1->GpuNodeUsage);
if (result == 0)
result = uint64cmp(block2->GpuRunningTimeDelta.Value, block1->GpuRunningTimeDelta.Value);
if (result == 0)
result = singlecmp(node2->ProcessItem->CpuUsage, node1->ProcessItem->CpuUsage);
return result;
}
int __cdecl EtpGpuListSectionNodeCompareFunction(
_In_ const void *elem1,
_In_ const void *elem2
)
{
PPH_MINIINFO_LIST_SECTION_SORT_DATA data1 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem1;
PPH_MINIINFO_LIST_SECTION_SORT_DATA data2 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem2;
return singlecmp(*(PFLOAT)data2->UserData, *(PFLOAT)data1->UserData);
}

View File

@@ -0,0 +1,21 @@
#ifndef GPUMINI_H
#define GPUMINI_H
BOOLEAN EtpGpuListSectionCallback(
_In_ struct _PH_MINIINFO_LIST_SECTION *ListSection,
_In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message,
_In_opt_ PVOID Parameter1,
_In_opt_ PVOID Parameter2
);
int __cdecl EtpGpuListSectionProcessCompareFunction(
_In_ const void *elem1,
_In_ const void *elem2
);
int __cdecl EtpGpuListSectionNodeCompareFunction(
_In_ const void *elem1,
_In_ const void *elem2
);
#endif

View File

@@ -0,0 +1,846 @@
/*
* Process Hacker Extended Tools -
* GPU monitoring
*
* Copyright (C) 2011-2015 wj32
* Copyright (C) 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/>.
*/
#define INITGUID
#include "exttools.h"
#include <cfgmgr32.h>
#include <devpkey.h>
#include "d3dkmt.h"
#include "gpumon.h"
static GUID GUID_DISPLAY_DEVICE_ARRIVAL_I = { 0x1ca05180, 0xa699, 0x450a, { 0x9a, 0x0c, 0xde, 0x4f, 0xbe, 0x3d, 0xdd, 0x89 } };
static PFND3DKMT_OPENADAPTERFROMDEVICENAME D3DKMTOpenAdapterFromDeviceName_I;
static PFND3DKMT_CLOSEADAPTER D3DKMTCloseAdapter_I;
static PFND3DKMT_QUERYSTATISTICS D3DKMTQueryStatistics_I;
BOOLEAN EtGpuEnabled;
static PPH_LIST EtpGpuAdapterList;
static PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration;
ULONG EtGpuTotalNodeCount;
ULONG EtGpuTotalSegmentCount;
ULONG64 EtGpuDedicatedLimit;
ULONG64 EtGpuSharedLimit;
ULONG EtGpuNextNodeIndex = 0;
RTL_BITMAP EtGpuNodeBitMap;
PULONG EtGpuNodeBitMapBuffer;
ULONG EtGpuNodeBitMapBitsSet;
PULONG EtGpuNewNodeBitMapBuffer;
PH_UINT64_DELTA EtClockTotalRunningTimeDelta;
LARGE_INTEGER EtClockTotalRunningTimeFrequency;
PH_UINT64_DELTA EtGpuTotalRunningTimeDelta;
PH_UINT64_DELTA EtGpuSystemRunningTimeDelta;
FLOAT EtGpuNodeUsage;
PH_CIRCULAR_BUFFER_FLOAT EtGpuNodeHistory;
PH_CIRCULAR_BUFFER_ULONG EtMaxGpuNodeHistory; // ID of max. GPU usage process
PH_CIRCULAR_BUFFER_FLOAT EtMaxGpuNodeUsageHistory;
PPH_UINT64_DELTA EtGpuNodesTotalRunningTimeDelta;
PPH_CIRCULAR_BUFFER_FLOAT EtGpuNodesHistory;
ULONG64 EtGpuDedicatedUsage;
ULONG64 EtGpuSharedUsage;
PH_CIRCULAR_BUFFER_ULONG EtGpuDedicatedHistory;
PH_CIRCULAR_BUFFER_ULONG EtGpuSharedHistory;
VOID EtGpuMonitorInitialization(
VOID
)
{
if (PhGetIntegerSetting(SETTING_NAME_ENABLE_GPU_MONITOR) && WindowsVersion >= WINDOWS_7)
{
PVOID gdi32Handle;
if (gdi32Handle = PhGetDllHandle(L"gdi32.dll"))
{
D3DKMTOpenAdapterFromDeviceName_I = PhGetProcedureAddress(gdi32Handle, "D3DKMTOpenAdapterFromDeviceName", 0);
D3DKMTCloseAdapter_I = PhGetProcedureAddress(gdi32Handle, "D3DKMTCloseAdapter", 0);
D3DKMTQueryStatistics_I = PhGetProcedureAddress(gdi32Handle, "D3DKMTQueryStatistics", 0);
}
if (
D3DKMTOpenAdapterFromDeviceName_I &&
D3DKMTCloseAdapter_I &&
D3DKMTQueryStatistics_I
)
{
EtpGpuAdapterList = PhCreateList(4);
if (EtpInitializeD3DStatistics() && EtpGpuAdapterList->Count != 0)
EtGpuEnabled = TRUE;
}
}
if (EtGpuEnabled)
{
ULONG sampleCount;
ULONG i;
ULONG j;
PPH_STRING bitmapString;
D3DKMT_QUERYSTATISTICS queryStatistics;
sampleCount = PhGetIntegerSetting(L"SampleCount");
PhInitializeCircularBuffer_FLOAT(&EtGpuNodeHistory, sampleCount);
PhInitializeCircularBuffer_ULONG(&EtMaxGpuNodeHistory, sampleCount);
PhInitializeCircularBuffer_FLOAT(&EtMaxGpuNodeUsageHistory, sampleCount);
PhInitializeCircularBuffer_ULONG(&EtGpuDedicatedHistory, sampleCount);
PhInitializeCircularBuffer_ULONG(&EtGpuSharedHistory, sampleCount);
EtGpuNodesTotalRunningTimeDelta = PhAllocate(sizeof(PH_UINT64_DELTA) * EtGpuTotalNodeCount);
memset(EtGpuNodesTotalRunningTimeDelta, 0, sizeof(PH_UINT64_DELTA) * EtGpuTotalNodeCount);
EtGpuNodesHistory = PhAllocate(sizeof(PH_CIRCULAR_BUFFER_FLOAT) * EtGpuTotalNodeCount);
for (i = 0; i < EtGpuTotalNodeCount; i++)
{
PhInitializeCircularBuffer_FLOAT(&EtGpuNodesHistory[i], sampleCount);
}
PhRegisterCallback(
&PhProcessesUpdatedEvent,
EtGpuProcessesUpdatedCallback,
NULL,
&ProcessesUpdatedCallbackRegistration
);
// Load the node bitmap.
bitmapString = PhGetStringSetting(SETTING_NAME_GPU_NODE_BITMAP);
if (!(bitmapString->Length & 3) && bitmapString->Length / 4 <= BYTES_NEEDED_FOR_BITS(EtGpuTotalNodeCount))
{
PhHexStringToBuffer(&bitmapString->sr, (PUCHAR)EtGpuNodeBitMapBuffer);
EtGpuNodeBitMapBitsSet = RtlNumberOfSetBits(&EtGpuNodeBitMap);
}
PhDereferenceObject(bitmapString);
// Fix up the node bitmap if the current node count differs from what we've seen.
if (EtGpuTotalNodeCount != PhGetIntegerSetting(SETTING_NAME_GPU_LAST_NODE_COUNT))
{
ULONG maxContextSwitch = 0;
ULONG maxContextSwitchNodeIndex = 0;
RtlClearAllBits(&EtGpuNodeBitMap);
EtGpuNodeBitMapBitsSet = 0;
for (i = 0; i < EtpGpuAdapterList->Count; i++)
{
PETP_GPU_ADAPTER gpuAdapter = EtpGpuAdapterList->Items[i];
for (j = 0; j < gpuAdapter->NodeCount; j++)
{
memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS));
queryStatistics.Type = D3DKMT_QUERYSTATISTICS_NODE;
queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid;
queryStatistics.QueryNode.NodeId = j;
if (NT_SUCCESS(D3DKMTQueryStatistics_I(&queryStatistics)))
{
// The numbers below are quite arbitrary.
if (queryStatistics.QueryResult.NodeInformation.GlobalInformation.RunningTime.QuadPart != 0 &&
queryStatistics.QueryResult.NodeInformation.GlobalInformation.ContextSwitch > 10000)
{
RtlSetBits(&EtGpuNodeBitMap, gpuAdapter->FirstNodeIndex + j, 1);
EtGpuNodeBitMapBitsSet++;
}
if (maxContextSwitch < queryStatistics.QueryResult.NodeInformation.GlobalInformation.ContextSwitch)
{
maxContextSwitch = queryStatistics.QueryResult.NodeInformation.GlobalInformation.ContextSwitch;
maxContextSwitchNodeIndex = gpuAdapter->FirstNodeIndex + j;
}
}
}
}
// Just in case
if (EtGpuNodeBitMapBitsSet == 0)
{
RtlSetBits(&EtGpuNodeBitMap, maxContextSwitchNodeIndex, 1);
EtGpuNodeBitMapBitsSet = 1;
}
PhSetIntegerSetting(SETTING_NAME_GPU_LAST_NODE_COUNT, EtGpuTotalNodeCount);
}
}
}
BOOLEAN EtpInitializeD3DStatistics(
VOID
)
{
PWSTR deviceInterfaceList = NULL;
ULONG deviceInterfaceListLength = 0;
PWSTR deviceInterface;
D3DKMT_OPENADAPTERFROMDEVICENAME openAdapterFromDeviceName;
D3DKMT_QUERYSTATISTICS queryStatistics;
D3DKMT_CLOSEADAPTER closeAdapter;
if (CM_Get_Device_Interface_List_Size(
&deviceInterfaceListLength,
&GUID_DISPLAY_DEVICE_ARRIVAL_I,
NULL,
CM_GET_DEVICE_INTERFACE_LIST_PRESENT
) != CR_SUCCESS)
{
return FALSE;
}
deviceInterfaceList = PhAllocate(deviceInterfaceListLength * sizeof(WCHAR));
memset(deviceInterfaceList, 0, deviceInterfaceListLength * sizeof(WCHAR));
if (CM_Get_Device_Interface_List(
&GUID_DISPLAY_DEVICE_ARRIVAL_I,
NULL,
deviceInterfaceList,
deviceInterfaceListLength,
CM_GET_DEVICE_INTERFACE_LIST_PRESENT
) != CR_SUCCESS)
{
PhFree(deviceInterfaceList);
return FALSE;
}
for (deviceInterface = deviceInterfaceList; *deviceInterface; deviceInterface += PhCountStringZ(deviceInterface) + 1)
{
memset(&openAdapterFromDeviceName, 0, sizeof(D3DKMT_OPENADAPTERFROMDEVICENAME));
openAdapterFromDeviceName.pDeviceName = deviceInterface;
if (NT_SUCCESS(D3DKMTOpenAdapterFromDeviceName_I(&openAdapterFromDeviceName)))
{
memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS));
queryStatistics.Type = D3DKMT_QUERYSTATISTICS_ADAPTER;
queryStatistics.AdapterLuid = openAdapterFromDeviceName.AdapterLuid;
if (NT_SUCCESS(D3DKMTQueryStatistics_I(&queryStatistics)))
{
PETP_GPU_ADAPTER gpuAdapter;
ULONG i;
gpuAdapter = EtpAllocateGpuAdapter(queryStatistics.QueryResult.AdapterInformation.NbSegments);
gpuAdapter->AdapterLuid = openAdapterFromDeviceName.AdapterLuid;
gpuAdapter->Description = EtpQueryDeviceDescription(deviceInterface);
gpuAdapter->NodeCount = queryStatistics.QueryResult.AdapterInformation.NodeCount;
gpuAdapter->SegmentCount = queryStatistics.QueryResult.AdapterInformation.NbSegments;
RtlInitializeBitMap(&gpuAdapter->ApertureBitMap, gpuAdapter->ApertureBitMapBuffer, queryStatistics.QueryResult.AdapterInformation.NbSegments);
PhAddItemList(EtpGpuAdapterList, gpuAdapter);
EtGpuTotalNodeCount += gpuAdapter->NodeCount;
EtGpuTotalSegmentCount += gpuAdapter->SegmentCount;
gpuAdapter->FirstNodeIndex = EtGpuNextNodeIndex;
EtGpuNextNodeIndex += gpuAdapter->NodeCount;
for (i = 0; i < gpuAdapter->SegmentCount; i++)
{
memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS));
queryStatistics.Type = D3DKMT_QUERYSTATISTICS_SEGMENT;
queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid;
queryStatistics.QuerySegment.SegmentId = i;
if (NT_SUCCESS(D3DKMTQueryStatistics_I(&queryStatistics)))
{
ULONG64 commitLimit;
ULONG aperture;
if (WindowsVersion >= WINDOWS_8)
{
commitLimit = queryStatistics.QueryResult.SegmentInformation.CommitLimit;
aperture = queryStatistics.QueryResult.SegmentInformation.Aperture;
}
else
{
commitLimit = queryStatistics.QueryResult.SegmentInformationV1.CommitLimit;
aperture = queryStatistics.QueryResult.SegmentInformationV1.Aperture;
}
if (aperture)
EtGpuSharedLimit += commitLimit;
else
EtGpuDedicatedLimit += commitLimit;
if (aperture)
RtlSetBits(&gpuAdapter->ApertureBitMap, i, 1);
}
}
}
memset(&closeAdapter, 0, sizeof(D3DKMT_CLOSEADAPTER));
closeAdapter.hAdapter = openAdapterFromDeviceName.hAdapter;
D3DKMTCloseAdapter_I(&closeAdapter);
}
}
PhFree(deviceInterfaceList);
EtGpuNodeBitMapBuffer = PhAllocate(BYTES_NEEDED_FOR_BITS(EtGpuTotalNodeCount));
RtlInitializeBitMap(&EtGpuNodeBitMap, EtGpuNodeBitMapBuffer, EtGpuTotalNodeCount);
RtlSetBits(&EtGpuNodeBitMap, 0, 1);
EtGpuNodeBitMapBitsSet = 1;
return TRUE;
}
PETP_GPU_ADAPTER EtpAllocateGpuAdapter(
_In_ ULONG NumberOfSegments
)
{
PETP_GPU_ADAPTER adapter;
SIZE_T sizeNeeded;
sizeNeeded = FIELD_OFFSET(ETP_GPU_ADAPTER, ApertureBitMapBuffer);
sizeNeeded += BYTES_NEEDED_FOR_BITS(NumberOfSegments);
adapter = PhAllocate(sizeNeeded);
memset(adapter, 0, sizeNeeded);
return adapter;
}
PPH_STRING EtpQueryDeviceDescription(
_In_ PWSTR DeviceInterface
)
{
CONFIGRET result;
PPH_STRING string;
ULONG bufferSize;
DEVPROPTYPE devicePropertyType;
DEVINST deviceInstanceHandle;
ULONG deviceInstanceIdLength = MAX_DEVICE_ID_LEN;
WCHAR deviceInstanceId[MAX_DEVICE_ID_LEN];
if (CM_Get_Device_Interface_Property(
DeviceInterface,
&DEVPKEY_Device_InstanceId,
&devicePropertyType,
(PBYTE)deviceInstanceId,
&deviceInstanceIdLength,
0
) != CR_SUCCESS)
{
return NULL;
}
if (CM_Locate_DevNode(
&deviceInstanceHandle,
deviceInstanceId,
CM_LOCATE_DEVNODE_NORMAL
) != CR_SUCCESS)
{
return NULL;
}
bufferSize = 0x40;
string = PhCreateStringEx(NULL, bufferSize);
if ((result = CM_Get_DevNode_Property( // CM_Get_DevNode_Registry_Property with CM_DRP_DEVICEDESC??
deviceInstanceHandle,
&DEVPKEY_Device_DeviceDesc,
&devicePropertyType,
(PBYTE)string->Buffer,
&bufferSize,
0
)) != CR_SUCCESS)
{
PhDereferenceObject(string);
string = PhCreateStringEx(NULL, bufferSize);
result = CM_Get_DevNode_Property(
deviceInstanceHandle,
&DEVPKEY_Device_DeviceDesc,
&devicePropertyType,
(PBYTE)string->Buffer,
&bufferSize,
0
);
}
if (result != CR_SUCCESS)
{
PhDereferenceObject(string);
return NULL;
}
PhTrimToNullTerminatorString(string);
return string;
}
VOID EtpUpdateSegmentInformation(
_In_opt_ PET_PROCESS_BLOCK Block
)
{
ULONG i;
ULONG j;
PETP_GPU_ADAPTER gpuAdapter;
D3DKMT_QUERYSTATISTICS queryStatistics;
ULONG64 dedicatedUsage;
ULONG64 sharedUsage;
if (Block && !Block->ProcessItem->QueryHandle)
return;
dedicatedUsage = 0;
sharedUsage = 0;
for (i = 0; i < EtpGpuAdapterList->Count; i++)
{
gpuAdapter = EtpGpuAdapterList->Items[i];
for (j = 0; j < gpuAdapter->SegmentCount; j++)
{
memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS));
if (Block)
queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT;
else
queryStatistics.Type = D3DKMT_QUERYSTATISTICS_SEGMENT;
queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid;
if (Block)
{
queryStatistics.hProcess = Block->ProcessItem->QueryHandle;
queryStatistics.QueryProcessSegment.SegmentId = j;
}
else
{
queryStatistics.QuerySegment.SegmentId = j;
}
if (NT_SUCCESS(D3DKMTQueryStatistics_I(&queryStatistics)))
{
if (Block)
{
ULONG64 bytesCommitted;
if (WindowsVersion >= WINDOWS_8)
{
bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted;
}
else
{
bytesCommitted = (ULONG)queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted;
}
if (RtlCheckBit(&gpuAdapter->ApertureBitMap, j))
sharedUsage += bytesCommitted;
else
dedicatedUsage += bytesCommitted;
}
else
{
ULONG64 bytesCommitted;
if (WindowsVersion >= WINDOWS_8)
{
bytesCommitted = queryStatistics.QueryResult.SegmentInformation.BytesCommitted;
}
else
{
bytesCommitted = queryStatistics.QueryResult.SegmentInformationV1.BytesCommitted;
}
if (RtlCheckBit(&gpuAdapter->ApertureBitMap, j))
sharedUsage += bytesCommitted;
else
dedicatedUsage += bytesCommitted;
}
}
}
}
if (Block)
{
Block->GpuDedicatedUsage = dedicatedUsage;
Block->GpuSharedUsage = sharedUsage;
}
else
{
EtGpuDedicatedUsage = dedicatedUsage;
EtGpuSharedUsage = sharedUsage;
}
}
VOID EtpUpdateNodeInformation(
_In_opt_ PET_PROCESS_BLOCK Block
)
{
ULONG i;
ULONG j;
PETP_GPU_ADAPTER gpuAdapter;
D3DKMT_QUERYSTATISTICS queryStatistics;
ULONG64 totalRunningTime;
ULONG64 systemRunningTime;
if (Block && !Block->ProcessItem->QueryHandle)
return;
totalRunningTime = 0;
systemRunningTime = 0;
for (i = 0; i < EtpGpuAdapterList->Count; i++)
{
gpuAdapter = EtpGpuAdapterList->Items[i];
for (j = 0; j < gpuAdapter->NodeCount; j++)
{
if (Block && !RtlCheckBit(&EtGpuNodeBitMap, gpuAdapter->FirstNodeIndex + j))
continue;
memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS));
if (Block)
queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS_NODE;
else
queryStatistics.Type = D3DKMT_QUERYSTATISTICS_NODE;
queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid;
if (Block)
{
queryStatistics.hProcess = Block->ProcessItem->QueryHandle;
queryStatistics.QueryProcessNode.NodeId = j;
}
else
{
queryStatistics.QueryNode.NodeId = j;
}
if (NT_SUCCESS(D3DKMTQueryStatistics_I(&queryStatistics)))
{
if (Block)
{
totalRunningTime += queryStatistics.QueryResult.ProcessNodeInformation.RunningTime.QuadPart;
}
else
{
ULONG nodeIndex;
nodeIndex = gpuAdapter->FirstNodeIndex + j;
PhUpdateDelta(&EtGpuNodesTotalRunningTimeDelta[nodeIndex], queryStatistics.QueryResult.NodeInformation.GlobalInformation.RunningTime.QuadPart);
if (RtlCheckBit(&EtGpuNodeBitMap, gpuAdapter->FirstNodeIndex + j))
{
totalRunningTime += queryStatistics.QueryResult.NodeInformation.GlobalInformation.RunningTime.QuadPart;
systemRunningTime += queryStatistics.QueryResult.NodeInformation.SystemInformation.RunningTime.QuadPart;
}
}
}
}
}
if (Block)
{
PhUpdateDelta(&Block->GpuRunningTimeDelta, totalRunningTime);
}
else
{
LARGE_INTEGER performanceCounter;
NtQueryPerformanceCounter(&performanceCounter, &EtClockTotalRunningTimeFrequency);
PhUpdateDelta(&EtClockTotalRunningTimeDelta, performanceCounter.QuadPart);
PhUpdateDelta(&EtGpuTotalRunningTimeDelta, totalRunningTime);
PhUpdateDelta(&EtGpuSystemRunningTimeDelta, systemRunningTime);
}
}
VOID NTAPI EtGpuProcessesUpdatedCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
static ULONG runCount = 0; // MUST keep in sync with runCount in process provider
DOUBLE elapsedTime; // total GPU node elapsed time in micro-seconds
ULONG i;
PLIST_ENTRY listEntry;
FLOAT maxNodeValue = 0;
PET_PROCESS_BLOCK maxNodeBlock = NULL;
// Update global statistics.
EtpUpdateSegmentInformation(NULL);
EtpUpdateNodeInformation(NULL);
elapsedTime = (DOUBLE)EtClockTotalRunningTimeDelta.Delta * 10000000 / EtClockTotalRunningTimeFrequency.QuadPart;
if (elapsedTime != 0)
EtGpuNodeUsage = (FLOAT)(EtGpuTotalRunningTimeDelta.Delta / (elapsedTime * EtGpuNodeBitMapBitsSet));
else
EtGpuNodeUsage = 0;
if (EtGpuNodeUsage > 1)
EtGpuNodeUsage = 1;
// Do the update of the node bitmap if needed.
if (EtGpuNewNodeBitMapBuffer)
{
PULONG newBuffer;
newBuffer = _InterlockedExchangePointer(&EtGpuNewNodeBitMapBuffer, NULL);
if (newBuffer)
{
PhFree(EtGpuNodeBitMap.Buffer);
EtGpuNodeBitMap.Buffer = newBuffer;
EtGpuNodeBitMapBuffer = newBuffer;
EtGpuNodeBitMapBitsSet = RtlNumberOfSetBits(&EtGpuNodeBitMap);
EtSaveGpuMonitorSettings();
}
}
// Update per-process statistics.
// Note: no lock is needed because we only ever modify the list on this same thread.
listEntry = EtProcessBlockListHead.Flink;
while (listEntry != &EtProcessBlockListHead)
{
PET_PROCESS_BLOCK block;
block = CONTAINING_RECORD(listEntry, ET_PROCESS_BLOCK, ListEntry);
EtpUpdateSegmentInformation(block);
EtpUpdateNodeInformation(block);
if (elapsedTime != 0)
{
block->GpuNodeUsage = (FLOAT)(block->GpuRunningTimeDelta.Delta / (elapsedTime * EtGpuNodeBitMapBitsSet));
if (block->GpuNodeUsage > 1)
block->GpuNodeUsage = 1;
}
if (maxNodeValue < block->GpuNodeUsage)
{
maxNodeValue = block->GpuNodeUsage;
maxNodeBlock = block;
}
listEntry = listEntry->Flink;
}
// Update history buffers.
if (runCount != 0)
{
PhAddItemCircularBuffer_FLOAT(&EtGpuNodeHistory, EtGpuNodeUsage);
PhAddItemCircularBuffer_ULONG(&EtGpuDedicatedHistory, (ULONG)(EtGpuDedicatedUsage / PAGE_SIZE));
PhAddItemCircularBuffer_ULONG(&EtGpuSharedHistory, (ULONG)(EtGpuSharedUsage / PAGE_SIZE));
for (i = 0; i < EtGpuTotalNodeCount; i++)
{
FLOAT usage;
usage = (FLOAT)(EtGpuNodesTotalRunningTimeDelta[i].Delta / elapsedTime);
if (usage > 1)
usage = 1;
PhAddItemCircularBuffer_FLOAT(&EtGpuNodesHistory[i], usage);
}
if (maxNodeBlock)
{
PhAddItemCircularBuffer_ULONG(&EtMaxGpuNodeHistory, HandleToUlong(maxNodeBlock->ProcessItem->ProcessId));
PhAddItemCircularBuffer_FLOAT(&EtMaxGpuNodeUsageHistory, maxNodeBlock->GpuNodeUsage);
PhReferenceProcessRecordForStatistics(maxNodeBlock->ProcessItem->Record);
}
else
{
PhAddItemCircularBuffer_ULONG(&EtMaxGpuNodeHistory, 0);
PhAddItemCircularBuffer_FLOAT(&EtMaxGpuNodeUsageHistory, 0);
}
}
runCount++;
}
VOID EtSaveGpuMonitorSettings(
VOID
)
{
PPH_STRING string;
string = PhBufferToHexString((PUCHAR)EtGpuNodeBitMapBuffer, BYTES_NEEDED_FOR_BITS(EtGpuTotalNodeCount));
PhSetStringSetting2(SETTING_NAME_GPU_NODE_BITMAP, &string->sr);
PhDereferenceObject(string);
}
ULONG EtGetGpuAdapterCount(
VOID
)
{
return EtpGpuAdapterList->Count;
}
ULONG EtGetGpuAdapterIndexFromNodeIndex(
_In_ ULONG NodeIndex
)
{
ULONG i;
PETP_GPU_ADAPTER gpuAdapter;
for (i = 0; i < EtpGpuAdapterList->Count; i++)
{
gpuAdapter = EtpGpuAdapterList->Items[i];
if (NodeIndex >= gpuAdapter->FirstNodeIndex && NodeIndex < gpuAdapter->FirstNodeIndex + gpuAdapter->NodeCount)
return i;
}
return -1;
}
PPH_STRING EtGetGpuAdapterDescription(
_In_ ULONG Index
)
{
PPH_STRING description;
if (Index >= EtpGpuAdapterList->Count)
return NULL;
description = ((PETP_GPU_ADAPTER)EtpGpuAdapterList->Items[Index])->Description;
if (description)
{
PhReferenceObject(description);
return description;
}
else
{
return NULL;
}
}
VOID EtAllocateGpuNodeBitMap(
_Out_ PRTL_BITMAP BitMap
)
{
SIZE_T numberOfBytes;
numberOfBytes = BYTES_NEEDED_FOR_BITS(EtGpuTotalNodeCount);
BitMap->Buffer = PhAllocate(numberOfBytes);
BitMap->SizeOfBitMap = EtGpuTotalNodeCount;
memset(BitMap->Buffer, 0, numberOfBytes);
}
VOID EtUpdateGpuNodeBitMap(
_In_ PRTL_BITMAP NewBitMap
)
{
PULONG buffer;
buffer = _InterlockedExchangePointer(&EtGpuNewNodeBitMapBuffer, NewBitMap->Buffer);
if (buffer)
PhFree(buffer);
}
VOID EtQueryProcessGpuStatistics(
_In_ HANDLE ProcessHandle,
_Out_ PET_PROCESS_GPU_STATISTICS Statistics
)
{
NTSTATUS status;
ULONG i;
ULONG j;
PETP_GPU_ADAPTER gpuAdapter;
D3DKMT_QUERYSTATISTICS queryStatistics;
memset(Statistics, 0, sizeof(ET_PROCESS_GPU_STATISTICS));
for (i = 0; i < EtpGpuAdapterList->Count; i++)
{
gpuAdapter = EtpGpuAdapterList->Items[i];
Statistics->SegmentCount += gpuAdapter->SegmentCount;
Statistics->NodeCount += gpuAdapter->NodeCount;
for (j = 0; j < gpuAdapter->SegmentCount; j++)
{
memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS));
queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT;
queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid;
queryStatistics.hProcess = ProcessHandle;
queryStatistics.QueryProcessSegment.SegmentId = j;
if (NT_SUCCESS(status = D3DKMTQueryStatistics_I(&queryStatistics)))
{
ULONG64 bytesCommitted;
if (WindowsVersion >= WINDOWS_8)
{
bytesCommitted = queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted;
}
else
{
bytesCommitted = (ULONG)queryStatistics.QueryResult.ProcessSegmentInformation.BytesCommitted;
}
if (RtlCheckBit(&gpuAdapter->ApertureBitMap, j))
Statistics->SharedCommitted += bytesCommitted;
else
Statistics->DedicatedCommitted += bytesCommitted;
}
}
for (j = 0; j < gpuAdapter->NodeCount; j++)
{
memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS));
queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS_NODE;
queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid;
queryStatistics.hProcess = ProcessHandle;
queryStatistics.QueryProcessNode.NodeId = j;
if (NT_SUCCESS(D3DKMTQueryStatistics_I(&queryStatistics)))
{
Statistics->RunningTime += queryStatistics.QueryResult.ProcessNodeInformation.RunningTime.QuadPart;
Statistics->ContextSwitches += queryStatistics.QueryResult.ProcessNodeInformation.ContextSwitch;
}
}
memset(&queryStatistics, 0, sizeof(D3DKMT_QUERYSTATISTICS));
queryStatistics.Type = D3DKMT_QUERYSTATISTICS_PROCESS;
queryStatistics.AdapterLuid = gpuAdapter->AdapterLuid;
queryStatistics.hProcess = ProcessHandle;
if (NT_SUCCESS(D3DKMTQueryStatistics_I(&queryStatistics)))
{
Statistics->BytesAllocated += queryStatistics.QueryResult.ProcessInformation.SystemMemory.BytesAllocated;
Statistics->BytesReserved += queryStatistics.QueryResult.ProcessInformation.SystemMemory.BytesReserved;
Statistics->WriteCombinedBytesAllocated += queryStatistics.QueryResult.ProcessInformation.SystemMemory.WriteCombinedBytesAllocated;
Statistics->WriteCombinedBytesReserved += queryStatistics.QueryResult.ProcessInformation.SystemMemory.WriteCombinedBytesReserved;
Statistics->CachedBytesAllocated += queryStatistics.QueryResult.ProcessInformation.SystemMemory.CachedBytesAllocated;
Statistics->CachedBytesReserved += queryStatistics.QueryResult.ProcessInformation.SystemMemory.CachedBytesReserved;
Statistics->SectionBytesAllocated += queryStatistics.QueryResult.ProcessInformation.SystemMemory.SectionBytesAllocated;
Statistics->SectionBytesReserved += queryStatistics.QueryResult.ProcessInformation.SystemMemory.SectionBytesReserved;
}
}
}

View File

@@ -0,0 +1,43 @@
#ifndef GPUMON_H
#define GPUMON_H
// Macros
#define BYTES_NEEDED_FOR_BITS(Bits) ((((Bits) + sizeof(ULONG) * 8 - 1) / 8) & ~(SIZE_T)(sizeof(ULONG) - 1)) // divide round up
// Structures
typedef struct _ETP_GPU_ADAPTER
{
LUID AdapterLuid;
PPH_STRING Description;
ULONG SegmentCount;
ULONG NodeCount;
ULONG FirstNodeIndex;
BOOLEAN HasActivity;
RTL_BITMAP ApertureBitMap;
ULONG ApertureBitMapBuffer[1];
} ETP_GPU_ADAPTER, *PETP_GPU_ADAPTER;
// Functions
BOOLEAN EtpInitializeD3DStatistics(
VOID
);
PETP_GPU_ADAPTER EtpAllocateGpuAdapter(
_In_ ULONG NumberOfSegments
);
PPH_STRING EtpQueryDeviceDescription(
_In_ PWSTR DeviceInterface
);
VOID NTAPI EtGpuProcessesUpdatedCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
);
#endif

View File

@@ -0,0 +1,430 @@
/*
* Process Hacker Extended Tools -
* GPU nodes window
*
* Copyright (C) 2011-2015 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 "exttools.h"
#define GRAPH_PADDING 5
#define CHECKBOX_PADDING 3
INT_PTR CALLBACK EtpGpuNodesDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
static HWND WindowHandle;
static RECT MinimumSize;
static PH_LAYOUT_MANAGER LayoutManager;
static RECT LayoutMargin;
static HWND *GraphHandle;
static HWND *CheckBoxHandle;
static PPH_GRAPH_STATE GraphState;
static PPH_SYSINFO_PARAMETERS SysInfoParameters;
static PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration;
VOID EtShowGpuNodesDialog(
_In_ HWND ParentWindowHandle,
_In_ PPH_SYSINFO_PARAMETERS Parameters
)
{
SysInfoParameters = Parameters;
DialogBox(
PluginInstance->DllBase,
MAKEINTRESOURCE(IDD_GPUNODES),
ParentWindowHandle,
EtpGpuNodesDlgProc
);
}
static VOID ProcessesUpdatedCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PostMessage(WindowHandle, UPDATE_MSG, 0, 0);
}
VOID EtpLoadNodeBitMap(
VOID
)
{
ULONG i;
for (i = 0; i < EtGpuTotalNodeCount; i++)
{
Button_SetCheck(
CheckBoxHandle[i],
RtlCheckBit(&EtGpuNodeBitMap, i) ? BST_CHECKED : BST_UNCHECKED
);
}
}
VOID EtpSaveNodeBitMap(
VOID
)
{
RTL_BITMAP newBitMap;
ULONG i;
EtAllocateGpuNodeBitMap(&newBitMap);
for (i = 0; i < EtGpuTotalNodeCount; i++)
{
if (Button_GetCheck(CheckBoxHandle[i]) == BST_CHECKED)
RtlSetBits(&newBitMap, i, 1);
}
if (RtlNumberOfSetBits(&newBitMap) == 0)
RtlSetBits(&newBitMap, 0, 1);
EtUpdateGpuNodeBitMap(&newBitMap);
}
INT_PTR CALLBACK EtpGpuNodesDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
ULONG i;
HFONT font;
PPH_STRING nodeString;
RECT labelRect;
RECT tempRect;
ULONG numberOfRows;
ULONG numberOfColumns;
WindowHandle = hwndDlg;
PhInitializeLayoutManager(&LayoutManager, hwndDlg);
PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
LayoutMargin = PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_LAYOUT), NULL, PH_ANCHOR_ALL)->Margin;
PhRegisterCallback(&PhProcessesUpdatedEvent, ProcessesUpdatedCallback, NULL, &ProcessesUpdatedCallbackRegistration);
GraphHandle = PhAllocate(sizeof(HWND) * EtGpuTotalNodeCount);
CheckBoxHandle = PhAllocate(sizeof(HWND) * EtGpuTotalNodeCount);
GraphState = PhAllocate(sizeof(PH_GRAPH_STATE) * EtGpuTotalNodeCount);
font = (HFONT)SendMessage(hwndDlg, WM_GETFONT, 0, 0);
for (i = 0; i < EtGpuTotalNodeCount; i++)
{
nodeString = PhFormatString(L"Node %lu", i);
GraphHandle[i] = CreateWindow(
PH_GRAPH_CLASSNAME,
NULL,
WS_VISIBLE | WS_CHILD | WS_BORDER,
0,
0,
3,
3,
hwndDlg,
NULL,
NULL,
NULL
);
Graph_SetTooltip(GraphHandle[i], TRUE);
CheckBoxHandle[i] = CreateWindow(
WC_BUTTON,
nodeString->Buffer,
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
0,
0,
3,
3,
hwndDlg,
NULL,
NULL,
NULL
);
SendMessage(CheckBoxHandle[i], WM_SETFONT, (WPARAM)font, FALSE);
PhInitializeGraphState(&GraphState[i]);
PhDereferenceObject(nodeString);
}
// Calculate the minimum size.
numberOfRows = (ULONG)sqrt(EtGpuTotalNodeCount);
numberOfColumns = (EtGpuTotalNodeCount + numberOfRows - 1) / numberOfRows;
MinimumSize.left = 0;
MinimumSize.top = 0;
MinimumSize.right = 55;
MinimumSize.bottom = 60;
MapDialogRect(hwndDlg, &MinimumSize);
MinimumSize.right += (MinimumSize.right + GRAPH_PADDING) * numberOfColumns;
MinimumSize.bottom += (MinimumSize.bottom + GRAPH_PADDING) * numberOfRows;
GetWindowRect(GetDlgItem(hwndDlg, IDC_INSTRUCTION), &labelRect);
MapWindowPoints(NULL, hwndDlg, (POINT *)&labelRect, 2);
labelRect.right += GetSystemMetrics(SM_CXFRAME) * 2;
tempRect.left = 0;
tempRect.top = 0;
tempRect.right = 7;
tempRect.bottom = 0;
MapDialogRect(hwndDlg, &tempRect);
labelRect.right += tempRect.right;
if (MinimumSize.right < labelRect.right)
MinimumSize.right = labelRect.right;
SetWindowPos(hwndDlg, NULL, 0, 0, MinimumSize.right, MinimumSize.bottom, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
// Note: This dialog must be centered after all other graphs and controls have been added.
PhCenterWindow(hwndDlg, GetParent(hwndDlg));
EtpLoadNodeBitMap();
}
break;
case WM_DESTROY:
{
ULONG i;
EtpSaveNodeBitMap();
PhUnregisterCallback(&PhProcessesUpdatedEvent, &ProcessesUpdatedCallbackRegistration);
for (i = 0; i < EtGpuTotalNodeCount; i++)
{
PhDeleteGraphState(&GraphState[i]);
}
PhFree(GraphHandle);
PhFree(CheckBoxHandle);
PhFree(GraphState);
PhDeleteLayoutManager(&LayoutManager);
}
break;
case WM_SIZE:
{
HDWP deferHandle;
RECT clientRect;
RECT checkBoxRect;
ULONG numberOfRows = (ULONG)sqrt(EtGpuTotalNodeCount);
ULONG numberOfColumns = (EtGpuTotalNodeCount + numberOfRows - 1) / numberOfRows;
ULONG numberOfYPaddings = numberOfRows - 1;
ULONG numberOfXPaddings = numberOfColumns - 1;
ULONG cellHeight;
ULONG y;
ULONG cellWidth;
ULONG x;
ULONG i;
PhLayoutManagerLayout(&LayoutManager);
deferHandle = BeginDeferWindowPos(EtGpuTotalNodeCount * 2);
GetClientRect(hwndDlg, &clientRect);
GetClientRect(GetDlgItem(hwndDlg, IDC_EXAMPLE), &checkBoxRect);
cellHeight = (clientRect.bottom - LayoutMargin.top - LayoutMargin.bottom - GRAPH_PADDING * numberOfYPaddings) / numberOfRows;
y = LayoutMargin.top;
i = 0;
for (ULONG row = 0; row < numberOfRows; ++row)
{
// Give the last row the remaining space; the height we calculated might be off by a few
// pixels due to integer division.
if (row == numberOfRows - 1)
cellHeight = clientRect.bottom - LayoutMargin.bottom - y;
cellWidth = (clientRect.right - LayoutMargin.left - LayoutMargin.right - GRAPH_PADDING * numberOfXPaddings) / numberOfColumns;
x = LayoutMargin.left;
for (ULONG column = 0; column < numberOfColumns; column++)
{
// Give the last cell the remaining space; the width we calculated might be off by a few
// pixels due to integer division.
if (column == numberOfColumns - 1)
cellWidth = clientRect.right - LayoutMargin.right - x;
if (i < EtGpuTotalNodeCount)
{
deferHandle = DeferWindowPos(
deferHandle,
GraphHandle[i],
NULL,
x,
y,
cellWidth,
cellHeight - checkBoxRect.bottom - CHECKBOX_PADDING,
SWP_NOACTIVATE | SWP_NOZORDER
);
deferHandle = DeferWindowPos(
deferHandle,
CheckBoxHandle[i],
NULL,
x,
y + cellHeight - checkBoxRect.bottom,
cellWidth,
checkBoxRect.bottom,
SWP_NOACTIVATE | SWP_NOZORDER
);
i++;
}
x += cellWidth + GRAPH_PADDING;
}
y += cellHeight + GRAPH_PADDING;
}
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:
{
EndDialog(hwndDlg, IDOK);
}
break;
}
}
break;
case WM_NOTIFY:
{
NMHDR *header = (NMHDR *)lParam;
ULONG i;
switch (header->code)
{
case GCN_GETDRAWINFO:
{
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_GRID_Y;
SysInfoParameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), 0);
for (i = 0; i < EtGpuTotalNodeCount; i++)
{
if (header->hwndFrom == GraphHandle[i])
{
PhGraphStateGetDrawInfo(
&GraphState[i],
getDrawInfo,
EtGpuNodesHistory[i].Count
);
if (!GraphState[i].Valid)
{
PhCopyCircularBuffer_FLOAT(&EtGpuNodesHistory[i], GraphState[i].Data1, drawInfo->LineDataCount);
GraphState[i].Valid = TRUE;
}
break;
}
}
}
break;
case GCN_GETTOOLTIPTEXT:
{
PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)header;
if (getTooltipText->Index < getTooltipText->TotalCount)
{
for (i = 0; i < EtGpuTotalNodeCount; i++)
{
if (header->hwndFrom == GraphHandle[i])
{
if (GraphState[i].TooltipIndex != getTooltipText->Index)
{
FLOAT gpu;
ULONG adapterIndex;
PPH_STRING adapterDescription;
gpu = PhGetItemCircularBuffer_FLOAT(&EtGpuNodesHistory[i], getTooltipText->Index);
adapterIndex = EtGetGpuAdapterIndexFromNodeIndex(i);
if (adapterIndex != -1)
{
adapterDescription = EtGetGpuAdapterDescription(adapterIndex);
if (adapterDescription && adapterDescription->Length == 0)
PhClearReference(&adapterDescription);
if (!adapterDescription)
adapterDescription = PhFormatString(L"Adapter %lu", adapterIndex);
}
else
{
adapterDescription = PhCreateString(L"Unknown Adapter");
}
PhMoveReference(&GraphState[i].TooltipText, PhFormatString(
L"Node %lu on %s\n%.2f%%\n%s",
i,
adapterDescription->Buffer,
gpu * 100,
((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
));
PhDereferenceObject(adapterDescription);
}
getTooltipText->Text = GraphState[i].TooltipText->sr;
break;
}
}
}
}
break;
}
}
break;
case UPDATE_MSG:
{
ULONG i;
for (i = 0; i < EtGpuTotalNodeCount; i++)
{
GraphState[i].Valid = FALSE;
GraphState[i].TooltipIndex = -1;
Graph_MoveGrid(GraphHandle[i], 1);
Graph_Draw(GraphHandle[i]);
Graph_UpdateTooltip(GraphHandle[i]);
InvalidateRect(GraphHandle[i], NULL, FALSE);
}
}
break;
}
return FALSE;
}

View File

@@ -0,0 +1,767 @@
/*
* Process Hacker Extended Tools -
* GPU process properties page
*
* Copyright (C) 2011 wj32
* 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 "exttools.h"
typedef struct _ET_GPU_CONTEXT
{
HWND WindowHandle;
HWND PanelHandle;
HWND DetailsHandle;
PET_PROCESS_BLOCK Block;
PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration;
BOOLEAN Enabled;
PH_LAYOUT_MANAGER LayoutManager;
HWND GpuGroupBox;
HWND MemGroupBox;
HWND SharedGroupBox;
HWND GpuGraphHandle;
HWND MemGraphHandle;
HWND SharedGraphHandle;
FLOAT CurrentGpuUsage;
ULONG CurrentMemUsage;
ULONG CurrentMemSharedUsage;
PH_GRAPH_STATE GpuGraphState;
PH_GRAPH_STATE MemoryGraphState;
PH_GRAPH_STATE MemorySharedGraphState;
PH_CIRCULAR_BUFFER_FLOAT GpuHistory;
PH_CIRCULAR_BUFFER_ULONG MemoryHistory;
PH_CIRCULAR_BUFFER_ULONG MemorySharedHistory;
} ET_GPU_CONTEXT, *PET_GPU_CONTEXT;
static RECT NormalGraphTextMargin = { 5, 5, 5, 5 };
static RECT NormalGraphTextPadding = { 3, 3, 3, 3 };
VOID GpuPropUpdatePanel(
_Inout_ PET_GPU_CONTEXT Context
);
INT_PTR CALLBACK GpuDetailsDialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
PET_GPU_CONTEXT context = NULL;
if (uMsg == WM_INITDIALOG)
{
context = (PET_GPU_CONTEXT)lParam;
SetProp(hwndDlg, L"Context", (HANDLE)context);
}
else
{
context = (PET_GPU_CONTEXT)GetProp(hwndDlg, L"Context");
if (uMsg == WM_DESTROY)
{
context->DetailsHandle = NULL;
RemoveProp(hwndDlg, L"Context");
}
}
if (context == NULL)
return FALSE;
switch (uMsg)
{
case WM_INITDIALOG:
{
context->DetailsHandle = hwndDlg;
PhCenterWindow(hwndDlg, GetParent(hwndDlg));
GpuPropUpdatePanel(context);
}
break;
case WM_COMMAND:
{
switch (GET_WM_COMMAND_ID(wParam, lparam))
{
case IDCANCEL:
EndDialog(hwndDlg, IDCANCEL);
break;
}
}
break;
}
return FALSE;
}
INT_PTR CALLBACK GpuPanelDialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
PET_GPU_CONTEXT context = NULL;
if (uMsg == WM_INITDIALOG)
{
context = (PET_GPU_CONTEXT)lParam;
SetProp(hwndDlg, L"Context", (HANDLE)context);
}
else
{
context = (PET_GPU_CONTEXT)GetProp(hwndDlg, L"Context");
if (uMsg == WM_DESTROY)
{
RemoveProp(hwndDlg, L"Context");
}
}
if (context == NULL)
return FALSE;
switch (uMsg)
{
case WM_COMMAND:
{
switch (GET_WM_COMMAND_ID(wParam, lparam))
{
case IDC_GPUDETAILS:
{
DialogBoxParam(
PluginInstance->DllBase,
MAKEINTRESOURCE(IDD_PROCGPU_DETAILS),
hwndDlg,
GpuDetailsDialogProc,
(LPARAM)context
);
}
break;
}
}
break;
}
return FALSE;
}
VOID GpuPropCreateGraphs(
_In_ PET_GPU_CONTEXT Context
)
{
Context->GpuGraphHandle = CreateWindow(
PH_GRAPH_CLASSNAME,
NULL,
WS_VISIBLE | WS_CHILD | WS_BORDER,
0,
0,
3,
3,
Context->WindowHandle,
NULL,
NULL,
NULL
);
Graph_SetTooltip(Context->GpuGraphHandle, TRUE);
Context->MemGraphHandle = CreateWindow(
PH_GRAPH_CLASSNAME,
NULL,
WS_VISIBLE | WS_CHILD | WS_BORDER,
0,
0,
3,
3,
Context->WindowHandle,
NULL,
NULL,
NULL
);
Graph_SetTooltip(Context->MemGraphHandle, TRUE);
Context->SharedGraphHandle = CreateWindow(
PH_GRAPH_CLASSNAME,
NULL,
WS_VISIBLE | WS_CHILD | WS_BORDER,
0,
0,
3,
3,
Context->WindowHandle,
NULL,
NULL,
NULL
);
Graph_SetTooltip(Context->SharedGraphHandle, TRUE);
}
VOID GpuPropCreatePanel(
_In_ PET_GPU_CONTEXT Context
)
{
RECT margin;
Context->PanelHandle = CreateDialogParam(
PluginInstance->DllBase,
MAKEINTRESOURCE(IDD_PROCGPU_PANEL),
Context->WindowHandle,
GpuPanelDialogProc,
(LPARAM)Context
);
SetWindowPos(
Context->PanelHandle,
NULL,
10, 0, 0, 0,
SWP_NOACTIVATE | SWP_NOREDRAW | SWP_NOSIZE | SWP_NOZORDER
);
ShowWindow(Context->PanelHandle, SW_SHOW);
margin.left = 0;
margin.top = 0;
margin.right = 0;
margin.bottom = 10;
MapDialogRect(Context->WindowHandle, &margin);
PhAddLayoutItemEx(
&Context->LayoutManager,
Context->PanelHandle,
NULL,
PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT,
margin
);
SendMessage(Context->WindowHandle, WM_SIZE, 0, 0);
}
VOID GpuPropLayoutGraphs(
_In_ PET_GPU_CONTEXT Context
)
{
HDWP deferHandle;
RECT clientRect;
RECT panelRect;
RECT margin = { ET_SCALE_DPI(13), ET_SCALE_DPI(13), ET_SCALE_DPI(13), ET_SCALE_DPI(13) };
RECT innerMargin = { ET_SCALE_DPI(10), ET_SCALE_DPI(20), ET_SCALE_DPI(10), ET_SCALE_DPI(10) };
LONG between = ET_SCALE_DPI(3);
ULONG graphWidth;
ULONG graphHeight;
PhLayoutManagerLayout(&Context->LayoutManager);
Context->GpuGraphState.Valid = FALSE;
Context->MemoryGraphState.Valid = FALSE;
Context->MemorySharedGraphState.Valid = FALSE;
GetClientRect(Context->WindowHandle, &clientRect);
// Limit the rectangle bottom to the top of the panel.
GetWindowRect(Context->PanelHandle, &panelRect);
MapWindowPoints(NULL, Context->WindowHandle, (PPOINT)&panelRect, 2);
clientRect.bottom = panelRect.top + 10; // +10 removing extra spacing
graphWidth = clientRect.right - margin.left - margin.right;
graphHeight = (clientRect.bottom - margin.top - margin.bottom - between * 2) / 3;
deferHandle = BeginDeferWindowPos(6);
deferHandle = DeferWindowPos(deferHandle, Context->GpuGroupBox, NULL, margin.left, margin.top, graphWidth, graphHeight, SWP_NOACTIVATE | SWP_NOZORDER);
deferHandle = DeferWindowPos(
deferHandle,
Context->GpuGraphHandle,
NULL,
margin.left + innerMargin.left,
margin.top + innerMargin.top,
graphWidth - innerMargin.left - innerMargin.right,
graphHeight - innerMargin.top - innerMargin.bottom,
SWP_NOACTIVATE | SWP_NOZORDER
);
deferHandle = DeferWindowPos(deferHandle, Context->MemGroupBox, NULL, margin.left, margin.top + graphHeight + between, graphWidth, graphHeight, SWP_NOACTIVATE | SWP_NOZORDER);
deferHandle = DeferWindowPos(
deferHandle,
Context->MemGraphHandle,
NULL,
margin.left + innerMargin.left,
margin.top + graphHeight + between + innerMargin.top,
graphWidth - innerMargin.left - innerMargin.right,
graphHeight - innerMargin.top - innerMargin.bottom,
SWP_NOACTIVATE | SWP_NOZORDER
);
deferHandle = DeferWindowPos(deferHandle, Context->SharedGroupBox, NULL, margin.left, margin.top + (graphHeight + between) * 2, graphWidth, graphHeight, SWP_NOACTIVATE | SWP_NOZORDER);
deferHandle = DeferWindowPos(
deferHandle,
Context->SharedGraphHandle,
NULL,
margin.left + innerMargin.left,
margin.top + (graphHeight + between) * 2 + innerMargin.top,
graphWidth - innerMargin.left - innerMargin.right,
graphHeight - innerMargin.top - innerMargin.bottom,
SWP_NOACTIVATE | SWP_NOZORDER
);
EndDeferWindowPos(deferHandle);
}
VOID GpuPropUpdateGraphs(
_In_ PET_GPU_CONTEXT Context
)
{
Context->GpuGraphState.Valid = FALSE;
Context->GpuGraphState.TooltipIndex = -1;
Graph_MoveGrid(Context->GpuGraphHandle, 1);
Graph_Draw(Context->GpuGraphHandle);
Graph_UpdateTooltip(Context->GpuGraphHandle);
InvalidateRect(Context->GpuGraphHandle, NULL, FALSE);
Context->MemoryGraphState.Valid = FALSE;
Context->MemoryGraphState.TooltipIndex = -1;
Graph_MoveGrid(Context->MemGraphHandle, 1);
Graph_Draw(Context->MemGraphHandle);
Graph_UpdateTooltip(Context->MemGraphHandle);
InvalidateRect(Context->MemGraphHandle, NULL, FALSE);
Context->MemorySharedGraphState.Valid = FALSE;
Context->MemorySharedGraphState.TooltipIndex = -1;
Graph_MoveGrid(Context->SharedGraphHandle, 1);
Graph_Draw(Context->SharedGraphHandle);
Graph_UpdateTooltip(Context->SharedGraphHandle);
InvalidateRect(Context->SharedGraphHandle, NULL, FALSE);
}
VOID GpuPropUpdatePanel(
_Inout_ PET_GPU_CONTEXT Context
)
{
ET_PROCESS_GPU_STATISTICS statistics;
WCHAR runningTimeString[PH_TIMESPAN_STR_LEN_1] = L"N/A";
if (Context->Block->ProcessItem->QueryHandle)
EtQueryProcessGpuStatistics(Context->Block->ProcessItem->QueryHandle, &statistics);
else
memset(&statistics, 0, sizeof(ET_PROCESS_GPU_STATISTICS));
PhPrintTimeSpan(runningTimeString, statistics.RunningTime * 10, PH_TIMESPAN_HMSM);
SetDlgItemText(Context->PanelHandle, IDC_ZRUNNINGTIME_V, runningTimeString);
SetDlgItemText(Context->PanelHandle, IDC_ZCONTEXTSWITCHES_V, PhaFormatUInt64(statistics.ContextSwitches, TRUE)->Buffer);
SetDlgItemText(Context->PanelHandle, IDC_ZTOTALNODES_V, PhaFormatUInt64(statistics.NodeCount, TRUE)->Buffer);
SetDlgItemText(Context->PanelHandle, IDC_ZTOTALSEGMENTS_V, PhaFormatUInt64(statistics.SegmentCount, TRUE)->Buffer);
if (Context->DetailsHandle)
{
// Note: no lock is needed because we only ever update the 'details' dialog text on this same thread.
SetDlgItemText(Context->DetailsHandle, IDC_ZDEDICATEDCOMMITTED_V, PhaFormatSize(statistics.DedicatedCommitted, -1)->Buffer);
SetDlgItemText(Context->DetailsHandle, IDC_ZSHAREDCOMMITTED_V, PhaFormatSize(statistics.SharedCommitted, -1)->Buffer);
SetDlgItemText(Context->DetailsHandle, IDC_ZTOTALALLOCATED_V, PhaFormatSize(statistics.BytesAllocated, -1)->Buffer);
SetDlgItemText(Context->DetailsHandle, IDC_ZTOTALRESERVED_V, PhaFormatSize(statistics.BytesReserved, -1)->Buffer);
SetDlgItemText(Context->DetailsHandle, IDC_ZWRITECOMBINEDALLOCATED_V, PhaFormatSize(statistics.WriteCombinedBytesAllocated, -1)->Buffer);
SetDlgItemText(Context->DetailsHandle, IDC_ZWRITECOMBINEDRESERVED_V, PhaFormatSize(statistics.WriteCombinedBytesReserved, -1)->Buffer);
SetDlgItemText(Context->DetailsHandle, IDC_ZCACHEDALLOCATED_V, PhaFormatSize(statistics.CachedBytesAllocated, -1)->Buffer);
SetDlgItemText(Context->DetailsHandle, IDC_ZCACHEDRESERVED_V, PhaFormatSize(statistics.CachedBytesReserved, -1)->Buffer);
SetDlgItemText(Context->DetailsHandle, IDC_ZSECTIONALLOCATED_V, PhaFormatSize(statistics.SectionBytesAllocated, -1)->Buffer);
SetDlgItemText(Context->DetailsHandle, IDC_ZSECTIONRESERVED_V, PhaFormatSize(statistics.SectionBytesReserved, -1)->Buffer);
}
}
VOID GpuPropUpdateInfo(
_In_ PET_GPU_CONTEXT Context
)
{
PET_PROCESS_BLOCK block = Context->Block;
Context->CurrentGpuUsage = block->GpuNodeUsage;
Context->CurrentMemUsage = (ULONG)(block->GpuDedicatedUsage / PAGE_SIZE);
Context->CurrentMemSharedUsage = (ULONG)(block->GpuSharedUsage / PAGE_SIZE);
PhAddItemCircularBuffer_FLOAT(&Context->GpuHistory, Context->CurrentGpuUsage);
PhAddItemCircularBuffer_ULONG(&Context->MemoryHistory, Context->CurrentMemUsage);
PhAddItemCircularBuffer_ULONG(&Context->MemorySharedHistory, Context->CurrentMemSharedUsage);
}
VOID NTAPI ProcessesUpdatedHandler(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PET_GPU_CONTEXT context = Context;
if (!context->Enabled)
return;
if (context->WindowHandle)
{
PostMessage(context->WindowHandle, UPDATE_MSG, 0, 0);
}
}
INT_PTR CALLBACK EtpGpuPageDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
LPPROPSHEETPAGE propSheetPage;
PPH_PROCESS_PROPPAGECONTEXT propPageContext;
PPH_PROCESS_ITEM processItem;
PET_GPU_CONTEXT context;
if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem))
{
context = propPageContext->Context;
}
else
{
return FALSE;
}
switch (uMsg)
{
case WM_INITDIALOG:
{
ULONG sampleCount;
sampleCount = PhGetIntegerSetting(L"SampleCount");
context = PhAllocate(sizeof(ET_GPU_CONTEXT));
memset(context, 0, sizeof(ET_GPU_CONTEXT));
context->WindowHandle = hwndDlg;
context->Block = EtGetProcessBlock(processItem);
context->Enabled = TRUE;
context->GpuGroupBox = GetDlgItem(hwndDlg, IDC_GROUPGPU);
context->MemGroupBox = GetDlgItem(hwndDlg, IDC_GROUPMEM);
context->SharedGroupBox = GetDlgItem(hwndDlg, IDC_GROUPSHARED);
propPageContext->Context = context;
PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);
PhInitializeGraphState(&context->GpuGraphState);
PhInitializeGraphState(&context->MemoryGraphState);
PhInitializeGraphState(&context->MemorySharedGraphState);
PhInitializeCircularBuffer_FLOAT(&context->GpuHistory, sampleCount);
PhInitializeCircularBuffer_ULONG(&context->MemoryHistory, sampleCount);
PhInitializeCircularBuffer_ULONG(&context->MemorySharedHistory, sampleCount);
GpuPropCreateGraphs(context);
GpuPropCreatePanel(context);
GpuPropUpdateInfo(context);
GpuPropUpdatePanel(context);
PhRegisterCallback(
&PhProcessesUpdatedEvent,
ProcessesUpdatedHandler,
context,
&context->ProcessesUpdatedRegistration
);
}
break;
case WM_DESTROY:
{
PhDeleteLayoutManager(&context->LayoutManager);
PhDeleteGraphState(&context->GpuGraphState);
PhDeleteGraphState(&context->MemoryGraphState);
PhDeleteGraphState(&context->MemorySharedGraphState);
PhDeleteCircularBuffer_FLOAT(&context->GpuHistory);
PhDeleteCircularBuffer_ULONG(&context->MemoryHistory);
PhDeleteCircularBuffer_ULONG(&context->MemorySharedHistory);
if (context->GpuGraphHandle)
DestroyWindow(context->GpuGraphHandle);
if (context->MemGraphHandle)
DestroyWindow(context->MemGraphHandle);
if (context->SharedGraphHandle)
DestroyWindow(context->SharedGraphHandle);
if (context->PanelHandle)
DestroyWindow(context->PanelHandle);
PhUnregisterCallback(&PhProcessesUpdatedEvent, &context->ProcessesUpdatedRegistration);
PhFree(context);
PhPropPageDlgProcDestroy(hwndDlg);
}
break;
case WM_SHOWWINDOW:
{
if (PhBeginPropPageLayout(hwndDlg, propPageContext))
PhEndPropPageLayout(hwndDlg, propPageContext);
}
break;
case WM_NOTIFY:
{
LPNMHDR header = (LPNMHDR)lParam;
switch (header->code)
{
case PSN_SETACTIVE:
context->Enabled = TRUE;
break;
case PSN_KILLACTIVE:
context->Enabled = FALSE;
break;
case GCN_GETDRAWINFO:
{
PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)header;
PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;
if (header->hwndFrom == context->GpuGraphHandle)
{
if (PhGetIntegerSetting(L"GraphShowText"))
{
HDC hdc;
PhMoveReference(&context->GpuGraphState.Text, PhFormatString(
L"%.2f%%",
context->CurrentGpuUsage * 100
));
hdc = Graph_GetBufferedContext(context->GpuGraphHandle);
SelectObject(hdc, PhApplicationFont);
PhSetGraphText(hdc, drawInfo, &context->GpuGraphState.Text->sr,
&NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT);
}
else
{
drawInfo->Text.Buffer = NULL;
}
drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y;
PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), 0);
PhGraphStateGetDrawInfo(&context->GpuGraphState, getDrawInfo, context->GpuHistory.Count);
if (!context->GpuGraphState.Valid)
{
PhCopyCircularBuffer_FLOAT(&context->GpuHistory, context->GpuGraphState.Data1, drawInfo->LineDataCount);
context->GpuGraphState.Valid = TRUE;
}
}
else if (header->hwndFrom == context->MemGraphHandle)
{
if (PhGetIntegerSetting(L"GraphShowText"))
{
HDC hdc;
PhMoveReference(&context->MemoryGraphState.Text, PhFormatString(
L"%s",
PhaFormatSize(UInt32x32To64(context->CurrentMemUsage, PAGE_SIZE), -1)->Buffer
));
hdc = Graph_GetBufferedContext(context->MemGraphHandle);
SelectObject(hdc, PhApplicationFont);
PhSetGraphText(
hdc,
drawInfo,
&context->MemoryGraphState.Text->sr,
&NormalGraphTextMargin,
&NormalGraphTextPadding,
PH_ALIGN_TOP | PH_ALIGN_LEFT
);
}
else
{
drawInfo->Text.Buffer = NULL;
}
drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y;
PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorPhysical"), 0);
PhGraphStateGetDrawInfo(
&context->MemoryGraphState,
getDrawInfo,
context->MemoryHistory.Count
);
if (!context->MemoryGraphState.Valid)
{
ULONG i = 0;
for (i = 0; i < drawInfo->LineDataCount; i++)
{
context->MemoryGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&context->MemoryHistory, i);
}
if (EtGpuDedicatedLimit != 0)
{
PhDivideSinglesBySingle(
context->MemoryGraphState.Data1,
(FLOAT)EtGpuDedicatedLimit / PAGE_SIZE,
drawInfo->LineDataCount
);
}
context->MemoryGraphState.Valid = TRUE;
}
}
else if (header->hwndFrom == context->SharedGraphHandle)
{
if (PhGetIntegerSetting(L"GraphShowText"))
{
HDC hdc;
PhMoveReference(&context->MemorySharedGraphState.Text, PhFormatString(
L"%s",
PhaFormatSize(UInt32x32To64(context->CurrentMemSharedUsage, PAGE_SIZE), -1)->Buffer
));
hdc = Graph_GetBufferedContext(context->SharedGraphHandle);
SelectObject(hdc, PhApplicationFont);
PhSetGraphText(hdc, drawInfo, &context->MemorySharedGraphState.Text->sr,
&NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT);
}
else
{
drawInfo->Text.Buffer = NULL;
}
drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y;
PhSiSetColorsGraphDrawInfo(drawInfo, PhGetIntegerSetting(L"ColorPrivate"), 0);
PhGraphStateGetDrawInfo(
&context->MemorySharedGraphState,
getDrawInfo,
context->MemorySharedHistory.Count
);
if (!context->MemorySharedGraphState.Valid)
{
ULONG i = 0;
for (i = 0; i < drawInfo->LineDataCount; i++)
{
context->MemorySharedGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&context->MemorySharedHistory, i);
}
if (EtGpuSharedLimit != 0)
{
PhDivideSinglesBySingle(
context->MemorySharedGraphState.Data1,
(FLOAT)EtGpuSharedLimit / PAGE_SIZE,
drawInfo->LineDataCount
);
}
context->MemorySharedGraphState.Valid = TRUE;
}
}
}
break;
case GCN_GETTOOLTIPTEXT:
{
PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)lParam;
if (getTooltipText->Index < getTooltipText->TotalCount)
{
if (header->hwndFrom == context->GpuGraphHandle)
{
if (context->GpuGraphState.TooltipIndex != getTooltipText->Index)
{
FLOAT gpuUsage = PhGetItemCircularBuffer_FLOAT(
&context->GpuHistory,
getTooltipText->Index
);
PhMoveReference(&context->GpuGraphState.TooltipText, PhFormatString(
L"%.2f%%",
gpuUsage * 100
));
}
getTooltipText->Text = context->GpuGraphState.TooltipText->sr;
}
else if (header->hwndFrom == context->MemGraphHandle)
{
if (context->MemoryGraphState.TooltipIndex != getTooltipText->Index)
{
ULONG gpuMemory = PhGetItemCircularBuffer_ULONG(
&context->MemoryHistory,
getTooltipText->Index
);
PhMoveReference(&context->MemoryGraphState.TooltipText,
PhFormatSize(UInt32x32To64(gpuMemory, PAGE_SIZE), -1)
);
}
getTooltipText->Text = context->MemoryGraphState.TooltipText->sr;
}
else if (header->hwndFrom == context->SharedGraphHandle)
{
if (context->MemorySharedGraphState.TooltipIndex != getTooltipText->Index)
{
ULONG gpuSharedMemory = PhGetItemCircularBuffer_ULONG(
&context->MemorySharedHistory,
getTooltipText->Index
);
PhMoveReference(&context->MemorySharedGraphState.TooltipText,
PhFormatSize(UInt32x32To64(gpuSharedMemory, PAGE_SIZE), -1)
);
}
getTooltipText->Text = context->MemorySharedGraphState.TooltipText->sr;
}
}
}
break;
}
}
break;
case UPDATE_MSG:
{
if (context->Enabled)
{
GpuPropUpdateInfo(context);
GpuPropUpdateGraphs(context);
GpuPropUpdatePanel(context);
}
}
break;
case WM_SIZE:
{
GpuPropLayoutGraphs(context);
}
break;
}
return FALSE;
}
VOID EtProcessGpuPropertiesInitializing(
_In_ PVOID Parameter
)
{
PPH_PLUGIN_PROCESS_PROPCONTEXT propContext = Parameter;
if (EtGpuEnabled)
{
PhAddProcessPropPage(
propContext->PropContext,
PhCreateProcessPropPageContextEx(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_PROCGPU), EtpGpuPageDlgProc, NULL)
);
}
}

View File

@@ -0,0 +1,722 @@
/*
* Process Hacker Extended Tools -
* GPU system information section
*
* Copyright (C) 2011 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 "exttools.h"
#include "gpusys.h"
static PPH_SYSINFO_SECTION GpuSection;
static HWND GpuDialog;
static PH_LAYOUT_MANAGER GpuLayoutManager;
static RECT GpuGraphMargin;
static HWND GpuGraphHandle;
static PH_GRAPH_STATE GpuGraphState;
static HWND DedicatedGraphHandle;
static PH_GRAPH_STATE DedicatedGraphState;
static HWND SharedGraphHandle;
static PH_GRAPH_STATE SharedGraphState;
static HWND GpuPanel;
VOID EtGpuSystemInformationInitializing(
_In_ PPH_PLUGIN_SYSINFO_POINTERS Pointers
)
{
PH_SYSINFO_SECTION section;
memset(&section, 0, sizeof(PH_SYSINFO_SECTION));
PhInitializeStringRef(&section.Name, L"GPU");
section.Flags = 0;
section.Callback = EtpGpuSysInfoSectionCallback;
GpuSection = Pointers->CreateSection(&section);
}
BOOLEAN EtpGpuSysInfoSectionCallback(
_In_ PPH_SYSINFO_SECTION Section,
_In_ PH_SYSINFO_SECTION_MESSAGE Message,
_In_opt_ PVOID Parameter1,
_In_opt_ PVOID Parameter2
)
{
switch (Message)
{
case SysInfoDestroy:
{
if (GpuDialog)
{
EtpUninitializeGpuDialog();
GpuDialog = NULL;
}
}
return TRUE;
case SysInfoTick:
{
if (GpuDialog)
{
EtpTickGpuDialog();
}
}
return TRUE;
case SysInfoCreateDialog:
{
PPH_SYSINFO_CREATE_DIALOG createDialog = Parameter1;
createDialog->Instance = PluginInstance->DllBase;
createDialog->Template = MAKEINTRESOURCE(IDD_SYSINFO_GPU);
createDialog->DialogProc = EtpGpuDialogProc;
}
return TRUE;
case SysInfoGraphGetDrawInfo:
{
PPH_GRAPH_DRAW_INFO drawInfo = Parameter1;
drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y;
Section->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), 0);
PhGetDrawInfoGraphBuffers(&Section->GraphState.Buffers, drawInfo, EtGpuNodeHistory.Count);
if (!Section->GraphState.Valid)
{
PhCopyCircularBuffer_FLOAT(&EtGpuNodeHistory, Section->GraphState.Data1, drawInfo->LineDataCount);
Section->GraphState.Valid = TRUE;
}
}
return TRUE;
case SysInfoGraphGetTooltipText:
{
PPH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT getTooltipText = Parameter1;
FLOAT gpu;
gpu = PhGetItemCircularBuffer_FLOAT(&EtGpuNodeHistory, getTooltipText->Index);
PhMoveReference(&Section->GraphState.TooltipText, PhFormatString(
L"%.2f%%%s\n%s",
gpu * 100,
PhGetStringOrEmpty(EtpGetMaxNodeString(getTooltipText->Index)),
((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
));
getTooltipText->Text = Section->GraphState.TooltipText->sr;
}
return TRUE;
case SysInfoGraphDrawPanel:
{
PPH_SYSINFO_DRAW_PANEL drawPanel = Parameter1;
drawPanel->Title = PhCreateString(L"GPU");
drawPanel->SubTitle = PhFormatString(L"%.2f%%", EtGpuNodeUsage * 100);
}
return TRUE;
}
return FALSE;
}
VOID EtpInitializeGpuDialog(
VOID
)
{
PhInitializeGraphState(&GpuGraphState);
PhInitializeGraphState(&DedicatedGraphState);
PhInitializeGraphState(&SharedGraphState);
}
VOID EtpUninitializeGpuDialog(
VOID
)
{
PhDeleteGraphState(&GpuGraphState);
PhDeleteGraphState(&DedicatedGraphState);
PhDeleteGraphState(&SharedGraphState);
}
VOID EtpTickGpuDialog(
VOID
)
{
EtpUpdateGpuGraphs();
EtpUpdateGpuPanel();
}
INT_PTR CALLBACK EtpGpuDialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
PPH_LAYOUT_ITEM graphItem;
PPH_LAYOUT_ITEM panelItem;
EtpInitializeGpuDialog();
GpuDialog = hwndDlg;
PhInitializeLayoutManager(&GpuLayoutManager, hwndDlg);
PhAddLayoutItem(&GpuLayoutManager, GetDlgItem(hwndDlg, IDC_GPUNAME), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT | PH_LAYOUT_FORCE_INVALIDATE);
graphItem = PhAddLayoutItem(&GpuLayoutManager, GetDlgItem(hwndDlg, IDC_GRAPH_LAYOUT), NULL, PH_ANCHOR_ALL);
GpuGraphMargin = graphItem->Margin;
panelItem = PhAddLayoutItem(&GpuLayoutManager, GetDlgItem(hwndDlg, IDC_PANEL_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
SendMessage(GetDlgItem(hwndDlg, IDC_TITLE), WM_SETFONT, (WPARAM)GpuSection->Parameters->LargeFont, FALSE);
SendMessage(GetDlgItem(hwndDlg, IDC_GPUNAME), WM_SETFONT, (WPARAM)GpuSection->Parameters->MediumFont, FALSE);
SetDlgItemText(hwndDlg, IDC_GPUNAME, ((PPH_STRING)PH_AUTO(EtpGetGpuNameString()))->Buffer);
GpuPanel = CreateDialog(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_SYSINFO_GPUPANEL), hwndDlg, EtpGpuPanelDialogProc);
ShowWindow(GpuPanel, SW_SHOW);
PhAddLayoutItemEx(&GpuLayoutManager, GpuPanel, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM, panelItem->Margin);
EtpCreateGpuGraphs();
EtpUpdateGpuGraphs();
EtpUpdateGpuPanel();
}
break;
case WM_DESTROY:
{
PhDeleteLayoutManager(&GpuLayoutManager);
}
break;
case WM_SIZE:
{
PhLayoutManagerLayout(&GpuLayoutManager);
EtpLayoutGpuGraphs();
}
break;
case WM_NOTIFY:
{
NMHDR *header = (NMHDR *)lParam;
if (header->hwndFrom == GpuGraphHandle)
{
EtpNotifyGpuGraph(header);
}
else if (header->hwndFrom == DedicatedGraphHandle)
{
EtpNotifyDedicatedGraph(header);
}
else if (header->hwndFrom == SharedGraphHandle)
{
EtpNotifySharedGraph(header);
}
}
break;
}
return FALSE;
}
INT_PTR CALLBACK EtpGpuPanelDialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
switch (uMsg)
{
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDC_NODES:
EtShowGpuNodesDialog(GpuDialog, GpuSection->Parameters);
break;
}
}
break;
}
return FALSE;
}
VOID EtpCreateGpuGraphs(
VOID
)
{
GpuGraphHandle = CreateWindow(
PH_GRAPH_CLASSNAME,
NULL,
WS_VISIBLE | WS_CHILD | WS_BORDER,
0,
0,
3,
3,
GpuDialog,
NULL,
NULL,
NULL
);
Graph_SetTooltip(GpuGraphHandle, TRUE);
DedicatedGraphHandle = CreateWindow(
PH_GRAPH_CLASSNAME,
NULL,
WS_VISIBLE | WS_CHILD | WS_BORDER,
0,
0,
3,
3,
GpuDialog,
NULL,
NULL,
NULL
);
Graph_SetTooltip(DedicatedGraphHandle, TRUE);
SharedGraphHandle = CreateWindow(
PH_GRAPH_CLASSNAME,
NULL,
WS_VISIBLE | WS_CHILD | WS_BORDER,
0,
0,
3,
3,
GpuDialog,
NULL,
NULL,
NULL
);
Graph_SetTooltip(SharedGraphHandle, TRUE);
}
VOID EtpLayoutGpuGraphs(
VOID
)
{
RECT clientRect;
RECT labelRect;
ULONG graphWidth;
ULONG graphHeight;
HDWP deferHandle;
ULONG y;
GetClientRect(GpuDialog, &clientRect);
GetClientRect(GetDlgItem(GpuDialog, IDC_GPU_L), &labelRect);
graphWidth = clientRect.right - GpuGraphMargin.left - GpuGraphMargin.right;
graphHeight = (clientRect.bottom - GpuGraphMargin.top - GpuGraphMargin.bottom - labelRect.bottom * 3 - ET_GPU_PADDING * 5) / 3;
deferHandle = BeginDeferWindowPos(6);
y = GpuGraphMargin.top;
deferHandle = DeferWindowPos(
deferHandle,
GetDlgItem(GpuDialog, IDC_GPU_L),
NULL,
GpuGraphMargin.left,
y,
0,
0,
SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER
);
y += labelRect.bottom + ET_GPU_PADDING;
deferHandle = DeferWindowPos(
deferHandle,
GpuGraphHandle,
NULL,
GpuGraphMargin.left,
y,
graphWidth,
graphHeight,
SWP_NOACTIVATE | SWP_NOZORDER
);
y += graphHeight + ET_GPU_PADDING;
deferHandle = DeferWindowPos(
deferHandle,
GetDlgItem(GpuDialog, IDC_DEDICATED_L),
NULL,
GpuGraphMargin.left,
y,
0,
0,
SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER
);
y += labelRect.bottom + ET_GPU_PADDING;
deferHandle = DeferWindowPos(
deferHandle,
DedicatedGraphHandle,
NULL,
GpuGraphMargin.left,
y,
graphWidth,
graphHeight,
SWP_NOACTIVATE | SWP_NOZORDER
);
y += graphHeight + ET_GPU_PADDING;
deferHandle = DeferWindowPos(
deferHandle,
GetDlgItem(GpuDialog, IDC_SHARED_L),
NULL,
GpuGraphMargin.left,
y,
0,
0,
SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER
);
y += labelRect.bottom + ET_GPU_PADDING;
deferHandle = DeferWindowPos(
deferHandle,
SharedGraphHandle,
NULL,
GpuGraphMargin.left,
y,
graphWidth,
clientRect.bottom - GpuGraphMargin.bottom - y,
SWP_NOACTIVATE | SWP_NOZORDER
);
EndDeferWindowPos(deferHandle);
}
VOID EtpNotifyGpuGraph(
_In_ NMHDR *Header
)
{
switch (Header->code)
{
case GCN_GETDRAWINFO:
{
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_GRID_Y;
GpuSection->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), 0);
PhGraphStateGetDrawInfo(
&GpuGraphState,
getDrawInfo,
EtGpuNodeHistory.Count
);
if (!GpuGraphState.Valid)
{
PhCopyCircularBuffer_FLOAT(&EtGpuNodeHistory, GpuGraphState.Data1, drawInfo->LineDataCount);
GpuGraphState.Valid = TRUE;
}
}
break;
case GCN_GETTOOLTIPTEXT:
{
PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header;
if (getTooltipText->Index < getTooltipText->TotalCount)
{
if (GpuGraphState.TooltipIndex != getTooltipText->Index)
{
FLOAT gpu;
gpu = PhGetItemCircularBuffer_FLOAT(&EtGpuNodeHistory, getTooltipText->Index);
PhMoveReference(&GpuGraphState.TooltipText, PhFormatString(
L"%.2f%%%s\n%s",
gpu * 100,
PhGetStringOrEmpty(EtpGetMaxNodeString(getTooltipText->Index)),
((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
));
}
getTooltipText->Text = GpuGraphState.TooltipText->sr;
}
}
break;
case GCN_MOUSEEVENT:
{
PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Header;
PPH_PROCESS_RECORD record;
record = NULL;
if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount)
{
record = EtpReferenceMaxNodeRecord(mouseEvent->Index);
}
if (record)
{
PhShowProcessRecordDialog(GpuDialog, record);
PhDereferenceProcessRecord(record);
}
}
break;
}
}
VOID EtpNotifyDedicatedGraph(
_In_ NMHDR *Header
)
{
switch (Header->code)
{
case GCN_GETDRAWINFO:
{
PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header;
PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;
ULONG i;
drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y;
GpuSection->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorPrivate"), 0);
PhGraphStateGetDrawInfo(
&DedicatedGraphState,
getDrawInfo,
EtGpuDedicatedHistory.Count
);
if (!DedicatedGraphState.Valid)
{
for (i = 0; i < drawInfo->LineDataCount; i++)
{
DedicatedGraphState.Data1[i] =
(FLOAT)PhGetItemCircularBuffer_ULONG(&EtGpuDedicatedHistory, i);
}
if (EtGpuDedicatedLimit != 0)
{
// Scale the data.
PhDivideSinglesBySingle(
DedicatedGraphState.Data1,
(FLOAT)EtGpuDedicatedLimit / PAGE_SIZE,
drawInfo->LineDataCount
);
}
DedicatedGraphState.Valid = TRUE;
}
}
break;
case GCN_GETTOOLTIPTEXT:
{
PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header;
if (getTooltipText->Index < getTooltipText->TotalCount)
{
if (DedicatedGraphState.TooltipIndex != getTooltipText->Index)
{
ULONG usedPages;
usedPages = PhGetItemCircularBuffer_ULONG(&EtGpuDedicatedHistory, getTooltipText->Index);
PhMoveReference(&DedicatedGraphState.TooltipText, PhFormatString(
L"Dedicated Memory: %s\n%s",
PhaFormatSize(UInt32x32To64(usedPages, PAGE_SIZE), -1)->Buffer,
((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
));
}
getTooltipText->Text = DedicatedGraphState.TooltipText->sr;
}
}
break;
}
}
VOID EtpNotifySharedGraph(
_In_ NMHDR *Header
)
{
switch (Header->code)
{
case GCN_GETDRAWINFO:
{
PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header;
PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;
ULONG i;
drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y;
GpuSection->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorPhysical"), 0);
PhGraphStateGetDrawInfo(
&SharedGraphState,
getDrawInfo,
EtGpuSharedHistory.Count
);
if (!SharedGraphState.Valid)
{
for (i = 0; i < drawInfo->LineDataCount; i++)
{
SharedGraphState.Data1[i] =
(FLOAT)PhGetItemCircularBuffer_ULONG(&EtGpuSharedHistory, i);
}
if (EtGpuSharedLimit != 0)
{
// Scale the data.
PhDivideSinglesBySingle(
SharedGraphState.Data1,
(FLOAT)EtGpuSharedLimit / PAGE_SIZE,
drawInfo->LineDataCount
);
}
SharedGraphState.Valid = TRUE;
}
}
break;
case GCN_GETTOOLTIPTEXT:
{
PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header;
if (getTooltipText->Index < getTooltipText->TotalCount)
{
if (SharedGraphState.TooltipIndex != getTooltipText->Index)
{
ULONG usedPages;
usedPages = PhGetItemCircularBuffer_ULONG(&EtGpuSharedHistory, getTooltipText->Index);
PhMoveReference(&SharedGraphState.TooltipText, PhFormatString(
L"Shared Memory: %s\n%s",
PhaFormatSize(UInt32x32To64(usedPages, PAGE_SIZE), -1)->Buffer,
((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
));
}
getTooltipText->Text = SharedGraphState.TooltipText->sr;
}
}
break;
}
}
VOID EtpUpdateGpuGraphs(
VOID
)
{
GpuGraphState.Valid = FALSE;
GpuGraphState.TooltipIndex = -1;
Graph_MoveGrid(GpuGraphHandle, 1);
Graph_Draw(GpuGraphHandle);
Graph_UpdateTooltip(GpuGraphHandle);
InvalidateRect(GpuGraphHandle, NULL, FALSE);
DedicatedGraphState.Valid = FALSE;
DedicatedGraphState.TooltipIndex = -1;
Graph_MoveGrid(DedicatedGraphHandle, 1);
Graph_Draw(DedicatedGraphHandle);
Graph_UpdateTooltip(DedicatedGraphHandle);
InvalidateRect(DedicatedGraphHandle, NULL, FALSE);
SharedGraphState.Valid = FALSE;
SharedGraphState.TooltipIndex = -1;
Graph_MoveGrid(SharedGraphHandle, 1);
Graph_Draw(SharedGraphHandle);
Graph_UpdateTooltip(SharedGraphHandle);
InvalidateRect(SharedGraphHandle, NULL, FALSE);
}
VOID EtpUpdateGpuPanel(
VOID
)
{
SetDlgItemText(GpuPanel, IDC_ZDEDICATEDCURRENT_V, PhaFormatSize(EtGpuDedicatedUsage, -1)->Buffer);
SetDlgItemText(GpuPanel, IDC_ZDEDICATEDLIMIT_V, PhaFormatSize(EtGpuDedicatedLimit, -1)->Buffer);
SetDlgItemText(GpuPanel, IDC_ZSHAREDCURRENT_V, PhaFormatSize(EtGpuSharedUsage, -1)->Buffer);
SetDlgItemText(GpuPanel, IDC_ZSHAREDLIMIT_V, PhaFormatSize(EtGpuSharedLimit, -1)->Buffer);
}
PPH_PROCESS_RECORD EtpReferenceMaxNodeRecord(
_In_ LONG Index
)
{
LARGE_INTEGER time;
ULONG maxProcessId;
maxProcessId = PhGetItemCircularBuffer_ULONG(&EtMaxGpuNodeHistory, Index);
if (!maxProcessId)
return NULL;
PhGetStatisticsTime(NULL, Index, &time);
time.QuadPart += PH_TICKS_PER_SEC - 1;
return PhFindProcessRecord(UlongToHandle(maxProcessId), &time);
}
PPH_STRING EtpGetMaxNodeString(
_In_ LONG Index
)
{
PPH_PROCESS_RECORD maxProcessRecord;
FLOAT maxGpuUsage;
PPH_STRING maxUsageString = NULL;
if (maxProcessRecord = EtpReferenceMaxNodeRecord(Index))
{
maxGpuUsage = PhGetItemCircularBuffer_FLOAT(&EtMaxGpuNodeUsageHistory, Index);
maxUsageString = PhaFormatString(
L"\n%s (%lu): %.2f%%",
maxProcessRecord->ProcessName->Buffer,
HandleToUlong(maxProcessRecord->ProcessId),
maxGpuUsage * 100
);
PhDereferenceProcessRecord(maxProcessRecord);
}
return maxUsageString;
}
PPH_STRING EtpGetGpuNameString(
VOID
)
{
ULONG i;
ULONG count;
PH_STRING_BUILDER sb;
count = EtGetGpuAdapterCount();
PhInitializeStringBuilder(&sb, 100);
for (i = 0; i < count; i++)
{
PPH_STRING description;
description = EtGetGpuAdapterDescription(i);
if (!PhIsNullOrEmptyString(description))
{
// Ignore "Microsoft Basic Render Driver" unless we don't have any other adapters.
// This does not take into account localization.
if (count == 1 || !PhEqualString2(description, L"Microsoft Basic Render Driver", TRUE))
{
PhAppendStringBuilder(&sb, &description->sr);
PhAppendStringBuilder2(&sb, L", ");
}
}
if (description)
PhDereferenceObject(description);
}
if (sb.String->Length != 0)
PhRemoveEndStringBuilder(&sb, 2);
return PhFinalStringBuilderString(&sb);
}

View File

@@ -0,0 +1,79 @@
#ifndef GPUSYS_H
#define GPUSYS_H
#define ET_GPU_PADDING 3
BOOLEAN EtpGpuSysInfoSectionCallback(
_In_ PPH_SYSINFO_SECTION Section,
_In_ PH_SYSINFO_SECTION_MESSAGE Message,
_In_opt_ PVOID Parameter1,
_In_opt_ PVOID Parameter2
);
VOID EtpInitializeGpuDialog(
VOID
);
VOID EtpUninitializeGpuDialog(
VOID
);
VOID EtpTickGpuDialog(
VOID
);
INT_PTR CALLBACK EtpGpuDialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
INT_PTR CALLBACK EtpGpuPanelDialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
VOID EtpCreateGpuGraphs(
VOID
);
VOID EtpLayoutGpuGraphs(
VOID
);
VOID EtpNotifyGpuGraph(
_In_ NMHDR *Header
);
VOID EtpNotifyDedicatedGraph(
_In_ NMHDR *Header
);
VOID EtpNotifySharedGraph(
_In_ NMHDR *Header
);
VOID EtpUpdateGpuGraphs(
VOID
);
VOID EtpUpdateGpuPanel(
VOID
);
PPH_PROCESS_RECORD EtpReferenceMaxNodeRecord(
_In_ LONG Index
);
PPH_STRING EtpGetMaxNodeString(
_In_ LONG Index
);
PPH_STRING EtpGetGpuNameString(
VOID
);
#endif

View File

@@ -0,0 +1,466 @@
/*
* Process Hacker Extended Tools -
* notification icon extensions
*
* Copyright (C) 2011 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 "exttools.h"
#define GPU_ICON_ID 1
#define DISK_ICON_ID 2
#define NETWORK_ICON_ID 3
VOID EtpGpuIconUpdateCallback(
_In_ struct _PH_NF_ICON *Icon,
_Out_ PVOID *NewIconOrBitmap,
_Out_ PULONG Flags,
_Out_ PPH_STRING *NewText,
_In_opt_ PVOID Context
);
BOOLEAN EtpGpuIconMessageCallback(
_In_ struct _PH_NF_ICON *Icon,
_In_ ULONG_PTR WParam,
_In_ ULONG_PTR LParam,
_In_opt_ PVOID Context
);
VOID EtpDiskIconUpdateCallback(
_In_ struct _PH_NF_ICON *Icon,
_Out_ PVOID *NewIconOrBitmap,
_Out_ PULONG Flags,
_Out_ PPH_STRING *NewText,
_In_opt_ PVOID Context
);
BOOLEAN EtpDiskIconMessageCallback(
_In_ struct _PH_NF_ICON *Icon,
_In_ ULONG_PTR WParam,
_In_ ULONG_PTR LParam,
_In_opt_ PVOID Context
);
VOID EtpNetworkIconUpdateCallback(
_In_ struct _PH_NF_ICON *Icon,
_Out_ PVOID *NewIconOrBitmap,
_Out_ PULONG Flags,
_Out_ PPH_STRING *NewText,
_In_opt_ PVOID Context
);
BOOLEAN EtpNetworkIconMessageCallback(
_In_ struct _PH_NF_ICON *Icon,
_In_ ULONG_PTR WParam,
_In_ ULONG_PTR LParam,
_In_opt_ PVOID Context
);
VOID EtRegisterNotifyIcons(
VOID
)
{
PH_NF_ICON_REGISTRATION_DATA data;
data.MessageCallback = NULL;
data.UpdateCallback = EtpGpuIconUpdateCallback;
data.MessageCallback = EtpGpuIconMessageCallback;
PhPluginRegisterIcon(
PluginInstance,
GPU_ICON_ID,
NULL,
L"GPU history",
PH_NF_ICON_SHOW_MINIINFO | (EtGpuEnabled ? 0 : PH_NF_ICON_UNAVAILABLE),
&data
);
data.UpdateCallback = EtpDiskIconUpdateCallback;
data.MessageCallback = EtpDiskIconMessageCallback;
PhPluginRegisterIcon(
PluginInstance,
DISK_ICON_ID,
NULL,
L"Disk history",
PH_NF_ICON_SHOW_MINIINFO | (EtEtwEnabled ? 0 : PH_NF_ICON_UNAVAILABLE),
&data
);
data.UpdateCallback = EtpNetworkIconUpdateCallback;
data.MessageCallback = EtpNetworkIconMessageCallback;
PhPluginRegisterIcon(
PluginInstance,
NETWORK_ICON_ID,
NULL,
L"Network history",
PH_NF_ICON_SHOW_MINIINFO | (EtEtwEnabled ? 0 : PH_NF_ICON_UNAVAILABLE),
&data
);
}
VOID EtpGpuIconUpdateCallback(
_In_ struct _PH_NF_ICON *Icon,
_Out_ PVOID *NewIconOrBitmap,
_Out_ PULONG Flags,
_Out_ PPH_STRING *NewText,
_In_opt_ PVOID Context
)
{
static PH_GRAPH_DRAW_INFO drawInfo =
{
16,
16,
0,
2,
RGB(0x00, 0x00, 0x00),
16,
NULL,
NULL,
0,
0,
0,
0
};
ULONG maxDataCount;
ULONG lineDataCount;
PFLOAT lineData1;
HBITMAP bitmap;
PVOID bits;
HDC hdc;
HBITMAP oldBitmap;
HANDLE maxGpuProcessId;
PPH_PROCESS_ITEM maxGpuProcessItem;
PH_FORMAT format[8];
// Icon
Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap);
maxDataCount = drawInfo.Width / 2 + 1;
lineData1 = _alloca(maxDataCount * sizeof(FLOAT));
lineDataCount = min(maxDataCount, EtGpuNodeHistory.Count);
PhCopyCircularBuffer_FLOAT(&EtGpuNodeHistory, lineData1, lineDataCount);
drawInfo.LineDataCount = lineDataCount;
drawInfo.LineData1 = lineData1;
drawInfo.LineColor1 = PhGetIntegerSetting(L"ColorCpuKernel");
drawInfo.LineBackColor1 = PhHalveColorBrightness(drawInfo.LineColor1);
if (bits)
PhDrawGraphDirect(hdc, bits, &drawInfo);
SelectObject(hdc, oldBitmap);
*NewIconOrBitmap = bitmap;
*Flags = PH_NF_UPDATE_IS_BITMAP;
// Text
if (EtMaxGpuNodeHistory.Count != 0)
maxGpuProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&EtMaxGpuNodeHistory, 0));
else
maxGpuProcessId = NULL;
if (maxGpuProcessId)
maxGpuProcessItem = PhReferenceProcessItem(maxGpuProcessId);
else
maxGpuProcessItem = NULL;
PhInitFormatS(&format[0], L"GPU Usage: ");
PhInitFormatF(&format[1], EtGpuNodeUsage * 100, 2);
PhInitFormatC(&format[2], '%');
if (maxGpuProcessItem)
{
PhInitFormatC(&format[3], '\n');
PhInitFormatSR(&format[4], maxGpuProcessItem->ProcessName->sr);
PhInitFormatS(&format[5], L": ");
PhInitFormatF(&format[6], EtGetProcessBlock(maxGpuProcessItem)->GpuNodeUsage * 100, 2);
PhInitFormatC(&format[7], '%');
}
*NewText = PhFormat(format, maxGpuProcessItem ? 8 : 3, 128);
if (maxGpuProcessItem) PhDereferenceObject(maxGpuProcessItem);
}
BOOLEAN EtpGpuIconMessageCallback(
_In_ struct _PH_NF_ICON *Icon,
_In_ ULONG_PTR WParam,
_In_ ULONG_PTR LParam,
_In_opt_ PVOID Context
)
{
switch (LOWORD(LParam))
{
case PH_NF_MSG_SHOWMINIINFOSECTION:
{
PPH_NF_MSG_SHOWMINIINFOSECTION_DATA data = (PVOID)WParam;
data->SectionName = L"GPU";
}
return TRUE;
}
return FALSE;
}
VOID EtpDiskIconUpdateCallback(
_In_ struct _PH_NF_ICON *Icon,
_Out_ PVOID *NewIconOrBitmap,
_Out_ PULONG Flags,
_Out_ PPH_STRING *NewText,
_In_opt_ PVOID Context
)
{
static PH_GRAPH_DRAW_INFO drawInfo =
{
16,
16,
PH_GRAPH_USE_LINE_2,
2,
RGB(0x00, 0x00, 0x00),
16,
NULL,
NULL,
0,
0,
0,
0
};
ULONG maxDataCount;
ULONG lineDataCount;
PFLOAT lineData1;
PFLOAT lineData2;
FLOAT max;
ULONG i;
HBITMAP bitmap;
PVOID bits;
HDC hdc;
HBITMAP oldBitmap;
HANDLE maxDiskProcessId;
PPH_PROCESS_ITEM maxDiskProcessItem;
PH_FORMAT format[6];
// Icon
Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap);
maxDataCount = drawInfo.Width / 2 + 1;
lineData1 = _alloca(maxDataCount * sizeof(FLOAT));
lineData2 = _alloca(maxDataCount * sizeof(FLOAT));
lineDataCount = min(maxDataCount, EtDiskReadHistory.Count);
max = 1024 * 1024; // minimum scaling of 1 MB.
for (i = 0; i < lineDataCount; i++)
{
lineData1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&EtDiskReadHistory, i);
lineData2[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&EtDiskWriteHistory, i);
if (max < lineData1[i] + lineData2[i])
max = lineData1[i] + lineData2[i];
}
PhDivideSinglesBySingle(lineData1, max, lineDataCount);
PhDivideSinglesBySingle(lineData2, max, lineDataCount);
drawInfo.LineDataCount = lineDataCount;
drawInfo.LineData1 = lineData1;
drawInfo.LineData2 = lineData2;
drawInfo.LineColor1 = PhGetIntegerSetting(L"ColorIoReadOther");
drawInfo.LineColor2 = PhGetIntegerSetting(L"ColorIoWrite");
drawInfo.LineBackColor1 = PhHalveColorBrightness(drawInfo.LineColor1);
drawInfo.LineBackColor2 = PhHalveColorBrightness(drawInfo.LineColor2);
if (bits)
PhDrawGraphDirect(hdc, bits, &drawInfo);
SelectObject(hdc, oldBitmap);
*NewIconOrBitmap = bitmap;
*Flags = PH_NF_UPDATE_IS_BITMAP;
// Text
if (EtMaxDiskHistory.Count != 0)
maxDiskProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&EtMaxDiskHistory, 0));
else
maxDiskProcessId = NULL;
if (maxDiskProcessId)
maxDiskProcessItem = PhReferenceProcessItem(maxDiskProcessId);
else
maxDiskProcessItem = NULL;
PhInitFormatS(&format[0], L"Disk\nR: ");
PhInitFormatSize(&format[1], EtDiskReadDelta.Delta);
PhInitFormatS(&format[2], L"\nW: ");
PhInitFormatSize(&format[3], EtDiskWriteDelta.Delta);
if (maxDiskProcessItem)
{
PhInitFormatC(&format[4], '\n');
PhInitFormatSR(&format[5], maxDiskProcessItem->ProcessName->sr);
}
*NewText = PhFormat(format, maxDiskProcessItem ? 6 : 4, 128);
if (maxDiskProcessItem) PhDereferenceObject(maxDiskProcessItem);
}
BOOLEAN EtpDiskIconMessageCallback(
_In_ struct _PH_NF_ICON *Icon,
_In_ ULONG_PTR WParam,
_In_ ULONG_PTR LParam,
_In_opt_ PVOID Context
)
{
switch (LOWORD(LParam))
{
case PH_NF_MSG_SHOWMINIINFOSECTION:
{
PPH_NF_MSG_SHOWMINIINFOSECTION_DATA data = (PVOID)WParam;
data->SectionName = L"Disk";
}
return TRUE;
}
return FALSE;
}
VOID EtpNetworkIconUpdateCallback(
_In_ struct _PH_NF_ICON *Icon,
_Out_ PVOID *NewIconOrBitmap,
_Out_ PULONG Flags,
_Out_ PPH_STRING *NewText,
_In_opt_ PVOID Context
)
{
static PH_GRAPH_DRAW_INFO drawInfo =
{
16,
16,
PH_GRAPH_USE_LINE_2,
2,
RGB(0x00, 0x00, 0x00),
16,
NULL,
NULL,
0,
0,
0,
0
};
ULONG maxDataCount;
ULONG lineDataCount;
PFLOAT lineData1;
PFLOAT lineData2;
FLOAT max;
ULONG i;
HBITMAP bitmap;
PVOID bits;
HDC hdc;
HBITMAP oldBitmap;
HANDLE maxNetworkProcessId;
PPH_PROCESS_ITEM maxNetworkProcessItem;
PH_FORMAT format[6];
// Icon
Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap);
maxDataCount = drawInfo.Width / 2 + 1;
lineData1 = _alloca(maxDataCount * sizeof(FLOAT));
lineData2 = _alloca(maxDataCount * sizeof(FLOAT));
lineDataCount = min(maxDataCount, EtNetworkReceiveHistory.Count);
max = 1024 * 1024; // minimum scaling of 1 MB.
for (i = 0; i < lineDataCount; i++)
{
lineData1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&EtNetworkReceiveHistory, i);
lineData2[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&EtNetworkSendHistory, i);
if (max < lineData1[i] + lineData2[i])
max = lineData1[i] + lineData2[i];
}
PhDivideSinglesBySingle(lineData1, max, lineDataCount);
PhDivideSinglesBySingle(lineData2, max, lineDataCount);
drawInfo.LineDataCount = lineDataCount;
drawInfo.LineData1 = lineData1;
drawInfo.LineData2 = lineData2;
drawInfo.LineColor1 = PhGetIntegerSetting(L"ColorIoReadOther");
drawInfo.LineColor2 = PhGetIntegerSetting(L"ColorIoWrite");
drawInfo.LineBackColor1 = PhHalveColorBrightness(drawInfo.LineColor1);
drawInfo.LineBackColor2 = PhHalveColorBrightness(drawInfo.LineColor2);
if (bits)
PhDrawGraphDirect(hdc, bits, &drawInfo);
SelectObject(hdc, oldBitmap);
*NewIconOrBitmap = bitmap;
*Flags = PH_NF_UPDATE_IS_BITMAP;
// Text
if (EtMaxNetworkHistory.Count != 0)
maxNetworkProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&EtMaxNetworkHistory, 0));
else
maxNetworkProcessId = NULL;
if (maxNetworkProcessId)
maxNetworkProcessItem = PhReferenceProcessItem(maxNetworkProcessId);
else
maxNetworkProcessItem = NULL;
PhInitFormatS(&format[0], L"Network\nR: ");
PhInitFormatSize(&format[1], EtNetworkReceiveDelta.Delta);
PhInitFormatS(&format[2], L"\nS: ");
PhInitFormatSize(&format[3], EtNetworkSendDelta.Delta);
if (maxNetworkProcessItem)
{
PhInitFormatC(&format[4], '\n');
PhInitFormatSR(&format[5], maxNetworkProcessItem->ProcessName->sr);
}
*NewText = PhFormat(format, maxNetworkProcessItem ? 6 : 4, 128);
if (maxNetworkProcessItem) PhDereferenceObject(maxNetworkProcessItem);
}
BOOLEAN EtpNetworkIconMessageCallback(
_In_ struct _PH_NF_ICON *Icon,
_In_ ULONG_PTR WParam,
_In_ ULONG_PTR LParam,
_In_opt_ PVOID Context
)
{
switch (LOWORD(LParam))
{
case PH_NF_MSG_SHOWMINIINFOSECTION:
{
PPH_NF_MSG_SHOWMINIINFOSECTION_DATA data = (PVOID)WParam;
data->SectionName = L"Network";
}
return TRUE;
}
return FALSE;
}

View File

@@ -0,0 +1,616 @@
/*
* Process Hacker Extended Tools -
* main program
*
* Copyright (C) 2010-2015 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 "exttools.h"
PPH_PLUGIN PluginInstance;
LIST_ENTRY EtProcessBlockListHead;
LIST_ENTRY EtNetworkBlockListHead;
HWND ProcessTreeNewHandle;
HWND NetworkTreeNewHandle;
PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration;
PH_CALLBACK_REGISTRATION PluginUnloadCallbackRegistration;
PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration;
PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration;
PH_CALLBACK_REGISTRATION PluginTreeNewMessageCallbackRegistration;
PH_CALLBACK_REGISTRATION MainWindowShowingCallbackRegistration;
PH_CALLBACK_REGISTRATION ProcessPropertiesInitializingCallbackRegistration;
PH_CALLBACK_REGISTRATION HandlePropertiesInitializingCallbackRegistration;
PH_CALLBACK_REGISTRATION ProcessMenuInitializingCallbackRegistration;
PH_CALLBACK_REGISTRATION ThreadMenuInitializingCallbackRegistration;
PH_CALLBACK_REGISTRATION ModuleMenuInitializingCallbackRegistration;
PH_CALLBACK_REGISTRATION ProcessTreeNewInitializingCallbackRegistration;
PH_CALLBACK_REGISTRATION NetworkTreeNewInitializingCallbackRegistration;
PH_CALLBACK_REGISTRATION SystemInformationInitializingCallbackRegistration;
PH_CALLBACK_REGISTRATION MiniInformationInitializingCallbackRegistration;
PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration;
PH_CALLBACK_REGISTRATION NetworkItemsUpdatedCallbackRegistration;
static HANDLE ModuleProcessId;
VOID NTAPI LoadCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
EtEtwStatisticsInitialization();
EtGpuMonitorInitialization();
EtRegisterNotifyIcons();
}
VOID NTAPI UnloadCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
EtSaveSettingsDiskTreeList();
EtEtwStatisticsUninitialization();
}
VOID NTAPI ShowOptionsCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
EtShowOptionsDialog((HWND)Parameter);
}
VOID NTAPI MenuItemCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN_MENU_ITEM menuItem = Parameter;
switch (menuItem->Id)
{
case ID_PROCESS_UNLOADEDMODULES:
{
EtShowUnloadedDllsDialog(PhMainWndHandle, menuItem->Context);
}
break;
case ID_PROCESS_WSWATCH:
{
EtShowWsWatchDialog(PhMainWndHandle, menuItem->Context);
}
break;
case ID_THREAD_CANCELIO:
{
EtUiCancelIoThread(menuItem->OwnerWindow, menuItem->Context);
}
break;
case ID_MODULE_SERVICES:
{
EtShowModuleServicesDialog(
menuItem->OwnerWindow,
ModuleProcessId,
((PPH_MODULE_ITEM)menuItem->Context)->Name->Buffer
);
}
break;
}
}
VOID NTAPI TreeNewMessageCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN_TREENEW_MESSAGE message = Parameter;
if (message->TreeNewHandle == ProcessTreeNewHandle)
EtProcessTreeNewMessage(Parameter);
else if (message->TreeNewHandle == NetworkTreeNewHandle)
EtNetworkTreeNewMessage(Parameter);
}
VOID NTAPI MainWindowShowingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
EtInitializeDiskTab();
}
VOID NTAPI ProcessPropertiesInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
EtProcessGpuPropertiesInitializing(Parameter);
EtProcessEtwPropertiesInitializing(Parameter);
}
VOID NTAPI HandlePropertiesInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
EtHandlePropertiesInitializing(Parameter);
}
VOID NTAPI ProcessMenuInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter;
PPH_PROCESS_ITEM processItem;
ULONG flags;
PPH_EMENU_ITEM miscMenu;
if (menuInfo->u.Process.NumberOfProcesses == 1)
processItem = menuInfo->u.Process.Processes[0];
else
processItem = NULL;
flags = 0;
if (!processItem)
flags = PH_EMENU_DISABLED;
miscMenu = PhFindEMenuItem(menuInfo->Menu, 0, L"Miscellaneous", 0);
if (miscMenu)
{
PhInsertEMenuItem(miscMenu, PhPluginCreateEMenuItem(PluginInstance, flags, ID_PROCESS_UNLOADEDMODULES, L"Unloaded modules", processItem), -1);
PhInsertEMenuItem(miscMenu, PhPluginCreateEMenuItem(PluginInstance, flags, ID_PROCESS_WSWATCH, L"WS watch", processItem), -1);
}
}
VOID NTAPI ThreadMenuInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter;
PPH_THREAD_ITEM threadItem;
ULONG insertIndex;
PPH_EMENU_ITEM menuItem;
if (menuInfo->u.Thread.NumberOfThreads == 1)
threadItem = menuInfo->u.Thread.Threads[0];
else
threadItem = NULL;
if (menuItem = PhFindEMenuItem(menuInfo->Menu, 0, L"Resume", 0))
insertIndex = PhIndexOfEMenuItem(menuInfo->Menu, menuItem) + 1;
else
insertIndex = 0;
PhInsertEMenuItem(menuInfo->Menu, menuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_THREAD_CANCELIO,
L"Cancel I/O", threadItem), insertIndex);
if (!threadItem) menuItem->Flags |= PH_EMENU_DISABLED;
}
VOID NTAPI ModuleMenuInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter;
PPH_PROCESS_ITEM processItem;
BOOLEAN addMenuItem;
PPH_MODULE_ITEM moduleItem;
ULONG insertIndex;
PPH_EMENU_ITEM menuItem;
addMenuItem = FALSE;
if (processItem = PhReferenceProcessItem(menuInfo->u.Module.ProcessId))
{
if (processItem->ServiceList && processItem->ServiceList->Count != 0)
addMenuItem = TRUE;
PhDereferenceObject(processItem);
}
if (!addMenuItem)
return;
if (menuInfo->u.Module.NumberOfModules == 1)
moduleItem = menuInfo->u.Module.Modules[0];
else
moduleItem = NULL;
if (menuItem = PhFindEMenuItem(menuInfo->Menu, PH_EMENU_FIND_STARTSWITH, L"Inspect", 0))
insertIndex = PhIndexOfEMenuItem(menuInfo->Menu, menuItem) + 1;
else
insertIndex = 0;
ModuleProcessId = menuInfo->u.Module.ProcessId;
PhInsertEMenuItem(menuInfo->Menu, menuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_MODULE_SERVICES,
L"Services", moduleItem), insertIndex);
if (!moduleItem) menuItem->Flags |= PH_EMENU_DISABLED;
}
VOID NTAPI ProcessTreeNewInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN_TREENEW_INFORMATION treeNewInfo = Parameter;
ProcessTreeNewHandle = treeNewInfo->TreeNewHandle;
EtProcessTreeNewInitializing(Parameter);
}
VOID NTAPI NetworkTreeNewInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN_TREENEW_INFORMATION treeNewInfo = Parameter;
NetworkTreeNewHandle = treeNewInfo->TreeNewHandle;
EtNetworkTreeNewInitializing(Parameter);
}
VOID NTAPI SystemInformationInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
if (EtGpuEnabled)
EtGpuSystemInformationInitializing(Parameter);
if (EtEtwEnabled)
EtEtwSystemInformationInitializing(Parameter);
}
VOID NTAPI MiniInformationInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
if (EtGpuEnabled)
EtGpuMiniInformationInitializing(Parameter);
if (EtEtwEnabled)
EtEtwMiniInformationInitializing(Parameter);
}
VOID NTAPI ProcessesUpdatedCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PLIST_ENTRY listEntry;
// Note: no lock is needed because we only ever modify the list on this same thread.
listEntry = EtProcessBlockListHead.Flink;
while (listEntry != &EtProcessBlockListHead)
{
PET_PROCESS_BLOCK block;
block = CONTAINING_RECORD(listEntry, ET_PROCESS_BLOCK, ListEntry);
PhUpdateDelta(&block->HardFaultsDelta, block->ProcessItem->HardFaultCount);
// Invalidate all text.
PhAcquireQueuedLockExclusive(&block->TextCacheLock);
memset(block->TextCacheValid, 0, sizeof(block->TextCacheValid));
PhReleaseQueuedLockExclusive(&block->TextCacheLock);
listEntry = listEntry->Flink;
}
}
VOID NTAPI NetworkItemsUpdatedCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PLIST_ENTRY listEntry;
// Note: no lock is needed because we only ever modify the list on this same thread.
listEntry = EtNetworkBlockListHead.Flink;
while (listEntry != &EtNetworkBlockListHead)
{
PET_NETWORK_BLOCK block;
block = CONTAINING_RECORD(listEntry, ET_NETWORK_BLOCK, ListEntry);
// Invalidate all text.
PhAcquireQueuedLockExclusive(&block->TextCacheLock);
memset(block->TextCacheValid, 0, sizeof(block->TextCacheValid));
PhReleaseQueuedLockExclusive(&block->TextCacheLock);
listEntry = listEntry->Flink;
}
}
PET_PROCESS_BLOCK EtGetProcessBlock(
_In_ PPH_PROCESS_ITEM ProcessItem
)
{
return PhPluginGetObjectExtension(PluginInstance, ProcessItem, EmProcessItemType);
}
PET_NETWORK_BLOCK EtGetNetworkBlock(
_In_ PPH_NETWORK_ITEM NetworkItem
)
{
return PhPluginGetObjectExtension(PluginInstance, NetworkItem, EmNetworkItemType);
}
VOID EtInitializeProcessBlock(
_Out_ PET_PROCESS_BLOCK Block,
_In_ PPH_PROCESS_ITEM ProcessItem
)
{
memset(Block, 0, sizeof(ET_PROCESS_BLOCK));
Block->ProcessItem = ProcessItem;
PhInitializeQueuedLock(&Block->TextCacheLock);
InsertTailList(&EtProcessBlockListHead, &Block->ListEntry);
}
VOID EtDeleteProcessBlock(
_In_ PET_PROCESS_BLOCK Block
)
{
ULONG i;
EtProcIconNotifyProcessDelete(Block);
for (i = 1; i <= ETPRTNC_MAXIMUM; i++)
{
PhClearReference(&Block->TextCache[i]);
}
RemoveEntryList(&Block->ListEntry);
}
VOID EtInitializeNetworkBlock(
_Out_ PET_NETWORK_BLOCK Block,
_In_ PPH_NETWORK_ITEM NetworkItem
)
{
memset(Block, 0, sizeof(ET_NETWORK_BLOCK));
Block->NetworkItem = NetworkItem;
PhInitializeQueuedLock(&Block->TextCacheLock);
InsertTailList(&EtNetworkBlockListHead, &Block->ListEntry);
}
VOID EtDeleteNetworkBlock(
_In_ PET_NETWORK_BLOCK Block
)
{
ULONG i;
for (i = 1; i <= ETNETNC_MAXIMUM; i++)
{
PhClearReference(&Block->TextCache[i]);
}
RemoveEntryList(&Block->ListEntry);
}
VOID NTAPI ProcessItemCreateCallback(
_In_ PVOID Object,
_In_ PH_EM_OBJECT_TYPE ObjectType,
_In_ PVOID Extension
)
{
EtInitializeProcessBlock(Extension, Object);
}
VOID NTAPI ProcessItemDeleteCallback(
_In_ PVOID Object,
_In_ PH_EM_OBJECT_TYPE ObjectType,
_In_ PVOID Extension
)
{
EtDeleteProcessBlock(Extension);
}
VOID NTAPI NetworkItemCreateCallback(
_In_ PVOID Object,
_In_ PH_EM_OBJECT_TYPE ObjectType,
_In_ PVOID Extension
)
{
EtInitializeNetworkBlock(Extension, Object);
}
VOID NTAPI NetworkItemDeleteCallback(
_In_ PVOID Object,
_In_ PH_EM_OBJECT_TYPE ObjectType,
_In_ PVOID Extension
)
{
EtDeleteNetworkBlock(Extension);
}
LOGICAL DllMain(
_In_ HINSTANCE Instance,
_In_ ULONG Reason,
_Reserved_ PVOID Reserved
)
{
switch (Reason)
{
case DLL_PROCESS_ATTACH:
{
PPH_PLUGIN_INFORMATION info;
PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info);
if (!PluginInstance)
return FALSE;
info->DisplayName = L"Extended Tools";
info->Author = L"wj32";
info->Description = L"Extended functionality for Windows Vista and above, including ETW monitoring, GPU monitoring and a Disk tab.";
info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1114";
info->HasOptions = TRUE;
PhRegisterCallback(
PhGetPluginCallback(PluginInstance, PluginCallbackLoad),
LoadCallback,
NULL,
&PluginLoadCallbackRegistration
);
PhRegisterCallback(
PhGetPluginCallback(PluginInstance, PluginCallbackUnload),
UnloadCallback,
NULL,
&PluginUnloadCallbackRegistration
);
PhRegisterCallback(
PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions),
ShowOptionsCallback,
NULL,
&PluginShowOptionsCallbackRegistration
);
PhRegisterCallback(
PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem),
MenuItemCallback,
NULL,
&PluginMenuItemCallbackRegistration
);
PhRegisterCallback(
PhGetPluginCallback(PluginInstance, PluginCallbackTreeNewMessage),
TreeNewMessageCallback,
NULL,
&PluginTreeNewMessageCallbackRegistration
);
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackMainWindowShowing),
MainWindowShowingCallback,
NULL,
&MainWindowShowingCallbackRegistration
);
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackProcessPropertiesInitializing),
ProcessPropertiesInitializingCallback,
NULL,
&ProcessPropertiesInitializingCallbackRegistration
);
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackHandlePropertiesInitializing),
HandlePropertiesInitializingCallback,
NULL,
&HandlePropertiesInitializingCallbackRegistration
);
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackProcessMenuInitializing),
ProcessMenuInitializingCallback,
NULL,
&ProcessMenuInitializingCallbackRegistration
);
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackThreadMenuInitializing),
ThreadMenuInitializingCallback,
NULL,
&ThreadMenuInitializingCallbackRegistration
);
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackModuleMenuInitializing),
ModuleMenuInitializingCallback,
NULL,
&ModuleMenuInitializingCallbackRegistration
);
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackProcessTreeNewInitializing),
ProcessTreeNewInitializingCallback,
NULL,
&ProcessTreeNewInitializingCallbackRegistration
);
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackNetworkTreeNewInitializing),
NetworkTreeNewInitializingCallback,
NULL,
&NetworkTreeNewInitializingCallbackRegistration
);
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackSystemInformationInitializing),
SystemInformationInitializingCallback,
NULL,
&SystemInformationInitializingCallbackRegistration
);
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackMiniInformationInitializing),
MiniInformationInitializingCallback,
NULL,
&MiniInformationInitializingCallbackRegistration
);
PhRegisterCallback(
&PhProcessesUpdatedEvent,
ProcessesUpdatedCallback,
NULL,
&ProcessesUpdatedCallbackRegistration
);
PhRegisterCallback(
&PhNetworkItemsUpdatedEvent,
NetworkItemsUpdatedCallback,
NULL,
&NetworkItemsUpdatedCallbackRegistration
);
InitializeListHead(&EtProcessBlockListHead);
InitializeListHead(&EtNetworkBlockListHead);
PhPluginSetObjectExtension(
PluginInstance,
EmProcessItemType,
sizeof(ET_PROCESS_BLOCK),
ProcessItemCreateCallback,
ProcessItemDeleteCallback
);
PhPluginSetObjectExtension(
PluginInstance,
EmNetworkItemType,
sizeof(ET_NETWORK_BLOCK),
NetworkItemCreateCallback,
NetworkItemDeleteCallback
);
{
static PH_SETTING_CREATE settings[] =
{
{ StringSettingType, SETTING_NAME_DISK_TREE_LIST_COLUMNS, L"" },
{ IntegerPairSettingType, SETTING_NAME_DISK_TREE_LIST_SORT, L"4,2" }, // 4, DescendingSortOrder
{ IntegerSettingType, SETTING_NAME_ENABLE_ETW_MONITOR, L"1" },
{ IntegerSettingType, SETTING_NAME_ENABLE_GPU_MONITOR, L"1" },
{ StringSettingType, SETTING_NAME_GPU_NODE_BITMAP, L"01000000" },
{ IntegerSettingType, SETTING_NAME_GPU_LAST_NODE_COUNT, L"0" }
};
PhAddSettings(settings, sizeof(settings) / sizeof(PH_SETTING_CREATE));
}
}
break;
}
return TRUE;
}

View File

@@ -0,0 +1,173 @@
/*
* Process Hacker Extended Tools -
* services referencing module
*
* Copyright (C) 2010-2011 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 "exttools.h"
#include <subprocesstag.h>
typedef struct _MODULE_SERVICES_CONTEXT
{
HANDLE ProcessId;
PWSTR ModuleName;
} MODULE_SERVICES_CONTEXT, *PMODULE_SERVICES_CONTEXT;
INT_PTR CALLBACK EtpModuleServicesDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
VOID EtShowModuleServicesDialog(
_In_ HWND ParentWindowHandle,
_In_ HANDLE ProcessId,
_In_ PWSTR ModuleName
)
{
MODULE_SERVICES_CONTEXT context;
context.ProcessId = ProcessId;
context.ModuleName = ModuleName;
DialogBoxParam(
PluginInstance->DllBase,
MAKEINTRESOURCE(IDD_MODSERVICES),
ParentWindowHandle,
EtpModuleServicesDlgProc,
(LPARAM)&context
);
}
INT_PTR CALLBACK EtpModuleServicesDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
PMODULE_SERVICES_CONTEXT context = (PMODULE_SERVICES_CONTEXT)lParam;
ULONG win32Result;
PQUERY_TAG_INFORMATION I_QueryTagInformation;
TAG_INFO_NAMES_REFERENCING_MODULE namesReferencingModule;
PPH_LIST serviceList;
PPH_SERVICE_ITEM *serviceItems;
HWND serviceListHandle;
RECT rect;
PPH_PROCESS_ITEM processItem;
PPH_STRING message;
PhCenterWindow(hwndDlg, GetParent(hwndDlg));
I_QueryTagInformation = PhGetModuleProcAddress(L"advapi32.dll", "I_QueryTagInformation");
if (!I_QueryTagInformation)
{
PhShowError(hwndDlg, L"Unable to query services because the feature is not supported by the operating system.");
EndDialog(hwndDlg, IDCANCEL);
return FALSE;
}
memset(&namesReferencingModule, 0, sizeof(TAG_INFO_NAMES_REFERENCING_MODULE));
namesReferencingModule.InParams.dwPid = HandleToUlong(context->ProcessId);
namesReferencingModule.InParams.pszModule = context->ModuleName;
win32Result = I_QueryTagInformation(NULL, eTagInfoLevelNamesReferencingModule, &namesReferencingModule);
if (win32Result == ERROR_NO_MORE_ITEMS)
win32Result = 0;
if (win32Result != 0)
{
PhShowStatus(hwndDlg, L"Unable to query services", 0, win32Result);
EndDialog(hwndDlg, IDCANCEL);
return FALSE;
}
serviceList = PhCreateList(16);
if (namesReferencingModule.OutParams.pmszNames)
{
PPH_SERVICE_ITEM serviceItem;
PWSTR serviceName;
ULONG nameLength;
serviceName = namesReferencingModule.OutParams.pmszNames;
while (TRUE)
{
nameLength = (ULONG)PhCountStringZ(serviceName);
if (nameLength == 0)
break;
if (serviceItem = PhReferenceServiceItem(serviceName))
PhAddItemList(serviceList, serviceItem);
serviceName += nameLength + 1;
}
LocalFree(namesReferencingModule.OutParams.pmszNames);
}
serviceItems = PhAllocateCopy(serviceList->Items, serviceList->Count * sizeof(PPH_SERVICE_ITEM));
PhDereferenceObject(serviceList);
serviceListHandle = PhCreateServiceListControl(hwndDlg, serviceItems, serviceList->Count);
// Position the control.
GetWindowRect(GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), &rect);
MapWindowPoints(NULL, hwndDlg, (POINT *)&rect, 2);
MoveWindow(serviceListHandle, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, FALSE);
ShowWindow(serviceListHandle, SW_SHOW);
if (processItem = PhReferenceProcessItem(context->ProcessId))
{
message = PhFormatString(L"Services referencing %s in %s:", context->ModuleName, processItem->ProcessName->Buffer);
PhDereferenceObject(processItem);
}
else
{
message = PhFormatString(L"Services referencing %s:", context->ModuleName);
}
SetDlgItemText(hwndDlg, IDC_MESSAGE, message->Buffer);
PhDereferenceObject(message);
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDCANCEL:
case IDOK:
EndDialog(hwndDlg, IDOK);
break;
}
}
break;
}
return FALSE;
}

View File

@@ -0,0 +1,312 @@
/*
* Process Hacker Extended Tools -
* handle properties extensions
*
* Copyright (C) 2010-2011 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 "exttools.h"
#include <symprv.h>
typedef struct _COMMON_PAGE_CONTEXT
{
PPH_HANDLE_ITEM HandleItem;
HANDLE ProcessId;
} COMMON_PAGE_CONTEXT, *PCOMMON_PAGE_CONTEXT;
HPROPSHEETPAGE EtpCommonCreatePage(
_In_ PPH_PLUGIN_HANDLE_PROPERTIES_CONTEXT Context,
_In_ PWSTR Template,
_In_ DLGPROC DlgProc
);
INT CALLBACK EtpCommonPropPageProc(
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ LPPROPSHEETPAGE ppsp
);
INT_PTR CALLBACK EtpAlpcPortPageDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
INT_PTR CALLBACK EtpTpWorkerFactoryPageDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
VOID EtHandlePropertiesInitializing(
_In_ PVOID Parameter
)
{
PPH_PLUGIN_OBJECT_PROPERTIES objectProperties = Parameter;
PPH_PLUGIN_HANDLE_PROPERTIES_CONTEXT context = objectProperties->Parameter;
if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages)
{
HPROPSHEETPAGE page = NULL;
if (PhEqualString2(context->HandleItem->TypeName, L"ALPC Port", TRUE))
{
page = EtpCommonCreatePage(
context,
MAKEINTRESOURCE(IDD_OBJALPCPORT),
EtpAlpcPortPageDlgProc
);
}
else if (PhEqualString2(context->HandleItem->TypeName, L"TpWorkerFactory", TRUE))
{
page = EtpCommonCreatePage(
context,
MAKEINTRESOURCE(IDD_OBJTPWORKERFACTORY),
EtpTpWorkerFactoryPageDlgProc
);
}
// Insert our page into the second slot.
if (page)
{
if (objectProperties->NumberOfPages > 1)
{
memmove(&objectProperties->Pages[2], &objectProperties->Pages[1],
(objectProperties->NumberOfPages - 1) * sizeof(HPROPSHEETPAGE));
}
objectProperties->Pages[1] = page;
objectProperties->NumberOfPages++;
}
}
}
static HPROPSHEETPAGE EtpCommonCreatePage(
_In_ PPH_PLUGIN_HANDLE_PROPERTIES_CONTEXT Context,
_In_ PWSTR Template,
_In_ DLGPROC DlgProc
)
{
HPROPSHEETPAGE propSheetPageHandle;
PROPSHEETPAGE propSheetPage;
PCOMMON_PAGE_CONTEXT pageContext;
pageContext = PhCreateAlloc(sizeof(COMMON_PAGE_CONTEXT));
memset(pageContext, 0, sizeof(COMMON_PAGE_CONTEXT));
pageContext->HandleItem = Context->HandleItem;
pageContext->ProcessId = Context->ProcessId;
memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));
propSheetPage.dwSize = sizeof(PROPSHEETPAGE);
propSheetPage.dwFlags = PSP_USECALLBACK;
propSheetPage.hInstance = PluginInstance->DllBase;
propSheetPage.pszTemplate = Template;
propSheetPage.pfnDlgProc = DlgProc;
propSheetPage.lParam = (LPARAM)pageContext;
propSheetPage.pfnCallback = EtpCommonPropPageProc;
propSheetPageHandle = CreatePropertySheetPage(&propSheetPage);
PhDereferenceObject(pageContext); // already got a ref from above call
return propSheetPageHandle;
}
INT CALLBACK EtpCommonPropPageProc(
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ LPPROPSHEETPAGE ppsp
)
{
PCOMMON_PAGE_CONTEXT pageContext;
pageContext = (PCOMMON_PAGE_CONTEXT)ppsp->lParam;
if (uMsg == PSPCB_ADDREF)
PhReferenceObject(pageContext);
else if (uMsg == PSPCB_RELEASE)
PhDereferenceObject(pageContext);
return 1;
}
static NTSTATUS EtpDuplicateHandleFromProcess(
_Out_ PHANDLE Handle,
_In_ ACCESS_MASK DesiredAccess,
_In_ PCOMMON_PAGE_CONTEXT Context
)
{
NTSTATUS status;
HANDLE processHandle;
if (!NT_SUCCESS(status = PhOpenProcess(
&processHandle,
PROCESS_DUP_HANDLE,
Context->ProcessId
)))
return status;
status = NtDuplicateObject(
processHandle,
Context->HandleItem->Handle,
NtCurrentProcess(),
Handle,
DesiredAccess,
0,
0
);
NtClose(processHandle);
return status;
}
INT_PTR CALLBACK EtpAlpcPortPageDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam;
PCOMMON_PAGE_CONTEXT context = (PCOMMON_PAGE_CONTEXT)propSheetPage->lParam;
HANDLE portHandle;
if (NT_SUCCESS(EtpDuplicateHandleFromProcess(&portHandle, READ_CONTROL, context)))
{
ALPC_BASIC_INFORMATION basicInfo;
if (NT_SUCCESS(NtAlpcQueryInformation(
portHandle,
AlpcBasicInformation,
&basicInfo,
sizeof(ALPC_BASIC_INFORMATION),
NULL
)))
{
PH_FORMAT format[2];
PPH_STRING string;
PhInitFormatS(&format[0], L"Sequence Number: ");
PhInitFormatD(&format[1], basicInfo.SequenceNo);
format[1].Type |= FormatGroupDigits;
string = PhFormat(format, 2, 128);
SetDlgItemText(hwndDlg, IDC_SEQUENCENUMBER, string->Buffer);
PhDereferenceObject(string);
SetDlgItemText(hwndDlg, IDC_PORTCONTEXT,
PhaFormatString(L"Port Context: 0x%Ix", basicInfo.PortContext)->Buffer);
}
NtClose(portHandle);
}
}
break;
}
return FALSE;
}
static BOOLEAN NTAPI EnumGenericModulesCallback(
_In_ PPH_MODULE_INFO Module,
_In_opt_ PVOID Context
)
{
if (Module->Type == PH_MODULE_TYPE_MODULE || Module->Type == PH_MODULE_TYPE_WOW64_MODULE)
{
PhLoadModuleSymbolProvider(Context, Module->FileName->Buffer,
(ULONG64)Module->BaseAddress, Module->Size);
}
return TRUE;
}
INT_PTR CALLBACK EtpTpWorkerFactoryPageDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam;
PCOMMON_PAGE_CONTEXT context = (PCOMMON_PAGE_CONTEXT)propSheetPage->lParam;
HANDLE workerFactoryHandle;
if (NT_SUCCESS(EtpDuplicateHandleFromProcess(&workerFactoryHandle, WORKER_FACTORY_QUERY_INFORMATION, context)))
{
WORKER_FACTORY_BASIC_INFORMATION basicInfo;
if (NT_SUCCESS(NtQueryInformationWorkerFactory(
workerFactoryHandle,
WorkerFactoryBasicInformation,
&basicInfo,
sizeof(WORKER_FACTORY_BASIC_INFORMATION),
NULL
)))
{
PPH_SYMBOL_PROVIDER symbolProvider;
PPH_STRING symbol = NULL;
symbolProvider = PhCreateSymbolProvider(basicInfo.ProcessId);
PhLoadSymbolProviderOptions(symbolProvider);
if (symbolProvider->IsRealHandle)
{
PhEnumGenericModules(basicInfo.ProcessId, symbolProvider->ProcessHandle,
0, EnumGenericModulesCallback, symbolProvider);
symbol = PhGetSymbolFromAddress(symbolProvider, (ULONG64)basicInfo.StartRoutine,
NULL, NULL, NULL, NULL);
}
PhDereferenceObject(symbolProvider);
if (symbol)
{
SetDlgItemText(hwndDlg, IDC_WORKERTHREADSTART,
PhaFormatString(L"Worker Thread Start: %s", symbol->Buffer)->Buffer);
PhDereferenceObject(symbol);
}
else
{
SetDlgItemText(hwndDlg, IDC_WORKERTHREADSTART,
PhaFormatString(L"Worker Thread Start: 0x%Ix", basicInfo.StartRoutine)->Buffer);
}
SetDlgItemText(hwndDlg, IDC_WORKERTHREADCONTEXT,
PhaFormatString(L"Worker Thread Context: 0x%Ix", basicInfo.StartParameter)->Buffer);
}
NtClose(workerFactoryHandle);
}
}
break;
}
return FALSE;
}

View File

@@ -0,0 +1,85 @@
/*
* Process Hacker Extended Tools -
* options dialog
*
* 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 "exttools.h"
INT_PTR CALLBACK OptionsDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
VOID EtShowOptionsDialog(
_In_ HWND ParentWindowHandle
)
{
DialogBox(
PluginInstance->DllBase,
MAKEINTRESOURCE(IDD_OPTIONS),
ParentWindowHandle,
OptionsDlgProc
);
}
INT_PTR CALLBACK OptionsDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLEETWMONITOR), PhGetIntegerSetting(SETTING_NAME_ENABLE_ETW_MONITOR) ? BST_CHECKED : BST_UNCHECKED);
Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLEGPUMONITOR), PhGetIntegerSetting(SETTING_NAME_ENABLE_GPU_MONITOR) ? BST_CHECKED : BST_UNCHECKED);
if (WindowsVersion < WINDOWS_7)
EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLEGPUMONITOR), FALSE);
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDCANCEL:
EndDialog(hwndDlg, IDCANCEL);
break;
case IDOK:
{
PhSetIntegerSetting(SETTING_NAME_ENABLE_ETW_MONITOR,
Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLEETWMONITOR)) == BST_CHECKED);
PhSetIntegerSetting(SETTING_NAME_ENABLE_GPU_MONITOR,
Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLEGPUMONITOR)) == BST_CHECKED);
EndDialog(hwndDlg, IDOK);
}
break;
}
}
break;
}
return FALSE;
}

View File

@@ -0,0 +1,95 @@
/*
* Process Hacker Extended Tools -
* process icon duplication
*
* Copyright (C) 2011 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 "exttools.h"
PET_PROCESS_ICON EtProcIconCreateProcessIcon(
_In_ HICON Icon
)
{
PET_PROCESS_ICON processIcon;
processIcon = PhAllocate(sizeof(ET_PROCESS_ICON));
processIcon->RefCount = 1;
processIcon->Icon = CopyIcon(Icon);
return processIcon;
}
VOID EtProcIconReferenceProcessIcon(
_Inout_ PET_PROCESS_ICON ProcessIcon
)
{
_InterlockedIncrement(&ProcessIcon->RefCount);
}
VOID EtProcIconDereferenceProcessIcon(
_Inout_ PET_PROCESS_ICON ProcessIcon
)
{
if (_InterlockedDecrement(&ProcessIcon->RefCount) == 0)
{
DestroyIcon(ProcessIcon->Icon);
PhFree(ProcessIcon);
}
}
PET_PROCESS_ICON EtProcIconReferenceSmallProcessIcon(
_Inout_ PET_PROCESS_BLOCK Block
)
{
PET_PROCESS_ICON smallProcessIcon;
smallProcessIcon = Block->SmallProcessIcon;
if (!smallProcessIcon && PhTestEvent(&Block->ProcessItem->Stage1Event))
{
smallProcessIcon = EtProcIconCreateProcessIcon(Block->ProcessItem->SmallIcon);
if (_InterlockedCompareExchangePointer(
&Block->SmallProcessIcon,
smallProcessIcon,
NULL
) != NULL)
{
EtProcIconDereferenceProcessIcon(smallProcessIcon);
smallProcessIcon = Block->SmallProcessIcon;
}
}
if (smallProcessIcon)
{
EtProcIconReferenceProcessIcon(smallProcessIcon);
}
return smallProcessIcon;
}
VOID EtProcIconNotifyProcessDelete(
_Inout_ PET_PROCESS_BLOCK Block
)
{
if (Block->SmallProcessIcon)
{
EtProcIconDereferenceProcessIcon(Block->SmallProcessIcon);
}
}

View File

@@ -0,0 +1,113 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by ExtendedTools.rc
//
#define ID_PROCESS_UNLOADEDMODULES 101
#define IDD_UNLOADEDDLLS 102
#define IDD_OBJALPCPORT 103
#define ID_THREAD_CANCELIO 104
#define IDD_OBJTPWORKERFACTORY 105
#define ID_MODULE_SERVICES 106
#define IDD_MODSERVICES 107
#define ID_VIEW_MEMORYLISTS 108
#define IDD_PROCDISKNET 110
#define ID_VIEW_DISKANDNETWORK 111
#define ID_PROCESS_WSWATCH 112
#define IDD_SYSINFO_DISKPANEL 113
#define IDD_OPTIONS 114
#define IDD_WSWATCH 115
#define IDD_SYSINFO_GPU 117
#define IDR_DISK 118
#define ID_VIEW_GPUINFORMATION 119
#define IDD_SYSINFO_GPUPANEL 120
#define IDD_PROCGPU 121
#define IDD_SYSINFO_DISK 122
#define IDD_GPUNODES 123
#define IDD_SYSINFO_NETPANEL 124
#define IDD_SYSINFO_NET 125
#define IDD_PROCGPU_PANEL 126
#define IDD_DISKTABRESTART 127
#define IDD_DISKTABERROR 128
#define IDD_PROCDISKNET_PANEL 129
#define IDD_PROCGPU_DETAILS 131
#define IDC_LIST 1001
#define IDC_REFRESH 1002
#define IDC_SEQUENCENUMBER 1003
#define IDC_PORTCONTEXT 1004
#define IDC_WORKERTHREADSTART 1005
#define IDC_WORKERTHREADCONTEXT 1006
#define IDC_SERVICES_LAYOUT 1007
#define IDC_MESSAGE 1008
#define IDC_ZREADS_V 1023
#define IDC_ZREADBYTES_V 1024
#define IDC_ZREADBYTESDELTA_V 1025
#define IDC_ZWRITES_V 1026
#define IDC_ZWRITEBYTES_V 1027
#define IDC_ZWRITEBYTESDELTA_V 1028
#define IDC_ZRECEIVES_V 1029
#define IDC_ZRECEIVEBYTES_V 1030
#define IDC_ZRECEIVEBYTESDELTA_V 1031
#define IDC_ZSENDS_V 1032
#define IDC_ZSENDBYTES_V 1033
#define IDC_ZSENDBYTESDELTA_V 1034
#define IDC_ENABLEETWMONITOR 1035
#define IDC_ENABLE 1036
#define IDC_WSWATCHENABLED 1037
#define IDC_NODES 1048
#define IDC_ENABLEGPUMONITOR 1049
#define IDC_EXAMPLE 1050
#define IDC_GROUPGPU 1051
#define IDC_GROUPMEM 1052
#define IDC_GROUPSHARED 1053
#define IDC_GROUPDEDICATED 1054
#define IDC_ZDEDICATEDCURRENT_V 1055
#define IDC_ZDEDICATEDLIMIT_V 1056
#define IDC_ZSHAREDCURRENT_V 1057
#define IDC_ZSHAREDLIMIT_V 1058
#define IDC_ZDEDICATEDCOMMITTED_V 1059
#define IDC_ZRUNNINGTIME_V 1060
#define IDC_ZCONTEXTSWITCHES_V 1061
#define IDC_ZTOTALNODES_V 1062
#define IDC_ZCACHEDALLOCATED_V 1063
#define IDC_ZCACHEDRESERVED_V 1064
#define IDC_ZSHAREDCOMMITTED_V 1065
#define IDC_ZTOTALALLOCATED_V 1066
#define IDC_ZTOTALRESERVED_V 1067
#define IDC_ZWRITECOMBINEDALLOCATED_V 1068
#define IDC_ZWRITECOMBINEDRESERVED_V 1069
#define IDC_ZSECTIONALLOCATED_V 1070
#define IDC_ZSECTIONRESERVED_V 1071
#define IDC_ZTOTALSEGMENTS_V 1072
#define IDC_TITLE 1073
#define IDC_GRAPH_LAYOUT 1074
#define IDC_LAYOUT 1075
#define IDC_GPUNAME 1076
#define IDC_GPU_L 1077
#define IDC_DEDICATED_L 1078
#define IDC_SHARED_L 1079
#define IDC_ZRECEIVESDELTA_V 1080
#define IDC_ZSENDSDELTA_V 1081
#define IDC_ZWRITESDELTA_V 1082
#define IDC_ZREADSDELTA_V 1083
#define IDC_INSTRUCTION 1084
#define IDC_PANEL_LAYOUT 1085
#define IDC_RESTART 1086
#define IDC_ERROR 1087
#define IDC_GROUPDISK 1088
#define IDC_GROUPNETWORK 1089
#define IDC_GPUDETAILS 1090
#define ID_DISK_GOTOPROCESS 40005
#define ID_DISK_COPY 40006
#define ID_DISK_PROPERTIES 40007
#define ID_DISK_OPENFILELOCATION 40008
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 134
#define _APS_NEXT_COMMAND_VALUE 40009
#define _APS_NEXT_CONTROL_VALUE 1091
#define _APS_NEXT_SYMED_VALUE 130
#endif
#endif

View File

@@ -0,0 +1,64 @@
/*
* Process Hacker Extended Tools -
* thread actions extensions
*
* 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 "exttools.h"
BOOLEAN EtUiCancelIoThread(
_In_ HWND hWnd,
_In_ PPH_THREAD_ITEM Thread
)
{
NTSTATUS status;
BOOLEAN cont = FALSE;
HANDLE threadHandle;
IO_STATUS_BLOCK isb;
if (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage(
hWnd,
L"end",
L"I/O for the selected thread",
NULL,
FALSE
))
cont = TRUE;
if (!cont)
return FALSE;
if (NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_TERMINATE, Thread->ThreadId)))
{
status = NtCancelSynchronousIoFile(threadHandle, NULL, &isb);
}
if (status == STATUS_NOT_FOUND)
{
PhShowInformation(hWnd, L"There is no synchronous I/O to cancel.");
return FALSE;
}
else if (!NT_SUCCESS(status))
{
PhShowStatus(hWnd, L"Unable to cancel synchronous I/O", status, 0);
return FALSE;
}
return TRUE;
}

View File

@@ -0,0 +1,783 @@
/*
* Process Hacker Extended Tools -
* process and network tree support
*
* Copyright (C) 2011 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 "exttools.h"
#define CINTERFACE
#define COBJMACROS
#include <netfw.h>
LONG EtpProcessTreeNewSortFunction(
_In_ PVOID Node1,
_In_ PVOID Node2,
_In_ ULONG SubId,
_In_ PVOID Context
);
LONG EtpNetworkTreeNewSortFunction(
_In_ PVOID Node1,
_In_ PVOID Node2,
_In_ ULONG SubId,
_In_ PVOID Context
);
typedef struct _COLUMN_INFO
{
ULONG SubId;
PWSTR Text;
ULONG Width;
ULONG Alignment;
ULONG TextFlags;
BOOLEAN SortDescending;
} COLUMN_INFO, *PCOLUMN_INFO;
static ULONG ProcessTreeListSortColumn;
static PH_SORT_ORDER ProcessTreeListSortOrder;
static GUID IID_INetFwMgr_I = { 0xf7898af5, 0xcac4, 0x4632, { 0xa2, 0xec, 0xda, 0x06, 0xe5, 0x11, 0x1a, 0xf2 } };
static GUID CLSID_NetFwMgr_I = { 0x304ce942, 0x6e39, 0x40d8, { 0x94, 0x3a, 0xb9, 0x13, 0xc4, 0x0c, 0x9c, 0xd4 } };
VOID EtpAddTreeNewColumn(
_In_ PPH_PLUGIN_TREENEW_INFORMATION TreeNewInfo,
_In_ ULONG SubId,
_In_ PWSTR Text,
_In_ ULONG Width,
_In_ ULONG Alignment,
_In_ ULONG TextFlags,
_In_ BOOLEAN SortDescending,
_In_ PPH_PLUGIN_TREENEW_SORT_FUNCTION SortFunction
)
{
PH_TREENEW_COLUMN column;
memset(&column, 0, sizeof(PH_TREENEW_COLUMN));
column.SortDescending = SortDescending;
column.Text = Text;
column.Width = Width;
column.Alignment = Alignment;
column.TextFlags = TextFlags;
PhPluginAddTreeNewColumn(
PluginInstance,
TreeNewInfo->CmData,
&column,
SubId,
NULL,
SortFunction
);
}
VOID EtProcessTreeNewInitializing(
_In_ PVOID Parameter
)
{
static COLUMN_INFO columns[] =
{
{ ETPRTNC_DISKREADS, L"Disk reads", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_DISKWRITES, L"Disk writes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_DISKREADBYTES, L"Disk read bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_DISKWRITEBYTES, L"Disk write bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_DISKTOTALBYTES, L"Disk total bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_DISKREADSDELTA, L"Disk reads delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_DISKWRITESDELTA, L"Disk writes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_DISKREADBYTESDELTA, L"Disk read bytes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_DISKWRITEBYTESDELTA, L"Disk write bytes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_DISKTOTALBYTESDELTA, L"Disk total bytes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_NETWORKRECEIVES, L"Network receives", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_NETWORKSENDS, L"Network sends", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_NETWORKRECEIVEBYTES, L"Network receive bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_NETWORKSENDBYTES, L"Network send bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_NETWORKTOTALBYTES, L"Network total bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_NETWORKRECEIVESDELTA, L"Network receives delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_NETWORKSENDSDELTA, L"Network sends delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_NETWORKRECEIVEBYTESDELTA, L"Network receive bytes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_NETWORKSENDBYTESDELTA, L"Network send bytes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_NETWORKTOTALBYTESDELTA, L"Network total bytes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_HARDFAULTS, L"Hard faults", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_HARDFAULTSDELTA, L"Hard faults delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_PEAKTHREADS, L"Peak threads", 45, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_GPU, L"GPU", 45, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_GPUDEDICATEDBYTES, L"GPU dedicated bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_GPUSHAREDBYTES, L"GPU shared bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_DISKREADRATE, L"Disk read rate", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_DISKWRITERATE, L"Disk write rate", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_DISKTOTALRATE, L"Disk total rate", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_NETWORKRECEIVERATE, L"Network receive rate", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_NETWORKSENDRATE, L"Network send rate", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETPRTNC_NETWORKTOTALRATE, L"Network total rate", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }
};
PPH_PLUGIN_TREENEW_INFORMATION treeNewInfo = Parameter;
ULONG i;
for (i = 0; i < sizeof(columns) / sizeof(COLUMN_INFO); i++)
{
EtpAddTreeNewColumn(treeNewInfo, columns[i].SubId, columns[i].Text, columns[i].Width, columns[i].Alignment,
columns[i].TextFlags, columns[i].SortDescending, EtpProcessTreeNewSortFunction);
}
PhPluginEnableTreeNewNotify(PluginInstance, treeNewInfo->CmData);
}
FLOAT EtpCalculateInclusiveGpuUsage(
_In_ PPH_PROCESS_NODE ProcessNode
)
{
FLOAT gpuUsage;
ULONG i;
gpuUsage = EtGetProcessBlock(ProcessNode->ProcessItem)->GpuNodeUsage;
for (i = 0; i < ProcessNode->Children->Count; i++)
{
gpuUsage += EtpCalculateInclusiveGpuUsage(ProcessNode->Children->Items[i]);
}
return gpuUsage;
}
VOID EtProcessTreeNewMessage(
_In_ PVOID Parameter
)
{
PPH_PLUGIN_TREENEW_MESSAGE message = Parameter;
PPH_PROCESS_NODE processNode;
PET_PROCESS_BLOCK block;
if (message->Message == TreeNewGetCellText)
{
PPH_TREENEW_GET_CELL_TEXT getCellText = message->Parameter1;
PPH_STRING text;
processNode = (PPH_PROCESS_NODE)getCellText->Node;
block = EtGetProcessBlock(processNode->ProcessItem);
PhAcquireQueuedLockExclusive(&block->TextCacheLock);
if (block->TextCacheValid[message->SubId])
{
if (block->TextCache[message->SubId])
getCellText->Text = block->TextCache[message->SubId]->sr;
}
else
{
text = NULL;
switch (message->SubId)
{
case ETPRTNC_DISKREADS:
if (block->DiskReadCount != 0)
text = PhFormatUInt64(block->DiskReadCount, TRUE);
break;
case ETPRTNC_DISKWRITES:
if (block->DiskWriteCount != 0)
text = PhFormatUInt64(block->DiskWriteCount, TRUE);
break;
case ETPRTNC_DISKREADBYTES:
if (block->DiskReadRaw != 0)
text = PhFormatSize(block->DiskReadRaw, -1);
break;
case ETPRTNC_DISKWRITEBYTES:
if (block->DiskWriteRaw != 0)
text = PhFormatSize(block->DiskWriteRaw, -1);
break;
case ETPRTNC_DISKTOTALBYTES:
if (block->DiskReadRaw + block->DiskWriteRaw != 0)
text = PhFormatSize(block->DiskReadRaw + block->DiskWriteRaw, -1);
break;
case ETPRTNC_DISKREADSDELTA:
if (block->DiskReadDelta.Delta != 0)
text = PhFormatUInt64(block->DiskReadDelta.Delta, TRUE);
break;
case ETPRTNC_DISKWRITESDELTA:
if (block->DiskWriteDelta.Delta != 0)
text = PhFormatUInt64(block->DiskWriteDelta.Delta, TRUE);
break;
case ETPRTNC_DISKREADBYTESDELTA:
if (block->DiskReadRawDelta.Delta != 0)
text = PhFormatSize(block->DiskReadRawDelta.Delta, -1);
break;
case ETPRTNC_DISKWRITEBYTESDELTA:
if (block->DiskWriteRawDelta.Delta != 0)
text = PhFormatSize(block->DiskWriteRawDelta.Delta, -1);
break;
case ETPRTNC_DISKTOTALBYTESDELTA:
if (block->DiskReadRawDelta.Delta + block->DiskWriteRawDelta.Delta != 0)
text = PhFormatSize(block->DiskReadRawDelta.Delta + block->DiskWriteRawDelta.Delta, -1);
break;
case ETPRTNC_NETWORKRECEIVES:
if (block->NetworkReceiveCount != 0)
text = PhFormatUInt64(block->NetworkReceiveCount, TRUE);
break;
case ETPRTNC_NETWORKSENDS:
if (block->NetworkSendCount != 0)
text = PhFormatUInt64(block->NetworkSendCount, TRUE);
break;
case ETPRTNC_NETWORKRECEIVEBYTES:
if (block->NetworkReceiveRaw != 0)
text = PhFormatSize(block->NetworkReceiveRaw, -1);
break;
case ETPRTNC_NETWORKSENDBYTES:
if (block->NetworkSendRaw != 0)
text = PhFormatSize(block->NetworkSendRaw, -1);
break;
case ETPRTNC_NETWORKTOTALBYTES:
if (block->NetworkReceiveRaw + block->NetworkSendRaw != 0)
text = PhFormatSize(block->NetworkReceiveRaw + block->NetworkSendRaw, -1);
break;
case ETPRTNC_NETWORKRECEIVESDELTA:
if (block->NetworkReceiveDelta.Delta != 0)
text = PhFormatUInt64(block->NetworkReceiveDelta.Delta, TRUE);
break;
case ETPRTNC_NETWORKSENDSDELTA:
if (block->NetworkSendDelta.Delta != 0)
text = PhFormatUInt64(block->NetworkSendDelta.Delta, TRUE);
break;
case ETPRTNC_NETWORKRECEIVEBYTESDELTA:
if (block->NetworkReceiveRawDelta.Delta != 0)
text = PhFormatSize(block->NetworkReceiveRawDelta.Delta, -1);
break;
case ETPRTNC_NETWORKSENDBYTESDELTA:
if (block->NetworkSendRawDelta.Delta != 0)
text = PhFormatSize(block->NetworkSendRawDelta.Delta, -1);
break;
case ETPRTNC_NETWORKTOTALBYTESDELTA:
if (block->NetworkReceiveRawDelta.Delta + block->NetworkSendRawDelta.Delta != 0)
text = PhFormatSize(block->NetworkReceiveRawDelta.Delta + block->NetworkSendRawDelta.Delta, -1);
break;
case ETPRTNC_HARDFAULTS:
text = PhFormatUInt64(block->HardFaultsDelta.Value, TRUE);
break;
case ETPRTNC_HARDFAULTSDELTA:
if (block->HardFaultsDelta.Delta != 0)
text = PhFormatUInt64(block->HardFaultsDelta.Delta, TRUE);
break;
case ETPRTNC_PEAKTHREADS:
text = PhFormatUInt64(block->ProcessItem->PeakNumberOfThreads, TRUE);
break;
case ETPRTNC_GPU:
{
FLOAT gpuUsage;
if (!PhGetIntegerSetting(L"PropagateCpuUsage") || processNode->Node.Expanded || ProcessTreeListSortOrder != NoSortOrder)
{
gpuUsage = block->GpuNodeUsage * 100;
}
else
{
gpuUsage = EtpCalculateInclusiveGpuUsage(processNode) * 100;
}
if (gpuUsage >= 0.01)
{
PH_FORMAT format;
PhInitFormatF(&format, gpuUsage, 2);
text = PhFormat(&format, 1, 0);
}
}
break;
case ETPRTNC_GPUDEDICATEDBYTES:
if (block->GpuDedicatedUsage != 0)
text = PhFormatSize(block->GpuDedicatedUsage, -1);
break;
case ETPRTNC_GPUSHAREDBYTES:
if (block->GpuSharedUsage != 0)
text = PhFormatSize(block->GpuSharedUsage, -1);
break;
case ETPRTNC_DISKREADRATE:
if (block->DiskReadRawDelta.Delta != 0)
EtFormatRate(block->DiskReadRawDelta.Delta, &text, NULL);
break;
case ETPRTNC_DISKWRITERATE:
if (block->DiskWriteRawDelta.Delta != 0)
EtFormatRate(block->DiskWriteRawDelta.Delta, &text, NULL);
break;
case ETPRTNC_DISKTOTALRATE:
if (block->DiskReadRawDelta.Delta + block->DiskWriteRawDelta.Delta != 0)
EtFormatRate(block->DiskReadRawDelta.Delta + block->DiskWriteRawDelta.Delta, &text, NULL);
break;
case ETPRTNC_NETWORKRECEIVERATE:
if (block->NetworkReceiveRawDelta.Delta != 0)
EtFormatRate(block->NetworkReceiveRawDelta.Delta, &text, NULL);
break;
case ETPRTNC_NETWORKSENDRATE:
if (block->NetworkSendRawDelta.Delta != 0)
EtFormatRate(block->NetworkSendRawDelta.Delta, &text, NULL);
break;
case ETPRTNC_NETWORKTOTALRATE:
if (block->NetworkReceiveRawDelta.Delta + block->NetworkSendRawDelta.Delta != 0)
EtFormatRate(block->NetworkReceiveRawDelta.Delta + block->NetworkSendRawDelta.Delta, &text, NULL);
break;
}
if (text)
{
getCellText->Text = text->sr;
}
PhMoveReference(&block->TextCache[message->SubId], text);
block->TextCacheValid[message->SubId] = TRUE;
}
PhReleaseQueuedLockExclusive(&block->TextCacheLock);
}
else if (message->Message == TreeNewSortChanged)
{
TreeNew_GetSort(message->TreeNewHandle, &ProcessTreeListSortColumn, &ProcessTreeListSortOrder);
}
else if (message->Message == TreeNewNodeExpanding)
{
processNode = message->Parameter1;
block = EtGetProcessBlock(processNode->ProcessItem);
if (PhGetIntegerSetting(L"PropagateCpuUsage"))
block->TextCacheValid[ETPRTNC_GPU] = FALSE;
}
}
LONG EtpProcessTreeNewSortFunction(
_In_ PVOID Node1,
_In_ PVOID Node2,
_In_ ULONG SubId,
_In_ PVOID Context
)
{
LONG result;
PPH_PROCESS_NODE node1 = Node1;
PPH_PROCESS_NODE node2 = Node2;
PET_PROCESS_BLOCK block1;
PET_PROCESS_BLOCK block2;
block1 = EtGetProcessBlock(node1->ProcessItem);
block2 = EtGetProcessBlock(node2->ProcessItem);
result = 0;
switch (SubId)
{
case ETPRTNC_DISKREADS:
result = uint64cmp(block1->DiskReadCount, block2->DiskReadCount);
break;
case ETPRTNC_DISKWRITES:
result = uint64cmp(block1->DiskWriteCount, block2->DiskWriteCount);
break;
case ETPRTNC_DISKREADBYTES:
result = uint64cmp(block1->DiskReadRaw, block2->DiskReadRaw);
break;
case ETPRTNC_DISKWRITEBYTES:
result = uint64cmp(block1->DiskWriteRaw, block2->DiskWriteRaw);
break;
case ETPRTNC_DISKTOTALBYTES:
result = uint64cmp(block1->DiskReadRaw + block1->DiskWriteRaw, block2->DiskReadRaw + block2->DiskWriteRaw);
break;
case ETPRTNC_DISKREADSDELTA:
result = uint64cmp(block1->DiskReadDelta.Delta, block2->DiskReadDelta.Delta);
break;
case ETPRTNC_DISKWRITESDELTA:
result = uint64cmp(block1->DiskWriteDelta.Delta, block2->DiskWriteDelta.Delta);
break;
case ETPRTNC_DISKREADBYTESDELTA:
result = uint64cmp(block1->DiskReadRawDelta.Delta, block2->DiskReadRawDelta.Delta);
break;
case ETPRTNC_DISKWRITEBYTESDELTA:
result = uint64cmp(block1->DiskWriteRawDelta.Delta, block2->DiskWriteRawDelta.Delta);
break;
case ETPRTNC_DISKTOTALBYTESDELTA:
result = uint64cmp(block1->DiskReadRawDelta.Delta + block1->DiskWriteRawDelta.Delta, block2->DiskReadRawDelta.Delta + block2->DiskWriteRawDelta.Delta);
break;
case ETPRTNC_NETWORKRECEIVES:
result = uint64cmp(block1->NetworkReceiveCount, block2->NetworkReceiveCount);
break;
case ETPRTNC_NETWORKSENDS:
result = uint64cmp(block1->NetworkSendCount, block2->NetworkSendCount);
break;
case ETPRTNC_NETWORKRECEIVEBYTES:
result = uint64cmp(block1->NetworkReceiveRaw, block2->NetworkReceiveRaw);
break;
case ETPRTNC_NETWORKSENDBYTES:
result = uint64cmp(block1->NetworkSendRaw, block2->NetworkSendRaw);
break;
case ETPRTNC_NETWORKTOTALBYTES:
result = uint64cmp(block1->NetworkReceiveRaw + block1->NetworkSendRaw, block2->NetworkReceiveRaw + block2->NetworkSendRaw);
break;
case ETPRTNC_NETWORKRECEIVESDELTA:
result = uint64cmp(block1->NetworkReceiveDelta.Delta, block2->NetworkReceiveDelta.Delta);
break;
case ETPRTNC_NETWORKSENDSDELTA:
result = uint64cmp(block1->NetworkSendDelta.Delta, block2->NetworkSendDelta.Delta);
break;
case ETPRTNC_NETWORKRECEIVEBYTESDELTA:
result = uint64cmp(block1->NetworkReceiveRawDelta.Delta, block2->NetworkReceiveRawDelta.Delta);
break;
case ETPRTNC_NETWORKSENDBYTESDELTA:
result = uint64cmp(block1->NetworkSendRawDelta.Delta, block2->NetworkSendRawDelta.Delta);
break;
case ETPRTNC_NETWORKTOTALBYTESDELTA:
result = uint64cmp(block1->NetworkReceiveRawDelta.Delta + block1->NetworkSendRawDelta.Delta, block2->NetworkReceiveRawDelta.Delta + block2->NetworkSendRawDelta.Delta);
break;
case ETPRTNC_HARDFAULTS:
result = uintcmp(block1->HardFaultsDelta.Value, block2->HardFaultsDelta.Value);
break;
case ETPRTNC_HARDFAULTSDELTA:
result = uintcmp(block1->HardFaultsDelta.Delta, block2->HardFaultsDelta.Delta);
break;
case ETPRTNC_PEAKTHREADS:
result = uintcmp(block1->ProcessItem->PeakNumberOfThreads, block2->ProcessItem->PeakNumberOfThreads);
break;
case ETPRTNC_GPU:
result = singlecmp(block1->GpuNodeUsage, block2->GpuNodeUsage);
break;
case ETPRTNC_GPUDEDICATEDBYTES:
result = uint64cmp(block1->GpuDedicatedUsage, block2->GpuDedicatedUsage);
break;
case ETPRTNC_GPUSHAREDBYTES:
result = uint64cmp(block1->GpuSharedUsage, block2->GpuSharedUsage);
break;
case ETPRTNC_DISKREADRATE:
result = uint64cmp(block1->DiskReadRawDelta.Delta, block2->DiskReadRawDelta.Delta);
break;
case ETPRTNC_DISKWRITERATE:
result = uint64cmp(block1->DiskWriteRawDelta.Delta, block2->DiskWriteRawDelta.Delta);
break;
case ETPRTNC_DISKTOTALRATE:
result = uint64cmp(block1->DiskReadRawDelta.Delta + block1->DiskWriteRawDelta.Delta, block2->DiskReadRawDelta.Delta + block2->DiskWriteRawDelta.Delta);
break;
case ETPRTNC_NETWORKRECEIVERATE:
result = uint64cmp(block1->NetworkReceiveRawDelta.Delta, block2->NetworkReceiveRawDelta.Delta);
break;
case ETPRTNC_NETWORKSENDRATE:
result = uint64cmp(block1->NetworkSendRawDelta.Delta, block2->NetworkSendRawDelta.Delta);
break;
case ETPRTNC_NETWORKTOTALRATE:
result = uint64cmp(block1->NetworkReceiveRawDelta.Delta + block1->NetworkSendRawDelta.Delta, block2->NetworkReceiveRawDelta.Delta + block2->NetworkSendRawDelta.Delta);
break;
}
return result;
}
VOID EtNetworkTreeNewInitializing(
_In_ PVOID Parameter
)
{
static COLUMN_INFO columns[] =
{
{ ETNETNC_RECEIVES, L"Receives", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETNETNC_SENDS, L"Sends", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETNETNC_RECEIVEBYTES, L"Receive bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETNETNC_SENDBYTES, L"Send bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETNETNC_TOTALBYTES, L"Total bytes", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETNETNC_RECEIVESDELTA, L"Receives delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETNETNC_SENDSDELTA, L"Sends delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETNETNC_RECEIVEBYTESDELTA, L"Receive bytes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETNETNC_SENDBYTESDELTA, L"Send bytes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETNETNC_TOTALBYTESDELTA, L"Total bytes delta", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETNETNC_FIREWALLSTATUS, L"Firewall status", 170, PH_ALIGN_LEFT, 0, FALSE },
{ ETNETNC_RECEIVERATE, L"Receive rate", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETNETNC_SENDRATE, L"Send rate", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE },
{ ETNETNC_TOTALRATE, L"Total rate", 70, PH_ALIGN_RIGHT, DT_RIGHT, TRUE }
};
PPH_PLUGIN_TREENEW_INFORMATION treeNewInfo = Parameter;
ULONG i;
for (i = 0; i < sizeof(columns) / sizeof(COLUMN_INFO); i++)
{
EtpAddTreeNewColumn(treeNewInfo, columns[i].SubId, columns[i].Text, columns[i].Width, columns[i].Alignment,
columns[i].TextFlags, columns[i].SortDescending, EtpNetworkTreeNewSortFunction);
}
}
VOID EtpUpdateFirewallStatus(
_Inout_ PET_NETWORK_BLOCK Block
)
{
if (!Block->FirewallStatusValid)
{
Block->FirewallStatus = EtQueryFirewallStatus(Block->NetworkItem);
Block->FirewallStatusValid = TRUE;
}
}
VOID EtNetworkTreeNewMessage(
_In_ PVOID Parameter
)
{
PPH_PLUGIN_TREENEW_MESSAGE message = Parameter;
if (message->Message == TreeNewGetCellText)
{
PPH_TREENEW_GET_CELL_TEXT getCellText = message->Parameter1;
PPH_NETWORK_NODE networkNode = (PPH_NETWORK_NODE)getCellText->Node;
PET_NETWORK_BLOCK block;
PPH_STRING text;
block = EtGetNetworkBlock(networkNode->NetworkItem);
PhAcquireQueuedLockExclusive(&block->TextCacheLock);
if (block->TextCacheValid[message->SubId])
{
if (block->TextCache[message->SubId])
getCellText->Text = block->TextCache[message->SubId]->sr;
}
else
{
text = NULL;
switch (message->SubId)
{
case ETNETNC_RECEIVES:
if (block->ReceiveCount != 0)
text = PhFormatUInt64(block->ReceiveCount, TRUE);
break;
case ETNETNC_SENDS:
if (block->SendCount != 0)
text = PhFormatUInt64(block->SendCount, TRUE);
break;
case ETNETNC_RECEIVEBYTES:
if (block->ReceiveRaw != 0)
text = PhFormatSize(block->ReceiveRaw, -1);
break;
case ETNETNC_SENDBYTES:
if (block->SendRaw != 0)
text = PhFormatSize(block->SendRaw, -1);
break;
case ETNETNC_TOTALBYTES:
if (block->ReceiveRaw + block->SendRaw != 0)
text = PhFormatSize(block->ReceiveRaw + block->SendRaw, -1);
break;
case ETNETNC_RECEIVESDELTA:
if (block->ReceiveDelta.Delta != 0)
text = PhFormatUInt64(block->ReceiveDelta.Delta, TRUE);
break;
case ETNETNC_SENDSDELTA:
if (block->SendDelta.Delta != 0)
text = PhFormatUInt64(block->SendDelta.Delta, TRUE);
break;
case ETNETNC_RECEIVEBYTESDELTA:
if (block->ReceiveRawDelta.Delta != 0)
text = PhFormatSize(block->ReceiveRawDelta.Delta, -1);
break;
case ETNETNC_SENDBYTESDELTA:
if (block->SendRawDelta.Delta != 0)
text = PhFormatSize(block->SendRawDelta.Delta, -1);
break;
case ETNETNC_TOTALBYTESDELTA:
if (block->ReceiveRawDelta.Delta + block->SendRawDelta.Delta != 0)
text = PhFormatSize(block->ReceiveRawDelta.Delta + block->SendRawDelta.Delta, -1);
break;
case ETNETNC_FIREWALLSTATUS:
{
static PPH_STRING strings[FirewallMaximumStatus];
static PH_INITONCE initOnce = PH_INITONCE_INIT;
if (PhBeginInitOnce(&initOnce))
{
strings[FirewallUnknownStatus] = NULL;
strings[FirewallAllowedNotRestricted] = PhCreateString(L"Allowed, not restricted");
strings[FirewallAllowedRestricted] = PhCreateString(L"Allowed, restricted");
strings[FirewallNotAllowedNotRestricted] = PhCreateString(L"Not allowed, not restricted");
strings[FirewallNotAllowedRestricted] = PhCreateString(L"Not allowed, restricted");
PhEndInitOnce(&initOnce);
}
EtpUpdateFirewallStatus(block);
if (block->FirewallStatus < FirewallMaximumStatus)
PhSetReference(&text, strings[block->FirewallStatus]);
}
break;
case ETNETNC_RECEIVERATE:
if (block->ReceiveRawDelta.Delta != 0)
EtFormatRate(block->ReceiveRawDelta.Delta, &text, NULL);
break;
case ETNETNC_SENDRATE:
if (block->SendRawDelta.Delta != 0)
EtFormatRate(block->SendRawDelta.Delta, &text, NULL);
break;
case ETNETNC_TOTALRATE:
if (block->ReceiveRawDelta.Delta + block->SendRawDelta.Delta != 0)
EtFormatRate(block->ReceiveRawDelta.Delta + block->SendRawDelta.Delta, &text, NULL);
break;
}
if (text)
{
getCellText->Text = text->sr;
}
PhMoveReference(&block->TextCache[message->SubId], text);
block->TextCacheValid[message->SubId] = TRUE;
}
PhReleaseQueuedLockExclusive(&block->TextCacheLock);
}
}
LONG EtpNetworkTreeNewSortFunction(
_In_ PVOID Node1,
_In_ PVOID Node2,
_In_ ULONG SubId,
_In_ PVOID Context
)
{
LONG result;
PPH_NETWORK_NODE node1 = Node1;
PPH_NETWORK_NODE node2 = Node2;
PET_NETWORK_BLOCK block1;
PET_NETWORK_BLOCK block2;
block1 = EtGetNetworkBlock(node1->NetworkItem);
block2 = EtGetNetworkBlock(node2->NetworkItem);
result = 0;
switch (SubId)
{
case ETNETNC_RECEIVES:
result = uint64cmp(block1->ReceiveCount, block2->ReceiveCount);
break;
case ETNETNC_SENDS:
result = uint64cmp(block1->SendCount, block2->SendCount);
break;
case ETNETNC_RECEIVEBYTES:
result = uint64cmp(block1->ReceiveRaw, block2->ReceiveRaw);
break;
case ETNETNC_SENDBYTES:
result = uint64cmp(block1->SendRaw, block2->SendRaw);
break;
case ETNETNC_TOTALBYTES:
result = uint64cmp(block1->ReceiveRaw + block1->SendRaw, block2->ReceiveRaw + block2->SendRaw);
break;
case ETNETNC_RECEIVESDELTA:
result = uint64cmp(block1->ReceiveDelta.Delta, block2->ReceiveDelta.Delta);
break;
case ETNETNC_SENDSDELTA:
result = uint64cmp(block1->SendDelta.Delta, block2->SendDelta.Delta);
break;
case ETNETNC_RECEIVEBYTESDELTA:
result = uint64cmp(block1->ReceiveRawDelta.Delta, block2->ReceiveRawDelta.Delta);
break;
case ETNETNC_SENDBYTESDELTA:
result = uint64cmp(block1->SendRawDelta.Delta, block2->SendRawDelta.Delta);
break;
case ETNETNC_TOTALBYTESDELTA:
result = uint64cmp(block1->ReceiveRawDelta.Delta + block1->SendRawDelta.Delta, block2->ReceiveRawDelta.Delta + block2->SendRawDelta.Delta);
break;
case ETNETNC_FIREWALLSTATUS:
EtpUpdateFirewallStatus(block1);
EtpUpdateFirewallStatus(block2);
result = intcmp(block1->FirewallStatus, block2->FirewallStatus);
break;
case ETNETNC_RECEIVERATE:
result = uint64cmp(block1->ReceiveRawDelta.Delta, block2->ReceiveRawDelta.Delta);
break;
case ETNETNC_SENDRATE:
result = uint64cmp(block1->SendRawDelta.Delta, block2->SendRawDelta.Delta);
break;
case ETNETNC_TOTALRATE:
result = uint64cmp(block1->ReceiveRawDelta.Delta + block1->SendRawDelta.Delta, block2->ReceiveRawDelta.Delta + block2->SendRawDelta.Delta);
break;
}
return result;
}
ET_FIREWALL_STATUS EtQueryFirewallStatus(
_In_ PPH_NETWORK_ITEM NetworkItem
)
{
static INetFwMgr* manager = NULL;
ET_FIREWALL_STATUS result;
PPH_PROCESS_ITEM processItem;
BSTR imageFileNameBStr;
BSTR localAddressBStr;
VARIANT allowed;
VARIANT restricted;
if (!manager)
{
if (!SUCCEEDED(CoCreateInstance(&CLSID_NetFwMgr_I, NULL, CLSCTX_INPROC_SERVER, &IID_INetFwMgr_I, &manager)))
return FirewallUnknownStatus;
if (!manager)
return FirewallUnknownStatus;
}
processItem = PhReferenceProcessItem(NetworkItem->ProcessId);
if (!processItem)
return FirewallUnknownStatus;
if (!processItem->FileName)
{
PhDereferenceObject(processItem);
return FirewallUnknownStatus;
}
result = FirewallUnknownStatus;
if (imageFileNameBStr = SysAllocStringLen(processItem->FileName->Buffer, (ULONG)processItem->FileName->Length / sizeof(WCHAR)))
{
localAddressBStr = NULL;
if (!PhIsNullIpAddress(&NetworkItem->LocalEndpoint.Address))
localAddressBStr = SysAllocString(NetworkItem->LocalAddressString);
if (SUCCEEDED(INetFwMgr_IsPortAllowed(
manager,
imageFileNameBStr,
(NetworkItem->ProtocolType & PH_IPV6_NETWORK_TYPE) ? NET_FW_IP_VERSION_V6 : NET_FW_IP_VERSION_V4,
NetworkItem->LocalEndpoint.Port,
localAddressBStr,
(NetworkItem->ProtocolType & PH_UDP_PROTOCOL_TYPE) ? NET_FW_IP_PROTOCOL_UDP : NET_FW_IP_PROTOCOL_TCP,
&allowed,
&restricted
)))
{
if (allowed.boolVal)
{
if (restricted.boolVal)
result = FirewallAllowedRestricted;
else
result = FirewallAllowedNotRestricted;
}
else
{
if (restricted.boolVal)
result = FirewallNotAllowedRestricted;
else
result = FirewallNotAllowedNotRestricted;
}
}
if (localAddressBStr)
SysFreeString(localAddressBStr);
SysFreeString(imageFileNameBStr);
}
PhDereferenceObject(processItem);
return result;
}

View File

@@ -0,0 +1,357 @@
/*
* Process Hacker Extended Tools -
* unloaded DLLs display
*
* Copyright (C) 2010-2011 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 "exttools.h"
typedef struct _UNLOADED_DLLS_CONTEXT
{
PPH_PROCESS_ITEM ProcessItem;
HWND ListViewHandle;
PVOID CapturedEventTrace;
} UNLOADED_DLLS_CONTEXT, *PUNLOADED_DLLS_CONTEXT;
INT_PTR CALLBACK EtpUnloadedDllsDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
VOID EtShowUnloadedDllsDialog(
_In_ HWND ParentWindowHandle,
_In_ PPH_PROCESS_ITEM ProcessItem
)
{
UNLOADED_DLLS_CONTEXT context;
context.ProcessItem = ProcessItem;
context.CapturedEventTrace = NULL;
DialogBoxParam(
PluginInstance->DllBase,
MAKEINTRESOURCE(IDD_UNLOADEDDLLS),
ParentWindowHandle,
EtpUnloadedDllsDlgProc,
(LPARAM)&context
);
if (context.CapturedEventTrace)
PhFree(context.CapturedEventTrace);
}
BOOLEAN EtpRefreshUnloadedDlls(
_In_ HWND hwndDlg,
_In_ PUNLOADED_DLLS_CONTEXT Context
)
{
NTSTATUS status;
PULONG elementSize;
PULONG elementCount;
PVOID eventTrace;
HANDLE processHandle = NULL;
ULONG eventTraceSize;
ULONG capturedElementSize;
ULONG capturedElementCount;
PVOID capturedEventTracePointer;
PVOID capturedEventTrace = NULL;
ULONG i;
PVOID currentEvent;
HWND lvHandle;
lvHandle = GetDlgItem(hwndDlg, IDC_LIST);
ListView_DeleteAllItems(lvHandle);
RtlGetUnloadEventTraceEx(&elementSize, &elementCount, &eventTrace);
if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_VM_READ, Context->ProcessItem->ProcessId)))
goto CleanupExit;
// We have the pointers for the unload event trace information.
// Since ntdll is loaded at the same base address across all processes,
// we can read the information in.
if (!NT_SUCCESS(status = NtReadVirtualMemory(
processHandle,
elementSize,
&capturedElementSize,
sizeof(ULONG),
NULL
)))
goto CleanupExit;
if (!NT_SUCCESS(status = NtReadVirtualMemory(
processHandle,
elementCount,
&capturedElementCount,
sizeof(ULONG),
NULL
)))
goto CleanupExit;
if (!NT_SUCCESS(status = NtReadVirtualMemory(
processHandle,
eventTrace,
&capturedEventTracePointer,
sizeof(PVOID),
NULL
)))
goto CleanupExit;
if (!capturedEventTracePointer)
goto CleanupExit; // no events
if (capturedElementCount > 0x4000)
capturedElementCount = 0x4000;
eventTraceSize = capturedElementSize * capturedElementCount;
capturedEventTrace = PhAllocateSafe(eventTraceSize);
if (!capturedEventTrace)
{
status = STATUS_NO_MEMORY;
goto CleanupExit;
}
if (!NT_SUCCESS(status = NtReadVirtualMemory(
processHandle,
capturedEventTracePointer,
capturedEventTrace,
eventTraceSize,
NULL
)))
goto CleanupExit;
currentEvent = capturedEventTrace;
ExtendedListView_SetRedraw(lvHandle, FALSE);
for (i = 0; i < capturedElementCount; i++)
{
PRTL_UNLOAD_EVENT_TRACE rtlEvent = currentEvent;
INT lvItemIndex;
WCHAR buffer[128];
PPH_STRING string;
LARGE_INTEGER time;
SYSTEMTIME systemTime;
if (!rtlEvent->BaseAddress)
break;
PhPrintUInt32(buffer, rtlEvent->Sequence);
lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, buffer, rtlEvent);
// Name
if (PhCopyStringZ(rtlEvent->ImageName, sizeof(rtlEvent->ImageName) / sizeof(WCHAR),
buffer, sizeof(buffer) / sizeof(WCHAR), NULL))
{
PhSetListViewSubItem(lvHandle, lvItemIndex, 1, buffer);
}
// Base Address
PhPrintPointer(buffer, rtlEvent->BaseAddress);
PhSetListViewSubItem(lvHandle, lvItemIndex, 2, buffer);
// Size
string = PhFormatSize(rtlEvent->SizeOfImage, -1);
PhSetListViewSubItem(lvHandle, lvItemIndex, 3, string->Buffer);
PhDereferenceObject(string);
// Time Stamp
RtlSecondsSince1970ToTime(rtlEvent->TimeDateStamp, &time);
PhLargeIntegerToLocalSystemTime(&systemTime, &time);
string = PhFormatDateTime(&systemTime);
PhSetListViewSubItem(lvHandle, lvItemIndex, 4, string->Buffer);
PhDereferenceObject(string);
// Checksum
PhPrintPointer(buffer, UlongToPtr(rtlEvent->CheckSum));
PhSetListViewSubItem(lvHandle, lvItemIndex, 5, buffer);
currentEvent = PTR_ADD_OFFSET(currentEvent, capturedElementSize);
}
ExtendedListView_SortItems(lvHandle);
ExtendedListView_SetRedraw(lvHandle, TRUE);
if (Context->CapturedEventTrace)
PhFree(Context->CapturedEventTrace);
Context->CapturedEventTrace = capturedEventTrace;
CleanupExit:
if (processHandle)
NtClose(processHandle);
if (NT_SUCCESS(status))
{
return TRUE;
}
else
{
PhShowStatus(hwndDlg, L"Unable to retrieve unload event trace information", status, 0);
return FALSE;
}
}
static INT NTAPI EtpNumberCompareFunction(
_In_ PVOID Item1,
_In_ PVOID Item2,
_In_opt_ PVOID Context
)
{
PRTL_UNLOAD_EVENT_TRACE item1 = Item1;
PRTL_UNLOAD_EVENT_TRACE item2 = Item2;
return uintcmp(item1->Sequence, item2->Sequence);
}
static INT NTAPI EtpBaseAddressCompareFunction(
_In_ PVOID Item1,
_In_ PVOID Item2,
_In_opt_ PVOID Context
)
{
PRTL_UNLOAD_EVENT_TRACE item1 = Item1;
PRTL_UNLOAD_EVENT_TRACE item2 = Item2;
return uintptrcmp((ULONG_PTR)item1->BaseAddress, (ULONG_PTR)item2->BaseAddress);
}
static INT NTAPI EtpSizeCompareFunction(
_In_ PVOID Item1,
_In_ PVOID Item2,
_In_opt_ PVOID Context
)
{
PRTL_UNLOAD_EVENT_TRACE item1 = Item1;
PRTL_UNLOAD_EVENT_TRACE item2 = Item2;
return uintptrcmp(item1->SizeOfImage, item2->SizeOfImage);
}
static INT NTAPI EtpTimeStampCompareFunction(
_In_ PVOID Item1,
_In_ PVOID Item2,
_In_opt_ PVOID Context
)
{
PRTL_UNLOAD_EVENT_TRACE item1 = Item1;
PRTL_UNLOAD_EVENT_TRACE item2 = Item2;
return uintcmp(item1->TimeDateStamp, item2->TimeDateStamp);
}
static INT NTAPI EtpCheckSumCompareFunction(
_In_ PVOID Item1,
_In_ PVOID Item2,
_In_opt_ PVOID Context
)
{
PRTL_UNLOAD_EVENT_TRACE item1 = Item1;
PRTL_UNLOAD_EVENT_TRACE item2 = Item2;
return uintcmp(item1->CheckSum, item2->CheckSum);
}
INT_PTR CALLBACK EtpUnloadedDllsDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
PUNLOADED_DLLS_CONTEXT context;
if (uMsg == WM_INITDIALOG)
{
context = (PUNLOADED_DLLS_CONTEXT)lParam;
SetProp(hwndDlg, L"Context", (HANDLE)context);
}
else
{
context = (PUNLOADED_DLLS_CONTEXT)GetProp(hwndDlg, L"Context");
if (uMsg == WM_DESTROY)
RemoveProp(hwndDlg, L"Context");
}
if (!context)
return FALSE;
switch (uMsg)
{
case WM_INITDIALOG:
{
HWND lvHandle;
PhCenterWindow(hwndDlg, GetParent(hwndDlg));
context->ListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_LIST);
PhSetListViewStyle(lvHandle, FALSE, TRUE);
PhSetControlTheme(lvHandle, L"explorer");
PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"No.");
PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 120, L"Name");
PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 80, L"Base Address");
PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 60, L"Size");
PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 100, L"Time Stamp");
PhAddListViewColumn(lvHandle, 5, 5, 5, LVCFMT_LEFT, 60, L"Checksum");
PhSetExtendedListView(lvHandle);
ExtendedListView_SetCompareFunction(lvHandle, 0, EtpNumberCompareFunction);
ExtendedListView_SetCompareFunction(lvHandle, 2, EtpBaseAddressCompareFunction);
ExtendedListView_SetCompareFunction(lvHandle, 3, EtpSizeCompareFunction);
ExtendedListView_SetCompareFunction(lvHandle, 4, EtpTimeStampCompareFunction);
ExtendedListView_SetCompareFunction(lvHandle, 5, EtpCheckSumCompareFunction);
if (!EtpRefreshUnloadedDlls(hwndDlg, context))
{
EndDialog(hwndDlg, IDCANCEL);
return FALSE;
}
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDCANCEL:
case IDOK:
EndDialog(hwndDlg, IDOK);
break;
case IDC_REFRESH:
EtpRefreshUnloadedDlls(hwndDlg, context);
break;
}
}
break;
case WM_NOTIFY:
{
PhHandleListViewNotifyForCopy(lParam, context->ListViewHandle);
}
break;
}
return FALSE;
}

View File

@@ -0,0 +1,48 @@
/*
* Process Hacker Extended Tools -
* utility functions
*
* Copyright (C) 2011 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 "exttools.h"
VOID EtFormatRate(
_In_ ULONG64 ValuePerPeriod,
_Inout_ PPH_STRING *Buffer,
_Out_opt_ PPH_STRINGREF String
)
{
ULONG64 number;
number = ValuePerPeriod;
number *= 1000;
number /= PhGetIntegerSetting(L"UpdateInterval");
if (number != 0)
{
PH_FORMAT format[2];
PhInitFormatSize(&format[0], number);
PhInitFormatS(&format[1], L"/s");
PhMoveReference(Buffer, PhFormat(format, 2, 0));
if (String)
*String = (*Buffer)->sr;
}
}

View File

@@ -0,0 +1,571 @@
/*
* Process Hacker Extended Tools -
* working set watch
*
* Copyright (C) 2011 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 "exttools.h"
#include <workqueue.h>
#include <symprv.h>
typedef struct _WS_WATCH_CONTEXT
{
LONG RefCount;
PPH_PROCESS_ITEM ProcessItem;
HWND WindowHandle;
HWND ListViewHandle;
BOOLEAN Enabled;
BOOLEAN Destroying;
PPH_HASHTABLE Hashtable;
HANDLE ProcessHandle;
PVOID Buffer;
ULONG BufferSize;
PPH_SYMBOL_PROVIDER SymbolProvider;
HANDLE LoadingSymbolsForProcessId;
SINGLE_LIST_ENTRY ResultListHead;
PH_QUEUED_LOCK ResultListLock;
} WS_WATCH_CONTEXT, *PWS_WATCH_CONTEXT;
typedef struct _SYMBOL_LOOKUP_RESULT
{
SINGLE_LIST_ENTRY ListEntry;
PWS_WATCH_CONTEXT Context;
PVOID Address;
PPH_STRING Symbol;
} SYMBOL_LOOKUP_RESULT, *PSYMBOL_LOOKUP_RESULT;
VOID EtpReferenceWsWatchContext(
_Inout_ PWS_WATCH_CONTEXT Context
);
VOID EtpDereferenceWsWatchContext(
_Inout_ PWS_WATCH_CONTEXT Context
);
INT_PTR CALLBACK EtpWsWatchDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
VOID EtShowWsWatchDialog(
_In_ HWND ParentWindowHandle,
_In_ PPH_PROCESS_ITEM ProcessItem
)
{
PWS_WATCH_CONTEXT context;
context = PhAllocate(sizeof(WS_WATCH_CONTEXT));
memset(context, 0, sizeof(WS_WATCH_CONTEXT));
context->RefCount = 1;
context->ProcessItem = ProcessItem;
DialogBoxParam(
PluginInstance->DllBase,
MAKEINTRESOURCE(IDD_WSWATCH),
ParentWindowHandle,
EtpWsWatchDlgProc,
(LPARAM)context
);
EtpDereferenceWsWatchContext(context);
}
static VOID EtpReferenceWsWatchContext(
_Inout_ PWS_WATCH_CONTEXT Context
)
{
_InterlockedIncrement(&Context->RefCount);
}
static VOID EtpDereferenceWsWatchContext(
_Inout_ PWS_WATCH_CONTEXT Context
)
{
if (_InterlockedDecrement(&Context->RefCount) == 0)
{
PSINGLE_LIST_ENTRY listEntry;
if (Context->SymbolProvider)
PhDereferenceObject(Context->SymbolProvider);
// Free all unused results.
PhAcquireQueuedLockExclusive(&Context->ResultListLock);
listEntry = Context->ResultListHead.Next;
while (listEntry)
{
PSYMBOL_LOOKUP_RESULT result;
result = CONTAINING_RECORD(listEntry, SYMBOL_LOOKUP_RESULT, ListEntry);
listEntry = listEntry->Next;
PhDereferenceObject(result->Symbol);
PhFree(result);
}
PhReleaseQueuedLockExclusive(&Context->ResultListLock);
PhFree(Context);
}
}
static NTSTATUS EtpSymbolLookupFunction(
_In_ PVOID Parameter
)
{
PSYMBOL_LOOKUP_RESULT result;
result = Parameter;
// Don't bother looking up the symbol if the window has already closed.
if (result->Context->Destroying)
{
EtpDereferenceWsWatchContext(result->Context);
PhFree(result);
return STATUS_SUCCESS;
}
result->Symbol = PhGetSymbolFromAddress(
result->Context->SymbolProvider,
(ULONG64)result->Address,
NULL,
NULL,
NULL,
NULL
);
// Fail if we don't have a symbol.
if (!result->Symbol)
{
EtpDereferenceWsWatchContext(result->Context);
PhFree(result);
return STATUS_SUCCESS;
}
PhAcquireQueuedLockExclusive(&result->Context->ResultListLock);
PushEntryList(&result->Context->ResultListHead, &result->ListEntry);
PhReleaseQueuedLockExclusive(&result->Context->ResultListLock);
EtpDereferenceWsWatchContext(result->Context);
return STATUS_SUCCESS;
}
static VOID EtpQueueSymbolLookup(
_In_ PWS_WATCH_CONTEXT Context,
_In_ PVOID Address
)
{
PSYMBOL_LOOKUP_RESULT result;
result = PhAllocate(sizeof(SYMBOL_LOOKUP_RESULT));
result->Context = Context;
result->Address = Address;
EtpReferenceWsWatchContext(Context);
PhQueueItemWorkQueue(PhGetGlobalWorkQueue(), EtpSymbolLookupFunction, result);
}
static PPH_STRING EtpGetBasicSymbol(
_In_ PPH_SYMBOL_PROVIDER SymbolProvider,
_In_ ULONG64 Address
)
{
ULONG64 modBase;
PPH_STRING fileName = NULL;
PPH_STRING baseName = NULL;
PPH_STRING symbol;
modBase = PhGetModuleFromAddress(SymbolProvider, Address, &fileName);
if (!fileName)
{
symbol = PhCreateStringEx(NULL, PH_PTR_STR_LEN * 2);
PhPrintPointer(symbol->Buffer, (PVOID)Address);
PhTrimToNullTerminatorString(symbol);
}
else
{
PH_FORMAT format[3];
baseName = PhGetBaseName(fileName);
PhInitFormatSR(&format[0], baseName->sr);
PhInitFormatS(&format[1], L"+0x");
PhInitFormatIX(&format[2], (ULONG_PTR)(Address - modBase));
symbol = PhFormat(format, 3, baseName->Length + 6 + 32);
}
if (fileName)
PhDereferenceObject(fileName);
if (baseName)
PhDereferenceObject(baseName);
return symbol;
}
static VOID EtpProcessSymbolLookupResults(
_In_ HWND hwndDlg,
_In_ PWS_WATCH_CONTEXT Context
)
{
PSINGLE_LIST_ENTRY listEntry;
// Remove all results.
PhAcquireQueuedLockExclusive(&Context->ResultListLock);
listEntry = Context->ResultListHead.Next;
Context->ResultListHead.Next = NULL;
PhReleaseQueuedLockExclusive(&Context->ResultListLock);
// Update the list view with the results.
while (listEntry)
{
PSYMBOL_LOOKUP_RESULT result;
result = CONTAINING_RECORD(listEntry, SYMBOL_LOOKUP_RESULT, ListEntry);
listEntry = listEntry->Next;
PhSetListViewSubItem(
Context->ListViewHandle,
PhFindListViewItemByParam(Context->ListViewHandle, -1, result->Address),
0,
result->Symbol->Buffer
);
PhDereferenceObject(result->Symbol);
PhFree(result);
}
}
static BOOLEAN EtpUpdateWsWatch(
_In_ HWND hwndDlg,
_In_ PWS_WATCH_CONTEXT Context
)
{
NTSTATUS status;
BOOLEAN result;
ULONG returnLength;
PPROCESS_WS_WATCH_INFORMATION_EX wsWatchInfo;
// Query WS watch information.
if (!Context->Buffer)
return FALSE;
status = NtQueryInformationProcess(
Context->ProcessHandle,
ProcessWorkingSetWatchEx,
Context->Buffer,
Context->BufferSize,
&returnLength
);
if (status == STATUS_UNSUCCESSFUL)
{
// WS Watch is not enabled.
return FALSE;
}
if (status == STATUS_NO_MORE_ENTRIES)
{
// There were no new faults, but we still need to process symbol lookup results.
result = TRUE;
goto SkipBuffer;
}
if (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_INFO_LENGTH_MISMATCH)
{
PhFree(Context->Buffer);
Context->Buffer = PhAllocate(returnLength);
Context->BufferSize = returnLength;
status = NtQueryInformationProcess(
Context->ProcessHandle,
ProcessWorkingSetWatchEx,
Context->Buffer,
Context->BufferSize,
&returnLength
);
}
if (!NT_SUCCESS(status))
{
// Error related to the buffer size. Try again later.
result = FALSE;
goto SkipBuffer;
}
// Update the hashtable and list view.
ExtendedListView_SetRedraw(Context->ListViewHandle, FALSE);
wsWatchInfo = Context->Buffer;
while (wsWatchInfo->BasicInfo.FaultingPc)
{
PVOID *entry;
WCHAR buffer[PH_INT32_STR_LEN_1];
INT lvItemIndex;
ULONG newCount;
// Update the count in the entry for this instruction pointer, or add a new entry if it doesn't exist.
entry = PhFindItemSimpleHashtable(Context->Hashtable, wsWatchInfo->BasicInfo.FaultingPc);
if (entry)
{
newCount = PtrToUlong(*entry) + 1;
*entry = UlongToPtr(newCount);
lvItemIndex = PhFindListViewItemByParam(Context->ListViewHandle, -1, wsWatchInfo->BasicInfo.FaultingPc);
}
else
{
PPH_STRING basicSymbol;
newCount = 1;
PhAddItemSimpleHashtable(Context->Hashtable, wsWatchInfo->BasicInfo.FaultingPc, UlongToPtr(1));
// Get a basic symbol name (module+offset).
basicSymbol = EtpGetBasicSymbol(Context->SymbolProvider, (ULONG64)wsWatchInfo->BasicInfo.FaultingPc);
lvItemIndex = PhAddListViewItem(Context->ListViewHandle, MAXINT, basicSymbol->Buffer, wsWatchInfo->BasicInfo.FaultingPc);
PhDereferenceObject(basicSymbol);
// Queue a full symbol lookup.
EtpQueueSymbolLookup(Context, wsWatchInfo->BasicInfo.FaultingPc);
}
// Update the count in the list view item.
PhPrintUInt32(buffer, newCount);
PhSetListViewSubItem(
Context->ListViewHandle,
lvItemIndex,
1,
buffer
);
wsWatchInfo++;
}
ExtendedListView_SetRedraw(Context->ListViewHandle, TRUE);
result = TRUE;
SkipBuffer:
EtpProcessSymbolLookupResults(hwndDlg, Context);
ExtendedListView_SortItems(Context->ListViewHandle);
return result;
}
static BOOLEAN NTAPI EnumGenericModulesCallback(
_In_ PPH_MODULE_INFO Module,
_In_opt_ PVOID Context
)
{
PWS_WATCH_CONTEXT context = Context;
// If we're loading kernel module symbols for a process other than
// System, ignore modules which are in user space. This may happen
// in Windows 7.
if (
context->LoadingSymbolsForProcessId == SYSTEM_PROCESS_ID &&
(ULONG_PTR)Module->BaseAddress <= PhSystemBasicInformation.MaximumUserModeAddress
)
return TRUE;
PhLoadModuleSymbolProvider(context->SymbolProvider, Module->FileName->Buffer,
(ULONG64)Module->BaseAddress, Module->Size);
return TRUE;
}
INT_PTR CALLBACK EtpWsWatchDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
PWS_WATCH_CONTEXT context;
if (uMsg == WM_INITDIALOG)
{
context = (PWS_WATCH_CONTEXT)lParam;
SetProp(hwndDlg, L"Context", (HANDLE)context);
}
else
{
context = (PWS_WATCH_CONTEXT)GetProp(hwndDlg, L"Context");
if (uMsg == WM_DESTROY)
RemoveProp(hwndDlg, L"Context");
}
if (!context)
return FALSE;
switch (uMsg)
{
case WM_INITDIALOG:
{
HWND lvHandle;
PhCenterWindow(hwndDlg, GetParent(hwndDlg));
context->WindowHandle = hwndDlg;
context->ListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_LIST);
PhSetListViewStyle(lvHandle, FALSE, TRUE);
PhSetControlTheme(lvHandle, L"explorer");
PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 340, L"Instruction");
PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 80, L"Count");
PhSetExtendedListView(lvHandle);
ExtendedListView_SetSort(lvHandle, 1, DescendingSortOrder);
context->Hashtable = PhCreateSimpleHashtable(64);
context->BufferSize = 0x2000;
context->Buffer = PhAllocate(context->BufferSize);
PhInitializeQueuedLock(&context->ResultListLock);
context->SymbolProvider = PhCreateSymbolProvider(context->ProcessItem->ProcessId);
PhLoadSymbolProviderOptions(context->SymbolProvider);
if (!context->SymbolProvider || !context->SymbolProvider->IsRealHandle)
{
PhShowError(hwndDlg, L"Unable to open the process.");
EndDialog(hwndDlg, IDCANCEL);
break;
}
context->ProcessHandle = context->SymbolProvider->ProcessHandle;
// Load symbols for both process and kernel modules.
context->LoadingSymbolsForProcessId = context->ProcessItem->ProcessId;
PhEnumGenericModules(
NULL,
context->ProcessHandle,
0,
EnumGenericModulesCallback,
context
);
context->LoadingSymbolsForProcessId = SYSTEM_PROCESS_ID;
PhEnumGenericModules(
SYSTEM_PROCESS_ID,
NULL,
0,
EnumGenericModulesCallback,
context
);
context->Enabled = EtpUpdateWsWatch(hwndDlg, context);
if (context->Enabled)
{
// WS Watch is already enabled for the process. Enable updating.
EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLE), FALSE);
ShowWindow(GetDlgItem(hwndDlg, IDC_WSWATCHENABLED), SW_SHOW);
SetTimer(hwndDlg, 1, 1000, NULL);
}
else
{
// WS Watch has not yet been enabled for the process.
}
}
break;
case WM_DESTROY:
{
context->Destroying = TRUE;
PhDereferenceObject(context->Hashtable);
if (context->Buffer)
{
PhFree(context->Buffer);
context->Buffer = NULL;
}
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDCANCEL:
case IDOK:
EndDialog(hwndDlg, IDOK);
break;
case IDC_ENABLE:
{
NTSTATUS status;
HANDLE processHandle;
if (NT_SUCCESS(status = PhOpenProcess(
&processHandle,
PROCESS_SET_INFORMATION,
context->ProcessItem->ProcessId
)))
{
status = NtSetInformationProcess(
processHandle,
ProcessWorkingSetWatchEx,
NULL,
0
);
NtClose(processHandle);
}
if (NT_SUCCESS(status))
{
EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLE), FALSE);
ShowWindow(GetDlgItem(hwndDlg, IDC_WSWATCHENABLED), SW_SHOW);
SetTimer(hwndDlg, 1, 1000, NULL);
}
else
{
PhShowStatus(hwndDlg, L"Unable to enable WS watch", status, 0);
}
}
break;
}
}
break;
case WM_NOTIFY:
{
PhHandleListViewNotifyForCopy(lParam, context->ListViewHandle);
}
break;
case WM_TIMER:
{
switch (wParam)
{
case 1:
{
EtpUpdateWsWatch(hwndDlg, context);
}
break;
}
}
break;
}
return FALSE;
}