diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 000000000000..8926f7673208
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,7 @@
+root=true
+
+[*]
+indent_style=space
+indent_size=4
+trim_trailing_whitespace=true
+insert_final_newline=true
diff --git a/.gitattributes b/.gitattributes
index 31335b861e1d..8c535f62e19d 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,4 +1,4 @@
-# Auto detect text files and perform LF normalization
+# Auto detect text files
* text=crlf
# Custom for Visual Studio
@@ -9,6 +9,22 @@
*.fsproj merge=union
*.dbproj merge=union
+# Project files
+*.bat eol=crlf
+*.c eol=crlf
+*.cs eol=crlf
+*.config eol=crlf
+*.cmd eol=crlf
+*.csproj eol=crlf
+*.def eol=crlf
+*.h eol=crlf
+*.manifest eol=crlf
+*.resx eol=crlf
+*.rc eol=crlf
+*.sln eol=crlf
+*.txt eol=crlf
+*.vcxproj eol=crlf
+
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
diff --git a/.gitignore b/.gitignore
index f29e5c0572b9..346a563a6704 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,25 +2,24 @@
## Visual Studio
#################
-## Ignore Visual Studio temporary files, build results, and
-## files generated by popular Visual Studio add-ons.
-
# User-specific files
*.suo
*.user
-*.sln.docstates
*.key
# Build results
-*_i.c
-*_p.c
+*.appx
+*.appxbundle
+*.cer
*.ilk
*.meta
*.obj
*.pch
*.pdb
+*.pfx
*.pgc
*.pgd
+*.pvk
*.rsp
*.sbr
*.tlb
@@ -28,11 +27,10 @@
*.tlh
*.tmp
*.vspscc
-.builds
-*.dotCover
+*_i.c
+*_p.c
# Visual C++ cache files
-ipch/
*.aps
*.ncb
*.opendb
@@ -40,6 +38,9 @@ ipch/
*.sdf
*.db
*.dll
+
+# Visual C++ cache folders
+ipch/
.vs/
# Visual Studio profiler
@@ -49,68 +50,40 @@ ipch/
# ReSharper is a .NET coding add-in
_ReSharper*
-# Installshield output folder
-[Ee]xpress
-
-# DocProject is a documentation generator add-in
-DocProject/buildhelp/
-DocProject/Help/*.HxT
-DocProject/Help/*.HxC
-DocProject/Help/*.hhc
-DocProject/Help/*.hhk
-DocProject/Help/*.hhp
-DocProject/Help/Html2
-DocProject/Help/html
-
# Click-Once directory
publish
# Others
[Bb]in
[Oo]bj
-sql
-TestResults
*.Cache
-ClientBin
-stylecop.*
~$*
-*.dbmdl
-Generated_Code #added for RIA/Silverlight projects
-# Backup & report files from converting an old project file to a newer
-# Visual Studio version. Backup files are not needed, because we have git ;-)
+# Backup & report files
_UpgradeReport_Files/
#Backup*/
UpgradeLog*.XML
-############
-## Windows
-############
-
# Windows image file caches
Thumbs.db
# Folder config file
Desktop.ini
-# Mac crap
-.DS_Store
-
##########################
## Project specific rules
##########################
-build/installer/*.exe
-ProcessHacker/include/phapprev.h
-ProcessHacker/sdk/phapppub.h
+build/output/
plugins-extra/
-/sdk/
+sdk/
-KProcessHacker/*.log
-KProcessHacker/*.err
-KProcessHacker/*.wrn
-KProcessHacker/*/objchk_*
-KProcessHacker/*/objfre_*
+!KProcessHacker/bin/
+KProcessHacker/bin/Debug32/
+KProcessHacker/bin/Debug64/
+KProcessHacker/bin/Release32/
+KProcessHacker/bin/Release64/
+KProcessHacker/bin/*
!plugins/SamplePlugin/bin/
plugins/SamplePlugin/bin/Debug32/
@@ -121,6 +94,13 @@ plugins/SamplePlugin/bin/Release64/*
!plugins/SamplePlugin/bin/Release64/SamplePlugin.dll
plugins/OnlineChecks/virustotal.h
+!tools/CustomBuildTool/bin/
+tools/CustomBuildTool/bin/Debug*/
+tools/CustomBuildTool/bin/Release*/*
+!tools/CustomBuildTool/bin/Release/CustomBuildTool.exe
+!tools/CustomBuildTool/bin/Release/CustomBuildTool.exe.config
+!tools/CustomBuildTool/bin/Release/CustomBuildTool.pdb
+
!tools/CustomSignTool/bin/
tools/CustomSignTool/bin/Debug*/
tools/CustomSignTool/bin/Release*/*
@@ -136,3 +116,5 @@ tools/fixlib/bin/Release/*
tools/GenerateZw/GenerateZw/bin/Debug/
tools/GenerateZw/GenerateZw/bin/Release/*
!tools/GenerateZw/GenerateZw/bin/Release/GenerateZw.exe
+
+!tools/delaylib/bin/
diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 6860af3f2ae8..a2a8cbddb6e7 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -1,661 +1,668 @@
-Process Hacker
-
-3.0
- * HIGHLIGHTS:
- * OTHER CHANGES:
- * NOTE:
- * Support for Windows XP and Vista has been dropped. For those platforms, use Process Hacker 2.38.
- * This release has significant internal code changes. Please make sure all plugins are up-to-date.
-
-2.39
- * HIGHLIGHTS:
- * Improved compatibility with security and anti-cheat software
- * Added ability to edit process environment variables
- * Fixed .NET process detection
- * OTHER CHANGES:
- * Improved tooltip information for dllhost.exe
- * Removed Terminator
- * Updated DotNetTools plugin:
- * 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
- * Updated ExtendedTools plugin:
- * Fixed "No process" disk event bug
- * Updated HardwareDevices plugin:
- * Fixed incorrect drive letters
- * Fixed drive letter and panel clipping issue
-
-2.38
- * HIGHLIGHTS:
- * Added labels to indicate the maximum data point in each I/O graph
- * Graph grids now scale correctly when resized
- * Improved high DPI scaling
- * Added exploit mitigation policy information to process properties (Windows 8 and above)
- * Added File modified time and File size columns for processes and modules
- * Added Key modified time column for services
- * Clicking a tray icon now shows the pop-up UI (useful for touch-enabled devices)
- * The NetAdapters plugin has been renamed to HardwareDevices
- * This plugin shows network adapter and disk drive graphs
- * If you are manually upgrading, please delete NetAdapters.dll from the plugins folder
- * Updated UserNotes plugin:
- * Added "Collapse by default" option for processes
- * OTHER CHANGES:
- * Added "Start when I log on" option
- * Added "Not responding" text to tray icon rich pop-up for programs that are hung
- * Added right-click menu and double-click action for environment variables
- * Added dialog box to show long command line strings
- * Added Time stamp column for processes
- * Added -sysinfo command line parameter for opening System Information at startup
- * Added 32x32 icons for high DPI displays
- * Digital signature verification is now performed with very low I/O priority
- * Improved performance when handling a large number of threads, modules or handles
- * The pop-up UI no longer displays when double-clicking the tray icon
- * Fixed ASLR state being shown as N/A in process properties
- * Fixed multi monitor window placement bug
- * Fixed handle enumeration bug affecting processes with PID >= 65536
- * Fixed Interrupts being missing from the max CPU usage history
- * Updated ToolStatus plugin:
- * Added 32x32 icons for high DPI displays
- * Fixed status bar crash
- * NOTE:
- * This release has significant internal code changes. Please make sure all plugins are up-to-date.
-
-2.37
- * HIGHLIGHTS:
- * Updated for Windows 10
- * The "Include CPU (and other) usage of children in collapsed processes" option now aggregates memory and I/O statistics
- * Added regex search to "Find Handles or DLLs"
- * Added process exit codes to log
- * Fixed crash that occurred under some conditions when processes terminated
- * OTHER CHANGES:
- * Added warning when trying to search for handles when the system has too many handles open
- * Upgraded to PCRE2
- * Updated DotNetTools plugin:
- * Rewrite of .NET Performance statistics and AppDomain enumeration
- * Updated OnlineChecks plugin:
- * Fixed virusscan.jotti.org uploader
- * Updated NetAdapters plugin:
- * Added adapter details window
- * Updated ToolStatus plugin:
- * Added CPU, Memory and I/O graphs to the toolbar (not enabled by default)
- * Added toolbar and status bar customization, as well as a new theme
- * Added option to auto-hide the main menu
- * Updated UserNotes plugin:
- * Added individual process highlighting support
-
-2.36
- * HIGHLIGHTS:
- * New rich pop-up UI when hovering the cursor over a tray icon, showing the most active processes
- * Completely new Memory tab for processes, with heap, stack and working set usage
- * Process Hacker now takes 32-bit dumps of 32-bit processes on 64-bit Windows
- * NOTE: When using the portable (.zip) release, the entire archive must be extracted
- * Updated DotNetTools plugin:
- * 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
- * OTHER CHANGES:
- * Added customizable bytes per row setting for memory editor
- * Dramatically faster handle listing and search when running without administrative privileges
- * Improved accuracy and speed of symbol resolution, especially when new modules are loaded
- * Added trigger and delayed start information to service list
- * Added file information to service list tooltips
- * Balloon tips for process/service notifications are now clickable
- * Added handle names for unnamed File objects
- * Added I/O Priority to tray icon process menu
- * Added warning for users who attempt to start the 32-bit version on 64-bit Windows
- * Updated ExtendedServices plugin:
- * Added service protection and SID information
- * Added auto-elevation when saving recovery information, triggers and other service settings
- * Updated ExtendedTools plugin:
- * Added tray icon mini info window support
- * Improved automatic GPU node selection
- * Updated UserNotes plugin:
- * Added tray icon mini info window support
- * Fixed a bug in phsvc that caused hangs when automatically elevating actions
- * Fixed hang when viewing handle security for certain File objects
- * Fixed lack of information on startup when using slower refresh intervals
- * Fixed Read/Write Address crash
- * Fixed service non-polling mode on Windows 8 and above
- * Fixed file dialog crash in Windows PE environments
- * Fixed string scanning false positive case
- * Fixed process window detection for Modern UI apps
- * Fixed handle list selection bug when disabling "Hide unnamed handles"
- * NOTE:
- * This release has significant internal code changes. Please make sure all plugins are up-to-date.
-
-2.35
- * NEW/IMPROVED:
- * Added Load Time and Load Reason columns for modules (Windows 8 and above)
- * Added handle names for Job and Section objects
- * Added Read/Write Memory for Section objects (in process Handles tab)
- * Added CF Guard (Control Flow Guard) column for processes and modules
- * Added highlighting for AppContainer DLLs
- * Added AppContainer and CF Guard image characteristics to peview
- * Added Open Key and Open File Location menu items for services
- * Set priority and I/O priority for multiple processes at once
- * Support for up to 64 processors when setting process/thread affinity
- * Updated ExtendedTools plugin:
- * Added Disk and Network graphs for all processes
- * Updated UserNotes plugin:
- * Added ability to save I/O priority
- * FIXED:
- * Fixed memory editor copy bug
-
-2.34
- * NEW/IMPROVED:
- * Proper Unicode support
- * CPU and GPU graphs are displayed in a grid now (thanks pavel_kv!)
- * Start Task Manager now elevates when necessary
- * Better names for memory regions in Memory tab (for PEBs, TEBs, thread stacks)
- * Added tooltip information for user-mode driver framework (UMDF) host processes
- * Added option to reduce row height (set ThinRows to 1 in settings.xml)
- * Added NetAdapters plugin: adds graphs for selected network adapters to the System Information window
- * Updated ExtendedTools plugin:
- * Added GPU graphs for all processes
- * Can now use the search box in the Disk tab
- * Improved kernel logger handling
- * FIXED:
- * Fixed touch scrolling
- * Fixed EtwRegistration object names for 64-bit Windows 8.1
- * Fixed tray icons being clipped in high DPI environments
- * Fixed crash in memory editor
- * Fixed multi monitor window placement bug
-
-2.33
- * NEW/IMPROVED:
- * View digital signature information from process properties and peview
- * Signatures for Windows 8 apps are now detected
- * Improved file, key, process and thread handle properties
- * Added DPI Awareness column
- * Added new Windows 8.1 process protection information
- * KProcessHacker is no longer needed for highlighting of GUI threads
- * Added suspend count for threads on Windows 8.1
- * Updated DotNetTools plugin:
- * Improved .NET assembly enumeration timeout handling
- * FIXED:
- * Service start type and error control are never updated if modified outside of Process Hacker
-
-2.32
- * NOTE:
- * All executable files are now signed.
- * NEW/IMPROVED:
- * Updated for Windows 8.1
- * Added progress display for thread stacks
- * Updated ExtendedServices plugin:
- * Added new trigger data types
- * Updated NetworkTools plugin:
- * Updated UI
- * Updated OnlineChecks plugin:
- * Added file analyzed prompt
- * FIXED:
- * Fixed handling of long symbol names
- * Fixed Run As preventing Windows 8 apps from starting
- * Fixed console host information for Windows 8.1
- * Fixed reflected processes not terminating on Windows 8.1
- * Fixed CPU frequency on Windows 8.1
-
-2.31
- * NEW/IMPROVED:
- * Updated ExtendedServices plugin:
- * Fixed some bugs relating to Windows 8
- * Updated OnlineChecks plugin:
- * Added upload progress
- * Updated UserNotes plugin:
- * Fixed bug where process priorities were not actually saved
- * FIXED:
- * Fixed module list not updating properly
- * DLL enumeration crash
-
-2.30
- * NEW/IMPROVED:
- * Added "Icon click toggles visibility" option
- * Re-enabled powerful process termination on 32-bit Windows 8
- * Updated UserNotes plugin:
- * Added ability to save process priority
- * Added "Only for processes with the same command line" option for process comments
- * FIXED:
- * Fixed crash on CPUs without SSE2
-
-2.29
- * NEW/IMPROVED:
- * Added App ID column for processes
- * Added new ASLR information for Windows 8
- * Added Restart to Boot Options and Hybrid Shutdown menu items for Windows 8
- * Added ability to specify processes by their names and inject and unload DLLs in command line
- * Removed 512 character limit when copying text
- * Moved Terminator to Miscellaneous menu
- * Updated default dbghelp.dll path for Windows SDK v8
- * Updated ExtendedServices plugin:
- * Added new triggers for Windows 8
- * Fixed bug when restarting services
- * Updated ExtendedTools plugin:
- * Improved support for multiple GPUs (again)
- * GPU column now respects "Include CPU usage of children" option
- * Updated ToolStatus plugin:
- * Fixed search box fonts
- * Fixed controls not being properly hidden/removed from the window when disabled
- * Updated WindowExplorer plugin:
- * Fixed window list not displaying Modern UI windows
- * FIXED:
- * Fixed Load Count column sorting bug
- * Fixed signature verification on Windows 8
- * Fixed task scheduler information on Windows 8
- * Fixed drag bug in tree list
- * Fixed KProcessHacker bug affecting TmTx objects
- * Fixed Run As feature on Windows 8
- * Fixed bug where -settings parameter is not propagated
- * Fixed tab key behavior on main window
- * Fixed recognition of Modern UI windows
-
-2.28
- * NEW/IMPROVED:
- * peview now resolves .lnk targets
- * Fixed Ctrl+A for processes, services and network connections and added Ctrl+A for other windows
- * Changed confirmation prompts to select the destructive action by default
- * Updated DotNetTools plugin:
- * Fixed inaccurate stack traces for certain .NET programs
- * Updated ExtendedTools plugin:
- * Fixed network graph scaling
- * Updated ToolStatus plugin:
- * Added search box
- * Updated Updater plugin
- * FIXED:
- * Fixed Verification Status column sorting bug in module list
- * Fixed rare System Information crash
- * Fixed bug in opening process handles
- * Fixed freezing when viewing stack traces of certain system threads
-
-2.27
- * NEW/IMPROVED:
- * Updated OnlineChecks plugin:
- * 2012-01-16: Updated VirusTotal uploader and added hash checking
- * FIXED:
- * Fixed Description column sorting bug
- * Fixed notification icon bug
-
-2.26
- * NEW/IMPROVED:
- * Added option to show Commit Charge in system information summary view
- * Added -priority and -selectpid command line options
- * Updated ExtendedTools plugin:
- * Improved support for multiple GPUs
- * FIXED:
- * Fixed 100% CPU when starting on some machines
-
-2.25
- * NEW/IMPROVED:
- * Improved CPU frequency calculation
- * Updated ExtendedTools plugin:
- * Added GPU node selection
- * Fixed incorrect GPU usage calculation
- * FIXED:
- * Graph tooltip position with large cursors
- * Fixed .NET process detection
- * Fixed incorrect values in Bits column
-
-2.24
- * NOTE:
- * This release has significant internal code changes. Please make sure all plugins are up-to-date.
- * NEW/IMPROVED:
- * Completely new system information window
- * Added option to scroll to new processes
- * Added option to hide driver services
- * Added menu item to copy individual cells
- * Improved module scanning
- * Added Start Task Manager menu item
- * Added Image base to peview
- * Updated ExtendedTools plugin:
- * Added support for new system information window
- * Added Disk, Network and GPU tray icons
- * Added support for custom fonts in the Disk tab
- * Updated Updater plugin:
- * Added download speed
- * Added remaining time
- * FIXED:
- * Fixed retrieval of version information for certain files
- * Fixed driver file names on Windows XP
- * Fixed Run As Administrator when used with complex commands
-
-2.23
- * NEW/IMPROVED:
- * Added display of token capabilities, user/device claims and security attributes
- * Added ability to change token integrity levels
- * Added Description column to service list
- * Added option to reset all settings
- * Made grid color darker
- * Enabled multi-selection in the hidden processes window
- * Added UserNotes plugin
- * Updated ExtendedNotifications plugin:
- * Added Growl support
- * Updated ExtendedTools plugin:
- * Added GPU monitoring
- * Added rate columns for disk and network I/O
- * FIXED:
- * Fixed copying lists when plugin columns are enabled
- * Freezing when viewing the tooltip for a process with a very long command line
- * Disabled Hidden Processes feature on 64-bit systems
-
-2.22
- * NEW/IMPROVED:
- * Added highlighting for metro style apps
- * Added Package Name column
- * Added package name to process tooltip
- * Improved .NET process detection
- * Updated OS Context column for Windows 8
- * Updated ExtendedTools plugin:
- * Updated disk monitoring for Windows 8
- * Updated memory list information for Windows 8
- * Updated WindowExplorer plugin:
- * Fixed hook support for low integrity processes
- * FIXED:
- * Fixed memory leaks
- * Fixed bug preventing Interrupts/DPCs from being shown as the max. CPU process on 64-bit systems
- * Fixed DEP Status column on 64-bit systems
-
-2.21
- * NEW/IMPROVED:
- * Added Private Bytes Delta, ASLR and Subsystem columns
- * Added ASLR and Time Stamp columns to modules list
- * Added check for debugger in Terminator
- * FIXED:
- * Fixed Show CPU Below 0.01 not respecting locale
- * Fixed copying from network list
-
-2.20
- * NEW/IMPROVED:
- * Added support for managed thread stacks on x64
- * Added column selection for handle list
- * Added CPU column to threads list
- * Improved module detection
- * Added Ideal Processor to Threads tab
- * Added pool usage and minimum/maximum working set columns
- * Implemented Properties button for Thread handles
- * Set descending sort as the default for most numeric columns
- * Extended header context menu
- * Removed tooltip text truncation
- * Improved cycle-based CPU usage calculation
- * Set default KProcessHacker security level to only allow connections when Process Hacker is running as administrator.
- See README.txt for instructions on how to restore the old behavior.
- * Added Updater plugin
- * Updated DotNetTools plugin:
- * Added managed symbol resolution for thread stacks
- * Updated ExtendedTools plugin:
- * Added Disk tab
- * Added Hard Faults, Hard Faults Delta and Peak Threads columns to process tree list
- * Added Firewall Status column
- * FIXED:
- * Fixed file name resolution bug
- * Save settings on shutdown/logoff
- * Fixed state highlighting bug
- * Fixed command line propagation for -elevate
- * Fixed tree list mouse wheel handling
- * Fixed saving network list
-
-2.19
- * NEW/IMPROVED:
- * Added cycle-based CPU usage for Windows 7
- * Added Show CPU Below 0.01
- * Added OS Context column
- * Rewrote graph drawing code for improved performance
- * Optimized retrieval of cycle time and private working set information for Windows 7
- * Added Open File Location to process context menu and reorganized some items
- * Added checkboxes to Terminator
- * FIXED:
- * Crash when sorting by Time Stamp
- * GDI handle leak in drag selection
-
-2.18
- * NEW/IMPROVED:
- * Completely rewritten tree list control:
- * Process Name column is now fixed to the left
- * Tooltips for column headers
- * Improved performance
- * Bug fixes
- * Added more process tree list columns
- * Added Time stamp column to network list
- * Date/time display is now swapped (so time is shown before date)
- * Added W3 terminator test
- * Added DotNetTools plugin
- * Updated ExtendedServices plugin:
- * Disabled editing of required privileges for drivers
- * Updated ExtendedTools plugin:
- * Added ETW columns for processes and network connections
- * Updated OnlineChecks plugin:
- * Added Comodo Instant Malware Analysis
- * Updated WindowExplorer plugin:
- * Fixed hook bugs
- * FIXED:
- * Fixed Run As This User
- * Verification Status sorting
-
-2.17
- * NEW/IMPROVED:
- * Added support for setting page priority
- * Added elevation support for setting priority
- * Added support for automatically using a settings file in the program directory (e.g. ProcessHacker.exe.settings.xml)
- * Improved Run As mechanism
- * Updated ExtendedServices plugin:
- * Added support for editing triggers
- * Added support for editing preshutdown time-out
- * Added support for editing required privileges
- * Added elevation support for restarting services
- * Updated WindowExplorer plugin:
- * Added more window properties
- * FIXED:
- * Handle leak
-
-2.16
- * NEW/IMPROVED:
- * Updated WindowExplorer plugin
- * PE viewer: Added version string to CLR tab
- * PE viewer: Added display of delay imports
- * PE viewer: Added Load Config tab
- * Improved wait analysis
- * Added arrows to the service list to indicate whether a service is running
- * FIXED:
- * Fixed the IPv6-related workaround causing crashes
- * Incorrect handling of window positions
-
-2.15
- * NEW/IMPROVED:
- * Updated ExtendedServices plugin
- * Updated ToolStatus plugin
- * Added DEP Status column
- * Improved User Name column
- * FIXED:
- * Image file versions
- * Workaround for an IPv6-related bug in Windows XP
- * DPCs and Interrupts in System Information tooltips
- * File dialog crash on Windows XP
- * ExtendedTools plugin: WS Watch refresh bug
-
-2.14
- * NEW/IMPROVED:
- * ExtendedServices plugin: Option to add a Services menu for processes
- * Command line support for setting process priority and I/O priority
- * Improved termination of explorer.exe
- * FIXED:
- * Icon should restore the main window if it is minimized
- * System Information window crashes
- * Hide Processes From Other Users and Hide Signed Processes settings are now saved
- * Font selection on Windows XP
- * ToolStatus plugin: Always on Top status being reset by Find Window
- * Service-related crashes
- * WindowExplorer plugin: sorting in tree list
- * Process minidump creation with old versions of dbghelp.dll
-
-2.13
- * NEW/IMPROVED:
- * Added copy support to PE viewer
- * Added Connect Time, Disconnect Time and Last Input Time to session properties
- * Added more working set counters to the Statistics tab
- * FIXED:
- * Column sort arrows
- * CPU usage calculations
-
-2.12
- * NEW/IMPROVED:
- * Updated KProcessHacker for Windows 7 SP1
- * Added elevation support for more actions
- * Added ability to disable plugins
- * Updated ToolStatus plugin
- * Added Remote Control for sessions
- * More command line options
- * FIXED:
- * Memory leaks
- * Run As issues with different sessions
-
-2.11
- * NEW/IMPROVED:
- * Added WS Watch and other features to ExtendedTools plugin
- * Added WindowExplorer plugin
- * Properties for hidden processes
- * Improved menus
- * Debug console can now be closed without affecting the entire program
- * FIXED:
- * Always on Top issues
- * Hang when setting DEP status of a terminating process
- * Encoding bug in NetworkTools plugin
- * LSA interfacing issues
- * Creating dumps of self
-
-2.10
- * NEW/IMPROVED:
- * KProcessHacker is now signed, so it works on 64-bit systems. Thank you to the ReactOS Foundation.
- * Added Run As Limited User
- * Added CPU, private bytes and I/O history columns
- * Added font selection
- * Slightly improved highlighting configuration
- * FIXED:
- * High DPI support
- * Multi-monitor support in graph tooltips
- * DEP status retrieval
- * ExtendedTools plugin crash
- * Notification icon menu crash
- * Memory leaks
- * Other small bug fixes
-
-2.9
- * NEW/IMPROVED:
- * Added column selection for modules list
- * Added wait analysis for 64-bit systems
- * Added signature verification for modules
- * Added ExtendedTools plugin (Vista and above only) with Disk and Network information
- * Updated ExtendedNotifications plugin: added ability to log events to a file
- * Updated ExtendedServices plugin: new tab on Vista and above
- * Updated ToolStatus plugin: resolves ghost windows to hung windows
- * Environment variables and current directory are now correctly shown for WOW64 processes
- * I/O priority names are now used instead of numbers
- * FIXED:
- * Network list bug
- * Memory leaks
-
-2.8
- * NEW/IMPROVED:
- * Better service list (including column selection)
- * Added Peak Handles
- * Process tree sorting is now preserved
- * Save works for services and network connections
- * Pausing now works correctly with the Network tab
- * Added option to display inclusive CPU usages for collapsed processes
- * Added CLR tab to peview
- * Added ability to destroy heaps
- * Improved process tree list appearance
- * Certain command line parameters are now propagated
- * FIXED:
- * Icon handling bugs
- * Memory leaks
- * Extended tooltips for WOW64 processes
-
-2.7
- * NEW/IMPROVED:
- * Vastly improved startup time and lower memory usage
- * Added Cycles and Cycles Delta columns
- * Added option to disable address resolution for network connections
- * Added Logon Time to session properties
- * Added time stamp display to peview
- * FIXED:
- * ToolStatus layout problems
- * .NET highlighting crashes
- * Run As on Windows XP
-
-2.6
- * NEW/IMPROVED:
- * Sorting for most lists is now much faster
- * Hide Signed Processes option
- * Added plugin for uploading files to online virus scanners
- * Added Network tools plugin
- * Updated ExtendedServices plugin
- * PE viewer now verifies checksums
- * Performance improvements
- * FIXED:
- * Fixed service handle leak
-
-2.5
- * NEW/IMPROVED:
- * Unmap section views in Memory tab
- * Plugin for extended service information (including recovery information, dependencies and dependents)
- * FIXED:
- * Critical bug for file dialogs on Windows XP
- * Esc couldn't close Service Properties on open
- * Small bug fixes
-
-2.4
- * NEW/IMPROVED:
- * Better Run As behaviour
- * Show Processes From All Users option
- * Can now unmap section views
- * Control over thread affinity
- * Window Title and Window Status columns
- * Plugin for filtering notifications
- * Plugin for toolbar and status bar
- * Performance improvements
- * FIXED:
- * Memory leak
- * SbieSupport plugin on 64-bit
- * Crash when running under certain conditions
- * Memory case-insensitive filter
- * Process parent association bug
- * REMOVED:
- * Process database
-
-2.3
- * NEW/IMPROVED:
- * Can add processes to jobs
- * Double-clicking in the system information graphs now opens information for the relevant process
- * Setting I/O priority doesn't need KProcessHacker anymore
- * Elevation for certain actions
- * FIXED:
- * HKCU key name resolution
- * Network connection host resolution
- * Information window resizing
- * Log clearing
-
-2.2
- * NEW/IMPROVED:
- * Plugins support
- * Can now unload 32-bit modules on 64-bit systems
- * Tasks are shown in tooltips for taskeng.exe/taskhost.exe processes
- * Run As can now start processes elevated
- * Handle count by type
- * Process priorities in notification icon menu
- * CSV export
- * Relative start times
- * FIXED:
- * Run and Run As shortcuts
- * Command line handling
- * Process tree selection
-
-2.1
- * NEW/IMPROVED:
- * Add Pause key shortcut to pause/resume updates
- * Added Ctrl+Tab and Ctrl+Shift+Tab shortcuts
- * Grid is a bit darker
- * Checks for digital signatures and packing is now off by default and optional
- * FIXED:
- * MD5 calculation code for files was wrong
- * Process record bugs
-
-2.0
- * First release in the Process Hacker 2.x branch.
+Process Hacker
+
+3.0
+ * HIGHLIGHTS:
+ * New Process Hacker setup.
+ * New process properties handle search.
+ * Added F11 hotkey for fullscreen System Information window.
+ * OTHER CHANGES:
+* Updated Updater plugin:
+ * New design and layout.
+* Updated WindowExplorer plugin:
+ * Added Windows process properties page.
+ * NOTE:
+ * Support for Windows XP and Vista has been dropped. For those platforms, use Process Hacker 2.38.
+ * This release has significant internal code changes. Please make sure all plugins are up-to-date.
+
+2.39
+ * HIGHLIGHTS:
+ * Improved compatibility with security and anti-cheat software
+ * Added ability to edit process environment variables
+ * Fixed .NET process detection
+ * OTHER CHANGES:
+ * Improved tooltip information for dllhost.exe
+ * Removed Terminator
+ * Updated DotNetTools plugin:
+ * 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
+ * Updated ExtendedTools plugin:
+ * Fixed "No process" disk event bug
+ * Updated HardwareDevices plugin:
+ * Fixed incorrect drive letters
+ * Fixed drive letter and panel clipping issue
+
+2.38
+ * HIGHLIGHTS:
+ * Added labels to indicate the maximum data point in each I/O graph
+ * Graph grids now scale correctly when resized
+ * Improved high DPI scaling
+ * Added exploit mitigation policy information to process properties (Windows 8 and above)
+ * Added File modified time and File size columns for processes and modules
+ * Added Key modified time column for services
+ * Clicking a tray icon now shows the pop-up UI (useful for touch-enabled devices)
+ * The NetAdapters plugin has been renamed to HardwareDevices
+ * This plugin shows network adapter and disk drive graphs
+ * If you are manually upgrading, please delete NetAdapters.dll from the plugins folder
+ * Updated UserNotes plugin:
+ * Added "Collapse by default" option for processes
+ * OTHER CHANGES:
+ * Added "Start when I log on" option
+ * Added "Not responding" text to tray icon rich pop-up for programs that are hung
+ * Added right-click menu and double-click action for environment variables
+ * Added dialog box to show long command line strings
+ * Added Time stamp column for processes
+ * Added -sysinfo command line parameter for opening System Information at startup
+ * Added 32x32 icons for high DPI displays
+ * Digital signature verification is now performed with very low I/O priority
+ * Improved performance when handling a large number of threads, modules or handles
+ * The pop-up UI no longer displays when double-clicking the tray icon
+ * Fixed ASLR state being shown as N/A in process properties
+ * Fixed multi monitor window placement bug
+ * Fixed handle enumeration bug affecting processes with PID >= 65536
+ * Fixed Interrupts being missing from the max CPU usage history
+ * Updated ToolStatus plugin:
+ * Added 32x32 icons for high DPI displays
+ * Fixed status bar crash
+ * NOTE:
+ * This release has significant internal code changes. Please make sure all plugins are up-to-date.
+
+2.37
+ * HIGHLIGHTS:
+ * Updated for Windows 10
+ * The "Include CPU (and other) usage of children in collapsed processes" option now aggregates memory and I/O statistics
+ * Added regex search to "Find Handles or DLLs"
+ * Added process exit codes to log
+ * Fixed crash that occurred under some conditions when processes terminated
+ * OTHER CHANGES:
+ * Added warning when trying to search for handles when the system has too many handles open
+ * Upgraded to PCRE2
+ * Updated DotNetTools plugin:
+ * Rewrite of .NET Performance statistics and AppDomain enumeration
+ * Updated OnlineChecks plugin:
+ * Fixed virusscan.jotti.org uploader
+ * Updated NetAdapters plugin:
+ * Added adapter details window
+ * Updated ToolStatus plugin:
+ * Added CPU, Memory and I/O graphs to the toolbar (not enabled by default)
+ * Added toolbar and status bar customization, as well as a new theme
+ * Added option to auto-hide the main menu
+ * Updated UserNotes plugin:
+ * Added individual process highlighting support
+
+2.36
+ * HIGHLIGHTS:
+ * New rich pop-up UI when hovering the cursor over a tray icon, showing the most active processes
+ * Completely new Memory tab for processes, with heap, stack and working set usage
+ * Process Hacker now takes 32-bit dumps of 32-bit processes on 64-bit Windows
+ * NOTE: When using the portable (.zip) release, the entire archive must be extracted
+ * Updated DotNetTools plugin:
+ * 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
+ * OTHER CHANGES:
+ * Added customizable bytes per row setting for memory editor
+ * Dramatically faster handle listing and search when running without administrative privileges
+ * Improved accuracy and speed of symbol resolution, especially when new modules are loaded
+ * Added trigger and delayed start information to service list
+ * Added file information to service list tooltips
+ * Balloon tips for process/service notifications are now clickable
+ * Added handle names for unnamed File objects
+ * Added I/O Priority to tray icon process menu
+ * Added warning for users who attempt to start the 32-bit version on 64-bit Windows
+ * Updated ExtendedServices plugin:
+ * Added service protection and SID information
+ * Added auto-elevation when saving recovery information, triggers and other service settings
+ * Updated ExtendedTools plugin:
+ * Added tray icon mini info window support
+ * Improved automatic GPU node selection
+ * Updated UserNotes plugin:
+ * Added tray icon mini info window support
+ * Fixed a bug in phsvc that caused hangs when automatically elevating actions
+ * Fixed hang when viewing handle security for certain File objects
+ * Fixed lack of information on startup when using slower refresh intervals
+ * Fixed Read/Write Address crash
+ * Fixed service non-polling mode on Windows 8 and above
+ * Fixed file dialog crash in Windows PE environments
+ * Fixed string scanning false positive case
+ * Fixed process window detection for Modern UI apps
+ * Fixed handle list selection bug when disabling "Hide unnamed handles"
+ * NOTE:
+ * This release has significant internal code changes. Please make sure all plugins are up-to-date.
+
+2.35
+ * NEW/IMPROVED:
+ * Added Load Time and Load Reason columns for modules (Windows 8 and above)
+ * Added handle names for Job and Section objects
+ * Added Read/Write Memory for Section objects (in process Handles tab)
+ * Added CF Guard (Control Flow Guard) column for processes and modules
+ * Added highlighting for AppContainer DLLs
+ * Added AppContainer and CF Guard image characteristics to peview
+ * Added Open Key and Open File Location menu items for services
+ * Set priority and I/O priority for multiple processes at once
+ * Support for up to 64 processors when setting process/thread affinity
+ * Updated ExtendedTools plugin:
+ * Added Disk and Network graphs for all processes
+ * Updated UserNotes plugin:
+ * Added ability to save I/O priority
+ * FIXED:
+ * Fixed memory editor copy bug
+
+2.34
+ * NEW/IMPROVED:
+ * Proper Unicode support
+ * CPU and GPU graphs are displayed in a grid now (thanks pavel_kv!)
+ * Start Task Manager now elevates when necessary
+ * Better names for memory regions in Memory tab (for PEBs, TEBs, thread stacks)
+ * Added tooltip information for user-mode driver framework (UMDF) host processes
+ * Added option to reduce row height (set ThinRows to 1 in settings.xml)
+ * Added NetAdapters plugin: adds graphs for selected network adapters to the System Information window
+ * Updated ExtendedTools plugin:
+ * Added GPU graphs for all processes
+ * Can now use the search box in the Disk tab
+ * Improved kernel logger handling
+ * FIXED:
+ * Fixed touch scrolling
+ * Fixed EtwRegistration object names for 64-bit Windows 8.1
+ * Fixed tray icons being clipped in high DPI environments
+ * Fixed crash in memory editor
+ * Fixed multi monitor window placement bug
+
+2.33
+ * NEW/IMPROVED:
+ * View digital signature information from process properties and peview
+ * Signatures for Windows 8 apps are now detected
+ * Improved file, key, process and thread handle properties
+ * Added DPI Awareness column
+ * Added new Windows 8.1 process protection information
+ * KProcessHacker is no longer needed for highlighting of GUI threads
+ * Added suspend count for threads on Windows 8.1
+ * Updated DotNetTools plugin:
+ * Improved .NET assembly enumeration timeout handling
+ * FIXED:
+ * Service start type and error control are never updated if modified outside of Process Hacker
+
+2.32
+ * NOTE:
+ * All executable files are now signed.
+ * NEW/IMPROVED:
+ * Updated for Windows 8.1
+ * Added progress display for thread stacks
+ * Updated ExtendedServices plugin:
+ * Added new trigger data types
+ * Updated NetworkTools plugin:
+ * Updated UI
+ * Updated OnlineChecks plugin:
+ * Added file analyzed prompt
+ * FIXED:
+ * Fixed handling of long symbol names
+ * Fixed Run As preventing Windows 8 apps from starting
+ * Fixed console host information for Windows 8.1
+ * Fixed reflected processes not terminating on Windows 8.1
+ * Fixed CPU frequency on Windows 8.1
+
+2.31
+ * NEW/IMPROVED:
+ * Updated ExtendedServices plugin:
+ * Fixed some bugs relating to Windows 8
+ * Updated OnlineChecks plugin:
+ * Added upload progress
+ * Updated UserNotes plugin:
+ * Fixed bug where process priorities were not actually saved
+ * FIXED:
+ * Fixed module list not updating properly
+ * DLL enumeration crash
+
+2.30
+ * NEW/IMPROVED:
+ * Added "Icon click toggles visibility" option
+ * Re-enabled powerful process termination on 32-bit Windows 8
+ * Updated UserNotes plugin:
+ * Added ability to save process priority
+ * Added "Only for processes with the same command line" option for process comments
+ * FIXED:
+ * Fixed crash on CPUs without SSE2
+
+2.29
+ * NEW/IMPROVED:
+ * Added App ID column for processes
+ * Added new ASLR information for Windows 8
+ * Added Restart to Boot Options and Hybrid Shutdown menu items for Windows 8
+ * Added ability to specify processes by their names and inject and unload DLLs in command line
+ * Removed 512 character limit when copying text
+ * Moved Terminator to Miscellaneous menu
+ * Updated default dbghelp.dll path for Windows SDK v8
+ * Updated ExtendedServices plugin:
+ * Added new triggers for Windows 8
+ * Fixed bug when restarting services
+ * Updated ExtendedTools plugin:
+ * Improved support for multiple GPUs (again)
+ * GPU column now respects "Include CPU usage of children" option
+ * Updated ToolStatus plugin:
+ * Fixed search box fonts
+ * Fixed controls not being properly hidden/removed from the window when disabled
+ * Updated WindowExplorer plugin:
+ * Fixed window list not displaying Modern UI windows
+ * FIXED:
+ * Fixed Load Count column sorting bug
+ * Fixed signature verification on Windows 8
+ * Fixed task scheduler information on Windows 8
+ * Fixed drag bug in tree list
+ * Fixed KProcessHacker bug affecting TmTx objects
+ * Fixed Run As feature on Windows 8
+ * Fixed bug where -settings parameter is not propagated
+ * Fixed tab key behavior on main window
+ * Fixed recognition of Modern UI windows
+
+2.28
+ * NEW/IMPROVED:
+ * peview now resolves .lnk targets
+ * Fixed Ctrl+A for processes, services and network connections and added Ctrl+A for other windows
+ * Changed confirmation prompts to select the destructive action by default
+ * Updated DotNetTools plugin:
+ * Fixed inaccurate stack traces for certain .NET programs
+ * Updated ExtendedTools plugin:
+ * Fixed network graph scaling
+ * Updated ToolStatus plugin:
+ * Added search box
+ * Updated Updater plugin
+ * FIXED:
+ * Fixed Verification Status column sorting bug in module list
+ * Fixed rare System Information crash
+ * Fixed bug in opening process handles
+ * Fixed freezing when viewing stack traces of certain system threads
+
+2.27
+ * NEW/IMPROVED:
+ * Updated OnlineChecks plugin:
+ * 2012-01-16: Updated VirusTotal uploader and added hash checking
+ * FIXED:
+ * Fixed Description column sorting bug
+ * Fixed notification icon bug
+
+2.26
+ * NEW/IMPROVED:
+ * Added option to show Commit Charge in system information summary view
+ * Added -priority and -selectpid command line options
+ * Updated ExtendedTools plugin:
+ * Improved support for multiple GPUs
+ * FIXED:
+ * Fixed 100% CPU when starting on some machines
+
+2.25
+ * NEW/IMPROVED:
+ * Improved CPU frequency calculation
+ * Updated ExtendedTools plugin:
+ * Added GPU node selection
+ * Fixed incorrect GPU usage calculation
+ * FIXED:
+ * Graph tooltip position with large cursors
+ * Fixed .NET process detection
+ * Fixed incorrect values in Bits column
+
+2.24
+ * NOTE:
+ * This release has significant internal code changes. Please make sure all plugins are up-to-date.
+ * NEW/IMPROVED:
+ * Completely new system information window
+ * Added option to scroll to new processes
+ * Added option to hide driver services
+ * Added menu item to copy individual cells
+ * Improved module scanning
+ * Added Start Task Manager menu item
+ * Added Image base to peview
+ * Updated ExtendedTools plugin:
+ * Added support for new system information window
+ * Added Disk, Network and GPU tray icons
+ * Added support for custom fonts in the Disk tab
+ * Updated Updater plugin:
+ * Added download speed
+ * Added remaining time
+ * FIXED:
+ * Fixed retrieval of version information for certain files
+ * Fixed driver file names on Windows XP
+ * Fixed Run As Administrator when used with complex commands
+
+2.23
+ * NEW/IMPROVED:
+ * Added display of token capabilities, user/device claims and security attributes
+ * Added ability to change token integrity levels
+ * Added Description column to service list
+ * Added option to reset all settings
+ * Made grid color darker
+ * Enabled multi-selection in the hidden processes window
+ * Added UserNotes plugin
+ * Updated ExtendedNotifications plugin:
+ * Added Growl support
+ * Updated ExtendedTools plugin:
+ * Added GPU monitoring
+ * Added rate columns for disk and network I/O
+ * FIXED:
+ * Fixed copying lists when plugin columns are enabled
+ * Freezing when viewing the tooltip for a process with a very long command line
+ * Disabled Hidden Processes feature on 64-bit systems
+
+2.22
+ * NEW/IMPROVED:
+ * Added highlighting for metro style apps
+ * Added Package Name column
+ * Added package name to process tooltip
+ * Improved .NET process detection
+ * Updated OS Context column for Windows 8
+ * Updated ExtendedTools plugin:
+ * Updated disk monitoring for Windows 8
+ * Updated memory list information for Windows 8
+ * Updated WindowExplorer plugin:
+ * Fixed hook support for low integrity processes
+ * FIXED:
+ * Fixed memory leaks
+ * Fixed bug preventing Interrupts/DPCs from being shown as the max. CPU process on 64-bit systems
+ * Fixed DEP Status column on 64-bit systems
+
+2.21
+ * NEW/IMPROVED:
+ * Added Private Bytes Delta, ASLR and Subsystem columns
+ * Added ASLR and Time Stamp columns to modules list
+ * Added check for debugger in Terminator
+ * FIXED:
+ * Fixed Show CPU Below 0.01 not respecting locale
+ * Fixed copying from network list
+
+2.20
+ * NEW/IMPROVED:
+ * Added support for managed thread stacks on x64
+ * Added column selection for handle list
+ * Added CPU column to threads list
+ * Improved module detection
+ * Added Ideal Processor to Threads tab
+ * Added pool usage and minimum/maximum working set columns
+ * Implemented Properties button for Thread handles
+ * Set descending sort as the default for most numeric columns
+ * Extended header context menu
+ * Removed tooltip text truncation
+ * Improved cycle-based CPU usage calculation
+ * Set default KProcessHacker security level to only allow connections when Process Hacker is running as administrator.
+ See README.txt for instructions on how to restore the old behavior.
+ * Added Updater plugin
+ * Updated DotNetTools plugin:
+ * Added managed symbol resolution for thread stacks
+ * Updated ExtendedTools plugin:
+ * Added Disk tab
+ * Added Hard Faults, Hard Faults Delta and Peak Threads columns to process tree list
+ * Added Firewall Status column
+ * FIXED:
+ * Fixed file name resolution bug
+ * Save settings on shutdown/logoff
+ * Fixed state highlighting bug
+ * Fixed command line propagation for -elevate
+ * Fixed tree list mouse wheel handling
+ * Fixed saving network list
+
+2.19
+ * NEW/IMPROVED:
+ * Added cycle-based CPU usage for Windows 7
+ * Added Show CPU Below 0.01
+ * Added OS Context column
+ * Rewrote graph drawing code for improved performance
+ * Optimized retrieval of cycle time and private working set information for Windows 7
+ * Added Open File Location to process context menu and reorganized some items
+ * Added checkboxes to Terminator
+ * FIXED:
+ * Crash when sorting by Time Stamp
+ * GDI handle leak in drag selection
+
+2.18
+ * NEW/IMPROVED:
+ * Completely rewritten tree list control:
+ * Process Name column is now fixed to the left
+ * Tooltips for column headers
+ * Improved performance
+ * Bug fixes
+ * Added more process tree list columns
+ * Added Time stamp column to network list
+ * Date/time display is now swapped (so time is shown before date)
+ * Added W3 terminator test
+ * Added DotNetTools plugin
+ * Updated ExtendedServices plugin:
+ * Disabled editing of required privileges for drivers
+ * Updated ExtendedTools plugin:
+ * Added ETW columns for processes and network connections
+ * Updated OnlineChecks plugin:
+ * Added Comodo Instant Malware Analysis
+ * Updated WindowExplorer plugin:
+ * Fixed hook bugs
+ * FIXED:
+ * Fixed Run As This User
+ * Verification Status sorting
+
+2.17
+ * NEW/IMPROVED:
+ * Added support for setting page priority
+ * Added elevation support for setting priority
+ * Added support for automatically using a settings file in the program directory (e.g. ProcessHacker.exe.settings.xml)
+ * Improved Run As mechanism
+ * Updated ExtendedServices plugin:
+ * Added support for editing triggers
+ * Added support for editing preshutdown time-out
+ * Added support for editing required privileges
+ * Added elevation support for restarting services
+ * Updated WindowExplorer plugin:
+ * Added more window properties
+ * FIXED:
+ * Handle leak
+
+2.16
+ * NEW/IMPROVED:
+ * Updated WindowExplorer plugin
+ * PE viewer: Added version string to CLR tab
+ * PE viewer: Added display of delay imports
+ * PE viewer: Added Load Config tab
+ * Improved wait analysis
+ * Added arrows to the service list to indicate whether a service is running
+ * FIXED:
+ * Fixed the IPv6-related workaround causing crashes
+ * Incorrect handling of window positions
+
+2.15
+ * NEW/IMPROVED:
+ * Updated ExtendedServices plugin
+ * Updated ToolStatus plugin
+ * Added DEP Status column
+ * Improved User Name column
+ * FIXED:
+ * Image file versions
+ * Workaround for an IPv6-related bug in Windows XP
+ * DPCs and Interrupts in System Information tooltips
+ * File dialog crash on Windows XP
+ * ExtendedTools plugin: WS Watch refresh bug
+
+2.14
+ * NEW/IMPROVED:
+ * ExtendedServices plugin: Option to add a Services menu for processes
+ * Command line support for setting process priority and I/O priority
+ * Improved termination of explorer.exe
+ * FIXED:
+ * Icon should restore the main window if it is minimized
+ * System Information window crashes
+ * Hide Processes From Other Users and Hide Signed Processes settings are now saved
+ * Font selection on Windows XP
+ * ToolStatus plugin: Always on Top status being reset by Find Window
+ * Service-related crashes
+ * WindowExplorer plugin: sorting in tree list
+ * Process minidump creation with old versions of dbghelp.dll
+
+2.13
+ * NEW/IMPROVED:
+ * Added copy support to PE viewer
+ * Added Connect Time, Disconnect Time and Last Input Time to session properties
+ * Added more working set counters to the Statistics tab
+ * FIXED:
+ * Column sort arrows
+ * CPU usage calculations
+
+2.12
+ * NEW/IMPROVED:
+ * Updated KProcessHacker for Windows 7 SP1
+ * Added elevation support for more actions
+ * Added ability to disable plugins
+ * Updated ToolStatus plugin
+ * Added Remote Control for sessions
+ * More command line options
+ * FIXED:
+ * Memory leaks
+ * Run As issues with different sessions
+
+2.11
+ * NEW/IMPROVED:
+ * Added WS Watch and other features to ExtendedTools plugin
+ * Added WindowExplorer plugin
+ * Properties for hidden processes
+ * Improved menus
+ * Debug console can now be closed without affecting the entire program
+ * FIXED:
+ * Always on Top issues
+ * Hang when setting DEP status of a terminating process
+ * Encoding bug in NetworkTools plugin
+ * LSA interfacing issues
+ * Creating dumps of self
+
+2.10
+ * NEW/IMPROVED:
+ * KProcessHacker is now signed, so it works on 64-bit systems. Thank you to the ReactOS Foundation.
+ * Added Run As Limited User
+ * Added CPU, private bytes and I/O history columns
+ * Added font selection
+ * Slightly improved highlighting configuration
+ * FIXED:
+ * High DPI support
+ * Multi-monitor support in graph tooltips
+ * DEP status retrieval
+ * ExtendedTools plugin crash
+ * Notification icon menu crash
+ * Memory leaks
+ * Other small bug fixes
+
+2.9
+ * NEW/IMPROVED:
+ * Added column selection for modules list
+ * Added wait analysis for 64-bit systems
+ * Added signature verification for modules
+ * Added ExtendedTools plugin (Vista and above only) with Disk and Network information
+ * Updated ExtendedNotifications plugin: added ability to log events to a file
+ * Updated ExtendedServices plugin: new tab on Vista and above
+ * Updated ToolStatus plugin: resolves ghost windows to hung windows
+ * Environment variables and current directory are now correctly shown for WOW64 processes
+ * I/O priority names are now used instead of numbers
+ * FIXED:
+ * Network list bug
+ * Memory leaks
+
+2.8
+ * NEW/IMPROVED:
+ * Better service list (including column selection)
+ * Added Peak Handles
+ * Process tree sorting is now preserved
+ * Save works for services and network connections
+ * Pausing now works correctly with the Network tab
+ * Added option to display inclusive CPU usages for collapsed processes
+ * Added CLR tab to peview
+ * Added ability to destroy heaps
+ * Improved process tree list appearance
+ * Certain command line parameters are now propagated
+ * FIXED:
+ * Icon handling bugs
+ * Memory leaks
+ * Extended tooltips for WOW64 processes
+
+2.7
+ * NEW/IMPROVED:
+ * Vastly improved startup time and lower memory usage
+ * Added Cycles and Cycles Delta columns
+ * Added option to disable address resolution for network connections
+ * Added Logon Time to session properties
+ * Added time stamp display to peview
+ * FIXED:
+ * ToolStatus layout problems
+ * .NET highlighting crashes
+ * Run As on Windows XP
+
+2.6
+ * NEW/IMPROVED:
+ * Sorting for most lists is now much faster
+ * Hide Signed Processes option
+ * Added plugin for uploading files to online virus scanners
+ * Added Network tools plugin
+ * Updated ExtendedServices plugin
+ * PE viewer now verifies checksums
+ * Performance improvements
+ * FIXED:
+ * Fixed service handle leak
+
+2.5
+ * NEW/IMPROVED:
+ * Unmap section views in Memory tab
+ * Plugin for extended service information (including recovery information, dependencies and dependents)
+ * FIXED:
+ * Critical bug for file dialogs on Windows XP
+ * Esc couldn't close Service Properties on open
+ * Small bug fixes
+
+2.4
+ * NEW/IMPROVED:
+ * Better Run As behaviour
+ * Show Processes From All Users option
+ * Can now unmap section views
+ * Control over thread affinity
+ * Window Title and Window Status columns
+ * Plugin for filtering notifications
+ * Plugin for toolbar and status bar
+ * Performance improvements
+ * FIXED:
+ * Memory leak
+ * SbieSupport plugin on 64-bit
+ * Crash when running under certain conditions
+ * Memory case-insensitive filter
+ * Process parent association bug
+ * REMOVED:
+ * Process database
+
+2.3
+ * NEW/IMPROVED:
+ * Can add processes to jobs
+ * Double-clicking in the system information graphs now opens information for the relevant process
+ * Setting I/O priority doesn't need KProcessHacker anymore
+ * Elevation for certain actions
+ * FIXED:
+ * HKCU key name resolution
+ * Network connection host resolution
+ * Information window resizing
+ * Log clearing
+
+2.2
+ * NEW/IMPROVED:
+ * Plugins support
+ * Can now unload 32-bit modules on 64-bit systems
+ * Tasks are shown in tooltips for taskeng.exe/taskhost.exe processes
+ * Run As can now start processes elevated
+ * Handle count by type
+ * Process priorities in notification icon menu
+ * CSV export
+ * Relative start times
+ * FIXED:
+ * Run and Run As shortcuts
+ * Command line handling
+ * Process tree selection
+
+2.1
+ * NEW/IMPROVED:
+ * Add Pause key shortcut to pause/resume updates
+ * Added Ctrl+Tab and Ctrl+Shift+Tab shortcuts
+ * Grid is a bit darker
+ * Checks for digital signatures and packing is now off by default and optional
+ * FIXED:
+ * MD5 calculation code for files was wrong
+ * Process record bugs
+
+2.0
+ * First release in the Process Hacker 2.x branch.
diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt
index 2fa97372f513..5469a3bafbe6 100644
--- a/COPYRIGHT.txt
+++ b/COPYRIGHT.txt
@@ -1,132 +1,132 @@
-== Process Hacker ==
-Process Hacker is licensed under the GNU GPL v3, with exceptions. A full
-copy of the license is provided in LICENSE.txt.
-
- Copyright (C) 2009-2016 wj32 and various authors
-
- This program 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.
-
- This program 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 this program. If not, see .
-
-== Mini-XML ==
-Process Hacker uses Mini-XML licensed under the following terms:
-
- The Mini-XML library and included programs are provided under the
- terms of the GNU Library General Public License (LGPL) with the
- following exceptions:
-
- 1. Static linking of applications to the Mini-XML library
- does not constitute a derivative work and does not require
- the author to provide source code for the application, use
- the shared Mini-XML libraries, or link their applications
- against a user-supplied version of Mini-XML.
-
- If you link the application to a modified version of
- Mini-XML, then the changes to Mini-XML must be provided
- under the terms of the LGPL in sections 1, 2, and 4.
-
- 2. You do not have to provide a copy of the Mini-XML license
- with programs that are linked to the Mini-XML library, nor
- do you have to identify the Mini-XML license in your
- program or documentation as required by section 6 of the
- LGPL.
-
-== PCRE ==
-Process Hacker uses Perl-Compatible Regular Expressions licensed under the
-following terms:
-
- PCRE is a library of functions to support regular expressions whose syntax
- and semantics are as close as possible to those of the Perl 5 language.
-
- Release 8 of PCRE is distributed under the terms of the "BSD" licence, as
- specified below.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- * 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.
-
- * Neither the name of the University of Cambridge nor the name of Google
- Inc. nor the names of their contributors may be used to endorse or
- promote products derived from this software without specific prior
- written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
-
-== MD5 ==
-Process Hacker uses a MD5 implementation licensed under the following terms:
-
- MD5 hash implementation and interface functions
- Copyright (c) 2003-2005, Jouni Malinen
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation.
-
-== SHA ==
-Process Hacker uses a SHA implementation licensed under the following terms:
-
- Copyright 2004 Filip Navara
- Based on public domain SHA code by Steve Reid
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
-
- This library 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
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
-
-== Natural order string comparison ==
-Process Hacker uses "strnatcmp.c" licensed under the following terms:
-
- strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
- Copyright (C) 2000, 2004 by Martin Pool
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-
- This code has been modified for Process Hacker.
+== Process Hacker ==
+Process Hacker is licensed under the GNU GPL v3, with exceptions. A full
+copy of the license is provided in LICENSE.txt.
+
+ Copyright (C) 2009-2016 wj32 and various authors
+
+ This program 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.
+
+ This program 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 this program. If not, see .
+
+== Mini-XML ==
+Process Hacker uses Mini-XML licensed under the following terms:
+
+ The Mini-XML library and included programs are provided under the
+ terms of the GNU Library General Public License (LGPL) with the
+ following exceptions:
+
+ 1. Static linking of applications to the Mini-XML library
+ does not constitute a derivative work and does not require
+ the author to provide source code for the application, use
+ the shared Mini-XML libraries, or link their applications
+ against a user-supplied version of Mini-XML.
+
+ If you link the application to a modified version of
+ Mini-XML, then the changes to Mini-XML must be provided
+ under the terms of the LGPL in sections 1, 2, and 4.
+
+ 2. You do not have to provide a copy of the Mini-XML license
+ with programs that are linked to the Mini-XML library, nor
+ do you have to identify the Mini-XML license in your
+ program or documentation as required by section 6 of the
+ LGPL.
+
+== PCRE ==
+Process Hacker uses Perl-Compatible Regular Expressions licensed under the
+following terms:
+
+ PCRE is a library of functions to support regular expressions whose syntax
+ and semantics are as close as possible to those of the Perl 5 language.
+
+ Release 8 of PCRE is distributed under the terms of the "BSD" licence, as
+ specified below.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * 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.
+
+ * Neither the name of the University of Cambridge nor the name of Google
+ Inc. nor the names of their contributors may be used to endorse or
+ promote products derived from this software without specific prior
+ written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
+
+== MD5 ==
+Process Hacker uses a MD5 implementation licensed under the following terms:
+
+ MD5 hash implementation and interface functions
+ Copyright (c) 2003-2005, Jouni Malinen
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+== SHA ==
+Process Hacker uses a SHA implementation licensed under the following terms:
+
+ Copyright 2004 Filip Navara
+ Based on public domain SHA code by Steve Reid
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+== Natural order string comparison ==
+Process Hacker uses "strnatcmp.c" licensed under the following terms:
+
+ strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
+ Copyright (C) 2000, 2004 by Martin Pool
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ This code has been modified for Process Hacker.
diff --git a/KProcessHacker/KProcessHacker.sln b/KProcessHacker/KProcessHacker.sln
new file mode 100644
index 000000000000..f10b7a09a817
--- /dev/null
+++ b/KProcessHacker/KProcessHacker.sln
@@ -0,0 +1,35 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26730.16
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KProcessHacker", "KProcessHacker.vcxproj", "{F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Debug|Win32.ActiveCfg = Debug|Win32
+ {F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Debug|Win32.Build.0 = Debug|Win32
+ {F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Debug|Win32.Deploy.0 = Debug|Win32
+ {F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Debug|x64.ActiveCfg = Debug|x64
+ {F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Debug|x64.Build.0 = Debug|x64
+ {F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Debug|x64.Deploy.0 = Debug|x64
+ {F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Release|Win32.ActiveCfg = Release|Win32
+ {F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Release|Win32.Build.0 = Release|Win32
+ {F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Release|Win32.Deploy.0 = Release|Win32
+ {F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Release|x64.ActiveCfg = Release|x64
+ {F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Release|x64.Build.0 = Release|x64
+ {F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}.Release|x64.Deploy.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {4989C8A8-DCF1-48A9-9012-23369AB01403}
+ EndGlobalSection
+EndGlobal
diff --git a/KProcessHacker/KProcessHacker.vcxproj b/KProcessHacker/KProcessHacker.vcxproj
index 98820bf88ad9..2523a02cadc5 100644
--- a/KProcessHacker/KProcessHacker.vcxproj
+++ b/KProcessHacker/KProcessHacker.vcxproj
@@ -1,139 +1,175 @@
-
-
-
-
- Win8 Debug
- Win32
-
-
- Win8 Release
- Win32
-
-
- Win8 Debug
- x64
-
-
- Win8 Release
- x64
-
-
-
- {F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}
- {dd38f7fc-d7bd-488b-9242-7d8754cde80d}
- v4.5
- 11.0
- Win8 Debug
- Win32
-
-
- KProcessHacker
- $(VCTargetsPath11)
-
-
- WindowsKernelModeDriver8.0
- Driver
- WDM
-
-
-
- Windows8
- true
-
-
- Windows8
- false
-
-
- Windows8
- true
-
-
- Windows8
- false
-
-
-
-
-
-
-
-
-
- DbgengKernelDebugger
-
-
- $(ProjectDir)bin\$(Configuration) $(PlatformArchitecture)\
- $(ProjectDir)obj\$(Configuration) $(PlatformArchitecture)\
- kprocesshacker
-
-
- $(ProjectDir)bin\$(Configuration) $(PlatformArchitecture)\
- $(ProjectDir)obj\$(Configuration) $(PlatformArchitecture)\
- kprocesshacker
-
-
- $(ProjectDir)bin\$(Configuration) $(PlatformArchitecture)\
- $(ProjectDir)obj\$(Configuration) $(PlatformArchitecture)\
- kprocesshacker
-
-
- $(ProjectDir)bin\$(Configuration) $(PlatformArchitecture)\
- $(ProjectDir)obj\$(Configuration) $(PlatformArchitecture)\
- kprocesshacker
-
-
-
- ../phnt/include;../phlib/include;include;$(IntDir);%(AdditionalIncludeDirectories)
- KPH_CONFIG_CLEAN;_X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions)
- Level3
-
-
-
-
- ../phnt/include;../phlib/include;include;$(IntDir);%(AdditionalIncludeDirectories)
- KPH_CONFIG_CLEAN;_X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions)
- Level3
-
-
-
-
- ../phnt/include;../phlib/include;include;$(IntDir);%(AdditionalIncludeDirectories)
- KPH_CONFIG_CLEAN;_WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions)
- Level3
-
-
-
-
- ../phnt/include;../phlib/include;include;$(IntDir);%(AdditionalIncludeDirectories)
- KPH_CONFIG_CLEAN;_WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions)
- Level3
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ {F4853009-C5D2-4A25-BE4D-BB0D9F84E2FF}
+ {dd38f7fc-d7bd-488b-9242-7d8754cde80d}
+ 11.0
+ Win8 Debug
+ Win32
+
+
+ KProcessHacker
+ $(VCTargetsPath11)
+ 10.0.18362.0
+
+
+ WindowsKernelModeDriver10.0
+ Driver
+ WDM
+
+
+
+ Windows7
+ true
+ Unicode
+
+
+ Windows7
+ false
+ Unicode
+
+
+ Windows7
+ true
+ Unicode
+
+
+ Windows7
+ false
+ Unicode
+
+
+
+
+
+
+
+
+
+ DbgengKernelDebugger
+
+
+ $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\
+ $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\
+ false
+ kprocesshacker
+
+
+ $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\
+ $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\
+ false
+ kprocesshacker
+
+
+ $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\
+ $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\
+ false
+ kprocesshacker
+
+
+ $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\
+ $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\
+ false
+ kprocesshacker
+
+
+
+ ../phnt/include;../phlib/include;include;$(IntDir);%(AdditionalIncludeDirectories)
+ KPH_CONFIG_CLEAN;POOL_NX_OPTIN;_X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions)
+ Level3
+ true
+ true
+ false
+
+
+ ksecdd.lib;%(AdditionalDependencies)
+ true
+
+
+
+
+ ../phnt/include;../phlib/include;include;$(IntDir);%(AdditionalIncludeDirectories)
+ KPH_CONFIG_CLEAN;POOL_NX_OPTIN;_X86_=1;i386=1;STD_CALL;%(PreprocessorDefinitions)
+ Level3
+ true
+ true
+
+
+ ksecdd.lib;%(AdditionalDependencies)
+ true
+
+
+
+
+ ../phnt/include;../phlib/include;include;$(IntDir);%(AdditionalIncludeDirectories)
+ KPH_CONFIG_CLEAN;POOL_NX_OPTIN;_WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions)
+ Level3
+ true
+ true
+ false
+
+
+ ksecdd.lib;%(AdditionalDependencies)
+ true
+
+
+
+
+ ../phnt/include;../phlib/include;include;$(IntDir);%(AdditionalIncludeDirectories)
+ KPH_CONFIG_CLEAN;POOL_NX_OPTIN;_WIN64;_AMD64_;AMD64;%(PreprocessorDefinitions)
+ Level3
+ true
+ true
+
+
+ ksecdd.lib;%(AdditionalDependencies)
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/KProcessHacker/KProcessHacker.vcxproj.filters b/KProcessHacker/KProcessHacker.vcxproj.filters
index 1ff8bd09f11c..87b584444426 100644
--- a/KProcessHacker/KProcessHacker.vcxproj.filters
+++ b/KProcessHacker/KProcessHacker.vcxproj.filters
@@ -46,6 +46,12 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
diff --git a/KProcessHacker/bin/amd64/kprocesshacker.pdb b/KProcessHacker/bin/amd64/kprocesshacker.pdb
deleted file mode 100644
index 93dbdc215621..000000000000
Binary files a/KProcessHacker/bin/amd64/kprocesshacker.pdb and /dev/null differ
diff --git a/KProcessHacker/bin/amd64/kprocesshacker.sys b/KProcessHacker/bin/amd64/kprocesshacker.sys
deleted file mode 100644
index f6a94ff33aa2..000000000000
Binary files a/KProcessHacker/bin/amd64/kprocesshacker.sys and /dev/null differ
diff --git a/KProcessHacker/bin/i386/kprocesshacker.pdb b/KProcessHacker/bin/i386/kprocesshacker.pdb
deleted file mode 100644
index b82fe335059d..000000000000
Binary files a/KProcessHacker/bin/i386/kprocesshacker.pdb and /dev/null differ
diff --git a/KProcessHacker/bin/i386/kprocesshacker.sys b/KProcessHacker/bin/i386/kprocesshacker.sys
deleted file mode 100644
index 4f8f329cc11f..000000000000
Binary files a/KProcessHacker/bin/i386/kprocesshacker.sys and /dev/null differ
diff --git a/KProcessHacker/clean/makefile b/KProcessHacker/clean/makefile
deleted file mode 100644
index 05a507be45d7..000000000000
--- a/KProcessHacker/clean/makefile
+++ /dev/null
@@ -1 +0,0 @@
-!INCLUDE $(NTMAKEENV)\makefile.def
\ No newline at end of file
diff --git a/KProcessHacker/clean/sources b/KProcessHacker/clean/sources
deleted file mode 100644
index e2834d805734..000000000000
--- a/KProcessHacker/clean/sources
+++ /dev/null
@@ -1,7 +0,0 @@
-!IF 0
-
-This builds a clean version of KProcessHacker suitable for driver signing.
-
-!ENDIF
-
-!include ..\sources.inc
diff --git a/KProcessHacker/devctrl.c b/KProcessHacker/devctrl.c
index f6a048fae306..8276f50d983f 100644
--- a/KProcessHacker/devctrl.c
+++ b/KProcessHacker/devctrl.c
@@ -1,566 +1,566 @@
-/*
- * KProcessHacker
- *
- * Copyright (C) 2010-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 .
- */
-
-#include
-
-NTSTATUS KphDispatchDeviceControl(
- __in PDEVICE_OBJECT DeviceObject,
- __in PIRP Irp
- )
-{
- NTSTATUS status;
- PIO_STACK_LOCATION stackLocation;
- PFILE_OBJECT fileObject;
- PKPH_CLIENT client;
- PVOID originalInput;
- ULONG inputLength;
- ULONG ioControlCode;
- KPROCESSOR_MODE accessMode;
- UCHAR capturedInput[16 * sizeof(ULONG_PTR)];
- PVOID capturedInputPointer;
-
-#define VERIFY_INPUT_LENGTH \
- do { \
- /* Ensure at compile time that our local buffer fits this particular call. */ \
- C_ASSERT(sizeof(*input) <= sizeof(capturedInput)); \
- \
- if (inputLength != sizeof(*input)) \
- { \
- status = STATUS_INFO_LENGTH_MISMATCH; \
- goto ControlEnd; \
- } \
- } while (0)
-
- stackLocation = IoGetCurrentIrpStackLocation(Irp);
- fileObject = stackLocation->FileObject;
- client = fileObject->FsContext;
-
- originalInput = stackLocation->Parameters.DeviceIoControl.Type3InputBuffer;
- inputLength = stackLocation->Parameters.DeviceIoControl.InputBufferLength;
- ioControlCode = stackLocation->Parameters.DeviceIoControl.IoControlCode;
- accessMode = Irp->RequestorMode;
-
- // Make sure we have a client object.
- if (!client)
- {
- status = STATUS_INTERNAL_ERROR;
- goto ControlEnd;
- }
-
- // Enforce signature requirement if necessary.
- if ((ioControlCode != KPH_GETFEATURES && ioControlCode != KPH_VERIFYCLIENT) &&
- (KphParameters.SecurityLevel == KphSecuritySignatureCheck ||
- KphParameters.SecurityLevel == KphSecuritySignatureAndPrivilegeCheck) &&
- !client->VerificationSucceeded)
- {
- status = STATUS_ACCESS_DENIED;
- goto ControlEnd;
- }
-
- // Make sure we actually have input if the input length is non-zero.
- if (inputLength != 0 && !originalInput)
- {
- status = STATUS_INVALID_BUFFER_SIZE;
- goto ControlEnd;
- }
-
- // Make sure the caller isn't giving us a huge buffer. If they are, it can't be correct because
- // we have a compile-time check that makes sure our buffer can store the arguments for all the
- // calls.
- if (inputLength > sizeof(capturedInput))
- {
- status = STATUS_INVALID_BUFFER_SIZE;
- goto ControlEnd;
- }
-
- // Probe and capture the input buffer.
- if (accessMode != KernelMode)
- {
- __try
- {
- ProbeForRead(originalInput, inputLength, sizeof(UCHAR));
- memcpy(capturedInput, originalInput, inputLength);
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- status = GetExceptionCode();
- goto ControlEnd;
- }
- }
- else
- {
- memcpy(capturedInput, originalInput, inputLength);
- }
-
- capturedInputPointer = capturedInput; // avoid casting below
-
- switch (ioControlCode)
- {
- case KPH_GETFEATURES:
- {
- struct
- {
- PULONG Features;
- } *input = capturedInputPointer;
-
- VERIFY_INPUT_LENGTH;
-
- status = KpiGetFeatures(
- input->Features,
- accessMode
- );
- }
- break;
- case KPH_VERIFYCLIENT:
- {
- struct
- {
- PVOID CodeAddress;
- PVOID Signature;
- ULONG SignatureSize;
- } *input = capturedInputPointer;
-
- VERIFY_INPUT_LENGTH;
-
- if (accessMode == UserMode)
- {
- status = KpiVerifyClient(
- input->CodeAddress,
- input->Signature,
- input->SignatureSize,
- client
- );
- }
- else
- {
- status = STATUS_UNSUCCESSFUL;
- }
- }
- break;
- case KPH_RETRIEVEKEY:
- {
- struct
- {
- KPH_KEY_LEVEL KeyLevel;
- } *input = capturedInputPointer;
-
- VERIFY_INPUT_LENGTH;
-
- if (accessMode == UserMode)
- {
- status = KphRetrieveKeyViaApc(
- client,
- input->KeyLevel,
- Irp
- );
- }
- else
- {
- status = STATUS_UNSUCCESSFUL;
- }
- }
- break;
- case KPH_OPENPROCESS:
- {
- struct
- {
- PHANDLE ProcessHandle;
- ACCESS_MASK DesiredAccess;
- PCLIENT_ID ClientId;
- KPH_KEY Key;
- } *input = capturedInputPointer;
-
- VERIFY_INPUT_LENGTH;
-
- status = KpiOpenProcess(
- input->ProcessHandle,
- input->DesiredAccess,
- input->ClientId,
- input->Key,
- client,
- accessMode
- );
- }
- break;
- case KPH_OPENPROCESSTOKEN:
- {
- struct
- {
- HANDLE ProcessHandle;
- ACCESS_MASK DesiredAccess;
- PHANDLE TokenHandle;
- KPH_KEY Key;
- } *input = capturedInputPointer;
-
- VERIFY_INPUT_LENGTH;
-
- status = KpiOpenProcessToken(
- input->ProcessHandle,
- input->DesiredAccess,
- input->TokenHandle,
- input->Key,
- client,
- accessMode
- );
- }
- break;
- case KPH_OPENPROCESSJOB:
- {
- struct
- {
- HANDLE ProcessHandle;
- ACCESS_MASK DesiredAccess;
- PHANDLE JobHandle;
- } *input = capturedInputPointer;
-
- VERIFY_INPUT_LENGTH;
-
- status = KpiOpenProcessJob(
- input->ProcessHandle,
- input->DesiredAccess,
- input->JobHandle,
- accessMode
- );
- }
- break;
- case KPH_TERMINATEPROCESS:
- {
- struct
- {
- HANDLE ProcessHandle;
- NTSTATUS ExitStatus;
- KPH_KEY Key;
- } *input = capturedInputPointer;
-
- VERIFY_INPUT_LENGTH;
-
- status = KpiTerminateProcess(
- input->ProcessHandle,
- input->ExitStatus,
- input->Key,
- client,
- accessMode
- );
- }
- break;
- case KPH_READVIRTUALMEMORYUNSAFE:
- {
- struct
- {
- HANDLE ProcessHandle;
- PVOID BaseAddress;
- PVOID Buffer;
- SIZE_T BufferSize;
- PSIZE_T NumberOfBytesRead;
- KPH_KEY Key;
- } *input = capturedInputPointer;
-
- VERIFY_INPUT_LENGTH;
-
- status = KpiReadVirtualMemoryUnsafe(
- input->ProcessHandle,
- input->BaseAddress,
- input->Buffer,
- input->BufferSize,
- input->NumberOfBytesRead,
- input->Key,
- client,
- accessMode
- );
- }
- break;
- case KPH_QUERYINFORMATIONPROCESS:
- {
- struct
- {
- HANDLE ProcessHandle;
- KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass;
- PVOID ProcessInformation;
- ULONG ProcessInformationLength;
- PULONG ReturnLength;
- } *input = capturedInputPointer;
-
- VERIFY_INPUT_LENGTH;
-
- status = KpiQueryInformationProcess(
- input->ProcessHandle,
- input->ProcessInformationClass,
- input->ProcessInformation,
- input->ProcessInformationLength,
- input->ReturnLength,
- accessMode
- );
- }
- break;
- case KPH_SETINFORMATIONPROCESS:
- {
- struct
- {
- HANDLE ProcessHandle;
- KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass;
- PVOID ProcessInformation;
- ULONG ProcessInformationLength;
- } *input = capturedInputPointer;
-
- VERIFY_INPUT_LENGTH;
-
- status = KpiSetInformationProcess(
- input->ProcessHandle,
- input->ProcessInformationClass,
- input->ProcessInformation,
- input->ProcessInformationLength,
- accessMode
- );
- }
- break;
- case KPH_OPENTHREAD:
- {
- struct
- {
- PHANDLE ThreadHandle;
- ACCESS_MASK DesiredAccess;
- PCLIENT_ID ClientId;
- KPH_KEY Key;
- } *input = capturedInputPointer;
-
- VERIFY_INPUT_LENGTH;
-
- status = KpiOpenThread(
- input->ThreadHandle,
- input->DesiredAccess,
- input->ClientId,
- input->Key,
- client,
- accessMode
- );
- }
- break;
- case KPH_OPENTHREADPROCESS:
- {
- struct
- {
- HANDLE ThreadHandle;
- ACCESS_MASK DesiredAccess;
- PHANDLE ProcessHandle;
- } *input = capturedInputPointer;
-
- VERIFY_INPUT_LENGTH;
-
- status = KpiOpenThreadProcess(
- input->ThreadHandle,
- input->DesiredAccess,
- input->ProcessHandle,
- accessMode
- );
- }
- break;
- case KPH_CAPTURESTACKBACKTRACETHREAD:
- {
- struct
- {
- HANDLE ThreadHandle;
- ULONG FramesToSkip;
- ULONG FramesToCapture;
- PVOID *BackTrace;
- PULONG CapturedFrames;
- PULONG BackTraceHash;
- } *input = capturedInputPointer;
-
- VERIFY_INPUT_LENGTH;
-
- status = KpiCaptureStackBackTraceThread(
- input->ThreadHandle,
- input->FramesToSkip,
- input->FramesToCapture,
- input->BackTrace,
- input->CapturedFrames,
- input->BackTraceHash,
- accessMode
- );
- }
- break;
- case KPH_QUERYINFORMATIONTHREAD:
- {
- struct
- {
- HANDLE ThreadHandle;
- KPH_THREAD_INFORMATION_CLASS ThreadInformationClass;
- PVOID ThreadInformation;
- ULONG ThreadInformationLength;
- PULONG ReturnLength;
- } *input = capturedInputPointer;
-
- VERIFY_INPUT_LENGTH;
-
- status = KpiQueryInformationThread(
- input->ThreadHandle,
- input->ThreadInformationClass,
- input->ThreadInformation,
- input->ThreadInformationLength,
- input->ReturnLength,
- accessMode
- );
- }
- break;
- case KPH_SETINFORMATIONTHREAD:
- {
- struct
- {
- HANDLE ThreadHandle;
- KPH_THREAD_INFORMATION_CLASS ThreadInformationClass;
- PVOID ThreadInformation;
- ULONG ThreadInformationLength;
- } *input = capturedInputPointer;
-
- VERIFY_INPUT_LENGTH;
-
- status = KpiSetInformationThread(
- input->ThreadHandle,
- input->ThreadInformationClass,
- input->ThreadInformation,
- input->ThreadInformationLength,
- accessMode
- );
- }
- break;
- case KPH_ENUMERATEPROCESSHANDLES:
- {
- struct
- {
- HANDLE ProcessHandle;
- PVOID Buffer;
- ULONG BufferLength;
- PULONG ReturnLength;
- } *input = capturedInputPointer;
-
- VERIFY_INPUT_LENGTH;
-
- status = KpiEnumerateProcessHandles(
- input->ProcessHandle,
- input->Buffer,
- input->BufferLength,
- input->ReturnLength,
- accessMode
- );
- }
- break;
- case KPH_QUERYINFORMATIONOBJECT:
- {
- struct
- {
- HANDLE ProcessHandle;
- HANDLE Handle;
- KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass;
- PVOID ObjectInformation;
- ULONG ObjectInformationLength;
- PULONG ReturnLength;
- } *input = capturedInputPointer;
-
- VERIFY_INPUT_LENGTH;
-
- status = KpiQueryInformationObject(
- input->ProcessHandle,
- input->Handle,
- input->ObjectInformationClass,
- input->ObjectInformation,
- input->ObjectInformationLength,
- input->ReturnLength,
- accessMode
- );
- }
- break;
- case KPH_SETINFORMATIONOBJECT:
- {
- struct
- {
- HANDLE ProcessHandle;
- HANDLE Handle;
- KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass;
- PVOID ObjectInformation;
- ULONG ObjectInformationLength;
- } *input = capturedInputPointer;
-
- VERIFY_INPUT_LENGTH;
-
- status = KpiSetInformationObject(
- input->ProcessHandle,
- input->Handle,
- input->ObjectInformationClass,
- input->ObjectInformation,
- input->ObjectInformationLength,
- accessMode
- );
- }
- break;
- case KPH_OPENDRIVER:
- {
- struct
- {
- PHANDLE DriverHandle;
- ACCESS_MASK DesiredAccess;
- POBJECT_ATTRIBUTES ObjectAttributes;
- } *input = capturedInputPointer;
-
- VERIFY_INPUT_LENGTH;
-
- status = KpiOpenDriver(
- input->DriverHandle,
- input->DesiredAccess,
- input->ObjectAttributes,
- accessMode
- );
- }
- break;
- case KPH_QUERYINFORMATIONDRIVER:
- {
- struct
- {
- HANDLE DriverHandle;
- DRIVER_INFORMATION_CLASS DriverInformationClass;
- PVOID DriverInformation;
- ULONG DriverInformationLength;
- PULONG ReturnLength;
- } *input = capturedInputPointer;
-
- VERIFY_INPUT_LENGTH;
-
- status = KpiQueryInformationDriver(
- input->DriverHandle,
- input->DriverInformationClass,
- input->DriverInformation,
- input->DriverInformationLength,
- input->ReturnLength,
- accessMode
- );
- }
- break;
- default:
- status = STATUS_INVALID_DEVICE_REQUEST;
- break;
- }
-
-ControlEnd:
- Irp->IoStatus.Status = status;
- Irp->IoStatus.Information = 0;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
-
- return status;
-}
+/*
+ * KProcessHacker
+ *
+ * Copyright (C) 2010-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 .
+ */
+
+#include
+
+NTSTATUS KphDispatchDeviceControl(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _Inout_ PIRP Irp
+ )
+{
+ NTSTATUS status;
+ PIO_STACK_LOCATION stackLocation;
+ PFILE_OBJECT fileObject;
+ PKPH_CLIENT client;
+ PVOID originalInput;
+ ULONG inputLength;
+ ULONG ioControlCode;
+ KPROCESSOR_MODE accessMode;
+ UCHAR capturedInput[16 * sizeof(ULONG_PTR)];
+ PVOID capturedInputPointer;
+
+#define VERIFY_INPUT_LENGTH \
+ do { \
+ /* Ensure at compile time that our local buffer fits this particular call. */ \
+ C_ASSERT(sizeof(*input) <= sizeof(capturedInput)); \
+ \
+ if (inputLength != sizeof(*input)) \
+ { \
+ status = STATUS_INFO_LENGTH_MISMATCH; \
+ goto ControlEnd; \
+ } \
+ } while (0)
+
+ stackLocation = IoGetCurrentIrpStackLocation(Irp);
+ fileObject = stackLocation->FileObject;
+ client = fileObject->FsContext;
+
+ originalInput = stackLocation->Parameters.DeviceIoControl.Type3InputBuffer;
+ inputLength = stackLocation->Parameters.DeviceIoControl.InputBufferLength;
+ ioControlCode = stackLocation->Parameters.DeviceIoControl.IoControlCode;
+ accessMode = Irp->RequestorMode;
+
+ // Make sure we have a client object.
+ if (!client)
+ {
+ status = STATUS_INTERNAL_ERROR;
+ goto ControlEnd;
+ }
+
+ // Enforce signature requirement if necessary.
+ if ((ioControlCode != KPH_GETFEATURES && ioControlCode != KPH_VERIFYCLIENT) &&
+ (KphParameters.SecurityLevel == KphSecuritySignatureCheck ||
+ KphParameters.SecurityLevel == KphSecuritySignatureAndPrivilegeCheck) &&
+ !client->VerificationSucceeded)
+ {
+ status = STATUS_ACCESS_DENIED;
+ goto ControlEnd;
+ }
+
+ // Make sure we actually have input if the input length is non-zero.
+ if (inputLength != 0 && !originalInput)
+ {
+ status = STATUS_INVALID_BUFFER_SIZE;
+ goto ControlEnd;
+ }
+
+ // Make sure the caller isn't giving us a huge buffer. If they are, it can't be correct because
+ // we have a compile-time check that makes sure our buffer can store the arguments for all the
+ // calls.
+ if (inputLength > sizeof(capturedInput))
+ {
+ status = STATUS_INVALID_BUFFER_SIZE;
+ goto ControlEnd;
+ }
+
+ // Probe and capture the input buffer.
+ if (accessMode != KernelMode)
+ {
+ __try
+ {
+ ProbeForRead(originalInput, inputLength, sizeof(UCHAR));
+ memcpy(capturedInput, originalInput, inputLength);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ goto ControlEnd;
+ }
+ }
+ else
+ {
+ memcpy(capturedInput, originalInput, inputLength);
+ }
+
+ capturedInputPointer = capturedInput; // avoid casting below
+
+ switch (ioControlCode)
+ {
+ case KPH_GETFEATURES:
+ {
+ struct
+ {
+ PULONG Features;
+ } *input = capturedInputPointer;
+
+ VERIFY_INPUT_LENGTH;
+
+ status = KpiGetFeatures(
+ input->Features,
+ accessMode
+ );
+ }
+ break;
+ case KPH_VERIFYCLIENT:
+ {
+ struct
+ {
+ PVOID CodeAddress;
+ PVOID Signature;
+ ULONG SignatureSize;
+ } *input = capturedInputPointer;
+
+ VERIFY_INPUT_LENGTH;
+
+ if (accessMode == UserMode)
+ {
+ status = KpiVerifyClient(
+ input->CodeAddress,
+ input->Signature,
+ input->SignatureSize,
+ client
+ );
+ }
+ else
+ {
+ status = STATUS_UNSUCCESSFUL;
+ }
+ }
+ break;
+ case KPH_RETRIEVEKEY:
+ {
+ struct
+ {
+ KPH_KEY_LEVEL KeyLevel;
+ } *input = capturedInputPointer;
+
+ VERIFY_INPUT_LENGTH;
+
+ if (accessMode == UserMode)
+ {
+ status = KphRetrieveKeyViaApc(
+ client,
+ input->KeyLevel,
+ Irp
+ );
+ }
+ else
+ {
+ status = STATUS_UNSUCCESSFUL;
+ }
+ }
+ break;
+ case KPH_OPENPROCESS:
+ {
+ struct
+ {
+ PHANDLE ProcessHandle;
+ ACCESS_MASK DesiredAccess;
+ PCLIENT_ID ClientId;
+ KPH_KEY Key;
+ } *input = capturedInputPointer;
+
+ VERIFY_INPUT_LENGTH;
+
+ status = KpiOpenProcess(
+ input->ProcessHandle,
+ input->DesiredAccess,
+ input->ClientId,
+ input->Key,
+ client,
+ accessMode
+ );
+ }
+ break;
+ case KPH_OPENPROCESSTOKEN:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ ACCESS_MASK DesiredAccess;
+ PHANDLE TokenHandle;
+ KPH_KEY Key;
+ } *input = capturedInputPointer;
+
+ VERIFY_INPUT_LENGTH;
+
+ status = KpiOpenProcessToken(
+ input->ProcessHandle,
+ input->DesiredAccess,
+ input->TokenHandle,
+ input->Key,
+ client,
+ accessMode
+ );
+ }
+ break;
+ case KPH_OPENPROCESSJOB:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ ACCESS_MASK DesiredAccess;
+ PHANDLE JobHandle;
+ } *input = capturedInputPointer;
+
+ VERIFY_INPUT_LENGTH;
+
+ status = KpiOpenProcessJob(
+ input->ProcessHandle,
+ input->DesiredAccess,
+ input->JobHandle,
+ accessMode
+ );
+ }
+ break;
+ case KPH_TERMINATEPROCESS:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ NTSTATUS ExitStatus;
+ KPH_KEY Key;
+ } *input = capturedInputPointer;
+
+ VERIFY_INPUT_LENGTH;
+
+ status = KpiTerminateProcess(
+ input->ProcessHandle,
+ input->ExitStatus,
+ input->Key,
+ client,
+ accessMode
+ );
+ }
+ break;
+ case KPH_READVIRTUALMEMORYUNSAFE:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ PVOID BaseAddress;
+ PVOID Buffer;
+ SIZE_T BufferSize;
+ PSIZE_T NumberOfBytesRead;
+ KPH_KEY Key;
+ } *input = capturedInputPointer;
+
+ VERIFY_INPUT_LENGTH;
+
+ status = KpiReadVirtualMemoryUnsafe(
+ input->ProcessHandle,
+ input->BaseAddress,
+ input->Buffer,
+ input->BufferSize,
+ input->NumberOfBytesRead,
+ input->Key,
+ client,
+ accessMode
+ );
+ }
+ break;
+ case KPH_QUERYINFORMATIONPROCESS:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass;
+ PVOID ProcessInformation;
+ ULONG ProcessInformationLength;
+ PULONG ReturnLength;
+ } *input = capturedInputPointer;
+
+ VERIFY_INPUT_LENGTH;
+
+ status = KpiQueryInformationProcess(
+ input->ProcessHandle,
+ input->ProcessInformationClass,
+ input->ProcessInformation,
+ input->ProcessInformationLength,
+ input->ReturnLength,
+ accessMode
+ );
+ }
+ break;
+ case KPH_SETINFORMATIONPROCESS:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass;
+ PVOID ProcessInformation;
+ ULONG ProcessInformationLength;
+ } *input = capturedInputPointer;
+
+ VERIFY_INPUT_LENGTH;
+
+ status = KpiSetInformationProcess(
+ input->ProcessHandle,
+ input->ProcessInformationClass,
+ input->ProcessInformation,
+ input->ProcessInformationLength,
+ accessMode
+ );
+ }
+ break;
+ case KPH_OPENTHREAD:
+ {
+ struct
+ {
+ PHANDLE ThreadHandle;
+ ACCESS_MASK DesiredAccess;
+ PCLIENT_ID ClientId;
+ KPH_KEY Key;
+ } *input = capturedInputPointer;
+
+ VERIFY_INPUT_LENGTH;
+
+ status = KpiOpenThread(
+ input->ThreadHandle,
+ input->DesiredAccess,
+ input->ClientId,
+ input->Key,
+ client,
+ accessMode
+ );
+ }
+ break;
+ case KPH_OPENTHREADPROCESS:
+ {
+ struct
+ {
+ HANDLE ThreadHandle;
+ ACCESS_MASK DesiredAccess;
+ PHANDLE ProcessHandle;
+ } *input = capturedInputPointer;
+
+ VERIFY_INPUT_LENGTH;
+
+ status = KpiOpenThreadProcess(
+ input->ThreadHandle,
+ input->DesiredAccess,
+ input->ProcessHandle,
+ accessMode
+ );
+ }
+ break;
+ case KPH_CAPTURESTACKBACKTRACETHREAD:
+ {
+ struct
+ {
+ HANDLE ThreadHandle;
+ ULONG FramesToSkip;
+ ULONG FramesToCapture;
+ PVOID *BackTrace;
+ PULONG CapturedFrames;
+ PULONG BackTraceHash;
+ } *input = capturedInputPointer;
+
+ VERIFY_INPUT_LENGTH;
+
+ status = KpiCaptureStackBackTraceThread(
+ input->ThreadHandle,
+ input->FramesToSkip,
+ input->FramesToCapture,
+ input->BackTrace,
+ input->CapturedFrames,
+ input->BackTraceHash,
+ accessMode
+ );
+ }
+ break;
+ case KPH_QUERYINFORMATIONTHREAD:
+ {
+ struct
+ {
+ HANDLE ThreadHandle;
+ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass;
+ PVOID ThreadInformation;
+ ULONG ThreadInformationLength;
+ PULONG ReturnLength;
+ } *input = capturedInputPointer;
+
+ VERIFY_INPUT_LENGTH;
+
+ status = KpiQueryInformationThread(
+ input->ThreadHandle,
+ input->ThreadInformationClass,
+ input->ThreadInformation,
+ input->ThreadInformationLength,
+ input->ReturnLength,
+ accessMode
+ );
+ }
+ break;
+ case KPH_SETINFORMATIONTHREAD:
+ {
+ struct
+ {
+ HANDLE ThreadHandle;
+ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass;
+ PVOID ThreadInformation;
+ ULONG ThreadInformationLength;
+ } *input = capturedInputPointer;
+
+ VERIFY_INPUT_LENGTH;
+
+ status = KpiSetInformationThread(
+ input->ThreadHandle,
+ input->ThreadInformationClass,
+ input->ThreadInformation,
+ input->ThreadInformationLength,
+ accessMode
+ );
+ }
+ break;
+ case KPH_ENUMERATEPROCESSHANDLES:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ PVOID Buffer;
+ ULONG BufferLength;
+ PULONG ReturnLength;
+ } *input = capturedInputPointer;
+
+ VERIFY_INPUT_LENGTH;
+
+ status = KpiEnumerateProcessHandles(
+ input->ProcessHandle,
+ input->Buffer,
+ input->BufferLength,
+ input->ReturnLength,
+ accessMode
+ );
+ }
+ break;
+ case KPH_QUERYINFORMATIONOBJECT:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ HANDLE Handle;
+ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass;
+ PVOID ObjectInformation;
+ ULONG ObjectInformationLength;
+ PULONG ReturnLength;
+ } *input = capturedInputPointer;
+
+ VERIFY_INPUT_LENGTH;
+
+ status = KpiQueryInformationObject(
+ input->ProcessHandle,
+ input->Handle,
+ input->ObjectInformationClass,
+ input->ObjectInformation,
+ input->ObjectInformationLength,
+ input->ReturnLength,
+ accessMode
+ );
+ }
+ break;
+ case KPH_SETINFORMATIONOBJECT:
+ {
+ struct
+ {
+ HANDLE ProcessHandle;
+ HANDLE Handle;
+ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass;
+ PVOID ObjectInformation;
+ ULONG ObjectInformationLength;
+ } *input = capturedInputPointer;
+
+ VERIFY_INPUT_LENGTH;
+
+ status = KpiSetInformationObject(
+ input->ProcessHandle,
+ input->Handle,
+ input->ObjectInformationClass,
+ input->ObjectInformation,
+ input->ObjectInformationLength,
+ accessMode
+ );
+ }
+ break;
+ case KPH_OPENDRIVER:
+ {
+ struct
+ {
+ PHANDLE DriverHandle;
+ ACCESS_MASK DesiredAccess;
+ POBJECT_ATTRIBUTES ObjectAttributes;
+ } *input = capturedInputPointer;
+
+ VERIFY_INPUT_LENGTH;
+
+ status = KpiOpenDriver(
+ input->DriverHandle,
+ input->DesiredAccess,
+ input->ObjectAttributes,
+ accessMode
+ );
+ }
+ break;
+ case KPH_QUERYINFORMATIONDRIVER:
+ {
+ struct
+ {
+ HANDLE DriverHandle;
+ DRIVER_INFORMATION_CLASS DriverInformationClass;
+ PVOID DriverInformation;
+ ULONG DriverInformationLength;
+ PULONG ReturnLength;
+ } *input = capturedInputPointer;
+
+ VERIFY_INPUT_LENGTH;
+
+ status = KpiQueryInformationDriver(
+ input->DriverHandle,
+ input->DriverInformationClass,
+ input->DriverInformation,
+ input->DriverInformationLength,
+ input->ReturnLength,
+ accessMode
+ );
+ }
+ break;
+ default:
+ status = STATUS_INVALID_DEVICE_REQUEST;
+ break;
+ }
+
+ControlEnd:
+ Irp->IoStatus.Status = status;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
diff --git a/KProcessHacker/dirs b/KProcessHacker/dirs
deleted file mode 100644
index 1caf7fa5b055..000000000000
--- a/KProcessHacker/dirs
+++ /dev/null
@@ -1 +0,0 @@
-DIRS=clean
diff --git a/KProcessHacker/dyndata.c b/KProcessHacker/dyndata.c
index 616e3aa7125c..be90cda839b0 100644
--- a/KProcessHacker/dyndata.c
+++ b/KProcessHacker/dyndata.c
@@ -1,167 +1,165 @@
-/*
- * KProcessHacker
- *
- * Copyright (C) 2010-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 .
- */
-
-#include
-#define _DYNDATA_PRIVATE
-#include
-
-#define C_2sTo4(x) ((unsigned int)(signed short)(x))
-
-NTSTATUS KphpLoadDynamicConfiguration(
- __in PVOID Buffer,
- __in ULONG Length
- );
-
-#ifdef ALLOC_PRAGMA
-#pragma alloc_text(PAGE, KphDynamicDataInitialization)
-#pragma alloc_text(PAGE, KphReadDynamicDataParameters)
-#pragma alloc_text(PAGE, KphpLoadDynamicConfiguration)
-#endif
-
-NTSTATUS KphDynamicDataInitialization(
- VOID
- )
-{
- NTSTATUS status = STATUS_SUCCESS;
-
- PAGED_CODE();
-
- // Get Windows version information.
-
- KphDynOsVersionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
- status = RtlGetVersion((PRTL_OSVERSIONINFOW)&KphDynOsVersionInfo);
-
- return status;
-}
-
-NTSTATUS KphReadDynamicDataParameters(
- __in_opt HANDLE KeyHandle
- )
-{
- NTSTATUS status;
- UNICODE_STRING valueName;
- PKEY_VALUE_PARTIAL_INFORMATION info;
- ULONG resultLength;
-
- PAGED_CODE();
-
- if (!KeyHandle)
- return STATUS_UNSUCCESSFUL;
-
- RtlInitUnicodeString(&valueName, L"DynamicConfiguration");
-
- status = ZwQueryValueKey(
- KeyHandle,
- &valueName,
- KeyValuePartialInformation,
- NULL,
- 0,
- &resultLength
- );
-
- if (status != STATUS_BUFFER_OVERFLOW && status != STATUS_BUFFER_TOO_SMALL)
- {
- // Unexpected status; fail now.
- return STATUS_UNSUCCESSFUL;
- }
-
- info = ExAllocatePoolWithTag(PagedPool, resultLength, 'ThpK');
-
- if (!info)
- return STATUS_INSUFFICIENT_RESOURCES;
-
- status = ZwQueryValueKey(
- KeyHandle,
- &valueName,
- KeyValuePartialInformation,
- info,
- resultLength,
- &resultLength
- );
-
- if (NT_SUCCESS(status))
- {
- if (info->Type == REG_BINARY)
- status = KphpLoadDynamicConfiguration(info->Data, info->DataLength);
- else
- status = STATUS_OBJECT_TYPE_MISMATCH;
-
- if (!NT_SUCCESS(status))
- dprintf("Unable to load dynamic configuration: 0x%x\n", status);
- }
-
- ExFreePoolWithTag(info, 'ThpK');
-
- return status;
-}
-
-NTSTATUS KphpLoadDynamicConfiguration(
- __in PVOID Buffer,
- __in ULONG Length
- )
-{
- PKPH_DYN_CONFIGURATION config;
- ULONG i;
- PKPH_DYN_PACKAGE package;
-
- PAGED_CODE();
-
- config = Buffer;
-
- if (Length < FIELD_OFFSET(KPH_DYN_CONFIGURATION, Packages))
- return STATUS_INVALID_PARAMETER;
- if (config->Version != KPH_DYN_CONFIGURATION_VERSION)
- return STATUS_INVALID_PARAMETER;
- if (config->NumberOfPackages > KPH_DYN_MAXIMUM_PACKAGES)
- return STATUS_INVALID_PARAMETER;
- if (Length < FIELD_OFFSET(KPH_DYN_CONFIGURATION, Packages) + config->NumberOfPackages * sizeof(KPH_DYN_PACKAGE))
- return STATUS_INVALID_PARAMETER;
-
- dprintf("Loading dynamic configuration with %u package(s)\n", config->NumberOfPackages);
-
- for (i = 0; i < config->NumberOfPackages; i++)
- {
- package = &config->Packages[i];
-
- if (package->MajorVersion == KphDynOsVersionInfo.dwMajorVersion &&
- package->MinorVersion == KphDynOsVersionInfo.dwMinorVersion &&
- (package->ServicePackMajor == (USHORT)-1 || package->ServicePackMajor == KphDynOsVersionInfo.wServicePackMajor) &&
- (package->BuildNumber == (USHORT)-1 || package->BuildNumber == KphDynOsVersionInfo.dwBuildNumber))
- {
- dprintf("Found matching package at index %u for Windows %u.%u\n", i, package->MajorVersion, package->MinorVersion);
-
- KphDynNtVersion = package->ResultingNtVersion;
-
- KphDynEgeGuid = C_2sTo4(package->StructData.EgeGuid);
- KphDynEpObjectTable = C_2sTo4(package->StructData.EpObjectTable);
- KphDynEreGuidEntry = C_2sTo4(package->StructData.EreGuidEntry);
- KphDynHtHandleContentionEvent = C_2sTo4(package->StructData.HtHandleContentionEvent);
- KphDynOtName = C_2sTo4(package->StructData.OtName);
- KphDynOtIndex = C_2sTo4(package->StructData.OtIndex);
- KphDynObDecodeShift = C_2sTo4(package->StructData.ObDecodeShift);
- KphDynObAttributesShift = C_2sTo4(package->StructData.ObAttributesShift);
-
- return STATUS_SUCCESS;
- }
- }
-
- return STATUS_NOT_FOUND;
-}
+/*
+ * KProcessHacker
+ *
+ * Copyright (C) 2010-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 .
+ */
+
+#include
+#define _DYNDATA_PRIVATE
+#include
+
+NTSTATUS KphpLoadDynamicConfiguration(
+ _In_ PVOID Buffer,
+ _In_ ULONG Length
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, KphDynamicDataInitialization)
+#pragma alloc_text(PAGE, KphReadDynamicDataParameters)
+#pragma alloc_text(PAGE, KphpLoadDynamicConfiguration)
+#endif
+
+NTSTATUS KphDynamicDataInitialization(
+ VOID
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+
+ PAGED_CODE();
+
+ // Get Windows version information.
+
+ KphDynOsVersionInfo.dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
+ status = RtlGetVersion((PRTL_OSVERSIONINFOW)&KphDynOsVersionInfo);
+
+ return status;
+}
+
+NTSTATUS KphReadDynamicDataParameters(
+ _In_opt_ HANDLE KeyHandle
+ )
+{
+ NTSTATUS status;
+ UNICODE_STRING valueName;
+ PKEY_VALUE_PARTIAL_INFORMATION info;
+ ULONG resultLength;
+
+ PAGED_CODE();
+
+ if (!KeyHandle)
+ return STATUS_UNSUCCESSFUL;
+
+ RtlInitUnicodeString(&valueName, L"DynamicConfiguration");
+
+ status = ZwQueryValueKey(
+ KeyHandle,
+ &valueName,
+ KeyValuePartialInformation,
+ NULL,
+ 0,
+ &resultLength
+ );
+
+ if (status != STATUS_BUFFER_OVERFLOW && status != STATUS_BUFFER_TOO_SMALL)
+ {
+ // Unexpected status; fail now.
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ info = ExAllocatePoolWithTag(PagedPool, resultLength, 'ThpK');
+
+ if (!info)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ status = ZwQueryValueKey(
+ KeyHandle,
+ &valueName,
+ KeyValuePartialInformation,
+ info,
+ resultLength,
+ &resultLength
+ );
+
+ if (NT_SUCCESS(status))
+ {
+ if (info->Type == REG_BINARY)
+ status = KphpLoadDynamicConfiguration(info->Data, info->DataLength);
+ else
+ status = STATUS_OBJECT_TYPE_MISMATCH;
+
+ if (!NT_SUCCESS(status))
+ dprintf("Unable to load dynamic configuration: 0x%x\n", status);
+ }
+
+ ExFreePoolWithTag(info, 'ThpK');
+
+ return status;
+}
+
+NTSTATUS KphpLoadDynamicConfiguration(
+ _In_ PVOID Buffer,
+ _In_ ULONG Length
+ )
+{
+ PKPH_DYN_CONFIGURATION config;
+ ULONG i;
+ PKPH_DYN_PACKAGE package;
+
+ PAGED_CODE();
+
+ config = Buffer;
+
+ if (Length < UFIELD_OFFSET(KPH_DYN_CONFIGURATION, Packages))
+ return STATUS_INVALID_PARAMETER;
+ if (config->Version != KPH_DYN_CONFIGURATION_VERSION)
+ return STATUS_INVALID_PARAMETER;
+ if (config->NumberOfPackages > KPH_DYN_MAXIMUM_PACKAGES)
+ return STATUS_INVALID_PARAMETER;
+ if (Length < UFIELD_OFFSET(KPH_DYN_CONFIGURATION, Packages) + config->NumberOfPackages * sizeof(KPH_DYN_PACKAGE))
+ return STATUS_INVALID_PARAMETER;
+
+ dprintf("Loading dynamic configuration with %u package(s)\n", config->NumberOfPackages);
+
+ for (i = 0; i < config->NumberOfPackages; i++)
+ {
+ package = &config->Packages[i];
+
+ if (package->MajorVersion == KphDynOsVersionInfo.dwMajorVersion &&
+ package->MinorVersion == KphDynOsVersionInfo.dwMinorVersion &&
+ (package->ServicePackMajor == (USHORT)-1 || package->ServicePackMajor == KphDynOsVersionInfo.wServicePackMajor) &&
+ (package->BuildNumber == (USHORT)-1 || package->BuildNumber == KphDynOsVersionInfo.dwBuildNumber))
+ {
+ dprintf("Found matching package at index %u for Windows %u.%u\n", i, package->MajorVersion, package->MinorVersion);
+
+ KphDynNtVersion = package->ResultingNtVersion;
+
+ KphDynEgeGuid = C_2sTo4(package->StructData.EgeGuid);
+ KphDynEpObjectTable = C_2sTo4(package->StructData.EpObjectTable);
+ KphDynEreGuidEntry = C_2sTo4(package->StructData.EreGuidEntry);
+ KphDynHtHandleContentionEvent = C_2sTo4(package->StructData.HtHandleContentionEvent);
+ KphDynOtName = C_2sTo4(package->StructData.OtName);
+ KphDynOtIndex = C_2sTo4(package->StructData.OtIndex);
+ KphDynObDecodeShift = C_2sTo4(package->StructData.ObDecodeShift);
+ KphDynObAttributesShift = C_2sTo4(package->StructData.ObAttributesShift);
+
+ return STATUS_SUCCESS;
+ }
+ }
+
+ return STATUS_NOT_FOUND;
+}
diff --git a/KProcessHacker/dynimp.c b/KProcessHacker/dynimp.c
index 979364464879..7b02b5b1841f 100644
--- a/KProcessHacker/dynimp.c
+++ b/KProcessHacker/dynimp.c
@@ -1,60 +1,60 @@
-/*
- * KProcessHacker
- *
- * Copyright (C) 2010-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 .
- */
-
-#include
-#include
-
-#ifdef ALLOC_PRAGMA
-#pragma alloc_text(PAGE, KphGetSystemRoutineAddress)
-#pragma alloc_text(PAGE, KphDynamicImport)
-#endif
-
-/**
- * Dynamically imports routines.
- */
-VOID KphDynamicImport(
- VOID
- )
-{
- PAGED_CODE();
- NOTHING;
-}
-
-/**
- * Retrieves the address of a function exported by NTOS or HAL.
- *
- * \param SystemRoutineName The name of the function.
- *
- * \return The address of the function, or NULL if the function could
- * not be found.
- */
-PVOID KphGetSystemRoutineAddress(
- __in PWSTR SystemRoutineName
- )
-{
- UNICODE_STRING systemRoutineName;
-
- PAGED_CODE();
-
- RtlInitUnicodeString(&systemRoutineName, SystemRoutineName);
-
- return MmGetSystemRoutineAddress(&systemRoutineName);
-}
+/*
+ * KProcessHacker
+ *
+ * Copyright (C) 2010-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 .
+ */
+
+#include
+#include
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, KphGetSystemRoutineAddress)
+#pragma alloc_text(PAGE, KphDynamicImport)
+#endif
+
+/**
+ * Dynamically imports routines.
+ */
+VOID KphDynamicImport(
+ VOID
+ )
+{
+ PAGED_CODE();
+ NOTHING;
+}
+
+/**
+ * Retrieves the address of a function exported by NTOS or HAL.
+ *
+ * \param SystemRoutineName The name of the function.
+ *
+ * \return The address of the function, or NULL if the function could
+ * not be found.
+ */
+PVOID KphGetSystemRoutineAddress(
+ _In_ PWSTR SystemRoutineName
+ )
+{
+ UNICODE_STRING systemRoutineName;
+
+ PAGED_CODE();
+
+ RtlInitUnicodeString(&systemRoutineName, SystemRoutineName);
+
+ return MmGetSystemRoutineAddress(&systemRoutineName);
+}
diff --git a/KProcessHacker/include/dyndata.h b/KProcessHacker/include/dyndata.h
index a9ba65dec015..ab36182a3fd9 100644
--- a/KProcessHacker/include/dyndata.h
+++ b/KProcessHacker/include/dyndata.h
@@ -1,47 +1,47 @@
-#ifndef DYNDATA_H
-#define DYNDATA_H
-
-#ifdef EXT
-#undef EXT
-#endif
-
-#ifdef _DYNDATA_PRIVATE
-#define EXT
-#define OFFDEFAULT = -1
-#else
-#define EXT extern
-#define OFFDEFAULT
-#endif
-
-EXT ULONG KphDynNtVersion;
-EXT RTL_OSVERSIONINFOEXW KphDynOsVersionInfo;
-
-// Structures
-// Ege: ETW_GUID_ENTRY
-// Ep: EPROCESS
-// Ere: ETW_REG_ENTRY
-// Et: ETHREAD
-// Ht: HANDLE_TABLE
-// Oh: OBJECT_HEADER
-// Ot: OBJECT_TYPE
-// Oti: OBJECT_TYPE_INITIALIZER, offset measured from an OBJECT_TYPE
-// ObDecodeShift: shift value in ObpDecodeObject
-// ObAttributesShift: shift value in ObpGetHandleAttributes
-EXT ULONG KphDynEgeGuid OFFDEFAULT;
-EXT ULONG KphDynEpObjectTable OFFDEFAULT;
-EXT ULONG KphDynEreGuidEntry OFFDEFAULT;
-EXT ULONG KphDynHtHandleContentionEvent OFFDEFAULT;
-EXT ULONG KphDynOtName OFFDEFAULT;
-EXT ULONG KphDynOtIndex OFFDEFAULT;
-EXT ULONG KphDynObDecodeShift OFFDEFAULT;
-EXT ULONG KphDynObAttributesShift OFFDEFAULT;
-
-NTSTATUS KphDynamicDataInitialization(
- VOID
- );
-
-NTSTATUS KphReadDynamicDataParameters(
- __in_opt HANDLE KeyHandle
- );
-
-#endif
+#ifndef DYNDATA_H
+#define DYNDATA_H
+
+#ifdef EXT
+#undef EXT
+#endif
+
+#ifdef _DYNDATA_PRIVATE
+#define EXT
+#define OFFDEFAULT = -1
+#else
+#define EXT extern
+#define OFFDEFAULT
+#endif
+
+EXT ULONG KphDynNtVersion;
+EXT RTL_OSVERSIONINFOEXW KphDynOsVersionInfo;
+
+// Structures
+// Ege: ETW_GUID_ENTRY
+// Ep: EPROCESS
+// Ere: ETW_REG_ENTRY
+// Et: ETHREAD
+// Ht: HANDLE_TABLE
+// Oh: OBJECT_HEADER
+// Ot: OBJECT_TYPE
+// Oti: OBJECT_TYPE_INITIALIZER, offset measured from an OBJECT_TYPE
+// ObDecodeShift: shift value in ObpDecodeObject
+// ObAttributesShift: shift value in ObpGetHandleAttributes
+EXT ULONG KphDynEgeGuid OFFDEFAULT;
+EXT ULONG KphDynEpObjectTable OFFDEFAULT;
+EXT ULONG KphDynEreGuidEntry OFFDEFAULT;
+EXT ULONG KphDynHtHandleContentionEvent OFFDEFAULT;
+EXT ULONG KphDynOtName OFFDEFAULT;
+EXT ULONG KphDynOtIndex OFFDEFAULT;
+EXT ULONG KphDynObDecodeShift OFFDEFAULT;
+EXT ULONG KphDynObAttributesShift OFFDEFAULT;
+
+NTSTATUS KphDynamicDataInitialization(
+ VOID
+ );
+
+NTSTATUS KphReadDynamicDataParameters(
+ _In_opt_ HANDLE KeyHandle
+ );
+
+#endif
diff --git a/KProcessHacker/include/kph.h b/KProcessHacker/include/kph.h
index 1d196675dfd0..2afa4a4fc84a 100644
--- a/KProcessHacker/include/kph.h
+++ b/KProcessHacker/include/kph.h
@@ -1,365 +1,374 @@
-#ifndef KPH_H
-#define KPH_H
-
-#include
-#define PHNT_MODE PHNT_MODE_KERNEL
-#include
-#include
-#include
-#include
-
-// Debugging
-
-#ifdef DBG
-#define dprintf(Format, ...) DbgPrint("KProcessHacker: " Format, __VA_ARGS__)
-#else
-#define dprintf
-#endif
-
-typedef struct _KPH_CLIENT
-{
- struct
- {
- ULONG VerificationPerformed : 1;
- ULONG VerificationSucceeded : 1;
- ULONG KeysGenerated : 1;
- ULONG SpareBits : 29;
- };
- FAST_MUTEX StateMutex;
- NTSTATUS VerificationStatus;
- PVOID VerifiedProcess; // EPROCESS (for equality checking only - do not access contents)
- HANDLE VerifiedProcessId;
- PVOID VerifiedRangeBase;
- SIZE_T VerifiedRangeSize;
- // Level 1 and 2 secret keys
- FAST_MUTEX KeyBackoffMutex;
- KPH_KEY L1Key;
- KPH_KEY L2Key;
-} KPH_CLIENT, *PKPH_CLIENT;
-
-typedef struct _KPH_PARAMETERS
-{
- KPH_SECURITY_LEVEL SecurityLevel;
-} KPH_PARAMETERS, *PKPH_PARAMETERS;
-
-// main
-
-extern ULONG KphFeatures;
-extern KPH_PARAMETERS KphParameters;
-
-NTSTATUS KpiGetFeatures(
- __out PULONG Features,
- __in KPROCESSOR_MODE AccessMode
- );
-
-// devctrl
-
-__drv_dispatchType(IRP_MJ_DEVICE_CONTROL) DRIVER_DISPATCH KphDispatchDeviceControl;
-
-NTSTATUS KphDispatchDeviceControl(
- __in PDEVICE_OBJECT DeviceObject,
- __in PIRP Irp
- );
-
-// dynimp
-
-VOID KphDynamicImport(
- VOID
- );
-
-PVOID KphGetSystemRoutineAddress(
- __in PWSTR SystemRoutineName
- );
-
-// object
-
-PHANDLE_TABLE KphReferenceProcessHandleTable(
- __in PEPROCESS Process
- );
-
-VOID KphDereferenceProcessHandleTable(
- __in PEPROCESS Process
- );
-
-VOID KphUnlockHandleTableEntry(
- __in PHANDLE_TABLE HandleTable,
- __in PHANDLE_TABLE_ENTRY HandleTableEntry
- );
-
-NTSTATUS KpiEnumerateProcessHandles(
- __in HANDLE ProcessHandle,
- __out_bcount(BufferLength) PVOID Buffer,
- __in_opt ULONG BufferLength,
- __out_opt PULONG ReturnLength,
- __in KPROCESSOR_MODE AccessMode
- );
-
-NTSTATUS KphQueryNameObject(
- __in PVOID Object,
- __out_bcount(BufferLength) POBJECT_NAME_INFORMATION Buffer,
- __in ULONG BufferLength,
- __out PULONG ReturnLength
- );
-
-NTSTATUS KphQueryNameFileObject(
- __in PFILE_OBJECT FileObject,
- __out_bcount(BufferLength) POBJECT_NAME_INFORMATION Buffer,
- __in ULONG BufferLength,
- __out PULONG ReturnLength
- );
-
-NTSTATUS KpiQueryInformationObject(
- __in HANDLE ProcessHandle,
- __in HANDLE Handle,
- __in KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass,
- __out_bcount(ObjectInformationLength) PVOID ObjectInformation,
- __in ULONG ObjectInformationLength,
- __out_opt PULONG ReturnLength,
- __in KPROCESSOR_MODE AccessMode
- );
-
-NTSTATUS KpiSetInformationObject(
- __in HANDLE ProcessHandle,
- __in HANDLE Handle,
- __in KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass,
- __in_bcount(ObjectInformationLength) PVOID ObjectInformation,
- __in ULONG ObjectInformationLength,
- __in KPROCESSOR_MODE AccessMode
- );
-
-NTSTATUS KphOpenNamedObject(
- __out PHANDLE ObjectHandle,
- __in ACCESS_MASK DesiredAccess,
- __in POBJECT_ATTRIBUTES ObjectAttributes,
- __in POBJECT_TYPE ObjectType,
- __in KPROCESSOR_MODE AccessMode
- );
-
-// process
-
-NTSTATUS KpiOpenProcess(
- __out PHANDLE ProcessHandle,
- __in ACCESS_MASK DesiredAccess,
- __in PCLIENT_ID ClientId,
- __in_opt KPH_KEY Key,
- __in PKPH_CLIENT Client,
- __in KPROCESSOR_MODE AccessMode
- );
-
-NTSTATUS KpiOpenProcessToken(
- __in HANDLE ProcessHandle,
- __in ACCESS_MASK DesiredAccess,
- __out PHANDLE TokenHandle,
- __in_opt KPH_KEY Key,
- __in PKPH_CLIENT Client,
- __in KPROCESSOR_MODE AccessMode
- );
-
-NTSTATUS KpiOpenProcessJob(
- __in HANDLE ProcessHandle,
- __in ACCESS_MASK DesiredAccess,
- __out PHANDLE JobHandle,
- __in KPROCESSOR_MODE AccessMode
- );
-
-NTSTATUS KpiTerminateProcess(
- __in HANDLE ProcessHandle,
- __in NTSTATUS ExitStatus,
- __in_opt KPH_KEY Key,
- __in PKPH_CLIENT Client,
- __in KPROCESSOR_MODE AccessMode
- );
-
-NTSTATUS KpiQueryInformationProcess(
- __in HANDLE ProcessHandle,
- __in KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,
- __out_bcount(ProcessInformationLength) PVOID ProcessInformation,
- __in ULONG ProcessInformationLength,
- __out_opt PULONG ReturnLength,
- __in KPROCESSOR_MODE AccessMode
- );
-
-NTSTATUS KpiSetInformationProcess(
- __in HANDLE ProcessHandle,
- __in KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,
- __in_bcount(ProcessInformationLength) PVOID ProcessInformation,
- __in ULONG ProcessInformationLength,
- __in KPROCESSOR_MODE AccessMode
- );
-
-// qrydrv
-
-NTSTATUS KpiOpenDriver(
- __out PHANDLE DriverHandle,
- __in ACCESS_MASK DesiredAccess,
- __in POBJECT_ATTRIBUTES ObjectAttributes,
- __in KPROCESSOR_MODE AccessMode
- );
-
-NTSTATUS KpiQueryInformationDriver(
- __in HANDLE DriverHandle,
- __in DRIVER_INFORMATION_CLASS DriverInformationClass,
- __out_bcount(DriverInformationLength) PVOID DriverInformation,
- __in ULONG DriverInformationLength,
- __out_opt PULONG ReturnLength,
- __in KPROCESSOR_MODE AccessMode
- );
-
-// thread
-
-NTSTATUS KpiOpenThread(
- __out PHANDLE ThreadHandle,
- __in ACCESS_MASK DesiredAccess,
- __in PCLIENT_ID ClientId,
- __in_opt KPH_KEY Key,
- __in PKPH_CLIENT Client,
- __in KPROCESSOR_MODE AccessMode
- );
-
-NTSTATUS KpiOpenThreadProcess(
- __in HANDLE ThreadHandle,
- __in ACCESS_MASK DesiredAccess,
- __out PHANDLE ProcessHandle,
- __in KPROCESSOR_MODE AccessMode
- );
-
-ULONG KphCaptureStackBackTrace(
- __in ULONG FramesToSkip,
- __in ULONG FramesToCapture,
- __in_opt ULONG Flags,
- __out_ecount(FramesToCapture) PVOID *BackTrace,
- __out_opt PULONG BackTraceHash
- );
-
-NTSTATUS KphCaptureStackBackTraceThread(
- __in PETHREAD Thread,
- __in ULONG FramesToSkip,
- __in ULONG FramesToCapture,
- __out_ecount(FramesToCapture) PVOID *BackTrace,
- __out_opt PULONG CapturedFrames,
- __out_opt PULONG BackTraceHash,
- __in KPROCESSOR_MODE AccessMode
- );
-
-NTSTATUS KpiCaptureStackBackTraceThread(
- __in HANDLE ThreadHandle,
- __in ULONG FramesToSkip,
- __in ULONG FramesToCapture,
- __out_ecount(FramesToCapture) PVOID *BackTrace,
- __out_opt PULONG CapturedFrames,
- __out_opt PULONG BackTraceHash,
- __in KPROCESSOR_MODE AccessMode
- );
-
-NTSTATUS KpiQueryInformationThread(
- __in HANDLE ThreadHandle,
- __in KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,
- __out_bcount(ProcessInformationLength) PVOID ThreadInformation,
- __in ULONG ThreadInformationLength,
- __out_opt PULONG ReturnLength,
- __in KPROCESSOR_MODE AccessMode
- );
-
-NTSTATUS KpiSetInformationThread(
- __in HANDLE ThreadHandle,
- __in KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,
- __in_bcount(ThreadInformationLength) PVOID ThreadInformation,
- __in ULONG ThreadInformationLength,
- __in KPROCESSOR_MODE AccessMode
- );
-
-// util
-
-VOID KphFreeCapturedUnicodeString(
- __in PUNICODE_STRING CapturedUnicodeString
- );
-
-NTSTATUS KphCaptureUnicodeString(
- __in PUNICODE_STRING UnicodeString,
- __out PUNICODE_STRING CapturedUnicodeString
- );
-
-NTSTATUS KphEnumerateSystemModules(
- __out PRTL_PROCESS_MODULES *Modules
- );
-
-NTSTATUS KphValidateAddressForSystemModules(
- __in PVOID Address,
- __in SIZE_T Length
- );
-
-NTSTATUS KphGetProcessMappedFileName(
- __in HANDLE ProcessHandle,
- __in PVOID BaseAddress,
- __out PUNICODE_STRING *FileName
- );
-
-// verify
-
-NTSTATUS KphHashFile(
- __in PUNICODE_STRING FileName,
- __out PVOID *Hash,
- __out PULONG HashSize
- );
-
-NTSTATUS KphVerifyFile(
- __in PUNICODE_STRING FileName,
- __in_bcount(SignatureSize) PUCHAR Signature,
- __in ULONG SignatureSize
- );
-
-VOID KphVerifyClient(
- __inout PKPH_CLIENT Client,
- __in PVOID CodeAddress,
- __in_bcount(SignatureSize) PUCHAR Signature,
- __in ULONG SignatureSize
- );
-
-NTSTATUS KpiVerifyClient(
- __in PVOID CodeAddress,
- __in_bcount(SignatureSize) PUCHAR Signature,
- __in ULONG SignatureSize,
- __in PKPH_CLIENT Client
- );
-
-VOID KphGenerateKeysClient(
- __inout PKPH_CLIENT Client
- );
-
-NTSTATUS KphRetrieveKeyViaApc(
- __inout PKPH_CLIENT Client,
- __in KPH_KEY_LEVEL KeyLevel,
- __inout PIRP Irp
- );
-
-NTSTATUS KphValidateKey(
- __in KPH_KEY_LEVEL RequiredKeyLevel,
- __in_opt KPH_KEY Key,
- __in PKPH_CLIENT Client,
- __in KPROCESSOR_MODE AccessMode
- );
-
-// vm
-
-NTSTATUS KphCopyVirtualMemory(
- __in PEPROCESS FromProcess,
- __in PVOID FromAddress,
- __in PEPROCESS ToProcess,
- __in PVOID ToAddress,
- __in SIZE_T BufferLength,
- __in KPROCESSOR_MODE AccessMode,
- __out PSIZE_T ReturnLength
- );
-
-NTSTATUS KpiReadVirtualMemoryUnsafe(
- __in_opt HANDLE ProcessHandle,
- __in PVOID BaseAddress,
- __out_bcount(BufferSize) PVOID Buffer,
- __in SIZE_T BufferSize,
- __out_opt PSIZE_T NumberOfBytesRead,
- __in_opt KPH_KEY Key,
- __in PKPH_CLIENT Client,
- __in KPROCESSOR_MODE AccessMode
- );
-
-#endif
+#ifndef KPH_H
+#define KPH_H
+
+#include
+#define PHNT_MODE PHNT_MODE_KERNEL
+#include
+#include
+#include
+#include
+
+// Memory
+
+#define PTR_ADD_OFFSET(Pointer, Offset) ((PVOID)((ULONG_PTR)(Pointer) + (ULONG_PTR)(Offset)))
+#define PTR_SUB_OFFSET(Pointer, Offset) ((PVOID)((ULONG_PTR)(Pointer) - (ULONG_PTR)(Offset)))
+
+// Zero extension and sign extension macros
+
+#define C_2sTo4(x) ((unsigned int)(signed short)(x))
+
+// Debugging
+
+#ifdef DBG
+#define dprintf(Format, ...) DbgPrint("KProcessHacker: " Format, __VA_ARGS__)
+#else
+#define dprintf
+#endif
+
+typedef struct _KPH_CLIENT
+{
+ struct
+ {
+ ULONG VerificationPerformed : 1;
+ ULONG VerificationSucceeded : 1;
+ ULONG KeysGenerated : 1;
+ ULONG SpareBits : 29;
+ };
+ FAST_MUTEX StateMutex;
+ NTSTATUS VerificationStatus;
+ PVOID VerifiedProcess; // EPROCESS (for equality checking only - do not access contents)
+ HANDLE VerifiedProcessId;
+ PVOID VerifiedRangeBase;
+ SIZE_T VerifiedRangeSize;
+ // Level 1 and 2 secret keys
+ FAST_MUTEX KeyBackoffMutex;
+ KPH_KEY L1Key;
+ KPH_KEY L2Key;
+} KPH_CLIENT, *PKPH_CLIENT;
+
+typedef struct _KPH_PARAMETERS
+{
+ KPH_SECURITY_LEVEL SecurityLevel;
+} KPH_PARAMETERS, *PKPH_PARAMETERS;
+
+// main
+
+extern ULONG KphFeatures;
+extern KPH_PARAMETERS KphParameters;
+
+NTSTATUS KpiGetFeatures(
+ _Out_ PULONG Features,
+ _In_ KPROCESSOR_MODE AccessMode
+ );
+
+// devctrl
+
+_Dispatch_type_(IRP_MJ_DEVICE_CONTROL) DRIVER_DISPATCH KphDispatchDeviceControl;
+
+NTSTATUS KphDispatchDeviceControl(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _Inout_ PIRP Irp
+ );
+
+// dynimp
+
+VOID KphDynamicImport(
+ VOID
+ );
+
+PVOID KphGetSystemRoutineAddress(
+ _In_ PWSTR SystemRoutineName
+ );
+
+// object
+
+PHANDLE_TABLE KphReferenceProcessHandleTable(
+ _In_ PEPROCESS Process
+ );
+
+VOID KphDereferenceProcessHandleTable(
+ _In_ PEPROCESS Process
+ );
+
+VOID KphUnlockHandleTableEntry(
+ _In_ PHANDLE_TABLE HandleTable,
+ _In_ PHANDLE_TABLE_ENTRY HandleTableEntry
+ );
+
+NTSTATUS KpiEnumerateProcessHandles(
+ _In_ HANDLE ProcessHandle,
+ _Out_writes_bytes_(BufferLength) PVOID Buffer,
+ _In_opt_ ULONG BufferLength,
+ _Out_opt_ PULONG ReturnLength,
+ _In_ KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KphQueryNameObject(
+ _In_ PVOID Object,
+ _Out_writes_bytes_(BufferLength) POBJECT_NAME_INFORMATION Buffer,
+ _In_ ULONG BufferLength,
+ _Out_ PULONG ReturnLength
+ );
+
+NTSTATUS KphQueryNameFileObject(
+ _In_ PFILE_OBJECT FileObject,
+ _Out_writes_bytes_(BufferLength) POBJECT_NAME_INFORMATION Buffer,
+ _In_ ULONG BufferLength,
+ _Out_ PULONG ReturnLength
+ );
+
+NTSTATUS KpiQueryInformationObject(
+ _In_ HANDLE ProcessHandle,
+ _In_ HANDLE Handle,
+ _In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass,
+ _Out_writes_bytes_(ObjectInformationLength) PVOID ObjectInformation,
+ _In_ ULONG ObjectInformationLength,
+ _Out_opt_ PULONG ReturnLength,
+ _In_ KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KpiSetInformationObject(
+ _In_ HANDLE ProcessHandle,
+ _In_ HANDLE Handle,
+ _In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass,
+ _In_reads_bytes_(ObjectInformationLength) PVOID ObjectInformation,
+ _In_ ULONG ObjectInformationLength,
+ _In_ KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KphOpenNamedObject(
+ _Out_ PHANDLE ObjectHandle,
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_ POBJECT_ATTRIBUTES ObjectAttributes,
+ _In_ POBJECT_TYPE ObjectType,
+ _In_ KPROCESSOR_MODE AccessMode
+ );
+
+// process
+
+NTSTATUS KpiOpenProcess(
+ _Out_ PHANDLE ProcessHandle,
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_ PCLIENT_ID ClientId,
+ _In_opt_ KPH_KEY Key,
+ _In_ PKPH_CLIENT Client,
+ _In_ KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KpiOpenProcessToken(
+ _In_ HANDLE ProcessHandle,
+ _In_ ACCESS_MASK DesiredAccess,
+ _Out_ PHANDLE TokenHandle,
+ _In_opt_ KPH_KEY Key,
+ _In_ PKPH_CLIENT Client,
+ _In_ KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KpiOpenProcessJob(
+ _In_ HANDLE ProcessHandle,
+ _In_ ACCESS_MASK DesiredAccess,
+ _Out_ PHANDLE JobHandle,
+ _In_ KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KpiTerminateProcess(
+ _In_ HANDLE ProcessHandle,
+ _In_ NTSTATUS ExitStatus,
+ _In_opt_ KPH_KEY Key,
+ _In_ PKPH_CLIENT Client,
+ _In_ KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KpiQueryInformationProcess(
+ _In_ HANDLE ProcessHandle,
+ _In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,
+ _Out_writes_bytes_(ProcessInformationLength) PVOID ProcessInformation,
+ _In_ ULONG ProcessInformationLength,
+ _Out_opt_ PULONG ReturnLength,
+ _In_ KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KpiSetInformationProcess(
+ _In_ HANDLE ProcessHandle,
+ _In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,
+ _In_reads_bytes_(ProcessInformationLength) PVOID ProcessInformation,
+ _In_ ULONG ProcessInformationLength,
+ _In_ KPROCESSOR_MODE AccessMode
+ );
+
+// qrydrv
+
+NTSTATUS KpiOpenDriver(
+ _Out_ PHANDLE DriverHandle,
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_ POBJECT_ATTRIBUTES ObjectAttributes,
+ _In_ KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KpiQueryInformationDriver(
+ _In_ HANDLE DriverHandle,
+ _In_ DRIVER_INFORMATION_CLASS DriverInformationClass,
+ _Out_writes_bytes_(DriverInformationLength) PVOID DriverInformation,
+ _In_ ULONG DriverInformationLength,
+ _Out_opt_ PULONG ReturnLength,
+ _In_ KPROCESSOR_MODE AccessMode
+ );
+
+// thread
+
+NTSTATUS KpiOpenThread(
+ _Out_ PHANDLE ThreadHandle,
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_ PCLIENT_ID ClientId,
+ _In_opt_ KPH_KEY Key,
+ _In_ PKPH_CLIENT Client,
+ _In_ KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KpiOpenThreadProcess(
+ _In_ HANDLE ThreadHandle,
+ _In_ ACCESS_MASK DesiredAccess,
+ _Out_ PHANDLE ProcessHandle,
+ _In_ KPROCESSOR_MODE AccessMode
+ );
+
+ULONG KphCaptureStackBackTrace(
+ _In_ ULONG FramesToSkip,
+ _In_ ULONG FramesToCapture,
+ _In_opt_ ULONG Flags,
+ _Out_writes_(FramesToCapture) PVOID *BackTrace,
+ _Out_opt_ PULONG BackTraceHash
+ );
+
+NTSTATUS KphCaptureStackBackTraceThread(
+ _In_ PETHREAD Thread,
+ _In_ ULONG FramesToSkip,
+ _In_ ULONG FramesToCapture,
+ _Out_writes_(FramesToCapture) PVOID *BackTrace,
+ _Out_opt_ PULONG CapturedFrames,
+ _Out_opt_ PULONG BackTraceHash,
+ _In_ KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KpiCaptureStackBackTraceThread(
+ _In_ HANDLE ThreadHandle,
+ _In_ ULONG FramesToSkip,
+ _In_ ULONG FramesToCapture,
+ _Out_writes_(FramesToCapture) PVOID *BackTrace,
+ _Out_opt_ PULONG CapturedFrames,
+ _Out_opt_ PULONG BackTraceHash,
+ _In_ KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KpiQueryInformationThread(
+ _In_ HANDLE ThreadHandle,
+ _In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,
+ _Out_writes_bytes_(ThreadInformationLength) PVOID ThreadInformation,
+ _In_ ULONG ThreadInformationLength,
+ _Out_opt_ PULONG ReturnLength,
+ _In_ KPROCESSOR_MODE AccessMode
+ );
+
+NTSTATUS KpiSetInformationThread(
+ _In_ HANDLE ThreadHandle,
+ _In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,
+ _In_reads_bytes_(ThreadInformationLength) PVOID ThreadInformation,
+ _In_ ULONG ThreadInformationLength,
+ _In_ KPROCESSOR_MODE AccessMode
+ );
+
+// util
+
+VOID KphFreeCapturedUnicodeString(
+ _In_ PUNICODE_STRING CapturedUnicodeString
+ );
+
+NTSTATUS KphCaptureUnicodeString(
+ _In_ PUNICODE_STRING UnicodeString,
+ _Out_ PUNICODE_STRING CapturedUnicodeString
+ );
+
+NTSTATUS KphEnumerateSystemModules(
+ _Out_ PRTL_PROCESS_MODULES *Modules
+ );
+
+NTSTATUS KphValidateAddressForSystemModules(
+ _In_ PVOID Address,
+ _In_ SIZE_T Length
+ );
+
+NTSTATUS KphGetProcessMappedFileName(
+ _In_ HANDLE ProcessHandle,
+ _In_ PVOID BaseAddress,
+ _Out_ PUNICODE_STRING *FileName
+ );
+
+// verify
+
+NTSTATUS KphHashFile(
+ _In_ PUNICODE_STRING FileName,
+ _Out_ PVOID *Hash,
+ _Out_ PULONG HashSize
+ );
+
+NTSTATUS KphVerifyFile(
+ _In_ PUNICODE_STRING FileName,
+ _In_reads_bytes_(SignatureSize) PUCHAR Signature,
+ _In_ ULONG SignatureSize
+ );
+
+VOID KphVerifyClient(
+ _Inout_ PKPH_CLIENT Client,
+ _In_ PVOID CodeAddress,
+ _In_reads_bytes_(SignatureSize) PUCHAR Signature,
+ _In_ ULONG SignatureSize
+ );
+
+NTSTATUS KpiVerifyClient(
+ _In_ PVOID CodeAddress,
+ _In_reads_bytes_(SignatureSize) PUCHAR Signature,
+ _In_ ULONG SignatureSize,
+ _In_ PKPH_CLIENT Client
+ );
+
+VOID KphGenerateKeysClient(
+ _Inout_ PKPH_CLIENT Client
+ );
+
+NTSTATUS KphRetrieveKeyViaApc(
+ _Inout_ PKPH_CLIENT Client,
+ _In_ KPH_KEY_LEVEL KeyLevel,
+ _Inout_ PIRP Irp
+ );
+
+NTSTATUS KphValidateKey(
+ _In_ KPH_KEY_LEVEL RequiredKeyLevel,
+ _In_opt_ KPH_KEY Key,
+ _In_ PKPH_CLIENT Client,
+ _In_ KPROCESSOR_MODE AccessMode
+ );
+
+// vm
+
+NTSTATUS KphCopyVirtualMemory(
+ _In_ PEPROCESS FromProcess,
+ _In_ PVOID FromAddress,
+ _In_ PEPROCESS ToProcess,
+ _In_ PVOID ToAddress,
+ _In_ SIZE_T BufferLength,
+ _In_ KPROCESSOR_MODE AccessMode,
+ _Out_ PSIZE_T ReturnLength
+ );
+
+NTSTATUS KpiReadVirtualMemoryUnsafe(
+ _In_opt_ HANDLE ProcessHandle,
+ _In_ PVOID BaseAddress,
+ _Out_writes_bytes_(BufferSize) PVOID Buffer,
+ _In_ SIZE_T BufferSize,
+ _Out_opt_ PSIZE_T NumberOfBytesRead,
+ _In_opt_ KPH_KEY Key,
+ _In_ PKPH_CLIENT Client,
+ _In_ KPROCESSOR_MODE AccessMode
+ );
+
+#endif
diff --git a/KProcessHacker/include/ntfill.h b/KProcessHacker/include/ntfill.h
index f430f49983e5..0cf0bcdc300c 100644
--- a/KProcessHacker/include/ntfill.h
+++ b/KProcessHacker/include/ntfill.h
@@ -1,351 +1,335 @@
-#ifndef NTFILL_H
-#define NTFILL_H
-
-extern ULONG KphDynNtVersion;
-extern ULONG KphDynObDecodeShift;
-extern ULONG KphDynObAttributesShift;
-
-// EX
-
-typedef struct _EX_PUSH_LOCK_WAIT_BLOCK *PEX_PUSH_LOCK_WAIT_BLOCK;
-
-NTKERNELAPI
-VOID
-FASTCALL
-ExfUnblockPushLock(
- __inout PEX_PUSH_LOCK PushLock,
- __inout_opt PEX_PUSH_LOCK_WAIT_BLOCK WaitBlock
- );
-
-typedef struct _HANDLE_TABLE_ENTRY
-{
- union
- {
- PVOID Object;
- ULONG ObAttributes;
- ULONG_PTR Value;
- };
- union
- {
- ACCESS_MASK GrantedAccess;
- LONG NextFreeTableEntry;
- };
-} HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;
-
-typedef struct _HANDLE_TABLE HANDLE_TABLE, *PHANDLE_TABLE;
-
-typedef BOOLEAN (NTAPI *PEX_ENUM_HANDLE_CALLBACK_61)(
- __inout PHANDLE_TABLE_ENTRY HandleTableEntry,
- __in HANDLE Handle,
- __in PVOID Context
- );
-
-// since WIN8
-typedef BOOLEAN (NTAPI *PEX_ENUM_HANDLE_CALLBACK)(
- __in PHANDLE_TABLE HandleTable,
- __inout PHANDLE_TABLE_ENTRY HandleTableEntry,
- __in HANDLE Handle,
- __in PVOID Context
- );
-
-NTKERNELAPI
-BOOLEAN
-NTAPI
-ExEnumHandleTable(
- __in PHANDLE_TABLE HandleTable,
- __in PEX_ENUM_HANDLE_CALLBACK EnumHandleProcedure,
- __inout PVOID Context,
- __out_opt PHANDLE Handle
- );
-
-NTSYSCALLAPI
-NTSTATUS
-NTAPI
-ZwQuerySystemInformation(
- __in SYSTEM_INFORMATION_CLASS SystemInformationClass,
- __out_bcount_opt(SystemInformationLength) PVOID SystemInformation,
- __in ULONG SystemInformationLength,
- __out_opt PULONG ReturnLength
- );
-
-// IO
-
-extern POBJECT_TYPE *IoDriverObjectType;
-
-// KE
-
-typedef enum _KAPC_ENVIRONMENT
-{
- OriginalApcEnvironment,
- AttachedApcEnvironment,
- CurrentApcEnvironment,
- InsertApcEnvironment
-} KAPC_ENVIRONMENT, *PKAPC_ENVIRONMENT;
-
-typedef VOID (NTAPI *PKNORMAL_ROUTINE)(
- __in PVOID NormalContext,
- __in PVOID SystemArgument1,
- __in PVOID SystemArgument2
- );
-
-typedef VOID KKERNEL_ROUTINE(
- __in PRKAPC Apc,
- __inout PKNORMAL_ROUTINE *NormalRoutine,
- __inout PVOID *NormalContext,
- __inout PVOID *SystemArgument1,
- __inout PVOID *SystemArgument2
- );
-
-typedef KKERNEL_ROUTINE (NTAPI *PKKERNEL_ROUTINE);
-
-typedef VOID (NTAPI *PKRUNDOWN_ROUTINE)(
- __in PRKAPC Apc
- );
-
-NTKERNELAPI
-VOID
-NTAPI
-KeInitializeApc(
- __out PRKAPC Apc,
- __in PRKTHREAD Thread,
- __in KAPC_ENVIRONMENT Environment,
- __in PKKERNEL_ROUTINE KernelRoutine,
- __in_opt PKRUNDOWN_ROUTINE RundownRoutine,
- __in_opt PKNORMAL_ROUTINE NormalRoutine,
- __in_opt KPROCESSOR_MODE ProcessorMode,
- __in_opt PVOID NormalContext
- );
-
-NTKERNELAPI
-BOOLEAN
-NTAPI
-KeInsertQueueApc(
- __inout PRKAPC Apc,
- __in_opt PVOID SystemArgument1,
- __in_opt PVOID SystemArgument2,
- __in KPRIORITY Increment
- );
-
-// MM
-
-NTSYSCALLAPI
-NTSTATUS
-NTAPI
-ZwQueryVirtualMemory(
- __in HANDLE ProcessHandle,
- __in PVOID BaseAddress,
- __in MEMORY_INFORMATION_CLASS MemoryInformationClass,
- __out_bcount(MemoryInformationLength) PVOID MemoryInformation,
- __in SIZE_T MemoryInformationLength,
- __out_opt PSIZE_T ReturnLength
- );
-
-// OB
-
-// These definitions are no longer correct, but they produce correct results.
-
-#define OBJ_PROTECT_CLOSE 0x00000001
-#define OBJ_HANDLE_ATTRIBUTES (OBJ_PROTECT_CLOSE | OBJ_INHERIT | OBJ_AUDIT_OBJECT_CLOSE)
-
-// This attribute is now stored in the GrantedAccess field.
-#define ObpAccessProtectCloseBit 0x2000000
-
-#define ObpDecodeGrantedAccess(Access) \
- ((Access) & ~ObpAccessProtectCloseBit)
-
-FORCEINLINE PVOID ObpDecodeObject(PVOID Object)
-{
-#ifdef _M_X64
- if (KphDynNtVersion >= PHNT_WIN8)
- {
- if (KphDynObDecodeShift != -1)
- return (PVOID)(((LONG_PTR)Object >> KphDynObDecodeShift) & ~(ULONG_PTR)0xf);
- else
- return NULL;
- }
- else
- {
- return (PVOID)((ULONG_PTR)Object & ~OBJ_HANDLE_ATTRIBUTES);
- }
-#else
- return (PVOID)((ULONG_PTR)Object & ~OBJ_HANDLE_ATTRIBUTES);
-#endif
-}
-
-FORCEINLINE ULONG ObpGetHandleAttributes(PHANDLE_TABLE_ENTRY HandleTableEntry)
-{
-#ifdef _M_X64
- if (KphDynNtVersion >= PHNT_WIN8)
- {
- if (KphDynObAttributesShift != -1)
- return (ULONG)(HandleTableEntry->Value >> KphDynObAttributesShift) & 0x3;
- else
- return 0;
- }
- else
- {
- return (HandleTableEntry->ObAttributes & (OBJ_INHERIT | OBJ_AUDIT_OBJECT_CLOSE)) |
- ((HandleTableEntry->GrantedAccess & ObpAccessProtectCloseBit) ? OBJ_PROTECT_CLOSE : 0);
- }
-#else
- return (HandleTableEntry->ObAttributes & (OBJ_INHERIT | OBJ_AUDIT_OBJECT_CLOSE)) |
- ((HandleTableEntry->GrantedAccess & ObpAccessProtectCloseBit) ? OBJ_PROTECT_CLOSE : 0);
-#endif
-}
-
-typedef struct _OBJECT_CREATE_INFORMATION OBJECT_CREATE_INFORMATION, *POBJECT_CREATE_INFORMATION;
-
-// This is incorrect as of Windows 8.1, but the size of the structure is still correct.
-typedef struct _OBJECT_HEADER
-{
- LONG PointerCount;
- union
- {
- LONG HandleCount;
- PVOID NextToFree;
- };
- POBJECT_TYPE Type;
- UCHAR NameInfoOffset;
- UCHAR HandleInfoOffset;
- UCHAR QuotaInfoOffset;
- UCHAR Flags;
- union
- {
- POBJECT_CREATE_INFORMATION ObjectCreateInfo;
- PVOID QuotaBlockCharged;
- };
- PVOID SecurityDescriptor;
- QUAD Body;
-} OBJECT_HEADER, *POBJECT_HEADER;
-
-#define OBJECT_TO_OBJECT_HEADER(Object) CONTAINING_RECORD((Object), OBJECT_HEADER, Body)
-
-NTKERNELAPI
-POBJECT_TYPE
-NTAPI
-ObGetObjectType(
- __in PVOID Object
- );
-
-NTKERNELAPI
-NTSTATUS
-NTAPI
-ObOpenObjectByName(
- __in POBJECT_ATTRIBUTES ObjectAttributes,
- __in POBJECT_TYPE ObjectType,
- __in KPROCESSOR_MODE PreviousMode,
- __in_opt PACCESS_STATE AccessState,
- __in_opt ACCESS_MASK DesiredAccess,
- __in PVOID ParseContext,
- __out PHANDLE Handle
- );
-
-NTKERNELAPI
-NTSTATUS
-NTAPI
-ObSetHandleAttributes(
- __in HANDLE Handle,
- __in POBJECT_HANDLE_FLAG_INFORMATION HandleFlags,
- __in KPROCESSOR_MODE PreviousMode
- );
-
-NTKERNELAPI
-NTSTATUS
-ObCloseHandle(
- __in HANDLE Handle,
- __in KPROCESSOR_MODE PreviousMode
- );
-
-// PS
-
-NTSYSCALLAPI
-NTSTATUS
-NTAPI
-ZwQueryInformationProcess(
- __in HANDLE ProcessHandle,
- __in PROCESSINFOCLASS ProcessInformationClass,
- __out_bcount(ProcessInformationLength) PVOID ProcessInformation,
- __in ULONG ProcessInformationLength,
- __out_opt PULONG ReturnLength
- );
-
-NTSYSCALLAPI
-NTSTATUS
-NTAPI
-ZwSetInformationProcess(
- __in HANDLE ProcessHandle,
- __in PROCESSINFOCLASS ProcessInformationClass,
- __in_bcount(ProcessInformationLength) PVOID ProcessInformation,
- __in ULONG ProcessInformationLength
- );
-
-NTSYSCALLAPI
-NTSTATUS
-NTAPI
-ZwQueryInformationThread(
- __in HANDLE ThreadHandle,
- __in THREADINFOCLASS ThreadInformationClass,
- __out_bcount(ThreadInformationLength) PVOID ThreadInformation,
- __in ULONG ThreadInformationLength,
- __out_opt PULONG ReturnLength
- );
-
-NTKERNELAPI
-NTSTATUS
-NTAPI
-PsLookupProcessThreadByCid(
- __in PCLIENT_ID ClientId,
- __out_opt PEPROCESS *Process,
- __out PETHREAD *Thread
- );
-
-NTKERNELAPI
-PVOID
-NTAPI
-PsGetThreadWin32Thread(
- __in PETHREAD Thread
- );
-
-typedef struct _EJOB *PEJOB;
-
-extern POBJECT_TYPE *PsJobType;
-
-NTKERNELAPI
-PEJOB
-NTAPI
-PsGetProcessJob(
- __in PEPROCESS Process
- );
-
-NTKERNELAPI
-NTSTATUS
-NTAPI
-PsAcquireProcessExitSynchronization(
- __in PEPROCESS Process
- );
-
-NTKERNELAPI
-VOID
-NTAPI
-PsReleaseProcessExitSynchronization(
- __in PEPROCESS Process
- );
-
-// RTL
-
-// Sensible limit that may or may not correspond to the actual Windows value.
-#define MAX_STACK_DEPTH 256
-
-#define RTL_WALK_USER_MODE_STACK 0x00000001
-#define RTL_WALK_VALID_FLAGS 0x00000001
-
-NTSYSAPI
-ULONG
-NTAPI
-RtlWalkFrameChain(
- __out PVOID *Callers,
- __in ULONG Count,
- __in ULONG Flags
- );
-
-#endif
+#ifndef NTFILL_H
+#define NTFILL_H
+
+extern ULONG KphDynNtVersion;
+extern ULONG KphDynObDecodeShift;
+extern ULONG KphDynObAttributesShift;
+
+// EX
+
+typedef struct _EX_PUSH_LOCK_WAIT_BLOCK *PEX_PUSH_LOCK_WAIT_BLOCK;
+
+NTKERNELAPI
+VOID
+FASTCALL
+ExfUnblockPushLock(
+ _Inout_ PEX_PUSH_LOCK PushLock,
+ _Inout_opt_ PEX_PUSH_LOCK_WAIT_BLOCK WaitBlock
+ );
+
+typedef struct _HANDLE_TABLE_ENTRY
+{
+ union
+ {
+ PVOID Object;
+ ULONG ObAttributes;
+ ULONG_PTR Value;
+ };
+ union
+ {
+ ACCESS_MASK GrantedAccess;
+ LONG NextFreeTableEntry;
+ };
+} HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;
+
+typedef struct _HANDLE_TABLE HANDLE_TABLE, *PHANDLE_TABLE;
+
+typedef BOOLEAN (NTAPI *PEX_ENUM_HANDLE_CALLBACK_61)(
+ _Inout_ PHANDLE_TABLE_ENTRY HandleTableEntry,
+ _In_ HANDLE Handle,
+ _In_ PVOID Context
+ );
+
+// since WIN8
+typedef BOOLEAN (NTAPI *PEX_ENUM_HANDLE_CALLBACK)(
+ _In_ PHANDLE_TABLE HandleTable,
+ _Inout_ PHANDLE_TABLE_ENTRY HandleTableEntry,
+ _In_ HANDLE Handle,
+ _In_ PVOID Context
+ );
+
+NTKERNELAPI
+BOOLEAN
+NTAPI
+ExEnumHandleTable(
+ _In_ PHANDLE_TABLE HandleTable,
+ _In_ PEX_ENUM_HANDLE_CALLBACK EnumHandleProcedure,
+ _Inout_ PVOID Context,
+ _Out_opt_ PHANDLE Handle
+ );
+
+NTSYSCALLAPI
+NTSTATUS
+NTAPI
+ZwQuerySystemInformation(
+ _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,
+ _Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation,
+ _In_ ULONG SystemInformationLength,
+ _Out_opt_ PULONG ReturnLength
+ );
+
+// IO
+
+extern POBJECT_TYPE *IoDriverObjectType;
+
+// KE
+
+typedef enum _KAPC_ENVIRONMENT
+{
+ OriginalApcEnvironment,
+ AttachedApcEnvironment,
+ CurrentApcEnvironment,
+ InsertApcEnvironment
+} KAPC_ENVIRONMENT, *PKAPC_ENVIRONMENT;
+
+typedef VOID (NTAPI *PKNORMAL_ROUTINE)(
+ _In_ PVOID NormalContext,
+ _In_ PVOID SystemArgument1,
+ _In_ PVOID SystemArgument2
+ );
+
+typedef VOID KKERNEL_ROUTINE(
+ _In_ PRKAPC Apc,
+ _Inout_ PKNORMAL_ROUTINE *NormalRoutine,
+ _Inout_ PVOID *NormalContext,
+ _Inout_ PVOID *SystemArgument1,
+ _Inout_ PVOID *SystemArgument2
+ );
+
+typedef KKERNEL_ROUTINE (NTAPI *PKKERNEL_ROUTINE);
+
+typedef VOID (NTAPI *PKRUNDOWN_ROUTINE)(
+ _In_ PRKAPC Apc
+ );
+
+NTKERNELAPI
+VOID
+NTAPI
+KeInitializeApc(
+ _Out_ PRKAPC Apc,
+ _In_ PRKTHREAD Thread,
+ _In_ KAPC_ENVIRONMENT Environment,
+ _In_ PKKERNEL_ROUTINE KernelRoutine,
+ _In_opt_ PKRUNDOWN_ROUTINE RundownRoutine,
+ _In_opt_ PKNORMAL_ROUTINE NormalRoutine,
+ _In_opt_ KPROCESSOR_MODE ProcessorMode,
+ _In_opt_ PVOID NormalContext
+ );
+
+NTKERNELAPI
+BOOLEAN
+NTAPI
+KeInsertQueueApc(
+ _Inout_ PRKAPC Apc,
+ _In_opt_ PVOID SystemArgument1,
+ _In_opt_ PVOID SystemArgument2,
+ _In_ KPRIORITY Increment
+ );
+
+// OB
+
+// These definitions are no longer correct, but they produce correct results.
+
+#define OBJ_PROTECT_CLOSE 0x00000001
+#define OBJ_HANDLE_ATTRIBUTES (OBJ_PROTECT_CLOSE | OBJ_INHERIT | OBJ_AUDIT_OBJECT_CLOSE)
+
+// This attribute is now stored in the GrantedAccess field.
+#define ObpAccessProtectCloseBit 0x2000000
+
+#define ObpDecodeGrantedAccess(Access) \
+ ((Access) & ~ObpAccessProtectCloseBit)
+
+FORCEINLINE PVOID ObpDecodeObject(PVOID Object)
+{
+#ifdef _M_X64
+ if (KphDynNtVersion >= PHNT_WIN8)
+ {
+ if (KphDynObDecodeShift != -1)
+ return (PVOID)(((LONG_PTR)Object >> KphDynObDecodeShift) & ~(ULONG_PTR)0xf);
+ else
+ return NULL;
+ }
+ else
+ {
+ return (PVOID)((ULONG_PTR)Object & ~OBJ_HANDLE_ATTRIBUTES);
+ }
+#else
+ return (PVOID)((ULONG_PTR)Object & ~OBJ_HANDLE_ATTRIBUTES);
+#endif
+}
+
+FORCEINLINE ULONG ObpGetHandleAttributes(PHANDLE_TABLE_ENTRY HandleTableEntry)
+{
+#ifdef _M_X64
+ if (KphDynNtVersion >= PHNT_WIN8)
+ {
+ if (KphDynObAttributesShift != -1)
+ return (ULONG)(HandleTableEntry->Value >> KphDynObAttributesShift) & 0x3;
+ else
+ return 0;
+ }
+ else
+ {
+ return (HandleTableEntry->ObAttributes & (OBJ_INHERIT | OBJ_AUDIT_OBJECT_CLOSE)) |
+ ((HandleTableEntry->GrantedAccess & ObpAccessProtectCloseBit) ? OBJ_PROTECT_CLOSE : 0);
+ }
+#else
+ return (HandleTableEntry->ObAttributes & (OBJ_INHERIT | OBJ_AUDIT_OBJECT_CLOSE)) |
+ ((HandleTableEntry->GrantedAccess & ObpAccessProtectCloseBit) ? OBJ_PROTECT_CLOSE : 0);
+#endif
+}
+
+typedef struct _OBJECT_CREATE_INFORMATION OBJECT_CREATE_INFORMATION, *POBJECT_CREATE_INFORMATION;
+
+// This structure is not correct on Windows 7, but the offsets we need are still correct.
+typedef struct _OBJECT_HEADER
+{
+ LONG PointerCount;
+ union
+ {
+ LONG HandleCount;
+ PVOID NextToFree;
+ };
+ EX_PUSH_LOCK Lock;
+ UCHAR TypeIndex;
+ union
+ {
+ UCHAR TraceFlags;
+ struct
+ {
+ UCHAR DbgRefTrace : 1;
+ UCHAR DbgTracePermanent : 1;
+ UCHAR Reserved : 6;
+ };
+ };
+ UCHAR InfoMask;
+ union
+ {
+ UCHAR Flags;
+ struct
+ {
+ UCHAR NewObject : 1;
+ UCHAR KernelObject : 1;
+ UCHAR KernelOnlyAccess : 1;
+ UCHAR ExclusiveObject : 1;
+ UCHAR PermanentObject : 1;
+ UCHAR DefaultSecurityQuota : 1;
+ UCHAR SingleHandleEntry : 1;
+ UCHAR DeletedInline : 1;
+ };
+ };
+ union
+ {
+ POBJECT_CREATE_INFORMATION ObjectCreateInfo;
+ PVOID QuotaBlockCharged;
+ };
+ PVOID SecurityDescriptor;
+ QUAD Body;
+} OBJECT_HEADER, *POBJECT_HEADER;
+
+#ifdef _M_X64
+C_ASSERT(FIELD_OFFSET(OBJECT_HEADER, Body) == 0x030);
+C_ASSERT(sizeof(OBJECT_HEADER) == 0x038);
+#else
+C_ASSERT(FIELD_OFFSET(OBJECT_HEADER, Body) == 0x018);
+C_ASSERT(sizeof(OBJECT_HEADER) == 0x020);
+#endif
+
+#define OBJECT_TO_OBJECT_HEADER(Object) CONTAINING_RECORD((Object), OBJECT_HEADER, Body)
+
+NTKERNELAPI
+POBJECT_TYPE
+NTAPI
+ObGetObjectType(
+ _In_ PVOID Object
+ );
+
+NTKERNELAPI
+NTSTATUS
+NTAPI
+ObOpenObjectByName(
+ _In_ POBJECT_ATTRIBUTES ObjectAttributes,
+ _In_ POBJECT_TYPE ObjectType,
+ _In_ KPROCESSOR_MODE PreviousMode,
+ _In_opt_ PACCESS_STATE AccessState,
+ _In_opt_ ACCESS_MASK DesiredAccess,
+ _In_opt_ PVOID ParseContext,
+ _Out_ PHANDLE Handle
+ );
+
+NTKERNELAPI
+NTSTATUS
+NTAPI
+ObSetHandleAttributes(
+ _In_ HANDLE Handle,
+ _In_ POBJECT_HANDLE_FLAG_INFORMATION HandleFlags,
+ _In_ KPROCESSOR_MODE PreviousMode
+ );
+
+// PS
+
+NTSYSCALLAPI
+NTSTATUS
+NTAPI
+ZwQueryInformationProcess(
+ _In_ HANDLE ProcessHandle,
+ _In_ PROCESSINFOCLASS ProcessInformationClass,
+ _Out_writes_bytes_(ProcessInformationLength) PVOID ProcessInformation,
+ _In_ ULONG ProcessInformationLength,
+ _Out_opt_ PULONG ReturnLength
+ );
+
+NTSYSCALLAPI
+NTSTATUS
+NTAPI
+ZwQueryInformationThread(
+ _In_ HANDLE ThreadHandle,
+ _In_ THREADINFOCLASS ThreadInformationClass,
+ _Out_writes_bytes_(ThreadInformationLength) PVOID ThreadInformation,
+ _In_ ULONG ThreadInformationLength,
+ _Out_opt_ PULONG ReturnLength
+ );
+
+NTKERNELAPI
+NTSTATUS
+NTAPI
+PsLookupProcessThreadByCid(
+ _In_ PCLIENT_ID ClientId,
+ _Out_opt_ PEPROCESS *Process,
+ _Out_ PETHREAD *Thread
+ );
+
+typedef struct _EJOB *PEJOB;
+
+extern POBJECT_TYPE *PsJobType;
+
+NTKERNELAPI
+PEJOB
+NTAPI
+PsGetProcessJob(
+ _In_ PEPROCESS Process
+ );
+
+NTKERNELAPI
+NTSTATUS
+NTAPI
+PsAcquireProcessExitSynchronization(
+ _In_ PEPROCESS Process
+ );
+
+NTKERNELAPI
+VOID
+NTAPI
+PsReleaseProcessExitSynchronization(
+ _In_ PEPROCESS Process
+ );
+
+// RTL
+
+// Sensible limit that may or may not correspond to the actual Windows value.
+#define MAX_STACK_DEPTH 256
+
+#define RTL_WALK_USER_MODE_STACK 0x00000001
+#define RTL_WALK_VALID_FLAGS 0x00000001
+
+#endif
diff --git a/KProcessHacker/main.c b/KProcessHacker/main.c
index d4eef0fc45b1..c2696cdee21f 100644
--- a/KProcessHacker/main.c
+++ b/KProcessHacker/main.c
@@ -1,356 +1,358 @@
-/*
- * KProcessHacker
- *
- * Copyright (C) 2010-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 .
- */
-
-#include
-#include
-
-DRIVER_INITIALIZE DriverEntry;
-DRIVER_UNLOAD DriverUnload;
-__drv_dispatchType(IRP_MJ_CREATE) DRIVER_DISPATCH KphDispatchCreate;
-__drv_dispatchType(IRP_MJ_CLOSE) DRIVER_DISPATCH KphDispatchClose;
-
-ULONG KphpReadIntegerParameter(
- __in_opt HANDLE KeyHandle,
- __in PUNICODE_STRING ValueName,
- __in ULONG DefaultValue
- );
-
-NTSTATUS KphpReadDriverParameters(
- __in PUNICODE_STRING RegistryPath
- );
-
-#ifdef ALLOC_PRAGMA
-#pragma alloc_text(PAGE, DriverEntry)
-#pragma alloc_text(PAGE, DriverUnload)
-#pragma alloc_text(PAGE, KphpReadIntegerParameter)
-#pragma alloc_text(PAGE, KphpReadDriverParameters)
-#pragma alloc_text(PAGE, KpiGetFeatures)
-#endif
-
-PDRIVER_OBJECT KphDriverObject;
-PDEVICE_OBJECT KphDeviceObject;
-ULONG KphFeatures;
-KPH_PARAMETERS KphParameters;
-
-NTSTATUS DriverEntry(
- __in PDRIVER_OBJECT DriverObject,
- __in PUNICODE_STRING RegistryPath
- )
-{
- NTSTATUS status;
- UNICODE_STRING deviceName;
- PDEVICE_OBJECT deviceObject;
-
- PAGED_CODE();
-
- KphDriverObject = DriverObject;
-
- if (!NT_SUCCESS(status = KphDynamicDataInitialization()))
- return status;
-
- KphDynamicImport();
-
- if (!NT_SUCCESS(status = KphpReadDriverParameters(RegistryPath)))
- return status;
-
- // Create the device.
-
- RtlInitUnicodeString(&deviceName, KPH_DEVICE_NAME);
-
- status = IoCreateDevice(
- DriverObject,
- 0,
- &deviceName,
- FILE_DEVICE_UNKNOWN,
- FILE_DEVICE_SECURE_OPEN,
- FALSE,
- &deviceObject
- );
-
- if (!NT_SUCCESS(status))
- return status;
-
- KphDeviceObject = deviceObject;
-
- // Set up I/O.
-
- DriverObject->MajorFunction[IRP_MJ_CREATE] = KphDispatchCreate;
- DriverObject->MajorFunction[IRP_MJ_CLOSE] = KphDispatchClose;
- DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KphDispatchDeviceControl;
- DriverObject->DriverUnload = DriverUnload;
-
- deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
-
- dprintf("Driver loaded\n");
-
- return status;
-}
-
-VOID DriverUnload(
- __in PDRIVER_OBJECT DriverObject
- )
-{
- PAGED_CODE();
-
- IoDeleteDevice(KphDeviceObject);
-
- dprintf("Driver unloaded\n");
-}
-
-NTSTATUS KphDispatchCreate(
- __in PDEVICE_OBJECT DeviceObject,
- __in PIRP Irp
- )
-{
- NTSTATUS status = STATUS_SUCCESS;
- PIO_STACK_LOCATION stackLocation;
- PFILE_OBJECT fileObject;
- PIO_SECURITY_CONTEXT securityContext;
- PKPH_CLIENT client;
-
- stackLocation = IoGetCurrentIrpStackLocation(Irp);
- fileObject = stackLocation->FileObject;
- securityContext = stackLocation->Parameters.Create.SecurityContext;
-
- dprintf("Client (PID %Iu) is connecting\n", PsGetCurrentProcessId());
-
- if (KphParameters.SecurityLevel == KphSecurityPrivilegeCheck ||
- KphParameters.SecurityLevel == KphSecuritySignatureAndPrivilegeCheck)
- {
- UCHAR requiredPrivilegesBuffer[FIELD_OFFSET(PRIVILEGE_SET, Privilege) + sizeof(LUID_AND_ATTRIBUTES)];
- PPRIVILEGE_SET requiredPrivileges;
-
- // Check for SeDebugPrivilege.
-
- requiredPrivileges = (PPRIVILEGE_SET)requiredPrivilegesBuffer;
- requiredPrivileges->PrivilegeCount = 1;
- requiredPrivileges->Control = PRIVILEGE_SET_ALL_NECESSARY;
- requiredPrivileges->Privilege[0].Luid.LowPart = SE_DEBUG_PRIVILEGE;
- requiredPrivileges->Privilege[0].Luid.HighPart = 0;
- requiredPrivileges->Privilege[0].Attributes = 0;
-
- if (!SePrivilegeCheck(
- requiredPrivileges,
- &securityContext->AccessState->SubjectSecurityContext,
- Irp->RequestorMode
- ))
- {
- status = STATUS_PRIVILEGE_NOT_HELD;
- dprintf("Client (PID %Iu) was rejected\n", PsGetCurrentProcessId());
- }
- }
-
- if (NT_SUCCESS(status))
- {
- client = ExAllocatePoolWithTag(PagedPool, sizeof(KPH_CLIENT), 'ChpK');
-
- if (client)
- {
- memset(client, 0, sizeof(KPH_CLIENT));
-
- ExInitializeFastMutex(&client->StateMutex);
- ExInitializeFastMutex(&client->KeyBackoffMutex);
-
- fileObject->FsContext = client;
- }
- else
- {
- dprintf("Unable to allocate memory for client (PID %Iu)\n", PsGetCurrentProcessId());
- status = STATUS_INSUFFICIENT_RESOURCES;
- }
- }
-
- Irp->IoStatus.Status = status;
- Irp->IoStatus.Information = 0;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
-
- return status;
-}
-
-NTSTATUS KphDispatchClose(
- __in PDEVICE_OBJECT DeviceObject,
- __in PIRP Irp
- )
-{
- NTSTATUS status = STATUS_SUCCESS;
- PIO_STACK_LOCATION stackLocation;
- PFILE_OBJECT fileObject;
- PKPH_CLIENT client;
-
- stackLocation = IoGetCurrentIrpStackLocation(Irp);
- fileObject = stackLocation->FileObject;
- client = fileObject->FsContext;
-
- if (client)
- {
- ExFreePoolWithTag(client, 'ChpK');
- }
-
- Irp->IoStatus.Status = status;
- Irp->IoStatus.Information = 0;
- IoCompleteRequest(Irp, IO_NO_INCREMENT);
-
- return status;
-}
-
-/**
- * Reads an integer (REG_DWORD) parameter from the registry.
- *
- * \param KeyHandle A handle to the Parameters key. If NULL, the function
- * fails immediately and returns \a DefaultValue.
- * \param ValueName The name of the parameter.
- * \param DefaultValue The value that is returned if the function fails
- * to retrieve the parameter from the registry.
- *
- * \return The parameter value, or \a DefaultValue if the function failed.
- */
-ULONG KphpReadIntegerParameter(
- __in_opt HANDLE KeyHandle,
- __in PUNICODE_STRING ValueName,
- __in ULONG DefaultValue
- )
-{
- NTSTATUS status;
- UCHAR buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + sizeof(ULONG)];
- PKEY_VALUE_PARTIAL_INFORMATION info;
- ULONG resultLength;
-
- PAGED_CODE();
-
- if (!KeyHandle)
- return DefaultValue;
-
- info = (PKEY_VALUE_PARTIAL_INFORMATION)buffer;
-
- status = ZwQueryValueKey(
- KeyHandle,
- ValueName,
- KeyValuePartialInformation,
- info,
- sizeof(buffer),
- &resultLength
- );
-
- if (info->Type != REG_DWORD)
- status = STATUS_OBJECT_TYPE_MISMATCH;
-
- if (!NT_SUCCESS(status))
- {
- dprintf("Unable to query parameter %.*S: 0x%x\n", ValueName->Length / sizeof(WCHAR), ValueName->Buffer, status);
- return DefaultValue;
- }
-
- return *(PULONG)info->Data;
-}
-
-/**
- * Reads the driver parameters.
- *
- * \param RegistryPath The registry path of the driver.
- */
-NTSTATUS KphpReadDriverParameters(
- __in PUNICODE_STRING RegistryPath
- )
-{
- NTSTATUS status;
- HANDLE parametersKeyHandle;
- UNICODE_STRING parametersString;
- UNICODE_STRING parametersKeyName;
- OBJECT_ATTRIBUTES objectAttributes;
- UNICODE_STRING valueName;
-
- PAGED_CODE();
-
- // Open the Parameters key.
-
- RtlInitUnicodeString(¶metersString, L"\\Parameters");
-
- parametersKeyName.Length = RegistryPath->Length + parametersString.Length;
- parametersKeyName.MaximumLength = parametersKeyName.Length;
- parametersKeyName.Buffer = ExAllocatePoolWithTag(PagedPool, parametersKeyName.MaximumLength, 'ThpK');
-
- if (!parametersKeyName.Buffer)
- return STATUS_INSUFFICIENT_RESOURCES;
-
- memcpy(parametersKeyName.Buffer, RegistryPath->Buffer, RegistryPath->Length);
- memcpy(¶metersKeyName.Buffer[RegistryPath->Length / sizeof(WCHAR)], parametersString.Buffer, parametersString.Length);
-
- InitializeObjectAttributes(
- &objectAttributes,
- ¶metersKeyName,
- OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
- NULL,
- NULL
- );
- status = ZwOpenKey(
- ¶metersKeyHandle,
- KEY_READ,
- &objectAttributes
- );
- ExFreePoolWithTag(parametersKeyName.Buffer, 'ThpK');
-
- if (!NT_SUCCESS(status))
- {
- dprintf("Unable to open Parameters key: 0x%x\n", status);
- status = STATUS_SUCCESS;
- parametersKeyHandle = NULL;
- // Continue so we can set up defaults.
- }
-
- // Read in the parameters.
-
- RtlInitUnicodeString(&valueName, L"SecurityLevel");
- KphParameters.SecurityLevel = KphpReadIntegerParameter(parametersKeyHandle, &valueName, KphSecurityPrivilegeCheck);
-
- KphReadDynamicDataParameters(parametersKeyHandle);
-
- if (parametersKeyHandle)
- ZwClose(parametersKeyHandle);
-
- return status;
-}
-
-NTSTATUS KpiGetFeatures(
- __out PULONG Features,
- __in KPROCESSOR_MODE AccessMode
- )
-{
- PAGED_CODE();
-
- if (AccessMode != KernelMode)
- {
- __try
- {
- ProbeForWrite(Features, sizeof(ULONG), sizeof(ULONG));
- *Features = KphFeatures;
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- return GetExceptionCode();
- }
- }
- else
- {
- *Features = KphFeatures;
- }
-
- return STATUS_SUCCESS;
-}
+/*
+ * KProcessHacker
+ *
+ * Copyright (C) 2010-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 .
+ */
+
+#include
+#include
+
+DRIVER_INITIALIZE DriverEntry;
+DRIVER_UNLOAD DriverUnload;
+_Dispatch_type_(IRP_MJ_CREATE) DRIVER_DISPATCH KphDispatchCreate;
+_Dispatch_type_(IRP_MJ_CLOSE) DRIVER_DISPATCH KphDispatchClose;
+
+ULONG KphpReadIntegerParameter(
+ _In_opt_ HANDLE KeyHandle,
+ _In_ PUNICODE_STRING ValueName,
+ _In_ ULONG DefaultValue
+ );
+
+NTSTATUS KphpReadDriverParameters(
+ _In_ PUNICODE_STRING RegistryPath
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, DriverEntry)
+#pragma alloc_text(PAGE, DriverUnload)
+#pragma alloc_text(PAGE, KphpReadIntegerParameter)
+#pragma alloc_text(PAGE, KphpReadDriverParameters)
+#pragma alloc_text(PAGE, KpiGetFeatures)
+#endif
+
+PDRIVER_OBJECT KphDriverObject;
+PDEVICE_OBJECT KphDeviceObject;
+ULONG KphFeatures;
+KPH_PARAMETERS KphParameters;
+
+NTSTATUS DriverEntry(
+ _In_ PDRIVER_OBJECT DriverObject,
+ _In_ PUNICODE_STRING RegistryPath
+ )
+{
+ NTSTATUS status;
+ UNICODE_STRING deviceName;
+ PDEVICE_OBJECT deviceObject;
+
+ PAGED_CODE();
+
+ ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
+
+ KphDriverObject = DriverObject;
+
+ if (!NT_SUCCESS(status = KphDynamicDataInitialization()))
+ return status;
+
+ KphDynamicImport();
+
+ if (!NT_SUCCESS(status = KphpReadDriverParameters(RegistryPath)))
+ return status;
+
+ // Create the device.
+
+ RtlInitUnicodeString(&deviceName, KPH_DEVICE_NAME);
+
+ status = IoCreateDevice(
+ DriverObject,
+ 0,
+ &deviceName,
+ FILE_DEVICE_UNKNOWN,
+ FILE_DEVICE_SECURE_OPEN,
+ FALSE,
+ &deviceObject
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ KphDeviceObject = deviceObject;
+
+ // Set up I/O.
+
+ DriverObject->MajorFunction[IRP_MJ_CREATE] = KphDispatchCreate;
+ DriverObject->MajorFunction[IRP_MJ_CLOSE] = KphDispatchClose;
+ DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KphDispatchDeviceControl;
+ DriverObject->DriverUnload = DriverUnload;
+
+ deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+
+ dprintf("Driver loaded\n");
+
+ return status;
+}
+
+VOID DriverUnload(
+ _In_ PDRIVER_OBJECT DriverObject
+ )
+{
+ PAGED_CODE();
+
+ IoDeleteDevice(KphDeviceObject);
+
+ dprintf("Driver unloaded\n");
+}
+
+NTSTATUS KphDispatchCreate(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _Inout_ PIRP Irp
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PIO_STACK_LOCATION stackLocation;
+ PFILE_OBJECT fileObject;
+ PIO_SECURITY_CONTEXT securityContext;
+ PKPH_CLIENT client;
+
+ stackLocation = IoGetCurrentIrpStackLocation(Irp);
+ fileObject = stackLocation->FileObject;
+ securityContext = stackLocation->Parameters.Create.SecurityContext;
+
+ dprintf("Client (PID %Iu) is connecting\n", PsGetCurrentProcessId());
+
+ if (KphParameters.SecurityLevel == KphSecurityPrivilegeCheck ||
+ KphParameters.SecurityLevel == KphSecuritySignatureAndPrivilegeCheck)
+ {
+ UCHAR requiredPrivilegesBuffer[FIELD_OFFSET(PRIVILEGE_SET, Privilege) + sizeof(LUID_AND_ATTRIBUTES)];
+ PPRIVILEGE_SET requiredPrivileges;
+
+ // Check for SeDebugPrivilege.
+
+ requiredPrivileges = (PPRIVILEGE_SET)requiredPrivilegesBuffer;
+ requiredPrivileges->PrivilegeCount = 1;
+ requiredPrivileges->Control = PRIVILEGE_SET_ALL_NECESSARY;
+ requiredPrivileges->Privilege[0].Luid.LowPart = SE_DEBUG_PRIVILEGE;
+ requiredPrivileges->Privilege[0].Luid.HighPart = 0;
+ requiredPrivileges->Privilege[0].Attributes = 0;
+
+ if (!SePrivilegeCheck(
+ requiredPrivileges,
+ &securityContext->AccessState->SubjectSecurityContext,
+ Irp->RequestorMode
+ ))
+ {
+ status = STATUS_PRIVILEGE_NOT_HELD;
+ dprintf("Client (PID %Iu) was rejected\n", PsGetCurrentProcessId());
+ }
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ client = ExAllocatePoolWithTag(PagedPool, sizeof(KPH_CLIENT), 'ChpK');
+
+ if (client)
+ {
+ memset(client, 0, sizeof(KPH_CLIENT));
+
+ ExInitializeFastMutex(&client->StateMutex);
+ ExInitializeFastMutex(&client->KeyBackoffMutex);
+
+ fileObject->FsContext = client;
+ }
+ else
+ {
+ dprintf("Unable to allocate memory for client (PID %Iu)\n", PsGetCurrentProcessId());
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ Irp->IoStatus.Status = status;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+NTSTATUS KphDispatchClose(
+ _In_ PDEVICE_OBJECT DeviceObject,
+ _Inout_ PIRP Irp
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PIO_STACK_LOCATION stackLocation;
+ PFILE_OBJECT fileObject;
+ PKPH_CLIENT client;
+
+ stackLocation = IoGetCurrentIrpStackLocation(Irp);
+ fileObject = stackLocation->FileObject;
+ client = fileObject->FsContext;
+
+ if (client)
+ {
+ ExFreePoolWithTag(client, 'ChpK');
+ }
+
+ Irp->IoStatus.Status = status;
+ Irp->IoStatus.Information = 0;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+/**
+ * Reads an integer (REG_DWORD) parameter from the registry.
+ *
+ * \param KeyHandle A handle to the Parameters key. If NULL, the function
+ * fails immediately and returns \a DefaultValue.
+ * \param ValueName The name of the parameter.
+ * \param DefaultValue The value that is returned if the function fails
+ * to retrieve the parameter from the registry.
+ *
+ * \return The parameter value, or \a DefaultValue if the function failed.
+ */
+ULONG KphpReadIntegerParameter(
+ _In_opt_ HANDLE KeyHandle,
+ _In_ PUNICODE_STRING ValueName,
+ _In_ ULONG DefaultValue
+ )
+{
+ NTSTATUS status;
+ UCHAR buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + sizeof(ULONG)];
+ PKEY_VALUE_PARTIAL_INFORMATION info;
+ ULONG resultLength;
+
+ PAGED_CODE();
+
+ if (!KeyHandle)
+ return DefaultValue;
+
+ info = (PKEY_VALUE_PARTIAL_INFORMATION)buffer;
+
+ status = ZwQueryValueKey(
+ KeyHandle,
+ ValueName,
+ KeyValuePartialInformation,
+ info,
+ sizeof(buffer),
+ &resultLength
+ );
+
+ if (info->Type != REG_DWORD)
+ status = STATUS_OBJECT_TYPE_MISMATCH;
+
+ if (!NT_SUCCESS(status))
+ {
+ dprintf("Unable to query parameter %.*S: 0x%x\n", ValueName->Length / sizeof(WCHAR), ValueName->Buffer, status);
+ return DefaultValue;
+ }
+
+ return *(PULONG)info->Data;
+}
+
+/**
+ * Reads the driver parameters.
+ *
+ * \param RegistryPath The registry path of the driver.
+ */
+NTSTATUS KphpReadDriverParameters(
+ _In_ PUNICODE_STRING RegistryPath
+ )
+{
+ NTSTATUS status;
+ HANDLE parametersKeyHandle;
+ UNICODE_STRING parametersString;
+ UNICODE_STRING parametersKeyName;
+ OBJECT_ATTRIBUTES objectAttributes;
+ UNICODE_STRING valueName;
+
+ PAGED_CODE();
+
+ // Open the Parameters key.
+
+ RtlInitUnicodeString(¶metersString, L"\\Parameters");
+
+ parametersKeyName.Length = RegistryPath->Length + parametersString.Length;
+ parametersKeyName.MaximumLength = parametersKeyName.Length;
+ parametersKeyName.Buffer = ExAllocatePoolWithTag(PagedPool, parametersKeyName.MaximumLength, 'ThpK');
+
+ if (!parametersKeyName.Buffer)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ memcpy(parametersKeyName.Buffer, RegistryPath->Buffer, RegistryPath->Length);
+ memcpy(¶metersKeyName.Buffer[RegistryPath->Length / sizeof(WCHAR)], parametersString.Buffer, parametersString.Length);
+
+ InitializeObjectAttributes(
+ &objectAttributes,
+ ¶metersKeyName,
+ OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+ NULL,
+ NULL
+ );
+ status = ZwOpenKey(
+ ¶metersKeyHandle,
+ KEY_READ,
+ &objectAttributes
+ );
+ ExFreePoolWithTag(parametersKeyName.Buffer, 'ThpK');
+
+ if (!NT_SUCCESS(status))
+ {
+ dprintf("Unable to open Parameters key: 0x%x\n", status);
+ status = STATUS_SUCCESS;
+ parametersKeyHandle = NULL;
+ // Continue so we can set up defaults.
+ }
+
+ // Read in the parameters.
+
+ RtlInitUnicodeString(&valueName, L"SecurityLevel");
+ KphParameters.SecurityLevel = KphpReadIntegerParameter(parametersKeyHandle, &valueName, KphSecurityPrivilegeCheck);
+
+ KphReadDynamicDataParameters(parametersKeyHandle);
+
+ if (parametersKeyHandle)
+ ZwClose(parametersKeyHandle);
+
+ return status;
+}
+
+NTSTATUS KpiGetFeatures(
+ _Out_ PULONG Features,
+ _In_ KPROCESSOR_MODE AccessMode
+ )
+{
+ PAGED_CODE();
+
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ ProbeForWrite(Features, sizeof(ULONG), sizeof(ULONG));
+ *Features = KphFeatures;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+ }
+ else
+ {
+ *Features = KphFeatures;
+ }
+
+ return STATUS_SUCCESS;
+}
diff --git a/KProcessHacker/object.c b/KProcessHacker/object.c
index 65e30548cfb3..704fd90dea58 100644
--- a/KProcessHacker/object.c
+++ b/KProcessHacker/object.c
@@ -1,1293 +1,1293 @@
-/*
- * KProcessHacker
- *
- * Copyright (C) 2010-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 .
- */
-
-#include
-#include
-
-#ifdef _X86_
-#define KERNEL_HANDLE_BIT (0x80000000)
-#else
-#define KERNEL_HANDLE_BIT (0xffffffff80000000)
-#endif
-
-#define IsKernelHandle(Handle) ((LONG_PTR)(Handle) < 0)
-#define MakeKernelHandle(Handle) ((HANDLE)((ULONG_PTR)(Handle) | KERNEL_HANDLE_BIT))
-
-typedef struct _KPHP_ENUMERATE_PROCESS_HANDLES_CONTEXT
-{
- PVOID Buffer;
- PVOID BufferLimit;
- PVOID CurrentEntry;
- ULONG Count;
- NTSTATUS Status;
-} KPHP_ENUMERATE_PROCESS_HANDLES_CONTEXT, *PKPHP_ENUMERATE_PROCESS_HANDLES_CONTEXT;
-
-BOOLEAN KphpEnumerateProcessHandlesEnumCallback61(
- __inout PHANDLE_TABLE_ENTRY HandleTableEntry,
- __in HANDLE Handle,
- __in PVOID Context
- );
-
-BOOLEAN KphpEnumerateProcessHandlesEnumCallback(
- __in PHANDLE_TABLE HandleTable,
- __inout PHANDLE_TABLE_ENTRY HandleTableEntry,
- __in HANDLE Handle,
- __in PVOID Context
- );
-
-#ifdef ALLOC_PRAGMA
-#pragma alloc_text(PAGE, KphReferenceProcessHandleTable)
-#pragma alloc_text(PAGE, KphDereferenceProcessHandleTable)
-#pragma alloc_text(PAGE, KphUnlockHandleTableEntry)
-#pragma alloc_text(PAGE, KphpEnumerateProcessHandlesEnumCallback61)
-#pragma alloc_text(PAGE, KphpEnumerateProcessHandlesEnumCallback)
-#pragma alloc_text(PAGE, KpiEnumerateProcessHandles)
-#pragma alloc_text(PAGE, KphQueryNameObject)
-#pragma alloc_text(PAGE, KphQueryNameFileObject)
-#pragma alloc_text(PAGE, KpiQueryInformationObject)
-#pragma alloc_text(PAGE, KpiSetInformationObject)
-#pragma alloc_text(PAGE, KphOpenNamedObject)
-#endif
-
-/**
- * Gets a pointer to the handle table of a process.
- *
- * \param Process A process object.
- *
- * \return A pointer to the handle table, or NULL if the process is terminating or the request is
- * not supported. You must call KphDereferenceProcessHandleTable() when the handle table is no
- * longer needed.
- */
-PHANDLE_TABLE KphReferenceProcessHandleTable(
- __in PEPROCESS Process
- )
-{
- PHANDLE_TABLE handleTable = NULL;
-
- PAGED_CODE();
-
- // Fail if we don't have an offset.
- if (KphDynEpObjectTable == -1)
- return NULL;
-
- // Prevent the process from terminating and get its handle table.
- if (NT_SUCCESS(PsAcquireProcessExitSynchronization(Process)))
- {
- handleTable = *(PHANDLE_TABLE *)((ULONG_PTR)Process + KphDynEpObjectTable);
-
- if (!handleTable)
- PsReleaseProcessExitSynchronization(Process);
- }
-
- return handleTable;
-}
-
-/**
- * Dereferences the handle table of a process.
- *
- * \param Process A process object.
- */
-VOID KphDereferenceProcessHandleTable(
- __in PEPROCESS Process
- )
-{
- PAGED_CODE();
-
- PsReleaseProcessExitSynchronization(Process);
-}
-
-VOID KphUnlockHandleTableEntry(
- __in PHANDLE_TABLE HandleTable,
- __in PHANDLE_TABLE_ENTRY HandleTableEntry
- )
-{
- PEX_PUSH_LOCK handleContentionEvent;
-
- PAGED_CODE();
-
- // Set the unlocked bit.
-
-#ifdef _M_X64
- InterlockedExchangeAdd64(&HandleTableEntry->Value, 1);
-#else
- InterlockedExchangeAdd(&HandleTableEntry->Value, 1);
-#endif
-
- // Allow waiters to wake up.
-
- handleContentionEvent = (PEX_PUSH_LOCK)((ULONG_PTR)HandleTable + KphDynHtHandleContentionEvent);
-
- if (*(PULONG_PTR)handleContentionEvent != 0)
- ExfUnblockPushLock(handleContentionEvent, NULL);
-}
-
-BOOLEAN KphpEnumerateProcessHandlesEnumCallback61(
- __inout PHANDLE_TABLE_ENTRY HandleTableEntry,
- __in HANDLE Handle,
- __in PVOID Context
- )
-{
- PKPHP_ENUMERATE_PROCESS_HANDLES_CONTEXT context = Context;
- KPH_PROCESS_HANDLE handleInfo;
- POBJECT_HEADER objectHeader;
- POBJECT_TYPE objectType;
- PKPH_PROCESS_HANDLE entryInBuffer;
-
- PAGED_CODE();
-
- objectHeader = ObpDecodeObject(HandleTableEntry->Object);
- handleInfo.Handle = Handle;
- handleInfo.Object = objectHeader ? &objectHeader->Body : NULL;
- handleInfo.GrantedAccess = ObpDecodeGrantedAccess(HandleTableEntry->GrantedAccess);
- handleInfo.ObjectTypeIndex = -1;
- handleInfo.Reserved1 = 0;
- handleInfo.HandleAttributes = ObpGetHandleAttributes(HandleTableEntry);
- handleInfo.Reserved2 = 0;
-
- if (handleInfo.Object)
- {
- objectType = ObGetObjectType(handleInfo.Object);
-
- if (objectType && KphDynOtIndex != -1)
- handleInfo.ObjectTypeIndex = (USHORT)*(PUCHAR)((ULONG_PTR)objectType + KphDynOtIndex);
- }
-
- // Advance the current entry pointer regardless of whether the information will be written; this
- // will allow the parent function to report the correct return length.
- entryInBuffer = context->CurrentEntry;
- context->CurrentEntry = (PVOID)((ULONG_PTR)context->CurrentEntry + sizeof(KPH_PROCESS_HANDLE));
- context->Count++;
-
- // Only write if we have not exceeded the buffer length. Also check for a potential overflow (if
- // the process has an extremely large number of handles, the buffer pointer may wrap).
- if (
- (ULONG_PTR)entryInBuffer >= (ULONG_PTR)context->Buffer &&
- (ULONG_PTR)entryInBuffer + sizeof(KPH_PROCESS_HANDLE) <= (ULONG_PTR)context->BufferLimit
- )
- {
- __try
- {
- *entryInBuffer = handleInfo;
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- // Report an error.
- if (context->Status == STATUS_SUCCESS)
- context->Status = GetExceptionCode();
- }
- }
- else
- {
- // Report that the buffer is too small.
- if (context->Status == STATUS_SUCCESS)
- context->Status = STATUS_BUFFER_TOO_SMALL;
- }
-
- return FALSE;
-}
-
-BOOLEAN KphpEnumerateProcessHandlesEnumCallback(
- __in PHANDLE_TABLE HandleTable,
- __inout PHANDLE_TABLE_ENTRY HandleTableEntry,
- __in HANDLE Handle,
- __in PVOID Context
- )
-{
- BOOLEAN result;
-
- PAGED_CODE();
-
- result = KphpEnumerateProcessHandlesEnumCallback61(HandleTableEntry, Handle, Context);
- KphUnlockHandleTableEntry(HandleTable, HandleTableEntry);
-
- return result;
-}
-
-/**
- * Enumerates the handles of a process.
- *
- * \param ProcessHandle A handle to a process.
- * \param Buffer The buffer in which the handle information will be stored.
- * \param BufferLength The number of bytes available in \a Buffer.
- * \param ReturnLength A variable which receives the number of bytes required to be available in
- * \a Buffer.
- * \param AccessMode The mode in which to perform access checks.
- */
-NTSTATUS KpiEnumerateProcessHandles(
- __in HANDLE ProcessHandle,
- __out_bcount(BufferLength) PVOID Buffer,
- __in_opt ULONG BufferLength,
- __out_opt PULONG ReturnLength,
- __in KPROCESSOR_MODE AccessMode
- )
-{
- NTSTATUS status;
- BOOLEAN result;
- PEPROCESS process;
- PHANDLE_TABLE handleTable;
- KPHP_ENUMERATE_PROCESS_HANDLES_CONTEXT context;
-
- PAGED_CODE();
-
- if (KphDynNtVersion >= PHNT_WIN8 && KphDynHtHandleContentionEvent == -1)
- {
- return STATUS_NOT_SUPPORTED;
- }
-
- if (AccessMode != KernelMode)
- {
- __try
- {
- ProbeForWrite(Buffer, BufferLength, sizeof(ULONG));
-
- if (ReturnLength)
- ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG));
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- return GetExceptionCode();
- }
- }
-
- // Reference the process object.
- status = ObReferenceObjectByHandle(
- ProcessHandle,
- 0,
- *PsProcessType,
- AccessMode,
- &process,
- NULL
- );
-
- if (!NT_SUCCESS(status))
- return status;
-
- // Get its handle table.
- handleTable = KphReferenceProcessHandleTable(process);
-
- if (!handleTable)
- {
- ObDereferenceObject(process);
- return STATUS_UNSUCCESSFUL;
- }
-
- // Initialize the enumeration context.
- context.Buffer = Buffer;
- context.BufferLimit = (PVOID)((ULONG_PTR)Buffer + BufferLength);
- context.CurrentEntry = ((PKPH_PROCESS_HANDLE_INFORMATION)Buffer)->Handles;
- context.Count = 0;
- context.Status = STATUS_SUCCESS;
-
- // Enumerate the handles.
-
- if (KphDynNtVersion >= PHNT_WIN8)
- {
- result = ExEnumHandleTable(
- handleTable,
- KphpEnumerateProcessHandlesEnumCallback,
- &context,
- NULL
- );
- }
- else
- {
- result = ExEnumHandleTable(
- handleTable,
- (PEX_ENUM_HANDLE_CALLBACK)KphpEnumerateProcessHandlesEnumCallback61,
- &context,
- NULL
- );
- }
-
- KphDereferenceProcessHandleTable(process);
- ObDereferenceObject(process);
-
- // Write the number of handles if we can.
- if (BufferLength >= FIELD_OFFSET(KPH_PROCESS_HANDLE_INFORMATION, Handles))
- {
- if (AccessMode != KernelMode)
- {
- __try
- {
- ((PKPH_PROCESS_HANDLE_INFORMATION)Buffer)->HandleCount = context.Count;
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- return GetExceptionCode();
- }
- }
- else
- {
- ((PKPH_PROCESS_HANDLE_INFORMATION)Buffer)->HandleCount = context.Count;
- }
- }
-
- // Supply the return length if the caller wanted it.
- if (ReturnLength)
- {
- ULONG returnLength;
-
- // Note: if the CurrentEntry pointer wrapped, this will give the wrong return length.
- returnLength = (ULONG)((ULONG_PTR)context.CurrentEntry - (ULONG_PTR)Buffer);
-
- if (AccessMode != KernelMode)
- {
- __try
- {
- *ReturnLength = returnLength;
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- return GetExceptionCode();
- }
- }
- else
- {
- *ReturnLength = returnLength;
- }
- }
-
- return context.Status;
-}
-
-/**
- * Queries the name of an object.
- *
- * \param Object A pointer to an object.
- * \param Buffer The buffer in which the object name will be stored.
- * \param BufferLength The number of bytes available in \a Buffer.
- * \param ReturnLength A variable which receives the number of bytes required to be available in
- * \a Buffer.
- */
-NTSTATUS KphQueryNameObject(
- __in PVOID Object,
- __out_bcount(BufferLength) POBJECT_NAME_INFORMATION Buffer,
- __in ULONG BufferLength,
- __out PULONG ReturnLength
- )
-{
- NTSTATUS status;
- POBJECT_TYPE objectType;
-
- PAGED_CODE();
-
- objectType = ObGetObjectType(Object);
-
- // Check if we are going to hang when querying the object, and use
- // the special file object query function if needed.
- if (objectType == *IoFileObjectType &&
- (((PFILE_OBJECT)Object)->Busy || ((PFILE_OBJECT)Object)->Waiters))
- {
- status = KphQueryNameFileObject(Object, Buffer, BufferLength, ReturnLength);
- dprintf("KphQueryNameFileObject: status 0x%x\n", status);
- }
- else
- {
- status = ObQueryNameString(Object, Buffer, BufferLength, ReturnLength);
- dprintf("ObQueryNameString: status 0x%x\n", status);
- }
-
- // Make the error returns consistent.
- if (status == STATUS_BUFFER_OVERFLOW) // returned by I/O subsystem
- status = STATUS_BUFFER_TOO_SMALL;
- if (status == STATUS_INFO_LENGTH_MISMATCH) // returned by ObQueryNameString
- status = STATUS_BUFFER_TOO_SMALL;
-
- if (NT_SUCCESS(status))
- dprintf("KphQueryNameObject: %.*S\n", Buffer->Name.Length / sizeof(WCHAR), Buffer->Name.Buffer);
- else
- dprintf("KphQueryNameObject: status 0x%x\n", status);
-
- return status;
-}
-
-/**
- * Queries the name of a file object.
- *
- * \param FileObject A pointer to a file object.
- * \param Buffer The buffer in which the object name will be stored.
- * \param BufferLength The number of bytes available in \a Buffer.
- * \param ReturnLength A variable which receives the number of bytes required to be available in
- * \a Buffer.
- */
-NTSTATUS KphQueryNameFileObject(
- __in PFILE_OBJECT FileObject,
- __out_bcount(BufferLength) POBJECT_NAME_INFORMATION Buffer,
- __in ULONG BufferLength,
- __out PULONG ReturnLength
- )
-{
- NTSTATUS status = STATUS_SUCCESS;
- ULONG returnLength;
- PCHAR objectName;
- ULONG usedLength;
- ULONG subNameLength;
- PFILE_OBJECT relatedFileObject;
-
- PAGED_CODE();
-
- // We need at least the size of OBJECT_NAME_INFORMATION to continue.
- if (BufferLength < sizeof(OBJECT_NAME_INFORMATION))
- {
- *ReturnLength = sizeof(OBJECT_NAME_INFORMATION);
-
- return STATUS_BUFFER_TOO_SMALL;
- }
-
- // Assume failure.
- Buffer->Name.Length = 0;
- // We will place the object name directly after the UNICODE_STRING structure in the buffer.
- Buffer->Name.Buffer = (PWSTR)((ULONG_PTR)Buffer + sizeof(OBJECT_NAME_INFORMATION));
- // Retain a local pointer to the object name so we can manipulate the pointer.
- objectName = (PCHAR)Buffer->Name.Buffer;
- // A variable that keeps track of how much space we have used.
- usedLength = sizeof(OBJECT_NAME_INFORMATION);
-
- // Check if the file object has an associated device (e.g. "\Device\NamedPipe", "\Device\Mup").
- // We can use the user-supplied buffer for this since if the buffer isn't big enough, we can't
- // proceed anyway (we are going to use the name).
- if (FileObject->DeviceObject)
- {
- status = ObQueryNameString(
- FileObject->DeviceObject,
- Buffer,
- BufferLength,
- &returnLength
- );
-
- if (!NT_SUCCESS(status))
- {
- if (status == STATUS_INFO_LENGTH_MISMATCH)
- status = STATUS_BUFFER_TOO_SMALL;
-
- *ReturnLength = returnLength;
-
- return status;
- }
-
- // The UNICODE_STRING in the buffer is now filled in. We will append to the object name
- // later, so we need to fix the object name pointer by adding the length, in bytes, of the
- // device name string we just got.
- objectName += Buffer->Name.Length;
- usedLength += Buffer->Name.Length;
- }
-
- // Check if the file object has a file name component. If not, we can't do anything else, so we
- // just return the name we have already.
- if (!FileObject->FileName.Buffer)
- {
- *ReturnLength = usedLength;
-
- return STATUS_SUCCESS;
- }
-
- // The file object has a name. We need to walk up the file object chain and append the names of
- // the related file objects in reverse order. This means we need to calculate the total length
- // first.
-
- relatedFileObject = FileObject;
- subNameLength = 0;
-
- do
- {
- subNameLength += relatedFileObject->FileName.Length;
-
- // Avoid infinite loops.
- if (relatedFileObject == relatedFileObject->RelatedFileObject)
- break;
-
- relatedFileObject = relatedFileObject->RelatedFileObject;
- } while (relatedFileObject);
-
- usedLength += subNameLength;
-
- // Check if we have enough space to write the whole thing.
- if (usedLength > BufferLength)
- {
- *ReturnLength = usedLength;
-
- return STATUS_BUFFER_TOO_SMALL;
- }
-
- // We're ready to begin copying the names.
-
- // Add the name length because we're copying in reverse order.
- objectName += subNameLength;
-
- relatedFileObject = FileObject;
-
- do
- {
- objectName -= relatedFileObject->FileName.Length;
- memcpy(objectName, relatedFileObject->FileName.Buffer, relatedFileObject->FileName.Length);
-
- // Avoid infinite loops.
- if (relatedFileObject == relatedFileObject->RelatedFileObject)
- break;
-
- relatedFileObject = relatedFileObject->RelatedFileObject;
- } while (relatedFileObject);
-
- // Update the length.
- Buffer->Name.Length += (USHORT)subNameLength;
-
- // Pass the return length back.
- *ReturnLength = usedLength;
-
- return STATUS_SUCCESS;
-}
-
-/**
- * Queries object information.
- *
- * \param ProcessHandle A handle to a process.
- * \param Handle A handle which is present in the process referenced by \a ProcessHandle.
- * \param ObjectInformationClass The type of information to retrieve.
- * \param ObjectInformation The buffer in which the information will be stored.
- * \param ObjectInformationLength The number of bytes available in \a ObjectInformation.
- * \param ReturnLength A variable which receives the number of bytes required to be available in
- * \a ObjectInformation.
- * \param AccessMode The mode in which to perform access checks.
- */
-NTSTATUS KpiQueryInformationObject(
- __in HANDLE ProcessHandle,
- __in HANDLE Handle,
- __in KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass,
- __out_bcount(ObjectInformationLength) PVOID ObjectInformation,
- __in ULONG ObjectInformationLength,
- __out_opt PULONG ReturnLength,
- __in KPROCESSOR_MODE AccessMode
- )
-{
- NTSTATUS status;
- PEPROCESS process;
- KPROCESSOR_MODE referenceMode;
- KAPC_STATE apcState;
- ULONG returnLength;
-
- PAGED_CODE();
-
- if (AccessMode != KernelMode)
- {
- __try
- {
- ProbeForWrite(ObjectInformation, ObjectInformationLength, sizeof(ULONG));
-
- if (ReturnLength)
- ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG));
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- return GetExceptionCode();
- }
- }
-
- status = ObReferenceObjectByHandle(
- ProcessHandle,
- 0,
- *PsProcessType,
- AccessMode,
- &process,
- NULL
- );
-
- if (!NT_SUCCESS(status))
- return status;
-
- if (process == PsInitialSystemProcess)
- {
- // A check was added in Windows 7 - if we're attached to the System process, the handle must
- // be a kernel handle.
- Handle = MakeKernelHandle(Handle);
- referenceMode = KernelMode;
- }
- else
- {
- // Make sure the handle isn't a kernel handle if we're not attached to the System process.
- // This means we can avoid referencing then opening the objects later when calling
- // ZwQueryObject, etc.
- if (IsKernelHandle(Handle))
- {
- ObDereferenceObject(process);
- return STATUS_INVALID_HANDLE;
- }
-
- referenceMode = AccessMode;
- }
-
- switch (ObjectInformationClass)
- {
- case KphObjectBasicInformation:
- {
- OBJECT_BASIC_INFORMATION basicInfo;
-
- KeStackAttachProcess(process, &apcState);
- status = ZwQueryObject(
- Handle,
- ObjectBasicInformation,
- &basicInfo,
- sizeof(OBJECT_BASIC_INFORMATION),
- NULL
- );
- KeUnstackDetachProcess(&apcState);
-
- if (NT_SUCCESS(status))
- {
- if (ObjectInformationLength == sizeof(OBJECT_BASIC_INFORMATION))
- {
- __try
- {
- *(POBJECT_BASIC_INFORMATION)ObjectInformation = basicInfo;
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- status = GetExceptionCode();
- }
- }
- else
- {
- status = STATUS_INFO_LENGTH_MISMATCH;
- }
- }
-
- returnLength = sizeof(OBJECT_BASIC_INFORMATION);
- }
- break;
- case KphObjectNameInformation:
- {
- PVOID object;
- ULONG allocateSize;
- POBJECT_NAME_INFORMATION nameInfo;
-
- returnLength = sizeof(OBJECT_NAME_INFORMATION);
-
- // Attach to the process a get a pointer to the object.
- KeStackAttachProcess(process, &apcState);
- status = ObReferenceObjectByHandle(
- Handle,
- 0,
- NULL,
- referenceMode,
- &object,
- NULL
- );
- KeUnstackDetachProcess(&apcState);
-
- if (NT_SUCCESS(status))
- {
- allocateSize = ObjectInformationLength;
-
- if (allocateSize < sizeof(OBJECT_NAME_INFORMATION)) // make sure we never try to allocate 0 bytes
- allocateSize = sizeof(OBJECT_NAME_INFORMATION);
-
- nameInfo = ExAllocatePoolWithQuotaTag(PagedPool, allocateSize, 'QhpK');
-
- if (nameInfo)
- {
- // Make sure we don't leak any data.
- memset(nameInfo, 0, ObjectInformationLength);
-
- status = KphQueryNameObject(
- object,
- nameInfo,
- ObjectInformationLength,
- &returnLength
- );
- dprintf("KpiQueryInformationObject: called KphQueryNameObject: Handle: 0x%Ix, ObjectInformationLength: %u, returnLength: %u\n",
- Handle, ObjectInformationLength, returnLength);
-
- if (NT_SUCCESS(status))
- {
- // Fix up the buffer pointer.
- if (nameInfo->Name.Buffer)
- nameInfo->Name.Buffer = (PVOID)((ULONG_PTR)nameInfo->Name.Buffer - (ULONG_PTR)nameInfo + (ULONG_PTR)ObjectInformation);
-
- __try
- {
- memcpy(ObjectInformation, nameInfo, ObjectInformationLength);
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- status = GetExceptionCode();
- }
- }
-
- ExFreePoolWithTag(nameInfo, 'QhpK');
- }
- else
- {
- status = STATUS_INSUFFICIENT_RESOURCES;
- }
-
- ObDereferenceObject(object);
- }
- }
- break;
- case KphObjectTypeInformation:
- {
- ULONG allocateSize;
- POBJECT_TYPE_INFORMATION typeInfo;
-
- returnLength = sizeof(OBJECT_TYPE_INFORMATION);
- allocateSize = ObjectInformationLength;
-
- if (allocateSize < sizeof(OBJECT_TYPE_INFORMATION))
- allocateSize = sizeof(OBJECT_TYPE_INFORMATION);
-
- // ObQueryTypeInfo uses ObjectType->Name.MaximumLength instead of
- // ObjectType->Name.Length + sizeof(WCHAR) to calculate the required buffer size. In
- // Windows 8, certain object types (e.g. TmTx) do NOT include the null terminator in
- // MaximumLength, which causes ObQueryTypeInfo to overrun the given buffer. To work
- // around this bug, we add some (generous) padding to our allocation.
- allocateSize += sizeof(ULONGLONG);
-
- typeInfo = ExAllocatePoolWithQuotaTag(PagedPool, allocateSize, 'QhpK');
-
- if (typeInfo)
- {
- memset(typeInfo, 0, ObjectInformationLength);
-
- KeStackAttachProcess(process, &apcState);
- status = ZwQueryObject(
- Handle,
- ObjectTypeInformation,
- typeInfo,
- ObjectInformationLength,
- &returnLength
- );
- KeUnstackDetachProcess(&apcState);
-
- if (NT_SUCCESS(status))
- {
- // Fix up the buffer pointer.
- if (typeInfo->TypeName.Buffer)
- typeInfo->TypeName.Buffer = (PVOID)((ULONG_PTR)typeInfo->TypeName.Buffer - (ULONG_PTR)typeInfo + (ULONG_PTR)ObjectInformation);
-
- __try
- {
- memcpy(ObjectInformation, typeInfo, ObjectInformationLength);
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- status = GetExceptionCode();
- }
- }
-
- ExFreePoolWithTag(typeInfo, 'QhpK');
- }
- else
- {
- status = STATUS_INSUFFICIENT_RESOURCES;
- }
- }
- break;
- case KphObjectHandleFlagInformation:
- {
- OBJECT_HANDLE_FLAG_INFORMATION handleFlagInfo;
-
- KeStackAttachProcess(process, &apcState);
- status = ZwQueryObject(
- Handle,
- ObjectHandleFlagInformation,
- &handleFlagInfo,
- sizeof(OBJECT_HANDLE_FLAG_INFORMATION),
- NULL
- );
- KeUnstackDetachProcess(&apcState);
-
- if (NT_SUCCESS(status))
- {
- if (ObjectInformationLength == sizeof(OBJECT_HANDLE_FLAG_INFORMATION))
- {
- __try
- {
- *(POBJECT_HANDLE_FLAG_INFORMATION)ObjectInformation = handleFlagInfo;
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- status = GetExceptionCode();
- }
- }
- else
- {
- status = STATUS_INFO_LENGTH_MISMATCH;
- }
- }
-
- returnLength = sizeof(OBJECT_HANDLE_FLAG_INFORMATION);
- }
- break;
- case KphObjectProcessBasicInformation:
- {
- PROCESS_BASIC_INFORMATION basicInfo;
-
- KeStackAttachProcess(process, &apcState);
- status = ZwQueryInformationProcess(
- Handle,
- ProcessBasicInformation,
- &basicInfo,
- sizeof(PROCESS_BASIC_INFORMATION),
- NULL
- );
- KeUnstackDetachProcess(&apcState);
-
- if (NT_SUCCESS(status))
- {
- if (ObjectInformationLength == sizeof(PROCESS_BASIC_INFORMATION))
- {
- __try
- {
- *(PPROCESS_BASIC_INFORMATION)ObjectInformation = basicInfo;
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- status = GetExceptionCode();
- }
- }
- else
- {
- status = STATUS_INFO_LENGTH_MISMATCH;
- }
- }
-
- returnLength = sizeof(PROCESS_BASIC_INFORMATION);
- }
- break;
- case KphObjectThreadBasicInformation:
- {
- THREAD_BASIC_INFORMATION basicInfo;
-
- KeStackAttachProcess(process, &apcState);
- status = ZwQueryInformationThread(
- Handle,
- ThreadBasicInformation,
- &basicInfo,
- sizeof(THREAD_BASIC_INFORMATION),
- NULL
- );
- KeUnstackDetachProcess(&apcState);
-
- if (NT_SUCCESS(status))
- {
- if (ObjectInformationLength == sizeof(THREAD_BASIC_INFORMATION))
- {
- __try
- {
- *(PTHREAD_BASIC_INFORMATION)ObjectInformation = basicInfo;
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- status = GetExceptionCode();
- }
- }
- else
- {
- status = STATUS_INFO_LENGTH_MISMATCH;
- }
- }
-
- returnLength = sizeof(THREAD_BASIC_INFORMATION);
- }
- break;
- case KphObjectEtwRegBasicInformation:
- {
- PVOID etwReg;
- PVOID objectType;
- PUNICODE_STRING objectTypeName;
- UNICODE_STRING etwRegistrationName;
- PVOID guidEntry;
- ETWREG_BASIC_INFORMATION basicInfo;
-
- // Check dynamic data requirements.
- if (KphDynEgeGuid != -1 &&
- KphDynEreGuidEntry != -1 &&
- KphDynOtName != -1)
- {
- // Attach to the process and get a pointer to the object. We don't have a pointer to
- // the EtwRegistration object type, so we'll just have to check the type name.
-
- KeStackAttachProcess(process, &apcState);
- status = ObReferenceObjectByHandle(
- Handle,
- 0,
- NULL,
- referenceMode,
- &etwReg,
- NULL
- );
- KeUnstackDetachProcess(&apcState);
-
- if (NT_SUCCESS(status))
- {
- // Check the type name.
-
- objectType = ObGetObjectType(etwReg);
-
- if (objectType)
- {
- objectTypeName = (PUNICODE_STRING)((ULONG_PTR)objectType + KphDynOtName);
- RtlInitUnicodeString(&etwRegistrationName, L"EtwRegistration");
-
- if (!RtlEqualUnicodeString(objectTypeName, &etwRegistrationName, FALSE))
- {
- status = STATUS_OBJECT_TYPE_MISMATCH;
- }
- }
- else
- {
- status = STATUS_NOT_SUPPORTED;
- }
-
- if (NT_SUCCESS(status))
- {
- guidEntry = *(PVOID *)((ULONG_PTR)etwReg + KphDynEreGuidEntry);
-
- if (guidEntry)
- basicInfo.Guid = *(GUID *)((ULONG_PTR)guidEntry + KphDynEgeGuid);
- else
- memset(&basicInfo.Guid, 0, sizeof(GUID));
-
- basicInfo.SessionId = 0; // not implemented
-
- if (ObjectInformationLength == sizeof(ETWREG_BASIC_INFORMATION))
- {
- __try
- {
- *(PETWREG_BASIC_INFORMATION)ObjectInformation = basicInfo;
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- status = GetExceptionCode();
- }
- }
- else
- {
- status = STATUS_INFO_LENGTH_MISMATCH;
- }
- }
-
- ObDereferenceObject(etwReg);
- }
- }
- else
- {
- status = STATUS_NOT_SUPPORTED;
- }
-
- returnLength = sizeof(ETWREG_BASIC_INFORMATION);
- }
- break;
- case KphObjectFileObjectInformation:
- {
- PFILE_OBJECT fileObject;
- KPH_FILE_OBJECT_INFORMATION objectInfo;
-
- KeStackAttachProcess(process, &apcState);
- status = ObReferenceObjectByHandle(
- Handle,
- 0,
- *IoFileObjectType,
- referenceMode,
- &fileObject,
- NULL
- );
- KeUnstackDetachProcess(&apcState);
-
- if (NT_SUCCESS(status))
- {
- objectInfo.LockOperation = fileObject->LockOperation;
- objectInfo.DeletePending = fileObject->DeletePending;
- objectInfo.ReadAccess = fileObject->ReadAccess;
- objectInfo.WriteAccess = fileObject->WriteAccess;
- objectInfo.DeleteAccess = fileObject->DeleteAccess;
- objectInfo.SharedRead = fileObject->SharedRead;
- objectInfo.SharedWrite = fileObject->SharedWrite;
- objectInfo.SharedDelete = fileObject->SharedDelete;
- objectInfo.CurrentByteOffset = fileObject->CurrentByteOffset;
- objectInfo.Flags = fileObject->Flags;
-
- if (ObjectInformationLength == sizeof(KPH_FILE_OBJECT_INFORMATION))
- {
- __try
- {
- *(PKPH_FILE_OBJECT_INFORMATION)ObjectInformation = objectInfo;
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- status = GetExceptionCode();
- }
- }
- else
- {
- status = STATUS_INFO_LENGTH_MISMATCH;
- }
-
- ObDereferenceObject(fileObject);
- }
-
- returnLength = sizeof(KPH_FILE_OBJECT_INFORMATION);
- }
- break;
- case KphObjectFileObjectDriver:
- {
- PFILE_OBJECT fileObject;
- HANDLE driverHandle;
-
- if (ObjectInformationLength == sizeof(KPH_FILE_OBJECT_DRIVER))
- {
- KeStackAttachProcess(process, &apcState);
- status = ObReferenceObjectByHandle(
- Handle,
- 0,
- *IoFileObjectType,
- referenceMode,
- &fileObject,
- NULL
- );
- KeUnstackDetachProcess(&apcState);
-
- if (NT_SUCCESS(status))
- {
- if (fileObject->DeviceObject && fileObject->DeviceObject->DriverObject)
- {
- status = ObOpenObjectByPointer(
- fileObject->DeviceObject->DriverObject,
- 0,
- NULL,
- SYNCHRONIZE,
- *IoDriverObjectType,
- AccessMode,
- &driverHandle
- );
- }
- else
- {
- driverHandle = NULL;
- }
-
- if (NT_SUCCESS(status))
- {
- __try
- {
- ((PKPH_FILE_OBJECT_DRIVER)ObjectInformation)->DriverHandle = driverHandle;
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- status = GetExceptionCode();
- }
- }
-
- ObDereferenceObject(fileObject);
- }
- }
- else
- {
- status = STATUS_INFO_LENGTH_MISMATCH;
- }
- }
- break;
- default:
- status = STATUS_INVALID_INFO_CLASS;
- returnLength = 0;
- break;
- }
-
- ObDereferenceObject(process);
-
- if (ReturnLength)
- {
- if (AccessMode != KernelMode)
- {
- __try
- {
- *ReturnLength = returnLength;
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- NOTHING;
- }
- }
- else
- {
- *ReturnLength = returnLength;
- }
- }
-
- return status;
-}
-
-/**
- * Sets object information.
- *
- * \param ProcessHandle A handle to a process.
- * \param Handle A handle which is present in the process referenced by \a ProcessHandle.
- * \param ObjectInformationClass The type of information to set.
- * \param ObjectInformation A buffer which contains the information to set.
- * \param ObjectInformationLength The number of bytes present in \a ObjectInformation.
- * \param AccessMode The mode in which to perform access checks.
- */
-NTSTATUS KpiSetInformationObject(
- __in HANDLE ProcessHandle,
- __in HANDLE Handle,
- __in KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass,
- __in_bcount(ObjectInformationLength) PVOID ObjectInformation,
- __in ULONG ObjectInformationLength,
- __in KPROCESSOR_MODE AccessMode
- )
-{
- NTSTATUS status;
- PEPROCESS process;
- KAPC_STATE apcState;
-
- PAGED_CODE();
-
- if (AccessMode != KernelMode)
- {
- ULONG alignment;
-
- switch (ObjectInformationClass)
- {
- case KphObjectHandleFlagInformation:
- alignment = sizeof(BOOLEAN);
- break;
- default:
- alignment = sizeof(ULONG);
- break;
- }
-
- __try
- {
- ProbeForRead(ObjectInformation, ObjectInformationLength, alignment);
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- return GetExceptionCode();
- }
- }
-
- status = ObReferenceObjectByHandle(
- ProcessHandle,
- 0,
- *PsProcessType,
- AccessMode,
- &process,
- NULL
- );
-
- if (!NT_SUCCESS(status))
- return status;
-
- if (process == PsInitialSystemProcess)
- {
- Handle = MakeKernelHandle(Handle);
- }
- else
- {
- if (IsKernelHandle(Handle))
- {
- ObDereferenceObject(process);
- return STATUS_INVALID_HANDLE;
- }
- }
-
- switch (ObjectInformationClass)
- {
- case KphObjectHandleFlagInformation:
- {
- OBJECT_HANDLE_FLAG_INFORMATION handleFlagInfo;
-
- if (ObjectInformationLength == sizeof(OBJECT_HANDLE_FLAG_INFORMATION))
- {
- __try
- {
- handleFlagInfo = *(POBJECT_HANDLE_FLAG_INFORMATION)ObjectInformation;
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- status = GetExceptionCode();
- }
- }
- else
- {
- status = STATUS_INFO_LENGTH_MISMATCH;
- }
-
- if (NT_SUCCESS(status))
- {
- KeStackAttachProcess(process, &apcState);
- status = ObSetHandleAttributes(Handle, &handleFlagInfo, KernelMode);
- KeUnstackDetachProcess(&apcState);
- }
- }
- break;
- default:
- status = STATUS_INVALID_INFO_CLASS;
- break;
- }
-
- ObDereferenceObject(process);
-
- return status;
-}
-
-NTSTATUS KphOpenNamedObject(
- __out PHANDLE ObjectHandle,
- __in ACCESS_MASK DesiredAccess,
- __in POBJECT_ATTRIBUTES ObjectAttributes,
- __in POBJECT_TYPE ObjectType,
- __in KPROCESSOR_MODE AccessMode
- )
-{
- NTSTATUS status;
- HANDLE objectHandle;
-
- PAGED_CODE();
-
- // Open the object.
- status = ObOpenObjectByName(
- ObjectAttributes,
- ObjectType,
- AccessMode,
- NULL,
- DesiredAccess,
- NULL,
- &objectHandle
- );
-
- // Pass the handle back.
- if (AccessMode != KernelMode)
- {
- __try
- {
- *ObjectHandle = objectHandle;
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- status = GetExceptionCode();
- }
- }
- else
- {
- *ObjectHandle = objectHandle;
- }
-
- return status;
-}
+/*
+ * KProcessHacker
+ *
+ * Copyright (C) 2010-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 .
+ */
+
+#include
+#include
+
+#ifdef _X86_
+#define KERNEL_HANDLE_BIT (0x80000000)
+#else
+#define KERNEL_HANDLE_BIT (0xffffffff80000000)
+#endif
+
+#define IsKernelHandle(Handle) ((LONG_PTR)(Handle) < 0)
+#define MakeKernelHandle(Handle) ((HANDLE)((ULONG_PTR)(Handle) | KERNEL_HANDLE_BIT))
+
+typedef struct _KPHP_ENUMERATE_PROCESS_HANDLES_CONTEXT
+{
+ PVOID Buffer;
+ PVOID BufferLimit;
+ PVOID CurrentEntry;
+ ULONG Count;
+ NTSTATUS Status;
+} KPHP_ENUMERATE_PROCESS_HANDLES_CONTEXT, *PKPHP_ENUMERATE_PROCESS_HANDLES_CONTEXT;
+
+BOOLEAN KphpEnumerateProcessHandlesEnumCallback61(
+ _Inout_ PHANDLE_TABLE_ENTRY HandleTableEntry,
+ _In_ HANDLE Handle,
+ _In_ PVOID Context
+ );
+
+BOOLEAN KphpEnumerateProcessHandlesEnumCallback(
+ _In_ PHANDLE_TABLE HandleTable,
+ _Inout_ PHANDLE_TABLE_ENTRY HandleTableEntry,
+ _In_ HANDLE Handle,
+ _In_ PVOID Context
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, KphReferenceProcessHandleTable)
+#pragma alloc_text(PAGE, KphDereferenceProcessHandleTable)
+#pragma alloc_text(PAGE, KphUnlockHandleTableEntry)
+#pragma alloc_text(PAGE, KphpEnumerateProcessHandlesEnumCallback61)
+#pragma alloc_text(PAGE, KphpEnumerateProcessHandlesEnumCallback)
+#pragma alloc_text(PAGE, KpiEnumerateProcessHandles)
+#pragma alloc_text(PAGE, KphQueryNameObject)
+#pragma alloc_text(PAGE, KphQueryNameFileObject)
+#pragma alloc_text(PAGE, KpiQueryInformationObject)
+#pragma alloc_text(PAGE, KpiSetInformationObject)
+#pragma alloc_text(PAGE, KphOpenNamedObject)
+#endif
+
+/**
+ * Gets a pointer to the handle table of a process.
+ *
+ * \param Process A process object.
+ *
+ * \return A pointer to the handle table, or NULL if the process is terminating or the request is
+ * not supported. You must call KphDereferenceProcessHandleTable() when the handle table is no
+ * longer needed.
+ */
+PHANDLE_TABLE KphReferenceProcessHandleTable(
+ _In_ PEPROCESS Process
+ )
+{
+ PHANDLE_TABLE handleTable = NULL;
+
+ PAGED_CODE();
+
+ // Fail if we don't have an offset.
+ if (KphDynEpObjectTable == -1)
+ return NULL;
+
+ // Prevent the process from terminating and get its handle table.
+ if (NT_SUCCESS(PsAcquireProcessExitSynchronization(Process)))
+ {
+ handleTable = *(PHANDLE_TABLE *)PTR_ADD_OFFSET(Process, KphDynEpObjectTable);
+
+ if (!handleTable)
+ PsReleaseProcessExitSynchronization(Process);
+ }
+
+ return handleTable;
+}
+
+/**
+ * Dereferences the handle table of a process.
+ *
+ * \param Process A process object.
+ */
+VOID KphDereferenceProcessHandleTable(
+ _In_ PEPROCESS Process
+ )
+{
+ PAGED_CODE();
+
+ PsReleaseProcessExitSynchronization(Process);
+}
+
+VOID KphUnlockHandleTableEntry(
+ _In_ PHANDLE_TABLE HandleTable,
+ _In_ PHANDLE_TABLE_ENTRY HandleTableEntry
+ )
+{
+ PEX_PUSH_LOCK handleContentionEvent;
+
+ PAGED_CODE();
+
+ // Set the unlocked bit.
+
+#ifdef _M_X64
+ InterlockedExchangeAdd64(&HandleTableEntry->Value, 1);
+#else
+ InterlockedExchangeAdd(&HandleTableEntry->Value, 1);
+#endif
+
+ // Allow waiters to wake up.
+
+ handleContentionEvent = (PEX_PUSH_LOCK)PTR_ADD_OFFSET(HandleTable, KphDynHtHandleContentionEvent);
+
+ if (*(PULONG_PTR)handleContentionEvent != 0)
+ ExfUnblockPushLock(handleContentionEvent, NULL);
+}
+
+BOOLEAN KphpEnumerateProcessHandlesEnumCallback61(
+ _Inout_ PHANDLE_TABLE_ENTRY HandleTableEntry,
+ _In_ HANDLE Handle,
+ _In_ PVOID Context
+ )
+{
+ PKPHP_ENUMERATE_PROCESS_HANDLES_CONTEXT context = Context;
+ KPH_PROCESS_HANDLE handleInfo;
+ POBJECT_HEADER objectHeader;
+ POBJECT_TYPE objectType;
+ PKPH_PROCESS_HANDLE entryInBuffer;
+
+ PAGED_CODE();
+
+ objectHeader = ObpDecodeObject(HandleTableEntry->Object);
+ handleInfo.Handle = Handle;
+ handleInfo.Object = objectHeader ? &objectHeader->Body : NULL;
+ handleInfo.GrantedAccess = ObpDecodeGrantedAccess(HandleTableEntry->GrantedAccess);
+ handleInfo.ObjectTypeIndex = -1;
+ handleInfo.Reserved1 = 0;
+ handleInfo.HandleAttributes = ObpGetHandleAttributes(HandleTableEntry);
+ handleInfo.Reserved2 = 0;
+
+ if (handleInfo.Object)
+ {
+ objectType = ObGetObjectType(handleInfo.Object);
+
+ if (objectType && KphDynOtIndex != -1)
+ handleInfo.ObjectTypeIndex = (USHORT)*(PUCHAR)PTR_ADD_OFFSET(objectType, KphDynOtIndex);
+ }
+
+ // Advance the current entry pointer regardless of whether the information will be written; this
+ // will allow the parent function to report the correct return length.
+ entryInBuffer = context->CurrentEntry;
+ context->CurrentEntry = PTR_ADD_OFFSET(context->CurrentEntry, sizeof(KPH_PROCESS_HANDLE));
+ context->Count++;
+
+ // Only write if we have not exceeded the buffer length. Also check for a potential overflow (if
+ // the process has an extremely large number of handles, the buffer pointer may wrap).
+ if (
+ (ULONG_PTR)entryInBuffer >= (ULONG_PTR)context->Buffer &&
+ (ULONG_PTR)entryInBuffer + sizeof(KPH_PROCESS_HANDLE) <= (ULONG_PTR)context->BufferLimit
+ )
+ {
+ __try
+ {
+ *entryInBuffer = handleInfo;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ // Report an error.
+ if (context->Status == STATUS_SUCCESS)
+ context->Status = GetExceptionCode();
+ }
+ }
+ else
+ {
+ // Report that the buffer is too small.
+ if (context->Status == STATUS_SUCCESS)
+ context->Status = STATUS_BUFFER_TOO_SMALL;
+ }
+
+ return FALSE;
+}
+
+BOOLEAN KphpEnumerateProcessHandlesEnumCallback(
+ _In_ PHANDLE_TABLE HandleTable,
+ _Inout_ PHANDLE_TABLE_ENTRY HandleTableEntry,
+ _In_ HANDLE Handle,
+ _In_ PVOID Context
+ )
+{
+ BOOLEAN result;
+
+ PAGED_CODE();
+
+ result = KphpEnumerateProcessHandlesEnumCallback61(HandleTableEntry, Handle, Context);
+ KphUnlockHandleTableEntry(HandleTable, HandleTableEntry);
+
+ return result;
+}
+
+/**
+ * Enumerates the handles of a process.
+ *
+ * \param ProcessHandle A handle to a process.
+ * \param Buffer The buffer in which the handle information will be stored.
+ * \param BufferLength The number of bytes available in \a Buffer.
+ * \param ReturnLength A variable which receives the number of bytes required to be available in
+ * \a Buffer.
+ * \param AccessMode The mode in which to perform access checks.
+ */
+NTSTATUS KpiEnumerateProcessHandles(
+ _In_ HANDLE ProcessHandle,
+ _Out_writes_bytes_(BufferLength) PVOID Buffer,
+ _In_opt_ ULONG BufferLength,
+ _Out_opt_ PULONG ReturnLength,
+ _In_ KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status;
+ BOOLEAN result;
+ PEPROCESS process;
+ PHANDLE_TABLE handleTable;
+ KPHP_ENUMERATE_PROCESS_HANDLES_CONTEXT context;
+
+ PAGED_CODE();
+
+ if (KphDynNtVersion >= PHNT_WIN8 && KphDynHtHandleContentionEvent == -1)
+ {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ ProbeForWrite(Buffer, BufferLength, sizeof(ULONG));
+
+ if (ReturnLength)
+ ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG));
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+ }
+
+ // Reference the process object.
+ status = ObReferenceObjectByHandle(
+ ProcessHandle,
+ 0,
+ *PsProcessType,
+ AccessMode,
+ &process,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ // Get its handle table.
+ handleTable = KphReferenceProcessHandleTable(process);
+
+ if (!handleTable)
+ {
+ ObDereferenceObject(process);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ // Initialize the enumeration context.
+ context.Buffer = Buffer;
+ context.BufferLimit = PTR_ADD_OFFSET(Buffer, BufferLength);
+ context.CurrentEntry = ((PKPH_PROCESS_HANDLE_INFORMATION)Buffer)->Handles;
+ context.Count = 0;
+ context.Status = STATUS_SUCCESS;
+
+ // Enumerate the handles.
+
+ if (KphDynNtVersion >= PHNT_WIN8)
+ {
+ result = ExEnumHandleTable(
+ handleTable,
+ KphpEnumerateProcessHandlesEnumCallback,
+ &context,
+ NULL
+ );
+ }
+ else
+ {
+ result = ExEnumHandleTable(
+ handleTable,
+ (PEX_ENUM_HANDLE_CALLBACK)KphpEnumerateProcessHandlesEnumCallback61,
+ &context,
+ NULL
+ );
+ }
+
+ KphDereferenceProcessHandleTable(process);
+ ObDereferenceObject(process);
+
+ // Write the number of handles if we can.
+ if (BufferLength >= UFIELD_OFFSET(KPH_PROCESS_HANDLE_INFORMATION, Handles))
+ {
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ ((PKPH_PROCESS_HANDLE_INFORMATION)Buffer)->HandleCount = context.Count;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+ }
+ else
+ {
+ ((PKPH_PROCESS_HANDLE_INFORMATION)Buffer)->HandleCount = context.Count;
+ }
+ }
+
+ // Supply the return length if the caller wanted it.
+ if (ReturnLength)
+ {
+ ULONG returnLength;
+
+ // Note: if the CurrentEntry pointer wrapped, this will give the wrong return length.
+ returnLength = (ULONG)((ULONG_PTR)context.CurrentEntry - (ULONG_PTR)Buffer);
+
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ *ReturnLength = returnLength;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+ }
+ else
+ {
+ *ReturnLength = returnLength;
+ }
+ }
+
+ return context.Status;
+}
+
+/**
+ * Queries the name of an object.
+ *
+ * \param Object A pointer to an object.
+ * \param Buffer The buffer in which the object name will be stored.
+ * \param BufferLength The number of bytes available in \a Buffer.
+ * \param ReturnLength A variable which receives the number of bytes required to be available in
+ * \a Buffer.
+ */
+NTSTATUS KphQueryNameObject(
+ _In_ PVOID Object,
+ _Out_writes_bytes_(BufferLength) POBJECT_NAME_INFORMATION Buffer,
+ _In_ ULONG BufferLength,
+ _Out_ PULONG ReturnLength
+ )
+{
+ NTSTATUS status;
+ POBJECT_TYPE objectType;
+
+ PAGED_CODE();
+
+ objectType = ObGetObjectType(Object);
+
+ // Check if we are going to hang when querying the object, and use
+ // the special file object query function if needed.
+ if (objectType == *IoFileObjectType &&
+ (((PFILE_OBJECT)Object)->Busy || ((PFILE_OBJECT)Object)->Waiters))
+ {
+ status = KphQueryNameFileObject(Object, Buffer, BufferLength, ReturnLength);
+ dprintf("KphQueryNameFileObject: status 0x%x\n", status);
+ }
+ else
+ {
+ status = ObQueryNameString(Object, Buffer, BufferLength, ReturnLength);
+ dprintf("ObQueryNameString: status 0x%x\n", status);
+ }
+
+ // Make the error returns consistent.
+ if (status == STATUS_BUFFER_OVERFLOW) // returned by I/O subsystem
+ status = STATUS_BUFFER_TOO_SMALL;
+ if (status == STATUS_INFO_LENGTH_MISMATCH) // returned by ObQueryNameString
+ status = STATUS_BUFFER_TOO_SMALL;
+
+ if (NT_SUCCESS(status))
+ dprintf("KphQueryNameObject: %.*S\n", Buffer->Name.Length / sizeof(WCHAR), Buffer->Name.Buffer);
+ else
+ dprintf("KphQueryNameObject: status 0x%x\n", status);
+
+ return status;
+}
+
+/**
+ * Queries the name of a file object.
+ *
+ * \param FileObject A pointer to a file object.
+ * \param Buffer The buffer in which the object name will be stored.
+ * \param BufferLength The number of bytes available in \a Buffer.
+ * \param ReturnLength A variable which receives the number of bytes required to be available in
+ * \a Buffer.
+ */
+NTSTATUS KphQueryNameFileObject(
+ _In_ PFILE_OBJECT FileObject,
+ _Out_writes_bytes_(BufferLength) POBJECT_NAME_INFORMATION Buffer,
+ _In_ ULONG BufferLength,
+ _Out_ PULONG ReturnLength
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ ULONG returnLength;
+ PCHAR objectName;
+ ULONG usedLength;
+ ULONG subNameLength;
+ PFILE_OBJECT relatedFileObject;
+
+ PAGED_CODE();
+
+ // We need at least the size of OBJECT_NAME_INFORMATION to continue.
+ if (BufferLength < sizeof(OBJECT_NAME_INFORMATION))
+ {
+ *ReturnLength = sizeof(OBJECT_NAME_INFORMATION);
+
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ // Assume failure.
+ Buffer->Name.Length = 0;
+ // We will place the object name directly after the UNICODE_STRING structure in the buffer.
+ Buffer->Name.Buffer = (PWSTR)PTR_ADD_OFFSET(Buffer, sizeof(OBJECT_NAME_INFORMATION));
+ // Retain a local pointer to the object name so we can manipulate the pointer.
+ objectName = (PCHAR)Buffer->Name.Buffer;
+ // A variable that keeps track of how much space we have used.
+ usedLength = sizeof(OBJECT_NAME_INFORMATION);
+
+ // Check if the file object has an associated device (e.g. "\Device\NamedPipe", "\Device\Mup").
+ // We can use the user-supplied buffer for this since if the buffer isn't big enough, we can't
+ // proceed anyway (we are going to use the name).
+ if (FileObject->DeviceObject)
+ {
+ status = ObQueryNameString(
+ FileObject->DeviceObject,
+ Buffer,
+ BufferLength,
+ &returnLength
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ if (status == STATUS_INFO_LENGTH_MISMATCH)
+ status = STATUS_BUFFER_TOO_SMALL;
+
+ *ReturnLength = returnLength;
+
+ return status;
+ }
+
+ // The UNICODE_STRING in the buffer is now filled in. We will append to the object name
+ // later, so we need to fix the object name pointer by adding the length, in bytes, of the
+ // device name string we just got.
+ objectName += Buffer->Name.Length;
+ usedLength += Buffer->Name.Length;
+ }
+
+ // Check if the file object has a file name component. If not, we can't do anything else, so we
+ // just return the name we have already.
+ if (!FileObject->FileName.Buffer)
+ {
+ *ReturnLength = usedLength;
+
+ return STATUS_SUCCESS;
+ }
+
+ // The file object has a name. We need to walk up the file object chain and append the names of
+ // the related file objects in reverse order. This means we need to calculate the total length
+ // first.
+
+ relatedFileObject = FileObject;
+ subNameLength = 0;
+
+ do
+ {
+ subNameLength += relatedFileObject->FileName.Length;
+
+ // Avoid infinite loops.
+ if (relatedFileObject == relatedFileObject->RelatedFileObject)
+ break;
+
+ relatedFileObject = relatedFileObject->RelatedFileObject;
+ } while (relatedFileObject);
+
+ usedLength += subNameLength;
+
+ // Check if we have enough space to write the whole thing.
+ if (usedLength > BufferLength)
+ {
+ *ReturnLength = usedLength;
+
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ // We're ready to begin copying the names.
+
+ // Add the name length because we're copying in reverse order.
+ objectName += subNameLength;
+
+ relatedFileObject = FileObject;
+
+ do
+ {
+ objectName -= relatedFileObject->FileName.Length;
+ memcpy(objectName, relatedFileObject->FileName.Buffer, relatedFileObject->FileName.Length);
+
+ // Avoid infinite loops.
+ if (relatedFileObject == relatedFileObject->RelatedFileObject)
+ break;
+
+ relatedFileObject = relatedFileObject->RelatedFileObject;
+ } while (relatedFileObject);
+
+ // Update the length.
+ Buffer->Name.Length += (USHORT)subNameLength;
+
+ // Pass the return length back.
+ *ReturnLength = usedLength;
+
+ return STATUS_SUCCESS;
+}
+
+/**
+ * Queries object information.
+ *
+ * \param ProcessHandle A handle to a process.
+ * \param Handle A handle which is present in the process referenced by \a ProcessHandle.
+ * \param ObjectInformationClass The type of information to retrieve.
+ * \param ObjectInformation The buffer in which the information will be stored.
+ * \param ObjectInformationLength The number of bytes available in \a ObjectInformation.
+ * \param ReturnLength A variable which receives the number of bytes required to be available in
+ * \a ObjectInformation.
+ * \param AccessMode The mode in which to perform access checks.
+ */
+NTSTATUS KpiQueryInformationObject(
+ _In_ HANDLE ProcessHandle,
+ _In_ HANDLE Handle,
+ _In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass,
+ _Out_writes_bytes_(ObjectInformationLength) PVOID ObjectInformation,
+ _In_ ULONG ObjectInformationLength,
+ _Out_opt_ PULONG ReturnLength,
+ _In_ KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status;
+ PEPROCESS process;
+ KPROCESSOR_MODE referenceMode;
+ KAPC_STATE apcState;
+ ULONG returnLength;
+
+ PAGED_CODE();
+
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ ProbeForWrite(ObjectInformation, ObjectInformationLength, sizeof(ULONG));
+
+ if (ReturnLength)
+ ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG));
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+ }
+
+ status = ObReferenceObjectByHandle(
+ ProcessHandle,
+ 0,
+ *PsProcessType,
+ AccessMode,
+ &process,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ if (process == PsInitialSystemProcess)
+ {
+ // A check was added in Windows 7 - if we're attached to the System process, the handle must
+ // be a kernel handle.
+ Handle = MakeKernelHandle(Handle);
+ referenceMode = KernelMode;
+ }
+ else
+ {
+ // Make sure the handle isn't a kernel handle if we're not attached to the System process.
+ // This means we can avoid referencing then opening the objects later when calling
+ // ZwQueryObject, etc.
+ if (IsKernelHandle(Handle))
+ {
+ ObDereferenceObject(process);
+ return STATUS_INVALID_HANDLE;
+ }
+
+ referenceMode = AccessMode;
+ }
+
+ switch (ObjectInformationClass)
+ {
+ case KphObjectBasicInformation:
+ {
+ OBJECT_BASIC_INFORMATION basicInfo;
+
+ KeStackAttachProcess(process, &apcState);
+ status = ZwQueryObject(
+ Handle,
+ ObjectBasicInformation,
+ &basicInfo,
+ sizeof(OBJECT_BASIC_INFORMATION),
+ NULL
+ );
+ KeUnstackDetachProcess(&apcState);
+
+ if (NT_SUCCESS(status))
+ {
+ if (ObjectInformationLength == sizeof(OBJECT_BASIC_INFORMATION))
+ {
+ __try
+ {
+ *(POBJECT_BASIC_INFORMATION)ObjectInformation = basicInfo;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+ else
+ {
+ status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+ }
+
+ returnLength = sizeof(OBJECT_BASIC_INFORMATION);
+ }
+ break;
+ case KphObjectNameInformation:
+ {
+ PVOID object;
+ ULONG allocateSize;
+ POBJECT_NAME_INFORMATION nameInfo;
+
+ returnLength = sizeof(OBJECT_NAME_INFORMATION);
+
+ // Attach to the process a get a pointer to the object.
+ KeStackAttachProcess(process, &apcState);
+ status = ObReferenceObjectByHandle(
+ Handle,
+ 0,
+ NULL,
+ referenceMode,
+ &object,
+ NULL
+ );
+ KeUnstackDetachProcess(&apcState);
+
+ if (NT_SUCCESS(status))
+ {
+ allocateSize = ObjectInformationLength;
+
+ if (allocateSize < sizeof(OBJECT_NAME_INFORMATION)) // make sure we never try to allocate 0 bytes
+ allocateSize = sizeof(OBJECT_NAME_INFORMATION);
+
+ nameInfo = ExAllocatePoolWithQuotaTag(PagedPool, allocateSize, 'QhpK');
+
+ if (nameInfo)
+ {
+ // Make sure we don't leak any data.
+ memset(nameInfo, 0, ObjectInformationLength);
+
+ status = KphQueryNameObject(
+ object,
+ nameInfo,
+ ObjectInformationLength,
+ &returnLength
+ );
+ dprintf("KpiQueryInformationObject: called KphQueryNameObject: Handle: 0x%Ix, ObjectInformationLength: %u, returnLength: %u\n",
+ Handle, ObjectInformationLength, returnLength);
+
+ if (NT_SUCCESS(status))
+ {
+ // Fix up the buffer pointer.
+ if (nameInfo->Name.Buffer)
+ nameInfo->Name.Buffer = (PVOID)((ULONG_PTR)nameInfo->Name.Buffer - (ULONG_PTR)nameInfo + (ULONG_PTR)ObjectInformation);
+
+ __try
+ {
+ memcpy(ObjectInformation, nameInfo, ObjectInformationLength);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+
+ ExFreePoolWithTag(nameInfo, 'QhpK');
+ }
+ else
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ ObDereferenceObject(object);
+ }
+ }
+ break;
+ case KphObjectTypeInformation:
+ {
+ ULONG allocateSize;
+ POBJECT_TYPE_INFORMATION typeInfo;
+
+ returnLength = sizeof(OBJECT_TYPE_INFORMATION);
+ allocateSize = ObjectInformationLength;
+
+ if (allocateSize < sizeof(OBJECT_TYPE_INFORMATION))
+ allocateSize = sizeof(OBJECT_TYPE_INFORMATION);
+
+ // ObQueryTypeInfo uses ObjectType->Name.MaximumLength instead of
+ // ObjectType->Name.Length + sizeof(WCHAR) to calculate the required buffer size. In
+ // Windows 8, certain object types (e.g. TmTx) do NOT include the null terminator in
+ // MaximumLength, which causes ObQueryTypeInfo to overrun the given buffer. To work
+ // around this bug, we add some (generous) padding to our allocation.
+ allocateSize += sizeof(ULONGLONG);
+
+ typeInfo = ExAllocatePoolWithQuotaTag(PagedPool, allocateSize, 'QhpK');
+
+ if (typeInfo)
+ {
+ memset(typeInfo, 0, ObjectInformationLength);
+
+ KeStackAttachProcess(process, &apcState);
+ status = ZwQueryObject(
+ Handle,
+ ObjectTypeInformation,
+ typeInfo,
+ ObjectInformationLength,
+ &returnLength
+ );
+ KeUnstackDetachProcess(&apcState);
+
+ if (NT_SUCCESS(status))
+ {
+ // Fix up the buffer pointer.
+ if (typeInfo->TypeName.Buffer)
+ typeInfo->TypeName.Buffer = (PVOID)((ULONG_PTR)typeInfo->TypeName.Buffer - (ULONG_PTR)typeInfo + (ULONG_PTR)ObjectInformation);
+
+ __try
+ {
+ memcpy(ObjectInformation, typeInfo, ObjectInformationLength);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+
+ ExFreePoolWithTag(typeInfo, 'QhpK');
+ }
+ else
+ {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+ break;
+ case KphObjectHandleFlagInformation:
+ {
+ OBJECT_HANDLE_FLAG_INFORMATION handleFlagInfo;
+
+ KeStackAttachProcess(process, &apcState);
+ status = ZwQueryObject(
+ Handle,
+ ObjectHandleFlagInformation,
+ &handleFlagInfo,
+ sizeof(OBJECT_HANDLE_FLAG_INFORMATION),
+ NULL
+ );
+ KeUnstackDetachProcess(&apcState);
+
+ if (NT_SUCCESS(status))
+ {
+ if (ObjectInformationLength == sizeof(OBJECT_HANDLE_FLAG_INFORMATION))
+ {
+ __try
+ {
+ *(POBJECT_HANDLE_FLAG_INFORMATION)ObjectInformation = handleFlagInfo;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+ else
+ {
+ status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+ }
+
+ returnLength = sizeof(OBJECT_HANDLE_FLAG_INFORMATION);
+ }
+ break;
+ case KphObjectProcessBasicInformation:
+ {
+ PROCESS_BASIC_INFORMATION basicInfo;
+
+ KeStackAttachProcess(process, &apcState);
+ status = ZwQueryInformationProcess(
+ Handle,
+ ProcessBasicInformation,
+ &basicInfo,
+ sizeof(PROCESS_BASIC_INFORMATION),
+ NULL
+ );
+ KeUnstackDetachProcess(&apcState);
+
+ if (NT_SUCCESS(status))
+ {
+ if (ObjectInformationLength == sizeof(PROCESS_BASIC_INFORMATION))
+ {
+ __try
+ {
+ *(PPROCESS_BASIC_INFORMATION)ObjectInformation = basicInfo;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+ else
+ {
+ status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+ }
+
+ returnLength = sizeof(PROCESS_BASIC_INFORMATION);
+ }
+ break;
+ case KphObjectThreadBasicInformation:
+ {
+ THREAD_BASIC_INFORMATION basicInfo;
+
+ KeStackAttachProcess(process, &apcState);
+ status = ZwQueryInformationThread(
+ Handle,
+ ThreadBasicInformation,
+ &basicInfo,
+ sizeof(THREAD_BASIC_INFORMATION),
+ NULL
+ );
+ KeUnstackDetachProcess(&apcState);
+
+ if (NT_SUCCESS(status))
+ {
+ if (ObjectInformationLength == sizeof(THREAD_BASIC_INFORMATION))
+ {
+ __try
+ {
+ *(PTHREAD_BASIC_INFORMATION)ObjectInformation = basicInfo;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+ else
+ {
+ status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+ }
+
+ returnLength = sizeof(THREAD_BASIC_INFORMATION);
+ }
+ break;
+ case KphObjectEtwRegBasicInformation:
+ {
+ PVOID etwReg;
+ PVOID objectType;
+ PUNICODE_STRING objectTypeName;
+ UNICODE_STRING etwRegistrationName;
+ PVOID guidEntry;
+ ETWREG_BASIC_INFORMATION basicInfo;
+
+ // Check dynamic data requirements.
+ if (KphDynEgeGuid != -1 &&
+ KphDynEreGuidEntry != -1 &&
+ KphDynOtName != -1)
+ {
+ // Attach to the process and get a pointer to the object. We don't have a pointer to
+ // the EtwRegistration object type, so we'll just have to check the type name.
+
+ KeStackAttachProcess(process, &apcState);
+ status = ObReferenceObjectByHandle(
+ Handle,
+ 0,
+ NULL,
+ referenceMode,
+ &etwReg,
+ NULL
+ );
+ KeUnstackDetachProcess(&apcState);
+
+ if (NT_SUCCESS(status))
+ {
+ // Check the type name.
+
+ objectType = ObGetObjectType(etwReg);
+
+ if (objectType)
+ {
+ objectTypeName = (PUNICODE_STRING)PTR_ADD_OFFSET(objectType, KphDynOtName);
+ RtlInitUnicodeString(&etwRegistrationName, L"EtwRegistration");
+
+ if (!RtlEqualUnicodeString(objectTypeName, &etwRegistrationName, FALSE))
+ {
+ status = STATUS_OBJECT_TYPE_MISMATCH;
+ }
+ }
+ else
+ {
+ status = STATUS_NOT_SUPPORTED;
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ guidEntry = *(PVOID *)PTR_ADD_OFFSET(etwReg, KphDynEreGuidEntry);
+
+ if (guidEntry)
+ basicInfo.Guid = *(GUID *)PTR_ADD_OFFSET(guidEntry, KphDynEgeGuid);
+ else
+ memset(&basicInfo.Guid, 0, sizeof(GUID));
+
+ basicInfo.SessionId = 0; // not implemented
+
+ if (ObjectInformationLength == sizeof(ETWREG_BASIC_INFORMATION))
+ {
+ __try
+ {
+ *(PETWREG_BASIC_INFORMATION)ObjectInformation = basicInfo;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+ else
+ {
+ status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+ }
+
+ ObDereferenceObject(etwReg);
+ }
+ }
+ else
+ {
+ status = STATUS_NOT_SUPPORTED;
+ }
+
+ returnLength = sizeof(ETWREG_BASIC_INFORMATION);
+ }
+ break;
+ case KphObjectFileObjectInformation:
+ {
+ PFILE_OBJECT fileObject;
+ KPH_FILE_OBJECT_INFORMATION objectInfo;
+
+ KeStackAttachProcess(process, &apcState);
+ status = ObReferenceObjectByHandle(
+ Handle,
+ 0,
+ *IoFileObjectType,
+ referenceMode,
+ &fileObject,
+ NULL
+ );
+ KeUnstackDetachProcess(&apcState);
+
+ if (NT_SUCCESS(status))
+ {
+ objectInfo.LockOperation = fileObject->LockOperation;
+ objectInfo.DeletePending = fileObject->DeletePending;
+ objectInfo.ReadAccess = fileObject->ReadAccess;
+ objectInfo.WriteAccess = fileObject->WriteAccess;
+ objectInfo.DeleteAccess = fileObject->DeleteAccess;
+ objectInfo.SharedRead = fileObject->SharedRead;
+ objectInfo.SharedWrite = fileObject->SharedWrite;
+ objectInfo.SharedDelete = fileObject->SharedDelete;
+ objectInfo.CurrentByteOffset = fileObject->CurrentByteOffset;
+ objectInfo.Flags = fileObject->Flags;
+
+ if (ObjectInformationLength == sizeof(KPH_FILE_OBJECT_INFORMATION))
+ {
+ __try
+ {
+ *(PKPH_FILE_OBJECT_INFORMATION)ObjectInformation = objectInfo;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+ else
+ {
+ status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+
+ ObDereferenceObject(fileObject);
+ }
+
+ returnLength = sizeof(KPH_FILE_OBJECT_INFORMATION);
+ }
+ break;
+ case KphObjectFileObjectDriver:
+ {
+ PFILE_OBJECT fileObject;
+ HANDLE driverHandle;
+
+ if (ObjectInformationLength == sizeof(KPH_FILE_OBJECT_DRIVER))
+ {
+ KeStackAttachProcess(process, &apcState);
+ status = ObReferenceObjectByHandle(
+ Handle,
+ 0,
+ *IoFileObjectType,
+ referenceMode,
+ &fileObject,
+ NULL
+ );
+ KeUnstackDetachProcess(&apcState);
+
+ if (NT_SUCCESS(status))
+ {
+ if (fileObject->DeviceObject && fileObject->DeviceObject->DriverObject)
+ {
+ status = ObOpenObjectByPointer(
+ fileObject->DeviceObject->DriverObject,
+ 0,
+ NULL,
+ SYNCHRONIZE,
+ *IoDriverObjectType,
+ AccessMode,
+ &driverHandle
+ );
+ }
+ else
+ {
+ driverHandle = NULL;
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ __try
+ {
+ ((PKPH_FILE_OBJECT_DRIVER)ObjectInformation)->DriverHandle = driverHandle;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+
+ ObDereferenceObject(fileObject);
+ }
+ }
+ else
+ {
+ status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+ }
+ break;
+ default:
+ status = STATUS_INVALID_INFO_CLASS;
+ returnLength = 0;
+ break;
+ }
+
+ ObDereferenceObject(process);
+
+ if (ReturnLength)
+ {
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ *ReturnLength = returnLength;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ NOTHING;
+ }
+ }
+ else
+ {
+ *ReturnLength = returnLength;
+ }
+ }
+
+ return status;
+}
+
+/**
+ * Sets object information.
+ *
+ * \param ProcessHandle A handle to a process.
+ * \param Handle A handle which is present in the process referenced by \a ProcessHandle.
+ * \param ObjectInformationClass The type of information to set.
+ * \param ObjectInformation A buffer which contains the information to set.
+ * \param ObjectInformationLength The number of bytes present in \a ObjectInformation.
+ * \param AccessMode The mode in which to perform access checks.
+ */
+NTSTATUS KpiSetInformationObject(
+ _In_ HANDLE ProcessHandle,
+ _In_ HANDLE Handle,
+ _In_ KPH_OBJECT_INFORMATION_CLASS ObjectInformationClass,
+ _In_reads_bytes_(ObjectInformationLength) PVOID ObjectInformation,
+ _In_ ULONG ObjectInformationLength,
+ _In_ KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status;
+ PEPROCESS process;
+ KAPC_STATE apcState;
+
+ PAGED_CODE();
+
+ if (AccessMode != KernelMode)
+ {
+ ULONG alignment;
+
+ switch (ObjectInformationClass)
+ {
+ case KphObjectHandleFlagInformation:
+ alignment = sizeof(BOOLEAN);
+ break;
+ default:
+ alignment = sizeof(ULONG);
+ break;
+ }
+
+ __try
+ {
+ ProbeForRead(ObjectInformation, ObjectInformationLength, alignment);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+ }
+
+ status = ObReferenceObjectByHandle(
+ ProcessHandle,
+ 0,
+ *PsProcessType,
+ AccessMode,
+ &process,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ if (process == PsInitialSystemProcess)
+ {
+ Handle = MakeKernelHandle(Handle);
+ }
+ else
+ {
+ if (IsKernelHandle(Handle))
+ {
+ ObDereferenceObject(process);
+ return STATUS_INVALID_HANDLE;
+ }
+ }
+
+ switch (ObjectInformationClass)
+ {
+ case KphObjectHandleFlagInformation:
+ {
+ OBJECT_HANDLE_FLAG_INFORMATION handleFlagInfo;
+
+ if (ObjectInformationLength == sizeof(OBJECT_HANDLE_FLAG_INFORMATION))
+ {
+ __try
+ {
+ handleFlagInfo = *(POBJECT_HANDLE_FLAG_INFORMATION)ObjectInformation;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+ else
+ {
+ status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ KeStackAttachProcess(process, &apcState);
+ status = ObSetHandleAttributes(Handle, &handleFlagInfo, KernelMode);
+ KeUnstackDetachProcess(&apcState);
+ }
+ }
+ break;
+ default:
+ status = STATUS_INVALID_INFO_CLASS;
+ break;
+ }
+
+ ObDereferenceObject(process);
+
+ return status;
+}
+
+NTSTATUS KphOpenNamedObject(
+ _Out_ PHANDLE ObjectHandle,
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_ POBJECT_ATTRIBUTES ObjectAttributes,
+ _In_ POBJECT_TYPE ObjectType,
+ _In_ KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status;
+ HANDLE objectHandle;
+
+ PAGED_CODE();
+
+ // Open the object.
+ status = ObOpenObjectByName(
+ ObjectAttributes,
+ ObjectType,
+ AccessMode,
+ NULL,
+ DesiredAccess,
+ NULL,
+ &objectHandle
+ );
+
+ // Pass the handle back.
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ *ObjectHandle = objectHandle;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+ else
+ {
+ *ObjectHandle = objectHandle;
+ }
+
+ return status;
+}
diff --git a/KProcessHacker/process.c b/KProcessHacker/process.c
index bdb27261fa3b..17532e91dd5c 100644
--- a/KProcessHacker/process.c
+++ b/KProcessHacker/process.c
@@ -1,570 +1,570 @@
-/*
- * KProcessHacker
- *
- * Copyright (C) 2010-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 .
- */
-
-#include
-#include
-
-#ifdef ALLOC_PRAGMA
-#pragma alloc_text(PAGE, KpiOpenProcess)
-#pragma alloc_text(PAGE, KpiOpenProcessToken)
-#pragma alloc_text(PAGE, KpiOpenProcessJob)
-#pragma alloc_text(PAGE, KpiTerminateProcess)
-#pragma alloc_text(PAGE, KpiQueryInformationProcess)
-#pragma alloc_text(PAGE, KpiSetInformationProcess)
-#endif
-
-/**
- * Opens a process.
- *
- * \param ProcessHandle A variable which receives the process handle.
- * \param DesiredAccess The desired access to the process.
- * \param ClientId The identifier of a process or thread. If \a UniqueThread is present, the process
- * of the identified thread will be opened. If \a UniqueProcess is present, the identified process
- * will be opened.
- * \param Key An access key.
- * \li If a L2 key is provided, no access checks are performed.
- * \li If a L1 key is provided, only read access is permitted but no additional access checks are
- * performed.
- * \li If no valid key is provided, the function fails.
- * \param Client The client that initiated the request.
- * \param AccessMode The mode in which to perform access checks.
- */
-NTSTATUS KpiOpenProcess(
- __out PHANDLE ProcessHandle,
- __in ACCESS_MASK DesiredAccess,
- __in PCLIENT_ID ClientId,
- __in_opt KPH_KEY Key,
- __in PKPH_CLIENT Client,
- __in KPROCESSOR_MODE AccessMode
- )
-{
- NTSTATUS status;
- CLIENT_ID clientId;
- PEPROCESS process;
- PETHREAD thread;
- KPH_KEY_LEVEL requiredKeyLevel;
- HANDLE processHandle;
-
- PAGED_CODE();
-
- if (AccessMode != KernelMode)
- {
- __try
- {
- ProbeForWrite(ProcessHandle, sizeof(HANDLE), sizeof(HANDLE));
- ProbeForRead(ClientId, sizeof(CLIENT_ID), sizeof(ULONG));
- clientId = *ClientId;
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- return GetExceptionCode();
- }
- }
- else
- {
- clientId = *ClientId;
- }
-
- // Use the thread ID if it was specified.
- if (clientId.UniqueThread)
- {
- status = PsLookupProcessThreadByCid(&clientId, &process, &thread);
-
- if (NT_SUCCESS(status))
- {
- // We don't actually need the thread.
- ObDereferenceObject(thread);
- }
- }
- else
- {
- status = PsLookupProcessByProcessId(clientId.UniqueProcess, &process);
- }
-
- if (!NT_SUCCESS(status))
- return status;
-
- requiredKeyLevel = KphKeyLevel1;
-
- if ((DesiredAccess & KPH_PROCESS_READ_ACCESS) != DesiredAccess)
- requiredKeyLevel = KphKeyLevel2;
-
- if (NT_SUCCESS(status = KphValidateKey(requiredKeyLevel, Key, Client, AccessMode)))
- {
- // Always open in KernelMode to skip ordinary access checks.
- status = ObOpenObjectByPointer(
- process,
- 0,
- NULL,
- DesiredAccess,
- *PsProcessType,
- KernelMode,
- &processHandle
- );
- }
-
- ObDereferenceObject(process);
-
- if (NT_SUCCESS(status))
- {
- if (AccessMode != KernelMode)
- {
- __try
- {
- *ProcessHandle = processHandle;
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- status = GetExceptionCode();
- }
- }
- else
- {
- *ProcessHandle = processHandle;
- }
- }
-
- return status;
-}
-
-/**
- * Opens the token of a process.
- *
- * \param ProcessHandle A handle to a process.
- * \param DesiredAccess The desired access to the token.
- * \param TokenHandle A variable which receives the token handle.
- * \param Key An access key.
- * \li If a L2 key is provided, no access checks are performed.
- * \li If a L1 key is provided, only read access is permitted but no additional access checks are
- * performed.
- * \li If no valid key is provided, the function fails.
- * \param Client The client that initiated the request.
- * \param AccessMode The mode in which to perform access checks.
- */
-NTSTATUS KpiOpenProcessToken(
- __in HANDLE ProcessHandle,
- __in ACCESS_MASK DesiredAccess,
- __out PHANDLE TokenHandle,
- __in_opt KPH_KEY Key,
- __in PKPH_CLIENT Client,
- __in KPROCESSOR_MODE AccessMode
- )
-{
- NTSTATUS status;
- PEPROCESS process;
- PACCESS_TOKEN primaryToken;
- KPH_KEY_LEVEL requiredKeyLevel;
- HANDLE tokenHandle;
-
- PAGED_CODE();
-
- if (AccessMode != KernelMode)
- {
- __try
- {
- ProbeForWrite(TokenHandle, sizeof(HANDLE), sizeof(HANDLE));
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- return GetExceptionCode();
- }
- }
-
- status = ObReferenceObjectByHandle(
- ProcessHandle,
- 0,
- *PsProcessType,
- AccessMode,
- &process,
- NULL
- );
-
- if (!NT_SUCCESS(status))
- return status;
-
- if (primaryToken = PsReferencePrimaryToken(process))
- {
- requiredKeyLevel = KphKeyLevel1;
-
- if ((DesiredAccess & KPH_TOKEN_READ_ACCESS) != DesiredAccess)
- requiredKeyLevel = KphKeyLevel2;
-
- if (NT_SUCCESS(status = KphValidateKey(requiredKeyLevel, Key, Client, AccessMode)))
- {
- status = ObOpenObjectByPointer(
- primaryToken,
- 0,
- NULL,
- DesiredAccess,
- *SeTokenObjectType,
- KernelMode,
- &tokenHandle
- );
- }
-
- PsDereferencePrimaryToken(primaryToken);
- }
- else
- {
- status = STATUS_NO_TOKEN;
- }
-
- ObDereferenceObject(process);
-
- if (NT_SUCCESS(status))
- {
- if (AccessMode != KernelMode)
- {
- __try
- {
- *TokenHandle = tokenHandle;
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- status = GetExceptionCode();
- }
- }
- else
- {
- *TokenHandle = tokenHandle;
- }
- }
-
- return status;
-}
-
-/**
- * Opens the job object of a process.
- *
- * \param ProcessHandle A handle to a process.
- * \param DesiredAccess The desired access to the job.
- * \param JobHandle A variable which receives the job object handle.
- * \param AccessMode The mode in which to perform access checks.
- */
-NTSTATUS KpiOpenProcessJob(
- __in HANDLE ProcessHandle,
- __in ACCESS_MASK DesiredAccess,
- __out PHANDLE JobHandle,
- __in KPROCESSOR_MODE AccessMode
- )
-{
- NTSTATUS status;
- PEPROCESS process;
- PEJOB job;
- HANDLE jobHandle = NULL;
-
- PAGED_CODE();
-
- if (AccessMode != KernelMode)
- {
- __try
- {
- ProbeForWrite(JobHandle, sizeof(HANDLE), sizeof(HANDLE));
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- return GetExceptionCode();
- }
- }
-
- status = ObReferenceObjectByHandle(
- ProcessHandle,
- 0,
- *PsProcessType,
- AccessMode,
- &process,
- NULL
- );
-
- if (!NT_SUCCESS(status))
- return status;
-
- job = PsGetProcessJob(process);
-
- if (job)
- {
- status = ObOpenObjectByPointer(
- job,
- 0,
- NULL,
- DesiredAccess,
- *PsJobType,
- AccessMode,
- &jobHandle
- );
- }
- else
- {
- status = STATUS_NOT_FOUND;
- }
-
- ObDereferenceObject(process);
-
- if (NT_SUCCESS(status))
- {
- if (AccessMode != KernelMode)
- {
- __try
- {
- *JobHandle = jobHandle;
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- status = GetExceptionCode();
- }
- }
- else
- {
- *JobHandle = jobHandle;
- }
- }
-
- return status;
-}
-
-/**
- * Terminates a process.
- *
- * \param ProcessHandle A handle to a process.
- * \param ExitStatus A status value which indicates why the process is being terminated.
- * \param Key An access key.
- * \li If a L2 key is provided, no access checks are performed.
- * \li If no valid L2 key is provided, the function fails.
- * \param Client The client that initiated the request.
- * \param AccessMode The mode in which to perform access checks.
- */
-NTSTATUS KpiTerminateProcess(
- __in HANDLE ProcessHandle,
- __in NTSTATUS ExitStatus,
- __in_opt KPH_KEY Key,
- __in PKPH_CLIENT Client,
- __in KPROCESSOR_MODE AccessMode
- )
-{
- NTSTATUS status;
- PEPROCESS process;
-
- PAGED_CODE();
-
- if (!NT_SUCCESS(status = KphValidateKey(KphKeyLevel2, Key, Client, AccessMode)))
- return status;
-
- status = ObReferenceObjectByHandle(
- ProcessHandle,
- 0,
- *PsProcessType,
- AccessMode,
- &process,
- NULL
- );
-
- if (!NT_SUCCESS(status))
- return status;
-
- if (process != PsGetCurrentProcess())
- {
- HANDLE newProcessHandle;
-
- // Re-open the process to get a kernel handle.
- if (NT_SUCCESS(status = ObOpenObjectByPointer(
- process,
- OBJ_KERNEL_HANDLE,
- NULL,
- PROCESS_TERMINATE,
- *PsProcessType,
- KernelMode,
- &newProcessHandle
- )))
- {
- status = ZwTerminateProcess(newProcessHandle, ExitStatus);
- ZwClose(newProcessHandle);
- }
- }
- else
- {
- status = STATUS_CANT_TERMINATE_SELF;
- }
-
- ObDereferenceObject(process);
-
- return status;
-}
-
-/**
- * Queries process information.
- *
- * \param ProcessHandle A handle to a process.
- * \param ProcessInformationClass The type of information to query.
- * \param ProcessInformation The buffer in which the information will be stored.
- * \param ProcessInformationLength The number of bytes available in \a ProcessInformation.
- * \param ReturnLength A variable which receives the number of bytes required to be available in
- * \a ProcessInformation.
- * \param AccessMode The mode in which to perform access checks.
- */
-NTSTATUS KpiQueryInformationProcess(
- __in HANDLE ProcessHandle,
- __in KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,
- __out_bcount(ProcessInformationLength) PVOID ProcessInformation,
- __in ULONG ProcessInformationLength,
- __out_opt PULONG ReturnLength,
- __in KPROCESSOR_MODE AccessMode
- )
-{
- NTSTATUS status;
- PEPROCESS process;
- ULONG returnLength;
-
- PAGED_CODE();
-
- if (AccessMode != KernelMode)
- {
- ULONG alignment;
-
- switch (ProcessInformationClass)
- {
- default:
- alignment = sizeof(ULONG);
- break;
- }
-
- __try
- {
- ProbeForWrite(ProcessInformation, ProcessInformationLength, alignment);
-
- if (ReturnLength)
- ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG));
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- return GetExceptionCode();
- }
- }
-
- status = ObReferenceObjectByHandle(
- ProcessHandle,
- PROCESS_QUERY_INFORMATION,
- *PsProcessType,
- AccessMode,
- &process,
- NULL
- );
-
- if (!NT_SUCCESS(status))
- return status;
-
- switch (ProcessInformationClass)
- {
- default:
- status = STATUS_INVALID_INFO_CLASS;
- returnLength = 0;
- break;
- }
-
- ObDereferenceObject(process);
-
- if (ReturnLength)
- {
- if (AccessMode != KernelMode)
- {
- __try
- {
- *ReturnLength = returnLength;
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- NOTHING;
- }
- }
- else
- {
- *ReturnLength = returnLength;
- }
- }
-
- return status;
-}
-
-/**
- * Sets process information.
- *
- * \param ProcessHandle A handle to a process.
- * \param ProcessInformationClass The type of information to set.
- * \param ProcessInformation A buffer which contains the information to set.
- * \param ProcessInformationLength The number of bytes present in \a ProcessInformation.
- * \param AccessMode The mode in which to perform access checks.
- */
-NTSTATUS KpiSetInformationProcess(
- __in HANDLE ProcessHandle,
- __in KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,
- __in_bcount(ProcessInformationLength) PVOID ProcessInformation,
- __in ULONG ProcessInformationLength,
- __in KPROCESSOR_MODE AccessMode
- )
-{
- NTSTATUS status;
- PEPROCESS process;
-
- PAGED_CODE();
-
- if (AccessMode != KernelMode)
- {
- ULONG alignment;
-
- switch (ProcessInformationClass)
- {
- default:
- alignment = sizeof(ULONG);
- break;
- }
-
- __try
- {
- ProbeForRead(ProcessInformation, ProcessInformationLength, alignment);
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- return GetExceptionCode();
- }
- }
-
- status = ObReferenceObjectByHandle(
- ProcessHandle,
- PROCESS_SET_INFORMATION,
- *PsProcessType,
- AccessMode,
- &process,
- NULL
- );
-
- if (!NT_SUCCESS(status))
- return status;
-
- switch (ProcessInformationClass)
- {
- default:
- status = STATUS_INVALID_INFO_CLASS;
- break;
- }
-
- ObDereferenceObject(process);
-
- return status;
-}
+/*
+ * KProcessHacker
+ *
+ * Copyright (C) 2010-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 .
+ */
+
+#include
+#include
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, KpiOpenProcess)
+#pragma alloc_text(PAGE, KpiOpenProcessToken)
+#pragma alloc_text(PAGE, KpiOpenProcessJob)
+#pragma alloc_text(PAGE, KpiTerminateProcess)
+#pragma alloc_text(PAGE, KpiQueryInformationProcess)
+#pragma alloc_text(PAGE, KpiSetInformationProcess)
+#endif
+
+/**
+ * Opens a process.
+ *
+ * \param ProcessHandle A variable which receives the process handle.
+ * \param DesiredAccess The desired access to the process.
+ * \param ClientId The identifier of a process or thread. If \a UniqueThread is present, the process
+ * of the identified thread will be opened. If \a UniqueProcess is present, the identified process
+ * will be opened.
+ * \param Key An access key.
+ * \li If a L2 key is provided, no access checks are performed.
+ * \li If a L1 key is provided, only read access is permitted but no additional access checks are
+ * performed.
+ * \li If no valid key is provided, the function fails.
+ * \param Client The client that initiated the request.
+ * \param AccessMode The mode in which to perform access checks.
+ */
+NTSTATUS KpiOpenProcess(
+ _Out_ PHANDLE ProcessHandle,
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_ PCLIENT_ID ClientId,
+ _In_opt_ KPH_KEY Key,
+ _In_ PKPH_CLIENT Client,
+ _In_ KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status;
+ CLIENT_ID clientId;
+ PEPROCESS process;
+ PETHREAD thread;
+ KPH_KEY_LEVEL requiredKeyLevel;
+ HANDLE processHandle;
+
+ PAGED_CODE();
+
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ ProbeForWrite(ProcessHandle, sizeof(HANDLE), sizeof(HANDLE));
+ ProbeForRead(ClientId, sizeof(CLIENT_ID), sizeof(ULONG));
+ clientId = *ClientId;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+ }
+ else
+ {
+ clientId = *ClientId;
+ }
+
+ // Use the thread ID if it was specified.
+ if (clientId.UniqueThread)
+ {
+ status = PsLookupProcessThreadByCid(&clientId, &process, &thread);
+
+ if (NT_SUCCESS(status))
+ {
+ // We don't actually need the thread.
+ ObDereferenceObject(thread);
+ }
+ }
+ else
+ {
+ status = PsLookupProcessByProcessId(clientId.UniqueProcess, &process);
+ }
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ requiredKeyLevel = KphKeyLevel1;
+
+ if ((DesiredAccess & KPH_PROCESS_READ_ACCESS) != DesiredAccess)
+ requiredKeyLevel = KphKeyLevel2;
+
+ if (NT_SUCCESS(status = KphValidateKey(requiredKeyLevel, Key, Client, AccessMode)))
+ {
+ // Always open in KernelMode to skip ordinary access checks.
+ status = ObOpenObjectByPointer(
+ process,
+ 0,
+ NULL,
+ DesiredAccess,
+ *PsProcessType,
+ KernelMode,
+ &processHandle
+ );
+
+ if (NT_SUCCESS(status))
+ {
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ *ProcessHandle = processHandle;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+ else
+ {
+ *ProcessHandle = processHandle;
+ }
+ }
+ }
+
+ ObDereferenceObject(process);
+
+ return status;
+}
+
+/**
+ * Opens the token of a process.
+ *
+ * \param ProcessHandle A handle to a process.
+ * \param DesiredAccess The desired access to the token.
+ * \param TokenHandle A variable which receives the token handle.
+ * \param Key An access key.
+ * \li If a L2 key is provided, no access checks are performed.
+ * \li If a L1 key is provided, only read access is permitted but no additional access checks are
+ * performed.
+ * \li If no valid key is provided, the function fails.
+ * \param Client The client that initiated the request.
+ * \param AccessMode The mode in which to perform access checks.
+ */
+NTSTATUS KpiOpenProcessToken(
+ _In_ HANDLE ProcessHandle,
+ _In_ ACCESS_MASK DesiredAccess,
+ _Out_ PHANDLE TokenHandle,
+ _In_opt_ KPH_KEY Key,
+ _In_ PKPH_CLIENT Client,
+ _In_ KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status;
+ PEPROCESS process;
+ PACCESS_TOKEN primaryToken;
+ KPH_KEY_LEVEL requiredKeyLevel;
+ HANDLE tokenHandle;
+
+ PAGED_CODE();
+
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ ProbeForWrite(TokenHandle, sizeof(HANDLE), sizeof(HANDLE));
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+ }
+
+ status = ObReferenceObjectByHandle(
+ ProcessHandle,
+ 0,
+ *PsProcessType,
+ AccessMode,
+ &process,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ if (primaryToken = PsReferencePrimaryToken(process))
+ {
+ requiredKeyLevel = KphKeyLevel1;
+
+ if ((DesiredAccess & KPH_TOKEN_READ_ACCESS) != DesiredAccess)
+ requiredKeyLevel = KphKeyLevel2;
+
+ if (NT_SUCCESS(status = KphValidateKey(requiredKeyLevel, Key, Client, AccessMode)))
+ {
+ status = ObOpenObjectByPointer(
+ primaryToken,
+ 0,
+ NULL,
+ DesiredAccess,
+ *SeTokenObjectType,
+ KernelMode,
+ &tokenHandle
+ );
+
+ if (NT_SUCCESS(status))
+ {
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ *TokenHandle = tokenHandle;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+ else
+ {
+ *TokenHandle = tokenHandle;
+ }
+ }
+ }
+
+ PsDereferencePrimaryToken(primaryToken);
+ }
+ else
+ {
+ status = STATUS_NO_TOKEN;
+ }
+
+ ObDereferenceObject(process);
+
+ return status;
+}
+
+/**
+ * Opens the job object of a process.
+ *
+ * \param ProcessHandle A handle to a process.
+ * \param DesiredAccess The desired access to the job.
+ * \param JobHandle A variable which receives the job object handle.
+ * \param AccessMode The mode in which to perform access checks.
+ */
+NTSTATUS KpiOpenProcessJob(
+ _In_ HANDLE ProcessHandle,
+ _In_ ACCESS_MASK DesiredAccess,
+ _Out_ PHANDLE JobHandle,
+ _In_ KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status;
+ PEPROCESS process;
+ PEJOB job;
+ HANDLE jobHandle;
+
+ PAGED_CODE();
+
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ ProbeForWrite(JobHandle, sizeof(HANDLE), sizeof(HANDLE));
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+ }
+
+ status = ObReferenceObjectByHandle(
+ ProcessHandle,
+ 0,
+ *PsProcessType,
+ AccessMode,
+ &process,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ job = PsGetProcessJob(process);
+
+ if (job)
+ {
+ status = ObOpenObjectByPointer(
+ job,
+ 0,
+ NULL,
+ DesiredAccess,
+ *PsJobType,
+ AccessMode,
+ &jobHandle
+ );
+
+ if (NT_SUCCESS(status))
+ {
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ *JobHandle = jobHandle;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+ else
+ {
+ *JobHandle = jobHandle;
+ }
+ }
+ }
+ else
+ {
+ status = STATUS_NOT_FOUND;
+ }
+
+ ObDereferenceObject(process);
+
+ return status;
+}
+
+/**
+ * Terminates a process.
+ *
+ * \param ProcessHandle A handle to a process.
+ * \param ExitStatus A status value which indicates why the process is being terminated.
+ * \param Key An access key.
+ * \li If a L2 key is provided, no access checks are performed.
+ * \li If no valid L2 key is provided, the function fails.
+ * \param Client The client that initiated the request.
+ * \param AccessMode The mode in which to perform access checks.
+ */
+NTSTATUS KpiTerminateProcess(
+ _In_ HANDLE ProcessHandle,
+ _In_ NTSTATUS ExitStatus,
+ _In_opt_ KPH_KEY Key,
+ _In_ PKPH_CLIENT Client,
+ _In_ KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status;
+ PEPROCESS process;
+
+ PAGED_CODE();
+
+ if (!NT_SUCCESS(status = KphValidateKey(KphKeyLevel2, Key, Client, AccessMode)))
+ return status;
+
+ status = ObReferenceObjectByHandle(
+ ProcessHandle,
+ 0,
+ *PsProcessType,
+ AccessMode,
+ &process,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ if (process != PsGetCurrentProcess())
+ {
+ HANDLE newProcessHandle;
+
+ // Re-open the process to get a kernel handle.
+ if (NT_SUCCESS(status = ObOpenObjectByPointer(
+ process,
+ OBJ_KERNEL_HANDLE,
+ NULL,
+ PROCESS_TERMINATE,
+ *PsProcessType,
+ KernelMode,
+ &newProcessHandle
+ )))
+ {
+ status = ZwTerminateProcess(newProcessHandle, ExitStatus);
+ ZwClose(newProcessHandle);
+ }
+ }
+ else
+ {
+ status = STATUS_CANT_TERMINATE_SELF;
+ }
+
+ ObDereferenceObject(process);
+
+ return status;
+}
+
+/**
+ * Queries process information.
+ *
+ * \param ProcessHandle A handle to a process.
+ * \param ProcessInformationClass The type of information to query.
+ * \param ProcessInformation The buffer in which the information will be stored.
+ * \param ProcessInformationLength The number of bytes available in \a ProcessInformation.
+ * \param ReturnLength A variable which receives the number of bytes required to be available in
+ * \a ProcessInformation.
+ * \param AccessMode The mode in which to perform access checks.
+ */
+NTSTATUS KpiQueryInformationProcess(
+ _In_ HANDLE ProcessHandle,
+ _In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,
+ _Out_writes_bytes_(ProcessInformationLength) PVOID ProcessInformation,
+ _In_ ULONG ProcessInformationLength,
+ _Out_opt_ PULONG ReturnLength,
+ _In_ KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status;
+ PEPROCESS process;
+ ULONG returnLength;
+
+ PAGED_CODE();
+
+ if (AccessMode != KernelMode)
+ {
+ ULONG alignment;
+
+ switch (ProcessInformationClass)
+ {
+ default:
+ alignment = sizeof(ULONG);
+ break;
+ }
+
+ __try
+ {
+ ProbeForWrite(ProcessInformation, ProcessInformationLength, alignment);
+
+ if (ReturnLength)
+ ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG));
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+ }
+
+ status = ObReferenceObjectByHandle(
+ ProcessHandle,
+ PROCESS_QUERY_INFORMATION,
+ *PsProcessType,
+ AccessMode,
+ &process,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ switch (ProcessInformationClass)
+ {
+ default:
+ status = STATUS_INVALID_INFO_CLASS;
+ returnLength = 0;
+ break;
+ }
+
+ ObDereferenceObject(process);
+
+ if (ReturnLength)
+ {
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ *ReturnLength = returnLength;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ NOTHING;
+ }
+ }
+ else
+ {
+ *ReturnLength = returnLength;
+ }
+ }
+
+ return status;
+}
+
+/**
+ * Sets process information.
+ *
+ * \param ProcessHandle A handle to a process.
+ * \param ProcessInformationClass The type of information to set.
+ * \param ProcessInformation A buffer which contains the information to set.
+ * \param ProcessInformationLength The number of bytes present in \a ProcessInformation.
+ * \param AccessMode The mode in which to perform access checks.
+ */
+NTSTATUS KpiSetInformationProcess(
+ _In_ HANDLE ProcessHandle,
+ _In_ KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,
+ _In_reads_bytes_(ProcessInformationLength) PVOID ProcessInformation,
+ _In_ ULONG ProcessInformationLength,
+ _In_ KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status;
+ PEPROCESS process;
+
+ PAGED_CODE();
+
+ if (AccessMode != KernelMode)
+ {
+ ULONG alignment;
+
+ switch (ProcessInformationClass)
+ {
+ default:
+ alignment = sizeof(ULONG);
+ break;
+ }
+
+ __try
+ {
+ ProbeForRead(ProcessInformation, ProcessInformationLength, alignment);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+ }
+
+ status = ObReferenceObjectByHandle(
+ ProcessHandle,
+ PROCESS_SET_INFORMATION,
+ *PsProcessType,
+ AccessMode,
+ &process,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ switch (ProcessInformationClass)
+ {
+ default:
+ status = STATUS_INVALID_INFO_CLASS;
+ break;
+ }
+
+ ObDereferenceObject(process);
+
+ return status;
+}
diff --git a/KProcessHacker/qrydrv.c b/KProcessHacker/qrydrv.c
index 3ecfb6197f00..cc3879e0e3fb 100644
--- a/KProcessHacker/qrydrv.c
+++ b/KProcessHacker/qrydrv.c
@@ -1,238 +1,238 @@
-/*
- * KProcessHacker
- *
- * Copyright (C) 2010-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 .
- */
-
-#include
-
-VOID KphpCopyInfoUnicodeString(
- __out PVOID Information,
- __in_opt PUNICODE_STRING UnicodeString
- );
-
-#ifdef ALLOC_PRAGMA
-#pragma alloc_text(PAGE, KpiOpenDriver)
-#pragma alloc_text(PAGE, KpiQueryInformationDriver)
-#pragma alloc_text(PAGE, KphpCopyInfoUnicodeString)
-#endif
-
-NTSTATUS KpiOpenDriver(
- __out PHANDLE DriverHandle,
- __in ACCESS_MASK DesiredAccess,
- __in POBJECT_ATTRIBUTES ObjectAttributes,
- __in KPROCESSOR_MODE AccessMode
- )
-{
- PAGED_CODE();
-
- return KphOpenNamedObject(
- DriverHandle,
- DesiredAccess,
- ObjectAttributes,
- *IoDriverObjectType,
- AccessMode
- );
-}
-
-NTSTATUS KpiQueryInformationDriver(
- __in HANDLE DriverHandle,
- __in DRIVER_INFORMATION_CLASS DriverInformationClass,
- __out_bcount(DriverInformationLength) PVOID DriverInformation,
- __in ULONG DriverInformationLength,
- __out_opt PULONG ReturnLength,
- __in KPROCESSOR_MODE AccessMode
- )
-{
- NTSTATUS status = STATUS_SUCCESS;
- PDRIVER_OBJECT driverObject;
-
- PAGED_CODE();
-
- if (AccessMode != KernelMode)
- {
- __try
- {
- ProbeForWrite(DriverInformation, DriverInformationLength, 1);
-
- if (ReturnLength)
- ProbeForWrite(ReturnLength, sizeof(ULONG), 1);
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- return GetExceptionCode();
- }
- }
-
- status = ObReferenceObjectByHandle(
- DriverHandle,
- 0,
- *IoDriverObjectType,
- AccessMode,
- &driverObject,
- NULL
- );
-
- if (!NT_SUCCESS(status))
- return status;
-
- __try
- {
- switch (DriverInformationClass)
- {
- // Basic information such as flags, driver base and driver size.
- case DriverBasicInformation:
- {
- if (DriverInformationLength == sizeof(DRIVER_BASIC_INFORMATION))
- {
- PDRIVER_BASIC_INFORMATION basicInfo;
-
- basicInfo = (PDRIVER_BASIC_INFORMATION)DriverInformation;
- basicInfo->Flags = driverObject->Flags;
- basicInfo->DriverStart = driverObject->DriverStart;
- basicInfo->DriverSize = driverObject->DriverSize;
- }
- else
- {
- status = STATUS_INFO_LENGTH_MISMATCH;
- }
-
- if (ReturnLength)
- *ReturnLength = sizeof(DRIVER_BASIC_INFORMATION);
- }
- break;
-
- // The name of the driver - e.g. \Driver\Null.
- case DriverNameInformation:
- {
- if (DriverInformation)
- {
- /* Check buffer length. */
- if (sizeof(UNICODE_STRING) + driverObject->DriverName.Length <=
- DriverInformationLength)
- {
- KphpCopyInfoUnicodeString(
- DriverInformation,
- &driverObject->DriverName
- );
- }
- else
- {
- status = STATUS_BUFFER_TOO_SMALL;
- }
- }
-
- if (ReturnLength)
- *ReturnLength = sizeof(UNICODE_STRING) + driverObject->DriverName.Length;
- }
- break;
-
- // The name of the driver's service key - e.g. \REGISTRY\...
- case DriverServiceKeyNameInformation:
- {
- if (driverObject->DriverExtension)
- {
- if (DriverInformation)
- {
- if (sizeof(UNICODE_STRING) +
- driverObject->DriverExtension->ServiceKeyName.Length <=
- DriverInformationLength)
- {
- KphpCopyInfoUnicodeString(
- DriverInformation,
- &driverObject->DriverExtension->ServiceKeyName
- );
- }
- else
- {
- status = STATUS_BUFFER_TOO_SMALL;
- }
- }
-
- if (ReturnLength)
- {
- *ReturnLength = sizeof(UNICODE_STRING) +
- driverObject->DriverExtension->ServiceKeyName.Length;
- }
- }
- else
- {
- if (DriverInformation)
- {
- if (sizeof(UNICODE_STRING) <= DriverInformationLength)
- {
- // Zero the information buffer.
- KphpCopyInfoUnicodeString(
- DriverInformation,
- NULL
- );
- }
- else
- {
- status = STATUS_BUFFER_TOO_SMALL;
- }
- }
-
- if (ReturnLength)
- *ReturnLength = sizeof(UNICODE_STRING);
- }
- }
- break;
-
- default:
- {
- status = STATUS_INVALID_INFO_CLASS;
- }
- }
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- status = GetExceptionCode();
- }
-
- ObDereferenceObject(driverObject);
-
- return status;
-}
-
-VOID KphpCopyInfoUnicodeString(
- __out PVOID Information,
- __in_opt PUNICODE_STRING UnicodeString
- )
-{
- PUNICODE_STRING targetUnicodeString = Information;
- PWCHAR targetBuffer;
-
- PAGED_CODE();
-
- if (UnicodeString)
- {
- targetBuffer = (PWCHAR)((PCHAR)Information + sizeof(UNICODE_STRING));
-
- targetUnicodeString->Length = UnicodeString->Length;
- targetUnicodeString->MaximumLength = UnicodeString->Length;
- targetUnicodeString->Buffer = targetBuffer;
- memcpy(targetBuffer, UnicodeString->Buffer, UnicodeString->Length);
- }
- else
- {
- targetUnicodeString->Length = 0;
- targetUnicodeString->MaximumLength = 0;
- targetUnicodeString->Buffer = NULL;
- }
-}
+/*
+ * KProcessHacker
+ *
+ * Copyright (C) 2010-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 .
+ */
+
+#include
+
+VOID KphpCopyInfoUnicodeString(
+ _Out_ PVOID Information,
+ _In_opt_ PUNICODE_STRING UnicodeString
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, KpiOpenDriver)
+#pragma alloc_text(PAGE, KpiQueryInformationDriver)
+#pragma alloc_text(PAGE, KphpCopyInfoUnicodeString)
+#endif
+
+NTSTATUS KpiOpenDriver(
+ _Out_ PHANDLE DriverHandle,
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_ POBJECT_ATTRIBUTES ObjectAttributes,
+ _In_ KPROCESSOR_MODE AccessMode
+ )
+{
+ PAGED_CODE();
+
+ return KphOpenNamedObject(
+ DriverHandle,
+ DesiredAccess,
+ ObjectAttributes,
+ *IoDriverObjectType,
+ AccessMode
+ );
+}
+
+NTSTATUS KpiQueryInformationDriver(
+ _In_ HANDLE DriverHandle,
+ _In_ DRIVER_INFORMATION_CLASS DriverInformationClass,
+ _Out_writes_bytes_(DriverInformationLength) PVOID DriverInformation,
+ _In_ ULONG DriverInformationLength,
+ _Out_opt_ PULONG ReturnLength,
+ _In_ KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PDRIVER_OBJECT driverObject;
+
+ PAGED_CODE();
+
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ ProbeForWrite(DriverInformation, DriverInformationLength, 1);
+
+ if (ReturnLength)
+ ProbeForWrite(ReturnLength, sizeof(ULONG), 1);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+ }
+
+ status = ObReferenceObjectByHandle(
+ DriverHandle,
+ 0,
+ *IoDriverObjectType,
+ AccessMode,
+ &driverObject,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ __try
+ {
+ switch (DriverInformationClass)
+ {
+ // Basic information such as flags, driver base and driver size.
+ case DriverBasicInformation:
+ {
+ if (DriverInformationLength == sizeof(DRIVER_BASIC_INFORMATION))
+ {
+ PDRIVER_BASIC_INFORMATION basicInfo;
+
+ basicInfo = (PDRIVER_BASIC_INFORMATION)DriverInformation;
+ basicInfo->Flags = driverObject->Flags;
+ basicInfo->DriverStart = driverObject->DriverStart;
+ basicInfo->DriverSize = driverObject->DriverSize;
+ }
+ else
+ {
+ status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+
+ if (ReturnLength)
+ *ReturnLength = sizeof(DRIVER_BASIC_INFORMATION);
+ }
+ break;
+
+ // The name of the driver - e.g. \Driver\Null.
+ case DriverNameInformation:
+ {
+ if (DriverInformation)
+ {
+ /* Check buffer length. */
+ if (sizeof(UNICODE_STRING) + driverObject->DriverName.Length <=
+ DriverInformationLength)
+ {
+ KphpCopyInfoUnicodeString(
+ DriverInformation,
+ &driverObject->DriverName
+ );
+ }
+ else
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ }
+ }
+
+ if (ReturnLength)
+ *ReturnLength = sizeof(UNICODE_STRING) + driverObject->DriverName.Length;
+ }
+ break;
+
+ // The name of the driver's service key - e.g. \REGISTRY\...
+ case DriverServiceKeyNameInformation:
+ {
+ if (driverObject->DriverExtension)
+ {
+ if (DriverInformation)
+ {
+ if (sizeof(UNICODE_STRING) +
+ driverObject->DriverExtension->ServiceKeyName.Length <=
+ DriverInformationLength)
+ {
+ KphpCopyInfoUnicodeString(
+ DriverInformation,
+ &driverObject->DriverExtension->ServiceKeyName
+ );
+ }
+ else
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ }
+ }
+
+ if (ReturnLength)
+ {
+ *ReturnLength = sizeof(UNICODE_STRING) +
+ driverObject->DriverExtension->ServiceKeyName.Length;
+ }
+ }
+ else
+ {
+ if (DriverInformation)
+ {
+ if (sizeof(UNICODE_STRING) <= DriverInformationLength)
+ {
+ // Zero the information buffer.
+ KphpCopyInfoUnicodeString(
+ DriverInformation,
+ NULL
+ );
+ }
+ else
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ }
+ }
+
+ if (ReturnLength)
+ *ReturnLength = sizeof(UNICODE_STRING);
+ }
+ }
+ break;
+
+ default:
+ {
+ status = STATUS_INVALID_INFO_CLASS;
+ }
+ }
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+
+ ObDereferenceObject(driverObject);
+
+ return status;
+}
+
+VOID KphpCopyInfoUnicodeString(
+ _Out_ PVOID Information,
+ _In_opt_ PUNICODE_STRING UnicodeString
+ )
+{
+ PUNICODE_STRING targetUnicodeString = Information;
+ PWCHAR targetBuffer;
+
+ PAGED_CODE();
+
+ if (UnicodeString)
+ {
+ targetBuffer = (PWCHAR)PTR_ADD_OFFSET(Information, sizeof(UNICODE_STRING));
+
+ targetUnicodeString->Length = UnicodeString->Length;
+ targetUnicodeString->MaximumLength = UnicodeString->Length;
+ targetUnicodeString->Buffer = targetBuffer;
+ memcpy(targetBuffer, UnicodeString->Buffer, UnicodeString->Length);
+ }
+ else
+ {
+ targetUnicodeString->Length = 0;
+ targetUnicodeString->MaximumLength = 0;
+ targetUnicodeString->Buffer = NULL;
+ }
+}
diff --git a/KProcessHacker/resource.rc b/KProcessHacker/resource.rc
index ca42f86d3631..ce831638b987 100644
--- a/KProcessHacker/resource.rc
+++ b/KProcessHacker/resource.rc
@@ -1,53 +1,53 @@
-#include
-
-#define VER_COMMA 3,1,0,0
-#define VER_STR "3.1\0"
-
-#define VER_FILEVERSION VER_COMMA
-#define VER_FILEVERSION_STR VER_STR
-#define VER_PRODUCTVERSION VER_COMMA
-#define VER_PRODUCTVERSION_STR VER_STR
-
-#ifndef DEBUG
-#define VER_DEBUG 0
-#else
-#define VER_DEBUG VS_FF_DEBUG
-#endif
-
-#define VER_PRIVATEBUILD 0
-#define VER_PRERELEASE 0
-
-#define VER_COMPANYNAME_STR "wj32\0"
-#define VER_FILEDESCRIPTION_STR "KProcessHacker\0"
-#define VER_LEGALCOPYRIGHT_STR "Licensed under the GNU GPL, v3.\0"
-#define VER_ORIGINALFILENAME_STR "kprocesshacker.sys\0"
-#define VER_PRODUCTNAME_STR "KProcessHacker\0"
-
-VS_VERSION_INFO VERSIONINFO
-FILEVERSION VER_FILEVERSION
-PRODUCTVERSION VER_PRODUCTVERSION
-FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
-FILEFLAGS (VER_PRIVATEBUILD | VER_PRERELEASE | VER_DEBUG)
-FILEOS VOS__WINDOWS32
-FILETYPE VFT_DRV
-FILESUBTYPE VFT2_DRV_SYSTEM
-BEGIN
- BLOCK "StringFileInfo"
- BEGIN
- BLOCK "040904E4"
- BEGIN
- VALUE "CompanyName", VER_COMPANYNAME_STR
- VALUE "FileDescription", VER_FILEDESCRIPTION_STR
- VALUE "FileVersion", VER_FILEVERSION_STR
- VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR
- VALUE "OriginalFilename", VER_ORIGINALFILENAME_STR
- VALUE "ProductName", VER_PRODUCTNAME_STR
- VALUE "ProductVersion", VER_PRODUCTVERSION_STR
- END
- END
-
- BLOCK "VarFileInfo"
- BEGIN
- VALUE "Translation", 0x409, 1252
- END
-END
+#include
+
+#define VER_COMMA 3,1,0,0
+#define VER_STR "3.1\0"
+
+#define VER_FILEVERSION VER_COMMA
+#define VER_FILEVERSION_STR VER_STR
+#define VER_PRODUCTVERSION VER_COMMA
+#define VER_PRODUCTVERSION_STR VER_STR
+
+#ifndef DEBUG
+#define VER_DEBUG 0
+#else
+#define VER_DEBUG VS_FF_DEBUG
+#endif
+
+#define VER_PRIVATEBUILD 0
+#define VER_PRERELEASE 0
+
+#define VER_COMPANYNAME_STR "wj32\0"
+#define VER_FILEDESCRIPTION_STR "KProcessHacker\0"
+#define VER_LEGALCOPYRIGHT_STR "Licensed under the GNU GPL, v3.\0"
+#define VER_ORIGINALFILENAME_STR "kprocesshacker.sys\0"
+#define VER_PRODUCTNAME_STR "KProcessHacker\0"
+
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION VER_FILEVERSION
+PRODUCTVERSION VER_PRODUCTVERSION
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+FILEFLAGS (VER_PRIVATEBUILD | VER_PRERELEASE | VER_DEBUG)
+FILEOS VOS__WINDOWS32
+FILETYPE VFT_DRV
+FILESUBTYPE VFT2_DRV_SYSTEM
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4"
+ BEGIN
+ VALUE "CompanyName", VER_COMPANYNAME_STR
+ VALUE "FileDescription", VER_FILEDESCRIPTION_STR
+ VALUE "FileVersion", VER_FILEVERSION_STR
+ VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR
+ VALUE "OriginalFilename", VER_ORIGINALFILENAME_STR
+ VALUE "ProductName", VER_PRODUCTNAME_STR
+ VALUE "ProductVersion", VER_PRODUCTVERSION_STR
+ END
+ END
+
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1252
+ END
+END
diff --git a/KProcessHacker/sign.cmd b/KProcessHacker/sign.cmd
deleted file mode 100644
index fe9c32599e2a..000000000000
--- a/KProcessHacker/sign.cmd
+++ /dev/null
@@ -1,7 +0,0 @@
-@echo off
-set PHBASE=..
-set SIGN_TIMESTAMP=1
-copy bin\i386\kprocesshacker.sys bin-signed\i386\kprocesshacker.sys
-copy bin\amd64\kprocesshacker.sys bin-signed\amd64\kprocesshacker.sys
-call ..\build\internal\sign.cmd bin-signed\i386\kprocesshacker.sys kmcs
-call ..\build\internal\sign.cmd bin-signed\amd64\kprocesshacker.sys kmcs
diff --git a/KProcessHacker/sources.inc b/KProcessHacker/sources.inc
deleted file mode 100644
index d50fe7368fa1..000000000000
--- a/KProcessHacker/sources.inc
+++ /dev/null
@@ -1,28 +0,0 @@
-TARGETTYPE=DRIVER
-
-!IF !DEFINED(TARGETNAME)
-TARGETNAME=kprocesshacker
-!ENDIF
-
-!IF !DEFINED(TARGETPATH)
-TARGETPATH=..\bin
-!ENDIF
-
-TARGETLIBS=$(TARGETLIBS) $(DDK_LIB_PATH)\ksecdd.lib
-
-INCLUDES=$(DDK_INC_PATH);..\include;..\..\phnt\include;..\..\phlib\include
-LIBS=%BUILD%\lib
-
-SOURCES= \
- ..\main.c \
- ..\devctrl.c \
- ..\dyndata.c \
- ..\dynimp.c \
- ..\object.c \
- ..\process.c \
- ..\qrydrv.c \
- ..\thread.c \
- ..\util.c \
- ..\verify.c \
- ..\vm.c \
- ..\resource.rc
diff --git a/KProcessHacker/thread.c b/KProcessHacker/thread.c
index 1ac2b750aab7..15ccd26705b8 100644
--- a/KProcessHacker/thread.c
+++ b/KProcessHacker/thread.c
@@ -1,714 +1,714 @@
-/*
- * KProcessHacker
- *
- * Copyright (C) 2010-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 .
- */
-
-#include
-#include
-
-typedef struct _CAPTURE_BACKTRACE_THREAD_CONTEXT
-{
- BOOLEAN Local;
- KAPC Apc;
- KEVENT CompletedEvent;
- ULONG FramesToSkip;
- ULONG FramesToCapture;
- PVOID *BackTrace;
- ULONG CapturedFrames;
- ULONG BackTraceHash;
-} CAPTURE_BACKTRACE_THREAD_CONTEXT, *PCAPTURE_BACKTRACE_THREAD_CONTEXT;
-
-KKERNEL_ROUTINE KphpCaptureStackBackTraceThreadSpecialApc;
-
-VOID KphpCaptureStackBackTraceThreadSpecialApc(
- __in PRKAPC Apc,
- __inout PKNORMAL_ROUTINE *NormalRoutine,
- __inout PVOID *NormalContext,
- __inout PVOID *SystemArgument1,
- __inout PVOID *SystemArgument2
- );
-
-#ifdef ALLOC_PRAGMA
-#pragma alloc_text(PAGE, KpiOpenThread)
-#pragma alloc_text(PAGE, KpiOpenThreadProcess)
-#pragma alloc_text(PAGE, KphCaptureStackBackTraceThread)
-#pragma alloc_text(PAGE, KphpCaptureStackBackTraceThreadSpecialApc)
-#pragma alloc_text(PAGE, KpiCaptureStackBackTraceThread)
-#pragma alloc_text(PAGE, KpiQueryInformationThread)
-#pragma alloc_text(PAGE, KpiSetInformationThread)
-#endif
-
-/**
- * Opens a thread.
- *
- * \param ThreadHandle A variable which receives the thread handle.
- * \param DesiredAccess The desired access to the thread.
- * \param ClientId The identifier of a thread. \a UniqueThread must be present. If \a UniqueProcess
- * is present, the process of the referenced thread will be checked against this identifier.
- * \param Key An access key.
- * \li If a L2 key is provided, no access checks are performed.
- * \li If a L1 key is provided, only read access is permitted but no additional access checks are
- * performed.
- * \li If no valid key is provided, the function fails.
- * \param Client The client that initiated the request.
- * \param AccessMode The mode in which to perform access checks.
- */
-NTSTATUS KpiOpenThread(
- __out PHANDLE ThreadHandle,
- __in ACCESS_MASK DesiredAccess,
- __in PCLIENT_ID ClientId,
- __in_opt KPH_KEY Key,
- __in PKPH_CLIENT Client,
- __in KPROCESSOR_MODE AccessMode
- )
-{
- NTSTATUS status;
- CLIENT_ID clientId;
- PETHREAD thread;
- KPH_KEY_LEVEL requiredKeyLevel;
- HANDLE threadHandle;
-
- PAGED_CODE();
-
- if (AccessMode != KernelMode)
- {
- __try
- {
- ProbeForWrite(ThreadHandle, sizeof(HANDLE), sizeof(HANDLE));
- ProbeForRead(ClientId, sizeof(CLIENT_ID), sizeof(ULONG));
- clientId = *ClientId;
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- return GetExceptionCode();
- }
- }
- else
- {
- clientId = *ClientId;
- }
-
- // Use the process ID if it was specified.
- if (clientId.UniqueProcess)
- {
- status = PsLookupProcessThreadByCid(&clientId, NULL, &thread);
- }
- else
- {
- status = PsLookupThreadByThreadId(clientId.UniqueThread, &thread);
- }
-
- if (!NT_SUCCESS(status))
- return status;
-
-
- requiredKeyLevel = KphKeyLevel1;
-
- if ((DesiredAccess & KPH_THREAD_READ_ACCESS) != DesiredAccess)
- requiredKeyLevel = KphKeyLevel2;
-
- if (NT_SUCCESS(status = KphValidateKey(requiredKeyLevel, Key, Client, AccessMode)))
- {
- // Always open in KernelMode to skip access checks.
- status = ObOpenObjectByPointer(
- thread,
- 0,
- NULL,
- DesiredAccess,
- *PsThreadType,
- KernelMode,
- &threadHandle
- );
- }
-
- ObDereferenceObject(thread);
-
- if (NT_SUCCESS(status))
- {
- if (AccessMode != KernelMode)
- {
- __try
- {
- *ThreadHandle = threadHandle;
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- status = GetExceptionCode();
- }
- }
- else
- {
- *ThreadHandle = threadHandle;
- }
- }
-
- return status;
-}
-
-/**
- * Opens the process of a thread.
- *
- * \param ThreadHandle A handle to a thread.
- * \param DesiredAccess The desired access to the process.
- * \param ProcessHandle A variable which receives the process handle.
- * \param AccessMode The mode in which to perform access checks.
- */
-NTSTATUS KpiOpenThreadProcess(
- __in HANDLE ThreadHandle,
- __in ACCESS_MASK DesiredAccess,
- __out PHANDLE ProcessHandle,
- __in KPROCESSOR_MODE AccessMode
- )
-{
- NTSTATUS status;
- PETHREAD thread;
- PEPROCESS process;
- HANDLE processHandle;
-
- PAGED_CODE();
-
- if (AccessMode != KernelMode)
- {
- __try
- {
- ProbeForWrite(ProcessHandle, sizeof(HANDLE), sizeof(HANDLE));
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- return GetExceptionCode();
- }
- }
-
- status = ObReferenceObjectByHandle(
- ThreadHandle,
- 0,
- *PsThreadType,
- AccessMode,
- &thread,
- NULL
- );
-
- if (!NT_SUCCESS(status))
- return status;
-
- process = IoThreadToProcess(thread);
-
- status = ObOpenObjectByPointer(
- process,
- 0,
- NULL,
- DesiredAccess,
- *PsProcessType,
- AccessMode,
- &processHandle
- );
-
- ObDereferenceObject(thread);
-
- if (NT_SUCCESS(status))
- {
- if (AccessMode != KernelMode)
- {
- __try
- {
- *ProcessHandle = processHandle;
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- status = GetExceptionCode();
- }
- }
- else
- {
- *ProcessHandle = processHandle;
- }
- }
-
- return status;
-}
-
-/**
- * Captures a stack trace of the current thread.
- *
- * \param FramesToSkip The number of frames to skip from the bottom of the stack.
- * \param FramesToCapture The number of frames to capture.
- * \param Flags A combination of the following:
- * \li \c RTL_WALK_USER_MODE_STACK The user-mode stack will be retrieved instead of the kernel-mode
- * stack.
- * \param BackTrace An array in which the stack trace will be stored.
- * \param BackTraceHash A variable which receives a hash of the stack trace.
- *
- * \return The number of frames captured.
- */
-ULONG KphCaptureStackBackTrace(
- __in ULONG FramesToSkip,
- __in ULONG FramesToCapture,
- __in_opt ULONG Flags,
- __out_ecount(FramesToCapture) PVOID *BackTrace,
- __out_opt PULONG BackTraceHash
- )
-{
- PVOID backTrace[MAX_STACK_DEPTH];
- ULONG framesFound;
- ULONG hash;
- ULONG i;
-
- // Skip the current frame (for this function).
- FramesToSkip++;
-
- // Ensure that we won't overrun the buffer.
- if (FramesToCapture + FramesToSkip > MAX_STACK_DEPTH)
- return 0;
- // Validate the flags.
- if ((Flags & RTL_WALK_VALID_FLAGS) != Flags)
- return 0;
-
- // Walk the stack.
- framesFound = RtlWalkFrameChain(
- backTrace,
- FramesToCapture + FramesToSkip,
- Flags
- );
- // Return nothing if we found fewer frames than we wanted to skip.
- if (framesFound <= FramesToSkip)
- return 0;
-
- // Copy over the stack trace. At the same time we calculate the stack trace hash by summing the
- // addresses.
- for (i = 0, hash = 0; i < FramesToCapture; i++)
- {
- if (FramesToSkip + i >= framesFound)
- break;
-
- BackTrace[i] = backTrace[FramesToSkip + i];
- hash += PtrToUlong(BackTrace[i]);
- }
-
- if (BackTraceHash)
- *BackTraceHash = hash;
-
- return i;
-}
-
-/**
- * Captures the stack trace of a thread.
- *
- * \param Thread The thread to capture the stack trace of.
- * \param FramesToSkip The number of frames to skip from the bottom of the stack.
- * \param FramesToCapture The number of frames to capture.
- * \param BackTrace An array in which the stack trace will be stored.
- * \param CapturedFrames A variable which receives the number of frames captured.
- * \param BackTraceHash A variable which receives a hash of the stack trace.
- * \param AccessMode The mode in which to perform access checks.
- *
- * \return The number of frames captured.
- */
-NTSTATUS KphCaptureStackBackTraceThread(
- __in PETHREAD Thread,
- __in ULONG FramesToSkip,
- __in ULONG FramesToCapture,
- __out_ecount(FramesToCapture) PVOID *BackTrace,
- __out_opt PULONG CapturedFrames,
- __out_opt PULONG BackTraceHash,
- __in KPROCESSOR_MODE AccessMode
- )
-{
- NTSTATUS status = STATUS_SUCCESS;
- CAPTURE_BACKTRACE_THREAD_CONTEXT context;
- ULONG backTraceSize;
- PVOID *backTrace;
-
- PAGED_CODE();
-
- // Make sure the caller didn't request too many frames. This also restricts the amount of memory
- // we will try to allocate later.
- if (FramesToCapture > MAX_STACK_DEPTH)
- return STATUS_INVALID_PARAMETER_3;
-
- backTraceSize = FramesToCapture * sizeof(PVOID);
-
- if (AccessMode != KernelMode)
- {
- __try
- {
- ProbeForWrite(BackTrace, backTraceSize, sizeof(PVOID));
-
- if (CapturedFrames)
- ProbeForWrite(CapturedFrames, sizeof(ULONG), sizeof(ULONG));
- if (BackTraceHash)
- ProbeForWrite(BackTraceHash, sizeof(ULONG), sizeof(ULONG));
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- return GetExceptionCode();
- }
- }
-
- // If the caller doesn't want to capture anything, return immediately.
- if (backTraceSize == 0)
- {
- if (AccessMode != KernelMode)
- {
- __try
- {
- if (CapturedFrames)
- *CapturedFrames = 0;
- if (BackTraceHash)
- *BackTraceHash = 0;
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- status = GetExceptionCode();
- }
- }
- else
- {
- if (CapturedFrames)
- *CapturedFrames = 0;
- if (BackTraceHash)
- *BackTraceHash = 0;
- }
-
- return status;
- }
-
- // Allocate storage for the stack trace.
- backTrace = ExAllocatePoolWithTag(NonPagedPool, backTraceSize, 'bhpK');
-
- if (!backTrace)
- return STATUS_INSUFFICIENT_RESOURCES;
-
- // Initialize the context structure.
- context.FramesToSkip = FramesToSkip;
- context.FramesToCapture = FramesToCapture;
- context.BackTrace = backTrace;
-
- // Check if we're trying to get a stack trace of the current thread.
- // If so, we don't need to insert an APC.
- if (Thread == PsGetCurrentThread())
- {
- PCAPTURE_BACKTRACE_THREAD_CONTEXT contextPtr = &context;
- PVOID dummy = NULL;
- KIRQL oldIrql;
-
- // Raise the IRQL to APC_LEVEL to simulate an APC environment,
- // and call the APC routine directly.
-
- context.Local = TRUE;
- KeRaiseIrql(APC_LEVEL, &oldIrql);
- KphpCaptureStackBackTraceThreadSpecialApc(
- &context.Apc,
- NULL,
- NULL,
- &contextPtr,
- &dummy
- );
- KeLowerIrql(oldIrql);
- }
- else
- {
- context.Local = FALSE;
- KeInitializeEvent(&context.CompletedEvent, NotificationEvent, FALSE);
- KeInitializeApc(
- &context.Apc,
- (PKTHREAD)Thread,
- OriginalApcEnvironment,
- KphpCaptureStackBackTraceThreadSpecialApc,
- NULL,
- NULL,
- KernelMode,
- NULL
- );
-
- if (KeInsertQueueApc(&context.Apc, &context, NULL, 2))
- {
- // Wait for the APC to complete.
- status = KeWaitForSingleObject(
- &context.CompletedEvent,
- Executive,
- KernelMode,
- FALSE,
- NULL
- );
- }
- else
- {
- status = STATUS_UNSUCCESSFUL;
- }
- }
-
- if (NT_SUCCESS(status))
- {
- ASSERT(context.CapturedFrames <= FramesToCapture);
-
- if (AccessMode != KernelMode)
- {
- __try
- {
- memcpy(BackTrace, backTrace, context.CapturedFrames * sizeof(PVOID));
-
- if (CapturedFrames)
- *CapturedFrames = context.CapturedFrames;
- if (BackTraceHash)
- *BackTraceHash = context.BackTraceHash;
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- status = GetExceptionCode();
- }
- }
- else
- {
- memcpy(BackTrace, backTrace, context.CapturedFrames * sizeof(PVOID));
-
- if (CapturedFrames)
- *CapturedFrames = context.CapturedFrames;
- if (BackTraceHash)
- *BackTraceHash = context.BackTraceHash;
- }
- }
-
- ExFreePoolWithTag(backTrace, 'bhpK');
-
- return status;
-}
-
-VOID KphpCaptureStackBackTraceThreadSpecialApc(
- __in PRKAPC Apc,
- __inout PKNORMAL_ROUTINE *NormalRoutine,
- __inout PVOID *NormalContext,
- __inout PVOID *SystemArgument1,
- __inout PVOID *SystemArgument2
- )
-{
- PCAPTURE_BACKTRACE_THREAD_CONTEXT context = *SystemArgument1;
-
- PAGED_CODE();
-
- context->CapturedFrames = KphCaptureStackBackTrace(
- context->FramesToSkip,
- context->FramesToCapture,
- 0,
- context->BackTrace,
- &context->BackTraceHash
- );
-
- if (!context->Local)
- {
- // Notify the originating thread that we have completed.
- KeSetEvent(&context->CompletedEvent, 0, FALSE);
- }
-}
-
-/**
- * Captures the stack trace of a thread.
- *
- * \param ThreadHandle A handle to the thread to capture the stack trace of.
- * \param FramesToSkip The number of frames to skip from the bottom of the stack.
- * \param FramesToCapture The number of frames to capture.
- * \param BackTrace An array in which the stack trace will be stored.
- * \param CapturedFrames A variable which receives the number of frames captured.
- * \param BackTraceHash A variable which receives a hash of the stack trace.
- * \param AccessMode The mode in which to perform access checks.
- *
- * \return The number of frames captured.
- */
-NTSTATUS KpiCaptureStackBackTraceThread(
- __in HANDLE ThreadHandle,
- __in ULONG FramesToSkip,
- __in ULONG FramesToCapture,
- __out_ecount(FramesToCapture) PVOID *BackTrace,
- __out_opt PULONG CapturedFrames,
- __out_opt PULONG BackTraceHash,
- __in KPROCESSOR_MODE AccessMode
- )
-{
- NTSTATUS status = STATUS_SUCCESS;
- PETHREAD thread;
-
- PAGED_CODE();
-
- status = ObReferenceObjectByHandle(
- ThreadHandle,
- 0,
- *PsThreadType,
- AccessMode,
- &thread,
- NULL
- );
-
- if (!NT_SUCCESS(status))
- return status;
-
- status = KphCaptureStackBackTraceThread(
- thread,
- FramesToSkip,
- FramesToCapture,
- BackTrace,
- CapturedFrames,
- BackTraceHash,
- AccessMode
- );
- ObDereferenceObject(thread);
-
- return status;
-}
-
-/**
- * Queries thread information.
- *
- * \param ThreadHandle A handle to a thread.
- * \param ThreadInformationClass The type of information to query.
- * \param ThreadInformation The buffer in which the information will be stored.
- * \param ThreadInformationLength The number of bytes available in \a ThreadInformation.
- * \param ReturnLength A variable which receives the number of bytes required to be available in
- * \a ThreadInformation.
- * \param AccessMode The mode in which to perform access checks.
- */
-NTSTATUS KpiQueryInformationThread(
- __in HANDLE ThreadHandle,
- __in KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,
- __out_bcount(ProcessInformationLength) PVOID ThreadInformation,
- __in ULONG ThreadInformationLength,
- __out_opt PULONG ReturnLength,
- __in KPROCESSOR_MODE AccessMode
- )
-{
- NTSTATUS status;
- PETHREAD thread;
- ULONG returnLength;
-
- PAGED_CODE();
-
- if (AccessMode != KernelMode)
- {
- __try
- {
- ProbeForWrite(ThreadInformation, ThreadInformationLength, sizeof(ULONG));
-
- if (ReturnLength)
- ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG));
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- return GetExceptionCode();
- }
- }
-
- status = ObReferenceObjectByHandle(
- ThreadHandle,
- THREAD_QUERY_INFORMATION,
- *PsThreadType,
- AccessMode,
- &thread,
- NULL
- );
-
- if (!NT_SUCCESS(status))
- return status;
-
- switch (ThreadInformationClass)
- {
- default:
- status = STATUS_INVALID_INFO_CLASS;
- returnLength = 0;
- break;
- }
-
- ObDereferenceObject(thread);
-
- if (ReturnLength)
- {
- if (AccessMode != KernelMode)
- {
- __try
- {
- *ReturnLength = returnLength;
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- NOTHING;
- }
- }
- else
- {
- *ReturnLength = returnLength;
- }
- }
-
- return status;
-}
-
-/**
- * Sets thread information.
- *
- * \param ThreadHandle A handle to a thread.
- * \param ThreadInformationClass The type of information to set.
- * \param ThreadInformation A buffer which contains the information to set.
- * \param ThreadInformationLength The number of bytes present in \a ThreadInformation.
- * \param AccessMode The mode in which to perform access checks.
- */
-NTSTATUS KpiSetInformationThread(
- __in HANDLE ThreadHandle,
- __in KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,
- __in_bcount(ThreadInformationLength) PVOID ThreadInformation,
- __in ULONG ThreadInformationLength,
- __in KPROCESSOR_MODE AccessMode
- )
-{
- NTSTATUS status;
- PETHREAD thread;
-
- PAGED_CODE();
-
- if (AccessMode != KernelMode)
- {
- __try
- {
- ProbeForRead(ThreadInformation, ThreadInformationLength, sizeof(ULONG));
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- return GetExceptionCode();
- }
- }
-
- status = ObReferenceObjectByHandle(
- ThreadHandle,
- THREAD_SET_INFORMATION,
- *PsThreadType,
- AccessMode,
- &thread,
- NULL
- );
-
- if (!NT_SUCCESS(status))
- return status;
-
- switch (ThreadInformationClass)
- {
- default:
- status = STATUS_INVALID_INFO_CLASS;
- break;
- }
-
- ObDereferenceObject(thread);
-
- return status;
-}
+/*
+ * KProcessHacker
+ *
+ * Copyright (C) 2010-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 .
+ */
+
+#include
+#include
+
+typedef struct _CAPTURE_BACKTRACE_THREAD_CONTEXT
+{
+ BOOLEAN Local;
+ KAPC Apc;
+ KEVENT CompletedEvent;
+ ULONG FramesToSkip;
+ ULONG FramesToCapture;
+ PVOID *BackTrace;
+ ULONG CapturedFrames;
+ ULONG BackTraceHash;
+} CAPTURE_BACKTRACE_THREAD_CONTEXT, *PCAPTURE_BACKTRACE_THREAD_CONTEXT;
+
+KKERNEL_ROUTINE KphpCaptureStackBackTraceThreadSpecialApc;
+
+VOID KphpCaptureStackBackTraceThreadSpecialApc(
+ _In_ PRKAPC Apc,
+ _Inout_opt_ PKNORMAL_ROUTINE *NormalRoutine,
+ _Inout_opt_ PVOID *NormalContext,
+ _Inout_ PVOID *SystemArgument1,
+ _Inout_ PVOID *SystemArgument2
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, KpiOpenThread)
+#pragma alloc_text(PAGE, KpiOpenThreadProcess)
+#pragma alloc_text(PAGE, KphCaptureStackBackTraceThread)
+#pragma alloc_text(PAGE, KphpCaptureStackBackTraceThreadSpecialApc)
+#pragma alloc_text(PAGE, KpiCaptureStackBackTraceThread)
+#pragma alloc_text(PAGE, KpiQueryInformationThread)
+#pragma alloc_text(PAGE, KpiSetInformationThread)
+#endif
+
+/**
+ * Opens a thread.
+ *
+ * \param ThreadHandle A variable which receives the thread handle.
+ * \param DesiredAccess The desired access to the thread.
+ * \param ClientId The identifier of a thread. \a UniqueThread must be present. If \a UniqueProcess
+ * is present, the process of the referenced thread will be checked against this identifier.
+ * \param Key An access key.
+ * \li If a L2 key is provided, no access checks are performed.
+ * \li If a L1 key is provided, only read access is permitted but no additional access checks are
+ * performed.
+ * \li If no valid key is provided, the function fails.
+ * \param Client The client that initiated the request.
+ * \param AccessMode The mode in which to perform access checks.
+ */
+NTSTATUS KpiOpenThread(
+ _Out_ PHANDLE ThreadHandle,
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_ PCLIENT_ID ClientId,
+ _In_opt_ KPH_KEY Key,
+ _In_ PKPH_CLIENT Client,
+ _In_ KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status;
+ CLIENT_ID clientId;
+ PETHREAD thread;
+ KPH_KEY_LEVEL requiredKeyLevel;
+ HANDLE threadHandle = NULL;
+
+ PAGED_CODE();
+
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ ProbeForWrite(ThreadHandle, sizeof(HANDLE), sizeof(HANDLE));
+ ProbeForRead(ClientId, sizeof(CLIENT_ID), sizeof(ULONG));
+ clientId = *ClientId;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+ }
+ else
+ {
+ clientId = *ClientId;
+ }
+
+ // Use the process ID if it was specified.
+ if (clientId.UniqueProcess)
+ {
+ status = PsLookupProcessThreadByCid(&clientId, NULL, &thread);
+ }
+ else
+ {
+ status = PsLookupThreadByThreadId(clientId.UniqueThread, &thread);
+ }
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+
+ requiredKeyLevel = KphKeyLevel1;
+
+ if ((DesiredAccess & KPH_THREAD_READ_ACCESS) != DesiredAccess)
+ requiredKeyLevel = KphKeyLevel2;
+
+ if (NT_SUCCESS(status = KphValidateKey(requiredKeyLevel, Key, Client, AccessMode)))
+ {
+ // Always open in KernelMode to skip access checks.
+ status = ObOpenObjectByPointer(
+ thread,
+ 0,
+ NULL,
+ DesiredAccess,
+ *PsThreadType,
+ KernelMode,
+ &threadHandle
+ );
+ }
+
+ ObDereferenceObject(thread);
+
+ if (NT_SUCCESS(status))
+ {
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ *ThreadHandle = threadHandle;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+ else
+ {
+ *ThreadHandle = threadHandle;
+ }
+ }
+
+ return status;
+}
+
+/**
+ * Opens the process of a thread.
+ *
+ * \param ThreadHandle A handle to a thread.
+ * \param DesiredAccess The desired access to the process.
+ * \param ProcessHandle A variable which receives the process handle.
+ * \param AccessMode The mode in which to perform access checks.
+ */
+NTSTATUS KpiOpenThreadProcess(
+ _In_ HANDLE ThreadHandle,
+ _In_ ACCESS_MASK DesiredAccess,
+ _Out_ PHANDLE ProcessHandle,
+ _In_ KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status;
+ PETHREAD thread;
+ PEPROCESS process;
+ HANDLE processHandle;
+
+ PAGED_CODE();
+
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ ProbeForWrite(ProcessHandle, sizeof(HANDLE), sizeof(HANDLE));
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+ }
+
+ status = ObReferenceObjectByHandle(
+ ThreadHandle,
+ 0,
+ *PsThreadType,
+ AccessMode,
+ &thread,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ process = IoThreadToProcess(thread);
+
+ status = ObOpenObjectByPointer(
+ process,
+ 0,
+ NULL,
+ DesiredAccess,
+ *PsProcessType,
+ AccessMode,
+ &processHandle
+ );
+
+ ObDereferenceObject(thread);
+
+ if (NT_SUCCESS(status))
+ {
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ *ProcessHandle = processHandle;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+ else
+ {
+ *ProcessHandle = processHandle;
+ }
+ }
+
+ return status;
+}
+
+/**
+ * Captures a stack trace of the current thread.
+ *
+ * \param FramesToSkip The number of frames to skip from the bottom of the stack.
+ * \param FramesToCapture The number of frames to capture.
+ * \param Flags A combination of the following:
+ * \li \c RTL_WALK_USER_MODE_STACK The user-mode stack will be retrieved instead of the kernel-mode
+ * stack.
+ * \param BackTrace An array in which the stack trace will be stored.
+ * \param BackTraceHash A variable which receives a hash of the stack trace.
+ *
+ * \return The number of frames captured.
+ */
+ULONG KphCaptureStackBackTrace(
+ _In_ ULONG FramesToSkip,
+ _In_ ULONG FramesToCapture,
+ _In_opt_ ULONG Flags,
+ _Out_writes_(FramesToCapture) PVOID *BackTrace,
+ _Out_opt_ PULONG BackTraceHash
+ )
+{
+ PVOID backTrace[MAX_STACK_DEPTH];
+ ULONG framesFound;
+ ULONG hash;
+ ULONG i;
+
+ // Skip the current frame (for this function).
+ FramesToSkip++;
+
+ // Ensure that we won't overrun the buffer.
+ if (FramesToCapture + FramesToSkip > MAX_STACK_DEPTH)
+ return 0;
+ // Validate the flags.
+ if ((Flags & RTL_WALK_VALID_FLAGS) != Flags)
+ return 0;
+
+ // Walk the stack.
+ framesFound = RtlWalkFrameChain(
+ backTrace,
+ FramesToCapture + FramesToSkip,
+ Flags
+ );
+ // Return nothing if we found fewer frames than we wanted to skip.
+ if (framesFound <= FramesToSkip)
+ return 0;
+
+ // Copy over the stack trace. At the same time we calculate the stack trace hash by summing the
+ // addresses.
+ for (i = 0, hash = 0; i < FramesToCapture; i++)
+ {
+ if (FramesToSkip + i >= framesFound)
+ break;
+
+ BackTrace[i] = backTrace[FramesToSkip + i];
+ hash += PtrToUlong(BackTrace[i]);
+ }
+
+ if (BackTraceHash)
+ *BackTraceHash = hash;
+
+ return i;
+}
+
+/**
+ * Captures the stack trace of a thread.
+ *
+ * \param Thread The thread to capture the stack trace of.
+ * \param FramesToSkip The number of frames to skip from the bottom of the stack.
+ * \param FramesToCapture The number of frames to capture.
+ * \param BackTrace An array in which the stack trace will be stored.
+ * \param CapturedFrames A variable which receives the number of frames captured.
+ * \param BackTraceHash A variable which receives a hash of the stack trace.
+ * \param AccessMode The mode in which to perform access checks.
+ *
+ * \return The number of frames captured.
+ */
+NTSTATUS KphCaptureStackBackTraceThread(
+ _In_ PETHREAD Thread,
+ _In_ ULONG FramesToSkip,
+ _In_ ULONG FramesToCapture,
+ _Out_writes_(FramesToCapture) PVOID *BackTrace,
+ _Out_opt_ PULONG CapturedFrames,
+ _Out_opt_ PULONG BackTraceHash,
+ _In_ KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ CAPTURE_BACKTRACE_THREAD_CONTEXT context;
+ ULONG backTraceSize;
+ PVOID *backTrace;
+
+ PAGED_CODE();
+
+ // Make sure the caller didn't request too many frames. This also restricts the amount of memory
+ // we will try to allocate later.
+ if (FramesToCapture > MAX_STACK_DEPTH)
+ return STATUS_INVALID_PARAMETER_3;
+
+ backTraceSize = FramesToCapture * sizeof(PVOID);
+
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ ProbeForWrite(BackTrace, backTraceSize, sizeof(PVOID));
+
+ if (CapturedFrames)
+ ProbeForWrite(CapturedFrames, sizeof(ULONG), sizeof(ULONG));
+ if (BackTraceHash)
+ ProbeForWrite(BackTraceHash, sizeof(ULONG), sizeof(ULONG));
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+ }
+
+ // If the caller doesn't want to capture anything, return immediately.
+ if (backTraceSize == 0)
+ {
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ if (CapturedFrames)
+ *CapturedFrames = 0;
+ if (BackTraceHash)
+ *BackTraceHash = 0;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+ else
+ {
+ if (CapturedFrames)
+ *CapturedFrames = 0;
+ if (BackTraceHash)
+ *BackTraceHash = 0;
+ }
+
+ return status;
+ }
+
+ // Allocate storage for the stack trace.
+ backTrace = ExAllocatePoolWithTag(NonPagedPool, backTraceSize, 'bhpK');
+
+ if (!backTrace)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ // Initialize the context structure.
+ context.FramesToSkip = FramesToSkip;
+ context.FramesToCapture = FramesToCapture;
+ context.BackTrace = backTrace;
+
+ // Check if we're trying to get a stack trace of the current thread.
+ // If so, we don't need to insert an APC.
+ if (Thread == PsGetCurrentThread())
+ {
+ PCAPTURE_BACKTRACE_THREAD_CONTEXT contextPtr = &context;
+ PVOID dummy = NULL;
+ KIRQL oldIrql;
+
+ // Raise the IRQL to APC_LEVEL to simulate an APC environment,
+ // and call the APC routine directly.
+
+ context.Local = TRUE;
+ KeRaiseIrql(APC_LEVEL, &oldIrql);
+ KphpCaptureStackBackTraceThreadSpecialApc(
+ &context.Apc,
+ NULL,
+ NULL,
+ &contextPtr,
+ &dummy
+ );
+ KeLowerIrql(oldIrql);
+ }
+ else
+ {
+ context.Local = FALSE;
+ KeInitializeEvent(&context.CompletedEvent, NotificationEvent, FALSE);
+ KeInitializeApc(
+ &context.Apc,
+ (PKTHREAD)Thread,
+ OriginalApcEnvironment,
+ KphpCaptureStackBackTraceThreadSpecialApc,
+ NULL,
+ NULL,
+ KernelMode,
+ NULL
+ );
+
+ if (KeInsertQueueApc(&context.Apc, &context, NULL, 2))
+ {
+ // Wait for the APC to complete.
+ status = KeWaitForSingleObject(
+ &context.CompletedEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+ }
+ else
+ {
+ status = STATUS_UNSUCCESSFUL;
+ }
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ ASSERT(context.CapturedFrames <= FramesToCapture);
+
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ memcpy(BackTrace, backTrace, context.CapturedFrames * sizeof(PVOID));
+
+ if (CapturedFrames)
+ *CapturedFrames = context.CapturedFrames;
+ if (BackTraceHash)
+ *BackTraceHash = context.BackTraceHash;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ status = GetExceptionCode();
+ }
+ }
+ else
+ {
+ memcpy(BackTrace, backTrace, context.CapturedFrames * sizeof(PVOID));
+
+ if (CapturedFrames)
+ *CapturedFrames = context.CapturedFrames;
+ if (BackTraceHash)
+ *BackTraceHash = context.BackTraceHash;
+ }
+ }
+
+ ExFreePoolWithTag(backTrace, 'bhpK');
+
+ return status;
+}
+
+VOID KphpCaptureStackBackTraceThreadSpecialApc(
+ _In_ PRKAPC Apc,
+ _Inout_opt_ PKNORMAL_ROUTINE *NormalRoutine,
+ _Inout_opt_ PVOID *NormalContext,
+ _Inout_ PVOID *SystemArgument1,
+ _Inout_ PVOID *SystemArgument2
+ )
+{
+ PCAPTURE_BACKTRACE_THREAD_CONTEXT context = *SystemArgument1;
+
+ PAGED_CODE();
+
+ context->CapturedFrames = KphCaptureStackBackTrace(
+ context->FramesToSkip,
+ context->FramesToCapture,
+ 0,
+ context->BackTrace,
+ &context->BackTraceHash
+ );
+
+ if (!context->Local)
+ {
+ // Notify the originating thread that we have completed.
+ KeSetEvent(&context->CompletedEvent, 0, FALSE);
+ }
+}
+
+/**
+ * Captures the stack trace of a thread.
+ *
+ * \param ThreadHandle A handle to the thread to capture the stack trace of.
+ * \param FramesToSkip The number of frames to skip from the bottom of the stack.
+ * \param FramesToCapture The number of frames to capture.
+ * \param BackTrace An array in which the stack trace will be stored.
+ * \param CapturedFrames A variable which receives the number of frames captured.
+ * \param BackTraceHash A variable which receives a hash of the stack trace.
+ * \param AccessMode The mode in which to perform access checks.
+ *
+ * \return The number of frames captured.
+ */
+NTSTATUS KpiCaptureStackBackTraceThread(
+ _In_ HANDLE ThreadHandle,
+ _In_ ULONG FramesToSkip,
+ _In_ ULONG FramesToCapture,
+ _Out_writes_(FramesToCapture) PVOID *BackTrace,
+ _Out_opt_ PULONG CapturedFrames,
+ _Out_opt_ PULONG BackTraceHash,
+ _In_ KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PETHREAD thread;
+
+ PAGED_CODE();
+
+ status = ObReferenceObjectByHandle(
+ ThreadHandle,
+ 0,
+ *PsThreadType,
+ AccessMode,
+ &thread,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ status = KphCaptureStackBackTraceThread(
+ thread,
+ FramesToSkip,
+ FramesToCapture,
+ BackTrace,
+ CapturedFrames,
+ BackTraceHash,
+ AccessMode
+ );
+ ObDereferenceObject(thread);
+
+ return status;
+}
+
+/**
+ * Queries thread information.
+ *
+ * \param ThreadHandle A handle to a thread.
+ * \param ThreadInformationClass The type of information to query.
+ * \param ThreadInformation The buffer in which the information will be stored.
+ * \param ThreadInformationLength The number of bytes available in \a ThreadInformation.
+ * \param ReturnLength A variable which receives the number of bytes required to be available in
+ * \a ThreadInformation.
+ * \param AccessMode The mode in which to perform access checks.
+ */
+NTSTATUS KpiQueryInformationThread(
+ _In_ HANDLE ThreadHandle,
+ _In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,
+ _Out_writes_bytes_(ThreadInformationLength) PVOID ThreadInformation,
+ _In_ ULONG ThreadInformationLength,
+ _Out_opt_ PULONG ReturnLength,
+ _In_ KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status;
+ PETHREAD thread;
+ ULONG returnLength;
+
+ PAGED_CODE();
+
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ ProbeForWrite(ThreadInformation, ThreadInformationLength, sizeof(ULONG));
+
+ if (ReturnLength)
+ ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG));
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+ }
+
+ status = ObReferenceObjectByHandle(
+ ThreadHandle,
+ THREAD_QUERY_INFORMATION,
+ *PsThreadType,
+ AccessMode,
+ &thread,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ switch (ThreadInformationClass)
+ {
+ default:
+ status = STATUS_INVALID_INFO_CLASS;
+ returnLength = 0;
+ break;
+ }
+
+ ObDereferenceObject(thread);
+
+ if (ReturnLength)
+ {
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ *ReturnLength = returnLength;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ NOTHING;
+ }
+ }
+ else
+ {
+ *ReturnLength = returnLength;
+ }
+ }
+
+ return status;
+}
+
+/**
+ * Sets thread information.
+ *
+ * \param ThreadHandle A handle to a thread.
+ * \param ThreadInformationClass The type of information to set.
+ * \param ThreadInformation A buffer which contains the information to set.
+ * \param ThreadInformationLength The number of bytes present in \a ThreadInformation.
+ * \param AccessMode The mode in which to perform access checks.
+ */
+NTSTATUS KpiSetInformationThread(
+ _In_ HANDLE ThreadHandle,
+ _In_ KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,
+ _In_reads_bytes_(ThreadInformationLength) PVOID ThreadInformation,
+ _In_ ULONG ThreadInformationLength,
+ _In_ KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status;
+ PETHREAD thread;
+
+ PAGED_CODE();
+
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ ProbeForRead(ThreadInformation, ThreadInformationLength, sizeof(ULONG));
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+ }
+
+ status = ObReferenceObjectByHandle(
+ ThreadHandle,
+ THREAD_SET_INFORMATION,
+ *PsThreadType,
+ AccessMode,
+ &thread,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ switch (ThreadInformationClass)
+ {
+ default:
+ status = STATUS_INVALID_INFO_CLASS;
+ break;
+ }
+
+ ObDereferenceObject(thread);
+
+ return status;
+}
diff --git a/KProcessHacker/util.c b/KProcessHacker/util.c
index b30ae7e6bcd6..d372284bda48 100644
--- a/KProcessHacker/util.c
+++ b/KProcessHacker/util.c
@@ -30,7 +30,7 @@
#endif
VOID KphFreeCapturedUnicodeString(
- __in PUNICODE_STRING CapturedUnicodeString
+ _In_ PUNICODE_STRING CapturedUnicodeString
)
{
PAGED_CODE();
@@ -40,8 +40,8 @@ VOID KphFreeCapturedUnicodeString(
}
NTSTATUS KphCaptureUnicodeString(
- __in PUNICODE_STRING UnicodeString,
- __out PUNICODE_STRING CapturedUnicodeString
+ _In_ PUNICODE_STRING UnicodeString,
+ _Out_ PUNICODE_STRING CapturedUnicodeString
)
{
UNICODE_STRING unicodeString;
@@ -107,7 +107,7 @@ NTSTATUS KphCaptureUnicodeString(
* the kernel modules. The structure must be freed with the tag 'ThpK'.
*/
NTSTATUS KphEnumerateSystemModules(
- __out PRTL_PROCESS_MODULES *Modules
+ _Out_ PRTL_PROCESS_MODULES *Modules
)
{
NTSTATUS status;
@@ -162,8 +162,8 @@ NTSTATUS KphEnumerateSystemModules(
* \param Length The number of bytes in the address range.
*/
NTSTATUS KphValidateAddressForSystemModules(
- __in PVOID Address,
- __in SIZE_T Length
+ _In_ PVOID Address,
+ _In_ SIZE_T Length
)
{
NTSTATUS status;
@@ -214,9 +214,9 @@ NTSTATUS KphValidateAddressForSystemModules(
* section. The structure must be freed with the tag 'ThpK'.
*/
NTSTATUS KphGetProcessMappedFileName(
- __in HANDLE ProcessHandle,
- __in PVOID BaseAddress,
- __out PUNICODE_STRING *FileName
+ _In_ HANDLE ProcessHandle,
+ _In_ PVOID BaseAddress,
+ _Out_ PUNICODE_STRING *FileName
)
{
NTSTATUS status;
diff --git a/KProcessHacker/verify.c b/KProcessHacker/verify.c
index 08ccbf15d82f..8756f17f2afb 100644
--- a/KProcessHacker/verify.c
+++ b/KProcessHacker/verify.c
@@ -25,7 +25,7 @@
#define FILE_MAX_SIZE (32 * 1024 * 1024) // 32 MB
VOID KphpBackoffKey(
- __in PKPH_CLIENT Client
+ _In_ PKPH_CLIENT Client
);
static UCHAR KphpTrustedPublicKey[] =
@@ -49,9 +49,9 @@ static UCHAR KphpTrustedPublicKey[] =
#endif
NTSTATUS KphHashFile(
- __in PUNICODE_STRING FileName,
- __out PVOID *Hash,
- __out PULONG HashSize
+ _In_ PUNICODE_STRING FileName,
+ _Out_ PVOID *Hash,
+ _Out_ PULONG HashSize
)
{
NTSTATUS status;
@@ -192,9 +192,9 @@ NTSTATUS KphHashFile(
}
NTSTATUS KphVerifyFile(
- __in PUNICODE_STRING FileName,
- __in_bcount(SignatureSize) PUCHAR Signature,
- __in ULONG SignatureSize
+ _In_ PUNICODE_STRING FileName,
+ _In_reads_bytes_(SignatureSize) PUCHAR Signature,
+ _In_ ULONG SignatureSize
)
{
NTSTATUS status;
@@ -240,10 +240,10 @@ NTSTATUS KphVerifyFile(
}
VOID KphVerifyClient(
- __inout PKPH_CLIENT Client,
- __in PVOID CodeAddress,
- __in_bcount(SignatureSize) PUCHAR Signature,
- __in ULONG SignatureSize
+ _Inout_ PKPH_CLIENT Client,
+ _In_ PVOID CodeAddress,
+ _In_reads_bytes_(SignatureSize) PUCHAR Signature,
+ _In_ ULONG SignatureSize
)
{
NTSTATUS status;
@@ -311,10 +311,10 @@ VOID KphVerifyClient(
}
NTSTATUS KpiVerifyClient(
- __in PVOID CodeAddress,
- __in_bcount(SignatureSize) PUCHAR Signature,
- __in ULONG SignatureSize,
- __in PKPH_CLIENT Client
+ _In_ PVOID CodeAddress,
+ _In_reads_bytes_(SignatureSize) PUCHAR Signature,
+ _In_ ULONG SignatureSize,
+ _In_ PKPH_CLIENT Client
)
{
PUCHAR signature;
@@ -347,14 +347,14 @@ NTSTATUS KpiVerifyClient(
return GetExceptionCode();
}
- KphVerifyClient(Client, CodeAddress, Signature, SignatureSize);
+ KphVerifyClient(Client, CodeAddress, signature, SignatureSize);
ExFreePoolWithTag(signature, 'ThpK');
return Client->VerificationStatus;
}
VOID KphGenerateKeysClient(
- __inout PKPH_CLIENT Client
+ _Inout_ PKPH_CLIENT Client
)
{
ULONGLONG interruptTime;
@@ -389,9 +389,9 @@ VOID KphGenerateKeysClient(
}
NTSTATUS KphRetrieveKeyViaApc(
- __inout PKPH_CLIENT Client,
- __in KPH_KEY_LEVEL KeyLevel,
- __inout PIRP Irp
+ _Inout_ PKPH_CLIENT Client,
+ _In_ KPH_KEY_LEVEL KeyLevel,
+ _Inout_ PIRP Irp
)
{
PIO_APC_ROUTINE userApcRoutine;
@@ -440,10 +440,10 @@ NTSTATUS KphRetrieveKeyViaApc(
}
NTSTATUS KphValidateKey(
- __in KPH_KEY_LEVEL RequiredKeyLevel,
- __in_opt KPH_KEY Key,
- __in PKPH_CLIENT Client,
- __in KPROCESSOR_MODE AccessMode
+ _In_ KPH_KEY_LEVEL RequiredKeyLevel,
+ _In_opt_ KPH_KEY Key,
+ _In_ PKPH_CLIENT Client,
+ _In_ KPROCESSOR_MODE AccessMode
)
{
PAGED_CODE();
@@ -478,7 +478,7 @@ NTSTATUS KphValidateKey(
}
VOID KphpBackoffKey(
- __in PKPH_CLIENT Client
+ _In_ PKPH_CLIENT Client
)
{
LARGE_INTEGER backoffTime;
diff --git a/KProcessHacker/vm.c b/KProcessHacker/vm.c
index 0ffbb578181d..32f0057a4089 100644
--- a/KProcessHacker/vm.c
+++ b/KProcessHacker/vm.c
@@ -1,449 +1,449 @@
-/*
- * KProcessHacker
- *
- * Copyright (C) 2010-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 .
- */
-
-#include
-
-ULONG KphpGetCopyExceptionInfo(
- __in PEXCEPTION_POINTERS ExceptionInfo,
- __out PBOOLEAN HaveBadAddress,
- __out PULONG_PTR BadAddress
- );
-
-#ifdef ALLOC_PRAGMA
-#pragma alloc_text(PAGE, KphCopyVirtualMemory)
-#pragma alloc_text(PAGE, KpiReadVirtualMemoryUnsafe)
-#endif
-
-#define KPH_STACK_COPY_BYTES 0x200
-#define KPH_POOL_COPY_BYTES 0x10000
-#define KPH_MAPPED_COPY_PAGES 14
-#define KPH_POOL_COPY_THRESHOLD 0x3ff
-
-ULONG KphpGetCopyExceptionInfo(
- __in PEXCEPTION_POINTERS ExceptionInfo,
- __out PBOOLEAN HaveBadAddress,
- __out PULONG_PTR BadAddress
- )
-{
- PEXCEPTION_RECORD exceptionRecord;
-
- *HaveBadAddress = FALSE;
- exceptionRecord = ExceptionInfo->ExceptionRecord;
-
- if ((exceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION) ||
- (exceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION) ||
- (exceptionRecord->ExceptionCode == STATUS_IN_PAGE_ERROR))
- {
- if (exceptionRecord->NumberParameters > 1)
- {
- /* We have the address. */
- *HaveBadAddress = TRUE;
- *BadAddress = exceptionRecord->ExceptionInformation[1];
- }
- }
-
- return EXCEPTION_EXECUTE_HANDLER;
-}
-
-/**
- * Copies memory from one process to another.
- *
- * \param FromProcess The source process.
- * \param FromAddress The source address.
- * \param ToProcess The target process.
- * \param ToAddress The target address.
- * \param BufferLength The number of bytes to copy.
- * \param AccessMode The mode in which to perform access checks.
- * \param ReturnLength A variable which receives the number of bytes copied.
- */
-NTSTATUS KphCopyVirtualMemory(
- __in PEPROCESS FromProcess,
- __in PVOID FromAddress,
- __in PEPROCESS ToProcess,
- __in PVOID ToAddress,
- __in SIZE_T BufferLength,
- __in KPROCESSOR_MODE AccessMode,
- __out PSIZE_T ReturnLength
- )
-{
- UCHAR stackBuffer[KPH_STACK_COPY_BYTES];
- PVOID buffer;
- PFN_NUMBER mdlBuffer[(sizeof(MDL) / sizeof(PFN_NUMBER)) + KPH_MAPPED_COPY_PAGES + 1];
- PMDL mdl = (PMDL)mdlBuffer;
- PVOID mappedAddress;
- SIZE_T mappedTotalSize;
- SIZE_T blockSize;
- SIZE_T stillToCopy;
- KAPC_STATE apcState;
- PVOID sourceAddress;
- PVOID targetAddress;
- BOOLEAN doMappedCopy;
- BOOLEAN pagesLocked;
- BOOLEAN copyingToTarget = FALSE;
- BOOLEAN probing = FALSE;
- BOOLEAN mapping = FALSE;
- BOOLEAN haveBadAddress;
- ULONG_PTR badAddress;
-
- PAGED_CODE();
-
- sourceAddress = FromAddress;
- targetAddress = ToAddress;
-
- // We don't check if buffer == NULL when freeing. If buffer doesn't need to be freed, set to
- // stackBuffer, not NULL.
- buffer = stackBuffer;
-
- mappedTotalSize = (KPH_MAPPED_COPY_PAGES - 2) * PAGE_SIZE;
-
- if (mappedTotalSize > BufferLength)
- mappedTotalSize = BufferLength;
-
- stillToCopy = BufferLength;
- blockSize = mappedTotalSize;
-
- while (stillToCopy)
- {
- // If we're at the last copy block, copy the remaining bytes instead of the whole block
- // size.
- if (blockSize > stillToCopy)
- blockSize = stillToCopy;
-
- // Choose the best method based on the number of bytes left to copy.
- if (blockSize > KPH_POOL_COPY_THRESHOLD)
- {
- doMappedCopy = TRUE;
- }
- else
- {
- doMappedCopy = FALSE;
-
- if (blockSize <= KPH_STACK_COPY_BYTES)
- {
- if (buffer != stackBuffer)
- ExFreePoolWithTag(buffer, 'ChpK');
-
- buffer = stackBuffer;
- }
- else
- {
- // Don't allocate the buffer if we've done so already. Note that the block size
- // never increases, so this allocation will always be OK.
- if (buffer == stackBuffer)
- {
- // Keep trying to allocate a buffer.
-
- while (TRUE)
- {
- buffer = ExAllocatePoolWithTag(NonPagedPool, blockSize, 'ChpK');
-
- // Stop trying if we got a buffer.
- if (buffer)
- break;
-
- blockSize /= 2;
-
- // Use the stack buffer if we can.
- if (blockSize <= KPH_STACK_COPY_BYTES)
- {
- buffer = stackBuffer;
- break;
- }
- }
- }
- }
- }
-
- // Reset state.
- mappedAddress = NULL;
- pagesLocked = FALSE;
- copyingToTarget = FALSE;
-
- KeStackAttachProcess(FromProcess, &apcState);
-
- __try
- {
- // Probe only if this is the first time.
- if (sourceAddress == FromAddress && AccessMode != KernelMode)
- {
- probing = TRUE;
- ProbeForRead(sourceAddress, BufferLength, sizeof(UCHAR));
- probing = FALSE;
- }
-
- if (doMappedCopy)
- {
- // Initialize the MDL.
- MmInitializeMdl(mdl, sourceAddress, blockSize);
- MmProbeAndLockPages(mdl, AccessMode, IoReadAccess);
- pagesLocked = TRUE;
-
- // Map the pages.
- mappedAddress = MmMapLockedPagesSpecifyCache(
- mdl,
- KernelMode,
- MmCached,
- NULL,
- FALSE,
- HighPagePriority
- );
-
- if (!mappedAddress)
- {
- // Insufficient resources; exit.
- mapping = TRUE;
- ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
- }
- }
- else
- {
- memcpy(buffer, sourceAddress, blockSize);
- }
-
- KeUnstackDetachProcess(&apcState);
-
- // Attach to the target process and copy the contents out.
- KeStackAttachProcess(ToProcess, &apcState);
-
- // Probe only if this is the first time.
- if (targetAddress == ToAddress && AccessMode != KernelMode)
- {
- probing = TRUE;
- ProbeForWrite(targetAddress, BufferLength, sizeof(UCHAR));
- probing = FALSE;
- }
-
- // Copy the data.
- copyingToTarget = TRUE;
-
- if (doMappedCopy)
- memcpy(targetAddress, mappedAddress, blockSize);
- else
- memcpy(targetAddress, buffer, blockSize);
- }
- __except (KphpGetCopyExceptionInfo(
- GetExceptionInformation(),
- &haveBadAddress,
- &badAddress
- ))
- {
- KeUnstackDetachProcess(&apcState);
-
- // If we mapped the pages, unmap them.
- if (mappedAddress)
- MmUnmapLockedPages(mappedAddress, mdl);
-
- // If we locked the pages, unlock them.
- if (pagesLocked)
- MmUnlockPages(mdl);
-
- // If we allocated pool storage, free it.
- if (buffer != stackBuffer)
- ExFreePoolWithTag(buffer, 'ChpK');
-
- // If we failed when probing or mapping, return the error status.
- if (probing || mapping)
- return GetExceptionCode();
-
- // Determine which copy failed.
- if (copyingToTarget && haveBadAddress)
- {
- *ReturnLength = (ULONG)(badAddress - (ULONG_PTR)sourceAddress);
- }
- else
- {
- *ReturnLength = BufferLength - stillToCopy;
- }
-
- return STATUS_PARTIAL_COPY;
- }
-
- KeUnstackDetachProcess(&apcState);
-
- if (doMappedCopy)
- {
- MmUnmapLockedPages(mappedAddress, mdl);
- MmUnlockPages(mdl);
- }
-
- stillToCopy -= blockSize;
- sourceAddress = (PVOID)((ULONG_PTR)sourceAddress + blockSize);
- targetAddress = (PVOID)((ULONG_PTR)targetAddress + blockSize);
- }
-
- if (buffer != stackBuffer)
- ExFreePoolWithTag(buffer, 'ChpK');
-
- *ReturnLength = BufferLength;
-
- return STATUS_SUCCESS;
-}
-
-/**
- * Copies process or kernel memory into the current process.
- *
- * \param ProcessHandle A handle to a process. The handle must have PROCESS_VM_READ access. This
- * parameter may be NULL if \a BaseAddress lies above the user-mode range.
- * \param BaseAddress The address from which memory is to be copied.
- * \param Buffer A buffer which receives the copied memory.
- * \param BufferSize The number of bytes to copy.
- * \param NumberOfBytesRead A variable which receives the number of bytes copied to the buffer.
- * \param Key An access key. If no valid L2 key is provided, the function fails.
- * \param Client The client that initiated the request.
- * \param AccessMode The mode in which to perform access checks.
- */
-NTSTATUS KpiReadVirtualMemoryUnsafe(
- __in_opt HANDLE ProcessHandle,
- __in PVOID BaseAddress,
- __out_bcount(BufferSize) PVOID Buffer,
- __in SIZE_T BufferSize,
- __out_opt PSIZE_T NumberOfBytesRead,
- __in_opt KPH_KEY Key,
- __in PKPH_CLIENT Client,
- __in KPROCESSOR_MODE AccessMode
- )
-{
- NTSTATUS status;
- PEPROCESS process;
- SIZE_T numberOfBytesRead;
-
- PAGED_CODE();
-
- if (!NT_SUCCESS(status = KphValidateKey(KphKeyLevel2, Key, Client, AccessMode)))
- return status;
-
- if (AccessMode != KernelMode)
- {
- if (
- (ULONG_PTR)BaseAddress + BufferSize < (ULONG_PTR)BaseAddress ||
- (ULONG_PTR)Buffer + BufferSize < (ULONG_PTR)Buffer ||
- (ULONG_PTR)Buffer + BufferSize > (ULONG_PTR)MmHighestUserAddress
- )
- {
- return STATUS_ACCESS_VIOLATION;
- }
-
- if (NumberOfBytesRead)
- {
- __try
- {
- ProbeForWrite(NumberOfBytesRead, sizeof(SIZE_T), sizeof(SIZE_T));
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- return GetExceptionCode();
- }
- }
- }
-
- if (BufferSize != 0)
- {
- // Select the appropriate copy method.
- if ((ULONG_PTR)BaseAddress + BufferSize > (ULONG_PTR)MmHighestUserAddress)
- {
- ULONG_PTR page;
- ULONG_PTR pageEnd;
-
- status = KphValidateAddressForSystemModules(BaseAddress, BufferSize);
-
- if (!NT_SUCCESS(status))
- return status;
-
- // Kernel memory copy (unsafe)
-
- page = (ULONG_PTR)BaseAddress & ~(PAGE_SIZE - 1);
- pageEnd = ((ULONG_PTR)BaseAddress + BufferSize - 1) & ~(PAGE_SIZE - 1);
-
- __try
- {
- // This will obviously fail if any of the pages aren't resident.
- for (; page <= pageEnd; page += PAGE_SIZE)
- {
- if (!MmIsAddressValid((PVOID)page))
- ExRaiseStatus(STATUS_ACCESS_VIOLATION);
- }
-
- memcpy(Buffer, BaseAddress, BufferSize);
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- return GetExceptionCode();
- }
-
- numberOfBytesRead = BufferSize;
- status = STATUS_SUCCESS;
- }
- else
- {
- // User memory copy (safe)
-
- status = ObReferenceObjectByHandle(
- ProcessHandle,
- PROCESS_VM_READ,
- *PsProcessType,
- AccessMode,
- &process,
- NULL
- );
-
- if (NT_SUCCESS(status))
- {
- status = KphCopyVirtualMemory(
- process,
- BaseAddress,
- PsGetCurrentProcess(),
- Buffer,
- BufferSize,
- AccessMode,
- &numberOfBytesRead
- );
- ObDereferenceObject(process);
- }
- }
- }
- else
- {
- numberOfBytesRead = 0;
- status = STATUS_SUCCESS;
- }
-
- if (NumberOfBytesRead)
- {
- if (AccessMode != KernelMode)
- {
- __try
- {
- *NumberOfBytesRead = numberOfBytesRead;
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- // Don't mess with the status.
- NOTHING;
- }
- }
- else
- {
- *NumberOfBytesRead = numberOfBytesRead;
- }
- }
-
- return status;
-}
+/*
+ * KProcessHacker
+ *
+ * Copyright (C) 2010-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 .
+ */
+
+#include
+
+ULONG KphpGetCopyExceptionInfo(
+ _In_ PEXCEPTION_POINTERS ExceptionInfo,
+ _Out_ PBOOLEAN HaveBadAddress,
+ _Out_ PULONG_PTR BadAddress
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, KphCopyVirtualMemory)
+#pragma alloc_text(PAGE, KpiReadVirtualMemoryUnsafe)
+#endif
+
+#define KPH_STACK_COPY_BYTES 0x200
+#define KPH_POOL_COPY_BYTES 0x10000
+#define KPH_MAPPED_COPY_PAGES 14
+#define KPH_POOL_COPY_THRESHOLD 0x3ff
+
+ULONG KphpGetCopyExceptionInfo(
+ _In_ PEXCEPTION_POINTERS ExceptionInfo,
+ _Out_ PBOOLEAN HaveBadAddress,
+ _Out_ PULONG_PTR BadAddress
+ )
+{
+ PEXCEPTION_RECORD exceptionRecord;
+
+ *HaveBadAddress = FALSE;
+ exceptionRecord = ExceptionInfo->ExceptionRecord;
+
+ if ((exceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION) ||
+ (exceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION) ||
+ (exceptionRecord->ExceptionCode == STATUS_IN_PAGE_ERROR))
+ {
+ if (exceptionRecord->NumberParameters > 1)
+ {
+ /* We have the address. */
+ *HaveBadAddress = TRUE;
+ *BadAddress = exceptionRecord->ExceptionInformation[1];
+ }
+ }
+
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+
+/**
+ * Copies memory from one process to another.
+ *
+ * \param FromProcess The source process.
+ * \param FromAddress The source address.
+ * \param ToProcess The target process.
+ * \param ToAddress The target address.
+ * \param BufferLength The number of bytes to copy.
+ * \param AccessMode The mode in which to perform access checks.
+ * \param ReturnLength A variable which receives the number of bytes copied.
+ */
+NTSTATUS KphCopyVirtualMemory(
+ _In_ PEPROCESS FromProcess,
+ _In_ PVOID FromAddress,
+ _In_ PEPROCESS ToProcess,
+ _In_ PVOID ToAddress,
+ _In_ SIZE_T BufferLength,
+ _In_ KPROCESSOR_MODE AccessMode,
+ _Out_ PSIZE_T ReturnLength
+ )
+{
+ UCHAR stackBuffer[KPH_STACK_COPY_BYTES];
+ PVOID buffer;
+ PFN_NUMBER mdlBuffer[(sizeof(MDL) / sizeof(PFN_NUMBER)) + KPH_MAPPED_COPY_PAGES + 1];
+ PMDL mdl = (PMDL)mdlBuffer;
+ PVOID mappedAddress;
+ SIZE_T mappedTotalSize;
+ SIZE_T blockSize;
+ SIZE_T stillToCopy;
+ KAPC_STATE apcState;
+ PVOID sourceAddress;
+ PVOID targetAddress;
+ BOOLEAN doMappedCopy;
+ BOOLEAN pagesLocked;
+ BOOLEAN copyingToTarget = FALSE;
+ BOOLEAN probing = FALSE;
+ BOOLEAN mapping = FALSE;
+ BOOLEAN haveBadAddress;
+ ULONG_PTR badAddress;
+
+ PAGED_CODE();
+
+ sourceAddress = FromAddress;
+ targetAddress = ToAddress;
+
+ // We don't check if buffer == NULL when freeing. If buffer doesn't need to be freed, set to
+ // stackBuffer, not NULL.
+ buffer = stackBuffer;
+
+ mappedTotalSize = (KPH_MAPPED_COPY_PAGES - 2) * PAGE_SIZE;
+
+ if (mappedTotalSize > BufferLength)
+ mappedTotalSize = BufferLength;
+
+ stillToCopy = BufferLength;
+ blockSize = mappedTotalSize;
+
+ while (stillToCopy)
+ {
+ // If we're at the last copy block, copy the remaining bytes instead of the whole block
+ // size.
+ if (blockSize > stillToCopy)
+ blockSize = stillToCopy;
+
+ // Choose the best method based on the number of bytes left to copy.
+ if (blockSize > KPH_POOL_COPY_THRESHOLD)
+ {
+ doMappedCopy = TRUE;
+ }
+ else
+ {
+ doMappedCopy = FALSE;
+
+ if (blockSize <= KPH_STACK_COPY_BYTES)
+ {
+ if (buffer != stackBuffer)
+ ExFreePoolWithTag(buffer, 'ChpK');
+
+ buffer = stackBuffer;
+ }
+ else
+ {
+ // Don't allocate the buffer if we've done so already. Note that the block size
+ // never increases, so this allocation will always be OK.
+ if (buffer == stackBuffer)
+ {
+ // Keep trying to allocate a buffer.
+
+ while (TRUE)
+ {
+ buffer = ExAllocatePoolWithTag(NonPagedPool, blockSize, 'ChpK');
+
+ // Stop trying if we got a buffer.
+ if (buffer)
+ break;
+
+ blockSize /= 2;
+
+ // Use the stack buffer if we can.
+ if (blockSize <= KPH_STACK_COPY_BYTES)
+ {
+ buffer = stackBuffer;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Reset state.
+ mappedAddress = NULL;
+ pagesLocked = FALSE;
+ copyingToTarget = FALSE;
+
+ KeStackAttachProcess(FromProcess, &apcState);
+
+ __try
+ {
+ // Probe only if this is the first time.
+ if (sourceAddress == FromAddress && AccessMode != KernelMode)
+ {
+ probing = TRUE;
+ ProbeForRead(sourceAddress, BufferLength, sizeof(UCHAR));
+ probing = FALSE;
+ }
+
+ if (doMappedCopy)
+ {
+ // Initialize the MDL.
+ MmInitializeMdl(mdl, sourceAddress, blockSize);
+ MmProbeAndLockPages(mdl, AccessMode, IoReadAccess);
+ pagesLocked = TRUE;
+
+ // Map the pages.
+ mappedAddress = MmMapLockedPagesSpecifyCache(
+ mdl,
+ KernelMode,
+ MmCached,
+ NULL,
+ FALSE,
+ HighPagePriority
+ );
+
+ if (!mappedAddress)
+ {
+ // Insufficient resources; exit.
+ mapping = TRUE;
+ ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
+ }
+ }
+ else
+ {
+ memcpy(buffer, sourceAddress, blockSize);
+ }
+
+ KeUnstackDetachProcess(&apcState);
+
+ // Attach to the target process and copy the contents out.
+ KeStackAttachProcess(ToProcess, &apcState);
+
+ // Probe only if this is the first time.
+ if (targetAddress == ToAddress && AccessMode != KernelMode)
+ {
+ probing = TRUE;
+ ProbeForWrite(targetAddress, BufferLength, sizeof(UCHAR));
+ probing = FALSE;
+ }
+
+ // Copy the data.
+ copyingToTarget = TRUE;
+
+ if (doMappedCopy)
+ memcpy(targetAddress, mappedAddress, blockSize);
+ else
+ memcpy(targetAddress, buffer, blockSize);
+ }
+ __except (KphpGetCopyExceptionInfo(
+ GetExceptionInformation(),
+ &haveBadAddress,
+ &badAddress
+ ))
+ {
+ KeUnstackDetachProcess(&apcState);
+
+ // If we mapped the pages, unmap them.
+ if (mappedAddress)
+ MmUnmapLockedPages(mappedAddress, mdl);
+
+ // If we locked the pages, unlock them.
+ if (pagesLocked)
+ MmUnlockPages(mdl);
+
+ // If we allocated pool storage, free it.
+ if (buffer != stackBuffer)
+ ExFreePoolWithTag(buffer, 'ChpK');
+
+ // If we failed when probing or mapping, return the error status.
+ if (probing || mapping)
+ return GetExceptionCode();
+
+ // Determine which copy failed.
+ if (copyingToTarget && haveBadAddress)
+ {
+ *ReturnLength = (ULONG)(badAddress - (ULONG_PTR)sourceAddress);
+ }
+ else
+ {
+ *ReturnLength = BufferLength - stillToCopy;
+ }
+
+ return STATUS_PARTIAL_COPY;
+ }
+
+ KeUnstackDetachProcess(&apcState);
+
+ if (doMappedCopy)
+ {
+ MmUnmapLockedPages(mappedAddress, mdl);
+ MmUnlockPages(mdl);
+ }
+
+ stillToCopy -= blockSize;
+ sourceAddress = (PVOID)((ULONG_PTR)sourceAddress + blockSize);
+ targetAddress = (PVOID)((ULONG_PTR)targetAddress + blockSize);
+ }
+
+ if (buffer != stackBuffer)
+ ExFreePoolWithTag(buffer, 'ChpK');
+
+ *ReturnLength = BufferLength;
+
+ return STATUS_SUCCESS;
+}
+
+/**
+ * Copies process or kernel memory into the current process.
+ *
+ * \param ProcessHandle A handle to a process. The handle must have PROCESS_VM_READ access. This
+ * parameter may be NULL if \a BaseAddress lies above the user-mode range.
+ * \param BaseAddress The address from which memory is to be copied.
+ * \param Buffer A buffer which receives the copied memory.
+ * \param BufferSize The number of bytes to copy.
+ * \param NumberOfBytesRead A variable which receives the number of bytes copied to the buffer.
+ * \param Key An access key. If no valid L2 key is provided, the function fails.
+ * \param Client The client that initiated the request.
+ * \param AccessMode The mode in which to perform access checks.
+ */
+NTSTATUS KpiReadVirtualMemoryUnsafe(
+ _In_opt_ HANDLE ProcessHandle,
+ _In_ PVOID BaseAddress,
+ _Out_writes_bytes_(BufferSize) PVOID Buffer,
+ _In_ SIZE_T BufferSize,
+ _Out_opt_ PSIZE_T NumberOfBytesRead,
+ _In_opt_ KPH_KEY Key,
+ _In_ PKPH_CLIENT Client,
+ _In_ KPROCESSOR_MODE AccessMode
+ )
+{
+ NTSTATUS status;
+ PEPROCESS process;
+ SIZE_T numberOfBytesRead = 0;
+
+ PAGED_CODE();
+
+ if (!NT_SUCCESS(status = KphValidateKey(KphKeyLevel2, Key, Client, AccessMode)))
+ return status;
+
+ if (AccessMode != KernelMode)
+ {
+ if (
+ (ULONG_PTR)BaseAddress + BufferSize < (ULONG_PTR)BaseAddress ||
+ (ULONG_PTR)Buffer + BufferSize < (ULONG_PTR)Buffer ||
+ (ULONG_PTR)Buffer + BufferSize > (ULONG_PTR)MmHighestUserAddress
+ )
+ {
+ return STATUS_ACCESS_VIOLATION;
+ }
+
+ if (NumberOfBytesRead)
+ {
+ __try
+ {
+ ProbeForWrite(NumberOfBytesRead, sizeof(SIZE_T), sizeof(SIZE_T));
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+ }
+ }
+
+ if (BufferSize != 0)
+ {
+ // Select the appropriate copy method.
+ if ((ULONG_PTR)BaseAddress + BufferSize > (ULONG_PTR)MmHighestUserAddress)
+ {
+ ULONG_PTR page;
+ ULONG_PTR pageEnd;
+
+ status = KphValidateAddressForSystemModules(BaseAddress, BufferSize);
+
+ if (!NT_SUCCESS(status))
+ return status;
+
+ // Kernel memory copy (unsafe)
+
+ page = (ULONG_PTR)BaseAddress & ~(PAGE_SIZE - 1);
+ pageEnd = ((ULONG_PTR)BaseAddress + BufferSize - 1) & ~(PAGE_SIZE - 1);
+
+ __try
+ {
+ // This will obviously fail if any of the pages aren't resident.
+ for (; page <= pageEnd; page += PAGE_SIZE)
+ {
+ if (!MmIsAddressValid((PVOID)page))
+ ExRaiseStatus(STATUS_ACCESS_VIOLATION);
+ }
+
+ memcpy(Buffer, BaseAddress, BufferSize);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return GetExceptionCode();
+ }
+
+ numberOfBytesRead = BufferSize;
+ status = STATUS_SUCCESS;
+ }
+ else
+ {
+ // User memory copy (safe)
+
+ status = ObReferenceObjectByHandle(
+ ProcessHandle,
+ PROCESS_VM_READ,
+ *PsProcessType,
+ AccessMode,
+ &process,
+ NULL
+ );
+
+ if (NT_SUCCESS(status))
+ {
+ status = KphCopyVirtualMemory(
+ process,
+ BaseAddress,
+ PsGetCurrentProcess(),
+ Buffer,
+ BufferSize,
+ AccessMode,
+ &numberOfBytesRead
+ );
+ ObDereferenceObject(process);
+ }
+ }
+ }
+ else
+ {
+ numberOfBytesRead = 0;
+ status = STATUS_SUCCESS;
+ }
+
+ if (NumberOfBytesRead)
+ {
+ if (AccessMode != KernelMode)
+ {
+ __try
+ {
+ *NumberOfBytesRead = numberOfBytesRead;
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ // Don't mess with the status.
+ NOTHING;
+ }
+ }
+ else
+ {
+ *NumberOfBytesRead = numberOfBytesRead;
+ }
+ }
+
+ return status;
+}
diff --git a/LICENSE.txt b/LICENSE.txt
index 4e402de2cfe4..201de86e9f7e 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -1,685 +1,685 @@
-Process Hacker is distributed under the GNU GPL version 3, with the
-following exception:
-
- Permission is granted to dynamically (but not statically) link this
- program with independent modules, regardless of the license terms of
- these independent modules, provided that this program is not modified
- in any way. An independent module is a module which is not derived
- from or based on this program. If you modify this program, this
- additional permission no longer applies unless authorized by the
- copyright holders.
-
- GNU GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc.
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
- The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works. By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users. We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors. You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
- To protect your rights, we need to prevent others from denying you
-these rights or asking you to surrender the rights. Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received. You must make sure that they, too, receive
-or can get the source code. And you must show them these terms so they
-know their rights.
-
- Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
- For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software. For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
- Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so. This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software. The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable. Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products. If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
- Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary. To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- TERMS AND CONDITIONS
-
- 0. Definitions.
-
- "This License" refers to version 3 of the GNU General Public License.
-
- "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
- "The Program" refers to any copyrightable work licensed under this
-License. Each licensee is addressed as "you". "Licensees" and
-"recipients" may be individuals or organizations.
-
- To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy. The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
- A "covered work" means either the unmodified Program or a work based
-on the Program.
-
- To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy. Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
- To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies. Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
- An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License. If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
- 1. Source Code.
-
- The "source code" for a work means the preferred form of the work
-for making modifications to it. "Object code" means any non-source
-form of a work.
-
- A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
- The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form. A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
- The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities. However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work. For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
- The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
- The Corresponding Source for a work in source code form is that
-same work.
-
- 2. Basic Permissions.
-
- All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met. This License explicitly affirms your unlimited
-permission to run the unmodified Program. The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work. This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
- You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force. You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright. Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
- Conveying under any other circumstances is permitted solely under
-the conditions stated below. Sublicensing is not allowed; section 10
-makes it unnecessary.
-
- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
- No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
- When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
- 4. Conveying Verbatim Copies.
-
- You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
- You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
- 5. Conveying Modified Source Versions.
-
- You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
- a) The work must carry prominent notices stating that you modified
- it, and giving a relevant date.
-
- b) The work must carry prominent notices stating that it is
- released under this License and any conditions added under section
- 7. This requirement modifies the requirement in section 4 to
- "keep intact all notices".
-
- c) You must license the entire work, as a whole, under this
- License to anyone who comes into possession of a copy. This
- License will therefore apply, along with any applicable section 7
- additional terms, to the whole of the work, and all its parts,
- regardless of how they are packaged. This License gives no
- permission to license the work in any other way, but it does not
- invalidate such permission if you have separately received it.
-
- d) If the work has interactive user interfaces, each must display
- Appropriate Legal Notices; however, if the Program has interactive
- interfaces that do not display Appropriate Legal Notices, your
- work need not make them do so.
-
- A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit. Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
- 6. Conveying Non-Source Forms.
-
- You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
- a) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by the
- Corresponding Source fixed on a durable physical medium
- customarily used for software interchange.
-
- b) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by a
- written offer, valid for at least three years and valid for as
- long as you offer spare parts or customer support for that product
- model, to give anyone who possesses the object code either (1) a
- copy of the Corresponding Source for all the software in the
- product that is covered by this License, on a durable physical
- medium customarily used for software interchange, for a price no
- more than your reasonable cost of physically performing this
- conveying of source, or (2) access to copy the
- Corresponding Source from a network server at no charge.
-
- c) Convey individual copies of the object code with a copy of the
- written offer to provide the Corresponding Source. This
- alternative is allowed only occasionally and noncommercially, and
- only if you received the object code with such an offer, in accord
- with subsection 6b.
-
- d) Convey the object code by offering access from a designated
- place (gratis or for a charge), and offer equivalent access to the
- Corresponding Source in the same way through the same place at no
- further charge. You need not require recipients to copy the
- Corresponding Source along with the object code. If the place to
- copy the object code is a network server, the Corresponding Source
- may be on a different server (operated by you or a third party)
- that supports equivalent copying facilities, provided you maintain
- clear directions next to the object code saying where to find the
- Corresponding Source. Regardless of what server hosts the
- Corresponding Source, you remain obligated to ensure that it is
- available for as long as needed to satisfy these requirements.
-
- e) Convey the object code using peer-to-peer transmission, provided
- you inform other peers where the object code and Corresponding
- Source of the work are being offered to the general public at no
- charge under subsection 6d.
-
- A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
- A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling. In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage. For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product. A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
- "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source. The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
- If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information. But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
- The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed. Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
- Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
- 7. Additional Terms.
-
- "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law. If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
- When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it. (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.) You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
- Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
- a) Disclaiming warranty or limiting liability differently from the
- terms of sections 15 and 16 of this License; or
-
- b) Requiring preservation of specified reasonable legal notices or
- author attributions in that material or in the Appropriate Legal
- Notices displayed by works containing it; or
-
- c) Prohibiting misrepresentation of the origin of that material, or
- requiring that modified versions of such material be marked in
- reasonable ways as different from the original version; or
-
- d) Limiting the use for publicity purposes of names of licensors or
- authors of the material; or
-
- e) Declining to grant rights under trademark law for use of some
- trade names, trademarks, or service marks; or
-
- f) Requiring indemnification of licensors and authors of that
- material by anyone who conveys the material (or modified versions of
- it) with contractual assumptions of liability to the recipient, for
- any liability that these contractual assumptions directly impose on
- those licensors and authors.
-
- All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10. If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term. If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
- If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
- Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
- 8. Termination.
-
- You may not propagate or modify a covered work except as expressly
-provided under this License. Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
- However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
- Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
- Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License. If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
- 9. Acceptance Not Required for Having Copies.
-
- You are not required to accept this License in order to receive or
-run a copy of the Program. Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance. However,
-nothing other than this License grants you permission to propagate or
-modify any covered work. These actions infringe copyright if you do
-not accept this License. Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
- 10. Automatic Licensing of Downstream Recipients.
-
- Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License. You are not responsible
-for enforcing compliance by third parties with this License.
-
- An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations. If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
- You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License. For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
- 11. Patents.
-
- A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based. The
-work thus licensed is called the contributor's "contributor version".
-
- A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version. For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
- Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
- In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement). To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
- If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients. "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
- If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
- A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License. You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
- Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
- 12. No Surrender of Others' Freedom.
-
- If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all. For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
- 13. Use with the GNU Affero General Public License.
-
- Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work. The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
- 14. Revised Versions of this License.
-
- The Free Software Foundation may publish revised and/or new versions of
-the GNU General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Program specifies that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation. If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
- If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
- Later license versions may give you additional or different
-permissions. However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
- 15. Disclaimer of Warranty.
-
- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. Limitation of Liability.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
- 17. Interpretation of Sections 15 and 16.
-
- If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-
- Copyright (C)
-
- This program 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.
-
- This program 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 this program. If not, see .
-
-Also add information on how to contact you by electronic and paper mail.
-
- If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
- Copyright (C)
- This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, your program's commands
-might be different; for a GUI interface, you would use an "about box".
-
- You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
-.
-
- The GNU General Public License does not permit incorporating your program
-into proprietary programs. If your program is a subroutine library, you
-may consider it more useful to permit linking proprietary applications with
-the library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License. But first, please read
-.
+Process Hacker is distributed under the GNU GPL version 3, with the
+following exception:
+
+ Permission is granted to dynamically (but not statically) link this
+ program with independent modules, regardless of the license terms of
+ these independent modules, provided that this program is not modified
+ in any way. An independent module is a module which is not derived
+ from or based on this program. If you modify this program, this
+ additional permission no longer applies unless authorized by the
+ copyright holders.
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program 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.
+
+ This program 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 this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/ProcessHacker.sln b/ProcessHacker.sln
index f9d474cc33d6..4e87a04af677 100644
--- a/ProcessHacker.sln
+++ b/ProcessHacker.sln
@@ -1,81 +1,51 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.26228.4
-MinimumVisualStudioVersion = 15.0.26228.4
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{2758DC86-368B-430C-9D29-F1EF20032A71}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ProcessHacker", "ProcessHacker\ProcessHacker.vcxproj", "{0271DD27-6707-4290-8DFE-285702B7115D}"
- ProjectSection(ProjectDependencies) = postProject
- {477D0215-F252-41A1-874B-F27E3EA1ED17} = {477D0215-F252-41A1-874B-F27E3EA1ED17}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "phlib", "phlib\phlib.vcxproj", "{477D0215-F252-41A1-874B-F27E3EA1ED17}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fixlib", "tools\fixlib\fixlib.vcxproj", "{31F4AA06-7ED5-4A6D-B901-19AD4BD16175}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "peview", "tools\peview\peview.vcxproj", "{72C124A2-3C80-41C6-ABA1-C4948B713204}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{FD3C278D-BD40-4551-AE67-4DE196F8D7F6}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "phlib-test", "tests\phlib-test\phlib-test.vcxproj", "{0C21014E-BC90-4AE5-AA32-398445C13B28}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CustomSignTool", "tools\CustomSignTool\CustomSignTool.vcxproj", "{E8CD0A41-1537-4EA6-98AC-E80CD59C478E}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Win32 = Debug|Win32
- Debug|x64 = Debug|x64
- Release|Win32 = Release|Win32
- Release|x64 = Release|x64
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {0271DD27-6707-4290-8DFE-285702B7115D}.Debug|Win32.ActiveCfg = Debug|Win32
- {0271DD27-6707-4290-8DFE-285702B7115D}.Debug|Win32.Build.0 = Debug|Win32
- {0271DD27-6707-4290-8DFE-285702B7115D}.Debug|x64.ActiveCfg = Debug|x64
- {0271DD27-6707-4290-8DFE-285702B7115D}.Debug|x64.Build.0 = Debug|x64
- {0271DD27-6707-4290-8DFE-285702B7115D}.Release|Win32.ActiveCfg = Release|Win32
- {0271DD27-6707-4290-8DFE-285702B7115D}.Release|Win32.Build.0 = Release|Win32
- {0271DD27-6707-4290-8DFE-285702B7115D}.Release|x64.ActiveCfg = Release|x64
- {0271DD27-6707-4290-8DFE-285702B7115D}.Release|x64.Build.0 = Release|x64
- {477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|Win32.ActiveCfg = Debug|Win32
- {477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|Win32.Build.0 = Debug|Win32
- {477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|x64.ActiveCfg = Debug|x64
- {477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|x64.Build.0 = Debug|x64
- {477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|Win32.ActiveCfg = Release|Win32
- {477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|Win32.Build.0 = Release|Win32
- {477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|x64.ActiveCfg = Release|x64
- {477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|x64.Build.0 = Release|x64
- {31F4AA06-7ED5-4A6D-B901-19AD4BD16175}.Debug|Win32.ActiveCfg = Debug|Win32
- {31F4AA06-7ED5-4A6D-B901-19AD4BD16175}.Debug|x64.ActiveCfg = Debug|Win32
- {31F4AA06-7ED5-4A6D-B901-19AD4BD16175}.Release|Win32.ActiveCfg = Release|Win32
- {31F4AA06-7ED5-4A6D-B901-19AD4BD16175}.Release|x64.ActiveCfg = Release|Win32
- {72C124A2-3C80-41C6-ABA1-C4948B713204}.Debug|Win32.ActiveCfg = Debug|Win32
- {72C124A2-3C80-41C6-ABA1-C4948B713204}.Debug|Win32.Build.0 = Debug|Win32
- {72C124A2-3C80-41C6-ABA1-C4948B713204}.Debug|x64.ActiveCfg = Debug|x64
- {72C124A2-3C80-41C6-ABA1-C4948B713204}.Debug|x64.Build.0 = Debug|x64
- {72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|Win32.ActiveCfg = Release|Win32
- {72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|Win32.Build.0 = Release|Win32
- {72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|x64.ActiveCfg = Release|x64
- {72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|x64.Build.0 = Release|x64
- {0C21014E-BC90-4AE5-AA32-398445C13B28}.Debug|Win32.ActiveCfg = Debug|Win32
- {0C21014E-BC90-4AE5-AA32-398445C13B28}.Debug|Win32.Build.0 = Debug|Win32
- {0C21014E-BC90-4AE5-AA32-398445C13B28}.Debug|x64.ActiveCfg = Debug|Win32
- {0C21014E-BC90-4AE5-AA32-398445C13B28}.Release|Win32.ActiveCfg = Release|Win32
- {0C21014E-BC90-4AE5-AA32-398445C13B28}.Release|Win32.Build.0 = Release|Win32
- {0C21014E-BC90-4AE5-AA32-398445C13B28}.Release|x64.ActiveCfg = Release|Win32
- {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Debug|Win32.ActiveCfg = Debug|Win32
- {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Debug|x64.ActiveCfg = Debug|x64
- {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Release|Win32.ActiveCfg = Release|Win32
- {E8CD0A41-1537-4EA6-98AC-E80CD59C478E}.Release|x64.ActiveCfg = Release|x64
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(NestedProjects) = preSolution
- {31F4AA06-7ED5-4A6D-B901-19AD4BD16175} = {2758DC86-368B-430C-9D29-F1EF20032A71}
- {72C124A2-3C80-41C6-ABA1-C4948B713204} = {2758DC86-368B-430C-9D29-F1EF20032A71}
- {0C21014E-BC90-4AE5-AA32-398445C13B28} = {FD3C278D-BD40-4551-AE67-4DE196F8D7F6}
- {E8CD0A41-1537-4EA6-98AC-E80CD59C478E} = {2758DC86-368B-430C-9D29-F1EF20032A71}
- EndGlobalSection
-EndGlobal
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26430.6
+MinimumVisualStudioVersion = 15.0.26228.4
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ProcessHacker", "ProcessHacker\ProcessHacker.vcxproj", "{0271DD27-6707-4290-8DFE-285702B7115D}"
+ ProjectSection(ProjectDependencies) = postProject
+ {477D0215-F252-41A1-874B-F27E3EA1ED17} = {477D0215-F252-41A1-874B-F27E3EA1ED17}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "phlib", "phlib\phlib.vcxproj", "{477D0215-F252-41A1-874B-F27E3EA1ED17}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "peview", "tools\peview\peview.vcxproj", "{72C124A2-3C80-41C6-ABA1-C4948B713204}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {0271DD27-6707-4290-8DFE-285702B7115D}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0271DD27-6707-4290-8DFE-285702B7115D}.Debug|Win32.Build.0 = Debug|Win32
+ {0271DD27-6707-4290-8DFE-285702B7115D}.Debug|x64.ActiveCfg = Debug|x64
+ {0271DD27-6707-4290-8DFE-285702B7115D}.Debug|x64.Build.0 = Debug|x64
+ {0271DD27-6707-4290-8DFE-285702B7115D}.Release|Win32.ActiveCfg = Release|Win32
+ {0271DD27-6707-4290-8DFE-285702B7115D}.Release|Win32.Build.0 = Release|Win32
+ {0271DD27-6707-4290-8DFE-285702B7115D}.Release|x64.ActiveCfg = Release|x64
+ {0271DD27-6707-4290-8DFE-285702B7115D}.Release|x64.Build.0 = Release|x64
+ {477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|Win32.ActiveCfg = Debug|Win32
+ {477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|Win32.Build.0 = Debug|Win32
+ {477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|x64.ActiveCfg = Debug|x64
+ {477D0215-F252-41A1-874B-F27E3EA1ED17}.Debug|x64.Build.0 = Debug|x64
+ {477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|Win32.ActiveCfg = Release|Win32
+ {477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|Win32.Build.0 = Release|Win32
+ {477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|x64.ActiveCfg = Release|x64
+ {477D0215-F252-41A1-874B-F27E3EA1ED17}.Release|x64.Build.0 = Release|x64
+ {72C124A2-3C80-41C6-ABA1-C4948B713204}.Debug|Win32.ActiveCfg = Debug|Win32
+ {72C124A2-3C80-41C6-ABA1-C4948B713204}.Debug|Win32.Build.0 = Debug|Win32
+ {72C124A2-3C80-41C6-ABA1-C4948B713204}.Debug|x64.ActiveCfg = Debug|x64
+ {72C124A2-3C80-41C6-ABA1-C4948B713204}.Debug|x64.Build.0 = Debug|x64
+ {72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|Win32.ActiveCfg = Release|Win32
+ {72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|Win32.Build.0 = Release|Win32
+ {72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|x64.ActiveCfg = Release|x64
+ {72C124A2-3C80-41C6-ABA1-C4948B713204}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/ProcessHacker/ProcessHacker.def b/ProcessHacker/ProcessHacker.def
index fec35a00d451..820c7f55006c 100644
--- a/ProcessHacker/ProcessHacker.def
+++ b/ProcessHacker/ProcessHacker.def
@@ -5,574 +5,693 @@ EXPORTS
;
; ref
- PhAutoDereferenceObject
- PhCreateAlloc
- PhCreateObject
- PhCreateObjectType
- PhCreateObjectTypeEx
- PhDeleteAutoPool
- PhDereferenceObject
- PhDereferenceObjectDeferDelete
- PhDereferenceObjectEx
- PhDrainAutoPool
- PhGetObjectType
- PhGetObjectTypeInformation
- PhInitializeAutoPool
- PhReferenceObject
- PhReferenceObjectEx
- PhReferenceObjectSafe
+ PhAutoDereferenceObject
+ PhCreateAlloc
+ PhCreateObject
+ PhCreateObjectType
+ PhCreateObjectTypeEx
+ PhDeleteAutoPool
+ PhDereferenceObject
+ PhDereferenceObjectDeferDelete
+ PhDereferenceObjectEx
+ PhDrainAutoPool
+ PhGetObjectType
+ PhGetObjectTypeInformation
+ PhInitializeAutoPool
+ PhReferenceObject
+ PhReferenceObjectEx
+ PhReferenceObjectSafe
; queuedlock
- PhfAcquireQueuedLockExclusive
- PhfAcquireQueuedLockShared
- PhfPulseAllCondition
- PhfPulseCondition
- PhfQueueWakeEvent
- PhfReleaseQueuedLockExclusive
- PhfReleaseQueuedLockShared
- PhfSetWakeEvent
- PhfWaitForCondition
- PhfWaitForConditionEx
- PhfWaitForWakeEvent
- PhfWakeForReleaseQueuedLock
+ PhfAcquireQueuedLockExclusive
+ PhfAcquireQueuedLockShared
+ PhfPulseAllCondition
+ PhfPulseCondition
+ PhfQueueWakeEvent
+ PhfReleaseQueuedLockExclusive
+ PhfReleaseQueuedLockShared
+ PhfSetWakeEvent
+ PhfWaitForCondition
+ PhfWaitForConditionEx
+ PhfWaitForWakeEvent
+ PhfWakeForReleaseQueuedLock
; phconfig
- PhGlobalDpi DATA
- PhHeapHandle DATA
- PhIsExecutingInWow64
- PhLibImageBase DATA
- PhOsVersion DATA
- PhSystemBasicInformation DATA
- ProcessAllAccess DATA
- ProcessQueryAccess DATA
- ThreadAllAccess DATA
- ThreadQueryAccess DATA
- ThreadSetAccess DATA
- WindowsVersion DATA
+ PhGlobalDpi DATA
+ PhIsExecutingInWow64
+ PhInstanceHandle DATA
+ PhOsVersion DATA
+ PhSystemBasicInformation DATA
+ ProcessAllAccess DATA
+ ProcessQueryAccess DATA
+ ThreadAllAccess DATA
+ ThreadQueryAccess DATA
+ ThreadSetAccess DATA
+ WindowsVersion DATA
; phbasesup
- PhAddElementAvlTree
- PhAddEntryHashtable
- PhAddEntryHashtableEx
- PhAddItemArray
- PhAddItemList
- PhAddItemPointerList
- PhAddItemsArray
- PhAddItemSimpleHashtable
- PhAddItemsList
- PhAllocate
- PhAllocateExSafe
- PhAllocateFromFreeList
- PhAllocatePage
- PhAllocateSafe
- PhAppendBytesBuilder
- PhAppendBytesBuilder2
- PhAppendBytesBuilderEx
- PhAppendCharStringBuilder
- PhAppendCharStringBuilder2
- PhAppendFormatStringBuilder
- PhAppendFormatStringBuilder_V
- PhAppendStringBuilder
- PhAppendStringBuilder2
- PhAppendStringBuilderEx
- PhBufferToHexString
- PhBufferToHexStringEx
- PhClearArray
- PhClearHashtable
- PhClearList
- PhCompareStringRef
- PhCompareStringZNatural
- PhConcatStringRef2
- PhConcatStringRef3
- PhConcatStrings
- PhConcatStrings_V
- PhConcatStrings2
- PhConvertMultiByteToUtf16
- PhConvertMultiByteToUtf16Ex
- PhConvertUtf16ToAsciiEx
- PhConvertUtf16ToMultiByte
- PhConvertUtf16ToMultiByteEx
- PhConvertUtf16ToUtf8
- PhConvertUtf16ToUtf8Buffer
- PhConvertUtf16ToUtf8Ex
- PhConvertUtf16ToUtf8Size
- PhConvertUtf8ToUtf16
- PhConvertUtf8ToUtf16Buffer
- PhConvertUtf8ToUtf16Ex
- PhConvertUtf8ToUtf16Size
- PhCopyBytesZ
- PhCopyStringZ
- PhCopyStringZFromBytes
- PhCopyStringZFromMultiByte
- PhCountStringZ
- PhCreateBytes
- PhCreateBytesEx
- PhCreateHashtable
- PhCreateList
- PhCreatePointerList
- PhCreateSimpleHashtable
- PhCreateString
- PhCreateStringEx
- PhCreateThread
- PhDecodeUnicodeDecoder
- PhDeleteArray
- PhDeleteBytesBuilder
- PhDeleteCallback
- PhDeleteFreeList
- PhDeleteStringBuilder
- PhDivideSinglesBySingle
- PhDosErrorToNtStatus
- PhDuplicateBytesZ
- PhDuplicateBytesZSafe
- PhDuplicateStringZ
- PhEncodeUnicode
- PhEnumAvlTree
- PhEnumHashtable
- PhEnumPointerListEx
- PhEqualStringRef
- PhExponentiate
- PhExponentiate64
- PhfAcquireRundownProtection
- PhfBeginInitOnce
- PhfEndInitOnce
- PhFillMemoryUlong
- PhFinalArrayItems
- PhFinalBytesBuilderBytes
- PhFinalStringBuilderString
- PhFindCharInStringRef
- PhFindElementAvlTree
- PhFindEntryHashtable
- PhFindItemList
- PhFindItemPointerList
- PhFindItemSimpleHashtable
- PhFindLastCharInStringRef
- PhFindStringInStringRef
- PhfInitializeBarrier
- PhfInitializeEvent
- PhfInitializeInitOnce
- PhfInitializeRundownProtection
- PhFormat
- PhFormatString
- PhFormatString_V
- PhFormatToBuffer
- PhFree
- PhFreePage
- PhFreeToFreeList
- PhfReleaseRundownProtection
- PhfResetEvent
- PhfSetEvent
- PhfWaitForBarrier
- PhfWaitForEvent
- PhfWaitForRundownProtection
- PhGetPrimeNumber
- PhHashBytes
- PhHashStringRef
- PhHexStringToBuffer
- PhInitializeArray
- PhInitializeAvlTree
- PhInitializeBytesBuilder
- PhInitializeCallback
- PhInitializeFreeList
- PhInitializeStringBuilder
- PhInsertItemList
- PhInsertItemsList
- PhInsertStringBuilder
- PhInsertStringBuilder2
- PhInsertStringBuilderEx
- PhIntegerToString64
- PhInvokeCallback
- PhLocalTimeToSystemTime
- PhLowerBoundElementAvlTree
- PhLowerDualBoundElementAvlTree
- PhMaximumElementAvlTree
- PhMinimumElementAvlTree
- PhNtStatusFileNotFound
- PhNtStatusToDosError
- PhPredecessorElementAvlTree
- PhPrintTimeSpan
- PhQuerySystemTime
- PhQueryTimeZoneBias
- PhReAllocate
- PhReAllocateSafe
- PhReferenceEmptyString
- PhRegisterCallback
- PhRegisterCallbackEx
- PhRemoveElementAvlTree
- PhRemoveEntryHashtable
- PhRemoveItemArray
- PhRemoveItemList
- PhRemoveItemPointerList
- PhRemoveItemsArray
- PhRemoveItemSimpleHashtable
- PhRemoveItemsList
- PhRemoveStringBuilder
- PhResizeArray
- PhResizeList
- PhRoundUpToPowerOfTwo
- PhSplitStringRefAtChar
- PhSplitStringRefAtLastChar
- PhSplitStringRefAtString
- PhSplitStringRefEx
- PhStringToDouble
- PhStringToInteger64
- PhSuccessorElementAvlTree
- PhSystemTimeToLocalTime
- PhTrimStringRef
- PhUnregisterCallback
- PhUpperBoundElementAvlTree
- PhUpperDualBoundElementAvlTree
- PhWriteUnicodeDecoder
- PhZeroExtendToUtf16Buffer
- PhZeroExtendToUtf16Ex
+ PhAddElementAvlTree
+ PhAddEntryHashtable
+ PhAddEntryHashtableEx
+ PhAddItemArray
+ PhAddItemList
+ PhAddItemPointerList
+ PhAddItemsArray
+ PhAddItemSimpleHashtable
+ PhAddItemsList
+ PhAllocate
+ PhAllocateExSafe
+ PhAllocateFromFreeList
+ PhAllocatePage
+ PhAllocateSafe
+ PhAppendBytesBuilder
+ PhAppendBytesBuilder2
+ PhAppendBytesBuilderEx
+ PhAppendCharStringBuilder
+ PhAppendCharStringBuilder2
+ PhAppendFormatStringBuilder
+ PhAppendFormatStringBuilder_V
+ PhAppendStringBuilder
+ PhAppendStringBuilder2
+ PhAppendStringBuilderEx
+ PhBufferToHexString
+ PhBufferToHexStringEx
+ PhClearArray
+ PhClearHashtable
+ PhClearList
+ PhCompareStringRef
+ PhCompareStringZNatural
+ PhConcatStringRef2
+ PhConcatStringRef3
+ PhConcatStrings
+ PhConcatStrings_V
+ PhConcatStrings2
+ PhConvertMultiByteToUtf16
+ PhConvertMultiByteToUtf16Ex
+ PhConvertUtf16ToAsciiEx
+ PhConvertUtf16ToMultiByte
+ PhConvertUtf16ToMultiByteEx
+ PhConvertUtf16ToUtf8
+ PhConvertUtf16ToUtf8Buffer
+ PhConvertUtf16ToUtf8Ex
+ PhConvertUtf16ToUtf8Size
+ PhConvertUtf8ToUtf16
+ PhConvertUtf8ToUtf16Buffer
+ PhConvertUtf8ToUtf16Ex
+ PhConvertUtf8ToUtf16Size
+ PhCopyBytesZ
+ PhCopyStringZ
+ PhCopyStringZFromBytes
+ PhCopyStringZFromMultiByte
+ PhCountStringZ
+ PhCreateBytes
+ PhCreateBytesEx
+ PhCreateHashtable
+ PhCreateList
+ PhCreatePointerList
+ PhCreateSimpleHashtable
+ PhCreateString
+ PhCreateStringEx
+ PhCreateThread
+ PhCreateThread2
+ PhCreateThreadEx
+ PhDecodeUnicodeDecoder
+ PhDeleteArray
+ PhDeleteBytesBuilder
+ PhDeleteCallback
+ PhDeleteFreeList
+ PhDeleteStringBuilder
+ PhDivideSinglesBySingle
+ PhDosErrorToNtStatus
+ PhDuplicateBytesZ
+ PhDuplicateBytesZSafe
+ PhDuplicateStringZ
+ PhEncodeUnicode
+ PhEnumAvlTree
+ PhEnumHashtable
+ PhEnumPointerListEx
+ PhEqualStringRef
+ PhExponentiate
+ PhExponentiate64
+ PhExtractIcon
+ PhExtractIconEx
+ PhfAcquireRundownProtection
+ PhfBeginInitOnce
+ PhfEndInitOnce
+ PhFillMemoryUlong
+ PhFinalArrayItems
+ PhFinalBytesBuilderBytes
+ PhFinalStringBuilderString
+ PhFindCharInStringRef
+ PhFindElementAvlTree
+ PhFindEntryHashtable
+ PhFindItemList
+ PhFindItemPointerList
+ PhFindItemSimpleHashtable
+ PhFindLastCharInStringRef
+ PhFindStringInStringRef
+ PhfInitializeBarrier
+ PhfInitializeEvent
+ PhfInitializeInitOnce
+ PhfInitializeRundownProtection
+ PhFormat
+ PhFormatString
+ PhFormatString_V
+ PhFormatToBuffer
+ PhFree
+ PhFreePage
+ PhFreeToFreeList
+ PhfReleaseRundownProtection
+ PhfResetEvent
+ PhfSetEvent
+ PhfWaitForBarrier
+ PhfWaitForEvent
+ PhfWaitForRundownProtection
+ PhGetPrimeNumber
+ PhHashBytes
+ PhHashStringRef
+ PhHexStringToBuffer
+ PhHexStringToBufferEx
+ PhInitializeArray
+ PhInitializeAvlTree
+ PhInitializeBytesBuilder
+ PhInitializeCallback
+ PhInitializeFreeList
+ PhInitializeStringBuilder
+ PhInsertItemList
+ PhInsertItemsList
+ PhInsertStringBuilder
+ PhInsertStringBuilder2
+ PhInsertStringBuilderEx
+ PhIntegerToString64
+ PhInvokeCallback
+ PhLoadIndirectString
+ PhLoadResource
+ PhLocalTimeToSystemTime
+ PhLowerBoundElementAvlTree
+ PhLowerDualBoundElementAvlTree
+ PhMaximumElementAvlTree
+ PhMinimumElementAvlTree
+ PhNtStatusFileNotFound
+ PhNtStatusToDosError
+ PhPredecessorElementAvlTree
+ PhPrintTimeSpan
+ PhQuerySystemTime
+ PhQueryTimeZoneBias
+ PhReAllocate
+ PhReAllocateSafe
+ PhReferenceEmptyString
+ PhRegisterCallback
+ PhRegisterCallbackEx
+ PhRemoveElementAvlTree
+ PhRemoveEntryHashtable
+ PhRemoveItemArray
+ PhRemoveItemList
+ PhRemoveItemPointerList
+ PhRemoveItemsArray
+ PhRemoveItemSimpleHashtable
+ PhRemoveItemsList
+ PhRemoveStringBuilder
+ PhResizeArray
+ PhResizeList
+ PhRoundUpToPowerOfTwo
+ PhSplitStringRefAtChar
+ PhSplitStringRefAtLastChar
+ PhSplitStringRefAtString
+ PhSplitStringRefEx
+ PhStringToDouble
+ PhStringToInteger64
+ PhSuccessorElementAvlTree
+ PhSystemTimeToLocalTime
+ PhTrimStringRef
+ PhUnregisterCallback
+ PhUpperBoundElementAvlTree
+ PhUpperDualBoundElementAvlTree
+ PhWriteUnicodeDecoder
+ PhZeroExtendToUtf16Buffer
+ PhZeroExtendToUtf16Ex
; phnative
- PhCreateFileWin32
- PhCreateFileWin32Ex
- PhCreateKey
- PhDeleteFileWin32
- PhDisconnectNamedPipe
- PhEnumDirectoryFile
- PhEnumDirectoryObjects
- PhEnumFileStreams
- PhEnumGenericModules
- PhEnumHandles
- PhEnumHandlesEx
- PhEnumKernelModules
- PhEnumPagefiles
- PhEnumProcessEnvironmentVariables
- PhEnumProcesses
- PhEnumProcessesEx
- PhEnumProcessesForSession
- PhEnumProcessModules
- PhEnumProcessModules32
- PhEnumProcessModules32Ex
- PhEnumProcessModulesEx
- PhFindProcessInformation
- PhFindProcessInformationByImageName
- PhGetFileName
- PhGetFileSize
- PhGetJobProcessIdList
- PhGetKernelFileName
- PhGetObjectSecurity
- PhGetOwnTokenAttributes
- PhGetProcedureAddressRemote
- PhGetProcessCommandLine
- PhGetProcessDepStatus
- PhGetProcessEnvironment
- PhGetProcessImageFileName
- PhGetProcessImageFileNameByProcessId
- PhGetProcessImageFileNameWin32
- PhGetProcessIsDotNet
- PhGetProcessIsDotNetEx
- PhGetProcessMappedFileName
- PhGetProcessPebString
- PhGetProcessWindowTitle
- PhGetProcessWorkingSetInformation
- PhGetProcessWsCounters
- PhGetTokenGroups
- PhGetTokenIntegrityLevel
- PhGetTokenOwner
- PhGetTokenPrimaryGroup
- PhGetTokenPrivileges
- PhGetTokenUser
- PhImpersonateClientOfNamedPipe
- PhInjectDllProcess
- PhListenNamedPipe
- PhOpenKey
- PhOpenProcess = PhOpenProcessPublic
- PhOpenThread = PhOpenThreadPublic
- PhOpenThreadProcess
- PhPeekNamedPipe
- PhQueryFullAttributesFileWin32
- PhQueryKey
- PhQueryValueKey
- PhResolveDevicePrefix
- PhSetFileSize
- PhSetObjectSecurity
- PhSetTokenIsVirtualizationEnabled
- PhSetTokenPrivilege
- PhSetTokenPrivilege2
- PhSetTokenSessionId
- PhTerminateProcess = PhTerminateProcessPublic
- PhTransceiveNamedPipe
- PhUnloadDllProcess
- PhUnloadDriver
- PhUpdateDosDevicePrefixes
- PhUpdateMupDevicePrefixes
- PhWaitForNamedPipe
+ PhCreateDirectory
+ PhCreateFileWin32
+ PhCreateFileWin32Ex
+ PhCreateKey
+ PhCreateNamedPipe
+ PhCreatePipe
+ PhConnectPipe
+ PhDeleteDirectory
+ PhDeleteFileWin32
+ PhDoesFileExistsWin32
+ PhDisconnectNamedPipe
+ PhEnumDirectoryFile
+ PhEnumDirectoryObjects
+ PhEnumFileStreams
+ PhEnumGenericModules
+ PhEnumHandles
+ PhEnumHandlesEx
+ PhEnumHandlesEx2
+ PhEnumKernelModules
+ PhEnumPagefiles
+ PhEnumProcessEnvironmentVariables
+ PhEnumProcesses
+ PhEnumProcessesEx
+ PhEnumProcessesForSession
+ PhEnumProcessModules
+ PhEnumProcessModules32
+ PhEnumProcessModules32Ex
+ PhEnumProcessModulesEx
+ PhFindProcessInformation
+ PhFindProcessInformationByImageName
+ PhGetFileName
+ PhGetFileSize
+ PhGetJobProcessIdList
+ PhGetKernelFileName
+ PhGetObjectSecurity
+ PhGetOwnTokenAttributes
+ PhGetDllHandle
+ PhGetModuleProcAddress
+ PhGetProcedureAddress
+ PhGetProcedureAddressRemote
+ PhGetProcessCommandLine
+ PhGetProcessDepStatus
+ PhGetProcessEnvironment
+ PhGetProcessImageFileName
+ PhGetProcessImageFileNameByProcessId
+ PhGetProcessImageFileNameWin32
+ PhGetProcessIsDotNet
+ PhGetProcessIsDotNetEx
+ PhGetProcessMappedFileName
+ PhGetProcessPebString
+ PhGetProcessUnloadedDlls
+ PhGetProcessWindowTitle
+ PhGetProcessWorkingSetInformation
+ PhGetProcessWsCounters
+ PhGetTokenGroups
+ PhGetTokenIntegrityLevelRID
+ PhGetTokenIntegrityLevel
+ PhGetTokenOwner
+ PhGetTokenPrimaryGroup
+ PhGetTokenPrivileges
+ PhGetTokenUser
+ PhImpersonateClientOfNamedPipe
+ PhListenNamedPipe
+ PhOpenKey
+ PhLoadAppKey
+ PhOpenProcess = PhOpenProcessPublic
+ PhOpenThread = PhOpenThreadPublic
+ PhOpenThreadProcess
+ PhOpenProcessToken = PhOpenProcessTokenPublic
+ PhPeekNamedPipe
+ PhQueryFullAttributesFileWin32
+ PhQueryKey
+ PhQueryValueKey
+ PhQueryTokenVariableSize
+ PhResolveDevicePrefix
+ PhSetFileSize
+ PhSetObjectSecurity
+ PhSetTokenIsVirtualizationEnabled
+ PhSetTokenPrivilege
+ PhSetTokenPrivilege2
+ PhSetTokenSessionId
+ PhTerminateProcess = PhTerminateProcessPublic
+ PhTransceiveNamedPipe
+ PhUnloadDllProcess
+ PhUnloadDriver
+ PhUpdateDosDevicePrefixes
+ PhUpdateMupDevicePrefixes
+ PhWaitForNamedPipe
; phutil
- PhAdjustRectangleToBounds
- PhAdjustRectangleToWorkingArea
- PhCenterRectangle
- PhCenterWindow
- PhCompareUnicodeStringZIgnoreMenuPrefix
- PhCreateOpenFileDialog
- PhCreateProcess
- PhCreateProcessAsUser
- PhCreateProcessWin32
- PhCreateProcessWin32Ex
- PhCreateSaveFileDialog
- PhDeleteImageVersionInfo
- PhDereferenceObjects
- PhEllipsisString
- PhEllipsisStringPath
- PhEscapeCommandLinePart
- PhEscapeStringForMenuPrefix
- PhExpandEnvironmentStrings
- PhFinalHash
- PhFindIntegerSiKeyValuePairs
- PhFindLoaderEntry
- PhFindStringSiKeyValuePairs
- PhFormatDate
- PhFormatDateTime
- PhFormatDecimal
- PhFormatGuid
- PhFormatImageVersionInfo
- PhFormatSize
- PhFormatTime
- PhFormatTimeSpan
- PhFormatTimeSpanRelative
- PhFormatUInt64
- PhFreeFileDialog
- PhGenerateGuid
- PhGenerateGuidFromName
- PhGenerateRandomAlphaString
- PhGetApplicationDirectory
- PhGetApplicationFileName
- PhGetBaseName
- PhGetDllFileName
- PhGetFileDialogFileName
- PhGetFileDialogFilterIndex
- PhGetFileDialogOptions
- PhGetFileVersionInfo
- PhGetFileVersionInfoLangCodePage
- PhGetFileVersionInfoString
- PhGetFileVersionInfoString2
- PhGetFullPath
- PhGetKnownLocation
- PhGetMessage
- PhGetNtMessage
- PhGetSystemDirectory
- PhGetSystemRoot
- PhGetWin32Message
- PhInitializeHash
- PhInitializeImageVersionInfo
- PhIsExecutablePacked
- PhMapFlags1
- PhMapFlags2
- PhMatchWildcards
- PhParseCommandLine
- PhParseCommandLineFuzzy
- PhParseCommandLinePart
- PhQueryRegistryString
- PhReferenceObjects
- PhSetFileDialogFileName
- PhSetFileDialogFilter
- PhSetFileDialogOptions
- PhShellExecute
- PhShellExecuteEx
- PhShellExploreFile
- PhShellOpenKey
- PhShellProperties
- PhShowConfirmMessage
- PhShowContinueStatus
- PhShowFileDialog
- PhShowMessage
- PhShowMessage_V
- PhShowStatus
- PhUpdateHash
+ PhAdjustRectangleToBounds
+ PhAdjustRectangleToWorkingArea
+ PhCenterRectangle
+ PhCenterWindow
+ PhCompareUnicodeStringZIgnoreMenuPrefix
+ PhCreateOpenFileDialog
+ PhCreateProcess
+ PhCreateProcessAsUser
+ PhCreateProcessWin32
+ PhCreateProcessWin32Ex
+ PhCreateSaveFileDialog
+ PhDeleteImageVersionInfo
+ PhDereferenceObjects
+ PhEllipsisString
+ PhEllipsisStringPath
+ PhEscapeCommandLinePart
+ PhEscapeStringForMenuPrefix
+ PhExpandEnvironmentStrings
+ PhFinalHash
+ PhFindIntegerSiKeyValuePairs
+ PhFindLoaderEntry
+ PhFindStringSiKeyValuePairs
+ PhFormatDate
+ PhFormatDateTime
+ PhFormatDecimal
+ PhFormatGuid
+ PhFormatImageVersionInfo
+ PhFormatSize
+ PhFormatTime
+ PhFormatTimeSpan
+ PhFormatTimeSpanRelative
+ PhFormatUInt64
+ PhFreeFileDialog
+ PhGenerateGuid
+ PhGenerateGuidFromName
+ PhGenerateRandomAlphaString
+ PhGetApplicationDirectory
+ PhGetApplicationFileName
+ PhGetBaseDirectory
+ PhGetBaseName
+ PhGetDllFileName
+ PhGetFileDialogFileName
+ PhGetFileDialogFilterIndex
+ PhGetFileDialogOptions
+ PhGetFileVersionInfo
+ PhGetFileVersionInfoLangCodePage
+ PhGetFileVersionInfoString
+ PhGetFileVersionInfoString2
+ PhGetFullPath
+ PhGetKnownLocation
+ PhGetMessage
+ PhGetNtMessage
+ PhGetStatusMessage
+ PhGetSystemDirectory
+ PhGetSystemRoot
+ PhGetWin32Message
+ PhInitializeHash
+ PhInitializeImageVersionInfo
+ PhIsExecutablePacked
+ PhMapFlags1
+ PhMapFlags2
+ PhMatchWildcards
+ PhParseCommandLine
+ PhParseCommandLineFuzzy
+ PhParseCommandLinePart
+ PhQueryRegistryString
+ PhQueryRegistryUlong
+ PhQueryRegistryUlong64
+ PhReferenceObjects
+ PhSetFileDialogFileName
+ PhSetFileDialogFilter
+ PhSetFileDialogOptions
+ PhShellExecute
+ PhShellExecuteEx
+ PhShellExploreFile
+ PhShellOpenKey
+ PhShellProperties
+ PhShowConfirmMessage
+ PhShowContinueStatus
+ PhShowFileDialog
+ PhShowMessage
+ PhShowMessage2
+ PhShowStatus
+ PhUpdateHash
; circbuf
- PhClearCircularBuffer_FLOAT
- PhClearCircularBuffer_PVOID
- PhClearCircularBuffer_ULONG
- PhClearCircularBuffer_ULONG64
- PhCopyCircularBuffer_FLOAT
- PhCopyCircularBuffer_PVOID
- PhCopyCircularBuffer_ULONG
- PhCopyCircularBuffer_ULONG64
- PhDeleteCircularBuffer_FLOAT
- PhDeleteCircularBuffer_PVOID
- PhDeleteCircularBuffer_ULONG
- PhDeleteCircularBuffer_ULONG64
- PhInitializeCircularBuffer_FLOAT
- PhInitializeCircularBuffer_PVOID
- PhInitializeCircularBuffer_ULONG
- PhInitializeCircularBuffer_ULONG64
- PhResizeCircularBuffer_FLOAT
- PhResizeCircularBuffer_PVOID
- PhResizeCircularBuffer_ULONG
- PhResizeCircularBuffer_ULONG64
+ PhClearCircularBuffer_FLOAT
+ PhClearCircularBuffer_PVOID
+ PhClearCircularBuffer_ULONG
+ PhClearCircularBuffer_ULONG64
+ PhCopyCircularBuffer_FLOAT
+ PhCopyCircularBuffer_PVOID
+ PhCopyCircularBuffer_ULONG
+ PhCopyCircularBuffer_ULONG64
+ PhDeleteCircularBuffer_FLOAT
+ PhDeleteCircularBuffer_PVOID
+ PhDeleteCircularBuffer_ULONG
+ PhDeleteCircularBuffer_ULONG64
+ PhInitializeCircularBuffer_FLOAT
+ PhInitializeCircularBuffer_PVOID
+ PhInitializeCircularBuffer_ULONG
+ PhInitializeCircularBuffer_ULONG64
+ PhResizeCircularBuffer_FLOAT
+ PhResizeCircularBuffer_PVOID
+ PhResizeCircularBuffer_ULONG
+ PhResizeCircularBuffer_ULONG64
; cpysave
- PhGetGenericTreeNewLines
- PhGetTreeNewText
+ PhGetGenericTreeNewLines
+ PhGetTreeNewText
; emenu
- PhCreateEMenu
- PhCreateEMenuItem
- PhDestroyEMenu
- PhDestroyEMenuItem
- PhFindEMenuItem
- PhIndexOfEMenuItem
- PhInsertEMenuItem
- PhLoadResourceEMenuItem
- PhModifyEMenuItem
- PhRemoveAllEMenuItems
- PhRemoveEMenuItem
- PhSetFlagsAllEMenuItems
- PhSetFlagsEMenuItem
- PhShowEMenu
+ PhCreateEMenu
+ PhCreateEMenuItem
+ PhDestroyEMenu
+ PhDestroyEMenuItem
+ PhFindEMenuItem
+ PhIndexOfEMenuItem
+ PhInsertEMenuItem
+ PhLoadResourceEMenuItem
+ PhModifyEMenuItem
+ PhRemoveAllEMenuItems
+ PhRemoveEMenuItem
+ PhSetFlagsAllEMenuItems
+ PhSetFlagsEMenuItem
+ PhShowEMenu
; fastlock
- PhDeleteFastLock
- PhfAcquireFastLockExclusive
- PhfAcquireFastLockShared
- PhfReleaseFastLockExclusive
- PhfReleaseFastLockShared
- PhfTryAcquireFastLockExclusive
- PhfTryAcquireFastLockShared
- PhInitializeFastLock
+ PhDeleteFastLock
+ PhfAcquireFastLockExclusive
+ PhfAcquireFastLockShared
+ PhfReleaseFastLockExclusive
+ PhfReleaseFastLockShared
+ PhfTryAcquireFastLockExclusive
+ PhfTryAcquireFastLockShared
+ PhInitializeFastLock
; filestream
- PhCreateFileStream
- PhCreateFileStream2
- PhFlushFileStream
- PhGetPositionFileStream
- PhLockFileStream
- PhReadFileStream
- PhSeekFileStream
- PhUnlockFileStream
- PhVerifyFileStream
- PhWriteFileStream
- PhWriteStringAsUtf8FileStream
- PhWriteStringAsUtf8FileStream2
- PhWriteStringAsUtf8FileStreamEx
- PhWriteStringFormatAsUtf8FileStream
- PhWriteStringFormatAsUtf8FileStream_V
+ PhCreateFileStream
+ PhCreateFileStream2
+ PhFlushFileStream
+ PhGetPositionFileStream
+ PhLockFileStream
+ PhReadFileStream
+ PhSeekFileStream
+ PhUnlockFileStream
+ PhVerifyFileStream
+ PhWriteFileStream
+ PhWriteStringAsUtf8FileStream
+ PhWriteStringAsUtf8FileStream2
+ PhWriteStringAsUtf8FileStreamEx
+ PhWriteStringFormatAsUtf8FileStream
+ PhWriteStringFormatAsUtf8FileStream_V
; graph
- PhDeleteGraphState
- PhDrawGraphDirect
- PhGetDrawInfoGraphBuffers
- PhGraphStateGetDrawInfo
- PhInitializeGraphState
- PhSetGraphText
+ PhDeleteGraphState
+ PhDrawGraphDirect
+ PhDrawTrayIconText
+ PhGetDrawInfoGraphBuffers
+ PhGraphStateGetDrawInfo
+ PhInitializeGraphState
+ PhSetGraphText
; guisup
- PhAddComboBoxStrings
- PhAddLayoutItem
- PhAddLayoutItemEx
- PhAddListViewColumn
- PhAddListViewItem
- PhAddTabControlTab
- PhDeleteLayoutManager
- PhFindListViewItemByFlags
- PhFindListViewItemByParam
- PhGetComboBoxString
- PhGetFileShellIcon
- PhGetListBoxString
- PhGetListViewItemImageIndex
- PhGetListViewItemParam
- PhGetSelectedListViewItemParam
- PhGetSelectedListViewItemParams
- PhGetStockApplicationIcon
- PhGetWindowText
- PhGetWindowTextEx
- PhIconToBitmap
- PhInitializeLayoutManager
- PhLayoutManagerLayout
- PhLoadIcon
- PhLoadListViewColumnSettings
- PhModalPropertySheet
- PhRemoveListViewItem
- PhSaveListViewColumnSettings
- PhSelectComboBoxString
- PhSetClipboardString
- PhSetControlTheme
- PhSetExtendedListView
- PhSetHeaderSortIcon
- PhSetImageListBitmap
- PhSetListViewItemImageIndex
- PhSetListViewSubItem
- PhSetStateAllListViewItems
+ PhAddComboBoxStrings
+ PhAddLayoutItem
+ PhAddLayoutItemEx
+ PhAddListViewColumn
+ PhAddListViewItem
+ PhAddTabControlTab
+ PhDeleteLayoutManager
+ PhFindListViewItemByFlags
+ PhFindListViewItemByParam
+ PhGetComboBoxString
+ PhGetFileShellIcon
+ PhGetListBoxString
+ PhGetListViewItemImageIndex
+ PhGetListViewItemParam
+ PhGetSelectedListViewItemParam
+ PhGetSelectedListViewItemParams
+ PhGetStockApplicationIcon
+ PhGetWindowText
+ PhGetWindowTextEx
+ PhIconToBitmap
+ PhInitializeLayoutManager
+ PhLayoutManagerLayout
+ PhLoadIcon
+ PhLoadListViewColumnSettings
+ PhModalPropertySheet
+ PhRemoveListViewItem
+ PhSaveListViewColumnSettings
+ PhSelectComboBoxString
+ PhSetClipboardString
+ PhSetControlTheme
+ PhSetExtendedListView
+ PhSetHeaderSortIcon
+ PhSetImageListBitmap
+ PhSetListViewItemImageIndex
+ PhSetListViewSubItem
+ PhAddListViewGroup
+ PhAddListViewGroupItem
+ PhSetStateAllListViewItems
+ PhGetWindowContext
+ PhSetWindowContext
+ PhRemoveWindowContext
+ PhGetDialogItemValue
+ PhSetDialogItemValue
+ PhSetDialogItemText
+ PhSetWindowText
+ PhApplicationFont
+ PhTreeWindowFont
+ PhRegisterWindowCallback
+ PhUnregisterWindowCallback
+ PhInitializeWindowTheme
+ PhReInitializeWindowTheme
+ PhInitializeWindowThemeStatusBar
+ PhGetGlobalTimerQueue
; hndlinfo
- PhEnumObjectTypes
- PhFormatNativeKeyName
- PhGetHandleInformation
- PhGetHandleInformationEx
- PhStdGetClientIdName
+ PhEnumObjectTypes
+ PhFormatNativeKeyName
+ PhGetHandleInformation
+ PhGetHandleInformationEx
+ PhStdGetClientIdName
; lsasup
- PhGetSidFullName
- PhLookupName
- PhLookupPrivilegeDisplayName
- PhLookupPrivilegeName
- PhLookupPrivilegeValue
- PhLookupSid
- PhOpenLsaPolicy
- PhSidToStringSid
+ PhGetSidFullName
+ PhLookupName
+ PhLookupPrivilegeDisplayName
+ PhLookupPrivilegeName
+ PhLookupPrivilegeValue
+ PhLookupSid
+ PhOpenLsaPolicy
+ PhSidToStringSid
; mapimg
- PhGetMappedImageCfg
- PhGetMappedImageCfgEntry
- PhGetMappedImageLoadConfig32
- PhGetMappedImageLoadConfig64
- PhInitializeMappedImage
- PhLoadMappedImage
+ PhGetMappedImageCfg
+ PhGetMappedImageCfgEntry
+ PhGetMappedImageLoadConfig32
+ PhGetMappedImageLoadConfig64
+ PhGetMappedImageExports
+ PhGetMappedImageExportFunction
+ PhMappedImageRvaToVa
+ PhInitializeMappedImage
+ PhLoadMappedImage
+ PhLoadMappedImageEx
+ PhUnloadMappedImage
+
+; settings
+ PhAddSetting
+ PhAddSettings
+ PhClearIgnoredSettings
+ PhConvertIgnoredSettings
+ PhGetIntegerSetting
+ PhGetIntegerPairSetting
+ PhGetScalableIntegerPairSetting
+ PhGetStringSetting
+ PhLoadSettings
+ PhLoadListViewColumnSettings
+ PhLoadListViewColumnsFromSetting
+ PhLoadListViewSortColumnsFromSetting
+ PhLoadListViewGroupStatesFromSetting
+ PhLoadWindowPlacementFromSetting
+ PhResetSettings
+ PhSaveListViewColumnSettings
+ PhSaveListViewColumnsToSetting
+ PhSaveListViewSortColumnsToSetting
+ PhSaveListViewGroupStatesToSetting
+ PhSaveWindowPlacementToSetting
+ PhSettingsInitialization
+ PhSetIntegerSetting
+ PhSetIntegerPairSetting
+ PhSetScalableIntegerPairSetting
+ PhSetScalableIntegerPairSetting2
+ PhSetStringSetting
+ PhSetStringSetting2
+ PhSaveSettings
+ PhUpdateCachedSettings
; secedit
- PhCreateSecurityPage
- PhEditSecurity
- PhGetAccessEntries
- PhGetAccessString
- PhGetSeObjectSecurity
- PhSetSeObjectSecurity
- PhStdGetObjectSecurity
- PhStdSetObjectSecurity
+ PhCreateSecurityPage
+ PhEditSecurity
+ PhGetAccessEntries
+ PhGetAccessString
+ PhGetSeObjectSecurity
+ PhSetSeObjectSecurity
+ PhStdGetObjectSecurity
+ PhStdSetObjectSecurity
; svcsup
- PhEnumServices
- PhGetServiceConfig
- PhGetServiceDelayedAutoStart
- PhGetServiceDescription
- PhGetServiceDllParameter
- PhGetServiceErrorControlInteger
- PhGetServiceErrorControlString
- PhGetServiceNameFromTag
- PhGetServiceStartTypeInteger
- PhGetServiceStartTypeString
- PhGetServiceStateString
- PhGetServiceTypeInteger
- PhGetServiceTypeString
- PhGetThreadServiceTag
- PhOpenService
- PhQueryServiceVariableSize
- PhSetServiceDelayedAutoStart
+ PhEnumServices
+ PhGetServiceConfig
+ PhGetServiceDelayedAutoStart
+ PhGetServiceDescription
+ PhGetServiceDllParameter
+ PhGetServiceErrorControlInteger
+ PhGetServiceErrorControlString
+ PhGetServiceNameFromTag
+ PhGetServiceStartTypeInteger
+ PhGetServiceStartTypeString
+ PhGetServiceStateString
+ PhGetServiceTypeInteger
+ PhGetServiceTypeString
+ PhGetThreadServiceTag
+ PhOpenService
+ PhQueryServiceVariableSize
+ PhSetServiceDelayedAutoStart
; symprv
- PhCreateSymbolProvider
- PhGetLineFromAddress
- PhGetModuleFromAddress
- PhGetSymbolFromAddress
- PhGetSymbolFromName
- PhLoadModuleSymbolProvider
- PhSetOptionsSymbolProvider
- PhSetSearchPathSymbolProvider
- PhStackWalk
- PhWalkThreadStack
- PhWriteMiniDumpProcess
+ PhCreateSymbolProvider
+ PhGetLineFromAddress
+ PhGetModuleFromAddress
+ PhGetSymbolFromAddress
+ PhGetSymbolFromName
+ PhLoadModuleSymbolProvider
+ PhSetOptionsSymbolProvider
+ PhSetSearchPathSymbolProvider
+ PhStackWalk
+ PhWalkThreadStack
+ PhWriteMiniDumpProcess
; verify
- PhVerifyFile
+ PhVerifyFile
; workqueue
- PhDeleteWorkQueue
- PhGetGlobalWorkQueue
- PhInitializeWorkQueue
- PhInitializeWorkQueueEnvironment
- PhQueueItemWorkQueue
- PhQueueItemWorkQueueEx
- PhWaitForWorkQueue
+ PhDeleteWorkQueue
+ PhGetGlobalWorkQueue
+ PhInitializeWorkQueue
+ PhInitializeWorkQueueEnvironment
+ PhQueueItemWorkQueue
+ PhQueueItemWorkQueueEx
+ PhWaitForWorkQueue
+
+; mxml
+ mxmlDelete
+ mxmlElementGetAttrCount
+ mxmlElementGetAttrByIndex
+ mxmlElementSetAttr
+ mxmlGetFirstChild
+ mxmlGetNextSibling
+ mxmlGetOpaque
+ mxmlGetType
+ mxmlLoadFd
+ mxmlNewOpaque
+ mxmlNewElement
+ mxmlSaveFd
+ mxml_opaque_cb
+
+; json
+ PhCreateJsonParser
+ PhFreeJsonParser
+ PhGetJsonValueAsString
+ PhGetJsonValueAsLong64
+ PhCreateJsonObject
+ PhGetJsonObject
+ PhGetJsonObjectLength
+ PhGetJsonObjectBool
+ PhAddJsonObject
+ PhGetJsonObjectAsArrayList
+ PhCreateJsonArray
+ PhAddJsonArrayObject
+ PhGetJsonArrayString
+ PhGetJsonArrayLong64
+ PhGetJsonArrayLength
+ PhGetJsonArrayIndexObject
+
+; cache
+ PhCreateCacheFile
+ PhClearCacheDirectory
+ PhDeleteCacheFile
+
+; appresolver
+ PhAppResolverGetAppIdForWindow
diff --git a/ProcessHacker/ProcessHacker.manifest b/ProcessHacker/ProcessHacker.manifest
index 3bc4a2568dd8..1a214566dc7e 100644
--- a/ProcessHacker/ProcessHacker.manifest
+++ b/ProcessHacker/ProcessHacker.manifest
@@ -1,49 +1,49 @@
-
-
-
- Process Hacker
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- true
-
-
- true
-
-
- true
-
-
+
+
+
+ Process Hacker
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ true
+
+
+ true
+
+
\ No newline at end of file
diff --git a/ProcessHacker/ProcessHacker.rc b/ProcessHacker/ProcessHacker.rc
index 1fdef831b78a..33a08b00949b 100644
--- a/ProcessHacker/ProcessHacker.rc
+++ b/ProcessHacker/ProcessHacker.rc
@@ -1,2607 +1,2371 @@
-// Microsoft Visual C++ generated resource script.
-//
-#include "resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#include "winres.h"
-#include "include/phappres.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""\r\n"
- "#include ""include/phappres.h""\0"
-END
-
-3 TEXTINCLUDE
-BEGIN
- "\r\n"
- "\0"
-END
-
-#endif // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Icon
-//
-
-// Icon with lowest ID value placed first to ensure application icon
-// remains consistent on all systems.
-IDI_PROCESSHACKER ICON "ProcessHacker.ico"
-
-IDI_PHAPPLICATION ICON "resources\\application.ico"
-
-IDI_COG ICON "resources\\cog.ico"
-
-IDI_PHAPPLICATIONGO ICON "resources\\application_go.ico"
-
-IDI_COGGO ICON "resources\\cog_go.ico"
-
-IDI_PIN ICON "resources\\pin.ico"
-
-IDI_FOLDER ICON "resources\\folder.ico"
-
-IDI_PENCIL ICON "resources\\pencil.ico"
-
-IDI_MAGNIFIER ICON "resources\\magnifier.ico"
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Menu
-//
-
-IDR_MAINWND MENU
-BEGIN
- POPUP "&Hacker"
- BEGIN
- MENUITEM "&Run...\aCtrl+R", ID_HACKER_RUN
- MENUITEM "Run as administrator...", ID_HACKER_RUNASADMINISTRATOR
- MENUITEM "Run as &limited user...", ID_HACKER_RUNASLIMITEDUSER
- MENUITEM "Run &as...\aCtrl+Shift+R", ID_HACKER_RUNAS
- MENUITEM "Show &details for all processes", ID_HACKER_SHOWDETAILSFORALLPROCESSES
- MENUITEM SEPARATOR
- MENUITEM "&Save...\aCtrl+S", ID_HACKER_SAVE
- MENUITEM "&Find handles or DLLs...\aCtrl+F", ID_HACKER_FINDHANDLESORDLLS
- MENUITEM "&Options...", ID_HACKER_OPTIONS
- MENUITEM "&Plugins...", ID_HACKER_PLUGINS
- MENUITEM SEPARATOR
- POPUP "&Computer"
- BEGIN
- MENUITEM "&Lock", ID_COMPUTER_LOCK
- MENUITEM "Log o&ff", ID_COMPUTER_LOGOFF
- MENUITEM SEPARATOR
- MENUITEM "&Sleep", ID_COMPUTER_SLEEP
- MENUITEM "&Hibernate", ID_COMPUTER_HIBERNATE
- MENUITEM SEPARATOR
- MENUITEM "R&estart", ID_COMPUTER_RESTART
- MENUITEM "Restart to boot options", ID_COMPUTER_RESTARTBOOTOPTIONS
- MENUITEM "Shu&t down", ID_COMPUTER_SHUTDOWN
- MENUITEM "H&ybrid shut down", ID_COMPUTER_SHUTDOWNHYBRID
- END
- MENUITEM "E&xit", ID_HACKER_EXIT
- END
- POPUP "&View"
- BEGIN
- MENUITEM "System &information\aCtrl+I", ID_VIEW_SYSTEMINFORMATION
- POPUP "&Tray icons"
- BEGIN
- MENUITEM "CPU history", ID_TRAYICONS_CPUHISTORY
- MENUITEM "CPU usage", ID_TRAYICONS_CPUUSAGE
- MENUITEM "I/O history", ID_TRAYICONS_IOHISTORY
- MENUITEM "Commit charge history", ID_TRAYICONS_COMMITHISTORY
- MENUITEM "Physical memory history", ID_TRAYICONS_PHYSICALMEMORYHISTORY
- END
- MENUITEM SEPARATOR
- MENUITEM "", ID_VIEW_SECTIONPLACEHOLDER
- MENUITEM SEPARATOR
- MENUITEM "&Always on top", ID_VIEW_ALWAYSONTOP
- POPUP "&Opacity"
- BEGIN
- MENUITEM "10%", ID_OPACITY_10
- MENUITEM "20%", ID_OPACITY_20
- MENUITEM "30%", ID_OPACITY_30
- MENUITEM "40%", ID_OPACITY_40
- MENUITEM "50%", ID_OPACITY_50
- MENUITEM "60%", ID_OPACITY_60
- MENUITEM "70%", ID_OPACITY_70
- MENUITEM "80%", ID_OPACITY_80
- MENUITEM "90%", ID_OPACITY_90
- MENUITEM "Opaque", ID_OPACITY_OPAQUE
- END
- MENUITEM SEPARATOR
- MENUITEM "&Refresh\aF5", ID_VIEW_REFRESH
- POPUP "Refresh i&nterval"
- BEGIN
- MENUITEM "Fast (0.5s)", ID_UPDATEINTERVAL_FAST
- MENUITEM "Normal (1s)", ID_UPDATEINTERVAL_NORMAL
- MENUITEM "Below normal (2s)", ID_UPDATEINTERVAL_BELOWNORMAL
- MENUITEM "Slow (5s)", ID_UPDATEINTERVAL_SLOW
- MENUITEM "Very slow (10s)", ID_UPDATEINTERVAL_VERYSLOW
- END
- MENUITEM "Refresh a&utomatically\aF6", ID_VIEW_UPDATEAUTOMATICALLY
- END
- POPUP "&Tools"
- BEGIN
- MENUITEM "Create service...", ID_TOOLS_CREATESERVICE
- MENUITEM "Hidden processes", ID_TOOLS_HIDDENPROCESSES
- MENUITEM "Inspect executable file...", ID_TOOLS_INSPECTEXECUTABLEFILE
- MENUITEM "Pagefiles", ID_TOOLS_PAGEFILES
- MENUITEM "Start Task Manager", ID_TOOLS_STARTTASKMANAGER
- END
- POPUP "&Users"
- BEGIN
- MENUITEM "Dummy", ID_USERS_DUMMY
- END
- POPUP "H&elp"
- BEGIN
- MENUITEM "&Log\aCtrl+L", ID_HELP_LOG
- MENUITEM "&Donate", ID_HELP_DONATE
- MENUITEM "Debu&g console", ID_HELP_DEBUGCONSOLE
- MENUITEM "&About", ID_HELP_ABOUT
- END
-END
-
-IDR_THREAD MENU
-BEGIN
- POPUP "Thread"
- BEGIN
- MENUITEM "&Inspect\aEnter", ID_THREAD_INSPECT
- MENUITEM "T&erminate\aDel", ID_THREAD_TERMINATE
- MENUITEM "&Suspend", ID_THREAD_SUSPEND
- MENUITEM "Res&ume", ID_THREAD_RESUME
- MENUITEM SEPARATOR
- MENUITEM "&Affinity", ID_THREAD_AFFINITY
- MENUITEM "Per&missions", ID_THREAD_PERMISSIONS
- MENUITEM "&Token", ID_THREAD_TOKEN
- POPUP "Analy&ze"
- BEGIN
- MENUITEM "Wait", ID_ANALYZE_WAIT
- END
- POPUP "&Priority"
- BEGIN
- MENUITEM "Time critical", ID_PRIORITY_TIMECRITICAL
- MENUITEM "Highest", ID_PRIORITY_HIGHEST
- MENUITEM "Above normal", ID_PRIORITY_ABOVENORMAL
- MENUITEM "Normal", ID_PRIORITY_NORMAL
- MENUITEM "Below normal", ID_PRIORITY_BELOWNORMAL
- MENUITEM "Lowest", ID_PRIORITY_LOWEST
- MENUITEM "Idle", ID_PRIORITY_IDLE
- END
- POPUP "I/O priority"
- BEGIN
- MENUITEM "High", ID_IOPRIORITY_HIGH
- MENUITEM "Normal", ID_IOPRIORITY_NORMAL
- MENUITEM "Low", ID_IOPRIORITY_LOW
- MENUITEM "Very low", ID_IOPRIORITY_VERYLOW
- END
- POPUP "Page priority"
- BEGIN
- MENUITEM "Normal", ID_PAGEPRIORITY_NORMAL
- MENUITEM "Below normal", ID_PAGEPRIORITY_BELOWNORMAL
- MENUITEM "Medium", ID_PAGEPRIORITY_MEDIUM
- MENUITEM "Low", ID_PAGEPRIORITY_LOW
- MENUITEM "Very low", ID_PAGEPRIORITY_VERYLOW
- END
- MENUITEM SEPARATOR
- MENUITEM "&Copy\aCtrl+C", ID_THREAD_COPY
- END
-END
-
-IDR_HANDLE MENU
-BEGIN
- POPUP "Handle"
- BEGIN
- MENUITEM "C&lose\aDel", ID_HANDLE_CLOSE
- MENUITEM "&Protected", ID_HANDLE_PROTECTED
- MENUITEM "&Inherit", ID_HANDLE_INHERIT
- MENUITEM SEPARATOR
- MENUITEM "&Copy\aCtrl+C", ID_HANDLE_COPY
- MENUITEM "Prope&rties\aEnter", ID_HANDLE_PROPERTIES
- END
-END
-
-IDR_MODULE MENU
-BEGIN
- POPUP "Module"
- BEGIN
- MENUITEM "&Unload\aDel", ID_MODULE_UNLOAD
- MENUITEM SEPARATOR
- MENUITEM "&Inspect\aEnter", ID_MODULE_INSPECT
- MENUITEM "&Search online\aCtrl+M", ID_MODULE_SEARCHONLINE
- MENUITEM "Open &file location\aCtrl+Enter", ID_MODULE_OPENFILELOCATION
- MENUITEM "P&roperties", ID_MODULE_PROPERTIES
- MENUITEM "&Copy\aCtrl+C", ID_MODULE_COPY
- END
-END
-
-IDR_COMPUTER MENU
-BEGIN
- POPUP "Computer"
- BEGIN
- MENUITEM "&Lock", ID_COMPUTER_LOCK
- MENUITEM "Log o&ff", ID_COMPUTER_LOGOFF
- MENUITEM SEPARATOR
- MENUITEM "&Sleep", ID_COMPUTER_SLEEP
- MENUITEM "&Hibernate", ID_COMPUTER_HIBERNATE
- MENUITEM SEPARATOR
- MENUITEM "R&estart", ID_COMPUTER_RESTART
- MENUITEM "Restart to boot &options", ID_COMPUTER_RESTARTBOOTOPTIONS
- MENUITEM "Shu&t down", ID_COMPUTER_SHUTDOWN
- MENUITEM "H&ybrid shut down", ID_COMPUTER_SHUTDOWNHYBRID
- END
-END
-
-IDR_PROCESS MENU
-BEGIN
- POPUP "Process"
- BEGIN
- MENUITEM "T&erminate\aDel", ID_PROCESS_TERMINATE
- MENUITEM "Terminate tree\aShift+Del", ID_PROCESS_TERMINATETREE
- MENUITEM "&Suspend", ID_PROCESS_SUSPEND
- MENUITEM "Res&ume", ID_PROCESS_RESUME
- MENUITEM "Res&tart", ID_PROCESS_RESTART
- MENUITEM SEPARATOR
- MENUITEM "Create dump file...", ID_PROCESS_CREATEDUMPFILE
- MENUITEM "Debug", ID_PROCESS_DEBUG
- MENUITEM "Virtualization", ID_PROCESS_VIRTUALIZATION
- MENUITEM SEPARATOR
- MENUITEM "&Affinity", ID_PROCESS_AFFINITY
- POPUP "&Priority"
- BEGIN
- MENUITEM "Real time", ID_PRIORITY_REALTIME
- MENUITEM "High", ID_PRIORITY_HIGH
- MENUITEM "Above normal", ID_PRIORITY_ABOVENORMAL
- MENUITEM "Normal", ID_PRIORITY_NORMAL
- MENUITEM "Below normal", ID_PRIORITY_BELOWNORMAL
- MENUITEM "Idle", ID_PRIORITY_IDLE
- END
- POPUP "&I/O priority"
- BEGIN
- MENUITEM "High", ID_IOPRIORITY_HIGH
- MENUITEM "Normal", ID_IOPRIORITY_NORMAL
- MENUITEM "Low", ID_IOPRIORITY_LOW
- MENUITEM "Very low", ID_IOPRIORITY_VERYLOW
- END
- POPUP "&Miscellaneous"
- BEGIN
- MENUITEM "Detach from debugger", ID_MISCELLANEOUS_DETACHFROMDEBUGGER
- MENUITEM "GDI handles", ID_MISCELLANEOUS_GDIHANDLES
- MENUITEM "Inject DLL...", ID_MISCELLANEOUS_INJECTDLL
- POPUP "Page priority"
- BEGIN
- MENUITEM "Normal", ID_PAGEPRIORITY_NORMAL
- MENUITEM "Below normal", ID_PAGEPRIORITY_BELOWNORMAL
- MENUITEM "Medium", ID_PAGEPRIORITY_MEDIUM
- MENUITEM "Low", ID_PAGEPRIORITY_LOW
- MENUITEM "Very low", ID_PAGEPRIORITY_VERYLOW
- END
- MENUITEM "Reduce working set", ID_MISCELLANEOUS_REDUCEWORKINGSET
- MENUITEM "Run as...", ID_MISCELLANEOUS_RUNAS
- MENUITEM "Run as this user...", ID_MISCELLANEOUS_RUNASTHISUSER
- END
- POPUP "&Window"
- BEGIN
- MENUITEM "Bring to front", ID_WINDOW_BRINGTOFRONT
- MENUITEM "Restore", ID_WINDOW_RESTORE
- MENUITEM "Minimize", ID_WINDOW_MINIMIZE
- MENUITEM "Maximize", ID_WINDOW_MAXIMIZE
- MENUITEM SEPARATOR
- MENUITEM "Close", ID_WINDOW_CLOSE
- END
- MENUITEM SEPARATOR
- MENUITEM "Search online\aCtrl+M", ID_PROCESS_SEARCHONLINE
- MENUITEM "Open &file location\aCtrl+Enter", ID_PROCESS_OPENFILELOCATION
- MENUITEM "P&roperties\aEnter", ID_PROCESS_PROPERTIES
- MENUITEM "&Copy\aCtrl+C", ID_PROCESS_COPY
- END
-END
-
-IDR_SERVICE MENU
-BEGIN
- POPUP "Service"
- BEGIN
- MENUITEM "&Go to process", ID_SERVICE_GOTOPROCESS
- MENUITEM "&Start", ID_SERVICE_START
- MENUITEM "C&ontinue", ID_SERVICE_CONTINUE
- MENUITEM "&Pause", ID_SERVICE_PAUSE
- MENUITEM "S&top", ID_SERVICE_STOP
- MENUITEM "&Delete\aDel", ID_SERVICE_DELETE
- MENUITEM SEPARATOR
- MENUITEM "Open &key", ID_SERVICE_OPENKEY
- MENUITEM "Open &file location\aCtrl+Enter", ID_SERVICE_OPENFILELOCATION
- MENUITEM "P&roperties\aEnter", ID_SERVICE_PROPERTIES
- MENUITEM "&Copy\aCtrl+C", ID_SERVICE_COPY
- END
-END
-
-IDR_PRIVILEGE MENU
-BEGIN
- POPUP "Privilege"
- BEGIN
- MENUITEM "&Enable", ID_PRIVILEGE_ENABLE
- MENUITEM "&Disable", ID_PRIVILEGE_DISABLE
- MENUITEM "&Remove", ID_PRIVILEGE_REMOVE
- MENUITEM SEPARATOR
- MENUITEM "&Copy\aCtrl+C", ID_PRIVILEGE_COPY
- END
-END
-
-IDR_FINDOBJ MENU
-BEGIN
- POPUP "Object"
- BEGIN
- MENUITEM "C&lose\aDel", ID_OBJECT_CLOSE
- MENUITEM SEPARATOR
- MENUITEM "Go to owning &process", ID_OBJECT_GOTOOWNINGPROCESS
- MENUITEM "Prope&rties", ID_OBJECT_PROPERTIES
- MENUITEM "&Copy\aCtrl+C", ID_OBJECT_COPY
- END
-END
-
-IDR_USER MENU
-BEGIN
- POPUP "User"
- BEGIN
- MENUITEM "&Connect", ID_USER_CONNECT
- MENUITEM "&Disconnect", ID_USER_DISCONNECT
- MENUITEM "&Logoff", ID_USER_LOGOFF
- MENUITEM "Rem&ote control", ID_USER_REMOTECONTROL
- MENUITEM "Send &message...", ID_USER_SENDMESSAGE
- MENUITEM "P&roperties", ID_USER_PROPERTIES
- END
-END
-
-IDR_NETWORK MENU
-BEGIN
- POPUP "Network"
- BEGIN
- MENUITEM "&Go to process\aEnter", ID_NETWORK_GOTOPROCESS
- MENUITEM "Go to service", ID_NETWORK_GOTOSERVICE
- MENUITEM "View &stack", ID_NETWORK_VIEWSTACK
- MENUITEM "C&lose", ID_NETWORK_CLOSE
- MENUITEM SEPARATOR
- MENUITEM "&Copy\aCtrl+C", ID_NETWORK_COPY
- END
-END
-
-IDR_ICON MENU
-BEGIN
- POPUP "Icon"
- BEGIN
- MENUITEM "&Show/Hide Process Hacker", ID_ICON_SHOWHIDEPROCESSHACKER
- MENUITEM "System &information", ID_ICON_SYSTEMINFORMATION
- POPUP "N&otifications"
- BEGIN
- MENUITEM "Enable all", ID_NOTIFICATIONS_ENABLEALL
- MENUITEM "Disable all", ID_NOTIFICATIONS_DISABLEALL
- MENUITEM SEPARATOR
- MENUITEM "New processes", ID_NOTIFICATIONS_NEWPROCESSES
- MENUITEM "Terminated processes", ID_NOTIFICATIONS_TERMINATEDPROCESSES
- MENUITEM "New services", ID_NOTIFICATIONS_NEWSERVICES
- MENUITEM "Started services", ID_NOTIFICATIONS_STARTEDSERVICES
- MENUITEM "Stopped services", ID_NOTIFICATIONS_STOPPEDSERVICES
- MENUITEM "Deleted services", ID_NOTIFICATIONS_DELETEDSERVICES
- END
- POPUP "&Processes"
- BEGIN
- MENUITEM "Dummy", ID_PROCESSES_DUMMY
- END
- MENUITEM SEPARATOR
- POPUP "&Computer"
- BEGIN
- MENUITEM "&Lock", ID_COMPUTER_LOCK
- MENUITEM "Log o&ff", ID_COMPUTER_LOGOFF
- MENUITEM SEPARATOR
- MENUITEM "&Sleep", ID_COMPUTER_SLEEP
- MENUITEM "&Hibernate", ID_COMPUTER_HIBERNATE
- MENUITEM SEPARATOR
- MENUITEM "R&estart", ID_COMPUTER_RESTART
- MENUITEM "Restart to boot options", ID_COMPUTER_RESTARTBOOTOPTIONS
- MENUITEM "Shu&t down", ID_COMPUTER_SHUTDOWN
- MENUITEM "H&ybrid shut down", ID_COMPUTER_SHUTDOWNHYBRID
- END
- MENUITEM "E&xit", ID_ICON_EXIT
- END
-END
-
-IDR_MEMORY MENU
-BEGIN
- POPUP "Memory"
- BEGIN
- MENUITEM "&Read/Write memory", ID_MEMORY_READWRITEMEMORY
- MENUITEM "&Save...", ID_MEMORY_SAVE
- MENUITEM "Change &protection...", ID_MEMORY_CHANGEPROTECTION
- MENUITEM "&Free", ID_MEMORY_FREE
- MENUITEM "&Decommit", ID_MEMORY_DECOMMIT
- MENUITEM SEPARATOR
- MENUITEM "Read/Write &address...", ID_MEMORY_READWRITEADDRESS
- MENUITEM "&Copy\aCtrl+C", ID_MEMORY_COPY
- END
-END
-
-IDR_MEMFILTER MENU
-BEGIN
- POPUP "Filter"
- BEGIN
- MENUITEM "Contains...", ID_FILTER_CONTAINS
- MENUITEM "Contains (case-insensitive)...", ID_FILTER_CONTAINS_CASEINSENSITIVE
- MENUITEM "Regex...", ID_FILTER_REGEX
- MENUITEM "Regex (case-insensitive)...", ID_FILTER_REGEX_CASEINSENSITIVE
- END
-END
-
-IDR_EMPTYMEMLISTS MENU
-BEGIN
- POPUP "Empty"
- BEGIN
- MENUITEM "Empty working sets", ID_EMPTY_EMPTYWORKINGSETS
- MENUITEM "Empty modified page list", ID_EMPTY_EMPTYMODIFIEDPAGELIST
- MENUITEM "Empty standby list", ID_EMPTY_EMPTYSTANDBYLIST
- MENUITEM "Empty priority 0 standby list", ID_EMPTY_EMPTYPRIORITY0STANDBYLIST
- END
-END
-
-IDR_MINIINFO MENU
-BEGIN
- POPUP "Mini Info"
- BEGIN
- POPUP "&Opacity"
- BEGIN
- MENUITEM "10%", ID_OPACITY_10
- MENUITEM "20%", ID_OPACITY_20
- MENUITEM "30%", ID_OPACITY_30
- MENUITEM "40%", ID_OPACITY_40
- MENUITEM "50%", ID_OPACITY_50
- MENUITEM "60%", ID_OPACITY_60
- MENUITEM "70%", ID_OPACITY_70
- MENUITEM "80%", ID_OPACITY_80
- MENUITEM "90%", ID_OPACITY_90
- MENUITEM "Opaque", ID_OPACITY_OPAQUE
- END
- MENUITEM SEPARATOR
- MENUITEM "&Refresh\aF5", ID_MINIINFO_REFRESH
- MENUITEM "Refresh a&utomatically\aF6", ID_MINIINFO_REFRESHAUTOMATICALLY
- END
-END
-
-IDR_MINIINFO_PROCESS MENU
-BEGIN
- POPUP "Process"
- BEGIN
- MENUITEM SEPARATOR
- MENUITEM "&Go to process", ID_PROCESS_GOTOPROCESS
- END
-END
-
-IDR_ENVIRONMENT MENU
-BEGIN
- POPUP "Environment"
- BEGIN
- MENUITEM "&Edit", ID_ENVIRONMENT_EDIT
- MENUITEM "&Delete\aDel", ID_ENVIRONMENT_DELETE
- MENUITEM "&Copy\aCtrl+C", ID_ENVIRONMENT_COPY
- END
-END
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Dialog
-//
-
-IDD_PROCGENERAL DIALOGEX 0, 0, 260, 260
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "General"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- PUSHBUTTON "Permissions",IDC_PERMISSIONS,143,197,50,14
- PUSHBUTTON "Terminate",IDC_TERMINATE,197,197,50,14
- GROUPBOX "File",IDC_FILE,7,7,246,79
- ICON "",IDC_FILEICON,14,18,20,20
- EDITTEXT IDC_NAME,44,17,182,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
- EDITTEXT IDC_COMPANYNAME,44,29,183,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
- CONTROL "Company name link",IDC_COMPANYNAME_LINK,"SysLink",LWS_NOPREFIX | NOT WS_VISIBLE | WS_TABSTOP,46,29,183,9
- LTEXT "Version:",IDC_STATIC,15,41,27,8
- EDITTEXT IDC_VERSION,44,41,113,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
- LTEXT "Image file name:",IDC_STATIC,15,55,56,8
- EDITTEXT IDC_FILENAME,15,65,191,12,ES_AUTOHSCROLL | ES_READONLY
- PUSHBUTTON "Inspect",IDC_INSPECT,210,64,17,15,BS_ICON
- PUSHBUTTON "Open",IDC_OPENFILENAME,230,64,17,15,BS_ICON
- GROUPBOX "Process",IDC_PROCESS,7,92,246,161
- LTEXT "Command line:",IDC_STATIC,13,103,50,8
- EDITTEXT IDC_CMDLINE,79,101,147,12,ES_AUTOHSCROLL | ES_READONLY
- LTEXT "Current directory:",IDC_STATIC,13,119,60,8
- EDITTEXT IDC_CURDIR,79,117,168,12,ES_AUTOHSCROLL | ES_READONLY
- LTEXT "Started:",IDC_STATIC,13,135,28,8
- EDITTEXT IDC_STARTED,79,133,168,12,ES_AUTOHSCROLL | ES_READONLY
- LTEXT "PEB address:",IDC_STATIC,13,151,44,8
- EDITTEXT IDC_PEBADDRESS,79,149,101,12,ES_AUTOHSCROLL | ES_READONLY
- LTEXT "Image type:",IDC_PROCESSTYPELABEL,185,151,41,8,NOT WS_VISIBLE
- LTEXT "32-bit",IDC_PROCESSTYPETEXT,228,151,20,8,NOT WS_VISIBLE
- LTEXT "Parent:",IDC_STATIC,13,167,25,8
- EDITTEXT IDC_PARENTPROCESS,79,165,147,12,ES_AUTOHSCROLL | ES_READONLY
- PUSHBUTTON "View",IDC_VIEWPARENTPROCESS,230,163,17,15,BS_ICON
- LTEXT "Mitigation policies:",IDC_STATIC,13,183,59,8
- EDITTEXT IDC_MITIGATION,79,181,126,12,ES_AUTOHSCROLL | ES_READONLY
- PUSHBUTTON "Details",IDC_VIEWMITIGATION,209,180,38,14
- LTEXT "Protection:",IDC_STATIC,13,200,36,8
- EDITTEXT IDC_PROTECTION,51,200,80,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
- PUSHBUTTON "View",IDC_VIEWCOMMANDLINE,230,100,17,15,BS_ICON
-END
-
-IDD_PROCMODULES DIALOGEX 0, 0, 260, 260
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Modules"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,7,7,246,246,WS_EX_CLIENTEDGE
-END
-
-IDD_PROCTHREADS DIALOGEX 0, 0, 260, 260
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Threads"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "Start module:",IDC_STATICBL1,7,170,44,8
- EDITTEXT IDC_STARTMODULE,55,168,177,12,ES_AUTOHSCROLL | ES_READONLY
- PUSHBUTTON "Open",IDC_OPENSTARTMODULE,236,166,17,15,BS_ICON | WS_DISABLED
- LTEXT "Started:",IDC_STATICBL2,7,184,28,8
- LTEXT "N/A",IDC_STARTED,75,184,178,8
- LTEXT "Kernel time:",IDC_STATICBL3,7,207,40,8
- LTEXT "N/A",IDC_KERNELTIME,75,207,51,8
- LTEXT "User time:",IDC_STATICBL4,7,217,35,8
- LTEXT "N/A",IDC_USERTIME,75,217,51,8
- LTEXT "Context switches:",IDC_STATICBL5,7,228,60,8
- LTEXT "N/A",IDC_CONTEXTSWITCHES,75,228,51,8,SS_ENDELLIPSIS
- LTEXT "Cycles:",IDC_STATICBL6,7,239,24,8
- LTEXT "N/A",IDC_CYCLES,41,239,85,8,SS_ENDELLIPSIS
- LTEXT "Base priority:",IDC_STATICBL9,136,205,44,8
- LTEXT "Priority:",IDC_STATICBL8,136,195,26,8
- LTEXT "I/O priority:",IDC_STATICBL10,136,216,39,8
- LTEXT "Page priority:",IDC_STATICBL11,136,227,44,8
- LTEXT "State:",IDC_STATICBL7,7,195,21,8
- LTEXT "N/A",IDC_STATE,41,195,85,8,SS_ENDELLIPSIS
- LTEXT "N/A",IDC_PRIORITY,195,195,58,8
- LTEXT "N/A",IDC_BASEPRIORITY,195,205,58,8
- LTEXT "N/A",IDC_IOPRIORITY,195,216,58,8
- LTEXT "N/A",IDC_PAGEPRIORITY,195,227,58,8
- CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x22,7,7,246,156,WS_EX_CLIENTEDGE
- LTEXT "Ideal processor:",IDC_STATICBL12,136,239,53,8
- LTEXT "N/A",IDC_IDEALPROCESSOR,195,239,58,8
-END
-
-IDD_PROCHANDLES DIALOGEX 0, 0, 260, 260
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Handles"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- CONTROL "Hide unnamed handles",IDC_HIDEUNNAMEDHANDLES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,88,10
- CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x2,7,21,246,232,WS_EX_CLIENTEDGE
-END
-
-IDD_PROCENVIRONMENT DIALOGEX 0, 0, 260, 260
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Environment"
-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,246,227
- PUSHBUTTON "New...",IDC_NEW,93,239,50,14
- PUSHBUTTON "Edit...",IDC_EDIT,148,239,50,14
- PUSHBUTTON "Delete",IDC_DELETE,203,239,50,14
-END
-
-IDD_THRDSTACK DIALOGEX 0, 0, 261, 228
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
-CAPTION "Thread Stack"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,7,247,196
- PUSHBUTTON "Copy",IDC_COPY,96,207,50,14
- PUSHBUTTON "Refresh",IDC_REFRESH,150,207,50,14
- PUSHBUTTON "Close",IDOK,204,207,50,14
-END
-
-IDD_ABOUT DIALOGEX 0, 0, 270, 195
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "About"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- ICON IDI_PROCESSHACKER,IDC_STATIC,16,15,20,20
- LTEXT "Process Hacker",IDC_ABOUT_NAME,45,14,192,8
- LTEXT "Licensed under the GNU GPL, v3.",IDC_STATIC,45,27,193,8
- LTEXT "Copyright (c) 2008-2017 Wen Jia Liu (wj32)",IDC_STATIC,15,40,140,8
- CONTROL "Credits.",IDC_CREDITS,"SysLink",WS_TABSTOP,15,55,248,115
- CONTROL "Process Hacker on SourceForge.net",IDC_LINK_SF,
- "SysLink",WS_TABSTOP,7,177,130,11
- PUSHBUTTON "Diagnostics",IDC_DIAGNOSTICS,160,174,50,14
- DEFPUSHBUTTON "OK",IDOK,213,174,50,14
-END
-
-IDD_SRVLIST DIALOGEX 0, 0, 237, 201
-STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,0,0,237,141
- EDITTEXT IDC_DESCRIPTION,0,144,237,40,ES_MULTILINE | ES_READONLY | NOT WS_BORDER
- PUSHBUTTON "&Start",IDC_START,134,187,50,14
- PUSHBUTTON "&Pause",IDC_PAUSE,187,187,50,14
-END
-
-IDD_SRVGENERAL DIALOGEX 0, 0, 282, 183
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "General"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- EDITTEXT IDC_DESCRIPTION,7,7,268,45,ES_MULTILINE | ES_READONLY | WS_VSCROLL
- LTEXT "Type:",IDC_STATIC,7,57,20,8
- COMBOBOX IDC_TYPE,30,56,110,65,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
- LTEXT "Start type:",IDC_STATIC,147,57,38,8
- COMBOBOX IDC_STARTTYPE,188,56,87,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
- LTEXT "Error control:",IDC_STATIC,7,75,47,8
- COMBOBOX IDC_ERRORCONTROL,58,73,82,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
- LTEXT "Group:",IDC_STATIC,147,75,23,8
- EDITTEXT IDC_GROUP,173,74,102,12,ES_AUTOHSCROLL
- LTEXT "Binary path:",IDC_STATIC,7,92,40,8
- EDITTEXT IDC_BINARYPATH,58,91,163,12,ES_AUTOHSCROLL
- PUSHBUTTON "Browse...",IDC_BROWSE,225,90,50,14
- LTEXT "User account:",IDC_STATIC,7,110,46,8
- EDITTEXT IDC_USERACCOUNT,58,108,217,12,ES_AUTOHSCROLL
- LTEXT "Password:",IDC_STATIC,7,127,34,8
- EDITTEXT IDC_PASSWORD,58,125,204,12,ES_PASSWORD | ES_AUTOHSCROLL
- CONTROL "",IDC_PASSWORDCHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,266,126,9,10
- LTEXT "Service DLL:",IDC_STATIC,7,144,48,8
- EDITTEXT IDC_SERVICEDLL,58,142,217,12,ES_AUTOHSCROLL | ES_READONLY
- CONTROL "Delayed start",IDC_DELAYEDSTART,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,158,59,10
-END
-
-IDD_HNDLGENERAL DIALOGEX 0, 0, 260, 181
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "General"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- GROUPBOX "Basic information",IDC_BASICINFORMATION,7,7,246,67
- LTEXT "Name:",IDC_STATIC,14,19,22,8
- EDITTEXT IDC_NAME,40,19,206,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
- LTEXT "Type:",IDC_STATIC,14,32,20,8
- EDITTEXT IDC_TYPE,40,32,206,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
- LTEXT "Object address:",IDC_STATIC,14,44,53,8
- EDITTEXT IDC_ADDRESS,71,44,175,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
- LTEXT "Granted access:",IDC_STATIC,14,56,54,8
- EDITTEXT IDC_GRANTED_ACCESS,71,56,175,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
- GROUPBOX "References",IDC_STATIC,7,78,119,39
- LTEXT "References:",IDC_STATIC,14,90,40,8
- LTEXT "Static",IDC_REFERENCES,58,90,41,8
- LTEXT "Handles:",IDC_STATIC,14,101,29,8
- LTEXT "Static",IDC_HANDLES,58,101,40,8
- GROUPBOX "Quota charges",IDC_STATIC,131,78,122,39
- LTEXT "Paged:",IDC_STATIC,138,89,24,8
- LTEXT "Static",IDC_PAGED,182,89,39,8
- LTEXT "Non-paged:",IDC_STATIC,138,100,39,8
- LTEXT "Static",IDC_NONPAGED,182,100,39,8
-END
-
-IDD_INFORMATION DIALOGEX 0, 0, 317, 184
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
-CAPTION "Information"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- EDITTEXT IDC_TEXT,7,7,303,152,ES_MULTILINE | ES_READONLY | WS_VSCROLL
- PUSHBUTTON "Save...",IDC_SAVE,154,163,50,14
- PUSHBUTTON "Copy",IDC_COPY,207,163,50,14
- DEFPUSHBUTTON "Close",IDOK,260,163,50,14
-END
-
-IDD_FINDOBJECTS DIALOGEX 0, 0, 357, 233
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
-CAPTION "Find Handles or DLLs"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "Filter:",IDC_STATIC,7,9,20,8
- EDITTEXT IDC_FILTER,32,8,223,12,ES_AUTOHSCROLL
- PUSHBUTTON "Find",IDOK,300,7,50,14
- CONTROL "",IDC_RESULTS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,26,343,200
- CONTROL "&Regex",IDC_REGEX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,261,9,36,10
-END
-
-IDD_OBJTOKEN DIALOGEX 0, 0, 260, 260
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Token"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "User:",IDC_STATIC,7,7,18,8
- EDITTEXT IDC_USER,48,7,205,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
- LTEXT "User SID:",IDC_STATIC,7,18,32,8
- EDITTEXT IDC_USERSID,48,18,205,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
- LTEXT "Session:",IDC_STATIC,7,29,28,8
- LTEXT "Unknown",IDC_SESSIONID,38,29,30,8
- LTEXT "Elevated:",IDC_STATIC,85,29,32,8
- LTEXT "Unknown",IDC_ELEVATED,120,29,30,8
- LTEXT "Virtualized:",IDC_STATIC,169,29,36,8
- LTEXT "Unknown",IDC_VIRTUALIZED,209,29,44,8
- LTEXT "App container SID:",IDC_STATIC,7,40,62,8
- EDITTEXT IDC_APPCONTAINERSID,75,40,178,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
- CONTROL "",IDC_GROUPS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,53,246,84
- CONTROL "",IDC_PRIVILEGES,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,142,246,83
- LTEXT "To view capabilities, claims and other attributes, click Advanced.",IDC_INSTRUCTION,7,228,206,8
- PUSHBUTTON "Integrity",IDC_INTEGRITY,149,239,50,14
- PUSHBUTTON "Advanced",IDC_ADVANCED,203,239,50,14
-END
-
-IDD_HIDDENPROCESSES DIALOGEX 0, 0, 337, 221
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
-CAPTION "Hidden Processes"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "Processes highlighted red are hidden while those highlighted grey have terminated.",IDC_INTRO,7,7,323,12
- CONTROL "",IDC_PROCESSES,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,23,323,162
- RTEXT "",IDC_DESCRIPTION,7,187,323,11
- COMBOBOX IDC_METHOD,7,201,73,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
- PUSHBUTTON "Terminate",IDC_TERMINATE,115,200,50,14
- PUSHBUTTON "Save...",IDC_SAVE,170,200,50,14
- PUSHBUTTON "&Scan",IDC_SCAN,225,200,50,14
- DEFPUSHBUTTON "Close",IDOK,280,200,50,14
-END
-
-IDD_RUNAS DIALOGEX 0, 0, 278, 127
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Run As"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "Enter the command to start as the specified user.",IDC_STATIC,7,7,160,8
- LTEXT "Program:",IDC_STATIC,7,23,30,8
- EDITTEXT IDC_PROGRAM,53,21,163,12,ES_AUTOHSCROLL
- PUSHBUTTON "Browse...",IDC_BROWSE,221,20,50,14
- LTEXT "User name:",IDC_STATIC,7,40,38,8
- COMBOBOX IDC_USERNAME,53,38,123,12,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP
- LTEXT "Type:",IDC_STATIC,183,40,20,8
- COMBOBOX IDC_TYPE,207,38,64,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
- LTEXT "Password:",IDC_STATIC,7,56,34,8
- EDITTEXT IDC_PASSWORD,53,55,123,12,ES_PASSWORD | ES_AUTOHSCROLL
- CONTROL "Toggle elevation",IDC_TOGGLEELEVATION,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,183,56,69,10
- LTEXT "Session ID:",IDC_STATIC,7,73,37,8
- EDITTEXT IDC_SESSIONID,53,72,104,12,ES_AUTOHSCROLL | ES_NUMBER
- PUSHBUTTON "...",IDC_SESSIONS,161,71,16,14
- LTEXT "Desktop:",IDC_STATIC,7,90,30,8
- EDITTEXT IDC_DESKTOP,53,88,104,12,ES_AUTOHSCROLL
- PUSHBUTTON "...",IDC_DESKTOPS,161,87,16,14
- DEFPUSHBUTTON "OK",IDOK,168,106,50,14
- PUSHBUTTON "Cancel",IDCANCEL,221,106,50,14
-END
-
-IDD_PROGRESS DIALOGEX 0, 0, 216, 62
-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,159,41,50,14
- CONTROL "",IDC_PROGRESS,"msctls_progress32",0x0,7,23,202,14
- LTEXT "Please wait...",IDC_PROGRESSTEXT,7,7,202,12
-END
-
-IDD_PAGEFILES DIALOGEX 0, 0, 322, 162
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Pagefiles"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,7,308,128
- PUSHBUTTON "Refresh",IDC_REFRESH,211,141,50,14
- DEFPUSHBUTTON "Close",IDOK,265,141,50,14
-END
-
-IDD_TOKGENERAL DIALOGEX 0, 0, 270, 228
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "General"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- GROUPBOX "Token",IDC_STATIC,7,7,256,132
- LTEXT "User:",IDC_STATIC,15,19,18,8
- EDITTEXT IDC_USER,71,17,185,12,ES_AUTOHSCROLL | ES_READONLY
- LTEXT "User SID:",IDC_STATIC,15,36,32,8
- EDITTEXT IDC_USERSID,71,34,185,12,ES_AUTOHSCROLL | ES_READONLY
- LTEXT "Owner:",IDC_STATIC,15,53,25,8
- EDITTEXT IDC_OWNER,71,51,185,12,ES_AUTOHSCROLL | ES_READONLY
- LTEXT "Primary group:",IDC_STATIC,15,70,49,8
- EDITTEXT IDC_PRIMARYGROUP,71,68,185,12,ES_AUTOHSCROLL | ES_READONLY
- LTEXT "Session ID:",IDC_STATIC,15,87,37,8
- EDITTEXT IDC_SESSIONID,71,85,88,12,ES_AUTOHSCROLL | ES_READONLY
- LTEXT "Elevated:",IDC_STATIC,15,104,32,8
- EDITTEXT IDC_ELEVATED,71,102,117,12,ES_AUTOHSCROLL | ES_READONLY
- LTEXT "Virtualization:",IDC_STATIC,15,121,44,8
- EDITTEXT IDC_VIRTUALIZATION,71,119,185,12,ES_AUTOHSCROLL | ES_READONLY
- PUSHBUTTON "Linked token",IDC_LINKEDTOKEN,193,101,63,14
- GROUPBOX "Source",IDC_STATIC,7,143,256,47
- LTEXT "Name:",IDC_STATIC,15,155,22,8
- EDITTEXT IDC_SOURCENAME,71,153,185,12,ES_AUTOHSCROLL | ES_READONLY
- LTEXT "LUID:",IDC_STATIC,15,173,19,8
- EDITTEXT IDC_SOURCELUID,71,171,185,12,ES_AUTOHSCROLL | ES_READONLY
-END
-
-IDD_TOKADVANCED DIALOGEX 0, 0, 236, 186
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Advanced"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "Type:",IDC_STATIC,7,8,20,8
- EDITTEXT IDC_TYPE,81,7,116,12,ES_AUTOHSCROLL | ES_READONLY
- LTEXT "Impersonation level:",IDC_STATIC,7,26,68,8
- EDITTEXT IDC_IMPERSONATIONLEVEL,81,24,116,12,ES_AUTOHSCROLL | ES_READONLY
- LTEXT "Token LUID:",IDC_STATIC,7,43,55,8
- EDITTEXT IDC_TOKENLUID,81,41,116,12,ES_AUTOHSCROLL | ES_READONLY
- LTEXT "Authentication LUID:",IDC_STATIC,7,61,68,8
- EDITTEXT IDC_AUTHENTICATIONLUID,81,59,116,12,ES_AUTOHSCROLL | ES_READONLY
- LTEXT "Memory used:",IDC_STATIC,7,78,47,8
- EDITTEXT IDC_MEMORYUSED,81,76,116,12,ES_AUTOHSCROLL | ES_READONLY
- LTEXT "Memory available:",IDC_STATIC,7,95,60,8
- EDITTEXT IDC_MEMORYAVAILABLE,81,93,116,12,ES_AUTOHSCROLL | ES_READONLY
-END
-
-IDD_OBJJOB DIALOGEX 0, 0, 260, 260
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Job"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "Name:",IDC_STATIC,7,9,22,8
- EDITTEXT IDC_NAME,35,8,164,12,ES_AUTOHSCROLL
- PUSHBUTTON "Terminate",IDC_TERMINATE,203,7,50,14
- LTEXT "Processes in job:",IDC_STATIC,7,25,55,8
- CONTROL "",IDC_PROCESSES,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,38,246,62
- PUSHBUTTON "Add...",IDC_ADD,203,103,50,14
- LTEXT "Limits:",IDC_STATIC,7,117,21,8
- CONTROL "",IDC_LIMITS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,129,246,107
- PUSHBUTTON "Advanced",IDC_ADVANCED,203,239,50,14
-END
-
-IDD_OBJEVENT DIALOGEX 0, 0, 186, 76
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Event"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "Type:",IDC_STATIC,7,7,20,8
- LTEXT "Unknown",IDC_TYPE,42,7,137,8
- LTEXT "Signaled:",IDC_STATIC,7,18,30,8
- LTEXT "Unknown",IDC_SIGNALED,42,18,137,8
- PUSHBUTTON "Set",IDC_SET,7,34,50,14
- PUSHBUTTON "Reset",IDC_RESET,61,34,50,14
- PUSHBUTTON "Pulse",IDC_PULSE,115,34,50,14
-END
-
-IDD_OBJMUTANT DIALOGEX 0, 0, 186, 76
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Mutant"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "Count:",IDC_STATIC,7,7,23,8
- LTEXT "Unknown",IDC_COUNT,55,7,124,8
- LTEXT "Abandoned:",IDC_STATIC,7,18,40,8
- LTEXT "Unknown",IDC_ABANDONED,55,18,124,8
- LTEXT "Owner:",IDC_OWNERLABEL,7,29,25,8
- LTEXT "Unknown",IDC_OWNER,55,29,124,8
-END
-
-IDD_OBJSEMAPHORE DIALOGEX 0, 0, 186, 76
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Semaphore"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "Current count:",IDC_STATIC,7,7,50,8
- LTEXT "Unknown",IDC_CURRENTCOUNT,66,7,113,8
- LTEXT "Maximum count:",IDC_STATIC,7,18,54,8
- LTEXT "Unknown",IDC_MAXIMUMCOUNT,66,18,113,8
- PUSHBUTTON "Acquire",IDC_ACQUIRE,7,34,50,14
- PUSHBUTTON "Release",IDC_RELEASE,61,34,50,14
-END
-
-IDD_OBJTIMER DIALOGEX 0, 0, 186, 76
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Timer"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "Signaled:",-1,7,7,30,8
- LTEXT "Unknown",IDC_SIGNALED,42,7,137,8
- PUSHBUTTON "Cancel",IDC_CANCEL,7,19,50,14
-END
-
-IDD_JOBSTATISTICS DIALOGEX 0, 0, 259, 186
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Statistics"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- GROUPBOX "General",IDC_STATIC,7,7,133,47
- LTEXT "Active processes",IDC_STATIC,15,18,55,8
- RTEXT "Static",IDC_ZACTIVEPROCESSES_V,99,18,37,8,SS_ENDELLIPSIS
- LTEXT "Total processes",IDC_STATIC,15,28,51,8
- RTEXT "Static",IDC_ZTOTALPROCESSES_V,95,29,41,8,SS_ENDELLIPSIS
- LTEXT "Terminated processes",IDC_STATIC,15,39,71,8
- RTEXT "Static",IDC_ZTERMINATEDPROCESSES_V,99,39,37,8,SS_ENDELLIPSIS
- GROUPBOX "Time",IDC_STATIC,7,57,133,57
- LTEXT "User time",IDC_STATIC,15,68,32,8
- LTEXT "Kernel time",IDC_STATIC,15,79,38,8
- LTEXT "User time (period)",IDC_STATIC,15,89,60,8
- LTEXT "Kernel time (period)",IDC_STATIC,15,99,65,8
- RTEXT "Static",IDC_ZUSERTIME_V,83,68,53,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZKERNELTIME_V,85,79,51,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZUSERTIMEPERIOD_V,87,89,49,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZKERNELTIMEPERIOD_V,87,99,49,8,SS_ENDELLIPSIS
- GROUPBOX "Memory",IDC_STATIC,7,118,133,48
- LTEXT "Page faults",IDC_STATIC,15,129,38,8
- LTEXT "Peak process usage",IDC_STATIC,15,140,65,8
- LTEXT "Peak job usage",IDC_STATIC,15,151,52,8
- RTEXT "Static",IDC_ZPAGEFAULTS_V,86,129,50,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZPEAKPROCESSUSAGE_V,85,140,51,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZPEAKJOBUSAGE_V,86,151,50,8,SS_ENDELLIPSIS
- GROUPBOX "I/O",IDC_STATIC,146,7,106,75
- LTEXT "Reads",IDC_STATIC,152,17,21,8
- LTEXT "Read bytes",IDC_STATIC,152,27,38,8
- LTEXT "Writes",IDC_STATIC,152,37,22,8
- LTEXT "Write bytes",IDC_STATIC,152,47,38,8
- LTEXT "Other",IDC_STATIC,152,57,20,8
- LTEXT "Other bytes",IDC_STATIC,152,67,40,8
- RTEXT "Static",IDC_ZIOREADS_V,200,17,47,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZIOREADBYTES_V,200,27,47,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZIOWRITES_V,200,37,47,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZIOWRITEBYTES_V,200,47,47,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZIOOTHER_V,200,57,47,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZIOOTHERBYTES_V,200,67,47,8,SS_ENDELLIPSIS
-END
-
-IDD_OBJEVENTPAIR DIALOGEX 0, 0, 186, 76
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Event Pair"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- PUSHBUTTON "Set low",IDC_SETLOW,7,7,50,14
- PUSHBUTTON "Set high",IDC_SETHIGH,61,7,50,14
-END
-
-IDD_OBJSECTION DIALOGEX 0, 0, 255, 76
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Section"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "Type:",IDC_STATIC,7,7,20,8
- LTEXT "Unknown",IDC_TYPE,43,7,205,8
- LTEXT "Size:",IDC_STATIC,7,18,16,8
- LTEXT "Unknown",IDC_SIZE_,43,18,205,8
- LTEXT "File:",IDC_STATIC,7,29,14,8
- EDITTEXT IDC_FILE,43,29,205,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
-END
-
-IDD_AFFINITY DIALOGEX 0, 0, 279, 227
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Affinity"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- DEFPUSHBUTTON "OK",IDOK,169,206,50,14
- PUSHBUTTON "Cancel",IDCANCEL,222,206,50,14
- LTEXT "Affinity controls which CPUs threads are allowed to execute on.",IDC_STATIC,7,7,265,11
- CONTROL "CPU 0",IDC_CPU0,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,21,35,10
- CONTROL "CPU 1",IDC_CPU1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,33,35,10
- CONTROL "CPU 2",IDC_CPU2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,44,35,10
- CONTROL "CPU 3",IDC_CPU3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,56,35,10
- CONTROL "CPU 4",IDC_CPU4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,67,35,10
- CONTROL "CPU 5",IDC_CPU5,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,78,35,10
- CONTROL "CPU 6",IDC_CPU6,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,89,35,10
- CONTROL "CPU 7",IDC_CPU7,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,100,35,10
- CONTROL "CPU 8",IDC_CPU8,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,111,35,10
- CONTROL "CPU 9",IDC_CPU9,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,122,35,10
- CONTROL "CPU 10",IDC_CPU10,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,134,39,10
- CONTROL "CPU 11",IDC_CPU11,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,145,39,10
- CONTROL "CPU 12",IDC_CPU12,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,156,39,10
- CONTROL "CPU 13",IDC_CPU13,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,167,39,10
- CONTROL "CPU 14",IDC_CPU14,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,178,39,10
- CONTROL "CPU 15",IDC_CPU15,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,190,39,10
- CONTROL "CPU 16",IDC_CPU16,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,21,39,10
- CONTROL "CPU 17",IDC_CPU17,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,33,39,10
- CONTROL "CPU 18",IDC_CPU18,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,44,39,10
- CONTROL "CPU 19",IDC_CPU19,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,56,39,10
- CONTROL "CPU 20",IDC_CPU20,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,67,39,10
- CONTROL "CPU 21",IDC_CPU21,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,78,39,10
- CONTROL "CPU 22",IDC_CPU22,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,89,39,10
- CONTROL "CPU 23",IDC_CPU23,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,100,39,10
- CONTROL "CPU 24",IDC_CPU24,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,111,39,10
- CONTROL "CPU 25",IDC_CPU25,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,122,39,10
- CONTROL "CPU 26",IDC_CPU26,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,134,39,10
- CONTROL "CPU 27",IDC_CPU27,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,145,39,10
- CONTROL "CPU 28",IDC_CPU28,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,156,39,10
- CONTROL "CPU 29",IDC_CPU29,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,167,39,10
- CONTROL "CPU 30",IDC_CPU30,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,178,39,10
- CONTROL "CPU 31",IDC_CPU31,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,190,39,10
- CONTROL "CPU 32",IDC_CPU32,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,21,39,10
- CONTROL "CPU 33",IDC_CPU33,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,33,39,10
- CONTROL "CPU 34",IDC_CPU34,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,44,39,10
- CONTROL "CPU 35",IDC_CPU35,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,56,39,10
- CONTROL "CPU 36",IDC_CPU36,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,67,39,10
- CONTROL "CPU 37",IDC_CPU37,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,78,39,10
- CONTROL "CPU 38",IDC_CPU38,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,89,39,10
- CONTROL "CPU 39",IDC_CPU39,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,100,39,10
- CONTROL "CPU 40",IDC_CPU40,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,111,39,10
- CONTROL "CPU 41",IDC_CPU41,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,122,39,10
- CONTROL "CPU 42",IDC_CPU42,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,134,39,10
- CONTROL "CPU 43",IDC_CPU43,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,145,39,10
- CONTROL "CPU 44",IDC_CPU44,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,156,39,10
- CONTROL "CPU 45",IDC_CPU45,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,167,39,10
- CONTROL "CPU 46",IDC_CPU46,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,178,39,10
- CONTROL "CPU 47",IDC_CPU47,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,190,39,10
- CONTROL "CPU 48",IDC_CPU48,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,21,39,10
- CONTROL "CPU 49",IDC_CPU49,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,33,39,10
- CONTROL "CPU 50",IDC_CPU50,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,44,39,10
- CONTROL "CPU 51",IDC_CPU51,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,56,39,10
- CONTROL "CPU 52",IDC_CPU52,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,67,39,10
- CONTROL "CPU 53",IDC_CPU53,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,78,39,10
- CONTROL "CPU 54",IDC_CPU54,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,89,39,10
- CONTROL "CPU 55",IDC_CPU55,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,100,39,10
- CONTROL "CPU 56",IDC_CPU56,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,111,39,10
- CONTROL "CPU 57",IDC_CPU57,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,122,39,10
- CONTROL "CPU 58",IDC_CPU58,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,134,39,10
- CONTROL "CPU 59",IDC_CPU59,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,145,39,10
- CONTROL "CPU 60",IDC_CPU60,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,156,39,10
- CONTROL "CPU 61",IDC_CPU61,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,167,39,10
- CONTROL "CPU 62",IDC_CPU62,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,178,39,10
- CONTROL "CPU 63",IDC_CPU63,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,190,39,10
- PUSHBUTTON "Select all",IDC_SELECTALL,7,206,50,14
- PUSHBUTTON "Deselect all",IDC_DESELECTALL,60,206,50,14
-END
-
-IDD_SYSINFO DIALOGEX 0, 0, 423, 247
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
-EXSTYLE WS_EX_APPWINDOW
-CAPTION "System Information"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "Click a graph to view details for that section.",IDC_INSTRUCTION,7,228,144,8
- CONTROL "Always on &top",IDC_ALWAYSONTOP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,297,228,63,10
- DEFPUSHBUTTON "Close",IDOK,366,226,50,14
-END
-
-IDD_EDITMESSAGE DIALOGEX 0, 0, 282, 163
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Message"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "Title:",IDC_STATIC,7,8,17,8
- EDITTEXT IDC_TITLE,52,7,223,12,ES_AUTOHSCROLL
- LTEXT "Text:",IDC_STATIC,7,24,18,8
- EDITTEXT IDC_TEXT,52,23,223,79,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL
- LTEXT "Icon:",IDC_STATIC,7,107,18,8
- COMBOBOX IDC_TYPE,52,105,80,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
- LTEXT "Timeout (s):",IDC_STATIC,7,123,40,8
- EDITTEXT IDC_TIMEOUT,52,122,43,12,ES_AUTOHSCROLL
- DEFPUSHBUTTON "OK",IDOK,172,142,50,14
- PUSHBUTTON "Cancel",IDCANCEL,225,142,50,14
-END
-
-IDD_SESSION DIALOGEX 0, 0, 201, 149
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Session Properties"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- DEFPUSHBUTTON "Close",IDOK,144,128,50,14
- LTEXT "User name:",IDC_STATIC,7,7,38,8
- LTEXT "Session ID:",IDC_STATIC,7,18,37,8
- LTEXT "State:",IDC_STATIC,7,29,21,8
- LTEXT "Client name:",IDC_STATIC,7,84,41,8
- LTEXT "Client address:",IDC_STATIC,7,95,49,8
- LTEXT "Client display:",IDC_STATIC,7,106,46,8
- LTEXT "N/A",IDC_USERNAME,66,7,128,8
- LTEXT "N/A",IDC_SESSIONID,66,18,128,8
- LTEXT "N/A",IDC_STATE,66,29,128,8
- LTEXT "N/A",IDC_CLIENTNAME,66,84,128,8
- LTEXT "N/A",IDC_CLIENTADDRESS,66,95,128,8
- LTEXT "N/A",IDC_CLIENTDISPLAY,66,106,128,8
- LTEXT "Logon time:",IDC_STATIC,7,40,38,8
- LTEXT "N/A",IDC_LOGONTIME,66,40,128,8
- LTEXT "Connect time:",IDC_STATIC,7,51,46,8
- LTEXT "Disconnect time:",IDC_STATIC,7,62,54,8
- LTEXT "Last input time:",IDC_STATIC,7,73,50,8
- LTEXT "N/A",IDC_CONNECTTIME,66,51,128,8
- LTEXT "N/A",IDC_DISCONNECTTIME,66,62,128,8
- LTEXT "N/A",IDC_LASTINPUTTIME,66,74,128,8
-END
-
-IDD_PROCMEMORY DIALOGEX 0, 0, 260, 260
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Memory"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- PUSHBUTTON "Strings...",IDC_STRINGS,150,7,50,14
- PUSHBUTTON "Refresh",IDC_REFRESH,203,7,50,14
- CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,7,26,246,227,WS_EX_CLIENTEDGE
- CONTROL "Hide free regions",IDC_HIDEFREEREGIONS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,9,71,10
-END
-
-IDD_CHOOSE DIALOGEX 0, 0, 199, 73
-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 "Text:",IDC_MESSAGE,7,7,185,8,SS_ENDELLIPSIS
- COMBOBOX IDC_CHOICE,7,20,185,30,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP
- CONTROL "Option",IDC_OPTION,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,39,185,10
- DEFPUSHBUTTON "OK",IDOK,89,52,50,14
- PUSHBUTTON "Cancel",IDCANCEL,142,52,50,14
- COMBOBOX IDC_CHOICEUSER,7,20,185,30,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP
- EDITTEXT IDC_CHOICESIMPLE,7,20,185,13,ES_PASSWORD | ES_AUTOHSCROLL | NOT WS_VISIBLE
-END
-
-IDD_OPTGENERAL DIALOGEX 0, 0, 250, 154
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "General"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "Search engine:",IDC_STATIC,7,8,49,8
- EDITTEXT IDC_SEARCHENGINE,61,7,182,12,ES_AUTOHSCROLL
- LTEXT "PE viewer:",IDC_STATIC,7,23,35,8
- EDITTEXT IDC_PEVIEWER,61,22,182,12,ES_AUTOHSCROLL
- LTEXT "Max. size unit:",IDC_STATIC,7,38,49,8
- COMBOBOX IDC_MAXSIZEUNIT,61,37,39,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
- LTEXT "Icon processes:",IDC_STATIC,7,55,52,8
- EDITTEXT IDC_ICONPROCESSES,61,53,40,12,ES_AUTOHSCROLL | ES_NUMBER
- CONTROL "Allow only one instance",IDC_ALLOWONLYONEINSTANCE,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,71,91,10
- CONTROL "Hide when closed",IDC_HIDEONCLOSE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,83,71,10
- CONTROL "Hide when minimized",IDC_HIDEONMINIMIZE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,95,81,10
- CONTROL "Start hidden",IDC_STARTHIDDEN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,119,55,10
- CONTROL "Collapse services on start",IDC_COLLAPSESERVICES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,122,71,98,10
- CONTROL "Single-click tray icons",IDC_ICONSINGLECLICK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,122,83,83,10
- CONTROL "Icon click toggles visibility",IDC_ICONTOGGLESVISIBILITY,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,122,95,97,10
- CONTROL "Enable plugins",IDC_ENABLEPLUGINS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,122,107,61,10
- PUSHBUTTON "Font...",IDC_FONT,7,133,50,14
- CONTROL "Start when I log on",IDC_STARTATLOGON,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,107,77,10
-END
-
-IDD_OPTHIGHLIGHTING DIALOGEX 0, 0, 250, 174
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Highlighting"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "Highlighting duration:",IDC_STATIC,7,8,70,8
- EDITTEXT IDC_HIGHLIGHTINGDURATION,79,7,40,12,ES_AUTOHSCROLL | ES_NUMBER
- LTEXT "New objects:",IDC_STATIC,7,25,44,8
- CONTROL "New objects",IDC_NEWOBJECTS,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,57,23,33,13
- LTEXT "Removed objects:",IDC_STATIC,127,25,60,8
- CONTROL "Removed objects",IDC_REMOVEDOBJECTS,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,193,23,33,13
- CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,7,41,236,107
- LTEXT "Double-click an item to change it.",IDC_STATIC,7,156,106,8
- PUSHBUTTON "Enable all",IDC_ENABLEALL,140,153,50,14
- PUSHBUTTON "Disable all",IDC_DISABLEALL,193,153,50,14
-END
-
-IDD_CHOOSECOLUMNS DIALOGEX 0, 0, 381, 207
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Choose Columns"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "Select the columns that will appear in the list.",IDC_MESSAGE,7,7,367,10
- LTEXT "Inactive columns:",IDC_STATIC,7,21,57,8
- LISTBOX IDC_INACTIVE,7,31,129,150,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
- PUSHBUTTON "Show >",IDC_SHOW,139,86,50,14
- PUSHBUTTON "< Hide",IDC_HIDE,139,103,50,14
- LISTBOX IDC_ACTIVE,192,31,129,150,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
- PUSHBUTTON "Move up",IDC_MOVEUP,324,31,50,14
- PUSHBUTTON "Move down",IDC_MOVEDOWN,324,48,50,14
- DEFPUSHBUTTON "OK",IDOK,272,186,50,14
- PUSHBUTTON "Cancel",IDCANCEL,324,186,50,14
- LTEXT "Active columns:",IDC_STATIC,192,21,51,8
-END
-
-IDD_NETSTACK DIALOGEX 0, 0, 261, 228
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
-CAPTION "Network Stack"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,7,247,196
- PUSHBUTTON "Close",IDOK,204,207,50,14
-END
-
-IDD_CREATESERVICE DIALOGEX 0, 0, 287, 133
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Create Service"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "Name:",IDC_STATIC,7,8,22,8
- EDITTEXT IDC_NAME,61,7,219,12,ES_AUTOHSCROLL
- LTEXT "Display name:",IDC_STATIC,7,24,46,8
- EDITTEXT IDC_DISPLAYNAME,61,23,219,12,ES_AUTOHSCROLL
- LTEXT "Type:",IDC_STATIC,7,41,20,8
- COMBOBOX IDC_TYPE,61,39,97,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
- LTEXT "Start type:",IDC_STATIC,7,58,38,8
- COMBOBOX IDC_STARTTYPE,61,56,97,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
- LTEXT "Error control:",IDC_STATIC,7,75,45,8
- COMBOBOX IDC_ERRORCONTROL,61,73,97,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
- LTEXT "Binary path:",IDC_STATIC,7,91,40,8
- EDITTEXT IDC_BINARYPATH,61,90,165,12,ES_AUTOHSCROLL
- PUSHBUTTON "Browse...",IDC_BROWSE,230,89,50,14
- DEFPUSHBUTTON "OK",IDOK,176,112,50,14
- PUSHBUTTON "Cancel",IDCANCEL,230,112,50,14
-END
-
-IDD_PROCPERFORMANCE DIALOGEX 0, 0, 260, 260
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Performance"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- GROUPBOX "CPU",IDC_GROUPCPU,7,7,246,74,0,WS_EX_TRANSPARENT
- GROUPBOX "Private bytes",IDC_GROUPPRIVATEBYTES,7,86,246,77,0,WS_EX_TRANSPARENT
- GROUPBOX "I/O",IDC_GROUPIO,7,164,246,89,0,WS_EX_TRANSPARENT
- CONTROL "",IDC_CPU,"PhGraph",WS_CLIPSIBLINGS,105,42,50,14
- CONTROL "",IDC_PRIVATEBYTES,"PhGraph",WS_CLIPSIBLINGS,105,122,50,14
- CONTROL "",IDC_IO,"PhGraph",WS_CLIPSIBLINGS,105,204,50,14
-END
-
-IDD_PROCSTATISTICS DIALOGEX 0, 0, 260, 260
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Statistics"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- GROUPBOX "CPU",IDC_STATIC,7,7,119,64
- GROUPBOX "I/O",IDC_STATIC,131,7,122,83
- LTEXT "Priority",IDC_STATIC,14,17,24,8
- LTEXT "Cycles",IDC_STATIC,14,27,22,8
- LTEXT "Kernel time",IDC_STATIC,14,37,38,8
- LTEXT "User time",IDC_STATIC,14,47,32,8
- LTEXT "Total time",IDC_STATIC,14,57,34,8
- RTEXT "Static",IDC_ZPRIORITY_V,59,17,61,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZCYCLES_V,43,27,77,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZKERNELTIME_V,59,37,61,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZUSERTIME_V,59,47,61,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZTOTALTIME_V,59,57,61,8,SS_ENDELLIPSIS
- GROUPBOX "Memory",IDC_STATIC,7,74,120,128
- LTEXT "Private bytes",IDC_STATIC,14,84,44,8
- LTEXT "Working set",IDC_STATIC,14,136,40,8
- LTEXT "Peak working set",IDC_STATIC,14,178,57,8
- LTEXT "Virtual size",IDC_STATIC,14,105,36,8
- LTEXT "Peak virtual size",IDC_STATIC,14,115,53,8
- LTEXT "Peak private bytes",IDC_STATIC,14,95,61,8
- LTEXT "Page faults",IDC_STATIC,14,125,38,8
- LTEXT "Page priority",IDC_STATIC,14,188,42,8
- RTEXT "Static",IDC_ZPRIVATEBYTES_V,72,84,48,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZWORKINGSET_V,72,136,48,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZPEAKWORKINGSET_V,78,178,42,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZVIRTUALSIZE_V,72,105,48,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZPEAKVIRTUALSIZE_V,72,115,48,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZPEAKPRIVATEBYTES_V,80,95,40,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZPAGEFAULTS_V,72,125,48,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZPAGEPRIORITY_V,72,188,48,8,SS_ENDELLIPSIS
- LTEXT "Reads",IDC_STATIC,138,17,21,8
- LTEXT "Read bytes",IDC_STATIC,138,27,38,8
- LTEXT "Writes",IDC_STATIC,138,37,22,8
- LTEXT "Write bytes",IDC_STATIC,138,47,38,8
- LTEXT "Other",IDC_STATIC,138,57,20,8
- LTEXT "Other bytes",IDC_STATIC,138,67,40,8
- LTEXT "I/O priority",IDC_STATIC,138,77,36,8
- RTEXT "Static",IDC_ZIOREADS_V,184,17,63,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZIOREADBYTES_V,184,27,63,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZIOWRITES_V,184,37,63,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZIOWRITEBYTES_V,184,47,63,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZIOOTHER_V,184,57,63,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZIOOTHERBYTES_V,184,67,63,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZIOPRIORITY_V,184,77,63,8,SS_ENDELLIPSIS
- GROUPBOX "Other",IDC_STATIC,131,92,122,70
- LTEXT "Handles",IDC_STATIC,138,102,26,8
- LTEXT "GDI handles",IDC_STATIC,138,122,40,8
- LTEXT "USER handles",IDC_STATIC,138,132,46,8
- RTEXT "Static",IDC_ZHANDLES_V,193,102,54,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZGDIHANDLES_V,193,122,54,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZUSERHANDLES_V,193,132,54,8,SS_ENDELLIPSIS
- PUSHBUTTON "Details",IDC_DETAILS,137,143,50,14
- LTEXT "Peak handles",IDC_STATIC,138,112,44,8
- RTEXT "Static",IDC_ZPEAKHANDLES_V,192,112,55,8,SS_ENDELLIPSIS
- LTEXT "Private WS",IDC_STATIC,22,147,36,8
- LTEXT "Shareable WS",IDC_STATIC,22,157,46,8
- LTEXT "Shared WS",IDC_STATIC,22,167,36,8
- RTEXT "Static",IDC_ZPRIVATEWS_V,78,147,42,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZSHAREABLEWS_V,78,157,42,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZSHAREDWS_V,78,167,42,8,SS_ENDELLIPSIS
-END
-
-IDD_OPTADVANCED DIALOGEX 0, 0, 250, 150
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Advanced"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- CONTROL "Enable warnings",IDC_ENABLEWARNINGS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,68,10
- CONTROL "Enable kernel-mode driver",IDC_ENABLEKERNELMODEDRIVER,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,19,99,10
- CONTROL "Hide unnamed handles",IDC_HIDEUNNAMEDHANDLES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,31,88,10
- CONTROL "Check images for digital signatures and packing",IDC_ENABLESTAGE2,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,43,167,10
- CONTROL "Resolve addresses for network connections",IDC_ENABLENETWORKRESOLVE,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,55,155,10
- CONTROL "Include CPU (and other) usage of children in collapsed processes",IDC_PROPAGATECPUUSAGE,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,67,223,10
- CONTROL "Show tooltips instantly",IDC_ENABLEINSTANTTOOLTIPS,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,79,88,10
- CONTROL "Enable cycle-based CPU usage",IDC_ENABLECYCLECPUUSAGE,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,91,114,10
- CONTROL "Replace Task Manager with Process Hacker",IDC_REPLACETASKMANAGER,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,105,154,10
- PUSHBUTTON "Change...",IDC_CHANGE,161,103,62,14
- LTEXT "History sample count:",IDC_SAMPLECOUNTLABEL,7,121,70,8
- EDITTEXT IDC_SAMPLECOUNT,82,120,39,12,ES_AUTOHSCROLL | ES_NUMBER
- CONTROL "Automatic",IDC_SAMPLECOUNTAUTOMATIC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,126,121,48,10
-END
-
-IDD_GDIHANDLES DIALOGEX 0, 0, 351, 307
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "GDI Handles"
-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,337,275
- PUSHBUTTON "Refresh",IDC_REFRESH,240,286,50,14
- DEFPUSHBUTTON "Close",IDOK,294,286,50,14
-END
-
-IDD_LOG DIALOGEX 0, 0, 313, 303
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
-EXSTYLE WS_EX_APPWINDOW
-CAPTION "Log"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_OWNERDATA | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,7,299,272
- PUSHBUTTON "Clear",IDC_CLEAR,7,282,50,14
- CONTROL "Auto-scroll",IDC_AUTOSCROLL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,61,284,50,10
- PUSHBUTTON "Save...",IDC_SAVE,148,282,50,14
- PUSHBUTTON "Copy",IDC_COPY,202,282,50,14
- DEFPUSHBUTTON "Close",IDOK,256,282,50,14
-END
-
-IDD_OPTSYMBOLS DIALOGEX 0, 0, 250, 75
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Symbols"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "Dbghelp.dll path:",IDC_STATIC,7,9,56,8
- EDITTEXT IDC_DBGHELPPATH,66,8,123,12,ES_AUTOHSCROLL
- PUSHBUTTON "Browse...",IDC_BROWSE,193,7,50,14
- LTEXT "Search path:",IDC_STATIC,7,24,42,8
- EDITTEXT IDC_DBGHELPSEARCHPATH,66,23,177,12,ES_AUTOHSCROLL
- CONTROL "Undecorate symbols",IDC_UNDECORATESYMBOLS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,38,81,10
-END
-
-IDD_MEMEDIT DIALOGEX 0, 0, 441, 269
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
-EXSTYLE WS_EX_APPWINDOW
-CAPTION "Memory"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- CONTROL "",IDC_MEMORY,"PhHexEdit",WS_CLIPSIBLINGS | WS_VSCROLL | WS_TABSTOP,7,7,427,239
- PUSHBUTTON "Re-read",IDC_REREAD,7,248,50,14
- PUSHBUTTON "Write",IDC_WRITE,60,248,50,14
- PUSHBUTTON "Go to...",IDC_GOTO,112,248,50,14
- PUSHBUTTON "Save...",IDC_SAVE,331,248,50,14
- PUSHBUTTON "Close",IDOK,384,248,50,14
- COMBOBOX IDC_BYTESPERROW,164,249,86,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-END
-
-IDD_MEMPROTECT DIALOGEX 0, 0, 270, 171
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Memory Protection"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- EDITTEXT IDC_INTRO,7,7,256,122,ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
- LTEXT "New value:",IDC_STATIC,120,136,37,8
- EDITTEXT IDC_VALUE,161,135,102,12,ES_AUTOHSCROLL
- DEFPUSHBUTTON "OK",IDOK,161,150,50,14
- PUSHBUTTON "Cancel",IDCANCEL,213,150,50,14
-END
-
-IDD_MEMRESULTS DIALOGEX 0, 0, 313, 266
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
-CAPTION "Results"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "Results.",IDC_INTRO,7,9,299,8
- CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_OWNERDATA | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,21,299,221
- PUSHBUTTON "Filter",IDC_FILTER,7,245,50,14
- PUSHBUTTON "Save...",IDC_SAVE,149,245,50,14
- PUSHBUTTON "Copy",IDC_COPY,203,245,50,14
- DEFPUSHBUTTON "Close",IDOK,256,245,50,14
-END
-
-IDD_MEMSTRING DIALOGEX 0, 0, 241, 86
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "String Search"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "Minimum length:",IDC_STATIC,7,8,54,8
- EDITTEXT IDC_MINIMUMLENGTH,67,7,51,12,ES_AUTOHSCROLL
- CONTROL "Detect Unicode",IDC_DETECTUNICODE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,22,65,10
- LTEXT "Search in the following types of memory regions:",IDC_STATIC,7,36,157,8
- CONTROL "Private",IDC_PRIVATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,49,39,10
- CONTROL "Image",IDC_IMAGE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,55,49,36,10
- CONTROL "Mapped",IDC_MAPPED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,101,49,41,10
- DEFPUSHBUTTON "OK",IDOK,131,65,50,14
- PUSHBUTTON "Cancel",IDCANCEL,184,65,50,14
-END
-
-IDD_OPTGRAPHS DIALOGEX 0, 0, 250, 156
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Graphs"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- CONTROL "Show text",IDC_SHOWTEXT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,49,10
- CONTROL "Use old colors (black background)",IDC_USEOLDCOLORS,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,19,123,10
- CONTROL "Show commit charge instead of physical memory in summary view",IDC_SHOWCOMMITINSUMMARY,
- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,31,227,10
- LTEXT "CPU kernel:",IDC_STATIC,7,48,39,8
- CONTROL "CPU kernel",IDC_CPUKERNEL,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,73,46,33,13
- LTEXT "CPU user:",IDC_STATIC,7,65,34,8
- CONTROL "CPU user",IDC_CPUUSER,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,73,63,33,13
- LTEXT "I/O R+O:",IDC_STATIC,7,82,32,8
- CONTROL "I/O R+O",IDC_IORO,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,73,80,33,13
- LTEXT "I/O W:",IDC_STATIC,7,98,23,8
- CONTROL "I/O W",IDC_IOW,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,73,97,33,13
- LTEXT "Private bytes:",IDC_STATIC,7,115,46,8
- CONTROL "Private bytes",IDC_PRIVATE,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,73,113,33,13
- LTEXT "Physical memory:",IDC_STATIC,7,131,56,8
- CONTROL "Physical memory",IDC_PHYSICAL,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,73,129,33,13
-END
-
-IDD_PLUGINS DIALOGEX 0, 0, 291, 272
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Plugins"
-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,277,119
- GROUPBOX "Plugin",IDC_STATIC,7,129,277,118
- LTEXT "Name:",IDC_STATIC,15,141,22,8
- EDITTEXT IDC_NAME,71,141,104,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
- LTEXT "Internal name:",IDC_STATIC,15,152,49,8
- EDITTEXT IDC_INTERNALNAME,71,152,203,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
- LTEXT "Author:",IDC_STATIC,15,163,26,8
- EDITTEXT IDC_AUTHOR,71,163,203,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
- LTEXT "URL:",IDC_STATIC,15,174,16,8
- EDITTEXT IDC_URL,71,174,174,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
- CONTROL "Open",IDC_OPENURL,"SysLink",WS_TABSTOP,250,174,26,10
- LTEXT "File name:",IDC_STATIC,15,185,34,8
- EDITTEXT IDC_FILENAME,71,185,203,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
- LTEXT "Version:",IDC_STATIC,183,141,27,8
- EDITTEXT IDC_VERSION,215,141,59,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
- LTEXT "Description:",IDC_STATIC,15,196,39,8
- EDITTEXT IDC_DESCRIPTION,14,208,211,34,ES_MULTILINE | ES_READONLY
- PUSHBUTTON "Disable",IDC_DISABLE,230,211,50,14
- PUSHBUTTON "Options...",IDC_OPTIONS,230,228,50,14
- PUSHBUTTON "Clean up",IDC_CLEANUP,7,251,50,14
- LTEXT "Changes may require a restart to take effect.",IDC_INSTRUCTION,82,254,148,8,NOT WS_VISIBLE
- DEFPUSHBUTTON "Close",IDOK,234,251,50,14
-END
-
-IDD_HANDLESTATS DIALOGEX 0, 0, 219, 175
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Handle Statistics"
-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,205,143
- DEFPUSHBUTTON "Close",IDOK,162,154,50,14
-END
-
-IDD_PROCRECORD DIALOGEX 0, 0, 260, 202
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Process Record"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "Name:",IDC_STATIC,7,9,22,8
- EDITTEXT IDC_PROCESSNAME,39,9,214,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
- LTEXT "Parent:",IDC_STATIC,7,21,25,8
- EDITTEXT IDC_PARENT,39,21,214,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
- GROUPBOX "File",IDC_FILE,7,38,246,79
- ICON "",IDC_FILEICON,14,49,20,20
- EDITTEXT IDC_NAME,44,48,182,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
- EDITTEXT IDC_COMPANYNAME,44,60,183,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
- LTEXT "Version:",IDC_STATIC,15,72,27,8
- EDITTEXT IDC_VERSION,44,72,183,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
- LTEXT "Image file name:",IDC_STATIC,15,86,56,8
- EDITTEXT IDC_FILENAME,15,96,211,12,ES_AUTOHSCROLL | ES_READONLY
- PUSHBUTTON "Open",IDC_OPENFILENAME,230,95,17,15,BS_ICON
- LTEXT "Command line:",IDC_STATIC,7,123,50,8
- EDITTEXT IDC_CMDLINE,65,121,188,12,ES_AUTOHSCROLL | ES_READONLY
- LTEXT "Started:",IDC_STATIC,7,139,28,8
- EDITTEXT IDC_STARTED,65,137,188,12,ES_AUTOHSCROLL | ES_READONLY
- LTEXT "Terminated:",IDC_STATIC,7,155,40,8
- EDITTEXT IDC_TERMINATED,65,153,188,12,ES_AUTOHSCROLL | ES_READONLY
- LTEXT "Session ID:",IDC_STATIC,7,170,37,8
- LTEXT "Static",IDC_SESSIONID,50,170,19,8
- PUSHBUTTON "Properties",IDC_PROPERTIES,150,181,50,14
- DEFPUSHBUTTON "Close",IDOK,203,181,50,14
-END
-
-IDD_CHOOSEPROCESS DIALOGEX 0, 0, 317, 239
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
-CAPTION "Select a Process"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "Select a process from the list below.",IDC_MESSAGE,7,7,303,8,SS_ENDELLIPSIS
- CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,21,303,193
- PUSHBUTTON "Refresh",IDC_REFRESH,7,218,50,14
- DEFPUSHBUTTON "OK",IDOK,205,218,50,14
- PUSHBUTTON "Cancel",IDCANCEL,260,218,50,14
-END
-
-IDD_PROCSERVICES DIALOGEX 0, 0, 260, 261
-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 "Services",IDC_SERVICES_LAYOUT,7,7,246,247,NOT WS_VISIBLE | WS_BORDER
-END
-
-IDD_SHADOWSESSION DIALOGEX 0, 0, 228, 84
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Remote Control"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "To end the remote control session, press this key and the modifiers selected below:",IDC_STATIC,7,7,214,19
- COMBOBOX IDC_VIRTUALKEY,7,27,74,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
- CONTROL "Shift",IDC_SHIFT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,47,31,10
- CONTROL "Ctrl",IDC_CTRL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,49,47,27,10
- CONTROL "Alt",IDC_ALT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,89,47,25,10
- DEFPUSHBUTTON "OK",IDOK,117,63,50,14
- PUSHBUTTON "Cancel",IDCANCEL,171,63,50,14
-END
-
-IDD_TOKCAPABILITIES DIALOGEX 0, 0, 270, 228
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Capabilities"
-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,256,214
-END
-
-IDD_TOKATTRIBUTES DIALOGEX 0, 0, 270, 228
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Attributes"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x32,7,7,256,214,WS_EX_CLIENTEDGE
-END
-
-IDD_SYSINFO_CPU DIALOGEX 0, 0, 316, 195
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CAPTION | WS_SYSMENU
-EXSTYLE WS_EX_CONTROLPARENT
-CAPTION "CPU"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- RTEXT "CPU name",IDC_CPUNAME,41,4,274,16,SS_WORDELLIPSIS
- LTEXT "CPU",IDC_TITLE,0,0,37,21
- LTEXT "Panel layout",IDC_LAYOUT,0,105,315,88,NOT WS_VISIBLE
- LTEXT "Graph layout",IDC_GRAPH_LAYOUT,0,22,315,82,NOT WS_VISIBLE
-END
-
-IDD_SYSINFO_CPUPANEL DIALOGEX 0, 0, 237, 86
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU
-EXSTYLE WS_EX_CONTROLPARENT
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "Utilization:",IDC_STATIC,0,3,34,8
- LTEXT "Speed:",IDC_STATIC,108,3,24,8
- LTEXT "Static",IDC_UTILIZATION,40,0,62,15
- LTEXT "Static",IDC_SPEED,137,0,100,15
- GROUPBOX "System",IDC_STATIC,0,17,97,55
- LTEXT "Processes",IDC_STATIC,7,28,33,8
- LTEXT "Threads",IDC_STATIC,7,38,27,8
- LTEXT "Handles",IDC_STATIC,7,48,26,8
- LTEXT "Uptime",IDC_STATIC,7,58,23,8
- RTEXT "Static",IDC_ZPROCESSES_V,45,28,46,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZTHREADS_V,45,38,46,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZHANDLES_V,45,48,46,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZUPTIME_V,46,58,45,8,SS_ENDELLIPSIS
- CONTROL "&Show one graph per CPU",IDC_ONEGRAPHPERCPU,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,0,76,96,10
- GROUPBOX "CPU",IDC_STATIC,101,17,136,55
- LTEXT "Context switches delta",IDC_STATIC,109,28,76,8
- LTEXT "Interrupts delta",IDC_STATIC,109,38,52,8
- LTEXT "DPCs delta",IDC_STATIC,109,48,36,8
- LTEXT "System calls delta",IDC_STATIC,109,58,60,8
- RTEXT "Static",IDC_ZCONTEXTSWITCHESDELTA_V,191,28,40,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZINTERRUPTSDELTA_V,185,39,46,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZDPCSDELTA_V,181,48,50,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZSYSTEMCALLSDELTA_V,179,59,52,8,SS_ENDELLIPSIS
-END
-
-IDD_SYSINFO_MEMPANEL DIALOGEX 0, 0, 358, 171
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU
-EXSTYLE WS_EX_CONTROLPARENT
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- GROUPBOX "Commit charge",IDC_STATIC,0,0,108,44
- LTEXT "Current",IDC_STATIC,7,11,26,8
- LTEXT "Peak",IDC_STATIC,7,21,16,8
- LTEXT "Limit",IDC_STATIC,7,31,15,8
- RTEXT "Static",IDC_ZCOMMITCURRENT_V,45,11,56,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZCOMMITPEAK_V,41,21,60,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZCOMMITLIMIT_V,40,31,61,8,SS_ENDELLIPSIS
- GROUPBOX "Physical memory",IDC_STATIC,112,0,118,73
- LTEXT "Current",IDC_STATIC,120,11,26,8
- LTEXT "Cache WS",IDC_STATIC,120,41,34,8
- RTEXT "Static",IDC_ZPHYSICALCURRENT_V,165,11,57,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZPHYSICALTOTAL_V,167,21,55,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZPHYSICALCACHEWS_V,159,41,63,8,SS_ENDELLIPSIS
- LTEXT "Total",IDC_STATIC,120,21,17,8
- LTEXT "Kernel WS",IDC_STATIC,120,51,34,8
- RTEXT "Static",IDC_ZPHYSICALKERNELWS_V,167,51,55,8,SS_ENDELLIPSIS
- LTEXT "Driver WS",IDC_STATIC,120,61,33,8
- RTEXT "Static",IDC_ZPHYSICALDRIVERWS_V,163,61,59,8,SS_ENDELLIPSIS
- GROUPBOX "Paged pool",IDC_STATIC,0,47,108,64
- LTEXT "Working set",IDC_STATIC,7,58,40,8
- LTEXT "Limit",IDC_STATIC,7,78,15,8
- RTEXT "Static",IDC_ZPAGEDWORKINGSET_V,54,58,47,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZPAGEDVIRTUALSIZE_V,52,68,49,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZPAGEDLIMIT_V,48,78,53,8,SS_ENDELLIPSIS
- LTEXT "Virtual size",IDC_STATIC,7,68,36,8
- LTEXT "Allocs delta",IDC_STATIC,7,88,38,8
- RTEXT "Static",IDC_ZPAGEDALLOCSDELTA_V,53,88,48,8,SS_ENDELLIPSIS
- LTEXT "Frees delta",IDC_STATIC,7,98,38,8
- RTEXT "Static",IDC_ZPAGEDFREESDELTA_V,51,98,50,8,SS_ENDELLIPSIS
- GROUPBOX "Non-paged pool",IDC_STATIC,0,114,108,55
- LTEXT "Usage",IDC_STATIC,7,125,21,8
- LTEXT "Allocs delta",IDC_STATIC,7,145,38,8
- RTEXT "Static",IDC_ZNONPAGEDUSAGE_V,54,125,47,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZNONPAGEDLIMIT_V,52,135,49,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZNONPAGEDALLOCSDELTA_V,56,145,45,8,SS_ENDELLIPSIS
- LTEXT "Limit",IDC_STATIC,7,135,15,8
- LTEXT "Frees delta",IDC_STATIC,7,155,38,8
- RTEXT "Static",IDC_ZNONPAGEDFREESDELTA_V,56,155,45,8,SS_ENDELLIPSIS
- GROUPBOX "Memory lists",IDC_STATIC,234,0,123,169
- LTEXT "Zeroed",IDC_STATIC,242,11,24,8
- LTEXT "Modified",IDC_STATIC,242,31,28,8
- RTEXT "Static",IDC_ZLISTZEROED_V,304,11,47,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTFREE_V,302,21,49,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTMODIFIED_V,298,31,53,8,SS_ENDELLIPSIS
- LTEXT "Free",IDC_STATIC,242,21,16,8
- LTEXT "Modified no-write",IDC_STATIC,242,41,56,8
- RTEXT "Static",IDC_ZLISTMODIFIEDNOWRITE_V,303,41,48,8,SS_ENDELLIPSIS
- LTEXT "Standby",IDC_STATIC,242,61,28,8
- LTEXT "Priority 0",IDC_STATIC,251,71,30,8
- LTEXT "Priority 1",IDC_STATIC,251,80,30,8
- LTEXT "Priority 2",IDC_STATIC,251,90,30,8
- LTEXT "Priority 3",IDC_STATIC,251,100,30,8
- LTEXT "Priority 4",IDC_STATIC,251,110,30,8
- LTEXT "Priority 5",IDC_STATIC,251,120,30,8
- LTEXT "Priority 6",IDC_STATIC,251,130,30,8
- LTEXT "Priority 7",IDC_STATIC,251,140,30,8
- RTEXT "Static",IDC_ZLISTSTANDBY_V,303,61,48,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTSTANDBY0_V,303,71,48,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTSTANDBY1_V,303,80,48,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTSTANDBY2_V,303,90,48,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTSTANDBY3_V,303,100,48,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTSTANDBY4_V,303,110,48,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTSTANDBY5_V,303,120,48,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTSTANDBY6_V,303,130,48,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTSTANDBY7_V,303,140,48,8,SS_ENDELLIPSIS
- GROUPBOX "Paging",IDC_STATIC,112,75,118,55
- LTEXT "Page faults delta",IDC_STATIC,120,86,57,8
- LTEXT "Pagefile writes delta",IDC_STATIC,120,106,68,8
- RTEXT "Static",IDC_ZPAGINGPAGEFAULTSDELTA_V,183,86,39,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZPAGINGPAGEREADSDELTA_V,179,96,43,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZPAGINGPAGEFILEWRITESDELTA_V,189,106,33,8,SS_ENDELLIPSIS
- LTEXT "Page reads delta",IDC_STATIC,120,96,58,8
- LTEXT "Mapped writes delta",IDC_STATIC,120,116,68,8
- RTEXT "Static",IDC_ZPAGINGMAPPEDWRITESDELTA_V,191,116,31,8,SS_ENDELLIPSIS
- LTEXT "Modified pagefile",IDC_STATIC,242,51,55,8
- RTEXT "Static",IDC_ZLISTMODIFIEDPAGEFILE_V,303,51,48,8,SS_ENDELLIPSIS
- PUSHBUTTON "&More",IDC_MORE,242,152,50,14
- RTEXT "Static",IDC_ZPHYSICALRESERVED_V,167,31,55,8,SS_ENDELLIPSIS
- LTEXT "Reserved",IDC_STATIC,120,31,32,8
-END
-
-IDD_SYSINFO_MEM DIALOGEX 0, 0, 316, 250
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CAPTION | WS_SYSMENU
-EXSTYLE WS_EX_CONTROLPARENT
-CAPTION "Memory"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "Memory",IDC_TITLE,0,0,110,21
- LTEXT "Panel layout",IDC_LAYOUT,0,74,315,175,NOT WS_VISIBLE
- LTEXT "Graph layout",IDC_GRAPH_LAYOUT,0,22,315,51,NOT WS_VISIBLE
- RTEXT "Total physical",IDC_TOTALPHYSICAL,127,4,188,16,SS_WORDELLIPSIS
- LTEXT "Commit charge:",IDC_COMMIT_L,111,1,52,8
- LTEXT "Physical memory:",IDC_PHYSICAL_L,111,7,56,8
-END
-
-IDD_SYSINFO_IO DIALOGEX 0, 0, 316, 187
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CAPTION | WS_SYSMENU
-CAPTION "I/O"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "I/O",IDC_TITLE,0,0,110,21
- LTEXT "Panel layout",IDC_LAYOUT,0,109,315,78,NOT WS_VISIBLE
- LTEXT "Graph layout",IDC_GRAPH_LAYOUT,0,22,315,84,NOT WS_VISIBLE
-END
-
-IDD_SYSINFO_IOPANEL DIALOGEX 0, 0, 276, 75
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- GROUPBOX "I/O deltas",IDC_STATIC,0,0,133,74
- LTEXT "Reads delta",IDC_STATIC,7,11,40,8
- LTEXT "Read bytes delta",IDC_STATIC,7,21,56,8
- LTEXT "Writes delta",IDC_STATIC,7,31,40,8
- LTEXT "Write bytes delta",IDC_STATIC,7,41,57,8
- RTEXT "Static",IDC_ZREADSDELTA_V,59,11,67,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZREADBYTESDELTA_V,75,21,51,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZWRITESDELTA_V,57,31,69,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZWRITEBYTESDELTA_V,73,41,53,8,SS_ENDELLIPSIS
- LTEXT "Other delta",IDC_STATIC,7,51,38,8
- LTEXT "Other bytes delta",IDC_STATIC,7,61,58,8
- RTEXT "Static",IDC_ZOTHERDELTA_V,67,51,59,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZOTHERBYTESDELTA_V,81,61,45,8,SS_ENDELLIPSIS
- GROUPBOX "I/O totals",IDC_STATIC,137,0,133,74
- LTEXT "Reads",IDC_STATIC,145,11,21,8
- LTEXT "Read bytes",IDC_STATIC,145,21,38,8
- LTEXT "Writes",IDC_STATIC,145,31,22,8
- LTEXT "Write bytes",IDC_STATIC,145,41,38,8
- RTEXT "Static",IDC_ZREADS_V,197,11,67,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZREADBYTES_V,192,21,72,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZWRITES_V,195,31,69,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZWRITEBYTES_V,190,41,74,8,SS_ENDELLIPSIS
- LTEXT "Other",IDC_STATIC,145,51,20,8
- LTEXT "Other bytes",IDC_STATIC,145,61,40,8
- RTEXT "Static",IDC_ZOTHER_V,191,51,73,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZOTHERBYTES_V,192,61,72,8,SS_ENDELLIPSIS
-END
-
-IDD_MEMLISTS DIALOGEX 0, 0, 228, 195
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
-EXSTYLE WS_EX_TOPMOST
-CAPTION "Memory Lists"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- DEFPUSHBUTTON "Close",IDOK,171,174,50,14
- LTEXT "Zeroed",IDC_STATIC,7,7,24,8
- LTEXT "Free",IDC_STATIC,7,17,16,8
- LTEXT "Modified",IDC_STATIC,7,28,28,8
- LTEXT "Modified no-write",IDC_STATIC,7,39,56,8
- LTEXT "Bad",IDC_STATIC,7,60,13,8
- LTEXT "Standby",IDC_STATIC,7,72,28,8
- LTEXT "Priority 0",IDC_STATIC,23,83,30,8
- LTEXT "Priority 1",IDC_STATIC,23,94,30,8
- LTEXT "Priority 2",IDC_STATIC,23,105,30,8
- LTEXT "Priority 3",IDC_STATIC,23,116,30,8
- LTEXT "Priority 4",IDC_STATIC,23,128,30,8
- LTEXT "Priority 5",IDC_STATIC,23,139,30,8
- LTEXT "Priority 6",IDC_STATIC,23,150,30,8
- LTEXT "Priority 7",IDC_STATIC,23,161,30,8
- RTEXT "Static",IDC_ZLISTZEROED_V,73,7,59,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTFREE_V,73,17,59,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTMODIFIED_V,73,28,59,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTMODIFIEDNOWRITE_V,73,39,59,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTBAD_V,73,60,59,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTSTANDBY_V,73,72,59,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTSTANDBY0_V,73,83,59,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTSTANDBY1_V,73,94,59,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTSTANDBY2_V,73,105,59,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTSTANDBY3_V,73,116,59,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTSTANDBY4_V,73,128,59,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTSTANDBY5_V,73,139,59,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTSTANDBY6_V,73,150,59,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTSTANDBY7_V,73,161,59,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTREPURPOSED_V,162,72,59,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTREPURPOSED0_V,162,84,59,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTREPURPOSED1_V,162,95,59,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTREPURPOSED2_V,162,106,59,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTREPURPOSED3_V,162,117,59,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTREPURPOSED4_V,162,128,59,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTREPURPOSED5_V,162,139,59,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTREPURPOSED6_V,162,150,59,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZLISTREPURPOSED7_V,162,161,59,8,SS_ENDELLIPSIS
- RTEXT "(Repurposed)",IDC_STATIC,162,60,59,8
- PUSHBUTTON "&Empty",IDC_EMPTY,117,174,50,14
- LTEXT "Modified pagefile",IDC_STATIC,7,49,55,8
- RTEXT "Static",IDC_ZLISTMODIFIEDPAGEFILE_V,73,49,59,8,SS_ENDELLIPSIS
-END
-
-IDD_CONTAINER DIALOGEX 0, 0, 316, 182
-STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU
-EXSTYLE WS_EX_CONTROLPARENT
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
-END
-
-IDD_SYSINFO_MEMPANELXP DIALOGEX 0, 0, 230, 171
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU
-EXSTYLE WS_EX_CONTROLPARENT
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- GROUPBOX "Commit charge",-1,0,0,108,44
- LTEXT "Current",-1,7,11,26,8
- LTEXT "Peak",-1,7,21,16,8
- LTEXT "Limit",-1,7,31,15,8
- RTEXT "Static",IDC_ZCOMMITCURRENT_V,45,11,56,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZCOMMITPEAK_V,41,21,60,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZCOMMITLIMIT_V,40,31,61,8,SS_ENDELLIPSIS
- GROUPBOX "Physical memory",-1,112,0,118,64
- LTEXT "Current",-1,120,11,26,8
- LTEXT "Cache WS",-1,120,31,34,8
- RTEXT "Static",IDC_ZPHYSICALCURRENT_V,165,11,57,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZPHYSICALTOTAL_V,167,21,55,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZPHYSICALCACHEWS_V,159,31,63,8,SS_ENDELLIPSIS
- LTEXT "Total",-1,120,21,17,8
- LTEXT "Kernel WS",-1,120,41,34,8
- RTEXT "Static",IDC_ZPHYSICALKERNELWS_V,167,41,55,8,SS_ENDELLIPSIS
- LTEXT "Driver WS",-1,120,51,33,8
- RTEXT "Static",IDC_ZPHYSICALDRIVERWS_V,163,51,59,8,SS_ENDELLIPSIS
- GROUPBOX "Paged pool",-1,0,47,108,64
- LTEXT "Working set",-1,7,58,40,8
- LTEXT "Limit",-1,7,78,15,8
- RTEXT "Static",IDC_ZPAGEDWORKINGSET_V,54,58,47,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZPAGEDVIRTUALSIZE_V,52,68,49,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZPAGEDLIMIT_V,48,78,53,8,SS_ENDELLIPSIS
- LTEXT "Virtual size",-1,7,68,36,8
- LTEXT "Allocs delta",-1,7,88,38,8
- RTEXT "Static",IDC_ZPAGEDALLOCSDELTA_V,53,88,48,8,SS_ENDELLIPSIS
- LTEXT "Frees delta",-1,7,98,38,8
- RTEXT "Static",IDC_ZPAGEDFREESDELTA_V,51,98,50,8,SS_ENDELLIPSIS
- GROUPBOX "Non-paged pool",-1,0,114,108,55
- LTEXT "Usage",-1,7,125,21,8
- LTEXT "Allocs delta",-1,7,145,38,8
- RTEXT "Static",IDC_ZNONPAGEDUSAGE_V,54,125,47,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZNONPAGEDLIMIT_V,52,135,49,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZNONPAGEDALLOCSDELTA_V,56,145,45,8,SS_ENDELLIPSIS
- LTEXT "Limit",-1,7,135,15,8
- LTEXT "Frees delta",-1,7,155,38,8
- RTEXT "Static",IDC_ZNONPAGEDFREESDELTA_V,56,155,45,8,SS_ENDELLIPSIS
- GROUPBOX "Paging",-1,112,67,118,55
- LTEXT "Page faults delta",-1,120,78,57,8
- LTEXT "Pagefile writes delta",-1,120,98,68,8
- RTEXT "Static",IDC_ZPAGINGPAGEFAULTSDELTA_V,183,78,39,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZPAGINGPAGEREADSDELTA_V,179,88,43,8,SS_ENDELLIPSIS
- RTEXT "Static",IDC_ZPAGINGPAGEFILEWRITESDELTA_V,189,98,33,8,SS_ENDELLIPSIS
- LTEXT "Page reads delta",-1,120,88,58,8
- LTEXT "Mapped writes delta",-1,120,108,68,8
- RTEXT "Static",IDC_ZPAGINGMAPPEDWRITESDELTA_V,191,108,31,8,SS_ENDELLIPSIS
-END
-
-IDD_MINIINFO DIALOGEX 0, 0, 217, 150
-STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "Content layout",IDC_LAYOUT,4,3,210,128,NOT WS_VISIBLE
- CONTROL "Section",IDC_SECTION,"Static",SS_LEFTNOWORDWRAP | SS_NOTIFY | SS_ENDELLIPSIS | WS_GROUP,4,134,177,13
- PUSHBUTTON "Options",IDC_OPTIONS,183,133,15,14,BS_ICON
- CONTROL "Pin",IDC_PIN,"Button",BS_AUTOCHECKBOX | BS_ICON | BS_PUSHLIKE | WS_TABSTOP,199,133,15,14
-END
-
-IDD_MINIINFO_LIST DIALOGEX 0, 0, 217, 141
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "CPU"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x82,0,0,217,140,WS_EX_CLIENTEDGE
-END
-
-IDD_MITIGATION DIALOGEX 0, 0, 277, 217
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
-CAPTION "Mitigation Policies"
-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,263,108
- LTEXT "Description:",IDC_DESCRIPTIONLABEL,7,118,38,8
- EDITTEXT IDC_DESCRIPTION,7,129,263,62,ES_MULTILINE | ES_READONLY | WS_VSCROLL
- DEFPUSHBUTTON "OK",IDOK,220,196,50,14
-END
-
-IDD_EDITENV DIALOGEX 0, 0, 311, 177
-STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
-CAPTION "Edit Environment Variable"
-FONT 8, "MS Shell Dlg", 400, 0, 0x1
-BEGIN
- LTEXT "Name:",IDC_STATIC,7,8,21,8
- EDITTEXT IDC_NAME,38,7,266,12,ES_AUTOHSCROLL
- LTEXT "Value:",IDC_STATIC,7,25,21,8
- EDITTEXT IDC_VALUE,38,24,266,128,ES_MULTILINE | WS_VSCROLL
- DEFPUSHBUTTON "OK",IDOK,200,156,50,14
- PUSHBUTTON "Cancel",IDCANCEL,254,156,50,14
-END
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// DESIGNINFO
-//
-
-#ifdef APSTUDIO_INVOKED
-GUIDELINES DESIGNINFO
-BEGIN
- IDD_PROCGENERAL, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 253
- TOPMARGIN, 7
- BOTTOMMARGIN, 253
- END
-
- IDD_PROCMODULES, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 253
- TOPMARGIN, 7
- BOTTOMMARGIN, 253
- END
-
- IDD_PROCTHREADS, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 253
- TOPMARGIN, 7
- BOTTOMMARGIN, 253
- END
-
- IDD_PROCHANDLES, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 253
- TOPMARGIN, 7
- BOTTOMMARGIN, 253
- END
-
- IDD_PROCENVIRONMENT, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 253
- TOPMARGIN, 7
- BOTTOMMARGIN, 253
- END
-
- IDD_THRDSTACK, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 254
- TOPMARGIN, 7
- BOTTOMMARGIN, 221
- END
-
- IDD_ABOUT, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 263
- TOPMARGIN, 7
- BOTTOMMARGIN, 188
- END
-
- IDD_SRVLIST, DIALOG
- BEGIN
- END
-
- IDD_SRVGENERAL, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 275
- TOPMARGIN, 7
- BOTTOMMARGIN, 176
- END
-
- IDD_HNDLGENERAL, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 253
- TOPMARGIN, 7
- BOTTOMMARGIN, 174
- END
-
- IDD_INFORMATION, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 310
- TOPMARGIN, 7
- BOTTOMMARGIN, 177
- END
-
- IDD_FINDOBJECTS, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 350
- TOPMARGIN, 7
- BOTTOMMARGIN, 226
- END
-
- IDD_OBJTOKEN, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 253
- TOPMARGIN, 7
- BOTTOMMARGIN, 253
- END
-
- IDD_HIDDENPROCESSES, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 330
- TOPMARGIN, 7
- BOTTOMMARGIN, 214
- END
-
- IDD_RUNAS, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 271
- TOPMARGIN, 7
- BOTTOMMARGIN, 120
- END
-
- IDD_PROGRESS, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 209
- TOPMARGIN, 7
- BOTTOMMARGIN, 55
- END
-
- IDD_PAGEFILES, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 315
- TOPMARGIN, 7
- BOTTOMMARGIN, 155
- END
-
- IDD_TOKGENERAL, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 263
- TOPMARGIN, 7
- BOTTOMMARGIN, 221
- END
-
- IDD_TOKADVANCED, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 229
- TOPMARGIN, 7
- BOTTOMMARGIN, 179
- END
-
- IDD_OBJJOB, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 253
- TOPMARGIN, 7
- BOTTOMMARGIN, 253
- END
-
- IDD_OBJEVENT, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 179
- TOPMARGIN, 7
- BOTTOMMARGIN, 69
- END
-
- IDD_OBJMUTANT, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 179
- TOPMARGIN, 7
- BOTTOMMARGIN, 69
- END
-
- IDD_OBJSEMAPHORE, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 179
- TOPMARGIN, 7
- BOTTOMMARGIN, 69
- END
-
- IDD_OBJTIMER, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 179
- TOPMARGIN, 7
- BOTTOMMARGIN, 69
- END
-
- IDD_JOBSTATISTICS, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 252
- TOPMARGIN, 7
- BOTTOMMARGIN, 179
- END
-
- IDD_OBJEVENTPAIR, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 179
- TOPMARGIN, 7
- BOTTOMMARGIN, 69
- END
-
- IDD_OBJSECTION, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 248
- TOPMARGIN, 7
- BOTTOMMARGIN, 69
- END
-
- IDD_AFFINITY, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 272
- TOPMARGIN, 7
- BOTTOMMARGIN, 220
- END
-
- IDD_SYSINFO, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 416
- TOPMARGIN, 7
- BOTTOMMARGIN, 240
- END
-
- IDD_EDITMESSAGE, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 275
- TOPMARGIN, 7
- BOTTOMMARGIN, 156
- END
-
- IDD_SESSION, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 194
- TOPMARGIN, 7
- BOTTOMMARGIN, 142
- END
-
- IDD_PROCMEMORY, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 253
- TOPMARGIN, 7
- BOTTOMMARGIN, 253
- END
-
- IDD_CHOOSE, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 192
- TOPMARGIN, 7
- BOTTOMMARGIN, 66
- END
-
- IDD_OPTGENERAL, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 243
- TOPMARGIN, 7
- BOTTOMMARGIN, 147
- END
-
- IDD_OPTHIGHLIGHTING, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 243
- TOPMARGIN, 7
- BOTTOMMARGIN, 167
- END
-
- IDD_CHOOSECOLUMNS, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 374
- TOPMARGIN, 7
- BOTTOMMARGIN, 200
- END
-
- IDD_NETSTACK, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 254
- TOPMARGIN, 7
- BOTTOMMARGIN, 221
- END
-
- IDD_CREATESERVICE, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 280
- TOPMARGIN, 7
- BOTTOMMARGIN, 126
- END
-
- IDD_PROCPERFORMANCE, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 253
- TOPMARGIN, 7
- BOTTOMMARGIN, 253
- END
-
- IDD_PROCSTATISTICS, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 253
- TOPMARGIN, 7
- BOTTOMMARGIN, 253
- END
-
- IDD_OPTADVANCED, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 243
- TOPMARGIN, 7
- BOTTOMMARGIN, 143
- END
-
- IDD_GDIHANDLES, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 344
- TOPMARGIN, 7
- BOTTOMMARGIN, 300
- END
-
- IDD_LOG, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 306
- TOPMARGIN, 7
- BOTTOMMARGIN, 296
- END
-
- IDD_OPTSYMBOLS, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 243
- TOPMARGIN, 7
- BOTTOMMARGIN, 68
- END
-
- IDD_MEMEDIT, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 434
- TOPMARGIN, 7
- BOTTOMMARGIN, 262
- END
-
- IDD_MEMPROTECT, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 263
- TOPMARGIN, 7
- BOTTOMMARGIN, 164
- END
-
- IDD_MEMRESULTS, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 306
- TOPMARGIN, 7
- BOTTOMMARGIN, 259
- END
-
- IDD_MEMSTRING, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 234
- TOPMARGIN, 7
- BOTTOMMARGIN, 79
- END
-
- IDD_OPTGRAPHS, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 243
- TOPMARGIN, 7
- BOTTOMMARGIN, 149
- END
-
- IDD_PLUGINS, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 284
- TOPMARGIN, 7
- BOTTOMMARGIN, 265
- END
-
- IDD_HANDLESTATS, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 212
- TOPMARGIN, 7
- BOTTOMMARGIN, 168
- END
-
- IDD_PROCRECORD, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 253
- TOPMARGIN, 7
- BOTTOMMARGIN, 195
- END
-
- IDD_CHOOSEPROCESS, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 310
- TOPMARGIN, 7
- BOTTOMMARGIN, 232
- END
-
- IDD_PROCSERVICES, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 253
- TOPMARGIN, 7
- BOTTOMMARGIN, 254
- END
-
- IDD_SHADOWSESSION, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 221
- TOPMARGIN, 7
- BOTTOMMARGIN, 77
- END
-
- IDD_TOKCAPABILITIES, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 263
- TOPMARGIN, 7
- BOTTOMMARGIN, 221
- END
-
- IDD_TOKATTRIBUTES, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 263
- TOPMARGIN, 7
- BOTTOMMARGIN, 221
- END
-
- IDD_SYSINFO_CPU, DIALOG
- BEGIN
- BOTTOMMARGIN, 193
- END
-
- IDD_SYSINFO_CPUPANEL, DIALOG
- BEGIN
- BOTTOMMARGIN, 85
- END
-
- IDD_SYSINFO_MEMPANEL, DIALOG
- BEGIN
- END
-
- IDD_SYSINFO_MEM, DIALOG
- BEGIN
- BOTTOMMARGIN, 247
- END
-
- IDD_SYSINFO_IO, DIALOG
- BEGIN
- END
-
- IDD_SYSINFO_IOPANEL, DIALOG
- BEGIN
- BOTTOMMARGIN, 74
- END
-
- IDD_MEMLISTS, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 221
- TOPMARGIN, 7
- BOTTOMMARGIN, 188
- END
-
- IDD_CONTAINER, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 309
- TOPMARGIN, 7
- BOTTOMMARGIN, 175
- END
-
- IDD_SYSINFO_MEMPANELXP, DIALOG
- BEGIN
- END
-
- IDD_MINIINFO, DIALOG
- BEGIN
- LEFTMARGIN, 4
- RIGHTMARGIN, 214
- TOPMARGIN, 3
- BOTTOMMARGIN, 147
- END
-
- IDD_MINIINFO_LIST, DIALOG
- BEGIN
- END
-
- IDD_MITIGATION, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 270
- TOPMARGIN, 7
- BOTTOMMARGIN, 210
- END
-
- IDD_EDITENV, DIALOG
- BEGIN
- LEFTMARGIN, 7
- RIGHTMARGIN, 304
- TOPMARGIN, 7
- BOTTOMMARGIN, 170
- END
-END
-#endif // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Accelerator
-//
-
-IDR_MAINWND_ACCEL ACCELERATORS
-BEGIN
- VK_ESCAPE, ID_ESC_EXIT, VIRTKEY, NOINVERT
- "F", ID_HACKER_FINDHANDLESORDLLS, VIRTKEY, CONTROL, NOINVERT
- "R", ID_HACKER_RUN, VIRTKEY, CONTROL, NOINVERT
- "R", ID_HACKER_RUNAS, VIRTKEY, SHIFT, CONTROL, NOINVERT
- "S", ID_HACKER_SAVE, VIRTKEY, CONTROL, NOINVERT
- "L", ID_HELP_LOG, VIRTKEY, CONTROL, NOINVERT
- "M", ID_PROCESS_SEARCHONLINE, VIRTKEY, CONTROL, NOINVERT
- VK_TAB, ID_TAB_NEXT, VIRTKEY, CONTROL, NOINVERT
- VK_TAB, ID_TAB_PREV, VIRTKEY, SHIFT, CONTROL, NOINVERT
- VK_F5, ID_VIEW_REFRESH, VIRTKEY, NOINVERT
- "I", ID_VIEW_SYSTEMINFORMATION, VIRTKEY, CONTROL, NOINVERT
- VK_PAUSE, ID_VIEW_UPDATEAUTOMATICALLY, VIRTKEY, NOINVERT
- VK_F6, ID_VIEW_UPDATEAUTOMATICALLY, VIRTKEY, NOINVERT
-END
-
-IDR_SYSINFO_ACCEL ACCELERATORS
-BEGIN
- "1", ID_DIGIT1, VIRTKEY, NOINVERT
- "2", ID_DIGIT2, VIRTKEY, NOINVERT
- "3", ID_DIGIT3, VIRTKEY, NOINVERT
- "4", ID_DIGIT4, VIRTKEY, NOINVERT
- "5", ID_DIGIT5, VIRTKEY, NOINVERT
- "6", ID_DIGIT6, VIRTKEY, NOINVERT
- "7", ID_DIGIT7, VIRTKEY, NOINVERT
- "8", ID_DIGIT8, VIRTKEY, NOINVERT
- "9", ID_DIGIT9, VIRTKEY, NOINVERT
- "B", IDC_BACK, VIRTKEY, ALT, NOINVERT
- VK_BACK, IDC_BACK, VIRTKEY, NOINVERT
- VK_F6, IDC_PAUSE, VIRTKEY, NOINVERT
- VK_PAUSE, IDC_PAUSE, VIRTKEY, NOINVERT
- VK_F5, IDC_REFRESH, VIRTKEY, NOINVERT
- VK_F11, IDC_MAXSCREEN, VIRTKEY, NOINVERT
-END
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Bitmap
-//
-
-IDB_CROSS BITMAP "resources\\cross.bmp"
-
-IDB_TICK BITMAP "resources\\tick.bmp"
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// RT_MANIFEST
-//
-
-IDR_RT_MANIFEST RT_MANIFEST "ProcessHacker.manifest"
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// AFX_DIALOG_LAYOUT
-//
-
-IDD_FINDOBJECTS AFX_DIALOG_LAYOUT
-BEGIN
- 0
-END
-
-IDD_OPTADVANCED AFX_DIALOG_LAYOUT
-BEGIN
- 0
-END
-
-IDD_SYSINFO_MEMPANEL AFX_DIALOG_LAYOUT
-BEGIN
- 0
-END
-
-IDD_ABOUT AFX_DIALOG_LAYOUT
-BEGIN
- 0
-END
-
-IDD_PROCGENERAL AFX_DIALOG_LAYOUT
-BEGIN
- 0
-END
-
-IDD_MITIGATION AFX_DIALOG_LAYOUT
-BEGIN
- 0
-END
-
-IDD_INFORMATION AFX_DIALOG_LAYOUT
-BEGIN
- 0
-END
-
-IDD_OPTGENERAL AFX_DIALOG_LAYOUT
-BEGIN
- 0
-END
-
-IDD_MINIINFO AFX_DIALOG_LAYOUT
-BEGIN
- 0
-END
-
-IDD_PROCTHREADS AFX_DIALOG_LAYOUT
-BEGIN
- 0
-END
-
-IDD_PROCRECORD AFX_DIALOG_LAYOUT
-BEGIN
- 0
-END
-
-IDD_PROCENVIRONMENT AFX_DIALOG_LAYOUT
-BEGIN
- 0
-END
-
-IDD_EDITENV AFX_DIALOG_LAYOUT
-BEGIN
- 0
-END
-
-#endif // English (Australia) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-
-
-/////////////////////////////////////////////////////////////////////////////
-#endif // not APSTUDIO_INVOKED
-
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "winres.h"
+#include "include/phappres.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""\r\n"
+ "#include ""include/phappres.h""\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_PROCESSHACKER ICON "ProcessHacker.ico"
+
+IDI_PHAPPLICATION ICON "resources\\application.ico"
+
+IDI_COG ICON "resources\\cog.ico"
+
+IDI_PIN ICON "resources\\pin.ico"
+
+IDI_FOLDER ICON "resources\\folder.ico"
+
+IDI_PENCIL ICON "resources\\pencil.ico"
+
+IDI_MAGNIFIER ICON "resources\\magnifier.ico"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_MAINWND MENU
+BEGIN
+ POPUP "&Hacker"
+ BEGIN
+ MENUITEM "&Run...\aCtrl+R", ID_HACKER_RUN
+ MENUITEM "Run &as...\aCtrl+Shift+R", ID_HACKER_RUNAS
+ MENUITEM "Show &details for all processes", ID_HACKER_SHOWDETAILSFORALLPROCESSES
+ MENUITEM SEPARATOR
+ MENUITEM "&Save...\aCtrl+S", ID_HACKER_SAVE
+ MENUITEM "&Find handles or DLLs...\aCtrl+F", ID_HACKER_FINDHANDLESORDLLS
+ MENUITEM "&Options...", ID_HACKER_OPTIONS
+ MENUITEM "&Plugins...", ID_HACKER_PLUGINS
+ MENUITEM SEPARATOR
+ POPUP "&Computer"
+ BEGIN
+ MENUITEM "&Lock", ID_COMPUTER_LOCK
+ MENUITEM "Log o&ff", ID_COMPUTER_LOGOFF
+ MENUITEM SEPARATOR
+ MENUITEM "&Sleep", ID_COMPUTER_SLEEP
+ MENUITEM "&Hibernate", ID_COMPUTER_HIBERNATE
+ MENUITEM SEPARATOR
+ MENUITEM "R&estart", ID_COMPUTER_RESTART
+ MENUITEM "Restart to boot options", ID_COMPUTER_RESTARTBOOTOPTIONS
+ MENUITEM "Shu&t down", ID_COMPUTER_SHUTDOWN
+ MENUITEM "H&ybrid shut down", ID_COMPUTER_SHUTDOWNHYBRID
+ END
+ MENUITEM "E&xit", ID_HACKER_EXIT
+ END
+ POPUP "&View"
+ BEGIN
+ MENUITEM "System &information\aCtrl+I", ID_VIEW_SYSTEMINFORMATION
+ MENUITEM "&Tray icons", ID_VIEW_TRAYICONS
+ MENUITEM SEPARATOR
+ MENUITEM "", ID_VIEW_SECTIONPLACEHOLDER
+ MENUITEM SEPARATOR
+ MENUITEM "&Always on top", ID_VIEW_ALWAYSONTOP
+ POPUP "&Opacity"
+ BEGIN
+ MENUITEM "&10%", ID_OPACITY_10
+ MENUITEM "&20%", ID_OPACITY_20
+ MENUITEM "&30%", ID_OPACITY_30
+ MENUITEM "&40%", ID_OPACITY_40
+ MENUITEM "&50%", ID_OPACITY_50
+ MENUITEM "&60%", ID_OPACITY_60
+ MENUITEM "&70%", ID_OPACITY_70
+ MENUITEM "&80%", ID_OPACITY_80
+ MENUITEM "&90%", ID_OPACITY_90
+ MENUITEM "&Opaque", ID_OPACITY_OPAQUE
+ END
+ MENUITEM SEPARATOR
+ MENUITEM "&Refresh\aF5", ID_VIEW_REFRESH
+ POPUP "Refresh i&nterval"
+ BEGIN
+ MENUITEM "&Fast (0.5s)", ID_UPDATEINTERVAL_FAST
+ MENUITEM "&Normal (1s)", ID_UPDATEINTERVAL_NORMAL
+ MENUITEM "&Below normal (2s)", ID_UPDATEINTERVAL_BELOWNORMAL
+ MENUITEM "&Slow (5s)", ID_UPDATEINTERVAL_SLOW
+ MENUITEM "&Very slow (10s)", ID_UPDATEINTERVAL_VERYSLOW
+ END
+ MENUITEM "Refresh a&utomatically\aF6", ID_VIEW_UPDATEAUTOMATICALLY
+ END
+ POPUP "&Tools"
+ BEGIN
+ MENUITEM "&Create service...", ID_TOOLS_CREATESERVICE
+ MENUITEM "&Hidden processes", ID_TOOLS_HIDDENPROCESSES
+ MENUITEM "Inspect e&xecutable file...", ID_TOOLS_INSPECTEXECUTABLEFILE
+ MENUITEM "&Pagefiles", ID_TOOLS_PAGEFILES
+ MENUITEM "Start &Task Manager", ID_TOOLS_STARTTASKMANAGER
+ POPUP "&Permissions"
+ BEGIN
+ MENUITEM "Service Control Manager", ID_TOOLS_SCM_PERMISSIONS
+ END
+ END
+ POPUP "&Users"
+ BEGIN
+ MENUITEM "Dummy", ID_USERS_DUMMY
+ END
+ POPUP "H&elp"
+ BEGIN
+ MENUITEM "&Log\aCtrl+L", ID_HELP_LOG
+ MENUITEM "&Donate", ID_HELP_DONATE
+ MENUITEM "Debu&g console", ID_HELP_DEBUGCONSOLE
+ MENUITEM "&About", ID_HELP_ABOUT
+ END
+END
+
+IDR_THREAD MENU
+BEGIN
+ POPUP "Thread"
+ BEGIN
+ MENUITEM "&Inspect\aEnter", ID_THREAD_INSPECT
+ MENUITEM "T&erminate\aDel", ID_THREAD_TERMINATE
+ MENUITEM "&Suspend", ID_THREAD_SUSPEND
+ MENUITEM "Res&ume", ID_THREAD_RESUME
+ MENUITEM SEPARATOR
+ MENUITEM "Analy&ze", ID_ANALYZE_WAIT
+ MENUITEM "&Affinity", ID_THREAD_AFFINITY
+ MENUITEM "Critical", ID_THREAD_CRITICAL
+ MENUITEM "Per&missions", ID_THREAD_PERMISSIONS
+ MENUITEM "&Token", ID_THREAD_TOKEN
+ POPUP "&Priority"
+ BEGIN
+ MENUITEM "Time &critical", ID_PRIORITY_TIMECRITICAL
+ MENUITEM "&Highest", ID_PRIORITY_HIGHEST
+ MENUITEM "&Above normal", ID_PRIORITY_ABOVENORMAL
+ MENUITEM "&Normal", ID_PRIORITY_NORMAL
+ MENUITEM "&Below normal", ID_PRIORITY_BELOWNORMAL
+ MENUITEM "&Lowest", ID_PRIORITY_LOWEST
+ MENUITEM "&Idle", ID_PRIORITY_IDLE
+ END
+ POPUP "&I/O priority"
+ BEGIN
+ MENUITEM "&High", ID_IOPRIORITY_HIGH
+ MENUITEM "&Normal", ID_IOPRIORITY_NORMAL
+ MENUITEM "&Low", ID_IOPRIORITY_LOW
+ MENUITEM "&Very low", ID_IOPRIORITY_VERYLOW
+ END
+ POPUP "Pa&ge priority"
+ BEGIN
+ MENUITEM "&Normal", ID_PAGEPRIORITY_NORMAL
+ MENUITEM "&Below normal", ID_PAGEPRIORITY_BELOWNORMAL
+ MENUITEM "&Medium", ID_PAGEPRIORITY_MEDIUM
+ MENUITEM "&Low", ID_PAGEPRIORITY_LOW
+ MENUITEM "&Very low", ID_PAGEPRIORITY_VERYLOW
+ END
+ MENUITEM SEPARATOR
+ MENUITEM "&Copy\aCtrl+C", ID_THREAD_COPY
+ END
+END
+
+IDR_HANDLE MENU
+BEGIN
+ POPUP "Handle"
+ BEGIN
+ MENUITEM "C&lose\aDel", ID_HANDLE_CLOSE
+ MENUITEM "&Protected", ID_HANDLE_PROTECTED
+ MENUITEM "&Inherit", ID_HANDLE_INHERIT
+ MENUITEM SEPARATOR
+ MENUITEM "Prope&rties\aEnter", ID_HANDLE_PROPERTIES
+ MENUITEM SEPARATOR
+ MENUITEM "&Copy\aCtrl+C", ID_HANDLE_COPY
+ END
+END
+
+IDR_MODULE MENU
+BEGIN
+ POPUP "Module"
+ BEGIN
+ MENUITEM "&Unload\aDel", ID_MODULE_UNLOAD
+ MENUITEM SEPARATOR
+ MENUITEM "&Inspect\aEnter", ID_MODULE_INSPECT
+ MENUITEM "&Search online\aCtrl+M", ID_MODULE_SEARCHONLINE
+ MENUITEM "Open &file location\aCtrl+Enter", ID_MODULE_OPENFILELOCATION
+ MENUITEM "P&roperties", ID_MODULE_PROPERTIES
+ MENUITEM "&Copy\aCtrl+C", ID_MODULE_COPY
+ END
+END
+
+IDR_COMPUTER MENU
+BEGIN
+ POPUP "Computer"
+ BEGIN
+ MENUITEM "&Lock", ID_COMPUTER_LOCK
+ MENUITEM "Log o&ff", ID_COMPUTER_LOGOFF
+ MENUITEM SEPARATOR
+ MENUITEM "&Sleep", ID_COMPUTER_SLEEP
+ MENUITEM "&Hibernate", ID_COMPUTER_HIBERNATE
+ MENUITEM SEPARATOR
+ MENUITEM "R&estart", ID_COMPUTER_RESTART
+ MENUITEM "Restart to boot &options", ID_COMPUTER_RESTARTBOOTOPTIONS
+ MENUITEM "Shu&t down", ID_COMPUTER_SHUTDOWN
+ MENUITEM "H&ybrid shut down", ID_COMPUTER_SHUTDOWNHYBRID
+ END
+END
+
+IDR_PROCESS MENU
+BEGIN
+ POPUP "Process"
+ BEGIN
+ MENUITEM "T&erminate\aDel", ID_PROCESS_TERMINATE
+ MENUITEM "Terminate tree\aShift+Del", ID_PROCESS_TERMINATETREE
+ MENUITEM "&Suspend", ID_PROCESS_SUSPEND
+ MENUITEM "Res&ume", ID_PROCESS_RESUME
+ MENUITEM "Res&tart", ID_PROCESS_RESTART
+ MENUITEM SEPARATOR
+ MENUITEM "Create dump fi&le...", ID_PROCESS_CREATEDUMPFILE
+ MENUITEM "De&bug", ID_PROCESS_DEBUG
+ MENUITEM "Virtuali&zation", ID_PROCESS_VIRTUALIZATION
+ MENUITEM SEPARATOR
+ MENUITEM "&Affinity", ID_PROCESS_AFFINITY
+ POPUP "&Priority"
+ BEGIN
+ MENUITEM "&Real time", ID_PRIORITY_REALTIME
+ MENUITEM "&High", ID_PRIORITY_HIGH
+ MENUITEM "&Above normal", ID_PRIORITY_ABOVENORMAL
+ MENUITEM "&Normal", ID_PRIORITY_NORMAL
+ MENUITEM "&Below normal", ID_PRIORITY_BELOWNORMAL
+ MENUITEM "&Idle", ID_PRIORITY_IDLE
+ END
+ POPUP "&I/O priority"
+ BEGIN
+ MENUITEM "&High", ID_IOPRIORITY_HIGH
+ MENUITEM "&Normal", ID_IOPRIORITY_NORMAL
+ MENUITEM "&Low", ID_IOPRIORITY_LOW
+ MENUITEM "&Very low", ID_IOPRIORITY_VERYLOW
+ END
+ POPUP "&Miscellaneous"
+ BEGIN
+ MENUITEM "&Critical", ID_MISCELLANEOUS_SETCRITICAL
+ MENUITEM "&Detach from debugger", ID_MISCELLANEOUS_DETACHFROMDEBUGGER
+ MENUITEM "GDI &handles", ID_MISCELLANEOUS_GDIHANDLES
+ POPUP "Pa&ge priority"
+ BEGIN
+ MENUITEM "&Normal", ID_PAGEPRIORITY_NORMAL
+ MENUITEM "&Below normal", ID_PAGEPRIORITY_BELOWNORMAL
+ MENUITEM "&Medium", ID_PAGEPRIORITY_MEDIUM
+ MENUITEM "&Low", ID_PAGEPRIORITY_LOW
+ MENUITEM "&Very low", ID_PAGEPRIORITY_VERYLOW
+ END
+ MENUITEM "Reduce working &set", ID_MISCELLANEOUS_REDUCEWORKINGSET
+ MENUITEM "&Run as...", ID_MISCELLANEOUS_RUNAS
+ MENUITEM "Run &as this user...", ID_MISCELLANEOUS_RUNASTHISUSER
+ END
+ POPUP "&Window"
+ BEGIN
+ MENUITEM "Bring to &front", ID_WINDOW_BRINGTOFRONT
+ MENUITEM "&Restore", ID_WINDOW_RESTORE
+ MENUITEM "M&inimize", ID_WINDOW_MINIMIZE
+ MENUITEM "M&aximize", ID_WINDOW_MAXIMIZE
+ MENUITEM SEPARATOR
+ MENUITEM "&Close", ID_WINDOW_CLOSE
+ END
+ MENUITEM SEPARATOR
+ MENUITEM "Search &online\aCtrl+M", ID_PROCESS_SEARCHONLINE
+ MENUITEM "Open &file location\aCtrl+Enter", ID_PROCESS_OPENFILELOCATION
+ MENUITEM "P&roperties\aEnter", ID_PROCESS_PROPERTIES
+ MENUITEM "&Copy\aCtrl+C", ID_PROCESS_COPY
+ END
+END
+
+IDR_SERVICE MENU
+BEGIN
+ POPUP "Service"
+ BEGIN
+ MENUITEM "&Go to process", ID_SERVICE_GOTOPROCESS
+ MENUITEM "&Start", ID_SERVICE_START
+ MENUITEM "C&ontinue", ID_SERVICE_CONTINUE
+ MENUITEM "&Pause", ID_SERVICE_PAUSE
+ MENUITEM "S&top", ID_SERVICE_STOP
+ MENUITEM "&Delete\aDel", ID_SERVICE_DELETE
+ MENUITEM SEPARATOR
+ MENUITEM "Open &key", ID_SERVICE_OPENKEY
+ MENUITEM "Open &file location\aCtrl+Enter", ID_SERVICE_OPENFILELOCATION
+ MENUITEM "P&roperties\aEnter", ID_SERVICE_PROPERTIES
+ MENUITEM "&Copy\aCtrl+C", ID_SERVICE_COPY
+ END
+END
+
+IDR_FINDOBJ MENU
+BEGIN
+ POPUP "Object"
+ BEGIN
+ MENUITEM "C&lose\aDel", ID_OBJECT_CLOSE
+ MENUITEM SEPARATOR
+ MENUITEM "Go to owning &process", ID_OBJECT_GOTOOWNINGPROCESS
+ MENUITEM "Prope&rties", ID_OBJECT_PROPERTIES
+ MENUITEM SEPARATOR
+ MENUITEM "&Copy\aCtrl+C", ID_OBJECT_COPY
+ END
+END
+
+IDR_USER MENU
+BEGIN
+ POPUP "User"
+ BEGIN
+ MENUITEM "&Connect", ID_USER_CONNECT
+ MENUITEM "&Disconnect", ID_USER_DISCONNECT
+ MENUITEM "&Logoff", ID_USER_LOGOFF
+ MENUITEM "Rem&ote control", ID_USER_REMOTECONTROL
+ MENUITEM "Send &message...", ID_USER_SENDMESSAGE
+ MENUITEM "P&roperties", ID_USER_PROPERTIES
+ END
+END
+
+IDR_NETWORK MENU
+BEGIN
+ POPUP "Network"
+ BEGIN
+ MENUITEM "&Go to process\aEnter", ID_NETWORK_GOTOPROCESS
+ MENUITEM "Go to service", ID_NETWORK_GOTOSERVICE
+ MENUITEM "C&lose", ID_NETWORK_CLOSE
+ MENUITEM SEPARATOR
+ MENUITEM "&Copy\aCtrl+C", ID_NETWORK_COPY
+ END
+END
+
+IDR_ICON MENU
+BEGIN
+ POPUP "Icon"
+ BEGIN
+ MENUITEM "&Show/Hide Process Hacker", ID_ICON_SHOWHIDEPROCESSHACKER
+ MENUITEM "System &information", ID_ICON_SYSTEMINFORMATION
+ POPUP "N&otifications"
+ BEGIN
+ MENUITEM "&Enable all", ID_NOTIFICATIONS_ENABLEALL
+ MENUITEM "&Disable all", ID_NOTIFICATIONS_DISABLEALL
+ MENUITEM SEPARATOR
+ MENUITEM "New &processes", ID_NOTIFICATIONS_NEWPROCESSES
+ MENUITEM "T&erminated processes", ID_NOTIFICATIONS_TERMINATEDPROCESSES
+ MENUITEM "New &services", ID_NOTIFICATIONS_NEWSERVICES
+ MENUITEM "St&arted services", ID_NOTIFICATIONS_STARTEDSERVICES
+ MENUITEM "St&opped services", ID_NOTIFICATIONS_STOPPEDSERVICES
+ MENUITEM "&Deleted services", ID_NOTIFICATIONS_DELETEDSERVICES
+ END
+ POPUP "&Processes"
+ BEGIN
+ MENUITEM "Dummy", ID_PROCESSES_DUMMY
+ END
+ MENUITEM SEPARATOR
+ POPUP "&Computer"
+ BEGIN
+ MENUITEM "&Lock", ID_COMPUTER_LOCK
+ MENUITEM "Log o&ff", ID_COMPUTER_LOGOFF
+ MENUITEM SEPARATOR
+ MENUITEM "&Sleep", ID_COMPUTER_SLEEP
+ MENUITEM "&Hibernate", ID_COMPUTER_HIBERNATE
+ MENUITEM SEPARATOR
+ MENUITEM "R&estart", ID_COMPUTER_RESTART
+ MENUITEM "Restart to boot &options", ID_COMPUTER_RESTARTBOOTOPTIONS
+ MENUITEM "Shu&t down", ID_COMPUTER_SHUTDOWN
+ MENUITEM "H&ybrid shut down", ID_COMPUTER_SHUTDOWNHYBRID
+ END
+ MENUITEM "E&xit", ID_ICON_EXIT
+ END
+END
+
+IDR_MEMORY MENU
+BEGIN
+ POPUP "Memory"
+ BEGIN
+ MENUITEM "&Read/Write memory", ID_MEMORY_READWRITEMEMORY
+ MENUITEM "&Save...", ID_MEMORY_SAVE
+ MENUITEM "Change &protection...", ID_MEMORY_CHANGEPROTECTION
+ MENUITEM "&Free", ID_MEMORY_FREE
+ MENUITEM "&Decommit", ID_MEMORY_DECOMMIT
+ MENUITEM SEPARATOR
+ MENUITEM "&Copy\aCtrl+C", ID_MEMORY_COPY
+ END
+END
+
+IDR_MINIINFO MENU
+BEGIN
+ POPUP "Mini Info"
+ BEGIN
+ POPUP "&Opacity"
+ BEGIN
+ MENUITEM "10%", ID_OPACITY_10
+ MENUITEM "20%", ID_OPACITY_20
+ MENUITEM "30%", ID_OPACITY_30
+ MENUITEM "40%", ID_OPACITY_40
+ MENUITEM "50%", ID_OPACITY_50
+ MENUITEM "60%", ID_OPACITY_60
+ MENUITEM "70%", ID_OPACITY_70
+ MENUITEM "80%", ID_OPACITY_80
+ MENUITEM "90%", ID_OPACITY_90
+ MENUITEM "Opaque", ID_OPACITY_OPAQUE
+ END
+ MENUITEM SEPARATOR
+ MENUITEM "&Refresh\aF5", ID_MINIINFO_REFRESH
+ MENUITEM "Refresh a&utomatically\aF6", ID_MINIINFO_REFRESHAUTOMATICALLY
+ END
+END
+
+IDR_MINIINFO_PROCESS MENU
+BEGIN
+ POPUP "Process"
+ BEGIN
+ MENUITEM SEPARATOR
+ MENUITEM "&Go to process", ID_PROCESS_GOTOPROCESS
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_PROCGENERAL DIALOGEX 0, 0, 260, 260
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "General"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ PUSHBUTTON "Permissions",IDC_PERMISSIONS,143,197,50,14
+ PUSHBUTTON "Terminate",IDC_TERMINATE,197,197,50,14
+ GROUPBOX "File",IDC_FILE,7,7,246,79
+ ICON "",IDC_FILEICON,14,18,20,20
+ EDITTEXT IDC_NAME,44,17,182,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ EDITTEXT IDC_COMPANYNAME,44,29,183,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ CONTROL "Company name link",IDC_COMPANYNAME_LINK,"SysLink",LWS_NOPREFIX | NOT WS_VISIBLE | WS_TABSTOP,46,29,183,9
+ LTEXT "Version:",IDC_STATIC,15,41,27,8
+ EDITTEXT IDC_VERSION,44,41,113,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "Image file name:",IDC_STATIC,15,55,56,8
+ EDITTEXT IDC_FILENAME,15,65,191,12,ES_AUTOHSCROLL | ES_READONLY
+ PUSHBUTTON "Inspect",IDC_INSPECT,210,64,17,15,BS_ICON
+ PUSHBUTTON "Open",IDC_OPENFILENAME,230,64,17,15,BS_ICON
+ GROUPBOX "Process",IDC_PROCESS,7,92,246,161
+ LTEXT "Command line:",IDC_STATIC,13,103,50,8
+ EDITTEXT IDC_CMDLINE,79,101,147,12,ES_AUTOHSCROLL | ES_READONLY
+ LTEXT "Current directory:",IDC_STATIC,13,119,60,8
+ EDITTEXT IDC_CURDIR,79,117,168,12,ES_AUTOHSCROLL | ES_READONLY
+ LTEXT "Started:",IDC_STATIC,13,135,28,8
+ EDITTEXT IDC_STARTED,79,133,168,12,ES_AUTOHSCROLL | ES_READONLY
+ LTEXT "PEB address:",IDC_STATIC,13,151,44,8
+ EDITTEXT IDC_PEBADDRESS,79,149,101,12,ES_AUTOHSCROLL | ES_READONLY
+ LTEXT "Image type:",IDC_PROCESSTYPELABEL,185,151,41,8,NOT WS_VISIBLE
+ LTEXT "32-bit",IDC_PROCESSTYPETEXT,228,151,20,8,NOT WS_VISIBLE
+ LTEXT "Parent:",IDC_STATIC,13,167,25,8
+ EDITTEXT IDC_PARENTPROCESS,79,165,147,12,ES_AUTOHSCROLL | ES_READONLY
+ PUSHBUTTON "View",IDC_VIEWPARENTPROCESS,230,163,17,15,BS_ICON
+ LTEXT "Mitigation policies:",IDC_STATIC,13,183,59,8
+ EDITTEXT IDC_MITIGATION,79,181,126,12,ES_AUTOHSCROLL | ES_READONLY
+ PUSHBUTTON "Details",IDC_VIEWMITIGATION,209,180,38,14
+ LTEXT "Protection:",IDC_STATIC,13,200,36,8
+ EDITTEXT IDC_PROTECTION,51,200,80,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ PUSHBUTTON "View",IDC_VIEWCOMMANDLINE,230,100,17,15,BS_ICON
+END
+
+IDD_PROCMODULES DIALOGEX 0, 0, 260, 260
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Modules"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,2,19,256,239,WS_EX_CLIENTEDGE
+ EDITTEXT IDC_SEARCH,114,3,144,14,ES_AUTOHSCROLL
+ PUSHBUTTON "Options",IDC_FILTEROPTIONS,2,2,50,14
+END
+
+IDD_PROCTHREADS DIALOGEX 0, 0, 260, 260
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Threads"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,2,19,256,239,WS_EX_CLIENTEDGE
+ EDITTEXT IDC_SEARCH,114,3,144,14,ES_AUTOHSCROLL
+ PUSHBUTTON "Options",IDC_OPTIONS,2,2,50,14
+END
+
+IDD_PROCHANDLES DIALOGEX 0, 0, 260, 260
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Handles"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ PUSHBUTTON "Options",IDC_OPTIONS,2,2,50,14
+ EDITTEXT IDC_HANDLESEARCH,114,3,144,14,ES_AUTOHSCROLL
+ CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x2,2,19,256,239,WS_EX_CLIENTEDGE
+END
+
+IDD_PROCENVIRONMENT DIALOGEX 0, 0, 260, 260
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Environment"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,2,19,256,239,WS_EX_CLIENTEDGE
+ EDITTEXT IDC_SEARCH,114,3,144,14,ES_AUTOHSCROLL
+ PUSHBUTTON "Refresh",IDC_REFRESH,53,2,50,14
+ PUSHBUTTON "Options",IDC_OPTIONS,2,2,50,14
+END
+
+IDD_THRDSTACK DIALOGEX 0, 0, 273, 228
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+CAPTION "Thread Stack"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ PUSHBUTTON "Copy",IDC_COPY,111,212,50,14
+ PUSHBUTTON "Refresh",IDC_REFRESH,165,212,50,14
+ PUSHBUTTON "Close",IDOK,219,212,50,14
+ CONTROL "",IDC_TREELIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x2,2,2,269,209,WS_EX_CLIENTEDGE
+END
+
+IDD_ABOUT DIALOGEX 0, 0, 270, 195
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "About"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ ICON IDI_PROCESSHACKER,IDC_STATIC,16,11,21,20
+ LTEXT "Process Hacker",IDC_ABOUT_NAME,45,10,192,8
+ LTEXT "Licensed under the GNU GPL, v3.",IDC_STATIC,45,23,193,8
+ LTEXT "Copyright (c) 2008-2019",IDC_STATIC,45,36,80,8
+ CONTROL "Credits.",IDC_CREDITS,"SysLink",WS_TABSTOP,15,49,248,121
+ CONTROL "Process Hacker on SourceForge.net",IDC_LINK_SF,
+ "SysLink",WS_TABSTOP,7,177,130,11
+ PUSHBUTTON "Diagnostics",IDC_DIAGNOSTICS,160,174,50,14
+ DEFPUSHBUTTON "OK",IDOK,213,174,50,14
+END
+
+IDD_SRVLIST DIALOGEX 0, 0, 237, 201
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,0,0,237,141
+ EDITTEXT IDC_DESCRIPTION,0,144,237,40,ES_MULTILINE | ES_READONLY | NOT WS_BORDER
+ PUSHBUTTON "&Start",IDC_START,134,187,50,14
+ PUSHBUTTON "&Pause",IDC_PAUSE,187,187,50,14
+END
+
+IDD_SRVGENERAL DIALOGEX 0, 0, 282, 183
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "General"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ EDITTEXT IDC_DESCRIPTION,7,7,268,45,ES_MULTILINE | ES_READONLY | WS_VSCROLL
+ LTEXT "Type:",IDC_STATIC,7,57,20,8
+ COMBOBOX IDC_TYPE,30,56,110,65,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Start type:",IDC_STATIC,147,57,38,8
+ COMBOBOX IDC_STARTTYPE,188,56,87,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Error control:",IDC_STATIC,7,75,47,8
+ COMBOBOX IDC_ERRORCONTROL,58,73,82,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Group:",IDC_STATIC,147,75,23,8
+ EDITTEXT IDC_GROUP,173,74,102,12,ES_AUTOHSCROLL
+ LTEXT "Binary path:",IDC_STATIC,7,92,40,8
+ EDITTEXT IDC_BINARYPATH,58,91,163,12,ES_AUTOHSCROLL
+ PUSHBUTTON "Browse...",IDC_BROWSE,225,90,50,14
+ LTEXT "User account:",IDC_STATIC,7,110,46,8
+ EDITTEXT IDC_USERACCOUNT,58,108,217,12,ES_AUTOHSCROLL
+ LTEXT "Password:",IDC_STATIC,7,127,34,8
+ EDITTEXT IDC_PASSWORD,58,125,204,12,ES_PASSWORD | ES_AUTOHSCROLL
+ CONTROL "",IDC_PASSWORDCHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,266,126,9,10
+ LTEXT "Service DLL:",IDC_STATIC,7,144,48,8
+ EDITTEXT IDC_SERVICEDLL,58,142,217,12,ES_AUTOHSCROLL | ES_READONLY
+ CONTROL "Delayed start",IDC_DELAYEDSTART,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,158,59,10
+ PUSHBUTTON "Permissions",IDC_PERMISSIONS,225,162,50,14
+END
+
+IDD_HNDLGENERAL DIALOGEX 0, 0, 260, 181
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "General"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_TABSTOP,0,2,260,179
+END
+
+IDD_INFORMATION DIALOGEX 0, 0, 317, 184
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+CAPTION "Information"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ EDITTEXT IDC_TEXT,7,7,303,152,ES_MULTILINE | ES_READONLY | WS_VSCROLL
+ PUSHBUTTON "Save...",IDC_SAVE,154,163,50,14
+ PUSHBUTTON "Copy",IDC_COPY,207,163,50,14
+ DEFPUSHBUTTON "Close",IDOK,260,163,50,14
+END
+
+IDD_FINDOBJECTS DIALOGEX 0, 0, 357, 233
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+CAPTION "Find Handles or DLLs"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ EDITTEXT IDC_FILTER,97,4,171,13,ES_AUTOHSCROLL
+ PUSHBUTTON "Find",IDOK,306,3,50,14
+ CONTROL "&Regex",IDC_REGEX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,271,6,34,10
+ COMBOBOX IDC_FILTERTYPE,2,4,93,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ CONTROL "",IDC_TREELIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x2,2,19,353,212,WS_EX_CLIENTEDGE
+END
+
+IDD_OBJTOKEN DIALOGEX 0, 0, 260, 260
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Token"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "User:",IDC_TOKENUSER,7,7,18,8
+ EDITTEXT IDC_USER,48,7,205,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "User SID:",IDC_TOKENSID,7,18,32,8
+ EDITTEXT IDC_USERSID,48,18,205,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "Session:",IDC_STATIC,7,29,28,8
+ LTEXT "Unknown",IDC_SESSIONID,38,29,30,8
+ LTEXT "Elevated:",IDC_STATIC,85,29,32,8
+ LTEXT "Unknown",IDC_ELEVATED,120,29,30,8
+ LTEXT "Virtualized:",IDC_STATIC,169,29,36,8
+ LTEXT "Unknown",IDC_VIRTUALIZED,209,29,44,8
+ CONTROL "",IDC_GROUPS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,42,246,194
+ PUSHBUTTON "Integrity",IDC_INTEGRITY,149,239,50,14
+ PUSHBUTTON "Advanced",IDC_ADVANCED,203,239,50,14
+ PUSHBUTTON "Permissions",IDC_PERMISSIONS,95,239,50,14
+ PUSHBUTTON "Default token",IDC_DEFAULTPERM,41,239,50,14
+END
+
+IDD_HIDDENPROCESSES DIALOGEX 0, 0, 337, 221
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+CAPTION "Hidden Processes"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Processes highlighted red are hidden while those highlighted grey have terminated.",IDC_INTRO,7,7,323,12
+ CONTROL "",IDC_PROCESSES,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,23,323,162
+ RTEXT "",IDC_DESCRIPTION,7,187,323,11
+ COMBOBOX IDC_METHOD,7,201,73,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "Terminate",IDC_TERMINATE,115,200,50,14
+ PUSHBUTTON "Save...",IDC_SAVE,170,200,50,14
+ PUSHBUTTON "&Scan",IDC_SCAN,225,200,50,14
+ DEFPUSHBUTTON "Close",IDOK,280,200,50,14
+END
+
+IDD_RUNAS DIALOGEX 0, 0, 293, 127
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Run As"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Enter the command to start as the specified user.",IDC_TITLE,7,7,160,8
+ LTEXT "Program:",IDC_STATIC,7,23,30,8
+ LTEXT "User name:",IDC_STATIC,7,40,38,8
+ COMBOBOX IDC_USERNAME,53,38,123,12,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Type:",IDC_STATIC,184,40,20,8
+ COMBOBOX IDC_TYPE,208,38,78,12,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Password:",IDC_STATIC,7,56,34,8
+ EDITTEXT IDC_PASSWORD,53,55,123,12,ES_PASSWORD | ES_AUTOHSCROLL
+ CONTROL "Toggle elevation",IDC_TOGGLEELEVATION,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,183,56,69,10
+ LTEXT "Session ID:",IDC_STATIC,7,73,37,8
+ LTEXT "Desktop:",IDC_STATIC,7,90,30,8
+ DEFPUSHBUTTON "OK",IDOK,127,106,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,182,106,50,14
+ COMBOBOX IDC_SESSIONCOMBO,53,72,123,12,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ COMBOBOX IDC_DESKTOPCOMBO,53,88,123,12,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "Browse",IDC_BROWSE,237,106,50,14
+ CONTROL "Create suspended",IDC_TOGGLESUSPENDED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,183,70,75,10
+ COMBOBOX IDC_PROGRAMCOMBO,53,21,233,12,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP
+END
+
+IDD_PROGRESS DIALOGEX 0, 0, 216, 62
+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,159,41,50,14
+ CONTROL "",IDC_PROGRESS,"msctls_progress32",0x0,7,23,202,14
+ LTEXT "Please wait...",IDC_PROGRESSTEXT,7,7,202,12
+END
+
+IDD_PAGEFILES DIALOGEX 0, 0, 322, 162
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Pagefiles"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,7,308,128
+ PUSHBUTTON "Refresh",IDC_REFRESH,211,141,50,14
+ DEFPUSHBUTTON "Close",IDOK,265,141,50,14
+END
+
+IDD_TOKGENERAL DIALOGEX 0, 0, 270, 228
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "General"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ GROUPBOX "Token",IDC_STATIC,7,7,256,149
+ LTEXT "User:",IDC_STATIC,15,19,18,8
+ EDITTEXT IDC_USER,71,17,185,12,ES_AUTOHSCROLL | ES_READONLY
+ LTEXT "User SID:",IDC_STATIC,15,36,32,8
+ EDITTEXT IDC_USERSID,71,34,185,12,ES_AUTOHSCROLL | ES_READONLY
+ LTEXT "Owner:",IDC_STATIC,15,53,25,8
+ EDITTEXT IDC_OWNER,71,51,185,12,ES_AUTOHSCROLL | ES_READONLY
+ LTEXT "Primary group:",IDC_STATIC,15,70,49,8
+ EDITTEXT IDC_PRIMARYGROUP,71,68,185,12,ES_AUTOHSCROLL | ES_READONLY
+ LTEXT "Session ID:",IDC_STATIC,15,87,37,8
+ EDITTEXT IDC_SESSIONID,71,85,88,12,ES_AUTOHSCROLL | ES_READONLY
+ LTEXT "Elevated:",IDC_STATIC,15,104,32,8
+ EDITTEXT IDC_ELEVATED,71,102,117,12,ES_AUTOHSCROLL | ES_READONLY
+ LTEXT "Virtualization:",IDC_STATIC,15,121,44,8
+ EDITTEXT IDC_VIRTUALIZATION,71,119,185,12,ES_AUTOHSCROLL | ES_READONLY
+ LTEXT "UIAccess:",IDC_STATIC,15,138,32,8
+ EDITTEXT IDC_UIACCESS,71,136,185,12,ES_AUTOHSCROLL | ES_READONLY
+ PUSHBUTTON "Linked token",IDC_LINKEDTOKEN,193,101,63,14
+ GROUPBOX "Source",IDC_STATIC,7,160,256,47
+ LTEXT "Name:",IDC_STATIC,15,172,22,8
+ EDITTEXT IDC_SOURCENAME,71,170,185,12,ES_AUTOHSCROLL | ES_READONLY
+ LTEXT "LUID:",IDC_STATIC,15,190,19,8
+ EDITTEXT IDC_SOURCELUID,71,188,185,12,ES_AUTOHSCROLL | ES_READONLY
+END
+
+IDD_TOKADVANCED DIALOGEX 0, 0, 236, 186
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Advanced"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | WS_TABSTOP,0,0,236,186
+END
+
+IDD_OBJJOB DIALOGEX 0, 0, 260, 260
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Job"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Name:",IDC_STATIC,7,9,22,8
+ EDITTEXT IDC_NAME,35,8,164,12,ES_AUTOHSCROLL
+ PUSHBUTTON "Terminate",IDC_TERMINATE,203,7,50,14
+ LTEXT "Processes in job:",IDC_STATIC,7,25,55,8
+ CONTROL "",IDC_PROCESSES,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,38,246,62
+ PUSHBUTTON "Add...",IDC_ADD,203,103,50,14
+ LTEXT "Limits:",IDC_STATIC,7,117,21,8
+ CONTROL "",IDC_LIMITS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,129,246,107
+ PUSHBUTTON "Advanced",IDC_ADVANCED,203,239,50,14
+END
+
+IDD_OBJEVENT DIALOGEX 0, 0, 186, 76
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Event"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Type:",IDC_STATIC,7,7,20,8
+ LTEXT "Unknown",IDC_TYPE,42,7,137,8
+ LTEXT "Signaled:",IDC_STATIC,7,18,30,8
+ LTEXT "Unknown",IDC_SIGNALED,42,18,137,8
+ PUSHBUTTON "Set",IDC_SET,7,34,50,14
+ PUSHBUTTON "Reset",IDC_RESET,61,34,50,14
+ PUSHBUTTON "Pulse",IDC_PULSE,115,34,50,14
+END
+
+IDD_OBJMUTANT DIALOGEX 0, 0, 186, 76
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Mutant"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Count:",IDC_STATIC,7,7,23,8
+ LTEXT "Unknown",IDC_COUNT,55,7,124,8
+ LTEXT "Abandoned:",IDC_STATIC,7,18,40,8
+ LTEXT "Unknown",IDC_ABANDONED,55,18,124,8
+ LTEXT "Owner:",IDC_OWNERLABEL,7,29,25,8
+ LTEXT "Unknown",IDC_OWNER,55,29,124,8
+END
+
+IDD_OBJSEMAPHORE DIALOGEX 0, 0, 186, 76
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Semaphore"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Current count:",IDC_STATIC,7,7,50,8
+ LTEXT "Unknown",IDC_CURRENTCOUNT,66,7,113,8
+ LTEXT "Maximum count:",IDC_STATIC,7,18,54,8
+ LTEXT "Unknown",IDC_MAXIMUMCOUNT,66,18,113,8
+ PUSHBUTTON "Acquire",IDC_ACQUIRE,7,34,50,14
+ PUSHBUTTON "Release",IDC_RELEASE,61,34,50,14
+END
+
+IDD_OBJTIMER DIALOGEX 0, 0, 186, 76
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Timer"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Signaled:",-1,7,7,30,8
+ LTEXT "Unknown",IDC_SIGNALED,42,7,137,8
+ PUSHBUTTON "Cancel",IDC_CANCEL,7,19,50,14
+END
+
+IDD_JOBSTATISTICS DIALOGEX 0, 0, 259, 186
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Statistics"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ GROUPBOX "General",IDC_STATIC,7,7,133,47
+ LTEXT "Active processes",IDC_STATIC,15,18,55,8
+ RTEXT "Static",IDC_ZACTIVEPROCESSES_V,99,18,37,8,SS_ENDELLIPSIS
+ LTEXT "Total processes",IDC_STATIC,15,28,51,8
+ RTEXT "Static",IDC_ZTOTALPROCESSES_V,95,29,41,8,SS_ENDELLIPSIS
+ LTEXT "Terminated due to job limits",IDC_STATIC,15,39,98,8
+ RTEXT "Static",IDC_ZTERMINATEDPROCESSES_V,107,39,29,8,SS_ENDELLIPSIS
+ GROUPBOX "Time",IDC_STATIC,7,57,133,57
+ LTEXT "User time",IDC_STATIC,15,68,32,8
+ LTEXT "Kernel time",IDC_STATIC,15,79,38,8
+ LTEXT "User time (period)",IDC_STATIC,15,89,60,8
+ LTEXT "Kernel time (period)",IDC_STATIC,15,99,65,8
+ RTEXT "Static",IDC_ZUSERTIME_V,83,68,53,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZKERNELTIME_V,85,79,51,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZUSERTIMEPERIOD_V,87,89,49,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZKERNELTIMEPERIOD_V,87,99,49,8,SS_ENDELLIPSIS
+ GROUPBOX "Memory",IDC_STATIC,7,118,133,48
+ LTEXT "Page faults",IDC_STATIC,15,129,38,8
+ LTEXT "Peak process usage",IDC_STATIC,15,140,65,8
+ LTEXT "Peak job usage",IDC_STATIC,15,151,52,8
+ RTEXT "Static",IDC_ZPAGEFAULTS_V,86,129,50,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZPEAKPROCESSUSAGE_V,85,140,51,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZPEAKJOBUSAGE_V,86,151,50,8,SS_ENDELLIPSIS
+ GROUPBOX "I/O",IDC_STATIC,146,7,106,75
+ LTEXT "Reads",IDC_STATIC,152,17,21,8
+ LTEXT "Read bytes",IDC_STATIC,152,27,38,8
+ LTEXT "Writes",IDC_STATIC,152,37,22,8
+ LTEXT "Write bytes",IDC_STATIC,152,47,38,8
+ LTEXT "Other",IDC_STATIC,152,57,20,8
+ LTEXT "Other bytes",IDC_STATIC,152,67,40,8
+ RTEXT "Static",IDC_ZIOREADS_V,200,17,47,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZIOREADBYTES_V,200,27,47,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZIOWRITES_V,200,37,47,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZIOWRITEBYTES_V,200,47,47,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZIOOTHER_V,200,57,47,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZIOOTHERBYTES_V,200,67,47,8,SS_ENDELLIPSIS
+END
+
+IDD_OBJEVENTPAIR DIALOGEX 0, 0, 186, 76
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Event Pair"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ PUSHBUTTON "Set low",IDC_SETLOW,7,7,50,14
+ PUSHBUTTON "Set high",IDC_SETHIGH,61,7,50,14
+END
+
+IDD_AFFINITY DIALOGEX 0, 0, 279, 227
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Affinity"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,169,206,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,222,206,50,14
+ LTEXT "Affinity controls which CPUs threads are allowed to execute on.",IDC_STATIC,7,7,265,11
+ CONTROL "CPU 0",IDC_CPU0,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,21,35,10
+ CONTROL "CPU 1",IDC_CPU1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,33,35,10
+ CONTROL "CPU 2",IDC_CPU2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,44,35,10
+ CONTROL "CPU 3",IDC_CPU3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,56,35,10
+ CONTROL "CPU 4",IDC_CPU4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,67,35,10
+ CONTROL "CPU 5",IDC_CPU5,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,78,35,10
+ CONTROL "CPU 6",IDC_CPU6,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,89,35,10
+ CONTROL "CPU 7",IDC_CPU7,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,100,35,10
+ CONTROL "CPU 8",IDC_CPU8,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,111,35,10
+ CONTROL "CPU 9",IDC_CPU9,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,122,35,10
+ CONTROL "CPU 10",IDC_CPU10,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,134,39,10
+ CONTROL "CPU 11",IDC_CPU11,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,145,39,10
+ CONTROL "CPU 12",IDC_CPU12,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,156,39,10
+ CONTROL "CPU 13",IDC_CPU13,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,167,39,10
+ CONTROL "CPU 14",IDC_CPU14,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,178,39,10
+ CONTROL "CPU 15",IDC_CPU15,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,190,39,10
+ CONTROL "CPU 16",IDC_CPU16,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,21,39,10
+ CONTROL "CPU 17",IDC_CPU17,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,33,39,10
+ CONTROL "CPU 18",IDC_CPU18,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,44,39,10
+ CONTROL "CPU 19",IDC_CPU19,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,56,39,10
+ CONTROL "CPU 20",IDC_CPU20,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,67,39,10
+ CONTROL "CPU 21",IDC_CPU21,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,78,39,10
+ CONTROL "CPU 22",IDC_CPU22,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,89,39,10
+ CONTROL "CPU 23",IDC_CPU23,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,100,39,10
+ CONTROL "CPU 24",IDC_CPU24,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,111,39,10
+ CONTROL "CPU 25",IDC_CPU25,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,122,39,10
+ CONTROL "CPU 26",IDC_CPU26,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,134,39,10
+ CONTROL "CPU 27",IDC_CPU27,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,145,39,10
+ CONTROL "CPU 28",IDC_CPU28,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,156,39,10
+ CONTROL "CPU 29",IDC_CPU29,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,167,39,10
+ CONTROL "CPU 30",IDC_CPU30,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,178,39,10
+ CONTROL "CPU 31",IDC_CPU31,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,79,190,39,10
+ CONTROL "CPU 32",IDC_CPU32,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,21,39,10
+ CONTROL "CPU 33",IDC_CPU33,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,33,39,10
+ CONTROL "CPU 34",IDC_CPU34,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,44,39,10
+ CONTROL "CPU 35",IDC_CPU35,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,56,39,10
+ CONTROL "CPU 36",IDC_CPU36,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,67,39,10
+ CONTROL "CPU 37",IDC_CPU37,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,78,39,10
+ CONTROL "CPU 38",IDC_CPU38,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,89,39,10
+ CONTROL "CPU 39",IDC_CPU39,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,100,39,10
+ CONTROL "CPU 40",IDC_CPU40,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,111,39,10
+ CONTROL "CPU 41",IDC_CPU41,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,122,39,10
+ CONTROL "CPU 42",IDC_CPU42,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,134,39,10
+ CONTROL "CPU 43",IDC_CPU43,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,145,39,10
+ CONTROL "CPU 44",IDC_CPU44,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,156,39,10
+ CONTROL "CPU 45",IDC_CPU45,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,167,39,10
+ CONTROL "CPU 46",IDC_CPU46,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,178,39,10
+ CONTROL "CPU 47",IDC_CPU47,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,150,190,39,10
+ CONTROL "CPU 48",IDC_CPU48,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,21,39,10
+ CONTROL "CPU 49",IDC_CPU49,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,33,39,10
+ CONTROL "CPU 50",IDC_CPU50,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,44,39,10
+ CONTROL "CPU 51",IDC_CPU51,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,56,39,10
+ CONTROL "CPU 52",IDC_CPU52,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,67,39,10
+ CONTROL "CPU 53",IDC_CPU53,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,78,39,10
+ CONTROL "CPU 54",IDC_CPU54,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,89,39,10
+ CONTROL "CPU 55",IDC_CPU55,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,100,39,10
+ CONTROL "CPU 56",IDC_CPU56,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,111,39,10
+ CONTROL "CPU 57",IDC_CPU57,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,122,39,10
+ CONTROL "CPU 58",IDC_CPU58,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,134,39,10
+ CONTROL "CPU 59",IDC_CPU59,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,145,39,10
+ CONTROL "CPU 60",IDC_CPU60,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,156,39,10
+ CONTROL "CPU 61",IDC_CPU61,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,167,39,10
+ CONTROL "CPU 62",IDC_CPU62,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,178,39,10
+ CONTROL "CPU 63",IDC_CPU63,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,224,190,39,10
+ PUSHBUTTON "Select all",IDC_SELECTALL,7,206,50,14
+ PUSHBUTTON "Deselect all",IDC_DESELECTALL,60,206,50,14
+END
+
+IDD_SYSINFO DIALOGEX 0, 0, 423, 247
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+EXSTYLE WS_EX_APPWINDOW
+CAPTION "System Information"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+END
+
+IDD_EDITMESSAGE DIALOGEX 0, 0, 282, 163
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Message"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Title:",IDC_STATIC,7,8,17,8
+ EDITTEXT IDC_TITLE,52,7,223,12,ES_AUTOHSCROLL
+ LTEXT "Text:",IDC_STATIC,7,24,18,8
+ EDITTEXT IDC_TEXT,52,23,223,79,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL
+ LTEXT "Icon:",IDC_STATIC,7,107,18,8
+ COMBOBOX IDC_TYPE,52,105,80,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Timeout (s):",IDC_STATIC,7,123,40,8
+ EDITTEXT IDC_TIMEOUT,52,122,43,12,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK",IDOK,172,142,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,225,142,50,14
+END
+
+IDD_SESSION DIALOGEX 0, 0, 201, 149
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Session Properties"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "Close",IDOK,144,128,50,14
+ LTEXT "User name:",IDC_STATIC,7,7,38,8
+ LTEXT "Session ID:",IDC_STATIC,7,18,37,8
+ LTEXT "State:",IDC_STATIC,7,29,21,8
+ LTEXT "Client name:",IDC_STATIC,7,84,41,8
+ LTEXT "Client address:",IDC_STATIC,7,95,49,8
+ LTEXT "Client display:",IDC_STATIC,7,106,46,8
+ LTEXT "N/A",IDC_USERNAME,66,7,128,8
+ LTEXT "N/A",IDC_SESSIONID,66,18,128,8
+ LTEXT "N/A",IDC_STATE,66,29,128,8
+ LTEXT "N/A",IDC_CLIENTNAME,66,84,128,8
+ LTEXT "N/A",IDC_CLIENTADDRESS,66,95,128,8
+ LTEXT "N/A",IDC_CLIENTDISPLAY,66,106,128,8
+ LTEXT "Logon time:",IDC_STATIC,7,40,38,8
+ LTEXT "N/A",IDC_LOGONTIME,66,40,128,8
+ LTEXT "Connect time:",IDC_STATIC,7,51,46,8
+ LTEXT "Disconnect time:",IDC_STATIC,7,62,54,8
+ LTEXT "Last input time:",IDC_STATIC,7,73,50,8
+ LTEXT "N/A",IDC_CONNECTTIME,66,51,128,8
+ LTEXT "N/A",IDC_DISCONNECTTIME,66,62,128,8
+ LTEXT "N/A",IDC_LASTINPUTTIME,66,74,128,8
+END
+
+IDD_PROCMEMORY DIALOGEX 0, 0, 260, 260
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Memory"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ PUSHBUTTON "Refresh",IDC_REFRESH,53,2,50,14
+ CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,2,19,256,239,WS_EX_CLIENTEDGE
+ PUSHBUTTON "Options",IDC_FILTEROPTIONS,2,2,50,14
+ EDITTEXT IDC_SEARCH,114,3,144,14,ES_AUTOHSCROLL
+END
+
+IDD_CHOOSE DIALOGEX 0, 0, 199, 73
+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 "Text:",IDC_MESSAGE,7,7,185,8,SS_ENDELLIPSIS
+ COMBOBOX IDC_CHOICE,7,20,185,30,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP
+ CONTROL "Option",IDC_OPTION,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,39,185,10
+ DEFPUSHBUTTON "OK",IDOK,89,52,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,142,52,50,14
+ COMBOBOX IDC_CHOICEUSER,7,20,185,30,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP
+ EDITTEXT IDC_CHOICESIMPLE,7,20,185,13,ES_PASSWORD | ES_AUTOHSCROLL | NOT WS_VISIBLE
+END
+
+IDD_OPTGENERAL DIALOGEX 0, 0, 315, 220
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "General"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Search engine:",IDC_STATIC,7,8,49,8
+ EDITTEXT IDC_SEARCHENGINE,61,7,247,12,ES_AUTOHSCROLL
+ LTEXT "PE viewer:",IDC_STATIC,7,23,35,8
+ EDITTEXT IDC_PEVIEWER,61,22,247,12,ES_AUTOHSCROLL
+ LTEXT "Max. size unit:",IDC_STATIC,7,55,49,8
+ COMBOBOX IDC_MAXSIZEUNIT,61,54,39,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Icon processes:",IDC_STATIC,7,72,52,8
+ EDITTEXT IDC_ICONPROCESSES,61,70,40,12,ES_AUTOHSCROLL | ES_NUMBER
+ PUSHBUTTON "Font...",IDC_FONT,179,70,49,14
+ PUSHBUTTON "Make default...",IDC_REPLACETASKMANAGER,179,86,72,14
+ LTEXT "Graph history length:",IDC_STATIC,106,56,69,8
+ EDITTEXT IDC_SAMPLECOUNT,180,55,48,12,ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "Automatic",IDC_SAMPLECOUNTAUTOMATIC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,233,56,48,10
+ CONTROL "",IDC_SETTINGS,"SysListView32",LVS_LIST | LVS_SINGLESEL | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,103,301,110
+ LTEXT "Application font:",IDC_STATIC,121,72,54,8
+ RTEXT "Process Hacker is the default Task Manager:",IDC_DEFSTATE,7,88,166,8
+ LTEXT "Symbol path:",IDC_STATIC,7,39,43,8
+ EDITTEXT IDC_DBGHELPSEARCHPATH,61,38,247,12,ES_AUTOHSCROLL
+END
+
+IDD_OPTHIGHLIGHTING DIALOGEX 0, 0, 250, 174
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Highlighting"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Highlighting duration:",IDC_STATIC,7,8,70,8
+ EDITTEXT IDC_HIGHLIGHTINGDURATION,79,7,40,12,ES_AUTOHSCROLL | ES_NUMBER
+ LTEXT "New objects:",IDC_STATIC,7,25,44,8
+ CONTROL "New objects",IDC_NEWOBJECTS,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,57,23,33,13
+ LTEXT "Removed objects:",IDC_STATIC,127,25,60,8
+ CONTROL "Removed objects",IDC_REMOVEDOBJECTS,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,193,23,33,13
+ CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,7,41,236,107
+ LTEXT "Double-click an item to change it.",IDC_INFO,7,156,106,8
+ PUSHBUTTON "Enable all",IDC_ENABLEALL,140,153,50,14
+ PUSHBUTTON "Disable all",IDC_DISABLEALL,193,153,50,14
+END
+
+IDD_CHOOSECOLUMNS DIALOGEX 0, 0, 381, 207
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Choose Columns"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Select the columns that will appear in the list.",IDC_MESSAGE,7,7,367,10
+ LTEXT "Inactive columns:",IDC_STATIC,7,21,57,8
+ LISTBOX IDC_INACTIVE,7,31,129,150,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "Show >",IDC_SHOW,139,86,50,14
+ PUSHBUTTON "< Hide",IDC_HIDE,139,103,50,14
+ LISTBOX IDC_ACTIVE,192,31,129,150,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "Move up",IDC_MOVEUP,324,31,50,14
+ PUSHBUTTON "Move down",IDC_MOVEDOWN,324,48,50,14
+ DEFPUSHBUTTON "OK",IDOK,272,186,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,324,186,50,14
+ LTEXT "Active columns:",IDC_STATIC,192,21,51,8
+END
+
+IDD_NETSTACK DIALOGEX 0, 0, 261, 228
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+CAPTION "Network Stack"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,7,247,196
+ PUSHBUTTON "Close",IDOK,204,207,50,14
+END
+
+IDD_CREATESERVICE DIALOGEX 0, 0, 287, 133
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Create Service"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Name:",IDC_STATIC,7,8,22,8
+ EDITTEXT IDC_NAME,61,7,219,12,ES_AUTOHSCROLL
+ LTEXT "Display name:",IDC_STATIC,7,24,46,8
+ EDITTEXT IDC_DISPLAYNAME,61,23,219,12,ES_AUTOHSCROLL
+ LTEXT "Type:",IDC_STATIC,7,41,20,8
+ COMBOBOX IDC_TYPE,61,39,97,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Start type:",IDC_STATIC,7,58,38,8
+ COMBOBOX IDC_STARTTYPE,61,56,97,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Error control:",IDC_STATIC,7,75,45,8
+ COMBOBOX IDC_ERRORCONTROL,61,73,97,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Binary path:",IDC_STATIC,7,91,40,8
+ EDITTEXT IDC_BINARYPATH,61,90,165,12,ES_AUTOHSCROLL
+ PUSHBUTTON "Browse...",IDC_BROWSE,230,89,50,14
+ DEFPUSHBUTTON "OK",IDOK,176,112,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,230,112,50,14
+END
+
+IDD_PROCPERFORMANCE DIALOGEX 0, 0, 260, 260
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Performance"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ GROUPBOX "CPU",IDC_GROUPCPU,7,7,246,74,0,WS_EX_TRANSPARENT
+ GROUPBOX "Private bytes",IDC_GROUPPRIVATEBYTES,7,86,246,77,0,WS_EX_TRANSPARENT
+ GROUPBOX "I/O",IDC_GROUPIO,7,164,246,89,0,WS_EX_TRANSPARENT
+ CONTROL "",IDC_CPU,"PhGraph",WS_CLIPSIBLINGS,105,42,50,14
+ CONTROL "",IDC_PRIVATEBYTES,"PhGraph",WS_CLIPSIBLINGS,105,122,50,14
+ CONTROL "",IDC_IO,"PhGraph",WS_CLIPSIBLINGS,105,204,50,14
+END
+
+IDD_PROCSTATISTICS DIALOGEX 0, 0, 260, 260
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Statistics"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_STATISTICS_LIST,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,2,3,255,255
+END
+
+IDD_OPTADVANCED DIALOGEX 0, 0, 317, 225
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Advanced"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_SETTINGS,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,303,211
+END
+
+IDD_GDIHANDLES DIALOGEX 0, 0, 351, 307
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "GDI Handles"
+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,337,275
+ PUSHBUTTON "Refresh",IDC_REFRESH,240,286,50,14
+ DEFPUSHBUTTON "Close",IDOK,294,286,50,14
+END
+
+IDD_LOG DIALOGEX 0, 0, 313, 303
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+EXSTYLE WS_EX_APPWINDOW
+CAPTION "Log"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_OWNERDATA | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,7,299,272
+ PUSHBUTTON "Clear",IDC_CLEAR,7,282,50,14
+ CONTROL "Auto-scroll",IDC_AUTOSCROLL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,61,284,50,10
+ PUSHBUTTON "Save...",IDC_SAVE,148,282,50,14
+ PUSHBUTTON "Copy",IDC_COPY,202,282,50,14
+ DEFPUSHBUTTON "Close",IDOK,256,282,50,14
+END
+
+IDD_MEMEDIT DIALOGEX 0, 0, 441, 269
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+EXSTYLE WS_EX_APPWINDOW
+CAPTION "Memory"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_MEMORY,"PhHexEdit",WS_CLIPSIBLINGS | WS_VSCROLL | WS_TABSTOP,7,7,427,239
+ PUSHBUTTON "Re-read",IDC_REREAD,7,248,50,14
+ PUSHBUTTON "Write",IDC_WRITE,60,248,50,14
+ PUSHBUTTON "Go to...",IDC_GOTO,112,248,50,14
+ PUSHBUTTON "Save...",IDC_SAVE,331,248,50,14
+ PUSHBUTTON "Close",IDOK,384,248,50,14
+ COMBOBOX IDC_BYTESPERROW,164,249,86,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+END
+
+IDD_MEMPROTECT DIALOGEX 0, 0, 270, 171
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Memory Protection"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ EDITTEXT IDC_INTRO,7,7,256,122,ES_MULTILINE | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "New value:",IDC_STATIC,120,136,37,8
+ EDITTEXT IDC_VALUE,161,135,102,12,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK",IDOK,161,150,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,213,150,50,14
+END
+
+IDD_MEMRESULTS DIALOGEX 0, 0, 313, 266
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+CAPTION "Results"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Results.",IDC_INTRO,7,9,299,8
+ CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_OWNERDATA | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,21,299,221
+ PUSHBUTTON "Filter",IDC_FILTER,7,245,50,14
+ PUSHBUTTON "Save...",IDC_SAVE,149,245,50,14
+ PUSHBUTTON "Copy",IDC_COPY,203,245,50,14
+ DEFPUSHBUTTON "Close",IDOK,256,245,50,14
+END
+
+IDD_MEMSTRING DIALOGEX 0, 0, 241, 86
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "String Search"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Minimum length:",IDC_STATIC,7,8,54,8
+ EDITTEXT IDC_MINIMUMLENGTH,67,7,51,12,ES_AUTOHSCROLL
+ CONTROL "Detect Unicode",IDC_DETECTUNICODE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,22,65,10
+ LTEXT "Search in the following types of memory regions:",IDC_STATIC,7,36,157,8
+ CONTROL "Private",IDC_PRIVATE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,49,39,10
+ CONTROL "Image",IDC_IMAGE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,55,49,36,10
+ CONTROL "Mapped",IDC_MAPPED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,101,49,41,10
+ DEFPUSHBUTTON "OK",IDOK,131,65,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,184,65,50,14
+ CONTROL "Extended Unicode",IDC_EXTENDEDUNICODE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,80,22,74,10
+END
+
+IDD_OPTGRAPHS DIALOGEX 0, 0, 250, 156
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Graphs"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "Show text",IDC_SHOWTEXT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,7,49,10
+ CONTROL "Use old colors (black background)",IDC_USEOLDCOLORS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,19,123,10
+ CONTROL "Show commit charge instead of physical memory in summary view",IDC_SHOWCOMMITINSUMMARY,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,31,227,10
+ LTEXT "CPU kernel:",IDC_STATIC,7,48,39,8
+ CONTROL "CPU kernel",IDC_CPUKERNEL,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,73,46,33,13
+ LTEXT "CPU user:",IDC_STATIC,7,65,34,8
+ CONTROL "CPU user",IDC_CPUUSER,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,73,63,33,13
+ LTEXT "I/O R+O:",IDC_STATIC,7,82,32,8
+ CONTROL "I/O R+O",IDC_IORO,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,73,80,33,13
+ LTEXT "I/O W:",IDC_STATIC,7,98,23,8
+ CONTROL "I/O W",IDC_IOW,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,73,97,33,13
+ LTEXT "Private bytes:",IDC_STATIC,7,115,46,8
+ CONTROL "Private bytes",IDC_PRIVATE,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,73,113,33,13
+ LTEXT "Physical memory:",IDC_STATIC,7,131,56,8
+ CONTROL "Physical memory",IDC_PHYSICAL,"PhColorBox",WS_CLIPSIBLINGS | WS_TABSTOP,73,129,33,13
+END
+
+IDD_PLUGINMANAGER DIALOGEX 0, 0, 501, 272
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+CAPTION "Plugins"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Changes may require a restart to take effect.",IDC_INSTRUCTION,187,262,148,8,NOT WS_VISIBLE
+ DEFPUSHBUTTON "Close",IDOK,449,256,50,14
+ CONTROL "",IDC_PLUGINTREE,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0xa,2,2,497,253,WS_EX_CLIENTEDGE
+ PUSHBUTTON "Disabled plugins (0)",IDC_DISABLED,2,256,72,14
+END
+
+IDD_HANDLESTATS DIALOGEX 0, 0, 219, 175
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Handle Statistics"
+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,205,143
+ DEFPUSHBUTTON "Close",IDOK,162,154,50,14
+END
+
+IDD_PROCRECORD DIALOGEX 0, 0, 260, 202
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Process Record"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Name:",IDC_STATIC,7,9,22,8
+ EDITTEXT IDC_PROCESSNAME,39,9,214,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "Parent:",IDC_STATIC,7,21,25,8
+ EDITTEXT IDC_PARENT,39,21,214,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ GROUPBOX "File",IDC_FILE,7,38,246,79
+ ICON "",IDC_FILEICON,14,49,20,20
+ EDITTEXT IDC_NAME,44,48,182,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ EDITTEXT IDC_COMPANYNAME,44,60,183,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "Version:",IDC_STATIC,15,72,27,8
+ EDITTEXT IDC_VERSION,44,72,183,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "Image file name:",IDC_STATIC,15,86,56,8
+ EDITTEXT IDC_FILENAME,15,96,211,12,ES_AUTOHSCROLL | ES_READONLY
+ PUSHBUTTON "Open",IDC_OPENFILENAME,230,95,17,15,BS_ICON
+ LTEXT "Command line:",IDC_STATIC,7,123,50,8
+ EDITTEXT IDC_CMDLINE,65,121,188,12,ES_AUTOHSCROLL | ES_READONLY
+ LTEXT "Started:",IDC_STATIC,7,139,28,8
+ EDITTEXT IDC_STARTED,65,137,188,12,ES_AUTOHSCROLL | ES_READONLY
+ LTEXT "Terminated:",IDC_STATIC,7,155,40,8
+ EDITTEXT IDC_TERMINATED,65,153,188,12,ES_AUTOHSCROLL | ES_READONLY
+ LTEXT "Session ID:",IDC_STATIC,7,170,37,8
+ LTEXT "Static",IDC_SESSIONID,50,170,19,8
+ PUSHBUTTON "Properties",IDC_PROPERTIES,150,181,50,14
+ DEFPUSHBUTTON "Close",IDOK,203,181,50,14
+END
+
+IDD_CHOOSEPROCESS DIALOGEX 0, 0, 317, 239
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+CAPTION "Select a Process"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Select a process from the list below.",IDC_MESSAGE,7,7,303,8,SS_ENDELLIPSIS
+ CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,21,303,193
+ PUSHBUTTON "Refresh",IDC_REFRESH,7,218,50,14
+ DEFPUSHBUTTON "OK",IDOK,205,218,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,260,218,50,14
+END
+
+IDD_PROCSERVICES DIALOGEX 0, 0, 260, 261
+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 "Services",IDC_SERVICES_LAYOUT,7,7,246,247,NOT WS_VISIBLE | WS_BORDER
+END
+
+IDD_SHADOWSESSION DIALOGEX 0, 0, 228, 84
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Remote Control"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "To end the remote control session, press this key and the modifiers selected below:",IDC_STATIC,7,7,214,19
+ COMBOBOX IDC_VIRTUALKEY,7,27,74,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ CONTROL "Shift",IDC_SHIFT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,47,31,10
+ CONTROL "Ctrl",IDC_CTRL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,49,47,27,10
+ CONTROL "Alt",IDC_ALT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,89,47,25,10
+ DEFPUSHBUTTON "OK",IDOK,117,63,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,171,63,50,14
+END
+
+IDD_TOKCAPABILITIES DIALOGEX 0, 0, 270, 228
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Capabilities"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x32,0,0,270,228
+END
+
+IDD_TOKATTRIBUTES DIALOGEX 0, 0, 270, 228
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Attributes"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x32,0,0,270,228
+END
+
+IDD_SYSINFO_CPU DIALOGEX 0, 0, 316, 195
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "CPU"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ RTEXT "CPU name",IDC_CPUNAME,41,4,274,16,SS_WORDELLIPSIS
+ LTEXT "CPU",IDC_TITLE,0,0,37,21
+ LTEXT "Panel layout",IDC_LAYOUT,0,105,315,88,NOT WS_VISIBLE
+ LTEXT "Graph layout",IDC_GRAPH_LAYOUT,0,22,315,82,NOT WS_VISIBLE
+END
+
+IDD_SYSINFO_CPUPANEL DIALOGEX 0, 0, 237, 86
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Utilization:",IDC_STATIC,0,3,34,8
+ LTEXT "Speed:",IDC_STATIC,108,3,24,8
+ LTEXT "Static",IDC_UTILIZATION,40,0,62,15
+ LTEXT "Static",IDC_SPEED,137,0,100,15
+ GROUPBOX "System",IDC_STATIC,0,17,97,55
+ LTEXT "Processes",IDC_STATIC,7,28,33,8
+ LTEXT "Threads",IDC_STATIC,7,38,27,8
+ LTEXT "Handles",IDC_STATIC,7,48,26,8
+ LTEXT "Uptime",IDC_STATIC,7,58,23,8
+ RTEXT "Static",IDC_ZPROCESSES_V,45,28,46,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZTHREADS_V,45,38,46,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZHANDLES_V,45,48,46,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZUPTIME_V,46,58,45,8,SS_ENDELLIPSIS
+ CONTROL "&Show one graph per CPU",IDC_ONEGRAPHPERCPU,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,0,76,96,10
+ GROUPBOX "CPU",IDC_STATIC,101,17,136,55
+ LTEXT "Context switches delta",IDC_STATIC,109,28,76,8
+ LTEXT "Interrupts delta",IDC_STATIC,109,38,52,8
+ LTEXT "DPCs delta",IDC_STATIC,109,48,36,8
+ LTEXT "System calls delta",IDC_STATIC,109,58,60,8
+ RTEXT "Static",IDC_ZCONTEXTSWITCHESDELTA_V,191,28,40,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZINTERRUPTSDELTA_V,185,39,46,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZDPCSDELTA_V,181,48,50,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZSYSTEMCALLSDELTA_V,179,59,52,8,SS_ENDELLIPSIS
+END
+
+IDD_SYSINFO_MEMPANEL DIALOGEX 0, 0, 358, 171
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ GROUPBOX "Commit charge",IDC_STATIC,0,0,108,44
+ LTEXT "Current",IDC_STATIC,7,11,26,8
+ LTEXT "Peak",IDC_STATIC,7,21,16,8
+ LTEXT "Limit",IDC_STATIC,7,31,15,8
+ RTEXT "Static",IDC_ZCOMMITCURRENT_V,45,11,56,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZCOMMITPEAK_V,41,21,60,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZCOMMITLIMIT_V,40,31,61,8,SS_ENDELLIPSIS
+ GROUPBOX "Physical memory",IDC_STATIC,112,0,118,73
+ LTEXT "Current",IDC_STATIC,120,11,26,8
+ LTEXT "Cache WS",IDC_STATIC,120,41,34,8
+ RTEXT "Static",IDC_ZPHYSICALCURRENT_V,165,11,57,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZPHYSICALTOTAL_V,167,21,55,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZPHYSICALCACHEWS_V,159,41,63,8,SS_ENDELLIPSIS
+ LTEXT "Total",IDC_STATIC,120,21,17,8
+ LTEXT "Kernel WS",IDC_STATIC,120,51,34,8
+ RTEXT "Static",IDC_ZPHYSICALKERNELWS_V,167,51,55,8,SS_ENDELLIPSIS
+ LTEXT "Driver WS",IDC_STATIC,120,61,33,8
+ RTEXT "Static",IDC_ZPHYSICALDRIVERWS_V,163,61,59,8,SS_ENDELLIPSIS
+ GROUPBOX "Paged pool",IDC_STATIC,0,47,108,64
+ LTEXT "Working set",IDC_STATIC,7,58,40,8
+ LTEXT "Limit",IDC_STATIC,7,78,15,8
+ RTEXT "Static",IDC_ZPAGEDWORKINGSET_V,54,58,47,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZPAGEDVIRTUALSIZE_V,52,68,49,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZPAGEDLIMIT_V,48,78,53,8,SS_ENDELLIPSIS
+ LTEXT "Virtual size",IDC_STATIC,7,68,36,8
+ LTEXT "Allocs delta",IDC_STATIC,7,88,38,8
+ RTEXT "Static",IDC_ZPAGEDALLOCSDELTA_V,53,88,48,8,SS_ENDELLIPSIS
+ LTEXT "Frees delta",IDC_STATIC,7,98,38,8
+ RTEXT "Static",IDC_ZPAGEDFREESDELTA_V,51,98,50,8,SS_ENDELLIPSIS
+ GROUPBOX "Non-paged pool",IDC_STATIC,0,114,108,55
+ LTEXT "Usage",IDC_STATIC,7,125,21,8
+ LTEXT "Allocs delta",IDC_STATIC,7,145,38,8
+ RTEXT "Static",IDC_ZNONPAGEDUSAGE_V,54,125,47,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZNONPAGEDLIMIT_V,52,135,49,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZNONPAGEDALLOCSDELTA_V,56,145,45,8,SS_ENDELLIPSIS
+ LTEXT "Limit",IDC_STATIC,7,135,15,8
+ LTEXT "Frees delta",IDC_STATIC,7,155,38,8
+ RTEXT "Static",IDC_ZNONPAGEDFREESDELTA_V,56,155,45,8,SS_ENDELLIPSIS
+ GROUPBOX "Memory lists",IDC_STATIC,234,0,123,169
+ LTEXT "Zeroed",IDC_STATIC,242,11,24,8
+ LTEXT "Modified",IDC_STATIC,242,31,28,8
+ RTEXT "Static",IDC_ZLISTZEROED_V,304,11,47,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTFREE_V,302,21,49,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTMODIFIED_V,298,31,53,8,SS_ENDELLIPSIS
+ LTEXT "Free",IDC_STATIC,242,21,16,8
+ LTEXT "Modified no-write",IDC_STATIC,242,41,56,8
+ RTEXT "Static",IDC_ZLISTMODIFIEDNOWRITE_V,303,41,48,8,SS_ENDELLIPSIS
+ LTEXT "Standby",IDC_STATIC,242,61,28,8
+ LTEXT "Priority 0",IDC_STATIC,251,71,30,8
+ LTEXT "Priority 1",IDC_STATIC,251,80,30,8
+ LTEXT "Priority 2",IDC_STATIC,251,90,30,8
+ LTEXT "Priority 3",IDC_STATIC,251,100,30,8
+ LTEXT "Priority 4",IDC_STATIC,251,110,30,8
+ LTEXT "Priority 5",IDC_STATIC,251,120,30,8
+ LTEXT "Priority 6",IDC_STATIC,251,130,30,8
+ LTEXT "Priority 7",IDC_STATIC,251,140,30,8
+ RTEXT "Static",IDC_ZLISTSTANDBY_V,303,61,48,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTSTANDBY0_V,303,71,48,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTSTANDBY1_V,303,80,48,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTSTANDBY2_V,303,90,48,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTSTANDBY3_V,303,100,48,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTSTANDBY4_V,303,110,48,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTSTANDBY5_V,303,120,48,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTSTANDBY6_V,303,130,48,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTSTANDBY7_V,303,140,48,8,SS_ENDELLIPSIS
+ GROUPBOX "Paging",IDC_STATIC,112,75,118,55
+ LTEXT "Page faults delta",IDC_STATIC,120,86,57,8
+ LTEXT "Pagefile writes delta",IDC_STATIC,120,106,68,8
+ RTEXT "Static",IDC_ZPAGINGPAGEFAULTSDELTA_V,183,86,39,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZPAGINGPAGEREADSDELTA_V,179,96,43,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZPAGINGPAGEFILEWRITESDELTA_V,189,106,33,8,SS_ENDELLIPSIS
+ LTEXT "Page reads delta",IDC_STATIC,120,96,58,8
+ LTEXT "Mapped writes delta",IDC_STATIC,120,116,68,8
+ RTEXT "Static",IDC_ZPAGINGMAPPEDWRITESDELTA_V,191,116,31,8,SS_ENDELLIPSIS
+ LTEXT "Modified pagefile",IDC_STATIC,242,51,55,8
+ RTEXT "Static",IDC_ZLISTMODIFIEDPAGEFILE_V,303,51,48,8,SS_ENDELLIPSIS
+ PUSHBUTTON "&More",IDC_MORE,242,152,50,14
+ RTEXT "Static",IDC_ZPHYSICALRESERVED_V,167,31,55,8,SS_ENDELLIPSIS
+ LTEXT "Reserved",IDC_STATIC,120,31,32,8
+ GROUPBOX "Mapped IO",IDC_STATIC,112,132,118,36
+ LTEXT "Mapped reads",IDC_STATIC,119,145,68,8
+ RTEXT "Static",IDC_ZMAPPEDREADIO,180,145,42,8,SS_ENDELLIPSIS
+ LTEXT "Mapped writes",IDC_STATIC,119,156,68,8
+ RTEXT "Static",IDC_ZMAPPEDWRITEIO,180,156,42,8,SS_ENDELLIPSIS
+END
+
+IDD_SYSINFO_MEM DIALOGEX 0, 0, 316, 250
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Memory"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Memory",IDC_TITLE,0,0,110,21
+ LTEXT "Panel layout",IDC_LAYOUT,0,74,315,175,NOT WS_VISIBLE
+ LTEXT "Graph layout",IDC_GRAPH_LAYOUT,0,22,315,51,NOT WS_VISIBLE
+ RTEXT "Total physical",IDC_TOTALPHYSICAL,127,4,188,16,SS_WORDELLIPSIS
+ LTEXT "Commit charge:",IDC_COMMIT_L,111,1,52,8
+ LTEXT "Physical memory:",IDC_PHYSICAL_L,111,7,56,8
+END
+
+IDD_SYSINFO_IO DIALOGEX 0, 0, 316, 187
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CAPTION | WS_SYSMENU
+CAPTION "I/O"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "I/O",IDC_TITLE,0,0,110,21
+ LTEXT "Panel layout",IDC_LAYOUT,0,109,315,78,NOT WS_VISIBLE
+ LTEXT "Graph layout",IDC_GRAPH_LAYOUT,0,22,315,84,NOT WS_VISIBLE
+END
+
+IDD_SYSINFO_IOPANEL DIALOGEX 0, 0, 276, 75
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ GROUPBOX "I/O deltas",IDC_STATIC,0,0,133,74
+ LTEXT "Reads delta",IDC_STATIC,7,11,40,8
+ LTEXT "Read bytes delta",IDC_STATIC,7,21,56,8
+ LTEXT "Writes delta",IDC_STATIC,7,31,40,8
+ LTEXT "Write bytes delta",IDC_STATIC,7,41,57,8
+ RTEXT "Static",IDC_ZREADSDELTA_V,59,11,67,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZREADBYTESDELTA_V,75,21,51,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZWRITESDELTA_V,57,31,69,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZWRITEBYTESDELTA_V,73,41,53,8,SS_ENDELLIPSIS
+ LTEXT "Other delta",IDC_STATIC,7,51,38,8
+ LTEXT "Other bytes delta",IDC_STATIC,7,61,58,8
+ RTEXT "Static",IDC_ZOTHERDELTA_V,67,51,59,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZOTHERBYTESDELTA_V,81,61,45,8,SS_ENDELLIPSIS
+ GROUPBOX "I/O totals",IDC_STATIC,137,0,133,74
+ LTEXT "Reads",IDC_STATIC,145,11,21,8
+ LTEXT "Read bytes",IDC_STATIC,145,21,38,8
+ LTEXT "Writes",IDC_STATIC,145,31,22,8
+ LTEXT "Write bytes",IDC_STATIC,145,41,38,8
+ RTEXT "Static",IDC_ZREADS_V,197,11,67,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZREADBYTES_V,192,21,72,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZWRITES_V,195,31,69,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZWRITEBYTES_V,190,41,74,8,SS_ENDELLIPSIS
+ LTEXT "Other",IDC_STATIC,145,51,20,8
+ LTEXT "Other bytes",IDC_STATIC,145,61,40,8
+ RTEXT "Static",IDC_ZOTHER_V,191,51,73,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZOTHERBYTES_V,192,61,72,8,SS_ENDELLIPSIS
+END
+
+IDD_MEMLISTS DIALOGEX 0, 0, 228, 195
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_TOPMOST
+CAPTION "Memory Lists"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "Close",IDOK,171,174,50,14
+ LTEXT "Zeroed",IDC_STATIC,7,7,24,8
+ LTEXT "Free",IDC_STATIC,7,17,16,8
+ LTEXT "Modified",IDC_STATIC,7,28,28,8
+ LTEXT "Modified no-write",IDC_STATIC,7,39,56,8
+ LTEXT "Bad",IDC_STATIC,7,60,13,8
+ LTEXT "Standby",IDC_STATIC,7,72,28,8
+ LTEXT "Priority 0",IDC_STATIC,23,83,30,8
+ LTEXT "Priority 1",IDC_STATIC,23,94,30,8
+ LTEXT "Priority 2",IDC_STATIC,23,105,30,8
+ LTEXT "Priority 3",IDC_STATIC,23,116,30,8
+ LTEXT "Priority 4",IDC_STATIC,23,128,30,8
+ LTEXT "Priority 5",IDC_STATIC,23,139,30,8
+ LTEXT "Priority 6",IDC_STATIC,23,150,30,8
+ LTEXT "Priority 7",IDC_STATIC,23,161,30,8
+ RTEXT "Static",IDC_ZLISTZEROED_V,73,7,59,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTFREE_V,73,17,59,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTMODIFIED_V,73,28,59,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTMODIFIEDNOWRITE_V,73,39,59,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTBAD_V,73,60,59,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTSTANDBY_V,73,72,59,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTSTANDBY0_V,73,83,59,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTSTANDBY1_V,73,94,59,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTSTANDBY2_V,73,105,59,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTSTANDBY3_V,73,116,59,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTSTANDBY4_V,73,128,59,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTSTANDBY5_V,73,139,59,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTSTANDBY6_V,73,150,59,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTSTANDBY7_V,73,161,59,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTREPURPOSED_V,162,72,59,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTREPURPOSED0_V,162,84,59,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTREPURPOSED1_V,162,95,59,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTREPURPOSED2_V,162,106,59,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTREPURPOSED3_V,162,117,59,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTREPURPOSED4_V,162,128,59,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTREPURPOSED5_V,162,139,59,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTREPURPOSED6_V,162,150,59,8,SS_ENDELLIPSIS
+ RTEXT "Static",IDC_ZLISTREPURPOSED7_V,162,161,59,8,SS_ENDELLIPSIS
+ RTEXT "(Repurposed)",IDC_STATIC,162,60,59,8
+ PUSHBUTTON "&Empty",IDC_EMPTY,117,174,50,14
+ LTEXT "Modified pagefile",IDC_STATIC,7,49,55,8
+ RTEXT "Static",IDC_ZLISTMODIFIEDPAGEFILE_V,73,49,59,8,SS_ENDELLIPSIS
+END
+
+IDD_CONTAINER DIALOGEX 0, 0, 316, 182
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+END
+
+IDD_MINIINFO DIALOGEX 0, 0, 217, 150
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Content layout",IDC_LAYOUT,4,3,210,128,NOT WS_VISIBLE
+ CONTROL "Section",IDC_SECTION,"Static",SS_LEFTNOWORDWRAP | SS_NOTIFY | SS_ENDELLIPSIS | WS_GROUP,4,134,177,13
+ PUSHBUTTON "Options",IDC_OPTIONS,183,133,15,14,BS_ICON
+ CONTROL "Pin",IDC_PINWINDOW,"Button",BS_AUTOCHECKBOX | BS_ICON | BS_PUSHLIKE | WS_TABSTOP,199,133,15,14
+END
+
+IDD_MINIINFO_LIST DIALOGEX 0, 0, 217, 141
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "CPU"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TABSTOP | 0x82,0,0,217,140,WS_EX_CLIENTEDGE
+END
+
+IDD_MITIGATION DIALOGEX 0, 0, 277, 217
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Mitigation Policies"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,7,7,263,108
+ LTEXT "Description:",IDC_DESCRIPTIONLABEL,7,118,38,8
+ EDITTEXT IDC_DESCRIPTION,7,129,263,62,ES_MULTILINE | ES_READONLY | WS_VSCROLL
+ DEFPUSHBUTTON "OK",IDOK,220,196,50,14
+END
+
+IDD_EDITENV DIALOGEX 0, 0, 311, 177
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+CAPTION "Edit Environment Variable"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Name:",IDC_STATIC,7,8,21,8
+ EDITTEXT IDC_NAME,38,7,266,12,ES_AUTOHSCROLL
+ LTEXT "Value:",IDC_STATIC,7,25,21,8
+ EDITTEXT IDC_VALUE,38,24,266,128,ES_MULTILINE | WS_VSCROLL
+ DEFPUSHBUTTON "OK",IDOK,200,156,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,254,156,50,14
+END
+
+IDD_OPTIONS DIALOGEX 0, 0, 423, 247
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+CAPTION "Options"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "Close",IDOK,371,231,50,14
+ CONTROL "",IDC_SECTIONTREE,"SysTreeView32",TVS_SHOWSELALWAYS | TVS_TRACKSELECT | TVS_FULLROWSELECT | WS_HSCROLL | WS_TABSTOP,2,1,103,244
+ CONTROL "",IDD_CONTAINER,"#32770",0x44c,107,0,316,229,WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT | 0xc0000800L
+ LTEXT "",IDC_SEPARATOR,105,0,8,246
+ PUSHBUTTON "Reset",IDC_RESET,113,231,50,14
+ PUSHBUTTON "Apply",IDC_APPLY,319,231,50,14,NOT WS_VISIBLE
+ PUSHBUTTON "Cleanup",IDC_CLEANUP,165,231,50,14
+END
+
+IDD_PLUGINPROPERTIES DIALOGEX 0, 0, 291, 152
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Plugin Properties"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ GROUPBOX "Plugin",IDC_STATIC,7,7,277,122
+ LTEXT "Name:",IDC_STATIC,15,18,22,8
+ EDITTEXT IDC_NAME,71,18,104,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "Internal name:",IDC_STATIC,15,30,49,8
+ EDITTEXT IDC_INTERNALNAME,71,30,203,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "Author:",IDC_STATIC,15,41,26,8
+ EDITTEXT IDC_AUTHOR,71,41,203,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "URL:",IDC_STATIC,15,52,16,8
+ EDITTEXT IDC_URL,71,52,174,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ CONTROL "Open",IDC_OPENURL,"SysLink",WS_TABSTOP,250,52,26,10
+ LTEXT "File name:",IDC_STATIC,15,63,34,8
+ EDITTEXT IDC_FILENAME,71,63,203,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "Version:",IDC_STATIC,183,18,27,8
+ EDITTEXT IDC_VERSION,215,18,59,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "Description:",IDC_STATIC,15,74,39,8
+ EDITTEXT IDC_DESCRIPTION,14,86,263,37,ES_MULTILINE | ES_READONLY
+ PUSHBUTTON "Options...",IDC_OPTIONS,7,131,50,14
+ DEFPUSHBUTTON "Close",IDOK,234,131,50,14
+END
+
+IDD_PLUGINSDISABLED DIALOGEX 0, 0, 309, 176
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Disabled Plugins"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,257,160,50,14
+ CONTROL "",IDC_LIST_DISABLED,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,2,2,305,157
+ LTEXT "Changes may require a restart to take effect.",IDC_INSTRUCTION,2,163,148,8,NOT WS_VISIBLE
+END
+
+IDD_PROCWMIPROVIDERS DIALOGEX 0, 0, 260, 260
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "WMI Providers"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_LIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,2,2,256,256
+END
+
+IDD_COLUMNSETS DIALOGEX 0, 0, 231, 188
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Organize Column Sets"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ PUSHBUTTON "Move up",IDC_MOVEUP,177,42,50,14
+ PUSHBUTTON "Move down",IDC_MOVEDOWN,177,59,50,14
+ PUSHBUTTON "OK",IDOK,177,171,50,14
+ PUSHBUTTON "Rename",IDC_RENAME,177,4,50,14
+ PUSHBUTTON "Delete",IDC_REMOVE,177,94,50,14
+ CONTROL "",IDC_COLUMNSETLIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_EDITLABELS | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,4,4,170,180
+END
+
+IDD_RUNFILEDLG DIALOGEX 0, 0, 235, 105
+STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Run"
+FONT 9, "Segoe UI", 0, 0, 0x1
+BEGIN
+ ICON 100,IDC_FILEICON,7,11,18,17
+ LTEXT "Type the name of a program, folder, document, or Internet resource, and Windows will open it for you.",IDC_STATIC,36,11,182,22
+ LTEXT "&Open:",IDC_STATIC,7,39,28,10
+ COMBOBOX IDC_PROGRAMCOMBO,36,37,183,200,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_DISABLENOSCROLL | WS_VSCROLL | WS_TABSTOP
+ CONTROL "Create this task with administrative privileges.",IDC_TOGGLEELEVATION,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,40,50,180,10
+ DEFPUSHBUTTON "OK",IDOK,62,82,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,116,82,50,14
+ PUSHBUTTON "&Browse...",IDC_BROWSE,170,82,50,14
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_PROCGENERAL, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 253
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 253
+ END
+
+ IDD_PROCMODULES, DIALOG
+ BEGIN
+ LEFTMARGIN, 2
+ RIGHTMARGIN, 258
+ TOPMARGIN, 2
+ BOTTOMMARGIN, 258
+ END
+
+ IDD_PROCTHREADS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 253
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 253
+ END
+
+ IDD_PROCHANDLES, DIALOG
+ BEGIN
+ LEFTMARGIN, 2
+ RIGHTMARGIN, 258
+ TOPMARGIN, 2
+ BOTTOMMARGIN, 258
+ END
+
+ IDD_PROCENVIRONMENT, DIALOG
+ BEGIN
+ LEFTMARGIN, 2
+ RIGHTMARGIN, 258
+ TOPMARGIN, 2
+ BOTTOMMARGIN, 258
+ END
+
+ IDD_THRDSTACK, DIALOG
+ BEGIN
+ LEFTMARGIN, 2
+ RIGHTMARGIN, 271
+ TOPMARGIN, 2
+ BOTTOMMARGIN, 226
+ END
+
+ IDD_ABOUT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 263
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 188
+ END
+
+ IDD_SRVLIST, DIALOG
+ BEGIN
+ END
+
+ IDD_SRVGENERAL, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 275
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 176
+ END
+
+ IDD_HNDLGENERAL, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 253
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 174
+ END
+
+ IDD_INFORMATION, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 310
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 177
+ END
+
+ IDD_FINDOBJECTS, DIALOG
+ BEGIN
+ LEFTMARGIN, 2
+ RIGHTMARGIN, 355
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 231
+ END
+
+ IDD_OBJTOKEN, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 253
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 253
+ END
+
+ IDD_HIDDENPROCESSES, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 330
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 214
+ END
+
+ IDD_RUNAS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 286
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 120
+ END
+
+ IDD_PROGRESS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 209
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 55
+ END
+
+ IDD_PAGEFILES, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 315
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 155
+ END
+
+ IDD_TOKGENERAL, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 263
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 221
+ END
+
+ IDD_TOKADVANCED, DIALOG
+ BEGIN
+ END
+
+ IDD_OBJJOB, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 253
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 253
+ END
+
+ IDD_OBJEVENT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 179
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 69
+ END
+
+ IDD_OBJMUTANT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 179
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 69
+ END
+
+ IDD_OBJSEMAPHORE, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 179
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 69
+ END
+
+ IDD_OBJTIMER, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 179
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 69
+ END
+
+ IDD_JOBSTATISTICS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 252
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 179
+ END
+
+ IDD_OBJEVENTPAIR, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 179
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 69
+ END
+
+ IDD_AFFINITY, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 272
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 220
+ END
+
+ IDD_SYSINFO, DIALOG
+ BEGIN
+ END
+
+ IDD_EDITMESSAGE, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 275
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 156
+ END
+
+ IDD_SESSION, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 194
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 142
+ END
+
+ IDD_PROCMEMORY, DIALOG
+ BEGIN
+ LEFTMARGIN, 2
+ RIGHTMARGIN, 258
+ TOPMARGIN, 2
+ BOTTOMMARGIN, 258
+ END
+
+ IDD_CHOOSE, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 192
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 66
+ END
+
+ IDD_OPTGENERAL, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 308
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 213
+ END
+
+ IDD_OPTHIGHLIGHTING, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 243
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 167
+ END
+
+ IDD_CHOOSECOLUMNS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 374
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 200
+ END
+
+ IDD_NETSTACK, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 254
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 221
+ END
+
+ IDD_CREATESERVICE, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 280
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 126
+ END
+
+ IDD_PROCPERFORMANCE, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 253
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 253
+ END
+
+ IDD_PROCSTATISTICS, DIALOG
+ BEGIN
+ LEFTMARGIN, 2
+ RIGHTMARGIN, 257
+ TOPMARGIN, 3
+ BOTTOMMARGIN, 258
+ END
+
+ IDD_OPTADVANCED, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 310
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 218
+ END
+
+ IDD_GDIHANDLES, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 344
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 300
+ END
+
+ IDD_LOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 306
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 296
+ END
+
+ IDD_MEMEDIT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 434
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 262
+ END
+
+ IDD_MEMPROTECT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 263
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 164
+ END
+
+ IDD_MEMRESULTS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 306
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 259
+ END
+
+ IDD_MEMSTRING, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 234
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 79
+ END
+
+ IDD_OPTGRAPHS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 243
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 149
+ END
+
+ IDD_PLUGINMANAGER, DIALOG
+ BEGIN
+ LEFTMARGIN, 2
+ RIGHTMARGIN, 499
+ TOPMARGIN, 2
+ BOTTOMMARGIN, 270
+ END
+
+ IDD_HANDLESTATS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 212
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 168
+ END
+
+ IDD_PROCRECORD, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 253
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 195
+ END
+
+ IDD_CHOOSEPROCESS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 310
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 232
+ END
+
+ IDD_PROCSERVICES, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 253
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 254
+ END
+
+ IDD_SHADOWSESSION, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 221
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 77
+ END
+
+ IDD_TOKCAPABILITIES, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 263
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 221
+ END
+
+ IDD_TOKATTRIBUTES, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 263
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 221
+ END
+
+ IDD_SYSINFO_CPU, DIALOG
+ BEGIN
+ BOTTOMMARGIN, 193
+ END
+
+ IDD_SYSINFO_CPUPANEL, DIALOG
+ BEGIN
+ BOTTOMMARGIN, 85
+ END
+
+ IDD_SYSINFO_MEMPANEL, DIALOG
+ BEGIN
+ END
+
+ IDD_SYSINFO_MEM, DIALOG
+ BEGIN
+ BOTTOMMARGIN, 247
+ END
+
+ IDD_SYSINFO_IO, DIALOG
+ BEGIN
+ END
+
+ IDD_SYSINFO_IOPANEL, DIALOG
+ BEGIN
+ BOTTOMMARGIN, 74
+ END
+
+ IDD_MEMLISTS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 221
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 188
+ END
+
+ IDD_CONTAINER, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 309
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 175
+ END
+
+ IDD_MINIINFO, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 214
+ TOPMARGIN, 3
+ BOTTOMMARGIN, 147
+ END
+
+ IDD_MINIINFO_LIST, DIALOG
+ BEGIN
+ END
+
+ IDD_MITIGATION, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 270
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 210
+ END
+
+ IDD_EDITENV, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 304
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 170
+ END
+
+ IDD_OPTIONS, DIALOG
+ BEGIN
+ LEFTMARGIN, 2
+ BOTTOMMARGIN, 245
+ END
+
+ IDD_PLUGINPROPERTIES, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 284
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 145
+ END
+
+ IDD_PLUGINSDISABLED, DIALOG
+ BEGIN
+ LEFTMARGIN, 2
+ RIGHTMARGIN, 307
+ TOPMARGIN, 2
+ BOTTOMMARGIN, 174
+ END
+
+ IDD_PROCWMIPROVIDERS, DIALOG
+ BEGIN
+ LEFTMARGIN, 2
+ RIGHTMARGIN, 258
+ TOPMARGIN, 2
+ BOTTOMMARGIN, 258
+ END
+
+ IDD_COLUMNSETS, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 227
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 184
+ END
+ IDD_RUNFILEDLG, DIALOG
+ BEGIN
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDR_MAINWND_ACCEL ACCELERATORS
+BEGIN
+ VK_ESCAPE, ID_ESC_EXIT, VIRTKEY, NOINVERT
+ "F", ID_HACKER_FINDHANDLESORDLLS, VIRTKEY, CONTROL, NOINVERT
+ "R", ID_HACKER_RUN, VIRTKEY, CONTROL, NOINVERT
+ "R", ID_HACKER_RUNAS, VIRTKEY, SHIFT, CONTROL, NOINVERT
+ "S", ID_HACKER_SAVE, VIRTKEY, CONTROL, NOINVERT
+ "L", ID_HELP_LOG, VIRTKEY, CONTROL, NOINVERT
+ "M", ID_PROCESS_SEARCHONLINE, VIRTKEY, CONTROL, NOINVERT
+ VK_TAB, ID_TAB_NEXT, VIRTKEY, CONTROL, NOINVERT
+ VK_TAB, ID_TAB_PREV, VIRTKEY, SHIFT, CONTROL, NOINVERT
+ VK_F5, ID_VIEW_REFRESH, VIRTKEY, NOINVERT
+ "I", ID_VIEW_SYSTEMINFORMATION, VIRTKEY, CONTROL, NOINVERT
+ VK_PAUSE, ID_VIEW_UPDATEAUTOMATICALLY, VIRTKEY, NOINVERT
+ VK_F6, ID_VIEW_UPDATEAUTOMATICALLY, VIRTKEY, NOINVERT
+END
+
+IDR_SYSINFO_ACCEL ACCELERATORS
+BEGIN
+ "1", ID_DIGIT1, VIRTKEY, NOINVERT
+ "2", ID_DIGIT2, VIRTKEY, NOINVERT
+ "3", ID_DIGIT3, VIRTKEY, NOINVERT
+ "4", ID_DIGIT4, VIRTKEY, NOINVERT
+ "5", ID_DIGIT5, VIRTKEY, NOINVERT
+ "6", ID_DIGIT6, VIRTKEY, NOINVERT
+ "7", ID_DIGIT7, VIRTKEY, NOINVERT
+ "8", ID_DIGIT8, VIRTKEY, NOINVERT
+ "9", ID_DIGIT9, VIRTKEY, NOINVERT
+ "B", IDC_BACK, VIRTKEY, ALT, NOINVERT
+ VK_BACK, IDC_BACK, VIRTKEY, NOINVERT
+ VK_F6, IDC_PAUSE, VIRTKEY, NOINVERT
+ VK_PAUSE, IDC_PAUSE, VIRTKEY, NOINVERT
+ VK_F5, IDC_REFRESH, VIRTKEY, NOINVERT
+ VK_F11, IDC_MAXSCREEN, VIRTKEY, NOINVERT
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_CROSS BITMAP "resources\\cross.bmp"
+
+IDB_TICK BITMAP "resources\\tick.bmp"
+
+IDB_SEARCH_ACTIVE_BMP BITMAP "resources\\active_search.bmp"
+
+IDB_SEARCH_INACTIVE_BMP BITMAP "resources\\inactive_search.bmp"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// RT_MANIFEST
+//
+
+IDR_RT_MANIFEST RT_MANIFEST "ProcessHacker.manifest"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// PNG
+//
+
+IDB_SEARCH_ACTIVE PNG "resources\\active_search.png"
+
+IDB_SEARCH_INACTIVE PNG "resources\\inactive_search.png"
+
+#endif // English (Australia) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/ProcessHacker/ProcessHacker.vcxproj b/ProcessHacker/ProcessHacker.vcxproj
index 7b8342faa6c4..00285a8f03ad 100644
--- a/ProcessHacker/ProcessHacker.vcxproj
+++ b/ProcessHacker/ProcessHacker.vcxproj
@@ -1,439 +1,447 @@
-
-
-
-
- Debug
- Win32
-
-
- Debug
- x64
-
-
- Release
- Win32
-
-
- Release
- x64
-
-
-
- {0271DD27-6707-4290-8DFE-285702B7115D}
- ProcessHacker
- Win32Proj
- 10.0.15063.0
-
-
-
- Application
- Unicode
- true
- v141
-
-
- Application
- Unicode
- v141
-
-
- Application
- Unicode
- true
- v141
-
-
- Application
- Unicode
- v141
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\
- $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\
- false
- $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\
- $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\
- false
- $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\
- $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\
- false
- $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\
- $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\
- false
- false
- false
- false
- false
-
-
-
- Disabled
- ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories)
- _PHLIB_;_PHAPP_;_WINDOWS;WIN32;DEBUG;%(PreprocessorDefinitions)
- EnableFastChecks
- MultiThreadedDebug
- Level3
- ProgramDatabase
- StdCall
- true
- true
-
-
- aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies)
- true
- Windows
- MachineX86
- 6.01
- ..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories)
- ProcessHacker.def
- aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs)
-
-
- ..\build\CustomBuildTool.exe -updaterev
- Generating revision number...
-
-
- ..\build\CustomBuildTool.exe -cleanup
- Cleaning up build...
-
-
-
-
- Disabled
- ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories)
- _PHLIB_;_PHAPP_;_WINDOWS;WIN64;DEBUG;%(PreprocessorDefinitions)
- EnableFastChecks
- MultiThreadedDebug
- Level3
- ProgramDatabase
- StdCall
- true
- true
-
-
- aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies)
- true
- Windows
- MachineX64
- 6.01
- ..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories)
- ProcessHacker.def
- aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs)
-
-
- ..\build\CustomBuildTool.exe -updaterev
- Generating revision number...
-
-
- ..\build\CustomBuildTool.exe -cleanup
- Cleaning up build...
-
-
-
-
- MaxSpeed
- true
- ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories)
- _PHLIB_;_PHAPP_;_WINDOWS;WIN32;NDEBUG;%(PreprocessorDefinitions)
- true
- MultiThreaded
- false
- true
- Level3
- ProgramDatabase
- StdCall
- true
- true
- StreamingSIMDExtensions
-
-
- aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies)
- true
- Windows
- true
- true
- MachineX86
- true
- 6.01
- ..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories)
- ProcessHacker.def
- aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs)
-
-
- ..\build\CustomBuildTool.exe -updaterev
- Generating revision number...
-
-
- ..\build\CustomBuildTool.exe -cleanup
- Cleaning up build...
-
-
-
-
- MaxSpeed
- true
- ..\phnt\include;..\phlib\include;include;%(AdditionalIncludeDirectories)
- _PHLIB_;_PHAPP_;_WINDOWS;WIN64;NDEBUG;%(PreprocessorDefinitions)
- true
- MultiThreaded
- false
- true
- Level3
- ProgramDatabase
- StdCall
- true
- true
-
-
- aclui.lib;comctl32.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;uxtheme.lib;version.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies)
- true
- Windows
- true
- true
- MachineX64
- true
- 6.01
- ..\phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories)
- ProcessHacker.def
- aclui.dll;iphlpapi.dll;ws2_32.dll;%(DelayLoadDLLs)
-
-
- ..\build\CustomBuildTool.exe -updaterev
- Generating revision number...
-
-
- ..\build\CustomBuildTool.exe -cleanup
- Cleaning up build...
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Designer
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {0271DD27-6707-4290-8DFE-285702B7115D}
+ ProcessHacker
+ Win32Proj
+ 10.0
+
+
+
+ Application
+ Unicode
+ true
+ v142
+ WindowsLocalDebugger
+ $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\
+ Spectre
+
+
+ Application
+ Unicode
+ v142
+ WindowsLocalDebugger
+ $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\
+
+
+ Application
+ Unicode
+ true
+ v142
+ WindowsLocalDebugger
+ $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\
+ Spectre
+
+
+ Application
+ Unicode
+ v142
+ WindowsLocalDebugger
+ $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\
+ $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\
+ false
+ $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\
+ $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\
+ false
+ $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\
+ $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\
+ false
+ $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\
+ $(ProjectDir)obj\$(Configuration)$(PlatformArchitecture)\
+ false
+ false
+ false
+ false
+ false
+
+
+
+ Disabled
+ $(SolutionDir)phnt\include;$(SolutionDir)phlib\include;include;%(AdditionalIncludeDirectories)
+ _PHLIB_;_PHAPP_;_WINDOWS;HAVE_CONFIG_H;WIN32;_DEBUG;DEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions)
+ EnableFastChecks
+ MultiThreadedDebug
+ Level3
+ ProgramDatabase
+ StdCall
+ true
+ true
+ true
+
+
+ aclui.lib;comctl32.lib;dnsapi.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;shlwapi.lib;userenv.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies)
+ true
+ Windows
+ MachineX86
+ 6.01
+ $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories)
+ ProcessHacker.def
+ advapi32.dll;aclui.dll;comdlg32.dll;comctl32.dll;dnsapi.dll;gdi32.dll;iphlpapi.dll;oleaut32.dll;ole32.dll;shell32.dll;shlwapi.dll;userenv.dll;user32.dll;uxtheme.dll;version.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs)
+ /DEPENDENTLOADFLAG:0xA00 %(AdditionalOptions)
+
+
+ _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions)
+ $(SolutionDir)phnt\include;$(SolutionDir)phlib\include;include;%(AdditionalIncludeDirectories)
+
+
+ "$(SolutionDir)build\build_sdk.cmd"
+
+
+
+
+ Disabled
+ $(SolutionDir)phnt\include;$(SolutionDir)phlib\include;include;%(AdditionalIncludeDirectories)
+ _PHLIB_;_PHAPP_;_WINDOWS;HAVE_CONFIG_H;WIN64;_DEBUG;DEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions)
+ EnableFastChecks
+ MultiThreadedDebug
+ Level3
+ ProgramDatabase
+ StdCall
+ true
+ true
+ true
+
+
+ aclui.lib;comctl32.lib;dnsapi.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;shlwapi.lib;userenv.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies)
+ true
+ Windows
+ MachineX64
+ 6.01
+ $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories)
+ ProcessHacker.def
+ advapi32.dll;aclui.dll;comdlg32.dll;comctl32.dll;dnsapi.dll;gdi32.dll;iphlpapi.dll;oleaut32.dll;ole32.dll;shell32.dll;shlwapi.dll;userenv.dll;user32.dll;uxtheme.dll;version.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs)
+ /DEPENDENTLOADFLAG:0xA00 %(AdditionalOptions)
+
+
+ _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions)
+ $(SolutionDir)phnt\include;$(SolutionDir)phlib\include;include;%(AdditionalIncludeDirectories)
+
+
+
+ "$(SolutionDir)build\build_sdk.cmd"
+
+
+
+
+ MaxSpeed
+ true
+ $(SolutionDir)phnt\include;$(SolutionDir)phlib\include;include;%(AdditionalIncludeDirectories)
+ _PHLIB_;_PHAPP_;_WINDOWS;HAVE_CONFIG_H;WIN32;NDEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions)
+ true
+ MultiThreaded
+ false
+ true
+ Level3
+ ProgramDatabase
+ StdCall
+ true
+ true
+ StreamingSIMDExtensions
+ Guard
+
+
+ aclui.lib;comctl32.lib;dnsapi.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;shlwapi.lib;userenv.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies)
+ Windows
+ true
+ true
+ MachineX86
+ true
+ 6.01
+ $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories)
+ ProcessHacker.def
+ advapi32.dll;aclui.dll;comdlg32.dll;comctl32.dll;dnsapi.dll;gdi32.dll;iphlpapi.dll;oleaut32.dll;ole32.dll;shell32.dll;shlwapi.dll;userenv.dll;user32.dll;uxtheme.dll;version.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs)
+ true
+ /DEPENDENTLOADFLAG:0xA00 %(AdditionalOptions)
+
+
+ _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions)
+ $(SolutionDir)phnt\include;$(SolutionDir)phlib\include;include;%(AdditionalIncludeDirectories)
+
+
+ "$(SolutionDir)build\build_sdk.cmd"
+
+
+
+
+ MaxSpeed
+ true
+ $(SolutionDir)phnt\include;$(SolutionDir)phlib\include;include;%(AdditionalIncludeDirectories)
+ _PHLIB_;_PHAPP_;_WINDOWS;HAVE_CONFIG_H;WIN64;NDEBUG;%(PreprocessorDefinitions);$(ExternalCompilerOptions)
+ true
+ MultiThreaded
+ false
+ true
+ Level3
+ ProgramDatabase
+ StdCall
+ true
+ true
+ Guard
+
+
+ aclui.lib;comctl32.lib;dnsapi.lib;iphlpapi.lib;noarg.obj;noenv.obj;ntdll.lib;phlib.lib;shlwapi.lib;userenv.lib;uxtheme.lib;version.lib;wbemuuid.lib;windowscodecs.lib;winsta.lib;ws2_32.lib;%(AdditionalDependencies)
+ Windows
+ true
+ true
+ MachineX64
+ true
+ 6.01
+ $(SolutionDir)phlib\bin\$(Configuration)$(PlatformArchitecture);%(AdditionalLibraryDirectories)
+ ProcessHacker.def
+ advapi32.dll;aclui.dll;comdlg32.dll;comctl32.dll;dnsapi.dll;gdi32.dll;iphlpapi.dll;oleaut32.dll;ole32.dll;shell32.dll;shlwapi.dll;userenv.dll;user32.dll;uxtheme.dll;version.dll;winsta.dll;ws2_32.dll;%(DelayLoadDLLs)
+ true
+ /DEPENDENTLOADFLAG:0xA00 %(AdditionalOptions)
+
+
+ _UNICODE;UNICODE;%(PreprocessorDefinitions);$(ExternalCompilerOptions)
+ $(SolutionDir)phnt\include;$(SolutionDir)phlib\include;include;%(AdditionalIncludeDirectories)
+
+
+ "$(SolutionDir)build\build_sdk.cmd"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Designer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ProcessHacker/ProcessHacker.vcxproj.filters b/ProcessHacker/ProcessHacker.vcxproj.filters
index 85a5e1b50318..a7ddace7b009 100644
--- a/ProcessHacker/ProcessHacker.vcxproj.filters
+++ b/ProcessHacker/ProcessHacker.vcxproj.filters
@@ -1,638 +1,611 @@
-
-
-
-
- {93995380-89BD-4b04-88EB-625FBE52EBFB}
- h;hpp;hxx;hm;inl;inc;xsd
-
-
- {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
- rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav
-
-
- {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
- cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
-
-
- {3fa0b151-12c1-4832-94fb-e16c52584b65}
-
-
- {eaabb14f-9091-4b18-8764-45c8350f4887}
-
-
- {84a3be0b-42cf-42ae-bcd3-16f165caa0db}
-
-
- {e72b6c69-b510-4578-9ed5-34a16d8dffc1}
-
-
- {c4b014d0-6bd0-4848-a23f-e639563d998e}
-
-
- {67c40321-0b28-4c16-8c48-dc0b64c148d7}
-
-
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Mini-XML
-
-
- Mini-XML
-
-
- Mini-XML
-
-
- Mini-XML
-
-
- Mini-XML
-
-
- Mini-XML
-
-
- Mini-XML
-
-
- Mini-XML
-
-
- Mini-XML
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- phsvc
-
-
- phsvc
-
-
- phsvc
-
-
- phsvc
-
-
- phsvc
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- PCRE
-
-
- PCRE
-
-
- PCRE
-
-
- PCRE
-
-
- PCRE
-
-
- PCRE
-
-
- PCRE
-
-
- PCRE
-
-
- PCRE
-
-
- PCRE
-
-
- PCRE
-
-
- PCRE
-
-
- PCRE
-
-
- PCRE
-
-
- PCRE
-
-
- PCRE
-
-
- PCRE
-
-
- PCRE
-
-
- PCRE
-
-
- PCRE
-
-
- PCRE
-
-
- PCRE
-
-
- PCRE
-
-
- PCRE
-
-
- PCRE
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
- Process Hacker
-
-
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- PCRE\Headers
-
-
- PCRE\Headers
-
-
- PCRE\Headers
-
-
- PCRE\Headers
-
-
- PCRE\Headers
-
-
- PCRE\Headers
-
-
- Mini-XML\Headers
-
-
- Mini-XML\Headers
-
-
- Mini-XML\Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
- Headers
-
-
-
-
- Resources
-
-
- Resources
-
-
- Resources
-
-
- Resources
-
-
- Resources
-
-
- Resources
-
-
- Resources
-
-
- Resources
-
-
- Module
-
-
-
-
- Resources
-
-
- Resources
-
-
-
-
- Resources
-
-
-
-
- Resources
-
-
- Resources
-
-
- Resources
-
-
- Resources
-
-
+
+
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {3fa0b151-12c1-4832-94fb-e16c52584b65}
+
+
+ {84a3be0b-42cf-42ae-bcd3-16f165caa0db}
+
+
+ {e72b6c69-b510-4578-9ed5-34a16d8dffc1}
+
+
+ {67c40321-0b28-4c16-8c48-dc0b64c148d7}
+
+
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ phsvc
+
+
+ phsvc
+
+
+ phsvc
+
+
+ phsvc
+
+
+ phsvc
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ PCRE
+
+
+ PCRE
+
+
+ PCRE
+
+
+ PCRE
+
+
+ PCRE
+
+
+ PCRE
+
+
+ PCRE
+
+
+ PCRE
+
+
+ PCRE
+
+
+ PCRE
+
+
+ PCRE
+
+
+ PCRE
+
+
+ PCRE
+
+
+ PCRE
+
+
+ PCRE
+
+
+ PCRE
+
+
+ PCRE
+
+
+ PCRE
+
+
+ PCRE
+
+
+ PCRE
+
+
+ PCRE
+
+
+ PCRE
+
+
+ PCRE
+
+
+ PCRE
+
+
+ PCRE
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ Process Hacker
+
+
+ PCRE
+
+
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ PCRE\Headers
+
+
+ PCRE\Headers
+
+
+ PCRE\Headers
+
+
+ PCRE\Headers
+
+
+ PCRE\Headers
+
+
+ PCRE\Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+ Headers
+
+
+
+
+ Resources
+
+
+ Resources
+
+
+ Resources
+
+
+ Resources
+
+
+ Resources
+
+
+ Resources
+
+
+ Module
+
+
+
+
+ Resources
+
+
+
+
+ Resources
+
+
+
+
+ Resources
+
+
+ Resources
+
+
+ Resources
+
+
+ Resources
+
+
+ Resources
+
+
+ Resources
+
+
+ Resources
+
+
+ Resources
+
+
\ No newline at end of file
diff --git a/ProcessHacker/about.c b/ProcessHacker/about.c
index fd9872cc7edf..357ca6374037 100644
--- a/ProcessHacker/about.c
+++ b/ProcessHacker/about.c
@@ -1,190 +1,220 @@
-/*
- * Process Hacker -
- * about dialog
- *
- * Copyright (C) 2010-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 .
- */
-
-#include
-
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-static INT_PTR CALLBACK PhpAboutDlgProc(
- _In_ HWND hwndDlg,
- _In_ UINT uMsg,
- _In_ WPARAM wParam,
- _In_ LPARAM lParam
- )
-{
- switch (uMsg)
- {
- case WM_INITDIALOG:
- {
- PPH_STRING appName;
-
- PhCenterWindow(hwndDlg, GetParent(hwndDlg));
-
-#if (PHAPP_VERSION_REVISION != 0)
- appName = PhFormatString(
- L"Process Hacker %u.%u.%u",
- PHAPP_VERSION_MAJOR,
- PHAPP_VERSION_MINOR,
- PHAPP_VERSION_REVISION
- );
-#else
- appName = PhFormatString(
- L"Process Hacker %u.%u",
- PHAPP_VERSION_MAJOR,
- PHAPP_VERSION_MINOR
- );
-#endif
-
- SetDlgItemText(hwndDlg, IDC_ABOUT_NAME, appName->Buffer);
- PhDereferenceObject(appName);
-
- SetDlgItemText(hwndDlg, IDC_CREDITS,
- L" Installer by XhmikosR\n"
- L"Thanks to:\n"
- L" dmex\n"
- L" Donors - thank you for your support!\n"
- L" Sysinternals Forums\n"
- L" ReactOS\n"
- L"Process Hacker uses the following components:\n"
- L" Mini-XML by Michael Sweet\n"
- L" PCRE\n"
- L" MD5 code by Jouni Malinen\n"
- L" SHA1 code by Filip Navara, based on code by Steve Reid\n"
- L" Silk icons\n"
- L" Farm-fresh web icons\n"
- );
-
- SendMessage(hwndDlg, WM_NEXTDLGCTL, (LPARAM)GetDlgItem(hwndDlg, IDOK), TRUE);
- }
- break;
- case WM_COMMAND:
- {
- switch (LOWORD(wParam))
- {
- case IDCANCEL:
- case IDOK:
- EndDialog(hwndDlg, IDOK);
- break;
- case IDC_DIAGNOSTICS:
- {
- PhShowInformationDialog(hwndDlg, PH_AUTO_T(PH_STRING, PhGetDiagnosticsString())->Buffer, 0);
- }
- break;
- }
- }
- break;
- case WM_NOTIFY:
- {
- LPNMHDR header = (LPNMHDR)lParam;
-
- switch (header->code)
- {
- case NM_CLICK:
- {
- switch (header->idFrom)
- {
- case IDC_CREDITS:
- case IDC_LINK_SF:
- PhShellExecute(hwndDlg, ((PNMLINK)header)->item.szUrl, NULL);
- break;
- }
- }
- break;
- }
- }
- break;
- }
-
- return FALSE;
-}
-
-VOID PhShowAboutDialog(
- _In_ HWND ParentWindowHandle
- )
-{
- DialogBox(
- PhInstanceHandle,
- MAKEINTRESOURCE(IDD_ABOUT),
- ParentWindowHandle,
- PhpAboutDlgProc
- );
-}
-
-FORCEINLINE ULONG PhpGetObjectTypeObjectCount(
- _In_ PPH_OBJECT_TYPE ObjectType
- )
-{
- PH_OBJECT_TYPE_INFORMATION info;
-
- PhGetObjectTypeInformation(ObjectType, &info);
-
- return info.NumberOfObjects;
-}
-
-PPH_STRING PhGetDiagnosticsString(
- VOID
- )
-{
- PH_STRING_BUILDER stringBuilder;
-
- PhInitializeStringBuilder(&stringBuilder, 50);
-
- PhAppendFormatStringBuilder(&stringBuilder, L"OBJECT INFORMATION\r\n");
-
-#define OBJECT_TYPE_COUNT(Type) PhAppendFormatStringBuilder(&stringBuilder, \
- L#Type L": %u objects\r\n", PhpGetObjectTypeObjectCount(Type))
-
- // ref
- OBJECT_TYPE_COUNT(PhObjectTypeObject);
-
- // basesup
- OBJECT_TYPE_COUNT(PhStringType);
- OBJECT_TYPE_COUNT(PhBytesType);
- OBJECT_TYPE_COUNT(PhListType);
- OBJECT_TYPE_COUNT(PhPointerListType);
- OBJECT_TYPE_COUNT(PhHashtableType);
- OBJECT_TYPE_COUNT(PhFileStreamType);
-
- // ph
- OBJECT_TYPE_COUNT(PhSymbolProviderType);
- OBJECT_TYPE_COUNT(PhProcessItemType);
- OBJECT_TYPE_COUNT(PhServiceItemType);
- OBJECT_TYPE_COUNT(PhNetworkItemType);
- OBJECT_TYPE_COUNT(PhModuleProviderType);
- OBJECT_TYPE_COUNT(PhModuleItemType);
- OBJECT_TYPE_COUNT(PhThreadProviderType);
- OBJECT_TYPE_COUNT(PhThreadItemType);
- OBJECT_TYPE_COUNT(PhHandleProviderType);
- OBJECT_TYPE_COUNT(PhHandleItemType);
- OBJECT_TYPE_COUNT(PhMemoryItemType);
-
- return PhFinalStringBuilderString(&stringBuilder);
-}
+/*
+ * Process Hacker -
+ * about dialog
+ *
+ * Copyright (C) 2010-2016 wj32
+ * Copyright (C) 2017-2018 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 .
+ */
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+static HWND PhAboutWindowHandle = NULL;
+
+static INT_PTR CALLBACK PhpAboutDlgProc(
+ _In_ HWND hwndDlg,
+ _In_ UINT uMsg,
+ _In_ WPARAM wParam,
+ _In_ LPARAM lParam
+ )
+{
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ PPH_STRING appName;
+
+ SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER)));
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER)));
+
+ PhCenterWindow(hwndDlg, (IsWindowVisible(PhMainWndHandle) && !IsMinimized(PhMainWndHandle)) ? PhMainWndHandle : NULL);
+
+#if (PHAPP_VERSION_REVISION != 0)
+ appName = PhFormatString(
+ L"Process Hacker %lu.%lu.%lu (%hs)",
+ PHAPP_VERSION_MAJOR,
+ PHAPP_VERSION_MINOR,
+ PHAPP_VERSION_REVISION,
+ PHAPP_VERSION_COMMIT
+ );
+#else
+ appName = PhFormatString(
+ L"Process Hacker %lu.%lu",
+ PHAPP_VERSION_MAJOR,
+ PHAPP_VERSION_MINOR
+ );
+#endif
+
+ PhSetDialogItemText(hwndDlg, IDC_ABOUT_NAME, appName->Buffer);
+ PhDereferenceObject(appName);
+
+ PhSetDialogItemText(hwndDlg, IDC_CREDITS,
+ L"Thanks to:\n"
+ L" wj32 - Wen Jia Liu\n"
+ L" dmex - Steven G\n"
+ L" XhmikosR\n"
+ L" Contributors - thank you for your additions!\n"
+ L" Donors - thank you for your support!\n\n"
+ L"Process Hacker uses the following components:\n"
+ L" Mini-XML by Michael Sweet\n"
+ L" PCRE\n"
+ L" json-c\n"
+ L" MD5 code by Jouni Malinen\n"
+ L" SHA1 code by Filip Navara, based on code by Steve Reid\n"
+ L" Silk icons\n"
+ L" Farm-fresh web icons\n"
+ );
+
+ PhSetDialogFocus(hwndDlg, GetDlgItem(hwndDlg, IDOK));
+
+ PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);
+ }
+ break;
+ case WM_DESTROY:
+ {
+ PhUnregisterDialog(PhAboutWindowHandle);
+ PhAboutWindowHandle = NULL;
+ }
+ break;
+ case WM_COMMAND:
+ {
+ switch (GET_WM_COMMAND_ID(wParam, lParam))
+ {
+ case IDCANCEL:
+ case IDOK:
+ DestroyWindow(hwndDlg);
+ break;
+ case IDC_DIAGNOSTICS:
+ {
+ PhShowInformationDialog(hwndDlg, PH_AUTO_T(PH_STRING, PhGetDiagnosticsString())->Buffer, 0);
+ }
+ break;
+ }
+ }
+ break;
+ case WM_NOTIFY:
+ {
+ LPNMHDR header = (LPNMHDR)lParam;
+
+ switch (header->code)
+ {
+ case NM_CLICK:
+ {
+ switch (header->idFrom)
+ {
+ case IDC_CREDITS:
+ case IDC_LINK_SF:
+ PhShellExecute(hwndDlg, ((PNMLINK)header)->item.szUrl, NULL);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+VOID PhShowAboutDialog(
+ VOID
+ )
+{
+ if (!PhAboutWindowHandle)
+ {
+ PhAboutWindowHandle = CreateDialog(
+ PhInstanceHandle,
+ MAKEINTRESOURCE(IDD_ABOUT),
+ NULL,
+ PhpAboutDlgProc
+ );
+ PhRegisterDialog(PhAboutWindowHandle);
+ ShowWindow(PhAboutWindowHandle, SW_SHOW);
+ }
+
+ if (IsMinimized(PhAboutWindowHandle))
+ ShowWindow(PhAboutWindowHandle, SW_RESTORE);
+ else
+ SetForegroundWindow(PhAboutWindowHandle);
+}
+
+FORCEINLINE ULONG PhpGetObjectTypeObjectCount(
+ _In_ PPH_OBJECT_TYPE ObjectType
+ )
+{
+ PH_OBJECT_TYPE_INFORMATION info;
+
+ memset(&info, 0, sizeof(PH_OBJECT_TYPE_INFORMATION));
+ if (ObjectType) PhGetObjectTypeInformation(ObjectType, &info);
+
+ return info.NumberOfObjects;
+}
+
+PPH_STRING PhGetDiagnosticsString(
+ VOID
+ )
+{
+ PH_STRING_BUILDER stringBuilder;
+
+ PhInitializeStringBuilder(&stringBuilder, 50);
+
+ PhAppendFormatStringBuilder(&stringBuilder, L"OBJECT INFORMATION\r\n");
+
+#define OBJECT_TYPE_COUNT(Type) PhAppendFormatStringBuilder(&stringBuilder, \
+ L#Type L": %lu objects\r\n", PhpGetObjectTypeObjectCount(Type))
+
+ // ref
+ OBJECT_TYPE_COUNT(PhObjectTypeObject);
+
+ // basesup
+ OBJECT_TYPE_COUNT(PhStringType);
+ OBJECT_TYPE_COUNT(PhBytesType);
+ OBJECT_TYPE_COUNT(PhListType);
+ OBJECT_TYPE_COUNT(PhPointerListType);
+ OBJECT_TYPE_COUNT(PhHashtableType);
+ OBJECT_TYPE_COUNT(PhFileStreamType);
+
+ // ph
+ OBJECT_TYPE_COUNT(PhSymbolProviderType);
+ OBJECT_TYPE_COUNT(PhProcessItemType);
+ OBJECT_TYPE_COUNT(PhServiceItemType);
+ OBJECT_TYPE_COUNT(PhNetworkItemType);
+ OBJECT_TYPE_COUNT(PhModuleProviderType);
+ OBJECT_TYPE_COUNT(PhModuleItemType);
+ OBJECT_TYPE_COUNT(PhThreadProviderType);
+ OBJECT_TYPE_COUNT(PhThreadItemType);
+ OBJECT_TYPE_COUNT(PhHandleProviderType);
+ OBJECT_TYPE_COUNT(PhHandleItemType);
+ OBJECT_TYPE_COUNT(PhMemoryItemType);
+
+ return PhFinalStringBuilderString(&stringBuilder);
+}
diff --git a/ProcessHacker/actions.c b/ProcessHacker/actions.c
index 36eaf7a16d21..c1865544e3a1 100644
--- a/ProcessHacker/actions.c
+++ b/ProcessHacker/actions.c
@@ -1,3130 +1,3243 @@
-/*
- * Process Hacker -
- * UI actions
- *
- * Copyright (C) 2010-2016 wj32
- * Copyright (C) 2017 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 .
- */
-
-/*
- * These are a set of consistent functions which will perform actions on objects such as processes,
- * threads and services, while displaying any necessary prompts and error messages. Automatic
- * elevation can also easily be added if necessary.
- */
-
-#include
-#include
-
-#include
-#include
-
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-typedef DWORD (WINAPI *_SetTcpEntry)(
- _In_ PMIB_TCPROW pTcpRow
- );
-
-static PWSTR DangerousProcesses[] =
-{
- L"csrss.exe", L"dwm.exe", L"logonui.exe", L"lsass.exe", L"lsm.exe",
- L"services.exe", L"smss.exe", L"wininit.exe", L"winlogon.exe"
-};
-
-static PPH_STRING DebuggerCommand = NULL;
-static PH_INITONCE DebuggerCommandInitOnce = PH_INITONCE_INIT;
-static ULONG PhSvcReferenceCount = 0;
-static PH_PHSVC_MODE PhSvcCurrentMode;
-static PH_QUEUED_LOCK PhSvcStartLock = PH_QUEUED_LOCK_INIT;
-
-HRESULT CALLBACK PhpElevateActionCallbackProc(
- _In_ HWND hwnd,
- _In_ UINT uNotification,
- _In_ WPARAM wParam,
- _In_ LPARAM lParam,
- _In_ LONG_PTR dwRefData
- )
-{
- switch (uNotification)
- {
- case TDN_CREATED:
- SendMessage(hwnd, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, IDYES, TRUE);
- break;
- }
-
- return S_OK;
-}
-
-BOOLEAN PhpShowElevatePrompt(
- _In_ HWND hWnd,
- _In_ PWSTR Message,
- _In_ NTSTATUS Status,
- _Out_ PINT Button
- )
-{
- TASKDIALOGCONFIG config = { sizeof(config) };
- TASKDIALOG_BUTTON buttons[1];
- INT button;
-
- // Currently the error dialog box is similar to the one displayed
- // when you try to label a drive in Windows Explorer. It's much better
- // than the clunky dialog in PH 1.x.
-
- config.hwndParent = hWnd;
- config.hInstance = PhInstanceHandle;
- config.dwFlags = IsWindowVisible(hWnd) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0;
- config.pszWindowTitle = L"Process Hacker";
- config.pszMainIcon = TD_ERROR_ICON;
- config.pszMainInstruction = PhaConcatStrings2(Message, L".")->Buffer;
- config.pszContent = L"You will need to provide administrator permission. "
- L"Click Continue to complete this operation.";
- config.dwCommonButtons = TDCBF_CANCEL_BUTTON;
-
- buttons[0].nButtonID = IDYES;
- buttons[0].pszButtonText = L"Continue";
-
- config.cButtons = 1;
- config.pButtons = buttons;
- config.nDefaultButton = IDYES;
-
- config.pfCallback = PhpElevateActionCallbackProc;
-
- if (TaskDialogIndirect(
- &config,
- &button,
- NULL,
- NULL
- ) == S_OK)
- {
- *Button = button;
- return TRUE;
- }
- else
- {
- return FALSE;
- }
-}
-
-/**
- * Shows an error, prompts for elevation, and executes a command.
- *
- * \param hWnd The window to display user interface components on.
- * \param Message A message describing the operation that failed.
- * \param Status A NTSTATUS value.
- * \param Command The arguments to pass to the new instance of
- * the application, if required.
- * \param Success A variable which receives TRUE if the elevated
- * action succeeded or FALSE if the action failed.
- *
- * \return TRUE if the user was prompted for elevation, otherwise
- * FALSE, in which case you need to show your own error message.
- */
-BOOLEAN PhpShowErrorAndElevateAction(
- _In_ HWND hWnd,
- _In_ PWSTR Message,
- _In_ NTSTATUS Status,
- _In_ PWSTR Command,
- _Out_ PBOOLEAN Success
- )
-{
- PH_ACTION_ELEVATION_LEVEL elevationLevel;
- INT button = IDNO;
-
- if (!(
- Status == STATUS_ACCESS_DENIED ||
- Status == STATUS_PRIVILEGE_NOT_HELD ||
- (NT_NTWIN32(Status) && WIN32_FROM_NTSTATUS(Status) == ERROR_ACCESS_DENIED)
- ))
- return FALSE;
-
- if (!WINDOWS_HAS_UAC || PhGetOwnTokenAttributes().Elevated)
- return FALSE;
-
- elevationLevel = PhGetIntegerSetting(L"ElevationLevel");
-
- if (elevationLevel == NeverElevateAction)
- return FALSE;
-
- if (elevationLevel == PromptElevateAction)
- {
- if (!PhpShowElevatePrompt(hWnd, Message, Status, &button))
- return FALSE;
- }
-
- if (elevationLevel == AlwaysElevateAction || button == IDYES)
- {
- NTSTATUS status;
- HANDLE processHandle;
- LARGE_INTEGER timeout;
- PROCESS_BASIC_INFORMATION basicInfo;
-
- if (PhShellProcessHacker(
- hWnd,
- Command,
- SW_SHOW,
- PH_SHELL_EXECUTE_ADMIN,
- PH_SHELL_APP_PROPAGATE_PARAMETERS,
- 0,
- &processHandle
- ))
- {
- timeout.QuadPart = -10 * PH_TIMEOUT_SEC;
- status = NtWaitForSingleObject(processHandle, FALSE, &timeout);
-
- if (
- status == STATUS_WAIT_0 &&
- NT_SUCCESS(status = PhGetProcessBasicInformation(processHandle, &basicInfo))
- )
- {
- status = basicInfo.ExitStatus;
- }
-
- NtClose(processHandle);
-
- if (NT_SUCCESS(status))
- {
- *Success = TRUE;
- }
- else
- {
- *Success = FALSE;
- PhShowStatus(hWnd, Message, status, 0);
- }
- }
- }
-
- return TRUE;
-}
-
-/**
- * Shows an error, prompts for elevation, and connects to phsvc.
- *
- * \param hWnd The window to display user interface components on.
- * \param Message A message describing the operation that failed.
- * \param Status A NTSTATUS value.
- * \param Connected A variable which receives TRUE if the user
- * elevated the action and phsvc was started, or FALSE if the user
- * cancelled elevation. If the value is TRUE, you need to
- * perform any necessary phsvc calls and use PhUiDisconnectFromPhSvc()
- * to disconnect from phsvc.
- *
- * \return TRUE if the user was prompted for elevation, otherwise
- * FALSE, in which case you need to show your own error message.
- */
-BOOLEAN PhpShowErrorAndConnectToPhSvc(
- _In_ HWND hWnd,
- _In_ PWSTR Message,
- _In_ NTSTATUS Status,
- _Out_ PBOOLEAN Connected
- )
-{
- PH_ACTION_ELEVATION_LEVEL elevationLevel;
- INT button = IDNO;
-
- *Connected = FALSE;
-
- if (!(
- Status == STATUS_ACCESS_DENIED ||
- Status == STATUS_PRIVILEGE_NOT_HELD ||
- (NT_NTWIN32(Status) && WIN32_FROM_NTSTATUS(Status) == ERROR_ACCESS_DENIED)
- ))
- return FALSE;
-
- if (!WINDOWS_HAS_UAC || PhGetOwnTokenAttributes().Elevated)
- return FALSE;
-
- elevationLevel = PhGetIntegerSetting(L"ElevationLevel");
-
- if (elevationLevel == NeverElevateAction)
- return FALSE;
-
- // Try to connect now so we can avoid prompting the user.
- if (PhUiConnectToPhSvc(hWnd, TRUE))
- {
- *Connected = TRUE;
- return TRUE;
- }
-
- if (elevationLevel == PromptElevateAction)
- {
- if (!PhpShowElevatePrompt(hWnd, Message, Status, &button))
- return FALSE;
- }
-
- if (elevationLevel == AlwaysElevateAction || button == IDYES)
- {
- *Connected = PhUiConnectToPhSvc(hWnd, FALSE);
- }
-
- return TRUE;
-}
-
-/**
- * Connects to phsvc.
- *
- * \param hWnd The window to display user interface components on.
- * \param ConnectOnly TRUE to only try to connect to phsvc, otherwise
- * FALSE to try to elevate and start phsvc if the initial connection
- * attempt failed.
- */
-BOOLEAN PhUiConnectToPhSvc(
- _In_opt_ HWND hWnd,
- _In_ BOOLEAN ConnectOnly
- )
-{
- return PhUiConnectToPhSvcEx(hWnd, ElevatedPhSvcMode, ConnectOnly);
-}
-
-VOID PhpGetPhSvcPortName(
- _In_ PH_PHSVC_MODE Mode,
- _Out_ PUNICODE_STRING PortName
- )
-{
- switch (Mode)
- {
- case ElevatedPhSvcMode:
- if (!PhIsExecutingInWow64())
- RtlInitUnicodeString(PortName, PHSVC_PORT_NAME);
- else
- RtlInitUnicodeString(PortName, PHSVC_WOW64_PORT_NAME);
- break;
- case Wow64PhSvcMode:
- RtlInitUnicodeString(PortName, PHSVC_WOW64_PORT_NAME);
- break;
- default:
- PhRaiseStatus(STATUS_INVALID_PARAMETER);
- break;
- }
-}
-
-BOOLEAN PhpStartPhSvcProcess(
- _In_opt_ HWND hWnd,
- _In_ PH_PHSVC_MODE Mode
- )
-{
- switch (Mode)
- {
- case ElevatedPhSvcMode:
- if (PhShellProcessHacker(
- hWnd,
- L"-phsvc",
- SW_HIDE,
- PH_SHELL_EXECUTE_ADMIN,
- PH_SHELL_APP_PROPAGATE_PARAMETERS,
- 0,
- NULL
- ))
- {
- return TRUE;
- }
-
- break;
- case Wow64PhSvcMode:
- {
- static PWSTR relativeFileNames[] =
- {
- L"\\x86\\ProcessHacker.exe",
- L"\\..\\x86\\ProcessHacker.exe",
-#ifdef DEBUG
- L"\\..\\Debug32\\ProcessHacker.exe",
-#endif
- L"\\..\\Release32\\ProcessHacker.exe"
- };
-
- ULONG i;
-
- for (i = 0; i < sizeof(relativeFileNames) / sizeof(PWSTR); i++)
- {
- PPH_STRING fileName;
-
- fileName = PhConcatStrings2(PhApplicationDirectory->Buffer, relativeFileNames[i]);
- PhMoveReference(&fileName, PhGetFullPath(fileName->Buffer, NULL));
-
- if (fileName && RtlDoesFileExists_U(fileName->Buffer))
- {
- if (PhShellProcessHackerEx(
- hWnd,
- fileName->Buffer,
- L"-phsvc",
- SW_HIDE,
- 0,
- PH_SHELL_APP_PROPAGATE_PARAMETERS,
- 0,
- NULL
- ))
- {
- PhDereferenceObject(fileName);
- return TRUE;
- }
- }
-
- PhClearReference(&fileName);
- }
- }
- break;
- }
-
- return FALSE;
-}
-
-/**
- * Connects to phsvc.
- *
- * \param hWnd The window to display user interface components on.
- * \param Mode The type of phsvc instance to connect to.
- * \param ConnectOnly TRUE to only try to connect to phsvc, otherwise
- * FALSE to try to elevate and start phsvc if the initial connection
- * attempt failed.
- */
-BOOLEAN PhUiConnectToPhSvcEx(
- _In_opt_ HWND hWnd,
- _In_ PH_PHSVC_MODE Mode,
- _In_ BOOLEAN ConnectOnly
- )
-{
- NTSTATUS status;
- BOOLEAN started;
- UNICODE_STRING portName;
-
- if (_InterlockedIncrementNoZero(&PhSvcReferenceCount))
- {
- if (PhSvcCurrentMode == Mode)
- {
- started = TRUE;
- }
- else
- {
- _InterlockedDecrement(&PhSvcReferenceCount);
- started = FALSE;
- }
- }
- else
- {
- PhAcquireQueuedLockExclusive(&PhSvcStartLock);
-
- if (PhSvcReferenceCount == 0)
- {
- started = FALSE;
- PhpGetPhSvcPortName(Mode, &portName);
-
- // Try to connect first, then start the server if we failed.
- status = PhSvcConnectToServer(&portName, 0);
-
- if (NT_SUCCESS(status))
- {
- started = TRUE;
- PhSvcCurrentMode = Mode;
- _InterlockedIncrement(&PhSvcReferenceCount);
- }
- else if (!ConnectOnly)
- {
- // Prompt for elevation, and then try to connect to the server.
-
- if (PhpStartPhSvcProcess(hWnd, Mode))
- started = TRUE;
-
- if (started)
- {
- ULONG attempts = 10;
- LARGE_INTEGER interval;
-
- // Try to connect several times because the server may take
- // a while to initialize.
- do
- {
- status = PhSvcConnectToServer(&portName, 0);
-
- if (NT_SUCCESS(status))
- break;
-
- interval.QuadPart = -50 * PH_TIMEOUT_MS;
- NtDelayExecution(FALSE, &interval);
- } while (--attempts != 0);
-
- // Increment the reference count even if we failed.
- // We don't want to prompt the user again.
-
- PhSvcCurrentMode = Mode;
- _InterlockedIncrement(&PhSvcReferenceCount);
- }
- }
- }
- else
- {
- if (PhSvcCurrentMode == Mode)
- {
- started = TRUE;
- _InterlockedIncrement(&PhSvcReferenceCount);
- }
- else
- {
- started = FALSE;
- }
- }
-
- PhReleaseQueuedLockExclusive(&PhSvcStartLock);
- }
-
- return started;
-}
-
-/**
- * Disconnects from phsvc.
- */
-VOID PhUiDisconnectFromPhSvc(
- VOID
- )
-{
- PhAcquireQueuedLockExclusive(&PhSvcStartLock);
-
- if (_InterlockedDecrement(&PhSvcReferenceCount) == 0)
- {
- PhSvcDisconnectFromServer();
- }
-
- PhReleaseQueuedLockExclusive(&PhSvcStartLock);
-}
-
-BOOLEAN PhUiLockComputer(
- _In_ HWND hWnd
- )
-{
- if (LockWorkStation())
- return TRUE;
- else
- PhShowStatus(hWnd, L"Unable to lock the computer", 0, GetLastError());
-
- return FALSE;
-}
-
-BOOLEAN PhUiLogoffComputer(
- _In_ HWND hWnd
- )
-{
- if (ExitWindowsEx(EWX_LOGOFF, 0))
- return TRUE;
- else
- PhShowStatus(hWnd, L"Unable to log off the computer", 0, GetLastError());
-
- return FALSE;
-}
-
-BOOLEAN PhUiSleepComputer(
- _In_ HWND hWnd
- )
-{
- NTSTATUS status;
-
- if (NT_SUCCESS(status = NtInitiatePowerAction(
- PowerActionSleep,
- PowerSystemSleeping1,
- 0,
- FALSE
- )))
- return TRUE;
- else
- PhShowStatus(hWnd, L"Unable to sleep the computer", status, 0);
-
- return FALSE;
-}
-
-BOOLEAN PhUiHibernateComputer(
- _In_ HWND hWnd
- )
-{
- NTSTATUS status;
-
- if (NT_SUCCESS(status = NtInitiatePowerAction(
- PowerActionHibernate,
- PowerSystemSleeping1,
- 0,
- FALSE
- )))
- return TRUE;
- else
- PhShowStatus(hWnd, L"Unable to hibernate the computer", status, 0);
-
- return FALSE;
-}
-
-BOOLEAN PhUiRestartComputer(
- _In_ HWND hWnd,
- _In_ ULONG Flags
- )
-{
- if (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage(
- hWnd,
- L"restart",
- L"the computer",
- NULL,
- FALSE
- ))
- {
- if (ExitWindowsEx(EWX_REBOOT | Flags, 0))
- return TRUE;
- else
- PhShowStatus(hWnd, L"Unable to restart the computer", 0, GetLastError());
- }
-
- return FALSE;
-}
-
-BOOLEAN PhUiShutdownComputer(
- _In_ HWND hWnd,
- _In_ ULONG Flags
- )
-{
- if (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage(
- hWnd,
- L"shut down",
- L"the computer",
- NULL,
- FALSE
- ))
- {
- if (ExitWindowsEx(EWX_POWEROFF | Flags, 0))
- {
- return TRUE;
- }
- else if (ExitWindowsEx(EWX_SHUTDOWN | Flags, 0))
- {
- return TRUE;
- }
- else
- {
- PhShowStatus(hWnd, L"Unable to shut down the computer", 0, GetLastError());
- }
- }
-
- return FALSE;
-}
-
-BOOLEAN PhUiConnectSession(
- _In_ HWND hWnd,
- _In_ ULONG SessionId
- )
-{
- BOOLEAN success = FALSE;
- PPH_STRING selectedChoice = NULL;
- PPH_STRING oldSelectedChoice = NULL;
-
- // Try once with no password.
- if (WinStationConnectW(NULL, SessionId, -1, L"", TRUE))
- return TRUE;
-
- while (PhaChoiceDialog(
- hWnd,
- L"Connect to session",
- L"Password:",
- NULL,
- 0,
- NULL,
- PH_CHOICE_DIALOG_PASSWORD,
- &selectedChoice,
- NULL,
- NULL
- ))
- {
- if (oldSelectedChoice)
- {
- RtlSecureZeroMemory(oldSelectedChoice->Buffer, oldSelectedChoice->Length);
- PhDereferenceObject(oldSelectedChoice);
- }
-
- oldSelectedChoice = selectedChoice;
-
- if (WinStationConnectW(NULL, SessionId, -1, selectedChoice->Buffer, TRUE))
- {
- success = TRUE;
- break;
- }
- else
- {
- if (!PhShowContinueStatus(hWnd, L"Unable to connect to the session", 0, GetLastError()))
- break;
- }
- }
-
- if (oldSelectedChoice)
- {
- RtlSecureZeroMemory(oldSelectedChoice->Buffer, oldSelectedChoice->Length);
- PhDereferenceObject(oldSelectedChoice);
- }
-
- return success;
-}
-
-BOOLEAN PhUiDisconnectSession(
- _In_ HWND hWnd,
- _In_ ULONG SessionId
- )
-{
- if (WinStationDisconnect(NULL, SessionId, FALSE))
- return TRUE;
- else
- PhShowStatus(hWnd, L"Unable to disconnect the session", 0, GetLastError());
-
- return FALSE;
-}
-
-BOOLEAN PhUiLogoffSession(
- _In_ HWND hWnd,
- _In_ ULONG SessionId
- )
-{
- if (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage(
- hWnd,
- L"logoff",
- L"the user",
- NULL,
- FALSE
- ))
- {
- if (WinStationReset(NULL, SessionId, FALSE))
- return TRUE;
- else
- PhShowStatus(hWnd, L"Unable to logoff the session", 0, GetLastError());
- }
-
- return FALSE;
-}
-
-/**
- * Determines if a process is a system process.
- *
- * \param ProcessId The PID of the process to check.
- */
-static BOOLEAN PhpIsDangerousProcess(
- _In_ HANDLE ProcessId
- )
-{
- NTSTATUS status;
- HANDLE processHandle;
- PPH_STRING fileName;
- PPH_STRING systemDirectory;
- ULONG i;
-
- if (ProcessId == SYSTEM_PROCESS_ID)
- return TRUE;
-
- if (WINDOWS_HAS_IMAGE_FILE_NAME_BY_PROCESS_ID)
- {
- status = PhGetProcessImageFileNameByProcessId(ProcessId, &fileName);
- }
- else
- {
- if (!NT_SUCCESS(status = PhOpenProcess(
- &processHandle,
- ProcessQueryAccess,
- ProcessId
- )))
- return FALSE;
-
- status = PhGetProcessImageFileName(processHandle, &fileName);
- NtClose(processHandle);
- }
-
- if (!NT_SUCCESS(status))
- return FALSE;
-
- PhMoveReference(&fileName, PhGetFileName(fileName));
- PH_AUTO(fileName);
-
- systemDirectory = PH_AUTO(PhGetSystemDirectory());
-
- for (i = 0; i < sizeof(DangerousProcesses) / sizeof(PWSTR); i++)
- {
- PPH_STRING fullName;
-
- fullName = PhaConcatStrings(3, systemDirectory->Buffer, L"\\", DangerousProcesses[i]);
-
- if (PhEqualString(fileName, fullName, TRUE))
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
- * Checks if the user wants to proceed with an operation.
- *
- * \param hWnd A handle to the parent window.
- * \param Verb A verb describing the action.
- * \param Message A message containing additional information
- * about the action.
- * \param WarnOnlyIfDangerous TRUE to skip the confirmation
- * dialog if none of the processes are system processes,
- * FALSE to always show the confirmation dialog.
- * \param Processes An array of pointers to process items.
- * \param NumberOfProcesses The number of process items.
- *
- * \return TRUE if the user wants to proceed with the operation,
- * otherwise FALSE.
- */
-static BOOLEAN PhpShowContinueMessageProcesses(
- _In_ HWND hWnd,
- _In_ PWSTR Verb,
- _In_opt_ PWSTR Message,
- _In_ BOOLEAN WarnOnlyIfDangerous,
- _In_ PPH_PROCESS_ITEM *Processes,
- _In_ ULONG NumberOfProcesses
- )
-{
- PWSTR object;
- ULONG i;
- BOOLEAN critical = FALSE;
- BOOLEAN dangerous = FALSE;
- BOOLEAN cont = FALSE;
-
- if (NumberOfProcesses == 0)
- return FALSE;
-
- for (i = 0; i < NumberOfProcesses; i++)
- {
- HANDLE processHandle;
- ULONG breakOnTermination;
-
- breakOnTermination = 0;
-
- if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_INFORMATION, Processes[i]->ProcessId)))
- {
- NtQueryInformationProcess(processHandle, ProcessBreakOnTermination, &breakOnTermination, sizeof(ULONG), NULL);
- NtClose(processHandle);
- }
-
- if (breakOnTermination != 0)
- {
- critical = TRUE;
- dangerous = TRUE;
- break;
- }
-
- if (PhpIsDangerousProcess(Processes[i]->ProcessId))
- {
- dangerous = TRUE;
- break;
- }
- }
-
- if (WarnOnlyIfDangerous && !dangerous)
- return TRUE;
-
- if (PhGetIntegerSetting(L"EnableWarnings"))
- {
- if (NumberOfProcesses == 1)
- {
- object = Processes[0]->ProcessName->Buffer;
- }
- else if (NumberOfProcesses == 2)
- {
- object = PhaConcatStrings(
- 3,
- Processes[0]->ProcessName->Buffer,
- L" and ",
- Processes[1]->ProcessName->Buffer
- )->Buffer;
- }
- else
- {
- object = L"the selected processes";
- }
-
- if (!dangerous)
- {
- cont = PhShowConfirmMessage(
- hWnd,
- Verb,
- object,
- Message,
- FALSE
- );
- }
- else if (!critical)
- {
- cont = PhShowConfirmMessage(
- hWnd,
- Verb,
- object,
- PhaConcatStrings(
- 3,
- L"You are about to ",
- Verb,
- L" one or more system processes."
- )->Buffer,
- TRUE
- );
- }
- else
- {
- PPH_STRING message;
-
- if (PhEqualStringZ(Verb, L"terminate", FALSE))
- {
- message = PhaConcatStrings(
- 3,
- L"You are about to ",
- Verb,
- L" one or more critical processes. This will shut down the operating system immediately."
- );
- }
- else
- {
- message = PhaConcatStrings(
- 3,
- L"You are about to ",
- Verb,
- L" one or more critical processes."
- );
- }
-
- cont = PhShowConfirmMessage(
- hWnd,
- Verb,
- object,
- message->Buffer,
- TRUE
- );
- }
- }
- else
- {
- cont = TRUE;
- }
-
- return cont;
-}
-
-/**
- * Shows an error message to the user and checks
- * if the user wants to continue.
- *
- * \param hWnd A handle to the parent window.
- * \param Verb A verb describing the action which
- * resulted in an error.
- * \param Process The process item which the action
- * was performed on.
- * \param Status A NT status value representing the
- * error.
- * \param Win32Result A Win32 error code representing
- * the error.
- *
- * \return TRUE if the user wants to continue, otherwise
- * FALSE. The result is typically only useful when
- * executing an action on multiple processes.
- */
-static BOOLEAN PhpShowErrorProcess(
- _In_ HWND hWnd,
- _In_ PWSTR Verb,
- _In_ PPH_PROCESS_ITEM Process,
- _In_ NTSTATUS Status,
- _In_opt_ ULONG Win32Result
- )
-{
- if (!PH_IS_FAKE_PROCESS_ID(Process->ProcessId))
- {
- return PhShowContinueStatus(
- hWnd,
- PhaFormatString(
- L"Unable to %s %s (PID %u)",
- Verb,
- Process->ProcessName->Buffer,
- HandleToUlong(Process->ProcessId)
- )->Buffer,
- Status,
- Win32Result
- );
- }
- else
- {
- return PhShowContinueStatus(
- hWnd,
- PhaFormatString(
- L"Unable to %s %s",
- Verb,
- Process->ProcessName->Buffer
- )->Buffer,
- Status,
- Win32Result
- );
- }
-}
-
-BOOLEAN PhUiTerminateProcesses(
- _In_ HWND hWnd,
- _In_ PPH_PROCESS_ITEM *Processes,
- _In_ ULONG NumberOfProcesses
- )
-{
- BOOLEAN success = TRUE;
- BOOLEAN cancelled = FALSE;
- ULONG i;
-
- if (!PhpShowContinueMessageProcesses(
- hWnd,
- L"terminate",
- L"Terminating a process will cause unsaved data to be lost.",
- FALSE,
- Processes,
- NumberOfProcesses
- ))
- return FALSE;
-
- for (i = 0; i < NumberOfProcesses; i++)
- {
- NTSTATUS status;
- HANDLE processHandle;
-
- if (NT_SUCCESS(status = PhOpenProcess(
- &processHandle,
- PROCESS_TERMINATE,
- Processes[i]->ProcessId
- )))
- {
- // An exit status of 1 is used here for compatibility reasons:
- // 1. Both Task Manager and Process Explorer use 1.
- // 2. winlogon tries to restart explorer.exe if the exit status is not 1.
-
- status = PhTerminateProcess(processHandle, 1);
- NtClose(processHandle);
- }
-
- if (!NT_SUCCESS(status))
- {
- BOOLEAN connected;
-
- success = FALSE;
-
- if (!cancelled && PhpShowErrorAndConnectToPhSvc(
- hWnd,
- PhaConcatStrings2(L"Unable to terminate ", Processes[i]->ProcessName->Buffer)->Buffer,
- status,
- &connected
- ))
- {
- if (connected)
- {
- if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessTerminate, 0)))
- success = TRUE;
- else
- PhpShowErrorProcess(hWnd, L"terminate", Processes[i], status, 0);
-
- PhUiDisconnectFromPhSvc();
- }
- else
- {
- cancelled = TRUE;
- }
- }
- else
- {
- if (!PhpShowErrorProcess(hWnd, L"terminate", Processes[i], status, 0))
- break;
- }
- }
- }
-
- return success;
-}
-
-BOOLEAN PhpUiTerminateTreeProcess(
- _In_ HWND hWnd,
- _In_ PPH_PROCESS_ITEM Process,
- _In_ PVOID Processes,
- _Inout_ PBOOLEAN Success
- )
-{
- NTSTATUS status;
- PSYSTEM_PROCESS_INFORMATION process;
- HANDLE processHandle;
- PPH_PROCESS_ITEM processItem;
-
- // Note:
- // FALSE should be written to Success if any part of the operation failed.
- // The return value of this function indicates whether to continue with
- // the operation (FALSE if user cancelled).
-
- // Terminate the process.
-
- if (NT_SUCCESS(status = PhOpenProcess(
- &processHandle,
- PROCESS_TERMINATE,
- Process->ProcessId
- )))
- {
- status = PhTerminateProcess(processHandle, 1);
- NtClose(processHandle);
- }
-
- if (!NT_SUCCESS(status))
- {
- *Success = FALSE;
-
- if (!PhpShowErrorProcess(hWnd, L"terminate", Process, status, 0))
- return FALSE;
- }
-
- // Terminate the process' children.
-
- process = PH_FIRST_PROCESS(Processes);
-
- do
- {
- if (process->UniqueProcessId != Process->ProcessId &&
- process->InheritedFromUniqueProcessId == Process->ProcessId)
- {
- if (processItem = PhReferenceProcessItem(process->UniqueProcessId))
- {
- // Check the creation time to make sure it is a descendant.
- if (processItem->CreateTime.QuadPart >= Process->CreateTime.QuadPart)
- {
- if (!PhpUiTerminateTreeProcess(hWnd, processItem, Processes, Success))
- {
- PhDereferenceObject(processItem);
- return FALSE;
- }
- }
-
- PhDereferenceObject(processItem);
- }
- }
- } while (process = PH_NEXT_PROCESS(process));
-
- return TRUE;
-}
-
-BOOLEAN PhUiTerminateTreeProcess(
- _In_ HWND hWnd,
- _In_ PPH_PROCESS_ITEM Process
- )
-{
- NTSTATUS status;
- BOOLEAN success = TRUE;
- BOOLEAN cont = FALSE;
- PVOID processes;
-
- if (PhGetIntegerSetting(L"EnableWarnings"))
- {
- cont = PhShowConfirmMessage(
- hWnd,
- L"terminate",
- PhaConcatStrings2(Process->ProcessName->Buffer, L" and its descendants")->Buffer,
- L"Terminating a process tree will cause the process and its descendants to be terminated.",
- FALSE
- );
- }
- else
- {
- cont = TRUE;
- }
-
- if (!cont)
- return FALSE;
-
- if (!NT_SUCCESS(status = PhEnumProcesses(&processes)))
- {
- PhShowStatus(hWnd, L"Unable to enumerate processes", status, 0);
- return FALSE;
- }
-
- PhpUiTerminateTreeProcess(hWnd, Process, processes, &success);
- PhFree(processes);
-
- return success;
-}
-
-BOOLEAN PhUiSuspendProcesses(
- _In_ HWND hWnd,
- _In_ PPH_PROCESS_ITEM *Processes,
- _In_ ULONG NumberOfProcesses
- )
-{
- BOOLEAN success = TRUE;
- BOOLEAN cancelled = FALSE;
- ULONG i;
-
- if (!PhpShowContinueMessageProcesses(
- hWnd,
- L"suspend",
- NULL,
- TRUE,
- Processes,
- NumberOfProcesses
- ))
- return FALSE;
-
- for (i = 0; i < NumberOfProcesses; i++)
- {
- NTSTATUS status;
- HANDLE processHandle;
-
- if (NT_SUCCESS(status = PhOpenProcess(
- &processHandle,
- PROCESS_SUSPEND_RESUME,
- Processes[i]->ProcessId
- )))
- {
- status = NtSuspendProcess(processHandle);
- NtClose(processHandle);
- }
-
- if (!NT_SUCCESS(status))
- {
- BOOLEAN connected;
-
- success = FALSE;
-
- if (!cancelled && PhpShowErrorAndConnectToPhSvc(
- hWnd,
- PhaConcatStrings2(L"Unable to suspend ", Processes[i]->ProcessName->Buffer)->Buffer,
- status,
- &connected
- ))
- {
- if (connected)
- {
- if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessSuspend, 0)))
- success = TRUE;
- else
- PhpShowErrorProcess(hWnd, L"suspend", Processes[i], status, 0);
-
- PhUiDisconnectFromPhSvc();
- }
- else
- {
- cancelled = TRUE;
- }
- }
- else
- {
- if (!PhpShowErrorProcess(hWnd, L"suspend", Processes[i], status, 0))
- break;
- }
- }
- }
-
- return success;
-}
-
-BOOLEAN PhUiResumeProcesses(
- _In_ HWND hWnd,
- _In_ PPH_PROCESS_ITEM *Processes,
- _In_ ULONG NumberOfProcesses
- )
-{
- BOOLEAN success = TRUE;
- BOOLEAN cancelled = FALSE;
- ULONG i;
-
- if (!PhpShowContinueMessageProcesses(
- hWnd,
- L"resume",
- NULL,
- TRUE,
- Processes,
- NumberOfProcesses
- ))
- return FALSE;
-
- for (i = 0; i < NumberOfProcesses; i++)
- {
- NTSTATUS status;
- HANDLE processHandle;
-
- if (NT_SUCCESS(status = PhOpenProcess(
- &processHandle,
- PROCESS_SUSPEND_RESUME,
- Processes[i]->ProcessId
- )))
- {
- status = NtResumeProcess(processHandle);
- NtClose(processHandle);
- }
-
- if (!NT_SUCCESS(status))
- {
- BOOLEAN connected;
-
- success = FALSE;
-
- if (!cancelled && PhpShowErrorAndConnectToPhSvc(
- hWnd,
- PhaConcatStrings2(L"Unable to resume ", Processes[i]->ProcessName->Buffer)->Buffer,
- status,
- &connected
- ))
- {
- if (connected)
- {
- if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessResume, 0)))
- success = TRUE;
- else
- PhpShowErrorProcess(hWnd, L"resume", Processes[i], status, 0);
-
- PhUiDisconnectFromPhSvc();
- }
- else
- {
- cancelled = TRUE;
- }
- }
- else
- {
- if (!PhpShowErrorProcess(hWnd, L"resume", Processes[i], status, 0))
- break;
- }
- }
- }
-
- return success;
-}
-
-BOOLEAN PhUiRestartProcess(
- _In_ HWND hWnd,
- _In_ PPH_PROCESS_ITEM Process
- )
-{
- NTSTATUS status;
- BOOLEAN cont = FALSE;
- HANDLE processHandle = NULL;
- PPH_STRING commandLine;
- PPH_STRING currentDirectory;
-
- if (PhGetIntegerSetting(L"EnableWarnings"))
- {
- cont = PhShowConfirmMessage(
- hWnd,
- L"restart",
- Process->ProcessName->Buffer,
- L"The process will be restarted with the same command line and "
- L"working directory, but if it is running under a different user it "
- L"will be restarted under the current user.",
- FALSE
- );
- }
- else
- {
- cont = TRUE;
- }
-
- if (!cont)
- return FALSE;
-
- // Open the process and get the command line and current directory.
-
- if (!NT_SUCCESS(status = PhOpenProcess(
- &processHandle,
- ProcessQueryAccess | PROCESS_VM_READ,
- Process->ProcessId
- )))
- goto ErrorExit;
-
- if (!NT_SUCCESS(status = PhGetProcessCommandLine(
- processHandle,
- &commandLine
- )))
- goto ErrorExit;
-
- PH_AUTO(commandLine);
-
- if (!NT_SUCCESS(status = PhGetProcessPebString(
- processHandle,
- PhpoCurrentDirectory,
- ¤tDirectory
- )))
- goto ErrorExit;
-
- PH_AUTO(currentDirectory);
-
- NtClose(processHandle);
- processHandle = NULL;
-
- // Open the process and terminate it.
-
- if (!NT_SUCCESS(status = PhOpenProcess(
- &processHandle,
- PROCESS_TERMINATE,
- Process->ProcessId
- )))
- goto ErrorExit;
-
- if (!NT_SUCCESS(status = PhTerminateProcess(
- processHandle,
- 1
- )))
- goto ErrorExit;
-
- NtClose(processHandle);
- processHandle = NULL;
-
- // Start the process.
-
- status = PhCreateProcessWin32(
- PhGetString(Process->FileName), // we didn't wait for S1 processing
- commandLine->Buffer,
- NULL,
- currentDirectory->Buffer,
- 0,
- NULL,
- NULL,
- NULL
- );
-
-ErrorExit:
- if (processHandle)
- NtClose(processHandle);
-
- if (!NT_SUCCESS(status))
- {
- PhpShowErrorProcess(hWnd, L"restart", Process, status, 0);
- return FALSE;
- }
-
- return TRUE;
-}
-
-// Contributed by evilpie (#2981421)
-BOOLEAN PhUiDebugProcess(
- _In_ HWND hWnd,
- _In_ PPH_PROCESS_ITEM Process
- )
-{
- NTSTATUS status;
- BOOLEAN cont = FALSE;
- PH_STRING_BUILDER commandLineBuilder;
-
- if (PhGetIntegerSetting(L"EnableWarnings"))
- {
- cont = PhShowConfirmMessage(
- hWnd,
- L"debug",
- Process->ProcessName->Buffer,
- L"Debugging a process may result in loss of data.",
- FALSE
- );
- }
- else
- {
- cont = TRUE;
- }
-
- if (!cont)
- return FALSE;
-
- if (PhBeginInitOnce(&DebuggerCommandInitOnce))
- {
- static PH_STRINGREF aeDebugKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug");
-
- HANDLE keyHandle;
- PPH_STRING debugger;
- PH_STRINGREF commandPart;
- PH_STRINGREF dummy;
-
- if (NT_SUCCESS(PhOpenKey(
- &keyHandle,
- KEY_READ,
- PH_KEY_LOCAL_MACHINE,
- &aeDebugKeyName,
- 0
- )))
- {
- if (debugger = PH_AUTO(PhQueryRegistryString(keyHandle, L"Debugger")))
- {
- if (PhSplitStringRefAtChar(&debugger->sr, '"', &dummy, &commandPart) &&
- PhSplitStringRefAtChar(&commandPart, '"', &commandPart, &dummy))
- {
- DebuggerCommand = PhCreateString2(&commandPart);
- }
- }
-
- NtClose(keyHandle);
- }
-
- PhEndInitOnce(&DebuggerCommandInitOnce);
- }
-
- if (!DebuggerCommand)
- {
- PhShowError(hWnd, L"Unable to locate the debugger.");
- return FALSE;
- }
-
- PhInitializeStringBuilder(&commandLineBuilder, DebuggerCommand->Length + 30);
-
- PhAppendCharStringBuilder(&commandLineBuilder, '"');
- PhAppendStringBuilder(&commandLineBuilder, &DebuggerCommand->sr);
- PhAppendCharStringBuilder(&commandLineBuilder, '"');
- PhAppendFormatStringBuilder(&commandLineBuilder, L" -p %u", HandleToUlong(Process->ProcessId));
-
- status = PhCreateProcessWin32(
- NULL,
- commandLineBuilder.String->Buffer,
- NULL,
- NULL,
- 0,
- NULL,
- NULL,
- NULL
- );
-
- PhDeleteStringBuilder(&commandLineBuilder);
-
- if (!NT_SUCCESS(status))
- {
- PhpShowErrorProcess(hWnd, L"debug", Process, status, 0);
- return FALSE;
- }
-
- return TRUE;
-}
-
-BOOLEAN PhUiReduceWorkingSetProcesses(
- _In_ HWND hWnd,
- _In_ PPH_PROCESS_ITEM *Processes,
- _In_ ULONG NumberOfProcesses
- )
-{
- BOOLEAN success = TRUE;
- ULONG i;
-
- for (i = 0; i < NumberOfProcesses; i++)
- {
- NTSTATUS status;
- HANDLE processHandle;
-
- if (NT_SUCCESS(status = PhOpenProcess(
- &processHandle,
- PROCESS_SET_QUOTA,
- Processes[i]->ProcessId
- )))
- {
- QUOTA_LIMITS quotaLimits;
-
- memset("aLimits, 0, sizeof(QUOTA_LIMITS));
- quotaLimits.MinimumWorkingSetSize = -1;
- quotaLimits.MaximumWorkingSetSize = -1;
-
- status = NtSetInformationProcess(
- processHandle,
- ProcessQuotaLimits,
- "aLimits,
- sizeof(QUOTA_LIMITS)
- );
-
- NtClose(processHandle);
- }
-
- if (!NT_SUCCESS(status))
- {
- success = FALSE;
-
- if (!PhpShowErrorProcess(hWnd, L"reduce the working set of", Processes[i], status, 0))
- break;
- }
- }
-
- return success;
-}
-
-BOOLEAN PhUiSetVirtualizationProcess(
- _In_ HWND hWnd,
- _In_ PPH_PROCESS_ITEM Process,
- _In_ BOOLEAN Enable
- )
-{
- NTSTATUS status;
- BOOLEAN cont = FALSE;
- HANDLE processHandle;
- HANDLE tokenHandle;
-
- if (PhGetIntegerSetting(L"EnableWarnings"))
- {
- cont = PhShowConfirmMessage(
- hWnd,
- L"set",
- L"virtualization for the process",
- L"Enabling or disabling virtualization for a process may "
- L"alter its functionality and produce undesirable effects.",
- FALSE
- );
- }
- else
- {
- cont = TRUE;
- }
-
- if (!cont)
- return FALSE;
-
- if (NT_SUCCESS(status = PhOpenProcess(
- &processHandle,
- ProcessQueryAccess,
- Process->ProcessId
- )))
- {
- if (NT_SUCCESS(status = PhOpenProcessToken(
- processHandle,
- TOKEN_WRITE,
- &tokenHandle
- )))
- {
- status = PhSetTokenIsVirtualizationEnabled(tokenHandle, Enable);
- NtClose(tokenHandle);
- }
-
- NtClose(processHandle);
- }
-
- if (!NT_SUCCESS(status))
- {
- PhpShowErrorProcess(hWnd, L"set virtualization for", Process, status, 0);
- return FALSE;
- }
-
- return TRUE;
-}
-
-BOOLEAN PhUiDetachFromDebuggerProcess(
- _In_ HWND hWnd,
- _In_ PPH_PROCESS_ITEM Process
- )
-{
- NTSTATUS status;
- HANDLE processHandle;
- HANDLE debugObjectHandle;
-
- if (NT_SUCCESS(status = PhOpenProcess(
- &processHandle,
- PROCESS_QUERY_INFORMATION | PROCESS_SUSPEND_RESUME,
- Process->ProcessId
- )))
- {
- if (NT_SUCCESS(status = PhGetProcessDebugObject(
- processHandle,
- &debugObjectHandle
- )))
- {
- ULONG flags;
-
- // Disable kill-on-close.
- flags = 0;
- NtSetInformationDebugObject(
- debugObjectHandle,
- DebugObjectFlags,
- &flags,
- sizeof(ULONG),
- NULL
- );
-
- status = NtRemoveProcessDebug(processHandle, debugObjectHandle);
-
- NtClose(debugObjectHandle);
- }
-
- NtClose(processHandle);
- }
-
- if (status == STATUS_PORT_NOT_SET)
- {
- PhShowInformation(hWnd, L"The process is not being debugged.");
- return FALSE;
- }
-
- if (!NT_SUCCESS(status))
- {
- PhpShowErrorProcess(hWnd, L"detach debugger from", Process, status, 0);
- return FALSE;
- }
-
- return TRUE;
-}
-
-BOOLEAN PhUiInjectDllProcess(
- _In_ HWND hWnd,
- _In_ PPH_PROCESS_ITEM Process
- )
-{
- static PH_FILETYPE_FILTER filters[] =
- {
- { L"DLL files (*.dll)", L"*.dll" },
- { L"All files (*.*)", L"*.*" }
- };
-
- NTSTATUS status;
- PVOID fileDialog;
- PPH_STRING fileName;
- HANDLE processHandle;
-
- fileDialog = PhCreateOpenFileDialog();
- PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER));
-
- if (!PhShowFileDialog(hWnd, fileDialog))
- {
- PhFreeFileDialog(fileDialog);
- return FALSE;
- }
-
- fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog));
- PhFreeFileDialog(fileDialog);
-
- if (NT_SUCCESS(status = PhOpenProcess(
- &processHandle,
- ProcessQueryAccess | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION |
- PROCESS_VM_READ | PROCESS_VM_WRITE,
- Process->ProcessId
- )))
- {
- LARGE_INTEGER timeout;
-
- timeout.QuadPart = -5 * PH_TIMEOUT_SEC;
- status = PhInjectDllProcess(
- processHandle,
- fileName->Buffer,
- &timeout
- );
-
- NtClose(processHandle);
- }
-
- if (!NT_SUCCESS(status))
- {
- PhpShowErrorProcess(hWnd, L"inject the DLL into", Process, status, 0);
- return FALSE;
- }
-
- return TRUE;
-}
-
-BOOLEAN PhUiSetIoPriorityProcesses(
- _In_ HWND hWnd,
- _In_ PPH_PROCESS_ITEM *Processes,
- _In_ ULONG NumberOfProcesses,
- _In_ IO_PRIORITY_HINT IoPriority
- )
-{
- BOOLEAN success = TRUE;
- BOOLEAN cancelled = FALSE;
- ULONG i;
-
- for (i = 0; i < NumberOfProcesses; i++)
- {
- NTSTATUS status;
- HANDLE processHandle;
-
- if (NT_SUCCESS(status = PhOpenProcess(
- &processHandle,
- PROCESS_SET_INFORMATION,
- Processes[i]->ProcessId
- )))
- {
- if (Processes[i]->ProcessId != SYSTEM_PROCESS_ID)
- {
- status = PhSetProcessIoPriority(processHandle, IoPriority);
- }
- else
- {
- // See comment in PhUiSetPriorityProcesses.
- status = STATUS_UNSUCCESSFUL;
- }
-
- NtClose(processHandle);
- }
-
- if (!NT_SUCCESS(status))
- {
- BOOLEAN connected;
-
- success = FALSE;
-
- // The operation may have failed due to the lack of SeIncreaseBasePriorityPrivilege.
- if (!cancelled && PhpShowErrorAndConnectToPhSvc(
- hWnd,
- PhaConcatStrings2(L"Unable to set the I/O priority of ", Processes[i]->ProcessName->Buffer)->Buffer,
- status,
- &connected
- ))
- {
- if (connected)
- {
- if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessIoPriority, IoPriority)))
- success = TRUE;
- else
- PhpShowErrorProcess(hWnd, L"set the I/O priority of", Processes[i], status, 0);
-
- PhUiDisconnectFromPhSvc();
- }
- else
- {
- cancelled = TRUE;
- }
- }
- else
- {
- if (!PhpShowErrorProcess(hWnd, L"set the I/O priority of", Processes[i], status, 0))
- break;
- }
- }
- }
-
- return success;
-}
-
-BOOLEAN PhUiSetPagePriorityProcess(
- _In_ HWND hWnd,
- _In_ PPH_PROCESS_ITEM Process,
- _In_ ULONG PagePriority
- )
-{
- NTSTATUS status;
- HANDLE processHandle;
-
- if (NT_SUCCESS(status = PhOpenProcess(
- &processHandle,
- PROCESS_SET_INFORMATION,
- Process->ProcessId
- )))
- {
- if (Process->ProcessId != SYSTEM_PROCESS_ID)
- {
- status = NtSetInformationProcess(
- processHandle,
- ProcessPagePriority,
- &PagePriority,
- sizeof(ULONG)
- );
- }
- else
- {
- // See comment in PhUiSetPriorityProcesses.
- status = STATUS_UNSUCCESSFUL;
- }
-
- NtClose(processHandle);
- }
-
- if (!NT_SUCCESS(status))
- {
- PhpShowErrorProcess(hWnd, L"set the page priority of", Process, status, 0);
- return FALSE;
- }
-
- return TRUE;
-}
-
-BOOLEAN PhUiSetPriorityProcesses(
- _In_ HWND hWnd,
- _In_ PPH_PROCESS_ITEM *Processes,
- _In_ ULONG NumberOfProcesses,
- _In_ ULONG PriorityClass
- )
-{
- BOOLEAN success = TRUE;
- BOOLEAN cancelled = FALSE;
- ULONG i;
-
- for (i = 0; i < NumberOfProcesses; i++)
- {
- NTSTATUS status;
- HANDLE processHandle;
- PROCESS_PRIORITY_CLASS priorityClass;
-
- if (NT_SUCCESS(status = PhOpenProcess(
- &processHandle,
- PROCESS_SET_INFORMATION,
- Processes[i]->ProcessId
- )))
- {
- if (Processes[i]->ProcessId != SYSTEM_PROCESS_ID)
- {
- priorityClass.Foreground = FALSE;
- priorityClass.PriorityClass = (UCHAR)PriorityClass;
- status = NtSetInformationProcess(processHandle, ProcessPriorityClass, &priorityClass, sizeof(PROCESS_PRIORITY_CLASS));
- }
- else
- {
- // Changing the priority of System can lead to a BSOD on some versions of Windows,
- // so disallow this.
- status = STATUS_UNSUCCESSFUL;
- }
-
- NtClose(processHandle);
- }
-
- if (!NT_SUCCESS(status))
- {
- BOOLEAN connected;
-
- success = FALSE;
-
- // The operation may have failed due to the lack of SeIncreaseBasePriorityPrivilege.
- if (!cancelled && PhpShowErrorAndConnectToPhSvc(
- hWnd,
- PhaConcatStrings2(L"Unable to set the priority of ", Processes[i]->ProcessName->Buffer)->Buffer,
- status,
- &connected
- ))
- {
- if (connected)
- {
- if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessPriority, PriorityClass)))
- success = TRUE;
- else
- PhpShowErrorProcess(hWnd, L"set the priority of", Processes[i], status, 0);
-
- PhUiDisconnectFromPhSvc();
- }
- else
- {
- cancelled = TRUE;
- }
- }
- else
- {
- if (!PhpShowErrorProcess(hWnd, L"set the priority of", Processes[i], status, 0))
- break;
- }
- }
- }
-
- return success;
-}
-
-static VOID PhpShowErrorService(
- _In_ HWND hWnd,
- _In_ PWSTR Verb,
- _In_ PPH_SERVICE_ITEM Service,
- _In_ NTSTATUS Status,
- _In_opt_ ULONG Win32Result
- )
-{
- PhShowStatus(
- hWnd,
- PhaFormatString(
- L"Unable to %s %s",
- Verb,
- Service->Name->Buffer
- )->Buffer,
- Status,
- Win32Result
- );
-}
-
-BOOLEAN PhUiStartService(
- _In_ HWND hWnd,
- _In_ PPH_SERVICE_ITEM Service
- )
-{
- SC_HANDLE serviceHandle;
- BOOLEAN success = FALSE;
-
- serviceHandle = PhOpenService(Service->Name->Buffer, SERVICE_START);
-
- if (serviceHandle)
- {
- if (StartService(serviceHandle, 0, NULL))
- success = TRUE;
-
- CloseServiceHandle(serviceHandle);
- }
-
- if (!success)
- {
- NTSTATUS status;
- BOOLEAN connected;
-
- status = PhGetLastWin32ErrorAsNtStatus();
-
- if (PhpShowErrorAndConnectToPhSvc(
- hWnd,
- PhaConcatStrings2(L"Unable to start ", Service->Name->Buffer)->Buffer,
- status,
- &connected
- ))
- {
- if (connected)
- {
- if (NT_SUCCESS(status = PhSvcCallControlService(Service->Name->Buffer, PhSvcControlServiceStart)))
- success = TRUE;
- else
- PhpShowErrorService(hWnd, L"start", Service, status, 0);
-
- PhUiDisconnectFromPhSvc();
- }
- }
- else
- {
- PhpShowErrorService(hWnd, L"start", Service, status, 0);
- }
- }
-
- return success;
-}
-
-BOOLEAN PhUiContinueService(
- _In_ HWND hWnd,
- _In_ PPH_SERVICE_ITEM Service
- )
-{
- SC_HANDLE serviceHandle;
- BOOLEAN success = FALSE;
-
- serviceHandle = PhOpenService(Service->Name->Buffer, SERVICE_PAUSE_CONTINUE);
-
- if (serviceHandle)
- {
- SERVICE_STATUS serviceStatus;
-
- if (ControlService(serviceHandle, SERVICE_CONTROL_CONTINUE, &serviceStatus))
- success = TRUE;
-
- CloseServiceHandle(serviceHandle);
- }
-
- if (!success)
- {
- NTSTATUS status;
- BOOLEAN connected;
-
- status = PhGetLastWin32ErrorAsNtStatus();
-
- if (PhpShowErrorAndConnectToPhSvc(
- hWnd,
- PhaConcatStrings2(L"Unable to continue ", Service->Name->Buffer)->Buffer,
- status,
- &connected
- ))
- {
- if (connected)
- {
- if (NT_SUCCESS(status = PhSvcCallControlService(Service->Name->Buffer, PhSvcControlServiceContinue)))
- success = TRUE;
- else
- PhpShowErrorService(hWnd, L"continue", Service, status, 0);
-
- PhUiDisconnectFromPhSvc();
- }
- }
- else
- {
- PhpShowErrorService(hWnd, L"continue", Service, status, 0);
- }
- }
-
- return success;
-}
-
-BOOLEAN PhUiPauseService(
- _In_ HWND hWnd,
- _In_ PPH_SERVICE_ITEM Service
- )
-{
- SC_HANDLE serviceHandle;
- BOOLEAN success = FALSE;
-
- serviceHandle = PhOpenService(Service->Name->Buffer, SERVICE_PAUSE_CONTINUE);
-
- if (serviceHandle)
- {
- SERVICE_STATUS serviceStatus;
-
- if (ControlService(serviceHandle, SERVICE_CONTROL_PAUSE, &serviceStatus))
- success = TRUE;
-
- CloseServiceHandle(serviceHandle);
- }
-
- if (!success)
- {
- NTSTATUS status;
- BOOLEAN connected;
-
- status = PhGetLastWin32ErrorAsNtStatus();
-
- if (PhpShowErrorAndConnectToPhSvc(
- hWnd,
- PhaConcatStrings2(L"Unable to pause ", Service->Name->Buffer)->Buffer,
- status,
- &connected
- ))
- {
- if (connected)
- {
- if (NT_SUCCESS(status = PhSvcCallControlService(Service->Name->Buffer, PhSvcControlServicePause)))
- success = TRUE;
- else
- PhpShowErrorService(hWnd, L"pause", Service, status, 0);
-
- PhUiDisconnectFromPhSvc();
- }
- }
- else
- {
- PhpShowErrorService(hWnd, L"pause", Service, status, 0);
- }
- }
-
- return success;
-}
-
-BOOLEAN PhUiStopService(
- _In_ HWND hWnd,
- _In_ PPH_SERVICE_ITEM Service
- )
-{
- SC_HANDLE serviceHandle;
- BOOLEAN success = FALSE;
-
- serviceHandle = PhOpenService(Service->Name->Buffer, SERVICE_STOP);
-
- if (serviceHandle)
- {
- SERVICE_STATUS serviceStatus;
-
- if (ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus))
- success = TRUE;
-
- CloseServiceHandle(serviceHandle);
- }
-
- if (!success)
- {
- NTSTATUS status;
- BOOLEAN connected;
-
- status = PhGetLastWin32ErrorAsNtStatus();
-
- if (PhpShowErrorAndConnectToPhSvc(
- hWnd,
- PhaConcatStrings2(L"Unable to stop ", Service->Name->Buffer)->Buffer,
- status,
- &connected
- ))
- {
- if (connected)
- {
- if (NT_SUCCESS(status = PhSvcCallControlService(Service->Name->Buffer, PhSvcControlServiceStop)))
- success = TRUE;
- else
- PhpShowErrorService(hWnd, L"stop", Service, status, 0);
-
- PhUiDisconnectFromPhSvc();
- }
- }
- else
- {
- PhpShowErrorService(hWnd, L"stop", Service, status, 0);
- }
- }
-
- return success;
-}
-
-BOOLEAN PhUiDeleteService(
- _In_ HWND hWnd,
- _In_ PPH_SERVICE_ITEM Service
- )
-{
- SC_HANDLE serviceHandle;
- BOOLEAN success = FALSE;
-
- // Warnings cannot be disabled for service deletion.
- if (!PhShowConfirmMessage(
- hWnd,
- L"delete",
- Service->Name->Buffer,
- L"Deleting a service can prevent the system from starting "
- L"or functioning properly.",
- TRUE
- ))
- return FALSE;
-
- serviceHandle = PhOpenService(Service->Name->Buffer, DELETE);
-
- if (serviceHandle)
- {
- if (DeleteService(serviceHandle))
- success = TRUE;
-
- CloseServiceHandle(serviceHandle);
- }
-
- if (!success)
- {
- NTSTATUS status;
- BOOLEAN connected;
-
- status = PhGetLastWin32ErrorAsNtStatus();
-
- if (PhpShowErrorAndConnectToPhSvc(
- hWnd,
- PhaConcatStrings2(L"Unable to delete ", Service->Name->Buffer)->Buffer,
- status,
- &connected
- ))
- {
- if (connected)
- {
- if (NT_SUCCESS(status = PhSvcCallControlService(Service->Name->Buffer, PhSvcControlServiceDelete)))
- success = TRUE;
- else
- PhpShowErrorService(hWnd, L"delete", Service, status, 0);
-
- PhUiDisconnectFromPhSvc();
- }
- }
- else
- {
- PhpShowErrorService(hWnd, L"delete", Service, status, 0);
- }
- }
-
- return success;
-}
-
-BOOLEAN PhUiCloseConnections(
- _In_ HWND hWnd,
- _In_ PPH_NETWORK_ITEM *Connections,
- _In_ ULONG NumberOfConnections
- )
-{
-
- BOOLEAN success = TRUE;
- BOOLEAN cancelled = FALSE;
- ULONG result;
- ULONG i;
- _SetTcpEntry SetTcpEntry_I;
- MIB_TCPROW tcpRow;
-
- SetTcpEntry_I = PhGetModuleProcAddress(L"iphlpapi.dll", "SetTcpEntry");
-
- if (!SetTcpEntry_I)
- {
- PhShowError(
- hWnd,
- L"This feature is not supported by your operating system."
- );
- return FALSE;
- }
-
- for (i = 0; i < NumberOfConnections; i++)
- {
- if (
- Connections[i]->ProtocolType != PH_TCP4_NETWORK_PROTOCOL ||
- Connections[i]->State != MIB_TCP_STATE_ESTAB
- )
- continue;
-
- tcpRow.dwState = MIB_TCP_STATE_DELETE_TCB;
- tcpRow.dwLocalAddr = Connections[i]->LocalEndpoint.Address.Ipv4;
- tcpRow.dwLocalPort = _byteswap_ushort((USHORT)Connections[i]->LocalEndpoint.Port);
- tcpRow.dwRemoteAddr = Connections[i]->RemoteEndpoint.Address.Ipv4;
- tcpRow.dwRemotePort = _byteswap_ushort((USHORT)Connections[i]->RemoteEndpoint.Port);
-
- if ((result = SetTcpEntry_I(&tcpRow)) != 0)
- {
- NTSTATUS status;
- BOOLEAN connected;
-
- success = FALSE;
-
- // SetTcpEntry returns ERROR_MR_MID_NOT_FOUND for access denied errors for some reason.
- if (result == ERROR_MR_MID_NOT_FOUND)
- result = ERROR_ACCESS_DENIED;
-
- if (!cancelled && PhpShowErrorAndConnectToPhSvc(
- hWnd,
- L"Unable to close the TCP connection",
- NTSTATUS_FROM_WIN32(result),
- &connected
- ))
- {
- if (connected)
- {
- if (NT_SUCCESS(status = PhSvcCallSetTcpEntry(&tcpRow)))
- success = TRUE;
- else
- PhShowStatus(hWnd, L"Unable to close the TCP connection", status, 0);
-
- PhUiDisconnectFromPhSvc();
- }
- else
- {
- cancelled = TRUE;
- }
- }
- else
- {
- if (PhShowMessage(
- hWnd,
- MB_ICONERROR | MB_OKCANCEL,
- L"Unable to close the TCP connection (from %s:%u). "
- L"Make sure Process Hacker is running with administrative privileges.",
- Connections[i]->LocalAddressString,
- Connections[i]->LocalEndpoint.Port
- ) != IDOK)
- break;
- }
- }
- }
-
- return success;
-}
-
-static BOOLEAN PhpShowContinueMessageThreads(
- _In_ HWND hWnd,
- _In_ PWSTR Verb,
- _In_ PWSTR Message,
- _In_ BOOLEAN Warning,
- _In_ PPH_THREAD_ITEM *Threads,
- _In_ ULONG NumberOfThreads
- )
-{
- PWSTR object;
- BOOLEAN cont = FALSE;
-
- if (NumberOfThreads == 0)
- return FALSE;
-
- if (PhGetIntegerSetting(L"EnableWarnings"))
- {
- if (NumberOfThreads == 1)
- {
- object = L"the selected thread";
- }
- else
- {
- object = L"the selected threads";
- }
-
- cont = PhShowConfirmMessage(
- hWnd,
- Verb,
- object,
- Message,
- Warning
- );
- }
- else
- {
- cont = TRUE;
- }
-
- return cont;
-}
-
-static BOOLEAN PhpShowErrorThread(
- _In_ HWND hWnd,
- _In_ PWSTR Verb,
- _In_ PPH_THREAD_ITEM Thread,
- _In_ NTSTATUS Status,
- _In_opt_ ULONG Win32Result
- )
-{
- return PhShowContinueStatus(
- hWnd,
- PhaFormatString(
- L"Unable to %s thread %u",
- Verb,
- HandleToUlong(Thread->ThreadId)
- )->Buffer,
- Status,
- Win32Result
- );
-}
-
-BOOLEAN PhUiTerminateThreads(
- _In_ HWND hWnd,
- _In_ PPH_THREAD_ITEM *Threads,
- _In_ ULONG NumberOfThreads
- )
-{
- BOOLEAN success = TRUE;
- BOOLEAN cancelled = FALSE;
- ULONG i;
-
- if (!PhpShowContinueMessageThreads(
- hWnd,
- L"terminate",
- L"Terminating a thread may cause the process to stop working.",
- FALSE,
- Threads,
- NumberOfThreads
- ))
- return FALSE;
-
- for (i = 0; i < NumberOfThreads; i++)
- {
- NTSTATUS status;
- HANDLE threadHandle;
-
- if (NT_SUCCESS(status = PhOpenThread(
- &threadHandle,
- THREAD_TERMINATE,
- Threads[i]->ThreadId
- )))
- {
- status = NtTerminateThread(threadHandle, STATUS_SUCCESS);
- NtClose(threadHandle);
- }
-
- if (!NT_SUCCESS(status))
- {
- BOOLEAN connected;
-
- success = FALSE;
-
- if (!cancelled && PhpShowErrorAndConnectToPhSvc(
- hWnd,
- PhaFormatString(L"Unable to terminate thread %u", HandleToUlong(Threads[i]->ThreadId))->Buffer,
- status,
- &connected
- ))
- {
- if (connected)
- {
- if (NT_SUCCESS(status = PhSvcCallControlThread(Threads[i]->ThreadId, PhSvcControlThreadTerminate, 0)))
- success = TRUE;
- else
- PhpShowErrorThread(hWnd, L"terminate", Threads[i], status, 0);
-
- PhUiDisconnectFromPhSvc();
- }
- else
- {
- cancelled = TRUE;
- }
- }
- else
- {
- if (!PhpShowErrorThread(hWnd, L"terminate", Threads[i], status, 0))
- break;
- }
- }
- }
-
- return success;
-}
-
-BOOLEAN PhUiSuspendThreads(
- _In_ HWND hWnd,
- _In_ PPH_THREAD_ITEM *Threads,
- _In_ ULONG NumberOfThreads
- )
-{
- BOOLEAN success = TRUE;
- BOOLEAN cancelled = FALSE;
- ULONG i;
-
- for (i = 0; i < NumberOfThreads; i++)
- {
- NTSTATUS status;
- HANDLE threadHandle;
-
- if (NT_SUCCESS(status = PhOpenThread(
- &threadHandle,
- THREAD_SUSPEND_RESUME,
- Threads[i]->ThreadId
- )))
- {
- status = NtSuspendThread(threadHandle, NULL);
- NtClose(threadHandle);
- }
-
- if (!NT_SUCCESS(status))
- {
- BOOLEAN connected;
-
- success = FALSE;
-
- if (!cancelled && PhpShowErrorAndConnectToPhSvc(
- hWnd,
- PhaFormatString(L"Unable to suspend thread %u", HandleToUlong(Threads[i]->ThreadId))->Buffer,
- status,
- &connected
- ))
- {
- if (connected)
- {
- if (NT_SUCCESS(status = PhSvcCallControlThread(Threads[i]->ThreadId, PhSvcControlThreadSuspend, 0)))
- success = TRUE;
- else
- PhpShowErrorThread(hWnd, L"suspend", Threads[i], status, 0);
-
- PhUiDisconnectFromPhSvc();
- }
- else
- {
- cancelled = TRUE;
- }
- }
- else
- {
- if (!PhpShowErrorThread(hWnd, L"suspend", Threads[i], status, 0))
- break;
- }
- }
- }
-
- return success;
-}
-
-BOOLEAN PhUiResumeThreads(
- _In_ HWND hWnd,
- _In_ PPH_THREAD_ITEM *Threads,
- _In_ ULONG NumberOfThreads
- )
-{
- BOOLEAN success = TRUE;
- BOOLEAN cancelled = FALSE;
- ULONG i;
-
- for (i = 0; i < NumberOfThreads; i++)
- {
- NTSTATUS status;
- HANDLE threadHandle;
-
- if (NT_SUCCESS(status = PhOpenThread(
- &threadHandle,
- THREAD_SUSPEND_RESUME,
- Threads[i]->ThreadId
- )))
- {
- status = NtResumeThread(threadHandle, NULL);
- NtClose(threadHandle);
- }
-
- if (!NT_SUCCESS(status))
- {
- BOOLEAN connected;
-
- success = FALSE;
-
- if (!cancelled && PhpShowErrorAndConnectToPhSvc(
- hWnd,
- PhaFormatString(L"Unable to resume thread %u", HandleToUlong(Threads[i]->ThreadId))->Buffer,
- status,
- &connected
- ))
- {
- if (connected)
- {
- if (NT_SUCCESS(status = PhSvcCallControlThread(Threads[i]->ThreadId, PhSvcControlThreadResume, 0)))
- success = TRUE;
- else
- PhpShowErrorThread(hWnd, L"resume", Threads[i], status, 0);
-
- PhUiDisconnectFromPhSvc();
- }
- else
- {
- cancelled = TRUE;
- }
- }
- else
- {
- if (!PhpShowErrorThread(hWnd, L"resume", Threads[i], status, 0))
- break;
- }
- }
- }
-
- return success;
-}
-
-BOOLEAN PhUiSetPriorityThread(
- _In_ HWND hWnd,
- _In_ PPH_THREAD_ITEM Thread,
- _In_ LONG Increment
- )
-{
- NTSTATUS status;
- HANDLE threadHandle;
-
- // Special saturation values
- if (Increment == THREAD_PRIORITY_TIME_CRITICAL)
- Increment = THREAD_BASE_PRIORITY_LOWRT + 1;
- else if (Increment == THREAD_PRIORITY_IDLE)
- Increment = THREAD_BASE_PRIORITY_IDLE - 1;
-
- if (NT_SUCCESS(status = PhOpenThread(
- &threadHandle,
- ThreadSetAccess,
- Thread->ThreadId
- )))
- {
- status = NtSetInformationThread(threadHandle, ThreadBasePriority, &Increment, sizeof(LONG));
- NtClose(threadHandle);
- }
-
- if (!NT_SUCCESS(status))
- {
- PhpShowErrorThread(hWnd, L"set the priority of", Thread, status, 0);
- return FALSE;
- }
-
- return TRUE;
-}
-
-BOOLEAN PhUiSetIoPriorityThread(
- _In_ HWND hWnd,
- _In_ PPH_THREAD_ITEM Thread,
- _In_ IO_PRIORITY_HINT IoPriority
- )
-{
- NTSTATUS status;
- BOOLEAN success = TRUE;
- HANDLE threadHandle;
-
- if (NT_SUCCESS(status = PhOpenThread(
- &threadHandle,
- THREAD_SET_INFORMATION,
- Thread->ThreadId
- )))
- {
- status = PhSetThreadIoPriority(threadHandle, IoPriority);
- NtClose(threadHandle);
- }
-
- if (!NT_SUCCESS(status))
- {
- BOOLEAN connected;
-
- success = FALSE;
-
- // The operation may have failed due to the lack of SeIncreaseBasePriorityPrivilege.
- if (PhpShowErrorAndConnectToPhSvc(
- hWnd,
- PhaFormatString(L"Unable to set the I/O priority of thread %u", HandleToUlong(Thread->ThreadId))->Buffer,
- status,
- &connected
- ))
- {
- if (connected)
- {
- if (NT_SUCCESS(status = PhSvcCallControlThread(Thread->ThreadId, PhSvcControlThreadIoPriority, IoPriority)))
- success = TRUE;
- else
- PhpShowErrorThread(hWnd, L"set the I/O priority of", Thread, status, 0);
-
- PhUiDisconnectFromPhSvc();
- }
- }
- else
- {
- PhpShowErrorThread(hWnd, L"set the I/O priority of", Thread, status, 0);
- }
- }
-
- return success;
-}
-
-BOOLEAN PhUiSetPagePriorityThread(
- _In_ HWND hWnd,
- _In_ PPH_THREAD_ITEM Thread,
- _In_ ULONG PagePriority
- )
-{
- NTSTATUS status;
- HANDLE threadHandle;
-
- if (NT_SUCCESS(status = PhOpenThread(
- &threadHandle,
- THREAD_SET_INFORMATION,
- Thread->ThreadId
- )))
- {
- status = NtSetInformationThread(
- threadHandle,
- ThreadPagePriority,
- &PagePriority,
- sizeof(ULONG)
- );
- NtClose(threadHandle);
- }
-
- if (!NT_SUCCESS(status))
- {
- PhpShowErrorThread(hWnd, L"set the page priority of", Thread, status, 0);
- return FALSE;
- }
-
- return TRUE;
-}
-
-BOOLEAN PhUiUnloadModule(
- _In_ HWND hWnd,
- _In_ HANDLE ProcessId,
- _In_ PPH_MODULE_ITEM Module
- )
-{
- NTSTATUS status;
- BOOLEAN cont = FALSE;
- HANDLE processHandle;
-
- if (PhGetIntegerSetting(L"EnableWarnings"))
- {
- PWSTR verb;
- PWSTR message;
-
- switch (Module->Type)
- {
- case PH_MODULE_TYPE_MODULE:
- case PH_MODULE_TYPE_WOW64_MODULE:
- verb = L"unload";
- message = L"Unloading a module may cause the process to crash.";
-
- if (WindowsVersion >= WINDOWS_8)
- message = L"Unloading a module may cause the process to crash. NOTE: This feature may not work correctly on your version of Windows.";
-
- break;
- case PH_MODULE_TYPE_KERNEL_MODULE:
- verb = L"unload";
- message = L"Unloading a driver may cause system instability.";
- break;
- case PH_MODULE_TYPE_MAPPED_FILE:
- case PH_MODULE_TYPE_MAPPED_IMAGE:
- verb = L"unmap";
- message = L"Unmapping a section view may cause the process to crash.";
- break;
- default:
- return FALSE;
- }
-
- cont = PhShowConfirmMessage(
- hWnd,
- verb,
- Module->Name->Buffer,
- message,
- TRUE
- );
- }
- else
- {
- cont = TRUE;
- }
-
- if (!cont)
- return FALSE;
-
- switch (Module->Type)
- {
- case PH_MODULE_TYPE_MODULE:
- case PH_MODULE_TYPE_WOW64_MODULE:
- if (NT_SUCCESS(status = PhOpenProcess(
- &processHandle,
- ProcessQueryAccess | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION |
- PROCESS_VM_READ | PROCESS_VM_WRITE,
- ProcessId
- )))
- {
- LARGE_INTEGER timeout;
-
- timeout.QuadPart = -5 * PH_TIMEOUT_SEC;
- status = PhUnloadDllProcess(
- processHandle,
- Module->BaseAddress,
- &timeout
- );
-
- NtClose(processHandle);
- }
-
- if (status == STATUS_DLL_NOT_FOUND)
- {
- PhShowError(hWnd, L"Unable to find the module to unload.");
- return FALSE;
- }
-
- if (!NT_SUCCESS(status))
- {
- PhShowStatus(
- hWnd,
- PhaConcatStrings2(L"Unable to unload ", Module->Name->Buffer)->Buffer,
- status,
- 0
- );
- return FALSE;
- }
-
- break;
-
- case PH_MODULE_TYPE_KERNEL_MODULE:
- status = PhUnloadDriver(Module->BaseAddress, Module->Name->Buffer);
-
- if (!NT_SUCCESS(status))
- {
- BOOLEAN success = FALSE;
- BOOLEAN connected;
-
- if (PhpShowErrorAndConnectToPhSvc(
- hWnd,
- PhaConcatStrings2(L"Unable to unload ", Module->Name->Buffer)->Buffer,
- status,
- &connected
- ))
- {
- if (connected)
- {
- if (NT_SUCCESS(status = PhSvcCallUnloadDriver(Module->BaseAddress, Module->Name->Buffer)))
- success = TRUE;
- else
- PhShowStatus(hWnd, PhaConcatStrings2(L"Unable to unload ", Module->Name->Buffer)->Buffer, status, 0);
-
- PhUiDisconnectFromPhSvc();
- }
- }
- else
- {
- PhShowStatus(
- hWnd,
- PhaConcatStrings(
- 3,
- L"Unable to unload ",
- Module->Name->Buffer,
- L". Make sure Process Hacker is running with "
- L"administrative privileges. Error"
- )->Buffer,
- status,
- 0
- );
- return FALSE;
- }
-
- return success;
- }
-
- break;
-
- case PH_MODULE_TYPE_MAPPED_FILE:
- case PH_MODULE_TYPE_MAPPED_IMAGE:
- if (NT_SUCCESS(status = PhOpenProcess(
- &processHandle,
- PROCESS_VM_OPERATION,
- ProcessId
- )))
- {
- status = NtUnmapViewOfSection(processHandle, Module->BaseAddress);
- NtClose(processHandle);
- }
-
- if (!NT_SUCCESS(status))
- {
- PhShowStatus(
- hWnd,
- PhaFormatString(L"Unable to unmap the section view at 0x%Ix", Module->BaseAddress)->Buffer,
- status,
- 0
- );
- return FALSE;
- }
-
- break;
-
- default:
- return FALSE;
- }
-
- return TRUE;
-}
-
-BOOLEAN PhUiFreeMemory(
- _In_ HWND hWnd,
- _In_ HANDLE ProcessId,
- _In_ PPH_MEMORY_ITEM MemoryItem,
- _In_ BOOLEAN Free
- )
-{
- NTSTATUS status;
- BOOLEAN cont = FALSE;
- HANDLE processHandle;
-
- if (PhGetIntegerSetting(L"EnableWarnings"))
- {
- PWSTR verb;
- PWSTR message;
-
- if (!(MemoryItem->Type & (MEM_MAPPED | MEM_IMAGE)))
- {
- if (Free)
- {
- verb = L"free";
- message = L"Freeing memory regions may cause the process to crash.";
- }
- else
- {
- verb = L"decommit";
- message = L"Decommitting memory regions may cause the process to crash.";
- }
- }
- else
- {
- verb = L"unmap";
- message = L"Unmapping a section view may cause the process to crash.";
- }
-
- cont = PhShowConfirmMessage(
- hWnd,
- verb,
- L"the memory region",
- message,
- TRUE
- );
- }
- else
- {
- cont = TRUE;
- }
-
- if (!cont)
- return FALSE;
-
- if (NT_SUCCESS(status = PhOpenProcess(
- &processHandle,
- PROCESS_VM_OPERATION,
- ProcessId
- )))
- {
- PVOID baseAddress;
- SIZE_T regionSize;
-
- baseAddress = MemoryItem->BaseAddress;
-
- if (!(MemoryItem->Type & (MEM_MAPPED | MEM_IMAGE)))
- {
- // The size needs to be 0 if we're freeing.
- if (Free)
- regionSize = 0;
- else
- regionSize = MemoryItem->RegionSize;
-
- status = NtFreeVirtualMemory(
- processHandle,
- &baseAddress,
- ®ionSize,
- Free ? MEM_RELEASE : MEM_DECOMMIT
- );
- }
- else
- {
- status = NtUnmapViewOfSection(processHandle, baseAddress);
- }
-
- NtClose(processHandle);
- }
-
- if (!NT_SUCCESS(status))
- {
- PWSTR message;
-
- if (!(MemoryItem->Type & (MEM_MAPPED | MEM_IMAGE)))
- {
- if (Free)
- message = L"Unable to free the memory region";
- else
- message = L"Unable to decommit the memory region";
- }
- else
- {
- message = L"Unable to unmap the section view";
- }
-
- PhShowStatus(
- hWnd,
- message,
- status,
- 0
- );
- return FALSE;
- }
-
- return TRUE;
-}
-
-static BOOLEAN PhpShowErrorHandle(
- _In_ HWND hWnd,
- _In_ PWSTR Verb,
- _In_ PPH_HANDLE_ITEM Handle,
- _In_ NTSTATUS Status,
- _In_opt_ ULONG Win32Result
- )
-{
- if (!PhIsNullOrEmptyString(Handle->BestObjectName))
- {
- return PhShowContinueStatus(
- hWnd,
- PhaFormatString(
- L"Unable to %s handle \"%s\" (0x%Ix)",
- Verb,
- Handle->BestObjectName->Buffer,
- HandleToUlong(Handle->Handle)
- )->Buffer,
- Status,
- Win32Result
- );
- }
- else
- {
- return PhShowContinueStatus(
- hWnd,
- PhaFormatString(
- L"Unable to %s handle 0x%Ix",
- Verb,
- HandleToUlong(Handle->Handle)
- )->Buffer,
- Status,
- Win32Result
- );
- }
-}
-
-BOOLEAN PhUiCloseHandles(
- _In_ HWND hWnd,
- _In_ HANDLE ProcessId,
- _In_ PPH_HANDLE_ITEM *Handles,
- _In_ ULONG NumberOfHandles,
- _In_ BOOLEAN Warn
- )
-{
- NTSTATUS status;
- BOOLEAN cont = FALSE;
- BOOLEAN success = TRUE;
- HANDLE processHandle;
-
- if (NumberOfHandles == 0)
- return FALSE;
-
- if (Warn && PhGetIntegerSetting(L"EnableWarnings"))
- {
- cont = PhShowConfirmMessage(
- hWnd,
- L"close",
- NumberOfHandles == 1 ? L"the selected handle" : L"the selected handles",
- L"Closing handles may cause system instability and data corruption.",
- FALSE
- );
- }
- else
- {
- cont = TRUE;
- }
-
- if (!cont)
- return FALSE;
-
- if (NT_SUCCESS(status = PhOpenProcess(
- &processHandle,
- PROCESS_DUP_HANDLE,
- ProcessId
- )))
- {
- ULONG i;
-
- for (i = 0; i < NumberOfHandles; i++)
- {
- status = NtDuplicateObject(
- processHandle,
- Handles[i]->Handle,
- NULL,
- NULL,
- 0,
- 0,
- DUPLICATE_CLOSE_SOURCE
- );
-
- if (!NT_SUCCESS(status))
- {
- success = FALSE;
-
- if (!PhpShowErrorHandle(
- hWnd,
- L"close",
- Handles[i],
- status,
- 0
- ))
- break;
- }
- }
-
- NtClose(processHandle);
- }
- else
- {
- PhShowStatus(hWnd, L"Unable to open the process", status, 0);
- return FALSE;
- }
-
- return success;
-}
-
-BOOLEAN PhUiSetAttributesHandle(
- _In_ HWND hWnd,
- _In_ HANDLE ProcessId,
- _In_ PPH_HANDLE_ITEM Handle,
- _In_ ULONG Attributes
- )
-{
- NTSTATUS status;
- HANDLE processHandle;
-
- if (!KphIsConnected())
- {
- PhShowError(hWnd, PH_KPH_ERROR_MESSAGE);
- return FALSE;
- }
-
- if (NT_SUCCESS(status = PhOpenProcess(
- &processHandle,
- ProcessQueryAccess,
- ProcessId
- )))
- {
- OBJECT_HANDLE_FLAG_INFORMATION handleFlagInfo;
-
- handleFlagInfo.Inherit = !!(Attributes & OBJ_INHERIT);
- handleFlagInfo.ProtectFromClose = !!(Attributes & OBJ_PROTECT_CLOSE);
-
- status = KphSetInformationObject(
- processHandle,
- Handle->Handle,
- KphObjectHandleFlagInformation,
- &handleFlagInfo,
- sizeof(OBJECT_HANDLE_FLAG_INFORMATION)
- );
-
- NtClose(processHandle);
- }
-
- if (!NT_SUCCESS(status))
- {
- PhpShowErrorHandle(hWnd, L"set attributes of", Handle, status, 0);
- return FALSE;
- }
-
- return TRUE;
-}
+/*
+ * Process Hacker -
+ * UI actions
+ *
+ * Copyright (C) 2010-2016 wj32
+ * Copyright (C) 2017-2018 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 .
+ */
+
+/*
+ * These are a set of consistent functions which will perform actions on objects such as processes,
+ * threads and services, while displaying any necessary prompts and error messages. Automatic
+ * elevation can also easily be added if necessary.
+ */
+
+#include
+#include
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static PWSTR DangerousProcesses[] =
+{
+ L"csrss.exe", L"dwm.exe", L"logonui.exe", L"lsass.exe", L"lsm.exe",
+ L"services.exe", L"smss.exe", L"wininit.exe", L"winlogon.exe"
+};
+
+static PPH_STRING DebuggerCommand = NULL;
+static ULONG PhSvcReferenceCount = 0;
+static PH_PHSVC_MODE PhSvcCurrentMode;
+static PH_QUEUED_LOCK PhSvcStartLock = PH_QUEUED_LOCK_INIT;
+
+HRESULT CALLBACK PhpElevateActionCallbackProc(
+ _In_ HWND hwnd,
+ _In_ UINT uNotification,
+ _In_ WPARAM wParam,
+ _In_ LPARAM lParam,
+ _In_ LONG_PTR dwRefData
+ )
+{
+ switch (uNotification)
+ {
+ case TDN_CREATED:
+ SendMessage(hwnd, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, IDYES, TRUE);
+ break;
+ }
+
+ return S_OK;
+}
+
+BOOLEAN PhpShowElevatePrompt(
+ _In_ HWND hWnd,
+ _In_ PWSTR Message,
+ _Out_ PINT Button
+ )
+{
+ TASKDIALOGCONFIG config = { sizeof(config) };
+ TASKDIALOG_BUTTON buttons[1];
+ INT button;
+
+ // Currently the error dialog box is similar to the one displayed
+ // when you try to label a drive in Windows Explorer. It's much better
+ // than the clunky dialog in PH 1.x.
+
+ config.hwndParent = hWnd;
+ config.hInstance = PhInstanceHandle;
+ config.dwFlags = IsWindowVisible(hWnd) ? TDF_POSITION_RELATIVE_TO_WINDOW : 0;
+ config.pszWindowTitle = PhApplicationName;
+ config.pszMainIcon = TD_ERROR_ICON;
+ config.pszMainInstruction = PhaConcatStrings2(Message, L".")->Buffer;
+ config.pszContent = L"You will need to provide administrator permission. "
+ L"Click Continue to complete this operation.";
+ config.dwCommonButtons = TDCBF_CANCEL_BUTTON;
+
+ buttons[0].nButtonID = IDYES;
+ buttons[0].pszButtonText = L"Continue";
+
+ config.cButtons = 1;
+ config.pButtons = buttons;
+ config.nDefaultButton = IDYES;
+
+ config.pfCallback = PhpElevateActionCallbackProc;
+
+ if (TaskDialogIndirect(
+ &config,
+ &button,
+ NULL,
+ NULL
+ ) == S_OK)
+ {
+ *Button = button;
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+/**
+ * Shows an error, prompts for elevation, and executes a command.
+ *
+ * \param hWnd The window to display user interface components on.
+ * \param Message A message describing the operation that failed.
+ * \param Status A NTSTATUS value.
+ * \param Command The arguments to pass to the new instance of
+ * the application, if required.
+ * \param Success A variable which receives TRUE if the elevated
+ * action succeeded or FALSE if the action failed.
+ *
+ * \return TRUE if the user was prompted for elevation, otherwise
+ * FALSE, in which case you need to show your own error message.
+ */
+BOOLEAN PhpShowErrorAndElevateAction(
+ _In_ HWND hWnd,
+ _In_ PWSTR Message,
+ _In_ NTSTATUS Status,
+ _In_ PWSTR Command,
+ _Out_ PBOOLEAN Success
+ )
+{
+ PH_ACTION_ELEVATION_LEVEL elevationLevel;
+ INT button = IDNO;
+
+ if (!(
+ Status == STATUS_ACCESS_DENIED ||
+ Status == STATUS_PRIVILEGE_NOT_HELD ||
+ (NT_NTWIN32(Status) && WIN32_FROM_NTSTATUS(Status) == ERROR_ACCESS_DENIED)
+ ))
+ return FALSE;
+
+ if (PhGetOwnTokenAttributes().Elevated)
+ return FALSE;
+
+ elevationLevel = PhGetIntegerSetting(L"ElevationLevel");
+
+ if (elevationLevel == NeverElevateAction)
+ return FALSE;
+
+ if (elevationLevel == PromptElevateAction)
+ {
+ if (!PhpShowElevatePrompt(hWnd, Message, &button))
+ return FALSE;
+ }
+
+ if (elevationLevel == AlwaysElevateAction || button == IDYES)
+ {
+ NTSTATUS status;
+ HANDLE processHandle;
+ LARGE_INTEGER timeout;
+ PROCESS_BASIC_INFORMATION basicInfo;
+
+ if (PhShellProcessHacker(
+ hWnd,
+ Command,
+ SW_SHOW,
+ PH_SHELL_EXECUTE_ADMIN,
+ PH_SHELL_APP_PROPAGATE_PARAMETERS,
+ 0,
+ &processHandle
+ ))
+ {
+ timeout.QuadPart = -(LONGLONG)UInt32x32To64(10, PH_TIMEOUT_SEC);
+ status = NtWaitForSingleObject(processHandle, FALSE, &timeout);
+
+ if (
+ status == STATUS_WAIT_0 &&
+ NT_SUCCESS(status = PhGetProcessBasicInformation(processHandle, &basicInfo))
+ )
+ {
+ status = basicInfo.ExitStatus;
+ }
+
+ NtClose(processHandle);
+
+ if (NT_SUCCESS(status))
+ {
+ *Success = TRUE;
+ }
+ else
+ {
+ *Success = FALSE;
+ PhShowStatus(hWnd, Message, status, 0);
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ * Shows an error, prompts for elevation, and connects to phsvc.
+ *
+ * \param hWnd The window to display user interface components on.
+ * \param Message A message describing the operation that failed.
+ * \param Status A NTSTATUS value.
+ * \param Connected A variable which receives TRUE if the user
+ * elevated the action and phsvc was started, or FALSE if the user
+ * cancelled elevation. If the value is TRUE, you need to
+ * perform any necessary phsvc calls and use PhUiDisconnectFromPhSvc()
+ * to disconnect from phsvc.
+ *
+ * \return TRUE if the user was prompted for elevation, otherwise
+ * FALSE, in which case you need to show your own error message.
+ */
+BOOLEAN PhpShowErrorAndConnectToPhSvc(
+ _In_ HWND hWnd,
+ _In_ PWSTR Message,
+ _In_ NTSTATUS Status,
+ _Out_ PBOOLEAN Connected
+ )
+{
+ PH_ACTION_ELEVATION_LEVEL elevationLevel;
+ INT button = IDNO;
+
+ *Connected = FALSE;
+
+ if (!(
+ Status == STATUS_ACCESS_DENIED ||
+ Status == STATUS_PRIVILEGE_NOT_HELD ||
+ (NT_NTWIN32(Status) && WIN32_FROM_NTSTATUS(Status) == ERROR_ACCESS_DENIED)
+ ))
+ return FALSE;
+
+ if (PhGetOwnTokenAttributes().Elevated)
+ return FALSE;
+
+ elevationLevel = PhGetIntegerSetting(L"ElevationLevel");
+
+ if (elevationLevel == NeverElevateAction)
+ return FALSE;
+
+ // Try to connect now so we can avoid prompting the user.
+ if (PhUiConnectToPhSvc(hWnd, TRUE))
+ {
+ *Connected = TRUE;
+ return TRUE;
+ }
+
+ if (elevationLevel == PromptElevateAction)
+ {
+ if (!PhpShowElevatePrompt(hWnd, Message, &button))
+ return FALSE;
+ }
+
+ if (elevationLevel == AlwaysElevateAction || button == IDYES)
+ {
+ *Connected = PhUiConnectToPhSvc(hWnd, FALSE);
+ }
+
+ return TRUE;
+}
+
+/**
+ * Connects to phsvc.
+ *
+ * \param hWnd The window to display user interface components on.
+ * \param ConnectOnly TRUE to only try to connect to phsvc, otherwise
+ * FALSE to try to elevate and start phsvc if the initial connection
+ * attempt failed.
+ */
+BOOLEAN PhUiConnectToPhSvc(
+ _In_opt_ HWND hWnd,
+ _In_ BOOLEAN ConnectOnly
+ )
+{
+ return PhUiConnectToPhSvcEx(hWnd, ElevatedPhSvcMode, ConnectOnly);
+}
+
+VOID PhpGetPhSvcPortName(
+ _In_ PH_PHSVC_MODE Mode,
+ _Out_ PUNICODE_STRING PortName
+ )
+{
+ switch (Mode)
+ {
+ case ElevatedPhSvcMode:
+ if (!PhIsExecutingInWow64())
+ RtlInitUnicodeString(PortName, PHSVC_PORT_NAME);
+ else
+ RtlInitUnicodeString(PortName, PHSVC_WOW64_PORT_NAME);
+ break;
+ case Wow64PhSvcMode:
+ RtlInitUnicodeString(PortName, PHSVC_WOW64_PORT_NAME);
+ break;
+ default:
+ PhRaiseStatus(STATUS_INVALID_PARAMETER);
+ break;
+ }
+}
+
+BOOLEAN PhpStartPhSvcProcess(
+ _In_opt_ HWND hWnd,
+ _In_ PH_PHSVC_MODE Mode
+ )
+{
+ switch (Mode)
+ {
+ case ElevatedPhSvcMode:
+ if (PhShellProcessHacker(
+ hWnd,
+ L"-phsvc",
+ SW_HIDE,
+ PH_SHELL_EXECUTE_ADMIN | PH_SHELL_EXECUTE_NOZONECHECKS,
+ PH_SHELL_APP_PROPAGATE_PARAMETERS,
+ 0,
+ NULL
+ ))
+ {
+ return TRUE;
+ }
+
+ break;
+ case Wow64PhSvcMode:
+ {
+ static PWSTR relativeFileNames[] =
+ {
+ L"\\x86\\ProcessHacker.exe",
+ L"\\..\\x86\\ProcessHacker.exe",
+#ifdef DEBUG
+ L"\\..\\Debug32\\ProcessHacker.exe",
+#endif
+ L"\\..\\Release32\\ProcessHacker.exe"
+ };
+
+ ULONG i;
+ PPH_STRING applicationDirectory;
+
+ if (!(applicationDirectory = PhGetApplicationDirectory()))
+ return FALSE;
+
+ for (i = 0; i < RTL_NUMBER_OF(relativeFileNames); i++)
+ {
+ PPH_STRING fileName;
+ PPH_STRING fileFullPath;
+
+ fileName = PhConcatStringRefZ(&applicationDirectory->sr, relativeFileNames[i]);
+
+ if (fileFullPath = PhGetFullPath(fileName->Buffer, NULL))
+ PhMoveReference(&fileName, fileFullPath);
+
+ if (PhDoesFileExistsWin32(fileName->Buffer))
+ {
+ if (PhShellProcessHackerEx(
+ hWnd,
+ fileName->Buffer,
+ L"-phsvc",
+ SW_HIDE,
+ PH_SHELL_EXECUTE_NOZONECHECKS,
+ PH_SHELL_APP_PROPAGATE_PARAMETERS,
+ 0,
+ NULL
+ ))
+ {
+ PhDereferenceObject(fileName);
+ PhDereferenceObject(applicationDirectory);
+ return TRUE;
+ }
+ }
+
+ PhDereferenceObject(fileName);
+ }
+
+ PhDereferenceObject(applicationDirectory);
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+/**
+ * Connects to phsvc.
+ *
+ * \param hWnd The window to display user interface components on.
+ * \param Mode The type of phsvc instance to connect to.
+ * \param ConnectOnly TRUE to only try to connect to phsvc, otherwise
+ * FALSE to try to elevate and start phsvc if the initial connection
+ * attempt failed.
+ */
+BOOLEAN PhUiConnectToPhSvcEx(
+ _In_opt_ HWND hWnd,
+ _In_ PH_PHSVC_MODE Mode,
+ _In_ BOOLEAN ConnectOnly
+ )
+{
+ NTSTATUS status;
+ BOOLEAN started;
+ UNICODE_STRING portName;
+
+ if (_InterlockedIncrementNoZero(&PhSvcReferenceCount))
+ {
+ if (PhSvcCurrentMode == Mode)
+ {
+ started = TRUE;
+ }
+ else
+ {
+ _InterlockedDecrement(&PhSvcReferenceCount);
+ started = FALSE;
+ }
+ }
+ else
+ {
+ PhAcquireQueuedLockExclusive(&PhSvcStartLock);
+
+ if (_InterlockedExchange(&PhSvcReferenceCount, 0) == 0)
+ {
+ started = FALSE;
+ PhpGetPhSvcPortName(Mode, &portName);
+
+ // Try to connect first, then start the server if we failed.
+ status = PhSvcConnectToServer(&portName, 0);
+
+ if (NT_SUCCESS(status))
+ {
+ started = TRUE;
+ PhSvcCurrentMode = Mode;
+ _InterlockedIncrement(&PhSvcReferenceCount);
+ }
+ else if (!ConnectOnly)
+ {
+ // Prompt for elevation, and then try to connect to the server.
+
+ if (PhpStartPhSvcProcess(hWnd, Mode))
+ started = TRUE;
+
+ if (started)
+ {
+ ULONG attempts = 50;
+
+ // Try to connect several times because the server may take
+ // a while to initialize.
+ do
+ {
+ status = PhSvcConnectToServer(&portName, 0);
+
+ if (NT_SUCCESS(status))
+ break;
+
+ PhDelayExecution(100);
+
+ } while (--attempts != 0);
+
+ // Increment the reference count even if we failed.
+ // We don't want to prompt the user again.
+
+ PhSvcCurrentMode = Mode;
+ _InterlockedIncrement(&PhSvcReferenceCount);
+ }
+ }
+ }
+ else
+ {
+ if (PhSvcCurrentMode == Mode)
+ {
+ started = TRUE;
+ _InterlockedIncrement(&PhSvcReferenceCount);
+ }
+ else
+ {
+ started = FALSE;
+ }
+ }
+
+ PhReleaseQueuedLockExclusive(&PhSvcStartLock);
+ }
+
+ return started;
+}
+
+/**
+ * Disconnects from phsvc.
+ */
+VOID PhUiDisconnectFromPhSvc(
+ VOID
+ )
+{
+ PhAcquireQueuedLockExclusive(&PhSvcStartLock);
+
+ if (_InterlockedDecrement(&PhSvcReferenceCount) == 0)
+ {
+ PhSvcDisconnectFromServer();
+ }
+
+ PhReleaseQueuedLockExclusive(&PhSvcStartLock);
+}
+
+BOOLEAN PhUiLockComputer(
+ _In_ HWND hWnd
+ )
+{
+ if (LockWorkStation())
+ return TRUE;
+ else
+ PhShowStatus(hWnd, L"Unable to lock the computer.", 0, GetLastError());
+
+ return FALSE;
+}
+
+BOOLEAN PhUiLogoffComputer(
+ _In_ HWND hWnd
+ )
+{
+ if (ExitWindowsEx(EWX_LOGOFF, 0))
+ return TRUE;
+ else
+ PhShowStatus(hWnd, L"Unable to log off the computer.", 0, GetLastError());
+
+ return FALSE;
+}
+
+BOOLEAN PhUiSleepComputer(
+ _In_ HWND hWnd
+ )
+{
+ NTSTATUS status;
+
+ if (NT_SUCCESS(status = NtInitiatePowerAction(
+ PowerActionSleep,
+ PowerSystemSleeping1,
+ 0,
+ FALSE
+ )))
+ return TRUE;
+ else
+ PhShowStatus(hWnd, L"Unable to sleep the computer.", status, 0);
+
+ return FALSE;
+}
+
+BOOLEAN PhUiHibernateComputer(
+ _In_ HWND hWnd
+ )
+{
+ NTSTATUS status;
+
+ if (NT_SUCCESS(status = NtInitiatePowerAction(
+ PowerActionHibernate,
+ PowerSystemSleeping1,
+ 0,
+ FALSE
+ )))
+ return TRUE;
+ else
+ PhShowStatus(hWnd, L"Unable to hibernate the computer.", status, 0);
+
+ return FALSE;
+}
+
+BOOLEAN PhUiRestartComputer(
+ _In_ HWND hWnd,
+ _In_ ULONG Flags
+ )
+{
+ NTSTATUS status;
+ BOOLEAN forceShutdown;
+
+ // Taskmgr prior to Windows 8 included a feature to force shutdown via NT instead of CSRSS
+ // when holding the control key. (dmex)
+ forceShutdown = !!(GetKeyState(VK_CONTROL) < 0);
+
+ if (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage(
+ hWnd,
+ L"restart",
+ L"the computer",
+ NULL,
+ FALSE
+ ))
+ {
+ if (forceShutdown)
+ {
+ if (!NT_SUCCESS(status = NtShutdownSystem(ShutdownReboot)))
+ {
+ PhShowStatus(hWnd, L"Unable to restart the computer.", status, 0);
+ }
+ }
+ else
+ {
+ if (ExitWindowsEx(EWX_REBOOT | Flags, 0))
+ return TRUE;
+ else
+ PhShowStatus(hWnd, L"Unable to restart the computer.", 0, GetLastError());
+ }
+ }
+
+ return FALSE;
+}
+
+BOOLEAN PhUiShutdownComputer(
+ _In_ HWND hWnd,
+ _In_ ULONG Flags
+ )
+{
+ NTSTATUS status;
+ BOOLEAN forceShutdown;
+
+ // Taskmgr prior to Windows 8 included a feature to force shutdown via NT instead of CSRSS
+ // when holding the control key. (dmex)
+ forceShutdown = !!(GetKeyState(VK_CONTROL) < 0);
+
+ if (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage(
+ hWnd,
+ L"shut down",
+ L"the computer",
+ NULL,
+ FALSE
+ ))
+ {
+ if (forceShutdown)
+ {
+ if (!NT_SUCCESS(status = NtShutdownSystem(ShutdownPowerOff)))
+ {
+ PhShowStatus(hWnd, L"Unable to shut down the computer.", status, 0);
+ }
+ }
+ else
+ {
+ if (ExitWindowsEx(EWX_POWEROFF | Flags, 0))
+ {
+ return TRUE;
+ }
+ else if (ExitWindowsEx(EWX_SHUTDOWN | Flags, 0))
+ {
+ return TRUE;
+ }
+ else
+ {
+ PhShowStatus(hWnd, L"Unable to shut down the computer.", 0, GetLastError());
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+BOOLEAN PhUiConnectSession(
+ _In_ HWND hWnd,
+ _In_ ULONG SessionId
+ )
+{
+ BOOLEAN success = FALSE;
+ PPH_STRING selectedChoice = NULL;
+ PPH_STRING oldSelectedChoice = NULL;
+
+ // Try once with no password.
+ if (WinStationConnectW(NULL, SessionId, LOGONID_CURRENT, L"", TRUE))
+ return TRUE;
+
+ while (PhaChoiceDialog(
+ hWnd,
+ L"Connect to session",
+ L"Password:",
+ NULL,
+ 0,
+ NULL,
+ PH_CHOICE_DIALOG_PASSWORD,
+ &selectedChoice,
+ NULL,
+ NULL
+ ))
+ {
+ if (oldSelectedChoice)
+ {
+ RtlSecureZeroMemory(oldSelectedChoice->Buffer, oldSelectedChoice->Length);
+ PhDereferenceObject(oldSelectedChoice);
+ }
+
+ oldSelectedChoice = selectedChoice;
+
+ if (WinStationConnectW(NULL, SessionId, LOGONID_CURRENT, selectedChoice->Buffer, TRUE))
+ {
+ success = TRUE;
+ break;
+ }
+ else
+ {
+ if (!PhShowContinueStatus(hWnd, L"Unable to connect to the session", 0, GetLastError()))
+ break;
+ }
+ }
+
+ if (oldSelectedChoice)
+ {
+ RtlSecureZeroMemory(oldSelectedChoice->Buffer, oldSelectedChoice->Length);
+ PhDereferenceObject(oldSelectedChoice);
+ }
+
+ return success;
+}
+
+BOOLEAN PhUiDisconnectSession(
+ _In_ HWND hWnd,
+ _In_ ULONG SessionId
+ )
+{
+ if (WinStationDisconnect(NULL, SessionId, FALSE))
+ return TRUE;
+ else
+ PhShowStatus(hWnd, L"Unable to disconnect the session", 0, GetLastError());
+
+ return FALSE;
+}
+
+BOOLEAN PhUiLogoffSession(
+ _In_ HWND hWnd,
+ _In_ ULONG SessionId
+ )
+{
+ if (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage(
+ hWnd,
+ L"logoff",
+ L"the user",
+ NULL,
+ FALSE
+ ))
+ {
+ if (WinStationReset(NULL, SessionId, FALSE))
+ return TRUE;
+ else
+ PhShowStatus(hWnd, L"Unable to logoff the session", 0, GetLastError());
+ }
+
+ return FALSE;
+}
+
+/**
+ * Determines if a process is a system process.
+ *
+ * \param ProcessId The PID of the process to check.
+ */
+static BOOLEAN PhpIsDangerousProcess(
+ _In_ HANDLE ProcessId
+ )
+{
+ NTSTATUS status;
+ PPH_STRING fileName;
+ PPH_STRING systemDirectory;
+ ULONG i;
+
+ if (ProcessId == SYSTEM_PROCESS_ID)
+ return TRUE;
+
+ if (!NT_SUCCESS(status = PhGetProcessImageFileNameByProcessId(ProcessId, &fileName)))
+ return FALSE;
+
+ PhMoveReference(&fileName, PhGetFileName(fileName));
+ PH_AUTO(fileName);
+
+ systemDirectory = PH_AUTO(PhGetSystemDirectory());
+
+ for (i = 0; i < sizeof(DangerousProcesses) / sizeof(PWSTR); i++)
+ {
+ PPH_STRING fullName;
+
+ fullName = PhaConcatStrings(3, systemDirectory->Buffer, L"\\", DangerousProcesses[i]);
+
+ if (PhEqualString(fileName, fullName, TRUE))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * Checks if the user wants to proceed with an operation.
+ *
+ * \param hWnd A handle to the parent window.
+ * \param Verb A verb describing the action.
+ * \param Message A message containing additional information
+ * about the action.
+ * \param WarnOnlyIfDangerous TRUE to skip the confirmation
+ * dialog if none of the processes are system processes,
+ * FALSE to always show the confirmation dialog.
+ * \param Processes An array of pointers to process items.
+ * \param NumberOfProcesses The number of process items.
+ *
+ * \return TRUE if the user wants to proceed with the operation,
+ * otherwise FALSE.
+ */
+static BOOLEAN PhpShowContinueMessageProcesses(
+ _In_ HWND hWnd,
+ _In_ PWSTR Verb,
+ _In_opt_ PWSTR Message,
+ _In_ BOOLEAN WarnOnlyIfDangerous,
+ _In_ PPH_PROCESS_ITEM *Processes,
+ _In_ ULONG NumberOfProcesses
+ )
+{
+ PWSTR object;
+ ULONG i;
+ BOOLEAN critical = FALSE;
+ BOOLEAN dangerous = FALSE;
+ BOOLEAN cont = FALSE;
+
+ if (NumberOfProcesses == 0)
+ return FALSE;
+
+ for (i = 0; i < NumberOfProcesses; i++)
+ {
+ HANDLE processHandle;
+ BOOLEAN breakOnTermination = FALSE;
+
+ if (PhpIsDangerousProcess(Processes[i]->ProcessId))
+ {
+ critical = TRUE;
+ dangerous = TRUE;
+ break;
+ }
+
+ if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_INFORMATION, Processes[i]->ProcessId)))
+ {
+ PhGetProcessBreakOnTermination(processHandle, &breakOnTermination);
+ NtClose(processHandle);
+ }
+
+ if (breakOnTermination)
+ {
+ critical = TRUE;
+ dangerous = TRUE;
+ break;
+ }
+ }
+
+ if (WarnOnlyIfDangerous && !dangerous)
+ return TRUE;
+
+ if (PhGetIntegerSetting(L"EnableWarnings"))
+ {
+ if (NumberOfProcesses == 1)
+ {
+ object = Processes[0]->ProcessName->Buffer;
+ }
+ else if (NumberOfProcesses == 2)
+ {
+ object = PhaConcatStrings(
+ 3,
+ Processes[0]->ProcessName->Buffer,
+ L" and ",
+ Processes[1]->ProcessName->Buffer
+ )->Buffer;
+ }
+ else
+ {
+ object = L"the selected processes";
+ }
+
+ if (!dangerous)
+ {
+ cont = PhShowConfirmMessage(
+ hWnd,
+ Verb,
+ object,
+ Message,
+ FALSE
+ );
+ }
+ else if (!critical)
+ {
+ cont = PhShowConfirmMessage(
+ hWnd,
+ Verb,
+ object,
+ PhaConcatStrings(
+ 3,
+ L"You are about to ",
+ Verb,
+ L" one or more system processes."
+ )->Buffer,
+ TRUE
+ );
+ }
+ else
+ {
+ PPH_STRING message;
+
+ if (PhEqualStringZ(Verb, L"terminate", FALSE))
+ {
+ message = PhaConcatStrings(
+ 3,
+ L"You are about to ",
+ Verb,
+ L" one or more critical processes. This will shut down the operating system immediately."
+ );
+ }
+ else
+ {
+ message = PhaConcatStrings(
+ 3,
+ L"You are about to ",
+ Verb,
+ L" one or more critical processes."
+ );
+ }
+
+ cont = PhShowConfirmMessage(
+ hWnd,
+ Verb,
+ object,
+ message->Buffer,
+ TRUE
+ );
+ }
+ }
+ else
+ {
+ cont = TRUE;
+ }
+
+ return cont;
+}
+
+/**
+ * Shows an error message to the user and checks
+ * if the user wants to continue.
+ *
+ * \param hWnd A handle to the parent window.
+ * \param Verb A verb describing the action which
+ * resulted in an error.
+ * \param Process The process item which the action
+ * was performed on.
+ * \param Status A NT status value representing the
+ * error.
+ * \param Win32Result A Win32 error code representing
+ * the error.
+ *
+ * \return TRUE if the user wants to continue, otherwise
+ * FALSE. The result is typically only useful when
+ * executing an action on multiple processes.
+ */
+static BOOLEAN PhpShowErrorProcess(
+ _In_ HWND hWnd,
+ _In_ PWSTR Verb,
+ _In_ PPH_PROCESS_ITEM Process,
+ _In_ NTSTATUS Status,
+ _In_opt_ ULONG Win32Result
+ )
+{
+ if (!PH_IS_FAKE_PROCESS_ID(Process->ProcessId))
+ {
+ return PhShowContinueStatus(
+ hWnd,
+ PhaFormatString(
+ L"Unable to %s %s (PID %lu)",
+ Verb,
+ Process->ProcessName->Buffer,
+ HandleToUlong(Process->ProcessId)
+ )->Buffer,
+ Status,
+ Win32Result
+ );
+ }
+ else
+ {
+ return PhShowContinueStatus(
+ hWnd,
+ PhaFormatString(
+ L"Unable to %s %s",
+ Verb,
+ Process->ProcessName->Buffer
+ )->Buffer,
+ Status,
+ Win32Result
+ );
+ }
+}
+
+BOOLEAN PhUiTerminateProcesses(
+ _In_ HWND hWnd,
+ _In_ PPH_PROCESS_ITEM *Processes,
+ _In_ ULONG NumberOfProcesses
+ )
+{
+ BOOLEAN success = TRUE;
+ BOOLEAN cancelled = FALSE;
+ ULONG i;
+
+ if (!PhpShowContinueMessageProcesses(
+ hWnd,
+ L"terminate",
+ L"Terminating a process will cause unsaved data to be lost.",
+ FALSE,
+ Processes,
+ NumberOfProcesses
+ ))
+ return FALSE;
+
+ for (i = 0; i < NumberOfProcesses; i++)
+ {
+ NTSTATUS status;
+ HANDLE processHandle;
+
+ if (NT_SUCCESS(status = PhOpenProcess(
+ &processHandle,
+ PROCESS_TERMINATE,
+ Processes[i]->ProcessId
+ )))
+ {
+ // An exit status of 1 is used here for compatibility reasons:
+ // 1. Both Task Manager and Process Explorer use 1.
+ // 2. winlogon tries to restart explorer.exe if the exit status is not 1.
+
+ status = PhTerminateProcess(processHandle, 1);
+ NtClose(processHandle);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ BOOLEAN connected;
+
+ success = FALSE;
+
+ if (!cancelled && PhpShowErrorAndConnectToPhSvc(
+ hWnd,
+ PhaConcatStrings2(L"Unable to terminate ", Processes[i]->ProcessName->Buffer)->Buffer,
+ status,
+ &connected
+ ))
+ {
+ if (connected)
+ {
+ if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessTerminate, 0)))
+ success = TRUE;
+ else
+ PhpShowErrorProcess(hWnd, L"terminate", Processes[i], status, 0);
+
+ PhUiDisconnectFromPhSvc();
+ }
+ else
+ {
+ cancelled = TRUE;
+ }
+ }
+ else
+ {
+ if (!PhpShowErrorProcess(hWnd, L"terminate", Processes[i], status, 0))
+ break;
+ }
+ }
+ }
+
+ return success;
+}
+
+BOOLEAN PhpUiTerminateTreeProcess(
+ _In_ HWND hWnd,
+ _In_ PPH_PROCESS_ITEM Process,
+ _In_ PVOID Processes,
+ _Inout_ PBOOLEAN Success
+ )
+{
+ NTSTATUS status;
+ PSYSTEM_PROCESS_INFORMATION process;
+ HANDLE processHandle;
+ PPH_PROCESS_ITEM processItem;
+
+ // Note:
+ // FALSE should be written to Success if any part of the operation failed.
+ // The return value of this function indicates whether to continue with
+ // the operation (FALSE if user cancelled).
+
+ // Terminate the process.
+
+ if (NT_SUCCESS(status = PhOpenProcess(
+ &processHandle,
+ PROCESS_TERMINATE,
+ Process->ProcessId
+ )))
+ {
+ status = PhTerminateProcess(processHandle, 1);
+ NtClose(processHandle);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ *Success = FALSE;
+
+ if (!PhpShowErrorProcess(hWnd, L"terminate", Process, status, 0))
+ return FALSE;
+ }
+
+ // Terminate the process' children.
+
+ process = PH_FIRST_PROCESS(Processes);
+
+ do
+ {
+ if (process->UniqueProcessId != Process->ProcessId &&
+ process->InheritedFromUniqueProcessId == Process->ProcessId)
+ {
+ if (processItem = PhReferenceProcessItem(process->UniqueProcessId))
+ {
+ if (WindowsVersion >= WINDOWS_10_RS3)
+ {
+ // Check the sequence number to make sure it is a descendant.
+ if (processItem->ProcessSequenceNumber >= Process->ProcessSequenceNumber)
+ {
+ if (!PhpUiTerminateTreeProcess(hWnd, processItem, Processes, Success))
+ {
+ PhDereferenceObject(processItem);
+ return FALSE;
+ }
+ }
+ }
+ else
+ {
+ // Check the creation time to make sure it is a descendant.
+ if (processItem->CreateTime.QuadPart >= Process->CreateTime.QuadPart)
+ {
+ if (!PhpUiTerminateTreeProcess(hWnd, processItem, Processes, Success))
+ {
+ PhDereferenceObject(processItem);
+ return FALSE;
+ }
+ }
+ }
+
+ PhDereferenceObject(processItem);
+ }
+ }
+ } while (process = PH_NEXT_PROCESS(process));
+
+ return TRUE;
+}
+
+BOOLEAN PhUiTerminateTreeProcess(
+ _In_ HWND hWnd,
+ _In_ PPH_PROCESS_ITEM Process
+ )
+{
+ NTSTATUS status;
+ BOOLEAN success = TRUE;
+ BOOLEAN cont = FALSE;
+ PVOID processes;
+
+ if (PhGetIntegerSetting(L"EnableWarnings"))
+ {
+ cont = PhShowConfirmMessage(
+ hWnd,
+ L"terminate",
+ PhaConcatStrings2(Process->ProcessName->Buffer, L" and its descendants")->Buffer,
+ L"Terminating a process tree will cause the process and its descendants to be terminated.",
+ FALSE
+ );
+ }
+ else
+ {
+ cont = TRUE;
+ }
+
+ if (!cont)
+ return FALSE;
+
+ if (!NT_SUCCESS(status = PhEnumProcesses(&processes)))
+ {
+ PhShowStatus(hWnd, L"Unable to enumerate processes", status, 0);
+ return FALSE;
+ }
+
+ PhpUiTerminateTreeProcess(hWnd, Process, processes, &success);
+ PhFree(processes);
+
+ return success;
+}
+
+BOOLEAN PhUiSuspendProcesses(
+ _In_ HWND hWnd,
+ _In_ PPH_PROCESS_ITEM *Processes,
+ _In_ ULONG NumberOfProcesses
+ )
+{
+ BOOLEAN success = TRUE;
+ BOOLEAN cancelled = FALSE;
+ ULONG i;
+
+ if (!PhpShowContinueMessageProcesses(
+ hWnd,
+ L"suspend",
+ NULL,
+ TRUE,
+ Processes,
+ NumberOfProcesses
+ ))
+ return FALSE;
+
+ for (i = 0; i < NumberOfProcesses; i++)
+ {
+ NTSTATUS status;
+ HANDLE processHandle;
+
+ if (NT_SUCCESS(status = PhOpenProcess(
+ &processHandle,
+ PROCESS_SUSPEND_RESUME,
+ Processes[i]->ProcessId
+ )))
+ {
+ status = NtSuspendProcess(processHandle);
+ NtClose(processHandle);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ BOOLEAN connected;
+
+ success = FALSE;
+
+ if (!cancelled && PhpShowErrorAndConnectToPhSvc(
+ hWnd,
+ PhaConcatStrings2(L"Unable to suspend ", Processes[i]->ProcessName->Buffer)->Buffer,
+ status,
+ &connected
+ ))
+ {
+ if (connected)
+ {
+ if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessSuspend, 0)))
+ success = TRUE;
+ else
+ PhpShowErrorProcess(hWnd, L"suspend", Processes[i], status, 0);
+
+ PhUiDisconnectFromPhSvc();
+ }
+ else
+ {
+ cancelled = TRUE;
+ }
+ }
+ else
+ {
+ if (!PhpShowErrorProcess(hWnd, L"suspend", Processes[i], status, 0))
+ break;
+ }
+ }
+ }
+
+ return success;
+}
+
+BOOLEAN PhUiResumeProcesses(
+ _In_ HWND hWnd,
+ _In_ PPH_PROCESS_ITEM *Processes,
+ _In_ ULONG NumberOfProcesses
+ )
+{
+ BOOLEAN success = TRUE;
+ BOOLEAN cancelled = FALSE;
+ ULONG i;
+
+ if (!PhpShowContinueMessageProcesses(
+ hWnd,
+ L"resume",
+ NULL,
+ TRUE,
+ Processes,
+ NumberOfProcesses
+ ))
+ return FALSE;
+
+ for (i = 0; i < NumberOfProcesses; i++)
+ {
+ NTSTATUS status;
+ HANDLE processHandle;
+
+ if (NT_SUCCESS(status = PhOpenProcess(
+ &processHandle,
+ PROCESS_SUSPEND_RESUME,
+ Processes[i]->ProcessId
+ )))
+ {
+ status = NtResumeProcess(processHandle);
+ NtClose(processHandle);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ BOOLEAN connected;
+
+ success = FALSE;
+
+ if (!cancelled && PhpShowErrorAndConnectToPhSvc(
+ hWnd,
+ PhaConcatStrings2(L"Unable to resume ", Processes[i]->ProcessName->Buffer)->Buffer,
+ status,
+ &connected
+ ))
+ {
+ if (connected)
+ {
+ if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessResume, 0)))
+ success = TRUE;
+ else
+ PhpShowErrorProcess(hWnd, L"resume", Processes[i], status, 0);
+
+ PhUiDisconnectFromPhSvc();
+ }
+ else
+ {
+ cancelled = TRUE;
+ }
+ }
+ else
+ {
+ if (!PhpShowErrorProcess(hWnd, L"resume", Processes[i], status, 0))
+ break;
+ }
+ }
+ }
+
+ return success;
+}
+
+BOOLEAN PhUiRestartProcess(
+ _In_ HWND hWnd,
+ _In_ PPH_PROCESS_ITEM Process
+ )
+{
+ NTSTATUS status;
+ BOOLEAN cont = FALSE;
+ HANDLE processHandle = NULL;
+ PPH_STRING commandLine;
+ PPH_STRING currentDirectory;
+
+ if (PhGetIntegerSetting(L"EnableWarnings"))
+ {
+ cont = PhShowConfirmMessage(
+ hWnd,
+ L"restart",
+ Process->ProcessName->Buffer,
+ L"The process will be restarted with the same command line and "
+ L"working directory, but if it is running under a different user it "
+ L"will be restarted under the current user.",
+ FALSE
+ );
+ }
+ else
+ {
+ cont = TRUE;
+ }
+
+ if (!cont)
+ return FALSE;
+
+ // Open the process and get the command line and current directory.
+
+ if (!NT_SUCCESS(status = PhOpenProcess(
+ &processHandle,
+ PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ,
+ Process->ProcessId
+ )))
+ goto ErrorExit;
+
+ if (!NT_SUCCESS(status = PhGetProcessCommandLine(
+ processHandle,
+ &commandLine
+ )))
+ goto ErrorExit;
+
+ PH_AUTO(commandLine);
+
+ if (!NT_SUCCESS(status = PhGetProcessPebString(
+ processHandle,
+ PhpoCurrentDirectory,
+ ¤tDirectory
+ )))
+ goto ErrorExit;
+
+ PH_AUTO(currentDirectory);
+
+ NtClose(processHandle);
+ processHandle = NULL;
+
+ // Open the process and terminate it.
+
+ if (!NT_SUCCESS(status = PhOpenProcess(
+ &processHandle,
+ PROCESS_TERMINATE,
+ Process->ProcessId
+ )))
+ goto ErrorExit;
+
+ if (!NT_SUCCESS(status = PhTerminateProcess(
+ processHandle,
+ 1
+ )))
+ goto ErrorExit;
+
+ NtClose(processHandle);
+ processHandle = NULL;
+
+ // Start the process.
+
+ status = PhCreateProcessWin32(
+ PhGetString(Process->FileName), // we didn't wait for S1 processing
+ commandLine->Buffer,
+ NULL,
+ currentDirectory->Buffer,
+ 0,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ErrorExit:
+ if (processHandle)
+ NtClose(processHandle);
+
+ if (!NT_SUCCESS(status))
+ {
+ PhpShowErrorProcess(hWnd, L"restart", Process, status, 0);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+// Contributed by evilpie (#2981421)
+BOOLEAN PhUiDebugProcess(
+ _In_ HWND hWnd,
+ _In_ PPH_PROCESS_ITEM Process
+ )
+{
+ static PH_STRINGREF aeDebugKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug");
+#ifdef _WIN64
+ static PH_STRINGREF aeDebugWow64KeyName = PH_STRINGREF_INIT(L"Software\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug");
+#endif
+ NTSTATUS status;
+ BOOLEAN cont = FALSE;
+ PH_STRING_BUILDER commandLineBuilder;
+ HANDLE keyHandle;
+ PPH_STRING debugger;
+ PH_STRINGREF commandPart;
+ PH_STRINGREF dummy;
+
+ if (PhGetIntegerSetting(L"EnableWarnings"))
+ {
+ cont = PhShowConfirmMessage(
+ hWnd,
+ L"debug",
+ Process->ProcessName->Buffer,
+ L"Debugging a process may result in loss of data.",
+ FALSE
+ );
+ }
+ else
+ {
+ cont = TRUE;
+ }
+
+ if (!cont)
+ return FALSE;
+
+ status = PhOpenKey(
+ &keyHandle,
+ KEY_READ,
+ PH_KEY_LOCAL_MACHINE,
+#ifdef _WIN64
+ Process->IsWow64 ? &aeDebugWow64KeyName : &aeDebugKeyName,
+#else
+ &aeDebugKeyName,
+#endif
+ 0
+ );
+
+ if (NT_SUCCESS(status))
+ {
+ if (debugger = PH_AUTO(PhQueryRegistryString(keyHandle, L"Debugger")))
+ {
+ if (PhSplitStringRefAtChar(&debugger->sr, '"', &dummy, &commandPart) &&
+ PhSplitStringRefAtChar(&commandPart, '"', &commandPart, &dummy))
+ {
+ DebuggerCommand = PhCreateString2(&commandPart);
+ }
+ }
+
+ NtClose(keyHandle);
+ }
+
+ if (PhIsNullOrEmptyString(DebuggerCommand))
+ {
+ PhShowError(hWnd, L"Unable to locate the debugger.");
+ return FALSE;
+ }
+
+ PhInitializeStringBuilder(&commandLineBuilder, DebuggerCommand->Length + 30);
+
+ PhAppendCharStringBuilder(&commandLineBuilder, '"');
+ PhAppendStringBuilder(&commandLineBuilder, &DebuggerCommand->sr);
+ PhAppendCharStringBuilder(&commandLineBuilder, '"');
+ PhAppendFormatStringBuilder(&commandLineBuilder, L" -p %lu", HandleToUlong(Process->ProcessId));
+
+ status = PhCreateProcessWin32(
+ NULL,
+ commandLineBuilder.String->Buffer,
+ NULL,
+ NULL,
+ 0,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ PhDeleteStringBuilder(&commandLineBuilder);
+
+ if (!NT_SUCCESS(status))
+ {
+ PhpShowErrorProcess(hWnd, L"debug", Process, status, 0);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN PhUiReduceWorkingSetProcesses(
+ _In_ HWND hWnd,
+ _In_ PPH_PROCESS_ITEM *Processes,
+ _In_ ULONG NumberOfProcesses
+ )
+{
+ BOOLEAN success = TRUE;
+ ULONG i;
+
+ for (i = 0; i < NumberOfProcesses; i++)
+ {
+ NTSTATUS status;
+ HANDLE processHandle;
+
+ if (NT_SUCCESS(status = PhOpenProcess(
+ &processHandle,
+ PROCESS_SET_QUOTA,
+ Processes[i]->ProcessId
+ )))
+ {
+ QUOTA_LIMITS quotaLimits;
+
+ memset("aLimits, 0, sizeof(QUOTA_LIMITS));
+ quotaLimits.MinimumWorkingSetSize = -1;
+ quotaLimits.MaximumWorkingSetSize = -1;
+
+ status = PhSetProcessQuotaLimits(processHandle, quotaLimits);
+
+ NtClose(processHandle);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ success = FALSE;
+
+ if (!PhpShowErrorProcess(hWnd, L"reduce the working set of", Processes[i], status, 0))
+ break;
+ }
+ }
+
+ return success;
+}
+
+BOOLEAN PhUiSetVirtualizationProcess(
+ _In_ HWND hWnd,
+ _In_ PPH_PROCESS_ITEM Process,
+ _In_ BOOLEAN Enable
+ )
+{
+ NTSTATUS status;
+ BOOLEAN cont = FALSE;
+ HANDLE processHandle;
+ HANDLE tokenHandle;
+
+ if (PhGetIntegerSetting(L"EnableWarnings"))
+ {
+ cont = PhShowConfirmMessage(
+ hWnd,
+ L"set",
+ L"virtualization for the process",
+ L"Enabling or disabling virtualization for a process may "
+ L"alter its functionality and produce undesirable effects.",
+ FALSE
+ );
+ }
+ else
+ {
+ cont = TRUE;
+ }
+
+ if (!cont)
+ return FALSE;
+
+ if (NT_SUCCESS(status = PhOpenProcess(
+ &processHandle,
+ PROCESS_QUERY_LIMITED_INFORMATION,
+ Process->ProcessId
+ )))
+ {
+ if (NT_SUCCESS(status = PhOpenProcessToken(
+ processHandle,
+ TOKEN_WRITE,
+ &tokenHandle
+ )))
+ {
+ status = PhSetTokenIsVirtualizationEnabled(tokenHandle, Enable);
+ NtClose(tokenHandle);
+ }
+
+ NtClose(processHandle);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ PhpShowErrorProcess(hWnd, L"set virtualization for", Process, status, 0);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN PhUiSetCriticalProcess(
+ _In_ HWND WindowHandle,
+ _In_ PPH_PROCESS_ITEM Process
+ )
+{
+ NTSTATUS status;
+ HANDLE processHandle;
+ BOOLEAN breakOnTermination;
+
+ status = PhOpenProcess(
+ &processHandle,
+ PROCESS_QUERY_INFORMATION | PROCESS_SET_INFORMATION,
+ Process->ProcessId
+ );
+
+ if (NT_SUCCESS(status))
+ {
+ status = PhGetProcessBreakOnTermination(
+ processHandle,
+ &breakOnTermination
+ );
+
+ if (NT_SUCCESS(status))
+ {
+ if (!breakOnTermination && (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage(
+ WindowHandle,
+ L"enable",
+ L"critical status on the process",
+ L"If the process ends, the operating system will shut down immediately.",
+ TRUE
+ )))
+ {
+ status = PhSetProcessBreakOnTermination(processHandle, TRUE);
+ }
+ else if (breakOnTermination && (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage(
+ WindowHandle,
+ L"disable",
+ L"critical status on the process",
+ NULL,
+ FALSE
+ )))
+ {
+ status = PhSetProcessBreakOnTermination(processHandle, FALSE);
+ }
+ }
+
+ NtClose(processHandle);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ PhpShowErrorProcess(WindowHandle, L"set critical status", Process, status, 0);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN PhUiDetachFromDebuggerProcess(
+ _In_ HWND hWnd,
+ _In_ PPH_PROCESS_ITEM Process
+ )
+{
+ NTSTATUS status;
+ HANDLE processHandle;
+ HANDLE debugObjectHandle;
+
+ if (NT_SUCCESS(status = PhOpenProcess(
+ &processHandle,
+ PROCESS_QUERY_INFORMATION | PROCESS_SUSPEND_RESUME,
+ Process->ProcessId
+ )))
+ {
+ if (NT_SUCCESS(status = PhGetProcessDebugObject(
+ processHandle,
+ &debugObjectHandle
+ )))
+ {
+ // Disable kill-on-close.
+ if (NT_SUCCESS(status = PhSetDebugKillProcessOnExit(
+ debugObjectHandle,
+ FALSE
+ )))
+ {
+ status = NtRemoveProcessDebug(processHandle, debugObjectHandle);
+ }
+
+ NtClose(debugObjectHandle);
+ }
+
+ NtClose(processHandle);
+ }
+
+ if (status == STATUS_PORT_NOT_SET)
+ {
+ PhShowInformation2(hWnd, L"The process is not being debugged.", L"");
+ return FALSE;
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ PhpShowErrorProcess(hWnd, L"detach debugger from", Process, status, 0);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN PhUiLoadDllProcess(
+ _In_ HWND hWnd,
+ _In_ PPH_PROCESS_ITEM Process
+ )
+{
+ static PH_FILETYPE_FILTER filters[] =
+ {
+ { L"DLL files (*.dll)", L"*.dll" },
+ { L"All files (*.*)", L"*.*" }
+ };
+
+ NTSTATUS status;
+ PVOID fileDialog;
+ PPH_STRING fileName;
+ HANDLE processHandle;
+
+ fileDialog = PhCreateOpenFileDialog();
+ PhSetFileDialogFilter(fileDialog, filters, RTL_NUMBER_OF(filters));
+
+ if (!PhShowFileDialog(hWnd, fileDialog))
+ {
+ PhFreeFileDialog(fileDialog);
+ return FALSE;
+ }
+
+ fileName = PH_AUTO(PhGetFileDialogFileName(fileDialog));
+ PhFreeFileDialog(fileDialog);
+
+ if (NT_SUCCESS(status = PhOpenProcess(
+ &processHandle,
+ PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION |
+ PROCESS_VM_READ | PROCESS_VM_WRITE,
+ Process->ProcessId
+ )))
+ {
+ LARGE_INTEGER timeout;
+
+ timeout.QuadPart = -(LONGLONG)UInt32x32To64(5, PH_TIMEOUT_SEC);
+ status = PhLoadDllProcess(
+ processHandle,
+ fileName->Buffer,
+ &timeout
+ );
+
+ NtClose(processHandle);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ PhpShowErrorProcess(hWnd, L"load the DLL into", Process, status, 0);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN PhUiSetIoPriorityProcesses(
+ _In_ HWND hWnd,
+ _In_ PPH_PROCESS_ITEM *Processes,
+ _In_ ULONG NumberOfProcesses,
+ _In_ IO_PRIORITY_HINT IoPriority
+ )
+{
+ BOOLEAN success = TRUE;
+ BOOLEAN cancelled = FALSE;
+ ULONG i;
+
+ for (i = 0; i < NumberOfProcesses; i++)
+ {
+ NTSTATUS status;
+ HANDLE processHandle;
+
+ if (NT_SUCCESS(status = PhOpenProcess(
+ &processHandle,
+ PROCESS_SET_INFORMATION,
+ Processes[i]->ProcessId
+ )))
+ {
+ if (Processes[i]->ProcessId != SYSTEM_PROCESS_ID)
+ {
+ status = PhSetProcessIoPriority(processHandle, IoPriority);
+ }
+ else
+ {
+ // See comment in PhUiSetPriorityProcesses.
+ status = STATUS_UNSUCCESSFUL;
+ }
+
+ NtClose(processHandle);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ BOOLEAN connected;
+
+ success = FALSE;
+
+ // The operation may have failed due to the lack of SeIncreaseBasePriorityPrivilege.
+ if (!cancelled && PhpShowErrorAndConnectToPhSvc(
+ hWnd,
+ PhaConcatStrings2(L"Unable to set the I/O priority of ", Processes[i]->ProcessName->Buffer)->Buffer,
+ status,
+ &connected
+ ))
+ {
+ if (connected)
+ {
+ if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessIoPriority, IoPriority)))
+ success = TRUE;
+ else
+ PhpShowErrorProcess(hWnd, L"set the I/O priority of", Processes[i], status, 0);
+
+ PhUiDisconnectFromPhSvc();
+ }
+ else
+ {
+ cancelled = TRUE;
+ }
+ }
+ else
+ {
+ if (!PhpShowErrorProcess(hWnd, L"set the I/O priority of", Processes[i], status, 0))
+ break;
+ }
+ }
+ }
+
+ return success;
+}
+
+BOOLEAN PhUiSetPagePriorityProcess(
+ _In_ HWND hWnd,
+ _In_ PPH_PROCESS_ITEM Process,
+ _In_ ULONG PagePriority
+ )
+{
+ NTSTATUS status;
+ HANDLE processHandle;
+
+ if (NT_SUCCESS(status = PhOpenProcess(
+ &processHandle,
+ PROCESS_SET_INFORMATION,
+ Process->ProcessId
+ )))
+ {
+ if (Process->ProcessId != SYSTEM_PROCESS_ID)
+ {
+ status = PhSetProcessPagePriority(processHandle, PagePriority);
+ }
+ else
+ {
+ // See comment in PhUiSetPriorityProcesses.
+ status = STATUS_UNSUCCESSFUL;
+ }
+
+ NtClose(processHandle);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ PhpShowErrorProcess(hWnd, L"set the page priority of", Process, status, 0);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN PhUiSetPriorityProcesses(
+ _In_ HWND hWnd,
+ _In_ PPH_PROCESS_ITEM *Processes,
+ _In_ ULONG NumberOfProcesses,
+ _In_ ULONG PriorityClass
+ )
+{
+ BOOLEAN success = TRUE;
+ BOOLEAN cancelled = FALSE;
+ ULONG i;
+
+ for (i = 0; i < NumberOfProcesses; i++)
+ {
+ NTSTATUS status;
+ HANDLE processHandle;
+
+ if (NT_SUCCESS(status = PhOpenProcess(
+ &processHandle,
+ PROCESS_SET_INFORMATION,
+ Processes[i]->ProcessId
+ )))
+ {
+ if (Processes[i]->ProcessId != SYSTEM_PROCESS_ID)
+ {
+ PROCESS_PRIORITY_CLASS priorityClass;
+
+ priorityClass.Foreground = FALSE;
+ priorityClass.PriorityClass = (UCHAR)PriorityClass;
+
+ status = PhSetProcessPriority(processHandle, priorityClass);
+ }
+ else
+ {
+ // Changing the priority of System can lead to a BSOD on some versions of Windows,
+ // so disallow this.
+ status = STATUS_UNSUCCESSFUL;
+ }
+
+ NtClose(processHandle);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ BOOLEAN connected;
+
+ success = FALSE;
+
+ // The operation may have failed due to the lack of SeIncreaseBasePriorityPrivilege.
+ if (!cancelled && PhpShowErrorAndConnectToPhSvc(
+ hWnd,
+ PhaConcatStrings2(L"Unable to set the priority of ", Processes[i]->ProcessName->Buffer)->Buffer,
+ status,
+ &connected
+ ))
+ {
+ if (connected)
+ {
+ if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessPriority, PriorityClass)))
+ success = TRUE;
+ else
+ PhpShowErrorProcess(hWnd, L"set the priority of", Processes[i], status, 0);
+
+ PhUiDisconnectFromPhSvc();
+ }
+ else
+ {
+ cancelled = TRUE;
+ }
+ }
+ else
+ {
+ if (!PhpShowErrorProcess(hWnd, L"set the priority of", Processes[i], status, 0))
+ break;
+ }
+ }
+ }
+
+ return success;
+}
+
+static VOID PhpShowErrorService(
+ _In_ HWND hWnd,
+ _In_ PWSTR Verb,
+ _In_ PPH_SERVICE_ITEM Service,
+ _In_ NTSTATUS Status,
+ _In_opt_ ULONG Win32Result
+ )
+{
+ PhShowStatus(
+ hWnd,
+ PhaFormatString(
+ L"Unable to %s %s.",
+ Verb,
+ Service->Name->Buffer
+ )->Buffer,
+ Status,
+ Win32Result
+ );
+}
+
+BOOLEAN PhUiStartService(
+ _In_ HWND hWnd,
+ _In_ PPH_SERVICE_ITEM Service
+ )
+{
+ SC_HANDLE serviceHandle;
+ BOOLEAN success = FALSE;
+
+ serviceHandle = PhOpenService(Service->Name->Buffer, SERVICE_START);
+
+ if (serviceHandle)
+ {
+ if (StartService(serviceHandle, 0, NULL))
+ success = TRUE;
+
+ CloseServiceHandle(serviceHandle);
+ }
+
+ if (!success)
+ {
+ NTSTATUS status;
+ BOOLEAN connected;
+
+ status = PhGetLastWin32ErrorAsNtStatus();
+
+ if (PhpShowErrorAndConnectToPhSvc(
+ hWnd,
+ PhaConcatStrings2(L"Unable to start ", Service->Name->Buffer)->Buffer,
+ status,
+ &connected
+ ))
+ {
+ if (connected)
+ {
+ if (NT_SUCCESS(status = PhSvcCallControlService(Service->Name->Buffer, PhSvcControlServiceStart)))
+ success = TRUE;
+ else
+ PhpShowErrorService(hWnd, L"start", Service, status, 0);
+
+ PhUiDisconnectFromPhSvc();
+ }
+ }
+ else
+ {
+ PhpShowErrorService(hWnd, L"start", Service, status, 0);
+ }
+ }
+
+ return success;
+}
+
+BOOLEAN PhUiContinueService(
+ _In_ HWND hWnd,
+ _In_ PPH_SERVICE_ITEM Service
+ )
+{
+ SC_HANDLE serviceHandle;
+ BOOLEAN success = FALSE;
+
+ serviceHandle = PhOpenService(Service->Name->Buffer, SERVICE_PAUSE_CONTINUE);
+
+ if (serviceHandle)
+ {
+ SERVICE_STATUS serviceStatus;
+
+ if (ControlService(serviceHandle, SERVICE_CONTROL_CONTINUE, &serviceStatus))
+ success = TRUE;
+
+ CloseServiceHandle(serviceHandle);
+ }
+
+ if (!success)
+ {
+ NTSTATUS status;
+ BOOLEAN connected;
+
+ status = PhGetLastWin32ErrorAsNtStatus();
+
+ if (PhpShowErrorAndConnectToPhSvc(
+ hWnd,
+ PhaConcatStrings2(L"Unable to continue ", Service->Name->Buffer)->Buffer,
+ status,
+ &connected
+ ))
+ {
+ if (connected)
+ {
+ if (NT_SUCCESS(status = PhSvcCallControlService(Service->Name->Buffer, PhSvcControlServiceContinue)))
+ success = TRUE;
+ else
+ PhpShowErrorService(hWnd, L"continue", Service, status, 0);
+
+ PhUiDisconnectFromPhSvc();
+ }
+ }
+ else
+ {
+ PhpShowErrorService(hWnd, L"continue", Service, status, 0);
+ }
+ }
+
+ return success;
+}
+
+BOOLEAN PhUiPauseService(
+ _In_ HWND hWnd,
+ _In_ PPH_SERVICE_ITEM Service
+ )
+{
+ SC_HANDLE serviceHandle;
+ BOOLEAN success = FALSE;
+
+ serviceHandle = PhOpenService(Service->Name->Buffer, SERVICE_PAUSE_CONTINUE);
+
+ if (serviceHandle)
+ {
+ SERVICE_STATUS serviceStatus;
+
+ if (ControlService(serviceHandle, SERVICE_CONTROL_PAUSE, &serviceStatus))
+ success = TRUE;
+
+ CloseServiceHandle(serviceHandle);
+ }
+
+ if (!success)
+ {
+ NTSTATUS status;
+ BOOLEAN connected;
+
+ status = PhGetLastWin32ErrorAsNtStatus();
+
+ if (PhpShowErrorAndConnectToPhSvc(
+ hWnd,
+ PhaConcatStrings2(L"Unable to pause ", Service->Name->Buffer)->Buffer,
+ status,
+ &connected
+ ))
+ {
+ if (connected)
+ {
+ if (NT_SUCCESS(status = PhSvcCallControlService(Service->Name->Buffer, PhSvcControlServicePause)))
+ success = TRUE;
+ else
+ PhpShowErrorService(hWnd, L"pause", Service, status, 0);
+
+ PhUiDisconnectFromPhSvc();
+ }
+ }
+ else
+ {
+ PhpShowErrorService(hWnd, L"pause", Service, status, 0);
+ }
+ }
+
+ return success;
+}
+
+BOOLEAN PhUiStopService(
+ _In_ HWND hWnd,
+ _In_ PPH_SERVICE_ITEM Service
+ )
+{
+ SC_HANDLE serviceHandle;
+ BOOLEAN success = FALSE;
+
+ serviceHandle = PhOpenService(Service->Name->Buffer, SERVICE_STOP);
+
+ if (serviceHandle)
+ {
+ SERVICE_STATUS serviceStatus;
+
+ if (ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus))
+ success = TRUE;
+
+ CloseServiceHandle(serviceHandle);
+ }
+
+ if (!success)
+ {
+ NTSTATUS status;
+ BOOLEAN connected;
+
+ status = PhGetLastWin32ErrorAsNtStatus();
+
+ if (PhpShowErrorAndConnectToPhSvc(
+ hWnd,
+ PhaConcatStrings2(L"Unable to stop ", Service->Name->Buffer)->Buffer,
+ status,
+ &connected
+ ))
+ {
+ if (connected)
+ {
+ if (NT_SUCCESS(status = PhSvcCallControlService(Service->Name->Buffer, PhSvcControlServiceStop)))
+ success = TRUE;
+ else
+ PhpShowErrorService(hWnd, L"stop", Service, status, 0);
+
+ PhUiDisconnectFromPhSvc();
+ }
+ }
+ else
+ {
+ PhpShowErrorService(hWnd, L"stop", Service, status, 0);
+ }
+ }
+
+ return success;
+}
+
+BOOLEAN PhUiDeleteService(
+ _In_ HWND hWnd,
+ _In_ PPH_SERVICE_ITEM Service
+ )
+{
+ SC_HANDLE serviceHandle;
+ BOOLEAN success = FALSE;
+
+ // Warnings cannot be disabled for service deletion.
+ if (!PhShowConfirmMessage(
+ hWnd,
+ L"delete",
+ Service->Name->Buffer,
+ L"Deleting a service can prevent the system from starting "
+ L"or functioning properly.",
+ TRUE
+ ))
+ return FALSE;
+
+ serviceHandle = PhOpenService(Service->Name->Buffer, DELETE);
+
+ if (serviceHandle)
+ {
+ if (DeleteService(serviceHandle))
+ success = TRUE;
+
+ CloseServiceHandle(serviceHandle);
+ }
+
+ if (!success)
+ {
+ NTSTATUS status;
+ BOOLEAN connected;
+
+ status = PhGetLastWin32ErrorAsNtStatus();
+
+ if (PhpShowErrorAndConnectToPhSvc(
+ hWnd,
+ PhaConcatStrings2(L"Unable to delete ", Service->Name->Buffer)->Buffer,
+ status,
+ &connected
+ ))
+ {
+ if (connected)
+ {
+ if (NT_SUCCESS(status = PhSvcCallControlService(Service->Name->Buffer, PhSvcControlServiceDelete)))
+ success = TRUE;
+ else
+ PhpShowErrorService(hWnd, L"delete", Service, status, 0);
+
+ PhUiDisconnectFromPhSvc();
+ }
+ }
+ else
+ {
+ PhpShowErrorService(hWnd, L"delete", Service, status, 0);
+ }
+ }
+
+ return success;
+}
+
+BOOLEAN PhUiCloseConnections(
+ _In_ HWND hWnd,
+ _In_ PPH_NETWORK_ITEM *Connections,
+ _In_ ULONG NumberOfConnections
+ )
+{
+
+ BOOLEAN success = TRUE;
+ BOOLEAN cancelled = FALSE;
+ ULONG result;
+ ULONG i;
+ MIB_TCPROW tcpRow;
+
+ for (i = 0; i < NumberOfConnections; i++)
+ {
+ if (
+ Connections[i]->ProtocolType != PH_TCP4_NETWORK_PROTOCOL ||
+ Connections[i]->State != MIB_TCP_STATE_ESTAB
+ )
+ continue;
+
+ tcpRow.dwState = MIB_TCP_STATE_DELETE_TCB;
+ tcpRow.dwLocalAddr = Connections[i]->LocalEndpoint.Address.Ipv4;
+ tcpRow.dwLocalPort = _byteswap_ushort((USHORT)Connections[i]->LocalEndpoint.Port);
+ tcpRow.dwRemoteAddr = Connections[i]->RemoteEndpoint.Address.Ipv4;
+ tcpRow.dwRemotePort = _byteswap_ushort((USHORT)Connections[i]->RemoteEndpoint.Port);
+
+ if ((result = SetTcpEntry(&tcpRow)) != NO_ERROR)
+ {
+ NTSTATUS status;
+ BOOLEAN connected;
+
+ success = FALSE;
+
+ // SetTcpEntry returns ERROR_MR_MID_NOT_FOUND for access denied errors for some reason.
+ if (result == ERROR_MR_MID_NOT_FOUND)
+ result = ERROR_ACCESS_DENIED;
+
+ if (!cancelled && PhpShowErrorAndConnectToPhSvc(
+ hWnd,
+ L"Unable to close the TCP connection",
+ NTSTATUS_FROM_WIN32(result),
+ &connected
+ ))
+ {
+ if (connected)
+ {
+ if (NT_SUCCESS(status = PhSvcCallSetTcpEntry(&tcpRow)))
+ success = TRUE;
+ else
+ PhShowStatus(hWnd, L"Unable to close the TCP connection", status, 0);
+
+ PhUiDisconnectFromPhSvc();
+ }
+ else
+ {
+ cancelled = TRUE;
+ }
+ }
+ else
+ {
+ if (PhShowMessage2(
+ hWnd,
+ TDCBF_OK_BUTTON,
+ TD_ERROR_ICON,
+ L"Unable to close the TCP connection.",
+ L"Make sure Process Hacker is running with administrative privileges."
+ ) != IDOK)
+ break;
+ }
+ }
+ }
+
+ return success;
+}
+
+static BOOLEAN PhpShowContinueMessageThreads(
+ _In_ HWND hWnd,
+ _In_ PWSTR Verb,
+ _In_ PWSTR Message,
+ _In_ BOOLEAN Warning,
+ _In_ PPH_THREAD_ITEM *Threads,
+ _In_ ULONG NumberOfThreads
+ )
+{
+ PWSTR object;
+ BOOLEAN cont = FALSE;
+
+ if (NumberOfThreads == 0)
+ return FALSE;
+
+ if (PhGetIntegerSetting(L"EnableWarnings"))
+ {
+ if (NumberOfThreads == 1)
+ {
+ object = L"the selected thread";
+ }
+ else
+ {
+ object = L"the selected threads";
+ }
+
+ cont = PhShowConfirmMessage(
+ hWnd,
+ Verb,
+ object,
+ Message,
+ Warning
+ );
+ }
+ else
+ {
+ cont = TRUE;
+ }
+
+ return cont;
+}
+
+static BOOLEAN PhpShowErrorThread(
+ _In_ HWND hWnd,
+ _In_ PWSTR Verb,
+ _In_ PPH_THREAD_ITEM Thread,
+ _In_ NTSTATUS Status,
+ _In_opt_ ULONG Win32Result
+ )
+{
+ return PhShowContinueStatus(
+ hWnd,
+ PhaFormatString(
+ L"Unable to %s thread %lu",
+ Verb,
+ HandleToUlong(Thread->ThreadId)
+ )->Buffer,
+ Status,
+ Win32Result
+ );
+}
+
+BOOLEAN PhUiTerminateThreads(
+ _In_ HWND hWnd,
+ _In_ PPH_THREAD_ITEM *Threads,
+ _In_ ULONG NumberOfThreads
+ )
+{
+ BOOLEAN success = TRUE;
+ BOOLEAN cancelled = FALSE;
+ ULONG i;
+
+ if (!PhpShowContinueMessageThreads(
+ hWnd,
+ L"terminate",
+ L"Terminating a thread may cause the process to stop working.",
+ FALSE,
+ Threads,
+ NumberOfThreads
+ ))
+ return FALSE;
+
+ for (i = 0; i < NumberOfThreads; i++)
+ {
+ NTSTATUS status;
+ HANDLE threadHandle;
+
+ if (NT_SUCCESS(status = PhOpenThread(
+ &threadHandle,
+ THREAD_TERMINATE,
+ Threads[i]->ThreadId
+ )))
+ {
+ status = NtTerminateThread(threadHandle, STATUS_SUCCESS);
+ NtClose(threadHandle);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ BOOLEAN connected;
+
+ success = FALSE;
+
+ if (!cancelled && PhpShowErrorAndConnectToPhSvc(
+ hWnd,
+ PhaFormatString(L"Unable to terminate thread %lu", HandleToUlong(Threads[i]->ThreadId))->Buffer,
+ status,
+ &connected
+ ))
+ {
+ if (connected)
+ {
+ if (NT_SUCCESS(status = PhSvcCallControlThread(Threads[i]->ThreadId, PhSvcControlThreadTerminate, 0)))
+ success = TRUE;
+ else
+ PhpShowErrorThread(hWnd, L"terminate", Threads[i], status, 0);
+
+ PhUiDisconnectFromPhSvc();
+ }
+ else
+ {
+ cancelled = TRUE;
+ }
+ }
+ else
+ {
+ if (!PhpShowErrorThread(hWnd, L"terminate", Threads[i], status, 0))
+ break;
+ }
+ }
+ }
+
+ return success;
+}
+
+BOOLEAN PhUiSuspendThreads(
+ _In_ HWND hWnd,
+ _In_ PPH_THREAD_ITEM *Threads,
+ _In_ ULONG NumberOfThreads
+ )
+{
+ BOOLEAN success = TRUE;
+ BOOLEAN cancelled = FALSE;
+ ULONG i;
+
+ for (i = 0; i < NumberOfThreads; i++)
+ {
+ NTSTATUS status;
+ HANDLE threadHandle;
+
+ if (NT_SUCCESS(status = PhOpenThread(
+ &threadHandle,
+ THREAD_SUSPEND_RESUME,
+ Threads[i]->ThreadId
+ )))
+ {
+ status = NtSuspendThread(threadHandle, NULL);
+ NtClose(threadHandle);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ BOOLEAN connected;
+
+ success = FALSE;
+
+ if (!cancelled && PhpShowErrorAndConnectToPhSvc(
+ hWnd,
+ PhaFormatString(L"Unable to suspend thread %lu", HandleToUlong(Threads[i]->ThreadId))->Buffer,
+ status,
+ &connected
+ ))
+ {
+ if (connected)
+ {
+ if (NT_SUCCESS(status = PhSvcCallControlThread(Threads[i]->ThreadId, PhSvcControlThreadSuspend, 0)))
+ success = TRUE;
+ else
+ PhpShowErrorThread(hWnd, L"suspend", Threads[i], status, 0);
+
+ PhUiDisconnectFromPhSvc();
+ }
+ else
+ {
+ cancelled = TRUE;
+ }
+ }
+ else
+ {
+ if (!PhpShowErrorThread(hWnd, L"suspend", Threads[i], status, 0))
+ break;
+ }
+ }
+ }
+
+ return success;
+}
+
+BOOLEAN PhUiResumeThreads(
+ _In_ HWND hWnd,
+ _In_ PPH_THREAD_ITEM *Threads,
+ _In_ ULONG NumberOfThreads
+ )
+{
+ BOOLEAN success = TRUE;
+ BOOLEAN cancelled = FALSE;
+ ULONG i;
+
+ for (i = 0; i < NumberOfThreads; i++)
+ {
+ NTSTATUS status;
+ HANDLE threadHandle;
+
+ if (NT_SUCCESS(status = PhOpenThread(
+ &threadHandle,
+ THREAD_SUSPEND_RESUME,
+ Threads[i]->ThreadId
+ )))
+ {
+ status = NtResumeThread(threadHandle, NULL);
+ NtClose(threadHandle);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ BOOLEAN connected;
+
+ success = FALSE;
+
+ if (!cancelled && PhpShowErrorAndConnectToPhSvc(
+ hWnd,
+ PhaFormatString(L"Unable to resume thread %lu", HandleToUlong(Threads[i]->ThreadId))->Buffer,
+ status,
+ &connected
+ ))
+ {
+ if (connected)
+ {
+ if (NT_SUCCESS(status = PhSvcCallControlThread(Threads[i]->ThreadId, PhSvcControlThreadResume, 0)))
+ success = TRUE;
+ else
+ PhpShowErrorThread(hWnd, L"resume", Threads[i], status, 0);
+
+ PhUiDisconnectFromPhSvc();
+ }
+ else
+ {
+ cancelled = TRUE;
+ }
+ }
+ else
+ {
+ if (!PhpShowErrorThread(hWnd, L"resume", Threads[i], status, 0))
+ break;
+ }
+ }
+ }
+
+ return success;
+}
+
+BOOLEAN PhUiSetPriorityThread(
+ _In_ HWND hWnd,
+ _In_ PPH_THREAD_ITEM Thread,
+ _In_ LONG Increment
+ )
+{
+ NTSTATUS status;
+ HANDLE threadHandle;
+
+ // Special saturation values
+ if (Increment == THREAD_PRIORITY_TIME_CRITICAL)
+ Increment = THREAD_BASE_PRIORITY_LOWRT + 1;
+ else if (Increment == THREAD_PRIORITY_IDLE)
+ Increment = THREAD_BASE_PRIORITY_IDLE - 1;
+
+ if (NT_SUCCESS(status = PhOpenThread(
+ &threadHandle,
+ THREAD_SET_LIMITED_INFORMATION,
+ Thread->ThreadId
+ )))
+ {
+ status = PhSetThreadBasePriority(threadHandle, Increment);
+ NtClose(threadHandle);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ PhpShowErrorThread(hWnd, L"set the priority of", Thread, status, 0);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN PhUiSetIoPriorityThread(
+ _In_ HWND hWnd,
+ _In_ PPH_THREAD_ITEM Thread,
+ _In_ IO_PRIORITY_HINT IoPriority
+ )
+{
+ NTSTATUS status;
+ BOOLEAN success = TRUE;
+ HANDLE threadHandle;
+
+ if (NT_SUCCESS(status = PhOpenThread(
+ &threadHandle,
+ THREAD_SET_INFORMATION,
+ Thread->ThreadId
+ )))
+ {
+ status = PhSetThreadIoPriority(threadHandle, IoPriority);
+ NtClose(threadHandle);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ BOOLEAN connected;
+
+ success = FALSE;
+
+ // The operation may have failed due to the lack of SeIncreaseBasePriorityPrivilege.
+ if (PhpShowErrorAndConnectToPhSvc(
+ hWnd,
+ PhaFormatString(L"Unable to set the I/O priority of thread %lu", HandleToUlong(Thread->ThreadId))->Buffer,
+ status,
+ &connected
+ ))
+ {
+ if (connected)
+ {
+ if (NT_SUCCESS(status = PhSvcCallControlThread(Thread->ThreadId, PhSvcControlThreadIoPriority, IoPriority)))
+ success = TRUE;
+ else
+ PhpShowErrorThread(hWnd, L"set the I/O priority of", Thread, status, 0);
+
+ PhUiDisconnectFromPhSvc();
+ }
+ }
+ else
+ {
+ PhpShowErrorThread(hWnd, L"set the I/O priority of", Thread, status, 0);
+ }
+ }
+
+ return success;
+}
+
+BOOLEAN PhUiSetPagePriorityThread(
+ _In_ HWND hWnd,
+ _In_ PPH_THREAD_ITEM Thread,
+ _In_ ULONG PagePriority
+ )
+{
+ NTSTATUS status;
+ HANDLE threadHandle;
+
+ if (NT_SUCCESS(status = PhOpenThread(
+ &threadHandle,
+ THREAD_SET_INFORMATION,
+ Thread->ThreadId
+ )))
+ {
+ status = PhSetThreadPagePriority(threadHandle, PagePriority);
+
+ NtClose(threadHandle);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ PhpShowErrorThread(hWnd, L"set the page priority of", Thread, status, 0);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN PhUiUnloadModule(
+ _In_ HWND hWnd,
+ _In_ HANDLE ProcessId,
+ _In_ PPH_MODULE_ITEM Module
+ )
+{
+ NTSTATUS status;
+ BOOLEAN cont = FALSE;
+ HANDLE processHandle;
+
+ if (PhGetIntegerSetting(L"EnableWarnings"))
+ {
+ PWSTR verb;
+ PWSTR message;
+
+ switch (Module->Type)
+ {
+ case PH_MODULE_TYPE_MODULE:
+ case PH_MODULE_TYPE_WOW64_MODULE:
+ verb = L"unload";
+ message = L"Unloading a module may cause the process to crash.";
+
+ if (WindowsVersion >= WINDOWS_8)
+ message = L"Unloading a module may cause the process to crash. NOTE: This feature may not work correctly on your version of Windows and some programs may restrict access or ban your account.";
+
+ break;
+ case PH_MODULE_TYPE_KERNEL_MODULE:
+ verb = L"unload";
+ message = L"Unloading a driver may cause system instability.";
+ break;
+ case PH_MODULE_TYPE_MAPPED_FILE:
+ case PH_MODULE_TYPE_MAPPED_IMAGE:
+ verb = L"unmap";
+ message = L"Unmapping a section view may cause the process to crash.";
+ break;
+ default:
+ return FALSE;
+ }
+
+ cont = PhShowConfirmMessage(
+ hWnd,
+ verb,
+ Module->Name->Buffer,
+ message,
+ TRUE
+ );
+ }
+ else
+ {
+ cont = TRUE;
+ }
+
+ if (!cont)
+ return FALSE;
+
+ switch (Module->Type)
+ {
+ case PH_MODULE_TYPE_MODULE:
+ case PH_MODULE_TYPE_WOW64_MODULE:
+ if (NT_SUCCESS(status = PhOpenProcess(
+ &processHandle,
+ PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION |
+ PROCESS_VM_READ | PROCESS_VM_WRITE,
+ ProcessId
+ )))
+ {
+ LARGE_INTEGER timeout;
+
+ timeout.QuadPart = -(LONGLONG)UInt32x32To64(5, PH_TIMEOUT_SEC);
+ status = PhUnloadDllProcess(
+ processHandle,
+ Module->BaseAddress,
+ &timeout
+ );
+
+ NtClose(processHandle);
+ }
+
+ if (status == STATUS_DLL_NOT_FOUND)
+ {
+ PhShowError(hWnd, L"Unable to find the module to unload.");
+ return FALSE;
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ PhShowStatus(
+ hWnd,
+ PhaConcatStrings2(L"Unable to unload ", Module->Name->Buffer)->Buffer,
+ status,
+ 0
+ );
+ return FALSE;
+ }
+
+ break;
+
+ case PH_MODULE_TYPE_KERNEL_MODULE:
+ status = PhUnloadDriver(Module->BaseAddress, Module->Name->Buffer);
+
+ if (!NT_SUCCESS(status))
+ {
+ BOOLEAN success = FALSE;
+ BOOLEAN connected;
+
+ if (PhpShowErrorAndConnectToPhSvc(
+ hWnd,
+ PhaConcatStrings2(L"Unable to unload ", Module->Name->Buffer)->Buffer,
+ status,
+ &connected
+ ))
+ {
+ if (connected)
+ {
+ if (NT_SUCCESS(status = PhSvcCallUnloadDriver(Module->BaseAddress, Module->Name->Buffer)))
+ success = TRUE;
+ else
+ PhShowStatus(hWnd, PhaConcatStrings2(L"Unable to unload ", Module->Name->Buffer)->Buffer, status, 0);
+
+ PhUiDisconnectFromPhSvc();
+ }
+ }
+ else
+ {
+ PhShowStatus(
+ hWnd,
+ PhaConcatStrings(
+ 3,
+ L"Unable to unload ",
+ Module->Name->Buffer,
+ L". Make sure Process Hacker is running with "
+ L"administrative privileges."
+ )->Buffer,
+ status,
+ 0
+ );
+ return FALSE;
+ }
+
+ return success;
+ }
+
+ break;
+
+ case PH_MODULE_TYPE_MAPPED_FILE:
+ case PH_MODULE_TYPE_MAPPED_IMAGE:
+ if (NT_SUCCESS(status = PhOpenProcess(
+ &processHandle,
+ PROCESS_VM_OPERATION,
+ ProcessId
+ )))
+ {
+ status = NtUnmapViewOfSection(processHandle, Module->BaseAddress);
+ NtClose(processHandle);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ PhShowStatus(
+ hWnd,
+ PhaFormatString(L"Unable to unmap the section view at 0x%Ix", Module->BaseAddress)->Buffer,
+ status,
+ 0
+ );
+ return FALSE;
+ }
+
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN PhUiFreeMemory(
+ _In_ HWND hWnd,
+ _In_ HANDLE ProcessId,
+ _In_ PPH_MEMORY_ITEM MemoryItem,
+ _In_ BOOLEAN Free
+ )
+{
+ NTSTATUS status;
+ BOOLEAN cont = FALSE;
+ HANDLE processHandle;
+
+ if (PhGetIntegerSetting(L"EnableWarnings"))
+ {
+ PWSTR verb;
+ PWSTR message;
+
+ if (!(MemoryItem->Type & (MEM_MAPPED | MEM_IMAGE)))
+ {
+ if (Free)
+ {
+ verb = L"free";
+ message = L"Freeing memory regions may cause the process to crash.\r\n\r\nSome programs may also restrict access or ban your account when freeing the memory of the process.";
+ }
+ else
+ {
+ verb = L"decommit";
+ message = L"Decommitting memory regions may cause the process to crash.\r\n\r\nSome programs may also restrict access or ban your account when decommitting the memory of the process.";
+ }
+ }
+ else
+ {
+ verb = L"unmap";
+ message = L"Unmapping a section view may cause the process to crash.\r\n\r\nSome programs may also restrict access or ban your account when unmapping the memory of the process.";
+ }
+
+ cont = PhShowConfirmMessage(
+ hWnd,
+ verb,
+ L"the memory region",
+ message,
+ TRUE
+ );
+ }
+ else
+ {
+ cont = TRUE;
+ }
+
+ if (!cont)
+ return FALSE;
+
+ if (NT_SUCCESS(status = PhOpenProcess(
+ &processHandle,
+ PROCESS_VM_OPERATION,
+ ProcessId
+ )))
+ {
+ PVOID baseAddress;
+ SIZE_T regionSize;
+
+ baseAddress = MemoryItem->BaseAddress;
+
+ if (!(MemoryItem->Type & (MEM_MAPPED | MEM_IMAGE)))
+ {
+ // The size needs to be 0 if we're freeing.
+ if (Free)
+ regionSize = 0;
+ else
+ regionSize = MemoryItem->RegionSize;
+
+ status = NtFreeVirtualMemory(
+ processHandle,
+ &baseAddress,
+ ®ionSize,
+ Free ? MEM_RELEASE : MEM_DECOMMIT
+ );
+ }
+ else
+ {
+ status = NtUnmapViewOfSection(processHandle, baseAddress);
+ }
+
+ NtClose(processHandle);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ PWSTR message;
+
+ if (!(MemoryItem->Type & (MEM_MAPPED | MEM_IMAGE)))
+ {
+ if (Free)
+ message = L"Unable to free the memory region";
+ else
+ message = L"Unable to decommit the memory region";
+ }
+ else
+ {
+ message = L"Unable to unmap the section view";
+ }
+
+ PhShowStatus(
+ hWnd,
+ message,
+ status,
+ 0
+ );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static BOOLEAN PhpShowErrorHandle(
+ _In_ HWND hWnd,
+ _In_ PWSTR Verb,
+ _In_ PPH_HANDLE_ITEM Handle,
+ _In_ NTSTATUS Status,
+ _In_opt_ ULONG Win32Result
+ )
+{
+ if (!PhIsNullOrEmptyString(Handle->BestObjectName))
+ {
+ return PhShowContinueStatus(
+ hWnd,
+ PhaFormatString(
+ L"Unable to %s handle \"%s\" (0x%Ix)",
+ Verb,
+ Handle->BestObjectName->Buffer,
+ HandleToUlong(Handle->Handle)
+ )->Buffer,
+ Status,
+ Win32Result
+ );
+ }
+ else
+ {
+ return PhShowContinueStatus(
+ hWnd,
+ PhaFormatString(
+ L"Unable to %s handle 0x%Ix",
+ Verb,
+ HandleToUlong(Handle->Handle)
+ )->Buffer,
+ Status,
+ Win32Result
+ );
+ }
+}
+
+BOOLEAN PhUiCloseHandles(
+ _In_ HWND hWnd,
+ _In_ HANDLE ProcessId,
+ _In_ PPH_HANDLE_ITEM *Handles,
+ _In_ ULONG NumberOfHandles,
+ _In_ BOOLEAN Warn
+ )
+{
+ NTSTATUS status;
+ BOOLEAN cont = FALSE;
+ BOOLEAN success = TRUE;
+ HANDLE processHandle;
+
+ if (NumberOfHandles == 0)
+ return FALSE;
+
+ if (Warn && PhGetIntegerSetting(L"EnableWarnings"))
+ {
+ cont = PhShowConfirmMessage(
+ hWnd,
+ L"close",
+ NumberOfHandles == 1 ? L"the selected handle" : L"the selected handles",
+ L"Closing handles may cause system instability and data corruption.",
+ FALSE
+ );
+ }
+ else
+ {
+ cont = TRUE;
+ }
+
+ if (!cont)
+ return FALSE;
+
+ if (NT_SUCCESS(status = PhOpenProcess(
+ &processHandle,
+ PROCESS_QUERY_INFORMATION | PROCESS_DUP_HANDLE,
+ ProcessId
+ )))
+ {
+ BOOLEAN critical = FALSE;
+ BOOLEAN strict = FALSE;
+
+ if (WindowsVersion >= WINDOWS_10)
+ {
+ BOOLEAN breakOnTermination;
+ PROCESS_MITIGATION_POLICY_INFORMATION policyInfo;
+
+ if (NT_SUCCESS(PhGetProcessBreakOnTermination(
+ processHandle,
+ &breakOnTermination
+ )))
+ {
+ if (breakOnTermination)
+ {
+ critical = TRUE;
+ }
+ }
+
+ policyInfo.Policy = ProcessStrictHandleCheckPolicy;
+ policyInfo.StrictHandleCheckPolicy.Flags = 0;
+
+ if (NT_SUCCESS(NtQueryInformationProcess(
+ processHandle,
+ ProcessMitigationPolicy,
+ &policyInfo,
+ sizeof(PROCESS_MITIGATION_POLICY_INFORMATION),
+ NULL
+ )))
+ {
+ if (policyInfo.StrictHandleCheckPolicy.Flags != 0)
+ {
+ strict = TRUE;
+ }
+ }
+ }
+
+ if (critical && strict)
+ {
+ cont = PhShowConfirmMessage(
+ hWnd,
+ L"close",
+ L"critical process handle(s)",
+ L"You are about to close one or more handles for a critical process with strict handle checks enabled. This will shut down the operating system immediately.\r\n\r\n",
+ TRUE
+ );
+ }
+
+ if (!cont)
+ return FALSE;
+
+ for (ULONG i = 0; i < NumberOfHandles; i++)
+ {
+ status = NtDuplicateObject(
+ processHandle,
+ Handles[i]->Handle,
+ NULL,
+ NULL,
+ 0,
+ 0,
+ DUPLICATE_CLOSE_SOURCE
+ );
+
+ if (!NT_SUCCESS(status))
+ {
+ success = FALSE;
+
+ if (!PhpShowErrorHandle(
+ hWnd,
+ L"close",
+ Handles[i],
+ status,
+ 0
+ ))
+ break;
+ }
+ }
+
+ NtClose(processHandle);
+ }
+ else
+ {
+ PhShowStatus(hWnd, L"Unable to open the process", status, 0);
+ return FALSE;
+ }
+
+ return success;
+}
+
+BOOLEAN PhUiSetAttributesHandle(
+ _In_ HWND hWnd,
+ _In_ HANDLE ProcessId,
+ _In_ PPH_HANDLE_ITEM Handle,
+ _In_ ULONG Attributes
+ )
+{
+ NTSTATUS status;
+ HANDLE processHandle;
+
+ if (!KphIsConnected())
+ {
+ PhShowError2(hWnd, PH_KPH_ERROR_TITLE, PH_KPH_ERROR_MESSAGE);
+ return FALSE;
+ }
+
+ if (NT_SUCCESS(status = PhOpenProcess(
+ &processHandle,
+ PROCESS_QUERY_LIMITED_INFORMATION,
+ ProcessId
+ )))
+ {
+ OBJECT_HANDLE_FLAG_INFORMATION handleFlagInfo;
+
+ handleFlagInfo.Inherit = !!(Attributes & OBJ_INHERIT);
+ handleFlagInfo.ProtectFromClose = !!(Attributes & OBJ_PROTECT_CLOSE);
+
+ status = KphSetInformationObject(
+ processHandle,
+ Handle->Handle,
+ KphObjectHandleFlagInformation,
+ &handleFlagInfo,
+ sizeof(OBJECT_HANDLE_FLAG_INFORMATION)
+ );
+
+ NtClose(processHandle);
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ PhpShowErrorHandle(hWnd, L"set attributes of", Handle, status, 0);
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/ProcessHacker/affinity.c b/ProcessHacker/affinity.c
index 9515cb6933ee..e3f121299122 100644
--- a/ProcessHacker/affinity.c
+++ b/ProcessHacker/affinity.c
@@ -1,317 +1,315 @@
-/*
- * Process Hacker -
- * process affinity editor
- *
- * 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 .
- */
-
-/*
- * The affinity dialog was originally created to support the modification
- * of process affinity masks, but now supports modifying thread affinity
- * and generic masks.
- */
-
-#include
-
-#include
-
-#include
-#include
-
-typedef struct _AFFINITY_DIALOG_CONTEXT
-{
- PPH_PROCESS_ITEM ProcessItem;
- PPH_THREAD_ITEM ThreadItem;
- ULONG_PTR AffinityMask;
- ULONG_PTR NewAffinityMask;
-} AFFINITY_DIALOG_CONTEXT, *PAFFINITY_DIALOG_CONTEXT;
-
-INT_PTR CALLBACK PhpProcessAffinityDlgProc(
- _In_ HWND hwndDlg,
- _In_ UINT uMsg,
- _In_ WPARAM wParam,
- _In_ LPARAM lParam
- );
-
-VOID PhShowProcessAffinityDialog(
- _In_ HWND ParentWindowHandle,
- _In_opt_ PPH_PROCESS_ITEM ProcessItem,
- _In_opt_ PPH_THREAD_ITEM ThreadItem
- )
-{
- AFFINITY_DIALOG_CONTEXT context;
-
- assert(!!ProcessItem != !!ThreadItem); // make sure we have one and not the other
-
- context.ProcessItem = ProcessItem;
- context.ThreadItem = ThreadItem;
-
- DialogBoxParam(
- PhInstanceHandle,
- MAKEINTRESOURCE(IDD_AFFINITY),
- ParentWindowHandle,
- PhpProcessAffinityDlgProc,
- (LPARAM)&context
- );
-}
-
-BOOLEAN PhShowProcessAffinityDialog2(
- _In_ HWND ParentWindowHandle,
- _In_ ULONG_PTR AffinityMask,
- _Out_ PULONG_PTR NewAffinityMask
- )
-{
- AFFINITY_DIALOG_CONTEXT context;
-
- context.ProcessItem = NULL;
- context.ThreadItem = NULL;
- context.AffinityMask = AffinityMask;
-
- if (DialogBoxParam(
- PhInstanceHandle,
- MAKEINTRESOURCE(IDD_AFFINITY),
- ParentWindowHandle,
- PhpProcessAffinityDlgProc,
- (LPARAM)&context
- ) == IDOK)
- {
- *NewAffinityMask = context.NewAffinityMask;
-
- return TRUE;
- }
- else
- {
- return FALSE;
- }
-}
-
-static INT_PTR CALLBACK PhpProcessAffinityDlgProc(
- _In_ HWND hwndDlg,
- _In_ UINT uMsg,
- _In_ WPARAM wParam,
- _In_ LPARAM lParam
- )
-{
- switch (uMsg)
- {
- case WM_INITDIALOG:
- {
- NTSTATUS status;
- PAFFINITY_DIALOG_CONTEXT context = (PAFFINITY_DIALOG_CONTEXT)lParam;
- SYSTEM_BASIC_INFORMATION systemBasicInfo;
- ULONG_PTR systemAffinityMask;
- ULONG_PTR affinityMask;
- ULONG i;
-
- SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context);
- PhCenterWindow(hwndDlg, GetParent(hwndDlg));
-
- systemAffinityMask = 0;
-
- if (context->ProcessItem)
- {
- HANDLE processHandle;
- PROCESS_BASIC_INFORMATION basicInfo;
-
- if (NT_SUCCESS(status = PhOpenProcess(
- &processHandle,
- ProcessQueryAccess,
- context->ProcessItem->ProcessId
- )))
- {
- status = PhGetProcessBasicInformation(processHandle, &basicInfo);
-
- if (NT_SUCCESS(status))
- affinityMask = basicInfo.AffinityMask;
-
- NtClose(processHandle);
- }
- }
- else if (context->ThreadItem)
- {
- HANDLE threadHandle;
- THREAD_BASIC_INFORMATION basicInfo;
- HANDLE processHandle;
- PROCESS_BASIC_INFORMATION processBasicInfo;
-
- if (NT_SUCCESS(status = PhOpenThread(
- &threadHandle,
- ThreadQueryAccess,
- context->ThreadItem->ThreadId
- )))
- {
- status = PhGetThreadBasicInformation(threadHandle, &basicInfo);
-
- if (NT_SUCCESS(status))
- {
- affinityMask = basicInfo.AffinityMask;
-
- // A thread's affinity mask is restricted by the process affinity mask,
- // so use that as the system affinity mask.
-
- if (NT_SUCCESS(PhOpenProcess(
- &processHandle,
- ProcessQueryAccess,
- basicInfo.ClientId.UniqueProcess
- )))
- {
- if (NT_SUCCESS(PhGetProcessBasicInformation(processHandle, &processBasicInfo)))
- systemAffinityMask = processBasicInfo.AffinityMask;
-
- NtClose(processHandle);
- }
- }
-
- NtClose(threadHandle);
- }
- }
- else
- {
- affinityMask = context->AffinityMask;
- status = STATUS_SUCCESS;
- }
-
- if (NT_SUCCESS(status) && systemAffinityMask == 0)
- {
- status = NtQuerySystemInformation(
- SystemBasicInformation,
- &systemBasicInfo,
- sizeof(SYSTEM_BASIC_INFORMATION),
- NULL
- );
-
- if (NT_SUCCESS(status))
- systemAffinityMask = systemBasicInfo.ActiveProcessorsAffinityMask;
- }
-
- if (!NT_SUCCESS(status))
- {
- PhShowStatus(hwndDlg, L"Unable to retrieve the affinity", status, 0);
- EndDialog(hwndDlg, IDCANCEL);
- break;
- }
-
- // Disable the CPU checkboxes which aren't part of the system affinity mask,
- // and check the CPU checkboxes which are part of the affinity mask.
-
- for (i = 0; i < 8 * 8; i++)
- {
- if ((i < sizeof(ULONG_PTR) * 8) && ((systemAffinityMask >> i) & 0x1))
- {
- if ((affinityMask >> i) & 0x1)
- {
- Button_SetCheck(GetDlgItem(hwndDlg, IDC_CPU0 + i), BST_CHECKED);
- }
- }
- else
- {
- EnableWindow(GetDlgItem(hwndDlg, IDC_CPU0 + i), FALSE);
- }
- }
- }
- break;
- case WM_DESTROY:
- {
- RemoveProp(hwndDlg, PhMakeContextAtom());
- }
- break;
- case WM_COMMAND:
- {
- switch (LOWORD(wParam))
- {
- case IDCANCEL:
- EndDialog(hwndDlg, IDCANCEL);
- break;
- case IDOK:
- {
- NTSTATUS status;
- PAFFINITY_DIALOG_CONTEXT context = (PAFFINITY_DIALOG_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom());
- ULONG i;
- ULONG_PTR affinityMask;
-
- // Work out the affinity mask.
-
- affinityMask = 0;
-
- for (i = 0; i < sizeof(ULONG_PTR) * 8; i++)
- {
- if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_CPU0 + i)) == BST_CHECKED)
- affinityMask |= (ULONG_PTR)1 << i;
- }
-
- if (context->ProcessItem)
- {
- HANDLE processHandle;
-
- if (NT_SUCCESS(status = PhOpenProcess(
- &processHandle,
- PROCESS_SET_INFORMATION,
- context->ProcessItem->ProcessId
- )))
- {
- status = PhSetProcessAffinityMask(processHandle, affinityMask);
- NtClose(processHandle);
- }
- }
- else if (context->ThreadItem)
- {
- HANDLE threadHandle;
-
- if (NT_SUCCESS(status = PhOpenThread(
- &threadHandle,
- ThreadSetAccess,
- context->ThreadItem->ThreadId
- )))
- {
- status = PhSetThreadAffinityMask(threadHandle, affinityMask);
- NtClose(threadHandle);
- }
- }
- else
- {
- context->NewAffinityMask = affinityMask;
- status = STATUS_SUCCESS;
- }
-
- if (NT_SUCCESS(status))
- EndDialog(hwndDlg, IDOK);
- else
- PhShowStatus(hwndDlg, L"Unable to set the affinity", status, 0);
- }
- break;
- case IDC_SELECTALL:
- case IDC_DESELECTALL:
- {
- ULONG i;
-
- for (i = 0; i < sizeof(ULONG_PTR) * 8; i++)
- {
- HWND checkBox = GetDlgItem(hwndDlg, IDC_CPU0 + i);
-
- if (IsWindowEnabled(checkBox))
- Button_SetCheck(checkBox, LOWORD(wParam) == IDC_SELECTALL ? BST_CHECKED : BST_UNCHECKED);
- }
- }
- break;
- }
- }
- break;
- }
-
- return FALSE;
-}
+/*
+ * Process Hacker -
+ * process affinity editor
+ *
+ * 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 .
+ */
+
+/*
+ * The affinity dialog was originally created to support the modification
+ * of process affinity masks, but now supports modifying thread affinity
+ * and generic masks.
+ */
+
+#include
+
+#include
+#include
+
+typedef struct _AFFINITY_DIALOG_CONTEXT
+{
+ PPH_PROCESS_ITEM ProcessItem;
+ PPH_THREAD_ITEM ThreadItem;
+ ULONG_PTR AffinityMask;
+ ULONG_PTR NewAffinityMask;
+} AFFINITY_DIALOG_CONTEXT, *PAFFINITY_DIALOG_CONTEXT;
+
+INT_PTR CALLBACK PhpProcessAffinityDlgProc(
+ _In_ HWND hwndDlg,
+ _In_ UINT uMsg,
+ _In_ WPARAM wParam,
+ _In_ LPARAM lParam
+ );
+
+VOID PhShowProcessAffinityDialog(
+ _In_ HWND ParentWindowHandle,
+ _In_opt_ PPH_PROCESS_ITEM ProcessItem,
+ _In_opt_ PPH_THREAD_ITEM ThreadItem
+ )
+{
+ AFFINITY_DIALOG_CONTEXT context;
+
+ assert(!!ProcessItem != !!ThreadItem); // make sure we have one and not the other
+
+ context.ProcessItem = ProcessItem;
+ context.ThreadItem = ThreadItem;
+
+ DialogBoxParam(
+ PhInstanceHandle,
+ MAKEINTRESOURCE(IDD_AFFINITY),
+ ParentWindowHandle,
+ PhpProcessAffinityDlgProc,
+ (LPARAM)&context
+ );
+}
+
+BOOLEAN PhShowProcessAffinityDialog2(
+ _In_ HWND ParentWindowHandle,
+ _In_ ULONG_PTR AffinityMask,
+ _Out_ PULONG_PTR NewAffinityMask
+ )
+{
+ AFFINITY_DIALOG_CONTEXT context;
+
+ context.ProcessItem = NULL;
+ context.ThreadItem = NULL;
+ context.AffinityMask = AffinityMask;
+
+ if (DialogBoxParam(
+ PhInstanceHandle,
+ MAKEINTRESOURCE(IDD_AFFINITY),
+ ParentWindowHandle,
+ PhpProcessAffinityDlgProc,
+ (LPARAM)&context
+ ) == IDOK)
+ {
+ *NewAffinityMask = context.NewAffinityMask;
+
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+static INT_PTR CALLBACK PhpProcessAffinityDlgProc(
+ _In_ HWND hwndDlg,
+ _In_ UINT uMsg,
+ _In_ WPARAM wParam,
+ _In_ LPARAM lParam
+ )
+{
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ NTSTATUS status;
+ PAFFINITY_DIALOG_CONTEXT context = (PAFFINITY_DIALOG_CONTEXT)lParam;
+ SYSTEM_BASIC_INFORMATION systemBasicInfo;
+ ULONG_PTR systemAffinityMask;
+ ULONG_PTR affinityMask;
+ ULONG i;
+
+ PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);
+ PhCenterWindow(hwndDlg, GetParent(hwndDlg));
+
+ systemAffinityMask = 0;
+
+ if (context->ProcessItem)
+ {
+ HANDLE processHandle;
+ PROCESS_BASIC_INFORMATION basicInfo;
+
+ if (NT_SUCCESS(status = PhOpenProcess(
+ &processHandle,
+ PROCESS_QUERY_LIMITED_INFORMATION,
+ context->ProcessItem->ProcessId
+ )))
+ {
+ status = PhGetProcessBasicInformation(processHandle, &basicInfo);
+
+ if (NT_SUCCESS(status))
+ affinityMask = basicInfo.AffinityMask;
+
+ NtClose(processHandle);
+ }
+ }
+ else if (context->ThreadItem)
+ {
+ HANDLE threadHandle;
+ THREAD_BASIC_INFORMATION basicInfo;
+ HANDLE processHandle;
+ PROCESS_BASIC_INFORMATION processBasicInfo;
+
+ if (NT_SUCCESS(status = PhOpenThread(
+ &threadHandle,
+ THREAD_QUERY_LIMITED_INFORMATION,
+ context->ThreadItem->ThreadId
+ )))
+ {
+ status = PhGetThreadBasicInformation(threadHandle, &basicInfo);
+
+ if (NT_SUCCESS(status))
+ {
+ affinityMask = basicInfo.AffinityMask;
+
+ // A thread's affinity mask is restricted by the process affinity mask,
+ // so use that as the system affinity mask.
+
+ if (NT_SUCCESS(PhOpenProcess(
+ &processHandle,
+ PROCESS_QUERY_LIMITED_INFORMATION,
+ basicInfo.ClientId.UniqueProcess
+ )))
+ {
+ if (NT_SUCCESS(PhGetProcessBasicInformation(processHandle, &processBasicInfo)))
+ systemAffinityMask = processBasicInfo.AffinityMask;
+
+ NtClose(processHandle);
+ }
+ }
+
+ NtClose(threadHandle);
+ }
+ }
+ else
+ {
+ affinityMask = context->AffinityMask;
+ status = STATUS_SUCCESS;
+ }
+
+ if (NT_SUCCESS(status) && systemAffinityMask == 0)
+ {
+ status = NtQuerySystemInformation(
+ SystemBasicInformation,
+ &systemBasicInfo,
+ sizeof(SYSTEM_BASIC_INFORMATION),
+ NULL
+ );
+
+ if (NT_SUCCESS(status))
+ systemAffinityMask = systemBasicInfo.ActiveProcessorsAffinityMask;
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ PhShowStatus(hwndDlg, L"Unable to retrieve the affinity", status, 0);
+ EndDialog(hwndDlg, IDCANCEL);
+ break;
+ }
+
+ // Disable the CPU checkboxes which aren't part of the system affinity mask,
+ // and check the CPU checkboxes which are part of the affinity mask.
+
+ for (i = 0; i < 8 * 8; i++)
+ {
+ if ((i < sizeof(ULONG_PTR) * 8) && ((systemAffinityMask >> i) & 0x1))
+ {
+ if ((affinityMask >> i) & 0x1)
+ {
+ Button_SetCheck(GetDlgItem(hwndDlg, IDC_CPU0 + i), BST_CHECKED);
+ }
+ }
+ else
+ {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CPU0 + i), FALSE);
+ }
+ }
+ }
+ break;
+ case WM_DESTROY:
+ {
+ PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);
+ }
+ break;
+ case WM_COMMAND:
+ {
+ switch (GET_WM_COMMAND_ID(wParam, lParam))
+ {
+ case IDCANCEL:
+ EndDialog(hwndDlg, IDCANCEL);
+ break;
+ case IDOK:
+ {
+ NTSTATUS status;
+ PAFFINITY_DIALOG_CONTEXT context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);
+ ULONG i;
+ ULONG_PTR affinityMask;
+
+ // Work out the affinity mask.
+
+ affinityMask = 0;
+
+ for (i = 0; i < sizeof(ULONG_PTR) * 8; i++)
+ {
+ if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_CPU0 + i)) == BST_CHECKED)
+ affinityMask |= (ULONG_PTR)1 << i;
+ }
+
+ if (context->ProcessItem)
+ {
+ HANDLE processHandle;
+
+ if (NT_SUCCESS(status = PhOpenProcess(
+ &processHandle,
+ PROCESS_SET_INFORMATION,
+ context->ProcessItem->ProcessId
+ )))
+ {
+ status = PhSetProcessAffinityMask(processHandle, affinityMask);
+ NtClose(processHandle);
+ }
+ }
+ else if (context->ThreadItem)
+ {
+ HANDLE threadHandle;
+
+ if (NT_SUCCESS(status = PhOpenThread(
+ &threadHandle,
+ THREAD_SET_LIMITED_INFORMATION,
+ context->ThreadItem->ThreadId
+ )))
+ {
+ status = PhSetThreadAffinityMask(threadHandle, affinityMask);
+ NtClose(threadHandle);
+ }
+ }
+ else
+ {
+ context->NewAffinityMask = affinityMask;
+ status = STATUS_SUCCESS;
+ }
+
+ if (NT_SUCCESS(status))
+ EndDialog(hwndDlg, IDOK);
+ else
+ PhShowStatus(hwndDlg, L"Unable to set the affinity", status, 0);
+ }
+ break;
+ case IDC_SELECTALL:
+ case IDC_DESELECTALL:
+ {
+ ULONG i;
+
+ for (i = 0; i < sizeof(ULONG_PTR) * 8; i++)
+ {
+ HWND checkBox = GetDlgItem(hwndDlg, IDC_CPU0 + i);
+
+ if (IsWindowEnabled(checkBox))
+ Button_SetCheck(checkBox, GET_WM_COMMAND_ID(wParam, lParam) == IDC_SELECTALL ? BST_CHECKED : BST_UNCHECKED);
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+
+ return FALSE;
+}
diff --git a/ProcessHacker/anawait.c b/ProcessHacker/anawait.c
index 63f355a0e008..f32333f9b624 100644
--- a/ProcessHacker/anawait.c
+++ b/ProcessHacker/anawait.c
@@ -1,1076 +1,1046 @@
-/*
- * Process Hacker -
- * thread wait analysis
- *
- * 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 .
- */
-
-/*
- * There are two ways of seeing what a thread is waiting on. The first method
- * is to walk the stack of a thread and read the arguments to whatever system
- * call it is blocking on; this only works on x86 because on x64 the arguments
- * are passed in registers (at least the first four are). The second method
- * involves using the ThreadLastSystemCall info class for NtQueryInformationThread
- * to retrieve the first argument to the system call the thread is blocking on.
- * This is obviously only useful for NtWaitForSingleObject.
- *
- * There are other methods for specific scenarios, like USER messages and ALPC
- * calls.
- */
-
-#include
-
-#include
-#include
-
-#include
-
-typedef HWND (WINAPI *_GetSendMessageReceiver)(
- _In_ HANDLE ThreadId
- );
-
-typedef NTSTATUS (NTAPI *_NtAlpcQueryInformation)(
- _In_ HANDLE PortHandle,
- _In_ ALPC_PORT_INFORMATION_CLASS PortInformationClass,
- _Out_writes_bytes_(Length) PVOID PortInformation,
- _In_ ULONG Length,
- _Out_opt_ PULONG ReturnLength
- );
-
-typedef struct _ANALYZE_WAIT_CONTEXT
-{
- BOOLEAN Found;
- BOOLEAN IsWow64;
- HANDLE ProcessId;
- HANDLE ThreadId;
- HANDLE ProcessHandle;
-
- PPH_SYMBOL_PROVIDER SymbolProvider;
- PH_STRING_BUILDER StringBuilder;
-
- PVOID PrevParams[4];
-} ANALYZE_WAIT_CONTEXT, *PANALYZE_WAIT_CONTEXT;
-
-VOID PhpAnalyzeWaitPassive(
- _In_ HWND hWnd,
- _In_ HANDLE ProcessId,
- _In_ HANDLE ThreadId
- );
-
-BOOLEAN NTAPI PhpWalkThreadStackAnalyzeCallback(
- _In_ PPH_THREAD_STACK_FRAME StackFrame,
- _In_opt_ PVOID Context
- );
-
-VOID PhpAnalyzeWaitFallbacks(
- _In_ PANALYZE_WAIT_CONTEXT Context
- );
-
-VOID PhpInitializeServiceNumbers(
- VOID
- );
-
-PPH_STRING PhpaGetHandleString(
- _In_ HANDLE ProcessHandle,
- _In_ HANDLE Handle
- );
-
-VOID PhpGetWfmoInformation(
- _In_ HANDLE ProcessHandle,
- _In_ BOOLEAN IsWow64,
- _In_ ULONG NumberOfHandles,
- _In_ PHANDLE AddressOfHandles,
- _In_ WAIT_TYPE WaitType,
- _In_ BOOLEAN Alertable,
- _Inout_ PPH_STRING_BUILDER StringBuilder
- );
-
-PPH_STRING PhpaGetSendMessageReceiver(
- _In_ HANDLE ThreadId
- );
-
-PPH_STRING PhpaGetAlpcInformation(
- _In_ HANDLE ThreadId
- );
-
-static PH_INITONCE ServiceNumbersInitOnce = PH_INITONCE_INIT;
-static USHORT NumberForWfso = -1;
-static USHORT NumberForWfmo = -1;
-static USHORT NumberForRf = -1;
-
-VOID PhUiAnalyzeWaitThread(
- _In_ HWND hWnd,
- _In_ HANDLE ProcessId,
- _In_ HANDLE ThreadId,
- _In_ PPH_SYMBOL_PROVIDER SymbolProvider
- )
-{
- NTSTATUS status;
- HANDLE threadHandle;
-#ifdef _WIN64
- HANDLE processHandle;
- BOOLEAN isWow64;
-#endif
- CLIENT_ID clientId;
- ANALYZE_WAIT_CONTEXT context;
-
-#ifdef _WIN64
- // Determine if the process is WOW64. If not, we use the passive method.
-
- if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, ProcessQueryAccess, ProcessId)))
- {
- PhShowStatus(hWnd, L"Unable to open the process", status, 0);
- return;
- }
-
- if (!NT_SUCCESS(status = PhGetProcessIsWow64(processHandle, &isWow64)) || !isWow64)
- {
- PhpAnalyzeWaitPassive(hWnd, ProcessId, ThreadId);
- return;
- }
-
- NtClose(processHandle);
-#endif
-
- if (!NT_SUCCESS(status = PhOpenThread(
- &threadHandle,
- ThreadQueryAccess | THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME,
- ThreadId
- )))
- {
- PhShowStatus(hWnd, L"Unable to open the thread", status, 0);
- return;
- }
-
- context.ProcessId = ProcessId;
- context.ThreadId = ThreadId;
-
- context.ProcessHandle = SymbolProvider->ProcessHandle;
- context.SymbolProvider = SymbolProvider;
- PhInitializeStringBuilder(&context.StringBuilder, 100);
-
- clientId.UniqueProcess = ProcessId;
- clientId.UniqueThread = ThreadId;
-
- PhWalkThreadStack(
- threadHandle,
- SymbolProvider->ProcessHandle,
- &clientId,
- SymbolProvider,
- PH_WALK_I386_STACK,
- PhpWalkThreadStackAnalyzeCallback,
- &context
- );
- NtClose(threadHandle);
-
- PhpAnalyzeWaitFallbacks(&context);
-
- if (context.Found)
- {
- PhShowInformationDialog(hWnd, context.StringBuilder.String->Buffer, 0);
- }
- else
- {
- PhShowInformation(hWnd, L"The thread does not appear to be waiting.");
- }
-
- PhDeleteStringBuilder(&context.StringBuilder);
-}
-
-VOID PhpAnalyzeWaitPassive(
- _In_ HWND hWnd,
- _In_ HANDLE ProcessId,
- _In_ HANDLE ThreadId
- )
-{
- NTSTATUS status;
- HANDLE processHandle;
- HANDLE threadHandle;
- THREAD_LAST_SYSCALL_INFORMATION lastSystemCall;
- PH_STRING_BUILDER stringBuilder;
- PPH_STRING string;
-
- PhpInitializeServiceNumbers();
-
- if (!NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_GET_CONTEXT, ThreadId)))
- {
- PhShowStatus(hWnd, L"Unable to open the thread", status, 0);
- return;
- }
-
- if (!NT_SUCCESS(status = NtQueryInformationThread(
- threadHandle,
- ThreadLastSystemCall,
- &lastSystemCall,
- sizeof(THREAD_LAST_SYSCALL_INFORMATION),
- NULL
- )))
- {
- NtClose(threadHandle);
- PhShowInformation(hWnd, L"Unable to determine whether the thread is waiting.");
- return;
- }
-
- if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_DUP_HANDLE, ProcessId)))
- {
- NtClose(threadHandle);
- PhShowStatus(hWnd, L"Unable to open the process", status, 0);
- return;
- }
-
- PhInitializeStringBuilder(&stringBuilder, 100);
-
- if (lastSystemCall.SystemCallNumber == NumberForWfso)
- {
- string = PhpaGetHandleString(processHandle, lastSystemCall.FirstArgument);
-
- PhAppendFormatStringBuilder(&stringBuilder, L"Thread is waiting for:\r\n");
- PhAppendStringBuilder(&stringBuilder, &string->sr);
- }
- else if (lastSystemCall.SystemCallNumber == NumberForWfmo)
- {
- PhAppendFormatStringBuilder(&stringBuilder, L"Thread is waiting for multiple (%u) objects.", PtrToUlong(lastSystemCall.FirstArgument));
- }
- else if (lastSystemCall.SystemCallNumber == NumberForRf)
- {
- string = PhpaGetHandleString(processHandle, lastSystemCall.FirstArgument);
-
- PhAppendFormatStringBuilder(&stringBuilder, L"Thread is waiting for file I/O:\r\n");
- PhAppendStringBuilder(&stringBuilder, &string->sr);
- }
- else
- {
- string = PhpaGetSendMessageReceiver(ThreadId);
-
- if (string)
- {
- PhAppendStringBuilder2(&stringBuilder, L"Thread is sending a USER message:\r\n");
- PhAppendStringBuilder(&stringBuilder, &string->sr);
- }
- else
- {
- string = PhpaGetAlpcInformation(ThreadId);
-
- if (string)
- {
- PhAppendStringBuilder2(&stringBuilder, L"Thread is waiting for an ALPC port:\r\n");
- PhAppendStringBuilder(&stringBuilder, &string->sr);
- }
- }
- }
-
- if (stringBuilder.String->Length == 0)
- PhAppendStringBuilder2(&stringBuilder, L"Unable to determine why the thread is waiting.");
-
- PhShowInformationDialog(hWnd, stringBuilder.String->Buffer, 0);
-
- PhDeleteStringBuilder(&stringBuilder);
- NtClose(processHandle);
- NtClose(threadHandle);
-}
-
-static BOOLEAN NTAPI PhpWalkThreadStackAnalyzeCallback(
- _In_ PPH_THREAD_STACK_FRAME StackFrame,
- _In_opt_ PVOID Context
- )
-{
- PANALYZE_WAIT_CONTEXT context = (PANALYZE_WAIT_CONTEXT)Context;
- PPH_STRING name;
-
- name = PhGetSymbolFromAddress(
- context->SymbolProvider,
- (ULONG64)StackFrame->PcAddress,
- NULL,
- NULL,
- NULL,
- NULL
- );
-
- if (!name)
- return TRUE;
-
- context->Found = TRUE;
-
-#define FUNC_MATCH(Name) PhStartsWithString2(name, L##Name, TRUE)
-#define NT_FUNC_MATCH(Name) ( \
- PhStartsWithString2(name, L"ntdll.dll!Nt" L##Name, TRUE) || \
- PhStartsWithString2(name, L"ntdll.dll!Zw" L##Name, TRUE) \
- )
-
- if (!name)
- {
- // Dummy
- }
- else if (FUNC_MATCH("kernel32.dll!Sleep"))
- {
- PhAppendFormatStringBuilder(
- &context->StringBuilder,
- L"Thread is sleeping. Timeout: %u milliseconds.",
- PtrToUlong(StackFrame->Params[0])
- );
- }
- else if (NT_FUNC_MATCH("DelayExecution"))
- {
- BOOLEAN alertable = !!StackFrame->Params[0];
- PVOID timeoutAddress = StackFrame->Params[1];
- LARGE_INTEGER timeout;
-
- if (NT_SUCCESS(NtReadVirtualMemory(
- context->ProcessHandle,
- timeoutAddress,
- &timeout,
- sizeof(LARGE_INTEGER),
- NULL
- )))
- {
- if (timeout.QuadPart < 0)
- {
- PhAppendFormatStringBuilder(
- &context->StringBuilder,
- L"Thread is sleeping. Timeout: %I64u milliseconds.",
- -timeout.QuadPart / PH_TIMEOUT_MS
- );
- }
- else
- {
- // TODO
- }
- }
- else
- {
- PhAppendStringBuilder2(
- &context->StringBuilder,
- L"Thread is sleeping."
- );
- }
- }
- else if (NT_FUNC_MATCH("DeviceIoControlFile"))
- {
- HANDLE handle = (HANDLE)StackFrame->Params[0];
-
- PhAppendStringBuilder2(
- &context->StringBuilder,
- L"Thread is waiting for an I/O control request:\r\n"
- );
- PhAppendStringBuilder(
- &context->StringBuilder,
- &PhpaGetHandleString(context->ProcessHandle, handle)->sr
- );
- }
- else if (NT_FUNC_MATCH("FsControlFile"))
- {
- HANDLE handle = StackFrame->Params[0];
-
- PhAppendStringBuilder2(
- &context->StringBuilder,
- L"Thread is waiting for a FS control request:\r\n"
- );
- PhAppendStringBuilder(
- &context->StringBuilder,
- &PhpaGetHandleString(context->ProcessHandle, handle)->sr
- );
- }
- else if (NT_FUNC_MATCH("QueryObject"))
- {
- HANDLE handle = StackFrame->Params[0];
-
- // Use the KiFastSystemCall args if the handle we have is wrong.
- if ((ULONG_PTR)handle % 4 != 0 || !handle)
- handle = context->PrevParams[1];
-
- PhAppendStringBuilder2(
- &context->StringBuilder,
- L"Thread is querying an object:\r\n"
- );
- PhAppendStringBuilder(
- &context->StringBuilder,
- &PhpaGetHandleString(context->ProcessHandle, handle)->sr
- );
- }
- else if (NT_FUNC_MATCH("ReadFile") || NT_FUNC_MATCH("WriteFile"))
- {
- HANDLE handle = StackFrame->Params[0];
-
- PhAppendStringBuilder2(
- &context->StringBuilder,
- L"Thread is waiting for file I/O:\r\n"
- );
- PhAppendStringBuilder(
- &context->StringBuilder,
- &PhpaGetHandleString(context->ProcessHandle, handle)->sr
- );
- }
- else if (NT_FUNC_MATCH("RemoveIoCompletion"))
- {
- HANDLE handle = StackFrame->Params[0];
-
- PhAppendStringBuilder2(
- &context->StringBuilder,
- L"Thread is waiting for an I/O completion port:\r\n"
- );
- PhAppendStringBuilder(
- &context->StringBuilder,
- &PhpaGetHandleString(context->ProcessHandle, handle)->sr
- );
- }
- else if (
- NT_FUNC_MATCH("ReplyWaitReceivePort") ||
- NT_FUNC_MATCH("RequestWaitReplyPort") ||
- NT_FUNC_MATCH("AlpcSendWaitReceivePort")
- )
- {
- HANDLE handle = StackFrame->Params[0];
- PPH_STRING alpcInfo;
-
- PhAppendStringBuilder2(
- &context->StringBuilder,
- WindowsVersion >= WINDOWS_VISTA ? L"Thread is waiting for an ALPC port:\r\n" : L"Thread is waiting for a LPC port:\r\n"
- );
- PhAppendStringBuilder(
- &context->StringBuilder,
- &PhpaGetHandleString(context->ProcessHandle, handle)->sr
- );
-
- if (alpcInfo = PhpaGetAlpcInformation(context->ThreadId))
- {
- PhAppendStringBuilder2(
- &context->StringBuilder,
- L"\r\n"
- );
- PhAppendStringBuilder(
- &context->StringBuilder,
- &alpcInfo->sr
- );
- }
- }
- else if (
- NT_FUNC_MATCH("SetHighWaitLowEventPair") ||
- NT_FUNC_MATCH("SetLowWaitHighEventPair") ||
- NT_FUNC_MATCH("WaitHighEventPair") ||
- NT_FUNC_MATCH("WaitLowEventPair")
- )
- {
- HANDLE handle = StackFrame->Params[0];
-
- if ((ULONG_PTR)handle % 4 != 0 || !handle)
- handle = context->PrevParams[1];
-
- PhAppendFormatStringBuilder(
- &context->StringBuilder,
- L"Thread is waiting (%s) for an event pair:\r\n",
- name->Buffer
- );
- PhAppendStringBuilder(
- &context->StringBuilder,
- &PhpaGetHandleString(context->ProcessHandle, handle)->sr
- );
- }
- else if (
- FUNC_MATCH("user32.dll!NtUserGetMessage") ||
- FUNC_MATCH("user32.dll!NtUserWaitMessage")
- )
- {
- PhAppendStringBuilder2(
- &context->StringBuilder,
- L"Thread is waiting for a USER message.\r\n"
- );
- }
- else if (FUNC_MATCH("user32.dll!NtUserMessageCall"))
- {
- PPH_STRING receiverString;
-
- PhAppendStringBuilder2(
- &context->StringBuilder,
- L"Thread is sending a USER message:\r\n"
- );
-
- receiverString = PhpaGetSendMessageReceiver(context->ThreadId);
-
- if (receiverString)
- {
- PhAppendStringBuilder(&context->StringBuilder, &receiverString->sr);
- PhAppendStringBuilder2(&context->StringBuilder, L"\r\n");
- }
- else
- {
- PhAppendStringBuilder2(&context->StringBuilder, L"Unknown.\r\n");
- }
- }
- else if (NT_FUNC_MATCH("WaitForDebugEvent"))
- {
- HANDLE handle = StackFrame->Params[0];
-
- PhAppendStringBuilder2(
- &context->StringBuilder,
- L"Thread is waiting for a debug event:\r\n"
- );
- PhAppendStringBuilder(
- &context->StringBuilder,
- &PhpaGetHandleString(context->ProcessHandle, handle)->sr
- );
- }
- else if (
- NT_FUNC_MATCH("WaitForKeyedEvent") ||
- NT_FUNC_MATCH("ReleaseKeyedEvent")
- )
- {
- HANDLE handle = StackFrame->Params[0];
- PVOID key = StackFrame->Params[1];
-
- PhAppendFormatStringBuilder(
- &context->StringBuilder,
- L"Thread is waiting (%s) for a keyed event (key 0x%Ix):\r\n",
- name->Buffer,
- key
- );
- PhAppendStringBuilder(
- &context->StringBuilder,
- &PhpaGetHandleString(context->ProcessHandle, handle)->sr
- );
- }
- else if (
- NT_FUNC_MATCH("WaitForMultipleObjects") ||
- FUNC_MATCH("kernel32.dll!WaitForMultipleObjects")
- )
- {
- ULONG numberOfHandles = PtrToUlong(StackFrame->Params[0]);
- PVOID addressOfHandles = StackFrame->Params[1];
- WAIT_TYPE waitType = (WAIT_TYPE)StackFrame->Params[2];
- BOOLEAN alertable = !!StackFrame->Params[3];
-
- if (numberOfHandles > MAXIMUM_WAIT_OBJECTS)
- {
- numberOfHandles = PtrToUlong(context->PrevParams[1]);
- addressOfHandles = context->PrevParams[2];
- waitType = (WAIT_TYPE)context->PrevParams[3];
- alertable = FALSE;
- }
-
- PhpGetWfmoInformation(
- context->ProcessHandle,
- TRUE, // on x64 this function is only called for WOW64 processes
- numberOfHandles,
- addressOfHandles,
- waitType,
- alertable,
- &context->StringBuilder
- );
- }
- else if (
- NT_FUNC_MATCH("WaitForSingleObject") ||
- FUNC_MATCH("kernel32.dll!WaitForSingleObject")
- )
- {
- HANDLE handle = StackFrame->Params[0];
- BOOLEAN alertable = !!StackFrame->Params[1];
-
- if ((ULONG_PTR)handle % 4 != 0 || !handle)
- {
- handle = context->PrevParams[1];
- alertable = !!context->PrevParams[2];
- }
-
- PhAppendFormatStringBuilder(
- &context->StringBuilder,
- L"Thread is waiting (%s) for:\r\n",
- alertable ? L"alertable" : L"non-alertable"
- );
- PhAppendStringBuilder(
- &context->StringBuilder,
- &PhpaGetHandleString(context->ProcessHandle, handle)->sr
- );
- }
- else if (NT_FUNC_MATCH("WaitForWorkViaWorkerFactory"))
- {
- HANDLE handle = StackFrame->Params[0];
-
- PhAppendStringBuilder2(
- &context->StringBuilder,
- L"Thread is waiting for work from a worker factory:\r\n"
- );
- PhAppendStringBuilder(
- &context->StringBuilder,
- &PhpaGetHandleString(context->ProcessHandle, handle)->sr
- );
- }
- else
- {
- context->Found = FALSE;
- }
-
- PhDereferenceObject(name);
- memcpy(&context->PrevParams, StackFrame->Params, sizeof(StackFrame->Params));
-
- return !context->Found;
-}
-
-static VOID PhpAnalyzeWaitFallbacks(
- _In_ PANALYZE_WAIT_CONTEXT Context
- )
-{
- PPH_STRING info;
-
- // We didn't detect NtUserMessageCall, but this may still apply due to another
- // win32k system call (e.g. from EnableWindow).
- if (!Context->Found && (info = PhpaGetSendMessageReceiver(Context->ThreadId)))
- {
- PhAppendStringBuilder2(
- &Context->StringBuilder,
- L"Thread is sending a USER message:\r\n"
- );
- PhAppendStringBuilder(&Context->StringBuilder, &info->sr);
- PhAppendStringBuilder2(&Context->StringBuilder, L"\r\n");
-
- Context->Found = TRUE;
- }
-
- // Nt(Alpc)ConnectPort doesn't get detected anywhere else.
- if (!Context->Found && (info = PhpaGetAlpcInformation(Context->ThreadId)))
- {
- PhAppendStringBuilder2(
- &Context->StringBuilder,
- L"Thread is waiting for an ALPC port:\r\n"
- );
- PhAppendStringBuilder(&Context->StringBuilder, &info->sr);
- PhAppendStringBuilder2(&Context->StringBuilder, L"\r\n");
-
- Context->Found = TRUE;
- }
-}
-
-static BOOLEAN PhpWaitUntilThreadIsWaiting(
- _In_ HANDLE ThreadHandle
- )
-{
- ULONG attempts;
- BOOLEAN isWaiting = FALSE;
- THREAD_BASIC_INFORMATION basicInfo;
-
- if (!NT_SUCCESS(PhGetThreadBasicInformation(ThreadHandle, &basicInfo)))
- return FALSE;
-
- for (attempts = 0; attempts < 5; attempts++)
- {
- PVOID processes;
- PSYSTEM_PROCESS_INFORMATION processInfo;
- ULONG i;
- LARGE_INTEGER interval;
-
- interval.QuadPart = -100 * PH_TIMEOUT_MS;
- NtDelayExecution(FALSE, &interval);
-
- if (!NT_SUCCESS(PhEnumProcesses(&processes)))
- break;
-
- processInfo = PhFindProcessInformation(processes, basicInfo.ClientId.UniqueProcess);
-
- if (processInfo)
- {
- for (i = 0; i < processInfo->NumberOfThreads; i++)
- {
- if (
- processInfo->Threads[i].ClientId.UniqueThread == basicInfo.ClientId.UniqueThread &&
- processInfo->Threads[i].ThreadState == Waiting &&
- (processInfo->Threads[i].WaitReason == UserRequest ||
- processInfo->Threads[i].WaitReason == Executive)
- )
- {
- isWaiting = TRUE;
- break;
- }
- }
- }
-
- PhFree(processes);
-
- if (isWaiting)
- break;
-
- interval.QuadPart = -500 * PH_TIMEOUT_MS;
- NtDelayExecution(FALSE, &interval);
- }
-
- return isWaiting;
-}
-
-static VOID PhpGetThreadLastSystemCallNumber(
- _In_ HANDLE ThreadHandle,
- _Out_ PUSHORT LastSystemCallNumber
- )
-{
- THREAD_LAST_SYSCALL_INFORMATION lastSystemCall;
-
- if (NT_SUCCESS(NtQueryInformationThread(
- ThreadHandle,
- ThreadLastSystemCall,
- &lastSystemCall,
- sizeof(THREAD_LAST_SYSCALL_INFORMATION),
- NULL
- )))
- {
- *LastSystemCallNumber = lastSystemCall.SystemCallNumber;
- }
-}
-
-static NTSTATUS PhpWfsoThreadStart(
- _In_ PVOID Parameter
- )
-{
- HANDLE eventHandle;
- LARGE_INTEGER timeout;
-
- eventHandle = Parameter;
-
- timeout.QuadPart = -5 * PH_TIMEOUT_SEC;
- NtWaitForSingleObject(eventHandle, FALSE, &timeout);
-
- return STATUS_SUCCESS;
-}
-
-static NTSTATUS PhpWfmoThreadStart(
- _In_ PVOID Parameter
- )
-{
- HANDLE eventHandle;
- LARGE_INTEGER timeout;
-
- eventHandle = Parameter;
-
- timeout.QuadPart = -5 * PH_TIMEOUT_SEC;
- NtWaitForMultipleObjects(1, &eventHandle, WaitAll, FALSE, &timeout);
-
- return STATUS_SUCCESS;
-}
-
-static NTSTATUS PhpRfThreadStart(
- _In_ PVOID Parameter
- )
-{
- HANDLE fileHandle;
- IO_STATUS_BLOCK isb;
- ULONG data;
-
- fileHandle = Parameter;
-
- NtReadFile(fileHandle, NULL, NULL, NULL, &isb, &data, sizeof(ULONG), NULL, NULL);
-
- return STATUS_SUCCESS;
-}
-
-static VOID PhpInitializeServiceNumbers(
- VOID
- )
-{
- if (PhBeginInitOnce(&ServiceNumbersInitOnce))
- {
- NTSTATUS status;
- HANDLE eventHandle;
- HANDLE threadHandle;
- HANDLE pipeReadHandle;
- HANDLE pipeWriteHandle;
-
- // The ThreadLastSystemCall info class only works when the thread is in the Waiting
- // state. We'll create a thread which blocks on an event object we create, then wait
- // until it is in the Waiting state. Only then can we query the thread using
- // ThreadLastSystemCall.
-
- // NtWaitForSingleObject
-
- status = NtCreateEvent(&eventHandle, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE);
-
- if (NT_SUCCESS(status))
- {
- if (threadHandle = PhCreateThread(0, PhpWfsoThreadStart, eventHandle))
- {
- if (PhpWaitUntilThreadIsWaiting(threadHandle))
- {
- PhpGetThreadLastSystemCallNumber(threadHandle, &NumberForWfso);
- }
-
- // Allow the thread to exit.
- NtSetEvent(eventHandle, NULL);
- NtClose(threadHandle);
- }
-
- NtClose(eventHandle);
- }
-
- // NtWaitForMultipleObjects
-
- status = NtCreateEvent(&eventHandle, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE);
-
- if (NT_SUCCESS(status))
- {
- if (threadHandle = PhCreateThread(0, PhpWfmoThreadStart, eventHandle))
- {
- if (PhpWaitUntilThreadIsWaiting(threadHandle))
- {
- PhpGetThreadLastSystemCallNumber(threadHandle, &NumberForWfmo);
- }
-
- NtSetEvent(eventHandle, NULL);
- NtClose(threadHandle);
- }
-
- NtClose(eventHandle);
- }
-
- // NtReadFile
-
- if (CreatePipe(&pipeReadHandle, &pipeWriteHandle, NULL, 0))
- {
- if (threadHandle = PhCreateThread(0, PhpRfThreadStart, pipeReadHandle))
- {
- ULONG data = 0;
- IO_STATUS_BLOCK isb;
-
- if (PhpWaitUntilThreadIsWaiting(threadHandle))
- {
- PhpGetThreadLastSystemCallNumber(threadHandle, &NumberForRf);
- }
-
- NtWriteFile(pipeWriteHandle, NULL, NULL, NULL, &isb, &data, sizeof(data), NULL, NULL);
- NtClose(threadHandle);
- }
-
- NtClose(pipeReadHandle);
- NtClose(pipeWriteHandle);
- }
-
- PhEndInitOnce(&ServiceNumbersInitOnce);
- }
-}
-
-static PPH_STRING PhpaGetHandleString(
- _In_ HANDLE ProcessHandle,
- _In_ HANDLE Handle
- )
-{
- PPH_STRING typeName = NULL;
- PPH_STRING name = NULL;
- PPH_STRING result;
-
- PhGetHandleInformation(
- ProcessHandle,
- Handle,
- -1,
- NULL,
- &typeName,
- NULL,
- &name
- );
- PH_AUTO(typeName);
- PH_AUTO(name);
-
- if (typeName && name)
- {
- result = PhaFormatString(
- L"Handle 0x%Ix (%s): %s",
- Handle,
- typeName->Buffer,
- !PhIsNullOrEmptyString(name) ? name->Buffer : L"(unnamed object)"
- );
- }
- else
- {
- result = PhaFormatString(
- L"Handle 0x%Ix: (error querying handle)",
- Handle
- );
- }
-
- return result;
-}
-
-static VOID PhpGetWfmoInformation(
- _In_ HANDLE ProcessHandle,
- _In_ BOOLEAN IsWow64,
- _In_ ULONG NumberOfHandles,
- _In_ PHANDLE AddressOfHandles,
- _In_ WAIT_TYPE WaitType,
- _In_ BOOLEAN Alertable,
- _Inout_ PPH_STRING_BUILDER StringBuilder
- )
-{
- NTSTATUS status;
- HANDLE handles[MAXIMUM_WAIT_OBJECTS];
- ULONG i;
-
- status = STATUS_SUCCESS;
-
- if (NumberOfHandles <= MAXIMUM_WAIT_OBJECTS)
- {
-#ifdef _WIN64
- if (IsWow64)
- {
- ULONG handles32[MAXIMUM_WAIT_OBJECTS];
-
- if (NT_SUCCESS(status = NtReadVirtualMemory(
- ProcessHandle,
- AddressOfHandles,
- handles32,
- NumberOfHandles * sizeof(ULONG),
- NULL
- )))
- {
- for (i = 0; i < NumberOfHandles; i++)
- handles[i] = UlongToHandle(handles32[i]);
- }
- }
- else
- {
-#endif
- status = NtReadVirtualMemory(
- ProcessHandle,
- AddressOfHandles,
- handles,
- NumberOfHandles * sizeof(HANDLE),
- NULL
- );
-#ifdef _WIN64
- }
-#endif
-
- if (NT_SUCCESS(status))
- {
- PhAppendFormatStringBuilder(
- StringBuilder,
- L"Thread is waiting (%s, %s) for:\r\n",
- Alertable ? L"alertable" : L"non-alertable",
- WaitType == WaitAll ? L"wait all" : L"wait any"
- );
-
- for (i = 0; i < NumberOfHandles; i++)
- {
- PhAppendStringBuilder(
- StringBuilder,
- &PhpaGetHandleString(ProcessHandle, handles[i])->sr
- );
- PhAppendStringBuilder2(
- StringBuilder,
- L"\r\n"
- );
- }
- }
- }
-
- if (!NT_SUCCESS(status) || NumberOfHandles > MAXIMUM_WAIT_OBJECTS)
- {
- PhAppendStringBuilder2(
- StringBuilder,
- L"Thread is waiting for multiple objects."
- );
- }
-}
-
-static PPH_STRING PhpaGetSendMessageReceiver(
- _In_ HANDLE ThreadId
- )
-{
- static _GetSendMessageReceiver GetSendMessageReceiver_I;
-
- HWND windowHandle;
- ULONG threadId;
- ULONG processId;
- CLIENT_ID clientId;
- PPH_STRING clientIdName;
- WCHAR windowClass[64];
- PPH_STRING windowText;
-
- // GetSendMessageReceiver is an undocumented function exported by
- // user32.dll. It retrieves the handle of the window which a thread
- // is sending a message to.
-
- if (!GetSendMessageReceiver_I)
- GetSendMessageReceiver_I = PhGetModuleProcAddress(L"user32.dll", "GetSendMessageReceiver");
-
- if (!GetSendMessageReceiver_I)
- return NULL;
-
- windowHandle = GetSendMessageReceiver_I(ThreadId);
-
- if (!windowHandle)
- return NULL;
-
- threadId = GetWindowThreadProcessId(windowHandle, &processId);
-
- clientId.UniqueProcess = UlongToHandle(processId);
- clientId.UniqueThread = UlongToHandle(threadId);
- clientIdName = PH_AUTO(PhGetClientIdName(&clientId));
-
- if (!GetClassName(windowHandle, windowClass, sizeof(windowClass) / sizeof(WCHAR)))
- windowClass[0] = 0;
-
- windowText = PH_AUTO(PhGetWindowText(windowHandle));
-
- return PhaFormatString(L"Window 0x%Ix (%s): %s \"%s\"", windowHandle, clientIdName->Buffer, windowClass, PhGetStringOrEmpty(windowText));
-}
-
-static PPH_STRING PhpaGetAlpcInformation(
- _In_ HANDLE ThreadId
- )
-{
- static _NtAlpcQueryInformation NtAlpcQueryInformation_I;
-
- NTSTATUS status;
- PPH_STRING string = NULL;
- HANDLE threadHandle;
- PALPC_SERVER_INFORMATION serverInfo;
- ULONG bufferLength;
-
- if (!NtAlpcQueryInformation_I)
- NtAlpcQueryInformation_I = PhGetModuleProcAddress(L"ntdll.dll", "NtAlpcQueryInformation");
-
- if (!NtAlpcQueryInformation_I)
- return NULL;
-
- if (!NT_SUCCESS(PhOpenThread(&threadHandle, THREAD_QUERY_INFORMATION, ThreadId)))
- return NULL;
-
- bufferLength = 0x110;
- serverInfo = PhAllocate(bufferLength);
- serverInfo->In.ThreadHandle = threadHandle;
-
- status = NtAlpcQueryInformation_I(NULL, AlpcServerInformation, serverInfo, bufferLength, &bufferLength);
-
- if (status == STATUS_INFO_LENGTH_MISMATCH)
- {
- PhFree(serverInfo);
- serverInfo = PhAllocate(bufferLength);
- serverInfo->In.ThreadHandle = threadHandle;
-
- status = NtAlpcQueryInformation_I(NULL, AlpcServerInformation, serverInfo, bufferLength, &bufferLength);
- }
-
- if (NT_SUCCESS(status) && serverInfo->Out.ThreadBlocked)
- {
- CLIENT_ID clientId;
- PPH_STRING clientIdName;
-
- clientId.UniqueProcess = serverInfo->Out.ConnectedProcessId;
- clientId.UniqueThread = NULL;
- clientIdName = PH_AUTO(PhGetClientIdName(&clientId));
-
- string = PhaFormatString(L"ALPC Port: %.*s (%s)", serverInfo->Out.ConnectionPortName.Length / 2, serverInfo->Out.ConnectionPortName.Buffer, clientIdName->Buffer);
- }
-
- PhFree(serverInfo);
- NtClose(threadHandle);
-
- return string;
-}
+/*
+ * Process Hacker -
+ * thread wait analysis
+ *
+ * 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 .
+ */
+
+/*
+ * There are two ways of seeing what a thread is waiting on. The first method
+ * is to walk the stack of a thread and read the arguments to whatever system
+ * call it is blocking on; this only works on x86 because on x64 the arguments
+ * are passed in registers (at least the first four are). The second method
+ * involves using the ThreadLastSystemCall info class for NtQueryInformationThread
+ * to retrieve the first argument to the system call the thread is blocking on.
+ * This is obviously only useful for NtWaitForSingleObject.
+ *
+ * There are other methods for specific scenarios, like USER messages and ALPC
+ * calls.
+ */
+
+#include
+
+#include
+#include
+
+#include
+
+typedef struct _ANALYZE_WAIT_CONTEXT
+{
+ BOOLEAN Found;
+ BOOLEAN IsWow64;
+ HANDLE ProcessId;
+ HANDLE ThreadId;
+ HANDLE ProcessHandle;
+
+ PPH_SYMBOL_PROVIDER SymbolProvider;
+ PH_STRING_BUILDER StringBuilder;
+
+ PVOID PrevParams[4];
+} ANALYZE_WAIT_CONTEXT, *PANALYZE_WAIT_CONTEXT;
+
+VOID PhpAnalyzeWaitPassive(
+ _In_ HWND hWnd,
+ _In_ HANDLE ProcessId,
+ _In_ HANDLE ThreadId
+ );
+
+BOOLEAN NTAPI PhpWalkThreadStackAnalyzeCallback(
+ _In_ PPH_THREAD_STACK_FRAME StackFrame,
+ _In_opt_ PVOID Context
+ );
+
+VOID PhpAnalyzeWaitFallbacks(
+ _In_ PANALYZE_WAIT_CONTEXT Context
+ );
+
+VOID PhpInitializeServiceNumbers(
+ VOID
+ );
+
+PPH_STRING PhpaGetHandleString(
+ _In_ HANDLE ProcessHandle,
+ _In_ HANDLE Handle
+ );
+
+VOID PhpGetWfmoInformation(
+ _In_ HANDLE ProcessHandle,
+ _In_ BOOLEAN IsWow64,
+ _In_ ULONG NumberOfHandles,
+ _In_ PHANDLE AddressOfHandles,
+ _In_ WAIT_TYPE WaitType,
+ _In_ BOOLEAN Alertable,
+ _Inout_ PPH_STRING_BUILDER StringBuilder
+ );
+
+PPH_STRING PhpaGetSendMessageReceiver(
+ _In_ HANDLE ThreadId
+ );
+
+PPH_STRING PhpaGetAlpcInformation(
+ _In_ HANDLE ThreadId
+ );
+
+static PH_INITONCE ServiceNumbersInitOnce = PH_INITONCE_INIT;
+static USHORT NumberForWfso = USHRT_MAX;
+static USHORT NumberForWfmo = USHRT_MAX;
+static USHORT NumberForRf = USHRT_MAX;
+
+VOID PhUiAnalyzeWaitThread(
+ _In_ HWND hWnd,
+ _In_ HANDLE ProcessId,
+ _In_ HANDLE ThreadId,
+ _In_ PPH_SYMBOL_PROVIDER SymbolProvider
+ )
+{
+ NTSTATUS status;
+ HANDLE threadHandle;
+#ifdef _WIN64
+ HANDLE processHandle;
+ BOOLEAN isWow64;
+#endif
+ CLIENT_ID clientId;
+ ANALYZE_WAIT_CONTEXT context;
+
+#ifdef _WIN64
+ // Determine if the process is WOW64. If not, we use the passive method.
+
+ if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, ProcessId)))
+ {
+ PhShowStatus(hWnd, L"Unable to open the process", status, 0);
+ return;
+ }
+
+ if (!NT_SUCCESS(status = PhGetProcessIsWow64(processHandle, &isWow64)) || !isWow64)
+ {
+ PhpAnalyzeWaitPassive(hWnd, ProcessId, ThreadId);
+ return;
+ }
+
+ NtClose(processHandle);
+#endif
+
+ if (!NT_SUCCESS(status = PhOpenThread(
+ &threadHandle,
+ THREAD_QUERY_LIMITED_INFORMATION | THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME,
+ ThreadId
+ )))
+ {
+ PhShowStatus(hWnd, L"Unable to open the thread.", status, 0);
+ return;
+ }
+
+ memset(&context, 0, sizeof(ANALYZE_WAIT_CONTEXT));
+ context.ProcessId = ProcessId;
+ context.ThreadId = ThreadId;
+
+ context.ProcessHandle = SymbolProvider->ProcessHandle;
+ context.SymbolProvider = SymbolProvider;
+ PhInitializeStringBuilder(&context.StringBuilder, 100);
+
+ clientId.UniqueProcess = ProcessId;
+ clientId.UniqueThread = ThreadId;
+
+ PhWalkThreadStack(
+ threadHandle,
+ SymbolProvider->ProcessHandle,
+ &clientId,
+ SymbolProvider,
+ PH_WALK_I386_STACK,
+ PhpWalkThreadStackAnalyzeCallback,
+ &context
+ );
+ NtClose(threadHandle);
+
+ PhpAnalyzeWaitFallbacks(&context);
+
+ if (context.Found)
+ {
+ PhShowInformationDialog(hWnd, context.StringBuilder.String->Buffer, 0);
+ }
+ else
+ {
+ PhShowInformation2(hWnd, L"The thread does not appear to be waiting.", L"");
+ }
+
+ PhDeleteStringBuilder(&context.StringBuilder);
+}
+
+VOID PhpAnalyzeWaitPassive(
+ _In_ HWND hWnd,
+ _In_ HANDLE ProcessId,
+ _In_ HANDLE ThreadId
+ )
+{
+ NTSTATUS status;
+ HANDLE processHandle;
+ HANDLE threadHandle;
+ THREAD_LAST_SYSCALL_INFORMATION lastSystemCall;
+ PH_STRING_BUILDER stringBuilder;
+ PPH_STRING string;
+
+ PhpInitializeServiceNumbers();
+
+ if (!NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_GET_CONTEXT, ThreadId)))
+ {
+ PhShowStatus(hWnd, L"Unable to open the thread.", status, 0);
+ return;
+ }
+
+ if (!NT_SUCCESS(status = PhGetThreadLastSystemCall(threadHandle, &lastSystemCall)))
+ {
+ NtClose(threadHandle);
+ PhShowStatus(hWnd, L"Unable to determine whether the thread is waiting.", status, 0);
+ return;
+ }
+
+ if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_DUP_HANDLE, ProcessId)))
+ {
+ NtClose(threadHandle);
+ PhShowStatus(hWnd, L"Unable to open the process.", status, 0);
+ return;
+ }
+
+ PhInitializeStringBuilder(&stringBuilder, 100);
+
+ if (lastSystemCall.SystemCallNumber == NumberForWfso)
+ {
+ string = PhpaGetHandleString(processHandle, lastSystemCall.FirstArgument);
+
+ PhAppendFormatStringBuilder(&stringBuilder, L"Thread is waiting for:\r\n");
+ PhAppendStringBuilder(&stringBuilder, &string->sr);
+ }
+ else if (lastSystemCall.SystemCallNumber == NumberForWfmo)
+ {
+ PhAppendFormatStringBuilder(&stringBuilder, L"Thread is waiting for multiple (%lu) objects.", PtrToUlong(lastSystemCall.FirstArgument));
+ }
+ else if (lastSystemCall.SystemCallNumber == NumberForRf)
+ {
+ string = PhpaGetHandleString(processHandle, lastSystemCall.FirstArgument);
+
+ PhAppendFormatStringBuilder(&stringBuilder, L"Thread is waiting for file I/O:\r\n");
+ PhAppendStringBuilder(&stringBuilder, &string->sr);
+ }
+ else
+ {
+ string = PhpaGetSendMessageReceiver(ThreadId);
+
+ if (string)
+ {
+ PhAppendStringBuilder2(&stringBuilder, L"Thread is sending a USER message:\r\n");
+ PhAppendStringBuilder(&stringBuilder, &string->sr);
+ }
+ else
+ {
+ string = PhpaGetAlpcInformation(ThreadId);
+
+ if (string)
+ {
+ PhAppendStringBuilder2(&stringBuilder, L"Thread is waiting for an ALPC port:\r\n");
+ PhAppendStringBuilder(&stringBuilder, &string->sr);
+ }
+ }
+ }
+
+ if (stringBuilder.String->Length == 0)
+ PhAppendStringBuilder2(&stringBuilder, L"Unable to determine why the thread is waiting.");
+
+ PhShowInformationDialog(hWnd, stringBuilder.String->Buffer, 0);
+
+ PhDeleteStringBuilder(&stringBuilder);
+ NtClose(processHandle);
+ NtClose(threadHandle);
+}
+
+static BOOLEAN NTAPI PhpWalkThreadStackAnalyzeCallback(
+ _In_ PPH_THREAD_STACK_FRAME StackFrame,
+ _In_opt_ PVOID Context
+ )
+{
+ PANALYZE_WAIT_CONTEXT context = (PANALYZE_WAIT_CONTEXT)Context;
+ PPH_STRING name;
+
+ name = PhGetSymbolFromAddress(
+ context->SymbolProvider,
+ (ULONG64)StackFrame->PcAddress,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ if (!name)
+ return TRUE;
+
+ context->Found = TRUE;
+
+#define FUNC_MATCH(Name) PhStartsWithString2(name, L##Name, TRUE)
+#define NT_FUNC_MATCH(Name) ( \
+ PhStartsWithString2(name, L"ntdll.dll!Nt" L##Name, TRUE) || \
+ PhStartsWithString2(name, L"ntdll.dll!Zw" L##Name, TRUE) \
+ )
+
+ if (!name)
+ {
+ // Dummy
+ }
+ else if (FUNC_MATCH("kernel32.dll!Sleep"))
+ {
+ PhAppendFormatStringBuilder(
+ &context->StringBuilder,
+ L"Thread is sleeping. Timeout: %lu milliseconds.",
+ PtrToUlong(StackFrame->Params[0])
+ );
+ }
+ else if (NT_FUNC_MATCH("DelayExecution"))
+ {
+ BOOLEAN alertable = !!StackFrame->Params[0];
+ PVOID timeoutAddress = StackFrame->Params[1];
+ LARGE_INTEGER timeout;
+
+ if (NT_SUCCESS(NtReadVirtualMemory(
+ context->ProcessHandle,
+ timeoutAddress,
+ &timeout,
+ sizeof(LARGE_INTEGER),
+ NULL
+ )))
+ {
+ if (timeout.QuadPart < 0)
+ {
+ PhAppendFormatStringBuilder(
+ &context->StringBuilder,
+ L"Thread is sleeping. Timeout: %I64u milliseconds.",
+ -timeout.QuadPart / PH_TIMEOUT_MS
+ );
+ }
+ else
+ {
+ // TODO
+ }
+ }
+ else
+ {
+ PhAppendStringBuilder2(
+ &context->StringBuilder,
+ L"Thread is sleeping."
+ );
+ }
+ }
+ else if (NT_FUNC_MATCH("DeviceIoControlFile"))
+ {
+ HANDLE handle = (HANDLE)StackFrame->Params[0];
+
+ PhAppendStringBuilder2(
+ &context->StringBuilder,
+ L"Thread is waiting for an I/O control request:\r\n"
+ );
+ PhAppendStringBuilder(
+ &context->StringBuilder,
+ &PhpaGetHandleString(context->ProcessHandle, handle)->sr
+ );
+ }
+ else if (NT_FUNC_MATCH("FsControlFile"))
+ {
+ HANDLE handle = StackFrame->Params[0];
+
+ PhAppendStringBuilder2(
+ &context->StringBuilder,
+ L"Thread is waiting for a FS control request:\r\n"
+ );
+ PhAppendStringBuilder(
+ &context->StringBuilder,
+ &PhpaGetHandleString(context->ProcessHandle, handle)->sr
+ );
+ }
+ else if (NT_FUNC_MATCH("QueryObject"))
+ {
+ HANDLE handle = StackFrame->Params[0];
+
+ // Use the KiFastSystemCall args if the handle we have is wrong.
+ if ((ULONG_PTR)handle % 4 != 0 || !handle)
+ handle = context->PrevParams[1];
+
+ PhAppendStringBuilder2(
+ &context->StringBuilder,
+ L"Thread is querying an object:\r\n"
+ );
+ PhAppendStringBuilder(
+ &context->StringBuilder,
+ &PhpaGetHandleString(context->ProcessHandle, handle)->sr
+ );
+ }
+ else if (NT_FUNC_MATCH("ReadFile") || NT_FUNC_MATCH("WriteFile"))
+ {
+ HANDLE handle = StackFrame->Params[0];
+
+ PhAppendStringBuilder2(
+ &context->StringBuilder,
+ L"Thread is waiting for file I/O:\r\n"
+ );
+ PhAppendStringBuilder(
+ &context->StringBuilder,
+ &PhpaGetHandleString(context->ProcessHandle, handle)->sr
+ );
+ }
+ else if (NT_FUNC_MATCH("RemoveIoCompletion"))
+ {
+ HANDLE handle = StackFrame->Params[0];
+
+ PhAppendStringBuilder2(
+ &context->StringBuilder,
+ L"Thread is waiting for an I/O completion port:\r\n"
+ );
+ PhAppendStringBuilder(
+ &context->StringBuilder,
+ &PhpaGetHandleString(context->ProcessHandle, handle)->sr
+ );
+ }
+ else if (
+ NT_FUNC_MATCH("ReplyWaitReceivePort") ||
+ NT_FUNC_MATCH("RequestWaitReplyPort") ||
+ NT_FUNC_MATCH("AlpcSendWaitReceivePort")
+ )
+ {
+ HANDLE handle = StackFrame->Params[0];
+ PPH_STRING alpcInfo;
+
+ PhAppendStringBuilder2(
+ &context->StringBuilder,
+ L"Thread is waiting for an ALPC port:\r\n"
+ );
+ PhAppendStringBuilder(
+ &context->StringBuilder,
+ &PhpaGetHandleString(context->ProcessHandle, handle)->sr
+ );
+
+ if (alpcInfo = PhpaGetAlpcInformation(context->ThreadId))
+ {
+ PhAppendStringBuilder2(
+ &context->StringBuilder,
+ L"\r\n"
+ );
+ PhAppendStringBuilder(
+ &context->StringBuilder,
+ &alpcInfo->sr
+ );
+ }
+ }
+ else if (
+ NT_FUNC_MATCH("SetHighWaitLowEventPair") ||
+ NT_FUNC_MATCH("SetLowWaitHighEventPair") ||
+ NT_FUNC_MATCH("WaitHighEventPair") ||
+ NT_FUNC_MATCH("WaitLowEventPair")
+ )
+ {
+ HANDLE handle = StackFrame->Params[0];
+
+ if ((ULONG_PTR)handle % 4 != 0 || !handle)
+ handle = context->PrevParams[1];
+
+ PhAppendFormatStringBuilder(
+ &context->StringBuilder,
+ L"Thread is waiting (%s) for an event pair:\r\n",
+ name->Buffer
+ );
+ PhAppendStringBuilder(
+ &context->StringBuilder,
+ &PhpaGetHandleString(context->ProcessHandle, handle)->sr
+ );
+ }
+ else if (
+ FUNC_MATCH("user32.dll!NtUserGetMessage") ||
+ FUNC_MATCH("user32.dll!NtUserWaitMessage")
+ )
+ {
+ PhAppendStringBuilder2(
+ &context->StringBuilder,
+ L"Thread is waiting for a USER message.\r\n"
+ );
+ }
+ else if (FUNC_MATCH("user32.dll!NtUserMessageCall"))
+ {
+ PPH_STRING receiverString;
+
+ PhAppendStringBuilder2(
+ &context->StringBuilder,
+ L"Thread is sending a USER message:\r\n"
+ );
+
+ receiverString = PhpaGetSendMessageReceiver(context->ThreadId);
+
+ if (receiverString)
+ {
+ PhAppendStringBuilder(&context->StringBuilder, &receiverString->sr);
+ PhAppendStringBuilder2(&context->StringBuilder, L"\r\n");
+ }
+ else
+ {
+ PhAppendStringBuilder2(&context->StringBuilder, L"Unknown.\r\n");
+ }
+ }
+ else if (NT_FUNC_MATCH("WaitForDebugEvent"))
+ {
+ HANDLE handle = StackFrame->Params[0];
+
+ PhAppendStringBuilder2(
+ &context->StringBuilder,
+ L"Thread is waiting for a debug event:\r\n"
+ );
+ PhAppendStringBuilder(
+ &context->StringBuilder,
+ &PhpaGetHandleString(context->ProcessHandle, handle)->sr
+ );
+ }
+ else if (
+ NT_FUNC_MATCH("WaitForKeyedEvent") ||
+ NT_FUNC_MATCH("ReleaseKeyedEvent")
+ )
+ {
+ HANDLE handle = StackFrame->Params[0];
+ PVOID key = StackFrame->Params[1];
+
+ PhAppendFormatStringBuilder(
+ &context->StringBuilder,
+ L"Thread is waiting (%s) for a keyed event (key 0x%Ix):\r\n",
+ name->Buffer,
+ key
+ );
+ PhAppendStringBuilder(
+ &context->StringBuilder,
+ &PhpaGetHandleString(context->ProcessHandle, handle)->sr
+ );
+ }
+ else if (
+ NT_FUNC_MATCH("WaitForMultipleObjects") ||
+ FUNC_MATCH("kernel32.dll!WaitForMultipleObjects")
+ )
+ {
+ ULONG numberOfHandles = PtrToUlong(StackFrame->Params[0]);
+ PVOID addressOfHandles = StackFrame->Params[1];
+ WAIT_TYPE waitType = (WAIT_TYPE)StackFrame->Params[2];
+ BOOLEAN alertable = !!StackFrame->Params[3];
+
+ if (numberOfHandles > MAXIMUM_WAIT_OBJECTS)
+ {
+ numberOfHandles = PtrToUlong(context->PrevParams[1]);
+ addressOfHandles = context->PrevParams[2];
+ waitType = (WAIT_TYPE)context->PrevParams[3];
+ alertable = FALSE;
+ }
+
+ PhpGetWfmoInformation(
+ context->ProcessHandle,
+ TRUE, // on x64 this function is only called for WOW64 processes
+ numberOfHandles,
+ addressOfHandles,
+ waitType,
+ alertable,
+ &context->StringBuilder
+ );
+ }
+ else if (
+ NT_FUNC_MATCH("WaitForSingleObject") ||
+ FUNC_MATCH("kernel32.dll!WaitForSingleObject")
+ )
+ {
+ HANDLE handle = StackFrame->Params[0];
+ BOOLEAN alertable = !!StackFrame->Params[1];
+
+ if ((ULONG_PTR)handle % 4 != 0 || !handle)
+ {
+ handle = context->PrevParams[1];
+ alertable = !!context->PrevParams[2];
+ }
+
+ PhAppendFormatStringBuilder(
+ &context->StringBuilder,
+ L"Thread is waiting (%s) for:\r\n",
+ alertable ? L"alertable" : L"non-alertable"
+ );
+ PhAppendStringBuilder(
+ &context->StringBuilder,
+ &PhpaGetHandleString(context->ProcessHandle, handle)->sr
+ );
+ }
+ else if (NT_FUNC_MATCH("WaitForWorkViaWorkerFactory"))
+ {
+ HANDLE handle = StackFrame->Params[0];
+
+ PhAppendStringBuilder2(
+ &context->StringBuilder,
+ L"Thread is waiting for work from a worker factory:\r\n"
+ );
+ PhAppendStringBuilder(
+ &context->StringBuilder,
+ &PhpaGetHandleString(context->ProcessHandle, handle)->sr
+ );
+ }
+ else
+ {
+ context->Found = FALSE;
+ }
+
+ PhDereferenceObject(name);
+ memcpy(&context->PrevParams, StackFrame->Params, sizeof(StackFrame->Params));
+
+ return !context->Found;
+}
+
+static VOID PhpAnalyzeWaitFallbacks(
+ _In_ PANALYZE_WAIT_CONTEXT Context
+ )
+{
+ PPH_STRING info;
+
+ // We didn't detect NtUserMessageCall, but this may still apply due to another
+ // win32k system call (e.g. from EnableWindow).
+ if (!Context->Found && (info = PhpaGetSendMessageReceiver(Context->ThreadId)))
+ {
+ PhAppendStringBuilder2(
+ &Context->StringBuilder,
+ L"Thread is sending a USER message:\r\n"
+ );
+ PhAppendStringBuilder(&Context->StringBuilder, &info->sr);
+ PhAppendStringBuilder2(&Context->StringBuilder, L"\r\n");
+
+ Context->Found = TRUE;
+ }
+
+ // Nt(Alpc)ConnectPort doesn't get detected anywhere else.
+ if (!Context->Found && (info = PhpaGetAlpcInformation(Context->ThreadId)))
+ {
+ PhAppendStringBuilder2(
+ &Context->StringBuilder,
+ L"Thread is waiting for an ALPC port:\r\n"
+ );
+ PhAppendStringBuilder(&Context->StringBuilder, &info->sr);
+ PhAppendStringBuilder2(&Context->StringBuilder, L"\r\n");
+
+ Context->Found = TRUE;
+ }
+}
+
+static BOOLEAN PhpWaitUntilThreadIsWaiting(
+ _In_ HANDLE ThreadHandle
+ )
+{
+ ULONG attempts;
+ BOOLEAN isWaiting = FALSE;
+ THREAD_BASIC_INFORMATION basicInfo;
+
+ if (!NT_SUCCESS(PhGetThreadBasicInformation(ThreadHandle, &basicInfo)))
+ return FALSE;
+
+ for (attempts = 0; attempts < 20; attempts++)
+ {
+ PVOID processes;
+ PSYSTEM_PROCESS_INFORMATION processInfo;
+ ULONG i;
+
+ PhDelayExecution(100);
+
+ if (!NT_SUCCESS(PhEnumProcesses(&processes)))
+ break;
+
+ processInfo = PhFindProcessInformation(processes, basicInfo.ClientId.UniqueProcess);
+
+ if (processInfo)
+ {
+ for (i = 0; i < processInfo->NumberOfThreads; i++)
+ {
+ if (
+ processInfo->Threads[i].ClientId.UniqueThread == basicInfo.ClientId.UniqueThread &&
+ processInfo->Threads[i].ThreadState == Waiting &&
+ (processInfo->Threads[i].WaitReason == UserRequest ||
+ processInfo->Threads[i].WaitReason == Executive)
+ )
+ {
+ isWaiting = TRUE;
+ break;
+ }
+ }
+ }
+
+ PhFree(processes);
+
+ if (isWaiting)
+ break;
+
+ PhDelayExecution(500);
+ }
+
+ return isWaiting;
+}
+
+static VOID PhpGetThreadLastSystemCallNumber(
+ _In_ HANDLE ThreadHandle,
+ _Out_ PUSHORT LastSystemCallNumber
+ )
+{
+ THREAD_LAST_SYSCALL_INFORMATION lastSystemCall;
+
+ if (NT_SUCCESS(PhGetThreadLastSystemCall(ThreadHandle, &lastSystemCall)))
+ {
+ *LastSystemCallNumber = lastSystemCall.SystemCallNumber;
+ }
+}
+
+static NTSTATUS PhpWfsoThreadStart(
+ _In_ PVOID Parameter
+ )
+{
+ HANDLE eventHandle;
+ LARGE_INTEGER timeout;
+
+ eventHandle = Parameter;
+
+ timeout.QuadPart = -(LONGLONG)UInt32x32To64(5, PH_TIMEOUT_SEC);
+ NtWaitForSingleObject(eventHandle, FALSE, &timeout);
+
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS PhpWfmoThreadStart(
+ _In_ PVOID Parameter
+ )
+{
+ HANDLE eventHandle;
+ LARGE_INTEGER timeout;
+
+ eventHandle = Parameter;
+
+ timeout.QuadPart = -(LONGLONG)UInt32x32To64(5, PH_TIMEOUT_SEC);
+ NtWaitForMultipleObjects(1, &eventHandle, WaitAll, FALSE, &timeout);
+
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS PhpRfThreadStart(
+ _In_ PVOID Parameter
+ )
+{
+ HANDLE fileHandle;
+ IO_STATUS_BLOCK isb;
+ ULONG data;
+
+ fileHandle = Parameter;
+
+ NtReadFile(fileHandle, NULL, NULL, NULL, &isb, &data, sizeof(ULONG), NULL, NULL);
+
+ return STATUS_SUCCESS;
+}
+
+static VOID PhpInitializeServiceNumbers(
+ VOID
+ )
+{
+ if (PhBeginInitOnce(&ServiceNumbersInitOnce))
+ {
+ NTSTATUS status;
+ HANDLE eventHandle;
+ HANDLE threadHandle;
+ HANDLE pipeReadHandle;
+ HANDLE pipeWriteHandle;
+
+ // The ThreadLastSystemCall info class only works when the thread is in the Waiting
+ // state. We'll create a thread which blocks on an event object we create, then wait
+ // until it is in the Waiting state. Only then can we query the thread using
+ // ThreadLastSystemCall.
+
+ // NtWaitForSingleObject
+
+ status = NtCreateEvent(&eventHandle, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE);
+
+ if (NT_SUCCESS(status))
+ {
+ if (NT_SUCCESS(PhCreateThreadEx(&threadHandle, PhpWfsoThreadStart, eventHandle)))
+ {
+ if (PhpWaitUntilThreadIsWaiting(threadHandle))
+ {
+ PhpGetThreadLastSystemCallNumber(threadHandle, &NumberForWfso);
+ }
+
+ // Allow the thread to exit.
+ NtSetEvent(eventHandle, NULL);
+ NtClose(threadHandle);
+ }
+
+ NtClose(eventHandle);
+ }
+
+ // NtWaitForMultipleObjects
+
+ status = NtCreateEvent(&eventHandle, EVENT_ALL_ACCESS, NULL, NotificationEvent, FALSE);
+
+ if (NT_SUCCESS(status))
+ {
+ if (NT_SUCCESS(PhCreateThreadEx(&threadHandle, PhpWfmoThreadStart, eventHandle)))
+ {
+ if (PhpWaitUntilThreadIsWaiting(threadHandle))
+ {
+ PhpGetThreadLastSystemCallNumber(threadHandle, &NumberForWfmo);
+ }
+
+ NtSetEvent(eventHandle, NULL);
+ NtClose(threadHandle);
+ }
+
+ NtClose(eventHandle);
+ }
+
+ // NtReadFile
+
+ status = PhCreatePipe(&pipeReadHandle, &pipeWriteHandle);
+
+ if (NT_SUCCESS(status))
+ {
+ if (NT_SUCCESS(PhCreateThreadEx(&threadHandle, PhpRfThreadStart, pipeReadHandle)))
+ {
+ ULONG data = 0;
+ IO_STATUS_BLOCK isb;
+
+ if (PhpWaitUntilThreadIsWaiting(threadHandle))
+ {
+ PhpGetThreadLastSystemCallNumber(threadHandle, &NumberForRf);
+ }
+
+ NtWriteFile(pipeWriteHandle, NULL, NULL, NULL, &isb, &data, sizeof(data), NULL, NULL);
+ NtClose(threadHandle);
+ }
+
+ NtClose(pipeReadHandle);
+ NtClose(pipeWriteHandle);
+ }
+
+ PhEndInitOnce(&ServiceNumbersInitOnce);
+ }
+}
+
+static PPH_STRING PhpaGetHandleString(
+ _In_ HANDLE ProcessHandle,
+ _In_ HANDLE Handle
+ )
+{
+ PPH_STRING typeName = NULL;
+ PPH_STRING name = NULL;
+ PPH_STRING result;
+
+ PhGetHandleInformation(
+ ProcessHandle,
+ Handle,
+ -1,
+ NULL,
+ &typeName,
+ NULL,
+ &name
+ );
+ PH_AUTO(typeName);
+ PH_AUTO(name);
+
+ if (typeName && name)
+ {
+ result = PhaFormatString(
+ L"Handle 0x%Ix (%s): %s",
+ Handle,
+ typeName->Buffer,
+ !PhIsNullOrEmptyString(name) ? name->Buffer : L"(unnamed object)"
+ );
+ }
+ else
+ {
+ result = PhaFormatString(
+ L"Handle 0x%Ix: (error querying handle)",
+ Handle
+ );
+ }
+
+ return result;
+}
+
+static VOID PhpGetWfmoInformation(
+ _In_ HANDLE ProcessHandle,
+ _In_ BOOLEAN IsWow64,
+ _In_ ULONG NumberOfHandles,
+ _In_ PHANDLE AddressOfHandles,
+ _In_ WAIT_TYPE WaitType,
+ _In_ BOOLEAN Alertable,
+ _Inout_ PPH_STRING_BUILDER StringBuilder
+ )
+{
+ NTSTATUS status;
+ HANDLE handles[MAXIMUM_WAIT_OBJECTS];
+ ULONG i;
+
+ status = STATUS_SUCCESS;
+
+ if (NumberOfHandles <= MAXIMUM_WAIT_OBJECTS)
+ {
+#ifdef _WIN64
+ if (IsWow64)
+ {
+ ULONG handles32[MAXIMUM_WAIT_OBJECTS];
+
+ if (NT_SUCCESS(status = NtReadVirtualMemory(
+ ProcessHandle,
+ AddressOfHandles,
+ handles32,
+ NumberOfHandles * sizeof(ULONG),
+ NULL
+ )))
+ {
+ for (i = 0; i < NumberOfHandles; i++)
+ handles[i] = UlongToHandle(handles32[i]);
+ }
+ }
+ else
+ {
+#endif
+ status = NtReadVirtualMemory(
+ ProcessHandle,
+ AddressOfHandles,
+ handles,
+ NumberOfHandles * sizeof(HANDLE),
+ NULL
+ );
+#ifdef _WIN64
+ }
+#endif
+
+ if (NT_SUCCESS(status))
+ {
+ PhAppendFormatStringBuilder(
+ StringBuilder,
+ L"Thread is waiting (%s, %s) for:\r\n",
+ Alertable ? L"alertable" : L"non-alertable",
+ WaitType == WaitAll ? L"wait all" : L"wait any"
+ );
+
+ for (i = 0; i < NumberOfHandles; i++)
+ {
+ PhAppendStringBuilder(
+ StringBuilder,
+ &PhpaGetHandleString(ProcessHandle, handles[i])->sr
+ );
+ PhAppendStringBuilder2(
+ StringBuilder,
+ L"\r\n"
+ );
+ }
+ }
+ }
+
+ if (!NT_SUCCESS(status) || NumberOfHandles > MAXIMUM_WAIT_OBJECTS)
+ {
+ PhAppendStringBuilder2(
+ StringBuilder,
+ L"Thread is waiting for multiple objects."
+ );
+ }
+}
+
+static PPH_STRING PhpaGetSendMessageReceiver(
+ _In_ HANDLE ThreadId
+ )
+{
+ static HWND (WINAPI *GetSendMessageReceiver_I)(
+ _In_ HANDLE ThreadId
+ );
+
+ HWND windowHandle;
+ ULONG threadId;
+ ULONG processId;
+ CLIENT_ID clientId;
+ PPH_STRING clientIdName;
+ WCHAR windowClass[64];
+ PPH_STRING windowText;
+
+ // GetSendMessageReceiver is an undocumented function exported by
+ // user32.dll. It retrieves the handle of the window which a thread
+ // is sending a message to.
+
+ if (!GetSendMessageReceiver_I)
+ GetSendMessageReceiver_I = PhGetDllProcedureAddress(L"user32.dll", "GetSendMessageReceiver", 0);
+
+ if (!GetSendMessageReceiver_I)
+ return NULL;
+
+ windowHandle = GetSendMessageReceiver_I(ThreadId);
+
+ if (!windowHandle)
+ return NULL;
+
+ threadId = GetWindowThreadProcessId(windowHandle, &processId);
+
+ clientId.UniqueProcess = UlongToHandle(processId);
+ clientId.UniqueThread = UlongToHandle(threadId);
+ clientIdName = PH_AUTO(PhGetClientIdName(&clientId));
+
+ if (!GetClassName(windowHandle, windowClass, sizeof(windowClass) / sizeof(WCHAR)))
+ windowClass[0] = UNICODE_NULL;
+
+ windowText = PH_AUTO(PhGetWindowText(windowHandle));
+
+ return PhaFormatString(L"Window 0x%Ix (%s): %s \"%s\"", windowHandle, clientIdName->Buffer, windowClass, PhGetStringOrEmpty(windowText));
+}
+
+PPH_STRING PhpaGetAlpcInformation(
+ _In_ HANDLE ThreadId
+ )
+{
+ NTSTATUS status;
+ PPH_STRING string = NULL;
+ HANDLE threadHandle;
+ PALPC_SERVER_INFORMATION serverInfo;
+ ULONG bufferLength;
+
+ if (!NT_SUCCESS(PhOpenThread(&threadHandle, THREAD_QUERY_INFORMATION, ThreadId)))
+ return NULL;
+
+ bufferLength = 0x110;
+ serverInfo = PhAllocate(bufferLength);
+ serverInfo->In.ThreadHandle = threadHandle;
+
+ status = NtAlpcQueryInformation(NULL, AlpcServerInformation, serverInfo, bufferLength, &bufferLength);
+
+ if (status == STATUS_INFO_LENGTH_MISMATCH)
+ {
+ PhFree(serverInfo);
+ serverInfo = PhAllocate(bufferLength);
+ serverInfo->In.ThreadHandle = threadHandle;
+
+ status = NtAlpcQueryInformation(NULL, AlpcServerInformation, serverInfo, bufferLength, &bufferLength);
+ }
+
+ if (NT_SUCCESS(status) && serverInfo->Out.ThreadBlocked)
+ {
+ CLIENT_ID clientId;
+ PPH_STRING clientIdName;
+
+ clientId.UniqueProcess = serverInfo->Out.ConnectedProcessId;
+ clientId.UniqueThread = NULL;
+ clientIdName = PH_AUTO(PhGetClientIdName(&clientId));
+
+ string = PhaFormatString(L"ALPC Port: %.*s (%s)", serverInfo->Out.ConnectionPortName.Length / sizeof(WCHAR), serverInfo->Out.ConnectionPortName.Buffer, clientIdName->Buffer);
+ }
+
+ PhFree(serverInfo);
+ NtClose(threadHandle);
+
+ return string;
+}
diff --git a/ProcessHacker/appsup.c b/ProcessHacker/appsup.c
index fa61833b5fda..4986206d7212 100644
--- a/ProcessHacker/appsup.c
+++ b/ProcessHacker/appsup.c
@@ -1,2207 +1,2142 @@
-/*
- * Process Hacker -
- * application support functions
- *
- * Copyright (C) 2010-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 .
- */
-
-#include
-
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-
-#include "mxml/mxml.h"
-#include "pcre/pcre2.h"
-
-typedef LONG (WINAPI *_GetPackageFullName)(
- _In_ HANDLE hProcess,
- _Inout_ UINT32 *packageFullNameLength,
- _Out_opt_ PWSTR packageFullName
- );
-
-typedef LONG (WINAPI *_GetPackagePath)(
- _In_ PACKAGE_ID *packageId,
- _Reserved_ UINT32 reserved,
- _Inout_ UINT32 *pathLength,
- _Out_opt_ PWSTR path
- );
-
-typedef LONG (WINAPI *_PackageIdFromFullName)(
- _In_ PCWSTR packageFullName,
- _In_ UINT32 flags,
- _Inout_ UINT32 *bufferLength,
- _Out_opt_ BYTE *buffer
- );
-
-GUID XP_CONTEXT_GUID = { 0xbeb1b341, 0x6837, 0x4c83, { 0x83, 0x66, 0x2b, 0x45, 0x1e, 0x7c, 0xe6, 0x9b } };
-GUID VISTA_CONTEXT_GUID = { 0xe2011457, 0x1546, 0x43c5, { 0xa5, 0xfe, 0x00, 0x8d, 0xee, 0xe3, 0xd3, 0xf0 } };
-GUID WIN7_CONTEXT_GUID = { 0x35138b9a, 0x5d96, 0x4fbd, { 0x8e, 0x2d, 0xa2, 0x44, 0x02, 0x25, 0xf9, 0x3a } };
-GUID WIN8_CONTEXT_GUID = { 0x4a2f28e3, 0x53b9, 0x4441, { 0xba, 0x9c, 0xd6, 0x9d, 0x4a, 0x4a, 0x6e, 0x38 } };
-GUID WINBLUE_CONTEXT_GUID = { 0x1f676c76, 0x80e1, 0x4239, { 0x95, 0xbb, 0x83, 0xd0, 0xf6, 0xd0, 0xda, 0x78 } };
-GUID WINTHRESHOLD_CONTEXT_GUID = { 0x8e0f7a12, 0xbfb3, 0x4fe8, { 0xb9, 0xa5, 0x48, 0xfd, 0x50, 0xa1, 0x5a, 0x9a } };
-
-/**
- * Determines whether a process is suspended.
- *
- * \param Process The SYSTEM_PROCESS_INFORMATION structure
- * of the process.
- */
-BOOLEAN PhGetProcessIsSuspended(
- _In_ PSYSTEM_PROCESS_INFORMATION Process
- )
-{
- ULONG i;
-
- for (i = 0; i < Process->NumberOfThreads; i++)
- {
- if (
- Process->Threads[i].ThreadState != Waiting ||
- Process->Threads[i].WaitReason != Suspended
- )
- return FALSE;
- }
-
- return Process->NumberOfThreads != 0;
-}
-
-/**
- * Determines the OS compatibility context of a process.
- *
- * \param ProcessHandle A handle to a process.
- * \param Guid A variable which receives a GUID identifying an
- * operating system version.
- */
-NTSTATUS PhGetProcessSwitchContext(
- _In_ HANDLE ProcessHandle,
- _Out_ PGUID Guid
- )
-{
- NTSTATUS status;
- PROCESS_BASIC_INFORMATION basicInfo;
-#ifdef _WIN64
- PVOID peb32;
- ULONG data32;
-#endif
- PVOID data;
-
- // Reverse-engineered from WdcGetProcessSwitchContext (wdc.dll).
- // On Windows 8, the function is now SdbGetAppCompatData (apphelp.dll).
- // On Windows 10, the function is again WdcGetProcessSwitchContext.
-
-#ifdef _WIN64
- if (NT_SUCCESS(PhGetProcessPeb32(ProcessHandle, &peb32)) && peb32)
- {
- if (WindowsVersion >= WINDOWS_8)
- {
- if (!NT_SUCCESS(status = NtReadVirtualMemory(
- ProcessHandle,
- PTR_ADD_OFFSET(peb32, FIELD_OFFSET(PEB32, pShimData)),
- &data32,
- sizeof(ULONG),
- NULL
- )))
- return status;
- }
- else
- {
- if (!NT_SUCCESS(status = NtReadVirtualMemory(
- ProcessHandle,
- PTR_ADD_OFFSET(peb32, FIELD_OFFSET(PEB32, pContextData)),
- &data32,
- sizeof(ULONG),
- NULL
- )))
- return status;
- }
-
- data = UlongToPtr(data32);
- }
- else
- {
-#endif
- if (!NT_SUCCESS(status = PhGetProcessBasicInformation(ProcessHandle, &basicInfo)))
- return status;
-
- if (WindowsVersion >= WINDOWS_8)
- {
- if (!NT_SUCCESS(status = NtReadVirtualMemory(
- ProcessHandle,
- PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, pShimData)),
- &data,
- sizeof(PVOID),
- NULL
- )))
- return status;
- }
- else
- {
- if (!NT_SUCCESS(status = NtReadVirtualMemory(
- ProcessHandle,
- PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, pContextData)),
- &data,
- sizeof(PVOID),
- NULL
- )))
- return status;
- }
-#ifdef _WIN64
- }
-#endif
-
- if (!data)
- return STATUS_UNSUCCESSFUL; // no compatibility context data
-
- if (WindowsVersion >= WINDOWS_10)
- {
- if (!NT_SUCCESS(status = NtReadVirtualMemory(
- ProcessHandle,
- PTR_ADD_OFFSET(data, 2040 + 24), // Magic value from SbReadProcContextByHandle
- Guid,
- sizeof(GUID),
- NULL
- )))
- return status;
- }
- else if (WindowsVersion >= WINDOWS_8_1)
- {
- if (!NT_SUCCESS(status = NtReadVirtualMemory(
- ProcessHandle,
- PTR_ADD_OFFSET(data, 2040 + 16), // Magic value from SbReadProcContextByHandle
- Guid,
- sizeof(GUID),
- NULL
- )))
- return status;
- }
- else if (WindowsVersion >= WINDOWS_8)
- {
- if (!NT_SUCCESS(status = NtReadVirtualMemory(
- ProcessHandle,
- PTR_ADD_OFFSET(data, 2040), // Magic value from SbReadProcContextByHandle
- Guid,
- sizeof(GUID),
- NULL
- )))
- return status;
- }
- else
- {
- if (!NT_SUCCESS(status = NtReadVirtualMemory(
- ProcessHandle,
- PTR_ADD_OFFSET(data, 32), // Magic value from WdcGetProcessSwitchContext
- Guid,
- sizeof(GUID),
- NULL
- )))
- return status;
- }
-
- return STATUS_SUCCESS;
-}
-
-PPH_STRING PhGetProcessPackageFullName(
- _In_ HANDLE ProcessHandle
- )
-{
- static _GetPackageFullName getPackageFullName = NULL;
-
- LONG result;
- PPH_STRING name;
- ULONG nameLength;
-
- if (!getPackageFullName)
- getPackageFullName = PhGetModuleProcAddress(L"kernel32.dll", "GetPackageFullName");
- if (!getPackageFullName)
- return NULL;
-
- nameLength = 101;
- name = PhCreateStringEx(NULL, (nameLength - 1) * 2);
-
- result = getPackageFullName(ProcessHandle, &nameLength, name->Buffer);
-
- if (result == ERROR_INSUFFICIENT_BUFFER)
- {
- PhDereferenceObject(name);
- name = PhCreateStringEx(NULL, (nameLength - 1) * 2);
-
- result = getPackageFullName(ProcessHandle, &nameLength, name->Buffer);
- }
-
- if (result == ERROR_SUCCESS)
- {
- PhTrimToNullTerminatorString(name);
- return name;
- }
- else
- {
- PhDereferenceObject(name);
- return NULL;
- }
-}
-
-PACKAGE_ID *PhPackageIdFromFullName(
- _In_ PWSTR PackageFullName
- )
-{
- static _PackageIdFromFullName packageIdFromFullName = NULL;
-
- LONG result;
- PVOID packageIdBuffer;
- ULONG packageIdBufferSize;
-
- if (!packageIdFromFullName)
- packageIdFromFullName = PhGetModuleProcAddress(L"kernel32.dll", "PackageIdFromFullName");
- if (!packageIdFromFullName)
- return NULL;
-
- packageIdBufferSize = 100;
- packageIdBuffer = PhAllocate(packageIdBufferSize);
-
- result = packageIdFromFullName(PackageFullName, PACKAGE_INFORMATION_BASIC, &packageIdBufferSize, (PBYTE)packageIdBuffer);
-
- if (result == ERROR_INSUFFICIENT_BUFFER)
- {
- PhFree(packageIdBuffer);
- packageIdBuffer = PhAllocate(packageIdBufferSize);
-
- result = packageIdFromFullName(PackageFullName, PACKAGE_INFORMATION_BASIC, &packageIdBufferSize, (PBYTE)packageIdBuffer);
- }
-
- if (result == ERROR_SUCCESS)
- {
- return packageIdBuffer;
- }
- else
- {
- PhFree(packageIdBuffer);
- return NULL;
- }
-}
-
-PPH_STRING PhGetPackagePath(
- _In_ PACKAGE_ID *PackageId
- )
-{
- static _GetPackagePath getPackagePath = NULL;
-
- LONG result;
- PPH_STRING path;
- ULONG pathLength;
-
- if (!getPackagePath)
- getPackagePath = PhGetModuleProcAddress(L"kernel32.dll", "GetPackagePath");
- if (!getPackagePath)
- return NULL;
-
- pathLength = 101;
- path = PhCreateStringEx(NULL, (pathLength - 1) * 2);
-
- result = getPackagePath(PackageId, 0, &pathLength, path->Buffer);
-
- if (result == ERROR_INSUFFICIENT_BUFFER)
- {
- PhDereferenceObject(path);
- path = PhCreateStringEx(NULL, (pathLength - 1) * 2);
-
- result = getPackagePath(PackageId, 0, &pathLength, path->Buffer);
- }
-
- if (result == ERROR_SUCCESS)
- {
- PhTrimToNullTerminatorString(path);
- return path;
- }
- else
- {
- PhDereferenceObject(path);
- return NULL;
- }
-}
-
-/**
- * Determines the type of a process based on its image file name.
- *
- * \param ProcessHandle A handle to a process.
- * \param KnownProcessType A variable which receives the process
- * type.
- */
-NTSTATUS PhGetProcessKnownType(
- _In_ HANDLE ProcessHandle,
- _Out_ PH_KNOWN_PROCESS_TYPE *KnownProcessType
- )
-{
- NTSTATUS status;
- PH_KNOWN_PROCESS_TYPE knownProcessType;
- PROCESS_BASIC_INFORMATION basicInfo;
- PH_STRINGREF systemRootPrefix;
- PPH_STRING fileName;
- PPH_STRING newFileName;
- PH_STRINGREF name;
-#ifdef _WIN64
- BOOLEAN isWow64 = FALSE;
-#endif
-
- if (!NT_SUCCESS(status = PhGetProcessBasicInformation(
- ProcessHandle,
- &basicInfo
- )))
- return status;
-
- if (basicInfo.UniqueProcessId == SYSTEM_PROCESS_ID)
- {
- *KnownProcessType = SystemProcessType;
- return STATUS_SUCCESS;
- }
-
- PhGetSystemRoot(&systemRootPrefix);
-
- if (!NT_SUCCESS(status = PhGetProcessImageFileName(
- ProcessHandle,
- &fileName
- )))
- {
- return status;
- }
-
- newFileName = PhGetFileName(fileName);
- PhDereferenceObject(fileName);
- name = newFileName->sr;
-
- knownProcessType = UnknownProcessType;
-
- if (PhStartsWithStringRef(&name, &systemRootPrefix, TRUE))
- {
- // Skip the system root, and we now have three cases:
- // 1. \\xyz.exe - Windows executable.
- // 2. \\System32\\xyz.exe - system32 executable.
- // 3. \\SysWow64\\xyz.exe - system32 executable + WOW64.
- PhSkipStringRef(&name, systemRootPrefix.Length);
-
- if (PhEqualStringRef2(&name, L"\\explorer.exe", TRUE))
- {
- knownProcessType = ExplorerProcessType;
- }
- else if (
- PhStartsWithStringRef2(&name, L"\\System32", TRUE)
-#ifdef _WIN64
- || (PhStartsWithStringRef2(&name, L"\\SysWow64", TRUE) && (isWow64 = TRUE, TRUE)) // ugly but necessary
-#endif
- )
- {
- // SysTem32 and SysWow64 are both 8 characters long.
- PhSkipStringRef(&name, 9 * sizeof(WCHAR));
-
- if (FALSE)
- ; // Dummy
- else if (PhEqualStringRef2(&name, L"\\smss.exe", TRUE))
- knownProcessType = SessionManagerProcessType;
- else if (PhEqualStringRef2(&name, L"\\csrss.exe", TRUE))
- knownProcessType = WindowsSubsystemProcessType;
- else if (PhEqualStringRef2(&name, L"\\wininit.exe", TRUE))
- knownProcessType = WindowsStartupProcessType;
- else if (PhEqualStringRef2(&name, L"\\services.exe", TRUE))
- knownProcessType = ServiceControlManagerProcessType;
- else if (PhEqualStringRef2(&name, L"\\lsass.exe", TRUE))
- knownProcessType = LocalSecurityAuthorityProcessType;
- else if (PhEqualStringRef2(&name, L"\\lsm.exe", TRUE))
- knownProcessType = LocalSessionManagerProcessType;
- else if (PhEqualStringRef2(&name, L"\\winlogon.exe", TRUE))
- knownProcessType = WindowsLogonProcessType;
- else if (PhEqualStringRef2(&name, L"\\svchost.exe", TRUE))
- knownProcessType = ServiceHostProcessType;
- else if (PhEqualStringRef2(&name, L"\\rundll32.exe", TRUE))
- knownProcessType = RunDllAsAppProcessType;
- else if (PhEqualStringRef2(&name, L"\\dllhost.exe", TRUE))
- knownProcessType = ComSurrogateProcessType;
- else if (PhEqualStringRef2(&name, L"\\taskeng.exe", TRUE))
- knownProcessType = TaskHostProcessType;
- else if (PhEqualStringRef2(&name, L"\\taskhost.exe", TRUE))
- knownProcessType = TaskHostProcessType;
- else if (PhEqualStringRef2(&name, L"\\taskhostex.exe", TRUE))
- knownProcessType = TaskHostProcessType;
- else if (PhEqualStringRef2(&name, L"\\taskhostw.exe", TRUE))
- knownProcessType = TaskHostProcessType;
- else if (PhEqualStringRef2(&name, L"\\wudfhost.exe", TRUE))
- knownProcessType = UmdfHostProcessType;
- }
- }
-
- PhDereferenceObject(newFileName);
-
-#ifdef _WIN64
- if (isWow64)
- knownProcessType |= KnownProcessWow64;
-#endif
-
- *KnownProcessType = knownProcessType;
-
- return status;
-}
-
-static BOOLEAN NTAPI PhpSvchostCommandLineCallback(
- _In_opt_ PPH_COMMAND_LINE_OPTION Option,
- _In_opt_ PPH_STRING Value,
- _In_opt_ PVOID Context
- )
-{
- PPH_KNOWN_PROCESS_COMMAND_LINE knownCommandLine = Context;
-
- if (Option && Option->Id == 1)
- {
- PhSwapReference(&knownCommandLine->ServiceHost.GroupName, Value);
- }
-
- return TRUE;
-}
-
-BOOLEAN PhaGetProcessKnownCommandLine(
- _In_ PPH_STRING CommandLine,
- _In_ PH_KNOWN_PROCESS_TYPE KnownProcessType,
- _Out_ PPH_KNOWN_PROCESS_COMMAND_LINE KnownCommandLine
- )
-{
- switch (KnownProcessType & KnownProcessTypeMask)
- {
- case ServiceHostProcessType:
- {
- // svchost.exe -k
-
- static PH_COMMAND_LINE_OPTION options[] =
- {
- { 1, L"k", MandatoryArgumentType }
- };
-
- KnownCommandLine->ServiceHost.GroupName = NULL;
-
- PhParseCommandLine(
- &CommandLine->sr,
- options,
- sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION),
- PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS,
- PhpSvchostCommandLineCallback,
- KnownCommandLine
- );
-
- if (KnownCommandLine->ServiceHost.GroupName)
- {
- PH_AUTO(KnownCommandLine->ServiceHost.GroupName);
- return TRUE;
- }
- else
- {
- return FALSE;
- }
- }
- break;
- case RunDllAsAppProcessType:
- {
- // rundll32.exe , ...
-
- SIZE_T i;
- PH_STRINGREF dllNamePart;
- PH_STRINGREF procedureNamePart;
- PPH_STRING dllName;
- PPH_STRING procedureName;
-
- i = 0;
-
- // Get the rundll32.exe part.
-
- dllName = PhParseCommandLinePart(&CommandLine->sr, &i);
-
- if (!dllName)
- return FALSE;
-
- PhDereferenceObject(dllName);
-
- // Get the DLL name part.
-
- while (i < CommandLine->Length / 2 && CommandLine->Buffer[i] == ' ')
- i++;
-
- dllName = PhParseCommandLinePart(&CommandLine->sr, &i);
-
- if (!dllName)
- return FALSE;
-
- PH_AUTO(dllName);
-
- // The procedure name begins after the last comma.
-
- if (!PhSplitStringRefAtLastChar(&dllName->sr, ',', &dllNamePart, &procedureNamePart))
- return FALSE;
-
- dllName = PH_AUTO(PhCreateString2(&dllNamePart));
- procedureName = PH_AUTO(PhCreateString2(&procedureNamePart));
-
- // If the DLL name isn't an absolute path, assume it's in system32.
- // TODO: Use a proper search function.
-
- if (RtlDetermineDosPathNameType_U(dllName->Buffer) == RtlPathTypeRelative)
- {
- dllName = PhaConcatStrings(
- 3,
- PH_AUTO_T(PH_STRING, PhGetSystemDirectory())->Buffer,
- L"\\",
- dllName->Buffer
- );
- }
-
- KnownCommandLine->RunDllAsApp.FileName = dllName;
- KnownCommandLine->RunDllAsApp.ProcedureName = procedureName;
- }
- break;
- case ComSurrogateProcessType:
- {
- // dllhost.exe /processid:
-
- static PH_STRINGREF inprocServer32Name = PH_STRINGREF_INIT(L"InprocServer32");
-
- SIZE_T i;
- ULONG_PTR indexOfProcessId;
- PPH_STRING argPart;
- PPH_STRING guidString;
- UNICODE_STRING guidStringUs;
- GUID guid;
- HANDLE rootKeyHandle;
- HANDLE inprocServer32KeyHandle;
- PPH_STRING fileName;
-
- i = 0;
-
- // Get the dllhost.exe part.
-
- argPart = PhParseCommandLinePart(&CommandLine->sr, &i);
-
- if (!argPart)
- return FALSE;
-
- PhDereferenceObject(argPart);
-
- // Get the argument part.
-
- while (i < (ULONG)CommandLine->Length / 2 && CommandLine->Buffer[i] == ' ')
- i++;
-
- argPart = PhParseCommandLinePart(&CommandLine->sr, &i);
-
- if (!argPart)
- return FALSE;
-
- PH_AUTO(argPart);
-
- // Find "/processid:"; the GUID is just after that.
-
- _wcsupr(argPart->Buffer);
- indexOfProcessId = PhFindStringInString(argPart, 0, L"/PROCESSID:");
-
- if (indexOfProcessId == -1)
- return FALSE;
-
- guidString = PhaSubstring(
- argPart,
- indexOfProcessId + 11,
- (ULONG)argPart->Length / 2 - indexOfProcessId - 11
- );
- PhStringRefToUnicodeString(&guidString->sr, &guidStringUs);
-
- if (!NT_SUCCESS(RtlGUIDFromString(
- &guidStringUs,
- &guid
- )))
- return FALSE;
-
- KnownCommandLine->ComSurrogate.Guid = guid;
- KnownCommandLine->ComSurrogate.Name = NULL;
- KnownCommandLine->ComSurrogate.FileName = NULL;
-
- // Lookup the GUID in the registry to determine the name and file name.
-
- if (NT_SUCCESS(PhOpenKey(
- &rootKeyHandle,
- KEY_READ,
- PH_KEY_CLASSES_ROOT,
- &PhaConcatStrings2(L"CLSID\\", guidString->Buffer)->sr,
- 0
- )))
- {
- KnownCommandLine->ComSurrogate.Name =
- PH_AUTO(PhQueryRegistryString(rootKeyHandle, NULL));
-
- if (NT_SUCCESS(PhOpenKey(
- &inprocServer32KeyHandle,
- KEY_READ,
- rootKeyHandle,
- &inprocServer32Name,
- 0
- )))
- {
- KnownCommandLine->ComSurrogate.FileName =
- PH_AUTO(PhQueryRegistryString(inprocServer32KeyHandle, NULL));
-
- if (fileName = PH_AUTO(PhExpandEnvironmentStrings(
- &KnownCommandLine->ComSurrogate.FileName->sr
- )))
- {
- KnownCommandLine->ComSurrogate.FileName = fileName;
- }
-
- NtClose(inprocServer32KeyHandle);
- }
-
- NtClose(rootKeyHandle);
- }
- else if (NT_SUCCESS(PhOpenKey(
- &rootKeyHandle,
- KEY_READ,
- PH_KEY_CLASSES_ROOT,
- &PhaConcatStrings2(L"AppID\\", guidString->Buffer)->sr,
- 0
- )))
- {
- KnownCommandLine->ComSurrogate.Name =
- PH_AUTO(PhQueryRegistryString(rootKeyHandle, NULL));
- NtClose(rootKeyHandle);
- }
- }
- break;
- default:
- return FALSE;
- }
-
- return TRUE;
-}
-
-VOID PhEnumChildWindows(
- _In_opt_ HWND hWnd,
- _In_ ULONG Limit,
- _In_ WNDENUMPROC Callback,
- _In_ LPARAM lParam
- )
-{
- HWND childWindow = NULL;
- ULONG i = 0;
-
- while (i < Limit && (childWindow = FindWindowEx(hWnd, childWindow, NULL, NULL)))
- {
- if (!Callback(childWindow, lParam))
- return;
-
- i++;
- }
-}
-
-typedef struct _GET_PROCESS_MAIN_WINDOW_CONTEXT
-{
- HWND Window;
- HWND ImmersiveWindow;
- HANDLE ProcessId;
- BOOLEAN IsImmersive;
-} GET_PROCESS_MAIN_WINDOW_CONTEXT, *PGET_PROCESS_MAIN_WINDOW_CONTEXT;
-
-BOOL CALLBACK PhpGetProcessMainWindowEnumWindowsProc(
- _In_ HWND hwnd,
- _In_ LPARAM lParam
- )
-{
- PGET_PROCESS_MAIN_WINDOW_CONTEXT context = (PGET_PROCESS_MAIN_WINDOW_CONTEXT)lParam;
- ULONG processId;
- HWND parentWindow;
- WINDOWINFO windowInfo;
-
- if (!IsWindowVisible(hwnd))
- return TRUE;
-
- GetWindowThreadProcessId(hwnd, &processId);
-
- if (UlongToHandle(processId) == context->ProcessId &&
- !((parentWindow = GetParent(hwnd)) && IsWindowVisible(parentWindow)) && // skip windows with a visible parent
- PhGetWindowTextEx(hwnd, PH_GET_WINDOW_TEXT_INTERNAL | PH_GET_WINDOW_TEXT_LENGTH_ONLY, NULL) != 0) // skip windows with no title
- {
- if (!context->ImmersiveWindow && context->IsImmersive &&
- GetProp(hwnd, L"Windows.ImmersiveShell.IdentifyAsMainCoreWindow"))
- {
- context->ImmersiveWindow = hwnd;
- }
-
- windowInfo.cbSize = sizeof(WINDOWINFO);
-
- if (!context->Window && GetWindowInfo(hwnd, &windowInfo) && (windowInfo.dwStyle & WS_DLGFRAME))
- {
- context->Window = hwnd;
-
- // If we're not looking at an immersive process, there's no need to search any more windows.
- if (!context->IsImmersive)
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-HWND PhGetProcessMainWindow(
- _In_ HANDLE ProcessId,
- _In_opt_ HANDLE ProcessHandle
- )
-{
- GET_PROCESS_MAIN_WINDOW_CONTEXT context;
- HANDLE processHandle = NULL;
-
- memset(&context, 0, sizeof(GET_PROCESS_MAIN_WINDOW_CONTEXT));
- context.ProcessId = ProcessId;
-
- if (ProcessHandle)
- processHandle = ProcessHandle;
- else
- PhOpenProcess(&processHandle, ProcessQueryAccess, ProcessId);
-
- if (processHandle && IsImmersiveProcess_I)
- context.IsImmersive = IsImmersiveProcess_I(processHandle);
-
- PhEnumChildWindows(NULL, 0x800, PhpGetProcessMainWindowEnumWindowsProc, (LPARAM)&context);
-
- if (!ProcessHandle && processHandle)
- NtClose(processHandle);
-
- return context.ImmersiveWindow ? context.ImmersiveWindow : context.Window;
-}
-
-PPH_STRING PhGetServiceRelevantFileName(
- _In_ PPH_STRINGREF ServiceName,
- _In_ SC_HANDLE ServiceHandle
- )
-{
- PPH_STRING fileName = NULL;
- LPQUERY_SERVICE_CONFIG config;
-
- if (config = PhGetServiceConfig(ServiceHandle))
- {
- PhGetServiceDllParameter(ServiceName, &fileName);
-
- if (!fileName)
- {
- PPH_STRING commandLine;
-
- commandLine = PhCreateString(config->lpBinaryPathName);
-
- if (config->dwServiceType & SERVICE_WIN32)
- {
- PH_STRINGREF dummyFileName;
- PH_STRINGREF dummyArguments;
-
- PhParseCommandLineFuzzy(&commandLine->sr, &dummyFileName, &dummyArguments, &fileName);
-
- if (!fileName)
- PhSwapReference(&fileName, commandLine);
- }
- else
- {
- fileName = PhGetFileName(commandLine);
- }
-
- PhDereferenceObject(commandLine);
- }
-
- PhFree(config);
- }
-
- return fileName;
-}
-
-PPH_STRING PhEscapeStringForDelimiter(
- _In_ PPH_STRING String,
- _In_ WCHAR Delimiter
- )
-{
- PH_STRING_BUILDER stringBuilder;
- SIZE_T length;
- SIZE_T i;
- WCHAR temp[2];
-
- length = String->Length / 2;
- PhInitializeStringBuilder(&stringBuilder, String->Length / 2 * 3);
-
- temp[0] = '\\';
-
- for (i = 0; i < length; i++)
- {
- if (String->Buffer[i] == '\\' || String->Buffer[i] == Delimiter)
- {
- temp[1] = String->Buffer[i];
- PhAppendStringBuilderEx(&stringBuilder, temp, 4);
- }
- else
- {
- PhAppendCharStringBuilder(&stringBuilder, String->Buffer[i]);
- }
- }
-
- return PhFinalStringBuilderString(&stringBuilder);
-}
-
-PPH_STRING PhUnescapeStringForDelimiter(
- _In_ PPH_STRING String,
- _In_ WCHAR Delimiter
- )
-{
- PH_STRING_BUILDER stringBuilder;
- SIZE_T length;
- SIZE_T i;
-
- length = String->Length / 2;
- PhInitializeStringBuilder(&stringBuilder, String->Length / 2 * 3);
-
- for (i = 0; i < length; i++)
- {
- if (String->Buffer[i] == '\\')
- {
- if (i != length - 1)
- {
- PhAppendCharStringBuilder(&stringBuilder, String->Buffer[i + 1]);
- i++;
- }
- else
- {
- // Trailing backslash. Just ignore it.
- break;
- }
- }
- else
- {
- PhAppendCharStringBuilder(&stringBuilder, String->Buffer[i]);
- }
- }
-
- return PhFinalStringBuilderString(&stringBuilder);
-}
-
-PPH_STRING PhGetOpaqueXmlNodeText(
- _In_ mxml_node_t *node
- )
-{
- if (node->child && node->child->type == MXML_OPAQUE && node->child->value.opaque)
- {
- return PhConvertUtf8ToUtf16(node->child->value.opaque);
- }
- else
- {
- return PhReferenceEmptyString();
- }
-}
-
-VOID PhSearchOnlineString(
- _In_ HWND hWnd,
- _In_ PWSTR String
- )
-{
- PhShellExecuteUserString(hWnd, L"SearchEngine", String, TRUE, NULL);
-}
-
-VOID PhShellExecuteUserString(
- _In_ HWND hWnd,
- _In_ PWSTR Setting,
- _In_ PWSTR String,
- _In_ BOOLEAN UseShellExecute,
- _In_opt_ PWSTR ErrorMessage
- )
-{
- static PH_STRINGREF replacementToken = PH_STRINGREF_INIT(L"%s");
-
- PPH_STRING executeString;
- PH_STRINGREF stringBefore;
- PH_STRINGREF stringMiddle;
- PH_STRINGREF stringAfter;
- PPH_STRING ntMessage;
-
- executeString = PhGetStringSetting(Setting);
-
- // Make sure the user executable string is absolute. We can't use RtlDetermineDosPathNameType_U
- // here because the string may be a URL.
- if (PhFindCharInString(executeString, 0, ':') == -1)
- PhMoveReference(&executeString, PhConcatStringRef2(&PhApplicationDirectory->sr, &executeString->sr));
-
- // Replace the token with the string, or use the original string if the token is not present.
- if (PhSplitStringRefAtString(&executeString->sr, &replacementToken, FALSE, &stringBefore, &stringAfter))
- {
- PhInitializeStringRef(&stringMiddle, String);
- PhMoveReference(&executeString, PhConcatStringRef3(&stringBefore, &stringMiddle, &stringAfter));
- }
-
- if (UseShellExecute)
- {
- PhShellExecute(hWnd, executeString->Buffer, NULL);
- }
- else
- {
- NTSTATUS status;
-
- status = PhCreateProcessWin32(NULL, executeString->Buffer, NULL, NULL, 0, NULL, NULL, NULL);
-
- if (!NT_SUCCESS(status))
- {
- if (ErrorMessage)
- {
- ntMessage = PhGetNtMessage(status);
- PhShowError(hWnd, L"Unable to execute the command: %s\n%s", PhGetStringOrDefault(ntMessage, L"An unknown error occurred."), ErrorMessage);
- PhDereferenceObject(ntMessage);
- }
- else
- {
- PhShowStatus(hWnd, L"Unable to execute the command", status, 0);
- }
- }
- }
-
- PhDereferenceObject(executeString);
-}
-
-VOID PhLoadSymbolProviderOptions(
- _Inout_ PPH_SYMBOL_PROVIDER SymbolProvider
- )
-{
- PPH_STRING searchPath;
-
- PhSetOptionsSymbolProvider(
- SYMOPT_UNDNAME,
- PhGetIntegerSetting(L"DbgHelpUndecorate") ? SYMOPT_UNDNAME : 0
- );
-
- searchPath = PhGetStringSetting(L"DbgHelpSearchPath");
-
- if (searchPath->Length != 0)
- PhSetSearchPathSymbolProvider(SymbolProvider, searchPath->Buffer);
-
- PhDereferenceObject(searchPath);
-}
-
-PWSTR PhMakeContextAtom(
- VOID
- )
-{
- PH_DEFINE_MAKE_ATOM(L"PH2_Context");
-}
-
-/**
- * Copies a string into a NMLVGETINFOTIP structure.
- *
- * \param GetInfoTip The NMLVGETINFOTIP structure.
- * \param Tip The string to copy.
- *
- * \remarks The text is truncated if it is too long.
- */
-VOID PhCopyListViewInfoTip(
- _Inout_ LPNMLVGETINFOTIP GetInfoTip,
- _In_ PPH_STRINGREF Tip
- )
-{
- ULONG copyIndex;
- ULONG bufferRemaining;
- ULONG copyLength;
-
- if (GetInfoTip->dwFlags == 0)
- {
- copyIndex = (ULONG)PhCountStringZ(GetInfoTip->pszText) + 1; // plus one for newline
-
- if (GetInfoTip->cchTextMax - copyIndex < 2) // need at least two bytes
- return;
-
- bufferRemaining = GetInfoTip->cchTextMax - copyIndex - 1;
- GetInfoTip->pszText[copyIndex - 1] = '\n';
- }
- else
- {
- copyIndex = 0;
- bufferRemaining = GetInfoTip->cchTextMax;
- }
-
- copyLength = min((ULONG)Tip->Length / 2, bufferRemaining - 1);
- memcpy(
- &GetInfoTip->pszText[copyIndex],
- Tip->Buffer,
- copyLength * 2
- );
- GetInfoTip->pszText[copyIndex + copyLength] = 0;
-}
-
-VOID PhCopyListView(
- _In_ HWND ListViewHandle
- )
-{
- PPH_STRING text;
-
- text = PhGetListViewText(ListViewHandle);
- PhSetClipboardString(ListViewHandle, &text->sr);
- PhDereferenceObject(text);
-}
-
-VOID PhHandleListViewNotifyForCopy(
- _In_ LPARAM lParam,
- _In_ HWND ListViewHandle
- )
-{
- PhHandleListViewNotifyBehaviors(lParam, ListViewHandle, PH_LIST_VIEW_CTRL_C_BEHAVIOR);
-}
-
-VOID PhHandleListViewNotifyBehaviors(
- _In_ LPARAM lParam,
- _In_ HWND ListViewHandle,
- _In_ ULONG Behaviors
- )
-{
- if (((LPNMHDR)lParam)->hwndFrom == ListViewHandle && ((LPNMHDR)lParam)->code == LVN_KEYDOWN)
- {
- LPNMLVKEYDOWN keyDown = (LPNMLVKEYDOWN)lParam;
-
- switch (keyDown->wVKey)
- {
- case 'C':
- if (Behaviors & PH_LIST_VIEW_CTRL_C_BEHAVIOR)
- {
- if (GetKeyState(VK_CONTROL) < 0)
- PhCopyListView(ListViewHandle);
- }
- break;
- case 'A':
- if (Behaviors & PH_LIST_VIEW_CTRL_A_BEHAVIOR)
- {
- if (GetKeyState(VK_CONTROL) < 0)
- PhSetStateAllListViewItems(ListViewHandle, LVIS_SELECTED, LVIS_SELECTED);
- }
- break;
- }
- }
-}
-
-BOOLEAN PhGetListViewContextMenuPoint(
- _In_ HWND ListViewHandle,
- _Out_ PPOINT Point
- )
-{
- INT selectedIndex;
- RECT bounds;
- RECT clientRect;
-
- // The user pressed a key to display the context menu.
- // Suggest where the context menu should display.
-
- if ((selectedIndex = ListView_GetNextItem(ListViewHandle, -1, LVNI_SELECTED)) != -1)
- {
- if (ListView_GetItemRect(ListViewHandle, selectedIndex, &bounds, LVIR_BOUNDS))
- {
- Point->x = bounds.left + PhSmallIconSize.X / 2;
- Point->y = bounds.top + PhSmallIconSize.Y / 2;
-
- GetClientRect(ListViewHandle, &clientRect);
-
- if (Point->x < 0 || Point->y < 0 || Point->x >= clientRect.right || Point->y >= clientRect.bottom)
- {
- // The menu is going to be outside of the control. Just put it at the top-left.
- Point->x = 0;
- Point->y = 0;
- }
-
- ClientToScreen(ListViewHandle, Point);
-
- return TRUE;
- }
- }
-
- Point->x = 0;
- Point->y = 0;
- ClientToScreen(ListViewHandle, Point);
-
- return FALSE;
-}
-
-HFONT PhDuplicateFontWithNewWeight(
- _In_ HFONT Font,
- _In_ LONG NewWeight
- )
-{
- LOGFONT logFont;
-
- if (GetObject(Font, sizeof(LOGFONT), &logFont))
- {
- logFont.lfWeight = NewWeight;
- return CreateFontIndirect(&logFont);
- }
- else
- {
- return NULL;
- }
-}
-
-VOID PhSetWindowOpacity(
- _In_ HWND WindowHandle,
- _In_ ULONG OpacityPercent
- )
-{
- if (OpacityPercent == 0)
- {
- // Make things a bit faster by removing the WS_EX_LAYERED bit.
- PhSetWindowExStyle(WindowHandle, WS_EX_LAYERED, 0);
- RedrawWindow(WindowHandle, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);
- return;
- }
-
- PhSetWindowExStyle(WindowHandle, WS_EX_LAYERED, WS_EX_LAYERED);
-
- // Disallow opacity values of less than 10%.
- OpacityPercent = min(OpacityPercent, 90);
-
- // The opacity value is backwards - 0 means opaque, 100 means transparent.
- SetLayeredWindowAttributes(
- WindowHandle,
- 0,
- (BYTE)(255 * (100 - OpacityPercent) / 100),
- LWA_ALPHA
- );
-}
-
-VOID PhLoadWindowPlacementFromSetting(
- _In_opt_ PWSTR PositionSettingName,
- _In_opt_ PWSTR SizeSettingName,
- _In_ HWND WindowHandle
- )
-{
- PH_RECTANGLE windowRectangle;
-
- if (PositionSettingName && SizeSettingName)
- {
- RECT rectForAdjust;
-
- windowRectangle.Position = PhGetIntegerPairSetting(PositionSettingName);
- windowRectangle.Size = PhGetScalableIntegerPairSetting(SizeSettingName, TRUE).Pair;
- PhAdjustRectangleToWorkingArea(NULL, &windowRectangle);
-
- // Let the window adjust for the minimum size if needed.
- rectForAdjust = PhRectangleToRect(windowRectangle);
- SendMessage(WindowHandle, WM_SIZING, WMSZ_BOTTOMRIGHT, (LPARAM)&rectForAdjust);
- windowRectangle = PhRectToRectangle(rectForAdjust);
-
- MoveWindow(WindowHandle, windowRectangle.Left, windowRectangle.Top,
- windowRectangle.Width, windowRectangle.Height, FALSE);
- }
- else
- {
- PH_INTEGER_PAIR position;
- PH_INTEGER_PAIR size;
- ULONG flags;
-
- flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE | SWP_NOZORDER;
-
- if (PositionSettingName)
- {
- position = PhGetIntegerPairSetting(PositionSettingName);
- flags &= ~SWP_NOMOVE;
- }
- else
- {
- position.X = 0;
- position.Y = 0;
- }
-
- if (SizeSettingName)
- {
- size = PhGetScalableIntegerPairSetting(SizeSettingName, TRUE).Pair;
- flags &= ~SWP_NOSIZE;
- }
- else
- {
- size.X = 16;
- size.Y = 16;
- }
-
- SetWindowPos(WindowHandle, NULL, position.X, position.Y, size.X, size.Y, flags);
- }
-}
-
-VOID PhSaveWindowPlacementToSetting(
- _In_opt_ PWSTR PositionSettingName,
- _In_opt_ PWSTR SizeSettingName,
- _In_ HWND WindowHandle
- )
-{
- WINDOWPLACEMENT placement = { sizeof(placement) };
- PH_RECTANGLE windowRectangle;
- MONITORINFO monitorInfo = { sizeof(MONITORINFO) };
-
- GetWindowPlacement(WindowHandle, &placement);
- windowRectangle = PhRectToRectangle(placement.rcNormalPosition);
-
- // The rectangle is in workspace coordinates. Convert the values back to screen coordinates.
- if (GetMonitorInfo(MonitorFromRect(&placement.rcNormalPosition, MONITOR_DEFAULTTOPRIMARY), &monitorInfo))
- {
- windowRectangle.Left += monitorInfo.rcWork.left - monitorInfo.rcMonitor.left;
- windowRectangle.Top += monitorInfo.rcWork.top - monitorInfo.rcMonitor.top;
- }
-
- if (PositionSettingName)
- PhSetIntegerPairSetting(PositionSettingName, windowRectangle.Position);
- if (SizeSettingName)
- PhSetScalableIntegerPairSetting2(SizeSettingName, windowRectangle.Size);
-}
-
-VOID PhLoadListViewColumnsFromSetting(
- _In_ PWSTR Name,
- _In_ HWND ListViewHandle
- )
-{
- PPH_STRING string;
-
- string = PhGetStringSetting(Name);
- PhLoadListViewColumnSettings(ListViewHandle, string);
- PhDereferenceObject(string);
-}
-
-VOID PhSaveListViewColumnsToSetting(
- _In_ PWSTR Name,
- _In_ HWND ListViewHandle
- )
-{
- PPH_STRING string;
-
- string = PhSaveListViewColumnSettings(ListViewHandle);
- PhSetStringSetting2(Name, &string->sr);
- PhDereferenceObject(string);
-}
-
-PPH_STRING PhGetPhVersion(
- VOID
- )
-{
- PH_FORMAT format[5];
-
- PhInitFormatU(&format[0], PHAPP_VERSION_MAJOR);
- PhInitFormatC(&format[1], '.');
- PhInitFormatU(&format[2], PHAPP_VERSION_MINOR);
- PhInitFormatC(&format[3], '.');
- PhInitFormatU(&format[4], PHAPP_VERSION_REVISION);
-
- return PhFormat(format, 5, 16);
-}
-
-VOID PhGetPhVersionNumbers(
- _Out_opt_ PULONG MajorVersion,
- _Out_opt_ PULONG MinorVersion,
- _Reserved_ PULONG Reserved,
- _Out_opt_ PULONG RevisionNumber
- )
-{
- if (MajorVersion)
- *MajorVersion = PHAPP_VERSION_MAJOR;
- if (MinorVersion)
- *MinorVersion = PHAPP_VERSION_MINOR;
- if (RevisionNumber)
- *RevisionNumber = PHAPP_VERSION_REVISION;
-}
-
-VOID PhWritePhTextHeader(
- _Inout_ PPH_FILE_STREAM FileStream
- )
-{
- PPH_STRING version;
- LARGE_INTEGER time;
- SYSTEMTIME systemTime;
- PPH_STRING dateString;
- PPH_STRING timeString;
-
- PhWriteStringAsUtf8FileStream2(FileStream, L"Process Hacker ");
-
- if (version = PhGetPhVersion())
- {
- PhWriteStringAsUtf8FileStream(FileStream, &version->sr);
- PhDereferenceObject(version);
- }
-
- PhWriteStringFormatAsUtf8FileStream(FileStream, L"\r\nWindows NT %u.%u", PhOsVersion.dwMajorVersion, PhOsVersion.dwMinorVersion);
-
- if (PhOsVersion.szCSDVersion[0] != 0)
- PhWriteStringFormatAsUtf8FileStream(FileStream, L" %s", PhOsVersion.szCSDVersion);
-
-#ifdef _WIN64
- PhWriteStringAsUtf8FileStream2(FileStream, L" (64-bit)");
-#else
- PhWriteStringAsUtf8FileStream2(FileStream, L" (32-bit)");
-#endif
-
- PhQuerySystemTime(&time);
- PhLargeIntegerToLocalSystemTime(&systemTime, &time);
-
- dateString = PhFormatDate(&systemTime, NULL);
- timeString = PhFormatTime(&systemTime, NULL);
- PhWriteStringFormatAsUtf8FileStream(FileStream, L"\r\n%s %s\r\n\r\n", dateString->Buffer, timeString->Buffer);
- PhDereferenceObject(dateString);
- PhDereferenceObject(timeString);
-}
-
-BOOLEAN PhShellProcessHacker(
- _In_opt_ HWND hWnd,
- _In_opt_ PWSTR Parameters,
- _In_ ULONG ShowWindowType,
- _In_ ULONG Flags,
- _In_ ULONG AppFlags,
- _In_opt_ ULONG Timeout,
- _Out_opt_ PHANDLE ProcessHandle
- )
-{
- return PhShellProcessHackerEx(
- hWnd,
- NULL,
- Parameters,
- ShowWindowType,
- Flags,
- AppFlags,
- Timeout,
- ProcessHandle
- );
-}
-
-VOID PhpAppendCommandLineArgument(
- _Inout_ PPH_STRING_BUILDER StringBuilder,
- _In_ PWSTR Name,
- _In_ PPH_STRINGREF Value
- )
-{
- PPH_STRING temp;
-
- PhAppendStringBuilder2(StringBuilder, L" -");
- PhAppendStringBuilder2(StringBuilder, Name);
- PhAppendStringBuilder2(StringBuilder, L" \"");
- temp = PhEscapeCommandLinePart(Value);
- PhAppendStringBuilder(StringBuilder, &temp->sr);
- PhDereferenceObject(temp);
- PhAppendCharStringBuilder(StringBuilder, '\"');
-}
-
-BOOLEAN PhShellProcessHackerEx(
- _In_opt_ HWND hWnd,
- _In_opt_ PWSTR FileName,
- _In_opt_ PWSTR Parameters,
- _In_ ULONG ShowWindowType,
- _In_ ULONG Flags,
- _In_ ULONG AppFlags,
- _In_opt_ ULONG Timeout,
- _Out_opt_ PHANDLE ProcessHandle
- )
-{
- BOOLEAN result;
- PH_STRING_BUILDER sb;
- PWSTR parameters;
-
- if (AppFlags & PH_SHELL_APP_PROPAGATE_PARAMETERS)
- {
- PhInitializeStringBuilder(&sb, 128);
-
- // Propagate parameters.
-
- if (PhStartupParameters.NoSettings)
- {
- PhAppendStringBuilder2(&sb, L" -nosettings");
- }
- else if (PhStartupParameters.SettingsFileName && (PhSettingsFileName || (AppFlags & PH_SHELL_APP_PROPAGATE_PARAMETERS_FORCE_SETTINGS)))
- {
- PPH_STRINGREF fileName;
-
- if (PhSettingsFileName)
- fileName = &PhSettingsFileName->sr;
- else
- fileName = &PhStartupParameters.SettingsFileName->sr;
-
- PhpAppendCommandLineArgument(&sb, L"settings", fileName);
- }
-
- if (PhStartupParameters.NoKph)
- PhAppendStringBuilder2(&sb, L" -nokph");
- if (PhStartupParameters.InstallKph)
- PhAppendStringBuilder2(&sb, L" -installkph");
- if (PhStartupParameters.UninstallKph)
- PhAppendStringBuilder2(&sb, L" -uninstallkph");
- if (PhStartupParameters.Debug)
- PhAppendStringBuilder2(&sb, L" -debug");
- if (PhStartupParameters.NoPlugins)
- PhAppendStringBuilder2(&sb, L" -noplugins");
- if (PhStartupParameters.NewInstance)
- PhAppendStringBuilder2(&sb, L" -newinstance");
-
- if (PhStartupParameters.SelectPid != 0)
- PhAppendFormatStringBuilder(&sb, L" -selectpid %u", PhStartupParameters.SelectPid);
-
- if (PhStartupParameters.PriorityClass != 0)
- {
- CHAR value = 0;
-
- switch (PhStartupParameters.PriorityClass)
- {
- case PROCESS_PRIORITY_CLASS_REALTIME:
- value = L'r';
- break;
- case PROCESS_PRIORITY_CLASS_HIGH:
- value = L'h';
- break;
- case PROCESS_PRIORITY_CLASS_NORMAL:
- value = L'n';
- break;
- case PROCESS_PRIORITY_CLASS_IDLE:
- value = L'l';
- break;
- }
-
- if (value != 0)
- {
- PhAppendStringBuilder2(&sb, L" -priority ");
- PhAppendCharStringBuilder(&sb, value);
- }
- }
-
- if (PhStartupParameters.PluginParameters)
- {
- ULONG i;
-
- for (i = 0; i < PhStartupParameters.PluginParameters->Count; i++)
- {
- PPH_STRING value = PhStartupParameters.PluginParameters->Items[i];
- PhpAppendCommandLineArgument(&sb, L"plugin", &value->sr);
- }
- }
-
- if (PhStartupParameters.SelectTab)
- PhpAppendCommandLineArgument(&sb, L"selecttab", &PhStartupParameters.SelectTab->sr);
-
- if (!(AppFlags & PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY))
- {
- if (PhStartupParameters.ShowVisible)
- PhAppendStringBuilder2(&sb, L" -v");
- if (PhStartupParameters.ShowHidden)
- PhAppendStringBuilder2(&sb, L" -hide");
- }
-
- // Add user-specified parameters last so they can override the propagated parameters.
- if (Parameters)
- {
- PhAppendCharStringBuilder(&sb, ' ');
- PhAppendStringBuilder2(&sb, Parameters);
- }
-
- if (sb.String->Length != 0 && sb.String->Buffer[0] == ' ')
- parameters = sb.String->Buffer + 1;
- else
- parameters = sb.String->Buffer;
- }
- else
- {
- parameters = Parameters;
- }
-
- result = PhShellExecuteEx(
- hWnd,
- FileName ? FileName : PhApplicationFileName->Buffer,
- parameters,
- ShowWindowType,
- Flags,
- Timeout,
- ProcessHandle
- );
-
- if (AppFlags & PH_SHELL_APP_PROPAGATE_PARAMETERS)
- PhDeleteStringBuilder(&sb);
-
- return result;
-}
-
-BOOLEAN PhCreateProcessIgnoreIfeoDebugger(
- _In_ PWSTR FileName
- )
-{
- BOOLEAN result;
- BOOL (NTAPI *debugSetProcessKillOnExit)(BOOL);
- BOOL (NTAPI *debugActiveProcessStop)(DWORD);
- BOOLEAN originalValue;
- STARTUPINFO startupInfo;
- PROCESS_INFORMATION processInfo;
-
- if (!(debugSetProcessKillOnExit = PhGetModuleProcAddress(L"kernel32.dll", "DebugSetProcessKillOnExit")) ||
- !(debugActiveProcessStop = PhGetModuleProcAddress(L"kernel32.dll", "DebugActiveProcessStop")))
- return FALSE;
-
- result = FALSE;
-
- // This is NOT thread-safe.
- originalValue = NtCurrentPeb()->ReadImageFileExecOptions;
- NtCurrentPeb()->ReadImageFileExecOptions = FALSE;
-
- memset(&startupInfo, 0, sizeof(STARTUPINFO));
- startupInfo.cb = sizeof(STARTUPINFO);
- memset(&processInfo, 0, sizeof(PROCESS_INFORMATION));
-
- // The combination of ReadImageFileExecOptions = FALSE and the DEBUG_PROCESS flag
- // allows us to skip the Debugger IFEO value.
- if (CreateProcess(FileName, NULL, NULL, NULL, FALSE, DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, NULL, NULL, &startupInfo, &processInfo))
- {
- // Stop debugging the process now.
- debugSetProcessKillOnExit(FALSE);
- debugActiveProcessStop(processInfo.dwProcessId);
- result = TRUE;
- }
-
- if (processInfo.hProcess)
- NtClose(processInfo.hProcess);
- if (processInfo.hThread)
- NtClose(processInfo.hThread);
-
- NtCurrentPeb()->ReadImageFileExecOptions = originalValue;
-
- return result;
-}
-
-VOID PhInitializeTreeNewColumnMenu(
- _Inout_ PPH_TN_COLUMN_MENU_DATA Data
- )
-{
- PhInitializeTreeNewColumnMenuEx(Data, 0);
-}
-
-VOID PhInitializeTreeNewColumnMenuEx(
- _Inout_ PPH_TN_COLUMN_MENU_DATA Data,
- _In_ ULONG Flags
- )
-{
- PPH_EMENU_ITEM resetSortMenuItem = NULL;
- PPH_EMENU_ITEM sizeColumnToFitMenuItem;
- PPH_EMENU_ITEM sizeAllColumnsToFitMenuItem;
- PPH_EMENU_ITEM hideColumnMenuItem;
- PPH_EMENU_ITEM chooseColumnsMenuItem;
- ULONG minimumNumberOfColumns;
-
- Data->Menu = PhCreateEMenu();
- Data->Selection = NULL;
- Data->ProcessedId = 0;
-
- sizeColumnToFitMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_SIZE_COLUMN_TO_FIT_ID, L"Size column to fit", NULL, NULL);
- sizeAllColumnsToFitMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_SIZE_ALL_COLUMNS_TO_FIT_ID, L"Size all columns to fit", NULL, NULL);
-
- if (!(Flags & PH_TN_COLUMN_MENU_NO_VISIBILITY))
- {
- hideColumnMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_HIDE_COLUMN_ID, L"Hide column", NULL, NULL);
- chooseColumnsMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_CHOOSE_COLUMNS_ID, L"Choose columns...", NULL, NULL);
- }
-
- if (Flags & PH_TN_COLUMN_MENU_SHOW_RESET_SORT)
- {
- ULONG sortColumn;
- PH_SORT_ORDER sortOrder;
-
- TreeNew_GetSort(Data->TreeNewHandle, &sortColumn, &sortOrder);
-
- if (sortOrder != Data->DefaultSortOrder || (Data->DefaultSortOrder != NoSortOrder && sortColumn != Data->DefaultSortColumn))
- resetSortMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_RESET_SORT_ID, L"Reset sort", NULL, NULL);
- }
-
- PhInsertEMenuItem(Data->Menu, sizeColumnToFitMenuItem, -1);
- PhInsertEMenuItem(Data->Menu, sizeAllColumnsToFitMenuItem, -1);
-
- if (!(Flags & PH_TN_COLUMN_MENU_NO_VISIBILITY))
- {
- PhInsertEMenuItem(Data->Menu, hideColumnMenuItem, -1);
-
- if (resetSortMenuItem)
- PhInsertEMenuItem(Data->Menu, resetSortMenuItem, -1);
-
- PhInsertEMenuItem(Data->Menu, PhCreateEMenuItem(PH_EMENU_SEPARATOR, 0, L"", NULL, NULL), -1);
- PhInsertEMenuItem(Data->Menu, chooseColumnsMenuItem, -1);
-
- if (TreeNew_GetFixedColumn(Data->TreeNewHandle))
- minimumNumberOfColumns = 2; // don't allow user to remove all normal columns (the fixed column can never be removed)
- else
- minimumNumberOfColumns = 1;
-
- if (!Data->MouseEvent || !Data->MouseEvent->Column ||
- Data->MouseEvent->Column->Fixed || // don't allow the fixed column to be hidden
- TreeNew_GetVisibleColumnCount(Data->TreeNewHandle) < minimumNumberOfColumns + 1
- )
- {
- hideColumnMenuItem->Flags |= PH_EMENU_DISABLED;
- }
- }
- else
- {
- if (resetSortMenuItem)
- PhInsertEMenuItem(Data->Menu, resetSortMenuItem, -1);
- }
-
- if (!Data->MouseEvent || !Data->MouseEvent->Column)
- {
- sizeColumnToFitMenuItem->Flags |= PH_EMENU_DISABLED;
- }
-}
-
-VOID PhpEnsureValidSortColumnTreeNew(
- _Inout_ HWND TreeNewHandle,
- _In_ ULONG DefaultSortColumn,
- _In_ PH_SORT_ORDER DefaultSortOrder
- )
-{
- ULONG sortColumn;
- PH_SORT_ORDER sortOrder;
-
- // Make sure the column we're sorting by is actually visible, and if not, don't sort anymore.
-
- TreeNew_GetSort(TreeNewHandle, &sortColumn, &sortOrder);
-
- if (sortOrder != NoSortOrder)
- {
- PH_TREENEW_COLUMN column;
-
- TreeNew_GetColumn(TreeNewHandle, sortColumn, &column);
-
- if (!column.Visible)
- {
- if (DefaultSortOrder != NoSortOrder)
- {
- // Make sure the default sort column is visible.
- TreeNew_GetColumn(TreeNewHandle, DefaultSortColumn, &column);
-
- if (!column.Visible)
- {
- ULONG maxId;
- ULONG id;
- BOOLEAN found;
-
- // Use the first visible column.
- maxId = TreeNew_GetMaxId(TreeNewHandle);
- id = 0;
- found = FALSE;
-
- while (id <= maxId)
- {
- if (TreeNew_GetColumn(TreeNewHandle, id, &column))
- {
- if (column.Visible)
- {
- DefaultSortColumn = id;
- found = TRUE;
- break;
- }
- }
-
- id++;
- }
-
- if (!found)
- {
- DefaultSortColumn = 0;
- DefaultSortOrder = NoSortOrder;
- }
- }
- }
-
- TreeNew_SetSort(TreeNewHandle, DefaultSortColumn, DefaultSortOrder);
- }
- }
-}
-
-BOOLEAN PhHandleTreeNewColumnMenu(
- _Inout_ PPH_TN_COLUMN_MENU_DATA Data
- )
-{
- if (!Data->Selection)
- return FALSE;
-
- switch (Data->Selection->Id)
- {
- case PH_TN_COLUMN_MENU_RESET_SORT_ID:
- {
- TreeNew_SetSort(Data->TreeNewHandle, Data->DefaultSortColumn, Data->DefaultSortOrder);
- }
- break;
- case PH_TN_COLUMN_MENU_SIZE_COLUMN_TO_FIT_ID:
- {
- if (Data->MouseEvent && Data->MouseEvent->Column)
- {
- TreeNew_AutoSizeColumn(Data->TreeNewHandle, Data->MouseEvent->Column->Id, 0);
- }
- }
- break;
- case PH_TN_COLUMN_MENU_SIZE_ALL_COLUMNS_TO_FIT_ID:
- {
- ULONG maxId;
- ULONG id;
-
- maxId = TreeNew_GetMaxId(Data->TreeNewHandle);
- id = 0;
-
- while (id <= maxId)
- {
- TreeNew_AutoSizeColumn(Data->TreeNewHandle, id, 0);
- id++;
- }
- }
- break;
- case PH_TN_COLUMN_MENU_HIDE_COLUMN_ID:
- {
- PH_TREENEW_COLUMN column;
-
- if (Data->MouseEvent && Data->MouseEvent->Column && !Data->MouseEvent->Column->Fixed)
- {
- column.Id = Data->MouseEvent->Column->Id;
- column.Visible = FALSE;
- TreeNew_SetColumn(Data->TreeNewHandle, TN_COLUMN_FLAG_VISIBLE, &column);
- PhpEnsureValidSortColumnTreeNew(Data->TreeNewHandle, Data->DefaultSortColumn, Data->DefaultSortOrder);
- InvalidateRect(Data->TreeNewHandle, NULL, FALSE);
- }
- }
- break;
- case PH_TN_COLUMN_MENU_CHOOSE_COLUMNS_ID:
- {
- PhShowChooseColumnsDialog(Data->TreeNewHandle, Data->TreeNewHandle, PH_CONTROL_TYPE_TREE_NEW);
- PhpEnsureValidSortColumnTreeNew(Data->TreeNewHandle, Data->DefaultSortColumn, Data->DefaultSortOrder);
- }
- break;
- default:
- return FALSE;
- }
-
- Data->ProcessedId = Data->Selection->Id;
-
- return TRUE;
-}
-
-VOID PhDeleteTreeNewColumnMenu(
- _In_ PPH_TN_COLUMN_MENU_DATA Data
- )
-{
- if (Data->Menu)
- {
- PhDestroyEMenu(Data->Menu);
- Data->Menu = NULL;
- }
-}
-
-VOID PhInitializeTreeNewFilterSupport(
- _Out_ PPH_TN_FILTER_SUPPORT Support,
- _In_ HWND TreeNewHandle,
- _In_ PPH_LIST NodeList
- )
-{
- Support->FilterList = NULL;
- Support->TreeNewHandle = TreeNewHandle;
- Support->NodeList = NodeList;
-}
-
-VOID PhDeleteTreeNewFilterSupport(
- _In_ PPH_TN_FILTER_SUPPORT Support
- )
-{
- PhDereferenceObject(Support->FilterList);
-}
-
-PPH_TN_FILTER_ENTRY PhAddTreeNewFilter(
- _In_ PPH_TN_FILTER_SUPPORT Support,
- _In_ PPH_TN_FILTER_FUNCTION Filter,
- _In_opt_ PVOID Context
- )
-{
- PPH_TN_FILTER_ENTRY entry;
-
- entry = PhAllocate(sizeof(PH_TN_FILTER_ENTRY));
- entry->Filter = Filter;
- entry->Context = Context;
-
- if (!Support->FilterList)
- Support->FilterList = PhCreateList(2);
-
- PhAddItemList(Support->FilterList, entry);
-
- return entry;
-}
-
-VOID PhRemoveTreeNewFilter(
- _In_ PPH_TN_FILTER_SUPPORT Support,
- _In_ PPH_TN_FILTER_ENTRY Entry
- )
-{
- ULONG index;
-
- if (!Support->FilterList)
- return;
-
- index = PhFindItemList(Support->FilterList, Entry);
-
- if (index != -1)
- {
- PhRemoveItemList(Support->FilterList, index);
- PhFree(Entry);
- }
-}
-
-BOOLEAN PhApplyTreeNewFiltersToNode(
- _In_ PPH_TN_FILTER_SUPPORT Support,
- _In_ PPH_TREENEW_NODE Node
- )
-{
- BOOLEAN show;
- ULONG i;
-
- show = TRUE;
-
- if (Support->FilterList)
- {
- for (i = 0; i < Support->FilterList->Count; i++)
- {
- PPH_TN_FILTER_ENTRY entry;
-
- entry = Support->FilterList->Items[i];
-
- if (!entry->Filter(Node, entry->Context))
- {
- show = FALSE;
- break;
- }
- }
- }
-
- return show;
-}
-
-VOID PhApplyTreeNewFilters(
- _In_ PPH_TN_FILTER_SUPPORT Support
- )
-{
- ULONG i;
-
- for (i = 0; i < Support->NodeList->Count; i++)
- {
- PPH_TREENEW_NODE node;
-
- node = Support->NodeList->Items[i];
- node->Visible = PhApplyTreeNewFiltersToNode(Support, node);
-
- if (!node->Visible && node->Selected)
- {
- node->Selected = FALSE;
- }
- }
-
- TreeNew_NodesStructured(Support->TreeNewHandle);
-}
-
-VOID NTAPI PhpCopyCellEMenuItemDeleteFunction(
- _In_ struct _PH_EMENU_ITEM *Item
- )
-{
- PPH_COPY_CELL_CONTEXT context;
-
- context = Item->Context;
- PhDereferenceObject(context->MenuItemText);
- PhFree(context);
-}
-
-BOOLEAN PhInsertCopyCellEMenuItem(
- _In_ struct _PH_EMENU_ITEM *Menu,
- _In_ ULONG InsertAfterId,
- _In_ HWND TreeNewHandle,
- _In_ PPH_TREENEW_COLUMN Column
- )
-{
- PPH_EMENU_ITEM parentItem;
- ULONG indexInParent;
- PPH_COPY_CELL_CONTEXT context;
- PH_STRINGREF columnText;
- PPH_STRING escapedText;
- PPH_STRING menuItemText;
- PPH_EMENU_ITEM copyCellItem;
-
- if (!Column)
- return FALSE;
-
- if (!PhFindEMenuItemEx(Menu, 0, NULL, InsertAfterId, &parentItem, &indexInParent))
- return FALSE;
-
- indexInParent++;
-
- context = PhAllocate(sizeof(PH_COPY_CELL_CONTEXT));
- context->TreeNewHandle = TreeNewHandle;
- context->Id = Column->Id;
-
- PhInitializeStringRef(&columnText, Column->Text);
- escapedText = PhEscapeStringForMenuPrefix(&columnText);
- menuItemText = PhFormatString(L"Copy \"%s\"", escapedText->Buffer);
- PhDereferenceObject(escapedText);
- copyCellItem = PhCreateEMenuItem(0, ID_COPY_CELL, menuItemText->Buffer, NULL, context);
- copyCellItem->DeleteFunction = PhpCopyCellEMenuItemDeleteFunction;
- context->MenuItemText = menuItemText;
-
- if (Column->CustomDraw)
- copyCellItem->Flags |= PH_EMENU_DISABLED;
-
- PhInsertEMenuItem(parentItem, copyCellItem, indexInParent);
-
- return TRUE;
-}
-
-BOOLEAN PhHandleCopyCellEMenuItem(
- _In_ struct _PH_EMENU_ITEM *SelectedItem
- )
-{
- PPH_COPY_CELL_CONTEXT context;
- PH_STRING_BUILDER stringBuilder;
- ULONG count;
- ULONG selectedCount;
- ULONG i;
- PPH_TREENEW_NODE node;
- PH_TREENEW_GET_CELL_TEXT getCellText;
-
- if (!SelectedItem)
- return FALSE;
- if (SelectedItem->Id != ID_COPY_CELL)
- return FALSE;
-
- context = SelectedItem->Context;
-
- PhInitializeStringBuilder(&stringBuilder, 0x100);
- count = TreeNew_GetFlatNodeCount(context->TreeNewHandle);
- selectedCount = 0;
-
- for (i = 0; i < count; i++)
- {
- node = TreeNew_GetFlatNode(context->TreeNewHandle, i);
-
- if (node && node->Selected)
- {
- selectedCount++;
-
- getCellText.Flags = 0;
- getCellText.Node = node;
- getCellText.Id = context->Id;
- PhInitializeEmptyStringRef(&getCellText.Text);
- TreeNew_GetCellText(context->TreeNewHandle, &getCellText);
-
- PhAppendStringBuilder(&stringBuilder, &getCellText.Text);
- PhAppendStringBuilder2(&stringBuilder, L"\r\n");
- }
- }
-
- if (stringBuilder.String->Length != 0 && selectedCount == 1)
- PhRemoveEndStringBuilder(&stringBuilder, 2);
-
- PhSetClipboardString(context->TreeNewHandle, &stringBuilder.String->sr);
- PhDeleteStringBuilder(&stringBuilder);
-
- return TRUE;
-}
-
-BOOLEAN PhpSelectFavoriteInRegedit(
- _In_ HWND RegeditWindow,
- _In_ PPH_STRINGREF FavoriteName,
- _In_ BOOLEAN UsePhSvc
- )
-{
- HMENU menu;
- HMENU favoritesMenu;
- ULONG count;
- ULONG i;
- ULONG id = -1;
-
- if (!(menu = GetMenu(RegeditWindow)))
- return FALSE;
-
- // Cause the Registry Editor to refresh the Favorites menu.
- if (UsePhSvc)
- PhSvcCallSendMessage(RegeditWindow, WM_MENUSELECT, MAKEWPARAM(3, MF_POPUP), (LPARAM)menu);
- else
- SendMessage(RegeditWindow, WM_MENUSELECT, MAKEWPARAM(3, MF_POPUP), (LPARAM)menu);
-
- if (!(favoritesMenu = GetSubMenu(menu, 3)))
- return FALSE;
-
- // Find our entry.
-
- count = GetMenuItemCount(favoritesMenu);
-
- if (count == -1)
- return FALSE;
- if (count > 1000)
- count = 1000;
-
- for (i = 3; i < count; i++)
- {
- MENUITEMINFO info = { sizeof(MENUITEMINFO) };
- WCHAR buffer[32];
-
- info.fMask = MIIM_ID | MIIM_STRING;
- info.dwTypeData = buffer;
- info.cch = sizeof(buffer) / sizeof(WCHAR);
- GetMenuItemInfo(favoritesMenu, i, TRUE, &info);
-
- if (info.cch == FavoriteName->Length / 2)
- {
- PH_STRINGREF text;
-
- text.Buffer = buffer;
- text.Length = info.cch * 2;
-
- if (PhEqualStringRef(&text, FavoriteName, TRUE))
- {
- id = info.wID;
- break;
- }
- }
- }
-
- if (id == -1)
- return FALSE;
-
- // Activate our entry.
- if (UsePhSvc)
- PhSvcCallSendMessage(RegeditWindow, WM_COMMAND, MAKEWPARAM(id, 0), 0);
- else
- SendMessage(RegeditWindow, WM_COMMAND, MAKEWPARAM(id, 0), 0);
-
- // "Close" the Favorites menu and restore normal status bar text.
- if (UsePhSvc)
- PhSvcCallPostMessage(RegeditWindow, WM_MENUSELECT, MAKEWPARAM(0, 0xffff), 0);
- else
- PostMessage(RegeditWindow, WM_MENUSELECT, MAKEWPARAM(0, 0xffff), 0);
-
- // Bring regedit to the top.
- if (IsIconic(RegeditWindow))
- {
- ShowWindow(RegeditWindow, SW_RESTORE);
- SetForegroundWindow(RegeditWindow);
- }
- else
- {
- SetForegroundWindow(RegeditWindow);
- }
-
- return TRUE;
-}
-
-/**
- * Opens a key in the Registry Editor. If the Registry Editor is already open,
- * the specified key is selected in the Registry Editor.
- *
- * \param hWnd A handle to the parent window.
- * \param KeyName The key name to open.
- */
-BOOLEAN PhShellOpenKey2(
- _In_ HWND hWnd,
- _In_ PPH_STRING KeyName
- )
-{
- static PH_STRINGREF favoritesKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\Applets\\Regedit\\Favorites");
-
- BOOLEAN result = FALSE;
- HWND regeditWindow;
- HANDLE favoritesKeyHandle;
- WCHAR favoriteName[32];
- UNICODE_STRING valueName;
- PH_STRINGREF valueNameSr;
- PPH_STRING expandedKeyName;
-
- regeditWindow = FindWindow(L"RegEdit_RegEdit", NULL);
-
- if (!regeditWindow)
- {
- PhShellOpenKey(hWnd, KeyName);
- return TRUE;
- }
-
- if (!PhGetOwnTokenAttributes().Elevated)
- {
- if (!PhUiConnectToPhSvc(hWnd, FALSE))
- return FALSE;
- }
-
- // Create our entry in Favorites.
-
- if (!NT_SUCCESS(PhCreateKey(
- &favoritesKeyHandle,
- KEY_WRITE,
- PH_KEY_CURRENT_USER,
- &favoritesKeyName,
- 0,
- 0,
- NULL
- )))
- goto CleanupExit;
-
- memcpy(favoriteName, L"A_ProcessHacker", 15 * sizeof(WCHAR));
- PhGenerateRandomAlphaString(&favoriteName[15], 16);
- RtlInitUnicodeString(&valueName, favoriteName);
- PhUnicodeStringToStringRef(&valueName, &valueNameSr);
-
- expandedKeyName = PhExpandKeyName(KeyName, TRUE);
- NtSetValueKey(favoritesKeyHandle, &valueName, 0, REG_SZ, expandedKeyName->Buffer, (ULONG)expandedKeyName->Length + 2);
- PhDereferenceObject(expandedKeyName);
-
- // Select our entry in regedit.
- result = PhpSelectFavoriteInRegedit(regeditWindow, &valueNameSr, !PhGetOwnTokenAttributes().Elevated);
-
- NtDeleteValueKey(favoritesKeyHandle, &valueName);
- NtClose(favoritesKeyHandle);
-
-CleanupExit:
- if (!PhGetOwnTokenAttributes().Elevated)
- PhUiDisconnectFromPhSvc();
-
- return result;
-}
-
-PPH_STRING PhPcre2GetErrorMessage(
- _In_ INT ErrorCode
- )
-{
- PPH_STRING buffer;
- SIZE_T bufferLength;
- INT_PTR returnLength;
-
- bufferLength = 128 * sizeof(WCHAR);
- buffer = PhCreateStringEx(NULL, bufferLength);
-
- while (TRUE)
- {
- if ((returnLength = pcre2_get_error_message(ErrorCode, buffer->Buffer, bufferLength / sizeof(WCHAR) + 1)) >= 0)
- break;
-
- PhDereferenceObject(buffer);
- bufferLength *= 2;
-
- if (bufferLength > 0x1000 * sizeof(WCHAR))
- break;
-
- buffer = PhCreateStringEx(NULL, bufferLength);
- }
-
- if (returnLength < 0)
- return NULL;
-
- buffer->Length = returnLength * sizeof(WCHAR);
- return buffer;
-}
+/*
+ * Process Hacker -
+ * application support functions
+ *
+ * Copyright (C) 2010-2016 wj32
+ * Copyright (C) 2017-2019 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 .
+ */
+
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include "pcre/pcre2.h"
+
+GUID XP_CONTEXT_GUID = { 0xbeb1b341, 0x6837, 0x4c83, { 0x83, 0x66, 0x2b, 0x45, 0x1e, 0x7c, 0xe6, 0x9b } };
+GUID VISTA_CONTEXT_GUID = { 0xe2011457, 0x1546, 0x43c5, { 0xa5, 0xfe, 0x00, 0x8d, 0xee, 0xe3, 0xd3, 0xf0 } };
+GUID WIN7_CONTEXT_GUID = { 0x35138b9a, 0x5d96, 0x4fbd, { 0x8e, 0x2d, 0xa2, 0x44, 0x02, 0x25, 0xf9, 0x3a } };
+GUID WIN8_CONTEXT_GUID = { 0x4a2f28e3, 0x53b9, 0x4441, { 0xba, 0x9c, 0xd6, 0x9d, 0x4a, 0x4a, 0x6e, 0x38 } };
+GUID WINBLUE_CONTEXT_GUID = { 0x1f676c76, 0x80e1, 0x4239, { 0x95, 0xbb, 0x83, 0xd0, 0xf6, 0xd0, 0xda, 0x78 } };
+GUID WIN10_CONTEXT_GUID = { 0x8e0f7a12, 0xbfb3, 0x4fe8, { 0xb9, 0xa5, 0x48, 0xfd, 0x50, 0xa1, 0x5a, 0x9a } };
+
+/**
+ * Determines whether a process is suspended.
+ *
+ * \param Process The SYSTEM_PROCESS_INFORMATION structure
+ * of the process.
+ */
+BOOLEAN PhGetProcessIsSuspended(
+ _In_ PSYSTEM_PROCESS_INFORMATION Process
+ )
+{
+ ULONG i;
+
+ for (i = 0; i < Process->NumberOfThreads; i++)
+ {
+ if (
+ Process->Threads[i].ThreadState != Waiting ||
+ Process->Threads[i].WaitReason != Suspended
+ )
+ return FALSE;
+ }
+
+ return Process->NumberOfThreads != 0;
+}
+
+BOOLEAN PhIsProcessSuspended(
+ _In_ HANDLE ProcessId
+ )
+{
+ BOOLEAN suspended = FALSE;
+ PVOID processes;
+ PSYSTEM_PROCESS_INFORMATION process;
+
+ if (NT_SUCCESS(PhEnumProcesses(&processes)))
+ {
+ if (process = PhFindProcessInformation(processes, ProcessId))
+ {
+ suspended = PhGetProcessIsSuspended(process);
+ }
+
+ PhFree(processes);
+ }
+
+ return suspended;
+}
+
+/**
+ * Determines the OS compatibility context of a process.
+ *
+ * \param ProcessHandle A handle to a process.
+ * \param Guid A variable which receives a GUID identifying an
+ * operating system version.
+ */
+NTSTATUS PhGetProcessSwitchContext(
+ _In_ HANDLE ProcessHandle,
+ _Out_ PGUID Guid
+ )
+{
+ NTSTATUS status;
+ PROCESS_BASIC_INFORMATION basicInfo;
+#ifdef _WIN64
+ PVOID peb32;
+ ULONG data32;
+#endif
+ PVOID data;
+
+ // Reverse-engineered from WdcGetProcessSwitchContext (wdc.dll).
+ // On Windows 8, the function is now SdbGetAppCompatData (apphelp.dll).
+ // On Windows 10, the function is again WdcGetProcessSwitchContext.
+
+#ifdef _WIN64
+ if (NT_SUCCESS(PhGetProcessPeb32(ProcessHandle, &peb32)) && peb32)
+ {
+ if (WindowsVersion >= WINDOWS_8)
+ {
+ if (!NT_SUCCESS(status = NtReadVirtualMemory(
+ ProcessHandle,
+ PTR_ADD_OFFSET(peb32, FIELD_OFFSET(PEB32, pShimData)),
+ &data32,
+ sizeof(ULONG),
+ NULL
+ )))
+ return status;
+ }
+ else
+ {
+ if (!NT_SUCCESS(status = NtReadVirtualMemory(
+ ProcessHandle,
+ PTR_ADD_OFFSET(peb32, FIELD_OFFSET(PEB32, pContextData)),
+ &data32,
+ sizeof(ULONG),
+ NULL
+ )))
+ return status;
+ }
+
+ data = UlongToPtr(data32);
+ }
+ else
+ {
+#endif
+ if (!NT_SUCCESS(status = PhGetProcessBasicInformation(ProcessHandle, &basicInfo)))
+ return status;
+
+ if (WindowsVersion >= WINDOWS_8)
+ {
+ if (!NT_SUCCESS(status = NtReadVirtualMemory(
+ ProcessHandle,
+ PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, pShimData)),
+ &data,
+ sizeof(PVOID),
+ NULL
+ )))
+ return status;
+ }
+ else
+ {
+ if (!NT_SUCCESS(status = NtReadVirtualMemory(
+ ProcessHandle,
+ PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, pUnused)),
+ &data,
+ sizeof(PVOID),
+ NULL
+ )))
+ return status;
+ }
+#ifdef _WIN64
+ }
+#endif
+
+ if (!data)
+ return STATUS_UNSUCCESSFUL; // no compatibility context data
+
+ if (WindowsVersion >= WINDOWS_10_RS5)
+ {
+ if (!NT_SUCCESS(status = NtReadVirtualMemory(
+ ProcessHandle,
+ PTR_ADD_OFFSET(data, 2040 + 24), // Magic value from SbReadProcContextByHandle
+ Guid,
+ sizeof(GUID),
+ NULL
+ )))
+ return status;
+ }
+ else if (WindowsVersion >= WINDOWS_10_RS2)
+ {
+ if (!NT_SUCCESS(status = NtReadVirtualMemory(
+ ProcessHandle,
+ PTR_ADD_OFFSET(data, 1544),
+ Guid,
+ sizeof(GUID),
+ NULL
+ )))
+ return status;
+ }
+ else if (WindowsVersion >= WINDOWS_10)
+ {
+ if (!NT_SUCCESS(status = NtReadVirtualMemory(
+ ProcessHandle,
+ PTR_ADD_OFFSET(data, 2040 + 24), // Magic value from SbReadProcContextByHandle
+ Guid,
+ sizeof(GUID),
+ NULL
+ )))
+ return status;
+ }
+ else if (WindowsVersion >= WINDOWS_8_1)
+ {
+ if (!NT_SUCCESS(status = NtReadVirtualMemory(
+ ProcessHandle,
+ PTR_ADD_OFFSET(data, 2040 + 16), // Magic value from SbReadProcContextByHandle
+ Guid,
+ sizeof(GUID),
+ NULL
+ )))
+ return status;
+ }
+ else if (WindowsVersion >= WINDOWS_8)
+ {
+ if (!NT_SUCCESS(status = NtReadVirtualMemory(
+ ProcessHandle,
+ PTR_ADD_OFFSET(data, 2040), // Magic value from SbReadProcContextByHandle
+ Guid,
+ sizeof(GUID),
+ NULL
+ )))
+ return status;
+ }
+ else
+ {
+ if (!NT_SUCCESS(status = NtReadVirtualMemory(
+ ProcessHandle,
+ PTR_ADD_OFFSET(data, 32), // Magic value from WdcGetProcessSwitchContext
+ Guid,
+ sizeof(GUID),
+ NULL
+ )))
+ return status;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+/**
+ * Determines the type of a process based on its image file name.
+ *
+ * \param ProcessHandle A handle to a process.
+ * \param KnownProcessType A variable which receives the process
+ * type.
+ */
+NTSTATUS PhGetProcessKnownType(
+ _In_ HANDLE ProcessHandle,
+ _Out_ PH_KNOWN_PROCESS_TYPE *KnownProcessType
+ )
+{
+ NTSTATUS status;
+ PROCESS_BASIC_INFORMATION basicInfo;
+ PPH_STRING fileName;
+ PPH_STRING newFileName;
+
+ if (!NT_SUCCESS(status = PhGetProcessBasicInformation(
+ ProcessHandle,
+ &basicInfo
+ )))
+ return status;
+
+ if (basicInfo.UniqueProcessId == SYSTEM_PROCESS_ID)
+ {
+ *KnownProcessType = SystemProcessType;
+ return STATUS_SUCCESS;
+ }
+
+ if (!NT_SUCCESS(status = PhGetProcessImageFileName(
+ ProcessHandle,
+ &fileName
+ )))
+ {
+ return status;
+ }
+
+ newFileName = PhGetFileName(fileName);
+ PhDereferenceObject(fileName);
+
+ *KnownProcessType = PhGetProcessKnownTypeEx(
+ basicInfo.UniqueProcessId,
+ newFileName
+ );
+
+ PhDereferenceObject(newFileName);
+
+ return status;
+}
+
+PH_KNOWN_PROCESS_TYPE PhGetProcessKnownTypeEx(
+ _In_ HANDLE ProcessId,
+ _In_ PPH_STRING FileName
+ )
+{
+ PH_KNOWN_PROCESS_TYPE knownProcessType;
+ PH_STRINGREF systemRootPrefix;
+ PPH_STRING fileName;
+ PH_STRINGREF name;
+#ifdef _WIN64
+ BOOLEAN isWow64 = FALSE;
+#endif
+
+ if (ProcessId == SYSTEM_PROCESS_ID || ProcessId == SYSTEM_IDLE_PROCESS_ID)
+ return SystemProcessType;
+
+ if (PhIsNullOrEmptyString(FileName))
+ return UnknownProcessType;
+
+ PhGetSystemRoot(&systemRootPrefix);
+
+ fileName = PhReferenceObject(FileName);
+ name = fileName->sr;
+
+ knownProcessType = UnknownProcessType;
+
+ if (PhStartsWithStringRef(&name, &systemRootPrefix, TRUE))
+ {
+ // Skip the system root, and we now have three cases:
+ // 1. \\xyz.exe - Windows executable.
+ // 2. \\System32\\xyz.exe - system32 executable.
+ // 3. \\SysWow64\\xyz.exe - system32 executable + WOW64.
+ PhSkipStringRef(&name, systemRootPrefix.Length);
+
+ if (PhEqualStringRef2(&name, L"\\explorer.exe", TRUE))
+ {
+ knownProcessType = ExplorerProcessType;
+ }
+ else if (
+ PhStartsWithStringRef2(&name, L"\\System32", TRUE)
+#ifdef _WIN64
+ || (PhStartsWithStringRef2(&name, L"\\SysWow64", TRUE) && (isWow64 = TRUE, TRUE)) // ugly but necessary
+#endif
+ )
+ {
+ // SysTem32 and SysWow64 are both 8 characters long.
+ PhSkipStringRef(&name, 9 * sizeof(WCHAR));
+
+ if (FALSE)
+ ; // Dummy
+ else if (PhEqualStringRef2(&name, L"\\smss.exe", TRUE))
+ knownProcessType = SessionManagerProcessType;
+ else if (PhEqualStringRef2(&name, L"\\csrss.exe", TRUE))
+ knownProcessType = WindowsSubsystemProcessType;
+ else if (PhEqualStringRef2(&name, L"\\wininit.exe", TRUE))
+ knownProcessType = WindowsStartupProcessType;
+ else if (PhEqualStringRef2(&name, L"\\services.exe", TRUE))
+ knownProcessType = ServiceControlManagerProcessType;
+ else if (PhEqualStringRef2(&name, L"\\lsass.exe", TRUE))
+ knownProcessType = LocalSecurityAuthorityProcessType;
+ else if (PhEqualStringRef2(&name, L"\\lsm.exe", TRUE))
+ knownProcessType = LocalSessionManagerProcessType;
+ else if (PhEqualStringRef2(&name, L"\\winlogon.exe", TRUE))
+ knownProcessType = WindowsLogonProcessType;
+ else if (PhEqualStringRef2(&name, L"\\svchost.exe", TRUE))
+ knownProcessType = ServiceHostProcessType;
+ else if (PhEqualStringRef2(&name, L"\\rundll32.exe", TRUE))
+ knownProcessType = RunDllAsAppProcessType;
+ else if (PhEqualStringRef2(&name, L"\\dllhost.exe", TRUE))
+ knownProcessType = ComSurrogateProcessType;
+ else if (PhEqualStringRef2(&name, L"\\taskeng.exe", TRUE))
+ knownProcessType = TaskHostProcessType;
+ else if (PhEqualStringRef2(&name, L"\\taskhost.exe", TRUE))
+ knownProcessType = TaskHostProcessType;
+ else if (PhEqualStringRef2(&name, L"\\taskhostex.exe", TRUE))
+ knownProcessType = TaskHostProcessType;
+ else if (PhEqualStringRef2(&name, L"\\taskhostw.exe", TRUE))
+ knownProcessType = TaskHostProcessType;
+ else if (PhEqualStringRef2(&name, L"\\wudfhost.exe", TRUE))
+ knownProcessType = UmdfHostProcessType;
+ else if (PhEqualStringRef2(&name, L"\\wbem\\WmiPrvSE.exe", TRUE))
+ knownProcessType = WmiProviderHostType;
+ else if (PhEqualStringRef2(&name, L"\\MicrosoftEdgeCP.exe", TRUE)) // RS5
+ knownProcessType = EdgeProcessType;
+ else if (PhEqualStringRef2(&name, L"\\MicrosoftEdgeSH.exe", TRUE)) // RS5
+ knownProcessType = EdgeProcessType;
+ }
+ else
+ {
+ if (PhEndsWithStringRef2(&name, L"\\MicrosoftEdgeCP.exe", TRUE)) // RS4
+ knownProcessType = EdgeProcessType;
+ else if (PhEndsWithStringRef2(&name, L"\\MicrosoftEdge.exe", TRUE))
+ knownProcessType = EdgeProcessType;
+ else if (PhEndsWithStringRef2(&name, L"\\ServiceWorkerHost.exe", TRUE))
+ knownProcessType = EdgeProcessType;
+ else if (PhEndsWithStringRef2(&name, L"\\Windows.WARP.JITService.exe", TRUE))
+ knownProcessType = EdgeProcessType;
+ }
+ }
+
+ PhDereferenceObject(fileName);
+
+#ifdef _WIN64
+ if (isWow64)
+ knownProcessType |= KnownProcessWow64;
+#endif
+
+ return knownProcessType;
+}
+
+static BOOLEAN NTAPI PhpSvchostCommandLineCallback(
+ _In_opt_ PPH_COMMAND_LINE_OPTION Option,
+ _In_opt_ PPH_STRING Value,
+ _In_opt_ PVOID Context
+ )
+{
+ PPH_KNOWN_PROCESS_COMMAND_LINE knownCommandLine = Context;
+
+ if (Option && Option->Id == 1)
+ {
+ PhSwapReference(&knownCommandLine->ServiceHost.GroupName, Value);
+ }
+
+ return TRUE;
+}
+
+BOOLEAN PhaGetProcessKnownCommandLine(
+ _In_ PPH_STRING CommandLine,
+ _In_ PH_KNOWN_PROCESS_TYPE KnownProcessType,
+ _Out_ PPH_KNOWN_PROCESS_COMMAND_LINE KnownCommandLine
+ )
+{
+ switch (KnownProcessType & KnownProcessTypeMask)
+ {
+ case ServiceHostProcessType:
+ {
+ // svchost.exe -k
+
+ static PH_COMMAND_LINE_OPTION options[] =
+ {
+ { 1, L"k", MandatoryArgumentType }
+ };
+
+ KnownCommandLine->ServiceHost.GroupName = NULL;
+
+ PhParseCommandLine(
+ &CommandLine->sr,
+ options,
+ sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION),
+ PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS,
+ PhpSvchostCommandLineCallback,
+ KnownCommandLine
+ );
+
+ if (KnownCommandLine->ServiceHost.GroupName)
+ {
+ PH_AUTO(KnownCommandLine->ServiceHost.GroupName);
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+ break;
+ case RunDllAsAppProcessType:
+ {
+ // rundll32.exe , ...
+
+ SIZE_T i;
+ PH_STRINGREF dllNamePart;
+ PH_STRINGREF procedureNamePart;
+ PPH_STRING dllName;
+ PPH_STRING procedureName;
+
+ i = 0;
+
+ // Get the rundll32.exe part.
+
+ dllName = PhParseCommandLinePart(&CommandLine->sr, &i);
+
+ if (!dllName)
+ return FALSE;
+
+ PhDereferenceObject(dllName);
+
+ // Get the DLL name part.
+
+ while (i < CommandLine->Length / sizeof(WCHAR) && CommandLine->Buffer[i] == ' ')
+ i++;
+
+ dllName = PhParseCommandLinePart(&CommandLine->sr, &i);
+
+ if (!dllName)
+ return FALSE;
+
+ PH_AUTO(dllName);
+
+ // The procedure name begins after the last comma.
+
+ if (!PhSplitStringRefAtLastChar(&dllName->sr, ',', &dllNamePart, &procedureNamePart))
+ return FALSE;
+
+ dllName = PH_AUTO(PhCreateString2(&dllNamePart));
+ procedureName = PH_AUTO(PhCreateString2(&procedureNamePart));
+
+ // If the DLL name isn't an absolute path, assume it's in system32.
+ // TODO: Use a proper search function.
+
+ if (RtlDetermineDosPathNameType_U(dllName->Buffer) == RtlPathTypeRelative)
+ {
+ dllName = PhaConcatStrings(
+ 3,
+ PH_AUTO_T(PH_STRING, PhGetSystemDirectory())->Buffer,
+ L"\\",
+ dllName->Buffer
+ );
+ }
+
+ KnownCommandLine->RunDllAsApp.FileName = dllName;
+ KnownCommandLine->RunDllAsApp.ProcedureName = procedureName;
+ }
+ break;
+ case ComSurrogateProcessType:
+ {
+ // dllhost.exe /processid:
+
+ static PH_STRINGREF inprocServer32Name = PH_STRINGREF_INIT(L"InprocServer32");
+
+ SIZE_T i;
+ ULONG_PTR indexOfProcessId;
+ PPH_STRING argPart;
+ PPH_STRING guidString;
+ UNICODE_STRING guidStringUs;
+ GUID guid;
+ HANDLE rootKeyHandle;
+ HANDLE inprocServer32KeyHandle;
+ PPH_STRING fileName;
+
+ i = 0;
+
+ // Get the dllhost.exe part.
+
+ argPart = PhParseCommandLinePart(&CommandLine->sr, &i);
+
+ if (!argPart)
+ return FALSE;
+
+ PhDereferenceObject(argPart);
+
+ // Get the argument part.
+
+ while (i < (ULONG)CommandLine->Length / sizeof(WCHAR) && CommandLine->Buffer[i] == ' ')
+ i++;
+
+ argPart = PhParseCommandLinePart(&CommandLine->sr, &i);
+
+ if (!argPart)
+ return FALSE;
+
+ PH_AUTO(argPart);
+
+ // Find "/processid:"; the GUID is just after that.
+
+ _wcsupr(argPart->Buffer);
+ indexOfProcessId = PhFindStringInString(argPart, 0, L"/PROCESSID:");
+
+ if (indexOfProcessId == -1)
+ return FALSE;
+
+ guidString = PhaSubstring(
+ argPart,
+ indexOfProcessId + 11,
+ (ULONG)argPart->Length / sizeof(WCHAR) - indexOfProcessId - 11
+ );
+ PhStringRefToUnicodeString(&guidString->sr, &guidStringUs);
+
+ if (!NT_SUCCESS(RtlGUIDFromString(
+ &guidStringUs,
+ &guid
+ )))
+ return FALSE;
+
+ KnownCommandLine->ComSurrogate.Guid = guid;
+ KnownCommandLine->ComSurrogate.Name = NULL;
+ KnownCommandLine->ComSurrogate.FileName = NULL;
+
+ // Lookup the GUID in the registry to determine the name and file name.
+
+ if (NT_SUCCESS(PhOpenKey(
+ &rootKeyHandle,
+ KEY_READ,
+ PH_KEY_CLASSES_ROOT,
+ &PhaConcatStrings2(L"CLSID\\", guidString->Buffer)->sr,
+ 0
+ )))
+ {
+ KnownCommandLine->ComSurrogate.Name =
+ PH_AUTO(PhQueryRegistryString(rootKeyHandle, NULL));
+
+ if (NT_SUCCESS(PhOpenKey(
+ &inprocServer32KeyHandle,
+ KEY_READ,
+ rootKeyHandle,
+ &inprocServer32Name,
+ 0
+ )))
+ {
+ KnownCommandLine->ComSurrogate.FileName =
+ PH_AUTO(PhQueryRegistryString(inprocServer32KeyHandle, NULL));
+
+ if (fileName = PH_AUTO(PhExpandEnvironmentStrings(
+ &KnownCommandLine->ComSurrogate.FileName->sr
+ )))
+ {
+ KnownCommandLine->ComSurrogate.FileName = fileName;
+ }
+
+ NtClose(inprocServer32KeyHandle);
+ }
+
+ NtClose(rootKeyHandle);
+ }
+ else if (NT_SUCCESS(PhOpenKey(
+ &rootKeyHandle,
+ KEY_READ,
+ PH_KEY_CLASSES_ROOT,
+ &PhaConcatStrings2(L"AppID\\", guidString->Buffer)->sr,
+ 0
+ )))
+ {
+ KnownCommandLine->ComSurrogate.Name =
+ PH_AUTO(PhQueryRegistryString(rootKeyHandle, NULL));
+ NtClose(rootKeyHandle);
+ }
+ }
+ break;
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+PPH_STRING PhGetServiceRelevantFileName(
+ _In_ PPH_STRINGREF ServiceName,
+ _In_ SC_HANDLE ServiceHandle
+ )
+{
+ PPH_STRING fileName = NULL;
+ LPQUERY_SERVICE_CONFIG config;
+
+ if (config = PhGetServiceConfig(ServiceHandle))
+ {
+ PhGetServiceDllParameter(config->dwServiceType, ServiceName, &fileName);
+
+ if (!fileName)
+ {
+ PPH_STRING commandLine;
+
+ if (config->lpBinaryPathName[0])
+ {
+ commandLine = PhCreateString(config->lpBinaryPathName);
+
+ if (config->dwServiceType & SERVICE_WIN32)
+ {
+ PH_STRINGREF dummyFileName;
+ PH_STRINGREF dummyArguments;
+
+ PhParseCommandLineFuzzy(&commandLine->sr, &dummyFileName, &dummyArguments, &fileName);
+
+ if (!fileName)
+ PhSwapReference(&fileName, commandLine);
+ }
+ else
+ {
+ fileName = PhGetFileName(commandLine);
+ }
+
+ PhDereferenceObject(commandLine);
+ }
+ }
+
+ PhFree(config);
+ }
+
+ return fileName;
+}
+
+PPH_STRING PhEscapeStringForDelimiter(
+ _In_ PPH_STRING String,
+ _In_ WCHAR Delimiter
+ )
+{
+ PH_STRING_BUILDER stringBuilder;
+ SIZE_T length;
+ SIZE_T i;
+ WCHAR temp[2];
+
+ length = String->Length / sizeof(WCHAR);
+ PhInitializeStringBuilder(&stringBuilder, String->Length / sizeof(WCHAR) * 3);
+
+ temp[0] = '\\';
+
+ for (i = 0; i < length; i++)
+ {
+ if (String->Buffer[i] == '\\' || String->Buffer[i] == Delimiter)
+ {
+ temp[1] = String->Buffer[i];
+ PhAppendStringBuilderEx(&stringBuilder, temp, 4);
+ }
+ else
+ {
+ PhAppendCharStringBuilder(&stringBuilder, String->Buffer[i]);
+ }
+ }
+
+ return PhFinalStringBuilderString(&stringBuilder);
+}
+
+PPH_STRING PhUnescapeStringForDelimiter(
+ _In_ PPH_STRING String,
+ _In_ WCHAR Delimiter
+ )
+{
+ PH_STRING_BUILDER stringBuilder;
+ SIZE_T length;
+ SIZE_T i;
+
+ length = String->Length / sizeof(WCHAR);
+ PhInitializeStringBuilder(&stringBuilder, String->Length / sizeof(WCHAR) * 3);
+
+ for (i = 0; i < length; i++)
+ {
+ if (String->Buffer[i] == '\\')
+ {
+ if (i != length - 1)
+ {
+ PhAppendCharStringBuilder(&stringBuilder, String->Buffer[i + 1]);
+ i++;
+ }
+ else
+ {
+ // Trailing backslash. Just ignore it.
+ break;
+ }
+ }
+ else
+ {
+ PhAppendCharStringBuilder(&stringBuilder, String->Buffer[i]);
+ }
+ }
+
+ return PhFinalStringBuilderString(&stringBuilder);
+}
+
+VOID PhSearchOnlineString(
+ _In_ HWND hWnd,
+ _In_ PWSTR String
+ )
+{
+ PhShellExecuteUserString(hWnd, L"SearchEngine", String, TRUE, NULL);
+}
+
+VOID PhShellExecuteUserString(
+ _In_ HWND hWnd,
+ _In_ PWSTR Setting,
+ _In_ PWSTR String,
+ _In_ BOOLEAN UseShellExecute,
+ _In_opt_ PWSTR ErrorMessage
+ )
+{
+ static PH_STRINGREF replacementToken = PH_STRINGREF_INIT(L"%s");
+ PPH_STRING applicationDirectory;
+ PPH_STRING executeString;
+ PH_STRINGREF stringBefore;
+ PH_STRINGREF stringAfter;
+ PPH_STRING ntMessage;
+
+ if (!(applicationDirectory = PhGetApplicationDirectory()))
+ {
+ PhShowStatus(hWnd, L"Unable to locate the application directory.", STATUS_NOT_FOUND, 0);
+ return;
+ }
+
+ // Get the execute command.
+ executeString = PhGetStringSetting(Setting);
+
+ // Expand environment strings.
+ PhMoveReference(&executeString, PhExpandEnvironmentStrings(&executeString->sr));
+
+ // Make sure the user executable string is absolute. We can't use RtlDetermineDosPathNameType_U
+ // here because the string may be a URL.
+ if (PhFindCharInString(executeString, 0, ':') == -1)
+ {
+ INT stringArgCount;
+ PWSTR* stringArgList;
+
+ // (dmex) HACK: Escape the individual executeString components.
+ if ((stringArgList = CommandLineToArgvW(executeString->Buffer, &stringArgCount)) && stringArgCount == 2)
+ {
+ PPH_STRING fileName = PhCreateString(stringArgList[0]);
+ PPH_STRING fileArgs = PhCreateString(stringArgList[1]);
+
+ // Make sure the string is absolute and escape the filename.
+ if (RtlDetermineDosPathNameType_U(fileName->Buffer) == RtlPathTypeRelative)
+ PhMoveReference(&fileName, PhConcatStrings(4, L"\"", applicationDirectory->Buffer, fileName->Buffer, L"\""));
+ else
+ PhMoveReference(&fileName, PhConcatStrings(3, L"\"", fileName->Buffer, L"\""));
+
+ // Escape the parameters.
+ PhMoveReference(&fileArgs, PhConcatStrings(3, L"\"", fileArgs->Buffer, L"\""));
+
+ // Create the escaped execute string.
+ PhMoveReference(&executeString, PhConcatStrings(3, fileName->Buffer, L" ", fileArgs->Buffer));
+
+ PhDereferenceObject(fileArgs);
+ PhDereferenceObject(fileName);
+ LocalFree(stringArgList);
+ }
+ else
+ {
+ if (RtlDetermineDosPathNameType_U(executeString->Buffer) == RtlPathTypeRelative)
+ PhMoveReference(&executeString, PhConcatStrings(4, L"\"", applicationDirectory->Buffer, executeString->Buffer, L"\""));
+ else
+ PhMoveReference(&executeString, PhConcatStrings(3, L"\"", executeString->Buffer, L"\""));
+ }
+ }
+
+ // Replace the token with the string, or use the original string if the token is not present.
+ if (PhSplitStringRefAtString(&executeString->sr, &replacementToken, FALSE, &stringBefore, &stringAfter))
+ {
+ PPH_STRING stringTemp;
+ PPH_STRING stringMiddle;
+
+ // Note: This code is needed to solve issues with faulty RamDisk software that doesn't use the Mount Manager API
+ // and instead returns \device\ FileName strings. We also can't change the way the process provider stores
+ // the FileName string since it'll break various features and use-cases required by developers
+ // who need the raw untranslated FileName string.
+ stringTemp = PhCreateString(String);
+ stringMiddle = PhGetFileName(stringTemp);
+
+ PhMoveReference(&executeString, PhConcatStringRef3(&stringBefore, &stringMiddle->sr, &stringAfter));
+
+ PhDereferenceObject(stringMiddle);
+ PhDereferenceObject(stringTemp);
+ }
+
+ if (UseShellExecute)
+ {
+ PhShellExecute(hWnd, executeString->Buffer, NULL);
+ }
+ else
+ {
+ NTSTATUS status;
+
+ status = PhCreateProcessWin32(NULL, executeString->Buffer, NULL, NULL, 0, NULL, NULL, NULL);
+
+ if (!NT_SUCCESS(status))
+ {
+ if (ErrorMessage)
+ {
+ ntMessage = PhGetNtMessage(status);
+ PhShowError2(
+ hWnd,
+ L"Unable to execute the command.",
+ L"%s\n%s",
+ PhGetStringOrDefault(ntMessage, L"An unknown error occurred."),
+ ErrorMessage
+ );
+ PhDereferenceObject(ntMessage);
+ }
+ else
+ {
+ PhShowStatus(hWnd, L"Unable to execute the command.", status, 0);
+ }
+ }
+ }
+
+ PhDereferenceObject(executeString);
+ PhDereferenceObject(applicationDirectory);
+}
+
+VOID PhLoadSymbolProviderOptions(
+ _Inout_ PPH_SYMBOL_PROVIDER SymbolProvider
+ )
+{
+ PPH_STRING searchPath;
+
+ PhSetOptionsSymbolProvider(
+ SYMOPT_UNDNAME,
+ PhGetIntegerSetting(L"DbgHelpUndecorate") ? SYMOPT_UNDNAME : 0
+ );
+
+ searchPath = PhGetStringSetting(L"DbgHelpSearchPath");
+
+ if (searchPath->Length != 0)
+ PhSetSearchPathSymbolProvider(SymbolProvider, searchPath->Buffer);
+
+ PhDereferenceObject(searchPath);
+}
+
+/**
+ * Copies a string into a NMLVGETINFOTIP structure.
+ *
+ * \param GetInfoTip The NMLVGETINFOTIP structure.
+ * \param Tip The string to copy.
+ *
+ * \remarks The text is truncated if it is too long.
+ */
+VOID PhCopyListViewInfoTip(
+ _Inout_ LPNMLVGETINFOTIP GetInfoTip,
+ _In_ PPH_STRINGREF Tip
+ )
+{
+ ULONG copyIndex;
+ ULONG bufferRemaining;
+ ULONG copyLength;
+
+ if (GetInfoTip->dwFlags == 0)
+ {
+ copyIndex = (ULONG)PhCountStringZ(GetInfoTip->pszText) + 1; // plus one for newline
+
+ if (GetInfoTip->cchTextMax - copyIndex < 2) // need at least two bytes
+ return;
+
+ bufferRemaining = GetInfoTip->cchTextMax - copyIndex - 1;
+ GetInfoTip->pszText[copyIndex - 1] = '\n';
+ }
+ else
+ {
+ copyIndex = 0;
+ bufferRemaining = GetInfoTip->cchTextMax;
+ }
+
+ copyLength = min((ULONG)Tip->Length / sizeof(WCHAR), bufferRemaining - 1);
+ memcpy(
+ &GetInfoTip->pszText[copyIndex],
+ Tip->Buffer,
+ copyLength * 2
+ );
+ GetInfoTip->pszText[copyIndex + copyLength] = UNICODE_NULL;
+}
+
+VOID PhCopyListView(
+ _In_ HWND ListViewHandle
+ )
+{
+ PPH_STRING text;
+
+ text = PhGetListViewText(ListViewHandle);
+ PhSetClipboardString(ListViewHandle, &text->sr);
+ PhDereferenceObject(text);
+}
+
+VOID PhHandleListViewNotifyForCopy(
+ _In_ LPARAM lParam,
+ _In_ HWND ListViewHandle
+ )
+{
+ PhHandleListViewNotifyBehaviors(lParam, ListViewHandle, PH_LIST_VIEW_CTRL_C_BEHAVIOR);
+}
+
+VOID PhHandleListViewNotifyBehaviors(
+ _In_ LPARAM lParam,
+ _In_ HWND ListViewHandle,
+ _In_ ULONG Behaviors
+ )
+{
+ if (((LPNMHDR)lParam)->hwndFrom == ListViewHandle && ((LPNMHDR)lParam)->code == LVN_KEYDOWN)
+ {
+ LPNMLVKEYDOWN keyDown = (LPNMLVKEYDOWN)lParam;
+
+ switch (keyDown->wVKey)
+ {
+ case 'C':
+ if (Behaviors & PH_LIST_VIEW_CTRL_C_BEHAVIOR)
+ {
+ if (GetKeyState(VK_CONTROL) < 0)
+ PhCopyListView(ListViewHandle);
+ }
+ break;
+ case 'A':
+ if (Behaviors & PH_LIST_VIEW_CTRL_A_BEHAVIOR)
+ {
+ if (GetKeyState(VK_CONTROL) < 0)
+ PhSetStateAllListViewItems(ListViewHandle, LVIS_SELECTED, LVIS_SELECTED);
+ }
+ break;
+ }
+ }
+}
+
+BOOLEAN PhGetListViewContextMenuPoint(
+ _In_ HWND ListViewHandle,
+ _Out_ PPOINT Point
+ )
+{
+ INT selectedIndex;
+ RECT bounds;
+ RECT clientRect;
+
+ // The user pressed a key to display the context menu.
+ // Suggest where the context menu should display.
+
+ if ((selectedIndex = ListView_GetNextItem(ListViewHandle, -1, LVNI_SELECTED)) != -1)
+ {
+ if (ListView_GetItemRect(ListViewHandle, selectedIndex, &bounds, LVIR_BOUNDS))
+ {
+ Point->x = bounds.left + PhSmallIconSize.X / 2;
+ Point->y = bounds.top + PhSmallIconSize.Y / 2;
+
+ GetClientRect(ListViewHandle, &clientRect);
+
+ if (Point->x < 0 || Point->y < 0 || Point->x >= clientRect.right || Point->y >= clientRect.bottom)
+ {
+ // The menu is going to be outside of the control. Just put it at the top-left.
+ Point->x = 0;
+ Point->y = 0;
+ }
+
+ ClientToScreen(ListViewHandle, Point);
+
+ return TRUE;
+ }
+ }
+
+ Point->x = 0;
+ Point->y = 0;
+ ClientToScreen(ListViewHandle, Point);
+
+ return FALSE;
+}
+
+VOID PhSetWindowOpacity(
+ _In_ HWND WindowHandle,
+ _In_ ULONG OpacityPercent
+ )
+{
+ if (OpacityPercent == 0)
+ {
+ // Make things a bit faster by removing the WS_EX_LAYERED bit.
+ PhSetWindowExStyle(WindowHandle, WS_EX_LAYERED, 0);
+ RedrawWindow(WindowHandle, NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_FRAME | RDW_ALLCHILDREN);
+ return;
+ }
+
+ PhSetWindowExStyle(WindowHandle, WS_EX_LAYERED, WS_EX_LAYERED);
+
+ // Disallow opacity values of less than 10%.
+ OpacityPercent = min(OpacityPercent, 90);
+
+ // The opacity value is backwards - 0 means opaque, 100 means transparent.
+ SetLayeredWindowAttributes(
+ WindowHandle,
+ 0,
+ (BYTE)(255 * (100 - OpacityPercent) / 100),
+ LWA_ALPHA
+ );
+}
+
+PPH_STRING PhGetPhVersion(
+ VOID
+ )
+{
+ PH_FORMAT format[5];
+
+ PhInitFormatU(&format[0], PHAPP_VERSION_MAJOR);
+ PhInitFormatC(&format[1], '.');
+ PhInitFormatU(&format[2], PHAPP_VERSION_MINOR);
+ PhInitFormatC(&format[3], '.');
+ PhInitFormatU(&format[4], PHAPP_VERSION_REVISION);
+
+ return PhFormat(format, 5, 16);
+}
+
+VOID PhGetPhVersionNumbers(
+ _Out_opt_ PULONG MajorVersion,
+ _Out_opt_ PULONG MinorVersion,
+ _Out_opt_ PULONG BuildNumber,
+ _Out_opt_ PULONG RevisionNumber
+ )
+{
+ if (MajorVersion)
+ *MajorVersion = PHAPP_VERSION_MAJOR;
+ if (MinorVersion)
+ *MinorVersion = PHAPP_VERSION_MINOR;
+ if (BuildNumber)
+ *BuildNumber = PHAPP_VERSION_BUILD;
+ if (RevisionNumber)
+ *RevisionNumber = PHAPP_VERSION_REVISION;
+}
+
+VOID PhWritePhTextHeader(
+ _Inout_ PPH_FILE_STREAM FileStream
+ )
+{
+ PPH_STRING version;
+ LARGE_INTEGER time;
+ SYSTEMTIME systemTime;
+ PPH_STRING timeString;
+
+ PhWriteStringAsUtf8FileStream2(FileStream, L"Process Hacker ");
+
+ if (version = PhGetPhVersion())
+ {
+ PhWriteStringAsUtf8FileStream(FileStream, &version->sr);
+ PhDereferenceObject(version);
+ }
+
+ PhWriteStringFormatAsUtf8FileStream(FileStream, L"\r\nWindows NT %lu.%lu", PhOsVersion.dwMajorVersion, PhOsVersion.dwMinorVersion);
+
+ if (PhOsVersion.szCSDVersion[0] != UNICODE_NULL)
+ PhWriteStringFormatAsUtf8FileStream(FileStream, L" %s", PhOsVersion.szCSDVersion);
+
+#ifdef _WIN64
+ PhWriteStringAsUtf8FileStream2(FileStream, L" (64-bit)");
+#else
+ PhWriteStringAsUtf8FileStream2(FileStream, L" (32-bit)");
+#endif
+
+ PhQuerySystemTime(&time);
+ PhLargeIntegerToLocalSystemTime(&systemTime, &time);
+
+ timeString = PhFormatDateTime(&systemTime);
+ PhWriteStringFormatAsUtf8FileStream(FileStream, L"\r\n%s\r\n\r\n", timeString->Buffer);
+ PhDereferenceObject(timeString);
+}
+
+BOOLEAN PhShellProcessHacker(
+ _In_opt_ HWND hWnd,
+ _In_opt_ PWSTR Parameters,
+ _In_ ULONG ShowWindowType,
+ _In_ ULONG Flags,
+ _In_ ULONG AppFlags,
+ _In_opt_ ULONG Timeout,
+ _Out_opt_ PHANDLE ProcessHandle
+ )
+{
+ return PhShellProcessHackerEx(
+ hWnd,
+ NULL,
+ Parameters,
+ ShowWindowType,
+ Flags,
+ AppFlags,
+ Timeout,
+ ProcessHandle
+ );
+}
+
+VOID PhpAppendCommandLineArgument(
+ _Inout_ PPH_STRING_BUILDER StringBuilder,
+ _In_ PWSTR Name,
+ _In_ PPH_STRINGREF Value
+ )
+{
+ PPH_STRING temp;
+
+ PhAppendStringBuilder2(StringBuilder, L" -");
+ PhAppendStringBuilder2(StringBuilder, Name);
+ PhAppendStringBuilder2(StringBuilder, L" \"");
+ temp = PhEscapeCommandLinePart(Value);
+ PhAppendStringBuilder(StringBuilder, &temp->sr);
+ PhDereferenceObject(temp);
+ PhAppendCharStringBuilder(StringBuilder, '\"');
+}
+
+BOOLEAN PhShellProcessHackerEx(
+ _In_opt_ HWND hWnd,
+ _In_opt_ PWSTR FileName,
+ _In_opt_ PWSTR Parameters,
+ _In_ ULONG ShowWindowType,
+ _In_ ULONG Flags,
+ _In_ ULONG AppFlags,
+ _In_opt_ ULONG Timeout,
+ _Out_opt_ PHANDLE ProcessHandle
+ )
+{
+ BOOLEAN result;
+ PPH_STRING applicationFileName;
+ PH_STRING_BUILDER sb;
+ PWSTR parameters;
+
+ if (!(applicationFileName = PhGetApplicationFileName()))
+ return FALSE;
+
+ if (AppFlags & PH_SHELL_APP_PROPAGATE_PARAMETERS)
+ {
+ PhInitializeStringBuilder(&sb, 128);
+
+ // Propagate parameters.
+
+ if (PhStartupParameters.NoSettings)
+ {
+ PhAppendStringBuilder2(&sb, L" -nosettings");
+ }
+ else if (PhStartupParameters.SettingsFileName && (PhSettingsFileName || (AppFlags & PH_SHELL_APP_PROPAGATE_PARAMETERS_FORCE_SETTINGS)))
+ {
+ PPH_STRINGREF fileName;
+
+ if (PhSettingsFileName)
+ fileName = &PhSettingsFileName->sr;
+ else
+ fileName = &PhStartupParameters.SettingsFileName->sr;
+
+ PhpAppendCommandLineArgument(&sb, L"settings", fileName);
+ }
+
+ if (PhStartupParameters.NoKph)
+ PhAppendStringBuilder2(&sb, L" -nokph");
+ if (PhStartupParameters.InstallKph)
+ PhAppendStringBuilder2(&sb, L" -installkph");
+ if (PhStartupParameters.UninstallKph)
+ PhAppendStringBuilder2(&sb, L" -uninstallkph");
+ if (PhStartupParameters.Debug)
+ PhAppendStringBuilder2(&sb, L" -debug");
+ if (PhStartupParameters.NoPlugins)
+ PhAppendStringBuilder2(&sb, L" -noplugins");
+ if (PhStartupParameters.NewInstance)
+ PhAppendStringBuilder2(&sb, L" -newinstance");
+
+ if (PhStartupParameters.SelectPid != 0)
+ PhAppendFormatStringBuilder(&sb, L" -selectpid %lu", PhStartupParameters.SelectPid);
+
+ if (PhStartupParameters.PriorityClass != 0)
+ {
+ CHAR value = 0;
+
+ switch (PhStartupParameters.PriorityClass)
+ {
+ case PROCESS_PRIORITY_CLASS_REALTIME:
+ value = L'r';
+ break;
+ case PROCESS_PRIORITY_CLASS_HIGH:
+ value = L'h';
+ break;
+ case PROCESS_PRIORITY_CLASS_NORMAL:
+ value = L'n';
+ break;
+ case PROCESS_PRIORITY_CLASS_IDLE:
+ value = L'l';
+ break;
+ }
+
+ if (value != 0)
+ {
+ PhAppendStringBuilder2(&sb, L" -priority ");
+ PhAppendCharStringBuilder(&sb, value);
+ }
+ }
+
+ if (PhStartupParameters.PluginParameters)
+ {
+ ULONG i;
+
+ for (i = 0; i < PhStartupParameters.PluginParameters->Count; i++)
+ {
+ PPH_STRING value = PhStartupParameters.PluginParameters->Items[i];
+ PhpAppendCommandLineArgument(&sb, L"plugin", &value->sr);
+ }
+ }
+
+ if (PhStartupParameters.SelectTab)
+ PhpAppendCommandLineArgument(&sb, L"selecttab", &PhStartupParameters.SelectTab->sr);
+
+ if (!(AppFlags & PH_SHELL_APP_PROPAGATE_PARAMETERS_IGNORE_VISIBILITY))
+ {
+ if (PhStartupParameters.ShowVisible)
+ PhAppendStringBuilder2(&sb, L" -v");
+ if (PhStartupParameters.ShowHidden)
+ PhAppendStringBuilder2(&sb, L" -hide");
+ }
+
+ // Add user-specified parameters last so they can override the propagated parameters.
+ if (Parameters)
+ {
+ PhAppendCharStringBuilder(&sb, ' ');
+ PhAppendStringBuilder2(&sb, Parameters);
+ }
+
+ if (sb.String->Length != 0 && sb.String->Buffer[0] == ' ')
+ parameters = sb.String->Buffer + 1;
+ else
+ parameters = sb.String->Buffer;
+ }
+ else
+ {
+ parameters = Parameters;
+ }
+
+ result = PhShellExecuteEx(
+ hWnd,
+ FileName ? FileName : PhGetString(applicationFileName),
+ parameters,
+ ShowWindowType,
+ Flags,
+ Timeout,
+ ProcessHandle
+ );
+
+ if (AppFlags & PH_SHELL_APP_PROPAGATE_PARAMETERS)
+ PhDeleteStringBuilder(&sb);
+
+ PhDereferenceObject(applicationFileName);
+
+ return result;
+}
+
+BOOLEAN PhCreateProcessIgnoreIfeoDebugger(
+ _In_ PWSTR FileName
+ )
+{
+ BOOLEAN result;
+ BOOLEAN originalValue;
+ HANDLE processHandle;
+
+ result = FALSE;
+
+ RtlEnterCriticalSection(NtCurrentPeb()->FastPebLock);
+ originalValue = NtCurrentPeb()->ReadImageFileExecOptions;
+ NtCurrentPeb()->ReadImageFileExecOptions = FALSE;
+ RtlLeaveCriticalSection(NtCurrentPeb()->FastPebLock);
+
+ // The combination of ReadImageFileExecOptions = FALSE and the DEBUG_PROCESS flag
+ // allows us to skip the Debugger IFEO value. (wj32)
+
+ if (NT_SUCCESS(PhCreateProcessWin32(
+ FileName,
+ NULL,
+ NULL,
+ NULL,
+ PH_CREATE_PROCESS_DEBUG | PH_CREATE_PROCESS_DEBUG_ONLY_THIS_PROCESS,
+ NULL,
+ &processHandle,
+ NULL
+ )))
+ {
+ HANDLE debugObjectHandle;
+
+ if (NT_SUCCESS(PhGetProcessDebugObject(
+ processHandle,
+ &debugObjectHandle
+ )))
+ {
+ // Disable kill-on-close.
+ if (NT_SUCCESS(PhSetDebugKillProcessOnExit(
+ debugObjectHandle,
+ FALSE
+ )))
+ {
+ // Stop debugging the process now.
+ NtRemoveProcessDebug(processHandle, debugObjectHandle);
+ }
+
+ NtClose(debugObjectHandle);
+ }
+
+ result = TRUE;
+
+ NtClose(processHandle);
+ }
+
+ if (originalValue)
+ {
+ RtlEnterCriticalSection(NtCurrentPeb()->FastPebLock);
+ NtCurrentPeb()->ReadImageFileExecOptions = originalValue;
+ RtlLeaveCriticalSection(NtCurrentPeb()->FastPebLock);
+ }
+
+ return result;
+}
+
+VOID PhInitializeTreeNewColumnMenu(
+ _Inout_ PPH_TN_COLUMN_MENU_DATA Data
+ )
+{
+ PhInitializeTreeNewColumnMenuEx(Data, 0);
+}
+
+VOID PhInitializeTreeNewColumnMenuEx(
+ _Inout_ PPH_TN_COLUMN_MENU_DATA Data,
+ _In_ ULONG Flags
+ )
+{
+ PPH_EMENU_ITEM resetSortMenuItem = NULL;
+ PPH_EMENU_ITEM sizeColumnToFitMenuItem;
+ PPH_EMENU_ITEM sizeAllColumnsToFitMenuItem;
+ PPH_EMENU_ITEM hideColumnMenuItem;
+ PPH_EMENU_ITEM chooseColumnsMenuItem;
+ ULONG minimumNumberOfColumns;
+
+ Data->Menu = PhCreateEMenu();
+ Data->Selection = NULL;
+ Data->ProcessedId = 0;
+
+ sizeColumnToFitMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_SIZE_COLUMN_TO_FIT_ID, L"Size column to fit", NULL, NULL);
+ sizeAllColumnsToFitMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_SIZE_ALL_COLUMNS_TO_FIT_ID, L"Size all columns to fit", NULL, NULL);
+
+ if (!(Flags & PH_TN_COLUMN_MENU_NO_VISIBILITY))
+ {
+ hideColumnMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_HIDE_COLUMN_ID, L"Hide column", NULL, NULL);
+ chooseColumnsMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_CHOOSE_COLUMNS_ID, L"Choose columns...", NULL, NULL);
+ }
+
+ if (Flags & PH_TN_COLUMN_MENU_SHOW_RESET_SORT)
+ {
+ ULONG sortColumn;
+ PH_SORT_ORDER sortOrder;
+
+ TreeNew_GetSort(Data->TreeNewHandle, &sortColumn, &sortOrder);
+
+ if (sortOrder != Data->DefaultSortOrder || (Data->DefaultSortOrder != NoSortOrder && sortColumn != Data->DefaultSortColumn))
+ resetSortMenuItem = PhCreateEMenuItem(0, PH_TN_COLUMN_MENU_RESET_SORT_ID, L"Reset sort", NULL, NULL);
+ }
+
+ PhInsertEMenuItem(Data->Menu, sizeColumnToFitMenuItem, ULONG_MAX);
+ PhInsertEMenuItem(Data->Menu, sizeAllColumnsToFitMenuItem, ULONG_MAX);
+
+ if (!(Flags & PH_TN_COLUMN_MENU_NO_VISIBILITY))
+ {
+ PhInsertEMenuItem(Data->Menu, hideColumnMenuItem, ULONG_MAX);
+
+ if (resetSortMenuItem)
+ PhInsertEMenuItem(Data->Menu, resetSortMenuItem, ULONG_MAX);
+
+ PhInsertEMenuItem(Data->Menu, PhCreateEMenuSeparator(), ULONG_MAX);
+ PhInsertEMenuItem(Data->Menu, chooseColumnsMenuItem, ULONG_MAX);
+
+ if (TreeNew_GetFixedColumn(Data->TreeNewHandle))
+ minimumNumberOfColumns = 2; // don't allow user to remove all normal columns (the fixed column can never be removed)
+ else
+ minimumNumberOfColumns = 1;
+
+ if (!Data->MouseEvent || !Data->MouseEvent->Column ||
+ Data->MouseEvent->Column->Fixed || // don't allow the fixed column to be hidden
+ TreeNew_GetVisibleColumnCount(Data->TreeNewHandle) < minimumNumberOfColumns + 1
+ )
+ {
+ hideColumnMenuItem->Flags |= PH_EMENU_DISABLED;
+ }
+ }
+ else
+ {
+ if (resetSortMenuItem)
+ PhInsertEMenuItem(Data->Menu, resetSortMenuItem, ULONG_MAX);
+ }
+
+ if (!Data->MouseEvent || !Data->MouseEvent->Column)
+ {
+ sizeColumnToFitMenuItem->Flags |= PH_EMENU_DISABLED;
+ }
+}
+
+VOID PhpEnsureValidSortColumnTreeNew(
+ _Inout_ HWND TreeNewHandle,
+ _In_ ULONG DefaultSortColumn,
+ _In_ PH_SORT_ORDER DefaultSortOrder
+ )
+{
+ ULONG sortColumn;
+ PH_SORT_ORDER sortOrder;
+
+ // Make sure the column we're sorting by is actually visible, and if not, don't sort anymore.
+
+ TreeNew_GetSort(TreeNewHandle, &sortColumn, &sortOrder);
+
+ if (sortOrder != NoSortOrder)
+ {
+ PH_TREENEW_COLUMN column;
+
+ TreeNew_GetColumn(TreeNewHandle, sortColumn, &column);
+
+ if (!column.Visible)
+ {
+ if (DefaultSortOrder != NoSortOrder)
+ {
+ // Make sure the default sort column is visible.
+ TreeNew_GetColumn(TreeNewHandle, DefaultSortColumn, &column);
+
+ if (!column.Visible)
+ {
+ ULONG maxId;
+ ULONG id;
+ BOOLEAN found;
+
+ // Use the first visible column.
+ maxId = TreeNew_GetMaxId(TreeNewHandle);
+ id = 0;
+ found = FALSE;
+
+ while (id <= maxId)
+ {
+ if (TreeNew_GetColumn(TreeNewHandle, id, &column))
+ {
+ if (column.Visible)
+ {
+ DefaultSortColumn = id;
+ found = TRUE;
+ break;
+ }
+ }
+
+ id++;
+ }
+
+ if (!found)
+ {
+ DefaultSortColumn = 0;
+ DefaultSortOrder = NoSortOrder;
+ }
+ }
+ }
+
+ TreeNew_SetSort(TreeNewHandle, DefaultSortColumn, DefaultSortOrder);
+ }
+ }
+}
+
+BOOLEAN PhHandleTreeNewColumnMenu(
+ _Inout_ PPH_TN_COLUMN_MENU_DATA Data
+ )
+{
+ if (!Data->Selection)
+ return FALSE;
+
+ switch (Data->Selection->Id)
+ {
+ case PH_TN_COLUMN_MENU_RESET_SORT_ID:
+ {
+ TreeNew_SetSort(Data->TreeNewHandle, Data->DefaultSortColumn, Data->DefaultSortOrder);
+ }
+ break;
+ case PH_TN_COLUMN_MENU_SIZE_COLUMN_TO_FIT_ID:
+ {
+ if (Data->MouseEvent && Data->MouseEvent->Column)
+ {
+ TreeNew_AutoSizeColumn(Data->TreeNewHandle, Data->MouseEvent->Column->Id, 0);
+ }
+ }
+ break;
+ case PH_TN_COLUMN_MENU_SIZE_ALL_COLUMNS_TO_FIT_ID:
+ {
+ ULONG maxId;
+ ULONG id;
+
+ maxId = TreeNew_GetMaxId(Data->TreeNewHandle);
+ id = 0;
+
+ while (id <= maxId)
+ {
+ TreeNew_AutoSizeColumn(Data->TreeNewHandle, id, 0);
+ id++;
+ }
+ }
+ break;
+ case PH_TN_COLUMN_MENU_HIDE_COLUMN_ID:
+ {
+ PH_TREENEW_COLUMN column;
+
+ if (Data->MouseEvent && Data->MouseEvent->Column && !Data->MouseEvent->Column->Fixed)
+ {
+ column.Id = Data->MouseEvent->Column->Id;
+ column.Visible = FALSE;
+ TreeNew_SetColumn(Data->TreeNewHandle, TN_COLUMN_FLAG_VISIBLE, &column);
+ PhpEnsureValidSortColumnTreeNew(Data->TreeNewHandle, Data->DefaultSortColumn, Data->DefaultSortOrder);
+ InvalidateRect(Data->TreeNewHandle, NULL, FALSE);
+ }
+ }
+ break;
+ case PH_TN_COLUMN_MENU_CHOOSE_COLUMNS_ID:
+ {
+ PhShowChooseColumnsDialog(Data->TreeNewHandle, Data->TreeNewHandle, PH_CONTROL_TYPE_TREE_NEW);
+ PhpEnsureValidSortColumnTreeNew(Data->TreeNewHandle, Data->DefaultSortColumn, Data->DefaultSortOrder);
+ }
+ break;
+ default:
+ return FALSE;
+ }
+
+ Data->ProcessedId = Data->Selection->Id;
+
+ return TRUE;
+}
+
+VOID PhDeleteTreeNewColumnMenu(
+ _In_ PPH_TN_COLUMN_MENU_DATA Data
+ )
+{
+ if (Data->Menu)
+ {
+ PhDestroyEMenu(Data->Menu);
+ Data->Menu = NULL;
+ }
+}
+
+VOID PhInitializeTreeNewFilterSupport(
+ _Out_ PPH_TN_FILTER_SUPPORT Support,
+ _In_ HWND TreeNewHandle,
+ _In_ PPH_LIST NodeList
+ )
+{
+ Support->FilterList = NULL;
+ Support->TreeNewHandle = TreeNewHandle;
+ Support->NodeList = NodeList;
+}
+
+VOID PhDeleteTreeNewFilterSupport(
+ _In_ PPH_TN_FILTER_SUPPORT Support
+ )
+{
+ PhDereferenceObject(Support->FilterList);
+}
+
+PPH_TN_FILTER_ENTRY PhAddTreeNewFilter(
+ _In_ PPH_TN_FILTER_SUPPORT Support,
+ _In_ PPH_TN_FILTER_FUNCTION Filter,
+ _In_opt_ PVOID Context
+ )
+{
+ PPH_TN_FILTER_ENTRY entry;
+
+ entry = PhAllocate(sizeof(PH_TN_FILTER_ENTRY));
+ entry->Filter = Filter;
+ entry->Context = Context;
+
+ if (!Support->FilterList)
+ Support->FilterList = PhCreateList(2);
+
+ PhAddItemList(Support->FilterList, entry);
+
+ return entry;
+}
+
+VOID PhRemoveTreeNewFilter(
+ _In_ PPH_TN_FILTER_SUPPORT Support,
+ _In_ PPH_TN_FILTER_ENTRY Entry
+ )
+{
+ ULONG index;
+
+ if (!Support->FilterList)
+ return;
+
+ index = PhFindItemList(Support->FilterList, Entry);
+
+ if (index != ULONG_MAX)
+ {
+ PhRemoveItemList(Support->FilterList, index);
+ PhFree(Entry);
+ }
+}
+
+BOOLEAN PhApplyTreeNewFiltersToNode(
+ _In_ PPH_TN_FILTER_SUPPORT Support,
+ _In_ PPH_TREENEW_NODE Node
+ )
+{
+ BOOLEAN show;
+ ULONG i;
+
+ show = TRUE;
+
+ if (Support->FilterList)
+ {
+ for (i = 0; i < Support->FilterList->Count; i++)
+ {
+ PPH_TN_FILTER_ENTRY entry;
+
+ entry = Support->FilterList->Items[i];
+
+ if (!entry->Filter(Node, entry->Context))
+ {
+ show = FALSE;
+ break;
+ }
+ }
+ }
+
+ return show;
+}
+
+VOID PhApplyTreeNewFilters(
+ _In_ PPH_TN_FILTER_SUPPORT Support
+ )
+{
+ ULONG i;
+
+ for (i = 0; i < Support->NodeList->Count; i++)
+ {
+ PPH_TREENEW_NODE node;
+
+ node = Support->NodeList->Items[i];
+ node->Visible = PhApplyTreeNewFiltersToNode(Support, node);
+
+ if (!node->Visible && node->Selected)
+ {
+ node->Selected = FALSE;
+ }
+ }
+
+ TreeNew_NodesStructured(Support->TreeNewHandle);
+}
+
+VOID NTAPI PhpCopyCellEMenuItemDeleteFunction(
+ _In_ struct _PH_EMENU_ITEM *Item
+ )
+{
+ PPH_COPY_CELL_CONTEXT context;
+
+ context = Item->Context;
+ PhDereferenceObject(context->MenuItemText);
+ PhFree(context);
+}
+
+BOOLEAN PhInsertCopyCellEMenuItem(
+ _In_ struct _PH_EMENU_ITEM *Menu,
+ _In_ ULONG InsertAfterId,
+ _In_ HWND TreeNewHandle,
+ _In_ PPH_TREENEW_COLUMN Column
+ )
+{
+ PPH_EMENU_ITEM parentItem;
+ ULONG indexInParent;
+ PPH_COPY_CELL_CONTEXT context;
+ PH_STRINGREF columnText;
+ PPH_STRING escapedText;
+ PPH_STRING menuItemText;
+ PPH_EMENU_ITEM copyCellItem;
+
+ if (!Column)
+ return FALSE;
+
+ if (!PhFindEMenuItemEx(Menu, 0, NULL, InsertAfterId, &parentItem, &indexInParent))
+ return FALSE;
+
+ indexInParent++;
+
+ context = PhAllocate(sizeof(PH_COPY_CELL_CONTEXT));
+ context->TreeNewHandle = TreeNewHandle;
+ context->Id = Column->Id;
+
+ PhInitializeStringRef(&columnText, Column->Text);
+ escapedText = PhEscapeStringForMenuPrefix(&columnText);
+ menuItemText = PhFormatString(L"Copy \"%s\"", escapedText->Buffer);
+ PhDereferenceObject(escapedText);
+ copyCellItem = PhCreateEMenuItem(0, ID_COPY_CELL, menuItemText->Buffer, NULL, context);
+ copyCellItem->DeleteFunction = PhpCopyCellEMenuItemDeleteFunction;
+ context->MenuItemText = menuItemText;
+
+ if (Column->CustomDraw)
+ copyCellItem->Flags |= PH_EMENU_DISABLED;
+
+ PhInsertEMenuItem(parentItem, copyCellItem, indexInParent);
+
+ return TRUE;
+}
+
+BOOLEAN PhHandleCopyCellEMenuItem(
+ _In_ struct _PH_EMENU_ITEM *SelectedItem
+ )
+{
+ PPH_COPY_CELL_CONTEXT context;
+ PH_STRING_BUILDER stringBuilder;
+ ULONG count;
+ ULONG selectedCount;
+ ULONG i;
+ PPH_TREENEW_NODE node;
+ PH_TREENEW_GET_CELL_TEXT getCellText;
+
+ if (!SelectedItem)
+ return FALSE;
+ if (SelectedItem->Id != ID_COPY_CELL)
+ return FALSE;
+
+ context = SelectedItem->Context;
+
+ PhInitializeStringBuilder(&stringBuilder, 0x100);
+ count = TreeNew_GetFlatNodeCount(context->TreeNewHandle);
+ selectedCount = 0;
+
+ for (i = 0; i < count; i++)
+ {
+ node = TreeNew_GetFlatNode(context->TreeNewHandle, i);
+
+ if (node && node->Selected)
+ {
+ selectedCount++;
+
+ getCellText.Flags = 0;
+ getCellText.Node = node;
+ getCellText.Id = context->Id;
+ PhInitializeEmptyStringRef(&getCellText.Text);
+ TreeNew_GetCellText(context->TreeNewHandle, &getCellText);
+
+ PhAppendStringBuilder(&stringBuilder, &getCellText.Text);
+ PhAppendStringBuilder2(&stringBuilder, L"\r\n");
+ }
+ }
+
+ if (stringBuilder.String->Length != 0 && selectedCount == 1)
+ PhRemoveEndStringBuilder(&stringBuilder, 2);
+
+ PhSetClipboardString(context->TreeNewHandle, &stringBuilder.String->sr);
+ PhDeleteStringBuilder(&stringBuilder);
+
+ return TRUE;
+}
+
+VOID NTAPI PhpCopyListViewEMenuItemDeleteFunction(
+ _In_ struct _PH_EMENU_ITEM *Item
+ )
+{
+ PPH_COPY_ITEM_CONTEXT context;
+
+ context = Item->Context;
+ PhDereferenceObject(context->MenuItemText);
+ PhFree(context);
+}
+
+BOOLEAN PhInsertCopyListViewEMenuItem(
+ _In_ struct _PH_EMENU_ITEM *Menu,
+ _In_ ULONG InsertAfterId,
+ _In_ HWND ListViewHandle
+ )
+{
+ PPH_EMENU_ITEM parentItem;
+ ULONG indexInParent;
+ PPH_COPY_ITEM_CONTEXT context;
+ PPH_STRING columnText = NULL;
+ PPH_STRING escapedText;
+ PPH_STRING menuItemText;
+ PPH_EMENU_ITEM copyMenuItem;
+ POINT location;
+ LVHITTESTINFO lvHitInfo;
+ HDITEM headerItem;
+ WCHAR headerText[MAX_PATH];
+
+ if (!GetCursorPos(&location))
+ return FALSE;
+ if (!ScreenToClient(ListViewHandle, &location))
+ return FALSE;
+
+ memset(&lvHitInfo, 0, sizeof(LVHITTESTINFO));
+ lvHitInfo.pt = location;
+
+ if (ListView_SubItemHitTest(ListViewHandle, &lvHitInfo) == -1)
+ return FALSE;
+
+ memset(headerText, 0, sizeof(headerText));
+ memset(&headerItem, 0, sizeof(HDITEM));
+ headerItem.mask = HDI_TEXT;
+ headerItem.cchTextMax = RTL_NUMBER_OF(headerText);
+ headerItem.pszText = headerText;
+
+ if (!Header_GetItem(ListView_GetHeader(ListViewHandle), lvHitInfo.iSubItem, &headerItem))
+ return FALSE;
+
+ columnText = PhaCreateString(headerText);
+
+ if (PhIsNullOrEmptyString(columnText))
+ return FALSE;
+
+ if (!PhFindEMenuItemEx(Menu, 0, NULL, InsertAfterId, &parentItem, &indexInParent))
+ return FALSE;
+
+ indexInParent++;
+
+ context = PhAllocate(sizeof(PH_COPY_ITEM_CONTEXT));
+ context->ListViewHandle = ListViewHandle;
+ context->Id = lvHitInfo.iItem;
+ context->SubId = lvHitInfo.iSubItem;
+
+ escapedText = PhEscapeStringForMenuPrefix(&columnText->sr);
+ menuItemText = PhFormatString(L"Copy \"%s\"", escapedText->Buffer);
+ PhDereferenceObject(escapedText);
+
+ copyMenuItem = PhCreateEMenuItem(0, ID_COPY_CELL, menuItemText->Buffer, NULL, context);
+ copyMenuItem->DeleteFunction = PhpCopyListViewEMenuItemDeleteFunction;
+ context->MenuItemText = menuItemText;
+
+ PhInsertEMenuItem(parentItem, copyMenuItem, indexInParent);
+
+ return TRUE;
+}
+
+BOOLEAN PhHandleCopyListViewEMenuItem(
+ _In_ struct _PH_EMENU_ITEM *SelectedItem
+ )
+{
+ PPH_COPY_ITEM_CONTEXT context;
+ PH_STRING_BUILDER stringBuilder;
+ ULONG count;
+ ULONG selectedCount;
+ ULONG i;
+ PPH_STRING getItemText;
+
+ if (!SelectedItem)
+ return FALSE;
+ if (SelectedItem->Id != ID_COPY_CELL)
+ return FALSE;
+
+ context = SelectedItem->Context;
+
+ PhInitializeStringBuilder(&stringBuilder, 0x100);
+ count = ListView_GetItemCount(context->ListViewHandle);
+ selectedCount = 0;
+
+ for (i = 0; i < count; i++)
+ {
+ if (!(ListView_GetItemState(context->ListViewHandle, i, LVIS_SELECTED) & LVIS_SELECTED))
+ continue;
+
+ getItemText = PhaGetListViewItemText(context->ListViewHandle, i, context->SubId);
+
+ PhAppendStringBuilder(&stringBuilder, &getItemText->sr);
+ PhAppendStringBuilder2(&stringBuilder, L"\r\n");
+
+ selectedCount++;
+ }
+
+ if (stringBuilder.String->Length != 0 && selectedCount == 1)
+ PhRemoveEndStringBuilder(&stringBuilder, 2);
+
+ PhSetClipboardString(context->ListViewHandle, &stringBuilder.String->sr);
+ PhDeleteStringBuilder(&stringBuilder);
+
+ return TRUE;
+}
+
+BOOLEAN PhpSelectFavoriteInRegedit(
+ _In_ HWND RegeditWindow,
+ _In_ PPH_STRINGREF FavoriteName,
+ _In_ BOOLEAN UsePhSvc
+ )
+{
+ HMENU menu;
+ HMENU favoritesMenu;
+ ULONG count;
+ ULONG i;
+ ULONG id = ULONG_MAX;
+
+ if (!(menu = GetMenu(RegeditWindow)))
+ return FALSE;
+
+ // Cause the Registry Editor to refresh the Favorites menu.
+ if (UsePhSvc)
+ PhSvcCallSendMessage(RegeditWindow, WM_MENUSELECT, MAKEWPARAM(3, MF_POPUP), (LPARAM)menu);
+ else
+ SendMessage(RegeditWindow, WM_MENUSELECT, MAKEWPARAM(3, MF_POPUP), (LPARAM)menu);
+
+ if (!(favoritesMenu = GetSubMenu(menu, 3)))
+ return FALSE;
+
+ // Find our entry.
+
+ count = GetMenuItemCount(favoritesMenu);
+
+ if (count == -1)
+ return FALSE;
+ if (count > 1000)
+ count = 1000;
+
+ for (i = 3; i < count; i++)
+ {
+ MENUITEMINFO info = { sizeof(MENUITEMINFO) };
+ WCHAR buffer[MAX_PATH];
+
+ info.fMask = MIIM_ID | MIIM_STRING;
+ info.dwTypeData = buffer;
+ info.cch = RTL_NUMBER_OF(buffer);
+ GetMenuItemInfo(favoritesMenu, i, TRUE, &info);
+
+ if (info.cch == FavoriteName->Length / sizeof(WCHAR))
+ {
+ PH_STRINGREF text;
+
+ text.Buffer = buffer;
+ text.Length = info.cch * sizeof(WCHAR);
+
+ if (PhEqualStringRef(&text, FavoriteName, TRUE))
+ {
+ id = info.wID;
+ break;
+ }
+ }
+ }
+
+ if (id == ULONG_MAX)
+ return FALSE;
+
+ // Activate our entry.
+ if (UsePhSvc)
+ PhSvcCallSendMessage(RegeditWindow, WM_COMMAND, MAKEWPARAM(id, 0), 0);
+ else
+ SendMessage(RegeditWindow, WM_COMMAND, MAKEWPARAM(id, 0), 0);
+
+ // "Close" the Favorites menu and restore normal status bar text.
+ if (UsePhSvc)
+ PhSvcCallPostMessage(RegeditWindow, WM_MENUSELECT, MAKEWPARAM(0, 0xffff), 0);
+ else
+ PostMessage(RegeditWindow, WM_MENUSELECT, MAKEWPARAM(0, 0xffff), 0);
+
+ // Bring regedit to the top.
+ if (IsMinimized(RegeditWindow))
+ {
+ ShowWindow(RegeditWindow, SW_RESTORE);
+ SetForegroundWindow(RegeditWindow);
+ }
+ else
+ {
+ SetForegroundWindow(RegeditWindow);
+ }
+
+ return TRUE;
+}
+
+/**
+ * Opens a key in the Registry Editor. If the Registry Editor is already open,
+ * the specified key is selected in the Registry Editor.
+ *
+ * \param hWnd A handle to the parent window.
+ * \param KeyName The key name to open.
+ */
+BOOLEAN PhShellOpenKey2(
+ _In_ HWND hWnd,
+ _In_ PPH_STRING KeyName
+ )
+{
+ static PH_STRINGREF favoritesKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\Applets\\Regedit\\Favorites");
+
+ BOOLEAN result = FALSE;
+ HWND regeditWindow;
+ HANDLE favoritesKeyHandle;
+ WCHAR favoriteName[32];
+ UNICODE_STRING valueName;
+ PH_STRINGREF valueNameSr;
+ PPH_STRING expandedKeyName;
+
+ regeditWindow = FindWindow(L"RegEdit_RegEdit", NULL);
+
+ if (!regeditWindow)
+ {
+ PhShellOpenKey(hWnd, KeyName);
+ return TRUE;
+ }
+
+ if (!PhGetOwnTokenAttributes().Elevated)
+ {
+ if (!PhUiConnectToPhSvc(hWnd, FALSE))
+ return FALSE;
+ }
+
+ // Create our entry in Favorites.
+
+ if (!NT_SUCCESS(PhCreateKey(
+ &favoritesKeyHandle,
+ KEY_WRITE,
+ PH_KEY_CURRENT_USER,
+ &favoritesKeyName,
+ 0,
+ 0,
+ NULL
+ )))
+ goto CleanupExit;
+
+ memcpy(favoriteName, L"A_ProcessHacker", 15 * sizeof(WCHAR));
+ PhGenerateRandomAlphaString(&favoriteName[15], 16);
+ RtlInitUnicodeString(&valueName, favoriteName);
+ PhUnicodeStringToStringRef(&valueName, &valueNameSr);
+
+ expandedKeyName = PhExpandKeyName(KeyName, FALSE);
+ NtSetValueKey(favoritesKeyHandle, &valueName, 0, REG_SZ, expandedKeyName->Buffer, (ULONG)expandedKeyName->Length + sizeof(UNICODE_NULL));
+ PhDereferenceObject(expandedKeyName);
+
+ // Select our entry in regedit.
+ result = PhpSelectFavoriteInRegedit(regeditWindow, &valueNameSr, !PhGetOwnTokenAttributes().Elevated);
+
+ NtDeleteValueKey(favoritesKeyHandle, &valueName);
+ NtClose(favoritesKeyHandle);
+
+CleanupExit:
+ if (!PhGetOwnTokenAttributes().Elevated)
+ PhUiDisconnectFromPhSvc();
+
+ return result;
+}
+
+PPH_STRING PhPcre2GetErrorMessage(
+ _In_ INT ErrorCode
+ )
+{
+ PPH_STRING buffer;
+ SIZE_T bufferLength;
+ INT_PTR returnLength;
+
+ bufferLength = 128 * sizeof(WCHAR);
+ buffer = PhCreateStringEx(NULL, bufferLength);
+
+ while (TRUE)
+ {
+ if ((returnLength = pcre2_get_error_message(ErrorCode, buffer->Buffer, bufferLength / sizeof(WCHAR) + 1)) >= 0)
+ break;
+
+ PhDereferenceObject(buffer);
+ bufferLength *= 2;
+
+ if (bufferLength > 0x1000 * sizeof(WCHAR))
+ break;
+
+ buffer = PhCreateStringEx(NULL, bufferLength);
+ }
+
+ if (returnLength < 0)
+ return NULL;
+
+ buffer->Length = returnLength * sizeof(WCHAR);
+ return buffer;
+}
+
+HBITMAP PhGetShieldBitmap(
+ VOID
+ )
+{
+ static HBITMAP shieldBitmap = NULL;
+
+ if (!shieldBitmap)
+ {
+ HICON shieldIcon;
+
+ if (shieldIcon = PhLoadIcon(NULL, IDI_SHIELD, PH_LOAD_ICON_SHARED | PH_LOAD_ICON_SIZE_SMALL | PH_LOAD_ICON_STRICT, 0, 0))
+ {
+ shieldBitmap = PhIconToBitmap(shieldIcon, PhSmallIconSize.X, PhSmallIconSize.Y);
+ DestroyIcon(shieldIcon);
+ }
+ }
+
+ return shieldBitmap;
+}
+
diff --git a/ProcessHacker/chcol.c b/ProcessHacker/chcol.c
index 58f06e824743..515b8a66f7b0 100644
--- a/ProcessHacker/chcol.c
+++ b/ProcessHacker/chcol.c
@@ -1,425 +1,427 @@
-/*
- * Process Hacker -
- * column chooser
- *
- * 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 .
- */
-
-#include
-
-#include
-
-#include
-
-typedef struct _COLUMNS_DIALOG_CONTEXT
-{
- HWND ControlHandle;
- ULONG Type;
- PPH_LIST Columns;
-
- HWND InactiveList;
- HWND ActiveList;
-} COLUMNS_DIALOG_CONTEXT, *PCOLUMNS_DIALOG_CONTEXT;
-
-INT_PTR CALLBACK PhpColumnsDlgProc(
- _In_ HWND hwndDlg,
- _In_ UINT uMsg,
- _In_ WPARAM wParam,
- _In_ LPARAM lParam
- );
-
-VOID PhShowChooseColumnsDialog(
- _In_ HWND ParentWindowHandle,
- _In_ HWND ControlHandle,
- _In_ ULONG Type
- )
-{
- COLUMNS_DIALOG_CONTEXT context;
-
- context.ControlHandle = ControlHandle;
- context.Type = Type;
-
- if (Type == PH_CONTROL_TYPE_TREE_NEW)
- context.Columns = PhCreateList(TreeNew_GetColumnCount(ControlHandle));
- else
- return;
-
- DialogBoxParam(
- PhInstanceHandle,
- MAKEINTRESOURCE(IDD_CHOOSECOLUMNS),
- ParentWindowHandle,
- PhpColumnsDlgProc,
- (LPARAM)&context
- );
-
- PhDereferenceObject(context.Columns);
-}
-
-static int __cdecl PhpColumnsCompareDisplayIndexTn(
- _In_ const void *elem1,
- _In_ const void *elem2
- )
-{
- PPH_TREENEW_COLUMN column1 = *(PPH_TREENEW_COLUMN *)elem1;
- PPH_TREENEW_COLUMN column2 = *(PPH_TREENEW_COLUMN *)elem2;
-
- return uintcmp(column1->DisplayIndex, column2->DisplayIndex);
-}
-
-_Success_(return != -1)
-static ULONG IndexOfStringInList(
- _In_ PPH_LIST List,
- _In_ PWSTR String
- )
-{
- ULONG i;
-
- for (i = 0; i < List->Count; i++)
- {
- if (PhEqualString2(List->Items[i], String, FALSE))
- return i;
- }
-
- return -1;
-}
-
-INT_PTR CALLBACK PhpColumnsDlgProc(
- _In_ HWND hwndDlg,
- _In_ UINT uMsg,
- _In_ WPARAM wParam,
- _In_ LPARAM lParam
- )
-{
- PCOLUMNS_DIALOG_CONTEXT context = NULL;
-
- if (uMsg == WM_INITDIALOG)
- {
- context = (PCOLUMNS_DIALOG_CONTEXT)lParam;
- SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context);
- }
- else
- {
- context = (PCOLUMNS_DIALOG_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom());
- }
-
- if (!context)
- return FALSE;
-
- switch (uMsg)
- {
- case WM_INITDIALOG:
- {
- ULONG count;
- ULONG total;
- ULONG i;
- PPH_LIST displayOrderList = NULL;
-
- context->InactiveList = GetDlgItem(hwndDlg, IDC_INACTIVE);
- context->ActiveList = GetDlgItem(hwndDlg, IDC_ACTIVE);
- PhCenterWindow(hwndDlg, GetParent(hwndDlg));
-
- if (context->Type == PH_CONTROL_TYPE_TREE_NEW)
- {
- PH_TREENEW_COLUMN column;
-
- count = 0;
- total = TreeNew_GetColumnCount(context->ControlHandle);
- i = 0;
-
- displayOrderList = PhCreateList(total);
-
- while (count < total)
- {
- if (TreeNew_GetColumn(context->ControlHandle, i, &column))
- {
- PPH_TREENEW_COLUMN copy;
-
- if (column.Fixed)
- {
- i++;
- total--;
- continue;
- }
-
- copy = PhAllocateCopy(&column, sizeof(PH_TREENEW_COLUMN));
- PhAddItemList(context->Columns, copy);
- count++;
-
- if (column.Visible)
- {
- PhAddItemList(displayOrderList, copy);
- }
- else
- {
- ListBox_AddString(context->InactiveList, column.Text);
- }
- }
-
- i++;
- }
-
- qsort(displayOrderList->Items, displayOrderList->Count, sizeof(PVOID), PhpColumnsCompareDisplayIndexTn);
- }
-
- if (displayOrderList)
- {
- for (i = 0; i < displayOrderList->Count; i++)
- {
- if (context->Type == PH_CONTROL_TYPE_TREE_NEW)
- {
- PPH_TREENEW_COLUMN copy = displayOrderList->Items[i];
-
- ListBox_AddString(context->ActiveList, copy->Text);
- }
- }
-
- PhDereferenceObject(displayOrderList);
- }
-
- SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_INACTIVE, LBN_SELCHANGE), (LPARAM)context->InactiveList);
- SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_ACTIVE, LBN_SELCHANGE), (LPARAM)context->ActiveList);
- }
- break;
- case WM_DESTROY:
- {
- ULONG i;
-
- for (i = 0; i < context->Columns->Count; i++)
- PhFree(context->Columns->Items[i]);
-
- RemoveProp(hwndDlg, PhMakeContextAtom());
- }
- break;
- case WM_COMMAND:
- {
- switch (LOWORD(wParam))
- {
- case IDCANCEL:
- EndDialog(hwndDlg, IDCANCEL);
- break;
- case IDOK:
- {
-#define ORDER_LIMIT 100
- PPH_LIST activeList;
- ULONG activeCount;
- ULONG i;
- INT orderArray[ORDER_LIMIT];
- INT maxOrder;
-
- memset(orderArray, 0, sizeof(orderArray));
- maxOrder = 0;
-
- activeCount = ListBox_GetCount(context->ActiveList);
- activeList = PhCreateList(activeCount);
-
- for (i = 0; i < activeCount; i++)
- PhAddItemList(activeList, PhGetListBoxString(context->ActiveList, i));
-
- if (context->Type == PH_CONTROL_TYPE_TREE_NEW)
- {
- // Apply visiblity settings and build the order array.
-
- TreeNew_SetRedraw(context->ControlHandle, FALSE);
-
- for (i = 0; i < context->Columns->Count; i++)
- {
- PPH_TREENEW_COLUMN column = context->Columns->Items[i];
- ULONG index;
-
- index = IndexOfStringInList(activeList, column->Text);
- column->Visible = index != -1;
-
- TreeNew_SetColumn(context->ControlHandle, TN_COLUMN_FLAG_VISIBLE, column);
-
- if (column->Visible && index < ORDER_LIMIT)
- {
- orderArray[index] = column->Id;
-
- if ((ULONG)maxOrder < index + 1)
- maxOrder = index + 1;
- }
- }
-
- // Apply display order.
- TreeNew_SetColumnOrderArray(context->ControlHandle, maxOrder, orderArray);
-
- TreeNew_SetRedraw(context->ControlHandle, TRUE);
-
- PhDereferenceObject(activeList);
-
- InvalidateRect(context->ControlHandle, NULL, FALSE);
- }
-
- EndDialog(hwndDlg, IDOK);
- }
- break;
- case IDC_INACTIVE:
- {
- switch (HIWORD(wParam))
- {
- case LBN_DBLCLK:
- {
- SendMessage(hwndDlg, WM_COMMAND, IDC_SHOW, 0);
- }
- break;
- case LBN_SELCHANGE:
- {
- INT sel = ListBox_GetCurSel(context->InactiveList);
-
- EnableWindow(GetDlgItem(hwndDlg, IDC_SHOW), sel != -1);
- }
- break;
- }
- }
- break;
- case IDC_ACTIVE:
- {
- switch (HIWORD(wParam))
- {
- case LBN_DBLCLK:
- {
- SendMessage(hwndDlg, WM_COMMAND, IDC_HIDE, 0);
- }
- break;
- case LBN_SELCHANGE:
- {
- INT sel = ListBox_GetCurSel(context->ActiveList);
- INT count = ListBox_GetCount(context->ActiveList);
-
- EnableWindow(GetDlgItem(hwndDlg, IDC_HIDE), sel != -1 && count != 1);
- EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEUP), sel != 0 && sel != -1);
- EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEDOWN), sel != count - 1 && sel != -1);
- }
- break;
- }
- }
- break;
- case IDC_SHOW:
- {
- INT sel;
- INT count;
- PPH_STRING string;
-
- sel = ListBox_GetCurSel(context->InactiveList);
- count = ListBox_GetCount(context->InactiveList);
-
- if (string = PhGetListBoxString(context->InactiveList, sel))
- {
- ListBox_DeleteString(context->InactiveList, sel);
- ListBox_AddString(context->ActiveList, string->Buffer);
- PhDereferenceObject(string);
-
- count--;
-
- if (sel >= count - 1)
- sel = count - 1;
-
- ListBox_SetCurSel(context->InactiveList, sel);
-
- SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_INACTIVE, LBN_SELCHANGE), (LPARAM)context->InactiveList);
- SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_ACTIVE, LBN_SELCHANGE), (LPARAM)context->ActiveList);
- }
- }
- break;
- case IDC_HIDE:
- {
- INT sel;
- INT count;
- PPH_STRING string;
-
- sel = ListBox_GetCurSel(context->ActiveList);
- count = ListBox_GetCount(context->ActiveList);
-
- if (count != 1)
- {
- if (string = PhGetListBoxString(context->ActiveList, sel))
- {
- ListBox_DeleteString(context->ActiveList, sel);
- ListBox_AddString(context->InactiveList, string->Buffer);
- PhDereferenceObject(string);
-
- count--;
-
- if (sel >= count - 1)
- sel = count - 1;
-
- ListBox_SetCurSel(context->ActiveList, sel);
-
- SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_INACTIVE, LBN_SELCHANGE), (LPARAM)context->InactiveList);
- SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_ACTIVE, LBN_SELCHANGE), (LPARAM)context->ActiveList);
- }
- }
- }
- break;
- case IDC_MOVEUP:
- {
- INT sel;
- INT count;
- PPH_STRING string;
-
- sel = ListBox_GetCurSel(context->ActiveList);
- count = ListBox_GetCount(context->ActiveList);
-
- if (sel != 0)
- {
- if (string = PhGetListBoxString(context->ActiveList, sel))
- {
- ListBox_DeleteString(context->ActiveList, sel);
- ListBox_InsertString(context->ActiveList, sel - 1, string->Buffer);
- PhDereferenceObject(string);
-
- sel -= 1;
- ListBox_SetCurSel(context->ActiveList, sel);
- EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEUP), sel != 0);
- EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEDOWN), sel != count - 1);
- }
- }
- }
- break;
- case IDC_MOVEDOWN:
- {
- INT sel;
- INT count;
- PPH_STRING string;
-
- sel = ListBox_GetCurSel(context->ActiveList);
- count = ListBox_GetCount(context->ActiveList);
-
- if (sel != count - 1)
- {
- if (string = PhGetListBoxString(context->ActiveList, sel))
- {
- ListBox_DeleteString(context->ActiveList, sel);
- ListBox_InsertString(context->ActiveList, sel + 1, string->Buffer);
- PhDereferenceObject(string);
-
- sel += 1;
- ListBox_SetCurSel(context->ActiveList, sel);
- EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEUP), sel != 0);
- EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEDOWN), sel != count - 1);
- }
- }
- }
- break;
- }
- }
- break;
- }
-
- return FALSE;
-}
+/*
+ * Process Hacker -
+ * column chooser
+ *
+ * Copyright (C) 2010 wj32
+ * Copyright (C) 2017-2018 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 .
+ */
+
+#include
+#include
+
+#include
+
+typedef struct _COLUMNS_DIALOG_CONTEXT
+{
+ HWND ControlHandle;
+ ULONG Type;
+ PPH_LIST Columns;
+
+ HWND InactiveList;
+ HWND ActiveList;
+} COLUMNS_DIALOG_CONTEXT, *PCOLUMNS_DIALOG_CONTEXT;
+
+INT_PTR CALLBACK PhpColumnsDlgProc(
+ _In_ HWND hwndDlg,
+ _In_ UINT uMsg,
+ _In_ WPARAM wParam,
+ _In_ LPARAM lParam
+ );
+
+VOID PhShowChooseColumnsDialog(
+ _In_ HWND ParentWindowHandle,
+ _In_ HWND ControlHandle,
+ _In_ ULONG Type
+ )
+{
+ COLUMNS_DIALOG_CONTEXT context;
+
+ context.ControlHandle = ControlHandle;
+ context.Type = Type;
+
+ if (Type == PH_CONTROL_TYPE_TREE_NEW)
+ context.Columns = PhCreateList(TreeNew_GetColumnCount(ControlHandle));
+ else
+ return;
+
+ DialogBoxParam(
+ PhInstanceHandle,
+ MAKEINTRESOURCE(IDD_CHOOSECOLUMNS),
+ ParentWindowHandle,
+ PhpColumnsDlgProc,
+ (LPARAM)&context
+ );
+
+ PhDereferenceObject(context.Columns);
+}
+
+static int __cdecl PhpColumnsCompareDisplayIndexTn(
+ _In_ const void *elem1,
+ _In_ const void *elem2
+ )
+{
+ PPH_TREENEW_COLUMN column1 = *(PPH_TREENEW_COLUMN *)elem1;
+ PPH_TREENEW_COLUMN column2 = *(PPH_TREENEW_COLUMN *)elem2;
+
+ return uintcmp(column1->DisplayIndex, column2->DisplayIndex);
+}
+
+_Success_(return != -1)
+static ULONG IndexOfStringInList(
+ _In_ PPH_LIST List,
+ _In_ PWSTR String
+ )
+{
+ ULONG i;
+
+ for (i = 0; i < List->Count; i++)
+ {
+ if (PhEqualString2(List->Items[i], String, FALSE))
+ return i;
+ }
+
+ return -1;
+}
+
+INT_PTR CALLBACK PhpColumnsDlgProc(
+ _In_ HWND hwndDlg,
+ _In_ UINT uMsg,
+ _In_ WPARAM wParam,
+ _In_ LPARAM lParam
+ )
+{
+ PCOLUMNS_DIALOG_CONTEXT context = NULL;
+
+ if (uMsg == WM_INITDIALOG)
+ {
+ context = (PCOLUMNS_DIALOG_CONTEXT)lParam;
+ PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);
+ }
+ else
+ {
+ context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);
+ }
+
+ if (!context)
+ return FALSE;
+
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ ULONG count;
+ ULONG total;
+ ULONG i;
+ PPH_LIST displayOrderList = NULL;
+
+ context->InactiveList = GetDlgItem(hwndDlg, IDC_INACTIVE);
+ context->ActiveList = GetDlgItem(hwndDlg, IDC_ACTIVE);
+ PhCenterWindow(hwndDlg, GetParent(hwndDlg));
+
+ if (context->Type == PH_CONTROL_TYPE_TREE_NEW)
+ {
+ PH_TREENEW_COLUMN column;
+
+ count = 0;
+ total = TreeNew_GetColumnCount(context->ControlHandle);
+ i = 0;
+
+ displayOrderList = PhCreateList(total);
+
+ while (count < total)
+ {
+ if (TreeNew_GetColumn(context->ControlHandle, i, &column))
+ {
+ PPH_TREENEW_COLUMN copy;
+
+ if (column.Fixed)
+ {
+ i++;
+ total--;
+ continue;
+ }
+
+ copy = PhAllocateCopy(&column, sizeof(PH_TREENEW_COLUMN));
+ PhAddItemList(context->Columns, copy);
+ count++;
+
+ if (column.Visible)
+ {
+ PhAddItemList(displayOrderList, copy);
+ }
+ else
+ {
+ ListBox_AddString(context->InactiveList, column.Text);
+ }
+ }
+
+ i++;
+ }
+
+ qsort(displayOrderList->Items, displayOrderList->Count, sizeof(PVOID), PhpColumnsCompareDisplayIndexTn);
+ }
+
+ if (displayOrderList)
+ {
+ for (i = 0; i < displayOrderList->Count; i++)
+ {
+ if (context->Type == PH_CONTROL_TYPE_TREE_NEW)
+ {
+ PPH_TREENEW_COLUMN copy = displayOrderList->Items[i];
+
+ ListBox_AddString(context->ActiveList, copy->Text);
+ }
+ }
+
+ PhDereferenceObject(displayOrderList);
+ }
+
+ SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_INACTIVE, LBN_SELCHANGE), (LPARAM)context->InactiveList);
+ SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_ACTIVE, LBN_SELCHANGE), (LPARAM)context->ActiveList);
+
+ PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);
+ }
+ break;
+ case WM_DESTROY:
+ {
+ ULONG i;
+
+ for (i = 0; i < context->Columns->Count; i++)
+ PhFree(context->Columns->Items[i]);
+
+ PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);
+ }
+ break;
+ case WM_COMMAND:
+ {
+ switch (GET_WM_COMMAND_ID(wParam, lParam))
+ {
+ case IDCANCEL:
+ EndDialog(hwndDlg, IDCANCEL);
+ break;
+ case IDOK:
+ {
+#define ORDER_LIMIT 200
+ PPH_LIST activeList;
+ ULONG activeCount;
+ ULONG i;
+ INT orderArray[ORDER_LIMIT];
+ INT maxOrder;
+
+ memset(orderArray, 0, sizeof(orderArray));
+ maxOrder = 0;
+
+ activeCount = ListBox_GetCount(context->ActiveList);
+ activeList = PhCreateList(activeCount);
+
+ for (i = 0; i < activeCount; i++)
+ PhAddItemList(activeList, PhGetListBoxString(context->ActiveList, i));
+
+ if (context->Type == PH_CONTROL_TYPE_TREE_NEW)
+ {
+ // Apply visiblity settings and build the order array.
+
+ TreeNew_SetRedraw(context->ControlHandle, FALSE);
+
+ for (i = 0; i < context->Columns->Count; i++)
+ {
+ PPH_TREENEW_COLUMN column = context->Columns->Items[i];
+ ULONG index;
+
+ index = IndexOfStringInList(activeList, column->Text);
+ column->Visible = index != -1;
+
+ TreeNew_SetColumn(context->ControlHandle, TN_COLUMN_FLAG_VISIBLE, column);
+
+ if (column->Visible && index < ORDER_LIMIT)
+ {
+ orderArray[index] = column->Id;
+
+ if ((ULONG)maxOrder < index + 1)
+ maxOrder = index + 1;
+ }
+ }
+
+ // Apply display order.
+ TreeNew_SetColumnOrderArray(context->ControlHandle, maxOrder, orderArray);
+
+ TreeNew_SetRedraw(context->ControlHandle, TRUE);
+
+ PhDereferenceObject(activeList);
+
+ InvalidateRect(context->ControlHandle, NULL, FALSE);
+ }
+
+ EndDialog(hwndDlg, IDOK);
+ }
+ break;
+ case IDC_INACTIVE:
+ {
+ switch (HIWORD(wParam))
+ {
+ case LBN_DBLCLK:
+ {
+ SendMessage(hwndDlg, WM_COMMAND, IDC_SHOW, 0);
+ }
+ break;
+ case LBN_SELCHANGE:
+ {
+ INT sel = ListBox_GetCurSel(context->InactiveList);
+
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SHOW), sel != -1);
+ }
+ break;
+ }
+ }
+ break;
+ case IDC_ACTIVE:
+ {
+ switch (HIWORD(wParam))
+ {
+ case LBN_DBLCLK:
+ {
+ SendMessage(hwndDlg, WM_COMMAND, IDC_HIDE, 0);
+ }
+ break;
+ case LBN_SELCHANGE:
+ {
+ INT sel = ListBox_GetCurSel(context->ActiveList);
+ INT count = ListBox_GetCount(context->ActiveList);
+
+ EnableWindow(GetDlgItem(hwndDlg, IDC_HIDE), sel != -1 && count != 1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEUP), sel != 0 && sel != -1);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEDOWN), sel != count - 1 && sel != -1);
+ }
+ break;
+ }
+ }
+ break;
+ case IDC_SHOW:
+ {
+ INT sel;
+ INT count;
+ PPH_STRING string;
+
+ sel = ListBox_GetCurSel(context->InactiveList);
+ count = ListBox_GetCount(context->InactiveList);
+
+ if (string = PhGetListBoxString(context->InactiveList, sel))
+ {
+ ListBox_DeleteString(context->InactiveList, sel);
+ ListBox_AddString(context->ActiveList, string->Buffer);
+ PhDereferenceObject(string);
+
+ count--;
+
+ if (sel >= count - 1)
+ sel = count - 1;
+
+ ListBox_SetCurSel(context->InactiveList, sel);
+
+ SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_INACTIVE, LBN_SELCHANGE), (LPARAM)context->InactiveList);
+ SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_ACTIVE, LBN_SELCHANGE), (LPARAM)context->ActiveList);
+ }
+ }
+ break;
+ case IDC_HIDE:
+ {
+ INT sel;
+ INT count;
+ PPH_STRING string;
+
+ sel = ListBox_GetCurSel(context->ActiveList);
+ count = ListBox_GetCount(context->ActiveList);
+
+ if (count != 1)
+ {
+ if (string = PhGetListBoxString(context->ActiveList, sel))
+ {
+ ListBox_DeleteString(context->ActiveList, sel);
+ ListBox_AddString(context->InactiveList, string->Buffer);
+ PhDereferenceObject(string);
+
+ count--;
+
+ if (sel >= count - 1)
+ sel = count - 1;
+
+ ListBox_SetCurSel(context->ActiveList, sel);
+
+ SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_INACTIVE, LBN_SELCHANGE), (LPARAM)context->InactiveList);
+ SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_ACTIVE, LBN_SELCHANGE), (LPARAM)context->ActiveList);
+ }
+ }
+ }
+ break;
+ case IDC_MOVEUP:
+ {
+ INT sel;
+ INT count;
+ PPH_STRING string;
+
+ sel = ListBox_GetCurSel(context->ActiveList);
+ count = ListBox_GetCount(context->ActiveList);
+
+ if (sel != 0)
+ {
+ if (string = PhGetListBoxString(context->ActiveList, sel))
+ {
+ ListBox_DeleteString(context->ActiveList, sel);
+ ListBox_InsertString(context->ActiveList, sel - 1, string->Buffer);
+ PhDereferenceObject(string);
+
+ sel -= 1;
+ ListBox_SetCurSel(context->ActiveList, sel);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEUP), sel != 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEDOWN), sel != count - 1);
+ }
+ }
+ }
+ break;
+ case IDC_MOVEDOWN:
+ {
+ INT sel;
+ INT count;
+ PPH_STRING string;
+
+ sel = ListBox_GetCurSel(context->ActiveList);
+ count = ListBox_GetCount(context->ActiveList);
+
+ if (sel != count - 1)
+ {
+ if (string = PhGetListBoxString(context->ActiveList, sel))
+ {
+ ListBox_DeleteString(context->ActiveList, sel);
+ ListBox_InsertString(context->ActiveList, sel + 1, string->Buffer);
+ PhDereferenceObject(string);
+
+ sel += 1;
+ ListBox_SetCurSel(context->ActiveList, sel);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEUP), sel != 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MOVEDOWN), sel != count - 1);
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+
+ return FALSE;
+}
diff --git a/ProcessHacker/chdlg.c b/ProcessHacker/chdlg.c
index 97c4bdac6eee..995946356e62 100644
--- a/ProcessHacker/chdlg.c
+++ b/ProcessHacker/chdlg.c
@@ -1,360 +1,360 @@
-/*
- * Process Hacker -
- * choice dialog
- *
- * Copyright (C) 2010-2013 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 .
- */
-
-#include
-
-#include
-
-#include
-
-typedef struct _CHOICE_DIALOG_CONTEXT
-{
- PWSTR Title;
- PWSTR Message;
- PWSTR *Choices;
- ULONG NumberOfChoices;
- PWSTR Option;
- ULONG Flags;
- PPH_STRING *SelectedChoice;
- PBOOLEAN SelectedOption;
- PWSTR SavedChoicesSettingName;
-
- HWND ComboBoxHandle;
-} CHOICE_DIALOG_CONTEXT, *PCHOICE_DIALOG_CONTEXT;
-
-INT_PTR CALLBACK PhpChoiceDlgProc(
- _In_ HWND hwndDlg,
- _In_ UINT uMsg,
- _In_ WPARAM wParam,
- _In_ LPARAM lParam
- );
-
-/**
- * Prompts the user for input.
- *
- * \remarks If \c PH_CHOICE_DIALOG_PASSWORD is specified, the string
- * returned in \a SelectedChoice is NOT auto-dereferenced.
- */
-BOOLEAN PhaChoiceDialog(
- _In_ HWND ParentWindowHandle,
- _In_ PWSTR Title,
- _In_ PWSTR Message,
- _In_opt_ PWSTR *Choices,
- _In_opt_ ULONG NumberOfChoices,
- _In_opt_ PWSTR Option,
- _In_ ULONG Flags,
- _Inout_ PPH_STRING *SelectedChoice,
- _Inout_opt_ PBOOLEAN SelectedOption,
- _In_opt_ PWSTR SavedChoicesSettingName
- )
-{
- CHOICE_DIALOG_CONTEXT context;
-
- context.Title = Title;
- context.Message = Message;
- context.Choices = Choices;
- context.NumberOfChoices = NumberOfChoices;
- context.Option = Option;
- context.Flags = Flags;
- context.SelectedChoice = SelectedChoice;
- context.SelectedOption = SelectedOption;
- context.SavedChoicesSettingName = SavedChoicesSettingName;
-
- return DialogBoxParam(
- PhInstanceHandle,
- MAKEINTRESOURCE(IDD_CHOOSE),
- ParentWindowHandle,
- PhpChoiceDlgProc,
- (LPARAM)&context
- ) == IDOK;
-}
-
-INT_PTR CALLBACK PhpChoiceDlgProc(
- _In_ HWND hwndDlg,
- _In_ UINT uMsg,
- _In_ WPARAM wParam,
- _In_ LPARAM lParam
- )
-{
- switch (uMsg)
- {
- case WM_INITDIALOG:
- {
- PCHOICE_DIALOG_CONTEXT context = (PCHOICE_DIALOG_CONTEXT)lParam;
- ULONG type;
- SIZE_T i;
- HWND comboBoxHandle;
- HWND checkBoxHandle;
- RECT checkBoxRect;
- RECT rect;
- ULONG diff;
-
- SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context);
- PhCenterWindow(hwndDlg, GetParent(hwndDlg));
-
- SetWindowText(hwndDlg, context->Title);
- SetWindowText(GetDlgItem(hwndDlg, IDC_MESSAGE), context->Message);
-
- type = context->Flags & PH_CHOICE_DIALOG_TYPE_MASK;
-
- // Select the control to show, depending on the type. This is
- // because it is impossible to change the style of the combo box
- // after it is created.
- switch (type)
- {
- case PH_CHOICE_DIALOG_USER_CHOICE:
- comboBoxHandle = GetDlgItem(hwndDlg, IDC_CHOICEUSER);
- ShowWindow(GetDlgItem(hwndDlg, IDC_CHOICEUSER), SW_SHOW);
- break;
- case PH_CHOICE_DIALOG_PASSWORD:
- comboBoxHandle = GetDlgItem(hwndDlg, IDC_CHOICESIMPLE);
- ShowWindow(GetDlgItem(hwndDlg, IDC_CHOICESIMPLE), SW_SHOW);
-
- // Disable combo box features since it isn't a combo box.
- context->SavedChoicesSettingName = NULL;
- break;
- case PH_CHOICE_DIALOG_CHOICE:
- default:
- comboBoxHandle = GetDlgItem(hwndDlg, IDC_CHOICE);
- ShowWindow(GetDlgItem(hwndDlg, IDC_CHOICE), SW_SHOW);
- break;
- }
-
- context->ComboBoxHandle = comboBoxHandle;
-
- checkBoxHandle = GetDlgItem(hwndDlg, IDC_OPTION);
-
- if (type == PH_CHOICE_DIALOG_PASSWORD)
- {
- // Nothing
- }
- else if (type == PH_CHOICE_DIALOG_USER_CHOICE && context->SavedChoicesSettingName)
- {
- PPH_STRING savedChoices = PhGetStringSetting(context->SavedChoicesSettingName);
- ULONG_PTR indexOfDelim;
- PPH_STRING savedChoice;
-
- i = 0;
-
- // Split the saved choices using the delimiter.
- while (i < savedChoices->Length / 2)
- {
- // BUG BUG BUG - what if the user saves "\s"?
- indexOfDelim = PhFindStringInString(savedChoices, i, L"\\s");
-
- if (indexOfDelim == -1)
- indexOfDelim = savedChoices->Length / 2;
-
- savedChoice = PhSubstring(savedChoices, i, indexOfDelim - i);
-
- if (savedChoice->Length != 0)
- {
- PPH_STRING unescaped;
-
- unescaped = PhUnescapeStringForDelimiter(savedChoice, '\\');
- ComboBox_InsertString(comboBoxHandle, -1, unescaped->Buffer);
- PhDereferenceObject(unescaped);
- }
-
- PhDereferenceObject(savedChoice);
-
- i = indexOfDelim + 2;
- }
-
- PhDereferenceObject(savedChoices);
- }
- else
- {
- for (i = 0; i < context->NumberOfChoices; i++)
- {
- ComboBox_AddString(comboBoxHandle, context->Choices[i]);
- }
-
- context->SavedChoicesSettingName = NULL; // make sure we don't try to save the choices
- }
-
- if (type == PH_CHOICE_DIALOG_PASSWORD)
- {
- if (*context->SelectedChoice)
- SetWindowText(comboBoxHandle, (*context->SelectedChoice)->Buffer);
-
- Edit_SetSel(comboBoxHandle, 0, -1);
- }
- else if (type == PH_CHOICE_DIALOG_USER_CHOICE || type == PH_CHOICE_DIALOG_CHOICE)
- {
- // If we failed to choose a default choice based on what was specified,
- // select the first one if possible, or set the text directly.
- if (!(*context->SelectedChoice) || PhSelectComboBoxString(
- comboBoxHandle, (*context->SelectedChoice)->Buffer, FALSE) == CB_ERR)
- {
- if (type == PH_CHOICE_DIALOG_USER_CHOICE && *context->SelectedChoice)
- {
- SetWindowText(comboBoxHandle, (*context->SelectedChoice)->Buffer);
- }
- else if (type == PH_CHOICE_DIALOG_CHOICE && context->NumberOfChoices != 0)
- {
- ComboBox_SetCurSel(comboBoxHandle, 0);
- }
- }
-
- if (type == PH_CHOICE_DIALOG_USER_CHOICE)
- ComboBox_SetEditSel(comboBoxHandle, 0, -1);
- }
-
- if (context->Option)
- {
- SetWindowText(checkBoxHandle, context->Option);
-
- if (context->SelectedOption)
- Button_SetCheck(checkBoxHandle, *context->SelectedOption ? BST_CHECKED : BST_UNCHECKED);
- }
- else
- {
- // Hide the check box and move the buttons up.
-
- ShowWindow(checkBoxHandle, SW_HIDE);
- GetWindowRect(checkBoxHandle, &checkBoxRect);
- MapWindowPoints(NULL, hwndDlg, (POINT *)&checkBoxRect, 2);
- GetWindowRect(GetDlgItem(hwndDlg, IDOK), &rect);
- MapWindowPoints(NULL, hwndDlg, (POINT *)&rect, 2);
- diff = rect.top - checkBoxRect.top;
-
- // OK
- rect.top -= diff;
- rect.bottom -= diff;
- SetWindowPos(GetDlgItem(hwndDlg, IDOK), NULL, rect.left, rect.top,
- rect.right - rect.left, rect.bottom - rect.top,
- SWP_NOACTIVATE | SWP_NOZORDER);
-
- // Cancel
- GetWindowRect(GetDlgItem(hwndDlg, IDCANCEL), &rect);
- MapWindowPoints(NULL, hwndDlg, (POINT *)&rect, 2);
- rect.top -= diff;
- rect.bottom -= diff;
- SetWindowPos(GetDlgItem(hwndDlg, IDCANCEL), NULL, rect.left, rect.top,
- rect.right - rect.left, rect.bottom - rect.top,
- SWP_NOACTIVATE | SWP_NOZORDER);
-
- // Window
- GetWindowRect(hwndDlg, &rect);
- rect.bottom -= diff;
- SetWindowPos(hwndDlg, NULL, rect.left, rect.top,
- rect.right - rect.left, rect.bottom - rect.top,
- SWP_NOACTIVATE | SWP_NOZORDER);
- }
-
- SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)comboBoxHandle, TRUE);
- }
- break;
- case WM_DESTROY:
- {
- RemoveProp(hwndDlg, PhMakeContextAtom());
- }
- break;
- case WM_COMMAND:
- {
- switch (LOWORD(wParam))
- {
- case IDCANCEL:
- EndDialog(hwndDlg, IDCANCEL);
- break;
- case IDOK:
- {
- PCHOICE_DIALOG_CONTEXT context = (PCHOICE_DIALOG_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom());
- PPH_STRING selectedChoice;
-
- if ((context->Flags & PH_CHOICE_DIALOG_TYPE_MASK) != PH_CHOICE_DIALOG_PASSWORD)
- {
- selectedChoice = PH_AUTO(PhGetWindowText(context->ComboBoxHandle));
- *context->SelectedChoice = selectedChoice;
- }
- else
- {
- // Password values are never auto-dereferenced.
- selectedChoice = PhGetWindowText(context->ComboBoxHandle);
- *context->SelectedChoice = selectedChoice;
- }
-
- if (context->Option && context->SelectedOption)
- *context->SelectedOption = Button_GetCheck(GetDlgItem(hwndDlg, IDC_OPTION)) == BST_CHECKED;
-
- if (context->SavedChoicesSettingName)
- {
- PH_STRING_BUILDER savedChoices;
- ULONG i;
- ULONG choicesToSave = PH_CHOICE_DIALOG_SAVED_CHOICES;
- PPH_STRING choice;
- PPH_STRING escaped;
-
- PhInitializeStringBuilder(&savedChoices, 100);
-
- // Push the selected choice to the top, then save the others.
-
- if (selectedChoice->Length != 0)
- {
- escaped = PhEscapeStringForDelimiter(selectedChoice, '\\');
- PhAppendStringBuilder(&savedChoices, &escaped->sr);
- PhDereferenceObject(escaped);
- PhAppendStringBuilder2(&savedChoices, L"\\s");
- }
-
- for (i = 1; i < choicesToSave; i++)
- {
- choice = PhGetComboBoxString(context->ComboBoxHandle, i - 1);
-
- if (!choice)
- break;
-
- // Don't save the choice if it's the same as the one
- // entered by the user (since we already saved it above).
- if (PhEqualString(choice, selectedChoice, FALSE))
- {
- PhDereferenceObject(choice);
- choicesToSave++; // useless for now, but may be needed in the future
- continue;
- }
-
- escaped = PhEscapeStringForDelimiter(choice, '\\');
- PhAppendStringBuilder(&savedChoices, &escaped->sr);
- PhDereferenceObject(escaped);
- PhDereferenceObject(choice);
-
- PhAppendStringBuilder2(&savedChoices, L"\\s");
- }
-
- if (PhEndsWithString2(savedChoices.String, L"\\s", FALSE))
- PhRemoveEndStringBuilder(&savedChoices, 2);
-
- PhSetStringSetting2(context->SavedChoicesSettingName, &savedChoices.String->sr);
- PhDeleteStringBuilder(&savedChoices);
- }
-
- EndDialog(hwndDlg, IDOK);
- }
- break;
- }
- }
- break;
- }
-
- return FALSE;
-}
+/*
+ * Process Hacker -
+ * choice dialog
+ *
+ * Copyright (C) 2010-2013 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 .
+ */
+
+#include
+#include
+#include
+
+typedef struct _CHOICE_DIALOG_CONTEXT
+{
+ PWSTR Title;
+ PWSTR Message;
+ PWSTR *Choices;
+ ULONG NumberOfChoices;
+ PWSTR Option;
+ ULONG Flags;
+ PPH_STRING *SelectedChoice;
+ PBOOLEAN SelectedOption;
+ PWSTR SavedChoicesSettingName;
+
+ HWND ComboBoxHandle;
+} CHOICE_DIALOG_CONTEXT, *PCHOICE_DIALOG_CONTEXT;
+
+INT_PTR CALLBACK PhpChoiceDlgProc(
+ _In_ HWND hwndDlg,
+ _In_ UINT uMsg,
+ _In_ WPARAM wParam,
+ _In_ LPARAM lParam
+ );
+
+/**
+ * Prompts the user for input.
+ *
+ * \remarks If \c PH_CHOICE_DIALOG_PASSWORD is specified, the string
+ * returned in \a SelectedChoice is NOT auto-dereferenced.
+ */
+BOOLEAN PhaChoiceDialog(
+ _In_ HWND ParentWindowHandle,
+ _In_ PWSTR Title,
+ _In_ PWSTR Message,
+ _In_opt_ PWSTR *Choices,
+ _In_opt_ ULONG NumberOfChoices,
+ _In_opt_ PWSTR Option,
+ _In_ ULONG Flags,
+ _Inout_ PPH_STRING *SelectedChoice,
+ _Inout_opt_ PBOOLEAN SelectedOption,
+ _In_opt_ PWSTR SavedChoicesSettingName
+ )
+{
+ CHOICE_DIALOG_CONTEXT context;
+
+ context.Title = Title;
+ context.Message = Message;
+ context.Choices = Choices;
+ context.NumberOfChoices = NumberOfChoices;
+ context.Option = Option;
+ context.Flags = Flags;
+ context.SelectedChoice = SelectedChoice;
+ context.SelectedOption = SelectedOption;
+ context.SavedChoicesSettingName = SavedChoicesSettingName;
+
+ return DialogBoxParam(
+ PhInstanceHandle,
+ MAKEINTRESOURCE(IDD_CHOOSE),
+ ParentWindowHandle,
+ PhpChoiceDlgProc,
+ (LPARAM)&context
+ ) == IDOK;
+}
+
+INT_PTR CALLBACK PhpChoiceDlgProc(
+ _In_ HWND hwndDlg,
+ _In_ UINT uMsg,
+ _In_ WPARAM wParam,
+ _In_ LPARAM lParam
+ )
+{
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ PCHOICE_DIALOG_CONTEXT context = (PCHOICE_DIALOG_CONTEXT)lParam;
+ ULONG type;
+ SIZE_T i;
+ HWND comboBoxHandle;
+ HWND checkBoxHandle;
+ RECT checkBoxRect;
+ RECT rect;
+ ULONG diff;
+
+ PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);
+ PhCenterWindow(hwndDlg, GetParent(hwndDlg));
+
+ PhSetWindowText(hwndDlg, context->Title);
+ PhSetWindowText(GetDlgItem(hwndDlg, IDC_MESSAGE), context->Message);
+
+ type = context->Flags & PH_CHOICE_DIALOG_TYPE_MASK;
+
+ // Select the control to show, depending on the type. This is
+ // because it is impossible to change the style of the combo box
+ // after it is created.
+ switch (type)
+ {
+ case PH_CHOICE_DIALOG_USER_CHOICE:
+ comboBoxHandle = GetDlgItem(hwndDlg, IDC_CHOICEUSER);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_CHOICEUSER), SW_SHOW);
+ break;
+ case PH_CHOICE_DIALOG_PASSWORD:
+ comboBoxHandle = GetDlgItem(hwndDlg, IDC_CHOICESIMPLE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_CHOICESIMPLE), SW_SHOW);
+
+ // Disable combo box features since it isn't a combo box.
+ context->SavedChoicesSettingName = NULL;
+ break;
+ case PH_CHOICE_DIALOG_CHOICE:
+ default:
+ comboBoxHandle = GetDlgItem(hwndDlg, IDC_CHOICE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_CHOICE), SW_SHOW);
+ break;
+ }
+
+ context->ComboBoxHandle = comboBoxHandle;
+
+ checkBoxHandle = GetDlgItem(hwndDlg, IDC_OPTION);
+
+ if (type == PH_CHOICE_DIALOG_PASSWORD)
+ {
+ // Nothing
+ }
+ else if (type == PH_CHOICE_DIALOG_USER_CHOICE && context->SavedChoicesSettingName)
+ {
+ PPH_STRING savedChoices = PhGetStringSetting(context->SavedChoicesSettingName);
+ ULONG_PTR indexOfDelim;
+ PPH_STRING savedChoice;
+
+ i = 0;
+
+ // Split the saved choices using the delimiter.
+ while (i < savedChoices->Length / sizeof(WCHAR))
+ {
+ // BUG BUG BUG - what if the user saves "\s"?
+ indexOfDelim = PhFindStringInString(savedChoices, i, L"\\s");
+
+ if (indexOfDelim == -1)
+ indexOfDelim = savedChoices->Length / sizeof(WCHAR);
+
+ savedChoice = PhSubstring(savedChoices, i, indexOfDelim - i);
+
+ if (savedChoice->Length != 0)
+ {
+ PPH_STRING unescaped;
+
+ unescaped = PhUnescapeStringForDelimiter(savedChoice, '\\');
+ ComboBox_InsertString(comboBoxHandle, -1, unescaped->Buffer);
+ PhDereferenceObject(unescaped);
+ }
+
+ PhDereferenceObject(savedChoice);
+
+ i = indexOfDelim + 2;
+ }
+
+ PhDereferenceObject(savedChoices);
+ }
+ else
+ {
+ for (i = 0; i < context->NumberOfChoices; i++)
+ {
+ ComboBox_AddString(comboBoxHandle, context->Choices[i]);
+ }
+
+ context->SavedChoicesSettingName = NULL; // make sure we don't try to save the choices
+ }
+
+ if (type == PH_CHOICE_DIALOG_PASSWORD)
+ {
+ if (*context->SelectedChoice)
+ PhSetWindowText(comboBoxHandle, (*context->SelectedChoice)->Buffer);
+
+ Edit_SetSel(comboBoxHandle, 0, -1);
+ }
+ else if (type == PH_CHOICE_DIALOG_USER_CHOICE || type == PH_CHOICE_DIALOG_CHOICE)
+ {
+ // If we failed to choose a default choice based on what was specified,
+ // select the first one if possible, or set the text directly.
+ if (!(*context->SelectedChoice) || PhSelectComboBoxString(
+ comboBoxHandle, (*context->SelectedChoice)->Buffer, FALSE) == CB_ERR)
+ {
+ if (type == PH_CHOICE_DIALOG_USER_CHOICE && *context->SelectedChoice)
+ {
+ PhSetWindowText(comboBoxHandle, (*context->SelectedChoice)->Buffer);
+ }
+ else if (type == PH_CHOICE_DIALOG_CHOICE && context->NumberOfChoices != 0)
+ {
+ ComboBox_SetCurSel(comboBoxHandle, 0);
+ }
+ }
+
+ if (type == PH_CHOICE_DIALOG_USER_CHOICE)
+ ComboBox_SetEditSel(comboBoxHandle, 0, -1);
+ }
+
+ if (context->Option)
+ {
+ PhSetWindowText(checkBoxHandle, context->Option);
+
+ if (context->SelectedOption)
+ Button_SetCheck(checkBoxHandle, *context->SelectedOption ? BST_CHECKED : BST_UNCHECKED);
+ }
+ else
+ {
+ // Hide the check box and move the buttons up.
+
+ ShowWindow(checkBoxHandle, SW_HIDE);
+ GetWindowRect(checkBoxHandle, &checkBoxRect);
+ MapWindowPoints(NULL, hwndDlg, (POINT *)&checkBoxRect, 2);
+ GetWindowRect(GetDlgItem(hwndDlg, IDOK), &rect);
+ MapWindowPoints(NULL, hwndDlg, (POINT *)&rect, 2);
+ diff = rect.top - checkBoxRect.top;
+
+ // OK
+ rect.top -= diff;
+ rect.bottom -= diff;
+ SetWindowPos(GetDlgItem(hwndDlg, IDOK), NULL, rect.left, rect.top,
+ rect.right - rect.left, rect.bottom - rect.top,
+ SWP_NOACTIVATE | SWP_NOZORDER);
+
+ // Cancel
+ GetWindowRect(GetDlgItem(hwndDlg, IDCANCEL), &rect);
+ MapWindowPoints(NULL, hwndDlg, (POINT *)&rect, 2);
+ rect.top -= diff;
+ rect.bottom -= diff;
+ SetWindowPos(GetDlgItem(hwndDlg, IDCANCEL), NULL, rect.left, rect.top,
+ rect.right - rect.left, rect.bottom - rect.top,
+ SWP_NOACTIVATE | SWP_NOZORDER);
+
+ // Window
+ GetWindowRect(hwndDlg, &rect);
+ rect.bottom -= diff;
+ SetWindowPos(hwndDlg, NULL, rect.left, rect.top,
+ rect.right - rect.left, rect.bottom - rect.top,
+ SWP_NOACTIVATE | SWP_NOZORDER);
+ }
+
+ PhInitializeWindowTheme(hwndDlg, PhEnableThemeSupport);
+
+ PhSetDialogFocus(hwndDlg, comboBoxHandle);
+ }
+ break;
+ case WM_DESTROY:
+ {
+ PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);
+ }
+ break;
+ case WM_COMMAND:
+ {
+ switch (GET_WM_COMMAND_ID(wParam, lParam))
+ {
+ case IDCANCEL:
+ EndDialog(hwndDlg, IDCANCEL);
+ break;
+ case IDOK:
+ {
+ PCHOICE_DIALOG_CONTEXT context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);
+ PPH_STRING selectedChoice;
+
+ if ((context->Flags & PH_CHOICE_DIALOG_TYPE_MASK) != PH_CHOICE_DIALOG_PASSWORD)
+ {
+ selectedChoice = PH_AUTO(PhGetWindowText(context->ComboBoxHandle));
+ *context->SelectedChoice = selectedChoice;
+ }
+ else
+ {
+ // Password values are never auto-dereferenced.
+ selectedChoice = PhGetWindowText(context->ComboBoxHandle);
+ *context->SelectedChoice = selectedChoice;
+ }
+
+ if (context->Option && context->SelectedOption)
+ *context->SelectedOption = Button_GetCheck(GetDlgItem(hwndDlg, IDC_OPTION)) == BST_CHECKED;
+
+ if (context->SavedChoicesSettingName)
+ {
+ PH_STRING_BUILDER savedChoices;
+ ULONG i;
+ ULONG choicesToSave = PH_CHOICE_DIALOG_SAVED_CHOICES;
+ PPH_STRING choice;
+ PPH_STRING escaped;
+
+ PhInitializeStringBuilder(&savedChoices, 100);
+
+ // Push the selected choice to the top, then save the others.
+
+ if (selectedChoice->Length != 0)
+ {
+ escaped = PhEscapeStringForDelimiter(selectedChoice, '\\');
+ PhAppendStringBuilder(&savedChoices, &escaped->sr);
+ PhDereferenceObject(escaped);
+ PhAppendStringBuilder2(&savedChoices, L"\\s");
+ }
+
+ for (i = 1; i < choicesToSave; i++)
+ {
+ choice = PhGetComboBoxString(context->ComboBoxHandle, i - 1);
+
+ if (!choice)
+ break;
+
+ // Don't save the choice if it's the same as the one
+ // entered by the user (since we already saved it above).
+ if (PhEqualString(choice, selectedChoice, FALSE))
+ {
+ PhDereferenceObject(choice);
+ choicesToSave++; // useless for now, but may be needed in the future
+ continue;
+ }
+
+ escaped = PhEscapeStringForDelimiter(choice, '\\');
+ PhAppendStringBuilder(&savedChoices, &escaped->sr);
+ PhDereferenceObject(escaped);
+ PhDereferenceObject(choice);
+
+ PhAppendStringBuilder2(&savedChoices, L"\\s");
+ }
+
+ if (PhEndsWithString2(savedChoices.String, L"\\s", FALSE))
+ PhRemoveEndStringBuilder(&savedChoices, 2);
+
+ PhSetStringSetting2(context->SavedChoicesSettingName, &savedChoices.String->sr);
+ PhDeleteStringBuilder(&savedChoices);
+ }
+
+ EndDialog(hwndDlg, IDOK);
+ }
+ break;
+ }
+ }
+ break;
+ }
+
+ return FALSE;
+}
diff --git a/ProcessHacker/chproc.c b/ProcessHacker/chproc.c
index ef2b32659a40..de817e5c6c91 100644
--- a/ProcessHacker/chproc.c
+++ b/ProcessHacker/chproc.c
@@ -1,316 +1,318 @@
-/*
- * Process Hacker -
- * choose process 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 .
- */
-
-#include
-
-#include
-
-typedef struct _CHOOSE_PROCESS_DIALOG_CONTEXT
-{
- PWSTR Message;
- HANDLE ProcessId;
-
- PH_LAYOUT_MANAGER LayoutManager;
- RECT MinimumSize;
- HIMAGELIST ImageList;
- HWND ListViewHandle;
-} CHOOSE_PROCESS_DIALOG_CONTEXT, *PCHOOSE_PROCESS_DIALOG_CONTEXT;
-
-INT_PTR CALLBACK PhpChooseProcessDlgProc(
- _In_ HWND hwndDlg,
- _In_ UINT uMsg,
- _In_ WPARAM wParam,
- _In_ LPARAM lParam
- );
-
-BOOLEAN PhShowChooseProcessDialog(
- _In_ HWND ParentWindowHandle,
- _In_ PWSTR Message,
- _Out_ PHANDLE ProcessId
- )
-{
- CHOOSE_PROCESS_DIALOG_CONTEXT context;
-
- context.Message = Message;
- context.ProcessId = NULL;
-
- if (DialogBoxParam(
- PhInstanceHandle,
- MAKEINTRESOURCE(IDD_CHOOSEPROCESS),
- ParentWindowHandle,
- PhpChooseProcessDlgProc,
- (LPARAM)&context
- ) == IDOK)
- {
- *ProcessId = context.ProcessId;
-
- return TRUE;
- }
- else
- {
- return FALSE;
- }
-}
-
-static VOID PhpRefreshProcessList(
- _In_ HWND hwndDlg,
- _In_ PCHOOSE_PROCESS_DIALOG_CONTEXT Context
- )
-{
- NTSTATUS status;
- HWND lvHandle;
- PVOID processes;
- PSYSTEM_PROCESS_INFORMATION process;
-
- lvHandle = Context->ListViewHandle;
-
- if (!NT_SUCCESS(status = PhEnumProcesses(&processes)))
- {
- PhShowStatus(hwndDlg, L"Unable to enumerate processes", status, 0);
- return;
- }
-
- ExtendedListView_SetRedraw(lvHandle, FALSE);
-
- ListView_DeleteAllItems(lvHandle);
- ImageList_RemoveAll(Context->ImageList);
-
- process = PH_FIRST_PROCESS(processes);
-
- do
- {
- INT lvItemIndex;
- PPH_STRING name;
- HANDLE processHandle;
- PPH_STRING fileName = NULL;
- HICON icon = NULL;
- WCHAR processIdString[PH_INT32_STR_LEN_1];
- PPH_STRING userName = NULL;
- INT imageIndex;
-
- if (process->UniqueProcessId != SYSTEM_IDLE_PROCESS_ID)
- name = PhCreateStringFromUnicodeString(&process->ImageName);
- else
- name = PhCreateString(SYSTEM_IDLE_PROCESS_NAME);
-
- lvItemIndex = PhAddListViewItem(lvHandle, MAXINT, name->Buffer, process->UniqueProcessId);
- PhDereferenceObject(name);
-
- if (NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess, process->UniqueProcessId)))
- {
- HANDLE tokenHandle;
- PTOKEN_USER user;
-
- if (!WINDOWS_HAS_IMAGE_FILE_NAME_BY_PROCESS_ID && process->UniqueProcessId != SYSTEM_PROCESS_ID)
- PhGetProcessImageFileName(processHandle, &fileName);
-
- if (NT_SUCCESS(PhOpenProcessToken(processHandle, TOKEN_QUERY, &tokenHandle)))
- {
- if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &user)))
- {
- userName = PhGetSidFullName(user->User.Sid, TRUE, NULL);
- PhFree(user);
- }
-
- NtClose(tokenHandle);
- }
-
- NtClose(processHandle);
- }
-
- if (process->UniqueProcessId == SYSTEM_IDLE_PROCESS_ID && !userName && PhLocalSystemName)
- PhSetReference(&userName, PhLocalSystemName);
-
- if (WINDOWS_HAS_IMAGE_FILE_NAME_BY_PROCESS_ID && process->UniqueProcessId != SYSTEM_PROCESS_ID)
- PhGetProcessImageFileNameByProcessId(process->UniqueProcessId, &fileName);
-
- if (process->UniqueProcessId == SYSTEM_PROCESS_ID)
- fileName = PhGetKernelFileName();
-
- if (fileName)
- PhMoveReference(&fileName, PhGetFileName(fileName));
-
- icon = PhGetFileShellIcon(PhGetString(fileName), L".exe", FALSE);
-
- // Icon
- if (icon)
- {
- imageIndex = ImageList_AddIcon(Context->ImageList, icon);
- PhSetListViewItemImageIndex(Context->ListViewHandle, lvItemIndex, imageIndex);
- DestroyIcon(icon);
- }
-
- // PID
- PhPrintUInt32(processIdString, HandleToUlong(process->UniqueProcessId));
- PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 1, processIdString);
-
- // User Name
- PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 2, PhGetString(userName));
-
- if (userName) PhDereferenceObject(userName);
- if (fileName) PhDereferenceObject(fileName);
- } while (process = PH_NEXT_PROCESS(process));
-
- PhFree(processes);
-
- ExtendedListView_SortItems(lvHandle);
- ExtendedListView_SetRedraw(lvHandle, TRUE);
-}
-
-INT_PTR CALLBACK PhpChooseProcessDlgProc(
- _In_ HWND hwndDlg,
- _In_ UINT uMsg,
- _In_ WPARAM wParam,
- _In_ LPARAM lParam
- )
-{
- PCHOOSE_PROCESS_DIALOG_CONTEXT context = NULL;
-
- if (uMsg == WM_INITDIALOG)
- {
- context = (PCHOOSE_PROCESS_DIALOG_CONTEXT)lParam;
- SetProp(hwndDlg, PhMakeContextAtom(), (HANDLE)context);
- }
- else
- {
- context = (PCHOOSE_PROCESS_DIALOG_CONTEXT)GetProp(hwndDlg, PhMakeContextAtom());
-
- if (uMsg == WM_DESTROY)
- {
- RemoveProp(hwndDlg, PhMakeContextAtom());
- }
- }
-
- if (!context)
- return FALSE;
-
- switch (uMsg)
- {
- case WM_INITDIALOG:
- {
- HWND lvHandle;
-
- PhCenterWindow(hwndDlg, GetParent(hwndDlg));
-
- SetDlgItemText(hwndDlg, IDC_MESSAGE, context->Message);
-
- PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);
- PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_MESSAGE), NULL,
- PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT | PH_LAYOUT_FORCE_INVALIDATE);
- PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_LIST), NULL,
- PH_ANCHOR_ALL);
- PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL,
- PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
- PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDCANCEL), NULL,
- PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
- PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_REFRESH), NULL,
- PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT);
- PhLayoutManagerLayout(&context->LayoutManager);
-
- context->MinimumSize.left = 0;
- context->MinimumSize.top = 0;
- context->MinimumSize.right = 280;
- context->MinimumSize.bottom = 170;
- MapDialogRect(hwndDlg, &context->MinimumSize);
-
- context->ListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_LIST);
- context->ImageList = ImageList_Create(PhSmallIconSize.X, PhSmallIconSize.Y, ILC_COLOR32 | ILC_MASK, 0, 40);
-
- PhSetListViewStyle(lvHandle, FALSE, TRUE);
- PhSetControlTheme(lvHandle, L"explorer");
- PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 180, L"Name");
- PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 60, L"PID");
- PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 160, L"User name");
- PhSetExtendedListView(lvHandle);
-
- ListView_SetImageList(lvHandle, context->ImageList, LVSIL_SMALL);
-
- PhpRefreshProcessList(hwndDlg, context);
-
- EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
- }
- break;
- case WM_DESTROY:
- {
- ImageList_Destroy(context->ImageList);
- PhDeleteLayoutManager(&context->LayoutManager);
- }
- break;
- case WM_COMMAND:
- {
- switch (LOWORD(wParam))
- {
- case IDCANCEL:
- {
- EndDialog(hwndDlg, IDCANCEL);
- }
- break;
- case IDOK:
- {
- if (ListView_GetSelectedCount(context->ListViewHandle) == 1)
- {
- context->ProcessId = (HANDLE)PhGetSelectedListViewItemParam(context->ListViewHandle);
- EndDialog(hwndDlg, IDOK);
- }
- }
- break;
- case IDC_REFRESH:
- {
- PhpRefreshProcessList(hwndDlg, context);
- }
- break;
- }
- }
- break;
- case WM_NOTIFY:
- {
- LPNMHDR header = (LPNMHDR)lParam;
-
- switch (header->code)
- {
- case LVN_ITEMCHANGED:
- {
- EnableWindow(GetDlgItem(hwndDlg, IDOK), ListView_GetSelectedCount(context->ListViewHandle) == 1);
- }
- break;
- case NM_DBLCLK:
- {
- SendMessage(hwndDlg, WM_COMMAND, IDOK, 0);
- }
- break;
- }
- }
- break;
- case WM_SIZE:
- {
- PhLayoutManagerLayout(&context->LayoutManager);
- }
- break;
- case WM_SIZING:
- {
- PhResizingMinimumSize((PRECT)lParam, wParam, context->MinimumSize.right, context->MinimumSize.bottom);
- }
- break;
- }
-
- return FALSE;
-}
+/*
+ * Process Hacker -
+ * choose process 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 .
+ */
+
+#include
+#include
+#include
+
+typedef struct _CHOOSE_PROCESS_DIALOG_CONTEXT
+{
+ PWSTR Message;
+ HANDLE ProcessId;
+
+ PH_LAYOUT_MANAGER LayoutManager;
+ RECT MinimumSize;
+ HIMAGELIST ImageList;
+ HWND ListViewHandle;
+} CHOOSE_PROCESS_DIALOG_CONTEXT, *PCHOOSE_PROCESS_DIALOG_CONTEXT;
+
+INT_PTR CALLBACK PhpChooseProcessDlgProc(
+ _In_ HWND hwndDlg,
+ _In_ UINT uMsg,
+ _In_ WPARAM wParam,
+ _In_ LPARAM lParam
+ );
+
+BOOLEAN PhShowChooseProcessDialog(
+ _In_ HWND ParentWindowHandle,
+ _In_ PWSTR Message,
+ _Out_ PHANDLE ProcessId
+ )
+{
+ CHOOSE_PROCESS_DIALOG_CONTEXT context;
+
+ memset(&context, 0, sizeof(CHOOSE_PROCESS_DIALOG_CONTEXT));
+ context.Message = Message;
+ context.ProcessId = NULL;
+
+ if (DialogBoxParam(
+ PhInstanceHandle,
+ MAKEINTRESOURCE(IDD_CHOOSEPROCESS),
+ ParentWindowHandle,
+ PhpChooseProcessDlgProc,
+ (LPARAM)&context
+ ) == IDOK)
+ {
+ *ProcessId = context.ProcessId;
+
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+static VOID PhpRefreshProcessList(
+ _In_ HWND hwndDlg,
+ _In_ PCHOOSE_PROCESS_DIALOG_CONTEXT Context
+ )
+{
+ NTSTATUS status;
+ PVOID processes;
+ PSYSTEM_PROCESS_INFORMATION process;
+
+ if (!NT_SUCCESS(status = PhEnumProcesses(&processes)))
+ {
+ PhShowStatus(hwndDlg, L"Unable to enumerate processes", status, 0);
+ return;
+ }
+
+ ExtendedListView_SetRedraw(Context->ListViewHandle, FALSE);
+ ListView_DeleteAllItems(Context->ListViewHandle);
+ ImageList_RemoveAll(Context->ImageList);
+
+ process = PH_FIRST_PROCESS(processes);
+
+ do
+ {
+ INT lvItemIndex;
+ PPH_STRING name;
+ HANDLE processHandle;
+ PPH_STRING fileName = NULL;
+ HICON icon = NULL;
+ WCHAR processIdString[PH_INT32_STR_LEN_1];
+ PPH_STRING userName = NULL;
+ INT imageIndex = INT_MAX;
+
+ if (process->UniqueProcessId != SYSTEM_IDLE_PROCESS_ID)
+ name = PhCreateStringFromUnicodeString(&process->ImageName);
+ else
+ name = PhCreateString(SYSTEM_IDLE_PROCESS_NAME);
+
+ lvItemIndex = PhAddListViewItem(Context->ListViewHandle, MAXINT, name->Buffer, process->UniqueProcessId);
+ PhDereferenceObject(name);
+
+ if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_LIMITED_INFORMATION, process->UniqueProcessId)))
+ {
+ HANDLE tokenHandle;
+ PTOKEN_USER user;
+
+ if (NT_SUCCESS(PhOpenProcessToken(processHandle, TOKEN_QUERY, &tokenHandle)))
+ {
+ if (NT_SUCCESS(PhGetTokenUser(tokenHandle, &user)))
+ {
+ userName = PhGetSidFullName(user->User.Sid, TRUE, NULL);
+ PhFree(user);
+ }
+
+ NtClose(tokenHandle);
+ }
+
+ NtClose(processHandle);
+ }
+
+ if (process->UniqueProcessId == SYSTEM_IDLE_PROCESS_ID && !userName)
+ {
+ PhSetReference(&userName, PhGetSidFullName(&PhSeLocalSystemSid, TRUE, NULL));
+ }
+
+ if (process->UniqueProcessId == SYSTEM_PROCESS_ID)
+ fileName = PhGetKernelFileName();
+ else if (PH_IS_REAL_PROCESS_ID(process->UniqueProcessId))
+ PhGetProcessImageFileNameByProcessId(process->UniqueProcessId, &fileName);
+
+ if (fileName)
+ PhMoveReference(&fileName, PhGetFileName(fileName));
+
+ // Icon
+ if (!PhIsNullOrEmptyString(fileName))
+ {
+ PhExtractIcon(PhGetString(fileName), NULL, &icon);
+ }
+
+ if (icon)
+ {
+ imageIndex = ImageList_AddIcon(Context->ImageList, icon);
+ PhSetListViewItemImageIndex(Context->ListViewHandle, lvItemIndex, imageIndex);
+ DestroyIcon(icon);
+ }
+ else
+ {
+ PhGetStockApplicationIcon(NULL, &icon);
+ imageIndex = ImageList_AddIcon(Context->ImageList, icon);
+ PhSetListViewItemImageIndex(Context->ListViewHandle, lvItemIndex, imageIndex);
+ }
+
+ // PID
+ PhPrintUInt32(processIdString, HandleToUlong(process->UniqueProcessId));
+ PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 1, processIdString);
+
+ // User Name
+ PhSetListViewSubItem(Context->ListViewHandle, lvItemIndex, 2, PhGetString(userName));
+
+ if (userName) PhDereferenceObject(userName);
+ if (fileName) PhDereferenceObject(fileName);
+ } while (process = PH_NEXT_PROCESS(process));
+
+ PhFree(processes);
+
+ ExtendedListView_SortItems(Context->ListViewHandle);
+ ExtendedListView_SetRedraw(Context->ListViewHandle, TRUE);
+}
+
+INT_PTR CALLBACK PhpChooseProcessDlgProc(
+ _In_ HWND hwndDlg,
+ _In_ UINT uMsg,
+ _In_ WPARAM wParam,
+ _In_ LPARAM lParam
+ )
+{
+ PCHOOSE_PROCESS_DIALOG_CONTEXT context = NULL;
+
+ if (uMsg == WM_INITDIALOG)
+ {
+ context = (PCHOOSE_PROCESS_DIALOG_CONTEXT)lParam;
+ PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);
+ }
+ else
+ {
+ context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);
+
+ if (uMsg == WM_DESTROY)
+ {
+ PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);
+ }
+ }
+
+ if (!context)
+ return FALSE;
+
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ HWND lvHandle;
+
+ SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)PH_LOAD_SHARED_ICON_SMALL(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER)));
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)PH_LOAD_SHARED_ICON_LARGE(PhInstanceHandle, MAKEINTRESOURCE(IDI_PROCESSHACKER)));
+
+ PhCenterWindow(hwndDlg, GetParent(hwndDlg));
+
+ PhSetDialogItemText(hwndDlg, IDC_MESSAGE, context->Message);
+
+ PhInitializeLayoutManager(&context->LayoutManager, hwndDlg);
+ PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_MESSAGE), NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT | PH_LAYOUT_FORCE_INVALIDATE);
+ PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_LIST), NULL, PH_ANCHOR_ALL);
+ PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDOK), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
+ PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDCANCEL), NULL, PH_ANCHOR_RIGHT | PH_ANCHOR_BOTTOM);
+ PhAddLayoutItem(&context->LayoutManager, GetDlgItem(hwndDlg, IDC_REFRESH), NULL, PH_ANCHOR_BOTTOM | PH_ANCHOR_LEFT);
+ PhLayoutManagerLayout(&context->LayoutManager);
+
+ context->MinimumSize.left = 0;
+ context->MinimumSize.top = 0;
+ context->MinimumSize.right = 280;
+ context->MinimumSize.bottom = 170;
+ MapDialogRect(hwndDlg, &context->MinimumSize);
+
+ context->ListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_LIST);
+ context->ImageList = ImageList_Create(PhSmallIconSize.X, PhSmallIconSize.Y, ILC_COLOR32 | ILC_MASK, 0, 40);
+
+ PhSetListViewStyle(lvHandle, FALSE, TRUE);
+ PhSetControlTheme(lvHandle, L"explorer");
+ PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 180, L"Name");
+ PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 60, L"PID");
+ PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 160, L"User name");
+ PhSetExtendedListView(lvHandle);
+
+ ListView_SetImageList(lvHandle, context->ImageList, LVSIL_SMALL);
+
+ PhpRefreshProcessList(hwndDlg, context);
+
+ EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
+ }
+ break;
+ case WM_DESTROY:
+ {
+ ImageList_Destroy(context->ImageList);
+ PhDeleteLayoutManager(&context->LayoutManager);
+ }
+ break;
+ case WM_COMMAND:
+ {
+ switch (GET_WM_COMMAND_ID(wParam, lParam))
+ {
+ case IDCANCEL:
+ {
+ EndDialog(hwndDlg, IDCANCEL);
+ }
+ break;
+ case IDOK:
+ {
+ if (ListView_GetSelectedCount(context->ListViewHandle) == 1)
+ {
+ context->ProcessId = (HANDLE)PhGetSelectedListViewItemParam(context->ListViewHandle);
+ EndDialog(hwndDlg, IDOK);
+ }
+ }
+ break;
+ case IDC_REFRESH:
+ {
+ PhpRefreshProcessList(hwndDlg, context);
+ }
+ break;
+ }
+ }
+ break;
+ case WM_NOTIFY:
+ {
+ LPNMHDR header = (LPNMHDR)lParam;
+
+ switch (header->code)
+ {
+ case LVN_ITEMCHANGED:
+ {
+ EnableWindow(GetDlgItem(hwndDlg, IDOK), ListView_GetSelectedCount(context->ListViewHandle) == 1);
+ }
+ break;
+ case NM_DBLCLK:
+ {
+ SendMessage(hwndDlg, WM_COMMAND, IDOK, 0);
+ }
+ break;
+ }
+ }
+ break;
+ case WM_SIZE:
+ {
+ PhLayoutManagerLayout(&context->LayoutManager);
+ }
+ break;
+ case WM_SIZING:
+ {
+ PhResizingMinimumSize((PRECT)lParam, wParam, context->MinimumSize.right, context->MinimumSize.bottom);
+ }
+ break;
+ }
+
+ return FALSE;
+}
diff --git a/ProcessHacker/cmdmode.c b/ProcessHacker/cmdmode.c
index c47b048ecef2..fdc08b3a7dea 100644
--- a/ProcessHacker/cmdmode.c
+++ b/ProcessHacker/cmdmode.c
@@ -1,452 +1,399 @@
-/*
- * Process Hacker -
- * command line action mode
- *
- * Copyright (C) 2010-2012 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 .
- */
-
-#include
-
-#include
-
-NTSTATUS PhpGetDllBaseRemote(
- _In_ HANDLE ProcessHandle,
- _In_ PPH_STRINGREF BaseDllName,
- _Out_ PVOID *DllBase
- );
-
-static HWND CommandModeWindowHandle;
-
-#define PH_COMMAND_OPTION_HWND 1
-
-BOOLEAN NTAPI PhpCommandModeOptionCallback(
- _In_opt_ PPH_COMMAND_LINE_OPTION Option,
- _In_opt_ PPH_STRING Value,
- _In_opt_ PVOID Context
- )
-{
- ULONG64 integer;
-
- if (Option)
- {
- switch (Option->Id)
- {
- case PH_COMMAND_OPTION_HWND:
- if (PhStringToInteger64(&Value->sr, 10, &integer))
- CommandModeWindowHandle = (HWND)integer;
- break;
- }
- }
-
- return TRUE;
-}
-
-NTSTATUS PhCommandModeStart(
- VOID
- )
-{
- static PH_COMMAND_LINE_OPTION options[] =
- {
- { PH_COMMAND_OPTION_HWND, L"hwnd", MandatoryArgumentType }
- };
- NTSTATUS status = STATUS_SUCCESS;
- PH_STRINGREF commandLine;
-
- PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, &commandLine);
-
- PhParseCommandLine(
- &commandLine,
- options,
- sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION),
- PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS,
- PhpCommandModeOptionCallback,
- NULL
- );
-
- if (PhEqualString2(PhStartupParameters.CommandType, L"process", TRUE))
- {
- SIZE_T i;
- SIZE_T processIdLength;
- HANDLE processId;
- HANDLE processHandle;
-
- if (!PhStartupParameters.CommandObject)
- return STATUS_INVALID_PARAMETER;
-
- processIdLength = PhStartupParameters.CommandObject->Length / 2;
-
- for (i = 0; i < processIdLength; i++)
- {
- if (!PhIsDigitCharacter(PhStartupParameters.CommandObject->Buffer[i]))
- break;
- }
-
- if (i == processIdLength)
- {
- ULONG64 processId64;
-
- if (!PhStringToInteger64(&PhStartupParameters.CommandObject->sr, 10, &processId64))
- return STATUS_INVALID_PARAMETER;
-
- processId = (HANDLE)processId64;
- }
- else
- {
- PVOID processes;
- PSYSTEM_PROCESS_INFORMATION process;
-
- if (!NT_SUCCESS(status = PhEnumProcesses(&processes)))
- return status;
-
- if (!(process = PhFindProcessInformationByImageName(processes, &PhStartupParameters.CommandObject->sr)))
- {
- PhFree(processes);
- return STATUS_NOT_FOUND;
- }
-
- processId = process->UniqueProcessId;
- PhFree(processes);
- }
-
- if (PhEqualString2(PhStartupParameters.CommandAction, L"terminate", TRUE))
- {
- if (NT_SUCCESS(status = PhOpenProcessPublic(&processHandle, PROCESS_TERMINATE, processId)))
- {
- status = NtTerminateProcess(processHandle, STATUS_SUCCESS);
- NtClose(processHandle);
- }
- }
- else if (PhEqualString2(PhStartupParameters.CommandAction, L"suspend", TRUE))
- {
- if (NT_SUCCESS(status = PhOpenProcessPublic(&processHandle, PROCESS_SUSPEND_RESUME, processId)))
- {
- status = NtSuspendProcess(processHandle);
- NtClose(processHandle);
- }
- }
- else if (PhEqualString2(PhStartupParameters.CommandAction, L"resume", TRUE))
- {
- if (NT_SUCCESS(status = PhOpenProcessPublic(&processHandle, PROCESS_SUSPEND_RESUME, processId)))
- {
- status = NtResumeProcess(processHandle);
- NtClose(processHandle);
- }
- }
- else if (PhEqualString2(PhStartupParameters.CommandAction, L"priority", TRUE))
- {
- UCHAR priority;
-
- if (!PhStartupParameters.CommandValue)
- return STATUS_INVALID_PARAMETER;
-
- if (PhEqualString2(PhStartupParameters.CommandValue, L"idle", TRUE))
- priority = PROCESS_PRIORITY_CLASS_IDLE;
- else if (PhEqualString2(PhStartupParameters.CommandValue, L"normal", TRUE))
- priority = PROCESS_PRIORITY_CLASS_NORMAL;
- else if (PhEqualString2(PhStartupParameters.CommandValue, L"high", TRUE))
- priority = PROCESS_PRIORITY_CLASS_HIGH;
- else if (PhEqualString2(PhStartupParameters.CommandValue, L"realtime", TRUE))
- priority = PROCESS_PRIORITY_CLASS_REALTIME;
- else if (PhEqualString2(PhStartupParameters.CommandValue, L"abovenormal", TRUE))
- priority = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL;
- else if (PhEqualString2(PhStartupParameters.CommandValue, L"belownormal", TRUE))
- priority = PROCESS_PRIORITY_CLASS_BELOW_NORMAL;
- else
- return STATUS_INVALID_PARAMETER;
-
- if (NT_SUCCESS(status = PhOpenProcessPublic(&processHandle, PROCESS_SET_INFORMATION, processId)))
- {
- PROCESS_PRIORITY_CLASS priorityClass;
- priorityClass.Foreground = FALSE;
- priorityClass.PriorityClass = priority;
- status = NtSetInformationProcess(processHandle, ProcessPriorityClass, &priorityClass, sizeof(PROCESS_PRIORITY_CLASS));
- NtClose(processHandle);
- }
- }
- else if (PhEqualString2(PhStartupParameters.CommandAction, L"iopriority", TRUE))
- {
- ULONG ioPriority;
-
- if (!PhStartupParameters.CommandValue)
- return STATUS_INVALID_PARAMETER;
-
- if (PhEqualString2(PhStartupParameters.CommandValue, L"verylow", TRUE))
- ioPriority = 0;
- else if (PhEqualString2(PhStartupParameters.CommandValue, L"low", TRUE))
- ioPriority = 1;
- else if (PhEqualString2(PhStartupParameters.CommandValue, L"normal", TRUE))
- ioPriority = 2;
- else if (PhEqualString2(PhStartupParameters.CommandValue, L"high", TRUE))
- ioPriority = 3;
- else
- return STATUS_INVALID_PARAMETER;
-
- if (NT_SUCCESS(status = PhOpenProcessPublic(&processHandle, PROCESS_SET_INFORMATION, processId)))
- {
- status = PhSetProcessIoPriority(processHandle, ioPriority);
- NtClose(processHandle);
- }
- }
- else if (PhEqualString2(PhStartupParameters.CommandAction, L"pagepriority", TRUE))
- {
- ULONG64 pagePriority64;
- ULONG pagePriority;
-
- if (!PhStartupParameters.CommandValue)
- return STATUS_INVALID_PARAMETER;
-
- PhStringToInteger64(&PhStartupParameters.CommandValue->sr, 10, &pagePriority64);
- pagePriority = (ULONG)pagePriority64;
-
- if (NT_SUCCESS(status = PhOpenProcessPublic(&processHandle, PROCESS_SET_INFORMATION, processId)))
- {
- status = NtSetInformationProcess(
- processHandle,
- ProcessPagePriority,
- &pagePriority,
- sizeof(ULONG)
- );
- NtClose(processHandle);
- }
- }
- else if (PhEqualString2(PhStartupParameters.CommandAction, L"injectdll", TRUE))
- {
- if (!PhStartupParameters.CommandValue)
- return STATUS_INVALID_PARAMETER;
-
- if (NT_SUCCESS(status = PhOpenProcessPublic(
- &processHandle,
- ProcessQueryAccess | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE,
- processId
- )))
- {
- LARGE_INTEGER timeout;
-
- timeout.QuadPart = -5 * PH_TIMEOUT_SEC;
- status = PhInjectDllProcess(
- processHandle,
- PhStartupParameters.CommandValue->Buffer,
- &timeout
- );
- NtClose(processHandle);
- }
- }
- else if (PhEqualString2(PhStartupParameters.CommandAction, L"unloaddll", TRUE))
- {
- if (!PhStartupParameters.CommandValue)
- return STATUS_INVALID_PARAMETER;
-
- if (NT_SUCCESS(status = PhOpenProcessPublic(
- &processHandle,
- ProcessQueryAccess | PROCESS_CREATE_THREAD | PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE,
- processId
- )))
- {
- PVOID baseAddress;
-
- if (NT_SUCCESS(status = PhpGetDllBaseRemote(
- processHandle,
- &PhStartupParameters.CommandValue->sr,
- &baseAddress
- )))
- {
- LARGE_INTEGER timeout;
-
- timeout.QuadPart = -5 * PH_TIMEOUT_SEC;
- status = PhUnloadDllProcess(
- processHandle,
- baseAddress,
- &timeout
- );
- }
-
- NtClose(processHandle);
- }
- }
- }
- else if (PhEqualString2(PhStartupParameters.CommandType, L"service", TRUE))
- {
- SC_HANDLE serviceHandle;
- SERVICE_STATUS serviceStatus;
-
- if (!PhStartupParameters.CommandObject)
- return STATUS_INVALID_PARAMETER;
-
- if (PhEqualString2(PhStartupParameters.CommandAction, L"start", TRUE))
- {
- if (!(serviceHandle = PhOpenService(
- PhStartupParameters.CommandObject->Buffer,
- SERVICE_START
- )))
- return PhGetLastWin32ErrorAsNtStatus();
-
- if (!StartService(serviceHandle, 0, NULL))
- status = PhGetLastWin32ErrorAsNtStatus();
-
- CloseServiceHandle(serviceHandle);
- }
- else if (PhEqualString2(PhStartupParameters.CommandAction, L"continue", TRUE))
- {
- if (!(serviceHandle = PhOpenService(
- PhStartupParameters.CommandObject->Buffer,
- SERVICE_PAUSE_CONTINUE
- )))
- return PhGetLastWin32ErrorAsNtStatus();
-
- if (!ControlService(serviceHandle, SERVICE_CONTROL_CONTINUE, &serviceStatus))
- status = PhGetLastWin32ErrorAsNtStatus();
-
- CloseServiceHandle(serviceHandle);
- }
- else if (PhEqualString2(PhStartupParameters.CommandAction, L"pause", TRUE))
- {
- if (!(serviceHandle = PhOpenService(
- PhStartupParameters.CommandObject->Buffer,
- SERVICE_PAUSE_CONTINUE
- )))
- return PhGetLastWin32ErrorAsNtStatus();
-
- if (!ControlService(serviceHandle, SERVICE_CONTROL_PAUSE, &serviceStatus))
- status = PhGetLastWin32ErrorAsNtStatus();
-
- CloseServiceHandle(serviceHandle);
- }
- else if (PhEqualString2(PhStartupParameters.CommandAction, L"stop", TRUE))
- {
- if (!(serviceHandle = PhOpenService(
- PhStartupParameters.CommandObject->Buffer,
- SERVICE_STOP
- )))
- return PhGetLastWin32ErrorAsNtStatus();
-
- if (!ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus))
- status = PhGetLastWin32ErrorAsNtStatus();
-
- CloseServiceHandle(serviceHandle);
- }
- else if (PhEqualString2(PhStartupParameters.CommandAction, L"delete", TRUE))
- {
- if (!(serviceHandle = PhOpenService(
- PhStartupParameters.CommandObject->Buffer,
- DELETE
- )))
- return PhGetLastWin32ErrorAsNtStatus();
-
- if (!DeleteService(serviceHandle))
- status = PhGetLastWin32ErrorAsNtStatus();
-
- CloseServiceHandle(serviceHandle);
- }
- }
- else if (PhEqualString2(PhStartupParameters.CommandType, L"thread", TRUE))
- {
- ULONG64 threadId64;
- HANDLE threadId;
- HANDLE threadHandle;
-
- if (!PhStartupParameters.CommandObject)
- return STATUS_INVALID_PARAMETER;
-
- if (!PhStringToInteger64(&PhStartupParameters.CommandObject->sr, 10, &threadId64))
- return STATUS_INVALID_PARAMETER;
-
- threadId = (HANDLE)threadId64;
-
- if (PhEqualString2(PhStartupParameters.CommandAction, L"terminate", TRUE))
- {
- if (NT_SUCCESS(status = PhOpenThreadPublic(&threadHandle, THREAD_TERMINATE, threadId)))
- {
- status = NtTerminateThread(threadHandle, STATUS_SUCCESS);
- NtClose(threadHandle);
- }
- }
- else if (PhEqualString2(PhStartupParameters.CommandAction, L"suspend", TRUE))
- {
- if (NT_SUCCESS(status = PhOpenThreadPublic(&threadHandle, THREAD_SUSPEND_RESUME, threadId)))
- {
- status = NtSuspendThread(threadHandle, NULL);
- NtClose(threadHandle);
- }
- }
- else if (PhEqualString2(PhStartupParameters.CommandAction, L"resume", TRUE))
- {
- if (NT_SUCCESS(status = PhOpenThreadPublic(&threadHandle, THREAD_SUSPEND_RESUME, threadId)))
- {
- status = NtResumeThread(threadHandle, NULL);
- NtClose(threadHandle);
- }
- }
- }
-
- return status;
-}
-
-typedef struct _GET_DLL_BASE_REMOTE_CONTEXT
-{
- PH_STRINGREF BaseDllName;
- PVOID DllBase;
-} GET_DLL_BASE_REMOTE_CONTEXT, *PGET_DLL_BASE_REMOTE_CONTEXT;
-
-static BOOLEAN PhpGetDllBaseRemoteCallback(
- _In_ PLDR_DATA_TABLE_ENTRY Module,
- _In_opt_ PVOID Context
- )
-{
- PGET_DLL_BASE_REMOTE_CONTEXT context = Context;
- PH_STRINGREF baseDllName;
-
- PhUnicodeStringToStringRef(&Module->BaseDllName, &baseDllName);
-
- if (PhEqualStringRef(&baseDllName, &context->BaseDllName, TRUE))
- {
- context->DllBase = Module->DllBase;
- return FALSE;
- }
-
- return TRUE;
-}
-
-NTSTATUS PhpGetDllBaseRemote(
- _In_ HANDLE ProcessHandle,
- _In_ PPH_STRINGREF BaseDllName,
- _Out_ PVOID *DllBase
- )
-{
- NTSTATUS status;
- GET_DLL_BASE_REMOTE_CONTEXT context;
-#ifdef _WIN64
- BOOLEAN isWow64 = FALSE;
-#endif
-
- context.BaseDllName = *BaseDllName;
- context.DllBase = NULL;
-
-#ifdef _WIN64
- PhGetProcessIsWow64(ProcessHandle, &isWow64);
-
- if (isWow64)
- status = PhEnumProcessModules32(ProcessHandle, PhpGetDllBaseRemoteCallback, &context);
- if (!context.DllBase)
-#endif
- status = PhEnumProcessModules(ProcessHandle, PhpGetDllBaseRemoteCallback, &context);
-
- if (NT_SUCCESS(status))
- *DllBase = context.DllBase;
-
- return status;
-}
+/*
+ * Process Hacker -
+ * command line action mode
+ *
+ * Copyright (C) 2010-2012 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 .
+ */
+
+#include
+
+#include
+
+NTSTATUS PhpGetDllBaseRemote(
+ _In_ HANDLE ProcessHandle,
+ _In_ PPH_STRINGREF BaseDllName,
+ _Out_ PVOID *DllBase
+ );
+
+static HWND CommandModeWindowHandle;
+
+#define PH_COMMAND_OPTION_HWND 1
+
+BOOLEAN NTAPI PhpCommandModeOptionCallback(
+ _In_opt_ PPH_COMMAND_LINE_OPTION Option,
+ _In_opt_ PPH_STRING Value,
+ _In_opt_ PVOID Context
+ )
+{
+ ULONG64 integer;
+
+ if (Option)
+ {
+ switch (Option->Id)
+ {
+ case PH_COMMAND_OPTION_HWND:
+ if (PhStringToInteger64(&Value->sr, 10, &integer))
+ CommandModeWindowHandle = (HWND)integer;
+ break;
+ }
+ }
+
+ return TRUE;
+}
+
+NTSTATUS PhCommandModeStart(
+ VOID
+ )
+{
+ static PH_COMMAND_LINE_OPTION options[] =
+ {
+ { PH_COMMAND_OPTION_HWND, L"hwnd", MandatoryArgumentType }
+ };
+ NTSTATUS status;
+ PPH_STRING commandLine;
+
+ if (!NT_SUCCESS(status = PhGetProcessCommandLine(NtCurrentProcess(), &commandLine)))
+ return status;
+
+ PhParseCommandLine(
+ &commandLine->sr,
+ options,
+ RTL_NUMBER_OF(options),
+ PH_COMMAND_LINE_IGNORE_UNKNOWN_OPTIONS,
+ PhpCommandModeOptionCallback,
+ NULL
+ );
+ PhDereferenceObject(commandLine);
+
+ if (PhEqualString2(PhStartupParameters.CommandType, L"process", TRUE))
+ {
+ SIZE_T i;
+ SIZE_T processIdLength;
+ HANDLE processId;
+ HANDLE processHandle;
+
+ if (!PhStartupParameters.CommandObject)
+ return STATUS_INVALID_PARAMETER;
+
+ processIdLength = PhStartupParameters.CommandObject->Length / sizeof(WCHAR);
+
+ for (i = 0; i < processIdLength; i++)
+ {
+ if (!PhIsDigitCharacter(PhStartupParameters.CommandObject->Buffer[i]))
+ break;
+ }
+
+ if (i == processIdLength)
+ {
+ ULONG64 processId64;
+
+ if (!PhStringToInteger64(&PhStartupParameters.CommandObject->sr, 10, &processId64))
+ return STATUS_INVALID_PARAMETER;
+
+ processId = (HANDLE)processId64;
+ }
+ else
+ {
+ PVOID processes;
+ PSYSTEM_PROCESS_INFORMATION process;
+
+ if (!NT_SUCCESS(status = PhEnumProcesses(&processes)))
+ return status;
+
+ if (!(process = PhFindProcessInformationByImageName(processes, &PhStartupParameters.CommandObject->sr)))
+ {
+ PhFree(processes);
+ return STATUS_NOT_FOUND;
+ }
+
+ processId = process->UniqueProcessId;
+ PhFree(processes);
+ }
+
+ if (PhEqualString2(PhStartupParameters.CommandAction, L"terminate", TRUE))
+ {
+ if (NT_SUCCESS(status = PhOpenProcessPublic(&processHandle, PROCESS_TERMINATE, processId)))
+ {
+ status = NtTerminateProcess(processHandle, STATUS_SUCCESS);
+ NtClose(processHandle);
+ }
+ }
+ else if (PhEqualString2(PhStartupParameters.CommandAction, L"suspend", TRUE))
+ {
+ if (NT_SUCCESS(status = PhOpenProcessPublic(&processHandle, PROCESS_SUSPEND_RESUME, processId)))
+ {
+ status = NtSuspendProcess(processHandle);
+ NtClose(processHandle);
+ }
+ }
+ else if (PhEqualString2(PhStartupParameters.CommandAction, L"resume", TRUE))
+ {
+ if (NT_SUCCESS(status = PhOpenProcessPublic(&processHandle, PROCESS_SUSPEND_RESUME, processId)))
+ {
+ status = NtResumeProcess(processHandle);
+ NtClose(processHandle);
+ }
+ }
+ else if (PhEqualString2(PhStartupParameters.CommandAction, L"priority", TRUE))
+ {
+ UCHAR priority;
+
+ if (!PhStartupParameters.CommandValue)
+ return STATUS_INVALID_PARAMETER;
+
+ if (PhEqualString2(PhStartupParameters.CommandValue, L"idle", TRUE))
+ priority = PROCESS_PRIORITY_CLASS_IDLE;
+ else if (PhEqualString2(PhStartupParameters.CommandValue, L"normal", TRUE))
+ priority = PROCESS_PRIORITY_CLASS_NORMAL;
+ else if (PhEqualString2(PhStartupParameters.CommandValue, L"high", TRUE))
+ priority = PROCESS_PRIORITY_CLASS_HIGH;
+ else if (PhEqualString2(PhStartupParameters.CommandValue, L"realtime", TRUE))
+ priority = PROCESS_PRIORITY_CLASS_REALTIME;
+ else if (PhEqualString2(PhStartupParameters.CommandValue, L"abovenormal", TRUE))
+ priority = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL;
+ else if (PhEqualString2(PhStartupParameters.CommandValue, L"belownormal", TRUE))
+ priority = PROCESS_PRIORITY_CLASS_BELOW_NORMAL;
+ else
+ return STATUS_INVALID_PARAMETER;
+
+ if (NT_SUCCESS(status = PhOpenProcessPublic(&processHandle, PROCESS_SET_INFORMATION, processId)))
+ {
+ PROCESS_PRIORITY_CLASS priorityClass;
+
+ priorityClass.Foreground = FALSE;
+ priorityClass.PriorityClass = priority;
+
+ status = PhSetProcessPriority(processHandle, priorityClass);
+
+ NtClose(processHandle);
+ }
+ }
+ else if (PhEqualString2(PhStartupParameters.CommandAction, L"iopriority", TRUE))
+ {
+ ULONG ioPriority;
+
+ if (!PhStartupParameters.CommandValue)
+ return STATUS_INVALID_PARAMETER;
+
+ if (PhEqualString2(PhStartupParameters.CommandValue, L"verylow", TRUE))
+ ioPriority = 0;
+ else if (PhEqualString2(PhStartupParameters.CommandValue, L"low", TRUE))
+ ioPriority = 1;
+ else if (PhEqualString2(PhStartupParameters.CommandValue, L"normal", TRUE))
+ ioPriority = 2;
+ else if (PhEqualString2(PhStartupParameters.CommandValue, L"high", TRUE))
+ ioPriority = 3;
+ else
+ return STATUS_INVALID_PARAMETER;
+
+ if (NT_SUCCESS(status = PhOpenProcessPublic(&processHandle, PROCESS_SET_INFORMATION, processId)))
+ {
+ status = PhSetProcessIoPriority(processHandle, ioPriority);
+ NtClose(processHandle);
+ }
+ }
+ else if (PhEqualString2(PhStartupParameters.CommandAction, L"pagepriority", TRUE))
+ {
+ ULONG64 pagePriority64;
+ ULONG pagePriority;
+
+ if (!PhStartupParameters.CommandValue)
+ return STATUS_INVALID_PARAMETER;
+
+ PhStringToInteger64(&PhStartupParameters.CommandValue->sr, 10, &pagePriority64);
+ pagePriority = (ULONG)pagePriority64;
+
+ if (NT_SUCCESS(status = PhOpenProcessPublic(&processHandle, PROCESS_SET_INFORMATION, processId)))
+ {
+ status = PhSetProcessPagePriority(processHandle, pagePriority);
+
+ NtClose(processHandle);
+ }
+ }
+ }
+ else if (PhEqualString2(PhStartupParameters.CommandType, L"service", TRUE))
+ {
+ SC_HANDLE serviceHandle;
+ SERVICE_STATUS serviceStatus;
+
+ if (!PhStartupParameters.CommandObject)
+ return STATUS_INVALID_PARAMETER;
+
+ if (PhEqualString2(PhStartupParameters.CommandAction, L"start", TRUE))
+ {
+ if (!(serviceHandle = PhOpenService(
+ PhStartupParameters.CommandObject->Buffer,
+ SERVICE_START
+ )))
+ return PhGetLastWin32ErrorAsNtStatus();
+
+ if (!StartService(serviceHandle, 0, NULL))
+ status = PhGetLastWin32ErrorAsNtStatus();
+
+ CloseServiceHandle(serviceHandle);
+ }
+ else if (PhEqualString2(PhStartupParameters.CommandAction, L"continue", TRUE))
+ {
+ if (!(serviceHandle = PhOpenService(
+ PhStartupParameters.CommandObject->Buffer,
+ SERVICE_PAUSE_CONTINUE
+ )))
+ return PhGetLastWin32ErrorAsNtStatus();
+
+ if (!ControlService(serviceHandle, SERVICE_CONTROL_CONTINUE, &serviceStatus))
+ status = PhGetLastWin32ErrorAsNtStatus();
+
+ CloseServiceHandle(serviceHandle);
+ }
+ else if (PhEqualString2(PhStartupParameters.CommandAction, L"pause", TRUE))
+ {
+ if (!(serviceHandle = PhOpenService(
+ PhStartupParameters.CommandObject->Buffer,
+ SERVICE_PAUSE_CONTINUE
+ )))
+ return PhGetLastWin32ErrorAsNtStatus();
+
+ if (!ControlService(serviceHandle, SERVICE_CONTROL_PAUSE, &serviceStatus))
+ status = PhGetLastWin32ErrorAsNtStatus();
+
+ CloseServiceHandle(serviceHandle);
+ }
+ else if (PhEqualString2(PhStartupParameters.CommandAction, L"stop", TRUE))
+ {
+ if (!(serviceHandle = PhOpenService(
+ PhStartupParameters.CommandObject->Buffer,
+ SERVICE_STOP
+ )))
+ return PhGetLastWin32ErrorAsNtStatus();
+
+ if (!ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus))
+ status = PhGetLastWin32ErrorAsNtStatus();
+
+ CloseServiceHandle(serviceHandle);
+ }
+ else if (PhEqualString2(PhStartupParameters.CommandAction, L"delete", TRUE))
+ {
+ if (!(serviceHandle = PhOpenService(
+ PhStartupParameters.CommandObject->Buffer,
+ DELETE
+ )))
+ return PhGetLastWin32ErrorAsNtStatus();
+
+ if (!DeleteService(serviceHandle))
+ status = PhGetLastWin32ErrorAsNtStatus();
+
+ CloseServiceHandle(serviceHandle);
+ }
+ }
+ else if (PhEqualString2(PhStartupParameters.CommandType, L"thread", TRUE))
+ {
+ ULONG64 threadId64;
+ HANDLE threadId;
+ HANDLE threadHandle;
+
+ if (!PhStartupParameters.CommandObject)
+ return STATUS_INVALID_PARAMETER;
+
+ if (!PhStringToInteger64(&PhStartupParameters.CommandObject->sr, 10, &threadId64))
+ return STATUS_INVALID_PARAMETER;
+
+ threadId = (HANDLE)threadId64;
+
+ if (PhEqualString2(PhStartupParameters.CommandAction, L"terminate", TRUE))
+ {
+ if (NT_SUCCESS(status = PhOpenThreadPublic(&threadHandle, THREAD_TERMINATE, threadId)))
+ {
+ status = NtTerminateThread(threadHandle, STATUS_SUCCESS);
+ NtClose(threadHandle);
+ }
+ }
+ else if (PhEqualString2(PhStartupParameters.CommandAction, L"suspend", TRUE))
+ {
+ if (NT_SUCCESS(status = PhOpenThreadPublic(&threadHandle, THREAD_SUSPEND_RESUME, threadId)))
+ {
+ status = NtSuspendThread(threadHandle, NULL);
+ NtClose(threadHandle);
+ }
+ }
+ else if (PhEqualString2(PhStartupParameters.CommandAction, L"resume", TRUE))
+ {
+ if (NT_SUCCESS(status = PhOpenThreadPublic(&threadHandle, THREAD_SUSPEND_RESUME, threadId)))
+ {
+ status = NtResumeThread(threadHandle, NULL);
+ NtClose(threadHandle);
+ }
+ }
+ }
+
+ return status;
+}
+
+typedef struct _GET_DLL_BASE_REMOTE_CONTEXT
+{
+ PH_STRINGREF BaseDllName;
+ PVOID DllBase;
+} GET_DLL_BASE_REMOTE_CONTEXT, *PGET_DLL_BASE_REMOTE_CONTEXT;
+
+static BOOLEAN PhpGetDllBaseRemoteCallback(
+ _In_ PLDR_DATA_TABLE_ENTRY Module,
+ _In_opt_ PVOID Context
+ )
+{
+ PGET_DLL_BASE_REMOTE_CONTEXT context = Context;
+ PH_STRINGREF baseDllName;
+
+ PhUnicodeStringToStringRef(&Module->BaseDllName, &baseDllName);
+
+ if (PhEqualStringRef(&baseDllName, &context->BaseDllName, TRUE))
+ {
+ context->DllBase = Module->DllBase;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+NTSTATUS PhpGetDllBaseRemote(
+ _In_ HANDLE ProcessHandle,
+ _In_ PPH_STRINGREF BaseDllName,
+ _Out_ PVOID *DllBase
+ )
+{
+ NTSTATUS status;
+ GET_DLL_BASE_REMOTE_CONTEXT context;
+#ifdef _WIN64
+ BOOLEAN isWow64 = FALSE;
+#endif
+
+ context.BaseDllName = *BaseDllName;
+ context.DllBase = NULL;
+
+#ifdef _WIN64
+ PhGetProcessIsWow64(ProcessHandle, &isWow64);
+
+ if (isWow64)
+ status = PhEnumProcessModules32(ProcessHandle, PhpGetDllBaseRemoteCallback, &context);
+ if (!context.DllBase)
+#endif
+ status = PhEnumProcessModules(ProcessHandle, PhpGetDllBaseRemoteCallback, &context);
+
+ if (NT_SUCCESS(status))
+ *DllBase = context.DllBase;
+
+ return status;
+}
diff --git a/ProcessHacker/colmgr.c b/ProcessHacker/colmgr.c
index ba95bbcad89f..bfbbd792dc4f 100644
--- a/ProcessHacker/colmgr.c
+++ b/ProcessHacker/colmgr.c
@@ -1,710 +1,710 @@
-/*
- * Process Hacker -
- * tree new column manager
- *
- * Copyright (C) 2011-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 .
- */
-
-#include
-#include
-
-#include
-#include
-
-typedef struct _PH_CM_SORT_CONTEXT
-{
- PPH_PLUGIN_TREENEW_SORT_FUNCTION SortFunction;
- ULONG SubId;
- PVOID Context;
- PPH_CM_POST_SORT_FUNCTION PostSortFunction;
- PH_SORT_ORDER SortOrder;
-} PH_CM_SORT_CONTEXT, *PPH_CM_SORT_CONTEXT;
-
-VOID PhCmInitializeManager(
- _Out_ PPH_CM_MANAGER Manager,
- _In_ HWND Handle,
- _In_ ULONG MinId,
- _In_ PPH_CM_POST_SORT_FUNCTION PostSortFunction
- )
-{
- Manager->Handle = Handle;
- Manager->MinId = MinId;
- Manager->NextId = MinId;
- Manager->PostSortFunction = PostSortFunction;
- InitializeListHead(&Manager->ColumnListHead);
- Manager->NotifyList = NULL;
-}
-
-VOID PhCmDeleteManager(
- _In_ PPH_CM_MANAGER Manager
- )
-{
- PLIST_ENTRY listEntry;
- PPH_CM_COLUMN column;
-
- listEntry = Manager->ColumnListHead.Flink;
-
- while (listEntry != &Manager->ColumnListHead)
- {
- column = CONTAINING_RECORD(listEntry, PH_CM_COLUMN, ListEntry);
- listEntry = listEntry->Flink;
-
- PhFree(column);
- }
-
- if (Manager->NotifyList)
- PhDereferenceObject(Manager->NotifyList);
-}
-
-PPH_CM_COLUMN PhCmCreateColumn(
- _Inout_ PPH_CM_MANAGER Manager,
- _In_ PPH_TREENEW_COLUMN Column,
- _In_ struct _PH_PLUGIN *Plugin,
- _In_ ULONG SubId,
- _In_opt_ PVOID Context,
- _In_ PVOID SortFunction
- )
-{
- PPH_CM_COLUMN column;
- PH_TREENEW_COLUMN tnColumn;
-
- column = PhAllocate(sizeof(PH_CM_COLUMN));
- memset(column, 0, sizeof(PH_CM_COLUMN));
- column->Id = Manager->NextId++;
- column->Plugin = Plugin;
- column->SubId = SubId;
- column->Context = Context;
- column->SortFunction = SortFunction;
- InsertTailList(&Manager->ColumnListHead, &column->ListEntry);
-
- memset(&tnColumn, 0, sizeof(PH_TREENEW_COLUMN));
- tnColumn.Id = column->Id;
- tnColumn.Context = column;
- tnColumn.Visible = Column->Visible;
- tnColumn.CustomDraw = Column->CustomDraw;
- tnColumn.SortDescending = Column->SortDescending;
- tnColumn.Text = Column->Text;
- tnColumn.Width = Column->Width;
- tnColumn.Alignment = Column->Alignment;
- tnColumn.DisplayIndex = Column->Visible ? Column->DisplayIndex : -1;
- tnColumn.TextFlags = Column->TextFlags;
- TreeNew_AddColumn(Manager->Handle, &tnColumn);
-
- return column;
-}
-
-PPH_CM_COLUMN PhCmFindColumn(
- _In_ PPH_CM_MANAGER Manager,
- _In_ PPH_STRINGREF PluginName,
- _In_ ULONG SubId
- )
-{
- PLIST_ENTRY listEntry;
- PPH_CM_COLUMN column;
-
- listEntry = Manager->ColumnListHead.Flink;
-
- while (listEntry != &Manager->ColumnListHead)
- {
- column = CONTAINING_RECORD(listEntry, PH_CM_COLUMN, ListEntry);
-
- if (column->SubId == SubId && PhEqualStringRef(PluginName, &column->Plugin->AppContext.AppName, FALSE))
- return column;
-
- listEntry = listEntry->Flink;
- }
-
- return NULL;
-}
-
-VOID PhCmSetNotifyPlugin(
- _In_ PPH_CM_MANAGER Manager,
- _In_ struct _PH_PLUGIN *Plugin
- )
-{
- if (!Manager->NotifyList)
- {
- Manager->NotifyList = PhCreateList(8);
- }
- else
- {
- if (PhFindItemList(Manager->NotifyList, Plugin) != -1)
- return;
- }
-
- PhAddItemList(Manager->NotifyList, Plugin);
-}
-
-BOOLEAN PhCmForwardMessage(
- _In_ HWND hwnd,
- _In_ PH_TREENEW_MESSAGE Message,
- _In_opt_ PVOID Parameter1,
- _In_opt_ PVOID Parameter2,
- _In_ PPH_CM_MANAGER Manager
- )
-{
- PH_PLUGIN_TREENEW_MESSAGE pluginMessage;
- PPH_PLUGIN plugin;
-
- if (Message == TreeNewDestroying)
- return FALSE;
-
- switch (Message)
- {
- case TreeNewGetCellText:
- {
- PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1;
- PH_TREENEW_COLUMN tnColumn;
- PPH_CM_COLUMN column;
-
- if (getCellText->Id < Manager->MinId)
- return FALSE;
-
- if (!TreeNew_GetColumn(hwnd, getCellText->Id, &tnColumn))
- return FALSE;
-
- column = tnColumn.Context;
- pluginMessage.SubId = column->SubId;
- pluginMessage.Context = column->Context;
- plugin = column->Plugin;
- }
- break;
- case TreeNewCustomDraw:
- {
- PPH_TREENEW_CUSTOM_DRAW customDraw = Parameter1;
- PPH_CM_COLUMN column;
-
- if (customDraw->Column->Id < Manager->MinId)
- return FALSE;
-
- column = customDraw->Column->Context;
- pluginMessage.SubId = column->SubId;
- pluginMessage.Context = column->Context;
- plugin = column->Plugin;
- }
- break;
- case TreeNewColumnResized:
- {
- PPH_TREENEW_COLUMN tlColumn = Parameter1;
- PPH_CM_COLUMN column;
-
- if (tlColumn->Id < Manager->MinId)
- return FALSE;
-
- column = tlColumn->Context;
- pluginMessage.SubId = column->SubId;
- pluginMessage.Context = column->Context;
- plugin = column->Plugin;
- }
- break;
- default:
- {
- // Some plugins want to be notified about all messages.
- if (Manager->NotifyList)
- {
- ULONG i;
-
- for (i = 0; i < Manager->NotifyList->Count; i++)
- {
- plugin = Manager->NotifyList->Items[i];
-
- pluginMessage.TreeNewHandle = hwnd;
- pluginMessage.Message = Message;
- pluginMessage.Parameter1 = Parameter1;
- pluginMessage.Parameter2 = Parameter2;
- pluginMessage.SubId = 0;
- pluginMessage.Context = NULL;
-
- PhInvokeCallback(PhGetPluginCallback(plugin, PluginCallbackTreeNewMessage), &pluginMessage);
- }
- }
- }
- return FALSE;
- }
-
- pluginMessage.TreeNewHandle = hwnd;
- pluginMessage.Message = Message;
- pluginMessage.Parameter1 = Parameter1;
- pluginMessage.Parameter2 = Parameter2;
-
- PhInvokeCallback(PhGetPluginCallback(plugin, PluginCallbackTreeNewMessage), &pluginMessage);
-
- return TRUE;
-}
-
-static int __cdecl PhCmpSortFunction(
- _In_ void *context,
- _In_ const void *elem1,
- _In_ const void *elem2
- )
-{
- PPH_CM_SORT_CONTEXT sortContext = context;
- PVOID node1 = *(PVOID *)elem1;
- PVOID node2 = *(PVOID *)elem2;
- LONG result;
-
- result = sortContext->SortFunction(node1, node2, sortContext->SubId, sortContext->Context);
-
- return sortContext->PostSortFunction(result, node1, node2, sortContext->SortOrder);
-}
-
-BOOLEAN PhCmForwardSort(
- _In_ PPH_TREENEW_NODE *Nodes,
- _In_ ULONG NumberOfNodes,
- _In_ ULONG SortColumn,
- _In_ PH_SORT_ORDER SortOrder,
- _In_ PPH_CM_MANAGER Manager
- )
-{
- PH_TREENEW_COLUMN tnColumn;
- PPH_CM_COLUMN column;
- PH_CM_SORT_CONTEXT sortContext;
-
- if (SortColumn < Manager->MinId)
- return FALSE;
-
- if (!TreeNew_GetColumn(Manager->Handle, SortColumn, &tnColumn))
- return TRUE;
-
- column = tnColumn.Context;
-
- if (!column->SortFunction)
- return TRUE;
-
- sortContext.SortFunction = column->SortFunction;
- sortContext.SubId = column->SubId;
- sortContext.Context = column->Context;
- sortContext.PostSortFunction = Manager->PostSortFunction;
- sortContext.SortOrder = SortOrder;
- qsort_s(Nodes, NumberOfNodes, sizeof(PVOID), PhCmpSortFunction, &sortContext);
-
- return TRUE;
-}
-
-BOOLEAN PhCmLoadSettings(
- _In_ HWND TreeNewHandle,
- _In_ PPH_STRINGREF Settings
- )
-{
- return PhCmLoadSettingsEx(TreeNewHandle, NULL, 0, Settings, NULL);
-}
-
-BOOLEAN PhCmLoadSettingsEx(
- _In_ HWND TreeNewHandle,
- _In_opt_ PPH_CM_MANAGER Manager,
- _In_ ULONG Flags,
- _In_ PPH_STRINGREF Settings,
- _In_opt_ PPH_STRINGREF SortSettings
- )
-{
- BOOLEAN result = FALSE;
- PH_STRINGREF scalePart;
- PH_STRINGREF columnPart;
- PH_STRINGREF remainingColumnPart;
- PH_STRINGREF valuePart;
- PH_STRINGREF subPart;
- ULONG64 integer;
- ULONG scale;
- ULONG total;
- BOOLEAN hasFixedColumn;
- ULONG count;
- ULONG i;
- PPH_HASHTABLE columnHashtable;
- PH_HASHTABLE_ENUM_CONTEXT enumContext;
- PPH_KEY_VALUE_PAIR pair;
- LONG orderArray[PH_CM_ORDER_LIMIT];
- LONG maxOrder;
-
- if (Settings->Length != 0)
- {
- columnHashtable = PhCreateSimpleHashtable(20);
-
- remainingColumnPart = *Settings;
-
- if (remainingColumnPart.Length != 0 && remainingColumnPart.Buffer[0] == '@')
- {
- PhSkipStringRef(&remainingColumnPart, sizeof(WCHAR));
- PhSplitStringRefAtChar(&remainingColumnPart, '|', &scalePart, &remainingColumnPart);
-
- if (scalePart.Length == 0 || !PhStringToInteger64(&scalePart, 10, &integer))
- goto CleanupExit;
-
- scale = (ULONG)integer;
- }
- else
- {
- scale = PhGlobalDpi;
- }
-
- while (remainingColumnPart.Length != 0)
- {
- PPH_TREENEW_COLUMN column;
- ULONG id;
- ULONG displayIndex;
- ULONG width;
-
- PhSplitStringRefAtChar(&remainingColumnPart, '|', &columnPart, &remainingColumnPart);
-
- if (columnPart.Length != 0)
- {
- // Id
-
- PhSplitStringRefAtChar(&columnPart, ',', &valuePart, &columnPart);
-
- if (valuePart.Length == 0)
- goto CleanupExit;
-
- if (valuePart.Buffer[0] == '+')
- {
- PH_STRINGREF pluginName;
- ULONG subId;
- PPH_CM_COLUMN cmColumn;
-
- // This is a plugin-owned column.
-
- if (!Manager)
- continue;
- if (!PhEmParseCompoundId(&valuePart, &pluginName, &subId))
- continue;
-
- cmColumn = PhCmFindColumn(Manager, &pluginName, subId);
-
- if (!cmColumn)
- continue; // can't find the column, skip this part
-
- id = cmColumn->Id;
- }
- else
- {
- if (!PhStringToInteger64(&valuePart, 10, &integer))
- goto CleanupExit;
-
- id = (ULONG)integer;
- }
-
- // Display Index
-
- PhSplitStringRefAtChar(&columnPart, ',', &valuePart, &columnPart);
-
- if (!(Flags & PH_CM_COLUMN_WIDTHS_ONLY))
- {
- if (valuePart.Length == 0 || !PhStringToInteger64(&valuePart, 10, &integer))
- goto CleanupExit;
-
- displayIndex = (ULONG)integer;
- }
- else
- {
- if (valuePart.Length != 0)
- goto CleanupExit;
-
- displayIndex = -1;
- }
-
- // Width
-
- if (columnPart.Length == 0 || !PhStringToInteger64(&columnPart, 10, &integer))
- goto CleanupExit;
-
- width = (ULONG)integer;
-
- if (scale != PhGlobalDpi && scale != 0)
- width = PhMultiplyDivide(width, PhGlobalDpi, scale);
-
- column = PhAllocate(sizeof(PH_TREENEW_COLUMN));
- column->Id = id;
- column->DisplayIndex = displayIndex;
- column->Width = width;
- PhAddItemSimpleHashtable(columnHashtable, UlongToPtr(column->Id), column);
- }
- }
-
- TreeNew_SetRedraw(TreeNewHandle, FALSE);
-
- // Set visibility and width.
-
- i = 0;
- count = 0;
- total = TreeNew_GetColumnCount(TreeNewHandle);
- hasFixedColumn = !!TreeNew_GetFixedColumn(TreeNewHandle);
- memset(orderArray, 0, sizeof(orderArray));
- maxOrder = 0;
-
- while (count < total)
- {
- PH_TREENEW_COLUMN setColumn;
- PPH_TREENEW_COLUMN *columnPtr;
-
- if (TreeNew_GetColumn(TreeNewHandle, i, &setColumn))
- {
- columnPtr = (PPH_TREENEW_COLUMN *)PhFindItemSimpleHashtable(columnHashtable, UlongToPtr(i));
-
- if (!(Flags & PH_CM_COLUMN_WIDTHS_ONLY))
- {
- if (columnPtr)
- {
- setColumn.Visible = TRUE;
- setColumn.Width = (*columnPtr)->Width;
- TreeNew_SetColumn(TreeNewHandle, TN_COLUMN_FLAG_VISIBLE | TN_COLUMN_WIDTH, &setColumn);
-
- if (!setColumn.Fixed)
- {
- // For compatibility reasons, normal columns have their display indicies stored
- // one higher than usual (so they start from 1, not 0). Fix that here.
- if (hasFixedColumn && (*columnPtr)->DisplayIndex != 0)
- (*columnPtr)->DisplayIndex--;
-
- if ((*columnPtr)->DisplayIndex < PH_CM_ORDER_LIMIT)
- {
- orderArray[(*columnPtr)->DisplayIndex] = i;
-
- if ((ULONG)maxOrder < (*columnPtr)->DisplayIndex + 1)
- maxOrder = (*columnPtr)->DisplayIndex + 1;
- }
- }
- }
- else if (!setColumn.Fixed) // never hide the fixed column
- {
- setColumn.Visible = FALSE;
- TreeNew_SetColumn(TreeNewHandle, TN_COLUMN_FLAG_VISIBLE, &setColumn);
- }
- }
- else
- {
- if (columnPtr)
- {
- setColumn.Width = (*columnPtr)->Width;
- TreeNew_SetColumn(TreeNewHandle, TN_COLUMN_WIDTH, &setColumn);
- }
- }
-
- count++;
- }
-
- i++;
- }
-
- if (!(Flags & PH_CM_COLUMN_WIDTHS_ONLY))
- {
- // Set the order array.
- TreeNew_SetColumnOrderArray(TreeNewHandle, maxOrder, orderArray);
- }
-
- TreeNew_SetRedraw(TreeNewHandle, TRUE);
-
- result = TRUE;
-
-CleanupExit:
- PhBeginEnumHashtable(columnHashtable, &enumContext);
-
- while (pair = PhNextEnumHashtable(&enumContext))
- PhFree(pair->Value);
-
- PhDereferenceObject(columnHashtable);
- }
-
- // Load sort settings.
-
- if (SortSettings && SortSettings->Length != 0)
- {
- PhSplitStringRefAtChar(SortSettings, ',', &valuePart, &subPart);
-
- if (valuePart.Length != 0 && subPart.Length != 0)
- {
- ULONG sortColumn;
- PH_SORT_ORDER sortOrder;
-
- sortColumn = -1;
-
- if (valuePart.Buffer[0] == '+')
- {
- PH_STRINGREF pluginName;
- ULONG subId;
- PPH_CM_COLUMN cmColumn;
-
- if (
- Manager &&
- PhEmParseCompoundId(&valuePart, &pluginName, &subId) &&
- (cmColumn = PhCmFindColumn(Manager, &pluginName, subId))
- )
- {
- sortColumn = cmColumn->Id;
- }
- }
- else
- {
- PhStringToInteger64(&valuePart, 10, &integer);
- sortColumn = (ULONG)integer;
- }
-
- PhStringToInteger64(&subPart, 10, &integer);
- sortOrder = (PH_SORT_ORDER)integer;
-
- if (sortColumn != -1 && sortOrder <= DescendingSortOrder)
- {
- TreeNew_SetSort(TreeNewHandle, sortColumn, sortOrder);
- }
- }
- }
-
- return result;
-}
-
-PPH_STRING PhCmSaveSettings(
- _In_ HWND TreeNewHandle
- )
-{
- return PhCmSaveSettingsEx(TreeNewHandle, NULL, 0, NULL);
-}
-
-PPH_STRING PhCmSaveSettingsEx(
- _In_ HWND TreeNewHandle,
- _In_opt_ PPH_CM_MANAGER Manager,
- _In_ ULONG Flags,
- _Out_opt_ PPH_STRING *SortSettings
- )
-{
- PH_STRING_BUILDER stringBuilder;
- ULONG i = 0;
- ULONG count = 0;
- ULONG total;
- ULONG increment;
- PH_TREENEW_COLUMN column;
-
- total = TreeNew_GetColumnCount(TreeNewHandle);
-
- if (TreeNew_GetFixedColumn(TreeNewHandle))
- increment = 1; // the first normal column should have a display index that starts with 1, for compatibility
- else
- increment = 0;
-
- PhInitializeStringBuilder(&stringBuilder, 100);
-
- PhAppendFormatStringBuilder(&stringBuilder, L"@%u|", PhGlobalDpi);
-
- while (count < total)
- {
- if (TreeNew_GetColumn(TreeNewHandle, i, &column))
- {
- if (!(Flags & PH_CM_COLUMN_WIDTHS_ONLY))
- {
- if (column.Visible)
- {
- if (!Manager || i < Manager->MinId)
- {
- PhAppendFormatStringBuilder(
- &stringBuilder,
- L"%u,%u,%u|",
- i,
- column.Fixed ? 0 : column.DisplayIndex + increment,
- column.Width
- );
- }
- else
- {
- PPH_CM_COLUMN cmColumn;
-
- cmColumn = column.Context;
- PhAppendFormatStringBuilder(
- &stringBuilder,
- L"+%s+%u,%u,%u|",
- cmColumn->Plugin->Name.Buffer,
- cmColumn->SubId,
- column.DisplayIndex + increment,
- column.Width
- );
- }
- }
- }
- else
- {
- if (!Manager || i < Manager->MinId)
- {
- PhAppendFormatStringBuilder(
- &stringBuilder,
- L"%u,,%u|",
- i,
- column.Width
- );
- }
- else
- {
- PPH_CM_COLUMN cmColumn;
-
- cmColumn = column.Context;
- PhAppendFormatStringBuilder(
- &stringBuilder,
- L"+%s+%u,,%u|",
- cmColumn->Plugin->Name.Buffer,
- cmColumn->SubId,
- column.Width
- );
- }
- }
-
- count++;
- }
-
- i++;
- }
-
- if (stringBuilder.String->Length != 0)
- PhRemoveEndStringBuilder(&stringBuilder, 1);
-
- if (SortSettings)
- {
- ULONG sortColumn;
- PH_SORT_ORDER sortOrder;
-
- if (TreeNew_GetSort(TreeNewHandle, &sortColumn, &sortOrder))
- {
- if (sortOrder != NoSortOrder)
- {
- if (!Manager || sortColumn < Manager->MinId)
- {
- *SortSettings = PhFormatString(L"%u,%u", sortColumn, sortOrder);
- }
- else
- {
- PH_TREENEW_COLUMN column;
- PPH_CM_COLUMN cmColumn;
-
- if (TreeNew_GetColumn(TreeNewHandle, sortColumn, &column))
- {
- cmColumn = column.Context;
- *SortSettings = PhFormatString(L"+%s+%u,%u", cmColumn->Plugin->Name.Buffer, cmColumn->SubId, sortOrder);
- }
- else
- {
- *SortSettings = PhReferenceEmptyString();
- }
- }
- }
- else
- {
- *SortSettings = PhCreateString(L"0,0");
- }
- }
- else
- {
- *SortSettings = PhReferenceEmptyString();
- }
- }
-
- return PhFinalStringBuilderString(&stringBuilder);
-}
+/*
+ * Process Hacker -
+ * tree new column manager
+ *
+ * Copyright (C) 2011-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 .
+ */
+
+#include
+#include
+
+#include
+#include
+
+typedef struct _PH_CM_SORT_CONTEXT
+{
+ PPH_PLUGIN_TREENEW_SORT_FUNCTION SortFunction;
+ ULONG SubId;
+ PVOID Context;
+ PPH_CM_POST_SORT_FUNCTION PostSortFunction;
+ PH_SORT_ORDER SortOrder;
+} PH_CM_SORT_CONTEXT, *PPH_CM_SORT_CONTEXT;
+
+VOID PhCmInitializeManager(
+ _Out_ PPH_CM_MANAGER Manager,
+ _In_ HWND Handle,
+ _In_ ULONG MinId,
+ _In_ PPH_CM_POST_SORT_FUNCTION PostSortFunction
+ )
+{
+ Manager->Handle = Handle;
+ Manager->MinId = MinId;
+ Manager->NextId = MinId;
+ Manager->PostSortFunction = PostSortFunction;
+ InitializeListHead(&Manager->ColumnListHead);
+ Manager->NotifyList = NULL;
+}
+
+VOID PhCmDeleteManager(
+ _In_ PPH_CM_MANAGER Manager
+ )
+{
+ PLIST_ENTRY listEntry;
+ PPH_CM_COLUMN column;
+
+ listEntry = Manager->ColumnListHead.Flink;
+
+ while (listEntry != &Manager->ColumnListHead)
+ {
+ column = CONTAINING_RECORD(listEntry, PH_CM_COLUMN, ListEntry);
+ listEntry = listEntry->Flink;
+
+ PhFree(column);
+ }
+
+ if (Manager->NotifyList)
+ PhDereferenceObject(Manager->NotifyList);
+}
+
+PPH_CM_COLUMN PhCmCreateColumn(
+ _Inout_ PPH_CM_MANAGER Manager,
+ _In_ PPH_TREENEW_COLUMN Column,
+ _In_ struct _PH_PLUGIN *Plugin,
+ _In_ ULONG SubId,
+ _In_opt_ PVOID Context,
+ _In_ PVOID SortFunction
+ )
+{
+ PPH_CM_COLUMN column;
+ PH_TREENEW_COLUMN tnColumn;
+
+ column = PhAllocate(sizeof(PH_CM_COLUMN));
+ memset(column, 0, sizeof(PH_CM_COLUMN));
+ column->Id = Manager->NextId++;
+ column->Plugin = Plugin;
+ column->SubId = SubId;
+ column->Context = Context;
+ column->SortFunction = SortFunction;
+ InsertTailList(&Manager->ColumnListHead, &column->ListEntry);
+
+ memset(&tnColumn, 0, sizeof(PH_TREENEW_COLUMN));
+ tnColumn.Id = column->Id;
+ tnColumn.Context = column;
+ tnColumn.Visible = Column->Visible;
+ tnColumn.CustomDraw = Column->CustomDraw;
+ tnColumn.SortDescending = Column->SortDescending;
+ tnColumn.Text = Column->Text;
+ tnColumn.Width = Column->Width;
+ tnColumn.Alignment = Column->Alignment;
+ tnColumn.DisplayIndex = Column->Visible ? Column->DisplayIndex : -1;
+ tnColumn.TextFlags = Column->TextFlags;
+ TreeNew_AddColumn(Manager->Handle, &tnColumn);
+
+ return column;
+}
+
+PPH_CM_COLUMN PhCmFindColumn(
+ _In_ PPH_CM_MANAGER Manager,
+ _In_ PPH_STRINGREF PluginName,
+ _In_ ULONG SubId
+ )
+{
+ PLIST_ENTRY listEntry;
+ PPH_CM_COLUMN column;
+
+ listEntry = Manager->ColumnListHead.Flink;
+
+ while (listEntry != &Manager->ColumnListHead)
+ {
+ column = CONTAINING_RECORD(listEntry, PH_CM_COLUMN, ListEntry);
+
+ if (column->SubId == SubId && PhEqualStringRef(PluginName, &column->Plugin->AppContext.AppName, FALSE))
+ return column;
+
+ listEntry = listEntry->Flink;
+ }
+
+ return NULL;
+}
+
+VOID PhCmSetNotifyPlugin(
+ _In_ PPH_CM_MANAGER Manager,
+ _In_ struct _PH_PLUGIN *Plugin
+ )
+{
+ if (!Manager->NotifyList)
+ {
+ Manager->NotifyList = PhCreateList(8);
+ }
+ else
+ {
+ if (PhFindItemList(Manager->NotifyList, Plugin) != -1)
+ return;
+ }
+
+ PhAddItemList(Manager->NotifyList, Plugin);
+}
+
+BOOLEAN PhCmForwardMessage(
+ _In_ HWND hwnd,
+ _In_ PH_TREENEW_MESSAGE Message,
+ _In_opt_ PVOID Parameter1,
+ _In_opt_ PVOID Parameter2,
+ _In_ PPH_CM_MANAGER Manager
+ )
+{
+ PH_PLUGIN_TREENEW_MESSAGE pluginMessage;
+ PPH_PLUGIN plugin;
+
+ if (Message == TreeNewDestroying)
+ return FALSE;
+
+ switch (Message)
+ {
+ case TreeNewGetCellText:
+ {
+ PPH_TREENEW_GET_CELL_TEXT getCellText = Parameter1;
+ PH_TREENEW_COLUMN tnColumn;
+ PPH_CM_COLUMN column;
+
+ if (getCellText->Id < Manager->MinId)
+ return FALSE;
+
+ if (!TreeNew_GetColumn(hwnd, getCellText->Id, &tnColumn))
+ return FALSE;
+
+ column = tnColumn.Context;
+ pluginMessage.SubId = column->SubId;
+ pluginMessage.Context = column->Context;
+ plugin = column->Plugin;
+ }
+ break;
+ case TreeNewCustomDraw:
+ {
+ PPH_TREENEW_CUSTOM_DRAW customDraw = Parameter1;
+ PPH_CM_COLUMN column;
+
+ if (customDraw->Column->Id < Manager->MinId)
+ return FALSE;
+
+ column = customDraw->Column->Context;
+ pluginMessage.SubId = column->SubId;
+ pluginMessage.Context = column->Context;
+ plugin = column->Plugin;
+ }
+ break;
+ case TreeNewColumnResized:
+ {
+ PPH_TREENEW_COLUMN tlColumn = Parameter1;
+ PPH_CM_COLUMN column;
+
+ if (tlColumn->Id < Manager->MinId)
+ return FALSE;
+
+ column = tlColumn->Context;
+ pluginMessage.SubId = column->SubId;
+ pluginMessage.Context = column->Context;
+ plugin = column->Plugin;
+ }
+ break;
+ default:
+ {
+ // Some plugins want to be notified about all messages.
+ if (Manager->NotifyList)
+ {
+ ULONG i;
+
+ for (i = 0; i < Manager->NotifyList->Count; i++)
+ {
+ plugin = Manager->NotifyList->Items[i];
+
+ pluginMessage.TreeNewHandle = hwnd;
+ pluginMessage.Message = Message;
+ pluginMessage.Parameter1 = Parameter1;
+ pluginMessage.Parameter2 = Parameter2;
+ pluginMessage.SubId = 0;
+ pluginMessage.Context = NULL;
+
+ PhInvokeCallback(PhGetPluginCallback(plugin, PluginCallbackTreeNewMessage), &pluginMessage);
+ }
+ }
+ }
+ return FALSE;
+ }
+
+ pluginMessage.TreeNewHandle = hwnd;
+ pluginMessage.Message = Message;
+ pluginMessage.Parameter1 = Parameter1;
+ pluginMessage.Parameter2 = Parameter2;
+
+ PhInvokeCallback(PhGetPluginCallback(plugin, PluginCallbackTreeNewMessage), &pluginMessage);
+
+ return TRUE;
+}
+
+static int __cdecl PhCmpSortFunction(
+ _In_ void *context,
+ _In_ const void *elem1,
+ _In_ const void *elem2
+ )
+{
+ PPH_CM_SORT_CONTEXT sortContext = context;
+ PVOID node1 = *(PVOID *)elem1;
+ PVOID node2 = *(PVOID *)elem2;
+ LONG result;
+
+ result = sortContext->SortFunction(node1, node2, sortContext->SubId, sortContext->SortOrder, sortContext->Context);
+
+ return sortContext->PostSortFunction(result, node1, node2, sortContext->SortOrder);
+}
+
+BOOLEAN PhCmForwardSort(
+ _In_ PPH_TREENEW_NODE *Nodes,
+ _In_ ULONG NumberOfNodes,
+ _In_ ULONG SortColumn,
+ _In_ PH_SORT_ORDER SortOrder,
+ _In_ PPH_CM_MANAGER Manager
+ )
+{
+ PH_TREENEW_COLUMN tnColumn;
+ PPH_CM_COLUMN column;
+ PH_CM_SORT_CONTEXT sortContext;
+
+ if (SortColumn < Manager->MinId)
+ return FALSE;
+
+ if (!TreeNew_GetColumn(Manager->Handle, SortColumn, &tnColumn))
+ return TRUE;
+
+ column = tnColumn.Context;
+
+ if (!column->SortFunction)
+ return TRUE;
+
+ sortContext.SortFunction = column->SortFunction;
+ sortContext.SubId = column->SubId;
+ sortContext.Context = column->Context;
+ sortContext.PostSortFunction = Manager->PostSortFunction;
+ sortContext.SortOrder = SortOrder;
+ qsort_s(Nodes, NumberOfNodes, sizeof(PVOID), PhCmpSortFunction, &sortContext);
+
+ return TRUE;
+}
+
+BOOLEAN PhCmLoadSettings(
+ _In_ HWND TreeNewHandle,
+ _In_ PPH_STRINGREF Settings
+ )
+{
+ return PhCmLoadSettingsEx(TreeNewHandle, NULL, 0, Settings, NULL);
+}
+
+BOOLEAN PhCmLoadSettingsEx(
+ _In_ HWND TreeNewHandle,
+ _In_opt_ PPH_CM_MANAGER Manager,
+ _In_ ULONG Flags,
+ _In_ PPH_STRINGREF Settings,
+ _In_opt_ PPH_STRINGREF SortSettings
+ )
+{
+ BOOLEAN result = FALSE;
+ PH_STRINGREF scalePart;
+ PH_STRINGREF columnPart;
+ PH_STRINGREF remainingColumnPart;
+ PH_STRINGREF valuePart;
+ PH_STRINGREF subPart;
+ ULONG64 integer;
+ ULONG scale;
+ ULONG total;
+ BOOLEAN hasFixedColumn;
+ ULONG count;
+ ULONG i;
+ PPH_HASHTABLE columnHashtable;
+ PH_HASHTABLE_ENUM_CONTEXT enumContext;
+ PPH_KEY_VALUE_PAIR pair;
+ LONG orderArray[PH_CM_ORDER_LIMIT];
+ LONG maxOrder;
+
+ if (Settings->Length != 0)
+ {
+ columnHashtable = PhCreateSimpleHashtable(20);
+
+ remainingColumnPart = *Settings;
+
+ if (remainingColumnPart.Length != 0 && remainingColumnPart.Buffer[0] == '@')
+ {
+ PhSkipStringRef(&remainingColumnPart, sizeof(WCHAR));
+ PhSplitStringRefAtChar(&remainingColumnPart, '|', &scalePart, &remainingColumnPart);
+
+ if (scalePart.Length == 0 || !PhStringToInteger64(&scalePart, 10, &integer))
+ goto CleanupExit;
+
+ scale = (ULONG)integer;
+ }
+ else
+ {
+ scale = PhGlobalDpi;
+ }
+
+ while (remainingColumnPart.Length != 0)
+ {
+ PPH_TREENEW_COLUMN column;
+ ULONG id;
+ ULONG displayIndex;
+ ULONG width;
+
+ PhSplitStringRefAtChar(&remainingColumnPart, '|', &columnPart, &remainingColumnPart);
+
+ if (columnPart.Length != 0)
+ {
+ // Id
+
+ PhSplitStringRefAtChar(&columnPart, ',', &valuePart, &columnPart);
+
+ if (valuePart.Length == 0)
+ goto CleanupExit;
+
+ if (valuePart.Buffer[0] == '+')
+ {
+ PH_STRINGREF pluginName;
+ ULONG subId;
+ PPH_CM_COLUMN cmColumn;
+
+ // This is a plugin-owned column.
+
+ if (!Manager)
+ continue;
+ if (!PhEmParseCompoundId(&valuePart, &pluginName, &subId))
+ continue;
+
+ cmColumn = PhCmFindColumn(Manager, &pluginName, subId);
+
+ if (!cmColumn)
+ continue; // can't find the column, skip this part
+
+ id = cmColumn->Id;
+ }
+ else
+ {
+ if (!PhStringToInteger64(&valuePart, 10, &integer))
+ goto CleanupExit;
+
+ id = (ULONG)integer;
+ }
+
+ // Display Index
+
+ PhSplitStringRefAtChar(&columnPart, ',', &valuePart, &columnPart);
+
+ if (!(Flags & PH_CM_COLUMN_WIDTHS_ONLY))
+ {
+ if (valuePart.Length == 0 || !PhStringToInteger64(&valuePart, 10, &integer))
+ goto CleanupExit;
+
+ displayIndex = (ULONG)integer;
+ }
+ else
+ {
+ if (valuePart.Length != 0)
+ goto CleanupExit;
+
+ displayIndex = -1;
+ }
+
+ // Width
+
+ if (columnPart.Length == 0 || !PhStringToInteger64(&columnPart, 10, &integer))
+ goto CleanupExit;
+
+ width = (ULONG)integer;
+
+ if (scale != PhGlobalDpi && scale != 0)
+ width = PhMultiplyDivide(width, PhGlobalDpi, scale);
+
+ column = PhAllocate(sizeof(PH_TREENEW_COLUMN));
+ column->Id = id;
+ column->DisplayIndex = displayIndex;
+ column->Width = width;
+ PhAddItemSimpleHashtable(columnHashtable, UlongToPtr(column->Id), column);
+ }
+ }
+
+ TreeNew_SetRedraw(TreeNewHandle, FALSE);
+
+ // Set visibility and width.
+
+ i = 0;
+ count = 0;
+ total = TreeNew_GetColumnCount(TreeNewHandle);
+ hasFixedColumn = !!TreeNew_GetFixedColumn(TreeNewHandle);
+ memset(orderArray, 0, sizeof(orderArray));
+ maxOrder = 0;
+
+ while (count < total)
+ {
+ PH_TREENEW_COLUMN setColumn;
+ PPH_TREENEW_COLUMN *columnPtr;
+
+ if (TreeNew_GetColumn(TreeNewHandle, i, &setColumn))
+ {
+ columnPtr = (PPH_TREENEW_COLUMN *)PhFindItemSimpleHashtable(columnHashtable, UlongToPtr(i));
+
+ if (!(Flags & PH_CM_COLUMN_WIDTHS_ONLY))
+ {
+ if (columnPtr)
+ {
+ setColumn.Visible = TRUE;
+ setColumn.Width = (*columnPtr)->Width;
+ TreeNew_SetColumn(TreeNewHandle, TN_COLUMN_FLAG_VISIBLE | TN_COLUMN_WIDTH, &setColumn);
+
+ if (!setColumn.Fixed)
+ {
+ // For compatibility reasons, normal columns have their display indicies stored
+ // one higher than usual (so they start from 1, not 0). Fix that here.
+ if (hasFixedColumn && (*columnPtr)->DisplayIndex != 0)
+ (*columnPtr)->DisplayIndex--;
+
+ if ((*columnPtr)->DisplayIndex < PH_CM_ORDER_LIMIT)
+ {
+ orderArray[(*columnPtr)->DisplayIndex] = i;
+
+ if ((ULONG)maxOrder < (*columnPtr)->DisplayIndex + 1)
+ maxOrder = (*columnPtr)->DisplayIndex + 1;
+ }
+ }
+ }
+ else if (!setColumn.Fixed) // never hide the fixed column
+ {
+ setColumn.Visible = FALSE;
+ TreeNew_SetColumn(TreeNewHandle, TN_COLUMN_FLAG_VISIBLE, &setColumn);
+ }
+ }
+ else
+ {
+ if (columnPtr)
+ {
+ setColumn.Width = (*columnPtr)->Width;
+ TreeNew_SetColumn(TreeNewHandle, TN_COLUMN_WIDTH, &setColumn);
+ }
+ }
+
+ count++;
+ }
+
+ i++;
+ }
+
+ if (!(Flags & PH_CM_COLUMN_WIDTHS_ONLY))
+ {
+ // Set the order array.
+ TreeNew_SetColumnOrderArray(TreeNewHandle, maxOrder, orderArray);
+ }
+
+ TreeNew_SetRedraw(TreeNewHandle, TRUE);
+
+ result = TRUE;
+
+CleanupExit:
+ PhBeginEnumHashtable(columnHashtable, &enumContext);
+
+ while (pair = PhNextEnumHashtable(&enumContext))
+ PhFree(pair->Value);
+
+ PhDereferenceObject(columnHashtable);
+ }
+
+ // Load sort settings.
+
+ if (SortSettings && SortSettings->Length != 0)
+ {
+ PhSplitStringRefAtChar(SortSettings, ',', &valuePart, &subPart);
+
+ if (valuePart.Length != 0 && subPart.Length != 0)
+ {
+ ULONG sortColumn;
+ PH_SORT_ORDER sortOrder;
+
+ sortColumn = -1;
+
+ if (valuePart.Buffer[0] == '+')
+ {
+ PH_STRINGREF pluginName;
+ ULONG subId;
+ PPH_CM_COLUMN cmColumn;
+
+ if (
+ Manager &&
+ PhEmParseCompoundId(&valuePart, &pluginName, &subId) &&
+ (cmColumn = PhCmFindColumn(Manager, &pluginName, subId))
+ )
+ {
+ sortColumn = cmColumn->Id;
+ }
+ }
+ else
+ {
+ PhStringToInteger64(&valuePart, 10, &integer);
+ sortColumn = (ULONG)integer;
+ }
+
+ PhStringToInteger64(&subPart, 10, &integer);
+ sortOrder = (PH_SORT_ORDER)integer;
+
+ if (sortColumn != -1 && sortOrder <= DescendingSortOrder)
+ {
+ TreeNew_SetSort(TreeNewHandle, sortColumn, sortOrder);
+ }
+ }
+ }
+
+ return result;
+}
+
+PPH_STRING PhCmSaveSettings(
+ _In_ HWND TreeNewHandle
+ )
+{
+ return PhCmSaveSettingsEx(TreeNewHandle, NULL, 0, NULL);
+}
+
+PPH_STRING PhCmSaveSettingsEx(
+ _In_ HWND TreeNewHandle,
+ _In_opt_ PPH_CM_MANAGER Manager,
+ _In_ ULONG Flags,
+ _Out_opt_ PPH_STRING *SortSettings
+ )
+{
+ PH_STRING_BUILDER stringBuilder;
+ ULONG i = 0;
+ ULONG count = 0;
+ ULONG total;
+ ULONG increment;
+ PH_TREENEW_COLUMN column;
+
+ total = TreeNew_GetColumnCount(TreeNewHandle);
+
+ if (TreeNew_GetFixedColumn(TreeNewHandle))
+ increment = 1; // the first normal column should have a display index that starts with 1, for compatibility
+ else
+ increment = 0;
+
+ PhInitializeStringBuilder(&stringBuilder, 100);
+
+ PhAppendFormatStringBuilder(&stringBuilder, L"@%lu|", PhGlobalDpi);
+
+ while (count < total)
+ {
+ if (TreeNew_GetColumn(TreeNewHandle, i, &column))
+ {
+ if (!(Flags & PH_CM_COLUMN_WIDTHS_ONLY))
+ {
+ if (column.Visible)
+ {
+ if (!Manager || i < Manager->MinId)
+ {
+ PhAppendFormatStringBuilder(
+ &stringBuilder,
+ L"%lu,%lu,%ld|",
+ i,
+ column.Fixed ? 0 : column.DisplayIndex + increment,
+ column.Width
+ );
+ }
+ else
+ {
+ PPH_CM_COLUMN cmColumn;
+
+ cmColumn = column.Context;
+ PhAppendFormatStringBuilder(
+ &stringBuilder,
+ L"+%s+%lu,%lu,%ld|",
+ cmColumn->Plugin->Name.Buffer,
+ cmColumn->SubId,
+ column.DisplayIndex + increment,
+ column.Width
+ );
+ }
+ }
+ }
+ else
+ {
+ if (!Manager || i < Manager->MinId)
+ {
+ PhAppendFormatStringBuilder(
+ &stringBuilder,
+ L"%lu,,%ld|",
+ i,
+ column.Width
+ );
+ }
+ else
+ {
+ PPH_CM_COLUMN cmColumn;
+
+ cmColumn = column.Context;
+ PhAppendFormatStringBuilder(
+ &stringBuilder,
+ L"+%s+%lu,,%ld|",
+ cmColumn->Plugin->Name.Buffer,
+ cmColumn->SubId,
+ column.Width
+ );
+ }
+ }
+
+ count++;
+ }
+
+ i++;
+ }
+
+ if (stringBuilder.String->Length != 0)
+ PhRemoveEndStringBuilder(&stringBuilder, 1);
+
+ if (SortSettings)
+ {
+ ULONG sortColumn;
+ PH_SORT_ORDER sortOrder;
+
+ if (TreeNew_GetSort(TreeNewHandle, &sortColumn, &sortOrder))
+ {
+ if (sortOrder != NoSortOrder)
+ {
+ if (!Manager || sortColumn < Manager->MinId)
+ {
+ *SortSettings = PhFormatString(L"%lu,%lu", sortColumn, sortOrder);
+ }
+ else
+ {
+ PH_TREENEW_COLUMN column;
+ PPH_CM_COLUMN cmColumn;
+
+ if (TreeNew_GetColumn(TreeNewHandle, sortColumn, &column))
+ {
+ cmColumn = column.Context;
+ *SortSettings = PhFormatString(L"+%s+%lu,%lu", cmColumn->Plugin->Name.Buffer, cmColumn->SubId, sortOrder);
+ }
+ else
+ {
+ *SortSettings = PhReferenceEmptyString();
+ }
+ }
+ }
+ else
+ {
+ *SortSettings = PhCreateString(L"0,0");
+ }
+ }
+ else
+ {
+ *SortSettings = PhReferenceEmptyString();
+ }
+ }
+
+ return PhFinalStringBuilderString(&stringBuilder);
+}
diff --git a/ProcessHacker/colsetmgr.c b/ProcessHacker/colsetmgr.c
new file mode 100644
index 000000000000..2d524f8f8df4
--- /dev/null
+++ b/ProcessHacker/colsetmgr.c
@@ -0,0 +1,651 @@
+/*
+ * Process Hacker -
+ * tree new column set manager
+ *
+ * Copyright (C) 2017 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 .
+ */
+
+#include
+#include
+#include
+#include
+
+PPH_LIST PhInitializeColumnSetList(
+ _In_ PWSTR SettingName
+ )
+{
+ PPH_LIST columnSetList;
+ PPH_STRING settingsString;
+ ULONG64 count;
+ ULONG64 index;
+ PH_STRINGREF remaining;
+ PH_STRINGREF part;
+
+ columnSetList = PhCreateList(10);
+ settingsString = PhaGetStringSetting(SettingName);
+ remaining = settingsString->sr;
+
+ if (remaining.Length == 0)
+ goto CleanupExit;
+ if (!PhSplitStringRefAtChar(&remaining, '-', &part, &remaining))
+ goto CleanupExit;
+ if (!PhStringToInteger64(&part, 10, &count))
+ goto CleanupExit;
+
+ for (index = 0; index < count; index++)
+ {
+ PH_STRINGREF columnSetNamePart;
+ PH_STRINGREF columnSetSettingPart;
+ PH_STRINGREF columnSetSortPart;
+
+ if (remaining.Length == 0)
+ break;
+
+ PhSplitStringRefAtChar(&remaining, '-', &columnSetNamePart, &remaining);
+ PhSplitStringRefAtChar(&remaining, '-', &columnSetSettingPart, &remaining);
+ PhSplitStringRefAtChar(&remaining, '-', &columnSetSortPart, &remaining);
+
+ {
+ PPH_COLUMN_SET_ENTRY entry;
+
+ entry = PhAllocate(sizeof(PH_COLUMN_SET_ENTRY));
+ entry->Name = PhCreateString2(&columnSetNamePart);
+ entry->Setting = PhCreateString2(&columnSetSettingPart);
+ entry->Sorting = PhCreateString2(&columnSetSortPart);
+
+ PhAddItemList(columnSetList, entry);
+ }
+ }
+
+CleanupExit:
+ return columnSetList;
+}
+
+VOID PhSaveSettingsColumnList(
+ _In_ PWSTR SettingName,
+ _In_ PPH_LIST ColumnSetList
+ )
+{
+ ULONG index;
+ PPH_STRING settingsString;
+ PH_STRING_BUILDER stringBuilder;
+
+ PhInitializeStringBuilder(&stringBuilder, 100);
+ PhAppendFormatStringBuilder(
+ &stringBuilder,
+ L"%lu-",
+ ColumnSetList->Count
+ );
+
+ for (index = 0; index < ColumnSetList->Count; index++)
+ {
+ PPH_COLUMN_SET_ENTRY entry = ColumnSetList->Items[index];
+
+ if (PhIsNullOrEmptyString(entry->Name))
+ continue;
+
+ PhAppendFormatStringBuilder(
+ &stringBuilder,
+ L"%s-%s-%s-",
+ entry->Name->Buffer,
+ PhGetStringOrEmpty(entry->Setting),
+ PhGetStringOrEmpty(entry->Sorting)
+ );
+ }
+
+ if (stringBuilder.String->Length != 0)
+ PhRemoveEndStringBuilder(&stringBuilder, 1);
+
+ settingsString = PH_AUTO(PhFinalStringBuilderString(&stringBuilder));
+ PhSetStringSetting2(SettingName, &settingsString->sr);
+}
+
+VOID PhDeleteColumnSetList(
+ _In_ PPH_LIST ColumnSetList
+ )
+{
+ for (ULONG i = 0; i < ColumnSetList->Count; i++)
+ {
+ PPH_COLUMN_SET_ENTRY entry = ColumnSetList->Items[i];
+
+ //PhRemoveItemList(ColumnSetList, PhFindItemList(ColumnSetList, entry));
+
+ PhClearReference(&entry->Name);
+ PhClearReference(&entry->Setting);
+ PhClearReference(&entry->Sorting);
+
+ PhFree(entry);
+ }
+
+ PhDereferenceObject(ColumnSetList);
+}
+
+_Success_(return)
+BOOLEAN PhLoadSettingsColumnSet(
+ _In_ PWSTR SettingName,
+ _In_ PPH_STRING ColumnSetName,
+ _Out_ PPH_STRING *TreeListSettings,
+ _Out_ PPH_STRING *TreeSortSettings
+ )
+{
+ PPH_STRING treeSettings = NULL;
+ PPH_STRING sortSettings = NULL;
+ PPH_STRING settingsString;
+ ULONG64 count;
+ ULONG64 index;
+ PH_STRINGREF remaining;
+ PH_STRINGREF part;
+
+ settingsString = PhaGetStringSetting(SettingName);
+ remaining = settingsString->sr;
+
+ if (remaining.Length == 0)
+ return FALSE;
+
+ if (!PhSplitStringRefAtChar(&remaining, '-', &part, &remaining))
+ return FALSE;
+ if (!PhStringToInteger64(&part, 10, &count))
+ return FALSE;
+
+ for (index = 0; index < count; index++)
+ {
+ PH_STRINGREF columnSetNamePart;
+ PH_STRINGREF columnSetSettingPart;
+ PH_STRINGREF columnSetSortPart;
+
+ if (remaining.Length == 0)
+ break;
+
+ PhSplitStringRefAtChar(&remaining, '-', &columnSetNamePart, &remaining);
+ PhSplitStringRefAtChar(&remaining, '-', &columnSetSettingPart, &remaining);
+ PhSplitStringRefAtChar(&remaining, '-', &columnSetSortPart, &remaining);
+
+ if (PhEqualStringRef(&columnSetNamePart, &ColumnSetName->sr, FALSE))
+ {
+ treeSettings = PhCreateString2(&columnSetSettingPart);
+ sortSettings = PhCreateString2(&columnSetSortPart);
+ break;
+ }
+ }
+
+ if (!PhIsNullOrEmptyString(treeSettings) && !PhIsNullOrEmptyString(sortSettings))
+ {
+ *TreeListSettings = treeSettings;
+ *TreeSortSettings = sortSettings;
+ return TRUE;
+ }
+ else
+ {
+ if (treeSettings)
+ PhDereferenceObject(treeSettings);
+ if (sortSettings)
+ PhDereferenceObject(sortSettings);
+ return FALSE;
+ }
+}
+
+VOID PhSaveSettingsColumnSet(
+ _In_ PWSTR SettingName,
+ _In_ PPH_STRING ColumnSetName,
+ _In_ PPH_STRING TreeListSettings,
+ _In_ PPH_STRING TreeSortSettings
+ )
+{
+ ULONG index;
+ BOOLEAN found = FALSE;
+ PPH_LIST columnSetList;
+
+ columnSetList = PhInitializeColumnSetList(SettingName);
+
+ for (index = 0; index < columnSetList->Count; index++)
+ {
+ PPH_COLUMN_SET_ENTRY entry = columnSetList->Items[index];
+
+ if (PhEqualString(entry->Name, ColumnSetName, FALSE))
+ {
+ PhReferenceObject(TreeListSettings);
+ PhReferenceObject(TreeSortSettings);
+
+ PhMoveReference(&entry->Setting, TreeListSettings);
+ PhMoveReference(&entry->Sorting, TreeSortSettings);
+
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ PPH_COLUMN_SET_ENTRY entry;
+
+ PhReferenceObject(ColumnSetName);
+ PhReferenceObject(TreeListSettings);
+ PhReferenceObject(TreeSortSettings);
+
+ entry = PhAllocate(sizeof(PH_COLUMN_SET_ENTRY));
+ entry->Name = ColumnSetName;
+ entry->Setting = TreeListSettings;
+ entry->Sorting = TreeSortSettings;
+
+ PhAddItemList(columnSetList, entry);
+ }
+
+ PhSaveSettingsColumnList(SettingName, columnSetList);
+
+ PhDeleteColumnSetList(columnSetList);
+}
+
+// Column Set Editor Dialog
+
+typedef struct _COLUMNSET_DIALOG_CONTEXT
+{
+ HWND DialogHandle;
+ HWND ListViewHandle;
+ HWND RenameButtonHandle;
+ HWND MoveUpButtonHandle;
+ HWND MoveDownButtonHandle;
+ HWND RemoveButtonHandle;
+ PPH_STRING SettingName;
+ PPH_LIST ColumnSetList;
+ BOOLEAN LabelEditActive;
+} COLUMNSET_DIALOG_CONTEXT, *PCOLUMNSET_DIALOG_CONTEXT;
+
+INT_PTR CALLBACK PhpColumnSetEditorDlgProc(
+ _In_ HWND hwndDlg,
+ _In_ UINT uMsg,
+ _In_ WPARAM wParam,
+ _In_ LPARAM lParam
+ );
+
+VOID PhShowColumnSetEditorDialog(
+ _In_ HWND ParentWindowHandle,
+ _In_ PWSTR SettingName
+ )
+{
+ DialogBoxParam(
+ PhInstanceHandle,
+ MAKEINTRESOURCE(IDD_COLUMNSETS),
+ ParentWindowHandle,
+ PhpColumnSetEditorDlgProc,
+ (LPARAM)SettingName
+ );
+}
+
+VOID PhpMoveListViewItem(
+ _In_ HWND ListViewHandle,
+ _In_ INT ItemIndex1,
+ _In_ INT ItemIndex2
+ )
+{
+ LVITEM item1;
+ LVITEM item2;
+ WCHAR buffer1[MAX_PATH];
+ WCHAR buffer2[MAX_PATH];
+
+ item1.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;
+ item1.stateMask = (UINT)-1;
+ item1.iItem = ItemIndex1;
+ item1.iSubItem = 0;
+ item1.cchTextMax = sizeof(buffer1);
+ item1.pszText = buffer1;
+
+ item2.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE;
+ item2.stateMask = (UINT)-1;
+ item2.iItem = ItemIndex2;
+ item2.iSubItem = 0;
+ item2.cchTextMax = sizeof(buffer2);
+ item2.pszText = buffer2;
+
+ if (
+ ListView_GetItem(ListViewHandle, &item1) &&
+ ListView_GetItem(ListViewHandle, &item2)
+ )
+ {
+ item1.iItem = ItemIndex2;
+ item2.iItem = ItemIndex1;
+
+ ListView_SetItem(ListViewHandle, &item1);
+ ListView_SetItem(ListViewHandle, &item2);
+ }
+}
+
+VOID PhpMoveSelectedListViewItemUp(
+ _In_ HWND ListViewHandle
+ )
+{
+ INT lvItemIndex;
+
+ lvItemIndex = ListView_GetNextItem(ListViewHandle, -1, LVNI_SELECTED);
+
+ if (lvItemIndex != -1)
+ {
+ PhpMoveListViewItem(ListViewHandle, lvItemIndex, lvItemIndex - 1);
+ }
+
+ SetFocus(ListViewHandle);
+ ListView_SetItemState(ListViewHandle, lvItemIndex - 1, LVNI_SELECTED, LVNI_SELECTED);
+ //ListView_EnsureVisible(ListViewHandle, lvItemIndex - 1, FALSE);
+}
+
+VOID PhpMoveSelectedListViewItemDown(
+ _In_ HWND ListViewHandle
+ )
+{
+ INT lvItemIndex;
+
+ lvItemIndex = ListView_GetNextItem(ListViewHandle, -1, LVNI_SELECTED);
+
+ if (lvItemIndex != -1)
+ {
+ PhpMoveListViewItem(ListViewHandle, lvItemIndex, lvItemIndex + 1);
+ }
+
+ SetFocus(ListViewHandle);
+ ListView_SetItemState(ListViewHandle, lvItemIndex + 1, LVNI_SELECTED, LVNI_SELECTED);
+ //ListView_EnsureVisible(ListViewHandle, lvItemIndex + 1, FALSE);
+}
+
+INT_PTR CALLBACK PhpColumnSetEditorDlgProc(
+ _In_ HWND hwndDlg,
+ _In_ UINT uMsg,
+ _In_ WPARAM wParam,
+ _In_ LPARAM lParam
+ )
+{
+ PCOLUMNSET_DIALOG_CONTEXT context = NULL;
+
+ if (uMsg == WM_INITDIALOG)
+ {
+ context = PhAllocate(sizeof(COLUMNSET_DIALOG_CONTEXT));
+ memset(context, 0, sizeof(COLUMNSET_DIALOG_CONTEXT));
+
+ context->SettingName = PhCreateString((PWSTR)lParam);
+
+ PhSetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT, context);
+ }
+ else
+ {
+ context = PhGetWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);
+ }
+
+ if (!context)
+ return FALSE;
+
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ context->DialogHandle = hwndDlg;
+ context->ListViewHandle = GetDlgItem(hwndDlg, IDC_COLUMNSETLIST);
+ context->RenameButtonHandle = GetDlgItem(hwndDlg, IDC_RENAME);
+ context->MoveUpButtonHandle = GetDlgItem(hwndDlg, IDC_MOVEUP);
+ context->MoveDownButtonHandle = GetDlgItem(hwndDlg, IDC_MOVEDOWN);
+ context->RemoveButtonHandle = GetDlgItem(hwndDlg, IDC_REMOVE);
+
+ PhCenterWindow(hwndDlg, GetParent(hwndDlg));
+
+ PhSetListViewStyle(context->ListViewHandle, FALSE, TRUE);
+ PhSetControlTheme(context->ListViewHandle, L"explorer");
+ PhAddListViewColumn(context->ListViewHandle, 0, 0, 0, LVCFMT_LEFT, 250, L"Name");
+ PhSetExtendedListView(context->ListViewHandle);
+
+ context->ColumnSetList = PhInitializeColumnSetList(PhGetString(context->SettingName));
+
+ for (ULONG i = 0; i < context->ColumnSetList->Count; i++)
+ {
+ PPH_COLUMN_SET_ENTRY entry = context->ColumnSetList->Items[i];
+
+ PhAddListViewItem(context->ListViewHandle, MAXINT, entry->Name->Buffer, entry);
+ }
+
+ Button_Enable(context->RenameButtonHandle, FALSE);
+ Button_Enable(context->MoveUpButtonHandle, FALSE);
+ Button_Enable(context->MoveDownButtonHandle, FALSE);
+ Button_Enable(context->RemoveButtonHandle, FALSE);
+ }
+ break;
+ case WM_DESTROY:
+ {
+ PhDeleteColumnSetList(context->ColumnSetList);
+
+ PhRemoveWindowContext(hwndDlg, PH_WINDOW_CONTEXT_DEFAULT);
+ PhFree(context);
+ }
+ break;
+ case WM_COMMAND:
+ {
+ switch (GET_WM_COMMAND_ID(wParam, lParam))
+ {
+ case IDCANCEL:
+ EndDialog(hwndDlg, IDCANCEL);
+ break;
+ case IDOK:
+ {
+ if (context->LabelEditActive)
+ break;
+
+ PhSaveSettingsColumnList(PhGetString(context->SettingName), context->ColumnSetList);
+
+ EndDialog(hwndDlg, IDOK);
+ }
+ break;
+ case IDC_RENAME:
+ {
+ INT lvItemIndex;
+
+ lvItemIndex = ListView_GetNextItem(context->ListViewHandle, -1, LVNI_SELECTED);
+
+ if (lvItemIndex != -1)
+ {
+ SetFocus(context->ListViewHandle);
+ ListView_EditLabel(context->ListViewHandle, lvItemIndex);
+ }
+ }
+ break;
+ case IDC_MOVEUP:
+ {
+ INT lvItemIndex;
+ PPH_COLUMN_SET_ENTRY entry;
+ ULONG index;
+
+ PhpMoveSelectedListViewItemUp(context->ListViewHandle);
+
+ lvItemIndex = ListView_GetNextItem(context->ListViewHandle, -1, LVNI_SELECTED);
+
+ if (lvItemIndex != -1 && PhGetListViewItemParam(context->ListViewHandle, lvItemIndex, (PVOID *)&entry))
+ {
+ index = PhFindItemList(context->ColumnSetList, entry);
+
+ if (index != -1)
+ {
+ PhRemoveItemList(context->ColumnSetList, index);
+ PhInsertItemList(context->ColumnSetList, lvItemIndex, entry);
+ }
+ }
+ }
+ break;
+ case IDC_MOVEDOWN:
+ {
+ INT lvItemIndex;
+ PPH_COLUMN_SET_ENTRY entry;
+ ULONG index;
+
+ PhpMoveSelectedListViewItemDown(context->ListViewHandle);
+
+ lvItemIndex = ListView_GetNextItem(context->ListViewHandle, -1, LVNI_SELECTED);
+
+ if (lvItemIndex != -1 && PhGetListViewItemParam(context->ListViewHandle, lvItemIndex, (PVOID *)&entry))
+ {
+ index = PhFindItemList(context->ColumnSetList, entry);
+
+ if (index != -1)
+ {
+ PhRemoveItemList(context->ColumnSetList, index);
+ PhInsertItemList(context->ColumnSetList, lvItemIndex, entry);
+ }
+ }
+ }
+ break;
+ case IDC_REMOVE:
+ {
+ INT lvItemIndex;
+ PPH_COLUMN_SET_ENTRY entry;
+ ULONG index;
+
+ lvItemIndex = ListView_GetNextItem(context->ListViewHandle, -1, LVNI_SELECTED);
+
+ if (lvItemIndex != -1 && PhGetListViewItemParam(context->ListViewHandle, lvItemIndex, (PVOID *)&entry))
+ {
+ index = PhFindItemList(context->ColumnSetList, entry);
+
+ if (index != -1)
+ {
+ PhRemoveItemList(context->ColumnSetList, index);
+ PhRemoveListViewItem(context->ListViewHandle, lvItemIndex);
+
+ PhClearReference(&entry->Name);
+ PhClearReference(&entry->Setting);
+ PhClearReference(&entry->Sorting);
+ PhFree(entry);
+ }
+
+ SetFocus(context->ListViewHandle);
+ ListView_SetItemState(context->ListViewHandle, 0, LVNI_SELECTED, LVNI_SELECTED);
+ //ListView_EnsureVisible(context->ListViewHandle, 0, FALSE);
+ }
+ }
+ break;
+ }
+ }
+ break;
+ case WM_NOTIFY:
+ {
+ LPNMHDR header = (LPNMHDR)lParam;
+
+ switch (header->code)
+ {
+ case NM_DBLCLK:
+ {
+ INT lvItemIndex;
+
+ lvItemIndex = ListView_GetNextItem(context->ListViewHandle, -1, LVNI_SELECTED);
+
+ if (lvItemIndex != -1)
+ {
+ SetFocus(context->ListViewHandle);
+ ListView_EditLabel(context->ListViewHandle, lvItemIndex);
+ }
+ }
+ break;
+ case LVN_ITEMCHANGED:
+ {
+ LPNMLISTVIEW listview = (LPNMLISTVIEW)lParam;
+ INT index;
+ INT lvItemIndex;
+ INT count;
+
+ index = listview->iItem;
+ lvItemIndex = ListView_GetNextItem(context->ListViewHandle, -1, LVNI_SELECTED);
+ count = ListView_GetItemCount(context->ListViewHandle);
+
+ if (count == 0 || index == -1 || lvItemIndex == -1)
+ {
+ Button_Enable(context->RenameButtonHandle, FALSE);
+ Button_Enable(context->MoveUpButtonHandle, FALSE);
+ Button_Enable(context->MoveDownButtonHandle, FALSE);
+ Button_Enable(context->RemoveButtonHandle, FALSE);
+ break;
+ }
+
+ if (index != lvItemIndex)
+ break;
+
+ if (index == 0 && count == 1)
+ {
+ // First and last item
+ Button_Enable(context->MoveUpButtonHandle, FALSE);
+ Button_Enable(context->MoveDownButtonHandle, FALSE);
+ }
+ else if (index == (count - 1))
+ {
+ // Last item
+ Button_Enable(context->MoveUpButtonHandle, TRUE);
+ Button_Enable(context->MoveDownButtonHandle, FALSE);
+ }
+ else if (index == 0)
+ {
+ // First item
+ Button_Enable(context->MoveUpButtonHandle, FALSE);
+ Button_Enable(context->MoveDownButtonHandle, TRUE);
+ }
+ else
+ {
+ Button_Enable(context->MoveUpButtonHandle, TRUE);
+ Button_Enable(context->MoveDownButtonHandle, TRUE);
+ }
+
+ Button_Enable(context->RenameButtonHandle, TRUE);
+ Button_Enable(context->RemoveButtonHandle, TRUE);
+ }
+ break;
+ case LVN_BEGINLABELEDIT:
+ context->LabelEditActive = TRUE;
+ break;
+ case LVN_ENDLABELEDIT:
+ {
+ LV_DISPINFO* lvinfo = (LV_DISPINFO*)lParam;
+
+ if (lvinfo->item.iItem != -1 && lvinfo->item.pszText)
+ {
+ BOOLEAN found = FALSE;
+ PPH_COLUMN_SET_ENTRY entry;
+ ULONG index;
+
+ for (ULONG i = 0; i < context->ColumnSetList->Count; i++)
+ {
+ entry = context->ColumnSetList->Items[i];
+
+ if (PhEqualStringRef2(&entry->Name->sr, lvinfo->item.pszText, FALSE))
+ {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if (!found && PhGetListViewItemParam(context->ListViewHandle, lvinfo->item.iItem, (PVOID *)&entry))
+ {
+ index = PhFindItemList(context->ColumnSetList, entry);
+
+ if (index != -1)
+ {
+ PhMoveReference(&entry->Name, PhCreateString(lvinfo->item.pszText));
+ ListView_SetItemText(context->ListViewHandle, lvinfo->item.iItem, 0, lvinfo->item.pszText);
+ }
+ }
+ }
+
+ context->LabelEditActive = FALSE;
+ }
+ break;
+ }
+ }
+ break;
+ }
+
+ return FALSE;
+}
diff --git a/ProcessHacker/dbgcon.c b/ProcessHacker/dbgcon.c
index d327bb58c58b..c1e742071539 100644
--- a/ProcessHacker/dbgcon.c
+++ b/ProcessHacker/dbgcon.c
@@ -1,1695 +1,1721 @@
-/*
- * Process Hacker -
- * debug console
- *
- * 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 .
- */
-
-/*
- * This is a simple debugging console which is able to explore phlib's
- * systems easily. Commands are provided to debug reference counting
- * problems and memory usage, as well as to do general performance testing.
- */
-
-#include
-
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-
-typedef struct _STRING_TABLE_ENTRY
-{
- PPH_STRING String;
- ULONG_PTR Count;
-} STRING_TABLE_ENTRY, *PSTRING_TABLE_ENTRY;
-
-BOOL ConsoleHandlerRoutine(
- _In_ DWORD dwCtrlType
- );
-
-VOID PhpPrintHashtableStatistics(
- _In_ PPH_HASHTABLE Hashtable
- );
-
-NTSTATUS PhpDebugConsoleThreadStart(
- _In_ PVOID Parameter
- );
-
-extern PH_FREE_LIST PhObjectSmallFreeList;
-
-static HANDLE DebugConsoleThreadHandle;
-static PPH_SYMBOL_PROVIDER DebugConsoleSymbolProvider;
-
-static PPH_HASHTABLE ObjectListSnapshot = NULL;
-#ifdef DEBUG
-static PPH_LIST NewObjectList = NULL;
-static PH_QUEUED_LOCK NewObjectListLock;
-#endif
-
-static BOOLEAN ShowAllLeaks = FALSE;
-static BOOLEAN InLeakDetection = FALSE;
-static ULONG NumberOfLeaks;
-static ULONG NumberOfLeaksShown;
-
-VOID PhShowDebugConsole(
- VOID
- )
-{
- if (AllocConsole())
- {
- HMENU menu;
-
- // Disable the close button because it's impossible to handle
- // those events.
- menu = GetSystemMenu(GetConsoleWindow(), FALSE);
- EnableMenuItem(menu, SC_CLOSE, MF_GRAYED | MF_DISABLED);
- DeleteMenu(menu, SC_CLOSE, 0);
-
- // Set a handler so we can catch Ctrl+C and Ctrl+Break.
- SetConsoleCtrlHandler(ConsoleHandlerRoutine, TRUE);
-
- freopen("CONOUT$", "w", stdout);
- freopen("CONOUT$", "w", stderr);
- freopen("CONIN$", "r", stdin);
- DebugConsoleThreadHandle = PhCreateThread(0, PhpDebugConsoleThreadStart, NULL);
- }
- else
- {
- HWND consoleWindow;
-
- consoleWindow = GetConsoleWindow();
-
- // Console window already exists, so bring it to the top.
- if (IsIconic(consoleWindow))
- ShowWindow(consoleWindow, SW_RESTORE);
- else
- BringWindowToTop(consoleWindow);
-
- return;
- }
-}
-
-VOID PhCloseDebugConsole(
- VOID
- )
-{
- freopen("NUL", "w", stdout);
- freopen("NUL", "w", stderr);
- freopen("NUL", "r", stdin);
-
- FreeConsole();
-}
-
-static BOOL ConsoleHandlerRoutine(
- _In_ DWORD dwCtrlType
- )
-{
- switch (dwCtrlType)
- {
- case CTRL_C_EVENT:
- case CTRL_BREAK_EVENT:
- case CTRL_CLOSE_EVENT:
- PhCloseDebugConsole();
- return TRUE;
- }
-
- return FALSE;
-}
-
-static BOOLEAN NTAPI PhpLoadCurrentProcessSymbolsCallback(
- _In_ PPH_MODULE_INFO Module,
- _In_opt_ PVOID Context
- )
-{
- PhLoadModuleSymbolProvider((PPH_SYMBOL_PROVIDER)Context, Module->FileName->Buffer,
- (ULONG64)Module->BaseAddress, Module->Size);
-
- return TRUE;
-}
-
-static PWSTR PhpGetSymbolForAddress(
- _In_ PVOID Address
- )
-{
- return PH_AUTO_T(PH_STRING, PhGetSymbolFromAddress(
- DebugConsoleSymbolProvider, (ULONG64)Address, NULL, NULL, NULL, NULL
- ))->Buffer;
-}
-
-static VOID PhpPrintObjectInfo(
- _In_ PPH_OBJECT_HEADER ObjectHeader,
- _In_ LONG RefToSubtract
- )
-{
- PVOID object;
- PPH_OBJECT_TYPE objectType;
- WCHAR c = ' ';
-
- object = PhObjectHeaderToObject(ObjectHeader);
- wprintf(L"%Ix", (ULONG_PTR)object);
- objectType = PhGetObjectType(object);
-
- wprintf(L"\t% 20s", objectType->Name);
-
- if (ObjectHeader->Flags & PH_OBJECT_FROM_SMALL_FREE_LIST)
- c = 'f';
- else if (ObjectHeader->Flags & PH_OBJECT_FROM_TYPE_FREE_LIST)
- c = 'F';
-
- wprintf(L"\t%4d %c", ObjectHeader->RefCount - RefToSubtract, c);
-
- if (!objectType)
- {
- // Dummy
- }
- else if (objectType == PhObjectTypeObject)
- {
- wprintf(L"\t%.32s", ((PPH_OBJECT_TYPE)object)->Name);
- }
- else if (objectType == PhStringType)
- {
- wprintf(L"\t%.32s", ((PPH_STRING)object)->Buffer);
- }
- else if (objectType == PhBytesType)
- {
- wprintf(L"\t%.32S", ((PPH_BYTES)object)->Buffer);
- }
- else if (objectType == PhListType)
- {
- wprintf(L"\tCount: %u", ((PPH_LIST)object)->Count);
- }
- else if (objectType == PhPointerListType)
- {
- wprintf(L"\tCount: %u", ((PPH_POINTER_LIST)object)->Count);
- }
- else if (objectType == PhHashtableType)
- {
- wprintf(L"\tCount: %u", ((PPH_HASHTABLE)object)->Count);
- }
- else if (objectType == PhProcessItemType)
- {
- wprintf(
- L"\t%.28s (%d)",
- ((PPH_PROCESS_ITEM)object)->ProcessName->Buffer,
- HandleToLong(((PPH_PROCESS_ITEM)object)->ProcessId)
- );
- }
- else if (objectType == PhServiceItemType)
- {
- wprintf(L"\t%s", ((PPH_SERVICE_ITEM)object)->Name->Buffer);
- }
- else if (objectType == PhThreadItemType)
- {
- wprintf(L"\tTID: %u", HandleToUlong(((PPH_THREAD_ITEM)object)->ThreadId));
- }
-
- wprintf(L"\n");
-}
-
-static VOID PhpDumpObjectInfo(
- _In_ PPH_OBJECT_HEADER ObjectHeader
- )
-{
- PVOID object;
- PPH_OBJECT_TYPE objectType;
-
- object = PhObjectHeaderToObject(ObjectHeader);
- objectType = PhGetObjectType(object);
-
- __try
- {
- wprintf(L"Type: %s\n", objectType->Name);
- wprintf(L"Reference count: %d\n", ObjectHeader->RefCount);
- wprintf(L"Flags: %x\n", ObjectHeader->Flags);
-
- if (objectType == PhObjectTypeObject)
- {
- wprintf(L"Name: %s\n", ((PPH_OBJECT_TYPE)object)->Name);
- wprintf(L"Number of objects: %u\n", ((PPH_OBJECT_TYPE)object)->NumberOfObjects);
- wprintf(L"Flags: %u\n", ((PPH_OBJECT_TYPE)object)->Flags);
- wprintf(L"Type index: %u\n", ((PPH_OBJECT_TYPE)object)->TypeIndex);
- wprintf(L"Free list count: %u\n", ((PPH_OBJECT_TYPE)object)->FreeList.Count);
- }
- else if (objectType == PhStringType)
- {
- wprintf(L"%s\n", ((PPH_STRING)object)->Buffer);
- }
- else if (objectType == PhBytesType)
- {
- wprintf(L"%S\n", ((PPH_BYTES)object)->Buffer);
- }
- else if (objectType == PhHashtableType)
- {
- PhpPrintHashtableStatistics((PPH_HASHTABLE)object);
- }
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- wprintf(L"Error.\n");
- }
-}
-
-static VOID PhpPrintHashtableStatistics(
- _In_ PPH_HASHTABLE Hashtable
- )
-{
- ULONG i;
- ULONG expectedLookupMisses = 0;
-
- wprintf(L"Count: %u\n", Hashtable->Count);
- wprintf(L"Allocated buckets: %u\n", Hashtable->AllocatedBuckets);
- wprintf(L"Allocated entries: %u\n", Hashtable->AllocatedEntries);
- wprintf(L"Next free entry: %d\n", Hashtable->FreeEntry);
- wprintf(L"Next usable entry: %d\n", Hashtable->NextEntry);
-
- wprintf(L"Equal function: %s\n", PhpGetSymbolForAddress(Hashtable->EqualFunction));
- wprintf(L"Hash function: %s\n", PhpGetSymbolForAddress(Hashtable->HashFunction));
-
- wprintf(L"\nBuckets:\n");
-
- for (i = 0; i < Hashtable->AllocatedBuckets; i++)
- {
- ULONG index;
- ULONG count = 0;
-
- // Count the number of entries in this bucket.
-
- index = Hashtable->Buckets[i];
-
- while (index != -1)
- {
- index = PH_HASHTABLE_GET_ENTRY(Hashtable, index)->Next;
- count++;
- }
-
- if (count != 0)
- {
- expectedLookupMisses += count - 1;
- }
-
- if (count != 0)
- {
- wprintf(L"%lu: ", i);
-
- // Print out the entry indicies.
-
- index = Hashtable->Buckets[i];
-
- while (index != -1)
- {
- wprintf(L"%lu", index);
-
- index = PH_HASHTABLE_GET_ENTRY(Hashtable, index)->Next;
- count--;
-
- if (count != 0)
- wprintf(L", ");
- }
-
- wprintf(L"\n");
- }
- else
- {
- //wprintf(L"%u: (empty)\n");
- }
- }
-
- wprintf(L"\nExpected lookup misses: %lu\n", expectedLookupMisses);
-}
-
-#ifdef DEBUG
-static VOID PhpDebugCreateObjectHook(
- _In_ PVOID Object,
- _In_ SIZE_T Size,
- _In_ ULONG Flags,
- _In_ PPH_OBJECT_TYPE ObjectType
- )
-{
- PhAcquireQueuedLockExclusive(&NewObjectListLock);
-
- if (NewObjectList)
- {
- PhReferenceObject(Object);
- PhAddItemList(NewObjectList, Object);
- }
-
- PhReleaseQueuedLockExclusive(&NewObjectListLock);
-}
-#endif
-
-#ifdef DEBUG
-static VOID PhpDeleteNewObjectList(
- VOID
- )
-{
- if (NewObjectList)
- {
- ULONG i;
-
- for (i = 0; i < NewObjectList->Count; i++)
- PhDereferenceObject(NewObjectList->Items[i]);
-
- PhDereferenceObject(NewObjectList);
- NewObjectList = NULL;
- }
-}
-#endif
-
-static BOOLEAN PhpStringHashtableEqualFunction(
- _In_ PVOID Entry1,
- _In_ PVOID Entry2
- )
-{
- PSTRING_TABLE_ENTRY entry1 = Entry1;
- PSTRING_TABLE_ENTRY entry2 = Entry2;
-
- return PhEqualString(entry1->String, entry2->String, FALSE);
-}
-
-static ULONG PhpStringHashtableHashFunction(
- _In_ PVOID Entry
- )
-{
- PSTRING_TABLE_ENTRY entry = Entry;
-
- return PhHashBytes((PUCHAR)entry->String->Buffer, entry->String->Length);
-}
-
-static int __cdecl PhpStringEntryCompareByCount(
- _In_ const void *elem1,
- _In_ const void *elem2
- )
-{
- PSTRING_TABLE_ENTRY entry1 = *(PSTRING_TABLE_ENTRY *)elem1;
- PSTRING_TABLE_ENTRY entry2 = *(PSTRING_TABLE_ENTRY *)elem2;
-
- return uintptrcmp(entry2->Count, entry1->Count);
-}
-
-static NTSTATUS PhpLeakEnumerationRoutine(
- _In_ LONG Reserved,
- _In_ PVOID HeapHandle,
- _In_ PVOID BaseAddress,
- _In_ SIZE_T BlockSize,
- _In_ ULONG StackTraceDepth,
- _In_ PVOID *StackTrace
- )
-{
- ULONG i;
-
- if (!InLeakDetection)
- return 0;
-
- if (!HeapHandle) // means no more entries
- return 0;
-
- if (ShowAllLeaks || HeapHandle == PhHeapHandle)
- {
- wprintf(L"Leak at 0x%Ix (%Iu bytes). Stack trace:\n", (ULONG_PTR)BaseAddress, BlockSize);
-
- for (i = 0; i < StackTraceDepth; i++)
- {
- PPH_STRING symbol;
-
- symbol = PhGetSymbolFromAddress(DebugConsoleSymbolProvider, (ULONG64)StackTrace[i], NULL, NULL, NULL, NULL);
-
- if (symbol)
- wprintf(L"\t%s\n", symbol->Buffer);
- else
- wprintf(L"\t?\n");
-
- PhDereferenceObject(symbol);
- }
-
- NumberOfLeaksShown++;
- }
-
- NumberOfLeaks++;
-
- return 0;
-}
-
-typedef struct _STOPWATCH
-{
- LARGE_INTEGER StartCounter;
- LARGE_INTEGER EndCounter;
- LARGE_INTEGER Frequency;
-} STOPWATCH, *PSTOPWATCH;
-
-static VOID PhInitializeStopwatch(
- _Out_ PSTOPWATCH Stopwatch
- )
-{
- Stopwatch->StartCounter.QuadPart = 0;
- Stopwatch->EndCounter.QuadPart = 0;
-}
-
-static VOID PhStartStopwatch(
- _Inout_ PSTOPWATCH Stopwatch
- )
-{
- NtQueryPerformanceCounter(&Stopwatch->StartCounter, &Stopwatch->Frequency);
-}
-
-static VOID PhStopStopwatch(
- _Inout_ PSTOPWATCH Stopwatch
- )
-{
- NtQueryPerformanceCounter(&Stopwatch->EndCounter, NULL);
-}
-
-static ULONG PhGetMillisecondsStopwatch(
- _In_ PSTOPWATCH Stopwatch
- )
-{
- LARGE_INTEGER countsPerMs;
-
- countsPerMs = Stopwatch->Frequency;
- countsPerMs.QuadPart /= 1000;
-
- return (ULONG)((Stopwatch->EndCounter.QuadPart - Stopwatch->StartCounter.QuadPart) /
- countsPerMs.QuadPart);
-}
-
-typedef VOID (FASTCALL *PPHF_RW_LOCK_FUNCTION)(
- _In_ PVOID Parameter
- );
-
-typedef struct _RW_TEST_CONTEXT
-{
- PWSTR Name;
-
- PPHF_RW_LOCK_FUNCTION AcquireExclusive;
- PPHF_RW_LOCK_FUNCTION AcquireShared;
- PPHF_RW_LOCK_FUNCTION ReleaseExclusive;
- PPHF_RW_LOCK_FUNCTION ReleaseShared;
-
- PVOID Parameter;
-} RW_TEST_CONTEXT, *PRW_TEST_CONTEXT;
-
-static PH_BARRIER RwStartBarrier;
-static LONG RwReadersActive;
-static LONG RwWritersActive;
-
-static NTSTATUS PhpRwLockTestThreadStart(
- _In_ PVOID Parameter
- )
-{
-#define RW_ITERS 10000
-#define RW_READ_ITERS 100
-#define RW_WRITE_ITERS 10
-#define RW_READ_SPIN_ITERS 60
-#define RW_WRITE_SPIN_ITERS 200
-
- RW_TEST_CONTEXT context = *(PRW_TEST_CONTEXT)Parameter;
- ULONG i;
- ULONG j;
- ULONG k;
- ULONG m;
-
- PhWaitForBarrier(&RwStartBarrier, FALSE);
-
- for (i = 0; i < RW_ITERS; i++)
- {
- for (j = 0; j < RW_READ_ITERS; j++)
- {
- // Read zone
-
- context.AcquireShared(context.Parameter);
- _InterlockedIncrement(&RwReadersActive);
-
- for (m = 0; m < RW_READ_SPIN_ITERS; m++)
- YieldProcessor();
-
- if (RwWritersActive != 0)
- {
- wprintf(L"[fail]: writers active in read zone!\n");
- NtWaitForSingleObject(NtCurrentProcess(), FALSE, NULL);
- }
-
- _InterlockedDecrement(&RwReadersActive);
- context.ReleaseShared(context.Parameter);
-
- // Spin for a while
-
- for (m = 0; m < 10; m++)
- YieldProcessor();
-
- if (j == RW_READ_ITERS / 2)
- {
- // Write zone
-
- for (k = 0; k < RW_WRITE_ITERS; k++)
- {
- context.AcquireExclusive(context.Parameter);
- _InterlockedIncrement(&RwWritersActive);
-
- for (m = 0; m < RW_WRITE_SPIN_ITERS; m++)
- YieldProcessor();
-
- if (RwReadersActive != 0)
- {
- wprintf(L"[fail]: readers active in write zone!\n");
- NtWaitForSingleObject(NtCurrentProcess(), FALSE, NULL);
- }
-
- _InterlockedDecrement(&RwWritersActive);
- context.ReleaseExclusive(context.Parameter);
- }
- }
- }
- }
-
- return STATUS_SUCCESS;
-}
-
-static VOID PhpTestRwLock(
- _In_ PRW_TEST_CONTEXT Context
- )
-{
-#define RW_PROCESSORS 4
-
- STOPWATCH stopwatch;
- ULONG i;
- HANDLE threadHandles[RW_PROCESSORS];
-
- // Dummy
-
- Context->AcquireExclusive(Context->Parameter);
- Context->ReleaseExclusive(Context->Parameter);
- Context->AcquireShared(Context->Parameter);
- Context->ReleaseShared(Context->Parameter);
-
- // Null test
-
- PhStartStopwatch(&stopwatch);
-
- for (i = 0; i < 2000000; i++)
- {
- Context->AcquireExclusive(Context->Parameter);
- Context->ReleaseExclusive(Context->Parameter);
- Context->AcquireShared(Context->Parameter);
- Context->ReleaseShared(Context->Parameter);
- }
-
- PhStopStopwatch(&stopwatch);
-
- wprintf(L"[null] %s: %ums\n", Context->Name, PhGetMillisecondsStopwatch(&stopwatch));
-
- // Stress test
-
- PhInitializeBarrier(&RwStartBarrier, RW_PROCESSORS + 1);
- RwReadersActive = 0;
- RwWritersActive = 0;
-
- for (i = 0; i < RW_PROCESSORS; i++)
- {
- threadHandles[i] = PhCreateThread(0, PhpRwLockTestThreadStart, Context);
- }
-
- PhWaitForBarrier(&RwStartBarrier, FALSE);
- PhStartStopwatch(&stopwatch);
- NtWaitForMultipleObjects(RW_PROCESSORS, threadHandles, WaitAll, FALSE, NULL);
- PhStopStopwatch(&stopwatch);
-
- for (i = 0; i < RW_PROCESSORS; i++)
- NtClose(threadHandles[i]);
-
- wprintf(L"[strs] %s: %ums\n", Context->Name, PhGetMillisecondsStopwatch(&stopwatch));
-}
-
-VOID FASTCALL PhfAcquireCriticalSection(
- _In_ PRTL_CRITICAL_SECTION CriticalSection
- )
-{
- RtlEnterCriticalSection(CriticalSection);
-}
-
-VOID FASTCALL PhfReleaseCriticalSection(
- _In_ PRTL_CRITICAL_SECTION CriticalSection
- )
-{
- RtlLeaveCriticalSection(CriticalSection);
-}
-
-VOID FASTCALL PhfReleaseQueuedLockExclusiveUsingInline(
- _In_ PPH_QUEUED_LOCK QueuedLock
- )
-{
- PhReleaseQueuedLockExclusive(QueuedLock);
-}
-
-NTSTATUS PhpDebugConsoleThreadStart(
- _In_ PVOID Parameter
- )
-{
- PH_AUTO_POOL autoPool;
- BOOLEAN exit = FALSE;
-
- PhInitializeAutoPool(&autoPool);
-
- DebugConsoleSymbolProvider = PhCreateSymbolProvider(NtCurrentProcessId());
-
- {
- WCHAR buffer[512];
- UNICODE_STRING name = RTL_CONSTANT_STRING(L"_NT_SYMBOL_PATH");
- UNICODE_STRING var;
- PPH_STRING newSearchPath;
-
- var.Buffer = buffer;
- var.MaximumLength = sizeof(buffer);
-
- if (!NT_SUCCESS(RtlQueryEnvironmentVariable_U(NULL, &name, &var)))
- buffer[0] = 0;
-
- newSearchPath = PhFormatString(L"%s;%s", buffer, PhApplicationDirectory->Buffer);
- PhSetSearchPathSymbolProvider(DebugConsoleSymbolProvider, newSearchPath->Buffer);
- PhDereferenceObject(newSearchPath);
- }
-
- PhEnumGenericModules(NtCurrentProcessId(), NtCurrentProcess(),
- 0, PhpLoadCurrentProcessSymbolsCallback, DebugConsoleSymbolProvider);
-
-#ifdef DEBUG
- PhInitializeQueuedLock(&NewObjectListLock);
- PhDbgCreateObjectHook = PhpDebugCreateObjectHook;
-#endif
-
- wprintf(L"Press Ctrl+C or type \"exit\" to close the debug console. Type \"help\" for a list of commands.\n");
-
- while (!exit)
- {
- static PWSTR delims = L" \t";
- static PWSTR commandDebugOnly = L"This command is not available on non-debug builds.\n";
-
- WCHAR line[201];
- ULONG inputLength;
- PWSTR context;
- PWSTR command;
-
- wprintf(L"dbg>");
-
- if (!fgetws(line, sizeof(line) / 2 - 1, stdin))
- break;
-
- // Remove the terminating new line character.
-
- inputLength = (ULONG)PhCountStringZ(line);
-
- if (inputLength != 0)
- line[inputLength - 1] = 0;
-
- context = NULL;
- command = wcstok_s(line, delims, &context);
-
- if (!command)
- {
- continue;
- }
- else if (PhEqualStringZ(command, L"help", TRUE))
- {
- wprintf(
- L"Commands:\n"
- L"exit\n"
- L"testperf\n"
- L"testlocks\n"
- L"stats\n"
- L"objects [type-name-filter]\n"
- L"objtrace object-address\n"
- L"objmksnap\n"
- L"objcmpsnap\n"
- L"objmknew\n"
- L"objdelnew\n"
- L"objviewnew\n"
- L"dumpobj\n"
- L"dumpautopool\n"
- L"threads\n"
- L"provthreads\n"
- L"workqueues\n"
- L"procrecords\n"
- L"procitem\n"
- L"uniquestr\n"
- L"enableleakdetect\n"
- L"leakdetect\n"
- L"mem\n"
- );
- }
- else if (PhEqualStringZ(command, L"exit", TRUE))
- {
- PhCloseDebugConsole();
- exit = TRUE;
- }
- else if (PhEqualStringZ(command, L"testperf", TRUE))
- {
- STOPWATCH stopwatch;
- ULONG i;
- PPH_STRING testString;
- RTL_CRITICAL_SECTION testCriticalSection;
- PH_FAST_LOCK testFastLock;
- PH_QUEUED_LOCK testQueuedLock;
-
- // Control (string reference counting)
-
- testString = PhCreateString(L"");
- PhReferenceObject(testString);
- PhDereferenceObject(testString);
- PhStartStopwatch(&stopwatch);
-
- for (i = 0; i < 10000000; i++)
- {
- PhReferenceObject(testString);
- PhDereferenceObject(testString);
- }
-
- PhStopStopwatch(&stopwatch);
- PhDereferenceObject(testString);
-
- wprintf(L"Referencing: %ums\n", PhGetMillisecondsStopwatch(&stopwatch));
-
- // Critical section
-
- RtlInitializeCriticalSection(&testCriticalSection);
- RtlEnterCriticalSection(&testCriticalSection);
- RtlLeaveCriticalSection(&testCriticalSection);
- PhStartStopwatch(&stopwatch);
-
- for (i = 0; i < 10000000; i++)
- {
- RtlEnterCriticalSection(&testCriticalSection);
- RtlLeaveCriticalSection(&testCriticalSection);
- }
-
- PhStopStopwatch(&stopwatch);
- RtlDeleteCriticalSection(&testCriticalSection);
-
- wprintf(L"Critical section: %ums\n", PhGetMillisecondsStopwatch(&stopwatch));
-
- // Fast lock
-
- PhInitializeFastLock(&testFastLock);
- PhAcquireFastLockExclusive(&testFastLock);
- PhReleaseFastLockExclusive(&testFastLock);
- PhStartStopwatch(&stopwatch);
-
- for (i = 0; i < 10000000; i++)
- {
- PhAcquireFastLockExclusive(&testFastLock);
- PhReleaseFastLockExclusive(&testFastLock);
- }
-
- PhStopStopwatch(&stopwatch);
- PhDeleteFastLock(&testFastLock);
-
- wprintf(L"Fast lock: %ums\n", PhGetMillisecondsStopwatch(&stopwatch));
-
- // Queued lock
-
- PhInitializeQueuedLock(&testQueuedLock);
- PhAcquireQueuedLockExclusive(&testQueuedLock);
- PhReleaseQueuedLockExclusive(&testQueuedLock);
- PhStartStopwatch(&stopwatch);
-
- for (i = 0; i < 10000000; i++)
- {
- PhAcquireQueuedLockExclusive(&testQueuedLock);
- PhReleaseQueuedLockExclusive(&testQueuedLock);
- }
-
- PhStopStopwatch(&stopwatch);
-
- wprintf(L"Queued lock: %ums\n", PhGetMillisecondsStopwatch(&stopwatch));
- }
- else if (PhEqualStringZ(command, L"testlocks", TRUE))
- {
- RW_TEST_CONTEXT testContext;
- PH_FAST_LOCK fastLock;
- PH_QUEUED_LOCK queuedLock;
- RTL_CRITICAL_SECTION criticalSection;
-
- testContext.Name = L"FastLock";
- testContext.AcquireExclusive = PhfAcquireFastLockExclusive;
- testContext.AcquireShared = PhfAcquireFastLockShared;
- testContext.ReleaseExclusive = PhfReleaseFastLockExclusive;
- testContext.ReleaseShared = PhfReleaseFastLockShared;
- testContext.Parameter = &fastLock;
- PhInitializeFastLock(&fastLock);
- PhpTestRwLock(&testContext);
- PhDeleteFastLock(&fastLock);
-
- testContext.Name = L"QueuedLock";
- testContext.AcquireExclusive = PhfAcquireQueuedLockExclusive;
- testContext.AcquireShared = PhfAcquireQueuedLockShared;
- testContext.ReleaseExclusive = PhfReleaseQueuedLockExclusive;
- testContext.ReleaseShared = PhfReleaseQueuedLockShared;
- testContext.Parameter = &queuedLock;
- PhInitializeQueuedLock(&queuedLock);
- PhpTestRwLock(&testContext);
-
- testContext.Name = L"CriticalSection";
- testContext.AcquireExclusive = PhfAcquireCriticalSection;
- testContext.AcquireShared = PhfAcquireCriticalSection;
- testContext.ReleaseExclusive = PhfReleaseCriticalSection;
- testContext.ReleaseShared = PhfReleaseCriticalSection;
- testContext.Parameter = &criticalSection;
- RtlInitializeCriticalSection(&criticalSection);
- PhpTestRwLock(&testContext);
- RtlDeleteCriticalSection(&criticalSection);
-
- testContext.Name = L"QueuedLockMutex";
- testContext.AcquireExclusive = PhfAcquireQueuedLockExclusive;
- testContext.AcquireShared = PhfAcquireQueuedLockExclusive;
- testContext.ReleaseExclusive = PhfReleaseQueuedLockExclusive;
- testContext.ReleaseShared = PhfReleaseQueuedLockExclusive;
- testContext.Parameter = &queuedLock;
- PhInitializeQueuedLock(&queuedLock);
- PhpTestRwLock(&testContext);
- }
- else if (PhEqualStringZ(command, L"stats", TRUE))
- {
-#ifdef DEBUG
- wprintf(L"Object small free list count: %u\n", PhObjectSmallFreeList.Count);
- wprintf(L"Statistics:\n");
-#define PRINT_STATISTIC(Name) wprintf(L#Name L": %u\n", PhLibStatisticsBlock.Name);
-
- PRINT_STATISTIC(BaseThreadsCreated);
- PRINT_STATISTIC(BaseThreadsCreateFailed);
- PRINT_STATISTIC(BaseStringBuildersCreated);
- PRINT_STATISTIC(BaseStringBuildersResized);
- PRINT_STATISTIC(RefObjectsCreated);
- PRINT_STATISTIC(RefObjectsDestroyed);
- PRINT_STATISTIC(RefObjectsAllocated);
- PRINT_STATISTIC(RefObjectsFreed);
- PRINT_STATISTIC(RefObjectsAllocatedFromSmallFreeList);
- PRINT_STATISTIC(RefObjectsFreedToSmallFreeList);
- PRINT_STATISTIC(RefObjectsAllocatedFromTypeFreeList);
- PRINT_STATISTIC(RefObjectsFreedToTypeFreeList);
- PRINT_STATISTIC(RefObjectsDeleteDeferred);
- PRINT_STATISTIC(RefAutoPoolsCreated);
- PRINT_STATISTIC(RefAutoPoolsDestroyed);
- PRINT_STATISTIC(RefAutoPoolsDynamicAllocated);
- PRINT_STATISTIC(RefAutoPoolsDynamicResized);
- PRINT_STATISTIC(QlBlockSpins);
- PRINT_STATISTIC(QlBlockWaits);
- PRINT_STATISTIC(QlAcquireExclusiveBlocks);
- PRINT_STATISTIC(QlAcquireSharedBlocks);
- PRINT_STATISTIC(WqWorkQueueThreadsCreated);
- PRINT_STATISTIC(WqWorkQueueThreadsCreateFailed);
- PRINT_STATISTIC(WqWorkItemsQueued);
-
-#else
- wprintf(commandDebugOnly);
-#endif
- }
- else if (PhEqualStringZ(command, L"objects", TRUE))
- {
-#ifdef DEBUG
- PWSTR typeFilter = wcstok_s(NULL, delims, &context);
- PLIST_ENTRY currentEntry;
- ULONG totalNumberOfObjects = 0;
- //SIZE_T totalNumberOfBytes = 0;
-
- if (typeFilter)
- _wcslwr(typeFilter);
-
- PhAcquireQueuedLockShared(&PhDbgObjectListLock);
-
- currentEntry = PhDbgObjectListHead.Flink;
-
- while (currentEntry != &PhDbgObjectListHead)
- {
- PPH_OBJECT_HEADER objectHeader;
- WCHAR typeName[32];
-
- objectHeader = CONTAINING_RECORD(currentEntry, PH_OBJECT_HEADER, ObjectListEntry);
-
- // Make sure the object isn't being destroyed.
- if (!PhReferenceObjectSafe(PhObjectHeaderToObject(objectHeader)))
- {
- currentEntry = currentEntry->Flink;
- continue;
- }
-
- totalNumberOfObjects++;
- //totalNumberOfBytes += objectHeader->Size;
-
- if (typeFilter)
- {
- wcscpy_s(typeName, sizeof(typeName) / 2, PhGetObjectType(PhObjectHeaderToObject(objectHeader))->Name);
- _wcslwr(typeName);
- }
-
- if (
- !typeFilter ||
- (typeFilter && wcsstr(typeName, typeFilter))
- )
- {
- PhpPrintObjectInfo(objectHeader, 1);
- }
-
- currentEntry = currentEntry->Flink;
- PhDereferenceObjectDeferDelete(PhObjectHeaderToObject(objectHeader));
- }
-
- PhReleaseQueuedLockShared(&PhDbgObjectListLock);
-
- wprintf(L"\n");
- wprintf(L"Total number: %lu\n", totalNumberOfObjects);
- /*wprintf(L"Total size (excl. header): %s\n",
- ((PPH_STRING)PH_AUTO(PhFormatSize(totalNumberOfBytes, 1)))->Buffer);*/
- wprintf(L"Total overhead (header): %s\n",
- ((PPH_STRING)PH_AUTO(
- PhFormatSize(PhAddObjectHeaderSize(0) * totalNumberOfObjects, 1)
- ))->Buffer);
-#else
- wprintf(commandDebugOnly);
-#endif
- }
- else if (PhEqualStringZ(command, L"objtrace", TRUE))
- {
-#ifdef DEBUG
- PWSTR objectAddress = wcstok_s(NULL, delims, &context);
- PH_STRINGREF objectAddressString;
- ULONG64 address;
-
- if (!objectAddress)
- {
- wprintf(L"Missing object address.\n");
- goto EndCommand;
- }
-
- PhInitializeStringRef(&objectAddressString, objectAddress);
-
- if (PhStringToInteger64(&objectAddressString, 16, &address))
- {
- PPH_OBJECT_HEADER objectHeader = (PPH_OBJECT_HEADER)PhObjectToObjectHeader((PVOID)address);
- PVOID stackBackTrace[16];
- ULONG i;
-
- // The address may not be valid.
- __try
- {
- memcpy(stackBackTrace, objectHeader->StackBackTrace, 16 * sizeof(PVOID));
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- PPH_STRING message;
-
- message = PH_AUTO(PhGetNtMessage(GetExceptionCode()));
- wprintf(L"Error: %s\n", PhGetString(message));
-
- goto EndCommand;
- }
-
- for (i = 0; i < 16; i++)
- {
- if (!stackBackTrace[i])
- break;
-
- wprintf(L"%s\n", PhpGetSymbolForAddress(stackBackTrace[i]));
- }
- }
- else
- {
- wprintf(L"Invalid object address.\n");
- }
-#else
- wprintf(commandDebugOnly);
-#endif
- }
- else if (PhEqualStringZ(command, L"objmksnap", TRUE))
- {
-#ifdef DEBUG
- PLIST_ENTRY currentEntry;
-
- if (ObjectListSnapshot)
- {
- PhDereferenceObject(ObjectListSnapshot);
- ObjectListSnapshot = NULL;
- }
-
- ObjectListSnapshot = PhCreateSimpleHashtable(100);
-
- PhAcquireQueuedLockShared(&PhDbgObjectListLock);
-
- currentEntry = PhDbgObjectListHead.Flink;
-
- while (currentEntry != &PhDbgObjectListHead)
- {
- PPH_OBJECT_HEADER objectHeader;
-
- objectHeader = CONTAINING_RECORD(currentEntry, PH_OBJECT_HEADER, ObjectListEntry);
- currentEntry = currentEntry->Flink;
-
- if (PhObjectHeaderToObject(objectHeader) != ObjectListSnapshot)
- PhAddItemSimpleHashtable(ObjectListSnapshot, objectHeader, NULL);
- }
-
- PhReleaseQueuedLockShared(&PhDbgObjectListLock);
-#else
- wprintf(commandDebugOnly);
-#endif
- }
- else if (PhEqualStringZ(command, L"objcmpsnap", TRUE))
- {
-#ifdef DEBUG
- PLIST_ENTRY currentEntry;
- PPH_LIST newObjects;
- ULONG i;
-
- if (!ObjectListSnapshot)
- {
- wprintf(L"No snapshot.\n");
- goto EndCommand;
- }
-
- newObjects = PhCreateList(10);
-
- PhAcquireQueuedLockShared(&PhDbgObjectListLock);
-
- currentEntry = PhDbgObjectListHead.Flink;
-
- while (currentEntry != &PhDbgObjectListHead)
- {
- PPH_OBJECT_HEADER objectHeader;
-
- objectHeader = CONTAINING_RECORD(currentEntry, PH_OBJECT_HEADER, ObjectListEntry);
- currentEntry = currentEntry->Flink;
-
- if (
- PhObjectHeaderToObject(objectHeader) != ObjectListSnapshot &&
- PhObjectHeaderToObject(objectHeader) != newObjects
- )
- {
- if (!PhFindItemSimpleHashtable(ObjectListSnapshot, objectHeader))
- {
- if (PhReferenceObjectSafe(PhObjectHeaderToObject(objectHeader)))
- PhAddItemList(newObjects, objectHeader);
- }
- }
- }
-
- PhReleaseQueuedLockShared(&PhDbgObjectListLock);
-
- for (i = 0; i < newObjects->Count; i++)
- {
- PPH_OBJECT_HEADER objectHeader = newObjects->Items[i];
-
- PhpPrintObjectInfo(objectHeader, 1);
-
- PhDereferenceObject(PhObjectHeaderToObject(objectHeader));
- }
-
- PhDereferenceObject(newObjects);
-#else
- wprintf(commandDebugOnly);
-#endif
- }
- else if (PhEqualStringZ(command, L"objmknew", TRUE))
- {
-#ifdef DEBUG
- PhAcquireQueuedLockExclusive(&NewObjectListLock);
- PhpDeleteNewObjectList();
- PhReleaseQueuedLockExclusive(&NewObjectListLock);
-
- // Creation needs to be done outside of the lock,
- // otherwise a deadlock will occur.
- NewObjectList = PhCreateList(100);
-#else
- wprintf(commandDebugOnly);
-#endif
- }
- else if (PhEqualStringZ(command, L"objdelnew", TRUE))
- {
-#ifdef DEBUG
- PhAcquireQueuedLockExclusive(&NewObjectListLock);
- PhpDeleteNewObjectList();
- PhReleaseQueuedLockExclusive(&NewObjectListLock);
-#else
- wprintf(commandDebugOnly);
-#endif
- }
- else if (PhEqualStringZ(command, L"objviewnew", TRUE))
- {
-#ifdef DEBUG
- ULONG i;
-
- PhAcquireQueuedLockExclusive(&NewObjectListLock);
-
- if (!NewObjectList)
- {
- wprintf(L"Object creation hooking not active.\n");
- PhReleaseQueuedLockExclusive(&NewObjectListLock);
- goto EndCommand;
- }
-
- for (i = 0; i < NewObjectList->Count; i++)
- {
- PhpPrintObjectInfo(PhObjectToObjectHeader(NewObjectList->Items[i]), 1);
- }
-
- PhReleaseQueuedLockExclusive(&NewObjectListLock);
-#else
- wprintf(commandDebugOnly);
-#endif
- }
- else if (PhEqualStringZ(command, L"dumpobj", TRUE))
- {
- PWSTR addressString = wcstok_s(NULL, delims, &context);
- PH_STRINGREF addressStringRef;
- ULONG64 address;
-
- if (!addressString)
- goto EndCommand;
-
- PhInitializeStringRef(&addressStringRef, addressString);
-
- if (PhStringToInteger64(&addressStringRef, 16, &address))
- {
- PhpDumpObjectInfo((PPH_OBJECT_HEADER)PhObjectToObjectHeader((PVOID)address));
- }
- }
- else if (PhEqualStringZ(command, L"dumpautopool", TRUE))
- {
- PWSTR addressString = wcstok_s(NULL, delims, &context);
- PH_STRINGREF addressStringRef;
- ULONG64 address;
-
- if (!addressString)
- goto EndCommand;
-
- PhInitializeStringRef(&addressStringRef, addressString);
-
- if (PhStringToInteger64(&addressStringRef, 16, &address))
- {
- PPH_AUTO_POOL userAutoPool = (PPH_AUTO_POOL)address;
- ULONG i;
-
- __try
- {
- wprintf(L"Static count: %u\n", userAutoPool->StaticCount);
- wprintf(L"Dynamic count: %u\n", userAutoPool->DynamicCount);
- wprintf(L"Dynamic allocated: %u\n", userAutoPool->DynamicAllocated);
-
- wprintf(L"Static objects:\n");
-
- for (i = 0; i < userAutoPool->StaticCount; i++)
- PhpPrintObjectInfo(PhObjectToObjectHeader(userAutoPool->StaticObjects[i]), 0);
-
- wprintf(L"Dynamic objects:\n");
-
- for (i = 0; i < userAutoPool->DynamicCount; i++)
- PhpPrintObjectInfo(PhObjectToObjectHeader(userAutoPool->DynamicObjects[i]), 0);
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- goto EndCommand;
- }
- }
- }
- else if (PhEqualStringZ(command, L"threads", TRUE))
- {
-#ifdef DEBUG
- PLIST_ENTRY currentEntry;
-
- PhAcquireQueuedLockShared(&PhDbgThreadListLock);
-
- currentEntry = PhDbgThreadListHead.Flink;
-
- while (currentEntry != &PhDbgThreadListHead)
- {
- PPHP_BASE_THREAD_DBG dbg;
-
- dbg = CONTAINING_RECORD(currentEntry, PHP_BASE_THREAD_DBG, ListEntry);
-
- wprintf(L"Thread %u\n", HandleToUlong(dbg->ClientId.UniqueThread));
- wprintf(L"\tStart Address: %s\n", PhpGetSymbolForAddress(dbg->StartAddress));
- wprintf(L"\tParameter: %Ix\n", (ULONG_PTR)dbg->Parameter);
- wprintf(L"\tCurrent auto-pool: %Ix\n", (ULONG_PTR)dbg->CurrentAutoPool);
-
- currentEntry = currentEntry->Flink;
- }
-
- PhReleaseQueuedLockShared(&PhDbgThreadListLock);
-#else
- wprintf(commandDebugOnly);
-#endif
- }
- else if (PhEqualStringZ(command, L"provthreads", TRUE))
- {
-#ifdef DEBUG
- ULONG i;
-
- if (PhDbgProviderList)
- {
- PhAcquireQueuedLockShared(&PhDbgProviderListLock);
-
- for (i = 0; i < PhDbgProviderList->Count; i++)
- {
- PPH_PROVIDER_THREAD providerThread = PhDbgProviderList->Items[i];
- THREAD_BASIC_INFORMATION basicInfo;
- PLIST_ENTRY providerEntry;
-
- if (providerThread->ThreadHandle)
- {
- PhGetThreadBasicInformation(providerThread->ThreadHandle, &basicInfo);
- wprintf(L"Thread %u\n", HandleToUlong(basicInfo.ClientId.UniqueThread));
- }
- else
- {
- wprintf(L"Thread not running\n");
- }
-
- PhAcquireQueuedLockExclusive(&providerThread->Lock);
-
- providerEntry = providerThread->ListHead.Flink;
-
- while (providerEntry != &providerThread->ListHead)
- {
- PPH_PROVIDER_REGISTRATION registration;
-
- registration = CONTAINING_RECORD(providerEntry, PH_PROVIDER_REGISTRATION, ListEntry);
-
- wprintf(L"\tProvider registration at %Ix\n", (ULONG_PTR)registration);
- wprintf(L"\t\tEnabled: %s\n", registration->Enabled ? L"Yes" : L"No");
- wprintf(L"\t\tFunction: %s\n", PhpGetSymbolForAddress(registration->Function));
-
- if (registration->Object)
- {
- wprintf(L"\t\tObject:\n");
- PhpPrintObjectInfo(PhObjectToObjectHeader(registration->Object), 0);
- }
-
- providerEntry = providerEntry->Flink;
- }
-
- PhReleaseQueuedLockExclusive(&providerThread->Lock);
-
- wprintf(L"\n");
- }
-
- PhReleaseQueuedLockShared(&PhDbgProviderListLock);
- }
-#else
- wprintf(commandDebugOnly);
-#endif
- }
- else if (PhEqualStringZ(command, L"workqueues", TRUE))
- {
-#ifdef DEBUG
- ULONG i;
-
- if (PhDbgWorkQueueList)
- {
- PhAcquireQueuedLockShared(&PhDbgWorkQueueListLock);
-
- for (i = 0; i < PhDbgWorkQueueList->Count; i++)
- {
- PPH_WORK_QUEUE workQueue = PhDbgWorkQueueList->Items[i];
- PLIST_ENTRY workQueueItemEntry;
-
- wprintf(L"Work queue at %s\n", PhpGetSymbolForAddress(workQueue));
- wprintf(L"Maximum threads: %u\n", workQueue->MaximumThreads);
- wprintf(L"Minimum threads: %u\n", workQueue->MinimumThreads);
- wprintf(L"No work timeout: %d\n", workQueue->NoWorkTimeout);
-
- wprintf(L"Current threads: %u\n", workQueue->CurrentThreads);
- wprintf(L"Busy count: %u\n", workQueue->BusyCount);
-
- PhAcquireQueuedLockExclusive(&workQueue->QueueLock);
-
- // List the items backwards.
- workQueueItemEntry = workQueue->QueueListHead.Blink;
-
- while (workQueueItemEntry != &workQueue->QueueListHead)
- {
- PPH_WORK_QUEUE_ITEM workQueueItem;
-
- workQueueItem = CONTAINING_RECORD(workQueueItemEntry, PH_WORK_QUEUE_ITEM, ListEntry);
-
- wprintf(L"\tWork queue item at %Ix\n", (ULONG_PTR)workQueueItem);
- wprintf(L"\t\tFunction: %s\n", PhpGetSymbolForAddress(workQueueItem->Function));
- wprintf(L"\t\tContext: %Ix\n", (ULONG_PTR)workQueueItem->Context);
-
- workQueueItemEntry = workQueueItemEntry->Blink;
- }
-
- PhReleaseQueuedLockExclusive(&workQueue->QueueLock);
-
- wprintf(L"\n");
- }
-
- PhReleaseQueuedLockShared(&PhDbgWorkQueueListLock);
- }
-#else
- wprintf(commandDebugOnly);
-#endif
- }
- else if (PhEqualStringZ(command, L"procrecords", TRUE))
- {
- PPH_PROCESS_RECORD record;
- ULONG i;
- SYSTEMTIME systemTime;
- PPH_PROCESS_RECORD startRecord;
-
- PhAcquireQueuedLockShared(&PhProcessRecordListLock);
-
- for (i = 0; i < PhProcessRecordList->Count; i++)
- {
- record = (PPH_PROCESS_RECORD)PhProcessRecordList->Items[i];
-
- PhLargeIntegerToLocalSystemTime(&systemTime, &record->CreateTime);
- wprintf(L"Records for %s %s:\n",
- ((PPH_STRING)PH_AUTO(PhFormatDate(&systemTime, NULL)))->Buffer,
- ((PPH_STRING)PH_AUTO(PhFormatTime(&systemTime, NULL)))->Buffer
- );
-
- startRecord = record;
-
- do
- {
- wprintf(L"\tRecord at %Ix: %s (%u) (refs: %d)\n", (ULONG_PTR)record, record->ProcessName->Buffer, HandleToUlong(record->ProcessId), record->RefCount);
-
- if (record->FileName)
- wprintf(L"\t\t%s\n", record->FileName->Buffer);
-
- record = CONTAINING_RECORD(record->ListEntry.Flink, PH_PROCESS_RECORD, ListEntry);
- } while (record != startRecord);
- }
-
- PhReleaseQueuedLockShared(&PhProcessRecordListLock);
- }
- else if (PhEqualStringZ(command, L"procitem", TRUE))
- {
- PWSTR filterString;
- PH_STRINGREF filterRef;
- ULONG64 filter64;
- LONG_PTR processIdFilter = -9; // can't use -2, -1 or 0 because they're all used for process IDs
- ULONG_PTR processAddressFilter = 0;
- PWSTR imageNameFilter = NULL;
- BOOLEAN showAll = FALSE;
- PPH_PROCESS_ITEM *processes;
- ULONG numberOfProcesses;
- ULONG i;
-
- filterString = wcstok_s(NULL, delims, &context);
-
- if (filterString)
- {
- PhInitializeStringRef(&filterRef, filterString);
-
- if (PhStringToInteger64(&filterRef, 10, &filter64))
- processIdFilter = (LONG_PTR)filter64;
- if (PhStringToInteger64(&filterRef, 16, &filter64))
- processAddressFilter = (ULONG_PTR)filter64;
-
- imageNameFilter = filterString;
- }
- else
- {
- showAll = TRUE;
- }
-
- PhEnumProcessItems(&processes, &numberOfProcesses);
-
- for (i = 0; i < numberOfProcesses; i++)
- {
- PPH_PROCESS_ITEM process = processes[i];
-
- if (
- showAll ||
- (processIdFilter != -9 && (LONG_PTR)process->ProcessId == processIdFilter) ||
- (processAddressFilter != 0 && (ULONG_PTR)process == processAddressFilter) ||
- (imageNameFilter && PhMatchWildcards(imageNameFilter, process->ProcessName->Buffer, TRUE))
- )
- {
- wprintf(L"Process item at %Ix: %s (%u)\n", (ULONG_PTR)process, process->ProcessName->Buffer, HandleToUlong(process->ProcessId));
- wprintf(L"\tRecord at %Ix\n", (ULONG_PTR)process->Record);
- wprintf(L"\tQuery handle %Ix\n", (ULONG_PTR)process->QueryHandle);
- wprintf(L"\tFile name at %Ix: %s\n", (ULONG_PTR)process->FileName, PhGetStringOrDefault(process->FileName, L"(null)"));
- wprintf(L"\tCommand line at %Ix: %s\n", (ULONG_PTR)process->CommandLine, PhGetStringOrDefault(process->CommandLine, L"(null)"));
- wprintf(L"\tFlags: %u\n", process->Flags);
- wprintf(L"\n");
- }
- }
-
- PhDereferenceObjects(processes, numberOfProcesses);
- }
- else if (PhEqualStringZ(command, L"uniquestr", TRUE))
- {
-#ifdef DEBUG
- PLIST_ENTRY currentEntry;
- PPH_HASHTABLE hashtable;
- PPH_LIST list;
- PSTRING_TABLE_ENTRY stringEntry;
- ULONG enumerationKey;
- ULONG i;
-
- hashtable = PhCreateHashtable(
- sizeof(STRING_TABLE_ENTRY),
- PhpStringHashtableEqualFunction,
- PhpStringHashtableHashFunction,
- 1024
- );
-
- PhAcquireQueuedLockShared(&PhDbgObjectListLock);
-
- currentEntry = PhDbgObjectListHead.Flink;
-
- while (currentEntry != &PhDbgObjectListHead)
- {
- PPH_OBJECT_HEADER objectHeader;
- PPH_STRING string;
- STRING_TABLE_ENTRY localStringEntry;
- BOOLEAN added;
-
- objectHeader = CONTAINING_RECORD(currentEntry, PH_OBJECT_HEADER, ObjectListEntry);
- currentEntry = currentEntry->Flink;
- string = PhObjectHeaderToObject(objectHeader);
-
- // Make sure this is a string.
- if (PhGetObjectType(string) != PhStringType)
- continue;
-
- // Make sure the object isn't being destroyed.
- if (!PhReferenceObjectSafe(string))
- continue;
-
- localStringEntry.String = string;
- stringEntry = PhAddEntryHashtableEx(hashtable, &localStringEntry, &added);
-
- if (added)
- {
- stringEntry->Count = 1;
- PhReferenceObject(string);
- }
- else
- {
- stringEntry->Count++;
- }
-
- PhDereferenceObjectDeferDelete(string);
- }
-
- PhReleaseQueuedLockShared(&PhDbgObjectListLock);
-
- // Sort the string entries by count.
-
- list = PhCreateList(hashtable->Count);
-
- enumerationKey = 0;
-
- while (PhEnumHashtable(hashtable, &stringEntry, &enumerationKey))
- {
- PhAddItemList(list, stringEntry);
- }
-
- qsort(list->Items, list->Count, sizeof(PSTRING_TABLE_ENTRY), PhpStringEntryCompareByCount);
-
- // Display...
-
- for (i = 0; i < 40 && i < list->Count; i++)
- {
- stringEntry = list->Items[i];
- wprintf(L"%Iu\t%.64s\n", stringEntry->Count, stringEntry->String->Buffer);
- }
-
- wprintf(L"\nTotal unique strings: %u\n", list->Count);
-
- // Cleanup
-
- for (i = 0; i < list->Count; i++)
- {
- stringEntry = list->Items[i];
- PhDereferenceObject(stringEntry->String);
- }
-
- PhDereferenceObject(list);
- PhDereferenceObject(hashtable);
-#else
- wprintf(commandDebugOnly);
-#endif
- }
- else if (PhEqualStringZ(command, L"enableleakdetect", TRUE))
- {
- HEAP_DEBUGGING_INFORMATION debuggingInfo;
-
- memset(&debuggingInfo, 0, sizeof(HEAP_DEBUGGING_INFORMATION));
- debuggingInfo.StackTraceDepth = 32;
- debuggingInfo.HeapLeakEnumerationRoutine = PhpLeakEnumerationRoutine;
-
- if (!NT_SUCCESS(RtlSetHeapInformation(NULL, HeapDebuggingInformation, &debuggingInfo, sizeof(HEAP_DEBUGGING_INFORMATION))))
- {
- wprintf(L"Unable to initialize heap debugging. Make sure that you are using Windows 7 or above.");
- }
- }
- else if (PhEqualStringZ(command, L"leakdetect", TRUE))
- {
- VOID (NTAPI *rtlDetectHeapLeaks)(VOID);
- PWSTR options = wcstok_s(NULL, delims, &context);
-
- rtlDetectHeapLeaks = PhGetModuleProcAddress(L"ntdll.dll", "RtlDetectHeapLeaks");
-
- if (!(NtCurrentPeb()->NtGlobalFlag & FLG_USER_STACK_TRACE_DB))
- {
- wprintf(L"Warning: user-mode stack trace database is not enabled. Stack traces will not be displayed.\n");
- }
-
- ShowAllLeaks = FALSE;
-
- if (options)
- {
- if (PhEqualStringZ(options, L"all", TRUE))
- ShowAllLeaks = TRUE;
- }
-
- if (rtlDetectHeapLeaks)
- {
- InLeakDetection = TRUE;
- NumberOfLeaks = 0;
- NumberOfLeaksShown = 0;
- rtlDetectHeapLeaks();
- InLeakDetection = FALSE;
-
- wprintf(L"\nNumber of leaks: %lu (%lu displayed)\n", NumberOfLeaks, NumberOfLeaksShown);
- }
- }
- else if (PhEqualStringZ(command, L"mem", TRUE))
- {
- PWSTR addressString;
- PWSTR bytesString;
- PH_STRINGREF addressStringRef;
- PH_STRINGREF bytesStringRef;
- ULONG64 address64;
- ULONG64 numberOfBytes64;
- PUCHAR address;
- ULONG numberOfBytes;
- ULONG blockSize;
- UCHAR buffer[16];
- ULONG i;
-
- addressString = wcstok_s(NULL, delims, &context);
-
- if (!addressString)
- goto PrintMemUsage;
-
- bytesString = wcstok_s(NULL, delims, &context);
-
- if (!bytesString)
- {
- bytesString = L"16";
- }
-
- PhInitializeStringRef(&addressStringRef, addressString);
- PhInitializeStringRef(&bytesStringRef, bytesString);
-
- if (PhStringToInteger64(&addressStringRef, 16, &address64) && PhStringToInteger64(&bytesStringRef, 10, &numberOfBytes64))
- {
- address = (PUCHAR)address64;
- numberOfBytes = (ULONG)numberOfBytes64;
-
- if (numberOfBytes > 256)
- {
- wprintf(L"Number of bytes must be 256 or smaller.\n");
- goto EndCommand;
- }
-
- blockSize = sizeof(buffer);
-
- while (numberOfBytes != 0)
- {
- if (blockSize > numberOfBytes)
- blockSize = numberOfBytes;
-
- __try
- {
- memcpy(buffer, address, blockSize);
- }
- __except (EXCEPTION_EXECUTE_HANDLER)
- {
- wprintf(L"Error reading address near %Ix.\n", (ULONG_PTR)address);
- goto EndCommand;
- }
-
- // Print hex dump
- for (i = 0; i < blockSize; i++)
- wprintf(L"%02x ", buffer[i]);
-
- // Fill remaining space (for last, possibly partial block)
- for (; i < sizeof(buffer); i++)
- wprintf(L" ");
-
- wprintf(L" ");
-
- // Print ASCII dump
- for (i = 0; i < blockSize; i++)
- putwchar((ULONG)(buffer[i] - ' ') <= (ULONG)('~' - ' ') ? buffer[i] : '.');
-
- wprintf(L"\n");
-
- address += blockSize;
- numberOfBytes -= blockSize;
- }
- }
-
- goto EndCommand;
-PrintMemUsage:
- wprintf(L"Usage: mem address [numberOfBytes]\n");
- wprintf(L"Example: mem 12345678 16\n");
- }
- else
- {
- wprintf(L"Unrecognized command.\n");
- goto EndCommand; // get rid of the compiler warning about the label being unreferenced
- }
-
-EndCommand:
- PhDrainAutoPool(&autoPool);
- }
-
- PhDereferenceObject(DebugConsoleSymbolProvider);
-
- PhDeleteAutoPool(&autoPool);
-
- return STATUS_SUCCESS;
-}
+/*
+ * Process Hacker -
+ * debug console
+ *
+ * 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 .
+ */
+
+/*
+ * This is a simple debugging console which is able to explore phlib's
+ * systems easily. Commands are provided to debug reference counting
+ * problems and memory usage, as well as to do general performance testing.
+ */
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+typedef struct _STRING_TABLE_ENTRY
+{
+ PPH_STRING String;
+ ULONG_PTR Count;
+} STRING_TABLE_ENTRY, *PSTRING_TABLE_ENTRY;
+
+BOOL ConsoleHandlerRoutine(
+ _In_ ULONG dwCtrlType
+ );
+
+VOID PhpPrintHashtableStatistics(
+ _In_ PPH_HASHTABLE Hashtable
+ );
+
+NTSTATUS PhpDebugConsoleThreadStart(
+ _In_ PVOID Parameter
+ );
+
+extern PH_FREE_LIST PhObjectSmallFreeList;
+
+static HANDLE DebugConsoleThreadHandle;
+static PPH_SYMBOL_PROVIDER DebugConsoleSymbolProvider;
+
+static PPH_HASHTABLE ObjectListSnapshot = NULL;
+#ifdef DEBUG
+static PPH_LIST NewObjectList = NULL;
+static PH_QUEUED_LOCK NewObjectListLock;
+#endif
+
+static BOOLEAN ShowAllLeaks = FALSE;
+static BOOLEAN InLeakDetection = FALSE;
+static ULONG NumberOfLeaks;
+static ULONG NumberOfLeaksShown;
+
+VOID PhShowDebugConsole(
+ VOID
+ )
+{
+ if (AllocConsole())
+ {
+ HMENU menu;
+
+ // Disable the close button because it's impossible to handle
+ // those events.
+ menu = GetSystemMenu(GetConsoleWindow(), FALSE);
+ EnableMenuItem(menu, SC_CLOSE, MF_GRAYED | MF_DISABLED);
+ DeleteMenu(menu, SC_CLOSE, 0);
+
+ // Set a handler so we can catch Ctrl+C and Ctrl+Break.
+ SetConsoleCtrlHandler(ConsoleHandlerRoutine, TRUE);
+
+ _wfreopen(L"CONOUT$", L"w", stdout);
+ _wfreopen(L"CONOUT$", L"w", stderr);
+ _wfreopen(L"CONIN$", L"r", stdin);
+
+ PhCreateThreadEx(&DebugConsoleThreadHandle, PhpDebugConsoleThreadStart, NULL);
+ }
+ else
+ {
+ HWND consoleWindow;
+
+ consoleWindow = GetConsoleWindow();
+
+ // Console window already exists, so bring it to the top.
+ if (IsMinimized(consoleWindow))
+ ShowWindow(consoleWindow, SW_RESTORE);
+ else
+ BringWindowToTop(consoleWindow);
+
+ return;
+ }
+}
+
+VOID PhCloseDebugConsole(
+ VOID
+ )
+{
+ _wfreopen(L"NUL", L"w", stdout);
+ _wfreopen(L"NUL", L"w", stderr);
+ _wfreopen(L"NUL", L"r", stdin);
+
+ FreeConsole();
+}
+
+static BOOL ConsoleHandlerRoutine(
+ _In_ ULONG dwCtrlType
+ )
+{
+ switch (dwCtrlType)
+ {
+ case CTRL_C_EVENT:
+ case CTRL_BREAK_EVENT:
+ case CTRL_CLOSE_EVENT:
+ PhCloseDebugConsole();
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static BOOLEAN NTAPI PhpLoadCurrentProcessSymbolsCallback(
+ _In_ PPH_MODULE_INFO Module,
+ _In_opt_ PVOID Context
+ )
+{
+ PhLoadModuleSymbolProvider((PPH_SYMBOL_PROVIDER)Context, Module->FileName->Buffer,
+ (ULONG64)Module->BaseAddress, Module->Size);
+
+ return TRUE;
+}
+
+static PWSTR PhpGetSymbolForAddress(
+ _In_ PVOID Address
+ )
+{
+ return PH_AUTO_T(PH_STRING, PhGetSymbolFromAddress(
+ DebugConsoleSymbolProvider, (ULONG64)Address, NULL, NULL, NULL, NULL
+ ))->Buffer;
+}
+
+static VOID PhpPrintObjectInfo(
+ _In_ PPH_OBJECT_HEADER ObjectHeader,
+ _In_ LONG RefToSubtract
+ )
+{
+ PVOID object;
+ PPH_OBJECT_TYPE objectType;
+ WCHAR c = ' ';
+
+ object = PhObjectHeaderToObject(ObjectHeader);
+ wprintf(L"%Ix", (ULONG_PTR)object);
+ objectType = PhGetObjectType(object);
+
+ wprintf(L"\t% 20s", objectType->Name);
+
+ if (ObjectHeader->Flags & PH_OBJECT_FROM_SMALL_FREE_LIST)
+ c = 'f';
+ else if (ObjectHeader->Flags & PH_OBJECT_FROM_TYPE_FREE_LIST)
+ c = 'F';
+
+ wprintf(L"\t%4d %c", ObjectHeader->RefCount - RefToSubtract, c);
+
+ if (!objectType)
+ {
+ // Dummy
+ }
+ else if (objectType == PhObjectTypeObject)
+ {
+ wprintf(L"\t%.32s", ((PPH_OBJECT_TYPE)object)->Name);
+ }
+ else if (objectType == PhStringType)
+ {
+ wprintf(L"\t%.32s", ((PPH_STRING)object)->Buffer);
+ }
+ else if (objectType == PhBytesType)
+ {
+ wprintf(L"\t%.32S", ((PPH_BYTES)object)->Buffer);
+ }
+ else if (objectType == PhListType)
+ {
+ wprintf(L"\tCount: %u", ((PPH_LIST)object)->Count);
+ }
+ else if (objectType == PhPointerListType)
+ {
+ wprintf(L"\tCount: %u", ((PPH_POINTER_LIST)object)->Count);
+ }
+ else if (objectType == PhHashtableType)
+ {
+ wprintf(L"\tCount: %u", ((PPH_HASHTABLE)object)->Count);
+ }
+ else if (objectType == PhProcessItemType)
+ {
+ wprintf(
+ L"\t%.28s (%lu)",
+ ((PPH_PROCESS_ITEM)object)->ProcessName->Buffer,
+ HandleToUlong(((PPH_PROCESS_ITEM)object)->ProcessId)
+ );
+ }
+ else if (objectType == PhServiceItemType)
+ {
+ wprintf(L"\t%s", ((PPH_SERVICE_ITEM)object)->Name->Buffer);
+ }
+ else if (objectType == PhThreadItemType)
+ {
+ wprintf(L"\tTID: %lu", HandleToUlong(((PPH_THREAD_ITEM)object)->ThreadId));
+ }
+
+ wprintf(L"\n");
+}
+
+static VOID PhpDumpObjectInfo(
+ _In_ PPH_OBJECT_HEADER ObjectHeader
+ )
+{
+ PVOID object;
+ PPH_OBJECT_TYPE objectType;
+
+ object = PhObjectHeaderToObject(ObjectHeader);
+ objectType = PhGetObjectType(object);
+
+ __try
+ {
+ wprintf(L"Type: %s\n", objectType->Name);
+ wprintf(L"Reference count: %ld\n", ObjectHeader->RefCount);
+ wprintf(L"Flags: %x\n", ObjectHeader->Flags);
+
+ if (objectType == PhObjectTypeObject)
+ {
+ wprintf(L"Name: %s\n", ((PPH_OBJECT_TYPE)object)->Name);
+ wprintf(L"Number of objects: %lu\n", ((PPH_OBJECT_TYPE)object)->NumberOfObjects);
+ wprintf(L"Flags: %u\n", ((PPH_OBJECT_TYPE)object)->Flags);
+ wprintf(L"Type index: %u\n", ((PPH_OBJECT_TYPE)object)->TypeIndex);
+ wprintf(L"Free list count: %lu\n", ((PPH_OBJECT_TYPE)object)->FreeList.Count);
+ }
+ else if (objectType == PhStringType)
+ {
+ wprintf(L"%s\n", ((PPH_STRING)object)->Buffer);
+ }
+ else if (objectType == PhBytesType)
+ {
+ wprintf(L"%S\n", ((PPH_BYTES)object)->Buffer);
+ }
+ else if (objectType == PhHashtableType)
+ {
+ PhpPrintHashtableStatistics((PPH_HASHTABLE)object);
+ }
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ wprintf(L"Error.\n");
+ }
+}
+
+static VOID PhpPrintHashtableStatistics(
+ _In_ PPH_HASHTABLE Hashtable
+ )
+{
+ ULONG i;
+ ULONG expectedLookupMisses = 0;
+
+ wprintf(L"Count: %u\n", Hashtable->Count);
+ wprintf(L"Allocated buckets: %u\n", Hashtable->AllocatedBuckets);
+ wprintf(L"Allocated entries: %u\n", Hashtable->AllocatedEntries);
+ wprintf(L"Next free entry: %d\n", Hashtable->FreeEntry);
+ wprintf(L"Next usable entry: %d\n", Hashtable->NextEntry);
+
+ wprintf(L"Equal function: %s\n", PhpGetSymbolForAddress(Hashtable->EqualFunction));
+ wprintf(L"Hash function: %s\n", PhpGetSymbolForAddress(Hashtable->HashFunction));
+
+ wprintf(L"\nBuckets:\n");
+
+ for (i = 0; i < Hashtable->AllocatedBuckets; i++)
+ {
+ ULONG index;
+ ULONG count = 0;
+
+ // Count the number of entries in this bucket.
+
+ index = Hashtable->Buckets[i];
+
+ while (index != -1)
+ {
+ index = PH_HASHTABLE_GET_ENTRY(Hashtable, index)->Next;
+ count++;
+ }
+
+ if (count != 0)
+ {
+ expectedLookupMisses += count - 1;
+ }
+
+ if (count != 0)
+ {
+ wprintf(L"%lu: ", i);
+
+ // Print out the entry indicies.
+
+ index = Hashtable->Buckets[i];
+
+ while (index != -1)
+ {
+ wprintf(L"%lu", index);
+
+ index = PH_HASHTABLE_GET_ENTRY(Hashtable, index)->Next;
+ count--;
+
+ if (count != 0)
+ wprintf(L", ");
+ }
+
+ wprintf(L"\n");
+ }
+ else
+ {
+ //wprintf(L"%u: (empty)\n");
+ }
+ }
+
+ wprintf(L"\nExpected lookup misses: %lu\n", expectedLookupMisses);
+}
+
+#ifdef DEBUG
+static VOID PhpDebugCreateObjectHook(
+ _In_ PVOID Object,
+ _In_ SIZE_T Size,
+ _In_ ULONG Flags,
+ _In_ PPH_OBJECT_TYPE ObjectType
+ )
+{
+ PhAcquireQueuedLockExclusive(&NewObjectListLock);
+
+ if (NewObjectList)
+ {
+ PhReferenceObject(Object);
+ PhAddItemList(NewObjectList, Object);
+ }
+
+ PhReleaseQueuedLockExclusive(&NewObjectListLock);
+}
+#endif
+
+#ifdef DEBUG
+static VOID PhpDeleteNewObjectList(
+ VOID
+ )
+{
+ if (NewObjectList)
+ {
+ PhDereferenceObjects(NewObjectList->Items, NewObjectList->Count);
+ PhDereferenceObject(NewObjectList);
+ NewObjectList = NULL;
+ }
+}
+#endif
+
+static BOOLEAN PhpStringHashtableEqualFunction(
+ _In_ PVOID Entry1,
+ _In_ PVOID Entry2
+ )
+{
+ PSTRING_TABLE_ENTRY entry1 = Entry1;
+ PSTRING_TABLE_ENTRY entry2 = Entry2;
+
+ return PhEqualString(entry1->String, entry2->String, FALSE);
+}
+
+static ULONG PhpStringHashtableHashFunction(
+ _In_ PVOID Entry
+ )
+{
+ PSTRING_TABLE_ENTRY entry = Entry;
+
+ return PhHashBytes((PUCHAR)entry->String->Buffer, entry->String->Length);
+}
+
+static int __cdecl PhpStringEntryCompareByCount(
+ _In_ const void *elem1,
+ _In_ const void *elem2
+ )
+{
+ PSTRING_TABLE_ENTRY entry1 = *(PSTRING_TABLE_ENTRY *)elem1;
+ PSTRING_TABLE_ENTRY entry2 = *(PSTRING_TABLE_ENTRY *)elem2;
+
+ return uintptrcmp(entry2->Count, entry1->Count);
+}
+
+static NTSTATUS PhpLeakEnumerationRoutine(
+ _In_ LONG Reserved,
+ _In_ PVOID HeapHandle,
+ _In_ PVOID BaseAddress,
+ _In_ SIZE_T BlockSize,
+ _In_ ULONG StackTraceDepth,
+ _In_ PVOID *StackTrace
+ )
+{
+ ULONG i;
+
+ if (!InLeakDetection)
+ return 0;
+
+ if (!HeapHandle) // means no more entries
+ return 0;
+
+ if (ShowAllLeaks || HeapHandle == PhHeapHandle)
+ {
+ wprintf(L"Leak at 0x%Ix (%Iu bytes). Stack trace:\n", (ULONG_PTR)BaseAddress, BlockSize);
+
+ for (i = 0; i < StackTraceDepth; i++)
+ {
+ PPH_STRING symbol;
+
+ symbol = PhGetSymbolFromAddress(DebugConsoleSymbolProvider, (ULONG64)StackTrace[i], NULL, NULL, NULL, NULL);
+
+ if (symbol)
+ wprintf(L"\t%s\n", symbol->Buffer);
+ else
+ wprintf(L"\t?\n");
+
+ PhDereferenceObject(symbol);
+ }
+
+ NumberOfLeaksShown++;
+ }
+
+ NumberOfLeaks++;
+
+ return 0;
+}
+
+typedef struct _STOPWATCH
+{
+ LARGE_INTEGER StartCounter;
+ LARGE_INTEGER EndCounter;
+ LARGE_INTEGER Frequency;
+} STOPWATCH, *PSTOPWATCH;
+
+static VOID PhInitializeStopwatch(
+ _Out_ PSTOPWATCH Stopwatch
+ )
+{
+ Stopwatch->StartCounter.QuadPart = 0;
+ Stopwatch->EndCounter.QuadPart = 0;
+}
+
+static VOID PhStartStopwatch(
+ _Inout_ PSTOPWATCH Stopwatch
+ )
+{
+ NtQueryPerformanceCounter(&Stopwatch->StartCounter, &Stopwatch->Frequency);
+}
+
+static VOID PhStopStopwatch(
+ _Inout_ PSTOPWATCH Stopwatch
+ )
+{
+ NtQueryPerformanceCounter(&Stopwatch->EndCounter, NULL);
+}
+
+static ULONG PhGetMillisecondsStopwatch(
+ _In_ PSTOPWATCH Stopwatch
+ )
+{
+ LARGE_INTEGER countsPerMs;
+
+ countsPerMs = Stopwatch->Frequency;
+ countsPerMs.QuadPart /= 1000;
+
+ return (ULONG)((Stopwatch->EndCounter.QuadPart - Stopwatch->StartCounter.QuadPart) /
+ countsPerMs.QuadPart);
+}
+
+typedef VOID (FASTCALL *PPHF_RW_LOCK_FUNCTION)(
+ _In_ PVOID Parameter
+ );
+
+typedef struct _RW_TEST_CONTEXT
+{
+ PWSTR Name;
+
+ PPHF_RW_LOCK_FUNCTION AcquireExclusive;
+ PPHF_RW_LOCK_FUNCTION AcquireShared;
+ PPHF_RW_LOCK_FUNCTION ReleaseExclusive;
+ PPHF_RW_LOCK_FUNCTION ReleaseShared;
+
+ PVOID Parameter;
+} RW_TEST_CONTEXT, *PRW_TEST_CONTEXT;
+
+static PH_BARRIER RwStartBarrier;
+static LONG RwReadersActive;
+static LONG RwWritersActive;
+
+static NTSTATUS PhpRwLockTestThreadStart(
+ _In_ PVOID Parameter
+ )
+{
+#define RW_ITERS 10000
+#define RW_READ_ITERS 100
+#define RW_WRITE_ITERS 10
+#define RW_READ_SPIN_ITERS 60
+#define RW_WRITE_SPIN_ITERS 200
+
+ RW_TEST_CONTEXT context = *(PRW_TEST_CONTEXT)Parameter;
+ ULONG i;
+ ULONG j;
+ ULONG k;
+ ULONG m;
+
+ PhWaitForBarrier(&RwStartBarrier, FALSE);
+
+ for (i = 0; i < RW_ITERS; i++)
+ {
+ for (j = 0; j < RW_READ_ITERS; j++)
+ {
+ // Read zone
+
+ context.AcquireShared(context.Parameter);
+ _InterlockedIncrement(&RwReadersActive);
+
+ for (m = 0; m < RW_READ_SPIN_ITERS; m++)
+ YieldProcessor();
+
+ if (RwWritersActive != 0)
+ {
+ wprintf(L"[fail]: writers active in read zone!\n");
+ NtWaitForSingleObject(NtCurrentProcess(), FALSE, NULL);
+ }
+
+ _InterlockedDecrement(&RwReadersActive);
+ context.ReleaseShared(context.Parameter);
+
+ // Spin for a while
+
+ for (m = 0; m < 10; m++)
+ YieldProcessor();
+
+ if (j == RW_READ_ITERS / 2)
+ {
+ // Write zone
+
+ for (k = 0; k < RW_WRITE_ITERS; k++)
+ {
+ context.AcquireExclusive(context.Parameter);
+ _InterlockedIncrement(&RwWritersActive);
+
+ for (m = 0; m < RW_WRITE_SPIN_ITERS; m++)
+ YieldProcessor();
+
+ if (RwReadersActive != 0)
+ {
+ wprintf(L"[fail]: readers active in write zone!\n");
+ NtWaitForSingleObject(NtCurrentProcess(), FALSE, NULL);
+ }
+
+ _InterlockedDecrement(&RwWritersActive);
+ context.ReleaseExclusive(context.Parameter);
+ }
+ }
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+static VOID PhpTestRwLock(
+ _In_ PRW_TEST_CONTEXT Context
+ )
+{
+#define RW_PROCESSORS 4
+
+ STOPWATCH stopwatch;
+ ULONG i;
+ HANDLE threadHandles[RW_PROCESSORS];
+
+ // Dummy
+
+ Context->AcquireExclusive(Context->Parameter);
+ Context->ReleaseExclusive(Context->Parameter);
+ Context->AcquireShared(Context->Parameter);
+ Context->ReleaseShared(Context->Parameter);
+
+ // Null test
+ PhInitializeStopwatch(&stopwatch);
+ PhStartStopwatch(&stopwatch);
+
+ for (i = 0; i < 2000000; i++)
+ {
+ Context->AcquireExclusive(Context->Parameter);
+ Context->ReleaseExclusive(Context->Parameter);
+ Context->AcquireShared(Context->Parameter);
+ Context->ReleaseShared(Context->Parameter);
+ }
+
+ PhStopStopwatch(&stopwatch);
+
+ wprintf(L"[null] %s: %ums\n", Context->Name, PhGetMillisecondsStopwatch(&stopwatch));
+
+ // Stress test
+
+ PhInitializeBarrier(&RwStartBarrier, RW_PROCESSORS + 1);
+ RwReadersActive = 0;
+ RwWritersActive = 0;
+
+ for (i = 0; i < RW_PROCESSORS; i++)
+ {
+ PhCreateThreadEx(&threadHandles[i], PhpRwLockTestThreadStart, Context);
+ }
+
+ PhWaitForBarrier(&RwStartBarrier, FALSE);
+ PhInitializeStopwatch(&stopwatch);
+ PhStartStopwatch(&stopwatch);
+ NtWaitForMultipleObjects(RW_PROCESSORS, threadHandles, WaitAll, FALSE, NULL);
+ PhStopStopwatch(&stopwatch);
+
+ for (i = 0; i < RW_PROCESSORS; i++)
+ NtClose(threadHandles[i]);
+
+ wprintf(L"[strs] %s: %ums\n", Context->Name, PhGetMillisecondsStopwatch(&stopwatch));
+}
+
+VOID FASTCALL PhfAcquireCriticalSection(
+ _In_ PRTL_CRITICAL_SECTION CriticalSection
+ )
+{
+ RtlEnterCriticalSection(CriticalSection);
+}
+
+VOID FASTCALL PhfReleaseCriticalSection(
+ _In_ PRTL_CRITICAL_SECTION CriticalSection
+ )
+{
+ RtlLeaveCriticalSection(CriticalSection);
+}
+
+VOID FASTCALL PhfReleaseQueuedLockExclusiveUsingInline(
+ _In_ PPH_QUEUED_LOCK QueuedLock
+ )
+{
+ PhReleaseQueuedLockExclusive(QueuedLock);
+}
+
+NTSTATUS PhpDebugConsoleThreadStart(
+ _In_ PVOID Parameter
+ )
+{
+ PH_AUTO_POOL autoPool;
+ BOOLEAN exit = FALSE;
+
+ PhInitializeAutoPool(&autoPool);
+
+ DebugConsoleSymbolProvider = PhCreateSymbolProvider(NtCurrentProcessId());
+ PhLoadSymbolProviderOptions(DebugConsoleSymbolProvider);
+
+ {
+ static UNICODE_STRING variableNameUs = RTL_CONSTANT_STRING(L"_NT_SYMBOL_PATH");
+ UNICODE_STRING variableValueUs;
+ PPH_STRING newSearchPath;
+ WCHAR buffer[MAX_PATH];
+
+ RtlInitEmptyUnicodeString(&variableValueUs, buffer, sizeof(buffer));
+
+ if (NT_SUCCESS(RtlQueryEnvironmentVariable_U(NULL, &variableNameUs, &variableValueUs)))
+ {
+ PPH_STRING currentDirectory = PhGetApplicationDirectory();
+ PPH_STRING currentSearchPath = PhGetStringSetting(L"DbgHelpSearchPath");
+
+ if (currentSearchPath->Length != 0)
+ {
+ newSearchPath = PhFormatString(
+ L"%s;%s;%s",
+ buffer,
+ PhGetStringOrEmpty(currentSearchPath),
+ PhGetStringOrEmpty(currentDirectory)
+ );
+ }
+ else
+ {
+ newSearchPath = PhFormatString(
+ L"%s;%s",
+ buffer,
+ PhGetStringOrEmpty(currentDirectory)
+ );
+ }
+
+ PhSetSearchPathSymbolProvider(DebugConsoleSymbolProvider, PhGetString(newSearchPath));
+
+ PhDereferenceObject(newSearchPath);
+ PhDereferenceObject(currentDirectory);
+ }
+ }
+
+ PhEnumGenericModules(
+ NtCurrentProcessId(),
+ NtCurrentProcess(),
+ 0,
+ PhpLoadCurrentProcessSymbolsCallback,
+ DebugConsoleSymbolProvider
+ );
+
+#ifdef DEBUG
+ PhInitializeQueuedLock(&NewObjectListLock);
+ PhDbgCreateObjectHook = PhpDebugCreateObjectHook;
+#endif
+
+ wprintf(L"Press Ctrl+C or type \"exit\" to close the debug console. Type \"help\" for a list of commands.\n");
+
+ while (!exit)
+ {
+ static PWSTR delims = L" \t";
+ static PWSTR commandDebugOnly = L"This command is not available on non-debug builds.\n";
+
+ WCHAR line[201];
+ ULONG inputLength;
+ PWSTR context;
+ PWSTR command;
+
+ wprintf(L"dbg>");
+
+ if (!fgetws(line, sizeof(line) / sizeof(WCHAR) - 1, stdin))
+ break;
+
+ // Remove the terminating new line character.
+
+ inputLength = (ULONG)PhCountStringZ(line);
+
+ if (inputLength != 0)
+ line[inputLength - 1] = UNICODE_NULL;
+
+ context = NULL;
+ command = wcstok_s(line, delims, &context);
+
+ if (!command)
+ {
+ continue;
+ }
+ else if (PhEqualStringZ(command, L"help", TRUE))
+ {
+ wprintf(
+ L"Commands:\n"
+ L"exit\n"
+ L"testperf\n"
+ L"testlocks\n"
+ L"stats\n"
+ L"objects [type-name-filter]\n"
+ L"objtrace object-address\n"
+ L"objmksnap\n"
+ L"objcmpsnap\n"
+ L"objmknew\n"
+ L"objdelnew\n"
+ L"objviewnew\n"
+ L"dumpobj\n"
+ L"dumpautopool\n"
+ L"threads\n"
+ L"provthreads\n"
+ L"workqueues\n"
+ L"procrecords\n"
+ L"procitem\n"
+ L"uniquestr\n"
+ L"enableleakdetect\n"
+ L"leakdetect\n"
+ L"mem\n"
+ );
+ }
+ else if (PhEqualStringZ(command, L"exit", TRUE))
+ {
+ PhCloseDebugConsole();
+ exit = TRUE;
+ }
+ else if (PhEqualStringZ(command, L"testperf", TRUE))
+ {
+ STOPWATCH stopwatch;
+ ULONG i;
+ PPH_STRING testString;
+ RTL_CRITICAL_SECTION testCriticalSection;
+ PH_FAST_LOCK testFastLock;
+ PH_QUEUED_LOCK testQueuedLock;
+
+ // Control (string reference counting)
+
+ testString = PhCreateString(L"");
+ PhReferenceObject(testString);
+ PhDereferenceObject(testString);
+ PhStartStopwatch(&stopwatch);
+
+ for (i = 0; i < 10000000; i++)
+ {
+ PhReferenceObject(testString);
+ PhDereferenceObject(testString);
+ }
+
+ PhStopStopwatch(&stopwatch);
+ PhDereferenceObject(testString);
+
+ wprintf(L"Referencing: %ums\n", PhGetMillisecondsStopwatch(&stopwatch));
+
+ // Critical section
+
+ RtlInitializeCriticalSection(&testCriticalSection);
+ RtlEnterCriticalSection(&testCriticalSection);
+ RtlLeaveCriticalSection(&testCriticalSection);
+ PhStartStopwatch(&stopwatch);
+
+ for (i = 0; i < 10000000; i++)
+ {
+ RtlEnterCriticalSection(&testCriticalSection);
+ RtlLeaveCriticalSection(&testCriticalSection);
+ }
+
+ PhStopStopwatch(&stopwatch);
+ RtlDeleteCriticalSection(&testCriticalSection);
+
+ wprintf(L"Critical section: %ums\n", PhGetMillisecondsStopwatch(&stopwatch));
+
+ // Fast lock
+
+ PhInitializeFastLock(&testFastLock);
+ PhAcquireFastLockExclusive(&testFastLock);
+ PhReleaseFastLockExclusive(&testFastLock);
+ PhStartStopwatch(&stopwatch);
+
+ for (i = 0; i < 10000000; i++)
+ {
+ PhAcquireFastLockExclusive(&testFastLock);
+ PhReleaseFastLockExclusive(&testFastLock);
+ }
+
+ PhStopStopwatch(&stopwatch);
+ PhDeleteFastLock(&testFastLock);
+
+ wprintf(L"Fast lock: %ums\n", PhGetMillisecondsStopwatch(&stopwatch));
+
+ // Queued lock
+
+ PhInitializeQueuedLock(&testQueuedLock);
+ PhAcquireQueuedLockExclusive(&testQueuedLock);
+ PhReleaseQueuedLockExclusive(&testQueuedLock);
+ PhStartStopwatch(&stopwatch);
+
+ for (i = 0; i < 10000000; i++)
+ {
+ PhAcquireQueuedLockExclusive(&testQueuedLock);
+ PhReleaseQueuedLockExclusive(&testQueuedLock);
+ }
+
+ PhStopStopwatch(&stopwatch);
+
+ wprintf(L"Queued lock: %ums\n", PhGetMillisecondsStopwatch(&stopwatch));
+ }
+ else if (PhEqualStringZ(command, L"testlocks", TRUE))
+ {
+ RW_TEST_CONTEXT testContext;
+ PH_FAST_LOCK fastLock;
+ PH_QUEUED_LOCK queuedLock;
+ RTL_CRITICAL_SECTION criticalSection;
+
+ testContext.Name = L"FastLock";
+ testContext.AcquireExclusive = PhfAcquireFastLockExclusive;
+ testContext.AcquireShared = PhfAcquireFastLockShared;
+ testContext.ReleaseExclusive = PhfReleaseFastLockExclusive;
+ testContext.ReleaseShared = PhfReleaseFastLockShared;
+ testContext.Parameter = &fastLock;
+ PhInitializeFastLock(&fastLock);
+ PhpTestRwLock(&testContext);
+ PhDeleteFastLock(&fastLock);
+
+ testContext.Name = L"QueuedLock";
+ testContext.AcquireExclusive = PhfAcquireQueuedLockExclusive;
+ testContext.AcquireShared = PhfAcquireQueuedLockShared;
+ testContext.ReleaseExclusive = PhfReleaseQueuedLockExclusive;
+ testContext.ReleaseShared = PhfReleaseQueuedLockShared;
+ testContext.Parameter = &queuedLock;
+ PhInitializeQueuedLock(&queuedLock);
+ PhpTestRwLock(&testContext);
+
+ testContext.Name = L"CriticalSection";
+ testContext.AcquireExclusive = PhfAcquireCriticalSection;
+ testContext.AcquireShared = PhfAcquireCriticalSection;
+ testContext.ReleaseExclusive = PhfReleaseCriticalSection;
+ testContext.ReleaseShared = PhfReleaseCriticalSection;
+ testContext.Parameter = &criticalSection;
+ RtlInitializeCriticalSection(&criticalSection);
+ PhpTestRwLock(&testContext);
+ RtlDeleteCriticalSection(&criticalSection);
+
+ testContext.Name = L"QueuedLockMutex";
+ testContext.AcquireExclusive = PhfAcquireQueuedLockExclusive;
+ testContext.AcquireShared = PhfAcquireQueuedLockExclusive;
+ testContext.ReleaseExclusive = PhfReleaseQueuedLockExclusive;
+ testContext.ReleaseShared = PhfReleaseQueuedLockExclusive;
+ testContext.Parameter = &queuedLock;
+ PhInitializeQueuedLock(&queuedLock);
+ PhpTestRwLock(&testContext);
+ }
+ else if (PhEqualStringZ(command, L"stats", TRUE))
+ {
+#ifdef DEBUG
+ wprintf(L"Object small free list count: %u\n", PhObjectSmallFreeList.Count);
+ wprintf(L"Statistics:\n");
+#define PRINT_STATISTIC(Name) wprintf(L#Name L": %u\n", PhLibStatisticsBlock.Name);
+
+ PRINT_STATISTIC(BaseThreadsCreated);
+ PRINT_STATISTIC(BaseThreadsCreateFailed);
+ PRINT_STATISTIC(BaseStringBuildersCreated);
+ PRINT_STATISTIC(BaseStringBuildersResized);
+ PRINT_STATISTIC(RefObjectsCreated);
+ PRINT_STATISTIC(RefObjectsDestroyed);
+ PRINT_STATISTIC(RefObjectsAllocated);
+ PRINT_STATISTIC(RefObjectsFreed);
+ PRINT_STATISTIC(RefObjectsAllocatedFromSmallFreeList);
+ PRINT_STATISTIC(RefObjectsFreedToSmallFreeList);
+ PRINT_STATISTIC(RefObjectsAllocatedFromTypeFreeList);
+ PRINT_STATISTIC(RefObjectsFreedToTypeFreeList);
+ PRINT_STATISTIC(RefObjectsDeleteDeferred);
+ PRINT_STATISTIC(RefAutoPoolsCreated);
+ PRINT_STATISTIC(RefAutoPoolsDestroyed);
+ PRINT_STATISTIC(RefAutoPoolsDynamicAllocated);
+ PRINT_STATISTIC(RefAutoPoolsDynamicResized);
+ PRINT_STATISTIC(QlBlockSpins);
+ PRINT_STATISTIC(QlBlockWaits);
+ PRINT_STATISTIC(QlAcquireExclusiveBlocks);
+ PRINT_STATISTIC(QlAcquireSharedBlocks);
+ PRINT_STATISTIC(WqWorkQueueThreadsCreated);
+ PRINT_STATISTIC(WqWorkQueueThreadsCreateFailed);
+ PRINT_STATISTIC(WqWorkItemsQueued);
+
+#else
+ wprintf(commandDebugOnly);
+#endif
+ }
+ else if (PhEqualStringZ(command, L"objects", TRUE))
+ {
+#ifdef DEBUG
+ PWSTR typeFilter = wcstok_s(NULL, delims, &context);
+ PLIST_ENTRY currentEntry;
+ ULONG totalNumberOfObjects = 0;
+ //SIZE_T totalNumberOfBytes = 0;
+
+ if (typeFilter)
+ _wcslwr(typeFilter);
+
+ PhAcquireQueuedLockShared(&PhDbgObjectListLock);
+
+ currentEntry = PhDbgObjectListHead.Flink;
+
+ while (currentEntry != &PhDbgObjectListHead)
+ {
+ PPH_OBJECT_HEADER objectHeader;
+ WCHAR typeName[32];
+
+ objectHeader = CONTAINING_RECORD(currentEntry, PH_OBJECT_HEADER, ObjectListEntry);
+
+ // Make sure the object isn't being destroyed.
+ if (!PhReferenceObjectSafe(PhObjectHeaderToObject(objectHeader)))
+ {
+ currentEntry = currentEntry->Flink;
+ continue;
+ }
+
+ totalNumberOfObjects++;
+ //totalNumberOfBytes += objectHeader->Size;
+
+ if (typeFilter)
+ {
+ wcscpy_s(typeName, sizeof(typeName) / sizeof(WCHAR), PhGetObjectType(PhObjectHeaderToObject(objectHeader))->Name);
+ _wcslwr(typeName);
+ }
+
+ if (
+ !typeFilter ||
+ (typeFilter && wcsstr(typeName, typeFilter))
+ )
+ {
+ PhpPrintObjectInfo(objectHeader, 1);
+ }
+
+ currentEntry = currentEntry->Flink;
+ PhDereferenceObjectDeferDelete(PhObjectHeaderToObject(objectHeader));
+ }
+
+ PhReleaseQueuedLockShared(&PhDbgObjectListLock);
+
+ wprintf(L"\n");
+ wprintf(L"Total number: %lu\n", totalNumberOfObjects);
+ /*wprintf(L"Total size (excl. header): %s\n",
+ ((PPH_STRING)PH_AUTO(PhFormatSize(totalNumberOfBytes, 1)))->Buffer);*/
+ wprintf(L"Total overhead (header): %s\n",
+ ((PPH_STRING)PH_AUTO(
+ PhFormatSize(PhAddObjectHeaderSize(0) * totalNumberOfObjects, 1)
+ ))->Buffer);
+#else
+ wprintf(commandDebugOnly);
+#endif
+ }
+ else if (PhEqualStringZ(command, L"objtrace", TRUE))
+ {
+#ifdef DEBUG
+ PWSTR objectAddress = wcstok_s(NULL, delims, &context);
+ PH_STRINGREF objectAddressString;
+ ULONG64 address;
+
+ if (!objectAddress)
+ {
+ wprintf(L"Missing object address.\n");
+ goto EndCommand;
+ }
+
+ PhInitializeStringRef(&objectAddressString, objectAddress);
+
+ if (PhStringToInteger64(&objectAddressString, 16, &address))
+ {
+ PPH_OBJECT_HEADER objectHeader = (PPH_OBJECT_HEADER)PhObjectToObjectHeader((PVOID)address);
+ PVOID stackBackTrace[16];
+ ULONG i;
+
+ // The address may not be valid.
+ __try
+ {
+ memcpy(stackBackTrace, objectHeader->StackBackTrace, 16 * sizeof(PVOID));
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ PPH_STRING message;
+
+ message = PH_AUTO(PhGetNtMessage(GetExceptionCode()));
+ wprintf(L"Error: %s\n", PhGetString(message));
+
+ goto EndCommand;
+ }
+
+ for (i = 0; i < 16; i++)
+ {
+ if (!stackBackTrace[i])
+ break;
+
+ wprintf(L"%s\n", PhpGetSymbolForAddress(stackBackTrace[i]));
+ }
+ }
+ else
+ {
+ wprintf(L"Invalid object address.\n");
+ }
+#else
+ wprintf(commandDebugOnly);
+#endif
+ }
+ else if (PhEqualStringZ(command, L"objmksnap", TRUE))
+ {
+#ifdef DEBUG
+ PLIST_ENTRY currentEntry;
+
+ if (ObjectListSnapshot)
+ {
+ PhDereferenceObject(ObjectListSnapshot);
+ ObjectListSnapshot = NULL;
+ }
+
+ ObjectListSnapshot = PhCreateSimpleHashtable(100);
+
+ PhAcquireQueuedLockShared(&PhDbgObjectListLock);
+
+ currentEntry = PhDbgObjectListHead.Flink;
+
+ while (currentEntry != &PhDbgObjectListHead)
+ {
+ PPH_OBJECT_HEADER objectHeader;
+
+ objectHeader = CONTAINING_RECORD(currentEntry, PH_OBJECT_HEADER, ObjectListEntry);
+ currentEntry = currentEntry->Flink;
+
+ if (PhObjectHeaderToObject(objectHeader) != ObjectListSnapshot)
+ PhAddItemSimpleHashtable(ObjectListSnapshot, objectHeader, NULL);
+ }
+
+ PhReleaseQueuedLockShared(&PhDbgObjectListLock);
+#else
+ wprintf(commandDebugOnly);
+#endif
+ }
+ else if (PhEqualStringZ(command, L"objcmpsnap", TRUE))
+ {
+#ifdef DEBUG
+ PLIST_ENTRY currentEntry;
+ PPH_LIST newObjects;
+ ULONG i;
+
+ if (!ObjectListSnapshot)
+ {
+ wprintf(L"No snapshot.\n");
+ goto EndCommand;
+ }
+
+ newObjects = PhCreateList(10);
+
+ PhAcquireQueuedLockShared(&PhDbgObjectListLock);
+
+ currentEntry = PhDbgObjectListHead.Flink;
+
+ while (currentEntry != &PhDbgObjectListHead)
+ {
+ PPH_OBJECT_HEADER objectHeader;
+
+ objectHeader = CONTAINING_RECORD(currentEntry, PH_OBJECT_HEADER, ObjectListEntry);
+ currentEntry = currentEntry->Flink;
+
+ if (
+ PhObjectHeaderToObject(objectHeader) != ObjectListSnapshot &&
+ PhObjectHeaderToObject(objectHeader) != newObjects
+ )
+ {
+ if (!PhFindItemSimpleHashtable(ObjectListSnapshot, objectHeader))
+ {
+ if (PhReferenceObjectSafe(PhObjectHeaderToObject(objectHeader)))
+ PhAddItemList(newObjects, objectHeader);
+ }
+ }
+ }
+
+ PhReleaseQueuedLockShared(&PhDbgObjectListLock);
+
+ for (i = 0; i < newObjects->Count; i++)
+ {
+ PPH_OBJECT_HEADER objectHeader = newObjects->Items[i];
+
+ PhpPrintObjectInfo(objectHeader, 1);
+
+ PhDereferenceObject(PhObjectHeaderToObject(objectHeader));
+ }
+
+ PhDereferenceObject(newObjects);
+#else
+ wprintf(commandDebugOnly);
+#endif
+ }
+ else if (PhEqualStringZ(command, L"objmknew", TRUE))
+ {
+#ifdef DEBUG
+ PhAcquireQueuedLockExclusive(&NewObjectListLock);
+ PhpDeleteNewObjectList();
+ PhReleaseQueuedLockExclusive(&NewObjectListLock);
+
+ // Creation needs to be done outside of the lock,
+ // otherwise a deadlock will occur.
+ NewObjectList = PhCreateList(100);
+#else
+ wprintf(commandDebugOnly);
+#endif
+ }
+ else if (PhEqualStringZ(command, L"objdelnew", TRUE))
+ {
+#ifdef DEBUG
+ PhAcquireQueuedLockExclusive(&NewObjectListLock);
+ PhpDeleteNewObjectList();
+ PhReleaseQueuedLockExclusive(&NewObjectListLock);
+#else
+ wprintf(commandDebugOnly);
+#endif
+ }
+ else if (PhEqualStringZ(command, L"objviewnew", TRUE))
+ {
+#ifdef DEBUG
+ ULONG i;
+
+ PhAcquireQueuedLockExclusive(&NewObjectListLock);
+
+ if (!NewObjectList)
+ {
+ wprintf(L"Object creation hooking not active.\n");
+ PhReleaseQueuedLockExclusive(&NewObjectListLock);
+ goto EndCommand;
+ }
+
+ for (i = 0; i < NewObjectList->Count; i++)
+ {
+ PhpPrintObjectInfo(PhObjectToObjectHeader(NewObjectList->Items[i]), 1);
+ }
+
+ PhReleaseQueuedLockExclusive(&NewObjectListLock);
+#else
+ wprintf(commandDebugOnly);
+#endif
+ }
+ else if (PhEqualStringZ(command, L"dumpobj", TRUE))
+ {
+ PWSTR addressString = wcstok_s(NULL, delims, &context);
+ PH_STRINGREF addressStringRef;
+ ULONG64 address;
+
+ if (!addressString)
+ goto EndCommand;
+
+ PhInitializeStringRef(&addressStringRef, addressString);
+
+ if (PhStringToInteger64(&addressStringRef, 16, &address))
+ {
+ PhpDumpObjectInfo((PPH_OBJECT_HEADER)PhObjectToObjectHeader((PVOID)address));
+ }
+ }
+ else if (PhEqualStringZ(command, L"dumpautopool", TRUE))
+ {
+ PWSTR addressString = wcstok_s(NULL, delims, &context);
+ PH_STRINGREF addressStringRef;
+ ULONG64 address;
+
+ if (!addressString)
+ goto EndCommand;
+
+ PhInitializeStringRef(&addressStringRef, addressString);
+
+ if (PhStringToInteger64(&addressStringRef, 16, &address))
+ {
+ PPH_AUTO_POOL userAutoPool = (PPH_AUTO_POOL)address;
+ ULONG i;
+
+ __try
+ {
+ wprintf(L"Static count: %u\n", userAutoPool->StaticCount);
+ wprintf(L"Dynamic count: %u\n", userAutoPool->DynamicCount);
+ wprintf(L"Dynamic allocated: %u\n", userAutoPool->DynamicAllocated);
+
+ wprintf(L"Static objects:\n");
+
+ for (i = 0; i < userAutoPool->StaticCount; i++)
+ PhpPrintObjectInfo(PhObjectToObjectHeader(userAutoPool->StaticObjects[i]), 0);
+
+ wprintf(L"Dynamic objects:\n");
+
+ for (i = 0; i < userAutoPool->DynamicCount; i++)
+ PhpPrintObjectInfo(PhObjectToObjectHeader(userAutoPool->DynamicObjects[i]), 0);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ goto EndCommand;
+ }
+ }
+ }
+ else if (PhEqualStringZ(command, L"threads", TRUE))
+ {
+#ifdef DEBUG
+ PLIST_ENTRY currentEntry;
+
+ PhAcquireQueuedLockShared(&PhDbgThreadListLock);
+
+ currentEntry = PhDbgThreadListHead.Flink;
+
+ while (currentEntry != &PhDbgThreadListHead)
+ {
+ PPHP_BASE_THREAD_DBG dbg;
+
+ dbg = CONTAINING_RECORD(currentEntry, PHP_BASE_THREAD_DBG, ListEntry);
+
+ wprintf(L"Thread %u\n", HandleToUlong(dbg->ClientId.UniqueThread));
+ wprintf(L"\tStart Address: %s\n", PhpGetSymbolForAddress(dbg->StartAddress));
+ wprintf(L"\tParameter: %Ix\n", (ULONG_PTR)dbg->Parameter);
+ wprintf(L"\tCurrent auto-pool: %Ix\n", (ULONG_PTR)dbg->CurrentAutoPool);
+
+ currentEntry = currentEntry->Flink;
+ }
+
+ PhReleaseQueuedLockShared(&PhDbgThreadListLock);
+#else
+ wprintf(commandDebugOnly);
+#endif
+ }
+ else if (PhEqualStringZ(command, L"provthreads", TRUE))
+ {
+#ifdef DEBUG
+ ULONG i;
+
+ if (PhDbgProviderList)
+ {
+ PhAcquireQueuedLockShared(&PhDbgProviderListLock);
+
+ for (i = 0; i < PhDbgProviderList->Count; i++)
+ {
+ PPH_PROVIDER_THREAD providerThread = PhDbgProviderList->Items[i];
+ THREAD_BASIC_INFORMATION basicInfo;
+ PLIST_ENTRY providerEntry;
+
+ if (providerThread->ThreadHandle)
+ {
+ PhGetThreadBasicInformation(providerThread->ThreadHandle, &basicInfo);
+ wprintf(L"Thread %u\n", HandleToUlong(basicInfo.ClientId.UniqueThread));
+ }
+ else
+ {
+ wprintf(L"Thread not running\n");
+ }
+
+ PhAcquireQueuedLockExclusive(&providerThread->Lock);
+
+ providerEntry = providerThread->ListHead.Flink;
+
+ while (providerEntry != &providerThread->ListHead)
+ {
+ PPH_PROVIDER_REGISTRATION registration;
+
+ registration = CONTAINING_RECORD(providerEntry, PH_PROVIDER_REGISTRATION, ListEntry);
+
+ wprintf(L"\tProvider registration at %Ix\n", (ULONG_PTR)registration);
+ wprintf(L"\t\tEnabled: %s\n", registration->Enabled ? L"Yes" : L"No");
+ wprintf(L"\t\tFunction: %s\n", PhpGetSymbolForAddress(registration->Function));
+
+ if (registration->Object)
+ {
+ wprintf(L"\t\tObject:\n");
+ PhpPrintObjectInfo(PhObjectToObjectHeader(registration->Object), 0);
+ }
+
+ providerEntry = providerEntry->Flink;
+ }
+
+ PhReleaseQueuedLockExclusive(&providerThread->Lock);
+
+ wprintf(L"\n");
+ }
+
+ PhReleaseQueuedLockShared(&PhDbgProviderListLock);
+ }
+#else
+ wprintf(commandDebugOnly);
+#endif
+ }
+ else if (PhEqualStringZ(command, L"workqueues", TRUE))
+ {
+#ifdef DEBUG
+ ULONG i;
+
+ if (PhDbgWorkQueueList)
+ {
+ PhAcquireQueuedLockShared(&PhDbgWorkQueueListLock);
+
+ for (i = 0; i < PhDbgWorkQueueList->Count; i++)
+ {
+ PPH_WORK_QUEUE workQueue = PhDbgWorkQueueList->Items[i];
+ PLIST_ENTRY workQueueItemEntry;
+
+ wprintf(L"Work queue at %s\n", PhpGetSymbolForAddress(workQueue));
+ wprintf(L"Maximum threads: %lu\n", workQueue->MaximumThreads);
+ wprintf(L"Minimum threads: %lu\n", workQueue->MinimumThreads);
+ wprintf(L"No work timeout: %lu\n", workQueue->NoWorkTimeout);
+
+ wprintf(L"Current threads: %lu\n", workQueue->CurrentThreads);
+ wprintf(L"Busy count: %lu\n", workQueue->BusyCount);
+
+ PhAcquireQueuedLockExclusive(&workQueue->QueueLock);
+
+ // List the items backwards.
+ workQueueItemEntry = workQueue->QueueListHead.Blink;
+
+ while (workQueueItemEntry != &workQueue->QueueListHead)
+ {
+ PPH_WORK_QUEUE_ITEM workQueueItem;
+
+ workQueueItem = CONTAINING_RECORD(workQueueItemEntry, PH_WORK_QUEUE_ITEM, ListEntry);
+
+ wprintf(L"\tWork queue item at %Ix\n", (ULONG_PTR)workQueueItem);
+ wprintf(L"\t\tFunction: %s\n", PhpGetSymbolForAddress(workQueueItem->Function));
+ wprintf(L"\t\tContext: %Ix\n", (ULONG_PTR)workQueueItem->Context);
+
+ workQueueItemEntry = workQueueItemEntry->Blink;
+ }
+
+ PhReleaseQueuedLockExclusive(&workQueue->QueueLock);
+
+ wprintf(L"\n");
+ }
+
+ PhReleaseQueuedLockShared(&PhDbgWorkQueueListLock);
+ }
+#else
+ wprintf(commandDebugOnly);
+#endif
+ }
+ else if (PhEqualStringZ(command, L"procrecords", TRUE))
+ {
+ PPH_PROCESS_RECORD record;
+ ULONG i;
+ SYSTEMTIME systemTime;
+ PPH_PROCESS_RECORD startRecord;
+
+ PhAcquireQueuedLockShared(&PhProcessRecordListLock);
+
+ for (i = 0; i < PhProcessRecordList->Count; i++)
+ {
+ record = (PPH_PROCESS_RECORD)PhProcessRecordList->Items[i];
+
+ PhLargeIntegerToLocalSystemTime(&systemTime, &record->CreateTime);
+ wprintf(L"Records for %s %s:\n",
+ ((PPH_STRING)PH_AUTO(PhFormatDate(&systemTime, NULL)))->Buffer,
+ ((PPH_STRING)PH_AUTO(PhFormatTime(&systemTime, NULL)))->Buffer
+ );
+
+ startRecord = record;
+
+ do
+ {
+ wprintf(L"\tRecord at %Ix: %s (%lu) (refs: %ld)\n", (ULONG_PTR)record, record->ProcessName->Buffer, HandleToUlong(record->ProcessId), record->RefCount);
+
+ if (record->FileName)
+ wprintf(L"\t\t%s\n", record->FileName->Buffer);
+
+ record = CONTAINING_RECORD(record->ListEntry.Flink, PH_PROCESS_RECORD, ListEntry);
+ } while (record != startRecord);
+ }
+
+ PhReleaseQueuedLockShared(&PhProcessRecordListLock);
+ }
+ else if (PhEqualStringZ(command, L"procitem", TRUE))
+ {
+ PWSTR filterString;
+ PH_STRINGREF filterRef;
+ ULONG64 filter64;
+ LONG_PTR processIdFilter = -9; // can't use -2, -1 or 0 because they're all used for process IDs
+ ULONG_PTR processAddressFilter = 0;
+ PWSTR imageNameFilter = NULL;
+ BOOLEAN showAll = FALSE;
+ PPH_PROCESS_ITEM *processes;
+ ULONG numberOfProcesses;
+ ULONG i;
+
+ filterString = wcstok_s(NULL, delims, &context);
+
+ if (filterString)
+ {
+ PhInitializeStringRef(&filterRef, filterString);
+
+ if (PhStringToInteger64(&filterRef, 10, &filter64))
+ processIdFilter = (LONG_PTR)filter64;
+ if (PhStringToInteger64(&filterRef, 16, &filter64))
+ processAddressFilter = (ULONG_PTR)filter64;
+
+ imageNameFilter = filterString;
+ }
+ else
+ {
+ showAll = TRUE;
+ }
+
+ PhEnumProcessItems(&processes, &numberOfProcesses);
+
+ for (i = 0; i < numberOfProcesses; i++)
+ {
+ PPH_PROCESS_ITEM process = processes[i];
+
+ if (
+ showAll ||
+ (processIdFilter != -9 && (LONG_PTR)process->ProcessId == processIdFilter) ||
+ (processAddressFilter != 0 && (ULONG_PTR)process == processAddressFilter) ||
+ (imageNameFilter && PhMatchWildcards(imageNameFilter, process->ProcessName->Buffer, TRUE))
+ )
+ {
+ wprintf(L"Process item at %Ix: %s (%u)\n", (ULONG_PTR)process, process->ProcessName->Buffer, HandleToUlong(process->ProcessId));
+ wprintf(L"\tRecord at %Ix\n", (ULONG_PTR)process->Record);
+ wprintf(L"\tQuery handle %Ix\n", (ULONG_PTR)process->QueryHandle);
+ wprintf(L"\tFile name at %Ix: %s\n", (ULONG_PTR)process->FileName, PhGetStringOrDefault(process->FileName, L"(null)"));
+ wprintf(L"\tCommand line at %Ix: %s\n", (ULONG_PTR)process->CommandLine, PhGetStringOrDefault(process->CommandLine, L"(null)"));
+ wprintf(L"\tFlags: %u\n", process->Flags);
+ wprintf(L"\n");
+ }
+ }
+
+ PhDereferenceObjects(processes, numberOfProcesses);
+ }
+ else if (PhEqualStringZ(command, L"uniquestr", TRUE))
+ {
+#ifdef DEBUG
+ PLIST_ENTRY currentEntry;
+ PPH_HASHTABLE hashtable;
+ PPH_LIST list;
+ PSTRING_TABLE_ENTRY stringEntry;
+ ULONG enumerationKey;
+ ULONG i;
+
+ hashtable = PhCreateHashtable(
+ sizeof(STRING_TABLE_ENTRY),
+ PhpStringHashtableEqualFunction,
+ PhpStringHashtableHashFunction,
+ 1024
+ );
+
+ PhAcquireQueuedLockShared(&PhDbgObjectListLock);
+
+ currentEntry = PhDbgObjectListHead.Flink;
+
+ while (currentEntry != &PhDbgObjectListHead)
+ {
+ PPH_OBJECT_HEADER objectHeader;
+ PPH_STRING string;
+ STRING_TABLE_ENTRY localStringEntry;
+ BOOLEAN added;
+
+ objectHeader = CONTAINING_RECORD(currentEntry, PH_OBJECT_HEADER, ObjectListEntry);
+ currentEntry = currentEntry->Flink;
+ string = PhObjectHeaderToObject(objectHeader);
+
+ // Make sure this is a string.
+ if (PhGetObjectType(string) != PhStringType)
+ continue;
+
+ // Make sure the object isn't being destroyed.
+ if (!PhReferenceObjectSafe(string))
+ continue;
+
+ localStringEntry.String = string;
+ stringEntry = PhAddEntryHashtableEx(hashtable, &localStringEntry, &added);
+
+ if (added)
+ {
+ stringEntry->Count = 1;
+ PhReferenceObject(string);
+ }
+ else
+ {
+ stringEntry->Count++;
+ }
+
+ PhDereferenceObjectDeferDelete(string);
+ }
+
+ PhReleaseQueuedLockShared(&PhDbgObjectListLock);
+
+ // Sort the string entries by count.
+
+ list = PhCreateList(hashtable->Count);
+
+ enumerationKey = 0;
+
+ while (PhEnumHashtable(hashtable, &stringEntry, &enumerationKey))
+ {
+ PhAddItemList(list, stringEntry);
+ }
+
+ qsort(list->Items, list->Count, sizeof(PSTRING_TABLE_ENTRY), PhpStringEntryCompareByCount);
+
+ // Display...
+
+ for (i = 0; i < 40 && i < list->Count; i++)
+ {
+ stringEntry = list->Items[i];
+ wprintf(L"%Iu\t%.64s\n", stringEntry->Count, stringEntry->String->Buffer);
+ }
+
+ wprintf(L"\nTotal unique strings: %u\n", list->Count);
+
+ // Cleanup
+
+ for (i = 0; i < list->Count; i++)
+ {
+ stringEntry = list->Items[i];
+ PhDereferenceObject(stringEntry->String);
+ }
+
+ PhDereferenceObject(list);
+ PhDereferenceObject(hashtable);
+#else
+ wprintf(commandDebugOnly);
+#endif
+ }
+ else if (PhEqualStringZ(command, L"enableleakdetect", TRUE))
+ {
+ HEAP_DEBUGGING_INFORMATION debuggingInfo;
+
+ memset(&debuggingInfo, 0, sizeof(HEAP_DEBUGGING_INFORMATION));
+ debuggingInfo.StackTraceDepth = 32;
+ debuggingInfo.HeapLeakEnumerationRoutine = PhpLeakEnumerationRoutine;
+
+ if (!NT_SUCCESS(RtlSetHeapInformation(NULL, HeapSetDebuggingInformation, &debuggingInfo, sizeof(HEAP_DEBUGGING_INFORMATION))))
+ {
+ wprintf(L"Unable to initialize heap debugging. Make sure that you are using Windows 7 or above.");
+ }
+ }
+ else if (PhEqualStringZ(command, L"leakdetect", TRUE))
+ {
+ VOID (NTAPI *rtlDetectHeapLeaks)(VOID);
+ PWSTR options = wcstok_s(NULL, delims, &context);
+
+ rtlDetectHeapLeaks = PhGetDllProcedureAddress(L"ntdll.dll", "RtlDetectHeapLeaks", 0);
+
+ if (!(NtCurrentPeb()->NtGlobalFlag & FLG_USER_STACK_TRACE_DB))
+ {
+ wprintf(L"Warning: user-mode stack trace database is not enabled. Stack traces will not be displayed.\n");
+ }
+
+ ShowAllLeaks = FALSE;
+
+ if (options)
+ {
+ if (PhEqualStringZ(options, L"all", TRUE))
+ ShowAllLeaks = TRUE;
+ }
+
+ if (rtlDetectHeapLeaks)
+ {
+ InLeakDetection = TRUE;
+ NumberOfLeaks = 0;
+ NumberOfLeaksShown = 0;
+ rtlDetectHeapLeaks();
+ InLeakDetection = FALSE;
+
+ wprintf(L"\nNumber of leaks: %lu (%lu displayed)\n", NumberOfLeaks, NumberOfLeaksShown);
+ }
+ }
+ else if (PhEqualStringZ(command, L"mem", TRUE))
+ {
+ PWSTR addressString;
+ PWSTR bytesString;
+ PH_STRINGREF addressStringRef;
+ PH_STRINGREF bytesStringRef;
+ ULONG64 address64;
+ ULONG64 numberOfBytes64;
+ PUCHAR address;
+ ULONG numberOfBytes;
+ ULONG blockSize;
+ UCHAR buffer[16];
+ ULONG i;
+
+ addressString = wcstok_s(NULL, delims, &context);
+
+ if (!addressString)
+ goto PrintMemUsage;
+
+ bytesString = wcstok_s(NULL, delims, &context);
+
+ if (!bytesString)
+ {
+ bytesString = L"16";
+ }
+
+ PhInitializeStringRef(&addressStringRef, addressString);
+ PhInitializeStringRef(&bytesStringRef, bytesString);
+
+ if (PhStringToInteger64(&addressStringRef, 16, &address64) && PhStringToInteger64(&bytesStringRef, 10, &numberOfBytes64))
+ {
+ address = (PUCHAR)address64;
+ numberOfBytes = (ULONG)numberOfBytes64;
+
+ if (numberOfBytes > 256)
+ {
+ wprintf(L"Number of bytes must be 256 or smaller.\n");
+ goto EndCommand;
+ }
+
+ blockSize = sizeof(buffer);
+
+ while (numberOfBytes != 0)
+ {
+ if (blockSize > numberOfBytes)
+ blockSize = numberOfBytes;
+
+ __try
+ {
+ memcpy(buffer, address, blockSize);
+ }
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ wprintf(L"Error reading address near %Ix.\n", (ULONG_PTR)address);
+ goto EndCommand;
+ }
+
+ // Print hex dump
+ for (i = 0; i < blockSize; i++)
+ wprintf(L"%02x ", buffer[i]);
+
+ // Fill remaining space (for last, possibly partial block)
+ for (; i < sizeof(buffer); i++)
+ wprintf(L" ");
+
+ wprintf(L" ");
+
+ // Print ASCII dump
+ for (i = 0; i < blockSize; i++)
+ putwchar((ULONG)(buffer[i] - ' ') <= (ULONG)('~' - ' ') ? buffer[i] : '.');
+
+ wprintf(L"\n");
+
+ address += blockSize;
+ numberOfBytes -= blockSize;
+ }
+ }
+
+ goto EndCommand;
+PrintMemUsage:
+ wprintf(L"Usage: mem address [numberOfBytes]\n");
+ wprintf(L"Example: mem 12345678 16\n");
+ }
+ else
+ {
+ wprintf(L"Unrecognized command.\n");
+ goto EndCommand; // get rid of the compiler warning about the label being unreferenced
+ }
+
+EndCommand:
+ PhDrainAutoPool(&autoPool);
+ }
+
+ PhDereferenceObject(DebugConsoleSymbolProvider);
+
+ PhDeleteAutoPool(&autoPool);
+
+ return STATUS_SUCCESS;
+}
diff --git a/ProcessHacker/extmgr.c b/ProcessHacker/extmgr.c
index 8d93706205d5..950d483b095d 100644
--- a/ProcessHacker/extmgr.c
+++ b/ProcessHacker/extmgr.c
@@ -1,226 +1,226 @@
-/*
- * Process Hacker -
- * extension manager
- *
- * 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 .
- */
-
-/*
- * The extension manager provides support for generic extensions. It sits directly
- * underneath the plugin manager, and has no knowledge of plugin details (how they are
- * loaded, plugin information, etc.).
- */
-
-#include
-#include
-
-LIST_ENTRY PhEmAppContextListHead = { &PhEmAppContextListHead, &PhEmAppContextListHead };
-ULONG PhEmAppContextCount = 0;
-PH_EM_OBJECT_TYPE_STATE PhEmObjectTypeState[EmMaximumObjectType] = { 0 };
-
-/**
- * Initializes the extension manager module.
- */
-VOID PhEmInitialization(
- VOID
- )
-{
- ULONG i;
-
- for (i = 0; i < EmMaximumObjectType; i++)
- {
- InitializeListHead(&PhEmObjectTypeState[i].ExtensionListHead);
- }
-}
-
-/**
- * Initializes an extension application context.
- *
- * \param AppContext The application context.
- * \param AppName The application name.
- */
-VOID PhEmInitializeAppContext(
- _Out_ PPH_EM_APP_CONTEXT AppContext,
- _In_ PPH_STRINGREF AppName
- )
-{
- AppContext->AppName = *AppName;
- memset(AppContext->Extensions, 0, sizeof(AppContext->Extensions));
-
- InsertTailList(&PhEmAppContextListHead, &AppContext->ListEntry);
- PhEmAppContextCount++;
-}
-
-/**
- * Sets the object extension size and callbacks for an object type.
- *
- * \param AppContext The application context.
- * \param ObjectType The type of object for which the extension is being registered.
- * \param ExtensionSize The size of the extension, in bytes.
- * \param CreateCallback The object creation callback.
- * \param DeleteCallback The object deletion callback.
- */
-VOID PhEmSetObjectExtension(
- _Inout_ PPH_EM_APP_CONTEXT AppContext,
- _In_ PH_EM_OBJECT_TYPE ObjectType,
- _In_ SIZE_T ExtensionSize,
- _In_opt_ PPH_EM_OBJECT_CALLBACK CreateCallback,
- _In_opt_ PPH_EM_OBJECT_CALLBACK DeleteCallback
- )
-{
- PPH_EM_OBJECT_TYPE_STATE objectTypeState;
- PPH_EM_OBJECT_EXTENSION objectExtension;
-
- objectTypeState = &PhEmObjectTypeState[ObjectType];
- objectExtension = AppContext->Extensions[ObjectType];
-
- if (!objectExtension)
- {
- objectExtension = PhAllocate(sizeof(PH_EM_OBJECT_EXTENSION));
- memset(objectExtension, 0, sizeof(PH_EM_OBJECT_EXTENSION));
- InsertTailList(&objectTypeState->ExtensionListHead, &objectExtension->ListEntry);
- AppContext->Extensions[ObjectType] = objectExtension;
-
- objectExtension->ExtensionSize = ExtensionSize;
- objectExtension->ExtensionOffset = objectTypeState->ExtensionOffset;
-
- objectTypeState->ExtensionOffset += ExtensionSize;
- }
-
- objectExtension->Callbacks[EmObjectCreate] = CreateCallback;
- objectExtension->Callbacks[EmObjectDelete] = DeleteCallback;
-}
-
-/**
- * Gets the object extension for an object.
- *
- * \param AppContext The application context.
- * \param ObjectType The type of object for which an extension has been registered.
- * \param Object The object.
- */
-PVOID PhEmGetObjectExtension(
- _In_ PPH_EM_APP_CONTEXT AppContext,
- _In_ PH_EM_OBJECT_TYPE ObjectType,
- _In_ PVOID Object
- )
-{
- PPH_EM_OBJECT_EXTENSION objectExtension;
-
- objectExtension = AppContext->Extensions[ObjectType];
-
- if (!objectExtension)
- return NULL;
-
- return (PCHAR)Object + PhEmObjectTypeState[ObjectType].InitialSize + objectExtension->ExtensionOffset;
-}
-
-/**
- * Determines the size of an object, including extensions.
- *
- * \param ObjectType The object type.
- * \param InitialSize The initial size of the object.
- */
-SIZE_T PhEmGetObjectSize(
- _In_ PH_EM_OBJECT_TYPE ObjectType,
- _In_ SIZE_T InitialSize
- )
-{
- PhEmObjectTypeState[ObjectType].InitialSize = InitialSize;
-
- return InitialSize + PhEmObjectTypeState[ObjectType].ExtensionOffset;
-}
-
-/**
- * Invokes callbacks for an object operation.
- *
- * \param ObjectType The object type.
- * \param Object The object.
- * \param Operation The operation being performed.
- */
-VOID PhEmCallObjectOperation(
- _In_ PH_EM_OBJECT_TYPE ObjectType,
- _In_ PVOID Object,
- _In_ PH_EM_OBJECT_OPERATION Operation
- )
-{
- PPH_EM_OBJECT_TYPE_STATE objectTypeState;
- PLIST_ENTRY listEntry;
- PPH_EM_OBJECT_EXTENSION objectExtension;
-
- if (PhEmAppContextCount == 0)
- return;
-
- objectTypeState = &PhEmObjectTypeState[ObjectType];
-
- listEntry = objectTypeState->ExtensionListHead.Flink;
-
- while (listEntry != &objectTypeState->ExtensionListHead)
- {
- objectExtension = CONTAINING_RECORD(listEntry, PH_EM_OBJECT_EXTENSION, ListEntry);
-
- if (objectExtension->Callbacks[Operation])
- {
- objectExtension->Callbacks[Operation](
- Object,
- ObjectType,
- (PCHAR)Object + objectTypeState->InitialSize + objectExtension->ExtensionOffset
- );
- }
-
- listEntry = listEntry->Flink;
- }
-}
-
-/**
- * Parses an application name and sub-ID pair.
- *
- * \param CompoundId The compound identifier.
- * \param AppName A variable which receives the application name.
- * \param SubId A variable which receives the sub-ID.
- */
-BOOLEAN PhEmParseCompoundId(
- _In_ PPH_STRINGREF CompoundId,
- _Out_ PPH_STRINGREF AppName,
- _Out_ PULONG SubId
- )
-{
- PH_STRINGREF firstPart;
- PH_STRINGREF secondPart;
- ULONG64 integer;
-
- firstPart = *CompoundId;
-
- if (firstPart.Length == 0)
- return FALSE;
- if (firstPart.Buffer[0] != '+')
- return FALSE;
-
- PhSkipStringRef(&firstPart, sizeof(WCHAR));
- PhSplitStringRefAtChar(&firstPart, '+', &firstPart, &secondPart);
-
- if (firstPart.Length == 0 || secondPart.Length == 0)
- return FALSE;
-
- if (!PhStringToInteger64(&secondPart, 10, &integer))
- return FALSE;
-
- *AppName = firstPart;
- *SubId = (ULONG)integer;
-
- return TRUE;
-}
+/*
+ * Process Hacker -
+ * extension manager
+ *
+ * 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 .
+ */
+
+/*
+ * The extension manager provides support for generic extensions. It sits directly
+ * underneath the plugin manager, and has no knowledge of plugin details (how they are
+ * loaded, plugin information, etc.).
+ */
+
+#include
+#include
+
+LIST_ENTRY PhEmAppContextListHead = { &PhEmAppContextListHead, &PhEmAppContextListHead };
+ULONG PhEmAppContextCount = 0;
+PH_EM_OBJECT_TYPE_STATE PhEmObjectTypeState[EmMaximumObjectType] = { 0 };
+
+/**
+ * Initializes the extension manager module.
+ */
+VOID PhEmInitialization(
+ VOID
+ )
+{
+ ULONG i;
+
+ for (i = 0; i < EmMaximumObjectType; i++)
+ {
+ InitializeListHead(&PhEmObjectTypeState[i].ExtensionListHead);
+ }
+}
+
+/**
+ * Initializes an extension application context.
+ *
+ * \param AppContext The application context.
+ * \param AppName The application name.
+ */
+VOID PhEmInitializeAppContext(
+ _Out_ PPH_EM_APP_CONTEXT AppContext,
+ _In_ PPH_STRINGREF AppName
+ )
+{
+ AppContext->AppName = *AppName;
+ memset(AppContext->Extensions, 0, sizeof(AppContext->Extensions));
+
+ InsertTailList(&PhEmAppContextListHead, &AppContext->ListEntry);
+ PhEmAppContextCount++;
+}
+
+/**
+ * Sets the object extension size and callbacks for an object type.
+ *
+ * \param AppContext The application context.
+ * \param ObjectType The type of object for which the extension is being registered.
+ * \param ExtensionSize The size of the extension, in bytes.
+ * \param CreateCallback The object creation callback.
+ * \param DeleteCallback The object deletion callback.
+ */
+VOID PhEmSetObjectExtension(
+ _Inout_ PPH_EM_APP_CONTEXT AppContext,
+ _In_ PH_EM_OBJECT_TYPE ObjectType,
+ _In_ SIZE_T ExtensionSize,
+ _In_opt_ PPH_EM_OBJECT_CALLBACK CreateCallback,
+ _In_opt_ PPH_EM_OBJECT_CALLBACK DeleteCallback
+ )
+{
+ PPH_EM_OBJECT_TYPE_STATE objectTypeState;
+ PPH_EM_OBJECT_EXTENSION objectExtension;
+
+ objectTypeState = &PhEmObjectTypeState[ObjectType];
+ objectExtension = AppContext->Extensions[ObjectType];
+
+ if (!objectExtension)
+ {
+ objectExtension = PhAllocate(sizeof(PH_EM_OBJECT_EXTENSION));
+ memset(objectExtension, 0, sizeof(PH_EM_OBJECT_EXTENSION));
+ InsertTailList(&objectTypeState->ExtensionListHead, &objectExtension->ListEntry);
+ AppContext->Extensions[ObjectType] = objectExtension;
+
+ objectExtension->ExtensionSize = ExtensionSize;
+ objectExtension->ExtensionOffset = objectTypeState->ExtensionOffset;
+
+ objectTypeState->ExtensionOffset += ExtensionSize;
+ }
+
+ objectExtension->Callbacks[EmObjectCreate] = CreateCallback;
+ objectExtension->Callbacks[EmObjectDelete] = DeleteCallback;
+}
+
+/**
+ * Gets the object extension for an object.
+ *
+ * \param AppContext The application context.
+ * \param ObjectType The type of object for which an extension has been registered.
+ * \param Object The object.
+ */
+PVOID PhEmGetObjectExtension(
+ _In_ PPH_EM_APP_CONTEXT AppContext,
+ _In_ PH_EM_OBJECT_TYPE ObjectType,
+ _In_ PVOID Object
+ )
+{
+ PPH_EM_OBJECT_EXTENSION objectExtension;
+
+ objectExtension = AppContext->Extensions[ObjectType];
+
+ if (!objectExtension)
+ return NULL;
+
+ return PTR_ADD_OFFSET(Object, PhEmObjectTypeState[ObjectType].InitialSize + objectExtension->ExtensionOffset);
+}
+
+/**
+ * Determines the size of an object, including extensions.
+ *
+ * \param ObjectType The object type.
+ * \param InitialSize The initial size of the object.
+ */
+SIZE_T PhEmGetObjectSize(
+ _In_ PH_EM_OBJECT_TYPE ObjectType,
+ _In_ SIZE_T InitialSize
+ )
+{
+ PhEmObjectTypeState[ObjectType].InitialSize = InitialSize;
+
+ return InitialSize + PhEmObjectTypeState[ObjectType].ExtensionOffset;
+}
+
+/**
+ * Invokes callbacks for an object operation.
+ *
+ * \param ObjectType The object type.
+ * \param Object The object.
+ * \param Operation The operation being performed.
+ */
+VOID PhEmCallObjectOperation(
+ _In_ PH_EM_OBJECT_TYPE ObjectType,
+ _In_ PVOID Object,
+ _In_ PH_EM_OBJECT_OPERATION Operation
+ )
+{
+ PPH_EM_OBJECT_TYPE_STATE objectTypeState;
+ PLIST_ENTRY listEntry;
+ PPH_EM_OBJECT_EXTENSION objectExtension;
+
+ if (PhEmAppContextCount == 0)
+ return;
+
+ objectTypeState = &PhEmObjectTypeState[ObjectType];
+
+ listEntry = objectTypeState->ExtensionListHead.Flink;
+
+ while (listEntry != &objectTypeState->ExtensionListHead)
+ {
+ objectExtension = CONTAINING_RECORD(listEntry, PH_EM_OBJECT_EXTENSION, ListEntry);
+
+ if (objectExtension->Callbacks[Operation])
+ {
+ objectExtension->Callbacks[Operation](
+ Object,
+ ObjectType,
+ PTR_ADD_OFFSET(Object, objectTypeState->InitialSize + objectExtension->ExtensionOffset)
+ );
+ }
+
+ listEntry = listEntry->Flink;
+ }
+}
+
+/**
+ * Parses an application name and sub-ID pair.
+ *
+ * \param CompoundId The compound identifier.
+ * \param AppName A variable which receives the application name.
+ * \param SubId A variable which receives the sub-ID.
+ */
+BOOLEAN PhEmParseCompoundId(
+ _In_ PPH_STRINGREF CompoundId,
+ _Out_ PPH_STRINGREF AppName,
+ _Out_ PULONG SubId
+ )
+{
+ PH_STRINGREF firstPart;
+ PH_STRINGREF secondPart;
+ ULONG64 integer;
+
+ firstPart = *CompoundId;
+
+ if (firstPart.Length == 0)
+ return FALSE;
+ if (firstPart.Buffer[0] != '+')
+ return FALSE;
+
+ PhSkipStringRef(&firstPart, sizeof(WCHAR));
+ PhSplitStringRefAtChar(&firstPart, '+', &firstPart, &secondPart);
+
+ if (firstPart.Length == 0 || secondPart.Length == 0)
+ return FALSE;
+
+ if (!PhStringToInteger64(&secondPart, 10, &integer))
+ return FALSE;
+
+ *AppName = firstPart;
+ *SubId = (ULONG)integer;
+
+ return TRUE;
+}
diff --git a/ProcessHacker/findobj.c b/ProcessHacker/findobj.c
index 98c68b117ee3..50311eee5b28 100644
--- a/ProcessHacker/findobj.c
+++ b/ProcessHacker/findobj.c
@@ -1,1016 +1,1659 @@
-/*
- * Process Hacker -
- * object search
- *
- * Copyright (C) 2010-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 .
- */
-
-#include
-
-#include
-
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "pcre/pcre2.h"
-
-#define WM_PH_SEARCH_UPDATE (WM_APP + 801)
-#define WM_PH_SEARCH_FINISHED (WM_APP + 802)
-
-typedef enum _PHP_OBJECT_RESULT_TYPE
-{
- HandleSearchResult,
- ModuleSearchResult,
- MappedFileSearchResult
-} PHP_OBJECT_RESULT_TYPE;
-
-typedef struct _PHP_OBJECT_SEARCH_RESULT
-{
- HANDLE ProcessId;
- PHP_OBJECT_RESULT_TYPE ResultType;
-
- HANDLE Handle;
- PPH_STRING TypeName;
- PPH_STRING Name;
- PPH_STRING ProcessName;
-
- WCHAR HandleString[PH_PTR_STR_LEN_1];
-
- SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Info;
-} PHP_OBJECT_SEARCH_RESULT, *PPHP_OBJECT_SEARCH_RESULT;
-
-INT_PTR CALLBACK PhpFindObjectsDlgProc(
- _In_ HWND hwndDlg,
- _In_ UINT uMsg,
- _In_ WPARAM wParam,
- _In_ LPARAM lParam
- );
-
-NTSTATUS PhpFindObjectsThreadStart(
- _In_ PVOID Parameter
- );
-
-HWND PhFindObjectsWindowHandle = NULL;
-HWND PhFindObjectsListViewHandle = NULL;
-static PH_LAYOUT_MANAGER WindowLayoutManager;
-static RECT MinimumSize;
-
-static HANDLE SearchThreadHandle = NULL;
-static BOOLEAN SearchStop;
-static PPH_STRING SearchString;
-static pcre2_code *SearchRegexCompiledExpression;
-static pcre2_match_data *SearchRegexMatchData;
-static PPH_LIST SearchResults = NULL;
-static ULONG SearchResultsAddIndex;
-static PH_QUEUED_LOCK SearchResultsLock = PH_QUEUED_LOCK_INIT;
-
-static ULONG64 SearchPointer;
-static BOOLEAN UseSearchPointer;
-
-VOID PhShowFindObjectsDialog(
- VOID
- )
-{
- if (!PhFindObjectsWindowHandle)
- {
- PhFindObjectsWindowHandle = CreateDialog(
- PhInstanceHandle,
- MAKEINTRESOURCE(IDD_FINDOBJECTS),
- PhMainWndHandle,
- PhpFindObjectsDlgProc
- );
- }
-
- if (!IsWindowVisible(PhFindObjectsWindowHandle))
- ShowWindow(PhFindObjectsWindowHandle, SW_SHOW);
-
- SetForegroundWindow(PhFindObjectsWindowHandle);
-}
-
-VOID PhpInitializeFindObjMenu(
- _In_ PPH_EMENU Menu,
- _In_ PPHP_OBJECT_SEARCH_RESULT *Results,
- _In_ ULONG NumberOfResults
- )
-{
- BOOLEAN allCanBeClosed = TRUE;
- ULONG i;
-
- if (NumberOfResults == 1)
- {
- PH_HANDLE_ITEM_INFO info;
-
- info.ProcessId = Results[0]->ProcessId;
- info.Handle = Results[0]->Handle;
- info.TypeName = Results[0]->TypeName;
- info.BestObjectName = Results[0]->Name;
- PhInsertHandleObjectPropertiesEMenuItems(Menu, ID_OBJECT_PROPERTIES, FALSE, &info);
- }
- else
- {
- PhSetFlagsAllEMenuItems(Menu, PH_EMENU_DISABLED, PH_EMENU_DISABLED);
- PhEnableEMenuItem(Menu, ID_OBJECT_COPY, TRUE);
- }
-
- for (i = 0; i < NumberOfResults; i++)
- {
- if (Results[i]->ResultType != HandleSearchResult)
- {
- allCanBeClosed = FALSE;
- break;
- }
- }
-
- PhEnableEMenuItem(Menu, ID_OBJECT_CLOSE, allCanBeClosed);
-}
-
-INT NTAPI PhpObjectProcessCompareFunction(
- _In_ PVOID Item1,
- _In_ PVOID Item2,
- _In_opt_ PVOID Context
- )
-{
- PPHP_OBJECT_SEARCH_RESULT item1 = Item1;
- PPHP_OBJECT_SEARCH_RESULT item2 = Item2;
- INT result;
-
- result = PhCompareStringWithNull(item1->ProcessName, item2->ProcessName, TRUE);
-
- if (result != 0)
- return result;
- else
- return uintptrcmp((ULONG_PTR)item1->ProcessId, (ULONG_PTR)item2->ProcessId);
-}
-
-INT NTAPI PhpObjectTypeCompareFunction(
- _In_ PVOID Item1,
- _In_ PVOID Item2,
- _In_opt_ PVOID Context
- )
-{
- PPHP_OBJECT_SEARCH_RESULT item1 = Item1;
- PPHP_OBJECT_SEARCH_RESULT item2 = Item2;
-
- return PhCompareString(item1->TypeName, item2->TypeName, TRUE);
-}
-
-INT NTAPI PhpObjectNameCompareFunction(
- _In_ PVOID Item1,
- _In_ PVOID Item2,
- _In_opt_ PVOID Context
- )
-{
- PPHP_OBJECT_SEARCH_RESULT item1 = Item1;
- PPHP_OBJECT_SEARCH_RESULT item2 = Item2;
-
- return PhCompareString(item1->Name, item2->Name, TRUE);
-}
-
-INT NTAPI PhpObjectHandleCompareFunction(
- _In_ PVOID Item1,
- _In_ PVOID Item2,
- _In_opt_ PVOID Context
- )
-{
- PPHP_OBJECT_SEARCH_RESULT item1 = Item1;
- PPHP_OBJECT_SEARCH_RESULT item2 = Item2;
-
- return uintptrcmp((ULONG_PTR)item1->Handle, (ULONG_PTR)item2->Handle);
-}
-
-static INT_PTR CALLBACK PhpFindObjectsDlgProc(
- _In_ HWND hwndDlg,
- _In_ UINT uMsg,
- _In_ WPARAM wParam,
- _In_ LPARAM lParam
- )
-{
- switch (uMsg)
- {
- case WM_INITDIALOG:
- {
- HWND lvHandle;
-
- PhCenterWindow(hwndDlg, GetParent(hwndDlg));
- PhFindObjectsListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_RESULTS);
-
- PhInitializeLayoutManager(&WindowLayoutManager, hwndDlg);
- PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_FILTER),
- NULL, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
- PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_REGEX),
- NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
- PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDOK),
- NULL, PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
- PhAddLayoutItem(&WindowLayoutManager, lvHandle,
- NULL, PH_ANCHOR_ALL);
-
- MinimumSize.left = 0;
- MinimumSize.top = 0;
- MinimumSize.right = 150;
- MinimumSize.bottom = 100;
- MapDialogRect(hwndDlg, &MinimumSize);
-
- PhRegisterDialog(hwndDlg);
-
- PhLoadWindowPlacementFromSetting(L"FindObjWindowPosition", L"FindObjWindowSize", hwndDlg);
-
- PhSetListViewStyle(lvHandle, TRUE, TRUE);
- PhSetControlTheme(lvHandle, L"explorer");
- PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 100, L"Process");
- PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 100, L"Type");
- PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 200, L"Name");
- PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 80, L"Handle");
-
- PhSetExtendedListView(lvHandle);
- ExtendedListView_SetSortFast(lvHandle, TRUE);
- ExtendedListView_SetCompareFunction(lvHandle, 0, PhpObjectProcessCompareFunction);
- ExtendedListView_SetCompareFunction(lvHandle, 1, PhpObjectTypeCompareFunction);
- ExtendedListView_SetCompareFunction(lvHandle, 2, PhpObjectNameCompareFunction);
- ExtendedListView_SetCompareFunction(lvHandle, 3, PhpObjectHandleCompareFunction);
- PhLoadListViewColumnsFromSetting(L"FindObjListViewColumns", lvHandle);
-
- Button_SetCheck(GetDlgItem(hwndDlg, IDC_REGEX), PhGetIntegerSetting(L"FindObjRegex") ? BST_CHECKED : BST_UNCHECKED);
- }
- break;
- case WM_DESTROY:
- {
- PhSetIntegerSetting(L"FindObjRegex", Button_GetCheck(GetDlgItem(hwndDlg, IDC_REGEX)) == BST_CHECKED);
- PhSaveWindowPlacementToSetting(L"FindObjWindowPosition", L"FindObjWindowSize", hwndDlg);
- PhSaveListViewColumnsToSetting(L"FindObjListViewColumns", PhFindObjectsListViewHandle);
- }
- break;
- case WM_SHOWWINDOW:
- {
- SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_FILTER), TRUE);
- Edit_SetSel(GetDlgItem(hwndDlg, IDC_FILTER), 0, -1);
- }
- break;
- case WM_CLOSE:
- {
- ShowWindow(hwndDlg, SW_HIDE);
- // IMPORTANT
- // Set the result to 0 so the default dialog message
- // handler doesn't invoke IDCANCEL, which will send
- // WM_CLOSE, creating an infinite loop.
- SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, 0);
- }
- return TRUE;
- case WM_SETCURSOR:
- {
- if (SearchThreadHandle)
- {
- SetCursor(LoadCursor(NULL, IDC_WAIT));
- SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);
- return TRUE;
- }
- }
- break;
- case WM_COMMAND:
- {
- switch (LOWORD(wParam))
- {
- case IDOK:
- {
- // Don't continue if the user requested cancellation.
- if (SearchStop)
- break;
-
- if (!SearchThreadHandle)
- {
- ULONG i;
-
- PhMoveReference(&SearchString, PhGetWindowText(GetDlgItem(hwndDlg, IDC_FILTER)));
-
- if (SearchRegexCompiledExpression)
- {
- pcre2_code_free(SearchRegexCompiledExpression);
- SearchRegexCompiledExpression = NULL;
- }
-
- if (SearchRegexMatchData)
- {
- pcre2_match_data_free(SearchRegexMatchData);
- SearchRegexMatchData = NULL;
- }
-
- if (Button_GetCheck(GetDlgItem(hwndDlg, IDC_REGEX)) == BST_CHECKED)
- {
- int errorCode;
- PCRE2_SIZE errorOffset;
-
- SearchRegexCompiledExpression = pcre2_compile(
- SearchString->Buffer,
- SearchString->Length / sizeof(WCHAR),
- PCRE2_CASELESS | PCRE2_DOTALL,
- &errorCode,
- &errorOffset,
- NULL
- );
-
- if (!SearchRegexCompiledExpression)
- {
- PhShowError(hwndDlg, L"Unable to compile the regular expression: \"%s\" at position %zu.",
- PhGetStringOrDefault(PH_AUTO(PhPcre2GetErrorMessage(errorCode)), L"Unknown error"),
- errorOffset
- );
- break;
- }
-
- SearchRegexMatchData = pcre2_match_data_create_from_pattern(SearchRegexCompiledExpression, NULL);
- }
-
- // Clean up previous results.
-
- ListView_DeleteAllItems(PhFindObjectsListViewHandle);
-
- if (SearchResults)
- {
- for (i = 0; i < SearchResults->Count; i++)
- {
- PPHP_OBJECT_SEARCH_RESULT searchResult = SearchResults->Items[i];
-
- PhDereferenceObject(searchResult->TypeName);
- PhDereferenceObject(searchResult->Name);
-
- if (searchResult->ProcessName)
- PhDereferenceObject(searchResult->ProcessName);
-
- PhFree(searchResult);
- }
-
- PhDereferenceObject(SearchResults);
- }
-
- // Start the search.
-
- SearchResults = PhCreateList(128);
- SearchResultsAddIndex = 0;
-
- SearchThreadHandle = PhCreateThread(0, PhpFindObjectsThreadStart, NULL);
-
- if (!SearchThreadHandle)
- {
- PhClearReference(&SearchResults);
- break;
- }
-
- SetDlgItemText(hwndDlg, IDOK, L"Cancel");
-
- SetCursor(LoadCursor(NULL, IDC_WAIT));
- }
- else
- {
- SearchStop = TRUE;
- EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
- }
- }
- break;
- case IDCANCEL:
- {
- SendMessage(hwndDlg, WM_CLOSE, 0, 0);
- }
- break;
- case ID_OBJECT_CLOSE:
- {
- PPHP_OBJECT_SEARCH_RESULT *results;
- ULONG numberOfResults;
- ULONG i;
-
- PhGetSelectedListViewItemParams(
- PhFindObjectsListViewHandle,
- &results,
- &numberOfResults
- );
-
- if (numberOfResults != 0 && PhShowConfirmMessage(
- hwndDlg,
- L"close",
- numberOfResults == 1 ? L"the selected handle" : L"the selected handles",
- L"Closing handles may cause system instability and data corruption.",
- FALSE
- ))
- {
- for (i = 0; i < numberOfResults; i++)
- {
- NTSTATUS status;
- HANDLE processHandle;
-
- if (results[i]->ResultType != HandleSearchResult)
- continue;
-
- if (NT_SUCCESS(status = PhOpenProcess(
- &processHandle,
- PROCESS_DUP_HANDLE,
- results[i]->ProcessId
- )))
- {
- if (NT_SUCCESS(status = NtDuplicateObject(
- processHandle,
- results[i]->Handle,
- NULL,
- NULL,
- 0,
- 0,
- DUPLICATE_CLOSE_SOURCE
- )))
- {
- PhRemoveListViewItem(PhFindObjectsListViewHandle,
- PhFindListViewItemByParam(PhFindObjectsListViewHandle, 0, results[i]));
- }
-
- NtClose(processHandle);
- }
-
- if (!NT_SUCCESS(status))
- {
- if (!PhShowContinueStatus(hwndDlg,
- PhaFormatString(L"Unable to close \"%s\"", results[i]->Name->Buffer)->Buffer,
- status,
- 0
- ))
- break;
- }
- }
- }
-
- PhFree(results);
- }
- break;
- case ID_HANDLE_OBJECTPROPERTIES1:
- case ID_HANDLE_OBJECTPROPERTIES2:
- {
- PPHP_OBJECT_SEARCH_RESULT result =
- PhGetSelectedListViewItemParam(PhFindObjectsListViewHandle);
-
- if (result)
- {
- PH_HANDLE_ITEM_INFO info;
-
- info.ProcessId = result->ProcessId;
- info.Handle = result->Handle;
- info.TypeName = result->TypeName;
- info.BestObjectName = result->Name;
-
- if (LOWORD(wParam) == ID_HANDLE_OBJECTPROPERTIES1)
- PhShowHandleObjectProperties1(hwndDlg, &info);
- else
- PhShowHandleObjectProperties2(hwndDlg, &info);
- }
- }
- break;
- case ID_OBJECT_GOTOOWNINGPROCESS:
- {
- PPHP_OBJECT_SEARCH_RESULT result =
- PhGetSelectedListViewItemParam(PhFindObjectsListViewHandle);
-
- if (result)
- {
- PPH_PROCESS_NODE processNode;
-
- if (processNode = PhFindProcessNode(result->ProcessId))
- {
- ProcessHacker_SelectTabPage(PhMainWndHandle, 0);
- ProcessHacker_SelectProcessNode(PhMainWndHandle, processNode);
- ProcessHacker_ToggleVisible(PhMainWndHandle, TRUE);
- }
- }
- }
- break;
- case ID_OBJECT_PROPERTIES:
- {
- PPHP_OBJECT_SEARCH_RESULT result =
- PhGetSelectedListViewItemParam(PhFindObjectsListViewHandle);
-
- if (result)
- {
- if (result->ResultType == HandleSearchResult)
- {
- PPH_HANDLE_ITEM handleItem;
-
- handleItem = PhCreateHandleItem(&result->Info);
-
- handleItem->BestObjectName = handleItem->ObjectName = result->Name;
- PhReferenceObjectEx(result->Name, 2);
-
- handleItem->TypeName = result->TypeName;
- PhReferenceObject(result->TypeName);
-
- PhShowHandleProperties(
- hwndDlg,
- result->ProcessId,
- handleItem
- );
- PhDereferenceObject(handleItem);
- }
- else
- {
- // DLL or Mapped File. Just show file properties.
- PhShellProperties(hwndDlg, result->Name->Buffer);
- }
- }
- }
- break;
- case ID_OBJECT_COPY:
- {
- PhCopyListView(PhFindObjectsListViewHandle);
- }
- break;
- }
- }
- break;
- case WM_NOTIFY:
- {
- LPNMHDR header = (LPNMHDR)lParam;
-
- switch (header->code)
- {
- case NM_DBLCLK:
- {
- if (header->hwndFrom == PhFindObjectsListViewHandle)
- {
- SendMessage(hwndDlg, WM_COMMAND, ID_OBJECT_PROPERTIES, 0);
- }
- }
- break;
- case LVN_KEYDOWN:
- {
- if (header->hwndFrom == PhFindObjectsListViewHandle)
- {
- LPNMLVKEYDOWN keyDown = (LPNMLVKEYDOWN)header;
-
- switch (keyDown->wVKey)
- {
- case 'C':
- if (GetKeyState(VK_CONTROL) < 0)
- SendMessage(hwndDlg, WM_COMMAND, ID_OBJECT_COPY, 0);
- break;
- case 'A':
- if (GetKeyState(VK_CONTROL) < 0)
- PhSetStateAllListViewItems(PhFindObjectsListViewHandle, LVIS_SELECTED, LVIS_SELECTED);
- break;
- case VK_DELETE:
- SendMessage(hwndDlg, WM_COMMAND, ID_OBJECT_CLOSE, 0);
- break;
- }
- }
- }
- break;
- }
- }
- break;
- case WM_CONTEXTMENU:
- {
- if ((HWND)wParam == PhFindObjectsListViewHandle)
- {
- POINT point;
- PPHP_OBJECT_SEARCH_RESULT *results;
- ULONG numberOfResults;
-
- point.x = (SHORT)LOWORD(lParam);
- point.y = (SHORT)HIWORD(lParam);
-
- if (point.x == -1 && point.y == -1)
- PhGetListViewContextMenuPoint((HWND)wParam, &point);
-
- PhGetSelectedListViewItemParams(PhFindObjectsListViewHandle, &results, &numberOfResults);
-
- if (numberOfResults != 0)
- {
- PPH_EMENU menu;
-
- menu = PhCreateEMenu();
- PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_FINDOBJ), 0);
- PhSetFlagsEMenuItem(menu, ID_OBJECT_PROPERTIES, PH_EMENU_DEFAULT, PH_EMENU_DEFAULT);
-
- PhpInitializeFindObjMenu(menu, results, numberOfResults);
- PhShowEMenu(
- menu,
- hwndDlg,
- PH_EMENU_SHOW_SEND_COMMAND | PH_EMENU_SHOW_LEFTRIGHT,
- PH_ALIGN_LEFT | PH_ALIGN_TOP,
- point.x,
- point.y
- );
- PhDestroyEMenu(menu);
- }
-
- PhFree(results);
- }
- }
- break;
- case WM_SIZE:
- {
- PhLayoutManagerLayout(&WindowLayoutManager);
- }
- break;
- case WM_SIZING:
- {
- PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom);
- }
- break;
- case WM_PH_SEARCH_UPDATE:
- {
- HWND lvHandle;
- ULONG i;
-
- lvHandle = GetDlgItem(hwndDlg, IDC_RESULTS);
-
- ExtendedListView_SetRedraw(lvHandle, FALSE);
-
- PhAcquireQueuedLockExclusive(&SearchResultsLock);
-
- for (i = SearchResultsAddIndex; i < SearchResults->Count; i++)
- {
- PPHP_OBJECT_SEARCH_RESULT searchResult = SearchResults->Items[i];
- CLIENT_ID clientId;
- PPH_PROCESS_ITEM processItem;
- PPH_STRING clientIdName;
- INT lvItemIndex;
-
- clientId.UniqueProcess = searchResult->ProcessId;
- clientId.UniqueThread = NULL;
-
- processItem = PhReferenceProcessItem(clientId.UniqueProcess);
- clientIdName = PhGetClientIdNameEx(&clientId, processItem ? processItem->ProcessName : NULL);
-
- lvItemIndex = PhAddListViewItem(
- lvHandle,
- MAXINT,
- clientIdName->Buffer,
- searchResult
- );
-
- PhDereferenceObject(clientIdName);
-
- if (processItem)
- {
- PhSetReference(&searchResult->ProcessName, processItem->ProcessName);
- PhDereferenceObject(processItem);
- }
- else
- {
- searchResult->ProcessName = NULL;
- }
-
- PhSetListViewSubItem(lvHandle, lvItemIndex, 1, searchResult->TypeName->Buffer);
- PhSetListViewSubItem(lvHandle, lvItemIndex, 2, searchResult->Name->Buffer);
- PhSetListViewSubItem(lvHandle, lvItemIndex, 3, searchResult->HandleString);
- }
-
- SearchResultsAddIndex = i;
-
- PhReleaseQueuedLockExclusive(&SearchResultsLock);
-
- ExtendedListView_SetRedraw(lvHandle, TRUE);
- }
- break;
- case WM_PH_SEARCH_FINISHED:
- {
- NTSTATUS handleSearchStatus = (NTSTATUS)wParam;
-
- // Add any un-added items.
- SendMessage(hwndDlg, WM_PH_SEARCH_UPDATE, 0, 0);
-
- NtWaitForSingleObject(SearchThreadHandle, FALSE, NULL);
- NtClose(SearchThreadHandle);
- SearchThreadHandle = NULL;
- SearchStop = FALSE;
-
- ExtendedListView_SortItems(GetDlgItem(hwndDlg, IDC_RESULTS));
-
- SetDlgItemText(hwndDlg, IDOK, L"Find");
- EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE);
-
- SetCursor(LoadCursor(NULL, IDC_ARROW));
-
- if (handleSearchStatus == STATUS_INSUFFICIENT_RESOURCES)
- {
- PhShowWarning(
- hwndDlg,
- L"Unable to search for handles because the total number of handles on the system is too large. "
- L"Please check if there are any processes with an extremely large number of handles open."
- );
- }
- }
- break;
- }
-
- return FALSE;
-}
-
-static BOOLEAN MatchSearchString(
- _In_ PPH_STRINGREF Input
- )
-{
- if (SearchRegexCompiledExpression && SearchRegexMatchData)
- {
- return pcre2_match(
- SearchRegexCompiledExpression,
- Input->Buffer,
- Input->Length / sizeof(WCHAR),
- 0,
- 0,
- SearchRegexMatchData,
- NULL
- ) >= 0;
- }
- else
- {
- return PhFindStringInStringRef(Input, &SearchString->sr, TRUE) != -1;
- }
-}
-
-typedef struct _SEARCH_HANDLE_CONTEXT
-{
- BOOLEAN NeedToFree;
- PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX HandleInfo;
- HANDLE ProcessHandle;
-} SEARCH_HANDLE_CONTEXT, *PSEARCH_HANDLE_CONTEXT;
-
-static NTSTATUS NTAPI SearchHandleFunction(
- _In_ PVOID Parameter
- )
-{
- PSEARCH_HANDLE_CONTEXT context = Parameter;
- PPH_STRING typeName;
- PPH_STRING bestObjectName;
-
- if (!SearchStop && NT_SUCCESS(PhGetHandleInformation(
- context->ProcessHandle,
- (HANDLE)context->HandleInfo->HandleValue,
- context->HandleInfo->ObjectTypeIndex,
- NULL,
- &typeName,
- NULL,
- &bestObjectName
- )))
- {
- PPH_STRING upperBestObjectName;
-
- upperBestObjectName = PhDuplicateString(bestObjectName);
- _wcsupr(upperBestObjectName->Buffer);
-
- if (MatchSearchString(&upperBestObjectName->sr) ||
- (UseSearchPointer && context->HandleInfo->Object == (PVOID)SearchPointer))
- {
- PPHP_OBJECT_SEARCH_RESULT searchResult;
-
- searchResult = PhAllocate(sizeof(PHP_OBJECT_SEARCH_RESULT));
- searchResult->ProcessId = (HANDLE)context->HandleInfo->UniqueProcessId;
- searchResult->ResultType = HandleSearchResult;
- searchResult->Handle = (HANDLE)context->HandleInfo->HandleValue;
- searchResult->TypeName = typeName;
- searchResult->Name = bestObjectName;
- PhPrintPointer(searchResult->HandleString, (PVOID)searchResult->Handle);
- searchResult->Info = *context->HandleInfo;
-
- PhAcquireQueuedLockExclusive(&SearchResultsLock);
-
- PhAddItemList(SearchResults, searchResult);
-
- // Update the search results in batches of 40.
- if (SearchResults->Count % 40 == 0)
- PostMessage(PhFindObjectsWindowHandle, WM_PH_SEARCH_UPDATE, 0, 0);
-
- PhReleaseQueuedLockExclusive(&SearchResultsLock);
- }
- else
- {
- PhDereferenceObject(typeName);
- PhDereferenceObject(bestObjectName);
- }
-
- PhDereferenceObject(upperBestObjectName);
- }
-
- if (context->NeedToFree)
- PhFree(context);
-
- return STATUS_SUCCESS;
-}
-
-static BOOLEAN NTAPI EnumModulesCallback(
- _In_ PPH_MODULE_INFO Module,
- _In_opt_ PVOID Context
- )
-{
- PPH_STRING upperFileName;
-
- upperFileName = PhDuplicateString(Module->FileName);
- _wcsupr(upperFileName->Buffer);
-
- if (MatchSearchString(&upperFileName->sr) ||
- (UseSearchPointer && Module->BaseAddress == (PVOID)SearchPointer))
- {
- PPHP_OBJECT_SEARCH_RESULT searchResult;
- PWSTR typeName;
-
- switch (Module->Type)
- {
- case PH_MODULE_TYPE_MAPPED_FILE:
- typeName = L"Mapped file";
- break;
- case PH_MODULE_TYPE_MAPPED_IMAGE:
- typeName = L"Mapped image";
- break;
- default:
- typeName = L"DLL";
- break;
- }
-
- searchResult = PhAllocate(sizeof(PHP_OBJECT_SEARCH_RESULT));
- searchResult->ProcessId = (HANDLE)Context;
- searchResult->ResultType = (Module->Type == PH_MODULE_TYPE_MAPPED_FILE || Module->Type == PH_MODULE_TYPE_MAPPED_IMAGE) ? MappedFileSearchResult : ModuleSearchResult;
- searchResult->Handle = (HANDLE)Module->BaseAddress;
- searchResult->TypeName = PhCreateString(typeName);
- PhSetReference(&searchResult->Name, Module->FileName);
- PhPrintPointer(searchResult->HandleString, Module->BaseAddress);
- memset(&searchResult->Info, 0, sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX));
-
- PhAcquireQueuedLockExclusive(&SearchResultsLock);
-
- PhAddItemList(SearchResults, searchResult);
-
- // Update the search results in batches of 40.
- if (SearchResults->Count % 40 == 0)
- PostMessage(PhFindObjectsWindowHandle, WM_PH_SEARCH_UPDATE, 0, 0);
-
- PhReleaseQueuedLockExclusive(&SearchResultsLock);
- }
-
- PhDereferenceObject(upperFileName);
-
- return TRUE;
-}
-
-static NTSTATUS PhpFindObjectsThreadStart(
- _In_ PVOID Parameter
- )
-{
- NTSTATUS status = STATUS_SUCCESS;
- PSYSTEM_HANDLE_INFORMATION_EX handles;
- PPH_HASHTABLE processHandleHashtable;
- PVOID processes;
- PSYSTEM_PROCESS_INFORMATION process;
- ULONG i;
-
- // Refuse to search with no filter.
- if (SearchString->Length == 0)
- goto Exit;
-
- // Try to get a search pointer from the search string.
- UseSearchPointer = PhStringToInteger64(&SearchString->sr, 0, &SearchPointer);
-
- _wcsupr(SearchString->Buffer);
-
- if (NT_SUCCESS(status = PhEnumHandlesEx(&handles)))
- {
- static PH_INITONCE initOnce = PH_INITONCE_INIT;
- static ULONG fileObjectTypeIndex = -1;
-
- BOOLEAN useWorkQueue = FALSE;
- PH_WORK_QUEUE workQueue;
- processHandleHashtable = PhCreateSimpleHashtable(8);
-
- if (!KphIsConnected() && WindowsVersion >= WINDOWS_VISTA)
- {
- useWorkQueue = TRUE;
- PhInitializeWorkQueue(&workQueue, 1, 20, 1000);
-
- if (PhBeginInitOnce(&initOnce))
- {
- UNICODE_STRING fileTypeName;
-
- RtlInitUnicodeString(&fileTypeName, L"File");
- fileObjectTypeIndex = PhGetObjectTypeNumber(&fileTypeName);
- PhEndInitOnce(&initOnce);
- }
- }
-
- for (i = 0; i < handles->NumberOfHandles; i++)
- {
- PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handleInfo = &handles->Handles[i];
- PVOID *processHandlePtr;
- HANDLE processHandle;
-
- if (SearchStop)
- break;
-
- // Open a handle to the process if we don't already have one.
-
- processHandlePtr = PhFindItemSimpleHashtable(
- processHandleHashtable,
- (PVOID)handleInfo->UniqueProcessId
- );
-
- if (processHandlePtr)
- {
- processHandle = (HANDLE)*processHandlePtr;
- }
- else
- {
- if (NT_SUCCESS(PhOpenProcess(
- &processHandle,
- PROCESS_DUP_HANDLE,
- (HANDLE)handleInfo->UniqueProcessId
- )))
- {
- PhAddItemSimpleHashtable(
- processHandleHashtable,
- (PVOID)handleInfo->UniqueProcessId,
- processHandle
- );
- }
- else
- {
- continue;
- }
- }
-
- if (useWorkQueue && handleInfo->ObjectTypeIndex == (USHORT)fileObjectTypeIndex)
- {
- PSEARCH_HANDLE_CONTEXT searchHandleContext;
-
- searchHandleContext = PhAllocate(sizeof(SEARCH_HANDLE_CONTEXT));
- searchHandleContext->NeedToFree = TRUE;
- searchHandleContext->HandleInfo = handleInfo;
- searchHandleContext->ProcessHandle = processHandle;
- PhQueueItemWorkQueue(&workQueue, SearchHandleFunction, searchHandleContext);
- }
- else
- {
- SEARCH_HANDLE_CONTEXT searchHandleContext;
-
- searchHandleContext.NeedToFree = FALSE;
- searchHandleContext.HandleInfo = handleInfo;
- searchHandleContext.ProcessHandle = processHandle;
- SearchHandleFunction(&searchHandleContext);
- }
- }
-
- if (useWorkQueue)
- {
- PhWaitForWorkQueue(&workQueue);
- PhDeleteWorkQueue(&workQueue);
- }
-
- {
- PPH_KEY_VALUE_PAIR entry;
-
- i = 0;
-
- while (PhEnumHashtable(processHandleHashtable, &entry, &i))
- NtClose((HANDLE)entry->Value);
- }
-
- PhDereferenceObject(processHandleHashtable);
- PhFree(handles);
- }
-
- if (NT_SUCCESS(PhEnumProcesses(&processes)))
- {
- process = PH_FIRST_PROCESS(processes);
-
- do
- {
- PhEnumGenericModules(
- process->UniqueProcessId,
- NULL,
- PH_ENUM_GENERIC_MAPPED_FILES | PH_ENUM_GENERIC_MAPPED_IMAGES,
- EnumModulesCallback,
- (PVOID)process->UniqueProcessId
- );
- } while (process = PH_NEXT_PROCESS(process));
-
- PhFree(processes);
- }
-
-Exit:
- PostMessage(PhFindObjectsWindowHandle, WM_PH_SEARCH_FINISHED, status, 0);
-
- return STATUS_SUCCESS;
-}
+/*
+ * Process Hacker -
+ * object search
+ *
+ * Copyright (C) 2010-2016 wj32
+ * Copyright (C) 2017-2019 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 .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include