go my file uploader

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

View File

@@ -0,0 +1,26 @@
1.6
* Fixed .NET assembly tab performance issues
* Added extra .NET memory counters to the .NET performance tab
* Added "Show sizes in bytes" checkbox to the .NET performance tab
* Added right-click menu to the .NET assembly tab
* Removed all Win32 functions for querying .NET process performance
1.5
* Rewrite of .NET Performance statistics and AppDomain enumeration
1.4
* Process Hacker now displays managed stack traces for 32-bit .NET processes on 64-bit Windows
* Fixed inaccurate stack traces when clicking Refresh
* Added AppDomain column for threads in .NET programs
1.3
* Improved .NET assembly enumeration timeout handling
1.2
* Fixed inaccurate stack traces for certain .NET programs
1.1
* Added managed symbol resolution for thread stacks
1.0
* Initial release

View File

@@ -0,0 +1,182 @@
// 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,6,0,0
PRODUCTVERSION 1,6,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", ".NET tools plugin for Process Hacker"
VALUE "FileVersion", "1.6"
VALUE "InternalName", "DotNetTools"
VALUE "LegalCopyright", "Licensed under the GNU GPL, v3."
VALUE "OriginalFilename", "DotNetTools.dll"
VALUE "ProductName", ".NET tools plugin for Process Hacker"
VALUE "ProductVersion", "1.6"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0xc09, 1200
END
END
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_PROCDOTNETPERF DIALOGEX 0, 0, 260, 260
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION ".NET performance"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
CONTROL "",IDC_APPDOMAINS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,246,59
LTEXT "Categories:",IDC_STATIC,7,72,38,8
COMBOBOX IDC_CATEGORIES,49,70,204,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
CONTROL "",IDC_COUNTERS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,88,246,154
CONTROL "Show sizes in bytes",IDC_DOTNET_PERF_SHOWBYTES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,244,78,10
END
IDD_PROCDOTNETASM DIALOGEX 0, 0, 260, 260
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION ".NET assemblies"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
CONTROL ".NET assemblies",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | 0x1a,7,7,246,246,WS_EX_CLIENTEDGE
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_PROCDOTNETPERF, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 253
TOPMARGIN, 7
BOTTOMMARGIN, 253
END
IDD_PROCDOTNETASM, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 253
TOPMARGIN, 7
BOTTOMMARGIN, 253
END
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// AFX_DIALOG_LAYOUT
//
IDD_PROCDOTNETASM AFX_DIALOG_LAYOUT
BEGIN
0
END
IDD_PROCDOTNETPERF AFX_DIALOG_LAYOUT
BEGIN
0
END
/////////////////////////////////////////////////////////////////////////////
//
// Menu
//
IDR_ASSEMBLY_MENU MENU
BEGIN
POPUP "CLR"
BEGIN
MENUITEM "Open &file location", ID_CLR_OPENFILELOCATION
MENUITEM "&Copy\aCtrl+C", ID_CLR_COPY
END
END
#endif // English (Australia) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@@ -0,0 +1,116 @@
<?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>{2B3235B0-31E1-44DA-81A1-183F40517E47}</ProjectGuid>
<RootNamespace>DotNetTools</RootNamespace>
<Keyword>Win32Proj</Keyword>
<ProjectName>DotNetTools</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 Label="UserMacros" />
<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>uxtheme.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Link>
<AdditionalDependencies>uxtheme.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Link>
<AdditionalDependencies>uxtheme.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Link>
<AdditionalDependencies>uxtheme.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="asmpage.c" />
<ClCompile Include="clrsup.c" />
<ClCompile Include="counters.c" />
<ClCompile Include="main.c" />
<ClCompile Include="perfpage.c" />
<ClCompile Include="stackext.c" />
<ClCompile Include="svcext.c" />
<ClCompile Include="treeext.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="clretw.h" />
<ClInclude Include="clrsup.h" />
<ClInclude Include="clr\dbgappdomain.h" />
<ClInclude Include="clr\ipcenums.h" />
<ClInclude Include="clr\ipcheader.h" />
<ClInclude Include="clr\ipcshared.h" />
<ClInclude Include="clr\perfcounterdefs.h" />
<ClInclude Include="dn.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="svcext.h" />
</ItemGroup>
<ItemGroup>
<None Include="CHANGELOG.txt" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="DotNetTools.rc" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

View File

@@ -0,0 +1,86 @@
<?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>
<Filter Include="Header Files\clr">
<UniqueIdentifier>{6b9aae9c-fc27-4d95-b258-53eb88081e1b}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="perfpage.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="counters.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="asmpage.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="clrsup.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="stackext.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="treeext.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="svcext.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="dn.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="clretw.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="clrsup.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="svcext.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="clr\dbgappdomain.h">
<Filter>Header Files\clr</Filter>
</ClInclude>
<ClInclude Include="clr\ipcenums.h">
<Filter>Header Files\clr</Filter>
</ClInclude>
<ClInclude Include="clr\ipcheader.h">
<Filter>Header Files\clr</Filter>
</ClInclude>
<ClInclude Include="clr\ipcshared.h">
<Filter>Header Files\clr</Filter>
</ClInclude>
<ClInclude Include="clr\perfcounterdefs.h">
<Filter>Header Files\clr</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="CHANGELOG.txt" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="DotNetTools.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) .NET Foundation and Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,139 @@
/*
* Process Hacker .NET Tools -
* .NET Process IPC definitions
*
* 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/>.
*/
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the current folder for more information.
//-----------------------------------------------------------------------------
//
// dmex: This header has been highly modified.
// Original: https://github.com/dotnet/coreclr/blob/master/src/debug/inc/dbgappdomain.h
#ifndef _DBG_APPDOMAIN_H_
#define _DBG_APPDOMAIN_H_
#ifndef _WIN64
#include <pshpack4.h>
#endif
typedef struct _AppDomainInfo
{
ULONG Id; // unique identifier
INT NameLengthInBytes;
PWSTR AppDomainName;
PVOID AppDomains;
} AppDomainInfo;
#ifndef _WIN64
#include <poppack.h>
#endif
#include <pshpack4.h>
typedef struct _AppDomainInfo_Wow64
{
ULONG Id; // unique identifier
INT NameLengthInBytes;
ULONG AppDomainName;
ULONG AppDomains;
} AppDomainInfo_Wow64;
#include <poppack.h>
// AppDomain publishing server support:
// Information about all appdomains in the process will be maintained
// in the shared memory block for use by the debugger, etc.
#ifndef _WIN64
#include <pshpack4.h>
#endif
typedef struct _AppDomainEnumerationIPCBlock
{
HANDLE Mutex; // lock for serialization while manipulating AppDomain list.
INT TotalSlots; // Number of slots in AppDomainListElement array
INT NumOfUsedSlots;
INT LastFreedSlot;
INT SizeInBytes; // Size of AppDomainInfo in bytes
INT ProcessNameLengthInBytes; // We can use psapi!GetModuleFileNameEx to get the module name.
PVOID ProcessName; // This provides an alternative.
PVOID ListOfAppDomains;
BOOL LockInvalid;
} AppDomainEnumerationIPCBlock;
#ifndef _WIN64
#include <poppack.h>
#endif
#include <pshpack4.h>
typedef struct _AppDomainEnumerationIPCBlock_Wow64
{
ULONG Mutex; // lock for serialization while manipulating AppDomain list.
INT TotalSlots; // Number of slots in AppDomainListElement array
INT NumOfUsedSlots;
INT LastFreedSlot;
INT SizeInBytes; // Size of AppDomainInfo in bytes
INT ProcessNameLengthInBytes; // We can use psapi!GetModuleFileNameEx to get the module name.
ULONG ProcessName; // This provides an alternative.
ULONG ListOfAppDomains;
BOOL LockInvalid;
} AppDomainEnumerationIPCBlock_Wow64;
#include <poppack.h>
// Enforce the AppDomain IPC block binary layout.
C_ASSERT(FIELD_OFFSET(AppDomainInfo_Wow64, Id) == 0x0);
C_ASSERT(FIELD_OFFSET(AppDomainInfo_Wow64, NameLengthInBytes) == 0x4);
C_ASSERT(FIELD_OFFSET(AppDomainInfo_Wow64, AppDomainName) == 0x8);
C_ASSERT(FIELD_OFFSET(AppDomainInfo_Wow64, AppDomains) == 0xC);
#if defined(_WIN64)
C_ASSERT(FIELD_OFFSET(AppDomainInfo, Id) == 0x0);
C_ASSERT(FIELD_OFFSET(AppDomainInfo, NameLengthInBytes) == 0x4);
C_ASSERT(FIELD_OFFSET(AppDomainInfo, AppDomainName) == 0x8);
C_ASSERT(FIELD_OFFSET(AppDomainInfo, AppDomains) == 0x10);
#endif
// Enforce the AppDomain IPC block binary layout.
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, Mutex) == 0x0);
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, TotalSlots) == 0x4);
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, NumOfUsedSlots) == 0x8);
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, LastFreedSlot) == 0xC);
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, SizeInBytes) == 0x10);
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, ProcessNameLengthInBytes) == 0x14);
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, ProcessName) == 0x18);
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, ListOfAppDomains) == 0x1C);
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, LockInvalid) == 0x20);
#if defined(_WIN64)
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, Mutex) == 0x0);
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, TotalSlots) == 0x8);
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, NumOfUsedSlots) == 0xC);
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, LastFreedSlot) == 0x10);
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, SizeInBytes) == 0x14);
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, ProcessNameLengthInBytes) == 0x18);
// TODO: Why does Visual Studio have issues with these entries...
//C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, ProcessName) == 0x20);
//C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, ListOfAppDomains) == 0x28);
//C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, LockInvalid) == 0x30);
#endif
#endif _DBG_APPDOMAIN_H_

View File

@@ -0,0 +1,77 @@
/*
* Process Hacker .NET Tools -
* .NET Process IPC definitions
*
* 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/>.
*/
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the current folder for more information.
//-----------------------------------------------------------------------------
// IPCEnums.h
//
// Define various enums used by IPCMan.
//-----------------------------------------------------------------------------
//
// dmex: This header has been highly modified.
// Original: https://github.com/dotnet/coreclr/blob/master/src/ipcman/ipcenums.h
#ifndef _IPC_ENUMS_H_
#define _IPC_ENUMS_H_
//-----------------------------------------------------------------------------
// Each IPC client for an IPC block has one entry.
//-----------------------------------------------------------------------------
typedef enum _EIPCClient
{
eIPC_PerfCounters = 0,
// MAX used for arrays, insert above this.
eIPC_MAX
} EIPCClient;
//-----------------------------------------------------------------------------
// Each IPC client for a LegacyPrivate block (debugging, perf counters, etc) has one entry.
//-----------------------------------------------------------------------------
typedef enum _ELegacyPrivateIPCClient
{
eLegacyPrivateIPC_PerfCounters = 0,
eLegacyPrivateIPC_Obsolete_Debugger = 1,
eLegacyPrivateIPC_AppDomain = 2,
eLegacyPrivateIPC_Obsolete_Service = 3,
eLegacyPrivateIPC_Obsolete_ClassDump = 4,
eLegacyPrivateIPC_Obsolete_MiniDump = 5,
eLegacyPrivateIPC_InstancePath = 6,
// MAX used for arrays, insert above this.
eLegacyPrivateIPC_MAX
} ELegacyPrivateIPCClient;
//-----------------------------------------------------------------------------
// Each IPC client for a LegacyPublic block has one entry.
//-----------------------------------------------------------------------------
typedef enum _ELegacyPublicIPCClient
{
eLegacyPublicIPC_PerfCounters = 0,
// MAX used for arrays, insert above this.
eLegacyPublicIPC_MAX
} ELegacyPublicIPCClient;
#endif _IPC_ENUMS_H_

View File

@@ -0,0 +1,545 @@
/*
* Process Hacker .NET Tools -
* .NET Process IPC definitions
*
* 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/>.
*/
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the current folder for more information.
//-----------------------------------------------------------------------------
// IPCHeader.h
//
// Define the LegacyPrivate header format for IPC memory mapped files.
//-----------------------------------------------------------------------------
//
// dmex: This header has been highly modified.
// Original: https://github.com/dotnet/coreclr/blob/master/src/ipcman/ipcheader.h
#ifndef _IPC_HEADER_H_
#define _IPC_HEADER_H_
#include "perfcounterdefs.h"
#include "ipcenums.h"
// Current version of the IPC Block
const USHORT VER_IPC_BLOCK = 4;
// Legacy version of the IPC Block
const USHORT VER_LEGACYPRIVATE_IPC_BLOCK = 2;
const USHORT VER_LEGACYPUBLIC_IPC_BLOCK = 3;
//-----------------------------------------------------------------------------
// Entry in the IPC Directory. Ensure binary compatibility across versions
// if we add (or remove) entries. If we remove an block, the entry should
// be EMPTY_ENTRY_OFFSET
//-----------------------------------------------------------------------------
const ULONG EMPTY_ENTRY_OFFSET = 0xFFFFFFFF;
const ULONG EMPTY_ENTRY_SIZE = 0;
typedef struct IPCEntry
{
ULONG Offset; // offset of the IPC Block from the end of the Full IPC Header
ULONG Size; // size (in bytes) of the block
} IPCEntry;
// Newer versions of the CLR use Flags field
const USHORT IPC_FLAG_USES_FLAGS = 0x1;
const USHORT IPC_FLAG_INITIALIZED = 0x2;
const USHORT IPC_FLAG_X86 = 0x4;
// In hindsight, we should have made the offsets be absolute, but we made them
// relative to the end of the FullIPCHeader.
// The problem is that as future versions added new Entries to the directory,
// the header size grew.
// Thus we make IPCEntry::Offset is relative to IPC_ENTRY_OFFSET_BASE, which
// corresponds to sizeof(PrivateIPCHeader) for an v1.0 /v1.1 build.
const ULONG IPC_ENTRY_OFFSET_BASE_X86 = 0x14;
const ULONG IPC_ENTRY_OFFSET_BASE_X64 = 0x0;
/******************************************************************************
* The CLR opens memory mapped files to expose perfcounter values and other
* information to other processes. Historically there have been three memory
* mapped files: the BlockTable, the LegacyPrivateBlock, and the
* LegacyPublicBlock.
*
* BlockTable - The block table was designed to work with multiple runtimes
* running side by side in the same process (SxS in-proc). We have defined
* semantics using interlocked operations that allow a runtime to allocate
* a block from the block table in a thread-safe manner.
*
* LegacyPrivateBlock - The legacy private block was used by older versions
* of the runtime to expose various information to the debugger. The
* legacy private block is not compatible with in-proc SxS, and thus it
* must be removed in the near future. Currently it is being used to expose
* information about AppDomains to the debugger. We will need to keep the
* code that knows how to read the legacy private block as long as we
* continue to support .NET 3.5 SP1.
*
* LegacyPublicBlock - The legacy public block was used by older versions
* of the runtime to expose perfcounter values. The legacy public block is
* not compatible with in-proc SxS, and thus it has been removed. We will
* need to keep the code that knows how to read the legacy public block as
* long as we continue to support .NET 3.5 SP1.
******************************************************************************/
/**************************************** BLOCK TABLE ****************************************/
#define IPC_BLOCK_TABLE_SIZE 65536
#define IPC_BLOCK_SIZE 2048
#define IPC_NUM_BLOCKS_IN_TABLE 32
C_ASSERT(IPC_BLOCK_TABLE_SIZE == IPC_NUM_BLOCKS_IN_TABLE * IPC_BLOCK_SIZE);
typedef struct _IPCHeader
{
// Chunk header
volatile LONG Counter; // *** Volatile<LONG> *** value of 0 is special; means that this block has never been touched before by a writer
ULONG RuntimeId; // value of 0 is special; means that chunk is currently free (runtime ids are always greater than 0)
ULONG Reserved1;
ULONG Reserved2;
// Standard header
USHORT Version; // version of the IPC Block
USHORT Flags; // flags field
ULONG blockSize; // Size of the entire shared memory block
USHORT BuildYear; // stamp for year built
USHORT BuildNumber; // stamp for Month/Day built
ULONG NumEntries; // Number of entries in the table
// Directory
IPCEntry EntryTable[eIPC_MAX]; // entry describing each client's block
} IPCHeader;
#define SXSPUBLIC_IPC_SIZE_NO_PADDING (sizeof(IPCHeader) + sizeof(PerfCounterIPCControlBlock))
#define SXSPUBLIC_WOW64_IPC_SIZE_NO_PADDING (sizeof(IPCHeader) + sizeof(PerfCounterIPCControlBlock_Wow64))
#define SXSPUBLIC_IPC_PAD_SIZE (IPC_BLOCK_SIZE - SXSPUBLIC_IPC_SIZE_NO_PADDING)
#define SXSPUBLIC_WOW64_IPC_PAD_SIZE (IPC_BLOCK_SIZE - SXSPUBLIC_WOW64_IPC_SIZE_NO_PADDING)
#ifndef _WIN64
#include <pshpack4.h>
#endif
typedef struct _IPCControlBlock
{
// Header
IPCHeader Header;
// Client blocks
PerfCounterIPCControlBlock PerfIpcBlock;
// Padding
BYTE Padding[SXSPUBLIC_IPC_PAD_SIZE];
} IPCControlBlock;
#ifndef _WIN64
#include <poppack.h>
#endif
#include <pshpack4.h>
typedef struct _IPCControlBlock_Wow64
{
// Header
IPCHeader Header;
// Client blocks
PerfCounterIPCControlBlock_Wow64 PerfIpcBlock;
// Padding
BYTE Padding[SXSPUBLIC_WOW64_IPC_PAD_SIZE];
} IPCControlBlock_Wow64;
#include <poppack.h>
C_ASSERT(sizeof(IPCControlBlock) == IPC_BLOCK_SIZE);
C_ASSERT(sizeof(IPCControlBlock_Wow64) == IPC_BLOCK_SIZE);
#ifndef _WIN64
#include <pshpack4.h>
#endif
typedef struct IPCControlBlockTable
{
IPCControlBlock Blocks[IPC_NUM_BLOCKS_IN_TABLE];
} IPCControlBlockTable;
#ifndef _WIN64
#include <poppack.h>
#endif
#include <pshpack4.h>
typedef struct IPCControlBlockTable_Wow64
{
IPCControlBlock_Wow64 Blocks[IPC_NUM_BLOCKS_IN_TABLE];
} IPCControlBlockTable_Wow64;
#include <poppack.h>
C_ASSERT(sizeof(IPCControlBlockTable) == IPC_BLOCK_TABLE_SIZE);
C_ASSERT(sizeof(IPCControlBlockTable_Wow64) == IPC_BLOCK_TABLE_SIZE);
#ifndef _WIN64
#include <pshpack4.h>
#endif
typedef struct LegacyPrivateIPCHeader
{
USHORT Version; // version of the IPC Block
USHORT Flags; // flags field
ULONG BlockSize; // Size of the entire shared memory block
HINSTANCE hInstance; // Instance of module that created this header
USHORT BuildYear; // stamp for year built
USHORT BuildNumber; // stamp for Month/Day built
ULONG NumEntries; // Number of entries in the table
} LegacyPrivateIPCHeader;
#ifndef _WIN64
#include <poppack.h>
#endif
#include <pshpack4.h>
typedef struct LegacyPrivateIPCHeader_Wow64
{
USHORT Version; // version of the IPC Block
USHORT Flags; // flags field
ULONG BlockSize; // Size of the entire shared memory block
ULONG hInstance; // Instance of module that created this header
USHORT BuildYear; // stamp for year built
USHORT BuildNumber; // stamp for Month/Day built
ULONG NumEntries; // Number of entries in the table
} LegacyPrivateIPCHeader_Wow64;
#include <poppack.h>
#ifndef _WIN64
#include <pshpack4.h>
#endif
typedef struct FullIPCHeaderLegacyPrivate
{
// Header
LegacyPrivateIPCHeader Header;
// Directory
IPCEntry EntryTable[eLegacyPrivateIPC_MAX]; // entry describing each client's block
} FullIPCHeaderLegacyPrivate;
#ifndef _WIN64
#include <poppack.h>
#endif
#include <pshpack4.h>
typedef struct FullIPCHeaderLegacyPrivate_Wow64
{
// Header
LegacyPrivateIPCHeader_Wow64 Header;
// Directory
IPCEntry EntryTable[eLegacyPrivateIPC_MAX]; // entry describing each client's block
} FullIPCHeaderLegacyPrivate_Wow64;
#include <poppack.h>
#ifndef _WIN64
#include <pshpack4.h>
#endif
typedef struct FullIPCHeaderLegacyPublic
{
// Header
LegacyPrivateIPCHeader Header;
// Directory
IPCEntry EntryTable[eLegacyPublicIPC_MAX]; // entry describing each client's block
} FullIPCHeaderLegacyPublic;
#ifndef _WIN64
#include <poppack.h>
#endif
#include <pshpack4.h>
typedef struct FullIPCHeaderLegacyPublic_Wow64
{
// Header
LegacyPrivateIPCHeader_Wow64 Header;
// Directory
IPCEntry EntryTable[eLegacyPublicIPC_MAX]; // entry describing each client's block
} FullIPCHeaderLegacyPublic_Wow64;
#include <poppack.h>
//-----------------------------------------------------------------------------
// LegacyPrivate (per process) IPC Block for COM+ apps
//-----------------------------------------------------------------------------
#ifndef _WIN64
#include <pshpack4.h>
#endif
typedef struct _LegacyPrivateIPCControlBlock
{
FullIPCHeaderLegacyPrivate FullIPCHeader;
// Client blocks
PerfCounterIPCControlBlock PerfIpcBlock; // no longer used but kept for compat
AppDomainEnumerationIPCBlock AppDomainBlock;
WCHAR InstancePath[MAX_PATH];
} LegacyPrivateIPCControlBlock;
#ifndef _WIN64
#include <poppack.h>
#endif
#include <pshpack4.h>
typedef struct _LegacyPrivateIPCControlBlock_Wow64
{
FullIPCHeaderLegacyPrivate_Wow64 FullIPCHeader;
// Client blocks
PerfCounterIPCControlBlock_Wow64 PerfIpcBlock; // no longer used but kept for compat
AppDomainEnumerationIPCBlock_Wow64 AppDomainBlock;
WCHAR InstancePath[MAX_PATH];
} LegacyPrivateIPCControlBlock_Wow64;
#include <poppack.h>
//-----------------------------------------------------------------------------
// LegacyPublic (per process) IPC Block for CLR apps
//-----------------------------------------------------------------------------
#ifndef _WIN64
#include <pshpack4.h>
#endif
typedef struct LegacyPublicIPCControlBlock
{
FullIPCHeaderLegacyPublic FullIPCHeaderLegacyPublic;
// Client blocks
PerfCounterIPCControlBlock PerfIpcBlock;
} LegacyPublicIPCControlBlock;
#ifndef _WIN64
#include <poppack.h>
#endif
#include <pshpack4.h>
typedef struct _LegacyPublicIPCControlBlock_Wow64
{
FullIPCHeaderLegacyPublic_Wow64 FullIPCHeaderLegacyPublic;
// Client blocks
PerfCounterIPCControlBlock_Wow64 PerfIpcBlock;
} LegacyPublicIPCControlBlock_Wow64;
#include <poppack.h>
//class IPCHeaderLockHolder
//{
// LONG Counter;
// BOOL HaveLock;
// IPCHeader & Header;
//
// public:
//
// IPCHeaderLockHolder(IPCHeader & header) : HaveLock(FALSE), Header(header) {}
//
// BOOL TryGetLock()
// {
// _ASSERTE(!HaveLock);
// LONG oldCounter = Header.Counter;
// if ((oldCounter & 1) != 0)
// return FALSE;
// Counter = oldCounter + 1;
// if (InterlockedCompareExchange((LONG *)(&(Header.Counter)), Counter, oldCounter) != oldCounter)
// return FALSE;
// HaveLock = TRUE;
//
// return TRUE;
// }
//
// BOOL TryGetLock(ULONG numRetries)
// {
// ULONG dwSwitchCount = 0;
//
// for (;;)
// {
// if (TryGetLock())
// return TRUE;
//
// if (numRetries == 0)
// return FALSE;
//
// --numRetries;
// __SwitchToThread(0, ++dwSwitchCount);
// }
// }
//
// void FreeLock()
// {
// _ASSERTE(HaveLock);
// _ASSERTE(Header.Counter == Counter);
// ++Counter;
// Counter = (Counter == 0) ? 2 : Counter;
// Header.Counter = Counter;
// HaveLock = FALSE;
// }
//
// ~IPCHeaderLockHolder()
// {
// if (HaveLock)
// FreeLock();
// }
//};
//
//class IPCHeaderReadHelper
//{
// IPCHeader CachedHeader;
// IPCHeader * pUnreliableHeader;
// BOOL IsOpen;
//
// public:
//
// IPCHeaderReadHelper() : pUnreliableHeader(NULL), IsOpen(FALSE) {}
//
// BOOL TryOpenHeader(IPCHeader * header)
// {
// _ASSERTE(!IsOpen);
//
// pUnreliableHeader = header;
//
// // Read the counter and the runtime ID from the header
// CachedHeader.Counter = pUnreliableHeader->Counter;
// if ((CachedHeader.Counter & 1) != 0)
// return FALSE;
// CachedHeader.RuntimeId = pUnreliableHeader->RuntimeId;
//
// // If runtime ID is 0, then this block is not allocated by
// // a runtime, and thus there is no further work to do
// if (CachedHeader.RuntimeId == 0)
// {
// IsOpen = TRUE;
// return TRUE;
// }
//
// // Read the rest of the values from the header
// CachedHeader.Reserved1 = pUnreliableHeader->Reserved1;
// CachedHeader.Reserved2 = pUnreliableHeader->Reserved2;
// CachedHeader.Version = pUnreliableHeader->Version;
// CachedHeader.Flags = pUnreliableHeader->Flags;
// CachedHeader.blockSize = pUnreliableHeader->blockSize;
// CachedHeader.BuildYear = pUnreliableHeader->BuildYear;
// CachedHeader.BuildNumber = pUnreliableHeader->BuildNumber;
// CachedHeader.numEntries = pUnreliableHeader->numEntries;
//
// // Verify that the header did not change during the read
// LONG counter = pUnreliableHeader->Counter;
// if (CachedHeader.Counter != counter)
// return FALSE;
//
// // Since we know we got a clean read of numEntries, we
// // should be able to assert this with confidence
// if (CachedHeader.numEntries == 0)
// {
// _ASSERTE(!"numEntries from IPCBlock is zero");
// return FALSE;
// }
// else if (CachedHeader.numEntries > eIPC_MAX)
// {
// _ASSERTE(!"numEntries from IPCBlock is too big");
// return FALSE;
// }
//
// if (CachedHeader.blockSize == 0)
// {
// _ASSERTE(!"blockSize from IPCBlock is zero");
// return FALSE;
// }
// else if (CachedHeader.blockSize > IPC_BLOCK_SIZE)
// {
// _ASSERTE(!"blockSize from IPCBlock is too big");
// return FALSE;
// }
//
// // Copy the table
// for (ULONG i = 0; i < CachedHeader.numEntries; ++i)
// {
// CachedHeader.EntryTable[i].Offset = pUnreliableHeader->EntryTable[i].Offset;
// CachedHeader.EntryTable[i].Size = pUnreliableHeader->EntryTable[i].Size;
// if (i == eIPC_PerfCounters)
// {
// if(!((SIZE_T)CachedHeader.EntryTable[i].Offset < IPC_BLOCK_SIZE) && ((SIZE_T)CachedHeader.EntryTable[i].Offset + CachedHeader.EntryTable[i].Size <= IPC_BLOCK_SIZE))
// {
// _ASSERTE(!"PerfCounter section offset + size is too large");
// return FALSE;
// }
// }
// }
//
// // If eIPC_MAX > numEntries, then mark the left over
// // slots in EntryTable as "empty".
// for (ULONG i = CachedHeader.numEntries; i < eIPC_MAX; ++i)
// {
// CachedHeader.EntryTable[i].Offset = EMPTY_ENTRY_OFFSET;
// CachedHeader.EntryTable[i].Size = EMPTY_ENTRY_SIZE;
// }
//
// // Verify again that the header did not change during the read
// counter = pUnreliableHeader->Counter;
// if (CachedHeader.Counter != counter)
// return FALSE;
//
// IsOpen = TRUE;
// return TRUE;
// }
//
//
// BOOL HeaderHasChanged()
// {
// _ASSERTE(IsOpen);
// LONG counter = pUnreliableHeader->Counter;
// return (CachedHeader.Counter != counter) ? TRUE : FALSE;
// }
//
// BOOL IsSentinal()
// {
// _ASSERTE(IsOpen);
// return (CachedHeader.Counter == 0);
// }
//
//
// BOOL UseWow64Structs()
// {
// _ASSERTE(IsOpen);
//#if !defined(_TARGET_X86_)
// return ((CachedHeader.Flags & IPC_FLAG_X86) != 0) ? TRUE : FALSE;
//#else
// return FALSE;
//#endif
// }
//
// void * GetUnreliableSection(EIPCClient eClient)
// {
// if (!IsOpen)
// {
// _ASSERTE(!"IPCHeaderReadHelper is not open");
// return NULL;
// }
//
// if (eClient < 0 || eClient >= eIPC_MAX)
// {
// _ASSERTE(!"eClient is out of bounds");
// return NULL;
// }
//
// if (CachedHeader.EntryTable[eClient].Offset == EMPTY_ENTRY_OFFSET)
// {
// _ASSERTE(!"Section is empty");
// return NULL;
// }
//
// return (BYTE*)pUnreliableHeader + (SIZE_T)CachedHeader.EntryTable[eClient].Offset;
// }
//};
#endif // _IPC_HEADER_H_

View File

@@ -0,0 +1,57 @@
/*
* Process Hacker .NET Tools -
* .NET Process IPC definitions
*
* 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/>.
*/
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the current folder for more information.
//-----------------------------------------------------------------------------
// IPCShared.h
//
// Shared LegacyPrivate utility functions for IPC operations.
//-----------------------------------------------------------------------------
//
// dmex: This header has been highly modified.
// Original: https://github.com/dotnet/coreclr/blob/master/src/ipcman/ipcshared.h
#ifndef _IPC_SHARED_H_
#define _IPC_SHARED_H_
// This is the name of the file backed session's name on the LS (debuggee)
// Name of the LegacyPrivate (per-process) block. %lu resolved to a PID
#define CorLegacyPrivateIPCBlock L"Cor_Private_IPCBlock_%lu"
#define CorLegacyPrivateIPCBlockTempV4 L"Cor_Private_IPCBlock_v4_%lu"
#define CorLegacyPublicIPCBlock L"Cor_Public_IPCBlock_%lu"
#define CorSxSPublicIPCBlock L"Cor_SxSPublic_IPCBlock_%lu"
#define CorSxSBoundaryDescriptor L"Cor_CLR_IPCBlock_%lu"
#define CorSxSWriterPrivateNamespacePrefix L"Cor_CLR_WRITER"
#define CorSxSReaderPrivateNamespacePrefix L"Cor_CLR_READER"
#define CorSxSVistaPublicIPCBlock L"Cor_SxSPublic_IPCBlock"
#define CorLegacyPrivateIPCBlock_RS L"CLR_PRIVATE_RS_IPCBlock_%lu"
#define CorLegacyPrivateIPCBlock_RSTempV4 L"CLR_PRIVATE_RS_IPCBlock_v4_%lu"
#define CorLegacyPublicIPCBlock_RS L"CLR_PUBLIC_IPCBlock_%lu"
#define CorSxSPublicIPCBlock_RS L"CLR_SXSPUBLIC_IPCBlock_%lu"
#define CorSxSPublicInstanceName L"%s_p%lu_r%lu"
#define CorSxSPublicInstanceNameWhidbey L"%s_p%lu"
#endif _IPC_SHARED_H_

View File

@@ -0,0 +1,333 @@
/*
* Process Hacker .NET Tools -
* .NET Process IPC definitions
*
* 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/>.
*/
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the current folder for more information.
//-----------------------------------------------------------------------------
// PerfCounterDefs.h
//
// Internal Interface for CLR to use Performance counters.
//-----------------------------------------------------------------------------
//
// dmex: This header has been highly modified.
// Original: https://github.com/dotnet/coreclr/blob/master/src/inc/perfcounterdefs.h
#ifndef _PERF_COUNTERS_H_
#define _PERF_COUNTERS_H_
//-----------------------------------------------------------------------------
// Name of global IPC block
#define SHARED_PERF_IPC_NAME "SharedPerfIPCBlock"
//-----------------------------------------------------------------------------
// Attributes for the IPC block
#define PERF_ATTR_ON 0x0001 // Are we even updating any counters?
#define PERF_ATTR_GLOBAL 0x0002 // Is this a global or private block?
//.............................................................................
// Tri Counter. Support for the common trio of counters (Total, Current, and Instantaneous).
typedef struct _TRICOUNT
{
ULONG Current; // Current, has +, -
ULONG Total; // Total, has only +
} TRICOUNT;
//.............................................................................
// Interlocked Tri Counter. Support for the common trio of counters (Total, Current, and Instantaneous).
typedef struct _TRICOUNT_IL
{
ULONG Current; // Current, has +, -
ULONG Total; // Total, has only +
} TRICOUNT_IL;
//.............................................................................
// Dual Counter. Support for the (Total and Instantaneous (rate)). Helpful in cases
// where the current value is always same as the total value. ie. the counter is never
// decremented.
//.............................................................................
typedef struct _DUALCOUNT
{
ULONG Total;
} DUALCOUNT;
//-----------------------------------------------------------------------------
// Format for the Perf Counter IPC Block
// IPC block is broken up into sections. This marks it easier to marshall
// into different perfmon objects
//
//.............................................................................
// Naming convention (by prefix):
// c - Raw count of something.
// cb- count of bytes
// time - time value.
// depth - stack depth
//-----------------------------------------------------------------------------
#define MAX_TRACKED_GENS 3 // number of generations we track
#ifndef _WIN64
#include <pshpack4.h>
#endif
typedef struct _Perf_GC
{
size_t cGenCollections[MAX_TRACKED_GENS]; // count of collects per gen
size_t cbPromotedMem[MAX_TRACKED_GENS - 1]; // count of promoted memory
size_t cbPromotedFinalizationMem; // count of memory promoted due to finalization
size_t cProcessID; // process ID
size_t cGenHeapSize[MAX_TRACKED_GENS]; // size of heaps per gen
size_t cTotalCommittedBytes; // total number of committed bytes.
size_t cTotalReservedBytes; // bytes reserved via VirtualAlloc
size_t cLrgObjSize; // size of Large Object Heap
size_t cSurviveFinalize; // count of instances surviving from finalizing
size_t cHandles; // count of GC handles
size_t cbAlloc; // bytes allocated
size_t cbLargeAlloc; // bytes allocated for Large Objects
size_t cInducedGCs; // number of explicit GCs
ULONG timeInGC; // Time in GC
ULONG timeInGCBase; // must follow time in GC counter
size_t cPinnedObj; // # of Pinned Objects
size_t cSinkBlocks; // # of sink blocks
} Perf_GC;
#ifndef _WIN64
#include <poppack.h>
#endif
// Perf_GC_Wow64 mimics in a 64 bit process, the layout of Perf_GC in a 32 bit process
// It does this by replacing all size_t by ULONG
#include <pshpack4.h>
typedef struct _Perf_GC_Wow64
{
ULONG cGenCollections[MAX_TRACKED_GENS]; // count of collects per gen
ULONG cbPromotedMem[MAX_TRACKED_GENS - 1]; // count of promoted memory
ULONG cbPromotedFinalizationMem; // count of memory promoted due to finalization
ULONG cProcessID; // process ID
ULONG cGenHeapSize[MAX_TRACKED_GENS]; // size of heaps per gen
ULONG cTotalCommittedBytes; // total number of committed bytes.
ULONG cTotalReservedBytes; // bytes reserved via VirtualAlloc
ULONG cLrgObjSize; // size of Large Object Heap
ULONG cSurviveFinalize; // count of instances surviving from finalizing
ULONG cHandles; // count of GC handles
ULONG cbAlloc; // bytes allocated
ULONG cbLargeAlloc; // bytes allocated for Large Objects
ULONG cInducedGCs; // number of explicit GCs
ULONG timeInGC; // Time in GC
ULONG timeInGCBase; // must follow time in GC counter
ULONG cPinnedObj; // # of Pinned Objects
ULONG cSinkBlocks; // # of sink blocks
} Perf_GC_Wow64;
#include <poppack.h>
#ifndef _WIN64
#include <pshpack4.h>
#endif
typedef struct Perf_Loading
{
TRICOUNT cClassesLoaded;
TRICOUNT_IL cAppDomains; // Current # of AppDomains
TRICOUNT cAssemblies; // Current # of Assemblies
UNALIGNED LONGLONG timeLoading; // % time loading
ULONG cAsmSearchLen; // Avg search length for assemblies
DUALCOUNT cLoadFailures; // Classes Failed to load
size_t cbLoaderHeapSize; // Total size of heap used by the loader
DUALCOUNT cAppDomainsUnloaded; // Rate at which app domains are unloaded
} Perf_Loading;
#ifndef _WIN64
#include <poppack.h>
#endif
#include <pshpack4.h>
typedef struct Perf_Loading_Wow64
{
TRICOUNT cClassesLoaded;
TRICOUNT_IL cAppDomains; // Current # of AppDomains
TRICOUNT cAssemblies; // Current # of Assemblies
UNALIGNED LONGLONG timeLoading; // % time loading
ULONG cAsmSearchLen; // Avg search length for assemblies
DUALCOUNT cLoadFailures; // Classes Failed to load
ULONG cbLoaderHeapSize; // Total size of heap used by the loader
DUALCOUNT cAppDomainsUnloaded; // Rate at which app domains are unloaded
} Perf_Loading_Wow64;
#include <poppack.h>
#ifndef _WIN64
#include <pshpack4.h>
#endif
typedef struct Perf_Jit
{
ULONG cMethodsJitted; // number of methods jitted
TRICOUNT cbILJitted; // IL jitted stats
//DUALCOUNT cbPitched; // Total bytes pitched
ULONG cJitFailures; // # of standard Jit failures
ULONG timeInJit; // Time in JIT since last sample
ULONG timeInJitBase; // Time in JIT base counter
} Perf_Jit;
#ifndef _WIN64
#include <poppack.h>
#endif
#ifndef _WIN64
#include <pshpack4.h>
#endif
typedef struct Perf_Excep
{
DUALCOUNT cThrown; // Number of Exceptions thrown
ULONG cFiltersExecuted; // Number of Filters executed
ULONG cFinallysExecuted; // Number of Finallys executed
ULONG cThrowToCatchStackDepth; // Delta from throw to catch site on stack
} Perf_Excep;
#ifndef _WIN64
#include <poppack.h>
#endif
#ifndef _WIN64
#include <pshpack4.h>
#endif
typedef struct Perf_Interop
{
ULONG cCCW; // Number of CCWs
ULONG cStubs; // Number of stubs
ULONG cMarshalling; // # of time marshalling args and return values.
ULONG cTLBImports; // Number of tlbs we import
ULONG cTLBExports; // Number of tlbs we export
} Perf_Interop;
#ifndef _WIN64
#include <poppack.h>
#endif
#ifndef _WIN64
#include <pshpack4.h>
#endif
typedef struct Perf_LocksAndThreads
{
// Locks
DUALCOUNT cContention; // # of times in AwareLock::EnterEpilogue()
TRICOUNT cQueueLength; // Lenght of queue
// Threads
ULONG cCurrentThreadsLogical; // Number (created - destroyed) of logical threads
ULONG cCurrentThreadsPhysical; // Number (created - destroyed) of OS threads
TRICOUNT cRecognizedThreads; // # of Threads execute in runtime's control
} Perf_LocksAndThreads;
#ifndef _WIN64
#include <poppack.h>
#endif
// IMPORTANT!!!!!!!: The first two fields in the struct have to be together
// and be the first two fields in the struct. The managed code in ChannelServices.cs
// depends on this.
#ifndef _WIN64
#include <pshpack4.h>
#endif
typedef struct Perf_Contexts
{
// Contexts & Remoting
DUALCOUNT cRemoteCalls; // # of remote calls
ULONG cChannels; // Number of current channels
ULONG cProxies; // Number of context proxies.
ULONG cClasses; // # of Context-bound classes
ULONG cObjAlloc; // # of context bound objects allocated
ULONG cContexts; // The current number of contexts.
} Perf_Contexts;
#ifndef _WIN64
#include <poppack.h>
#endif
#ifndef _WIN64
#include <pshpack4.h>
#endif
typedef struct Perf_Security
{
ULONG cTotalRTChecks; // Total runtime checks
UNALIGNED LONGLONG timeAuthorize; // % time authenticating
ULONG cLinkChecks; // link time checks
ULONG timeRTchecks; // % time in Runtime checks
ULONG timeRTchecksBase; // % time in Runtime checks base counter
ULONG stackWalkDepth; // depth of stack for security checks
} Perf_Security;
#ifndef _WIN64
#include <poppack.h>
#endif
#include <pshpack4.h>
typedef struct Perf_Security_Wow64
{
ULONG cTotalRTChecks; // Total runtime checks
UNALIGNED LONGLONG timeAuthorize; // % time authenticating
ULONG cLinkChecks; // link time checks
ULONG timeRTchecks; // % time in Runtime checks
ULONG timeRTchecksBase; // % time in Runtime checks base counter
ULONG stackWalkDepth; // depth of stack for security checks
} Perf_Security_Wow64;
#include <poppack.h>
#ifndef _WIN64
#include <pshpack4.h>
#endif
typedef struct _PerfCounterIPCControlBlock
{
// Versioning info
USHORT Bytes; // size of this entire block
USHORT Attributes; // attributes for this block
// Counter Sections
Perf_GC GC;
Perf_Contexts Context;
Perf_Interop Interop;
Perf_Loading Loading;
Perf_Excep Excep;
Perf_LocksAndThreads LocksAndThreads;
Perf_Jit Jit;
Perf_Security Security;
} PerfCounterIPCControlBlock;
#ifndef _WIN64
#include <poppack.h>
#endif
#include <pshpack4.h>
typedef struct _PerfCounterIPCControlBlock_Wow64
{
// Versioning info
USHORT Bytes; // size of this entire block
USHORT Attributes; // attributes for this block
// Counter Sections
Perf_GC_Wow64 GC;
Perf_Contexts Context;
Perf_Interop Interop;
Perf_Loading_Wow64 Loading;
Perf_Excep Excep;
Perf_LocksAndThreads LocksAndThreads;
Perf_Jit Jit;
Perf_Security_Wow64 Security;
} PerfCounterIPCControlBlock_Wow64;
#include <poppack.h>
#endif _PERF_COUNTERS_H_

View File

@@ -0,0 +1,146 @@
/*
* Process Hacker .NET Tools
*
* 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/>.
*/
#ifndef CLRETW_H
#define CLRETW_H
// Keywords
#define CLR_LOADER_KEYWORD 0x8
#define CLR_STARTENUMERATION_KEYWORD 0x40
// Event IDs
#define DCStartComplete_V1 145
#define ModuleDCStart_V1 153
#define AssemblyDCStart_V1 155
#define AppDomainDCStart_V1 157
#define RuntimeInformationDCStart 187
// Opcodes
#define CLR_METHODDC_DCSTARTCOMPLETE_OPCODE 14
#define CLR_MODULEDCSTART_OPCODE 35
// Bit maps
// AppDomainFlags
#define AppDomainFlags_Default 0x1
#define AppDomainFlags_Executable 0x2
#define AppDomainFlags_Shared 0x4
// AssemblyFlags
#define AssemblyFlags_DomainNeutral 0x1
#define AssemblyFlags_Dynamic 0x2
#define AssemblyFlags_Native 0x4
#define AssemblyFlags_Collectible 0x8
// ModuleFlags
#define ModuleFlags_DomainNeutral 0x1
#define ModuleFlags_Native 0x2
#define ModuleFlags_Dynamic 0x4
#define ModuleFlags_Manifest 0x8
// StartupMode
#define StartupMode_ManagedExe 0x1
#define StartupMode_HostedCLR 0x2
#define StartupMode_IjwDll 0x4
#define StartupMode_ComActivated 0x8
#define StartupMode_Other 0x10
// StartupFlags
#define StartupFlags_CONCURRENT_GC 0x1
#define StartupFlags_LOADER_OPTIMIZATION_SINGLE_DOMAIN 0x2
#define StartupFlags_LOADER_OPTIMIZATION_MULTI_DOMAIN 0x4
#define StartupFlags_LOADER_SAFEMODE 0x10
#define StartupFlags_LOADER_SETPREFERENCE 0x100
#define StartupFlags_SERVER_GC 0x1000
#define StartupFlags_HOARD_GC_VM 0x2000
#define StartupFlags_SINGLE_VERSION_HOSTING_INTERFACE 0x4000
#define StartupFlags_LEGACY_IMPERSONATION 0x10000
#define StartupFlags_DISABLE_COMMITTHREADSTACK 0x20000
#define StartupFlags_ALWAYSFLOW_IMPERSONATION 0x40000
#define StartupFlags_TRIM_GC_COMMIT 0x80000
#define StartupFlags_ETW 0x100000
#define StartupFlags_SERVER_BUILD 0x200000
#define StartupFlags_ARM 0x400000
// Templates
#include <pshpack1.h>
typedef struct _DCStartEnd
{
USHORT ClrInstanceID;
} DCStartEnd, *PDCStartEnd;
typedef struct _ModuleLoadUnloadRundown_V1
{
ULONG64 ModuleID;
ULONG64 AssemblyID;
ULONG ModuleFlags; // ModuleFlags
ULONG Reserved1;
WCHAR ModuleILPath[1];
// WCHAR ModuleNativePath[1];
// USHORT ClrInstanceID;
} ModuleLoadUnloadRundown_V1, *PModuleLoadUnloadRundown_V1;
typedef struct _AssemblyLoadUnloadRundown_V1
{
ULONG64 AssemblyID;
ULONG64 AppDomainID;
ULONG64 BindingID;
ULONG AssemblyFlags; // AssemblyFlags
WCHAR FullyQualifiedAssemblyName[1];
// USHORT ClrInstanceID;
} AssemblyLoadUnloadRundown_V1, *PAssemblyLoadUnloadRundown_V1;
typedef struct _AppDomainLoadUnloadRundown_V1
{
ULONG64 AppDomainID;
ULONG AppDomainFlags; // AppDomainFlags
WCHAR AppDomainName[1];
// ULONG AppDomainIndex;
// USHORT ClrInstanceID;
} AppDomainLoadUnloadRundown_V1, *PAppDomainLoadUnloadRundown_V1;
typedef struct _RuntimeInformationRundown
{
USHORT ClrInstanceID;
USHORT Sku;
USHORT BclMajorVersion;
USHORT BclMinorVersion;
USHORT BclBuildNumber;
USHORT BclQfeNumber;
USHORT VMMajorVersion;
USHORT VMMinorVersion;
USHORT VMBuildNumber;
USHORT VMQfeNumber;
ULONG StartupFlags; // StartupFlags
UCHAR StartupMode; // StartupMode
WCHAR CommandLine[1];
// GUID ComObjectGuid;
// WCHAR RuntimeDllPath[1];
} RuntimeInformationRundown, *PRuntimeInformationRundown;
#include <poppack.h>
#endif

View File

@@ -0,0 +1,575 @@
/*
* Process Hacker .NET Tools -
* CLR data access functions
*
* 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 "dn.h"
#include "clrsup.h"
static GUID IID_ICLRDataTarget_I = { 0x3e11ccee, 0xd08b, 0x43e5, { 0xaf, 0x01, 0x32, 0x71, 0x7a, 0x64, 0xda, 0x03 } };
static GUID IID_IXCLRDataProcess = { 0x5c552ab6, 0xfc09, 0x4cb3, { 0x8e, 0x36, 0x22, 0xfa, 0x03, 0xc7, 0x98, 0xb7 } };
static ICLRDataTargetVtbl DnCLRDataTarget_VTable =
{
DnCLRDataTarget_QueryInterface,
DnCLRDataTarget_AddRef,
DnCLRDataTarget_Release,
DnCLRDataTarget_GetMachineType,
DnCLRDataTarget_GetPointerSize,
DnCLRDataTarget_GetImageBase,
DnCLRDataTarget_ReadVirtual,
DnCLRDataTarget_WriteVirtual,
DnCLRDataTarget_GetTLSValue,
DnCLRDataTarget_SetTLSValue,
DnCLRDataTarget_GetCurrentThreadID,
DnCLRDataTarget_GetThreadContext,
DnCLRDataTarget_SetThreadContext,
DnCLRDataTarget_Request
};
PCLR_PROCESS_SUPPORT CreateClrProcessSupport(
_In_ HANDLE ProcessId
)
{
PCLR_PROCESS_SUPPORT support;
ICLRDataTarget *dataTarget;
IXCLRDataProcess *dataProcess;
dataTarget = DnCLRDataTarget_Create(ProcessId);
if (!dataTarget)
return NULL;
dataProcess = NULL;
CreateXCLRDataProcess(ProcessId, dataTarget, &dataProcess);
ICLRDataTarget_Release(dataTarget);
if (!dataProcess)
return NULL;
support = PhAllocate(sizeof(CLR_PROCESS_SUPPORT));
support->DataProcess = dataProcess;
return support;
}
VOID FreeClrProcessSupport(
_In_ PCLR_PROCESS_SUPPORT Support
)
{
IXCLRDataProcess_Release(Support->DataProcess);
PhFree(Support);
}
PPH_STRING GetRuntimeNameByAddressClrProcess(
_In_ PCLR_PROCESS_SUPPORT Support,
_In_ ULONG64 Address,
_Out_opt_ PULONG64 Displacement
)
{
PPH_STRING buffer;
ULONG bufferLength;
ULONG returnLength;
ULONG64 displacement;
bufferLength = 33;
buffer = PhCreateStringEx(NULL, (bufferLength - 1) * 2);
returnLength = 0;
if (!SUCCEEDED(IXCLRDataProcess_GetRuntimeNameByAddress(
Support->DataProcess,
Address,
0,
bufferLength,
&returnLength,
buffer->Buffer,
&displacement
)))
{
PhDereferenceObject(buffer);
return NULL;
}
// Try again if our buffer was too small.
if (returnLength > bufferLength)
{
PhDereferenceObject(buffer);
bufferLength = returnLength;
buffer = PhCreateStringEx(NULL, (bufferLength - 1) * 2);
if (!SUCCEEDED(IXCLRDataProcess_GetRuntimeNameByAddress(
Support->DataProcess,
Address,
0,
bufferLength,
&returnLength,
buffer->Buffer,
&displacement
)))
{
PhDereferenceObject(buffer);
return NULL;
}
}
if (Displacement)
*Displacement = displacement;
buffer->Length = (returnLength - 1) * 2;
return buffer;
}
PPH_STRING GetNameXClrDataAppDomain(
_In_ PVOID AppDomain
)
{
IXCLRDataAppDomain *appDomain;
PPH_STRING buffer;
ULONG bufferLength;
ULONG returnLength;
appDomain = AppDomain;
bufferLength = 33;
buffer = PhCreateStringEx(NULL, (bufferLength - 1) * 2);
returnLength = 0;
if (!SUCCEEDED(IXCLRDataAppDomain_GetName(appDomain, bufferLength, &returnLength, buffer->Buffer)))
{
PhDereferenceObject(buffer);
return NULL;
}
// Try again if our buffer was too small.
if (returnLength > bufferLength)
{
PhDereferenceObject(buffer);
bufferLength = returnLength;
buffer = PhCreateStringEx(NULL, (bufferLength - 1) * 2);
if (!SUCCEEDED(IXCLRDataAppDomain_GetName(appDomain, bufferLength, &returnLength, buffer->Buffer)))
{
PhDereferenceObject(buffer);
return NULL;
}
}
buffer->Length = (returnLength - 1) * 2;
return buffer;
}
PVOID LoadMscordacwks(
_In_ BOOLEAN IsClrV4
)
{
PVOID dllBase;
PH_STRINGREF systemRootString;
PH_STRINGREF mscordacwksPathString;
PPH_STRING mscordacwksFileName;
LoadLibrary(L"mscoree.dll");
PhGetSystemRoot(&systemRootString);
if (IsClrV4)
{
#ifdef _WIN64
PhInitializeStringRef(&mscordacwksPathString, L"\\Microsoft.NET\\Framework64\\v4.0.30319\\mscordacwks.dll");
#else
PhInitializeStringRef(&mscordacwksPathString, L"\\Microsoft.NET\\Framework\\v4.0.30319\\mscordacwks.dll");
#endif
}
else
{
#ifdef _WIN64
PhInitializeStringRef(&mscordacwksPathString, L"\\Microsoft.NET\\Framework64\\v2.0.50727\\mscordacwks.dll");
#else
PhInitializeStringRef(&mscordacwksPathString, L"\\Microsoft.NET\\Framework\\v2.0.50727\\mscordacwks.dll");
#endif
}
mscordacwksFileName = PhConcatStringRef2(&systemRootString, &mscordacwksPathString);
dllBase = LoadLibrary(mscordacwksFileName->Buffer);
PhDereferenceObject(mscordacwksFileName);
return dllBase;
}
HRESULT CreateXCLRDataProcess(
_In_ HANDLE ProcessId,
_In_ ICLRDataTarget *Target,
_Out_ struct IXCLRDataProcess **DataProcess
)
{
ULONG flags;
BOOLEAN clrV4;
HMODULE dllBase;
HRESULT (__stdcall *clrDataCreateInstance)(REFIID, ICLRDataTarget *, void **);
clrV4 = FALSE;
if (NT_SUCCESS(PhGetProcessIsDotNetEx(ProcessId, NULL, 0, NULL, &flags)))
{
if (flags & PH_CLR_VERSION_4_ABOVE)
clrV4 = TRUE;
}
// Load the correct version of mscordacwks.dll.
if (clrV4)
{
static PH_INITONCE initOnce = PH_INITONCE_INIT;
static HMODULE mscordacwksDllBase;
if (PhBeginInitOnce(&initOnce))
{
mscordacwksDllBase = LoadMscordacwks(TRUE);
PhEndInitOnce(&initOnce);
}
dllBase = mscordacwksDllBase;
}
else
{
static PH_INITONCE initOnce = PH_INITONCE_INIT;
static HMODULE mscordacwksDllBase;
if (PhBeginInitOnce(&initOnce))
{
mscordacwksDllBase = LoadMscordacwks(FALSE);
PhEndInitOnce(&initOnce);
}
dllBase = mscordacwksDllBase;
}
if (!dllBase)
return E_FAIL;
clrDataCreateInstance = PhGetProcedureAddress(dllBase, "CLRDataCreateInstance", 0);
if (!clrDataCreateInstance)
return E_FAIL;
return clrDataCreateInstance(&IID_IXCLRDataProcess, Target, DataProcess);
}
ICLRDataTarget *DnCLRDataTarget_Create(
_In_ HANDLE ProcessId
)
{
DnCLRDataTarget *dataTarget;
HANDLE processHandle;
BOOLEAN isWow64;
if (!NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessId)))
return NULL;
#ifdef _WIN64
if (!NT_SUCCESS(PhGetProcessIsWow64(processHandle, &isWow64)))
{
NtClose(processHandle);
return NULL;
}
#else
isWow64 = FALSE;
#endif
dataTarget = PhAllocate(sizeof(DnCLRDataTarget));
dataTarget->VTable = &DnCLRDataTarget_VTable;
dataTarget->RefCount = 1;
dataTarget->ProcessId = ProcessId;
dataTarget->ProcessHandle = processHandle;
dataTarget->IsWow64 = isWow64;
return (ICLRDataTarget *)dataTarget;
}
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_QueryInterface(
_In_ ICLRDataTarget *This,
_In_ REFIID Riid,
_Out_ PVOID *Object
)
{
if (
IsEqualIID(Riid, &IID_IUnknown) ||
IsEqualIID(Riid, &IID_ICLRDataTarget_I)
)
{
DnCLRDataTarget_AddRef(This);
*Object = This;
return S_OK;
}
*Object = NULL;
return E_NOINTERFACE;
}
ULONG STDMETHODCALLTYPE DnCLRDataTarget_AddRef(
_In_ ICLRDataTarget *This
)
{
DnCLRDataTarget *this = (DnCLRDataTarget *)This;
this->RefCount++;
return this->RefCount;
}
ULONG STDMETHODCALLTYPE DnCLRDataTarget_Release(
_In_ ICLRDataTarget *This
)
{
DnCLRDataTarget *this = (DnCLRDataTarget *)This;
this->RefCount--;
if (this->RefCount == 0)
{
NtClose(this->ProcessHandle);
PhFree(this);
return 0;
}
return this->RefCount;
}
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetMachineType(
_In_ ICLRDataTarget *This,
_Out_ ULONG32 *machineType
)
{
DnCLRDataTarget *this = (DnCLRDataTarget *)This;
#ifdef _WIN64
if (!this->IsWow64)
*machineType = IMAGE_FILE_MACHINE_AMD64;
else
*machineType = IMAGE_FILE_MACHINE_I386;
#else
*machineType = IMAGE_FILE_MACHINE_I386;
#endif
return S_OK;
}
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetPointerSize(
_In_ ICLRDataTarget *This,
_Out_ ULONG32 *pointerSize
)
{
DnCLRDataTarget *this = (DnCLRDataTarget *)This;
#ifdef _WIN64
if (!this->IsWow64)
#endif
*pointerSize = sizeof(PVOID);
#ifdef _WIN64
else
*pointerSize = sizeof(ULONG);
#endif
return S_OK;
}
BOOLEAN NTAPI PhpGetImageBaseCallback(
_In_ PLDR_DATA_TABLE_ENTRY Module,
_In_opt_ PVOID Context
)
{
PPHP_GET_IMAGE_BASE_CONTEXT context = Context;
if (RtlEqualUnicodeString(&Module->FullDllName, &context->ImagePath, TRUE) ||
RtlEqualUnicodeString(&Module->BaseDllName, &context->ImagePath, TRUE))
{
context->BaseAddress = Module->DllBase;
return FALSE;
}
return TRUE;
}
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetImageBase(
_In_ ICLRDataTarget *This,
_In_ LPCWSTR imagePath,
_Out_ CLRDATA_ADDRESS *baseAddress
)
{
DnCLRDataTarget *this = (DnCLRDataTarget *)This;
PHP_GET_IMAGE_BASE_CONTEXT context;
RtlInitUnicodeString(&context.ImagePath, (PWSTR)imagePath);
context.BaseAddress = NULL;
PhEnumProcessModules(this->ProcessHandle, PhpGetImageBaseCallback, &context);
#ifdef _WIN64
if (this->IsWow64)
PhEnumProcessModules32(this->ProcessHandle, PhpGetImageBaseCallback, &context);
#endif
if (context.BaseAddress)
{
*baseAddress = (CLRDATA_ADDRESS)context.BaseAddress;
return S_OK;
}
else
{
return E_FAIL;
}
}
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_ReadVirtual(
_In_ ICLRDataTarget *This,
_In_ CLRDATA_ADDRESS address,
_Out_ BYTE *buffer,
_In_ ULONG32 bytesRequested,
_Out_ ULONG32 *bytesRead
)
{
DnCLRDataTarget *this = (DnCLRDataTarget *)This;
NTSTATUS status;
SIZE_T numberOfBytesRead;
if (NT_SUCCESS(status = NtReadVirtualMemory(
this->ProcessHandle,
(PVOID)address,
buffer,
bytesRequested,
&numberOfBytesRead
)))
{
*bytesRead = (ULONG32)numberOfBytesRead;
return S_OK;
}
else
{
ULONG result;
result = RtlNtStatusToDosError(status);
return HRESULT_FROM_WIN32(result);
}
}
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_WriteVirtual(
_In_ ICLRDataTarget *This,
_In_ CLRDATA_ADDRESS address,
_In_ BYTE *buffer,
_In_ ULONG32 bytesRequested,
_Out_ ULONG32 *bytesWritten
)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetTLSValue(
_In_ ICLRDataTarget *This,
_In_ ULONG32 threadID,
_In_ ULONG32 index,
_Out_ CLRDATA_ADDRESS *value
)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_SetTLSValue(
_In_ ICLRDataTarget *This,
_In_ ULONG32 threadID,
_In_ ULONG32 index,
_In_ CLRDATA_ADDRESS value
)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetCurrentThreadID(
_In_ ICLRDataTarget *This,
_Out_ ULONG32 *threadID
)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetThreadContext(
_In_ ICLRDataTarget *This,
_In_ ULONG32 threadID,
_In_ ULONG32 contextFlags,
_In_ ULONG32 contextSize,
_Out_ BYTE *context
)
{
NTSTATUS status;
HANDLE threadHandle;
CONTEXT buffer;
if (contextSize < sizeof(CONTEXT))
return E_INVALIDARG;
memset(&buffer, 0, sizeof(CONTEXT));
buffer.ContextFlags = contextFlags;
if (NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_GET_CONTEXT, UlongToHandle(threadID))))
{
status = NtGetContextThread(threadHandle, &buffer);
NtClose(threadHandle);
}
if (NT_SUCCESS(status))
{
memcpy(context, &buffer, sizeof(CONTEXT));
return S_OK;
}
else
{
return HRESULT_FROM_WIN32(RtlNtStatusToDosError(status));
}
}
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_SetThreadContext(
_In_ ICLRDataTarget *This,
_In_ ULONG32 threadID,
_In_ ULONG32 contextSize,
_In_ BYTE *context
)
{
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_Request(
_In_ ICLRDataTarget *This,
_In_ ULONG32 reqCode,
_In_ ULONG32 inBufferSize,
_In_ BYTE *inBuffer,
_In_ ULONG32 outBufferSize,
_Out_ BYTE *outBuffer
)
{
return E_NOTIMPL;
}

View File

@@ -0,0 +1,645 @@
/*
* Process Hacker .NET Tools -
* CLR data access functions
*
* 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/>.
*/
#ifndef CLRSUP_H
#define CLRSUP_H
#define CINTERFACE
#define COBJMACROS
#include <clrdata.h>
#undef CINTERFACE
#undef COBJMACROS
// General interfaces
typedef struct _CLR_PROCESS_SUPPORT
{
struct IXCLRDataProcess *DataProcess;
} CLR_PROCESS_SUPPORT, *PCLR_PROCESS_SUPPORT;
PCLR_PROCESS_SUPPORT CreateClrProcessSupport(
_In_ HANDLE ProcessId
);
VOID FreeClrProcessSupport(
_In_ PCLR_PROCESS_SUPPORT Support
);
PPH_STRING GetRuntimeNameByAddressClrProcess(
_In_ PCLR_PROCESS_SUPPORT Support,
_In_ ULONG64 Address,
_Out_opt_ PULONG64 Displacement
);
PPH_STRING GetNameXClrDataAppDomain(
_In_ PVOID AppDomain
);
PVOID LoadMscordacwks(
_In_ BOOLEAN IsClrV4
);
HRESULT CreateXCLRDataProcess(
_In_ HANDLE ProcessId,
_In_ ICLRDataTarget *Target,
_Out_ struct IXCLRDataProcess **DataProcess
);
// xclrdata
typedef ULONG64 CLRDATA_ENUM;
typedef struct IXCLRDataProcess IXCLRDataProcess;
typedef struct IXCLRDataAppDomain IXCLRDataAppDomain;
typedef struct IXCLRDataTask IXCLRDataTask;
typedef struct IXCLRDataStackWalk IXCLRDataStackWalk;
typedef struct IXCLRDataFrame IXCLRDataFrame;
typedef struct IXCLRDataProcessVtbl
{
HRESULT (STDMETHODCALLTYPE *QueryInterface)(
_In_ IXCLRDataProcess *This,
_In_ REFIID riid,
_Outptr_ void **ppvObject
);
ULONG (STDMETHODCALLTYPE *AddRef)(
_In_ IXCLRDataProcess *This
);
ULONG (STDMETHODCALLTYPE *Release)(
_In_ IXCLRDataProcess *This
);
HRESULT (STDMETHODCALLTYPE *Flush)(
_In_ IXCLRDataProcess *This
);
HRESULT (STDMETHODCALLTYPE *StartEnumTasks)(
_In_ IXCLRDataProcess *This,
_Out_ CLRDATA_ENUM *handle
);
HRESULT (STDMETHODCALLTYPE *EnumTask)(
_In_ IXCLRDataProcess *This,
_Inout_ CLRDATA_ENUM *handle,
_Out_ IXCLRDataTask **task
);
HRESULT (STDMETHODCALLTYPE *EndEnumTasks)(
_In_ IXCLRDataProcess *This,
_In_ CLRDATA_ENUM handle
);
HRESULT (STDMETHODCALLTYPE *GetTaskByOSThreadID)(
_In_ IXCLRDataProcess *This,
_In_ ULONG32 osThreadID,
_Out_ IXCLRDataTask **task
);
PVOID GetTaskByUniqueID;
PVOID GetFlags;
PVOID IsSameObject;
PVOID GetManagedObject;
PVOID GetDesiredExecutionState;
PVOID SetDesiredExecutionState;
PVOID GetAddressType;
HRESULT (STDMETHODCALLTYPE *GetRuntimeNameByAddress)(
_In_ IXCLRDataProcess *This,
_In_ CLRDATA_ADDRESS address,
_In_ ULONG32 flags,
_In_ ULONG32 bufLen,
_Out_ ULONG32 *nameLen,
_Out_ WCHAR *nameBuf,
_Out_ CLRDATA_ADDRESS *displacement
);
// ...
} IXCLRDataProcessVtbl;
typedef struct IXCLRDataProcess
{
struct IXCLRDataProcessVtbl *lpVtbl;
} IXCLRDataProcess;
#define IXCLRDataProcess_QueryInterface(This, riid, ppvObject) \
((This)->lpVtbl->QueryInterface(This, riid, ppvObject))
#define IXCLRDataProcess_AddRef(This) \
((This)->lpVtbl->AddRef(This))
#define IXCLRDataProcess_Release(This) \
((This)->lpVtbl->Release(This))
#define IXCLRDataProcess_GetRuntimeNameByAddress(This, address, flags, bufLen, nameLen, nameBuf, displacement) \
((This)->lpVtbl->GetRuntimeNameByAddress(This, address, flags, bufLen, nameLen, nameBuf, displacement))
#define IXCLRDataProcess_Flush(This) \
((This)->lpVtbl->Flush(This))
#define IXCLRDataProcess_StartEnumTasks(This, handle) \
((This)->lpVtbl->StartEnumTasks(This, handle))
#define IXCLRDataProcess_EnumTask(This, handle, task) \
((This)->lpVtbl->EnumTask(This, handle, task))
#define IXCLRDataProcess_EndEnumTasks(This, handle) \
((This)->lpVtbl->EndEnumTasks(This, handle))
#define IXCLRDataProcess_GetTaskByOSThreadID(This, osThreadID, task) \
((This)->lpVtbl->GetTaskByOSThreadID(This, osThreadID, task))
typedef struct IXCLRDataAppDomainVtbl
{
HRESULT (STDMETHODCALLTYPE *QueryInterface)(
_In_ IXCLRDataAppDomain *This,
_In_ REFIID riid,
_Outptr_ void **ppvObject
);
ULONG (STDMETHODCALLTYPE *AddRef)(
_In_ IXCLRDataAppDomain *This
);
ULONG (STDMETHODCALLTYPE *Release)(
_In_ IXCLRDataAppDomain *This
);
HRESULT (STDMETHODCALLTYPE *GetProcess)(
_In_ IXCLRDataAppDomain *This,
_Out_ IXCLRDataProcess **process
);
HRESULT (STDMETHODCALLTYPE *GetName)(
_In_ IXCLRDataAppDomain *This,
_In_ ULONG32 bufLen,
_Out_ ULONG32 *nameLen,
_Out_ WCHAR *name
);
HRESULT (STDMETHODCALLTYPE *GetUniqueID)(
_In_ IXCLRDataAppDomain *This,
_Out_ ULONG64 *id
);
// ...
} IXCLRDataAppDomainVtbl;
typedef struct IXCLRDataAppDomain
{
struct IXCLRDataAppDomainVtbl *lpVtbl;
} IXCLRDataAppDomain;
#define IXCLRDataAppDomain_QueryInterface(This, riid, ppvObject) \
((This)->lpVtbl->QueryInterface(This, riid, ppvObject))
#define IXCLRDataAppDomain_AddRef(This) \
((This)->lpVtbl->AddRef(This))
#define IXCLRDataAppDomain_Release(This) \
((This)->lpVtbl->Release(This))
#define IXCLRDataAppDomain_GetProcess(This, process) \
((This)->lpVtbl->GetProcess(This, process))
#define IXCLRDataAppDomain_GetName(This, bufLen, nameLen, name) \
((This)->lpVtbl->GetName(This, bufLen, nameLen, name))
#define IXCLRDataAppDomain_GetUniqueID(This, id) \
((This)->lpVtbl->GetUniqueID(This, id))
typedef struct IXCLRDataTaskVtbl
{
HRESULT (STDMETHODCALLTYPE *QueryInterface)(
_In_ IXCLRDataTask *This,
_In_ REFIID riid,
_Outptr_ void **ppvObject
);
ULONG (STDMETHODCALLTYPE *AddRef)(
_In_ IXCLRDataTask *This
);
ULONG (STDMETHODCALLTYPE *Release)(
_In_ IXCLRDataTask *This
);
HRESULT (STDMETHODCALLTYPE *GetProcess)(
_In_ IXCLRDataTask *This,
_Out_ IXCLRDataProcess **process
);
HRESULT (STDMETHODCALLTYPE *GetCurrentAppDomain)(
_In_ IXCLRDataTask *This,
_Out_ IXCLRDataAppDomain **appDomain
);
HRESULT (STDMETHODCALLTYPE *GetUniqueID)(
_In_ IXCLRDataTask *This,
_Out_ ULONG64 *id
);
HRESULT (STDMETHODCALLTYPE *GetFlags)(
_In_ IXCLRDataTask *This,
_Out_ ULONG32 *flags
);
PVOID IsSameObject;
PVOID GetManagedObject;
PVOID GetDesiredExecutionState;
PVOID SetDesiredExecutionState;
HRESULT (STDMETHODCALLTYPE *CreateStackWalk)(
_In_ IXCLRDataTask *This,
_In_ ULONG32 flags,
_Out_ IXCLRDataStackWalk **stackWalk
);
HRESULT (STDMETHODCALLTYPE *GetOSThreadID)(
_In_ IXCLRDataTask *This,
_Out_ ULONG32 *id
);
PVOID GetContext;
PVOID SetContext;
PVOID GetCurrentExceptionState;
PVOID Request;
HRESULT (STDMETHODCALLTYPE *GetName)(
_In_ IXCLRDataTask *This,
_In_ ULONG32 bufLen,
_Out_ ULONG32 *nameLen,
_Out_ WCHAR *name
);
PVOID GetLastExceptionState;
} IXCLRDataTaskVtbl;
typedef struct IXCLRDataTask
{
struct IXCLRDataTaskVtbl *lpVtbl;
} IXCLRDataTask;
#define IXCLRDataTask_QueryInterface(This, riid, ppvObject) \
((This)->lpVtbl->QueryInterface(This, riid, ppvObject))
#define IXCLRDataTask_AddRef(This) \
((This)->lpVtbl->AddRef(This))
#define IXCLRDataTask_Release(This) \
((This)->lpVtbl->Release(This))
#define IXCLRDataTask_GetProcess(This, process) \
((This)->lpVtbl->GetProcess(This, process))
#define IXCLRDataTask_GetCurrentAppDomain(This, appDomain) \
((This)->lpVtbl->GetCurrentAppDomain(This, appDomain))
#define IXCLRDataTask_GetUniqueID(This, id) \
((This)->lpVtbl->GetUniqueID(This, id))
#define IXCLRDataTask_GetFlags(This, flags) \
((This)->lpVtbl->GetFlags(This, flags))
#define IXCLRDataTask_CreateStackWalk(This, flags, stackWalk) \
((This)->lpVtbl->CreateStackWalk(This, flags, stackWalk))
#define IXCLRDataTask_GetOSThreadID(This, id) \
((This)->lpVtbl->GetOSThreadID(This, id))
#define IXCLRDataTask_GetName(This, bufLen, nameLen, name) \
((This)->lpVtbl->GetName(This, bufLen, nameLen, name))
typedef enum
{
CLRDATA_SIMPFRAME_UNRECOGNIZED = 0x1,
CLRDATA_SIMPFRAME_MANAGED_METHOD = 0x2,
CLRDATA_SIMPFRAME_RUNTIME_MANAGED_CODE = 0x4,
CLRDATA_SIMPFRAME_RUNTIME_UNMANAGED_CODE = 0x8
} CLRDataSimpleFrameType;
typedef enum
{
CLRDATA_DETFRAME_UNRECOGNIZED,
CLRDATA_DETFRAME_UNKNOWN_STUB,
CLRDATA_DETFRAME_CLASS_INIT,
CLRDATA_DETFRAME_EXCEPTION_FILTER,
CLRDATA_DETFRAME_SECURITY,
CLRDATA_DETFRAME_CONTEXT_POLICY,
CLRDATA_DETFRAME_INTERCEPTION,
CLRDATA_DETFRAME_PROCESS_START,
CLRDATA_DETFRAME_THREAD_START,
CLRDATA_DETFRAME_TRANSITION_TO_MANAGED,
CLRDATA_DETFRAME_TRANSITION_TO_UNMANAGED,
CLRDATA_DETFRAME_COM_INTEROP_STUB,
CLRDATA_DETFRAME_DEBUGGER_EVAL,
CLRDATA_DETFRAME_CONTEXT_SWITCH,
CLRDATA_DETFRAME_FUNC_EVAL,
CLRDATA_DETFRAME_FINALLY
} CLRDataDetailedFrameType;
typedef enum
{
CLRDATA_STACK_SET_UNWIND_CONTEXT = 0x00000000,
CLRDATA_STACK_SET_CURRENT_CONTEXT = 0x00000001
} CLRDataStackSetContextFlag;
typedef struct IXCLRDataStackWalkVtbl
{
HRESULT (STDMETHODCALLTYPE *QueryInterface)(
_In_ IXCLRDataStackWalk *This,
_In_ REFIID riid,
_Outptr_ void **ppvObject
);
ULONG (STDMETHODCALLTYPE *AddRef)(
_In_ IXCLRDataStackWalk *This
);
ULONG (STDMETHODCALLTYPE *Release)(
_In_ IXCLRDataStackWalk *This
);
HRESULT (STDMETHODCALLTYPE *GetContext)(
_In_ IXCLRDataStackWalk *This,
_In_ ULONG32 contextFlags,
_In_ ULONG32 contextBufSize,
_Out_ ULONG32 *contextSize,
_Out_ BYTE *contextBuf
);
PVOID SetContext;
HRESULT (STDMETHODCALLTYPE *Next)(
_In_ IXCLRDataStackWalk *This
);
HRESULT (STDMETHODCALLTYPE *GetStackSizeSkipped)(
_In_ IXCLRDataStackWalk *This,
_Out_ ULONG64 *stackSizeSkipped
);
HRESULT (STDMETHODCALLTYPE *GetFrameType)(
_In_ IXCLRDataStackWalk *This,
_Out_ CLRDataSimpleFrameType *simpleType,
_Out_ CLRDataDetailedFrameType *detailedType
);
HRESULT (STDMETHODCALLTYPE *GetFrame)(
_In_ IXCLRDataStackWalk *This,
_Out_ PVOID *frame
);
HRESULT (STDMETHODCALLTYPE *Request)(
_In_ IXCLRDataStackWalk *This,
_In_ ULONG32 reqCode,
_In_ ULONG32 inBufferSize,
_In_ BYTE *inBuffer,
_In_ ULONG32 outBufferSize,
_Out_ BYTE *outBuffer
);
HRESULT (STDMETHODCALLTYPE *SetContext2)(
_In_ IXCLRDataStackWalk *This,
_In_ ULONG32 flags,
_In_ ULONG32 contextSize,
_In_ BYTE *context
);
} IXCLRDataStackWalkVtbl;
typedef struct IXCLRDataStackWalk
{
struct IXCLRDataStackWalkVtbl *lpVtbl;
} IXCLRDataStackWalk;
#define IXCLRDataStackWalk_QueryInterface(This, riid, ppvObject) \
((This)->lpVtbl->QueryInterface(This, riid, ppvObject))
#define IXCLRDataStackWalk_AddRef(This) \
((This)->lpVtbl->AddRef(This))
#define IXCLRDataStackWalk_Release(This) \
((This)->lpVtbl->Release(This))
#define IXCLRDataStackWalk_GetContext(This, contextFlags, contextBufSize, contextSize, contextBuf) \
((This)->lpVtbl->GetContext(This, contextFlags, contextBufSize, contextSize, contextBuf))
#define IXCLRDataStackWalk_Next(This) \
((This)->lpVtbl->Next(This))
#define IXCLRDataStackWalk_GetStackSizeSkipped(This, stackSizeSkipped) \
((This)->lpVtbl->GetStackSizeSkipped(This, stackSizeSkipped))
#define IXCLRDataStackWalk_GetFrameType(This, simpleType, detailedType) \
((This)->lpVtbl->GetFrameType(This, simpleType, detailedType))
#define IXCLRDataStackWalk_GetFrame(This, frame) \
((This)->lpVtbl->GetFrame(This, frame))
#define IXCLRDataStackWalk_Request(This, reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer) \
((This)->lpVtbl->SetContext2(This, reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer))
#define IXCLRDataStackWalk_SetContext2(This, flags, contextSize, context) \
((This)->lpVtbl->SetContext2(This, flags, contextSize, context))
typedef struct IXCLRDataFrameVtbl
{
HRESULT (STDMETHODCALLTYPE *QueryInterface)(
_In_ IXCLRDataFrame *This,
_In_ REFIID riid,
_Outptr_ void **ppvObject
);
ULONG (STDMETHODCALLTYPE *AddRef)(
_In_ IXCLRDataFrame *This
);
ULONG (STDMETHODCALLTYPE *Release)(
_In_ IXCLRDataFrame *This
);
HRESULT (STDMETHODCALLTYPE *GetFrameType)(
_In_ IXCLRDataFrame *This,
_Out_ CLRDataSimpleFrameType *simpleType,
_Out_ CLRDataDetailedFrameType *detailedType
);
HRESULT (STDMETHODCALLTYPE *GetContext)(
_In_ IXCLRDataFrame *This,
_In_ ULONG32 contextFlags,
_In_ ULONG32 contextBufSize,
_Out_ ULONG32 *contextSize,
_Out_ BYTE *contextBuf
);
PVOID GetAppDomain;
PVOID GetNumArguments;
PVOID GetArgumentByIndex;
PVOID GetNumLocalVariables;
PVOID GetLocalVariableByIndex;
HRESULT (STDMETHODCALLTYPE *GetCodeName)(
_In_ IXCLRDataFrame *This,
_In_ ULONG32 *flags,
_In_ ULONG32 *bufLen,
_Out_ ULONG32 *nameLen,
_Out_ WCHAR *nameBuf
);
} IXCLRDataFrameVtbl;
typedef struct IXCLRDataFrame
{
IXCLRDataFrameVtbl *lpVtbl;
} IXCLRDataFrame;
#define IXCLRDataFrame_QueryInterface(This, riid, ppvObject) \
((This)->lpVtbl->QueryInterface(This, riid, ppvObject))
#define IXCLRDataFrame_AddRef(This) \
((This)->lpVtbl->AddRef(This))
#define IXCLRDataFrame_Release(This) \
((This)->lpVtbl->Release(This))
#define IXCLRDataFrame_GetFrameType(This, simpleType, detailedType) \
((This)->lpVtbl->GetFrameType(This, simpleType, detailedType))
#define IXCLRDataFrame_GetContext(This, contextFlags, contextBufSize, contextSize, contextBuf) \
((This)->lpVtbl->GetContext(This, contextFlags, contextBufSize, contextSize, contextBuf))
#define IXCLRDataFrame_GetCodeName(This, flags, bufLen, nameLen, nameBuf) \
((This)->lpVtbl->GetCodeName(This, flags, bufLen, nameLen, nameBuf))
// DnCLRDataTarget
typedef struct
{
ICLRDataTargetVtbl *VTable;
ULONG RefCount;
HANDLE ProcessId;
HANDLE ProcessHandle;
BOOLEAN IsWow64;
} DnCLRDataTarget;
ICLRDataTarget *DnCLRDataTarget_Create(
_In_ HANDLE ProcessId
);
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_QueryInterface(
_In_ ICLRDataTarget *This,
_In_ REFIID Riid,
_Out_ PVOID *Object
);
ULONG STDMETHODCALLTYPE DnCLRDataTarget_AddRef(
_In_ ICLRDataTarget *This
);
ULONG STDMETHODCALLTYPE DnCLRDataTarget_Release(
_In_ ICLRDataTarget *This
);
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetMachineType(
_In_ ICLRDataTarget *This,
_Out_ ULONG32 *machineType
);
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetPointerSize(
_In_ ICLRDataTarget *This,
_Out_ ULONG32 *pointerSize
);
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetImageBase(
_In_ ICLRDataTarget *This,
_In_ LPCWSTR imagePath,
_Out_ CLRDATA_ADDRESS *baseAddress
);
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_ReadVirtual(
_In_ ICLRDataTarget *This,
_In_ CLRDATA_ADDRESS address,
_Out_ BYTE *buffer,
_In_ ULONG32 bytesRequested,
_Out_ ULONG32 *bytesRead
);
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_WriteVirtual(
_In_ ICLRDataTarget *This,
_In_ CLRDATA_ADDRESS address,
_In_ BYTE *buffer,
_In_ ULONG32 bytesRequested,
_Out_ ULONG32 *bytesWritten
);
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetTLSValue(
_In_ ICLRDataTarget *This,
_In_ ULONG32 threadID,
_In_ ULONG32 index,
_Out_ CLRDATA_ADDRESS *value
);
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_SetTLSValue(
_In_ ICLRDataTarget *This,
_In_ ULONG32 threadID,
_In_ ULONG32 index,
_In_ CLRDATA_ADDRESS value
);
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetCurrentThreadID(
_In_ ICLRDataTarget *This,
_Out_ ULONG32 *threadID
);
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetThreadContext(
_In_ ICLRDataTarget *This,
_In_ ULONG32 threadID,
_In_ ULONG32 contextFlags,
_In_ ULONG32 contextSize,
_Out_ BYTE *context
);
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_SetThreadContext(
_In_ ICLRDataTarget *This,
_In_ ULONG32 threadID,
_In_ ULONG32 contextSize,
_In_ BYTE *context
);
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_Request(
_In_ ICLRDataTarget *This,
_In_ ULONG32 reqCode,
_In_ ULONG32 inBufferSize,
_In_ BYTE *inBuffer,
_In_ ULONG32 outBufferSize,
_Out_ BYTE *outBuffer
);
typedef struct _PHP_GET_IMAGE_BASE_CONTEXT
{
UNICODE_STRING ImagePath;
PVOID BaseAddress;
} PHP_GET_IMAGE_BASE_CONTEXT, *PPHP_GET_IMAGE_BASE_CONTEXT;
#endif

File diff suppressed because it is too large Load Diff

144
plugins/DotNetTools/dn.h Normal file
View File

@@ -0,0 +1,144 @@
/*
* Process Hacker .NET Tools
*
* Copyright (C) 2011-2015 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/>.
*/
#ifndef DN_H
#define DN_H
#define CINTERFACE
#define COBJMACROS
#include <phdk.h>
#include <windowsx.h>
#include "resource.h"
#define PLUGIN_NAME L"ProcessHacker.DotNetTools"
#define SETTING_NAME_ASM_TREE_LIST_COLUMNS (PLUGIN_NAME L".AsmTreeListColumns")
#define SETTING_NAME_DOT_NET_CATEGORY_INDEX (PLUGIN_NAME L".DotNetCategoryIndex")
#define SETTING_NAME_DOT_NET_COUNTERS_COLUMNS (PLUGIN_NAME L".DotNetListColumns")
#define SETTING_NAME_DOT_NET_SHOW_BYTE_SIZE (PLUGIN_NAME L".DotNetShowByteSizes")
#define MSG_UPDATE (WM_APP + 1)
extern PPH_PLUGIN PluginInstance;
typedef struct _DN_THREAD_ITEM
{
PPH_THREAD_ITEM ThreadItem;
BOOLEAN ClrDataValid;
PPH_STRING AppDomainText;
} DN_THREAD_ITEM, *PDN_THREAD_ITEM;
// counters
PVOID GetPerfIpcBlock_V2(
_In_ BOOLEAN Wow64,
_In_ PVOID BlockTableAddress
);
PVOID GetPerfIpcBlock_V4(
_In_ BOOLEAN Wow64,
_In_ PVOID BlockTableAddress
);
BOOLEAN OpenDotNetPublicControlBlock_V2(
_In_ HANDLE ProcessId,
_Out_ HANDLE* BlockTableHandle,
_Out_ PVOID* BlockTableAddress
);
BOOLEAN OpenDotNetPublicControlBlock_V4(
_In_ BOOLEAN IsImmersive,
_In_ HANDLE ProcessHandle,
_In_ HANDLE ProcessId,
_Out_ HANDLE* BlockTableHandle,
_Out_ PVOID* BlockTableAddress
);
PPH_LIST QueryDotNetAppDomainsForPid_V2(
_In_ BOOLEAN Wow64,
_In_ HANDLE ProcessHandle,
_In_ HANDLE ProcessId
);
PPH_LIST QueryDotNetAppDomainsForPid_V4(
_In_ BOOLEAN Wow64,
_In_ HANDLE ProcessHandle,
_In_ HANDLE ProcessId
);
// asmpage
VOID AddAsmPageToPropContext(
_In_ PPH_PLUGIN_PROCESS_PROPCONTEXT PropContext
);
// perfpage
VOID AddPerfPageToPropContext(
_In_ PPH_PLUGIN_PROCESS_PROPCONTEXT PropContext
);
// stackext
VOID ProcessThreadStackControl(
_In_ PPH_PLUGIN_THREAD_STACK_CONTROL Control
);
VOID PredictAddressesFromClrData(
_In_ struct _CLR_PROCESS_SUPPORT *Support,
_In_ HANDLE ThreadId,
_In_ PVOID PcAddress,
_In_ PVOID FrameAddress,
_In_ PVOID StackAddress,
_Out_ PVOID *PredictedEip,
_Out_ PVOID *PredictedEbp,
_Out_ PVOID *PredictedEsp
);
// svcext
VOID DispatchPhSvcRequest(
_In_ PVOID Parameter
);
// treeext
VOID InitializeTreeNewObjectExtensions(
VOID
);
VOID DispatchTreeNewMessage(
__in PVOID Parameter
);
#define DNTHTNC_APPDOMAIN 1
VOID ThreadTreeNewInitializing(
__in PVOID Parameter
);
VOID ThreadTreeNewUninitializing(
__in PVOID Parameter
);
#endif

336
plugins/DotNetTools/main.c Normal file
View File

@@ -0,0 +1,336 @@
/*
* Process Hacker .NET Tools -
* main program
*
* Copyright (C) 2011-2015 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 "dn.h"
PPH_PLUGIN PluginInstance;
static PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration;
static PH_CALLBACK_REGISTRATION PluginUnloadCallbackRegistration;
static PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration;
static PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration;
static PH_CALLBACK_REGISTRATION PluginTreeNewMessageCallbackRegistration;
static PH_CALLBACK_REGISTRATION PluginPhSvcRequestCallbackRegistration;
static PH_CALLBACK_REGISTRATION MainWindowShowingCallbackRegistration;
static PH_CALLBACK_REGISTRATION ProcessPropertiesInitializingCallbackRegistration;
static PH_CALLBACK_REGISTRATION ProcessMenuInitializingCallbackRegistration;
static PH_CALLBACK_REGISTRATION ThreadMenuInitializingCallbackRegistration;
static PH_CALLBACK_REGISTRATION ModuleMenuInitializingCallbackRegistration;
static PH_CALLBACK_REGISTRATION ProcessTreeNewInitializingCallbackRegistration;
static PH_CALLBACK_REGISTRATION ThreadTreeNewInitializingCallbackRegistration;
static PH_CALLBACK_REGISTRATION ThreadTreeNewUninitializingCallbackRegistration;
static PH_CALLBACK_REGISTRATION ThreadStackControlCallbackRegistration;
VOID NTAPI LoadCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
NOTHING;
}
VOID NTAPI UnloadCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
NOTHING;
}
VOID NTAPI ShowOptionsCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
NOTHING;
}
VOID NTAPI MenuItemCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN_MENU_ITEM menuItem = Parameter;
switch (menuItem->Id)
{
default:
NOTHING;
break;
}
}
VOID NTAPI TreeNewMessageCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
DispatchTreeNewMessage(Parameter);
}
VOID NTAPI PhSvcRequestCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
DispatchPhSvcRequest(Parameter);
}
VOID NTAPI ThreadTreeNewInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
ThreadTreeNewInitializing(Parameter);
}
VOID NTAPI ThreadTreeNewUninitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
ThreadTreeNewUninitializing(Parameter);
}
VOID NTAPI ProcessPropertiesInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN_PROCESS_PROPCONTEXT propContext = Parameter;
BOOLEAN isDotNet;
if (NT_SUCCESS(PhGetProcessIsDotNet(propContext->ProcessItem->ProcessId, &isDotNet)))
{
if (isDotNet)
{
if (WindowsVersion >= WINDOWS_VISTA)
AddAsmPageToPropContext(propContext);
AddPerfPageToPropContext(propContext);
}
if (propContext->ProcessItem->IsDotNet != isDotNet)
propContext->ProcessItem->UpdateIsDotNet = TRUE; // force a refresh
}
}
VOID NTAPI ProcessMenuInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
NOTHING;
}
VOID NTAPI ThreadMenuInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
NOTHING;
}
VOID NTAPI ModuleMenuInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
NOTHING;
}
VOID NTAPI ProcessTreeNewInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
NOTHING;
}
VOID NTAPI ThreadStackControlCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
ProcessThreadStackControl(Parameter);
}
VOID NTAPI ThreadItemCreateCallback(
_In_ PVOID Object,
_In_ PH_EM_OBJECT_TYPE ObjectType,
_In_ PVOID Extension
)
{
PDN_THREAD_ITEM dnThread = Extension;
memset(dnThread, 0, sizeof(DN_THREAD_ITEM));
dnThread->ThreadItem = Object;
}
VOID NTAPI ThreadItemDeleteCallback(
_In_ PVOID Object,
_In_ PH_EM_OBJECT_TYPE ObjectType,
_In_ PVOID Extension
)
{
PDN_THREAD_ITEM dnThread = Extension;
PhClearReference(&dnThread->AppDomainText);
}
LOGICAL DllMain(
_In_ HINSTANCE Instance,
_In_ ULONG Reason,
_Reserved_ PVOID Reserved
)
{
switch (Reason)
{
case DLL_PROCESS_ATTACH:
{
PPH_PLUGIN_INFORMATION info;
PH_SETTING_CREATE settings[] =
{
{ StringSettingType, SETTING_NAME_ASM_TREE_LIST_COLUMNS, L"" },
{ IntegerSettingType, SETTING_NAME_DOT_NET_CATEGORY_INDEX, L"5" },
{ StringSettingType, SETTING_NAME_DOT_NET_COUNTERS_COLUMNS, L"" },
{ IntegerSettingType, SETTING_NAME_DOT_NET_SHOW_BYTE_SIZE, L"1" }
};
PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info);
if (!PluginInstance)
return FALSE;
info->DisplayName = L".NET Tools";
info->Author = L"dmex, wj32";
info->Description = L"Adds .NET performance counters, assembly information, thread stack support, and more.";
info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1111";
info->HasOptions = FALSE;
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(
PhGetPluginCallback(PluginInstance, PluginCallbackPhSvcRequest),
PhSvcRequestCallback,
NULL,
&PluginPhSvcRequestCallbackRegistration
);
//PhRegisterCallback(
// PhGetGeneralCallback(GeneralCallbackMainWindowShowing),
// MainWindowShowingCallback,
// NULL,
// &MainWindowShowingCallbackRegistration
// );
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackProcessPropertiesInitializing),
ProcessPropertiesInitializingCallback,
NULL,
&ProcessPropertiesInitializingCallbackRegistration
);
//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(GeneralCallbackThreadTreeNewInitializing),
ThreadTreeNewInitializingCallback,
NULL,
&ThreadTreeNewInitializingCallbackRegistration
);
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackThreadTreeNewUninitializing),
ThreadTreeNewUninitializingCallback,
NULL,
&ThreadTreeNewUninitializingCallbackRegistration
);
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackThreadStackControl),
ThreadStackControlCallback,
NULL,
&ThreadStackControlCallbackRegistration
);
PhPluginSetObjectExtension(
PluginInstance,
EmThreadItemType,
sizeof(DN_THREAD_ITEM),
ThreadItemCreateCallback,
ThreadItemDeleteCallback
);
InitializeTreeNewObjectExtensions();
PhAddSettings(settings, ARRAYSIZE(settings));
}
break;
}
return TRUE;
}

View File

@@ -0,0 +1,944 @@
/*
* Process Hacker .NET Tools -
* .NET Performance property page
*
* Copyright (C) 2011-2015 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 "dn.h"
#include "clr\perfcounterdefs.h"
typedef enum _DOTNET_CATEGORY
{
// .NET CLR Exceptions (Runtime statistics on CLR exception handling)
DOTNET_CATEGORY_EXCEPTIONS,
// .NET CLR Interop (Stats for CLR interop)
DOTNET_CATEGORY_INTEROP,
// .NET CLR Jit (Stats for CLR Jit)
DOTNET_CATEGORY_JIT,
// .NET CLR Loading (Statistics for CLR Class Loader)
DOTNET_CATEGORY_LOADING,
// .NET CLR LocksAndThreads (Stats for CLR Locks and Threads)
DOTNET_CATEGORY_LOCKSANDTHREADS,
// .NET CLR Memory (Counters for CLR Garbage Collected heap)
DOTNET_CATEGORY_MEMORY,
// .NET CLR Remoting (Stats for CLR Remoting)
DOTNET_CATEGORY_REMOTING,
// .NET CLR Security (Stats for CLR Security)
DOTNET_CATEGORY_SECURITY
} DOTNET_CATEGORY;
typedef struct _PERFPAGE_CONTEXT
{
HWND WindowHandle;
PPH_PROCESS_ITEM ProcessItem;
BOOLEAN Enabled;
HWND AppDomainsLv;
HWND CountersLv;
HWND CategoriesCb;
BOOLEAN ControlBlockValid;
BOOLEAN ClrV4;
BOOLEAN IsWow64;
BOOLEAN ShowByteSize;
DOTNET_CATEGORY CategoryIndex;
HANDLE ProcessHandle;
HANDLE BlockTableHandle;
PVOID BlockTableAddress;
PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration;
} PERFPAGE_CONTEXT, *PPERFPAGE_CONTEXT;
static PWSTR DotNetCategoryStrings[] =
{
L".NET CLR Exceptions",
L".NET CLR Interop",
L".NET CLR Jit",
L".NET CLR Loading",
L".NET CLR LocksAndThreads",
L".NET CLR Memory",
L".NET CLR Remoting",
L".NET CLR Security"
};
PPH_STRING FormatByteValue(
_In_ PPERFPAGE_CONTEXT Context,
_In_ ULONG64 Value
)
{
if (Context->ShowByteSize)
return PhaFormatUInt64(Value, TRUE);
return PhaFormatSize(Value, -1);
}
VOID NTAPI ProcessesUpdatedCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPERFPAGE_CONTEXT context = Context;
if (context->WindowHandle)
{
PostMessage(context->WindowHandle, MSG_UPDATE, 0, 0);
}
}
VOID UpdateCategoryValues(
_In_ HWND hwndDlg,
_In_ PPERFPAGE_CONTEXT Context
)
{
ListView_DeleteAllItems(Context->CountersLv);
switch (Context->CategoryIndex)
{
case DOTNET_CATEGORY_EXCEPTIONS:
{
// This counter displays the total number of exceptions thrown since the start of the application. These include both .NET exceptions and unmanaged exceptions that get converted into .NET exceptions e.g. null pointer reference exception in unmanaged code would get re-thrown in managed code as a .NET System.NullReferenceException; this counter includes both handled and unhandled exceptions.Exceptions that are re-thrown would get counted again. Exceptions should only occur in rare situations and not in the normal control flow of the program.
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Exceps Thrown", NULL);
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Filters Executed", NULL);
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Finallys Executed", NULL);
// Reserved for future use.
//PhAddListViewItem(Context->CountersLv, MAXINT, L" Delta from throw to catch site on stack", NULL);
// # of Exceps Thrown / sec
// This counter displays the number of exceptions thrown per second.These include both.NET exceptions and unmanaged exceptions that get converted into.NET exceptions e.g.null pointer reference exception in unmanaged code would get re - thrown in managed code as a.NET System.NullReferenceException; this counter includes both handled and unhandled exceptions.Exceptions should only occur in rare situations and not in the normal control flow of the program; this counter was designed as an indicator of potential performance problems due to large(> 100s) rate of exceptions thrown.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
// # of Filters / sec
// This counter displays the number of.NET exception filters executed per second.An exception filter evaluates whether an exception should be handled or not.This counter tracks the rate of exception filters evaluated; irrespective of whether the exception was handled or not.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
// # of Finallys / sec
// This counter displays the number of finally blocks executed per second.A finally block is guaranteed to be executed regardless of how the try block was exited.Only the finally blocks that are executed for an exception are counted; finally blocks on normal code paths are not counted by this counter.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
// Throw To Catch Depth / sec
// This counter displays the number of stack frames traversed from the frame that threw the.NET exception to the frame that handled the exception per second.This counter resets to 0 when an exception handler is entered; so nested exceptions would show the handler to handler stack depth.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.* /
}
break;
case DOTNET_CATEGORY_INTEROP:
{
// This counter displays the current number of Com-Callable-Wrappers (CCWs). A CCW is a proxy for the .NET managed object being referenced from unmanaged COM client(s). This counter was designed to indicate the number of managed objects being referenced by unmanaged COM code.
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of CCWs", NULL);
// This counter displays the current number of stubs created by the CLR. Stubs are responsible for marshalling arguments and return values from managed to unmanaged code and vice versa; during a COM Interop call or PInvoke call.
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Stubs", NULL);
// This counter displays the total number of times arguments and return values have been marshaled from managed to unmanaged code and vice versa since the start of the application. This counter is not incremented if the stubs are inlined. (Stubs are responsible for marshalling arguments and return values). Stubs usually get inlined if the marshalling overhead is small.
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Marshalling", NULL);
// Reserved for future use.
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of TLB imports / sec", NULL);
// Reserved for future use.
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of TLB exports / sec", NULL);
}
break;
case DOTNET_CATEGORY_JIT:
{
// This counter displays the total number of methods compiled Just-In-Time (JIT) by the CLR JIT compiler since the start of the application. This counter does not include the pre-jitted methods.
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Methods Jitted", NULL);
// This counter displays the total IL bytes jitted since the start of the application. This counter is exactly equivalent to the "Total # of IL Bytes Jitted" counter.
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of IL Bytes Jitted", NULL);
// This counter displays the total IL bytes jitted since the start of the application. This counter is exactly equivalent to the "# of IL Bytes Jitted" counter.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Total # of IL Bytes Jitted", NULL);
// This counter displays the peak number of methods the JIT compiler has failed to JIT since the start of the application. This failure can occur if the IL cannot be verified or if there was an internal error in the JIT compiler.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Jit Failures", NULL);
// This counter displays the percentage of elapsed time spent in JIT compilation since the last JIT compilation phase. This counter is updated at the end of every JIT compilation phase. A JIT compilation phase is the phase when a method and its dependencies are being compiled.
PhAddListViewItem(Context->CountersLv, MAXINT, L"% Time in Jit", NULL);
// IL Bytes Jitted / sec
// This counter displays the rate at which IL bytes are jitted per second. This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
}
break;
case DOTNET_CATEGORY_LOADING:
{
// This counter displays the current number of classes loaded in all Assemblies.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Current Classes Loaded", NULL);
// This counter displays the cumulative number of classes loaded in all Assemblies since the start of this application.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Classes Loaded", NULL);
// This counter displays the current number of AppDomains loaded in this application. AppDomains (application domains) provide a secure and versatile unit of processing that the CLR can use to provide isolation between applications running in the same process.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Current Appdomains", NULL);
// This counter displays the peak number of AppDomains loaded since the start of this application. AppDomains (application domains) provide a secure and versatile unit of processing that the CLR can use to provide isolation between applications running in the same process.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Appdomains", NULL);
// This counter displays the current number of Assemblies loaded across all AppDomains in this application. If the Assembly is loaded as domain - neutral from multiple AppDomains then this counter is incremented once only. Assemblies can be loaded as domain - neutral when their code can be shared by all AppDomains or they can be loaded as domain - specific when their code is private to the AppDomain.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Current Assemblies", NULL);
// This counter displays the total number of Assemblies loaded since the start of this application. If the Assembly is loaded as domain - neutral from multiple AppDomains then this counter is incremented once only. Assemblies can be loaded as domain - neutral when their code can be shared by all AppDomains or they can be loaded as domain - specific when their code is private to the AppDomain.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Assemblies", NULL);
// Reserved for future use.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Assembly Search Length", NULL);
// This counter displays the peak number of classes that have failed to load since the start of the application.These load failures could be due to many reasons like inadequate security or illegal format.Full details can be found in the profiling services help.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Total # of Load Failures", NULL);
// This counter displays the current size(in bytes) of the memory committed by the class loader across all AppDomains. (Committed memory is the physical memory for which space has been reserved on the disk paging file.)
PhAddListViewItem(Context->CountersLv, MAXINT, L"Bytes in Loader Heap", NULL);
// This counter displays the total number of AppDomains unloaded since the start of the application. If an AppDomain is loaded and unloaded multiple times this counter would count each of those unloads as separate.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Appdomains Unloaded", NULL);
// Reserved for future use.
//PhAddListViewItem(Context->CountersLv, MAXINT, L"% Time Loading", NULL);
// Rate of Load Failures
// This counter displays the number of classes that failed to load per second. This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. These load failures could be due to many reasons like inadequate security or illegal format. Full details can be found in the profiling services help.
// Rate of appdomains unloaded
// This counter displays the number of AppDomains unloaded per second.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
// Rate of Classes Loaded
// This counter displays the number of classes loaded per second in all Assemblies.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
// Rate of appdomains
// This counter displays the number of AppDomains loaded per second.AppDomains(application domains) provide a secure and versatile unit of processing that the CLR can use to provide isolation between applications running in the same process.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
// Rate of Assemblies
// This counter displays the number of Assemblies loaded across all AppDomains per second.If the Assembly is loaded as domain - neutral from multiple AppDomains then this counter is incremented once only.Assemblies can be loaded as domain - neutral when their code can be shared by all AppDomains or they can be loaded as domain - specific when their code is private to the AppDomain.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
}
break;
case DOTNET_CATEGORY_LOCKSANDTHREADS:
{
// This counter displays the total number of times threads in the CLR have attempted to acquire a managed lock unsuccessfully. Managed locks can be acquired in many ways; by the "lock" statement in C# or by calling System.Monitor.Enter or by using MethodImplOptions.Synchronized custom attribute.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Total # of Contentions", NULL);
// This counter displays the total number of threads currently waiting to acquire some managed lock in the application. This counter is not an average over time; it displays the last observed value.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Current Queue Length", NULL);
// This counter displays the total number of threads that waited to acquire some managed lock since the start of the application.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Queue Length Peak", NULL);
// This counter displays the number of current.NET thread objects in the application.A.NET thread object is created either by new System.Threading.Thread or when an unmanaged thread enters the managed environment. This counters maintains the count of both running and stopped threads. This counter is not an average over time; it just displays the last observed value.
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Current Logical Threads", NULL);
// This counter displays the number of native OS threads created and owned by the CLR to act as underlying threads for .NET thread objects. This counters value does not include the threads used by the CLR in its internal operations; it is a subset of the threads in the OS process.
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Current Physical Threads", NULL);
// This counter displays the number of threads that are currently recognized by the CLR; they have a corresponding .NET thread object associated with them. These threads are not created by the CLR; they are created outside the CLR but have since run inside the CLR at least once. Only unique threads are tracked; threads with same thread ID re-entering the CLR or recreated after thread exit are not counted twice.
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Current Recognized Threads", NULL);
// This counter displays the total number of threads that have been recognized by the CLR since the start of this application; these threads have a corresponding .NET thread object associated with them. These threads are not created by the CLR; they are created outside the CLR but have since run inside the CLR at least once. Only unique threads are tracked; threads with same thread ID re-entering the CLR or recreated after thread exit are not counted twice.
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Total Recognized Threads", NULL);
// Contention Rate / sec
// Rate at which threads in the runtime attempt to acquire a managed lock unsuccessfully.Managed locks can be acquired in many ways; by the "lock" statement in C# or by calling System.Monitor.Enter or by using MethodImplOptions.Synchronized custom attribute.
// Queue Length / sec
// This counter displays the number of threads per second waiting to acquire some lock in the application. This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
// rate of recognized threads / sec
// This counter displays the number of threads per second that have been recognized by the CLR; these threads have a corresponding .NET thread object associated with them. These threads are not created by the CLR; they are created outside the CLR but have since run inside the CLR at least once. Only unique threads are tracked; threads with same thread ID re-entering the CLR or recreated after thread exit are not counted twice. This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
}
break;
case DOTNET_CATEGORY_MEMORY:
{
// This counter displays the number of times the generation 0 objects (youngest; most recently allocated) are garbage collected (Gen 0 GC) since the start of the application. Gen 0 GC occurs when the available memory in generation 0 is not sufficient to satisfy an allocation request. This counter is incremented at the end of a Gen 0 GC. Higher generation GCs include all lower generation GCs.This counter is explicitly incremented when a higher generation (Gen 1 or Gen 2) GC occurs. _Global_ counter value is not accurate and should be ignored. This counter displays the last observed value.
PhAddListViewItem(Context->CountersLv, MAXINT, L"# Gen 0 Collections", NULL);
// This counter displays the number of times the generation 1 objects are garbage collected since the start of the application. The counter is incremented at the end of a Gen 1 GC. Higher generation GCs include all lower generation GCs. This counter is explicitly incremented when a higher generation (Gen 2) GC occurs. _Global_ counter value is not accurate and should be ignored. This counter displays the last observed value.
PhAddListViewItem(Context->CountersLv, MAXINT, L"# Gen 1 Collections", NULL);
// This counter displays the number of times the generation 2 objects(older) are garbage collected since the start of the application.The counter is incremented at the end of a Gen 2 GC(also called full GC)._Global_ counter value is not accurate and should be ignored.This counter displays the last observed value.
PhAddListViewItem(Context->CountersLv, MAXINT, L"# Gen 2 Collections", NULL);
// This counter displays the bytes of memory that survive garbage collection(GC) and are promoted from generation 0 to generation 1; objects that are promoted just because they are waiting to be finalized are not included in this counter.This counter displays the value observed at the end of the last GC; its not a cumulative counter.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Promoted Memory from Gen 0", NULL);
// This counter displays the bytes of memory that survive garbage collection(GC) and are promoted from generation 1 to generation 2; objects that are promoted just because they are waiting to be finalized are not included in this counter.This counter displays the value observed at the end of the last GC; its not a cumulative counter.This counter is reset to 0 if the last GC was a Gen 0 GC only.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Promoted Memory from Gen 1", NULL);
// This counter displays the bytes of memory that are promoted from generation 0 to generation 1 just because they are waiting to be finalized.This counter displays the value observed at the end of the last GC; its not a cumulative counter.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Promoted Finalization-Memory from Gen 0", NULL);
// Reserved for future use.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Process ID", NULL);
// This counter displays the maximum bytes that can be allocated in generation 0 (Gen 0); its does not indicate the current number of bytes allocated in Gen 0. A Gen 0 GC is triggered when the allocations since the last GC exceed this size.The Gen 0 size is tuned by the Garbage Collector and can change during the execution of the application.At the end of a Gen 0 collection the size of the Gen 0 heap is infact 0 bytes; this counter displays the size(in bytes) of allocations that would trigger the next Gen 0 GC.This counter is updated at the end of a GC; its not updated on every allocation.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Gen 0 Heap Size", NULL);
// This counter displays the current number of bytes in generation 1 (Gen 1); this counter does not display the maximum size of Gen 1. Objects are not directly allocated in this generation; they are promoted from previous Gen 0 GCs.This counter is updated at the end of a GC; its not updated on every allocation.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Gen 1 Heap Size", NULL);
// This counter displays the current number of bytes in generation 2 (Gen 2).Objects are not directly allocated in this generation; they are promoted from Gen 1 during previous Gen 1 GCs.This counter is updated at the end of a GC; its not updated on every allocation.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Gen 2 Heap Size", NULL);
// This counter displays the current size of the Large Object Heap in bytes.Objects greater than 20 KBytes are treated as large objects by the Garbage Collector and are directly allocated in a special heap; they are not promoted through the generations.This counter is updated at the end of a GC; its not updated on every allocation.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Large Object Heap Size", NULL);
// This counter displays the number of garbage collected objects that survive a collection because they are waiting to be finalized.If these objects hold references to other objects then those objects also survive but are not counted by this counter; the "Promoted Finalization-Memory from Gen 0" and "Promoted Finalization-Memory from Gen 1" counters represent all the memory that survived due to finalization.This counter is not a cumulative counter; its updated at the end of every GC with count of the survivors during that particular GC only.This counter was designed to indicate the extra overhead that the application might incur because of finalization.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Finalization Survivors", NULL);
// This counter displays the current number of GC Handles in use.GCHandles are handles to resources external to the CLR and the managed environment.Handles occupy small amounts of memory in the GCHeap but potentially expensive unmanaged resources.
PhAddListViewItem(Context->CountersLv, MAXINT, L"# GC Handles", NULL);
// This counter displays the peak number of times a garbage collection was performed because of an explicit call to GC.Collect. Its a good practice to let the GC tune the frequency of its collections.
PhAddListViewItem(Context->CountersLv, MAXINT, L"# Induced GC", NULL);
// % Time in GC is the percentage of elapsed time that was spent in performing a garbage collection(GC) since the last GC cycle. This counter is usually an indicator of the work done by the Garbage Collector on behalf of the application to collect and compact memory.This counter is updated only at the end of every GC and the counter value reflects the last observed value; its not an average.
PhAddListViewItem(Context->CountersLv, MAXINT, L"% Time in GC", NULL);
// This counter is the sum of four other counters; Gen 0 Heap Size; Gen 1 Heap Size; Gen 2 Heap Size and the Large Object Heap Size. This counter indicates the current memory allocated in bytes on the GC Heaps.
PhAddListViewItem(Context->CountersLv, MAXINT, L"# Bytes in all Heaps", NULL);
// This counter displays the amount of virtual memory(in bytes) currently committed by the Garbage Collector. (Committed memory is the physical memory for which space has been reserved on the disk paging file).
PhAddListViewItem(Context->CountersLv, MAXINT, L"# Total Committed Bytes", NULL);
// This counter displays the amount of virtual memory(in bytes) currently reserved by the Garbage Collector. (Reserved memory is the virtual memory space reserved for the application but no disk or main memory pages have been used.)
PhAddListViewItem(Context->CountersLv, MAXINT, L"# Total Reserved Bytes", NULL);
// This counter displays the number of pinned objects encountered in the last GC. This counter tracks the pinned objects only in the heaps that were garbage collected e.g. A Gen 0 GC would cause enumeration of pinned objects in the generation 0 heap only. A pinned object is one that the Garbage Collector cannot move in memory.
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Pinned Objects", NULL);
// This counter displays the current number of sync blocks in use. Sync blocks are per-object data structures allocated for storing synchronization information. Sync blocks hold weak references to managed objects and need to be scanned by the Garbage Collector. Sync blocks are not limited to storing synchronization information and can also store COM interop metadata. This counter was designed to indicate performance problems with heavy use of synchronization primitives.
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Sink Blocks in use", NULL);
// Reserved for future use.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Bytes Allocated (since start)", NULL);
// Reserved for future use.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Bytes Allocated for Large Objects (since start)", NULL);
// Gen 0 Promoted Bytes / Sec
// This counter displays the bytes per second that are promoted from generation 0 (youngest)to generation 1; objects that are promoted just because they are waiting to be finalized are not included in this counter.Memory is promoted when it survives a garbage collection.This counter was designed as an indicator of relatively long - lived objects being created per sec.This counter displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
// Gen 1 Promoted Bytes / Sec
// This counter displays the bytes per second that are promoted from generation 1 to generation 2 (oldest); objects that are promoted just because they are waiting to be finalized are not included in this counter.Memory is promoted when it survives a garbage collection.Nothing is promoted from generation 2 since it is the oldest.This counter was designed as an indicator of very long - lived objects being created per sec.This counter displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
// Promoted Finalization - Memory from Gen 1
// This counter displays the bytes of memory that are promoted from generation 1 to generation 2 just because they are waiting to be finalized.This counter displays the value observed at the end of the last GC; its not a cumulative counter.This counter is reset to 0 if the last GC was a Gen 0 GC only.
// Allocated Bytes / sec
// This counter displays the rate of bytes per second allocated on the GC Heap.This counter is updated at the end of every GC; not at each allocation.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
}
break;
case DOTNET_CATEGORY_REMOTING:
{
// This counter displays the total number of remote procedure calls invoked since the start of this application. A remote procedure call is a call on any object outside the callers AppDomain.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Remote Calls", NULL);
// This counter displays the total number of remoting channels registered across all AppDomains since the start of the application. Channels are used to transport messages to and from remote objects.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Channels", NULL);
// This counter displays the total number of remoting proxy objects created in this process since the start of the process. Proxy object acts as a representative of the remote objects and ensures that all calls made on the proxy are forwarded to the correct remote object instance.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Context Proxies", NULL);
// This counter displays the current number of context-bound classes loaded. Classes that can be bound to a context are called context-bound classes; context-bound classes are marked with Context Attributes which provide usage rules for synchronization; thread affinity; transactions etc.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Context-Bound Classes Loaded", NULL);
// This counter displays the current number of remoting contexts in the application. A context is a boundary containing a collection of objects with the same usage rules like synchronization; thread affinity; transactions etc.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Contexts", NULL);
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of context bound objects allocated", NULL);
// Remote Calls / sec
// This counter displays the number of remote procedure calls invoked per second. A remote procedure call is a call on any object outside the callers AppDomain. This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
// Context - Bound Objects Alloc / sec
// This counter displays the number of context - bound objects allocated per second. Instances of classes that can be bound to a context are called context - bound objects; context - bound classes are marked with Context Attributes which provide usage rules for synchronization; thread affinity; transactions etc.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
}
break;
case DOTNET_CATEGORY_SECURITY:
{
// This counter displays the total number of runtime Code Access Security(CAS) checks performed since the start of the application. Runtime CAS checks are performed when a caller makes a call to a callee demanding a particular permission; the runtime check is made on every call by the caller; the check is done by examining the current thread stack of the caller. This counter used together with "Stack Walk Depth" is indicative of performance penalty for security checks.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Runtime Checks", NULL);
// This counter displays the total number of linktime Code Access Security(CAS) checks since the start of the application. Linktime CAS checks are performed when a caller makes a call to a callee demanding a particular permission at JIT compile time; linktime check is performed once per caller. This count is not indicative of serious performance issues; its indicative of the security system activity.
PhAddListViewItem(Context->CountersLv, MAXINT, L"# Link Time Checks", NULL);
// This counter displays the percentage of elapsed time spent in performing runtime Code Access Security(CAS) checks since the last such check. CAS allows code to be trusted to varying degrees and enforces these varying levels of trust depending on code identity. This counter is updated at the end of a runtime security check; it represents the last observed value; its not an average.
PhAddListViewItem(Context->CountersLv, MAXINT, L"% Time in RT checks", NULL);
// This counter displays the depth of the stack during that last runtime Code Access Security check.Runtime Code Access Security check is performed by crawling the stack. This counter is not an average; it just displays the last observed value.
PhAddListViewItem(Context->CountersLv, MAXINT, L"Stack Walk Depth", NULL);
// % Time Sig.Authenticating
// Reserved for future use.
}
break;
}
}
VOID AddProcessAppDomains(
_In_ HWND hwndDlg,
_In_ PPERFPAGE_CONTEXT Context
)
{
SendMessage(Context->AppDomainsLv, WM_SETREDRAW, FALSE, 0);
ListView_DeleteAllItems(Context->AppDomainsLv);
if (Context->ClrV4)
{
PPH_LIST processAppDomains = QueryDotNetAppDomainsForPid_V4(
Context->IsWow64,
Context->ProcessHandle,
Context->ProcessItem->ProcessId
);
for (ULONG i = 0; i < processAppDomains->Count; i++)
{
PhAddListViewItem(Context->AppDomainsLv, MAXINT, processAppDomains->Items[i], NULL);
PhFree(processAppDomains->Items[i]);
}
PhDereferenceObject(processAppDomains);
}
else
{
PPH_LIST processAppDomains = QueryDotNetAppDomainsForPid_V2(
Context->IsWow64,
Context->ProcessHandle,
Context->ProcessItem->ProcessId
);
for (ULONG i = 0; i < processAppDomains->Count; i++)
{
PhAddListViewItem(Context->AppDomainsLv, MAXINT, processAppDomains->Items[i], NULL);
PhFree(processAppDomains->Items[i]);
}
PhDereferenceObject(processAppDomains);
}
SendMessage(Context->AppDomainsLv, WM_SETREDRAW, TRUE, 0);
}
VOID UpdateCounterData(
_In_ HWND hwndDlg,
_In_ PPERFPAGE_CONTEXT Context
)
{
PVOID perfStatBlock = NULL;
Perf_GC dotNetPerfGC;
Perf_Contexts dotNetPerfContext;
Perf_Interop dotNetPerfInterop;
Perf_Loading dotNetPerfLoading;
Perf_Excep dotNetPerfExcep;
Perf_LocksAndThreads dotNetPerfLocksAndThreads;
Perf_Jit dotNetPerfJit;
Perf_Security dotNetPerfSecurity;
if (Context->ClrV4)
{
perfStatBlock = GetPerfIpcBlock_V4(
Context->IsWow64,
Context->BlockTableAddress
);
}
else
{
perfStatBlock = GetPerfIpcBlock_V2(
Context->IsWow64,
Context->BlockTableAddress
);
}
if (!perfStatBlock)
return;
if (Context->IsWow64)
{
PerfCounterIPCControlBlock_Wow64* perfBlock = perfStatBlock;
Perf_GC_Wow64 dotNetPerfGC_Wow64 = perfBlock->GC;
Perf_Loading_Wow64 dotNetPerfLoading_Wow64 = perfBlock->Loading;
Perf_Security_Wow64 dotNetPerfSecurity_Wow64 = perfBlock->Security;
// Thunk the Wow64 structures into their 64bit versions (or 32bit version on x86).
dotNetPerfGC.cGenCollections[0] = dotNetPerfGC_Wow64.cGenCollections[0];
dotNetPerfGC.cGenCollections[1] = dotNetPerfGC_Wow64.cGenCollections[1];
dotNetPerfGC.cGenCollections[2] = dotNetPerfGC_Wow64.cGenCollections[2];
dotNetPerfGC.cbPromotedMem[0] = dotNetPerfGC_Wow64.cbPromotedMem[0];
dotNetPerfGC.cbPromotedMem[1] = dotNetPerfGC_Wow64.cbPromotedMem[1];
dotNetPerfGC.cbPromotedFinalizationMem = dotNetPerfGC_Wow64.cbPromotedFinalizationMem;
dotNetPerfGC.cProcessID = dotNetPerfGC_Wow64.cProcessID;
dotNetPerfGC.cGenHeapSize[0] = dotNetPerfGC_Wow64.cGenHeapSize[0];
dotNetPerfGC.cGenHeapSize[1] = dotNetPerfGC_Wow64.cGenHeapSize[1];
dotNetPerfGC.cGenHeapSize[2] = dotNetPerfGC_Wow64.cGenHeapSize[2];
dotNetPerfGC.cTotalCommittedBytes = dotNetPerfGC_Wow64.cTotalCommittedBytes;
dotNetPerfGC.cTotalReservedBytes = dotNetPerfGC_Wow64.cTotalReservedBytes;
dotNetPerfGC.cLrgObjSize = dotNetPerfGC_Wow64.cLrgObjSize;
dotNetPerfGC.cSurviveFinalize = dotNetPerfGC_Wow64.cSurviveFinalize;
dotNetPerfGC.cHandles = dotNetPerfGC_Wow64.cHandles;
dotNetPerfGC.cbAlloc = dotNetPerfGC_Wow64.cbAlloc;
dotNetPerfGC.cbLargeAlloc = dotNetPerfGC_Wow64.cbLargeAlloc;
dotNetPerfGC.cInducedGCs = dotNetPerfGC_Wow64.cInducedGCs;
dotNetPerfGC.timeInGC = dotNetPerfGC_Wow64.timeInGC;
dotNetPerfGC.timeInGCBase = dotNetPerfGC_Wow64.timeInGCBase;
dotNetPerfGC.cPinnedObj = dotNetPerfGC_Wow64.cPinnedObj;
dotNetPerfGC.cSinkBlocks = dotNetPerfGC_Wow64.cSinkBlocks;
dotNetPerfContext = perfBlock->Context;
dotNetPerfInterop = perfBlock->Interop;
dotNetPerfLoading.cClassesLoaded.Current = dotNetPerfLoading_Wow64.cClassesLoaded.Current;
dotNetPerfLoading.cClassesLoaded.Total = dotNetPerfLoading_Wow64.cClassesLoaded.Total;
dotNetPerfLoading.cAppDomains.Current = dotNetPerfLoading_Wow64.cAppDomains.Current;
dotNetPerfLoading.cAppDomains.Total = dotNetPerfLoading_Wow64.cAppDomains.Total;
dotNetPerfLoading.cAssemblies.Current = dotNetPerfLoading_Wow64.cAssemblies.Current;
dotNetPerfLoading.cAssemblies.Total = dotNetPerfLoading_Wow64.cAssemblies.Total;
dotNetPerfLoading.timeLoading = dotNetPerfLoading_Wow64.timeLoading;
dotNetPerfLoading.cAsmSearchLen = dotNetPerfLoading_Wow64.cAsmSearchLen;
dotNetPerfLoading.cLoadFailures.Total = dotNetPerfLoading_Wow64.cLoadFailures.Total;
dotNetPerfLoading.cbLoaderHeapSize = dotNetPerfLoading_Wow64.cbLoaderHeapSize;
dotNetPerfLoading.cAppDomainsUnloaded = dotNetPerfLoading_Wow64.cAppDomainsUnloaded;
dotNetPerfExcep = perfBlock->Excep;
dotNetPerfLocksAndThreads = perfBlock->LocksAndThreads;
dotNetPerfJit = perfBlock->Jit;
dotNetPerfSecurity.cTotalRTChecks = dotNetPerfSecurity_Wow64.cTotalRTChecks;
dotNetPerfSecurity.timeAuthorize = dotNetPerfSecurity_Wow64.timeAuthorize;
dotNetPerfSecurity.cLinkChecks = dotNetPerfSecurity_Wow64.cLinkChecks;
dotNetPerfSecurity.timeRTchecks = dotNetPerfSecurity_Wow64.timeRTchecks;
dotNetPerfSecurity.timeRTchecksBase = dotNetPerfSecurity_Wow64.timeRTchecksBase;
dotNetPerfSecurity.stackWalkDepth = dotNetPerfSecurity_Wow64.stackWalkDepth;
}
else
{
PerfCounterIPCControlBlock* perfBlock = perfStatBlock;
dotNetPerfGC = perfBlock->GC;
dotNetPerfContext = perfBlock->Context;
dotNetPerfInterop = perfBlock->Interop;
dotNetPerfLoading = perfBlock->Loading;
dotNetPerfExcep = perfBlock->Excep;
dotNetPerfLocksAndThreads = perfBlock->LocksAndThreads;
dotNetPerfJit = perfBlock->Jit;
dotNetPerfSecurity = perfBlock->Security;
}
switch (Context->CategoryIndex)
{
case DOTNET_CATEGORY_EXCEPTIONS:
{
PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfExcep.cThrown.Total, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfExcep.cFiltersExecuted, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfExcep.cFinallysExecuted, TRUE)->Buffer);
//PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfExcep.cThrowToCatchStackDepth, TRUE)->Buffer);
}
break;
case DOTNET_CATEGORY_INTEROP:
{
PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfInterop.cCCW, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfInterop.cStubs, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfInterop.cMarshalling, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfInterop.cTLBImports, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 4, 1, PhaFormatUInt64(dotNetPerfInterop.cTLBExports, TRUE)->Buffer);
}
break;
case DOTNET_CATEGORY_JIT:
{
PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfJit.cMethodsJitted, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 1, 1, FormatByteValue(Context, dotNetPerfJit.cbILJitted.Current)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 2, 1, FormatByteValue(Context, dotNetPerfJit.cbILJitted.Total)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfJit.cJitFailures, TRUE)->Buffer);
if (dotNetPerfJit.timeInJitBase != 0)
{
PH_FORMAT format;
WCHAR formatBuffer[10];
// TODO: TimeInJit is always above 100% for some processes ??
// SeeAlso: https://github.com/dotnet/coreclr/blob/master/src/gc/gcee.cpp#L324
PhInitFormatF(&format, (dotNetPerfJit.timeInJit << 8) * 100 / (FLOAT)(dotNetPerfJit.timeInJitBase << 8), 2);
if (PhFormatToBuffer(&format, 1, formatBuffer, sizeof(formatBuffer), NULL))
PhSetListViewSubItem(Context->CountersLv, 4, 1, formatBuffer);
}
else
{
PhSetListViewSubItem(Context->CountersLv, 4, 1, L"0.00");
}
}
break;
case DOTNET_CATEGORY_LOADING:
{
PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfLoading.cClassesLoaded.Current, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfLoading.cClassesLoaded.Total, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfLoading.cAppDomains.Current, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfLoading.cAppDomains.Total, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 4, 1, PhaFormatUInt64(dotNetPerfLoading.cAssemblies.Current, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 5, 1, PhaFormatUInt64(dotNetPerfLoading.cAssemblies.Total, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 6, 1, PhaFormatUInt64(dotNetPerfLoading.cAsmSearchLen, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 7, 1, PhaFormatUInt64(dotNetPerfLoading.cLoadFailures.Total, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 8, 1, FormatByteValue(Context, dotNetPerfLoading.cbLoaderHeapSize)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 9, 1, PhaFormatUInt64(dotNetPerfLoading.cAppDomainsUnloaded.Total, TRUE)->Buffer);
//PhSetListViewSubItem(Context->CountersLv, 10, 1, PhaFormatUInt64(dotNetPerfLoading.timeLoading, TRUE)->Buffer);
}
break;
case DOTNET_CATEGORY_LOCKSANDTHREADS:
{
PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cContention.Total, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cQueueLength.Current, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cQueueLength.Total, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cCurrentThreadsLogical, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 4, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cCurrentThreadsPhysical, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 5, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cRecognizedThreads.Current, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 6, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cRecognizedThreads.Total, TRUE)->Buffer);
}
break;
case DOTNET_CATEGORY_MEMORY:
{
PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfGC.cGenCollections[0], TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfGC.cGenCollections[1], TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfGC.cGenCollections[2], TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 3, 1, FormatByteValue(Context, dotNetPerfGC.cbPromotedMem[0])->Buffer);
PhSetListViewSubItem(Context->CountersLv, 4, 1, FormatByteValue(Context, dotNetPerfGC.cbPromotedMem[1])->Buffer);
PhSetListViewSubItem(Context->CountersLv, 5, 1, FormatByteValue(Context, dotNetPerfGC.cbPromotedFinalizationMem)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 6, 1, PhaFormatUInt64(dotNetPerfGC.cProcessID, FALSE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 7, 1, FormatByteValue(Context, dotNetPerfGC.cGenHeapSize[0])->Buffer);
PhSetListViewSubItem(Context->CountersLv, 8, 1, FormatByteValue(Context, dotNetPerfGC.cGenHeapSize[1])->Buffer);
PhSetListViewSubItem(Context->CountersLv, 9, 1, FormatByteValue(Context, dotNetPerfGC.cGenHeapSize[2])->Buffer);
PhSetListViewSubItem(Context->CountersLv, 10, 1, FormatByteValue(Context, dotNetPerfGC.cLrgObjSize)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 11, 1, PhaFormatUInt64(dotNetPerfGC.cSurviveFinalize, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 12, 1, PhaFormatUInt64(dotNetPerfGC.cHandles, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 13, 1, PhaFormatUInt64(dotNetPerfGC.cInducedGCs, TRUE)->Buffer);
if (dotNetPerfGC.timeInGCBase != 0)
{
PH_FORMAT format;
WCHAR formatBuffer[10];
PhInitFormatF(&format, (FLOAT)dotNetPerfGC.timeInGC * 100 / (FLOAT)dotNetPerfGC.timeInGCBase, 2);
if (PhFormatToBuffer(&format, 1, formatBuffer, sizeof(formatBuffer), NULL))
PhSetListViewSubItem(Context->CountersLv, 14, 1, formatBuffer);
}
else
{
PhSetListViewSubItem(Context->CountersLv, 14, 1, L"0.00");
}
// The CLR source says this value should be "Gen 0 Heap Size; Gen 1 Heap Size; Gen 2 Heap Size and the Large Object Heap Size",
// but Perflib only counts Gen 1, Gen 2 and cLrgObjSize... For now, just do what perflib does.
PhSetListViewSubItem(Context->CountersLv, 15, 1, FormatByteValue(Context, dotNetPerfGC.cGenHeapSize[1] + dotNetPerfGC.cGenHeapSize[2] + dotNetPerfGC.cLrgObjSize)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 16, 1, FormatByteValue(Context, dotNetPerfGC.cTotalCommittedBytes)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 17, 1, FormatByteValue(Context, dotNetPerfGC.cTotalReservedBytes)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 18, 1, PhaFormatUInt64(dotNetPerfGC.cPinnedObj, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 19, 1, PhaFormatUInt64(dotNetPerfGC.cSinkBlocks, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 20, 1, FormatByteValue(Context, dotNetPerfGC.cbAlloc)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 21, 1, FormatByteValue(Context, dotNetPerfGC.cbLargeAlloc)->Buffer);
}
break;
case DOTNET_CATEGORY_REMOTING:
{
PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfContext.cRemoteCalls.Total, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfContext.cChannels, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfContext.cProxies, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfContext.cClasses, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 4, 1, PhaFormatUInt64(dotNetPerfContext.cContexts, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 5, 1, PhaFormatUInt64(dotNetPerfContext.cObjAlloc, TRUE)->Buffer);
}
break;
case DOTNET_CATEGORY_SECURITY:
{
PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfSecurity.cTotalRTChecks, TRUE)->Buffer);
PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfSecurity.cLinkChecks, TRUE)->Buffer);
if (dotNetPerfSecurity.timeRTchecksBase != 0)
{
PH_FORMAT format;
WCHAR formatBuffer[10];
PhInitFormatF(&format, (FLOAT)dotNetPerfSecurity.timeRTchecks * 100 / (FLOAT)dotNetPerfSecurity.timeRTchecksBase, 2);
if (PhFormatToBuffer(&format, 1, formatBuffer, sizeof(formatBuffer), NULL))
PhSetListViewSubItem(Context->CountersLv, 2, 1, formatBuffer);
}
else
{
PhSetListViewSubItem(Context->CountersLv, 2, 1, L"0.00");
}
PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfSecurity.stackWalkDepth, TRUE)->Buffer);
}
break;
}
}
INT_PTR CALLBACK DotNetPerfPageDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
LPPROPSHEETPAGE propSheetPage;
PPH_PROCESS_PROPPAGECONTEXT propPageContext;
PPH_PROCESS_ITEM processItem;
PPERFPAGE_CONTEXT context;
if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem))
{
context = propPageContext->Context;
}
else
{
return FALSE;
}
switch (uMsg)
{
case WM_INITDIALOG:
{
context = PhAllocate(sizeof(PERFPAGE_CONTEXT));
memset(context, 0, sizeof(PERFPAGE_CONTEXT));
propPageContext->Context = context;
context->WindowHandle = hwndDlg;
context->ProcessItem = processItem;
context->Enabled = TRUE;
context->AppDomainsLv = GetDlgItem(hwndDlg, IDC_APPDOMAINS);
context->CountersLv = GetDlgItem(hwndDlg, IDC_COUNTERS);
context->CategoriesCb = GetDlgItem(hwndDlg, IDC_CATEGORIES);
PhSetListViewStyle(context->AppDomainsLv, FALSE, TRUE);
PhSetControlTheme(context->AppDomainsLv, L"explorer");
PhAddListViewColumn(context->AppDomainsLv, 0, 0, 0, LVCFMT_LEFT, 300, L"Application domain");
PhSetListViewStyle(context->CountersLv, FALSE, TRUE);
PhSetControlTheme(context->CountersLv, L"explorer");
PhAddListViewColumn(context->CountersLv, 0, 0, 0, LVCFMT_LEFT, 250, L"Counter");
PhAddListViewColumn(context->CountersLv, 1, 1, 1, LVCFMT_RIGHT, 140, L"Value");
PhLoadListViewColumnsFromSetting(SETTING_NAME_DOT_NET_COUNTERS_COLUMNS, context->CountersLv);
if (PhGetIntegerSetting(SETTING_NAME_DOT_NET_SHOW_BYTE_SIZE))
{
context->ShowByteSize = TRUE;
Button_SetCheck(GetDlgItem(hwndDlg, IDC_DOTNET_PERF_SHOWBYTES), TRUE);
}
PhAddComboBoxStrings(context->CategoriesCb, DotNetCategoryStrings, ARRAYSIZE(DotNetCategoryStrings));
context->CategoryIndex = PhGetIntegerSetting(SETTING_NAME_DOT_NET_CATEGORY_INDEX);
ComboBox_SetCurSel(context->CategoriesCb, context->CategoryIndex);
#ifdef _WIN64
context->IsWow64 = !!context->ProcessItem->IsWow64;
#else
// HACK: Work-around for Appdomain enumeration on 32bit.
context->IsWow64 = TRUE;
#endif
if (NT_SUCCESS(PhOpenProcess(
&context->ProcessHandle,
PROCESS_VM_READ | ProcessQueryAccess | PROCESS_DUP_HANDLE | SYNCHRONIZE,
context->ProcessItem->ProcessId
)))
{
ULONG flags = 0;
if (NT_SUCCESS(PhGetProcessIsDotNetEx(
context->ProcessItem->ProcessId,
context->ProcessHandle,
context->ProcessItem->IsImmersive == 1 ? 0 : PH_CLR_USE_SECTION_CHECK,
NULL,
&flags
)))
{
if (flags & PH_CLR_VERSION_4_ABOVE)
{
context->ClrV4 = TRUE;
}
}
// Skip AppDomain enumeration of 'Modern' .NET applications as they don't expose the CLR 'Private IPC' block.
if (!context->ProcessItem->IsImmersive)
{
AddProcessAppDomains(hwndDlg, context);
}
}
if (context->ClrV4)
{
if (OpenDotNetPublicControlBlock_V4(
!!context->ProcessItem->IsImmersive,
context->ProcessHandle,
context->ProcessItem->ProcessId,
&context->BlockTableHandle,
&context->BlockTableAddress
))
{
context->ControlBlockValid = TRUE;
}
}
else
{
if (OpenDotNetPublicControlBlock_V2(
context->ProcessItem->ProcessId,
&context->BlockTableHandle,
&context->BlockTableAddress
))
{
context->ControlBlockValid = TRUE;
}
}
if (context->ControlBlockValid)
{
UpdateCategoryValues(hwndDlg, context);
UpdateCounterData(hwndDlg, context);
}
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackProcessesUpdated),
ProcessesUpdatedCallback,
context,
&context->ProcessesUpdatedCallbackRegistration
);
}
break;
case WM_DESTROY:
{
PhUnregisterCallback(
PhGetGeneralCallback(GeneralCallbackProcessesUpdated),
&context->ProcessesUpdatedCallbackRegistration
);
if (context->BlockTableAddress)
{
NtUnmapViewOfSection(NtCurrentProcess(), context->BlockTableAddress);
}
if (context->BlockTableHandle)
{
NtClose(context->BlockTableHandle);
}
if (context->ProcessHandle)
{
NtClose(context->ProcessHandle);
}
PhSaveListViewColumnsToSetting(SETTING_NAME_DOT_NET_COUNTERS_COLUMNS, context->CountersLv);
PhFree(context);
PhPropPageDlgProcDestroy(hwndDlg);
}
break;
case WM_SHOWWINDOW:
{
PPH_LAYOUT_ITEM dialogItem;
if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext))
{
PhAddPropPageLayoutItem(hwndDlg, context->AppDomainsLv, dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
PhAddPropPageLayoutItem(hwndDlg, context->CategoriesCb, dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
PhAddPropPageLayoutItem(hwndDlg, context->CountersLv, dialogItem, PH_ANCHOR_ALL);
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_DOTNET_PERF_SHOWBYTES), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM);
PhEndPropPageLayout(hwndDlg, propPageContext);
}
}
break;
case WM_COMMAND:
{
switch (GET_WM_COMMAND_ID(wParam, lParam))
{
case IDC_CATEGORIES:
{
if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE)
{
context->CategoryIndex = ComboBox_GetCurSel(context->CategoriesCb);
PhSetIntegerSetting(SETTING_NAME_DOT_NET_CATEGORY_INDEX, context->CategoryIndex);
if (context->ControlBlockValid)
{
UpdateCategoryValues(hwndDlg, context);
UpdateCounterData(hwndDlg, context);
}
}
}
break;
case IDC_DOTNET_PERF_SHOWBYTES:
{
if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED)
{
context->ShowByteSize = !context->ShowByteSize;
PhSetIntegerSetting(SETTING_NAME_DOT_NET_SHOW_BYTE_SIZE, context->ShowByteSize);
if (context->ControlBlockValid)
{
UpdateCategoryValues(hwndDlg, context);
UpdateCounterData(hwndDlg, context);
}
}
}
break;
}
}
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;
}
PhHandleListViewNotifyForCopy(lParam, context->AppDomainsLv);
PhHandleListViewNotifyForCopy(lParam, context->CountersLv);
}
break;
case MSG_UPDATE:
{
if (context->Enabled && context->ControlBlockValid)
{
UpdateCounterData(hwndDlg, context);
}
}
break;
}
return FALSE;
}
VOID AddPerfPageToPropContext(
_In_ PPH_PLUGIN_PROCESS_PROPCONTEXT PropContext
)
{
PhAddProcessPropPage(
PropContext->PropContext,
PhCreateProcessPropPageContextEx(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_PROCDOTNETPERF), DotNetPerfPageDlgProc, NULL)
);
}

View File

@@ -0,0 +1,26 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by DotNetTools.rc
//
#define IDD_PROCDOTNETPERF 101
#define ID_COPY 101
#define IDD_PROCDOTNETASM 102
#define IDR_ASSEMBLY_MENU 104
#define IDC_APPDOMAINS 1001
#define IDC_CATEGORIES 1002
#define IDC_COUNTERS 1003
#define IDC_LIST 1005
#define IDC_DOTNET_PERF_SHOWBYTES 1006
#define ID_CLR_OPENFILELOCATION 40001
#define ID_CLR_COPY 40002
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 105
#define _APS_NEXT_COMMAND_VALUE 40003
#define _APS_NEXT_CONTROL_VALUE 1007
#define _APS_NEXT_SYMED_VALUE 102
#endif
#endif

View File

@@ -0,0 +1,321 @@
/*
* Process Hacker .NET Tools -
* thread stack extensions
*
* 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 "dn.h"
#include "clrsup.h"
#include "svcext.h"
#include <symprv.h>
typedef struct _THREAD_STACK_CONTEXT
{
PCLR_PROCESS_SUPPORT Support;
HANDLE ProcessId;
HANDLE ThreadId;
HANDLE ThreadHandle;
PVOID PredictedEip;
PVOID PredictedEbp;
PVOID PredictedEsp;
#ifdef _WIN64
BOOLEAN IsWow64;
BOOLEAN ConnectedToPhSvc;
#endif
} THREAD_STACK_CONTEXT, *PTHREAD_STACK_CONTEXT;
static PPH_HASHTABLE ContextHashtable;
static PH_QUEUED_LOCK ContextHashtableLock = PH_QUEUED_LOCK_INIT;
static PH_INITONCE ContextHashtableInitOnce = PH_INITONCE_INIT;
PTHREAD_STACK_CONTEXT FindThreadStackContext(
_In_ PVOID UniqueKey
)
{
PTHREAD_STACK_CONTEXT context;
PVOID *item;
PhAcquireQueuedLockExclusive(&ContextHashtableLock);
item = PhFindItemSimpleHashtable(ContextHashtable, UniqueKey);
if (item)
context = *item;
else
context = NULL;
PhReleaseQueuedLockExclusive(&ContextHashtableLock);
return context;
}
VOID ProcessThreadStackControl(
_In_ PPH_PLUGIN_THREAD_STACK_CONTROL Control
)
{
if (PhBeginInitOnce(&ContextHashtableInitOnce))
{
ContextHashtable = PhCreateSimpleHashtable(4);
PhEndInitOnce(&ContextHashtableInitOnce);
}
switch (Control->Type)
{
case PluginThreadStackInitializing:
{
PTHREAD_STACK_CONTEXT context;
#if _WIN64
HANDLE processHandle;
#endif
context = PhAllocate(sizeof(THREAD_STACK_CONTEXT));
memset(context, 0, sizeof(THREAD_STACK_CONTEXT));
context->ProcessId = Control->u.Initializing.ProcessId;
context->ThreadId = Control->u.Initializing.ThreadId;
context->ThreadHandle = Control->u.Initializing.ThreadHandle;
#if _WIN64
if (NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess, Control->u.Initializing.ProcessId)))
{
PhGetProcessIsWow64(processHandle, &context->IsWow64);
NtClose(processHandle);
}
#endif
PhAcquireQueuedLockExclusive(&ContextHashtableLock);
PhAddItemSimpleHashtable(ContextHashtable, Control->UniqueKey, context);
PhReleaseQueuedLockExclusive(&ContextHashtableLock);
}
break;
case PluginThreadStackUninitializing:
{
PTHREAD_STACK_CONTEXT context = FindThreadStackContext(Control->UniqueKey);
if (!context)
return;
PhFree(context);
PhAcquireQueuedLockExclusive(&ContextHashtableLock);
PhRemoveItemSimpleHashtable(ContextHashtable, Control->UniqueKey);
PhReleaseQueuedLockExclusive(&ContextHashtableLock);
}
break;
case PluginThreadStackResolveSymbol:
{
PTHREAD_STACK_CONTEXT context = FindThreadStackContext(Control->UniqueKey);
PPH_STRING managedSymbol = NULL;
ULONG64 displacement;
if (!context)
return;
if (context->Support)
{
#ifndef _WIN64
PVOID predictedEip;
PVOID predictedEbp;
PVOID predictedEsp;
predictedEip = context->PredictedEip;
predictedEbp = context->PredictedEbp;
predictedEsp = context->PredictedEsp;
PredictAddressesFromClrData(
context->Support,
context->ThreadId,
Control->u.ResolveSymbol.StackFrame->PcAddress,
Control->u.ResolveSymbol.StackFrame->FrameAddress,
Control->u.ResolveSymbol.StackFrame->StackAddress,
&context->PredictedEip,
&context->PredictedEbp,
&context->PredictedEsp
);
// Fix up dbghelp EBP with real EBP given by the CLR data routines.
if (Control->u.ResolveSymbol.StackFrame->PcAddress == predictedEip)
{
Control->u.ResolveSymbol.StackFrame->FrameAddress = predictedEbp;
Control->u.ResolveSymbol.StackFrame->StackAddress = predictedEsp;
}
#endif
managedSymbol = GetRuntimeNameByAddressClrProcess(
context->Support,
(ULONG64)Control->u.ResolveSymbol.StackFrame->PcAddress,
&displacement
);
}
#ifdef _WIN64
else if (context->IsWow64 && context->ConnectedToPhSvc)
{
PVOID predictedEip;
PVOID predictedEbp;
PVOID predictedEsp;
predictedEip = context->PredictedEip;
predictedEbp = context->PredictedEbp;
predictedEsp = context->PredictedEsp;
CallPredictAddressesFromClrData(
context->ProcessId,
context->ThreadId,
Control->u.ResolveSymbol.StackFrame->PcAddress,
Control->u.ResolveSymbol.StackFrame->FrameAddress,
Control->u.ResolveSymbol.StackFrame->StackAddress,
&context->PredictedEip,
&context->PredictedEbp,
&context->PredictedEsp
);
// Fix up dbghelp EBP with real EBP given by the CLR data routines.
if (Control->u.ResolveSymbol.StackFrame->PcAddress == predictedEip)
{
Control->u.ResolveSymbol.StackFrame->FrameAddress = predictedEbp;
Control->u.ResolveSymbol.StackFrame->StackAddress = predictedEsp;
}
managedSymbol = CallGetRuntimeNameByAddress(
context->ProcessId,
(ULONG64)Control->u.ResolveSymbol.StackFrame->PcAddress,
&displacement
);
}
#endif
if (managedSymbol)
{
if (displacement != 0)
PhMoveReference(&managedSymbol, PhFormatString(L"%s + 0x%I64x", managedSymbol->Buffer, displacement));
if (Control->u.ResolveSymbol.Symbol)
PhMoveReference(&managedSymbol, PhFormatString(L"%s <-- %s", managedSymbol->Buffer, Control->u.ResolveSymbol.Symbol->Buffer));
PhMoveReference(&Control->u.ResolveSymbol.Symbol, managedSymbol);
}
}
break;
case PluginThreadStackBeginDefaultWalkStack:
{
PTHREAD_STACK_CONTEXT context = FindThreadStackContext(Control->UniqueKey);
BOOLEAN isDotNet;
if (!context)
return;
if (!NT_SUCCESS(PhGetProcessIsDotNet(context->ProcessId, &isDotNet)) || !isDotNet)
return;
context->Support = CreateClrProcessSupport(context->ProcessId);
#ifdef _WIN64
if (context->IsWow64)
context->ConnectedToPhSvc = PhUiConnectToPhSvcEx(NULL, Wow64PhSvcMode, FALSE);
#endif
}
break;
case PluginThreadStackEndDefaultWalkStack:
{
PTHREAD_STACK_CONTEXT context = FindThreadStackContext(Control->UniqueKey);
if (!context)
return;
if (context->Support)
{
FreeClrProcessSupport(context->Support);
context->Support = NULL;
}
#ifdef _WIN64
if (context->ConnectedToPhSvc)
{
PhUiDisconnectFromPhSvc();
context->ConnectedToPhSvc = FALSE;
}
#endif
}
break;
}
}
VOID PredictAddressesFromClrData(
_In_ PCLR_PROCESS_SUPPORT Support,
_In_ HANDLE ThreadId,
_In_ PVOID PcAddress,
_In_ PVOID FrameAddress,
_In_ PVOID StackAddress,
_Out_ PVOID *PredictedEip,
_Out_ PVOID *PredictedEbp,
_Out_ PVOID *PredictedEsp
)
{
#ifdef _WIN64
*PredictedEip = NULL;
*PredictedEbp = NULL;
*PredictedEsp = NULL;
#else
IXCLRDataTask *task;
*PredictedEip = NULL;
*PredictedEbp = NULL;
*PredictedEsp = NULL;
if (SUCCEEDED(IXCLRDataProcess_GetTaskByOSThreadID(
Support->DataProcess,
HandleToUlong(ThreadId),
&task
)))
{
IXCLRDataStackWalk *stackWalk;
if (SUCCEEDED(IXCLRDataTask_CreateStackWalk(task, 0xf, &stackWalk)))
{
HRESULT result;
BOOLEAN firstTime = TRUE;
CONTEXT context;
ULONG contextSize;
memset(&context, 0, sizeof(CONTEXT));
context.ContextFlags = CONTEXT_CONTROL;
context.Eip = PtrToUlong(PcAddress);
context.Ebp = PtrToUlong(FrameAddress);
context.Esp = PtrToUlong(StackAddress);
result = IXCLRDataStackWalk_SetContext2(stackWalk, CLRDATA_STACK_SET_CURRENT_CONTEXT, sizeof(CONTEXT), (BYTE *)&context);
if (SUCCEEDED(result = IXCLRDataStackWalk_Next(stackWalk)) && result != S_FALSE)
{
if (SUCCEEDED(IXCLRDataStackWalk_GetContext(stackWalk, CONTEXT_CONTROL, sizeof(CONTEXT), &contextSize, (BYTE *)&context)))
{
*PredictedEip = UlongToPtr(context.Eip);
*PredictedEbp = UlongToPtr(context.Ebp);
*PredictedEsp = UlongToPtr(context.Esp);
}
}
IXCLRDataStackWalk_Release(stackWalk);
}
IXCLRDataTask_Release(task);
}
#endif
}

View File

@@ -0,0 +1,209 @@
/*
* Process Hacker .NET Tools -
* phsvc extensions
*
* 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 "dn.h"
#include "svcext.h"
#include "clrsup.h"
PPH_STRING CallGetRuntimeNameByAddress(
_In_ HANDLE ProcessId,
_In_ ULONG64 Address,
_Out_opt_ PULONG64 Displacement
)
{
NTSTATUS status;
PH_PLUGIN_PHSVC_CLIENT client;
DN_API_GETRUNTIMENAMEBYADDRESS in;
DN_API_GETRUNTIMENAMEBYADDRESS out;
ULONG bufferSize;
PVOID buffer;
PPH_STRING name = NULL;
if (!PhPluginQueryPhSvc(&client))
return NULL;
in.i.ProcessId = HandleToUlong(ProcessId);
in.i.Address = Address;
bufferSize = 0x1000;
if (!(buffer = client.CreateString(NULL, bufferSize, &in.i.Name)))
return NULL;
status = PhPluginCallPhSvc(PluginInstance, DnGetRuntimeNameByAddressApiNumber, &in, sizeof(in), &out, sizeof(out));
if (status == STATUS_BUFFER_OVERFLOW)
{
client.FreeHeap(buffer);
bufferSize = out.o.NameLength;
if (!(buffer = client.CreateString(NULL, bufferSize, &in.i.Name)))
return NULL;
status = PhPluginCallPhSvc(PluginInstance, DnGetRuntimeNameByAddressApiNumber, &in, sizeof(in), &out, sizeof(out));
}
if (NT_SUCCESS(status))
{
name = PhCreateStringEx(buffer, out.o.NameLength);
if (Displacement)
*Displacement = out.o.Displacement;
}
client.FreeHeap(buffer);
return name;
}
NTSTATUS DispatchGetRuntimeNameByAddress(
_In_ PPH_PLUGIN_PHSVC_REQUEST Request,
_In_ PDN_API_GETRUNTIMENAMEBYADDRESS In,
_Out_ PDN_API_GETRUNTIMENAMEBYADDRESS Out
)
{
NTSTATUS status = STATUS_SUCCESS;
PVOID nameBuffer;
PCLR_PROCESS_SUPPORT support;
PPH_STRING name;
if (!NT_SUCCESS(status = Request->ProbeBuffer(&In->i.Name, sizeof(WCHAR), FALSE, &nameBuffer)))
return status;
support = CreateClrProcessSupport(UlongToHandle(In->i.ProcessId));
if (!support)
return STATUS_UNSUCCESSFUL;
name = GetRuntimeNameByAddressClrProcess(support, In->i.Address, &Out->o.Displacement);
if (!name)
{
status = STATUS_UNSUCCESSFUL;
goto CleanupExit;
}
memcpy(nameBuffer, name->Buffer, min(name->Length, In->i.Name.Length));
Out->o.NameLength = (ULONG)name->Length;
if (In->i.Name.Length < name->Length)
status = STATUS_BUFFER_OVERFLOW;
CleanupExit:
FreeClrProcessSupport(support);
return status;
}
VOID CallPredictAddressesFromClrData(
_In_ HANDLE ProcessId,
_In_ HANDLE ThreadId,
_In_ PVOID PcAddress,
_In_ PVOID FrameAddress,
_In_ PVOID StackAddress,
_Out_ PVOID *PredictedEip,
_Out_ PVOID *PredictedEbp,
_Out_ PVOID *PredictedEsp
)
{
PH_PLUGIN_PHSVC_CLIENT client;
DN_API_PREDICTADDRESSESFROMCLRDATA in;
DN_API_PREDICTADDRESSESFROMCLRDATA out;
*PredictedEip = NULL;
*PredictedEbp = NULL;
*PredictedEsp = NULL;
if (!PhPluginQueryPhSvc(&client))
return;
in.i.ProcessId = HandleToUlong(ProcessId);
in.i.ThreadId = HandleToUlong(ThreadId);
in.i.PcAddress = PtrToUlong(PcAddress);
in.i.FrameAddress = PtrToUlong(FrameAddress);
in.i.StackAddress = PtrToUlong(StackAddress);
if (NT_SUCCESS(PhPluginCallPhSvc(PluginInstance, DnPredictAddressesFromClrDataApiNumber, &in, sizeof(in), &out, sizeof(out))))
{
*PredictedEip = UlongToPtr(out.o.PredictedEip);
*PredictedEbp = UlongToPtr(out.o.PredictedEbp);
*PredictedEsp = UlongToPtr(out.o.PredictedEsp);
}
}
NTSTATUS DispatchPredictAddressesFromClrData(
_In_ PPH_PLUGIN_PHSVC_REQUEST Request,
_In_ PDN_API_PREDICTADDRESSESFROMCLRDATA In,
_Out_ PDN_API_PREDICTADDRESSESFROMCLRDATA Out
)
{
PCLR_PROCESS_SUPPORT support;
PVOID predictedEip;
PVOID predictedEbp;
PVOID predictedEsp;
support = CreateClrProcessSupport(UlongToHandle(In->i.ProcessId));
if (!support)
return STATUS_UNSUCCESSFUL;
PredictAddressesFromClrData(
support,
UlongToHandle(In->i.ThreadId),
UlongToPtr(In->i.PcAddress),
UlongToPtr(In->i.FrameAddress),
UlongToPtr(In->i.StackAddress),
&predictedEip,
&predictedEbp,
&predictedEsp
);
FreeClrProcessSupport(support);
Out->o.PredictedEip = PtrToUlong(predictedEip);
Out->o.PredictedEbp = PtrToUlong(predictedEbp);
Out->o.PredictedEsp = PtrToUlong(predictedEsp);
return STATUS_SUCCESS;
}
VOID DispatchPhSvcRequest(
_In_ PVOID Parameter
)
{
PPH_PLUGIN_PHSVC_REQUEST request = Parameter;
PVOID inBuffer;
// InBuffer can alias OutBuffer, so make a copy of InBuffer.
inBuffer = PhAllocateCopy(request->InBuffer, request->InLength);
switch (request->SubId)
{
case DnGetRuntimeNameByAddressApiNumber:
request->ReturnStatus = DispatchGetRuntimeNameByAddress(request, inBuffer, request->OutBuffer);
break;
case DnPredictAddressesFromClrDataApiNumber:
request->ReturnStatus = DispatchPredictAddressesFromClrData(request, inBuffer, request->OutBuffer);
break;
}
PhFree(inBuffer);
}

View File

@@ -0,0 +1,87 @@
/*
* Process Hacker .NET Tools -
* phsvc extensions
*
* 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/>.
*/
#ifndef SVCEXT_H
#define SVCEXT_H
// API
typedef enum _DN_API_NUMBER
{
DnGetRuntimeNameByAddressApiNumber = 1,
DnPredictAddressesFromClrDataApiNumber = 2
} DN_API_NUMBER;
typedef union _DN_API_GETRUNTIMENAMEBYADDRESS
{
struct
{
ULONG ProcessId;
ULONG Reserved;
ULONG64 Address;
PH_RELATIVE_STRINGREF Name; // out
} i;
struct
{
ULONG64 Displacement;
ULONG NameLength;
} o;
} DN_API_GETRUNTIMENAMEBYADDRESS, *PDN_API_GETRUNTIMENAMEBYADDRESS;
typedef union _DN_API_PREDICTADDRESSESFROMCLRDATA
{
struct
{
ULONG ProcessId;
ULONG ThreadId;
ULONG PcAddress;
ULONG FrameAddress;
ULONG StackAddress;
} i;
struct
{
ULONG PredictedEip;
ULONG PredictedEbp;
ULONG PredictedEsp;
} o;
} DN_API_PREDICTADDRESSESFROMCLRDATA, *PDN_API_PREDICTADDRESSESFROMCLRDATA;
// Calls
PPH_STRING CallGetRuntimeNameByAddress(
_In_ HANDLE ProcessId,
_In_ ULONG64 Address,
_Out_opt_ PULONG64 Displacement
);
VOID CallPredictAddressesFromClrData(
_In_ HANDLE ProcessId,
_In_ HANDLE ThreadId,
_In_ PVOID PcAddress,
_In_ PVOID FrameAddress,
_In_ PVOID StackAddress,
_Out_ PVOID *PredictedEip,
_Out_ PVOID *PredictedEbp,
_Out_ PVOID *PredictedEsp
);
#endif

View File

@@ -0,0 +1,296 @@
/*
* Process Hacker .NET Tools -
* thread list extensions
*
* 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 "dn.h"
#include "clrsup.h"
VOID NTAPI ThreadsContextCreateCallback(
_In_ PVOID Object,
_In_ PH_EM_OBJECT_TYPE ObjectType,
_In_ PVOID Extension
);
VOID NTAPI ThreadsContextDeleteCallback(
_In_ PVOID Object,
_In_ PH_EM_OBJECT_TYPE ObjectType,
_In_ PVOID Extension
);
VOID ThreadTreeNewMessage(
_In_ PVOID Parameter
);
LONG ThreadTreeNewSortFunction(
_In_ PVOID Node1,
_In_ PVOID Node2,
_In_ ULONG SubId,
_In_ PVOID Context
);
#define THREAD_TREE_CONTEXT_TYPE 1
typedef struct _THREAD_TREE_CONTEXT
{
ULONG Type;
HANDLE ProcessId;
PH_CALLBACK_REGISTRATION AddedCallbackRegistration;
PCLR_PROCESS_SUPPORT Support;
} THREAD_TREE_CONTEXT, *PTHREAD_TREE_CONTEXT;
static PPH_HASHTABLE ContextHashtable;
static PH_QUEUED_LOCK ContextHashtableLock = PH_QUEUED_LOCK_INIT;
static PH_INITONCE ContextHashtableInitOnce = PH_INITONCE_INIT;
VOID InitializeTreeNewObjectExtensions(
VOID
)
{
PhPluginSetObjectExtension(
PluginInstance,
EmThreadsContextType,
sizeof(THREAD_TREE_CONTEXT),
ThreadsContextCreateCallback,
ThreadsContextDeleteCallback
);
}
VOID AddTreeNewColumn(
_In_ PPH_PLUGIN_TREENEW_INFORMATION TreeNewInfo,
_In_ PVOID Context,
_In_ ULONG SubId,
_In_ BOOLEAN Visible,
_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.Visible = Visible;
column.SortDescending = SortDescending;
column.Text = Text;
column.Width = Width;
column.Alignment = Alignment;
column.DisplayIndex = TreeNew_GetVisibleColumnCount(TreeNewInfo->TreeNewHandle);
column.TextFlags = TextFlags;
PhPluginAddTreeNewColumn(
PluginInstance,
TreeNewInfo->CmData,
&column,
SubId,
Context,
SortFunction
);
}
VOID DispatchTreeNewMessage(
_In_ PVOID Parameter
)
{
PPH_PLUGIN_TREENEW_MESSAGE message = Parameter;
switch (*(PULONG)message->Context)
{
case THREAD_TREE_CONTEXT_TYPE:
ThreadTreeNewMessage(Parameter);
break;
}
}
static VOID ThreadAddedHandler(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_THREAD_ITEM threadItem = Parameter;
PDN_THREAD_ITEM dnThread;
PTHREAD_TREE_CONTEXT context = Context;
dnThread = PhPluginGetObjectExtension(PluginInstance, threadItem, EmThreadItemType);
memset(dnThread, 0, sizeof(DN_THREAD_ITEM));
dnThread->ThreadItem = threadItem;
}
VOID NTAPI ThreadsContextCreateCallback(
_In_ PVOID Object,
_In_ PH_EM_OBJECT_TYPE ObjectType,
_In_ PVOID Extension
)
{
PPH_THREADS_CONTEXT threadsContext = Object;
PTHREAD_TREE_CONTEXT context = Extension;
memset(context, 0, sizeof(THREAD_TREE_CONTEXT));
context->Type = THREAD_TREE_CONTEXT_TYPE;
context->ProcessId = threadsContext->Provider->ProcessId;
PhRegisterCallback(
&threadsContext->Provider->ThreadAddedEvent,
ThreadAddedHandler,
context,
&context->AddedCallbackRegistration
);
}
VOID NTAPI ThreadsContextDeleteCallback(
_In_ PVOID Object,
_In_ PH_EM_OBJECT_TYPE ObjectType,
_In_ PVOID Extension
)
{
PPH_THREADS_CONTEXT threadsContext = Object;
PTHREAD_TREE_CONTEXT context = Extension;
PhUnregisterCallback(
&threadsContext->Provider->ThreadAddedEvent,
&context->AddedCallbackRegistration
);
if (context->Support)
FreeClrProcessSupport(context->Support);
}
VOID ThreadTreeNewInitializing(
_In_ PVOID Parameter
)
{
PPH_PLUGIN_TREENEW_INFORMATION info = Parameter;
PPH_THREADS_CONTEXT threadsContext;
PTHREAD_TREE_CONTEXT context;
BOOLEAN isDotNet;
threadsContext = info->SystemContext;
context = PhPluginGetObjectExtension(PluginInstance, threadsContext, EmThreadsContextType);
if (NT_SUCCESS(PhGetProcessIsDotNet(threadsContext->Provider->ProcessId, &isDotNet)) && isDotNet)
{
PCLR_PROCESS_SUPPORT support;
support = CreateClrProcessSupport(threadsContext->Provider->ProcessId);
if (!support)
return;
context->Support = support;
AddTreeNewColumn(info, context, DNTHTNC_APPDOMAIN, TRUE, L"AppDomain", 120, PH_ALIGN_LEFT, 0, FALSE, ThreadTreeNewSortFunction);
}
}
VOID ThreadTreeNewUninitializing(
_In_ PVOID Parameter
)
{
NOTHING;
}
VOID UpdateThreadClrData(
_In_ PTHREAD_TREE_CONTEXT Context,
_Inout_ PDN_THREAD_ITEM DnThread
)
{
if (!DnThread->ClrDataValid)
{
IXCLRDataProcess *process;
IXCLRDataTask *task;
IXCLRDataAppDomain *appDomain;
if (Context->Support)
process = Context->Support->DataProcess;
else
return;
if (SUCCEEDED(IXCLRDataProcess_GetTaskByOSThreadID(process, HandleToUlong(DnThread->ThreadItem->ThreadId), &task)))
{
if (SUCCEEDED(IXCLRDataTask_GetCurrentAppDomain(task, &appDomain)))
{
DnThread->AppDomainText = GetNameXClrDataAppDomain(appDomain);
IXCLRDataAppDomain_Release(appDomain);
}
IXCLRDataTask_Release(task);
}
DnThread->ClrDataValid = TRUE;
}
}
VOID ThreadTreeNewMessage(
_In_ PVOID Parameter
)
{
PPH_PLUGIN_TREENEW_MESSAGE message = Parameter;
PTHREAD_TREE_CONTEXT context = message->Context;
if (message->Message == TreeNewGetCellText)
{
PPH_TREENEW_GET_CELL_TEXT getCellText = message->Parameter1;
PPH_THREAD_NODE threadNode = (PPH_THREAD_NODE)getCellText->Node;
PDN_THREAD_ITEM dnThread;
dnThread = PhPluginGetObjectExtension(PluginInstance, threadNode->ThreadItem, EmThreadItemType);
switch (message->SubId)
{
case DNTHTNC_APPDOMAIN:
UpdateThreadClrData(context, dnThread);
getCellText->Text = PhGetStringRef(dnThread->AppDomainText);
break;
}
}
}
LONG ThreadTreeNewSortFunction(
_In_ PVOID Node1,
_In_ PVOID Node2,
_In_ ULONG SubId,
_In_ PVOID Context
)
{
PTHREAD_TREE_CONTEXT context = Context;
LONG result;
PPH_THREAD_NODE node1 = Node1;
PPH_THREAD_NODE node2 = Node2;
PDN_THREAD_ITEM dnThread1;
PDN_THREAD_ITEM dnThread2;
dnThread1 = PhPluginGetObjectExtension(PluginInstance, node1->ThreadItem, EmThreadItemType);
dnThread2 = PhPluginGetObjectExtension(PluginInstance, node2->ThreadItem, EmThreadItemType);
result = 0;
switch (SubId)
{
case DNTHTNC_APPDOMAIN:
UpdateThreadClrData(context, dnThread1);
UpdateThreadClrData(context, dnThread2);
result = PhCompareStringWithNull(dnThread1->AppDomainText, dnThread2->AppDomainText, TRUE);
break;
}
return result;
}

View File

@@ -0,0 +1,11 @@
1.3
* Added Growl support
1.2
* Added ability to log events to a file
1.1
* Fixed memory leak
1.0
* Initial release

View File

@@ -0,0 +1,214 @@
// 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,3,0,0
PRODUCTVERSION 1,3,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 Notifications for Process Hacker"
VALUE "FileVersion", "1.3"
VALUE "InternalName", "ExtendedNotifications"
VALUE "LegalCopyright", "Licensed under the GNU GPL, v3."
VALUE "OriginalFilename", "ExtendedNotifications.dll"
VALUE "ProductName", "Extended Notifications for Process Hacker"
VALUE "ProductVersion", "1.3"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0xc09, 1200
END
END
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_PROCESSES DIALOGEX 0, 0, 255, 229
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Processes"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "You can configure processes for which notifications are displayed. Wildcards can be used, and ordering is considered.",IDC_STATIC,7,7,241,19
LISTBOX IDC_LIST,7,30,187,118,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "Move up",IDC_MOVEUP,198,30,50,14
PUSHBUTTON "Move down",IDC_MOVEDOWN,198,47,50,14
EDITTEXT IDC_TEXT,7,152,147,12,ES_AUTOHSCROLL
CONTROL "Include",IDC_INCLUDE,"Button",BS_AUTORADIOBUTTON,163,153,39,10
CONTROL "Exclude",IDC_EXCLUDE,"Button",BS_AUTORADIOBUTTON,207,153,41,10
PUSHBUTTON "Add/Update",IDC_ADD,145,168,50,14
PUSHBUTTON "Remove",IDC_REMOVE,198,168,50,14
LTEXT "Examples:\nnote*.exe\nC:\\Windows\\system32\\cmd.exe\nC:\\Windows\\*",IDC_STATIC,7,186,241,36
END
IDD_SERVICES DIALOGEX 0, 0, 255, 229
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 "You can configure services for which notifications are displayed. Wildcards can be used, and ordering is considered.",IDC_STATIC,7,7,241,19
LISTBOX IDC_LIST,7,30,187,118,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "Move up",IDC_MOVEUP,198,30,50,14
PUSHBUTTON "Move down",IDC_MOVEDOWN,198,47,50,14
EDITTEXT IDC_TEXT,7,152,147,12,ES_AUTOHSCROLL
CONTROL "Include",IDC_INCLUDE,"Button",BS_AUTORADIOBUTTON,163,153,39,10
CONTROL "Exclude",IDC_EXCLUDE,"Button",BS_AUTORADIOBUTTON,207,153,41,10
PUSHBUTTON "Add/Update",IDC_ADD,145,168,50,14
PUSHBUTTON "Remove",IDC_REMOVE,198,168,50,14
LTEXT "Examples:\nWdi*\nseclogon",IDC_STATIC,7,186,241,36
END
IDD_LOGGING DIALOGEX 0, 0, 255, 229
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Logging"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
GROUPBOX "File",IDC_STATIC,7,7,241,53
LTEXT "Log all events to this file (leave blank to disable this feature):",IDC_STATIC,13,18,196,8
EDITTEXT IDC_LOGFILENAME,13,29,178,12,ES_AUTOHSCROLL
PUSHBUTTON "Browse...",IDC_BROWSE,194,28,50,14
LTEXT "Changes will require a restart of Process Hacker.",IDC_STATIC,14,45,157,8
END
IDD_GROWL DIALOGEX 0, 0, 255, 229
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Growl"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
CONTROL "Send notifications to Growl",IDC_ENABLEGROWL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,101,10
LTEXT "gntp-send license:",IDC_STATIC,7,23,60,8
EDITTEXT IDC_LICENSE,7,34,241,188,ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL | WS_HSCROLL
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_PROCESSES, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 248
TOPMARGIN, 7
BOTTOMMARGIN, 222
END
IDD_SERVICES, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 248
TOPMARGIN, 7
BOTTOMMARGIN, 222
END
IDD_LOGGING, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 248
TOPMARGIN, 7
BOTTOMMARGIN, 222
END
IDD_GROWL, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 248
TOPMARGIN, 7
BOTTOMMARGIN, 222
END
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// AFX_DIALOG_LAYOUT
//
IDD_GROWL AFX_DIALOG_LAYOUT
BEGIN
0
END
#endif // English (Australia) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@@ -0,0 +1,111 @@
<?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>{80E791B8-AC98-407E-8FF9-5154AF50E887}</ProjectGuid>
<RootNamespace>ExtendedNotifications</RootNamespace>
<Keyword>Win32Proj</Keyword>
<ProjectName>ExtendedNotifications</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>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>ws2_32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Link>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>ws2_32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Link>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>ws2_32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Link>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>ws2_32.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="filelog.c" />
<ClCompile Include="gntp-send\growl.c" />
<ClCompile Include="gntp-send\tcp.c" />
<ClCompile Include="main.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="extnoti.h" />
<ClInclude Include="gntp-send\growl.h" />
<ClInclude Include="gntp-send\md5.h" />
<ClInclude Include="gntp-send\tcp.h" />
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="ExtendedNotifications.rc" />
</ItemGroup>
<ItemGroup>
<None Include="CHANGELOG.txt" />
<None Include="gntp-send\LICENSE.txt" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

View File

@@ -0,0 +1,57 @@
<?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="filelog.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="gntp-send\growl.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="gntp-send\tcp.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="extnoti.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="gntp-send\growl.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="gntp-send\tcp.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="gntp-send\md5.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="ExtendedNotifications.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<None Include="CHANGELOG.txt" />
<None Include="gntp-send\LICENSE.txt" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,30 @@
#ifndef EXTNOTI_H
#define EXTNOTI_H
#define PLUGIN_NAME L"ProcessHacker.ExtendedNotifications"
#define SETTING_NAME_ENABLE_GROWL (PLUGIN_NAME L".EnableGrowl")
#define SETTING_NAME_LOG_FILENAME (PLUGIN_NAME L".LogFileName")
#define SETTING_NAME_PROCESS_LIST (PLUGIN_NAME L".ProcessList")
#define SETTING_NAME_SERVICE_LIST (PLUGIN_NAME L".ServiceList")
// main
typedef enum _FILTER_TYPE
{
FilterInclude,
FilterExclude
} FILTER_TYPE;
typedef struct _FILTER_ENTRY
{
FILTER_TYPE Type;
PPH_STRING Filter;
} FILTER_ENTRY, *PFILTER_ENTRY;
// filelog
VOID FileLogInitialization(
VOID
);
#endif

View File

@@ -0,0 +1,79 @@
/*
* Process Hacker Extended Notifications -
* file logging
*
* 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 <phdk.h>
#include "extnoti.h"
VOID NTAPI LoggedCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
);
PPH_FILE_STREAM LogFileStream = NULL;
PH_CALLBACK_REGISTRATION LoggedCallbackRegistration;
VOID FileLogInitialization(
VOID
)
{
NTSTATUS status;
PPH_STRING fileName;
fileName = PhaGetStringSetting(SETTING_NAME_LOG_FILENAME);
if (fileName->Length != 0)
{
status = PhCreateFileStream(
&LogFileStream,
fileName->Buffer,
FILE_GENERIC_WRITE,
FILE_SHARE_READ,
FILE_OPEN_IF,
PH_FILE_STREAM_APPEND | PH_FILE_STREAM_UNBUFFERED
);
if (NT_SUCCESS(status))
{
PhRegisterCallback(
&PhLoggedCallback,
LoggedCallback,
NULL,
&LoggedCallbackRegistration
);
}
}
}
VOID NTAPI LoggedCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_LOG_ENTRY logEntry = Parameter;
PhWriteStringFormatAsUtf8FileStream(
LogFileStream,
L"%s: %s\r\n",
PhaFormatDateTime(NULL)->Buffer,
PH_AUTO_T(PH_STRING, PhFormatLogEntry(logEntry))->Buffer
);
}

View File

@@ -0,0 +1,26 @@
[The "BSD licence"]
Copyright (c) 2009-2010 Yasuhiro Matsumoto
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,544 @@
#define _CRT_RAND_S
#include <phdk.h>
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "md5.h"
#include "tcp.h"
#include "growl.h"
static const char hex_table[] = "0123456789ABCDEF";
static char* string_to_hex_alloc(const char* str, int len) {
int n, l;
char* tmp = (char*)PhAllocateSafe(len * 2 + 1);
if (tmp) {
memset(tmp, 0, len * 2 + 1);
for (l = 0, n = 0; l < len; l++) {
tmp[n++] = hex_table[(str[l] & 0xF0) >> 4];
tmp[n++] = hex_table[str[l] & 0x0F];
}
}
return tmp;
}
int growl_init_ = 0;
/* dmex: modified to use latest Winsock version */
int growl_init()
{
if (growl_init_ == 0)
{
#ifdef _WIN32
WSADATA wsaData;
if (WSAStartup(WINSOCK_VERSION, &wsaData) != 0)
{
return -1;
}
#endif
growl_init_ = 1;
}
return 1;
}
void growl_shutdown()
{
if (growl_init_ == 1)
{
#ifdef _WIN32
WSACleanup();
#endif
}
}
/* dmex: modified to use a version of rand with security enhancements */
char* gen_salt_alloc(int count)
{
char* salt = (char*)PhAllocateSafe(count + 1);
if (salt)
{
int n;
int randSeed = 0;
rand_s(&randSeed);
for (n = 0; n < count; n++)
salt[n] = (randSeed % 255) + 1;
salt[n] = 0;
}
return salt;
}
char* gen_password_hash_alloc(const char* password, const char* salt) {
md5_context md5ctx;
char md5tmp[20];
char* md5digest;
memset(md5tmp, 0, sizeof(md5tmp));
md5_starts(&md5ctx);
md5_update(&md5ctx, (uint8_t*)password, (uint32_t)strlen(password));
md5_update(&md5ctx, (uint8_t*)salt, (uint32_t)strlen(salt));
md5_finish(&md5ctx, (uint8_t*)md5tmp);
md5_starts(&md5ctx);
md5_update(&md5ctx, (uint8_t*)md5tmp, 16);
md5_finish(&md5ctx, (uint8_t*)md5tmp);
md5digest = string_to_hex_alloc(md5tmp, 16);
return md5digest;
}
char *growl_generate_authheader_alloc(const char*const password)
{
char* salt;
char* salthash;
char* keyhash;
char* authheader = NULL;
if (password) {
salt = gen_salt_alloc(8);
if (salt) {
keyhash = gen_password_hash_alloc(password, salt);
if (keyhash) {
salthash = string_to_hex_alloc(salt, 8);
if (salthash) {
authheader = (char*)PhAllocateSafe(strlen(keyhash) + strlen(salthash) + 7);
if (authheader) {
sprintf(authheader, " MD5:%s.%s", keyhash, salthash);
}
PhFree(salthash);
}
PhFree(keyhash);
}
PhFree(salt);
}
}
return authheader;
}
/* dmex: modified to use INVALID_SOCKET */
int growl_tcp_register( const char *const server , const char *const appname , const char **const notifications , const int notifications_count ,
const char *const password, const char* const icon )
{
SOCKET sock = INVALID_SOCKET;
int i=0;
char *authheader;
char *iconid = NULL;
FILE *iconfile = NULL;
size_t iconsize;
uint8_t buffer[1024];
growl_init();
authheader = growl_generate_authheader_alloc(password);
sock = growl_tcp_open(server);
if (sock == INVALID_SOCKET) goto leave;
if (icon) {
size_t bytes_read;
md5_context md5ctx;
char md5tmp[20];
iconfile = fopen(icon, "rb");
if (iconfile) {
fseek(iconfile, 0, SEEK_END);
iconsize = ftell(iconfile);
fseek(iconfile, 0, SEEK_SET);
memset(md5tmp, 0, sizeof(md5tmp));
md5_starts(&md5ctx);
while (!feof(iconfile)) {
bytes_read = fread(buffer, 1, 1024, iconfile);
if (bytes_read) md5_update(&md5ctx, buffer, (uint32_t)bytes_read);
}
fseek(iconfile, 0, SEEK_SET);
md5_finish(&md5ctx, md5tmp);
iconid = string_to_hex_alloc(md5tmp, 16);
}
}
growl_tcp_write(sock, "GNTP/1.0 REGISTER NONE %s", authheader ? authheader : "");
growl_tcp_write(sock, "Application-Name: %s", appname);
if(iconid)
{
growl_tcp_write(sock, "Application-Icon: x-growl-resource://%s", iconid);
}
else if(icon)
{
growl_tcp_write(sock, "Application-Icon: %s", icon );
}
growl_tcp_write(sock, "Notifications-Count: %d", notifications_count);
growl_tcp_write(sock, "" );
for(i=0;i<notifications_count;i++)
{
growl_tcp_write(sock, "Notification-Name: %s", notifications[i]);
growl_tcp_write(sock, "Notification-Display-Name: %s", notifications[i]);
growl_tcp_write(sock, "Notification-Enabled: True" );
if(iconid)
{
growl_tcp_write(sock, "Notification-Icon: x-growl-resource://%s", iconid);
}
else if(icon)
{
growl_tcp_write(sock, "Notification-Icon: %s", icon );
}
growl_tcp_write(sock, "" );
}
if (iconid)
{
growl_tcp_write(sock, "Identifier: %s", iconid);
growl_tcp_write(sock, "Length: %d", iconsize);
growl_tcp_write(sock, "" );
while (!feof(iconfile))
{
size_t bytes_read = fread(buffer, 1, 1024, iconfile);
if (bytes_read) growl_tcp_write_raw(sock, buffer, (int)bytes_read);
}
growl_tcp_write(sock, "" );
}
growl_tcp_write(sock, "" );
while (1)
{
char* line = growl_tcp_read(sock);
if (!line) {
growl_tcp_close(sock);
sock = INVALID_SOCKET;
goto leave;
}
else
{
int len = (int)strlen(line);
/* fprintf(stderr, "%s\n", line); */
if (strncmp(line, "GNTP/1.0 -ERROR", 15) == 0)
{
if (strncmp(line + 15, " NONE", 5) != 0)
{
fprintf(stderr, "failed to register notification\n");
PhFree(line);
goto leave;
}
}
PhFree(line);
if (len == 0) break;
}
}
growl_tcp_close(sock);
sock = 0;
leave:
if (iconfile) fclose(iconfile);
if (iconid) PhFree(iconid);
if (authheader) PhFree(authheader);
return (sock == 0) ? 0 : INVALID_SOCKET;
}
/* dmex: modified to use INVALID_SOCKET */
int growl_tcp_notify( const char *const server,const char *const appname,const char *const notify,const char *const title, const char *const message ,
const char *const password, const char* const url, const char* const icon)
{
SOCKET sock = INVALID_SOCKET;
char *authheader = growl_generate_authheader_alloc(password);
char *iconid = NULL;
FILE *iconfile = NULL;
size_t iconsize;
uint8_t buffer[1024];
growl_init();
sock = growl_tcp_open(server);
if (sock == INVALID_SOCKET) goto leave;
if (icon)
{
size_t bytes_read;
md5_context md5ctx;
char md5tmp[20];
iconfile = fopen(icon, "rb");
if (iconfile)
{
fseek(iconfile, 0, SEEK_END);
iconsize = ftell(iconfile);
fseek(iconfile, 0, SEEK_SET);
memset(md5tmp, 0, sizeof(md5tmp));
md5_starts(&md5ctx);
while (!feof(iconfile))
{
bytes_read = fread(buffer, 1, 1024, iconfile);
if (bytes_read) md5_update(&md5ctx, buffer, (uint32_t)bytes_read);
}
fseek(iconfile, 0, SEEK_SET);
md5_finish(&md5ctx, md5tmp);
iconid = string_to_hex_alloc(md5tmp, 16);
}
}
growl_tcp_write(sock, "GNTP/1.0 NOTIFY NONE %s", authheader ? authheader : "");
growl_tcp_write(sock, "Application-Name: %s", appname);
growl_tcp_write(sock, "Notification-Name: %s", notify);
growl_tcp_write(sock, "Notification-Title: %s", title);
growl_tcp_write(sock, "Notification-Text: %s", message);
if(iconid)
{
growl_tcp_write(sock, "Notification-Icon: x-growl-resource://%s", iconid);
}
else if(icon)
{
growl_tcp_write(sock, "Notification-Icon: %s", icon );
}
if (url) growl_tcp_write(sock, "Notification-Callback-Target: %s", url );
if (iconid)
{
growl_tcp_write(sock, "Identifier: %s", iconid);
growl_tcp_write(sock, "Length: %d", iconsize);
growl_tcp_write(sock, "");
while (!feof(iconfile))
{
size_t bytes_read = fread(buffer, 1, 1024, iconfile);
if (bytes_read) growl_tcp_write_raw(sock, buffer, (int)bytes_read);
}
growl_tcp_write(sock, "" );
}
growl_tcp_write(sock, "");
while (1)
{
char* line = growl_tcp_read(sock);
if (!line)
{
growl_tcp_close(sock);
sock = INVALID_SOCKET;
goto leave;
} else
{
int len = (int)strlen(line);
/* fprintf(stderr, "%s\n", line); */
if (strncmp(line, "GNTP/1.0 -ERROR", 15) == 0)
{
if (strncmp(line + 15, " NONE", 5) != 0)
{
fprintf(stderr, "failed to post notification\n");
PhFree(line);
goto leave;
}
}
PhFree(line);
if (len == 0) break;
}
}
growl_tcp_close(sock);
sock = 0;
leave:
if (iconfile) fclose(iconfile);
if (iconid) PhFree(iconid);
if (authheader) PhFree(authheader);
return (sock == 0) ? 0 : INVALID_SOCKET;
}
int growl( const char *const server,const char *const appname,const char *const notify,const char *const title, const char *const message ,
const char *const icon , const char *const password , const char *url )
{
int rc = growl_tcp_register( server , appname , (const char **const)&notify , 1 , password, icon );
if( rc == 0 )
{
rc = growl_tcp_notify( server, appname, notify, title, message , password, url, icon );
}
return rc;
}
void growl_append_md5( unsigned char *const data , const int data_length , const char *const password )
{
md5_context md5ctx;
char md5tmp[20];
memset(md5tmp, 0, sizeof(md5tmp));
md5_starts(&md5ctx);
md5_update(&md5ctx, (uint8_t*)data, data_length );
if(password != NULL)
{
md5_update(&md5ctx, (uint8_t*)password, (uint32_t)strlen(password));
}
md5_finish(&md5ctx, (uint8_t*)md5tmp);
memcpy( data + data_length , md5tmp , 16 );
}
int growl_udp_register( const char *const server , const char *const appname , const char **const notifications , const int notifications_count , const char *const password )
{
int register_header_length = 22+(int)strlen(appname);
unsigned char *data;
int pointer = 0;
int rc = 0;
int i=0;
uint8_t GROWL_PROTOCOL_VERSION = 1;
uint8_t GROWL_TYPE_REGISTRATION = 0;
uint16_t appname_length = ntohs((u_short)strlen(appname));
uint8_t _notifications_count = notifications_count;
uint8_t default_notifications_count = notifications_count;
uint8_t j;
growl_init();
for(i=0;i<notifications_count;i++)
{
register_header_length += 3 + (int)strlen(notifications[i]);
}
data = (unsigned char*)PhAllocateSafe(register_header_length);
if (!data) return -1;
memset( data , 0 , register_header_length );
pointer = 0;
memcpy( data + pointer , &GROWL_PROTOCOL_VERSION , 1 );
pointer++;
memcpy( data + pointer , &GROWL_TYPE_REGISTRATION , 1 );
pointer++;
memcpy( data + pointer , &appname_length , 2 );
pointer += 2;
memcpy( data + pointer , &_notifications_count , 1 );
pointer++;
memcpy( data + pointer, &default_notifications_count , 1 );
pointer++;
sprintf( (char*)data + pointer , "%s" , appname );
pointer += (int)strlen(appname);
for(i=0;i<notifications_count;i++)
{
uint16_t notify_length = ntohs((u_short)strlen(notifications[i]));
memcpy( data + pointer, &notify_length , 2 );
pointer +=2;
sprintf( (char*)data + pointer , "%s" , notifications[i] );
pointer += (int)strlen(notifications[i]);
}
for(j=0;j<notifications_count;j++)
{
memcpy( data + pointer , &j , 1 );
pointer++;
}
growl_append_md5( data , pointer , password );
pointer += 16;
rc = growl_tcp_datagram( server , data , pointer );
PhFree(data);
return rc;
}
int growl_udp_notify( const char *const server,const char *const appname,const char *const notify,const char *const title, const char *const message ,
const char *const password )
{
int notify_header_length = 28 + (int)(strlen(appname)+strlen(notify)+strlen(message)+strlen(title));
unsigned char *data = (unsigned char*)PhAllocateSafe(notify_header_length);
int pointer = 0;
int rc = 0;
uint8_t GROWL_PROTOCOL_VERSION = 1;
uint8_t GROWL_TYPE_NOTIFICATION = 1;
uint16_t flags = ntohs(0);
uint16_t appname_length = ntohs((u_short)strlen(appname));
uint16_t notify_length = ntohs((u_short)strlen(notify));
uint16_t title_length = ntohs((u_short)strlen(title));
uint16_t message_length = ntohs((u_short)strlen(message));
if (!data) return -1;
growl_init();
memset( data , 0 , notify_header_length );
pointer = 0;
memcpy( data + pointer , &GROWL_PROTOCOL_VERSION , 1 );
pointer++;
memcpy( data + pointer , &GROWL_TYPE_NOTIFICATION , 1 );
pointer++;
memcpy( data + pointer , &flags , 2 );
pointer += 2;
memcpy( data + pointer , &notify_length , 2 );
pointer += 2;
memcpy( data + pointer , &title_length , 2 );
pointer += 2;
memcpy( data + pointer , &message_length , 2 );
pointer += 2;
memcpy( data + pointer , &appname_length , 2 );
pointer += 2;
strcpy( (char*)data + pointer , notify );
pointer += (int)strlen(notify);
strcpy( (char*)data + pointer , title );
pointer += (int)strlen(title);
strcpy( (char*)data + pointer , message );
pointer += (int)strlen(message);
strcpy( (char*)data + pointer , appname );
pointer += (int)strlen(appname);
growl_append_md5( data , pointer , password );
pointer += 16;
rc = growl_tcp_datagram( server , data , pointer );
PhFree(data);
return rc;
}
int growl_udp( const char *const server,const char *const appname,const char *const notify,const char *const title, const char *const message ,
const char *const icon , const char *const password , const char *url )
{
int rc = growl_udp_register( server , appname , (const char **const)&notify , 1 , password );
if( rc == 0 )
{
rc = growl_udp_notify( server, appname, notify, title, message , password );
}
return rc;
}
char *gntp_send_license_text =
"[The \"BSD licence\"]\r\n"
"Copyright (c) 2009-2010 Yasuhiro Matsumoto\r\n"
"All rights reserved.\r\n"
"\r\n"
"Redistribution and use in source and binary forms, with or without\r\n"
"modification, are permitted provided that the following conditions\r\n"
"are met:\r\n"
"\r\n"
" 1. Redistributions of source code must retain the above copyright\r\n"
" notice, this list of conditions and the following disclaimer.\r\n"
" 2. Redistributions in binary form must reproduce the above copyright\r\n"
" notice, this list of conditions and the following disclaimer in the\r\n"
" documentation and/or other materials provided with the distribution.\r\n"
" 3. The name of the author may not be used to endorse or promote products\r\n"
" derived from this software without specific prior written permission.\r\n"
"\r\n"
"THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\r\n"
"IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r\n"
"OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r\n"
"IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\r\n"
"INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r\n"
"NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r\n"
"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r\n"
"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n"
"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r\n"
"THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n"
;

View File

@@ -0,0 +1,33 @@
#ifndef _GROWL_H_
#define _GROWL_H_
#ifdef __cplusplus
extern "C" {
#endif
int growl( const char *const server,const char *const appname,const char *const notify,const char *const title, const char *const message ,
const char *const icon , const char *const password , const char *url );
int growl_tcp_notify( const char *const server,const char *const appname,const char *const notify,const char *const title, const char *const message ,
const char *const password, const char* const url, const char* const icon );
int growl_tcp_register( const char *const server , const char *const appname , const char **const notifications , const int notifications_count , const char *const password, const char *const icon );
int growl_udp( const char *const server,const char *const appname,const char *const notify,const char *const title, const char *const message ,
const char *const icon , const char *const password , const char *url );
int growl_udp_notify( const char *const server,const char *const appname,const char *const notify,const char *const title, const char *const message ,
const char *const password );
int growl_udp_register( const char *const server , const char *const appname , const char **const notifications , const int notifications_count , const char *const password );
int growl_init(void);
void growl_shutdown(void);
extern char *gntp_send_license_text;
#ifdef __cplusplus
}
#endif
#endif /* _GROWL_H_ */

View File

@@ -0,0 +1,26 @@
#ifndef _MD5_H_
#define _MD5_H_
#include <stdint.h>
typedef struct {
PH_HASH_CONTEXT hc;
} md5_context;
__forceinline void md5_starts(md5_context *ctx)
{
PhInitializeHash(&ctx->hc, Md5HashAlgorithm);
}
__forceinline void md5_update(md5_context *ctx, const uint8_t *input, uint32_t length)
{
PhUpdateHash(&ctx->hc, (PVOID)input, length);
}
__forceinline void md5_finish(md5_context *ctx, uint8_t digest[16])
{
if (!PhFinalHash(&ctx->hc, digest, 16, NULL))
PhRaiseStatus(STATUS_INTERNAL_ERROR);
}
#endif /* _MD5_H_ */

View File

@@ -0,0 +1,185 @@
#include <phdk.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#ifdef _WIN32
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <winsock2.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <unistd.h>
#endif
#include "tcp.h"
int growl_tcp_parse_hostname( const char *const server , int default_port , struct sockaddr_in *const sockaddr );
void growl_tcp_write_raw( SOCKET sock, const unsigned char * data, const int data_length )
{
send(sock, data, data_length, 0);
}
void growl_tcp_write( SOCKET sock , const char *const format , ... )
{
int length;
char *output;
char *stop;
va_list ap;
va_start( ap , format );
length = vsnprintf( NULL , 0 , format , ap );
va_end(ap);
va_start(ap,format);
output = (char*)PhAllocateSafe(length+1);
if (!output) {
va_end(ap);
return;
}
vsnprintf( output , length+1 , format , ap );
va_end(ap);
while ((stop = strstr(output, "\r\n"))) strcpy(stop, stop + 1);
send( sock , output , length , 0 );
send( sock , "\r\n" , 2 , 0 );
PhFree(output);
}
char *growl_tcp_read(SOCKET sock) {
const int growsize = 80;
char c = 0;
char* line = (char*) PhAllocateSafe(growsize);
if (line) {
int len = growsize, pos = 0;
char* newline;
while (line) {
if (recv(sock, &c, 1, 0) <= 0) break;
if (c == '\r') continue;
if (c == '\n') break;
line[pos++] = c;
if (pos >= len) {
len += growsize;
newline = (char*) realloc(line, len);
if (!newline) {
PhFree(line);
return NULL;
}
line = newline;
}
}
line[pos] = 0;
}
return line;
}
/* dmex: modified to use INVALID_SOCKET and SOCKET_ERROR */
SOCKET growl_tcp_open(const char* server) {
SOCKET sock = INVALID_SOCKET;
#ifdef _WIN32
char on;
#else
int on;
#endif
struct sockaddr_in serv_addr;
if( growl_tcp_parse_hostname( server , 23053 , &serv_addr ) == -1 ) {
return INVALID_SOCKET;
}
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
perror("create socket");
return INVALID_SOCKET;
}
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == SOCKET_ERROR) {
perror("connect");
closesocket(sock); // dmex: fixed handle leaking on error
return INVALID_SOCKET;
}
on = 1;
if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) == SOCKET_ERROR) {
perror("setsockopt");
closesocket(sock); // dmex: fixed handle leaking on error
return INVALID_SOCKET;
}
return sock;
}
/* dmex: modified to use INVALID_SOCKET */
void growl_tcp_close(SOCKET sock) {
#ifdef _WIN32
if (sock != INVALID_SOCKET) closesocket(sock);
#else
if (sock > 0) close(sock);
#endif
}
int growl_tcp_parse_hostname( const char *const server , int default_port , struct sockaddr_in *const sockaddr )
{
char *hostname = PhDuplicateBytesZSafe((PSTR)server);
char *port = strchr( hostname, ':' );
struct hostent* host_ent;
if( port != NULL )
{
*port = '\0';
port++;
default_port = atoi(port);
}
host_ent = gethostbyname(hostname);
if( host_ent == NULL )
{
perror("gethostbyname");
PhFree(hostname);
return -1;
}
// dmex: fixed wrong sizeof argument
memset( sockaddr , 0 , sizeof(struct sockaddr_in) );
sockaddr->sin_family = AF_INET;
memcpy( &sockaddr->sin_addr , host_ent->h_addr , host_ent->h_length );
sockaddr->sin_port = htons(default_port);
PhFree(hostname);
return 0;
}
int growl_tcp_datagram( const char *server , const unsigned char *data , const int data_length )
{
int result;
struct sockaddr_in serv_addr;
SOCKET sock = 0;
if( growl_tcp_parse_hostname( server , 9887 , &serv_addr ) == -1 )
{
return -1;
}
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if( sock == INVALID_SOCKET )
{
return -1;
}
if( sendto(sock, (char*)data , data_length , 0 , (struct sockaddr*)&serv_addr , sizeof(serv_addr) ) > 0 )
{
result = 0;
}
else
{
result = 1;
}
closesocket(sock);
return result;
}

View File

@@ -0,0 +1,14 @@
#ifndef _TCP_H_
#define _TCP_H_
#ifdef _MSC_VER
#define __attribute__(x)
#endif
void growl_tcp_write_raw( SOCKET sock, const unsigned char * data, const int data_length );
void growl_tcp_write( SOCKET sock , const char *const format , ... ) __attribute__ ((format (printf, 2, 3)));
char* growl_tcp_read(SOCKET sock);
SOCKET growl_tcp_open(const char* server);
void growl_tcp_close(SOCKET sock);
int growl_tcp_datagram( const char *server , const unsigned char *data , const int data_length );
#endif /* _TCP_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,33 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by ExtendedNotifications.rc
//
#define IDD_PROCESSES 101
#define IDC_TEXT_RETURN 101
#define IDD_SERVICES 102
#define IDD_LOGGING 103
#define IDD_GROWL 104
#define IDC_INCLUDE 1006
#define IDC_EXCLUDE 1007
#define IDC_REMOVE 1008
#define IDC_ADD 1009
#define IDC_MOVEUP 1010
#define IDC_MOVEDOWN 1011
#define IDC_LIST 1012
#define IDC_TEXT 1013
#define IDC_EDIT1 1014
#define IDC_LOGFILENAME 1014
#define IDC_LICENSE 1014
#define IDC_BROWSE 1015
#define IDC_ENABLEGROWL 1016
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 108
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1017
#define _APS_NEXT_SYMED_VALUE 102
#endif
#endif

View File

@@ -0,0 +1,38 @@
1.10
* Added service protection and SID information
* Added auto-elevation when saving recovery information, triggers and other service settings
1.9
* Added new trigger data types
1.8
* Fixed some bugs relating to Windows 8
1.7
* Added new triggers for Windows 8
* Fixed bug when restarting services
1.6
* Disabled editing of required privileges for drivers
1.5
* Added support for editing triggers
* Added support for editing preshutdown time-out
* Added support for editing required privileges
* Added elevation support for restarting services
1.4
* Improved Services submenu when there is only one service
1.3
* Added Services submenu for processes
1.2
* Added Other tab
1.1
* Added Restart menu item for services
* Fixed service handle leak
1.0
* Initial release

View File

@@ -0,0 +1,350 @@
// 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,10,0,0
PRODUCTVERSION 1,10,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 Services for Process Hacker"
VALUE "FileVersion", "1.10"
VALUE "InternalName", "ExtendedServices"
VALUE "LegalCopyright", "Licensed under the GNU GPL, v3."
VALUE "OriginalFilename", "ExtendedServices.dll"
VALUE "ProductName", "Extended Services for Process Hacker"
VALUE "ProductVersion", "1.10"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0xc09, 1200
END
END
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_SRVLIST DIALOGEX 0, 0, 282, 183
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "List"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Static",IDC_SERVICES_LAYOUT,7,19,268,157,NOT WS_VISIBLE
LTEXT "Static",IDC_MESSAGE,7,7,268,8
END
IDD_SRVRECOVERY DIALOGEX 0, 0, 282, 183
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Recovery"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "First failure:",IDC_STATIC,7,8,40,8
COMBOBOX IDC_FIRSTFAILURE,85,7,103,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Second failure:",IDC_STATIC,7,24,49,8
COMBOBOX IDC_SECONDFAILURE,85,23,103,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Subsequent failures:",IDC_STATIC,7,40,67,8
COMBOBOX IDC_SUBSEQUENTFAILURES,85,39,103,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Reset fail count after:",IDC_STATIC,7,56,72,8
EDITTEXT IDC_RESETFAILCOUNT,85,55,40,12,ES_AUTOHSCROLL | ES_NUMBER
LTEXT "days",IDC_STATIC,130,56,16,8
LTEXT "Restart service after:",IDC_RESTARTSERVICEAFTER_LABEL,7,72,70,8
EDITTEXT IDC_RESTARTSERVICEAFTER,85,71,40,12,ES_AUTOHSCROLL | ES_NUMBER
LTEXT "minutes",IDC_RESTARTSERVICEAFTER_MINUTES,130,72,26,8
CONTROL "Enable actions for stops with errors",IDC_ENABLEFORERRORSTOPS,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,87,129,10
PUSHBUTTON "Restart computer options...",IDC_RESTARTCOMPUTEROPTIONS,7,100,114,14
GROUPBOX "Run program",IDC_RUNPROGRAM_GROUP,7,118,268,45
LTEXT "Program:",IDC_RUNPROGRAM_LABEL,15,132,30,8
EDITTEXT IDC_RUNPROGRAM,50,131,165,12,ES_AUTOHSCROLL
PUSHBUTTON "Browse...",IDC_BROWSE,220,130,50,14
LTEXT "Append /fail=%1% to pass the fail count to the program.",IDC_RUNPROGRAM_INFO,15,148,186,8
END
IDD_RESTARTCOMP DIALOGEX 0, 0, 245, 137
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Restart the computer after:",IDC_STATIC,7,8,90,8
EDITTEXT IDC_RESTARTCOMPAFTER,102,7,40,12,ES_AUTOHSCROLL | ES_NUMBER
LTEXT "minutes",IDC_STATIC,147,8,26,8
CONTROL "Before restarting, send this message to computers on the network:",IDC_ENABLERESTARTMESSAGE,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,23,231,10
EDITTEXT IDC_RESTARTMESSAGE,7,36,231,76,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL
PUSHBUTTON "Use default message",IDC_USEDEFAULTMESSAGE,7,116,79,14
DEFPUSHBUTTON "OK",IDOK,134,116,50,14
PUSHBUTTON "Cancel",IDCANCEL,188,116,50,14
END
IDD_SRVRECOVERY2 DIALOGEX 0, 0, 282, 183
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Recovery"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
CTEXT "If this service fails, the computer will restart.\nRecovery actions are not supported for this service.",IDC_STATIC,51,80,179,21
END
IDD_SRVPROGRESS DIALOGEX 0, 0, 204, 61
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Progress"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
PUSHBUTTON "Cancel",IDCANCEL,147,40,50,14
LTEXT "Progress",IDC_MESSAGE,7,7,190,8,SS_ENDELLIPSIS
CONTROL "",IDC_PROGRESS,"msctls_progress32",WS_BORDER,7,21,190,14
END
IDD_SRVOTHER DIALOGEX 0, 0, 282, 218
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Other"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Preshutdown timeout:",IDC_STATIC,7,8,72,8
EDITTEXT IDC_PRESHUTDOWNTIMEOUT,85,7,75,12,ES_AUTOHSCROLL
LTEXT "milliseconds",IDC_STATIC,166,8,38,8
LTEXT "Service SID:",IDC_STATIC,7,24,40,8
EDITTEXT IDC_SERVICESID,64,23,211,12,ES_AUTOHSCROLL | ES_READONLY
LTEXT "SID type:",IDC_STATIC,7,40,32,8
COMBOBOX IDC_SIDTYPE,64,39,122,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
LTEXT "Protection:",IDC_STATIC,7,57,36,8
COMBOBOX IDC_PROTECTION,64,56,122,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
LTEXT "Required privileges:",IDC_STATIC,7,77,64,8
CONTROL "",IDC_PRIVILEGES,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,88,268,79
PUSHBUTTON "Add...",IDC_ADD,171,171,50,14
PUSHBUTTON "Remove",IDC_REMOVE,225,171,50,14
END
IDD_OPTIONS DIALOGEX 0, 0, 215, 54
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Options"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
CONTROL "Enable Services submenu for processes",IDC_ENABLESERVICESMENU,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,142,10
DEFPUSHBUTTON "OK",IDOK,105,33,50,14
PUSHBUTTON "Cancel",IDCANCEL,158,33,50,14
END
IDD_SRVTRIGGER DIALOGEX 0, 0, 330, 196
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Trigger"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Type:",IDC_STATIC,7,9,20,8
COMBOBOX IDC_TYPE,52,7,271,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Subtype:",IDC_STATIC,7,26,30,8
COMBOBOX IDC_SUBTYPE,52,24,271,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
EDITTEXT IDC_SUBTYPECUSTOM,52,41,271,12,ES_AUTOHSCROLL
LTEXT "Action:",IDC_STATIC,7,59,24,8
COMBOBOX IDC_ACTION,52,58,72,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Data items:",IDC_STATIC,7,76,38,8
CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,52,79,217,90
PUSHBUTTON "New...",IDC_NEW,273,79,50,14
PUSHBUTTON "Edit...",IDC_EDIT,273,96,50,14
PUSHBUTTON "Delete",IDC_DELETE,273,113,50,14
DEFPUSHBUTTON "OK",IDOK,219,175,50,14
PUSHBUTTON "Cancel",IDCANCEL,273,175,50,14
END
IDD_VALUE DIALOGEX 0, 0, 267, 167
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Edit Data"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Values (one per line):",IDC_STATIC,7,7,69,8
EDITTEXT IDC_VALUES,7,18,253,124,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL
DEFPUSHBUTTON "OK",IDOK,156,146,50,14
PUSHBUTTON "Cancel",IDCANCEL,210,146,50,14
END
IDD_SRVTRIGGERS DIALOGEX 0, 0, 282, 218
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Triggers"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
CONTROL "",IDC_TRIGGERS,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,268,186
PUSHBUTTON "New...",IDC_NEW,117,197,50,14
PUSHBUTTON "Edit...",IDC_EDIT,171,197,50,14
PUSHBUTTON "Delete",IDC_DELETE,225,197,50,14
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_SRVLIST, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 275
TOPMARGIN, 7
BOTTOMMARGIN, 176
END
IDD_SRVRECOVERY, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 275
TOPMARGIN, 7
BOTTOMMARGIN, 176
END
IDD_RESTARTCOMP, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 238
TOPMARGIN, 7
BOTTOMMARGIN, 130
END
IDD_SRVRECOVERY2, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 275
TOPMARGIN, 7
BOTTOMMARGIN, 176
END
IDD_SRVPROGRESS, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 197
TOPMARGIN, 7
BOTTOMMARGIN, 54
END
IDD_SRVOTHER, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 275
TOPMARGIN, 7
BOTTOMMARGIN, 211
END
IDD_OPTIONS, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 208
TOPMARGIN, 7
BOTTOMMARGIN, 47
END
IDD_SRVTRIGGER, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 323
TOPMARGIN, 7
BOTTOMMARGIN, 189
END
IDD_VALUE, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 260
TOPMARGIN, 7
BOTTOMMARGIN, 160
END
IDD_SRVTRIGGERS, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 275
TOPMARGIN, 7
BOTTOMMARGIN, 211
END
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// AFX_DIALOG_LAYOUT
//
IDD_OPTIONS AFX_DIALOG_LAYOUT
BEGIN
0
END
#endif // English (Australia) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View File

@@ -0,0 +1,87 @@
<?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>{AC547368-D861-4B88-B5D4-E3B1F1AEEEDD}</ProjectGuid>
<RootNamespace>ExtendedServices</RootNamespace>
<Keyword>Win32Proj</Keyword>
<ProjectName>ExtendedServices</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>
<ItemGroup>
<ClCompile Include="depend.c" />
<ClCompile Include="main.c" />
<ClCompile Include="options.c" />
<ClCompile Include="other.c" />
<ClCompile Include="srvprgrs.c" />
<ClCompile Include="recovery.c" />
<ClCompile Include="trigger.c" />
<ClCompile Include="triggpg.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="extsrv.h" />
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="ExtendedServices.rc" />
</ItemGroup>
<ItemGroup>
<None Include="CHANGELOG.txt" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

View File

@@ -0,0 +1,59 @@
<?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="depend.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="main.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="srvprgrs.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="other.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="options.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="trigger.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="triggpg.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="recovery.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="extsrv.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="ExtendedServices.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<None Include="CHANGELOG.txt" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,344 @@
/*
* Process Hacker Extended Services -
* dependencies and dependents
*
* 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 "extsrv.h"
typedef struct _SERVICE_LIST_CONTEXT
{
HWND ServiceListHandle;
PH_LAYOUT_MANAGER LayoutManager;
} SERVICE_LIST_CONTEXT, *PSERVICE_LIST_CONTEXT;
LPENUM_SERVICE_STATUS EsEnumDependentServices(
_In_ SC_HANDLE ServiceHandle,
_In_opt_ ULONG State,
_Out_ PULONG Count
)
{
LOGICAL result;
PVOID buffer;
ULONG bufferSize;
ULONG returnLength;
ULONG servicesReturned;
if (!State)
State = SERVICE_STATE_ALL;
bufferSize = 0x800;
buffer = PhAllocate(bufferSize);
if (!(result = EnumDependentServices(
ServiceHandle,
State,
buffer,
bufferSize,
&returnLength,
&servicesReturned
)))
{
if (GetLastError() == ERROR_MORE_DATA)
{
PhFree(buffer);
bufferSize = returnLength;
buffer = PhAllocate(bufferSize);
result = EnumDependentServices(
ServiceHandle,
State,
buffer,
bufferSize,
&returnLength,
&servicesReturned
);
}
if (!result)
{
PhFree(buffer);
return NULL;
}
}
*Count = servicesReturned;
return buffer;
}
VOID EspLayoutServiceListControl(
_In_ HWND hwndDlg,
_In_ HWND ServiceListHandle
)
{
RECT rect;
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,
TRUE
);
}
INT_PTR CALLBACK EspServiceDependenciesDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
PSERVICE_LIST_CONTEXT context;
if (uMsg == WM_INITDIALOG)
{
context = PhAllocate(sizeof(SERVICE_LIST_CONTEXT));
memset(context, 0, sizeof(SERVICE_LIST_CONTEXT));
SetProp(hwndDlg, L"Context", (HANDLE)context);
}
else
{
context = (PSERVICE_LIST_CONTEXT)GetProp(hwndDlg, L"Context");
if (uMsg == WM_DESTROY)
RemoveProp(hwndDlg, L"Context");
}
if (!context)
return FALSE;
switch (uMsg)
{
case WM_INITDIALOG:
{
LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam;
PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)propSheetPage->lParam;
HWND serviceListHandle;
PPH_LIST serviceList;
SC_HANDLE serviceHandle;
ULONG win32Result = 0;
BOOLEAN success = FALSE;
PPH_SERVICE_ITEM *services;
SetDlgItemText(hwndDlg, IDC_MESSAGE, L"This service depends on the following services:");
PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);
PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), NULL, PH_ANCHOR_ALL);
if (serviceHandle = PhOpenService(serviceItem->Name->Buffer, SERVICE_QUERY_CONFIG))
{
LPQUERY_SERVICE_CONFIG serviceConfig;
if (serviceConfig = PhGetServiceConfig(serviceHandle))
{
PWSTR dependency;
PPH_SERVICE_ITEM dependencyService;
dependency = serviceConfig->lpDependencies;
serviceList = PH_AUTO(PhCreateList(8));
success = TRUE;
if (dependency)
{
ULONG dependencyLength;
while (TRUE)
{
dependencyLength = (ULONG)PhCountStringZ(dependency);
if (dependencyLength == 0)
break;
if (dependency[0] == SC_GROUP_IDENTIFIER)
goto ContinueLoop;
if (dependencyService = PhReferenceServiceItem(dependency))
PhAddItemList(serviceList, dependencyService);
ContinueLoop:
dependency += dependencyLength + 1;
}
}
services = PhAllocateCopy(serviceList->Items, sizeof(PPH_SERVICE_ITEM) * serviceList->Count);
serviceListHandle = PhCreateServiceListControl(hwndDlg, services, serviceList->Count);
context->ServiceListHandle = serviceListHandle;
EspLayoutServiceListControl(hwndDlg, serviceListHandle);
ShowWindow(serviceListHandle, SW_SHOW);
PhFree(serviceConfig);
}
else
{
win32Result = GetLastError();
}
CloseServiceHandle(serviceHandle);
}
else
{
win32Result = GetLastError();
}
if (!success)
{
SetDlgItemText(hwndDlg, IDC_SERVICES_LAYOUT, PhaConcatStrings2(L"Unable to enumerate dependencies: ",
((PPH_STRING)PH_AUTO(PhGetWin32Message(win32Result)))->Buffer)->Buffer);
ShowWindow(GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), SW_SHOW);
}
}
break;
case WM_DESTROY:
{
PhDeleteLayoutManager(&context->LayoutManager);
PhFree(context);
}
break;
case WM_SIZE:
{
PhLayoutManagerLayout(&context->LayoutManager);
if (context->ServiceListHandle)
EspLayoutServiceListControl(hwndDlg, context->ServiceListHandle);
}
break;
}
return FALSE;
}
INT_PTR CALLBACK EspServiceDependentsDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
PSERVICE_LIST_CONTEXT context;
if (uMsg == WM_INITDIALOG)
{
context = PhAllocate(sizeof(SERVICE_LIST_CONTEXT));
memset(context, 0, sizeof(SERVICE_LIST_CONTEXT));
SetProp(hwndDlg, L"Context", (HANDLE)context);
}
else
{
context = (PSERVICE_LIST_CONTEXT)GetProp(hwndDlg, L"Context");
if (uMsg == WM_DESTROY)
RemoveProp(hwndDlg, L"Context");
}
if (!context)
return FALSE;
switch (uMsg)
{
case WM_INITDIALOG:
{
LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam;
PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)propSheetPage->lParam;
HWND serviceListHandle;
PPH_LIST serviceList;
SC_HANDLE serviceHandle;
ULONG win32Result = 0;
BOOLEAN success = FALSE;
PPH_SERVICE_ITEM *services;
SetDlgItemText(hwndDlg, IDC_MESSAGE, L"The following services depend on this service:");
PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);
PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), NULL, PH_ANCHOR_ALL);
if (serviceHandle = PhOpenService(serviceItem->Name->Buffer, SERVICE_ENUMERATE_DEPENDENTS))
{
LPENUM_SERVICE_STATUS dependentServices;
ULONG numberOfDependentServices;
if (dependentServices = EsEnumDependentServices(serviceHandle, 0, &numberOfDependentServices))
{
ULONG i;
PPH_SERVICE_ITEM dependentService;
serviceList = PH_AUTO(PhCreateList(8));
success = TRUE;
for (i = 0; i < numberOfDependentServices; i++)
{
if (dependentService = PhReferenceServiceItem(dependentServices[i].lpServiceName))
PhAddItemList(serviceList, dependentService);
}
services = PhAllocateCopy(serviceList->Items, sizeof(PPH_SERVICE_ITEM) * serviceList->Count);
serviceListHandle = PhCreateServiceListControl(hwndDlg, services, serviceList->Count);
context->ServiceListHandle = serviceListHandle;
EspLayoutServiceListControl(hwndDlg, serviceListHandle);
ShowWindow(serviceListHandle, SW_SHOW);
PhFree(dependentServices);
}
else
{
win32Result = GetLastError();
}
CloseServiceHandle(serviceHandle);
}
else
{
win32Result = GetLastError();
}
if (!success)
{
SetDlgItemText(hwndDlg, IDC_SERVICES_LAYOUT, PhaConcatStrings2(L"Unable to enumerate dependents: ",
((PPH_STRING)PH_AUTO(PhGetWin32Message(win32Result)))->Buffer)->Buffer);
ShowWindow(GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), SW_SHOW);
}
}
break;
case WM_DESTROY:
{
PhDeleteLayoutManager(&context->LayoutManager);
PhFree(context);
}
break;
case WM_SIZE:
{
PhLayoutManagerLayout(&context->LayoutManager);
if (context->ServiceListHandle)
EspLayoutServiceListControl(hwndDlg, context->ServiceListHandle);
}
break;
}
return FALSE;
}

View File

@@ -0,0 +1,128 @@
#ifndef ES_EXTSRV_H
#define ES_EXTSRV_H
#include <phdk.h>
#include <windowsx.h>
#include "resource.h"
// main
extern PPH_PLUGIN PluginInstance;
#define PLUGIN_NAME L"ProcessHacker.ExtendedServices"
#define SETTING_NAME_ENABLE_SERVICES_MENU (PLUGIN_NAME L".EnableServicesMenu")
#define SIP(String, Integer) { (String), (PVOID)(Integer) }
// depend
LPENUM_SERVICE_STATUS EsEnumDependentServices(
_In_ SC_HANDLE ServiceHandle,
_In_opt_ ULONG State,
_Out_ PULONG Count
);
INT_PTR CALLBACK EspServiceDependenciesDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
INT_PTR CALLBACK EspServiceDependentsDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
// options
VOID EsShowOptionsDialog(
_In_ HWND ParentWindowHandle
);
// other
typedef NTSTATUS (NTAPI *_RtlCreateServiceSid)(
_In_ PUNICODE_STRING ServiceName,
_Out_writes_bytes_opt_(*ServiceSidLength) PSID ServiceSid,
_Inout_ PULONG ServiceSidLength
);
INT_PTR CALLBACK EspServiceOtherDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
// recovery
INT_PTR CALLBACK EspServiceRecoveryDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
INT_PTR CALLBACK EspServiceRecovery2DlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
// srvprgrs
VOID EsRestartServiceWithProgress(
_In_ HWND hWnd,
_In_ PPH_SERVICE_ITEM ServiceItem,
_In_ SC_HANDLE ServiceHandle
);
// trigger
struct _ES_TRIGGER_CONTEXT;
struct _ES_TRIGGER_CONTEXT *EsCreateServiceTriggerContext(
_In_ PPH_SERVICE_ITEM ServiceItem,
_In_ HWND WindowHandle,
_In_ HWND TriggersLv
);
VOID EsDestroyServiceTriggerContext(
_In_ struct _ES_TRIGGER_CONTEXT *Context
);
VOID EsLoadServiceTriggerInfo(
_In_ struct _ES_TRIGGER_CONTEXT *Context,
_In_ SC_HANDLE ServiceHandle
);
BOOLEAN EsSaveServiceTriggerInfo(
_In_ struct _ES_TRIGGER_CONTEXT *Context,
_Out_ PULONG Win32Result
);
#define ES_TRIGGER_EVENT_NEW 1
#define ES_TRIGGER_EVENT_EDIT 2
#define ES_TRIGGER_EVENT_DELETE 3
#define ES_TRIGGER_EVENT_SELECTIONCHANGED 4
VOID EsHandleEventServiceTrigger(
_In_ struct _ES_TRIGGER_CONTEXT *Context,
_In_ ULONG Event
);
// triggpg
INT_PTR CALLBACK EspServiceTriggersDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
#endif

View File

@@ -0,0 +1,481 @@
/*
* Process Hacker Extended Services -
* 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 "extsrv.h"
PPH_PLUGIN PluginInstance;
static PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration;
static PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration;
static PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration;
static PH_CALLBACK_REGISTRATION ProcessMenuInitializingCallbackRegistration;
static PH_CALLBACK_REGISTRATION ServicePropertiesInitializingCallbackRegistration;
static PH_CALLBACK_REGISTRATION ServiceMenuInitializingCallbackRegistration;
VOID NTAPI LoadCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
// Nothing
}
VOID NTAPI ShowOptionsCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
EsShowOptionsDialog((HWND)Parameter);
}
VOID NTAPI MenuItemCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN_MENU_ITEM menuItem = Parameter;
switch (menuItem->Id)
{
case ID_SERVICE_GOTOSERVICE:
{
ProcessHacker_SelectTabPage(PhMainWndHandle, 1);
ProcessHacker_SelectServiceItem(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context);
}
break;
case ID_SERVICE_START:
{
PhUiStartService(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context);
}
break;
case ID_SERVICE_CONTINUE:
{
PhUiContinueService(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context);
}
break;
case ID_SERVICE_PAUSE:
{
PhUiPauseService(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context);
}
break;
case ID_SERVICE_STOP:
{
PhUiStopService(PhMainWndHandle, (PPH_SERVICE_ITEM)menuItem->Context);
}
break;
case ID_SERVICE_RESTART:
{
PPH_SERVICE_ITEM serviceItem = menuItem->Context;
SC_HANDLE serviceHandle;
ULONG win32Result = 0;
if (serviceHandle = PhOpenService(serviceItem->Name->Buffer, SERVICE_QUERY_STATUS))
{
EsRestartServiceWithProgress(PhMainWndHandle, serviceItem, serviceHandle);
CloseServiceHandle(serviceHandle);
}
else
{
win32Result = GetLastError();
}
if (win32Result != 0)
{
PhShowStatus(
PhMainWndHandle,
PhaFormatString(L"Unable to restart %s", serviceItem->Name->Buffer)->Buffer,
0,
win32Result
);
}
}
break;
}
}
static int __cdecl ServiceForServicesMenuCompare(
_In_ const void *elem1,
_In_ const void *elem2
)
{
PPH_SERVICE_ITEM serviceItem1 = *(PPH_SERVICE_ITEM *)elem1;
PPH_SERVICE_ITEM serviceItem2 = *(PPH_SERVICE_ITEM *)elem2;
return PhCompareString(serviceItem1->Name, serviceItem2->Name, TRUE);
}
VOID NTAPI ProcessMenuInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter;
if (
PhGetIntegerSetting(SETTING_NAME_ENABLE_SERVICES_MENU) &&
menuInfo->u.Process.NumberOfProcesses == 1 &&
menuInfo->u.Process.Processes[0]->ServiceList &&
menuInfo->u.Process.Processes[0]->ServiceList->Count != 0
)
{
PPH_PROCESS_ITEM processItem;
PPH_EMENU_ITEM servicesMenuItem = NULL;
ULONG enumerationKey;
PPH_SERVICE_ITEM serviceItem;
PPH_LIST serviceList;
ULONG i;
PPH_EMENU_ITEM priorityMenuItem;
ULONG insertIndex;
processItem = menuInfo->u.Process.Processes[0];
// Create a service list so we can sort it.
serviceList = PH_AUTO(PhCreateList(processItem->ServiceList->Count));
enumerationKey = 0;
PhAcquireQueuedLockShared(&processItem->ServiceListLock);
while (PhEnumPointerList(processItem->ServiceList, &enumerationKey, &serviceItem))
{
PhReferenceObject(serviceItem);
// We need to use the service item when the user chooses a menu item.
PH_AUTO(serviceItem);
PhAddItemList(serviceList, serviceItem);
}
PhReleaseQueuedLockShared(&processItem->ServiceListLock);
// Sort the service list.
qsort(serviceList->Items, serviceList->Count, sizeof(PPH_SERVICE_ITEM), ServiceForServicesMenuCompare);
// If there is only one service:
// * We use the text "Service (Xxx)".
// * There are no extra submenus.
if (serviceList->Count != 1)
{
servicesMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, 0, L"Services", NULL);
}
// Create and add a menu item for each service.
for (i = 0; i < serviceList->Count; i++)
{
PPH_STRING escapedName;
PPH_EMENU_ITEM serviceMenuItem;
PPH_EMENU_ITEM startMenuItem;
PPH_EMENU_ITEM continueMenuItem;
PPH_EMENU_ITEM pauseMenuItem;
PPH_EMENU_ITEM stopMenuItem;
serviceItem = serviceList->Items[i];
escapedName = PH_AUTO(PhEscapeStringForMenuPrefix(&serviceItem->Name->sr));
if (serviceList->Count == 1)
{
// "Service (Xxx)"
escapedName = PhaFormatString(L"Service (%s)", escapedName->Buffer);
}
serviceMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, 0, escapedName->Buffer, NULL);
if (serviceList->Count == 1)
{
// Make this the root submenu that we will insert.
servicesMenuItem = serviceMenuItem;
}
PhInsertEMenuItem(serviceMenuItem, PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_GOTOSERVICE, L"Go to service", serviceItem), -1);
PhInsertEMenuItem(serviceMenuItem, startMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_START, L"Start", serviceItem), -1);
PhInsertEMenuItem(serviceMenuItem, continueMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_CONTINUE, L"Continue", serviceItem), -1);
PhInsertEMenuItem(serviceMenuItem, pauseMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_PAUSE, L"Pause", serviceItem), -1);
PhInsertEMenuItem(serviceMenuItem, stopMenuItem = PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_STOP, L"Stop", serviceItem), -1);
// Massive copy and paste from mainwnd.c.
// == START ==
#define SET_MENU_ITEM_ENABLED(MenuItem, Enabled) if (!(Enabled)) (MenuItem)->Flags |= PH_EMENU_DISABLED;
switch (serviceItem->State)
{
case SERVICE_RUNNING:
{
SET_MENU_ITEM_ENABLED(startMenuItem, FALSE);
SET_MENU_ITEM_ENABLED(continueMenuItem, FALSE);
SET_MENU_ITEM_ENABLED(pauseMenuItem,
serviceItem->ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE);
SET_MENU_ITEM_ENABLED(stopMenuItem,
serviceItem->ControlsAccepted & SERVICE_ACCEPT_STOP);
}
break;
case SERVICE_PAUSED:
{
SET_MENU_ITEM_ENABLED(startMenuItem, FALSE);
SET_MENU_ITEM_ENABLED(continueMenuItem,
serviceItem->ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE);
SET_MENU_ITEM_ENABLED(pauseMenuItem, FALSE);
SET_MENU_ITEM_ENABLED(stopMenuItem,
serviceItem->ControlsAccepted & SERVICE_ACCEPT_STOP);
}
break;
case SERVICE_STOPPED:
{
SET_MENU_ITEM_ENABLED(continueMenuItem, FALSE);
SET_MENU_ITEM_ENABLED(pauseMenuItem, FALSE);
SET_MENU_ITEM_ENABLED(stopMenuItem, FALSE);
}
break;
case SERVICE_START_PENDING:
case SERVICE_CONTINUE_PENDING:
case SERVICE_PAUSE_PENDING:
case SERVICE_STOP_PENDING:
{
SET_MENU_ITEM_ENABLED(startMenuItem, FALSE);
SET_MENU_ITEM_ENABLED(continueMenuItem, FALSE);
SET_MENU_ITEM_ENABLED(pauseMenuItem, FALSE);
SET_MENU_ITEM_ENABLED(stopMenuItem, FALSE);
}
break;
}
if (!(serviceItem->ControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE))
{
PhDestroyEMenuItem(continueMenuItem);
PhDestroyEMenuItem(pauseMenuItem);
}
// == END ==
if (serviceList->Count != 1)
PhInsertEMenuItem(servicesMenuItem, serviceMenuItem, -1);
}
// Insert our Services menu after the I/O Priority menu.
priorityMenuItem = PhFindEMenuItem(menuInfo->Menu, 0, L"I/O Priority", 0);
if (!priorityMenuItem)
priorityMenuItem = PhFindEMenuItem(menuInfo->Menu, 0, L"Priority", 0);
if (priorityMenuItem)
insertIndex = PhIndexOfEMenuItem(menuInfo->Menu, priorityMenuItem) + 1;
else
insertIndex = 0;
PhInsertEMenuItem(menuInfo->Menu, servicesMenuItem, insertIndex);
}
}
NTAPI ServicePropertiesInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN_OBJECT_PROPERTIES objectProperties = Parameter;
PROPSHEETPAGE propSheetPage;
PPH_SERVICE_ITEM serviceItem;
serviceItem = objectProperties->Parameter;
// Recovery
if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages)
{
memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));
propSheetPage.dwSize = sizeof(PROPSHEETPAGE);
propSheetPage.hInstance = PluginInstance->DllBase;
propSheetPage.lParam = (LPARAM)serviceItem;
if (!(serviceItem->Flags & SERVICE_RUNS_IN_SYSTEM_PROCESS))
{
propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SRVRECOVERY);
propSheetPage.pfnDlgProc = EspServiceRecoveryDlgProc;
}
else
{
// Services which run in system processes don't support failure actions.
// Create a different page with a message saying this.
propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SRVRECOVERY2);
propSheetPage.pfnDlgProc = EspServiceRecovery2DlgProc;
}
objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage);
}
// Dependencies
if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages)
{
memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));
propSheetPage.dwSize = sizeof(PROPSHEETPAGE);
propSheetPage.dwFlags = PSP_USETITLE;
propSheetPage.hInstance = PluginInstance->DllBase;
propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SRVLIST);
propSheetPage.pszTitle = L"Dependencies";
propSheetPage.pfnDlgProc = EspServiceDependenciesDlgProc;
propSheetPage.lParam = (LPARAM)serviceItem;
objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage);
}
// Dependents
if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages)
{
memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));
propSheetPage.dwSize = sizeof(PROPSHEETPAGE);
propSheetPage.dwFlags = PSP_USETITLE;
propSheetPage.hInstance = PluginInstance->DllBase;
propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SRVLIST);
propSheetPage.pszTitle = L"Dependents";
propSheetPage.pfnDlgProc = EspServiceDependentsDlgProc;
propSheetPage.lParam = (LPARAM)serviceItem;
objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage);
}
// Other
if (WindowsVersion >= WINDOWS_7 && objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages)
{
memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));
propSheetPage.dwSize = sizeof(PROPSHEETPAGE);
propSheetPage.dwFlags = PSP_USETITLE;
propSheetPage.hInstance = PluginInstance->DllBase;
propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SRVTRIGGERS);
propSheetPage.pszTitle = L"Triggers";
propSheetPage.pfnDlgProc = EspServiceTriggersDlgProc;
propSheetPage.lParam = (LPARAM)serviceItem;
objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage);
}
// Other
if (WindowsVersion >= WINDOWS_VISTA && objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages)
{
memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));
propSheetPage.dwSize = sizeof(PROPSHEETPAGE);
propSheetPage.dwFlags = PSP_USETITLE;
propSheetPage.hInstance = PluginInstance->DllBase;
propSheetPage.pszTemplate = MAKEINTRESOURCE(IDD_SRVOTHER);
propSheetPage.pszTitle = L"Other";
propSheetPage.pfnDlgProc = EspServiceOtherDlgProc;
propSheetPage.lParam = (LPARAM)serviceItem;
objectProperties->Pages[objectProperties->NumberOfPages++] = CreatePropertySheetPage(&propSheetPage);
}
}
VOID NTAPI ServiceMenuInitializingCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PPH_PLUGIN_MENU_INFORMATION menuInfo = Parameter;
PPH_EMENU_ITEM menuItem;
ULONG indexOfMenuItem;
if (
menuInfo->u.Service.NumberOfServices == 1 &&
(menuInfo->u.Service.Services[0]->State == SERVICE_RUNNING || menuInfo->u.Service.Services[0]->State == SERVICE_PAUSED)
)
{
// Insert our Restart menu item after the Stop menu item.
menuItem = PhFindEMenuItem(menuInfo->Menu, PH_EMENU_FIND_STARTSWITH, L"Stop", 0);
if (menuItem)
indexOfMenuItem = PhIndexOfEMenuItem(menuInfo->Menu, menuItem);
else
indexOfMenuItem = -1;
PhInsertEMenuItem(
menuInfo->Menu,
PhPluginCreateEMenuItem(PluginInstance, 0, ID_SERVICE_RESTART, L"Restart", menuInfo->u.Service.Services[0]),
indexOfMenuItem + 1
);
}
}
LOGICAL DllMain(
_In_ HINSTANCE Instance,
_In_ ULONG Reason,
_Reserved_ PVOID Reserved
)
{
switch (Reason)
{
case DLL_PROCESS_ATTACH:
{
PPH_PLUGIN_INFORMATION info;
PH_SETTING_CREATE settings[] =
{
{ IntegerSettingType, SETTING_NAME_ENABLE_SERVICES_MENU, L"1" }
};
PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info);
if (!PluginInstance)
return FALSE;
info->DisplayName = L"Extended Services";
info->Author = L"wj32";
info->Description = L"Extends service management capabilities.";
info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1113";
info->HasOptions = TRUE;
PhRegisterCallback(
PhGetPluginCallback(PluginInstance, PluginCallbackLoad),
LoadCallback,
NULL,
&PluginLoadCallbackRegistration
);
PhRegisterCallback(
PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions),
ShowOptionsCallback,
NULL,
&PluginShowOptionsCallbackRegistration
);
PhRegisterCallback(
PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem),
MenuItemCallback,
NULL,
&PluginMenuItemCallbackRegistration
);
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackProcessMenuInitializing),
ProcessMenuInitializingCallback,
NULL,
&ProcessMenuInitializingCallbackRegistration
);
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackServicePropertiesInitializing),
ServicePropertiesInitializingCallback,
NULL,
&ServicePropertiesInitializingCallbackRegistration
);
PhRegisterCallback(
PhGetGeneralCallback(GeneralCallbackServiceMenuInitializing),
ServiceMenuInitializingCallback,
NULL,
&ServiceMenuInitializingCallbackRegistration
);
PhAddSettings(settings, ARRAYSIZE(settings));
}
break;
}
return TRUE;
}

View File

@@ -0,0 +1,72 @@
/*
* Process Hacker Extended Services -
* options dialog
*
* 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 "extsrv.h"
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_ENABLESERVICESMENU), PhGetIntegerSetting(SETTING_NAME_ENABLE_SERVICES_MENU) ? BST_CHECKED : BST_UNCHECKED);
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDCANCEL:
EndDialog(hwndDlg, IDCANCEL);
break;
case IDOK:
{
PhSetIntegerSetting(SETTING_NAME_ENABLE_SERVICES_MENU,
Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLESERVICESMENU)) == BST_CHECKED);
EndDialog(hwndDlg, IDOK);
}
break;
}
}
break;
}
return FALSE;
}
VOID EsShowOptionsDialog(
_In_ HWND ParentWindowHandle
)
{
DialogBox(
PluginInstance->DllBase,
MAKEINTRESOURCE(IDD_OPTIONS),
ParentWindowHandle,
OptionsDlgProc
);
}

View File

@@ -0,0 +1,732 @@
/*
* Process Hacker Extended Services -
* other information
*
* 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 "extsrv.h"
typedef struct _SERVICE_OTHER_CONTEXT
{
PPH_SERVICE_ITEM ServiceItem;
struct
{
ULONG Ready : 1;
ULONG Dirty : 1;
ULONG PreshutdownTimeoutValid : 1;
ULONG RequiredPrivilegesValid : 1;
ULONG SidTypeValid : 1;
ULONG LaunchProtectedValid : 1;
};
HWND PrivilegesLv;
PPH_LIST PrivilegeList;
ULONG OriginalLaunchProtected;
} SERVICE_OTHER_CONTEXT, *PSERVICE_OTHER_CONTEXT;
static _RtlCreateServiceSid RtlCreateServiceSid_I = NULL;
static PH_KEY_VALUE_PAIR EspServiceSidTypePairs[] =
{
SIP(L"None", SERVICE_SID_TYPE_NONE),
SIP(L"Restricted", SERVICE_SID_TYPE_RESTRICTED),
SIP(L"Unrestricted", SERVICE_SID_TYPE_UNRESTRICTED)
};
static PH_KEY_VALUE_PAIR EspServiceLaunchProtectedPairs[] =
{
SIP(L"None", SERVICE_LAUNCH_PROTECTED_NONE),
SIP(L"Full (Windows)", SERVICE_LAUNCH_PROTECTED_WINDOWS),
SIP(L"Light (Windows)", SERVICE_LAUNCH_PROTECTED_WINDOWS_LIGHT),
SIP(L"Light (Antimalware)", SERVICE_LAUNCH_PROTECTED_ANTIMALWARE_LIGHT)
};
static WCHAR *EspServiceSidTypeStrings[3] = { L"None", L"Restricted", L"Unrestricted" };
static WCHAR *EspServiceLaunchProtectedStrings[4] = { L"None", L"Full (Windows)", L"Light (Windows)", L"Light (Antimalware)" };
PWSTR EspGetServiceSidTypeString(
_In_ ULONG SidType
)
{
PWSTR string;
if (PhFindStringSiKeyValuePairs(
EspServiceSidTypePairs,
sizeof(EspServiceSidTypePairs),
SidType,
&string
))
return string;
else
return L"Unknown";
}
ULONG EspGetServiceSidTypeInteger(
_In_ PWSTR SidType
)
{
ULONG integer;
if (PhFindIntegerSiKeyValuePairs(
EspServiceSidTypePairs,
sizeof(EspServiceSidTypePairs),
SidType,
&integer
))
return integer;
else
return -1;
}
PWSTR EspGetServiceLaunchProtectedString(
_In_ ULONG LaunchProtected
)
{
PWSTR string;
if (PhFindStringSiKeyValuePairs(
EspServiceLaunchProtectedPairs,
sizeof(EspServiceLaunchProtectedPairs),
LaunchProtected,
&string
))
return string;
else
return L"Unknown";
}
ULONG EspGetServiceLaunchProtectedInteger(
_In_ PWSTR LaunchProtected
)
{
ULONG integer;
if (PhFindIntegerSiKeyValuePairs(
EspServiceLaunchProtectedPairs,
sizeof(EspServiceLaunchProtectedPairs),
LaunchProtected,
&integer
))
return integer;
else
return -1;
}
NTSTATUS EspLoadOtherInfo(
_In_ HWND hwndDlg,
_In_ PSERVICE_OTHER_CONTEXT Context
)
{
NTSTATUS status = STATUS_SUCCESS;
SC_HANDLE serviceHandle;
ULONG returnLength;
SERVICE_PRESHUTDOWN_INFO preshutdownInfo;
LPSERVICE_REQUIRED_PRIVILEGES_INFO requiredPrivilegesInfo;
SERVICE_SID_INFO sidInfo;
SERVICE_LAUNCH_PROTECTED_INFO launchProtectedInfo;
if (!(serviceHandle = PhOpenService(Context->ServiceItem->Name->Buffer, SERVICE_QUERY_CONFIG)))
return NTSTATUS_FROM_WIN32(GetLastError());
// Preshutdown timeout
if (QueryServiceConfig2(serviceHandle,
SERVICE_CONFIG_PRESHUTDOWN_INFO,
(PBYTE)&preshutdownInfo,
sizeof(SERVICE_PRESHUTDOWN_INFO),
&returnLength
))
{
SetDlgItemInt(hwndDlg, IDC_PRESHUTDOWNTIMEOUT, preshutdownInfo.dwPreshutdownTimeout, FALSE);
Context->PreshutdownTimeoutValid = TRUE;
}
// Required privileges
if (requiredPrivilegesInfo = PhQueryServiceVariableSize(serviceHandle, SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO))
{
PWSTR privilege;
ULONG privilegeLength;
INT lvItemIndex;
PH_STRINGREF privilegeSr;
PPH_STRING privilegeString;
PPH_STRING displayName;
privilege = requiredPrivilegesInfo->pmszRequiredPrivileges;
if (privilege)
{
while (TRUE)
{
privilegeLength = (ULONG)PhCountStringZ(privilege);
if (privilegeLength == 0)
break;
privilegeString = PhCreateStringEx(privilege, privilegeLength * sizeof(WCHAR));
PhAddItemList(Context->PrivilegeList, privilegeString);
lvItemIndex = PhAddListViewItem(Context->PrivilegesLv, MAXINT, privilege, privilegeString);
privilegeSr.Buffer = privilege;
privilegeSr.Length = privilegeLength * sizeof(WCHAR);
if (PhLookupPrivilegeDisplayName(&privilegeSr, &displayName))
{
PhSetListViewSubItem(Context->PrivilegesLv, lvItemIndex, 1, displayName->Buffer);
PhDereferenceObject(displayName);
}
privilege += privilegeLength + 1;
}
}
ExtendedListView_SortItems(Context->PrivilegesLv);
PhFree(requiredPrivilegesInfo);
Context->RequiredPrivilegesValid = TRUE;
}
// SID type
if (QueryServiceConfig2(serviceHandle,
SERVICE_CONFIG_SERVICE_SID_INFO,
(PBYTE)&sidInfo,
sizeof(SERVICE_SID_INFO),
&returnLength
))
{
PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_SIDTYPE),
EspGetServiceSidTypeString(sidInfo.dwServiceSidType), FALSE);
Context->SidTypeValid = TRUE;
}
// Launch protected
if (QueryServiceConfig2(serviceHandle,
SERVICE_CONFIG_LAUNCH_PROTECTED,
(PBYTE)&launchProtectedInfo,
sizeof(SERVICE_LAUNCH_PROTECTED_INFO),
&returnLength
))
{
PhSelectComboBoxString(GetDlgItem(hwndDlg, IDC_PROTECTION),
EspGetServiceLaunchProtectedString(launchProtectedInfo.dwLaunchProtected), FALSE);
Context->LaunchProtectedValid = TRUE;
Context->OriginalLaunchProtected = launchProtectedInfo.dwLaunchProtected;
}
CloseServiceHandle(serviceHandle);
return status;
}
PPH_STRING EspGetServiceSidString(
_In_ PPH_STRINGREF ServiceName
)
{
PSID serviceSid = NULL;
UNICODE_STRING serviceNameUs;
ULONG serviceSidLength = 0;
PPH_STRING sidString = NULL;
if (!RtlCreateServiceSid_I)
{
if (!(RtlCreateServiceSid_I = PhGetModuleProcAddress(L"ntdll.dll", "RtlCreateServiceSid")))
return NULL;
}
PhStringRefToUnicodeString(ServiceName, &serviceNameUs);
if (RtlCreateServiceSid_I(&serviceNameUs, serviceSid, &serviceSidLength) == STATUS_BUFFER_TOO_SMALL)
{
serviceSid = PhAllocate(serviceSidLength);
if (NT_SUCCESS(RtlCreateServiceSid_I(&serviceNameUs, serviceSid, &serviceSidLength)))
sidString = PhSidToStringSid(serviceSid);
PhFree(serviceSid);
}
return sidString;
}
BOOLEAN EspChangeServiceConfig2(
_In_ PWSTR ServiceName,
_In_opt_ SC_HANDLE ServiceHandle,
_In_ ULONG InfoLevel,
_In_ PVOID Info
)
{
if (ServiceHandle)
{
return !!ChangeServiceConfig2(ServiceHandle, InfoLevel, Info);
}
else
{
NTSTATUS status;
if (NT_SUCCESS(status = PhSvcCallChangeServiceConfig2(ServiceName, InfoLevel, Info)))
{
return TRUE;
}
else
{
SetLastError(PhNtStatusToDosError(status));
return FALSE;
}
}
}
static int __cdecl PrivilegeNameCompareFunction(
_In_ const void *elem1,
_In_ const void *elem2
)
{
PWSTR string1 = *(PWSTR *)elem1;
PWSTR string2 = *(PWSTR *)elem2;
return PhCompareStringZ(string1, string2, TRUE);
}
INT_PTR CALLBACK EspServiceOtherDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
PSERVICE_OTHER_CONTEXT context;
if (uMsg == WM_INITDIALOG)
{
context = PhAllocate(sizeof(SERVICE_OTHER_CONTEXT));
memset(context, 0, sizeof(SERVICE_OTHER_CONTEXT));
SetProp(hwndDlg, L"Context", (HANDLE)context);
}
else
{
context = (PSERVICE_OTHER_CONTEXT)GetProp(hwndDlg, L"Context");
if (uMsg == WM_DESTROY)
RemoveProp(hwndDlg, L"Context");
}
if (!context)
return FALSE;
switch (uMsg)
{
case WM_INITDIALOG:
{
NTSTATUS status;
LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam;
PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)propSheetPage->lParam;
HWND privilegesLv;
context->ServiceItem = serviceItem;
context->PrivilegesLv = privilegesLv = GetDlgItem(hwndDlg, IDC_PRIVILEGES);
PhSetListViewStyle(privilegesLv, FALSE, TRUE);
PhSetControlTheme(privilegesLv, L"explorer");
PhAddListViewColumn(privilegesLv, 0, 0, 0, LVCFMT_LEFT, 140, L"Name");
PhAddListViewColumn(privilegesLv, 1, 1, 1, LVCFMT_LEFT, 220, L"Display name");
PhSetExtendedListView(privilegesLv);
context->PrivilegeList = PhCreateList(32);
if (context->ServiceItem->Type == SERVICE_KERNEL_DRIVER || context->ServiceItem->Type == SERVICE_FILE_SYSTEM_DRIVER)
{
// Drivers don't support required privileges.
EnableWindow(GetDlgItem(hwndDlg, IDC_ADD), FALSE);
}
EnableWindow(GetDlgItem(hwndDlg, IDC_REMOVE), FALSE);
PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_SIDTYPE),
EspServiceSidTypeStrings, sizeof(EspServiceSidTypeStrings) / sizeof(PWSTR));
PhAddComboBoxStrings(GetDlgItem(hwndDlg, IDC_PROTECTION),
EspServiceLaunchProtectedStrings, sizeof(EspServiceLaunchProtectedStrings) / sizeof(PWSTR));
if (WindowsVersion < WINDOWS_8_1)
EnableWindow(GetDlgItem(hwndDlg, IDC_PROTECTION), FALSE);
SetDlgItemText(hwndDlg, IDC_SERVICESID,
PhGetStringOrDefault(PH_AUTO(EspGetServiceSidString(&serviceItem->Name->sr)), L"N/A"));
status = EspLoadOtherInfo(hwndDlg, context);
if (!NT_SUCCESS(status))
{
PhShowWarning(hwndDlg, L"Unable to query service information: %s",
((PPH_STRING)PH_AUTO(PhGetNtMessage(status)))->Buffer);
}
context->Ready = TRUE;
}
break;
case WM_DESTROY:
{
if (context->PrivilegeList)
{
PhDereferenceObjects(context->PrivilegeList->Items, context->PrivilegeList->Count);
PhDereferenceObject(context->PrivilegeList);
}
PhFree(context);
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDC_ADD:
{
NTSTATUS status;
LSA_HANDLE policyHandle;
LSA_ENUMERATION_HANDLE enumContext;
PPOLICY_PRIVILEGE_DEFINITION buffer;
ULONG count;
ULONG i;
PPH_LIST choices;
PPH_STRING selectedChoice = NULL;
choices = PH_AUTO(PhCreateList(100));
if (!NT_SUCCESS(status = PhOpenLsaPolicy(&policyHandle, POLICY_VIEW_LOCAL_INFORMATION, NULL)))
{
PhShowStatus(hwndDlg, L"Unable to open LSA policy", status, 0);
break;
}
enumContext = 0;
while (TRUE)
{
status = LsaEnumeratePrivileges(
policyHandle,
&enumContext,
&buffer,
0x100,
&count
);
if (status == STATUS_NO_MORE_ENTRIES)
break;
if (!NT_SUCCESS(status))
break;
for (i = 0; i < count; i++)
{
PhAddItemList(choices, PhaCreateStringEx(buffer[i].Name.Buffer, buffer[i].Name.Length)->Buffer);
}
LsaFreeMemory(buffer);
}
LsaClose(policyHandle);
qsort(choices->Items, choices->Count, sizeof(PWSTR), PrivilegeNameCompareFunction);
while (PhaChoiceDialog(
hwndDlg,
L"Add privilege",
L"Select a privilege to add:",
(PWSTR *)choices->Items,
choices->Count,
NULL,
PH_CHOICE_DIALOG_CHOICE,
&selectedChoice,
NULL,
NULL
))
{
BOOLEAN found = FALSE;
PPH_STRING privilegeString;
INT lvItemIndex;
PPH_STRING displayName;
// Check for duplicates.
for (i = 0; i < context->PrivilegeList->Count; i++)
{
if (PhEqualString(context->PrivilegeList->Items[i], selectedChoice, FALSE))
{
found = TRUE;
break;
}
}
if (found)
{
if (PhShowMessage(
hwndDlg,
MB_OKCANCEL | MB_ICONERROR,
L"The selected privilege has already been added."
) == IDOK)
{
continue;
}
else
{
break;
}
}
PhSetReference(&privilegeString, selectedChoice);
PhAddItemList(context->PrivilegeList, privilegeString);
lvItemIndex = PhAddListViewItem(context->PrivilegesLv, MAXINT, privilegeString->Buffer, privilegeString);
if (PhLookupPrivilegeDisplayName(&privilegeString->sr, &displayName))
{
PhSetListViewSubItem(context->PrivilegesLv, lvItemIndex, 1, displayName->Buffer);
PhDereferenceObject(displayName);
}
ExtendedListView_SortItems(context->PrivilegesLv);
context->Dirty = TRUE;
context->RequiredPrivilegesValid = TRUE;
break;
}
}
break;
case IDC_REMOVE:
{
INT lvItemIndex;
PPH_STRING privilegeString;
ULONG index;
lvItemIndex = ListView_GetNextItem(context->PrivilegesLv, -1, LVNI_SELECTED);
if (lvItemIndex != -1 && PhGetListViewItemParam(context->PrivilegesLv, lvItemIndex, (PVOID *)&privilegeString))
{
index = PhFindItemList(context->PrivilegeList, privilegeString);
if (index != -1)
{
PhDereferenceObject(privilegeString);
PhRemoveItemList(context->PrivilegeList, index);
PhRemoveListViewItem(context->PrivilegesLv, lvItemIndex);
context->Dirty = TRUE;
context->RequiredPrivilegesValid = TRUE;
}
}
}
break;
}
switch (HIWORD(wParam))
{
case EN_CHANGE:
case CBN_SELCHANGE:
{
if (context->Ready)
{
context->Dirty = TRUE;
switch (LOWORD(wParam))
{
case IDC_PRESHUTDOWNTIMEOUT:
context->PreshutdownTimeoutValid = TRUE;
break;
case IDC_SIDTYPE:
context->SidTypeValid = TRUE;
break;
case IDC_PROTECTION:
context->LaunchProtectedValid = TRUE;
break;
}
}
}
break;
}
}
break;
case WM_NOTIFY:
{
LPNMHDR header = (LPNMHDR)lParam;
switch (header->code)
{
case PSN_KILLACTIVE:
{
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, FALSE);
}
return TRUE;
case PSN_APPLY:
{
SC_HANDLE serviceHandle = NULL;
ULONG win32Result = 0;
BOOLEAN connectedToPhSvc = FALSE;
PPH_STRING launchProtectedString;
ULONG launchProtected;
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
launchProtectedString = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_PROTECTION)));
launchProtected = EspGetServiceLaunchProtectedInteger(launchProtectedString->Buffer);
if (context->LaunchProtectedValid && launchProtected != 0 && launchProtected != context->OriginalLaunchProtected)
{
if (PhShowMessage(
hwndDlg,
MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2,
L"Setting service protection will prevent the service from being controlled, modified, or deleted. Do you want to continue?"
) == IDNO)
{
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID);
return TRUE;
}
}
if (context->Dirty)
{
SERVICE_PRESHUTDOWN_INFO preshutdownInfo;
SERVICE_REQUIRED_PRIVILEGES_INFO requiredPrivilegesInfo;
SERVICE_SID_INFO sidInfo;
SERVICE_LAUNCH_PROTECTED_INFO launchProtectedInfo;
if (!(serviceHandle = PhOpenService(context->ServiceItem->Name->Buffer, SERVICE_CHANGE_CONFIG)))
{
win32Result = GetLastError();
if (win32Result == ERROR_ACCESS_DENIED && !PhGetOwnTokenAttributes().Elevated)
{
// Elevate using phsvc.
if (PhUiConnectToPhSvc(hwndDlg, FALSE))
{
win32Result = 0;
connectedToPhSvc = TRUE;
}
else
{
// User cancelled elevation.
win32Result = ERROR_CANCELLED;
goto Done;
}
}
else
{
goto Done;
}
}
if (context->PreshutdownTimeoutValid)
{
preshutdownInfo.dwPreshutdownTimeout = GetDlgItemInt(hwndDlg, IDC_PRESHUTDOWNTIMEOUT, NULL, FALSE);
if (!EspChangeServiceConfig2(context->ServiceItem->Name->Buffer, serviceHandle,
SERVICE_CONFIG_PRESHUTDOWN_INFO, &preshutdownInfo))
{
win32Result = GetLastError();
}
}
if (context->RequiredPrivilegesValid)
{
PH_STRING_BUILDER sb;
ULONG i;
PhInitializeStringBuilder(&sb, 100);
for (i = 0; i < context->PrivilegeList->Count; i++)
{
PhAppendStringBuilder(&sb, &((PPH_STRING)context->PrivilegeList->Items[i])->sr);
PhAppendCharStringBuilder(&sb, 0);
}
requiredPrivilegesInfo.pmszRequiredPrivileges = sb.String->Buffer;
if (win32Result == 0 && !EspChangeServiceConfig2(context->ServiceItem->Name->Buffer, serviceHandle,
SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO, &requiredPrivilegesInfo))
{
win32Result = GetLastError();
}
PhDeleteStringBuilder(&sb);
}
if (context->SidTypeValid)
{
PPH_STRING sidTypeString;
sidTypeString = PH_AUTO(PhGetWindowText(GetDlgItem(hwndDlg, IDC_SIDTYPE)));
sidInfo.dwServiceSidType = EspGetServiceSidTypeInteger(sidTypeString->Buffer);
if (win32Result == 0 && !EspChangeServiceConfig2(context->ServiceItem->Name->Buffer, serviceHandle,
SERVICE_CONFIG_SERVICE_SID_INFO, &sidInfo))
{
win32Result = GetLastError();
}
}
if (context->LaunchProtectedValid)
{
launchProtectedInfo.dwLaunchProtected = launchProtected;
if (!EspChangeServiceConfig2(context->ServiceItem->Name->Buffer, serviceHandle,
SERVICE_CONFIG_LAUNCH_PROTECTED, &launchProtectedInfo))
{
// For now, ignore errors here.
// win32Result = GetLastError();
}
}
Done:
if (connectedToPhSvc)
PhUiDisconnectFromPhSvc();
if (serviceHandle)
CloseServiceHandle(serviceHandle);
if (win32Result != 0)
{
if (win32Result == ERROR_CANCELLED || PhShowMessage(
hwndDlg,
MB_ICONERROR | MB_RETRYCANCEL,
L"Unable to change service information: %s",
((PPH_STRING)PH_AUTO(PhGetWin32Message(win32Result)))->Buffer
) == IDRETRY)
{
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID);
}
}
}
return TRUE;
}
break;
case LVN_ITEMCHANGED:
{
if (header->hwndFrom == context->PrivilegesLv)
{
EnableWindow(GetDlgItem(hwndDlg, IDC_REMOVE), ListView_GetSelectedCount(context->PrivilegesLv) == 1);
}
}
break;
}
}
break;
}
return FALSE;
}

View File

@@ -0,0 +1,709 @@
/*
* Process Hacker Extended Services -
* recovery information
*
* 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 "extsrv.h"
typedef struct _SERVICE_RECOVERY_CONTEXT
{
PPH_SERVICE_ITEM ServiceItem;
ULONG NumberOfActions;
BOOLEAN EnableFlagCheckBox;
ULONG RebootAfter; // in ms
PPH_STRING RebootMessage;
BOOLEAN Ready;
BOOLEAN Dirty;
} SERVICE_RECOVERY_CONTEXT, *PSERVICE_RECOVERY_CONTEXT;
static PH_KEY_VALUE_PAIR ServiceActionPairs[] =
{
SIP(L"Take no action", SC_ACTION_NONE),
SIP(L"Restart the service", SC_ACTION_RESTART),
SIP(L"Run a program", SC_ACTION_RUN_COMMAND),
SIP(L"Restart the computer", SC_ACTION_REBOOT)
};
INT_PTR CALLBACK RestartComputerDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
VOID EspAddServiceActionStrings(
_In_ HWND ComboBoxHandle
)
{
ULONG i;
for (i = 0; i < sizeof(ServiceActionPairs) / sizeof(PH_KEY_VALUE_PAIR); i++)
ComboBox_AddString(ComboBoxHandle, (PWSTR)ServiceActionPairs[i].Key);
PhSelectComboBoxString(ComboBoxHandle, (PWSTR)ServiceActionPairs[0].Key, FALSE);
}
SC_ACTION_TYPE EspStringToServiceAction(
_In_ PWSTR String
)
{
ULONG integer;
if (PhFindIntegerSiKeyValuePairs(ServiceActionPairs, sizeof(ServiceActionPairs), String, &integer))
return integer;
else
return 0;
}
PWSTR EspServiceActionToString(
_In_ SC_ACTION_TYPE ActionType
)
{
PWSTR string;
if (PhFindStringSiKeyValuePairs(ServiceActionPairs, sizeof(ServiceActionPairs), ActionType, &string))
return string;
else
return NULL;
}
SC_ACTION_TYPE ComboBoxToServiceAction(
_In_ HWND ComboBoxHandle
)
{
PPH_STRING string;
string = PH_AUTO(PhGetComboBoxString(ComboBoxHandle, ComboBox_GetCurSel(ComboBoxHandle)));
if (!string)
return SC_ACTION_NONE;
return EspStringToServiceAction(string->Buffer);
}
VOID ServiceActionToComboBox(
_In_ HWND ComboBoxHandle,
_In_ SC_ACTION_TYPE ActionType
)
{
PWSTR string;
if (string = EspServiceActionToString(ActionType))
PhSelectComboBoxString(ComboBoxHandle, string, FALSE);
else
PhSelectComboBoxString(ComboBoxHandle, (PWSTR)ServiceActionPairs[0].Key, FALSE);
}
VOID EspFixControls(
_In_ HWND hwndDlg,
_In_ PSERVICE_RECOVERY_CONTEXT Context
)
{
SC_ACTION_TYPE action1;
SC_ACTION_TYPE action2;
SC_ACTION_TYPE actionS;
BOOLEAN enableRestart;
BOOLEAN enableReboot;
BOOLEAN enableCommand;
action1 = ComboBoxToServiceAction(GetDlgItem(hwndDlg, IDC_FIRSTFAILURE));
action2 = ComboBoxToServiceAction(GetDlgItem(hwndDlg, IDC_SECONDFAILURE));
actionS = ComboBoxToServiceAction(GetDlgItem(hwndDlg, IDC_SUBSEQUENTFAILURES));
EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLEFORERRORSTOPS), Context->EnableFlagCheckBox);
enableRestart = action1 == SC_ACTION_RESTART || action2 == SC_ACTION_RESTART || actionS == SC_ACTION_RESTART;
enableReboot = action1 == SC_ACTION_REBOOT || action2 == SC_ACTION_REBOOT || actionS == SC_ACTION_REBOOT;
enableCommand = action1 == SC_ACTION_RUN_COMMAND || action2 == SC_ACTION_RUN_COMMAND || actionS == SC_ACTION_RUN_COMMAND;
EnableWindow(GetDlgItem(hwndDlg, IDC_RESTARTSERVICEAFTER_LABEL), enableRestart);
EnableWindow(GetDlgItem(hwndDlg, IDC_RESTARTSERVICEAFTER), enableRestart);
EnableWindow(GetDlgItem(hwndDlg, IDC_RESTARTSERVICEAFTER_MINUTES), enableRestart);
EnableWindow(GetDlgItem(hwndDlg, IDC_RESTARTCOMPUTEROPTIONS), enableReboot);
EnableWindow(GetDlgItem(hwndDlg, IDC_RUNPROGRAM_GROUP), enableCommand);
EnableWindow(GetDlgItem(hwndDlg, IDC_RUNPROGRAM_LABEL), enableCommand);
EnableWindow(GetDlgItem(hwndDlg, IDC_RUNPROGRAM), enableCommand);
EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE), enableCommand);
EnableWindow(GetDlgItem(hwndDlg, IDC_RUNPROGRAM_INFO), enableCommand);
}
NTSTATUS EspLoadRecoveryInfo(
_In_ HWND hwndDlg,
_In_ PSERVICE_RECOVERY_CONTEXT Context
)
{
NTSTATUS status = STATUS_SUCCESS;
SC_HANDLE serviceHandle;
LPSERVICE_FAILURE_ACTIONS failureActions;
SERVICE_FAILURE_ACTIONS_FLAG failureActionsFlag;
SC_ACTION_TYPE lastType;
ULONG returnLength;
ULONG i;
if (!(serviceHandle = PhOpenService(Context->ServiceItem->Name->Buffer, SERVICE_QUERY_CONFIG)))
return NTSTATUS_FROM_WIN32(GetLastError());
if (!(failureActions = PhQueryServiceVariableSize(serviceHandle, SERVICE_CONFIG_FAILURE_ACTIONS)))
{
CloseServiceHandle(serviceHandle);
return NTSTATUS_FROM_WIN32(GetLastError());
}
// Failure action types
Context->NumberOfActions = failureActions->cActions;
if (failureActions->cActions != 0 && failureActions->cActions != 3)
status = STATUS_SOME_NOT_MAPPED;
// If failure actions are not defined for a particular fail count, the
// last failure action is used. Here we duplicate this behaviour when there
// are fewer than 3 failure actions.
lastType = SC_ACTION_NONE;
ServiceActionToComboBox(GetDlgItem(hwndDlg, IDC_FIRSTFAILURE),
failureActions->cActions >= 1 ? (lastType = failureActions->lpsaActions[0].Type) : lastType);
ServiceActionToComboBox(GetDlgItem(hwndDlg, IDC_SECONDFAILURE),
failureActions->cActions >= 2 ? (lastType = failureActions->lpsaActions[1].Type) : lastType);
ServiceActionToComboBox(GetDlgItem(hwndDlg, IDC_SUBSEQUENTFAILURES),
failureActions->cActions >= 3 ? (lastType = failureActions->lpsaActions[2].Type) : lastType);
// Reset fail count after
SetDlgItemInt(hwndDlg, IDC_RESETFAILCOUNT, failureActions->dwResetPeriod / (60 * 60 * 24), FALSE); // s to days
// Restart service after
SetDlgItemText(hwndDlg, IDC_RESTARTSERVICEAFTER, L"1");
for (i = 0; i < failureActions->cActions; i++)
{
if (failureActions->lpsaActions[i].Type == SC_ACTION_RESTART)
{
if (failureActions->lpsaActions[i].Delay != 0)
{
SetDlgItemInt(hwndDlg, IDC_RESTARTSERVICEAFTER,
failureActions->lpsaActions[i].Delay / (1000 * 60), FALSE); // ms to min
}
break;
}
}
// Enable actions for stops with errors
// This is Vista and above only.
if (WindowsVersion >= WINDOWS_VISTA && QueryServiceConfig2(
serviceHandle,
SERVICE_CONFIG_FAILURE_ACTIONS_FLAG,
(BYTE *)&failureActionsFlag,
sizeof(SERVICE_FAILURE_ACTIONS_FLAG),
&returnLength
))
{
Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLEFORERRORSTOPS),
failureActionsFlag.fFailureActionsOnNonCrashFailures ? BST_CHECKED : BST_UNCHECKED);
Context->EnableFlagCheckBox = TRUE;
}
else
{
Context->EnableFlagCheckBox = FALSE;
}
// Restart computer options
Context->RebootAfter = 1 * 1000 * 60;
for (i = 0; i < failureActions->cActions; i++)
{
if (failureActions->lpsaActions[i].Type == SC_ACTION_REBOOT)
{
if (failureActions->lpsaActions[i].Delay != 0)
Context->RebootAfter = failureActions->lpsaActions[i].Delay;
break;
}
}
if (failureActions->lpRebootMsg && failureActions->lpRebootMsg[0] != 0)
PhMoveReference(&Context->RebootMessage, PhCreateString(failureActions->lpRebootMsg));
else
PhClearReference(&Context->RebootMessage);
// Run program
SetDlgItemText(hwndDlg, IDC_RUNPROGRAM, failureActions->lpCommand);
PhFree(failureActions);
CloseServiceHandle(serviceHandle);
return status;
}
INT_PTR CALLBACK EspServiceRecoveryDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
PSERVICE_RECOVERY_CONTEXT context;
if (uMsg == WM_INITDIALOG)
{
context = PhAllocate(sizeof(SERVICE_RECOVERY_CONTEXT));
memset(context, 0, sizeof(SERVICE_RECOVERY_CONTEXT));
SetProp(hwndDlg, L"Context", (HANDLE)context);
}
else
{
context = (PSERVICE_RECOVERY_CONTEXT)GetProp(hwndDlg, L"Context");
if (uMsg == WM_DESTROY)
RemoveProp(hwndDlg, L"Context");
}
if (!context)
return FALSE;
switch (uMsg)
{
case WM_INITDIALOG:
{
NTSTATUS status;
LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam;
PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)propSheetPage->lParam;
context->ServiceItem = serviceItem;
EspAddServiceActionStrings(GetDlgItem(hwndDlg, IDC_FIRSTFAILURE));
EspAddServiceActionStrings(GetDlgItem(hwndDlg, IDC_SECONDFAILURE));
EspAddServiceActionStrings(GetDlgItem(hwndDlg, IDC_SUBSEQUENTFAILURES));
status = EspLoadRecoveryInfo(hwndDlg, context);
if (status == STATUS_SOME_NOT_MAPPED)
{
if (context->NumberOfActions > 3)
{
PhShowWarning(
hwndDlg,
L"The service has %lu failure actions configured, but this program only supports editing 3. "
L"If you save the recovery information using this program, the additional failure actions will be lost.",
context->NumberOfActions
);
}
}
else if (!NT_SUCCESS(status))
{
SetDlgItemText(hwndDlg, IDC_RESETFAILCOUNT, L"0");
if (WindowsVersion >= WINDOWS_VISTA)
{
context->EnableFlagCheckBox = TRUE;
EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLEFORERRORSTOPS), TRUE);
}
PhShowWarning(hwndDlg, L"Unable to query service recovery information: %s",
((PPH_STRING)PH_AUTO(PhGetNtMessage(status)))->Buffer);
}
EspFixControls(hwndDlg, context);
context->Ready = TRUE;
}
break;
case WM_DESTROY:
{
PhClearReference(&context->RebootMessage);
PhFree(context);
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDC_FIRSTFAILURE:
case IDC_SECONDFAILURE:
case IDC_SUBSEQUENTFAILURES:
{
if (HIWORD(wParam) == CBN_SELCHANGE)
{
EspFixControls(hwndDlg, context);
}
}
break;
case IDC_RESTARTCOMPUTEROPTIONS:
{
DialogBoxParam(
PluginInstance->DllBase,
MAKEINTRESOURCE(IDD_RESTARTCOMP),
hwndDlg,
RestartComputerDlgProc,
(LPARAM)context
);
}
break;
case IDC_BROWSE:
{
static PH_FILETYPE_FILTER filters[] =
{
{ L"Executable files (*.exe;*.cmd;*.bat)", L"*.exe;*.cmd;*.bat" },
{ L"All files (*.*)", L"*.*" }
};
PVOID fileDialog;
PPH_STRING fileName;
fileDialog = PhCreateOpenFileDialog();
PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER));
fileName = PhaGetDlgItemText(hwndDlg, IDC_RUNPROGRAM);
PhSetFileDialogFileName(fileDialog, fileName->Buffer);
if (PhShowFileDialog(hwndDlg, fileDialog))
{
fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog));
SetDlgItemText(hwndDlg, IDC_RUNPROGRAM, fileName->Buffer);
}
PhFreeFileDialog(fileDialog);
}
break;
case IDC_ENABLEFORERRORSTOPS:
{
context->Dirty = TRUE;
}
break;
}
switch (HIWORD(wParam))
{
case EN_CHANGE:
case CBN_SELCHANGE:
{
if (context->Ready)
context->Dirty = TRUE;
}
break;
}
}
break;
case WM_NOTIFY:
{
LPNMHDR header = (LPNMHDR)lParam;
switch (header->code)
{
case PSN_KILLACTIVE:
{
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, FALSE);
}
return TRUE;
case PSN_APPLY:
{
NTSTATUS status;
PPH_SERVICE_ITEM serviceItem = context->ServiceItem;
SC_HANDLE serviceHandle;
ULONG restartServiceAfter;
SERVICE_FAILURE_ACTIONS failureActions;
SC_ACTION actions[3];
ULONG i;
BOOLEAN enableRestart = FALSE;
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
if (!context->Dirty)
{
return TRUE;
}
// Build the failure actions structure.
failureActions.dwResetPeriod = GetDlgItemInt(hwndDlg, IDC_RESETFAILCOUNT, NULL, FALSE) * 60 * 60 * 24;
failureActions.lpRebootMsg = PhGetStringOrEmpty(context->RebootMessage);
failureActions.lpCommand = PhaGetDlgItemText(hwndDlg, IDC_RUNPROGRAM)->Buffer;
failureActions.cActions = 3;
failureActions.lpsaActions = actions;
actions[0].Type = ComboBoxToServiceAction(GetDlgItem(hwndDlg, IDC_FIRSTFAILURE));
actions[1].Type = ComboBoxToServiceAction(GetDlgItem(hwndDlg, IDC_SECONDFAILURE));
actions[2].Type = ComboBoxToServiceAction(GetDlgItem(hwndDlg, IDC_SUBSEQUENTFAILURES));
restartServiceAfter = GetDlgItemInt(hwndDlg, IDC_RESTARTSERVICEAFTER, NULL, FALSE) * 1000 * 60;
for (i = 0; i < 3; i++)
{
switch (actions[i].Type)
{
case SC_ACTION_RESTART:
actions[i].Delay = restartServiceAfter;
enableRestart = TRUE;
break;
case SC_ACTION_REBOOT:
actions[i].Delay = context->RebootAfter;
break;
case SC_ACTION_RUN_COMMAND:
actions[i].Delay = 0;
break;
}
}
// Try to save the changes.
serviceHandle = PhOpenService(
serviceItem->Name->Buffer,
SERVICE_CHANGE_CONFIG | (enableRestart ? SERVICE_START : 0) // SC_ACTION_RESTART requires SERVICE_START
);
if (serviceHandle)
{
if (ChangeServiceConfig2(
serviceHandle,
SERVICE_CONFIG_FAILURE_ACTIONS,
&failureActions
))
{
if (context->EnableFlagCheckBox)
{
SERVICE_FAILURE_ACTIONS_FLAG failureActionsFlag;
failureActionsFlag.fFailureActionsOnNonCrashFailures =
Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLEFORERRORSTOPS)) == BST_CHECKED;
ChangeServiceConfig2(
serviceHandle,
SERVICE_CONFIG_FAILURE_ACTIONS_FLAG,
&failureActionsFlag
);
}
CloseServiceHandle(serviceHandle);
}
else
{
CloseServiceHandle(serviceHandle);
goto ErrorCase;
}
}
else
{
if (GetLastError() == ERROR_ACCESS_DENIED && !PhGetOwnTokenAttributes().Elevated)
{
// Elevate using phsvc.
if (PhUiConnectToPhSvc(hwndDlg, FALSE))
{
if (NT_SUCCESS(status = PhSvcCallChangeServiceConfig2(
serviceItem->Name->Buffer,
SERVICE_CONFIG_FAILURE_ACTIONS,
&failureActions
)))
{
if (context->EnableFlagCheckBox)
{
SERVICE_FAILURE_ACTIONS_FLAG failureActionsFlag;
failureActionsFlag.fFailureActionsOnNonCrashFailures =
Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLEFORERRORSTOPS)) == BST_CHECKED;
PhSvcCallChangeServiceConfig2(
serviceItem->Name->Buffer,
SERVICE_CONFIG_FAILURE_ACTIONS_FLAG,
&failureActionsFlag
);
}
}
PhUiDisconnectFromPhSvc();
if (!NT_SUCCESS(status))
{
SetLastError(PhNtStatusToDosError(status));
goto ErrorCase;
}
}
else
{
// User cancelled elevation.
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID);
}
}
else
{
goto ErrorCase;
}
}
return TRUE;
ErrorCase:
if (PhShowMessage(
hwndDlg,
MB_ICONERROR | MB_RETRYCANCEL,
L"Unable to change service recovery information: %s",
((PPH_STRING)PH_AUTO(PhGetWin32Message(GetLastError())))->Buffer
) == IDRETRY)
{
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID);
}
}
return TRUE;
}
}
break;
}
return FALSE;
}
INT_PTR CALLBACK EspServiceRecovery2DlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
return FALSE;
}
INT_PTR CALLBACK RestartComputerDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
PSERVICE_RECOVERY_CONTEXT context;
if (uMsg == WM_INITDIALOG)
{
context = (PSERVICE_RECOVERY_CONTEXT)lParam;
SetProp(hwndDlg, L"Context", (HANDLE)context);
}
else
{
context = (PSERVICE_RECOVERY_CONTEXT)GetProp(hwndDlg, L"Context");
if (uMsg == WM_DESTROY)
RemoveProp(hwndDlg, L"Context");
}
if (!context)
return FALSE;
switch (uMsg)
{
case WM_INITDIALOG:
{
PhCenterWindow(hwndDlg, GetParent(hwndDlg));
SetDlgItemInt(hwndDlg, IDC_RESTARTCOMPAFTER, context->RebootAfter / (1000 * 60), FALSE); // ms to min
Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLERESTARTMESSAGE), context->RebootMessage ? BST_CHECKED : BST_UNCHECKED);
SetDlgItemText(hwndDlg, IDC_RESTARTMESSAGE, PhGetString(context->RebootMessage));
SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_RESTARTCOMPAFTER), TRUE);
Edit_SetSel(GetDlgItem(hwndDlg, IDC_RESTARTCOMPAFTER), 0, -1);
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDCANCEL:
EndDialog(hwndDlg, IDCANCEL);
break;
case IDOK:
{
context->RebootAfter = GetDlgItemInt(hwndDlg, IDC_RESTARTCOMPAFTER, NULL, FALSE) * 1000 * 60;
if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLERESTARTMESSAGE)) == BST_CHECKED)
PhMoveReference(&context->RebootMessage, PhGetWindowText(GetDlgItem(hwndDlg, IDC_RESTARTMESSAGE)));
else
PhClearReference(&context->RebootMessage);
context->Dirty = TRUE;
EndDialog(hwndDlg, IDOK);
}
break;
case IDC_USEDEFAULTMESSAGE:
{
PPH_STRING message;
PWSTR computerName;
ULONG bufferSize;
BOOLEAN allocated = TRUE;
// Get the computer name.
bufferSize = 64;
computerName = PhAllocate((bufferSize + 1) * sizeof(WCHAR));
if (!GetComputerName(computerName, &bufferSize))
{
PhFree(computerName);
computerName = PhAllocate((bufferSize + 1) * sizeof(WCHAR));
if (!GetComputerName(computerName, &bufferSize))
{
PhFree(computerName);
computerName = L"(unknown)";
allocated = FALSE;
}
}
// This message is exactly the same as the one in the Services console,
// except the double spaces are replaced by single spaces.
message = PhaFormatString(
L"Your computer is connected to the computer named %s. "
L"The %s service on %s has ended unexpectedly. "
L"%s will restart automatically, and then you can reestablish the connection.",
computerName,
context->ServiceItem->Name->Buffer,
computerName,
computerName
);
SetDlgItemText(hwndDlg, IDC_RESTARTMESSAGE, message->Buffer);
if (allocated)
PhFree(computerName);
Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLERESTARTMESSAGE), BST_CHECKED);
}
break;
case IDC_RESTARTMESSAGE:
{
if (HIWORD(wParam) == EN_CHANGE)
{
// A zero length restart message disables it, so we might as well uncheck the box.
Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLERESTARTMESSAGE),
GetWindowTextLength(GetDlgItem(hwndDlg, IDC_RESTARTMESSAGE)) != 0 ? BST_CHECKED : BST_UNCHECKED);
}
}
break;
}
}
break;
}
return FALSE;
}

View File

@@ -0,0 +1,73 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by ExtendedServices.rc
//
#define IDD_SVCLIST 101
#define IDD_SRVLIST 101
#define ID_SERVICE_RESTART 101
#define IDD_SRVRECOVERY 102
#define ID_SERVICE_START 102
#define IDD_RESTARTCOMP 103
#define ID_SERVICE_STOP 103
#define IDD_SRVRECOVERY2 104
#define ID_SERVICE_GOTOSERVICE 104
#define IDD_SRVPROGRESS 105
#define ID_SERVICE_CONTINUE 105
#define IDD_SRVOTHER 106
#define ID_SERVICE_PAUSE 106
#define IDD_OPTIONS 107
#define IDD_SRVTRIGGER 108
#define IDD_VALUE 109
#define IDD_SRVTRIGGERS 110
#define IDC_SERVICES_LAYOUT 1001
#define IDC_MESSAGE 1002
#define IDC_FIRSTFAILURE 1003
#define IDC_SECONDFAILURE 1004
#define IDC_SUBSEQUENTFAILURES 1005
#define IDC_RESETFAILCOUNT 1006
#define IDC_RESTARTSERVICEAFTER 1007
#define IDC_RESTARTSERVICEAFTER_LABEL 1008
#define IDC_RESTARTSERVICEAFTER_MINUTES 1009
#define IDC_ENABLEFORERRORSTOPS 1011
#define IDC_RESTARTCOMPUTEROPTIONS 1012
#define IDC_RUNPROGRAM 1014
#define IDC_BROWSE 1015
#define IDC_RESTARTCOMPAFTER 1016
#define IDC_ENABLERESTARTMESSAGE 1017
#define IDC_RESTARTMESSAGE 1018
#define IDC_RUNPROGRAM_GROUP 1019
#define IDC_RUNPROGRAM_LABEL 1020
#define IDC_RUNPROGRAM_INFO 1021
#define IDC_USEDEFAULTMESSAGE 1022
#define IDC_PROGRESS 1023
#define IDC_PRESHUTDOWNTIMEOUT 1024
#define IDC_PRIVILEGES 1025
#define IDC_TRIGGERS 1026
#define IDC_TRIGGERS_LABEL 1027
#define IDC_ENABLESERVICESMENU 1028
#define IDC_TYPE 1029
#define IDC_SUBTYPE 1030
#define IDC_SUBTYPECUSTOM 1031
#define IDC_ACTION 1032
#define IDC_LIST 1033
#define IDC_NEW 1034
#define IDC_EDIT 1035
#define IDC_DELETE 1037
#define IDC_VALUES 1038
#define IDC_REMOVE 1042
#define IDC_ADD 1043
#define IDC_SERVICESID 1044
#define IDC_SIDTYPE 1045
#define IDC_COMBO2 1046
#define IDC_PROTECTION 1046
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 111
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1047
#define _APS_NEXT_SYMED_VALUE 107
#endif
#endif

View File

@@ -0,0 +1,151 @@
/*
* Process Hacker Extended Services -
* progress 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 "extsrv.h"
typedef struct _RESTART_SERVICE_CONTEXT
{
PPH_SERVICE_ITEM ServiceItem;
SC_HANDLE ServiceHandle;
BOOLEAN Starting;
BOOLEAN DisableTimer;
} RESTART_SERVICE_CONTEXT, *PRESTART_SERVICE_CONTEXT;
INT_PTR CALLBACK EspRestartServiceDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
PRESTART_SERVICE_CONTEXT context;
if (uMsg == WM_INITDIALOG)
{
context = (PRESTART_SERVICE_CONTEXT)lParam;
SetProp(hwndDlg, L"Context", (HANDLE)context);
}
else
{
context = (PRESTART_SERVICE_CONTEXT)GetProp(hwndDlg, L"Context");
if (uMsg == WM_DESTROY)
RemoveProp(hwndDlg, L"Context");
}
if (!context)
return FALSE;
switch (uMsg)
{
case WM_INITDIALOG:
{
PhCenterWindow(hwndDlg, GetParent(hwndDlg));
// TODO: Use the progress information.
PhSetWindowStyle(GetDlgItem(hwndDlg, IDC_PROGRESS), PBS_MARQUEE, PBS_MARQUEE);
SendMessage(GetDlgItem(hwndDlg, IDC_PROGRESS), PBM_SETMARQUEE, TRUE, 75);
SetDlgItemText(hwndDlg, IDC_MESSAGE, PhaFormatString(L"Attempting to stop %s...", context->ServiceItem->Name->Buffer)->Buffer);
if (PhUiStopService(hwndDlg, context->ServiceItem))
{
SetTimer(hwndDlg, 1, 250, NULL);
}
else
{
EndDialog(hwndDlg, IDCANCEL);
}
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDCANCEL:
{
EndDialog(hwndDlg, IDCANCEL);
}
break;
}
}
break;
case WM_TIMER:
{
if (wParam == 1 && !context->DisableTimer)
{
SERVICE_STATUS serviceStatus;
if (QueryServiceStatus(context->ServiceHandle, &serviceStatus))
{
if (!context->Starting && serviceStatus.dwCurrentState == SERVICE_STOPPED)
{
// The service is stopped, so start the service now.
SetDlgItemText(hwndDlg, IDC_MESSAGE,
PhaFormatString(L"Attempting to start %s...", context->ServiceItem->Name->Buffer)->Buffer);
context->DisableTimer = TRUE;
if (PhUiStartService(hwndDlg, context->ServiceItem))
{
context->DisableTimer = FALSE;
context->Starting = TRUE;
}
else
{
EndDialog(hwndDlg, IDCANCEL);
}
}
else if (context->Starting && serviceStatus.dwCurrentState == SERVICE_RUNNING)
{
EndDialog(hwndDlg, IDOK);
}
}
}
}
break;
}
return FALSE;
}
VOID EsRestartServiceWithProgress(
_In_ HWND hWnd,
_In_ PPH_SERVICE_ITEM ServiceItem,
_In_ SC_HANDLE ServiceHandle
)
{
RESTART_SERVICE_CONTEXT context;
context.ServiceItem = ServiceItem;
context.ServiceHandle = ServiceHandle;
context.Starting = FALSE;
context.DisableTimer = FALSE;
DialogBoxParam(
PluginInstance->DllBase,
MAKEINTRESOURCE(IDD_SRVPROGRESS),
hWnd,
EspRestartServiceDlgProc,
(LPARAM)&context
);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,182 @@
/*
* Process Hacker Extended Services -
* triggers page
*
* 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 "extsrv.h"
typedef struct _SERVICE_TRIGGERS_CONTEXT
{
PPH_SERVICE_ITEM ServiceItem;
HWND TriggersLv;
struct _ES_TRIGGER_CONTEXT *TriggerContext;
} SERVICE_TRIGGERS_CONTEXT, *PSERVICE_TRIGGERS_CONTEXT;
NTSTATUS EspLoadTriggerInfo(
_In_ HWND hwndDlg,
_In_ PSERVICE_TRIGGERS_CONTEXT Context
)
{
NTSTATUS status = STATUS_SUCCESS;
SC_HANDLE serviceHandle;
if (!(serviceHandle = PhOpenService(Context->ServiceItem->Name->Buffer, SERVICE_QUERY_CONFIG)))
return NTSTATUS_FROM_WIN32(GetLastError());
EsLoadServiceTriggerInfo(Context->TriggerContext, serviceHandle);
CloseServiceHandle(serviceHandle);
return status;
}
INT_PTR CALLBACK EspServiceTriggersDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
PSERVICE_TRIGGERS_CONTEXT context;
if (uMsg == WM_INITDIALOG)
{
context = PhAllocate(sizeof(SERVICE_TRIGGERS_CONTEXT));
memset(context, 0, sizeof(SERVICE_TRIGGERS_CONTEXT));
SetProp(hwndDlg, L"Context", (HANDLE)context);
}
else
{
context = (PSERVICE_TRIGGERS_CONTEXT)GetProp(hwndDlg, L"Context");
if (uMsg == WM_DESTROY)
RemoveProp(hwndDlg, L"Context");
}
if (!context)
return FALSE;
switch (uMsg)
{
case WM_INITDIALOG:
{
NTSTATUS status;
LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam;
PPH_SERVICE_ITEM serviceItem = (PPH_SERVICE_ITEM)propSheetPage->lParam;
HWND triggersLv;
context->ServiceItem = serviceItem;
context->TriggersLv = triggersLv = GetDlgItem(hwndDlg, IDC_TRIGGERS);
context->TriggerContext = EsCreateServiceTriggerContext(
context->ServiceItem,
hwndDlg,
triggersLv
);
status = EspLoadTriggerInfo(hwndDlg, context);
if (!NT_SUCCESS(status))
{
PhShowWarning(hwndDlg, L"Unable to query service trigger information: %s",
((PPH_STRING)PH_AUTO(PhGetNtMessage(status)))->Buffer);
}
}
break;
case WM_DESTROY:
{
EsDestroyServiceTriggerContext(context->TriggerContext);
PhFree(context);
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDC_NEW:
if (context->TriggerContext)
EsHandleEventServiceTrigger(context->TriggerContext, ES_TRIGGER_EVENT_NEW);
break;
case IDC_EDIT:
if (context->TriggerContext)
EsHandleEventServiceTrigger(context->TriggerContext, ES_TRIGGER_EVENT_EDIT);
break;
case IDC_DELETE:
if (context->TriggerContext)
EsHandleEventServiceTrigger(context->TriggerContext, ES_TRIGGER_EVENT_DELETE);
break;
}
}
break;
case WM_NOTIFY:
{
LPNMHDR header = (LPNMHDR)lParam;
switch (header->code)
{
case PSN_KILLACTIVE:
{
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, FALSE);
}
return TRUE;
case PSN_APPLY:
{
ULONG win32Result = 0;
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_NOERROR);
if (!EsSaveServiceTriggerInfo(context->TriggerContext, &win32Result))
{
if (win32Result == ERROR_CANCELLED || (PhShowMessage(
hwndDlg,
MB_ICONERROR | MB_RETRYCANCEL,
L"Unable to change service trigger information: %s",
((PPH_STRING)PH_AUTO(PhGetWin32Message(win32Result)))->Buffer
) == IDRETRY))
{
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID);
}
}
return TRUE;
}
break;
case LVN_ITEMCHANGED:
{
if (header->hwndFrom == context->TriggersLv && context->TriggerContext)
{
EsHandleEventServiceTrigger(context->TriggerContext, ES_TRIGGER_EVENT_SELECTIONCHANGED);
}
}
break;
case NM_DBLCLK:
{
if (header->hwndFrom == context->TriggersLv && context->TriggerContext)
{
EsHandleEventServiceTrigger(context->TriggerContext, ES_TRIGGER_EVENT_EDIT);
}
}
break;
}
}
break;
}
return FALSE;
}

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@@ -0,0 +1,264 @@
/*
* Process Hacker Extended Tools -
* ETW mini information section
*
* Copyright (C) 2015 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
#include "exttools.h"
#include "etwmini.h"
VOID EtEtwMiniInformationInitializing(
_In_ PPH_PLUGIN_MINIINFO_POINTERS Pointers
)
{
PH_MINIINFO_LIST_SECTION section;
memset(&section, 0, sizeof(PH_MINIINFO_LIST_SECTION));
section.Callback = EtpDiskListSectionCallback;
Pointers->CreateListSection(L"Disk", 0, &section);
memset(&section, 0, sizeof(PH_MINIINFO_LIST_SECTION));
section.Callback = EtpNetworkListSectionCallback;
Pointers->CreateListSection(L"Network", 0, &section);
}
BOOLEAN EtpDiskListSectionCallback(
_In_ struct _PH_MINIINFO_LIST_SECTION *ListSection,
_In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message,
_In_opt_ PVOID Parameter1,
_In_opt_ PVOID Parameter2
)
{
switch (Message)
{
case MiListSectionTick:
{
PH_FORMAT format[4];
PhInitFormatS(&format[0], L"Disk R: ");
PhInitFormatSize(&format[1], EtDiskReadDelta.Delta);
format[1].Type |= FormatUsePrecision;
format[1].Precision = 0;
PhInitFormatS(&format[2], L" W: ");
PhInitFormatSize(&format[3], EtDiskWriteDelta.Delta);
format[3].Type |= FormatUsePrecision;
format[3].Precision = 0;
ListSection->Section->Parameters->SetSectionText(ListSection->Section,
PH_AUTO(PhFormat(format, 4, 50)));
}
break;
case MiListSectionSortProcessList:
{
PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1;
qsort(sortList->List->Items, sortList->List->Count,
sizeof(PPH_PROCESS_NODE), EtpDiskListSectionProcessCompareFunction);
}
return TRUE;
case MiListSectionAssignSortData:
{
PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA assignSortData = Parameter1;
PPH_LIST processes = assignSortData->ProcessGroup->Processes;
ULONG64 diskReadDelta = 0;
ULONG64 diskWriteDelta = 0;
ULONG i;
for (i = 0; i < processes->Count; i++)
{
PPH_PROCESS_ITEM processItem = processes->Items[i];
PET_PROCESS_BLOCK block = EtGetProcessBlock(processItem);
diskReadDelta += block->DiskReadRawDelta.Delta;
diskWriteDelta += block->DiskWriteRawDelta.Delta;
}
assignSortData->SortData->UserData[0] = diskReadDelta;
assignSortData->SortData->UserData[1] = diskWriteDelta;
}
return TRUE;
case MiListSectionSortGroupList:
{
PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1;
qsort(sortList->List->Items, sortList->List->Count,
sizeof(PPH_MINIINFO_LIST_SECTION_SORT_DATA), EtpDiskListSectionNodeCompareFunction);
}
return TRUE;
case MiListSectionGetUsageText:
{
PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT getUsageText = Parameter1;
PPH_LIST processes = getUsageText->ProcessGroup->Processes;
ULONG64 diskReadDelta = getUsageText->SortData->UserData[0];
ULONG64 diskWriteDelta = getUsageText->SortData->UserData[1];
PH_FORMAT format[1];
PhInitFormatSize(&format[0], diskReadDelta + diskWriteDelta);
PhMoveReference(&getUsageText->Line1, PhFormat(format, 1, 16));
}
return TRUE;
}
return FALSE;
}
int __cdecl EtpDiskListSectionProcessCompareFunction(
_In_ const void *elem1,
_In_ const void *elem2
)
{
int result;
PPH_PROCESS_NODE node1 = *(PPH_PROCESS_NODE *)elem1;
PPH_PROCESS_NODE node2 = *(PPH_PROCESS_NODE *)elem2;
PET_PROCESS_BLOCK block1 = EtGetProcessBlock(node1->ProcessItem);
PET_PROCESS_BLOCK block2 = EtGetProcessBlock(node2->ProcessItem);
ULONG64 total1 = block1->DiskReadRawDelta.Delta + block1->DiskWriteRawDelta.Delta;
ULONG64 total2 = block2->DiskReadRawDelta.Delta + block2->DiskWriteRawDelta.Delta;
result = uint64cmp(total2, total1);
if (result == 0)
result = uint64cmp(block2->DiskReadRaw + block2->DiskWriteRaw, block1->DiskReadRaw + block1->DiskWriteRaw);
if (result == 0)
result = singlecmp(node2->ProcessItem->CpuUsage, node1->ProcessItem->CpuUsage);
return result;
}
int __cdecl EtpDiskListSectionNodeCompareFunction(
_In_ const void *elem1,
_In_ const void *elem2
)
{
PPH_MINIINFO_LIST_SECTION_SORT_DATA data1 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem1;
PPH_MINIINFO_LIST_SECTION_SORT_DATA data2 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem2;
return uint64cmp(data2->UserData[0] + data2->UserData[1], data1->UserData[0] + data1->UserData[1]);
}
BOOLEAN EtpNetworkListSectionCallback(
_In_ struct _PH_MINIINFO_LIST_SECTION *ListSection,
_In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message,
_In_opt_ PVOID Parameter1,
_In_opt_ PVOID Parameter2
)
{
switch (Message)
{
case MiListSectionTick:
{
PH_FORMAT format[4];
PhInitFormatS(&format[0], L"Network R: ");
PhInitFormatSize(&format[1], EtNetworkReceiveDelta.Delta);
format[1].Type |= FormatUsePrecision;
format[1].Precision = 0;
PhInitFormatS(&format[2], L" S: ");
PhInitFormatSize(&format[3], EtNetworkSendDelta.Delta);
format[3].Type |= FormatUsePrecision;
format[3].Precision = 0;
ListSection->Section->Parameters->SetSectionText(ListSection->Section,
PH_AUTO(PhFormat(format, 4, 50)));
}
break;
case MiListSectionSortProcessList:
{
PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1;
qsort(sortList->List->Items, sortList->List->Count,
sizeof(PPH_PROCESS_NODE), EtpNetworkListSectionProcessCompareFunction);
}
return TRUE;
case MiListSectionAssignSortData:
{
PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA assignSortData = Parameter1;
PPH_LIST processes = assignSortData->ProcessGroup->Processes;
ULONG64 networkReceiveDelta = 0;
ULONG64 networkSendDelta = 0;
ULONG i;
for (i = 0; i < processes->Count; i++)
{
PPH_PROCESS_ITEM processItem = processes->Items[i];
PET_PROCESS_BLOCK block = EtGetProcessBlock(processItem);
networkReceiveDelta += block->NetworkReceiveRawDelta.Delta;
networkSendDelta += block->NetworkSendRawDelta.Delta;
}
assignSortData->SortData->UserData[0] = networkReceiveDelta;
assignSortData->SortData->UserData[1] = networkSendDelta;
}
return TRUE;
case MiListSectionSortGroupList:
{
PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1;
qsort(sortList->List->Items, sortList->List->Count,
sizeof(PPH_MINIINFO_LIST_SECTION_SORT_DATA), EtpNetworkListSectionNodeCompareFunction);
}
return TRUE;
case MiListSectionGetUsageText:
{
PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT getUsageText = Parameter1;
PPH_LIST processes = getUsageText->ProcessGroup->Processes;
ULONG64 networkReceiveDelta = getUsageText->SortData->UserData[0];
ULONG64 networkSendDelta = getUsageText->SortData->UserData[1];
PH_FORMAT format[1];
PhInitFormatSize(&format[0], networkReceiveDelta + networkSendDelta);
PhMoveReference(&getUsageText->Line1, PhFormat(format, 1, 16));
}
return TRUE;
}
return FALSE;
}
int __cdecl EtpNetworkListSectionProcessCompareFunction(
_In_ const void *elem1,
_In_ const void *elem2
)
{
int result;
PPH_PROCESS_NODE node1 = *(PPH_PROCESS_NODE *)elem1;
PPH_PROCESS_NODE node2 = *(PPH_PROCESS_NODE *)elem2;
PET_PROCESS_BLOCK block1 = EtGetProcessBlock(node1->ProcessItem);
PET_PROCESS_BLOCK block2 = EtGetProcessBlock(node2->ProcessItem);
ULONG64 total1 = block1->NetworkReceiveRawDelta.Delta + block1->NetworkSendRawDelta.Delta;
ULONG64 total2 = block2->NetworkReceiveRawDelta.Delta + block2->NetworkSendRawDelta.Delta;
result = uint64cmp(total2, total1);
if (result == 0)
result = uint64cmp(block2->NetworkReceiveRaw + block2->NetworkSendRaw, block1->NetworkReceiveRaw + block1->NetworkSendRaw);
if (result == 0)
result = singlecmp(node2->ProcessItem->CpuUsage, node1->ProcessItem->CpuUsage);
return result;
}
int __cdecl EtpNetworkListSectionNodeCompareFunction(
_In_ const void *elem1,
_In_ const void *elem2
)
{
PPH_MINIINFO_LIST_SECTION_SORT_DATA data1 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem1;
PPH_MINIINFO_LIST_SECTION_SORT_DATA data2 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem2;
return uint64cmp(data2->UserData[0] + data2->UserData[1], data1->UserData[0] + data1->UserData[1]);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,811 @@
/*
* Process Hacker Extended Tools -
* ETW system information section
*
* Copyright (C) 2010-2011 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
#include "exttools.h"
#include "etwsys.h"
static PPH_SYSINFO_SECTION DiskSection;
static HWND DiskDialog;
static PH_LAYOUT_MANAGER DiskLayoutManager;
static HWND DiskGraphHandle;
static PH_GRAPH_STATE DiskGraphState;
static HWND DiskPanel;
static PPH_SYSINFO_SECTION NetworkSection;
static HWND NetworkDialog;
static PH_LAYOUT_MANAGER NetworkLayoutManager;
static HWND NetworkGraphHandle;
static PH_GRAPH_STATE NetworkGraphState;
static HWND NetworkPanel;
VOID EtEtwSystemInformationInitializing(
_In_ PPH_PLUGIN_SYSINFO_POINTERS Pointers
)
{
PH_SYSINFO_SECTION section;
memset(&section, 0, sizeof(PH_SYSINFO_SECTION));
PhInitializeStringRef(&section.Name, L"Disk");
section.Flags = 0;
section.Callback = EtpDiskSysInfoSectionCallback;
DiskSection = Pointers->CreateSection(&section);
memset(&section, 0, sizeof(PH_SYSINFO_SECTION));
PhInitializeStringRef(&section.Name, L"Network");
section.Flags = 0;
section.Callback = EtpNetworkSysInfoSectionCallback;
NetworkSection = Pointers->CreateSection(&section);
}
BOOLEAN EtpDiskSysInfoSectionCallback(
_In_ PPH_SYSINFO_SECTION Section,
_In_ PH_SYSINFO_SECTION_MESSAGE Message,
_In_opt_ PVOID Parameter1,
_In_opt_ PVOID Parameter2
)
{
switch (Message)
{
case SysInfoDestroy:
{
if (DiskDialog)
{
PhDeleteGraphState(&DiskGraphState);
DiskDialog = NULL;
}
}
return TRUE;
case SysInfoTick:
{
if (DiskDialog)
{
EtpUpdateDiskGraph();
EtpUpdateDiskPanel();
}
}
return TRUE;
case SysInfoCreateDialog:
{
PPH_SYSINFO_CREATE_DIALOG createDialog = Parameter1;
createDialog->Instance = PluginInstance->DllBase;
createDialog->Template = MAKEINTRESOURCE(IDD_SYSINFO_DISK);
createDialog->DialogProc = EtpDiskDialogProc;
}
return TRUE;
case SysInfoGraphGetDrawInfo:
{
PPH_GRAPH_DRAW_INFO drawInfo = Parameter1;
drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_LABEL_MAX_Y | PH_GRAPH_USE_LINE_2;
Section->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite"));
PhGetDrawInfoGraphBuffers(&Section->GraphState.Buffers, drawInfo, EtDiskReadHistory.Count);
if (!Section->GraphState.Valid)
{
ULONG i;
FLOAT max = 1024 * 1024; // Minimum scaling of 1 MB
for (i = 0; i < drawInfo->LineDataCount; i++)
{
FLOAT data1;
FLOAT data2;
Section->GraphState.Data1[i] = data1 =
(FLOAT)PhGetItemCircularBuffer_ULONG(&EtDiskReadHistory, i);
Section->GraphState.Data2[i] = data2 =
(FLOAT)PhGetItemCircularBuffer_ULONG(&EtDiskWriteHistory, i);
if (max < data1 + data2)
max = data1 + data2;
}
if (max != 0)
{
// Scale the data.
PhDivideSinglesBySingle(
Section->GraphState.Data1,
max,
drawInfo->LineDataCount
);
PhDivideSinglesBySingle(
Section->GraphState.Data2,
max,
drawInfo->LineDataCount
);
}
drawInfo->LabelYFunction = PhSiSizeLabelYFunction;
drawInfo->LabelYFunctionParameter = max;
Section->GraphState.Valid = TRUE;
}
}
return TRUE;
case SysInfoGraphGetTooltipText:
{
PPH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT getTooltipText = Parameter1;
ULONG64 diskRead;
ULONG64 diskWrite;
diskRead = PhGetItemCircularBuffer_ULONG(&EtDiskReadHistory, getTooltipText->Index);
diskWrite = PhGetItemCircularBuffer_ULONG(&EtDiskWriteHistory, getTooltipText->Index);
PhMoveReference(&Section->GraphState.TooltipText, PhFormatString(
L"R: %s\nW: %s%s\n%s",
PhaFormatSize(diskRead, -1)->Buffer,
PhaFormatSize(diskWrite, -1)->Buffer,
PhGetStringOrEmpty(EtpGetMaxDiskString(getTooltipText->Index)),
((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
));
getTooltipText->Text = Section->GraphState.TooltipText->sr;
}
return TRUE;
case SysInfoGraphDrawPanel:
{
PPH_SYSINFO_DRAW_PANEL drawPanel = Parameter1;
drawPanel->Title = PhCreateString(L"Disk");
drawPanel->SubTitle = PhFormatString(
L"R: %s\nW: %s",
PhaFormatSize(EtDiskReadDelta.Delta, -1)->Buffer,
PhaFormatSize(EtDiskWriteDelta.Delta, -1)->Buffer
);
}
return TRUE;
}
return FALSE;
}
INT_PTR CALLBACK EtpDiskDialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
PPH_LAYOUT_ITEM graphItem;
PPH_LAYOUT_ITEM panelItem;
PhInitializeGraphState(&DiskGraphState);
DiskDialog = hwndDlg;
PhInitializeLayoutManager(&DiskLayoutManager, hwndDlg);
graphItem = PhAddLayoutItem(&DiskLayoutManager, GetDlgItem(hwndDlg, IDC_GRAPH_LAYOUT), NULL, PH_ANCHOR_ALL);
panelItem = PhAddLayoutItem(&DiskLayoutManager, GetDlgItem(hwndDlg, IDC_PANEL_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
SendMessage(GetDlgItem(hwndDlg, IDC_TITLE), WM_SETFONT, (WPARAM)DiskSection->Parameters->LargeFont, FALSE);
DiskPanel = CreateDialog(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_SYSINFO_DISKPANEL), hwndDlg, EtpDiskPanelDialogProc);
ShowWindow(DiskPanel, SW_SHOW);
PhAddLayoutItemEx(&DiskLayoutManager, DiskPanel, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM, panelItem->Margin);
DiskGraphHandle = CreateWindow(
PH_GRAPH_CLASSNAME,
NULL,
WS_VISIBLE | WS_CHILD | WS_BORDER,
0,
0,
3,
3,
hwndDlg,
NULL,
NULL,
NULL
);
Graph_SetTooltip(DiskGraphHandle, TRUE);
PhAddLayoutItemEx(&DiskLayoutManager, DiskGraphHandle, NULL, PH_ANCHOR_ALL, graphItem->Margin);
EtpUpdateDiskGraph();
EtpUpdateDiskPanel();
}
break;
case WM_DESTROY:
{
PhDeleteLayoutManager(&DiskLayoutManager);
}
break;
case WM_SIZE:
{
PhLayoutManagerLayout(&DiskLayoutManager);
}
break;
case WM_NOTIFY:
{
NMHDR *header = (NMHDR *)lParam;
if (header->hwndFrom == DiskGraphHandle)
{
EtpNotifyDiskGraph(header);
}
}
break;
}
return FALSE;
}
INT_PTR CALLBACK EtpDiskPanelDialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
return FALSE;
}
VOID EtpNotifyDiskGraph(
_In_ NMHDR *Header
)
{
switch (Header->code)
{
case GCN_GETDRAWINFO:
{
PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header;
PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;
drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_LABEL_MAX_Y | PH_GRAPH_USE_LINE_2;
DiskSection->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite"));
PhGraphStateGetDrawInfo(
&DiskGraphState,
getDrawInfo,
EtDiskReadHistory.Count
);
if (!DiskGraphState.Valid)
{
ULONG i;
FLOAT max = 1024 * 1024; // Minimum scaling of 1 MB
for (i = 0; i < drawInfo->LineDataCount; i++)
{
FLOAT data1;
FLOAT data2;
DiskGraphState.Data1[i] = data1 =
(FLOAT)PhGetItemCircularBuffer_ULONG(&EtDiskReadHistory, i);
DiskGraphState.Data2[i] = data2 =
(FLOAT)PhGetItemCircularBuffer_ULONG(&EtDiskWriteHistory, i);
if (max < data1 + data2)
max = data1 + data2;
}
if (max != 0)
{
// Scale the data.
PhDivideSinglesBySingle(
DiskGraphState.Data1,
max,
drawInfo->LineDataCount
);
PhDivideSinglesBySingle(
DiskGraphState.Data2,
max,
drawInfo->LineDataCount
);
}
drawInfo->LabelYFunction = PhSiSizeLabelYFunction;
drawInfo->LabelYFunctionParameter = max;
DiskGraphState.Valid = TRUE;
}
}
break;
case GCN_GETTOOLTIPTEXT:
{
PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header;
if (getTooltipText->Index < getTooltipText->TotalCount)
{
if (DiskGraphState.TooltipIndex != getTooltipText->Index)
{
ULONG64 diskRead;
ULONG64 diskWrite;
diskRead = PhGetItemCircularBuffer_ULONG(&EtDiskReadHistory, getTooltipText->Index);
diskWrite = PhGetItemCircularBuffer_ULONG(&EtDiskWriteHistory, getTooltipText->Index);
PhMoveReference(&DiskGraphState.TooltipText, PhFormatString(
L"R: %s\nW: %s%s\n%s",
PhaFormatSize(diskRead, -1)->Buffer,
PhaFormatSize(diskWrite, -1)->Buffer,
PhGetStringOrEmpty(EtpGetMaxDiskString(getTooltipText->Index)),
((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
));
}
getTooltipText->Text = DiskGraphState.TooltipText->sr;
}
}
break;
case GCN_MOUSEEVENT:
{
PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Header;
PPH_PROCESS_RECORD record;
record = NULL;
if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount)
{
record = EtpReferenceMaxDiskRecord(mouseEvent->Index);
}
if (record)
{
PhShowProcessRecordDialog(DiskDialog, record);
PhDereferenceProcessRecord(record);
}
}
break;
}
}
VOID EtpUpdateDiskGraph(
VOID
)
{
DiskGraphState.Valid = FALSE;
DiskGraphState.TooltipIndex = -1;
Graph_MoveGrid(DiskGraphHandle, 1);
Graph_Draw(DiskGraphHandle);
Graph_UpdateTooltip(DiskGraphHandle);
InvalidateRect(DiskGraphHandle, NULL, FALSE);
}
VOID EtpUpdateDiskPanel(
VOID
)
{
SetDlgItemText(DiskPanel, IDC_ZREADSDELTA_V, PhaFormatUInt64(EtDiskReadCountDelta.Delta, TRUE)->Buffer);
SetDlgItemText(DiskPanel, IDC_ZREADBYTESDELTA_V, PhaFormatSize(EtDiskReadDelta.Delta, -1)->Buffer);
SetDlgItemText(DiskPanel, IDC_ZWRITESDELTA_V, PhaFormatUInt64(EtDiskWriteCountDelta.Delta, TRUE)->Buffer);
SetDlgItemText(DiskPanel, IDC_ZWRITEBYTESDELTA_V, PhaFormatSize(EtDiskWriteDelta.Delta, -1)->Buffer);
}
PPH_PROCESS_RECORD EtpReferenceMaxDiskRecord(
_In_ LONG Index
)
{
LARGE_INTEGER time;
ULONG maxProcessId;
maxProcessId = PhGetItemCircularBuffer_ULONG(&EtMaxDiskHistory, Index);
if (!maxProcessId)
return NULL;
PhGetStatisticsTime(NULL, Index, &time);
time.QuadPart += PH_TICKS_PER_SEC - 1;
return PhFindProcessRecord(UlongToHandle(maxProcessId), &time);
}
PPH_STRING EtpGetMaxDiskString(
_In_ LONG Index
)
{
PPH_PROCESS_RECORD maxProcessRecord;
PPH_STRING maxUsageString = NULL;
if (maxProcessRecord = EtpReferenceMaxDiskRecord(Index))
{
maxUsageString = PhaFormatString(
L"\n%s (%lu)",
maxProcessRecord->ProcessName->Buffer,
HandleToUlong(maxProcessRecord->ProcessId)
);
PhDereferenceProcessRecord(maxProcessRecord);
}
return maxUsageString;
}
BOOLEAN EtpNetworkSysInfoSectionCallback(
_In_ PPH_SYSINFO_SECTION Section,
_In_ PH_SYSINFO_SECTION_MESSAGE Message,
_In_opt_ PVOID Parameter1,
_In_opt_ PVOID Parameter2
)
{
switch (Message)
{
case SysInfoDestroy:
{
if (NetworkDialog)
{
PhDeleteGraphState(&NetworkGraphState);
NetworkDialog = NULL;
}
}
return TRUE;
case SysInfoTick:
{
if (NetworkDialog)
{
EtpUpdateNetworkGraph();
EtpUpdateNetworkPanel();
}
}
return TRUE;
case SysInfoCreateDialog:
{
PPH_SYSINFO_CREATE_DIALOG createDialog = Parameter1;
createDialog->Instance = PluginInstance->DllBase;
createDialog->Template = MAKEINTRESOURCE(IDD_SYSINFO_NET);
createDialog->DialogProc = EtpNetworkDialogProc;
}
return TRUE;
case SysInfoGraphGetDrawInfo:
{
PPH_GRAPH_DRAW_INFO drawInfo = Parameter1;
drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_LABEL_MAX_Y | PH_GRAPH_USE_LINE_2;
Section->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite"));
PhGetDrawInfoGraphBuffers(&Section->GraphState.Buffers, drawInfo, EtNetworkReceiveHistory.Count);
if (!Section->GraphState.Valid)
{
ULONG i;
FLOAT max = 1024 * 1024; // Minimum scaling of 1 MB
for (i = 0; i < drawInfo->LineDataCount; i++)
{
FLOAT data1;
FLOAT data2;
Section->GraphState.Data1[i] = data1 =
(FLOAT)PhGetItemCircularBuffer_ULONG(&EtNetworkReceiveHistory, i);
Section->GraphState.Data2[i] = data2 =
(FLOAT)PhGetItemCircularBuffer_ULONG(&EtNetworkSendHistory, i);
if (max < data1 + data2)
max = data1 + data2;
}
if (max != 0)
{
// Scale the data.
PhDivideSinglesBySingle(
Section->GraphState.Data1,
max,
drawInfo->LineDataCount
);
PhDivideSinglesBySingle(
Section->GraphState.Data2,
max,
drawInfo->LineDataCount
);
}
drawInfo->LabelYFunction = PhSiSizeLabelYFunction;
drawInfo->LabelYFunctionParameter = max;
Section->GraphState.Valid = TRUE;
}
}
return TRUE;
case SysInfoGraphGetTooltipText:
{
PPH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT getTooltipText = Parameter1;
ULONG64 networkReceive;
ULONG64 networkSend;
networkReceive = PhGetItemCircularBuffer_ULONG(&EtNetworkReceiveHistory, getTooltipText->Index);
networkSend = PhGetItemCircularBuffer_ULONG(&EtNetworkSendHistory, getTooltipText->Index);
PhMoveReference(&Section->GraphState.TooltipText, PhFormatString(
L"R: %s\nS: %s%s\n%s",
PhaFormatSize(networkReceive, -1)->Buffer,
PhaFormatSize(networkSend, -1)->Buffer,
PhGetStringOrEmpty(EtpGetMaxNetworkString(getTooltipText->Index)),
((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
));
getTooltipText->Text = Section->GraphState.TooltipText->sr;
}
return TRUE;
case SysInfoGraphDrawPanel:
{
PPH_SYSINFO_DRAW_PANEL drawPanel = Parameter1;
drawPanel->Title = PhCreateString(L"Network");
drawPanel->SubTitle = PhFormatString(
L"R: %s\nS: %s",
PhaFormatSize(EtNetworkReceiveDelta.Delta, -1)->Buffer,
PhaFormatSize(EtNetworkSendDelta.Delta, -1)->Buffer
);
}
return TRUE;
}
return FALSE;
}
INT_PTR CALLBACK EtpNetworkDialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
PPH_LAYOUT_ITEM graphItem;
PPH_LAYOUT_ITEM panelItem;
PhInitializeGraphState(&NetworkGraphState);
NetworkDialog = hwndDlg;
PhInitializeLayoutManager(&NetworkLayoutManager, hwndDlg);
graphItem = PhAddLayoutItem(&NetworkLayoutManager, GetDlgItem(hwndDlg, IDC_GRAPH_LAYOUT), NULL, PH_ANCHOR_ALL);
panelItem = PhAddLayoutItem(&NetworkLayoutManager, GetDlgItem(hwndDlg, IDC_PANEL_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
SendMessage(GetDlgItem(hwndDlg, IDC_TITLE), WM_SETFONT, (WPARAM)NetworkSection->Parameters->LargeFont, FALSE);
NetworkPanel = CreateDialog(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_SYSINFO_NETPANEL), hwndDlg, EtpNetworkPanelDialogProc);
ShowWindow(NetworkPanel, SW_SHOW);
PhAddLayoutItemEx(&NetworkLayoutManager, NetworkPanel, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM, panelItem->Margin);
NetworkGraphHandle = CreateWindow(
PH_GRAPH_CLASSNAME,
NULL,
WS_VISIBLE | WS_CHILD | WS_BORDER,
0,
0,
3,
3,
hwndDlg,
NULL,
NULL,
NULL
);
Graph_SetTooltip(NetworkGraphHandle, TRUE);
PhAddLayoutItemEx(&NetworkLayoutManager, NetworkGraphHandle, NULL, PH_ANCHOR_ALL, graphItem->Margin);
EtpUpdateNetworkGraph();
EtpUpdateNetworkPanel();
}
break;
case WM_DESTROY:
{
PhDeleteLayoutManager(&NetworkLayoutManager);
}
break;
case WM_SIZE:
{
PhLayoutManagerLayout(&NetworkLayoutManager);
}
break;
case WM_NOTIFY:
{
NMHDR *header = (NMHDR *)lParam;
if (header->hwndFrom == NetworkGraphHandle)
{
EtpNotifyNetworkGraph(header);
}
}
break;
}
return FALSE;
}
INT_PTR CALLBACK EtpNetworkPanelDialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
return FALSE;
}
VOID EtpNotifyNetworkGraph(
_In_ NMHDR *Header
)
{
switch (Header->code)
{
case GCN_GETDRAWINFO:
{
PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)Header;
PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;
drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y | PH_GRAPH_LABEL_MAX_Y | PH_GRAPH_USE_LINE_2;
NetworkSection->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite"));
PhGraphStateGetDrawInfo(
&NetworkGraphState,
getDrawInfo,
EtNetworkReceiveHistory.Count
);
if (!NetworkGraphState.Valid)
{
ULONG i;
FLOAT max = 1024 * 1024; // Minimum scaling of 1 MB
for (i = 0; i < drawInfo->LineDataCount; i++)
{
FLOAT data1;
FLOAT data2;
NetworkGraphState.Data1[i] = data1 =
(FLOAT)PhGetItemCircularBuffer_ULONG(&EtNetworkReceiveHistory, i);
NetworkGraphState.Data2[i] = data2 =
(FLOAT)PhGetItemCircularBuffer_ULONG(&EtNetworkSendHistory, i);
if (max < data1 + data2)
max = data1 + data2;
}
if (max != 0)
{
// Scale the data.
PhDivideSinglesBySingle(
NetworkGraphState.Data1,
max,
drawInfo->LineDataCount
);
PhDivideSinglesBySingle(
NetworkGraphState.Data2,
max,
drawInfo->LineDataCount
);
}
drawInfo->LabelYFunction = PhSiSizeLabelYFunction;
drawInfo->LabelYFunctionParameter = max;
NetworkGraphState.Valid = TRUE;
}
}
break;
case GCN_GETTOOLTIPTEXT:
{
PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header;
if (getTooltipText->Index < getTooltipText->TotalCount)
{
if (NetworkGraphState.TooltipIndex != getTooltipText->Index)
{
ULONG64 networkReceive;
ULONG64 networkSend;
networkReceive = PhGetItemCircularBuffer_ULONG(&EtNetworkReceiveHistory, getTooltipText->Index);
networkSend = PhGetItemCircularBuffer_ULONG(&EtNetworkSendHistory, getTooltipText->Index);
PhMoveReference(&NetworkGraphState.TooltipText, PhFormatString(
L"R: %s\nS: %s%s\n%s",
PhaFormatSize(networkReceive, -1)->Buffer,
PhaFormatSize(networkSend, -1)->Buffer,
PhGetStringOrEmpty(EtpGetMaxNetworkString(getTooltipText->Index)),
((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
));
}
getTooltipText->Text = NetworkGraphState.TooltipText->sr;
}
}
break;
case GCN_MOUSEEVENT:
{
PPH_GRAPH_MOUSEEVENT mouseEvent = (PPH_GRAPH_MOUSEEVENT)Header;
PPH_PROCESS_RECORD record;
record = NULL;
if (mouseEvent->Message == WM_LBUTTONDBLCLK && mouseEvent->Index < mouseEvent->TotalCount)
{
record = EtpReferenceMaxNetworkRecord(mouseEvent->Index);
}
if (record)
{
PhShowProcessRecordDialog(NetworkDialog, record);
PhDereferenceProcessRecord(record);
}
}
break;
}
}
VOID EtpUpdateNetworkGraph(
VOID
)
{
NetworkGraphState.Valid = FALSE;
NetworkGraphState.TooltipIndex = -1;
Graph_MoveGrid(NetworkGraphHandle, 1);
Graph_Draw(NetworkGraphHandle);
Graph_UpdateTooltip(NetworkGraphHandle);
InvalidateRect(NetworkGraphHandle, NULL, FALSE);
}
VOID EtpUpdateNetworkPanel(
VOID
)
{
SetDlgItemText(NetworkPanel, IDC_ZRECEIVESDELTA_V, PhaFormatUInt64(EtNetworkReceiveCountDelta.Delta, TRUE)->Buffer);
SetDlgItemText(NetworkPanel, IDC_ZRECEIVEBYTESDELTA_V, PhaFormatSize(EtNetworkReceiveDelta.Delta, -1)->Buffer);
SetDlgItemText(NetworkPanel, IDC_ZSENDSDELTA_V, PhaFormatUInt64(EtNetworkSendCountDelta.Delta, TRUE)->Buffer);
SetDlgItemText(NetworkPanel, IDC_ZSENDBYTESDELTA_V, PhaFormatSize(EtNetworkSendDelta.Delta, -1)->Buffer);
}
PPH_PROCESS_RECORD EtpReferenceMaxNetworkRecord(
_In_ LONG Index
)
{
LARGE_INTEGER time;
ULONG maxProcessId;
maxProcessId = PhGetItemCircularBuffer_ULONG(&EtMaxNetworkHistory, Index);
if (!maxProcessId)
return NULL;
PhGetStatisticsTime(NULL, Index, &time);
time.QuadPart += PH_TICKS_PER_SEC - 1;
return PhFindProcessRecord(UlongToHandle(maxProcessId), &time);
}
PPH_STRING EtpGetMaxNetworkString(
_In_ LONG Index
)
{
PPH_PROCESS_RECORD maxProcessRecord;
PPH_STRING maxUsageString = NULL;
if (maxProcessRecord = EtpReferenceMaxNetworkRecord(Index))
{
maxUsageString = PhaFormatString(
L"\n%s (%lu)",
maxProcessRecord->ProcessName->Buffer,
HandleToUlong(maxProcessRecord->ProcessId)
);
PhDereferenceProcessRecord(maxProcessRecord);
}
return maxUsageString;
}

View File

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

View File

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

View File

@@ -0,0 +1,129 @@
/*
* Process Hacker Extended Tools -
* GPU mini information section
*
* Copyright (C) 2015 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
#include "exttools.h"
#include "gpumini.h"
VOID EtGpuMiniInformationInitializing(
_In_ PPH_PLUGIN_MINIINFO_POINTERS Pointers
)
{
PH_MINIINFO_LIST_SECTION section;
memset(&section, 0, sizeof(PH_MINIINFO_LIST_SECTION));
section.Callback = EtpGpuListSectionCallback;
Pointers->CreateListSection(L"GPU", 0, &section);
}
BOOLEAN EtpGpuListSectionCallback(
_In_ struct _PH_MINIINFO_LIST_SECTION *ListSection,
_In_ PH_MINIINFO_LIST_SECTION_MESSAGE Message,
_In_opt_ PVOID Parameter1,
_In_opt_ PVOID Parameter2
)
{
switch (Message)
{
case MiListSectionTick:
{
ListSection->Section->Parameters->SetSectionText(ListSection->Section,
PhaFormatString(L"GPU %.2f%%", EtGpuNodeUsage * 100));
}
break;
case MiListSectionSortProcessList:
{
PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1;
qsort(sortList->List->Items, sortList->List->Count,
sizeof(PPH_PROCESS_NODE), EtpGpuListSectionProcessCompareFunction);
}
return TRUE;
case MiListSectionAssignSortData:
{
PPH_MINIINFO_LIST_SECTION_ASSIGN_SORT_DATA assignSortData = Parameter1;
PPH_LIST processes = assignSortData->ProcessGroup->Processes;
FLOAT gpuUsage = 0;
ULONG i;
for (i = 0; i < processes->Count; i++)
{
PPH_PROCESS_ITEM processItem = processes->Items[i];
PET_PROCESS_BLOCK block = EtGetProcessBlock(processItem);
gpuUsage += block->GpuNodeUsage;
}
*(PFLOAT)assignSortData->SortData->UserData = gpuUsage;
}
return TRUE;
case MiListSectionSortGroupList:
{
PPH_MINIINFO_LIST_SECTION_SORT_LIST sortList = Parameter1;
qsort(sortList->List->Items, sortList->List->Count,
sizeof(PPH_MINIINFO_LIST_SECTION_SORT_DATA), EtpGpuListSectionNodeCompareFunction);
}
return TRUE;
case MiListSectionGetUsageText:
{
PPH_MINIINFO_LIST_SECTION_GET_USAGE_TEXT getUsageText = Parameter1;
PPH_LIST processes = getUsageText->ProcessGroup->Processes;
FLOAT gpuUsage = *(PFLOAT)getUsageText->SortData->UserData;
PhMoveReference(&getUsageText->Line1, PhFormatString(L"%.2f%%", gpuUsage * 100));
}
return TRUE;
}
return FALSE;
}
int __cdecl EtpGpuListSectionProcessCompareFunction(
_In_ const void *elem1,
_In_ const void *elem2
)
{
int result;
PPH_PROCESS_NODE node1 = *(PPH_PROCESS_NODE *)elem1;
PPH_PROCESS_NODE node2 = *(PPH_PROCESS_NODE *)elem2;
PET_PROCESS_BLOCK block1 = EtGetProcessBlock(node1->ProcessItem);
PET_PROCESS_BLOCK block2 = EtGetProcessBlock(node2->ProcessItem);
result = singlecmp(block2->GpuNodeUsage, block1->GpuNodeUsage);
if (result == 0)
result = uint64cmp(block2->GpuRunningTimeDelta.Value, block1->GpuRunningTimeDelta.Value);
if (result == 0)
result = singlecmp(node2->ProcessItem->CpuUsage, node1->ProcessItem->CpuUsage);
return result;
}
int __cdecl EtpGpuListSectionNodeCompareFunction(
_In_ const void *elem1,
_In_ const void *elem2
)
{
PPH_MINIINFO_LIST_SECTION_SORT_DATA data1 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem1;
PPH_MINIINFO_LIST_SECTION_SORT_DATA data2 = *(PPH_MINIINFO_LIST_SECTION_SORT_DATA *)elem2;
return singlecmp(*(PFLOAT)data2->UserData, *(PFLOAT)data1->UserData);
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,430 @@
/*
* Process Hacker Extended Tools -
* GPU nodes window
*
* Copyright (C) 2011-2015 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
#include "exttools.h"
#define GRAPH_PADDING 5
#define CHECKBOX_PADDING 3
INT_PTR CALLBACK EtpGpuNodesDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
static HWND WindowHandle;
static RECT MinimumSize;
static PH_LAYOUT_MANAGER LayoutManager;
static RECT LayoutMargin;
static HWND *GraphHandle;
static HWND *CheckBoxHandle;
static PPH_GRAPH_STATE GraphState;
static PPH_SYSINFO_PARAMETERS SysInfoParameters;
static PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration;
VOID EtShowGpuNodesDialog(
_In_ HWND ParentWindowHandle,
_In_ PPH_SYSINFO_PARAMETERS Parameters
)
{
SysInfoParameters = Parameters;
DialogBox(
PluginInstance->DllBase,
MAKEINTRESOURCE(IDD_GPUNODES),
ParentWindowHandle,
EtpGpuNodesDlgProc
);
}
static VOID ProcessesUpdatedCallback(
_In_opt_ PVOID Parameter,
_In_opt_ PVOID Context
)
{
PostMessage(WindowHandle, UPDATE_MSG, 0, 0);
}
VOID EtpLoadNodeBitMap(
VOID
)
{
ULONG i;
for (i = 0; i < EtGpuTotalNodeCount; i++)
{
Button_SetCheck(
CheckBoxHandle[i],
RtlCheckBit(&EtGpuNodeBitMap, i) ? BST_CHECKED : BST_UNCHECKED
);
}
}
VOID EtpSaveNodeBitMap(
VOID
)
{
RTL_BITMAP newBitMap;
ULONG i;
EtAllocateGpuNodeBitMap(&newBitMap);
for (i = 0; i < EtGpuTotalNodeCount; i++)
{
if (Button_GetCheck(CheckBoxHandle[i]) == BST_CHECKED)
RtlSetBits(&newBitMap, i, 1);
}
if (RtlNumberOfSetBits(&newBitMap) == 0)
RtlSetBits(&newBitMap, 0, 1);
EtUpdateGpuNodeBitMap(&newBitMap);
}
INT_PTR CALLBACK EtpGpuNodesDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
ULONG i;
HFONT font;
PPH_STRING nodeString;
RECT labelRect;
RECT tempRect;
ULONG numberOfRows;
ULONG numberOfColumns;
WindowHandle = hwndDlg;
PhInitializeLayoutManager(&LayoutManager, hwndDlg);
PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
LayoutMargin = PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_LAYOUT), NULL, PH_ANCHOR_ALL)->Margin;
PhRegisterCallback(&PhProcessesUpdatedEvent, ProcessesUpdatedCallback, NULL, &ProcessesUpdatedCallbackRegistration);
GraphHandle = PhAllocate(sizeof(HWND) * EtGpuTotalNodeCount);
CheckBoxHandle = PhAllocate(sizeof(HWND) * EtGpuTotalNodeCount);
GraphState = PhAllocate(sizeof(PH_GRAPH_STATE) * EtGpuTotalNodeCount);
font = (HFONT)SendMessage(hwndDlg, WM_GETFONT, 0, 0);
for (i = 0; i < EtGpuTotalNodeCount; i++)
{
nodeString = PhFormatString(L"Node %lu", i);
GraphHandle[i] = CreateWindow(
PH_GRAPH_CLASSNAME,
NULL,
WS_VISIBLE | WS_CHILD | WS_BORDER,
0,
0,
3,
3,
hwndDlg,
NULL,
NULL,
NULL
);
Graph_SetTooltip(GraphHandle[i], TRUE);
CheckBoxHandle[i] = CreateWindow(
WC_BUTTON,
nodeString->Buffer,
WS_VISIBLE | WS_CHILD | BS_AUTOCHECKBOX,
0,
0,
3,
3,
hwndDlg,
NULL,
NULL,
NULL
);
SendMessage(CheckBoxHandle[i], WM_SETFONT, (WPARAM)font, FALSE);
PhInitializeGraphState(&GraphState[i]);
PhDereferenceObject(nodeString);
}
// Calculate the minimum size.
numberOfRows = (ULONG)sqrt(EtGpuTotalNodeCount);
numberOfColumns = (EtGpuTotalNodeCount + numberOfRows - 1) / numberOfRows;
MinimumSize.left = 0;
MinimumSize.top = 0;
MinimumSize.right = 55;
MinimumSize.bottom = 60;
MapDialogRect(hwndDlg, &MinimumSize);
MinimumSize.right += (MinimumSize.right + GRAPH_PADDING) * numberOfColumns;
MinimumSize.bottom += (MinimumSize.bottom + GRAPH_PADDING) * numberOfRows;
GetWindowRect(GetDlgItem(hwndDlg, IDC_INSTRUCTION), &labelRect);
MapWindowPoints(NULL, hwndDlg, (POINT *)&labelRect, 2);
labelRect.right += GetSystemMetrics(SM_CXFRAME) * 2;
tempRect.left = 0;
tempRect.top = 0;
tempRect.right = 7;
tempRect.bottom = 0;
MapDialogRect(hwndDlg, &tempRect);
labelRect.right += tempRect.right;
if (MinimumSize.right < labelRect.right)
MinimumSize.right = labelRect.right;
SetWindowPos(hwndDlg, NULL, 0, 0, MinimumSize.right, MinimumSize.bottom, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
// Note: This dialog must be centered after all other graphs and controls have been added.
PhCenterWindow(hwndDlg, GetParent(hwndDlg));
EtpLoadNodeBitMap();
}
break;
case WM_DESTROY:
{
ULONG i;
EtpSaveNodeBitMap();
PhUnregisterCallback(&PhProcessesUpdatedEvent, &ProcessesUpdatedCallbackRegistration);
for (i = 0; i < EtGpuTotalNodeCount; i++)
{
PhDeleteGraphState(&GraphState[i]);
}
PhFree(GraphHandle);
PhFree(CheckBoxHandle);
PhFree(GraphState);
PhDeleteLayoutManager(&LayoutManager);
}
break;
case WM_SIZE:
{
HDWP deferHandle;
RECT clientRect;
RECT checkBoxRect;
ULONG numberOfRows = (ULONG)sqrt(EtGpuTotalNodeCount);
ULONG numberOfColumns = (EtGpuTotalNodeCount + numberOfRows - 1) / numberOfRows;
ULONG numberOfYPaddings = numberOfRows - 1;
ULONG numberOfXPaddings = numberOfColumns - 1;
ULONG cellHeight;
ULONG y;
ULONG cellWidth;
ULONG x;
ULONG i;
PhLayoutManagerLayout(&LayoutManager);
deferHandle = BeginDeferWindowPos(EtGpuTotalNodeCount * 2);
GetClientRect(hwndDlg, &clientRect);
GetClientRect(GetDlgItem(hwndDlg, IDC_EXAMPLE), &checkBoxRect);
cellHeight = (clientRect.bottom - LayoutMargin.top - LayoutMargin.bottom - GRAPH_PADDING * numberOfYPaddings) / numberOfRows;
y = LayoutMargin.top;
i = 0;
for (ULONG row = 0; row < numberOfRows; ++row)
{
// Give the last row the remaining space; the height we calculated might be off by a few
// pixels due to integer division.
if (row == numberOfRows - 1)
cellHeight = clientRect.bottom - LayoutMargin.bottom - y;
cellWidth = (clientRect.right - LayoutMargin.left - LayoutMargin.right - GRAPH_PADDING * numberOfXPaddings) / numberOfColumns;
x = LayoutMargin.left;
for (ULONG column = 0; column < numberOfColumns; column++)
{
// Give the last cell the remaining space; the width we calculated might be off by a few
// pixels due to integer division.
if (column == numberOfColumns - 1)
cellWidth = clientRect.right - LayoutMargin.right - x;
if (i < EtGpuTotalNodeCount)
{
deferHandle = DeferWindowPos(
deferHandle,
GraphHandle[i],
NULL,
x,
y,
cellWidth,
cellHeight - checkBoxRect.bottom - CHECKBOX_PADDING,
SWP_NOACTIVATE | SWP_NOZORDER
);
deferHandle = DeferWindowPos(
deferHandle,
CheckBoxHandle[i],
NULL,
x,
y + cellHeight - checkBoxRect.bottom,
cellWidth,
checkBoxRect.bottom,
SWP_NOACTIVATE | SWP_NOZORDER
);
i++;
}
x += cellWidth + GRAPH_PADDING;
}
y += cellHeight + GRAPH_PADDING;
}
EndDeferWindowPos(deferHandle);
}
break;
case WM_SIZING:
{
PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom);
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDCANCEL:
case IDOK:
{
EndDialog(hwndDlg, IDOK);
}
break;
}
}
break;
case WM_NOTIFY:
{
NMHDR *header = (NMHDR *)lParam;
ULONG i;
switch (header->code)
{
case GCN_GETDRAWINFO:
{
PPH_GRAPH_GETDRAWINFO getDrawInfo = (PPH_GRAPH_GETDRAWINFO)header;
PPH_GRAPH_DRAW_INFO drawInfo = getDrawInfo->DrawInfo;
drawInfo->Flags = PH_GRAPH_USE_GRID_X | PH_GRAPH_USE_GRID_Y;
SysInfoParameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), 0);
for (i = 0; i < EtGpuTotalNodeCount; i++)
{
if (header->hwndFrom == GraphHandle[i])
{
PhGraphStateGetDrawInfo(
&GraphState[i],
getDrawInfo,
EtGpuNodesHistory[i].Count
);
if (!GraphState[i].Valid)
{
PhCopyCircularBuffer_FLOAT(&EtGpuNodesHistory[i], GraphState[i].Data1, drawInfo->LineDataCount);
GraphState[i].Valid = TRUE;
}
break;
}
}
}
break;
case GCN_GETTOOLTIPTEXT:
{
PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)header;
if (getTooltipText->Index < getTooltipText->TotalCount)
{
for (i = 0; i < EtGpuTotalNodeCount; i++)
{
if (header->hwndFrom == GraphHandle[i])
{
if (GraphState[i].TooltipIndex != getTooltipText->Index)
{
FLOAT gpu;
ULONG adapterIndex;
PPH_STRING adapterDescription;
gpu = PhGetItemCircularBuffer_FLOAT(&EtGpuNodesHistory[i], getTooltipText->Index);
adapterIndex = EtGetGpuAdapterIndexFromNodeIndex(i);
if (adapterIndex != -1)
{
adapterDescription = EtGetGpuAdapterDescription(adapterIndex);
if (adapterDescription && adapterDescription->Length == 0)
PhClearReference(&adapterDescription);
if (!adapterDescription)
adapterDescription = PhFormatString(L"Adapter %lu", adapterIndex);
}
else
{
adapterDescription = PhCreateString(L"Unknown Adapter");
}
PhMoveReference(&GraphState[i].TooltipText, PhFormatString(
L"Node %lu on %s\n%.2f%%\n%s",
i,
adapterDescription->Buffer,
gpu * 100,
((PPH_STRING)PH_AUTO(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
));
PhDereferenceObject(adapterDescription);
}
getTooltipText->Text = GraphState[i].TooltipText->sr;
break;
}
}
}
}
break;
}
}
break;
case UPDATE_MSG:
{
ULONG i;
for (i = 0; i < EtGpuTotalNodeCount; i++)
{
GraphState[i].Valid = FALSE;
GraphState[i].TooltipIndex = -1;
Graph_MoveGrid(GraphHandle[i], 1);
Graph_Draw(GraphHandle[i]);
Graph_UpdateTooltip(GraphHandle[i]);
InvalidateRect(GraphHandle[i], NULL, FALSE);
}
}
break;
}
return FALSE;
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,466 @@
/*
* Process Hacker Extended Tools -
* notification icon extensions
*
* Copyright (C) 2011 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
#include "exttools.h"
#define GPU_ICON_ID 1
#define DISK_ICON_ID 2
#define NETWORK_ICON_ID 3
VOID EtpGpuIconUpdateCallback(
_In_ struct _PH_NF_ICON *Icon,
_Out_ PVOID *NewIconOrBitmap,
_Out_ PULONG Flags,
_Out_ PPH_STRING *NewText,
_In_opt_ PVOID Context
);
BOOLEAN EtpGpuIconMessageCallback(
_In_ struct _PH_NF_ICON *Icon,
_In_ ULONG_PTR WParam,
_In_ ULONG_PTR LParam,
_In_opt_ PVOID Context
);
VOID EtpDiskIconUpdateCallback(
_In_ struct _PH_NF_ICON *Icon,
_Out_ PVOID *NewIconOrBitmap,
_Out_ PULONG Flags,
_Out_ PPH_STRING *NewText,
_In_opt_ PVOID Context
);
BOOLEAN EtpDiskIconMessageCallback(
_In_ struct _PH_NF_ICON *Icon,
_In_ ULONG_PTR WParam,
_In_ ULONG_PTR LParam,
_In_opt_ PVOID Context
);
VOID EtpNetworkIconUpdateCallback(
_In_ struct _PH_NF_ICON *Icon,
_Out_ PVOID *NewIconOrBitmap,
_Out_ PULONG Flags,
_Out_ PPH_STRING *NewText,
_In_opt_ PVOID Context
);
BOOLEAN EtpNetworkIconMessageCallback(
_In_ struct _PH_NF_ICON *Icon,
_In_ ULONG_PTR WParam,
_In_ ULONG_PTR LParam,
_In_opt_ PVOID Context
);
VOID EtRegisterNotifyIcons(
VOID
)
{
PH_NF_ICON_REGISTRATION_DATA data;
data.MessageCallback = NULL;
data.UpdateCallback = EtpGpuIconUpdateCallback;
data.MessageCallback = EtpGpuIconMessageCallback;
PhPluginRegisterIcon(
PluginInstance,
GPU_ICON_ID,
NULL,
L"GPU history",
PH_NF_ICON_SHOW_MINIINFO | (EtGpuEnabled ? 0 : PH_NF_ICON_UNAVAILABLE),
&data
);
data.UpdateCallback = EtpDiskIconUpdateCallback;
data.MessageCallback = EtpDiskIconMessageCallback;
PhPluginRegisterIcon(
PluginInstance,
DISK_ICON_ID,
NULL,
L"Disk history",
PH_NF_ICON_SHOW_MINIINFO | (EtEtwEnabled ? 0 : PH_NF_ICON_UNAVAILABLE),
&data
);
data.UpdateCallback = EtpNetworkIconUpdateCallback;
data.MessageCallback = EtpNetworkIconMessageCallback;
PhPluginRegisterIcon(
PluginInstance,
NETWORK_ICON_ID,
NULL,
L"Network history",
PH_NF_ICON_SHOW_MINIINFO | (EtEtwEnabled ? 0 : PH_NF_ICON_UNAVAILABLE),
&data
);
}
VOID EtpGpuIconUpdateCallback(
_In_ struct _PH_NF_ICON *Icon,
_Out_ PVOID *NewIconOrBitmap,
_Out_ PULONG Flags,
_Out_ PPH_STRING *NewText,
_In_opt_ PVOID Context
)
{
static PH_GRAPH_DRAW_INFO drawInfo =
{
16,
16,
0,
2,
RGB(0x00, 0x00, 0x00),
16,
NULL,
NULL,
0,
0,
0,
0
};
ULONG maxDataCount;
ULONG lineDataCount;
PFLOAT lineData1;
HBITMAP bitmap;
PVOID bits;
HDC hdc;
HBITMAP oldBitmap;
HANDLE maxGpuProcessId;
PPH_PROCESS_ITEM maxGpuProcessItem;
PH_FORMAT format[8];
// Icon
Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap);
maxDataCount = drawInfo.Width / 2 + 1;
lineData1 = _alloca(maxDataCount * sizeof(FLOAT));
lineDataCount = min(maxDataCount, EtGpuNodeHistory.Count);
PhCopyCircularBuffer_FLOAT(&EtGpuNodeHistory, lineData1, lineDataCount);
drawInfo.LineDataCount = lineDataCount;
drawInfo.LineData1 = lineData1;
drawInfo.LineColor1 = PhGetIntegerSetting(L"ColorCpuKernel");
drawInfo.LineBackColor1 = PhHalveColorBrightness(drawInfo.LineColor1);
if (bits)
PhDrawGraphDirect(hdc, bits, &drawInfo);
SelectObject(hdc, oldBitmap);
*NewIconOrBitmap = bitmap;
*Flags = PH_NF_UPDATE_IS_BITMAP;
// Text
if (EtMaxGpuNodeHistory.Count != 0)
maxGpuProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&EtMaxGpuNodeHistory, 0));
else
maxGpuProcessId = NULL;
if (maxGpuProcessId)
maxGpuProcessItem = PhReferenceProcessItem(maxGpuProcessId);
else
maxGpuProcessItem = NULL;
PhInitFormatS(&format[0], L"GPU Usage: ");
PhInitFormatF(&format[1], EtGpuNodeUsage * 100, 2);
PhInitFormatC(&format[2], '%');
if (maxGpuProcessItem)
{
PhInitFormatC(&format[3], '\n');
PhInitFormatSR(&format[4], maxGpuProcessItem->ProcessName->sr);
PhInitFormatS(&format[5], L": ");
PhInitFormatF(&format[6], EtGetProcessBlock(maxGpuProcessItem)->GpuNodeUsage * 100, 2);
PhInitFormatC(&format[7], '%');
}
*NewText = PhFormat(format, maxGpuProcessItem ? 8 : 3, 128);
if (maxGpuProcessItem) PhDereferenceObject(maxGpuProcessItem);
}
BOOLEAN EtpGpuIconMessageCallback(
_In_ struct _PH_NF_ICON *Icon,
_In_ ULONG_PTR WParam,
_In_ ULONG_PTR LParam,
_In_opt_ PVOID Context
)
{
switch (LOWORD(LParam))
{
case PH_NF_MSG_SHOWMINIINFOSECTION:
{
PPH_NF_MSG_SHOWMINIINFOSECTION_DATA data = (PVOID)WParam;
data->SectionName = L"GPU";
}
return TRUE;
}
return FALSE;
}
VOID EtpDiskIconUpdateCallback(
_In_ struct _PH_NF_ICON *Icon,
_Out_ PVOID *NewIconOrBitmap,
_Out_ PULONG Flags,
_Out_ PPH_STRING *NewText,
_In_opt_ PVOID Context
)
{
static PH_GRAPH_DRAW_INFO drawInfo =
{
16,
16,
PH_GRAPH_USE_LINE_2,
2,
RGB(0x00, 0x00, 0x00),
16,
NULL,
NULL,
0,
0,
0,
0
};
ULONG maxDataCount;
ULONG lineDataCount;
PFLOAT lineData1;
PFLOAT lineData2;
FLOAT max;
ULONG i;
HBITMAP bitmap;
PVOID bits;
HDC hdc;
HBITMAP oldBitmap;
HANDLE maxDiskProcessId;
PPH_PROCESS_ITEM maxDiskProcessItem;
PH_FORMAT format[6];
// Icon
Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap);
maxDataCount = drawInfo.Width / 2 + 1;
lineData1 = _alloca(maxDataCount * sizeof(FLOAT));
lineData2 = _alloca(maxDataCount * sizeof(FLOAT));
lineDataCount = min(maxDataCount, EtDiskReadHistory.Count);
max = 1024 * 1024; // minimum scaling of 1 MB.
for (i = 0; i < lineDataCount; i++)
{
lineData1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&EtDiskReadHistory, i);
lineData2[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&EtDiskWriteHistory, i);
if (max < lineData1[i] + lineData2[i])
max = lineData1[i] + lineData2[i];
}
PhDivideSinglesBySingle(lineData1, max, lineDataCount);
PhDivideSinglesBySingle(lineData2, max, lineDataCount);
drawInfo.LineDataCount = lineDataCount;
drawInfo.LineData1 = lineData1;
drawInfo.LineData2 = lineData2;
drawInfo.LineColor1 = PhGetIntegerSetting(L"ColorIoReadOther");
drawInfo.LineColor2 = PhGetIntegerSetting(L"ColorIoWrite");
drawInfo.LineBackColor1 = PhHalveColorBrightness(drawInfo.LineColor1);
drawInfo.LineBackColor2 = PhHalveColorBrightness(drawInfo.LineColor2);
if (bits)
PhDrawGraphDirect(hdc, bits, &drawInfo);
SelectObject(hdc, oldBitmap);
*NewIconOrBitmap = bitmap;
*Flags = PH_NF_UPDATE_IS_BITMAP;
// Text
if (EtMaxDiskHistory.Count != 0)
maxDiskProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&EtMaxDiskHistory, 0));
else
maxDiskProcessId = NULL;
if (maxDiskProcessId)
maxDiskProcessItem = PhReferenceProcessItem(maxDiskProcessId);
else
maxDiskProcessItem = NULL;
PhInitFormatS(&format[0], L"Disk\nR: ");
PhInitFormatSize(&format[1], EtDiskReadDelta.Delta);
PhInitFormatS(&format[2], L"\nW: ");
PhInitFormatSize(&format[3], EtDiskWriteDelta.Delta);
if (maxDiskProcessItem)
{
PhInitFormatC(&format[4], '\n');
PhInitFormatSR(&format[5], maxDiskProcessItem->ProcessName->sr);
}
*NewText = PhFormat(format, maxDiskProcessItem ? 6 : 4, 128);
if (maxDiskProcessItem) PhDereferenceObject(maxDiskProcessItem);
}
BOOLEAN EtpDiskIconMessageCallback(
_In_ struct _PH_NF_ICON *Icon,
_In_ ULONG_PTR WParam,
_In_ ULONG_PTR LParam,
_In_opt_ PVOID Context
)
{
switch (LOWORD(LParam))
{
case PH_NF_MSG_SHOWMINIINFOSECTION:
{
PPH_NF_MSG_SHOWMINIINFOSECTION_DATA data = (PVOID)WParam;
data->SectionName = L"Disk";
}
return TRUE;
}
return FALSE;
}
VOID EtpNetworkIconUpdateCallback(
_In_ struct _PH_NF_ICON *Icon,
_Out_ PVOID *NewIconOrBitmap,
_Out_ PULONG Flags,
_Out_ PPH_STRING *NewText,
_In_opt_ PVOID Context
)
{
static PH_GRAPH_DRAW_INFO drawInfo =
{
16,
16,
PH_GRAPH_USE_LINE_2,
2,
RGB(0x00, 0x00, 0x00),
16,
NULL,
NULL,
0,
0,
0,
0
};
ULONG maxDataCount;
ULONG lineDataCount;
PFLOAT lineData1;
PFLOAT lineData2;
FLOAT max;
ULONG i;
HBITMAP bitmap;
PVOID bits;
HDC hdc;
HBITMAP oldBitmap;
HANDLE maxNetworkProcessId;
PPH_PROCESS_ITEM maxNetworkProcessItem;
PH_FORMAT format[6];
// Icon
Icon->Pointers->BeginBitmap(&drawInfo.Width, &drawInfo.Height, &bitmap, &bits, &hdc, &oldBitmap);
maxDataCount = drawInfo.Width / 2 + 1;
lineData1 = _alloca(maxDataCount * sizeof(FLOAT));
lineData2 = _alloca(maxDataCount * sizeof(FLOAT));
lineDataCount = min(maxDataCount, EtNetworkReceiveHistory.Count);
max = 1024 * 1024; // minimum scaling of 1 MB.
for (i = 0; i < lineDataCount; i++)
{
lineData1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&EtNetworkReceiveHistory, i);
lineData2[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&EtNetworkSendHistory, i);
if (max < lineData1[i] + lineData2[i])
max = lineData1[i] + lineData2[i];
}
PhDivideSinglesBySingle(lineData1, max, lineDataCount);
PhDivideSinglesBySingle(lineData2, max, lineDataCount);
drawInfo.LineDataCount = lineDataCount;
drawInfo.LineData1 = lineData1;
drawInfo.LineData2 = lineData2;
drawInfo.LineColor1 = PhGetIntegerSetting(L"ColorIoReadOther");
drawInfo.LineColor2 = PhGetIntegerSetting(L"ColorIoWrite");
drawInfo.LineBackColor1 = PhHalveColorBrightness(drawInfo.LineColor1);
drawInfo.LineBackColor2 = PhHalveColorBrightness(drawInfo.LineColor2);
if (bits)
PhDrawGraphDirect(hdc, bits, &drawInfo);
SelectObject(hdc, oldBitmap);
*NewIconOrBitmap = bitmap;
*Flags = PH_NF_UPDATE_IS_BITMAP;
// Text
if (EtMaxNetworkHistory.Count != 0)
maxNetworkProcessId = UlongToHandle(PhGetItemCircularBuffer_ULONG(&EtMaxNetworkHistory, 0));
else
maxNetworkProcessId = NULL;
if (maxNetworkProcessId)
maxNetworkProcessItem = PhReferenceProcessItem(maxNetworkProcessId);
else
maxNetworkProcessItem = NULL;
PhInitFormatS(&format[0], L"Network\nR: ");
PhInitFormatSize(&format[1], EtNetworkReceiveDelta.Delta);
PhInitFormatS(&format[2], L"\nS: ");
PhInitFormatSize(&format[3], EtNetworkSendDelta.Delta);
if (maxNetworkProcessItem)
{
PhInitFormatC(&format[4], '\n');
PhInitFormatSR(&format[5], maxNetworkProcessItem->ProcessName->sr);
}
*NewText = PhFormat(format, maxNetworkProcessItem ? 6 : 4, 128);
if (maxNetworkProcessItem) PhDereferenceObject(maxNetworkProcessItem);
}
BOOLEAN EtpNetworkIconMessageCallback(
_In_ struct _PH_NF_ICON *Icon,
_In_ ULONG_PTR WParam,
_In_ ULONG_PTR LParam,
_In_opt_ PVOID Context
)
{
switch (LOWORD(LParam))
{
case PH_NF_MSG_SHOWMINIINFOSECTION:
{
PPH_NF_MSG_SHOWMINIINFOSECTION_DATA data = (PVOID)WParam;
data->SectionName = L"Network";
}
return TRUE;
}
return FALSE;
}

View File

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

View File

@@ -0,0 +1,173 @@
/*
* Process Hacker Extended Tools -
* services referencing module
*
* Copyright (C) 2010-2011 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
#include "exttools.h"
#include <subprocesstag.h>
typedef struct _MODULE_SERVICES_CONTEXT
{
HANDLE ProcessId;
PWSTR ModuleName;
} MODULE_SERVICES_CONTEXT, *PMODULE_SERVICES_CONTEXT;
INT_PTR CALLBACK EtpModuleServicesDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
VOID EtShowModuleServicesDialog(
_In_ HWND ParentWindowHandle,
_In_ HANDLE ProcessId,
_In_ PWSTR ModuleName
)
{
MODULE_SERVICES_CONTEXT context;
context.ProcessId = ProcessId;
context.ModuleName = ModuleName;
DialogBoxParam(
PluginInstance->DllBase,
MAKEINTRESOURCE(IDD_MODSERVICES),
ParentWindowHandle,
EtpModuleServicesDlgProc,
(LPARAM)&context
);
}
INT_PTR CALLBACK EtpModuleServicesDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
PMODULE_SERVICES_CONTEXT context = (PMODULE_SERVICES_CONTEXT)lParam;
ULONG win32Result;
PQUERY_TAG_INFORMATION I_QueryTagInformation;
TAG_INFO_NAMES_REFERENCING_MODULE namesReferencingModule;
PPH_LIST serviceList;
PPH_SERVICE_ITEM *serviceItems;
HWND serviceListHandle;
RECT rect;
PPH_PROCESS_ITEM processItem;
PPH_STRING message;
PhCenterWindow(hwndDlg, GetParent(hwndDlg));
I_QueryTagInformation = PhGetModuleProcAddress(L"advapi32.dll", "I_QueryTagInformation");
if (!I_QueryTagInformation)
{
PhShowError(hwndDlg, L"Unable to query services because the feature is not supported by the operating system.");
EndDialog(hwndDlg, IDCANCEL);
return FALSE;
}
memset(&namesReferencingModule, 0, sizeof(TAG_INFO_NAMES_REFERENCING_MODULE));
namesReferencingModule.InParams.dwPid = HandleToUlong(context->ProcessId);
namesReferencingModule.InParams.pszModule = context->ModuleName;
win32Result = I_QueryTagInformation(NULL, eTagInfoLevelNamesReferencingModule, &namesReferencingModule);
if (win32Result == ERROR_NO_MORE_ITEMS)
win32Result = 0;
if (win32Result != 0)
{
PhShowStatus(hwndDlg, L"Unable to query services", 0, win32Result);
EndDialog(hwndDlg, IDCANCEL);
return FALSE;
}
serviceList = PhCreateList(16);
if (namesReferencingModule.OutParams.pmszNames)
{
PPH_SERVICE_ITEM serviceItem;
PWSTR serviceName;
ULONG nameLength;
serviceName = namesReferencingModule.OutParams.pmszNames;
while (TRUE)
{
nameLength = (ULONG)PhCountStringZ(serviceName);
if (nameLength == 0)
break;
if (serviceItem = PhReferenceServiceItem(serviceName))
PhAddItemList(serviceList, serviceItem);
serviceName += nameLength + 1;
}
LocalFree(namesReferencingModule.OutParams.pmszNames);
}
serviceItems = PhAllocateCopy(serviceList->Items, serviceList->Count * sizeof(PPH_SERVICE_ITEM));
PhDereferenceObject(serviceList);
serviceListHandle = PhCreateServiceListControl(hwndDlg, serviceItems, serviceList->Count);
// Position the control.
GetWindowRect(GetDlgItem(hwndDlg, IDC_SERVICES_LAYOUT), &rect);
MapWindowPoints(NULL, hwndDlg, (POINT *)&rect, 2);
MoveWindow(serviceListHandle, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, FALSE);
ShowWindow(serviceListHandle, SW_SHOW);
if (processItem = PhReferenceProcessItem(context->ProcessId))
{
message = PhFormatString(L"Services referencing %s in %s:", context->ModuleName, processItem->ProcessName->Buffer);
PhDereferenceObject(processItem);
}
else
{
message = PhFormatString(L"Services referencing %s:", context->ModuleName);
}
SetDlgItemText(hwndDlg, IDC_MESSAGE, message->Buffer);
PhDereferenceObject(message);
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDCANCEL:
case IDOK:
EndDialog(hwndDlg, IDOK);
break;
}
}
break;
}
return FALSE;
}

View File

@@ -0,0 +1,312 @@
/*
* Process Hacker Extended Tools -
* handle properties extensions
*
* Copyright (C) 2010-2011 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
#include "exttools.h"
#include <symprv.h>
typedef struct _COMMON_PAGE_CONTEXT
{
PPH_HANDLE_ITEM HandleItem;
HANDLE ProcessId;
} COMMON_PAGE_CONTEXT, *PCOMMON_PAGE_CONTEXT;
HPROPSHEETPAGE EtpCommonCreatePage(
_In_ PPH_PLUGIN_HANDLE_PROPERTIES_CONTEXT Context,
_In_ PWSTR Template,
_In_ DLGPROC DlgProc
);
INT CALLBACK EtpCommonPropPageProc(
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ LPPROPSHEETPAGE ppsp
);
INT_PTR CALLBACK EtpAlpcPortPageDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
INT_PTR CALLBACK EtpTpWorkerFactoryPageDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
VOID EtHandlePropertiesInitializing(
_In_ PVOID Parameter
)
{
PPH_PLUGIN_OBJECT_PROPERTIES objectProperties = Parameter;
PPH_PLUGIN_HANDLE_PROPERTIES_CONTEXT context = objectProperties->Parameter;
if (objectProperties->NumberOfPages < objectProperties->MaximumNumberOfPages)
{
HPROPSHEETPAGE page = NULL;
if (PhEqualString2(context->HandleItem->TypeName, L"ALPC Port", TRUE))
{
page = EtpCommonCreatePage(
context,
MAKEINTRESOURCE(IDD_OBJALPCPORT),
EtpAlpcPortPageDlgProc
);
}
else if (PhEqualString2(context->HandleItem->TypeName, L"TpWorkerFactory", TRUE))
{
page = EtpCommonCreatePage(
context,
MAKEINTRESOURCE(IDD_OBJTPWORKERFACTORY),
EtpTpWorkerFactoryPageDlgProc
);
}
// Insert our page into the second slot.
if (page)
{
if (objectProperties->NumberOfPages > 1)
{
memmove(&objectProperties->Pages[2], &objectProperties->Pages[1],
(objectProperties->NumberOfPages - 1) * sizeof(HPROPSHEETPAGE));
}
objectProperties->Pages[1] = page;
objectProperties->NumberOfPages++;
}
}
}
static HPROPSHEETPAGE EtpCommonCreatePage(
_In_ PPH_PLUGIN_HANDLE_PROPERTIES_CONTEXT Context,
_In_ PWSTR Template,
_In_ DLGPROC DlgProc
)
{
HPROPSHEETPAGE propSheetPageHandle;
PROPSHEETPAGE propSheetPage;
PCOMMON_PAGE_CONTEXT pageContext;
pageContext = PhCreateAlloc(sizeof(COMMON_PAGE_CONTEXT));
memset(pageContext, 0, sizeof(COMMON_PAGE_CONTEXT));
pageContext->HandleItem = Context->HandleItem;
pageContext->ProcessId = Context->ProcessId;
memset(&propSheetPage, 0, sizeof(PROPSHEETPAGE));
propSheetPage.dwSize = sizeof(PROPSHEETPAGE);
propSheetPage.dwFlags = PSP_USECALLBACK;
propSheetPage.hInstance = PluginInstance->DllBase;
propSheetPage.pszTemplate = Template;
propSheetPage.pfnDlgProc = DlgProc;
propSheetPage.lParam = (LPARAM)pageContext;
propSheetPage.pfnCallback = EtpCommonPropPageProc;
propSheetPageHandle = CreatePropertySheetPage(&propSheetPage);
PhDereferenceObject(pageContext); // already got a ref from above call
return propSheetPageHandle;
}
INT CALLBACK EtpCommonPropPageProc(
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ LPPROPSHEETPAGE ppsp
)
{
PCOMMON_PAGE_CONTEXT pageContext;
pageContext = (PCOMMON_PAGE_CONTEXT)ppsp->lParam;
if (uMsg == PSPCB_ADDREF)
PhReferenceObject(pageContext);
else if (uMsg == PSPCB_RELEASE)
PhDereferenceObject(pageContext);
return 1;
}
static NTSTATUS EtpDuplicateHandleFromProcess(
_Out_ PHANDLE Handle,
_In_ ACCESS_MASK DesiredAccess,
_In_ PCOMMON_PAGE_CONTEXT Context
)
{
NTSTATUS status;
HANDLE processHandle;
if (!NT_SUCCESS(status = PhOpenProcess(
&processHandle,
PROCESS_DUP_HANDLE,
Context->ProcessId
)))
return status;
status = NtDuplicateObject(
processHandle,
Context->HandleItem->Handle,
NtCurrentProcess(),
Handle,
DesiredAccess,
0,
0
);
NtClose(processHandle);
return status;
}
INT_PTR CALLBACK EtpAlpcPortPageDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam;
PCOMMON_PAGE_CONTEXT context = (PCOMMON_PAGE_CONTEXT)propSheetPage->lParam;
HANDLE portHandle;
if (NT_SUCCESS(EtpDuplicateHandleFromProcess(&portHandle, READ_CONTROL, context)))
{
ALPC_BASIC_INFORMATION basicInfo;
if (NT_SUCCESS(NtAlpcQueryInformation(
portHandle,
AlpcBasicInformation,
&basicInfo,
sizeof(ALPC_BASIC_INFORMATION),
NULL
)))
{
PH_FORMAT format[2];
PPH_STRING string;
PhInitFormatS(&format[0], L"Sequence Number: ");
PhInitFormatD(&format[1], basicInfo.SequenceNo);
format[1].Type |= FormatGroupDigits;
string = PhFormat(format, 2, 128);
SetDlgItemText(hwndDlg, IDC_SEQUENCENUMBER, string->Buffer);
PhDereferenceObject(string);
SetDlgItemText(hwndDlg, IDC_PORTCONTEXT,
PhaFormatString(L"Port Context: 0x%Ix", basicInfo.PortContext)->Buffer);
}
NtClose(portHandle);
}
}
break;
}
return FALSE;
}
static BOOLEAN NTAPI EnumGenericModulesCallback(
_In_ PPH_MODULE_INFO Module,
_In_opt_ PVOID Context
)
{
if (Module->Type == PH_MODULE_TYPE_MODULE || Module->Type == PH_MODULE_TYPE_WOW64_MODULE)
{
PhLoadModuleSymbolProvider(Context, Module->FileName->Buffer,
(ULONG64)Module->BaseAddress, Module->Size);
}
return TRUE;
}
INT_PTR CALLBACK EtpTpWorkerFactoryPageDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
LPPROPSHEETPAGE propSheetPage = (LPPROPSHEETPAGE)lParam;
PCOMMON_PAGE_CONTEXT context = (PCOMMON_PAGE_CONTEXT)propSheetPage->lParam;
HANDLE workerFactoryHandle;
if (NT_SUCCESS(EtpDuplicateHandleFromProcess(&workerFactoryHandle, WORKER_FACTORY_QUERY_INFORMATION, context)))
{
WORKER_FACTORY_BASIC_INFORMATION basicInfo;
if (NT_SUCCESS(NtQueryInformationWorkerFactory(
workerFactoryHandle,
WorkerFactoryBasicInformation,
&basicInfo,
sizeof(WORKER_FACTORY_BASIC_INFORMATION),
NULL
)))
{
PPH_SYMBOL_PROVIDER symbolProvider;
PPH_STRING symbol = NULL;
symbolProvider = PhCreateSymbolProvider(basicInfo.ProcessId);
PhLoadSymbolProviderOptions(symbolProvider);
if (symbolProvider->IsRealHandle)
{
PhEnumGenericModules(basicInfo.ProcessId, symbolProvider->ProcessHandle,
0, EnumGenericModulesCallback, symbolProvider);
symbol = PhGetSymbolFromAddress(symbolProvider, (ULONG64)basicInfo.StartRoutine,
NULL, NULL, NULL, NULL);
}
PhDereferenceObject(symbolProvider);
if (symbol)
{
SetDlgItemText(hwndDlg, IDC_WORKERTHREADSTART,
PhaFormatString(L"Worker Thread Start: %s", symbol->Buffer)->Buffer);
PhDereferenceObject(symbol);
}
else
{
SetDlgItemText(hwndDlg, IDC_WORKERTHREADSTART,
PhaFormatString(L"Worker Thread Start: 0x%Ix", basicInfo.StartRoutine)->Buffer);
}
SetDlgItemText(hwndDlg, IDC_WORKERTHREADCONTEXT,
PhaFormatString(L"Worker Thread Context: 0x%Ix", basicInfo.StartParameter)->Buffer);
}
NtClose(workerFactoryHandle);
}
}
break;
}
return FALSE;
}

View File

@@ -0,0 +1,85 @@
/*
* Process Hacker Extended Tools -
* options dialog
*
* Copyright (C) 2010 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
#include "exttools.h"
INT_PTR CALLBACK OptionsDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
VOID EtShowOptionsDialog(
_In_ HWND ParentWindowHandle
)
{
DialogBox(
PluginInstance->DllBase,
MAKEINTRESOURCE(IDD_OPTIONS),
ParentWindowHandle,
OptionsDlgProc
);
}
INT_PTR CALLBACK OptionsDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
switch (uMsg)
{
case WM_INITDIALOG:
{
Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLEETWMONITOR), PhGetIntegerSetting(SETTING_NAME_ENABLE_ETW_MONITOR) ? BST_CHECKED : BST_UNCHECKED);
Button_SetCheck(GetDlgItem(hwndDlg, IDC_ENABLEGPUMONITOR), PhGetIntegerSetting(SETTING_NAME_ENABLE_GPU_MONITOR) ? BST_CHECKED : BST_UNCHECKED);
if (WindowsVersion < WINDOWS_7)
EnableWindow(GetDlgItem(hwndDlg, IDC_ENABLEGPUMONITOR), FALSE);
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDCANCEL:
EndDialog(hwndDlg, IDCANCEL);
break;
case IDOK:
{
PhSetIntegerSetting(SETTING_NAME_ENABLE_ETW_MONITOR,
Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLEETWMONITOR)) == BST_CHECKED);
PhSetIntegerSetting(SETTING_NAME_ENABLE_GPU_MONITOR,
Button_GetCheck(GetDlgItem(hwndDlg, IDC_ENABLEGPUMONITOR)) == BST_CHECKED);
EndDialog(hwndDlg, IDOK);
}
break;
}
}
break;
}
return FALSE;
}

View File

@@ -0,0 +1,95 @@
/*
* Process Hacker Extended Tools -
* process icon duplication
*
* Copyright (C) 2011 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
#include "exttools.h"
PET_PROCESS_ICON EtProcIconCreateProcessIcon(
_In_ HICON Icon
)
{
PET_PROCESS_ICON processIcon;
processIcon = PhAllocate(sizeof(ET_PROCESS_ICON));
processIcon->RefCount = 1;
processIcon->Icon = CopyIcon(Icon);
return processIcon;
}
VOID EtProcIconReferenceProcessIcon(
_Inout_ PET_PROCESS_ICON ProcessIcon
)
{
_InterlockedIncrement(&ProcessIcon->RefCount);
}
VOID EtProcIconDereferenceProcessIcon(
_Inout_ PET_PROCESS_ICON ProcessIcon
)
{
if (_InterlockedDecrement(&ProcessIcon->RefCount) == 0)
{
DestroyIcon(ProcessIcon->Icon);
PhFree(ProcessIcon);
}
}
PET_PROCESS_ICON EtProcIconReferenceSmallProcessIcon(
_Inout_ PET_PROCESS_BLOCK Block
)
{
PET_PROCESS_ICON smallProcessIcon;
smallProcessIcon = Block->SmallProcessIcon;
if (!smallProcessIcon && PhTestEvent(&Block->ProcessItem->Stage1Event))
{
smallProcessIcon = EtProcIconCreateProcessIcon(Block->ProcessItem->SmallIcon);
if (_InterlockedCompareExchangePointer(
&Block->SmallProcessIcon,
smallProcessIcon,
NULL
) != NULL)
{
EtProcIconDereferenceProcessIcon(smallProcessIcon);
smallProcessIcon = Block->SmallProcessIcon;
}
}
if (smallProcessIcon)
{
EtProcIconReferenceProcessIcon(smallProcessIcon);
}
return smallProcessIcon;
}
VOID EtProcIconNotifyProcessDelete(
_Inout_ PET_PROCESS_BLOCK Block
)
{
if (Block->SmallProcessIcon)
{
EtProcIconDereferenceProcessIcon(Block->SmallProcessIcon);
}
}

View File

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

View File

@@ -0,0 +1,64 @@
/*
* Process Hacker Extended Tools -
* thread actions extensions
*
* Copyright (C) 2010 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
#include "exttools.h"
BOOLEAN EtUiCancelIoThread(
_In_ HWND hWnd,
_In_ PPH_THREAD_ITEM Thread
)
{
NTSTATUS status;
BOOLEAN cont = FALSE;
HANDLE threadHandle;
IO_STATUS_BLOCK isb;
if (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage(
hWnd,
L"end",
L"I/O for the selected thread",
NULL,
FALSE
))
cont = TRUE;
if (!cont)
return FALSE;
if (NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_TERMINATE, Thread->ThreadId)))
{
status = NtCancelSynchronousIoFile(threadHandle, NULL, &isb);
}
if (status == STATUS_NOT_FOUND)
{
PhShowInformation(hWnd, L"There is no synchronous I/O to cancel.");
return FALSE;
}
else if (!NT_SUCCESS(status))
{
PhShowStatus(hWnd, L"Unable to cancel synchronous I/O", status, 0);
return FALSE;
}
return TRUE;
}

View File

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

View File

@@ -0,0 +1,357 @@
/*
* Process Hacker Extended Tools -
* unloaded DLLs display
*
* Copyright (C) 2010-2011 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
#include "exttools.h"
typedef struct _UNLOADED_DLLS_CONTEXT
{
PPH_PROCESS_ITEM ProcessItem;
HWND ListViewHandle;
PVOID CapturedEventTrace;
} UNLOADED_DLLS_CONTEXT, *PUNLOADED_DLLS_CONTEXT;
INT_PTR CALLBACK EtpUnloadedDllsDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
VOID EtShowUnloadedDllsDialog(
_In_ HWND ParentWindowHandle,
_In_ PPH_PROCESS_ITEM ProcessItem
)
{
UNLOADED_DLLS_CONTEXT context;
context.ProcessItem = ProcessItem;
context.CapturedEventTrace = NULL;
DialogBoxParam(
PluginInstance->DllBase,
MAKEINTRESOURCE(IDD_UNLOADEDDLLS),
ParentWindowHandle,
EtpUnloadedDllsDlgProc,
(LPARAM)&context
);
if (context.CapturedEventTrace)
PhFree(context.CapturedEventTrace);
}
BOOLEAN EtpRefreshUnloadedDlls(
_In_ HWND hwndDlg,
_In_ PUNLOADED_DLLS_CONTEXT Context
)
{
NTSTATUS status;
PULONG elementSize;
PULONG elementCount;
PVOID eventTrace;
HANDLE processHandle = NULL;
ULONG eventTraceSize;
ULONG capturedElementSize;
ULONG capturedElementCount;
PVOID capturedEventTracePointer;
PVOID capturedEventTrace = NULL;
ULONG i;
PVOID currentEvent;
HWND lvHandle;
lvHandle = GetDlgItem(hwndDlg, IDC_LIST);
ListView_DeleteAllItems(lvHandle);
RtlGetUnloadEventTraceEx(&elementSize, &elementCount, &eventTrace);
if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_VM_READ, Context->ProcessItem->ProcessId)))
goto CleanupExit;
// We have the pointers for the unload event trace information.
// Since ntdll is loaded at the same base address across all processes,
// we can read the information in.
if (!NT_SUCCESS(status = NtReadVirtualMemory(
processHandle,
elementSize,
&capturedElementSize,
sizeof(ULONG),
NULL
)))
goto CleanupExit;
if (!NT_SUCCESS(status = NtReadVirtualMemory(
processHandle,
elementCount,
&capturedElementCount,
sizeof(ULONG),
NULL
)))
goto CleanupExit;
if (!NT_SUCCESS(status = NtReadVirtualMemory(
processHandle,
eventTrace,
&capturedEventTracePointer,
sizeof(PVOID),
NULL
)))
goto CleanupExit;
if (!capturedEventTracePointer)
goto CleanupExit; // no events
if (capturedElementCount > 0x4000)
capturedElementCount = 0x4000;
eventTraceSize = capturedElementSize * capturedElementCount;
capturedEventTrace = PhAllocateSafe(eventTraceSize);
if (!capturedEventTrace)
{
status = STATUS_NO_MEMORY;
goto CleanupExit;
}
if (!NT_SUCCESS(status = NtReadVirtualMemory(
processHandle,
capturedEventTracePointer,
capturedEventTrace,
eventTraceSize,
NULL
)))
goto CleanupExit;
currentEvent = capturedEventTrace;
ExtendedListView_SetRedraw(lvHandle, FALSE);
for (i = 0; i < capturedElementCount; i++)
{
PRTL_UNLOAD_EVENT_TRACE rtlEvent = currentEvent;
INT lvItemIndex;
WCHAR buffer[128];
PPH_STRING string;
LARGE_INTEGER time;
SYSTEMTIME systemTime;
if (!rtlEvent->BaseAddress)
break;
PhPrintUInt32(buffer, rtlEvent->Sequence);
lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, buffer, rtlEvent);
// Name
if (PhCopyStringZ(rtlEvent->ImageName, sizeof(rtlEvent->ImageName) / sizeof(WCHAR),
buffer, sizeof(buffer) / sizeof(WCHAR), NULL))
{
PhSetListViewSubItem(lvHandle, lvItemIndex, 1, buffer);
}
// Base Address
PhPrintPointer(buffer, rtlEvent->BaseAddress);
PhSetListViewSubItem(lvHandle, lvItemIndex, 2, buffer);
// Size
string = PhFormatSize(rtlEvent->SizeOfImage, -1);
PhSetListViewSubItem(lvHandle, lvItemIndex, 3, string->Buffer);
PhDereferenceObject(string);
// Time Stamp
RtlSecondsSince1970ToTime(rtlEvent->TimeDateStamp, &time);
PhLargeIntegerToLocalSystemTime(&systemTime, &time);
string = PhFormatDateTime(&systemTime);
PhSetListViewSubItem(lvHandle, lvItemIndex, 4, string->Buffer);
PhDereferenceObject(string);
// Checksum
PhPrintPointer(buffer, UlongToPtr(rtlEvent->CheckSum));
PhSetListViewSubItem(lvHandle, lvItemIndex, 5, buffer);
currentEvent = PTR_ADD_OFFSET(currentEvent, capturedElementSize);
}
ExtendedListView_SortItems(lvHandle);
ExtendedListView_SetRedraw(lvHandle, TRUE);
if (Context->CapturedEventTrace)
PhFree(Context->CapturedEventTrace);
Context->CapturedEventTrace = capturedEventTrace;
CleanupExit:
if (processHandle)
NtClose(processHandle);
if (NT_SUCCESS(status))
{
return TRUE;
}
else
{
PhShowStatus(hwndDlg, L"Unable to retrieve unload event trace information", status, 0);
return FALSE;
}
}
static INT NTAPI EtpNumberCompareFunction(
_In_ PVOID Item1,
_In_ PVOID Item2,
_In_opt_ PVOID Context
)
{
PRTL_UNLOAD_EVENT_TRACE item1 = Item1;
PRTL_UNLOAD_EVENT_TRACE item2 = Item2;
return uintcmp(item1->Sequence, item2->Sequence);
}
static INT NTAPI EtpBaseAddressCompareFunction(
_In_ PVOID Item1,
_In_ PVOID Item2,
_In_opt_ PVOID Context
)
{
PRTL_UNLOAD_EVENT_TRACE item1 = Item1;
PRTL_UNLOAD_EVENT_TRACE item2 = Item2;
return uintptrcmp((ULONG_PTR)item1->BaseAddress, (ULONG_PTR)item2->BaseAddress);
}
static INT NTAPI EtpSizeCompareFunction(
_In_ PVOID Item1,
_In_ PVOID Item2,
_In_opt_ PVOID Context
)
{
PRTL_UNLOAD_EVENT_TRACE item1 = Item1;
PRTL_UNLOAD_EVENT_TRACE item2 = Item2;
return uintptrcmp(item1->SizeOfImage, item2->SizeOfImage);
}
static INT NTAPI EtpTimeStampCompareFunction(
_In_ PVOID Item1,
_In_ PVOID Item2,
_In_opt_ PVOID Context
)
{
PRTL_UNLOAD_EVENT_TRACE item1 = Item1;
PRTL_UNLOAD_EVENT_TRACE item2 = Item2;
return uintcmp(item1->TimeDateStamp, item2->TimeDateStamp);
}
static INT NTAPI EtpCheckSumCompareFunction(
_In_ PVOID Item1,
_In_ PVOID Item2,
_In_opt_ PVOID Context
)
{
PRTL_UNLOAD_EVENT_TRACE item1 = Item1;
PRTL_UNLOAD_EVENT_TRACE item2 = Item2;
return uintcmp(item1->CheckSum, item2->CheckSum);
}
INT_PTR CALLBACK EtpUnloadedDllsDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
PUNLOADED_DLLS_CONTEXT context;
if (uMsg == WM_INITDIALOG)
{
context = (PUNLOADED_DLLS_CONTEXT)lParam;
SetProp(hwndDlg, L"Context", (HANDLE)context);
}
else
{
context = (PUNLOADED_DLLS_CONTEXT)GetProp(hwndDlg, L"Context");
if (uMsg == WM_DESTROY)
RemoveProp(hwndDlg, L"Context");
}
if (!context)
return FALSE;
switch (uMsg)
{
case WM_INITDIALOG:
{
HWND lvHandle;
PhCenterWindow(hwndDlg, GetParent(hwndDlg));
context->ListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_LIST);
PhSetListViewStyle(lvHandle, FALSE, TRUE);
PhSetControlTheme(lvHandle, L"explorer");
PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 40, L"No.");
PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 120, L"Name");
PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 80, L"Base Address");
PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 60, L"Size");
PhAddListViewColumn(lvHandle, 4, 4, 4, LVCFMT_LEFT, 100, L"Time Stamp");
PhAddListViewColumn(lvHandle, 5, 5, 5, LVCFMT_LEFT, 60, L"Checksum");
PhSetExtendedListView(lvHandle);
ExtendedListView_SetCompareFunction(lvHandle, 0, EtpNumberCompareFunction);
ExtendedListView_SetCompareFunction(lvHandle, 2, EtpBaseAddressCompareFunction);
ExtendedListView_SetCompareFunction(lvHandle, 3, EtpSizeCompareFunction);
ExtendedListView_SetCompareFunction(lvHandle, 4, EtpTimeStampCompareFunction);
ExtendedListView_SetCompareFunction(lvHandle, 5, EtpCheckSumCompareFunction);
if (!EtpRefreshUnloadedDlls(hwndDlg, context))
{
EndDialog(hwndDlg, IDCANCEL);
return FALSE;
}
}
break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDCANCEL:
case IDOK:
EndDialog(hwndDlg, IDOK);
break;
case IDC_REFRESH:
EtpRefreshUnloadedDlls(hwndDlg, context);
break;
}
}
break;
case WM_NOTIFY:
{
PhHandleListViewNotifyForCopy(lParam, context->ListViewHandle);
}
break;
}
return FALSE;
}

View File

@@ -0,0 +1,48 @@
/*
* Process Hacker Extended Tools -
* utility functions
*
* Copyright (C) 2011 wj32
*
* This file is part of Process Hacker.
*
* Process Hacker is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Process Hacker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
*/
#include "exttools.h"
VOID EtFormatRate(
_In_ ULONG64 ValuePerPeriod,
_Inout_ PPH_STRING *Buffer,
_Out_opt_ PPH_STRINGREF String
)
{
ULONG64 number;
number = ValuePerPeriod;
number *= 1000;
number /= PhGetIntegerSetting(L"UpdateInterval");
if (number != 0)
{
PH_FORMAT format[2];
PhInitFormatSize(&format[0], number);
PhInitFormatS(&format[1], L"/s");
PhMoveReference(Buffer, PhFormat(format, 2, 0));
if (String)
*String = (*Buffer)->sr;
}
}

View File

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

View File

@@ -0,0 +1,17 @@
1.4
* Fixed incorrect drive letters
* Fixed drive letter and panel clipping issue
1.3
* Fixed Vista support
* Adapter information is now updated regardless of whether System Information is open
* Added disk statistics support
1.2
* Added network adapter details window
1.1
* Added native network driver statistics support
1.0
* Initial release

View File

@@ -0,0 +1,402 @@
// 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)
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,4,0,0
PRODUCTVERSION 1,4,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", "dmex"
VALUE "FileDescription", "Hardware Devices plugin for Process Hacker"
VALUE "FileVersion", "1.4"
VALUE "InternalName", "HardwareDevices"
VALUE "LegalCopyright", "Licensed under the GNU GPL, v3."
VALUE "OriginalFilename", "HardwareDevices.dll"
VALUE "ProductName", "Hardware Devices plugin for Process Hacker"
VALUE "ProductVersion", "1.4"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0xc09, 1200
END
END
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\0"
END
3 TEXTINCLUDE
BEGIN
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_NETADAPTER_OPTIONS DIALOGEX 0, 0, 265, 177
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Network Adapters"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
CONTROL "",IDC_NETADAPTERS_LISTVIEW,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,7,7,251,146
CONTROL "Show hidden adapters",IDC_SHOW_HIDDEN_ADAPTERS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,159,87,10
END
IDD_NETADAPTER_DIALOG DIALOGEX 0, 0, 269, 130
STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
EXSTYLE WS_EX_APPWINDOW
CAPTION "Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "",IDC_GRAPH_LAYOUT,0,21,269,53,NOT WS_VISIBLE | WS_BORDER
LTEXT "Static",IDC_ADAPTERNAME,0,0,269,21
LTEXT "Panel layout",IDC_LAYOUT,0,91,268,36,NOT WS_VISIBLE
END
IDD_NETADAPTER_PANEL DIALOGEX 0, 0, 254, 50
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "Link speed",IDC_STATIC,7,11,35,8
RTEXT "Static",IDC_LINK_SPEED,50,11,54,8,SS_ENDELLIPSIS
GROUPBOX "Adapter",IDC_STATIC,0,0,111,34
LTEXT "Link state",IDC_STATIC,7,23,32,8
RTEXT "Static",IDC_LINK_STATE,50,23,54,8,SS_ENDELLIPSIS
GROUPBOX "Statistics",IDC_STATIC,116,0,136,45
LTEXT "Bytes sent",IDC_STATIC,125,11,36,8
LTEXT "Bytes received",IDC_STATIC,125,22,50,8
RTEXT "Static",IDC_STAT_BSENT,182,11,62,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_STAT_BRECEIVED,182,22,62,8,SS_ENDELLIPSIS
LTEXT "Bytes total",IDC_STATIC,125,33,37,8
RTEXT "Static",IDC_STAT_BTOTAL,182,33,62,8,SS_ENDELLIPSIS
PUSHBUTTON "Details",IDC_DETAILS,0,35,50,14
END
IDD_NETADAPTER_DETAILS DIALOGEX 0, 0, 309, 265
STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
CAPTION "Adapter Details"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
PUSHBUTTON "Close",IDOK,253,244,50,14
CONTROL "",IDC_DETAILS_LIST,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,295,235
END
IDD_DISKDRIVE_OPTIONS DIALOGEX 0, 0, 265, 177
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Disk Drives"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
CONTROL "",IDC_DISKDRIVE_LISTVIEW,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,7,7,251,163
END
IDD_DISKDRIVE_DIALOG DIALOGEX 0, 0, 315, 135
STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
EXSTYLE WS_EX_APPWINDOW
CAPTION "Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "",IDC_GRAPH_LAYOUT,0,21,314,60,NOT WS_VISIBLE | WS_BORDER
LTEXT "Disk",IDC_DISKMOUNTPATH,0,0,105,21
LTEXT "Panel layout",IDC_LAYOUT,0,98,314,36,NOT WS_VISIBLE
RTEXT "Disk name",IDC_DISKNAME,107,4,207,16,SS_WORDELLIPSIS
END
IDD_DISKDRIVE_PANEL DIALOGEX 0, 0, 330, 50
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
GROUPBOX "Statistics",IDC_STATIC,139,0,136,44
LTEXT "Bytes read",IDC_STATIC,148,11,38,8
LTEXT "Bytes written",IDC_STATIC,148,22,45,8
RTEXT "Static",IDC_STAT_BREAD,205,11,62,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_STAT_BWRITE,205,22,62,8,SS_ENDELLIPSIS
LTEXT "Bytes total",IDC_STATIC,148,33,37,8
RTEXT "Static",IDC_STAT_BTOTAL,205,33,62,8,SS_ENDELLIPSIS
LTEXT "Active time",IDC_STATIC,8,11,53,8,SS_ENDELLIPSIS
LTEXT "Response time",IDC_STATIC,8,22,64,8,SS_ENDELLIPSIS
LTEXT "Queue length",IDC_STATIC,8,33,57,8,SS_ENDELLIPSIS
GROUPBOX "Disk",IDC_STATIC,0,0,135,44
PUSHBUTTON "Details",IDC_DETAILS,278,30,50,14,NOT WS_VISIBLE
RTEXT "Static",IDC_STAT_ACTIVE,65,11,62,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_STAT_RESPONSETIME,65,22,62,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_STAT_QUEUELENGTH,65,33,62,8,SS_ENDELLIPSIS
END
IDD_DISKDRIVE_DETAILS_SMART DIALOGEX 0, 0, 309, 265
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "SMART"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
CONTROL "",IDC_DETAILS_LIST,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,295,182
EDITTEXT IDC_EDIT1,7,200,295,58,ES_MULTILINE | ES_READONLY | WS_VSCROLL
LTEXT "Description:",IDC_DESCRIPTION,7,190,39,8
END
IDD_DISKDRIVE_DETAILS_FILESYSTEM DIALOGEX 0, 0, 309, 265
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Volume(s)"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
CONTROL "",IDC_DETAILS_LIST,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,295,182
EDITTEXT IDC_EDIT1,7,200,295,58,ES_MULTILINE | ES_READONLY | WS_VSCROLL
LTEXT "Description:",IDC_DESCRIPTION,7,190,39,8
END
IDD_DISKDRIVE_DETAILS_GENERAL DIALOGEX 0, 0, 275, 262
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
END
IDD_GPU_DIALOG DIALOGEX 0, 0, 315, 191
STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
EXSTYLE WS_EX_APPWINDOW
CAPTION "Dialog"
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_LAYOUT,0,145,315,46,NOT WS_VISIBLE
LTEXT "Graph layout",IDC_GRAPH_LAYOUT,0,22,315,120,NOT WS_VISIBLE
LTEXT "GPU:",IDC_GPU_L,73,0,17,8
LTEXT "Memory:",IDC_MEMORY_L,73,5,29,8
LTEXT "Memory Controller:",IDC_SHARED_L,74,11,62,8
LTEXT "Bus Interface:",IDC_BUS_L,74,18,47,8
END
IDD_GPU_PANEL DIALOGEX 0, 0, 372, 47
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
GROUPBOX "Clocks",IDC_STATIC,0,0,118,43
LTEXT "Core",IDC_STATIC,8,10,16,8
LTEXT "Memory",IDC_STATIC,8,21,26,8
RTEXT "Static",IDC_CLOCK_CORE,55,10,54,8,SS_ENDELLIPSIS
RTEXT "Static",IDC_CLOCK_MEMORY,55,21,54,8,SS_ENDELLIPSIS
GROUPBOX "Fan",IDC_STATIC,122,0,124,22
LTEXT "Speed",IDC_STATIC,130,10,21,8
RTEXT "Static",IDC_FAN_PERCENT,158,10,78,8,SS_ENDELLIPSIS
LTEXT "Shader",IDC_STATIC,8,32,24,8
RTEXT "Static",IDC_CLOCK_SHADER,55,32,54,8,SS_ENDELLIPSIS
GROUPBOX "Temperature",IDC_STATIC,122,22,124,21
LTEXT "Core",IDC_STATIC,130,32,16,8
RTEXT "Static",IDC_TEMP_VALUE,158,32,78,8,SS_ENDELLIPSIS
GROUPBOX "Voltage",IDC_STATIC,248,0,124,22
LTEXT "Core",IDC_STATIC,256,10,16,8
RTEXT "Static",IDC_VOLTAGE,284,10,78,8,SS_ENDELLIPSIS
PUSHBUTTON "Details",IDC_DETAILS,249,27,50,14,NOT WS_VISIBLE
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_NETADAPTER_OPTIONS, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 258
TOPMARGIN, 7
BOTTOMMARGIN, 170
END
IDD_NETADAPTER_DIALOG, DIALOG
BEGIN
END
IDD_NETADAPTER_PANEL, DIALOG
BEGIN
RIGHTMARGIN, 253
TOPMARGIN, 1
END
IDD_NETADAPTER_DETAILS, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 302
TOPMARGIN, 7
BOTTOMMARGIN, 258
END
IDD_DISKDRIVE_OPTIONS, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 258
TOPMARGIN, 7
BOTTOMMARGIN, 170
END
IDD_DISKDRIVE_DIALOG, DIALOG
BEGIN
RIGHTMARGIN, 314
BOTTOMMARGIN, 134
END
IDD_DISKDRIVE_PANEL, DIALOG
BEGIN
RIGHTMARGIN, 329
BOTTOMMARGIN, 49
END
IDD_DISKDRIVE_DETAILS_SMART, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 302
TOPMARGIN, 7
BOTTOMMARGIN, 258
END
IDD_DISKDRIVE_DETAILS_FILESYSTEM, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 302
TOPMARGIN, 7
BOTTOMMARGIN, 258
END
IDD_DISKDRIVE_DETAILS_GENERAL, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 268
TOPMARGIN, 7
BOTTOMMARGIN, 255
END
IDD_GPU_DIALOG, DIALOG
BEGIN
END
IDD_GPU_PANEL, DIALOG
BEGIN
END
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// AFX_DIALOG_LAYOUT
//
IDD_NETADAPTER_PANEL AFX_DIALOG_LAYOUT
BEGIN
0
END
IDD_NETADAPTER_DETAILS AFX_DIALOG_LAYOUT
BEGIN
0
END
IDD_NETADAPTER_OPTIONS AFX_DIALOG_LAYOUT
BEGIN
0
END
IDD_NETADAPTER_DIALOG AFX_DIALOG_LAYOUT
BEGIN
0
END
IDD_DISKDRIVE_OPTIONS AFX_DIALOG_LAYOUT
BEGIN
0
END
IDD_DISKDRIVE_DIALOG AFX_DIALOG_LAYOUT
BEGIN
0
END
IDD_DISKDRIVE_PANEL AFX_DIALOG_LAYOUT
BEGIN
0
END
IDD_DISKDRIVE_DETAILS_SMART AFX_DIALOG_LAYOUT
BEGIN
0
END
IDD_DISKDRIVE_DETAILS_FILESYSTEM AFX_DIALOG_LAYOUT
BEGIN
0
END
IDD_DISKDRIVE_DETAILS_GENERAL AFX_DIALOG_LAYOUT
BEGIN
0
END
IDD_GPU_DIALOG AFX_DIALOG_LAYOUT
BEGIN
0
END
IDD_GPU_PANEL AFX_DIALOG_LAYOUT
BEGIN
0
END
#endif // English (Australia) resources
/////////////////////////////////////////////////////////////////////////////

View File

@@ -0,0 +1,120 @@
<?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>{5F0D72C4-8319-4B61-9E13-6084B680EB90}</ProjectGuid>
<RootNamespace>HardwareDevices</RootNamespace>
<Keyword>Win32Proj</Keyword>
<ProjectName>HardwareDevices</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>iphlpapi.lib;setupapi.lib;uxtheme.lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>iphlpapi.dll;setupapi.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Link>
<AdditionalDependencies>iphlpapi.lib;setupapi.lib;uxtheme.lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>iphlpapi.dll;setupapi.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Link>
<AdditionalDependencies>iphlpapi.lib;setupapi.lib;uxtheme.lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>iphlpapi.dll;setupapi.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Link>
<AdditionalDependencies>iphlpapi.lib;setupapi.lib;uxtheme.lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>iphlpapi.dll;setupapi.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="adapter.c" />
<ClCompile Include="diskdetails.c" />
<ClCompile Include="disknotify.c" />
<ClCompile Include="gpugraph.c" />
<ClCompile Include="netdetails.c" />
<ClCompile Include="diskgraph.c" />
<ClCompile Include="diskoptions.c" />
<ClCompile Include="disk.c" />
<ClCompile Include="netgraph.c" />
<ClCompile Include="main.c" />
<ClCompile Include="ndis.c" />
<ClCompile Include="netoptions.c" />
<ClCompile Include="nvidia.c" />
<ClCompile Include="storage.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="devices.h" />
<ClInclude Include="nvapi\nvapi.h" />
<ClInclude Include="nvapi\nvapi_lite_common.h" />
<ClInclude Include="nvidia.h" />
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="HardwareDevices.rc" />
</ItemGroup>
<ItemGroup>
<None Include="CHANGELOG.txt" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>

View File

@@ -0,0 +1,95 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Header Files">
<UniqueIdentifier>{47359E56-A930-4DDC-A651-E2E99D48E957}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files">
<UniqueIdentifier>{4965CB7A-371A-4B22-AC3F-E70DC77C5D24}</UniqueIdentifier>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{00475F04-2369-42D8-9A52-9DB77E37AE62}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Disk">
<UniqueIdentifier>{1ccecf79-cd82-4ae5-b891-64a0a2d18e8e}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Network">
<UniqueIdentifier>{c7c48d78-64cd-4559-87c1-74e2141dcd2e}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\Graphics">
<UniqueIdentifier>{17660e06-b187-4eca-81d7-f6d3548f3c2f}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\Graphics">
<UniqueIdentifier>{987f6036-c8df-4352-abc3-060d5a1bc7e4}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="devices.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="nvapi\nvapi.h">
<Filter>Header Files\Graphics</Filter>
</ClInclude>
<ClInclude Include="nvapi\nvapi_lite_common.h">
<Filter>Header Files\Graphics</Filter>
</ClInclude>
<ClInclude Include="nvidia.h">
<Filter>Header Files\Graphics</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="main.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="diskoptions.c">
<Filter>Source Files\Disk</Filter>
</ClCompile>
<ClCompile Include="ndis.c">
<Filter>Source Files\Network</Filter>
</ClCompile>
<ClCompile Include="storage.c">
<Filter>Source Files\Disk</Filter>
</ClCompile>
<ClCompile Include="adapter.c">
<Filter>Source Files\Network</Filter>
</ClCompile>
<ClCompile Include="netgraph.c">
<Filter>Source Files\Network</Filter>
</ClCompile>
<ClCompile Include="netoptions.c">
<Filter>Source Files\Network</Filter>
</ClCompile>
<ClCompile Include="netdetails.c">
<Filter>Source Files\Network</Filter>
</ClCompile>
<ClCompile Include="disk.c">
<Filter>Source Files\Disk</Filter>
</ClCompile>
<ClCompile Include="diskgraph.c">
<Filter>Source Files\Disk</Filter>
</ClCompile>
<ClCompile Include="diskdetails.c">
<Filter>Source Files\Disk</Filter>
</ClCompile>
<ClCompile Include="disknotify.c">
<Filter>Source Files\Disk</Filter>
</ClCompile>
<ClCompile Include="gpugraph.c">
<Filter>Source Files\Graphics</Filter>
</ClCompile>
<ClCompile Include="nvidia.c">
<Filter>Source Files\Graphics</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="CHANGELOG.txt" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="HardwareDevices.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

View File

@@ -0,0 +1,292 @@
/*
* Process Hacker Plugins -
* Hardware Devices Plugin
*
* Copyright (C) 2015-2016 dmex
* Copyright (C) 2016 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 "devices.h"
VOID AdapterEntryDeleteProcedure(
_In_ PVOID Object,
_In_ ULONG Flags
)
{
PDV_NETADAPTER_ENTRY entry = Object;
PhAcquireQueuedLockExclusive(&NetworkAdaptersListLock);
PhRemoveItemList(NetworkAdaptersList, PhFindItemList(NetworkAdaptersList, entry));
PhReleaseQueuedLockExclusive(&NetworkAdaptersListLock);
DeleteNetAdapterId(&entry->Id);
PhClearReference(&entry->AdapterName);
PhDeleteCircularBuffer_ULONG64(&entry->InboundBuffer);
PhDeleteCircularBuffer_ULONG64(&entry->OutboundBuffer);
}
VOID NetAdaptersInitialize(
VOID
)
{
NetworkAdaptersList = PhCreateList(1);
NetAdapterEntryType = PhCreateObjectType(L"NetAdapterEntry", 0, AdapterEntryDeleteProcedure);
}
VOID NetAdaptersUpdate(
VOID
)
{
static ULONG runCount = 0; // MUST keep in sync with runCount in process provider
PhAcquireQueuedLockShared(&NetworkAdaptersListLock);
for (ULONG i = 0; i < NetworkAdaptersList->Count; i++)
{
HANDLE deviceHandle = NULL;
PDV_NETADAPTER_ENTRY entry;
ULONG64 networkInOctets = 0;
ULONG64 networkOutOctets = 0;
ULONG64 networkRcvSpeed = 0;
ULONG64 networkXmitSpeed = 0;
NDIS_MEDIA_CONNECT_STATE mediaState = MediaConnectStateUnknown;
entry = PhReferenceObjectSafe(NetworkAdaptersList->Items[i]);
if (!entry)
continue;
if (PhGetIntegerSetting(SETTING_NAME_ENABLE_NDIS))
{
if (NT_SUCCESS(NetworkAdapterCreateHandle(&deviceHandle, entry->Id.InterfaceGuid)))
{
if (!entry->CheckedDeviceSupport)
{
// Check the network adapter supports the OIDs we're going to be using.
if (NetworkAdapterQuerySupported(deviceHandle))
{
entry->DeviceSupported = TRUE;
}
entry->CheckedDeviceSupport = TRUE;
}
if (!entry->DeviceSupported)
{
// Device is faulty. Close the handle so we can fallback to GetIfEntry.
NtClose(deviceHandle);
deviceHandle = NULL;
}
}
}
if (deviceHandle)
{
NDIS_STATISTICS_INFO interfaceStats;
NDIS_LINK_STATE interfaceState;
memset(&interfaceStats, 0, sizeof(NDIS_STATISTICS_INFO));
NetworkAdapterQueryStatistics(deviceHandle, &interfaceStats);
if (NT_SUCCESS(NetworkAdapterQueryLinkState(deviceHandle, &interfaceState)))
{
mediaState = interfaceState.MediaConnectState;
}
if (!(interfaceStats.SupportedStatistics & NDIS_STATISTICS_FLAGS_VALID_BYTES_RCV))
networkInOctets = NetworkAdapterQueryValue(deviceHandle, OID_GEN_BYTES_RCV);
else
networkInOctets = interfaceStats.ifHCInOctets;
if (!(interfaceStats.SupportedStatistics & NDIS_STATISTICS_FLAGS_VALID_BYTES_XMIT))
networkOutOctets = NetworkAdapterQueryValue(deviceHandle, OID_GEN_BYTES_XMIT);
else
networkOutOctets = interfaceStats.ifHCOutOctets;
networkRcvSpeed = networkInOctets - entry->LastInboundValue;
networkXmitSpeed = networkOutOctets - entry->LastOutboundValue;
// HACK: Pull the Adapter name from the current query.
if (!entry->AdapterName)
{
entry->AdapterName = NetworkAdapterQueryName(deviceHandle, entry->Id.InterfaceGuid);
}
entry->DevicePresent = TRUE;
NtClose(deviceHandle);
}
else if (WindowsVersion >= WINDOWS_VISTA && GetIfEntry2)
{
MIB_IF_ROW2 interfaceRow;
if (QueryInterfaceRowVista(&entry->Id, &interfaceRow))
{
networkInOctets = interfaceRow.InOctets;
networkOutOctets = interfaceRow.OutOctets;
mediaState = interfaceRow.MediaConnectState;
networkRcvSpeed = networkInOctets - entry->LastInboundValue;
networkXmitSpeed = networkOutOctets - entry->LastOutboundValue;
// HACK: Pull the Adapter name from the current query.
if (!entry->AdapterName && PhCountStringZ(interfaceRow.Description) > 0)
{
entry->AdapterName = PhCreateString(interfaceRow.Description);
}
entry->DevicePresent = TRUE;
}
else
{
entry->DevicePresent = FALSE;
}
}
else
{
MIB_IFROW interfaceRow;
if (QueryInterfaceRowXP(&entry->Id, &interfaceRow))
{
networkInOctets = interfaceRow.dwInOctets;
networkOutOctets = interfaceRow.dwOutOctets;
mediaState = interfaceRow.dwOperStatus == IF_OPER_STATUS_OPERATIONAL ? MediaConnectStateConnected : MediaConnectStateDisconnected;
networkRcvSpeed = networkInOctets - entry->LastInboundValue;
networkXmitSpeed = networkOutOctets - entry->LastOutboundValue;
// HACK: Pull the Adapter name from the current query.
if (!entry->AdapterName && strlen(interfaceRow.bDescr) > 0)
{
entry->AdapterName = PhConvertMultiByteToUtf16(interfaceRow.bDescr);
}
entry->DevicePresent = TRUE;
}
else
{
entry->DevicePresent = FALSE;
}
}
if (mediaState == MediaConnectStateUnknown)
{
// We don't want incorrect data when the adapter is disabled.
networkRcvSpeed = 0;
networkXmitSpeed = 0;
}
if (!entry->HaveFirstSample)
{
// The first sample must be zero.
networkRcvSpeed = 0;
networkXmitSpeed = 0;
entry->HaveFirstSample = TRUE;
}
if (runCount != 0)
{
PhAddItemCircularBuffer_ULONG64(&entry->InboundBuffer, networkRcvSpeed);
PhAddItemCircularBuffer_ULONG64(&entry->OutboundBuffer, networkXmitSpeed);
}
//context->LinkSpeed = networkLinkSpeed;
entry->InboundValue = networkRcvSpeed;
entry->OutboundValue = networkXmitSpeed;
entry->LastInboundValue = networkInOctets;
entry->LastOutboundValue = networkOutOctets;
PhDereferenceObjectDeferDelete(entry);
}
PhReleaseQueuedLockShared(&NetworkAdaptersListLock);
runCount++;
}
VOID InitializeNetAdapterId(
_Out_ PDV_NETADAPTER_ID Id,
_In_ NET_IFINDEX InterfaceIndex,
_In_ IF_LUID InterfaceLuid,
_In_ PPH_STRING InterfaceGuid
)
{
Id->InterfaceIndex = InterfaceIndex;
Id->InterfaceLuid = InterfaceLuid;
PhSetReference(&Id->InterfaceGuid, InterfaceGuid);
}
VOID CopyNetAdapterId(
_Out_ PDV_NETADAPTER_ID Destination,
_In_ PDV_NETADAPTER_ID Source
)
{
InitializeNetAdapterId(
Destination,
Source->InterfaceIndex,
Source->InterfaceLuid,
Source->InterfaceGuid
);
}
VOID DeleteNetAdapterId(
_Inout_ PDV_NETADAPTER_ID Id
)
{
PhClearReference(&Id->InterfaceGuid);
}
BOOLEAN EquivalentNetAdapterId(
_In_ PDV_NETADAPTER_ID Id1,
_In_ PDV_NETADAPTER_ID Id2
)
{
if (WindowsVersion >= WINDOWS_VISTA)
{
if (Id1->InterfaceLuid.Value == Id2->InterfaceLuid.Value)
return TRUE;
}
else
{
if (Id1->InterfaceIndex == Id2->InterfaceIndex)
return TRUE;
}
return FALSE;
}
PDV_NETADAPTER_ENTRY CreateNetAdapterEntry(
_In_ PDV_NETADAPTER_ID Id
)
{
PDV_NETADAPTER_ENTRY entry;
entry = PhCreateObject(sizeof(DV_NETADAPTER_ENTRY), NetAdapterEntryType);
memset(entry, 0, sizeof(DV_NETADAPTER_ENTRY));
CopyNetAdapterId(&entry->Id, Id);
PhInitializeCircularBuffer_ULONG64(&entry->InboundBuffer, PhGetIntegerSetting(L"SampleCount"));
PhInitializeCircularBuffer_ULONG64(&entry->OutboundBuffer, PhGetIntegerSetting(L"SampleCount"));
PhAcquireQueuedLockExclusive(&NetworkAdaptersListLock);
PhAddItemList(NetworkAdaptersList, entry);
PhReleaseQueuedLockExclusive(&NetworkAdaptersListLock);
return entry;
}

View File

@@ -0,0 +1,773 @@
/*
* Process Hacker Plugins -
* Hardware Devices Plugin
*
* Copyright (C) 2015-2016 dmex
* Copyright (C) 2016 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/>.
*/
#ifndef _DEVICES_H_
#define _DEVICES_H_
#define PLUGIN_NAME L"ProcessHacker.HardwareDevices"
#define SETTING_NAME_ENABLE_NDIS (PLUGIN_NAME L".EnableNDIS")
#define SETTING_NAME_INTERFACE_LIST (PLUGIN_NAME L".NetworkList")
#define SETTING_NAME_DISK_LIST (PLUGIN_NAME L".DiskList")
#ifdef _NV_GPU_BUILD
#define SETTING_NAME_ENABLE_GPU (PLUGIN_NAME L".EnableGpu")
#define SETTING_NAME_ENABLE_FAHRENHEIT (PLUGIN_NAME L".ShowFahrenheit")
#endif
#define CINTERFACE
#define COBJMACROS
#include <phdk.h>
#include <phappresource.h>
#include <windowsx.h>
#include <uxtheme.h>
#include <ws2def.h>
#include <ws2ipdef.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <nldef.h>
#include <netioapi.h>
//#include <WinSock2.h>
#include "resource.h"
#define WM_SHOWDIALOG (WM_APP + 1)
#define UPDATE_MSG (WM_APP + 2)
extern PPH_PLUGIN PluginInstance;
extern PPH_OBJECT_TYPE NetAdapterEntryType;
extern PPH_LIST NetworkAdaptersList;
extern PH_QUEUED_LOCK NetworkAdaptersListLock;
extern PPH_OBJECT_TYPE DiskDriveEntryType;
extern PPH_LIST DiskDrivesList;
extern PH_QUEUED_LOCK DiskDrivesListLock;
// main.c
PPH_STRING TrimString(
_In_ PPH_STRING String
);
INT AddListViewGroup(
_In_ HWND ListViewHandle,
_In_ INT Index,
_In_ PWSTR Text
);
INT AddListViewItemGroupId(
_In_ HWND ListViewHandle,
_In_ INT GroupId,
_In_ INT Index,
_In_ PWSTR Text,
_In_opt_ PVOID Param
);
ULONG64 RegQueryUlong64(
_In_ HANDLE KeyHandle,
_In_ PWSTR ValueName
);
VOID ShowDeviceMenu(
_In_ HWND ParentWindow,
_In_ PPH_STRING DeviceInstance
);
// adapter.c
typedef struct _DV_NETADAPTER_ID
{
NET_IFINDEX InterfaceIndex;
IF_LUID InterfaceLuid;
PPH_STRING InterfaceGuid;
} DV_NETADAPTER_ID, *PDV_NETADAPTER_ID;
typedef struct _DV_NETADAPTER_ENTRY
{
DV_NETADAPTER_ID Id;
PPH_STRING AdapterName;
union
{
BOOLEAN BitField;
struct
{
BOOLEAN UserReference : 1;
BOOLEAN HaveFirstSample : 1;
BOOLEAN CheckedDeviceSupport : 1;
BOOLEAN DeviceSupported : 1;
BOOLEAN DevicePresent : 1;
BOOLEAN Spare : 3;
};
};
//ULONG64 LinkSpeed;
ULONG64 InboundValue;
ULONG64 OutboundValue;
ULONG64 LastInboundValue;
ULONG64 LastOutboundValue;
PH_CIRCULAR_BUFFER_ULONG64 InboundBuffer;
PH_CIRCULAR_BUFFER_ULONG64 OutboundBuffer;
} DV_NETADAPTER_ENTRY, *PDV_NETADAPTER_ENTRY;
typedef struct _DV_NETADAPTER_SYSINFO_CONTEXT
{
PDV_NETADAPTER_ENTRY AdapterEntry;
PPH_STRING SectionName;
HWND WindowHandle;
HWND PanelWindowHandle;
HWND GraphHandle;
PPH_SYSINFO_SECTION SysinfoSection;
PH_GRAPH_STATE GraphState;
PH_LAYOUT_MANAGER LayoutManager;
} DV_NETADAPTER_SYSINFO_CONTEXT, *PDV_NETADAPTER_SYSINFO_CONTEXT;
typedef struct _DV_NETADAPTER_DETAILS_CONTEXT
{
PPH_STRING AdapterName;
DV_NETADAPTER_ID AdapterId;
union
{
BOOLEAN BitField;
struct
{
BOOLEAN HaveFirstSample : 1;
BOOLEAN CheckedDeviceSupport : 1;
BOOLEAN DeviceSupported : 1;
BOOLEAN Spare : 5;
};
};
HWND WindowHandle;
HWND ParentHandle;
HWND ListViewHandle;
HANDLE NotifyHandle;
PH_LAYOUT_MANAGER LayoutManager;
PH_CALLBACK_REGISTRATION ProcessesUpdatedRegistration;
ULONG64 LastDetailsInboundValue;
ULONG64 LastDetailsIOutboundValue;
} DV_NETADAPTER_DETAILS_CONTEXT, *PDV_NETADAPTER_DETAILS_CONTEXT;
typedef struct _DV_NETADAPTER_CONTEXT
{
HWND ListViewHandle;
//HIMAGELIST ImageList;
BOOLEAN OptionsChanged;
BOOLEAN EnumeratingAdapters;
BOOLEAN UseAlternateMethod;
} DV_NETADAPTER_CONTEXT, *PDV_NETADAPTER_CONTEXT;
VOID NetAdaptersLoadList(
VOID
);
VOID ShowOptionsDialog(
_In_ HWND ParentHandle
);
// adapter.c
VOID NetAdaptersInitialize(
VOID
);
VOID NetAdaptersUpdate(
VOID
);
VOID InitializeNetAdapterId(
_Out_ PDV_NETADAPTER_ID Id,
_In_ NET_IFINDEX InterfaceIndex,
_In_ IF_LUID InterfaceLuid,
_In_ PPH_STRING InterfaceGuid
);
VOID CopyNetAdapterId(
_Out_ PDV_NETADAPTER_ID Destination,
_In_ PDV_NETADAPTER_ID Source
);
VOID DeleteNetAdapterId(
_Inout_ PDV_NETADAPTER_ID Id
);
BOOLEAN EquivalentNetAdapterId(
_In_ PDV_NETADAPTER_ID Id1,
_In_ PDV_NETADAPTER_ID Id2
);
PDV_NETADAPTER_ENTRY CreateNetAdapterEntry(
_In_ PDV_NETADAPTER_ID Id
);
// dialog.c
typedef enum _NETADAPTER_DETAILS_CATEGORY
{
NETADAPTER_DETAILS_CATEGORY_ADAPTER,
NETADAPTER_DETAILS_CATEGORY_UNICAST,
NETADAPTER_DETAILS_CATEGORY_BROADCAST,
NETADAPTER_DETAILS_CATEGORY_MULTICAST,
NETADAPTER_DETAILS_CATEGORY_ERRORS
} NETADAPTER_DETAILS_CATEGORY;
typedef enum _NETADAPTER_DETAILS_INDEX
{
NETADAPTER_DETAILS_INDEX_STATE,
//NETADAPTER_DETAILS_INDEX_CONNECTIVITY,
NETADAPTER_DETAILS_INDEX_IPADDRESS,
NETADAPTER_DETAILS_INDEX_SUBNET,
NETADAPTER_DETAILS_INDEX_GATEWAY,
NETADAPTER_DETAILS_INDEX_DNS,
NETADAPTER_DETAILS_INDEX_DOMAIN,
NETADAPTER_DETAILS_INDEX_LINKSPEED,
NETADAPTER_DETAILS_INDEX_SENT,
NETADAPTER_DETAILS_INDEX_RECEIVED,
NETADAPTER_DETAILS_INDEX_TOTAL,
NETADAPTER_DETAILS_INDEX_SENDING,
NETADAPTER_DETAILS_INDEX_RECEIVING,
NETADAPTER_DETAILS_INDEX_UTILIZATION,
NETADAPTER_DETAILS_INDEX_UNICAST_SENTPKTS,
NETADAPTER_DETAILS_INDEX_UNICAST_RECVPKTS,
NETADAPTER_DETAILS_INDEX_UNICAST_TOTALPKTS,
NETADAPTER_DETAILS_INDEX_UNICAST_SENT,
NETADAPTER_DETAILS_INDEX_UNICAST_RECEIVED,
NETADAPTER_DETAILS_INDEX_UNICAST_TOTAL,
//NETADAPTER_DETAILS_INDEX_UNICAST_SENDING,
//NETADAPTER_DETAILS_INDEX_UNICAST_RECEIVING,
//NETADAPTER_DETAILS_INDEX_UNICAST_UTILIZATION,
NETADAPTER_DETAILS_INDEX_BROADCAST_SENTPKTS,
NETADAPTER_DETAILS_INDEX_BROADCAST_RECVPKTS,
NETADAPTER_DETAILS_INDEX_BROADCAST_TOTALPKTS,
NETADAPTER_DETAILS_INDEX_BROADCAST_SENT,
NETADAPTER_DETAILS_INDEX_BROADCAST_RECEIVED,
NETADAPTER_DETAILS_INDEX_BROADCAST_TOTAL,
NETADAPTER_DETAILS_INDEX_MULTICAST_SENTPKTS,
NETADAPTER_DETAILS_INDEX_MULTICAST_RECVPKTS,
NETADAPTER_DETAILS_INDEX_MULTICAST_TOTALPKTS,
NETADAPTER_DETAILS_INDEX_MULTICAST_SENT,
NETADAPTER_DETAILS_INDEX_MULTICAST_RECEIVED,
NETADAPTER_DETAILS_INDEX_MULTICAST_TOTAL,
NETADAPTER_DETAILS_INDEX_ERRORS_SENTPKTS,
NETADAPTER_DETAILS_INDEX_ERRORS_RECVPKTS,
NETADAPTER_DETAILS_INDEX_ERRORS_TOTALPKTS,
NETADAPTER_DETAILS_INDEX_ERRORS_SENT,
NETADAPTER_DETAILS_INDEX_ERRORS_RECEIVED,
NETADAPTER_DETAILS_INDEX_ERRORS_TOTAL
} NETADAPTER_DETAILS_INDEX;
VOID ShowNetAdapterDetailsDialog(
_In_ PDV_NETADAPTER_SYSINFO_CONTEXT Context
);
// ndis.c
#define BITS_IN_ONE_BYTE 8
#define NDIS_UNIT_OF_MEASUREMENT 100
// dmex: rev
typedef ULONG (WINAPI* _GetInterfaceDescriptionFromGuid)(
_Inout_ PGUID InterfaceGuid,
_Out_opt_ PWSTR InterfaceDescription,
_Inout_ PSIZE_T LengthAddress,
PVOID Unknown1,
PVOID Unknown2
);
NTSTATUS NetworkAdapterCreateHandle(
_Out_ PHANDLE DeviceHandle,
_In_ PPH_STRING InterfaceGuid
);
BOOLEAN NetworkAdapterQuerySupported(
_In_ HANDLE DeviceHandle
);
BOOLEAN NetworkAdapterQueryNdisVersion(
_In_ HANDLE DeviceHandle,
_Out_opt_ PUINT MajorVersion,
_Out_opt_ PUINT MinorVersion
);
PPH_STRING NetworkAdapterQueryName(
_In_ HANDLE DeviceHandle,
_In_ PPH_STRING InterfaceGuid
);
NTSTATUS NetworkAdapterQueryStatistics(
_In_ HANDLE DeviceHandle,
_Out_ PNDIS_STATISTICS_INFO Info
);
NTSTATUS NetworkAdapterQueryLinkState(
_In_ HANDLE DeviceHandle,
_Out_ PNDIS_LINK_STATE State
);
BOOLEAN NetworkAdapterQueryMediaType(
_In_ HANDLE DeviceHandle,
_Out_ PNDIS_PHYSICAL_MEDIUM Medium
);
NTSTATUS NetworkAdapterQueryLinkSpeed(
_In_ HANDLE DeviceHandle,
_Out_ PULONG64 LinkSpeed
);
ULONG64 NetworkAdapterQueryValue(
_In_ HANDLE DeviceHandle,
_In_ NDIS_OID OpCode
);
BOOLEAN QueryInterfaceRowVista(
_In_ PDV_NETADAPTER_ID Id,
_Out_ PMIB_IF_ROW2 InterfaceRow
);
BOOLEAN QueryInterfaceRowXP(
_In_ PDV_NETADAPTER_ID Id,
_Out_ PMIB_IFROW InterfaceRow
);
// netoptions.c
INT_PTR CALLBACK NetworkAdapterOptionsDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
// diskoptions.c
INT_PTR CALLBACK DiskDriveOptionsDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
// disk.c
typedef struct _DV_DISK_ID
{
PPH_STRING DevicePath;
} DV_DISK_ID, *PDV_DISK_ID;
typedef struct _DV_DISK_ENTRY
{
DV_DISK_ID Id;
PPH_STRING DiskName;
PPH_STRING DiskIndexName;
ULONG DiskIndex;
union
{
BOOLEAN BitField;
struct
{
BOOLEAN UserReference : 1;
BOOLEAN HaveFirstSample : 1;
BOOLEAN DevicePresent : 1;
BOOLEAN Spare : 5;
};
};
PH_CIRCULAR_BUFFER_ULONG64 ReadBuffer;
PH_CIRCULAR_BUFFER_ULONG64 WriteBuffer;
PH_UINT64_DELTA BytesReadDelta;
PH_UINT64_DELTA BytesWrittenDelta;
PH_UINT64_DELTA ReadTimeDelta;
PH_UINT64_DELTA WriteTimeDelta;
PH_UINT64_DELTA IdleTimeDelta;
PH_UINT32_DELTA ReadCountDelta;
PH_UINT32_DELTA WriteCountDelta;
PH_UINT64_DELTA QueryTimeDelta;
FLOAT ResponseTime;
FLOAT ActiveTime;
ULONG QueueDepth;
ULONG SplitCount;
} DV_DISK_ENTRY, *PDV_DISK_ENTRY;
typedef struct _DV_DISK_SYSINFO_CONTEXT
{
PDV_DISK_ENTRY DiskEntry;
PPH_STRING SectionName;
HWND WindowHandle;
HWND PanelWindowHandle;
HWND GraphHandle;
PPH_SYSINFO_SECTION SysinfoSection;
PH_GRAPH_STATE GraphState;
PH_LAYOUT_MANAGER LayoutManager;
} DV_DISK_SYSINFO_CONTEXT, *PDV_DISK_SYSINFO_CONTEXT;
typedef struct _DV_DISK_OPTIONS_CONTEXT
{
HWND ListViewHandle;
//HIMAGELIST ImageList;
BOOLEAN OptionsChanged;
BOOLEAN EnumeratingDisks;
} DV_DISK_OPTIONS_CONTEXT, *PDV_DISK_OPTIONS_CONTEXT;
VOID DiskDrivesInitialize(VOID);
VOID DiskDrivesLoadList(VOID);
VOID DiskDrivesUpdate(VOID);
VOID DiskDriveUpdateDeviceInfo(
_In_opt_ HANDLE DeviceHandle,
_In_ PDV_DISK_ENTRY DiskEntry
);
VOID InitializeDiskId(
_Out_ PDV_DISK_ID Id,
_In_ PPH_STRING DevicePath
);
VOID CopyDiskId(
_Out_ PDV_DISK_ID Destination,
_In_ PDV_DISK_ID Source
);
VOID DeleteDiskId(
_Inout_ PDV_DISK_ID Id
);
BOOLEAN EquivalentDiskId(
_In_ PDV_DISK_ID Id1,
_In_ PDV_DISK_ID Id2
);
PDV_DISK_ENTRY CreateDiskEntry(
_In_ PDV_DISK_ID Id
);
// diskdetails.c
VOID ShowDiskDriveDetailsDialog(
_In_ PDV_DISK_SYSINFO_CONTEXT Context
);
// disknotify.c
VOID AddRemoveDeviceChangeCallback(
VOID
);
// storage.c
NTSTATUS DiskDriveCreateHandle(
_Out_ PHANDLE DeviceHandle,
_In_ PPH_STRING DevicePath
);
PPH_STRING DiskDriveQueryDosMountPoints(
_In_ ULONG DeviceNumber
);
BOOLEAN DiskDriveQueryDeviceInformation(
_In_ HANDLE DeviceHandle,
_Out_opt_ PPH_STRING* DiskVendor,
_Out_opt_ PPH_STRING* DiskModel,
_Out_opt_ PPH_STRING* DiskRevision,
_Out_opt_ PPH_STRING* DiskSerial
);
NTSTATUS DiskDriveQueryDeviceTypeAndNumber(
_In_ HANDLE DeviceHandle,
_Out_opt_ PULONG DeviceNumber,
_Out_opt_ DEVICE_TYPE* DeviceType
);
NTSTATUS DiskDriveQueryStatistics(
_In_ HANDLE DeviceHandle,
_Out_ PDISK_PERFORMANCE Info
);
PPH_STRING DiskDriveQueryGeometry(
_In_ HANDLE DeviceHandle
);
BOOLEAN DiskDriveQueryImminentFailure(
_In_ HANDLE DeviceHandle,
_Out_ PPH_LIST* DiskSmartAttributes
);
typedef struct _DISK_HANDLE_ENTRY
{
WCHAR DeviceLetter;
HANDLE DeviceHandle;
} DISK_HANDLE_ENTRY, *PDISK_HANDLE_ENTRY;
PPH_LIST DiskDriveQueryMountPointHandles(
_In_ ULONG DeviceNumber
);
typedef struct _NTFS_FILESYSTEM_STATISTICS
{
FILESYSTEM_STATISTICS FileSystemStatistics;
NTFS_STATISTICS NtfsStatistics;
} NTFS_FILESYSTEM_STATISTICS, *PNTFS_FILESYSTEM_STATISTICS;
typedef struct _FAT_FILESYSTEM_STATISTICS
{
FILESYSTEM_STATISTICS FileSystemStatistics;
NTFS_STATISTICS FatStatistics;
} FAT_FILESYSTEM_STATISTICS, *PFAT_FILESYSTEM_STATISTICS;
typedef struct _EXFAT_FILESYSTEM_STATISTICS
{
FILESYSTEM_STATISTICS FileSystemStatistics;
EXFAT_STATISTICS ExFatStatistics;
} EXFAT_FILESYSTEM_STATISTICS, *PEXFAT_FILESYSTEM_STATISTICS;
BOOLEAN DiskDriveQueryFileSystemInfo(
_In_ HANDLE DeviceHandle,
_Out_ USHORT* FileSystemType,
_Out_ PVOID* FileSystemStatistics
);
typedef struct _NTFS_VOLUME_INFO
{
NTFS_VOLUME_DATA_BUFFER VolumeData;
NTFS_EXTENDED_VOLUME_DATA ExtendedVolumeData;
} NTFS_VOLUME_INFO, *PNTFS_VOLUME_INFO;
BOOLEAN DiskDriveQueryNtfsVolumeInfo(
_In_ HANDLE DosDeviceHandle,
_Out_ PNTFS_VOLUME_INFO VolumeInfo
);
BOOLEAN DiskDriveQueryRefsVolumeInfo(
_In_ HANDLE DosDeviceHandle,
_Out_ PREFS_VOLUME_DATA_BUFFER VolumeInfo
);
NTSTATUS DiskDriveQueryVolumeInformation(
_In_ HANDLE DosDeviceHandle,
_Out_ PFILE_FS_VOLUME_INFORMATION* VolumeInfo
);
NTSTATUS DiskDriveQueryVolumeAttributes(
_In_ HANDLE DosDeviceHandle,
_Out_ PFILE_FS_ATTRIBUTE_INFORMATION* AttributeInfo
);
typedef enum _SMART_ATTRIBUTE_ID
{
SMART_ATTRIBUTE_ID_READ_ERROR_RATE = 0x01,
SMART_ATTRIBUTE_ID_THROUGHPUT_PERFORMANCE = 0x02,
SMART_ATTRIBUTE_ID_SPIN_UP_TIME = 0x03,
SMART_ATTRIBUTE_ID_START_STOP_COUNT = 0x04,
SMART_ATTRIBUTE_ID_REALLOCATED_SECTORS_COUNT = 0x05,
SMART_ATTRIBUTE_ID_READ_CHANNEL_MARGIN = 0x06,
SMART_ATTRIBUTE_ID_SEEK_ERROR_RATE = 0x07,
SMART_ATTRIBUTE_ID_SEEK_TIME_PERFORMANCE = 0x08,
SMART_ATTRIBUTE_ID_POWER_ON_HOURS = 0x09,
SMART_ATTRIBUTE_ID_SPIN_RETRY_COUNT = 0x0A,
SMART_ATTRIBUTE_ID_CALIBRATION_RETRY_COUNT = 0x0B,
SMART_ATTRIBUTE_ID_POWER_CYCLE_COUNT = 0x0C,
SMART_ATTRIBUTE_ID_SOFT_READ_ERROR_RATE = 0x0D,
// Unknown values 14-182
SMART_ATTRIBUTE_ID_SATA_DOWNSHIFT_ERROR_COUNT = 0xB7,
SMART_ATTRIBUTE_ID_END_TO_END_ERROR = 0xB8,
SMART_ATTRIBUTE_ID_HEAD_STABILITY = 0xB9,
SMART_ATTRIBUTE_ID_INDUCED_OP_VIBRATION_DETECTION = 0xBA,
SMART_ATTRIBUTE_ID_REPORTED_UNCORRECTABLE_ERRORS = 0xBB,
SMART_ATTRIBUTE_ID_COMMAND_TIMEOUT = 0xBC,
SMART_ATTRIBUTE_ID_HIGH_FLY_WRITES = 0xBD,
SMART_ATTRIBUTE_ID_TEMPERATURE_DIFFERENCE_FROM_100 = 0xBE, // AirflowTemperature
SMART_ATTRIBUTE_ID_GSENSE_ERROR_RATE = 0xBF,
SMART_ATTRIBUTE_ID_POWER_OFF_RETRACT_COUNT = 0xC0,
SMART_ATTRIBUTE_ID_LOAD_CYCLE_COUNT = 0xC1,
SMART_ATTRIBUTE_ID_TEMPERATURE = 0xC2,
SMART_ATTRIBUTE_ID_HARDWARE_ECC_RECOVERED = 0xC3,
SMART_ATTRIBUTE_ID_REALLOCATION_EVENT_COUNT = 0xC4,
SMART_ATTRIBUTE_ID_CURRENT_PENDING_SECTOR_COUNT = 0xC5,
SMART_ATTRIBUTE_ID_UNCORRECTABLE_SECTOR_COUNT = 0xC6,
SMART_ATTRIBUTE_ID_ULTRADMA_CRC_ERROR_COUNT = 0xC7,
SMART_ATTRIBUTE_ID_MULTI_ZONE_ERROR_RATE = 0xC8,
SMART_ATTRIBUTE_ID_OFFTRACK_SOFT_READ_ERROR_RATE = 0xC9,
SMART_ATTRIBUTE_ID_DATA_ADDRESS_MARK_ERRORS = 0xCA,
SMART_ATTRIBUTE_ID_RUN_OUT_CANCEL = 0xCB,
SMART_ATTRIBUTE_ID_SOFT_ECC_CORRECTION = 0xCC,
SMART_ATTRIBUTE_ID_THERMAL_ASPERITY_RATE_TAR = 0xCD,
SMART_ATTRIBUTE_ID_FLYING_HEIGHT = 0xCE,
SMART_ATTRIBUTE_ID_SPIN_HIGH_CURRENT = 0xCF,
SMART_ATTRIBUTE_ID_SPIN_BUZZ = 0xD0,
SMART_ATTRIBUTE_ID_OFFLINE_SEEK_PERFORMANCE = 0xD1,
SMART_ATTRIBUTE_ID_VIBRATION_DURING_WRITE = 0xD3,
SMART_ATTRIBUTE_ID_SHOCK_DURING_WRITE = 0xD4,
SMART_ATTRIBUTE_ID_DISK_SHIFT = 0xDC,
SMART_ATTRIBUTE_ID_GSENSE_ERROR_RATE_ALT = 0xDD,
SMART_ATTRIBUTE_ID_LOADED_HOURS = 0xDE,
SMART_ATTRIBUTE_ID_LOAD_UNLOAD_RETRY_COUNT = 0xDF,
SMART_ATTRIBUTE_ID_LOAD_FRICTION = 0xE0,
SMART_ATTRIBUTE_ID_LOAD_UNLOAD_CYCLE_COUNT = 0xE1,
SMART_ATTRIBUTE_ID_LOAD_IN_TIME = 0xE2,
SMART_ATTRIBUTE_ID_TORQUE_AMPLIFICATION_COUNT = 0xE3,
SMART_ATTRIBUTE_ID_POWER_OFF_RETTRACT_CYCLE = 0xE4,
// Unknown values 229
SMART_ATTRIBUTE_ID_GMR_HEAD_AMPLITUDE = 0xE6,
SMART_ATTRIBUTE_ID_DRIVE_TEMPERATURE = 0xE7,
// Unknown values 232-239
SMART_ATTRIBUTE_ID_HEAD_FLYING_HOURS = 0xF0,
SMART_ATTRIBUTE_ID_TOTAL_LBA_WRITTEN = 0xF1,
SMART_ATTRIBUTE_ID_TOTAL_LBA_READ = 0xF2,
// Unknown values 243-249
SMART_ATTRIBUTE_ID_READ_ERROR_RETY_RATE = 0xFA,
// Unknown values 251-253
SMART_ATTRIBUTE_ID_FREE_FALL_PROTECTION = 0xFE,
} SMART_ATTRIBUTE_ID;
#define SMART_HEADER_SIZE 2
#include <pshpack1.h>
typedef struct _SMART_ATTRIBUTE
{
BYTE Id;
USHORT Flags;
BYTE CurrentValue;
BYTE WorstValue;
BYTE RawValue[6];
BYTE Reserved;
} SMART_ATTRIBUTE, *PSMART_ATTRIBUTE;
#include <poppack.h>
typedef struct _SMART_ATTRIBUTES
{
SMART_ATTRIBUTE_ID AttributeId;
UINT CurrentValue;
UINT WorstValue;
UINT RawValue;
// Pre-fail/Advisory bit
// This bit is applicable only when the value of this attribute is less than or equal to its threshhold.
// 0 : Advisory: The device has exceeded its intended design life period.
// 1 : Pre-failure notification : Failure is predicted within 24 hours.
BOOLEAN Advisory;
BOOLEAN FailureImminent;
// Online data collection bit
// 0 : This value of this attribute is only updated during offline activities.
// 1 : The value of this attribute is updated during both normal operation and offline activities.
BOOLEAN OnlineDataCollection;
// TRUE: This attribute characterizes a performance aspect of the drive,
// degradation of which may indicate imminent drive failure, such as data throughput, seektimes, spin up time, etc.
BOOLEAN Performance;
// TRUE: This attribute is based on the expected, non-fatal errors that are inherent in disk drives,
// increases in which may indicate imminent drive failure, such as ECC errors, seek errors, etc.
BOOLEAN ErrorRate;
// TRUE: This attribute counts events, of which an excessive number of which may
// indicate imminent drive failure, such as number of re-allocated sectors, etc.
BOOLEAN EventCount;
// TRUE: This type is used to specify an attribute that is collected and saved by the drive automatically.
BOOLEAN SelfPreserving;
} SMART_ATTRIBUTES, *PSMART_ATTRIBUTES;
PWSTR SmartAttributeGetText(
_In_ SMART_ATTRIBUTE_ID AttributeId
);
PWSTR SmartAttributeGetDescription(
_In_ SMART_ATTRIBUTE_ID AttributeId
);
// diskgraph.c
VOID DiskDriveSysInfoInitializing(
_In_ PPH_PLUGIN_SYSINFO_POINTERS Pointers,
_In_ _Assume_refs_(1) PDV_DISK_ENTRY DiskEntry
);
// netgraph.c
VOID NetAdapterSysInfoInitializing(
_In_ PPH_PLUGIN_SYSINFO_POINTERS Pointers,
_In_ _Assume_refs_(1) PDV_NETADAPTER_ENTRY AdapterEntry
);
#ifdef _NV_GPU_BUILD
// Graphics
extern BOOLEAN NvApiInitialized;
extern ULONG GpuMemoryLimit;
extern FLOAT GpuCurrentGpuUsage;
extern FLOAT GpuCurrentCoreUsage;
extern FLOAT GpuCurrentBusUsage;
extern ULONG GpuCurrentMemUsage;
extern ULONG GpuCurrentMemSharedUsage;
extern ULONG GpuCurrentCoreTemp;
extern ULONG GpuCurrentBoardTemp;
extern ULONG GpuCurrentCoreClock;
extern ULONG GpuCurrentMemoryClock;
extern ULONG GpuCurrentShaderClock;
extern ULONG GpuCurrentVoltage;
extern PH_CIRCULAR_BUFFER_FLOAT GpuUtilizationHistory;
extern PH_CIRCULAR_BUFFER_ULONG GpuMemoryHistory;
extern PH_CIRCULAR_BUFFER_FLOAT GpuBoardHistory;
extern PH_CIRCULAR_BUFFER_FLOAT GpuBusHistory;
VOID NvGpuSysInfoInitializing(
_In_ PPH_PLUGIN_SYSINFO_POINTERS Pointers
);
VOID NvApiInitialize(VOID);
BOOLEAN DestroyNvApi(VOID);
PPH_STRING NvGpuQueryDriverVersion(VOID);
PPH_STRING NvGpuQueryVbiosVersionString(VOID);
PPH_STRING NvGpuQueryName(VOID);
PPH_STRING NvGpuQueryShortName(VOID);
PPH_STRING NvGpuQueryRevision(VOID);
PPH_STRING NvGpuQueryRamType(VOID);
PPH_STRING NvGpuQueryFoundry(VOID);
PPH_STRING NvGpuQueryDeviceId(VOID);
PPH_STRING NvGpuQueryRopsCount(VOID);
PPH_STRING NvGpuQueryShaderCount(VOID);
PPH_STRING NvGpuQueryPciInfo(VOID);
PPH_STRING NvGpuQueryBusWidth(VOID);
PPH_STRING NvGpuQueryPcbValue(VOID);
PPH_STRING NvGpuQueryDriverSettings(VOID);
PPH_STRING NvGpuQueryFanSpeed(VOID);
BOOLEAN NvGpuDriverIsWHQL(VOID);
VOID NvGpuUpdate(VOID);
#endif
#endif _DEVICES_H_

View File

@@ -0,0 +1,303 @@
/*
* Process Hacker Plugins -
* Hardware Devices Plugin
*
* Copyright (C) 2015-2016 dmex
* Copyright (C) 2016 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 "devices.h"
VOID DiskEntryDeleteProcedure(
_In_ PVOID Object,
_In_ ULONG Flags
)
{
PDV_DISK_ENTRY entry = Object;
PhAcquireQueuedLockExclusive(&DiskDrivesListLock);
PhRemoveItemList(DiskDrivesList, PhFindItemList(DiskDrivesList, entry));
PhReleaseQueuedLockExclusive(&DiskDrivesListLock);
DeleteDiskId(&entry->Id);
PhClearReference(&entry->DiskName);
PhDeleteCircularBuffer_ULONG64(&entry->ReadBuffer);
PhDeleteCircularBuffer_ULONG64(&entry->WriteBuffer);
AddRemoveDeviceChangeCallback();
}
VOID DiskDrivesInitialize(
VOID
)
{
DiskDrivesList = PhCreateList(1);
DiskDriveEntryType = PhCreateObjectType(L"DiskDriveEntry", 0, DiskEntryDeleteProcedure);
}
VOID DiskDrivesUpdate(
VOID
)
{
static ULONG runCount = 0; // MUST keep in sync with runCount in process provider
PhAcquireQueuedLockShared(&DiskDrivesListLock);
for (ULONG i = 0; i < DiskDrivesList->Count; i++)
{
HANDLE deviceHandle;
PDV_DISK_ENTRY entry;
entry = PhReferenceObjectSafe(DiskDrivesList->Items[i]);
if (!entry)
continue;
if (NT_SUCCESS(DiskDriveCreateHandle(&deviceHandle, entry->Id.DevicePath)))
{
DISK_PERFORMANCE diskPerformance;
if (NT_SUCCESS(DiskDriveQueryStatistics(deviceHandle, &diskPerformance)))
{
ULONG64 readTime;
ULONG64 writeTime;
ULONG64 idleTime;
ULONG readCount;
ULONG writeCount;
ULONG64 queryTime;
PhUpdateDelta(&entry->BytesReadDelta, diskPerformance.BytesRead.QuadPart);
PhUpdateDelta(&entry->BytesWrittenDelta, diskPerformance.BytesWritten.QuadPart);
PhUpdateDelta(&entry->ReadTimeDelta, diskPerformance.ReadTime.QuadPart);
PhUpdateDelta(&entry->WriteTimeDelta, diskPerformance.WriteTime.QuadPart);
PhUpdateDelta(&entry->IdleTimeDelta, diskPerformance.IdleTime.QuadPart);
PhUpdateDelta(&entry->ReadCountDelta, diskPerformance.ReadCount);
PhUpdateDelta(&entry->WriteCountDelta, diskPerformance.WriteCount);
PhUpdateDelta(&entry->QueryTimeDelta, diskPerformance.QueryTime.QuadPart);
readTime = entry->ReadTimeDelta.Delta;
writeTime = entry->WriteTimeDelta.Delta;
idleTime = entry->IdleTimeDelta.Delta;
readCount = entry->ReadCountDelta.Delta;
writeCount = entry->WriteCountDelta.Delta;
queryTime = entry->QueryTimeDelta.Delta;
if (readCount + writeCount != 0)
entry->ResponseTime = ((FLOAT)readTime + (FLOAT)writeTime) / (readCount + writeCount);
else
entry->ResponseTime = 0;
if (queryTime != 0)
entry->ActiveTime = (FLOAT)(queryTime - idleTime) / queryTime * 100;
else
entry->ActiveTime = 0.0f;
if (entry->ActiveTime > 100.f)
entry->ActiveTime = 0.f;
if (entry->ActiveTime < 0.f)
entry->ActiveTime = 0.f;
entry->QueueDepth = diskPerformance.QueueDepth;
entry->SplitCount = diskPerformance.SplitCount;
entry->DiskIndex = diskPerformance.StorageDeviceNumber;
entry->DevicePresent = TRUE;
}
else
{
// Disk has been disconnected or dismounted.
PhInitializeDelta(&entry->BytesReadDelta);
PhInitializeDelta(&entry->BytesWrittenDelta);
PhInitializeDelta(&entry->ReadTimeDelta);
PhInitializeDelta(&entry->WriteTimeDelta);
PhInitializeDelta(&entry->IdleTimeDelta);
PhInitializeDelta(&entry->ReadCountDelta);
PhInitializeDelta(&entry->WriteCountDelta);
PhInitializeDelta(&entry->QueryTimeDelta);
entry->ResponseTime = 0;
entry->ActiveTime = 0.0f;
entry->QueueDepth = 0;
entry->SplitCount = 0;
entry->DiskIndex = ULONG_MAX;
entry->DevicePresent = FALSE;
PhClearReference(&entry->DiskIndexName);
}
if (runCount > 1)
{
// Delay the first query for the disk name, index and type.
// 1) This information is not needed until the user opens the sysinfo window.
// 2) Try not to query this information while opening the sysinfo window (e.g. delay).
// 3) Try not to query this information during startup (e.g. delay).
//
// Note: If the user opens the Sysinfo window before we query the disk info,
// we have a second check in diskgraph.c that queries the information on demand.
DiskDriveUpdateDeviceInfo(deviceHandle, entry);
}
NtClose(deviceHandle);
}
else
{
// Disk has been disconnected or dismounted.
PhInitializeDelta(&entry->BytesReadDelta);
PhInitializeDelta(&entry->BytesWrittenDelta);
PhInitializeDelta(&entry->ReadTimeDelta);
PhInitializeDelta(&entry->WriteTimeDelta);
PhInitializeDelta(&entry->IdleTimeDelta);
PhInitializeDelta(&entry->ReadCountDelta);
PhInitializeDelta(&entry->WriteCountDelta);
PhInitializeDelta(&entry->QueryTimeDelta);
entry->ResponseTime = 0;
entry->ActiveTime = 0.0f;
entry->QueueDepth = 0;
entry->SplitCount = 0;
entry->DiskIndex = ULONG_MAX;
entry->DevicePresent = FALSE;
PhClearReference(&entry->DiskIndexName);
}
if (!entry->HaveFirstSample)
{
// The first sample must be zero.
entry->BytesReadDelta.Delta = 0;
entry->BytesWrittenDelta.Delta = 0;
entry->HaveFirstSample = TRUE;
}
if (runCount != 0)
{
PhAddItemCircularBuffer_ULONG64(&entry->ReadBuffer, entry->BytesReadDelta.Delta);
PhAddItemCircularBuffer_ULONG64(&entry->WriteBuffer, entry->BytesWrittenDelta.Delta);
}
PhDereferenceObjectDeferDelete(entry);
}
PhReleaseQueuedLockShared(&DiskDrivesListLock);
runCount++;
}
VOID DiskDriveUpdateDeviceInfo(
_In_opt_ HANDLE DeviceHandle,
_In_ PDV_DISK_ENTRY DiskEntry
)
{
if (!DiskEntry->DiskName || DiskEntry->DiskIndex == ULONG_MAX)
{
HANDLE deviceHandle = NULL;
if (!DeviceHandle)
{
DiskDriveCreateHandle(&deviceHandle, DiskEntry->Id.DevicePath);
}
else
{
deviceHandle = DeviceHandle;
}
if (deviceHandle)
{
if (!DiskEntry->DiskName)
{
PPH_STRING diskName = NULL;
if (NT_SUCCESS(DiskDriveQueryDeviceInformation(deviceHandle, NULL, &diskName, NULL, NULL)))
{
DiskEntry->DiskName = diskName;
}
}
if (DiskEntry->DiskIndex == ULONG_MAX)
{
ULONG diskIndex = ULONG_MAX; // Note: Do not initialize to zero.
if (NT_SUCCESS(DiskDriveQueryDeviceTypeAndNumber(deviceHandle, &diskIndex, NULL)))
{
DiskEntry->DiskIndex = diskIndex;
}
}
if (!DeviceHandle)
{
NtClose(deviceHandle);
}
}
}
}
VOID InitializeDiskId(
_Out_ PDV_DISK_ID Id,
_In_ PPH_STRING DevicePath
)
{
PhSetReference(&Id->DevicePath, DevicePath);
}
VOID CopyDiskId(
_Out_ PDV_DISK_ID Destination,
_In_ PDV_DISK_ID Source
)
{
InitializeDiskId(
Destination,
Source->DevicePath
);
}
VOID DeleteDiskId(
_Inout_ PDV_DISK_ID Id
)
{
PhClearReference(&Id->DevicePath);
}
BOOLEAN EquivalentDiskId(
_In_ PDV_DISK_ID Id1,
_In_ PDV_DISK_ID Id2
)
{
return PhEqualString(Id1->DevicePath, Id2->DevicePath, TRUE);
}
PDV_DISK_ENTRY CreateDiskEntry(
_In_ PDV_DISK_ID Id
)
{
PDV_DISK_ENTRY entry;
entry = PhCreateObject(sizeof(DV_DISK_ENTRY), DiskDriveEntryType);
memset(entry, 0, sizeof(DV_DISK_ENTRY));
entry->DiskIndex = ULONG_MAX;
CopyDiskId(&entry->Id, Id);
PhInitializeCircularBuffer_ULONG64(&entry->ReadBuffer, PhGetIntegerSetting(L"SampleCount"));
PhInitializeCircularBuffer_ULONG64(&entry->WriteBuffer, PhGetIntegerSetting(L"SampleCount"));
PhAcquireQueuedLockExclusive(&DiskDrivesListLock);
PhAddItemList(DiskDrivesList, entry);
PhReleaseQueuedLockExclusive(&DiskDrivesListLock);
AddRemoveDeviceChangeCallback();
return entry;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,504 @@
/*
* Process Hacker Plugins -
* Hardware Devices Plugin
*
* 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 "devices.h"
VOID DiskDriveUpdateGraphs(
_Inout_ PDV_DISK_SYSINFO_CONTEXT Context
)
{
Context->GraphState.Valid = FALSE;
Context->GraphState.TooltipIndex = -1;
Graph_MoveGrid(Context->GraphHandle, 1);
Graph_Draw(Context->GraphHandle);
Graph_UpdateTooltip(Context->GraphHandle);
InvalidateRect(Context->GraphHandle, NULL, FALSE);
}
VOID DiskDriveUpdatePanel(
_Inout_ PDV_DISK_SYSINFO_CONTEXT Context
)
{
SetDlgItemText(Context->PanelWindowHandle, IDC_STAT_BREAD, PhaFormatSize(Context->DiskEntry->BytesReadDelta.Value, -1)->Buffer);
SetDlgItemText(Context->PanelWindowHandle, IDC_STAT_BWRITE, PhaFormatSize(Context->DiskEntry->BytesWrittenDelta.Value, -1)->Buffer);
SetDlgItemText(Context->PanelWindowHandle, IDC_STAT_BTOTAL, PhaFormatSize(Context->DiskEntry->BytesReadDelta.Value + Context->DiskEntry->BytesWrittenDelta.Value, -1)->Buffer);
SetDlgItemText(Context->PanelWindowHandle, IDC_STAT_ACTIVE,
PhaFormatString(L"%.0f%%", Context->DiskEntry->ActiveTime)->Buffer
);
SetDlgItemText(Context->PanelWindowHandle, IDC_STAT_RESPONSETIME,
PhaFormatString(L"%.1f ms", Context->DiskEntry->ResponseTime / PH_TICKS_PER_MS)->Buffer
);
SetDlgItemText(Context->PanelWindowHandle, IDC_STAT_QUEUELENGTH,
PhaFormatString(L"%lu", Context->DiskEntry->QueueDepth)->Buffer
);
}
VOID UpdateDiskDriveDialog(
_Inout_ PDV_DISK_SYSINFO_CONTEXT Context
)
{
if (Context->DiskEntry->DiskName)
SetDlgItemText(Context->WindowHandle, IDC_DISKNAME, Context->DiskEntry->DiskName->Buffer);
else
SetDlgItemText(Context->WindowHandle, IDC_DISKNAME, L"Unknown disk");
if (Context->DiskEntry->DiskIndexName)
SetDlgItemText(Context->WindowHandle, IDC_DISKMOUNTPATH, Context->DiskEntry->DiskIndexName->Buffer);
else
SetDlgItemText(Context->WindowHandle, IDC_DISKMOUNTPATH, L"Unknown disk");
DiskDriveUpdateGraphs(Context);
DiskDriveUpdatePanel(Context);
}
VOID UpdateDiskIndexText(
_Inout_ PDV_DISK_SYSINFO_CONTEXT Context
)
{
// If our delayed lookup of the disk name, index and type hasn't fired then query the information now.
DiskDriveUpdateDeviceInfo(NULL, Context->DiskEntry);
// TODO: Move into DiskDriveUpdateDeviceInfo.
if (Context->DiskEntry->DiskIndex != ULONG_MAX && !Context->DiskEntry->DiskIndexName)
{
// Query the disk DosDevices mount points.
PPH_STRING diskMountPoints = PH_AUTO_T(PH_STRING, DiskDriveQueryDosMountPoints(Context->DiskEntry->DiskIndex));
if (!PhIsNullOrEmptyString(diskMountPoints))
{
PhMoveReference(&Context->DiskEntry->DiskIndexName, PhFormatString(
L"Disk %lu (%s)",
Context->DiskEntry->DiskIndex,
diskMountPoints->Buffer
));
}
else
{
PhMoveReference(&Context->DiskEntry->DiskIndexName, PhFormatString(
L"Disk %lu",
Context->DiskEntry->DiskIndex
));
}
}
}
INT_PTR CALLBACK DiskDrivePanelDialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
PDV_DISK_SYSINFO_CONTEXT context = NULL;
if (uMsg == WM_INITDIALOG)
{
context = (PDV_DISK_SYSINFO_CONTEXT)lParam;
SetProp(hwndDlg, L"Context", (HANDLE)context);
}
else
{
context = (PDV_DISK_SYSINFO_CONTEXT)GetProp(hwndDlg, L"Context");
if (uMsg == WM_NCDESTROY)
{
RemoveProp(hwndDlg, L"Context");
}
}
if (context == NULL)
return FALSE;
switch (uMsg)
{
case WM_COMMAND:
{
switch (GET_WM_COMMAND_ID(wParam, lParam))
{
case IDC_DETAILS:
ShowDiskDriveDetailsDialog(context);
break;
}
}
break;
}
return FALSE;
}
INT_PTR CALLBACK DiskDriveDialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
PDV_DISK_SYSINFO_CONTEXT context = NULL;
if (uMsg == WM_INITDIALOG)
{
context = (PDV_DISK_SYSINFO_CONTEXT)lParam;
SetProp(hwndDlg, L"Context", (HANDLE)context);
}
else
{
context = (PDV_DISK_SYSINFO_CONTEXT)GetProp(hwndDlg, L"Context");
if (uMsg == WM_DESTROY)
{
PhDeleteLayoutManager(&context->LayoutManager);
PhDeleteGraphState(&context->GraphState);
if (context->GraphHandle)
DestroyWindow(context->GraphHandle);
if (context->PanelWindowHandle)
DestroyWindow(context->PanelWindowHandle);
RemoveProp(hwndDlg, L"Context");
}
}
if (context == NULL)
return FALSE;
switch (uMsg)
{
case WM_INITDIALOG:
{
PPH_LAYOUT_ITEM graphItem;
PPH_LAYOUT_ITEM panelItem;
context->WindowHandle = hwndDlg;
PhInitializeGraphState(&context->GraphState);
PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);
PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_DISKMOUNTPATH), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT | PH_LAYOUT_FORCE_INVALIDATE);
PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_DISKNAME), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_TOP | PH_LAYOUT_FORCE_INVALIDATE);
graphItem = PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_GRAPH_LAYOUT), NULL, PH_ANCHOR_ALL);
panelItem = PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
SendMessage(GetDlgItem(hwndDlg, IDC_DISKMOUNTPATH), WM_SETFONT, (WPARAM)context->SysinfoSection->Parameters->LargeFont, FALSE);
SendMessage(GetDlgItem(hwndDlg, IDC_DISKNAME), WM_SETFONT, (WPARAM)context->SysinfoSection->Parameters->MediumFont, FALSE);
if (context->DiskEntry->DiskIndexName)
SetDlgItemText(hwndDlg, IDC_DISKMOUNTPATH, context->DiskEntry->DiskIndexName->Buffer);
else
SetDlgItemText(hwndDlg, IDC_DISKMOUNTPATH, L"Unknown disk");
if (context->DiskEntry->DiskName)
SetDlgItemText(hwndDlg, IDC_DISKNAME, context->DiskEntry->DiskName->Buffer);
else
SetDlgItemText(hwndDlg, IDC_DISKNAME, L"Unknown disk");
context->PanelWindowHandle = CreateDialogParam(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_DISKDRIVE_PANEL), hwndDlg, DiskDrivePanelDialogProc, (LPARAM)context);
ShowWindow(context->PanelWindowHandle, SW_SHOW);
PhAddLayoutItemEx(&context->LayoutManager, context->PanelWindowHandle, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM, panelItem->Margin);
// Create the graph control.
context->GraphHandle = CreateWindow(
PH_GRAPH_CLASSNAME,
NULL,
WS_VISIBLE | WS_CHILD | WS_BORDER,
0,
0,
3,
3,
hwndDlg,
NULL,
NULL,
NULL
);
Graph_SetTooltip(context->GraphHandle, TRUE);
PhAddLayoutItemEx(&context->LayoutManager, context->GraphHandle, NULL, PH_ANCHOR_ALL, graphItem->Margin);
UpdateDiskDriveDialog(context);
}
break;
case WM_SIZE:
PhLayoutManagerLayout(&context->LayoutManager);
break;
case WM_NOTIFY:
{
NMHDR* header = (NMHDR*)lParam;
if (header->hwndFrom == context->GraphHandle)
{
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;
context->SysinfoSection->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorIoReadOther"), PhGetIntegerSetting(L"ColorIoWrite"));
PhGraphStateGetDrawInfo(
&context->GraphState,
getDrawInfo,
context->DiskEntry->ReadBuffer.Count
);
if (!context->GraphState.Valid)
{
FLOAT max = 1024 * 1024; // minimum scaling of 1 MB.
for (ULONG i = 0; i < drawInfo->LineDataCount; i++)
{
FLOAT data1;
FLOAT data2;
context->GraphState.Data1[i] = data1 = (FLOAT)PhGetItemCircularBuffer_ULONG64(&context->DiskEntry->ReadBuffer, i);
context->GraphState.Data2[i] = data2 = (FLOAT)PhGetItemCircularBuffer_ULONG64(&context->DiskEntry->WriteBuffer, i);
if (max < data1 + data2)
max = data1 + data2;
}
if (max != 0)
{
// Scale the data.
PhDivideSinglesBySingle(
context->GraphState.Data1,
max,
drawInfo->LineDataCount
);
// Scale the data.
PhDivideSinglesBySingle(
context->GraphState.Data2,
max,
drawInfo->LineDataCount
);
}
drawInfo->LabelYFunction = PhSiSizeLabelYFunction;
drawInfo->LabelYFunctionParameter = max;
context->GraphState.Valid = TRUE;
}
}
break;
case GCN_GETTOOLTIPTEXT:
{
PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)header;
if (getTooltipText->Index < getTooltipText->TotalCount)
{
if (context->GraphState.TooltipIndex != getTooltipText->Index)
{
ULONG64 diskReadValue = PhGetItemCircularBuffer_ULONG64(
&context->DiskEntry->ReadBuffer,
getTooltipText->Index
);
ULONG64 diskWriteValue = PhGetItemCircularBuffer_ULONG64(
&context->DiskEntry->WriteBuffer,
getTooltipText->Index
);
PhMoveReference(&context->GraphState.TooltipText, PhFormatString(
L"R: %s\nW: %s\n%s",
PhaFormatSize(diskReadValue, -1)->Buffer,
PhaFormatSize(diskWriteValue, -1)->Buffer,
((PPH_STRING)PhAutoDereferenceObject(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
));
}
getTooltipText->Text = context->GraphState.TooltipText->sr;
}
}
break;
}
}
}
break;
case UPDATE_MSG:
{
UpdateDiskDriveDialog(context);
}
break;
}
return FALSE;
}
BOOLEAN DiskDriveSectionCallback(
_In_ PPH_SYSINFO_SECTION Section,
_In_ PH_SYSINFO_SECTION_MESSAGE Message,
_In_opt_ PVOID Parameter1,
_In_opt_ PVOID Parameter2
)
{
PDV_DISK_SYSINFO_CONTEXT context = (PDV_DISK_SYSINFO_CONTEXT)Section->Context;
switch (Message)
{
case SysInfoCreate:
{
UpdateDiskIndexText(context);
}
return TRUE;
case SysInfoDestroy:
{
PhDereferenceObject(context->DiskEntry);
PhDereferenceObject(context->SectionName);
PhFree(context);
}
return TRUE;
case SysInfoTick:
{
UpdateDiskIndexText(context);
if (context->WindowHandle)
PostMessage(context->WindowHandle, UPDATE_MSG, 0, 0);
}
return TRUE;
case SysInfoCreateDialog:
{
PPH_SYSINFO_CREATE_DIALOG createDialog = (PPH_SYSINFO_CREATE_DIALOG)Parameter1;
createDialog->Instance = PluginInstance->DllBase;
createDialog->Template = MAKEINTRESOURCE(IDD_DISKDRIVE_DIALOG);
createDialog->DialogProc = DiskDriveDialogProc;
createDialog->Parameter = context;
}
return TRUE;
case SysInfoGraphGetDrawInfo:
{
PPH_GRAPH_DRAW_INFO drawInfo = (PPH_GRAPH_DRAW_INFO)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, context->DiskEntry->ReadBuffer.Count);
if (!Section->GraphState.Valid)
{
FLOAT max = 1024 * 1024; // minimum scaling of 1 MB.
for (ULONG i = 0; i < drawInfo->LineDataCount; i++)
{
FLOAT data1;
FLOAT data2;
Section->GraphState.Data1[i] = data1 = (FLOAT)PhGetItemCircularBuffer_ULONG64(&context->DiskEntry->ReadBuffer, i);
Section->GraphState.Data2[i] = data2 = (FLOAT)PhGetItemCircularBuffer_ULONG64(&context->DiskEntry->WriteBuffer, i);
if (max < data1 + data2)
max = data1 + data2;
}
if (max != 0)
{
// Scale the data.
PhDivideSinglesBySingle(
Section->GraphState.Data1,
max,
drawInfo->LineDataCount
);
// Scale the data.
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 = (PPH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT)Parameter1;
ULONG64 diskReadValue = PhGetItemCircularBuffer_ULONG64(
&context->DiskEntry->ReadBuffer,
getTooltipText->Index
);
ULONG64 diskWriteValue = PhGetItemCircularBuffer_ULONG64(
&context->DiskEntry->WriteBuffer,
getTooltipText->Index
);
PhMoveReference(&Section->GraphState.TooltipText, PhFormatString(
L"R: %s\nW: %s\n%s",
PhaFormatSize(diskReadValue, -1)->Buffer,
PhaFormatSize(diskWriteValue, -1)->Buffer,
((PPH_STRING)PhAutoDereferenceObject(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
));
getTooltipText->Text = Section->GraphState.TooltipText->sr;
}
return TRUE;
case SysInfoGraphDrawPanel:
{
PPH_SYSINFO_DRAW_PANEL drawPanel = (PPH_SYSINFO_DRAW_PANEL)Parameter1;
PhSetReference(&drawPanel->Title, context->DiskEntry->DiskIndexName);
drawPanel->SubTitle = PhFormatString(
L"R: %s\nW: %s",
PhaFormatSize(context->DiskEntry->BytesReadDelta.Delta, -1)->Buffer,
PhaFormatSize(context->DiskEntry->BytesWrittenDelta.Delta, -1)->Buffer
);
if (!drawPanel->Title)
drawPanel->Title = PhCreateString(L"Unknown disk");
}
return TRUE;
}
return FALSE;
}
VOID DiskDriveSysInfoInitializing(
_In_ PPH_PLUGIN_SYSINFO_POINTERS Pointers,
_In_ _Assume_refs_(1) PDV_DISK_ENTRY DiskEntry
)
{
PH_SYSINFO_SECTION section;
PDV_DISK_SYSINFO_CONTEXT context;
context = (PDV_DISK_SYSINFO_CONTEXT)PhAllocate(sizeof(DV_DISK_SYSINFO_CONTEXT));
memset(context, 0, sizeof(DV_DISK_SYSINFO_CONTEXT));
memset(&section, 0, sizeof(PH_SYSINFO_SECTION));
context->DiskEntry = DiskEntry;
context->SectionName = PhConcatStrings2(L"Disk ", DiskEntry->Id.DevicePath->Buffer);
section.Context = context;
section.Callback = DiskDriveSectionCallback;
section.Name = context->SectionName->sr;
context->SysinfoSection = Pointers->CreateSection(&section);
}

View File

@@ -0,0 +1,119 @@
/*
* Process Hacker Plugins -
* Hardware Devices Plugin
*
* 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/>.
*/
#include "devices.h"
#include <Dbt.h>
static BOOLEAN SubclassActive = FALSE;
LRESULT CALLBACK MainWndDevicesSubclassProc(
_In_ HWND hWnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam,
_In_ UINT_PTR uIdSubclass,
_In_ ULONG_PTR dwRefData
)
{
// Subclassing the main window just to process drive letter notifications
// is bad and I don't know of any other way to achieve this.
// The IOCTL_MOUNTMGR_CHANGE_NOTIFY callback would have been preferred but
// doesn't work from non-elevated processes.
switch (uMsg)
{
case WM_DEVICECHANGE:
{
switch (wParam)
{
case DBT_DEVICEARRIVAL: // Drive letter added
case DBT_DEVICEREMOVECOMPLETE: // Drive letter removed
{
DEV_BROADCAST_HDR* deviceBroadcast = (DEV_BROADCAST_HDR*)lParam;
if (deviceBroadcast->dbch_devicetype == DBT_DEVTYP_VOLUME)
{
PDEV_BROADCAST_VOLUME deviceVolume = (PDEV_BROADCAST_VOLUME)deviceBroadcast;
PhAcquireQueuedLockShared(&DiskDrivesListLock);
for (ULONG i = 0; i < DiskDrivesList->Count; i++)
{
PDV_DISK_ENTRY entry;
entry = PhReferenceObjectSafe(DiskDrivesList->Items[i]);
if (!entry)
continue;
// Reset the DiskIndex so we can re-query the index on the next interval update.
entry->DiskIndex = ULONG_MAX;
// Reset the DiskIndexName so we can re-query the name on the next interval update.
PhClearReference(&entry->DiskIndexName);
PhDereferenceObjectDeferDelete(entry);
}
PhReleaseQueuedLockShared(&DiskDrivesListLock);
}
}
}
goto DefaultWndProc;
}
break;
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
DefaultWndProc:
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
VOID AddRemoveDeviceChangeCallback(
VOID
)
{
// We get called during the plugin LoadCallback, don't do anything.
if (!PhMainWndHandle)
return;
// Add the subclass only when disks are being monitored, remove when no longer needed.
if (DiskDrivesList->Count != 0)
{
if (!SubclassActive)
{
// We have a disk device, subclass the main window to detect drive letter changes.
SetWindowSubclass(PhMainWndHandle, MainWndDevicesSubclassProc, 0, 0);
SubclassActive = TRUE;
}
}
else
{
if (SubclassActive)
{
// The user has removed the last disk device, remove the subclass.
RemoveWindowSubclass(PhMainWndHandle, MainWndDevicesSubclassProc, 0);
SubclassActive = FALSE;
}
}
}

View File

@@ -0,0 +1,695 @@
/*
* Process Hacker Plugins -
* Hardware Devices Plugin
*
* 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 "devices.h"
#include <Setupapi.h>
#define ITEM_CHECKED (INDEXTOSTATEIMAGEMASK(2))
#define ITEM_UNCHECKED (INDEXTOSTATEIMAGEMASK(1))
typedef struct _DISK_ENUM_ENTRY
{
ULONG DeviceIndex;
BOOLEAN DevicePresent;
PPH_STRING DevicePath;
PPH_STRING DeviceName;
PPH_STRING DeviceMountPoints;
} DISK_ENUM_ENTRY, *PDISK_ENUM_ENTRY;
static int __cdecl DiskEntryCompareFunction(
_In_ const void *elem1,
_In_ const void *elem2
)
{
PDISK_ENUM_ENTRY entry1 = *(PDISK_ENUM_ENTRY *)elem1;
PDISK_ENUM_ENTRY entry2 = *(PDISK_ENUM_ENTRY *)elem2;
return uint64cmp(entry1->DeviceIndex, entry2->DeviceIndex);
}
VOID DiskDrivesLoadList(
VOID
)
{
PPH_STRING settingsString;
PH_STRINGREF remaining;
settingsString = PhaGetStringSetting(SETTING_NAME_DISK_LIST);
remaining = settingsString->sr;
while (remaining.Length != 0)
{
PH_STRINGREF part;
DV_DISK_ID id;
PDV_DISK_ENTRY entry;
if (remaining.Length == 0)
break;
PhSplitStringRefAtChar(&remaining, ',', &part, &remaining);
InitializeDiskId(&id, PhCreateString2(&part));
entry = CreateDiskEntry(&id);
DeleteDiskId(&id);
entry->UserReference = TRUE;
}
}
VOID DiskDrivesSaveList(
VOID
)
{
PH_STRING_BUILDER stringBuilder;
PPH_STRING settingsString;
PhInitializeStringBuilder(&stringBuilder, 260);
PhAcquireQueuedLockShared(&DiskDrivesListLock);
for (ULONG i = 0; i < DiskDrivesList->Count; i++)
{
PDV_DISK_ENTRY entry = PhReferenceObjectSafe(DiskDrivesList->Items[i]);
if (!entry)
continue;
if (entry->UserReference)
{
PhAppendFormatStringBuilder(
&stringBuilder,
L"%s,",
entry->Id.DevicePath->Buffer // This value is SAFE and does not change.
);
}
PhDereferenceObjectDeferDelete(entry);
}
PhReleaseQueuedLockShared(&DiskDrivesListLock);
if (stringBuilder.String->Length != 0)
PhRemoveEndStringBuilder(&stringBuilder, 1);
settingsString = PH_AUTO(PhFinalStringBuilderString(&stringBuilder));
PhSetStringSetting2(SETTING_NAME_DISK_LIST, &settingsString->sr);
}
BOOLEAN FindDiskEntry(
_In_ PDV_DISK_ID Id,
_In_ BOOLEAN RemoveUserReference
)
{
BOOLEAN found = FALSE;
PhAcquireQueuedLockShared(&DiskDrivesListLock);
for (ULONG i = 0; i < DiskDrivesList->Count; i++)
{
PDV_DISK_ENTRY currentEntry = PhReferenceObjectSafe(DiskDrivesList->Items[i]);
if (!currentEntry)
continue;
found = EquivalentDiskId(&currentEntry->Id, Id);
if (found)
{
if (RemoveUserReference)
{
if (currentEntry->UserReference)
{
PhDereferenceObjectDeferDelete(currentEntry);
currentEntry->UserReference = FALSE;
}
}
PhDereferenceObjectDeferDelete(currentEntry);
break;
}
else
{
PhDereferenceObjectDeferDelete(currentEntry);
}
}
PhReleaseQueuedLockShared(&DiskDrivesListLock);
return found;
}
VOID AddDiskDriveToListView(
_In_ PDV_DISK_OPTIONS_CONTEXT Context,
_In_ BOOLEAN DiskPresent,
_In_ PPH_STRING DiskPath,
_In_ PPH_STRING DiskName
)
{
DV_DISK_ID adapterId;
INT lvItemIndex;
BOOLEAN found = FALSE;
PDV_DISK_ID newId = NULL;
InitializeDiskId(&adapterId, DiskPath);
for (ULONG i = 0; i < DiskDrivesList->Count; i++)
{
PDV_DISK_ENTRY entry = PhReferenceObjectSafe(DiskDrivesList->Items[i]);
if (!entry)
continue;
if (EquivalentDiskId(&entry->Id, &adapterId))
{
newId = PhAllocate(sizeof(DV_DISK_ID));
CopyDiskId(newId, &entry->Id);
if (entry->UserReference)
found = TRUE;
}
PhDereferenceObjectDeferDelete(entry);
if (newId)
break;
}
if (!newId)
{
newId = PhAllocate(sizeof(DV_DISK_ID));
CopyDiskId(newId, &adapterId);
PhMoveReference(&newId->DevicePath, DiskPath);
}
lvItemIndex = AddListViewItemGroupId(
Context->ListViewHandle,
DiskPresent ? 0 : 1,
MAXINT,
DiskName->Buffer,
newId
);
if (found)
ListView_SetItemState(Context->ListViewHandle, lvItemIndex, ITEM_CHECKED, LVIS_STATEIMAGEMASK);
DeleteDiskId(&adapterId);
}
VOID FreeListViewDiskDriveEntries(
_In_ PDV_DISK_OPTIONS_CONTEXT Context
)
{
ULONG index = -1;
while ((index = PhFindListViewItemByFlags(
Context->ListViewHandle,
index,
LVNI_ALL
)) != -1)
{
PDV_DISK_ID param;
if (PhGetListViewItemParam(Context->ListViewHandle, index, &param))
{
DeleteDiskId(param);
PhFree(param);
}
}
}
VOID FindDiskDrives(
_In_ PDV_DISK_OPTIONS_CONTEXT Context
)
{
PPH_LIST deviceList;
HDEVINFO deviceInfoHandle;
SP_DEVICE_INTERFACE_DATA deviceInterfaceData = { sizeof(SP_DEVICE_INTERFACE_DATA) };
SP_DEVINFO_DATA deviceInfoData = { sizeof(SP_DEVINFO_DATA) };
PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetail;
ULONG deviceInfoLength = 0;
if ((deviceInfoHandle = SetupDiGetClassDevs(
&GUID_DEVINTERFACE_DISK,
NULL,
NULL,
DIGCF_DEVICEINTERFACE
)) == INVALID_HANDLE_VALUE)
{
return;
}
deviceList = PH_AUTO(PhCreateList(1));
for (ULONG i = 0; SetupDiEnumDeviceInterfaces(deviceInfoHandle, NULL, &GUID_DEVINTERFACE_DISK, i, &deviceInterfaceData); i++)
{
if (SetupDiGetDeviceInterfaceDetail(
deviceInfoHandle,
&deviceInterfaceData,
0,
0,
&deviceInfoLength,
&deviceInfoData
) || GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
continue;
}
deviceInterfaceDetail = PhAllocate(deviceInfoLength);
deviceInterfaceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (SetupDiGetDeviceInterfaceDetail(
deviceInfoHandle,
&deviceInterfaceData,
deviceInterfaceDetail,
deviceInfoLength,
&deviceInfoLength,
&deviceInfoData
))
{
HANDLE deviceHandle;
PDISK_ENUM_ENTRY diskEntry;
WCHAR diskFriendlyName[MAX_PATH] = L"";
// This crashes on XP with error 0xC06D007F
//SetupDiGetDeviceProperty(
// deviceInfoHandle,
// &deviceInfoData,
// &DEVPKEY_Device_FriendlyName,
// &devicePropertyType,
// (PBYTE)diskFriendlyName,
// ARRAYSIZE(diskFriendlyName),
// NULL,
// 0
// );
if (!SetupDiGetDeviceRegistryProperty(
deviceInfoHandle,
&deviceInfoData,
SPDRP_FRIENDLYNAME,
NULL,
(PBYTE)diskFriendlyName,
ARRAYSIZE(diskFriendlyName),
NULL
))
{
continue;
}
diskEntry = PhAllocate(sizeof(DISK_ENUM_ENTRY));
memset(diskEntry, 0, sizeof(DISK_ENUM_ENTRY));
diskEntry->DeviceIndex = ULONG_MAX; // Note: Do not initialize to zero.
diskEntry->DeviceName = PhCreateString(diskFriendlyName);
diskEntry->DevicePath = PhCreateString(deviceInterfaceDetail->DevicePath);
if (NT_SUCCESS(DiskDriveCreateHandle(
&deviceHandle,
diskEntry->DevicePath
)))
{
ULONG diskIndex = ULONG_MAX; // Note: Do not initialize to zero
if (NT_SUCCESS(DiskDriveQueryDeviceTypeAndNumber(
deviceHandle,
&diskIndex,
NULL
)))
{
PPH_STRING diskMountPoints = PH_AUTO_T(PH_STRING, DiskDriveQueryDosMountPoints(diskIndex));
diskEntry->DeviceIndex = diskIndex;
diskEntry->DevicePresent = TRUE;
if (!PhIsNullOrEmptyString(diskMountPoints))
{
diskEntry->DeviceMountPoints = PhFormatString(
L"Disk %lu (%s) [%s]",
diskIndex,
diskMountPoints->Buffer,
diskFriendlyName
);
}
else
{
diskEntry->DeviceMountPoints = PhFormatString(
L"Disk %lu [%s]",
diskIndex,
diskFriendlyName
);
}
}
NtClose(deviceHandle);
}
PhAddItemList(deviceList, diskEntry);
}
PhFree(deviceInterfaceDetail);
}
SetupDiDestroyDeviceInfoList(deviceInfoHandle);
// Sort the entries
qsort(deviceList->Items, deviceList->Count, sizeof(PVOID), DiskEntryCompareFunction);
Context->EnumeratingDisks = TRUE;
PhAcquireQueuedLockShared(&DiskDrivesListLock);
for (ULONG i = 0; i < deviceList->Count; i++)
{
PDISK_ENUM_ENTRY entry = deviceList->Items[i];
AddDiskDriveToListView(
Context,
entry->DevicePresent,
entry->DevicePath,
entry->DeviceMountPoints ? entry->DeviceMountPoints : entry->DeviceName
);
if (entry->DeviceMountPoints)
PhDereferenceObject(entry->DeviceMountPoints);
if (entry->DeviceName)
PhDereferenceObject(entry->DeviceName);
// Note: DevicePath is disposed by WM_DESTROY.
PhFree(entry);
}
PhReleaseQueuedLockShared(&DiskDrivesListLock);
Context->EnumeratingDisks = FALSE;
// HACK: Show all unknown devices.
Context->EnumeratingDisks = TRUE;
PhAcquireQueuedLockShared(&DiskDrivesListLock);
for (ULONG i = 0; i < DiskDrivesList->Count; i++)
{
ULONG index = -1;
BOOLEAN found = FALSE;
PDV_DISK_ENTRY entry = PhReferenceObjectSafe(DiskDrivesList->Items[i]);
if (!entry)
continue;
while ((index = PhFindListViewItemByFlags(
Context->ListViewHandle,
index,
LVNI_ALL
)) != -1)
{
PDV_DISK_ID param;
if (PhGetListViewItemParam(Context->ListViewHandle, index, &param))
{
if (EquivalentDiskId(param, &entry->Id))
{
found = TRUE;
}
}
}
if (!found)
{
PPH_STRING description;
if (description = PhCreateString(L"Unknown disk"))
{
AddDiskDriveToListView(
Context,
FALSE,
entry->Id.DevicePath,
description
);
PhDereferenceObject(description);
}
}
PhDereferenceObjectDeferDelete(entry);
}
PhReleaseQueuedLockShared(&DiskDrivesListLock);
Context->EnumeratingDisks = FALSE;
}
PPH_STRING FindDiskDeviceInstance(
_In_ PPH_STRING DevicePath
)
{
PPH_STRING deviceIdString = NULL;
HDEVINFO deviceInfoHandle;
SP_DEVICE_INTERFACE_DATA deviceInterfaceData = { sizeof(SP_DEVICE_INTERFACE_DATA) };
SP_DEVINFO_DATA deviceInfoData = { sizeof(SP_DEVINFO_DATA) };
PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetail;
ULONG deviceInfoLength = 0;
if ((deviceInfoHandle = SetupDiGetClassDevs(
&GUID_DEVINTERFACE_DISK,
NULL,
NULL,
DIGCF_DEVICEINTERFACE
)) == INVALID_HANDLE_VALUE)
{
return NULL;
}
for (ULONG i = 0; SetupDiEnumDeviceInterfaces(deviceInfoHandle, NULL, &GUID_DEVINTERFACE_DISK, i, &deviceInterfaceData); i++)
{
if (SetupDiGetDeviceInterfaceDetail(
deviceInfoHandle,
&deviceInterfaceData,
0,
0,
&deviceInfoLength,
&deviceInfoData
) || GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
continue;
}
deviceInterfaceDetail = PhAllocate(deviceInfoLength);
deviceInterfaceDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (SetupDiGetDeviceInterfaceDetail(
deviceInfoHandle,
&deviceInterfaceData,
deviceInterfaceDetail,
deviceInfoLength,
&deviceInfoLength,
&deviceInfoData
))
{
if (PhEqualStringZ(deviceInterfaceDetail->DevicePath, DevicePath->Buffer, TRUE))
{
deviceIdString = PhCreateStringEx(NULL, 0x100);
SetupDiGetDeviceInstanceId(
deviceInfoHandle,
&deviceInfoData,
deviceIdString->Buffer,
(ULONG)deviceIdString->Length,
NULL
);
PhTrimToNullTerminatorString(deviceIdString);
}
}
PhFree(deviceInterfaceDetail);
}
SetupDiDestroyDeviceInfoList(deviceInfoHandle);
return deviceIdString;
}
//VOID LoadDiskDriveImages(
// _In_ PDV_DISK_OPTIONS_CONTEXT Context
// )
//{
// HICON smallIcon = NULL;
//
// Context->ImageList = ImageList_Create(
// GetSystemMetrics(SM_CXSMICON),
// GetSystemMetrics(SM_CYSMICON),
// ILC_COLOR32,
// 1,
// 1
// );
//
// // We could use SetupDiLoadClassIcon but this works.
// // Copied from HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Class\{4d36e967-e325-11ce-bfc1-08002be10318}\\IconPath
// // The index is only valid on Vista and above.
// ExtractIconEx(
// L"%SystemRoot%\\system32\\imageres.dll",
// -32,
// NULL,
// &smallIcon,
// 1
// );
//
// if (smallIcon)
// {
// ImageList_AddIcon(Context->ImageList, smallIcon);
// DestroyIcon(smallIcon);
//
// // Set the imagelist only if the image was loaded.
// ListView_SetImageList(
// Context->ListViewHandle,
// Context->ImageList,
// LVSIL_SMALL
// );
// }
//}
INT_PTR CALLBACK DiskDriveOptionsDlgProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
PDV_DISK_OPTIONS_CONTEXT context = NULL;
if (uMsg == WM_INITDIALOG)
{
context = (PDV_DISK_OPTIONS_CONTEXT)PhAllocate(sizeof(DV_DISK_OPTIONS_CONTEXT));
memset(context, 0, sizeof(DV_DISK_OPTIONS_CONTEXT));
SetProp(hwndDlg, L"Context", (HANDLE)context);
}
else
{
context = (PDV_DISK_OPTIONS_CONTEXT)GetProp(hwndDlg, L"Context");
if (uMsg == WM_DESTROY)
{
if (context->OptionsChanged)
DiskDrivesSaveList();
FreeListViewDiskDriveEntries(context);
RemoveProp(hwndDlg, L"Context");
PhFree(context);
}
}
if (context == NULL)
return FALSE;
switch (uMsg)
{
case WM_INITDIALOG:
{
// Center the property sheet.
PhCenterWindow(GetParent(hwndDlg), GetParent(GetParent(hwndDlg)));
// Hide the OK button.
ShowWindow(GetDlgItem(GetParent(hwndDlg), IDOK), SW_HIDE);
// Set the Cancel button text.
Button_SetText(GetDlgItem(GetParent(hwndDlg), IDCANCEL), L"Close");
context->ListViewHandle = GetDlgItem(hwndDlg, IDC_DISKDRIVE_LISTVIEW);
PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE);
ListView_SetExtendedListViewStyleEx(context->ListViewHandle, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
PhSetControlTheme(context->ListViewHandle, L"explorer");
PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 350, L"Disk Drives");
PhSetExtendedListView(context->ListViewHandle);
if (WindowsVersion >= WINDOWS_VISTA)
{
ListView_EnableGroupView(context->ListViewHandle, TRUE);
AddListViewGroup(context->ListViewHandle, 0, L"Connected");
AddListViewGroup(context->ListViewHandle, 1, L"Disconnected");
}
FindDiskDrives(context);
context->OptionsChanged = FALSE;
EnableThemeDialogTexture(hwndDlg, ETDT_ENABLETAB);
}
break;
case WM_NOTIFY:
{
LPNMHDR header = (LPNMHDR)lParam;
if (header->code == LVN_ITEMCHANGED)
{
LPNM_LISTVIEW listView = (LPNM_LISTVIEW)lParam;
if (context->EnumeratingDisks)
break;
if (listView->uChanged & LVIF_STATE)
{
switch (listView->uNewState & LVIS_STATEIMAGEMASK)
{
case 0x2000: // checked
{
PDV_DISK_ID param = (PDV_DISK_ID)listView->lParam;
if (!FindDiskEntry(param, FALSE))
{
PDV_DISK_ENTRY entry;
entry = CreateDiskEntry(param);
entry->UserReference = TRUE;
}
context->OptionsChanged = TRUE;
}
break;
case 0x1000: // unchecked
{
PDV_DISK_ID param = (PDV_DISK_ID)listView->lParam;
FindDiskEntry(param, TRUE);
context->OptionsChanged = TRUE;
}
break;
}
}
}
else if (header->code == NM_RCLICK)
{
PDV_DISK_ID param;
PPH_STRING deviceInstance;
if (param = PhGetSelectedListViewItemParam(context->ListViewHandle))
{
if (deviceInstance = FindDiskDeviceInstance(param->DevicePath))
{
ShowDeviceMenu(hwndDlg, deviceInstance);
PhDereferenceObject(deviceInstance);
}
}
}
}
break;
}
return FALSE;
}

View File

@@ -0,0 +1,793 @@
/*
* Process Hacker Extra Plugins -
* Nvidia GPU Plugin
*
* 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 "devices.h"
#ifdef _NV_GPU_BUILD
#define ET_GPU_PADDING 3
static RECT NormalGraphTextMargin = { 5, 5, 5, 5 };
static RECT NormalGraphTextPadding = { 3, 3, 3, 3 };
static PPH_STRING GpuName;
static HWND WindowHandle;
static HWND DetailsHandle;
static PPH_SYSINFO_SECTION Section;
static PH_LAYOUT_MANAGER LayoutManager;
static RECT GpuGraphMargin;
static HWND GpuPanel;
static HWND GpuLabelHandle;
static HWND MemLabelHandle;
static HWND SharedLabelHandle;
static HWND BusLabelHandle;
static HWND GpuGraphHandle;
static HWND MemGraphHandle;
static HWND SharedGraphHandle;
static HWND BusGraphHandle;
static PH_GRAPH_STATE GpuGraphState;
static PH_GRAPH_STATE MemGraphState;
static PH_GRAPH_STATE SharedGraphState;
static PH_GRAPH_STATE BusGraphState;
PH_CIRCULAR_BUFFER_FLOAT GpuUtilizationHistory;
PH_CIRCULAR_BUFFER_ULONG GpuMemoryHistory;
PH_CIRCULAR_BUFFER_FLOAT GpuBoardHistory;
PH_CIRCULAR_BUFFER_FLOAT GpuBusHistory;
INT_PTR CALLBACK NvGpuPanelDialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
return FALSE;
}
VOID NvGpuCreateGraphs(
VOID
)
{
GpuGraphHandle = CreateWindow(
PH_GRAPH_CLASSNAME,
NULL,
WS_VISIBLE | WS_CHILD | WS_BORDER,
0,
0,
3,
3,
WindowHandle,
NULL,
NULL,
NULL
);
Graph_SetTooltip(GpuGraphHandle, TRUE);
MemGraphHandle = CreateWindow(
PH_GRAPH_CLASSNAME,
NULL,
WS_VISIBLE | WS_CHILD | WS_BORDER,
0,
0,
3,
3,
WindowHandle,
NULL,
NULL,
NULL
);
Graph_SetTooltip(MemGraphHandle, TRUE);
SharedGraphHandle = CreateWindow(
PH_GRAPH_CLASSNAME,
NULL,
WS_VISIBLE | WS_CHILD | WS_BORDER,
0,
0,
3,
3,
WindowHandle,
NULL,
NULL,
NULL
);
Graph_SetTooltip(SharedGraphHandle, TRUE);
BusGraphHandle = CreateWindow(
PH_GRAPH_CLASSNAME,
NULL,
WS_VISIBLE | WS_CHILD | WS_BORDER,
0,
0,
3,
3,
WindowHandle,
NULL,
NULL,
NULL
);
Graph_SetTooltip(BusGraphHandle, TRUE);
}
VOID NvGpuLayoutGraphs(
VOID
)
{
RECT clientRect;
RECT labelRect;
ULONG graphWidth;
ULONG graphHeight;
HDWP deferHandle;
ULONG y;
PhLayoutManagerLayout(&LayoutManager);
GetClientRect(WindowHandle, &clientRect);
GetClientRect(GpuLabelHandle, &labelRect);
graphWidth = clientRect.right - GpuGraphMargin.left - GpuGraphMargin.right;
graphHeight = (clientRect.bottom - GpuGraphMargin.top - GpuGraphMargin.bottom - labelRect.bottom * 4 - ET_GPU_PADDING * 5) / 4;
deferHandle = BeginDeferWindowPos(8);
y = GpuGraphMargin.top;
deferHandle = DeferWindowPos(
deferHandle,
GpuLabelHandle,
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,
MemLabelHandle,
NULL,
GpuGraphMargin.left,
y,
0,
0,
SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER
);
y += labelRect.bottom + ET_GPU_PADDING;
deferHandle = DeferWindowPos(
deferHandle,
MemGraphHandle,
NULL,
GpuGraphMargin.left,
y,
graphWidth,
graphHeight,
SWP_NOACTIVATE | SWP_NOZORDER
);
y += graphHeight + ET_GPU_PADDING;
deferHandle = DeferWindowPos(
deferHandle,
SharedLabelHandle,
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,
graphHeight,
SWP_NOACTIVATE | SWP_NOZORDER
);
y += graphHeight + ET_GPU_PADDING;
deferHandle = DeferWindowPos(
deferHandle,
BusLabelHandle,
NULL,
GpuGraphMargin.left,
y,
0,
0,
SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER
);
y += labelRect.bottom + ET_GPU_PADDING;
deferHandle = DeferWindowPos(
deferHandle,
BusGraphHandle,
NULL,
GpuGraphMargin.left,
y,
graphWidth,
clientRect.bottom - GpuGraphMargin.bottom - y,
SWP_NOACTIVATE | SWP_NOZORDER
);
EndDeferWindowPos(deferHandle);
}
VOID NvGpuNotifyUsageGraph(
_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;
Section->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), 0);
PhGraphStateGetDrawInfo(&GpuGraphState, getDrawInfo, GpuUtilizationHistory.Count);
if (PhGetIntegerSetting(L"GraphShowText"))
{
HDC hdc = Graph_GetBufferedContext(GpuGraphHandle);
PhMoveReference(&GpuGraphState.Text,
PhFormatString(L"%.0f%%", GpuCurrentGpuUsage * 100)
);
SelectObject(hdc, PhApplicationFont);
PhSetGraphText(hdc, drawInfo, &GpuGraphState.Text->sr,
&NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT);
}
else
{
drawInfo->Text.Buffer = NULL;
}
if (!GpuGraphState.Valid)
{
PhCopyCircularBuffer_FLOAT(&GpuUtilizationHistory, 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 gpuUsageValue;
gpuUsageValue = PhGetItemCircularBuffer_FLOAT(&GpuUtilizationHistory, getTooltipText->Index);
PhMoveReference(&GpuGraphState.TooltipText, PhFormatString(
L"%.0f%%\n%s",
gpuUsageValue * 100,
((PPH_STRING)PhAutoDereferenceObject(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
));
}
getTooltipText->Text = GpuGraphState.TooltipText->sr;
}
}
break;
}
}
VOID NvGpuNotifyMemoryGraph(
_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;
Section->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorPhysical"), 0);
PhGraphStateGetDrawInfo(&MemGraphState, getDrawInfo, GpuMemoryHistory.Count);
if (PhGetIntegerSetting(L"GraphShowText"))
{
HDC hdc = Graph_GetBufferedContext(MemGraphHandle);
PhMoveReference(&MemGraphState.Text, PhFormatString(
L"%s / %s (%.2f%%)",
PhaFormatSize(UInt32x32To64(GpuCurrentMemUsage, 1024), -1)->Buffer,
PhaFormatSize(UInt32x32To64(GpuMemoryLimit, 1024), -1)->Buffer,
(FLOAT)GpuCurrentMemUsage / GpuMemoryLimit * 100
));
SelectObject(hdc, PhApplicationFont);
PhSetGraphText(hdc, drawInfo, &MemGraphState.Text->sr,
&NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT);
}
else
{
drawInfo->Text.Buffer = NULL;
}
if (!MemGraphState.Valid)
{
for (ULONG i = 0; i < drawInfo->LineDataCount; i++)
{
MemGraphState.Data1[i] = (FLOAT)PhGetItemCircularBuffer_ULONG(&GpuMemoryHistory, i);
}
if (GpuMemoryLimit != 0)
{
// Scale the data.
PhDivideSinglesBySingle(
MemGraphState.Data1,
(FLOAT)GpuMemoryLimit,
drawInfo->LineDataCount
);
}
MemGraphState.Valid = TRUE;
}
}
break;
case GCN_GETTOOLTIPTEXT:
{
PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header;
if (getTooltipText->Index < getTooltipText->TotalCount)
{
if (MemGraphState.TooltipIndex != getTooltipText->Index)
{
ULONG usedPages;
usedPages = PhGetItemCircularBuffer_ULONG(&GpuMemoryHistory, getTooltipText->Index);
PhMoveReference(&MemGraphState.TooltipText, PhFormatString(
L"%s / %s (%.2f%%)\n%s",
PhaFormatSize(UInt32x32To64(usedPages, 1024), -1)->Buffer,
PhaFormatSize(UInt32x32To64(GpuMemoryLimit, 1024), -1)->Buffer,
(FLOAT)usedPages / GpuMemoryLimit * 100,
((PPH_STRING)PhAutoDereferenceObject(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
));
}
getTooltipText->Text = MemGraphState.TooltipText->sr;
}
}
break;
}
}
VOID NvGpuNotifySharedGraph(
_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;
Section->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), 0);
PhGraphStateGetDrawInfo(&SharedGraphState, getDrawInfo, GpuBoardHistory.Count);
if (PhGetIntegerSetting(L"GraphShowText"))
{
HDC hdc = Graph_GetBufferedContext(SharedGraphHandle);
PhMoveReference(&SharedGraphState.Text, PhFormatString(
L"%.0f%%",
(FLOAT)GpuCurrentCoreUsage * 100
));
SelectObject(hdc, PhApplicationFont);
PhSetGraphText(hdc, drawInfo, &SharedGraphState.Text->sr,
&NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT);
}
else
{
drawInfo->Text.Buffer = NULL;
}
if (!SharedGraphState.Valid)
{
PhCopyCircularBuffer_FLOAT(&GpuBoardHistory, SharedGraphState.Data1, 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)
{
FLOAT usedPages;
usedPages = PhGetItemCircularBuffer_FLOAT(&GpuBoardHistory, getTooltipText->Index);
PhMoveReference(&SharedGraphState.TooltipText, PhFormatString(
L"%.0f%%\n%s",
usedPages * 100,
((PPH_STRING)PhAutoDereferenceObject(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
));
}
getTooltipText->Text = SharedGraphState.TooltipText->sr;
}
}
break;
}
}
VOID NvGpuNotifyBusGraph(
_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;
Section->Parameters->ColorSetupFunction(drawInfo, PhGetIntegerSetting(L"ColorCpuKernel"), 0);
PhGraphStateGetDrawInfo(&BusGraphState, getDrawInfo, GpuBusHistory.Count);
if (PhGetIntegerSetting(L"GraphShowText"))
{
HDC hdc = Graph_GetBufferedContext(BusGraphHandle);
PhMoveReference(&BusGraphState.Text, PhFormatString(
L"%.0f%%",
(FLOAT)GpuCurrentBusUsage * 100
));
SelectObject(hdc, PhApplicationFont);
PhSetGraphText(hdc, drawInfo, &BusGraphState.Text->sr,
&NormalGraphTextMargin, &NormalGraphTextPadding, PH_ALIGN_TOP | PH_ALIGN_LEFT);
}
else
{
drawInfo->Text.Buffer = NULL;
}
if (!BusGraphState.Valid)
{
PhCopyCircularBuffer_FLOAT(&GpuBusHistory, BusGraphState.Data1, drawInfo->LineDataCount);
BusGraphState.Valid = TRUE;
}
}
break;
case GCN_GETTOOLTIPTEXT:
{
PPH_GRAPH_GETTOOLTIPTEXT getTooltipText = (PPH_GRAPH_GETTOOLTIPTEXT)Header;
if (getTooltipText->Index < getTooltipText->TotalCount)
{
if (BusGraphState.TooltipIndex != getTooltipText->Index)
{
FLOAT busUsage;
busUsage = PhGetItemCircularBuffer_FLOAT(&GpuBusHistory, getTooltipText->Index);
PhMoveReference(&BusGraphState.TooltipText, PhFormatString(
L"%.0f%%\n%s",
busUsage * 100,
((PPH_STRING)PhAutoDereferenceObject(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
));
}
getTooltipText->Text = BusGraphState.TooltipText->sr;
}
}
break;
}
}
VOID NvGpuUpdateGraphs(
VOID
)
{
GpuGraphState.Valid = FALSE;
GpuGraphState.TooltipIndex = -1;
Graph_MoveGrid(GpuGraphHandle, 1);
Graph_Draw(GpuGraphHandle);
Graph_UpdateTooltip(GpuGraphHandle);
InvalidateRect(GpuGraphHandle, NULL, FALSE);
MemGraphState.Valid = FALSE;
MemGraphState.TooltipIndex = -1;
Graph_MoveGrid(MemGraphHandle, 1);
Graph_Draw(MemGraphHandle);
Graph_UpdateTooltip(MemGraphHandle);
InvalidateRect(MemGraphHandle, NULL, FALSE);
SharedGraphState.Valid = FALSE;
SharedGraphState.TooltipIndex = -1;
Graph_MoveGrid(SharedGraphHandle, 1);
Graph_Draw(SharedGraphHandle);
Graph_UpdateTooltip(SharedGraphHandle);
InvalidateRect(SharedGraphHandle, NULL, FALSE);
BusGraphState.Valid = FALSE;
BusGraphState.TooltipIndex = -1;
Graph_MoveGrid(BusGraphHandle, 1);
Graph_Draw(BusGraphHandle);
Graph_UpdateTooltip(BusGraphHandle);
InvalidateRect(BusGraphHandle, NULL, FALSE);
}
VOID NvGpuUpdatePanel(
VOID
)
{
SetDlgItemText(GpuPanel, IDC_CLOCK_CORE, PhaFormatString(L"%lu MHz", GpuCurrentCoreClock)->Buffer);
SetDlgItemText(GpuPanel, IDC_CLOCK_MEMORY, PhaFormatString(L"%lu MHz", GpuCurrentMemoryClock)->Buffer);
SetDlgItemText(GpuPanel, IDC_CLOCK_SHADER, PhaFormatString(L"%lu MHz", GpuCurrentShaderClock)->Buffer);
SetDlgItemText(GpuPanel, IDC_FAN_PERCENT, ((PPH_STRING)PhAutoDereferenceObject(NvGpuQueryFanSpeed()))->Buffer);
if (PhGetIntegerSetting(SETTING_NAME_ENABLE_FAHRENHEIT))
{
FLOAT fahrenheit = (FLOAT)(GpuCurrentCoreTemp * 1.8 + 32);
SetDlgItemText(GpuPanel, IDC_TEMP_VALUE, PhaFormatString(L"%.1f\u00b0F", fahrenheit)->Buffer);
}
else
{
SetDlgItemText(GpuPanel, IDC_TEMP_VALUE, PhaFormatString(L"%lu\u00b0C", GpuCurrentCoreTemp)->Buffer);
}
//SetDlgItemText(GpuPanel, IDC_TEMP_VALUE, PhaFormatString(L"%s\u00b0C", PhaFormatUInt64(GpuCurrentBoardTemp, TRUE)->Buffer)->Buffer);
SetDlgItemText(GpuPanel, IDC_VOLTAGE, PhaFormatString(L"%lu mV", GpuCurrentVoltage)->Buffer);
}
static INT_PTR CALLBACK NvGpuDialogProc(
_In_ HWND hwndDlg,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
//PhDeleteLayoutManager(&LayoutManager);
//PhDeleteGraphState(&GpuGraphState);
//PhDeleteGraphState(&MemGraphState);
//PhDeleteGraphState(&SharedGraphState);
//PhDeleteGraphState(&BusGraphState);
//if (GpuGraphHandle)
// DestroyWindow(GpuGraphHandle);
//if (MemGraphHandle)
// DestroyWindow(MemGraphHandle);
//if (SharedGraphHandle)
// DestroyWindow(SharedGraphHandle);
//if (BusGraphHandle)
// DestroyWindow(BusGraphHandle);
//if (GpuPanel)
// DestroyWindow(GpuPanel);
switch (uMsg)
{
case WM_INITDIALOG:
{
PPH_LAYOUT_ITEM graphItem;
PPH_LAYOUT_ITEM panelItem;
WindowHandle = hwndDlg;
GpuLabelHandle = GetDlgItem(hwndDlg, IDC_GPU_L);
MemLabelHandle = GetDlgItem(hwndDlg, IDC_MEMORY_L);
SharedLabelHandle = GetDlgItem(hwndDlg, IDC_SHARED_L);
BusLabelHandle = GetDlgItem(hwndDlg, IDC_BUS_L);
PhInitializeGraphState(&GpuGraphState);
PhInitializeGraphState(&MemGraphState);
PhInitializeGraphState(&SharedGraphState);
PhInitializeGraphState(&BusGraphState);
PhInitializeLayoutManager(&LayoutManager, hwndDlg);
PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_GPUNAME), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT | PH_LAYOUT_FORCE_INVALIDATE);
graphItem = PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_GRAPH_LAYOUT), NULL, PH_ANCHOR_ALL);
GpuGraphMargin = graphItem->Margin;
panelItem = PhAddLayoutItem(&LayoutManager, GetDlgItem(hwndDlg, IDC_LAYOUT), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
SendMessage(GetDlgItem(hwndDlg, IDC_TITLE), WM_SETFONT, (WPARAM)Section->Parameters->LargeFont, FALSE);
SendMessage(GetDlgItem(hwndDlg, IDC_GPUNAME), WM_SETFONT, (WPARAM)Section->Parameters->MediumFont, FALSE);
SetDlgItemText(hwndDlg, IDC_GPUNAME, GpuName->Buffer);
GpuPanel = CreateDialog(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_GPU_PANEL), hwndDlg, NvGpuPanelDialogProc);
ShowWindow(GpuPanel, SW_SHOW);
PhAddLayoutItemEx(&LayoutManager, GpuPanel, NULL, PH_ANCHOR_LEFT | PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM, panelItem->Margin);
NvGpuCreateGraphs();
NvGpuUpdate();
NvGpuUpdateGraphs();
NvGpuUpdatePanel();
}
break;
case WM_SIZE:
NvGpuLayoutGraphs();
break;
case WM_NOTIFY:
{
NMHDR* header = (NMHDR*)lParam;
if (header->hwndFrom == GpuGraphHandle)
{
NvGpuNotifyUsageGraph(header);
}
else if (header->hwndFrom == MemGraphHandle)
{
NvGpuNotifyMemoryGraph(header);
}
else if (header->hwndFrom == SharedGraphHandle)
{
NvGpuNotifySharedGraph(header);
}
else if (header->hwndFrom == BusGraphHandle)
{
NvGpuNotifyBusGraph(header);
}
}
break;
case UPDATE_MSG:
{
NvGpuUpdateGraphs();
NvGpuUpdatePanel();
}
break;
}
return FALSE;
}
static BOOLEAN NvGpuSectionCallback(
_In_ PPH_SYSINFO_SECTION Section,
_In_ PH_SYSINFO_SECTION_MESSAGE Message,
_In_opt_ PVOID Parameter1,
_In_opt_ PVOID Parameter2
)
{
switch (Message)
{
case SysInfoCreate:
return TRUE;
case SysInfoDestroy:
return TRUE;
case SysInfoTick:
{
if (WindowHandle)
PostMessage(WindowHandle, UPDATE_MSG, 0, 0);
if (DetailsHandle)
PostMessage(DetailsHandle, UPDATE_MSG, 0, 0);
}
return TRUE;
case SysInfoCreateDialog:
{
PPH_SYSINFO_CREATE_DIALOG createDialog = (PPH_SYSINFO_CREATE_DIALOG)Parameter1;
createDialog->Instance = PluginInstance->DllBase;
createDialog->Template = MAKEINTRESOURCE(IDD_GPU_DIALOG);
createDialog->DialogProc = NvGpuDialogProc;
//createDialog->Parameter = context;
}
return TRUE;
case SysInfoGraphGetDrawInfo:
{
PPH_GRAPH_DRAW_INFO drawInfo = (PPH_GRAPH_DRAW_INFO)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, GpuUtilizationHistory.Count);
if (!Section->GraphState.Valid)
{
PhCopyCircularBuffer_FLOAT(&GpuUtilizationHistory, Section->GraphState.Data1, drawInfo->LineDataCount);
Section->GraphState.Valid = TRUE;
}
}
return TRUE;
case SysInfoGraphGetTooltipText:
{
FLOAT gpuUsageValue;
PPH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT getTooltipText = (PPH_SYSINFO_GRAPH_GET_TOOLTIP_TEXT)Parameter1;
gpuUsageValue = PhGetItemCircularBuffer_FLOAT(&GpuUtilizationHistory, getTooltipText->Index);
PhMoveReference(&Section->GraphState.TooltipText, PhFormatString(
L"%.0f%%\n%s",
gpuUsageValue * 100,
((PPH_STRING)PhAutoDereferenceObject(PhGetStatisticsTimeString(NULL, getTooltipText->Index)))->Buffer
));
getTooltipText->Text = Section->GraphState.TooltipText->sr;
}
return TRUE;
case SysInfoGraphDrawPanel:
{
PPH_SYSINFO_DRAW_PANEL drawPanel = (PPH_SYSINFO_DRAW_PANEL)Parameter1;
drawPanel->Title = PhCreateString(Section->Name.Buffer);
drawPanel->SubTitle = PhFormatString(
L"%.0f%%",
GpuCurrentGpuUsage * 100
);
}
return TRUE;
}
return FALSE;
}
VOID NvGpuSysInfoInitializing(
_In_ PPH_PLUGIN_SYSINFO_POINTERS Pointers
)
{
PH_SYSINFO_SECTION section;
if (!PhGetIntegerSetting(SETTING_NAME_ENABLE_GPU))
return;
if (!NvApiInitialized)
return;
memset(&section, 0, sizeof(PH_SYSINFO_SECTION));
section.Callback = NvGpuSectionCallback;
GpuName = NvGpuQueryName();
PhInitializeStringRef(&section.Name, GpuName->Buffer);
Section = Pointers->CreateSection(&section);
}
#endif

Some files were not shown because too many files have changed in this diff Show More