go my file uploader
This commit is contained in:
65
plugins/ExtendedTools/CHANGELOG.txt
Normal file
65
plugins/ExtendedTools/CHANGELOG.txt
Normal 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
|
||||
537
plugins/ExtendedTools/ExtendedTools.rc
Normal file
537
plugins/ExtendedTools/ExtendedTools.rc
Normal 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
|
||||
|
||||
134
plugins/ExtendedTools/ExtendedTools.vcxproj
Normal file
134
plugins/ExtendedTools/ExtendedTools.vcxproj
Normal 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>
|
||||
128
plugins/ExtendedTools/ExtendedTools.vcxproj.filters
Normal file
128
plugins/ExtendedTools/ExtendedTools.vcxproj.filters
Normal 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>
|
||||
482
plugins/ExtendedTools/d3dkmt.h
Normal file
482
plugins/ExtendedTools/d3dkmt.h
Normal 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
|
||||
1176
plugins/ExtendedTools/disktab.c
Normal file
1176
plugins/ExtendedTools/disktab.c
Normal file
File diff suppressed because it is too large
Load Diff
171
plugins/ExtendedTools/disktabp.h
Normal file
171
plugins/ExtendedTools/disktabp.h
Normal 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
|
||||
536
plugins/ExtendedTools/etwdisk.c
Normal file
536
plugins/ExtendedTools/etwdisk.c
Normal 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++;
|
||||
}
|
||||
264
plugins/ExtendedTools/etwmini.c
Normal file
264
plugins/ExtendedTools/etwmini.c
Normal 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(§ion, 0, sizeof(PH_MINIINFO_LIST_SECTION));
|
||||
section.Callback = EtpDiskListSectionCallback;
|
||||
Pointers->CreateListSection(L"Disk", 0, §ion);
|
||||
|
||||
memset(§ion, 0, sizeof(PH_MINIINFO_LIST_SECTION));
|
||||
section.Callback = EtpNetworkListSectionCallback;
|
||||
|
||||
Pointers->CreateListSection(L"Network", 0, §ion);
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
38
plugins/ExtendedTools/etwmini.h
Normal file
38
plugins/ExtendedTools/etwmini.h
Normal 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
|
||||
562
plugins/ExtendedTools/etwmon.c
Normal file
562
plugins/ExtendedTools/etwmon.c
Normal 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;
|
||||
}
|
||||
140
plugins/ExtendedTools/etwmon.h
Normal file
140
plugins/ExtendedTools/etwmon.h
Normal 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
|
||||
615
plugins/ExtendedTools/etwprprp.c
Normal file
615
plugins/ExtendedTools/etwprprp.c
Normal 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)
|
||||
);
|
||||
}
|
||||
}
|
||||
419
plugins/ExtendedTools/etwstat.c
Normal file
419
plugins/ExtendedTools/etwstat.c
Normal 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;
|
||||
}
|
||||
811
plugins/ExtendedTools/etwsys.c
Normal file
811
plugins/ExtendedTools/etwsys.c
Normal 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(§ion, 0, sizeof(PH_SYSINFO_SECTION));
|
||||
PhInitializeStringRef(§ion.Name, L"Disk");
|
||||
section.Flags = 0;
|
||||
section.Callback = EtpDiskSysInfoSectionCallback;
|
||||
|
||||
DiskSection = Pointers->CreateSection(§ion);
|
||||
|
||||
memset(§ion, 0, sizeof(PH_SYSINFO_SECTION));
|
||||
PhInitializeStringRef(§ion.Name, L"Network");
|
||||
section.Flags = 0;
|
||||
section.Callback = EtpNetworkSysInfoSectionCallback;
|
||||
|
||||
NetworkSection = Pointers->CreateSection(§ion);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
90
plugins/ExtendedTools/etwsys.h
Normal file
90
plugins/ExtendedTools/etwsys.h
Normal 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
|
||||
549
plugins/ExtendedTools/exttools.h
Normal file
549
plugins/ExtendedTools/exttools.h
Normal 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
|
||||
129
plugins/ExtendedTools/gpumini.c
Normal file
129
plugins/ExtendedTools/gpumini.c
Normal 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(§ion, 0, sizeof(PH_MINIINFO_LIST_SECTION));
|
||||
section.Callback = EtpGpuListSectionCallback;
|
||||
Pointers->CreateListSection(L"GPU", 0, §ion);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
21
plugins/ExtendedTools/gpumini.h
Normal file
21
plugins/ExtendedTools/gpumini.h
Normal 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
|
||||
846
plugins/ExtendedTools/gpumon.c
Normal file
846
plugins/ExtendedTools/gpumon.c
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
43
plugins/ExtendedTools/gpumon.h
Normal file
43
plugins/ExtendedTools/gpumon.h
Normal 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
|
||||
430
plugins/ExtendedTools/gpunodes.c
Normal file
430
plugins/ExtendedTools/gpunodes.c
Normal 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;
|
||||
}
|
||||
767
plugins/ExtendedTools/gpuprprp.c
Normal file
767
plugins/ExtendedTools/gpuprprp.c
Normal 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)
|
||||
);
|
||||
}
|
||||
}
|
||||
722
plugins/ExtendedTools/gpusys.c
Normal file
722
plugins/ExtendedTools/gpusys.c
Normal 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(§ion, 0, sizeof(PH_SYSINFO_SECTION));
|
||||
PhInitializeStringRef(§ion.Name, L"GPU");
|
||||
section.Flags = 0;
|
||||
section.Callback = EtpGpuSysInfoSectionCallback;
|
||||
|
||||
GpuSection = Pointers->CreateSection(§ion);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
79
plugins/ExtendedTools/gpusys.h
Normal file
79
plugins/ExtendedTools/gpusys.h
Normal 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
|
||||
466
plugins/ExtendedTools/iconext.c
Normal file
466
plugins/ExtendedTools/iconext.c
Normal 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;
|
||||
}
|
||||
616
plugins/ExtendedTools/main.c
Normal file
616
plugins/ExtendedTools/main.c
Normal 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;
|
||||
}
|
||||
173
plugins/ExtendedTools/modsrv.c
Normal file
173
plugins/ExtendedTools/modsrv.c
Normal 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;
|
||||
}
|
||||
312
plugins/ExtendedTools/objprp.c
Normal file
312
plugins/ExtendedTools/objprp.c
Normal 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;
|
||||
}
|
||||
85
plugins/ExtendedTools/options.c
Normal file
85
plugins/ExtendedTools/options.c
Normal 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;
|
||||
}
|
||||
95
plugins/ExtendedTools/procicon.c
Normal file
95
plugins/ExtendedTools/procicon.c
Normal 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);
|
||||
}
|
||||
}
|
||||
113
plugins/ExtendedTools/resource.h
Normal file
113
plugins/ExtendedTools/resource.h
Normal 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
|
||||
64
plugins/ExtendedTools/thrdact.c
Normal file
64
plugins/ExtendedTools/thrdact.c
Normal 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;
|
||||
}
|
||||
783
plugins/ExtendedTools/treeext.c
Normal file
783
plugins/ExtendedTools/treeext.c
Normal 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;
|
||||
}
|
||||
357
plugins/ExtendedTools/unldll.c
Normal file
357
plugins/ExtendedTools/unldll.c
Normal 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;
|
||||
}
|
||||
48
plugins/ExtendedTools/utils.c
Normal file
48
plugins/ExtendedTools/utils.c
Normal 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;
|
||||
}
|
||||
}
|
||||
571
plugins/ExtendedTools/wswatch.c
Normal file
571
plugins/ExtendedTools/wswatch.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user