diff --git a/branches/ph-plugins/Assistant/Assistant.cs b/branches/ph-plugins/Assistant/Assistant.cs new file mode 100644 index 000000000..880edd639 --- /dev/null +++ b/branches/ph-plugins/Assistant/Assistant.cs @@ -0,0 +1,341 @@ +/* + * Process Hacker Assistant + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using ProcessHacker.Common; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; +using ProcessHacker.Native.Security.AccessControl; + +namespace Assistant +{ + static class Program + { + static void SetDesktopWinStaAccess() + { + using (var wsHandle = new WindowStationHandle("WinSta0", (WindowStationAccess)StandardRights.WriteDac)) + wsHandle.SetSecurity(SecurityInformation.Dacl, new SecurityDescriptor()); + + using (var dhandle = new DesktopHandle("Default", false, + (DesktopAccess)StandardRights.WriteDac | DesktopAccess.ReadObjects | DesktopAccess.WriteObjects)) + dhandle.SetSecurity(SecurityInformation.Dacl, new SecurityDescriptor()); + } + + static Dictionary ParseArgs(string[] args) + { + Dictionary dict = new Dictionary(); + string argPending = null; + + foreach (string s in args) + { + if (s.StartsWith("-")) + { + if (dict.ContainsKey(s)) + throw new Exception("Option already specified."); + + dict.Add(s, ""); + argPending = s; + } + else + { + if (argPending != null) + { + dict[argPending] = s; + argPending = null; + } + else + { + if (dict.ContainsKey("")) + throw new Exception("Input file already specified."); + + dict.Add("", s); + } + } + } + + return dict; + } + + static void PrintUsage() + { + Console.Write("Process Hacker Assistant\nCopyright (c) 2008 wj32. Licensed under the GNU GPL v3.\n\nUsage:\n" + + "\tassistant [-w] [-k] [-P pid] [-u username] [-p password] [-t logontype] [-s sessionid] [-d dir] " + + "[-c cmdline] [-f filename] [-E name]\n\n" + + "-w\t\tSpecifies that the permissions of WinSta0 and WinSta0\\Default should be " + + "modified with all access. You should use this option as a normal user (\"assistant -w\") before attempting to " + + "use this program as a Windows service.\n" + + "-k\t\tDebugging purposes: specifies that this program should sleep after completion.\n" + + "-P pid\t\t\"Steals\" the token of the specified process to start the specified program. You must not use " + + "the -u and -p options with this option.\n" + + "-u username\tSpecifies the user under which the program should be run. The username can be specified " + + "as username, domain\\username, or username@domain. On Windows XP, specifying NT AUTHORITY\\SYSTEM does " + + "not work by itself. You must specify \"-t newcredentials\" as well.\n" + + "-p password\tSpecifies the password for the user.\n" + + "-t logontype\tSpecifies the logon type. For logons to normal users, specify \"interactive\". For logons " + + "to NT AUTHORITY\\SYSTEM, LOCAL SERVICE or NETWORK SERVICE, specify \"service\" (see above for using SYSTEM on " + + "Windows XP).\n" + + "-s sessionid\tSpecifies the session ID under which the program should be run.\n" + + "-d dir\t\tSpecifies the current directory for the program.\n" + + "-c cmdline\tSpecifies the command line for the program. You must not use the -f option if you use this.\n" + + "-f filename\tSpecifies the full path to the program.\n" + + "-E name\tSpecifies the partial name of the mailslot to write a 4-byte error code to.\n" + + "\n" + + "This application is not useful by itself; even Administrators do not normally have " + + "SeAssignPrimaryTokenPrivilege and SeTcbPrivilege, both of which are required for the useful " + + "functioning of this program. You must create a Windows service for this program:\n" + + "\tsc.exe create PHAssistant binPath= \"\\\"[path to this program]\\\" -u \\\"SYSTEM@NT AUTHORITY\\\" " + + "-t service -s [your session Id, normally 0 on XP and 1 on Vista] -c calc.exe\"\n" + + "then start it:\n\tsc.exe start PHAssistant\n" + + "and finally delete it:\n\tsc.exe delete PHAssistant\n"); + } + + static void Exit(int exitCode) + { + if (args.ContainsKey("-k")) + System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite); + + if (args.ContainsKey("-E")) + { + string mailslotName = args["-E"]; + + using (var fhandle = new FileHandle( + @"\Device\Mailslot\" + mailslotName, + FileShareMode.ReadWrite, + FileAccess.GenericWrite + )) + fhandle.Write(exitCode.GetBytes()); + } + + Environment.Exit(exitCode); + } + + static void Exit() + { + Exit(0); + } + + static Dictionary args; + + static bool EnablePrivilege(string name) + { + try + { + Privilege.Enable(name); + return true; + } + catch + { + return false; + } + } + + static void Main() + { + EnablePrivilege("SeAssignPrimaryTokenPrivilege"); + EnablePrivilege("SeBackupPrivilege"); + EnablePrivilege("SeRestorePrivilege"); + + try + { + args = ParseArgs(Environment.GetCommandLineArgs()); + + bool bad = false; + + if (!args.ContainsKey("-w")) + { + if (!args.ContainsKey("-c") && !args.ContainsKey("-f")) + bad = true; + + if (args.ContainsKey("-c") && args.ContainsKey("-f")) + bad = true; + + if (!args.ContainsKey("-u") && !args.ContainsKey("-P")) + bad = true; + + if (args.ContainsKey("-u") && args.ContainsKey("-P")) + bad = true; + } + + if (args.ContainsKey("-v") || args.ContainsKey("-h")) + bad = true; + + if (bad) + { + PrintUsage(); + Exit(); + } + } + catch + { + PrintUsage(); + Exit(); + } + + if (args.ContainsKey("-w")) + { + try + { + SetDesktopWinStaAccess(); + } + catch (Exception ex) + { + Console.WriteLine("Warning: Could not set desktop and window station access: " + ex.Message); + } + } + + IntPtr token = IntPtr.Zero; + string domain = null; + string username = ""; + + if (args.ContainsKey("-u")) + { + string user = args["-u"]; + + if (user.Contains("\\")) + { + domain = user.Split('\\')[0]; + username = user.Split('\\')[1]; + } + else if (user.Contains("@")) + { + username = user.Split('@')[0]; + domain = user.Split('@')[1]; + } + else + { + username = user; + } + + LogonType type = LogonType.Interactive; + + if (args.ContainsKey("-t")) + { + try + { + type = (LogonType)Enum.Parse(typeof(LogonType), args["-t"], true); + } + catch + { + Console.WriteLine("Error: Invalid logon type."); + Exit(-1); + } + } + + if (!Win32.LogonUser(username, domain, args.ContainsKey("-p") ? args["-p"] : "", type, + LogonProvider.Default, out token)) + { + Console.WriteLine("Error: Could not logon as user: " + Win32.GetLastErrorMessage()); + Exit(Marshal.GetLastWin32Error()); + } + } + else + { + int pid = System.Diagnostics.Process.GetCurrentProcess().Id; + + try + { + if (args.ContainsKey("-P")) + pid = int.Parse(args["-P"]); + } + catch + { + Console.WriteLine("Error: Invalid PID."); + } + + IntPtr handle = IntPtr.Zero; + + try + { + handle = System.Diagnostics.Process.GetProcessById(pid).Handle; + } + catch + { + Console.WriteLine("Error: Could not open process."); + } + + + if (!Win32.OpenProcessToken(handle, TokenAccess.All, out token)) + { + Console.WriteLine("Error: Could not open process token: " + Win32.GetLastErrorMessage()); + Exit(Marshal.GetLastWin32Error()); + } + + if (Environment.OSVersion.Version.Major != 5) + { + IntPtr dupToken; + + if (!Win32.DuplicateTokenEx(token, TokenAccess.All, IntPtr.Zero, SecurityImpersonationLevel.SecurityImpersonation, + TokenType.Primary, out dupToken)) + { + Console.WriteLine("Error: Could not duplicate own token: " + Win32.GetLastErrorMessage()); + Exit(Marshal.GetLastWin32Error()); + } + + Win32.CloseHandle(token); + token = dupToken; + } + } + + if (args.ContainsKey("-s")) + { + int sessionId = int.Parse(args["-s"]); + + if (!Win32.SetTokenInformation(token, TokenInformationClass.TokenSessionId, ref sessionId, 4)) + { + Console.WriteLine("Error: Could not set token session Id: " + Win32.GetLastErrorMessage()); + } + } + + if (args.ContainsKey("-c") || args.ContainsKey("-f")) + { + if (!args.ContainsKey("-e")) + { + StartupInfo info = new StartupInfo(); + ProcessInformation pinfo = new ProcessInformation(); + IntPtr environment; + + Win32.CreateEnvironmentBlock(out environment, token, false); + + info.Size = Marshal.SizeOf(info); + info.Desktop = "WinSta0\\Default"; + + if (!Win32.CreateProcessAsUser(token, + args.ContainsKey("-f") ? args["-f"] : null, + args.ContainsKey("-c") ? args["-c"] : null, + IntPtr.Zero, IntPtr.Zero, false, ProcessCreationFlags.CreateUnicodeEnvironment, environment, + args.ContainsKey("-d") ? args["-d"] : null, + ref info, out pinfo)) + { + Console.WriteLine("Error: Could not create process: " + Win32.GetLastErrorMessage()); + Exit(Marshal.GetLastWin32Error()); + } + + Win32.CloseHandle(token); + } + } + + Exit(); + } + } +} diff --git a/branches/ph-plugins/Assistant/Assistant.csproj b/branches/ph-plugins/Assistant/Assistant.csproj new file mode 100644 index 000000000..46724f8ff --- /dev/null +++ b/branches/ph-plugins/Assistant/Assistant.csproj @@ -0,0 +1,87 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {0710ADEF-F89E-4CBC-8150-B340460BC9D6} + Exe + Properties + Assistant + Assistant + v2.0 + 512 + Assistant.Program + app.manifest + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + AnyCPU + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AnyCPU + + + + + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + {8E10F5E8-D4FA-4980-BB23-2EDD134AC15E} + ProcessHacker.Common + + + {8A448157-E1A7-4DDF-954E-287F1117832B} + ProcessHacker.Native + + + + + + mkdir "$(SolutionDir)\ProcessHacker\$(OutDir)" +copy "$(TargetPath)" "$(SolutionDir)\ProcessHacker\$(OutDir)" +copy "$(TargetDir)\Assistant.pdb" "$(SolutionDir)\ProcessHacker\$(OutDir)" + + \ No newline at end of file diff --git a/branches/ph-plugins/Assistant/Properties/AssemblyInfo.cs b/branches/ph-plugins/Assistant/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..e3968b1c7 --- /dev/null +++ b/branches/ph-plugins/Assistant/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Process Hacker Assistant")] +[assembly: AssemblyDescription("Process Hacker Assistant")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("wj32")] +[assembly: AssemblyProduct("Process Hacker")] +[assembly: AssemblyCopyright("Licensed under the GNU GPL.")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("10a62c48-2a7a-4e76-9103-ac46d4d55ea8")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.6.0.0")] +[assembly: AssemblyFileVersion("1.6.0.0")] diff --git a/branches/ph-plugins/Assistant/Properties/Resources.Designer.cs b/branches/ph-plugins/Assistant/Properties/Resources.Designer.cs new file mode 100644 index 000000000..1eae069fc --- /dev/null +++ b/branches/ph-plugins/Assistant/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.1434 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Assistant.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Assistant.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/branches/ph-plugins/Assistant/Properties/Resources.resx b/branches/ph-plugins/Assistant/Properties/Resources.resx new file mode 100644 index 000000000..ffecec851 --- /dev/null +++ b/branches/ph-plugins/Assistant/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/Assistant/Properties/Settings.Designer.cs b/branches/ph-plugins/Assistant/Properties/Settings.Designer.cs new file mode 100644 index 000000000..dc7bdcb9a --- /dev/null +++ b/branches/ph-plugins/Assistant/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.1434 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Assistant.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/branches/ph-plugins/Assistant/Properties/Settings.settings b/branches/ph-plugins/Assistant/Properties/Settings.settings new file mode 100644 index 000000000..abf36c5d3 --- /dev/null +++ b/branches/ph-plugins/Assistant/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/branches/ph-plugins/Assistant/app.manifest b/branches/ph-plugins/Assistant/app.manifest new file mode 100644 index 000000000..eb3c3ae01 --- /dev/null +++ b/branches/ph-plugins/Assistant/app.manifest @@ -0,0 +1,22 @@ + + + + + + + + + + + + diff --git a/branches/ph-plugins/CHANGELOG.txt b/branches/ph-plugins/CHANGELOG.txt new file mode 100644 index 000000000..9b169170b --- /dev/null +++ b/branches/ph-plugins/CHANGELOG.txt @@ -0,0 +1,725 @@ +Process Hacker + +1.6 + * NEW/IMPROVED: + * #2817429 - "Add Port and IP Address columns to Network tab" + * #2845829 - "System uptime" + * #2853452 - "Find handles window: Minor usability improvements" + * Update system + * Network tools: ping, traceroute and whois + * Object security editor + * Displays IPv6 network connections + * VirusTotal uploader + * Two new terminator tests: W1 (send WM_DESTROY messages) and + W2 (send WM_QUIT messages) + * Wait chain analysis + * Mutant owner information + * Elevation prompt when attempting to view process properties + * All list views now have sort arrows + * Network list now displays process tooltips + * Enabled DLL injection into processes from other sessions + * Decreased memory and CPU usage + * Added a glossary to Help + * Configurable elevation prompts + * Better Windows 7 user interface support + * Exception reporting from within Process Hacker + * Slimmer thread call stack window + * FIXED: + * #2820170 - "System.ArgumentOutOfRangeException in network list" + * #2845427 - "Indicator integer overflow" + * #2847691 - "Apply button bug" + * #2849052 - "not defined by current visual style" + * #2863305 - "Unhandled exception in comparer" + * Critical KProcessHacker denial-of-service security issues + * Crashes within the process tree model + * Incorrect menu items for System threads + * Crash when viewing error details in the event + of a corrupt configuration file + * Notification icons were fixed at 16x16 size + * Sort order for the relative start time column + * Incorrect process priority class display + * Commit and Physical Memory History icon colors + * Packed file detection, PE reader + * Performance history buffer problems + * REMOVED: + * Messages in the main window's status bar + +1.5 + * NEW/IMPROVED: + * #2831605 - "Add handle count by type to process properties handle tab" + * #2836706 - "Signature Column in Processes" + * Improved kernel modules list + * Detects custom kernels + * Performance improvements + * KTM resource manager information + * FIXED: + * Windows XP BSODs + * Incorrect drive letter resolving for file handles + * Linked token display on x64 + +1.4 + * NEW/IMPROVED: + * Full support for Windows 7 SP0 + * Basic support for Windows 64-bit + * Ability to unload drivers + * Handle names for Kernel Transaction Manager (KTM) objects + * Ability to save details for processes + * Improved handle granted access display + * Improved process window exit status display + * Improved user prompts + * Ability to open key handles in regedit + * Thread list is more responsive + * Process exit notification (in the process window) is now instant + * Improved control tab indicies + * Small performance improvements + * FIXED: + * #2821437 - "Windows 7 PsTerminateProcess crash" + * #2834578 - "Unable to replace Task Manager with Process Hacker error" + * Properties menu item for handles was disabled most of the time + * Handle names could not be viewed properly without KPH and + on systems without the VC++ 9 runtime + * Minor KPH pool leak + * Annoying popup when Process Hacker replaces Task Manager on + Windows 7 + * No symbols for protected processes + +1.3.9.0 + * NEW/IMPROVED: + * #2812814 - "Auto-scroll option should be remembered" + * Kernel-mode stack traces + * POSIX process support, including command lines and + highlighting + * Hidden processes scanner can now detect FUTo + * Highlighting for .NET and relocated DLLs + * Ability to terminate system threads + * Ability to force terminate threads + * Ability to create services + * Ability to set DEP status of processes in other sessions + * Ability to unload modules of processes in other sessions + * Ability to dump memory to a file + * Process window manipulation + * Process heap information + * Paged and non-paged pool limit display + * Terminator test: TP1a (TP1, alternative method) + * Terminator test: TT1a (TT1, alternative method) + * Terminator test: TT4 (dangerous thread termination) + * Better file object names without KProcessHacker + * Better IP address resolving + * CPU, I/O and memory indicators + * Child windows float by default + * dbghelp is now set up automatically when Process Hacker is + run the first time + * Thread wait analysis now detects NtQueryObject hangs and + named pipe connections + * Automatic tree text coloring, allowing for dark highlighting + colors + * Small performance improvements + * FIXED: + * #2811733 - "System.NullReferenceException" + * Broken system thread start addresses due to sign-extending + instead of zero-extending pointers + * Broken Ctrl+A for memory, results, and PE lists + * Removed several annoying thread-related warnings + * Network connections now display process IDs + * Ctrl+C in the log window + * Window location problem when hiding and restoring the window + * ObjectDisposedExceptions when closing search options windows + * "Inject DLL" menu item enabling problem + * InvalidCastException when attempting to close handles in + the handle filter window + +1.3.8.5 + * NEW/IMPROVED: + * Full support for Windows Vista SP2 + * Users/sessions list + * Window process finder + * Thread wait analysis - right-click a thread and choose + Analyze > Wait to see what a thread is hanging on + * Added ability to create dump files for processes + * Added ability to detach processes from debuggers + * Added "scroll down process tree on startup" option + * Notification icon process list is now sorted + * Lists are dramatically faster (especially the handle list) + * Detailed handle properties + * Event objects can now be modified - set, clear, pulse, reset + * Event pair objects can now be modified - set high, set low + * Semaphore objects can now be modified - acquire, release + * Statistics for token objects + * Token object names now include their session LUIDs + * Added Shift+Del for Terminate Process Tree + * FIXED: + * #2795871 - "Hidden Processes window resizing problem" + * #2800710 - "System.ObjectDisposedException" + * Windows 7 RC BSOD (Windows 7 Beta is no longer supported) at + startup; support is STILL EXPERIMENTAL + * Memory search addresses being in decimal + * Disabling "Warn about dangerous actions" now disables all + process-related prompts + * Terminator window would be hidden if the main window was top-most + * Using the keyboard (Up/Down/Left/Right) in the process list was fixed + * Potential BSOD with KphReadVirtualMemory and KphWriteVirtualMemory + due to incorrect address probing + * Get Function Address window would return incorrect hex addresses + +1.3.8.0 + * NEW/IMPROVED: + * KProcessHacker can now perform process memory reading/writing + by itself and does not require MmCopyVirtualMemory + * KProcessHacker can now bypass all handle-opening protections + * Experimental process protection feature + * Ability to set handle flags such as protect-from-close and inherit + * Better highlighting + * Terminator test: TD1 (debugs a process and closes the debug object) + * Terminator test: TT3 (TT1 is now completely user-mode) + * Shows function file and line numbers where available + * Icon updating is now done on the shared thread to avoid the GUI + blocking when explorer.exe is suspended or is hanging + * FIXED: + * #2785648 - "cursor down crashes PH" + * #2790404 - "System.InvalidOperationException" + * Incomplete or inaccurate thread call stacks + * Windows 7 BSOD + * Crash upon executing terminator test M1 + * Unexpected actions being performed when a key was pressed in + the memory and handle lists + * Changed I/O tray icon tooltip from ROW to RWO + * Corrupted usernames + * .NET processes getting recognized as packed + * Start times like "20 centuries ago" + * Unable to change service configurations + * "Access denied" when changing DEP status or unloading a module + on Windows XP + +1.3.7.5 + * NEW/IMPROVED: + * #2780260 - "add key to open Proc Properties" + * #2780277 - "add to shortcut list for default action" + * #2781625 - "System Idle Process should not have network connections" + * #2784954 - "Ctrl+F find DLLs and not just Handles" + * Customizable tray icons - CPU History, CPU Usage, I/O History, + Commit History and Physical Memory History + * Base Priority, Start Time, and CPU Time columns + * "Terminate Process Tree" + * Can close TCP connections + * Process tree loads instantly + * Process properties (appears to) loads faster + * Decreased CPU usage + * Significantly less memory usage, especially when opening + process properties + * Thread termination now prompts + * Implemented Esc to close windows + * Cycles, Page Priority and I/O Priority in process statistics + * Integrity, I/O priority and page priority columns + * Windows are protected from being offscreen when they load + * Process property window locations are now saved + * The main window dimensions are saved when exiting minimized + * Enabled Reduce Working Set for multiple processes at a time + * Hides Process Hacker network connections by default + * FIXED: + * #2782808 - "Exception generated when CPU History is set to first column." + * #2784922 - "Hidden processes window: window location not remembered" + * #2784924 - "Network connections: process's icon not shown" + * Unhandled exception when process properties is closed within 100ms of + being opened + * Handle filter took a while to start up + * Forgot to add sorting for Private WS, Shared WS and Shareable WS + * dbghelp warnings were not being shown the first time process + properties opened + * Random file-object-related BSODs + * Increased PID limit in Hidden Processes to 65536 + * Inaccurate I/O Total rates when using a refresh interval other than + 1000ms + * Incorrect thread start addresses + +1.3.7.1 + * NEW: + * "-nokph" command line switch to disable KProcessHacker + * FIXED: + * #2779558 - "TreeViewAdv font cannot be initialized" + * KProcessHacker BSOD on some Vista systems + * Minor issue where new handle providers in the process window would + not be added to the shared thread provider + +1.3.7.0 + * NEW/IMPROVED: + * Terminating processes and threads now bypasses all but the most + advanced anti-termination methods + * Better hidden processes scanner (similar to Blacklight's and IceSword's) + which can now detect both Hacker Defender and FU. + * Basic support for Windows 7 in Process Hacker and KProcessHacker + * Proper symbol support with dbghelp.dll + * Private, Shared and Shareable Working Set columns + * Improved handle viewing with KProcessHacker - more object types are visible, + including ALPC Ports and protected process handles + * Stack viewing uses KProcessHacker on Windows Vista + * Handle highlighting + * Lists now have column sorting priority + * Memory list is much faster + * Better thread start addresses, especially on Windows XP + * Job termination + * Elevation button in Options now spawns a child options window instead of + restarting Process Hacker elevated + * Can open process properties from the handle list + * Better "could not initialize configuration" message for Windows Vista + * New Terminator method: assigns a job object to the process and terminates it + * Process Properties menu item in the handle filter window + * Can now close multiple handles at once from the handle filter window + * FIXED: + * Service properties Key handle leak + * Handle deletion detection + * Unhandled exceptions when viewing performance/statistics for a non-existent process + * Network connections for processes without icons would not be displayed + * Virtualization menu item visible on Windows XP + * When processes are terminated they are deselected (to provide feedback to the user) + * When Native API calls failed they would pass through the exception handling + code unchecked, causing random crashes (rarely) + * REMOVED: + * Useless Window menu items (PITA + causes memory leaks due to Microsoft's poor + implementation of MenuItem) + * Registers from the thread window + +1.3.6.5 + * NEW/IMPROVED: + * #2702907 - "CSR Processes: Enable termination of multiple processes" + * #2702909 - "CSR Processes: Show process name when confirming termination" + * #2702911 - "Show process name when terminating process in properties" + * #2702929 - "Add a Cancel button in Options" + * #2713088 - "Network: Ctrl+A and Ctrl+C should copy the processes' names" + * #2714130 - "Option to disable/enable all highlighting colors" + * Job information + * "Inject DLL" function + * Statistics times in System Information and process properties + * Highlighting system + * Configurable max. samples and plotter step size + * Network list with icons + * Can close multiple handles at once + * Less memory usage + * Confirmation dialogs are now consistent and use new Vista interfaces where possible + * KProcessHacker now retrieves thread start addresses + * KProcessHacker now performs memory manipulation (allowing the command lines of more + processes to be displayed) + * KProcessHacker now performs process suspending/resuming on Windows Vista + * Custom module information querying; can now display the modules for protected processes + * Displays service DLL paths + * Thread list displays cycles instead of context switches on Windows Vista + * GUI threads are highlighted (with KProcessHacker) + * Suspended and GUI thread highlighting can be configured + * Special tooltip information for dllhost.exe (shows COM target) + * FIXED: + * #2642442 - "System Information label text gets clipped" + * #2694437 - "Crash when sorting the process list" + * #2713087 - "Processes: Copy should copy only the columns currently used" + * #2716815 - "PH crashes during EnumProcesses" + * Network connections would be readded if their state changed + * Integer overflows in the process provider and system statistics + * Memory leaks with various windows + * Crash when saving with the I/O or CPU History column visible + * Inconsistent Copy menu after columns are modified + * Crash when F5 (Refresh) is held down + * Resizable statusbar + * Module unloading now works properly + * REMOVED: + * Disassembler - not used very often + +1.3.6.1 + * NEW: + * CPU and I/O history columns + * System Cache value in System Information + * FIXED: + * #2625167 - "Commit charge limit should not be 16EB" + * #2642385 - "Maximum File Cache size should not be 16EB" + * Minimize size of the System Information window + * Settings were lost between versions + * Handle and memory leaks + * Integer overflows in System Information + +1.3.6.0 + * NEW: + * #2596473 - "Add "Save Processes"" + * #2596481 - "Add option for one instance of Process Hacker" + * #2601397 - "Ability to sort by name, type etc to all of the windows" + * #2605155 - "CSR Processes: Add Save Processes" + * #2625192 - "Log: Add clear log" + * #2625193 - "Add warning before shutting down, or restarting pc etc." + * #2647235 - "Update Log even when it’s open" + * #2647387 - "Add descriptions to Memory Editor's buttons" + * #2647418 - "Add ctrl+A and ctrl+C to threads, token, modules etc" + * #2647422 - "Suggest filename in Memory Editor->Data->Save" + * #2647435 - "Add descriptions to Memory search results window" + * #2657138 - "Add a toolbar" + * #2657143 - "Add Changelog in Help menu" + * #2675859 - "Log: auto-scroll option" + * #2675864 - "System Information improvements" + * #2675871 - "Suggest file extension everywhere" + * Full CPU, I/O and memory usage history for processes and the OS + * Tooltips for graphs + * Modules tab shows mapped files + * "Reduce Working Set" function + * Can change virtualization for processes + * Customizable columns for the process list/tree + * All lists now have Ctrl+A and Ctrl+C support + * Vista-style lists + * Changing service settings under a limited account now prompts for + elevation instead of giving an Access Denied error + * Run As now works under a limited account and prompts for elevation + * Shows environment variables + * Unicode string memory scanning + * Better Terminate Process confirmation dialog + * FIXED: + * #2602541 - "Bug with 'Hide When Minimized' enabled -svn635" + * Replace Task Manager works correctly when Start hidden is enabled + * csc.exe launching + * Black border bug when restoring from minimized state + * Nulls at the ends of handle names + * Errors when changing service settings + * Slow closing of various windows + * "Hide when minimized" is better + * Opened process properties when a plus/minus was double-clicked + * Redrawing of the process tree when the window is activated/deactivated + * Double-escaping in the Run As tool + * Priority getting/setting under limited accounts + * Run As tool sets new environment variables for the child process + * .NET processes are sometimes labelled as packed + * KProcessHacker BSOD + +1.3.5.0 + * NEW: + * #2596502 - "Add access keys" + * #2596509 - "Double click on mutant-->Open properties window" + * #2596512 - "General tab window goes in the background" + * #2600995 - "Improvements to Help file" + * #2602538 - "Move some options to new window" + * #2602553 - "Add access key for Help" + * #2602606 - "Display a warning when running on 64bit WIN" + * #2605000 - "Add descriptions to some buttons" + * #2605133 - "Add access key to Log" + * #2605140 - "Save Log-->Suggest Log.txt" + * #2605146 - "When you open Log, the entries shouldn't be selected" + * #2605148 - "CSR Processes: Add select all and/or ctrl+A" + * #2605158 - "Log: Add Copy to clipboard and ctrl+A" + * #2605167 - "Add "Hide When Closed" option" + * #2608710 - "Notifications menu improvements" + * #2608801 - "Add Shutdown options" + * #2609039 - "Use thousands separator" + * #2613838 - "Add process' icon before process' name in process' window" + * #2615707 - "Improvements to Log" + * #2617637 - "Help file improvements No2" + * #2617691 - "Add option to replace task manager with Process Hacker" + * #2628961 - "Add ctrl+A in Services and Network window" + * #2628967 - "Add ctrl+C in Processes, Services and Network window" + * #2642505 - "Make some columns' size bigger" + * KProcessHacker is now enabled by default + * KProcessHacker now supports multiple clients at one time + * Process termination now uses KProcessHacker + * Process Hacker can now use KProcessHacker under a limited user account if it is + loaded, giving it full admin-like permissions to processes + * Process Hacker no longer requires UAC elevation - instead, there are two extra + menu items, "Run As Administrator..." and "Show Details for All Processes". It + also automatically prompts for elevation for specific tasks. + * "Run" function + * "Restart" function + * "Set Token" function for Windows XP + * "Verify File Signature" function + * "Re-analyze" function + * Around 50% reduction in CPU usage + * Specific highlighting can be enabled/disabled + * CSR Processes tool - displays hidden processes (this does not detect Hacker + Defender but does detect simple kernel-mode rootkits) + * Processes list in the notification icon menu, for quick actions on processes + * Options window has a detailed description for each setting + * Process window has descriptions for each field + * File processing (signature verification, checks for packed images) is now + asynchronous. This means that there are no more delays when starting + certain programs. + * Notification icon looks better and shows both user and kernel time + * GDI and USER handle counts + * Terminator's TT2 test is more effective now + * FIXED: + * Bug #2553406 - "COMException: Class not registered" + * Bug #2601383 - "Threads' column's width is not remembered." + * Bug #2612242 - "CPU usage > 100%" + * Bug #2615591 - "Bug with Show one graph per cpu?" + * Limited user account weirdness + * No longer deletes the KProcessHacker service if it's already started + * Memory searching now uses KProcessHacker if possible + * Incorrect labeling of process files which can't be read (due to permissions) + as packed + * Insane memory usage on Windows XP + * Now uses the proper method of detecting .NET processes + * System Information now runs on a separate thread + * Disables "Show one graph per CPU" in System Information if there is only one CPU + * Process tree weirdness for users with limited privileges + * CPU usage is now correctly displayed in graphs - K+U are not overlayed anymore + * "Require signatures for" names are now forced to be lower-case + * "Hide handles with no name" is now unique to each process window - + changing it in one window does not affect others + * Dialog/input boxes are now more consistent + * Very old bug where the refresh interval isn't applied at startup + * Displays-2-more-processes-than-actual-number bug + * System Information screwing up when the user tries to open it when it's + already open + * "a hour" -> "an hour", "yesterday ago" -> "a day ago" + * Handle leaks in the process window, thread window, handle list and process updater + * GDI+ handle leaks in the icon menu + * PH window is permanently offscreen if it is hidden when minimized + * Process colors not being refreshed when items are removed + +1.3.2.0 + * NEW: + * Network tab - shows current network connections + * KProcessHacker - an experimental kernel-mode driver for Process Hacker which + finally enables Process Hacker to display all file handles without freezing + * Can protect and unprotect processes (Vista's DRM protection) + * System Information menu item in the tray icon menu + * Hide when minimized option + * Now resolves device names into drive letters - e.g. "\Device\Harddisk1\FileName" into + "C:\FileName". + * Properly verifies system components instead of just checking file permissions + * Configurable dangerous-process-names highlighting + * Added protection against PEB file name spoofing + * Customizable fonts + * Command line switch: -m to hide Process Hacker + * Nice relative times - "2 seconds ago", "14 minutes and 33 seconds ago", etc. + * Displays service descriptions, dependencies, and dependents + * Offers to reset settings if they are corrupt + * FIXED: + * Bug #2527154 - "Process Hacker crashes on Win XP" + * Small UI enabling/disabling fixes + * Now the process tree and service list update instantly after + starting Process Hacker instead of waiting + * Random "Generic GDI+ Error" exceptions + * Small performance improvements + * Now shows proper command lines of programs where they contain null characters + * Handle filter actually works now + * Relative RunDLL targets + * Handle leaks with threads + +1.3.1.0 + * NEW: + * "Free" and "Decommit" actions for memory regions + * "Description" column for processes + * Current Directory for processes automatically updates + * Can now display the file names of DRM-protected + processes (like audiodg.exe) + * Now displays thread information under the thread list + * Module file name info for thread start addresses + and stack traces + * Highlighting for .NET processes and packed executables + * Shows CPU usage and physical memory usage in the status bar + * "Reload Struct Definitions" menu item + * Struct Searcher - displays addresses which match the specified + struct definition + * Ability to unload remote modules (by remote thread + injection) + * New float and double types for structs + * Special tooltip info for rundll32.exe + * Verifies file signatures (and detects Windows components by + checking the files' owners and ACLs) + * Highlights processes which have invalid signatures or are + pretending to be system processes + * Better method for suspending/resuming processes + * FIXED: + * System information window resizing + * "Overflow error" exceptions + * Problems with the search button + * Process properties for DPCs and Interrupts + * Disabled expanding of processes when double-clicking + them + * Now shows non-existent parent PIDs + * build-and-clean script is now XP compatible + * Redrawing problems with the lists in the process window + +1.3.0.0 + * NEW: + * Process tree using TreeViewAdv + * Process properties window with statistics and graphs + * System Information Window with statistics and graphs + * Detailed token information, including source, owner and primary group + * Information about remote handles to events, mutants, sections and tokens + * Terminator tool - tries many techniques to terminate processes + * Highlighting for UAC elevated processes and processes in job objects + * Struct reader for examining PEBs and TEBs - note that this can be + extended by writing your own definitions + * Better tray icon - displays a graph, and the tooltip contains the current + CPU usage and the process using most of the CPU + * FIXED: + * Shows SIDs without names (like Logon IDs) in SDDL format + * Uses PROCESS_QUERY_LIMITED_INFORMATION on Windows Vista - e.g. on audiodg.exe + * Symbols are now bound to each process - no more weird stack traces/symbols + * Handle filtering is now much faster - uses a cache for session ID checking + +1.2.6.5 + * A new member of the project - Dean + * Can view thread usernames, groups and privileges + * The handle filter window is now faster + * Added thread start addresses in thread list + * The process list now has less CPU usage + * Fixed some processes not having icons + +1.2.6.0 + * Fixed the fix for the huge regression - the cause was a double "free" of the same handle + * Added Assistant - can start processes as any user, including SYSTEM, + LOCAL SERVICE and NETWORK SERVICE. Injector's create process item is + now deprecated. + * Fixed service handle leaks which caused service deletions to be + undetected. + * Fixed service list in process tooltips when new own-process services are started and when + shared-process services are stopped. + +1.2.5.1 + * Fixed huge regression caused by revision #250 in Win32.ProcessHandle.~ProcessHandle() + +1.2.5.0 + * Fixed wrong usernames when Process Hacker is running as a non-admin user + * Gets command line of processes without using Injector + * Added highlighting for debugged processes + * Added viewing/setting of process affinity + * Fixed all handle leaks + * Added I/O counters to misc. info + * Added CPU usage column + * Fixed services in tooltips + * Added highlighting for processes with services + * System and System Idle Processes now have usernames (hardcoded in) + * Handle finder now only searches in processes with same session ID (faster, + avoids hangs) + * Fixed window activation when showing Process Hacker from the tray icon + * Fixed highlighting + * Fixed various memory corruption issues + +1.2.3.5 + * Added handle viewing/closing support + * Fixed random crashes + * Doesn't update threads/handles unless viewing them + * Fixed most handle leaks + * Fixed randomly changing process usernames + * Added WaitReason column in thread list + * Highlights suspended threads in thread list + * Only require highestAvailable elevation for UAC + +1.2.3.0 + * Fixed incorrect messages about "new services" (actually fixed this time) + * Fixed Injector - now uses MinGW instead of Visual C++ + * "Create Process..." feature of Injector works on XP now + * Added StartType column in services list + +1.2.2.5 + * Now shows function parameters in call stack + * Added Injector + * Added "Get Symbol Name From Address..." and "Find SYSTEM processes with same Session ID" + * Services list now displays a blank space when there is no PID + * Fixed services with own process and interactive type + * Fixed random crashes with the process list and services list + * Added copyright information (to comply with VistaMenu and SplitButton licensing) + * Now displays user names of most processes using the Terminal Server APIs + * Fixed incorrect messages about "new services" + * Added tray icon + +1.2.1.5 + * Fixed disassemblies from PE window - they disassemble the right function now + * Fixed UI inconsistencies + * Allow Toolhelp module listings + * Updated help + * Fixed service start/stop buttons in service window + +1.2.1.0 + * Can now display services + * Displays services in process tooltips + +1.2.0.5 + * Updated credits + * Fixed crash when opening two thread inspectors with the same process and thread + * Disassembler window can now display backward short jumps (>0x7fffffff) + * Now unloads symbols for all other EXEs before opening the thread inspector + * Improvements in symbol loading + +1.2.0.0 + * Added PE Inspector (can read exe/dll/sys files and their properties) + * Added "Search Online" menu item + * Added highlighting of processes and threads + * Added "Always on Top" menu item + * Added status bar messages and log + * Added "Go to Parent" menu item + * Removed "Close Active Window" menu item - practically same as "Terminate Process" + * Added disassembler + * Added Thread Inspector - shows call stack of threads + +1.1.5.0 + * Fixed memory leak with process icons + * Removed useless starting "\" in account names + * Fixed group menu item enabling and disabling + * Added filtering of search results + +1.1.4.5 + * Fixed crash when attempting to open privileges for System on XP + * Added Groups Window (to view process groups) + * Fixed Search window startup position + +1.1.4.0 + * Enabled Select All for all lists on the main window + * Added Privileges Window (to enable, disable and remove privileges) + * Fixed error messages - they now have the correct Win32 error descriptions + +1.1.3.5 + * Now saves column settings + * Now saves results and memory window settings + * Now saves selected tab + +1.1.3.0 + * Completely rewrote thread list code + * Can now display kernel threads on Vista + * Disables thread priority menu item when there is an error + * Now displays process 0 as System Idle Process + * Fixed thread list for System Idle Process + * Now displays description for System + * Now has a good system of copying list items (currently in every ListView) + +1.1.2.0 + * Completely rewrote process list code + * Added lots of information to process tooltips + +1.1.1.0 + * Memory editor is now properly activated from the Hacker Window + * Fixed obscure bug where the process list disables itself + * Added my email address + * Added CONTEXT code + * Now bolds the kernel name when the System process is selected + * Fixed opening Memory Editor from Results Window + * Changed Search button to a SplitButton + * Added username column + * Now shows process description and filename in tooltip + * Added more "options" + * Added keyboard shortcuts for terminating process(es) (Del) and refreshing (F5) + * Added some menu items - Select All and Refresh + +1.1.0.5 + * Upgraded messageboxes when performing operations on processes and threads to OKCancel + * Fixed checking for dangerous PIDs on XP + * Fixed getting icons for certain processes on XP + * Fixed crashes when attempting to read from invalid memory locations + * Fixed crash when opening help window after closing it + * Fixed default menu item text drawing + +1.1.0.0 + * Fixed certain programs' modules not having a description + * Major refactoring in code + * Moved memory editor panel into its own form + * Moved search into its own form + * Merged string scanning and heap scanning into the Search form + * Removed debug programs option + * Now has proper main menu + * Search results window is now on its own thread + * Search results list now uses VirtualMode - huge speed increase + * Added "prevent overlapping results" option + * Made memory editor windows spawn in separate threads + * Removed all Application.DoEvents() calls + * Fixed cursor problems + * Now displays busy cursor on startup + * Intersect menu is now sorted + * Fixed form focusing + * Added Window menu items in all forms + +1.0.1.0 + * Fixed occasional "Object not set to an instance of object" error + * Added link to SourceForge project page + * Fixed FlatStyle inconsistencies + * Fixed "invalid characters in path name" problem on Windows X \ No newline at end of file diff --git a/branches/ph-plugins/ExtraTools/ExtraTools.sln b/branches/ph-plugins/ExtraTools/ExtraTools.sln new file mode 100644 index 000000000..bc820629f --- /dev/null +++ b/branches/ph-plugins/ExtraTools/ExtraTools.sln @@ -0,0 +1,50 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProcessHacker.Native", "..\ProcessHacker.Native\ProcessHacker.Native.csproj", "{8A448157-E1A7-4DDF-954E-287F1117832B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProcessHacker.Common", "..\ProcessHacker.Common\ProcessHacker.Common.csproj", "{8E10F5E8-D4FA-4980-BB23-2EDD134AC15E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NtObjects", "NtObjects\NtObjects.csproj", "{06AC6477-D3DA-4997-9A4A-4F809F7C9396}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NtProfiler", "NtProfiler\NtProfiler.csproj", "{E3CEB6D7-7080-4089-B54E-41025E30CE46}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProcessAnalyzer", "ProcessAnalyzer\ProcessAnalyzer.csproj", "{A6709B97-F7B5-40AD-AB6E-F23019BA0A3C}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SysCallHacker", "SysCallHacker\SysCallHacker.csproj", "{39B5CDC9-0AB3-4E1F-862C-EA95BC5A0715}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8A448157-E1A7-4DDF-954E-287F1117832B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8A448157-E1A7-4DDF-954E-287F1117832B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8A448157-E1A7-4DDF-954E-287F1117832B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8A448157-E1A7-4DDF-954E-287F1117832B}.Release|Any CPU.Build.0 = Release|Any CPU + {8E10F5E8-D4FA-4980-BB23-2EDD134AC15E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8E10F5E8-D4FA-4980-BB23-2EDD134AC15E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8E10F5E8-D4FA-4980-BB23-2EDD134AC15E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8E10F5E8-D4FA-4980-BB23-2EDD134AC15E}.Release|Any CPU.Build.0 = Release|Any CPU + {06AC6477-D3DA-4997-9A4A-4F809F7C9396}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {06AC6477-D3DA-4997-9A4A-4F809F7C9396}.Debug|Any CPU.Build.0 = Debug|Any CPU + {06AC6477-D3DA-4997-9A4A-4F809F7C9396}.Release|Any CPU.ActiveCfg = Release|Any CPU + {06AC6477-D3DA-4997-9A4A-4F809F7C9396}.Release|Any CPU.Build.0 = Release|Any CPU + {E3CEB6D7-7080-4089-B54E-41025E30CE46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E3CEB6D7-7080-4089-B54E-41025E30CE46}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E3CEB6D7-7080-4089-B54E-41025E30CE46}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E3CEB6D7-7080-4089-B54E-41025E30CE46}.Release|Any CPU.Build.0 = Release|Any CPU + {A6709B97-F7B5-40AD-AB6E-F23019BA0A3C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A6709B97-F7B5-40AD-AB6E-F23019BA0A3C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A6709B97-F7B5-40AD-AB6E-F23019BA0A3C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A6709B97-F7B5-40AD-AB6E-F23019BA0A3C}.Release|Any CPU.Build.0 = Release|Any CPU + {39B5CDC9-0AB3-4E1F-862C-EA95BC5A0715}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39B5CDC9-0AB3-4E1F-862C-EA95BC5A0715}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39B5CDC9-0AB3-4E1F-862C-EA95BC5A0715}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39B5CDC9-0AB3-4E1F-862C-EA95BC5A0715}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/branches/ph-plugins/ExtraTools/NtObjects/NtObjects.csproj b/branches/ph-plugins/ExtraTools/NtObjects/NtObjects.csproj new file mode 100644 index 000000000..80fb1ef7a --- /dev/null +++ b/branches/ph-plugins/ExtraTools/NtObjects/NtObjects.csproj @@ -0,0 +1,92 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {06AC6477-D3DA-4997-9A4A-4F809F7C9396} + WinExe + Properties + NtObjects + NtObjects + v2.0 + 512 + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + AnyCPU + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AnyCPU + + + + + + + + + Form + + + ObjectsWindow.cs + + + + + ObjectsWindow.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + {8E10F5E8-D4FA-4980-BB23-2EDD134AC15E} + ProcessHacker.Common + + + {8A448157-E1A7-4DDF-954E-287F1117832B} + ProcessHacker.Native + + + + + \ No newline at end of file diff --git a/branches/ph-plugins/ExtraTools/NtObjects/ObjectsWindow.Designer.cs b/branches/ph-plugins/ExtraTools/NtObjects/ObjectsWindow.Designer.cs new file mode 100644 index 000000000..4399d9a38 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/NtObjects/ObjectsWindow.Designer.cs @@ -0,0 +1,163 @@ +namespace NtObjects +{ + partial class ObjectsWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ObjectsWindow)); + this.splitContainer = new System.Windows.Forms.SplitContainer(); + this.treeDirectories = new System.Windows.Forms.TreeView(); + this.imageList = new System.Windows.Forms.ImageList(this.components); + this.listObjects = new System.Windows.Forms.ListView(); + this.columnName = new System.Windows.Forms.ColumnHeader(); + this.columnType = new System.Windows.Forms.ColumnHeader(); + this.columnData = new System.Windows.Forms.ColumnHeader(); + this.splitContainer.Panel1.SuspendLayout(); + this.splitContainer.Panel2.SuspendLayout(); + this.splitContainer.SuspendLayout(); + this.SuspendLayout(); + // + // splitContainer + // + this.splitContainer.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer.Location = new System.Drawing.Point(0, 0); + this.splitContainer.Name = "splitContainer"; + // + // splitContainer.Panel1 + // + this.splitContainer.Panel1.Controls.Add(this.treeDirectories); + // + // splitContainer.Panel2 + // + this.splitContainer.Panel2.Controls.Add(this.listObjects); + this.splitContainer.Size = new System.Drawing.Size(794, 441); + this.splitContainer.SplitterDistance = 264; + this.splitContainer.TabIndex = 0; + // + // treeDirectories + // + this.treeDirectories.Dock = System.Windows.Forms.DockStyle.Fill; + this.treeDirectories.HideSelection = false; + this.treeDirectories.ImageKey = "directory"; + this.treeDirectories.ImageList = this.imageList; + this.treeDirectories.Location = new System.Drawing.Point(0, 0); + this.treeDirectories.Name = "treeDirectories"; + this.treeDirectories.SelectedImageKey = "directory"; + this.treeDirectories.Size = new System.Drawing.Size(264, 441); + this.treeDirectories.TabIndex = 0; + this.treeDirectories.MouseDown += new System.Windows.Forms.MouseEventHandler(this.treeDirectories_MouseDown); + this.treeDirectories.NodeMouseClick += new System.Windows.Forms.TreeNodeMouseClickEventHandler(this.treeDirectories_NodeMouseClick); + // + // imageList + // + this.imageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList.ImageStream"))); + this.imageList.TransparentColor = System.Drawing.Color.Transparent; + this.imageList.Images.SetKeyName(0, "object"); + this.imageList.Images.SetKeyName(1, "directory"); + this.imageList.Images.SetKeyName(2, "symboliclink"); + this.imageList.Images.SetKeyName(3, "event"); + this.imageList.Images.SetKeyName(4, "mutant"); + this.imageList.Images.SetKeyName(5, "device"); + this.imageList.Images.SetKeyName(6, "key"); + this.imageList.Images.SetKeyName(7, "alpc port"); + this.imageList.Images.SetKeyName(8, "port"); + this.imageList.Images.SetKeyName(9, "section"); + this.imageList.Images.SetKeyName(10, "job"); + this.imageList.Images.SetKeyName(11, "callback"); + this.imageList.Images.SetKeyName(12, "type"); + this.imageList.Images.SetKeyName(13, "windowstation"); + this.imageList.Images.SetKeyName(14, "desktop"); + this.imageList.Images.SetKeyName(15, "filterconnectionport"); + this.imageList.Images.SetKeyName(16, "semaphore"); + this.imageList.Images.SetKeyName(17, "session"); + this.imageList.Images.SetKeyName(18, "keyedevent"); + this.imageList.Images.SetKeyName(19, "driver"); + // + // listObjects + // + this.listObjects.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnName, + this.columnType, + this.columnData}); + this.listObjects.Dock = System.Windows.Forms.DockStyle.Fill; + this.listObjects.FullRowSelect = true; + this.listObjects.HideSelection = false; + this.listObjects.Location = new System.Drawing.Point(0, 0); + this.listObjects.Name = "listObjects"; + this.listObjects.Size = new System.Drawing.Size(526, 441); + this.listObjects.SmallImageList = this.imageList; + this.listObjects.Sorting = System.Windows.Forms.SortOrder.Ascending; + this.listObjects.TabIndex = 0; + this.listObjects.UseCompatibleStateImageBehavior = false; + this.listObjects.View = System.Windows.Forms.View.Details; + this.listObjects.DoubleClick += new System.EventHandler(this.listObjects_DoubleClick); + // + // columnName + // + this.columnName.Text = "Name"; + this.columnName.Width = 200; + // + // columnType + // + this.columnType.Text = "Type"; + this.columnType.Width = 100; + // + // columnData + // + this.columnData.Text = "Data"; + this.columnData.Width = 200; + // + // ObjectsWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(794, 441); + this.Controls.Add(this.splitContainer); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Name = "ObjectsWindow"; + this.Text = "NtObjects"; + this.splitContainer.Panel1.ResumeLayout(false); + this.splitContainer.Panel2.ResumeLayout(false); + this.splitContainer.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.SplitContainer splitContainer; + private System.Windows.Forms.TreeView treeDirectories; + private System.Windows.Forms.ImageList imageList; + private System.Windows.Forms.ListView listObjects; + private System.Windows.Forms.ColumnHeader columnName; + private System.Windows.Forms.ColumnHeader columnType; + private System.Windows.Forms.ColumnHeader columnData; + + } +} + diff --git a/branches/ph-plugins/ExtraTools/NtObjects/ObjectsWindow.cs b/branches/ph-plugins/ExtraTools/NtObjects/ObjectsWindow.cs new file mode 100644 index 000000000..23ae7eeb7 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/NtObjects/ObjectsWindow.cs @@ -0,0 +1,174 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Text; +using System.Windows.Forms; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace NtObjects +{ + public partial class ObjectsWindow : Form + { + private class TreeViewSorter : System.Collections.IComparer + { + public int Compare(object x, object y) + { + return ((TreeNode)x).Text.CompareTo(((TreeNode)y).Text); + } + } + + public ObjectsWindow() + { + InitializeComponent(); + + try + { + using (var thandle = ProcessHandle.GetCurrent().GetToken(TokenAccess.AdjustPrivileges)) + { + try { thandle.SetPrivilege("SeCreateGlobalPrivilege", SePrivilegeAttributes.Enabled); } + catch { } + } + } + catch + { } + + treeDirectories.TreeViewNodeSorter = new TreeViewSorter(); + Win32.SetWindowTheme(treeDirectories.Handle, "explorer", null); + treeDirectories.Nodes.Add("\\", "\\"); + treeDirectories.SelectedNode = treeDirectories.Nodes["\\"]; + this.PopulateDirectories(); + this.ChangeDirectory(); + treeDirectories.SelectedNode.Expand(); + } + + private void treeDirectories_MouseDown(object sender, MouseEventArgs e) + { + treeDirectories.SelectedNode = treeDirectories.GetNodeAt(e.Location); + } + + private void PopulateDirectories() + { + this.PopulateDirectory("\\"); + } + + private void PopulateDirectory(string directory) + { + try + { + using (DirectoryHandle dhandle = + new DirectoryHandle(directory, DirectoryAccess.Query)) + { + var objects = dhandle.GetObjects(); + + foreach (var obj in objects) + { + if (obj.TypeName != "Directory") + continue; + + this.GetTreeNode(directory).Nodes.Add(obj.Name, obj.Name); + + this.PopulateDirectory(this.NormalizePath(directory + "\\" + obj.Name)); + } + } + } + catch (WindowsException) + { } + } + + private string NormalizePath(string path) + { + string[] s = path.Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries); + + return "\\" + string.Join("\\", s); + } + + private TreeNode GetTreeNode(string path) + { + return this.GetTreeNode(treeDirectories.Nodes["\\"], path, 0); + } + + private TreeNode GetTreeNode(TreeNode root, string path, int index) + { + string[] s = path.Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries); + + if (index >= s.Length) + return root; + + if (root.Nodes[s[index]] == null) + return null; + + return this.GetTreeNode(root.Nodes[s[index]], path, index + 1); + } + + private void ChangeDirectory() + { + listObjects.Items.Clear(); + + if (treeDirectories.SelectedNode != null) + { + listObjects.BeginUpdate(); + + try + { + using (DirectoryHandle dhandle = + new DirectoryHandle(this.NormalizePath(treeDirectories.SelectedNode.FullPath), DirectoryAccess.Query)) + { + var objects = dhandle.GetObjects(); + + foreach (var obj in objects) + { + var item = listObjects.Items.Add(new ListViewItem(new string[] { obj.Name, obj.TypeName, "" })); + + if (imageList.Images.ContainsKey(obj.TypeName.ToLower())) + item.ImageKey = obj.TypeName.ToLower(); + else + item.ImageKey = "object"; + + if (obj.TypeName == "SymbolicLink") + { + try + { + using (SymbolicLinkHandle shandle = + new SymbolicLinkHandle( + this.NormalizePath( + treeDirectories.SelectedNode.FullPath + + "\\" + obj.Name), + SymbolicLinkAccess.Query)) + item.SubItems[2].Text = shandle.GetTarget(); + } + catch + { } + } + } + } + } + catch (WindowsException) + { } + + listObjects.EndUpdate(); + } + } + + private void treeDirectories_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) + { + this.ChangeDirectory(); + } + + private void listObjects_DoubleClick(object sender, EventArgs e) + { + if (listObjects.SelectedItems.Count != 1) + return; + + if (listObjects.SelectedItems[0].SubItems[1].Text == "Directory") + { + treeDirectories.SelectedNode = + treeDirectories.SelectedNode.Nodes[listObjects.SelectedItems[0].SubItems[0].Text]; + this.ChangeDirectory(); + } + } + } +} diff --git a/branches/ph-plugins/ExtraTools/NtObjects/ObjectsWindow.resx b/branches/ph-plugins/ExtraTools/NtObjects/ObjectsWindow.resx new file mode 100644 index 000000000..f35146b97 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/NtObjects/ObjectsWindow.resx @@ -0,0 +1,1299 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj0yLjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAADo + WAAAAk1TRnQBSQFMAgEBFAEAARwBAAEEAQABEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + AwABYAMAAQEBAAEgBgABYP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8APgADAgEDATsBTQFZ + AXwBKAFhAY8B6QEmAV4BjAHsATgBWAF3AbsBFwEYARkBIGQAAUMBWwFrAYUBSQGVAcIB6QFDAYQBswHg + ATMBOwFCAVYcAAE9AXoBzwHVASgBgQL/ASABfAL/AToBZgGlAa9EAAE8AVIBXwGCAR0BcAGnAf8BKgGL + Ab0B/wEzAaMB2QH/ATIBnwHZAf8BJgF4AbMB/wE7AUwBWwGCFAADCgENAw8BEwFyAU8BPQGYAZMBRgEt + AeMBpAFGAScB9QGpAUcBJAH6AagBRQEkAfoBogFDASUB9gGVAUIBKQHqAYgBUwE8AboDEQEWAwoBDRgA + AwoBDQMmATEBUAGUAbYB0wGGAekB+QH/AUwB2QH1Af8BPQGOAcIB8wE1AT0BRQFdFAABSQF+AcQBzAFg + AaQC/wGXAcIC/wGUAcAC/wFQAZgC/wE7AWYBpQGvOAABLAEzATcBRwEeAXgBrQH/AS8BmAHGAf8BSgHI + AeMB/wFGAcUB5wH/ASgBnQHIAf8BJwG2AeQB/wEtAZcB0AH/ATUBYAGDAckQAAFNAVkBZAF5ASYBdwHJ + AfsBhQJgAfsBvwFfATQB/wH+AbkBYAH/Af4BuQFhAf8B/gG5AWEB/wH+AbkBYQH/Af4BuQFgAf8B/gG5 + AWAB/wGxAUgBIwH/AXcBYwFsAfUBMQF9AcgB+AFRAV8BbAGDCAADGgEhA28BnQOYAfADoQH/A6sB/wFZ + AaoB1gH/AaEB5gH4Af8BNwHSAfIB/wFGAdYB9gH/AT0BkQHFAfYBNwE/AUgBYgMKAQ0DCgENCAABSAGV + Av8BoAHHAv8BgwG3Av8BfgG0Av8BlwHCAv8BUgGZAv8BPAFnAaUBrzAAATwBaQGAAa4BLgGOAb0B/wE3 + AYwBugH/ASoBdwGvAf8BQQGXAcYB/wELAVoBlQH/AQgBSQGIAf8BGwGSAc4B/wEzAacB3QH/ASwBZgGS + AeEQAAEpAX0B0AH+AYIBugHuAf8BnwFlAVcB/wH1AbsBhAL/AawBWgH/Af4BqAFZAf8B/gGiAVYB/wH+ + AZwBUgL/AaMBVAL/AZ8BTwH/AfgBrgF3Af8BpAFdAUkB/wGDAbwB7wH/ASoBdwHJAf4EAAM5AUoDoAH0 + A84B/wPtAf8D9AH/A/UB/wGtAdMB6wH/AVwBrgHgAf8BmQHiAfYB/wFSAdwB9QH/AUUB2QH2Af8BOgGN + AcQB9gE8AX0BvAHoAT0BfgG/AegBMQE4AT8BUwQAAVIBnQL/AaQBywL/AYsBvAL/AXYBsAL/AYABtQL/ + AZgBwwL/AVUBnAL/AT4BZwGiAawoAAEyAXsBoQHZATABoAHIAf8BVgGeAcgB/wFyAb0B3gH/AYIB3gH2 + Af8BWAG0AdoB/wEMAVwBkQH/ARUBgAG9Af8BJAGyAfMB/wE8Aa4B4gH/ATIBbAGRAdUQAAEpAXsBywH8 + AXcBswHqAf8BswGeAZQC/wG3AV8C/wG2AWIB/wH+AbIBYAH/Af4BrAFcAf8B/gGlAVgB/wH9AZ4BUgH/ + Af4BlwFNAv8BjQFCAf8BvAGPAYIB/wF9AbgB7QH/ASoBcwHDAfoEAAOeAeoD3gH/A/MB/wPbAf8D0gH/ + A9sB/wPWAf8BogG3AcUB/wFgAbAB3AH/AWIBvgHlAf8BXQHZAfIB/wFNAdsB9gH/AVoB3QH3Af8BVAHY + AfUB/wEyAX8BxwH3ATMBOgFDAVkBUQFoAYcBkgF4AbMC/wGlAcwC/wGNAb0C/wF4AbIC/wGDAbYC/wGZ + AcMC/wFXAZwC/wE/AWgBogGsIAABOAF6AZkBxgExAacBzwH/AXkB3QHyAf8BLQF2Aa8B/wGMAeAB9gH/ + AXcB0AHtAf8BKwGKAbgB/wEdAY0ByQH/ASUBtQHvAf8BHwGdAd0B/wFDAbUB5QH/ASkBegGsAe4QAAE9 + ATUBMQFQAYoBUwFDAf8B/AHIAasC/wHRAZgB/wH+AccBbAH/Af4BvwFnAf8B/gG5AWMB/wH+AbEBXQH/ + Af4BqAFYAf8B/QGgAVMC/wG3AXkB/wH+AakBgAH/AYgBTwFBAf8BRQE8ATcBYAQAA6AB6gPwAf8D3gH/ + A9QB/wPSAf8D2wH/A9YB/wO/Af8DsAH/AW8BpQHHAf8BiQHdAfQB/wFpAeAB9gH/AXIB4gH3Af8BXgHf + AfYB/wFUAdoB9gH/ATsBfQHDAfMEAAFSAWkBhwGSAXoBtAL/AaYBzAL/AY4BvgL/AXsBswL/AYUBuAL/ + AZsBxQL/AVgBngL/AUABaAGgAaoYAAE/AWgBewGaATsBtAHaAf8BewHZAe4B/wFOAa4B1AH/ATcBgQG0 + Af8BPwGSAb0B/wEgAYsBvAH/AS0BrAHfAf8BLwG5Ae4B/wEgAZIB0gH/AR4BnQHdAf8BQwG3AegB/wEq + AZYBzwH/ASwBMwE3AUcPAAEBAUkBOwEzAWABxAFLAR4B/wH2AeQB1gL/AeQBpAL/AdQBcQL/AckBaAL/ + AcABYgL/AbYBXgL/AcEBgAH/AfYB1wHGAf8BxQFIAR4B/wFNAT0BNQFpAwMBBAQAA6IB6gPyAf8D4gH/ + A9gB/wPVAf8D3AH/A9gB/wPAAf8DswH/AWEBqAHRAf8BqQHuAfkB/wF9AeYB+AH/AZoB6AH4Af8BfQHR + AfAB/wGAAeIB9gH/AUIBkgHLAfAIAAFTAWkBhwGSAXsBtgL/AagBzgL/AZABvwL/AYsBvQL/AaAByAL/ + AWABpAL/AUUBdwG+AckYAAEwAZUBvQHlAWgB3QHyAf8BggHdAfIB/wErAaQBygH/ASkBqgHQAf8BNQGp + AdUB/wE1AakB3AH/ATUBuAHpAf8BIwGRAcsB/wEiAZABzgH/ASMBpgHjAf8BRAG6AesB/wE7AawB4QH/ + ATwBYwF7AawQAAMFAQcBTwE/ATYBaQG8AUcBGwH/AfQB4gHUAf8BTQF6AakB/wFMAXoBqAH/AUwBegGo + Af8BTQF6AakB/wHzAdYBwwH/Ab4BRQEbAf8BUQFAATcBbwMIAQoIAAOkAeoD8wH/A+cB/wPdAf8D2QH/ + A+AB/wPbAf8DxAH/A7gB/wGDAawBxwH/AV0BwQHqAf8BowHwAfsB/wGAAdQB8AH/AX0BxwHsAf8BUQGe + AdMB9QE0AT0BRgFZDAABVAFqAYcBkgF9AbcC/wGpAc4C/wGoAc0C/wFvAawC/wFeAZoB7gH/A4cB9wMb + ASMUAAE8AYcBnQG8AVQB0gHrAf8BnQHoAfkB/wF3AeEB9gH/AWAB2AH2Af8BUQHTAfcB/wFAAcEB6gH/ + ATABqgHbAf8BKgGfAdYB/wElAZcB0QH/ASYBpwHgAf8BKgGvAekB/wFFAbYB5gH/AS0BdQGfAeIUAAME + AQUBWwFIAT8BogEzAWwBpwH/AZwBzAH4Af8BrwHUAfcB/wGvAdQB9wH/AaUBzwH2Af8BMwFzAa4B/wFe + AUoBQgGtAwcBCQwAA6UB6gP0Af8D6gH/A+EB/wPdAf8D4wH/A94B/wPJAf8DvQH/A78B/wGRAb4B3gH/ + AW4ByQHsAf8ByQHzAfsB/wFYAa4B1QHtAS0BNQE7AUgUAAFUAWsBhwGSAYEBtwL/AXsBtAL/AW4BpwHy + Af8D0gH/A7UB/wOIAf4DhgH7A4QB+wN5AdYDTQFwBAABGwEdAR4BJQExAagBxgHmASYBsgHZAf4BfQHT + AesB/wHLAfAB+wH/AYQB3QH1Af8BRgHGAesB/wE9Ab0B6QH/ATYBtQHlAf8BLAGmAdwB/wErAawB4wH/ + ASoBsAHpAf8BRwG5AegB/wEkAYQBuwH5GAABPgFbAXwBxAGmAcoB7gH/AasBzAHqAf8BpwHQAfYB/wGo + AdAB9gH/AasBzAHqAf8BpwHNAe4B/wE+AV8BhAHMEAADpwHqA/UB/wPuAf8D5gH/A+IB/wPmAf8D4QH/ + A80B/wPCAf8DwgH/AuIB4wH/AWEBmAG5AfUBTgGOAbABywE4AUgBUwFjHAABVgFrAYcBkgFkAY0BwgHP + A5EB+wPHAf8DzAH/A8cB/wPGAf8DwwH/A8AB/wOCAfUDTQFwCAABEwIUARkBPQGLAZ8BuwFXAcsB5gH/ + AakB4AHzAf8BogHjAfgB/wFJAcsB8QH/AUABxAHvAf8BOQG9AewB/wEyAbgB6wH/AS0BtAHqAf8BSAG8 + AeoB/wElAY0ByAH7GAABKAFeAZQB7QHZAegB9wH/AZcBxQHxAf8BjgG7AeUB/wF+AakB0QH/AYkBtQHf + Af8BzQHfAe4B/wEqAWcBoAHxAwQBBgwAA6gB6gP2Af8D6wH/A94B/wPWAf8D1QH/A9EB/wPDAf8DvAH/ + A8AB/wPlAf8DmQHqLAADNgFIA5IB/gPUAf8DyAH/A7wB/wO6Af8DwgH/A8QB/wN6AdYQAAEyAUEBRQFT + ATgBvwHgAf8BigHWAesB/wG2AeoB+gH/AVUBzgHxAf8BQQHDAe4B/wEqAa8B6QH/ATYBsAHoAf8BQgG4 + AegB/wExAXgBnQHYGAABCwE9AYcB/wF7AZcBuAH/AYoBtwHkAf8BcAGcAcgB/wEUAT8BbQH/ARgBQwFx + Af8BIQFEAWoB/wEUATwBZQH6AwUBBwwAA6oB6gP3Af8D5wH/A+8B/wP2Af8D+wH/A/oB/wPwAf8D3gH/ + A8MB/wPmAf8DmgHqMAADlAH8A90B/wPFAf8DeAHBA3kBwwOsAf8D1wH/A4YB+xQAARsCHgElASoBsQHU + AfcBbAHPAekB/wG8AeoB+AH/AbkB6QH5Af8BcAHMAfAB/wFAAbMB6gH/AS8BmAHUAf8BPAFUAWEBfxgA + AQ4BSgGXAf8BEQFXAZ8B/wEOAUkBigH/AQ4BSgGHAf8BEAFKAYcB/wEUAUsBhQH/AREBQAF0Af8BGAE4 + AV0B8RAAA6sB6gP4Af8D/hn/A/sB/wPqAf8DnAHqMAADlgH7A+QB/wPPAf8DegHCBAADjgH/A4wB/wOJ + AfscAAE/AXQBggGZATMBogHAAeIBLQGnAcsB8QEmAawB0wH9ATQBtgHiAf8BIQGOAcUB/gErAY0BxgH/ + ATsBaQGBAbMUAAE4AUABSwF3AREBTgGVAf4BEQFXAZsB/wERAVcBmQH/ARABUgGTAf8BDgFJAYcB/wEO + AT4BcQH+ATkBPwFIAYEQAAOPAb8D4QH/A/4Z/wP7Af8DzwH/A3QBoTAAA4kB1gPiAf8D5wH/A7kB/wOT + Af8sAAEQAhEBFQEeASEBIgEqAQwCDQEQAT4BYwFuAYMBMQG0AeAB/wFDAbUB6wH/ASIBggG0AfsYAAE5 + AUEBTgF9ARgBSgGKAfQBDwFKAZAB/wEOAUcBigH/ARYBQwF7AfUBOgFCAU0BhBQAAyIBKgOcAdED0AH/ + A+gB/wPzAf8D/QH/A/wB/wPtAf8D4AH/A8IB/wOLAcMDFQEbMAADUgFwA5cB9QPkAf8D7gH/A5YB/zwA + AT4BhAGYAbQBJgGqAdEB+wE8AXMBiwGvSAADBQEHA0MBVQOEAa4DnQHWA7QB+wOyAfkDlQHNA34BqQM3 + AUYDAgEDOAADUgFwA4oB1gOZAfsDlwH7KwABAQFJAUUBQgFkAZwBdgFXAfQBsgGAAVUB/wGvAX0BUQH/ + AZwBcwFTAfYBUgFMAUcBc1gAAXkBYQFSAakBwwGOAWcB/wHAAYsBZQH/Ab4BiAFjAf8BuwGFAWAB/wG5 + AYMBXgH/AbQBfQFbAf8BsQF6AVcB/wGuAXgBVgH/Aa0BdQFVAf8BqQFwAVAB/wF5AWEBUgGpWAABLwEt + ASwBPQGVAXcBXAHnAbIBgQFXAf8BywGrAYkB/wHRAbQBlQH/AbsBjgFiAf8BtQGHAVkB/wGrAXYBTAH/ + AZMBcgFYAesBNQEyATEBRlAAAcgBkgFrKf8BqQFxAVAB/1AAAQ8BEAEPARQDBgEIAawBfwFWAf4B1QG7 + AZ8B/wHWAbsBngH/AdMBuAGcAf8B0QGzAZQB/wG3AYkBXAH/AboBjgFhAf8BuAGNAWAB/wGyAYEBVQH/ + AacBdQFNAf4BeQFhAVIBqQHDAY4BZwH/AcABiwFlAf8BvgGIAWMB/wG7AYUBYAH/AbkBgwFeAf8BtAF9 + AVsB/wGyAXsBWQH/AbEBegFXAf8BrgF4AVYB/wGtAXUBVQH/AasBdAFTAf8BqQFyAVIB/wGpAXABUAH/ + AXkBYQFSAakUAAHYAaIBeB//Af4C/wL+Bf8BtwGBAV0B/0cAAQEBQgFHAUIBYwFhAZEBZQH0AWIBogFp + Af8BYAGhAWgB/wGxAX0BUQH/AeEBzQG4Af8B2AHAAaUB/wHYAcABpwH/AdQBugGdAf8BuAGMAV8B/wG3 + AYoBXwH/AbgBjQFgAf8BugGOAWEB/wGxAX0BUQH/AcgBkgFrNf8BqQFxAVAB/xQAAdkBowF4G/8B/gL/ + Av4B/wP+Bf8BugGFAV8B/0AAASwBLgEtAT0BZgGNAWoB5wFlAaMBawH/AZMBwAGZAf8BngHHAaQB/wFw + AawBdwH/Aa8BfQFQAf8B4wHQAbwB/wHaAcMBqwH/AdMBuAGeAf8BxwGjAXwB/wHBAZgBbgH/AbYBiQFb + Af8BtwGKAV8B/wG6AY4BYQH/AbEBgAFTAf8BygGUAW0L/wH+A/8B/QH/Av4B/QH/Av4B/AH/Av4B/AH/ + Av4B/AH/Av4B/AH/Av4B+gH/Av4B+gH/AvwB+QX/AaoBcgFSAf8MAAFsAVoBTwGUAa0BhQFmAeAB2wGk + AXkp/wG9AYcBYgH/QAABYwGeAWsB/gGpAc0BrwH/AaYBzAGsAf8BogHJAakB/wGZAcUBnwH/AWoBqQFz + Af8BrgF7AU4B/wHcAcgBsAH/Ab8BnwGBAf8BuAGNAWQB/wHRAbMBjwH/AdEBswGPAf8BuwGQAWUB/wG8 + AZEBZwH/AbcBigFfAf8BsQF9AVEB/wHMAZcBbgf/AfwD/wH9Af8C/gH8Af8C/gH8Af8C/gH7Af8C/QH6 + Af8C/QH6Af8C/QH6Af8C/QH6Af8C/AH3Af8C+wH2Bf8BrAF0AVMB/wwAAbEBhwFpAeAD2wHgAdwBpwF6 + Af8B3AGnAXoB/wHcAacBegH/AdwBpwF6Af8B3AGnAXoB/wHcAacBegH/AdwBpwF6Af8B3AGnAXoB/wHc + AacBegH/AdwBpwF6Af8B3AGnAXoB/wHAAYsBZQH/BAADAgEDAyIBMANPAd8DZAH0A2sB9wNqAfkDPAFe + Ay8BQwNqAfIDawH3A2QB9ANPAd8DIgEwAwIBAwQAAWEBoQFoAf8BwAHaAcUB/wGtAdABswH/AasBzgGx + Af8BngHIAaYB/wFsAaoBdQH/AZUBegF9Af8BWQFgAcgB/wFPAVcB4wH/AU4BVQHgAf8BVwFeAcgB/wGQ + AXcBhAH/AbsBkAFlAf8B0QGzAY8B/wHGAaIBegH/AagBeAFPAf4B0QGcAXIF/wL+AfwB/wL+AfwB/wL+ + AfwB/wL9AfsB/wL9AfsB/wL9AfoB/wL9AfgB/wL7AfkB/wH7AfoB9wH/AfsB+gH2Af8B+wH4AfQF/wGw + AXkBVwH/DAABvQGTAXQB4APbAeAB3QGtAYYB/wHoAbkBkgH/AegBuQGSAf8B6AG5AZIB/wHoAbkBkgH/ + AegBuQGSAf8B6AG5AZIB/wHoAbkBkgH/AegBuQGSAf8B6AG5AZIB/wHoAbkBkgH/Ab8BkAFuAf0EAAMd + ASkDUgHXA4gB7wOhAe0DrgH/A5cB/wNwAf8DdwH/A5cB/wOuAf8DoQHtA4gB7wNSAdcDHQEpBAABXwGg + AWcB/wHFAd4ByQH/AbQB1AG5Af8BpAHJAaoB/wGBAasBmgH/AWABbAHDAf8BTwFXAeAB/wFlAWcB6wH/ + ApMB9AH/AWABYgHqAf8BVwFaAeQB/wFIAVEB3AH/AV8BYgG+Af8BpgGJAX4B/wHBAZoBcAH/AYkBdQFm + AcgB1AGeAXQF/wL+AfwB/wL9AfsB/wL9AfwB/wL9AfsB/wL9AfkB/wL8AfgB/wH7AfkB9wH/AfsB+QH1 + Af8B+wH4AfQB/wH7AfcB8gH/AfsB9QHyBf8BsgF7AVkB/wwAAb4BlAF0AeAD2wHgAcgBswGnAe0B3QGz + AZAB/gHcAacBegH/AdwBpgF5Af8B2gGkAXkB/wHYAaIBeAH/AdUBoAF1Af8B0gGdAXIB/wHPAZoBcQH/ + Ac4BmQFvAf8BxAGaAXgB/wFRAUcBQQFrBAADOwFpA2YB7wNTAXQDVAG5A0IB+gNFAf8DUAH/A1AB/wNF + Af8DQgH6A1QBuQNTAXQDZgHvAzsBaQQAAVwBnwFkAf8BuQHWAb4B/wGHAboBjwH/AXABrAF3Af8BUgFY + AdwB/wFlAWkB6wH/AZgBlgH0Af8CkQHzAf8BiQGKAfAB/wFaAV4B5wH/AV4BYQHpAf8BXAFgAegB/wFQ + AVcB5AH/AUkBVAHXAf4BMwIxAUMDCAEKAdUBoAF1Bf8C/QH8Af8C/QH7Af8C/QH6Af8C/AH5Af8B/AH7 + AfcB/wH7AfkB9QH/AfsB+AH0Af8B+wH3AfMB/wH7AfUB8gH/AfoB8wHvAf8B+AHyAewF/wG1AX0BWwH/ + BAABYAFSAUkBggGZAXkBYwHEAdIBnwF3AfgB8QHrAegB+AHwAesB6AH4AfAB6gHnAfgB7wHqAecB+AHv + AeoB5wH4Ae8B6gHnAfgB7wHqAeYB+AHvAekB5gH4AecB5QHiAfAD2wHgAagBfwFiAeAMAANCAYoDgQH3 + A0oBZwMIAQoDQgHzA70B/wPOAf8DwgH/A60B/wNCAfMDCAEKA0oBZwOBAfcDQgGKBAABZAGfAWsB/gGG + AboBjwH/AZkBxgGiAf8BcwGtAXsB/wFOAVYB4gH/AbQBsQH5Af8BlwGWAfQB/wKTAfQB/wGMAY0B8AH/ + AVsBXwHoAf8BWwFgAecB/wFcAWAB6AH/AV4BYQHpAf8BTgFWAeIB/wIkASYBMAQAAdgBogF4Bf8C/QH6 + Af8C/AH6Af8B/AH7AfkB/wH7AfoB9gH/AfsB+AH1Af8B+wH3AfQB/wH7AfYB8QH/AfgB9AHuAf8B9wHy + AesB/wH3AfAB6gH/AfYB7AHoBf8BtwGBAV0B/wQAAZwBfAFlAcQDvAHEAdkBrAGGAfgB2QGsAYYB+AHZ + AawBhgH4AdkBrAGGAfgB2QGsAYYB+AHZAawBhgH4AdkBrAGGAfgB2QGsAYYB+AHZAawBhgH4AdEBnwF2 + AfgBwAGYAXYB4AGrAYIBZQHgDAADMQFOA3AB8APGAe4DVwG2A0oB/ANkAf8DkgH/A3gB/wNkAf8DSgH8 + A1cBtgOYAeEDcAHwAzEBTgQAAWwBhQFvAcgBewG0AYUB/wF1Aa8BfQH/AW4BqwF3Af8BTQFTAeEB/wG0 + AbEB+QH/AZUBlgH1Af8BZQFpAesB/wFuAXAB7AH/AW0BcQHsAf8BWQFbAeUB/wFbAWAB5wH/AV4BYQHp + Af8BUAFXAeIB/wIkASYBMAQAAdkBowF4Bf8B/AH7AfkB/wH8AfsB+AH/AfsB+QH3Af8B+wH3AfQB/wH6 + AfcB8gH/AfkB9QHwAf8B9wHzAe0B/wH2Ae8B6gH/AfUB6wHnAf8B8wHqAeQB/wHyAecB3gX/AboBhQFf + Af8EAAGlAYUBbQHEA7wBxAHZAa8BjgH3AeMBuwGbAfgB4wG7AZsB+AHjAbsBmwH4AeMBuwGbAfgB4wG7 + AZsB+AHjAbsBmwH4AeMBuwGbAfgB4wG7AZsB+AHcAbABiwH4AcoBpgGHAeABqQGEAWsB3gwAAwQBBgNK + AYoDkQH/A+gB/wPdAf8DwQH/A3kB3gNtAcID0wH4A90B/wPEAf8DkQH/A0oBigMEAQYEAAMIAQoBKwEt + ASsBOwE+AUIBPgFbAW0BqAF2Af8BSwFRAeAB/wKiAfQB/wFpAWsB7AH/AWABYgHqAf8BlwGTAfcB/wGX + AZMB9wH/AWMBZwHpAf8BZAFlAeoB/wFbAWAB5wH/AU4BVgHiAf8CJAEmATAEAAHbAaQBeTX/Ab0BhwFi + Af8EAAGmAYUBbQHEA7wBxAG5AagBngHaAdgBtAGXAfYB2QGsAYYB+AHZAasBhQH4AdgBqQGFAfgB1gGn + AYQB+AHTAaUBgQH4AdABowF/AfgBzgGgAX4B+AHGAZUBbQH4Aa4BjQF0AeABRwFAATwBXhAAAwgBCwNK + AXUDgQHuA54B/wN2AeEDKAE3AxIBGAN1Ad0DngH/A4EB7gNKAXUDCAELGAABVAFaAdoB/gJ7AfIB/wGX + AZMB9wH/AWMBZwHpAf8BUQFXAeMB/wFRAVcB4wH/AWMBZwHpAf8BlwGTAfcB/wJ7AfIB/wFNAVYB2AH+ + Ah0BHwEmBAAB3AGnAXoB/wHcAacBegH/AdwBpwF6Af8B3AGnAXoB/wHcAacBegH/AdwBpwF6Af8B3AGn + AXoB/wHcAacBegH/AdwBpwF6Af8B3AGnAXoB/wHcAacBegH/AdwBpwF6Af8B3AGnAXoB/wHcAacBegH/ + AcABiwFlAf8EAAGmAYYBbgHEA7wBxAO8AcQDvAHEA7wBxAO8AcQDvAHEA7wBxAO8AcQDvAHEA7wBxAGV + AXUBXwHEYAABawFuAaMByAFtAW4B7AH/AWUBZwHrAf8BXgFhAekB/wJ3AfAB/wJzAfAB/wFeAWEB6QH/ + AWgBagHrAf8BbgFwAewB/wFqAW0BoQHICAAB2wGrAYUB/QHoAbkBkgH/AegBuQGSAf8B6AG5AZIB/wHo + AbkBkgH/AegBuQGSAf8B6AG5AZIB/wHoAbkBkgH/AegBuQGSAf8B6AG5AZIB/wHoAbkBkgH/AegBuQGS + Af8B6AG5AZIB/wHoAbkBkgH/Ab8BkAFuAf0EAAGnAYgBbwHEAacBiAFvAcQBpwGIAW8BxAGnAYgBbwHE + AacBiAFvAcQBpwGIAW8BxAGnAYgBbwHEAacBiAFvAcQBpwGIAW8BxAGnAYgBbwHEAacBiAFvAcQBlwF4 + AWEBxGAAAwgBCgErASwBLwE7AT4BPwFIAVsBYAFiAeMB/wFQAVYB4gH/AVABVgHiAf8BXgFhAeMB/wE/ + AUABSgFeASsBLAEvATsDCAEKCAABUQFHAUEBawHSAaoBigH0AdwBpwF6Af8B3AGmAXkB/wHaAaQBeQH/ + AdgBogF4Af8B1QGgAXUB/wHUAZ4BdAH/AdIBnQFyAf8BzwGaAXEB/wHOAZkBbwH/AcsBlgFuAf8ByQGU + AWsB/wG8AZUBeAH0AVEBRwFBAWsEAAGlAYkBcwHCAa4BkwF8AcQBrgGTAXwBxAGuAZMBfAHEAa4BkwF8 + AcQBrgGTAXwBxAGuAZMBfAHEAa4BkwF8AcQBrgGTAXwBxAGuAZMBfAHEAa4BkwF8AcQBlgF6AWYBwtAA + AT8BOQE2AVIBoAGIAXUBvAGnAYgBbwHEAacBiAFuAcQBpgGGAW4BxAGjAYQBawHEAaMBggFrAcQBoQGC + AWkBxAGgAYABaQHEAZ8BgAFoAcQBmQGAAW0BxAE/ATkBNgFSUAACEgERARcBqwFoATwB/wGiAV8BOwH2 + ATABLAEqAT90AAMGAQgBSQFRAVsBbgFjAXsBlgGzAWYBiwG1Ad0BXAGNAb8B9AFOAYYBvQH9AT4BegGz + Af8BLgFvAagB/wEiAWUBngH9ARoBXQGRAfQBIAFYAYQB3QExAVYBcgGzATUBRAFOAW4DBgEICAABsgF7 + AVkC1QGDAVAB/wHRAXwBSgH/AY8BZgFNAa8sAAG6AXoBSQH/AcABiQFeAf8BvwGJAWEB/wGvAWwBRgH/ + ATIBLQErAUFwAAFoAYMBpAHEAYcBtwHgAf8BlQHGAeYB/wGbAc0B6QH/AZwBzQHpAf8BmQHHAecB/wGV + AcEB5AH/AY4BuAHgAf8BiQGwAd0B/wGBAacB1wH/AXIBmwHPAf8BXAGMAcIB/wE9AXcBrgH/ASwBWAF6 + AcQEAAGsAX4BYgHMAd8BpAGBAf8B6gHCAasB/wHqAcABqAH/AdwBmQFwAf8BjwFnAU4BrygAAcMBiAFY + Af8BzwGiAXwB/wHNAaIBgAH/AcABjAFlAf8BsAFxAUgB/wFrAVMBRgGVATsBNQExAU4BLAEoAScBOQEX + AhYBHgMDAQRcAAFoAYMBpAHEAZgBuQHUAf8BxQHHAcQB/wHsAdgBxwH/AfYB6wHjAf8B+gH1AfEB/wHz + AecB3gH/Ad8BvwGmAf8B0AGkAYAB/wHLAZoBcwH/AcgBlwFwAf8BowGTAYwB/wFhAX4BnAH/ASwBWAF6 + AcQEAAHbAZcBbgH/Ae0ByAGzAf8B5wG4AZsB/wHmAbQBmAH/AeoBwwGrAf8B3gGcAXIB/wGPAWgBTwGv + JAABWwFQAUcBcQHMAZkBcAH/AdABowGBAf8BzwGkAYMB/wHKAZ4BegH/AbwBhQFcAf8BrwFwAUgB/wGn + AWMBPwH/AZ4BVgE3Af8BfwFQAUABxgMHAQlYAAIiASEBKgHmAcMBpQH/Ae8B1gHAAf8B+wHyAeoB/wH+ + AfwB+gL/Af4B/QH/Af4B/QH8Af8B/AH2AfAB/wH4AegB2QH/AfYB4wHRAf8B9gHiAc4B/wHmAcgBrQH/ + Ac4BoAF6Af8BIQIgASoEAAHdAZ8BeAH/Ae0BzAG3Af8B6AG9AaMB/wHkAbEBkgH/AeYBtgGaAf8B6gHD + AawB/wHeAZwBcwH/AY4BaAFRAawkAAFdAVEBSQFyAc4BnQF1Af8B1QGsAYwB/wHLAZsBdQH/AcwBoAF7 + Af8ByAGbAXUB/wHFAZUBbgH/AcABjwFoAf8BrAFsAUcB/wFUAUUBPwF2FAADfwG3A6AB/wObAf8DlwH/ + A5IB/wOOAf8DigH/A4UB/wOBAf8DfAH/A3gB/wN0Af8DcQH/A20B/wNqAf8DYQG3CAABpAGQAX4BuQHt + AdMBuwH/AfoB8AHlAf8B/QH5AfUB/wH+AfwB+gH/Af4B/QH8Af8B/QH5AfQB/wH2AeMBzwH/AfcB5QHT + Af8B9gHjAdEB/wHdAbkBmgH/AZQBegFmAbgIAAF8AWkBXQGSAeYBswGUAf8B7gHMAbgB/wHpAb4BpQH/ + AeUBswGUAf8B5gG3AZsB/wHqAcQBrQH/Ad4BngF3Af8BjgFpAVEBrCQAAZABdgFiAbEB0wGoAYYB/wHW + AawBjgH/AckBmAFwAf8BxAGQAWcB/wG/AYoBXgH/AcIBjwFmAf8BvwGLAWMB/wF+AWYBRwH7ASABHgEd + ASkQAAOpAf8D6QH/A9MB/wPSAf8D0QH/A9AB/wPOAf8DzQH/A80B/wPLAf8DywH/A8oB/wPJAf8DyAH/ + A+IB/wNqAf8MAAGbAYoBewGwAegBxwGrAf4B9wHqAd4B/wH+AfoB9wH/Af4B/AH5Af8B/QH3AfIB/wH6 + Ae0B4gH/AesB0AG3Af8B0AGhAX4B/gGOAXcBZgGuEAABfAFpAV4BkgHmAbQBmAH/Ae4BzQG6Af8B6QG/ + AaUB/wHlAbQBlgH/AecBuQGdAf8B6wHGAa4B/wHeAZ8BeAH/AY0BaAFSAaogAAFAATwBOAFOAdQBowF9 + Af8B3AG1AZgB/wHQAaEBfAH/AcwBmgFzAf8BzwGkAYMB/wHIAZoBdQH/AXwBjAFjAf8BaQG4AXkB/wGL + AVABNQH7AXABSwFAAa8DBwEJCAADrgH/A9YB/wOxAf8DqAH/A6YB/wOkAf8DogH/A6EB/wOeAf8DnAH/ + A5wB/wOaAf8DmQH/A6IB/wPIAf8DbgH/EAABMQEvAS0BOgHLAbQBnwHhAfMB4gHSAf8B/AH0Ae0B/wH7 + AfEB5wH/AekBzAG1Af8BuQGYAX4B3AEuASwBKgE4GAABfQFqAV8BkgHmAbcBmQH/Ae4BzgG7Af8B6QHA + AacB/wHoAb0BowH/AewByAGzAf8B3wGkAYEB/wGmAXgBXAHJIAABLwEtASsBOQHbAasBiQH/AeEBvQGi + Af8B1gGqAYcB/wHZAbMBlAH/Ac4BnwF5Af8BlAGIAV8B+wFsAbwBewH/AZMBbgFFAf8BsAF0AU4B/wGk + AWEBQAH/AYMBSgE5AdoDAwEEBAADsgH/A9kB/wNwAf8DZgH/A2UB/wNjAf8DYwH/A2IB/wNgAf8DYAH/ + A18B/wNdAf8DXAH/A3cB/wPKAf8DcgH/GAABsgGdAYoBxwH0AeMB0AH/AfMB3wHNAf8BqAGPAXwBwyQA + AX0BawFfAZIB5gG3AZwB/wHvAc8BvAH/Ae4BzgG6Af8B4gGuAYwB/wHSAZsBegH/A4cB9wMbASMcAAEZ + ARgBFwEeAeABsQGPAf8B5gHEAasB/wHiAb8BpAH/AdgBrQGOAf8BpgGSAXAB+gFaAVIBSAF3AaIBdwFH + AfwBuwGEAVwB/wHAAY8BaAH/AbwBigFgAf8BnAFRATQB/wEXAhYBHgQAA7cB/wPdAf8DtwH/A60B/wOs + Af8DqgH/A6gB/wOmAf8DpQH/A6MB/wOhAf8DngH/A50B/wOoAf8DzwH/A3YB/xgAAa8BmQGHAcMB9AHh + Ac4B/wHzAd8BzAH/AagBkAF8AcIoAAF9AWsBYAGSAecBuQGcAf8B5gG2AZgB/wHYAakBjAH/A9IB/wO1 + Af8DiAH+A4YB+wOEAfsDeQHWA00BcAwAAwMBBAHCAaABiQHaAeQBuwGfAf8B5AG7AZ8B/wGeAaQBgwH8 + AXUBwQF+Af8BrgGNAVkB/AHHAZYBbgH/AcsBngF6Af8BvAGFAVgB/wHDAZIBawH/AaYBYgE+Af8BLAEo + AScBOQQAA48BvQPaAf8DyAH/A8EB/wPAAf8DvgH/A7sB/wO5Af8DuAH/A7YB/wO0Af8DsQH/A7AB/wO0 + Af8DwwH/A20BvRAAAS8BLgEsATgBzAGzAZ0B3QHzAd0ByQH/AfoB7gHiAf8B+QHrAd4B/wHtAdABtgH/ + Ab8BogGIAdsBLwEtASsBOCQAAX4BbAFhAZIBsAGPAXoBzwORAfsDxwH/A8wB/wPHAf8DxgH/A8MB/wPA + Af8DggH1A00BcAwAAwcBCQGZAYMBdgGvAbYBrwGQAfkBdgHFAYIB/wG1AbABgQH/AdgBsAGSAf8B1wGu + AY8B/wHJAZcBbgH/AcMBjwFlAf8ByAGbAXUB/wGxAXABSQH/ATwBNQExAU4EAAOSAb0D4wH/A+cB/wPh + Af8D4AH/A+AB/wPfAf8D3wH/A94B/wPdAf8D3QH/A9wB/wPbAf8D4AH/A9AB/wNvAb0MAAGhAZIBhAGv + AfQB1QG4Af4B+QHsAeAB/wH9AfgB9AH/AfsB8AHmAf8B+AHnAdcB/wH5AesB3gH/AfIB2gHFAf8B4QG4 + AZYB/gGVAYIBcgGuKAADNgFIA5IB/gPUAf8DyAH/A7wB/wO6Af8DwgH/A8QB/wN6AdYUAAIfAR4BJgHD + AbIBhgH9AeIBvgGjAf8B3wG3AZoB/wHVAagBhgH/AdABoQF8Af8BywGaAXIB/wHOAaIBgAH/Ab8BiwFh + Af8BbgFXAUcBlQQAAzMBPwPOAf8D7AH/A94B/wPYAf8D0gH/A8wB/wPIAf8DxwH/A8gB/wPLAf8D0AH/ + A90B/wPoAf8DpQH/AzEBQggAAawBnAGNAbgB+QHjAc0B/wH7AfMB7AH/Af4B+gH3Af8B/gH7AfgB/wH8 + AfUB7QH/AfcB5gHVAf8B9gHhAcwB/wH5AewB3wH/AfkB6wHdAf8B6wHOAbQB/wGeAYkBeAG4KAADlAH8 + A90B/wPFAf8DeAHBA3kBwwOsAf8D1wH/A4YB+xgAAWUBWwFUAXYB5AG6AZ0B/wHmAcQBqwH/AeIBvgGk + Af8B3gG5AZwB/wHZAbIBkwH/AdEBowF+Af8B0QGmAYUB/wG7AX4BUAH/ATEBLQErAT8EAAOUAb0D4wH/ + A9sB/wPiAf8D4gH/A+EB/wPgAf8D4AH/A+AB/wPfAf8DwwH/A9EB/wPTAf8DdgG9CAABIwIiASoBwAHF + Ac0B/wGaAbcB3AH/AXwBpgHVAf8BYgGVAcoB/wFOAYcBvgH/AT4BegGzAf8BLgFvAagB/wEiAWYBnwH/ + AR0BYgGYAf8BKwFqAZoB/wFSAYMBpwH/AYgBlAGaAf8CIQEgASokAAOWAfsD5AH/A88B/wN6AcIEAAOO + Af8DjAH/A4kB+xgAAwcBCQGvAZMBgAHGAeMBtAGTAf8B3wGxAY4B/wHaAasBiQH/AdoBrQGMAf8B3AG1 + AZgB/wHXAa8BkAH/AcwBmwFzAf8BswF3AUUB+gQAAzMBPwPRAf8D8wH/A+0B/wPtAf8D7QH/A+0B/wPt + Af8D7AH/A+wB/wPsAf8D8QH/A7AB/wMyAUIIAAFxAY0BrgHRAYcBtwHgAf8BlQHGAeYB/wGbAc0B6QH/ + AZwBzQHpAf8BmQHHAecB/wGVAcEB5AH/AY4BuAHgAf8BiQGwAd0B/wGBAacB1wH/AXIBmwHPAf8BXAGM + AcIB/wE9AXcBrgH/AS8BXQGAAdEkAAOJAdYD4gH/A+cB/wO5Af8DkwH/KAADAwEEARkCGAEeATABLQEs + ATkBQQE8ATkBTgF8AWwBXwGUAdgBpwGCAf8B1wGsAYsB/wHTAacBhAH/AboBggFWAfYIAAOWAb0DxQH/ + A8EB/wO+Af8DugH/A7YB/wOyAf8DrgH/A6kB/wOlAf8DoQH/A34BvQwAAWgBgwGkAcQBhwG3AeAB/wGV + AcYB5gH/AZ0BzwHqAf8BoQHTAewB/wGgAdEB6wH/AZsBygHoAf8BlgHCAeUB/wGPAboB4gH/AYcBsQHd + Af8BeAGjAdQB/wFgAZABxAH/AT0BdwGuAf8BLAFYAXoBxCQAA1IBcAOXAfUD5AH/A+4B/wOWAf88AAEz + ATABLgE+AdABngF6AfsByAGWAW4B9gE6ATYBMgFIRAADBgEIAUkBUQFbAW4BYwF7AZYBswFsAZABuQHd + AW8BmgHNAfQBcAGfAdUB/QFoAZkB0QH/AVsBkAHIAf8BTgGGAb0B/QFBAXkBrAH0ATsBawGXAd0BPAFf + AXoBswE3AUUBTwFuAwYBCCgAA1IBcAOKAdYDmQH7A5cB+xAAATUBnQHZAf8BMAGZAdgB/wErAZQB1wH/ + AScBkAHWAf8BIgGMAdUB/wEdAYgB1AH/ARkBhAHTAf8BFAGAAdIB/wEQAXsB0QH/AQ0BeAHRAf8BCQF1 + AdAB/wEGAXIBzwH/AQMBbwHPAf8BAAFtAc4B/xwAA0IBYwNYAb8DVQG/Az4BYzAAAwoBDQMmATEDJAEv + AwUBBxgAAhIBEQEXAasBaAE8Af8BogFfATsB9gEwASwBKgE/NAABPAGjAdoB/wG8AesB+gH/AbwB6wH8 + Af8BvwHuAf4B/wHGAfQC/wHOAfgC/wHTAfoC/wHQAfgC/wHHAfIC/wG6AekB/AH/AbMB5AH5Af8BsAHi + AfgB/wGwAeIB+AH/AQQBcAHPAf8QAAMfASkDCwEOAwEBAgN8AeoDvQH/A7IB/wNcAeoDAQECAwsBDgMe + ASkYAAMaASEDbwGdA5gB8AOhAf8DqwH/A6cB/wOVAf8DhgHnA1wBigMRARYMAAG6AXoBSQH/AcABiQFe + Af8BvwGJAWEB/wGvAWwBRgH/ATIBLQErAUEwAAFCAagB2wH/Ab8B7AH7Af8BWAHPAfUB/wFAAbAB7AH/ + AU0BugHvAf8BWQHCAe8B/wFfAcYB7wH/AVsBxAHvAf8BSwG2Ae8B/wE2AaUB5gH/ASkBmgHhAf8BNwG4 + Ae4B/wGxAeMB+AH/AQgBdAHQAf8MAANiAZsDbgH9A2QB5wMTARkDfgHnA8sB/wPHAf8DYgHnAxMBGQNa + AecDTgH9A0wBmxAAAzkBSgOgAfQDzgH/A+0B/wP0Af8D9QH/A/QB/wPvAf8D4gH/A7oB/wODAecDKAE1 + CAABwwGIAVgB/wHPAaIBfAH/Ac0BogGAAf8BwAGMAWUB/wGwAXEBSAH/AWsBUwFGAZUBOwE1ATEBTgEs + ASgBJwE5ARcCFgEeAwMBBBwAAUgBrQHcAf8BwQHuAfsB/wFeAdMB9wH/AWsB2wH8Af8BfgHlAv8BjwHt + Av8BlwHyAv8BkwHtAv8BewHfAv8BWgHMAfgB/wFFAb4B7wH/ATsBugHuAf8BswHjAfkB/wENAXgB0QH/ + CAADWgF7A7wB/wPeAf8DpgH/A4AB9AOEAf4DxAH/A8IB/wNtAf4DbAH0A6YB/wPSAf8DgAH/A0gBewwA + A54B6gPeAf8D8wH/A9sB/wPSAf8D2wH/A9YB/wPAAf8DyQH/A+YB/wPEAf8DhQHqCAABWwFQAUcBcQHM + AZkBcAH/AdABowGBAf8BzwGkAYMB/wHKAZ4BegH/AbwBhQFcAf8BrwFwAUgB/wGnAWMBPwH/AZ4BVgE3 + Af8BfwFQAUABxgMHAQkYAAFNAbIB3QH/AcMB7wH7Af8BZAHWAfgB/wFLAbYB7AH/AVkBvQHvAf8BlQHr + Av8BLwGXAd0B/wFMAYIBqwH/AYQB4QL/AUABqQHpAf8BMQGfAeEB/wFBAb4B7wH/AbQB5QH5Af8BEgF9 + AdIB/wgAA14BfQOlAf4D1QH/A8UB/wPLAf8D0QH/A8kB/wPHAf8DzAH/A8UB/wO9Af8DywH/A24B/gNN + AX0MAAOgAeoD8AH/A94B/wPUAf8D0gH/A9sB/wPWAf8DvwH/A7AB/wOzAf8D3gH/A4kB6gwAAV0BUQFJ + AXIBzgGdAXUB/wHVAawBjAH/AcsBmwF1Af8BzAGgAXsB/wHIAZsBdQH/AcUBlQFuAf8BwAGPAWgB/wGs + AWwBRwH/AVQBRQE/AXYYAAFSAbcB3gH/AcYB8AH8Af8BaQHZAfgB/wF7AeIB/QH/AZAB6AL/AZkB6QL/ + ATEBnwHfAf8BUwGLAbIB/wGKAeIC/wFpAdAB+QH/AU8BxQHxAf8BRQHBAfAB/wG2AecB+QH/ARcBgwHT + Af8MAANjAYUDxQH/A8EB/wPFAf8DxwH/A6oB/wOnAf8DwQH/A74B/wO1Af8DqgH/A1EBhRAAA6IB6gPy + Af8D4gH/A9gB/wPVAf8D3AH/A9gB/wPAAf8DswH/A7cB/wPgAf8DjgHqEAABkAF2AWIBsQHTAagBhgH/ + AdYBrAGOAf8ByQGYAXAB/wHEAZABZwH/Ab8BigFeAf8BwgGPAWYB/wG/AYsBYwH/AX4BZgFHAfsBIAEe + AR0BKRQAAVcBuwHfAf8BxwHxAfwB/wFuAdwB+QH/AVUBuwHtAf8BYAG9Ae8B/wGbAecC/wE0AaYB4gH/ + AUoBpAHhAf8BkAHiAv8BSAGtAekB/wE3AaQB4wH/AUgBxAHwAf8BuAHoAfkB/wEdAYgB1AH/BAADigHN + A4UB4wOYAe4DzwH/A8YB/wPMAf8DhAHGAzQBRAMzAUQDegHGA8EB/wO8Af8DuQH/A2MB7gNZAeMDVgHN + CAADpAHqA/MB/wPnAf8D3QH/A9kB/wPgAf8D2wH/A8QB/wO4Af8DuwH/A+EB/wOSAeoQAAFAATwBOAFO + AdQBowF9Af8B3AG1AZgB/wHQAaEBfAH/AcwBmgFzAf8BzwGkAYMB/wHIAZoBdQH/AXwBjAFjAf8BaQG4 + AXkB/wGLAVABNQH7AXABSwFAAa8DBwEJDAABWwG/AeAB/wHIAfMB/AH/AXQB3wH5Af8BiQHmAf0B/wGV + AecC/wGaAeUC/wGqAe4C/wGoAe0C/wGZAeMC/wFzAdUB+QH/AVgBzAHzAf8BTgHIAfEB/wG7AekB+gH/ + ASMBjQHVAf8EAAO+Af0D4gH/A9IB/wPGAf8DzQH/A7EB/wMzAUQIAAM0AUQDqAH/A8IB/wO3Af8DwAH/ + A9IB/wNgAf0IAAOlAeoD9AH/A+oB/wPhAf8D3QH/A+MB/wPeAf8DyQH/A70B/wO/Af8D4gH/A5QB6hAA + AS8BLQErATkB2wGrAYkB/wHhAb0BogH/AdYBqgGHAf8B2QGzAZQB/wHOAZ8BeQH/AZQBiAFfAfsBbAG8 + AXsB/wGTAW4BRQH/AbABdAFOAf8BpAFhAUAB/wGDAUoBOQHaAwMBBAgAAV8BwgHhAf8ByQHzAfwB/wHL + AfMB/QH/AdQB9gH+Af8B1wH2Av8B2AH0Av8B4AH4Av8B3wH4Av8B2gH1Av8BzQHxAfwB/wHCAe0B+gH/ + Ab0B6wH6Af8BvQHrAfoB/wEqAZMB1gH/BAADwgH9A+kB/wPWAf8DyQH/A84B/wOlAf8DMgFECAADNAFE + A6wB/wPEAf8DugH/A8YB/wPdAf8DagH9CAADpwHqA/UB/wPuAf8D5gH/A+IB/wPmAf8D4QH/A80B/wPC + Af8DwgH/A+MB/wOWAeoQAAEZARgBFwEeAeABsQGPAf8B5gHEAasB/wHiAb8BpAH/AdgBrQGOAf8BpgGS + AXAB+gFaAVIBSAF3AaIBdwFHAfwBuwGEAVwB/wHAAY8BaAH/AbwBigFgAf8BnAFRATQB/wEXAhYBHggA + AWABwwHhAf8BiAGgAagB/wORAf8DjgH/AVkBuQHcAf8BVAG4Ad8B/wFQAbUB3gH/AUwBsQHdAf8BSAGt + AdwB/wFFAagB1wH/A3cB/wN1Af8BZAF9AY0B/wEwAZkB2AH/BAADogHNA68B4wO0Ae4D2AH/A80B/wO8 + Af8DcwHGAzEBRAMyAUQDegHGA8MB/wPCAf8DzQH/A4cB7gN/AeMDdQHNCAADqAHqA/YB/wPrAf8D3gH/ + A9YB/wPVAf8D0QH/A8MB/wO8Af8DwAH/A+UB/wOZAeoQAAMDAQQBwgGgAYkB2gHkAbsBnwH/AeQBuwGf + Af8BngGkAYMB/AF1AcEBfgH/Aa4BjQFZAfwBxwGWAW4B/wHLAZ4BegH/AbwBhQFYAf8BwwGSAWsB/wGm + AWIBPgH/ASwBKAEnATkMAAN/AcMDxgH/A5QB/wMGAQgQAAMGAQgDfAH/A6sB/wNrAcMQAANqAYUD1AH/ + A8wB/wPJAf8DugH/A5wB/wOhAf8DwgH/A8YB/wPBAf8DtwH/A1kBhRAAA6oB6gP3Af8D5wH/A+8B/wP2 + Af8D+wH/A/oB/wPwAf8D3gH/A8MB/wPmAf8DmgHqFAADBwEJAZkBgwF2Aa8BtgGvAZAB+QF2AcUBggH/ + AbUBsAGBAf8B2AGwAZIB/wHXAa4BjwH/AckBlwFuAf8BwwGPAWUB/wHIAZsBdQH/AbEBcAFJAf8BPAE1 + ATEBTgwAA3YBrgPEAf8DoQH/AyABKRAAAx8BKQOJAf8DqQH/A2YBrgwAA2UBfQPDAf4D3AH/A9QB/wPZ + Af8D2wH/A9YB/wPUAf8D2QH/A9IB/wPLAf8DyAH/A3kB/gNQAX0MAAOrAeoD+AH/A/4Z/wP7Af8D6gH/ + A5wB6hwAAh8BHgEmAcMBsgGGAf0B4gG+AaMB/wHfAbcBmgH/AdUBqAGGAf8B0AGhAXwB/wHLAZoBcgH/ + Ac4BogGAAf8BvwGLAWEB/wFuAVcBRwGVDAADVgF1A7oB/wO/Af8DigHdAxgBHwMEAQUDBAEFAxgBHwOA + AeUDqAH/A54B/wNOAXUMAANkAXsD3AH/A+0B/wPbAf8DugH0A70B/gPWAf8D1AH/A68B/gOmAfQDywH/ + A+cB/wO3Af8DVQF7DAADjwG/A+EB/wP+Gf8D+wH/A88B/wN0AaEgAAFlAVsBVAF2AeQBugGdAf8B5gHE + AasB/wHiAb4BpAH/Ad4BuQGcAf8B2QGyAZMB/wHRAaMBfgH/AdEBpgGFAf8BuwF+AVAB/wExAS0BKwE/ + CAADCQEMA5AB2wPEAf8DvgH/A6EB/wOWAf8DkwH/A5cB/wOuAf8DrgH/A3sB2wMHAQkQAAN/AZsDzAH9 + A7gB5wMUARkDsQHnA94B/wPdAf8DpAHnAxQBGQOfAecDpwH9A24BmxAAAyIBKgOcAdED0AH/A+gB/wPz + Af8D/QH/A/wB/wPtAf8D4AH/A8IB/wOLAcMDFQEbIAADBwEJAa8BkwGAAcYB4wG0AZMB/wHfAbEBjgH/ + AdoBqwGJAf8B2gGtAYwB/wHcAbUBmAH/AdcBrwGQAf8BzAGbAXMB/wGzAXcBRQH6DAADJgEwA5IB3gO8 + Af8DygH/A8wB/wPKAf8DwgH/A60B/wOCAd4DJQEwGAADIQEpAwsBDgMBAQIDtwHqA+UB/wPkAf8DoAHq + AwEBAgMLAQ4DIAEpGAADBQEHA0MBVQOEAa4DnQHWA7QB+wOyAfkDlQHNA34BqQM3AUYDAgEDKAADAwEE + ARkCGAEeATABLQEsATkBQQE8ATkBTgF8AWwBXwGUAdgBpwGCAf8B1wGsAYsB/wHTAacBhAH/AboBggFW + AfYQAAMJAQwDXgGBA38BugOGAcwDhAHMA3oBugNaAYEDCQEMKAADUAFjA5cBvwOVAb8DTgFjiAABMwEw + AS4BPgHQAZ4BegH7AcgBlgFuAfYBOgE2ATIBSIgAAT0BjAFEAf8BOQGHAUAB/wE2AYIBPAH/ATIBfQE4 + Af80AANxAZoDPAFOGAADNgFNAzQBSgMCAQMIAAE4AVgBcQG3ARoBVwGIAf8BGQFVAYYB/wEZAVQBhQH/ + ARgBUwGDAf8BGAFTAYIB/wEXAVIBgAH/ARcBUQF+Af8BFgFQAX0B/wEWAU8BfAH/ARUBTgF6Af8BFQFN + AXkB/wEVAU0BeAH/ARUBTAF4Af8BFAFMAXcB/wEzAVEBawHASAABQQGRAUgB/wGBAcUBhwH/AX0BwwGF + Af8BNgGDAT0B/zQAAzsBSwObAeQDWwF8EAADUwGAA2cBwAMxAUUMAAEjAVoBhwHwAX0BrQHgAf8BgQGv + AeQB/wF+AasB4gH/AX0BqAHgAf8BewGmAd8B/wF5AaIB3gH/AXgBoAHdAf8BdgGeAdwB/wF1AZsB2wH/ + AXQBmQHaAf8BcwGYAdoB/wFzAZgB2gH/AXMBmAHaAf8BcwGYAdoB/wEUAUwBdwH/BAABPAFNAV0BcAFC + AWoBjAGmATUBgQHFAeoBMQGHAdEB9wExAYcB0QH3ATEBhwHRAfcBMQGHAdEB9wExAYcB0QH3ATEBhwHR + AfcBMQGHAdEB9wExAYcB0QH3ATEBhgHRAfcBMwGFAcwB8QFBAV8BewGTDAABRQGXAU0B/wGFAccBiwH/ + AYIBxgGJAf8BOgGJAUEB/zgAA4oBvAOmAfcDbgGcCAADZwGjA30B8wNlAa4QAAEjAVsBhwHwAYABsgHj + Af8BUAGUAdwB/wFDAYoB2AH/AUEBhQHVAf8BPwGAAdQB/wE8AXsB0QH/AToBdgHPAf8BNwFyAc0B/wE1 + AW8BzAH/ATMBbAHKAf8BMQFoAckB/wEwAWYByAH/AS8BZAHIAf8BcwGYAdoB/wEVAUwBeAH/BAABPAGG + AcMB5gHOAeAB6AHwAacB2wHyAf0BngHbAfQB/wGWAdoB8wH/AY4B2AHzAf8BhgHXAfMB/wF+AdQB8gH/ + AXgB0wHyAf8BcQHSAfEB/wFrAdAB8QH/AWgBzwHxAf8BwQHpAfcB/gE4AYkBywHwDAABSQGcAVEB/wGJ + AcoBkAH/AYYByAGNAf8BPgGOAUYB/zgAAyYBMAOyAf0DqQH+A4UBxAOAAcQDjgH+A4QB9AMcASQQAAEk + AVwBiQHwAYMBtwHlAf8BVAGdAd8B/wFJAZIB2wH/AUYBjQHZAf8BQwGJAdcB/wFAAYMB1QH/AT4BfgHT + Af8BOwF6AdAB/wE5AXUBzgH/ATYBcQHNAf8BNAFtAcsB/wEyAWoBygH/ATEBZwHJAf8BdAGYAdoB/wEV + AU0BeQH/BAABNwGRAdMB9wHvAfoB/gH/AaEB6QH5Af8BkQHlAfgB/wGBAeEB9wH/AXEB3gH2Af8BYgHa + AfUB/wFTAdcB9AH/AUYB0wHzAf8BOAHQAfIB/wEtAc0B8QH/ASUBywHwAf8BygHyAfsB/wE3AZEB0wH3 + DAABTAGiAVUB/wGNAcsBlAH/AYoBywGRAf8BQgGUAUoB/zwAA3QBlgOxAfwBzwHrAv8BywHpAv8DlwH8 + A1wBhxQAASQBXQGKAfABhQG9AeYB/wFYAaQB4wH/AU4BmwHeAf8BSwGWAdwB/wFIAZEB2gH/AUYBjAHY + Af8BQgGHAdYB/wE/AYIB1AH/AT0BfAHRAf8BOwF5AdAB/wE3AXMBzgH/ATYBcAHMAf8BMwFtAcsB/wF1 + AZsB2wH/ARUBTgF6Af8EAAE5AZgB1AH4AfIB+gH9Af8BswHtAfoB/wGkAekB+QH/AZUB5gH4Af8BhQHi + AfcB/wF1Ad4B9gH/AWQB2wH1Af8BVgHXAfQB/wFIAdQB8wH/AToB0QHyAf8BLwHOAfEB/wHMAfIB+wH/ + ATcBlQHTAfcMAAFQAacBWgH/AZABzwGZAf8BjgHMAZYB/wFGAZkBTwH/KAABRAFQAWQBbwFAAUsBWwFm + AwwBDwgAAw4BEgO0AfMDsgH+A6kB/gOWAeUDCQEMDAABKQEvATYBPwEyATwBSwFVASUBXQGLAfABiAHB + AegB/wFdAawB5gH/AVMBowHjAf8BTwGeAeEB/wFMAZkB3gH/AUoBlAHcAf8BRwGPAdoB/wFDAYoB2AH/ + AUEBhQHVAf8BPwGAAdQB/wE8AXsB0QH/AToBdgHPAf8BNwFyAc0B/wF3AZ8B3QH/ARYBTwF7Af8EAAE4 + AZ4B1QH5AfYB/AH+Af8ByAHyAfwB/wG5Ae8B+wH/AawB7AH6Af8BnAHoAfkB/wGLAeMB9wH/AXsB4AH2 + Af8BawHcAfYB/wFcAdkB9QH/AU4B1gH0Af8BQwHTAfMB/wHQAfMB/AH/ATcBnAHTAfcMAAFUAawBXgH/ + AZQB0AGdAf8BkgHPAZoB/wFKAZ8BUwH/KAABZAGRAdUB2wF0Aa0C/wFYAZYB9AH2AwQBBgErAS8BNgE+ + BAADgAGjAbkB0AL/AboB3AL/A3UBogQAAR8BIQElASwDBAEFAS4BdwHfAeQBMwGIAv8BNAF0Ac8B1QEl + AV4BjAHwAYsBxgHqAf8BYQGzAekB/wFXAaoB5gH/AVQBpgHkAf8BUQGiAeIB/wFOAZwB4AH/AUwBmAHd + Af8BSQGSAdsB/wFGAY0B2QH/AUMBiQHXAf8BQAGDAdUB/wE+AX4B0wH/ATsBegHQAf8BegGjAd4B/wEW + AVABfQH/BAABOAGkAdUB+gH+A/8B+AH9Av8B9gH9Av8B9QH8Av8B8wH8Af4B/wHYAfYB/AH/AZQB5gH4 + Af8BhQHjAfcB/wF1Ad8B9gH/AWcB2wH1Af8BWwHYAfQB/wHXAfQB/AH/ATcBoQHTAfcMAAFXAbEBYgH/ + AZgB0wGhAf8BlgHRAZ4B/wFqAbYBcwH/AUwBZgFPAY8MAAFDAVUBRAF7AwIBAxAAAXABqAH4AfkBnQHE + Av8BZAGjAv8DBwEJAVYBmAL/AVIBjwHmAeoBLAEvATQBPAPBAfsDuAH6ATEBNgE/AUgBOwF8AdwB4QEs + AX4C/wMHAQkBIwF5Av8BaQGmAv8BJgF6AfEB8wEmAV8BjgHwAY0ByAHtAf8BZAG4AesB/wFaAbIB6QH/ + AVgBrgHnAf8BVgGpAeUB/wFTAaUB4wH/AVABoAHiAf8BTgGbAd4B/wFLAZYB3AH/AUgBkQHaAf8BRgGM + AdgB/wFCAYcB1gH/AT8BggHUAf8BfQGoAeAB/wEXAVEBfgH/BAABNgGoAdUB+gHoAfYB+wH/AZQB1AHv + Af8BiAHOAe4B/wFyAcEB6QH/AckB6QH2Af8B8gH8Af4B/wHzAfwB/gH/AfIB/AH+Af8B8AH8Af4B/wHv + AfsB/gH/Ae4B+wH+Af8B/gP/ATgBpwHTAfcMAAFaAYkBXwG3AYkBygGSAf8BkgHQAZsB/wGPAc0BlwH/ + AVMBlgFaAeIBTAFmAU8BjwgAAUoBgQFQAdIBSQFoAUwBnxAAAXkBrAH4AfkBowHGAv8BbwGqAv8DAgED + AWIBnQH0AfYBZwGjAv8BLAEwATYEPwFOAyIBKgErAS8BNgE/AUoBkwL/ATYBgAH0AfYDAgEDAScBegL/ + AWwBpQL/ASkBdwHtAfABJgFgAY8B8AGPAcwB7gH/AY8BzAH0Af8BhwHFAfIB/wGDAcMB8QH/AYABvwHv + Af8BfAG8Ae4B/wF5AbgB6wH/AXQBtAHqAf8BcAGwAegB/wFtAasB5gH/AWgBpwHlAf8BZQGjAeMB/wFh + AZ4B4QH/AYABrQHjAf8BFwFSAYEB/wQAAToBowHPAfIB8QH6Af0B/wGUAd4B9QH/AZMB3AH0Af8BgQHV + AfIB/wFpAcoB7QH/AWsBywHqAf8BhQHTAe8B/wGAAdIB7wH/AXkB0AHvAf8BdQHPAe4B/wFxAc8B7gH/ + AekB9wH7Af8BOAGoAc8B8wwAAUYBVwFIAXABeAHEAYQB/wGdAdUBpgH/AZsB1AGjAf8BkQHOAZkB/wFs + AbgBdAH/AUwBoQFVAf8BSQGcAVEB/wFjAa4BawH/AWABqgFnAf8BRwFiAUsBkwwAAXsBngHSAdgBpAHG + Av8BeQGvAv8DBwEJAV8BeQGhAasBgQGzAv8BWAF0AaABqgEsATABNgE/ASwBMAE2AT8BTwFuAaABqgFl + AaMC/wFKAW0BoQGrAwcBCQEyAYIC/wFoAaQC/wE4AXIBzwHVASYBYQGQAfABdgGxAdkB/wEoAW0BpAH/ + ARYBYAGbAf8BFgFdAZkB/wEWAVsBlgH/ARUBWgGSAf8BFAFYAY4B/wEUAVUBiwH/ARMBUwGHAf8BEwFQ + AYIB/wERAU0BfQH/AREBSwF5Af8BOAFnAYwB/wFmAY4BsAH/ARgBUwGCAf8EAAE6AaYBzAHwAfcB/AH+ + Af8BjgHkAfgB/wGRAd4B9QH/AZ8B4AH1Af8BrAHhAfYB/wHvAfsB/gH/AfQB/QH+Af8B8wH8Af4B/wHx + AfwB/gH/Ae8B+wH+Af8B7gH7Af4B/wHzAfYB+AH5AUMBlgG0AdQMAAEWARcBFgEdAVoBhgFfAbABiAHL + AZEB/wGeAdYBpwH/AZQB0QGeAf8BmQHUAaIB/wGXAdIBoAH/AZQB0AGdAf8BkwHPAZsB/wGPAc0BlwH/ + AWABqwFoAf8BRwFeAUkBiggAAWEBbwGFAZABngHEAv8BkAG+Av8BMAE0ATkBQgEVAhYBGwFtAZkB2AHe + AYMBtQL/AW8BqAL/AWkBpgL/AXABqAL/AVQBigHYAd4BFAEVARYBGwEsATEBOQFCAUwBkwL/AVsBnAL/ + AUIBXAGBAY0BMAFhAYkB2wFAAXsBqgH/AWMBlgG+Af8BKgFuAaYB/wEfAWcBoQH/AR8BZAGfAf8BHwFj + AZwB/wEeAWEBmQH/AR4BXwGVAf8BHQFeAZEB/wEdAVwBjwH/ARwBWAGKAf8BPgFvAZgB/wFaAYQBpgH/ + ATcBagGUAf8BOAFUAWwBrwQAATkBrwHUAfgB/QL+Af8B/gP/Av4C/wH9Af4C/wH+A/8B6gH3AfsB/wFq + AcIB3gH5AWoBwgHcAfgBagHCAdwB+AFqAcIB3AH4AXcBxwHeAfcBbwGzAcgB4QE1AUMBRwFWEAABKQEu + ASoBOQFaAYYBYAGwAXoBxgGFAf8BjAHNAZUB/wGXAdIBoAH/AZsB1AGkAf8BmQHTAaIB/wGWAdEBngH/ + AZIBzwGaAf8BZAGvAW0B/wFHAVwBSQGECAABIwEkASYBLQGQAb0B+wH8AaYByAL/AYUBtQH7AfwBGAEZ + ARoBHwIJAQoBDAFUAWMBeQGEAWgBiwG+AcYBZAGHAb4BxgFPAWABeQGEAgkBCgEMARcBGAEaAR8BTAGR + AfsB/AFxAaoC/wE/AYgB+wH8AR4BIAEjASoBDQIOARIBKAFhAZEB7gE+AXkBqAH/AV8BkwG8Af8BYAGU + AbwB/wFgAZMBvAH/AV8BkgG7Af8BXwGRAbkB/wFfAZABtwH/AV8BjwG1Af8BXgGOAbMB/wFeAYwBsAH/ + AVkBiAGrAf8BNwFsAZgB/wE7AUwBWAGDCAABQQGXAbAB0AFdAb4B3AH6AV8BvwHdAfoBXwG/Ad0B+gFf + Ab8B3QH6AV4BvwHdAfoBRQGhAb0B3QIRARIBFgELAgwBDwELAgwBDwELAgwBDwELAgwBDwELAgwBDwMD + AQQUAAEWARcBFgEdAUYBWAFIAXABWgGJAWEBtwFcAagBZAHqAVcBsQFhAf8BVAGsAV4B/wFvAboBdwH/ + AWwBtgF1Af8BSwFmAU4BkBAAAWQBcAGFAZABpAHJAv8BpAHIAv8BiQG3AfsB/AExATQBOQFCAwcBCQgA + AwcBCQEvATMBOQFCAV0BnAH7AfwBdgGsAv8BaAGjAv8BSgFgAYEBjQgAAwkBDAE9AVkBbgGkASYBYgGR + AfEBJQFgAZIB8wElAWABkQHzASUBXwGQAfMBJQFfAY4B8wElAV4BjQHzASQBXQGMAfMBJAFdAYsB8wEj + AVwBiQHzASgBXAGFAecBOgFKAVUBfHAAAVcBkwFeAdIBUQFxAVQBnBQAAwQBBgF6AY4BrgG3AaQByAL/ + AawBzgL/AZcBwAL/AYgBtgL/AYUBtwL/AXwBsAL/AXYBrgL/AX0BsQL/AY4BvgL/AXkBrwL/AVkBegGu + AbcDBAEGrAABSAFcAUsBeAMCAQMcAAFTAVoBZwFyAZMBtwH0AfYBqAHJAv8BsQHRAv8BswHRAv8BsAHQ + Av8BowHFAv8BlQHAAv8BcwGnAfQB9gFKAVYBZwFy3AACHwEhAScBYwFvAYEBjQGCAZsBxAHMAZMBvgH7 + AfwBjgG6AfsB/AF6AZgBxAHMAV0BawGBAY0BHgEfASEBJxAAAUIBTQE+BwABPgMAASgDAAFAAwABYAMA + AQEBAAEBBgABAxYAA/+BAAH+AQcC/wH8AT8BhwH/AfwBBwHAAQMB8AEfAQMB/wHwAQcBgAEBAYABAwEB + Af8B4AEHAYABAQEAAQEBAAH/AcABBwGAAQEDAAF/AYABBwGAAQECAAGAAT8BAAEDAYABAQIAAcABPwEA + AQMBwAEDAgAB4AEfAQABAwHgAQcBAAEBAfABAQEAAQMB8AEPAQABAwH4AQABwAEDAfABBwEAAQ8B/gEA + AfABAwHwAQcBAAEPAf8BAAH4AQMB8AEPAQABDwH/AQgB/gEBAfABDwEAAQ8B/wEHAf8BAQH4AR8BAAEP + Af8BBwH/AfEC/wGAAR8B/wGHAf4BAwL/AfABAAL/AfwBAAL/AfABAAL/AfACAAEBAfABAAL/AYACAAEB + AfABAAL/AwABAQHAAQAC/wMAAQEBwAEAAYABAQMAAQEBwAEAAYABAQMAAQEBwAEAAYABAQMAAQEBAAED + AYABAQEAAQEBAAEBAQABAwGAAQEBAAEBAQABAQEAAQMBgAEBAQABAQEAAQEBAAEDAcABAwHwAQEBAAEB + AQABDwL/AfABAwEAAQEBAAEPAv8B8AEDAQABAQEAAQ8G/wEAAQ8C/wEPA/8BgAEBAYcB/wEHA/8BgAEB + AQMB/wEAAT8C/wGAAgEB/wEAAR8C/wGAAQEBAAH/AYABHwIAAcABAwEAAX8BwAEPAgAB4AEHAYABPwHA + AQMCAAHwAQ8BwAE/AcABAQIAAfwBPwHgAR8BwAEBAgAB/AE/AfABAQHAAQECAAHwAQ8B+AEAAeABAQIA + AeABBwH+AQAB+AEBAgABwAEDAf8BAAH8AQABgAEBAYABAQH/AQgB/AEAAYABAQGAAQEB/wEHAf4BAAHA + AQMBgAEBAf8BBwH/AfAC/wGAAQEB/wGHAYABAQH8AT8B/AE/AQ8B/wGAAQEB4AEHAeACBwH/AYABAQHA + AQMBwAEDAQABPwGAAQEBgAEBAcABAwEAAR8BgAEBAYABAQHAAQMBgAEfAYABAQHAAQMBwAEDAcABDwGA + AQECAAHAAQMBwAEDAYACAQGAAcABAwHAAQEBgAIBAYABwAEDAcABAQGAAQECAAHAAQMBwAEBAsMBwAED + AcABAwHgAQECwwGAAQEBwAEDAfgBAQHAAQMBgAEBAcABAwH8AQABwAEDAcABAwHAAQMB/AEAAeABBwHg + AQcB4AEHAf4BAAHwAQ8B/AE/A/8B8AT/AcMB/wHnAeMCAAL/AcMB/wHjAccCAAGAAQEBwwH/AfEBjwIA + AYABAQHDAf8B8AEPAgABgAEBAcMB/wH4AR8CAAGAAQEBwwH/ARgBHAIAAYABAQHDAf8BBAEgAgABgAEB + AcEBzwQAAYABAQHAAc8EAAGAAQEBwAEHBAABgAEBAcABAwQAAYABAQHgAQMDAAEBAYABAQHwAQcCgQGA + AQMD/wHPAYABAQX/Ac8B4AEHBv8B8AEPCw== + + + + + + AAABAA8AMDAQAAEABABoBgAA9gAAACAgEAABAAQA6AIAAF4HAAAQEBAAAQAEACgBAABGCgAAAAAAAAEA + CABqDQAAbgsAADAwAAABAAgAqA4AANgYAAAgIAAAAQAIAKgIAACAJwAAEBAAAAEACABoBQAAKDAAAAAA + AAABABgAOQ0AAJA1AAAwMAAAAQAYAKgcAADJQgAAICAAAAEAGACoDAAAcV8AABAQAAABABgAaAMAABls + AAAAAAAAAQAgAHANAACBbwAAMDAAAAEAIACoJQAA8XwAACAgAAABACAAqBAAAJmiAAAQEAAAAQAgAGgE + AABBswAAKAAAADAAAABgAAAAAQAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAIAAAACA + gACAAAAAgACAAICAAACAgIAAAAD/AAD/AAAA//8A/wAAAP8A/wD//wAAwMDAAP///wDwAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFRGVGVlZGVkdGVlAAAA + AAAAAAAAAAAAAFZGtkZLa2Rka0a0AAAAAAAAAAAAAAAAAGtka2tka2trZkZHAAAAAAAAAAAAAAAAAGRr + a2tmtmtra2tkAAAAAAAAAAAAAAAAAFZrZma2a2a2a2tnAAAAAAAAAAAAAAAAAEa2a2tra2tra2ZkAAAA + AAAAAAAAAAAAAGa2trZra2a2a2tlAAAAAAAAAAAAAAAAAHa2bbZrZttmtmtmAAAAAAABODE4ExgxAFa2 + tra2tra2tmtlAAAAAAABgxg4E4OBAEZrZrZr1rZr29tmAAAAAAADgTETgxMTAHvWvb22tmvba2tlAAAA + AAADE4ODgxg4AGRr272729tr29vUAAAAAAAIE4MTgTgxAF2729vb22bb29tnAAAAAAABODg4ODgxAEbb + 29vb29u2vb22AAAAAAADg4ODg4ODAEZmZmZmZm1mZmZlAAAAAAABODg4ODg4AHR2VlZWR1ZHRlZWAAAA + AAAIODg4ODg4AAAAAAAAAAAAAAAAAAAAAAADg4ODg4ODM4ODiDiDg4ODg4OIOIODg44BODiDioOBiuiu + p6euinqK6K6np66o6j4BioODg4ODOurqjq6nrq6urqeup3qK6h4Dg4OKg4ODjoruqK6o6o6o6uqOqurq + 6o4Bg4ODiDg4Oq6orqeup66np6iuqOqOqD4Dg4qIOKg4h6eup66Kenp6eurqeup66j4Biog4qDiDPqen + p66urq6np66K6np6eo4DiKg4OKiBiq6nrqiuqKeup6p6enp66j4Bg4OIODgzOup66nrqeup6eurqenrq + eo4BMRMTgTGBh66orqenp6rorop66np66j4AAAAAAAAAOup66np66nrqrqrqenrqeo4AAAAAAAAAinp6 + eup6enrqeurqeup66j4AAAAAAAAAPqrq6qeq6up6euqK6q6uqh4AAAAAAAAAiup6eup6eqeup66urqiu + 6j4AAAAAAAAAOup66np66n6qeqeqenrqqo4AAAAAAAAAGq6q6q6q6qrq6urqrqrq6j4AAAAAAAAAPq6u + qurq6urq6uqurq6q6o4AAAAAAAAAiq6q6uqq6q6qququqq6q6j4AAAAAAAAAOuqurqrq6uqurq6urq6u + ro4AAAAAAAAAiurqqurq6q6urqrqrqquqj4AAAAAAAAAPq6q6urqququqq6q6q6uro4AAAAAAAAAOqrq + 6qqurq6q6urqrq6q6j4AAAAAAAAAOurqqurqrqququqq6uquqj4AAAAAAAAAiuqurqrqrq6q6q6uqq6q + 6o4AAAAAAAAAOuququrqrqrq6q6q6uquqn4AAAAAAAAAeq6uququrqrqrq6q6q6uqo4AAAAAAAAAOq6q + rqquqq6qrqquqq6qrj4AAAAAAAAAgzODM4MzgzODM4MzgzODMT8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AA9///////4AAP///////wAA//8AAAP/AAD//wAAA/8AAP//AAAD/wAA//8AAAP/AAD//wAAA/8AAP// + AAAD/wAA//8AAAP/AAD//wAAA/8AAIADAAAD/wAAgAMAAAP/AACAAwAAA/8AAIADAAAD/wAAgAMAAAP/ + AACAAwAAA/8AAIADAAAD/wAAgAMAAAP/AACAA/////8AAIAAAAAAAAAAgAAAAAAAAACAAAAAAAAAAIAA + AAAAAAAAgAAAAAAAAACAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAACAAAAAAAAAAIAAAAAAAAAA//wAAAAA + AAD//AAAAAAAAP/8AAAAAAAA//wAAAAAAAD//AAAAAAAAP/8AAAAAAAA//wAAAAAAAD//AAAAAAAAP/8 + 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 + Hx8fHx8fHx8fGwAAARQXFxcXFxcXFxcXFxcXFxcXFxcXAQAAAAAAAAAAAAAAGyAhISEhISEhISEgGwAA + ARYZGRkZGRkZGRkZGRkZGRkZGRkZAQAAAAAAAAAAAAAAGyEhISEhISEhISEhGwAAARgaGhoaGhoaGhoa + GhoaGhoaGhoaAQAAAAAAAAAAAAAAGyIiIyIjIyIjIyMiGwAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAA + AAAAAAAAAAAAGyUlJSUlJSUlJSUlGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGyYm + JiYmJiYmJiYmGyQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJEIAGyYnJygnKCcoJycnHCQv + Ly8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vJEEAGygpKSkpKSkpKSkpHCQwLzAwMDAwMDAwMDAw + MDAwMDAwMDAwMDAwMDAwMDAvJEEAGykrKiorKisqKyoqHCQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw + MDAwMDAwJEEAGyosLCwsLCwsLCwsGyQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwJEEAGywt + LS0tLS0tLS0tHCQxMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExJEEAGy0uLi4uLi4uLi4uHCQy + MjIxMjEyMTIxMjEyMTIxMjEyMTIxMjEyMTIxMjEyJEEAGy4uLi4uLi4uLi4uGyQyMjIyMjIyMjIyMjIy + MjIyMjIyMjIyMjIyMjIyMjIyJEEAGyorKysrKysrKysrGyQzMzQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0 + NDQ0NDQzJEEAGxsbGxsbGxsbGxsbHCQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDU0JEEAAAAA + AAAAAAAAAAAAACQ1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1JEEAAAAAAAAAAAAAAAAAACQ1 + NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1JEEAAAAAAAAAAAAAAAAAACQ2Njc3Nzc3Nzc3Nzc3 + Nzc3Nzc3Nzc3Nzc3Nzc3NzY2JEEAAAAAAAAAAAAAAAAAACQ3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3 + Nzc3Nzg3JEEAAAAAAAAAAAAAAAAAACQ4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4JEEAAAAA + AAAAAAAAAAAAACQ4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4JEEAAAAAAAAAAAAAAAAAACQ5 + OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5JEEAAAAAAAAAAAAAAAAAACQ6Ojo6Ojo6Ojo6Ojo6 + Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6JEEAAAAAAAAAAAAAAAAAACQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7 + Ozs7Ozs7JEEAAAAAAAAAAAAAAAAAACQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7JEEAAAAA + AAAAAAAAAAAAACQ8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8JEEAAAAAAAAAAAAAAAAAACQ9 + PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09JEEAAAAAAAAAAAAAAAAAACQ9PT09PT09PT09PT09 + PT09PT09PT09PT09PT09PT09JEEAAAAAAAAAAAAAAAAAACQ+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+ + Pj4+Pj4+JEEAAAAAAAAAAAAAAAAAACQ/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/JEEAAAAA + AAAAAAAAAAAAACQ/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/JEEAAAAAAAAAAAAAAAAAACRA + QEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAJEEAAAAAAAAAAAAAAAAAACQkJCQkJCQkJCQkJCQk + JCQkJCQkJCQkJCQkJCQkJCQkJEMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAER///////4O7v///////w7u//8AAAP/Du7//wAAA/8O7v//AAAD/w7u//8AAAP/Du7//wAA + A/8O7v//AAAD/w7u//8AAAP/Du7//wAAA/8O7oADAAAD/w7ugAMAAAP/Du6AAwAAA/8O7oADAAAD/w7u + gAMAAAP/Du6AAwAAA/8O7oADAAAD/w7ugAMAAAP/Du6AA/////8O7oAAAAAAAA7ugAAAAAAADu6AAAAA + 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 + HBwcHBwcHBwcHBwcHBwcHBwcEBktCxYWFhYWFgsQHR0dHR0dHR0dHR0dHR0dHR0dHR0QGS0LCwsLCwsL + CxAeHh4eHh4eHh4eHh4eHh4eHh4eHhAZAAAAAAAAAAAAEB8fHx8fHx8fHx8fHx8fHx8fHx8fEBkAAAAA + AAAAAAAQICAgICAgICAgICAgICAgICAgICAQGQAAAAAAAAAAABAhISEhISEhISEhISEhISEhISEhIRAZ + AAAAAAAAAAAAECIiIiIiIiIiIiIiIiIiIiIiIiIiEBkAAAAAAAAAAAAQIyMjIyMjIyMjIyMjIyMjIyMj + IyMQGQAAAAAAAAAAABAkJCQkJCQkJCQkJCQkJCQkJCQkJBAZAAAAAAAAAAAAECUkJSQlJCQkJCQkJCQk + JCQkJCQkEBkAAAAAAAAAAAAQJSUlJSUlJSUlJSUlJSUlJSUlJSUQGQAAAAAAAAAAABAmJiYmJiYmJiYm + JiYmJiYmJiYmJhAZAAAAAAAAAAAAECcnJycnJycnJycnJycnJycnJycnEBkAAAAAAAAAAAAQKCgoKCgo + KCgoKCgoKCgoKCgoKCgQGQAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBArAAAAAAAAAAAALy4u + Li4uLi4uLi4uLi4uLi4uLi4uLjD//////+AAf//gAD//4AA//+AAP//gAD//4AA/AGAAPwAgAD8AIAA/ + ACAAPwAgAD8AP///AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA + /4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAACgAAAAQAAAAIAAAAAEACAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAoj8AAK5OAAC6XQAAr2MPAMZtAACqbEwAsHNMALZ7TACwflQAvINMALKDbwC2h28A + uYxvAL2RbwC2jnQAADerAAA8tgAQUL8AQGi9AABCwgAAR80AEFPEAABM2AAlW8AAQGrDAD6w3wA+tuEA + PrzkAHiGwgB4iMUAcIzKAHiJyQB4jM0AZI3QAHCT2QBftdwAX7neAGCt2ABgstoAR7zmAF+/4QA9wucA + PcjqADzO7QA81O8AO9ryAEfD6QBGyuwAXsLhAEbR7wBG2PIARd/1AEXl+ABE7PwAu7zZALu93ACBuuAA + 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 + ADAAAABgAAAAAQAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7i4gAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7g + 4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAGYzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2Yz + M2YzM2YzM2YzM2YzM2YzM2YzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM5o5A546AJ46AJ46AJ46AJ46AJ46 + AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AGYzMwAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AGYzM54+A6I/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/ + AKI/AGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM6JCA6ZDAKZDAKZDAKZDAKZDAKZDAKZDAKZDAKZDAKZD + AKZDAKZDAKZDAKZDAKZDAKZDAKZDAKZDAKZDAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM6ZHA6pJAKpJ + AKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAGYzMwAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAGYzM6lMA65OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5O + AK5OAK5OAK5OAK5OAK5OAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM61RA7JTALJTALJTALJTALJTALJT + ALJTALJTALJTALJTALJTALJTALJTALJTALJTALJTALJTALJTALJTAGYzMwAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AGYzM7FWA7ZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZ + ALZZAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQAzoQAzoQAzoQAzoQAzoQAz + oQAzoQAzoQAzoQAzoQAzoQAzoQAAAAAAAGYzM7RaA7pdALpdALpdALpdALpdALpdALpdALpdALpdALpd + ALpdALpdALpdALpdALpdALpdALpdALpdALpdAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAzoQA0owA0pAA0pAA0pAA0pAA0pAA0pAA0pAA0pAA0pAA0pAAzoQAAAAAAAGYzM7hfA75iAL5i + AL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAGYzMwAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQA2pwA2qAA2qAA2qAA2qAA2qAA2qAA2qAA2qAA2 + qAA2qAAzoQAAAAAAAGYzM7xkA8JoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJo + AMJoAMJoAMJoAMJoAMJoAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQA3qwA3 + qwA3qwA3qwA3qwA3qwA3qwA3qwA3qwA3qwA3qwAzoQAAAAAAAGYzM8BpA8ZtAMZtAMZtAMZtAMZtAMZt + AMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAGYzMwAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAzoQA5rgA5rwA5rwA5rwA5rwA5rwA5rwA5rwA5rwA5rwA5rwAzoQAAAAAA + AGYzM8NuA8pyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpy + AMpyAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQA6sQA7swA7swA7swA7swA7 + swA7swA7swA7swA7swA7swAzoQAAAAAAAGYzM8dzA853AM53AM53AM53AM53AM53AM53AM53AM53AM53 + AM53AM53AM53AM53AM53AM53AM53AM53AM53AGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAzoQA8tQA8tgA8tgA8tgA8tgA8tgA8tgA8tgA8tgA8tgA8tgAzoQAAAAAAAGYzM8t3A9J8ANJ8 + ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8AGYzMwAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQA9uAA+ugA+ugA+ugA+ugA+ugA+ugA+ugA+ugA+ + ugA+ugAzoQAAAAAAAGYzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2Yz + M2YzM2YzM2YzM2YzM2YzM2YzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQA/vABA + vgBAvgBAvgBAvgBAvgBAvgBAvgBAvgBAvgBAvgAzoQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAzoQBBvwBBwQBBwQBBwQBBwQBBwQBBwQBBwQBBwQBBwQBBwQAzoQBbrwBb + rwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBb + rwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbr7rH3wAAAAAzoQBCwwBDxQBDxQBDxQBDxQBD + xQBDxQBDxQBDxQBDxQBDxQAzoQBbr0i45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei4 + 5Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45ABbr6y8 + 2QAAAAAzoQBExgBFyQBFyQBFyQBFyQBFyQBFyQBFyQBFyQBFyQBFyQAzoQBbr0i65Ui65Ui65Ui65Ui6 + 5Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui6 + 5Ui65Ui65Ui65Ui65Ui65Ui65QBbr6y82QAAAAAzoQBFygBHzABHzABHzABHzABHzABHzABHzABHzABH + zABHzAAzoQBbr0i85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki8 + 5ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85gBbr6y82QAAAAAzoQBHzQBI + 0ABI0ABI0ABI0ABI0ABI0ABI0ABI0ABI0ABI0AAzoQBbr0i/50i/50i/50i/50i/50i/50i/50i/50i/ + 50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/ + 50i/50i/5wBbr6y82QAAAAAzoQBI0QBK1ABK1ABK1ABK1ABK1ABK1ABK1ABK1ABK1ABK1AAzoQBbr0fB + 6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB + 6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6ABbr6y82QAAAAAzoQBK1ABM2ABM2ABM2ABM2ABM + 2ABM2ABM2ABM2ABM2ABM2AAzoQBbr0fD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD + 6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6QBbr6y8 + 2QAAAAAzoQBM2ABN2wBN2wBN2wBN2wBN2wBN2wBN2wBN2wBN2wBN2wAzoQBbr0fF6kfF6kfF6kfF6kfF + 6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF + 6kfF6kfF6kfF6kfF6kfF6kfF6gBbr6y82QAAAAAzoQBGzABIzwBIzwBIzwBIzwBIzwBIzwBIzwBIzwBI + zwBIzwAzoQBbr0fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI + 60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI6wBbr6y82QAAAAAzoQAzoQAz + oQAzoQAzoQAzoQAzoQAzoQAzoQAzoQAzoQAzoQAzoQBbr0fK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK + 7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK + 7EfK7EfK7ABbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0fM + 7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM + 7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7QBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAABbr0bO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO + 7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7gBbr6y8 + 2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0bR70bR70bR70bR70bR + 70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR + 70bR70bR70bR70bR70bR70bR7wBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAABbr0bT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT + 8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8ABbr6y82QAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0bV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV + 8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV + 8kbV8kbV8gBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0bX + 80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX + 80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX8wBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAABbr0ba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba + 9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9ABbr6y8 + 2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Xc9UXc9UXc9UXc9UXc + 9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc + 9UXc9UXc9UXc9UXc9UXc9UXc9QBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAABbr0Xe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe + 9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9gBbr6y82QAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg + 90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg + 90Xg90Xg9wBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Xj + +EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj + +EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+ABbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAABbr0Xl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl + +UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+QBbr6y8 + 2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Xn+kXn+kXn+kXn+kXn + +kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn + +kXn+kXn+kXn+kXn+kXn+kXn+gBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAABbr0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp + +0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+wBbr6y82QAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Ts/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs + /ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs + /ETs/ETs/ABbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Tu + /UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu + /UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/QBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAABbr0Tw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw + /kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/gBbr669 + 2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbrwBbrwBbrwBbrwBbrwBb + rwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBb + rwBbrwBbrwBbrwBbrwBbrwBbrwBbr+XZ4gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7i4n///////g7u//// + ////Du7//wAAA/8O7v//AAAD/w7u//8AAAP/Du7//wAAA/8O7v//AAAD/w7u//8AAAP/Du7//wAAA/8O + 7v//AAAD/w7ugAMAAAP/Du6AAwAAA/8O7oADAAAD/w7ugAMAAAP/Du6AAwAAA/8O7oADAAAD/w7ugAMA + AAP/Du6AAwAAA/8O7oAD/////w7ugAAAAAAADu6AAAAAAAAO7oAAAAAAAA7ugAAAAAAADu6AAAAAAAAO + 7oAAAAAAAA7ugAAAAAAADu6AAAAAAAAO7oAAAAAAAA7ugAAAAAAADu7//AAAAAAO7v/8AAAAAA7u//wA + AAAADu7//AAAAAAO7v/8AAAAAA7u//wAAAAADu7//AAAAAAO7v/8AAAAAA7u//wAAAAADu7//AAAAAAO + 7v/8AAAAAA7u//wAAAAADu7//AAAAAAO7v/8AAAAAA7u//wAAAAADu7//AAAAAAO7v/8AAAAAA7u//wA + AAAADu7///////4O7igAAAAgAAAAQAAAAAEAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzMAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmMzOfOwCfOwCfOwCfOwCfOwCfOwCf + OwCfOwCfOwCfOwCfOwCfOwBmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABmMzOkQQCkQQCkQQCkQQCkQQCkQQCkQQCkQQCkQQCkQQCkQQCkQQBmMzOxmJgA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmMzOrSgCrSgCr + SgCrSgCrSgCrSgCrSgCrSgCrSgCrSgCrSgCrSgBmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmMzOwUQCwUQCwUQCwUQCwUQCwUQCwUQCwUQCwUQCwUQCw + UQCwUQBmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABmMzO3WgC3WgC3WgC3WgC3WgC3WgC3WgC3WgC3WgC3WgC3WgC3WgBmMzOxmJgAAAAAAAAAAAAAAAAA + AAAAAADHu9QAM6EAM6EAM6EAM6EAM6EAM6EAM6EAM6EAAAAAAABmMzO8YAC8YAC8YAC8YAC8YAC8YAC8 + YAC8YAC8YAC8YAC8YAC8YABmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAADHu9QAM6EANqkANqkANqkANqkA + NqkANqkAM6F/mM8AAABmMzPDaQDDaQDDaQDDaQDDaQDDaQDDaQDDaQDDaQDDaQDDaQDDaQBmMzOxmJgA + AAAAAAAAAAAAAAAAAAAAAADHu9QAM6EAOK0AOK0AOK0AOK0AOK0AOK0AM6F/mM8AAABmMzPIcADIcADI + cADIcADIcADIcADIcADIcADIcADIcADIcADIcABmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAADHu9QAM6EA + O7QAO7QAO7QAO7QAO7QAO7QAM6F/mM8AAABmMzPPeADPeADPeADPeADPeADPeADPeADPeADPeADPeADP + eADPeABmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAADHu9QAM6EAPbgAPbgAPbgAPbgAPbgAPbgAM6F/mM8A + AABmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzOxmJgAAAAAAAAAAAAAAAAA + AAAAAADHu9QAM6EAQL8AQL8AQL8AQL8AQL8AQL8AM6FVfMEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADHu9QAM6EAQsMAQsMAQsMAQsMA + QsMAQsMAM6EAW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68A + W68AW68AW68AW68AW6+BpM7Hu9QAM6EARcoARcoARcoARcoARcoARcoAM6EAW69IuuVIuuVIuuVIuuVI + uuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuUAW698oMzHu9QAM6EA + R84AR84AR84AR84AR84AR84AM6EAW69IvuZIvuZIvuZIvuZIvuZIvuZIvuZIvuZIvuZIvuZIvuZIvuZI + vuZIvuZIvuZIvuZIvuZIvuZIvuZIvuYAW698oMzHu9QAM6EAStUAStUAStUAStUAStUAStUAM6EAW69H + wehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwegA + 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 + SH08XNsEAFaMAdioj++z4Eh9MkLbBABWjAHYsLfvs+BIzR6pbQIAK8YAbEAAYqPmEACUwBiAFr18nwVH + au4obRMAWDEGYP2evs+CI/XpaG0TAFgxBmC9Hr7PgiM1b4y2CQCsGAOwLgGIjfqMAKAExgCss6fvs+BI + fT5W2wQAVowBaL6H77PgSH0xTtsEAFaMAWjW3fdZcKS+HK9tAgArxgA07e77LDhS88drmwDAijEAa3fz + fRYcqQVV2iYAsGIMQJOuvs+CI/XVBG0TAFgxBmCtLr7PgiP19URtEwBYIQDlgQCgJMYArNnZ91lwpL6Z + pG0CACvGAKzRyfdZcKQWTtY2AYAVYwBW7+j7LDhSi6q1TQBgxRiA1QhAbNRiAoASGAPQuIPvs+BILZmi + bQIAK8YArNre91lwpL6t0TYBgBVjAFZp5/ssOFLfTdU2AYAVYwBWJgCxUd8TAJTAGIBGbX2fBUfqh2na + JgCwYgzASm18nwVHaul0bRMAWDEFAPEjALBCAMoTAYAVAlCeCACsEIDyRAAARI8AAAkjAEDCCACQMAIA + JIwAAAkjAEDCCACQMFMAAKRlbv1PNdVF4Jm637at+5rUfY3qvrL4iScADfsZgOX03tj+IOMAAAAASUVO + RK5CYIIoAAAAMAAAAGAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/svLi/7Ly2D+y8tb/svL + W/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svL + W/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svL + W/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8uU/svL + ev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AGUyMhxlMjIgZTIyIGUyMiBlMjIgZTIyIGUyMiBlMjIgZTIyIGUyMiBlMjIgZTIyIGUyMiBlMjIgZTIy + IGUyMiBlMjIgZTIyIGUyMiBlMjIgZTIyIGUyMiBlMjIIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAGYzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz + /2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM/+aOQP/njoA/546AP+eOgD/njoA/546AP+eOgD/njoA + /546AP+eOgD/njoA/546AP+eOgD/njoA/546AP+eOgD/njoA/546AP+eOgD/njoA/2YzM/9lMjJAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM/+ePgP/oj8A/6I/AP+iPwD/oj8A + /6I/AP+iPwD/oj8A/6I/AP+iPwD/oj8A/6I/AP+iPwD/oj8A/6I/AP+iPwD/oj8A/6I/AP+iPwD/oj8A + /2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLev7LywgAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM/+iQgP/pkMA + /6ZDAP+mQwD/pkMA/6ZDAP+mQwD/pkMA/6ZDAP+mQwD/pkMA/6ZDAP+mQwD/pkMA/6ZDAP+mQwD/pkMA + /6ZDAP+mQwD/pkMA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svL + ev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AGYzM/+mRwP/qkkA/6pJAP+qSQD/qkkA/6pJAP+qSQD/qkkA/6pJAP+qSQD/qkkA/6pJAP+qSQD/qkkA + /6pJAP+qSQD/qkkA/6pJAP+qSQD/qkkA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAGYzM/+pTAP/rk4A/65OAP+uTgD/rk4A/65OAP+uTgD/rk4A/65OAP+uTgD/rk4A + /65OAP+uTgD/rk4A/65OAP+uTgD/rk4A/65OAP+uTgD/rk4A/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM/+tUQP/slMA/7JTAP+yUwD/slMA/7JTAP+yUwD/slMA + /7JTAP+yUwD/slMA/7JTAP+yUwD/slMA/7JTAP+yUwD/slMA/7JTAP+yUwD/slMA/2YzM/9lMjJAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM/+xVgP/tlkA/7ZZAP+2WQD/tlkA + /7ZZAP+2WQD/tlkA/7ZZAP+2WQD/tlkA/7ZZAP+2WQD/tlkA/7ZZAP+2WQD/tlkA/7ZZAP+2WQD/tlkA + /2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AM6H/ADOh + /wAzof8AM6H/ADOh/wAzof8AM6H/ADOh/wAzof8AM6H/ADOh/wAzof8AMqAsAAAAAGYzM/+0WgP/ul0A + /7pdAP+6XQD/ul0A/7pdAP+6XQD/ul0A/7pdAP+6XQD/ul0A/7pdAP+6XQD/ul0A/7pdAP+6XQD/ul0A + /7pdAP+6XQD/ul0A/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svL + egAzof8ANKP/ADSk/wA0pP8ANKT/ADSk/wA0pP8ANKT/ADSk/wA0pP8ANKT/ADSk/wAzof8AMqBAAAAA + AGYzM/+4XwP/vmIA/75iAP++YgD/vmIA/75iAP++YgD/vmIA/75iAP++YgD/vmIA/75iAP++YgD/vmIA + /75iAP++YgD/vmIA/75iAP++YgD/vmIA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAD+y8tb/svLegAzof8ANqf/ADao/wA2qP8ANqj/ADao/wA2qP8ANqj/ADao/wA2qP8ANqj/ADao + /wAzof8AMqBAAAAAAGYzM/+8ZAP/wmgA/8JoAP/CaAD/wmgA/8JoAP/CaAD/wmgA/8JoAP/CaAD/wmgA + /8JoAP/CaAD/wmgA/8JoAP/CaAD/wmgA/8JoAP/CaAD/wmgA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AN6v/ADer/wA3q/8AN6v/ADer/wA3q/8AN6v/ADer + /wA3q/8AN6v/ADer/wAzof8AMqBAAAAAAGYzM//AaQP/xm0A/8ZtAP/GbQD/xm0A/8ZtAP/GbQD/xm0A + /8ZtAP/GbQD/xm0A/8ZtAP/GbQD/xm0A/8ZtAP/GbQD/xm0A/8ZtAP/GbQD/xm0A/2YzM/9lMjJAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AOa7/ADmv/wA5r/8AOa//ADmv + /wA5r/8AOa//ADmv/wA5r/8AOa//ADmv/wAzof8AMqBAAAAAAGYzM//DbgP/ynIA/8pyAP/KcgD/ynIA + /8pyAP/KcgD/ynIA/8pyAP/KcgD/ynIA/8pyAP/KcgD/ynIA/8pyAP/KcgD/ynIA/8pyAP/KcgD/ynIA + /2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AOrH/ADuz + /wA7s/8AO7P/ADuz/wA7s/8AO7P/ADuz/wA7s/8AO7P/ADuz/wAzof8AMqBAAAAAAGYzM//HcwP/zncA + /853AP/OdwD/zncA/853AP/OdwD/zncA/853AP/OdwD/zncA/853AP/OdwD/zncA/853AP/OdwD/zncA + /853AP/OdwD/zncA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svL + egAzof8APLX/ADy2/wA8tv8APLb/ADy2/wA8tv8APLb/ADy2/wA8tv8APLb/ADy2/wAzof8AMqBAAAAA + AGYzM//LdwP/0nwA/9J8AP/SfAD/0nwA/9J8AP/SfAD/0nwA/9J8AP/SfAD/0nwA/9J8AP/SfAD/0nwA + /9J8AP/SfAD/0nwA/9J8AP/SfAD/0nwA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAD+y8tb/svLegAzof8APbj/AD66/wA+uv8APrr/AD66/wA+uv8APrr/AD66/wA+uv8APrr/AD66 + /wAzof8AMqBAAAAAAGYzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz + /2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AP7z/AEC+/wBAvv8AQL7/AEC+/wBAvv8AQL7/AEC+ + /wBAvv8AQL7/AEC+/wAzof8AMqBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AQb//AEHB/wBBwf8AQcH/AEHB + /wBBwf8AQcH/AEHB/wBBwf8AQcH/AEHB/wAzof8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/+InsiS/svLegAzof8AQsP/AEPF + /wBDxf8AQ8X/AEPF/wBDxf8AQ8X/AEPF/wBDxf8AQ8X/AEPF/wAzof8AW6//SLjk/0i45P9IuOT/SLjk + /0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/0i45P9IuOT/SLjk + /0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/wBbr/9+mMWk/svL + egAzof8ARMb/AEXJ/wBFyf8ARcn/AEXJ/wBFyf8ARcn/AEXJ/wBFyf8ARcn/AEXJ/wAzof8AW6//SLrl + /0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl + /0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl + /wBbr/9+mMWk/svLegAzof8ARcr/AEfM/wBHzP8AR8z/AEfM/wBHzP8AR8z/AEfM/wBHzP8AR8z/AEfM + /wAzof8AW6//SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm + /0i85v9IvOb/SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm + /0i85v9IvOb/SLzm/wBbr/9+mMWk/svLegAzof8AR83/AEjQ/wBI0P8ASND/AEjQ/wBI0P8ASND/AEjQ + /wBI0P8ASND/AEjQ/wAzof8AW6//SL/n/0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n + /0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n + /0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n/wBbr/9+mMWk/svLegAzof8ASNH/AErU/wBK1P8AStT/AErU + /wBK1P8AStT/AErU/wBK1P8AStT/AErU/wAzof8AW6//R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho + /0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho + /0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/wBbr/9+mMWk/8zMegAzof8AStT/AEzY + /wBM2P8ATNj/AEzY/wBM2P8ATNj/AEzY/wBM2P8ATNj/AEzY/wAzof8AW6//R8Pp/0fD6f9Hw+n/R8Pp + /0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp + /0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/wBbr/9+mMWk/8zM + egAzof8ATNj/AE3b/wBN2/8ATdv/AE3b/wBN2/8ATdv/AE3b/wBN2/8ATdv/AE3b/wAzof8AW6//R8Xq + /0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq + /0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq + /wBbr/9+mMWk/8zMegAzof8ARsz/AEjP/wBIz/8ASM//AEjP/wBIz/8ASM//AEjP/wBIz/8ASM//AEjP + /wAzof8AW6//R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr + /0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr + /0fI6/9HyOv/R8jr/wBbr/9+mMWk/8zMegAzof8AM6H/ADOh/wAzof8AM6H/ADOh/wAzof8AM6H/ADOh + /wAzof8AM6H/ADOh/wAzof8AW6//R8rs/0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs + /0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs + /0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//R8zt/0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt + /0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt + /0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Rs7u/0bO7v9Gzu7/Rs7u + /0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u + /0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/wBbr/9+mMWk/8zM + ev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//RtHv + /0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv + /0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv + /wBbr/9+mMWk/8zMev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAW6//RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw + /0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw + /0bT8P9G0/D/RtPw/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAW6//RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy + /0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy + /0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Rtfz/0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz + /0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz + /0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Rtr0/0ba9P9G2vT/Rtr0 + /0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0 + /0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/wBbr/9+mMWk/svL + ev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Rdz1 + /0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1 + /0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1 + /wBbr/9+mMWk/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAW6//Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72 + /0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72 + /0Xe9v9F3vb/Rd72/wBbr/9+mMWk/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAW6//ReD3/0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3 + /0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3 + /0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3/wBbr/9+mMWk/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4 + /0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4 + /0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/wBbr/9+mMWk/svLev7LywgAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//ReX5/0Xl+f9F5fn/ReX5 + /0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5 + /0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/wBbr/9+mMWk/svL + ev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Ref6 + /0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6 + /0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6 + /wBbr/9+mMWk/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAW6//ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7 + /0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7 + /0Tp+/9E6fv/ROn7/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAW6//ROz8/0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8 + /0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8 + /0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8/wBbr/9+mMWk/svLev/LywgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//RO79/0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79 + /0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79 + /0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79/wBbr/9+mMWk/svLev7LywgAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//RPD+/0Tw/v9E8P7/RPD+ + /0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+ + /0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/wBbr/+BmMSi/svL + ev7Lyw7+y8sI/8zMCP/MzAj+y8sI/svLCP7Lywj+y8sI/svLCP7Lywj+y8sI/8zMCP/MzAgAW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr//NtcaA/svLfP/Ly3r+y8t6/8zMev/MzHr+y8t6/svLev7Ly3r+y8t6/svLev7Ly3r+y8t6/8zM + ev/MzHr/zMx6/8zMev/MzHr/zMx6/8zMev/MzHr/zMx6/8zMev/MzHr+y8t6/svLev7Ly3r+y8t6/svL + ev7Ly3r+y8t6/svLev7Ly3r+y8t6/svLev7Ly3r+y8t6/svLev7Ly3r+y8t6/svLev7Ly3r+y8t6/svL + ev7Ly3r+y8t6/svLev7Ly3r+y8uLAAAAAAAADu4//wAAAf4O7j//AAAB/g7uP/8AAAH+Du4//wAAAf4O + 7j//AAAB/g7uP/8AAAH+Du4//wAAAf4O7j//AAAB/g7uP/8AAAH+Du4AAQAAAf4O7gABAAAB/g7uAAEA + AAH+Du4AAQAAAf4O7gABAAAB/g7uAAEAAAH+Du4AAQAAAf4O7gABAAAB/g7uAAH////+Du4AAAAAAAAO + 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 + PamYvaYAM6H/AEC//wBAv/8AQL//AEC//wBAv/8AQL//ADOh/wA7o6oAW69VAFuvVQBbr1UAW69VAFuv + VQBbr1UAW69VAFuvVQBbr1UAW69VAFuvVQBbr1UAW69VAFuvVQBbr1UAW69VAFuvVQBbr1UAW69VAFuv + VQBbr1WsqMRlqZi9pgAzof8AQsP/AELD/wBCw/8AQsP/AELD/wBCw/8AM6H/AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/1aFvr6pmL2mADOh/wBFyv8ARcr/AEXK/wBFyv8ARcr/AEXK/wAzof8AW6//SLrl + /0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl + /0i65f9IuuX/SLrl/0i65f8AW6//VIO9wqmYvaYAM6H/AEfO/wBHzv8AR87/AEfO/wBHzv8AR87/ADOh + /wBbr/9Ivub/SL7m/0i+5v9Ivub/SL7m/0i+5v9Ivub/SL7m/0i+5v9Ivub/SL7m/0i+5v9Ivub/SL7m + /0i+5v9Ivub/SL7m/0i+5v9Ivub/SL7m/wBbr/9Ug73CqZi9pgAzof8AStX/AErV/wBK1f8AStX/AErV + /wBK1f8AM6H/AFuv/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho + /0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/AFuv/1SDvcKqmb2mADOh/wBM2v8ATNr/AEza + /wBM2v8ATNr/AEza/wAzof8AW6//R8Tp/0fE6f9HxOn/R8Tp/0fE6f9HxOn/R8Tp/0fE6f9HxOn/R8Tp + /0fE6f9HxOn/R8Tp/0fE6f9HxOn/R8Tp/0fE6f9HxOn/R8Tp/0fE6f8AW6//VIO9wqqZvaYAM6H/ADOh + /wAzof8AM6H/ADOh/wAzof8AM6H/ADOh/wBbr/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr + /0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/wBbr/9Ug73C4rvH + b15rsFcAM6FVADOhVQAzoVUAM6FVADOhVQAzoVUAM6FVAFuv/0fL7P9Hy+z/R8vs/0fL7P9Hy+z/R8vs + /0fL7P9Hy+z/R8vs/0fL7P9Hy+z/R8vs/0fL7P9Hy+z/R8vs/0fL7P9Hy+z/R8vs/0fL7P9Hy+z/AFuv + /1SDvcL/zMxU/8zMAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Rs/u/0bP7v9Gz+7/Rs/u + /0bP7v9Gz+7/Rs/u/0bP7v9Gz+7/Rs/u/0bP7v9Gz+7/Rs/u/0bP7v9Gz+7/Rs/u/0bP7v9Gz+7/Rs/u + /0bP7v8AW6//VIO9wv/MzFT/zMwDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr/9G0u//RtLv + /0bS7/9G0u//RtLv/0bS7/9G0u//RtLv/0bS7/9G0u//RtLv/0bS7/9G0u//RtLv/0bS7/9G0u//RtLv + /0bS7/9G0u//RtLv/wBbr/9Ug73C/8zMVP/MzAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFuv + /0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy + /0bV8v9G1fL/RtXy/0bV8v9G1fL/AFuv/1SDvcL/zMxU/8zMAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAW6//Rtnz/0bZ8/9G2fP/Rtnz/0bZ8/9G2fP/Rtnz/0bZ8/9G2fP/Rtnz/0bZ8/9G2fP/Rtnz + /0bZ8/9G2fP/Rtnz/0bZ8/9G2fP/Rtnz/0bZ8/8AW6//VIO9wv7Ly1T+y8sDAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABbr/9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1 + /0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/wBbr/9Ug73C/svLVP7LywMAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAFuv/0Xf9v9F3/b/Rd/2/0Xf9v9F3/b/Rd/2/0Xf9v9F3/b/Rd/2 + /0Xf9v9F3/b/Rd/2/0Xf9v9F3/b/Rd/2/0Xf9v9F3/b/Rd/2/0Xf9v9F3/b/AFuv/1SDvcL+y8tU/svL + AwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4 + /0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P8AW6//VIO9 + wv7Ly1T+y8sDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr/9F5vn/Reb5/0Xm+f9F5vn/Reb5 + /0Xm+f9F5vn/Reb5/0Xm+f9F5vn/Reb5/0Xm+f9F5vn/Reb5/0Xm+f9F5vn/Reb5/0Xm+f9F5vn/Reb5 + /wBbr/9Ug73C/svLVP7LywMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFuv/0Tq+/9E6vv/ROr7 + /0Tq+/9E6vv/ROr7/0Tq+/9E6vv/ROr7/0Tq+/9E6vv/ROr7/0Tq+/9E6vv/ROr7/0Tq+/9E6vv/ROr7 + /0Tq+/9E6vv/AFuv/1SDvcL+y8tU/8vLAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//RO38 + /0Tt/P9E7fz/RO38/0Tt/P9E7fz/RO38/0Tt/P9E7fz/RO38/0Tt/P9E7fz/RO38/0Tt/P9E7fz/RO38 + /0Tt/P9E7fz/RO38/0Tt/P8AW6//VIO9wv7Ly1X+y8sF/8zMA/7LywP+y8sD/svLA/7LywP+y8sD/8zM + AwBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/9mir25/svLb/7Ly1X/zMxU/svLVP7Ly1T+y8tU/svL + VP7Ly1T/zMxUxrLFi6qmwqaqpsKmqqbCpqqmwqaqpsKmqaXBpqmlwaappcGmqaXBpqmlwaappcGmqaXB + pqmlwaappcGmqaXBpqmlwaappcGmqaXBpqmlwaappcGmqaXBpta5xpIAAAAAP8AAPj/AAD4/wAA+P8AA + Pj/AAD4AAAA+AAAAPgAAAD4AAAA+AAAAPgAAAD4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAAAAAAAAAAAACgAAAAQAAAAIAAA + AAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tB/svLHv7Lyx7+y8se/svLHp1qanCYZWWjmGVl + o5hlZaOYZWWjmGVlo5hlZaOYZWV4/svLHv7Lyx7+y8s5/svLLAAAAAAAAAAAAAAAAAAAAABmMzP/ZjMz + /2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/wAAAAAAAAAA/svLHv7LyywAAAAAAAAAAAAAAAAAAAAAZjMz + /61NAP+tTQD/rU0A/61NAP+tTQD/rU0A/2YzM/8AAAAAAAAAAP7Lyx4AM6H/ADOh/wAzof8AM6H/ADOh + /2YzM/+5XQD/uV0A/7ldAP+5XQD/uV0A/7ldAP9mMzP/AAAAAAAAAAD+y8seADOh/wA3q/8AN6v/ADer + /wAzof9mMzP/xWwA/8VsAP/FbAD/xWwA/8VsAP/FbAD/ZjMz/wAAAAAAAAAA/svLHgAzof8APLb/ADy2 + /wA8tv8AM6H/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/8AAAAAAAAAAP7Lyx4AM6H/AEHB + /wBBwf8AQcH/ADOh/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//ADOh + /wBGzP8ARsz/AEbM/wAzof9IvOX/SLzl/0i85f9IvOX/SLzl/0i85f9IvOX/SLzl/0i85f9IvOX/AFuv + /wAzof8AS9f/AEvX/wBL1/8AM6H/R8Lo/0fC6P9Hwuj/R8Lo/0fC6P9Hwuj/R8Lo/0fC6P9Hwuj/R8Lo + /wBbr/8AM6H/ADOh/wAzof8AM6H/ADOh/0fJ6/9Hyev/R8nr/0fJ6/9Hyev/R8nr/0fJ6/9Hyev/R8nr + /0fJ6/8AW6///8zMLAAAAAAAAAAAAAAAAABbr/9G0O7/RtDu/0bQ7v9G0O7/RtDu/0bQ7v9G0O7/RtDu + /0bQ7v9G0O7/AFuv///MzCwAAAAAAAAAAAAAAAAAW6//Rtfy/0bX8v9G1/L/Rtfy/0bX8v9G1/L/Rtfy + /0bX8v9G1/L/Rtfy/wBbr//+y8ssAAAAAAAAAAAAAAAAAFuv/0Xd9f9F3fX/Rd31/0Xd9f9F3fX/Rd31 + /0Xd9f9F3fX/Rd31/0Xd9f8AW6///svLLAAAAAAAAAAAAAAAAABbr/9F5Pj/ReT4/0Xk+P9F5Pj/ReT4 + /0Xk+P9F5Pj/ReT4/0Xk+P9F5Pj/AFuv//7LyywAAAAAAAAAAAAAAAAAW6//ROv7/0Tr+/9E6/v/ROv7 + /0Tr+/9E6/v/ROv7/0Tr+/9E6/v/ROv7/wBbr//+y8tI/svLLP7Lyyz+y8ssAFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AACsQXgGrEF4BqxBAAasQQAGrEEABqxBAACs + QQAArEEAAKxBAACsQXAArEFwAKxBcACsQXAArEFwAKxBAACsQQ== + + + \ No newline at end of file diff --git a/branches/ph-plugins/ExtraTools/NtObjects/Program.cs b/branches/ph-plugins/ExtraTools/NtObjects/Program.cs new file mode 100644 index 000000000..da2872772 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/NtObjects/Program.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Windows.Forms; + +namespace NtObjects +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new ObjectsWindow()); + } + } +} diff --git a/branches/ph-plugins/ExtraTools/NtObjects/Properties/AssemblyInfo.cs b/branches/ph-plugins/ExtraTools/NtObjects/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..c34b08eca --- /dev/null +++ b/branches/ph-plugins/ExtraTools/NtObjects/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("NtObjects")] +[assembly: AssemblyDescription("NtObjects")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("wj32")] +[assembly: AssemblyProduct("NtObjects")] +[assembly: AssemblyCopyright("Copyright © 2009 wj32. Licensed under the GNU GPL, v3.")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("5cea10c2-8c9e-45c7-be29-93a5ec8e3f30")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/branches/ph-plugins/ExtraTools/NtObjects/Properties/Resources.Designer.cs b/branches/ph-plugins/ExtraTools/NtObjects/Properties/Resources.Designer.cs new file mode 100644 index 000000000..152144e10 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/NtObjects/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.3074 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace NtObjects.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("NtObjects.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/branches/ph-plugins/ExtraTools/NtObjects/Properties/Resources.resx b/branches/ph-plugins/ExtraTools/NtObjects/Properties/Resources.resx new file mode 100644 index 000000000..ffecec851 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/NtObjects/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ExtraTools/NtObjects/Properties/Settings.Designer.cs b/branches/ph-plugins/ExtraTools/NtObjects/Properties/Settings.Designer.cs new file mode 100644 index 000000000..e906f1ebc --- /dev/null +++ b/branches/ph-plugins/ExtraTools/NtObjects/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.3074 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace NtObjects.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/branches/ph-plugins/ExtraTools/NtObjects/Properties/Settings.settings b/branches/ph-plugins/ExtraTools/NtObjects/Properties/Settings.settings new file mode 100644 index 000000000..abf36c5d3 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/NtObjects/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/branches/ph-plugins/ExtraTools/NtObjects/app.config b/branches/ph-plugins/ExtraTools/NtObjects/app.config new file mode 100644 index 000000000..b7db28170 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/NtObjects/app.config @@ -0,0 +1,3 @@ + + + diff --git a/branches/ph-plugins/ExtraTools/NtProfiler/NtProfiler.csproj b/branches/ph-plugins/ExtraTools/NtProfiler/NtProfiler.csproj new file mode 100644 index 000000000..f156eeca4 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/NtProfiler/NtProfiler.csproj @@ -0,0 +1,130 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {E3CEB6D7-7080-4089-B54E-41025E30CE46} + WinExe + Properties + NtProfiler + NtProfiler + v2.0 + 512 + + + NtProfiler.Program + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + app.manifest + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + AnyCPU + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AnyCPU + + + + + + + + + + + + Form + + + ProfilerWindow.cs + + + + + ProfilerWindow.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + False + .NET Framework 2.0 %28AnyCPU%29 + true + + + False + .NET Framework 3.0 %28AnyCPU%29 + false + + + False + .NET Framework 3.5 + false + + + + + {8E10F5E8-D4FA-4980-BB23-2EDD134AC15E} + ProcessHacker.Common + + + {8A448157-E1A7-4DDF-954E-287F1117832B} + ProcessHacker.Native + + + + + \ No newline at end of file diff --git a/branches/ph-plugins/ExtraTools/NtProfiler/ProfilerWindow.Designer.cs b/branches/ph-plugins/ExtraTools/NtProfiler/ProfilerWindow.Designer.cs new file mode 100644 index 000000000..b8e5f9bf4 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/NtProfiler/ProfilerWindow.Designer.cs @@ -0,0 +1,304 @@ +namespace NtProfiler +{ + partial class ProfilerWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ProfilerWindow)); + this.menuStripMain = new System.Windows.Forms.MenuStrip(); + this.profilerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.profileProcessToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.profileKernelToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.tabControl = new System.Windows.Forms.TabControl(); + this.tabModules = new System.Windows.Forms.TabPage(); + this.listModules = new System.Windows.Forms.ListView(); + this.columnName = new System.Windows.Forms.ColumnHeader(); + this.columnHits = new System.Windows.Forms.ColumnHeader(); + this.columnFileName = new System.Windows.Forms.ColumnHeader(); + this.tabFunctions = new System.Windows.Forms.TabPage(); + this.toolStripContainer = new System.Windows.Forms.ToolStripContainer(); + this.toolStripProfileControl = new System.Windows.Forms.ToolStrip(); + this.toolStripButtonStart = new System.Windows.Forms.ToolStripButton(); + this.toolStripButtonStop = new System.Windows.Forms.ToolStripButton(); + this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator(); + this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.listFunctions = new System.Windows.Forms.ListView(); + this.columnFunction = new System.Windows.Forms.ColumnHeader(); + this.columnFunctionHits = new System.Windows.Forms.ColumnHeader(); + this.menuStripMain.SuspendLayout(); + this.tabControl.SuspendLayout(); + this.tabModules.SuspendLayout(); + this.tabFunctions.SuspendLayout(); + this.toolStripContainer.ContentPanel.SuspendLayout(); + this.toolStripContainer.TopToolStripPanel.SuspendLayout(); + this.toolStripContainer.SuspendLayout(); + this.toolStripProfileControl.SuspendLayout(); + this.SuspendLayout(); + // + // menuStripMain + // + this.menuStripMain.Dock = System.Windows.Forms.DockStyle.None; + this.menuStripMain.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.profilerToolStripMenuItem}); + this.menuStripMain.Location = new System.Drawing.Point(0, 0); + this.menuStripMain.Name = "menuStripMain"; + this.menuStripMain.Size = new System.Drawing.Size(661, 24); + this.menuStripMain.TabIndex = 0; + this.menuStripMain.Text = "menuStrip1"; + // + // profilerToolStripMenuItem + // + this.profilerToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.profileProcessToolStripMenuItem, + this.profileKernelToolStripMenuItem, + this.toolStripMenuItem1, + this.exitToolStripMenuItem}); + this.profilerToolStripMenuItem.Name = "profilerToolStripMenuItem"; + this.profilerToolStripMenuItem.ShowShortcutKeys = false; + this.profilerToolStripMenuItem.Size = new System.Drawing.Size(57, 20); + this.profilerToolStripMenuItem.Text = "&Profiler"; + // + // profileProcessToolStripMenuItem + // + this.profileProcessToolStripMenuItem.Name = "profileProcessToolStripMenuItem"; + this.profileProcessToolStripMenuItem.Size = new System.Drawing.Size(160, 22); + this.profileProcessToolStripMenuItem.Text = "Profile &Process..."; + this.profileProcessToolStripMenuItem.Click += new System.EventHandler(this.profileProcessToolStripMenuItem_Click); + // + // profileKernelToolStripMenuItem + // + this.profileKernelToolStripMenuItem.Name = "profileKernelToolStripMenuItem"; + this.profileKernelToolStripMenuItem.Size = new System.Drawing.Size(160, 22); + this.profileKernelToolStripMenuItem.Text = "Profile &Kernel"; + this.profileKernelToolStripMenuItem.Click += new System.EventHandler(this.profileKernelToolStripMenuItem_Click); + // + // tabControl + // + this.tabControl.Controls.Add(this.tabModules); + this.tabControl.Controls.Add(this.tabFunctions); + this.tabControl.Dock = System.Windows.Forms.DockStyle.Fill; + this.tabControl.Location = new System.Drawing.Point(0, 0); + this.tabControl.Name = "tabControl"; + this.tabControl.SelectedIndex = 0; + this.tabControl.Size = new System.Drawing.Size(661, 404); + this.tabControl.TabIndex = 1; + // + // tabModules + // + this.tabModules.Controls.Add(this.listModules); + this.tabModules.Location = new System.Drawing.Point(4, 22); + this.tabModules.Name = "tabModules"; + this.tabModules.Padding = new System.Windows.Forms.Padding(3); + this.tabModules.Size = new System.Drawing.Size(653, 378); + this.tabModules.TabIndex = 0; + this.tabModules.Text = "Modules"; + this.tabModules.UseVisualStyleBackColor = true; + // + // listModules + // + this.listModules.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnName, + this.columnHits, + this.columnFileName}); + this.listModules.Dock = System.Windows.Forms.DockStyle.Fill; + this.listModules.FullRowSelect = true; + this.listModules.HideSelection = false; + this.listModules.Location = new System.Drawing.Point(3, 3); + this.listModules.Name = "listModules"; + this.listModules.ShowItemToolTips = true; + this.listModules.Size = new System.Drawing.Size(647, 372); + this.listModules.TabIndex = 0; + this.listModules.UseCompatibleStateImageBehavior = false; + this.listModules.View = System.Windows.Forms.View.Details; + this.listModules.DoubleClick += new System.EventHandler(this.listModules_DoubleClick); + // + // columnName + // + this.columnName.Text = "Name"; + this.columnName.Width = 160; + // + // columnHits + // + this.columnHits.Text = "Hits"; + this.columnHits.Width = 100; + // + // columnFileName + // + this.columnFileName.Text = "File Name"; + this.columnFileName.Width = 300; + // + // tabFunctions + // + this.tabFunctions.Controls.Add(this.listFunctions); + this.tabFunctions.Location = new System.Drawing.Point(4, 22); + this.tabFunctions.Name = "tabFunctions"; + this.tabFunctions.Padding = new System.Windows.Forms.Padding(3); + this.tabFunctions.Size = new System.Drawing.Size(653, 378); + this.tabFunctions.TabIndex = 1; + this.tabFunctions.Text = "Functions"; + this.tabFunctions.UseVisualStyleBackColor = true; + // + // toolStripContainer + // + // + // toolStripContainer.ContentPanel + // + this.toolStripContainer.ContentPanel.Controls.Add(this.tabControl); + this.toolStripContainer.ContentPanel.Size = new System.Drawing.Size(661, 404); + this.toolStripContainer.Dock = System.Windows.Forms.DockStyle.Fill; + this.toolStripContainer.Location = new System.Drawing.Point(0, 0); + this.toolStripContainer.Name = "toolStripContainer"; + this.toolStripContainer.Size = new System.Drawing.Size(661, 453); + this.toolStripContainer.TabIndex = 1; + this.toolStripContainer.Text = "toolStripContainer1"; + // + // toolStripContainer.TopToolStripPanel + // + this.toolStripContainer.TopToolStripPanel.Controls.Add(this.menuStripMain); + this.toolStripContainer.TopToolStripPanel.Controls.Add(this.toolStripProfileControl); + // + // toolStripProfileControl + // + this.toolStripProfileControl.Dock = System.Windows.Forms.DockStyle.None; + this.toolStripProfileControl.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripButtonStart, + this.toolStripButtonStop}); + this.toolStripProfileControl.Location = new System.Drawing.Point(3, 24); + this.toolStripProfileControl.Name = "toolStripProfileControl"; + this.toolStripProfileControl.Size = new System.Drawing.Size(58, 25); + this.toolStripProfileControl.TabIndex = 1; + // + // toolStripButtonStart + // + this.toolStripButtonStart.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.toolStripButtonStart.Image = ((System.Drawing.Image)(resources.GetObject("toolStripButtonStart.Image"))); + this.toolStripButtonStart.ImageTransparentColor = System.Drawing.Color.Magenta; + this.toolStripButtonStart.Name = "toolStripButtonStart"; + this.toolStripButtonStart.Size = new System.Drawing.Size(23, 22); + this.toolStripButtonStart.Text = "Start"; + this.toolStripButtonStart.Click += new System.EventHandler(this.toolStripButtonStart_Click); + // + // toolStripButtonStop + // + this.toolStripButtonStop.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.toolStripButtonStop.Enabled = false; + this.toolStripButtonStop.Image = ((System.Drawing.Image)(resources.GetObject("toolStripButtonStop.Image"))); + this.toolStripButtonStop.ImageTransparentColor = System.Drawing.Color.Magenta; + this.toolStripButtonStop.Name = "toolStripButtonStop"; + this.toolStripButtonStop.Size = new System.Drawing.Size(23, 22); + this.toolStripButtonStop.Text = "Stop"; + this.toolStripButtonStop.Click += new System.EventHandler(this.toolStripButtonStop_Click); + // + // toolStripMenuItem1 + // + this.toolStripMenuItem1.Name = "toolStripMenuItem1"; + this.toolStripMenuItem1.Size = new System.Drawing.Size(157, 6); + // + // exitToolStripMenuItem + // + this.exitToolStripMenuItem.Name = "exitToolStripMenuItem"; + this.exitToolStripMenuItem.Size = new System.Drawing.Size(160, 22); + this.exitToolStripMenuItem.Text = "E&xit"; + this.exitToolStripMenuItem.Click += new System.EventHandler(this.exitToolStripMenuItem_Click); + // + // listFunctions + // + this.listFunctions.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnFunction, + this.columnFunctionHits}); + this.listFunctions.Dock = System.Windows.Forms.DockStyle.Fill; + this.listFunctions.FullRowSelect = true; + this.listFunctions.HideSelection = false; + this.listFunctions.Location = new System.Drawing.Point(3, 3); + this.listFunctions.Name = "listFunctions"; + this.listFunctions.ShowItemToolTips = true; + this.listFunctions.Size = new System.Drawing.Size(647, 372); + this.listFunctions.TabIndex = 1; + this.listFunctions.UseCompatibleStateImageBehavior = false; + this.listFunctions.View = System.Windows.Forms.View.Details; + // + // columnFunction + // + this.columnFunction.Text = "Function"; + this.columnFunction.Width = 300; + // + // columnFunctionHits + // + this.columnFunctionHits.Text = "Hits"; + this.columnFunctionHits.Width = 100; + // + // ProfilerWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(661, 453); + this.Controls.Add(this.toolStripContainer); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MainMenuStrip = this.menuStripMain; + this.Name = "ProfilerWindow"; + this.Text = "NtProfiler"; + this.menuStripMain.ResumeLayout(false); + this.menuStripMain.PerformLayout(); + this.tabControl.ResumeLayout(false); + this.tabModules.ResumeLayout(false); + this.tabFunctions.ResumeLayout(false); + this.toolStripContainer.ContentPanel.ResumeLayout(false); + this.toolStripContainer.TopToolStripPanel.ResumeLayout(false); + this.toolStripContainer.TopToolStripPanel.PerformLayout(); + this.toolStripContainer.ResumeLayout(false); + this.toolStripContainer.PerformLayout(); + this.toolStripProfileControl.ResumeLayout(false); + this.toolStripProfileControl.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.MenuStrip menuStripMain; + private System.Windows.Forms.ToolStripMenuItem profilerToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem profileProcessToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem profileKernelToolStripMenuItem; + private System.Windows.Forms.TabControl tabControl; + private System.Windows.Forms.TabPage tabModules; + private System.Windows.Forms.TabPage tabFunctions; + private System.Windows.Forms.ListView listModules; + private System.Windows.Forms.ColumnHeader columnName; + private System.Windows.Forms.ColumnHeader columnHits; + private System.Windows.Forms.ColumnHeader columnFileName; + private System.Windows.Forms.ToolStripContainer toolStripContainer; + private System.Windows.Forms.ToolStrip toolStripProfileControl; + private System.Windows.Forms.ToolStripButton toolStripButtonStart; + private System.Windows.Forms.ToolStripButton toolStripButtonStop; + private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1; + private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem; + private System.Windows.Forms.ListView listFunctions; + private System.Windows.Forms.ColumnHeader columnFunction; + private System.Windows.Forms.ColumnHeader columnFunctionHits; + } +} + diff --git a/branches/ph-plugins/ExtraTools/NtProfiler/ProfilerWindow.cs b/branches/ph-plugins/ExtraTools/NtProfiler/ProfilerWindow.cs new file mode 100644 index 000000000..1a11d43a7 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/NtProfiler/ProfilerWindow.cs @@ -0,0 +1,267 @@ +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using ProcessHacker.Common.Ui; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; +using ProcessHacker.Native.Symbols; + +namespace NtProfiler +{ + public partial class ProfilerWindow : Form + { + private readonly IntPtr _userModeBase; + private readonly IntPtr _userModeLimit; + private readonly IntPtr _kernelModeBase; + private readonly IntPtr _kernelModeLimit; + + private ProfileHandle _profileHandle; + private Dictionary _kernelModules; + private SymbolProvider _kernelSymbols; + private IntPtr _profileBase; + private uint _profileSize; + private int _bucketSizeLog; + private uint _bucketSize; + + public ProfilerWindow() + { + InitializeComponent(); + + unchecked + { + _userModeBase = new IntPtr(0x00000000); + _userModeLimit = new IntPtr(0x7fffffff); + _kernelModeBase = new IntPtr((int)0x80000000); + _kernelModeLimit = new IntPtr((int)0xffffffff); + } + + try { KProcessHacker.Instance = new KProcessHacker(); } + catch { } + + try + { + using (var thandle = ProcessHandle.GetCurrent().GetToken(TokenAccess.Query | TokenAccess.AdjustPrivileges)) + thandle.SetPrivilege("SeSystemProfilePrivilege", SePrivilegeAttributes.Enabled); + } + catch + { } + + Win32.LoadLibrary("C:\\Program Files\\Debugging Tools for Windows (x86)\\dbghelp.dll"); + SymbolProvider.Options |= SymbolOptions.DeferredLoads; + + listModules.ListViewItemSorter = new SortedListViewComparer(listModules) + { + SortColumn = 1, + SortOrder = SortOrder.Descending + }; + listFunctions.ListViewItemSorter = new SortedListViewComparer(listFunctions) + { + SortColumn = 1, + SortOrder = SortOrder.Descending + }; + } + + private uint GetKernelModeCodeRange(out IntPtr baseAddress) + { + IntPtr minAddress = _kernelModeLimit; + IntPtr maxAddress = _kernelModeBase; + + foreach (var module in Windows.GetKernelModules()) + { + if (module.BaseAddress.CompareTo(_kernelModeBase) == -1) + continue; + + if (module.BaseAddress.CompareTo(minAddress) == -1) + minAddress = module.BaseAddress; + if (module.BaseAddress.CompareTo(maxAddress) == 1) + maxAddress = module.BaseAddress; + } + + baseAddress = minAddress; + + return maxAddress.Decrement(minAddress).ToUInt32(); + } + + private IntPtr GetAddress(int bufferIndex) + { + return _profileBase.Increment(_bucketSize * bufferIndex); + } + + private void LoadKernelSymbols() + { + _kernelSymbols = new SymbolProvider(new ProcessHandle(4, ProcessAccess.QueryInformation)); + _kernelSymbols.PreloadModules = true; + + foreach (var module in Windows.GetKernelModules()) + { + try + { + _kernelSymbols.LoadModule(module.FileName, module.BaseAddress); + } + catch + { } + } + } + + private void LoadProfileModules() + { + int[] counters = _profileHandle.Collect(); + Dictionary modules = new Dictionary(); + + for (int i = 0; i < counters.Length; i++) + { + if (counters[i] != 0) + { + IntPtr realAddress = this.GetAddress(i); + IntPtr baseAddress; + + _kernelSymbols.GetModuleFromAddress(realAddress, out baseAddress); + + if (!modules.ContainsKey(baseAddress)) + modules.Add(baseAddress, 0); + + modules[baseAddress]++; + } + } + + listModules.Items.Clear(); + + foreach (var moduleBase in modules.Keys) + { + listModules.Items.Add(new ListViewItem( + new string[] + { + _kernelModules[moduleBase].BaseName, + modules[moduleBase].ToString("N0"), + _kernelModules[moduleBase].FileName + }) + { + Tag = moduleBase + } + ); + } + } + + private void LoadProfileFunctions(IntPtr moduleBase) + { + int[] counters = _profileHandle.Collect(); + Dictionary functions = new Dictionary(); + + for (int i = 0; i < counters.Length; i++) + { + if (counters[i] != 0) + { + IntPtr realAddress = this.GetAddress(i); + IntPtr baseAddress; + + _kernelSymbols.GetModuleFromAddress(realAddress, out baseAddress); + + if (baseAddress != moduleBase) + continue; + + string fileName; + string symbolName; + ulong displacement; + + symbolName = _kernelSymbols.GetSymbolFromAddress(realAddress.ToUInt64(), out fileName, out displacement); + + if (symbolName != null) + { + if (!functions.ContainsKey(symbolName)) + functions.Add(symbolName, 0); + + functions[symbolName]++; + } + } + } + + listFunctions.Items.Clear(); + + foreach (var function in functions.Keys) + { + listFunctions.Items.Add(new ListViewItem( + new string[] + { + function, + functions[function].ToString("N0") + })); + } + } + + #region Menu Items + + #region Profiler + + private void profileProcessToolStripMenuItem_Click(object sender, EventArgs e) + { + + } + + private void profileKernelToolStripMenuItem_Click(object sender, EventArgs e) + { + IntPtr baseAddress; + uint size = this.GetKernelModeCodeRange(out baseAddress); + + _kernelModules = new Dictionary(); + + foreach (var module in Windows.GetKernelModules()) + _kernelModules.Add(module.BaseAddress, module); + + _profileBase = baseAddress; + _profileSize = size; + _bucketSizeLog = 6; // 64 byte bucket size + _bucketSize = (uint)(2 << (_bucketSizeLog - 1)); + _profileHandle = ProfileHandle.Create( + null, + baseAddress, + size, + _bucketSizeLog, + KProfileSource.ProfileTime, + IntPtr.Zero + ); + ProfileHandle.SetInterval(KProfileSource.ProfileTime, 1); // 100 nanoseconds + + this.LoadKernelSymbols(); + } + + private void exitToolStripMenuItem_Click(object sender, EventArgs e) + { + this.Close(); + } + + #endregion + + #endregion + + #region Toolbar + + #region Profile Control + + private void toolStripButtonStart_Click(object sender, EventArgs e) + { + _profileHandle.Start(); + toolStripButtonStart.Enabled = false; + toolStripButtonStop.Enabled = true; + } + + private void toolStripButtonStop_Click(object sender, EventArgs e) + { + _profileHandle.Stop(); + toolStripButtonStart.Enabled = true; + toolStripButtonStop.Enabled = false; + this.LoadProfileModules(); + } + + #endregion + + #endregion + + private void listModules_DoubleClick(object sender, EventArgs e) + { + this.LoadProfileFunctions((IntPtr)listModules.SelectedItems[0].Tag); + tabControl.SelectedTab = tabFunctions; + } + } +} diff --git a/branches/ph-plugins/ExtraTools/NtProfiler/ProfilerWindow.resx b/branches/ph-plugins/ExtraTools/NtProfiler/ProfilerWindow.resx new file mode 100644 index 000000000..fad04cebc --- /dev/null +++ b/branches/ph-plugins/ExtraTools/NtProfiler/ProfilerWindow.resx @@ -0,0 +1,944 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 125, 17 + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAdhJREFUOE+tU8mq + IjEUfR/lP/kB1frKXtUPiKCCijtBEVy4cCUIBhVBHHCK4sKF81hqOaCoeF9OeFUiiIumA5eCSs5w70m+ + vv736na7NlGaKNbpdHTOud5qtVij0dCq1arto16v17MLIF+tVnQ6neh+v8s6Ho80n8+pUqnwcrlsf0sC + sFA0LpcLYeG73+/JMAw6n8/yH0hLpZJRLBZfSX5tcxO83W5ps9lQPp8nXddpvV4TXJkk2WyWi3q2g57N + AyYYQKfzm3K5nAQvFgtZWP1+n1KplGa10m63GezBKoCmqsPhJBRjTIIxB8wD7hKJBLMIms2mjmHtdjsJ + huJyuRRghyyX6y+JBGg6nUqi6/VK0WhUtwhERJIA9k0wDgKsqi5SlD9ybzKZWC4ikciToF6vM0wcbZi9 + wq6qqi/g8XgskxkMBhQOh58tCHsaNh+Ph1SYzWbSrqIoUhl7o9GIhsMh3W43EjFSKBR6DlFkaysUChwz + wIJVFMAmEKoQAIkA82Aw+HorM5mMPZ1OG8gcBw+Hg+UGlwnKIBFgw+v1vr+NyWTSHo/Hea1Wky1gJugZ + uSNKn8/HPR7Pe7AZSSwWs4kBaYFAgPn9fl2o6QLE3G63Jgg+P6Z/edk/yU9ET/seY4MAAAAASUVORK5C + YII= + + + + + iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAcNJREFUOE+tU0ur + QVEYvT/KfzLCXzgYS6GQmSJlYGCklD2QkkdemwwMvJ8bxyNCvrvX7u6jW+4d3O6ulXLOenzr2+fj479P + r9ezSRgSrNvtCs65aLfbrNlsGrVazfarX7/ft0siX6/XdD6f6fF4KJxOJ1osFlStVnmlUrG/FQFZOprX + 65Vw8Hs4HMg0TbpcLuo/iJbLZbNUKn0X+YrNNXm329F2uyUhhMJmsyGk0iKFQoFLvMbBzPqFn8jL5ZIA + nMFgQNls1rBG6XQ6DPEQVbu6XC4CnE4neb1eRUYP6APp0uk0swRarZZAWfv9XgkgDYgaEJjP5zSbzZTQ + 7XajRCIhLAG5IiWA+CCvViuL7HA4yOPx0HQ6VdAp4vH4S6DRaDA0jjH0rHAFEXC73Yo8mUzUZobDIcVi + sdcI8oIYePh8PpWDjqtd8Ww8HtNoNKL7/U5yjRSNRl8lyt3aisUiRwc474hwhQFEJJlHIpHvtzKfz9tz + uZyJnePF4/FopcFlgjNEJNkMBALvb2Mmk7GnUiler9dV4+gEM2PvjDEKBoPc7/e/J+uVJJNJmyzICIfD + LBQKCekmJIn5fD5DCvz+Mf3ly/4E08xAcyCRlTQAAAAASUVORK5CYII= + + + + + AAABAA8AMDAQAAEABABoBgAA9gAAACAgEAABAAQA6AIAAF4HAAAQEBAAAQAEACgBAABGCgAAAAAAAAEA + CABqDQAAbgsAADAwAAABAAgAqA4AANgYAAAgIAAAAQAIAKgIAACAJwAAEBAAAAEACABoBQAAKDAAAAAA + AAABABgAOQ0AAJA1AAAwMAAAAQAYAKgcAADJQgAAICAAAAEAGACoDAAAcV8AABAQAAABABgAaAMAABls + AAAAAAAAAQAgAHANAACBbwAAMDAAAAEAIACoJQAA8XwAACAgAAABACAAqBAAAJmiAAAQEAAAAQAgAGgE + AABBswAAKAAAADAAAABgAAAAAQAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAIAAAACA + gACAAAAAgACAAICAAACAgIAAAAD/AAD/AAAA//8A/wAAAP8A/wD//wAAwMDAAP///wDwAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFRGVGVlZGVkdGVlAAAA + AAAAAAAAAAAAAFZGtkZLa2Rka0a0AAAAAAAAAAAAAAAAAGtka2tka2trZkZHAAAAAAAAAAAAAAAAAGRr + a2tmtmtra2tkAAAAAAAAAAAAAAAAAFZrZma2a2a2a2tnAAAAAAAAAAAAAAAAAEa2a2tra2tra2ZkAAAA + AAAAAAAAAAAAAGa2trZra2a2a2tlAAAAAAAAAAAAAAAAAHa2bbZrZttmtmtmAAAAAAABODE4ExgxAFa2 + tra2tra2tmtlAAAAAAABgxg4E4OBAEZrZrZr1rZr29tmAAAAAAADgTETgxMTAHvWvb22tmvba2tlAAAA + AAADE4ODgxg4AGRr272729tr29vUAAAAAAAIE4MTgTgxAF2729vb22bb29tnAAAAAAABODg4ODgxAEbb + 29vb29u2vb22AAAAAAADg4ODg4ODAEZmZmZmZm1mZmZlAAAAAAABODg4ODg4AHR2VlZWR1ZHRlZWAAAA + AAAIODg4ODg4AAAAAAAAAAAAAAAAAAAAAAADg4ODg4ODM4ODiDiDg4ODg4OIOIODg44BODiDioOBiuiu + p6euinqK6K6np66o6j4BioODg4ODOurqjq6nrq6urqeup3qK6h4Dg4OKg4ODjoruqK6o6o6o6uqOqurq + 6o4Bg4ODiDg4Oq6orqeup66np6iuqOqOqD4Dg4qIOKg4h6eup66Kenp6eurqeup66j4Biog4qDiDPqen + p66urq6np66K6np6eo4DiKg4OKiBiq6nrqiuqKeup6p6enp66j4Bg4OIODgzOup66nrqeup6eurqenrq + eo4BMRMTgTGBh66orqenp6rorop66np66j4AAAAAAAAAOup66np66nrqrqrqenrqeo4AAAAAAAAAinp6 + eup6enrqeurqeup66j4AAAAAAAAAPqrq6qeq6up6euqK6q6uqh4AAAAAAAAAiup6eup6eqeup66urqiu + 6j4AAAAAAAAAOup66np66n6qeqeqenrqqo4AAAAAAAAAGq6q6q6q6qrq6urqrqrq6j4AAAAAAAAAPq6u + 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 + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQIDAwMDAwMDAwMDAwMDAwMDAwMDAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAQQFBQUFBQUFBQUFBQUFBQUFBQUFAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AQYHBwcHBwcHBwcHBwcHBwcHBwcHAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQgJCQkJCQkJCQkJ + CQkJCQkJCQkJAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQoMlZWVlZWVlZWVlZWVlZWVlZWVAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQwNDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NAQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAQ4PEA8PDw8PDw8PDw8PDw8PDw8PAQAAAAAAAAAAAAAAGxsbGxsbGxsbGxsbHAAA + AQ8QEBAQEBAQEBAQEBAQEBAQEBAQAQAAAAAAAAAAAAAAGxwdHR0dHR0dHR0dGwAAARASERERERERERER + ERERERERERERAQAAAAAAAAAAAAAAHB4eHh4eHh4eHh4eGwAAARITExMTExMTExMTExMTExMTExMTAQAA + AAAAAAAAAAAAGx4eHh8eHx4fHh8fGwAAARMVFRUVFRUVFRUVFRUVFRUVFRUVAQAAAAAAAAAAAAAAGx8f + Hx8fHx8fHx8fGwAAARQXFxcXFxcXFxcXFxcXFxcXFxcXAQAAAAAAAAAAAAAAGyAhISEhISEhISEgGwAA + ARYZGRkZGRkZGRkZGRkZGRkZGRkZAQAAAAAAAAAAAAAAGyEhISEhISEhISEhGwAAARgaGhoaGhoaGhoa + GhoaGhoaGhoaAQAAAAAAAAAAAAAAGyIiIyIjIyIjIyMiGwAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAA + AAAAAAAAAAAAGyUlJSUlJSUlJSUlGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGyYm + JiYmJiYmJiYmGyQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJEIAGyYnJygnKCcoJycnHCQv + Ly8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vJEEAGygpKSkpKSkpKSkpHCQwLzAwMDAwMDAwMDAw + MDAwMDAwMDAwMDAwMDAwMDAvJEEAGykrKiorKisqKyoqHCQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw + MDAwMDAwJEEAGyosLCwsLCwsLCwsGyQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwJEEAGywt + LS0tLS0tLS0tHCQxMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExJEEAGy0uLi4uLi4uLi4uHCQy + MjIxMjEyMTIxMjEyMTIxMjEyMTIxMjEyMTIxMjEyJEEAGy4uLi4uLi4uLi4uGyQyMjIyMjIyMjIyMjIy + MjIyMjIyMjIyMjIyMjIyMjIyJEEAGyorKysrKysrKysrGyQzMzQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0 + NDQ0NDQzJEEAGxsbGxsbGxsbGxsbHCQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDU0JEEAAAAA + AAAAAAAAAAAAACQ1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1JEEAAAAAAAAAAAAAAAAAACQ1 + NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1JEEAAAAAAAAAAAAAAAAAACQ2Njc3Nzc3Nzc3Nzc3 + Nzc3Nzc3Nzc3Nzc3Nzc3NzY2JEEAAAAAAAAAAAAAAAAAACQ3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3 + Nzc3Nzg3JEEAAAAAAAAAAAAAAAAAACQ4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4JEEAAAAA + AAAAAAAAAAAAACQ4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4JEEAAAAAAAAAAAAAAAAAACQ5 + OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5JEEAAAAAAAAAAAAAAAAAACQ6Ojo6Ojo6Ojo6Ojo6 + Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6JEEAAAAAAAAAAAAAAAAAACQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7 + Ozs7Ozs7JEEAAAAAAAAAAAAAAAAAACQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7JEEAAAAA + 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 + 3LH/AOvR/wD///8AAAAAAAgALwAOAFAAFQBwABsAkAAhALAAJgDPACwA8AA+Ef8AWDH/AHFR/wCMcf8A + ppH/AL+x/wDa0f8A////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB + AQEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAECAgICAgICAgICAgIBKQAAAAAAAAAAAAAAAAAA + AAAAAQMDAwMDAwMDAwMDAwEpAAAAAAAAAAAAAAAAAAAAAAABBAQEBAQEBAQEBAQEASkAAAAAAAAAAAAA + AAAAAAAAAAEFBQUFBQUFBQUFBQUBKQAAAAAAAAAAAAAAAAAAAAAAAQYGBgYGBgYGBgYGBgEpAAAAAAAA + LAsLCwsLCwsLAAABBwcHBwcHBwcHBwcHASkAAAAAAAAsCwwMDAwMDAsYAAEICAgICAgICAgICAgBKQAA + AAAAACwLDQ0NDQ0NCxgAAQkJCQkJCQkJCQkJCQEpAAAAAAAALAsODg4ODg4LGAABCgoKCgoKCgoKCgoK + ASkAAAAAAAAsCw8PDw8PDwsYAAEBAQEBAQEBAQEBAQEBKQAAAAAAACwLERERERERCxcAAAAAAAAAAAAA + AAAAAAAAAAAAAAAALAsSEhISEhILEBAQEBAQEBAQEBAQEBAQEBAQEBAQECosCxMTExMTEwsQGhoaGhoa + GhoaGhoaGhoaGhoaGhoQGSwLFBQUFBQUCxAbGxsbGxsbGxsbGxsbGxsbGxsbGxAZLAsVFRUVFRULEBwc + HBwcHBwcHBwcHBwcHBwcHBwcEBktCxYWFhYWFgsQHR0dHR0dHR0dHR0dHR0dHR0dHR0QGS0LCwsLCwsL + CxAeHh4eHh4eHh4eHh4eHh4eHh4eHhAZAAAAAAAAAAAAEB8fHx8fHx8fHx8fHx8fHx8fHx8fEBkAAAAA + AAAAAAAQICAgICAgICAgICAgICAgICAgICAQGQAAAAAAAAAAABAhISEhISEhISEhISEhISEhISEhIRAZ + AAAAAAAAAAAAECIiIiIiIiIiIiIiIiIiIiIiIiIiEBkAAAAAAAAAAAAQIyMjIyMjIyMjIyMjIyMjIyMj + IyMQGQAAAAAAAAAAABAkJCQkJCQkJCQkJCQkJCQkJCQkJBAZAAAAAAAAAAAAECUkJSQlJCQkJCQkJCQk + JCQkJCQkEBkAAAAAAAAAAAAQJSUlJSUlJSUlJSUlJSUlJSUlJSUQGQAAAAAAAAAAABAmJiYmJiYmJiYm + JiYmJiYmJiYmJhAZAAAAAAAAAAAAECcnJycnJycnJycnJycnJycnJycnEBkAAAAAAAAAAAAQKCgoKCgo + KCgoKCgoKCgoKCgoKCgQGQAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBArAAAAAAAAAAAALy4u + Li4uLi4uLi4uLi4uLi4uLi4uLjD//////+AAf//gAD//4AA//+AAP//gAD//4AA/AGAAPwAgAD8AIAA/ + ACAAPwAgAD8AP///AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA + /4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAACgAAAAQAAAAIAAAAAEACAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAoj8AAK5OAAC6XQAAr2MPAMZtAACqbEwAsHNMALZ7TACwflQAvINMALKDbwC2h28A + uYxvAL2RbwC2jnQAADerAAA8tgAQUL8AQGi9AABCwgAAR80AEFPEAABM2AAlW8AAQGrDAD6w3wA+tuEA + PrzkAHiGwgB4iMUAcIzKAHiJyQB4jM0AZI3QAHCT2QBftdwAX7neAGCt2ABgstoAR7zmAF+/4QA9wucA + PcjqADzO7QA81O8AO9ryAEfD6QBGyuwAXsLhAEbR7wBG2PIARd/1AEXl+ABE7PwAu7zZALu93ACBuuAA + g73iAJrA3wClw9sApsbcALfH3AD///8AAAAAAAAvDgAAUBgAAHAiAACQLAAAsDYAAM9AAADwSgAR/1sA + Mf9xAFH/hwBx/50Akf+yALH/yQDR/98A////AAAAAAACLwAABFAAAAZwAAAIkAAACrAAAAvPAAAO8AAA + IP8SAD3/MQBb/1EAef9xAJj/kQC1/7EA1P/RAP///wAAAAAAFC8AACJQAAAwcAAAPZAAAEywAABZzwAA + Z/AAAHj/EQCK/zEAnP9RAK7/cQDA/5EA0v+xAOT/0QD///8AAAAAACYvAABAUAAAWnAAAHSQAACOsAAA + qc8AAMLwAADR/xEA2P8xAN7/UQDj/3EA6f+RAO//sQD2/9EA////AAAAAAAvJgAAUEEAAHBbAACQdAAA + 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 + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAGYzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2Yz + M2YzM2YzM2YzM2YzM2YzM2YzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM5o5A546AJ46AJ46AJ46AJ46AJ46 + AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AGYzMwAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AGYzM54+A6I/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/ + AKI/AGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM6JCA6ZDAKZDAKZDAKZDAKZDAKZDAKZDAKZDAKZDAKZD + AKZDAKZDAKZDAKZDAKZDAKZDAKZDAKZDAKZDAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM6ZHA6pJAKpJ + AKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAGYzMwAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAGYzM6lMA65OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5O + AK5OAK5OAK5OAK5OAK5OAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM61RA7JTALJTALJTALJTALJTALJT + ALJTALJTALJTALJTALJTALJTALJTALJTALJTALJTALJTALJTALJTAGYzMwAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AGYzM7FWA7ZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZ + ALZZAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQAzoQAzoQAzoQAzoQAzoQAz + oQAzoQAzoQAzoQAzoQAzoQAzoQAAAAAAAGYzM7RaA7pdALpdALpdALpdALpdALpdALpdALpdALpdALpd + ALpdALpdALpdALpdALpdALpdALpdALpdALpdAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAzoQA0owA0pAA0pAA0pAA0pAA0pAA0pAA0pAA0pAA0pAA0pAAzoQAAAAAAAGYzM7hfA75iAL5i + AL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAGYzMwAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQA2pwA2qAA2qAA2qAA2qAA2qAA2qAA2qAA2qAA2 + qAA2qAAzoQAAAAAAAGYzM7xkA8JoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJo + AMJoAMJoAMJoAMJoAMJoAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQA3qwA3 + qwA3qwA3qwA3qwA3qwA3qwA3qwA3qwA3qwA3qwAzoQAAAAAAAGYzM8BpA8ZtAMZtAMZtAMZtAMZtAMZt + AMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAGYzMwAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAzoQA5rgA5rwA5rwA5rwA5rwA5rwA5rwA5rwA5rwA5rwA5rwAzoQAAAAAA + AGYzM8NuA8pyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpy + AMpyAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQA6sQA7swA7swA7swA7swA7 + swA7swA7swA7swA7swA7swAzoQAAAAAAAGYzM8dzA853AM53AM53AM53AM53AM53AM53AM53AM53AM53 + AM53AM53AM53AM53AM53AM53AM53AM53AM53AGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAzoQA8tQA8tgA8tgA8tgA8tgA8tgA8tgA8tgA8tgA8tgA8tgAzoQAAAAAAAGYzM8t3A9J8ANJ8 + ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8AGYzMwAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQA9uAA+ugA+ugA+ugA+ugA+ugA+ugA+ugA+ugA+ + ugA+ugAzoQAAAAAAAGYzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2Yz + M2YzM2YzM2YzM2YzM2YzM2YzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQA/vABA + vgBAvgBAvgBAvgBAvgBAvgBAvgBAvgBAvgBAvgAzoQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAzoQBBvwBBwQBBwQBBwQBBwQBBwQBBwQBBwQBBwQBBwQBBwQAzoQBbrwBb + rwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBb + rwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbr7rH3wAAAAAzoQBCwwBDxQBDxQBDxQBDxQBD + xQBDxQBDxQBDxQBDxQBDxQAzoQBbr0i45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei4 + 5Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45ABbr6y8 + 2QAAAAAzoQBExgBFyQBFyQBFyQBFyQBFyQBFyQBFyQBFyQBFyQBFyQAzoQBbr0i65Ui65Ui65Ui65Ui6 + 5Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui6 + 5Ui65Ui65Ui65Ui65Ui65Ui65QBbr6y82QAAAAAzoQBFygBHzABHzABHzABHzABHzABHzABHzABHzABH + zABHzAAzoQBbr0i85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki8 + 5ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85gBbr6y82QAAAAAzoQBHzQBI + 0ABI0ABI0ABI0ABI0ABI0ABI0ABI0ABI0ABI0AAzoQBbr0i/50i/50i/50i/50i/50i/50i/50i/50i/ + 50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/ + 50i/50i/5wBbr6y82QAAAAAzoQBI0QBK1ABK1ABK1ABK1ABK1ABK1ABK1ABK1ABK1ABK1AAzoQBbr0fB + 6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB + 6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6ABbr6y82QAAAAAzoQBK1ABM2ABM2ABM2ABM2ABM + 2ABM2ABM2ABM2ABM2ABM2AAzoQBbr0fD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD + 6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6QBbr6y8 + 2QAAAAAzoQBM2ABN2wBN2wBN2wBN2wBN2wBN2wBN2wBN2wBN2wBN2wAzoQBbr0fF6kfF6kfF6kfF6kfF + 6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF + 6kfF6kfF6kfF6kfF6kfF6kfF6gBbr6y82QAAAAAzoQBGzABIzwBIzwBIzwBIzwBIzwBIzwBIzwBIzwBI + zwBIzwAzoQBbr0fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI + 60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI6wBbr6y82QAAAAAzoQAzoQAz + oQAzoQAzoQAzoQAzoQAzoQAzoQAzoQAzoQAzoQAzoQBbr0fK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK + 7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK + 7EfK7EfK7ABbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0fM + 7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM + 7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7QBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAABbr0bO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO + 7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7gBbr6y8 + 2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0bR70bR70bR70bR70bR + 70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR + 70bR70bR70bR70bR70bR70bR7wBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAABbr0bT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT + 8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8ABbr6y82QAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0bV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV + 8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV + 8kbV8kbV8gBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0bX + 80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX + 80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX8wBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAABbr0ba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba + 9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9ABbr6y8 + 2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Xc9UXc9UXc9UXc9UXc + 9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc + 9UXc9UXc9UXc9UXc9UXc9UXc9QBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAABbr0Xe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe + 9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9gBbr6y82QAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg + 90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg + 90Xg90Xg9wBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Xj + +EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj + +EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+ABbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAABbr0Xl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl + +UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+QBbr6y8 + 2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Xn+kXn+kXn+kXn+kXn + +kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn + +kXn+kXn+kXn+kXn+kXn+kXn+gBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAABbr0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp + +0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+wBbr6y82QAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Ts/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs + /ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs + /ETs/ETs/ABbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Tu + /UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu + /UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/QBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAABbr0Tw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw + /kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/gBbr669 + 2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbrwBbrwBbrwBbrwBbrwBb + rwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBb + rwBbrwBbrwBbrwBbrwBbrwBbrwBbr+XZ4gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7i4n///////g7u//// + ////Du7//wAAA/8O7v//AAAD/w7u//8AAAP/Du7//wAAA/8O7v//AAAD/w7u//8AAAP/Du7//wAAA/8O + 7v//AAAD/w7ugAMAAAP/Du6AAwAAA/8O7oADAAAD/w7ugAMAAAP/Du6AAwAAA/8O7oADAAAD/w7ugAMA + AAP/Du6AAwAAA/8O7oAD/////w7ugAAAAAAADu6AAAAAAAAO7oAAAAAAAA7ugAAAAAAADu6AAAAAAAAO + 7oAAAAAAAA7ugAAAAAAADu6AAAAAAAAO7oAAAAAAAA7ugAAAAAAADu7//AAAAAAO7v/8AAAAAA7u//wA + AAAADu7//AAAAAAO7v/8AAAAAA7u//wAAAAADu7//AAAAAAO7v/8AAAAAA7u//wAAAAADu7//AAAAAAO + 7v/8AAAAAA7u//wAAAAADu7//AAAAAAO7v/8AAAAAA7u//wAAAAADu7//AAAAAAO7v/8AAAAAA7u//wA + AAAADu7///////4O7igAAAAgAAAAQAAAAAEAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzMAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmMzOfOwCfOwCfOwCfOwCfOwCfOwCf + OwCfOwCfOwCfOwCfOwCfOwBmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABmMzOkQQCkQQCkQQCkQQCkQQCkQQCkQQCkQQCkQQCkQQCkQQCkQQBmMzOxmJgA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmMzOrSgCrSgCr + SgCrSgCrSgCrSgCrSgCrSgCrSgCrSgCrSgCrSgBmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmMzOwUQCwUQCwUQCwUQCwUQCwUQCwUQCwUQCwUQCwUQCw + UQCwUQBmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABmMzO3WgC3WgC3WgC3WgC3WgC3WgC3WgC3WgC3WgC3WgC3WgC3WgBmMzOxmJgAAAAAAAAAAAAAAAAA + AAAAAADHu9QAM6EAM6EAM6EAM6EAM6EAM6EAM6EAM6EAAAAAAABmMzO8YAC8YAC8YAC8YAC8YAC8YAC8 + YAC8YAC8YAC8YAC8YAC8YABmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAADHu9QAM6EANqkANqkANqkANqkA + NqkANqkAM6F/mM8AAABmMzPDaQDDaQDDaQDDaQDDaQDDaQDDaQDDaQDDaQDDaQDDaQDDaQBmMzOxmJgA + AAAAAAAAAAAAAAAAAAAAAADHu9QAM6EAOK0AOK0AOK0AOK0AOK0AOK0AM6F/mM8AAABmMzPIcADIcADI + cADIcADIcADIcADIcADIcADIcADIcADIcADIcABmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAADHu9QAM6EA + O7QAO7QAO7QAO7QAO7QAO7QAM6F/mM8AAABmMzPPeADPeADPeADPeADPeADPeADPeADPeADPeADPeADP + eADPeABmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAADHu9QAM6EAPbgAPbgAPbgAPbgAPbgAPbgAM6F/mM8A + AABmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzOxmJgAAAAAAAAAAAAAAAAA + AAAAAADHu9QAM6EAQL8AQL8AQL8AQL8AQL8AQL8AM6FVfMEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADHu9QAM6EAQsMAQsMAQsMAQsMA + QsMAQsMAM6EAW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68A + W68AW68AW68AW68AW6+BpM7Hu9QAM6EARcoARcoARcoARcoARcoARcoAM6EAW69IuuVIuuVIuuVIuuVI + uuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuUAW698oMzHu9QAM6EA + R84AR84AR84AR84AR84AR84AM6EAW69IvuZIvuZIvuZIvuZIvuZIvuZIvuZIvuZIvuZIvuZIvuZIvuZI + vuZIvuZIvuZIvuZIvuZIvuZIvuZIvuYAW698oMzHu9QAM6EAStUAStUAStUAStUAStUAStUAM6EAW69H + wehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwegA + W698oMzHvNQAM6EATNoATNoATNoATNoATNoATNoAM6EAW69HxOlHxOlHxOlHxOlHxOlHxOlHxOlHxOlH + xOlHxOlHxOlHxOlHxOlHxOlHxOlHxOlHxOlHxOlHxOlHxOkAW698oMzHvNQAM6EAM6EAM6EAM6EAM6EA + M6EAM6EAM6EAW69HyOtHyOtHyOtHyOtHyOtHyOtHyOtHyOtHyOtHyOtHyOtHyOtHyOtHyOtHyOtHyOtH + yOtHyOtHyOtHyOsAW698oMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW69Hy+xHy+xHy+xHy+xH + y+xHy+xHy+xHy+xHy+xHy+xHy+xHy+xHy+xHy+xHy+xHy+xHy+xHy+xHy+xHy+wAW698oMwAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAW69Gz+5Gz+5Gz+5Gz+5Gz+5Gz+5Gz+5Gz+5Gz+5Gz+5Gz+5Gz+5G + z+5Gz+5Gz+5Gz+5Gz+5Gz+5Gz+5Gz+4AW698oMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW69G + 0u9G0u9G0u9G0u9G0u9G0u9G0u9G0u9G0u9G0u9G0u9G0u9G0u9G0u9G0u9G0u9G0u9G0u9G0u9G0u8A + W698oMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW69G1fJG1fJG1fJG1fJG1fJG1fJG1fJG1fJG + 1fJG1fJG1fJG1fJG1fJG1fJG1fJG1fJG1fJG1fJG1fJG1fIAW698oMwAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAW69G2fNG2fNG2fNG2fNG2fNG2fNG2fNG2fNG2fNG2fNG2fNG2fNG2fNG2fNG2fNG2fNG + 2fNG2fNG2fNG2fMAW698oMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW69F3PVF3PVF3PVF3PVF + 3PVF3PVF3PVF3PVF3PVF3PVF3PVF3PVF3PVF3PVF3PVF3PVF3PVF3PVF3PVF3PUAW698oMwAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAW69F3/ZF3/ZF3/ZF3/ZF3/ZF3/ZF3/ZF3/ZF3/ZF3/ZF3/ZF3/ZF + 3/ZF3/ZF3/ZF3/ZF3/ZF3/ZF3/ZF3/YAW698oMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW69F + 4/hF4/hF4/hF4/hF4/hF4/hF4/hF4/hF4/hF4/hF4/hF4/hF4/hF4/hF4/hF4/hF4/hF4/hF4/hF4/gA + W698oMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW69F5vlF5vlF5vlF5vlF5vlF5vlF5vlF5vlF + 5vlF5vlF5vlF5vlF5vlF5vlF5vlF5vlF5vlF5vlF5vlF5vkAW698oMwAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAW69E6vtE6vtE6vtE6vtE6vtE6vtE6vtE6vtE6vtE6vtE6vtE6vtE6vtE6vtE6vtE6vtE + 6vtE6vtE6vtE6vsAW698oMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW69E7fxE7fxE7fxE7fxE + 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 + bQIAK8YArNre91lwpL6t0TYBgBVjAFZp5/ssOFLfTdU2AYAVYwBWJgCxUd8TAJTAGIBGbX2fBUfqh2na + JgCwYgzASm18nwVHaul0bRMAWDEFAPEjALBCAMoTAYAVAlCeCACsEIDyRAAARI8AAAkjAEDCCACQMAIA + JIwAAAkjAEDCCACQMFMAAKRlbv1PNdVF4Jm637at+5rUfY3qvrL4iScADfsZgOX03tj+IOMAAAAASUVO + RK5CYIIoAAAAMAAAAGAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/svLi/7Ly2D+y8tb/svL + W/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svL + W/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svL + W/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8uU/svL + ev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AGUyMhxlMjIgZTIyIGUyMiBlMjIgZTIyIGUyMiBlMjIgZTIyIGUyMiBlMjIgZTIyIGUyMiBlMjIgZTIy + IGUyMiBlMjIgZTIyIGUyMiBlMjIgZTIyIGUyMiBlMjIIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAGYzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz + /2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM/+aOQP/njoA/546AP+eOgD/njoA/546AP+eOgD/njoA + /546AP+eOgD/njoA/546AP+eOgD/njoA/546AP+eOgD/njoA/546AP+eOgD/njoA/2YzM/9lMjJAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM/+ePgP/oj8A/6I/AP+iPwD/oj8A + /6I/AP+iPwD/oj8A/6I/AP+iPwD/oj8A/6I/AP+iPwD/oj8A/6I/AP+iPwD/oj8A/6I/AP+iPwD/oj8A + /2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLev7LywgAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM/+iQgP/pkMA + /6ZDAP+mQwD/pkMA/6ZDAP+mQwD/pkMA/6ZDAP+mQwD/pkMA/6ZDAP+mQwD/pkMA/6ZDAP+mQwD/pkMA + /6ZDAP+mQwD/pkMA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svL + ev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AGYzM/+mRwP/qkkA/6pJAP+qSQD/qkkA/6pJAP+qSQD/qkkA/6pJAP+qSQD/qkkA/6pJAP+qSQD/qkkA + /6pJAP+qSQD/qkkA/6pJAP+qSQD/qkkA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAGYzM/+pTAP/rk4A/65OAP+uTgD/rk4A/65OAP+uTgD/rk4A/65OAP+uTgD/rk4A + /65OAP+uTgD/rk4A/65OAP+uTgD/rk4A/65OAP+uTgD/rk4A/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM/+tUQP/slMA/7JTAP+yUwD/slMA/7JTAP+yUwD/slMA + /7JTAP+yUwD/slMA/7JTAP+yUwD/slMA/7JTAP+yUwD/slMA/7JTAP+yUwD/slMA/2YzM/9lMjJAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM/+xVgP/tlkA/7ZZAP+2WQD/tlkA + /7ZZAP+2WQD/tlkA/7ZZAP+2WQD/tlkA/7ZZAP+2WQD/tlkA/7ZZAP+2WQD/tlkA/7ZZAP+2WQD/tlkA + /2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AM6H/ADOh + /wAzof8AM6H/ADOh/wAzof8AM6H/ADOh/wAzof8AM6H/ADOh/wAzof8AMqAsAAAAAGYzM/+0WgP/ul0A + /7pdAP+6XQD/ul0A/7pdAP+6XQD/ul0A/7pdAP+6XQD/ul0A/7pdAP+6XQD/ul0A/7pdAP+6XQD/ul0A + /7pdAP+6XQD/ul0A/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svL + egAzof8ANKP/ADSk/wA0pP8ANKT/ADSk/wA0pP8ANKT/ADSk/wA0pP8ANKT/ADSk/wAzof8AMqBAAAAA + AGYzM/+4XwP/vmIA/75iAP++YgD/vmIA/75iAP++YgD/vmIA/75iAP++YgD/vmIA/75iAP++YgD/vmIA + /75iAP++YgD/vmIA/75iAP++YgD/vmIA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAD+y8tb/svLegAzof8ANqf/ADao/wA2qP8ANqj/ADao/wA2qP8ANqj/ADao/wA2qP8ANqj/ADao + /wAzof8AMqBAAAAAAGYzM/+8ZAP/wmgA/8JoAP/CaAD/wmgA/8JoAP/CaAD/wmgA/8JoAP/CaAD/wmgA + /8JoAP/CaAD/wmgA/8JoAP/CaAD/wmgA/8JoAP/CaAD/wmgA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AN6v/ADer/wA3q/8AN6v/ADer/wA3q/8AN6v/ADer + /wA3q/8AN6v/ADer/wAzof8AMqBAAAAAAGYzM//AaQP/xm0A/8ZtAP/GbQD/xm0A/8ZtAP/GbQD/xm0A + /8ZtAP/GbQD/xm0A/8ZtAP/GbQD/xm0A/8ZtAP/GbQD/xm0A/8ZtAP/GbQD/xm0A/2YzM/9lMjJAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AOa7/ADmv/wA5r/8AOa//ADmv + /wA5r/8AOa//ADmv/wA5r/8AOa//ADmv/wAzof8AMqBAAAAAAGYzM//DbgP/ynIA/8pyAP/KcgD/ynIA + /8pyAP/KcgD/ynIA/8pyAP/KcgD/ynIA/8pyAP/KcgD/ynIA/8pyAP/KcgD/ynIA/8pyAP/KcgD/ynIA + /2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AOrH/ADuz + /wA7s/8AO7P/ADuz/wA7s/8AO7P/ADuz/wA7s/8AO7P/ADuz/wAzof8AMqBAAAAAAGYzM//HcwP/zncA + /853AP/OdwD/zncA/853AP/OdwD/zncA/853AP/OdwD/zncA/853AP/OdwD/zncA/853AP/OdwD/zncA + /853AP/OdwD/zncA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svL + egAzof8APLX/ADy2/wA8tv8APLb/ADy2/wA8tv8APLb/ADy2/wA8tv8APLb/ADy2/wAzof8AMqBAAAAA + AGYzM//LdwP/0nwA/9J8AP/SfAD/0nwA/9J8AP/SfAD/0nwA/9J8AP/SfAD/0nwA/9J8AP/SfAD/0nwA + /9J8AP/SfAD/0nwA/9J8AP/SfAD/0nwA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAD+y8tb/svLegAzof8APbj/AD66/wA+uv8APrr/AD66/wA+uv8APrr/AD66/wA+uv8APrr/AD66 + /wAzof8AMqBAAAAAAGYzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz + /2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AP7z/AEC+/wBAvv8AQL7/AEC+/wBAvv8AQL7/AEC+ + /wBAvv8AQL7/AEC+/wAzof8AMqBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AQb//AEHB/wBBwf8AQcH/AEHB + /wBBwf8AQcH/AEHB/wBBwf8AQcH/AEHB/wAzof8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/+InsiS/svLegAzof8AQsP/AEPF + /wBDxf8AQ8X/AEPF/wBDxf8AQ8X/AEPF/wBDxf8AQ8X/AEPF/wAzof8AW6//SLjk/0i45P9IuOT/SLjk + /0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/0i45P9IuOT/SLjk + /0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/wBbr/9+mMWk/svL + egAzof8ARMb/AEXJ/wBFyf8ARcn/AEXJ/wBFyf8ARcn/AEXJ/wBFyf8ARcn/AEXJ/wAzof8AW6//SLrl + /0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl + /0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl + /wBbr/9+mMWk/svLegAzof8ARcr/AEfM/wBHzP8AR8z/AEfM/wBHzP8AR8z/AEfM/wBHzP8AR8z/AEfM + /wAzof8AW6//SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm + /0i85v9IvOb/SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm + /0i85v9IvOb/SLzm/wBbr/9+mMWk/svLegAzof8AR83/AEjQ/wBI0P8ASND/AEjQ/wBI0P8ASND/AEjQ + /wBI0P8ASND/AEjQ/wAzof8AW6//SL/n/0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n + /0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n + /0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n/wBbr/9+mMWk/svLegAzof8ASNH/AErU/wBK1P8AStT/AErU + /wBK1P8AStT/AErU/wBK1P8AStT/AErU/wAzof8AW6//R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho + /0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho + /0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/wBbr/9+mMWk/8zMegAzof8AStT/AEzY + /wBM2P8ATNj/AEzY/wBM2P8ATNj/AEzY/wBM2P8ATNj/AEzY/wAzof8AW6//R8Pp/0fD6f9Hw+n/R8Pp + /0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp + /0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/wBbr/9+mMWk/8zM + egAzof8ATNj/AE3b/wBN2/8ATdv/AE3b/wBN2/8ATdv/AE3b/wBN2/8ATdv/AE3b/wAzof8AW6//R8Xq + /0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq + /0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq + /wBbr/9+mMWk/8zMegAzof8ARsz/AEjP/wBIz/8ASM//AEjP/wBIz/8ASM//AEjP/wBIz/8ASM//AEjP + /wAzof8AW6//R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr + /0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr + /0fI6/9HyOv/R8jr/wBbr/9+mMWk/8zMegAzof8AM6H/ADOh/wAzof8AM6H/ADOh/wAzof8AM6H/ADOh + /wAzof8AM6H/ADOh/wAzof8AW6//R8rs/0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs + /0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs + /0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//R8zt/0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt + /0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt + /0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Rs7u/0bO7v9Gzu7/Rs7u + /0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u + /0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/wBbr/9+mMWk/8zM + ev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//RtHv + /0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv + /0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv + /wBbr/9+mMWk/8zMev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAW6//RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw + /0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw + /0bT8P9G0/D/RtPw/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAW6//RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy + /0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy + /0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Rtfz/0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz + /0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz + /0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Rtr0/0ba9P9G2vT/Rtr0 + /0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0 + /0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/wBbr/9+mMWk/svL + ev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Rdz1 + /0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1 + /0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1 + /wBbr/9+mMWk/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAW6//Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72 + /0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72 + /0Xe9v9F3vb/Rd72/wBbr/9+mMWk/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAW6//ReD3/0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3 + /0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3 + /0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3/wBbr/9+mMWk/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4 + /0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4 + /0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/wBbr/9+mMWk/svLev7LywgAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//ReX5/0Xl+f9F5fn/ReX5 + /0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5 + /0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/wBbr/9+mMWk/svL + ev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Ref6 + /0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6 + /0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6 + /wBbr/9+mMWk/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAW6//ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7 + /0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7 + /0Tp+/9E6fv/ROn7/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAW6//ROz8/0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8 + /0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8 + /0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8/wBbr/9+mMWk/svLev/LywgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//RO79/0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79 + /0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79 + /0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79/wBbr/9+mMWk/svLev7LywgAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//RPD+/0Tw/v9E8P7/RPD+ + /0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+ + /0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/wBbr/+BmMSi/svL + ev7Lyw7+y8sI/8zMCP/MzAj+y8sI/svLCP7Lywj+y8sI/svLCP7Lywj+y8sI/8zMCP/MzAgAW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr//NtcaA/svLfP/Ly3r+y8t6/8zMev/MzHr+y8t6/svLev7Ly3r+y8t6/svLev7Ly3r+y8t6/8zM + ev/MzHr/zMx6/8zMev/MzHr/zMx6/8zMev/MzHr/zMx6/8zMev/MzHr+y8t6/svLev7Ly3r+y8t6/svL + ev7Ly3r+y8t6/svLev7Ly3r+y8t6/svLev7Ly3r+y8t6/svLev7Ly3r+y8t6/svLev7Ly3r+y8t6/svL + ev7Ly3r+y8t6/svLev7Ly3r+y8uLAAAAAAAADu4//wAAAf4O7j//AAAB/g7uP/8AAAH+Du4//wAAAf4O + 7j//AAAB/g7uP/8AAAH+Du4//wAAAf4O7j//AAAB/g7uP/8AAAH+Du4AAQAAAf4O7gABAAAB/g7uAAEA + AAH+Du4AAQAAAf4O7gABAAAB/g7uAAEAAAH+Du4AAQAAAf4O7gABAAAB/g7uAAH////+Du4AAAAAAAAO + 7gAAAAAAAA7uAAAAAAAADu4AAAAAAAAO7gAAAAAAAA7uAAAAAAAADu4AAAAAAAAO7gAAAAAAAA7uAAAA + AAAADu4AAAAAAAAO7j/8AAAAAA7uP/wAAAAADu4//AAAAAAO7j/8AAAAAA7uP/wAAAAADu4//AAAAAAO + 7j/8AAAAAA7uP/wAAAAADu4//AAAAAAO7j/8AAAAAA7uP/wAAAAADu4//AAAAAAO7j/8AAAAAA7uP/wA + AAAADu4//AAAAAAO7j/8AAAAAA7uP/wAAAAADu4AAAAAAAAO7gAAAAAAAA7uKAAAACAAAABAAAAAAQAg + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7Ly2/+y8s//svLPf7Lyz3+y8s9/svLPf7Lyz3+y8s9/svL + Pf7Lyz3hrq5Ay5iYR8uYmEfLmJhHy5iYR8uYmEfLmJhHy5iYR8uYmEfLmJhHy5iYR8uYmEfLmJhHy5iY + R8uYmEfLmJhC/svLPf7Lyz3+y8s9/svLPf7Lyz3+y8tq/svLVP7LywMAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAGUyMjxmMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz + /2YzM/9mMzP/ZjMz/2UyMloAAAAAAAAAAAAAAAAAAAAAAAAAAP7Lyz3+y8tU/svLAwAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAZjMzVWYzM/+fOwD/nzsA/587AP+fOwD/nzsA/587AP+fOwD/nzsA + /587AP+fOwD/nzsA/587AP9mMzP/ZTIygAAAAAAAAAAAAAAAAAAAAAAAAAAA/svLPf7Ly1T+y8sDAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmMzNVZjMz/6RBAP+kQQD/pEEA/6RBAP+kQQD/pEEA + /6RBAP+kQQD/pEEA/6RBAP+kQQD/pEEA/2YzM/9lMjKAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8s9/svL + VP7LywMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM1VmMzP/q0oA/6tKAP+rSgD/q0oA + /6tKAP+rSgD/q0oA/6tKAP+rSgD/q0oA/6tKAP+rSgD/ZjMz/2UyMoAAAAAAAAAAAAAAAAAAAAAAAAAA + AP7Lyz3+y8tU/svLAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZjMzVWYzM/+wUQD/sFEA + /7BRAP+wUQD/sFEA/7BRAP+wUQD/sFEA/7BRAP+wUQD/sFEA/7BRAP9mMzP/ZTIygAAAAAAAAAAAAAAA + AAAAAAAAAAAA/svLPeG6xm9da7BXADOhVQAzoVUAM6FVADOhVQAzoVUAM6FVADOhVQAyoCZmMzNVZjMz + /7daAP+3WgD/t1oA/7daAP+3WgD/t1oA/7daAP+3WgD/t1oA/7daAP+3WgD/t1oA/2YzM/9lMjKAAAAA + AAAAAAAAAAAAAAAAAAAAAAD+y8s9qZi9pgAzof8AM6H/ADOh/wAzof8AM6H/ADOh/wAzof8AM6H/ADKg + e2YzM1VmMzP/vGAA/7xgAP+8YAD/vGAA/7xgAP+8YAD/vGAA/7xgAP+8YAD/vGAA/7xgAP+8YAD/ZjMz + /2UyMoAAAAAAAAAAAAAAAAAAAAAAAAAAAP7Lyz2pmL2mADOh/wA2qf8ANqn/ADap/wA2qf8ANqn/ADap + /wAzof8AMqCAZjMzVWYzM//DaQD/w2kA/8NpAP/DaQD/w2kA/8NpAP/DaQD/w2kA/8NpAP/DaQD/w2kA + /8NpAP9mMzP/ZTIygAAAAAAAAAAAAAAAAAAAAAAAAAAA/svLPamYvaYAM6H/ADit/wA4rf8AOK3/ADit + /wA4rf8AOK3/ADOh/wAyoIBmMzNVZjMz/8hwAP/IcAD/yHAA/8hwAP/IcAD/yHAA/8hwAP/IcAD/yHAA + /8hwAP/IcAD/yHAA/2YzM/9lMjKAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8s9qZi9pgAzof8AO7T/ADu0 + /wA7tP8AO7T/ADu0/wA7tP8AM6H/ADKggGYzM1VmMzP/z3gA/894AP/PeAD/z3gA/894AP/PeAD/z3gA + /894AP/PeAD/z3gA/894AP/PeAD/ZjMz/2UyMoAAAAAAAAAAAAAAAAAAAAAAAAAAAP7Lyz2pmL2mADOh + /wA9uP8APbj/AD24/wA9uP8APbj/AD24/wAzof8AMqCAZjMzVWYzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz + /2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZTIygAAAAAAAAAAAAAAAAAAAAAAAAAAA/svL + PamYvaYAM6H/AEC//wBAv/8AQL//AEC//wBAv/8AQL//ADOh/wA7o6oAW69VAFuvVQBbr1UAW69VAFuv + VQBbr1UAW69VAFuvVQBbr1UAW69VAFuvVQBbr1UAW69VAFuvVQBbr1UAW69VAFuvVQBbr1UAW69VAFuv + VQBbr1WsqMRlqZi9pgAzof8AQsP/AELD/wBCw/8AQsP/AELD/wBCw/8AM6H/AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/1aFvr6pmL2mADOh/wBFyv8ARcr/AEXK/wBFyv8ARcr/AEXK/wAzof8AW6//SLrl + /0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl + /0i65f9IuuX/SLrl/0i65f8AW6//VIO9wqmYvaYAM6H/AEfO/wBHzv8AR87/AEfO/wBHzv8AR87/ADOh + /wBbr/9Ivub/SL7m/0i+5v9Ivub/SL7m/0i+5v9Ivub/SL7m/0i+5v9Ivub/SL7m/0i+5v9Ivub/SL7m + /0i+5v9Ivub/SL7m/0i+5v9Ivub/SL7m/wBbr/9Ug73CqZi9pgAzof8AStX/AErV/wBK1f8AStX/AErV + /wBK1f8AM6H/AFuv/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho + /0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/AFuv/1SDvcKqmb2mADOh/wBM2v8ATNr/AEza + /wBM2v8ATNr/AEza/wAzof8AW6//R8Tp/0fE6f9HxOn/R8Tp/0fE6f9HxOn/R8Tp/0fE6f9HxOn/R8Tp + /0fE6f9HxOn/R8Tp/0fE6f9HxOn/R8Tp/0fE6f9HxOn/R8Tp/0fE6f8AW6//VIO9wqqZvaYAM6H/ADOh + /wAzof8AM6H/ADOh/wAzof8AM6H/ADOh/wBbr/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr + /0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/wBbr/9Ug73C4rvH + b15rsFcAM6FVADOhVQAzoVUAM6FVADOhVQAzoVUAM6FVAFuv/0fL7P9Hy+z/R8vs/0fL7P9Hy+z/R8vs + /0fL7P9Hy+z/R8vs/0fL7P9Hy+z/R8vs/0fL7P9Hy+z/R8vs/0fL7P9Hy+z/R8vs/0fL7P9Hy+z/AFuv + /1SDvcL/zMxU/8zMAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Rs/u/0bP7v9Gz+7/Rs/u + /0bP7v9Gz+7/Rs/u/0bP7v9Gz+7/Rs/u/0bP7v9Gz+7/Rs/u/0bP7v9Gz+7/Rs/u/0bP7v9Gz+7/Rs/u + /0bP7v8AW6//VIO9wv/MzFT/zMwDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr/9G0u//RtLv + /0bS7/9G0u//RtLv/0bS7/9G0u//RtLv/0bS7/9G0u//RtLv/0bS7/9G0u//RtLv/0bS7/9G0u//RtLv + /0bS7/9G0u//RtLv/wBbr/9Ug73C/8zMVP/MzAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFuv + /0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy + /0bV8v9G1fL/RtXy/0bV8v9G1fL/AFuv/1SDvcL/zMxU/8zMAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAW6//Rtnz/0bZ8/9G2fP/Rtnz/0bZ8/9G2fP/Rtnz/0bZ8/9G2fP/Rtnz/0bZ8/9G2fP/Rtnz + /0bZ8/9G2fP/Rtnz/0bZ8/9G2fP/Rtnz/0bZ8/8AW6//VIO9wv7Ly1T+y8sDAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABbr/9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1 + /0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/wBbr/9Ug73C/svLVP7LywMAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAFuv/0Xf9v9F3/b/Rd/2/0Xf9v9F3/b/Rd/2/0Xf9v9F3/b/Rd/2 + /0Xf9v9F3/b/Rd/2/0Xf9v9F3/b/Rd/2/0Xf9v9F3/b/Rd/2/0Xf9v9F3/b/AFuv/1SDvcL+y8tU/svL + AwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4 + /0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P8AW6//VIO9 + wv7Ly1T+y8sDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr/9F5vn/Reb5/0Xm+f9F5vn/Reb5 + /0Xm+f9F5vn/Reb5/0Xm+f9F5vn/Reb5/0Xm+f9F5vn/Reb5/0Xm+f9F5vn/Reb5/0Xm+f9F5vn/Reb5 + /wBbr/9Ug73C/svLVP7LywMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFuv/0Tq+/9E6vv/ROr7 + /0Tq+/9E6vv/ROr7/0Tq+/9E6vv/ROr7/0Tq+/9E6vv/ROr7/0Tq+/9E6vv/ROr7/0Tq+/9E6vv/ROr7 + /0Tq+/9E6vv/AFuv/1SDvcL+y8tU/8vLAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//RO38 + /0Tt/P9E7fz/RO38/0Tt/P9E7fz/RO38/0Tt/P9E7fz/RO38/0Tt/P9E7fz/RO38/0Tt/P9E7fz/RO38 + /0Tt/P9E7fz/RO38/0Tt/P8AW6//VIO9wv7Ly1X+y8sF/8zMA/7LywP+y8sD/svLA/7LywP+y8sD/8zM + AwBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/9mir25/svLb/7Ly1X/zMxU/svLVP7Ly1T+y8tU/svL + VP7Ly1T/zMxUxrLFi6qmwqaqpsKmqqbCpqqmwqaqpsKmqaXBpqmlwaappcGmqaXBpqmlwaappcGmqaXB + pqmlwaappcGmqaXBpqmlwaappcGmqaXBpqmlwaappcGmqaXBpta5xpIAAAAAP8AAPj/AAD4/wAA+P8AA + Pj/AAD4AAAA+AAAAPgAAAD4AAAA+AAAAPgAAAD4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAAAAAAAAAAAACgAAAAQAAAAIAAA + AAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tB/svLHv7Lyx7+y8se/svLHp1qanCYZWWjmGVl + o5hlZaOYZWWjmGVlo5hlZaOYZWV4/svLHv7Lyx7+y8s5/svLLAAAAAAAAAAAAAAAAAAAAABmMzP/ZjMz + /2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/wAAAAAAAAAA/svLHv7LyywAAAAAAAAAAAAAAAAAAAAAZjMz + /61NAP+tTQD/rU0A/61NAP+tTQD/rU0A/2YzM/8AAAAAAAAAAP7Lyx4AM6H/ADOh/wAzof8AM6H/ADOh + /2YzM/+5XQD/uV0A/7ldAP+5XQD/uV0A/7ldAP9mMzP/AAAAAAAAAAD+y8seADOh/wA3q/8AN6v/ADer + /wAzof9mMzP/xWwA/8VsAP/FbAD/xWwA/8VsAP/FbAD/ZjMz/wAAAAAAAAAA/svLHgAzof8APLb/ADy2 + /wA8tv8AM6H/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/8AAAAAAAAAAP7Lyx4AM6H/AEHB + /wBBwf8AQcH/ADOh/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//ADOh + /wBGzP8ARsz/AEbM/wAzof9IvOX/SLzl/0i85f9IvOX/SLzl/0i85f9IvOX/SLzl/0i85f9IvOX/AFuv + /wAzof8AS9f/AEvX/wBL1/8AM6H/R8Lo/0fC6P9Hwuj/R8Lo/0fC6P9Hwuj/R8Lo/0fC6P9Hwuj/R8Lo + /wBbr/8AM6H/ADOh/wAzof8AM6H/ADOh/0fJ6/9Hyev/R8nr/0fJ6/9Hyev/R8nr/0fJ6/9Hyev/R8nr + /0fJ6/8AW6///8zMLAAAAAAAAAAAAAAAAABbr/9G0O7/RtDu/0bQ7v9G0O7/RtDu/0bQ7v9G0O7/RtDu + /0bQ7v9G0O7/AFuv///MzCwAAAAAAAAAAAAAAAAAW6//Rtfy/0bX8v9G1/L/Rtfy/0bX8v9G1/L/Rtfy + /0bX8v9G1/L/Rtfy/wBbr//+y8ssAAAAAAAAAAAAAAAAAFuv/0Xd9f9F3fX/Rd31/0Xd9f9F3fX/Rd31 + /0Xd9f9F3fX/Rd31/0Xd9f8AW6///svLLAAAAAAAAAAAAAAAAABbr/9F5Pj/ReT4/0Xk+P9F5Pj/ReT4 + /0Xk+P9F5Pj/ReT4/0Xk+P9F5Pj/AFuv//7LyywAAAAAAAAAAAAAAAAAW6//ROv7/0Tr+/9E6/v/ROv7 + /0Tr+/9E6/v/ROv7/0Tr+/9E6/v/ROv7/wBbr//+y8tI/svLLP7Lyyz+y8ssAFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AACsQXgGrEF4BqxBAAasQQAGrEEABqxBAACs + QQAArEEAAKxBAACsQXAArEFwAKxBcACsQXAArEFwAKxBAACsQQ== + + + \ No newline at end of file diff --git a/branches/ph-plugins/ExtraTools/NtProfiler/Program.cs b/branches/ph-plugins/ExtraTools/NtProfiler/Program.cs new file mode 100644 index 000000000..372899312 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/NtProfiler/Program.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Windows.Forms; + +namespace NtProfiler +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new ProfilerWindow()); + } + } +} diff --git a/branches/ph-plugins/ExtraTools/NtProfiler/Properties/AssemblyInfo.cs b/branches/ph-plugins/ExtraTools/NtProfiler/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..54c29984e --- /dev/null +++ b/branches/ph-plugins/ExtraTools/NtProfiler/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("NtProfiler")] +[assembly: AssemblyDescription("NtProfiler")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("wj32")] +[assembly: AssemblyProduct("NtProfiler")] +[assembly: AssemblyCopyright("Copyright © 2009 wj32. Licensed under the GNU GPL, v3.")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("ad8532b1-3718-4e5d-904a-54085eb45e77")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/branches/ph-plugins/ExtraTools/NtProfiler/Properties/Resources.Designer.cs b/branches/ph-plugins/ExtraTools/NtProfiler/Properties/Resources.Designer.cs new file mode 100644 index 000000000..72cdade61 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/NtProfiler/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.4016 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace NtProfiler.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("NtProfiler.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/branches/ph-plugins/ExtraTools/NtProfiler/Properties/Resources.resx b/branches/ph-plugins/ExtraTools/NtProfiler/Properties/Resources.resx new file mode 100644 index 000000000..ffecec851 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/NtProfiler/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ExtraTools/NtProfiler/Properties/Settings.Designer.cs b/branches/ph-plugins/ExtraTools/NtProfiler/Properties/Settings.Designer.cs new file mode 100644 index 000000000..6fa45666e --- /dev/null +++ b/branches/ph-plugins/ExtraTools/NtProfiler/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.4016 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace NtProfiler.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/branches/ph-plugins/ExtraTools/NtProfiler/Properties/Settings.settings b/branches/ph-plugins/ExtraTools/NtProfiler/Properties/Settings.settings new file mode 100644 index 000000000..abf36c5d3 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/NtProfiler/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/branches/ph-plugins/ExtraTools/NtProfiler/app.config b/branches/ph-plugins/ExtraTools/NtProfiler/app.config new file mode 100644 index 000000000..b7db28170 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/NtProfiler/app.config @@ -0,0 +1,3 @@ + + + diff --git a/branches/ph-plugins/ExtraTools/NtProfiler/app.manifest b/branches/ph-plugins/ExtraTools/NtProfiler/app.manifest new file mode 100644 index 000000000..25c0371c1 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/NtProfiler/app.manifest @@ -0,0 +1,22 @@ + + + + + + + + + + + + diff --git a/branches/ph-plugins/ExtraTools/ProcessAnalyzer/MainWindow.Designer.cs b/branches/ph-plugins/ExtraTools/ProcessAnalyzer/MainWindow.Designer.cs new file mode 100644 index 000000000..0207b7b86 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/ProcessAnalyzer/MainWindow.Designer.cs @@ -0,0 +1,353 @@ +namespace ProcessAnalyzer +{ + partial class MainWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainWindow)); + this.menuStrip = new System.Windows.Forms.MenuStrip(); + this.analyzerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.openProcessToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator(); + this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.tabControl = new System.Windows.Forms.TabControl(); + this.tabHandleTracing = new System.Windows.Forms.TabPage(); + this.listHandleStack = new System.Windows.Forms.ListView(); + this.columnAddress = new System.Windows.Forms.ColumnHeader(); + this.columnSymbol = new System.Windows.Forms.ColumnHeader(); + this.listHandleTraces = new System.Windows.Forms.ListView(); + this.columnIndex = new System.Windows.Forms.ColumnHeader(); + this.columnHandle = new System.Windows.Forms.ColumnHeader(); + this.columnType = new System.Windows.Forms.ColumnHeader(); + this.columnTid = new System.Windows.Forms.ColumnHeader(); + this.columnHandleName = new System.Windows.Forms.ColumnHeader(); + this.buttonSnapshot = new System.Windows.Forms.Button(); + this.buttonDisableHandleTracing = new System.Windows.Forms.Button(); + this.buttonEnableHandleTracing = new System.Windows.Forms.Button(); + this.tabHiddenObjects = new System.Windows.Forms.TabPage(); + this.labelObjectsScanProgress = new System.Windows.Forms.Label(); + this.buttonScanHiddenObjects = new System.Windows.Forms.Button(); + this.listHiddenObjects = new System.Windows.Forms.ListView(); + this.columnObjectType = new System.Windows.Forms.ColumnHeader(); + this.columnObjectId = new System.Windows.Forms.ColumnHeader(); + this.columnObjectInfo = new System.Windows.Forms.ColumnHeader(); + this.menuStrip.SuspendLayout(); + this.tabControl.SuspendLayout(); + this.tabHandleTracing.SuspendLayout(); + this.tabHiddenObjects.SuspendLayout(); + this.SuspendLayout(); + // + // menuStrip + // + this.menuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.analyzerToolStripMenuItem}); + this.menuStrip.Location = new System.Drawing.Point(0, 0); + this.menuStrip.Name = "menuStrip"; + this.menuStrip.Size = new System.Drawing.Size(695, 24); + this.menuStrip.TabIndex = 0; + this.menuStrip.Text = "menuStrip1"; + // + // analyzerToolStripMenuItem + // + this.analyzerToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.openProcessToolStripMenuItem, + this.toolStripMenuItem1, + this.exitToolStripMenuItem}); + this.analyzerToolStripMenuItem.Name = "analyzerToolStripMenuItem"; + this.analyzerToolStripMenuItem.Size = new System.Drawing.Size(64, 20); + this.analyzerToolStripMenuItem.Text = "Analyzer"; + // + // openProcessToolStripMenuItem + // + this.openProcessToolStripMenuItem.Name = "openProcessToolStripMenuItem"; + this.openProcessToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.O))); + this.openProcessToolStripMenuItem.Size = new System.Drawing.Size(198, 22); + this.openProcessToolStripMenuItem.Text = "&Open Process..."; + this.openProcessToolStripMenuItem.Click += new System.EventHandler(this.openProcessToolStripMenuItem_Click); + // + // toolStripMenuItem1 + // + this.toolStripMenuItem1.Name = "toolStripMenuItem1"; + this.toolStripMenuItem1.Size = new System.Drawing.Size(195, 6); + // + // exitToolStripMenuItem + // + this.exitToolStripMenuItem.Name = "exitToolStripMenuItem"; + this.exitToolStripMenuItem.Size = new System.Drawing.Size(198, 22); + this.exitToolStripMenuItem.Text = "E&xit"; + this.exitToolStripMenuItem.Click += new System.EventHandler(this.exitToolStripMenuItem_Click); + // + // tabControl + // + this.tabControl.Controls.Add(this.tabHandleTracing); + this.tabControl.Controls.Add(this.tabHiddenObjects); + this.tabControl.Dock = System.Windows.Forms.DockStyle.Fill; + this.tabControl.Location = new System.Drawing.Point(0, 24); + this.tabControl.Name = "tabControl"; + this.tabControl.SelectedIndex = 0; + this.tabControl.Size = new System.Drawing.Size(695, 469); + this.tabControl.TabIndex = 1; + // + // tabHandleTracing + // + this.tabHandleTracing.Controls.Add(this.listHandleStack); + this.tabHandleTracing.Controls.Add(this.listHandleTraces); + this.tabHandleTracing.Controls.Add(this.buttonSnapshot); + this.tabHandleTracing.Controls.Add(this.buttonDisableHandleTracing); + this.tabHandleTracing.Controls.Add(this.buttonEnableHandleTracing); + this.tabHandleTracing.Location = new System.Drawing.Point(4, 22); + this.tabHandleTracing.Name = "tabHandleTracing"; + this.tabHandleTracing.Padding = new System.Windows.Forms.Padding(3); + this.tabHandleTracing.Size = new System.Drawing.Size(687, 443); + this.tabHandleTracing.TabIndex = 0; + this.tabHandleTracing.Text = "Handle Tracing"; + this.tabHandleTracing.UseVisualStyleBackColor = true; + // + // listHandleStack + // + this.listHandleStack.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listHandleStack.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnAddress, + this.columnSymbol}); + this.listHandleStack.FullRowSelect = true; + this.listHandleStack.HideSelection = false; + this.listHandleStack.Location = new System.Drawing.Point(6, 226); + this.listHandleStack.MultiSelect = false; + this.listHandleStack.Name = "listHandleStack"; + this.listHandleStack.Size = new System.Drawing.Size(675, 211); + this.listHandleStack.TabIndex = 1; + this.listHandleStack.UseCompatibleStateImageBehavior = false; + this.listHandleStack.View = System.Windows.Forms.View.Details; + // + // columnAddress + // + this.columnAddress.Text = "Address"; + this.columnAddress.Width = 100; + // + // columnSymbol + // + this.columnSymbol.Text = "Symbol"; + this.columnSymbol.Width = 300; + // + // listHandleTraces + // + this.listHandleTraces.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listHandleTraces.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnIndex, + this.columnHandle, + this.columnType, + this.columnTid, + this.columnHandleName}); + this.listHandleTraces.FullRowSelect = true; + this.listHandleTraces.HideSelection = false; + this.listHandleTraces.Location = new System.Drawing.Point(6, 35); + this.listHandleTraces.MultiSelect = false; + this.listHandleTraces.Name = "listHandleTraces"; + this.listHandleTraces.Size = new System.Drawing.Size(675, 185); + this.listHandleTraces.TabIndex = 1; + this.listHandleTraces.UseCompatibleStateImageBehavior = false; + this.listHandleTraces.View = System.Windows.Forms.View.Details; + this.listHandleTraces.SelectedIndexChanged += new System.EventHandler(this.listHandleTraces_SelectedIndexChanged); + // + // columnIndex + // + this.columnIndex.Text = "Index"; + // + // columnHandle + // + this.columnHandle.Text = "Handle"; + // + // columnType + // + this.columnType.Text = "Type"; + this.columnType.Width = 120; + // + // columnTid + // + this.columnTid.Text = "TID"; + // + // columnHandleName + // + this.columnHandleName.Text = "Handle Name"; + this.columnHandleName.Width = 300; + // + // buttonSnapshot + // + this.buttonSnapshot.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonSnapshot.Location = new System.Drawing.Point(168, 6); + this.buttonSnapshot.Name = "buttonSnapshot"; + this.buttonSnapshot.Size = new System.Drawing.Size(75, 23); + this.buttonSnapshot.TabIndex = 0; + this.buttonSnapshot.Text = "Snapshot"; + this.buttonSnapshot.UseVisualStyleBackColor = true; + this.buttonSnapshot.Click += new System.EventHandler(this.buttonSnapshot_Click); + // + // buttonDisableHandleTracing + // + this.buttonDisableHandleTracing.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonDisableHandleTracing.Location = new System.Drawing.Point(87, 6); + this.buttonDisableHandleTracing.Name = "buttonDisableHandleTracing"; + this.buttonDisableHandleTracing.Size = new System.Drawing.Size(75, 23); + this.buttonDisableHandleTracing.TabIndex = 0; + this.buttonDisableHandleTracing.Text = "Disable"; + this.buttonDisableHandleTracing.UseVisualStyleBackColor = true; + this.buttonDisableHandleTracing.Click += new System.EventHandler(this.buttonDisableHandleTracing_Click); + // + // buttonEnableHandleTracing + // + this.buttonEnableHandleTracing.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonEnableHandleTracing.Location = new System.Drawing.Point(6, 6); + this.buttonEnableHandleTracing.Name = "buttonEnableHandleTracing"; + this.buttonEnableHandleTracing.Size = new System.Drawing.Size(75, 23); + this.buttonEnableHandleTracing.TabIndex = 0; + this.buttonEnableHandleTracing.Text = "Enable"; + this.buttonEnableHandleTracing.UseVisualStyleBackColor = true; + this.buttonEnableHandleTracing.Click += new System.EventHandler(this.buttonEnableHandleTracing_Click); + // + // tabHiddenObjects + // + this.tabHiddenObjects.Controls.Add(this.labelObjectsScanProgress); + this.tabHiddenObjects.Controls.Add(this.buttonScanHiddenObjects); + this.tabHiddenObjects.Controls.Add(this.listHiddenObjects); + this.tabHiddenObjects.Location = new System.Drawing.Point(4, 22); + this.tabHiddenObjects.Name = "tabHiddenObjects"; + this.tabHiddenObjects.Padding = new System.Windows.Forms.Padding(3); + this.tabHiddenObjects.Size = new System.Drawing.Size(687, 443); + this.tabHiddenObjects.TabIndex = 1; + this.tabHiddenObjects.Text = "Hidden Objects"; + this.tabHiddenObjects.UseVisualStyleBackColor = true; + // + // labelObjectsScanProgress + // + this.labelObjectsScanProgress.AutoSize = true; + this.labelObjectsScanProgress.Location = new System.Drawing.Point(87, 11); + this.labelObjectsScanProgress.Name = "labelObjectsScanProgress"; + this.labelObjectsScanProgress.Size = new System.Drawing.Size(41, 13); + this.labelObjectsScanProgress.TabIndex = 4; + this.labelObjectsScanProgress.Text = "Ready."; + // + // buttonScanHiddenObjects + // + this.buttonScanHiddenObjects.Enabled = false; + this.buttonScanHiddenObjects.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonScanHiddenObjects.Location = new System.Drawing.Point(6, 6); + this.buttonScanHiddenObjects.Name = "buttonScanHiddenObjects"; + this.buttonScanHiddenObjects.Size = new System.Drawing.Size(75, 23); + this.buttonScanHiddenObjects.TabIndex = 3; + this.buttonScanHiddenObjects.Text = "Scan"; + this.buttonScanHiddenObjects.UseVisualStyleBackColor = true; + this.buttonScanHiddenObjects.Click += new System.EventHandler(this.buttonScanHiddenObjects_Click); + // + // listHiddenObjects + // + this.listHiddenObjects.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listHiddenObjects.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnObjectType, + this.columnObjectId, + this.columnObjectInfo}); + this.listHiddenObjects.FullRowSelect = true; + this.listHiddenObjects.HideSelection = false; + this.listHiddenObjects.Location = new System.Drawing.Point(6, 35); + this.listHiddenObjects.MultiSelect = false; + this.listHiddenObjects.Name = "listHiddenObjects"; + this.listHiddenObjects.Size = new System.Drawing.Size(675, 402); + this.listHiddenObjects.TabIndex = 2; + this.listHiddenObjects.UseCompatibleStateImageBehavior = false; + this.listHiddenObjects.View = System.Windows.Forms.View.Details; + // + // columnObjectType + // + this.columnObjectType.Text = "Type"; + this.columnObjectType.Width = 100; + // + // columnObjectId + // + this.columnObjectId.Text = "ID"; + // + // columnObjectInfo + // + this.columnObjectInfo.Text = "Information"; + this.columnObjectInfo.Width = 300; + // + // MainWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(695, 493); + this.Controls.Add(this.tabControl); + this.Controls.Add(this.menuStrip); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MainMenuStrip = this.menuStrip; + this.Name = "MainWindow"; + this.Text = "Process Analyzer"; + this.menuStrip.ResumeLayout(false); + this.menuStrip.PerformLayout(); + this.tabControl.ResumeLayout(false); + this.tabHandleTracing.ResumeLayout(false); + this.tabHiddenObjects.ResumeLayout(false); + this.tabHiddenObjects.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.MenuStrip menuStrip; + private System.Windows.Forms.ToolStripMenuItem analyzerToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem openProcessToolStripMenuItem; + private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1; + private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem; + private System.Windows.Forms.TabControl tabControl; + private System.Windows.Forms.TabPage tabHandleTracing; + private System.Windows.Forms.Button buttonDisableHandleTracing; + private System.Windows.Forms.Button buttonEnableHandleTracing; + private System.Windows.Forms.Button buttonSnapshot; + private System.Windows.Forms.ListView listHandleTraces; + private System.Windows.Forms.ColumnHeader columnHandle; + private System.Windows.Forms.ColumnHeader columnType; + private System.Windows.Forms.ColumnHeader columnTid; + private System.Windows.Forms.ListView listHandleStack; + private System.Windows.Forms.ColumnHeader columnAddress; + private System.Windows.Forms.ColumnHeader columnSymbol; + private System.Windows.Forms.ColumnHeader columnHandleName; + private System.Windows.Forms.ColumnHeader columnIndex; + private System.Windows.Forms.TabPage tabHiddenObjects; + private System.Windows.Forms.ListView listHiddenObjects; + private System.Windows.Forms.ColumnHeader columnObjectType; + private System.Windows.Forms.ColumnHeader columnObjectId; + private System.Windows.Forms.ColumnHeader columnObjectInfo; + private System.Windows.Forms.Button buttonScanHiddenObjects; + private System.Windows.Forms.Label labelObjectsScanProgress; + } +} + diff --git a/branches/ph-plugins/ExtraTools/ProcessAnalyzer/MainWindow.cs b/branches/ph-plugins/ExtraTools/ProcessAnalyzer/MainWindow.cs new file mode 100644 index 000000000..589a54aff --- /dev/null +++ b/branches/ph-plugins/ExtraTools/ProcessAnalyzer/MainWindow.cs @@ -0,0 +1,314 @@ +using System; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Common.Ui; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; +using ProcessHacker.Native.Symbols; +using ProcessHacker.Native.Ui; + +namespace ProcessAnalyzer +{ + public partial class MainWindow : Form + { + private int _pid; + + public MainWindow() + { + InitializeComponent(); + + try + { + KProcessHacker.Instance = new KProcessHacker(); + } + catch + { } + + Win32.LoadLibrary("C:\\Program Files\\Debugging Tools for Windows (x86)\\dbghelp.dll"); + + listHandleTraces.ListViewItemSorter = new SortedListViewComparer(listHandleTraces); + } + + private void openProcessToolStripMenuItem_Click(object sender, EventArgs e) + { + this.ChooseProcess(); + } + + private void exitToolStripMenuItem_Click(object sender, EventArgs e) + { + this.Close(); + } + + private void ShowException(string operation, Exception ex) + { + MessageBox.Show(operation + ": " + ex.Message, "Process Analyzer", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + + #region Handle Tracing + + private SymbolProvider _symbols; + private ProcessHandleTraceCollection _currentHtCollection; + + private void ChooseProcess() + { + ChooseProcessDialog cpd = new ChooseProcessDialog(); + + if (cpd.ShowDialog() == DialogResult.OK) + _pid = cpd.SelectedPid; + } + + private void PopulateHandleTraceList() + { + listHandleTraces.BeginUpdate(); + listHandleTraces.Items.Clear(); + + for (int i = 0; i < _currentHtCollection.Count; i++) + { + var trace = _currentHtCollection[i]; + ListViewItem item = new ListViewItem( + new string[] + { + i.ToString(), + "0x" + trace.Handle.ToString("x"), + trace.Type.ToString(), + trace.ClientId.ThreadId.ToString() + }); + + item.Tag = i; + listHandleTraces.Items.Add(item); + } + + listHandleTraces.EndUpdate(); + } + + private void buttonEnableHandleTracing_Click(object sender, EventArgs e) + { + try + { + using (var phandle = new ProcessHandle(_pid, ProcessAccess.SetInformation)) + phandle.EnableHandleTracing(); + } + catch (Exception ex) + { + this.ShowException("Error enabling handle tracing", ex); + } + } + + private void buttonDisableHandleTracing_Click(object sender, EventArgs e) + { + try + { + using (var phandle = new ProcessHandle(_pid, ProcessAccess.SetInformation)) + phandle.DisableHandleTracing(); + } + catch (Exception ex) + { + this.ShowException("Error disabling handle tracing", ex); + } + } + + private void buttonSnapshot_Click(object sender, EventArgs e) + { + try + { + using (var phandle = new ProcessHandle(_pid, ProcessAccess.QueryInformation | ProcessAccess.VmRead)) + { + _currentHtCollection = phandle.GetHandleTraces(); + + if (_symbols != null) + _symbols.Dispose(); + + SymbolProvider.Options |= SymbolOptions.DeferredLoads; + _symbols = new SymbolProvider(phandle); + + WorkQueue.GlobalQueueWorkItem(new Action(() => + { + var symbols = _symbols; + + _symbols.PreloadModules = true; + + try + { + foreach (var module in phandle.GetModules()) + { + try + { + symbols.LoadModule(module.FileName, module.BaseAddress); + } + catch + { } + } + } + catch + { } + + try + { + foreach (var module in Windows.GetKernelModules()) + { + try + { + symbols.LoadModule(module.FileName, module.BaseAddress); + } + catch + { } + } + } + catch + { } + })); + } + + this.PopulateHandleTraceList(); + } + catch (Exception ex) + { + this.ShowException("Error getting the handle trace snapshot", ex); + } + } + + private void listHandleTraces_SelectedIndexChanged(object sender, EventArgs e) + { + if (_currentHtCollection == null || listHandleTraces.SelectedItems.Count != 1) + return; + + var trace = _currentHtCollection[(int)listHandleTraces.SelectedItems[0].Tag]; + + listHandleStack.BeginUpdate(); + listHandleStack.Items.Clear(); + + foreach (var address in trace.Stack) + { + ListViewItem item = new ListViewItem(); + + item.Text = "0x" + address.ToInt32().ToString("x8"); + item.SubItems.Add(new ListViewItem.ListViewSubItem(item, _symbols.GetSymbolFromAddress(address.ToUInt64()))); + listHandleStack.Items.Add(item); + } + + listHandleStack.EndUpdate(); + } + + #endregion + + #region Hidden Objects + + private struct KVars + { + public IntPtr NonPagedPoolStartAddress; + public IntPtr NonPagedPoolSizeAddress; + public IntPtr NonPagedPoolStart; + public uint NonPagedPoolSize; + public IntPtr PsProcessTypeAddress; + public IntPtr PsProcessType; + public IntPtr PsThreadTypeAddress; + public IntPtr PsThreadType; + } + + private unsafe KVars GetKVars() + { + SymbolProvider symbols = new SymbolProvider(); + + symbols.LoadModule(Windows.KernelFileName, Windows.KernelBase); + + KVars vars = new KVars(); + + vars.NonPagedPoolStartAddress = symbols.GetSymbolFromName("MmNonPagedPoolStart").Address.ToIntPtr(); + vars.NonPagedPoolSizeAddress = symbols.GetSymbolFromName("MmMaximumNonPagedPoolInBytes").Address.ToIntPtr(); + vars.PsProcessTypeAddress = symbols.GetSymbolFromName("PsProcessType").Address.ToIntPtr(); + vars.PsThreadTypeAddress = symbols.GetSymbolFromName("PsThreadType").Address.ToIntPtr(); + + int bytesRead; + + KProcessHacker.Instance.KphReadVirtualMemoryUnsafe( + ProcessHandle.Current, + vars.NonPagedPoolStartAddress.ToInt32(), + &vars.NonPagedPoolStart, + IntPtr.Size, + out bytesRead + ); + KProcessHacker.Instance.KphReadVirtualMemoryUnsafe( + ProcessHandle.Current, + vars.NonPagedPoolSizeAddress.ToInt32(), + &vars.NonPagedPoolSize, + sizeof(uint), + out bytesRead + ); + KProcessHacker.Instance.KphReadVirtualMemoryUnsafe( + ProcessHandle.Current, + vars.PsProcessTypeAddress.ToInt32(), + &vars.PsProcessType, + IntPtr.Size, + out bytesRead + ); + KProcessHacker.Instance.KphReadVirtualMemoryUnsafe( + ProcessHandle.Current, + vars.PsThreadTypeAddress.ToInt32(), + &vars.PsThreadType, + IntPtr.Size, + out bytesRead + ); + + symbols.Dispose(); + + return vars; + } + + private unsafe void ScanHiddenObjects() + { + KVars vars = this.GetKVars(); + int bytesRead; + + throw new NotSupportedException(); + + listHiddenObjects.Items.Clear(); + + using (var currentPage = new MemoryAlloc(Windows.PageSize)) + { + for ( + IntPtr address = vars.NonPagedPoolStart; + address.CompareTo(vars.NonPagedPoolStart.Increment(vars.NonPagedPoolSize)) == -1; + address = address.Increment(Windows.PageSize) + ) + { + try + { + KProcessHacker.Instance.KphReadVirtualMemoryUnsafe( + ProcessHandle.Current, + address.ToInt32(), + (IntPtr)currentPage, + Windows.PageSize, + out bytesRead + ); + } + catch + { + continue; + } + + for ( + IntPtr inner = address; + inner.CompareTo(address.Increment(Windows.PageSize)) == -1; + inner = inner.Increment(8) + ) + { + } + + labelObjectsScanProgress.Text = string.Format("Scanned 0x{0:x8}", address.ToInt32()); + Application.DoEvents(); + } + } + + labelObjectsScanProgress.Text = "Finished."; + } + + private void buttonScanHiddenObjects_Click(object sender, EventArgs e) + { + this.ScanHiddenObjects(); + } + + #endregion + } +} diff --git a/branches/ph-plugins/ExtraTools/ProcessAnalyzer/MainWindow.resx b/branches/ph-plugins/ExtraTools/ProcessAnalyzer/MainWindow.resx new file mode 100644 index 000000000..0a2236b3e --- /dev/null +++ b/branches/ph-plugins/ExtraTools/ProcessAnalyzer/MainWindow.resx @@ -0,0 +1,912 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + + + AAABAA8AMDAQAAEABABoBgAA9gAAACAgEAABAAQA6AIAAF4HAAAQEBAAAQAEACgBAABGCgAAAAAAAAEA + CABqDQAAbgsAADAwAAABAAgAqA4AANgYAAAgIAAAAQAIAKgIAACAJwAAEBAAAAEACABoBQAAKDAAAAAA + AAABABgAOQ0AAJA1AAAwMAAAAQAYAKgcAADJQgAAICAAAAEAGACoDAAAcV8AABAQAAABABgAaAMAABls + AAAAAAAAAQAgAHANAACBbwAAMDAAAAEAIACoJQAA8XwAACAgAAABACAAqBAAAJmiAAAQEAAAAQAgAGgE + AABBswAAKAAAADAAAABgAAAAAQAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAIAAAACA + gACAAAAAgACAAICAAACAgIAAAAD/AAD/AAAA//8A/wAAAP8A/wD//wAAwMDAAP///wDwAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFRGVGVlZGVkdGVlAAAA + AAAAAAAAAAAAAFZGtkZLa2Rka0a0AAAAAAAAAAAAAAAAAGtka2tka2trZkZHAAAAAAAAAAAAAAAAAGRr + a2tmtmtra2tkAAAAAAAAAAAAAAAAAFZrZma2a2a2a2tnAAAAAAAAAAAAAAAAAEa2a2tra2tra2ZkAAAA + AAAAAAAAAAAAAGa2trZra2a2a2tlAAAAAAAAAAAAAAAAAHa2bbZrZttmtmtmAAAAAAABODE4ExgxAFa2 + tra2tra2tmtlAAAAAAABgxg4E4OBAEZrZrZr1rZr29tmAAAAAAADgTETgxMTAHvWvb22tmvba2tlAAAA + AAADE4ODgxg4AGRr272729tr29vUAAAAAAAIE4MTgTgxAF2729vb22bb29tnAAAAAAABODg4ODgxAEbb + 29vb29u2vb22AAAAAAADg4ODg4ODAEZmZmZmZm1mZmZlAAAAAAABODg4ODg4AHR2VlZWR1ZHRlZWAAAA + AAAIODg4ODg4AAAAAAAAAAAAAAAAAAAAAAADg4ODg4ODM4ODiDiDg4ODg4OIOIODg44BODiDioOBiuiu + p6euinqK6K6np66o6j4BioODg4ODOurqjq6nrq6urqeup3qK6h4Dg4OKg4ODjoruqK6o6o6o6uqOqurq + 6o4Bg4ODiDg4Oq6orqeup66np6iuqOqOqD4Dg4qIOKg4h6eup66Kenp6eurqeup66j4Biog4qDiDPqen + p66urq6np66K6np6eo4DiKg4OKiBiq6nrqiuqKeup6p6enp66j4Bg4OIODgzOup66nrqeup6eurqenrq + eo4BMRMTgTGBh66orqenp6rorop66np66j4AAAAAAAAAOup66np66nrqrqrqenrqeo4AAAAAAAAAinp6 + eup6enrqeurqeup66j4AAAAAAAAAPqrq6qeq6up6euqK6q6uqh4AAAAAAAAAiup6eup6eqeup66urqiu + 6j4AAAAAAAAAOup66np66n6qeqeqenrqqo4AAAAAAAAAGq6q6q6q6qrq6urqrqrq6j4AAAAAAAAAPq6u + qurq6urq6uqurq6q6o4AAAAAAAAAiq6q6uqq6q6qququqq6q6j4AAAAAAAAAOuqurqrq6uqurq6urq6u + ro4AAAAAAAAAiurqqurq6q6urqrqrqquqj4AAAAAAAAAPq6q6urqququqq6q6q6uro4AAAAAAAAAOqrq + 6qqurq6q6urqrq6q6j4AAAAAAAAAOurqqurqrqququqq6uquqj4AAAAAAAAAiuqurqrqrq6q6q6uqq6q + 6o4AAAAAAAAAOuququrqrqrq6q6q6uquqn4AAAAAAAAAeq6uququrqrqrq6q6q6uqo4AAAAAAAAAOq6q + rqquqq6qrqquqq6qrj4AAAAAAAAAgzODM4MzgzODM4MzgzODMT8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AA9///////4AAP///////wAA//8AAAP/AAD//wAAA/8AAP//AAAD/wAA//8AAAP/AAD//wAAA/8AAP// + AAAD/wAA//8AAAP/AAD//wAAA/8AAIADAAAD/wAAgAMAAAP/AACAAwAAA/8AAIADAAAD/wAAgAMAAAP/ + AACAAwAAA/8AAIADAAAD/wAAgAMAAAP/AACAA/////8AAIAAAAAAAAAAgAAAAAAAAACAAAAAAAAAAIAA + AAAAAAAAgAAAAAAAAACAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAACAAAAAAAAAAIAAAAAAAAAA//wAAAAA + AAD//AAAAAAAAP/8AAAAAAAA//wAAAAAAAD//AAAAAAAAP/8AAAAAAAA//wAAAAAAAD//AAAAAAAAP/8 + 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 + Hx8fHx8fHx8fGwAAARQXFxcXFxcXFxcXFxcXFxcXFxcXAQAAAAAAAAAAAAAAGyAhISEhISEhISEgGwAA + ARYZGRkZGRkZGRkZGRkZGRkZGRkZAQAAAAAAAAAAAAAAGyEhISEhISEhISEhGwAAARgaGhoaGhoaGhoa + GhoaGhoaGhoaAQAAAAAAAAAAAAAAGyIiIyIjIyIjIyMiGwAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAA + AAAAAAAAAAAAGyUlJSUlJSUlJSUlGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGyYm + JiYmJiYmJiYmGyQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJEIAGyYnJygnKCcoJycnHCQv + Ly8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vJEEAGygpKSkpKSkpKSkpHCQwLzAwMDAwMDAwMDAw + MDAwMDAwMDAwMDAwMDAwMDAvJEEAGykrKiorKisqKyoqHCQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw + MDAwMDAwJEEAGyosLCwsLCwsLCwsGyQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwJEEAGywt + LS0tLS0tLS0tHCQxMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExJEEAGy0uLi4uLi4uLi4uHCQy + MjIxMjEyMTIxMjEyMTIxMjEyMTIxMjEyMTIxMjEyJEEAGy4uLi4uLi4uLi4uGyQyMjIyMjIyMjIyMjIy + MjIyMjIyMjIyMjIyMjIyMjIyJEEAGyorKysrKysrKysrGyQzMzQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0 + NDQ0NDQzJEEAGxsbGxsbGxsbGxsbHCQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDU0JEEAAAAA + AAAAAAAAAAAAACQ1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1JEEAAAAAAAAAAAAAAAAAACQ1 + NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1JEEAAAAAAAAAAAAAAAAAACQ2Njc3Nzc3Nzc3Nzc3 + Nzc3Nzc3Nzc3Nzc3Nzc3NzY2JEEAAAAAAAAAAAAAAAAAACQ3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3 + Nzc3Nzg3JEEAAAAAAAAAAAAAAAAAACQ4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4JEEAAAAA + AAAAAAAAAAAAACQ4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4JEEAAAAAAAAAAAAAAAAAACQ5 + OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5JEEAAAAAAAAAAAAAAAAAACQ6Ojo6Ojo6Ojo6Ojo6 + Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6JEEAAAAAAAAAAAAAAAAAACQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7 + Ozs7Ozs7JEEAAAAAAAAAAAAAAAAAACQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7JEEAAAAA + AAAAAAAAAAAAACQ8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8JEEAAAAAAAAAAAAAAAAAACQ9 + PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09JEEAAAAAAAAAAAAAAAAAACQ9PT09PT09PT09PT09 + PT09PT09PT09PT09PT09PT09JEEAAAAAAAAAAAAAAAAAACQ+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+ + Pj4+Pj4+JEEAAAAAAAAAAAAAAAAAACQ/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/JEEAAAAA + AAAAAAAAAAAAACQ/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/JEEAAAAAAAAAAAAAAAAAACRA + QEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAJEEAAAAAAAAAAAAAAAAAACQkJCQkJCQkJCQkJCQk + JCQkJCQkJCQkJCQkJCQkJCQkJEMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAER///////4O7v///////w7u//8AAAP/Du7//wAAA/8O7v//AAAD/w7u//8AAAP/Du7//wAA + A/8O7v//AAAD/w7u//8AAAP/Du7//wAAA/8O7oADAAAD/w7ugAMAAAP/Du6AAwAAA/8O7oADAAAD/w7u + gAMAAAP/Du6AAwAAA/8O7oADAAAD/w7ugAMAAAP/Du6AA/////8O7oAAAAAAAA7ugAAAAAAADu6AAAAA + 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 + HBwcHBwcHBwcHBwcHBwcHBwcEBktCxYWFhYWFgsQHR0dHR0dHR0dHR0dHR0dHR0dHR0QGS0LCwsLCwsL + CxAeHh4eHh4eHh4eHh4eHh4eHh4eHhAZAAAAAAAAAAAAEB8fHx8fHx8fHx8fHx8fHx8fHx8fEBkAAAAA + AAAAAAAQICAgICAgICAgICAgICAgICAgICAQGQAAAAAAAAAAABAhISEhISEhISEhISEhISEhISEhIRAZ + AAAAAAAAAAAAECIiIiIiIiIiIiIiIiIiIiIiIiIiEBkAAAAAAAAAAAAQIyMjIyMjIyMjIyMjIyMjIyMj + IyMQGQAAAAAAAAAAABAkJCQkJCQkJCQkJCQkJCQkJCQkJBAZAAAAAAAAAAAAECUkJSQlJCQkJCQkJCQk + JCQkJCQkEBkAAAAAAAAAAAAQJSUlJSUlJSUlJSUlJSUlJSUlJSUQGQAAAAAAAAAAABAmJiYmJiYmJiYm + JiYmJiYmJiYmJhAZAAAAAAAAAAAAECcnJycnJycnJycnJycnJycnJycnEBkAAAAAAAAAAAAQKCgoKCgo + KCgoKCgoKCgoKCgoKCgQGQAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBArAAAAAAAAAAAALy4u + Li4uLi4uLi4uLi4uLi4uLi4uLjD//////+AAf//gAD//4AA//+AAP//gAD//4AA/AGAAPwAgAD8AIAA/ + ACAAPwAgAD8AP///AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA + /4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAACgAAAAQAAAAIAAAAAEACAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAoj8AAK5OAAC6XQAAr2MPAMZtAACqbEwAsHNMALZ7TACwflQAvINMALKDbwC2h28A + uYxvAL2RbwC2jnQAADerAAA8tgAQUL8AQGi9AABCwgAAR80AEFPEAABM2AAlW8AAQGrDAD6w3wA+tuEA + PrzkAHiGwgB4iMUAcIzKAHiJyQB4jM0AZI3QAHCT2QBftdwAX7neAGCt2ABgstoAR7zmAF+/4QA9wucA + PcjqADzO7QA81O8AO9ryAEfD6QBGyuwAXsLhAEbR7wBG2PIARd/1AEXl+ABE7PwAu7zZALu93ACBuuAA + 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 + ADAAAABgAAAAAQAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7i4gAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7g + 4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAGYzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2Yz + M2YzM2YzM2YzM2YzM2YzM2YzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM5o5A546AJ46AJ46AJ46AJ46AJ46 + AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AGYzMwAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AGYzM54+A6I/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/ + AKI/AGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM6JCA6ZDAKZDAKZDAKZDAKZDAKZDAKZDAKZDAKZDAKZD + AKZDAKZDAKZDAKZDAKZDAKZDAKZDAKZDAKZDAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM6ZHA6pJAKpJ + AKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAGYzMwAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAGYzM6lMA65OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5O + AK5OAK5OAK5OAK5OAK5OAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM61RA7JTALJTALJTALJTALJTALJT + ALJTALJTALJTALJTALJTALJTALJTALJTALJTALJTALJTALJTALJTAGYzMwAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AGYzM7FWA7ZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZ + ALZZAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQAzoQAzoQAzoQAzoQAzoQAz + oQAzoQAzoQAzoQAzoQAzoQAzoQAAAAAAAGYzM7RaA7pdALpdALpdALpdALpdALpdALpdALpdALpdALpd + ALpdALpdALpdALpdALpdALpdALpdALpdALpdAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAzoQA0owA0pAA0pAA0pAA0pAA0pAA0pAA0pAA0pAA0pAA0pAAzoQAAAAAAAGYzM7hfA75iAL5i + AL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAGYzMwAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQA2pwA2qAA2qAA2qAA2qAA2qAA2qAA2qAA2qAA2 + qAA2qAAzoQAAAAAAAGYzM7xkA8JoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJo + AMJoAMJoAMJoAMJoAMJoAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQA3qwA3 + qwA3qwA3qwA3qwA3qwA3qwA3qwA3qwA3qwA3qwAzoQAAAAAAAGYzM8BpA8ZtAMZtAMZtAMZtAMZtAMZt + AMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAGYzMwAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAzoQA5rgA5rwA5rwA5rwA5rwA5rwA5rwA5rwA5rwA5rwA5rwAzoQAAAAAA + AGYzM8NuA8pyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpy + AMpyAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQA6sQA7swA7swA7swA7swA7 + swA7swA7swA7swA7swA7swAzoQAAAAAAAGYzM8dzA853AM53AM53AM53AM53AM53AM53AM53AM53AM53 + AM53AM53AM53AM53AM53AM53AM53AM53AM53AGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAzoQA8tQA8tgA8tgA8tgA8tgA8tgA8tgA8tgA8tgA8tgA8tgAzoQAAAAAAAGYzM8t3A9J8ANJ8 + ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8AGYzMwAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQA9uAA+ugA+ugA+ugA+ugA+ugA+ugA+ugA+ugA+ + ugA+ugAzoQAAAAAAAGYzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2Yz + M2YzM2YzM2YzM2YzM2YzM2YzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQA/vABA + vgBAvgBAvgBAvgBAvgBAvgBAvgBAvgBAvgBAvgAzoQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAzoQBBvwBBwQBBwQBBwQBBwQBBwQBBwQBBwQBBwQBBwQBBwQAzoQBbrwBb + rwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBb + rwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbr7rH3wAAAAAzoQBCwwBDxQBDxQBDxQBDxQBD + xQBDxQBDxQBDxQBDxQBDxQAzoQBbr0i45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei4 + 5Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45ABbr6y8 + 2QAAAAAzoQBExgBFyQBFyQBFyQBFyQBFyQBFyQBFyQBFyQBFyQBFyQAzoQBbr0i65Ui65Ui65Ui65Ui6 + 5Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui6 + 5Ui65Ui65Ui65Ui65Ui65Ui65QBbr6y82QAAAAAzoQBFygBHzABHzABHzABHzABHzABHzABHzABHzABH + zABHzAAzoQBbr0i85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki8 + 5ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85gBbr6y82QAAAAAzoQBHzQBI + 0ABI0ABI0ABI0ABI0ABI0ABI0ABI0ABI0ABI0AAzoQBbr0i/50i/50i/50i/50i/50i/50i/50i/50i/ + 50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/ + 50i/50i/5wBbr6y82QAAAAAzoQBI0QBK1ABK1ABK1ABK1ABK1ABK1ABK1ABK1ABK1ABK1AAzoQBbr0fB + 6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB + 6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6ABbr6y82QAAAAAzoQBK1ABM2ABM2ABM2ABM2ABM + 2ABM2ABM2ABM2ABM2ABM2AAzoQBbr0fD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD + 6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6QBbr6y8 + 2QAAAAAzoQBM2ABN2wBN2wBN2wBN2wBN2wBN2wBN2wBN2wBN2wBN2wAzoQBbr0fF6kfF6kfF6kfF6kfF + 6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF + 6kfF6kfF6kfF6kfF6kfF6kfF6gBbr6y82QAAAAAzoQBGzABIzwBIzwBIzwBIzwBIzwBIzwBIzwBIzwBI + zwBIzwAzoQBbr0fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI + 60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI6wBbr6y82QAAAAAzoQAzoQAz + oQAzoQAzoQAzoQAzoQAzoQAzoQAzoQAzoQAzoQAzoQBbr0fK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK + 7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK + 7EfK7EfK7ABbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0fM + 7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM + 7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7QBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAABbr0bO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO + 7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7gBbr6y8 + 2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0bR70bR70bR70bR70bR + 70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR + 70bR70bR70bR70bR70bR70bR7wBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAABbr0bT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT + 8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8ABbr6y82QAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0bV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV + 8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV + 8kbV8kbV8gBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0bX + 80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX + 80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX8wBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAABbr0ba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba + 9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9ABbr6y8 + 2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Xc9UXc9UXc9UXc9UXc + 9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc + 9UXc9UXc9UXc9UXc9UXc9UXc9QBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAABbr0Xe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe + 9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9gBbr6y82QAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg + 90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg + 90Xg90Xg9wBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Xj + +EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj + +EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+ABbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAABbr0Xl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl + +UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+QBbr6y8 + 2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Xn+kXn+kXn+kXn+kXn + +kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn + +kXn+kXn+kXn+kXn+kXn+kXn+gBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAABbr0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp + +0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+wBbr6y82QAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Ts/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs + /ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs + /ETs/ETs/ABbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Tu + /UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu + /UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/QBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAABbr0Tw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw + /kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/gBbr669 + 2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbrwBbrwBbrwBbrwBbrwBb + rwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBb + rwBbrwBbrwBbrwBbrwBbrwBbrwBbr+XZ4gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7i4n///////g7u//// + ////Du7//wAAA/8O7v//AAAD/w7u//8AAAP/Du7//wAAA/8O7v//AAAD/w7u//8AAAP/Du7//wAAA/8O + 7v//AAAD/w7ugAMAAAP/Du6AAwAAA/8O7oADAAAD/w7ugAMAAAP/Du6AAwAAA/8O7oADAAAD/w7ugAMA + AAP/Du6AAwAAA/8O7oAD/////w7ugAAAAAAADu6AAAAAAAAO7oAAAAAAAA7ugAAAAAAADu6AAAAAAAAO + 7oAAAAAAAA7ugAAAAAAADu6AAAAAAAAO7oAAAAAAAA7ugAAAAAAADu7//AAAAAAO7v/8AAAAAA7u//wA + AAAADu7//AAAAAAO7v/8AAAAAA7u//wAAAAADu7//AAAAAAO7v/8AAAAAA7u//wAAAAADu7//AAAAAAO + 7v/8AAAAAA7u//wAAAAADu7//AAAAAAO7v/8AAAAAA7u//wAAAAADu7//AAAAAAO7v/8AAAAAA7u//wA + AAAADu7///////4O7igAAAAgAAAAQAAAAAEAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzMAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmMzOfOwCfOwCfOwCfOwCfOwCfOwCf + OwCfOwCfOwCfOwCfOwCfOwBmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABmMzOkQQCkQQCkQQCkQQCkQQCkQQCkQQCkQQCkQQCkQQCkQQCkQQBmMzOxmJgA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmMzOrSgCrSgCr + SgCrSgCrSgCrSgCrSgCrSgCrSgCrSgCrSgCrSgBmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmMzOwUQCwUQCwUQCwUQCwUQCwUQCwUQCwUQCwUQCwUQCw + UQCwUQBmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABmMzO3WgC3WgC3WgC3WgC3WgC3WgC3WgC3WgC3WgC3WgC3WgC3WgBmMzOxmJgAAAAAAAAAAAAAAAAA + AAAAAADHu9QAM6EAM6EAM6EAM6EAM6EAM6EAM6EAM6EAAAAAAABmMzO8YAC8YAC8YAC8YAC8YAC8YAC8 + YAC8YAC8YAC8YAC8YAC8YABmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAADHu9QAM6EANqkANqkANqkANqkA + NqkANqkAM6F/mM8AAABmMzPDaQDDaQDDaQDDaQDDaQDDaQDDaQDDaQDDaQDDaQDDaQDDaQBmMzOxmJgA + AAAAAAAAAAAAAAAAAAAAAADHu9QAM6EAOK0AOK0AOK0AOK0AOK0AOK0AM6F/mM8AAABmMzPIcADIcADI + cADIcADIcADIcADIcADIcADIcADIcADIcADIcABmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAADHu9QAM6EA + O7QAO7QAO7QAO7QAO7QAO7QAM6F/mM8AAABmMzPPeADPeADPeADPeADPeADPeADPeADPeADPeADPeADP + eADPeABmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAADHu9QAM6EAPbgAPbgAPbgAPbgAPbgAPbgAM6F/mM8A + AABmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzOxmJgAAAAAAAAAAAAAAAAA + AAAAAADHu9QAM6EAQL8AQL8AQL8AQL8AQL8AQL8AM6FVfMEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADHu9QAM6EAQsMAQsMAQsMAQsMA + QsMAQsMAM6EAW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68A + W68AW68AW68AW68AW6+BpM7Hu9QAM6EARcoARcoARcoARcoARcoARcoAM6EAW69IuuVIuuVIuuVIuuVI + uuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuUAW698oMzHu9QAM6EA + R84AR84AR84AR84AR84AR84AM6EAW69IvuZIvuZIvuZIvuZIvuZIvuZIvuZIvuZIvuZIvuZIvuZIvuZI + vuZIvuZIvuZIvuZIvuZIvuZIvuZIvuYAW698oMzHu9QAM6EAStUAStUAStUAStUAStUAStUAM6EAW69H + wehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwegA + 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 + SH08XNsEAFaMAdioj++z4Eh9MkLbBABWjAHYsLfvs+BIzR6pbQIAK8YAbEAAYqPmEACUwBiAFr18nwVH + au4obRMAWDEGYP2evs+CI/XpaG0TAFgxBmC9Hr7PgiM1b4y2CQCsGAOwLgGIjfqMAKAExgCss6fvs+BI + fT5W2wQAVowBaL6H77PgSH0xTtsEAFaMAWjW3fdZcKS+HK9tAgArxgA07e77LDhS88drmwDAijEAa3fz + fRYcqQVV2iYAsGIMQJOuvs+CI/XVBG0TAFgxBmCtLr7PgiP19URtEwBYIQDlgQCgJMYArNnZ91lwpL6Z + pG0CACvGAKzRyfdZcKQWTtY2AYAVYwBW7+j7LDhSi6q1TQBgxRiA1QhAbNRiAoASGAPQuIPvs+BILZmi + bQIAK8YArNre91lwpL6t0TYBgBVjAFZp5/ssOFLfTdU2AYAVYwBWJgCxUd8TAJTAGIBGbX2fBUfqh2na + JgCwYgzASm18nwVHaul0bRMAWDEFAPEjALBCAMoTAYAVAlCeCACsEIDyRAAARI8AAAkjAEDCCACQMAIA + JIwAAAkjAEDCCACQMFMAAKRlbv1PNdVF4Jm637at+5rUfY3qvrL4iScADfsZgOX03tj+IOMAAAAASUVO + RK5CYIIoAAAAMAAAAGAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/svLi/7Ly2D+y8tb/svL + W/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svL + W/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svL + W/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8uU/svL + ev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AGUyMhxlMjIgZTIyIGUyMiBlMjIgZTIyIGUyMiBlMjIgZTIyIGUyMiBlMjIgZTIyIGUyMiBlMjIgZTIy + IGUyMiBlMjIgZTIyIGUyMiBlMjIgZTIyIGUyMiBlMjIIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAGYzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz + /2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM/+aOQP/njoA/546AP+eOgD/njoA/546AP+eOgD/njoA + /546AP+eOgD/njoA/546AP+eOgD/njoA/546AP+eOgD/njoA/546AP+eOgD/njoA/2YzM/9lMjJAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM/+ePgP/oj8A/6I/AP+iPwD/oj8A + /6I/AP+iPwD/oj8A/6I/AP+iPwD/oj8A/6I/AP+iPwD/oj8A/6I/AP+iPwD/oj8A/6I/AP+iPwD/oj8A + /2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLev7LywgAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM/+iQgP/pkMA + /6ZDAP+mQwD/pkMA/6ZDAP+mQwD/pkMA/6ZDAP+mQwD/pkMA/6ZDAP+mQwD/pkMA/6ZDAP+mQwD/pkMA + /6ZDAP+mQwD/pkMA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svL + ev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AGYzM/+mRwP/qkkA/6pJAP+qSQD/qkkA/6pJAP+qSQD/qkkA/6pJAP+qSQD/qkkA/6pJAP+qSQD/qkkA + /6pJAP+qSQD/qkkA/6pJAP+qSQD/qkkA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAGYzM/+pTAP/rk4A/65OAP+uTgD/rk4A/65OAP+uTgD/rk4A/65OAP+uTgD/rk4A + /65OAP+uTgD/rk4A/65OAP+uTgD/rk4A/65OAP+uTgD/rk4A/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM/+tUQP/slMA/7JTAP+yUwD/slMA/7JTAP+yUwD/slMA + /7JTAP+yUwD/slMA/7JTAP+yUwD/slMA/7JTAP+yUwD/slMA/7JTAP+yUwD/slMA/2YzM/9lMjJAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM/+xVgP/tlkA/7ZZAP+2WQD/tlkA + /7ZZAP+2WQD/tlkA/7ZZAP+2WQD/tlkA/7ZZAP+2WQD/tlkA/7ZZAP+2WQD/tlkA/7ZZAP+2WQD/tlkA + /2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AM6H/ADOh + /wAzof8AM6H/ADOh/wAzof8AM6H/ADOh/wAzof8AM6H/ADOh/wAzof8AMqAsAAAAAGYzM/+0WgP/ul0A + /7pdAP+6XQD/ul0A/7pdAP+6XQD/ul0A/7pdAP+6XQD/ul0A/7pdAP+6XQD/ul0A/7pdAP+6XQD/ul0A + /7pdAP+6XQD/ul0A/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svL + egAzof8ANKP/ADSk/wA0pP8ANKT/ADSk/wA0pP8ANKT/ADSk/wA0pP8ANKT/ADSk/wAzof8AMqBAAAAA + AGYzM/+4XwP/vmIA/75iAP++YgD/vmIA/75iAP++YgD/vmIA/75iAP++YgD/vmIA/75iAP++YgD/vmIA + /75iAP++YgD/vmIA/75iAP++YgD/vmIA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAD+y8tb/svLegAzof8ANqf/ADao/wA2qP8ANqj/ADao/wA2qP8ANqj/ADao/wA2qP8ANqj/ADao + /wAzof8AMqBAAAAAAGYzM/+8ZAP/wmgA/8JoAP/CaAD/wmgA/8JoAP/CaAD/wmgA/8JoAP/CaAD/wmgA + /8JoAP/CaAD/wmgA/8JoAP/CaAD/wmgA/8JoAP/CaAD/wmgA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AN6v/ADer/wA3q/8AN6v/ADer/wA3q/8AN6v/ADer + /wA3q/8AN6v/ADer/wAzof8AMqBAAAAAAGYzM//AaQP/xm0A/8ZtAP/GbQD/xm0A/8ZtAP/GbQD/xm0A + /8ZtAP/GbQD/xm0A/8ZtAP/GbQD/xm0A/8ZtAP/GbQD/xm0A/8ZtAP/GbQD/xm0A/2YzM/9lMjJAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AOa7/ADmv/wA5r/8AOa//ADmv + /wA5r/8AOa//ADmv/wA5r/8AOa//ADmv/wAzof8AMqBAAAAAAGYzM//DbgP/ynIA/8pyAP/KcgD/ynIA + /8pyAP/KcgD/ynIA/8pyAP/KcgD/ynIA/8pyAP/KcgD/ynIA/8pyAP/KcgD/ynIA/8pyAP/KcgD/ynIA + /2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AOrH/ADuz + /wA7s/8AO7P/ADuz/wA7s/8AO7P/ADuz/wA7s/8AO7P/ADuz/wAzof8AMqBAAAAAAGYzM//HcwP/zncA + /853AP/OdwD/zncA/853AP/OdwD/zncA/853AP/OdwD/zncA/853AP/OdwD/zncA/853AP/OdwD/zncA + /853AP/OdwD/zncA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svL + egAzof8APLX/ADy2/wA8tv8APLb/ADy2/wA8tv8APLb/ADy2/wA8tv8APLb/ADy2/wAzof8AMqBAAAAA + AGYzM//LdwP/0nwA/9J8AP/SfAD/0nwA/9J8AP/SfAD/0nwA/9J8AP/SfAD/0nwA/9J8AP/SfAD/0nwA + /9J8AP/SfAD/0nwA/9J8AP/SfAD/0nwA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAD+y8tb/svLegAzof8APbj/AD66/wA+uv8APrr/AD66/wA+uv8APrr/AD66/wA+uv8APrr/AD66 + /wAzof8AMqBAAAAAAGYzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz + /2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AP7z/AEC+/wBAvv8AQL7/AEC+/wBAvv8AQL7/AEC+ + /wBAvv8AQL7/AEC+/wAzof8AMqBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AQb//AEHB/wBBwf8AQcH/AEHB + /wBBwf8AQcH/AEHB/wBBwf8AQcH/AEHB/wAzof8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/+InsiS/svLegAzof8AQsP/AEPF + /wBDxf8AQ8X/AEPF/wBDxf8AQ8X/AEPF/wBDxf8AQ8X/AEPF/wAzof8AW6//SLjk/0i45P9IuOT/SLjk + /0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/0i45P9IuOT/SLjk + /0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/wBbr/9+mMWk/svL + egAzof8ARMb/AEXJ/wBFyf8ARcn/AEXJ/wBFyf8ARcn/AEXJ/wBFyf8ARcn/AEXJ/wAzof8AW6//SLrl + /0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl + /0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl + /wBbr/9+mMWk/svLegAzof8ARcr/AEfM/wBHzP8AR8z/AEfM/wBHzP8AR8z/AEfM/wBHzP8AR8z/AEfM + /wAzof8AW6//SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm + /0i85v9IvOb/SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm + /0i85v9IvOb/SLzm/wBbr/9+mMWk/svLegAzof8AR83/AEjQ/wBI0P8ASND/AEjQ/wBI0P8ASND/AEjQ + /wBI0P8ASND/AEjQ/wAzof8AW6//SL/n/0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n + /0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n + /0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n/wBbr/9+mMWk/svLegAzof8ASNH/AErU/wBK1P8AStT/AErU + /wBK1P8AStT/AErU/wBK1P8AStT/AErU/wAzof8AW6//R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho + /0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho + /0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/wBbr/9+mMWk/8zMegAzof8AStT/AEzY + /wBM2P8ATNj/AEzY/wBM2P8ATNj/AEzY/wBM2P8ATNj/AEzY/wAzof8AW6//R8Pp/0fD6f9Hw+n/R8Pp + /0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp + /0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/wBbr/9+mMWk/8zM + egAzof8ATNj/AE3b/wBN2/8ATdv/AE3b/wBN2/8ATdv/AE3b/wBN2/8ATdv/AE3b/wAzof8AW6//R8Xq + /0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq + /0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq + /wBbr/9+mMWk/8zMegAzof8ARsz/AEjP/wBIz/8ASM//AEjP/wBIz/8ASM//AEjP/wBIz/8ASM//AEjP + /wAzof8AW6//R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr + /0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr + /0fI6/9HyOv/R8jr/wBbr/9+mMWk/8zMegAzof8AM6H/ADOh/wAzof8AM6H/ADOh/wAzof8AM6H/ADOh + /wAzof8AM6H/ADOh/wAzof8AW6//R8rs/0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs + /0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs + /0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//R8zt/0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt + /0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt + /0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Rs7u/0bO7v9Gzu7/Rs7u + /0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u + /0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/wBbr/9+mMWk/8zM + ev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//RtHv + /0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv + /0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv + /wBbr/9+mMWk/8zMev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAW6//RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw + /0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw + /0bT8P9G0/D/RtPw/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAW6//RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy + /0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy + /0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Rtfz/0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz + /0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz + /0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Rtr0/0ba9P9G2vT/Rtr0 + /0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0 + /0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/wBbr/9+mMWk/svL + ev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Rdz1 + /0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1 + /0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1 + /wBbr/9+mMWk/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAW6//Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72 + /0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72 + /0Xe9v9F3vb/Rd72/wBbr/9+mMWk/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAW6//ReD3/0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3 + /0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3 + /0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3/wBbr/9+mMWk/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4 + /0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4 + /0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/wBbr/9+mMWk/svLev7LywgAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//ReX5/0Xl+f9F5fn/ReX5 + /0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5 + /0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/wBbr/9+mMWk/svL + ev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Ref6 + /0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6 + /0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6 + /wBbr/9+mMWk/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAW6//ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7 + /0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7 + /0Tp+/9E6fv/ROn7/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAW6//ROz8/0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8 + /0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8 + /0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8/wBbr/9+mMWk/svLev/LywgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//RO79/0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79 + /0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79 + /0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79/wBbr/9+mMWk/svLev7LywgAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//RPD+/0Tw/v9E8P7/RPD+ + /0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+ + /0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/wBbr/+BmMSi/svL + ev7Lyw7+y8sI/8zMCP/MzAj+y8sI/svLCP7Lywj+y8sI/svLCP7Lywj+y8sI/8zMCP/MzAgAW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr//NtcaA/svLfP/Ly3r+y8t6/8zMev/MzHr+y8t6/svLev7Ly3r+y8t6/svLev7Ly3r+y8t6/8zM + ev/MzHr/zMx6/8zMev/MzHr/zMx6/8zMev/MzHr/zMx6/8zMev/MzHr+y8t6/svLev7Ly3r+y8t6/svL + ev7Ly3r+y8t6/svLev7Ly3r+y8t6/svLev7Ly3r+y8t6/svLev7Ly3r+y8t6/svLev7Ly3r+y8t6/svL + ev7Ly3r+y8t6/svLev7Ly3r+y8uLAAAAAAAADu4//wAAAf4O7j//AAAB/g7uP/8AAAH+Du4//wAAAf4O + 7j//AAAB/g7uP/8AAAH+Du4//wAAAf4O7j//AAAB/g7uP/8AAAH+Du4AAQAAAf4O7gABAAAB/g7uAAEA + AAH+Du4AAQAAAf4O7gABAAAB/g7uAAEAAAH+Du4AAQAAAf4O7gABAAAB/g7uAAH////+Du4AAAAAAAAO + 7gAAAAAAAA7uAAAAAAAADu4AAAAAAAAO7gAAAAAAAA7uAAAAAAAADu4AAAAAAAAO7gAAAAAAAA7uAAAA + AAAADu4AAAAAAAAO7j/8AAAAAA7uP/wAAAAADu4//AAAAAAO7j/8AAAAAA7uP/wAAAAADu4//AAAAAAO + 7j/8AAAAAA7uP/wAAAAADu4//AAAAAAO7j/8AAAAAA7uP/wAAAAADu4//AAAAAAO7j/8AAAAAA7uP/wA + AAAADu4//AAAAAAO7j/8AAAAAA7uP/wAAAAADu4AAAAAAAAO7gAAAAAAAA7uKAAAACAAAABAAAAAAQAg + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7Ly2/+y8s//svLPf7Lyz3+y8s9/svLPf7Lyz3+y8s9/svL + Pf7Lyz3hrq5Ay5iYR8uYmEfLmJhHy5iYR8uYmEfLmJhHy5iYR8uYmEfLmJhHy5iYR8uYmEfLmJhHy5iY + R8uYmEfLmJhC/svLPf7Lyz3+y8s9/svLPf7Lyz3+y8tq/svLVP7LywMAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAGUyMjxmMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz + /2YzM/9mMzP/ZjMz/2UyMloAAAAAAAAAAAAAAAAAAAAAAAAAAP7Lyz3+y8tU/svLAwAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAZjMzVWYzM/+fOwD/nzsA/587AP+fOwD/nzsA/587AP+fOwD/nzsA + /587AP+fOwD/nzsA/587AP9mMzP/ZTIygAAAAAAAAAAAAAAAAAAAAAAAAAAA/svLPf7Ly1T+y8sDAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmMzNVZjMz/6RBAP+kQQD/pEEA/6RBAP+kQQD/pEEA + /6RBAP+kQQD/pEEA/6RBAP+kQQD/pEEA/2YzM/9lMjKAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8s9/svL + VP7LywMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM1VmMzP/q0oA/6tKAP+rSgD/q0oA + /6tKAP+rSgD/q0oA/6tKAP+rSgD/q0oA/6tKAP+rSgD/ZjMz/2UyMoAAAAAAAAAAAAAAAAAAAAAAAAAA + AP7Lyz3+y8tU/svLAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZjMzVWYzM/+wUQD/sFEA + /7BRAP+wUQD/sFEA/7BRAP+wUQD/sFEA/7BRAP+wUQD/sFEA/7BRAP9mMzP/ZTIygAAAAAAAAAAAAAAA + AAAAAAAAAAAA/svLPeG6xm9da7BXADOhVQAzoVUAM6FVADOhVQAzoVUAM6FVADOhVQAyoCZmMzNVZjMz + /7daAP+3WgD/t1oA/7daAP+3WgD/t1oA/7daAP+3WgD/t1oA/7daAP+3WgD/t1oA/2YzM/9lMjKAAAAA + AAAAAAAAAAAAAAAAAAAAAAD+y8s9qZi9pgAzof8AM6H/ADOh/wAzof8AM6H/ADOh/wAzof8AM6H/ADKg + e2YzM1VmMzP/vGAA/7xgAP+8YAD/vGAA/7xgAP+8YAD/vGAA/7xgAP+8YAD/vGAA/7xgAP+8YAD/ZjMz + /2UyMoAAAAAAAAAAAAAAAAAAAAAAAAAAAP7Lyz2pmL2mADOh/wA2qf8ANqn/ADap/wA2qf8ANqn/ADap + /wAzof8AMqCAZjMzVWYzM//DaQD/w2kA/8NpAP/DaQD/w2kA/8NpAP/DaQD/w2kA/8NpAP/DaQD/w2kA + /8NpAP9mMzP/ZTIygAAAAAAAAAAAAAAAAAAAAAAAAAAA/svLPamYvaYAM6H/ADit/wA4rf8AOK3/ADit + /wA4rf8AOK3/ADOh/wAyoIBmMzNVZjMz/8hwAP/IcAD/yHAA/8hwAP/IcAD/yHAA/8hwAP/IcAD/yHAA + /8hwAP/IcAD/yHAA/2YzM/9lMjKAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8s9qZi9pgAzof8AO7T/ADu0 + /wA7tP8AO7T/ADu0/wA7tP8AM6H/ADKggGYzM1VmMzP/z3gA/894AP/PeAD/z3gA/894AP/PeAD/z3gA + /894AP/PeAD/z3gA/894AP/PeAD/ZjMz/2UyMoAAAAAAAAAAAAAAAAAAAAAAAAAAAP7Lyz2pmL2mADOh + /wA9uP8APbj/AD24/wA9uP8APbj/AD24/wAzof8AMqCAZjMzVWYzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz + /2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZTIygAAAAAAAAAAAAAAAAAAAAAAAAAAA/svL + PamYvaYAM6H/AEC//wBAv/8AQL//AEC//wBAv/8AQL//ADOh/wA7o6oAW69VAFuvVQBbr1UAW69VAFuv + VQBbr1UAW69VAFuvVQBbr1UAW69VAFuvVQBbr1UAW69VAFuvVQBbr1UAW69VAFuvVQBbr1UAW69VAFuv + VQBbr1WsqMRlqZi9pgAzof8AQsP/AELD/wBCw/8AQsP/AELD/wBCw/8AM6H/AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/1aFvr6pmL2mADOh/wBFyv8ARcr/AEXK/wBFyv8ARcr/AEXK/wAzof8AW6//SLrl + /0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl + /0i65f9IuuX/SLrl/0i65f8AW6//VIO9wqmYvaYAM6H/AEfO/wBHzv8AR87/AEfO/wBHzv8AR87/ADOh + /wBbr/9Ivub/SL7m/0i+5v9Ivub/SL7m/0i+5v9Ivub/SL7m/0i+5v9Ivub/SL7m/0i+5v9Ivub/SL7m + /0i+5v9Ivub/SL7m/0i+5v9Ivub/SL7m/wBbr/9Ug73CqZi9pgAzof8AStX/AErV/wBK1f8AStX/AErV + /wBK1f8AM6H/AFuv/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho + /0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/AFuv/1SDvcKqmb2mADOh/wBM2v8ATNr/AEza + /wBM2v8ATNr/AEza/wAzof8AW6//R8Tp/0fE6f9HxOn/R8Tp/0fE6f9HxOn/R8Tp/0fE6f9HxOn/R8Tp + /0fE6f9HxOn/R8Tp/0fE6f9HxOn/R8Tp/0fE6f9HxOn/R8Tp/0fE6f8AW6//VIO9wqqZvaYAM6H/ADOh + /wAzof8AM6H/ADOh/wAzof8AM6H/ADOh/wBbr/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr + /0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/wBbr/9Ug73C4rvH + b15rsFcAM6FVADOhVQAzoVUAM6FVADOhVQAzoVUAM6FVAFuv/0fL7P9Hy+z/R8vs/0fL7P9Hy+z/R8vs + /0fL7P9Hy+z/R8vs/0fL7P9Hy+z/R8vs/0fL7P9Hy+z/R8vs/0fL7P9Hy+z/R8vs/0fL7P9Hy+z/AFuv + /1SDvcL/zMxU/8zMAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Rs/u/0bP7v9Gz+7/Rs/u + /0bP7v9Gz+7/Rs/u/0bP7v9Gz+7/Rs/u/0bP7v9Gz+7/Rs/u/0bP7v9Gz+7/Rs/u/0bP7v9Gz+7/Rs/u + /0bP7v8AW6//VIO9wv/MzFT/zMwDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr/9G0u//RtLv + /0bS7/9G0u//RtLv/0bS7/9G0u//RtLv/0bS7/9G0u//RtLv/0bS7/9G0u//RtLv/0bS7/9G0u//RtLv + /0bS7/9G0u//RtLv/wBbr/9Ug73C/8zMVP/MzAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFuv + /0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy + /0bV8v9G1fL/RtXy/0bV8v9G1fL/AFuv/1SDvcL/zMxU/8zMAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAW6//Rtnz/0bZ8/9G2fP/Rtnz/0bZ8/9G2fP/Rtnz/0bZ8/9G2fP/Rtnz/0bZ8/9G2fP/Rtnz + /0bZ8/9G2fP/Rtnz/0bZ8/9G2fP/Rtnz/0bZ8/8AW6//VIO9wv7Ly1T+y8sDAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABbr/9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1 + /0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/wBbr/9Ug73C/svLVP7LywMAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAFuv/0Xf9v9F3/b/Rd/2/0Xf9v9F3/b/Rd/2/0Xf9v9F3/b/Rd/2 + /0Xf9v9F3/b/Rd/2/0Xf9v9F3/b/Rd/2/0Xf9v9F3/b/Rd/2/0Xf9v9F3/b/AFuv/1SDvcL+y8tU/svL + AwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4 + /0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P8AW6//VIO9 + wv7Ly1T+y8sDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr/9F5vn/Reb5/0Xm+f9F5vn/Reb5 + /0Xm+f9F5vn/Reb5/0Xm+f9F5vn/Reb5/0Xm+f9F5vn/Reb5/0Xm+f9F5vn/Reb5/0Xm+f9F5vn/Reb5 + /wBbr/9Ug73C/svLVP7LywMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFuv/0Tq+/9E6vv/ROr7 + /0Tq+/9E6vv/ROr7/0Tq+/9E6vv/ROr7/0Tq+/9E6vv/ROr7/0Tq+/9E6vv/ROr7/0Tq+/9E6vv/ROr7 + /0Tq+/9E6vv/AFuv/1SDvcL+y8tU/8vLAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//RO38 + /0Tt/P9E7fz/RO38/0Tt/P9E7fz/RO38/0Tt/P9E7fz/RO38/0Tt/P9E7fz/RO38/0Tt/P9E7fz/RO38 + /0Tt/P9E7fz/RO38/0Tt/P8AW6//VIO9wv7Ly1X+y8sF/8zMA/7LywP+y8sD/svLA/7LywP+y8sD/8zM + AwBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/9mir25/svLb/7Ly1X/zMxU/svLVP7Ly1T+y8tU/svL + VP7Ly1T/zMxUxrLFi6qmwqaqpsKmqqbCpqqmwqaqpsKmqaXBpqmlwaappcGmqaXBpqmlwaappcGmqaXB + pqmlwaappcGmqaXBpqmlwaappcGmqaXBpqmlwaappcGmqaXBpta5xpIAAAAAP8AAPj/AAD4/wAA+P8AA + Pj/AAD4AAAA+AAAAPgAAAD4AAAA+AAAAPgAAAD4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAAAAAAAAAAAACgAAAAQAAAAIAAA + AAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tB/svLHv7Lyx7+y8se/svLHp1qanCYZWWjmGVl + o5hlZaOYZWWjmGVlo5hlZaOYZWV4/svLHv7Lyx7+y8s5/svLLAAAAAAAAAAAAAAAAAAAAABmMzP/ZjMz + /2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/wAAAAAAAAAA/svLHv7LyywAAAAAAAAAAAAAAAAAAAAAZjMz + /61NAP+tTQD/rU0A/61NAP+tTQD/rU0A/2YzM/8AAAAAAAAAAP7Lyx4AM6H/ADOh/wAzof8AM6H/ADOh + /2YzM/+5XQD/uV0A/7ldAP+5XQD/uV0A/7ldAP9mMzP/AAAAAAAAAAD+y8seADOh/wA3q/8AN6v/ADer + /wAzof9mMzP/xWwA/8VsAP/FbAD/xWwA/8VsAP/FbAD/ZjMz/wAAAAAAAAAA/svLHgAzof8APLb/ADy2 + /wA8tv8AM6H/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/8AAAAAAAAAAP7Lyx4AM6H/AEHB + /wBBwf8AQcH/ADOh/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//ADOh + /wBGzP8ARsz/AEbM/wAzof9IvOX/SLzl/0i85f9IvOX/SLzl/0i85f9IvOX/SLzl/0i85f9IvOX/AFuv + /wAzof8AS9f/AEvX/wBL1/8AM6H/R8Lo/0fC6P9Hwuj/R8Lo/0fC6P9Hwuj/R8Lo/0fC6P9Hwuj/R8Lo + /wBbr/8AM6H/ADOh/wAzof8AM6H/ADOh/0fJ6/9Hyev/R8nr/0fJ6/9Hyev/R8nr/0fJ6/9Hyev/R8nr + /0fJ6/8AW6///8zMLAAAAAAAAAAAAAAAAABbr/9G0O7/RtDu/0bQ7v9G0O7/RtDu/0bQ7v9G0O7/RtDu + /0bQ7v9G0O7/AFuv///MzCwAAAAAAAAAAAAAAAAAW6//Rtfy/0bX8v9G1/L/Rtfy/0bX8v9G1/L/Rtfy + /0bX8v9G1/L/Rtfy/wBbr//+y8ssAAAAAAAAAAAAAAAAAFuv/0Xd9f9F3fX/Rd31/0Xd9f9F3fX/Rd31 + /0Xd9f9F3fX/Rd31/0Xd9f8AW6///svLLAAAAAAAAAAAAAAAAABbr/9F5Pj/ReT4/0Xk+P9F5Pj/ReT4 + /0Xk+P9F5Pj/ReT4/0Xk+P9F5Pj/AFuv//7LyywAAAAAAAAAAAAAAAAAW6//ROv7/0Tr+/9E6/v/ROv7 + /0Tr+/9E6/v/ROv7/0Tr+/9E6/v/ROv7/wBbr//+y8tI/svLLP7Lyyz+y8ssAFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AACsQXgGrEF4BqxBAAasQQAGrEEABqxBAACs + QQAArEEAAKxBAACsQXAArEFwAKxBcACsQXAArEFwAKxBAACsQQ== + + + \ No newline at end of file diff --git a/branches/ph-plugins/ExtraTools/ProcessAnalyzer/ProcessAnalyzer.csproj b/branches/ph-plugins/ExtraTools/ProcessAnalyzer/ProcessAnalyzer.csproj new file mode 100644 index 000000000..eeba5aae8 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/ProcessAnalyzer/ProcessAnalyzer.csproj @@ -0,0 +1,98 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {A6709B97-F7B5-40AD-AB6E-F23019BA0A3C} + WinExe + Properties + ProcessAnalyzer + ProcessAnalyzer + v2.0 + 512 + fake_base.ico + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + true + AnyCPU + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + true + AnyCPU + + + + + + + + + + + + Form + + + MainWindow.cs + + + + + MainWindow.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + {8E10F5E8-D4FA-4980-BB23-2EDD134AC15E} + ProcessHacker.Common + + + {8A448157-E1A7-4DDF-954E-287F1117832B} + ProcessHacker.Native + + + + + + + + \ No newline at end of file diff --git a/branches/ph-plugins/ExtraTools/ProcessAnalyzer/Program.cs b/branches/ph-plugins/ExtraTools/ProcessAnalyzer/Program.cs new file mode 100644 index 000000000..72127b455 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/ProcessAnalyzer/Program.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Windows.Forms; + +namespace ProcessAnalyzer +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new MainWindow()); + } + } +} diff --git a/branches/ph-plugins/ExtraTools/ProcessAnalyzer/Properties/AssemblyInfo.cs b/branches/ph-plugins/ExtraTools/ProcessAnalyzer/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..ca8c088ab --- /dev/null +++ b/branches/ph-plugins/ExtraTools/ProcessAnalyzer/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Process Analyzer")] +[assembly: AssemblyDescription("Process Analyzer")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("wj32")] +[assembly: AssemblyProduct("Process Analyzer")] +[assembly: AssemblyCopyright("Copyright © 2009 wj32. Licensed under the GNU GPL, v3.")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("c98807ff-33c2-465b-a70c-8b0ac257ff96")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/branches/ph-plugins/ExtraTools/ProcessAnalyzer/Properties/Resources.Designer.cs b/branches/ph-plugins/ExtraTools/ProcessAnalyzer/Properties/Resources.Designer.cs new file mode 100644 index 000000000..dacacce16 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/ProcessAnalyzer/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.4016 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace ProcessAnalyzer.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ProcessAnalyzer.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/branches/ph-plugins/ExtraTools/ProcessAnalyzer/Properties/Resources.resx b/branches/ph-plugins/ExtraTools/ProcessAnalyzer/Properties/Resources.resx new file mode 100644 index 000000000..ffecec851 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/ProcessAnalyzer/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ExtraTools/ProcessAnalyzer/Properties/Settings.Designer.cs b/branches/ph-plugins/ExtraTools/ProcessAnalyzer/Properties/Settings.Designer.cs new file mode 100644 index 000000000..8a1647c9e --- /dev/null +++ b/branches/ph-plugins/ExtraTools/ProcessAnalyzer/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.4016 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace ProcessAnalyzer.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/branches/ph-plugins/ExtraTools/ProcessAnalyzer/Properties/Settings.settings b/branches/ph-plugins/ExtraTools/ProcessAnalyzer/Properties/Settings.settings new file mode 100644 index 000000000..abf36c5d3 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/ProcessAnalyzer/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/branches/ph-plugins/ExtraTools/ProcessAnalyzer/fake_base.ico b/branches/ph-plugins/ExtraTools/ProcessAnalyzer/fake_base.ico new file mode 100644 index 000000000..e724a6b20 Binary files /dev/null and b/branches/ph-plugins/ExtraTools/ProcessAnalyzer/fake_base.ico differ diff --git a/branches/ph-plugins/ExtraTools/SysCallHacker/EventProperties.Designer.cs b/branches/ph-plugins/ExtraTools/SysCallHacker/EventProperties.Designer.cs new file mode 100644 index 000000000..ae5fa185b --- /dev/null +++ b/branches/ph-plugins/ExtraTools/SysCallHacker/EventProperties.Designer.cs @@ -0,0 +1,312 @@ +namespace SysCallHacker +{ + partial class EventProperties + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.tabControl = new System.Windows.Forms.TabControl(); + this.tabEvent = new System.Windows.Forms.TabPage(); + this.groupArguments = new System.Windows.Forms.GroupBox(); + this.listArguments = new System.Windows.Forms.ListView(); + this.columnIndex = new System.Windows.Forms.ColumnHeader(); + this.columnValue = new System.Windows.Forms.ColumnHeader(); + this.columnExtendedValue = new System.Windows.Forms.ColumnHeader(); + this.columnType = new System.Windows.Forms.ColumnHeader(); + this.groupBasic = new System.Windows.Forms.GroupBox(); + this.textSystemCall = new System.Windows.Forms.TextBox(); + this.textMode = new System.Windows.Forms.TextBox(); + this.textTime = new System.Windows.Forms.TextBox(); + this.label1 = new System.Windows.Forms.Label(); + this.labelMode = new System.Windows.Forms.Label(); + this.tabProcess = new System.Windows.Forms.TabPage(); + this.tabStackTrace = new System.Windows.Forms.TabPage(); + this.listStackTrace = new System.Windows.Forms.ListView(); + this.columnAddress = new System.Windows.Forms.ColumnHeader(); + this.columnSymbol = new System.Windows.Forms.ColumnHeader(); + this.buttonClose = new System.Windows.Forms.Button(); + this.tabControl.SuspendLayout(); + this.tabEvent.SuspendLayout(); + this.groupArguments.SuspendLayout(); + this.groupBasic.SuspendLayout(); + this.tabStackTrace.SuspendLayout(); + this.SuspendLayout(); + // + // tabControl + // + this.tabControl.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.tabControl.Controls.Add(this.tabEvent); + this.tabControl.Controls.Add(this.tabProcess); + this.tabControl.Controls.Add(this.tabStackTrace); + this.tabControl.Location = new System.Drawing.Point(12, 12); + this.tabControl.Name = "tabControl"; + this.tabControl.SelectedIndex = 0; + this.tabControl.Size = new System.Drawing.Size(510, 409); + this.tabControl.TabIndex = 0; + // + // tabEvent + // + this.tabEvent.Controls.Add(this.groupArguments); + this.tabEvent.Controls.Add(this.groupBasic); + this.tabEvent.Location = new System.Drawing.Point(4, 22); + this.tabEvent.Name = "tabEvent"; + this.tabEvent.Padding = new System.Windows.Forms.Padding(3); + this.tabEvent.Size = new System.Drawing.Size(502, 383); + this.tabEvent.TabIndex = 0; + this.tabEvent.Text = "Event"; + this.tabEvent.UseVisualStyleBackColor = true; + // + // groupArguments + // + this.groupArguments.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupArguments.Controls.Add(this.listArguments); + this.groupArguments.Location = new System.Drawing.Point(6, 138); + this.groupArguments.Name = "groupArguments"; + this.groupArguments.Size = new System.Drawing.Size(490, 239); + this.groupArguments.TabIndex = 2; + this.groupArguments.TabStop = false; + this.groupArguments.Text = "Arguments"; + // + // listArguments + // + this.listArguments.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnIndex, + this.columnValue, + this.columnExtendedValue, + this.columnType}); + this.listArguments.Dock = System.Windows.Forms.DockStyle.Fill; + this.listArguments.FullRowSelect = true; + this.listArguments.HideSelection = false; + this.listArguments.Location = new System.Drawing.Point(3, 16); + this.listArguments.Name = "listArguments"; + this.listArguments.ShowItemToolTips = true; + this.listArguments.Size = new System.Drawing.Size(484, 220); + this.listArguments.TabIndex = 1; + this.listArguments.UseCompatibleStateImageBehavior = false; + this.listArguments.View = System.Windows.Forms.View.Details; + // + // columnIndex + // + this.columnIndex.Text = "Index"; + this.columnIndex.Width = 40; + // + // columnValue + // + this.columnValue.Text = "Value"; + this.columnValue.Width = 100; + // + // columnExtendedValue + // + this.columnExtendedValue.Text = "Extended Value"; + this.columnExtendedValue.Width = 260; + // + // columnType + // + this.columnType.Text = "Type"; + this.columnType.Width = 80; + // + // groupBasic + // + this.groupBasic.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBasic.Controls.Add(this.textSystemCall); + this.groupBasic.Controls.Add(this.textMode); + this.groupBasic.Controls.Add(this.textTime); + this.groupBasic.Controls.Add(this.label1); + this.groupBasic.Controls.Add(this.labelMode); + this.groupBasic.Location = new System.Drawing.Point(6, 6); + this.groupBasic.Name = "groupBasic"; + this.groupBasic.Size = new System.Drawing.Size(490, 126); + this.groupBasic.TabIndex = 1; + this.groupBasic.TabStop = false; + this.groupBasic.Text = "Basic"; + // + // textSystemCall + // + this.textSystemCall.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textSystemCall.BackColor = System.Drawing.SystemColors.Window; + this.textSystemCall.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.textSystemCall.Location = new System.Drawing.Point(6, 19); + this.textSystemCall.Name = "textSystemCall"; + this.textSystemCall.ReadOnly = true; + this.textSystemCall.Size = new System.Drawing.Size(478, 13); + this.textSystemCall.TabIndex = 4; + // + // textMode + // + this.textMode.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textMode.BackColor = System.Drawing.SystemColors.Window; + this.textMode.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.textMode.Location = new System.Drawing.Point(49, 57); + this.textMode.Name = "textMode"; + this.textMode.ReadOnly = true; + this.textMode.Size = new System.Drawing.Size(435, 13); + this.textMode.TabIndex = 3; + // + // textTime + // + this.textTime.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textTime.BackColor = System.Drawing.SystemColors.Window; + this.textTime.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.textTime.Location = new System.Drawing.Point(45, 38); + this.textTime.Name = "textTime"; + this.textTime.ReadOnly = true; + this.textTime.Size = new System.Drawing.Size(439, 13); + this.textTime.TabIndex = 3; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(6, 38); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(33, 13); + this.label1.TabIndex = 2; + this.label1.Text = "Time:"; + // + // labelMode + // + this.labelMode.AutoSize = true; + this.labelMode.Location = new System.Drawing.Point(6, 57); + this.labelMode.Name = "labelMode"; + this.labelMode.Size = new System.Drawing.Size(37, 13); + this.labelMode.TabIndex = 1; + this.labelMode.Text = "Mode:"; + // + // tabProcess + // + this.tabProcess.Location = new System.Drawing.Point(4, 22); + this.tabProcess.Name = "tabProcess"; + this.tabProcess.Padding = new System.Windows.Forms.Padding(3); + this.tabProcess.Size = new System.Drawing.Size(502, 383); + this.tabProcess.TabIndex = 1; + this.tabProcess.Text = "Process"; + this.tabProcess.UseVisualStyleBackColor = true; + // + // tabStackTrace + // + this.tabStackTrace.Controls.Add(this.listStackTrace); + this.tabStackTrace.Location = new System.Drawing.Point(4, 22); + this.tabStackTrace.Name = "tabStackTrace"; + this.tabStackTrace.Padding = new System.Windows.Forms.Padding(3); + this.tabStackTrace.Size = new System.Drawing.Size(502, 383); + this.tabStackTrace.TabIndex = 2; + this.tabStackTrace.Text = "Stack Trace"; + this.tabStackTrace.UseVisualStyleBackColor = true; + // + // listStackTrace + // + this.listStackTrace.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnAddress, + this.columnSymbol}); + this.listStackTrace.Dock = System.Windows.Forms.DockStyle.Fill; + this.listStackTrace.FullRowSelect = true; + this.listStackTrace.HideSelection = false; + this.listStackTrace.Location = new System.Drawing.Point(3, 3); + this.listStackTrace.Name = "listStackTrace"; + this.listStackTrace.ShowItemToolTips = true; + this.listStackTrace.Size = new System.Drawing.Size(496, 377); + this.listStackTrace.TabIndex = 0; + this.listStackTrace.UseCompatibleStateImageBehavior = false; + this.listStackTrace.View = System.Windows.Forms.View.Details; + // + // columnAddress + // + this.columnAddress.Text = "Address"; + this.columnAddress.Width = 100; + // + // columnSymbol + // + this.columnSymbol.Text = "Symbol"; + this.columnSymbol.Width = 360; + // + // buttonClose + // + this.buttonClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonClose.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonClose.Location = new System.Drawing.Point(447, 427); + this.buttonClose.Name = "buttonClose"; + this.buttonClose.Size = new System.Drawing.Size(75, 23); + this.buttonClose.TabIndex = 1; + this.buttonClose.Text = "Close"; + this.buttonClose.UseVisualStyleBackColor = true; + this.buttonClose.Click += new System.EventHandler(this.buttonClose_Click); + // + // EventProperties + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(534, 462); + this.Controls.Add(this.buttonClose); + this.Controls.Add(this.tabControl); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "EventProperties"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Event Properties"; + this.tabControl.ResumeLayout(false); + this.tabEvent.ResumeLayout(false); + this.groupArguments.ResumeLayout(false); + this.groupBasic.ResumeLayout(false); + this.groupBasic.PerformLayout(); + this.tabStackTrace.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TabControl tabControl; + private System.Windows.Forms.TabPage tabEvent; + private System.Windows.Forms.TabPage tabProcess; + private System.Windows.Forms.Button buttonClose; + private System.Windows.Forms.TabPage tabStackTrace; + private System.Windows.Forms.ListView listStackTrace; + private System.Windows.Forms.ColumnHeader columnAddress; + private System.Windows.Forms.ColumnHeader columnSymbol; + private System.Windows.Forms.GroupBox groupArguments; + private System.Windows.Forms.GroupBox groupBasic; + private System.Windows.Forms.Label labelMode; + private System.Windows.Forms.TextBox textMode; + private System.Windows.Forms.TextBox textTime; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox textSystemCall; + private System.Windows.Forms.ListView listArguments; + private System.Windows.Forms.ColumnHeader columnIndex; + private System.Windows.Forms.ColumnHeader columnValue; + private System.Windows.Forms.ColumnHeader columnExtendedValue; + private System.Windows.Forms.ColumnHeader columnType; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ExtraTools/SysCallHacker/EventProperties.cs b/branches/ph-plugins/ExtraTools/SysCallHacker/EventProperties.cs new file mode 100644 index 000000000..375d40285 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/SysCallHacker/EventProperties.cs @@ -0,0 +1,154 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Text; +using System.Windows.Forms; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.SsLogging; +using ProcessHacker.Native.Symbols; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; +using ProcessHacker.Common; + +namespace SysCallHacker +{ + public partial class EventProperties : Form + { + private LogEvent _event; + private SymbolProvider _symbols; + + public EventProperties(LogEvent even) + { + InitializeComponent(); + + _event = even; + + textSystemCall.Text = MainWindow.SysCallNames.ContainsKey(even.Event.CallNumber) ? MainWindow.SysCallNames[even.Event.CallNumber] : "(unknown)"; + textTime.Text = _event.Event.Time.ToString(); + textMode.Text = _event.Event.Mode == KProcessorMode.UserMode ? "User-mode" : "Kernel-mode"; + + for (int i = 0; i < _event.Event.Arguments.Length; i++) + { + ListViewItem item = new ListViewItem(); + + item.Text = i.ToString(); + item.SubItems.Add(new ListViewItem.ListViewSubItem(item, "0x" + _event.Event.Arguments[i].ToString("x"))); + + if (_event.Arguments[i] != null) + { + string text = ""; + SsData data = _event.Arguments[i]; + + if (data is SsSimple) + { + text = (data as SsSimple).Argument.ToString(); + } + else if (data is SsHandle) + { + SsHandle handle = data as SsHandle; + + if (!string.IsNullOrEmpty(handle.Name)) + text = handle.TypeName + ": " + handle.Name; + else + text = handle.TypeName + ": PID: " + handle.ProcessId.ToString() + + ", TID: " + handle.ThreadId.ToString(); + } + else if (data is SsUnicodeString) + { + text = (data as SsUnicodeString).String; + } + else if (data is SsObjectAttributes) + { + SsObjectAttributes oa = data as SsObjectAttributes; + text = ""; + + if (oa.RootDirectory != null) + text = oa.RootDirectory.Name; + + if (oa.ObjectName != null) + { + if (!string.IsNullOrEmpty(text)) + text = text + "\\" + oa.ObjectName.String; + else + text = oa.ObjectName.String; + } + } + else if (data is SsClientId) + { + text = "PID: " + (data as SsClientId).Original.ProcessId.ToString() + + ", TID: " + (data as SsClientId).Original.ThreadId.ToString(); + } + + item.SubItems.Add(new ListViewItem.ListViewSubItem(item, text)); + item.SubItems.Add(new ListViewItem.ListViewSubItem(item, _event.Arguments[i].GetType().Name.Remove(0, 2))); + } + else + { + item.SubItems.Add(new ListViewItem.ListViewSubItem(item, "")); + item.SubItems.Add(new ListViewItem.ListViewSubItem(item, "")); + } + + listArguments.Items.Add(item); + } + + SymbolProvider.Options = SymbolOptions.DeferredLoads | SymbolOptions.UndName; + + try + { + using (var phandle = new ProcessHandle(_event.Event.ProcessId, + ProcessAccess.QueryInformation | ProcessAccess.VmRead)) + { + _symbols = new SymbolProvider(phandle); + + phandle.EnumModules((module) => + { + _symbols.LoadModule(module.FileName, module.BaseAddress, module.Size); + return true; + }); + Windows.EnumKernelModules((module) => + { + _symbols.LoadModule(module.FileName, module.BaseAddress); + return true; + }); + _symbols.PreloadModules = true; + + for (int i = 0; i < _event.Event.StackTrace.Length; i++) + { + var address = _event.Event.StackTrace[i]; + string fileName; + IntPtr baseAddress; + + fileName = _symbols.GetModuleFromAddress(address, out baseAddress); + + listStackTrace.Items.Add(new ListViewItem(new string[] + { + "0x" + address.ToString("x"), + (new System.IO.FileInfo(fileName)).Name + "+0x" + address.Decrement(baseAddress).ToString("x") + })); + + WorkQueue.GlobalQueueWorkItemTag(new Action((i_, address_) => + { + string symbol = _symbols.GetSymbolFromAddress(address_.ToUInt64()); + + if (this.IsHandleCreated) + this.BeginInvoke(new Action(() => listStackTrace.Items[i_].SubItems[1].Text = symbol)); + }), "resolve-symbol", i, address); + } + } + } + catch + { } + + listArguments.SetDoubleBuffered(true); + listStackTrace.SetDoubleBuffered(true); + } + + private void buttonClose_Click(object sender, EventArgs e) + { + this.Close(); + } + } +} diff --git a/branches/ph-plugins/ExtraTools/SysCallHacker/EventProperties.resx b/branches/ph-plugins/ExtraTools/SysCallHacker/EventProperties.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/SysCallHacker/EventProperties.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ExtraTools/SysCallHacker/LogEvent.cs b/branches/ph-plugins/ExtraTools/SysCallHacker/LogEvent.cs new file mode 100644 index 000000000..0eba597f4 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/SysCallHacker/LogEvent.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Native.SsLogging; + +namespace SysCallHacker +{ + public class LogEvent + { + private SsEvent _event; + private SsData[] _arguments; + + public LogEvent(SsEvent even) + { + _event = even; + _arguments = new SsData[even.Arguments.Length]; + } + + public SsData[] Arguments + { + get { return _arguments; } + } + + public SsEvent Event + { + get { return _event; } + } + } +} diff --git a/branches/ph-plugins/ExtraTools/SysCallHacker/MainWindow.Designer.cs b/branches/ph-plugins/ExtraTools/SysCallHacker/MainWindow.Designer.cs new file mode 100644 index 000000000..ea3961ba7 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/SysCallHacker/MainWindow.Designer.cs @@ -0,0 +1,241 @@ +namespace SysCallHacker +{ + partial class MainWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainWindow)); + this.mainMenu = new System.Windows.Forms.MainMenu(this.components); + this.hackerMenuItem = new System.Windows.Forms.MenuItem(); + this.clearHackerMenuItem = new System.Windows.Forms.MenuItem(); + this.exitMenuItem = new System.Windows.Forms.MenuItem(); + this.menuItem1 = new System.Windows.Forms.MenuItem(); + this.removeAllFiltersMenuItem = new System.Windows.Forms.MenuItem(); + this.addProcessFiltersMenuItem = new System.Windows.Forms.MenuItem(); + this.listEvents = new System.Windows.Forms.ListView(); + this.columnTime = new System.Windows.Forms.ColumnHeader(); + this.columnClient = new System.Windows.Forms.ColumnHeader(); + this.columnCall = new System.Windows.Forms.ColumnHeader(); + this.columnMode = new System.Windows.Forms.ColumnHeader(); + this.columnArguments = new System.Windows.Forms.ColumnHeader(); + this.imageList = new System.Windows.Forms.ImageList(this.components); + this.toolBarButtonStop = new System.Windows.Forms.ToolBarButton(); + this.toolBarButtonStart = new System.Windows.Forms.ToolBarButton(); + this.toolBar = new System.Windows.Forms.ToolBar(); + this.statusBar = new System.Windows.Forms.StatusBar(); + this.timerUpdate = new System.Windows.Forms.Timer(this.components); + this.SuspendLayout(); + // + // mainMenu + // + this.mainMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.hackerMenuItem, + this.menuItem1}); + // + // hackerMenuItem + // + this.hackerMenuItem.Index = 0; + this.hackerMenuItem.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.clearHackerMenuItem, + this.exitMenuItem}); + this.hackerMenuItem.Text = "Hacker"; + // + // clearHackerMenuItem + // + this.clearHackerMenuItem.Index = 0; + this.clearHackerMenuItem.Text = "Clear"; + this.clearHackerMenuItem.Click += new System.EventHandler(this.clearHackerMenuItem_Click); + // + // exitMenuItem + // + this.exitMenuItem.Index = 1; + this.exitMenuItem.Text = "E&xit"; + this.exitMenuItem.Click += new System.EventHandler(this.exitMenuItem_Click); + // + // menuItem1 + // + this.menuItem1.Index = 1; + this.menuItem1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.removeAllFiltersMenuItem, + this.addProcessFiltersMenuItem}); + this.menuItem1.Text = "Filters"; + // + // removeAllFiltersMenuItem + // + this.removeAllFiltersMenuItem.Index = 0; + this.removeAllFiltersMenuItem.Text = "Remove All"; + this.removeAllFiltersMenuItem.Click += new System.EventHandler(this.removeAllFiltersMenuItem_Click); + // + // addProcessFiltersMenuItem + // + this.addProcessFiltersMenuItem.Index = 1; + this.addProcessFiltersMenuItem.Text = "Add Process..."; + this.addProcessFiltersMenuItem.Click += new System.EventHandler(this.addProcessFiltersMenuItem_Click); + // + // listEvents + // + this.listEvents.AllowColumnReorder = true; + this.listEvents.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listEvents.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnTime, + this.columnClient, + this.columnCall, + this.columnMode, + this.columnArguments}); + this.listEvents.FullRowSelect = true; + this.listEvents.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; + this.listEvents.HideSelection = false; + this.listEvents.Location = new System.Drawing.Point(0, 28); + this.listEvents.Name = "listEvents"; + this.listEvents.ShowItemToolTips = true; + this.listEvents.Size = new System.Drawing.Size(813, 435); + this.listEvents.TabIndex = 1; + this.listEvents.UseCompatibleStateImageBehavior = false; + this.listEvents.View = System.Windows.Forms.View.Details; + this.listEvents.VirtualMode = true; + this.listEvents.DoubleClick += new System.EventHandler(this.listEvents_DoubleClick); + this.listEvents.RetrieveVirtualItem += new System.Windows.Forms.RetrieveVirtualItemEventHandler(this.listEvents_RetrieveVirtualItem); + // + // columnTime + // + this.columnTime.Text = "Time"; + this.columnTime.Width = 140; + // + // columnClient + // + this.columnClient.Text = "Client"; + this.columnClient.Width = 120; + // + // columnCall + // + this.columnCall.Text = "Call"; + this.columnCall.Width = 160; + // + // columnMode + // + this.columnMode.Text = "Mode"; + this.columnMode.Width = 70; + // + // columnArguments + // + this.columnArguments.Text = "Arguments"; + this.columnArguments.Width = 300; + // + // imageList + // + this.imageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList.ImageStream"))); + this.imageList.TransparentColor = System.Drawing.Color.Transparent; + this.imageList.Images.SetKeyName(0, "control_play"); + this.imageList.Images.SetKeyName(1, "control_stop"); + // + // toolBarButtonStop + // + this.toolBarButtonStop.ImageKey = "control_stop"; + this.toolBarButtonStop.Name = "toolBarButtonStop"; + this.toolBarButtonStop.ToolTipText = "Stop"; + // + // toolBarButtonStart + // + this.toolBarButtonStart.ImageKey = "control_play"; + this.toolBarButtonStart.Name = "toolBarButtonStart"; + this.toolBarButtonStart.ToolTipText = "Start"; + // + // toolBar + // + this.toolBar.Appearance = System.Windows.Forms.ToolBarAppearance.Flat; + this.toolBar.Buttons.AddRange(new System.Windows.Forms.ToolBarButton[] { + this.toolBarButtonStart, + this.toolBarButtonStop}); + this.toolBar.DropDownArrows = true; + this.toolBar.ImageList = this.imageList; + this.toolBar.Location = new System.Drawing.Point(0, 0); + this.toolBar.Name = "toolBar"; + this.toolBar.ShowToolTips = true; + this.toolBar.Size = new System.Drawing.Size(813, 28); + this.toolBar.TabIndex = 0; + this.toolBar.ButtonClick += new System.Windows.Forms.ToolBarButtonClickEventHandler(this.toolBar_ButtonClick); + // + // statusBar + // + this.statusBar.Location = new System.Drawing.Point(0, 462); + this.statusBar.Name = "statusBar"; + this.statusBar.Size = new System.Drawing.Size(813, 22); + this.statusBar.TabIndex = 2; + // + // timerUpdate + // + this.timerUpdate.Enabled = true; + this.timerUpdate.Interval = 500; + this.timerUpdate.Tick += new System.EventHandler(this.timerUpdate_Tick); + // + // MainWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(813, 484); + this.Controls.Add(this.statusBar); + this.Controls.Add(this.listEvents); + this.Controls.Add(this.toolBar); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Menu = this.mainMenu; + this.Name = "MainWindow"; + this.Text = "System Call Hacker"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainWindow_FormClosing); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.MainMenu mainMenu; + private System.Windows.Forms.MenuItem hackerMenuItem; + private System.Windows.Forms.MenuItem exitMenuItem; + private System.Windows.Forms.ListView listEvents; + private System.Windows.Forms.ColumnHeader columnTime; + private System.Windows.Forms.ColumnHeader columnCall; + private System.Windows.Forms.ColumnHeader columnMode; + private System.Windows.Forms.ColumnHeader columnArguments; + private System.Windows.Forms.ImageList imageList; + private System.Windows.Forms.ToolBarButton toolBarButtonStop; + private System.Windows.Forms.ToolBarButton toolBarButtonStart; + private System.Windows.Forms.ToolBar toolBar; + private System.Windows.Forms.StatusBar statusBar; + private System.Windows.Forms.Timer timerUpdate; + private System.Windows.Forms.ColumnHeader columnClient; + private System.Windows.Forms.MenuItem menuItem1; + private System.Windows.Forms.MenuItem removeAllFiltersMenuItem; + private System.Windows.Forms.MenuItem addProcessFiltersMenuItem; + private System.Windows.Forms.MenuItem clearHackerMenuItem; + + + } +} + diff --git a/branches/ph-plugins/ExtraTools/SysCallHacker/MainWindow.cs b/branches/ph-plugins/ExtraTools/SysCallHacker/MainWindow.cs new file mode 100644 index 000000000..81f04cd7a --- /dev/null +++ b/branches/ph-plugins/ExtraTools/SysCallHacker/MainWindow.cs @@ -0,0 +1,233 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Text; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; +using ProcessHacker.Native.SsLogging; +using ProcessHacker.Native.Symbols; + +namespace SysCallHacker +{ + public partial class MainWindow : Form + { + private static Dictionary _sysCallNames = new Dictionary(); + + public static Dictionary SysCallNames + { + get { return _sysCallNames; } + } + + private SsLogger _logger; + private List _events = new List(); + private LogEvent _lastEvent; + private List _rules = new List(); + private Dictionary _processes; + + public MainWindow() + { + InitializeComponent(); + + Win32.LoadLibrary("C:\\Program Files\\Debugging Tools for Windows (x86)\\dbghelp.dll"); + + SymbolProvider symbols = new SymbolProvider(ProcessHandle.Current); + + SymbolProvider.Options |= SymbolOptions.PublicsOnly; + + IntPtr ntdllBase = Loader.GetDllHandle("ntdll.dll"); + FileHandle ntdllFileHandle = null; + Section section = null; + + ProcessHandle.Current.EnumModules((module) => + { + if (module.BaseName.Equals("ntdll.dll", StringComparison.InvariantCultureIgnoreCase)) + { + section = new Section( + ntdllFileHandle = new FileHandle(@"\??\" + module.FileName, + FileShareMode.ReadWrite, + FileAccess.GenericExecute | FileAccess.GenericRead + ), + true, + MemoryProtection.ExecuteRead + ); + + symbols.LoadModule(module.FileName, module.BaseAddress, module.Size); + return false; + } + + return true; + }); + + SectionView view = section.MapView((int)ntdllFileHandle.GetSize()); + + ntdllFileHandle.Dispose(); + + symbols.EnumSymbols("ntdll!Zw*", (symbol) => + { + int number = Marshal.ReadInt32( + (symbol.Address.ToIntPtr().Decrement(ntdllBase)).Increment(view.Memory).Increment(1)); + + _sysCallNames.Add( + number, + "Nt" + symbol.Name.Substring(2) + ); + + return true; + }); + + view.Dispose(); + section.Dispose(); + + symbols.Dispose(); + + KProcessHacker.Instance = new KProcessHacker(); + + _logger = new SsLogger(4096, false); + _logger.EventBlockReceived += new EventBlockReceivedDelegate(logger_EventBlockReceived); + _logger.ArgumentBlockReceived += new ArgumentBlockReceivedDelegate(logger_ArgumentBlockReceived); + _logger.AddPreviousModeRule(FilterType.Include, KProcessorMode.UserMode); + _logger.AddProcessIdRule(FilterType.Exclude, ProcessHandle.GetCurrentId()); + //_logger.Start(); + + listEvents.SetDoubleBuffered(true); + } + + private void MainWindow_FormClosing(object sender, FormClosingEventArgs e) + { + ProcessHandle.Current.Terminate(); + } + + private void logger_EventBlockReceived(SsEvent eventBlock) + { + LogEvent logEvent = new LogEvent(eventBlock); + + lock (_events) + _events.Add(logEvent); + + _lastEvent = logEvent; + } + + private void logger_ArgumentBlockReceived(SsData argBlock) + { + if (_lastEvent != null) + { + if (argBlock.Index < _lastEvent.Arguments.Length) + _lastEvent.Arguments[argBlock.Index] = argBlock; + } + } + + private void timerUpdate_Tick(object sender, EventArgs e) + { + _processes = Windows.GetProcesses(); + + lock (_events) + listEvents.VirtualListSize = _events.Count; + + int blocksWritten, blocksDropped; + + _logger.GetStatistics(out blocksWritten, out blocksDropped); + + if (blocksWritten > 0 || blocksDropped > 0) + { + lock (_events) + { + statusBar.Text = _events.Count.ToString("N0") + " events, " + + blocksWritten.ToString("N0") + " blocks, " + + blocksDropped.ToString("N0") + " dropped (" + + ((double)blocksDropped / (blocksWritten + blocksDropped) * 100).ToString("F2") + "%)"; + } + } + } + + private void listEvents_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e) + { + LogEvent logEvent; + ListViewItem item; + + lock (_events) + logEvent = _events[e.ItemIndex]; + + string objectName = ""; + + if (logEvent.Arguments.Length > 2) + { + SsObjectAttributes oa = logEvent.Arguments[2] as SsObjectAttributes; + + if (oa != null) + { + if (oa.ObjectName != null) + objectName = oa.ObjectName.String; + } + } + + item = new ListViewItem(new string[] + { + logEvent.Event.Time.ToString(), + _processes.ContainsKey(logEvent.Event.ProcessId) ? _processes[logEvent.Event.ProcessId].Name : logEvent.Event.ProcessId.ToString(), + _sysCallNames.ContainsKey(logEvent.Event.CallNumber) ? _sysCallNames[logEvent.Event.CallNumber] : "(unknown)", + logEvent.Event.Mode == KProcessorMode.UserMode ? "User" : "Kernel", + objectName + }); + e.Item = item; + } + + private void exitMenuItem_Click(object sender, EventArgs e) + { + this.Close(); + } + + private void toolBar_ButtonClick(object sender, ToolBarButtonClickEventArgs e) + { + if (e.Button == toolBarButtonStart) + { + _logger.Start(); + } + else if (e.Button == toolBarButtonStop) + { + _logger.Stop(); + } + } + + private void ShowProperties(int index) + { + (new EventProperties(_events[index])).ShowDialog(); + } + + private void listEvents_DoubleClick(object sender, EventArgs e) + { + this.ShowProperties(listEvents.SelectedIndices[0]); + } + + private void clearHackerMenuItem_Click(object sender, EventArgs e) + { + lock (_events) + { + listEvents.VirtualListSize = 0; + _events.Clear(); + } + } + + private void removeAllFiltersMenuItem_Click(object sender, EventArgs e) + { + foreach (var rule in _rules) + _logger.RemoveRule(rule); + + _rules.Clear(); + } + + private void addProcessFiltersMenuItem_Click(object sender, EventArgs e) + { + ProcessHacker.Native.Ui.ChooseProcessDialog cpd = new ProcessHacker.Native.Ui.ChooseProcessDialog(); + + if (cpd.ShowDialog() == DialogResult.OK) + _rules.Add(_logger.AddProcessIdRule(FilterType.Include, cpd.SelectedPid)); + } + } +} diff --git a/branches/ph-plugins/ExtraTools/SysCallHacker/MainWindow.resx b/branches/ph-plugins/ExtraTools/SysCallHacker/MainWindow.resx new file mode 100644 index 000000000..fc7d1066f --- /dev/null +++ b/branches/ph-plugins/ExtraTools/SysCallHacker/MainWindow.resx @@ -0,0 +1,953 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 127, 17 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj0yLjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAB4 + BgAAAk1TRnQBSQFMAgEBAgEAAQQBAAEEAQABEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + AwABEAMAAQEBAAEgBgABEP8AIwADIwE0A0cBgANaAcADYgHtA2IB7QNaAcADRwGAAyMBNCAAAyMBNANH + AYADWgHAA2IB7QNiAe0DWgHAA0cBgAMjATScAAM9AWcDXgHVA84B/wPmAf8D9QH/A/IB/wPdAf8DwAH/ + A14B1QM9AWcYAAM9AWcDXgHVA84B/wPmAf8D9QH/A/IB/wPdAf8DwAH/A14B1QM9AWeUAAM9AWcDbgHx + A+wB/wP+Af8D8wH/A+gB/wPnAf8D8QH/A/sB/wPhAf8DZwHxAz0BZxAAAz0BZwNuAfED7AH/A/4B/wPz + Af8D6AH/A+cB/wPxAf8D+wH/A+EB/wNnAfEDPQFnjAADIwE0A14B1QPwBf8D5QH/A+UB/wPvAf8D4wH/ + A+IB/wPhAf8D/gH/A+IB/wNeAdUDIwE0CAADIwE0A14B1QPwBf8D5QH/A+UB/wPkAf8D4wH/A+IB/wPh + Af8D/gH/A+IB/wNeAdUDIwE0iAADRwGAA+QB/wP+Af8D6AH/A+cB/wPmAf8DYQH/A+8B/wPkAf8D4wH/ + A+IB/wP7Af8DxgH/A0cBgAgAA0cBgAPkAf8D/gH/A+gB/wPnAf8D5gH/A+UB/wPlAf8D5AH/A+MB/wPi + Af8D+wH/A8YB/wNHAYCIAANaAcAD8gH/A/UB/wPpAf8D6QH/A+gB/wNmAf8BYgJhAf8D7wH/A+UB/wPk + Af8D8gH/A+EB/wNaAcAIAANaAcAD8gH/A/UB/wPpAf8D6QH/A4MB/wOCAf8DggH/A4EB/wPlAf8D5AH/ + A/IB/wPhAf8DWgHAiAADaAHtA/wB/wPvAf8D6wH/A+oB/wPpAf8DYwH/AWcCZgH/AWICYQH/A+8B/wPl + Af8D6AH/A/QB/wNkAe0IAANoAe0D/AH/A+8B/wPrAf8D6gH/A1wB/wNcAf8DWwH/A4IB/wPlAf8D5QH/ + A+gB/wP0Af8DZAHtiAADaAHtA/wB/wPwAf8D7QH/A+sB/wPqAf8DYwH/A2MB/wFoAmcB/wPNAf8D5gH/ + A+kB/wP6Af8DZAHtCAADaAHtA/wB/wPwAf8D7QH/A+sB/wNcAf8DXAH/A1wB/wODAf8D5wH/A+YB/wPp + Af8D+gH/A2QB7YgAA1oBwAP1Af8D9wH/A+0B/wPtAf8D7AH/AWQCYwH/AWQCYwH/A8AB/wPpAf8D6AH/ + A/QB/wPuAf8DWgHACAADWgHAA/UB/wP3Af8D7QH/A+0B/wNdAf8DXQH/A1wB/wODAf8D6QH/A+gB/wP0 + Af8D7gH/A1oBwIgAA0cBgAPrBf8D7wH/A+4B/wPtAf8BZQJkAf8DwgH/A+sB/wPpAf8D6QX/A90B/wNH + AYAIAANHAYAD6wX/A+8B/wPuAf8D7QH/A+0B/wPsAf8D6wH/A+kB/wPpBf8D3QH/A0cBgIgAAyMBNANe + AdUD+AX/A+8B/wPuAf8DwwH/A+0B/wPsAf8D6wX/A/UB/wNeAdUDIwE0CAADIwE0A14B1QP4Bf8D7wH/ + A+4B/wPtAf8D7QH/A+wB/wPrBf8D9QH/A14B1QMjATSMAAM9AWcDcgHxA/gF/wP4Af8D8gH/A/EB/wP3 + Bf8D9QH/A3AB8QM9AWcQAAM9AWcDcgHxA/gF/wP4Af8D8gH/A/EB/wP3Bf8D9QH/A3AB8QM9AWeUAAM9 + AWcDXgHVA+sB/wP1Af8D/AH/A/wB/wP0Af8D6AH/A14B1QM9AWcYAAM9AWcDXgHVA+sB/wP1Af8D/AH/ + A/wB/wP0Af8D6AH/A14B1QM9AWecAAMjATQDRwGAA1oBwANoAe0DaAHtA1oBwANHAYADIwE0IAADIwE0 + A0cBgANaAcADaAHtA2gB7QNaAcADRwGAAyMBNP8AkQABQgFNAT4HAAE+AwABKAMAAUADAAEQAwABAQEA + AQEFAAGAFwAD/wEABP8EAAHwAQ8B8AEPBAAB4AEHAeABBwQAAcABAwHAAQMEAAGAAQEBgAEBBAABgAEB + AYABAQQAAYABAQGAAQEEAAGAAQEBgAEBBAABgAEBAYABAQQAAYABAQGAAQEEAAGAAQEBgAEBBAABgAEB + AYABAQQAAcABAwHAAQMEAAHgAQcB4AEHBAAB8AEPAfABDwQABP8EAAs= + + + + 230, 17 + + + + + AAABAA8AMDAQAAEABABoBgAA9gAAACAgEAABAAQA6AIAAF4HAAAQEBAAAQAEACgBAABGCgAAAAAAAAEA + CABqDQAAbgsAADAwAAABAAgAqA4AANgYAAAgIAAAAQAIAKgIAACAJwAAEBAAAAEACABoBQAAKDAAAAAA + AAABABgAOQ0AAJA1AAAwMAAAAQAYAKgcAADJQgAAICAAAAEAGACoDAAAcV8AABAQAAABABgAaAMAABls + AAAAAAAAAQAgAHANAACBbwAAMDAAAAEAIACoJQAA8XwAACAgAAABACAAqBAAAJmiAAAQEAAAAQAgAGgE + AABBswAAKAAAADAAAABgAAAAAQAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAIAAAACA + gACAAAAAgACAAICAAACAgIAAAAD/AAD/AAAA//8A/wAAAP8A/wD//wAAwMDAAP///wDwAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFRGVGVlZGVkdGVlAAAA + AAAAAAAAAAAAAFZGtkZLa2Rka0a0AAAAAAAAAAAAAAAAAGtka2tka2trZkZHAAAAAAAAAAAAAAAAAGRr + a2tmtmtra2tkAAAAAAAAAAAAAAAAAFZrZma2a2a2a2tnAAAAAAAAAAAAAAAAAEa2a2tra2tra2ZkAAAA + AAAAAAAAAAAAAGa2trZra2a2a2tlAAAAAAAAAAAAAAAAAHa2bbZrZttmtmtmAAAAAAABODE4ExgxAFa2 + tra2tra2tmtlAAAAAAABgxg4E4OBAEZrZrZr1rZr29tmAAAAAAADgTETgxMTAHvWvb22tmvba2tlAAAA + AAADE4ODgxg4AGRr272729tr29vUAAAAAAAIE4MTgTgxAF2729vb22bb29tnAAAAAAABODg4ODgxAEbb + 29vb29u2vb22AAAAAAADg4ODg4ODAEZmZmZmZm1mZmZlAAAAAAABODg4ODg4AHR2VlZWR1ZHRlZWAAAA + AAAIODg4ODg4AAAAAAAAAAAAAAAAAAAAAAADg4ODg4ODM4ODiDiDg4ODg4OIOIODg44BODiDioOBiuiu + p6euinqK6K6np66o6j4BioODg4ODOurqjq6nrq6urqeup3qK6h4Dg4OKg4ODjoruqK6o6o6o6uqOqurq + 6o4Bg4ODiDg4Oq6orqeup66np6iuqOqOqD4Dg4qIOKg4h6eup66Kenp6eurqeup66j4Biog4qDiDPqen + p66urq6np66K6np6eo4DiKg4OKiBiq6nrqiuqKeup6p6enp66j4Bg4OIODgzOup66nrqeup6eurqenrq + eo4BMRMTgTGBh66orqenp6rorop66np66j4AAAAAAAAAOup66np66nrqrqrqenrqeo4AAAAAAAAAinp6 + eup6enrqeurqeup66j4AAAAAAAAAPqrq6qeq6up6euqK6q6uqh4AAAAAAAAAiup6eup6eqeup66urqiu + 6j4AAAAAAAAAOup66np66n6qeqeqenrqqo4AAAAAAAAAGq6q6q6q6qrq6urqrqrq6j4AAAAAAAAAPq6u + qurq6urq6uqurq6q6o4AAAAAAAAAiq6q6uqq6q6qququqq6q6j4AAAAAAAAAOuqurqrq6uqurq6urq6u + ro4AAAAAAAAAiurqqurq6q6urqrqrqquqj4AAAAAAAAAPq6q6urqququqq6q6q6uro4AAAAAAAAAOqrq + 6qqurq6q6urqrq6q6j4AAAAAAAAAOurqqurqrqququqq6uquqj4AAAAAAAAAiuqurqrqrq6q6q6uqq6q + 6o4AAAAAAAAAOuququrqrqrq6q6q6uquqn4AAAAAAAAAeq6uququrqrqrq6q6q6uqo4AAAAAAAAAOq6q + rqquqq6qrqquqq6qrj4AAAAAAAAAgzODM4MzgzODM4MzgzODMT8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AA9///////4AAP///////wAA//8AAAP/AAD//wAAA/8AAP//AAAD/wAA//8AAAP/AAD//wAAA/8AAP// + AAAD/wAA//8AAAP/AAD//wAAA/8AAIADAAAD/wAAgAMAAAP/AACAAwAAA/8AAIADAAAD/wAAgAMAAAP/ + AACAAwAAA/8AAIADAAAD/wAAgAMAAAP/AACAA/////8AAIAAAAAAAAAAgAAAAAAAAACAAAAAAAAAAIAA + AAAAAAAAgAAAAAAAAACAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAACAAAAAAAAAAIAAAAAAAAAA//wAAAAA + AAD//AAAAAAAAP/8AAAAAAAA//wAAAAAAAD//AAAAAAAAP/8AAAAAAAA//wAAAAAAAD//AAAAAAAAP/8 + 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 + Hx8fHx8fHx8fGwAAARQXFxcXFxcXFxcXFxcXFxcXFxcXAQAAAAAAAAAAAAAAGyAhISEhISEhISEgGwAA + ARYZGRkZGRkZGRkZGRkZGRkZGRkZAQAAAAAAAAAAAAAAGyEhISEhISEhISEhGwAAARgaGhoaGhoaGhoa + GhoaGhoaGhoaAQAAAAAAAAAAAAAAGyIiIyIjIyIjIyMiGwAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAA + AAAAAAAAAAAAGyUlJSUlJSUlJSUlGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGyYm + JiYmJiYmJiYmGyQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJEIAGyYnJygnKCcoJycnHCQv + Ly8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vJEEAGygpKSkpKSkpKSkpHCQwLzAwMDAwMDAwMDAw + MDAwMDAwMDAwMDAwMDAwMDAvJEEAGykrKiorKisqKyoqHCQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw + MDAwMDAwJEEAGyosLCwsLCwsLCwsGyQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwJEEAGywt + LS0tLS0tLS0tHCQxMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExJEEAGy0uLi4uLi4uLi4uHCQy + MjIxMjEyMTIxMjEyMTIxMjEyMTIxMjEyMTIxMjEyJEEAGy4uLi4uLi4uLi4uGyQyMjIyMjIyMjIyMjIy + MjIyMjIyMjIyMjIyMjIyMjIyJEEAGyorKysrKysrKysrGyQzMzQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0 + NDQ0NDQzJEEAGxsbGxsbGxsbGxsbHCQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDU0JEEAAAAA + AAAAAAAAAAAAACQ1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1JEEAAAAAAAAAAAAAAAAAACQ1 + NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1JEEAAAAAAAAAAAAAAAAAACQ2Njc3Nzc3Nzc3Nzc3 + Nzc3Nzc3Nzc3Nzc3Nzc3NzY2JEEAAAAAAAAAAAAAAAAAACQ3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3 + Nzc3Nzg3JEEAAAAAAAAAAAAAAAAAACQ4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4JEEAAAAA + AAAAAAAAAAAAACQ4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4JEEAAAAAAAAAAAAAAAAAACQ5 + OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5JEEAAAAAAAAAAAAAAAAAACQ6Ojo6Ojo6Ojo6Ojo6 + Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6JEEAAAAAAAAAAAAAAAAAACQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7 + Ozs7Ozs7JEEAAAAAAAAAAAAAAAAAACQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7JEEAAAAA + AAAAAAAAAAAAACQ8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8JEEAAAAAAAAAAAAAAAAAACQ9 + PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09JEEAAAAAAAAAAAAAAAAAACQ9PT09PT09PT09PT09 + PT09PT09PT09PT09PT09PT09JEEAAAAAAAAAAAAAAAAAACQ+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+ + Pj4+Pj4+JEEAAAAAAAAAAAAAAAAAACQ/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/JEEAAAAA + AAAAAAAAAAAAACQ/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/JEEAAAAAAAAAAAAAAAAAACRA + QEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAJEEAAAAAAAAAAAAAAAAAACQkJCQkJCQkJCQkJCQk + JCQkJCQkJCQkJCQkJCQkJCQkJEMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAER///////4O7v///////w7u//8AAAP/Du7//wAAA/8O7v//AAAD/w7u//8AAAP/Du7//wAA + A/8O7v//AAAD/w7u//8AAAP/Du7//wAAA/8O7oADAAAD/w7ugAMAAAP/Du6AAwAAA/8O7oADAAAD/w7u + gAMAAAP/Du6AAwAAA/8O7oADAAAD/w7ugAMAAAP/Du6AA/////8O7oAAAAAAAA7ugAAAAAAADu6AAAAA + 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 + HBwcHBwcHBwcHBwcHBwcHBwcEBktCxYWFhYWFgsQHR0dHR0dHR0dHR0dHR0dHR0dHR0QGS0LCwsLCwsL + CxAeHh4eHh4eHh4eHh4eHh4eHh4eHhAZAAAAAAAAAAAAEB8fHx8fHx8fHx8fHx8fHx8fHx8fEBkAAAAA + AAAAAAAQICAgICAgICAgICAgICAgICAgICAQGQAAAAAAAAAAABAhISEhISEhISEhISEhISEhISEhIRAZ + AAAAAAAAAAAAECIiIiIiIiIiIiIiIiIiIiIiIiIiEBkAAAAAAAAAAAAQIyMjIyMjIyMjIyMjIyMjIyMj + IyMQGQAAAAAAAAAAABAkJCQkJCQkJCQkJCQkJCQkJCQkJBAZAAAAAAAAAAAAECUkJSQlJCQkJCQkJCQk + JCQkJCQkEBkAAAAAAAAAAAAQJSUlJSUlJSUlJSUlJSUlJSUlJSUQGQAAAAAAAAAAABAmJiYmJiYmJiYm + JiYmJiYmJiYmJhAZAAAAAAAAAAAAECcnJycnJycnJycnJycnJycnJycnEBkAAAAAAAAAAAAQKCgoKCgo + KCgoKCgoKCgoKCgoKCgQGQAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBArAAAAAAAAAAAALy4u + Li4uLi4uLi4uLi4uLi4uLi4uLjD//////+AAf//gAD//4AA//+AAP//gAD//4AA/AGAAPwAgAD8AIAA/ + ACAAPwAgAD8AP///AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA + /4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAACgAAAAQAAAAIAAAAAEACAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAoj8AAK5OAAC6XQAAr2MPAMZtAACqbEwAsHNMALZ7TACwflQAvINMALKDbwC2h28A + uYxvAL2RbwC2jnQAADerAAA8tgAQUL8AQGi9AABCwgAAR80AEFPEAABM2AAlW8AAQGrDAD6w3wA+tuEA + PrzkAHiGwgB4iMUAcIzKAHiJyQB4jM0AZI3QAHCT2QBftdwAX7neAGCt2ABgstoAR7zmAF+/4QA9wucA + PcjqADzO7QA81O8AO9ryAEfD6QBGyuwAXsLhAEbR7wBG2PIARd/1AEXl+ABE7PwAu7zZALu93ACBuuAA + g73iAJrA3wClw9sApsbcALfH3AD///8AAAAAAAAvDgAAUBgAAHAiAACQLAAAsDYAAM9AAADwSgAR/1sA + Mf9xAFH/hwBx/50Akf+yALH/yQDR/98A////AAAAAAACLwAABFAAAAZwAAAIkAAACrAAAAvPAAAO8AAA + IP8SAD3/MQBb/1EAef9xAJj/kQC1/7EA1P/RAP///wAAAAAAFC8AACJQAAAwcAAAPZAAAEywAABZzwAA + Z/AAAHj/EQCK/zEAnP9RAK7/cQDA/5EA0v+xAOT/0QD///8AAAAAACYvAABAUAAAWnAAAHSQAACOsAAA + qc8AAMLwAADR/xEA2P8xAN7/UQDj/3EA6f+RAO//sQD2/9EA////AAAAAAAvJgAAUEEAAHBbAACQdAAA + sI4AAM+pAADwwwAA/9IRAP/YMQD/3VEA/+RxAP/qkQD/8LEA//bRAP///wAAAAAALxQAAFAiAABwMAAA + kD4AALBNAADPWwAA8GkAAP95EQD/ijEA/51RAP+vcQD/wZEA/9KxAP/l0QD///8AAAAAAC8DAABQBAAA + cAYAAJAJAACwCgAAzwwAAPAOAAD/IBIA/z4xAP9cUQD/enEA/5eRAP+2sQD/1NEA////AAAAAAAvAA4A + UAAXAHAAIQCQACsAsAA2AM8AQADwAEkA/xFaAP8xcAD/UYYA/3GcAP+RsgD/scgA/9HfAP///wAAAAAA + LwAgAFAANgBwAEwAkABiALAAeADPAI4A8ACkAP8RswD/Mb4A/1HHAP9x0QD/kdwA/7HlAP/R8AD///8A + AAAAACwALwBLAFAAaQBwAIcAkAClALAAxADPAOEA8ADwEf8A8jH/APRR/wD2cf8A95H/APmx/wD70f8A + ////AAAAAAAbAC8ALQBQAD8AcABSAJAAYwCwAHYAzwCIAPAAmRH/AKYx/wC0Uf8AwnH/AM+R/wDcsf8A + 69H/AP///wAAAAAACAAvAA4AUAAVAHAAGwCQACEAsAAmAM8ALADwAD4R/wBYMf8AcVH/AIxx/wCmkf8A + v7H/ANrR/wD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAACwEBAQEBAQYAAAAAAAAAAAwCAgICAgIHAAAA + Nx8fHwANAwMDAwMDCAAAAB0QEBATDgUFBQUFBQoAAAAeERERGQ8EBAQEBAQJAAAAIBQUFBg5Ojo6Ojo6 + Ojo6OyAVFRUSGigoKCgoKCgoKCYhFxcXFhsvLy8vLy8vLy8mOCMjIyIcMDAwMDAwMDAwJwAAAAAAKjIy + MjIyMjIyMiQAAAAAACszMzMzMzMzMzMlAAAAAAAsNDQ0NDQ0NDQ0JQAAAAAALTU1NTU1NTU1NSkAAAAA + AC42NjY2NjY2NjYxAAAAAAA8PT09PT09PT09Pv//AAD4BwAA+AcAAAgHAAAABwAAAAcAAAAAAAAAAAAA + AAAAAAAAAAD4AAAA+AAAAPgAAAD4AAAA+AAAAPgAAACJUE5HDQoaCgAAAA1JSERSAAABAAAAAQAIBgAA + AFxyqGYAAA0ASURBVHja7dp1tJdFHsfxi4KigihggB3YPXSrlL1u79rd2B3Y3Qp2YGzvuiLdl7i03dgF + SkiJICB7OHvOXWbv3HNmfs/3eWbmN+/XH/ecz3/f4fC8+YNbpwJAsuqs+TF9+urVvg8BUKyWLevUqQ5A + o0a+zwFQlIULKyrWfPNaAFq0+G8QAJS3Nd98/foEAEjSmm++Xj0CACRpzTdfty4BAJJEAICEEYAMXjqm + gv82RZSOfvF/3zwBKBEBQKwIgAACgFgRAAEEALEiAAIIAGJFAASYAnBUv26+zwJqePnskdomAAIIAGJB + AHJgDEBfAoDwvHwOARBHABALApADUwCOJAAI0AACIM8YgIcJAMIz4FwCII4AIBYEIAfGADxEABCeAecR + AHEEALEgADkwBeCIBwkAwvNKbwIgjgAgFgQgBwQAsSAAOTAG4AECgPC8cj4BEEcAEAsCkANTAA6/v7vv + s4AaBl4wQtsEQAABQCwIQA6MAbiPACA8Ay8kAOIIAGJBAHJAABALApADUwAOu5cAIDyDLiIA4ggAYkEA + cmAMwD0EAOEZdDEBEEcAEAsCkANjAO4mAAjPoEsIgDhTAA4lAAjQYAIgjwAgFgQgB8YA3EUAEJ7BlxIA + cQQAsSAAOTAG4E4CgPAMvowAiDMF4BACgAANIQDyjAG4gwAgPEMuJwDiCABiQQByQAAQCwKQA2MAbicA + CM+QKwiAOAKAWBCAHJgC0Os2AoDwDL2SAIgjAIgFAciBMQC3EgCEZ+hVBEAcAUAsCEAOCABiQQByYApA + z1sIAMIz7GoCII4AIBYEIAfGANxMABCeYdcQAHEEALEgADkwBuAmAoDwDLuWAIgzBaAHAUCAhhMAeQQA + sSAAOTAG4EYCgPAMv44AiCMAiAUByIExADcQAIRneB8CIM4UgO439PB9FlDDiD7DtU0ABBgDcD0BQHhG + XE8AxBEAxIIA5IAAIBYEIAfGAPQhAAjPiBsIgDhTALoRAARoJAGQZwzAdQQA4Rl5IwEQRwAQCwKQA2MA + riUACM/ImwiAOAKAWBCAHJgCcDABQIBGEQB5xgBcQwAQnlE3EwBxBACxIAA5MAbgagKA8Iy6hQCIIwCI + BQHIgSkAB11FABCe0bcSAHEEALEgADkgAIgFAciBMQBXEgCEZ/RtBEAcAUAsCEAOTAE48AoCgPCMuZ0A + iCMAiAUByIExAJcTAIRnzB0EQBwBQCwIQA6MAbiMACA8Y+4kAOJMAehKABCgsQRAHgFALAhADowBuJQA + IDxj7yIA4ggAYkEAcmAMwCUEAOEZezcBEGcKQBcCgABVEgB5xgBcTAAQnsp7CIA4AoBYEIAcEADEggDk + wBiAiwgAwlN5LwEQZwpA54t6+j4LqGHcvcO0TQAEGANwIQFAeMbdRwDEEQDEggDkwBiACwgAwjPufgIg + jgAgFiUHoL+q+ZccFRUnzKioYwpAJwKAAI0nALJqDcD5BADhGf8AARBFABATAiCs1gD0JgAIz/gHCYAo + AoCYiAagyza+n1O8yi/1XVsAOp5HABCeCQ9JBmBr388pXuVX+iYAiIloADonGIBxBAAREw1ApwQDMN42 + AOcSAIRnwsOCAei4le/nFG/C1/omAIgJAcjINgAdziEACM/EvoIB6JBgACYSAERMNADtEwxAlW0AziYA + CM/EfpIBaO77OcWr+kbfBAAxEQ1AuwQDMIkAIGKiAWibYAAm2wbgLAKA8Ex8RDIAzXw/p3iTZ+m7tgC0 + JwAIUJVkANokGIAptgE4kwAgPFWPCgagdYIBmEoAEDHRALTa0vdzijdttr5rDcAZBADhqXqMAGRCABAz + 0QC0TDAA0y0D0I4AIECTJAOgtvD9nOLN+FbftQbgdAKA8Ex6nABkQgAQM9EAHJBgAF61DcBpBADhmfSE + YAD239z3c4r32nf6JgCICQHIyDYAbU8lAAjP5CcFA7BfggF4nQAgYqIB2Hcz388p3htz9E0AEBMCkJF1 + AE4hAAjP5KcEA7BPggF4kwAgYqIB2DvBALxlGYA2J/fyfSpQw5Snh2o7UwD2aur7OcV7e66+CQBiQgAy + sg7ASQQA4ZnyjGAA9kwwAO8QAERMNAB7NPH9nOK9O0/fBAAxIQAZ2Qag9YkEAOGZ+qxgAHZPMADvEQBE + TDQAuzX2/ZzivT9f37UG4AQCgPBM7U8AMiEAiJloAHZNMAAf2AbgeAKA8Ex9TjAAu2zq+znF+/B7fdcW + gFYEAAGaRgCyIQCImWgAWiQYgJm2ATiOACA8054XDMDOm/h+TvE+WqBvAoCYiAZgpwQD8LFtAI4lAAjP + tBcIQCa2AQBikCkAOzbyfX7xPlmobwKAmGUKwA4JBuBTAoAyQgAcEQCUk0wB2D7BAHxmCIDvm4CsSgrA + dhv7Prt4ny/SNwFAOSAAlggAylFJAdg2wQB8QQBQhkoKwDYNfZ9dvC8X65sAoByUFICtEwzAVwQAZYgA + WCIAKEclBWCrBr7PLt7XS/RtGwClTud3BcrQjBmPl8U/ACUFoHmCAfiGAGAtBCAxBABrSzoAzTbyfXbx + Zv2gbwKQtqQDsGWCAZhNALAWApAYyQDMOLy37+fAkRr4oLaTDsAWG/o+u3jfLtV3pgAcdp7v58CRGvSQ + tpMOwOYJBuA7yQAcSgBiowYTgGoEIGMADjnX93PgSA15WNtJB2CzDXyfXbw5P+o7UwB6neP7OXCkhvbV + dtIBaJpgAOZKBqDn2b6fA0dqWD9tJx2AJgkGYJ5kAHoQgNio4QSgGgHIGIDuZ/l+DhypEY9oO+kANK7v + ++zizV+m70wB6Ham7+fAkRr5qLaTDsCmCQbge8kAHHyG7+fAkRr1mLYJQGIIQNoIwFo2Wd/32cVbsFzf + mQJw0Om+nwNHavTj2k46AI0SDMBCyQAceJrv58CRGvOEtglAYkQD0PVU38+BIzX2SW0nHYCN1/N9dvEW + /aTvTAHoQgBioyoJQLWGCQZgsWQAOp/i+zlwpMY9pW0CkBjRAHQ62fdz4EiNf1rbSQegQT3fZxdvyQp9 + ZwpAx5N8PweO1IRntJ10ADZKMAA/SAagAwGIjZpIAKptmGAAlkoGoP2Jvp8DR6rqWW2nHYC6vs8u3tKV + +s4UgHYn+H4OHKlJ/bWddAA2SDAAP0oGoO3xvp8DR2ryc9pOOgD1EwzAMskAtCEAsVFTCEC1+uv6Prt4 + y1bpO1MAWh/n+zlwpKY+r+2kA7B+ggFYLhmAVsf6fg4cqWkvaDvpAKyXYAB+kgxAy2N8PweO1PQXtU0A + EiMaAEUAYqNmEIBq9dbxfXbxVvys70wBOOCPvp8DR+rVP2k76QDUTTAAKyUDsP8ffD8HjtRrf9Z20gFY + N8EArJIMwH6/9/0cOFKv/0XbaQegLJ7uZtX//SlkCsC+BCA26g0CUG2dsni6m58lA7DP73w/B47Um3/V + dtIBQMYA7P1b3+fDkXrrb9omAInLFIC9fuP7fDhSb/9d2wQgcZkCsCcBiI16hwBgLZkCsMevfZ8PR+rd + f2g7mQAgG2MAdv+V77PgSL33T20TAFgxBmC3X/o+C47U+//SNgGAFQJQHggASmIMwK5H+z4LjtQHL2mb + AMCKMQC7/ML3WXCkPvy3tgkArBgD0OIo32fBkZr5srYJAKwYA7AzAYiN+ogAoATGAOx0pO+z4Eh9PEDb + BABWjAHY8QjfZ8GR+uQVbRMAWDEGYIfDfZ8FR+rTgdomALBiDMD2BCA26jMCgBIYA7DdYb7PgiP1+SBt + EwBYMQZg20N9nwVH6ovB2iYAsGIMwDaH+D4LjtSXQ7RNAGDFGICtCUBs1FcEACUwBmCrXr7PgiP19VBt + EwBYMQageU/fZ8GR+maYtgkArBgD0KyH77PgSM0arm0CACvGAGxJAGKjZhMAlMAYgC26+z4LjtS3I7RN + AGDFGIDNu/k+C47UdyO1TQBgxRiAzQ72fRYcqTmjtE0AYMUYgKYEIDZqLgFACYwBaHKQ77PgSM0brW0C + ACvGADQ+0PdZcKTmj9E2AYAVYwA27er7LDhS34/VNgGAFWMANunq+yw4UgvGapsAwIoxAI26+D4LjtTC + Sm0TAFgxBmDjzr7PgiO1aJy2CQCsGAPQsJPvs+BILR6vbQIAKwSgPBAAlMQYgAYdfZ8FR2rJBG0TAFgx + BmCjDr7PgiP1w0RtEwBYMQZgw/a+z4IjtbRK2wQAVowB2IAAxEb9SABQAmMA6rfzfRYcqWWTtE0AYMUY + gPXb+j4LjtTyydomALBiDMB6bXyfBUfqpynaJgCwYgxAPQIQG7WCAKAExgDUbe37LDhSK6dqmwDAijEA + 67byfRYcqVXTtE0AYMUUAMSPAMAKAShPBABWCEB5IgCwQgDKEwEAED0CACSMAAAJIwBAwggAkDACACSM + AAAJIwBAwmoEwPdBAIpVHYA1Zs5cvXr58oqKVasqKsgBkIb/AA/38rf1PkgbAAAAAElFTkSuQmCCKAAA + ADAAAABgAAAAAQAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7i4gAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7g + 4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAGYzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2Yz + M2YzM2YzM2YzM2YzM2YzM2YzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM5o5A546AJ46AJ46AJ46AJ46AJ46 + AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AGYzMwAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AGYzM54+A6I/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/ + AKI/AGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM6JCA6ZDAKZDAKZDAKZDAKZDAKZDAKZDAKZDAKZDAKZD + AKZDAKZDAKZDAKZDAKZDAKZDAKZDAKZDAKZDAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM6ZHA6pJAKpJ + AKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAGYzMwAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAGYzM6lMA65OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5O + AK5OAK5OAK5OAK5OAK5OAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM61RA7JTALJTALJTALJTALJTALJT + ALJTALJTALJTALJTALJTALJTALJTALJTALJTALJTALJTALJTALJTAGYzMwAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AGYzM7FWA7ZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZ + ALZZAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQAzoQAzoQAzoQAzoQAzoQAz + oQAzoQAzoQAzoQAzoQAzoQAzoQAAAAAAAGYzM7RaA7pdALpdALpdALpdALpdALpdALpdALpdALpdALpd + ALpdALpdALpdALpdALpdALpdALpdALpdALpdAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAzoQA0owA0pAA0pAA0pAA0pAA0pAA0pAA0pAA0pAA0pAA0pAAzoQAAAAAAAGYzM7hfA75iAL5i + AL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAGYzMwAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQA2pwA2qAA2qAA2qAA2qAA2qAA2qAA2qAA2qAA2 + qAA2qAAzoQAAAAAAAGYzM7xkA8JoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJo + AMJoAMJoAMJoAMJoAMJoAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQA3qwA3 + qwA3qwA3qwA3qwA3qwA3qwA3qwA3qwA3qwA3qwAzoQAAAAAAAGYzM8BpA8ZtAMZtAMZtAMZtAMZtAMZt + AMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAGYzMwAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAzoQA5rgA5rwA5rwA5rwA5rwA5rwA5rwA5rwA5rwA5rwA5rwAzoQAAAAAA + AGYzM8NuA8pyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpy + AMpyAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQA6sQA7swA7swA7swA7swA7 + swA7swA7swA7swA7swA7swAzoQAAAAAAAGYzM8dzA853AM53AM53AM53AM53AM53AM53AM53AM53AM53 + AM53AM53AM53AM53AM53AM53AM53AM53AM53AGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAzoQA8tQA8tgA8tgA8tgA8tgA8tgA8tgA8tgA8tgA8tgA8tgAzoQAAAAAAAGYzM8t3A9J8ANJ8 + ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8AGYzMwAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQA9uAA+ugA+ugA+ugA+ugA+ugA+ugA+ugA+ugA+ + ugA+ugAzoQAAAAAAAGYzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2Yz + M2YzM2YzM2YzM2YzM2YzM2YzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQA/vABA + vgBAvgBAvgBAvgBAvgBAvgBAvgBAvgBAvgBAvgAzoQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAzoQBBvwBBwQBBwQBBwQBBwQBBwQBBwQBBwQBBwQBBwQBBwQAzoQBbrwBb + rwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBb + rwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbr7rH3wAAAAAzoQBCwwBDxQBDxQBDxQBDxQBD + xQBDxQBDxQBDxQBDxQBDxQAzoQBbr0i45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei4 + 5Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45ABbr6y8 + 2QAAAAAzoQBExgBFyQBFyQBFyQBFyQBFyQBFyQBFyQBFyQBFyQBFyQAzoQBbr0i65Ui65Ui65Ui65Ui6 + 5Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui6 + 5Ui65Ui65Ui65Ui65Ui65Ui65QBbr6y82QAAAAAzoQBFygBHzABHzABHzABHzABHzABHzABHzABHzABH + zABHzAAzoQBbr0i85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki8 + 5ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85gBbr6y82QAAAAAzoQBHzQBI + 0ABI0ABI0ABI0ABI0ABI0ABI0ABI0ABI0ABI0AAzoQBbr0i/50i/50i/50i/50i/50i/50i/50i/50i/ + 50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/ + 50i/50i/5wBbr6y82QAAAAAzoQBI0QBK1ABK1ABK1ABK1ABK1ABK1ABK1ABK1ABK1ABK1AAzoQBbr0fB + 6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB + 6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6ABbr6y82QAAAAAzoQBK1ABM2ABM2ABM2ABM2ABM + 2ABM2ABM2ABM2ABM2ABM2AAzoQBbr0fD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD + 6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6QBbr6y8 + 2QAAAAAzoQBM2ABN2wBN2wBN2wBN2wBN2wBN2wBN2wBN2wBN2wBN2wAzoQBbr0fF6kfF6kfF6kfF6kfF + 6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF + 6kfF6kfF6kfF6kfF6kfF6kfF6gBbr6y82QAAAAAzoQBGzABIzwBIzwBIzwBIzwBIzwBIzwBIzwBIzwBI + zwBIzwAzoQBbr0fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI + 60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI6wBbr6y82QAAAAAzoQAzoQAz + oQAzoQAzoQAzoQAzoQAzoQAzoQAzoQAzoQAzoQAzoQBbr0fK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK + 7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK + 7EfK7EfK7ABbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0fM + 7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM + 7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7QBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAABbr0bO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO + 7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7gBbr6y8 + 2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0bR70bR70bR70bR70bR + 70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR + 70bR70bR70bR70bR70bR70bR7wBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAABbr0bT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT + 8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8ABbr6y82QAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0bV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV + 8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV + 8kbV8kbV8gBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0bX + 80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX + 80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX8wBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAABbr0ba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba + 9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9ABbr6y8 + 2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Xc9UXc9UXc9UXc9UXc + 9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc + 9UXc9UXc9UXc9UXc9UXc9UXc9QBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAABbr0Xe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe + 9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9gBbr6y82QAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg + 90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg + 90Xg90Xg9wBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Xj + +EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj + +EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+ABbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAABbr0Xl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl + +UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+QBbr6y8 + 2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Xn+kXn+kXn+kXn+kXn + +kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn + +kXn+kXn+kXn+kXn+kXn+kXn+gBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAABbr0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp + +0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+wBbr6y82QAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Ts/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs + /ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs + /ETs/ETs/ABbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Tu + /UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu + /UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/QBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAABbr0Tw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw + /kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/gBbr669 + 2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbrwBbrwBbrwBbrwBbrwBb + rwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBb + rwBbrwBbrwBbrwBbrwBbrwBbrwBbr+XZ4gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7i4n///////g7u//// + ////Du7//wAAA/8O7v//AAAD/w7u//8AAAP/Du7//wAAA/8O7v//AAAD/w7u//8AAAP/Du7//wAAA/8O + 7v//AAAD/w7ugAMAAAP/Du6AAwAAA/8O7oADAAAD/w7ugAMAAAP/Du6AAwAAA/8O7oADAAAD/w7ugAMA + AAP/Du6AAwAAA/8O7oAD/////w7ugAAAAAAADu6AAAAAAAAO7oAAAAAAAA7ugAAAAAAADu6AAAAAAAAO + 7oAAAAAAAA7ugAAAAAAADu6AAAAAAAAO7oAAAAAAAA7ugAAAAAAADu7//AAAAAAO7v/8AAAAAA7u//wA + AAAADu7//AAAAAAO7v/8AAAAAA7u//wAAAAADu7//AAAAAAO7v/8AAAAAA7u//wAAAAADu7//AAAAAAO + 7v/8AAAAAA7u//wAAAAADu7//AAAAAAO7v/8AAAAAA7u//wAAAAADu7//AAAAAAO7v/8AAAAAA7u//wA + AAAADu7///////4O7igAAAAgAAAAQAAAAAEAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzMAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmMzOfOwCfOwCfOwCfOwCfOwCfOwCf + OwCfOwCfOwCfOwCfOwCfOwBmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABmMzOkQQCkQQCkQQCkQQCkQQCkQQCkQQCkQQCkQQCkQQCkQQCkQQBmMzOxmJgA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmMzOrSgCrSgCr + SgCrSgCrSgCrSgCrSgCrSgCrSgCrSgCrSgCrSgBmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmMzOwUQCwUQCwUQCwUQCwUQCwUQCwUQCwUQCwUQCwUQCw + UQCwUQBmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABmMzO3WgC3WgC3WgC3WgC3WgC3WgC3WgC3WgC3WgC3WgC3WgC3WgBmMzOxmJgAAAAAAAAAAAAAAAAA + AAAAAADHu9QAM6EAM6EAM6EAM6EAM6EAM6EAM6EAM6EAAAAAAABmMzO8YAC8YAC8YAC8YAC8YAC8YAC8 + YAC8YAC8YAC8YAC8YAC8YABmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAADHu9QAM6EANqkANqkANqkANqkA + NqkANqkAM6F/mM8AAABmMzPDaQDDaQDDaQDDaQDDaQDDaQDDaQDDaQDDaQDDaQDDaQDDaQBmMzOxmJgA + AAAAAAAAAAAAAAAAAAAAAADHu9QAM6EAOK0AOK0AOK0AOK0AOK0AOK0AM6F/mM8AAABmMzPIcADIcADI + cADIcADIcADIcADIcADIcADIcADIcADIcADIcABmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAADHu9QAM6EA + O7QAO7QAO7QAO7QAO7QAO7QAM6F/mM8AAABmMzPPeADPeADPeADPeADPeADPeADPeADPeADPeADPeADP + eADPeABmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAADHu9QAM6EAPbgAPbgAPbgAPbgAPbgAPbgAM6F/mM8A + AABmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzOxmJgAAAAAAAAAAAAAAAAA + AAAAAADHu9QAM6EAQL8AQL8AQL8AQL8AQL8AQL8AM6FVfMEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADHu9QAM6EAQsMAQsMAQsMAQsMA + QsMAQsMAM6EAW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68A + W68AW68AW68AW68AW6+BpM7Hu9QAM6EARcoARcoARcoARcoARcoARcoAM6EAW69IuuVIuuVIuuVIuuVI + uuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuUAW698oMzHu9QAM6EA + R84AR84AR84AR84AR84AR84AM6EAW69IvuZIvuZIvuZIvuZIvuZIvuZIvuZIvuZIvuZIvuZIvuZIvuZI + vuZIvuZIvuZIvuZIvuZIvuZIvuZIvuYAW698oMzHu9QAM6EAStUAStUAStUAStUAStUAStUAM6EAW69H + wehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwegA + 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 + SH08XNsEAFaMAdioj++z4Eh9MkLbBABWjAHYsLfvs+BIzR6pbQIAK8YAbEAAYqPmEACUwBiAFr18nwVH + au4obRMAWDEGYP2evs+CI/XpaG0TAFgxBmC9Hr7PgiM1b4y2CQCsGAOwLgGIjfqMAKAExgCss6fvs+BI + fT5W2wQAVowBaL6H77PgSH0xTtsEAFaMAWjW3fdZcKS+HK9tAgArxgA07e77LDhS88drmwDAijEAa3fz + fRYcqQVV2iYAsGIMQJOuvs+CI/XVBG0TAFgxBmCtLr7PgiP19URtEwBYIQDlgQCgJMYArNnZ91lwpL6Z + pG0CACvGAKzRyfdZcKQWTtY2AYAVYwBW7+j7LDhSi6q1TQBgxRiA1QhAbNRiAoASGAPQuIPvs+BILZmi + bQIAK8YArNre91lwpL6t0TYBgBVjAFZp5/ssOFLfTdU2AYAVYwBWJgCxUd8TAJTAGIBGbX2fBUfqh2na + JgCwYgzASm18nwVHaul0bRMAWDEFAPEjALBCAMoTAYAVAlCeCACsEIDyRAAARI8AAAkjAEDCCACQMAIA + JIwAAAkjAEDCCACQMFMAAKRlbv1PNdVF4Jm637at+5rUfY3qvrL4iScADfsZgOX03tj+IOMAAAAASUVO + RK5CYIIoAAAAMAAAAGAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/svLi/7Ly2D+y8tb/svL + W/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svL + W/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svL + W/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8uU/svL + ev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AGUyMhxlMjIgZTIyIGUyMiBlMjIgZTIyIGUyMiBlMjIgZTIyIGUyMiBlMjIgZTIyIGUyMiBlMjIgZTIy + IGUyMiBlMjIgZTIyIGUyMiBlMjIgZTIyIGUyMiBlMjIIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAGYzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz + /2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM/+aOQP/njoA/546AP+eOgD/njoA/546AP+eOgD/njoA + /546AP+eOgD/njoA/546AP+eOgD/njoA/546AP+eOgD/njoA/546AP+eOgD/njoA/2YzM/9lMjJAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM/+ePgP/oj8A/6I/AP+iPwD/oj8A + /6I/AP+iPwD/oj8A/6I/AP+iPwD/oj8A/6I/AP+iPwD/oj8A/6I/AP+iPwD/oj8A/6I/AP+iPwD/oj8A + /2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLev7LywgAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM/+iQgP/pkMA + /6ZDAP+mQwD/pkMA/6ZDAP+mQwD/pkMA/6ZDAP+mQwD/pkMA/6ZDAP+mQwD/pkMA/6ZDAP+mQwD/pkMA + /6ZDAP+mQwD/pkMA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svL + ev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AGYzM/+mRwP/qkkA/6pJAP+qSQD/qkkA/6pJAP+qSQD/qkkA/6pJAP+qSQD/qkkA/6pJAP+qSQD/qkkA + /6pJAP+qSQD/qkkA/6pJAP+qSQD/qkkA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAGYzM/+pTAP/rk4A/65OAP+uTgD/rk4A/65OAP+uTgD/rk4A/65OAP+uTgD/rk4A + /65OAP+uTgD/rk4A/65OAP+uTgD/rk4A/65OAP+uTgD/rk4A/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM/+tUQP/slMA/7JTAP+yUwD/slMA/7JTAP+yUwD/slMA + /7JTAP+yUwD/slMA/7JTAP+yUwD/slMA/7JTAP+yUwD/slMA/7JTAP+yUwD/slMA/2YzM/9lMjJAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM/+xVgP/tlkA/7ZZAP+2WQD/tlkA + /7ZZAP+2WQD/tlkA/7ZZAP+2WQD/tlkA/7ZZAP+2WQD/tlkA/7ZZAP+2WQD/tlkA/7ZZAP+2WQD/tlkA + /2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AM6H/ADOh + /wAzof8AM6H/ADOh/wAzof8AM6H/ADOh/wAzof8AM6H/ADOh/wAzof8AMqAsAAAAAGYzM/+0WgP/ul0A + /7pdAP+6XQD/ul0A/7pdAP+6XQD/ul0A/7pdAP+6XQD/ul0A/7pdAP+6XQD/ul0A/7pdAP+6XQD/ul0A + /7pdAP+6XQD/ul0A/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svL + egAzof8ANKP/ADSk/wA0pP8ANKT/ADSk/wA0pP8ANKT/ADSk/wA0pP8ANKT/ADSk/wAzof8AMqBAAAAA + AGYzM/+4XwP/vmIA/75iAP++YgD/vmIA/75iAP++YgD/vmIA/75iAP++YgD/vmIA/75iAP++YgD/vmIA + /75iAP++YgD/vmIA/75iAP++YgD/vmIA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAD+y8tb/svLegAzof8ANqf/ADao/wA2qP8ANqj/ADao/wA2qP8ANqj/ADao/wA2qP8ANqj/ADao + /wAzof8AMqBAAAAAAGYzM/+8ZAP/wmgA/8JoAP/CaAD/wmgA/8JoAP/CaAD/wmgA/8JoAP/CaAD/wmgA + /8JoAP/CaAD/wmgA/8JoAP/CaAD/wmgA/8JoAP/CaAD/wmgA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AN6v/ADer/wA3q/8AN6v/ADer/wA3q/8AN6v/ADer + /wA3q/8AN6v/ADer/wAzof8AMqBAAAAAAGYzM//AaQP/xm0A/8ZtAP/GbQD/xm0A/8ZtAP/GbQD/xm0A + /8ZtAP/GbQD/xm0A/8ZtAP/GbQD/xm0A/8ZtAP/GbQD/xm0A/8ZtAP/GbQD/xm0A/2YzM/9lMjJAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AOa7/ADmv/wA5r/8AOa//ADmv + /wA5r/8AOa//ADmv/wA5r/8AOa//ADmv/wAzof8AMqBAAAAAAGYzM//DbgP/ynIA/8pyAP/KcgD/ynIA + /8pyAP/KcgD/ynIA/8pyAP/KcgD/ynIA/8pyAP/KcgD/ynIA/8pyAP/KcgD/ynIA/8pyAP/KcgD/ynIA + /2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AOrH/ADuz + /wA7s/8AO7P/ADuz/wA7s/8AO7P/ADuz/wA7s/8AO7P/ADuz/wAzof8AMqBAAAAAAGYzM//HcwP/zncA + /853AP/OdwD/zncA/853AP/OdwD/zncA/853AP/OdwD/zncA/853AP/OdwD/zncA/853AP/OdwD/zncA + /853AP/OdwD/zncA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svL + egAzof8APLX/ADy2/wA8tv8APLb/ADy2/wA8tv8APLb/ADy2/wA8tv8APLb/ADy2/wAzof8AMqBAAAAA + AGYzM//LdwP/0nwA/9J8AP/SfAD/0nwA/9J8AP/SfAD/0nwA/9J8AP/SfAD/0nwA/9J8AP/SfAD/0nwA + /9J8AP/SfAD/0nwA/9J8AP/SfAD/0nwA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAD+y8tb/svLegAzof8APbj/AD66/wA+uv8APrr/AD66/wA+uv8APrr/AD66/wA+uv8APrr/AD66 + /wAzof8AMqBAAAAAAGYzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz + /2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AP7z/AEC+/wBAvv8AQL7/AEC+/wBAvv8AQL7/AEC+ + /wBAvv8AQL7/AEC+/wAzof8AMqBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AQb//AEHB/wBBwf8AQcH/AEHB + /wBBwf8AQcH/AEHB/wBBwf8AQcH/AEHB/wAzof8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/+InsiS/svLegAzof8AQsP/AEPF + /wBDxf8AQ8X/AEPF/wBDxf8AQ8X/AEPF/wBDxf8AQ8X/AEPF/wAzof8AW6//SLjk/0i45P9IuOT/SLjk + /0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/0i45P9IuOT/SLjk + /0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/wBbr/9+mMWk/svL + egAzof8ARMb/AEXJ/wBFyf8ARcn/AEXJ/wBFyf8ARcn/AEXJ/wBFyf8ARcn/AEXJ/wAzof8AW6//SLrl + /0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl + /0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl + /wBbr/9+mMWk/svLegAzof8ARcr/AEfM/wBHzP8AR8z/AEfM/wBHzP8AR8z/AEfM/wBHzP8AR8z/AEfM + /wAzof8AW6//SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm + /0i85v9IvOb/SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm + /0i85v9IvOb/SLzm/wBbr/9+mMWk/svLegAzof8AR83/AEjQ/wBI0P8ASND/AEjQ/wBI0P8ASND/AEjQ + /wBI0P8ASND/AEjQ/wAzof8AW6//SL/n/0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n + /0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n + /0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n/wBbr/9+mMWk/svLegAzof8ASNH/AErU/wBK1P8AStT/AErU + /wBK1P8AStT/AErU/wBK1P8AStT/AErU/wAzof8AW6//R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho + /0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho + /0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/wBbr/9+mMWk/8zMegAzof8AStT/AEzY + /wBM2P8ATNj/AEzY/wBM2P8ATNj/AEzY/wBM2P8ATNj/AEzY/wAzof8AW6//R8Pp/0fD6f9Hw+n/R8Pp + /0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp + /0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/wBbr/9+mMWk/8zM + egAzof8ATNj/AE3b/wBN2/8ATdv/AE3b/wBN2/8ATdv/AE3b/wBN2/8ATdv/AE3b/wAzof8AW6//R8Xq + /0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq + /0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq + /wBbr/9+mMWk/8zMegAzof8ARsz/AEjP/wBIz/8ASM//AEjP/wBIz/8ASM//AEjP/wBIz/8ASM//AEjP + /wAzof8AW6//R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr + /0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr + /0fI6/9HyOv/R8jr/wBbr/9+mMWk/8zMegAzof8AM6H/ADOh/wAzof8AM6H/ADOh/wAzof8AM6H/ADOh + /wAzof8AM6H/ADOh/wAzof8AW6//R8rs/0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs + /0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs + /0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//R8zt/0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt + /0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt + /0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Rs7u/0bO7v9Gzu7/Rs7u + /0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u + /0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/wBbr/9+mMWk/8zM + ev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//RtHv + /0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv + /0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv + /wBbr/9+mMWk/8zMev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAW6//RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw + /0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw + /0bT8P9G0/D/RtPw/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAW6//RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy + /0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy + /0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Rtfz/0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz + /0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz + /0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Rtr0/0ba9P9G2vT/Rtr0 + /0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0 + /0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/wBbr/9+mMWk/svL + ev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Rdz1 + /0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1 + /0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1 + /wBbr/9+mMWk/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAW6//Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72 + /0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72 + /0Xe9v9F3vb/Rd72/wBbr/9+mMWk/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAW6//ReD3/0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3 + /0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3 + /0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3/wBbr/9+mMWk/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4 + /0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4 + /0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/wBbr/9+mMWk/svLev7LywgAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//ReX5/0Xl+f9F5fn/ReX5 + /0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5 + /0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/wBbr/9+mMWk/svL + ev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Ref6 + /0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6 + /0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6 + /wBbr/9+mMWk/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAW6//ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7 + /0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7 + /0Tp+/9E6fv/ROn7/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAW6//ROz8/0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8 + /0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8 + /0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8/wBbr/9+mMWk/svLev/LywgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//RO79/0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79 + /0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79 + /0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79/wBbr/9+mMWk/svLev7LywgAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//RPD+/0Tw/v9E8P7/RPD+ + /0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+ + /0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/wBbr/+BmMSi/svL + ev7Lyw7+y8sI/8zMCP/MzAj+y8sI/svLCP7Lywj+y8sI/svLCP7Lywj+y8sI/8zMCP/MzAgAW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr//NtcaA/svLfP/Ly3r+y8t6/8zMev/MzHr+y8t6/svLev7Ly3r+y8t6/svLev7Ly3r+y8t6/8zM + ev/MzHr/zMx6/8zMev/MzHr/zMx6/8zMev/MzHr/zMx6/8zMev/MzHr+y8t6/svLev7Ly3r+y8t6/svL + ev7Ly3r+y8t6/svLev7Ly3r+y8t6/svLev7Ly3r+y8t6/svLev7Ly3r+y8t6/svLev7Ly3r+y8t6/svL + ev7Ly3r+y8t6/svLev7Ly3r+y8uLAAAAAAAADu4//wAAAf4O7j//AAAB/g7uP/8AAAH+Du4//wAAAf4O + 7j//AAAB/g7uP/8AAAH+Du4//wAAAf4O7j//AAAB/g7uP/8AAAH+Du4AAQAAAf4O7gABAAAB/g7uAAEA + AAH+Du4AAQAAAf4O7gABAAAB/g7uAAEAAAH+Du4AAQAAAf4O7gABAAAB/g7uAAH////+Du4AAAAAAAAO + 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 + PamYvaYAM6H/AEC//wBAv/8AQL//AEC//wBAv/8AQL//ADOh/wA7o6oAW69VAFuvVQBbr1UAW69VAFuv + VQBbr1UAW69VAFuvVQBbr1UAW69VAFuvVQBbr1UAW69VAFuvVQBbr1UAW69VAFuvVQBbr1UAW69VAFuv + VQBbr1WsqMRlqZi9pgAzof8AQsP/AELD/wBCw/8AQsP/AELD/wBCw/8AM6H/AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/1aFvr6pmL2mADOh/wBFyv8ARcr/AEXK/wBFyv8ARcr/AEXK/wAzof8AW6//SLrl + /0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl + /0i65f9IuuX/SLrl/0i65f8AW6//VIO9wqmYvaYAM6H/AEfO/wBHzv8AR87/AEfO/wBHzv8AR87/ADOh + /wBbr/9Ivub/SL7m/0i+5v9Ivub/SL7m/0i+5v9Ivub/SL7m/0i+5v9Ivub/SL7m/0i+5v9Ivub/SL7m + /0i+5v9Ivub/SL7m/0i+5v9Ivub/SL7m/wBbr/9Ug73CqZi9pgAzof8AStX/AErV/wBK1f8AStX/AErV + /wBK1f8AM6H/AFuv/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho + /0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/AFuv/1SDvcKqmb2mADOh/wBM2v8ATNr/AEza + /wBM2v8ATNr/AEza/wAzof8AW6//R8Tp/0fE6f9HxOn/R8Tp/0fE6f9HxOn/R8Tp/0fE6f9HxOn/R8Tp + /0fE6f9HxOn/R8Tp/0fE6f9HxOn/R8Tp/0fE6f9HxOn/R8Tp/0fE6f8AW6//VIO9wqqZvaYAM6H/ADOh + /wAzof8AM6H/ADOh/wAzof8AM6H/ADOh/wBbr/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr + /0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/wBbr/9Ug73C4rvH + b15rsFcAM6FVADOhVQAzoVUAM6FVADOhVQAzoVUAM6FVAFuv/0fL7P9Hy+z/R8vs/0fL7P9Hy+z/R8vs + /0fL7P9Hy+z/R8vs/0fL7P9Hy+z/R8vs/0fL7P9Hy+z/R8vs/0fL7P9Hy+z/R8vs/0fL7P9Hy+z/AFuv + /1SDvcL/zMxU/8zMAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Rs/u/0bP7v9Gz+7/Rs/u + /0bP7v9Gz+7/Rs/u/0bP7v9Gz+7/Rs/u/0bP7v9Gz+7/Rs/u/0bP7v9Gz+7/Rs/u/0bP7v9Gz+7/Rs/u + /0bP7v8AW6//VIO9wv/MzFT/zMwDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr/9G0u//RtLv + /0bS7/9G0u//RtLv/0bS7/9G0u//RtLv/0bS7/9G0u//RtLv/0bS7/9G0u//RtLv/0bS7/9G0u//RtLv + /0bS7/9G0u//RtLv/wBbr/9Ug73C/8zMVP/MzAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFuv + /0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy + /0bV8v9G1fL/RtXy/0bV8v9G1fL/AFuv/1SDvcL/zMxU/8zMAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAW6//Rtnz/0bZ8/9G2fP/Rtnz/0bZ8/9G2fP/Rtnz/0bZ8/9G2fP/Rtnz/0bZ8/9G2fP/Rtnz + /0bZ8/9G2fP/Rtnz/0bZ8/9G2fP/Rtnz/0bZ8/8AW6//VIO9wv7Ly1T+y8sDAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABbr/9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1 + /0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/wBbr/9Ug73C/svLVP7LywMAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAFuv/0Xf9v9F3/b/Rd/2/0Xf9v9F3/b/Rd/2/0Xf9v9F3/b/Rd/2 + /0Xf9v9F3/b/Rd/2/0Xf9v9F3/b/Rd/2/0Xf9v9F3/b/Rd/2/0Xf9v9F3/b/AFuv/1SDvcL+y8tU/svL + AwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4 + /0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P8AW6//VIO9 + wv7Ly1T+y8sDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr/9F5vn/Reb5/0Xm+f9F5vn/Reb5 + /0Xm+f9F5vn/Reb5/0Xm+f9F5vn/Reb5/0Xm+f9F5vn/Reb5/0Xm+f9F5vn/Reb5/0Xm+f9F5vn/Reb5 + /wBbr/9Ug73C/svLVP7LywMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFuv/0Tq+/9E6vv/ROr7 + /0Tq+/9E6vv/ROr7/0Tq+/9E6vv/ROr7/0Tq+/9E6vv/ROr7/0Tq+/9E6vv/ROr7/0Tq+/9E6vv/ROr7 + /0Tq+/9E6vv/AFuv/1SDvcL+y8tU/8vLAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//RO38 + /0Tt/P9E7fz/RO38/0Tt/P9E7fz/RO38/0Tt/P9E7fz/RO38/0Tt/P9E7fz/RO38/0Tt/P9E7fz/RO38 + /0Tt/P9E7fz/RO38/0Tt/P8AW6//VIO9wv7Ly1X+y8sF/8zMA/7LywP+y8sD/svLA/7LywP+y8sD/8zM + AwBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/9mir25/svLb/7Ly1X/zMxU/svLVP7Ly1T+y8tU/svL + VP7Ly1T/zMxUxrLFi6qmwqaqpsKmqqbCpqqmwqaqpsKmqaXBpqmlwaappcGmqaXBpqmlwaappcGmqaXB + pqmlwaappcGmqaXBpqmlwaappcGmqaXBpqmlwaappcGmqaXBpta5xpIAAAAAP8AAPj/AAD4/wAA+P8AA + Pj/AAD4AAAA+AAAAPgAAAD4AAAA+AAAAPgAAAD4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAAAAAAAAAAAACgAAAAQAAAAIAAA + AAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tB/svLHv7Lyx7+y8se/svLHp1qanCYZWWjmGVl + o5hlZaOYZWWjmGVlo5hlZaOYZWV4/svLHv7Lyx7+y8s5/svLLAAAAAAAAAAAAAAAAAAAAABmMzP/ZjMz + /2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/wAAAAAAAAAA/svLHv7LyywAAAAAAAAAAAAAAAAAAAAAZjMz + /61NAP+tTQD/rU0A/61NAP+tTQD/rU0A/2YzM/8AAAAAAAAAAP7Lyx4AM6H/ADOh/wAzof8AM6H/ADOh + /2YzM/+5XQD/uV0A/7ldAP+5XQD/uV0A/7ldAP9mMzP/AAAAAAAAAAD+y8seADOh/wA3q/8AN6v/ADer + /wAzof9mMzP/xWwA/8VsAP/FbAD/xWwA/8VsAP/FbAD/ZjMz/wAAAAAAAAAA/svLHgAzof8APLb/ADy2 + /wA8tv8AM6H/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/8AAAAAAAAAAP7Lyx4AM6H/AEHB + /wBBwf8AQcH/ADOh/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//ADOh + /wBGzP8ARsz/AEbM/wAzof9IvOX/SLzl/0i85f9IvOX/SLzl/0i85f9IvOX/SLzl/0i85f9IvOX/AFuv + /wAzof8AS9f/AEvX/wBL1/8AM6H/R8Lo/0fC6P9Hwuj/R8Lo/0fC6P9Hwuj/R8Lo/0fC6P9Hwuj/R8Lo + /wBbr/8AM6H/ADOh/wAzof8AM6H/ADOh/0fJ6/9Hyev/R8nr/0fJ6/9Hyev/R8nr/0fJ6/9Hyev/R8nr + /0fJ6/8AW6///8zMLAAAAAAAAAAAAAAAAABbr/9G0O7/RtDu/0bQ7v9G0O7/RtDu/0bQ7v9G0O7/RtDu + /0bQ7v9G0O7/AFuv///MzCwAAAAAAAAAAAAAAAAAW6//Rtfy/0bX8v9G1/L/Rtfy/0bX8v9G1/L/Rtfy + /0bX8v9G1/L/Rtfy/wBbr//+y8ssAAAAAAAAAAAAAAAAAFuv/0Xd9f9F3fX/Rd31/0Xd9f9F3fX/Rd31 + /0Xd9f9F3fX/Rd31/0Xd9f8AW6///svLLAAAAAAAAAAAAAAAAABbr/9F5Pj/ReT4/0Xk+P9F5Pj/ReT4 + /0Xk+P9F5Pj/ReT4/0Xk+P9F5Pj/AFuv//7LyywAAAAAAAAAAAAAAAAAW6//ROv7/0Tr+/9E6/v/ROv7 + /0Tr+/9E6/v/ROv7/0Tr+/9E6/v/ROv7/wBbr//+y8tI/svLLP7Lyyz+y8ssAFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AACsQXgGrEF4BqxBAAasQQAGrEEABqxBAACs + QQAArEEAAKxBAACsQXAArEFwAKxBcACsQXAArEFwAKxBAACsQQ== + + + \ No newline at end of file diff --git a/branches/ph-plugins/ExtraTools/SysCallHacker/Program.cs b/branches/ph-plugins/ExtraTools/SysCallHacker/Program.cs new file mode 100644 index 000000000..fcabcf5db --- /dev/null +++ b/branches/ph-plugins/ExtraTools/SysCallHacker/Program.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Windows.Forms; + +namespace SysCallHacker +{ + static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new MainWindow()); + } + } +} diff --git a/branches/ph-plugins/ExtraTools/SysCallHacker/Properties/AssemblyInfo.cs b/branches/ph-plugins/ExtraTools/SysCallHacker/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..f48626a0f --- /dev/null +++ b/branches/ph-plugins/ExtraTools/SysCallHacker/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SysCallHacker")] +[assembly: AssemblyDescription("System Call Hacker")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("wj32")] +[assembly: AssemblyProduct("SysCallHacker")] +[assembly: AssemblyCopyright("Copyright © 2009 wj32. Licensed under the GNU GPL, v3.")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("55039872-9923-42d3-893d-2dd59e582765")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/branches/ph-plugins/ExtraTools/SysCallHacker/Properties/Resources.Designer.cs b/branches/ph-plugins/ExtraTools/SysCallHacker/Properties/Resources.Designer.cs new file mode 100644 index 000000000..d6a9b8ec8 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/SysCallHacker/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.4016 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SysCallHacker.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SysCallHacker.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/branches/ph-plugins/ExtraTools/SysCallHacker/Properties/Resources.resx b/branches/ph-plugins/ExtraTools/SysCallHacker/Properties/Resources.resx new file mode 100644 index 000000000..ffecec851 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/SysCallHacker/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ExtraTools/SysCallHacker/Properties/Settings.Designer.cs b/branches/ph-plugins/ExtraTools/SysCallHacker/Properties/Settings.Designer.cs new file mode 100644 index 000000000..9f286282d --- /dev/null +++ b/branches/ph-plugins/ExtraTools/SysCallHacker/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.4016 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace SysCallHacker.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/branches/ph-plugins/ExtraTools/SysCallHacker/Properties/Settings.settings b/branches/ph-plugins/ExtraTools/SysCallHacker/Properties/Settings.settings new file mode 100644 index 000000000..abf36c5d3 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/SysCallHacker/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/branches/ph-plugins/ExtraTools/SysCallHacker/SysCallHacker.csproj b/branches/ph-plugins/ExtraTools/SysCallHacker/SysCallHacker.csproj new file mode 100644 index 000000000..3da8365d5 --- /dev/null +++ b/branches/ph-plugins/ExtraTools/SysCallHacker/SysCallHacker.csproj @@ -0,0 +1,102 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {39B5CDC9-0AB3-4E1F-862C-EA95BC5A0715} + WinExe + Properties + SysCallHacker + SysCallHacker + v2.0 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + AnyCPU + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AnyCPU + + + + + + + + + + + + Form + + + EventProperties.cs + + + + Form + + + MainWindow.cs + + + + + EventProperties.cs + + + MainWindow.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + {8E10F5E8-D4FA-4980-BB23-2EDD134AC15E} + ProcessHacker.Common + + + {8A448157-E1A7-4DDF-954E-287F1117832B} + ProcessHacker.Native + + + + + \ No newline at end of file diff --git a/branches/ph-plugins/HACKING.txt b/branches/ph-plugins/HACKING.txt new file mode 100644 index 000000000..4422509e3 --- /dev/null +++ b/branches/ph-plugins/HACKING.txt @@ -0,0 +1,19 @@ +Note to SVN users: +If you use SVN code you may encounter weird bugs. Please use releases instead. + +Process Hacker is developed using Visual Studio 2008, and +will only work with C# compilers which support C# 3.0. It has been tested on +Visual Studio 2008 and Visual C# Express Edition (free). + +To build KProcessHacker, you will need the Windows DDK. +To build NProcessHacker, you will need Visual Studio 2008 or Visual C++ +Express Edition (free). + +IMPORTANT: If you are using Visual C# Express Edition to compile/run +Process Hacker, you MUST enable "Show advanced build configurations" in +Tools > Options > Projects and Solutions > General. + +The build script relies on ILMerge being present in the default installation +location ("%PROGRAMFILES%\Microsoft\ILMerge\ILMerge.exe") or in your PATH +environment variable. In order to build the installer you must have Inno Setup +QuickStart Pack installed (v5.3.5+). \ No newline at end of file diff --git a/branches/ph-plugins/KProcessHacker/HACKING.txt b/branches/ph-plugins/KProcessHacker/HACKING.txt new file mode 100644 index 000000000..00c104cfa --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/HACKING.txt @@ -0,0 +1,67 @@ +==== KProcessHacker ==== + +== IMPORTANT == +KProcessHacker has been developed from either reverse engineering of +the Windows kernel or ReactOS code (http://www.reactos.org). The +following files contain "ported" ReactOS code (with modifications): + + * mm.c + * MiDoMappedCopy + * MiDoPoolCopy (added smarter buffer management) + * MiGetExceptionInfo + * ps.c + * KphOpenProcess + * KphOpenThread + * se.c + * KphOpenProcessTokenEx + +== CODE STRUCTURE == + * handle.c + - Contains handle table code. + * hook.c + - Contains hooking code. Currently you may hook any kernel-mode + function and object type open procedures. + * io.c + - Contains I/O-related code, such as device and driver functions. + * kph.c + - Contains support routines. + * kprocesshacker.c + - Contains interfacing code, mainly consisting of the I/O control + handler. + * mm.c + - Contains memory-related code, such as reading and writing. + * ob.c + - Contains object-related code, such as handle duplication. + * protect.c + - Contains process protection code. Process protection is + achieved by hooking ObOpenObjectByPointer and some object type + OpenProcedures. + * ps.c + - Contains process- and thread-related code, such as opening and + terminating. + * ref.c + - Contains the KPH object manager. + * se.c + - Contains security-related code. Only function there is + KphOpenProcessTokenEx. + * sync.c + - Various synchronization functions. + * sysservice.c + - System service logging. + * trace.c + - Stack trace code. + * version.c + - Contains Windows-version-specific data. + +== POOL TAGS == +PhAB: System service logging argument block. sysservice.h +PhCH: Client handle table. kprocesshacker.h +PhCt: System service logging argument capture temporary buffer. sysservicep.h +PhCU: Captured Unicode string. kph.h +PhEB: System service logging event block. sysservice.h +PhOb: Object manager object. refp.h +PhPC: Pool-based virtual memory copying. mm.h +PhPr: Protection entry. protect.h +PhSc: System service call entry. sysservicedata.h +PhSD: Processor lock DPC storage. sync.h +PhSt: Stack back trace. ps.h diff --git a/branches/ph-plugins/KProcessHacker/amd64/kprocesshacker.sys b/branches/ph-plugins/KProcessHacker/amd64/kprocesshacker.sys new file mode 100644 index 000000000..9c86f5624 Binary files /dev/null and b/branches/ph-plugins/KProcessHacker/amd64/kprocesshacker.sys differ diff --git a/branches/ph-plugins/KProcessHacker/auto.cmd b/branches/ph-plugins/KProcessHacker/auto.cmd new file mode 100644 index 000000000..28cde9736 --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/auto.cmd @@ -0,0 +1,7 @@ +@echo off + +build -cZ +if not %errorlevel%==0 goto end +copy i386\kprocesshacker.sys ..\ProcessHacker\bin\Release\ +copy i386\kprocesshacker.pdb ..\ProcessHacker\bin\Release\ +:end \ No newline at end of file diff --git a/branches/ph-plugins/KProcessHacker/autoreload.cmd b/branches/ph-plugins/KProcessHacker/autoreload.cmd new file mode 100644 index 000000000..b1e09e9c1 --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/autoreload.cmd @@ -0,0 +1,2 @@ +@echo off +auto & sc stop kprocesshacker & sc start kprocesshacker \ No newline at end of file diff --git a/branches/ph-plugins/KProcessHacker/handle.c b/branches/ph-plugins/KProcessHacker/handle.c new file mode 100644 index 000000000..43b94fd9a --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/handle.c @@ -0,0 +1,355 @@ +/* + * Process Hacker Driver - + * handle table + * + * Copyright (C) 2009 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/handle.h" +#include "include/handlep.h" + +NTSTATUS KphpAllocateHandleEntry( + __in PKPH_HANDLE_TABLE HandleTable, + __out PKPH_HANDLE_TABLE_ENTRY *Entry + ); + +NTSTATUS KphpFreeHandleEntry( + __in PKPH_HANDLE_TABLE HandleTable, + __in PKPH_HANDLE_TABLE_ENTRY Entry + ); + +/* KphCreateHandleTable + * + * Creates a handle table. + * + * HandleTable: A variable which receives a pointer to the handle table. + * MaximumHandles: The maximum number of handles that can be created. + * SizeOfEntry: The size of each handle table entry. This value must be + * divisible by 4. + * Tag: The tag to use when allocating handle table resources. + */ +NTSTATUS KphCreateHandleTable( + __out PKPH_HANDLE_TABLE *HandleTable, + __in ULONG MaximumHandles, + __in ULONG SizeOfEntry, + __in ULONG Tag + ) +{ + PKPH_HANDLE_TABLE handleTable; + + /* Each handle entry must be at least the size of our + * handle table entry definition. + */ + if (SizeOfEntry < sizeof(KPH_HANDLE_TABLE_ENTRY)) + return STATUS_INVALID_PARAMETER_3; + /* Handle entries must be 4-byte aligned. */ + if (SizeOfEntry % 4 != 0) + return STATUS_INVALID_PARAMETER_3; + + /* Allocate storage for the handle table structure. */ + handleTable = ExAllocatePoolWithTag( + PagedPool, + sizeof(KPH_HANDLE_TABLE), + Tag + ); + + if (!handleTable) + return STATUS_INSUFFICIENT_RESOURCES; + + /* Allocate storage for the handle table itself. */ + handleTable->Table = ExAllocatePoolWithTag( + PagedPool, + MaximumHandles * SizeOfEntry, + Tag + ); + + if (!handleTable->Table) + { + ExFreePoolWithTag(handleTable, Tag); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Initialize the rest of the table descriptor. */ + handleTable->Tag = Tag; + handleTable->SizeOfEntry = SizeOfEntry; + handleTable->NextHandle = (HANDLE)0; + handleTable->FreeHandle = NULL; + ExInitializeFastMutex(&handleTable->Mutex); + handleTable->TableSize = MaximumHandles * SizeOfEntry; + + /* Zero the handle table. */ + memset(handleTable->Table, 0, handleTable->TableSize); + + /* Pass the pointer to the handle table back. */ + *HandleTable = handleTable; + + return STATUS_SUCCESS; +} + +/* KphFreeHandleTable + * + * Frees all handle table resources. + */ +VOID KphFreeHandleTable( + __in PKPH_HANDLE_TABLE HandleTable + ) +{ + ULONG i; + ULONG tag; + + /* Free all handle values. */ + for (i = 0; i < HandleTable->TableSize / HandleTable->SizeOfEntry; i++) + { + KphCloseHandle(HandleTable, KphHandleFromIndex(i)); + } + + /* Save the handle table tag first. */ + tag = HandleTable->Tag; + /* Free the table. */ + ExFreePoolWithTag(HandleTable->Table, tag); + /* Free the descriptor. */ + ExFreePoolWithTag(HandleTable, tag); +} + +/* KphCloseHandle + * + * Closes a handle, dereferencing the referenced object. + */ +NTSTATUS KphCloseHandle( + __in PKPH_HANDLE_TABLE HandleTable, + __in HANDLE Handle + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PKPH_HANDLE_TABLE_ENTRY entry; + PVOID object; + + if (!KphValidHandle(HandleTable, Handle, &entry)) + return STATUS_INVALID_HANDLE; + + /* Save a pointer to the object referenced by the handle. */ + object = entry->Object; + /* Free the handle. */ + status = KphpFreeHandleEntry(HandleTable, entry); + + if (!NT_SUCCESS(status)) + return status; + + /* Dereference the object. */ + KphDereferenceObject(object); + + return status; +} + +/* KphCreateHandle + * + * Creates a handle and references an object. + */ +NTSTATUS KphCreateHandle( + __in PKPH_HANDLE_TABLE HandleTable, + __in PVOID Object, + __out PHANDLE Handle + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PKPH_HANDLE_TABLE_ENTRY entry; + + /* Allocate a handle. */ + status = KphpAllocateHandleEntry(HandleTable, &entry); + + if (!NT_SUCCESS(status)) + return status; + + /* Reference and set the object in the entry. */ + KphReferenceObject(Object); + entry->Object = Object; + + /* Pass the handle back. */ + *Handle = KphGetHandleEntry(entry); + + return status; +} + +/* KphReferenceObjectByHandle + * + * References an object from a handle. + */ +NTSTATUS KphReferenceObjectByHandle( + __in PKPH_HANDLE_TABLE HandleTable, + __in HANDLE Handle, + __in_opt PKPH_OBJECT_TYPE ObjectType, + __out PVOID *Object + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PKPH_HANDLE_TABLE_ENTRY entry; + + if (!KphValidHandle(HandleTable, Handle, &entry)) + return STATUS_INVALID_HANDLE; + + /* Lock the entry. */ + if (!KphLockAllocatedHandleEntry(entry)) + return STATUS_INVALID_HANDLE; + + /* Check the type of object if the caller requested us + * to do that. + */ + if (ObjectType) + { + if (KphGetObjectType(entry->Object) != ObjectType) + { + /* Bad type. */ + KphUnlockHandleEntry(entry); + + return STATUS_OBJECT_TYPE_MISMATCH; + } + } + + /* Reference and pass the object back. */ + KphReferenceObject(entry->Object); + *Object = entry->Object; + + KphUnlockHandleEntry(entry); + + return status; +} + +/* KphValidHandle + * + * Checks if a handle is valid. + */ +BOOLEAN KphValidHandle( + __in PKPH_HANDLE_TABLE HandleTable, + __in HANDLE Handle, + __out_opt PKPH_HANDLE_TABLE_ENTRY *Entry + ) +{ + PKPH_HANDLE_TABLE_ENTRY entry; + BOOLEAN valid; + + entry = KphEntryFromHandle(HandleTable, Handle); + valid = + ((ULONG_PTR)entry >= (ULONG_PTR)HandleTable->Table) && + ((ULONG_PTR)entry + HandleTable->SizeOfEntry <= + (ULONG_PTR)HandleTable->Table + HandleTable->TableSize); + + if (valid) + *Entry = entry; + + return valid; +} + +/* KphpAllocateHandleEntry + * + * Allocates a handle table entry. + */ +NTSTATUS KphpAllocateHandleEntry( + __in PKPH_HANDLE_TABLE HandleTable, + __out PKPH_HANDLE_TABLE_ENTRY *Entry + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PKPH_HANDLE_TABLE_ENTRY entry = NULL; + + /* Prevent others from modifying the handle table. */ + ExAcquireFastMutex(&HandleTable->Mutex); + + /* Check the free list first. If we have a free entry, + * claim it and update the free list. Otherwise, create + * a new entry from the NextHandle value. + */ + if (HandleTable->FreeHandle) + { + /* We have a free entry. Update the free list. */ + entry = HandleTable->FreeHandle; + /* The next free entry goes into FreeHandle. */ + HandleTable->FreeHandle = KphGetNextFreeEntry(entry); + } + else + { + /* No free handles. We have to initialize a new one + * based on the NextHandle value. + */ + /* Make sure we don't go past the end of the table. */ + if ( + KphIndexFromHandle(HandleTable->NextHandle) * + HandleTable->SizeOfEntry <= + HandleTable->TableSize + ) + { + /* Get a pointer to the entry from the handle. */ + entry = KphEntryFromHandle(HandleTable, HandleTable->NextHandle); + /* Increment the next handle value. */ + HandleTable->NextHandle = KphIncrementHandle(HandleTable->NextHandle); + } + else + { + status = STATUS_INSUFFICIENT_RESOURCES; + } + } + + if (NT_SUCCESS(status)) + { + /* Set the entry's handle value. */ + entry->Handle = KphHandleFromEntry(HandleTable, entry); + KphSetAllocatedEntry(entry); + + *Entry = entry; + } + + ExReleaseFastMutex(&HandleTable->Mutex); + + return status; +} + +/* KphpFreeHandleEntry + * + * Frees a handle table entry. + */ +NTSTATUS KphpFreeHandleEntry( + __in PKPH_HANDLE_TABLE HandleTable, + __in PKPH_HANDLE_TABLE_ENTRY Entry + ) +{ + ExAcquireFastMutex(&HandleTable->Mutex); + + /* Lock the entry. */ + if (!KphLockAllocatedHandleEntry(Entry)) + { + /* Someone else has already freed the entry (or it was never allocated). */ + ExReleaseFastMutex(&HandleTable->Mutex); + return STATUS_INVALID_HANDLE; + } + + /* Mark the entry as unallocated. */ + KphClearAllocatedEntry(Entry); + + /* Add the entry to the free list. */ + KphSetNextFreeEntry(Entry, HandleTable->FreeHandle); + HandleTable->FreeHandle = Entry; + + /* Zero the entry (except for the Value). */ + memset(&Entry->Object, 0, HandleTable->SizeOfEntry - sizeof(ULONG_PTR)); + + /* Unlock the entry. */ + KphUnlockHandleEntry(Entry); + + ExReleaseFastMutex(&HandleTable->Mutex); + + return STATUS_SUCCESS; +} diff --git a/branches/ph-plugins/KProcessHacker/hook.c b/branches/ph-plugins/KProcessHacker/hook.c new file mode 100644 index 000000000..3f775db5d --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/hook.c @@ -0,0 +1,408 @@ +/* + * Process Hacker Driver - + * hooks + * + * Copyright (C) 2009 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/hook.h" +#include "include/sync.h" + +static KPH_PROCESSOR_LOCK HookProcessorLock; + +/* KphHookInit + * + * Initializes the hooking module. + */ +NTSTATUS KphHookInit() +{ + KphInitializeProcessorLock(&HookProcessorLock); + + return STATUS_SUCCESS; +} + +/* KphInitializeHook + * + * Initializes a hook structure. + */ +VOID KphInitializeHook( + __out PKPH_HOOK Hook, + __in PVOID Function, + __in PVOID Target + ) +{ + memset(Hook, 0, sizeof(KPH_HOOK)); + Hook->Function = Function; + Hook->Target = Target; +} + +/* KphHook + * + * Hooks a kernel-mode function. + * WARNING: DO NOT HOOK A FUNCTION THAT IS CALLABLE ABOVE APC_LEVEL. + * + * Thread safety: Full + * IRQL: <= APC_LEVEL + */ +NTSTATUS KphHook( + __inout PKPH_HOOK Hook + ) +{ + NTSTATUS status = STATUS_SUCCESS; + MAPPED_MDL mappedMdl; + PUCHAR function; + + status = KphpCreateMappedMdl( + Hook->Function, + 5, + &mappedMdl + ); + + if (!NT_SUCCESS(status)) + return status; + + function = (PUCHAR)mappedMdl.Address; + + /* Acquire a lock on all other processors. */ + if (KphAcquireProcessorLock(&HookProcessorLock)) + { + /* Note that this is completely safe even though we are at + * DISPATCH_LEVEL because we are using the mapped MDL. + */ + /* Copy the original five bytes (for unhooking). */ + memcpy(Hook->Bytes, function, 10); + /* Hook the function by writing a jump instruction. */ + Hook->Hooked = TRUE; + /* jmp Target */ + *function = 0xe9; + *(PULONG_PTR)(function + 1) = (ULONG_PTR)Hook->Target - (ULONG_PTR)Hook->Function - 5; + + /* Release the processor lock. */ + KphReleaseProcessorLock(&HookProcessorLock); + } + else + { + dprintf("KphHook: Could not acquire processor lock!\n"); + status = STATUS_INSUFFICIENT_RESOURCES; + } + + KphpFreeMappedMdl(&mappedMdl); + + return status; +} + +/* KphUnhook + * + * Unhooks a kernel-mode function. + * WARNING: DO NOT UNHOOK A FUNCTION THAT IS CALLABLE ABOVE APC_LEVEL. + * + * Thread safety: Full + * IRQL: <= APC_LEVEL + */ +NTSTATUS KphUnhook( + __inout PKPH_HOOK Hook + ) +{ + NTSTATUS status = STATUS_SUCCESS; + MAPPED_MDL mappedMdl; + + if (!Hook->Hooked) + return STATUS_UNSUCCESSFUL; + + status = KphpCreateMappedMdl( + Hook->Function, + 5, + &mappedMdl + ); + + if (!NT_SUCCESS(status)) + return status; + + /* Acquire a lock on all other processors. */ + if (KphAcquireProcessorLock(&HookProcessorLock)) + { + /* Unpatch the function. */ + memcpy(mappedMdl.Address, Hook->Bytes, 5); + Hook->Hooked = FALSE; + /* Release the processor lock. */ + KphReleaseProcessorLock(&HookProcessorLock); + } + else + { + dprintf("KphUnhook: Could not acquire processor lock!\n"); + status = STATUS_INSUFFICIENT_RESOURCES; + } + + KphpFreeMappedMdl(&mappedMdl); + + return status; +} + +/* KphObOpenCall + * + * Calls the original open procedure for an object type. + * + * AccessMode: If this argument is unavailable, specify KernelMode. + */ +NTSTATUS NTAPI KphObOpenCall( + __in PKPH_OB_OPEN_HOOK ObOpenHook, + __in OB_OPEN_REASON OpenReason, + __in KPROCESSOR_MODE AccessMode, + __in PEPROCESS Process, + __in PVOID Object, + __in ACCESS_MASK GrantedAccess, + __in ULONG HandleCount + ) +{ + /* If there wasn't any original open procedure, exit. */ + if (!ObOpenHook->Function) + return STATUS_SUCCESS; + + if (WindowsVersion == WINDOWS_XP) + { + return ((OB_OPEN_METHOD_51)ObOpenHook->Function)( + OpenReason, + Process, + Object, + GrantedAccess, + HandleCount + ); + } + else if ( + WindowsVersion == WINDOWS_VISTA || + WindowsVersion == WINDOWS_7 + ) + { + return ((OB_OPEN_METHOD_60)ObOpenHook->Function)( + OpenReason, + AccessMode, + Process, + Object, + GrantedAccess, + HandleCount + ); + } + else + { + return STATUS_NOT_SUPPORTED; + } +} + +/* KphInitializeObOpenHook + * + * Initializes a hook structure. + */ +VOID KphInitializeObOpenHook( + __inout PKPH_OB_OPEN_HOOK ObOpenHook, + __in POBJECT_TYPE ObjectType, + __in PVOID Target51, + __in PVOID Target60 + ) +{ + memset(ObOpenHook, 0, sizeof(KPH_OB_OPEN_HOOK)); + ObOpenHook->ObjectType = ObjectType; + ObOpenHook->Target51 = Target51; + ObOpenHook->Target60 = Target60; +} + +/* KphObOpenHook + * + * Hooks the open procedure for an object type. + * + * Thread safety: Full + * IRQL: <= APC_LEVEL + */ +NTSTATUS KphObOpenHook( + __inout PKPH_OB_OPEN_HOOK ObOpenHook + ) +{ + NTSTATUS status = STATUS_SUCCESS; + MAPPED_MDL mappedMdl; + PVOID *openProcedure; + + status = KphpCreateMappedMdl( + KVOFF(ObOpenHook->ObjectType, OffOtiOpenProcedure), + sizeof(PVOID), + &mappedMdl + ); + + if (!NT_SUCCESS(status)) + return status; + + openProcedure = (PVOID *)mappedMdl.Address; + + /* Acquire a lock on all other processors. */ + if (KphAcquireProcessorLock(&HookProcessorLock)) + { + /* Save the original open procedure pointer. */ + ObOpenHook->Function = *openProcedure; + + /* Choose the correct target open procedure and hook. */ + if (WindowsVersion == WINDOWS_XP) + { + if (ObOpenHook->Target51) + *openProcedure = ObOpenHook->Target51; + else + status = STATUS_INVALID_PARAMETER; + } + else if ( + WindowsVersion == WINDOWS_VISTA || + WindowsVersion == WINDOWS_7 + ) + { + if (ObOpenHook->Target60) + *openProcedure = ObOpenHook->Target60; + else + status = STATUS_INVALID_PARAMETER; + } + else + { + status = STATUS_NOT_SUPPORTED; + } + + ObOpenHook->Hooked = TRUE; + + /* Release the processor lock. */ + KphReleaseProcessorLock(&HookProcessorLock); + } + else + { + status = STATUS_INSUFFICIENT_RESOURCES; + } + + KphpFreeMappedMdl(&mappedMdl); + + return status; +} + +/* KphObOpenUnhook + * + * Unhooks the open procedure for an object type. + * + * Thread safety: Full + * IRQL: <= APC_LEVEL + */ +NTSTATUS KphObOpenUnhook( + __inout PKPH_OB_OPEN_HOOK ObOpenHook + ) +{ + NTSTATUS status = STATUS_SUCCESS; + MAPPED_MDL mappedMdl; + PVOID *openProcedure; + + if (!ObOpenHook->Hooked) + return STATUS_UNSUCCESSFUL; + + status = KphpCreateMappedMdl( + KVOFF(ObOpenHook->ObjectType, OffOtiOpenProcedure), + sizeof(PVOID), + &mappedMdl + ); + + if (!NT_SUCCESS(status)) + return status; + + openProcedure = (PVOID *)mappedMdl.Address; + + /* Acquire a lock on all other processors. */ + if (KphAcquireProcessorLock(&HookProcessorLock)) + { + /* Restore the original open procedure pointer. */ + *openProcedure = ObOpenHook->Function; + ObOpenHook->Hooked = FALSE; + + /* Release the processor lock. */ + KphReleaseProcessorLock(&HookProcessorLock); + } + else + { + status = STATUS_INSUFFICIENT_RESOURCES; + } + + KphpFreeMappedMdl(&mappedMdl); + + return status; +} + +/* KphpCreateMappedMdl + * + * Creates and maps a MDL. + * + * Thread safety: Full + * IRQL: Any + */ +NTSTATUS KphpCreateMappedMdl( + __in PVOID Address, + __in ULONG Length, + __out PMAPPED_MDL MappedMdl + ) +{ + PMDL mdl; + + MappedMdl->Mdl = NULL; + MappedMdl->Address = NULL; + + mdl = IoAllocateMdl(Address, Length, FALSE, FALSE, NULL); + + if (mdl == NULL) + return STATUS_INSUFFICIENT_RESOURCES; + + MmBuildMdlForNonPagedPool(mdl); + mdl->MdlFlags |= MDL_MAPPED_TO_SYSTEM_VA; + MappedMdl->Address = MmMapLockedPagesSpecifyCache( + mdl, + KernelMode, + MmNonCached, + NULL, + FALSE, + HighPagePriority + ); + MappedMdl->Mdl = mdl; + + if (!MappedMdl->Address) + { + KphpFreeMappedMdl(MappedMdl); + return STATUS_INSUFFICIENT_RESOURCES; + } + + return STATUS_SUCCESS; +} + +/* KphpFreeMappedMdl + * + * Unmaps and frees a MDL. + * + * Thread safety: Full + * IRQL: Any + */ +VOID KphpFreeMappedMdl( + __in PMAPPED_MDL MappedMdl + ) +{ + if (MappedMdl->Mdl != NULL) + { + if (MappedMdl->Address != NULL) + { + MmUnmapLockedPages(MappedMdl->Address, MappedMdl->Mdl); + MappedMdl->Address = NULL; + } + + IoFreeMdl(MappedMdl->Mdl); + MappedMdl->Mdl = NULL; + } +} diff --git a/branches/ph-plugins/KProcessHacker/i386/kprocesshacker.sys b/branches/ph-plugins/KProcessHacker/i386/kprocesshacker.sys new file mode 100644 index 000000000..ae87f7343 Binary files /dev/null and b/branches/ph-plugins/KProcessHacker/i386/kprocesshacker.sys differ diff --git a/branches/ph-plugins/KProcessHacker/include/debug.h b/branches/ph-plugins/KProcessHacker/include/debug.h new file mode 100644 index 000000000..0a140616b --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/include/debug.h @@ -0,0 +1,35 @@ +/* + * Process Hacker Driver - + * debug definitions + * + * Copyright (C) 2009 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 . + */ + +#ifndef _DEBUG_H +#define _DEBUG_H + +#ifdef DBG +#define dprintf(fs, ...) DbgPrint("KProcessHacker: " fs, __VA_ARGS__) +#else +#define dprintf +#endif + +#define dfprintf(fs, ...) DbgPrint("KProcessHacker: " fs, __VA_ARGS__) +#define dwprintf DbgPrint + +#endif diff --git a/branches/ph-plugins/KProcessHacker/include/ex.h b/branches/ph-plugins/KProcessHacker/include/ex.h new file mode 100644 index 000000000..bfd06ccbe --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/include/ex.h @@ -0,0 +1,262 @@ +/* + * Process Hacker Driver - + * executive + * + * Copyright (C) 2009 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 . + */ + +#ifndef _EX_H +#define _EX_H + +#include "types.h" + +/* HACK - version.c dependency */ +#define WINDOWS_XP 51 +#define WINDOWS_SERVER_2003 52 +#define WINDOWS_VISTA 60 +#define WINDOWS_7 61 + +extern ULONG WindowsVersion; + +/* Handles */ + +struct _HANDLE_TABLE; +struct _HANDLE_TABLE_ENTRY; + +typedef BOOLEAN (NTAPI *PEX_ENUM_HANDLE_CALLBACK)( + struct _HANDLE_TABLE_ENTRY *HandleTableEntry, + HANDLE Handle, + PVOID Context + ); + +BOOLEAN NTAPI ExEnumHandleTable( + __in struct _HANDLE_TABLE *HandleTable, + __in PEX_ENUM_HANDLE_CALLBACK EnumHandleProcedure, + __inout PVOID Context, + __out_opt PHANDLE Handle + ); + +/* Push Locks */ + +/* Definition for Windows 2003 and above. This means we + * MUST use the slow path on Windows XP. + */ +typedef struct _EXI_PUSH_LOCK +{ + union + { + struct + { + ULONG_PTR Locked : 1; + ULONG_PTR Waiting : 1; + ULONG_PTR Waking : 1; + ULONG_PTR MultipleShared : 1; + ULONG_PTR Shared : sizeof(ULONG_PTR) * 8 - 4; /* ULONG_PTR bits minus 4 */ + }; + ULONG_PTR Value; + PVOID Ptr; + }; +} EXI_PUSH_LOCK, *PEXI_PUSH_LOCK; + +#define EX_PUSH_LOCK_LOCK_SHIFT 0 +#define EX_PUSH_LOCK_LOCK ((ULONG_PTR)0x1) +/* Indicates chained waiters */ +#define EX_PUSH_LOCK_WAITING ((ULONG_PTR)0x2) +/* Traversing the list */ +#define EX_PUSH_LOCK_WAKING ((ULONG_PTR)0x4) +/* Multiple owners + waiters */ +#define EX_PUSH_LOCK_MULTIPLE_SHARED ((ULONG_PTR)0x8) + +#define EX_PUSH_LOCK_SHARE_INC ((ULONG_PTR)0x10) +#define EX_PUSH_LOCK_PTR_BITS ((ULONG_PTR)0xf) + +NTKERNELAPI VOID FASTCALL ExfAcquirePushLockExclusive( + __inout PEX_PUSH_LOCK PushLock + ); + +NTKERNELAPI VOID FASTCALL ExfAcquirePushLockShared( + __inout PEX_PUSH_LOCK PushLock + ); + +NTKERNELAPI VOID FASTCALL ExfReleasePushLock( + __inout PEX_PUSH_LOCK PushLock + ); + +/* The below functions are only exported on Vista and higher. */ + +NTKERNELAPI VOID FASTCALL ExfReleasePushLockShared( + __inout PEX_PUSH_LOCK PushLock + ); + +NTKERNELAPI VOID FASTCALL ExfReleasePushLockExclusive( + __inout PEX_PUSH_LOCK PushLock + ); + +NTKERNELAPI BOOLEAN FASTCALL ExfTryAcquirePushLockShared( + __inout PEX_PUSH_LOCK PushLock + ); + +NTKERNELAPI VOID FASTCALL ExfTryToWakePushLock( + __inout PEX_PUSH_LOCK PushLock + ); + +/* Wrapper functions */ + +/* ExInitializePushLock + * + * Initializes a push lock. + */ +FORCEINLINE VOID ExInitializePushLock( + __out PEX_PUSH_LOCK PushLock + ) +{ + *PushLock = 0; +} + +/* ExAcquirePushLockExclusive + * + * Acquires a push lock in exclusive mode. + */ +FORCEINLINE VOID ExAcquirePushLockExclusive( + __inout PEX_PUSH_LOCK PushLock + ) +{ + /* Fast path - acquire push lock, no function call. */ + if (WindowsVersion < WINDOWS_SERVER_2003 || InterlockedBitTestAndSet((PLONG)PushLock, EX_PUSH_LOCK_LOCK_SHIFT)) + { + /* Slow path - call the function. */ + ExfAcquirePushLockExclusive(PushLock); + } +} + +/* ExAcquirePushLockShared + * + * Acquires a push lock in shared mode. + */ +FORCEINLINE VOID ExAcquirePushLockShared( + __inout PEX_PUSH_LOCK PushLock + ) +{ + /* Fast path - acquire push lock which is not held at all, no function call. */ + if (WindowsVersion < WINDOWS_SERVER_2003 || InterlockedCompareExchangePointer( + (PVOID)PushLock, + (PVOID)(EX_PUSH_LOCK_SHARE_INC | EX_PUSH_LOCK_LOCK), + 0 + ) != 0) + { + /* Slow path - call the function. */ + ExfAcquirePushLockShared(PushLock); + } +} + +/* ExReleasePushLock + * + * Releases a push lock (for both types). + */ +FORCEINLINE VOID ExReleasePushLock( + __inout PEX_PUSH_LOCK PushLock + ) +{ + EXI_PUSH_LOCK oldValue, newValue; + + oldValue.Value = *PushLock; + + /* If we are the last to release in shared mode or we + * are releasing in exclusive mode, we simply set + * the value to 0. + */ + + if (oldValue.Shared > 1) + { + /* One less shared holder. */ + newValue.Value = oldValue.Value - EX_PUSH_LOCK_SHARE_INC; + } + else + { + newValue.Value = 0; + } + + /* If we have chained waiters, we can't release the + * push lock using the fast path since they need to + * be unblocked. + */ + if ( + WindowsVersion < WINDOWS_SERVER_2003 || + oldValue.Waiting || + InterlockedCompareExchangePointer( + (PVOID)PushLock, + newValue.Ptr, + oldValue.Ptr + ) != oldValue.Ptr + ) + { + /* Slow path - call the function. */ + ExfReleasePushLock(PushLock); + } +} + +#ifndef NEVER_DEFINED +/* ExTryAcquirePushLockExclusive + * + * Attempts to acquire a push lock in exclusive mode. + * + * Return value: TRUE if the push lock was acquired, FALSE if + * the push lock was already acquired in exclusive mode. + */ +FORCEINLINE BOOLEAN ExTryAcquirePushLockExclusive( + __inout PEX_PUSH_LOCK PushLock + ) +{ + if (!InterlockedBitTestAndSet((PLONG)PushLock, EX_PUSH_LOCK_LOCK_SHIFT)) + { + return TRUE; + } + else + { + return FALSE; + } +} + +/* ExTryAcquirePushLockShared + * + * Attempts to acquire a push lock in shared mode. + * + * Return value: TRUE if the push lock was acquired, FALSE if + * the push lock was already acquired in exclusive mode. + */ +FORCEINLINE BOOLEAN ExTryAcquirePushLockShared( + __inout PEX_PUSH_LOCK PushLock + ) +{ + /* Fast path with the push lock not held at all. */ + if (InterlockedCompareExchangePointer( + (PVOID)PushLock, + (PVOID)(EX_PUSH_LOCK_SHARE_INC | EX_PUSH_LOCK_LOCK), + 0 + ) != 0) + { + return ExfTryAcquirePushLockShared(PushLock); + } + else + { + return TRUE; + } +} +#endif + +#endif \ No newline at end of file diff --git a/branches/ph-plugins/KProcessHacker/include/handle.h b/branches/ph-plugins/KProcessHacker/include/handle.h new file mode 100644 index 000000000..710205b3e --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/include/handle.h @@ -0,0 +1,78 @@ +/* + * Process Hacker Driver - + * handle table + * + * Copyright (C) 2009 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 . + */ + +#ifndef _HANDLE_H +#define _HANDLE_H + +#include "kph.h" +#include "ref.h" + +struct _KPH_HANDLE_TABLE; +typedef struct _KPH_HANDLE_TABLE *PKPH_HANDLE_TABLE; + +typedef struct _KPH_HANDLE_TABLE_ENTRY +{ + union + { + HANDLE Handle; + ULONG_PTR Value; + struct _KPH_HANDLE_TABLE_ENTRY *NextFree; + }; + PVOID Object; +} KPH_HANDLE_TABLE_ENTRY, *PKPH_HANDLE_TABLE_ENTRY; + +NTSTATUS KphCreateHandleTable( + __out PKPH_HANDLE_TABLE *HandleTable, + __in ULONG MaximumHandles, + __in ULONG SizeOfEntry, + __in ULONG Tag + ); + +VOID KphFreeHandleTable( + __in PKPH_HANDLE_TABLE HandleTable + ); + +NTSTATUS KphCloseHandle( + __in PKPH_HANDLE_TABLE HandleTable, + __in HANDLE Handle + ); + +NTSTATUS KphCreateHandle( + __in PKPH_HANDLE_TABLE HandleTable, + __in PVOID Object, + __out PHANDLE Handle + ); + +NTSTATUS KphReferenceObjectByHandle( + __in PKPH_HANDLE_TABLE HandleTable, + __in HANDLE Handle, + __in_opt PKPH_OBJECT_TYPE ObjectType, + __out PVOID *Object + ); + +BOOLEAN KphValidHandle( + __in PKPH_HANDLE_TABLE HandleTable, + __in HANDLE Handle, + __out_opt PKPH_HANDLE_TABLE_ENTRY *Entry + ); + +#endif diff --git a/branches/ph-plugins/KProcessHacker/include/handlep.h b/branches/ph-plugins/KProcessHacker/include/handlep.h new file mode 100644 index 000000000..a6cd445ee --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/include/handlep.h @@ -0,0 +1,144 @@ +/* + * Process Hacker Driver - + * handle table + * + * Copyright (C) 2009 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 . + */ + +#ifndef _HANDLEP_H +#define _HANDLEP_H + +#define _HANDLE_PRIVATE +#include "handle.h" +#include "sync.h" + +#define KPH_HANDLE_INCREMENT 4 +#define KPH_HANDLE_LOCKED 0x1 +#define KPH_HANDLE_LOCKED_SHIFT 0 +#define KPH_HANDLE_ALLOCATED 0x2 +#define KPH_HANDLE_FLAGS 0x3 + +#define KphGetFlagsEntry(Entry) ((Entry)->Value & KPH_HANDLE_FLAGS) +#define KphGetHandleEntry(Entry) ((HANDLE)((Entry)->Value & ~KPH_HANDLE_FLAGS)) +#define KphIncrementHandle(Handle) ((HANDLE)((ULONG_PTR)(Handle) + KPH_HANDLE_INCREMENT)) + +#define KphIsAllocatedEntry(Entry) ((Entry)->Value & KPH_HANDLE_ALLOCATED) +#define KphClearAllocatedEntry(Entry) ((Entry)->Value &= ~KPH_HANDLE_ALLOCATED) +#define KphSetAllocatedEntry(Entry) ((Entry)->Value |= KPH_HANDLE_ALLOCATED) + +#define KphGetNextFreeEntry(Entry) ((PKPH_HANDLE_TABLE_ENTRY)((Entry)->Value & ~KPH_HANDLE_FLAGS)) +#define KphSetNextFreeEntry(Entry, NextFree) ((Entry)->Value = ((ULONG_PTR)(NextFree) | KphGetFlagsEntry(Entry))) + +#define KphHandleFromIndex(Index) ((HANDLE)((ULONG_PTR)(Index) * KPH_HANDLE_INCREMENT)) +#define KphHandleFromIndexEx(Index, Flags) ((HANDLE)(((Index) * KPH_HANDLE_INCREMENT) | (Flags))) +#define KphIndexFromHandle(Handle) (((ULONG_PTR)(Handle) & ~KPH_HANDLE_FLAGS) / KPH_HANDLE_INCREMENT) + +#define KphEntryFromHandle(HandleTable, Handle) KphEntryFromIndex((HandleTable), KphIndexFromHandle(Handle)) +#define KphEntryFromIndex(HandleTable, Index) \ + ((PKPH_HANDLE_TABLE_ENTRY)((ULONG_PTR)(HandleTable)->Table + (Index) * (HandleTable)->SizeOfEntry)) +#define KphHandleFromEntry(HandleTable, Entry) KphHandleFromIndex(KphIndexFromEntry((HandleTable), (Entry))) +#define KphHandleFromEntryEx(HandleTable, Entry, Flags) \ + KphHandleFromIndexEx(KphIndexFromEntry((HandleTable), (Entry)), (Flags)) +#define KphIndexFromEntry(HandleTable, Entry) \ + (((ULONG_PTR)(Entry) - (ULONG_PTR)(HandleTable)->Table) / (HandleTable)->SizeOfEntry) + +typedef struct _KPH_HANDLE_TABLE +{ + /* The pool tag used for this descriptor and the table itself. */ + ULONG Tag; + /* The size of each handle table entry. */ + ULONG SizeOfEntry; + /* The next handle value to use. */ + HANDLE NextHandle; + /* The free list of handle table entries. */ + struct _KPH_HANDLE_TABLE_ENTRY *FreeHandle; + + /* A fast mutex guarding writes to the handle table. */ + FAST_MUTEX Mutex; + /* The size of the table, in bytes. */ + ULONG TableSize; + /* The actual handle table. */ + PVOID Table; +} KPH_HANDLE_TABLE, *PKPH_HANDLE_TABLE; + +FORCEINLINE BOOLEAN KphLockHandleEntry( + __inout PKPH_HANDLE_TABLE_ENTRY Entry + ); + +FORCEINLINE BOOLEAN KphLockAllocatedHandleEntry( + __inout PKPH_HANDLE_TABLE_ENTRY Entry + ); + +FORCEINLINE VOID KphUnlockHandleEntry( + __inout PKPH_HANDLE_TABLE_ENTRY Entry + ); + +/* KphLockHandle + * + * Locks a handle table entry for exclusive access. Do not + * modify the lowest bit of the entry's value while you + * hold the lock. + * + * Return value: TRUE if the entry is allocated, otherwise FALSE. + */ +FORCEINLINE BOOLEAN KphLockHandleEntry( + __inout PKPH_HANDLE_TABLE_ENTRY Entry + ) +{ + /* Acquire the spinlock. */ + KphAcquireBitSpinLock((PLONG)&Entry->Value, KPH_HANDLE_LOCKED_SHIFT); + + /* Return whether the entry is allocated. */ + return !!(Entry->Value & KPH_HANDLE_ALLOCATED); +} + +/* KphLockAllocatedHandle + * + * Locks a handle table entry for exclusive access. Do not + * modify the lowest bit of the entry's value while you + * hold the lock. + * The function will not lock the handle if it is unallocated. + * + * Return value: TRUE if the entry was locked, otherwise FALSE. + */ +FORCEINLINE BOOLEAN KphLockAllocatedHandleEntry( + __inout PKPH_HANDLE_TABLE_ENTRY Entry + ) +{ + if (!KphLockHandleEntry(Entry)) + { + KphUnlockHandleEntry(Entry); + return FALSE; + } + + return TRUE; +} + +/* KphUnlockHandle + * + * Unlocks a handle table entry. + */ +FORCEINLINE VOID KphUnlockHandleEntry( + __inout PKPH_HANDLE_TABLE_ENTRY Entry + ) +{ + /* Unlock the spinlock. */ + KphReleaseBitSpinLock((PLONG)&Entry->Value, KPH_HANDLE_LOCKED_SHIFT); +} + +#endif diff --git a/branches/ph-plugins/KProcessHacker/include/hook.h b/branches/ph-plugins/KProcessHacker/include/hook.h new file mode 100644 index 000000000..12ec3d3f9 --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/include/hook.h @@ -0,0 +1,108 @@ +/* + * Process Hacker Driver - + * hooks + * + * Copyright (C) 2009 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 . + */ + +#ifndef _HOOK_H +#define _HOOK_H + +#include "kph.h" +#include "ob.h" + +#define KPH_DEFINE_HOOK_CALL(Name, Arguments, Hook) \ + __declspec(naked) Name(Arguments) \ + { \ + __asm lea eax, Hook \ + __asm mov eax, [eax+KPH_HOOK.Function] \ + __asm add eax, 5 \ + __asm push ebp \ + __asm mov ebp, esp \ + __asm jmp eax \ + } \ + +typedef struct _KPH_HOOK +{ + /* The address of the hooked function. + Should NOT be a function that is callable above PASSIVE_LEVEL. */ + PVOID Function; + /* The address of the new function. */ + PVOID Target; + /* Whether the function is hooked. */ + BOOLEAN Hooked; + /* The original first 10 bytes. */ + CHAR Bytes[10]; +} KPH_HOOK, *PKPH_HOOK; + +typedef struct _KPH_OB_OPEN_HOOK +{ + /* The object type that is being hooked. */ + POBJECT_TYPE ObjectType; + /* The original open procedure. */ + PVOID Function; + /* The new open procedure for NT 5.1 (XP). */ + OB_OPEN_METHOD_51 Target51; + /* The new open procedure for NT 6.1 and above (Vista, 7 or higher). */ + OB_OPEN_METHOD_60 Target60; + /* Whether the open procedure is hooked. */ + BOOLEAN Hooked; +} KPH_OB_OPEN_HOOK, *PKPH_OB_OPEN_HOOK; + +NTSTATUS KphHookInit(); + +VOID KphInitializeHook( + __out PKPH_HOOK Hook, + __in PVOID Function, + __in PVOID Target + ); + +NTSTATUS KphHook( + __inout PKPH_HOOK Hook + ); + +NTSTATUS KphUnhook( + __inout PKPH_HOOK Hook + ); + +NTSTATUS NTAPI KphObOpenCall( + __in PKPH_OB_OPEN_HOOK ObOpenHook, + __in OB_OPEN_REASON OpenReason, + __in KPROCESSOR_MODE AccessMode, + __in PEPROCESS Process, + __in PVOID Object, + __in ACCESS_MASK GrantedAccess, + __in ULONG HandleCount + ); + +VOID KphInitializeObOpenHook( + __inout PKPH_OB_OPEN_HOOK ObOpenHook, + __in POBJECT_TYPE ObjectType, + __in PVOID Target51, + __in PVOID Target60 + ); + +NTSTATUS KphObOpenHook( + __inout PKPH_OB_OPEN_HOOK ObOpenHook + ); + +NTSTATUS KphObOpenUnhook( + __inout PKPH_OB_OPEN_HOOK ObOpenHook + ); + +#endif diff --git a/branches/ph-plugins/KProcessHacker/include/io.h b/branches/ph-plugins/KProcessHacker/include/io.h new file mode 100644 index 000000000..bc98fb151 --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/include/io.h @@ -0,0 +1,34 @@ +/* + * Process Hacker Driver - + * I/O manager + * + * Copyright (C) 2009 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 . + */ + +#ifndef _IO_H +#define _IO_H + +#include "types.h" + +extern POBJECT_TYPE *IoAdapterObjectType; +extern POBJECT_TYPE *IoControllerObjectType; +extern POBJECT_TYPE *IoDeviceHandlerObjectType; /* not used anymore */ +extern POBJECT_TYPE *IoDeviceObjectType; +extern POBJECT_TYPE *IoDriverObjectType; + +#endif \ No newline at end of file diff --git a/branches/ph-plugins/KProcessHacker/include/ke.h b/branches/ph-plugins/KProcessHacker/include/ke.h new file mode 100644 index 000000000..741c1b00b --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/include/ke.h @@ -0,0 +1,95 @@ +/* + * Process Hacker Driver - + * kernel + * + * Copyright (C) 2009 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 . + */ + +#ifndef _KE_H +#define _KE_H + +#include "types.h" + +/* APCs */ + +typedef enum _KAPC_ENVIRONMENT +{ + OriginalApcEnvironment, + AttachedApcEnvironment, + CurrentApcEnvironment, + InsertApcEnvironment +} KAPC_ENVIRONMENT, *PKAPC_ENVIRONMENT; + +typedef VOID (NTAPI *PKKERNEL_ROUTINE)( + PKAPC Apc, + PKNORMAL_ROUTINE *NormalRoutine, + PVOID *NormalContext, + PVOID *SystemArgument1, + PVOID *SystemArgument2 + ); + +typedef VOID (NTAPI *PKRUNDOWN_ROUTINE)( + PKAPC Apc + ); + +typedef VOID (NTAPI *PKNORMAL_ROUTINE)( + PVOID NormalContext, + PVOID SystemArgument1, + PVOID SystemArgument2 + ); + +NTKERNELAPI VOID NTAPI KeInitializeApc( + PKAPC Apc, + PKTHREAD Thread, + KAPC_ENVIRONMENT Environment, + PKKERNEL_ROUTINE KernelRoutine, + PKRUNDOWN_ROUTINE RundownRoutine, + PKNORMAL_ROUTINE NormalRoutine, + KPROCESSOR_MODE ProcessorMode, + PVOID NormalContext + ); + +NTKERNELAPI BOOLEAN NTAPI KeInsertQueueApc( + PRKAPC Apc, + PVOID SystemArgument1, + PVOID SystemArgument2, + KPRIORITY Increment + ); + +/* System services */ + +/* Exported by ntoskrnl as KeServiceDescriptorTable. */ +typedef struct _KSERVICE_TABLE_DESCRIPTOR +{ + /* A pointer to an array of ULONG_PTRs - addresses of + * system services. + */ + PULONG_PTR Base; + /* A pointer to an array of ULONGs which contain counters for + * the system services. + */ + PULONG Count; + /* The number of system services. */ + ULONG Limit; + /* A pointer to an array of UCHARs which contain + * the number of arguments (in bytes) for each system service. + */ + PUCHAR Number; +} KSERVICE_TABLE_DESCRIPTOR, *PKSERVICE_TABLE_DESCRIPTOR; + +#endif \ No newline at end of file diff --git a/branches/ph-plugins/KProcessHacker/include/kph.h b/branches/ph-plugins/KProcessHacker/include/kph.h new file mode 100644 index 000000000..91e0b3db4 --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/include/kph.h @@ -0,0 +1,503 @@ +/* + * Process Hacker Driver - + * custom APIs + * + * Copyright (C) 2009 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 . + */ + +#ifndef _KPH_H +#define _KPH_H + +#include "types.h" +#include "debug.h" +#include "ref.h" +#include "version.h" + +#include "ke.h" +#include "mm.h" +#include "ps.h" +#include "trace.h" +#include "zw.h" + +#define MAX_UINTEGER(Bits) ((1 << (Bits)) - 1) +#define BITS_UCHAR 8 +#define MAX_UCHAR MAX_UINTEGER(BITS_UCHAR) +#define BITS_USHORT 16 +#define MAX_USHORT MAX_UINTEGER(BITS_USHORT) +#define BITS_ULONG 32 +#define MAX_ULONG MAX_UINTEGER(BITS_ULONG) + +#define SYSTEM_PROCESS_ID ((HANDLE)4) +#define KERNEL_HANDLE_BIT ((ULONG_PTR)1 << (sizeof(HANDLE) * 8 - 1)) +#define IsKernelHandle(Handle) ((LONG_PTR)(Handle) < 0) +#define MakeKernelHandle(Handle) ((ULONG_PTR)(Handle) |= KERNEL_HANDLE_BIT) + +#define PTR_ADD_OFFSET(Pointer, Offset) ((PVOID)((ULONG_PTR)(Pointer) + (ULONG_PTR)(Offset))) + +#define GET_BIT(Integer, Bit) (((Integer) >> (Bit)) & 0x1) +#define SET_BIT(Integer, Bit) ((Integer) |= 1 << (Bit)) +#define CLEAR_BIT(Integer, Bit) ((Integer) &= ~(1 << (Bit))) + +#define KPH_TIMEOUT_TO_SEC ((LONGLONG) 1 * 10 * 1000 * 1000) +#define KPH_REL_TIMEOUT_IN_SEC(Time) (Time * -1 * KPH_TIMEOUT_TO_SEC) + +#define TAG_CAPTURED_UNICODE_STRING ('UChP') + +#ifdef EXT +#undef EXT +#endif + +#ifdef _KPH_PRIVATE +#define EXT +#define EQNULL = NULL +#else +#define EXT extern +#define EQNULL +#endif + +EXT PKSERVICE_TABLE_DESCRIPTOR __KeServiceDescriptorTable EQNULL; +EXT PVOID __KiFastCallEntry EQNULL; +EXT _NtClose __NtClose EQNULL; +EXT _ObGetObjectType ObGetObjectType EQNULL; +EXT _PsGetProcessJob PsGetProcessJob EQNULL; +EXT _PsResumeProcess PsResumeProcess EQNULL; +EXT _PsSuspendProcess PsSuspendProcess EQNULL; +EXT _PsTerminateProcess __PsTerminateProcess EQNULL; +EXT PVOID __PspTerminateThreadByPointer EQNULL; +EXT _NtClose __ZwClose EQNULL; + +/* Driver information */ + +typedef enum _DRIVER_INFORMATION_CLASS +{ + DriverBasicInformation, + DriverNameInformation, + DriverServiceKeyNameInformation, + MaxDriverInfoClass +} DRIVER_INFORMATION_CLASS; + +typedef struct _DRIVER_BASIC_INFORMATION +{ + ULONG Flags; + PVOID DriverStart; + ULONG DriverSize; +} DRIVER_BASIC_INFORMATION, *PDRIVER_BASIC_INFORMATION; + +typedef struct _KPH_ATTACH_STATE +{ + BOOLEAN Attached; + PEPROCESS Process; + KAPC_STATE ApcState; +} KPH_ATTACH_STATE, *PKPH_ATTACH_STATE; + +typedef struct _MAPPED_MDL +{ + PMDL Mdl; + PVOID Address; +} MAPPED_MDL, *PMAPPED_MDL; + +typedef struct _PROCESS_HANDLE +{ + HANDLE Handle; + PVOID Object; + ACCESS_MASK GrantedAccess; + ULONG HandleAttributes; +} PROCESS_HANDLE, *PPROCESS_HANDLE; + +typedef struct _PROCESS_HANDLE_INFORMATION +{ + ULONG HandleCount; + PROCESS_HANDLE Handles[1]; +} PROCESS_HANDLE_INFORMATION, *PPROCESS_HANDLE_INFORMATION; + +/* Support routines */ + +NTSTATUS KphNtInit(); + +PVOID GetSystemRoutineAddress( + WCHAR *Name + ); + +VOID KphAttachProcess( + __in PEPROCESS Process, + __out PKPH_ATTACH_STATE AttachState + ); + +NTSTATUS KphAttachProcessHandle( + __in HANDLE ProcessHandle, + __out PKPH_ATTACH_STATE AttachState + ); + +NTSTATUS KphAttachProcessId( + __in HANDLE ProcessId, + __out PKPH_ATTACH_STATE AttachState + ); + +NTSTATUS KphCaptureUnicodeString( + __in PUNICODE_STRING UnicodeString, + __out PUNICODE_STRING CapturedUnicodeString + ); + +VOID KphDetachProcess( + __in PKPH_ATTACH_STATE AttachState + ); + +VOID KphFreeCapturedUnicodeString( + __in PUNICODE_STRING CapturedUnicodeString + ); + +VOID KphProbeForReadUnicodeString( + __in PUNICODE_STRING UnicodeString + ); + +VOID KphProbeSystemAddressRange( + __in PVOID BaseAddress, + __in ULONG Length + ); + +NTSTATUS OpenProcess( + __out PHANDLE ProcessHandle, + __in ACCESS_MASK DesiredAccess, + __in HANDLE ProcessId + ); + +NTSTATUS SetProcessToken( + __in HANDLE sourcePid, + __in HANDLE targetPid + ); + +/* KProcessHacker */ + +BOOLEAN KphAcquireProcessRundownProtection( + __in PEPROCESS Process + ); + +NTSTATUS KphAssignImpersonationToken( + __in HANDLE ThreadHandle, + __in HANDLE TokenHandle + ); + +NTSTATUS KphCaptureStackBackTraceThread( + __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 KphDangerousTerminateThread( + __in HANDLE ThreadHandle, + __in NTSTATUS ExitStatus + ); + +NTSTATUS KphDuplicateObject( + __in HANDLE SourceProcessHandle, + __in HANDLE SourceHandle, + __in_opt HANDLE TargetProcessHandle, + __out_opt PHANDLE TargetHandle, + __in ACCESS_MASK DesiredAccess, + __in ULONG HandleAttributes, + __in ULONG Options, + __in KPROCESSOR_MODE AccessMode + ); + +BOOLEAN KphEnumProcessHandleTable( + __in PEPROCESS Process, + __in PEX_ENUM_HANDLE_CALLBACK EnumHandleProcedure, + __inout PVOID Context, + __out_opt PHANDLE Handle + ); + +NTSTATUS KphGetContextThread( + __in HANDLE ThreadHandle, + __inout PCONTEXT ThreadContext, + __in KPROCESSOR_MODE AccessMode + ); + +POBJECT_TYPE KphGetObjectTypeNt( + __in PVOID Object + ); + +HANDLE KphGetProcessId( + __in HANDLE ProcessHandle + ); + +HANDLE KphGetThreadId( + __in HANDLE ThreadHandle, + __out_opt PHANDLE ProcessId + ); + +NTSTATUS KphGetThreadWin32Thread( + __in HANDLE ThreadHandle, + __out PVOID *Win32Thread, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS KphOpenDevice( + __out PHANDLE DeviceHandle, + __in POBJECT_ATTRIBUTES ObjectAttributes, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS KphOpenDirectoryObject( + __out PHANDLE DirectoryObjectHandle, + __in ACCESS_MASK DesiredAccess, + __in POBJECT_ATTRIBUTES ObjectAttributes, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS KphOpenDriver( + __out PHANDLE DriverHandle, + __in POBJECT_ATTRIBUTES ObjectAttributes, + __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 + ); + +NTSTATUS KphOpenProcess( + __out PHANDLE ProcessHandle, + __in ACCESS_MASK DesiredAccess, + __in POBJECT_ATTRIBUTES ObjectAttributes, + __in_opt PCLIENT_ID ClientId, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS KphOpenProcessJob( + __in HANDLE ProcessHandle, + __in ACCESS_MASK DesiredAccess, + __out PHANDLE JobHandle, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS KphOpenProcessTokenEx( + __in HANDLE ProcessHandle, + __in ACCESS_MASK DesiredAccess, + __in ULONG ObjectAttributes, + __out PHANDLE TokenHandle, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS KphOpenThread( + __out PHANDLE ThreadHandle, + __in ACCESS_MASK DesiredAccess, + __in POBJECT_ATTRIBUTES ObjectAttributes, + __in_opt PCLIENT_ID ClientId, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS KphOpenThreadProcess( + __in HANDLE ThreadHandle, + __in ACCESS_MASK DesiredAccess, + __out PHANDLE ProcessHandle, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS KphQueryInformationDriver( + __in HANDLE DriverHandle, + __in DRIVER_INFORMATION_CLASS DriverInformationClass, + __out_bcount_opt(DriverInformationLength) PVOID DriverInformation, + __in ULONG DriverInformationLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS KphQueryNameFileObject( + __in PFILE_OBJECT FileObject, + __inout_bcount(BufferLength) PUNICODE_STRING Buffer, + __in ULONG BufferLength, + __out PULONG ReturnLength + ); + +NTSTATUS KphQueryNameObject( + __in PVOID Object, + __inout_bcount(BufferLength) PUNICODE_STRING Buffer, + __in ULONG BufferLength, + __out PULONG ReturnLength + ); + +NTSTATUS KphQueryProcessHandles( + __in HANDLE ProcessHandle, + __out_bcount_opt(BufferLength) PPROCESS_HANDLE_INFORMATION Buffer, + __in_opt ULONG BufferLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS KphReadVirtualMemory( + __in HANDLE ProcessHandle, + __in PVOID BaseAddress, + __out_bcount(BufferLength) PVOID Buffer, + __in ULONG BufferLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode + ); + +VOID KphReleaseProcessRundownProtection( + __in PEPROCESS Process + ); + +NTSTATUS KphResumeProcess( + __in HANDLE ProcessHandle + ); + +NTSTATUS KphSetContextThread( + __in HANDLE ThreadHandle, + __in PCONTEXT ThreadContext, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS KphSetHandleGrantedAccess( + __in PEPROCESS Process, + __in HANDLE Handle, + __in ACCESS_MASK GrantedAccess + ); + +NTSTATUS KphSuspendProcess( + __in HANDLE ProcessHandle + ); + +NTSTATUS KphTerminateProcess( + __in HANDLE ProcessHandle, + __in NTSTATUS ExitStatus + ); + +NTSTATUS KphTerminateThread( + __in HANDLE ThreadHandle, + __in NTSTATUS ExitStatus + ); + +NTSTATUS KphUnsafeReadVirtualMemory( + __in HANDLE ProcessHandle, + __in PVOID BaseAddress, + __out_bcount(BufferLength) PVOID Buffer, + __in ULONG BufferLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS KphWriteVirtualMemory( + __in HANDLE ProcessHandle, + __in PVOID BaseAddress, + __in_bcount(BufferLength) PVOID Buffer, + __in ULONG BufferLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode + ); + +/* MM */ + +NTSTATUS MiDoMappedCopy( + __in PEPROCESS FromProcess, + __in PVOID FromAddress, + __in PEPROCESS ToProcess, + __in PVOID ToAddress, + __in ULONG BufferLength, + __in KPROCESSOR_MODE AccessMode, + __out PULONG ReturnLength + ); + +NTSTATUS MiDoPoolCopy( + __in PEPROCESS FromProcess, + __in PVOID FromAddress, + __in PEPROCESS ToProcess, + __in PVOID ToAddress, + __in ULONG BufferLength, + __in KPROCESSOR_MODE AccessMode, + __out PULONG ReturnLength + ); + +ULONG MiGetExceptionInfo( + __in PEXCEPTION_POINTERS ExceptionInfo, + __out PBOOLEAN HaveBadAddress, + __out PULONG_PTR BadAddress + ); + +NTSTATUS MmCopyVirtualMemory( + __in PEPROCESS FromProcess, + __in PVOID FromAddress, + __in PEPROCESS ToProcess, + __in PVOID ToAddress, + __in ULONG BufferLength, + __in KPROCESSOR_MODE AccessMode, + __out PULONG ReturnLength + ); + +/* KProcessHacker private */ + +NTSTATUS KphpCaptureStackBackTraceThread( + __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 KphpCreateMappedMdl( + __in PVOID Address, + __in ULONG Length, + __out PMAPPED_MDL MappedMdl + ); + +VOID KphpFreeMappedMdl( + __in PMAPPED_MDL MappedMdl + ); + +/* OB */ + +NTSTATUS ObDuplicateObject( + __in PEPROCESS SourceProcess, + __in_opt PEPROCESS TargetProcess, + __in HANDLE SourceHandle, + __out_opt PHANDLE TargetHandle, + __in ACCESS_MASK DesiredAccess, + __in ULONG HandleAttributes, + __in ULONG Options, + __in KPROCESSOR_MODE AccessMode + ); + +PHANDLE_TABLE ObReferenceProcessHandleTable( + __in PEPROCESS Process + ); + +VOID ObDereferenceProcessHandleTable( + __in PEPROCESS Process + ); + +/* PS */ + +NTSTATUS PsTerminateProcess( + __in PEPROCESS Process, + __in NTSTATUS ExitStatus + ); + +NTSTATUS PspTerminateThreadByPointer( + __in PETHREAD Thread, + __in NTSTATUS ExitStatus + ); + +#endif \ No newline at end of file diff --git a/branches/ph-plugins/KProcessHacker/include/kprocesshacker.h b/branches/ph-plugins/KProcessHacker/include/kprocesshacker.h new file mode 100644 index 000000000..4b45f01dc --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/include/kprocesshacker.h @@ -0,0 +1,165 @@ +/* + * Process Hacker Driver - + * main header file + * + * Copyright (C) 2009 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 . + */ + +#ifndef KPROCESSHACKER_H +#define KPROCESSHACKER_H + +#include "include/kph.h" +#include "include/handle.h" +#include "include/ref.h" +#include "include/sync.h" + +/* KPH Configuration */ + +//#define KPH_REQUIRE_DEBUG_PRIVILEGE + +/* Device */ + +#define KPH_DEVICE_TYPE (0x9999) +#define KPH_DEVICE_NAME (L"\\Device\\KProcessHacker") +#define KPH_DEVICE_DOS_NAME (L"\\DosDevices\\KProcessHacker") + +/* Features */ + +#define KPHF_PSTERMINATEPROCESS 0x1 +#define KPHF_PSPTERMINATETHREADBPYPOINTER 0x2 + +/* Control Codes */ + +#define KPH_CTL_CODE(x) CTL_CODE(KPH_DEVICE_TYPE, 0x800 + x, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define KPH_CLOSEHANDLE KPH_CTL_CODE(0) +#define KPH_SSQUERYCLIENTENTRY KPH_CTL_CODE(1) +#define KPH_RESERVED1 KPH_CTL_CODE(2) +#define KPH_OPENPROCESS KPH_CTL_CODE(3) +#define KPH_OPENTHREAD KPH_CTL_CODE(4) +#define KPH_OPENPROCESSTOKEN KPH_CTL_CODE(5) +#define KPH_GETPROCESSPROTECTED KPH_CTL_CODE(6) +#define KPH_SETPROCESSPROTECTED KPH_CTL_CODE(7) +#define KPH_TERMINATEPROCESS KPH_CTL_CODE(8) +#define KPH_SUSPENDPROCESS KPH_CTL_CODE(9) +#define KPH_RESUMEPROCESS KPH_CTL_CODE(10) +#define KPH_READVIRTUALMEMORY KPH_CTL_CODE(11) +#define KPH_WRITEVIRTUALMEMORY KPH_CTL_CODE(12) +#define KPH_SETPROCESSTOKEN KPH_CTL_CODE(13) +#define KPH_GETTHREADSTARTADDRESS KPH_CTL_CODE(14) +#define KPH_SETHANDLEATTRIBUTES KPH_CTL_CODE(15) +#define KPH_GETHANDLEOBJECTNAME KPH_CTL_CODE(16) +#define KPH_OPENPROCESSJOB KPH_CTL_CODE(17) +#define KPH_GETCONTEXTTHREAD KPH_CTL_CODE(18) +#define KPH_SETCONTEXTTHREAD KPH_CTL_CODE(19) +#define KPH_GETTHREADWIN32THREAD KPH_CTL_CODE(20) +#define KPH_DUPLICATEOBJECT KPH_CTL_CODE(21) +#define KPH_ZWQUERYOBJECT KPH_CTL_CODE(22) +#define KPH_GETPROCESSID KPH_CTL_CODE(23) +#define KPH_GETTHREADID KPH_CTL_CODE(24) +#define KPH_TERMINATETHREAD KPH_CTL_CODE(25) +#define KPH_GETFEATURES KPH_CTL_CODE(26) +#define KPH_SETHANDLEGRANTEDACCESS KPH_CTL_CODE(27) +#define KPH_ASSIGNIMPERSONATIONTOKEN KPH_CTL_CODE(28) +#define KPH_PROTECTADD KPH_CTL_CODE(29) +#define KPH_PROTECTREMOVE KPH_CTL_CODE(30) +#define KPH_PROTECTQUERY KPH_CTL_CODE(31) +#define KPH_UNSAFEREADVIRTUALMEMORY KPH_CTL_CODE(32) +#define KPH_SETEXECUTEOPTIONS KPH_CTL_CODE(33) +#define KPH_QUERYPROCESSHANDLES KPH_CTL_CODE(34) +#define KPH_OPENTHREADPROCESS KPH_CTL_CODE(35) +#define KPH_CAPTURESTACKBACKTRACETHREAD KPH_CTL_CODE(36) +#define KPH_DANGEROUSTERMINATETHREAD KPH_CTL_CODE(37) +#define KPH_OPENDEVICE KPH_CTL_CODE(38) +#define KPH_OPENDRIVER KPH_CTL_CODE(39) +#define KPH_QUERYINFORMATIONDRIVER KPH_CTL_CODE(40) +#define KPH_OPENDIRECTORYOBJECT KPH_CTL_CODE(41) +#define KPH_SSREF KPH_CTL_CODE(42) +#define KPH_SSUNREF KPH_CTL_CODE(43) +#define KPH_SSCREATECLIENTENTRY KPH_CTL_CODE(44) +#define KPH_SSCREATERULESETENTRY KPH_CTL_CODE(45) +#define KPH_SSREMOVERULE KPH_CTL_CODE(46) +#define KPH_SSADDPROCESSIDRULE KPH_CTL_CODE(47) +#define KPH_SSADDTHREADIDRULE KPH_CTL_CODE(48) +#define KPH_SSADDPREVIOUSMODERULE KPH_CTL_CODE(49) +#define KPH_SSADDNUMBERRULE KPH_CTL_CODE(50) +#define KPH_SSENABLECLIENTENTRY KPH_CTL_CODE(51) + +/* Standard Driver Routines */ + +NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath); +VOID DriverUnload(PDRIVER_OBJECT DriverObject); +NTSTATUS KphDispatchCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp); +NTSTATUS KphDispatchClose(PDEVICE_OBJECT DeviceObject, PIRP Irp); +NTSTATUS KphDispatchDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp); +NTSTATUS KphDispatchRead(PDEVICE_OBJECT DeviceObject, PIRP Irp); +NTSTATUS KphUnsupported(PDEVICE_OBJECT DeviceObject, PIRP Irp); + +/* Clients */ + +#define TAG_CLIENT_HANDLETABLE ('HChP') +#define KPH_CLIENT_SSMAXCOUNT 1000 +#define KPH_CLIENT_MAXHANDLES 100 + +typedef struct _KPH_CLIENT_ENTRY +{ + LIST_ENTRY ClientListEntry; + HANDLE ProcessId; + PKPH_HANDLE_TABLE HandleTable; + + KPH_GUARDED_LOCK SsLock; + /* The number of times the client has "started" the system service logger. */ + LONG SsStartCount; +} KPH_CLIENT_ENTRY, *PKPH_CLIENT_ENTRY; + +/* Functions */ + +VOID SsRef(LONG count); +VOID SsUnref(LONG count); + +VOID NTAPI ClientEntryDeleteProcedure( + __in PVOID Object, + __in ULONG Flags + ); + +PKPH_CLIENT_ENTRY CreateClientEntry( + __in HANDLE ProcessId + ); + +PKPH_CLIENT_ENTRY ReferenceClientEntry( + __in_opt HANDLE ProcessId + ); + +NTSTATUS CloseClientHandle( + __in_opt HANDLE ProcessId, + __in HANDLE Handle + ); + +NTSTATUS CreateClientHandle( + __in_opt HANDLE ProcessId, + __in PVOID Object, + __out PHANDLE Handle + ); + +NTSTATUS ReferenceClientHandle( + __in_opt HANDLE ProcessId, + __in HANDLE Handle, + __in PKPH_OBJECT_TYPE ObjectType, + __out PVOID *Object + ); + +#endif \ No newline at end of file diff --git a/branches/ph-plugins/KProcessHacker/include/mm.h b/branches/ph-plugins/KProcessHacker/include/mm.h new file mode 100644 index 000000000..07206dc0a --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/include/mm.h @@ -0,0 +1,37 @@ +/* + * Process Hacker Driver - + * memory manager + * + * Copyright (C) 2009 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 . + */ + +#ifndef _MM_H +#define _MM_H + +#define MI_MAX_TRANSFER_SIZE (0x10000) +#define MI_COPY_STACK_SIZE (0x200) +#define MI_MAPPED_COPY_PAGES (14) +#define MM_POOL_COPY_THRESHOLD (0x1ff) +#define TAG_POOL_COPY ('CPhP') + +#define MEM_EXECUTE_OPTION_DISABLE 0x1 +#define MEM_EXECUTE_OPTION_ENABLE 0x2 +#define MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION 0x4 +#define MEM_EXECUTE_OPTION_PERMANENT 0x8 + +#endif \ No newline at end of file diff --git a/branches/ph-plugins/KProcessHacker/include/ob.h b/branches/ph-plugins/KProcessHacker/include/ob.h new file mode 100644 index 000000000..783629c12 --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/include/ob.h @@ -0,0 +1,168 @@ +/* + * Process Hacker Driver - + * object manager + * + * Copyright (C) 2009 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 . + */ + +#ifndef _OB_H +#define _OB_H + +#include "types.h" +#include "ex.h" + +#define OBJECT_TO_OBJECT_HEADER(o) \ + CONTAINING_RECORD((o), OBJECT_HEADER, Body) + +#define OBJ_PROTECT_CLOSE 0x00000001L +#define OBJ_INHERIT 0x00000002L +#define OBJ_AUDIT_OBJECT_CLOSE 0x00000004L +#define OBJ_HANDLE_ATTRIBUTES (OBJ_PROTECT_CLOSE | OBJ_INHERIT | OBJ_AUDIT_OBJECT_CLOSE) + +#define ObpDecodeGrantedAccess(Access) \ + ((Access) & ~ObpAccessProtectCloseBit) +#define ObpDecodeObject(Object) \ + ((PVOID)((ULONG_PTR)(Object) & ~OBJ_HANDLE_ATTRIBUTES)) +#define ObpGetHandleAttributes(HandleTableEntry) \ + (((HandleTableEntry)->GrantedAccess & ObpAccessProtectCloseBit) ? \ + (((HandleTableEntry)->Value & OBJ_HANDLE_ATTRIBUTES) | OBJ_PROTECT_CLOSE) : \ + ((HandleTableEntry)->Value & (OBJ_INHERIT | OBJ_AUDIT_OBJECT_CLOSE))) + +/* FUNCTION DEFS */ + +struct _OBJECT_HANDLE_FLAG_INFORMATION; +typedef struct _OBJECT_TYPE_INITIALIZER OBJECT_TYPE_INITIALIZER, *POBJECT_TYPE_INITIALIZER; + +NTSTATUS NTAPI ObCreateObjectType( + __in PUNICODE_STRING TypeName, + __in POBJECT_TYPE_INITIALIZER ObjectTypeInitializer, + __in PSECURITY_DESCRIPTOR SecurityDescriptor, + __out_opt POBJECT_TYPE *ObjectType + ); + +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 + ); + +NTSTATUS NTAPI ObSetHandleAttributes( + __in HANDLE Handle, + __in struct _OBJECT_HANDLE_FLAG_INFORMATION *HandleFlags, + __in KPROCESSOR_MODE PreviousMode + ); + +/* FUNCTION TYPEDEFS */ + +/* Seven+ */ +typedef POBJECT_TYPE (NTAPI *_ObGetObjectType)( + __in PVOID Object + ); + +enum _OB_OPEN_REASON; + +typedef NTSTATUS (NTAPI *OB_OPEN_METHOD_51)( + enum _OB_OPEN_REASON OpenReason, + PEPROCESS Process, + PVOID Object, + ACCESS_MASK GrantedAccess, + ULONG HandleCount + ); + +typedef NTSTATUS (NTAPI *OB_OPEN_METHOD_60)( + enum _OB_OPEN_REASON OpenReason, + KPROCESSOR_MODE AccessMode, + PEPROCESS Process, + PVOID Object, + ACCESS_MASK GrantedAccess, + ULONG HandleCount + ); + +/* ENUMS */ +typedef enum _OB_OPEN_REASON +{ + ObCreateHandle, + ObOpenHandle, + ObDuplicateHandle, + ObInheritHandle, + ObMaxOpenReason +} OB_OPEN_REASON, *POB_OPEN_REASON; + +/* STRUCTS */ + +typedef struct _OBP_QUERY_PROCESS_HANDLES_DATA +{ + PVOID Buffer; + ULONG BufferLength; + ULONG CurrentIndex; + NTSTATUS Status; +} OBP_QUERY_PROCESS_HANDLES_DATA, *POBP_QUERY_PROCESS_HANDLES_DATA; + +typedef struct _OBP_SET_HANDLE_GRANTED_ACCESS_DATA +{ + HANDLE Handle; + ACCESS_MASK GrantedAccess; +} OBP_SET_HANDLE_GRANTED_ACCESS_DATA, *POBP_SET_HANDLE_GRANTED_ACCESS_DATA; + +typedef struct _OBJECT_HANDLE_FLAG_INFORMATION +{ + BOOLEAN Inherit; + BOOLEAN ProtectFromClose; +} OBJECT_HANDLE_FLAG_INFORMATION, *POBJECT_HANDLE_FLAG_INFORMATION; + +typedef struct _OBJECT_CREATE_INFORMATION OBJECT_CREATE_INFORMATION, *POBJECT_CREATE_INFORMATION; + +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; + +typedef struct _HANDLE_TABLE_ENTRY +{ + union + { + PVOID Object; + ULONG Value; + }; + ULONG GrantedAccess; +} HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY; + +typedef struct _HANDLE_TABLE HANDLE_TABLE, *PHANDLE_TABLE; + +#endif diff --git a/branches/ph-plugins/KProcessHacker/include/protect.h b/branches/ph-plugins/KProcessHacker/include/protect.h new file mode 100644 index 000000000..b714ab1b0 --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/include/protect.h @@ -0,0 +1,95 @@ +/* + * Process Hacker Driver - + * process protection + * + * Copyright (C) 2009 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 . + */ + +#ifndef _PROTECT_H +#define _PROTECT_H + +#include "hook.h" + +#define TAG_PROTECTION_ENTRY ('rPhP') + +#define OBOPENOBJECTBYPOINTER_ARGS \ + PVOID Object, \ + ULONG HandleAttributes, \ + PACCESS_STATE PassedAccessState, \ + ACCESS_MASK DesiredAccess, \ + POBJECT_TYPE ObjectType, \ + KPROCESSOR_MODE AccessMode, \ + PHANDLE Handle + +typedef struct _KPH_PROCESS_ENTRY +{ + LIST_ENTRY ListEntry; + PEPROCESS Process; + PEPROCESS CreatorProcess; + HANDLE Tag; + LOGICAL AllowKernelMode; + ACCESS_MASK ProcessAllowMask; + ACCESS_MASK ThreadAllowMask; +} KPH_PROCESS_ENTRY, *PKPH_PROCESS_ENTRY; + +NTSTATUS NTAPI KphNewObOpenObjectByPointer(OBOPENOBJECTBYPOINTER_ARGS); +NTSTATUS NTAPI KphOldObOpenObjectByPointer(OBOPENOBJECTBYPOINTER_ARGS); + +NTSTATUS NTAPI KphNewOpenProcedure51( + __in OB_OPEN_REASON OpenReason, + __in PEPROCESS Process, + __in PVOID Object, + __in ACCESS_MASK GrantedAccess, + __in ULONG HandleCount + ); + +NTSTATUS NTAPI KphNewOpenProcedure60( + __in OB_OPEN_REASON OpenReason, + __in KPROCESSOR_MODE AccessMode, + __in PEPROCESS Process, + __in PVOID Object, + __in ACCESS_MASK GrantedAccess, + __in ULONG HandleCount + ); + +NTSTATUS KphProtectInit(); +NTSTATUS KphProtectDeinit(); + +PKPH_PROCESS_ENTRY KphProtectAddEntry( + __in PEPROCESS Process, + __in HANDLE Tag, + __in LOGICAL AllowKernelMode, + __in ACCESS_MASK ProcessAllowMask, + __in ACCESS_MASK ThreadAllowMask + ); + +PKPH_PROCESS_ENTRY KphProtectFindEntry( + __in PEPROCESS Process, + __in HANDLE Tag, + __out_opt PKPH_PROCESS_ENTRY ProcessEntryCopy + ); + +BOOLEAN KphProtectRemoveByProcess( + __in PEPROCESS Process + ); + +ULONG KphProtectRemoveByTag( + __in HANDLE Tag + ); + +#endif diff --git a/branches/ph-plugins/KProcessHacker/include/ps.h b/branches/ph-plugins/KProcessHacker/include/ps.h new file mode 100644 index 000000000..df68bb16e --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/include/ps.h @@ -0,0 +1,151 @@ +/* + * Process Hacker Driver - + * processes and threads + * + * Copyright (C) 2009 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 . + */ + +#ifndef _PS_H +#define _PS_H + +#include "types.h" +#include "ex.h" +#include "mm.h" +#include "ob.h" +#include "se.h" + +#define TAG_CAPTURE_STACK_BACKTRACE ('tShP') + +#define PROCESS_TERMINATE (0x0001) +#define PROCESS_CREATE_THREAD (0x0002) +#define PROCESS_SET_SESSIONID (0x0004) +#define PROCESS_VM_OPERATION (0x0008) +#define PROCESS_VM_READ (0x0010) +#define PROCESS_VM_WRITE (0x0020) +#define PROCESS_DUP_HANDLE (0x0040) +#define PROCESS_CREATE_PROCESS (0x0080) +#define PROCESS_SET_QUOTA (0x0100) +#define PROCESS_SET_INFORMATION (0x0200) +#define PROCESS_QUERY_INFORMATION (0x0400) +#define PROCESS_SUSPEND_RESUME (0x0800) +#define PROCESS_QUERY_LIMITED_INFORMATION (0x1000) +#ifndef PROCESS_ALL_ACCESS +#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xffff) +#endif + +#define THREAD_TERMINATE (0x0001) +#define THREAD_SUSPEND_RESUME (0x0002) +#define THREAD_ALERT (0x0004) +#define THREAD_GET_CONTEXT (0x0008) +#define THREAD_SET_CONTEXT (0x0010) +#define THREAD_SET_INFORMATION (0x0020) +#define THREAD_QUERY_INFORMATION (0x0040) +#define THREAD_SET_THREAD_TOKEN (0x0080) +#define THREAD_IMPERSONATE (0x0100) +#define THREAD_DIRECT_IMPERSONATION (0x0200) +#ifndef THREAD_ALL_ACCESS +#define THREAD_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff) +#endif + +#define JOB_OBJECT_ASSIGN_PROCESS (0x0001) +#define JOB_OBJECT_SET_ATTRIBUTES (0x0002) +#define JOB_OBJECT_QUERY (0x0004) +#define JOB_OBJECT_TERMINATE (0x0008) +#define JOB_OBJECT_SET_SECURITY_ATTRIBUTES (0x0010) +#define JOB_OBJECT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1f) + +extern POBJECT_TYPE *PsJobType; + +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; + +typedef struct _EXIT_THREAD_CONTEXT +{ + KAPC Apc; + KEVENT CompletedEvent; + NTSTATUS ExitStatus; +} EXIT_THREAD_CONTEXT, *PEXIT_THREAD_CONTEXT; + +/* FUNCTION DEFS */ + +NTSTATUS NTAPI PsGetContextThread( + __in PETHREAD Thread, + __inout PCONTEXT ThreadContext, + __in KPROCESSOR_MODE PreviousMode + ); + +BOOLEAN NTAPI PsGetProcessExitProcessCalled( + __in PEPROCESS Process + ); + +PVOID NTAPI PsGetThreadWin32Thread( + __in PETHREAD Thread + ); + +NTSTATUS NTAPI PsLookupProcessThreadByCid( + __in PCLIENT_ID ClientId, + __out_opt PEPROCESS *Process, + __out PETHREAD *Thread + ); + +NTSTATUS NTAPI PsSetContextThread( + __in PETHREAD Thread, + __in PCONTEXT ThreadContext, + __in KPROCESSOR_MODE PreviousMode + ); + +/* FUNCTION TYPEDEFS */ + +typedef PVOID (NTAPI *_PsGetProcessJob)( + PEPROCESS Process + ); + +typedef NTSTATUS (NTAPI *_PsResumeProcess)( + PEPROCESS Process + ); + +typedef NTSTATUS (NTAPI *_PsSuspendProcess)( + PEPROCESS Process + ); + +typedef NTSTATUS (NTAPI *_PsTerminateProcess)( + PEPROCESS Process, + NTSTATUS ExitStatus + ); + +typedef NTSTATUS (NTAPI *_PspTerminateThreadByPointer51)( + PETHREAD Thread, + NTSTATUS ExitStatus + ); + +typedef NTSTATUS (NTAPI *_PspTerminateThreadByPointer60)( + PETHREAD Thread, + NTSTATUS ExitStatus, + BOOLEAN DirectTerminate + ); + +#endif \ No newline at end of file diff --git a/branches/ph-plugins/KProcessHacker/include/ref.h b/branches/ph-plugins/KProcessHacker/include/ref.h new file mode 100644 index 000000000..03f9fdb9e --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/include/ref.h @@ -0,0 +1,113 @@ +/* + * Process Hacker Driver - + * internal object manager + * + * Copyright (C) 2009 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 . + */ + +#ifndef _REF_H +#define _REF_H + +#include "kph.h" + +/* Object flags */ +#define KPHOBJ_RAISE_ON_FAIL 0x00000001 +#define KPHOBJ_PAGED_POOL 0x00000002 +#define KPHOBJ_NONPAGED_POOL 0x00000004 +#define KPHOBJ_VALID_FLAGS 0x00000007 + +/* Object type flags */ +#define KPHOBJTYPE_PASSIVE_LEVEL_DELETE 0x00000001 +#define KPHOBJTYPE_VALID_FLAGS 0x00000001 + +/* Object type callbacks */ + +/* PKPH_TYPE_DELETE_PROCEDURE + * + * The delete procedure for an object type, called when + * an object of the type is being freed. + * + * Object: A pointer to the object being freed. + * Flags: The flags specified when the object was created. + * + * IRQL: = PASSIVE_LEVEL if the require passive level flag was + * specified for the object type, otherwise <= APC_LEVEL. + */ +typedef VOID (NTAPI *PKPH_TYPE_DELETE_PROCEDURE)( + __in PVOID Object, + __in ULONG Flags + ); + +struct _KPH_OBJECT_TYPE; +typedef struct _KPH_OBJECT_TYPE *PKPH_OBJECT_TYPE; + +#ifndef _REF_PRIVATE +extern PKPH_OBJECT_TYPE KphObjectTypeObject; +#endif + +NTSTATUS KphRefInit(); + +NTSTATUS KphRefDeinit(); + +NTSTATUS KphCreateObject( + __out PVOID *Object, + __in SIZE_T ObjectSize, + __in ULONG Flags, + __in_opt PKPH_OBJECT_TYPE ObjectType, + __in_opt LONG AdditionalReferences + ); + +NTSTATUS KphCreateObjectType( + __out PKPH_OBJECT_TYPE *ObjectType, + __in POOL_TYPE DefaultPoolType, + __in ULONG Flags, + __in PKPH_TYPE_DELETE_PROCEDURE DeleteProcedure + ); + +BOOLEAN KphDereferenceObject( + __in PVOID Object + ); + +BOOLEAN KphDereferenceObjectDeferDelete( + __in PVOID Object + ); + +LONG KphDereferenceObjectEx( + __in PVOID Object, + __in LONG RefCount, + __in BOOLEAN DeferDelete + ); + +PKPH_OBJECT_TYPE KphGetObjectType( + __in PVOID Object + ); + +VOID KphReferenceObject( + __in PVOID Object + ); + +LONG KphReferenceObjectEx( + __in PVOID Object, + __in LONG RefCount + ); + +BOOLEAN KphReferenceObjectSafe( + __in PVOID Object + ); + +#endif diff --git a/branches/ph-plugins/KProcessHacker/include/refp.h b/branches/ph-plugins/KProcessHacker/include/refp.h new file mode 100644 index 000000000..92456a857 --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/include/refp.h @@ -0,0 +1,137 @@ +/* + * Process Hacker Driver - + * internal object manager + * + * Copyright (C) 2009 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 . + */ + +#ifndef _REFP_H +#define _REFP_H + +#define _REF_PRIVATE +#include "ref.h" +#include "sync.h" + +#define TAG_KPHOBJ ('bOhP') + +#define KphObjectToObjectHeader(Object) ((PKPH_OBJECT_HEADER)CONTAINING_RECORD((PCHAR)(Object), KPH_OBJECT_HEADER, Body)) +#define KphObjectHeaderToObject(ObjectHeader) (&((PKPH_OBJECT_HEADER)(ObjectHeader))->Body) +#define KphpAddObjectHeaderSize(Size) ((Size) + sizeof(KPH_OBJECT_HEADER) - sizeof(QUAD)) + +typedef struct _KPH_OBJECT_HEADER *PKPH_OBJECT_HEADER; +typedef struct _KPH_OBJECT_TYPE *PKPH_OBJECT_TYPE; + +typedef struct _KPH_OBJECT_HEADER +{ + /* The reference count of the object. */ + LONG RefCount; + /* The flags that were used to create the object. */ + ULONG Flags; + union + { + /* The size of the object, excluding the header. */ + SIZE_T Size; + /* A pointer to the object header of the next object to free. */ + PKPH_OBJECT_HEADER NextToFree; + }; + /* The type of the object. */ + PKPH_OBJECT_TYPE Type; + /* A linked list entry for an optional object manager object list. + * For example, this may be used to free all objects when the + * driver exits. + */ + LIST_ENTRY GlobalObjectListEntry; + + /* The body of the object. For use by the KphObject(Header)ToObject(Header) macros. */ + QUAD Body; +} KPH_OBJECT_HEADER, *PKPH_OBJECT_HEADER; + +typedef struct _KPH_OBJECT_TYPE +{ + /* The default pool type for objects of this type, used when the + * pool type is not specified when an object is created. */ + POOL_TYPE DefaultPoolType; + /* The flags that were used to create the object type. */ + ULONG Flags; + /* An optional procedure called when objects of this type are freed. */ + PKPH_TYPE_DELETE_PROCEDURE DeleteProcedure; + + /* The total number of objects of this type that are alive. */ + ULONG NumberOfObjects; +} KPH_OBJECT_TYPE, *PKPH_OBJECT_TYPE; + +/* KphpInterlockedIncrementSafe + * + * Increments a reference count, but will never increment + * from 0 to 1. + */ +FORCEINLINE BOOLEAN KphpInterlockedIncrementSafe( + __inout PLONG RefCount + ) +{ + LONG refCount; + + /* Here we will attempt to increment the reference count, + * making sure that it is not 0. + */ + + while (TRUE) + { + refCount = *RefCount; + + /* Check if the reference count is 0. If it is, the + * object is being or about to be deleted. + */ + if (refCount == 0) + return FALSE; + + /* Try to increment the reference count. */ + if (InterlockedCompareExchange( + RefCount, + refCount + 1, + refCount + ) == refCount) + { + /* Success. */ + return TRUE; + } + + /* Someone else changed the reference count before we did. + * Go back and try again. + */ + } +} + +PKPH_OBJECT_HEADER KphpAllocateObject( + __in SIZE_T ObjectSize, + __in POOL_TYPE PoolType + ); + +VOID KphpDeferDeleteObject( + __in PKPH_OBJECT_HEADER ObjectHeader + ); + +VOID KphpDeferDeleteObjectRoutine( + __in PVOID Parameter + ); + +VOID KphpFreeObject( + __in PKPH_OBJECT_HEADER ObjectHeader + ); + +#endif diff --git a/branches/ph-plugins/KProcessHacker/include/se.h b/branches/ph-plugins/KProcessHacker/include/se.h new file mode 100644 index 000000000..947d59f5f --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/include/se.h @@ -0,0 +1,55 @@ +/* + * Process Hacker Driver - + * memory manager + * + * Copyright (C) 2009 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 . + */ + +#ifndef _SE_H +#define _SE_H + +#include "types.h" + +extern POBJECT_TYPE *SeTokenObjectType; + +/* Was 0x38 on Vista, appears to be 0xc8 on 7. */ +#define AUX_ACCESS_DATA_SIZE (0xc8) + +typedef PVOID PAUX_ACCESS_DATA; + +/* FUNCTION DEFS */ + +NTKERNELAPI NTSTATUS NTAPI SeCreateAccessState( + PACCESS_STATE AccessState, + PAUX_ACCESS_DATA AuxData, + ACCESS_MASK DesiredAccess, + PGENERIC_MAPPING Mapping + ); + +NTKERNELAPI VOID NTAPI SeDeleteAccessState( + PACCESS_STATE AccessState + ); + +/* STRUCTS */ + +typedef struct _SE_AUDIT_PROCESS_CREATION_INFO +{ + POBJECT_NAME_INFORMATION ImageFileName; +} SE_AUDIT_PROCESS_CREATION_INFO, *PSE_AUDIT_PROCESS_CREATION_INFO; + +#endif diff --git a/branches/ph-plugins/KProcessHacker/include/sync.h b/branches/ph-plugins/KProcessHacker/include/sync.h new file mode 100644 index 000000000..e344ea75e --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/include/sync.h @@ -0,0 +1,320 @@ +/* + * Process Hacker Driver - + * synchronization code + * + * Copyright (C) 2009 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 . + */ + +#ifndef _SYNC_H +#define _SYNC_H + +#include "kph.h" +#include "ex.h" + +/* General synchronization macros */ + +/* KphEqualSpin + * + * Spins until the first value is equal to the second + * value. + */ +FORCEINLINE VOID KphSpinUntilEqual( + __inout PLONG Value, + __in LONG Value2 + ) +{ + while (InterlockedCompareExchange( + Value, + Value2, + Value2 + ) != Value2) + YieldProcessor(); +} + +/* KphNotEqualSpin + * + * Spins until the first value is not equal to the second + * value. + */ +FORCEINLINE VOID KphSpinUntilNotEqual( + __inout PLONG Value, + __in LONG Value2 + ) +{ + while (InterlockedCompareExchange( + Value, + Value2, + Value2 + ) == Value2) + YieldProcessor(); +} + +/* Spin Locks */ + +/* KphAcquireBitSpinLock + * + * Uses the specified bit as a spinlock and acquires the + * lock in the given value. + */ +FORCEINLINE VOID KphAcquireBitSpinLock( + __inout PLONG Value, + __in LONG Bit + ) +{ + while (InterlockedBitTestAndSet(Value, Bit)) + YieldProcessor(); +} + +/* KphReleaseBitSpinLock + * + * Uses the specified bit as a spinlock and releases the + * lock in the given value. + */ +FORCEINLINE VOID KphReleaseBitSpinLock( + __inout PLONG Value, + __in LONG Bit + ) +{ + InterlockedBitTestAndReset(Value, Bit); +} + +/* Guarded Locks */ +/* Guarded locks are small spinlocks. Code within + * synchronized regions run at APC_LEVEL. They also contain + * a signal which can used to implement rundown routines. + */ + +#define KPH_GUARDED_LOCK_ACTIVE 0x80000000 +#define KPH_GUARDED_LOCK_ACTIVE_SHIFT 31 +#define KPH_GUARDED_LOCK_SIGNALED 0x40000000 +#define KPH_GUARDED_LOCK_SIGNALED_SHIFT 30 +#define KPH_GUARDED_LOCK_FLAGS 0xc0000000 + +typedef struct _KPH_GUARDED_LOCK +{ + LONG Value; +} KPH_GUARDED_LOCK, *PKPH_GUARDED_LOCK; + +#define KphAcquireGuardedLock KphfAcquireGuardedLock +VOID FASTCALL KphfAcquireGuardedLock( + __inout PKPH_GUARDED_LOCK Lock + ); + +#define KphReleaseGuardedLock KphfReleaseGuardedLock +VOID FASTCALL KphfReleaseGuardedLock( + __inout PKPH_GUARDED_LOCK Lock + ); + +/* KphInitializeGuardedLock + * + * Initializes a guarded lock. + * + * IRQL: Any + */ +FORCEINLINE VOID KphInitializeGuardedLock( + __out PKPH_GUARDED_LOCK Lock, + __in BOOLEAN Signaled + ) +{ + Lock->Value = 0; + + if (Signaled) + Lock->Value |= KPH_GUARDED_LOCK_SIGNALED; +} + +/* KphClearGuardedLock + * + * Clears the signal state of a guarded lock, assuming + * that the current thread has acquired it. + * + * IRQL: Any + */ +FORCEINLINE VOID KphClearGuardedLock( + __in PKPH_GUARDED_LOCK Lock + ) +{ + Lock->Value &= ~KPH_GUARDED_LOCK_SIGNALED; +} + +/* KphSignalGuardedLock + * + * Signals a guarded lock. + * + * IRQL: Any + */ +FORCEINLINE VOID KphSignalGuardedLock( + __in PKPH_GUARDED_LOCK Lock + ) +{ + Lock->Value |= KPH_GUARDED_LOCK_SIGNALED; +} + +/* KphSignaledGuardedLock + * + * Determines whether a guarded lock is signaled. + * + * IRQL: Any + */ +FORCEINLINE BOOLEAN KphSignaledGuardedLock( + __in PKPH_GUARDED_LOCK Lock + ) +{ + return !!(Lock->Value & KPH_GUARDED_LOCK_SIGNALED); +} + +/* KphAcquireAndClearGuardedLock + * + * Acquires a guarded lock, clear its signal, and raises the IRQL to APC_LEVEL. + * + * IRQL: <= APC_LEVEL + */ +FORCEINLINE VOID KphAcquireAndClearGuardedLock( + __inout PKPH_GUARDED_LOCK Lock + ) +{ + KphAcquireGuardedLock(Lock); + KphClearGuardedLock(Lock); +} + +/* KphAcquireAndSignalGuardedLock + * + * Acquires a guarded lock, signals it, and raises the IRQL to APC_LEVEL. + * + * IRQL: <= APC_LEVEL + */ +FORCEINLINE VOID KphAcquireAndSignalGuardedLock( + __inout PKPH_GUARDED_LOCK Lock + ) +{ + KphAcquireGuardedLock(Lock); + KphSignalGuardedLock(Lock); +} + +/* KphAcquireNonSignaledGuardedLock + * + * Acquires a guarded lock and raises the IRQL to APC_LEVEL, + * making sure the lock is not signaled. If it is, the + * lock is not acquired. + * + * Return value: whether the lock was acquired. + * IRQL: <= APC_LEVEL + */ +FORCEINLINE BOOLEAN KphAcquireNonSignaledGuardedLock( + __inout PKPH_GUARDED_LOCK Lock + ) +{ + KphAcquireGuardedLock(Lock); + + if (Lock->Value & KPH_GUARDED_LOCK_SIGNALED) + { + KphReleaseGuardedLock(Lock); + return FALSE; + } + + return TRUE; +} + +/* KphAcquireSignaledGuardedLock + * + * Acquires a guarded lock and raises the IRQL to APC_LEVEL, + * making sure the lock is signaled. If it is not, the + * lock is not acquired. + * + * Return value: whether the lock was acquired. + * IRQL: <= APC_LEVEL + */ +FORCEINLINE BOOLEAN KphAcquireSignaledGuardedLock( + __inout PKPH_GUARDED_LOCK Lock + ) +{ + KphAcquireGuardedLock(Lock); + + if (!(Lock->Value & KPH_GUARDED_LOCK_SIGNALED)) + { + KphReleaseGuardedLock(Lock); + return FALSE; + } + + return TRUE; +} + +/* KphReleaseAndClearGuardedLock + * + * Releases a guarded lock, clears its signal, and restores the old IRQL. + * + * IRQL: >= APC_LEVEL + */ +FORCEINLINE VOID KphReleaseAndClearGuardedLock( + __inout PKPH_GUARDED_LOCK Lock + ) +{ + KphClearGuardedLock(Lock); + KphReleaseGuardedLock(Lock); +} + +/* KphReleaseAndSignalGuardedLock + * + * Releases a guarded lock, signals it, and restores the old IRQL. + * + * IRQL: >= APC_LEVEL + */ +FORCEINLINE VOID KphReleaseAndSignalGuardedLock( + __inout PKPH_GUARDED_LOCK Lock + ) +{ + KphSignalGuardedLock(Lock); + KphReleaseGuardedLock(Lock); +} + +/* Processor Locks */ +/* Processor locks prevent code from executing on all other + * processors. Code within synchronized regions run at + * DISPATCH_LEVEL. + */ + +#define TAG_SYNC_DPC ('DShP') + +typedef struct _KPH_PROCESSOR_LOCK +{ + /* Synchronizes access to the processor lock. */ + KPH_GUARDED_LOCK Lock; + /* Storage allocated for DPCs. */ + PKDPC Dpcs; + /* The number of currently acquired processors. */ + LONG AcquiredProcessors; + /* The signal for acquired processors to be released. */ + LONG ReleaseSignal; + /* The old IRQL. */ + KIRQL OldIrql; + /* Whether the processor lock has been acquired. */ + BOOLEAN Acquired; +} KPH_PROCESSOR_LOCK, *PKPH_PROCESSOR_LOCK; + +BOOLEAN KphAcquireProcessorLock( + __inout PKPH_PROCESSOR_LOCK ProcessorLock + ); + +VOID KphInitializeProcessorLock( + __out PKPH_PROCESSOR_LOCK ProcessorLock + ); + +VOID KphReleaseProcessorLock( + __inout PKPH_PROCESSOR_LOCK ProcessorLock + ); + +#endif diff --git a/branches/ph-plugins/KProcessHacker/include/sysservice.h b/branches/ph-plugins/KProcessHacker/include/sysservice.h new file mode 100644 index 000000000..89e7b8dc7 --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/include/sysservice.h @@ -0,0 +1,278 @@ +/* + * Process Hacker Driver - + * system service logging + * + * Copyright (C) 2009 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 . + */ + +#ifndef _SYSSERVICE_H +#define _SYSSERVICE_H + +#include "kph.h" +#include "sysservicedata.h" + +/* Define opaque object types */ + +struct _KPHSS_CLIENT_ENTRY; +typedef struct _KPHSS_CLIENT_ENTRY *PKPHSS_CLIENT_ENTRY; +struct _KPHSS_RULESET_ENTRY; +typedef struct _KPHSS_RULESET_ENTRY *PKPHSS_RULESET_ENTRY; +struct _KPHSS_RULE_ENTRY; +typedef struct _KPHSS_RULE_ENTRY *PKPHSS_RULE_ENTRY; + +/* Information types */ + +typedef struct _KPHSS_CLIENT_INFORMATION +{ + HANDLE ProcessId; + PVOID BufferBase; + ULONG BufferSize; + + ULONG NumberOfBlocksWritten; + ULONG NumberOfBlocksDropped; +} KPHSS_CLIENT_INFORMATION, *PKPHSS_CLIENT_INFORMATION; + +/* Object types */ + +#ifndef _SYSSERVICE_PRIVATE +extern PKPH_OBJECT_TYPE KphSsClientEntryType; +extern PKPH_OBJECT_TYPE KphSsRuleSetEntryType; +extern PKPH_OBJECT_TYPE KphSsRuleEntryType; +#endif + +/* Ruleset types */ + +typedef enum _KPHSS_RULESET_ACTION +{ + LogRuleSetAction, + MaxRuleSetAction +} KPHSS_RULESET_ACTION; + +/* Rule types */ + +typedef enum _KPHSS_FILTER_TYPE +{ + IncludeFilterType, + ExcludeFilterType, + MaxFilterType +} KPHSS_FILTER_TYPE; + +typedef enum _KPHSS_RULE_TYPE +{ + ProcessIdRuleType = 0, + ThreadIdRuleType, + PreviousModeRuleType, + NumberRuleType, + MaxRuleType +} KPHSS_RULE_TYPE; + +/* Block types */ + +#define KPHSS_BLOCK_SUCCESS(Status) (NT_SUCCESS(Status) && (Status) != STATUS_TIMEOUT) + +typedef enum _KPHSS_BLOCK_TYPE +{ + ResetBlockType, + EventBlockType, + ArgumentBlockType, + ProcessBlockType, + ModuleBlockType +} KPHSS_BLOCK_TYPE; + +typedef struct _KPHSS_BLOCK_HEADER +{ + USHORT Size; /* a.k.a. NextEntryOffset */ + USHORT Type; +} KPHSS_BLOCK_HEADER, *PKPHSS_BLOCK_HEADER; + +typedef struct _KPHSS_RESET_BLOCK +{ + KPHSS_BLOCK_HEADER Header; +} KPHSS_RESET_BLOCK, *PKPHSS_RESET_BLOCK; + +#define TAG_EVENT_BLOCK ('BEhP') + +#define KPHSS_EVENT_PROBE_ARGUMENTS_FAILED 0x00000001 +#define KPHSS_EVENT_COPY_ARGUMENTS_FAILED 0x00000002 +#define KPHSS_EVENT_KERNEL_MODE 0x00000004 +#define KPHSS_EVENT_USER_MODE 0x00000008 + +typedef struct _KPHSS_EVENT_BLOCK +{ + KPHSS_BLOCK_HEADER Header; + USHORT Flags; + LARGE_INTEGER Time; + CLIENT_ID ClientId; + + /* The system service number. */ + ULONG Number; + /* The number of ULONG arguments to the system service. */ + USHORT NumberOfArguments; + USHORT ArgumentsOffset; /* ULONG[] */ + + /* The number of PVOIDs in the trace. */ + USHORT TraceCount; + USHORT TraceOffset; /* PVOID[] */ +} KPHSS_EVENT_BLOCK, *PKPHSS_EVENT_BLOCK; + +/* Argument Blocks + * + * These blocks provide additional information about + * arguments. + */ + +#define TAG_ARGUMENT_BLOCK ('BAhP') + +#define KPHSS_ARGUMENT_BLOCK_OVERHEAD \ + FIELD_OFFSET(KPHSS_ARGUMENT_BLOCK, Normal) +#define KPHSS_ARGUMENT_BLOCK_SIZE(InnerSize) \ + (KPHSS_ARGUMENT_BLOCK_OVERHEAD + (InnerSize)) + +typedef struct _KPHSS_ARGUMENT_BLOCK +{ + KPHSS_BLOCK_HEADER Header; + UCHAR Index; + UCHAR Type; /* KPHSS_ARGUMENT_TYPE */ + + union + { + ULONG Normal; + + LARGE_INTEGER Simple; + KPHSS_HANDLE Handle; + KPHSS_STRING String; + KPHSS_WSTRING WString; + KPHSS_ANSI_STRING AnsiString; + KPHSS_UNICODE_STRING UnicodeString; + KPHSS_OBJECT_ATTRIBUTES ObjectAttributes; + CLIENT_ID ClientId; + CONTEXT Context; + KPHSS_INITIAL_TEB InitialTeb; + GUID Guid; + }; +} KPHSS_ARGUMENT_BLOCK, *PKPHSS_ARGUMENT_BLOCK; + +/* Process Blocks + * + * These blocks notify the client of a new process. + */ + +#define TAG_PROCESS_BLOCK ('BPhP') + +typedef struct _KPHSS_PROCESS_BLOCK +{ + KPHSS_BLOCK_HEADER Header; + + HANDLE ProcessId; + USHORT NameOffset; /* KPHSS_WSTRING */ + USHORT ImageFileNameOffset; /* KPHSS_WSTRING */ +} KPHSS_PROCESS_BLOCK, *PKPHSS_PROCESS_BLOCK; + +/* Module Blocks + * + * These blocks provide information about modules + * loaded by a process. + */ + +#define TAG_MODULE_BLOCK ('BMhP') + +typedef struct _KPHSS_MODULE_BLOCK +{ + KPHSS_BLOCK_HEADER Header; + + HANDLE ProcessId; + PVOID ModuleBase; + ULONG ModuleSize; + USHORT FileNameOffset; /* KPHSS_WSTRING */ +} KPHSS_MODULE_BLOCK, *PKPHSS_MODULE_BLOCK; + +/* Functions */ + +NTSTATUS KphSsLogInit(); +NTSTATUS KphSsLogDeinit(); +NTSTATUS KphSsLogStart(); +NTSTATUS KphSsLogStop(); + +NTSTATUS KphSsCreateClientEntry( + __out PKPHSS_CLIENT_ENTRY *ClientEntry, + __in HANDLE ProcessHandle, + __in HANDLE ReadSemaphoreHandle, + __in HANDLE WriteSemaphoreHandle, + __in PVOID BufferBase, + __in ULONG BufferSize, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS KphSsEnableClientEntry( + __in PKPHSS_CLIENT_ENTRY ClientEntry, + __in BOOLEAN Enable + ); + +NTSTATUS KphSsQueryClientEntry( + __in PKPHSS_CLIENT_ENTRY ClientEntry, + __out_bcount_opt(ClientInformationLength) PKPHSS_CLIENT_INFORMATION ClientInformation, + __in ULONG ClientInformationLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode + ); + +NTSTATUS KphSsCreateRuleSetEntry( + __out PKPHSS_RULESET_ENTRY *RuleSetEntry, + __in PKPHSS_CLIENT_ENTRY ClientEntry, + __in KPHSS_FILTER_TYPE DefaultFilterType, + __in KPHSS_RULESET_ACTION Action + ); + +HANDLE KphSsGetHandleRule( + __in PKPHSS_RULE_ENTRY RuleEntry + ); + +NTSTATUS KphSsRemoveRule( + __in PKPHSS_RULESET_ENTRY RuleSetEntry, + __in HANDLE RuleEntryHandle + ); + +NTSTATUS KphSsAddProcessIdRule( + __out PKPHSS_RULE_ENTRY *RuleEntry, + __in PKPHSS_RULESET_ENTRY RuleSetEntry, + __in KPHSS_FILTER_TYPE FilterType, + __in HANDLE ProcessId + ); + +NTSTATUS KphSsAddThreadIdRule( + __out PKPHSS_RULE_ENTRY *RuleEntry, + __in PKPHSS_RULESET_ENTRY RuleSetEntry, + __in KPHSS_FILTER_TYPE FilterType, + __in HANDLE ThreadId + ); + +NTSTATUS KphSsAddPreviousModeRule( + __out PKPHSS_RULE_ENTRY *RuleEntry, + __in PKPHSS_RULESET_ENTRY RuleSetEntry, + __in KPHSS_FILTER_TYPE FilterType, + __in KPROCESSOR_MODE PreviousMode + ); + +NTSTATUS KphSsAddNumberRule( + __out PKPHSS_RULE_ENTRY *RuleEntry, + __in PKPHSS_RULESET_ENTRY RuleSetEntry, + __in KPHSS_FILTER_TYPE FilterType, + __in ULONG Number + ); + +#endif diff --git a/branches/ph-plugins/KProcessHacker/include/sysservicedata.h b/branches/ph-plugins/KProcessHacker/include/sysservicedata.h new file mode 100644 index 000000000..80f2e870b --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/include/sysservicedata.h @@ -0,0 +1,166 @@ +/* + * Process Hacker Driver - + * system service logging (data) + * + * Copyright (C) 2009 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 . + */ + +#ifndef _SYSSERVICEDATA_H +#define _SYSSERVICEDATA_H + +#include "kph.h" + +#define TAG_CALL_ENTRY ('cShP') + +typedef enum _KPHSS_ARGUMENT_TYPE +{ + /* Having argument info for out variables is very rare + * because usually the caller does not fill in anything + * in the variable. In some cases, however, the caller + * does specify a length (usually Length, or MaximumLength). + * + * Note that with the exception of a few types such as + * HANDLE, all types listed here are POINTER TYPES + * (although a handle is the size of a pointer). This + * is because non-pointer arguments are already recorded + * in the event block. + */ + + /* Anything passed by value */ + NormalArgument = 0, + + /* PBOOLEAN */ + Int8Argument, + /* P(U)SHORT */ + Int16Argument, + /* P(U)LONG */ + Int32Argument, + /* P(U)LARGE_INTEGER */ + Int64Argument, + /* HANDLE */ + /* Only object manager handles, no fake handles. */ + HandleArgument, + /* PSTR */ + StringArgument, + /* PWSTR */ + WStringArgument, + /* PANSI_STRING */ + AnsiStringArgument, + /* PUNICODE_STRING */ + UnicodeStringArgument, + /* POBJECT_ATTRIBUTES */ + ObjectAttributesArgument, + /* PCLIENT_ID */ + ClientIdArgument, + /* PCONTEXT */ + ContextArgument, + /* PINITIAL_TEB */ + InitialTebArgument, + /* PGUID */ + GuidArgument +} KPHSS_ARGUMENT_TYPE; + +typedef struct _KPHSS_HANDLE +{ + CLIENT_ID ClientId; + USHORT TypeNameOffset; /* KPHSS_WSTRING */ + USHORT NameOffset; /* KPHSS_WSTRING */ +} KPHSS_HANDLE, *PKPHSS_HANDLE; + +typedef struct _KPHSS_STRING +{ + USHORT Length; + CHAR Buffer[1]; +} KPHSS_STRING, *PKPHSS_STRING; + +typedef struct _KPHSS_WSTRING +{ + USHORT Length; + WCHAR Buffer[1]; +} KPHSS_WSTRING, *PKPHSS_WSTRING; + +typedef struct _KPHSS_ANSI_STRING +{ + USHORT Length; + USHORT MaximumLength; + PSTR Pointer; + CHAR Buffer[1]; +} KPHSS_ANSI_STRING, *PKPHSS_ANSI_STRING; + +typedef struct _KPHSS_UNICODE_STRING +{ + USHORT Length; + USHORT MaximumLength; + PWSTR Pointer; + WCHAR Buffer[1]; +} KPHSS_UNICODE_STRING, *PKPHSS_UNICODE_STRING; + +typedef struct _KPHSS_OBJECT_ATTRIBUTES +{ + union + { + OBJECT_ATTRIBUTES ObjectAttributes; + struct + { + ULONG Length; + HANDLE RootDirectory; + PUNICODE_STRING ObjectName; + ULONG Attributes; + PVOID SecurityDescriptor; + PVOID SecurityQualityOfService; + }; + }; + + USHORT RootDirectoryOffset; /* KPHSS_HANDLE */ + USHORT ObjectNameOffset; /* KPHSS_UNICODE_STRING */ +} KPHSS_OBJECT_ATTRIBUTES, *PKPHSS_OBJECT_ATTRIBUTES; + +typedef struct _KPHSS_INITIAL_TEB +{ + struct + { + PVOID OldStackBase; + PVOID OldStackLimit; + } OldInitialTeb; + PVOID StackBase; + PVOID StackLimit; + PVOID StackAllocationBase; +} KPHSS_INITIAL_TEB, *PKPHSS_INITIAL_TEB; + +#ifndef _SYSSERVICEDATA_PRIVATE +extern RTL_GENERIC_TABLE KphSsCallTable; +#endif + +#define KPHSS_MAXIMUM_ARGUMENT_BLOCKS 20 + +typedef struct _KPHSS_CALL_ENTRY +{ + PULONG Number; + PSTR Name; + ULONG NumberOfArguments; + KPHSS_ARGUMENT_TYPE Arguments[KPHSS_MAXIMUM_ARGUMENT_BLOCKS]; +} KPHSS_CALL_ENTRY, *PKPHSS_CALL_ENTRY; + +VOID KphSsDataInit(); +VOID KphSsDataDeinit(); + +PKPHSS_CALL_ENTRY KphSsLookupCallEntry( + __in ULONG Number + ); + +#endif \ No newline at end of file diff --git a/branches/ph-plugins/KProcessHacker/include/sysservicep.h b/branches/ph-plugins/KProcessHacker/include/sysservicep.h new file mode 100644 index 000000000..50f297c33 --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/include/sysservicep.h @@ -0,0 +1,414 @@ +/* + * Process Hacker Driver - + * system service logging + * + * Copyright (C) 2009 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 . + */ + +#ifndef _SYSSERVICEP_H +#define _SYSSERVICEP_H + +#define _SYSSERVICE_PRIVATE +#include "sysservice.h" +#include "ex.h" +#include "ref.h" + +/* PKPHPSS_KIFASTCALLENTRYPROC + * + * Represents a function called by KphpSsNewKiFastCallEntry. + */ +typedef VOID (NTAPI *PKPHPSS_KIFASTCALLENTRYPROC)( + __in ULONG Number, + __in ULONG *Arguments, + __in ULONG NumberOfArguments, + __in PKSERVICE_TABLE_DESCRIPTOR ServiceTable, + __in PKTHREAD Thread + ); + +/* Client entries + * + * Client entries describe a process and a circular buffer which + * receives logging events. + */ + +typedef struct _KPHSS_CLIENT_ENTRY +{ + PEPROCESS Process; + BOOLEAN Enabled; + + /* Buffer */ + PKSEMAPHORE ReadSemaphore; + PKSEMAPHORE WriteSemaphore; + FAST_MUTEX BufferMutex; + PVOID BufferBase; + ULONG BufferSize; + ULONG BufferCursor; + + /* Statistics */ + ULONG NumberOfBlocksWritten; /* excludes reset blocks */ + ULONG NumberOfBlocksDropped; +} KPHSS_CLIENT_ENTRY, *PKPHSS_CLIENT_ENTRY; + +/* Rulesets + * + * Rulesets contain a list of rules and an action to take if a + * system service matches the set of rules. + */ + +#define KPHSS_RULESET_ENTRY(ListEntry) \ + CONTAINING_RECORD((ListEntry), KPHSS_RULESET_ENTRY, RuleSetListEntry) +#define KPHSS_RULESET_ENTRY_LIMIT 10 +#define KPHSS_RULE_HANDLE_INCREMENT 4 + +typedef struct _KPHSS_RULESET_ENTRY +{ + LIST_ENTRY RuleSetListEntry; + /* The client is referenced. */ + PKPHSS_CLIENT_ENTRY Client; + + KPHSS_RULESET_ACTION Action; + KPHSS_FILTER_TYPE DefaultFilterType; + + ULONG NextRuleHandle; + EX_PUSH_LOCK RuleListPushLock; + /* A list of rules. Each rule is referenced when stored. */ + LIST_ENTRY RuleListHead; +} KPHSS_RULESET_ENTRY, *PKPHSS_RULESET_ENTRY; + +/* Rules */ + +#define KPHSS_RULE_ENTRY(ListEntry) \ + CONTAINING_RECORD((ListEntry), KPHSS_RULE_ENTRY, RuleListEntry) + +typedef struct _KPHSS_RULE_ENTRY +{ + BOOLEAN Initialized; + HANDLE Handle; + LIST_ENTRY RuleListEntry; + + KPHSS_FILTER_TYPE FilterType; + KPHSS_RULE_TYPE RuleType; + + union + { + struct + { + HANDLE ProcessId; + } ProcessIdRule; + struct + { + HANDLE ThreadId; + } ThreadIdRule; + struct + { + KPROCESSOR_MODE PreviousMode; + } PreviousModeRule; + struct + { + ULONG Number; + } NumberRule; + }; +} KPHSS_RULE_ENTRY, *PKPHSS_RULE_ENTRY; + +typedef enum _KPHSS_SEQUENCE_MODE +{ + NoSequence, + StartSequence, + InSequence, + EndSequence +} KPHSS_SEQUENCE_MODE; + +#define TAG_CAPTURE_TEMP_BUFFER ('tChP') +#define CAPTURE_HANDLE_BUFFER_SIZE 0x400 +#define CAPTURE_UNICODE_STRING_MAX_SIZE 0x400 + +/* KphpSsMatchRuleSetEntry + * + * Determines if a ruleset is relevant to an event. + * + * Note: This function is inlined for performance reasons. + */ +FORCEINLINE BOOLEAN KphpSsMatchRuleSetEntry( + __in PKPHSS_RULESET_ENTRY RuleSetEntry, + __in ULONG Number, + __in ULONG *Arguments, + __in ULONG NumberOfArguments, + __in PKSERVICE_TABLE_DESCRIPTOR ServiceTable, + __in PKTHREAD Thread, + __in KPROCESSOR_MODE PreviousMode + ) +{ + PLIST_ENTRY currentListEntry; + ULONG i; + BOOLEAN ruleTypeUsedArray[MaxRuleType]; + BOOLEAN ruleTypeIncludeArray[MaxRuleType]; + BOOLEAN ruleTypeExcludeArray[MaxRuleType]; + BOOLEAN ruleTypeFailedArray[MaxRuleType]; + BOOLEAN isRuleSetMatch; + + /* Due to the lack of proper boolean expression support, + * we are going to have these rules: + * + * * Each rule type has four arrays. The standard + * filtering rules apply to each rule type, + * except that on an include we increment the value + * in the include array and on an exclude we + * increment the value in the exclude array. On a + * failed include we increment the value in the + * failed array. + * * When we're done matching the rules, we'll look + * at the default filter type. If it's Include, + * we assume the ruleset matches. If it's Exclude, + * we assume the ruleset fails. + * * We will go through each rule type and look at + * the two arrays. See the code for further + * information. + */ + + /* Initialize the arrays. */ + for (i = 0; i < MaxRuleType; i++) + { + ruleTypeUsedArray[i] = FALSE; + ruleTypeIncludeArray[i] = FALSE; + ruleTypeExcludeArray[i] = FALSE; + ruleTypeFailedArray[i] = FALSE; + } + + KeEnterCriticalRegion(); + ExAcquirePushLockShared(&RuleSetEntry->RuleListPushLock); + + currentListEntry = RuleSetEntry->RuleListHead.Flink; + + while (currentListEntry != &RuleSetEntry->RuleListHead) + { + PKPHSS_RULE_ENTRY ruleEntry = KPHSS_RULE_ENTRY(currentListEntry); + BOOLEAN isRuleMatch = FALSE; + + /* Check if the rule is initialized, and if + * the rule type has already been failed - + * Exclude filter types take precedence. + */ + if ( + !ruleEntry->Initialized || + ruleTypeExcludeArray[ruleEntry->RuleType] + ) + { + currentListEntry = currentListEntry->Flink; + continue; + } + + /* Attempt to match the rule. All rule types are + * considered in this one function. + */ + switch (ruleEntry->RuleType) + { + case ProcessIdRuleType: + if (PsGetProcessId(IoThreadToProcess(Thread)) == + ruleEntry->ProcessIdRule.ProcessId) + isRuleMatch = TRUE; + break; + case ThreadIdRuleType: + if (PsGetThreadId(Thread) == ruleEntry->ThreadIdRule.ThreadId) + isRuleMatch = TRUE; + break; + case PreviousModeRuleType: + if (PreviousMode == ruleEntry->PreviousModeRule.PreviousMode) + isRuleMatch = TRUE; + break; + case NumberRuleType: + if (Number == ruleEntry->NumberRule.Number) + isRuleMatch = TRUE; + break; + } + + /* Now that we have attempted to match the rule, we + * must look at the rule filter type to determine + * what to do. + */ + if (isRuleMatch) + { + if (ruleEntry->FilterType == IncludeFilterType) + { + ruleTypeIncludeArray[ruleEntry->RuleType] = TRUE; + } + else if (ruleEntry->FilterType == ExcludeFilterType) + { + ruleTypeExcludeArray[ruleEntry->RuleType] = TRUE; + } + } + else + { + if (ruleEntry->FilterType == IncludeFilterType) + { + ruleTypeFailedArray[ruleEntry->RuleType] = TRUE; + } + } + + /* Declare that we have used the rule type. */ + ruleTypeUsedArray[ruleEntry->RuleType] = TRUE; + + currentListEntry = currentListEntry->Flink; + } + + ExReleasePushLock(&RuleSetEntry->RuleListPushLock); + KeLeaveCriticalRegion(); + + /* Look at the default filter type. If it's Include, + * we assume the ruleset matches. Otherwise, we + * assume it fails. + */ + if (RuleSetEntry->DefaultFilterType == IncludeFilterType) + { + isRuleSetMatch = TRUE; + } + else if (RuleSetEntry->DefaultFilterType == ExcludeFilterType) + { + isRuleSetMatch = FALSE; + } + + /* Go through the rule type match/failed arrays. */ + + for (i = 0; i < MaxRuleType; i++) + { + /* Make sure this rule type has been used. */ + if (!ruleTypeUsedArray[i]) + continue; + + /* The ordering of these if statements are + * extremely important. The order of precedence + * is: exclude, include, failed include. Failed include + * doesn't apply if we're using the Include default + * filter type, though. + */ + if (ruleTypeExcludeArray[i]) + { + isRuleSetMatch = FALSE; + break; + } + else if (ruleTypeIncludeArray[i]) + { + isRuleSetMatch = TRUE; + } + else if ( + ruleTypeFailedArray[i] && + RuleSetEntry->DefaultFilterType != IncludeFilterType + ) + { + isRuleSetMatch = FALSE; + break; + } + } + + return isRuleSetMatch; +} + +/* Functions */ + +VOID NTAPI KphpSsClientEntryDeleteProcedure( + __in PVOID Object, + __in ULONG Flags + ); + +VOID NTAPI KphpSsRuleSetEntryDeleteProcedure( + __in PVOID Object, + __in ULONG Flags + ); + +NTSTATUS KphpSsAddRule( + __out PKPHSS_RULE_ENTRY *RuleEntry, + __in PKPHSS_RULESET_ENTRY RuleSetEntry, + __in KPHSS_FILTER_TYPE FilterType, + __in KPHSS_RULE_TYPE RuleType + ); + +NTSTATUS KphpSsCreateEventBlock( + __out PKPHSS_EVENT_BLOCK *EventBlock, + __in PKTHREAD Thread, + __in ULONG Number, + __in ULONG *Arguments, + __in ULONG NumberOfArguments + ); + +VOID KphpSsFreeEventBlock( + __in PKPHSS_EVENT_BLOCK EventBlock + ); + +NTSTATUS KphpSsCaptureSimpleArgument( + __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock, + __in PVOID Argument, + __in KPHSS_ARGUMENT_TYPE Type, + __in KPROCESSOR_MODE PreviousMode + ); + +NTSTATUS KphpSsCaptureHandleArgument( + __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock, + __in HANDLE Argument, + __in KPROCESSOR_MODE PreviousMode + ); + +NTSTATUS KphpSsCaptureUnicodeStringArgument( + __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock, + __in PUNICODE_STRING Argument, + __in KPROCESSOR_MODE PreviousMode + ); + +NTSTATUS KphpSsCaptureObjectAttributesArgument( + __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock, + __in POBJECT_ATTRIBUTES Argument, + __in KPROCESSOR_MODE PreviousMode + ); + +NTSTATUS KphpSsCaptureClientIdArgument( + __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock, + __in PCLIENT_ID Argument, + __in KPROCESSOR_MODE PreviousMode + ); + +NTSTATUS KphpSsCreateArgumentBlock( + __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock, + __in ULONG Number, + __in ULONG Argument, + __in ULONG Index + ); + +PKPHSS_ARGUMENT_BLOCK KphpSsAllocateArgumentBlock( + __in ULONG InnerSize, + __in KPHSS_ARGUMENT_TYPE Type + ); + +VOID KphpSsFreeArgumentBlock( + __in PKPHSS_ARGUMENT_BLOCK ArgumentBlock + ); + +NTSTATUS KphpSsWriteBlock( + __in PKPHSS_CLIENT_ENTRY ClientEntry, + __in_opt PKPHSS_BLOCK_HEADER Block, + __in KPHSS_SEQUENCE_MODE SequenceMode + ); + +VOID NTAPI KphpSsLogSystemServiceCall( + __in ULONG Number, + __in ULONG *Arguments, + __in ULONG NumberOfArguments, + __in PKSERVICE_TABLE_DESCRIPTOR ServiceTable, + __in PKTHREAD Thread + ); + +VOID NTAPI KphpSsNewKiFastCallEntry(); + +#endif diff --git a/branches/ph-plugins/KProcessHacker/include/test.h b/branches/ph-plugins/KProcessHacker/include/test.h new file mode 100644 index 000000000..49dc96095 --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/include/test.h @@ -0,0 +1,30 @@ +/* + * Process Hacker Driver - + * testing code + * + * Copyright (C) 2009 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 . + */ + +#ifndef _TEST_H +#define _TEST_H + +#include "kph.h" + +VOID KphTestPushLock(); + +#endif diff --git a/branches/ph-plugins/KProcessHacker/include/trace.h b/branches/ph-plugins/KProcessHacker/include/trace.h new file mode 100644 index 000000000..6b707ede5 --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/include/trace.h @@ -0,0 +1,188 @@ +/* + * Process Hacker Driver - + * stack tracing + * + * Copyright (C) 2009 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 . + */ + +#ifndef _TRACE_H +#define _TRACE_H + +#include "types.h" + +/* Stack Tracing */ + +/* Sensible limit that may or may not correspond to the actual Windows value. */ +#define MAX_STACK_DEPTH 64 + +#define RTL_WALK_USER_MODE_STACK 0x00000001 +#define RTL_WALK_VALID_FLAGS 0x00000001 + +/* RtlWalkFrameChain + * + * Walks an EBP chain and fills out an array of addresses. + * + * Return value: the number of frames found. + */ +NTSYSAPI ULONG NTAPI RtlWalkFrameChain( + __out PVOID *Callers, + __in ULONG Count, + __in ULONG Flags + ); + +/* Trace Database */ + +#define RTL_TRACE_IN_USER_MODE 0x00000001 +#define RTL_TRACE_IN_KERNEL_MODE 0x00000002 +#define RTL_TRACE_USE_NONPAGED_POOL 0x00000004 +#define RTL_TRACE_USE_PAGED_POOL 0x00000008 + +typedef struct _RTL_TRACE_BLOCK +{ + ULONG Magic; + ULONG Count; /* Reference count */ + ULONG Size; /* Size, in PVOIDs, of the trace */ + + SIZE_T UserCount; + SIZE_T UserSize; + PVOID UserContext; + + struct _RTL_TRACE_BLOCK *Next; + PVOID *Trace; +} RTL_TRACE_BLOCK, *PRTL_TRACE_BLOCK; + +typedef struct _RTL_TRACE_DATABASE *PRTL_TRACE_DATABASE; + +/* Enumeration context. */ +typedef struct _RTL_TRACE_ENUMERATE +{ + PRTL_TRACE_DATABASE Database; + ULONG Index; + PRTL_TRACE_BLOCK Block; +} RTL_TRACE_ENUMERATE, *PRTL_TRACE_ENUMERATE; + +typedef ULONG (*RTL_TRACE_HASH_FUNCTION)( + ULONG Count, + PVOID *Trace + ); + +PRTL_TRACE_DATABASE RtlTraceDatabaseCreate( + __in ULONG Buckets, + __in_opt SIZE_T MaximumSize, + __in ULONG Flags, /* optional in user-mode */ + __in ULONG Tag, /* optional in user-mode */ + __in_opt RTL_TRACE_HASH_FUNCTION HashFunction + ); + +BOOLEAN RtlTraceDatabaseDestroy( + __in PRTL_TRACE_DATABASE Database + ); + +BOOLEAN RtlTraceDatabaseValidate( + __in PRTL_TRACE_DATABASE Database + ); + +BOOLEAN RtlTraceDatabaseAdd( + __in PRTL_TRACE_DATABASE Database, + __in ULONG Count, + __in PVOID *Trace, + __out_opt PRTL_TRACE_BLOCK *TraceBlock + ); + +/* RtlTraceDatabaseEnumerate + * + * Enumerates the trace blocks in the specified trace database. + * + * Database: The trace database to process. + * Enumerate: A context structure for the enumeration. Zero the + * structure if you are using it for the first time. + * TraceBlock: The trace block that was found by the function. + * + * Return value: TRUE if a trace block was found, FALSE if there + * are no more trace blocks. + */ +BOOLEAN RtlTraceDatabaseEnumerate( + __in PRTL_TRACE_DATABASE Database, + __inout PRTL_TRACE_ENUMERATE Enumerate, + __out PRTL_TRACE_BLOCK *TraceBlock + ); + +BOOLEAN RtlTraceDatabaseFind( + __in PRTL_TRACE_DATABASE Database, + __in ULONG Count, + __in PVOID *Trace, + __out_opt PRTL_TRACE_BLOCK *TraceBlock + ); + +/* Note: locking/unlocking is only needed when trace blocks are modified. + * It is not needed for adding/enumerating/finding. */ +VOID RtlTraceDatabaseLock( + __in PRTL_TRACE_DATABASE Database + ); + +VOID RtlTraceDatabaseUnlock( + __in PRTL_TRACE_DATABASE Database + ); + +/* KPH trace interface */ + +typedef enum _KPH_CAPTURE_AND_ADD_STACK_TYPE +{ + KphCaptureAndAddKModeStack, + KphCaptureAndAddUModeStack, + KphCaptureAndAddBothStacks, + KphCaptureAndAddMaximum +} KPH_CAPTURE_AND_ADD_STACK_TYPE, *PKPH_CAPTURE_AND_ADD_STACK_TYPE; + +typedef struct _KPH_TRACE_DATABASE +{ + PRTL_TRACE_DATABASE Database; +} KPH_TRACE_DATABASE, *PKPH_TRACE_DATABASE; + +typedef struct _KPH_TRACEDB_INFORMATION +{ + ULONG NextEntryOffset; + ULONG Count; + ULONG TraceSize; + PVOID Trace[1]; +} KPH_TRACEDB_INFORMATION, *PKPH_TRACEDB_INFORMATION; + +NTSTATUS KphTraceDatabaseInitialization(); + +BOOLEAN KphCaptureAndAddStack( + __in PKPH_TRACE_DATABASE Database, + __in KPH_CAPTURE_AND_ADD_STACK_TYPE Type, + __out_opt PRTL_TRACE_BLOCK *TraceBlock + ); + +ULONG KphCaptureStackBackTrace( + __in ULONG FramesToSkip, + __in ULONG FramesToCapture, + __in_opt ULONG Flags, + __out_ecount(FramesToCapture) PVOID *BackTrace, + __out_opt PULONG BackTraceHash + ); + +NTSTATUS KphCreateTraceDatabase( + __out PKPH_TRACE_DATABASE *Database, + __in_opt SIZE_T MaximumSize, + __in ULONG Flags, + __in ULONG Tag + ); + +#endif diff --git a/branches/ph-plugins/KProcessHacker/include/types.h b/branches/ph-plugins/KProcessHacker/include/types.h new file mode 100644 index 000000000..e1ca291c1 --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/include/types.h @@ -0,0 +1,7 @@ +#ifndef _TYPES_H +#define _TYPES_H + +#include +#include "version.h" + +#endif diff --git a/branches/ph-plugins/KProcessHacker/include/util.h b/branches/ph-plugins/KProcessHacker/include/util.h new file mode 100644 index 000000000..b62b0d22e --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/include/util.h @@ -0,0 +1,133 @@ +/* + * Process Hacker Driver - + * utility functions + * + * Copyright (C) 2009 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 . + */ + +#ifndef _UTIL_H +#define _UTIL_H + +#include "kph.h" + +/* Streams + * + * Streams are small buffer management structures. They + * automatically raise an exception if the buffer is overrun. + */ + +typedef struct _KPH_STREAM +{ + PVOID Buffer; + ULONG Length; + ULONG Position; +} KPH_STREAM, *PKPH_STREAM; + +typedef enum _KPH_STREAM_ORIGIN +{ + StartOrigin, + CurrentOrigin, + EndOrigin +} KPH_STREAM_ORIGIN; + +VOID KphInitializeStream( + __out PKPH_STREAM Stream, + __in PVOID Buffer, + __in ULONG Length + ); + +ULONG KphWriteDataStream( + __inout PKPH_STREAM Stream, + __in PVOID Data, + __in ULONG Length + ); + +/* KphCheckStreamPosition + * + * Checks a stream position and raises an exception if + * appropriate. + */ +FORCEINLINE VOID KphCheckStreamPosition( + __in PKPH_STREAM Stream, + __in ULONG Position + ) +{ + if (Position > Stream->Length) + ExRaiseStatus(STATUS_BUFFER_TOO_SMALL); +} + +/* KphPositionStream + * + * Gets the current position of the specified stream. + */ +FORCEINLINE ULONG KphPositionStream( + __in PKPH_STREAM Stream + ) +{ + return Stream->Position; +} + +/* KphWriteInt8Stream + * + * Writes a 1-byte value to a stream. + */ +FORCEINLINE VOID KphWriteInt8Stream( + __inout PKPH_STREAM Stream, + __in BOOLEAN Value + ) +{ + KphWriteDataStream(Stream, &Value, sizeof(BOOLEAN)); +} + +/* KphWriteInt16Stream + * + * Writes a 2-byte value to a stream. + */ +FORCEINLINE VOID KphWriteInt16Stream( + __inout PKPH_STREAM Stream, + __in SHORT Value + ) +{ + KphWriteDataStream(Stream, &Value, sizeof(SHORT)); +} + +/* KphWriteInt32Stream + * + * Writes a 4-byte value to a stream. + */ +FORCEINLINE VOID KphWriteInt32Stream( + __inout PKPH_STREAM Stream, + __in LONG Value + ) +{ + KphWriteDataStream(Stream, &Value, sizeof(LONG)); +} + +/* KphWriteInt64Stream + * + * Writes a 8-byte value to a stream. + */ +FORCEINLINE VOID KphWriteInt64Stream( + __inout PKPH_STREAM Stream, + __in PLARGE_INTEGER Value + ) +{ + KphWriteDataStream(Stream, Value, sizeof(LARGE_INTEGER)); +} + +#endif diff --git a/branches/ph-plugins/KProcessHacker/include/version.h b/branches/ph-plugins/KProcessHacker/include/version.h new file mode 100644 index 000000000..00d6ba5ab --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/include/version.h @@ -0,0 +1,241 @@ +/* + * Process Hacker Driver - + * Windows version-specific data + * + * Copyright (C) 2009 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 . + */ + +#ifndef _VERSION_H +#define _VERSION_H + +#include "kph.h" + +#define WINDOWS_XP 51 +#define WINDOWS_SERVER_2003 52 +#define WINDOWS_VISTA 60 +#define WINDOWS_7 61 + +#define KVOFF(object, offset) ((PCHAR)(object) + offset) +#define SCAN_LENGTH 0x100000 +#define INIT_SCAN(scan, bytes, length, address, scanLength, displacement) \ + ( \ + ((scan).Initialized = TRUE), \ + ((scan).Bytes = (bytes)), \ + ((scan).Length = (length)), \ + ((scan).StartAddress = (address)), \ + ((scan).ScanLength = (scanLength)), \ + ((scan).Displacement = (displacement)), \ + bytes \ + ) + +typedef struct _KV_SCANPROC +{ + BOOLEAN Initialized; + PUCHAR Bytes; + ULONG Length; + ULONG_PTR StartAddress; + ULONG ScanLength; + LONG Displacement; +} KV_SCANPROC, *PKV_SCANPROC; + +NTSTATUS KvInit(); + +PVOID KvScanProc( + PKV_SCANPROC ScanProc + ); + +PVOID KvVerifyPrologue( + PVOID Address + ); + +#ifdef EXT +#undef EXT +#endif + +#ifdef _VERSION_PRIVATE +#define EXT +#define SCANNULL = { FALSE, NULL, 0, 0, 0, 0 } +#else +#define EXT extern +#define SCANNULL +#endif + +EXT ULONG WindowsVersion; +EXT RTL_OSVERSIONINFOEXW RtlWindowsVersion; +EXT ACCESS_MASK ProcessAllAccess; +EXT ACCESS_MASK ThreadAllAccess; + +/* Offsets */ +/* Structures + * Et: ETHREAD + * Ep: EPROCESS + * Ot: OBJECT_TYPE + * Oti: OBJECT_TYPE_INITIALIZER, offset measured from an OBJECT_TYPE + */ +EXT ULONG OffEtClientId; +EXT ULONG OffEtSpareByteForSs; +EXT ULONG OffEtStartAddress; +EXT ULONG OffEtWin32StartAddress; +EXT ULONG OffEpJob; +EXT ULONG OffEpObjectTable; +EXT ULONG OffEpProtectedProcessOff; +EXT ULONG OffEpProtectedProcessBit; +EXT ULONG OffEpRundownProtect; +EXT ULONG OffOhBody; +EXT ULONG OffOtName; +EXT ULONG OffOtiGenericMapping; +EXT ULONG OffOtiOpenProcedure; + +/* Functions + */ +EXT KV_SCANPROC KiFastCallEntryScan SCANNULL; +EXT KV_SCANPROC PsExitSpecialApcScan SCANNULL; +EXT KV_SCANPROC PsTerminateProcessScan SCANNULL; +EXT KV_SCANPROC PspTerminateThreadByPointerScan SCANNULL; + +/* System Call Numbers + */ +EXT ULONG SsNtAddAtom; +EXT ULONG SsNtAlertResumeThread; +EXT ULONG SsNtAlertThread; +EXT ULONG SsNtAllocateLocallyUniqueId; +EXT ULONG SsNtAllocateUserPhysicalPages; +EXT ULONG SsNtAllocateUuids; +EXT ULONG SsNtAllocateVirtualMemory; +EXT ULONG SsNtApphelpCacheControl; +EXT ULONG SsNtAreMappedFilesTheSame; +EXT ULONG SsNtAssignProcessToJobObject; +EXT ULONG SsNtCallbackReturn; +EXT ULONG SsNtCancelDeviceWakeupRequest; +EXT ULONG SsNtCancelIoFile; +EXT ULONG SsNtCancelTimer; +EXT ULONG SsNtClearEvent; +EXT ULONG SsNtClose; +EXT ULONG SsNtContinue; +EXT ULONG SsNtCreateDebugObject; +EXT ULONG SsNtCreateDirectoryObject; +EXT ULONG SsNtCreateEvent; +EXT ULONG SsNtCreateEventPair; +EXT ULONG SsNtCreateFile; +EXT ULONG SsNtCreateIoCompletion; +EXT ULONG SsNtCreateJobObject; +EXT ULONG SsNtCreateJobSet; +EXT ULONG SsNtCreateKey; +EXT ULONG SsNtCreateKeyedEvent; +EXT ULONG SsNtCreateMailslotFile; +EXT ULONG SsNtCreateMutant; +EXT ULONG SsNtCreateNamedPipeFile; +EXT ULONG SsNtCreatePagingFile; +EXT ULONG SsNtCreatePort; +EXT ULONG SsNtCreatePrivateNamespace; +EXT ULONG SsNtCreateProcess; +EXT ULONG SsNtCreateProcessEx; +EXT ULONG SsNtCreateProfile; +EXT ULONG SsNtCreateSection; +EXT ULONG SsNtCreateSemaphore; +EXT ULONG SsNtCreateSymbolicLinkObject; +EXT ULONG SsNtCreateThread; +EXT ULONG SsNtCreateTimer; +EXT ULONG SsNtCreateToken; +EXT ULONG SsNtCreateUserProcess; +EXT ULONG SsNtCreateWaitablePort; +EXT ULONG SsNtDebugActiveProcess; +EXT ULONG SsNtDebugContinue; +EXT ULONG SsNtDelayExecution; +EXT ULONG SsNtDeleteAtom; +EXT ULONG SsNtDeleteBootEntry; +EXT ULONG SsNtDeleteDriverEntry; +EXT ULONG SsNtDeleteFile; +EXT ULONG SsNtDeleteKey; +EXT ULONG SsNtDeleteObjectAuditAlarm; +EXT ULONG SsNtDeletePrivateNamespace; +EXT ULONG SsNtDeleteValueKey; +EXT ULONG SsNtDeviceIoControlFile; +EXT ULONG SsNtDisplayString; +EXT ULONG SsNtDuplicateObject; +EXT ULONG SsNtDuplicateToken; +EXT ULONG SsNtEnumerateBootEntries; +EXT ULONG SsNtEnumerateDriverEntries; +EXT ULONG SsNtEnumerateKey; +EXT ULONG SsNtEnumerateSystemEnvironmentValuesEx; +EXT ULONG SsNtEnumerateValueKey; +EXT ULONG SsNtExtendSection; +EXT ULONG SsNtFilterToken; +EXT ULONG SsNtFindAtom; +EXT ULONG SsNtFlushBuffersFile; +EXT ULONG SsNtFlushInstructionCache; +EXT ULONG SsNtFlushKey; +EXT ULONG SsNtFlushProcessWriteBuffers; +EXT ULONG SsNtFlushVirtualMemory; +EXT ULONG SsNtFlushWriteBuffer; +EXT ULONG SsNtFreeUserPhysicalPages; +EXT ULONG SsNtFreeVirtualMemory; +EXT ULONG SsNtFsControlFile; +EXT ULONG SsNtGetContextThread; +EXT ULONG SsNtGetCurrentProcessorNumber; +EXT ULONG SsNtGetDevicePowerState; +EXT ULONG SsNtGetNextProcess; +EXT ULONG SsNtGetNextThread; +EXT ULONG SsNtGetPlugPlayEvent; +EXT ULONG SsNtGetWriteWatch; +EXT ULONG SsNtImpersonateAnonymousToken; +EXT ULONG SsNtImpersonateClientOfPort; +EXT ULONG SsNtImpersonateThread; +EXT ULONG SsNtInitiatePowerAction; +EXT ULONG SsNtIsProcessInJob; +EXT ULONG SsNtIsSystemResumeAutomatic; +EXT ULONG SsNtListenPort; +EXT ULONG SsNtLoadDriver; +EXT ULONG SsNtLoadKey; +EXT ULONG SsNtLoadKey2; +EXT ULONG SsNtLockFile; +EXT ULONG SsNtLockVirtualMemory; +EXT ULONG SsNtMakePermanentObject; +EXT ULONG SsNtMakeTemporaryObject; +EXT ULONG SsNtMapUserPhysicalPages; +EXT ULONG SsNtMapUserPhysicalPagesScatter; +EXT ULONG SsNtMapViewOfSection; +EXT ULONG SsNtModifyBootEntry; +EXT ULONG SsNtModifyDriverEntry; +EXT ULONG SsNtNotifyChangeDirectoryFile; +EXT ULONG SsNtNotifyChangeKey; +EXT ULONG SsNtNotifyChangeMultipleKeys; +EXT ULONG SsNtOpenDirectoryObject; +EXT ULONG SsNtOpenEvent; +EXT ULONG SsNtOpenEventPair; +EXT ULONG SsNtOpenFile; +EXT ULONG SsNtOpenIoCompletion; +EXT ULONG SsNtOpenJobObject; +EXT ULONG SsNtOpenKey; +EXT ULONG SsNtOpenKeyedEvent; +EXT ULONG SsNtOpenMutant; +EXT ULONG SsNtOpenObjectAuditAlarm; +EXT ULONG SsNtOpenProcess; +EXT ULONG SsNtOpenProcessToken; +EXT ULONG SsNtOpenProcessTokenEx; +EXT ULONG SsNtOpenSection; +EXT ULONG SsNtOpenSemaphore; +EXT ULONG SsNtOpenSymbolicLinkObject; +EXT ULONG SsNtOpenThread; +EXT ULONG SsNtOpenThreadToken; +EXT ULONG SsNtOpenThreadTokenEx; +EXT ULONG SsNtOpenTimer; +EXT ULONG SsNtReadFile; +EXT ULONG SsNtWriteFile; + +#endif diff --git a/branches/ph-plugins/KProcessHacker/include/zw.h b/branches/ph-plugins/KProcessHacker/include/zw.h new file mode 100644 index 000000000..e6ab70f4e --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/include/zw.h @@ -0,0 +1,45 @@ +/* + * Process Hacker Driver - + * system calls + * + * Copyright (C) 2009 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 . + */ + +#ifndef _ZW_H +#define _ZW_H + +#include "types.h" + +NTSTATUS NTAPI ZwOpenProcessToken( + HANDLE ProcessHandle, + ACCESS_MASK DesiredAccess, + PHANDLE TokenHandle + ); + +NTSTATUS NTAPI ZwSetInformationProcess( + HANDLE ProcessHandle, + PROCESSINFOCLASS ProcessInformationClass, + PVOID ProcessInformation, + ULONG ProcessInformationLength + ); + +typedef NTSTATUS (NTAPI *_NtClose)( + HANDLE Handle + ); + +#endif diff --git a/branches/ph-plugins/KProcessHacker/io.c b/branches/ph-plugins/KProcessHacker/io.c new file mode 100644 index 000000000..ddd8a779d --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/io.c @@ -0,0 +1,284 @@ +/* + * Process Hacker Driver - + * I/O manager + * + * Copyright (C) 2009 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/io.h" + +VOID KphpCopyInfoUnicodeString( + __out PVOID Information, + __in PUNICODE_STRING UnicodeString + ); + +/* KphOpenDevice + * + * Opens a device object. + */ +NTSTATUS KphOpenDevice( + __out PHANDLE DeviceHandle, + __in POBJECT_ATTRIBUTES ObjectAttributes, + __in KPROCESSOR_MODE AccessMode + ) +{ + return KphOpenNamedObject( + DeviceHandle, + 0, + ObjectAttributes, + *IoDeviceObjectType, + AccessMode + ); +} + +/* KphOpenDriver + * + * Opens a driver object. + */ +NTSTATUS KphOpenDriver( + __out PHANDLE DriverHandle, + __in POBJECT_ATTRIBUTES ObjectAttributes, + __in KPROCESSOR_MODE AccessMode + ) +{ + return KphOpenNamedObject( + DriverHandle, + 0, + ObjectAttributes, + *IoDriverObjectType, + AccessMode + ); +} + +/* KphQueryInformationDriver + * + * Queries information about a driver object. + */ +NTSTATUS KphQueryInformationDriver( + __in HANDLE DriverHandle, + __in DRIVER_INFORMATION_CLASS DriverInformationClass, + __out_bcount_opt(DriverInformationLength) PVOID DriverInformation, + __in ULONG DriverInformationLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PDRIVER_OBJECT driverObject; + + if ( + DriverInformationClass < DriverBasicInformation || + DriverInformationClass >= MaxDriverInfoClass + ) + return STATUS_INVALID_INFO_CLASS; + + /* Probe user input. */ + if (AccessMode != KernelMode) + { + __try + { + if (DriverInformation) + ProbeForWrite(DriverInformation, DriverInformationLength, 1); + if (ReturnLength) + ProbeForWrite(ReturnLength, sizeof(ULONG), 1); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + + status = ObReferenceObjectByHandle( + DriverHandle, + 0, + *IoDriverObjectType, + KernelMode, + &driverObject, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + __try + { + switch (DriverInformationClass) + { + /* DriverBasicInformation + * + * Basic information such as flags, driver base and driver size. + */ + case DriverBasicInformation: + { + if (DriverInformation) + { + /* Check buffer length. */ + 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; + + /* DriverNameInformation + * + * The name of the driver - e.g. \Driver\KProcessHacker. + */ + 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; + } + } + + /* Pass the ReturnLength. */ + if (ReturnLength) + *ReturnLength = sizeof(UNICODE_STRING) + driverObject->DriverName.Length; + } + break; + + /* DriverServiceKeyNameInformation + * + * 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; +} + +/* KphpCopyInfoUnicodeString + * + * Copies a UNICODE_STRING to an information buffer. If + * the given string is NULL, the function zeros the + * destination UNICODE_STRING. + */ +VOID KphpCopyInfoUnicodeString( + __out PVOID Information, + __in PUNICODE_STRING UnicodeString + ) +{ + PUNICODE_STRING targetUnicodeString = (PUNICODE_STRING)Information; + + if (UnicodeString) + { + targetUnicodeString->Length = UnicodeString->Length; + targetUnicodeString->MaximumLength = targetUnicodeString->Length; + targetUnicodeString->Buffer = (PWSTR)((PCHAR)Information + sizeof(UNICODE_STRING)); + memcpy( + targetUnicodeString->Buffer, + UnicodeString->Buffer, + targetUnicodeString->Length + ); + } + else + { + targetUnicodeString->Length = 0; + targetUnicodeString->MaximumLength = 0; + targetUnicodeString->Buffer = NULL; + } +} diff --git a/branches/ph-plugins/KProcessHacker/kph.c b/branches/ph-plugins/KProcessHacker/kph.c new file mode 100644 index 000000000..0fb19d84d --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/kph.c @@ -0,0 +1,373 @@ +/* + * Process Hacker Driver - + * custom APIs + * + * Copyright (C) 2009 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 . + */ + +#define _KPH_PRIVATE +#include "include/kph.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, GetSystemRoutineAddress) +#pragma alloc_text(PAGE, KphNtInit) +#pragma alloc_text(PAGE, OpenProcess) +#pragma alloc_text(PAGE, SetProcessToken) +#endif + +/* GetSystemRoutineAddress + * + * Gets the address of a function exported by ntoskrnl or hal. + */ +PVOID GetSystemRoutineAddress(WCHAR *Name) +{ + UNICODE_STRING routineName; + PVOID routineAddress = NULL; + + RtlInitUnicodeString(&routineName, Name); + + /* Wrap in SEH because MmGetSystemRoutineAddress is known to cause + some BSODs. */ + try + { + routineAddress = MmGetSystemRoutineAddress(&routineName); + } + except (EXCEPTION_EXECUTE_HANDLER) + { + routineAddress = NULL; + } + + return routineAddress; +} + +/* KphNtInit + * + * Initializes the KProcessHacker NT component. + */ +NTSTATUS KphNtInit() +{ + NTSTATUS status = STATUS_SUCCESS; + /* Confuse those damn AVs... */ + PWCHAR keService = L"KeService"; // length 9, 18 bytes + PWCHAR descriptorTable = L"DescriptorTable"; // 15, 30 bytes + WCHAR keServiceDescriptorTable[9 + 15 + 1]; + + /* Reconstruct the string. */ + memcpy(keServiceDescriptorTable, keService, 18); + memcpy(keServiceDescriptorTable + 9, descriptorTable, 30); + keServiceDescriptorTable[9 + 15] = L'\0'; + + /* Dynamically get function pointers. */ + __KeServiceDescriptorTable = GetSystemRoutineAddress(keServiceDescriptorTable); + dfprintf("KeServiceDescriptorTable: %#x\n", __KeServiceDescriptorTable); + PsGetProcessJob = GetSystemRoutineAddress(L"PsGetProcessJob"); + dfprintf("PsGetProcessJob: %#x\n", PsGetProcessJob); + PsResumeProcess = GetSystemRoutineAddress(L"PsResumeProcess"); + dfprintf("PsResumeProcess: %#x\n", PsResumeProcess); + PsSuspendProcess = GetSystemRoutineAddress(L"PsSuspendProcess"); + dfprintf("PsSuspendProcess: %#x\n", PsSuspendProcess); + + if (WindowsVersion >= WINDOWS_7) + { + ObGetObjectType = GetSystemRoutineAddress(L"ObGetObjectType"); + dfprintf("ObGetObjectType: %#x\n", ObGetObjectType); + } + + /* Scan for functions. */ + if (KiFastCallEntryScan.Initialized) + { + __KiFastCallEntry = KvScanProc(&KiFastCallEntryScan); + dfprintf("KiFastCallEntry+x: %#x\n", __KiFastCallEntry); + } + if (PsTerminateProcessScan.Initialized) + { + __PsTerminateProcess = KvScanProc(&PsTerminateProcessScan); + dfprintf("PsTerminateProcess: %#x\n", __PsTerminateProcess); + } + if (PspTerminateThreadByPointerScan.Initialized) + { + __PspTerminateThreadByPointer = KvScanProc(&PspTerminateThreadByPointerScan); + dfprintf("PspTerminateThreadByPointer: %#x\n", __PspTerminateThreadByPointer); + } + + return status; +} + +/* KphAttachProcess + * + * Attaches to a process represented by the specified EPROCESS. + */ +VOID KphAttachProcess( + __in PEPROCESS Process, + __out PKPH_ATTACH_STATE AttachState + ) +{ + AttachState->Attached = FALSE; + + /* Don't attach if we are already attached to the target. */ + if (Process != PsGetCurrentProcess()) + { + KeStackAttachProcess(Process, &AttachState->ApcState); + AttachState->Attached = TRUE; + AttachState->Process = Process; + } +} + +/* KphAttachProcessHandle + * + * Attaches to a process represented by the specified handle. + */ +NTSTATUS KphAttachProcessHandle( + __in HANDLE ProcessHandle, + __out PKPH_ATTACH_STATE AttachState + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PEPROCESS processObject; + + AttachState->Attached = FALSE; + + status = ObReferenceObjectByHandle( + ProcessHandle, + 0, + *PsProcessType, + KernelMode, + &processObject, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + KphAttachProcess(processObject, AttachState); + ObDereferenceObject(processObject); + + return status; +} + +/* KphAttachProcessId + * + * Attaches to a process represented by the specified process ID. + */ +NTSTATUS KphAttachProcessId( + __in HANDLE ProcessId, + __out PKPH_ATTACH_STATE AttachState + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PEPROCESS processObject; + + AttachState->Attached = FALSE; + + status = PsLookupProcessByProcessId(ProcessId, &processObject); + + if (!NT_SUCCESS(status)) + return status; + + KphAttachProcess(processObject, AttachState); + ObDereferenceObject(processObject); + + return status; +} + +/* KphCaptureUnicodeString + * + * Captures a UNICODE_STRING. This function will not throw exceptions. + */ +NTSTATUS KphCaptureUnicodeString( + __in PUNICODE_STRING UnicodeString, + __out PUNICODE_STRING CapturedUnicodeString + ) +{ + __try + { + CapturedUnicodeString->Length = UnicodeString->Length; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + + CapturedUnicodeString->MaximumLength = CapturedUnicodeString->Length; + CapturedUnicodeString->Buffer = ExAllocatePoolWithTag( + PagedPool, + CapturedUnicodeString->Length, + TAG_CAPTURED_UNICODE_STRING + ); + + if (!CapturedUnicodeString->Buffer) + return STATUS_INSUFFICIENT_RESOURCES; + + __try + { + memcpy( + CapturedUnicodeString->Buffer, + UnicodeString->Buffer, + CapturedUnicodeString->Length + ); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + KphFreeCapturedUnicodeString(CapturedUnicodeString); + return GetExceptionCode(); + } + + return STATUS_SUCCESS; +} + +/* KphDetachProcess + * + * Detaches from the currently attached process. + */ +VOID KphDetachProcess( + __in PKPH_ATTACH_STATE AttachState + ) +{ + if (AttachState->Attached) + KeUnstackDetachProcess(&AttachState->ApcState); +} + +/* KphFreeCapturedUnicodeString + * + * Frees a UNICODE_STRING captured by KphCaptureUnicodeString. + */ +VOID KphFreeCapturedUnicodeString( + __in PUNICODE_STRING CapturedUnicodeString + ) +{ + ExFreePoolWithTag( + CapturedUnicodeString->Buffer, + TAG_CAPTURED_UNICODE_STRING + ); +} + +/* KphProbeForReadUnicodeString + * + * Probes a UNICODE_STRING structure for reading. + */ +VOID KphProbeForReadUnicodeString( + __in PUNICODE_STRING UnicodeString + ) +{ + ProbeForRead(UnicodeString, sizeof(UNICODE_STRING), 1); + ProbeForRead(UnicodeString->Buffer, UnicodeString->Length, 1); +} + +/* KphProbeSystemAddressRange + * + * Probes an address range in kernel-mode memory for reading. + */ +VOID KphProbeSystemAddressRange( + __in PVOID BaseAddress, + __in ULONG Length + ) +{ + ULONG_PTR page, pageEnd; + + /* HACK HACK HACK HACK HACK HACK */ + /* Check the address range by checking each page. */ + /* Round down the base address to the page size. Note: please make sure you are + * not using a dumbass compiler which optimizes the following line by removing + * the divide and multiply. + */ + page = (ULONG_PTR)BaseAddress / PAGE_SIZE * PAGE_SIZE; + /* BaseAddress + Length - 1 is the last address we will be reading. */ + pageEnd = ((ULONG_PTR)BaseAddress + Length - 1) / PAGE_SIZE * PAGE_SIZE; + + for (; page <= pageEnd; page += PAGE_SIZE) + { + /* Check the page. */ + if (!MmIsAddressValid((PVOID)page)) + ExRaiseStatus(STATUS_ACCESS_VIOLATION); + } +} + +/* OpenProcess + * + * Opens the process with the specified PID. + */ +NTSTATUS OpenProcess( + __out PHANDLE ProcessHandle, + __in ACCESS_MASK DesiredAccess, + __in HANDLE ProcessId + ) +{ + OBJECT_ATTRIBUTES objAttr = { 0 }; + CLIENT_ID clientId; + + objAttr.Length = sizeof(objAttr); + clientId.UniqueThread = 0; + clientId.UniqueProcess = ProcessId; + + return KphOpenProcess(ProcessHandle, DesiredAccess, &objAttr, &clientId, KernelMode); +} + +/* SetProcessToken + * + * Assigns the primary token of the target process from the + * primary token of source process. + */ +NTSTATUS SetProcessToken( + __in HANDLE sourcePid, + __in HANDLE targetPid + ) +{ + NTSTATUS status; + HANDLE source; + + if (NT_SUCCESS(status = OpenProcess(&source, PROCESS_QUERY_INFORMATION, sourcePid))) + { + HANDLE target; + + if (NT_SUCCESS(status = OpenProcess(&target, PROCESS_QUERY_INFORMATION | + PROCESS_SET_INFORMATION, targetPid))) + { + HANDLE sourceToken; + + if (NT_SUCCESS(status = KphOpenProcessTokenEx(source, TOKEN_DUPLICATE, 0, + &sourceToken, UserMode))) + { + HANDLE dupSourceToken; + OBJECT_ATTRIBUTES objectAttributes = { 0 }; + + objectAttributes.Length = sizeof(objectAttributes); + + if (NT_SUCCESS(status = ZwDuplicateToken(sourceToken, TOKEN_ASSIGN_PRIMARY, &objectAttributes, + FALSE, TokenPrimary, &dupSourceToken))) + { + PROCESS_ACCESS_TOKEN token; + + token.Token = dupSourceToken; + token.Thread = 0; + + status = ZwSetInformationProcess(target, ProcessAccessToken, &token, sizeof(token)); + } + + ZwClose(dupSourceToken); + } + + ZwClose(sourceToken); + } + + ZwClose(target); + } + + ZwClose(source); + + return status; +} diff --git a/branches/ph-plugins/KProcessHacker/kprocesshacker.c b/branches/ph-plugins/KProcessHacker/kprocesshacker.c new file mode 100644 index 000000000..6b2249298 --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/kprocesshacker.c @@ -0,0 +1,2367 @@ +/* + * Process Hacker Driver - + * main driver code + * + * Copyright (C) 2009 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/kprocesshacker.h" +#include "include/debug.h" + +#include "include/kph.h" +#include "include/protect.h" +#include "include/ps.h" +#include "include/sysservice.h" +#include "include/version.h" + +#define CHECK_IN_LENGTH \ + if (inLength < sizeof(*args)) \ + { \ + status = STATUS_BUFFER_TOO_SMALL; \ + goto IoControlEnd; \ + } +#define CHECK_OUT_LENGTH \ + if (outLength < sizeof(*ret)) \ + { \ + status = STATUS_BUFFER_TOO_SMALL; \ + goto IoControlEnd; \ + } +#define CHECK_IN_OUT_LENGTH \ + if (inLength < sizeof(*args) || outLength < sizeof(*ret)) \ + { \ + status = STATUS_BUFFER_TOO_SMALL; \ + goto IoControlEnd; \ + } + +PDRIVER_OBJECT KphDriverObject; + +static PKPH_OBJECT_TYPE ClientEntryType; +static LIST_ENTRY ClientListHead; +static EX_PUSH_LOCK ClientListLock; + +static BOOLEAN ProtectionInitialized = FALSE; +static FAST_MUTEX ProtectionMutex; + +static ULONG SsStartCount = 0; +static FAST_MUTEX SsMutex; + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, DriverEntry) +#pragma alloc_text(PAGE, DriverUnload) +#pragma alloc_text(PAGE, KphDispatchCreate) +#pragma alloc_text(PAGE, KphDispatchClose) +#pragma alloc_text(PAGE, KphDispatchDeviceControl) +#pragma alloc_text(PAGE, KphDispatchRead) +#pragma alloc_text(PAGE, KphUnsupported) +#endif + +NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) +{ + NTSTATUS status = STATUS_SUCCESS; + int i; + PDEVICE_OBJECT deviceObject = NULL; + UNICODE_STRING deviceName, dosDeviceName; + + KphDriverObject = DriverObject; + + /* Initialize version information. */ + status = KvInit(); + + if (!NT_SUCCESS(status)) + { + if (status == STATUS_NOT_SUPPORTED) + dprintf("Your operating system is not supported by KProcessHacker\n"); + + return status; + } + + /* Initialize NT KPH. */ + status = KphNtInit(); + + if (!NT_SUCCESS(status)) + return status; + + /* Initialize hooking. */ + status = KphHookInit(); + + if (!NT_SUCCESS(status)) + return status; + + /* Initialize the KPH object manager. */ + status = KphRefInit(); + + if (!NT_SUCCESS(status)) + return status; + + /* Initialize system service logging. */ + status = KphSsLogInit(); + + if (!NT_SUCCESS(status)) + { + KphRefDeinit(); + return status; + } + + /* Initialize trace databases. */ + status = KphTraceDatabaseInitialization(); + + if (!NT_SUCCESS(status)) + { + KphRefDeinit(); + return status; + } + + /* Initialize client list structures. */ + InitializeListHead(&ClientListHead); + ExInitializePushLock(&ClientListLock); + + status = KphCreateObjectType( + &ClientEntryType, + PagedPool, + 0, + ClientEntryDeleteProcedure + ); + + if (!NT_SUCCESS(status)) + { + KphRefDeinit(); + return status; + } + + /* Initialize process protection. */ + ExInitializeFastMutex(&ProtectionMutex); + /* Initialize the system service logging mutex. */ + ExInitializeFastMutex(&SsMutex); + + RtlInitUnicodeString(&deviceName, KPH_DEVICE_NAME); + RtlInitUnicodeString(&dosDeviceName, KPH_DEVICE_DOS_NAME); + + /* Create the KProcessHacker device. */ + status = IoCreateDevice(DriverObject, 0, &deviceName, + FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &deviceObject); + + /* Set up the major functions. */ + for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) + DriverObject->MajorFunction[i] = NULL; + + DriverObject->MajorFunction[IRP_MJ_CLOSE] = KphDispatchClose; + DriverObject->MajorFunction[IRP_MJ_CREATE] = KphDispatchCreate; + DriverObject->MajorFunction[IRP_MJ_READ] = KphDispatchRead; + DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KphDispatchDeviceControl; + DriverObject->DriverUnload = DriverUnload; + + deviceObject->Flags |= DO_BUFFERED_IO; + deviceObject->Flags &= ~DO_DEVICE_INITIALIZING; + + IoCreateSymbolicLink(&dosDeviceName, &deviceName); + + dprintf("Driver loaded\n"); + + return STATUS_SUCCESS; +} + +VOID DriverUnload(PDRIVER_OBJECT DriverObject) +{ + UNICODE_STRING dosDeviceName; + + RtlInitUnicodeString(&dosDeviceName, KPH_DEVICE_DOS_NAME); + IoDeleteSymbolicLink(&dosDeviceName); + IoDeleteDevice(DriverObject->DeviceObject); + + ExAcquireFastMutex(&ProtectionMutex); + + if (ProtectionInitialized) + { + KphProtectDeinit(); + ProtectionInitialized = FALSE; + } + + ExReleaseFastMutex(&ProtectionMutex); + + /* Make sure system service logging is disabled. */ + if (SsStartCount > 0) + SsUnref(SsStartCount); + + /* Free system service logging structures. */ + KphSsLogDeinit(); + + /* Free all objects in the object manager. */ + KphRefDeinit(); + + dprintf("Driver unloaded\n"); +} + +NTSTATUS KphDispatchCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp) +{ + NTSTATUS status = STATUS_SUCCESS; + +#ifdef KPH_REQUIRE_DEBUG_PRIVILEGE + if (!SeSinglePrivilegeCheck(SeExports->SeDebugPrivilege, UserMode)) + { + dprintf("Client (PID %d) was refused\n", PsGetCurrentProcessId()); + Irp->IoStatus.Status = STATUS_PRIVILEGE_NOT_HELD; + + return STATUS_PRIVILEGE_NOT_HELD; + } +#endif + + /* Add a client entry. Note that we don't dereference it because + * we keep one reference for it being on the client list. + */ + if (!CreateClientEntry(NULL)) + { + Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; + return STATUS_INSUFFICIENT_RESOURCES; + } + + dprintf("Client (PID %d) connected\n", PsGetCurrentProcessId()); + dprintf("Base IOCTL is 0x%08x\n", KPH_CTL_CODE(0)); + + return status; +} + +NTSTATUS KphDispatchClose(PDEVICE_OBJECT DeviceObject, PIRP Irp) +{ + NTSTATUS status = STATUS_SUCCESS; + PKPH_CLIENT_ENTRY clientEntry; + + ExAcquireFastMutex(&ProtectionMutex); + + if (ProtectionInitialized) + { + ULONG count = KphProtectRemoveByTag(PsGetCurrentProcessId()); + dprintf("Removed %d protection entries\n", count); + } + + ExReleaseFastMutex(&ProtectionMutex); + + /* Get the current client entry and dereference it twice to remove it. */ + clientEntry = ReferenceClientEntry(NULL); + + if (clientEntry) + KphDereferenceObjectEx(clientEntry, 2, FALSE); + + dprintf("Client (PID %d) disconnected\n", PsGetCurrentProcessId()); + + return status; +} + +VOID InitProtection() +{ + ExAcquireFastMutex(&ProtectionMutex); + + if (!ProtectionInitialized) + { + if (NT_SUCCESS(KphProtectInit())) + ProtectionInitialized = TRUE; + } + + ExReleaseFastMutex(&ProtectionMutex); +} + +VOID SsRef(LONG count) +{ + LONG oldRefCount; + + ASSERT(count >= 0); + + if (count == 0) + return; + + ExAcquireFastMutex(&SsMutex); + + /* Add references. */ + oldRefCount = InterlockedExchangeAdd(&SsStartCount, count); + ASSERT(oldRefCount >= 0); + + /* Start system service logging if this was the first bunch of references. */ + if (oldRefCount == 0) + KphSsLogStart(); + + ExReleaseFastMutex(&SsMutex); +} + +VOID SsUnref(LONG count) +{ + LONG oldRefCount; + + ASSERT(count >= 0); + + if (count == 0) + return; + + ExAcquireFastMutex(&SsMutex); + + oldRefCount = InterlockedExchangeAdd(&SsStartCount, -count); + ASSERT(oldRefCount > 0); + + if (oldRefCount - count == 0) + KphSsLogStop(); + + ExReleaseFastMutex(&SsMutex); +} + +VOID NTAPI ClientEntryDeleteProcedure( + __in PVOID Object, + __in ULONG Flags + ) +{ + PKPH_CLIENT_ENTRY entry = (PKPH_CLIENT_ENTRY)Object; + + /* Lower the SS start count. */ + SsUnref(entry->SsStartCount); + + /* Free the handle table. */ + KphFreeHandleTable(entry->HandleTable); + + /* Remove the entry from the client list. */ + KeEnterCriticalRegion(); + ExAcquirePushLockExclusive(&ClientListLock); + RemoveEntryList(&entry->ClientListEntry); + ExReleasePushLock(&ClientListLock); + KeLeaveCriticalRegion(); +} + +PKPH_CLIENT_ENTRY CreateClientEntry( + __in_opt HANDLE ProcessId + ) +{ + PKPH_CLIENT_ENTRY entry; + PKPH_HANDLE_TABLE handleTable; + + /* If the PID wasn't specified, use the current one. */ + if (!ProcessId) + ProcessId = PsGetCurrentProcessId(); + + if (!NT_SUCCESS(KphCreateHandleTable( + &handleTable, + KPH_CLIENT_MAXHANDLES, + sizeof(KPH_HANDLE_TABLE_ENTRY), + TAG_CLIENT_HANDLETABLE + ))) + return NULL; + + if (!NT_SUCCESS(KphCreateObject( + &entry, + sizeof(KPH_CLIENT_ENTRY), + 0, + ClientEntryType, + 0 + ))) + { + KphFreeHandleTable(handleTable); + return NULL; + } + + /* Initialize the entry. */ + entry->ProcessId = ProcessId; + entry->HandleTable = handleTable; + KphInitializeGuardedLock(&entry->SsLock, FALSE); + entry->SsStartCount = 0; + + /* Insert the entry into the client list. */ + KeEnterCriticalRegion(); + ExAcquirePushLockExclusive(&ClientListLock); + InsertHeadList(&ClientListHead, &entry->ClientListEntry); + ExReleasePushLock(&ClientListLock); + KeLeaveCriticalRegion(); + + return entry; +} + +PKPH_CLIENT_ENTRY ReferenceClientEntry( + __in_opt HANDLE ProcessId + ) +{ + PLIST_ENTRY entry = ClientListHead.Flink; + + /* If the PID wasn't specified, use the current one. */ + if (!ProcessId) + ProcessId = PsGetCurrentProcessId(); + + KeEnterCriticalRegion(); + ExAcquirePushLockShared(&ClientListLock); + + /* Find the client entry. */ + while (entry != &ClientListHead) + { + PKPH_CLIENT_ENTRY clientEntry = + CONTAINING_RECORD(entry, KPH_CLIENT_ENTRY, ClientListEntry); + + if (clientEntry->ProcessId == ProcessId) + { + PKPH_CLIENT_ENTRY returnEntry = NULL; + + /* Reference and return the entry. */ + if (KphReferenceObjectSafe(clientEntry)) + { + returnEntry = clientEntry; + } + + ExReleasePushLock(&ClientListLock); + KeLeaveCriticalRegion(); + + return returnEntry; + } + + entry = entry->Flink; + } + + ExReleasePushLock(&ClientListLock); + KeLeaveCriticalRegion(); + + return NULL; +} + +NTSTATUS CloseClientHandle( + __in_opt HANDLE ProcessId, + __in HANDLE Handle + ) +{ + NTSTATUS status; + PKPH_CLIENT_ENTRY clientEntry; + + clientEntry = ReferenceClientEntry(ProcessId); + + if (!clientEntry) + return STATUS_UNSUCCESSFUL; + + status = KphCloseHandle(clientEntry->HandleTable, Handle); + KphDereferenceObject(clientEntry); + + return status; +} + +NTSTATUS CreateClientHandle( + __in_opt HANDLE ProcessId, + __in PVOID Object, + __out PHANDLE Handle + ) +{ + NTSTATUS status; + PKPH_CLIENT_ENTRY clientEntry; + + clientEntry = ReferenceClientEntry(ProcessId); + + if (!clientEntry) + return STATUS_UNSUCCESSFUL; + + status = KphCreateHandle(clientEntry->HandleTable, Object, Handle); + KphDereferenceObject(clientEntry); + + return status; +} + +NTSTATUS ReferenceClientHandle( + __in_opt HANDLE ProcessId, + __in HANDLE Handle, + __in PKPH_OBJECT_TYPE ObjectType, + __out PVOID *Object + ) +{ + NTSTATUS status; + PKPH_CLIENT_ENTRY clientEntry; + + clientEntry = ReferenceClientEntry(ProcessId); + + if (!clientEntry) + return STATUS_UNSUCCESSFUL; + + status = KphReferenceObjectByHandle( + clientEntry->HandleTable, + Handle, + ObjectType, + Object + ); + KphDereferenceObject(clientEntry); + + return status; +} + +PCHAR GetIoControlName(ULONG ControlCode) +{ + switch (ControlCode) + { + case KPH_CLOSEHANDLE: + return "Client Close Handle"; + case KPH_SSQUERYCLIENTENTRY: + return "SsQueryClientEntry"; + case KPH_OPENPROCESS: + return "KphOpenProcess"; + case KPH_OPENTHREAD: + return "KphOpenThread"; + case KPH_OPENPROCESSTOKEN: + return "KphOpenProcessTokenEx"; + case KPH_GETPROCESSPROTECTED: + return "Get Process Protected"; + case KPH_SETPROCESSPROTECTED: + return "Set Process Protected"; + case KPH_TERMINATEPROCESS: + return "KphTerminateProcess"; + case KPH_SUSPENDPROCESS: + return "KphSuspendProcess"; + case KPH_RESUMEPROCESS: + return "KphResumeProcess"; + case KPH_READVIRTUALMEMORY: + return "KphReadVirtualMemory"; + case KPH_WRITEVIRTUALMEMORY: + return "KphWriteVirtualMemory"; + case KPH_SETPROCESSTOKEN: + return "Set Process Token"; + case KPH_GETTHREADSTARTADDRESS: + return "Get Thread Start Address"; + case KPH_SETHANDLEATTRIBUTES: + return "Set Handle Attributes"; + case KPH_GETHANDLEOBJECTNAME: + return "Get Handle Object Name"; + case KPH_OPENPROCESSJOB: + return "KphOpenProcessJob"; + case KPH_GETCONTEXTTHREAD: + return "KphGetContextThread"; + case KPH_SETCONTEXTTHREAD: + return "KphSetContextThread"; + case KPH_GETTHREADWIN32THREAD: + return "KphGetThreadWin32Thread"; + case KPH_DUPLICATEOBJECT: + return "KphDuplicateObject"; + case KPH_ZWQUERYOBJECT: + return "ZwQueryObject"; + case KPH_GETPROCESSID: + return "KphGetProcessId"; + case KPH_GETTHREADID: + return "KphGetThreadId"; + case KPH_TERMINATETHREAD: + return "KphTerminateThread"; + case KPH_GETFEATURES: + return "Get Features"; + case KPH_SETHANDLEGRANTEDACCESS: + return "KphSetHandleGrantedAccess"; + case KPH_ASSIGNIMPERSONATIONTOKEN: + return "KphAssignImpersonationToken"; + case KPH_PROTECTADD: + return "Add Process Protection"; + case KPH_PROTECTREMOVE: + return "Remove Process Protection"; + case KPH_PROTECTQUERY: + return "Query Process Protection"; + case KPH_UNSAFEREADVIRTUALMEMORY: + return "KphUnsafeReadVirtualMemory"; + case KPH_SETEXECUTEOPTIONS: + return "Set Execute Options"; + case KPH_QUERYPROCESSHANDLES: + return "KphQueryProcessHandles"; + case KPH_OPENTHREADPROCESS: + return "KphOpenThreadProcess"; + case KPH_CAPTURESTACKBACKTRACETHREAD: + return "KphCaptureStackBackTraceThread"; + case KPH_DANGEROUSTERMINATETHREAD: + return "KphDangerousTerminateThread"; + case KPH_OPENDEVICE: + return "KphOpenDevice"; + case KPH_OPENDRIVER: + return "KphOpenDriver"; + case KPH_QUERYINFORMATIONDRIVER: + return "KphQueryInformationDriver"; + case KPH_OPENDIRECTORYOBJECT: + return "KphOpenDirectoryObject"; + case KPH_SSREF: + return "SsRef"; + case KPH_SSUNREF: + return "SsUnref"; + case KPH_SSCREATECLIENTENTRY: + return "SsCreateClientEntry"; + case KPH_SSCREATERULESETENTRY: + return "SsCreateRuleSetEntry"; + case KPH_SSREMOVERULE: + return "SsRemoveRule"; + case KPH_SSADDPROCESSIDRULE: + return "SsAddProcessIdRule"; + case KPH_SSADDTHREADIDRULE: + return "SsAddThreadIdRule"; + case KPH_SSADDPREVIOUSMODERULE: + return "SsAddPreviousModeRule"; + case KPH_SSADDNUMBERRULE: + return "SsAddNumberRule"; + case KPH_SSENABLECLIENTENTRY: + return "SsEnableClientEntry"; + default: + return "Unknown"; + } +} + +NTSTATUS KphDispatchDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp) +{ + NTSTATUS status = STATUS_SUCCESS; + PIO_STACK_LOCATION ioStackIrp = NULL; + PVOID dataBuffer; + ULONG controlCode; + ULONG inLength = 0; + ULONG outLength = 0; + ULONG retLength = 0; + + Irp->IoStatus.Status = STATUS_SUCCESS; + Irp->IoStatus.Information = 0; + + ioStackIrp = IoGetCurrentIrpStackLocation(Irp); + + if (ioStackIrp == NULL) + { + status = STATUS_INTERNAL_ERROR; + goto IoControlEnd; + } + + dataBuffer = Irp->AssociatedIrp.SystemBuffer; + + if (dataBuffer == NULL && (inLength != 0 || outLength != 0)) + { + status = STATUS_BUFFER_TOO_SMALL; + goto IoControlEnd; + } + + inLength = ioStackIrp->Parameters.DeviceIoControl.InputBufferLength; + outLength = ioStackIrp->Parameters.DeviceIoControl.OutputBufferLength; + controlCode = ioStackIrp->Parameters.DeviceIoControl.IoControlCode; + + dprintf("IoControl 0x%08x (%s)\n", controlCode, GetIoControlName(controlCode)); + + /* 1-byte packing for KPH input/output structures. */ + #include + + switch (controlCode) + { + /* Client Close Handle + * + * Closes a handle opened by the client. + */ + case KPH_CLOSEHANDLE: + { + struct + { + HANDLE Handle; + } *args = dataBuffer; + PKPH_CLIENT_ENTRY clientEntry; + + CHECK_IN_LENGTH; + + status = CloseClientHandle(NULL, args->Handle); + } + break; + + /* SsQueryClientEntry + * + * Queries information about a client entry. + */ + case KPH_SSQUERYCLIENTENTRY: + { + struct + { + HANDLE ClientEntryHandle; + PKPHSS_CLIENT_INFORMATION ClientInformation; + ULONG ClientInformationLength; + PULONG ReturnLength; + } *args = dataBuffer; + PKPHSS_CLIENT_ENTRY clientEntry; + + CHECK_IN_LENGTH; + + /* Reference the client entry. */ + status = ReferenceClientHandle( + NULL, + args->ClientEntryHandle, + KphSsClientEntryType, + &clientEntry + ); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + /* Query the client entry. */ + status = KphSsQueryClientEntry( + clientEntry, + args->ClientInformation, + args->ClientInformationLength, + args->ReturnLength, + UserMode + ); + KphDereferenceObject(clientEntry); + } + break; + + /* KphOpenProcess + * + * Opens the specified process. This call will never fail unless: + * 1. PsLookupProcessByProcessId, ObOpenObjectByPointer or some lower-level + * function is hooked, or + * 2. The process is protected. + */ + case KPH_OPENPROCESS: + { + struct + { + HANDLE ProcessId; + ACCESS_MASK DesiredAccess; + } *args = dataBuffer; + struct + { + HANDLE ProcessHandle; + } *ret = dataBuffer; + OBJECT_ATTRIBUTES objectAttributes = { 0 }; + CLIENT_ID clientId; + + CHECK_IN_OUT_LENGTH; + + clientId.UniqueThread = 0; + clientId.UniqueProcess = args->ProcessId; + status = KphOpenProcess( + &ret->ProcessHandle, + args->DesiredAccess, + &objectAttributes, + &clientId, + KernelMode + ); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + retLength = sizeof(*ret); + } + break; + + /* KphOpenThread + * + * Opens the specified thread. This call will never fail unless: + * 1. PsLookupProcessThreadByCid, ObOpenObjectByPointer or some lower-level + * function is hooked, or + * 2. The thread's process is protected. + */ + case KPH_OPENTHREAD: + { + struct + { + HANDLE ThreadId; + ACCESS_MASK DesiredAccess; + } *args = dataBuffer; + struct + { + HANDLE ThreadHandle; + } *ret = dataBuffer; + OBJECT_ATTRIBUTES objectAttributes = { 0 }; + CLIENT_ID clientId; + + CHECK_IN_OUT_LENGTH; + + clientId.UniqueThread = args->ThreadId; + clientId.UniqueProcess = 0; + status = KphOpenThread( + &ret->ThreadHandle, + args->DesiredAccess, + &objectAttributes, + &clientId, + KernelMode + ); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + retLength = sizeof(*ret); + } + break; + + /* KphOpenProcessToken + * + * Opens the specified process' token. This call will never fail unless + * a low-level function is hooked. + */ + case KPH_OPENPROCESSTOKEN: + { + struct + { + HANDLE ProcessHandle; + ACCESS_MASK DesiredAccess; + } *args = dataBuffer; + struct + { + HANDLE TokenHandle; + } *ret = dataBuffer; + + CHECK_IN_OUT_LENGTH; + + status = KphOpenProcessTokenEx( + args->ProcessHandle, + args->DesiredAccess, + 0, + &ret->TokenHandle, + KernelMode + ); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + retLength = sizeof(*ret); + } + break; + + /* Get Process Protected + * + * Gets whether the process is protected. + */ + case KPH_GETPROCESSPROTECTED: + { + struct + { + HANDLE ProcessId; + } *args = dataBuffer; + struct + { + BOOLEAN IsProtected; + } *ret = dataBuffer; + PEPROCESS processObject; + + CHECK_IN_OUT_LENGTH; + + status = PsLookupProcessByProcessId(args->ProcessId, &processObject); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + ret->IsProtected = + (CHAR)GET_BIT( + *(PULONG)KVOFF(processObject, OffEpProtectedProcessOff), + OffEpProtectedProcessBit + ); + ObDereferenceObject(processObject); + retLength = sizeof(*ret); + } + break; + + /* Set Process Protected + * + * Sets whether the process is protected. + */ + case KPH_SETPROCESSPROTECTED: + { + struct + { + HANDLE ProcessId; + BOOLEAN IsProtected; + } *args = dataBuffer; + PEPROCESS processObject; + + CHECK_IN_LENGTH; + + status = PsLookupProcessByProcessId(args->ProcessId, &processObject); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + if (args->IsProtected) + { + SET_BIT( + *(PULONG)KVOFF(processObject, OffEpProtectedProcessOff), + OffEpProtectedProcessBit + ); + } + else + { + CLEAR_BIT( + *(PULONG)KVOFF(processObject, OffEpProtectedProcessOff), + OffEpProtectedProcessBit + ); + } + + ObDereferenceObject(processObject); + } + break; + + /* KphTerminateProcess + * + * Terminates the specified process. This call will never fail unless + * PsTerminateProcess could not be located and Zw/NtTerminateProcess + * is hooked, or an attempt was made to terminate the current process. + * In that case, the call will fail with STATUS_CANT_TERMINATE_SELF. + */ + case KPH_TERMINATEPROCESS: + { + struct + { + HANDLE ProcessHandle; + NTSTATUS ExitStatus; + } *args = dataBuffer; + + CHECK_IN_LENGTH; + + status = KphTerminateProcess(args->ProcessHandle, args->ExitStatus); + } + break; + + /* KphSuspendProcess + * + * Suspends the specified process. This call will fail on Windows XP + * and below. + */ + case KPH_SUSPENDPROCESS: + { + struct + { + HANDLE ProcessHandle; + } *args = dataBuffer; + + CHECK_IN_LENGTH; + + status = KphSuspendProcess(args->ProcessHandle); + } + break; + + /* KphResumeProcess + * + * Resumes the specified process. This call will fail on Windows XP + * and below. + */ + case KPH_RESUMEPROCESS: + { + struct + { + HANDLE ProcessHandle; + } *args = dataBuffer; + + CHECK_IN_LENGTH; + + status = KphResumeProcess(args->ProcessHandle); + } + break; + + /* KphReadVirtualMemory + * + * Reads process memory. + */ + case KPH_READVIRTUALMEMORY: + { + struct + { + HANDLE ProcessHandle; + PVOID BaseAddress; + PVOID Buffer; + ULONG BufferLength; + PULONG ReturnLength; + } *args = dataBuffer; + + CHECK_IN_LENGTH; + + status = KphReadVirtualMemory( + args->ProcessHandle, + args->BaseAddress, + args->Buffer, + args->BufferLength, + args->ReturnLength, + UserMode + ); + } + break; + + /* KphWriteVirtualMemory + * + * Writes to process memory. + */ + case KPH_WRITEVIRTUALMEMORY: + { + struct + { + HANDLE ProcessHandle; + PVOID BaseAddress; + PVOID Buffer; + ULONG BufferLength; + PULONG ReturnLength; + } *args = dataBuffer; + + CHECK_IN_LENGTH; + + status = KphWriteVirtualMemory( + args->ProcessHandle, + args->BaseAddress, + args->Buffer, + args->BufferLength, + args->ReturnLength, + UserMode + ); + } + break; + + /* Set Process Token + * + * Assigns the primary token of a source process to a target process. + */ + case KPH_SETPROCESSTOKEN: + { + struct + { + HANDLE SourceProcessId; + HANDLE TargetProcessId; + } *args = dataBuffer; + + CHECK_IN_LENGTH; + + status = SetProcessToken(args->SourceProcessId, args->TargetProcessId); + } + break; + + /* Get Thread Start Address + * + * Gets the specified thread's start address. + */ + case KPH_GETTHREADSTARTADDRESS: + { + struct + { + HANDLE ThreadHandle; + } *args = dataBuffer; + struct + { + PVOID StartAddress; + } *ret = dataBuffer; + PETHREAD threadObject; + + CHECK_IN_OUT_LENGTH; + + status = ObReferenceObjectByHandle(args->ThreadHandle, 0, *PsThreadType, KernelMode, &threadObject, NULL); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + /* Get the Win32StartAddress */ + if (!(ret->StartAddress = *(PVOID *)KVOFF(threadObject, OffEtWin32StartAddress))) + { + /* If that failed, get the StartAddress */ + ret->StartAddress = *(PVOID *)KVOFF(threadObject, OffEtStartAddress); + } + + ObDereferenceObject(threadObject); + retLength = sizeof(*ret); + } + break; + + /* Set Handle Attributes + * + * Sets handle flags in the specified process. + */ + case KPH_SETHANDLEATTRIBUTES: + { + struct + { + HANDLE ProcessHandle; + HANDLE Handle; + ULONG Flags; + } *args = dataBuffer; + KPH_ATTACH_STATE attachState; + OBJECT_HANDLE_FLAG_INFORMATION handleFlags = { 0 }; + + CHECK_IN_LENGTH; + + status = KphAttachProcessHandle(args->ProcessHandle, &attachState); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + if (args->Flags & OBJ_PROTECT_CLOSE) + handleFlags.ProtectFromClose = TRUE; + if (args->Flags & OBJ_INHERIT) + handleFlags.Inherit = TRUE; + + status = ObSetHandleAttributes(args->Handle, &handleFlags, UserMode); + KphDetachProcess(&attachState); + } + break; + + /* Get Handle Object Name + * + * Gets the name of the specified handle. The handle can be remote; in + * that case a valid process handle must be passed. Otherwise, set the + * process handle to -1 (NtCurrentProcess()). + */ + case KPH_GETHANDLEOBJECTNAME: + { + struct + { + HANDLE ProcessHandle; + HANDLE Handle; + } *args = dataBuffer; + KPH_ATTACH_STATE attachState; + PVOID object; + + CHECK_IN_LENGTH; + + status = KphAttachProcessHandle(args->ProcessHandle, &attachState); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + /* See the block for KPH_ZWQUERYOBJECT for information. */ + if (attachState.Process == PsInitialSystemProcess) + MakeKernelHandle(args->Handle); + + status = ObReferenceObjectByHandle(args->Handle, 0, NULL, KernelMode, &object, NULL); + KphDetachProcess(&attachState); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + status = KphQueryNameObject(object, (PUNICODE_STRING)dataBuffer, outLength, &retLength); + ObDereferenceObject(object); + } + break; + + /* KphOpenProcessJob + * + * Opens the job object that the process is assigned to. If the process is + * not assigned to any job object, the call will fail with STATUS_PROCESS_NOT_IN_JOB. + */ + case KPH_OPENPROCESSJOB: + { + struct + { + HANDLE ProcessHandle; + ACCESS_MASK DesiredAccess; + } *args = dataBuffer; + struct + { + HANDLE JobHandle; + } *ret = dataBuffer; + + CHECK_IN_OUT_LENGTH; + + status = KphOpenProcessJob(args->ProcessHandle, args->DesiredAccess, &ret->JobHandle, KernelMode); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + retLength = sizeof(*ret); + } + break; + + /* KphGetContextThread + * + * Gets the context of the specified thread. + */ + case KPH_GETCONTEXTTHREAD: + { + struct + { + HANDLE ThreadHandle; + PCONTEXT ThreadContext; + } *args = dataBuffer; + + CHECK_IN_LENGTH; + + status = KphGetContextThread(args->ThreadHandle, args->ThreadContext, UserMode); + } + break; + + /* KphSetContextThread + * + * Sets the context of the specified thread. + */ + case KPH_SETCONTEXTTHREAD: + { + struct + { + HANDLE ThreadHandle; + PCONTEXT ThreadContext; + } *args = dataBuffer; + + CHECK_IN_LENGTH; + + status = KphSetContextThread(args->ThreadHandle, args->ThreadContext, UserMode); + } + break; + + /* KphGetThreadWin32Thread + * + * Gets a pointer to the specified thread's Win32Thread structure. + */ + case KPH_GETTHREADWIN32THREAD: + { + struct + { + HANDLE ThreadHandle; + } *args = dataBuffer; + struct + { + PVOID Win32Thread; + } *ret = dataBuffer; + + CHECK_IN_OUT_LENGTH; + + status = KphGetThreadWin32Thread(args->ThreadHandle, &ret->Win32Thread, KernelMode); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + retLength = sizeof(*ret); + } + break; + + /* KphDuplicateObject + * + * Duplicates the specified handle from the source process to the target process. + * Do not use this call to duplicate file handles; it may freeze indefinitely if + * the file is a named pipe. + */ + case KPH_DUPLICATEOBJECT: + { + struct + { + HANDLE SourceProcessHandle; + HANDLE SourceHandle; + HANDLE TargetProcessHandle; + PHANDLE TargetHandle; + ACCESS_MASK DesiredAccess; + ULONG HandleAttributes; + ULONG Options; + } *args = dataBuffer; + + CHECK_IN_LENGTH; + + status = KphDuplicateObject( + args->SourceProcessHandle, + args->SourceHandle, + args->TargetProcessHandle, + args->TargetHandle, + args->DesiredAccess, + args->HandleAttributes, + args->Options, + UserMode + ); + } + break; + + /* ZwQueryObject + * + * Performs ZwQueryObject in the context of another process. + */ + case KPH_ZWQUERYOBJECT: + { + struct + { + HANDLE ProcessHandle; + HANDLE Handle; + OBJECT_INFORMATION_CLASS ObjectInformationClass; + } *args = dataBuffer; + struct + { + NTSTATUS Status; + ULONG ReturnLength; + PVOID BufferBase; + CHAR Buffer[1]; + } *ret = dataBuffer; + NTSTATUS status2 = STATUS_SUCCESS; + KPH_ATTACH_STATE attachState; + BOOLEAN attached; + + if (inLength < sizeof(*args) || outLength < sizeof(*ret) - sizeof(CHAR)) + { + status = STATUS_BUFFER_TOO_SMALL; + goto IoControlEnd; + } + + status = KphAttachProcessHandle(args->ProcessHandle, &attachState); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + /* Are we attached to the system process? If we are, + * we must set the high bit in the handle to indicate + * that it is a kernel handle - a new check for this + * was added in Windows 7. + */ + if (attachState.Process == PsInitialSystemProcess) + MakeKernelHandle(args->Handle); + + status2 = ZwQueryObject( + args->Handle, + args->ObjectInformationClass, + ret->Buffer, + outLength - (sizeof(*ret) - sizeof(CHAR)), + &retLength + ); + KphDetachProcess(&attachState); + + ret->ReturnLength = retLength; + ret->BufferBase = ret->Buffer; + + if (NT_SUCCESS(status2)) + retLength += sizeof(*ret) - sizeof(CHAR); + else + retLength = sizeof(*ret) - sizeof(CHAR); + + ret->Status = status2; + } + break; + + /* KphGetProcessId + * + * Gets the process ID of a process handle in the context of another process. + */ + case KPH_GETPROCESSID: + { + struct + { + HANDLE ProcessHandle; + HANDLE Handle; + } *args = dataBuffer; + struct + { + HANDLE ProcessId; + } *ret = dataBuffer; + KPH_ATTACH_STATE attachState; + + CHECK_IN_OUT_LENGTH; + + status = KphAttachProcessHandle(args->ProcessHandle, &attachState); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + if (attachState.Process == PsInitialSystemProcess) + MakeKernelHandle(args->Handle); + + ret->ProcessId = KphGetProcessId(args->Handle); + KphDetachProcess(&attachState); + retLength = sizeof(*ret); + } + break; + + /* KphGetThreadId + * + * Gets the thread ID of a thread handle in the context of another process. + */ + case KPH_GETTHREADID: + { + struct + { + HANDLE ProcessHandle; + HANDLE Handle; + } *args = dataBuffer; + struct + { + HANDLE ThreadId; + HANDLE ProcessId; + } *ret = dataBuffer; + KPH_ATTACH_STATE attachState; + + CHECK_IN_OUT_LENGTH; + + status = KphAttachProcessHandle(args->ProcessHandle, &attachState); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + if (attachState.Process == PsInitialSystemProcess) + MakeKernelHandle(args->Handle); + + ret->ThreadId = KphGetThreadId(args->Handle, &ret->ProcessId); + KphDetachProcess(&attachState); + retLength = sizeof(*ret); + } + break; + + /* KphTerminateThread + * + * Terminates the specified thread. This call will fail if + * PspTerminateThreadByPointer could not be located or if an attempt + * was made to terminate the current thread. In that case, the call + * will return STATUS_CANT_TERMINATE_SELF. + */ + case KPH_TERMINATETHREAD: + { + struct + { + HANDLE ThreadHandle; + NTSTATUS ExitStatus; + } *args = dataBuffer; + + CHECK_IN_LENGTH; + + status = KphTerminateThread(args->ThreadHandle, args->ExitStatus); + } + break; + + /* Get Features + * + * Gets the features supported by the driver. + */ + case KPH_GETFEATURES: + { + struct + { + ULONG Features; + } *ret = dataBuffer; + ULONG features = 0; + + CHECK_OUT_LENGTH; + + if (__PsTerminateProcess) + features |= KPHF_PSTERMINATEPROCESS; + if (__PspTerminateThreadByPointer) + features |= KPHF_PSPTERMINATETHREADBPYPOINTER; + + ret->Features = features; + retLength = sizeof(*ret); + } + break; + + /* KphSetHandleGrantedAccess + * + * Sets the granted access for a handle. + */ + case KPH_SETHANDLEGRANTEDACCESS: + { + struct + { + HANDLE Handle; + ACCESS_MASK GrantedAccess; + } *args = dataBuffer; + + CHECK_IN_LENGTH; + + status = KphSetHandleGrantedAccess( + PsGetCurrentProcess(), + args->Handle, + args->GrantedAccess + ); + } + break; + + /* KphAssignImpersonationToken + * + * Assigns an impersonation token to a thread. + */ + case KPH_ASSIGNIMPERSONATIONTOKEN: + { + struct + { + HANDLE ThreadHandle; + HANDLE TokenHandle; + } *args = dataBuffer; + + CHECK_IN_LENGTH; + + status = KphAssignImpersonationToken(args->ThreadHandle, args->TokenHandle); + } + break; + + /* Add Process Protection */ + case KPH_PROTECTADD: + { + struct + { + HANDLE ProcessHandle; + LOGICAL AllowKernelMode; + ACCESS_MASK ProcessAllowMask; + ACCESS_MASK ThreadAllowMask; + } *args = dataBuffer; + PEPROCESS processObject; + + CHECK_IN_LENGTH; + + /* We'll reference the process and then dereference it. That way + * we can get the address of the object - that's all we need. + */ + + status = ObReferenceObjectByHandle( + args->ProcessHandle, + 0, + *PsProcessType, + KernelMode, + &processObject, + NULL + ); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + ObDereferenceObject(processObject); + + InitProtection(); + + /* Don't protect the same process twice. */ + if (KphProtectFindEntry(processObject, NULL, NULL)) + { + status = STATUS_NOT_SUPPORTED; + goto IoControlEnd; + } + + if (!KphProtectAddEntry( + processObject, + PsGetCurrentProcessId(), + args->AllowKernelMode, + args->ProcessAllowMask, + args->ThreadAllowMask + )) + { + status = STATUS_UNSUCCESSFUL; + goto IoControlEnd; + } + } + break; + + /* Remove Process Protection */ + case KPH_PROTECTREMOVE: + { + struct + { + HANDLE ProcessHandle; + } *args = dataBuffer; + PEPROCESS processObject; + + /* Can't remove anything if process protection hasn't been initialized - + there isn't anything to remove. */ + if (!ProtectionInitialized) + { + status = STATUS_INVALID_PARAMETER; + goto IoControlEnd; + } + + CHECK_IN_LENGTH; + + status = ObReferenceObjectByHandle( + args->ProcessHandle, + 0, + *PsProcessType, + KernelMode, + &processObject, + NULL + ); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + ObDereferenceObject(processObject); + + if (!KphProtectRemoveByProcess(processObject)) + { + status = STATUS_UNSUCCESSFUL; + goto IoControlEnd; + } + } + break; + + /* Query Process Protection */ + case KPH_PROTECTQUERY: + { + struct + { + HANDLE ProcessHandle; + PLOGICAL AllowKernelMode; + PACCESS_MASK ProcessAllowMask; + PACCESS_MASK ThreadAllowMask; + } *args = dataBuffer; + PEPROCESS processObject; + KPH_PROCESS_ENTRY processEntry; + + /* Can't query anything if process protection hasn't been initialized - + there isn't anything to query. */ + if (!ProtectionInitialized) + { + status = STATUS_INVALID_PARAMETER; + goto IoControlEnd; + } + + CHECK_IN_LENGTH; + + __try + { + ProbeForWrite(args->AllowKernelMode, sizeof(LOGICAL), 1); + ProbeForWrite(args->ProcessAllowMask, sizeof(ACCESS_MASK), 1); + ProbeForWrite(args->ThreadAllowMask, sizeof(ACCESS_MASK), 1); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + goto IoControlEnd; + } + + status = ObReferenceObjectByHandle( + args->ProcessHandle, + 0, + *PsProcessType, + KernelMode, + &processObject, + NULL + ); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + ObDereferenceObject(processObject); + + if (!KphProtectFindEntry(processObject, NULL, &processEntry)) + { + status = STATUS_UNSUCCESSFUL; + goto IoControlEnd; + } + + __try + { + *(args->AllowKernelMode) = processEntry.AllowKernelMode; + *(args->ProcessAllowMask) = processEntry.ProcessAllowMask; + *(args->ThreadAllowMask) = processEntry.ThreadAllowMask; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + } + break; + + /* KphUnsafeReadVirtualMemory + * + * Reads process memory or kernel memory. + */ + case KPH_UNSAFEREADVIRTUALMEMORY: + { + struct + { + HANDLE ProcessHandle; + PVOID BaseAddress; + PVOID Buffer; + ULONG BufferLength; + PULONG ReturnLength; + } *args = dataBuffer; + + CHECK_IN_LENGTH; + + status = KphUnsafeReadVirtualMemory( + args->ProcessHandle, + args->BaseAddress, + args->Buffer, + args->BufferLength, + args->ReturnLength, + UserMode + ); + } + break; + + /* Set Execute Options + * + * Sets NX status for a process. + */ + case KPH_SETEXECUTEOPTIONS: + { + struct + { + HANDLE ProcessHandle; + ULONG ExecuteOptions; + } *args = dataBuffer; + KPH_ATTACH_STATE attachState; + + CHECK_IN_LENGTH; + + status = KphAttachProcessHandle(args->ProcessHandle, &attachState); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + status = ZwSetInformationProcess( + NtCurrentProcess(), + ProcessExecuteFlags, + &args->ExecuteOptions, + sizeof(ULONG) + ); + KphDetachProcess(&attachState); + } + break; + + /* KphQueryProcessHandles + * + * Gets the handles in a process handle table. + */ + case KPH_QUERYPROCESSHANDLES: + { + struct + { + HANDLE ProcessHandle; + PVOID Buffer; + ULONG BufferLength; + PULONG ReturnLength; + } *args = dataBuffer; + + CHECK_IN_LENGTH; + + status = KphQueryProcessHandles( + args->ProcessHandle, + (PPROCESS_HANDLE_INFORMATION)args->Buffer, + args->BufferLength, + args->ReturnLength, + UserMode + ); + } + break; + + /* KphOpenThreadProcess + * + * Opens the process associated with the specified thread. + */ + case KPH_OPENTHREADPROCESS: + { + struct + { + HANDLE ThreadHandle; + ACCESS_MASK DesiredAccess; + } *args = dataBuffer; + struct + { + HANDLE ProcessHandle; + } *ret = dataBuffer; + + CHECK_IN_OUT_LENGTH; + + status = KphOpenThreadProcess( + args->ThreadHandle, + args->DesiredAccess, + &ret->ProcessHandle, + KernelMode + ); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + retLength = sizeof(*ret); + } + break; + + /* KphCaptureStackBackTraceThread + * + * Captures a kernel stack trace for the specified thread. + */ + case KPH_CAPTURESTACKBACKTRACETHREAD: + { + struct + { + HANDLE ThreadHandle; + ULONG FramesToSkip; + ULONG FramesToCapture; + PVOID *BackTrace; + PULONG CapturedFrames; + PULONG BackTraceHash; + } *args = dataBuffer; + + CHECK_IN_LENGTH; + + status = KphCaptureStackBackTraceThread( + args->ThreadHandle, + args->FramesToSkip, + args->FramesToCapture, + args->BackTrace, + args->CapturedFrames, + args->BackTraceHash, + UserMode + ); + } + break; + + /* KphDangerousTerminateThread + * + * Terminates the specified thread. This operation may cause a bugcheck. + */ + case KPH_DANGEROUSTERMINATETHREAD: + { + struct + { + HANDLE ThreadHandle; + NTSTATUS ExitStatus; + } *args = dataBuffer; + + CHECK_IN_LENGTH; + + status = KphDangerousTerminateThread(args->ThreadHandle, args->ExitStatus); + } + break; + + /* KphOpenDevice + * + * Opens a device object. + */ + case KPH_OPENDEVICE: + { + struct + { + PHANDLE DeviceHandle; + POBJECT_ATTRIBUTES ObjectAttributes; + } *args = dataBuffer; + + CHECK_IN_LENGTH; + + status = KphOpenDevice(args->DeviceHandle, args->ObjectAttributes, UserMode); + } + break; + + /* KphOpenDriver + * + * Opens a driver object. + */ + case KPH_OPENDRIVER: + { + struct + { + PHANDLE DriverHandle; + POBJECT_ATTRIBUTES ObjectAttributes; + } *args = dataBuffer; + + CHECK_IN_LENGTH; + + status = KphOpenDriver(args->DriverHandle, args->ObjectAttributes, UserMode); + } + break; + + /* KphQueryInformationDriver + * + * Queries information about a driver object. + */ + case KPH_QUERYINFORMATIONDRIVER: + { + struct + { + HANDLE DriverHandle; + DRIVER_INFORMATION_CLASS DriverInformationClass; + PVOID DriverInformation; + ULONG DriverInformationLength; + PULONG ReturnLength; + } *args = dataBuffer; + + CHECK_IN_LENGTH; + + status = KphQueryInformationDriver( + args->DriverHandle, + args->DriverInformationClass, + args->DriverInformation, + args->DriverInformationLength, + args->ReturnLength, + UserMode + ); + } + break; + + /* KphOpenDirectoryObject + * + * Opens a directory object. + */ + case KPH_OPENDIRECTORYOBJECT: + { + struct + { + PHANDLE DirectoryObjectHandle; + ACCESS_MASK DesiredAccess; + POBJECT_ATTRIBUTES ObjectAttributes; + } *args = dataBuffer; + + CHECK_IN_LENGTH; + + status = KphOpenDirectoryObject( + args->DirectoryObjectHandle, + args->DesiredAccess, + args->ObjectAttributes, + UserMode + ); + } + break; + + /* SsRef + * + * Adds a system service logging reference. + */ + case KPH_SSREF: + { + PKPH_CLIENT_ENTRY clientEntry = ReferenceClientEntry(NULL); + + if (!clientEntry) + { + status = STATUS_INTERNAL_ERROR; + goto IoControlEnd; + } + + KphAcquireGuardedLock(&clientEntry->SsLock); + + if (clientEntry->SsStartCount < KPH_CLIENT_SSMAXCOUNT) + { + clientEntry->SsStartCount++; + SsRef(1); + } + else + { + status = STATUS_UNSUCCESSFUL; + } + + KphReleaseGuardedLock(&clientEntry->SsLock); + + KphDereferenceObject(clientEntry); + } + break; + + /* SsUnref + * + * Removes a system service logging reference. + */ + case KPH_SSUNREF: + { + PKPH_CLIENT_ENTRY clientEntry = ReferenceClientEntry(NULL); + + if (!clientEntry) + { + status = STATUS_INTERNAL_ERROR; + goto IoControlEnd; + } + + KphAcquireGuardedLock(&clientEntry->SsLock); + + if (clientEntry->SsStartCount > 0) + { + clientEntry->SsStartCount--; + SsUnref(1); + } + else + { + status = STATUS_UNSUCCESSFUL; + } + + KphReleaseGuardedLock(&clientEntry->SsLock); + + KphDereferenceObject(clientEntry); + } + break; + + /* SsCreateClientEntry + * + * Creates a system service logging client entry. + */ + case KPH_SSCREATECLIENTENTRY: + { + struct + { + HANDLE ProcessHandle; + HANDLE EventHandle; + HANDLE SemaphoreHandle; + PVOID BufferBase; + ULONG BufferSize; + } *args = dataBuffer; + struct + { + HANDLE ClientEntryHandle; + } *ret = dataBuffer; + PKPHSS_CLIENT_ENTRY clientEntry; + + CHECK_IN_OUT_LENGTH; + + status = KphSsCreateClientEntry( + &clientEntry, + args->ProcessHandle, + args->EventHandle, + args->SemaphoreHandle, + args->BufferBase, + args->BufferSize, + UserMode + ); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + status = CreateClientHandle(NULL, clientEntry, &ret->ClientEntryHandle); + KphDereferenceObject(clientEntry); + retLength = sizeof(*ret); + } + break; + + /* SsCreateRuleSetEntry + * + * Creates a system service logging ruleset entry. + */ + case KPH_SSCREATERULESETENTRY: + { + struct + { + HANDLE ClientEntryHandle; + KPHSS_FILTER_TYPE DefaultFilterType; + KPHSS_RULESET_ACTION Action; + } *args = dataBuffer; + struct + { + HANDLE RuleSetEntryHandle; + } *ret = dataBuffer; + PKPHSS_CLIENT_ENTRY clientEntry; + PKPHSS_RULESET_ENTRY ruleSetEntry; + + CHECK_IN_OUT_LENGTH; + + /* Reference the client entry. */ + status = ReferenceClientHandle( + NULL, + args->ClientEntryHandle, + KphSsClientEntryType, + &clientEntry + ); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + /* Create the ruleset entry. */ + status = KphSsCreateRuleSetEntry( + &ruleSetEntry, + clientEntry, + args->DefaultFilterType, + args->Action + ); + KphDereferenceObject(clientEntry); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + /* Create and return a handle to the ruleset entry. */ + status = CreateClientHandle(NULL, ruleSetEntry, &ret->RuleSetEntryHandle); + KphDereferenceObject(ruleSetEntry); + retLength = sizeof(*ret); + } + break; + + /* SsRemoveRule + * + * Removes a rule from a ruleset. + */ + case KPH_SSREMOVERULE: + { + struct + { + HANDLE RuleSetEntryHandle; + HANDLE RuleEntryHandle; + } *args = dataBuffer; + PKPHSS_RULESET_ENTRY ruleSetEntry; + + CHECK_IN_LENGTH; + + /* Reference the ruleset entry. */ + status = ReferenceClientHandle( + NULL, + args->RuleSetEntryHandle, + KphSsRuleSetEntryType, + &ruleSetEntry + ); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + /* Remove the rule. */ + status = KphSsRemoveRule(ruleSetEntry, args->RuleEntryHandle); + KphDereferenceObject(ruleSetEntry); + } + break; + + /* SsAddProcessIdRule + * + * Adds a process ID rule to a ruleset. + */ + case KPH_SSADDPROCESSIDRULE: + { + struct + { + HANDLE RuleSetEntryHandle; + KPHSS_FILTER_TYPE FilterType; + HANDLE ProcessId; + } *args = dataBuffer; + struct + { + HANDLE RuleEntryHandle; + } *ret = dataBuffer; + PKPHSS_RULESET_ENTRY ruleSetEntry; + PKPHSS_RULE_ENTRY ruleEntry; + + CHECK_IN_OUT_LENGTH; + + /* Reference the client entry. */ + status = ReferenceClientHandle( + NULL, + args->RuleSetEntryHandle, + KphSsRuleSetEntryType, + &ruleSetEntry + ); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + /* Add a process ID rule. */ + status = KphSsAddProcessIdRule( + &ruleEntry, + ruleSetEntry, + args->FilterType, + args->ProcessId + ); + KphDereferenceObject(ruleSetEntry); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + /* Return the rule handle. */ + ret->RuleEntryHandle = KphSsGetHandleRule(ruleEntry); + KphDereferenceObject(ruleEntry); + retLength = sizeof(*ret); + } + break; + + /* SsAddThreadIdRule + * + * Adds a thread ID rule to a ruleset. + */ + case KPH_SSADDTHREADIDRULE: + { + struct + { + HANDLE RuleSetEntryHandle; + KPHSS_FILTER_TYPE FilterType; + HANDLE ThreadId; + } *args = dataBuffer; + struct + { + HANDLE RuleEntryHandle; + } *ret = dataBuffer; + PKPHSS_RULESET_ENTRY ruleSetEntry; + PKPHSS_RULE_ENTRY ruleEntry; + + CHECK_IN_OUT_LENGTH; + + /* Reference the client entry. */ + status = ReferenceClientHandle( + NULL, + args->RuleSetEntryHandle, + KphSsRuleSetEntryType, + &ruleSetEntry + ); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + /* Add a thread ID rule. */ + status = KphSsAddThreadIdRule( + &ruleEntry, + ruleSetEntry, + args->FilterType, + args->ThreadId + ); + KphDereferenceObject(ruleSetEntry); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + /* Return the rule handle. */ + ret->RuleEntryHandle = KphSsGetHandleRule(ruleEntry); + KphDereferenceObject(ruleEntry); + retLength = sizeof(*ret); + } + break; + + /* SsAddPreviousModeRule + * + * Adds a previous mode rule to a ruleset. + */ + case KPH_SSADDPREVIOUSMODERULE: + { + struct + { + HANDLE RuleSetEntryHandle; + KPHSS_FILTER_TYPE FilterType; + KPROCESSOR_MODE PreviousMode; + } *args = dataBuffer; + struct + { + HANDLE RuleEntryHandle; + } *ret = dataBuffer; + PKPHSS_RULESET_ENTRY ruleSetEntry; + PKPHSS_RULE_ENTRY ruleEntry; + + CHECK_IN_OUT_LENGTH; + + /* Reference the client entry. */ + status = ReferenceClientHandle( + NULL, + args->RuleSetEntryHandle, + KphSsRuleSetEntryType, + &ruleSetEntry + ); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + /* Add a previous mode rule. */ + status = KphSsAddPreviousModeRule( + &ruleEntry, + ruleSetEntry, + args->FilterType, + args->PreviousMode + ); + KphDereferenceObject(ruleSetEntry); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + /* Return the rule handle. */ + ret->RuleEntryHandle = KphSsGetHandleRule(ruleEntry); + KphDereferenceObject(ruleEntry); + retLength = sizeof(*ret); + } + break; + + /* SsAddNumberRule + * + * Adds a system service number rule to a ruleset. + */ + case KPH_SSADDNUMBERRULE: + { + struct + { + HANDLE RuleSetEntryHandle; + KPHSS_FILTER_TYPE FilterType; + ULONG Number; + } *args = dataBuffer; + struct + { + HANDLE RuleEntryHandle; + } *ret = dataBuffer; + PKPHSS_RULESET_ENTRY ruleSetEntry; + PKPHSS_RULE_ENTRY ruleEntry; + + CHECK_IN_OUT_LENGTH; + + /* Reference the client entry. */ + status = ReferenceClientHandle( + NULL, + args->RuleSetEntryHandle, + KphSsRuleSetEntryType, + &ruleSetEntry + ); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + /* Add a number rule. */ + status = KphSsAddNumberRule( + &ruleEntry, + ruleSetEntry, + args->FilterType, + args->Number + ); + KphDereferenceObject(ruleSetEntry); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + /* Return the rule handle. */ + ret->RuleEntryHandle = KphSsGetHandleRule(ruleEntry); + KphDereferenceObject(ruleEntry); + retLength = sizeof(*ret); + } + break; + + /* SsEnableClientEntry + * + * Enables or disables a client entry. + */ + case KPH_SSENABLECLIENTENTRY: + { + struct + { + HANDLE ClientEntryHandle; + BOOLEAN Enable; + } *args = dataBuffer; + PKPHSS_CLIENT_ENTRY clientEntry; + + CHECK_IN_LENGTH; + + /* Reference the client entry. */ + status = ReferenceClientHandle( + NULL, + args->ClientEntryHandle, + KphSsClientEntryType, + &clientEntry + ); + + if (!NT_SUCCESS(status)) + goto IoControlEnd; + + /* Enable/disable the client entry. */ + status = KphSsEnableClientEntry(clientEntry, args->Enable); + KphDereferenceObject(clientEntry); + } + break; + + default: + { + dprintf("Unrecognized IOCTL code 0x%08x\n", controlCode); + status = STATUS_INVALID_DEVICE_REQUEST; + } + break; + } + + /* Restore the old packing. */ + #include + +IoControlEnd: + Irp->IoStatus.Information = retLength; + Irp->IoStatus.Status = status; + dprintf("IOCTL 0x%08x result was 0x%08x\n", controlCode, status); + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return status; +} + +NTSTATUS KphDispatchRead(PDEVICE_OBJECT DeviceObject, PIRP Irp) +{ + NTSTATUS status = STATUS_SUCCESS; + PIO_STACK_LOCATION ioStackIrp = NULL; + ULONG retLength = 0; + + ioStackIrp = IoGetCurrentIrpStackLocation(Irp); + + if (ioStackIrp != NULL) + { + PCHAR readDataBuffer = (PCHAR)Irp->AssociatedIrp.SystemBuffer; + ULONG readLength = ioStackIrp->Parameters.Read.Length; + + if (readDataBuffer != NULL) + { + dprintf("Client read %d bytes!\n", readLength); + + if (readLength == 4) + { + *(ULONG *)readDataBuffer = KPH_CTL_CODE(0); + retLength = 4; + } + else + { + status = STATUS_INFO_LENGTH_MISMATCH; + } + } + } + + Irp->IoStatus.Information = retLength; + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + return status; +} + +NTSTATUS KphUnsupported(PDEVICE_OBJECT DeviceObject, PIRP Irp) +{ + dfprintf("Unsupported function called.\n"); + + return STATUS_NOT_SUPPORTED; +} diff --git a/branches/ph-plugins/KProcessHacker/makefile b/branches/ph-plugins/KProcessHacker/makefile new file mode 100644 index 000000000..05a507be4 --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/makefile @@ -0,0 +1 @@ +!INCLUDE $(NTMAKEENV)\makefile.def \ No newline at end of file diff --git a/branches/ph-plugins/KProcessHacker/mm.c b/branches/ph-plugins/KProcessHacker/mm.c new file mode 100644 index 000000000..84492ab34 --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/mm.c @@ -0,0 +1,703 @@ +/* + * Process Hacker Driver - + * memory manager + * + * Copyright (C) 2009 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/kph.h" +#include "include/mm.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, KphReadVirtualMemory) +#pragma alloc_text(PAGE, KphUnsafeReadVirtualMemory) +#pragma alloc_text(PAGE, KphWriteVirtualMemory) +#pragma alloc_text(PAGE, MiDoMappedCopy) +#pragma alloc_text(PAGE, MiDoPoolCopy) +#pragma alloc_text(PAGE, MiGetExceptionInfo) +#pragma alloc_text(PAGE, MmCopyVirtualMemory) +#endif + +/* KphReadVirtualMemory + * + * Reads virtual memory from the specified process. + */ +NTSTATUS KphReadVirtualMemory( + __in HANDLE ProcessHandle, + __in PVOID BaseAddress, + __out_bcount(BufferLength) PVOID Buffer, + __in ULONG BufferLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PEPROCESS processObject; + ULONG returnLength = 0; + + /* Probe user input if we're not from kernel-mode. */ + if (AccessMode != KernelMode) + { + if ((((ULONG_PTR)BaseAddress + BufferLength) < (ULONG_PTR)BaseAddress) || + (((ULONG_PTR)Buffer + BufferLength) < (ULONG_PTR)Buffer) || + (((ULONG_PTR)BaseAddress + BufferLength) > (ULONG_PTR)MmHighestUserAddress) || + (((ULONG_PTR)Buffer + BufferLength) > (ULONG_PTR)MmHighestUserAddress)) + { + return STATUS_ACCESS_VIOLATION; + } + + __try + { + if (ReturnLength) + ProbeForWrite(ReturnLength, sizeof(ULONG), 1); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return STATUS_ACCESS_VIOLATION; + } + } + + /* If we actually have work to do, reference the process object and + call the internal function. */ + if (BufferLength) + { + status = ObReferenceObjectByHandle( + ProcessHandle, + PROCESS_VM_READ, + *PsProcessType, + KernelMode, + &processObject, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + status = MmCopyVirtualMemory( + processObject, + BaseAddress, + PsGetCurrentProcess(), + Buffer, + BufferLength, + AccessMode, + &returnLength + ); + ObDereferenceObject(processObject); + } + + if (ReturnLength) + { + __try + { + *ReturnLength = returnLength; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + } + + return status; +} + +NTSTATUS KphUnsafeReadVirtualMemory( + __in HANDLE ProcessHandle, + __in PVOID BaseAddress, + __out_bcount(BufferLength) PVOID Buffer, + __in ULONG BufferLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG returnLength = 0; + + /* Initial probing. */ + if (AccessMode != KernelMode) + { + if ((((ULONG_PTR)BaseAddress + BufferLength) < (ULONG_PTR)BaseAddress) || + (((ULONG_PTR)Buffer + BufferLength) < (ULONG_PTR)Buffer) || + (((ULONG_PTR)Buffer + BufferLength) > (ULONG_PTR)MmHighestUserAddress)) + { + return STATUS_ACCESS_VIOLATION; + } + + __try + { + ProbeForWrite(Buffer, BufferLength, 1); + + if (ReturnLength) + ProbeForWrite(ReturnLength, sizeof(ULONG), 1); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + + /* Make sure we have something to copy. */ + if (BufferLength == 0) + { + __try + { + *ReturnLength = 0; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + + return STATUS_SUCCESS; + } + + /* Select the appropriate copy method. */ + if (((ULONG_PTR)BaseAddress + BufferLength) > (ULONG_PTR)MmHighestUserAddress) + { + /* Kernel memory unsafe copy. */ + + __try + { + /* Probe the address range. */ + KphProbeSystemAddressRange(BaseAddress, BufferLength); + + /* Copy the data. */ + memcpy(Buffer, BaseAddress, BufferLength); + returnLength = BufferLength; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + + if (ReturnLength) + { + __try + { + *ReturnLength = returnLength; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + } + } + else + { + /* User memory safe copy. */ + status = KphReadVirtualMemory( + ProcessHandle, + BaseAddress, + Buffer, + BufferLength, + ReturnLength, + AccessMode + ); + } + + return status; +} + +/* KphWriteVirtualMemory + * + * Writes virtual memory to the specified process. + */ +NTSTATUS KphWriteVirtualMemory( + __in HANDLE ProcessHandle, + __in PVOID BaseAddress, + __in_bcount(BufferLength) PVOID Buffer, + __in ULONG BufferLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PEPROCESS processObject; + ULONG returnLength = 0; + + /* Probe user input if we're not from kernel-mode. */ + if (AccessMode != KernelMode) + { + if ((((ULONG_PTR)BaseAddress + BufferLength) < (ULONG_PTR)BaseAddress) || + (((ULONG_PTR)Buffer + BufferLength) < (ULONG_PTR)Buffer) || + (((ULONG_PTR)BaseAddress + BufferLength) > (ULONG_PTR)MmHighestUserAddress) || + (((ULONG_PTR)Buffer + BufferLength) > (ULONG_PTR)MmHighestUserAddress)) + { + return STATUS_ACCESS_VIOLATION; + } + + __try + { + if (ReturnLength) + ProbeForWrite(ReturnLength, sizeof(ULONG), 1); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return STATUS_ACCESS_VIOLATION; + } + } + + /* If we actually have work to do, reference the process object and + call the internal function. */ + if (BufferLength) + { + status = ObReferenceObjectByHandle( + ProcessHandle, + PROCESS_VM_WRITE, + *PsProcessType, + KernelMode, + &processObject, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + status = MmCopyVirtualMemory( + PsGetCurrentProcess(), + Buffer, + processObject, + BaseAddress, + BufferLength, + AccessMode, + &returnLength + ); + ObDereferenceObject(processObject); + } + + if (ReturnLength) + { + __try + { + *ReturnLength = returnLength; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + } + + return status; +} + +/* MiDoMappedCopy + * + * Copies virtual memory from the source process to the target process + * using a memory mapping. + */ +NTSTATUS MiDoMappedCopy( + __in PEPROCESS FromProcess, + __in PVOID FromAddress, + __in PEPROCESS ToProcess, + __in PVOID ToAddress, + __in ULONG BufferLength, + __in KPROCESSOR_MODE AccessMode, + __out PULONG ReturnLength + ) +{ + PFN_NUMBER mdlBuffer[(sizeof(MDL) / sizeof(PFN_NUMBER)) + MI_MAPPED_COPY_PAGES + 1]; + PMDL mdl = (PMDL)mdlBuffer; + /* The mapped address. */ + PVOID mappedAddress; + /* The total size allocated (mapped pages). */ + ULONG totalSize; + /* The block size. */ + ULONG blockSize; + /* The amount still left to copy. */ + ULONG stillToCopy; + /* Attach state. */ + KPH_ATTACH_STATE attachState; + /* The current source address. */ + PVOID sourceAddress; + /* The current target address. */ + PVOID targetAddress; + /* Whether the pages have been locked. */ + BOOLEAN pagesLocked; + /* Whether we are currently copying. */ + BOOLEAN copying = FALSE; + /* Whether we are currently probing. */ + BOOLEAN probing = FALSE; + /* Whether we are currently mapping. */ + BOOLEAN mapping = FALSE; + /* Whether we have the bad address. */ + BOOLEAN haveBadAddress; + /* The bad address of the exception. */ + ULONG_PTR badAddress; + + sourceAddress = FromAddress; + targetAddress = ToAddress; + + totalSize = (MI_MAPPED_COPY_PAGES - 2) * PAGE_SIZE; + + if (BufferLength <= totalSize) + totalSize = BufferLength; + + stillToCopy = BufferLength; + blockSize = totalSize; + + while (stillToCopy) + { + /* If we're at the last copy block, copy the remaining bytes instead + of the whole block size. */ + if (stillToCopy < blockSize) + blockSize = stillToCopy; + + /* Reset state. */ + mappedAddress = NULL; + pagesLocked = FALSE; + copying = FALSE; + + KphAttachProcess(FromProcess, &attachState); + + __try + { + /* Probe only if this is the first time. */ + if ((sourceAddress == FromAddress) && (AccessMode != KernelMode)) + { + probing = TRUE; + ProbeForRead(sourceAddress, BufferLength, 1); + probing = FALSE; + } + + /* 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); + } + + KphDetachProcess(&attachState); + + /* Attach to the target process and copy the mapped contents. */ + KphAttachProcess(ToProcess, &attachState); + + /* Probe only if this is the first time. */ + if ((targetAddress == ToAddress) && (AccessMode != KernelMode)) + { + probing = TRUE; + ProbeForWrite(targetAddress, BufferLength, 1); + probing = FALSE; + } + + /* Copy the data. */ + copying = TRUE; + memcpy(targetAddress, mappedAddress, blockSize); + } + __except (MiGetExceptionInfo( + GetExceptionInformation(), + &haveBadAddress, + &badAddress + )) + { + KphDetachProcess(&attachState); + + /* 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 failed when probing or mapping, return the error code. */ + if (probing || mapping) + return GetExceptionCode(); + + /* Otherwise, give the caller the number of bytes we copied. */ + *ReturnLength = BufferLength - stillToCopy; + + /* If we were copying, we can probably get the exact + number of bytes copied. */ + if (copying && haveBadAddress) + *ReturnLength = (ULONG)(badAddress - (ULONG_PTR)sourceAddress); + + return STATUS_PARTIAL_COPY; + } + + KphDetachProcess(&attachState); + MmUnmapLockedPages(mappedAddress, mdl); + MmUnlockPages(mdl); + + stillToCopy -= blockSize; + sourceAddress = (PVOID)((ULONG_PTR)sourceAddress + blockSize); + targetAddress = (PVOID)((ULONG_PTR)targetAddress + blockSize); + } + + *ReturnLength = BufferLength; + + return STATUS_SUCCESS; +} + +/* MiDoPoolCopy + * + * Copies virtual memory from the source process to the target process + * using either a pool allocation or a stack buffer. + */ +NTSTATUS MiDoPoolCopy( + __in PEPROCESS FromProcess, + __in PVOID FromAddress, + __in PEPROCESS ToProcess, + __in PVOID ToAddress, + __in ULONG BufferLength, + __in KPROCESSOR_MODE AccessMode, + __out PULONG ReturnLength + ) +{ + /* The size of the pool-allocated buffer. */ + ULONG allocSize = MI_MAX_TRANSFER_SIZE; + /* The stack-based buffer. */ + CHAR stackBuffer[MI_COPY_STACK_SIZE]; + /* The buffer - could be from the pool or could be the stack buffer. */ + PVOID buffer = NULL; + /* The block size - should be the same as the allocated size. */ + ULONG blockSize; + /* The amount still left to copy. */ + ULONG stillToCopy; + /* Attach state. */ + KPH_ATTACH_STATE attachState; + /* The current source address. */ + PVOID sourceAddress; + /* The current target address. */ + PVOID targetAddress; + /* Whether we are currently copying. */ + BOOLEAN copying = FALSE; + /* Whether we are currently probing. */ + BOOLEAN probing = FALSE; + /* Whether we have the bad address. */ + BOOLEAN haveBadAddress; + /* The bad address of the exception. */ + ULONG_PTR badAddress; + + sourceAddress = FromAddress; + targetAddress = ToAddress; + + /* Don't allocate a buffer larger than the amount we're about to copy. */ + if (allocSize > BufferLength) + allocSize = BufferLength; + + /* If we're copying MI_COPY_STACK_SIZE bytes or less, use the stack buffer. */ + if (BufferLength <= MI_COPY_STACK_SIZE) + { + buffer = stackBuffer; + } + else + { + /* Keep on trying to allocate a buffer, halving the size each time + we fail. */ + while (TRUE) + { + buffer = ExAllocatePoolWithTag(NonPagedPool, allocSize, TAG_POOL_COPY); + + /* Stop trying if we got a buffer. */ + if (buffer) + break; + + /* Otherwise, halve the size and try again. */ + allocSize /= 2; + /* Could we use the stack buffer? */ + if (allocSize <= MI_COPY_STACK_SIZE) + { + buffer = stackBuffer; + break; + } + } + } + + stillToCopy = BufferLength; + blockSize = allocSize; + + /* Perform the copy in blocks of blockSize. */ + while (stillToCopy) + { + /* If we're at the last copy block, copy the remaining bytes instead + of the whole block size. */ + if (stillToCopy < blockSize) + blockSize = stillToCopy; + + copying = FALSE; + KphAttachProcess(FromProcess, &attachState); + + __try + { + /* Probe before reading the source contents. */ + /* Probe only if this is the first time. */ + if ((sourceAddress == FromAddress) && (AccessMode != KernelMode)) + { + probing = TRUE; + ProbeForRead(sourceAddress, BufferLength, 1); + probing = FALSE; + } + + /* Copy the source contents to the buffer. */ + memcpy(buffer, sourceAddress, blockSize); + KphDetachProcess(&attachState); + + /* Probe before writing. */ + KphAttachProcess(ToProcess, &attachState); + + /* Probe only if this is the first time. */ + if ((targetAddress == ToAddress) && (AccessMode != KernelMode)) + { + probing = TRUE; + ProbeForWrite(targetAddress, BufferLength, 1); + probing = FALSE; + } + + /* Copy the buffer contents to the destination. */ + copying = TRUE; + memcpy(targetAddress, buffer, blockSize); + } + __except (MiGetExceptionInfo( + GetExceptionInformation(), + &haveBadAddress, + &badAddress + )) + { + KphDetachProcess(&attachState); + + /* Free the allocated buffer if needed. */ + if (buffer != stackBuffer) + ExFreePoolWithTag(buffer, TAG_POOL_COPY); + + /* If we were probing an address, return the error code. */ + if (probing) + return GetExceptionCode(); + + /* Otherwise, give the caller the number of bytes we copied. */ + *ReturnLength = BufferLength - stillToCopy; + + /* If we were copying, we can probably get the exact + number of bytes copied. */ + if (copying && haveBadAddress) + *ReturnLength = (ULONG)(badAddress - (ULONG_PTR)sourceAddress); + + return STATUS_PARTIAL_COPY; + } + + KphDetachProcess(&attachState); + + stillToCopy -= blockSize; + sourceAddress = (PVOID)((ULONG_PTR)sourceAddress + blockSize); + targetAddress = (PVOID)((ULONG_PTR)targetAddress + blockSize); + } + + /* Free the buffer if it wasn't stack-allocated. */ + if (buffer != stackBuffer) + ExFreePoolWithTag(buffer, TAG_POOL_COPY); + + *ReturnLength = BufferLength; + + return STATUS_SUCCESS; +} + +ULONG MiGetExceptionInfo( + __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; +} + +NTSTATUS MmCopyVirtualMemory( + __in PEPROCESS FromProcess, + __in PVOID FromAddress, + __in PEPROCESS ToProcess, + __in PVOID ToAddress, + __in ULONG BufferLength, + __in KPROCESSOR_MODE AccessMode, + __out PULONG ReturnLength + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PEPROCESS processToLock = FromProcess; + + if (!BufferLength) + return STATUS_SUCCESS; + + /* If we're copying from the current process, lock the target. */ + if (processToLock == PsGetCurrentProcess()) + processToLock = ToProcess; + + /* Prevent the process from terminating. */ + if (!KphAcquireProcessRundownProtection(processToLock)) + return STATUS_PROCESS_IS_TERMINATING; + + /* If the amount we're trying to copy is over the threshold + for MiDoPoolCopy, use MiDoMappedCopy. */ + if (BufferLength > MM_POOL_COPY_THRESHOLD) + { + status = MiDoMappedCopy( + FromProcess, + FromAddress, + ToProcess, + ToAddress, + BufferLength, + AccessMode, + ReturnLength + ); + } + else + { + status = MiDoPoolCopy( + FromProcess, + FromAddress, + ToProcess, + ToAddress, + BufferLength, + AccessMode, + ReturnLength + ); + } + + /* Allow the process to terminate. */ + KphReleaseProcessRundownProtection(processToLock); + + return status; +} diff --git a/branches/ph-plugins/KProcessHacker/ob.c b/branches/ph-plugins/KProcessHacker/ob.c new file mode 100644 index 000000000..21255b0e8 --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/ob.c @@ -0,0 +1,847 @@ +/* + * Process Hacker Driver - + * object manager + * + * Copyright (C) 2009 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/kph.h" +#include "include/ob.h" + +BOOLEAN KphpQueryProcessHandlesEnumCallback( + __inout PHANDLE_TABLE_ENTRY HandleTableEntry, + __in HANDLE Handle, + __in POBP_QUERY_PROCESS_HANDLES_DATA Context + ); + +BOOLEAN KphpSetHandleGrantedAccessEnumCallback( + __inout PHANDLE_TABLE_ENTRY HandleTableEntry, + __in HANDLE Handle, + __in POBP_SET_HANDLE_GRANTED_ACCESS_DATA Context + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, KphDuplicateObject) +#pragma alloc_text(PAGE, ObDuplicateObject) +#endif + +/* This attribute is now stored in the GrantedAccess field. */ +ULONG ObpAccessProtectCloseBit = 0x80000000; + +/* KphDuplicateObject + * + * Duplicates a handle from the source process to the target process. + */ +NTSTATUS KphDuplicateObject( + __in HANDLE SourceProcessHandle, + __in HANDLE SourceHandle, + __in_opt HANDLE TargetProcessHandle, + __out_opt PHANDLE TargetHandle, + __in ACCESS_MASK DesiredAccess, + __in ULONG HandleAttributes, + __in ULONG Options, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PEPROCESS sourceProcess = NULL; + PEPROCESS targetProcess = NULL; + HANDLE targetHandle; + + if (TargetHandle && AccessMode != KernelMode) + { + __try + { + ProbeForWrite(TargetHandle, sizeof(HANDLE), 1); + *TargetHandle = NULL; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return STATUS_ACCESS_VIOLATION; + } + } + + status = ObReferenceObjectByHandle( + SourceProcessHandle, + PROCESS_DUP_HANDLE, + *PsProcessType, + KernelMode, + &sourceProcess, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + /* Target handle is optional. */ + if (TargetProcessHandle) + { + status = ObReferenceObjectByHandle( + TargetProcessHandle, + PROCESS_DUP_HANDLE, + *PsProcessType, + KernelMode, + &targetProcess, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + } + + /* Fix the source handle if the source process is + * the system process. + */ + if (sourceProcess == PsInitialSystemProcess) + MakeKernelHandle(SourceHandle); + + /* Call the internal function. */ + status = ObDuplicateObject( + sourceProcess, + targetProcess, + SourceHandle, + &targetHandle, + DesiredAccess, + HandleAttributes, + Options, + AccessMode + ); + + if (TargetHandle) + { + __try + { + *TargetHandle = targetHandle; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = STATUS_ACCESS_VIOLATION; + } + } + + ObDereferenceObject(sourceProcess); + if (targetProcess) + ObDereferenceObject(targetProcess); + + return status; +} + +/* KphEnumProcessHandleTable + * + * Enumerates the handles in the specified process' handle table. + */ +BOOLEAN KphEnumProcessHandleTable( + __in PEPROCESS Process, + __in PEX_ENUM_HANDLE_CALLBACK EnumHandleProcedure, + __inout PVOID Context, + __out_opt PHANDLE Handle + ) +{ + BOOLEAN result = FALSE; + PHANDLE_TABLE handleTable = NULL; + + handleTable = ObReferenceProcessHandleTable(Process); + + if (!handleTable) + return FALSE; + + result = ExEnumHandleTable( + handleTable, + EnumHandleProcedure, + Context, + Handle + ); + ObDereferenceProcessHandleTable(Process); + + return result; +} + +/* KphGetObjectTypeNt + * + * Gets the type of an object. + */ +POBJECT_TYPE KphGetObjectTypeNt( + __in PVOID Object + ) +{ + /* XP to Vista: A pointer to the object type is + * stored in the object header. + */ + if ( + WindowsVersion >= WINDOWS_XP && + WindowsVersion <= WINDOWS_VISTA + ) + { + return OBJECT_TO_OBJECT_HEADER(Object)->Type; + } + /* Seven and above: An index to an internal object type + * table is stored in the object header. Luckily we have + * a new exported function, ObGetObjectType, to get + * the object type. + */ + else if (WindowsVersion >= WINDOWS_7) + { + return ObGetObjectType(Object); + } + else + { + return NULL; + } +} + +/* KphOpenDirectoryObject + * + * Opens a directory object. + */ +NTSTATUS KphOpenDirectoryObject( + __out PHANDLE DirectoryObjectHandle, + __in ACCESS_MASK DesiredAccess, + __in POBJECT_ATTRIBUTES ObjectAttributes, + __in KPROCESSOR_MODE AccessMode + ) +{ + return KphOpenNamedObject( + DirectoryObjectHandle, + DesiredAccess, + ObjectAttributes, + NULL, + AccessMode + ); +} + +/* KphOpenNamedObject + * + * Opens a named object. + */ +NTSTATUS KphOpenNamedObject( + __out PHANDLE ObjectHandle, + __in ACCESS_MASK DesiredAccess, + __in POBJECT_ATTRIBUTES ObjectAttributes, + __in POBJECT_TYPE ObjectType, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status = STATUS_SUCCESS; + HANDLE objectHandle; + UNICODE_STRING capturedObjectName; + OBJECT_ATTRIBUTES objectAttributes = { 0 }; + + if (!ObjectAttributes) + return STATUS_INVALID_PARAMETER; + + /* Probe user input. */ + if (AccessMode != KernelMode) + { + __try + { + ProbeForWrite(ObjectHandle, sizeof(HANDLE), 1); + ProbeForRead(ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), 1); + + if (ObjectAttributes->ObjectName) + KphProbeForReadUnicodeString(ObjectAttributes->ObjectName); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + + __try + { + /* Verify parameters. */ + if (!ObjectAttributes->ObjectName) + return STATUS_INVALID_PARAMETER; + + /* Copy the object attributes structure. */ + memcpy(&objectAttributes, ObjectAttributes, sizeof(OBJECT_ATTRIBUTES)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + + /* Capture the ObjectName string. */ + status = KphCaptureUnicodeString( + ObjectAttributes->ObjectName, + &capturedObjectName + ); + + if (!NT_SUCCESS(status)) + return status; + + /* Set the new string in the object attributes. */ + objectAttributes.ObjectName = &capturedObjectName; + /* Make sure the SecurityDescriptor and SecurityQualityOfService fields are NULL + * since we haven't probed them. + */ + objectAttributes.SecurityDescriptor = NULL; + objectAttributes.SecurityQualityOfService = NULL; + + /* Open the object. */ + status = ObOpenObjectByName( + &objectAttributes, + ObjectType, + KernelMode, + NULL, + DesiredAccess, + NULL, + &objectHandle + ); + + /* Free the captured ObjectName. */ + KphFreeCapturedUnicodeString(&capturedObjectName); + + /* Pass the handle back. */ + __try + { + *ObjectHandle = objectHandle; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + + return status; +} + +/* KphQueryFileObjectName + * + * Queries the name of a file object. + * + * Technique from YAPM. + */ +NTSTATUS KphQueryNameFileObject( + __in PFILE_OBJECT FileObject, + __inout_bcount(BufferLength) PUNICODE_STRING Buffer, + __in ULONG BufferLength, + __out PULONG ReturnLength + ) +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG returnLength; + PCHAR objectName; + ULONG usedLength; + ULONG subNameLength; + PFILE_OBJECT relatedFileObject; + + /* We need at least the size of UNICODE_STRING to + * continue. + */ + if (BufferLength < sizeof(UNICODE_STRING)) + { + *ReturnLength = sizeof(UNICODE_STRING); + + return STATUS_BUFFER_TOO_SMALL; + } + + /* Assume failure. */ + Buffer->Length = 0; + /* We will place the object name directly after the + * UNICODE_STRING structure in the buffer. + */ + Buffer->Buffer = (PWSTR)PTR_ADD_OFFSET(Buffer, sizeof(UNICODE_STRING)); + /* Retain a local pointer to the object name so we + * can manipulate the pointer. + */ + objectName = (PCHAR)Buffer->Buffer; + /* A variable that keeps track of how much space we + * have used. + */ + usedLength = sizeof(UNICODE_STRING); + + /* 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, + (POBJECT_NAME_INFORMATION)Buffer, + BufferLength, + &returnLength + ); + + if (!NT_SUCCESS(status)) + { + *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->Length; + usedLength += Buffer->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 tree 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->Length += (USHORT)subNameLength; + + /* Pass the return length back. */ + *ReturnLength = usedLength; + + return STATUS_SUCCESS; +} + +/* KphQueryObjectName + * + * Queries the name of an object. + */ +NTSTATUS KphQueryNameObject( + __in PVOID Object, + __inout_bcount(BufferLength) PUNICODE_STRING Buffer, + __in ULONG BufferLength, + __out PULONG ReturnLength + ) +{ + NTSTATUS status = STATUS_SUCCESS; + POBJECT_TYPE objectType; + + objectType = KphGetObjectTypeNt(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((PFILE_OBJECT)Object, Buffer, BufferLength, ReturnLength); + } + else + { + status = ObQueryNameString(Object, (POBJECT_NAME_INFORMATION)Buffer, BufferLength, ReturnLength); + } + + return status; +} + +/* KphQueryProcessHandles + * + * Queries a process handle table. + */ +NTSTATUS KphQueryProcessHandles( + __in HANDLE ProcessHandle, + __out_bcount_opt(BufferLength) PPROCESS_HANDLE_INFORMATION Buffer, + __in_opt ULONG BufferLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status; + BOOLEAN result; + PEPROCESS processObject; + OBP_QUERY_PROCESS_HANDLES_DATA context; + + /* Probe buffer contents. */ + if (AccessMode != KernelMode) + { + __try + { + if (Buffer) + ProbeForWrite(Buffer, BufferLength, 1); + if (ReturnLength) + ProbeForWrite(ReturnLength, sizeof(ULONG), 1); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + + /* Reference the process object. */ + status = ObReferenceObjectByHandle( + ProcessHandle, + PROCESS_QUERY_INFORMATION, + *PsProcessType, + KernelMode, + &processObject, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + /* Initialize the enumeration context. */ + context.Buffer = Buffer; + context.BufferLength = BufferLength; + context.CurrentIndex = 0; + context.Status = STATUS_SUCCESS; + + /* Enumerate the handles. */ + result = KphEnumProcessHandleTable( + processObject, + KphpQueryProcessHandlesEnumCallback, + &context, + NULL + ); + ObDereferenceObject(processObject); + + /* Write the number of handles (if we have a buffer). */ + if ( + Buffer && + BufferLength >= sizeof(ULONG) + ) + { + __try + { + Buffer->HandleCount = context.CurrentIndex; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + + /* Supply the return length if the caller wanted it. */ + if (ReturnLength) + { + __try + { + /* CurrentIndex should contain the number of handles, so we simply multiply it + by the size of PROCESS_HANDLE. */ + *ReturnLength = sizeof(ULONG) + context.CurrentIndex * sizeof(PROCESS_HANDLE); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + + return context.Status; +} + +/* KphpQueryProcessHandlesEnumCallback + * + * The callback for KphEnumProcessHandleTable, used by + * KphQueryProcessHandles. + */ +BOOLEAN KphpQueryProcessHandlesEnumCallback( + __inout PHANDLE_TABLE_ENTRY HandleTableEntry, + __in HANDLE Handle, + __in POBP_QUERY_PROCESS_HANDLES_DATA Context + ) +{ + PROCESS_HANDLE handleInfo; + PPROCESS_HANDLE_INFORMATION buffer = Context->Buffer; + ULONG i; + + handleInfo.Handle = Handle; + handleInfo.Object = ObpDecodeObject(HandleTableEntry->Object); + handleInfo.GrantedAccess = ObpDecodeGrantedAccess(HandleTableEntry->GrantedAccess); + handleInfo.HandleAttributes = ObpGetHandleAttributes(HandleTableEntry); + + /* Increment the index regardless of whether the information will be written; + this will allow KphQueryProcessHandles to report the correct return length. */ + i = Context->CurrentIndex++; + + /* Only write if we have a buffer and have not exceeded the buffer length. */ + if ( + buffer && + (sizeof(ULONG) + Context->CurrentIndex * sizeof(PROCESS_HANDLE)) <= Context->BufferLength + ) + { + __try + { + buffer->Handles[i] = 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; +} + +/* KphSetHandleGrantedAccess + * + * Sets the granted access of a handle. + */ +NTSTATUS KphSetHandleGrantedAccess( + __in PEPROCESS Process, + __in HANDLE Handle, + __in ACCESS_MASK GrantedAccess + ) +{ + BOOLEAN result; + OBP_SET_HANDLE_GRANTED_ACCESS_DATA context; + + context.Handle = Handle; + context.GrantedAccess = GrantedAccess; + + result = KphEnumProcessHandleTable( + Process, + KphpSetHandleGrantedAccessEnumCallback, + &context, + NULL + ); + + return result ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL; +} + +/* KphpSetHandleGrantedAccessEnumCallback + * + * The callback for KphEnumProcessHandleTable, used by + * KphSetHandleGrantedAccess. + */ +BOOLEAN KphpSetHandleGrantedAccessEnumCallback( + __inout PHANDLE_TABLE_ENTRY HandleTableEntry, + __in HANDLE Handle, + __in POBP_SET_HANDLE_GRANTED_ACCESS_DATA Context + ) +{ + if (Handle != Context->Handle) + return FALSE; + + HandleTableEntry->GrantedAccess = Context->GrantedAccess; + + return TRUE; +} + +/* ObDereferenceProcessHandleTable + * + * Allows the process to terminate. + */ +VOID ObDereferenceProcessHandleTable( + __in PEPROCESS Process + ) +{ + KphReleaseProcessRundownProtection(Process); +} + +/* ObDuplicateObject + * + * Duplicates a handle from the source process to the target process. + * WARNING: This does not actually duplicate a handle. It simply + * re-opens an object in another process. + */ +NTSTATUS ObDuplicateObject( + __in PEPROCESS SourceProcess, + __in_opt PEPROCESS TargetProcess, + __in HANDLE SourceHandle, + __out_opt PHANDLE TargetHandle, + __in ACCESS_MASK DesiredAccess, + __in ULONG HandleAttributes, + __in ULONG Options, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status = STATUS_SUCCESS; + BOOLEAN sourceAttached = FALSE; + BOOLEAN targetAttached = FALSE; + KAPC_STATE apcState; + PVOID object; + HANDLE objectHandle; + + /* Validate the parameters */ + if (!TargetProcess || !TargetHandle) + { + if (!(Options & DUPLICATE_CLOSE_SOURCE)) + return STATUS_INVALID_PARAMETER; + } + + /* Check if we need to attach to the source process */ + if (SourceProcess != PsGetCurrentProcess()) + { + KeStackAttachProcess(SourceProcess, &apcState); + sourceAttached = TRUE; + } + + /* If the caller wants us to close the source handle, do it now */ + if (Options & DUPLICATE_CLOSE_SOURCE) + { + status = NtClose(SourceHandle); + if (sourceAttached) + KeUnstackDetachProcess(&apcState); + + return status; + } + + /* Reference the object and detach from the source process */ + status = ObReferenceObjectByHandle( + SourceHandle, + 0, + NULL, + KernelMode, + &object, + NULL + ); + if (sourceAttached) + KeUnstackDetachProcess(&apcState); + + if (!NT_SUCCESS(status)) + return status; + + /* Check if we need to attach to the target process */ + if (TargetProcess != PsGetCurrentProcess()) + { + KeStackAttachProcess(TargetProcess, &apcState); + targetAttached = TRUE; + } + + /* Open the object and detach from the target process */ + { + POBJECT_TYPE objectType = KphGetObjectTypeNt(object); + ACCESS_STATE accessState; + CHAR auxData[AUX_ACCESS_DATA_SIZE]; + + if (!objectType && AccessMode != KernelMode) + { + status = STATUS_INVALID_HANDLE; + goto OpenObjectEnd; + } + + status = SeCreateAccessState( + &accessState, + (PAUX_ACCESS_DATA)auxData, + DesiredAccess, + (PGENERIC_MAPPING)KVOFF(objectType, OffOtiGenericMapping) + ); + + if (!NT_SUCCESS(status)) + goto OpenObjectEnd; + + accessState.PreviouslyGrantedAccess |= 0xffffffff; /* HACK, doesn't work properly */ + accessState.RemainingDesiredAccess = 0; + + status = ObOpenObjectByPointer( + object, + HandleAttributes, + &accessState, + DesiredAccess, + objectType, + KernelMode, + &objectHandle + ); + SeDeleteAccessState(&accessState); + } + +OpenObjectEnd: + ObDereferenceObject(object); + + if (targetAttached) + KeUnstackDetachProcess(&apcState); + + if (NT_SUCCESS(status)) + *TargetHandle = objectHandle; + else + *TargetHandle = NULL; + + return status; +} + +/* ObReferenceProcessHandleTable + * + * Prevents the process from terminating and returns a pointer + * to its handle table. + */ +PHANDLE_TABLE ObReferenceProcessHandleTable( + __in PEPROCESS Process + ) +{ + PHANDLE_TABLE handleTable = NULL; + + if (KphAcquireProcessRundownProtection(Process)) + { + handleTable = *(PHANDLE_TABLE *)KVOFF(Process, OffEpObjectTable); + + if (!handleTable) + KphReleaseProcessRundownProtection(Process); + } + + return handleTable; +} diff --git a/branches/ph-plugins/KProcessHacker/protect.c b/branches/ph-plugins/KProcessHacker/protect.c new file mode 100644 index 000000000..406c32019 --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/protect.c @@ -0,0 +1,457 @@ +/* + * Process Hacker Driver - + * process protection + * + * Copyright (C) 2009 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/protect.h" + +BOOLEAN KphpIsAccessAllowed( + __in PVOID Object, + __in KPROCESSOR_MODE AccessMode, + __in ACCESS_MASK DesiredAccess + ); + +BOOLEAN KphpIsCurrentProcessProtected(); + +VOID KphpProtectRemoveEntry( + __in PKPH_PROCESS_ENTRY Entry + ); + +/* ProtectedProcessRundownProtect + * + * Rundown protection making sure this module doesn't deinitialize before all hook targets + * have finished executing and no one is accessing the lookaside list. + */ +static EX_RUNDOWN_REF ProtectedProcessRundownProtect; +/* ProtectedProcessListHead + * + * The head of the process protection linked list. Each entry stores protection + * information for a process. + */ +static LIST_ENTRY ProtectedProcessListHead; +/* ProtectedProcessListLock + * + * The spinlock which protects all accesses to the protected process list (even + * the individual entries) + */ +static KSPIN_LOCK ProtectedProcessListLock; +/* ProtectedProcessLookasideList + * + * The lookaside list for protected process entries. + */ +static NPAGED_LOOKASIDE_LIST ProtectedProcessLookasideList; + +static KPH_OB_OPEN_HOOK ProcessOpenHook = { 0 }; +static KPH_OB_OPEN_HOOK ThreadOpenHook = { 0 }; + +/* KphProtectInit + * + * Initializes process protection. + * + * IRQL: <= APC_LEVEL + */ +NTSTATUS KphProtectInit() +{ + NTSTATUS status; + + /* Initialize rundown protection. */ + ExInitializeRundownProtection(&ProtectedProcessRundownProtect); + /* Initialize list structures. */ + InitializeListHead(&ProtectedProcessListHead); + KeInitializeSpinLock(&ProtectedProcessListLock); + ExInitializeNPagedLookasideList( + &ProtectedProcessLookasideList, + NULL, + NULL, + 0, + sizeof(KPH_PROCESS_ENTRY), + TAG_PROTECTION_ENTRY, + 0 + ); + + /* Hook various functions. */ + /* Hooking the open procedure calls for processes and threads allows + * us to intercept handle creation/duplication/inheritance. */ + KphInitializeObOpenHook(&ProcessOpenHook, *PsProcessType, KphNewOpenProcedure51, KphNewOpenProcedure60); + if (!NT_SUCCESS(status = KphObOpenHook(&ProcessOpenHook))) + return status; + KphInitializeObOpenHook(&ThreadOpenHook, *PsThreadType, KphNewOpenProcedure51, KphNewOpenProcedure60); + if (!NT_SUCCESS(status = KphObOpenHook(&ThreadOpenHook))) + return status; + + return STATUS_SUCCESS; +} + +/* KphProtectDeinit + * + * Removes process protection and frees associated structures. + * + * IRQL: <= APC_LEVEL + */ +NTSTATUS KphProtectDeinit() +{ + NTSTATUS status = STATUS_SUCCESS; + KIRQL oldIrql; + LARGE_INTEGER waitLi; + + /* Unhook. */ + status = KphObOpenUnhook(&ProcessOpenHook); + status = KphObOpenUnhook(&ThreadOpenHook); + + /* Wait for all activity to finish. */ + ExWaitForRundownProtectionRelease(&ProtectedProcessRundownProtect); + /* Wait for a bit (some regions of hook target functions + are NOT guarded by rundown protection, e.g. + prologues and epilogues). */ + waitLi.QuadPart = KPH_REL_TIMEOUT_IN_SEC(1); + KeDelayExecutionThread(KernelMode, FALSE, &waitLi); + + /* Free all process protection entries. */ + ExDeleteNPagedLookasideList(&ProtectedProcessLookasideList); + + return status; +} + +/* KphNewOpenProcedure51 + * + * New process/thread open procedure for NT 5.1. + */ +NTSTATUS NTAPI KphNewOpenProcedure51( + __in OB_OPEN_REASON OpenReason, + __in PEPROCESS Process, + __in PVOID Object, + __in ACCESS_MASK GrantedAccess, + __in ULONG HandleCount + ) +{ + /* Simply call the 6.0 open procedure. */ + /* NOTE: GrantedAccess is always 0 on XP... */ + return KphNewOpenProcedure60( + OpenReason, + /* Assume worst case. */ + UserMode, + Process, + Object, + GrantedAccess, + HandleCount + ); +} + +/* KphNewOpenProcedure60 + * + * New process/thread open procedure for NT 6.0 and 6.1. + */ +NTSTATUS NTAPI KphNewOpenProcedure60( + __in OB_OPEN_REASON OpenReason, + __in KPROCESSOR_MODE AccessMode, + __in PEPROCESS Process, + __in PVOID Object, + __in ACCESS_MASK GrantedAccess, + __in ULONG HandleCount + ) +{ + NTSTATUS status = STATUS_SUCCESS; + BOOLEAN accessAllowed = TRUE; + + /* Prevent the driver from unloading while this routine is executing. */ + if (!ExAcquireRundownProtection(&ProtectedProcessRundownProtect)) + { + /* Should never happen. */ + return STATUS_INTERNAL_ERROR; + } + + accessAllowed = KphpIsAccessAllowed( + Object, + AccessMode, + /* Assume worst case if granted access not available. */ + !GrantedAccess ? (ACCESS_MASK)-1 : GrantedAccess + ); + + if (accessAllowed) + { + POBJECT_TYPE objectType = KphGetObjectTypeNt(Object); + + /* Call the original open procedure. There shouldn't be any for Windows XP, + * while on Windows Vista and 7 it is used for implementing protected + * processes (Big Content's DRM protection, not KProcessHacker's protection). + */ + status = KphObOpenCall( + objectType == *PsProcessType ? &ProcessOpenHook : &ThreadOpenHook, + OpenReason, + AccessMode, + Process, + Object, + GrantedAccess, + HandleCount + ); + } + else + { + dprintf("KphNewOpenProcedure60: Access denied.\n"); + status = STATUS_ACCESS_DENIED; + } + + ExReleaseRundownProtection(&ProtectedProcessRundownProtect); + + return status; +} + +/* KphProtectAddEntry + * + * Protects the specified process. + * + * Thread safety: Full + * IRQL: <= DISPATCH_LEVEL + */ +PKPH_PROCESS_ENTRY KphProtectAddEntry( + __in PEPROCESS Process, + __in HANDLE Tag, + __in LOGICAL AllowKernelMode, + __in ACCESS_MASK ProcessAllowMask, + __in ACCESS_MASK ThreadAllowMask + ) +{ + KIRQL oldIrql; + PKPH_PROCESS_ENTRY entry; + + /* Prevent the lookaside list from being freed. */ + if (!ExAcquireRundownProtection(&ProtectedProcessRundownProtect)) + return NULL; + + entry = ExAllocateFromNPagedLookasideList(&ProtectedProcessLookasideList); + /* Lookaside list no longer needed. */ + ExReleaseRundownProtection(&ProtectedProcessRundownProtect); + + if (!entry) + return NULL; + + entry->Process = Process; + entry->CreatorProcess = PsGetCurrentProcess(); + entry->Tag = Tag; + entry->AllowKernelMode = AllowKernelMode; + entry->ProcessAllowMask = ProcessAllowMask; + entry->ThreadAllowMask = ThreadAllowMask; + + KeAcquireSpinLock(&ProtectedProcessListLock, &oldIrql); + InsertHeadList(&ProtectedProcessListHead, &entry->ListEntry); + KeReleaseSpinLock(&ProtectedProcessListLock, oldIrql); + + return entry; +} + +/* KphProtectFindEntry + * + * Finds process protection data. + * + * Thread safety: Full/Limited. The returned pointer is not guaranteed to + * point to a valid process entry. However, the copied entry is safe to + * read. + * IRQL: <= DISPATCH_LEVEL + */ +PKPH_PROCESS_ENTRY KphProtectFindEntry( + __in PEPROCESS Process, + __in HANDLE Tag, + __out_opt PKPH_PROCESS_ENTRY ProcessEntryCopy + ) +{ + KIRQL oldIrql; + PLIST_ENTRY entry = ProtectedProcessListHead.Flink; + + KeAcquireSpinLock(&ProtectedProcessListLock, &oldIrql); + + while (entry != &ProtectedProcessListHead) + { + PKPH_PROCESS_ENTRY processEntry = + CONTAINING_RECORD(entry, KPH_PROCESS_ENTRY, ListEntry); + + if ( + (Process != NULL && processEntry->Process == Process) || + (Tag != NULL && processEntry->Tag == Tag) + ) + { + /* Copy the entry if requested. */ + if (ProcessEntryCopy) + memcpy(ProcessEntryCopy, processEntry, sizeof(KPH_PROCESS_ENTRY)); + + KeReleaseSpinLock(&ProtectedProcessListLock, oldIrql); + + return processEntry; + } + + entry = entry->Flink; + } + + KeReleaseSpinLock(&ProtectedProcessListLock, oldIrql); + + return NULL; +} + +/* KphProtectRemoveByProcess + * + * Removes protection from the specified process. + * + * Thread safety: Limited. Callers must synchronize remove calls such + * as KphProtectRemoveByProcess and KphProtectRemoveByTag. + * IRQL: <= DISPATCH_LEVEL + */ +BOOLEAN KphProtectRemoveByProcess( + __in PEPROCESS Process + ) +{ + PKPH_PROCESS_ENTRY entry = KphProtectFindEntry(Process, NULL, NULL); + + if (!entry) + return FALSE; + + KphpProtectRemoveEntry(entry); + + return TRUE; +} + +/* KphProtectRemoveByTag + * + * Removes protection from all processes with the specified tag. + * + * Thread safety: Limited. Callers must synchronize remove calls such + * as KphProtectRemoveByProcess and KphProtectRemoveByTag. + * IRQL: <= DISPATCH_LEVEL + */ +ULONG KphProtectRemoveByTag( + __in HANDLE Tag + ) +{ + KIRQL oldIrql; + ULONG count = 0; + PKPH_PROCESS_ENTRY entry; + + /* Keep removing entries until we can't find any more. */ + while (entry = KphProtectFindEntry(NULL, Tag, NULL)) + { + KphpProtectRemoveEntry(entry); + count++; + } + + return count; +} + +/* KphpIsAccessAllowed + * + * Checks if the specified access is allowed, according to process + * protection rules. + * + * Thread safety: Full + * IRQL: <= DISPATCH_LEVEL + */ +BOOLEAN KphpIsAccessAllowed( + __in PVOID Object, + __in KPROCESSOR_MODE AccessMode, + __in ACCESS_MASK DesiredAccess + ) +{ + POBJECT_TYPE objectType; + PEPROCESS processObject; + BOOLEAN isThread = FALSE; + + objectType = KphGetObjectTypeNt(Object); + /* It doesn't matter if it isn't actually a process because we won't be + dereferencing it. */ + processObject = (PEPROCESS)Object; + isThread = objectType == *PsThreadType; + + /* If this is a thread, get its parent process. */ + if (isThread) + processObject = IoThreadToProcess((PETHREAD)Object); + + if ( + processObject != PsGetCurrentProcess() && /* let the caller open its own processes/threads */ + (objectType == *PsProcessType || objectType == *PsThreadType) /* only protect processes and threads */ + ) + { + KPH_PROCESS_ENTRY processEntry; + + /* Search for and copy the corresponding process protection entry. */ + if (KphProtectFindEntry(processObject, NULL, &processEntry)) + { + ACCESS_MASK mask = + isThread ? processEntry.ThreadAllowMask : processEntry.ProcessAllowMask; + + /* The process/thread is protected. Check if the requested access is allowed. */ + if ( + /* check if kernel-mode is exempt from protection */ + !(processEntry.AllowKernelMode && AccessMode == KernelMode) && + /* allow the creator of the rule to bypass protection */ + processEntry.CreatorProcess != PsGetCurrentProcess() && + (DesiredAccess & mask) != DesiredAccess + ) + { + /* Access denied. */ + dprintf( + "%d: Access denied: 0x%08x (%s)\n", + PsGetCurrentProcessId(), + DesiredAccess, + isThread ? "Thread" : "Process" + ); + + return FALSE; + } + } + } + + return TRUE; +} + +/* KphpIsCurrentProcessProtected + * + * Determines whether the current process is protected. + * + * Thread safety: Full + * IRQL: <= DISPATCH_LEVEL + */ +BOOLEAN KphpIsCurrentProcessProtected() +{ + return KphProtectFindEntry(PsGetCurrentProcess(), NULL, NULL) != NULL; +} + +/* KphpProtectRemoveEntry + * + * Removes and frees process protection data. + * + * Thread safety: Full + * IRQL: <= DISPATCH_LEVEL + */ +VOID KphpProtectRemoveEntry( + __in PKPH_PROCESS_ENTRY Entry + ) +{ + KIRQL oldIrql; + + KeAcquireSpinLock(&ProtectedProcessListLock, &oldIrql); + RemoveEntryList(&Entry->ListEntry); + + /* Prevent the lookaside list from being destroyed. */ + ExAcquireRundownProtection(&ProtectedProcessRundownProtect); + ExFreeToNPagedLookasideList( + &ProtectedProcessLookasideList, + Entry + ); + ExReleaseRundownProtection(&ProtectedProcessRundownProtect); + + KeReleaseSpinLock(&ProtectedProcessListLock, oldIrql); +} diff --git a/branches/ph-plugins/KProcessHacker/ps.c b/branches/ph-plugins/KProcessHacker/ps.c new file mode 100644 index 000000000..ac7502747 --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/ps.c @@ -0,0 +1,1217 @@ +/* + * Process Hacker Driver - + * processes and threads + * + * Copyright (C) 2009 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/kph.h" +#include "include/ke.h" +#include "include/ps.h" + +VOID NTAPI KphpCaptureStackBackTraceThreadSpecialApc( + PKAPC Apc, + PKNORMAL_ROUTINE *NormalRoutine, + PVOID *NormalContext, + PVOID *SystemArgument1, + PVOID *SystemArgument2 + ); + +VOID NTAPI KphpExitSpecialApc( + PKAPC Apc, + PKNORMAL_ROUTINE *NormalRoutine, + PVOID *NormalContext, + PVOID *SystemArgument1, + PVOID *SystemArgument2 + ); + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, KphAssignImpersonationToken) +#pragma alloc_text(PAGE, KphCaptureStackBackTraceThread) +#pragma alloc_text(PAGE, KphpCaptureStackBackTraceThread) +#pragma alloc_text(PAGE, KphpCaptureStackBackTraceThreadSpecialApc) +#pragma alloc_text(PAGE, KphDangerousTerminateThread) +#pragma alloc_text(PAGE, KphpExitSpecialApc) +#pragma alloc_text(PAGE, KphGetContextThread) +#pragma alloc_text(PAGE, KphGetProcessId) +#pragma alloc_text(PAGE, KphGetThreadId) +#pragma alloc_text(PAGE, KphGetThreadWin32Thread) +#pragma alloc_text(PAGE, KphOpenProcess) +#pragma alloc_text(PAGE, KphOpenProcessJob) +#pragma alloc_text(PAGE, KphOpenThread) +#pragma alloc_text(PAGE, KphOpenThreadProcess) +#pragma alloc_text(PAGE, KphResumeProcess) +#pragma alloc_text(PAGE, KphSetContextThread) +#pragma alloc_text(PAGE, KphSuspendProcess) +#pragma alloc_text(PAGE, KphResumeProcess) +#pragma alloc_text(PAGE, KphTerminateProcess) +#pragma alloc_text(PAGE, KphTerminateThread) +#pragma alloc_text(PAGE, PsTerminateProcess) +#pragma alloc_text(PAGE, PspTerminateThreadByPointer) +#endif + +/* KphAcquireProcessRundownProtection + * + * Prevents the process from terminating. + */ +BOOLEAN KphAcquireProcessRundownProtection( + __in PEPROCESS Process + ) +{ + return ExAcquireRundownProtection((PEX_RUNDOWN_REF)KVOFF(Process, OffEpRundownProtect)); +} + +/* KphAssignImpersonationToken + * + * Assigns an impersonation token to the specified thread. + */ +NTSTATUS KphAssignImpersonationToken( + __in HANDLE ThreadHandle, + __in HANDLE TokenHandle + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PETHREAD threadObject; + + status = ObReferenceObjectByHandle( + ThreadHandle, + 0, + *PsThreadType, + KernelMode, + &threadObject, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + status = PsAssignImpersonationToken(threadObject, TokenHandle); + ObDereferenceObject(threadObject); + + return status; +} + +/* KphCaptureStackBackTraceThread + * + * Captures a kernel-mode stack backtrace for the specified thread. + */ +NTSTATUS KphCaptureStackBackTraceThread( + __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 threadObject; + + /* Reference the thread. */ + status = ObReferenceObjectByHandle( + ThreadHandle, + THREAD_QUERY_INFORMATION, + *PsThreadType, + KernelMode, + &threadObject, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + /* Get the stack trace. */ + status = KphpCaptureStackBackTraceThread( + threadObject, + FramesToSkip, + FramesToCapture, + BackTrace, + CapturedFrames, + BackTraceHash, + AccessMode + ); + /* Dereference the thread. */ + ObDereferenceObject(threadObject); + + return status; +} + +/* KphpCaptureStackBackTraceThread + * + * Captures a kernel-mode stack backtrace for the specified thread. + * + * IRQL: <= APC_LEVEL + */ +NTSTATUS KphpCaptureStackBackTraceThread( + __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; + + backTraceSize = FramesToCapture * sizeof(PVOID); + + /* Probe user input. */ + if (AccessMode != KernelMode) + { + __try + { + ProbeForWrite(BackTrace, backTraceSize, 1); + + if (CapturedFrames) + ProbeForWrite(CapturedFrames, sizeof(ULONG), 1); + if (BackTraceHash) + ProbeForWrite(BackTraceHash, sizeof(ULONG), 1); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + + /* Allocate storage for the stack trace. */ + backTrace = (PVOID *)ExAllocatePoolWithTag(NonPagedPool, backTraceSize, TAG_CAPTURE_STACK_BACKTRACE); + + 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 (Thread == PsGetCurrentThread()) + { + PCAPTURE_BACKTRACE_THREAD_CONTEXT contextPtr = &context; + PVOID dummy = NULL; + KIRQL oldIrql; + + context.Local = TRUE; + /* Raise the IRQL to APC_LEVEL to simulate an APC environment. */ + KeRaiseIrql(APC_LEVEL, &oldIrql); + /* Call the APC routine directly. */ + KphpCaptureStackBackTraceThreadSpecialApc( + &context.Apc, + NULL, + NULL, + &contextPtr, + &dummy + ); + /* Lower the IRQL back. */ + KeLowerIrql(oldIrql); + } + else + { + context.Local = FALSE; + /* Initialize the stack trace completed event. */ + KeInitializeEvent(&context.CompletedEvent, NotificationEvent, FALSE); + /* Initialize the APC. */ + KeInitializeApc( + &context.Apc, + (PKTHREAD)Thread, + OriginalApcEnvironment, + KphpCaptureStackBackTraceThreadSpecialApc, + NULL, + NULL, + KernelMode, + NULL + ); + /* Queue the APC. */ + 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); + + /* Write the information. */ + __try + { + memcpy(BackTrace, backTrace, context.CapturedFrames * sizeof(PVOID)); + + if (CapturedFrames) + *CapturedFrames = context.CapturedFrames; + if (BackTraceHash) + *BackTraceHash = context.BackTraceHash; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + } + + /* Free the allocated stack trace storage. */ + ExFreePoolWithTag(backTrace, TAG_CAPTURE_STACK_BACKTRACE); + + return status; +} + +/* KphpCaptureStackBackTraceThreadSpecialApc + * + * The special APC routine which captures a thread stack trace. + */ +VOID NTAPI KphpCaptureStackBackTraceThreadSpecialApc( + PKAPC Apc, + PKNORMAL_ROUTINE *NormalRoutine, + PVOID *NormalContext, + PVOID *SystemArgument1, + PVOID *SystemArgument2 + ) +{ + PCAPTURE_BACKTRACE_THREAD_CONTEXT context = + (PCAPTURE_BACKTRACE_THREAD_CONTEXT)*SystemArgument1; + + /* Capture a stack trace. */ + context->CapturedFrames = KphCaptureStackBackTrace( + context->FramesToSkip, + context->FramesToCapture, + 0, + context->BackTrace, + &context->BackTraceHash + ); + + if (!context->Local) + { + /* Signal the completed event. */ + KeSetEvent(&context->CompletedEvent, 0, FALSE); + } +} + +/* KphDangerousTerminateThread + * + * Terminates the specified thread by queueing an APC. + */ +NTSTATUS KphDangerousTerminateThread( + __in HANDLE ThreadHandle, + __in NTSTATUS ExitStatus + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PETHREAD threadObject; + + if (!__PspTerminateThreadByPointer) + return STATUS_NOT_SUPPORTED; + + status = ObReferenceObjectByHandle( + ThreadHandle, + THREAD_TERMINATE, + *PsThreadType, + KernelMode, + &threadObject, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + if (threadObject != PsGetCurrentThread()) + { + EXIT_THREAD_CONTEXT context; + + /* Initialize the context structure. */ + context.ExitStatus = ExitStatus; + /* Initialize the completion event. */ + KeInitializeEvent(&context.CompletedEvent, NotificationEvent, FALSE); + /* Initialize the APC. */ + KeInitializeApc( + &context.Apc, + (PKTHREAD)threadObject, + OriginalApcEnvironment, + KphpExitSpecialApc, + NULL, + NULL, + KernelMode, + NULL + ); + + /* Queue the APC. */ + if (KeInsertQueueApc(&context.Apc, &context, NULL, 2)) + { + /* Wait for the APC to initialize. */ + status = KeWaitForSingleObject( + &context.CompletedEvent, + Executive, + KernelMode, + FALSE, + NULL + ); + } + else + { + status = STATUS_UNSUCCESSFUL; + } + + ObDereferenceObject(threadObject); + } + else + { + /* Can't terminate self. */ + ObDereferenceObject(threadObject); + return STATUS_CANT_TERMINATE_SELF; + } + + return status; +} + +VOID NTAPI KphpExitSpecialApc( + PKAPC Apc, + PKNORMAL_ROUTINE *NormalRoutine, + PVOID *NormalContext, + PVOID *SystemArgument1, + PVOID *SystemArgument2 + ) +{ + PEXIT_THREAD_CONTEXT context = + (PEXIT_THREAD_CONTEXT)*SystemArgument1; + NTSTATUS exitStatus; + + /* Get the exit status. */ + exitStatus = context->ExitStatus; + /* That's the best we can do. Once we exit the current thread we can't + * signal the event, so just signal it now. */ + KeSetEvent(&context->CompletedEvent, 0, FALSE); + /* Exit the thread by calling PspTerminateThreadByPointer. */ + PspTerminateThreadByPointer(PsGetCurrentThread(), exitStatus); + /* Should never happen. */ + dfprintf( + "WARNING: Thread was not terminated by PspTerminateThreadByPointer: %d, %#x\n", + PsGetCurrentThreadId(), + PsGetCurrentThread() + ); +} + +/* KphGetContextThread + * + * Gets the context of the specified thread. + */ +NTSTATUS KphGetContextThread( + __in HANDLE ThreadHandle, + __inout PCONTEXT ThreadContext, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PETHREAD threadObject; + + status = ObReferenceObjectByHandle( + ThreadHandle, + THREAD_GET_CONTEXT, + *PsThreadType, + KernelMode, + &threadObject, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + status = PsGetContextThread(threadObject, ThreadContext, AccessMode); + ObDereferenceObject(threadObject); + + return status; +} + +/* KphGetProcessId + * + * Gets the ID of the process referenced by the specified handle. + */ +HANDLE KphGetProcessId( + __in HANDLE ProcessHandle + ) +{ + PEPROCESS processObject; + HANDLE processId; + + if (!NT_SUCCESS(ObReferenceObjectByHandle(ProcessHandle, 0, + *PsProcessType, KernelMode, &processObject, NULL))) + return 0; + + processId = PsGetProcessId(processObject); + ObDereferenceObject(processObject); + + return processId; +} + +/* KphGetThreadId + * + * Gets the ID of the thread referenced by the specified handle, + * and optionally the ID of the thread's process. + */ +HANDLE KphGetThreadId( + __in HANDLE ThreadHandle, + __out_opt PHANDLE ProcessId + ) +{ + PETHREAD threadObject; + CLIENT_ID clientId; + + if (!NT_SUCCESS(ObReferenceObjectByHandle(ThreadHandle, 0, + *PsThreadType, KernelMode, &threadObject, NULL))) + return 0; + + clientId = *(PCLIENT_ID)KVOFF(threadObject, OffEtClientId); + + ObDereferenceObject(threadObject); + + if (ProcessId) + { + *ProcessId = clientId.UniqueProcess; + } + + return clientId.UniqueThread; +} + +/* KphGetThreadWin32Thread + * + * Gets a pointer to the WIN32THREAD structure of the specified thread. + */ +NTSTATUS KphGetThreadWin32Thread( + __in HANDLE ThreadHandle, + __out PVOID *Win32Thread, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PETHREAD threadObject; + PVOID win32Thread; + + if (AccessMode != KernelMode) + { + __try + { + ProbeForWrite(Win32Thread, sizeof(PVOID), 1); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + + status = ObReferenceObjectByHandle( + ThreadHandle, + 0, + *PsThreadType, + KernelMode, + &threadObject, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + win32Thread = PsGetThreadWin32Thread(threadObject); + ObDereferenceObject(threadObject); + + __try + { + *Win32Thread = win32Thread; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + + return status; +} + +/* KphOpenProcess + * + * Opens a process. + */ +NTSTATUS KphOpenProcess( + __out PHANDLE ProcessHandle, + __in ACCESS_MASK DesiredAccess, + __in POBJECT_ATTRIBUTES ObjectAttributes, + __in_opt PCLIENT_ID ClientId, + __in KPROCESSOR_MODE AccessMode + ) +{ + BOOLEAN hasObjectName = ObjectAttributes->ObjectName != NULL; + ULONG attributes = ObjectAttributes->Attributes; + NTSTATUS status = STATUS_SUCCESS; + ACCESS_STATE accessState; + CHAR auxData[AUX_ACCESS_DATA_SIZE]; + PEPROCESS processObject = NULL; + PETHREAD threadObject = NULL; + HANDLE processHandle = NULL; + + if (hasObjectName && ClientId) + return STATUS_INVALID_PARAMETER_MIX; + + /* ReactOS code cleared this bit up for me :) */ + status = SeCreateAccessState( + &accessState, + (PAUX_ACCESS_DATA)auxData, + DesiredAccess, + (PGENERIC_MAPPING)KVOFF(*PsProcessType, OffOtiGenericMapping) + ); + + if (!NT_SUCCESS(status)) + { + return status; + } + + /* Let's hope our client isn't a virus... */ + if (accessState.RemainingDesiredAccess & MAXIMUM_ALLOWED) + accessState.PreviouslyGrantedAccess |= ProcessAllAccess; + else + accessState.PreviouslyGrantedAccess |= accessState.RemainingDesiredAccess; + + accessState.RemainingDesiredAccess = 0; + + if (hasObjectName) + { + status = ObOpenObjectByName( + ObjectAttributes, + *PsProcessType, + AccessMode, + &accessState, + 0, + NULL, + &processHandle + ); + SeDeleteAccessState(&accessState); + } + else if (ClientId) + { + if (ClientId->UniqueThread) + { + status = PsLookupProcessThreadByCid(ClientId, &processObject, &threadObject); + } + else + { + status = PsLookupProcessByProcessId(ClientId->UniqueProcess, &processObject); + } + + if (!NT_SUCCESS(status)) + { + SeDeleteAccessState(&accessState); + return status; + } + + status = ObOpenObjectByPointer( + processObject, + attributes, + &accessState, + 0, + *PsProcessType, + AccessMode, + &processHandle + ); + + SeDeleteAccessState(&accessState); + ObDereferenceObject(processObject); + + if (threadObject) + ObDereferenceObject(threadObject); + } + else + { + SeDeleteAccessState(&accessState); + return STATUS_INVALID_PARAMETER_MIX; + } + + if (NT_SUCCESS(status)) + { + *ProcessHandle = processHandle; + } + + return status; +} + +/* KphOpenProcessJob + * + * Opens the specified process' job object. If the process has + * not been assigned to a job object, the function returns + * STATUS_PROCESS_NOT_IN_JOB. + */ +NTSTATUS KphOpenProcessJob( + __in HANDLE ProcessHandle, + __in ACCESS_MASK DesiredAccess, + __out PHANDLE JobHandle, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PEPROCESS processObject; + PVOID jobObject; + HANDLE jobHandle; + ACCESS_STATE accessState; + CHAR auxData[AUX_ACCESS_DATA_SIZE]; + + status = SeCreateAccessState( + &accessState, + (PAUX_ACCESS_DATA)auxData, + DesiredAccess, + (PGENERIC_MAPPING)KVOFF(*PsJobType, OffOtiGenericMapping) + ); + + if (!NT_SUCCESS(status)) + { + return status; + } + + if (accessState.RemainingDesiredAccess & MAXIMUM_ALLOWED) + accessState.PreviouslyGrantedAccess |= JOB_OBJECT_ALL_ACCESS; + else + accessState.PreviouslyGrantedAccess |= accessState.RemainingDesiredAccess; + + accessState.RemainingDesiredAccess = 0; + + status = ObReferenceObjectByHandle(ProcessHandle, 0, *PsProcessType, KernelMode, &processObject, 0); + + if (!NT_SUCCESS(status)) + { + SeDeleteAccessState(&accessState); + return status; + } + + /* If we have PsGetProcessJob, use it. Otherwise, read the EPROCESS structure. */ + if (PsGetProcessJob) + { + jobObject = PsGetProcessJob(processObject); + } + else + { + jobObject = *(PVOID *)((PCHAR)processObject + OffEpJob); + } + + ObDereferenceObject(processObject); + + if (jobObject == NULL) + { + /* No such job. Output a NULL handle and exit. */ + SeDeleteAccessState(&accessState); + *JobHandle = NULL; + return STATUS_PROCESS_NOT_IN_JOB; + } + + ObReferenceObject(jobObject); + status = ObOpenObjectByPointer( + jobObject, + 0, + &accessState, + 0, + *PsJobType, + AccessMode, + &jobHandle + ); + SeDeleteAccessState(&accessState); + ObDereferenceObject(jobObject); + + if (NT_SUCCESS(status)) + *JobHandle = jobHandle; + + return status; +} + +/* KphOpenThread + * + * Opens a thread. + */ +NTSTATUS KphOpenThread( + __out PHANDLE ThreadHandle, + __in ACCESS_MASK DesiredAccess, + __in POBJECT_ATTRIBUTES ObjectAttributes, + __in_opt PCLIENT_ID ClientId, + __in KPROCESSOR_MODE AccessMode + ) +{ + BOOLEAN hasObjectName = ObjectAttributes->ObjectName != NULL; + ULONG attributes = ObjectAttributes->Attributes; + NTSTATUS status = STATUS_SUCCESS; + ACCESS_STATE accessState; + CHAR auxData[AUX_ACCESS_DATA_SIZE]; + PETHREAD threadObject = NULL; + HANDLE threadHandle = NULL; + + if (hasObjectName && ClientId) + return STATUS_INVALID_PARAMETER_MIX; + + status = SeCreateAccessState( + &accessState, + (PAUX_ACCESS_DATA)auxData, + DesiredAccess, + (PGENERIC_MAPPING)KVOFF(*PsThreadType, OffOtiGenericMapping) + ); + + if (!NT_SUCCESS(status)) + { + return status; + } + + if (accessState.RemainingDesiredAccess & MAXIMUM_ALLOWED) + accessState.PreviouslyGrantedAccess |= ThreadAllAccess; + else + accessState.PreviouslyGrantedAccess |= accessState.RemainingDesiredAccess; + + accessState.RemainingDesiredAccess = 0; + + if (hasObjectName) + { + status = ObOpenObjectByName( + ObjectAttributes, + *PsThreadType, + AccessMode, + &accessState, + 0, + NULL, + &threadHandle + ); + SeDeleteAccessState(&accessState); + } + else if (ClientId) + { + if (ClientId->UniqueProcess) + { + status = PsLookupProcessThreadByCid(ClientId, NULL, &threadObject); + } + else + { + status = PsLookupThreadByThreadId(ClientId->UniqueThread, &threadObject); + } + + if (!NT_SUCCESS(status)) + { + SeDeleteAccessState(&accessState); + return status; + } + + status = ObOpenObjectByPointer( + threadObject, + attributes, + &accessState, + 0, + *PsThreadType, + AccessMode, + &threadHandle + ); + + SeDeleteAccessState(&accessState); + ObDereferenceObject(threadObject); + } + else + { + SeDeleteAccessState(&accessState); + return STATUS_INVALID_PARAMETER_MIX; + } + + if (NT_SUCCESS(status)) + { + *ThreadHandle = threadHandle; + } + + return status; +} + +/* KphOpenThreadProcess + * + * Opens a thread's process. + */ +NTSTATUS KphOpenThreadProcess( + __in HANDLE ThreadHandle, + __in ACCESS_MASK DesiredAccess, + __out PHANDLE ProcessHandle, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PETHREAD threadObject; + PEPROCESS processObject; + HANDLE processHandle; + ACCESS_STATE accessState; + CHAR auxData[AUX_ACCESS_DATA_SIZE]; + + status = SeCreateAccessState( + &accessState, + (PAUX_ACCESS_DATA)auxData, + DesiredAccess, + (PGENERIC_MAPPING)KVOFF(*PsProcessType, OffOtiGenericMapping) + ); + + if (!NT_SUCCESS(status)) + { + return status; + } + + if (accessState.RemainingDesiredAccess & MAXIMUM_ALLOWED) + accessState.PreviouslyGrantedAccess |= ProcessAllAccess; + else + accessState.PreviouslyGrantedAccess |= accessState.RemainingDesiredAccess; + + accessState.RemainingDesiredAccess = 0; + + status = ObReferenceObjectByHandle(ThreadHandle, 0, *PsThreadType, KernelMode, &threadObject, 0); + + if (!NT_SUCCESS(status)) + { + SeDeleteAccessState(&accessState); + return status; + } + + /* Get the process object. */ + processObject = IoThreadToProcess(threadObject); + ObDereferenceObject(threadObject); + + if (processObject == NULL) + { + /* Thread does not have a process (?). */ + SeDeleteAccessState(&accessState); + *ProcessHandle = NULL; + return STATUS_UNSUCCESSFUL; + } + + ObReferenceObject(processObject); + status = ObOpenObjectByPointer( + processObject, + 0, + &accessState, + 0, + *PsProcessType, + AccessMode, + &processHandle + ); + SeDeleteAccessState(&accessState); + ObDereferenceObject(processObject); + + if (NT_SUCCESS(status)) + *ProcessHandle = processHandle; + + return status; +} + +/* KphReleaseProcessRundownProtection + * + * Allows the process to terminate. + */ +VOID KphReleaseProcessRundownProtection( + __in PEPROCESS Process + ) +{ + ExReleaseRundownProtection((PEX_RUNDOWN_REF)KVOFF(Process, OffEpRundownProtect)); +} + +/* KphResumeProcess + * + * Resumes the specified process. + */ +NTSTATUS KphResumeProcess( + __in HANDLE ProcessHandle + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PEPROCESS processObject; + + if (!PsResumeProcess) + return STATUS_NOT_SUPPORTED; + + status = ObReferenceObjectByHandle( + ProcessHandle, + PROCESS_SUSPEND_RESUME, + *PsProcessType, + KernelMode, + &processObject, + NULL); + + if (!NT_SUCCESS(status)) + return status; + + status = PsResumeProcess(processObject); + ObDereferenceObject(processObject); + + return status; +} + +/* KphSetContextThread + * + * Sets the context of the specified thread. + */ +NTSTATUS KphSetContextThread( + __in HANDLE ThreadHandle, + __in PCONTEXT ThreadContext, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PETHREAD threadObject; + + status = ObReferenceObjectByHandle( + ThreadHandle, + THREAD_SET_CONTEXT, + *PsThreadType, + KernelMode, + &threadObject, + NULL); + + if (!NT_SUCCESS(status)) + return status; + + status = PsSetContextThread(threadObject, ThreadContext, AccessMode); + ObDereferenceObject(threadObject); + + return status; +} + +/* KphSuspendProcess + * + * Suspends the specified process. + */ +NTSTATUS KphSuspendProcess( + __in HANDLE ProcessHandle + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PEPROCESS processObject; + + if (!PsSuspendProcess) + return STATUS_NOT_SUPPORTED; + + status = ObReferenceObjectByHandle( + ProcessHandle, + PROCESS_SUSPEND_RESUME, + *PsProcessType, + KernelMode, + &processObject, + NULL); + + if (!NT_SUCCESS(status)) + return status; + + status = PsSuspendProcess(processObject); + ObDereferenceObject(processObject); + + return status; +} + +/* KphTerminateProcess + * + * Terminates the specified process. + */ +NTSTATUS KphTerminateProcess( + __in HANDLE ProcessHandle, + __in NTSTATUS ExitStatus + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PEPROCESS processObject; + + status = ObReferenceObjectByHandle( + ProcessHandle, + PROCESS_TERMINATE, + *PsProcessType, + KernelMode, + &processObject, + NULL); + + if (!NT_SUCCESS(status)) + return status; + + /* Can't terminate ourself. Get user-mode to do it. */ + if (processObject == PsGetCurrentProcess()) + { + ObDereferenceObject(processObject); + return STATUS_CANT_TERMINATE_SELF; + } + + /* If we have located PsTerminateProcess/PspTerminateProcess, + call it. */ + if (__PsTerminateProcess) + { + status = PsTerminateProcess(processObject, ExitStatus); + ObDereferenceObject(processObject); + } + else + { + /* Otherwise, we'll have to call ZwTerminateProcess - most hooks on this function + allow kernel-mode callers through. */ + OBJECT_ATTRIBUTES objectAttributes = { 0 }; + CLIENT_ID clientId; + HANDLE newProcessHandle; + + /* We have to open it again because ZwTerminateProcess only accepts kernel handles. */ + clientId.UniqueThread = 0; + clientId.UniqueProcess = PsGetProcessId(processObject); + status = KphOpenProcess(&newProcessHandle, 0x1, &objectAttributes, &clientId, KernelMode); + ObDereferenceObject(processObject); + + if (NT_SUCCESS(status)) + { + status = ZwTerminateProcess(newProcessHandle, ExitStatus); + ZwClose(newProcessHandle); + } + } + + return status; +} + +/* KphTerminateThread + * + * Terminates the specified thread. + */ +NTSTATUS KphTerminateThread( + __in HANDLE ThreadHandle, + __in NTSTATUS ExitStatus + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PETHREAD threadObject; + + status = ObReferenceObjectByHandle( + ThreadHandle, + THREAD_TERMINATE, + *PsThreadType, + KernelMode, + &threadObject, + NULL); + + if (!NT_SUCCESS(status)) + return status; + + if (threadObject != PsGetCurrentThread()) + { + status = PspTerminateThreadByPointer(threadObject, ExitStatus); + ObDereferenceObject(threadObject); + } + else + {/* + ObDereferenceObject(threadObject); + status = PspTerminateThreadByPointer(PsGetCurrentThread(), ExitStatus); */ + /* Leads to bugs, so don't terminate self. */ + ObDereferenceObject(threadObject); + return STATUS_CANT_TERMINATE_SELF; + } + + return status; +} + +/* PsTerminateProcess + * + * Terminates the specified process. If PsTerminateProcess or + * PspTerminateProcess could not be located, the call will fail + * with STATUS_NOT_SUPPORTED. + */ +NTSTATUS PsTerminateProcess( + __in PEPROCESS Process, + __in NTSTATUS ExitStatus + ) +{ + PVOID psTerminateProcess = __PsTerminateProcess; + NTSTATUS status; + + if (!psTerminateProcess) + return STATUS_NOT_SUPPORTED; + +#ifdef _X86_ + if (WindowsVersion == WINDOWS_XP) + { + /* PspTerminateProcess on XP is stdcall. */ + __asm + { + push [ExitStatus] + push [Process] + call [psTerminateProcess] + mov [status], eax + } + } + else if ( + WindowsVersion == WINDOWS_VISTA || + WindowsVersion == WINDOWS_7 + ) + { + /* PsTerminateProcess on Vista and above is thiscall. */ + __asm + { + push [ExitStatus] + mov ecx, [Process] + call [psTerminateProcess] + mov [status], eax + } + } + else + { + return STATUS_NOT_SUPPORTED; + } +#else + status = __PsTerminateProcess(Process, ExitStatus); +#endif + + return status; +} + +/* PspTerminateThreadByPointer + * + * Terminates the specified thread. If PspTerminateThreadByPointer + * could not be located, the call will fail with STATUS_NOT_SUPPORTED. + */ +NTSTATUS PspTerminateThreadByPointer( + __in PETHREAD Thread, + __in NTSTATUS ExitStatus + ) +{ + PVOID pspTerminateThreadByPointer = __PspTerminateThreadByPointer; + + if (!pspTerminateThreadByPointer) + return STATUS_NOT_SUPPORTED; + + if (WindowsVersion == WINDOWS_XP) + { + return ((_PspTerminateThreadByPointer51)pspTerminateThreadByPointer)( + Thread, + ExitStatus + ); + } + else if ( + WindowsVersion == WINDOWS_VISTA || + WindowsVersion == WINDOWS_7 + ) + { + return ((_PspTerminateThreadByPointer60)pspTerminateThreadByPointer)( + Thread, + ExitStatus, + Thread == PsGetCurrentThread() + ); + } + else + { + return STATUS_NOT_SUPPORTED; + } +} diff --git a/branches/ph-plugins/KProcessHacker/ref.c b/branches/ph-plugins/KProcessHacker/ref.c new file mode 100644 index 000000000..eeb0f917a --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/ref.c @@ -0,0 +1,574 @@ +/* + * Process Hacker Driver - + * internal object manager + * + * Copyright (C) 2009 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/refp.h" + +/* A list of all objects created by the object manager. */ +LIST_ENTRY KphObjectListHead; +/* A mutex protecting global data structures. */ +FAST_MUTEX KphObjectListMutex; +/* The object type type. */ +PKPH_OBJECT_TYPE KphObjectTypeObject = NULL; + +/* Whether the object manager is destroying all objects. */ +BOOLEAN KphObjectDeinitializing = FALSE; +/* The work item for deferred object deletes. */ +WORK_QUEUE_ITEM KphObjectDeferDeleteWorkItem; +/* The next object to delete. */ +PKPH_OBJECT_HEADER KphObjectNextToFree = NULL; + +/* KphRefInit + * + * Initializes the KPH object manager. + * + * IRQL: <= APC_LEVEL + */ +NTSTATUS KphRefInit() +{ + NTSTATUS status = STATUS_SUCCESS; + + /* Initialize the object list. */ + InitializeListHead(&KphObjectListHead); + /* Initialize the object list mutex. */ + ExInitializeFastMutex(&KphObjectListMutex); + + /* Initialize the deferred delete work item. */ + ExInitializeWorkItem( + &KphObjectDeferDeleteWorkItem, + KphpDeferDeleteObjectRoutine, + NULL + ); + + /* Create the fundamental object type. */ + status = KphCreateObjectType( + &KphObjectTypeObject, + NonPagedPool, + 0, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + /* Now that the fundamental object type exists, fix it up. */ + KphObjectToObjectHeader(KphObjectTypeObject)->Type = KphObjectTypeObject; + KphObjectTypeObject->NumberOfObjects = 1; + + return status; +} + +/* KphRefDeinit + * + * Frees all objects created by the KPH object manager. + * + * IRQL: = PASSIVE_LEVEL + */ +NTSTATUS KphRefDeinit() +{ + NTSTATUS status = STATUS_SUCCESS; + PLIST_ENTRY currentEntry; + + KphObjectDeinitializing = TRUE; + + /* Acquire the object list mutex to make sure no one else + * modifies the list. */ + ExAcquireFastMutex(&KphObjectListMutex); + + /* Remove and free all objects in the list. */ + while ((currentEntry = RemoveHeadList(&KphObjectListHead)) != &KphObjectListHead) + { + PKPH_OBJECT_HEADER objectHeader = + CONTAINING_RECORD(currentEntry, KPH_OBJECT_HEADER, GlobalObjectListEntry); + + /* Free the object, ignoring its reference count. */ + KphpFreeObject(objectHeader); + } + + /* Release the object list mutex and restore the IRQL. */ + ExReleaseFastMutex(&KphObjectListMutex); + + return STATUS_SUCCESS; +} + +/* KphCreateObject + * + * Allocates a object. + * + * Object: A variable which receives a pointer to the newly allocated object. + * ObjectSize: The size of the object. + * Flags: A combination of flags specifying how the object is to be allocated. + * * KPHOBJ_RAISE_ON_FAIL: An exception will be raised if the object could + * not be allocated. + * * KPHOBJ_PAGED_POOL: The object will be allocated in the paged pool. If + * this flag is specified, KPHOBJ_NONPAGED_POOL cannot be specified. + * * KPHOBJ_NONPAGED_POOL: The object will be allocated in the non-paged pool. + * If this flag is specified, KPHOBJ_PAGED_POOL cannot be specified. + * ObjectType: The type of the object. + * AdditionalReferences: The number of references to add to the object. The + * object will have a reference count of 1 + AdditionalReferences. + * + * IRQL: <= APC_LEVEL + */ +NTSTATUS KphCreateObject( + __out PVOID *Object, + __in SIZE_T ObjectSize, + __in ULONG Flags, + __in_opt PKPH_OBJECT_TYPE ObjectType, + __in_opt LONG AdditionalReferences + ) +{ + PKPH_OBJECT_HEADER objectHeader; + POOL_TYPE poolType; + + /* Check the flags. */ + if ((Flags & KPHOBJ_VALID_FLAGS) != Flags) /* Valid flag mask */ + return STATUS_INVALID_PARAMETER_3; + if ((Flags & KPHOBJ_PAGED_POOL) && (Flags & KPHOBJ_NONPAGED_POOL)) /* Can't be both pools */ + return STATUS_INVALID_PARAMETER_3; + /* The object type is only optional if the fundamental object type + * hasn't been created. */ + if (!ObjectType && KphObjectTypeObject) + return STATUS_INVALID_PARAMETER_4; + /* Make sure the additional reference count isn't negative. */ + if (AdditionalReferences < 0) + return STATUS_INVALID_PARAMETER_5; + + /* Figure out the pool type. If it wasn't specified in Flags, + * get the pool type from the object type. */ + if (Flags & KPHOBJ_PAGED_POOL) + poolType = PagedPool; + else if (Flags & KPHOBJ_NONPAGED_POOL) + poolType = NonPagedPool; + else if (ObjectType) /* May be null if we're creating the fundamental type */ + poolType = ObjectType->DefaultPoolType; + else + poolType = NonPagedPool; + + /* Allocate storage for the object. Note that this includes + * the object header followed by the object body. */ + objectHeader = KphpAllocateObject(ObjectSize, poolType); + + if (!objectHeader) + { + if (Flags & KPHOBJ_RAISE_ON_FAIL) + ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); + else + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Object type statistics. */ + if (ObjectType) + { + InterlockedIncrement(&ObjectType->NumberOfObjects); + } + + /* Initialize the object header. */ + objectHeader->RefCount = 1 + AdditionalReferences; + objectHeader->Flags = Flags; + objectHeader->Size = ObjectSize; + objectHeader->Type = ObjectType; + + /* Insert the object into the global object list. */ + ExAcquireFastMutex(&KphObjectListMutex); + InsertHeadList(&KphObjectListHead, &objectHeader->GlobalObjectListEntry); + ExReleaseFastMutex(&KphObjectListMutex); + + /* Pass a pointer to the object body back to the caller. */ + *Object = KphObjectHeaderToObject(objectHeader); + + return STATUS_SUCCESS; +} + +/* KphCreateObjectType + * + * Creates an object type. + * + * IRQL: <= APC_LEVEL + */ +NTSTATUS KphCreateObjectType( + __out PKPH_OBJECT_TYPE *ObjectType, + __in POOL_TYPE DefaultPoolType, + __in ULONG Flags, + __in PKPH_TYPE_DELETE_PROCEDURE DeleteProcedure + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PKPH_OBJECT_TYPE objectType; + + /* Check the flags. */ + if ((Flags & KPHOBJTYPE_VALID_FLAGS) != Flags) /* Valid flag mask */ + return STATUS_INVALID_PARAMETER_3; + + /* Create the type object. */ + status = KphCreateObject( + &objectType, + sizeof(KPH_OBJECT_TYPE), + 0, + KphObjectTypeObject, + 0 + ); + + if (!NT_SUCCESS(status)) + return status; + + /* Initialize the type object. */ + objectType->DefaultPoolType = DefaultPoolType; + objectType->Flags = Flags; + objectType->DeleteProcedure = DeleteProcedure; + objectType->NumberOfObjects = 0; + + *ObjectType = objectType; + + return status; +} + +/* KphDereferenceObject + * + * Dereferences the specified object. The object will be freed if + * its reference count reaches 0. + * + * Object: A pointer to the object to dereference. + * + * Return value: TRUE if the object was freed, otherwise FALSE. + * + * IRQL: <= APC_LEVEL + */ +BOOLEAN KphDereferenceObject( + __in PVOID Object + ) +{ + return KphDereferenceObjectEx(Object, 1, FALSE) == 0; +} + +/* KphDereferenceObjectDeferDelete + * + * Dereferences the specified object. The object will be freed in + * a worker thread if its reference count reaches 0. + * + * Object: A pointer to the object to dereference. + * + * Return value: TRUE if the object was freed, otherwise FALSE. + * + * IRQL: <= DISPATCH_LEVEL if the object was allocated using the + * non-paged pool, otherwise <= APC_LEVEL. + */ +BOOLEAN KphDereferenceObjectDeferDelete( + __in PVOID Object + ) +{ + return KphDereferenceObjectEx(Object, 1, TRUE) == 0; +} + +/* KphDereferenceObjectEx + * + * Dereferences the specified object. The object will be freed if + * its reference count reaches 0. + * + * Object: A pointer to the object to dereference. + * RefCount: The number of references to remove. + * + * Return value: The new reference count of the object. + * + * IRQL: <= DISPATCH_LEVEL if the object was allocated using the + * non-paged pool and deletion is being deferred, otherwise <= APC_LEVEL. + */ +LONG KphDereferenceObjectEx( + __in PVOID Object, + __in LONG RefCount, + __in BOOLEAN DeferDelete + ) +{ + PKPH_OBJECT_HEADER objectHeader; + LONG oldRefCount; + + /* Make sure we're not subtracting a negative reference count. */ + if (RefCount < 0) + ExRaiseStatus(STATUS_INVALID_PARAMETER_2); + + objectHeader = KphObjectToObjectHeader(Object); + + /* Decrease the reference count. */ + oldRefCount = InterlockedExchangeAdd(&objectHeader->RefCount, -RefCount); + + /* Free the object if it has 0 references. */ + if (oldRefCount - RefCount == 0) + { + /* If we are at DISPATCH_LEVEL or higher, the type requests + * us to do so, or the caller requests us to do so, defer + * the deletion. + */ + if ( + DeferDelete || + (objectHeader->Type->Flags & KPHOBJTYPE_PASSIVE_LEVEL_DELETE) || + (KeGetCurrentIrql() > APC_LEVEL) + ) + { + KphpDeferDeleteObject(objectHeader); + } + else + { + /* Free the object. */ + KphpFreeObject(objectHeader); + } + } + + return oldRefCount - RefCount; +} + +/* KphGetObjectType + * + * Gets an object's type. + * + * IRQL: <= DISPATCH_LEVEL if the object was allocated using the + * non-paged pool, otherwise <= APC_LEVEL. + */ +PKPH_OBJECT_TYPE KphGetObjectType( + __in PVOID Object + ) +{ + return KphObjectToObjectHeader(Object)->Type; +} + +/* KphReferenceObject + * + * References the specified object. + * + * Object: A pointer to the object to reference. + * + * IRQL: <= DISPATCH_LEVEL if the object was allocated using the + * non-paged pool, otherwise <= APC_LEVEL. + */ +VOID KphReferenceObject( + __in PVOID Object + ) +{ + PKPH_OBJECT_HEADER objectHeader; + + objectHeader = KphObjectToObjectHeader(Object); + /* Increment the reference count. */ + InterlockedIncrement(&objectHeader->RefCount); +} + +/* KphReferenceObjectEx + * + * References the specified object. + * + * Object: A pointer to the object to reference. + * RefCount: The number of references to add. + * + * Return value: The new reference count of the object. + * + * IRQL: <= DISPATCH_LEVEL if the object was allocated using the + * non-paged pool, otherwise <= APC_LEVEL. + */ +LONG KphReferenceObjectEx( + __in PVOID Object, + __in LONG RefCount + ) +{ + PKPH_OBJECT_HEADER objectHeader; + LONG oldRefCount; + + /* Make sure we're not adding a negative reference count. */ + if (RefCount < 0) + ExRaiseStatus(STATUS_INVALID_PARAMETER_2); + + objectHeader = KphObjectToObjectHeader(Object); + /* Increase the reference count. */ + oldRefCount = InterlockedExchangeAdd(&objectHeader->RefCount, RefCount); + + return oldRefCount + RefCount; +} + +/* KphReferenceObjectSafe + * + * Attempts to reference an object and fails if it is being + * destroyed. + * + * Object: The object to reference if it is not being deleted. + * + * Return value: TRUE if the object was referenced, FALSE if + * it was being deleted and was not referenced. + * + * Remarks: + * This function is useful if a reference to an object is + * held, protected by a mutex, and the delete procedure of + * the object's type attempts to acquire the mutex. If this + * function is called while the mutex is owned, you can + * avoid referencing an object that is being destroyed. + * + * IRQL: <= DISPATCH_LEVEL if the object was allocated using the + * non-paged pool, otherwise <= APC_LEVEL. + */ +BOOLEAN KphReferenceObjectSafe( + __in PVOID Object + ) +{ + PKPH_OBJECT_HEADER objectHeader; + BOOLEAN result; + + objectHeader = KphObjectToObjectHeader(Object); + /* Increase the reference count only if it isn't 0 (atomically). */ + result = KphpInterlockedIncrementSafe(&objectHeader->RefCount); + + return result; +} + +/* KphpAllocateObject + * + * Allocates storage for an object. + * + * ObjectSize: The size of the object, excluding the header. + * PoolType: The pool in which to allocate the object. + */ +PKPH_OBJECT_HEADER KphpAllocateObject( + __in SIZE_T ObjectSize, + __in POOL_TYPE PoolType + ) +{ + return ExAllocatePoolWithTag( + PoolType, + KphpAddObjectHeaderSize(ObjectSize), + TAG_KPHOBJ + ); +} + +/* KphpDeferDeleteObject + * + * Queues an object for deletion. + * + * IRQL: <= DISPATCH_LEVEL if the object was allocated using the + * non-paged pool, otherwise <= APC_LEVEL. + */ +VOID KphpDeferDeleteObject( + __in PKPH_OBJECT_HEADER ObjectHeader + ) +{ + PKPH_OBJECT_HEADER nextToFree; + + /* Add the object to the list while saving the old value, atomically. + * Note that it is first-in, last-out. + */ + while (TRUE) + { + nextToFree = KphObjectNextToFree; + ObjectHeader->NextToFree = nextToFree; + + /* Attempt to set the global next-to-free variable. */ + if (InterlockedCompareExchangePointer( + &KphObjectNextToFree, + ObjectHeader, + nextToFree + ) == nextToFree) + { + /* Success. */ + break; + } + + /* Someone else changed the next-to-free variable. + * Go back and try again. + */ + } + + /* Was the to-free list empty before? If so, we need to queue + * the work item. + */ + if (!nextToFree) + { + ExQueueWorkItem(&KphObjectDeferDeleteWorkItem, CriticalWorkQueue); + } +} + +/* KphpDeferDeleteObjectRoutine + * + * Removes and frees objects from the to-free list. + * + * IRQL: PASSIVE_LEVEL + */ +VOID KphpDeferDeleteObjectRoutine( + __in PVOID Parameter + ) +{ + PKPH_OBJECT_HEADER objectHeader = NULL; + + while (TRUE) + { + /* Get the next object to free while replacing the global variable with + * what we needed to free next. + */ + objectHeader = InterlockedExchangePointer(&KphObjectNextToFree, objectHeader); + + /* If we have an object to free, free it and move on to the + * next object. Otherwise, stop. + */ + if (objectHeader) + { + KphpFreeObject(objectHeader); + objectHeader = objectHeader->NextToFree; + } + else + { + break; + } + } +} + +/* KphpFreeObject + * + * Calls the delete procedure for an object and frees its + * allocated storage. + * + * ObjectHeader: A pointer to the object header of an allocated object. + */ +VOID KphpFreeObject( + __in PKPH_OBJECT_HEADER ObjectHeader + ) +{ + /* Object type statistics. */ + InterlockedDecrement(&ObjectHeader->Type->NumberOfObjects); + + /* Remove the object from the global object list. + * If the object manager is being destroyed, don't do this - + * we will deadlock because the deinitialization function + * holds the mutex. + */ + if (!KphObjectDeinitializing) + { + ExAcquireFastMutex(&KphObjectListMutex); + RemoveEntryList(&ObjectHeader->GlobalObjectListEntry); + ExReleaseFastMutex(&KphObjectListMutex); + } + + /* Call the delete procedure if we have one. */ + if (ObjectHeader->Type->DeleteProcedure) + { + ObjectHeader->Type->DeleteProcedure( + KphObjectHeaderToObject(ObjectHeader), + ObjectHeader->Flags + ); + } + + ExFreePoolWithTag( + ObjectHeader, + TAG_KPHOBJ + ); +} diff --git a/branches/ph-plugins/KProcessHacker/resource.rc b/branches/ph-plugins/KProcessHacker/resource.rc new file mode 100644 index 000000000..e02647e28 --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/resource.rc @@ -0,0 +1,53 @@ +#include + +#define VER_COMMA 1,6,0,0 +#define VER_STR "1.6\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 "Copyright (c) 2009 wj32. 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/branches/ph-plugins/KProcessHacker/se.c b/branches/ph-plugins/KProcessHacker/se.c new file mode 100644 index 000000000..ce09c6607 --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/se.c @@ -0,0 +1,102 @@ +/* + * Process Hacker Driver - + * security + * + * Copyright (C) 2009 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/kph.h" +#include "include/se.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, KphOpenProcessTokenEx) +#endif + +/* KphOpenProcessTokenEx + * + * Opens the primary token of the specified process. + */ +NTSTATUS KphOpenProcessTokenEx( + __in HANDLE ProcessHandle, + __in ACCESS_MASK DesiredAccess, + __in ULONG ObjectAttributes, + __out PHANDLE TokenHandle, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PEPROCESS processObject; + PACCESS_TOKEN tokenObject; + HANDLE tokenHandle; + ACCESS_STATE accessState; + CHAR auxData[AUX_ACCESS_DATA_SIZE]; + + status = SeCreateAccessState( + &accessState, + (PAUX_ACCESS_DATA)auxData, + DesiredAccess, + (PGENERIC_MAPPING)KVOFF(*SeTokenObjectType, OffOtiGenericMapping) + ); + + if (!NT_SUCCESS(status)) + { + return status; + } + + if (accessState.RemainingDesiredAccess & MAXIMUM_ALLOWED) + accessState.PreviouslyGrantedAccess |= TOKEN_ALL_ACCESS; + else + accessState.PreviouslyGrantedAccess |= accessState.RemainingDesiredAccess; + + accessState.RemainingDesiredAccess = 0; + + status = ObReferenceObjectByHandle( + ProcessHandle, + 0, + *PsProcessType, + KernelMode, + &processObject, + NULL + ); + + if (!NT_SUCCESS(status)) + { + SeDeleteAccessState(&accessState); + return status; + } + + tokenObject = PsReferencePrimaryToken(processObject); + ObDereferenceObject(processObject); + + status = ObOpenObjectByPointer( + tokenObject, + ObjectAttributes, + &accessState, + 0, + *SeTokenObjectType, + AccessMode, + &tokenHandle + ); + SeDeleteAccessState(&accessState); + ObDereferenceObject(tokenObject); + + if (NT_SUCCESS(status)) + *TokenHandle = tokenHandle; + + return status; +} diff --git a/branches/ph-plugins/KProcessHacker/sources b/branches/ph-plugins/KProcessHacker/sources new file mode 100644 index 000000000..ff6e07b5e --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/sources @@ -0,0 +1,29 @@ +TARGETNAME=kprocesshacker +TARGETTYPE=DRIVER +TARGETPATH=.\ + +INCLUDES=$(DDK_INC_PATH) +LIBS=%BUILD%\lib + +SOURCES= \ + kprocesshacker.c \ + version.c \ + \ + kph.c \ + handle.c \ + hook.c \ + protect.c \ + ref.c \ + sync.c \ + sysservice.c \ + sysservicedata.c \ + test.c \ + trace.c \ + util.c \ + \ + io.c \ + mm.c \ + ob.c \ + ps.c \ + se.c \ + resource.rc diff --git a/branches/ph-plugins/KProcessHacker/sync.c b/branches/ph-plugins/KProcessHacker/sync.c new file mode 100644 index 000000000..99bd46bf8 --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/sync.c @@ -0,0 +1,312 @@ +/* + * Process Hacker Driver - + * synchronization code + * + * Copyright (C) 2009 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/sync.h" +#include "include/debug.h" + +ULONG KphpCountBits( + __in ULONG_PTR Number + ); + +VOID KphpProcessorLockDpc( + __in PKDPC Dpc, + __in PVOID DeferredContext, + __in PVOID SystemArgument1, + __in PVOID SystemArgument2 + ); + +/* KphfAcquireGuardedLock + * + * Acquires a guarded lock and raises the IRQL to APC_LEVEL. + * + * IRQL: <= APC_LEVEL + */ +VOID FASTCALL KphfAcquireGuardedLock( + __inout PKPH_GUARDED_LOCK Lock + ) +{ + KIRQL oldIrql; + + ASSERT(KeGetCurrentIrql() <= APC_LEVEL); + + /* Raise to APC_LEVEL. */ + oldIrql = KeRaiseIrql(APC_LEVEL, &oldIrql); + + /* Acquire the spinlock. */ + KphAcquireBitSpinLock(&Lock->Value, KPH_GUARDED_LOCK_ACTIVE_SHIFT); + + /* Now that we have the lock, we must save the old IRQL. */ + /* Clear the old IRQL. */ + Lock->Value &= KPH_GUARDED_LOCK_FLAGS; + /* Set the new IRQL. */ + Lock->Value |= oldIrql; +} + +/* KphfReleaseGuardedLock + * + * Releases a guarded lock and restores the old IRQL. + * + * IRQL: >= APC_LEVEL + */ +VOID FASTCALL KphfReleaseGuardedLock( + __inout PKPH_GUARDED_LOCK Lock + ) +{ + KIRQL oldIrql; + + ASSERT(KeGetCurrentIrql() >= APC_LEVEL); + + /* Get the old IRQL. */ + oldIrql = (KIRQL)(Lock->Value & ~KPH_GUARDED_LOCK_FLAGS); + /* Unlock the spinlock. */ + KphReleaseBitSpinLock(&Lock->Value, KPH_GUARDED_LOCK_ACTIVE_SHIFT); + /* Restore the old IRQL. */ + KeLowerIrql(oldIrql); +} + +/* KphAcquireProcessorLock + * + * Raises the IRQL to DISPATCH_LEVEL and prevents threads from + * executing on other processors until the processor lock is released. + * Blocks if the supplied processor lock is already in use. + * + * ProcessorLock: A processor lock structure that is present in + * non-paged memory. + * + * Comments: + * Here is how the processor lock works: + * 1. Tries to acquire the mutex in the processor lock, and + * blocks until it can be obtained. + * 2. Initializes a DPC for each processor on the computer. + * 3. Raises the IRQL to DISPATCH_LEVEL to make sure the + * code is not interrupted by a context switch. + * 4. Queues each of the previously-initialized DPCs, except if + * it is targeted at the current processor. + * 5. Since DPCs run at DISPATCH_LEVEL, they have exclusive + * control of the processor. As each runs, they increment + * a counter in the processor lock. They then enter a loop. + * 6. The routine waits for the counter to become n - 1, + * signaling that all (other) processors have been acquired + * (where n is the number of processors). + * 7. It returns. Any code from here will be running in + * DISPATCH_LEVEL and will be the only code running on the + * machine. + * Thread safety: Full + * IRQL: <= APC_LEVEL + */ +BOOLEAN KphAcquireProcessorLock( + __inout PKPH_PROCESSOR_LOCK ProcessorLock + ) +{ + ULONG i; + ULONG numberProcessors; + ULONG currentProcessor; + + /* Acquire the processor lock guarded lock. */ + KphAcquireGuardedLock(&ProcessorLock->Lock); + + /* Reset some state. */ + ASSERT(ProcessorLock->AcquiredProcessors == 0); + ProcessorLock->AcquiredProcessors = 0; + ProcessorLock->ReleaseSignal = 0; /* IMPORTANT */ + + /* Get the number of processors. */ + numberProcessors = KphpCountBits(KeQueryActiveProcessors()); + + /* If there's only one processor we can simply raise the IRQL and exit. */ + if (numberProcessors == 1) + { + dprintf("KphAcquireProcessorLock: Only one processor, raising IRQL and exiting...\n"); + KeRaiseIrql(DISPATCH_LEVEL, &ProcessorLock->OldIrql); + ProcessorLock->Acquired = TRUE; + + return TRUE; + } + + /* Allocate storage for the DPCs. */ + ProcessorLock->Dpcs = ExAllocatePoolWithTag( + NonPagedPool, + sizeof(KDPC) * numberProcessors, + TAG_SYNC_DPC + ); + + if (!ProcessorLock->Dpcs) + { + dprintf("KphAcquireProcessorLock: Could not allocate storage for DPCs!\n"); + KphReleaseGuardedLock(&ProcessorLock->Lock); + return FALSE; + } + + /* Initialize the DPCs. */ + for (i = 0; i < numberProcessors; i++) + { + KeInitializeDpc(&ProcessorLock->Dpcs[i], KphpProcessorLockDpc, NULL); + KeSetTargetProcessorDpc(&ProcessorLock->Dpcs[i], (CCHAR)i); + KeSetImportanceDpc(&ProcessorLock->Dpcs[i], HighImportance); + } + + /* Raise the IRQL to DISPATCH_LEVEL to prevent context switching. */ + KeRaiseIrql(DISPATCH_LEVEL, &ProcessorLock->OldIrql); + /* Get the current processor number. */ + currentProcessor = KeGetCurrentProcessorNumber(); + + /* Queue the DPCs (except on the current processor). */ + for (i = 0; i < numberProcessors; i++) + if (i != currentProcessor) + KeInsertQueueDpc(&ProcessorLock->Dpcs[i], ProcessorLock, NULL); + + /* Spinwait for all (other) processors to be acquired. */ + KphSpinUntilEqual(&ProcessorLock->AcquiredProcessors, numberProcessors - 1); + + dprintf("KphAcquireProcessorLock: All processors acquired.\n"); + ProcessorLock->Acquired = TRUE; + + return TRUE; +} + +/* KphInitializeProcessorLock + * + * Initializes a processor lock. + * + * ProcessorLock: A processor lock structure that is present in + * non-paged memory. + * + * IRQL: Any + */ +VOID KphInitializeProcessorLock( + __out PKPH_PROCESSOR_LOCK ProcessorLock + ) +{ + KphInitializeGuardedLock(&ProcessorLock->Lock, FALSE); + ProcessorLock->Dpcs = NULL; + ProcessorLock->AcquiredProcessors = 0; + ProcessorLock->ReleaseSignal = 0; + ProcessorLock->OldIrql = PASSIVE_LEVEL; + ProcessorLock->Acquired = FALSE; +} + +/* KphReleaseProcessorLock + * + * Allows threads to execute on other processors and restores the IRQL. + * + * ProcessorLock: A processor lock structure that is present in + * non-paged memory. + * + * Comments: + * Here is how the processor lock is released: + * 1. Sets the signal to release the processors. The DPCs that are + * currently waiting for the signal will return and decrement + * the acquired processors counter. + * 2. Waits for the acquired processors counter to become zero. + * 3. Restores the old IRQL. This will always be APC_LEVEL due to + * the mutex. + * 4. Frees the storage allocated for the DPCs. + * 5. Releases the processor lock mutex. This will restore the IRQL + * back to normal. + * Thread safety: Full + * IRQL: DISPATCH_LEVEL + */ +VOID KphReleaseProcessorLock( + __inout PKPH_PROCESSOR_LOCK ProcessorLock + ) +{ + if (!ProcessorLock->Acquired) + return; + + /* Signal for the acquired processors to be released. */ + InterlockedExchange(&ProcessorLock->ReleaseSignal, 1); + + /* Spinwait for all acquired processors to be released. */ + KphSpinUntilEqual(&ProcessorLock->AcquiredProcessors, 0); + + dprintf("KphReleaseProcessorLock: All processors released.\n"); + + /* Restore the old IRQL (should always be APC_LEVEL due to the + * fast mutex). */ + KeLowerIrql(ProcessorLock->OldIrql); + + /* Free the DPCs if necessary. */ + if (ProcessorLock->Dpcs != NULL) + { + ExFreePoolWithTag(ProcessorLock->Dpcs, TAG_SYNC_DPC); + ProcessorLock->Dpcs = NULL; + } + + ProcessorLock->Acquired = FALSE; + + /* Release the processor lock guarded lock. This will restore the + * IRQL back to what it was before the processor lock was + * acquired. + */ + KphReleaseGuardedLock(&ProcessorLock->Lock); +} + +/* KphpCountBits + * + * Counts the number of bits set in an integer. + */ +ULONG KphpCountBits( + __in ULONG_PTR Number + ) +{ + ULONG count = 0; + + while (Number) + { + count++; + Number &= Number - 1; + } + + return count; +} + +/* KphpProcessorLockDpc + * + * The DPC routine which "locks" processors. + * + * Thread safety: Full + * IRQL: DISPATCH_LEVEL + */ +VOID KphpProcessorLockDpc( + __in PKDPC Dpc, + __in PVOID DeferredContext, + __in PVOID SystemArgument1, + __in PVOID SystemArgument2 + ) +{ + PKPH_PROCESSOR_LOCK processorLock = (PKPH_PROCESSOR_LOCK)SystemArgument1; + + ASSERT(processorLock != NULL); + + dprintf("KphpProcessorLockDpc: Acquiring processor %d.\n", KeGetCurrentProcessorNumber()); + + /* Increase the number of acquired processors. */ + InterlockedIncrement(&processorLock->AcquiredProcessors); + + /* Spin until we get the signal to release the processor. */ + KphSpinUntilNotEqual(&processorLock->ReleaseSignal, 0); + + /* Decrease the number of acquired processors. */ + InterlockedDecrement(&processorLock->AcquiredProcessors); + + dprintf("KphpProcessorLockDpc: Releasing processor %d.\n", KeGetCurrentProcessorNumber()); +} diff --git a/branches/ph-plugins/KProcessHacker/sysservice.c b/branches/ph-plugins/KProcessHacker/sysservice.c new file mode 100644 index 000000000..0568e7d07 --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/sysservice.c @@ -0,0 +1,2050 @@ +/* + * Process Hacker Driver - + * system service logging + * + * Copyright (C) 2009 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 . + */ + +/* ================ IMPORTANT ================ + * Please read the comments in KphpSsNewKiFastCallEntry to find out how + * KiFastCallEntry can be hooked. + * + * Note that the ONLY SUPPORTED METHOD of hooking is KiFastCallEntry, + * which means you MUST be using a CPU which supports sysenter. + * =========================================== + */ + +#include "include/sysservicep.h" +#include "include/hook.h" +#include "include/sync.h" +#include "include/trace.h" + +extern PDRIVER_OBJECT KphDriverObject; + +/* A fast mutex guarding starting/stopping system service logging. */ +FAST_MUTEX KphSsMutex; +/* Whether system service logging has been initialized. */ +BOOLEAN KphSsInitialized = FALSE; +/* The KiFastCallEntry hook. */ +KPH_HOOK KphSsKiFastCallEntryHook; +/* The number of active loggers. */ +ULONG KphSsNumberOfActiveLoggers = 0; + +/* The object type for client entries. */ +PKPH_OBJECT_TYPE KphSsClientEntryType; +/* The object type for ruleset entries. */ +PKPH_OBJECT_TYPE KphSsRuleSetEntryType; +/* The object type for rule entries. */ +PKPH_OBJECT_TYPE KphSsRuleEntryType; + +/* The list of ruleset entries. */ +LIST_ENTRY KphSsRuleSetListHead; +/* A push lock guarding accesses to the ruleset list. */ +EX_PUSH_LOCK KphSsRuleSetListPushLock; + +/* KphSsLogInit + * + * Initializes system service logging. + */ +NTSTATUS KphSsLogInit() +{ + NTSTATUS status = STATUS_SUCCESS; + + /* Initialize the system service call data. */ + KphSsDataInit(); + + /* Initialize the ruleset list. */ + InitializeListHead(&KphSsRuleSetListHead); + ExInitializeFastMutex(&KphSsMutex); + ExInitializePushLock(&KphSsRuleSetListPushLock); + + /* Initialize the object types. */ + status = KphCreateObjectType( + &KphSsClientEntryType, + NonPagedPool, + 0, + KphpSsClientEntryDeleteProcedure + ); + + if (!NT_SUCCESS(status)) + return status; + + status = KphCreateObjectType( + &KphSsRuleSetEntryType, + NonPagedPool, + 0, + KphpSsRuleSetEntryDeleteProcedure + ); + + if (!NT_SUCCESS(status)) + { + KphDereferenceObject(KphSsClientEntryType); + return status; + } + + status = KphCreateObjectType( + &KphSsRuleEntryType, + NonPagedPool, + 0, + NULL + ); + + if (!NT_SUCCESS(status)) + { + KphDereferenceObject(KphSsClientEntryType); + KphDereferenceObject(KphSsRuleSetEntryType); + return status; + } + + return status; +} + +/* KphSsLogDeinit + * + * Frees system service logging data. + */ +NTSTATUS KphSsLogDeinit() +{ + KphSsDataDeinit(); + + return STATUS_SUCCESS; +} + +/* KphSsLogStart + * + * Starts system service logging. + */ +NTSTATUS KphSsLogStart() +{ +#ifdef _X86_ + NTSTATUS status = STATUS_SUCCESS; + + /* Make sure we have the KiFastCallEntry+x address. */ + if (!__KiFastCallEntry) + return STATUS_NOT_SUPPORTED; + + ExAcquireFastMutex(&KphSsMutex); + + if (KphSsInitialized) + { + ExReleaseFastMutex(&KphSsMutex); + return STATUS_UNSUCCESSFUL; + } + + /* Hook KiFastCallEntry. Logging will start from now. */ + KphInitializeHook( + &KphSsKiFastCallEntryHook, + __KiFastCallEntry, + KphpSsNewKiFastCallEntry + ); + status = KphHook(&KphSsKiFastCallEntryHook); + + if (!NT_SUCCESS(status)) + { + ExReleaseFastMutex(&KphSsMutex); + return status; + } + + KphSsInitialized = TRUE; + + ExReleaseFastMutex(&KphSsMutex); + + return status; +#else + return STATUS_NOT_SUPPORTED; +#endif +} + +/* KphSsLogStop + * + * Stops system service logging. + */ +NTSTATUS KphSsLogStop() +{ +#ifdef _X86_ + NTSTATUS status = STATUS_SUCCESS; + + ExAcquireFastMutex(&KphSsMutex); + + if (!KphSsInitialized) + { + ExReleaseFastMutex(&KphSsMutex); + return STATUS_UNSUCCESSFUL; + } + + status = KphUnhook(&KphSsKiFastCallEntryHook); + + if (!NT_SUCCESS(status)) + { + ExReleaseFastMutex(&KphSsMutex); + return status; + } + + /* Spin until the logger count reaches 0. */ + KphSpinUntilEqual(&KphSsNumberOfActiveLoggers, 0); + + KphSsInitialized = FALSE; + + ExReleaseFastMutex(&KphSsMutex); + + return status; +#else + return STATUS_NOT_SUPPORTED; +#endif +} + +/* KphSsCreateClientEntry + * + * Creates a client entry which describes a client of the + * system service logger. Clients receive system service log events. + * Note that a client may have several ruleset entries associated + * with it. + * + * ClientEntry: A variable which receives a pointer to the client entry. + * ProcessHandle: A handle to the client process, with PROCESS_VM_WRITE + * access. + * ReadSemaphoreHandle: A handle to a semaphore which is released when an + * event is written to the client buffer. The client must wait for the + * semaphore when it is about to read a block. + * WriteSemaphoreHandle: A handle to a semaphore which is acquired when an + * event is about to be written to the client buffer. If the semaphore + * cannot be acquired immediately, the event is dropped. The client must + * continually read the buffer and release the semaphore. + * BufferBase: A pointer to a buffer in the client process. + * BufferSize: The size of the buffer, in bytes. + * AccessMode: The mode to use when probing arguments. + */ +NTSTATUS KphSsCreateClientEntry( + __out PKPHSS_CLIENT_ENTRY *ClientEntry, + __in HANDLE ProcessHandle, + __in HANDLE ReadSemaphoreHandle, + __in HANDLE WriteSemaphoreHandle, + __in PVOID BufferBase, + __in ULONG BufferSize, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PKPHSS_CLIENT_ENTRY clientEntry; + PEPROCESS processObject; + PKSEMAPHORE readSemaphore; + PKSEMAPHORE writeSemaphore; + + /* Probe. */ + if (AccessMode != KernelMode) + { + __try + { + ProbeForWrite(BufferBase, BufferSize, 1); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + + /* Reference the client process. */ + status = ObReferenceObjectByHandle( + ProcessHandle, + PROCESS_VM_WRITE, + *PsProcessType, + AccessMode, + &processObject, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + /* Reference the read semaphore. */ + status = ObReferenceObjectByHandle( + ReadSemaphoreHandle, + SEMAPHORE_MODIFY_STATE, + *ExSemaphoreObjectType, + AccessMode, + &readSemaphore, + NULL + ); + + if (!NT_SUCCESS(status)) + { + ObDereferenceObject(processObject); + return status; + } + + /* Reference the write semaphore. */ + status = ObReferenceObjectByHandle( + WriteSemaphoreHandle, + SEMAPHORE_MODIFY_STATE, + *ExSemaphoreObjectType, + AccessMode, + &writeSemaphore, + NULL + ); + + if (!NT_SUCCESS(status)) + { + ObDereferenceObject(processObject); + ObDereferenceObject(readSemaphore); + return status; + } + + /* Create the client entry object. */ + status = KphCreateObject( + &clientEntry, + sizeof(KPHSS_CLIENT_ENTRY), + 0, + KphSsClientEntryType, + 0 + ); + + if (!NT_SUCCESS(status)) + { + ObDereferenceObject(processObject); + ObDereferenceObject(readSemaphore); + ObDereferenceObject(writeSemaphore); + + return status; + } + + clientEntry->Process = processObject; + clientEntry->Enabled = TRUE; + clientEntry->ReadSemaphore = readSemaphore; + clientEntry->WriteSemaphore = writeSemaphore; + ExInitializeFastMutex(&clientEntry->BufferMutex); + clientEntry->BufferBase = BufferBase; + clientEntry->BufferSize = BufferSize; + clientEntry->BufferCursor = 0; + clientEntry->NumberOfBlocksWritten = 0; + clientEntry->NumberOfBlocksDropped = 0; + + *ClientEntry = clientEntry; + + return status; +} + +/* KphSsEnableClientEntry + * + * Enables or disables a client entry. + */ +NTSTATUS KphSsEnableClientEntry( + __in PKPHSS_CLIENT_ENTRY ClientEntry, + __in BOOLEAN Enable + ) +{ + if (Enable) + ClientEntry->Enabled = TRUE; + else + ClientEntry->Enabled = FALSE; + + return STATUS_SUCCESS; +} + +/* KphSsQueryClientEntry + * + * Queries information about a client entry. + */ +NTSTATUS KphSsQueryClientEntry( + __in PKPHSS_CLIENT_ENTRY ClientEntry, + __out_bcount_opt(ClientInformationLength) PKPHSS_CLIENT_INFORMATION ClientInformation, + __in ULONG ClientInformationLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status = STATUS_SUCCESS; + + /* Probe the return length if necessary. */ + if (AccessMode != KernelMode) + { + __try + { + ProbeForWrite(ReturnLength, sizeof(ULONG), 1); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + + /* Check the length. */ + if (ClientInformationLength >= sizeof(KPHSS_CLIENT_INFORMATION)) + { + if (ClientInformation) + { + __try + { + /* Probe the buffer if we're not from kernel-mode. */ + if (AccessMode != KernelMode) + ProbeForWrite(ClientInformation, sizeof(KPHSS_CLIENT_INFORMATION), 1); + + ClientInformation->ProcessId = PsGetProcessId(ClientEntry->Process); + ClientInformation->BufferBase = ClientEntry->BufferBase; + ClientInformation->BufferSize = ClientEntry->BufferSize; + ClientInformation->NumberOfBlocksWritten = ClientEntry->NumberOfBlocksWritten; + ClientInformation->NumberOfBlocksDropped = ClientEntry->NumberOfBlocksDropped; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + } + } + else + { + status = STATUS_BUFFER_TOO_SMALL; + } + + /* Pass the return length back if requested. */ + if (ReturnLength) + { + __try + { + *ReturnLength = sizeof(KPHSS_CLIENT_INFORMATION); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + } + + return status; +} + +/* KphpSsClientEntryDeleteProcedure + * + * Performs cleanup for a client entry. + */ +VOID NTAPI KphpSsClientEntryDeleteProcedure( + __in PVOID Object, + __in ULONG Flags + ) +{ + PKPHSS_CLIENT_ENTRY clientEntry = (PKPHSS_CLIENT_ENTRY)Object; + + ObDereferenceObject(clientEntry->Process); + ObDereferenceObject(clientEntry->ReadSemaphore); + ObDereferenceObject(clientEntry->WriteSemaphore); +} + +/* KphSsCreateRuleSetEntry + * + * Creates a ruleset entry which contains a list of rules + * and an action to perform. + */ +NTSTATUS KphSsCreateRuleSetEntry( + __out PKPHSS_RULESET_ENTRY *RuleSetEntry, + __in PKPHSS_CLIENT_ENTRY ClientEntry, + __in KPHSS_FILTER_TYPE DefaultFilterType, + __in KPHSS_RULESET_ACTION Action + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PKPHSS_RULESET_ENTRY ruleSetEntry; + + /* Make sure the action is valid. */ + if (Action < LogRuleSetAction || Action >= MaxRuleSetAction) + return STATUS_INVALID_PARAMETER_3; + + /* Create the ruleset object. */ + status = KphCreateObject( + &ruleSetEntry, + sizeof(KPHSS_RULESET_ENTRY), + 0, + KphSsRuleSetEntryType, + 0 + ); + + if (!NT_SUCCESS(status)) + return status; + + /* Initialize the ruleset object. */ + KphReferenceObject(ClientEntry); + ruleSetEntry->Client = ClientEntry; + ruleSetEntry->DefaultFilterType = DefaultFilterType; + ruleSetEntry->Action = Action; + ruleSetEntry->NextRuleHandle = 4; + ExInitializePushLock(&ruleSetEntry->RuleListPushLock); + InitializeListHead(&ruleSetEntry->RuleListHead); + + /* Add the ruleset to the list. */ + KeEnterCriticalRegion(); + ExAcquirePushLockExclusive(&KphSsRuleSetListPushLock); + InsertHeadList(&KphSsRuleSetListHead, &ruleSetEntry->RuleSetListEntry); + ExReleasePushLock(&KphSsRuleSetListPushLock); + KeLeaveCriticalRegion(); + + *RuleSetEntry = ruleSetEntry; + + return status; +} + +/* KphpSsRuleSetEntryDeleteProcedure + * + * Performs cleanup for a ruleset entry. + */ +VOID NTAPI KphpSsRuleSetEntryDeleteProcedure( + __in PVOID Object, + __in ULONG Flags + ) +{ + PKPHSS_RULESET_ENTRY ruleSetEntry = (PKPHSS_RULESET_ENTRY)Object; + PLIST_ENTRY currentRuleListEntry; + + /* Dereference the client entry. */ + KphDereferenceObject(ruleSetEntry->Client); + + KeEnterCriticalRegion(); + + /* Dereference all rules in the ruleset. */ + ExAcquirePushLockExclusive(&ruleSetEntry->RuleListPushLock); + + currentRuleListEntry = ruleSetEntry->RuleListHead.Flink; + + while (currentRuleListEntry != &ruleSetEntry->RuleListHead) + { + PLIST_ENTRY nextEntry; + + /* Save the next entry pointer since currentRuleListEntry may + * be deallocated due to the dereference. + */ + nextEntry = currentRuleListEntry->Flink; + KphDereferenceObject(KPHSS_RULE_ENTRY(currentRuleListEntry)); + currentRuleListEntry = nextEntry; + } + + ExReleasePushLock(&ruleSetEntry->RuleListPushLock); + + /* Remove the ruleset from the list. */ + ExAcquirePushLockExclusive(&KphSsRuleSetListPushLock); + RemoveEntryList(&ruleSetEntry->RuleSetListEntry); + ExReleasePushLock(&KphSsRuleSetListPushLock); + + KeLeaveCriticalRegion(); +} + +/* KphSsAddProcessIdRule + * + * Adds a process ID rule entry to a ruleset entry. + */ +NTSTATUS KphSsAddProcessIdRule( + __out PKPHSS_RULE_ENTRY *RuleEntry, + __in PKPHSS_RULESET_ENTRY RuleSetEntry, + __in KPHSS_FILTER_TYPE FilterType, + __in HANDLE ProcessId + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PKPHSS_RULE_ENTRY ruleEntry; + + /* Add the rule. */ + status = KphpSsAddRule(&ruleEntry, RuleSetEntry, FilterType, ProcessIdRuleType); + + if (!NT_SUCCESS(status)) + return status; + + ruleEntry->ProcessIdRule.ProcessId = ProcessId; + ruleEntry->Initialized = TRUE; + + *RuleEntry = ruleEntry; + + return status; +} + +/* KphSsAddThreadIdRule + * + * Adds a thread ID rule entry to a ruleset entry. + */ +NTSTATUS KphSsAddThreadIdRule( + __out PKPHSS_RULE_ENTRY *RuleEntry, + __in PKPHSS_RULESET_ENTRY RuleSetEntry, + __in KPHSS_FILTER_TYPE FilterType, + __in HANDLE ThreadId + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PKPHSS_RULE_ENTRY ruleEntry; + + /* Add the rule. */ + status = KphpSsAddRule(&ruleEntry, RuleSetEntry, FilterType, ThreadIdRuleType); + + if (!NT_SUCCESS(status)) + return status; + + ruleEntry->ThreadIdRule.ThreadId = ThreadId; + ruleEntry->Initialized = TRUE; + + *RuleEntry = ruleEntry; + + return status; +} + +/* KphSsAddPreviousModeRule + * + * Adds a previous mode rule entry to a ruleset entry. + */ +NTSTATUS KphSsAddPreviousModeRule( + __out PKPHSS_RULE_ENTRY *RuleEntry, + __in PKPHSS_RULESET_ENTRY RuleSetEntry, + __in KPHSS_FILTER_TYPE FilterType, + __in KPROCESSOR_MODE PreviousMode + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PKPHSS_RULE_ENTRY ruleEntry; + + /* Add the rule. */ + status = KphpSsAddRule(&ruleEntry, RuleSetEntry, FilterType, PreviousModeRuleType); + + if (!NT_SUCCESS(status)) + return status; + + ruleEntry->PreviousModeRule.PreviousMode = PreviousMode; + ruleEntry->Initialized = TRUE; + + *RuleEntry = ruleEntry; + + return status; +} + +/* KphSsAddNumberRule + * + * Adds a system service number rule entry to a ruleset entry. + */ +NTSTATUS KphSsAddNumberRule( + __out PKPHSS_RULE_ENTRY *RuleEntry, + __in PKPHSS_RULESET_ENTRY RuleSetEntry, + __in KPHSS_FILTER_TYPE FilterType, + __in ULONG Number + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PKPHSS_RULE_ENTRY ruleEntry; + + /* Add the rule. */ + status = KphpSsAddRule(&ruleEntry, RuleSetEntry, FilterType, NumberRuleType); + + if (!NT_SUCCESS(status)) + return status; + + ruleEntry->NumberRule.Number = Number; + ruleEntry->Initialized = TRUE; + + *RuleEntry = ruleEntry; + + return status; +} + +/* KphSsGetHandleRule + * + * Gets the handle of a rule. + */ +HANDLE KphSsGetHandleRule( + __in PKPHSS_RULE_ENTRY RuleEntry + ) +{ + return RuleEntry->Handle; +} + +/* KphSsRemoveRule + * + * Removes a rule entry from a ruleset entry. + */ +NTSTATUS KphSsRemoveRule( + __in PKPHSS_RULESET_ENTRY RuleSetEntry, + __in HANDLE RuleEntryHandle + ) +{ + PLIST_ENTRY currentListEntry; + + KeEnterCriticalRegion(); + ExAcquirePushLockExclusive(&RuleSetEntry->RuleListPushLock); + + /* Find the rule in the ruleset. */ + + currentListEntry = RuleSetEntry->RuleListHead.Flink; + + while (currentListEntry != &RuleSetEntry->RuleListHead) + { + PKPHSS_RULE_ENTRY ruleEntry = KPHSS_RULE_ENTRY(currentListEntry); + + if (ruleEntry->Handle == RuleEntryHandle) + { + /* Remove the rule from the list. */ + RemoveEntryList(&ruleEntry->RuleListEntry); + /* Dereference the rule (it was referenced when it + * got added to the list). + */ + KphDereferenceObject(ruleEntry); + + ExReleasePushLock(&RuleSetEntry->RuleListPushLock); + KeLeaveCriticalRegion(); + + return STATUS_SUCCESS; + } + + currentListEntry = currentListEntry->Flink; + } + + ExReleasePushLock(&RuleSetEntry->RuleListPushLock); + KeLeaveCriticalRegion(); + + return STATUS_INVALID_PARAMETER_2; +} + +/* KphpSsAddRule + * + * Adds a rule entry to a ruleset entry. + */ +NTSTATUS KphpSsAddRule( + __out PKPHSS_RULE_ENTRY *RuleEntry, + __in PKPHSS_RULESET_ENTRY RuleSetEntry, + __in KPHSS_FILTER_TYPE FilterType, + __in KPHSS_RULE_TYPE RuleType + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PKPHSS_RULE_ENTRY ruleEntry; + + /* Make sure the filter/rule type is valid. */ + if (FilterType < IncludeFilterType || FilterType >= MaxFilterType) + return STATUS_INVALID_PARAMETER_3; + if (RuleType < ProcessIdRuleType || RuleType >= MaxRuleType) + return STATUS_INVALID_PARAMETER_4; + + /* Create the rule entry object. */ + status = KphCreateObject( + &ruleEntry, + sizeof(KPHSS_RULE_ENTRY), + 0, + KphSsRuleEntryType, + 0 + ); + + if (!NT_SUCCESS(status)) + return status; + + /* Initialize the object. */ + ruleEntry->Initialized = FALSE; + ruleEntry->FilterType = FilterType; + ruleEntry->RuleType = RuleType; + + /* Get a handle for the rule. */ + ruleEntry->Handle = (HANDLE)(ULONG_PTR)InterlockedExchangeAdd( + &RuleSetEntry->NextRuleHandle, + KPHSS_RULE_HANDLE_INCREMENT + ); + + /* Add the rule to the ruleset. */ + KeEnterCriticalRegion(); + ExAcquirePushLockExclusive(&RuleSetEntry->RuleListPushLock); + InsertTailList(&RuleSetEntry->RuleListHead, &ruleEntry->RuleListEntry); + ExReleasePushLock(&RuleSetEntry->RuleListPushLock); + KeLeaveCriticalRegion(); + /* Add a reference for the rule being on the list. */ + KphReferenceObject(ruleEntry); + + *RuleEntry = ruleEntry; + + return status; +} + +/* KphpSsCreateEventBlock + * + * Allocates and initializes an event block. + * + * EventBlock: A variable which receives a pointer to the event block. + * Thread: The thread for which the event is being generated. + * Number: The system service number. + * Arguments: A pointer to the caller-supplied arguments. + * NumberOfArguments: The number of arguments, in ULONGs. + */ +NTSTATUS KphpSsCreateEventBlock( + __out PKPHSS_EVENT_BLOCK *EventBlock, + __in PKTHREAD Thread, + __in ULONG Number, + __in ULONG *Arguments, + __in ULONG NumberOfArguments + ) +{ + PKPHSS_EVENT_BLOCK eventBlock; + KPROCESSOR_MODE previousMode; + ULONG eventBlockSize; + ULONG argumentsSize; + ULONG traceSize; + PVOID stackTrace[MAX_STACK_DEPTH * 2]; + ULONG capturedFrames; + + /* Make sure the argument count isn't too large. */ + if (NumberOfArguments > MAX_USHORT) + return STATUS_INVALID_PARAMETER; + + previousMode = ExGetPreviousMode(); + + /* Capture kernel-mode and user-mode stack traces. + * We do this before we allocate the event block so + * we can calculate how large the block should be. + */ + + /* Get a kernel-mode stack trace. */ + capturedFrames = KphCaptureStackBackTrace( + 0, + MAX_STACK_DEPTH - 1, + 0, + stackTrace, + NULL + ); + + if (PsGetCurrentProcess() != PsInitialSystemProcess) + { + /* Get a user-mode stack trace. */ + capturedFrames += KphCaptureStackBackTrace( + 0, + MAX_STACK_DEPTH - 1, + RTL_WALK_USER_MODE_STACK, + &stackTrace[capturedFrames], + NULL + ); + } + + /* Calculate the size of the event block. */ + argumentsSize = NumberOfArguments * sizeof(ULONG); + traceSize = capturedFrames * sizeof(PVOID); + eventBlockSize = sizeof(KPHSS_EVENT_BLOCK) + argumentsSize + traceSize; + + /* Make sure the block size isn't too large. */ + if (eventBlockSize > MAX_USHORT) + return STATUS_INVALID_PARAMETER; + + /* Allocate the event block. */ + eventBlock = ExAllocatePoolWithTag(PagedPool, eventBlockSize, TAG_EVENT_BLOCK); + + if (!eventBlock) + return STATUS_INSUFFICIENT_RESOURCES; + + /* Initialize the event block. */ + eventBlock->Header.Size = (USHORT)eventBlockSize; + eventBlock->Header.Type = EventBlockType; + eventBlock->Flags = 0; + KeQuerySystemTime(&eventBlock->Time); + eventBlock->ClientId.UniqueThread = PsGetThreadId(Thread); + eventBlock->ClientId.UniqueProcess = PsGetProcessId(IoThreadToProcess(Thread)); + eventBlock->Number = Number; + eventBlock->NumberOfArguments = (USHORT)NumberOfArguments; + eventBlock->ArgumentsOffset = sizeof(KPHSS_EVENT_BLOCK); + eventBlock->TraceCount = (USHORT)capturedFrames; + eventBlock->TraceOffset = (USHORT)(sizeof(KPHSS_EVENT_BLOCK) + argumentsSize); + + /* Set the flags according to the previous mode. */ + if (previousMode == UserMode) + eventBlock->Flags |= KPHSS_EVENT_USER_MODE; + else if (previousMode == KernelMode) + eventBlock->Flags |= KPHSS_EVENT_KERNEL_MODE; + + /* Probe and copy the arguments. */ + if (previousMode != KernelMode) + { + __try + { + ProbeForRead(Arguments, argumentsSize, 4); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + eventBlock->Flags |= KPHSS_EVENT_PROBE_ARGUMENTS_FAILED; + } + } + + __try + { + /* Copy the arguments to the space immediately after the event block. */ + memcpy((PCHAR)eventBlock + eventBlock->ArgumentsOffset, Arguments, argumentsSize); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + eventBlock->Flags |= KPHSS_EVENT_COPY_ARGUMENTS_FAILED; + } + + /* Copy the stack trace. */ + memcpy((PCHAR)eventBlock + eventBlock->TraceOffset, stackTrace, traceSize); + + /* Pass the pointer to the event block back. */ + *EventBlock = eventBlock; + + return STATUS_SUCCESS; +} + +/* KphpSsFreeEventBlock + * + * Frees an event block created by KphpSsCreateEventBlock. + */ +VOID KphpSsFreeEventBlock( + __in PKPHSS_EVENT_BLOCK EventBlock + ) +{ + ExFreePoolWithTag(EventBlock, TAG_EVENT_BLOCK); +} + +/* KphpSsCaptureSimpleArgument + * + * Captures a simple (1-, 2-, 4- or 8-byte) argument. + */ +NTSTATUS KphpSsCaptureSimpleArgument( + __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock, + __in PVOID Argument, + __in KPHSS_ARGUMENT_TYPE Type, + __in KPROCESSOR_MODE PreviousMode + ) +{ + PKPHSS_ARGUMENT_BLOCK argumentBlock; + ULONG size; + LARGE_INTEGER value; + + /* Return if we have a NULL pointer. */ + if (!Argument) + return STATUS_INVALID_PARAMETER_2; + + /* Get the proper argument size based on the argument type. */ + switch (Type) + { + case Int8Argument: + size = sizeof(BOOLEAN); + break; + case Int16Argument: + size = sizeof(SHORT); + break; + case Int32Argument: + size = sizeof(LONG); + break; + case Int64Argument: + size = sizeof(LARGE_INTEGER); + break; + default: + return STATUS_INVALID_PARAMETER_3; + } + + /* Probe and read the value. */ + __try + { + if (PreviousMode != KernelMode) + ProbeForRead(Argument, size, 1); + + memcpy(&value, Argument, size); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + + /* Allocate an argument block. */ + argumentBlock = KphpSsAllocateArgumentBlock(size, Type); + + if (!argumentBlock) + return STATUS_INSUFFICIENT_RESOURCES; + + /* Copy the value into the argument block. */ + memcpy(&argumentBlock->Simple, &value, size); + *ArgumentBlock = argumentBlock; + + return STATUS_SUCCESS; +} + +/* KphpSsCaptureHandleArgument + * + * Captures a handle argument. + */ +NTSTATUS KphpSsCaptureHandleArgument( + __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock, + __in HANDLE Argument, + __in KPROCESSOR_MODE PreviousMode + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PKPHSS_ARGUMENT_BLOCK argumentBlock; + ULONG bufferLength; + PVOID object; + POBJECT_TYPE objectType; + PUNICODE_STRING objectTypeName; + PUNICODE_STRING objectNameInfo; + ULONG returnLength; + PKPHSS_HANDLE handleInfo; + PKPHSS_WSTRING wString; + + /* Return if we have a NULL handle. */ + if (!Argument) + return STATUS_INVALID_PARAMETER_2; + + /* Make sure the handle isn't a kernel handle if we're + * from user-mode. We need exceptions for the process + * and thread pseudo-handles. + */ + if (PreviousMode != KernelMode) + { + if ( + IsKernelHandle(Argument) && + Argument != NtCurrentProcess() && + Argument != NtCurrentThread() + ) + return STATUS_INVALID_HANDLE; + } + + /* Reference the object. */ + status = ObReferenceObjectByHandle( + Argument, + 0, + NULL, + KernelMode, + &object, + NULL + ); + + if (!NT_SUCCESS(status)) + return status; + + /* Get a pointer to the UNICODE_STRING containing the + * object type name. + */ + objectType = KphGetObjectTypeNt(object); + objectTypeName = (PUNICODE_STRING)KVOFF(objectType, OffOtName); + + /* Allocate a buffer for name information. */ + objectNameInfo = (PUNICODE_STRING)ExAllocatePoolWithTag( + PagedPool, + CAPTURE_HANDLE_BUFFER_SIZE, + TAG_CAPTURE_TEMP_BUFFER + ); + + if (!objectNameInfo) + goto CleanupObject; + + /* Query the name of the object. */ + status = KphQueryNameObject( + object, + objectNameInfo, + CAPTURE_HANDLE_BUFFER_SIZE, + &returnLength + ); + + if (!NT_SUCCESS(status)) + goto CleanupName; + + /* Allocate an argument block. */ + argumentBlock = KphpSsAllocateArgumentBlock( + sizeof(KPHSS_HANDLE) + sizeof(KPHSS_WSTRING) + sizeof(KPHSS_WSTRING) + + objectTypeName->Length + objectNameInfo->Length, + HandleArgument + ); + + if (!argumentBlock) + goto CleanupName; + + handleInfo = &argumentBlock->Handle; + /* Calculate the offsets. */ + handleInfo->TypeNameOffset = sizeof(KPHSS_HANDLE); + handleInfo->NameOffset = + handleInfo->TypeNameOffset + sizeof(KPHSS_WSTRING) + + objectTypeName->Length; + + /* Copy the object type name into the block. */ + wString = (PKPHSS_WSTRING)PTR_ADD_OFFSET(handleInfo, handleInfo->TypeNameOffset); + wString->Length = objectTypeName->Length; + memcpy(&wString->Buffer, objectTypeName->Buffer, wString->Length); + + /* Copy the object name into the block. */ + wString = (PKPHSS_WSTRING)PTR_ADD_OFFSET(handleInfo, handleInfo->NameOffset); + wString->Length = objectNameInfo->Length; + memcpy(&wString->Buffer, objectNameInfo->Buffer, wString->Length); + + /* We may be able to get additional information for the + * object. + */ + + handleInfo->ClientId.UniqueProcess = NULL; + handleInfo->ClientId.UniqueThread = NULL; + + if (objectType == *PsProcessType) + { + handleInfo->ClientId.UniqueProcess = PsGetProcessId((PEPROCESS)object); + } + else if (objectType == *PsThreadType) + { + handleInfo->ClientId.UniqueThread = PsGetThreadId((PETHREAD)object); + handleInfo->ClientId.UniqueProcess = PsGetProcessId(IoThreadToProcess((PETHREAD)object)); + } + + *ArgumentBlock = argumentBlock; + +CleanupName: + ExFreePoolWithTag(objectNameInfo, TAG_CAPTURE_TEMP_BUFFER); +CleanupObject: + ObDereferenceObject(object); + + return status; +} + +/* KphpSsCaptureUnicodeStringArgument + * + * Captures a UNICODE_STRING argument. + */ +NTSTATUS KphpSsCaptureUnicodeStringArgument( + __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock, + __in PUNICODE_STRING Argument, + __in KPROCESSOR_MODE PreviousMode + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PKPHSS_ARGUMENT_BLOCK argumentBlock; + UNICODE_STRING unicodeString; + + /* Return if we have a NULL pointer. */ + if (!Argument) + return STATUS_INVALID_PARAMETER_2; + + /* Probe and copy the UNICODE_STRING structure. */ + __try + { + if (PreviousMode != KernelMode) + ProbeForRead(Argument, sizeof(UNICODE_STRING), 1); + + memcpy(&unicodeString, Argument, sizeof(UNICODE_STRING)); + + /* Probe the buffer, if present. */ + if (unicodeString.Buffer && PreviousMode != KernelMode) + { + ProbeForRead(unicodeString.Buffer, unicodeString.Length, 1); + } + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + + /* Check if the string is too large. */ + if (unicodeString.Length > CAPTURE_UNICODE_STRING_MAX_SIZE) + return STATUS_UNSUCCESSFUL; + + /* Allocate an argument block. */ + argumentBlock = KphpSsAllocateArgumentBlock( + sizeof(KPHSS_UNICODE_STRING) + unicodeString.Length, + UnicodeStringArgument + ); + + if (!argumentBlock) + return STATUS_INSUFFICIENT_RESOURCES; + + /* Copy the string into the argument block. */ + argumentBlock->UnicodeString.Length = unicodeString.Length; + argumentBlock->UnicodeString.MaximumLength = unicodeString.MaximumLength; + argumentBlock->UnicodeString.Pointer = unicodeString.Buffer; + + if (unicodeString.Buffer) + { + __try + { + memcpy(argumentBlock->UnicodeString.Buffer, unicodeString.Buffer, unicodeString.Length); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + KphpSsFreeArgumentBlock(argumentBlock); + return GetExceptionCode(); + } + } + + *ArgumentBlock = argumentBlock; + + return status; +} + +/* KphpSsCaptureObjectAttributesArgument + * + * Captures an OBJECT_ATTRIBUTES argument. + */ +NTSTATUS KphpSsCaptureObjectAttributesArgument( + __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock, + __in POBJECT_ATTRIBUTES Argument, + __in KPROCESSOR_MODE PreviousMode + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PKPHSS_ARGUMENT_BLOCK argumentBlock; + OBJECT_ATTRIBUTES objectAttributes; + PKPHSS_ARGUMENT_BLOCK rootDirectoryArgumentBlock = NULL; + ULONG rootDirectoryArgumentBlockSize = 0; + PKPHSS_ARGUMENT_BLOCK objectNameArgumentBlock = NULL; + ULONG objectNameArgumentBlockSize = 0; + + /* Return if we have a NULL pointer. */ + if (!Argument) + return STATUS_INVALID_PARAMETER_2; + + /* Probe and copy the OBJECT_ATTRIBUTES structure. */ + __try + { + if (PreviousMode != KernelMode) + ProbeForRead(Argument, sizeof(OBJECT_ATTRIBUTES), 1); + + memcpy(&objectAttributes, Argument, sizeof(OBJECT_ATTRIBUTES)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + + /* If we have a root directory, create an argument block from it + * and copy it to our argument block. + */ + if (objectAttributes.RootDirectory) + { + status = KphpSsCaptureHandleArgument( + &rootDirectoryArgumentBlock, + objectAttributes.RootDirectory, + PreviousMode + ); + + /* If we created the argument block, we need to calculate + * the size of the KPHSS_HANDLE structure. + */ + if (NT_SUCCESS(status)) + { + rootDirectoryArgumentBlockSize = + rootDirectoryArgumentBlock->Header.Size - KPHSS_ARGUMENT_BLOCK_OVERHEAD; + } + else + { + rootDirectoryArgumentBlock = NULL; + } + } + + /* If we have a object name, create an argument block from it and + * copy it to our argument block. + */ + if (objectAttributes.ObjectName) + { + status = KphpSsCaptureUnicodeStringArgument( + &objectNameArgumentBlock, + objectAttributes.ObjectName, + PreviousMode + ); + + /* If we created the argument block, we need to calculate + * the size of the KPHSS_UNICODE_STRING structure. + */ + if (NT_SUCCESS(status)) + { + objectNameArgumentBlockSize = + objectNameArgumentBlock->Header.Size - KPHSS_ARGUMENT_BLOCK_OVERHEAD; + } + else + { + objectNameArgumentBlock = NULL; + } + } + + /* Allocate an argument block. */ + argumentBlock = KphpSsAllocateArgumentBlock( + sizeof(KPHSS_OBJECT_ATTRIBUTES) + rootDirectoryArgumentBlockSize + objectNameArgumentBlockSize, + ObjectAttributesArgument + ); + + argumentBlock->ObjectAttributes.RootDirectoryOffset = 0; + argumentBlock->ObjectAttributes.ObjectNameOffset = 0; + + /* Copy the object attributes fields. */ + memcpy( + &argumentBlock->ObjectAttributes.ObjectAttributes, + &objectAttributes, + sizeof(OBJECT_ATTRIBUTES) + ); + + /* Copy the root directory structure, if we have one. */ + if (rootDirectoryArgumentBlock) + { + ULONG rootDirectoryOffset; + + /* It will go directly after the KPHSS_OBJECT_ATTRIBUTES structure. */ + rootDirectoryOffset = sizeof(KPHSS_OBJECT_ATTRIBUTES); + argumentBlock->ObjectAttributes.RootDirectoryOffset = (USHORT)rootDirectoryOffset; + /* Copy it. */ + memcpy( + PTR_ADD_OFFSET(&argumentBlock->ObjectAttributes, rootDirectoryOffset), + &rootDirectoryArgumentBlock->Handle, + rootDirectoryArgumentBlockSize + ); + /* Free the block. */ + KphpSsFreeArgumentBlock(rootDirectoryArgumentBlock); + } + + /* Copy the object name structure, if we have one. */ + if (objectNameArgumentBlock) + { + ULONG objectNameOffset; + + /* We'll place the structure after the root directory structure, + * if present. + */ + objectNameOffset = sizeof(KPHSS_OBJECT_ATTRIBUTES) + rootDirectoryArgumentBlockSize; + + /* Make sure the offset isn't too large. */ + if (objectNameOffset <= MAX_USHORT) + { + argumentBlock->ObjectAttributes.ObjectNameOffset = (USHORT)objectNameOffset; + /* Copy it. */ + memcpy( + PTR_ADD_OFFSET(&argumentBlock->ObjectAttributes, objectNameOffset), + &objectNameArgumentBlock->UnicodeString, + objectNameArgumentBlockSize + ); + } + + /* Free the block. */ + KphpSsFreeArgumentBlock(objectNameArgumentBlock); + } + + *ArgumentBlock = argumentBlock; + + return status; +} + +/* KphpSsCaptureClientIdArgument + * + * Captures a CLIENT_ID argument. + */ +NTSTATUS KphpSsCaptureClientIdArgument( + __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock, + __in PCLIENT_ID Argument, + __in KPROCESSOR_MODE PreviousMode + ) +{ + NTSTATUS status = STATUS_SUCCESS; + CLIENT_ID clientId; + PKPHSS_ARGUMENT_BLOCK argumentBlock; + + /* Check if we have a NULL pointer. */ + if (!Argument) + return STATUS_INVALID_PARAMETER_2; + + /* Probe and copy the CLIENT_ID structure. */ + __try + { + if (PreviousMode != KernelMode) + ProbeForRead(Argument, sizeof(CLIENT_ID), 1); + + memcpy(&clientId, Argument, sizeof(CLIENT_ID)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + + /* Allocate an argument block. */ + argumentBlock = KphpSsAllocateArgumentBlock( + sizeof(CLIENT_ID), + ClientIdArgument + ); + + if (!argumentBlock) + return STATUS_INSUFFICIENT_RESOURCES; + + /* Fill in the argument block. */ + memcpy(&argumentBlock->ClientId, &clientId, sizeof(CLIENT_ID)); + + *ArgumentBlock = argumentBlock; + + return status; +} + +/* KphpSsCreateArgumentBlock + * + * Allocates and initializes an argument block. + */ +NTSTATUS KphpSsCreateArgumentBlock( + __out PKPHSS_ARGUMENT_BLOCK *ArgumentBlock, + __in ULONG Number, + __in ULONG Argument, + __in ULONG Index + ) +{ +#ifdef _X86_ + NTSTATUS status = STATUS_SUCCESS; + PKPHSS_ARGUMENT_BLOCK argumentBlock; + KPROCESSOR_MODE previousMode; + PKPHSS_CALL_ENTRY callEntry; + KPHSS_ARGUMENT_TYPE argumentType; + + previousMode = ExGetPreviousMode(); + + /* Get a pointer to the call entry for the system service. + * If we don't have one, we can't proceed. + */ + callEntry = KphSsLookupCallEntry(Number); + + if (!callEntry) + return STATUS_INVALID_PARAMETER_2; + + /* Validate the argument index. */ + if (Index >= callEntry->NumberOfArguments) + return STATUS_INVALID_PARAMETER_3; + + /* Is this a normal argument? If so, there's no point + * creating an argument block since the data is already + * in the event block. + */ + argumentType = callEntry->Arguments[Index]; + + if (argumentType == NormalArgument) + return STATUS_UNSUCCESSFUL; + + /* Capture the argument. */ + + switch (argumentType) + { + case Int8Argument: + case Int16Argument: + case Int32Argument: + case Int64Argument: + status = KphpSsCaptureSimpleArgument( + &argumentBlock, + (PVOID)Argument, + argumentType, + previousMode + ); + break; + case HandleArgument: + status = KphpSsCaptureHandleArgument( + &argumentBlock, + (HANDLE)Argument, + previousMode + ); + break; + case UnicodeStringArgument: + status = KphpSsCaptureUnicodeStringArgument( + &argumentBlock, + (PUNICODE_STRING)Argument, + previousMode + ); + break; + case ObjectAttributesArgument: + status = KphpSsCaptureObjectAttributesArgument( + &argumentBlock, + (POBJECT_ATTRIBUTES)Argument, + previousMode + ); + break; + case ClientIdArgument: + status = KphpSsCaptureClientIdArgument( + &argumentBlock, + (PCLIENT_ID)Argument, + previousMode + ); + break; + default: + status = STATUS_NOT_IMPLEMENTED; + break; + } + + if (!NT_SUCCESS(status)) + return status; + + /* Put the index in. */ + argumentBlock->Index = (UCHAR)Index; + + *ArgumentBlock = argumentBlock; + + return status; +#else + return STATUS_NOT_SUPPORTED; +#endif +} + +/* KphpSsAllocateArgumentBlock + * + * Allocates an argument block and initializes some fields. + */ +PKPHSS_ARGUMENT_BLOCK KphpSsAllocateArgumentBlock( + __in ULONG InnerSize, + __in KPHSS_ARGUMENT_TYPE Type + ) +{ + PKPHSS_ARGUMENT_BLOCK argumentBlock; + ULONG size; + + size = KPHSS_ARGUMENT_BLOCK_SIZE(InnerSize); + + /* Make sure the size isn't too large. */ + if (size > MAX_USHORT) + return NULL; + + argumentBlock = ExAllocatePoolWithTag( + PagedPool, + size, + TAG_ARGUMENT_BLOCK + ); + + if (!argumentBlock) + return NULL; + + argumentBlock->Header.Type = ArgumentBlockType; + argumentBlock->Header.Size = (USHORT)size; + argumentBlock->Type = Type; + + return argumentBlock; +} + +/* KphpSsFreeArgumentBlock + * + * Frees an argument block created by KphpSsCreateArgumentBlock. + */ +VOID KphpSsFreeArgumentBlock( + __in PKPHSS_ARGUMENT_BLOCK ArgumentBlock + ) +{ + ExFreePoolWithTag(ArgumentBlock, TAG_ARGUMENT_BLOCK); +} + +/* KphpSsWriteBlock + * + * Writes a block into client memory. + */ +NTSTATUS KphpSsWriteBlock( + __in PKPHSS_CLIENT_ENTRY ClientEntry, + __in_opt PKPHSS_BLOCK_HEADER Block, + __in KPHSS_SEQUENCE_MODE SequenceMode + ) +{ + NTSTATUS status = STATUS_SUCCESS; + LARGE_INTEGER zeroTimeout; + KPH_ATTACH_STATE attachState; + ULONG availableSpace; + HANDLE dupHandleInClient = NULL; + + zeroTimeout.QuadPart = 0; + + /* Take care of the sequence mode. If it isn't + * NoSequence, it is effectively a way for the caller + * to control the buffer mutex. + */ + if (SequenceMode == StartSequence) + { + ExAcquireFastMutex(&ClientEntry->BufferMutex); + return STATUS_SUCCESS; + } + else if (SequenceMode == EndSequence) + { + ExReleaseFastMutex(&ClientEntry->BufferMutex); + return STATUS_SUCCESS; + } + else + { + /* If we aren't manipulating the mutex, we need + * a block to write. + */ + if (!Block) + return STATUS_INVALID_PARAMETER_2; + + /* If we're in a sequence, don't acquire the mutex + * because the caller would have acquired it using + * StartSequence already. + */ + if (SequenceMode != InSequence) + ExAcquireFastMutex(&ClientEntry->BufferMutex); + } + + /* Try to acquire the write semaphore. If we can't acquire + * it immediately, drop the block. + */ + status = KeWaitForSingleObject( + ClientEntry->WriteSemaphore, + Executive, + KernelMode, + FALSE, + &zeroTimeout + ); + + if (!KPHSS_BLOCK_SUCCESS(status)) + { + if (status == STATUS_TIMEOUT) + { + dprintf("Ss: WARNING: Dropped block (server %#x).\n", ClientEntry->BufferCursor); + ClientEntry->NumberOfBlocksDropped++; + } + + goto CleanupBufferMutex; + } + + availableSpace = ClientEntry->BufferSize - ClientEntry->BufferCursor; + + /* Blocks are recorded in a circular buffer. + * In the case that there is not enough space for an entire block, + * we will record a reset block that tells the client to reset + * its read cursor to 0. In the case that there is not enough + * space for a block header, it is implied that the client will + * reset its read cursor. + */ + + /* Check if we have enough space for a block header. */ + if (availableSpace < sizeof(KPHSS_BLOCK_HEADER)) + { + /* Not enough space. Reset the cursor. */ + dprintf("Ss: Implicit cursor reset (server %#x).\n", ClientEntry->BufferCursor); + ClientEntry->BufferCursor = 0; + availableSpace = ClientEntry->BufferSize; + } + /* Check if we have enough space for the block. */ + else if (availableSpace < Block->Size) + { + KPHSS_RESET_BLOCK resetBlock; + + /* Not enough space for the block, but enough space + * for a reset block. Write the reset block and reset + * the cursor. + */ + resetBlock.Header.Size = sizeof(KPHSS_RESET_BLOCK); + resetBlock.Header.Type = ResetBlockType; + + /* Attach to the client process and copy the block. */ + KphAttachProcess(ClientEntry->Process, &attachState); + + __try + { + memcpy( + PTR_ADD_OFFSET(ClientEntry->BufferBase, ClientEntry->BufferCursor), + &resetBlock, + resetBlock.Header.Size + ); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + KphDetachProcess(&attachState); + status = GetExceptionCode(); + goto CleanupBufferMutex; + } + + dprintf("Ss: Wrote reset block (server %#x).\n", ClientEntry->BufferCursor); + KphDetachProcess(&attachState); + ClientEntry->BufferCursor = 0; + availableSpace = ClientEntry->BufferSize; + } + + /* Now that we have dealt with any end-of-buffer issues, + * we still have to check if we have enough space for the + * event. We may have a huge event or the client may have a + * tiny buffer. + */ + if (availableSpace < Block->Size) + { + dfprintf("Ss: WARNING: Insufficient buffer size (server %#x).\n", ClientEntry->BufferCursor); + status = STATUS_BUFFER_TOO_SMALL; + goto CleanupBufferMutex; + } + + /* Time to copy the block into the buffer. + */ + KphAttachProcess(ClientEntry->Process, &attachState); + + __try + { + memcpy( + PTR_ADD_OFFSET(ClientEntry->BufferBase, ClientEntry->BufferCursor), + Block, + Block->Size + ); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + dfprintf("Ss: ERROR: Could not write to the client buffer (server %#x)!\n", ClientEntry->BufferCursor); + KphDetachProcess(&attachState); + status = GetExceptionCode(); + goto CleanupBufferMutex; + } + + KphDetachProcess(&attachState); + + /* Now that we have succesfully copied the block, we need to + * release the read semaphore to notify to the client that they have + * a block to read. We also need to advance our cursor. + */ + + /* May cause an exception (STATUS_SEMAPHORE_LIMIT_EXCEEDED). */ + __try + { + KeReleaseSemaphore(ClientEntry->ReadSemaphore, 2, 1, FALSE); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + dfprintf("Ss: ERROR: Could not release read semaphore (server %#x)!\n", ClientEntry->BufferCursor); + status = GetExceptionCode(); + goto CleanupBufferMutex; + } + + ClientEntry->BufferCursor += Block->Size; + ClientEntry->NumberOfBlocksWritten++; + + dprintf("Ss: Wrote block (server %#x).\n", ClientEntry->BufferCursor); + +CleanupBufferMutex: + if (SequenceMode != InSequence) + ExReleaseFastMutex(&ClientEntry->BufferMutex); + + return status; +} + +/* KphpSsLogSystemServiceCall + * + * Logs a system service. + * + * WARNING: This function CANNOT make any system calls. + * + * IRQL: <= APC_LEVEL + */ +VOID NTAPI KphpSsLogSystemServiceCall( + __in ULONG Number, + __in ULONG *Arguments, + __in ULONG NumberOfArguments, + __in PKSERVICE_TABLE_DESCRIPTOR ServiceTable, + __in PKTHREAD Thread + ) +{ +#ifdef _X86_ + NTSTATUS status = STATUS_SUCCESS; + KPROCESSOR_MODE previousMode; + PLIST_ENTRY currentListEntry; + PKPHSS_RULESET_ENTRY ruleSetEntryArray[KPHSS_RULESET_ENTRY_LIMIT]; + ULONG ruleSetEntryCount; + PKPHSS_EVENT_BLOCK eventBlock; + PKPHSS_ARGUMENT_BLOCK argumentBlockArray[KPHSS_MAXIMUM_ARGUMENT_BLOCKS]; + ULONG i, j; + + previousMode = ExGetPreviousMode(); + /* Ignore the Thread argument. Replace it with our own. */ + Thread = KeGetCurrentThread(); + + /* First, some checks. + * * We can't operate at IRQL > APC_LEVEL because + * of restrictions on logging. + * * We can't operate on unknown service tables like the + * shadow service table (yet). + * * We have to make sure we aren't attempting to log + * a call to ZwContinue because we caused an exception + * last time we were logging something. This will cause + * a deadlock! + */ + + if (KeGetCurrentIrql() > APC_LEVEL) + return; + if ( + ServiceTable->Base != __KeServiceDescriptorTable->Base || + ServiceTable->Number != __KeServiceDescriptorTable->Number || + ServiceTable->Limit != __KeServiceDescriptorTable->Limit + ) + return; + + /* Make sure we aren't logging ZwContinue if it's because + * we caused an exception somewhere. */ + if ( + ServiceTable->Base == __KeServiceDescriptorTable->Base && + Number == SsNtContinue && + NumberOfArguments == 2 && + previousMode == KernelMode + ) + { + /* "Reverse probe" the arguments. */ + if ( + (ULONG_PTR)Arguments > (ULONG_PTR)MmHighestUserAddress && + Arguments[0] > (ULONG_PTR)MmHighestUserAddress + ) + { + CONTEXT context; + + /* The first argument contains the context. */ + memcpy(&context, (PCONTEXT)Arguments[0], sizeof(CONTEXT)); + /* Check if the context Eip points into the KPH module. + * If so, abort the logging. + */ + if ( + context.Eip >= (ULONG_PTR)KphDriverObject->DriverStart && + context.Eip < (ULONG_PTR)KphDriverObject->DriverStart + KphDriverObject->DriverSize + ) + return; + } + } + + /* Build the ruleset entry array by going through the ruleset + * list, referencing each relevant one and copying them into + * the local array. This we way don't hold the lock for too + * long. + */ + + KeEnterCriticalRegion(); + ExAcquirePushLockShared(&KphSsRuleSetListPushLock); + + currentListEntry = KphSsRuleSetListHead.Flink; + ruleSetEntryCount = 0; + + while ( + currentListEntry != &KphSsRuleSetListHead && + ruleSetEntryCount < KPHSS_RULESET_ENTRY_LIMIT + ) + { + PKPHSS_RULESET_ENTRY ruleSetEntry = KPHSS_RULESET_ENTRY(currentListEntry); + + if (KphpSsMatchRuleSetEntry( + ruleSetEntry, + Number, + Arguments, + NumberOfArguments, + ServiceTable, + Thread, + previousMode + )) + { + /* Reference and store the ruleset entry in the local array. */ + if (KphReferenceObjectSafe(ruleSetEntry)) + { + /* Make sure the client is enabled. */ + if (ruleSetEntry->Client->Enabled) + { + ruleSetEntryArray[ruleSetEntryCount] = ruleSetEntry; + ruleSetEntryCount++; + } + else + { + /* We need to use defer delete here because we hold the + * ruleset list lock. + */ + KphDereferenceObjectDeferDelete(ruleSetEntry); + } + } + } + + currentListEntry = currentListEntry->Flink; + } + + ExReleasePushLock(&KphSsRuleSetListPushLock); + KeLeaveCriticalRegion(); + + /* If we didn't find any ruleset entries, don't bother creating the + * event block. + */ + if (ruleSetEntryCount == 0) + return; + + /* We have work to do. Create an event block first. */ + if (!NT_SUCCESS(KphpSsCreateEventBlock( + &eventBlock, + Thread, + Number, + Arguments, + NumberOfArguments + ))) + { + dfprintf("Ss: ERROR: Unable to create an event block!\n"); + return; + } + + /* Create the argument blocks. If we fail to create one, + * set the array entry to NULL and we'll skip it later. + */ + + for (i = 0; i < NumberOfArguments && i < KPHSS_MAXIMUM_ARGUMENT_BLOCKS; i++) + { + ULONG argument; + + __try + { + /* We'll assume the arguments have already been probed + * since we created the event block successfully. + */ + argument = Arguments[i]; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + /* Silently skip this argument. Even though it is 99% likely + * that we will fail to read the next argument, continue + * anyway. + */ + argumentBlockArray[i] = NULL; + continue; + } + + status = KphpSsCreateArgumentBlock( + &argumentBlockArray[i], + Number, + argument, + i + ); + + if (!NT_SUCCESS(status)) + argumentBlockArray[i] = NULL; + } + + /* Go through the ruleset entry array and write the blocks to each + * client. While we're doing that we can also dereference each + * ruleset entry. + */ + for (i = 0; i < ruleSetEntryCount; i++) + { + /* Begin a sequence. */ + status = KphpSsWriteBlock(ruleSetEntryArray[i]->Client, NULL, StartSequence); + + if (NT_SUCCESS(status)) + { + /* Write the event block. */ + KphpSsWriteBlock(ruleSetEntryArray[i]->Client, &eventBlock->Header, InSequence); + + /* Write the argument blocks. */ + for (j = 0; j < NumberOfArguments && j < KPHSS_MAXIMUM_ARGUMENT_BLOCKS; j++) + { + if (argumentBlockArray[j]) + { + KphpSsWriteBlock(ruleSetEntryArray[i]->Client, &argumentBlockArray[j]->Header, InSequence); + } + } + + /* End the sequence. */ + KphpSsWriteBlock(ruleSetEntryArray[i]->Client, NULL, EndSequence); + } + + KphDereferenceObject(ruleSetEntryArray[i]); + } + + /* Free the event block. */ + KphpSsFreeEventBlock(eventBlock); + + /* Free the argument blocks. */ + for (i = 0; i < NumberOfArguments && i < KPHSS_MAXIMUM_ARGUMENT_BLOCKS; i++) + { + if (argumentBlockArray[i]) + KphpSsFreeArgumentBlock(argumentBlockArray[i]); + } +#else + KeBugCheck(STATUS_NOT_SUPPORTED); +#endif +} + +#ifdef _X86_ + +/* KphpSsNewKiFastCallEntry + * + * The hook function called from within the hooked KiFastCallEntry. + */ +__declspec(naked) VOID NTAPI KphpSsNewKiFastCallEntry() +{ + /* KiFastCallEntry handles system service calls. User-mode applications + * will perform system calls like this: + * + * Nt*: + * mov eax, SystemServiceNumber + * mov edx, 0x7ffe0300 <-- at 0x7ffe0300 we have a pointer to KiFastSystemCall + * call [edx] + * ret + * + * At KiFastSystemCall: + * mov edx, esp + * sysenter + */ + /* This means that in KiFastCallEntry, eax will contain the system service + * number while edx will contain a pointer to the arguments for the system + * service. KiFastCallEntry will fill in edi with the service table, and + * esi will contain the caller KTHREAD. + * + * We cannot hook KiFastCallEntry from the beginning because it starts on the DPC + * stack. KiFastCallEntry switches to the proper thread stack, and we want to + * hook it just after it switches to the stack. That way we can avoid having to + * manually switch the thread stack ourselves. + * + * At this point: + * * eax contains the system service number. + * * edx contains a pointer to the user-supplied arguments for + * the system service. + * * edi contains a pointer to the service table associated with + * the system service number. + * * esi contains a pointer to the KTHREAD of the caller. + */ + /* Some context: + * + * push edx + * push eax + * call [_KeGdiFlushUserBatch] + * pop eax + * pop edx + * inc dword ptr fs:[PbSystemCalls] <-- this gets overwritten with a jmp to here + * mov edi, edx + * mov ebx, [edi+...] + * ... + */ + __asm + { + /* Save all registers first. */ + push ebp + push edi + push esi + push edx + push ecx + push ebx + push eax + + /* Since we overwrite the inc instruction when we did the hook, + * perform the job now - we have to increment the system calls + * counter. + */ + lea ebx, KphSsKiFastCallEntryHook /* get a pointer to the hook structure */ + mov ebx, dword ptr [ebx+KPH_HOOK.Bytes+3] /* get the PbSystemCalls offset from the original inc instruction */ + inc dword ptr fs:[ebx] /* increment PbSystemCalls in the PRCB */ + + /* Get the number of arguments for this system service. */ + mov ebx, dword ptr [edi+KSERVICE_TABLE_DESCRIPTOR.Number] /* ebx = a pointer to the argument table */ + xor ecx, ecx + mov cl, [ebx+eax] /* ecx = size of the arguments, in bytes. */ + shr ecx, 2 /* divide by 2 to get the number of arguments (all ULONGs) */ + + /* Call the KiFastCallEntry proc while maintaining the logger count + * so that the driver doesn't get unloaded while we're executing. + */ + push esi /* Thread */ + push edi /* ServiceTable */ + push ecx /* NumberOfArguments */ + push edx /* Arguments */ + push eax /* Number */ + lock inc dword ptr KphSsNumberOfActiveLoggers + call KphpSsLogSystemServiceCall + lock dec dword ptr KphSsNumberOfActiveLoggers + + /* Restore the registers and resume execution in KiFastCallEntry. */ + pop eax + pop ebx + pop ecx + pop edx + pop esi + pop edi + pop ebp + + /* Luckily, KiFastCallEntry will overwrite ebx when we jump back, so it's safe to use it. */ + lea ebx, __KiFastCallEntry + mov ebx, [ebx] /* ebx = KiFastCallEntry at the inc instruction */ + add ebx, 7 /* skip the inc instruction */ + jmp ebx /* jump back */ + } +} + +#else + +VOID NTAPI KphpSsNewKiFastCallEntry() +{ + KeBugCheck(STATUS_NOT_SUPPORTED); +} + +#endif diff --git a/branches/ph-plugins/KProcessHacker/sysservicedata.c b/branches/ph-plugins/KProcessHacker/sysservicedata.c new file mode 100644 index 000000000..c30c36917 --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/sysservicedata.c @@ -0,0 +1,513 @@ +/* + * Process Hacker Driver - + * system service logging (data) + * + * Copyright (C) 2009 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 . + */ + +#define _SYSSERVICEDATA_PRIVATE +#include "include/sysservicedata.h" + +PVOID KphpSsCallEntryAllocateRoutine( + __in PRTL_GENERIC_TABLE Table, + __in CLONG ByteSize + ); + +RTL_GENERIC_COMPARE_RESULTS KphpSsCallEntryCompareRoutine( + __in PRTL_GENERIC_TABLE Table, + __in PVOID FirstStruct, + __in PVOID SecondStruct + ); + +VOID KphpSsCallEntryFreeRoutine( + __in PRTL_GENERIC_TABLE Table, + __in PVOID Buffer + ); + +KPHSS_CALL_ENTRY SsEntries[] = +{ + /* NTSTATUS NtAddAtom(PWSTR String, ULONG StringLength, PUSHORT Atom) */ + { &SsNtAddAtom, "NtAddAtom", 3, { WStringArgument, 0, Int16Argument } }, + /* NTSTATUS NtAlertResumeThread(HANDLE ThreadHandle, PULONG PreviousSuspendCount) */ + { &SsNtAlertResumeThread, "NtAlertResumeThread", 2, { HandleArgument, 0 } }, + /* NTSTATUS NtAlertThread(HANDLE ThreadHandle) */ + { &SsNtAlertThread, "NtAlertThread", 1, { HandleArgument } }, + /* NTSTATUS NtAllocateLocallyUniqueId(PLUID Luid) */ + { &SsNtAllocateLocallyUniqueId, "NtAllocateLocallyUniqueId", 1, { 0 } }, + /* NTSTATUS NtAllocateUserPhysicalPages(HANDLE ProcessHandle, PULONG NumberOfPages, PULONG PageFrameNumbers) */ + { &SsNtAllocateUserPhysicalPages, "NtAllocateUserPhysicalPages", 3, { HandleArgument, Int32Argument, 0 } }, + /* NTSTATUS NtAllocateUuids(PLARGE_INTEGER UuidLastTimeAllocated, PULONG UuidDeltaTime, PULONG UuidSequenceNumber, + * PUCHAR UuidSeed) */ + { &SsNtAllocateUuids, "NtAllocateUuids", 4, { Int64Argument, 0, 0, 0 } }, + /* NTSTATUS NtAllocateVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, ULONG ZeroBits, + * PULONG AllocationSize, ULONG AllocationType, ULONG Protect) */ + { &SsNtAllocateVirtualMemory, "NtAllocateVirtualMemory", 6, { HandleArgument, Int32Argument, 0, Int32Argument, 0, 0 } }, + /* NTSTATUS NtApphelpCacheControl(APPHELPCACHECONTROL ApphelpCacheControl, PUNICODE_STRING ApphelpCacheObject) */ + { &SsNtApphelpCacheControl, "NtApphelpCacheControl", 2, { 0, UnicodeStringArgument } }, + /* NTSTATUS NtAreMappedFilesTheSame(PVOID Address1, PVOID Address2) */ + { &SsNtAreMappedFilesTheSame, "NtAreMappedFilesTheSame", 2, { 0, 0 } }, + /* NTSTATUS NtAssignProcessToJobObject(HANDLE JobHandle, HANDLE ProcessHandle) */ + { &SsNtAssignProcessToJobObject, "NtAssignProcessToJobObject", 2, { HandleArgument, HandleArgument } }, + /* NTSTATUS NtCallbackReturn(PVOID Result, ULONG ResultLength, NTSTATUS Status) */ + { &SsNtCallbackReturn, "NtCallbackReturn", 3, { 0, 0, 0 } }, + /* NTSTATUS NtCancelDeviceWakeupRequest(HANDLE DeviceHandle) */ + { &SsNtCancelDeviceWakeupRequest, "NtCancelDeviceWakeupRequest", 1, { HandleArgument } }, + /* NTSTATUS NtCancelIoFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock) */ + { &SsNtCancelIoFile, "NtCancelIoFile", 2, { HandleArgument, 0 } }, + /* NTSTATUS NtCancelTimer(HANDLE TimerHandle, PBOOLEAN CurrentState) */ + { &SsNtCancelTimer, "NtCancelTimer", 2, { HandleArgument, 0 } }, + /* NTSTATUS NtClearEvent(HANDLE EventHandle) */ + { &SsNtClearEvent, "NtClearEvent", 1, { HandleArgument } }, + /* NTSTATUS NtClose(HANDLE Handle) */ + { &SsNtClose, "NtClose", 1, { HandleArgument } }, + /* NTSTATUS NtContinue(PCONTEXT Context, BOOLEAN TestAlert) */ + { &SsNtContinue, "NtContinue", 2, { ContextArgument, 0 } }, + /* NTSTATUS NtCreateDebugObject(PHANDLE DebugObjectHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, + * ULONG Flags) */ + { &SsNtCreateDebugObject, "NtCreateDebugObject", 4, { 0, 0, ObjectAttributesArgument, 0 } }, + /* NTSTATUS NtCreateDirectoryObject(PHANDLE DirectoryHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */ + { &SsNtCreateDirectoryObject, "NtCreateDirectoryObject", 3, { 0, 0, ObjectAttributesArgument } }, + /* NTSTATUS NtCreateEvent(PHANDLE EventHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, + * EVENT_TYPE EventType, BOOLEAN InitialState) */ + { &SsNtCreateEvent, "NtCreateEvent", 5, { 0, 0, ObjectAttributesArgument, 0, 0 } }, + /* NTSTATUS NtCreateEventPair(PHANDLE EventPairHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */ + { &SsNtCreateEventPair, "NtCreateEventPair", 3, { 0, 0, ObjectAttributesArgument } }, + /* NTSTATUS NtCreateFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, + * PIO_STATUS_BLOCK IoStatusBlock, PLARGE_INTEGER AllocationSize, ULONG FileAttributes, + * ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions, + * PVOID EaBuffer, ULONG EaLength) */ + { &SsNtCreateFile, "NtCreateFile", 11, { 0, 0, ObjectAttributesArgument, 0, Int64Argument, 0, 0, 0, 0, 0, 0 } }, + /* NTSTATUS NtCreateIoCompletion(PHANDLE IoCompletionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, + * ULONG NumberOfConcurrentThreads) */ + { &SsNtCreateIoCompletion, "NtCreateIoCompletion", 4, { 0, 0, ObjectAttributesArgument, 0 } }, + /* NTSTATUS NtCreateJobObject(PHANDLE JobHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */ + { &SsNtCreateJobObject, "NtCreateJobObject", 3, { 0, 0, ObjectAttributesArgument } }, + /* NTSTATUS NtCreateJobSet(ULONG NumJob, IN PJOB_SET_ARRAY UserJobSet, IN ULONG Flags) */ + { &SsNtCreateJobSet, "NtCreateJobSet", 3, { 0, 0, 0 } }, + /* NTSTATUS NtCreateKey(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, + * ULONG TitleIndex, PUNICODE_STRING Class, ULONG CreateOptions, + * PULONG Disposition) */ + { &SsNtCreateKey, "NtCreateKey", 7, { 0, 0, ObjectAttributesArgument, 0, UnicodeStringArgument, 0, 0 } }, + /* NTSTATUS NtCreateKeyedEvent(PHANDLE KeyedEventHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, + * ULONG Flags) */ + { &SsNtCreateKeyedEvent, "NtCreateKeyedEvent", 4, { 0, 0, ObjectAttributesArgument, 0 } }, + /* NTSTATUS NtCreateMailslotFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, + * PIO_STATUS_BLOCK IoStatusBlock, ULONG CreateOptions, ULONG MailslotQuota, + * ULONG MaximumMessageSize, PLARGE_INTEGER ReadTimeout) */ + { &SsNtCreateMailslotFile, "NtCreateMailslotFile", 8, { 0, 0, ObjectAttributesArgument, 0, 0, 0, 0, Int64Argument } }, + /* NTSTATUS NtCreateMutant(PHANDLE MutantHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, + * BOOLEAN InitialOwner) */ + { &SsNtCreateMutant, "NtCreateMutant", 4, { 0, 0, ObjectAttributesArgument, 0 } }, + /* NTSTATUS NtCreateNamedPipeFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, + * PIO_STATUS_BLOCK IoStatusBlock, ULONG ShareAccess, ULONG CreateDisposition, + * ULONG CreateOptions, BOOLEAN TypeMessage, BOOLEAN ReadmodeMessage, + * BOOLEAN Nonblocking, ULONG MaxInstances, ULONG InBufferSize, + * ULONG OutBufferSize, PLARGE_INTEGER DefaultTimeout) */ + { &SsNtCreateNamedPipeFile, "NtCreateNamedPipeFile", 14, { 0, 0, ObjectAttributesArgument, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Int64Argument } }, + /* NTSTATUS NtCreatePagingFile(PUNICODE_STRING FileName, PULARGE_INTEGER MinimumSize, PULARGE_INTEGER MaximumSize, + * ULONG Priority) */ + { &SsNtCreatePagingFile, "NtCreatePagingFile", 4, { UnicodeStringArgument, Int64Argument, Int64Argument, 0 } }, + /* NTSTATUS NtCreatePort(PHANDLE PortHandle, POBJECT_ATTRIBUTES ObjectAttributes, ULONG MaxConnectionInfoLength, + * ULONG MaxMessageLength, ULONG MaxPoolUsage) */ + { &SsNtCreatePort, "NtCreatePort", 5, { 0, ObjectAttributesArgument, 0, 0, 0 } }, + /* NTSTATUS NtCreatePrivateNamespace(PHANDLE PrivateNamespaceHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, + * PBOUNDARY_DESCRIPTOR BoundaryDescriptor) */ + { &SsNtCreatePrivateNamespace, "NtCreatePrivateNamespace", 4, { 0, 0, ObjectAttributesArgument, 0 } }, + /* NTSTATUS NtCreateProcess(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, + * HANDLE InheritFromProcessHandle, BOOLEAN InheritHandles, HANDLE SectionHandle, + * HANDLE DebugPort, HANDLE ExceptionPort) */ + { &SsNtCreateProcess, "NtCreateProcess", 8, { 0, 0, ObjectAttributesArgument, HandleArgument, 0, HandleArgument, HandleArgument, HandleArgument } }, + /* NTSTATUS NtCreateProcessEx(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, + * HANDLE ParentProcess, ULONG Flags, HANDLE SectionHandle, + * HANDLE DebugPort, HANDLE ExceptionPort, ULONG JobMemberLevel */ + { &SsNtCreateProcessEx, "NtCreateProcessEx", 9, { 0, 0, ObjectAttributesArgument, HandleArgument, 0, HandleArgument, HandleArgument, HandleArgument, 0 } }, + /* NTSTATUS NtCreateProfile(PHANDLE ProfileHandle, HANDLE ProcessHandle, PVOID Base, + * ULONG Size, ULONG BucketShift, PULONG Buffer, + * ULONG BufferLength, KPROFILE_SOURCE Source, ULONG ProcessorMask) */ + { &SsNtCreateProfile, "NtCreateProfile", 9, { 0, HandleArgument, 0, 0, 0, 0, 0, 0, 0 } }, + /* NTSTATUS NtCreateSection(PHANDLE SectionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, + * PLARGE_INTEGER SectionSize, ULONG Protect, ULONG Attributes, + * HANDLE FileHandle) */ + { &SsNtCreateSection, "NtCreateSection", 7, { 0, 0, ObjectAttributesArgument, Int64Argument, 0, 0, HandleArgument } }, + /* NTSTATUS NtCreateSemaphore(PHANDLE SemaphoreHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, + * LONG InitialCount, LONG MaximumCount) */ + { &SsNtCreateSemaphore, "NtCreateSemaphore", 5, { 0, 0, ObjectAttributesArgument, 0, 0 } }, + /* NTSTATUS NtCreateSymbolicLinkObject(PHANDLE SymbolicLinkHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, + * PUNICODE_STRING TargetName) */ + { &SsNtCreateSymbolicLinkObject, "NtCreateSymbolicLinkObject", 4, { 0, 0, ObjectAttributesArgument, UnicodeStringArgument } }, + /* NTSTATUS NtCreateThread(PHANDLE ThreadHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, + * HANDLE ProcessHandle, PCLIENT_ID ClientId, PCONTEXT ThreadContext, + * PINITIAL_TEB UserStack, BOOLEAN CreateSuspended) */ + { &SsNtCreateThread, "NtCreateThread", 8, { 0, 0, ObjectAttributesArgument, HandleArgument, 0, ContextArgument, InitialTebArgument, 0 } }, + /* NTSTATUS NtCreateTimer(PHANDLE TimerHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, + * TIMER_TYPE TimerType) */ + { &SsNtCreateTimer, "NtCreateTimer", 4, { 0, 0, ObjectAttributesArgument, 0 } }, + /* NTSTATUS NtCreateToken(PHANDLE TokenHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, + * TOKEN_TYPE Type, PLUID AuthenticationId, PLARGE_INTEGER ExpirationTime, + * PTOKEN_USER User, PTOKEN_GROUPS Groups, PTOKEN_PRIVILEGES Privileges, + * PTOKEN_OWNER Owner, PTOKEN_PRIMARY_GROUP PrimaryGroup, PTOKEN_DEFAULT_DACL DefaultDacl, + * PTOKEN_SOURCE Source) */ + { &SsNtCreateToken, "NtCreateToken", 13, { 0, 0, ObjectAttributesArgument, 0, Int64Argument, Int64Argument, 0, 0, 0, 0, 0, 0, 0 } }, + /* NTSTATUS NtCreateWaitablePort(PHANDLE PortHandle, POBJECT_ATTRIBUTES ObjectAttributes, ULONG MaxConnectionInfoLength, + * ULONG MaxMessageLength, ULONG MaxPoolUsage) */ + { &SsNtCreateWaitablePort, "NtCreateWaitablePort", 5, { 0, ObjectAttributesArgument, 0, 0, 0 } }, + /* NTSTATUS NtDebugActiveProcess(HANDLE ProcessHandle, HANDLE DebugObjectHandle) */ + { &SsNtDebugActiveProcess, "NtDebugActiveProcess", 2, { HandleArgument, HandleArgument } }, + /* NTSTATUS NtDebugContinue(HANDLE DebugObjectHandle, PCLIENT_ID ClientId, NTSTATUS ContinueStatus) */ + { &SsNtDebugContinue, "NtDebugContinue", 3, { HandleArgument, ClientIdArgument, 0 } }, + /* NTSTATUS NtDelayExecution(BOOLEAN Alertable, PLARGE_INTEGER Interval) */ + { &SsNtDelayExecution, "NtDelayExecution", 2, { 0, Int64Argument } }, + /* NTSTATUS NtDeleteAtom(USHORT Atom) */ + { &SsNtDeleteAtom, "NtDeleteAtom", 1, { 0 } }, + /* NTSTATUS NtDeleteBootEntry(ULONG Id) */ + { &SsNtDeleteBootEntry, "NtDeleteBootEntry", 1, { 0 } }, + /* NTSTATUS NtDeleteDriverEntry(ULONG Id) */ + { &SsNtDeleteDriverEntry, "NtDeleteDriverEntry", 1, { 0 } }, + /* NTSTATUS NtDeleteFile(POBJECT_ATTRIBUTES ObjectAttributes) */ + { &SsNtDeleteFile, "NtDeleteFile", 1, { ObjectAttributesArgument } }, + /* NTSTATUS NtDeleteKey(HANDLE KeyHandle) */ + { &SsNtDeleteKey, "NtDeleteKey", 1, { HandleArgument } }, + /* NTSTATUS NtDeleteObjectAuditAlarm(PUNICODE_STRING SubsystemName, PVOID HandleId, BOOLEAN GenerateOnClose) */ + { &SsNtDeleteObjectAuditAlarm, "NtDeleteObjectAuditAlarm", 3, { UnicodeStringArgument, 0, 0 } }, + /* NTSTATUS NtDeletePrivateNamespace(HANDLE PrivateNamespaceHandle) */ + { &SsNtDeletePrivateNamespace, "NtDeletePrivateNamespace", 1, { HandleArgument } }, + /* NTSTATUS NtDeleteValueKey(HANDLE KeyHandle, PUNICODE_STRING ValueName) */ + { &SsNtDeleteValueKey, "NtDeleteValueKey", 2, { HandleArgument, UnicodeStringArgument } }, + /* NTSTATUS NtDeviceIoControlFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, + * PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, ULONG IoControlCode, + * PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, + * ULONG OutputBufferLength) */ + { &SsNtDeviceIoControlFile, "NtDeviceIoControlFile", 10, { HandleArgument, HandleArgument, 0, 0, 0, 0, 0, 0, 0, 0 } }, + /* NTSTATUS NtDisplayString(PUNICODE_STRING String) */ + { &SsNtDisplayString, "NtDisplayString", 1, { UnicodeStringArgument } }, + /* NTSTATUS NtDuplicateObject(HANDLE SourceProcessHandle, HANDLE SourceHandle, HANDLE TargetProcessHandle, + * PHANDLE TargetHandle, ACCESS_MASK DesiredAccess, ULONG Attributes, + * ULONG Options) */ + { &SsNtDuplicateObject, "NtDuplicateObject", 7, { HandleArgument, HandleArgument, HandleArgument, 0, 0, 0, 0 } }, + /* NTSTATUS NtDuplicateToken(HANDLE ExistingTokenHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, + * BOOLEAN EffectiveOnly, TOKEN_TYPE TokenType, PHANDLE NewTokenHandle) */ + { &SsNtDuplicateToken, "NtDuplicateToken", 6, { HandleArgument, 0, ObjectAttributesArgument, 0, 0, 0 } }, + /* NTSTATUS NtEnumerateBootEntries(PVOID Buffer, PULONG BufferLength) */ + { &SsNtEnumerateBootEntries, "NtEnumerateBootEntries", 2, { 0, Int32Argument } }, + /* NTSTATUS NtEnumerateDriverEntries(PVOID Buffer, PULONG BufferLength) */ + { &SsNtEnumerateDriverEntries, "NtEnumerateDriverEntries", 2, { 0, Int32Argument } }, + /* NTSTATUS NtEnumerateKey(HANDLE KeyHandle, ULONG Index, KEY_INFORMATION_CLASS KeyInformationClass, + * PVOID KeyInformation, ULONG KeyInformationLength, PULONG ResultLength) */ + { &SsNtEnumerateKey, "NtEnumerateKey", 6, { HandleArgument, 0, 0, 0, 0, 0 } }, + /* NTSTATUS NtEnumerateSystemEnvironmentValuesEx(ULONG InformationClass, PVOID Buffer, PULONG BufferLength) */ + { &SsNtEnumerateSystemEnvironmentValuesEx, "NtEnumerateSystemEnvironmentValuesEx", 3, { 0, 0, Int32Argument } }, + /* NTSTATUS NtEnumerateValueKey(HANDLE KeyHandle, ULONG Index, KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, + * PVOID KeyValueInformation, ULONG KeyValueInformationLength, PULONG ResultLength) */ + { &SsNtEnumerateValueKey, "NtEnumerateValueKey", 6, { HandleArgument, 0, 0, 0, 0, 0 } }, + /* NTSTATUS NtExtendSection(HANDLE SectionHandle, PLARGE_INTEGER SectionSize) */ + { &SsNtExtendSection, "NtExtendSection", 2, { HandleArgument, Int64Argument } }, + /* NTSTATUS NtFilterToken(HANDLE ExistingTokenHandle, ULONG Flags, PTOKEN_GROUPS SidsToDisable, + * PTOKEN_PRIVILEGES PrivilegesToDelete, PTOKEN_GROUPS SidsToRestricted, PHANDLE NewTokenHandle) */ + { &SsNtFilterToken, "NtFilterToken", 6, { HandleArgument, 0, 0, 0, 0, 0 } }, + /* NTSTATUS NtFindAtom(PWSTR String, ULONG StringLength, PUSHORT Atom) */ + { &SsNtFindAtom, "NtFindAtom", 3, { WStringArgument, 0, 0 } }, + /* NTSTATUS NtFlushBuffersFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock) */ + { &SsNtFlushBuffersFile, "NtFlushBuffersFile", 2, { HandleArgument, 0 } }, + /* NTSTATUS NtFlushInstructionCache(HANDLE ProcessHandle, PVOID BaseAddress, ULONG FlushSize) */ + { &SsNtFlushInstructionCache, "NtFlushInstructionCache", 3, { HandleArgument, 0, 0 } }, + /* NTSTATUS NtFlushKey(HANDLE KeyHandle) */ + { &SsNtFlushKey, "NtFlushKey", 1, { HandleArgument } }, + /* NTSTATUS NtFlushProcessWriteBuffers() */ + { &SsNtFlushProcessWriteBuffers, "NtFlushProcessWriteBuffers", 0 }, + /* NTSTATUS NtFlushVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, PULONG FlushSize, + * PIO_STATUS_BLOCK IoStatusBlock) */ + { &SsNtFlushVirtualMemory, "NtFlushVirtualMemory", 4, { HandleArgument, Int32Argument, Int32Argument, 0 } }, + /* NTSTATUS NtFlushWriteBuffer() */ + { &SsNtFlushWriteBuffer, "NtFlushWriteBuffer", 0 }, + /* NTSTATUS NtFreeUserPhysicalPages(HANDLE ProcessHandle, PULONG NumberOfPages, PULONG PageFrameNumbers) */ + { &SsNtFreeUserPhysicalPages, "NtFreeUserPhysicalPages", 3, { HandleArgument, Int32Argument, 0 } }, + /* NTSTATUS NtFreeVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, PULONG FreeSize, + * ULONG FreeType) */ + { &SsNtFreeVirtualMemory, "NtFreeVirtualMemory", 4, { HandleArgument, Int32Argument, Int32Argument, 0 } }, + /* NTSTATUS NtFsControlFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, + * PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, ULONG FsControlCode, + * PVOID InputBuffer, ULONG InputBufferLength, PVOID OutputBuffer, + * ULONG OutputBufferLength) */ + { &SsNtFsControlFile, "NtFsControlFile", 10, { HandleArgument, HandleArgument, 0, 0, 0, 0, 0, 0, 0, 0 } }, + /* NTSTATUS NtGetContextThread(HANDLE ThreadHandle, PCONTEXT Context) */ + { &SsNtGetContextThread, "NtGetContextThread", 2, { HandleArgument, ContextArgument } }, + /* NTSTATUS NtGetCurrentProcessorNumber() */ + { &SsNtGetCurrentProcessorNumber, "NtGetCurrentProcessorNumber", 0 }, + /* NTSTATUS NtGetDevicePowerState(HANDLE DeviceHandle, PDEVICE_POWER_STATE DevicePowerState) */ + { &SsNtGetDevicePowerState, "NtGetDevicePowerState", 2, { HandleArgument, 0 } }, + /* NTSTATUS NtGetNextProcess(HANDLE ProcessHandle, ACCESS_MASK DesiredAccess, ULONG HandleAttributes, + * ULONG Flags, PHANDLE NewProcessHandle) */ + { &SsNtGetNextProcess, "NtGetNextProcess", 5, { HandleArgument, 0, 0, 0, 0 } }, + /* NTSTATUS NtGetNextThread(HANDLE ProcessHandle, HANDLE ThreadHandle, ACCESS_MASK DesiredAccess, + * ULONG HandleAttributes, ULONG Flags, PHANDLE NewThreadHandle) */ + { &SsNtGetNextThread, "NtGetNextThread", 6, { HandleArgument, HandleArgument, 0, 0, 0, 0 } }, + /* NTSTATUS NtGetPlugPlayEvent(HANDLE EventHandle, PVOID Context, PVOID Buffer, + * ULONG BufferLength) */ + { &SsNtGetPlugPlayEvent, "NtGetPlugPlayEvent", 4, { HandleArgument, 0, 0, 0 } }, + /* NTSTATUS NtGetWriteWatch(HANDLE ProcessHandle, ULONG Flags, PVOID BaseAddress, + * ULONG RegionSize, PULONG Buffer, PULONG BufferEntries, + * PULONG Granularity) */ + { &SsNtGetWriteWatch, "NtGetWriteWatch", 7, { HandleArgument, 0, 0, 0, 0, 0, 0 } }, + /* NTSTATUS NtImpersonateAnonymousToken(HANDLE ThreadHandle) */ + { &SsNtImpersonateAnonymousToken, "NtImpersonateAnonymousToken", 1, { HandleArgument } }, + /* NTSTATUS NtImpersonateClientOfPort(HANDLE PortHandle, PPORT_MESSAGE Message) */ + { &SsNtImpersonateClientOfPort, "SsNtImpersonateClientOfPort", 2, { HandleArgument, 0 } }, + /* NTSTATUS NtImpersonateThread(HANDLE ThreadHandle, HANDLE TargetThreadHandle, PSECURITY_QUALITY_OF_SERVICE SecurityQos) */ + { &SsNtImpersonateThread, "NtImpersonateThread", 3, { HandleArgument, HandleArgument, 0 } }, + /* NTSTATUS NtInitiatePowerAction(POWER_ACTION SystemAction, SYSTEM_POWER_STATE MinSystemState, ULONG Flags, + * BOOLEAN Asynchronous) */ + { &SsNtInitiatePowerAction, "NtInitiatePowerAction", 4, { 0, 0, 0, 0 } }, + /* NTSTATUS NtIsProcessInJob(HANDLE ProcessHandle, HANDLE JobHandle) */ + { &SsNtIsProcessInJob, "NtIsProcessInJob", 2, { HandleArgument, HandleArgument } }, + /* NTSTATUS NtIsSystemResumeAutomatic() */ + { &SsNtIsSystemResumeAutomatic, "NtIsSystemResumeAutomatic", 0 }, + /* NTSTATUS NtListenPort(HANDLE PortHandle, PPORT_MESSAGE Message) */ + { &SsNtListenPort, "NtListenPort", 2, { HandleArgument, 0 } }, + /* NTSTATUS NtLoadDriver(PUNICODE_STRING DriverServiceName) */ + { &SsNtLoadDriver, "NtLoadDriver", 1, { UnicodeStringArgument } }, + /* NTSTATUS NtLoadKey(POBJECT_ATTRIBUTES KeyObjectAttributes, POBJECT_ATTRIBUTES FileObjectAttributes) */ + { &SsNtLoadKey, "NtLoadKey", 2, { ObjectAttributesArgument, ObjectAttributesArgument } }, + /* NTSTATUS NtLoadKey2(POBJECT_ATTRIBUTES KeyObjectAttributes, POBJECT_ATTRIBUTES FileObjectAttributes, ULONG Flags) */ + { &SsNtLoadKey2, "NtLoadKey2", 3, { ObjectAttributesArgument, ObjectAttributesArgument, 0 } }, + /* NTSTATUS NtLockFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, + * PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PULARGE_INTEGER LockOffset, + * PULARGE_INTEGER LockLength, ULONG Key, BOOLEAN FailImmediately, + * BOOLEAN ExclusiveLock) */ + { &SsNtLockFile, "NtLockFile", 10, { HandleArgument, HandleArgument, 0, 0, 0, Int64Argument, Int64Argument, 0, 0, 0 } }, + /* NTSTATUS NtLockVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, PULONG LockSize, + * ULONG LockType) */ + { &SsNtLockVirtualMemory, "NtLockVirtualMemory", 4, { HandleArgument, Int32Argument, Int32Argument, 0 } }, + /* NTSTATUS NtMakePermanentObject(HANDLE Handle) */ + { &SsNtMakePermanentObject, "NtMakePermanentObject", 1, { HandleArgument } }, + /* NTSTATUS NtMakeTemporaryObject(HANDLE Handle) */ + { &SsNtMakeTemporaryObject, "NtMakeTemporaryObject", 1, { HandleArgument } }, + /* NTSTATUS NtMapUserPhysicalPages(PVOID BaseAddress, PULONG NumberOfPages, PULONG PageFrameNumbers) */ + { &SsNtMapUserPhysicalPages, "NtMapUserPhysicalPages", 3, { 0, Int32Argument, 0 } }, + /* NTSTATUS NtMapUserPhysicalPagesScatter(PVOID BaseAddress, PULONG NumberOfPages, PULONG PageFrameNumbers) */ + { &SsNtMapUserPhysicalPagesScatter, "NtMapUserPhysicalPagesScatter", 3, { 0, Int32Argument, 0 } }, + /* NTSTATUS NtMapViewOfSection(HANDLE SectionHandle, HANDLE ProcessHandle, PVOID *BaseAddress, + * ULONG ZeroBits, ULONG CommitSize, PLARGE_INTEGER SectionOffset, + * PULONG ViewSize, SECTION_INHERIT InheritDisposition, ULONG AllocationType, + * ULONG Protect) */ + { &SsNtMapViewOfSection, "NtMapViewOfSection", 10, { HandleArgument, HandleArgument, Int32Argument, 0, 0, Int64Argument, Int32Argument, 0, 0, 0 } }, + /* NTSTATUS NtModifyBootEntry(PBOOT_ENTRY BootEntry) */ + { &SsNtModifyBootEntry, "NtModifyBootEntry", 1, { 0 } }, + /* NTSTATUS NtModifyDriverEntry(PEFI_DRIVER_ENTRY DriverEntry) */ + { &SsNtModifyDriverEntry, "NtModifyDriverEntry", 1, { 0 } }, + /* NTSTATUS NtNotifyChangeDirectoryFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, + * PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PFILE_NOTIFY_INFORMATION Buffer, + * ULONG BufferLength, ULONG NotifyFilter, BOOLEAN WatchSubtree) */ + { &SsNtNotifyChangeDirectoryFile, "NtNotifyChangeDirectoryFile", 9, { HandleArgument, HandleArgument, 0, 0, 0, 0, 0, 0, 0 } }, + /* NTSTATUS NtNotifyChangeKey(HANDLE KeyHandle, HANDLE EventHandle, PIO_APC_ROUTINE ApcRoutine, + * PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, ULONG NotifyFilter, + * BOOLEAN WatchSubtree, PVOID Buffer, ULONG BufferLength, + * BOOLEAN Asynchronous) */ + { &SsNtNotifyChangeKey, "NtNotifyChangeKey", 10, { HandleArgument, HandleArgument, 0, 0, 0, 0, 0, 0, 0, 0 } }, + /* NTSTATUS NtNotifyChangeMultipleKeys(HANDLE KeyHandle, ULONG Flags, POBJECT_ATTRIBUTES KeyObjectAttributes, + * HANDLE EventHandle, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext, + * PIO_STATUS_BLOCK IoStatusBlock, ULONG NotifyFilter, BOOLEAN WatchSubtree, + * PVOID Buffer, ULONG BufferLength, BOOLEAN Asynchronous) */ + { &SsNtNotifyChangeMultipleKeys, "NtNotifyChangeMultipleKeys", 12, { HandleArgument, 0, ObjectAttributesArgument, HandleArgument, 0, 0, 0, 0, 0, 0, 0, 0 } }, + /* NTSTATUS NtOpenDirectoryObject(PHANDLE DirectoryHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */ + { &SsNtOpenDirectoryObject, "NtOpenDirectoryObject", 3, { 0, 0, ObjectAttributesArgument } }, + /* NTSTATUS NtOpenEvent(PHANDLE EventHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */ + { &SsNtOpenEvent, "NtOpenEvent", 3, { 0, 0, ObjectAttributesArgument } }, + /* NTSTATUS NtOpenEventPair(PHANDLE EventPairHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */ + { &SsNtOpenEventPair, "NtOpenEventPair", 3, { 0, 0, ObjectAttributesArgument } }, + /* NTSTATUS NtOpenFile(PHANDLE FileHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, + * PIO_STATUS_BLOCK IoStatusBlock, ULONG ShareAccess, ULONG OpenOptions) */ + { &SsNtOpenFile, "NtOpenFile", 6, { 0, 0, ObjectAttributesArgument, 0, 0, 0 } }, + /* NTSTATUS NtOpenIoCompletion(PHANDLE IoCompletionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */ + { &SsNtOpenIoCompletion, "NtOpenIoCompletion", 3, { 0, 0, ObjectAttributesArgument } }, + /* NTSTATUS NtOpenJobObject(PHANDLE JobHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */ + { &SsNtOpenJobObject, "NtOpenJobObject", 3, { 0, 0, ObjectAttributesArgument } }, + /* NTSTATUS NtOpenKey(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */ + { &SsNtOpenKey, "NtOpenKey", 3, { 0, 0, ObjectAttributesArgument } }, + /* NTSTATUS NtOpenKeyedEvent(PHANDLE KeyedEventHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */ + { &SsNtOpenKeyedEvent, "NtOpenKeyedEvent", 3, { 0, 0, ObjectAttributesArgument } }, + /* NTSTATUS NtOpenMutant(PHANDLE MutantHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */ + { &SsNtOpenMutant, "NtOpenMutant", 3, { 0, 0, ObjectAttributesArgument } }, + /* NTSTATUS NtOpenObjectAuditAlarm(PUNICODE_STRING SubsystemName, PVOID *HandleId, PUNICODE_STRING ObjectTypeName, + * PUNICODE_STRING ObjectName, PSECURITY_DESCRIPTOR SecurityDescriptor, HANDLE TokenHandle, + * ACCESS_MASK DesiredAccess, ACCESS_MASK GrantedAccess, PPRIVILEGE_SET Privileges, + * BOOLEAN ObjectCreation, BOOLEAN AccessGranted, PBOOLEAN GenerateOnClose) */ + { &SsNtOpenObjectAuditAlarm, "NtOpenObjectAuditAlarm", 12, { UnicodeStringArgument, Int32Argument, UnicodeStringArgument, UnicodeStringArgument, 0, HandleArgument, 0, 0, 0, 0, 0, 0 } }, + /* NTSTATUS NtOpenProcess(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, + * PCLIENT_ID ClientId) */ + { &SsNtOpenProcess, "NtOpenProcess", 4, { 0, 0, ObjectAttributesArgument, ClientIdArgument } }, + /* NTSTATUS NtOpenProcessToken(HANDLE ProcessHandle, ACCESS_MASK DesiredAccess, PHANDLE TokenHandle) */ + { &SsNtOpenProcessToken, "NtOpenProcessToken", 3, { HandleArgument, 0, 0 } }, + /* NTSTATUS NtOpenProcessTokenEx(HANDLE ProcessHandle, ACCESS_MASK DesiredAccess, ULONG HandleAttributes, + * PHANDLE TokenHandle) */ + { &SsNtOpenProcessTokenEx, "NtOpenProcessTokenEx", 4, { HandleArgument, 0, 0, 0 } }, + /* NTSTATUS NtOpenSection(PHANDLE SectionHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */ + { &SsNtOpenSection, "NtOpenSection", 3, { 0, 0, ObjectAttributesArgument } }, + /* NTSTATUS NtOpenSemaphore(PHANDLE SemaphoreHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */ + { &SsNtOpenSemaphore, "NtOpenSemaphore", 3, { 0, 0, ObjectAttributesArgument } }, + /* NTSTATUS NtOpenSymbolicLinkObject(PHANDLE SymbolicLinkHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */ + { &SsNtOpenSymbolicLinkObject, "NtOpenSymbolicLinkObject", 3, { 0, 0, ObjectAttributesArgument } }, + /* NTSTATUS NtOpenThread(PHANDLE ThreadHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes, + * PCLIENT_ID ClientId) */ + { &SsNtOpenThread, "NtOpenThread", 4, { 0, 0, ObjectAttributesArgument, ClientIdArgument } }, + /* NTSTATUS NtOpenThreadToken(HANDLE ThreadHandle, ACCESS_MASK DesiredAccess, BOOLEAN OpenAsSelf, + * PHANDLE TokenHandle) */ + { &SsNtOpenThreadToken, "NtOpenThreadToken", 4, { HandleArgument, 0, 0, 0 } }, + /* NTSTATUS NtOpenThreadTokenEx(HANDLE ThreadHandle, ACCESS_MASK DesiredAccess, BOOLEAN OpenAsSelf, + * ULONG HandleAttributes, PHANDLE TokenHandle) */ + { &SsNtOpenThreadTokenEx, "NtOpenThreadTokenEx", 5, { HandleArgument, 0, 0, 0, 0 } }, + /* NTSTATUS NtOpenTimer(PHANDLE TimerHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes) */ + { &SsNtOpenTimer, "NtOpenTimer", 3, { 0, 0, ObjectAttributesArgument } }, + /* NTSTATUS NtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, + * PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, + * ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key) */ + { &SsNtReadFile, "NtReadFile", 9, { HandleArgument, HandleArgument, 0, 0, 0, 0, 0, Int64Argument, Int32Argument } }, + /* NTSTATUS NtWriteFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, + * PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, + * ULONG Length, PLARGE_INTEGER ByteOffset, PULONG Key) */ + { &SsNtWriteFile, "NtWriteFile", 9, { HandleArgument, HandleArgument, 0, 0, 0, 0, 0, Int64Argument, Int32Argument } }, + + { NULL, "Dummy", 0 } +}; + +RTL_GENERIC_TABLE KphSsCallTable; +FAST_MUTEX KphSsCallTableMutex; + +/* KphSsDataInit + * + * Initializes all data structures so that system service entries + * can be looked up. + */ +VOID KphSsDataInit() +{ + ULONG i; + + RtlInitializeGenericTable( + &KphSsCallTable, + KphpSsCallEntryCompareRoutine, + KphpSsCallEntryAllocateRoutine, + KphpSsCallEntryFreeRoutine, + NULL + ); + + for (i = 0; i < sizeof(SsEntries) / sizeof(KPHSS_CALL_ENTRY); i++) + { + /* Ignore the dummy entry. */ + if (SsEntries[i].Number) + { + RtlInsertElementGenericTable( + &KphSsCallTable, + &SsEntries[i], + /* Save some space... */ + FIELD_OFFSET(KPHSS_CALL_ENTRY, Arguments) + + SsEntries[i].NumberOfArguments * sizeof(KPHSS_ARGUMENT_TYPE), + NULL + ); + } + } + + ExInitializeFastMutex(&KphSsCallTableMutex); +} + +/* KphSsDataDeinit + * + * Frees all memory associated with system service data. + */ +VOID KphSsDataDeinit() +{ + PKPHSS_CALL_ENTRY callEntry; + + while (callEntry = (PKPHSS_CALL_ENTRY)RtlGetElementGenericTable(&KphSsCallTable, 0)) + RtlDeleteElementGenericTable(&KphSsCallTable, callEntry); +} + +/* KphSsLookupCallEntry + * + * Lookups up a system service entry by system service number. + */ +PKPHSS_CALL_ENTRY KphSsLookupCallEntry( + __in ULONG Number + ) +{ + KPHSS_CALL_ENTRY callEntry; + PKPHSS_CALL_ENTRY foundEntry; + + callEntry.Number = &Number; + + ExAcquireFastMutex(&KphSsCallTableMutex); + foundEntry = (PKPHSS_CALL_ENTRY)RtlLookupElementGenericTable( + &KphSsCallTable, + &callEntry + ); + ExReleaseFastMutex(&KphSsCallTableMutex); + + return foundEntry; +} + +/* KphpSsCallEntryAllocateRoutine + * + * Allocates storage for a system service entry. + */ +PVOID KphpSsCallEntryAllocateRoutine( + __in PRTL_GENERIC_TABLE Table, + __in CLONG ByteSize + ) +{ + return ExAllocatePoolWithTag( + PagedPool, + ByteSize, + TAG_CALL_ENTRY + ); +} + +/* KphpSsCallEntryCompareRoutine + * + * Compares two system service entries. + */ +RTL_GENERIC_COMPARE_RESULTS KphpSsCallEntryCompareRoutine( + __in PRTL_GENERIC_TABLE Table, + __in PVOID FirstStruct, + __in PVOID SecondStruct + ) +{ + PKPHSS_CALL_ENTRY callEntry1, callEntry2; + + callEntry1 = (PKPHSS_CALL_ENTRY)FirstStruct; + callEntry2 = (PKPHSS_CALL_ENTRY)SecondStruct; + + if (*(callEntry1->Number) < *(callEntry2->Number)) + return GenericLessThan; + else if (*(callEntry1->Number) > *(callEntry2->Number)) + return GenericGreaterThan; + else + return GenericEqual; +} + +/* KphpSsCallEntryFreeRoutine + * + * Frees storage for a system service entry. + */ +VOID KphpSsCallEntryFreeRoutine( + __in PRTL_GENERIC_TABLE Table, + __in PVOID Buffer + ) +{ + ExFreePoolWithTag( + Buffer, + TAG_CALL_ENTRY + ); +} diff --git a/branches/ph-plugins/KProcessHacker/test.c b/branches/ph-plugins/KProcessHacker/test.c new file mode 100644 index 000000000..ffc9d6016 --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/test.c @@ -0,0 +1,71 @@ +/* + * Process Hacker Driver - + * testing code + * + * Copyright (C) 2009 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/kph.h" + +static EX_PUSH_LOCK TestLock; + +VOID KphpTestPushLockThreadStart( + __in PVOID Context + ); + +VOID KphTestPushLock() +{ + ULONG i; + + ExInitializePushLock(&TestLock); + + for (i = 0; i < 10; i++) + { + HANDLE threadHandle; + OBJECT_ATTRIBUTES objectAttributes; + + InitializeObjectAttributes(&objectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); + PsCreateSystemThread(&threadHandle, 0, &objectAttributes, NULL, NULL, KphpTestPushLockThreadStart, NULL); + } +} + +VOID KphpTestPushLockThreadStart( + __in PVOID Context + ) +{ + ULONG i, j; + + for (i = 0; i < 400000; i++) + { + ExAcquirePushLockShared(&TestLock); + + for (j = 0; j < 1000; j++) + YieldProcessor(); + + ExReleasePushLock(&TestLock); + + ExAcquirePushLockExclusive(&TestLock); + + for (j = 0; j < 9000; j++) + YieldProcessor(); + + ExReleasePushLock(&TestLock); + } + + PsTerminateSystemThread(STATUS_SUCCESS); +} diff --git a/branches/ph-plugins/KProcessHacker/trace.c b/branches/ph-plugins/KProcessHacker/trace.c new file mode 100644 index 000000000..57fc98ede --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/trace.c @@ -0,0 +1,344 @@ +/* + * Process Hacker Driver - + * stack tracing + * + * Copyright (C) 2009 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/kph.h" + +BOOLEAN KphpCaptureAndAddStack( + __in PRTL_TRACE_DATABASE Database, + __in KPH_CAPTURE_AND_ADD_STACK_TYPE Type, + __out_opt PRTL_TRACE_BLOCK *TraceBlock + ); + +VOID KphpTraceDatabaseDeleteProcedure( + __in PVOID Object, + __in ULONG Flags + ); + +PKPH_OBJECT_TYPE KphTraceDatabaseType; + +/* KphTraceDatabaseInitialization + * + * Creates the TraceDatabase object type. + */ +NTSTATUS KphTraceDatabaseInitialization() +{ + NTSTATUS status = STATUS_SUCCESS; + + status = KphCreateObjectType( + &KphTraceDatabaseType, + PagedPool, + 0, + KphpTraceDatabaseDeleteProcedure + ); + + if (!NT_SUCCESS(status)) + return status; + + return status; +} + +/* KphCaptureStackBackTrace + * + * Walks the stack, capturing the return address from each frame. + * + * Return value: the number of captured addresses in the buffer. + */ +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++; + + /* Check the input. */ + /* Ensure we won't overrun the buffer. */ + if (FramesToCapture + FramesToSkip > MAX_STACK_DEPTH) + return 0; + /* Make sure the flags are correct. */ + if ((Flags & RTL_WALK_VALID_FLAGS) != Flags) + return 0; + + /* Walk the frame chain. */ + framesFound = RtlWalkFrameChain( + backTrace, + FramesToCapture + FramesToSkip, + Flags + ); + /* Return 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]); + } + + /* Pass the hash back if the caller requested it. */ + if (BackTraceHash) + *BackTraceHash = hash; + + /* Return the number of addresses we copied. */ + return i; +} + +/* KphCaptureAndAddStack + * + * Captures a stack trace and adds it to a trace database. + */ +BOOLEAN KphCaptureAndAddStack( + __in PKPH_TRACE_DATABASE Database, + __in KPH_CAPTURE_AND_ADD_STACK_TYPE Type, + __out_opt PRTL_TRACE_BLOCK *TraceBlock + ) +{ + return KphpCaptureAndAddStack( + Database->Database, + Type, + TraceBlock + ); +} + +/* KphCreateTraceDatabase + * + * Creates a trace database. + */ +NTSTATUS KphCreateTraceDatabase( + __out PKPH_TRACE_DATABASE *Database, + __in_opt SIZE_T MaximumSize, + __in ULONG Flags, + __in ULONG Tag + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PRTL_TRACE_DATABASE rtlDatabase; + PKPH_TRACE_DATABASE database; + + /* Create the trace database. */ + rtlDatabase = RtlTraceDatabaseCreate( + 8, + MaximumSize, + Flags, + Tag, + NULL + ); + + if (!rtlDatabase) + return STATUS_INSUFFICIENT_RESOURCES; + + /* Create the object. */ + status = KphCreateObject( + &database, + sizeof(KPH_TRACE_DATABASE), + 0, + KphTraceDatabaseType, + 0 + ); + + if (!NT_SUCCESS(status)) + { + /* Destroy the trace database, since we can't use it. */ + RtlTraceDatabaseDestroy(rtlDatabase); + + return status; + } + + /* Set up the trace database object. */ + database->Database = rtlDatabase; + *Database = database; + + return status; +} + +NTSTATUS KphQueryTraceDatabase( + __in PKPH_TRACE_DATABASE Database, + __out_bcount_opt(BufferLength) PKPH_TRACEDB_INFORMATION Buffer, + __in_opt ULONG BufferLength, + __out_opt PULONG ReturnLength, + __in KPROCESSOR_MODE AccessMode + ) +{ + NTSTATUS status = STATUS_SUCCESS; + PRTL_TRACE_DATABASE rtlDatabase = Database->Database; + PKPH_TRACEDB_INFORMATION nextEntry; + RTL_TRACE_ENUMERATE enumContext = { 0 }; + PRTL_TRACE_BLOCK currentBlock; + + /* Probe buffers. */ + if (AccessMode != KernelMode) + { + __try + { + if (Buffer) + ProbeForWrite(Buffer, BufferLength, 1); + if (ReturnLength) + ProbeForWrite(ReturnLength, sizeof(ULONG), 1); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + return GetExceptionCode(); + } + } + + /* First entry to write to. */ + /* Note that this is completely safe if Buffer is NULL. */ + nextEntry = Buffer; + + /* Enumerate the trace blocks. */ + while (RtlTraceDatabaseEnumerate(rtlDatabase, &enumContext, ¤tBlock)) + { + PKPH_TRACEDB_INFORMATION currentEntry; + + /* Save the pointer to the entry we are about to write to. */ + currentEntry = nextEntry; + /* Compute the location of the next entry. */ + nextEntry = (PKPH_TRACEDB_INFORMATION)( + (ULONG_PTR)currentEntry + /* Current entry plus */ + sizeof(KPH_TRACEDB_INFORMATION) - /* the size of the current entry minus */ + sizeof(PVOID) + /* the extra PVOID in the Trace array plus */ + currentBlock->Size * sizeof(PVOID) /* the size of the stack trace. */ + ); + + if ( + /* If we got an error last time we tried to write to the buffer, + * don't try again this time. */ + NT_SUCCESS(status) && + /* Make sure the buffer isn't NULL. */ + Buffer && + /* Make sure we don't exceed the buffer length. */ + ((ULONG_PTR)nextEntry - (ULONG_PTR)Buffer) <= BufferLength + ) + { + __try + { + currentEntry->NextEntryOffset = (ULONG)((ULONG_PTR)nextEntry - (ULONG_PTR)currentEntry); + currentEntry->Count = currentBlock->Count; + currentEntry->TraceSize = currentBlock->Size; + memcpy(currentEntry->Trace, currentBlock->Trace, currentBlock->Size * sizeof(PVOID)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + } + else + { + status = STATUS_BUFFER_TOO_SMALL; + } + } + + if (ReturnLength) + { + __try + { + *ReturnLength = (ULONG)((ULONG_PTR)nextEntry - (ULONG_PTR)Buffer); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + } + + return status; +} + +/* KphCaptureAndAddStack + * + * Captures a stack trace and adds it to a trace database. + */ +BOOLEAN KphpCaptureAndAddStack( + __in PRTL_TRACE_DATABASE Database, + __in KPH_CAPTURE_AND_ADD_STACK_TYPE Type, + __out_opt PRTL_TRACE_BLOCK *TraceBlock + ) +{ + PVOID trace[MAX_STACK_DEPTH * 2]; + ULONG kmodeFramesFound = 0; + ULONG umodeFramesFound = 0; + + /* Check input. */ + if (Type >= KphCaptureAndAddMaximum) + return FALSE; + + /* Capture the kernel-mode stack if needed. */ + if ( + Type == KphCaptureAndAddKModeStack || + Type == KphCaptureAndAddBothStacks + ) + kmodeFramesFound = KphCaptureStackBackTrace( + 1, + MAX_STACK_DEPTH - 1, + 0, + trace, + NULL + ); + /* Capture the user-mode stack if needed. */ + if ( + Type == KphCaptureAndAddUModeStack || + Type == KphCaptureAndAddBothStacks + ) + umodeFramesFound = KphCaptureStackBackTrace( + 0, + MAX_STACK_DEPTH - 1, + RTL_WALK_USER_MODE_STACK, + &trace[kmodeFramesFound], + NULL + ); + + /* Add the trace to the database. */ + return RtlTraceDatabaseAdd( + Database, + kmodeFramesFound + umodeFramesFound, + trace, + TraceBlock + ); +} + +/* KphpTraceDatabaseDeleteProcedure + * + * Destroys a trace database. + */ +VOID KphpTraceDatabaseDeleteProcedure( + __in PVOID Object, + __in ULONG Flags + ) +{ + PKPH_TRACE_DATABASE database = (PKPH_TRACE_DATABASE)Object; + + RtlTraceDatabaseDestroy(database->Database); +} diff --git a/branches/ph-plugins/KProcessHacker/util.c b/branches/ph-plugins/KProcessHacker/util.c new file mode 100644 index 000000000..61e3b3ecf --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/util.c @@ -0,0 +1,115 @@ +/* + * Process Hacker Driver - + * utility functions + * + * Copyright (C) 2009 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/util.h" + +/* KphInitializeStream + * + * Initializes a stream. + * + * Stream: The stream to initialize. + * Buffer: The buffer to use. + * Length: The maximum number of bytes that can be stored in + * the buffer. If an attempt is made to overrun or underrun + * the buffer, an exception will be raised. + */ +VOID KphInitializeStream( + __out PKPH_STREAM Stream, + __in PVOID Buffer, + __in ULONG Length + ) +{ + ASSERT(Length > 0); + + Stream->Buffer = Buffer; + Stream->Length = Length; + Stream->Position = 0; +} + +/* KphSeekStream + * + * Changes the position of a stream. + */ +ULONG KphSeekStream( + __inout PKPH_STREAM Stream, + __in LONG Offset, + __in KPH_STREAM_ORIGIN Origin + ) +{ + ULONG newPosition; + + switch (Origin) + { + case StartOrigin: + { + /* Can't seek to before the start of the buffer. */ + if (Offset < 0) + ExRaiseStatus(STATUS_INVALID_PARAMETER_2); + + newPosition = Offset; + } + break; + + case CurrentOrigin: + { + newPosition = Stream->Position + Offset; + } + break; + + case EndOrigin: + { + newPosition = Stream->Length - Offset - 1; + } + break; + } + + /* Check the new position and raise an exception if + * appropriate. + */ + KphCheckStreamPosition(Stream, newPosition); + Stream->Position = newPosition; + + return newPosition; +} + +/* KphWriteDataStream + * + * Writes data to a stream. + */ +ULONG KphWriteDataStream( + __inout PKPH_STREAM Stream, + __in PVOID Data, + __in ULONG Length + ) +{ + /* Check if we are going to overrun the buffer. */ + KphCheckStreamPosition(Stream, Stream->Position + Length); + /* Copy the data. */ + memcpy( + PTR_ADD_OFFSET(Stream->Buffer, Stream->Position), + Data, + Length + ); + + /* Increase the position. */ + return Stream->Position += Length; +} diff --git a/branches/ph-plugins/KProcessHacker/version.c b/branches/ph-plugins/KProcessHacker/version.c new file mode 100644 index 000000000..e8a7a8410 --- /dev/null +++ b/branches/ph-plugins/KProcessHacker/version.c @@ -0,0 +1,536 @@ +/* + * Process Hacker Driver - + * Windows version-specific data + * + * Copyright (C) 2009 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 . + */ + +#define _VERSION_PRIVATE +#include "include/version.h" +#include "include/debug.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, KvInit) +#pragma alloc_text(PAGE, KvScanProc) +#pragma alloc_text(PAGE, KvVerifyPrologue) +#endif + +/* + * mov edi, edi + * push ebp + * mov ebp, esp + */ +static char StandardPrologue[] = { 0x8b, 0xff, 0x55, 0x8b, 0xec }; + +/* KiFastCallEntry */ +/* + * Note that this scan will get the address of + * mov esi, edx + * within KiFastCallEntry, not the start of KiFastCallEntry. + * We will then subtract 7 to get the address of + * inc dword ptr fs:PbSystemCalls + * See sysservice.c for more details. + */ +static char KiFastCallEntry51[] = +{ + 0x8b, 0xf2, 0x8b, 0x5f, 0x0c, 0x33, 0xc9, 0x8a, + 0x0c, 0x18, 0x8b, 0x3f, 0x8b, 0x1c, 0x87, 0x2b +}; +static char KiFastCallEntry60[] = +{ + 0x8b, 0xf2, 0x33, 0xc9, 0x8b, 0x57, 0x0c, 0x8b, + 0x3f, 0x8a, 0x0c, 0x10, 0x8b, 0x14, 0x87, 0x2b +}; +static char KiFastCallEntry61[] = +{ + 0x8b, 0xf2, 0x33, 0xc9, 0x8b, 0x57, 0x0c, 0x8b, + 0x3f, 0x8a, 0x0c, 0x10, 0x8b, 0x14, 0x87, 0x2b +}; +/* Below is the scan to find the start of KiFastCallEntry. */ +/* static char KiFastCallEntry[] = +{ + 0xb9, 0x23, 0x00, 0x00, 0x00, 0x6a, 0x30, 0x0f, + 0xa1, 0x8e, 0xd9, 0x8e, 0xc1, 0x64, 0x8b, 0x0d +}; */ + +/* PsExitSpecialApc */ +static char PsExitSpecialApc51[] = +{ + 0x8b, 0xff, 0x55, 0x8b, 0xec, 0x64, 0xa1, 0x24, + 0x01, 0x00, 0x00, 0x8b, 0x45, 0x08, 0xf6, 0x40 +}; +static char PsExitSpecialApc60[] = +{ + 0x8b, 0xff, 0x55, 0x8b, 0xec, 0x83, 0xe4, 0xf8, + 0x51, 0x8b, 0x45, 0x08, 0xf6, 0x40, 0x28, 0x01 +}; +static char PsExitSpecialApc61[] = +{ + 0x8b, 0xff, 0x55, 0x8b, 0xec, 0x83, 0xe4, 0xf8, + 0x51, 0x8b, 0x45, 0x08, 0xf6, 0x40, 0x28, 0x01 +}; /* same as 6.0 */ + +/* PsTerminateProcess/PspTerminateProcess */ +static char PspTerminateProcess51[] = +{ + 0x8b, 0xff, 0x55, 0x8b, 0xec, 0x56, 0x64, 0xa1, + 0x24, 0x01, 0x00, 0x00, 0x8b, 0x75, 0x08, 0x3b +}; +static char PsTerminateProcess60[] = +{ + 0x8b, 0xff, 0x55, 0x8b, 0xec, 0x53, 0x56, 0x57, + 0x33, 0xd2, 0x6a, 0x08, 0x42, 0x5e, 0x8d, 0xb9 +}; +static char PsTerminateProcess61[] = +{ + 0x8b, 0xff, 0x55, 0x8b, 0xec, 0x51, 0x51, 0x53, + 0x56, 0x64, 0x8b, 0x35, 0x24, 0x01, 0x00, 0x00, + 0x66, 0xff, 0x8e, 0x84, 0x00, 0x00, 0x00, 0x57, + 0xc7, 0x45, 0xfc +}; /* a lot of functions seem to share the first + * 16 bytes of the Windows 7 PsTerminateProcess, + * and a few even share the first 24 bytes. + */ + +/* PspTerminateThreadByPointer */ +static char PspTerminateThreadByPointer51[] = +{ + 0x8b, 0xff, 0x55, 0x8b, 0xec, 0x83, 0xec, 0x0c, + 0x83, 0x4d, 0xf8, 0xff, 0x56, 0x57, 0x8b, 0x7d +}; +static char PspTerminateThreadByPointer60[] = +{ + 0x8b, 0xff, 0x55, 0x8b, 0xec, 0x83, 0xe4, 0xf8, + 0x51, 0x53, 0x56, 0x8b, 0x75, 0x08, 0x57, 0x8d, + 0xbe, 0x60, 0x02, 0x00, 0x00, 0xf6, 0x07, 0x40 +}; +static char PspTerminateThreadByPointer61[] = +{ + 0x8b, 0xff, 0x55, 0x8b, 0xec, 0x83, 0xe4, 0xf8, + 0x51, 0x53, 0x56, 0x8b, 0x75, 0x08, 0x57, 0x8d, + 0xbe, 0x80, 0x02, 0x00, 0x00, 0xf6, 0x07, 0x40 +}; + +/* The following offsets took me a long time to work out, so + please do not steal them. If you want to use them, please + license your project under the GNU GPL (although you are + not legally required to). + */ +NTSTATUS KvInit() +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG majorVersion, minorVersion, servicePack, buildNumber; + + /* Get Windows version information. */ + + RtlWindowsVersion.dwOSVersionInfoSize = sizeof(RtlWindowsVersion); + status = RtlGetVersion((PRTL_OSVERSIONINFOW)&RtlWindowsVersion); + + if (!NT_SUCCESS(status)) + return status; + + majorVersion = RtlWindowsVersion.dwMajorVersion; + minorVersion = RtlWindowsVersion.dwMinorVersion; + servicePack = RtlWindowsVersion.wServicePackMajor; + buildNumber = RtlWindowsVersion.dwBuildNumber; + dfprintf("Windows %d.%d, SP%d.%d, build %d\n", + majorVersion, minorVersion, servicePack, + RtlWindowsVersion.wServicePackMinor, buildNumber + ); + + __NtClose = GetSystemRoutineAddress(L"NtClose"); + + /* NtClose is used as a reference point for most addresses + dependent on where the kernel is loaded, so if we don't + have it, we can't proceed. + */ + if (!__NtClose) + return STATUS_NOT_SUPPORTED; + + /* We also need the address of ZwClose to get KiFastCallEntry. */ + __ZwClose = GetSystemRoutineAddress(L"ZwClose"); + + if (!__ZwClose) + return STATUS_NOT_SUPPORTED; + + /* Windows XP */ + if (majorVersion == 5 && minorVersion == 1) + { + ULONG_PTR searchOffset = (ULONG_PTR)__NtClose; + + WindowsVersion = WINDOWS_XP; + ProcessAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xfff; + ThreadAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3ff; + + OffEtClientId = 0x1ec; + OffEtSpareByteForSs = 0x256; /* Padding, last */ + OffEtStartAddress = 0x224; + OffEtWin32StartAddress = 0x228; + OffEpJob = 0x134; + OffEpObjectTable = 0xc4; + OffEpProtectedProcessOff = 0; + OffEpProtectedProcessBit = 0; + OffEpRundownProtect = 0x80; + OffOhBody = 0x18; + OffOtName = 0x40; + OffOtiGenericMapping = 0x60 + 0x8; + OffOtiOpenProcedure = 0x60 + 0x30; + + SsNtContinue = 0x20; + + /* INIT_SCAN( + KiFastCallEntryScan, + KiFastCallEntry51, + sizeof(KiFastCallEntry51), + (ULONG_PTR)__ZwClose, SCAN_LENGTH, -6 + ); */ + /* We are scanning for PspTerminateProcess which has + the same signature as PsTerminateProcess because + PsTerminateProcess is simply a wrapper on XP. + */ + INIT_SCAN( + PsTerminateProcessScan, + PspTerminateProcess51, + sizeof(PspTerminateProcess51), + searchOffset, SCAN_LENGTH, 0 + ); + INIT_SCAN( + PspTerminateThreadByPointerScan, + PspTerminateThreadByPointer51, + sizeof(PspTerminateThreadByPointer51), + searchOffset, SCAN_LENGTH, 0 + ); + + /* Windows XP SP0 and 1 are not supported */ + if (servicePack == 0) + { + return STATUS_NOT_SUPPORTED; + } + else if (servicePack == 1) + { + return STATUS_NOT_SUPPORTED; + } + else if (servicePack == 2) + { + } + else if (servicePack == 3) + { + } + else + { + return STATUS_NOT_SUPPORTED; + } + + dprintf("Initialized version-specific data for Windows XP SP%d\n", servicePack); + } + /* Windows Server 2003 */ + else if (majorVersion == 5 && minorVersion == 2) + { + WindowsVersion = WINDOWS_SERVER_2003; + + /* Not supported yet */ + return STATUS_NOT_SUPPORTED; + } + /* Windows Vista, Windows Server 2008 */ + else if (majorVersion == 6 && minorVersion == 0) + { + ULONG_PTR searchOffset = (ULONG_PTR)__NtClose; + + WindowsVersion = WINDOWS_VISTA; + ProcessAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xffff; + ThreadAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xffff; + OffEtClientId = 0x20c; + OffEtSpareByteForSs = 0x26f; /* Padding, second-last */ + OffEtStartAddress = 0x1f8; + OffEtWin32StartAddress = 0x240; + OffEpJob = 0x10c; + OffEpObjectTable = 0xdc; + OffEpProtectedProcessOff = 0x224; + OffEpProtectedProcessBit = 0xb; + OffEpRundownProtect = 0x98; + OffOhBody = 0x18; + + INIT_SCAN( + KiFastCallEntryScan, + KiFastCallEntry60, + sizeof(KiFastCallEntry60), + (ULONG_PTR)__ZwClose, SCAN_LENGTH, -7 + ); + INIT_SCAN( + PsTerminateProcessScan, + PsTerminateProcess60, + sizeof(PsTerminateProcess60), + searchOffset, SCAN_LENGTH, 0 + ); + INIT_SCAN( + PspTerminateThreadByPointerScan, + PspTerminateThreadByPointer60, + sizeof(PspTerminateThreadByPointer60), + searchOffset - 0x50000, SCAN_LENGTH, 0 + ); + + /* SP0 */ + if (servicePack == 0) + { + OffOtName = 0x40; + OffOtiGenericMapping = 0x60 + 0xc; + OffOtiOpenProcedure = 0x60 + 0x30; + + SsNtContinue = 0x36; + } + /* SP1 */ + else if (servicePack == 1) + { + OffOtName = 0x8; + OffOtiGenericMapping = 0x28 + 0xc; /* They got rid of the Mutex (an ERESOURCE) */ + OffOtiOpenProcedure = 0x28 + 0x34; + + SsNtContinue = 0x37; + } + /* SP2 */ + else if (servicePack == 2) + { + OffOtName = 0x8; + OffOtiGenericMapping = 0x28 + 0xc; + OffOtiOpenProcedure = 0x28 + 0x34; + + SsNtAddAtom = 0x8; + SsNtAlertResumeThread = 0xd; + SsNtAlertThread = 0xe; + SsNtAllocateLocallyUniqueId = 0xf; + SsNtAllocateUserPhysicalPages = 0x10; + SsNtAllocateUuids = 0x11; + SsNtAllocateVirtualMemory = 0x12; + SsNtApphelpCacheControl = 0x28; + SsNtAreMappedFilesTheSame = 0x29; + SsNtAssignProcessToJobObject = 0x2a; + SsNtCallbackReturn = 0x2b; + SsNtCancelDeviceWakeupRequest = 0x2c; + SsNtCancelIoFile = 0x2d; + SsNtCancelTimer = 0x2e; + SsNtClearEvent = 0x2f; + SsNtClose = 0x30; + SsNtContinue = 0x37; + SsNtCreateDebugObject = 0x38; + SsNtCreateDirectoryObject = 0x39; + SsNtCreateEvent = 0x3a; + SsNtCreateEventPair = 0x3b; + SsNtCreateFile = 0x3c; + SsNtCreateIoCompletion = 0x3d; + SsNtCreateJobObject = 0x3e; + SsNtCreateJobSet = 0x3f; + SsNtCreateKey = 0x40; + SsNtCreateKeyedEvent = 0x168; + SsNtCreateMailslotFile = 0x42; + SsNtCreateMutant = 0x43; + SsNtCreateNamedPipeFile = 0x44; + SsNtCreatePagingFile = 0x46; + SsNtCreatePort = 0x47; + SsNtCreatePrivateNamespace = 0x45; + SsNtCreateProcess = 0x48; + SsNtCreateProcessEx = 0x49; + SsNtCreateProfile = 0x4a; + SsNtCreateSection = 0x4b; + SsNtCreateSemaphore = 0x4c; + SsNtCreateSymbolicLinkObject = 0x4d; + SsNtCreateThread = 0x4e; + SsNtCreateTimer = 0x4f; + SsNtCreateToken = 0x50; + SsNtCreateUserProcess = 0x17f; + SsNtCreateWaitablePort = 0x73; + SsNtDebugActiveProcess = 0x74; + SsNtDebugContinue = 0x75; + SsNtDelayExecution = 0x76; + SsNtDeleteAtom = 0x77; + SsNtDeleteBootEntry = 0x78; + SsNtDeleteDriverEntry = 0x79; + SsNtDeleteFile = 0x7a; + SsNtDeleteKey = 0x7b; + SsNtDeletePrivateNamespace = 0x7c; + SsNtDeleteObjectAuditAlarm = 0x7d; + SsNtDeleteValueKey = 0x7e; + SsNtDeviceIoControlFile = 0x7f; + SsNtDisplayString = 0x80; + SsNtDuplicateObject = 0x81; + SsNtDuplicateToken = 0x82; + SsNtEnumerateBootEntries = 0x83; + SsNtEnumerateDriverEntries = 0x84; + SsNtEnumerateKey = 0x85; + SsNtEnumerateSystemEnvironmentValuesEx = 0x86; + SsNtEnumerateValueKey = 0x88; + SsNtExtendSection = 0x89; + SsNtFilterToken = 0x8a; + SsNtFindAtom = 0x8b; + SsNtFlushBuffersFile = 0x8c; + SsNtFlushInstructionCache = 0x8d; + SsNtFlushKey = 0x8e; + SsNtFlushProcessWriteBuffers = 0x8f; + SsNtFlushVirtualMemory = 0x90; + SsNtFlushWriteBuffer = 0x91; + SsNtFreeUserPhysicalPages = 0x92; + SsNtFreeVirtualMemory = 0x93; + SsNtFsControlFile = 0x96; + SsNtGetContextThread = 0x97; + SsNtGetDevicePowerState = 0x98; + SsNtGetPlugPlayEvent = 0x9a; + SsNtGetWriteWatch = 0x9b; + SsNtImpersonateAnonymousToken = 0x9c; + SsNtImpersonateClientOfPort = 0x9d; + SsNtImpersonateThread = 0x9e; + SsNtInitiatePowerAction = 0xa1; + SsNtIsProcessInJob = 0xa2; + SsNtIsSystemResumeAutomatic = 0xa3; + SsNtListenPort = 0xa4; + SsNtLoadDriver = 0xa5; + SsNtLoadKey = 0xa6; + SsNtLoadKey2 = 0xa7; + SsNtLockFile = 0xa9; + SsNtLockVirtualMemory = 0xac; + SsNtMakePermanentObject = 0xad; + SsNtMakeTemporaryObject = 0xae; + SsNtMapUserPhysicalPages = 0xaf; + SsNtMapUserPhysicalPagesScatter = 0xb0; + SsNtMapViewOfSection = 0xb1; + SsNtModifyBootEntry = 0xb2; + SsNtModifyDriverEntry = 0xb3; + SsNtNotifyChangeDirectoryFile = 0xb4; + SsNtNotifyChangeKey = 0xb5; + SsNtNotifyChangeMultipleKeys = 0xb6; + SsNtOpenDirectoryObject = 0xb7; + SsNtOpenEvent = 0xb8; + SsNtOpenEventPair = 0xb9; + SsNtOpenFile = 0xba; + SsNtOpenIoCompletion = 0xbb; + SsNtOpenJobObject = 0xbc; + SsNtOpenKey = 0xbd; + SsNtOpenKeyedEvent = 0x169; + SsNtOpenMutant = 0xbf; + SsNtOpenObjectAuditAlarm = 0xc1; + SsNtOpenProcess = 0xc2; + SsNtOpenProcessToken = 0xc3; + SsNtOpenProcessTokenEx = 0xc4; + SsNtOpenSection = 0xc5; + SsNtOpenSemaphore = 0xc6; + SsNtOpenSymbolicLinkObject = 0xc8; + SsNtOpenThread = 0xc9; + SsNtOpenThreadToken = 0xca; + SsNtOpenThreadTokenEx = 0xcb; + SsNtOpenTimer = 0xcc; + SsNtReadFile = 0x102; + SsNtWriteFile = 0x163; + } + else + { + return STATUS_NOT_SUPPORTED; + } + + dprintf("Initialized version-specific data for Windows Vista SP%d/Windows Server 2008\n", servicePack); + } + /* Windows 7 */ + else if (majorVersion == 6 && minorVersion == 1) + { + ULONG_PTR psSearchOffset = (ULONG_PTR)GetSystemRoutineAddress(L"PsSetCreateProcessNotifyRoutine"); + ULONG psScanLength = 0x200000; + + if (!psSearchOffset) + return STATUS_NOT_SUPPORTED; + + WindowsVersion = WINDOWS_7; + ProcessAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xffff; + ThreadAllAccess = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xffff; + OffEtClientId = 0x22c; + OffEtSpareByteForSs = 0x2b4; /* Padding, last */ + OffEtStartAddress = 0x218; + OffEtWin32StartAddress = 0x260; + OffEpJob = 0x124; + OffEpObjectTable = 0xf4; + OffEpProtectedProcessOff = 0x26c; + OffEpProtectedProcessBit = 0xb; + OffEpRundownProtect = 0xb0; + OffOhBody = 0x18; + OffOtName = 0x8; + OffOtiGenericMapping = 0x28 + 0xc; + OffOtiOpenProcedure = 0x28 + 0x34; + + SsNtContinue = 0x3c; + + INIT_SCAN( + KiFastCallEntryScan, + KiFastCallEntry61, + sizeof(KiFastCallEntry61), + (ULONG_PTR)__ZwClose, SCAN_LENGTH, -7 + ); + INIT_SCAN( + PsTerminateProcessScan, + PsTerminateProcess61, + sizeof(PsTerminateProcess61), + psSearchOffset, psScanLength, 0 + ); + INIT_SCAN( + PspTerminateThreadByPointerScan, + PspTerminateThreadByPointer61, + sizeof(PspTerminateThreadByPointer61), + psSearchOffset, psScanLength, 0 + ); + + /* SP0 */ + if (servicePack == 0) + { + } + else + { + return STATUS_NOT_SUPPORTED; + } + + dprintf("Initialized version-specific data for Windows 7 SP%d\n", servicePack); + } + else + { + return STATUS_NOT_SUPPORTED; + } + + return status; +} + +PVOID KvScanProc( + PKV_SCANPROC ScanProc + ) +{ + PUCHAR bytes = ScanProc->Bytes; + ULONG length = ScanProc->Length; + ULONG_PTR endAddress = ScanProc->StartAddress + ScanProc->ScanLength; + ULONG_PTR i; + + for (i = ScanProc->StartAddress; i < endAddress; i++) + { + if (memcmp((PVOID)i, bytes, length) == 0) + return (PVOID)(i + ScanProc->Displacement); + } + + return NULL; +} + +PVOID KvVerifyPrologue( + PVOID Address + ) +{ + if (memcmp(Address, StandardPrologue, 5) == 0) + return Address; + else + return NULL; +} diff --git a/branches/ph-plugins/LICENSE.txt b/branches/ph-plugins/LICENSE.txt new file mode 100644 index 000000000..89c3eac73 --- /dev/null +++ b/branches/ph-plugins/LICENSE.txt @@ -0,0 +1,674 @@ + 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/branches/ph-plugins/NProcessHacker/NProcessHacker.sln b/branches/ph-plugins/NProcessHacker/NProcessHacker.sln new file mode 100644 index 000000000..e43c98b54 --- /dev/null +++ b/branches/ph-plugins/NProcessHacker/NProcessHacker.sln @@ -0,0 +1,52 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NProcessHacker", "NProcessHacker.vcproj", "{52426135-4597-4988-B5BC-BE8E93489A53}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Test", "Test\Test.vcproj", "{A910A5C9-9BCA-47BA-AFAD-92698E512DED}" + ProjectSection(ProjectDependencies) = postProject + {52426135-4597-4988-B5BC-BE8E93489A53} = {52426135-4597-4988-B5BC-BE8E93489A53} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NProcessHackerHook", "NProcessHackerHook\NProcessHackerHook.vcproj", "{DC2D13B6-4BD1-4AC8-933F-DDB0DE850162}" + ProjectSection(ProjectDependencies) = postProject + {52426135-4597-4988-B5BC-BE8E93489A53} = {52426135-4597-4988-B5BC-BE8E93489A53} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|Win64 = Debug|Win64 + Release|Win32 = Release|Win32 + Release|Win64 = Release|Win64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {52426135-4597-4988-B5BC-BE8E93489A53}.Debug|Win32.ActiveCfg = Debug|x64 + {52426135-4597-4988-B5BC-BE8E93489A53}.Debug|Win32.Build.0 = Debug|x64 + {52426135-4597-4988-B5BC-BE8E93489A53}.Debug|Win64.ActiveCfg = Debug|x64 + {52426135-4597-4988-B5BC-BE8E93489A53}.Debug|Win64.Build.0 = Debug|x64 + {52426135-4597-4988-B5BC-BE8E93489A53}.Release|Win32.ActiveCfg = Release|Win32 + {52426135-4597-4988-B5BC-BE8E93489A53}.Release|Win32.Build.0 = Release|Win32 + {52426135-4597-4988-B5BC-BE8E93489A53}.Release|Win64.ActiveCfg = Release|x64 + {52426135-4597-4988-B5BC-BE8E93489A53}.Release|Win64.Build.0 = Release|x64 + {A910A5C9-9BCA-47BA-AFAD-92698E512DED}.Debug|Win32.ActiveCfg = Debug|Win32 + {A910A5C9-9BCA-47BA-AFAD-92698E512DED}.Debug|Win32.Build.0 = Debug|Win32 + {A910A5C9-9BCA-47BA-AFAD-92698E512DED}.Debug|Win64.ActiveCfg = Debug|x64 + {A910A5C9-9BCA-47BA-AFAD-92698E512DED}.Debug|Win64.Build.0 = Debug|x64 + {A910A5C9-9BCA-47BA-AFAD-92698E512DED}.Release|Win32.ActiveCfg = Release|Win32 + {A910A5C9-9BCA-47BA-AFAD-92698E512DED}.Release|Win32.Build.0 = Release|Win32 + {A910A5C9-9BCA-47BA-AFAD-92698E512DED}.Release|Win64.ActiveCfg = Release|x64 + {A910A5C9-9BCA-47BA-AFAD-92698E512DED}.Release|Win64.Build.0 = Release|x64 + {DC2D13B6-4BD1-4AC8-933F-DDB0DE850162}.Debug|Win32.ActiveCfg = Debug|x64 + {DC2D13B6-4BD1-4AC8-933F-DDB0DE850162}.Debug|Win32.Build.0 = Debug|x64 + {DC2D13B6-4BD1-4AC8-933F-DDB0DE850162}.Debug|Win64.ActiveCfg = Debug|x64 + {DC2D13B6-4BD1-4AC8-933F-DDB0DE850162}.Debug|Win64.Build.0 = Debug|x64 + {DC2D13B6-4BD1-4AC8-933F-DDB0DE850162}.Release|Win32.ActiveCfg = Release|Win32 + {DC2D13B6-4BD1-4AC8-933F-DDB0DE850162}.Release|Win32.Build.0 = Release|Win32 + {DC2D13B6-4BD1-4AC8-933F-DDB0DE850162}.Release|Win64.ActiveCfg = Release|x64 + {DC2D13B6-4BD1-4AC8-933F-DDB0DE850162}.Release|Win64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/branches/ph-plugins/NProcessHacker/NProcessHacker.vcproj b/branches/ph-plugins/NProcessHacker/NProcessHacker.vcproj new file mode 100644 index 000000000..6834dca3a --- /dev/null +++ b/branches/ph-plugins/NProcessHacker/NProcessHacker.vcproj @@ -0,0 +1,410 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/ph-plugins/NProcessHacker/NProcessHackerHook/NProcessHackerHook.vcproj b/branches/ph-plugins/NProcessHacker/NProcessHackerHook/NProcessHackerHook.vcproj new file mode 100644 index 000000000..254e1902d --- /dev/null +++ b/branches/ph-plugins/NProcessHacker/NProcessHackerHook/NProcessHackerHook.vcproj @@ -0,0 +1,334 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/ph-plugins/NProcessHacker/NProcessHackerHook/nphhook.c b/branches/ph-plugins/NProcessHacker/NProcessHackerHook/nphhook.c new file mode 100644 index 000000000..c0d06ae3a --- /dev/null +++ b/branches/ph-plugins/NProcessHacker/NProcessHackerHook/nphhook.c @@ -0,0 +1,23 @@ +#include +#include "../kphhook.h" + +BOOL WINAPI DllMain( + HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved + ) +{ + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + KphHookInit(); + break; + case DLL_PROCESS_DETACH: + KphHookDeinit(); + break; + default: + break; + } + + return TRUE; +} diff --git a/branches/ph-plugins/NProcessHacker/Release/NProcessHacker.dll b/branches/ph-plugins/NProcessHacker/Release/NProcessHacker.dll new file mode 100644 index 000000000..b37a9623d Binary files /dev/null and b/branches/ph-plugins/NProcessHacker/Release/NProcessHacker.dll differ diff --git a/branches/ph-plugins/NProcessHacker/Test/Test.vcproj b/branches/ph-plugins/NProcessHacker/Test/Test.vcproj new file mode 100644 index 000000000..fd7dceb32 --- /dev/null +++ b/branches/ph-plugins/NProcessHacker/Test/Test.vcproj @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/branches/ph-plugins/NProcessHacker/Test/test.c b/branches/ph-plugins/NProcessHacker/Test/test.c new file mode 100644 index 000000000..33abb2b12 --- /dev/null +++ b/branches/ph-plugins/NProcessHacker/Test/test.c @@ -0,0 +1,29 @@ +#ifndef UNICODE +#define UNICODE +#endif + +#include +#include +#include "../kph.h" +#include "../kphhook.h" + +int wmain(int argc, WCHAR *argv[]) +{ + ULONG pid; + HANDLE processHandle; + CHAR memory[0x1000]; + + if (argc < 2) + { + printf("Usage: test [pid to kill]\n"); + return 1; + } + + pid = _wtoi(argv[1]); + + KphHookInit(); + processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); + ReadProcessMemory(processHandle, (PVOID)0x10000, memory, 0x1000, NULL); + + return 0; +} diff --git a/branches/ph-plugins/NProcessHacker/hook.c b/branches/ph-plugins/NProcessHacker/hook.c new file mode 100644 index 000000000..0ba0a55ed --- /dev/null +++ b/branches/ph-plugins/NProcessHacker/hook.c @@ -0,0 +1,96 @@ +/* + * Process Hacker Library - + * hooks + * + * Copyright (C) 2009 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 "hook.h" + +VOID PHAPI PhInitializeHook( + PPH_HOOK Hook, + PVOID Function, + PVOID Target + ) +{ + memset(Hook, 0, sizeof(PH_HOOK)); + Hook->Function = Function; + Hook->Target = Target; +} + +NTSTATUS PHAPI PhHook( + PPH_HOOK Hook + ) +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG oldProtection; + PCHAR function; + + /* Change the page protection of the target page so we can write to it. */ + if (!VirtualProtect(Hook->Function, 5, PAGE_EXECUTE_READWRITE, &oldProtection)) + return STATUS_ACCESS_VIOLATION; + + __try + { + function = (PCHAR)Hook->Function; + /* Copy the original five bytes for unhooking. */ + memcpy(Hook->Bytes, function, 5); + /* Hook the function by writing a jump instruction. */ + Hook->Hooked = TRUE; + /* jmp Target */ + *function = 0xe9; + *(PULONG_PTR)(function + 1) = (ULONG_PTR)Hook->Target - (ULONG_PTR)Hook->Function - 5; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + + /* Restore the old page protection. */ + VirtualProtect(Hook->Function, 5, oldProtection, NULL); + + return status; +} + +NTSTATUS PHAPI PhUnhook( + PPH_HOOK Hook + ) +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG oldProtection; + + /* Change the page protection of the target page so we can write to it. */ + if (!VirtualProtect(Hook->Function, 5, PAGE_EXECUTE_READWRITE, &oldProtection)) + return STATUS_ACCESS_VIOLATION; + + __try + { + /* Unpatch the function by restoring the original first 5 bytes. */ + memcpy(Hook->Function, Hook->Bytes, 5); + Hook->Hooked = FALSE; + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + status = GetExceptionCode(); + } + + /* Restore the old page protection. */ + VirtualProtect(Hook->Function, 5, oldProtection, NULL); + + return status; +} diff --git a/branches/ph-plugins/NProcessHacker/hook.h b/branches/ph-plugins/NProcessHacker/hook.h new file mode 100644 index 000000000..e06c74bfc --- /dev/null +++ b/branches/ph-plugins/NProcessHacker/hook.h @@ -0,0 +1,93 @@ +/* + * Process Hacker Library - + * hooks + * + * Copyright (C) 2009 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 . + */ + +#ifndef _HOOK_H +#define _HOOK_H + +#include "nph.h" + +/* Almost exactly the same as the hooking code in KProcessHacker. */ + +#ifdef _X86_ + +#define PH_DEFINE_HOOK_CALL(Name, Arguments, Hook) \ + __declspec(naked) Name(Arguments) \ + { \ + __asm lea eax, Hook \ + __asm mov eax, [eax+PH_HOOK.Function] \ + __asm add eax, 5 \ + __asm push ebp \ + __asm mov ebp, esp \ + __asm jmp eax \ + } \ + +#define PH_DEFINE_NT_HOOK_CALL(Name, Arguments, Hook) \ + __declspec(naked) Name(Arguments) \ + { \ + __asm lea eax, Hook \ + __asm mov edx, [eax+PH_HOOK.Function] \ + __asm add edx, 5 \ + /* Store the system call number in eax. */ \ + __asm mov eax, dword ptr [eax+PH_HOOK.Bytes+1] \ + __asm jmp edx \ + } \ + +#else + +#define PH_DEFINE_HOOK_CALL(Name, Arguments, Hook) \ + Name(Arguments) \ + { \ + RaiseException(STATUS_NOT_SUPPORTED, 0, 0, NULL); \ + return 0; \ + } \ + +#define PH_DEFINE_NT_HOOK_CALL(Name, Arguments, Hook) \ + Name(Arguments) \ + { \ + RaiseException(STATUS_NOT_SUPPORTED, 0, 0, NULL); \ + return 0; \ + } \ + +#endif +typedef struct _PH_HOOK +{ + PVOID Function; + PVOID Target; + BOOLEAN Hooked; + CHAR Bytes[5]; +} PH_HOOK, *PPH_HOOK; + +NPHAPI VOID PHAPI PhInitializeHook( + PPH_HOOK Hook, + PVOID Function, + PVOID Target + ); + +NPHAPI NTSTATUS PHAPI PhHook( + PPH_HOOK Hook + ); + +NPHAPI NTSTATUS PHAPI PhUnhook( + PPH_HOOK Hook + ); + +#endif diff --git a/branches/ph-plugins/NProcessHacker/kph.c b/branches/ph-plugins/NProcessHacker/kph.c new file mode 100644 index 000000000..3f5052c26 --- /dev/null +++ b/branches/ph-plugins/NProcessHacker/kph.c @@ -0,0 +1,880 @@ +/* + * Process Hacker Library - + * KProcessHacker interface + * + * Copyright (C) 2009 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 "kph.h" + +NTSTATUS PHAPI KphpDeviceIoControl( + HANDLE KphHandle, + ULONG KphControlCode, + PVOID InBuffer, + ULONG InBufferLength, + PVOID OutBuffer, + ULONG OutBufferLength, + PULONG ReturnLength + ); + +_NtDeviceIoControlFile NtDeviceIoControlFile = NULL; +_NtTerminateProcess NtTerminateProcess = NULL; +_NtTerminateThread NtTerminateThread = NULL; + +NTSTATUS PHAPI KphInit() +{ + if (!(NtDeviceIoControlFile = (_NtDeviceIoControlFile) + PhGetProcAddress(L"ntdll.dll", "NtDeviceIoControlFile"))) + return STATUS_PROCEDURE_NOT_FOUND; + if (!(NtTerminateProcess = (_NtTerminateProcess) + PhGetProcAddress(L"ntdll.dll", "NtTerminateProcess"))) + return STATUS_PROCEDURE_NOT_FOUND; + if (!(NtTerminateThread = (_NtTerminateThread) + PhGetProcAddress(L"ntdll.dll", "NtTerminateThread"))) + return STATUS_PROCEDURE_NOT_FOUND; + + return STATUS_SUCCESS; +} + +NTSTATUS PHAPI KphConnect( + __out PHANDLE KphHandle + ) +{ + HANDLE deviceHandle; + + deviceHandle = CreateFileW( + KPH_DEVICE_NAME, + FILE_GENERIC_READ | FILE_GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL + ); + + if (deviceHandle == INVALID_HANDLE_VALUE) + { + deviceHandle = NULL; + return STATUS_UNSUCCESSFUL; + } + + *KphHandle = deviceHandle; + + return STATUS_SUCCESS; +} + +NTSTATUS PHAPI KphDisconnect( + __in HANDLE KphHandle + ) +{ + if (CloseHandle(KphHandle)) + return STATUS_SUCCESS; + else + return STATUS_INVALID_HANDLE; +} + +NTSTATUS PHAPI KphpDeviceIoControl( + HANDLE KphHandle, + ULONG KphControlCode, + PVOID InBuffer, + ULONG InBufferLength, + PVOID OutBuffer, + ULONG OutBufferLength, + PULONG ReturnLength + ) +{ + NTSTATUS status; + IO_STATUS_BLOCK ioStatusBlock; + + status = NtDeviceIoControlFile( + KphHandle, + NULL, + NULL, + NULL, + &ioStatusBlock, + KphControlCode, + InBuffer, + InBufferLength, + OutBuffer, + OutBufferLength + ); + + if (NT_SUCCESS(status) && ReturnLength) + *ReturnLength = ioStatusBlock.Information; + + return status; +} + +NTSTATUS PHAPI KphGetFeatures( + __in HANDLE KphHandle, + __out PULONG Features + ) +{ + NTSTATUS status; + ULONG features; + + if (NT_SUCCESS( + status = KphpDeviceIoControl( + KphHandle, + KPH_GETFEATURES, + NULL, + 0, + &features, + sizeof(ULONG), + NULL) + )) + *Features = features; + + return status; +} + +NTSTATUS PHAPI KphRead( + __in HANDLE KphHandle, + __in PVOID Address, + __out_bcount(BufferLength) PVOID Buffer, + __in ULONG BufferLength + ) +{ + return KphpDeviceIoControl( + KphHandle, + KPH_READ, + &Address, + sizeof(PVOID), + Buffer, + BufferLength, + NULL + ); +} + +NTSTATUS PHAPI KphWrite( + __in HANDLE KphHandle, + __in PVOID Address, + __in_bcount(Length) PVOID Buffer, + __in ULONG Length + ) +{ + NTSTATUS status; + PVOID data = PhAlloc(Length + sizeof(PVOID)); + + *(PVOID *)data = Address; + memcpy((PCHAR)data + sizeof(PVOID), Buffer, Length); + + status = KphpDeviceIoControl( + KphHandle, + KPH_WRITE, + data, + Length + sizeof(PVOID), + NULL, + 0, + NULL + ); + PhFree(data); + + return status; +} + +NTSTATUS PHAPI KphOpenProcess( + __in HANDLE KphHandle, + __out PHANDLE ProcessHandle, + __in HANDLE ProcessId, + __in ACCESS_MASK DesiredAccess + ) +{ + NTSTATUS status; + + struct + { + HANDLE ProcessId; + ACCESS_MASK DesiredAccess; + } args; + struct + { + HANDLE ProcessHandle; + } ret; + + args.ProcessId = ProcessId; + args.DesiredAccess = DesiredAccess; + + status = KphpDeviceIoControl( + KphHandle, + KPH_OPENPROCESS, + &args, + sizeof(args), + &ret, + sizeof(ret), + NULL + ); + + *ProcessHandle = ret.ProcessHandle; + + return status; +} + +NTSTATUS PHAPI KphOpenThread( + __in HANDLE KphHandle, + __out PHANDLE ThreadHandle, + __in HANDLE ThreadId, + __in ACCESS_MASK DesiredAccess + ) +{ + NTSTATUS status; + + struct + { + HANDLE ThreadId; + ACCESS_MASK DesiredAccess; + } args; + struct + { + HANDLE ThreadHandle; + } ret; + + args.ThreadId = ThreadId; + args.DesiredAccess = DesiredAccess; + + status = KphpDeviceIoControl( + KphHandle, + KPH_OPENTHREAD, + &args, + sizeof(args), + &ret, + sizeof(ret), + NULL + ); + + *ThreadHandle = ret.ThreadHandle; + + return status; +} + +NTSTATUS PHAPI KphOpenProcessToken( + __in HANDLE KphHandle, + __out PHANDLE TokenHandle, + __in HANDLE ProcessHandle, + __in ACCESS_MASK DesiredAccess + ) +{ + NTSTATUS status; + + struct + { + HANDLE ProcessHandle; + ACCESS_MASK DesiredAccess; + } args; + struct + { + HANDLE TokenHandle; + } ret; + + args.ProcessHandle = ProcessHandle; + args.DesiredAccess = DesiredAccess; + + status = KphpDeviceIoControl( + KphHandle, + KPH_OPENPROCESSTOKEN, + &args, + sizeof(args), + &ret, + sizeof(ret), + NULL + ); + + *TokenHandle = ret.TokenHandle; + + return status; +} + +NTSTATUS PHAPI KphGetProcessProtected( + __in HANDLE KphHandle, + __in ULONG_PTR ProcessId, + __out PBOOLEAN IsProtected + ) +{ + NTSTATUS status; + + struct + { + HANDLE ProcessId; + } args; + struct + { + BOOLEAN IsProtected; + } ret; + + args.ProcessId = (HANDLE)ProcessId; + + status = KphpDeviceIoControl( + KphHandle, + KPH_GETPROCESSPROTECTED, + &args, + sizeof(args), + &ret, + sizeof(ret), + NULL + ); + + *IsProtected = ret.IsProtected; + + return status; +} + +NTSTATUS PHAPI KphSetProcessProtected( + __in HANDLE KphHandle, + __in ULONG_PTR ProcessId, + __in BOOLEAN IsProtected + ) +{ + struct + { + HANDLE ProcessId; + BOOLEAN IsProtected; + } args; + + args.ProcessId = (HANDLE)ProcessId; + args.IsProtected = IsProtected; + + return KphpDeviceIoControl( + KphHandle, + KPH_SETPROCESSPROTECTED, + &args, + sizeof(args), + NULL, + 0, + NULL + ); +} + +NTSTATUS PHAPI KphTerminateProcess( + __in HANDLE KphHandle, + __in HANDLE ProcessHandle, + __in NTSTATUS ExitStatus + ) +{ + NTSTATUS status = STATUS_SUCCESS; + struct + { + HANDLE ProcessHandle; + NTSTATUS ExitStatus; + } args; + + args.ProcessHandle = ProcessHandle; + args.ExitStatus = ExitStatus; + + status = KphpDeviceIoControl( + KphHandle, + KPH_TERMINATEPROCESS, + &args, + sizeof(args), + NULL, + 0, + NULL + ); + + /* Check if we were trying to terminate the current + * process and do it now. */ + if (status == STATUS_CANT_TERMINATE_SELF) + status = NtTerminateProcess(GetCurrentProcess(), ExitStatus); + + return status; +} + +NTSTATUS PHAPI KphSuspendProcess( + __in HANDLE KphHandle, + __in HANDLE ProcessHandle + ) +{ + struct + { + HANDLE ProcessHandle; + } args; + + args.ProcessHandle = ProcessHandle; + + return KphpDeviceIoControl( + KphHandle, + KPH_SUSPENDPROCESS, + &args, + sizeof(args), + NULL, + 0, + NULL + ); +} + +NTSTATUS PHAPI KphResumeProcess( + __in HANDLE KphHandle, + __in HANDLE ProcessHandle + ) +{ + struct + { + HANDLE ProcessHandle; + } args; + + args.ProcessHandle = ProcessHandle; + + return KphpDeviceIoControl( + KphHandle, + KPH_RESUMEPROCESS, + &args, + sizeof(args), + NULL, + 0, + NULL + ); +} + +NTSTATUS PHAPI KphReadVirtualMemory( + __in HANDLE KphHandle, + __in HANDLE ProcessHandle, + __in PVOID BaseAddress, + __out_bcount(BufferLength) PVOID Buffer, + __in ULONG BufferLength, + __out_opt PULONG ReturnLength + ) +{ + struct + { + HANDLE ProcessHandle; + PVOID BaseAddress; + PVOID Buffer; + ULONG BufferLength; + PULONG ReturnLength; + } args; + + args.ProcessHandle = ProcessHandle; + args.BaseAddress = BaseAddress; + args.Buffer = Buffer; + args.BufferLength = BufferLength; + args.ReturnLength = ReturnLength; + + return KphpDeviceIoControl( + KphHandle, + KPH_READVIRTUALMEMORY, + &args, + sizeof(args), + NULL, + 0, + NULL + ); +} + +NTSTATUS PHAPI KphWriteVirtualMemory( + __in HANDLE KphHandle, + __in HANDLE ProcessHandle, + __in PVOID BaseAddress, + __in_bcount(BufferLength) PVOID Buffer, + __in ULONG BufferLength, + __out_opt PULONG ReturnLength + ) +{ + struct + { + HANDLE ProcessHandle; + PVOID BaseAddress; + PVOID Buffer; + ULONG BufferLength; + PULONG ReturnLength; + } args; + + args.ProcessHandle = ProcessHandle; + args.BaseAddress = BaseAddress; + args.Buffer = Buffer; + args.BufferLength = BufferLength; + args.ReturnLength = ReturnLength; + + return KphpDeviceIoControl( + KphHandle, + KPH_WRITEVIRTUALMEMORY, + &args, + sizeof(args), + NULL, + 0, + NULL + ); +} + +NTSTATUS PHAPI KphOpenProcessJob( + __in HANDLE KphHandle, + __out PHANDLE JobHandle, + __in HANDLE ProcessHandle, + __in ACCESS_MASK DesiredAccess + ) +{ + NTSTATUS status; + + struct + { + HANDLE ProcessHandle; + ACCESS_MASK DesiredAccess; + } args; + struct + { + HANDLE JobHandle; + } ret; + + args.ProcessHandle = ProcessHandle; + args.DesiredAccess = DesiredAccess; + + status = KphpDeviceIoControl( + KphHandle, + KPH_OPENPROCESSJOB, + &args, + sizeof(args), + &ret, + sizeof(ret), + NULL + ); + + *JobHandle = ret.JobHandle; + + return status; +} + +NTSTATUS PHAPI KphGetContextThread( + __in HANDLE KphHandle, + __in HANDLE ThreadHandle, + __inout PCONTEXT ThreadContext + ) +{ + struct + { + HANDLE ThreadHandle; + PCONTEXT ThreadContext; + } args; + + args.ThreadHandle = ThreadHandle; + args.ThreadContext = ThreadContext; + + return KphpDeviceIoControl( + KphHandle, + KPH_GETCONTEXTTHREAD, + &args, + sizeof(args), + NULL, + 0, + NULL + ); +} + +NTSTATUS PHAPI KphSetContextThread( + __in HANDLE KphHandle, + __in HANDLE ThreadHandle, + __in PCONTEXT ThreadContext + ) +{ + struct + { + HANDLE ThreadHandle; + PCONTEXT ThreadContext; + } args; + + args.ThreadHandle = ThreadHandle; + args.ThreadContext = ThreadContext; + + return KphpDeviceIoControl( + KphHandle, + KPH_SETCONTEXTTHREAD, + &args, + sizeof(args), + NULL, + 0, + NULL + ); +} + +NTSTATUS PHAPI KphTerminateThread( + __in HANDLE KphHandle, + __in HANDLE ThreadHandle, + __in NTSTATUS ExitStatus + ) +{ + NTSTATUS status = STATUS_SUCCESS; + struct + { + HANDLE ThreadHandle; + NTSTATUS ExitStatus; + } args; + + args.ThreadHandle = ThreadHandle; + args.ExitStatus = ExitStatus; + + status = KphpDeviceIoControl( + KphHandle, + KPH_TERMINATETHREAD, + &args, + sizeof(args), + NULL, + 0, + NULL + ); + + if (status == STATUS_CANT_TERMINATE_SELF) + status = NtTerminateThread(GetCurrentThread(), ExitStatus); + + return status; +} + +NTSTATUS PHAPI KphSetHandleGrantedAccess( + __in HANDLE KphHandle, + __in HANDLE Handle, + __in ACCESS_MASK GrantedAccess + ) +{ + struct + { + HANDLE Handle; + ACCESS_MASK GrantedAccess; + } args; + + args.Handle = Handle; + args.GrantedAccess = GrantedAccess; + + return KphpDeviceIoControl( + KphHandle, + KPH_SETHANDLEGRANTEDACCESS, + &args, + sizeof(args), + NULL, + 0, + NULL + ); +} + +NTSTATUS PHAPI KphProtectAdd( + __in HANDLE KphHandle, + __in HANDLE ProcessHandle, + __in BOOLEAN AllowKernelMode, + __in ACCESS_MASK ProcessAllowMask, + __in ACCESS_MASK ThreadAllowMask + ) +{ + struct + { + HANDLE ProcessHandle; + LOGICAL AllowKernelMode; + ACCESS_MASK ProcessAllowMask; + ACCESS_MASK ThreadAllowMask; + } args; + + args.ProcessHandle = ProcessHandle; + args.AllowKernelMode = AllowKernelMode; + args.ProcessAllowMask = ProcessAllowMask; + args.ThreadAllowMask = ThreadAllowMask; + + return KphpDeviceIoControl( + KphHandle, + KPH_PROTECTADD, + &args, + sizeof(args), + NULL, + 0, + NULL + ); +} + +NTSTATUS PHAPI KphProtectRemove( + __in HANDLE KphHandle, + __in HANDLE ProcessHandle + ) +{ + struct + { + HANDLE ProcessHandle; + } args; + + args.ProcessHandle = ProcessHandle; + + return KphpDeviceIoControl( + KphHandle, + KPH_PROTECTREMOVE, + &args, + sizeof(args), + NULL, + 0, + NULL + ); +} + +NTSTATUS PHAPI KphProtectQuery( + __in HANDLE KphHandle, + __in HANDLE ProcessHandle, + __out PBOOLEAN AllowKernelMode, + __out PACCESS_MASK ProcessAllowMask, + __out PACCESS_MASK ThreadAllowMask + ) +{ + NTSTATUS status = STATUS_SUCCESS; + struct + { + HANDLE ProcessHandle; + PLOGICAL AllowKernelMode; + PACCESS_MASK ProcessAllowMask; + PACCESS_MASK ThreadAllowMask; + } args; + LOGICAL allowKernelMode; + + args.ProcessHandle = ProcessHandle; + args.AllowKernelMode = &allowKernelMode; + args.ProcessAllowMask = ProcessAllowMask; + args.ThreadAllowMask = ThreadAllowMask; + + status = KphpDeviceIoControl( + KphHandle, + KPH_PROTECTQUERY, + &args, + sizeof(args), + NULL, + 0, + NULL + ); + + *AllowKernelMode = (BOOLEAN)allowKernelMode; + + return status; +} + +NTSTATUS PHAPI KphUnsafeReadVirtualMemory( + __in HANDLE KphHandle, + __in HANDLE ProcessHandle, + __in PVOID BaseAddress, + __in_bcount(BufferLength) PVOID Buffer, + __in ULONG BufferLength, + __out_opt PULONG ReturnLength + ) +{ + struct + { + HANDLE ProcessHandle; + PVOID BaseAddress; + PVOID Buffer; + ULONG BufferLength; + PULONG ReturnLength; + } args; + + args.ProcessHandle = ProcessHandle; + args.BaseAddress = BaseAddress; + args.Buffer = Buffer; + args.BufferLength = BufferLength; + args.ReturnLength = ReturnLength; + + return KphpDeviceIoControl( + KphHandle, + KPH_UNSAFEREADVIRTUALMEMORY, + &args, + sizeof(args), + NULL, + 0, + NULL + ); +} + +NTSTATUS PHAPI KphSetExecuteOptions( + __in HANDLE KphHandle, + __in HANDLE ProcessHandle, + __in ULONG ExecuteOptions + ) +{ + struct + { + HANDLE ProcessHandle; + ULONG ExecuteOptions; + } args; + + args.ProcessHandle = ProcessHandle; + args.ExecuteOptions = ExecuteOptions; + + return KphpDeviceIoControl( + KphHandle, + KPH_SETEXECUTEOPTIONS, + &args, + sizeof(args), + NULL, + 0, + NULL + ); +} + +NTSTATUS PHAPI KphQueryProcessHandles( + __in HANDLE KphHandle, + __in HANDLE ProcessHandle, + __out_bcount_opt(BufferLength) PVOID Buffer, + __in_opt ULONG BufferLength, + __out_opt PULONG ReturnLength + ) +{ + struct + { + HANDLE ProcessHandle; + PVOID Buffer; + ULONG BufferLength; + PULONG ReturnLength; + } args; + + args.ProcessHandle = ProcessHandle; + args.Buffer = Buffer; + args.BufferLength = BufferLength; + args.ReturnLength = ReturnLength; + + return KphpDeviceIoControl( + KphHandle, + KPH_QUERYPROCESSHANDLES, + &args, + sizeof(args), + NULL, + 0, + NULL + ); +} + +NTSTATUS PHAPI KphOpenThreadProcess( + __in HANDLE KphHandle, + __out PHANDLE ProcessHandle, + __in HANDLE ThreadHandle, + __in ACCESS_MASK DesiredAccess + ) +{ + NTSTATUS status; + + struct + { + HANDLE ThreadHandle; + ACCESS_MASK DesiredAccess; + } args; + struct + { + HANDLE ProcessHandle; + } ret; + + args.ThreadHandle = ThreadHandle; + args.DesiredAccess = DesiredAccess; + + status = KphpDeviceIoControl( + KphHandle, + KPH_OPENTHREADPROCESS, + &args, + sizeof(args), + &ret, + sizeof(ret), + NULL + ); + + *ProcessHandle = ret.ProcessHandle; + + return status; +} diff --git a/branches/ph-plugins/NProcessHacker/kph.h b/branches/ph-plugins/NProcessHacker/kph.h new file mode 100644 index 000000000..f66820022 --- /dev/null +++ b/branches/ph-plugins/NProcessHacker/kph.h @@ -0,0 +1,289 @@ +/* + * Process Hacker Library - + * KProcessHacker interface + * + * Copyright (C) 2009 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 . + */ + +#ifndef _KPH_H +#define _KPH_H + +#include "nph.h" +#include "nativedefs.h" + +#define KPH_DEVICE_TYPE (0x9999) +#define KPH_DEVICE_NAME (L"\\\\.\\KProcessHacker") + +#define KPHF_PSTERMINATEPROCESS 0x1 +#define KPHF_PSPTERMINATETHREADBPYPOINTER 0x2 + +#define METHOD_BUFFERED 0 +#define METHOD_IN_DIRECT 1 +#define METHOD_OUT_DIRECT 2 +#define METHOD_NEITHER 3 + +#ifndef FILE_ANY_ACCESS +#define FILE_ANY_ACCESS 0 +#define FILE_SPECIAL_ACCESS (FILE_ANY_ACCESS) +#define FILE_READ_ACCESS (0x0001) +#define FILE_WRITE_ACCESS (0x0002) +#endif + +#ifndef CTL_CODE +#define CTL_CODE(DeviceType, Function, Method, Access) ( \ + ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method)) +#define KPH_CTL_CODE(x) CTL_CODE(KPH_DEVICE_TYPE, 0x800 + x, METHOD_BUFFERED, FILE_ANY_ACCESS) +#endif + +#define KPH_READ KPH_CTL_CODE(0) +#define KPH_WRITE KPH_CTL_CODE(1) +#define KPH_GETFILEOBJECTNAME KPH_CTL_CODE(2) +#define KPH_OPENPROCESS KPH_CTL_CODE(3) +#define KPH_OPENTHREAD KPH_CTL_CODE(4) +#define KPH_OPENPROCESSTOKEN KPH_CTL_CODE(5) +#define KPH_GETPROCESSPROTECTED KPH_CTL_CODE(6) +#define KPH_SETPROCESSPROTECTED KPH_CTL_CODE(7) +#define KPH_TERMINATEPROCESS KPH_CTL_CODE(8) +#define KPH_SUSPENDPROCESS KPH_CTL_CODE(9) +#define KPH_RESUMEPROCESS KPH_CTL_CODE(10) +#define KPH_READVIRTUALMEMORY KPH_CTL_CODE(11) +#define KPH_WRITEVIRTUALMEMORY KPH_CTL_CODE(12) +#define KPH_SETPROCESSTOKEN KPH_CTL_CODE(13) +#define KPH_GETTHREADSTARTADDRESS KPH_CTL_CODE(14) +#define KPH_SETHANDLEATTRIBUTES KPH_CTL_CODE(15) +#define KPH_GETHANDLEOBJECTNAME KPH_CTL_CODE(16) +#define KPH_OPENPROCESSJOB KPH_CTL_CODE(17) +#define KPH_GETCONTEXTTHREAD KPH_CTL_CODE(18) +#define KPH_SETCONTEXTTHREAD KPH_CTL_CODE(19) +#define KPH_GETTHREADWIN32THREAD KPH_CTL_CODE(20) +#define KPH_DUPLICATEOBJECT KPH_CTL_CODE(21) +#define KPH_ZWQUERYOBJECT KPH_CTL_CODE(22) +#define KPH_GETPROCESSID KPH_CTL_CODE(23) +#define KPH_GETTHREADID KPH_CTL_CODE(24) +#define KPH_TERMINATETHREAD KPH_CTL_CODE(25) +#define KPH_GETFEATURES KPH_CTL_CODE(26) +#define KPH_SETHANDLEGRANTEDACCESS KPH_CTL_CODE(27) +#define KPH_ASSIGNIMPERSONATIONTOKEN KPH_CTL_CODE(28) +#define KPH_PROTECTADD KPH_CTL_CODE(29) +#define KPH_PROTECTREMOVE KPH_CTL_CODE(30) +#define KPH_PROTECTQUERY KPH_CTL_CODE(31) +#define KPH_UNSAFEREADVIRTUALMEMORY KPH_CTL_CODE(32) +#define KPH_SETEXECUTEOPTIONS KPH_CTL_CODE(33) +#define KPH_QUERYPROCESSHANDLES KPH_CTL_CODE(34) +#define KPH_OPENTHREADPROCESS KPH_CTL_CODE(35) + +#ifndef MEM_EXECUTE_OPTION_DISABLE +#define MEM_EXECUTE_OPTION_DISABLE 0x1 +#define MEM_EXECUTE_OPTION_ENABLE 0x2 +#define MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION 0x4 +#define MEM_EXECUTE_OPTION_PERMANENT 0x8 +#endif + +typedef struct _PROCESS_HANDLE +{ + HANDLE Handle; + PVOID Object; + ACCESS_MASK GrantedAccess; + ULONG HandleAttributes; +} PROCESS_HANDLE, *PPROCESS_HANDLE; + +typedef struct _PROCESS_HANDLE_INFORMATION +{ + ULONG HandleCount; + PROCESS_HANDLE Handles[1]; +} PROCESS_HANDLE_INFORMATION, *PPROCESS_HANDLE_INFORMATION; + +NTSTATUS PHAPI KphInit(); + +NPHAPI NTSTATUS PHAPI KphConnect( + __out PHANDLE KphHandle + ); + +NPHAPI NTSTATUS PHAPI KphDisconnect( + __in HANDLE KphHandle + ); + +NPHAPI NTSTATUS PHAPI KphGetFeatures( + __in HANDLE KphHandle, + __out PULONG Features + ); + +NPHAPI NTSTATUS PHAPI KphRead( + __in HANDLE KphHandle, + __in PVOID Address, + __out_bcount(BufferLength) PVOID Buffer, + __in ULONG BufferLength + ); + +NPHAPI NTSTATUS PHAPI KphWrite( + __in HANDLE KphHandle, + __in PVOID Address, + __in_bcount(Length) PVOID Buffer, + __in ULONG Length + ); + +NPHAPI NTSTATUS PHAPI KphOpenProcess( + __in HANDLE KphHandle, + __out PHANDLE ProcessHandle, + __in HANDLE ProcessId, + __in ACCESS_MASK DesiredAccess + ); + +NPHAPI NTSTATUS PHAPI KphOpenThread( + __in HANDLE KphHandle, + __out PHANDLE ThreadHandle, + __in HANDLE ThreadId, + __in ACCESS_MASK DesiredAccess + ); + +NPHAPI NTSTATUS PHAPI KphOpenProcessToken( + __in HANDLE KphHandle, + __out PHANDLE TokenHandle, + __in HANDLE ProcessHandle, + __in ACCESS_MASK DesiredAccess + ); + +NPHAPI NTSTATUS PHAPI KphGetProcessProtected( + __in HANDLE KphHandle, + __in ULONG_PTR ProcessId, + __out PBOOLEAN IsProtected + ); + +NPHAPI NTSTATUS PHAPI KphSetProcessProtected( + __in HANDLE KphHandle, + __in ULONG_PTR ProcessId, + __in BOOLEAN IsProtected + ); + +NPHAPI NTSTATUS PHAPI KphTerminateProcess( + __in HANDLE KphHandle, + __in HANDLE ProcessHandle, + __in NTSTATUS ExitStatus + ); + +NPHAPI NTSTATUS PHAPI KphSuspendProcess( + __in HANDLE KphHandle, + __in HANDLE ProcessHandle + ); + +NPHAPI NTSTATUS PHAPI KphResumeProcess( + __in HANDLE KphHandle, + __in HANDLE ProcessHandle + ); + +NPHAPI NTSTATUS PHAPI KphReadVirtualMemory( + __in HANDLE KphHandle, + __in HANDLE ProcessHandle, + __in PVOID BaseAddress, + __out_bcount(BufferLength) PVOID Buffer, + __in ULONG BufferLength, + __out_opt PULONG ReturnLength + ); + +NPHAPI NTSTATUS PHAPI KphWriteVirtualMemory( + __in HANDLE KphHandle, + __in HANDLE ProcessHandle, + __in PVOID BaseAddress, + __in_bcount(BufferLength) PVOID Buffer, + __in ULONG BufferLength, + __out_opt PULONG ReturnLength + ); + +NPHAPI NTSTATUS PHAPI KphOpenProcessJob( + __in HANDLE KphHandle, + __out PHANDLE JobHandle, + __in HANDLE ProcessHandle, + __in ACCESS_MASK DesiredAccess + ); + +NPHAPI NTSTATUS PHAPI KphGetContextThread( + __in HANDLE KphHandle, + __in HANDLE ThreadHandle, + __inout PCONTEXT ThreadContext + ); + +NPHAPI NTSTATUS PHAPI KphSetContextThread( + __in HANDLE KphHandle, + __in HANDLE ThreadHandle, + __in PCONTEXT ThreadContext + ); + +NPHAPI NTSTATUS PHAPI KphTerminateThread( + __in HANDLE KphHandle, + __in HANDLE ThreadHandle, + __in NTSTATUS ExitStatus + ); + +NPHAPI NTSTATUS PHAPI KphSetHandleGrantedAccess( + __in HANDLE KphHandle, + __in HANDLE Handle, + __in ACCESS_MASK GrantedAccess + ); + +NPHAPI NTSTATUS PHAPI KphProtectAdd( + __in HANDLE KphHandle, + __in HANDLE ProcessHandle, + __in BOOLEAN AllowKernelMode, + __in ACCESS_MASK ProcessAllowMask, + __in ACCESS_MASK ThreadAllowMask + ); + +NPHAPI NTSTATUS PHAPI KphProtectRemove( + __in HANDLE KphHandle, + __in HANDLE ProcessHandle + ); + +NPHAPI NTSTATUS PHAPI KphProtectQuery( + __in HANDLE KphHandle, + __in HANDLE ProcessHandle, + __out PBOOLEAN AllowKernelMode, + __out PACCESS_MASK ProcessAllowMask, + __out PACCESS_MASK ThreadAllowMask + ); + +NPHAPI NTSTATUS PHAPI KphUnsafeReadVirtualMemory( + __in HANDLE KphHandle, + __in HANDLE ProcessHandle, + __in PVOID BaseAddress, + __in_bcount(BufferLength) PVOID Buffer, + __in ULONG BufferLength, + __out_opt PULONG ReturnLength + ); + +NPHAPI NTSTATUS PHAPI KphSetExecuteOptions( + __in HANDLE KphHandle, + __in HANDLE ProcessHandle, + __in ULONG ExecuteOptions + ); + +NPHAPI NTSTATUS PHAPI KphQueryProcessHandles( + __in HANDLE KphHandle, + __in HANDLE ProcessHandle, + __out_bcount_opt(BufferLength) PVOID Buffer, + __in_opt ULONG BufferLength, + __out_opt PULONG ReturnLength + ); + +NPHAPI NTSTATUS PHAPI KphOpenThreadProcess( + __in HANDLE KphHandle, + __out PHANDLE ProcessHandle, + __in HANDLE ThreadHandle, + __in ACCESS_MASK DesiredAccess + ); + +#endif diff --git a/branches/ph-plugins/NProcessHacker/kphhook.c b/branches/ph-plugins/NProcessHacker/kphhook.c new file mode 100644 index 000000000..243bb5f3a --- /dev/null +++ b/branches/ph-plugins/NProcessHacker/kphhook.c @@ -0,0 +1,180 @@ +/* + * Process Hacker Library - + * KProcessHacker transparency hooking + * + * Copyright (C) 2009 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 "kphhook.h" + +#define STD_PREFIX NTSTATUS NTAPI +#define DECLARE_NT_HOOK(Name, Arguments) \ + static _##Name Name; \ + static PH_HOOK Name##Hook; \ + PH_DEFINE_NT_HOOK_CALL(NTSTATUS NTAPI Old##Name, Arguments, Name##Hook); \ + STD_PREFIX New##Name(Arguments) +#define DECLARE_NEW_FUNC(Name, Arguments) \ + STD_PREFIX New##Name(Arguments) +#define INITIALIZE_NT_HOOK(Name) \ + Name = PhGetProcAddress(L"ntdll.dll", #Name); \ + PhInitializeHook(&Name##Hook, Name, New##Name); \ + PhHook(&Name##Hook) +#define DEINITIALIZE_NT_HOOK(Name) \ + PhUnhook(&Name##Hook) + +BOOLEAN KphHookInitialized = FALSE; +HANDLE KphHandle = NULL; +DECLARE_NT_HOOK(NtGetContextThread, NTGETCONTEXTTHREAD_ARGS); +DECLARE_NT_HOOK(NtOpenProcess, NTOPENPROCESS_ARGS); +DECLARE_NT_HOOK(NtOpenProcessToken, NTOPENPROCESSTOKEN_ARGS); +DECLARE_NT_HOOK(NtOpenProcessTokenEx, NTOPENPROCESSTOKENEX_ARGS); +DECLARE_NT_HOOK(NtOpenThread, NTOPENTHREAD_ARGS); +DECLARE_NT_HOOK(NtReadVirtualMemory, NTREADVIRTUALMEMORY_ARGS); +DECLARE_NT_HOOK(NtSetContextThread, NTSETCONTEXTTHREAD_ARGS); +DECLARE_NT_HOOK(NtTerminateProcess, NTTERMINATEPROCESS_ARGS); +DECLARE_NT_HOOK(NtTerminateThread, NTTERMINATETHREAD_ARGS); +DECLARE_NT_HOOK(NtWriteVirtualMemory, NTWRITEVIRTUALMEMORY_ARGS); + +VOID PHAPI KphHookInit() +{ + if (KphHookInitialized) + return; + + if (!NT_SUCCESS(KphConnect(&KphHandle))) + return; + + INITIALIZE_NT_HOOK(NtGetContextThread); + INITIALIZE_NT_HOOK(NtOpenProcess); + INITIALIZE_NT_HOOK(NtOpenProcessToken); + INITIALIZE_NT_HOOK(NtOpenProcessTokenEx); + INITIALIZE_NT_HOOK(NtOpenThread); + INITIALIZE_NT_HOOK(NtReadVirtualMemory); + INITIALIZE_NT_HOOK(NtSetContextThread); + INITIALIZE_NT_HOOK(NtTerminateProcess); + INITIALIZE_NT_HOOK(NtTerminateThread); + INITIALIZE_NT_HOOK(NtWriteVirtualMemory); + + KphHookInitialized = TRUE; +} + +VOID PHAPI KphHookDeinit() +{ + if (!KphHookInitialized) + return; + + DEINITIALIZE_NT_HOOK(NtGetContextThread); + DEINITIALIZE_NT_HOOK(NtOpenProcess); + DEINITIALIZE_NT_HOOK(NtOpenProcessToken); + DEINITIALIZE_NT_HOOK(NtOpenProcessTokenEx); + DEINITIALIZE_NT_HOOK(NtOpenThread); + DEINITIALIZE_NT_HOOK(NtReadVirtualMemory); + DEINITIALIZE_NT_HOOK(NtSetContextThread); + DEINITIALIZE_NT_HOOK(NtTerminateProcess); + DEINITIALIZE_NT_HOOK(NtTerminateThread); + DEINITIALIZE_NT_HOOK(NtWriteVirtualMemory); + + KphDisconnect(KphHandle); + + KphHookInitialized = FALSE; +} + +DECLARE_NEW_FUNC(NtGetContextThread, NTGETCONTEXTTHREAD_ARGS) +{ + return KphGetContextThread(KphHandle, ThreadHandle, Context); +} + +DECLARE_NEW_FUNC(NtOpenProcess, NTOPENPROCESS_ARGS) +{ + /* Use KPH if we only have a PID, no name or TID. */ + if (!ObjectAttributes->ObjectName && ClientId->UniqueThread == 0) + return KphOpenProcess(KphHandle, ProcessHandle, ClientId->UniqueProcess, DesiredAccess); + + return OldNtOpenProcess(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId); +} + +DECLARE_NEW_FUNC(NtOpenProcessToken, NTOPENPROCESSTOKEN_ARGS) +{ + return NtOpenProcessTokenEx(ProcessHandle, DesiredAccess, 0, TokenHandle); +} + +DECLARE_NEW_FUNC(NtOpenProcessTokenEx, NTOPENPROCESSTOKENEX_ARGS) +{ + /* HandleAttributes is ignored. */ + return KphOpenProcessToken(KphHandle, TokenHandle, ProcessHandle, DesiredAccess); +} + +DECLARE_NEW_FUNC(NtOpenThread, NTOPENTHREAD_ARGS) +{ + /* Use KPH if we only have a CID, no name. */ + if (!ObjectAttributes->ObjectName) + return KphOpenThread(KphHandle, ThreadHandle, ClientId->UniqueThread, DesiredAccess); + + return OldNtOpenThread(ThreadHandle, DesiredAccess, ObjectAttributes, ClientId); +} + +DECLARE_NEW_FUNC(NtReadVirtualMemory, NTREADVIRTUALMEMORY_ARGS) +{ + return KphReadVirtualMemory(KphHandle, ProcessHandle, BaseAddress, Buffer, BufferLength, ReturnLength); +} + +DECLARE_NEW_FUNC(NtSetContextThread, NTSETCONTEXTTHREAD_ARGS) +{ + return KphSetContextThread(KphHandle, ThreadHandle, Context); +} + +DECLARE_NEW_FUNC(NtTerminateProcess, NTTERMINATEPROCESS_ARGS) +{ + NTSTATUS status; + + /* Call the original NtTerminateProcess if we are terminating self to + * avoid infinite recursion with KphTerminateProcess. + */ + if (ProcessHandle == NULL || ProcessHandle == GetCurrentProcess()) + return OldNtTerminateProcess(ProcessHandle, ExitStatus); + + status = KphTerminateProcess(KphHandle, ProcessHandle, ExitStatus); + + /* Fall back to using the original NtTerminateProcess if KPH couldn't + * do it. */ + if (status == STATUS_NOT_SUPPORTED) + status = OldNtTerminateProcess(ProcessHandle, ExitStatus); + + return status; +} + +DECLARE_NEW_FUNC(NtTerminateThread, NTTERMINATETHREAD_ARGS) +{ + NTSTATUS status; + + if (ThreadHandle == NULL || ThreadHandle == GetCurrentThread()) + return OldNtTerminateThread(ThreadHandle, ExitStatus); + + status = KphTerminateThread(KphHandle, ThreadHandle, ExitStatus); + + /* Fall back to using the original NtTerminateThread if KPH couldn't + * do it. */ + if (status == STATUS_NOT_SUPPORTED) + status = OldNtTerminateThread(ThreadHandle, ExitStatus); + + return status; +} + +DECLARE_NEW_FUNC(NtWriteVirtualMemory, NTWRITEVIRTUALMEMORY_ARGS) +{ + return KphWriteVirtualMemory(KphHandle, ProcessHandle, BaseAddress, Buffer, BufferLength, ReturnLength); +} diff --git a/branches/ph-plugins/NProcessHacker/kphhook.h b/branches/ph-plugins/NProcessHacker/kphhook.h new file mode 100644 index 000000000..ac602c4f3 --- /dev/null +++ b/branches/ph-plugins/NProcessHacker/kphhook.h @@ -0,0 +1,32 @@ +/* + * Process Hacker Library - + * KProcessHacker transparency hooking + * + * Copyright (C) 2009 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 . + */ + +#ifndef _KPHHOOK_H +#define _KPHHOOK_H + +#include "hook.h" +#include "kph.h" + +NPHAPI VOID PHAPI KphHookInit(); +NPHAPI VOID PHAPI KphHookDeinit(); + +#endif diff --git a/branches/ph-plugins/NProcessHacker/nativedefs.h b/branches/ph-plugins/NProcessHacker/nativedefs.h new file mode 100644 index 000000000..af754046d --- /dev/null +++ b/branches/ph-plugins/NProcessHacker/nativedefs.h @@ -0,0 +1,175 @@ +#ifndef _NATIVEDEFS_H +#define _NATIVEDEFS_H + +#include "nph.h" + +typedef enum _OBJECT_INFORMATION_CLASS +{ + ObjectBasicInformation, + ObjectNameInformation, + ObjectTypeInformation, + ObjectAllInformation, + ObjectDataInformation +} OBJECT_INFORMATION_CLASS, *POBJECT_INFORMATION_CLASS; + +typedef struct _UNICODE_STRING UNICODE_STRING, *PUNICODE_STRING; + +typedef struct _CLIENT_ID +{ + HANDLE UniqueProcess; + HANDLE UniqueThread; +} CLIENT_ID, *PCLIENT_ID; + +typedef struct _IO_STATUS_BLOCK +{ + union + { + NTSTATUS Status; + PVOID Pointer; + }; + ULONG_PTR Information; +} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; + +typedef struct _OBJECT_ATTRIBUTES +{ + ULONG Length; + PVOID RootDirectory; + PUNICODE_STRING ObjectName; + ULONG Attributes; + PVOID SecurityDescriptor; + PVOID SecurityQualityOfService; +} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; + +typedef struct _UNICODE_STRING +{ + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; +} UNICODE_STRING, *PUNICODE_STRING; + +typedef struct _OBJECT_NAME_INFORMATION +{ + UNICODE_STRING Name; +} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION; + +#define NTDEVICEIOCONTROLFILE_ARGS \ + HANDLE FileHandle, \ + HANDLE Event, \ + PVOID ApcRoutine, \ + PVOID ApcContext, \ + PIO_STATUS_BLOCK IoStatusBlock, \ + ULONG IoControlCode, \ + PVOID InputBuffer, \ + ULONG InputBufferLength, \ + PVOID OutputBuffer, \ + ULONG OutputBufferLength + +typedef NTSTATUS (NTAPI *_NtDeviceIoControlFile)( + NTDEVICEIOCONTROLFILE_ARGS + ); + +#define NTGETCONTEXTTHREAD_ARGS \ + HANDLE ThreadHandle, \ + PCONTEXT Context + +typedef NTSTATUS (NTAPI *_NtGetContextThread)( + NTGETCONTEXTTHREAD_ARGS + ); + +#define NTOPENPROCESS_ARGS \ + PHANDLE ProcessHandle, \ + ACCESS_MASK DesiredAccess, \ + POBJECT_ATTRIBUTES ObjectAttributes, \ + PCLIENT_ID ClientId + +typedef NTSTATUS (NTAPI *_NtOpenProcess)( + NTOPENPROCESS_ARGS + ); + +#define NTOPENPROCESSTOKEN_ARGS \ + HANDLE ProcessHandle, \ + ACCESS_MASK DesiredAccess, \ + PHANDLE TokenHandle + +typedef NTSTATUS (NTAPI *_NtOpenProcessToken)( + NTOPENPROCESSTOKEN_ARGS + ); + +#define NTOPENPROCESSTOKENEX_ARGS \ + HANDLE ProcessHandle, \ + ACCESS_MASK DesiredAccess, \ + ULONG HandleAttributes, \ + PHANDLE TokenHandle + +typedef NTSTATUS (NTAPI *_NtOpenProcessTokenEx)( + NTOPENPROCESSTOKENEX_ARGS + ); + +#define NTOPENTHREAD_ARGS \ + PHANDLE ThreadHandle, \ + ACCESS_MASK DesiredAccess, \ + POBJECT_ATTRIBUTES ObjectAttributes, \ + PCLIENT_ID ClientId + +typedef NTSTATUS (NTAPI *_NtOpenThread)( + NTOPENTHREAD_ARGS + ); + +#define NTQUERYOBJECT_ARGS \ + HANDLE Handle, \ + OBJECT_INFORMATION_CLASS ObjectInformationClass, \ + PVOID ObjectInformation, \ + ULONG Length, \ + PULONG ReturnLength + +typedef NTSTATUS (NTAPI *_NtQueryObject)( + NTQUERYOBJECT_ARGS + ); + +#define NTREADVIRTUALMEMORY_ARGS \ + HANDLE ProcessHandle, \ + PVOID BaseAddress, \ + PVOID Buffer, \ + ULONG BufferLength, \ + PULONG ReturnLength + +typedef NTSTATUS (NTAPI *_NtReadVirtualMemory)( + NTREADVIRTUALMEMORY_ARGS + ); + +#define NTSETCONTEXTTHREAD_ARGS \ + HANDLE ThreadHandle, \ + PCONTEXT Context + +typedef NTSTATUS (NTAPI *_NtSetContextThread)( + NTSETCONTEXTTHREAD_ARGS + ); + +#define NTTERMINATEPROCESS_ARGS \ + HANDLE ProcessHandle, \ + NTSTATUS ExitStatus + +typedef NTSTATUS (NTAPI *_NtTerminateProcess)( + NTTERMINATEPROCESS_ARGS + ); + +#define NTTERMINATETHREAD_ARGS \ + HANDLE ThreadHandle, \ + NTSTATUS ExitStatus + +typedef NTSTATUS (NTAPI *_NtTerminateThread)( + NTTERMINATETHREAD_ARGS + ); + +#define NTWRITEVIRTUALMEMORY_ARGS \ + HANDLE ProcessHandle, \ + PVOID BaseAddress, \ + PVOID Buffer, \ + ULONG BufferLength, \ + PULONG ReturnLength + +typedef NTSTATUS (NTAPI *_NtWriteVirtualMemory)( + NTWRITEVIRTUALMEMORY_ARGS + ); + +#endif \ No newline at end of file diff --git a/branches/ph-plugins/NProcessHacker/nph.c b/branches/ph-plugins/NProcessHacker/nph.c new file mode 100644 index 000000000..42c4eeab7 --- /dev/null +++ b/branches/ph-plugins/NProcessHacker/nph.c @@ -0,0 +1,85 @@ +/* + * Process Hacker Library - + * common code + * + * Copyright (C) 2009 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 "nph.h" +#include "kph.h" +#include "obj.h" +#include "verify.h" + +PVOID PHAPI PhAlloc(SIZE_T Size) +{ + PVOID memory; + + if (!(memory = malloc(Size))) + RaiseException(EXCEPTION_NO_MEMORY, 0, 0, NULL); + + return memory; +} + +PVOID PHAPI PhRealloc(PVOID Memory, SIZE_T Size) +{ + PVOID memory; + + if (!(memory = realloc(Memory, Size))) + RaiseException(EXCEPTION_NO_MEMORY, 0, 0, NULL); + + return memory; +} + +VOID PHAPI PhFree(PVOID Memory) +{ + free(Memory); +} + +PVOID PHAPI PhGetProcAddress(PWSTR LibraryName, PSTR ProcName) +{ + return GetProcAddress(GetModuleHandle(LibraryName), ProcName); +} + +VOID PHAPI PhVoid() +{ + return; +} + +BOOL WINAPI DllMain( + HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved + ) +{ + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + if (!NT_SUCCESS(PhVerifyInit())) + return FALSE; + if (!NT_SUCCESS(PhObjInit())) + return FALSE; + if (!NT_SUCCESS(KphInit())) + return FALSE; + + break; + default: + break; + } + + return TRUE; +} diff --git a/branches/ph-plugins/NProcessHacker/nph.h b/branches/ph-plugins/NProcessHacker/nph.h new file mode 100644 index 000000000..887b94f9f --- /dev/null +++ b/branches/ph-plugins/NProcessHacker/nph.h @@ -0,0 +1,70 @@ +/* + * Process Hacker Library - + * main header file + * + * Copyright (C) 2009 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 . + */ + +#ifndef _NPH_H +#define _NPH_H + +/* If the user has already included windows.h, don't include ntstatus.h + * to avoid duplicate macro definitions. */ +#ifndef _WINDOWS_ +#include +#endif + +#define WIN32_LEAN_AND_MEAN +#define WIN32_NO_STATUS /* Need ntstatus.h instead */ +#include +#include + +#ifndef LOGICAL +#define LOGICAL ULONG +#define PLOGICAL PULONG +#endif + +#ifndef STATUS_SUCCESS +#define STATUS_SUCCESS (0) +#endif + +#ifndef NTSTATUS +#define NTSTATUS LONG +#endif + +#ifndef NT_SUCCESS +#define NT_SUCCESS(x) ((x) >= STATUS_SUCCESS) +#endif + +#ifdef NPH_EXPORTS +#define NPHAPI __declspec(dllexport) +#else +#define NPHAPI __declspec(dllimport) +#endif + +#define PHAPI __stdcall + +#define EXCEPTION_NO_MEMORY STATUS_NO_MEMORY + +NPHAPI PVOID PHAPI PhAlloc(SIZE_T Size); +NPHAPI PVOID PHAPI PhRealloc(PVOID Memory, SIZE_T Size); +NPHAPI VOID PHAPI PhFree(PVOID Memory); +PVOID PHAPI PhGetProcAddress(PWSTR LibraryName, PSTR ProcName); +NPHAPI VOID PHAPI PhVoid(); + +#endif diff --git a/branches/ph-plugins/NProcessHacker/obj.c b/branches/ph-plugins/NProcessHacker/obj.c new file mode 100644 index 000000000..2dfa285d6 --- /dev/null +++ b/branches/ph-plugins/NProcessHacker/obj.c @@ -0,0 +1,157 @@ +/* + * Process Hacker Library + * + * Copyright (C) 2009 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 "obj.h" + +ULONG PHAPI PhpQueryFileObjectThreadStart( + PVOID Parameter + ); + +_NtQueryObject NtQueryObject = NULL; + +HANDLE QueryFileObjectThreadHandle = NULL; +PVOID QueryFileObjectFiber = NULL; +CRITICAL_SECTION QueryFileObjectCs; +HANDLE QueryFileObjectStartEvent = NULL; +HANDLE QueryFileObjectCompletedEvent = NULL; +HANDLE QueryFileObjectFileHandle; +PH_QUERY_FILE_OBJECT_BUFFER QueryFileObjectBuffer; + +NTSTATUS PHAPI PhObjInit() +{ + if (!(NtQueryObject = (_NtQueryObject) + PhGetProcAddress(L"ntdll.dll", "NtQueryObject"))) + return STATUS_PROCEDURE_NOT_FOUND; + + InitializeCriticalSection(&QueryFileObjectCs); + + return STATUS_SUCCESS; +} + +NTSTATUS PHAPI PhQueryNameFileObject( + HANDLE FileHandle, + POBJECT_NAME_INFORMATION FileObjectNameInformation, + ULONG FileObjectNameInformationLength, + PULONG ReturnLength + ) +{ + ULONG waitResult; + + EnterCriticalSection(&QueryFileObjectCs); + + /* Create a query thread if we don't have one. */ + if (!QueryFileObjectThreadHandle) + { + QueryFileObjectThreadHandle = CreateThread( + NULL, 0, (LPTHREAD_START_ROUTINE)PhpQueryFileObjectThreadStart, NULL, 0, NULL); + + if (!QueryFileObjectThreadHandle) + { + LeaveCriticalSection(&QueryFileObjectCs); + return STATUS_UNSUCCESSFUL; + } + } + + /* Create the events if they don't exist. */ + if (!QueryFileObjectStartEvent) + if (!(QueryFileObjectStartEvent = CreateEvent(NULL, FALSE, FALSE, NULL))) + return STATUS_UNSUCCESSFUL; + if (!QueryFileObjectCompletedEvent) + if (!(QueryFileObjectCompletedEvent = CreateEvent(NULL, FALSE, FALSE, NULL))) + return STATUS_UNSUCCESSFUL; + + /* Initialize the work context. */ + QueryFileObjectFileHandle = FileHandle; + QueryFileObjectBuffer.Length = FileObjectNameInformationLength; + QueryFileObjectBuffer.Name = FileObjectNameInformation; + QueryFileObjectBuffer.Initialized = TRUE; + /* Allow the worker thread to start. */ + SetEvent(QueryFileObjectStartEvent); + /* Wait for the work to complete, with a timeout of 1 second. */ + waitResult = WaitForSingleObject(QueryFileObjectCompletedEvent, 1000); + /* Set the buffer as uninitialized. */ + QueryFileObjectBuffer.Initialized = FALSE; + + /* Return normally if the work was completed. */ + if (waitResult == WAIT_OBJECT_0) + { + NTSTATUS status; + ULONG returnLength; + + /* Copy the status information before we leave the critical section. */ + status = QueryFileObjectBuffer.Status; + returnLength = QueryFileObjectBuffer.ReturnLength; + LeaveCriticalSection(&QueryFileObjectCs); + + if (ReturnLength) + *ReturnLength = returnLength; + + return status; + } + /* Kill the worker thread if it took too long. */ + /* else if (waitResult == WAIT_TIMEOUT) */ + else + { + /* Kill the thread. */ + if (TerminateThread(QueryFileObjectThreadHandle, 1)) + { + QueryFileObjectThreadHandle = NULL; + + /* Delete the fiber (and free the thread stack). */ + DeleteFiber(QueryFileObjectFiber); + QueryFileObjectFiber = NULL; + } + + LeaveCriticalSection(&QueryFileObjectCs); + return STATUS_UNSUCCESSFUL; + } +} + +ULONG PHAPI PhpQueryFileObjectThreadStart( + PVOID Parameter + ) +{ + QueryFileObjectFiber = ConvertThreadToFiber(Parameter); + + while (TRUE) + { + /* Wait for work. */ + if (WaitForSingleObject(QueryFileObjectStartEvent, INFINITE) != WAIT_OBJECT_0) + continue; + + /* Make sure we actually have work. */ + if (QueryFileObjectBuffer.Initialized) + { + QueryFileObjectBuffer.Status = NtQueryObject( + QueryFileObjectFileHandle, + ObjectNameInformation, + QueryFileObjectBuffer.Name, + QueryFileObjectBuffer.Length, + &QueryFileObjectBuffer.ReturnLength + ); + + /* Work done. */ + SetEvent(QueryFileObjectCompletedEvent); + } + } + + return 0; +} diff --git a/branches/ph-plugins/NProcessHacker/obj.h b/branches/ph-plugins/NProcessHacker/obj.h new file mode 100644 index 000000000..f98f35520 --- /dev/null +++ b/branches/ph-plugins/NProcessHacker/obj.h @@ -0,0 +1,46 @@ +/* + * Process Hacker Library + * + * Copyright (C) 2009 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 . + */ + +#ifndef _OBJ_H +#define _OBJ_H + +#include "nph.h" +#include "nativedefs.h" + +typedef struct _PH_QUERY_FILE_OBJECT_BUFFER +{ + LOGICAL Initialized; + NTSTATUS Status; + ULONG Length; + ULONG ReturnLength; + POBJECT_NAME_INFORMATION Name; +} PH_QUERY_FILE_OBJECT_BUFFER, *PPH_QUERY_FILE_OBJECT_BUFFER; + +NTSTATUS PHAPI PhObjInit(); + +NPHAPI NTSTATUS PHAPI PhQueryNameFileObject( + HANDLE FileHandle, + POBJECT_NAME_INFORMATION FileObjectNameInformation, + ULONG FileObjectNameInformationLength, + PULONG ReturnLength + ); + +#endif diff --git a/branches/ph-plugins/NProcessHacker/process.c b/branches/ph-plugins/NProcessHacker/process.c new file mode 100644 index 000000000..52c0b35d9 --- /dev/null +++ b/branches/ph-plugins/NProcessHacker/process.c @@ -0,0 +1,117 @@ +/* + * Process Hacker Library + * + * Copyright (C) 2009 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 "process.h" + +NTSTATUS PHAPI PhQueryProcessWs( + HANDLE ProcessHandle, + WS_INFORMATION_CLASS WsInformationClass, + PVOID WsInformation, + ULONG WsInformationLength, + PULONG ReturnLength + ) +{ + switch (WsInformationClass) + { + case WsCount: + case WsPrivateCount: + case WsSharedCount: + case WsShareableCount: + if (WsInformationLength < 4) + return STATUS_BUFFER_TOO_SMALL; + goto WsCounters; + case WsAllCounts: + if (WsInformationLength < sizeof(WS_ALL_COUNTS)) + return STATUS_BUFFER_TOO_SMALL; +WsCounters: + { + PROCESS_MEMORY_COUNTERS procMem; + ULONG count = 0; + ULONG privateCount = 0; + ULONG sharedCount = 0; + ULONG shareableCount = 0; + PPSAPI_WORKING_SET_INFORMATION wsInfo; + SIZE_T wsInfoLength; + ULONG i; + + if (!GetProcessMemoryInfo(ProcessHandle, &procMem, sizeof(procMem))) + return STATUS_UNSUCCESSFUL; + + /* Assume the page size is 4kB */ + wsInfoLength = sizeof(PSAPI_WORKING_SET_INFORMATION) + + sizeof(PSAPI_WORKING_SET_BLOCK) * (procMem.WorkingSetSize / 4096); + wsInfo = (PPSAPI_WORKING_SET_INFORMATION)PhAlloc(wsInfoLength); + + if (!QueryWorkingSet(ProcessHandle, wsInfo, wsInfoLength)) + { + PhFree(wsInfo); + return STATUS_UNSUCCESSFUL; + } + + for (i = 0; i < wsInfo->NumberOfEntries; i++) + { + PSAPI_WORKING_SET_BLOCK block = wsInfo->WorkingSetInfo[i]; + + count++; + + if (block.ShareCount > 1) + sharedCount++; + if (block.ShareCount == 0) + privateCount++; + if (block.Shared) + shareableCount++; + } + + PhFree(wsInfo); + + switch (WsInformationClass) + { + case WsCount: + *(PULONG)WsInformation = count; + break; + case WsPrivateCount: + *(PULONG)WsInformation = privateCount; + break; + case WsSharedCount: + *(PULONG)WsInformation = sharedCount; + break; + case WsShareableCount: + *(PULONG)WsInformation = shareableCount; + break; + case WsAllCounts: + { + PWS_ALL_COUNTS allCounts = (PWS_ALL_COUNTS)WsInformation; + + allCounts->Count = count; + allCounts->PrivateCount = privateCount; + allCounts->SharedCount = sharedCount; + allCounts->ShareableCount = shareableCount; + break; + } + } + + return STATUS_SUCCESS; + } + break; + default: + return STATUS_INVALID_PARAMETER; + } +} diff --git a/branches/ph-plugins/NProcessHacker/process.h b/branches/ph-plugins/NProcessHacker/process.h new file mode 100644 index 000000000..6d795ebc0 --- /dev/null +++ b/branches/ph-plugins/NProcessHacker/process.h @@ -0,0 +1,53 @@ +/* + * Process Hacker Library + * + * Copyright (C) 2009 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 . + */ + +#ifndef _PROCESS_H +#define _PROCESS_H + +#include "nph.h" +#include + +typedef enum _WS_INFORMATION_CLASS +{ + WsCount = 0, + WsPrivateCount, + WsSharedCount, + WsShareableCount, + WsAllCounts +} WS_INFORMATION_CLASS, *PWS_INFORMATION_CLASS; + +typedef struct _WS_ALL_COUNTS +{ + ULONG Count; + ULONG PrivateCount; + ULONG SharedCount; + ULONG ShareableCount; +} WS_ALL_COUNTS, *PWS_ALL_COUNTS; + +NPHAPI NTSTATUS PHAPI PhQueryProcessWs( + HANDLE ProcessHandle, + WS_INFORMATION_CLASS WsInformationClass, + PVOID WsInformation, + ULONG WsInformationLength, + PULONG ReturnLength + ); + +#endif \ No newline at end of file diff --git a/branches/ph-plugins/NProcessHacker/resource.rc b/branches/ph-plugins/NProcessHacker/resource.rc new file mode 100644 index 000000000..337d53ea5 --- /dev/null +++ b/branches/ph-plugins/NProcessHacker/resource.rc @@ -0,0 +1,53 @@ +#include + +#define VER_COMMA 1,5,0,0 +#define VER_STR "1.5\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 "Process Hacker Library\0" +#define VER_LEGALCOPYRIGHT_STR "Copyright (c) 2009 wj32. Licensed under the GNU GPL, v3.\0" +#define VER_ORIGINALFILENAME_STR "NProcessHacker.dll\0" +#define VER_PRODUCTNAME_STR "Process Hacker\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_DLL +FILESUBTYPE VFT2_UNKNOWN +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/branches/ph-plugins/NProcessHacker/secedit.c b/branches/ph-plugins/NProcessHacker/secedit.c new file mode 100644 index 000000000..944056ccf --- /dev/null +++ b/branches/ph-plugins/NProcessHacker/secedit.c @@ -0,0 +1,24 @@ +/* + * Process Hacker Library + * + * Copyright (C) 2009 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 "secedit.h" + + diff --git a/branches/ph-plugins/NProcessHacker/secedit.h b/branches/ph-plugins/NProcessHacker/secedit.h new file mode 100644 index 000000000..df33f1cde --- /dev/null +++ b/branches/ph-plugins/NProcessHacker/secedit.h @@ -0,0 +1,48 @@ +/* + * Process Hacker Library + * + * Copyright (C) 2009 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 . + */ + +#ifndef _SECEDIT_H +#define _SECEDIT_H + +#include "nph.h" + +typedef HRESULT (__stdcall *_QueryInterface)( + PVOID This, + REFIID Id, + PVOID *Object + ); + +typedef ULONG (__stdcall *_AddRef)( + PVOID This + ); + +typedef ULONG (__stdcall *_Release)( + PVOID This + ); + +typedef struct _ISECURITY_INFORMATION +{ + _QueryInterface QueryInterface; + _AddRef AddRef; + _Release Release; +} ISECURITY_INFORMATION, *PISECURITY_INFORMATION; + +#endif diff --git a/branches/ph-plugins/NProcessHacker/verify.c b/branches/ph-plugins/NProcessHacker/verify.c new file mode 100644 index 000000000..6718a09d1 --- /dev/null +++ b/branches/ph-plugins/NProcessHacker/verify.c @@ -0,0 +1,200 @@ +/* + * Process Hacker Library + * + * Copyright (C) 2009 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 "verify.h" + +VERIFY_RESULT PHAPI PhpStatusToVerifyResult(LONG Status); +VERIFY_RESULT PHAPI PhpVerifyFileBasic(PWSTR FileName); +VERIFY_RESULT PHAPI PhpVerifyFileCat(PWSTR FileName); + +_CryptCATAdminCalcHashFromFileHandle CryptCATAdminCalcHashFromFileHandle; +_CryptCATAdminAcquireContext CryptCATAdminAcquireContext; +_CryptCATAdminEnumCatalogFromHash CryptCATAdminEnumCatalogFromHash; +_CryptCATCatalogInfoFromContext CryptCATCatalogInfoFromContext; +_CryptCATAdminReleaseCatalogContext CryptCATAdminReleaseCatalogContext; +_CryptCATAdminReleaseContext CryptCATAdminReleaseContext; + +NTSTATUS PHAPI PhVerifyInit() +{ + LoadLibrary(L"wintrust.dll"); + + CryptCATAdminCalcHashFromFileHandle = + PhGetProcAddress(L"wintrust.dll", "CryptCATAdminCalcHashFromFileHandle"); + CryptCATAdminAcquireContext = + PhGetProcAddress(L"wintrust.dll", "CryptCATAdminAcquireContext"); + CryptCATAdminEnumCatalogFromHash = + PhGetProcAddress(L"wintrust.dll", "CryptCATAdminEnumCatalogFromHash"); + CryptCATCatalogInfoFromContext = + PhGetProcAddress(L"wintrust.dll", "CryptCATCatalogInfoFromContext"); + CryptCATAdminReleaseCatalogContext = + PhGetProcAddress(L"wintrust.dll", "CryptCATAdminReleaseCatalogContext"); + CryptCATAdminReleaseContext = + PhGetProcAddress(L"wintrust.dll", "CryptCATAdminReleaseContext"); + + return STATUS_SUCCESS; +} + +VERIFY_RESULT PHAPI PhpStatusToVerifyResult(LONG Status) +{ + switch (Status) + { + case 0: + return VrTrusted; + case TRUST_E_NOSIGNATURE: + return VrNoSignature; + case CERT_E_EXPIRED: + return VrExpired; + case CERT_E_REVOKED: + return VrRevoked; + case TRUST_E_EXPLICIT_DISTRUST: + return VrDistrust; + case CRYPT_E_SECURITY_SETTINGS: + return VrSecuritySettings; + default: + return VrSecuritySettings; + } +} + +VERIFY_RESULT PHAPI PhpVerifyFileBasic(PWSTR FileName) +{ + WINTRUST_DATA trustData = { 0 }; + WINTRUST_FILE_INFO fileInfo = { 0 }; + GUID actionGenericVerifyV2 = WINTRUST_ACTION_GENERIC_VERIFY_V2; + + fileInfo.cbStruct = sizeof(fileInfo); + fileInfo.pcwszFilePath = FileName; + + trustData.cbStruct = sizeof(trustData); + trustData.dwUIChoice = WTD_UI_NONE; + trustData.dwProvFlags = WTD_SAFER_FLAG; + trustData.dwUnionChoice = WTD_CHOICE_FILE; + trustData.pFile = &fileInfo; + + return PhpStatusToVerifyResult(WinVerifyTrust(NULL, &actionGenericVerifyV2, &trustData)); +} + +VERIFY_RESULT PHAPI PhpVerifyFileCat(PWSTR FileName) +{ + LONG status = TRUST_E_NOSIGNATURE; + WINTRUST_DATA trustData = { 0 }; + WINTRUST_CATALOG_INFO catalogInfo = { 0 }; + GUID driverActionVerify = DRIVER_ACTION_VERIFY; + HANDLE fileHandle; + PBYTE fileHash = NULL; + ULONG fileHashLength; + PWSTR fileHashTag = NULL; + HANDLE catAdminHandle = NULL; + HANDLE catInfoHandle = NULL; + ULONG i; + + fileHandle = CreateFile( + FileName, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL + ); + + if (fileHandle == INVALID_HANDLE_VALUE) + return VrNoSignature; + + fileHashLength = 256; + fileHash = (PBYTE)PhAlloc(fileHashLength); + + if (!CryptCATAdminCalcHashFromFileHandle(fileHandle, &fileHashLength, fileHash, 0)) + { + fileHash = (PBYTE)PhRealloc(fileHash, fileHashLength); + + if (!CryptCATAdminCalcHashFromFileHandle(fileHandle, &fileHashLength, fileHash, 0)) + { + CloseHandle(fileHandle); + PhFree(fileHash); + return VrNoSignature; + } + } + + if (!CryptCATAdminAcquireContext(&catAdminHandle, &driverActionVerify, 0)) + { + CloseHandle(fileHandle); + PhFree(fileHash); + return VrNoSignature; + } + + fileHashTag = (PWSTR)PhAlloc((fileHashLength * 2 + 1) * sizeof(WCHAR)); + + for (i = 0; i < fileHashLength; i++) + wsprintfW(&fileHashTag[i * 2], L"%02X", fileHash[i]); + + catInfoHandle = CryptCATAdminEnumCatalogFromHash( + catAdminHandle, + fileHash, + fileHashLength, + 0, + NULL + ); + + PhFree(fileHash); + + if (catInfoHandle) + { + CATALOG_INFO ci = { 0 }; + + if (CryptCATCatalogInfoFromContext(catInfoHandle, &ci, 0)) + { + catalogInfo.cbStruct = sizeof(catalogInfo); + catalogInfo.pcwszCatalogFilePath = ci.wszCatalogFile; + catalogInfo.pcwszMemberFilePath = FileName; + catalogInfo.pcwszMemberTag = fileHashTag; + + trustData.cbStruct = sizeof(trustData); + trustData.dwUIChoice = WTD_UI_NONE; + trustData.fdwRevocationChecks = WTD_STATEACTION_VERIFY; + trustData.dwUnionChoice = WTD_CHOICE_CATALOG; + trustData.pCatalog = &catalogInfo; + + status = WinVerifyTrust(NULL, &driverActionVerify, &trustData); + } + + CryptCATAdminReleaseCatalogContext(catAdminHandle, catInfoHandle, 0); + } + + PhFree(fileHashTag); + CryptCATAdminReleaseContext(catAdminHandle, 0); + CloseHandle(fileHandle); + + return PhpStatusToVerifyResult(status); +} + +VERIFY_RESULT PHAPI PhVerifyFile(PWSTR FileName) +{ + VERIFY_RESULT result = VrNoSignature; + + result = PhpVerifyFileBasic(FileName); + + if (result == VrNoSignature) + { + result = PhpVerifyFileCat(FileName); + } + + return result; +} diff --git a/branches/ph-plugins/NProcessHacker/verify.h b/branches/ph-plugins/NProcessHacker/verify.h new file mode 100644 index 000000000..4c950a1fb --- /dev/null +++ b/branches/ph-plugins/NProcessHacker/verify.h @@ -0,0 +1,88 @@ +/* + * Process Hacker Library + * + * Copyright (C) 2009 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 . + */ + +#ifndef _VERIFY_H +#define _VERIFY_H + +#include "nph.h" +#include +#include + +typedef enum _VERIFY_RESULT +{ + VrUnknown = 0, + VrNoSignature, + VrTrusted, + VrTrustedInstaller, + VrExpired, + VrRevoked, + VrDistrust, + VrSecuritySettings +} VERIFY_RESULT, *PVERIFY_RESULT; + +typedef struct _CATALOG_INFO +{ + DWORD cbStruct; + WCHAR wszCatalogFile[MAX_PATH]; +} CATALOG_INFO, *PCATALOG_INFO; + +typedef BOOL (WINAPI *_CryptCATAdminCalcHashFromFileHandle)( + HANDLE hFile, + DWORD *pcbHash, + BYTE *pbHash, + DWORD dwFlags + ); + +typedef BOOL (WINAPI *_CryptCATAdminAcquireContext)( + HANDLE *phCatAdmin, + GUID *pgSubsystem, + DWORD dwFlags + ); + +typedef HANDLE (WINAPI *_CryptCATAdminEnumCatalogFromHash)( + HANDLE hCatAdmin, + BYTE *pbHash, + DWORD cbHash, + DWORD dwFlags, + HANDLE *phPrevCatInfo + ); + +typedef BOOL (WINAPI *_CryptCATCatalogInfoFromContext)( + HANDLE hCatInfo, + CATALOG_INFO *psCatInfo, + DWORD dwFlags + ); + +typedef BOOL (WINAPI *_CryptCATAdminReleaseCatalogContext)( + HANDLE hCatAdmin, + HANDLE hCatInfo, + DWORD dwFlags + ); + +typedef BOOL (WINAPI *_CryptCATAdminReleaseContext)( + HANDLE hCatAdmin, + DWORD dwFlags + ); + +NTSTATUS PHAPI PhVerifyInit(); +NPHAPI VERIFY_RESULT PHAPI PhVerifyFile(PWSTR FileName); + +#endif \ No newline at end of file diff --git a/branches/ph-plugins/NProcessHacker/x64/Release/NProcessHacker.dll b/branches/ph-plugins/NProcessHacker/x64/Release/NProcessHacker.dll new file mode 100644 index 000000000..3e91b4c99 Binary files /dev/null and b/branches/ph-plugins/NProcessHacker/x64/Release/NProcessHacker.dll differ diff --git a/branches/ph-plugins/ProcessHacker.Common/BaseConverter.cs b/branches/ph-plugins/ProcessHacker.Common/BaseConverter.cs new file mode 100644 index 000000000..52bd7687d --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/BaseConverter.cs @@ -0,0 +1,176 @@ +/* + * Process Hacker - + * base converter + * + * Copyright (C) 2006-2008 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 . + */ + +using System; +using System.Text; + +namespace ProcessHacker.Common +{ + /// + /// Contains methods to parse numbers from string representations using different bases. + /// + public static class BaseConverter + { + private static int[] _reverseChars = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 52, + 53, 54, 55, 56, 57, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 60, 61, 62, 63, 64, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 65, 66, 67, 68, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + /// + /// Reverses a string. + /// + /// The string to be reversed + /// The reversed string. + public static string ReverseString(string str) + { + StringBuilder sb = new StringBuilder(); + + for (int i = str.Length - 1; i >= 0; i--) + { + sb.Append(str[i]); + } + + return sb.ToString(); + } + + /// + /// Converts a string to a number using the specified base. + /// + /// + /// This function does not parse prefixes; to do so, use + /// + /// The string to convert + /// The base to use + /// + public static decimal ToNumber(string number, int b) + { + if (b > 70) + return 0; + + if (number == "") + return 0; + + bool negative = number[0] == '-'; + int length = number.Length; + long result = 0; + + if (negative) + { + length -= 1; + } + + number = ReverseString(number).ToLower(); + + for (int i = 0; i < length; i++) + { + result += _reverseChars[number[i]] * ((long)Math.Pow(b, i)); + } + + if (negative) + return -result; + else + return result; + } + + /// + /// Converts a string to a number, parsing prefixes to determine the base. + /// + /// The string to convert. + /// + public static decimal ToNumberParse(string number) + { + return ToNumberParse(number, true); + } + + /// + /// Converts a string to a number, parsing prefixes to determine the base. + /// + /// The string to convert. + /// Enables or disables non-standard prefixes for + /// bases 2 (b), 3 (t), 4 (q), 12 (w) and 32 (r). + /// + public static decimal ToNumberParse(string number, bool allowNonStandardExts) + { + if (number == "") + return 0; + + bool negative = number[0] == '-'; + decimal result = 0; + + if (negative) + number = number.Substring(1); + + if (number.Length > 2 && (number.Substring(0, 2) == "0x")) // hexadecimal + { + result = ToNumber(number.Substring(2), 16); + } + else if (number.Length > 1) + { + if (number[0] == '0') // octal + { + result = ToNumber(number.Substring(1), 8); + } + else if (number[0] == 'b' && allowNonStandardExts) // binary + { + result = ToNumber(number.Substring(1), 2); + } + else if (number[0] == 't' && allowNonStandardExts) // ternary + { + result = ToNumber(number.Substring(1), 3); + } + else if (number[0] == 'q' && allowNonStandardExts) // quaternary + { + result = ToNumber(number.Substring(1), 4); + } + else if (number[0] == 'w' && allowNonStandardExts) // base 12 + { + result = ToNumber(number.Substring(1), 12); + } + else if (number[0] == 'r' && allowNonStandardExts) // base 32 + { + result = ToNumber(number.Substring(1), 32); + } + else // base 10 + { + result = ToNumber(number, 10); + } + } + else // base 10 + { + result = ToNumber(number, 10); + } + + if (negative) + return -result; + else + return result; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/ByteStreamReader.cs b/branches/ph-plugins/ProcessHacker.Common/ByteStreamReader.cs new file mode 100644 index 000000000..37026970a --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/ByteStreamReader.cs @@ -0,0 +1,118 @@ +/* + * Process Hacker - + * byte stream reader + * + * Copyright (C) 2008-2009 wj32 + * + * This file is part of PNG.Net. + * + * 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 . + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace ProcessHacker.Common +{ + public sealed class ByteStreamReader : Stream + { + private byte[] _data; + private long _position; + + public ByteStreamReader(byte[] data) + { + _data = data; + _position = 0; + } + + public override bool CanRead + { + get { return true; } + } + + public override bool CanSeek + { + get { return true; } + } + + public override bool CanWrite + { + get { return false; } + } + + public override void Flush() + { + // don't need to flush + } + + public override long Length + { + get { return _data.LongLength; } + } + + public override long Position + { + get { return _position; } + set { _position = value; } + } + + public override int Read(byte[] buffer, int offset, int count) + { + long length = (_position + count > _data.Length) ? _data.Length - _position - 1 : count; + + if (_position >= _data.Length) + return 0; + + for (long i = 0; i < length; i++, _position++) + buffer[offset + i] = _data[_position]; + + return (int)length; + } + + public override long Seek(long offset, SeekOrigin origin) + { + switch (origin) + { + case SeekOrigin.Begin: + _position = offset; + break; + + case SeekOrigin.Current: + _position += offset; + break; + + case SeekOrigin.End: + _position = _data.Length - 1 + offset; + break; + + default: + throw new ArgumentException(); + } + + return _position; + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/CircularBuffer.cs b/branches/ph-plugins/ProcessHacker.Common/CircularBuffer.cs new file mode 100644 index 000000000..546023a12 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/CircularBuffer.cs @@ -0,0 +1,369 @@ +/* + * Process Hacker - + * circular buffer + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; + +namespace ProcessHacker.Common +{ + /// + /// Provides methods for manipulating a circular buffer. A circular buffer + /// is a fixed-size array where old elements will be automatically deleted + /// as new elements are added. + /// + /// + /// This data structure is not thread-safe. You must provide your own + /// synchronization if more than one thread reads from or writes to the + /// buffer. + /// + /// + /// Ten-element circular buffer: + /// Data array: [4] [3] [2] [1] [0] [9] [8] [7] [6] [5] + /// ^ most recent data + /// ^ index + /// + public class CircularBuffer : IList + { + private int _size; + private int _count; + private int _index; + private T[] _data; + + /// + /// Creates a new circular buffer of the specified size. + /// + /// The size of the buffer. + public CircularBuffer(int size) + { + /* + * [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] [ ] + * ^ _index + */ + _size = size; + _count = 0; + _index = 0; + _data = new T[size]; + } + + /// + /// Gets or sets an element in the buffer. This is guaranteed to + /// never throw an exception. + /// + /// + /// A zero-based index into the buffer. Index 0 contains the + /// most recently added item, and higher positive indicies + /// access less recent items. Index -1 contains the least recently + /// added item, and lower negative indicies access more recent + /// items. + /// + public T this[int index] + { + get + { + /* + * For example, if _index = 6 and index = 5: + * + * [5] [4] [3] [2] [1] [0] [9] [8] [7] [6] + * ^ _index + * ^ (_index + index) mod _size = 11 mod 10 = 1 + */ + + // See the comment in Add for more details on modulus. + return _data[(((_index + index) % _size) + _size) % _size]; + } + set + { + // See the comment in Add for more details. + _data[(((_index + index) % _size) + _size) % _size] = value; + } + } + + /// + /// Gets the number of elements stored in the buffer. + /// + public int Count + { + get { return _count; } + } + + /// + /// Gets the maximum number of elements that can be stored in + /// the buffer. + /// + public int Size + { + get { return _size; } + } + + /// + /// Adds an element to the buffer. If the maximum buffer size + /// has been reached, the least recently added element will + /// be erased by the new element. + /// + /// The element to add. + public void Add(T value) + { + /* + * To add an item to the circular buffer the index is + * decremented and a modulus is performed on it to ensure + * it is not negative. + * + * [5] [4] [3] [2] [1] [0] [9] [8] [7] [6] + * ^ _index (6) + * When the new element x is added: + * [5] [4] [3] [2] [1] [x] [9] [8] [7] [6] + * ^ _index (5) + * + * Another example: + * [9] [8] [7] [6] [5] [4] [3] [2] [1] [0] + * ^ _index (0) + * When the new element x is added: + * [9] [8] [7] [6] [5] [4] [3] [2] [1] [x] + * ^ _index (9) + * = -1 mod 10 = 9 + */ + + /* The C# modulus operator produces a result which has the + * same sign as the dividend. For circular array access, + * we want the result to have the same sign as the divisor. + * We do this by using r = ((i % t) + t) % t where i is + * the index (possibly negative) and t is the size of the + * array. + */ + _data[_index = (((_index - 1) % _size) + _size) % _size] = value; + + if (_count < _size) + _count++; + } + + /// + /// Resizes the circular buffer. + /// + /// The new maximum buffer size. + public void Resize(int newSize) + { + // If we're not actually resizing the thing... + if (newSize == _size) + return; + + T[] newArray = new T[newSize]; + int tailSize = (_size - _index) % _size; + int headSize = _count - tailSize; + + /* + * The tail contains the most recent data. + * [3] [2] [1] [0] [ ] [8] [7] [6] [5] [4] + * [ ... head ... ] [ ..... tail ..... ] + * ^ _index (5) + * tailSize = _size - _index = 5 + * headSize = _count - tailSize = 9 - 5 = 4 + */ + + // If the new buffer is bigger than the current one. + if (newSize > _size) + { + /* + * Copy the tail, then the head. + * This means that the tail will now be at the front. + * [8] [7] [6] [5] [4] [3] [2] [1] [0] [ ] [ ] [ ] + * [ ..... tail ..... ][ ... head ... ] + * ^ _index (0) + */ + Array.Copy(_data, _index, newArray, 0, tailSize); + Array.Copy(_data, 0, newArray, tailSize, headSize); + _index = 0; + } + // If the new buffer is smaller than the current one. + else if (newSize < _size) + { + // If the new buffer is smaller than (or equal to) the tail size. + if (tailSize >= newSize) + { + /* + * Copy only a part of the tail because we don't have enough room. + * [8] [7] [6] + * [ . tail . ] + * ^ _index (0) + */ + Array.Copy(_data, _index, newArray, 0, newSize); + _index = 0; + } + // If the new buffer is bigger than the tail size. + else + { + /* + * Copy the tail in full, then copy a part of the head. + * [8] [7] [6] [5] [4] [3] [2] + * [ ..... tail ..... ][ head ] + * ^ _index (0) + */ + Array.Copy(_data, _index, newArray, 0, tailSize); + Array.Copy(_data, 0, newArray, tailSize, newSize - tailSize); + _index = 0; + } + + // The number of elements obviously can't be bigger than the + // buffer size. + if (_count > newSize) + _count = newSize; + } + + _data = newArray; + _size = newSize; + } + + /// + /// Converts the buffer to an array. + /// + /// + public T[] ToArray() + { + T[] newArray = new T[this.Count]; + + this.CopyTo(newArray, 0); + + return newArray; + } + + #region IList Members + + /// + /// Gets the index of the specified element in the array. + /// + /// The element to search for. + /// A positive index if the element was found. Otherwise, -1. + public int IndexOf(T item) + { + for (int i = 0; i < this.Count; i++) + if (this[i].Equals(item)) + return i; + + return -1; + } + + /// + /// This method is not supported. + /// + public void Insert(int index, T item) + { + throw new NotSupportedException(); + } + + /// + /// This method is not supported. + /// + public void RemoveAt(int index) + { + throw new NotSupportedException(); + } + + #endregion + + #region ICollection Members + + /// + /// Clears the buffer. + /// + public void Clear() + { + // Just set the number of elements to zero. + _count = 0; + } + + /// + /// Gets whether the buffer contains the specified element. + /// + /// The element to search for. + /// Whether the element is present. + public bool Contains(T item) + { + return this.IndexOf(item) != -1; + } + + /// + /// Copies the elements of the buffer to the specified array. + /// + /// The array to copy to. + /// The index of the destination array at which to begin copying. + public void CopyTo(T[] array, int arrayIndex) + { + /* + * We have to make sure we don't copy unused elements. + * [2] [1] [0] [ ] [ ] [ ] [6] [5] [4] [3] + * [ . head . ] [ ... tail ... ] + * ^ _index (6) + * tailSize = _size - _index = 10 - 6 = 4 + * headSize = _count - tailSize = 7 - 4 = 3 + */ + int tailSize = _size - _index; + int headSize = _count - tailSize; + + // Copy the tail, then the head. + Array.Copy(_data, _index, array, arrayIndex, tailSize); + Array.Copy(_data, 0, array, arrayIndex + tailSize, headSize); + } + + /// + /// Gets whether the buffer is read-only. + /// + public bool IsReadOnly + { + get { return false; } + } + + /// + /// This method is not supported. + /// + public bool Remove(T item) + { + throw new NotSupportedException(); + } + + #endregion + + #region IEnumerable Members + + /// + /// Gets an enumerator for the buffer. + /// + public IEnumerator GetEnumerator() + { + for (int i = 0; i < this.Count; i++) + yield return this[i]; + } + + #endregion + + #region IEnumerable Members + + /// + /// Gets an enumerator for the buffer. + /// + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + for (int i = 0; i < this.Count; i++) + yield return this[i]; + } + + #endregion + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Delegates.cs b/branches/ph-plugins/ProcessHacker.Common/Delegates.cs new file mode 100644 index 000000000..24862dd46 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Delegates.cs @@ -0,0 +1,19 @@ +namespace System +{ + public delegate void Action(); + //public delegate void Action(T a1); + public delegate void Action(T a1, U a2); + public delegate void Action(T a1, U a2, V a3); + public delegate void Action(T a1, U a2, V a3, W a4); + public delegate void Action(T a1, U a2, V a3, W a4, X a5); + public delegate void Action(T a1, U a2, V a3, W a4, X a5, Y a6); + public delegate void Action(T a1, U a2, V a3, W a4, X a5, Y a6, Z a7); + + public delegate T Func(); + public delegate U Func(T a1); + public delegate V Func(T a1, U a2); + public delegate W Func(T a1, U a2, V a3); + public delegate X Func(T a1, U a2, V a3, W a4); + public delegate Y Func(T a1, U a2, V a3, W a4, X a5); + public delegate Z Func(T a1, U a2, V a3, W a4, X a5, Y a6); +} diff --git a/branches/ph-plugins/ProcessHacker.Common/DeltaManager.cs b/branches/ph-plugins/ProcessHacker.Common/DeltaManager.cs new file mode 100644 index 000000000..526e9fbef --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/DeltaManager.cs @@ -0,0 +1,168 @@ +/* + * Process Hacker - + * delta manager + * + * Copyright (C) 2008 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 . + */ + +using System.Collections.Generic; + +namespace ProcessHacker.Common +{ + /// + /// Defines subtraction for a numeric type. + /// + /// The numeric type. + public interface ISubtractor + { + /// + /// Subtracts v2 from v1, i.e., v1 - v2. + /// + T Subtract(T v1, T v2); + } + + public static class Subtractor + { + private static Int64Subtractor _int64Subtractor = new Int64Subtractor(); + private static Int32Subtractor _int32Subtractor = new Int32Subtractor(); + private static DoubleSubtractor _doubleSubtractor = new DoubleSubtractor(); + private static FloatSubtractor _floatSubtractor = new FloatSubtractor(); + + public static Int64Subtractor Int64Subtractor + { + get { return _int64Subtractor; } + } + + public static Int32Subtractor Int32Subtractor + { + get { return _int32Subtractor; } + } + + public static DoubleSubtractor DoubleSubtractor + { + get { return _doubleSubtractor; } + } + + public static FloatSubtractor FloatSubtractor + { + get { return _floatSubtractor; } + } + } + + /// + /// Provides subtraction for 64-bit integers. + /// + public class Int64Subtractor : ISubtractor + { + public long Subtract(long v1, long v2) + { + return v1 - v2; + } + } + + /// + /// Provides subtraction for 32-bit integers. + /// + public class Int32Subtractor : ISubtractor + { + public int Subtract(int v1, int v2) + { + return v1 - v2; + } + } + + /// + /// Provides subtraction for double-precision floating-point values. + /// + public class DoubleSubtractor : ISubtractor + { + public double Subtract(double v1, double v2) + { + return v1 - v2; + } + } + + /// + /// Provides subtraction for single-precision floating-point values. + /// + public class FloatSubtractor : ISubtractor + { + public float Subtract(float v1, float v2) + { + return v1 - v2; + } + } + + /// + /// Provides methods for managing deltas of discrete sets of data. + /// + public sealed class DeltaManager + { + private Dictionary _values; + private Dictionary _deltas; + private ISubtractor _subtractor; + + /// + /// Creates a delta manager using the specified subtractor. + /// + /// A subtractor for the appropriate type. + public DeltaManager(ISubtractor subtractor) + { + _subtractor = subtractor; + _values = new Dictionary(); + _deltas = new Dictionary(); + } + + public DeltaManager(ISubtractor subtractor, IEqualityComparer comparer) + { + _subtractor = subtractor; + _values = new Dictionary(comparer); + _deltas = new Dictionary(comparer); + } + + public TValue this[TKey key] + { + get { return _deltas[key]; } + set { _deltas[key] = value; } + } + + public TValue GetDelta(TKey key) + { + return _deltas[key]; + } + + public void Add(TKey key, TValue initialValue) + { + _values.Add(key, initialValue); + _deltas.Add(key, initialValue); + } + + public void SetDelta(TKey key, TValue value) + { + _deltas[key] = value; + } + + public TValue Update(TKey key, TValue value) + { + _deltas[key] = _subtractor.Subtract(value, _values[key]); + _values[key] = value; + + return _deltas[key]; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/EnumComparer.cs b/branches/ph-plugins/ProcessHacker.Common/EnumComparer.cs new file mode 100644 index 000000000..ed0aa58a5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/EnumComparer.cs @@ -0,0 +1,124 @@ +/* + * http://www.codeproject.com/KB/cs/EnumComparer.aspx + * + * by Omer Mor + */ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Reflection.Emit; + +namespace ProcessHacker.Common +{ + public sealed class EnumComparer : IEqualityComparer + where TEnum : struct, IComparable, IConvertible, IFormattable + { + public static readonly EnumComparer Instance; + + private static readonly Func _equals; + private static readonly Func _getHashCode; + + static EnumComparer() + { + _getHashCode = generateGetHashCode(); + _equals = generateEquals(); + Instance = new EnumComparer(); + } + + private EnumComparer() + { + AssertTypeIsEnum(); + AssertUnderlyingTypeIsSupported(); + } + + public bool Equals(TEnum x, TEnum y) + { + return _equals(x, y); + } + + public int GetHashCode(TEnum obj) + { + return _getHashCode(obj); + } + + private static void AssertTypeIsEnum() + { + if (typeof(TEnum).IsEnum) + return; + + throw new NotSupportedException(); + } + + private static void AssertUnderlyingTypeIsSupported() + { + var underlyingType = Enum.GetUnderlyingType(typeof(TEnum)); + ICollection supportedTypes = + new[] + { + typeof (byte), typeof (sbyte), typeof (short), typeof (ushort), + typeof (int), typeof (uint), typeof (long), typeof (ulong) + }; + + if (supportedTypes.Contains(underlyingType)) + return; + + throw new NotSupportedException(); + } + + /// + /// Generates a comparison method similar to this: + /// + /// bool Equals(TEnum x, TEnum y) + /// { + /// return x == y; + /// } + /// + /// + /// The generated method. + private static Func generateEquals() + { + var method = new DynamicMethod(typeof(TEnum).Name + "_Equals", + typeof(bool), + new[] { typeof(TEnum), typeof(TEnum) }, + typeof(TEnum), true); + var generator = method.GetILGenerator(); + // Writing body + generator.Emit(OpCodes.Ldarg_0); // load x to stack + generator.Emit(OpCodes.Ldarg_1); // load y to stack + generator.Emit(OpCodes.Ceq); // x == y + generator.Emit(OpCodes.Ret); // return result + return (Func)method.CreateDelegate + (typeof(Func)); + } + + /// + /// Generates a GetHashCode method similar to this: + /// + /// int GetHashCode(TEnum obj) + /// { + /// return ((int)obj).GetHashCode(); + /// } + /// + /// + /// The generated method. + private static Func generateGetHashCode() + { + var method = new DynamicMethod(typeof(TEnum).Name + "_GetHashCode", + typeof(int), + new[] { typeof(TEnum) }, + typeof(TEnum), true); + var generator = method.GetILGenerator(); + var underlyingType = Enum.GetUnderlyingType(typeof(TEnum)); + var getHashCodeMethod = underlyingType.GetMethod("GetHashCode"); + var castValue = generator.DeclareLocal(underlyingType); + // Writing body + generator.Emit(OpCodes.Ldarg_0); // load obj to stack + generator.Emit(OpCodes.Stloc_0); // castValue = obj + generator.Emit(OpCodes.Ldloca_S, castValue); // load *castValue to stack + generator.Emit(OpCodes.Call, getHashCodeMethod); // castValue.GetHashCode() + generator.Emit(OpCodes.Ret); // return result + return (Func)method.CreateDelegate(typeof(Func)); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/ExtensionAttribute.cs b/branches/ph-plugins/ProcessHacker.Common/ExtensionAttribute.cs new file mode 100644 index 000000000..0e39f6c55 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/ExtensionAttribute.cs @@ -0,0 +1,6 @@ +namespace System.Runtime.CompilerServices +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] + public class ExtensionAttribute : Attribute + { } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/FreeList.cs b/branches/ph-plugins/ProcessHacker.Common/FreeList.cs new file mode 100644 index 000000000..6b2588b30 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/FreeList.cs @@ -0,0 +1,126 @@ +/* + * Process Hacker - + * free list + * + * Copyright (C) 2009 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 . + */ + +using System.Threading; + +namespace ProcessHacker.Common +{ + /// + /// Manages a list of free objects that can be re-used. + /// + public class FreeList + where T : IResettable, new() + { + private class FreeListEntry + where U : IResettable, new() + { + public U Object; + public FreeListEntry Next; + } + + private FreeListEntry _listHead = null; + private int _count = 0; + private int _maximumCount = 0; + + public int Count + { + get { return _count; } + } + + public int MaximumCount + { + get { return _maximumCount; } + set { _maximumCount = value; } + } + + public T Allocate() + { + FreeListEntry listHead; + + // Atomically pop an entry off and replace the list head + // pointer with a pointer to the next entry. + while (true) + { + listHead = _listHead; + + // If the list head pointer is null, we don't have anything + // to use from the free list. + if (listHead == null) + break; + + // Try to replace the list head pointer. + if (Interlocked.CompareExchange>( + ref _listHead, + listHead.Next, + listHead + ) == listHead) + { + // Success. + _count--; + return listHead.Object; + } + } + + return this.AllocateNew(); + } + + private T AllocateNew() + { + T obj = new T(); + obj.ResetObject(); + return obj; + } + + public void Free(T obj) + { + FreeListEntry listHead; + FreeListEntry listEntry; + + // Add the object to the free list if we haven't + // exceeded the maximum count. + if (_count < _maximumCount || _maximumCount == 0) + { + listEntry = new FreeListEntry(); + + listEntry.Object = obj; + + // Atomically add the list entry. + while (true) + { + listHead = _listHead; + listEntry.Next = listHead; + + if (Interlocked.CompareExchange>( + ref _listHead, + listEntry, + listHead + ) == listHead) + { + // Success. + _count++; + break; + } + } + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/HistoryManager.cs b/branches/ph-plugins/ProcessHacker.Common/HistoryManager.cs new file mode 100644 index 000000000..a7db51960 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/HistoryManager.cs @@ -0,0 +1,104 @@ +/* + * Process Hacker - + * history manager + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Text; + +namespace ProcessHacker.Common +{ + public static class HistoryManager + { + private static int _globalMaxCount = 600; + + public static int GlobalMaxCount + { + get { return _globalMaxCount; } + set { _globalMaxCount = value; } + } + } + + public sealed class HistoryManager + { + private Dictionary> _history; + private Dictionary> _readOnlyCollections; + private int _maxCount = -1; + + public HistoryManager() + { + _history = new Dictionary>(); + _readOnlyCollections = new Dictionary>(); + } + + public HistoryManager(IEqualityComparer comparer) + { + _history = new Dictionary>(comparer); + _readOnlyCollections = new Dictionary>(comparer); + } + + public int MaxCount + { + get { return _maxCount; } + set { _maxCount = value; } + } + + public int EffectiveMaxCount + { + get { return _maxCount == -1 ? HistoryManager.GlobalMaxCount : _maxCount; } + } + + public ReadOnlyCollection this[TKey key] + { + get { return GetHistory(key); } + } + + public void Add(TKey key) + { + _history.Add(key, new CircularBuffer(this.EffectiveMaxCount)); + } + + public ReadOnlyCollection GetHistory(TKey key) + { + if (!_readOnlyCollections.ContainsKey(key)) + { + lock (_readOnlyCollections) + { + if (!_readOnlyCollections.ContainsKey(key)) + _readOnlyCollections.Add(key, new ReadOnlyCollection(_history[key])); + } + } + + return _readOnlyCollections[key]; + } + + public void Update(TKey key, TValue value) + { + int maxCount = this.EffectiveMaxCount; + + if (_history[key].Size != maxCount) + _history[key].Resize(maxCount); + + _history[key].Add(value); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/IResettable.cs b/branches/ph-plugins/ProcessHacker.Common/IResettable.cs new file mode 100644 index 000000000..2fa07049c --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/IResettable.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Common +{ + public interface IResettable + { + void ResetObject(); + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/IdGenerator.cs b/branches/ph-plugins/ProcessHacker.Common/IdGenerator.cs new file mode 100644 index 000000000..cae77136d --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/IdGenerator.cs @@ -0,0 +1,116 @@ +/* + * Process Hacker - + * unique ID generator + * + * Copyright (C) 2008 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 . + */ + +using System; +using System.Collections.Generic; + +namespace ProcessHacker.Common +{ + /// + /// Provides a facility for generating unique IDs. + /// + public class IdGenerator + { + private int _step = 1; + private bool _sort = false; + private List _ids = new List(); + private int _id; + + /// + /// Creates a new ID generator. + /// + public IdGenerator() + : this(0) + { } + + /// + /// Creates a new ID generator. + /// + /// The starting ID. + public IdGenerator(int start) + : this(start, 1) + { } + + /// + /// Creates a new ID generator. + /// + /// The starting ID. + /// The number each ID will be divisible by. + public IdGenerator(int start, int step) + { + if (step == 0) + throw new ArgumentException("step cannot be zero."); + + _id = start; + _step = step; + } + + public bool Sort + { + get { return _sort; } + set { _sort = value; } + } + + /// + /// Generates a new ID. + /// + /// + public int Pop() + { + int id; + + lock (_ids) + { + if (_ids.Count > 0) + { + id = _ids[0]; + + _ids.Remove(_ids[0]); + + return id; + } + else + { + id = _id; + _id += _step; + } + } + + return id; + } + + /// + /// Makes an ID available for use. + /// + /// + public void Push(int id) + { + lock (_ids) + { + _ids.Add(id); + + if (_sort) + _ids.Sort(); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Linq/GroupedEnumerable.cs b/branches/ph-plugins/ProcessHacker.Common/Linq/GroupedEnumerable.cs new file mode 100644 index 000000000..d9b935a1c --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Linq/GroupedEnumerable.cs @@ -0,0 +1,43 @@ +//using System; +//using System.Collections.Generic; +//using System.Text; +//using System.Collections; + +//namespace System.Linq +//{ +// internal class GroupedEnumerable : IEnumerable>, IEnumerable +// { +// IEnumerable _source; +// Func _keySelector; +// Func _elementSelector; +// IEqualityComparer _comparer; + +// // Methods +// public GroupedEnumerable ( +// IEnumerable source, +// Func keySelector, +// Func elementSelector, +// IEqualityComparer comparer) +// { +// if (source == null) throw new ArgumentNullException ("source"); +// if (keySelector == null) throw new ArgumentNullException ("keySelector"); +// if (elementSelector == null) throw new ArgumentNullException ("elementSelector"); + +// _source = source; +// _keySelector = keySelector; +// _elementSelector = elementSelector; +// _comparer = comparer; +// } + +// public IEnumerator> GetEnumerator () +// { +// return Lookup.Create (_source, _keySelector, _elementSelector, _comparer).GetEnumerator (); +// } + +// IEnumerator IEnumerable.GetEnumerator () +// { +// return this.GetEnumerator (); +// } +// } + +//} diff --git a/branches/ph-plugins/ProcessHacker.Common/Linq/Grouping.cs b/branches/ph-plugins/ProcessHacker.Common/Linq/Grouping.cs new file mode 100644 index 000000000..836f9cc26 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Linq/Grouping.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Collections.ObjectModel; + +namespace System.Linq +{ + internal class Grouping : ReadOnlyCollection, IGrouping + { + internal IList InnerList { get { return this.Items; } } + + public TKey Key { get; private set; } + + public Grouping (TKey key) : base (new List()) + { + Key = key; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Linq/IGrouping.cs b/branches/ph-plugins/ProcessHacker.Common/Linq/IGrouping.cs new file mode 100644 index 000000000..2bb7a8438 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Linq/IGrouping.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace System.Linq +{ + public interface IGrouping : IEnumerable + { + TKey Key { get; } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Linq/ILookup.cs b/branches/ph-plugins/ProcessHacker.Common/Linq/ILookup.cs new file mode 100644 index 000000000..00ab824b5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Linq/ILookup.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace System.Linq +{ + public interface ILookup : IEnumerable> + { + int Count { get; } + bool Contains (TKey key); + IEnumerable this [TKey key] { get; } + } + +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker.Common/Linq/IOrderedEnumerable.cs b/branches/ph-plugins/ProcessHacker.Common/Linq/IOrderedEnumerable.cs new file mode 100644 index 000000000..4e466b336 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Linq/IOrderedEnumerable.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace System +{ + // We'll stick with Microsoft's definition of IOrderedEnumerable to minimize confusion. + + public interface IOrderedEnumerable : IEnumerable + { + IOrderedEnumerable CreateOrderedEnumerable ( + Func keySelector, + IComparer comparer, + bool descending); + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Linq/License.txt b/branches/ph-plugins/ProcessHacker.Common/Linq/License.txt new file mode 100644 index 000000000..e440b797d --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Linq/License.txt @@ -0,0 +1,20 @@ +LINQBridge Copyright (c) 2007-2008 Joseph Albahari + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/branches/ph-plugins/ProcessHacker.Common/Linq/Lookup.cs b/branches/ph-plugins/ProcessHacker.Common/Linq/Lookup.cs new file mode 100644 index 000000000..d91e08968 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Linq/Lookup.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Collections; + +namespace System.Linq +{ + public class Lookup : ILookup + { + Dictionary> _groupings; + + internal static Lookup Create ( + IEnumerable source, + Func keySelector, + Func elementSelector, + IEqualityComparer comparer) + { + if (source == null) throw new ArgumentNullException ("source"); + if (keySelector == null) throw new ArgumentNullException ("keySelector"); + if (elementSelector == null) throw new ArgumentNullException ("elementSelector"); + + var lookup = new Lookup (comparer ?? EqualityComparer.Default); + + foreach (TSource element in source) + { + TKey key = keySelector (element); + Grouping grouping; + + if (!lookup._groupings.TryGetValue (key, out grouping)) + lookup._groupings.Add (key, grouping = new Grouping (key)); + + grouping.InnerList.Add (elementSelector (element)); + } + + return lookup; + } + + Lookup (IEqualityComparer comparer) + { + _groupings = new Dictionary> (comparer); + } + + public int Count { get { return _groupings.Count; } } + + public IEnumerable this [TKey key] + { + get + { + Grouping result; + if (_groupings.TryGetValue (key, out result)) + return result; + else + return Enumerable.Empty (); + } + } + + public bool Contains (TKey key) + { + return _groupings.ContainsKey (key); + } + + public IEnumerator> GetEnumerator () + { + foreach (var grouping in _groupings.Values) + yield return grouping; + } + + IEnumerator IEnumerable.GetEnumerator () { return GetEnumerator (); } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Linq/OrderByEnumerable.cs b/branches/ph-plugins/ProcessHacker.Common/Linq/OrderByEnumerable.cs new file mode 100644 index 000000000..ec2d16dec --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Linq/OrderByEnumerable.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace System.Linq +{ + class OrderByEnumerable : IOrderedEnumerable + { + public readonly IEnumerable Source; + public readonly Func KeySelector; + public readonly IComparer Comparer; + public readonly bool Descending; + + public OrderByEnumerable (IEnumerable source, Func keySelector, IComparer comparer, bool descending) + { + if (source == null) throw new ArgumentNullException ("source"); + if (keySelector == null) throw new ArgumentNullException ("keySelector"); + + Source = source; + KeySelector = keySelector; + Comparer = comparer ?? Comparer.Default; + Descending = descending; + } + + public IOrderedEnumerable CreateOrderedEnumerable ( + Func keySelector, + IComparer comparer, + bool descending) + { + return new ThenByEnumerable (this, keySelector, comparer, descending); + } + + internal virtual int CompareElements (TElement e1, TElement e2) // ThenByEnumerable will override this method. + { + int result = Comparer.Compare (KeySelector (e1), KeySelector (e2)); + return Descending ? -result : result; + } + + internal virtual IEnumerable GetElementsToSort () // ThenByEnumerable will override this method. + { + return Source; + } + + public IEnumerator GetEnumerator () + { + TElement [] array = GetElementsToSort ().ToArray(); + Array.Sort (array, CompareElements); + foreach (TElement element in array) + yield return element; + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () + { + return GetEnumerator(); + } + } + +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Aggregation Operators - Average.cs b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Aggregation Operators - Average.cs new file mode 100644 index 000000000..571384bbc --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Aggregation Operators - Average.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace System.Linq +{ + public static partial class Enumerable + { + // int + + public static double Average (this IEnumerable source) + { + if (source == null) throw new ArgumentNullException ("source"); + return (double) source.Sum () / source.Count (); + } + + public static double? Average (this IEnumerable source) + { + if (source == null) throw new ArgumentNullException ("source"); + + int count = source.Count(); + if (count == 0) return null; + return (double)source.Sum () / count; + } + + public static double Average (this IEnumerable source, Func selector) + { + return source.Select (selector).Average (); + } + + public static double? Average (this IEnumerable source, Func selector) + { + return source.Select (selector).Average (); + } + + // long + + public static double Average (this IEnumerable source) + { + if (source == null) throw new ArgumentNullException ("source"); + return (double)source.Sum () / source.Count (); + } + + public static double? Average (this IEnumerable source) + { + if (source == null) throw new ArgumentNullException ("source"); + + int count = source.Count (); + if (count == 0) return null; + return (double)source.Sum () / count; + } + + public static double Average (this IEnumerable source, Func selector) + { + return source.Select (selector).Average (); + } + + public static double? Average (this IEnumerable source, Func selector) + { + return source.Select (selector).Average (); + } + + // float + + public static float Average (this IEnumerable source) + { + if (source == null) throw new ArgumentNullException ("source"); + return source.Sum () / source.Count (); + } + + public static float? Average (this IEnumerable source) + { + if (source == null) throw new ArgumentNullException ("source"); + + int count = source.Count (); + if (count == 0) return null; + return source.Sum () / count; + } + + public static float Average (this IEnumerable source, Func selector) + { + return source.Select (selector).Average (); + } + + public static float? Average (this IEnumerable source, Func selector) + { + return source.Select (selector).Average (); + } + + // double + + public static double Average (this IEnumerable source) + { + if (source == null) throw new ArgumentNullException ("source"); + return source.Sum () / source.Count (); + } + + public static double? Average (this IEnumerable source) + { + if (source == null) throw new ArgumentNullException ("source"); + + int count = source.Count (); + if (count == 0) return null; + return source.Sum () / count; + } + + public static double Average (this IEnumerable source, Func selector) + { + return source.Select (selector).Average (); + } + + public static double? Average (this IEnumerable source, Func selector) + { + return source.Select (selector).Average (); + } + + // decimal + + public static decimal Average (this IEnumerable source) + { + if (source == null) throw new ArgumentNullException ("source"); + + int count = source.Count (); + if (count == 0) ThrowNoElements (); // decimal has no special "NaN" value, so we can't divide by zero. + return source.Sum () / count; + } + + public static decimal? Average (this IEnumerable source) + { + if (source == null) throw new ArgumentNullException ("source"); + + int count = source.Count (); + if (count == 0) return null; + return source.Sum () / count; + } + + public static decimal Average (this IEnumerable source, Func selector) + { + return source.Select (selector).Average (); + } + + public static decimal? Average (this IEnumerable source, Func selector) + { + return source.Select (selector).Average (); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Aggregation Operators - Sum.cs b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Aggregation Operators - Sum.cs new file mode 100644 index 000000000..bc82e92dc --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Aggregation Operators - Sum.cs @@ -0,0 +1,162 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace System.Linq +{ + public static partial class Enumerable + { + // int + + public static int Sum (this IEnumerable source) + { + if (source == null) throw new ArgumentNullException ("source"); + + int tot = 0; + foreach (int element in source) checked { tot += element; }; + return tot; + } + + // It makes no sense to me that this returns a double? rather than a double, but that's the way the standard query operators work. + public static int? Sum (this IEnumerable source) + { + if (source == null) throw new ArgumentNullException ("source"); + + int tot = 0; + foreach (int? element in source) checked { tot += element ?? 0; }; + return tot; + } + + public static int Sum (this IEnumerable source, Func selector) + { + return source.Select (selector).Sum (); + } + + public static int? Sum (this IEnumerable source, Func selector) + { + return source.Select (selector).Sum (); + } + + // long + + public static long Sum (this IEnumerable source) + { + if (source == null) throw new ArgumentNullException ("source"); + + long tot = 0; + foreach (long element in source) checked { tot += element; } + return tot; + } + + public static long? Sum (this IEnumerable source) + { + if (source == null) throw new ArgumentNullException ("source"); + + long tot = 0; + foreach (long? element in source) checked { tot += element ?? 0; } + return tot; + } + + public static long Sum (this IEnumerable source, Func selector) + { + return source.Select (selector).Sum (); + } + + public static long? Sum (this IEnumerable source, Func selector) + { + return source.Select (selector).Sum (); + } + + // float + + public static float Sum (this IEnumerable source) + { + if (source == null) throw new ArgumentNullException ("source"); + + float tot = 0; + foreach (float element in source) tot += element; + return tot; + } + + public static float? Sum (this IEnumerable source) + { + if (source == null) throw new ArgumentNullException ("source"); + + float tot = 0; + foreach (float? element in source) tot += element ?? 0; + return tot; + } + + public static float Sum (this IEnumerable source, Func selector) + { + return source.Select (selector).Sum (); + } + + public static float? Sum (this IEnumerable source, Func selector) + { + return source.Select (selector).Sum (); + } + + // double + + public static double Sum (this IEnumerable source) + { + if (source == null) throw new ArgumentNullException ("source"); + + double tot = 0; + foreach (double element in source) tot += element; + return tot; + } + + public static double? Sum (this IEnumerable source) + { + if (source == null) throw new ArgumentNullException ("source"); + + double tot = 0; + foreach (double? element in source) + tot += element ?? 0; + return tot; + } + + public static double Sum (this IEnumerable source, Func selector) + { + return source.Select (selector).Sum (); + } + + public static double ?Sum (this IEnumerable source, Func selector) + { + return source.Select (selector).Sum (); + } + + // decimal + + public static decimal Sum (this IEnumerable source) + { + if (source == null) throw new ArgumentNullException ("source"); + + decimal tot = 0; + foreach (decimal element in source) tot += element; + return tot; + } + + public static decimal? Sum (this IEnumerable source) + { + if (source == null) throw new ArgumentNullException ("source"); + + decimal tot = 0; + foreach (decimal? element in source) + tot += element ?? 0; + return tot; + } + + public static decimal Sum (this IEnumerable source, Func selector) + { + return source.Select (selector).Sum (); + } + + public static decimal? Sum (this IEnumerable source, Func selector) + { + return source.Select (selector).Sum (); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Aggregation Operators.cs b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Aggregation Operators.cs new file mode 100644 index 000000000..df33123e1 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Aggregation Operators.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; + +namespace System.Linq +{ + public static partial class Enumerable + { + // Count / LongCount + + public static int Count (this IEnumerable source) + { + if (source is ICollection) return ((ICollection)source).Count; + if (source is ICollection) return ((ICollection)source).Count; + + int count = 0; + foreach (TSource element in source) count++; + return count; + } + + public static int Count (this IEnumerable source, Func predicate) + { + if (source == null) throw new ArgumentNullException ("source"); + if (predicate == null) throw new ArgumentNullException ("predicate"); + + int count = 0; + foreach (TSource element in source) + if (predicate (element)) + count++; + + return count; + } + + public static long LongCount (this IEnumerable source) + { + if (source is ICollection) return ((ICollection)source).Count; + if (source is ICollection) return ((ICollection)source).Count; + + long count = 0; + foreach (TSource element in source) count++; + return count; + } + + public static long LongCount (this IEnumerable source, Func predicate) + { + if (source == null) throw new ArgumentNullException ("source"); + if (predicate == null) throw new ArgumentNullException ("predicate"); + + long count = 0; + foreach (TSource element in source) + if (predicate (element)) + count++; + + return count; + } + + // Min + + public static TSource Min (this IEnumerable source) + { + if (!source.Any () && default (TSource) == null) return default (TSource); + return source.Aggregate ((accum, element) => Comparer.Default.Compare (accum, element) < 0 ? accum : element); + } + + public static TSource? Min (this IEnumerable source) + where TSource : struct + { + if (!source.Any ()) return default (TSource?); + return source.Aggregate ((accum, element) => Comparer.Default.Compare (accum, element) < 0 ? accum : element); + } + + public static TResult Min (this IEnumerable source, Func selector) + { + return source.Select (selector).Min (); + } + + // Max + + public static TSource Max (this IEnumerable source) + { + if (!source.Any () && default (TSource) == null) return default (TSource); + return source.Aggregate ((accum, element) => Comparer.Default.Compare (accum, element) > 0 ? accum : element); + } + + public static TSource? Max (this IEnumerable source) + where TSource : struct + { + if (!source.Any ()) return default (TSource?); + return source.Aggregate ((accum, element) => Comparer.Default.Compare (accum, element) > 0 ? accum : element); + } + + public static TResult Max (this IEnumerable source, Func selector) + { + return source.Select (selector).Max (); + } + + // Aggregate + + public static TSource Aggregate (this IEnumerable source, Func func) + { + if (source == null) throw new ArgumentNullException ("source"); + if (func == null) throw new ArgumentNullException ("func"); + + bool noElements = true; + TSource runningValue = default (TSource); + + foreach (TSource element in source) + { + if (noElements) + { + noElements = false; + runningValue = element; + } + else + runningValue = func (runningValue, element); + } + + if (noElements) ThrowNoElements (); + return runningValue; + } + + public static TAccumulate Aggregate ( + this IEnumerable source, + TAccumulate seed, + Func func) + { + return source.Aggregate (seed, func, x => x); + } + + public static TResult Aggregate ( + this IEnumerable source, TAccumulate seed, + Func func, + Func resultSelector) + { + if (source == null) throw new ArgumentNullException ("source"); + if (func == null) throw new ArgumentNullException ("func"); + if (resultSelector == null) throw new ArgumentNullException ("resultSelector"); + + TAccumulate runningValue = seed; + + foreach (TSource element in source) + runningValue = func (runningValue, element); + + return resultSelector (runningValue); + } + + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Conversion Operators.cs b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Conversion Operators.cs new file mode 100644 index 000000000..a24361212 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Conversion Operators.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Collections; + +namespace System.Linq +{ + public static partial class Enumerable + { + public static List ToList (this IEnumerable source) + { + if (source == null) throw new ArgumentNullException ("source"); + return new List (source); + } + + public static TSource [] ToArray (this IEnumerable source) + { + if (source == null) throw new ArgumentNullException ("source"); + return source.ToList ().ToArray (); + } + + public static Dictionary ToDictionary (this IEnumerable source, Func keySelector) + { + return source.ToDictionary (keySelector, x => x, null); + } + + public static Dictionary ToDictionary (this IEnumerable source, Func keySelector, IEqualityComparer comparer) + { + return source.ToDictionary (keySelector, x => x, comparer); + } + + public static Dictionary ToDictionary ( + this IEnumerable source, + Func keySelector, + Func elementSelector) + { + return source.ToDictionary (keySelector, elementSelector, null); + } + + public static Dictionary ToDictionary ( + this IEnumerable source, + Func keySelector, + Func elementSelector, + IEqualityComparer comparer) + { + if (source == null) throw new ArgumentNullException ("source"); + if (keySelector == null) throw new ArgumentNullException ("keySelector"); + if (elementSelector == null) throw new ArgumentNullException ("elementSelector"); + + Dictionary d = new Dictionary (comparer); + + foreach (TSource element in source) + d.Add (keySelector (element), elementSelector (element)); + + return d; + } + + public static ILookup ToLookup (this IEnumerable source, Func keySelector) + { + return Lookup.Create (source, keySelector, x => x, null); + } + + public static ILookup ToLookup ( + this IEnumerable source, + Func keySelector, + IEqualityComparer comparer) + { + return Lookup.Create (source, keySelector, x => x, comparer); + } + + public static ILookup ToLookup ( + this IEnumerable source, + Func keySelector, + Func elementSelector) + { + return Lookup.Create (source, keySelector, elementSelector, null); + } + + public static ILookup ToLookup ( + this IEnumerable source, + Func keySelector, + Func elementSelector, + IEqualityComparer comparer) + { + return Lookup.Create (source, keySelector, elementSelector, comparer); + } + + public static IEnumerable AsEnumerable (this IEnumerable source) + { + return source; + } + + public static IEnumerable OfType (this IEnumerable source) + { + if (source == null) throw new ArgumentNullException ("source"); + + foreach (object obj in source) + if (obj is TResult) + yield return (TResult) obj; + } + + public static IEnumerable Cast (this IEnumerable source) + { + if (source == null) throw new ArgumentNullException ("source"); + + foreach (object obj in source) + yield return (TResult) obj; + } + + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Element Operators.cs b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Element Operators.cs new file mode 100644 index 000000000..f928f1de9 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Element Operators.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Collections; + +namespace System.Linq +{ + public static partial class Enumerable + { + // Single + + public static TSource Single (this IEnumerable source) + { + return source.Single (x => true, false); + } + + public static TSource Single (this IEnumerable source, Func predicate) + { + return source.Single (predicate, false); + } + + public static TSource SingleOrDefault (this IEnumerable source) + { + return source.Single (x => true, true); + } + + public static TSource SingleOrDefault (this IEnumerable source, Func predicate) + { + return source.Single (predicate, true); + } + + static TSource Single (this IEnumerable source, Func predicate, bool orDefault) + { + if (source == null) throw new ArgumentNullException ("source"); + if (predicate == null) throw new ArgumentNullException ("predicate"); + + TSource answer = default (TSource); + bool match = false; + + foreach (TSource element in source) + if (predicate (element)) + { + if (match) throw new InvalidOperationException ("Enumerable contains more than one matching element"); + match = true; + answer = element; + } + + if (!match && !orDefault) ThrowNoMatches (); + return answer; + } + + // First + + public static TSource First (this IEnumerable source) + { + return source.First (x => true, false); + } + + public static TSource First (this IEnumerable source, Func predicate) + { + return source.First (predicate, false); + } + + public static TSource FirstOrDefault (this IEnumerable source) + { + return source.First (x => true, true); + } + + public static TSource FirstOrDefault (this IEnumerable source, Func predicate) + { + return source.First (predicate, true); + } + + static TSource First (this IEnumerable source, Func predicate, bool orDefault) + { + if (source == null) throw new ArgumentNullException ("source"); + if (predicate == null) throw new ArgumentNullException ("predicate"); + + foreach (TSource element in source) + if (predicate (element)) + return element; + + if (!orDefault) ThrowNoMatches (); + return default (TSource); + } + + // Last + + public static TSource Last (this IEnumerable source) + { + return source.Last (x => true, false); + } + + public static TSource Last (this IEnumerable source, Func predicate) + { + return source.Last (predicate, false); + } + + public static TSource LastOrDefault (this IEnumerable source) + { + return source.Last (x => true, true); + } + + public static TSource LastOrDefault (this IEnumerable source, Func predicate) + { + return source.Last (predicate, true); + } + + static TSource Last (this IEnumerable source, Func predicate, bool orDefault) + { + if (source == null) throw new ArgumentNullException ("source"); + if (predicate == null) throw new ArgumentNullException ("predicate"); + + TSource answer = default (TSource); + bool match = false; + + foreach (TSource element in source) + if (predicate (element)) + { + match = true; + answer = element; + } + + if (!match && !orDefault) ThrowNoMatches (); + return answer; + } + + // ElementAt + + public static TSource ElementAt (this IEnumerable source, int index) + { + return source.ElementAt (index, false); + } + + public static TSource ElementAtOrDefault (this IEnumerable source, int index) + { + return source.ElementAt (index, true); + } + + static TSource ElementAt (this IEnumerable source, int index, bool orDefault) + { + if (source == null) throw new ArgumentNullException ("source"); + if (index < 0) throw new ArgumentOutOfRangeException ("index"); + + if (source is IList) return ((IList)source) [index]; + if (source is IList) return (TSource) ((IList)source) [index]; + + foreach (TSource element in source) + if (index-- == 0) + return element; + + if (!orDefault) throw new ArgumentOutOfRangeException ("index"); + return default (TSource); + } + + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Enumerable Private.cs b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Enumerable Private.cs new file mode 100644 index 000000000..04f3b6e9d --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Enumerable Private.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace System.Linq +{ + public static partial class Enumerable + { + static void ThrowNoElements () + { + throw new InvalidOperationException ("Enumerable contains no elements"); + } + + static void ThrowNoMatches () + { + throw new InvalidOperationException ("Enumerable contains no matching element"); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Filtering Operators.cs b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Filtering Operators.cs new file mode 100644 index 000000000..96d3af0de --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Filtering Operators.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace System.Linq +{ + public static partial class Enumerable + { + public static IEnumerable Distinct (this IEnumerable source) + { + if (source == null) throw new ArgumentNullException ("source"); + + // We can't use a HashSet here, because we don't have access to FW3.5! + var visitedElements = new Dictionary (); + + foreach (TSource element in source) + if (!visitedElements.ContainsKey (element)) + { + visitedElements.Add (element, null); + yield return element; + } + } + + public static IEnumerable Skip (this IEnumerable source, int count) + { + if (source == null) throw new ArgumentNullException ("source"); + + foreach (TSource element in source) + if (count-- <= 0) + yield return element; + } + + public static IEnumerable SkipWhile (this IEnumerable source, Func predicate) + { + if (source == null) throw new ArgumentNullException ("source"); + if (predicate == null) throw new ArgumentNullException ("predicate"); + + bool unsatisfied = true; + foreach (TSource element in source) + { + if (unsatisfied) unsatisfied = predicate (element); + if (!unsatisfied) yield return element; + } + } + + public static IEnumerable SkipWhile (this IEnumerable source, Func predicate) + { + if (source == null) throw new ArgumentNullException ("source"); + if (predicate == null) throw new ArgumentNullException ("predicate"); + + bool unsatisfied = true; + int i = 0; + foreach (TSource element in source) + { + if (unsatisfied) unsatisfied = predicate (element, i++); + if (!unsatisfied) yield return element; + } + } + + public static IEnumerable Take (this IEnumerable source, int count) + { + if (source == null) throw new ArgumentNullException ("source"); + + if (count <= 0) yield break; + foreach (TSource element in source) + if (count-- == 0) + break; + else + yield return element; + } + + public static IEnumerable TakeWhile (this IEnumerable source, Func predicate) + { + if (source == null) throw new ArgumentNullException ("source"); + if (predicate == null) throw new ArgumentNullException ("predicate"); + + foreach (TSource element in source) + if (predicate (element)) + yield return element; + else + break; + } + + public static IEnumerable TakeWhile (this IEnumerable source, Func predicate) + { + if (source == null) throw new ArgumentNullException ("source"); + if (predicate == null) throw new ArgumentNullException ("predicate"); + + int i = 0; + foreach (TSource element in source) + if (predicate (element, i++)) + yield return element; + else + break; + } + + public static IEnumerable Where (this IEnumerable source, Func predicate) + { + if (source == null) throw new ArgumentNullException ("source"); + if (predicate == null) throw new ArgumentNullException ("predicate"); + + foreach (TSource element in source) + if (predicate (element)) + yield return element; + } + + public static IEnumerable Where (this IEnumerable source, Func predicate) + { + if (source == null) throw new ArgumentNullException ("source"); + if (predicate == null) throw new ArgumentNullException ("predicate"); + + int i = 0; + foreach (TSource element in source) + if (predicate (element, i++)) + yield return element; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Generation Operators.cs b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Generation Operators.cs new file mode 100644 index 000000000..5d8e23d1c --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Generation Operators.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace System.Linq +{ + public static partial class Enumerable + { + public static IEnumerable Range (int start, int count) + { + for (int i = 0; i < count; i++) + yield return i + start; + } + + public static IEnumerable Repeat (TResult element, int count) + { + for (int i = 0; i < count; i++) + yield return element; + } + + public static IEnumerable Empty () + { + yield break; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Grouping Operators.cs b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Grouping Operators.cs new file mode 100644 index 000000000..5a05ba0b7 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Grouping Operators.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace System.Linq +{ + public static partial class Enumerable + { + public static IEnumerable> GroupBy ( + this IEnumerable source, + Func keySelector) + { + return source.GroupBy (keySelector, x => x, null); + } + + public static IEnumerable> GroupBy ( + this IEnumerable source, + Func keySelector, + IEqualityComparer comparer) + { + return source.GroupBy (keySelector, x => x, comparer); + } + + public static IEnumerable> GroupBy ( + this IEnumerable source, + Func keySelector, + Func elementSelector) + { + return source.GroupBy (keySelector, elementSelector, null); + } + + public static IEnumerable> GroupBy ( + this IEnumerable source, + Func keySelector, + Func elementSelector, + IEqualityComparer comparer) + { + return Lookup.Create (source, keySelector, elementSelector, comparer); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Joining Operators.cs b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Joining Operators.cs new file mode 100644 index 000000000..67edb76a2 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Joining Operators.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace System.Linq +{ + public static partial class Enumerable + { + public static IEnumerable Join + (this IEnumerable outer, + IEnumerable inner, + Func outerKeySelector, + Func innerKeySelector, + Func resultSelector) + { + if (outer == null) throw new ArgumentNullException ("outer"); + if (inner == null) throw new ArgumentNullException ("inner"); + if (outerKeySelector == null) throw new ArgumentNullException ("outerKeySelector"); + if (innerKeySelector == null) throw new ArgumentNullException ("innerKeySelector"); + if (resultSelector == null) throw new ArgumentNullException ("resultSelector"); + + ILookup lookup = inner.ToLookup (innerKeySelector); + + // We can use LINQ to write LINQ! A SelectMany-style query over a lookup is the easiest way to + // implement a Join (see page 344, C# 3.0 in a Nutshell). + return + from outerItem in outer + from innerItem in lookup [outerKeySelector (outerItem)] + select resultSelector (outerItem, innerItem); + } + + public static IEnumerable GroupJoin ( + this IEnumerable outer, + IEnumerable inner, + Func outerKeySelector, + Func innerKeySelector, + Func, TResult> resultSelector) + { + if (outer == null) throw new ArgumentNullException ("outer"); + if (inner == null) throw new ArgumentNullException ("inner"); + if (outerKeySelector == null) throw new ArgumentNullException ("outerKeySelector"); + if (innerKeySelector == null) throw new ArgumentNullException ("innerKeySelector"); + if (resultSelector == null) throw new ArgumentNullException ("resultSelector"); + + ILookup lookup = inner.ToLookup (innerKeySelector); + + // We won't make this harder than it needs to be - a GroupJoin is just a projection over a lookup! + return + from outerItem in outer + select resultSelector (outerItem, lookup [outerKeySelector (outerItem)]); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Misc Operators.cs b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Misc Operators.cs new file mode 100644 index 000000000..a305980a0 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Misc Operators.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace System.Linq +{ + public static partial class Enumerable + { + public static IEnumerable Reverse (this IEnumerable source) + { + if (source == null) throw new ArgumentNullException ("source"); + + var list = source.ToList (); + + for (int i = list.Count - 1; i >= 0; i--) + yield return list [i]; + } + + public static IEnumerable DefaultIfEmpty (this IEnumerable source) + { + return source.DefaultIfEmpty (default (TSource)); + } + + public static IEnumerable DefaultIfEmpty (this IEnumerable source, TSource defaultValue) + { + if (source == null) throw new ArgumentNullException ("source"); + + bool empty = true; + foreach (TSource element in source) + { + empty = false; + yield return element; + } + if (empty) yield return defaultValue; + } + + // A bonus query operator! It allows you to do this: + // myQuery.ForEach (Console.WriteLine); + + public static void ForEach (this IEnumerable source, Action action) + { + foreach (TSource element in source) + action (element); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Ordering Operators.cs b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Ordering Operators.cs new file mode 100644 index 000000000..587992be3 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Ordering Operators.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace System.Linq +{ + public static partial class Enumerable + { + // OrderBy: + + public static IOrderedEnumerable OrderBy ( + this IEnumerable source, + Func keySelector) + { + return OrderBy (source, keySelector, null); + } + + public static IOrderedEnumerable OrderBy ( + this IEnumerable source, + Func keySelector, + IComparer comparer) + { + return new OrderByEnumerable (source, keySelector, null, false); + } + + public static IOrderedEnumerable OrderByDescending ( + this IEnumerable source, + Func keySelector) + { + return OrderByDescending (source, keySelector, null); + } + + public static IOrderedEnumerable OrderByDescending ( + this IEnumerable source, + Func keySelector, + IComparer comparer) + { + return new OrderByEnumerable (source, keySelector, null, true); + } + + // ThenBy: + + public static IOrderedEnumerable ThenBy ( + this IOrderedEnumerable source, + Func keySelector) + { + return ThenBy (source, keySelector, null); + } + + public static IOrderedEnumerable ThenBy ( + this IOrderedEnumerable source, + Func keySelector, + IComparer comparer) + { + return source.CreateOrderedEnumerable (keySelector, comparer, false); + } + + public static IOrderedEnumerable ThenByDescending ( + this IOrderedEnumerable source, + Func keySelector) + { + return ThenByDescending (source, keySelector, null); + } + + public static IOrderedEnumerable ThenByDescending ( + this IOrderedEnumerable source, + Func keySelector, + IComparer comparer) + { + return source.CreateOrderedEnumerable (keySelector, comparer, true); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Projection Operators.cs b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Projection Operators.cs new file mode 100644 index 000000000..47375ce55 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Projection Operators.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace System.Linq +{ + public static partial class Enumerable + { + // Select + + public static IEnumerable Select (this IEnumerable source, Func selector) + { + if (source == null) throw new ArgumentNullException ("source"); + if (selector == null) throw new ArgumentNullException ("selector"); + + foreach (TSource element in source) + yield return selector (element); + } + + public static IEnumerable Select (this IEnumerable source, Func selector) + { + if (source == null) throw new ArgumentNullException ("source"); + if (selector == null) throw new ArgumentNullException ("selector"); + + int i = 0; + foreach (TSource element in source) + yield return selector (element, i++); + } + + // SelectMany + + public static IEnumerable SelectMany ( + this IEnumerable source, + Func> selector) + { + if (source == null) throw new ArgumentNullException ("source"); + if (selector == null) throw new ArgumentNullException ("selector"); + + foreach (TSource element in source) + foreach (TResult childElement in selector (element)) + yield return childElement; + } + + public static IEnumerable SelectMany ( + this IEnumerable source, + Func> selector) + { + if (source == null) throw new ArgumentNullException ("source"); + if (selector == null) throw new ArgumentNullException ("selector"); + + int i = 0; + foreach (TSource element in source) + { + foreach (TResult innerElement in selector (element, i)) + yield return innerElement; + i++; + } + } + + public static IEnumerable SelectMany ( + this IEnumerable source, + Func> collectionSelector, + Func resultSelector) + { + if (source == null) throw new ArgumentNullException ("source"); + if (collectionSelector == null) throw new ArgumentNullException ("collectionSelector"); + if (resultSelector == null) throw new ArgumentNullException ("resultSelector"); + + foreach (TSource element in source) + foreach (TCollection innerElement in collectionSelector (element)) + yield return resultSelector (element, innerElement); + } + + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Quantifiers.cs b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Quantifiers.cs new file mode 100644 index 000000000..2e5b41df2 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Quantifiers.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace System.Linq +{ + public static partial class Enumerable + { + public static bool Contains (this IEnumerable source, TSource value) + { + if (source == null) throw new ArgumentNullException ("source"); + + foreach (TSource element in source) + if (object.Equals (element, value)) + return true; + + return false; + } + + public static bool Any (this IEnumerable source) + { + return Any (source, x => true); + } + + public static bool Any (this IEnumerable source, Func predicate) + { + if (source == null) throw new ArgumentNullException ("source"); + if (predicate == null) throw new ArgumentNullException ("predicate"); + + foreach (TSource element in source) + if (predicate (element)) + return true; + + return false; + } + + public static bool All (this IEnumerable source, Func predicate) + { + if (source == null) throw new ArgumentNullException ("source"); + if (predicate == null) throw new ArgumentNullException ("predicate"); + + foreach (TSource element in source) + if (!predicate (element)) + return false; + + return true; + } + + public static bool SequenceEqual (this IEnumerable first, IEnumerable second) + { + if (first == null) throw new ArgumentNullException ("first"); + if (second == null) throw new ArgumentNullException ("second"); + + using (var firstRator = second.GetEnumerator ()) + { + foreach (TSource secondElement in first) + { + if (!firstRator.MoveNext ()) return false; + if (!object.Equals (firstRator.Current, secondElement)) return false; + } + if (firstRator.MoveNext ()) return false; + } + return true; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Set Operators.cs b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Set Operators.cs new file mode 100644 index 000000000..fa452981e --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Linq/Query Operators/Set Operators.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace System.Linq +{ + public static partial class Enumerable + { + public static IEnumerable Concat (this IEnumerable first, IEnumerable second) + { + if (first == null) throw new ArgumentException ("first"); + if (second == null) throw new ArgumentException ("second"); + + foreach (TSource element in first) + yield return element; + + foreach (TSource element in second) + yield return element; + } + + public static IEnumerable Union (this IEnumerable first, IEnumerable second) + { + return first.Concat (second).Distinct (); + } + + public static IEnumerable Intersect (this IEnumerable first, IEnumerable second) + { + if (first == null) throw new ArgumentException ("first"); + if (second == null) throw new ArgumentException ("second"); + + var firstDict = new Dictionary(); + + foreach (TSource element in first) + firstDict [element] = false; + + foreach (TSource element in second) + if (firstDict.ContainsKey (element)) + firstDict [element] = true; + + foreach (KeyValuePair keyValue in firstDict) + if (keyValue.Value) + yield return keyValue.Key; + } + + public static IEnumerable Except (this IEnumerable first, IEnumerable second) + { + if (first == null) throw new ArgumentException ("first"); + if (second == null) throw new ArgumentException ("second"); + + Dictionary firstDict = new Dictionary (); + + foreach (TSource element in first) + firstDict [element] = null; + + foreach (TSource element in second) + firstDict.Remove (element); + + foreach (TSource element in firstDict.Keys) + yield return element; + } + + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Linq/ThenByEnumerable.cs b/branches/ph-plugins/ProcessHacker.Common/Linq/ThenByEnumerable.cs new file mode 100644 index 000000000..a50f1208d --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Linq/ThenByEnumerable.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace System.Linq +{ + class ThenByEnumerable : OrderByEnumerable + { + public ThenByEnumerable ( + OrderByEnumerable source, + Func keySelector, + IComparer comparer, + bool descending) + : base (source, keySelector, comparer, descending) + { + } + + public OrderByEnumerable OrderedSource { get { return (OrderByEnumerable) Source; } } + + internal override int CompareElements (TElement e1, TElement e2) + { + // First compare elements using the preceding OrderBy operator in the chain. (If the preceding operator is also + // an instance of ThenByEnumerable, it will, in turn, look at its previous OrderBy operator). If we get a non-zero + // result back, we can ignore our own comparison logic: + int result = OrderedSource.CompareElements (e1, e2); + if (result != 0) return result; + + // All preceding OrderBy operators have decided that the two elements are in the same sorting position. + // Now it's up to us to arbitrate! We'll call upon our normal sorting logic - as defined in the base class. + return base.CompareElements (e1, e2); + } + + internal override IEnumerable GetElementsToSort () + { + // Rather than sorting the result of the previous OrderBy, we'll sort the *original* sequence, using a + // comparer that takes all keys into account at once: + return OrderedSource.GetElementsToSort(); + } + } + +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Logging.cs b/branches/ph-plugins/ProcessHacker.Common/Logging.cs new file mode 100644 index 000000000..e2c973f84 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Logging.cs @@ -0,0 +1,78 @@ +/* + * Process Hacker - + * logging + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace ProcessHacker.Common +{ + public delegate void LoggingDelegate(string message); + + public static class Logging + { + public enum Importance : int + { + Information = 0, + Warning, + Error, + Critical + } + + public static event LoggingDelegate Logged; + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] + private static extern void OutputDebugString(string OutputString); + + private static object _logLock = new object(); + + [Conditional("DEBUG")] + public static void Log(Importance importance, string message) + { + lock (_logLock) + { + string debugMessage = + DateTime.Now.ToString("hh:mm:ss:fff:") + + " ProcessHacker (T" + System.Threading.Thread.CurrentThread.ManagedThreadId + + "): (" + importance.ToString() + ") " + message + "\r\n\r\n" + Environment.StackTrace; + + OutputDebugString(debugMessage); + + if (Logged != null) + Logged(debugMessage); + } + } + + [Conditional("DEBUG")] + public static void Log(Exception ex) + { + string message = ex.Message; + + if (ex.InnerException != null) + message += "\r\nInner exception:\r\n" + ex.InnerException.ToString(); + if (ex.StackTrace != null) + message += "\r\n" + ex.StackTrace; + + Log(Importance.Error, message); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Messaging/Message.cs b/branches/ph-plugins/ProcessHacker.Common/Messaging/Message.cs new file mode 100644 index 000000000..99616e719 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Messaging/Message.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Common.Messaging +{ + public class Message + { + private object _tag; + + public object Tag + { + get { return _tag; } + set { _tag = value; } + } + } + + public class ActionMessage : Message + { + private Action _action; + + public ActionMessage(Action action) + { + _action = action; + } + + public Action Action + { + get { return _action; } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Messaging/MessageQueue.cs b/branches/ph-plugins/ProcessHacker.Common/Messaging/MessageQueue.cs new file mode 100644 index 000000000..9ef8adb34 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Messaging/MessageQueue.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Common.Messaging +{ + public class MessageQueue + { + private Queue _queue = new Queue(); + private List _listeners = new List(); + + public MessageQueue() + { + // Action message listener. + this.AddListener(new MessageQueueListener((action) => action.Action())); + } + + public void AddListener(MessageQueueListener listener) + { + lock (_listeners) + _listeners.Add(listener); + } + + public void Enqueue(Message message) + { + lock (_queue) + _queue.Enqueue(message); + } + + public void EnqueueAction(Action action) + { + this.Enqueue(new ActionMessage(action)); + } + + public void Listen() + { + lock (_queue) + { + // Start dequeuing. + while (_queue.Count > 0) + { + Message message = _queue.Dequeue(); + + // Look for receivers. + lock (_listeners) + { + foreach (MessageQueueListener listener in _listeners) + { + // If this listener is of the right type, execute the callback. + if (listener.Type.IsInstanceOfType(message)) + listener.Callback(message); + } + } + } + } + } + + public void RemoveListener(MessageQueueListener listener) + { + lock (_listeners) + _listeners.Remove(listener); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Messaging/MessageQueueListener.cs b/branches/ph-plugins/ProcessHacker.Common/Messaging/MessageQueueListener.cs new file mode 100644 index 000000000..b63b72ee0 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Messaging/MessageQueueListener.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Common.Messaging +{ + public delegate void MessageReceivedDelegate(Message message); + + public class MessageQueueListener + { + private MessageReceivedDelegate _callback; + private Type _type; + + public MessageQueueListener(MessageReceivedDelegate callback, Type type) + { + _callback = callback; + _type = type; + } + + public MessageReceivedDelegate Callback + { + get { return _callback; } + } + + public Type Type + { + get { return _type; } + } + } + + public class MessageQueueListener : MessageQueueListener + where T : Message + { + public delegate void MessageReceivedDelegate(T message); + + public MessageQueueListener(MessageReceivedDelegate callback) + : base((message) => callback((T)message), typeof(T)) + { } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Objects/BaseObject.cs b/branches/ph-plugins/ProcessHacker.Common/Objects/BaseObject.cs new file mode 100644 index 000000000..2770fcbd2 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Objects/BaseObject.cs @@ -0,0 +1,504 @@ +/* + * Process Hacker - + * disposable object base functionality + * + * Copyright (C) 2009 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 . + */ + +#define ENABLE_STATISTICS +//#define EXTENDED_FINALIZER + +using System; +using System.ComponentModel; +using System.Threading; + +namespace ProcessHacker.Common.Objects +{ + /// + /// Provides methods for managing a disposable object or resource. + /// + /// + /// + /// Each disposable object starts with a reference count of one + /// when it is created. The object is not owned by the creator; + /// rather, it is owned by the GC (garbage collector). If the user + /// does not dispose the object, the finalizer will be called by + /// the GC, the reference count will be decremented and the object + /// will be freed. If the user chooses to call Dispose, the reference + /// count will be decremented and the object will be freed. The + /// object is no longer owned by the GC and the finalizer will be + /// suppressed. Any further calls to Dispose will have no effect. + /// + /// + /// If the user chooses to use reference counting, the object + /// functions normally with the GC. If the object's reference count + /// is incremented after it is created and becomes 2, it will be + /// decremented when it is finalized or disposed. Only after the + /// object is dereferenced will the reference count become 0 and + /// the object will be freed. + /// + /// + public abstract class BaseObject : IDisposable, IRefCounted + { + private static int _createdCount = 0; + private static int _freedCount = 0; + private static int _disposedCount = 0; + private static int _finalizedCount = 0; + private static int _referencedCount = 0; + private static int _dereferencedCount = 0; + + /// + /// Gets the number of disposable objects that have been created. + /// + public static int CreatedCount { get { return _createdCount; } } + /// + /// Gets the number of disposable objects that have been freed. + /// + public static int FreedCount { get { return _freedCount; } } + /// + /// Gets the number of disposable objects that have been Disposed with managed = true. + /// + public static int DisposedCount { get { return _disposedCount; } } + /// + /// Gets the number of disposable objects that have been Disposed with managed = false. + /// + public static int FinalizedCount { get { return _finalizedCount; } } + /// + /// Gets the number of times disposable objects have been referenced. + /// + public static int ReferencedCount { get { return _referencedCount; } } + /// + /// Gets the number of times disposable objects have been dereferenced. + /// + public static int DereferencedCount { get { return _dereferencedCount; } } + + public static T SwapRef(ref T reference, T newObj) + where T : class, IRefCounted + { + T oldObj; + + // Swap the reference. + oldObj = Interlocked.Exchange(ref reference, newObj); + // Reference the new object. + if (newObj != null) + newObj.Reference(); + // Dereference the old object. + if (oldObj != null) + oldObj.Dereference(); + + return oldObj; + } + +#if DEBUG + /// + /// A stack trace collected when the object is created. + /// + private string _creationStackTrace; +#endif + /// + /// Whether the object is owned (rather, whether this class should + /// take care of anything). + /// + private bool _owned = true; + /// + /// Whether the object is owned by the garbage collector (to ensure + /// calling Dispose more than once has no effect). + /// + private int _ownedByGc = 1; + /// + /// The reference count of the object. + /// + private int _refCount = 1; + /// + /// Whether the object has been freed. + /// + private volatile bool _disposed = false; +#if EXTENDED_FINALIZER + /// + /// Whether the finalizer will run. + /// + private int _finalizerRegistered = 1; +#endif + + /// + /// Initializes a disposable object. + /// + public BaseObject() + : this(true) + { } + + /// + /// Initializes a disposable object. + /// + /// Whether the resource is owned. + public BaseObject(bool owned) + { + _owned = owned; + + // Don't need to finalize the object if it doesn't need to be disposed. + if (!_owned) + { +#if EXTENDED_FINALIZER + this.DisableFinalizer(); +#else + GC.SuppressFinalize(this); +#endif + _ownedByGc = 0; + _refCount = 0; + } + +#if ENABLE_STATISTICS + Interlocked.Increment(ref _createdCount); +#endif + +#if DEBUG + _creationStackTrace = Environment.StackTrace; +#endif + } + + /// + /// Ensures that the GC does not own the object. + /// + ~BaseObject() + { + // Get rid of GC ownership if still present. + this.Dispose(false); + +#if ENABLE_STATISTICS + Interlocked.Increment(ref _finalizedCount); + // Dispose just incremented this value, but it + // shouldn't have been incremented. + Interlocked.Decrement(ref _disposedCount); +#endif + } + + /// + /// Ensures that the GC does not own the object. + /// + public void Dispose() + { + this.Dispose(true); + } + + /// + /// Ensures that the GC does not own the object. + /// + /// Whether to dispose managed resources. + public void Dispose(bool managed) + { + if (!_owned) + return; + + Thread.BeginCriticalRegion(); + + try + { + int oldOwnedByGc; + + // Only proceed if the object is owned by the GC. We can perform + // this operation without any locks by using CAS. + oldOwnedByGc = Interlocked.CompareExchange(ref _ownedByGc, 0, 1); + + if (oldOwnedByGc == 1) + { + // Decrement the reference count. + this.Dereference(managed); + + // Disable the finalizer. + if (managed) + { +#if EXTENDED_FINALIZER + this.DisableFinalizer(); +#else + GC.SuppressFinalize(this); +#endif + } + +#if ENABLE_STATISTICS + // Stats. + Interlocked.Increment(ref _disposedCount); + + // The dereferenced count should count the number of times + // the user has called Dereference, so decrement it + // because we just called it. + Interlocked.Decrement(ref _dereferencedCount); +#endif + } + } + finally + { + Thread.EndCriticalRegion(); + } + } + + /// + /// Queues the object for disposal in the current delayed release pool. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void DisposeDelayed() + { + DelayedReleasePool.CurrentPool.AddDispose(this); + } + + /// + /// Disposes the resources of the object. This method must not be + /// called directly; instead, override this method in a derived class. + /// + /// Whether or not to dispose managed objects. + protected abstract void DisposeObject(bool disposing); + + /// + /// Gets whether the object has been freed. + /// + public bool Disposed + { + get { return _disposed; } + } + + /// + /// Gets whether the object will be freed. + /// + public bool Owned + { + get { return _owned; } + } + + /// + /// Gets whether the object is owned by the garbage collector. + /// + public bool OwnedByGc + { + get { return _ownedByGc == 1; } + } + + /// + /// Gets the current reference count of the object. + /// + /// + /// This information is for debugging purposes ONLY. DO NOT + /// base memory management logic upon this value. + /// + public int ReferenceCount + { + get { return Thread.VolatileRead(ref _refCount); } + } + +#if EXTENDED_FINALIZER + /// + /// Disables the finalizer if it is not already disabled. + /// + private void DisableFinalizer() + { + int oldFinalizerRegistered; + + oldFinalizerRegistered = Interlocked.CompareExchange(ref _finalizerRegistered, 0, 1); + + if (oldFinalizerRegistered == 1) + { + GC.SuppressFinalize(this); + } + } +#endif + + /// + /// Declares that the object should no longer be owned. + /// + protected void DisableOwnership(bool dispose) + { + if (dispose) + this.Dispose(); + +#if EXTENDED_FINALIZER + this.DisableFinalizer(); +#else + GC.SuppressFinalize(this); +#endif + _owned = false; + +#if ENABLE_STATISTICS + // If the object didn't get disposed, pretend the object + // never got created. + if (!dispose) + Interlocked.Decrement(ref _createdCount); +#endif + } + + /// + /// Decrements the reference count of the object. + /// + /// The old reference count. + /// + /// + /// DO NOT call Dereference if you have not called Reference. + /// Call Dispose instead. + /// + /// + /// If you are calling Dereference from a finalizer, call + /// Dereference(false). + /// + /// + public int Dereference() + { + return this.Dereference(true); + } + + /// + /// Decrements the reference count of the object. + /// + /// Whether to dispose managed resources. + /// The new reference count. + /// + /// If you are calling this method from a finalizer, set + /// to false. + /// + public int Dereference(bool managed) + { + return this.Dereference(1, managed); + } + + /// + /// Decreases the reference count of the object. + /// + /// The number of times to dereference the object. + /// The new reference count. + public int Dereference(int count) + { + return this.Dereference(count, true); + } + + /// + /// Decreases the reference count of the object. + /// + /// The number of times to dereference the object. + /// Whether to dispose managed resources. + /// The new reference count. + public int Dereference(int count, bool managed) + { + // Initial parameter validation. + if (count == 0) + return Interlocked.Add(ref _refCount, 0); + if (count < 0) + throw new ArgumentException("Cannot dereference a negative number of times."); + + // Critical, prevent thread abortion. + Thread.BeginCriticalRegion(); + + try + { + if (!_owned) + return 0; + +#if ENABLE_STATISTICS + // Statistics. + Interlocked.Add(ref _dereferencedCount, count); +#endif + + // Decrease the reference count. + int newRefCount = Interlocked.Add(ref _refCount, -count); + + // Should not ever happen. + if (newRefCount < 0) + throw new InvalidOperationException("Reference count cannot be negative."); + + // Dispose the object if the reference count is 0. + if (newRefCount == 0 && !_disposed) + { + // If the dispose object method throws an exception, nothing bad + // should happen if it does not invalidate any state. + this.DisposeObject(managed); + // Prevent the object from being disposed twice. + _disposed = true; + +#if ENABLE_STATISTICS + Interlocked.Increment(ref _freedCount); +#endif + } + + return newRefCount; + } + finally + { + Thread.EndCriticalRegion(); + } + } + + /// + /// Queues the object for dereferencing in the current delayed release pool. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public void DereferenceDelayed() + { + DelayedReleasePool.CurrentPool.AddDereference(this); + } + +#if EXTENDED_FINALIZER + /// + /// Enables the finalizer if it is not already enabled. + /// + private void EnableFinalizer() + { + int oldFinalizerRegistered; + + oldFinalizerRegistered = Interlocked.CompareExchange(ref _finalizerRegistered, 1, 0); + + if (oldFinalizerRegistered == 0) + { + GC.ReRegisterForFinalize(this); + } + } +#endif + + /// + /// Increments the reference count of the object. + /// + /// The new reference count. + /// + /// + /// You must call Dereference once (when you are finished with the + /// object) to match each call to Reference. Do not call Dispose. + /// + /// + public int Reference() + { + return this.Reference(1); + } + + /// + /// Increases the reference count of the object. + /// + /// The number of times to reference the object. + /// The new reference count. + public int Reference(int count) + { + // Don't do anything if the object isn't owned. + if (!_owned) + return 0; + // Parameter validation. + if (count == 0) + return Interlocked.Add(ref _refCount, 0); + if (count < 0) + throw new ArgumentException("Cannot reference a negative number of times."); + +#if ENABLE_STATISTICS + Interlocked.Add(ref _referencedCount, count); +#endif + + return Interlocked.Add(ref _refCount, count); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Objects/DelayedReleasePool.cs b/branches/ph-plugins/ProcessHacker.Common/Objects/DelayedReleasePool.cs new file mode 100644 index 000000000..b240d38c9 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Objects/DelayedReleasePool.cs @@ -0,0 +1,209 @@ +/* + * Process Hacker - + * delayed release pool + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Threading; + +namespace ProcessHacker.Common.Objects +{ + /// + /// Indicates that an operation was performed out-of-order. + /// + public class OutOfOrderException : Exception + { + public OutOfOrderException(string message) + : base(message) + { } + } + + /// + /// Represents a pool of objects to be disposed or dereferenced at some point. + /// + public sealed class DelayedReleasePool : BaseObject + { + /// + /// Describes how an object should be disposed. + /// + [Flags] + private enum DelayedReleaseFlags + { + Dispose = 0x1, + Dereference = 0x2 + } + + /// + /// Describes an object that is to be disposed. + /// + private struct DelayedReleaseObject + { + private DelayedReleaseFlags _flags; + private BaseObject _object; + + public DelayedReleaseObject(DelayedReleaseFlags flags, BaseObject obj) + { + _flags = flags; + _object = obj; + } + + public DelayedReleaseFlags Flags + { + get { return _flags; } + } + + public BaseObject Object + { + get { return _object; } + } + } + + [ThreadStatic] + private static Stack _poolStack; + [ThreadStatic] + private static DelayedReleasePool _currentPool; + + /// + /// Gets the currently active delayed release pool. + /// + public static DelayedReleasePool CurrentPool + { + get + { + if (_currentPool == null) + _currentPool = new DelayedReleasePool(); + + return _currentPool; + } + private set { _currentPool = value; } + } + + /// + /// Gets the stack of delayed release pools. + /// + private static Stack PoolStack + { + get + { + // No locking needed because the stack is thread-local. + if (_poolStack == null) + _poolStack = new Stack(); + + return _poolStack; + } + } + + /// + /// Restores an older delayed release pool from the pool stack. + /// + /// The current delayed release pool. + private static void PopPool(DelayedReleasePool pool) + { + if (_currentPool != pool) + throw new OutOfOrderException( + "Attempted to pop a pool when it wasn't on top of the stack. " + + "This usually indicates that a pool was popped out-of-order." + ); + + _currentPool = PoolStack.Pop(); + } + + /// + /// Sets the specified delayed release pool as the currently active pool. + /// + /// The pool to set. + private static void PushPool(DelayedReleasePool pool) + { + PoolStack.Push(_currentPool); + _currentPool = pool; + } + + private int _creatorThreadId; + private List _objects = new List(); + + /// + /// Creates a delayed release pool and sets it as the currently active pool. + /// + public DelayedReleasePool() + { + _creatorThreadId = Thread.CurrentThread.ManagedThreadId; + PushPool(this); + } + + protected override void DisposeObject(bool disposing) + { + // Only pop the pool if we're on the same thread as the + // creator thread. This either means that the thread has + // died, or the user forgot to pop the pool by calling + // Dispose. If they forgot, it's not our problem... + if ( + disposing && + _creatorThreadId == Thread.CurrentThread.ManagedThreadId + ) + PopPool(this); + + this.Drain(disposing); + } + + /// + /// Adds the specified object for dereferencing. + /// + /// The object to dereference. + public void AddDereference(BaseObject obj) + { + _objects.Add(new DelayedReleaseObject(DelayedReleaseFlags.Dereference, obj)); + } + + /// + /// Adds the specified object for disposal. + /// + /// The object to dispose. + public void AddDispose(BaseObject obj) + { + _objects.Add(new DelayedReleaseObject(DelayedReleaseFlags.Dispose, obj)); + } + + /// + /// Releases all objects in the pool. + /// + public void Drain() + { + this.Drain(true); + } + + /// + /// Releases all objects in the pool. + /// + /// Whether to release managed resources. + public void Drain(bool managed) + { + foreach (var obj in _objects) + { + if ((obj.Flags & DelayedReleaseFlags.Dispose) == DelayedReleaseFlags.Dispose) + obj.Object.Dispose(); + if ((obj.Flags & DelayedReleaseFlags.Dereference) == DelayedReleaseFlags.Dereference) + obj.Object.Dereference(managed); + } + + _objects.Clear(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Objects/HandleTable.cs b/branches/ph-plugins/ProcessHacker.Common/Objects/HandleTable.cs new file mode 100644 index 000000000..680420697 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Objects/HandleTable.cs @@ -0,0 +1,301 @@ +/* + * Process Hacker - + * handle table + * + * Copyright (C) 2009 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 . + */ + +using System.Collections.Generic; + +namespace ProcessHacker.Common.Objects +{ + public class HandleTableEntry + { + private int _handle; + private IRefCounted _object; + + public int Handle + { + get { return _handle; } + internal set { _handle = value; } + } + + public IRefCounted Object + { + get { return _object; } + internal set { _object = value; } + } + } + + /// + /// Provides methods for managing handles to objects. + /// + public class HandleTable : HandleTable + { } + + /// + /// Provides methods for managing handles to objects. + /// + /// The type of each handle table entry. + public class HandleTable : BaseObject + where TEntry : HandleTableEntry, new() + { + /// + /// Represents a callback function for handle table enumeration. + /// + /// The current handle. + /// The current object. + /// Return true to stop enumerating; otherwise return false. + public delegate bool EnumerateHandleTableDelegate(int handle, TEntry entry); + + private IdGenerator _handleGenerator = new IdGenerator(4, 4); + private Dictionary _handles = + new Dictionary(); + + protected override void DisposeObject(bool disposing) + { + lock (_handles) + { + foreach (var entry in _handles.Values) + entry.Object.Dereference(disposing); + } + } + + /// + /// Creates a handle to the specified object. + /// + /// The object to reference. + /// The new handle. + public int Allocate(IRefCounted obj) + { + TEntry entry = new TEntry(); + + return this.Allocate(obj, entry); + } + + /// + /// Creates a handle to the specified object. + /// + /// The object to reference. + /// The handle table entry to use. + /// The new handle. + public int Allocate(IRefCounted obj, TEntry entry) + { + int handle = _handleGenerator.Pop(); + + // Reference the object so it does not get freed while + // it is stored in the handle table. + obj.Reference(); + // GC should not own the object. + obj.Dispose(); + // Initialize the entry. + entry.Handle = handle; + entry.Object = obj; + + // Add the handle entry. + lock (_handles) + { + _handles.Add(handle, entry); + } + + return handle; + } + + /// + /// Enumerates the handles in the handle table. + /// + /// The callback for the enumeration. + /// Whether the enumeration was stopped by the callback. + public bool Enumerate(EnumerateHandleTableDelegate callback) + { + lock (_handles) + { + foreach (var entry in _handles.Values) + { + if (callback(entry.Handle, entry)) + return true; + } + + return false; + } + } + + /// + /// Closes a handle. + /// + /// The handle to close. + /// Whether the handle was closed. + public bool Free(int handle) + { + IRefCounted obj; + + lock (_handles) + { + if (!_handles.ContainsKey(handle)) + return false; + + // Store the object reference for dereferencing later. + obj = _handles[handle].Object; + // Remove the handle so it can no longer be used. + _handles.Remove(handle); + } + + // Make the handle value available. + _handleGenerator.Push(handle); + // Dereference the object (this doesn't need to be in the locking block). + obj.Dereference(); + + return true; + } + + /// + /// Gets the handle table entry for a handle. + /// + /// The handle to lookup. + /// A handle table entry. + public TEntry LookupEntry(int handle) + { + lock (_handles) + { + if (_handles.ContainsKey(handle)) + return _handles[handle]; + else + return null; + } + } + + /// + /// Gets the object referenced by a handle. + /// + /// The handle to lookup. + /// + /// An object. This object has not been referenced and is + /// not guaranteed to be valid. + /// + public IRefCounted LookupObject(int handle) + { + return this.LookupEntry(handle).Object; + } + + /// + /// Gets the object referenced by a handle. + /// + /// The type of the object to retrieve. + /// The handle to lookup. + /// + /// An object. This object has not been referenced and is + /// not guaranteed to be valid. + /// + public T LookupObject(int handle) + where T : class, IRefCounted + { + return this.LookupObject(handle) as T; + } + + /// + /// References an object using a handle. + /// + /// The handle to lookup. + /// + /// An object. This object has been referenced and must be + /// dereferenced once it is no longer needed. + /// + public IRefCounted ReferenceByHandle(int handle) + { + TEntry entry; + return this.ReferenceByHandle(handle, out entry); + } + + /// + /// References an object using a handle. + /// + /// The handle to lookup. + /// The handle table entry. + /// + /// An object. This object has been referenced and must be + /// dereferenced once it is no longer needed. + /// + public IRefCounted ReferenceByHandle(int handle, out TEntry entry) + { + lock (_handles) + { + if (_handles.ContainsKey(handle)) + { + IRefCounted obj = _handles[handle].Object; + + obj.Reference(); + entry = _handles[handle]; + + return obj; + } + else + { + entry = null; + return null; + } + } + } + + /// + /// References an object using a handle. + /// + /// The type of the object to reference. + /// The handle to lookup. + /// + /// An object. This object has been referenced and must be + /// dereferenced once it is no longer needed. + /// + public T ReferenceByHandle(int handle) + where T : class, IRefCounted + { + TEntry entry; + return this.ReferenceByHandle(handle, out entry); + } + + /// + /// References an object using a handle. + /// + /// The type of the object to reference. + /// The handle to lookup. + /// The handle table entry. + /// + /// An object. This object has been referenced and must be + /// dereferenced once it is no longer needed. + /// + public T ReferenceByHandle(int handle, out TEntry entry) + where T : class, IRefCounted + { + IRefCounted obj = this.ReferenceByHandle(handle, out entry); + + if (obj == null) + return null; + + // Check the type. + if (obj is T) + { + return (T)obj; + } + else + { + // Wrong type. Dereference and return. + obj.Dereference(); + return null; + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Objects/IRefCounted.cs b/branches/ph-plugins/ProcessHacker.Common/Objects/IRefCounted.cs new file mode 100644 index 000000000..cbb37b004 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Objects/IRefCounted.cs @@ -0,0 +1,55 @@ +using System; + +namespace ProcessHacker.Common.Objects +{ + public interface IRefCounted : IDisposable + { + /// + /// Decrements the reference count of the object. + /// + /// The new reference count. + int Dereference(); + + /// + /// Decrements the reference count of the object. + /// + /// Whether to dispose managed resources. + /// The new reference count. + int Dereference(bool managed); + + /// + /// Decreases the reference count of the object. + /// + /// The number of times to dereference the object. + /// The new reference count. + int Dereference(int count); + + /// + /// Decreases the reference count of the object. + /// + /// The number of times to dereference the object. + /// Whether to dispose managed resources. + /// The new reference count. + int Dereference(int count, bool managed); + + /// + /// Ensures that the reference counting system has exclusive control + /// over the lifetime of the object. + /// + /// Whether to dispose managed resources. + void Dispose(bool managed); + + /// + /// Increments the reference count of the object. + /// + /// The new reference count. + int Reference(); + + /// + /// Increases the reference count of the object. + /// + /// The number of times to reference the object. + /// The new reference count. + int Reference(int count); + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Objects/SecuredHandleTable.cs b/branches/ph-plugins/ProcessHacker.Common/Objects/SecuredHandleTable.cs new file mode 100644 index 000000000..77dd24b2c --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Objects/SecuredHandleTable.cs @@ -0,0 +1,202 @@ +/* + * Process Hacker - + * secured handle table + * + * Copyright (C) 2009 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 . + */ + +using System; + +namespace ProcessHacker.Common.Objects +{ + public class SecuredHandleTableEntry : HandleTableEntry + { + private long _grantedAccess; + + public long GrantedAccess + { + get { return _grantedAccess; } + set { _grantedAccess = value; } + } + + public bool AreAllAccessesGranted(TAccess access) + where TAccess : struct + { + long accessLong = Convert.ToInt64(access); + + if ((_grantedAccess & accessLong) == accessLong) + return true; + else + return false; + } + + public bool AreAnyAccessesGranted(TAccess access) + where TAccess : struct + { + long accessLong = Convert.ToInt64(access); + + if ((_grantedAccess & accessLong) != 0) + return true; + else + return false; + } + } + + /// + /// Provides methods for managing handles to objects securely. + /// + public class SecuredHandleTable : SecuredHandleTable + { } + + /// + /// Provides methods for managing handles to objects securely. + /// + /// The type of each handle table entry. + public class SecuredHandleTable : HandleTable + where TEntry : SecuredHandleTableEntry, new() + { + /// + /// Creates a handle to an object with the specified granted access. + /// + /// The type of access mask. + /// The object to reference. + /// The granted access to the object. + /// The new handle. + public int Allocate(IRefCounted obj, TAccess grantedAccess) + where TAccess : struct + { + TEntry entry = new TEntry(); + + entry.GrantedAccess = Convert.ToInt64(grantedAccess); + + return base.Allocate(obj, entry); + } + + /// + /// References an object using a handle. + /// + /// The type of access mask. + /// The handle to lookup. + /// The desired access to the object. + /// + /// An object. This object has been referenced and must be + /// dereferenced once it is no longer needed. + /// + public IRefCounted ReferenceByHandle(int handle, TAccess access) + where TAccess : struct + { + return this.ReferenceByHandle(handle, access, false); + } + + /// + /// References an object using a handle. + /// + /// The type of access mask. + /// The handle to lookup. + /// The desired access to the object. + /// + /// Whether an exception will be thrown if access to the object is denied. + /// + /// + /// An object. This object has been referenced and must be + /// dereferenced once it is no longer needed. + /// + public IRefCounted ReferenceByHandle(int handle, TAccess access, bool throwOnAccessDenied) + where TAccess : struct + { + TEntry entry; + IRefCounted obj; + + // Reference the object. + obj = this.ReferenceByHandle(handle, out entry); + + if (obj == null) + return null; + + // Check the access. + if (entry.AreAllAccessesGranted(access)) + { + // OK, return the object. + return obj; + } + else + { + // Access denied. Dereference the object and return. + obj.Dereference(); + + if (throwOnAccessDenied) + throw new UnauthorizedAccessException("Access denied."); + else + return null; + } + } + + /// + /// References an object using a handle. + /// + /// The type of the object to reference. + /// The type of access mask. + /// The handle to lookup. + /// The desired access to the object. + /// + /// An object. This object has been referenced and must be + /// dereferenced once it is no longer needed. + /// + public T ReferenceByHandle(int handle, TAccess access) + where T : class, IRefCounted + where TAccess : struct + { + return this.ReferenceByHandle(handle, access, false); + } + + /// + /// References an object using a handle. + /// + /// The type of the object to reference. + /// The type of access mask. + /// The handle to lookup. + /// The desired access to the object. + /// + /// Whether an exception will be thrown if access to the object is denied. + /// + /// + /// An object. This object has been referenced and must be + /// dereferenced once it is no longer needed. + /// + public T ReferenceByHandle(int handle, TAccess access, bool throwOnAccessDenied) + where T : class, IRefCounted + where TAccess : struct + { + IRefCounted obj = this.ReferenceByHandle(handle, access, throwOnAccessDenied); + + if (obj == null) + return null; + + // Check the type. + if (obj is T) + { + return (T)obj; + } + else + { + obj.Dereference(); + return null; + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/ProcessHacker.Common.csproj b/branches/ph-plugins/ProcessHacker.Common/ProcessHacker.Common.csproj new file mode 100644 index 000000000..73cc893c1 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/ProcessHacker.Common.csproj @@ -0,0 +1,129 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {8E10F5E8-D4FA-4980-BB23-2EDD134AC15E} + Library + Properties + ProcessHacker.Common + ProcessHacker.Common + v2.0 + 512 + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + + + true + AnyCPU + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + bin\Release\ProcessHacker.Common.xml + 1591 + true + AnyCPU + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker.Common/Properties/AssemblyInfo.cs b/branches/ph-plugins/ProcessHacker.Common/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..b83edceee --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Process Hacker Common Library")] +[assembly: AssemblyDescription("Process Hacker Common Library")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("wj32")] +[assembly: AssemblyProduct("Process Hacker")] +[assembly: AssemblyCopyright("Licensed under the GNU GPL, v3.")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("ab61b552-e6b9-43bb-baa0-73852d9e97ab")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.6.0.0")] +[assembly: AssemblyFileVersion("1.6.0.0")] diff --git a/branches/ph-plugins/ProcessHacker.Common/Settings/SettingDefaultAttribute.cs b/branches/ph-plugins/ProcessHacker.Common/Settings/SettingDefaultAttribute.cs new file mode 100644 index 000000000..8873cb387 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Settings/SettingDefaultAttribute.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Common.Settings +{ + public class SettingDefaultAttribute + { + private string _value; + + public SettingDefaultAttribute(string value) + { + _value = value; + } + + public string Value + { + get { return _value; } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Settings/SettingsBase.cs b/branches/ph-plugins/ProcessHacker.Common/Settings/SettingsBase.cs new file mode 100644 index 000000000..9dfe836f7 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Settings/SettingsBase.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Common.Settings +{ + public abstract class SettingsBase + { + private SettingsStore _store; + private Dictionary _settings = new Dictionary(); + + public SettingsBase(SettingsStore store) + { + _store = store; + } + + public object this[string name] + { + get { return this.GetValue(name); } + set { this.SetValue(name, value); } + } + + private object GetValue(string name) + { + return null; + } + + private void SetValue(string name, object value) + { + + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Settings/SettingsManager.cs b/branches/ph-plugins/ProcessHacker.Common/Settings/SettingsManager.cs new file mode 100644 index 000000000..f75aabf75 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Settings/SettingsManager.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Common.Settings +{ + public sealed class SettingsManager + { + private SettingsStore _store; + + public SettingsManager(SettingsStore store) + { + _store = store; + } + + public T GetProperty(string name) + { + return (T)this.GetProperty(name); + } + + public object GetProperty(string name) + { + return null; + } + + public void SetProperty(string name, T value) + { + this.SetProperty(name, value); + } + + public void SetProperty(string name, object value) + { + + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Settings/SettingsStore.cs b/branches/ph-plugins/ProcessHacker.Common/Settings/SettingsStore.cs new file mode 100644 index 000000000..ba2dbb69e --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Settings/SettingsStore.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Common.Settings +{ + public abstract class SettingsStore + { + public abstract string GetValue(string name); + public abstract void SetValue(string name, string value); + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Threading/FastMutex.cs b/branches/ph-plugins/ProcessHacker.Common/Threading/FastMutex.cs new file mode 100644 index 000000000..5a83cc3c3 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Threading/FastMutex.cs @@ -0,0 +1,92 @@ +using System; +using System.Threading; + +namespace ProcessHacker.Common.Threading +{ + /// + /// Provides methods for synchronizing access to a shared resource. + /// + /// Just a wrapper around Monitor (minus the event methods + /// like Pulse and Wait). + public sealed class FastMutex + { + /// + /// Represents a context for mutex acquisition. + /// + public struct FastMutexContext : IDisposable + { + private bool _disposed; + private FastMutex _fastMutex; + + internal FastMutexContext(FastMutex fastMutex) + { + _fastMutex = fastMutex; + _disposed = false; + } + + /// + /// Releases the mutex. + /// + public void Dispose() + { + if (!_disposed) + { + _fastMutex.Release(); + _disposed = true; + } + } + } + + private object _lock = new object(); + + /// + /// Acquires the mutex and prevents others from acquiring it. + /// If the mutex is already acquired, the function will block + /// until it can acquire the mutex. + /// + public void Acquire() + { + Monitor.Enter(_lock); + } + + /// + /// Acquires the mutex and returns a context object which + /// must be disposed to release the mutex. + /// + /// The context object. + public FastMutexContext AcquireContext() + { + this.Acquire(); + return new FastMutexContext(this); + } + + /// + /// Releases the mutex and allows others to acquire the mutex. + /// + public void Release() + { + Monitor.Exit(_lock); + } + + /// + /// Attempts to acquire the mutex and returns immediately + /// regardless of whether the mutex was acquired. + /// + /// Whether or not the mutex was acquired. + public bool TryAcquire() + { + return Monitor.TryEnter(_lock); + } + + /// + /// Attempts to acquire the mutex and returns after a + /// timeout period if the mutex could not be acquired. + /// + /// The timeout, in milliseconds. + /// Whether or not the mutex was acquired. + public bool TryAcquire(int millisecondsTimeout) + { + return Monitor.TryEnter(_lock, millisecondsTimeout); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Threading/FastQueue.cs b/branches/ph-plugins/ProcessHacker.Common/Threading/FastQueue.cs new file mode 100644 index 000000000..5abe5a482 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Threading/FastQueue.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace ProcessHacker.Common.Threading +{ + public class FastQueue : IEnumerable + { + private class FastQueueNode + { + public U Value; + public FastQueueNode Next; + } + + private int _count = 0; + // The head node. The next pointer of the head node always points + // to the least recently added node - the node to dequeue first. + private FastQueueNode _head; + // The tail node. This is always the most recently added node. + private FastQueueNode _tail; + // Note: all next pointers point to less recently added nodes (i.e. + // the next node to dequeue). + + public FastQueue() + { + _head = new FastQueueNode(); + _tail = _head; + _tail.Next = null; + } + + public int Count + { + get { return _count; } + } + + public T Dequeue() + { + throw new NotImplementedException(); + } + + public void Enqueue(T value) + { + throw new NotImplementedException(); + + //FastQueueNode tail; + //FastQueueNode tailNext; + //FastQueueNode node; + + //// Create a new queue node. + //node = new FastQueueNode(); + //node.Value = value; + //node.Next = null; + + //// Add the node to the tail of the list, atomically. + //// We have to set the next pointer of the current tail node + //// and then replace the tail pointer with our new node. + //while (true) + //{ + // tailNext = _tail.Next; + + // while (true) + // { + // tail = _tail; + // } + //} + } + + public IEnumerator GetEnumerator() + { + return null; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)this).GetEnumerator(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Threading/FastStack.cs b/branches/ph-plugins/ProcessHacker.Common/Threading/FastStack.cs new file mode 100644 index 000000000..42fd55a71 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Threading/FastStack.cs @@ -0,0 +1,109 @@ +using System.Collections; +using System.Collections.Generic; +using System.Threading; +using System; + +namespace ProcessHacker.Common.Threading +{ + public class FastStack : IEnumerable + { + private class FastStackNode + { + public U Value; + public FastStackNode Next; + } + + private int _count = 0; + private FastStackNode _bottom = null; + + public int Count + { + get { return _count; } + } + + public T Peek() + { + FastStackNode bottom; + + bottom = _bottom; + + if (bottom == null) + throw new InvalidOperationException("The stack is empty."); + + return bottom.Value; + } + + public T Pop() + { + FastStackNode bottom; + + // Atomically replace the bottom of the stack. + while (true) + { + bottom = _bottom; + + // If the bottom of the stack is null, the + // stack is empty. + if (bottom == null) + throw new InvalidOperationException("The stack is empty."); + + // Try to replace the pointer. + if (Interlocked.CompareExchange>( + ref _bottom, + bottom.Next, + bottom + ) == bottom) + { + // Success. + return bottom.Value; + } + } + } + + public void Push(T value) + { + FastStackNode bottom; + FastStackNode entry; + + entry = new FastStackNode(); + entry.Value = value; + + // Atomically replace the bottom of the stack. + while (true) + { + bottom = _bottom; + entry.Next = bottom; + + // Try to replace the pointer. + if (Interlocked.CompareExchange>( + ref _bottom, + entry, + bottom + ) == bottom) + { + // Success. + break; + } + } + } + + public IEnumerator GetEnumerator() + { + FastStackNode entry; + + entry = _bottom; + + // Start the enumeration. + while (entry != null) + { + yield return entry.Value; + entry = entry.Next; + } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IEnumerable)this).GetEnumerator(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Threading/RundownProtection.cs b/branches/ph-plugins/ProcessHacker.Common/Threading/RundownProtection.cs new file mode 100644 index 000000000..12a4f073c --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Threading/RundownProtection.cs @@ -0,0 +1,101 @@ +using System; +using System.Threading; + +namespace ProcessHacker.Common.Threading +{ + /// + /// Provides methods for managing object/resource destruction. + /// + public sealed class RundownProtection + { + private object _rundownLock = new object(); + private volatile bool _rundownActive = false; + private int _refCount = 0; + + /// + /// Attempts to acquire rundown protection. + /// + /// Whether rundown protection was acquired. + public bool Acquire() + { + Thread.BeginCriticalRegion(); + + try + { + lock (_rundownLock) + { + if (_rundownActive) + return false; + + Interlocked.Increment(ref _refCount); + + return true; + } + } + finally + { + Thread.EndCriticalRegion(); + } + } + + /// + /// Releases rundown protection. + /// + public void Release() + { + Thread.BeginCriticalRegion(); + + try + { + lock (_rundownLock) + { + int newRefCount = Interlocked.Decrement(ref _refCount); + + if (newRefCount < 0) + throw new InvalidOperationException("Reference count cannot be negative."); + + if (_rundownActive) + { + // If we are the last out, release all waiters. + if (newRefCount == 0) + Monitor.PulseAll(_rundownLock); + } + } + } + finally + { + Thread.EndCriticalRegion(); + } + } + + /// + /// Waits for all references to be released while disallowing + /// attempts to acquire rundown protection. + /// + public void Wait() + { + this.Wait(-1); + } + + /// + /// Waits for all references to be released while disallowing + /// attempts to acquire rundown protection. + /// + /// The timeout, in milliseconds. + /// Whether all references were released. + public bool Wait(int timeout) + { + lock (_rundownLock) + { + _rundownActive = true; + + // If there are no references, we can exit. + if (Thread.VolatileRead(ref _refCount) == 0) + return true; + + // Otherwise, wait for the release signal. + return Monitor.Wait(_rundownLock, timeout); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Threading/SemaphorePair.cs b/branches/ph-plugins/ProcessHacker.Common/Threading/SemaphorePair.cs new file mode 100644 index 000000000..25013a681 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Threading/SemaphorePair.cs @@ -0,0 +1,60 @@ +using System; +using System.Threading; + +namespace ProcessHacker.Common.Threading +{ + public class SemaphorePair : IDisposable + { + private int _count; + private Semaphore _readSemaphore; + private Semaphore _writeSemaphore; + + public SemaphorePair(int count) + { + _count = count; + _readSemaphore = new Semaphore(0, count); + _writeSemaphore = new Semaphore(count, count); + } + + public int Count + { + get { return _count; } + } + + public void Dispose() + { + _readSemaphore.Close(); + _writeSemaphore.Close(); + } + + public void ReleaseRead() + { + _readSemaphore.Release(); + } + + public void ReleaseWrite() + { + _writeSemaphore.Release(); + } + + public void WaitRead() + { + _readSemaphore.WaitOne(); + } + + public bool WaitRead(int timeout) + { + return _readSemaphore.WaitOne(timeout, false); + } + + public void WaitWrite() + { + _writeSemaphore.WaitOne(); + } + + public bool WaitWrite(int timeout) + { + return _writeSemaphore.WaitOne(timeout, false); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Threading/SpinLock.cs b/branches/ph-plugins/ProcessHacker.Common/Threading/SpinLock.cs new file mode 100644 index 000000000..b75e2d836 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Threading/SpinLock.cs @@ -0,0 +1,115 @@ +/* + * Process Hacker - + * spinlock + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Threading; + +namespace ProcessHacker.Common.Threading +{ + /// + /// Represents a spinlock, a high-performance mutual exclusion lock. + /// + public sealed class SpinLock + { + public struct SpinLockContext : IDisposable + { + private bool _disposed; + private SpinLock _spinLock; + + internal SpinLockContext(SpinLock spinLock) + { + _spinLock = spinLock; + _spinLock.Acquire(); + _disposed = false; + } + + public void Dispose() + { + if (!_disposed) + { + _spinLock.Release(); + _disposed = true; + } + } + } + + private int _value = 0; + private bool _spin; + private int _acquireCount = 0; + private int _spinCount = 0; + + /// + /// Creates a spinlock. + /// + public SpinLock() + { + // We don't want to spin on uniprocessor systems. + if (Environment.ProcessorCount == 1) + _spin = false; + else + _spin = true; + } + + /// + /// Acquires the spinlock. + /// + public void Acquire() + { + Thread.BeginCriticalRegion(); + + Interlocked.Increment(ref _acquireCount); + + if (_spin) + { + while (Interlocked.CompareExchange(ref _value, 1, 0) == 1) + Thread.SpinWait((_spinCount++ % Thread.VolatileRead(ref _acquireCount)) + 1); + } + else + { + while (Interlocked.CompareExchange(ref _value, 1, 0) == 1) + Thread.Sleep(0); + } + + Thread.EndCriticalRegion(); + } + + /// + /// Acquires the spinlock using a context object. + /// + /// A disposable context object. + public SpinLockContext AcquireContext() + { + return new SpinLockContext(this); + } + + /// + /// Releases the spinlock. + /// + public void Release() + { + Thread.BeginCriticalRegion(); + Interlocked.Exchange(ref _value, 0); + Interlocked.Decrement(ref _acquireCount); + Thread.EndCriticalRegion(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Threading/ThreadTask.cs b/branches/ph-plugins/ProcessHacker.Common/Threading/ThreadTask.cs new file mode 100644 index 000000000..7c06d6c3b --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Threading/ThreadTask.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace ProcessHacker.Common.Threading +{ + public delegate void ThreadTaskCompletedDelegate(object result); + public delegate void ThreadTaskRunTaskDelegate(object param, ref object result); + + public sealed class ThreadTask + { + public event ThreadTaskCompletedDelegate Completed; + public event ThreadTaskRunTaskDelegate RunTask; + + private Thread _thread = null; + private object _result; + private Exception _exception; + private bool _cancelled = false; + private bool _running = false; + + public bool Cancelled + { + get { return _cancelled; } + } + + public Exception Exception + { + get { return _exception; } + } + + public object Result + { + get { return _result; } + } + + public bool Running + { + get { return _running; } + } + + public void Cancel() + { + _cancelled = true; + } + + public void Start() + { + this.Start(null); + } + + public void Start(object param) + { + if (_thread != null) + throw new InvalidOperationException("The task has already been started."); + + _thread = new Thread(this.ThreadStart); + _thread.IsBackground = true; + _thread.Start(param); + } + + private void ThreadStart(object param) + { + _cancelled = false; + _running = true; + + try + { + if (this.RunTask != null) + this.RunTask(param, ref _result); + } + catch (Exception ex) + { + _exception = ex; + } + + if (!_cancelled && this.Completed != null) + this.Completed(_result); + + _running = false; + _thread = null; + } + + public void Wait() + { + _thread.Join(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Threading/WaitableQueue.cs b/branches/ph-plugins/ProcessHacker.Common/Threading/WaitableQueue.cs new file mode 100644 index 000000000..fef78eb7e --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Threading/WaitableQueue.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace ProcessHacker.Common.Threading +{ + public class WaitableQueue : IEnumerable, IEnumerable + { + private Queue _queue = new Queue(); + private SemaphorePair _pair; + + public WaitableQueue() + : this(int.MaxValue) + { } + + public WaitableQueue(int maximumCount) + { + _pair = new SemaphorePair(maximumCount); + } + + public int Count + { + get { return _queue.Count; } + } + + public void Clear() + { + lock (_queue) + _queue.Clear(); + } + + public bool Contains(T item) + { + lock (_queue) + return _queue.Contains(item); + } + + public T Dequeue() + { + // Wait for an item to dequeue. + _pair.WaitRead(); + // Release a slot. + _pair.ReleaseWrite(); + + lock (_queue) + return _queue.Dequeue(); + } + + public bool Dequeue(int timeout, out T item) + { + bool waitResult = true; + + // Wait for an item to dequeue. + waitResult = _pair.WaitRead(timeout); + + // Dequeue an item if we waited successfully, + // otherwise pass the default value back. + if (waitResult) + { + lock (_queue) + item = _queue.Dequeue(); + + // We just dequeued an item, so we can + // release a slot. + _pair.ReleaseWrite(); + } + else + { + item = default(T); + } + + return waitResult; + } + + public void Enqueue(T item) + { + // Make sure we have an available slot. + _pair.WaitWrite(); + + // Enqueue the item. + lock (_queue) + _queue.Enqueue(item); + + // Unwait one dequeuer. + _pair.ReleaseRead(); + } + + public IEnumerator GetEnumerator() + { + return _queue.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return _queue.GetEnumerator(); + } + + public T[] ToArray() + { + lock (_queue) + return _queue.ToArray(); + } + + public void TrimExcess() + { + lock (_queue) + _queue.TrimExcess(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Tokenizer.cs b/branches/ph-plugins/ProcessHacker.Common/Tokenizer.cs new file mode 100644 index 000000000..5847eafb6 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Tokenizer.cs @@ -0,0 +1,237 @@ +using System; +using System.Text; + +namespace ProcessHacker.Common +{ + public class Tokenizer + { + private string _text; + private int _i = 0; + + public Tokenizer(string text) + { + _text = text; + } + + public int Index + { + get { return _i; } + set { _i = value; } + } + + public string EatId() + { + StringBuilder sb = new StringBuilder(); + + while (_i < _text.Length) + { + // identifiers can't start with a number- + if (sb.Length == 0) + { + if (!(char.IsLetter(_text[_i]) || _text[_i] == '_')) + break; + } + else + { + if (!(char.IsLetterOrDigit(_text[_i]) || _text[_i] == '_')) + break; + } + + sb.Append(_text[_i]); + _i++; + } + + return sb.ToString(); + } + + public string EatNumber() + { + StringBuilder sb = new StringBuilder(); + + while (_i < _text.Length) + { + // allow hex numbers and floating-point numbers + if (sb.Length == 1 && sb[0] == '0') + { + if (!char.IsDigit(_text[_i]) && char.ToLower(_text[_i]) != 'x' && _text[_i] != '.') + break; + } + else if (sb.Length >= 2 && sb[0] == '0' && char.ToLower(sb[1]) == 'x') + { + if (!(char.IsDigit(_text[_i]) || + char.ToLower(_text[_i]) == 'a' || + char.ToLower(_text[_i]) == 'b' || + char.ToLower(_text[_i]) == 'c' || + char.ToLower(_text[_i]) == 'd' || + char.ToLower(_text[_i]) == 'e' || + char.ToLower(_text[_i]) == 'f')) + break; + } + else + { + if (!char.IsDigit(_text[_i])) + break; + } + + sb.Append(_text[_i]); + _i++; + } + + return sb.ToString(); + } + + public string EatQuotedString() + { + StringBuilder sb = new StringBuilder(); + bool inEscape = false; + + if (_text[_i] == '"') + { + _i++; + } + else + return ""; + + while (_i < _text.Length) + { + if (_text[_i] == '\\') + { + inEscape = true; + _i++; + continue; + } + else if (inEscape) + { + if (_text[_i] == '\\') + sb.Append('\\'); + else if (_text[_i] == '"') + sb.Append('"'); + else if (_text[_i] == '\'') + sb.Append('\''); + else if (_text[_i] == 'r') + sb.Append('\r'); + else if (_text[_i] == 'n') + sb.Append('\n'); + else if (_text[_i] == 't') + sb.Append('\t'); + else + throw new Exception("Unrecognized escape sequence '\\" + _text[_i] + "'"); + + _i++; + inEscape = false; + continue; + } + else if (_text[_i] == '"') + { + _i++; + break; + } + + sb.Append(_text[_i]); + _i++; + } + + return sb.ToString(); + } + + public string EatSymbol() + { + StringBuilder sb = new StringBuilder(); + + while (_i < _text.Length && sb.Length < 1) // we need a proper parser to solve this + { + char c = _text[_i]; + + if (c < ' ' || c > '~') // check if its an ASCII character + break; + if (char.IsLetterOrDigit(c) || c == '_') // check if its eligible to be an identifier + break; + + sb.Append(c); + _i++; + } + + return sb.ToString(); + } + + public string EatUntil(char c) + { + StringBuilder sb = new StringBuilder(); + + while (_text[_i] != c && _i < _text.Length) + { + sb.Append(_text[_i]); + _i++; + } + + return sb.ToString(); + } + + public bool EatWhitespace() + { + return this.EatWhitespace(false); + } + + public bool EatWhitespace(bool comments) + { + bool ranOut = true; + bool preComment = false; // '/' + bool inComment = false; // '*' + bool prePostComment = false; // '*' + + while (_i < _text.Length) + { + if (comments && inComment && _text[_i] == '*') + { + prePostComment = true; + _i++; + continue; + } + else if (comments && prePostComment && _text[_i] == '/') + { + prePostComment = false; + inComment = false; + _i++; + continue; + } + else if (comments && !inComment && _text[_i] == '/') + { + preComment = true; + _i++; + continue; + } + else if (comments && preComment) + { + if (_text[_i] == '*') + { + preComment = false; + inComment = true; + _i++; + continue; + } + else + { + // it's a mistake, revert! + _i -= 1; + break; + } + } + else + { + preComment = false; + prePostComment = false; + } + + if (!(_text[_i] == '\r' || _text[_i] == '\n' || _text[_i] == ' ' || _text[_i] == '\t') && !inComment) + { + ranOut = false; + break; + } + + _i++; + } + + return ranOut; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Ui/ColumnHeaderExtensions.cs b/branches/ph-plugins/ProcessHacker.Common/Ui/ColumnHeaderExtensions.cs new file mode 100644 index 000000000..cef6c409d --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Ui/ColumnHeaderExtensions.cs @@ -0,0 +1,75 @@ +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.Windows.Forms; + +namespace ProcessHacker.Common.Ui +{ + // From http://stackoverflow.com/questions/254129/how-to-i-display-a-sort-arrow-in-the-header-of-a-list-view-column-using-c + [EditorBrowsable(EditorBrowsableState.Never)] + public static class ColumnHeaderExtensions + { + [StructLayout(LayoutKind.Sequential)] + private struct LVCOLUMN + { + public Int32 mask; + public Int32 cx; + [MarshalAs(UnmanagedType.LPTStr)] + public string pszText; + public IntPtr hbm; + public Int32 cchTextMax; + public Int32 fmt; + public Int32 iSubItem; + public Int32 iImage; + public Int32 iOrder; + } + + private const Int32 HDI_FORMAT = 0x4; + private const Int32 HDF_SORTUP = 0x400; + private const Int32 HDF_SORTDOWN = 0x200; + private const Int32 LVM_GETHEADER = 0x101f; + private const Int32 HDM_GETITEM = 0x120b; + private const Int32 HDM_SETITEM = 0x120c; + + [DllImport("user32.dll")] + private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); + + [DllImport("user32.dll", EntryPoint = "SendMessage")] + private static extern IntPtr SendMessage(IntPtr hWnd, Int32 Msg, IntPtr wParam, ref LVCOLUMN lPLVCOLUMN); + + public static void SetSortIcon(this ColumnHeader column, SortOrder order) + { + ListView listView = column.ListView; + IntPtr columnHeader = SendMessage(listView.Handle, LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero); + + for (int i = 0; i <= listView.Columns.Count - 1; i++) + { + IntPtr ColumnPtr = new IntPtr(i); + LVCOLUMN lvColumn = new LVCOLUMN(); + lvColumn.mask = HDI_FORMAT; + SendMessage(columnHeader, HDM_GETITEM, ColumnPtr, ref lvColumn); + + if (!(order == SortOrder.None) && i == column.Index) + { + switch (order) + { + case SortOrder.Ascending: + lvColumn.fmt &= ~HDF_SORTDOWN; + lvColumn.fmt |= HDF_SORTUP; + break; + case SortOrder.Descending: + lvColumn.fmt &= ~HDF_SORTUP; + lvColumn.fmt |= HDF_SORTDOWN; + break; + } + } + else + { + lvColumn.fmt &= ~HDF_SORTDOWN & ~HDF_SORTUP; + } + + SendMessage(columnHeader, HDM_SETITEM, ColumnPtr, ref lvColumn); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Ui/SortedListViewComparer.cs b/branches/ph-plugins/ProcessHacker.Common/Ui/SortedListViewComparer.cs new file mode 100644 index 000000000..588d1298c --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Ui/SortedListViewComparer.cs @@ -0,0 +1,317 @@ +/* + * Process Hacker - + * sorted list comparer + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Windows.Forms; +using System.Globalization; + +namespace ProcessHacker.Common.Ui +{ + public interface ISortedListViewComparer + { + int Compare(ListViewItem x, ListViewItem y, int column); + } + + /// + /// Provides automatic sorting support for the ListView control. + /// + /// + /// myListView.ListViewItemSorter = new SortedListComparer(myListView); + /// + public class SortedListViewComparer : IComparer + { + private class DefaultComparer : ISortedListViewComparer + { + private SortedListViewComparer _sortedListComparer; + + public DefaultComparer(SortedListViewComparer sortedListComparer) + { + _sortedListComparer = sortedListComparer; + } + + public int Compare(ListViewItem x, ListViewItem y, int column) + { + string sx, sy; + long ix, iy; + IComparable cx, cy; + + sx = x.SubItems[column].Text.Replace(",", ""); + sy = y.SubItems[column].Text.Replace(",", ""); + + if (!long.TryParse(sx.StartsWith("0x") ? sx.Substring(2) : sx, + sx.StartsWith("0x") ? NumberStyles.AllowHexSpecifier : 0, + null, out ix) || + !long.TryParse(sy.StartsWith("0x") ? sy.Substring(2) : sy, + sy.StartsWith("0x") ? NumberStyles.AllowHexSpecifier : 0, + null, out iy)) + { + cx = x.SubItems[column].Text; + cy = y.SubItems[column].Text; + } + else + { + cx = ix; + cy = iy; + } + + return cx.CompareTo(cy); + } + } + + private ListView _list; + private bool _virtualMode = false; + private RetrieveVirtualItemEventHandler _retrieveVirtualItem; + private bool _triState = false; + private ISortedListViewComparer _comparer; + private ISortedListViewComparer _triStateComparer; + private int _sortColumn; + private SortOrder _sortOrder; + private Dictionary> _customSorters = + new Dictionary>(); + private List _columnSortOrder = new List(); + + /// + /// Creates a new sorted list manager. + /// + /// The ListView to manage. + public SortedListViewComparer(ListView list) + { + _list = list; + _list.ColumnClick += new ColumnClickEventHandler(list_ColumnClick); + _sortColumn = 0; + _sortOrder = SortOrder.Ascending; + _comparer = new DefaultComparer(this); + this.SetSortIcon(); + } + + /// + /// Specifies whether the ListView is using VirtualMode. If true, + /// the SortedListComparer will not automatically sort the ListView. + /// + public bool VirtualMode + { + get { return _virtualMode; } + set { _virtualMode = value; } + } + + public RetrieveVirtualItemEventHandler RetrieveVirtualItem + { + get { return _retrieveVirtualItem; } + set { _retrieveVirtualItem = value; } + } + + /// + /// Allows three states of sorting: Ascending, Descending and None. + /// You must specify the sorter used for the None state using + /// TriStateComparer. + /// + public bool TriState + { + get { return _triState; } + set { _triState = value; } + } + + /// + /// The comparer to use when sorting. This is optional because a + /// default comparer will be provided. + /// + public ISortedListViewComparer Comparer + { + get { return _comparer; } + set + { + if (value == null) + _comparer = new DefaultComparer(this); + else + _comparer = value; + } + } + + /// + /// Specifies the sorter used for the None sorting state. + /// + public ISortedListViewComparer TriStateComparer + { + get { return _triStateComparer; } + set { _triStateComparer = value; } + } + + public ListView ListView + { + get { return _list; } + } + + /// + /// Specifies the index of the column to sort. + /// + public int SortColumn + { + get { return _sortColumn; } + set + { + _sortColumn = value; + this.SetSortIcon(); + } + } + + /// + /// Specifies the sort order/state. + /// + public SortOrder SortOrder + { + get { return _sortOrder; } + set + { + _sortOrder = value; + this.SetSortIcon(); + } + } + + /// + /// Allows custom sorting for individual columns. + /// + public IDictionary> CustomSorters + { + get { return _customSorters; } + } + + public IList ColumnSortOrder + { + get { return _columnSortOrder; } + } + + private void list_ColumnClick(object sender, ColumnClickEventArgs e) + { + if (e.Column == _sortColumn) + { + if (_triState) + { + if (_sortOrder == SortOrder.Ascending) + _sortOrder = SortOrder.Descending; + else if (_sortOrder == SortOrder.Descending) + _sortOrder = SortOrder.None; + else + _sortOrder = SortOrder.Ascending; + } + else + { + _sortOrder = _sortOrder == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending; + } + } + else + { + _sortColumn = e.Column; + _sortOrder = SortOrder.Ascending; + } + + this.SetSortIcon(); + + if (!_virtualMode) + _list.Sort(); + } + + private void SetSortIcon() + { + // Avoid forcing handle creation before all other initialization + // has finished. This is done by handling the Layout event and + // performing the icon setting there. + _list.DoDelayed((control) => _list.Columns[_sortColumn].SetSortIcon(_sortOrder)); + } + + private ListViewItem GetItem(int index) + { + if (_virtualMode) + { + var args = new RetrieveVirtualItemEventArgs(index); + _retrieveVirtualItem(this, args); + return args.Item; + } + else + { + return _list.Items[index]; + } + } + + private int ModifySort(int result, SortOrder order) + { + if (order == SortOrder.Ascending) + return result; + else if (order == SortOrder.Descending) + return -result; + else + return result; + } + + private int Compare(ListViewItem x, ListViewItem y, int column) + { + int result = 0; + + if (_triState && _sortOrder == SortOrder.None) + result = _triStateComparer.Compare(x, y, column); + + if (result != 0) + return result; + + if (_customSorters.ContainsKey(column)) + result = ModifySort(_customSorters[column](x, y), _sortOrder); + + if (result != 0) + return result; + + return ModifySort(_comparer.Compare(x, y, column), _sortOrder); + } + + public int Compare(ListViewItem x, ListViewItem y) + { + int result = this.Compare(x, y, _sortColumn); + + if (result != 0) + return result; + + foreach (int column in _columnSortOrder) + { + if (column == _sortColumn) + continue; + + result = this.Compare(x, y, column); + + if (result != 0) + return result; + } + + return 0; + } + + /// + /// Compares two ListView objects. + /// + /// The first ListView. + /// The second ListView. + /// A comparison result. + public int Compare(object x, object y) + { + return this.Compare(x as ListViewItem, y as ListViewItem); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/Utils.cs b/branches/ph-plugins/ProcessHacker.Common/Utils.cs new file mode 100644 index 000000000..8776faeee --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/Utils.cs @@ -0,0 +1,1439 @@ +/* + * Process Hacker - + * misc. functions + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Reflection; +using System.Text; +using System.Windows.Forms; + +namespace ProcessHacker.Common +{ + /// + /// Provides methods for manipulating various types of data. + /// + public static class Utils + { + public enum Endianness + { + Little, Big + } + + #region Constants + + public static int[] Primes = + { + 3, 7, 11, 0x11, 0x17, 0x1d, 0x25, 0x2f, 0x3b, 0x47, 0x59, 0x6b, 0x83, 0xa3, 0xc5, 0xef, + 0x125, 0x161, 0x1af, 0x209, 0x277, 0x2f9, 0x397, 0x44f, 0x52f, 0x63d, 0x78b, 0x91d, 0xaf1, + 0xd2b, 0xfd1, 0x12fd, 0x16cf, 0x1b65, 0x20e3, 0x2777, 0x2f6f, 0x38ff, 0x446f, 0x521f, 0x628d, + 0x7655, 0x8e01, 0xaa6b, 0xcc89, 0xf583, 0x126a7, 0x1619b, 0x1a857, 0x1fd3b, 0x26315, 0x2dd67, + 0x3701b, 0x42023, 0x4f361, 0x5f0ed, 0x72125, 0x88e31, 0xa443b, 0xc51eb, 0xec8c1, 0x11bdbf, + 0x154a3f, 0x198c4f, 0x1ea867, 0x24ca19, 0x2c25c1, 0x34fa1b, 0x3f928f, 0x4c4987, 0x5b8b6f, 0x6dda89 + }; + + public static string[] SizeUnitNames = { "B", "kB", "MB", "GB", "TB", "PB", "EB" }; + + #endregion + + /// + /// The maximum unit specifier to use when formatting sizes. + /// + public static int UnitSpecifier = 4; + + /// + /// Flattens an array of arrays into a single array. + /// + /// The type of each element in the arrays. + /// + /// An array of arrays. If an array in the array is null, it will be ignored. + /// + /// An array containing elements from each array. + public static T[] Concat(params T[][] ap) + { + int tl = 0; + + foreach (var array in ap) + if (array != null) + tl += array.Length; + + T[] na = new T[tl]; + int i = 0; + + foreach (var array in ap) + { + if (array != null) + { + Array.Copy(array, 0, na, i, array.Length); + i += array.Length; + } + } + + return na; + } + + /// + /// Determines whether the specified value is contained + /// within an array. + /// + /// The type of the array. + /// The array to search. + /// The value to search for. + /// True if the array contains the value, otherwise false. + public static bool Contains(this T[] array, T value) + { + return Array.IndexOf(array, value) != -1; + } + + /// + /// Counts the number of bits in the specified number. + /// + /// The number to process. + /// The number of bits in the specified number. + public static int CountBits(this int value) + { + int count = 0; + + while (value != 0) + { + count++; + value &= value - 1; + } + + return count; + } + + /// + /// Counts the number of bits in the specified number. + /// + /// The number to process. + /// The number of bits in the specified number. + public static int CountBits(this long value) + { + int count = 0; + + while (value != 0) + { + count++; + value &= value - 1; + } + + return count; + } + + /// + /// Creates an array of bytes from the specified byte pointer. + /// + /// A pointer to an array of bytes. + /// The length of the array. + /// A new byte array. + public unsafe static byte[] Create(byte* ptr, int length) + { + byte[] array = new byte[length]; + + for (int i = 0; i < length; i++) + array[i] = ptr[i]; + + return array; + } + + /// + /// Adds an ellipsis to a string if it is longer than the specified length. + /// + /// The string. + /// The maximum length. + /// The modified string. + public static string CreateEllipsis(string s, int len) + { + if (s.Length <= len) + return s; + else + return s.Substring(0, len - 4) + " ..."; + } + + /// + /// Creates a string containing random uppercase characters. + /// + /// The number of characters to generate. + /// The generated string. + public static string CreateRandomString(int length) + { + Random r = new Random((int)(DateTime.Now.ToFileTime() & 0xffffffff)); + StringBuilder sb = new StringBuilder(length); + + for (int i = 0; i < length; i++) + sb.Append((char)('A' + r.Next(25))); + + return sb.ToString(); + } + + /// + /// Clears and cleans up resources held by the menu items. + /// + public static void DisposeAndClear(this Menu.MenuItemCollection items) + { + //foreach (MenuItem item in items) + //{ + // item.Dispose(); + //} + + items.Clear(); + } + + /// + /// Disables the menu items contained in the specified menu. + /// + /// The menu. + public static void DisableAllMenuItems(Menu menu) + { + foreach (MenuItem item in menu.MenuItems) + item.Enabled = false; + } + + /// + /// Disables all menu items. + /// + public static void DisableAll(this Menu menu) + { + DisableAllMenuItems(menu); + } + + /// + /// Performs a divide operation, rounding up. + /// + /// + /// The positive number to divide. The result is undefined if the dividend + /// is negative or zero. + /// + /// + /// The positive number to divide by. The result is undefined if the divisor + /// is negative or zero. + /// + /// A rounded-up quotient. + public static int DivideUp(int dividend, int divisor) + { + return (dividend - 1) / divisor + 1; + } + + /// + /// Performs an action on a control after its handle has been created. + /// If the control's handle has already been created, the action is + /// executed immediately. + /// + /// The control is execute the action on. + /// The action to execute. + public static void DoDelayed(this Control control, Action action) + { + if (control.IsHandleCreated) + { + action(control); + } + else + { + LayoutEventHandler handler = null; + + handler = (sender, e) => + { + if (control.IsHandleCreated) + { + control.Layout -= handler; + action(control); + } + }; + + control.Layout += handler; + } + } + + /// + /// Duplicates the specified array. + /// + /// The type of array to duplicate. + /// The array to duplicate. + /// A copy of the specified array. + public static T[] Duplicate(this T[] array) + { + T[] newArray = new T[array.Length]; + + array.CopyTo(newArray, 0); + + return newArray; + } + + /// + /// Enables the menu items contained in the specified menu. + /// + /// The menu. + public static void EnableAllMenuItems(Menu menu) + { + foreach (MenuItem item in menu.MenuItems) + item.Enabled = true; + } + + /// + /// Enables all menu items. + /// + public static void EnableAll(this Menu menu) + { + EnableAllMenuItems(menu); + } + + /// + /// Compares two arrays and determines whether they are equal. + /// + /// The type of each element in the arrays. + /// The first array. + /// The second array. + /// Whether the two arrays are considered to be equal. + public static bool Equals(this T[] array, T[] other) + { + return Equals(array, other, 0); + } + + /// + /// Compares two arrays and determines whether they are equal. + /// + /// The type of each element in the arrays. + /// The first array. + /// The second array. + /// The index from which to begin comparing. + /// Whether the two arrays are considered to be equal. + public static bool Equals(this T[] array, T[] other, int startIndex) + { + return Equals(array, other, startIndex, array.Length); + } + + /// + /// Compares two arrays and determines whether they are equal. + /// + /// The type of each element in the arrays. + /// The first array. + /// The second array. + /// The index from which to begin comparing. + /// The number of elements to compare. + /// Whether the two arrays are considered to be equal. + public static bool Equals(this T[] array, T[] other, int startIndex, int length) + { + for (int i = startIndex; i < startIndex + length; i++) + if (!array[i].Equals(other[i])) + return false; + + return true; + } + + /// + /// Escapes a string using C-style escaping. + /// + /// The string to escape. + /// The escaped string. + public static string Escape(this string str) + { + str = str.Replace("\\", "\\\\"); + str = str.Replace("\"", "\\\""); + + return str; + } + + public static void Fill(this T[] array, T value) + { + for (int i = 0; i < array.Length; i++) + array[i] = value; + } + + /// + /// Fills a combobox with enum value names. + /// + /// The combobox to modify. + /// The type of the enum. + public static void Fill(this ComboBox box, Type t) + { + foreach (string s in Enum.GetNames(t)) + box.Items.Add(s); + } + + /// + /// Moves the specified rectangle to fit inside the working area + /// of the display containing the specified control. + /// + /// The rectangle to process. + /// The control from which to get the display. + /// A new rectangle with its location modified. + public static Rectangle FitRectangle(Rectangle rect, Control c) + { + return FitRectangle(rect, Screen.GetWorkingArea(c)); + } + + /// + /// Moves the specified rectangle to fit inside the specified bounds. + /// + /// The rectangle to process. + /// The bounds in which the rectangle should be. + /// A new rectangle with its location modified. + public static Rectangle FitRectangle(Rectangle rect, Rectangle bounds) + { + if (rect.X < bounds.Left) + rect.X = bounds.Left; + if (rect.Y < bounds.Top) + rect.Y = bounds.Top; + if (rect.X + rect.Width > bounds.Width) + rect.X = bounds.Width - rect.Width; + if (rect.Y + rect.Height > bounds.Height) + rect.Y = bounds.Height - rect.Height; + + return rect; + } + + /// + /// Gets a string representation for an address. + /// + /// An address. + /// A string representation of the specified address. + public static string FormatAddress(int address) + { + return "0x" + address.ToString("x"); + } + + /// + /// Gets a string representation for an address. + /// + /// An address. + /// A string representation of the specified address. + public static string FormatAddress(uint address) + { + return "0x" + address.ToString("x"); + } + + /// + /// Gets a string representation for an address. + /// + /// An address. + /// A string representation of the specified address. + public static string FormatAddress(long address) + { + return "0x" + address.ToString("x"); + } + + /// + /// Gets a string representation for an address. + /// + /// An address. + /// A string representation of the specified address. + public static string FormatAddress(ulong address) + { + return "0x" + address.ToString("x"); + } + + /// + /// Gets a string representation for an address. + /// + /// An address. + /// A string representation of the specified address. + public static string FormatAddress(IntPtr address) + { + return "0x" + address.ToString("x"); + } + + public static string FormatFlags(Type e, long value) + { + string r = ""; + + for (int i = 0; i < 32; i++) + { + long fv = 1 << i; + + if ((value & fv) == fv) + { + r += Enum.GetName(e, fv) + ", "; + } + } + + if (r.EndsWith(", ")) + r = r.Remove(r.Length - 2, 2); + + return r; + } + + /// + /// Formats a object into a string representation. + /// + /// The to format. + /// + public static string FormatLongTimeSpan(TimeSpan time) + { + return String.Format( + "{0}{1:d2}:{2:d2}:{3:d2}", + time.Days != 0 ? (time.Days.ToString() + ".") : "", + time.Hours, + time.Minutes, + time.Seconds + ); + } + + /// + /// Gets the relative time in nice English. + /// + /// A DateTime. + /// A string. + public static string FormatRelativeDateTime(DateTime time) + { + // Get the time span from the time to now. + TimeSpan span = DateTime.Now.Subtract(time); + // The partial number of weeks. + double weeks = span.TotalDays / 7; + // The partial number of fortnights. + double fortnights = weeks / 2; + // ... + double months = span.TotalDays * 12 / 365; + double years = months / 12; + double centuries = years / 100; + string str = ""; + + // Start from the most general time unit and see if they can be used + // without any fractional component. + // x centur(y|ies) + if (centuries >= 1) + str = (int)centuries + " " + ((int)centuries == 1 ? "century" : "centuries"); + // x year(s) + else if (years >= 1) + str = (int)years + " " + ((int)years == 1 ? "year" : "years"); + // x month(s) + else if (months >= 1) + str = (int)months + " " + ((int)months == 1 ? "month" : "months"); + // x fortnight(s) + else if (fortnights >= 1) + str = (int)fortnights + " " + ((int)fortnights == 1 ? "fortnight" : "fortnights"); + // x week(s) + else if (weeks >= 1) + str = (int)weeks + " " + ((int)weeks == 1 ? "week" : "weeks"); + // x day(s) (and y hour(s)) + else if (span.TotalDays >= 1) + { + str = (int)span.TotalDays + " " + ((int)span.TotalDays == 1 ? "day" : "days"); + + if (span.Hours >= 1) + str += " and " + span.Hours + " " + + (span.Hours == 1 ? "hour" : "hours"); + } + // x hour(s) (and y minute(s)) + else if (span.Hours >= 1) + { + str = span.Hours + " " + (span.Hours == 1 ? "hour" : "hours"); + + if (span.Minutes >= 1) + str += " and " + span.Minutes + " " + + (span.Minutes == 1 ? "minute" : "minutes"); + } + // x minute(s) (and y second(s)) + else if (span.Minutes >= 1) + { + str = span.Minutes + " " + (span.Minutes == 1 ? "minute" : "minutes"); + + if (span.Seconds >= 1) + str += " and " + span.Seconds + " " + + (span.Seconds == 1 ? "second" : "seconds"); + } + // x second(s) + else if (span.Seconds >= 1) + str = span.Seconds + " " + (span.Seconds == 1 ? "second" : "seconds"); + // x millisecond(s) + else if (span.Milliseconds >= 1) + str = span.Milliseconds + " " + (span.Milliseconds == 1 ? "millisecond" : "milliseconds"); + else + str = "a very short time"; + + // Turn 1 into "a", e.g. 1 minute -> a minute + if (str.StartsWith("1 ")) + { + // Special vowel case: a hour -> an hour + if (str[2] != 'h') + str = "a " + str.Substring(2); + else + str = "an " + str.Substring(2); + } + + return str + " ago"; + } + + /// + /// Formats a size into a string representation, postfixing it with the correct unit. + /// + /// The size to format. + public static string FormatSize(int size) + { + return FormatSize((uint)size); + } + + /// + /// Formats a size into a string representation, postfixing it with the correct unit. + /// + /// The size to format. + public static string FormatSize(uint size) + { + int i = 0; + double s = (double)size; + + while (s > 1024 && i < SizeUnitNames.Length && i < UnitSpecifier) + { + s /= 1024; + i++; + } + + return (s == 0 ? "0" : s.ToString("#,#.##")) + " " + SizeUnitNames[i]; + } + + /// + /// Formats a size into a string representation, postfixing it with the correct unit. + /// + /// The size to format. + public static string FormatSize(IntPtr size) + { + unchecked + { + return FormatSize((ulong)size.ToInt64()); + } + } + + /// + /// Formats a size into a string representation, postfixing it with the correct unit. + /// + /// The size to format. + public static string FormatSize(long size) + { + return FormatSize((ulong)size); + } + + /// + /// Formats a size into a string representation, postfixing it with the correct unit. + /// + /// The size to format. + public static string FormatSize(ulong size) + { + int i = 0; + double s = (double)size; + + while (s > 1024 && i < SizeUnitNames.Length && i < UnitSpecifier) + { + s /= 1024; + i++; + } + + return (s == 0 ? "0" : s.ToString("#,#.##")) + " " + SizeUnitNames[i]; + } + + /// + /// Formats a object into a string representation. + /// + /// The to format. + /// + public static string FormatTimeSpan(TimeSpan time) + { + return String.Format("{0:d2}:{1:d2}:{2:d2}.{3:d3}", + time.Hours, + time.Minutes, + time.Seconds, + time.Milliseconds); + } + + // + // Gets a System.DateTime indicating the time the specified assembly was last built. + // This will attempt to calculate the time from the build number, if possible. + // Otherwise, the last write time of the assembly will be used. + // + // The assembly to get the build date for. + // True to always use the last write time of the assembly, otherwise false. + // The time this assembly was built. + public static DateTime GetAssemblyBuildDate(Assembly assembly, bool forceFileDate) + { + Version AssemblyVersion = assembly.GetName().Version; + DateTime dt; + + if (forceFileDate) + { + dt = GetAssemblyLastWriteTime(assembly); + } + else + { + dt = DateTime.Parse("01/01/2000").AddDays(AssemblyVersion.Build).AddSeconds(AssemblyVersion.Revision * 2); + if (TimeZone.IsDaylightSavingTime(dt, TimeZone.CurrentTimeZone.GetDaylightChanges(dt.Year))) + { + dt = dt.AddHours(1); + } + if (dt > DateTime.Now || AssemblyVersion.Build < 730 || AssemblyVersion.Revision == 0) + { + dt = GetAssemblyLastWriteTime(assembly); + } + } + + return dt; + } + + // + // Returns the last write time of the specified assembly. + // + // The last write time of the assembly, or DateTime.MaxValue if an exception occurred. + public static DateTime GetAssemblyLastWriteTime(Assembly assembly) + { + if (assembly.Location == null || assembly.Location == "") + return DateTime.MaxValue; + + try + { + return File.GetLastWriteTime(assembly.Location); + } + catch + { + return DateTime.MaxValue; + } + } + + public static byte[] GetBytes(this int n) + { + return n.GetBytes(Endianness.Little); + } + + public static byte[] GetBytes(this int n, Endianness type) + { + byte[] data = new byte[4]; + + if (type == Endianness.Little) + { + data[0] = (byte)(n & 0xff); + data[1] = (byte)((n >> 8) & 0xff); + data[2] = (byte)((n >> 16) & 0xff); + data[3] = (byte)((n >> 24) & 0xff); + } + else if (type == Endianness.Big) + { + data[0] = (byte)((n >> 24) & 0xff); + data[1] = (byte)((n >> 16) & 0xff); + data[2] = (byte)((n >> 8) & 0xff); + data[3] = (byte)(n & 0xff); + } + else + { + throw new ArgumentException(); + } + + return data; + } + + public static byte[] GetBytes(this uint n) + { + return n.GetBytes(Endianness.Little); + } + + public static byte[] GetBytes(this uint n, Endianness type) + { + byte[] data = new byte[4]; + + if (type == Endianness.Little) + { + data[0] = (byte)(n & 0xff); + data[1] = (byte)((n >> 8) & 0xff); + data[2] = (byte)((n >> 16) & 0xff); + data[3] = (byte)((n >> 24) & 0xff); + } + else if (type == Endianness.Big) + { + data[0] = (byte)((n >> 24) & 0xff); + data[1] = (byte)((n >> 16) & 0xff); + data[2] = (byte)((n >> 8) & 0xff); + data[3] = (byte)(n & 0xff); + } + else + { + throw new ArgumentException(); + } + + return data; + } + + public static byte[] GetBytes(this ushort n) + { + return n.GetBytes(Endianness.Little); + } + + public static byte[] GetBytes(this ushort n, Endianness type) + { + byte[] data = new byte[2]; + + if (type == Endianness.Little) + { + data[0] = (byte)(n & 0xff); + data[1] = (byte)((n >> 8) & 0xff); + } + else if (type == Endianness.Big) + { + data[0] = (byte)((n >> 8) & 0xff); + data[1] = (byte)(n & 0xff); + } + else + { + throw new ArgumentException(); + } + + return data; + } + + /// + /// Converts a 32-bit Unix time value into a DateTime object. + /// + /// The Unix time value. + public static DateTime GetDateTimeFromUnixTime(uint time) + { + return (new DateTime(1970, 1, 1, 0, 0, 0)).Add(new TimeSpan(0, 0, 0, (int)time)); + } + + public static int GetPrime(int minimum) + { + if (minimum < 0) + throw new ArgumentOutOfRangeException("minimum"); + + for (int i = 0; i < Primes.Length; i++) + { + if (Primes[i] >= minimum) + return Primes[i]; + } + + for (int i = minimum | 1; i < int.MaxValue; i += 2) + { + if (IsPrime(i)) + return i; + } + + return minimum; + } + + /// + /// Parses a string and produces a rectangle. + /// + /// + /// A string describing a rectangle in the following format: + /// x,y,width,height (with no spaces). + /// + /// A rectangle. + public static Rectangle GetRectangle(string s) + { + var split = s.Split(','); + + return new Rectangle(int.Parse(split[0]), int.Parse(split[1]), + int.Parse(split[2]), int.Parse(split[3])); + } + + /// + /// Returns a object of the specified thread ID. + /// + /// The process which the thread belongs to. + /// The ID of the thread. + /// + public static System.Diagnostics.ProcessThread GetThreadFromId(System.Diagnostics.Process p, int id) + { + foreach (System.Diagnostics.ProcessThread t in p.Threads) + if (t.Id == id) + return t; + + return null; + } + + /// + /// Determines whether the array is empty (all 0's). + /// + /// The array to search. + /// True if the array is empty; otherwise false. + public static bool IsEmpty(this byte[] array) + { + foreach (byte b in array) + { + if (b != 0) + return false; + } + + return true; + } + + public static bool IsPrime(this int number) + { + int x; + + // Is the number even? + if ((number & 1) == 0) + return number == 2; + + x = (int)Math.Sqrt(number); + + for (int i = 3; i <= x; i += 2) + { + if ((number % i) == 0) + return false; + } + + return true; + } + + /// + /// Makes a character printable by converting unprintable characters to a dot ('.'). + /// + /// The character to convert. + /// + public static char MakePrintable(char c) + { + if (c >= ' ' && c <= '~') + return c; + else + return '.'; + } + + /// + /// Makes a string printable by converting unprintable characters to a dot ('.'). + /// + /// The string to convert. + /// + public static string MakePrintable(string s) + { + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < s.Length; i++) + sb.Append(MakePrintable(s[i])); + + return sb.ToString(); + } + + /// + /// Determines whether a string matches according to a wildcard expression. + /// + /// The wildcard expression. + /// The string to match. + /// Whether the string matches. + public static bool MatchWildcards(string pattern, string text) + { + return MatchWildcards(pattern, 0, text, 0); + } + + private static bool MatchWildcards(string pattern, int patternStart, string text, int textStart) + { + // Note: this algorithm is currently recursive for easy understanding. + // It should be re-implemented without recursion... + + int patternIndex = patternStart; + int textIndex = textStart; + + // If we have a zero-length pattern, the string matches. + if (pattern.Length == 0 || patternIndex >= pattern.Length) + return true; + // If we have a zero-length string, the string doesn't match. + if (text.Length == 0 || textIndex >= text.Length) + return false; + + // Match up to the first asterisk (or maybe a number of them). + + while (true) + { + // Did we reach the end of the pattern? If so, check if we + // have also reached the end of the text. + if (patternIndex >= pattern.Length) + return textIndex >= text.Length; + + if (pattern[patternIndex] == '*') + { + patternIndex++; + + // Skip duplicate asterisks. + while (patternIndex < pattern.Length) + { + if (pattern[patternIndex] != '*') + break; + + patternIndex++; + } + + break; + } + + // Did we reach the end of the text? If so, the match fails. + if (textIndex >= text.Length) + return false; + + if (pattern[patternIndex] != text[textIndex] && pattern[patternIndex] != '?') + return false; + + patternIndex++; + textIndex++; + } + + // We reached an asterisk (otherwise we would have returned by now). + // Keep incrementing the text index until we get a match. + + // Shortcut: if we are at the end of the pattern, it means the pattern + // has trailing asterisk(s). The string matches. + if (patternIndex >= pattern.Length) + return true; + + while (textIndex < text.Length) + { + if (MatchWildcards(pattern, patternIndex, text, textIndex)) + return true; + + textIndex++; + } + + return false; + } + + public static Dictionary ParseCommandLine(string[] args) + { + Dictionary dict = new Dictionary(); + string argPending = null; + + foreach (string s in args) + { + if (s.StartsWith("-")) + { + if (dict.ContainsKey(s)) + throw new ArgumentException("Option already specified."); + + dict.Add(s, ""); + argPending = s; + } + else + { + if (argPending != null) + { + dict[argPending] = s; + argPending = null; + } + else + { + if (!dict.ContainsKey("")) + dict.Add("", s); + } + } + } + + return dict; + } + + public static int ReadInt32(Stream s, Endianness type) + { + byte[] buffer = new byte[4]; + + if (s.Read(buffer, 0, 4) == 0) + throw new EndOfStreamException(); + + return ToInt32(buffer, type); + } + + /// + /// Reads a null-terminated string from a stream. + /// + /// The stream to read from. + /// The read string. + public static string ReadString(Stream s) + { + StringBuilder str = new StringBuilder(); + + while (true) + { + int b = s.ReadByte(); + + if (b == 0 || b == -1) + break; + + str.Append((char)(byte)b); + } + + return str.ToString(); + } + + public static string ReadString(Stream s, int length) + { + byte[] buffer = new byte[length]; + + if (s.Read(buffer, 0, length) == 0) + throw new EndOfStreamException(); + + return System.Text.ASCIIEncoding.ASCII.GetString(buffer); + } + + public static uint ReadUInt32(Stream s, Endianness type) + { + byte[] buffer = new byte[4]; + + if (s.Read(buffer, 0, 4) == 0) + throw new EndOfStreamException(); + + return ToUInt32(buffer, type); + } + + /// + /// Reads a null-terminated Unicode string from a stream. + /// + /// The stream to read from. + /// The read string. + public static string ReadUnicodeString(Stream s) + { + StringBuilder str = new StringBuilder(); + + while (true) + { + int b = s.ReadByte(); + + if (b == -1) + break; + + int b2 = s.ReadByte(); + + if (b2 == -1) + break; + + if (b == 0 && b2 == 0) + break; + + str.Append(UnicodeEncoding.Unicode.GetChars(new byte[] { (byte)b, (byte)b2 })); + } + + return str.ToString(); + } + + /// + /// Reads a Unicode string from a stream. + /// + /// The stream to read from. + /// The length, in bytes, of the string. + /// The read string. + public static string ReadUnicodeString(Stream s, int length) + { + StringBuilder str = new StringBuilder(); + int i = 0; + + while (i < length) + { + int b = s.ReadByte(); + + if (b == -1) + break; + + int b2 = s.ReadByte(); + + if (b2 == -1) + break; + + str.Append(UnicodeEncoding.Unicode.GetChars(new byte[] { (byte)b, (byte)b2 })); + i += 2; + } + + return str.ToString(); + } + + /// + /// Swaps the order of the bytes. + /// + /// The number to change. + /// A number. + public static int Reverse(this int v) + { + byte b1 = (byte)v; + byte b2 = (byte)(v >> 8); + byte b3 = (byte)(v >> 16); + byte b4 = (byte)(v >> 24); + + return b4 | (b3 << 8) | (b2 << 16) | (b1 << 24); + } + + /// + /// Swaps the order of the bytes. + /// + /// The number to change. + /// A number. + public static uint Reverse(this uint v) + { + uint b0 = v & 0xff; + uint b1 = (v >> 8) & 0xff; + uint b2 = (v >> 16) & 0xff; + uint b3 = (v >> 24) & 0xff; + + b0 <<= 24; + b1 <<= 16; + b2 <<= 8; + + return b0 | b1 | b2 | b3; + } + + /// + /// Swaps the order of the bytes. + /// + /// The number to change. + /// A number. + public static ushort Reverse(this ushort v) + { + byte b1 = (byte)v; + byte b2 = (byte)(v >> 8); + + return (ushort)(b2 | (b1 << 8)); + } + + /// + /// Reverses an array. + /// + /// The array to reverse. + /// A new array. + public static T[] Reverse(this T[] data) + { + T[] newData = new T[data.Length]; + + for (int i = 0; i < data.Length; i++) + newData[i] = data[data.Length - i - 1]; + + return newData; + } + + /// + /// Selects all of the specified items. + /// + /// The items. + public static void SelectAll(this ListView.ListViewItemCollection items) + { + foreach (ListViewItem item in items) + item.Selected = true; + } + + /// + /// Selects all of the items in the specified ListView. + /// + /// The ListView to process. + public static void SelectAll(this ListView items) + { + for (int i = 0; i < items.VirtualListSize; i++) + if (!items.SelectedIndices.Contains(i)) + items.SelectedIndices.Add(i); + } + + /// + /// Enables or disables double buffering for a control. + /// + /// The control. + /// The type of the control. + /// The new setting. + public static void SetDoubleBuffered(this Control c, Type t, bool value) + { + PropertyInfo property = t.GetProperty("DoubleBuffered", + BindingFlags.NonPublic | BindingFlags.Instance); + + property.SetValue(c, value, null); + } + + /// + /// Enables or disables double buffering for a control. + /// + /// The control to set the property on. + /// The new value. + public static void SetDoubleBuffered(this Control c, bool value) + { + c.SetDoubleBuffered(c.GetType(), value); + } + + /// + /// Shows a file in Windows Explorer. + /// + /// The file to show. + public static void ShowFileInExplorer(string fileName) + { + System.Diagnostics.Process.Start("explorer.exe", "/select," + fileName); + } + + /// + /// Calculates the size of a structure. + /// + /// The structure type. + /// The size of the structure. + public static int SizeOf() + { + return System.Runtime.InteropServices.Marshal.SizeOf(typeof(T)); + } + + /// + /// Calculates the size of a structure. + /// + /// The structure type. + /// A power-of-two whole-structure alignment to apply. + /// The size of the structure. + public static int SizeOf(int alignment) + { + // HACK: This is wrong, but it works. + return SizeOf() + alignment; + } + + /// + /// Returns a sorted list of the names in a given enum type. + /// + /// The enum type to process. + /// A list of key-value pairs, sorted based on the number of bits in the value. + public static List> SortFlagNames(Type enumType) + { + List> nameList = new List>(); + + foreach (string name in Enum.GetNames(enumType)) + { + long nameLong = Convert.ToInt64(Enum.Parse(enumType, name)); + + nameList.Add(new KeyValuePair(name, nameLong)); + } + + nameList.Sort((kvp1, kvp2) => kvp2.Value.CountBits().CompareTo(kvp1.Value.CountBits())); + + return nameList; + } + + public static int ToInt32(this byte[] data) + { + return data.ToInt32(Endianness.Little); + } + + public static int ToInt32(this byte[] data, Endianness type) + { + if (type == Endianness.Little) + { + return (data[0]) | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); + } + else if (type == Endianness.Big) + { + return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | (data[3]); + } + else + { + throw new ArgumentException(); + } + } + + public static long ToInt64(this byte[] data) + { + return data.ToInt64(Endianness.Little); + } + + public static long ToInt64(this byte[] data, Endianness type) + { + if (type == Endianness.Little) + { + return (data[0]) | (data[1] << 8) | (data[2] << 16) | (data[3] << 24) | + (data[4] << 32) | (data[5] << 40) | (data[6] << 48) | (data[7] << 56); + } + else if (type == Endianness.Big) + { + return (data[0] << 56) | (data[1] << 48) | (data[2] << 40) | (data[3] << 32) | + (data[4] << 24) | (data[5] << 16) | (data[6] << 8) | (data[7]); + } + else + { + throw new ArgumentException(); + } + } + + public static IntPtr ToIntPtr(this byte[] data) + { + if (IntPtr.Size != data.Length) + throw new ArgumentException("data"); + + if (IntPtr.Size == sizeof(int)) + return new IntPtr(data.ToInt32(Endianness.Little)); + else if (IntPtr.Size == sizeof(long)) + return new IntPtr(data.ToInt64(Endianness.Little)); + else + throw new ArgumentException("data"); + } + + public static ushort ToUInt16(this byte[] data, Endianness type) + { + return ToUInt16(data, 0, type); + } + + public static ushort ToUInt16(this byte[] data, int offset, Endianness type) + { + if (type == Endianness.Little) + { + return (ushort)(data[offset] | (data[offset + 1] << 8)); + } + else if (type == Endianness.Big) + { + return (ushort)((data[offset] << 8) | data[offset + 1]); + } + else + { + throw new ArgumentException(); + } + } + + public static uint ToUInt32(this byte[] data, Endianness type) + { + return ToUInt32(data, 0, type); + } + + public static uint ToUInt32(this byte[] data, int offset, Endianness type) + { + if (type == Endianness.Little) + { + return (uint)(data[offset]) | (uint)(data[offset + 1] << 8) | + (uint)(data[offset + 2] << 16) | (uint)(data[offset + 3] << 24); + } + else if (type == Endianness.Big) + { + return (uint)(data[offset] << 24) | (uint)(data[offset + 1] << 16) | + (uint)(data[offset + 2] << 8) | (uint)(data[offset + 3]); + } + else + { + throw new ArgumentException(); + } + } + + public static void ValidateBuffer(byte[] buffer, int offset, int length) + { + ValidateBuffer(buffer, offset, length, false); + } + + public static void ValidateBuffer(byte[] buffer, int offset, int length, bool canBeNull) + { + // Make sure the offset isn't negative. + if (offset < 0) + throw new ArgumentOutOfRangeException("offset"); + + // Make sure the length isn't negative. + if (length < 0) + throw new ArgumentOutOfRangeException("length"); + + // Make sure we won't overrun the buffer. + if (buffer != null) + { + if (buffer.Length - offset < length) + throw new ArgumentOutOfRangeException("The buffer is too small for the specified offset and length."); + } + else + { + if (!canBeNull) + throw new ArgumentException("The buffer cannot be null."); + + // We don't have a buffer, so make sure the offset and length are zero. + if (offset != 0 || length != 0) + throw new ArgumentOutOfRangeException("The offset and length must be zero for a null buffer."); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/WeakReference.cs b/branches/ph-plugins/ProcessHacker.Common/WeakReference.cs new file mode 100644 index 000000000..a7d0bece0 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/WeakReference.cs @@ -0,0 +1,39 @@ +using System; + +namespace ProcessHacker.Common +{ + public class WeakReference + where T : class + { + public static implicit operator T(WeakReference reference) + { + return reference.Target; + } + + private WeakReference _weakReference; + + public WeakReference(T obj) + : this(obj, false) + { } + + public WeakReference(T obj, bool trackResurrection) + { + _weakReference = new WeakReference(obj, trackResurrection); + } + + public bool Alive + { + get { return _weakReference.IsAlive; } + } + + public bool TrackResurrection + { + get { return _weakReference.TrackResurrection; } + } + + public T Target + { + get { return _weakReference.Target as T; } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/WorkQueue.cs b/branches/ph-plugins/ProcessHacker.Common/WorkQueue.cs new file mode 100644 index 000000000..7843a1071 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/WorkQueue.cs @@ -0,0 +1,598 @@ +/* + * Process Hacker - + * thread pool/work queue + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Threading; + +namespace ProcessHacker.Common +{ + /// + /// Manages a work queue which is executed by worker threads. + /// + public sealed class WorkQueue + { + /// + /// Represents a work item to be executed on a worker thread. + /// + public sealed class WorkItem + { + private WorkQueue _owner; + private string _tag; + private Delegate _work; + private object[] _args; + private bool _enabled = true; + private bool _completed = false; + private object _completedEventLock = new object(); + private ManualResetEvent _completedEvent; + private object _result; + private Exception _exception; + + internal WorkItem(WorkQueue owner, Delegate work, object[] args) + : this(owner, work, args, null) + { } + + internal WorkItem(WorkQueue owner, Delegate work, object[] args, string tag) + { + _owner = owner; + _work = work; + _args = args; + _tag = tag; + } + + public Delegate Work + { + get { return _work; } + } + + public object[] Arguments + { + get { return _args; } + } + + /// + /// The tag associated with the work item. + /// + public string Tag + { + get { return _tag; } + } + + /// + /// Whether the work item is to be executed. + /// + internal bool Enabled + { + get { return _enabled; } + set { _enabled = value; } + } + + /// + /// Whether the work item has been completed. + /// + public bool Completed + { + get { return _completed; } + } + + /// + /// The value returned by the target method. + /// + public object Result + { + get { return _result; } + } + + /// + /// The exception thrown by the work item target, if any. + /// + public Exception Exception + { + get { return _exception; } + } + + /// + /// If the work item has not been executed yet, prevents the + /// work item from executing. Otherwise, takes no action. + /// + /// True if the work item has not been executed yet; otherwise false. + public bool Abort() + { + return _owner.RemoveQueuedWorkItem(this); + } + + /// + /// Waits for the work item to complete and returns the result. + /// + /// The value returned by the target method. + public object GetResult() + { + this.WaitOne(); + return _result; + } + + /// + /// Performs the work. + /// + internal void PerformWork() + { + if (!_enabled) + return; + + try + { + if (_args == null) + _result = _work.Method.Invoke(_work.Target, null); + else + _result = _work.Method.Invoke(_work.Target, _args.Length != 0 ? _args : null); + } + catch (Exception ex) + { + _exception = ex; + } + + _completed = true; + + lock (_completedEventLock) + { + if (_completedEvent != null) + _completedEvent.Set(); + } + } + + /// + /// Waits for the work item to be completed. + /// + /// Always returns true. + public bool WaitOne() + { + return this.WaitOne(-1); + } + + /// + /// Waits for the work item to be completed. + /// + /// The timeout for the wait operation. + /// + /// True if the work item was completed within the timeout + /// (or was already completed); otherwise false. + /// + public bool WaitOne(int timeout) + { + lock (_completedEventLock) + { + if (_completed) + return true; + + if (_completedEvent == null) + _completedEvent = new ManualResetEvent(false); + } + + return _completedEvent.WaitOne(timeout, false); + } + } + + private static WorkQueue _globalWorkQueue = new WorkQueue(); + + /// + /// Gets the global work queue instance. + /// + public static WorkQueue GlobalWorkQueue + { + get { return _globalWorkQueue; } + } + + /// + /// Queues work for the global work queue. + /// + /// The work to be executed. + public static WorkItem GlobalQueueWorkItem(Delegate work) + { + return _globalWorkQueue.QueueWorkItem(work); + } + + /// + /// Queues work for the global work queue. + /// + /// The work to be executed. + /// The arguments to pass to the delegate. + public static WorkItem GlobalQueueWorkItem(Delegate work, params object[] args) + { + return _globalWorkQueue.QueueWorkItemTag(work, null, true, args); + } + + /// + /// Queues work for the global work queue. + /// + /// The work to be executed. + /// A tag for the work item. + public static WorkItem GlobalQueueWorkItemTag(Delegate work, string tag) + { + return _globalWorkQueue.QueueWorkItemTag(work, tag, true, null); + } + + /// + /// Queues work for the global work queue. + /// + /// The work to be executed. + /// A tag for the work item. + /// The arguments to pass to the delegate. + public static WorkItem GlobalQueueWorkItemTag(Delegate work, string tag, params object[] args) + { + return _globalWorkQueue.QueueWorkItemTag(work, tag, true, args); + } + + /// + /// The work queue. This object is used as a lock. + /// + private Queue _workQueue = new Queue(); + /// + /// The maximum number of worker threads. If there are less worker threads + /// than this limit, they will be created as necessary. If there are more + /// worker threads than this limit, they will terminate once they have + /// finished processing their current work items. + /// + private int _maxWorkerThreads = 1; + /// + /// The minimum number of worker threads. Worker threads will be created + /// as necessary and the number of worker threads will never drop below + /// this number. + /// + private int _minWorkerThreads = 0; + /// + /// The pool of worker threads. This object is used as a lock. + /// + private Dictionary _workerThreads = new Dictionary(); + /// + /// The number of worker threads which are currently running work. + /// + private int _busyCount = 0; + /// + /// A worker will block on the work-arrived event for this amount of time + /// before terminating. + /// + private int _noWorkTimeout = 1000; + /// + /// If true, prevents new work items from being queued. + /// + private volatile bool _isJoining = false; + + /// + /// Creates a new work queue. + /// + public WorkQueue() + { } + + /// + /// Gets the number of worker threads that are currently busy. + /// + public int BusyCount + { + get { return _busyCount; } + } + + /// + /// Gets or sets the maximum number of worker threads. + /// + public int MaxWorkerThreads + { + get { return _maxWorkerThreads; } + set { _maxWorkerThreads = value; } + } + + /// + /// Gets or sets the minimum number of worker threads. + /// + public int MinWorkerThreads + { + get { return _minWorkerThreads; } + set { _minWorkerThreads = value; } + } + + /// + /// Gets or sets the time, in milliseconds, after which a + /// worker thread with no work will terminate. Specify 0 so that + /// worker threads will terminate immediately, or specify -1 so that + /// worker threads will wait indefinitely for work. + /// + public int NoWorkTimeout + { + get { return _noWorkTimeout; } + set { _noWorkTimeout = value; } + } + + /// + /// Gets the number of queued work items. + /// + public int QueuedCount + { + get { return _workQueue.Count; } + } + + /// + /// Gets the number of worker threads that are alive. + /// + public int WorkerCount + { + get { return _workerThreads.Count; } + } + + /// + /// Creates worker threads if necessary to satisfy the + /// worker thread minimum. + /// + public void CreateMinimumWorkerThreads() + { + if (_workerThreads.Count < _minWorkerThreads) + { + lock (_workerThreads) + { + // Create worker threads until we have enough. + while (_workerThreads.Count < _minWorkerThreads) + this.CreateWorkerThread(); + } + } + } + + /// + /// Creates a worker thread. + /// + private void CreateWorkerThread() + { + Thread workThread = new Thread(this.WorkerThreadStart); + workThread.IsBackground = true; + workThread.Priority = ThreadPriority.Lowest; + workThread.SetApartmentState(ApartmentState.STA); + _workerThreads.Add(workThread.ManagedThreadId, workThread); + workThread.Start(); + } + + /// + /// Destroys the current worker thread. + /// + private void DestroyWorkerThread() + { + _workerThreads.Remove(Thread.CurrentThread.ManagedThreadId); + } + + /// + /// Gets the work items in the queue. + /// + /// An array of WorkItem objects. + public WorkItem[] GetQueuedWorkItems() + { + lock (_workQueue) + return _workQueue.ToArray(); + } + + /// + /// Waits for all work items to complete and prevents new work items from being queued. + /// + public void JoinAll() + { + _isJoining = true; + + // Check for work items. + while (_workQueue.Count > 0) + { + WorkItem workItem = null; + + // Lock and re-check. + lock (_workQueue) + { + if (_workQueue.Count > 0) + workItem = _workQueue.Peek(); + else + continue; + } + + // Wait for this work item to finish. + workItem.WaitOne(); + } + } + + /// + /// Removes the work item from the work queue. + /// + /// The work item to remove + /// If the work item was in the work queue, true. Otherwise, false. + public bool RemoveQueuedWorkItem(WorkItem workItem) + { + // Lock the work queue to prevent data corruption. + lock (_workQueue) + { + // Check if the work queue (still) contains the work item. + if (_workQueue.Contains(workItem)) + { + // The work item is in the queue. Prevent it from executing. + workItem.Enabled = false; + return true; + } + else + { + // The work item is no longer in the queue. + return false; + } + } + } + + /// + /// Allows new work items to be queued. + /// + public void ResetJoin() + { + _isJoining = false; + } + + /// + /// Queues work for the worker thread(s). + /// + /// The work to be performed. + public WorkItem QueueWorkItem(Delegate work) + { + return this.QueueWorkItemTag(work, null, true, null); + } + + /// + /// Queues work for the worker thread(s). + /// + /// The work to be performed. + /// The arguments to pass to the delegate. + public WorkItem QueueWorkItem(Delegate work, params object[] args) + { + return this.QueueWorkItemTag(work, null, true, args); + } + + /// + /// Queues work for the worker thread(s). + /// + /// The work to be performed. + /// A tag for the work item. + public WorkItem QueueWorkItemTag(Delegate work, string tag) + { + return this.QueueWorkItemTag(work, tag, true, null); + } + + /// + /// Queues work for the worker thread(s). + /// + /// The work to be performed. + /// A tag for the work item. + /// The arguments to pass to the delegate. + public WorkItem QueueWorkItemTag(Delegate work, string tag, params object[] args) + { + return this.QueueWorkItemTag(work, tag, true, args); + } + + /// + /// Queues work for the worker thread(s). + /// + /// The work to be performed. + /// A tag for the work item. + /// Ignored. + /// The arguments to pass to the delegate. + public WorkItem QueueWorkItemTag(Delegate work, string tag, bool isArray, object[] args) + { + WorkItem workItem; + + // Can't queue any work items if joining. + if (_isJoining) + return null; + + lock (_workQueue) + { + _workQueue.Enqueue(workItem = new WorkItem(this, work, args, tag)); + Monitor.Pulse(_workQueue); + } + + // Check if all worker threads are currently busy. + if (Thread.VolatileRead(ref _busyCount) == _workerThreads.Count) + { + // Check if we still have available worker threads + if (_workerThreads.Count < _maxWorkerThreads) + { + // We do, so we must lock and re-check. + lock (_workerThreads) + { + if (_workerThreads.Count < _maxWorkerThreads) + { + this.CreateWorkerThread(); + } + } + } + } + + return workItem; + } + + /// + /// The entry point for all worker threads. + /// + private void WorkerThreadStart() + { + while (true) + { + // Check if we have more worker threads than the limit. + if (_workerThreads.Count > _maxWorkerThreads) + { + // Lock and re-check. + lock (_workerThreads) + { + // Check the minimum as well. + if (_workerThreads.Count > _maxWorkerThreads && + _workerThreads.Count > _minWorkerThreads) + { + // We have an excess amount of worker threads. + this.DestroyWorkerThread(); + return; + } + } + } + + // Check for work. + if (_workQueue.Count > 0) + { + WorkItem workItem = null; + + // There is work, but we must lock and re-check. + lock (_workQueue) + { + if (_workQueue.Count > 0) + workItem = _workQueue.Dequeue(); + else + continue; + } + + Interlocked.Increment(ref _busyCount); + workItem.PerformWork(); + Interlocked.Decrement(ref _busyCount); + } + else + { + // No work available. Wait for work. + bool workArrived = false; + + lock (_workQueue) + workArrived = Monitor.Wait(_workQueue, _noWorkTimeout); + + if (workArrived) + { + // Work arrived. Go back so we can perform it. + continue; + } + else + { + // No work arrived during the timeout period. Delete the thread. + lock (_workerThreads) + { + // Check the minimum. + if (_workerThreads.Count > _minWorkerThreads) + this.DestroyWorkerThread(); + } + + return; + } + } + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Common/app.config b/branches/ph-plugins/ProcessHacker.Common/app.config new file mode 100644 index 000000000..b7db28170 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Common/app.config @@ -0,0 +1,3 @@ + + + diff --git a/branches/ph-plugins/ProcessHacker.Native/Api/Enums.cs b/branches/ph-plugins/ProcessHacker.Native/Api/Enums.cs new file mode 100644 index 000000000..8e1a6e484 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Api/Enums.cs @@ -0,0 +1,1072 @@ +/* + * Process Hacker - + * windows API enums + * + * Copyright (C) 2009 Uday Shanbhag + * Copyright (C) 2009 Dean + * Copyright (C) 2008-2009 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 file contains enumeration declarations for the Win32 API. + * + * All enumerations which do not belong in any other category + * are placed in this file. + */ + +using System; + +namespace ProcessHacker.Native.Api +{ + public enum AddressMode : int + { + AddrMode1616, + AddrMode1632, + AddrModeReal, + AddrModeFlat + } + + public enum AiFamily : int + { + /// + /// The address family is unspecified. + /// + Unspecified = 0, + /// + /// The Internet Protocol version 4 (IPv4) address family. + /// + INet = 2, + /// + /// The NetBIOS address family. This address family is only supported + /// if a Windows Sockets provider for NetBIOS is installed. + /// + NetBios = 17, + /// + /// The Internet Protocol version 6 (IPv6) address family. + /// + INet6 = 23, + /// + /// The Infrared Data Association (IrDA) address family. This address + /// family is only supported if the computer has an infrared port and + /// driver installed. + /// + IrDA = 26, + /// + /// The Bluetooth address family. This address family is only supported + /// if a Bluetooth adapter is installed on Windows Server 2003 or later. + /// + Bth = 32 + } + + [Flags] + public enum AllocFlags : uint + { + LHnd = 0x42, + LMemFixed = 0x0, + LMemMoveable = 0x2, + LMemZeroInit = 0x40, + LPtr = 0x40, + NonZeroLHnd = LMemMoveable, + NonZeroLPtr = LMemFixed + } + + public enum DepFlags : uint + { + Disable = 0x00000000, + Enable = 0x00000001, + DisableAtlThunkEmulation = 0x00000002 + } + + public enum DepSystemPolicyType : int + { + AlwaysOff = 0, + AlwaysOn, + OptIn, + OptOut + } + + [Flags] + public enum ExitWindowsFlags : uint + { + Logoff = 0x0, + Poweroff = 0x8, + Reboot = 0x2, + RestartApps = 0x40, + Shutdown = 0x1, + Force = 0x4, + ForceIfHung = 0x10 + } + + public enum FileCreationDispositionWin32 : uint + { + /// + /// Creates a new file. The function fails if the specified file already exists. + /// + CreateNew = 1, + /// + /// Creates a new file. If the file exists, the function overwrites the file and clears the existing attributes. + /// + CreateAlways = 2, + /// + /// Opens the file. The function fails if the file does not exist. + /// + OpenExisting = 3, + /// + /// Opens the file, if it exists. If the file does not exist, the function creates the file. + /// + OpenAlways = 4, + /// + /// Opens the file. Once opened, the file is truncated so that its size is zero bytes. + /// The function fails if the file does not exist. + /// + TruncateExisting = 5 + } + + public enum GdiBlendMode : int + { + Black = 1, + NotMergePen, + MaskNotPen, + NotCopyPen, + MaskPenNot, + Not, + XorPen, + NotMaskPen, + MaskPen, + NotXorPen, + Nop, + MergeNotPen, + CopyPen, + MergePenNot, + MergePen, + White, + Last + } + + public enum GdiPenStyle : int + { + Solid = 0, + Dash, + Dot, + DashDot, + DashDotDot, + Null, + InsideFrame, + UserStyle, + Alternate + } + + public enum GdiStockObject : int + { + WhiteBrush = 0, + LightGrayBrush, + GrayBrush, + DarkGrayBrush, + BlackBrush, + NullBrush, + WhitePen, + BlackPen, + NullPen, + OemFixedFont, + AnsiFixedFont, + AnsiVarFont, + SystemFont, + DeviceDefaultFont, + DefaultPalette, + SystemFixedFont, + DefaultGuiFont, + DcBrush, + DcPen + } + + public enum GetWindowLongOffset : int + { + WndProc = -4, + HInstance = -6, + HwndParent = -8, + Id = -12, + Style = -16, + ExStyle = -20, + UserData = -21 + } + + [Flags] + public enum HeapEntry32Flags : int + { + Fixed = 0x00000001, + Free = 0x00000002, + Moveable = 0x00000004 + } + + public enum LogonFlags : uint + { + LogonWithProfile = 1, + NetCredentialsOnly = 2 + } + + public enum LogonType : uint + { + Interactive = 2, + Network = 3, + Batch = 4, + Service = 5, + Unlock = 7, + NetworkCleartext = 8, + NewCredentials = 9 + } + + public enum LogonProvider : uint + { + Default = 0, + WinNT35 = 1, + WinNT40 = 2, + WinNT50 = 3 + } + + [Flags] + public enum MemoryState : uint + { + Commit = 0x1000, + Reserve = 0x2000, + + /// + /// Decommits memory, putting it into the reserved state. + /// + Decommit = 0x4000, + + /// + /// Frees memory, putting it into the freed state. + /// + Release = 0x8000, + Free = 0x10000, + Reset = 0x80000, + Physical = 0x400000, + LargePages = 0x20000000 + } + + public enum MemoryType : int + { + Image = 0x1000000, + Mapped = 0x40000, + Private = 0x20000 + } + + public enum MibTcpState : int + { + Closed = 1, + Listening = 2, + SynSent = 3, + SynReceived = 4, + Established = 5, + FinWait1 = 6, + FinWait2 = 7, + CloseWait = 8, + Closing = 9, + LastAck = 10, + TimeWait = 11, + DeleteTcb = 12 + } + + public enum MinidumpType : uint + { + Normal = 0x00000000, + WithDataSegs = 0x00000001, + WithFullMemory = 0x00000002, + WithHandleData = 0x00000004, + FilterMemory = 0x00000008, + ScanMemory = 0x00000010, + WithUnloadedModules = 0x00000020, + WithIndirectlyReferencedMemory = 0x00000040, + FilterModulePaths = 0x00000080, + WithProcessThreadData = 0x00000100, + WithPrivateReadWriteMemory = 0x00000200, + WithoutOptionalData = 0x00000400, + WithFullMemoryInfo = 0x00000800, + WithThreadInfo = 0x00001000, + WithCodeSegs = 0x00002000, + WithoutAuxiliaryState = 0x00004000, + WithFullAuxiliaryState = 0x00008000 + } + + public enum PeekMessageFlags : int + { + NoRemove = 0, + Remove = 1, + NoYield = 2, + } + + [Flags] + public enum PipeAccessMode : uint + { + Inbound = 0x1, + Outbound = 0x2, + Duplex = 0x3, + FirstPipeInstance = 0x80000, + WriteThrough = 0x80000000, + Overlapped = 0x40000000, + WriteDac = 0x40000, + WriteOwner = 0x80000, + AccessSystemSecurity = 0x01000000 + } + + [Flags] + public enum PipeMode : uint + { + TypeByte = 0x0, + TypeMessage = 0x4, + ReadModeByte = 0x0, + ReadModeMessage = 0x2, + Wait = 0x0, + NoWait = 0x1, + AcceptRemoteClients = 0x0, + RejectRemoteClients = 0x8 + } + + public enum PoolType : uint + { + NonPagedPool, + PagedPool, + NonPagedPoolMustSucceed, + DontUseThisType, + NonPagedPoolCacheAligned, + PagedPoolCacheAligned, + NonPagedPoolCacheAlignedMustS + } + + public enum PrivateNamespaceFlags : int + { + Destroy = 0x1 + } + + [Flags] + public enum ProcessCreationFlags : uint + { + DebugProcess = 0x1, + DebugOnlyThisProcess = 0x2, + CreateSuspended = 0x4, + DetachedProcess = 0x8, + CreateNewConsole = 0x10, + NormalPriorityClass = 0x20, + IdlePriorityClass = 0x40, + HighPriorityClass = 0x80, + RealtimePriorityClass = 0x100, + CreateNewProcessGroup = 0x200, + CreateUnicodeEnvironment = 0x400, + CreateSeparateWowVdm = 0x800, + CreateSharedWowVdm = 0x1000, + CreateForceDos = 0x2000, + BelowNormalPriorityClass = 0x4000, + AboveNormalPriorityClass = 0x8000, + StackSizeParamIsAReservation = 0x10000, + InheritCallerPriority = 0x20000, + CreateProtectedProcess = 0x40000, + ExtendedStartupInfoPresent = 0x80000, + ProcessModeBackgroundBegin = 0x100000, + ProcessModeBackgroundEnd = 0x200000, + CreateBreakawayFromJob = 0x1000000, + CreatePreserveCodeAuthzLevel = 0x2000000, + CreateDefaultErrorMode = 0x4000000, + CreateNoWindow = 0x8000000, + ProfileUser = 0x10000000, + ProfileKernel = 0x20000000, + ProfileServer = 0x40000000, + CreateIgnoreSystemDefault = 0x80000000 + } + + public enum ProcessPriorityClassWin32 : int + { + Idle = 0x40, + Normal = 0x20, + High = 0x80, + RealTime = 0x100, + BelowNormal = 0x4000, + AboveNormal = 0x8000 + } + + [Flags] + public enum RedrawWindowFlags + { + Invalidate = 0x0001, + InternalPaint = 0x0002, + Erase = 0x0004, + + Validate = 0x0008, + NoInternalPaint = 0x0010, + NoErase = 0x0020, + + NoChildren = 0x0040, + AllChildren = 0x0080, + + UpdateNow = 0x0100, + EraseNow = 0x0200, + + Frame = 0x0400, + NoFrame = 0x0800 + } + + [Flags] + public enum RunFileDialogFlags : uint + { + /// + /// Don't use any of the flags (only works alone) + /// + None = 0x0000, + /// + /// Removes the browse button + /// + NoBrowse = 0x0001, + /// + /// No default item selected + /// + NoDefault = 0x0002, + /// + /// Calculates the working directory from the file name + /// + CalcDirectory = 0x0004, + /// + /// Removes the edit box label + /// + NoLabel = 0x0008, + /// + /// Removes the separate memory space checkbox (Windows NT only) + /// + NoSeparateMemory = 0x0020 + } + + public enum ScActionType : int + { + None = 0, + Reboot = 2, + Restart = 1, + RunCommand = 3 + } + + public enum SeObjectType : int + { + Unknown = 0, + FileObject, + Service, + Printer, + RegistryKey, + LmShare, + KernelObject, + WindowObject, + DsObject, + DsObjectAll, + ProviderDefinedObject, + WmiGuidObject, + RegistryWow6432Key + } + + [Flags] + public enum SePrivilegeAttributes : uint + { + Disabled = 0x00000000, + EnabledByDefault = 0x00000001, + Enabled = 0x00000002, + Removed = 0x00000004, + UsedForAccess = 0x80000000 + } + + public enum ShowWindowType : int + { + Hide = 0, + ShowNormal = 1, + Normal = 1, + ShowMinimized = 2, + ShowMaximized = 3, + Maximize = 3, + ShowNoActivate = 4, + Show = 5, + Minimize = 6, + ShowMinNoActive = 7, + ShowNa = 8, + Restore = 9, + ShowDefault = 10, + ForceMinimize = 11, + Max = 11 + } + + [Flags] + public enum SiAccessFlags : int + { + Specific = 0x00010000, + General = 0x00020000, + Container = 0x00040000, + Property = 0x00080000 + } + + public enum SiCallbackMessage : uint + { + Release = 1, + Create = 2, + InitDialog = WindowMessage.User + 1 + } + + [Flags] + public enum SiObjectInfoFlags : int + { + EditAll = EditPerms | EditOwner | EditAudits, + EditPerms = 0x00000000, + EditOwner = 0x00000001, + EditAudits = 0x00000002, + Container = 0x00000004, + ReadOnly = 0x00000008, + Advanced = 0x00000010, + Reset = 0x00000020, + OwnerReadOnly = 0x00000040, + EditProperties = 0x00000080, + Recurse = 0x00000100, + NoAclProtect = 0x00000200, + NoTreeApply = 0x00000400, + PageTitle = 0x00000800, + ServerIsDc = 0x00001000, + ResetDaclTree = 0x00004000, + ResetSaclTree = 0x00008000, + ObjectGuid = 0x00010000, + EditEffective = 0x00020000, + ResetDacl = 0x00040000, + ResetSacl = 0x00080000, + ResetOwner = 0x00100000, + NoAdditionalPermission = 0x00200000, + ViewOnly = 0x00400000, + PermsElevationRequired = 0x01000000, + AuditsElevationRequired = 0x02000000, + OwnerElevationRequested = 0x04000000, + MayWrite = 0x10000000 + } + + public enum SiPageType : int + { + Perm, + AdvPerm, + Audit, + Owner, + Effective, + TakeOwnership + } + + [Flags] + public enum SmtoFlags : int + { + Normal = 0x0, + Block = 0x1, + AbortIfHung = 0x2, + NoTimeoutIfNotHung = 0x8, + ErrorOnExit = 0x20 + } + + [Flags] + public enum SnapshotFlags : uint + { + HeapList = 0x00000001, + Process = 0x00000002, + Thread = 0x00000004, + Module = 0x00000008, + Module32 = 0x00000010, + Inherit = 0x80000000, + All = 0x0000001f + } + + [Flags] + public enum StartupFlags : uint + { + UseShowWindow = 0x1, + UseSize = 0x2, + UsePosition = 0x4, + UseCountChars = 0x8, + UseFillAttribute = 0x10, + RunFullScreen = 0x20, + ForceOnFeedback = 0x40, + ForceOffFeedback = 0x80, + UseStdHandles = 0x100, + UseHotkey = 0x200 + } + + [Flags] + public enum SymbolFlags : int + { + ClrToken = 0x00040000, + Constant = 0x00000100, + Export = 0x00000200, + Forwarder = 0x00000400, + FrameRel = 0x00000020, + Function = 0x00000800, + IlRel = 0x00010000, + Local = 0x00000080, + Metadata = 0x00020000, + Parameter = 0x00000040, + Register = 0x00000008, + RegRel = 0x00000010, + Slot = 0x00008000, + Thunk = 0x00002000, + TlsRel = 0x00004000, + ValuePresent = 0x00000001, + Virtual = 0x00001000 + } + + [Flags] + public enum SymbolOptions : uint + { + AllowAbsoluteSymbols = 0x00000800, + AllowZeroAddress = 0x01000000, + AutoPublics = 0x00010000, + CaseInsensitive = 0x00000001, + Debug = 0x80000000, + DeferredLoads = 0x00000004, + DisableSymSrvAutodetect = 0x02000000, + ExactSymbols = 0x00000400, + FailCriticalErrors = 0x00000200, + FavorCompressed = 0x00800000, + FlatDirectory = 0x00400000, + IgnoreCvRec = 0x00000080, + IgnoreImageDir = 0x00200000, + IgnoreNtSymPath = 0x00001000, + Include32BitModules = 0x00002000, + LoadAnything = 0x00000040, + LoadLines = 0x00000010, + NoCpp = 0x00000008, + NoImageSearch = 0x00020000, + NoPrompts = 0x00080000, + NoPublics = 0x00008000, + NoUnqualifiedLoads = 0x00000100, + Overwrite = 0x00100000, + PublicsOnly = 0x00004000, + Secure = 0x00040000, + UndName = 0x00000002 + } + + [Flags] + public enum SymbolServerOption + { + Callback = 0x01, + Unattended = 0x20, + ParentWin = 0x80, + } + + public enum TcpConnectionOffloadState + { + InHost = 0, + Offloading = 1, + Offloaded = 2, + Uploading = 3, + Max = 4 + } + + public enum TcpTableClass : int + { + BasicListener, + BasicConnections, + BasicAll, + OwnerPidListener, + OwnerPidConnections, + OwnerPidAll, + OwnerModuleListener, + OwnerModuleConnections, + OwnerModuleAll + } + + public enum UipiFilterFlag : uint + { + Add = 1, + Remove = 2 + } + + public enum UdpTableClass : int + { + Basic, + OwnerPid, + OwnerModule + } + + public enum WaitResult : uint + { + Object0 = 0x0, + Abandoned = 0x80, + Timeout = 0x102, + Failed = 0xffffffff + } + + [Flags] + public enum Win32HandleFlags : int + { + Inherit = 0x1, + ProtectFromClose = 0x2 + } + + public enum WindowMessage : uint + { + Null = 0x00, + Create = 0x01, + Destroy = 0x02, + Move = 0x03, + Size = 0x05, + Activate = 0x06, + SetFocus = 0x07, + KillFocus = 0x08, + Enable = 0x0a, + SetRedraw = 0x0b, + SetText = 0x0c, + GetText = 0x0d, + GetTextLength = 0x0e, + Paint = 0x0f, + Close = 0x10, + QueryEndSession = 0x11, + Quit = 0x12, + QueryOpen = 0x13, + EraseBkgnd = 0x14, + SysColorChange = 0x15, + EndSession = 0x16, + SystemError = 0x17, + ShowWindow = 0x18, + CtlColor = 0x19, + WinIniChange = 0x1a, + SettingChange = 0x1a, + DevModeChange = 0x1b, + ActivateApp = 0x1c, + FontChange = 0x1d, + TimeChange = 0x1e, + CancelMode = 0x1f, + SetCursor = 0x20, + MouseActivate = 0x21, + ChildActivate = 0x22, + QueueSync = 0x23, + GetMinMaxInfo = 0x24, + PaintIcon = 0x26, + IconEraseBkgnd = 0x27, + NextDlgCtl = 0x28, + SpoolerStatus = 0x2a, + DrawIcon = 0x2b, + MeasureItem = 0x2c, + DeleteItem = 0x2d, + VKeyToItem = 0x2e, + CharToItem = 0x2f, + + SetFont = 0x30, + GetFont = 0x31, + SetHotkey = 0x32, + GetHotkey = 0x33, + QueryDragIcon = 0x37, + CompareItem = 0x39, + Compacting = 0x41, + WindowPosChanging = 0x46, + WindowPosChanged = 0x47, + Power = 0x48, + CopyData = 0x4a, + CancelJournal = 0x4b, + Notify = 0x4e, + InputLangChangeRequest = 0x50, + InputLangChange = 0x51, + TCard = 0x52, + Help = 0x53, + UserChanged = 0x54, + NotifyFormat = 0x55, + ContextMenu = 0x7b, + StyleChanging = 0x7c, + StyleChanged = 0x7d, + DisplayChange = 0x7e, + GetIcon = 0x7f, + SetIcon = 0x80, + + NcCreate = 0x81, + NcDestroy = 0x82, + NcCalcSize = 0x83, + NcHitTest = 0x84, + NcPaint = 0x85, + NcActivate = 0x86, + GetDlgCode = 0x87, + NcMouseMove = 0xa0, + NcLButtonDown = 0xa1, + NcLButtonUp = 0xa2, + NcLButtonDblClk = 0xa3, + NcRButtonDown = 0xa4, + NcRButtonUp = 0xa5, + NcRButtonDblClk = 0xa6, + NcMButtonDown = 0xa7, + NcMButtonUp = 0xa8, + NcMButtonDblClk = 0xa9, + + KeyDown = 0x100, + KeyUp = 0x101, + Char = 0x102, + DeadChar = 0x103, + SysKeyDown = 0x104, + SysKeyUp = 0x105, + SysChar = 0x106, + SysDeadChar = 0x107, + + ImeStartComposition = 0x10d, + ImeEndComposition = 0x10e, + ImeComposition = 0x10f, + ImeKeyLast = 0x10f, + + InitDialog = 0x110, + Command = 0x111, + SysCommand = 0x112, + Timer = 0x113, + HScroll = 0x114, + VScroll = 0x115, + InitMenu = 0x116, + InitMenuPopup = 0x117, + MenuSelect = 0x11f, + MenuChar = 0x120, + EnterIdle = 0x121, + + CtlColorMsgBox = 0x132, + CtlColorEdit = 0x133, + CtlColorListBox = 0x134, + CtlColorBtn = 0x135, + CtlColorDlg = 0x136, + CtlColorScrollbar = 0x137, + CtlColorStatic = 0x138, + + MouseMove = 0x200, + LButtonDown = 0x201, + LButtonUp = 0x202, + LButtonDblClk = 0x203, + RButtonDown = 0x204, + RButtonUp = 0x205, + RButtonDblClk = 0x206, + MButtonDown = 0x207, + MButtonUp = 0x208, + MButtonDblClk = 0x209, + MouseWheel = 0x20a, + + ParentNotify = 0x210, + EnterMenuLoop = 0x211, + ExitMenuLoop = 0x212, + NextMenu = 0x213, + Sizing = 0x214, + CaptureChanged = 0x215, + Moving = 0x216, + PowerBroadcast = 0x218, + DeviceChange = 0x219, + + MdiCreate = 0x220, + MdiDestroy = 0x221, + MdiActivate = 0x222, + MdiRestore = 0x223, + MdiNext = 0x224, + MdiMaximize = 0x225, + MdiTile = 0x226, + MdiCascade = 0x227, + MdiIconArrange = 0x228, + MdiGetActive = 0x229, + MdiSetMenu = 0x230, + EnterSizeMove = 0x231, + ExitSizeMove = 0x232, + DropFiles = 0x233, + MdiRefreshMenu = 0x234, + + ImeSetContext = 0x281, + ImeNotify = 0x282, + ImeControl = 0x283, + ImeCompositionFull = 0x284, + ImeSelect = 0x285, + ImeChar = 0x286, + ImeKeyDown = 0x290, + ImeKeyUp = 0x291, + + NcMouseHover = 0x2a0, + MouseHover = 0x2a1, + NcMouseLeave = 0x2a2, + MouseLeave = 0x2a3, + + WtsSessionChange = 0x2b1, + + TabletFirst = 0x2c0, + TabletLast = 0x2df, + + Cut = 0x300, + Copy = 0x301, + Paste = 0x302, + Clear = 0x303, + Undo = 0x304, + + RenderFormat = 0x305, + RenderAllFormats = 0x306, + DestroyClipboard = 0x307, + DrawClipboard = 0x308, + PaintClipboard = 0x309, + VScrollClipboard = 0x30a, + SizeClipboard = 0x30b, + AskCbFormatName = 0x30c, + ChangeCbChain = 0x30d, + HScrollClipboard = 0x30e, + QueryNewPalette = 0x30f, + PaletteIsChanging = 0x310, + PaletteChanged = 0x311, + + Hotkey = 0x312, + Print = 0x317, + PrintClient = 0x318, + + DwmSendIconicThumbnail = 0x323, + DwmSendIconicLivePreviewBitmap = 0x326, + + HandheldFirst = 0x358, + HandheldLast = 0x35f, + PenWinFirst = 0x380, + PenWinLast = 0x38f, + CoalesceFirst = 0x390, + CoalesceLast = 0x39f, + DdeInitiate = 0x3e0, + DdeTerminate = 0x3e1, + DdeAdvise = 0x3e2, + DdeUnadvise = 0x3e3, + DdeAck = 0x3e4, + DdeData = 0x3e5, + DdeRequest = 0x3e6, + DdePoke = 0x3e7, + DdeExecute = 0x3e8, + + User = 0x400, + + BcmSetShield = 0x160c, + + App = 0x8000 + } + + [Flags] + public enum WindowPlacementFlags : int + { + SetMinPosition = 0x1, + RestoreToMaximized = 0x2, + AsyncWindowPlacement = 0x4 + } + + public enum WindowStyles : uint + { + Overlapped = 0x00000000, + Popup = 0x80000000, + Child = 0x40000000, + Minimize = 0x20000000, + Visible = 0x10000000, + Disabled = 0x08000000, + ClipSiblings = 0x04000000, + ClipChildren = 0x02000000, + Maximize = 0x01000000, + Caption = 0x00C00000, /* WindowStyles.Border | WindowStyles.DialogFrame */ + Border = 0x00800000, + DialogFrame = 0x00400000, + VerticalScroll = 0x00200000, + HorizontalScroll = 0x00100000, + SystemMenu = 0x00080000, + ThickFrame = 0x00040000, + Group = 0x00020000, + TabStop = 0x00010000, + MinimizeBox = 0x00020000, + MaximizeBox = 0x00010000 + } + + [Flags] + public enum WtProvFlags : int + { + RevocationCheckNone = 0x10, + RevocationCheckEndCert = 0x20, + RevocationCheckChain = 0x40, + RevocationCheckChainExcludeRoot = 0x80, + Safer = 0x100, + HashOnly = 0x200, + UseDefaultOsVerCheck = 0x800, + CacheOnlyUrlRetrieval = 0x1000 + } + + public enum WtRevocationChecks : int + { + None = 0, + WholeChain = 1 + } + + public enum WtStateAction + { + Ignore = 0, + Verify = 1, + Close = 2, + AutoCache = 3, + AutoCacheFlush = 4 + } + + public enum WtsConnectStateClass : int + { + Active, + Connected, + ConnectQuery, + Shadow, + Disconnected, + Idle, + Listen, + Reset, + Down, + Init + } + + public enum WtsInformationClass : int + { + InitialProgram, + ApplicationName, + WorkingDirectory, + OemId, + SessionId, + UserName, + WinStationName, + DomainName, + ConnectState, + ClientBuildNumber, + ClientName, + ClientDirectory, + ClientProductId, + ClientHardwareId, + ClientAddress, + ClientDisplay, + ClientProtocolType, + IdleTime, + LogonTime, + IncomingBytes, + OutgoingBytes, + IncomingFrames, + OutgoingFrames + } + + public enum WtsNotificationFlags : int + { + ThisSession = 0x0, + AllSessions = 0x1 + } + + public enum WtsSessionChangeEvent : int + { + ConsoleConnect = 1, + ConsoleDisconnect, + RemoteConnect, + RemoteDisconnect, + SessionLogon, + SessionLogoff, + SessionLock, + SessionUnlock, + RemoteControl + } + + public enum WtsShutdownFlags : int + { + Logoff = 0x1, + Shutdown = 0x2, + Reboot = 0x4, + Poweroff = 0x8, + FastReboot = 0x10 + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Api/Extensions.cs b/branches/ph-plugins/ProcessHacker.Native/Api/Extensions.cs new file mode 100644 index 000000000..450c293ad --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Api/Extensions.cs @@ -0,0 +1,504 @@ +/* + * Process Hacker - + * windows API structure extension functions + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Runtime.InteropServices; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native +{ + public static class NativeExtensions + { + public static ObjectBasicInformation GetBasicInfo(this SystemHandleEntry thisHandle) + { + using (ProcessHandle process = new ProcessHandle(thisHandle.ProcessId, ProcessAccess.DupHandle)) + { + return thisHandle.GetBasicInfo(process); + } + } + + public static ObjectBasicInformation GetBasicInfo(this SystemHandleEntry thisHandle, ProcessHandle process) + { + NtStatus status = NtStatus.Success; + IntPtr handle = new IntPtr(thisHandle.Handle); + IntPtr objectHandleI; + GenericHandle objectHandle = null; + int retLength; + int baseAddress; + + if (KProcessHacker.Instance == null) + { + if ((status = Win32.NtDuplicateObject( + process, handle, ProcessHandle.Current, out objectHandleI, 0, 0, 0)) >= NtStatus.Error) + Win32.ThrowLastError(); + + objectHandle = new GenericHandle(objectHandleI); + } + + try + { + using (var data = new MemoryAlloc(Marshal.SizeOf(typeof(ObjectBasicInformation)))) + { + if (KProcessHacker.Instance != null) + { + KProcessHacker.Instance.ZwQueryObject(process, handle, ObjectInformationClass.ObjectBasicInformation, + data, data.Size, out retLength, out baseAddress); + } + else + { + status = Win32.NtQueryObject(objectHandle, ObjectInformationClass.ObjectBasicInformation, + data, data.Size, out retLength); + } + + if (status >= NtStatus.Error) + Win32.ThrowLastError(status); + + return data.ReadStruct(); + } + } + finally + { + if (objectHandle != null) + objectHandle.Dispose(); + } + } + + public static string GetName(this ClientId clientId) + { + return clientId.GetName(true); + } + + public static string GetName(this ClientId clientId, bool includeThread) + { + string processName = Windows.GetProcessName(clientId.ProcessId); + + if (includeThread) + { + if (processName != null) + return processName + " (" + clientId.ProcessId.ToString() + "): " + + clientId.ThreadId.ToString(); + else + return "Non-existent process (" + clientId.ProcessId.ToString() + "): " + + clientId.ThreadId.ToString(); + } + else + { + if (processName != null) + return processName + " (" + clientId.ProcessId.ToString() + ")"; + else + return "Non-existent process (" + clientId.ProcessId.ToString() + ")"; + } + } + + private static string GetObjectNameNt(ProcessHandle process, IntPtr handle, GenericHandle dupHandle) + { + int retLength; + int baseAddress = 0; + + if (KProcessHacker.Instance != null) + { + KProcessHacker.Instance.ZwQueryObject(process, handle, ObjectInformationClass.ObjectNameInformation, + IntPtr.Zero, 0, out retLength, out baseAddress); + } + else + { + Win32.NtQueryObject(dupHandle, ObjectInformationClass.ObjectNameInformation, + IntPtr.Zero, 0, out retLength); + } + + if (retLength > 0) + { + using (MemoryAlloc oniMem = new MemoryAlloc(retLength)) + { + if (KProcessHacker.Instance != null) + { + if (KProcessHacker.Instance.ZwQueryObject(process, handle, ObjectInformationClass.ObjectNameInformation, + oniMem, oniMem.Size, out retLength, out baseAddress) >= NtStatus.Error) + throw new Exception("ZwQueryObject failed."); + } + else + { + if (Win32.NtQueryObject(dupHandle, ObjectInformationClass.ObjectNameInformation, + oniMem, oniMem.Size, out retLength) >= NtStatus.Error) + throw new Exception("NtQueryObject failed."); + } + + var oni = oniMem.ReadStruct(); + var str = oni.Name; + + if (KProcessHacker.Instance != null) + str.Buffer = str.Buffer.Increment(oniMem.Memory.Decrement(baseAddress)); + + return str.Read(); + } + } + + throw new Exception("NtQueryObject failed."); + } + + public static ObjectInformation GetHandleInfo(this SystemHandleEntry thisHandle) + { + return thisHandle.GetHandleInfo(true); + } + + public static ObjectInformation GetHandleInfo(this SystemHandleEntry thisHandle, bool getName) + { + using (ProcessHandle process = new ProcessHandle(thisHandle.ProcessId, + KProcessHacker.Instance != null ? OSVersion.MinProcessQueryInfoAccess : ProcessAccess.DupHandle)) + { + return thisHandle.GetHandleInfo(process, getName); + } + } + + public static ObjectInformation GetHandleInfo(this SystemHandleEntry thisHandle, ProcessHandle process) + { + return thisHandle.GetHandleInfo(process, true); + } + + public static ObjectInformation GetHandleInfo(this SystemHandleEntry thisHandle, ProcessHandle process, bool getName) + { + IntPtr handle = new IntPtr(thisHandle.Handle); + IntPtr objectHandleI; + int retLength = 0; + GenericHandle objectHandle = null; + + if (thisHandle.Handle == 0 || thisHandle.Handle == -1 || thisHandle.Handle == -2) + throw new WindowsException(NtStatus.InvalidHandle); + + // Duplicate the handle if we're not using KPH + if (KProcessHacker.Instance == null) + { + NtStatus status; + + if ((status = Win32.NtDuplicateObject( + process, handle, ProcessHandle.Current, out objectHandleI, 0, 0, 0)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + objectHandle = new GenericHandle(objectHandleI); + } + + ObjectInformation info = new ObjectInformation(); + + // If the cache contains the object type's name, use it. Otherwise, query the type + // for its name. + lock (Windows.ObjectTypes) + { + if (Windows.ObjectTypes.ContainsKey(thisHandle.ObjectTypeNumber)) + { + info.TypeName = Windows.ObjectTypes[thisHandle.ObjectTypeNumber]; + } + else + { + int baseAddress = 0; + + if (KProcessHacker.Instance != null) + { + KProcessHacker.Instance.ZwQueryObject(process, handle, ObjectInformationClass.ObjectTypeInformation, + IntPtr.Zero, 0, out retLength, out baseAddress); + } + else + { + Win32.NtQueryObject(objectHandle, ObjectInformationClass.ObjectTypeInformation, + IntPtr.Zero, 0, out retLength); + } + + if (retLength > 0) + { + using (MemoryAlloc otiMem = new MemoryAlloc(retLength)) + { + if (KProcessHacker.Instance != null) + { + if (KProcessHacker.Instance.ZwQueryObject(process, handle, ObjectInformationClass.ObjectTypeInformation, + otiMem, otiMem.Size, out retLength, out baseAddress) >= NtStatus.Error) + throw new Exception("ZwQueryObject failed."); + } + else + { + if (Win32.NtQueryObject(objectHandle, ObjectInformationClass.ObjectTypeInformation, + otiMem, otiMem.Size, out retLength) >= NtStatus.Error) + throw new Exception("NtQueryObject failed."); + } + + var oti = otiMem.ReadStruct(); + var str = oti.Name; + + if (KProcessHacker.Instance != null) + str.Buffer = str.Buffer.Increment(otiMem.Memory.Decrement(baseAddress)); + + info.TypeName = str.Read(); + Windows.ObjectTypes.Add(thisHandle.ObjectTypeNumber, info.TypeName); + } + } + } + } + + if (!getName) + return info; + + // Get the object's name. If the object is a file we must take special + // precautions so that we don't hang. + if (info.TypeName == "File") + { + if (KProcessHacker.Instance != null) + { + // Use KProcessHacker for files to avoid hangs. + info.OrigName = KProcessHacker.Instance.GetHandleObjectName(process, handle); + } + else + { + // 0: No hack, query the thing normally. + // 1: No hack, use NProcessHacker. + // 2: Hack. + int hackLevel = 1; + + // Can't use NPH because XP had a bug where a thread hanging + // on NtQueryObject couldn't be terminated. + if (OSVersion.IsBelowOrEqual(WindowsVersion.XP)) + hackLevel = 2; + + // On Windows 7 and above the hanging bug appears to have + // been fixed. Query the object normally. + // UPDATE: Not so. It still happens. + //if (OSVersion.IsAboveOrEqual(WindowsVersion.Seven)) + // hackLevel = 0; + + if (hackLevel == 1) + { + try + { + // Use NProcessHacker. + using (MemoryAlloc oniMem = new MemoryAlloc(0x4000)) + { + if (NProcessHacker.PhQueryNameFileObject( + objectHandle, oniMem, oniMem.Size, out retLength) >= NtStatus.Error) + throw new Exception("PhQueryNameFileObject failed."); + + var oni = oniMem.ReadStruct(); + + info.OrigName = oni.Name.Read(); + } + } + catch (DllNotFoundException) + { + hackLevel = 2; + } + } + + if (hackLevel == 0) + { + info.OrigName = GetObjectNameNt(process, handle, objectHandle); + } + else if (hackLevel == 2) + { + // KProcessHacker and NProcessHacker not available. Fall back to using hack + // (i.e. not querying the name at all if the access is 0x0012019f). + if ((int)thisHandle.GrantedAccess != 0x0012019f) + info.OrigName = GetObjectNameNt(process, handle, objectHandle); + } + } + } + else + { + // Not a file. Query the object normally. + info.OrigName = GetObjectNameNt(process, handle, objectHandle); + } + + // Get a better name for the handle. + try + { + switch (info.TypeName) + { + case "File": + // Resolves \Device\Harddisk1 into C:, for example. + if (!string.IsNullOrEmpty(info.OrigName)) + info.BestName = FileUtils.GetFileName(info.OrigName); + + break; + + case "Key": + info.BestName = NativeUtils.FormatNativeKeyName(info.OrigName); + + break; + + case "Process": + { + int processId; + + if (KProcessHacker.Instance != null) + { + processId = KProcessHacker.Instance.KphGetProcessId(process, handle); + + if (processId == 0) + throw new Exception("Invalid PID"); + } + else + { + using (var processHandle = + new NativeHandle(process, handle, OSVersion.MinProcessQueryInfoAccess)) + { + if ((processId = Win32.GetProcessId(processHandle)) == 0) + Win32.ThrowLastError(); + } + } + + info.BestName = (new ClientId(processId, 0)).GetName(false); + } + + break; + + case "Thread": + { + int processId; + int threadId; + + if (KProcessHacker.Instance != null) + { + threadId = KProcessHacker.Instance.KphGetThreadId(process, handle, out processId); + + if (threadId == 0 || processId == 0) + throw new Exception("Invalid TID or PID"); + } + else + { + using (var threadHandle = + new NativeHandle(process, handle, OSVersion.MinThreadQueryInfoAccess)) + { + var basicInfo = ThreadHandle.FromHandle(threadHandle).GetBasicInformation(); + + threadId = basicInfo.ClientId.ThreadId; + processId = basicInfo.ClientId.ProcessId; + } + } + + info.BestName = (new ClientId(processId, threadId)).GetName(true); + } + + break; + + case "TmEn": + { + using (var enHandleDup = + new NativeHandle(process, handle, EnlistmentAccess.QueryInformation)) + { + var enHandle = EnlistmentHandle.FromHandle(enHandleDup); + + info.BestName = enHandle.GetBasicInformation().EnlistmentId.ToString("B"); + } + } + break; + + case "TmRm": + { + using (var rmHandleDup = + new NativeHandle(process, handle, ResourceManagerAccess.QueryInformation)) + { + var rmHandle = ResourceManagerHandle.FromHandle(rmHandleDup); + + info.BestName = rmHandle.GetDescription(); + + if (string.IsNullOrEmpty(info.BestName)) + info.BestName = rmHandle.GetGuid().ToString("B"); + } + } + break; + + case "TmTm": + { + using (var tmHandleDup = + new NativeHandle(process, handle, TmAccess.QueryInformation)) + { + var tmHandle = TmHandle.FromHandle(tmHandleDup); + + info.BestName = FileUtils.GetFileName(FileUtils.GetFileName(tmHandle.GetLogFileName())); + + if (string.IsNullOrEmpty(info.BestName)) + info.BestName = tmHandle.GetBasicInformation().TmIdentity.ToString("B"); + } + } + break; + + case "TmTx": + { + using (var transactionHandleDup = + new NativeHandle(process, handle, TransactionAccess.QueryInformation)) + { + var transactionHandle = TransactionHandle.FromHandle(transactionHandleDup); + + info.BestName = transactionHandle.GetDescription(); + + if (string.IsNullOrEmpty(info.BestName)) + info.BestName = transactionHandle.GetBasicInformation().TransactionId.ToString("B"); + } + } + break; + + case "Token": + { + using (var tokenHandleDup = + new NativeHandle(process, handle, TokenAccess.Query)) + { + var tokenHandle = TokenHandle.FromHandle(tokenHandleDup); + var sid = tokenHandle.GetUser(); + + using (sid) + info.BestName = sid.GetFullName(true) + ": 0x" + + tokenHandle.GetStatistics().AuthenticationId.ToString(); + } + } + + break; + + default: + if (info.OrigName != null && + info.OrigName != "") + { + info.BestName = info.OrigName; + } + else + { + info.BestName = null; + } + + break; + } + } + catch + { + if (info.OrigName != null && info.OrigName != "") + { + info.BestName = info.OrigName; + } + else + { + info.BestName = null; + } + } + + if (objectHandle != null) + objectHandle.Dispose(); + + return info; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Api/Functions.cs b/branches/ph-plugins/ProcessHacker.Native/Api/Functions.cs new file mode 100644 index 000000000..74caa4290 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Api/Functions.cs @@ -0,0 +1,2816 @@ +/* + * Process Hacker - + * windows API functions + * + * Copyright (C) 2009 Flavio Erlich + * Copyright (C) 2009 Uday Shanbhag + * Copyright (C) 2009 Dean + * Copyright (C) 2008-2009 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 file contains function declarations for the Win32 API. + * + * All functions which do not belong in any other category + * are placed in this file. + */ + +using System; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Windows.Forms; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Api +{ + public static partial class Win32 + { + #region Cryptography + + [DllImport("wintrust.dll", SetLastError = true)] + public static extern bool CryptCATCatalogInfoFromContext( + [In] IntPtr CatInfoHandle, + [Out] out CatalogInfo CatInfo, + [In] int Flags + ); + + [DllImport("wintrust.dll", SetLastError = true)] + public static extern IntPtr CryptCATAdminEnumCatalogFromHash( + [In] IntPtr CatAdminHandle, + [In] byte[] Hash, + [In] int HashSize, + [In] int Flags, + [In] IntPtr PrevCatInfoHandle + ); + + [DllImport("wintrust.dll", SetLastError = true)] + public static extern bool CryptCATAdminAcquireContext( + [Out] out IntPtr CatAdminHandle, + [In] [MarshalAs(UnmanagedType.LPStruct)] Guid Subsystem, + [In] int Flags + ); + + [DllImport("wintrust.dll", SetLastError = true)] + public static extern bool CryptCATAdminCalcHashFromFileHandle( + [In] IntPtr FileHandle, + ref int HashSize, + [In] byte[] Hash, + [In] int Flags + ); + + [DllImport("wintrust.dll", SetLastError = true)] + public static extern bool CryptCATAdminReleaseContext( + [In] IntPtr CatAdminHandle, + [In] int Flags + ); + + [DllImport("wintrust.dll", SetLastError = true)] + public static extern bool CryptCATAdminReleaseCatalogContext( + [In] IntPtr CatAdminHandle, + [In] IntPtr CatInfoHandle, + [In] int Flags + ); + + [DllImport("wintrust.dll", SetLastError = true)] + public static extern uint WinVerifyTrust( + [In] IntPtr hWnd, + [In] [MarshalAs(UnmanagedType.LPStruct)] Guid ActionId, + [In] ref WintrustData WintrustData + ); + + #endregion + + #region Debugging + + [DllImport("kernel32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DebugActiveProcess( + [In] int Pid + ); + + [DllImport("kernel32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DebugActiveProcessStop( + [In] int Pid + ); + + [DllImport("kernel32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DebugSetProcessKillOnExit( + [In] bool KillOnExit + ); + + #endregion + + #region Error Handling + + /// + /// Removes an Application from Windows Error Reporting on Windows XP + /// + /// The process.exe or the path\process.exe to be excluded + /// True if successfully excluded + [DllImport("faultrep.dll", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern bool AddERExcludedApplication( + [In] string ExeName + ); + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern int FormatMessage( + [In] int Flags, + [In] [Optional] IntPtr Source, + [In] int MessageId, + [In] int LanguageId, + [Out] StringBuilder Buffer, + [In] int Size, + [In] [Optional] IntPtr Arguments + ); + + /// + /// Removes an Application from Windows Error Reporting on Windows Vista + /// + /// The process.exe or the path\process.exe to be excluded + /// true to exclude process from all users. Note: Administrator access is Required if set true + /// A HResult indicating the result + [DllImport("wer.dll", CharSet = CharSet.Unicode)] + public static extern HResult WerAddExcludedApplication( + [In] string ExeName, + [In] bool AllUsers + ); + + #endregion + + #region Files + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool GetFileInformationByHandleEx( + [In] IntPtr FileHandle, + [In] int FileInformationClass, + [In] IntPtr FileInformation, + [In] int FileInformationLength + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool GetFileSizeEx( + [In] IntPtr FileHandle, + [Out] out long FileSize + ); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern int QueryDosDevice( + [In] [Optional] string DeviceName, + [In] IntPtr TargetPath, + [In] int MaxLength + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern IntPtr CreateFile( + [In] string FileName, + [In] FileAccess DesiredAccess, + [In] FileShareMode ShareMode, + [In] [Optional] int SecurityAttributes, + [In] FileCreationDispositionWin32 CreationDisposition, + [In] int FlagsAndAttributes, + [In] [Optional] IntPtr TemplateFile + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool ReadFile( + [In] IntPtr FileHandle, + [Out] byte[] Buffer, + [In] int Bytes, + [Out] [Optional] out int ReadBytes, + [Optional] IntPtr Overlapped + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool WriteFile( + [In] IntPtr FileHandle, + [In] byte[] Buffer, + [In] int Bytes, + [Out] [Optional] out int WrittenBytes, + [Optional] IntPtr Overlapped + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public unsafe static extern bool WriteFile( + [In] IntPtr FileHandle, + [In] void* Buffer, + [In] int Bytes, + [Out] [Optional] out int WrittenBytes, + [Optional] IntPtr Overlapped + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool DeviceIoControl( + [In] IntPtr FileHandle, + [In] int IoControlCode, + [In] [Optional] byte[] InBuffer, + [In] int InBufferLength, + [Out] [Optional] byte[] OutBuffer, + [In] int OutBufferLength, + [Out] [Optional]out int BytesReturned, + [Optional] IntPtr Overlapped + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public unsafe static extern bool DeviceIoControl( + [In] IntPtr FileHandle, + [In] int IoControlCode, + [In] [Optional] byte* InBuffer, + [In] int InBufferLength, + [Out] [Optional] byte* OutBuffer, + [In] int OutBufferLength, + [Out] [Optional] out int BytesReturned, + [Optional] IntPtr Overlapped + ); + + #endregion + + #region GDI + + [DllImport("gdi32.dll")] + public static extern bool DeleteObject( + [In] IntPtr Object + ); + + [DllImport("gdi32.dll")] + public static extern IntPtr GetStockObject( + [In] GdiStockObject Object + ); + + [DllImport("gdi32.dll")] + public static extern bool Rectangle( + [In] IntPtr hDC, + [In] int LeftRect, + [In] int TopRect, + [In] int RightRect, + [In] int BottomRect + ); + + [DllImport("gdi32.dll")] + public static extern IntPtr SelectObject( + [In] IntPtr hDC, + [In] IntPtr hGdiObject + ); + + [DllImport("gdi32.dll")] + public static extern IntPtr CreatePen( + [In] GdiPenStyle PenStyle, + [In] int Width, + [In] IntPtr Color + ); + + [DllImport("gdi32.dll")] + public static extern bool RestoreDC( + [In] IntPtr hDC, + [In] int SavedDC + ); + + [DllImport("gdi32.dll")] + public static extern int SaveDC( + [In] IntPtr hDC + ); + + [DllImport("gdi32.dll")] + public static extern GdiBlendMode SetROP2( + [In] IntPtr hDC, + [In] GdiBlendMode DrawMode + ); + + #endregion + + #region Images + + [DllImport("imagehlp.dll", SetLastError = true)] + public static extern IntPtr CheckSumMappedFile( + [In] IntPtr BaseAddress, + [In] int FileLength, + [Out] out int HeaderSum, + [Out] out int CheckSum + ); + + [DllImport("dbghelp.dll", SetLastError = true)] + public static extern IntPtr ImageNtHeader( + [In] IntPtr ImageBase + ); + + [DllImport("imagehlp.dll", SetLastError = true, CharSet = CharSet.Ansi)] + public static extern bool MapAndLoad( + [In] string ImageName, + [In] [Optional] string DllPath, + [Out] out LoadedImage LoadedImage, + [MarshalAs(UnmanagedType.Bool)] + [In] bool DotDll, + [In] bool ReadOnly + ); + + [DllImport("imagehlp.dll", SetLastError = true)] + public static extern bool UnMapAndLoad( + [In] ref LoadedImage LoadedImage + ); + + #endregion + + #region Jobs + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool TerminateJobObject( + [In] IntPtr JobHandle, + [In] int ExitCode + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool AssignProcessToJobObject( + [In] IntPtr JobHandle, + [In] IntPtr ProcessHandle + ); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr CreateJobObject( + [In] [Optional] IntPtr SecurityAttributes, + [In] [Optional] string Name + ); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr OpenJobObject( + [In] JobObjectAccess DesiredAccess, + [In] bool Inherit, + [In] string Name + ); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern bool QueryInformationJobObject( + [In] [Optional] IntPtr JobHandle, + [In] JobObjectInformationClass JobInformationClass, + [Out] IntPtr JobInformation, + [In] int JobInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern bool QueryInformationJobObject( + [In] [Optional] IntPtr JobHandle, + [In] JobObjectInformationClass JobInformationClass, + [Out] out JobObjectBasicUiRestrictions JobInformation, + [In] int JobInformationLength, + [Out] [Optional] out int ReturnLength + ); + + #endregion + + #region Kernel + + [DllImport("psapi.dll", SetLastError = true)] + public static extern bool EnumDeviceDrivers( + [Out] IntPtr[] ImageBases, + [In] int Size, + [Out] out int Needed + ); + + [DllImport("psapi.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern int GetDeviceDriverBaseName( + [In] IntPtr ImageBase, + [Out] StringBuilder FileName, + [In] int Size + ); + + [DllImport("psapi.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern int GetDeviceDriverFileName( + [In] IntPtr ImageBase, + [Out] StringBuilder FileName, + [In] int Size + ); + + #endregion + + #region Libraries + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern IntPtr LoadLibrary( + [In] string FileName + ); + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] + public static extern IntPtr LoadLibraryEx( + [In] string FileName, + IntPtr File, + [In] int Flags + ); + + [DllImport("kernel32.dll")] + public static extern bool FreeLibrary( + [In] IntPtr Handle + ); + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] + public static extern IntPtr GetModuleHandle( + [In] [Optional] string ModuleName + ); + + [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)] + public static extern IntPtr GetProcAddress( + [In] IntPtr Module, + [In] string ProcName + ); + + [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)] + public static extern IntPtr GetProcAddress( + [In] IntPtr Module, + [In] ushort ProcOrdinal + ); + + #endregion + + #region Mailslots + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr CreateMailslot( + [In] string Name, + [In] int MaxMessageSize, + [In] int ReadTimeout, + [In] IntPtr SecurityAttributes + ); + + #endregion + + #region Memory + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool AllocateUserPhysicalPages( + [In] IntPtr ProcessHandle, + ref IntPtr NumberOfPages, + IntPtr[] UserPfnArray + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool FreeUserPhysicalPages( + [In] IntPtr ProcessHandle, + ref IntPtr NumberOfPages, + IntPtr[] UserPfnArray + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool MapUserPhysicalPages( + [In] IntPtr Address, + IntPtr NumberOfPages, + IntPtr[] UserPfnArray + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern IntPtr LocalAlloc( + [In] AllocFlags Flags, + [In] int Bytes + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern IntPtr LocalReAlloc( + [In] IntPtr Memory, + [In] AllocFlags Flags, + [In] int Bytes + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern IntPtr LocalFree( + [In] IntPtr Memory + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern int GetProcessHeaps( + [In] int NumberOfHeaps, + [Out] IntPtr[] Heaps + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern int HeapCompact( + [In] IntPtr Heap, + [In] bool NoSerialize + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern IntPtr HeapCreate( + [In] HeapFlags Flags, + [In] IntPtr InitialSize, + [In] IntPtr MaximumSize + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool HeapDestroy( + [In] IntPtr Heap + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool HeapFree( + [In] IntPtr Heap, + [In] HeapFlags Flags, + [In] IntPtr Memory + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern IntPtr HeapAlloc( + [In] IntPtr Heap, + [In] HeapFlags Flags, + [In] IntPtr Bytes + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern IntPtr HeapReAlloc( + [In] IntPtr Heap, + [In] HeapFlags Flags, + [In] IntPtr Memory, + [In] IntPtr Bytes + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern IntPtr GetProcessHeap(); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern int VirtualQueryEx( + [In] IntPtr Process, + [In] [Optional] IntPtr Address, + [Out] [MarshalAs(UnmanagedType.Struct)] out MemoryBasicInformation Buffer, + [In] int Size + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool VirtualProtectEx( + [In] IntPtr Process, + [In] IntPtr Address, + [In] int Size, + [In] MemoryProtection NewProtect, + [Out] out MemoryProtection OldProtect + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern IntPtr VirtualAllocEx( + [In] IntPtr Process, + [In] [Optional] IntPtr Address, + [In] int Size, + [In] MemoryState Type, + [In] MemoryProtection Protect + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool VirtualFreeEx( + [In] IntPtr Process, + [In] IntPtr Address, + [In] int Size, + [In] MemoryState FreeType + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ReadProcessMemory( + [In] IntPtr Process, + [In] IntPtr BaseAddress, + [Out] byte[] Buffer, + [In] int Size, + [Out] out int BytesRead + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public unsafe static extern bool ReadProcessMemory( + [In] IntPtr Process, + [In] IntPtr BaseAddress, + [Out] void* Buffer, + [In] int Size, + [Out] out int BytesRead + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool WriteProcessMemory( + [In] IntPtr Process, + [In] IntPtr BaseAddress, + [In] byte[] Buffer, + [In] int Size, + [Out] out int BytesWritten + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public unsafe static extern bool WriteProcessMemory( + [In] IntPtr Process, + [In] IntPtr BaseAddress, + [In] void* Buffer, + [In] int Size, + [Out] out int BytesWritten + ); + + #endregion + + #region Misc. + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetProcessShutdownParameters( + [In] int Level, + [In] int Flags + ); + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ExitWindowsEx( + [In] ExitWindowsFlags flags, + [In] int reason + ); + + [DllImport("powrprof.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetSuspendState( + [In] bool hibernate, + [In] bool forceCritical, + [In] bool disableWakeEvent + ); + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool LockWorkStation(); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool QueryPerformanceFrequency( + [Out] out long PerformanceFrequency + ); + + [DllImport("kernel32.dll")] + public static extern int GetTickCount(); + + #endregion + + #region Named Pipes + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ConnectNamedPipe( + [In] IntPtr NamedPipe, + [Optional] IntPtr Overlapped + ); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr CreateNamedPipe( + [In] string Name, + [In] PipeAccessMode OpenMode, + [In] PipeMode PipeMode, + [In] int MaxInstances, + [In] int OutBufferSize, + [In] int InBufferSize, + [In] int DefaultTimeOut, + [In] [Optional] IntPtr SecurityAttributes + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DisconnectNamedPipe( + [In] IntPtr NamedPipe + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetNamedPipeClientProcessId( + [In] IntPtr NamedPipeHandle, + [Out] out int ServerProcessId + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetNamedPipeHandleState( + [In] IntPtr NamedPipeHandle, + [Out] [Optional] out PipeState State, + [Out] [Optional] out int CurInstances, + [Out] [Optional] out int MaxCollectionCount, + [Out] [Optional] out int CollectDataTimeout, + [Out] [Optional] out int UserName, + [In] int MaxUserNameSize + ); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool WaitNamedPipe( + [In] string Name, + [In] int Timeout + ); + + #endregion + + #region Network + + /// + /// Allows an application to check if a connection to the Internet can be established. + /// + /// A string that specifies the URL to use for checking the connection. + /// Forces a connection, must be 1. + /// This parameter is reserved and must be 0. + /// + [DllImport("wininet.dll", SetLastError = true, CharSet = CharSet.Auto)] + [return: MarshalAs(UnmanagedType.Bool)] + public extern static bool InternetCheckConnection( + [In] string Url, + [In] int Flags, + [In] int Reserved + ); + + /// + /// The NdfCancelIncident function is used to cancel unneeded functions which have been previously called on an existing incident. + /// + /// Before using this API, an application must call an incident creation function such as NdfCreateWebIncident. + /// NdfCloseIncident should be used to close an incident once it has been resolved, as NdfCancelIncident does not actually close the incident itself. + /// + /// A handle to the Network Diagnostics Framework incident. + /// This handle should match the handle of an existing incident. + /// A HResult value indicating the result + [DllImport("ndfapi.dll")] + public static extern HResult NdfCancelIncident( + [In] IntPtr NdfHandle + ); + + /// + /// The NdfCloseIncident function is used to close an Network Diagnostics Framework (NDF) incident following its resolution. + /// + /// The handle to the NDF incident that is being closed. + /// A HResult value indicating the result + [DllImport("ndfapi.dll")] + public static extern HResult NdfCloseIncident( + [In] IntPtr NdfHandle + ); + + /// + /// The NdfCreateConnectivityIncident function diagnoses generic internet connectivity problems. + /// + /// The handle to the Network Diagnostics Framework incident. + /// A HResult value indicating the result + [DllImport("ndfapi.dll")] + public static extern HResult NdfCreateConnectivityIncident( + [In, Out] ref IntPtr NdfHandle + ); + + /// + /// The NdfCreateInboundIncident function creates a session to diagnose inbound connectivity for a specific application or service. + /// + /// The fully qualified path to the application receiving the inbound traffic. + /// The Windows service receiving the inbound traffic. + /// The SID for the application receiving the traffic. If NULL, the caller's SID is automatically used. + /// A SOCKADDR_STORAGE structure which limits the diagnosis to traffic to a specific IP address. If NULL, all traffic will be included in the diagnosis + /// The protocol which should be diagnosed. For example, IPPROTO_TCP would be used to indicate the TCP/IP protocol. + /// The Inbound flags for specifying the type of options to preform during diagnostics. + /// Pointer to a handle to the Network Diagnostics Framework incident. + /// A HResult value indicating the result + [DllImport("ndfapi.dll", CharSet = CharSet.Unicode)] + public static extern HResult NdfCreateInboundIncident( + [In, Optional] string applicationID, + [In, Optional] string serviceID, + [In, Optional] int userID, //Incorrect + [In, Optional] int localTarget, //Incorrect + int protocol, //Incorrect + int dwFlags, //IsUnum: NDF_INBOUND_FLAG + [In, Out] ref IntPtr NdfHandle + ); + + /// + /// The NdfCreateDNSIncident function diagnoses name resolution issues in resolving a specific host name. + /// + /// The host name with which there is a name resolution issue. + /// The numeric representation of the type of record that was queried when the issue occurred. + /// A handle to the Network Diagnostics Framework incident. + /// A HResult value indicating the result + [DllImport("ndfapi.dll", CharSet = CharSet.Unicode)] + public static extern HResult NdfCreateDNSIncident( + [In] string hostname, + ushort querytype, //enum value: see the windns.h header file + [In, Out] ref IntPtr NdfHandle + ); + + /// + /// The NdfCreateSharingIncident function diagnoses network problems in accessing a specific network share. + /// + /// The full UNC string (for example, "\\server\folder\file.ext")for the shared asset with which there is a connectivity issue. + /// A handle to the Network Diagnostics Framework incident. + /// A HResult value indicating the result + [DllImport("ndfapi.dll", CharSet = CharSet.Unicode)] + public static extern HResult NdfCreateSharingIncident( + [In] string shareName, + [In, Out] ref IntPtr NdfHandle + ); + + /// + /// The NdfCreateWebIncident function diagnoses web connectivity problems concerning a specific URL. + /// + /// The URL with which there is a connectivity issue. + /// A handle to the Network Diagnostics Framework incident. + /// A HResult value indicating the result + [DllImport("ndfapi.dll", CharSet = CharSet.Unicode)] + public static extern HResult NdfCreateWebIncident( + [In] string url, + [In, Out] ref IntPtr NdfHandle + ); + + /// + /// The NdfCreateWebIncidentEx function diagnoses web connectivity problems concerning a specific URL. This function allows for more control over the underlying diagnosis than the NdfCreateWebIncident function. + /// + /// The URL with which there is a connectivity issue. + /// If TRUE, diagnosis is performed using the WinHTTP APIs. Otherwise, the WinInet APIs are used. + /// The module name to use when checking against application-specific filtering rules (for example, "C:\Program Files\Internet Explorer\iexplorer.exe"). If NULL, the value is autodetected during the diagnosis. + /// A handle to the Network Diagnostics Framework incident. + /// A HResult value indicating the result + [DllImport("ndfapi.dll", CharSet = CharSet.Unicode)] + public static extern HResult NdfCreateWebIncidentEx( + [In] string url, + [MarshalAs(UnmanagedType.Bool)] + [In] bool useWinHTTP, + [In] string moduleName, + [In, Out] ref IntPtr NdfHandle + ); + + /// + /// The NdfExecuteDiagnosis function is used to diagnose the root cause of the incident that has occurred. + /// + /// A handle to the Network Diagnostics Framework incident. + /// The handle to the window that is intended to display the diagnostic information. If specified, the NDF UI is modal to the window. If NULL, the UI is non-modal. + /// A HResult value indicating the result + [DllImport("ndfapi.dll")] + public static extern HResult NdfExecuteDiagnosis( + [In] IntPtr NdfHandle, + [In] IntPtr hwnd + ); + + /// + /// The NdfGetTraceFile function is used to retrieve the path containing an Event Trace Log (ETL) file that contains Event Tracing for Windows (ETW) events from a diagnostic session. + /// + /// A handle to a Network Diagnostics Framework incident. This handle should match the handle of an existing incident. + /// Pointer to a string that contains the location of the trace file. + /// A HResult value indicating the result + [DllImport("ndfapi.dll", CharSet = CharSet.Unicode)] + public static extern HResult NdfGetTraceFile( + [In] IntPtr NdfHandle, + [Out] string TraceFileLocation + ); + + #endregion + + #region Private Namespaces + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool AddSIDToBoundaryDescriptor( + ref IntPtr BoundaryDescriptor, + [In] IntPtr RequiredSid + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool ClosePrivateNamespace( + [In] IntPtr PrivateNamespaceHandle, + [In] PrivateNamespaceFlags Flags + ); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr CreateBoundaryDescriptor( + [In] string Name, + [In] int Flags + ); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr CreatePrivateNamespace( + [In] IntPtr PrivateNamespaceAttributes, + [In] IntPtr BoundaryDescriptor, + [In] string AliasPrefix + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern void DeleteBoundaryDescriptor( + [In] IntPtr BoundaryDescriptor + ); + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr OpenPrivateNamespace( + [In] IntPtr BoundaryDescriptor, + [In] string AliasPrefix + ); + + #endregion + + #region Processes + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern void ExitProcess( + [In] int ExitCode + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool QueryProcessCycleTime( + [In] IntPtr ProcessHandle, + [Out] out ulong CycleTime + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetPriorityClass( + [In] IntPtr ProcessHandle, + [In] ProcessPriorityClassWin32 Priority + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern ProcessPriorityClassWin32 GetPriorityClass( + [In] IntPtr ProcessHandle + ); + + [DllImport("psapi.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool EmptyWorkingSet( + [In] IntPtr ProcessHandle + ); + + [DllImport("psapi.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern int GetMappedFileName( + [In] IntPtr ProcessHandle, + [In] IntPtr Address, + [Out] StringBuilder Buffer, + [In] int Size + ); + + [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool CreateProcessWithTokenW( + [In] IntPtr TokenHandle, + [In] LogonFlags Flags, + [In] [Optional] string ApplicationName, + [Optional] string CommandLine, + [In] ProcessCreationFlags CreationFlags, + [In] [Optional] int Environment, + [In] [Optional] string CurrentDirectory, + [In] ref StartupInfo StartupInfo, + [Out] out ProcessInformation ProcessInfo + ); + + [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool CreateProcessAsUser( + [In] [Optional] IntPtr TokenHandle, + [In] [Optional] string ApplicationName, + [Optional] string CommandLine, + [In] [Optional] IntPtr ProcessAttributes, + [In] [Optional] IntPtr ThreadAttributes, + [In] bool InheritHandles, + [In] ProcessCreationFlags CreationFlags, + [In] [Optional] IntPtr Environment, + [In] [Optional] string CurrentDirectory, + [In] ref StartupInfo StartupInfo, + [Out] out ProcessInformation ProcessInformation + ); + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool CreateProcess( + [In] [Optional] string ApplicationName, + [Optional] string CommandLine, + [In] [Optional] IntPtr ProcessAttributes, + [In] [Optional] IntPtr ThreadAttributes, + [In] bool InheritHandles, + [In] ProcessCreationFlags CreationFlags, + [In] [Optional] IntPtr Environment, + [In] [Optional] string CurrentDirectory, + [In] ref StartupInfo StartupInfo, + [Out] out ProcessInformation ProcessInformation + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetExitCodeProcess( + [In] IntPtr ProcessHandle, + [Out] out int ExitCode + ); + + // Vista and higher + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool QueryFullProcessImageName( + [In] IntPtr ProcessHandle, + [In] [MarshalAs(UnmanagedType.Bool)] bool UseNativeName, + [Out] StringBuilder ExeName, + ref int Size + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IsProcessInJob( + [In] IntPtr ProcessHandle, + [In] [Optional] IntPtr JobHandle, + [Out] [MarshalAs(UnmanagedType.Bool)] out bool Result + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetProcessAffinityMask( + [In] IntPtr ProcessHandle, + [In] IntPtr ProcessAffinityMask + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetProcessAffinityMask( + [In] IntPtr ProcessHandle, + [Out] out IntPtr ProcessAffinityMask, + [Out] out IntPtr SystemAffinityMask + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool CheckRemoteDebuggerPresent( + [In] IntPtr ProcessHandle, + [MarshalAs(UnmanagedType.Bool)] ref bool DebuggerPresent + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern int GetProcessId( + [In] IntPtr ProcessHandle + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern int GetCurrentProcessId(); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetProcessDEPPolicy( + [In] IntPtr ProcessHandle, + [Out] out DepFlags Flags, + [Out] [MarshalAs(UnmanagedType.Bool)] out bool Permanent + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool TerminateProcess( + [In] IntPtr ProcessHandle, + [In] int ExitCode + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern IntPtr OpenProcess( + [In] ProcessAccess DesiredAccess, + [In] bool InheritHandle, + [In] int ProcessId + ); + + [DllImport("psapi.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool EnumProcessModules( + [In] IntPtr ProcessHandle, + [Out] IntPtr[] ModuleHandles, + [In] int Size, + [Out] out int RequiredSize + ); + + [DllImport("psapi.dll", CharSet = CharSet.Unicode)] + public static extern int GetModuleBaseName( + [In] IntPtr ProcessHandle, + [In] [Optional] IntPtr ModuleHandle, + [Out] StringBuilder BaseName, + [In] int Size + ); + + [DllImport("psapi.dll", CharSet = CharSet.Unicode)] + public static extern int GetModuleFileNameEx( + [In] IntPtr ProcessHandle, + [In] [Optional] IntPtr ModuleHandle, + [Out] StringBuilder FileName, + [In] int Size + ); + + [DllImport("psapi.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetModuleInformation( + [In] IntPtr ProcessHandle, + [In] [Optional] IntPtr ModuleHandle, + [Out] ModuleInfo ModInfo, + [In] int Size + ); + + #endregion + + #region Resources/Handles + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr CreateMutex( + [In] [Optional] IntPtr attributes, + [In] bool initialOwner, + [In] [Optional] string name + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetHandleInformation( + [In] IntPtr handle, + [In] Win32HandleFlags mask, + [In] Win32HandleFlags flags + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetHandleInformation( + [In] IntPtr handle, + [Out] out Win32HandleFlags flags + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool CloseHandle( + [In] IntPtr Handle + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern WaitResult WaitForSingleObject( + [In] IntPtr Object, + [In] uint Timeout + ); + + #endregion + + #region Security + + [DllImport("advapi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool CreateWellKnownSid( + [In] WellKnownSidType WellKnownSidType, + [In] [Optional] IntPtr DomainSid, + [In] IntPtr Sid, + ref int SidSize + ); + + [DllImport("advapi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool EqualDomainSid( + [In] IntPtr Sid1, + [In] IntPtr Sid2, + [Out] [MarshalAs(UnmanagedType.Bool)] out bool Equal + ); + + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ConvertStringSidToSid( + [In] string StringSid, + [Out] out IntPtr Sid + ); + + [DllImport("aclui.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool EditSecurity( + [In] IntPtr hWnd, + [MarshalAs(UnmanagedType.Interface)] + [In] ISecurityInformation SecurityInformation + ); + + [DllImport("advapi32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetSecurityDescriptorDacl( + [In] IntPtr SecurityDescriptor, + [MarshalAs(UnmanagedType.Bool)] + [Out] out bool DaclPresent, + [Out] out IntPtr Dacl, + [MarshalAs(UnmanagedType.Bool)] + [Out] out bool DaclDefaulted + ); + + [DllImport("advapi32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetSecurityDescriptorGroup( + [In] IntPtr SecurityDescriptor, + [Out] out IntPtr Group, + [MarshalAs(UnmanagedType.Bool)] + [Out] out bool GroupDefaulted + ); + + [DllImport("advapi32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetSecurityDescriptorOwner( + [In] IntPtr SecurityDescriptor, + [Out] out IntPtr Owner, + [MarshalAs(UnmanagedType.Bool)] + [Out] out bool OwnerDefaulted + ); + + [DllImport("advapi32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetSecurityDescriptorSacl( + [In] IntPtr SecurityDescriptor, + [MarshalAs(UnmanagedType.Bool)] + [Out] out bool SaclPresent, + [Out] out IntPtr Sacl, + [MarshalAs(UnmanagedType.Bool)] + [Out] out bool SaclDefaulted + ); + + [DllImport("advapi32.dll")] + public static extern Win32Error GetSecurityInfo( + [In] IntPtr Handle, + [In] SeObjectType ObjectType, + [In] SecurityInformation SecurityInformation, + [Out] [Optional] out IntPtr OwnerSid, + [Out] [Optional] out IntPtr GroupSid, + [Out] [Optional] out IntPtr Dacl, + [Out] [Optional] out IntPtr Sacl, + [Out] [Optional] out IntPtr SecurityDescriptor + ); + + [DllImport("advapi32.dll")] + public static extern Win32Error SetSecurityInfo( + [In] IntPtr Handle, + [In] SeObjectType ObjectType, + [In] SecurityInformation SecurityInformation, + [In] [Optional] IntPtr OwnerSid, + [In] [Optional] IntPtr GroupSid, + [In] [Optional] IntPtr Dacl, + [In] [Optional] IntPtr Sacl + ); + + [DllImport("advapi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ImpersonateLoggedOnUser( + [In] IntPtr TokenHandle + ); + + [DllImport("advapi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool RevertToSelf(); + + [DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool LogonUser( + [In] string Username, + [In] [Optional] string Domain, + [In] string Password, + [In] LogonType LogonType, + [In] LogonProvider LogonProvider, + [Out] out IntPtr TokenHandle + ); + + [DllImport("advapi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool OpenProcessToken( + [In] IntPtr ProcessHandle, + [In] TokenAccess DesiredAccess, + [Out] out IntPtr TokenHandle + ); + + [DllImport("advapi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool OpenThreadToken( + [In] IntPtr ThreadHandle, + [In] TokenAccess DesiredAccess, + [In] bool OpenAsSelf, + [Out] out IntPtr TokenHandle + ); + + [DllImport("advapi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DuplicateTokenEx( + [In] IntPtr ExistingToken, + [In] TokenAccess DesiredAccess, + [In] [Optional] IntPtr TokenAttributes, + [In] SecurityImpersonationLevel ImpersonationLevel, + [In] TokenType TokenType, + [Out] out IntPtr NewToken + ); + + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetTokenInformation( + [In] IntPtr TokenHandle, + [In] TokenInformationClass TokenInformationClass, + [In] ref int TokenInformation, + [In] int TokenInformationLength + ); + + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetTokenInformation( + [In] IntPtr TokenHandle, + [In] TokenInformationClass TokenInformationClass, + [Out] [Optional] IntPtr TokenInformation, + [In] int TokenInformationLength, + [Out] out int ReturnLength + ); + + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetTokenInformation( + [In] IntPtr TokenHandle, + [In] TokenInformationClass TokenInformationClass, + [Out] out int TokenInformation, + [In] int TokenInformationLength, + [Out] out int ReturnLength + ); + + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetTokenInformation( + [In] IntPtr TokenHandle, + [In] TokenInformationClass TokenInformationClass, + [Out] out IntPtr TokenInformation, + [In] int TokenInformationLength, + [Out] out int ReturnLength + ); + + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetTokenInformation( + [In] IntPtr TokenHandle, + [In] TokenInformationClass TokenInformationClass, + [Optional] out TokenSource TokenInformation, + [In] int TokenInformationLength, + [Out] out int ReturnLength + ); + + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetTokenInformation( + [In] IntPtr TokenHandle, + [In] TokenInformationClass TokenInformationClass, + [Optional] out TokenStatistics TokenInformation, + [In] int TokenInformationLength, + [Out] out int ReturnLength + ); + + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool LookupAccountName( + [In] [Optional] string SystemName, + [In] string AccountName, + [In] [Optional] IntPtr Sid, + ref int SidSize, + [Out] [Optional] StringBuilder ReferencedDomainName, + ref int ReferencedDomainNameSize, + [Out] out SidNameUse Use + ); + + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool LookupAccountSid( + [In] [Optional] string SystemName, + [In] IntPtr Sid, + [Out] [Optional] StringBuilder Name, + ref int NameSize, + [Out] [Optional] StringBuilder ReferencedDomainName, + ref int ReferencedDomainNameSize, + [Out] out SidNameUse Use + ); + + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool LookupPrivilegeDisplayName( + [In] [Optional] string SystemName, + [In] string Name, + [Out] [Optional] StringBuilder DisplayName, + ref int DisplayNameSize, + [Out] out int LanguageId + ); + + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool LookupPrivilegeName( + [In] [Optional] string SystemName, + [In] ref Luid Luid, + [Out] [Optional] StringBuilder Name, + ref int RequiredSize + ); + + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool LookupPrivilegeValue( + [In] [Optional] string SystemName, + [In] string PrivilegeName, + [Out] out Luid Luid + ); + + [DllImport("advapi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool AdjustTokenGroups( + [In] IntPtr TokenHandle, + [In] [MarshalAs(UnmanagedType.Bool)] bool ResetToDefault, + [In] [Optional] ref TokenGroups NewState, + [In] int BufferLength, + [Out] [Optional] IntPtr PreviousState, + [Out] [Optional] IntPtr ReturnLength + ); + + [DllImport("advapi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool AdjustTokenPrivileges( + [In] IntPtr TokenHandle, + [In] [MarshalAs(UnmanagedType.Bool)] bool DisableAllPrivileges, + [In] [Optional] ref TokenPrivileges NewState, + [In] int BufferLength, + [Out] [Optional] IntPtr PreviousState, + [Out] [Optional] IntPtr ReturnLength + ); + + [DllImport("advapi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool InitializeSecurityDescriptor( + IntPtr SecurityDescriptor, + [In] int Revision + ); + + [DllImport("advapi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetSecurityDescriptorDacl( + IntPtr SecurityDescriptor, + [In] [MarshalAs(UnmanagedType.Bool)] bool DaclPresent, + [In] [Optional] IntPtr Dacl, + [In] [MarshalAs(UnmanagedType.Bool)] bool DaclDefaulted + ); + + #endregion + + #region Services + + [DllImport("advapi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool CloseServiceHandle( + [In] IntPtr ServiceHandle + ); + + [DllImport("advapi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool StartService( + [In] IntPtr Service, + [In] int NumServiceArgs, + [In] [Optional] string[] Args + ); + + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ChangeServiceConfig( + [In] IntPtr Service, + [In] ServiceType ServiceType, + [In] ServiceStartType StartType, + [In] ServiceErrorControl ErrorControl, + [In] [Optional] string BinaryPath, + [In] [Optional] string LoadOrderGroup, + [Out] [Optional] IntPtr TagId, + [In] [Optional] string Dependencies, + [In] [Optional] string StartName, + [In] [Optional] string Password, + [In] [Optional] string DisplayName + ); + + [DllImport("advapi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ControlService( + [In] IntPtr Service, + [In] ServiceControl Control, + [Out] out ServiceStatus ServiceStatus + ); + + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr CreateService( + [In] IntPtr SCManager, + [In] string ServiceName, + [In] [Optional] string DisplayName, + [In] ServiceAccess DesiredAccess, + [In] ServiceType ServiceType, + [In] ServiceStartType StartType, + [In] ServiceErrorControl ErrorControl, + [In] [Optional] string BinaryPathName, + [In] [Optional] string LoadOrderGroup, + [Out] [Optional] IntPtr TagId, + [In] [Optional] IntPtr Dependencies, + [In] [Optional] string ServiceStartName, + [In] [Optional] string Password + ); + + [DllImport("advapi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DeleteService( + [In] IntPtr Service + ); + + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool QueryServiceStatus( + [In] IntPtr Service, + [Out] out ServiceStatus ServiceStatus + ); + + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool QueryServiceStatusEx( + [In] IntPtr Service, + [In] int InfoLevel, + [Out] [Optional] out ServiceStatusProcess ServiceStatus, + [In] int BufferSize, + [Out] out int BytesNeeded + ); + + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool QueryServiceConfig( + [In] IntPtr Service, + [Out] [Optional] IntPtr ServiceConfig, + [In] int BufferSize, + [Out] out int BytesNeeded + ); + + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool QueryServiceConfig2( + [In] IntPtr Service, + [In] ServiceInfoLevel InfoLevel, + [Out] [Optional] IntPtr Buffer, + [In] int BufferSize, + [Out] out int ReturnLength + ); + + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr OpenService( + [In] IntPtr SCManager, + [In] string ServiceName, + [In] ServiceAccess DesiredAccess + ); + + /// + /// Enumerates services in the specified service control manager database. + /// The name and status of each service are provided, along with additional + /// data based on the specified information level. + /// + /// A handle to the service control manager database. + /// Set this to 0. + /// The type of services to be enumerated. + /// The state of the services to be enumerated. + /// A pointer to the buffer that receives the status information. + /// The size of the buffer pointed to by the Services parameter, in bytes. + /// A pointer to a variable that receives the number of bytes needed to + /// return the remaining service entries, if the buffer is too small. + /// A pointer to a variable that receives the number of service + /// entries returned. + /// A pointer to a variable that, on input, specifies the + /// starting point of enumeration. You must set this value to zero the first time the + /// EnumServicesStatusEx function is called. + /// Must be 0 for this definition. + /// A non-zero value for success, zero for failure. + [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool EnumServicesStatusEx( + [In] IntPtr SCManager, + [In] IntPtr InfoLevel, + [In] ServiceQueryType ServiceType, + [In] ServiceQueryState ServiceState, + [Out] [Optional] IntPtr Services, + [In] int BufSize, + [Out] out int BytesNeeded, + [Out] out int ServicesReturned, + ref int ResumeHandle, + [In] [Optional] string GroupName + ); + + [DllImport("advapi32.dll", SetLastError = true)] + public static extern IntPtr OpenSCManager( + [In] [Optional] string MachineName, + [In] [Optional] string DatabaseName, + [In] ScManagerAccess DesiredAccess + ); + + #endregion + + #region Shell + + [DllImport("shell32.dll", CharSet = CharSet.Unicode)] + public static extern int ShellAbout( + [In] [Optional] IntPtr hWnd, + [In] string App, + [In] [Optional] string OtherStuff, + [In] [Optional] IntPtr IconHandle + ); + + [DllImport("shell32.dll", EntryPoint = "#61", CharSet = CharSet.Unicode)] + public static extern int RunFileDlg( + [In] IntPtr hWnd, + [In] IntPtr Icon, + [In] string Path, + [In] string Title, + [In] string Prompt, + [In] RunFileDialogFlags Flags + ); + + [DllImport("shell32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ShellExecuteEx( + [MarshalAs(UnmanagedType.Struct)] ref ShellExecuteInfo s + ); + + [DllImport("user32.dll", SetLastError = true)] + public static extern IntPtr SetWindowsHookEx( + [In] int HookId, + [In] IntPtr HookFunction, + [In] IntPtr Module, + [In] int ThreadId + ); + + [DllImport("shell32.dll")] + public extern static int ExtractIconEx( + [In] string libName, + [In] int iconIndex, + [Out] IntPtr[] largeIcon, + [Out] IntPtr[] smallIcon, + [In] int nIcons + ); + + [DllImport("shell32.dll")] + public static extern int SHGetFileInfo( + [In] string pszPath, + [In] uint dwFileAttributes, + [Out] out ShFileInfo psfi, + [In] uint cbSizeFileInfo, + [In] uint uFlags); + + [DllImport("shell32.dll", EntryPoint = "#660")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool FileIconInit([In] bool RestoreCache); + + #endregion + + #region Statistics + + [DllImport("psapi.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetPerformanceInfo( + [Out] out PerformanceInformation PerformanceInformation, + [In] int Size + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetProcessTimes( + [In] IntPtr ProcessHandle, + [Out] out LargeInteger CreationTime, + [Out] out LargeInteger ExitTime, + [Out] out LargeInteger KernelTime, + [Out] out LargeInteger UserTime + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetProcessIoCounters( + [In] IntPtr ProcessHandle, + [Out] out IoCounters IoCounters + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetSystemTimes( + [Out] out LargeInteger IdleTime, + [Out] out LargeInteger KernelTime, + [Out] out LargeInteger UserTime + ); + + [DllImport("kernel32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetThreadTimes( + [In] IntPtr ThreadHandle, + [Out] out LargeInteger CreationTime, + [Out] out LargeInteger ExitTime, + [Out] out LargeInteger KernelTime, + [Out] out LargeInteger UserTime + ); + + #endregion + + #region Symbols/Stack Walking + + [DllImport("dbghelp.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool MiniDumpWriteDump( + [In] IntPtr ProcessHandle, + [In] int ProcessId, + [In] IntPtr FileHandle, + [In] MinidumpType DumpType, + [In] IntPtr ExceptionParam, + [In] IntPtr UserStreamParam, + [In] IntPtr CallbackParam + ); + + [DllImport("dbghelp.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool StackWalk64( + [In] MachineType MachineType, + [In] IntPtr ProcessHandle, + [In] IntPtr ThreadHandle, + ref StackFrame64 StackFrame, + [In] IntPtr ContextRecord, + [In] [Optional] ReadProcessMemoryProc64 ReadMemoryRoutine, + [In] [Optional] FunctionTableAccessProc64 FunctionTableAccessRoutine, + [In] [Optional] GetModuleBaseProc64 GetModuleBaseRoutine, + [In] [Optional] IntPtr TranslateAddress + ); + + [DllImport("dbghelp.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool StackWalk64( + [In] MachineType MachineType, + [In] IntPtr ProcessHandle, + [In] IntPtr ThreadHandle, + ref StackFrame64 StackFrame, + ref Context ContextRecord, + [In] [Optional] ReadProcessMemoryProc64 ReadMemoryRoutine, + [In] [Optional] FunctionTableAccessProc64 FunctionTableAccessRoutine, + [In] [Optional] GetModuleBaseProc64 GetModuleBaseRoutine, + [In] [Optional] IntPtr TranslateAddress + ); + + [DllImport("dbghelp.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool StackWalk64( + [In] MachineType MachineType, + [In] IntPtr ProcessHandle, + [In] IntPtr ThreadHandle, + ref StackFrame64 StackFrame, + ref ContextAmd64 ContextRecord, + [In] [Optional] ReadProcessMemoryProc64 ReadMemoryRoutine, + [In] [Optional] FunctionTableAccessProc64 FunctionTableAccessRoutine, + [In] [Optional] GetModuleBaseProc64 GetModuleBaseRoutine, + [In] [Optional] IntPtr TranslateAddress + ); + + [DllImport("dbghelp.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SymCleanup( + [In] IntPtr ProcessHandle + ); + + [DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Ansi)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SymEnumSymbols( + [In] IntPtr ProcessHandle, + [In] ulong BaseOfDll, + [In] [Optional] string Mask, + [In] SymEnumSymbolsProc EnumSymbolsCallback, + [In] [Optional] IntPtr UserContext + ); + + [DllImport("dbghelp.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SymFromAddr( + [In] IntPtr ProcessHandle, + [In] ulong Address, + [Out] out ulong Displacement, + [In] IntPtr Symbol + ); + + [DllImport("dbghelp.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SymFromIndex( + [In] IntPtr ProcessHandle, + [In] ulong BaseOfDll, + [In] int Index, + IntPtr Symbol + ); + + [DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Ansi)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SymFromName( + [In] IntPtr ProcessHandle, + [In] string Name, + [In] IntPtr Symbol + ); + + [DllImport("dbghelp.dll", SetLastError = true)] + public static extern IntPtr SymFunctionTableAccess64( + [In] IntPtr ProcessHandle, + [In] ulong AddrBase + ); + + [DllImport("dbghelp.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SymGetLineFromAddr64( + [In] IntPtr ProcessHandle, + [In] ulong Address, + [Out] out int Displacement, + [Out] out ImagehlpLine64 Line + ); + + [DllImport("dbghelp.dll", SetLastError = true)] + public static extern ulong SymGetModuleBase64( + [In] IntPtr ProcessHandle, + [In] ulong Address + ); + + [DllImport("dbghelp.dll", SetLastError = true)] + public static extern SymbolOptions SymGetOptions(); + + [DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Ansi)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SymGetSearchPath( + [In] IntPtr ProcessHandle, + [Out] StringBuilder SearchPath, + [In] int SearchPathLength + ); + + [DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Ansi)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SymInitialize( + [In] IntPtr ProcessHandle, + [In] [Optional] string UserSearchPath, + [In] bool InvadeProcess + ); + + [DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Ansi)] + public static extern long SymLoadModule64( + [In] IntPtr ProcessHandle, + [In] [Optional] IntPtr FileHandle, + [In] [Optional] string ImageName, + [In] [Optional] string ModuleName, + [In] ulong BaseOfDll, + [In] int SizeOfDll + ); + + [DllImport("dbghelp.dll", SetLastError = true)] + public static extern SymbolOptions SymSetOptions( + [In] SymbolOptions SymOptions + ); + + [DllImport("dbghelp.dll", SetLastError = true, CharSet = CharSet.Ansi)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SymSetSearchPath( + [In] IntPtr ProcessHandle, + [In] [Optional] string SearchPath + ); + + [DllImport("dbghelp.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SymUnloadModule64( + [In] IntPtr ProcessHandle, + [In] ulong BaseOfDll + ); + + [DllImport("symsrv.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SymbolServerSetOptions( + [In] SymbolServerOption Options, + [In] ulong Data + ); + + #endregion + + #region TCP + + [DllImport("iphlpapi.dll", SetLastError = true)] + public extern static int SetTcpEntry( + [In] ref MibTcpRow TcpRow + ); + + [DllImport("iphlpapi.dll", SetLastError = true)] + public extern static int GetExtendedTcpTable( + [Out] IntPtr Table, + ref int Size, + [In] bool Order, + [In] AiFamily IpVersion, + [In] TcpTableClass TableClass, + [In] int Reserved + ); + + [DllImport("iphlpapi.dll", SetLastError = true)] + public extern static int GetTcpStatistics( + [Out] out MibTcpStats pStats + ); + + [DllImport("iphlpapi.dll", SetLastError = true)] + public static extern int GetTcpTable( + [Out] byte[] tcpTable, + ref int pdwSize, + [In] bool bOrder + ); + + [DllImport("iphlpapi.dll", SetLastError = true)] + public static extern int GetTcp6Table( + [Out] byte[] tcpTable, + ref int pdwSize, + [In] bool bOrder); + + [DllImport("iphlpapi.dll", SetLastError = true)] + public extern static int AllocateAndGetTcpExTableFromStack( + [Out] out IntPtr pTable, + [In] bool bOrder, + [In] IntPtr heap, + [In] int flags, + [In] int family + ); + + #endregion + + #region Terminal Server + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ProcessIdToSessionId( + [In] int ProcessId, + [Out] out int SessionId + ); + + [DllImport("wtsapi32.dll")] + public static extern void WTSCloseServer( + [In] IntPtr ServerHandle + ); + + [DllImport("wtsapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool WTSConnectSession( + [In] int LogonId, + [In] int TargetLogonId, + [In] string Password, + [In] bool Wait + ); + + [DllImport("wtsapi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool WTSDisconnectSession( + [In] IntPtr ServerHandle, + [In] int SessionId, + [In] bool Wait + ); + + [DllImport("wtsapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool WTSEnumerateProcesses( + [In] IntPtr ServerHandle, + [In] int Reserved, + [In] int Version, + [Out] out IntPtr ProcessInfo, + [Out] out int Count + ); + + [DllImport("wtsapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool WTSEnumerateSessions( + [In] IntPtr ServerHandle, + [In] int Reserved, + [In] int Version, + [Out] out IntPtr SessionInfo, + [Out] out int Count + ); + + [DllImport("wtsapi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool WTSFreeMemory( + [In] IntPtr Memory + ); + + [DllImport("wtsapi32.dll", SetLastError = true)] + public static extern int WTSGetActiveConsoleSessionId(); + + [DllImport("wtsapi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool WTSLogoffSession( + [In] IntPtr ServerHandle, + [In] int SessionId, + [In] bool Wait + ); + + [DllImport("wtsapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr WTSOpenServer( + [In] string ServerName + ); + + [DllImport("wtsapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool WTSQuerySessionInformation( + [In] IntPtr ServerHandle, + [In] int SessionId, + [In] WtsInformationClass InfoClass, + [Out] out IntPtr Buffer, + [Out] out int BytesReturned + ); + + [DllImport("wtsapi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool WTSRegisterSessionNotification( + [In] IntPtr hWnd, + [In] WtsNotificationFlags Flags + ); + + [DllImport("wtsapi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool WTSRegisterSessionNotificationEx( + [In] IntPtr ServerHandle, + [In] IntPtr hWnd, + [In] WtsNotificationFlags Flags + ); + + [DllImport("wtsapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool WTSSendMessage( + [In] IntPtr ServerHandle, + [In] int SessionId, + [In] string Title, + [In] int TitleLength, + [In] string Message, + [In] int MessageLength, + [In] int Style, + [In] int Timeout, + [Out] out DialogResult Response, + [In] bool Wait + ); + + [DllImport("wtsapi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool WTSShutdownSystem( + [In] IntPtr ServerHandle, + [In] WtsShutdownFlags ShutdownFlag + ); + + [DllImport("wtsapi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool WTSTerminateProcess( + [In] IntPtr ServerHandle, + [In] int ProcessId, + [In] int ExitCode + ); + + [DllImport("wtsapi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool WTSUnRegisterSessionNotification( + [In] IntPtr hWnd + ); + + [DllImport("wtsapi32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool WTSUnRegisterSessionNotificationEx( + [In] IntPtr ServerHandle, + [In] IntPtr hWnd + ); + + #endregion + + #region Threads + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool QueryThreadCycleTime( + [In] IntPtr ThreadHandle, + [Out] out ulong CycleTime + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool QueueUserAPC( + [In] IntPtr APC, + [In] IntPtr ThreadHandle, + [In] IntPtr Data + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool QueueUserAPC( + [MarshalAs(UnmanagedType.FunctionPtr)] + [In] ApcRoutine APC, + [In] IntPtr ThreadHandle, + [In] IntPtr Data + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetExitCodeThread( + [In] IntPtr ThreadHandle, + [Out] out int ExitCode + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetThreadPriority( + [In] IntPtr ThreadHandle, + [In] int Priority + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern int GetThreadPriority([In] IntPtr ThreadHandle); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern IntPtr CreateThread( + [In] [Optional] IntPtr ThreadAttributes, + [In] int StackSize, + [In] [MarshalAs(UnmanagedType.FunctionPtr)] ThreadStart StartAddress, + [In] IntPtr Parameter, + [In] int CreationFlags, + [Out] out int ThreadId + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern int GetProcessIdOfThread( + [In] IntPtr ThreadHandle + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern int GetThreadId( + [In] IntPtr ThreadHandle + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern IntPtr OpenThread( + [In] ThreadAccess DesiredAccess, + [In] bool InheritHandle, + [In] int ThreadId + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool TerminateThread( + IntPtr ThreadHandle, + [In] int ExitCode + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern int SuspendThread( + [In] IntPtr ThreadHandle + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern int ResumeThread( + [In] IntPtr ThreadHandle + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetThreadContext( + [In] IntPtr ThreadHandle, + [In] ref Context Context + ); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetThreadContext( + [In] IntPtr ThreadHandle, + ref Context Context + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern IntPtr CreateRemoteThread( + [In] IntPtr ProcessHandle, + [In] IntPtr ThreadAttributes, + [In] IntPtr StackSize, + [In] IntPtr StartAddress, + [In] IntPtr Parameter, + [In] ProcessCreationFlags CreationFlags, + [Out] out int ThreadId + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern int GetCurrentThreadId(); + + #endregion + + #region Toolhelp + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern IntPtr CreateToolhelp32Snapshot( + [In] SnapshotFlags dwFlags, + [In] int th32ProcessID + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool Process32First( + [In] IntPtr hSnapshot, + [MarshalAs(UnmanagedType.Struct)] ref ProcessEntry32 lppe + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool Process32Next( + [In] IntPtr hSnapshot, + [Out] [MarshalAs(UnmanagedType.Struct)] out ProcessEntry32 lppe + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool Thread32First( + [In] IntPtr hSnapshot, + [MarshalAs(UnmanagedType.Struct)] ref ThreadEntry32 lppe + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool Thread32Next( + [In] IntPtr hSnapshot, + [Out] [MarshalAs(UnmanagedType.Struct)] out ThreadEntry32 lppe + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool Module32First( + [In] IntPtr hSnapshot, + [MarshalAs(UnmanagedType.Struct)] ref ModuleEntry32 lppe + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool Module32Next( + [In] IntPtr hSnapshot, + [Out] [MarshalAs(UnmanagedType.Struct)] out ModuleEntry32 lppe + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool Heap32ListFirst( + [In] IntPtr hSnapshot, + [MarshalAs(UnmanagedType.Struct)] ref HeapList32 lppe + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool Heap32ListNext( + [In] IntPtr hSnapshot, + [Out] [MarshalAs(UnmanagedType.Struct)] out HeapList32 lppe + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool Heap32First( + [MarshalAs(UnmanagedType.Struct)] ref HeapEntry32 lppe, + [In] int ProcessID, + [In] IntPtr HeapID + ); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern int Heap32Next( + [Out] [MarshalAs(UnmanagedType.Struct)] out HeapEntry32 lppe + ); + + #endregion + + #region UDP + + [DllImport("iphlpapi.dll", SetLastError = true)] + public extern static int GetExtendedUdpTable( + [Out] IntPtr Table, + ref int Size, + [In] bool Order, + [In] AiFamily IpVersion, + [In] UdpTableClass TableClass, + [In] int Reserved + ); + + [DllImport("iphlpapi.dll", SetLastError = true)] + public static extern int GetUdpStatistics( + [Out] out MibUdpStats pStats + ); + + [DllImport("iphlpapi.dll", SetLastError = true)] + public static extern int GetUdpTable( + [Out] byte[] udpTable, + ref int pdwSize, + [In] bool bOrder + ); + + [DllImport("iphlpapi.dll", SetLastError = true)] + public extern static int AllocateAndGetUdpExTableFromStack( + [Out] out IntPtr pTable, + [In] bool bOrder, + [In] IntPtr heap, + [In] int flags, + [In] int family + ); + + #endregion + + #region User + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SwitchDesktop( + [In] IntPtr DesktopHandle + ); + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetUserObjectSecurity( + [In] IntPtr Handle, + [In] ref SiRequested SiRequested, + [In] IntPtr Sid + ); + + [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern IntPtr OpenDesktop( + [In] string Desktop, + [In] int Flags, + [In] bool Inherit, + [In] DesktopAccess DesiredAccess + ); + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool CloseDesktop( + [In] IntPtr Handle + ); + + [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern IntPtr OpenWindowStation( + [In] string WinSta, + [In] bool Inherit, + [In] WindowStationAccess DesiredAccess + ); + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool CloseWindowStation( + [In] IntPtr Handle + ); + + [DllImport("user32.dll", SetLastError = true)] + public static extern IntPtr GetThreadDesktop( + [In] int ThreadId + ); + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetThreadDesktop( + [In] IntPtr DesktopHandle + ); + + [DllImport("user32.dll", SetLastError = true)] + public static extern IntPtr GetProcessWindowStation(); + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetProcessWindowStation( + [In] IntPtr WindowStationHandle + ); + + [DllImport("userenv.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool CreateEnvironmentBlock( + [Out] out IntPtr Environment, + [In] IntPtr TokenHandle, + [In] bool Inherit + ); + + [DllImport("userenv.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + static extern bool LoadUserProfile( + [In] IntPtr TokenHandle, + ref ProfileInformation ProfileInfo + ); + + [DllImport("userenv.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + static extern bool UnloadUserProfile( + [In] IntPtr TokenHandle, + [In] IntPtr ProfileHandle + ); + + #endregion + + #region Windows + + [DllImport("user32.dll")] + public static extern bool EndTask( + [In] IntPtr hWnd, + [In] bool ShutDown, + [In] bool Force + ); + + [DllImport("user32.dll")] + public static extern bool UpdateWindow( + [In] IntPtr hWnd + ); + + [DllImport("user32.dll")] + public static extern bool MoveWindow( + [In] IntPtr hWnd, + [In] int X, + [In] int Y, + [In] int Width, + [In] int Height, + [In] bool Repaint + ); + + [DllImport("user32.dll")] + public static extern int GetSystemMetrics( + [In] int Index + ); + + [DllImport("user32.dll")] + public static extern bool InvalidateRect( + [In] IntPtr hWnd, + [In] IntPtr Rect, + [In] bool Erase + ); + + [DllImport("user32.dll")] + public static extern bool InvalidateRect( + [In] IntPtr hWnd, + [In] ref Rect Rect, + [In] bool Erase + ); + + [DllImport("user32.dll")] + public static extern bool RedrawWindow( + [In] IntPtr hWnd, + [In] IntPtr UpdateRect, + [In] IntPtr UpdateRgn, + [In] RedrawWindowFlags Flags + ); + + [DllImport("user32.dll")] + public static extern int ReleaseDC( + [In] IntPtr hWnd, + [In] IntPtr hDC + ); + + [DllImport("user32.dll")] + public static extern IntPtr GetWindowDC( + [In] IntPtr hWnd + ); + + [DllImport("user32.dll")] + public static extern IntPtr WindowFromPoint( + [In] Point location + ); + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetCursorPos( + [Out] out Point location + ); + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ChangeWindowMessageFilter( + [In] WindowMessage message, + [In] UipiFilterFlag flag + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern IntPtr SendMessage( + [In] IntPtr hWnd, + [In] WindowMessage msg, + [In] int w, + [In] int l + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern IntPtr SendMessageTimeout( + [In] IntPtr hWnd, + [In] WindowMessage msg, + [In] int w, + [In] int l, + [In] SmtoFlags flags, + [In] int timeout, + [Out] out int result + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern bool PostMessage( + [In] IntPtr hWnd, + [In] WindowMessage msg, + [In] int w, + [In] int l + ); + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetForegroundWindow( + [In] IntPtr hWnd + ); + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool AllowSetForegroundWindow( + [In] int processId + ); + + [DllImport("uxtheme.dll", CharSet = CharSet.Unicode)] + public static extern HResult SetWindowTheme( + [In] IntPtr hWnd, + [In] string appName, + [In] string idList + ); + + [DllImport("user32.dll")] + public static extern int GetGuiResources( + [In] IntPtr ProcessHandle, + [In] int UserObjects + ); + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DestroyIcon( + [In] IntPtr Handle + ); + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool BringWindowToTop( + [In] IntPtr hWnd + ); + + [DllImport("user32.dll")] + public static extern bool EnumWindows( + [In] [MarshalAs(UnmanagedType.FunctionPtr)] EnumWindowsProc Callback, + [In] int param + ); + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool EnumThreadWindows( + [In] int ThreadId, + [In] [MarshalAs(UnmanagedType.FunctionPtr)] EnumThreadWndProc callback, + [In] int Param + ); + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool EnumChildWindows( + [In] IntPtr hWnd, + [In] [MarshalAs(UnmanagedType.FunctionPtr)] EnumChildProc callback, + [In] int param + ); + + [DllImport("user32.dll")] + public static extern int GetWindowThreadProcessId( + [In] IntPtr hWnd, + [Out] out int processId + ); + + [DllImport("user32.dll")] + public static extern IntPtr SetActiveWindow( + [In] IntPtr hWnd + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool PeekMessage( + [Out] out Message msg, + [In] IntPtr hWnd, + [In] uint messageFilterMin, + [In] uint messageFilterMax, + [In] PeekMessageFlags flags + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool TranslateMessage( + [In] ref Message msg + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern IntPtr DispatchMessage( + [In] ref Message msg + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern IntPtr DefWindowProc( + [In] IntPtr hWnd, + [In] WindowMessage msg, + [In] IntPtr wParam, + [In] IntPtr lParam + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern void PostQuitMessage( + [In] int exitCode + ); + +#if _WIN64 + [DllImport("user32.dll", SetLastError = true, EntryPoint = "SetWindowLongPtr", CharSet = CharSet.Auto)] +#else + [DllImport("user32.dll", SetLastError = true, EntryPoint = "SetWindowLong", CharSet = CharSet.Auto)] +#endif + private static extern IntPtr SetWindowLongPtr( + [In] IntPtr hWnd, + [In] GetWindowLongOffset Index, + [In] [MarshalAs(UnmanagedType.FunctionPtr)] WndProcDelegate WndProc + ); + +#if _WIN64 + [DllImport("user32.dll", SetLastError = true, EntryPoint = "SetWindowLongPtr", CharSet = CharSet.Auto)] +#else + [DllImport("user32.dll", SetLastError = true, EntryPoint = "SetWindowLong", CharSet = CharSet.Auto)] +#endif + public static extern IntPtr SetWindowLongPtr( + [In] IntPtr hWnd, + [In] GetWindowLongOffset Index, + [In] IntPtr NewLong + ); + +#if _WIN64 + [DllImport("user32.dll", SetLastError = true, EntryPoint = "GetWindowLongPtr", CharSet = CharSet.Auto)] +#else + [DllImport("user32.dll", SetLastError = true, EntryPoint = "GetWindowLong", CharSet = CharSet.Auto)] +#endif + public static extern IntPtr GetWindowLongPtr( + [In] IntPtr hWnd, + [In] GetWindowLongOffset Index + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetClientRect( + [In] IntPtr hWnd, + [Out] out Rect rect + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetWindowRect( + [In] IntPtr hWnd, + [Out] out Rect rect + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetWindowPos( + [In] IntPtr hWnd, + [In] IntPtr hWndAfter, + [In] int x, + [In] int y, + [In] int w, + [In] int h, + [In] uint flags + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ScreenToClient( + [In] IntPtr hWnd, + ref Point point + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern IntPtr SetFocus( + [In] IntPtr hWnd + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern IntPtr GetParent( + [In] IntPtr hWnd + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetMonitorInfo( + [In] IntPtr hWnd, + [Out] out MonitorInformation info + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern IntPtr MonitorFromWindow( + [In] IntPtr hWnd, + [In] uint flags + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern short GetAsyncKeyState( + [In] uint Key + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern IntPtr SetCapture( + [In] IntPtr handle + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ReleaseCapture(); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ShowWindow( + [In] IntPtr hWnd, + [In] ShowWindowType flags + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetMenu( + [In] IntPtr hWnd, + [In] IntPtr menuHandle + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool CloseWindow( + [In] IntPtr hWnd); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DestroyWindow( + [In] IntPtr hWnd + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IsIconic( + [In] IntPtr hWnd + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool AdjustWindowRect( + ref Rect rect, + [In] WindowStyles style, + [In] [MarshalAs(UnmanagedType.Bool)]bool menu + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern IntPtr RegisterClass( + [In] ref WindowClass wndClass + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool UnregisterClass( + [In] [MarshalAs(UnmanagedType.LPTStr)] string className, + [In] IntPtr instanceHandle + ); + + [DllImport("user32.dll", SetLastError = true, EntryPoint = "CreateWindowEx", CharSet = CharSet.Auto)] + public static extern IntPtr CreateWindow( + [In] int ExStyle, + [In] [MarshalAs(UnmanagedType.LPTStr)] string ClassName, + [In] [MarshalAs(UnmanagedType.LPTStr)] string WindowName, + [In] WindowStyles Style, + [In] int X, + [In] int Y, + [In] int Width, + [In] int Height, + [In] IntPtr Parent, + [In] IntPtr MenuHandle, + [In] IntPtr InstanceHandle, + [In] IntPtr Zero + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern int GetCaretBlinkTime(); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern int InternalGetWindowText( + [In] IntPtr hWnd, + [In] IntPtr String, + [In] int MaxCount + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern bool IsHungAppWindow( + [In] IntPtr hWnd + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern bool IsWindow( + [In] IntPtr hWnd + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern bool IsWindowVisible( + [In] IntPtr hWnd + ); + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool GetWindowPlacement( + [In] IntPtr hWnd, + ref WindowPlacement WindowPlacement + ); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + public static extern IntPtr FindWindow( + [In] string ClassName, + [In] string WindowName + ); + + [DllImport("user32.dll")] + public static extern IntPtr GetDesktopWindow(); + + [DllImport("user32.dll")] + public static extern IntPtr GetForegroundWindow(); + + [DllImport("user32.dll")] + public static extern IntPtr GetShellWindow(); + + #endregion + + #region Window Stations + + [DllImport("winsta.dll", SetLastError = true)] + public static extern bool WinStationRevertFromServicesSession(); + + [DllImport("winsta.dll", SetLastError = true)] + public static extern bool WinStationSwitchToServicesSession(); + + [DllImport("winsta.dll", SetLastError = true)] + public static extern bool WinStationTerminateProcess( + [In] IntPtr ServerHandle, + [In] int ProcessId, + [In] int ExitCode + ); + + #endregion + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Api/HResult.cs b/branches/ph-plugins/ProcessHacker.Native/Api/HResult.cs new file mode 100644 index 000000000..b91d0cb78 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Api/HResult.cs @@ -0,0 +1,109 @@ +/* + * Process Hacker - + * HResult values + * + * Copyright (C) 2009 wj32 + * Copyright (C) 2009 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 . + */ + +using System; +using System.Runtime.InteropServices; + +namespace ProcessHacker.Native.Api +{ + /*////////////////////////// + // // + // COM Error Codes // + // // + //////////////////////////// + // + // The return value of COM functions and methods is an HRESULT. + // This is not a handle to anything, but is merely a 32-bit value + // with several fields encoded in the value. The parts of an + // HRESULT are shown below. + // + // Many of the macros and functions below were orginally defined to + // operate on SCODEs. SCODEs are no longer used. The macros are + // still present for compatibility and easy porting of Win16 code. + // Newly written code should use the HRESULT macros and functions. + // + // HRESULTs are 32 bit values layed out as follows: + // + // 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 + // 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + // +-+-+-+-+-+---------------------+-------------------------------+ + // | S | R | C | N | r | Facility | Code | + // +-+-+-+-+-+---------------------+-------------------------------+ + // + // where + // + // S - Severity - indicates success/fail + // + // 0 - Success + // 1 - Fail (COERROR) + // + // R - reserved portion of the facility code, corresponds to NT's + // second severity bit. + // + // C - reserved portion of the facility code, corresponds to NT's + // C field. + // + // N - reserved portion of the facility code. Used to indicate a + // mapped NT status value. + // + // r - reserved portion of the facility code. Reserved for internal + // use. Used to indicate HRESULT values that are not status + // values, but are instead message ids for display strings. + // + // Facility - is the facility code + // + // Code - is the facility's status code + */ + + public enum HResult : uint + { + False = 0x0001, + OK = 0x0000, + Cancelled = 1223, + + Error = 0x80000000, + NoInterface = 0x80004002, + Fail = 0x80004005, + TypeElementNotFound = 0x8002802b, + NoObject = 0x800401e5, + OutOfMemory = 0x8007000e, + InvalidArgument = 0x80070057, + ResourceInUse = 0x800700aa, + ElementNotFound = 0x80070490 + } + + public static class HResultExtensions + { + public static bool IsError(this HResult result) + { + //Return != OK because there are come errors with lower values than HResult.False + return result != HResult.OK; + } + + public static void ThrowIf(this HResult result) + { + if (result.IsError()) + throw Marshal.GetExceptionForHR((int)result); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Api/ISecurityInformation.cs b/branches/ph-plugins/ProcessHacker.Native/Api/ISecurityInformation.cs new file mode 100644 index 000000000..4938bca58 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Api/ISecurityInformation.cs @@ -0,0 +1,80 @@ +/* + * Process Hacker - + * ISecurityInformation definition + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; + +namespace ProcessHacker.Native.Api +{ + [ComImport, Guid("965fc360-16ff-11d0-91cb-00aa00bbb723"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface ISecurityInformation + { + [PreserveSig] + HResult GetObjectInformation( + [Out] out SiObjectInfo ObjectInfo + ); + + [PreserveSig] + HResult GetSecurity( + [In] SecurityInformation RequestedInformation, + [Out] out IntPtr SecurityDescriptor, + [In] bool Default + ); + + [PreserveSig] + HResult SetSecurity( + [In] SecurityInformation SecurityInformation, + [In] IntPtr SecurityDescriptor + ); + + [PreserveSig] + HResult GetAccessRights( + [In] ref Guid ObjectType, + [In] SiObjectInfoFlags Flags, + [Out] out IntPtr Access, + [Out] out int Accesses, + [Out] out int DefaultAccess + ); + + [PreserveSig] + HResult MapGeneric( + [In] ref Guid ObjectType, + [In] ref AceFlags AceFlags, + [In] ref int Mask + ); + + [PreserveSig] + HResult GetInheritTypes( + [Out] out IntPtr InheritTypes, + [Out] out int InheritTypesCount + ); + + [PreserveSig] + HResult PropertySheetPageCallback( + [In] IntPtr hWnd, + [In] SiCallbackMessage Msg, + [In] SiPageType Page + ); + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Api/LsaEnums.cs b/branches/ph-plugins/ProcessHacker.Native/Api/LsaEnums.cs new file mode 100644 index 000000000..9dca920ef --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Api/LsaEnums.cs @@ -0,0 +1,120 @@ +/* + * Process Hacker - + * LSA enumerations + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; + +namespace ProcessHacker.Native.Api +{ + [Flags] + public enum LsaOperationalMode + { + PasswordProtected = 0x1, + IndividualAccounts = 0x2, + MandatoryAccess = 0x4, + LogFull = 0x8 + } + + public enum PolicyDomainInformationClass + { + PolicyDomainEfsInformation = 2, + PolicyDomainKerberosTicketInformation + } + + public enum PolicyInformationClass + { + PolicyAuditLogInformation = 1, + PolicyAuditEventsInformation, + PolicyPrimaryDomainInformation, + PolicyPdAccountInformation, + PolicyAccountDomainInformation, + PolicyLsaServerRoleInformation, + PolicyReplicaSourceInformation, + PolicyDefaultQuotaInformation, + PolicyModificationInformation, + PolicyAuditFullSetInformation, + PolicyAuditFullQueryInformation, + PolicyDnsDomainInformation, + PolicyDnsDomainInformationInt + } + + public enum PolicyNotificationInformationClass + { + PolicyNotifyAuditEventsInformation = 1, + PolicyNotifyAccountDomainInformation, + PolicyNotifyServerRoleInformation, + PolicyNotifyDnsDomainInformation, + PolicyNotifyDomainEfsInformation, + PolicyNotifyDomainKerberosTicketInformation, + PolicyNotifyMachineAccountPasswordInformation + } + + public enum SecurityLogonType + { + Interactive = 2, + Network, + Batch, + Service, + Proxy, + Unlock, + NetworkCleartext, + NewCredentials, + RemoteInteractive, + CachedInteractive, + CachedRemoteInteractive, + CachedUnlock + } + + [Flags] + public enum SecuritySystemAccess : int + { + Interactive = 0x1, + Network = 0x2, + Batch = 0x4, + Service = 0x10, + Proxy = 0x20, + DenyInteractive = 0x40, + DenyNetwork = 0x80, + DenyBatch = 0x100, + DenyService = 0x200, + RemoteInteractive = 0x400, + DenyRemoteInteractive = 0x800 + } + + public enum TrustedInformationClass + { + TrustedDomainNameInformation = 1, + TrustedControllersInformation, + TrustedPosixOffsetInformation, + TrustedPasswordInformation, + TrustedDomainInformationBasic, + TrustedDomainInformationEx, + TrustedDomainAuthInformation, + TrustedDomainFullInformation, + TrustedDomainAuthInformationInternal, + TrustedDomainFullInformationInternal, + TrustedDomainInformationEx2Internal, + TrustedDomainFullInformation2Internal + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Api/LsaFunctions.cs b/branches/ph-plugins/ProcessHacker.Native/Api/LsaFunctions.cs new file mode 100644 index 000000000..d982add5a --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Api/LsaFunctions.cs @@ -0,0 +1,501 @@ +/* + * Process Hacker - + * LSA functions + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Api +{ + public static partial class Win32 + { + /* Note: Be very careful about where these functions are + * imported from. Some come from advapi32.dll, others are + * from secur32.dll. + * + * An important side-effect is that ALL buffers allocated + * by secur32 functions MUST be freed with + * LsaFreeReturnBuffer, while advapi32-allocated buffers + * must be freed with LsaFreeMemory. + */ + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaAddAccountRights( + [In] IntPtr PolicyHandle, + [In] IntPtr AccountSid, // Sid* + [In] UnicodeString[] UserRights, + [In] int CountOfRights + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaAddPrivilegesToAccount( + [In] IntPtr AccountHandle, + [In] IntPtr Privileges // PrivilegeSet* + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaClearAuditLog( + [In] IntPtr PolicyHandle + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaClose( + [In] IntPtr ObjectHandle + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaChangePassword( + [In] ref UnicodeString ServerName, + [In] ref UnicodeString DomainName, + [In] ref UnicodeString AccountName, + [In] ref UnicodeString OldPassword, + [In] ref UnicodeString NewPassword + ); + + [DllImport("secur32.dll")] + public static extern NtStatus LsaConnectUntrusted( + [Out] out IntPtr LsaHandle + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaCreateAccount( + [In] IntPtr PolicyHandle, + [In] IntPtr AccountSid, // Sid* + [In] LsaAccountAccess DesiredAccess, + [Out] out IntPtr AccountHandle + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaCreateSecret( + [In] IntPtr PolicyHandle, + [In] ref UnicodeString SecretName, + [In] LsaSecretAccess DesiredAccess, + [Out] out IntPtr SecretHandle + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaCreateTrustedDomain( + [In] IntPtr PolicyHandle, + [In] ref LsaTrustInformation TrustedDomainInformation, + [In] LsaTrustedAccess DesiredAccess, + [Out] out IntPtr TrustedDomainHandle + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaDelete( + [In] IntPtr ObjectHandle + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaDeleteTrustedDomain( + [In] IntPtr PolicyHandle, + [In] IntPtr TrustedDomainSid // Sid* + ); + + [DllImport("secur32.dll")] + public static extern NtStatus LsaDeregisterLogonProcess( + [In] IntPtr LsaHandle + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaEnumerateAccounts( + [In] IntPtr PolicyHandle, + ref int EnumerationContext, + [Out] out IntPtr Buffer, // Sid*** + [In] int PreferredMaximumLength, + [Out] out int CountReturned + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaEnumerateAccountsWithUserRight( + [In] IntPtr PolicyHandle, + [In] [Optional] ref UnicodeString UserRight, + [Out] out IntPtr Buffer, // Sid*** + [Out] out int CountReturned + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaEnumerateAccountRights( + [In] IntPtr PolicyHandle, + [In] IntPtr AccountSid, // Sid* + [Out] IntPtr UserRights, // UnicodeString** + [Out] out int CountOfRights + ); + + [DllImport("secur32.dll")] + public static extern NtStatus LsaEnumerateLogonSessions( + [Out] out int LogonSessionCount, + [Out] out IntPtr LogonSessionList // Luid** + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaEnumeratePrivileges( + [In] IntPtr PolicyHandle, + ref int EnumerationContext, + [Out] out IntPtr Buffer, // PolicyPrivilegeDefinition** + [In] int PreferredMaximumLength, + [Out] out int CountReturned + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaEnumeratePrivilegesOfAccount( + [In] IntPtr AccountHandle, + [Out] out IntPtr Privileges // PrivilegeSet** + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaEnumerateTrustedDomains( + [In] IntPtr PolicyHandle, + ref int EnumerationContext, + [Out] out IntPtr Buffer, // LsaTrustInformation** + [In] int PreferredMaximumLength, + [Out] out int CountReturned + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaEnumerateTrustedDomainsEx( + [In] IntPtr PolicyHandle, + ref int EnumerationContext, + [Out] out IntPtr Buffer, // TrustedDomainInformationEx** + [In] int PreferredMaximumLength, + [Out] out int CountReturned + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaFreeMemory( + [In] IntPtr Buffer + ); + + [DllImport("secur32.dll")] + public static extern NtStatus LsaFreeReturnBuffer( + [In] IntPtr Buffer + ); + + [DllImport("secur32.dll")] + public static extern NtStatus LsaGetLogonSessionData( + [In] ref Luid LogonId, + [Out] out IntPtr LogonSessionData // SecurityLogonSessionData** + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaGetQuotasForAccount( + [In] IntPtr AccountHandle, + [Out] out QuotaLimits QuotaLimits + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaGetRemoteUserName( + [In] [Optional] ref UnicodeString SystemName, + [Out] out IntPtr UserName, // UnicodeString** + [Out] [Optional] out IntPtr DomainName // UnicodeString** + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaGetSystemAccessAccount( + [In] IntPtr AccountHandle, + [Out] out SecuritySystemAccess SystemAccess + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaGetUserName( + [Out] out IntPtr UserName, // UnicodeString** + [Out] [Optional] out IntPtr DomainName // UnicodeString** + ); + + [DllImport("secur32.dll")] + public static extern NtStatus LsaLookupAuthenticationPackage( + [In] IntPtr LsaHandle, + [In] ref AnsiString PackageName, + [Out] out int AuthenticationPackage + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaLookupNames( + [In] IntPtr PolicyHandle, + [In] int Count, + [In] UnicodeString[] Names, + [Out] out IntPtr ReferencedDomains, // LsaReferencedDomainList** + [Out] out IntPtr Sids // LsaTranslatedSid** + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaLookupNames2( + [In] IntPtr PolicyHandle, + [In] int Flags, + [In] int Count, + [In] UnicodeString[] Names, + [Out] out IntPtr ReferencedDomains, // LsaReferencedDomainList** + [Out] out IntPtr Sids // LsaTranslatedSid2** + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaLookupPrivilegeDisplayName( + [In] IntPtr PolicyHandle, + [In] ref UnicodeString Name, + [Out] out IntPtr DisplayName, // UnicodeString** + [Out] out short LanguageReturned + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaLookupPrivilegeName( + [In] IntPtr PolicyHandle, + [In] ref Luid Value, + [Out] out IntPtr Name // UnicodeString** + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaLookupPrivilegeValue( + [In] IntPtr PolicyHandle, + [In] ref UnicodeString Name, + [Out] out Luid Value + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaLookupSids( + [In] IntPtr PolicyHandle, + [In] int Count, + [In] IntPtr[] Sids, // Sid** + [Out] out IntPtr ReferencedDomains, // LsaReferencedDomainList** + [Out] out IntPtr Names // LsaTranslatedName** + ); + + [DllImport("advapi32.dll")] + public static extern int LsaNtStatusToWinError( + [In] NtStatus Status + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaOpenAccount( + [In] IntPtr PolicyHandle, + [In] IntPtr AccountSid, // Sid* + [In] LsaAccountAccess DesiredAccess, + [Out] out IntPtr AccountHandle + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaOpenPolicy( + [In] [Optional] ref UnicodeString SystemName, + [In] ref ObjectAttributes ObjectAttributes, + [In] LsaPolicyAccess DesiredAccess, + [Out] out IntPtr PolicyHandle + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaOpenPolicySce( + [In] [Optional] ref UnicodeString SystemName, + [In] ref ObjectAttributes ObjectAttributes, + [In] LsaPolicyAccess DesiredAccess, + [Out] out IntPtr PolicyHandle + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaOpenSecret( + [In] IntPtr PolicyHandle, + [In] ref UnicodeString SecretName, + [In] LsaSecretAccess DesiredAccess, + [Out] out IntPtr SecretHandle + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaOpenTrustedDomain( + [In] IntPtr PolicyHandle, + [In] IntPtr TrustedDomainSid, // Sid* + [In] LsaTrustedAccess DesiredAccess, + [Out] out IntPtr TrustedDomainHandle + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaOpenTrustedDomainByName( + [In] IntPtr PolicyHandle, + [In] ref UnicodeString TrustedDomainName, + [In] LsaTrustedAccess DesiredAccess, + [Out] out IntPtr TrustedDomainHandle + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaQueryDomainInformationPolicy( + [In] IntPtr PolicyHandle, + [In] PolicyDomainInformationClass InformationClass, + [Out] out IntPtr Buffer + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaQueryInformationPolicy( + [In] IntPtr PolicyHandle, + [In] PolicyInformationClass InformationClass, + [Out] out IntPtr Buffer + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaQueryInfoTrustedDomain( + [In] IntPtr TrustedDomainHandle, + [In] TrustedInformationClass InformationClass, + [Out] out IntPtr Buffer + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaQuerySecret( + [In] IntPtr SecretHandle, + [Out] [Optional] out IntPtr CurrentValue, // UnicodeString** + [Out] [Optional] out long CurrentValueSetTime, + [Out] [Optional] out IntPtr OldValue, // UnicodeString** + [Out] [Optional] out long OldValueSetTime + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaQuerySecurityObject( + [In] IntPtr ObjectHandle, + [In] SecurityInformation SecurityInformation, + [Out] out IntPtr SecurityDescriptor // SecurityDescriptor** + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaQueryTrustedDomainInfo( + [In] IntPtr PolicyHandle, + [In] IntPtr TrustedDomainSid, // Sid* + [In] TrustedInformationClass InformationClass, + [Out] out IntPtr Buffer + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaQueryTrustedDomainInfoByName( + [In] IntPtr PolicyHandle, + [In] ref UnicodeString TrustedDomainName, + [In] TrustedInformationClass InformationClass, + [Out] out IntPtr Buffer + ); + + [DllImport("secur32.dll")] + public static extern NtStatus LsaRegisterLogonProcess( + [In] ref AnsiString LogonProcessName, + [Out] out IntPtr LsaHandle, + [Out] out LsaOperationalMode SecurityMode + ); + + [DllImport("secur32.dll")] + public static extern NtStatus LsaRegisterPolicyChangeNotification( + [In] PolicyNotificationInformationClass InformationClass, + [In] IntPtr NotificationEventHandle + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaRemoveAccountRights( + [In] IntPtr PolicyHandle, + [In] IntPtr AccountSid, // Sid* + [In] bool AllRights, + [In] UnicodeString[] UserRights, + [In] int CountOfRights + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaRemovePrivilegesFromAccount( + [In] IntPtr AccountHandle, + [In] bool AllPrivileges, + [In] [Optional] IntPtr Privileges // PrivilegeSet* + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaRetrievePrivateData( + [In] IntPtr PolicyHandle, + [In] ref UnicodeString KeyName, + [Out] out IntPtr PrivateData // UnicodeString** + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaSetDomainInformationPolicy( + [In] IntPtr PolicyHandle, + [In] PolicyDomainInformationClass InformationClass, + [In] [Optional] IntPtr Buffer + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaSetInformationPolicy( + [In] IntPtr PolicyHandle, + [In] PolicyInformationClass InformationClass, + [In] IntPtr Buffer + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaSetInformationTrustedDomain( + [In] IntPtr TrustedDomainHandle, + [In] TrustedInformationClass InformationClass, + [In] IntPtr Buffer + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaSetQuotasForAccount( + [In] IntPtr AccountHandle, + [In] ref QuotaLimits QuotaLimits + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaSetSecret( + [In] IntPtr SecretHandle, + [In] [Optional] ref UnicodeString CurrentValue, + [In] [Optional] ref UnicodeString OldValue + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaSetSecurityObject( + [In] IntPtr ObjectHandle, + [In] SecurityInformation SecurityInformation, + [In] IntPtr SecurityDescriptor // SecurityDescriptor* + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaSetSystemAccessAccount( + [In] IntPtr AccountHandle, + [In] SecuritySystemAccess SystemAccess + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaSetTrustedDomainInformation( + [In] IntPtr PolicyHandle, + [In] IntPtr TrustedDomainSid, // Sid* + [In] TrustedInformationClass InformationClass, + [In] IntPtr Buffer + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaSetTrustedDomainInfoByName( + [In] IntPtr PolicyHandle, + [In] ref UnicodeString TrustedDomainName, + [In] TrustedInformationClass InformationClass, + [In] IntPtr Buffer + ); + + [DllImport("advapi32.dll")] + public static extern NtStatus LsaStorePrivateData( + [In] IntPtr PolicyHandle, + [In] ref UnicodeString KeyName, + [In] [Optional] ref UnicodeString PrivateData + ); + + [DllImport("secur32.dll")] + public static extern NtStatus LsaUnregisterPolicyChangeNotification( + [In] PolicyNotificationInformationClass InformationClass, + [In] IntPtr NotificationEventHandle + ); + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Api/LsaStructs.cs b/branches/ph-plugins/ProcessHacker.Native/Api/LsaStructs.cs new file mode 100644 index 000000000..f18b4699e --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Api/LsaStructs.cs @@ -0,0 +1,114 @@ +/* + * Process Hacker - + * LSA structures + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; + +namespace ProcessHacker.Native.Api +{ + [StructLayout(LayoutKind.Sequential)] + public struct LsaReferencedDomainList + { + public int Entries; + public IntPtr Domains; // LsaTrustInformation* + } + + [StructLayout(LayoutKind.Sequential)] + public struct LsaTranslatedName + { + public SidNameUse Use; + public UnicodeString Name; + public int DomainIndex; + } + + [StructLayout(LayoutKind.Sequential)] + public struct LsaTranslatedSid + { + public SidNameUse Use; + public int RelativeId; + public int DomainIndex; + } + + [StructLayout(LayoutKind.Sequential)] + public struct LsaTranslatedSid2 + { + public SidNameUse Use; + public IntPtr Sid; // Sid* + public int DomainIndex; + public int Flags; + } + + [StructLayout(LayoutKind.Sequential)] + public struct LsaTrustInformation + { + public UnicodeString Name; + public IntPtr Sid; // Sid* + } + + [StructLayout(LayoutKind.Sequential)] + public struct PolicyPrivilegeDefinition + { + public UnicodeString Name; + public Luid LocalValue; + } + + [StructLayout(LayoutKind.Sequential)] + public struct QuotaLimits + { + public IntPtr PagedPoolLimit; + public IntPtr NonPagedPoolLimit; + public IntPtr MinimumWorkingSetSize; + public IntPtr MaximumWorkingSetSize; + public IntPtr PagefileLimit; + public long TimeLimit; + } + + [StructLayout(LayoutKind.Sequential)] + public struct SecurityLogonSessionData + { + public int Size; + public Luid LogonId; + public UnicodeString UserName; + public UnicodeString LogonDomain; + public UnicodeString AuthenticationPackage; + public LogonType LogonType; + public int Session; + public IntPtr Sid; // Sid* + public long LogonTime; + public UnicodeString LogonServer; + public UnicodeString DnsDomainName; + public UnicodeString Upn; + } + + [StructLayout(LayoutKind.Sequential)] + public struct TrustedDomainInformationEx + { + public UnicodeString Name; + public UnicodeString FlatName; + public IntPtr Sid; // Sid* + public int TrustDirection; + public int TrustType; + public int TrustAttributes; + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Api/NativeDefinitions.cs b/branches/ph-plugins/ProcessHacker.Native/Api/NativeDefinitions.cs new file mode 100644 index 000000000..f72d1a20b --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Api/NativeDefinitions.cs @@ -0,0 +1,105 @@ +/* + * Process Hacker - + * native API consts and delegates + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Runtime.InteropServices; + +namespace ProcessHacker.Native.Api +{ + public delegate void ApcCallbackDelegate(NtStatus ioStatus, IntPtr apcContext, IntPtr context); + public delegate void ApcRoutine(IntPtr parameter); + public delegate void IoApcRoutine(IntPtr apcContext, ref IoStatusBlock ioStatusBlock, int reserved); + public delegate void TimerApcRoutine(IntPtr context, int lowValue, int highValue); + public delegate void WaitOrTimerCallbackDelegate(IntPtr context, bool timeout); + public delegate void WorkerCallbackDelegate(IntPtr context); + + public static partial class Win32 + { + public const int AclRevision = 2; + public const int AclRevisionDs = 4; + public const int CsrSrvServerDllIndex = 0; + public const int CsrSrvFirstApiNumber = 0; + public const int BaseSrvServerDllIndex = 1; + public const int BaseSrvFirstApiNumber = 0; + public const int ConSrvServerDllIndex = 2; + public const int ConSrvFirstApiNumber = 512; + public const int UserSrvServerDllIndex = 3; + public const int UserSrvFirstApiNumber = 1024; + public const int ExceptionMaximumParameters = 15; + public const uint FileWriteToEndOfFile = 0xffffffff; + public const uint FileUseFilePointerPosition = 0xfffffffe; + public const int FlsMaximumAvailable = 128; +#if _WIN64 + public const int GdiHandleBufferSize = 60; +#else + public const int GdiHandleBufferSize = 34; +#endif + public const int MaximumSupportedExtension = 512; + public const int MaximumWaitObjects = 64; + public const int MaxKeyNameLength = 512; + public const int MaxKeyValueNameLength = 32767; + public const int MaxStackDepth = 32; + public const int MaxWow64SharedEntries = 16; + public const short Pe32Magic = 0x10b; + public const short Pe32PlusMagic = 0x20b; + public const short RomMagic = 0x107; + public const int PortMessageMaxDataLength = 0x130; + public const int PortMessageMaxLength = 0x148; + public const int ProcessHandleTracingMaxStacks = 16; + public const int ProcessorFeatureMax = 64; + public const int SecurityDescriptorRevision = 1; + public const int SidMaxSubAuthorities = 15; + public const int SidRecommendedSubAuthorities = 1; + public const int SidRevision = 1; + public const int SizeOf80387Registers = 80; + public const int TimeMsTo100Ns = 10000; + + // Known object paths + public const string BeepDeviceName = @"\Device\Beep"; + public const string EnlistmentPath = @"\Enlistment"; + public const string MailslotPath = @"\Device\Mailslot"; + public const string MountMgrDeviceName = @"\Device\MountPointManager"; + public const string NamedPipePath = @"\Device\NamedPipe"; + public const string ResourceManagerPath = @"\ResourceManager"; + public const string TransactionPath = @"\Transaction"; + public const string TransactionManagerPath = @"\TransactionManager"; + + public static readonly IntPtr KnownAceSidStartOffset = Marshal.OffsetOf(typeof(KnownAceStruct), "SidStart"); + public static readonly int SecurityDescriptorMinLength = Marshal.SizeOf(typeof(SecurityDescriptorStruct)); + public static readonly int SecurityMaxSidSize = + Marshal.SizeOf(typeof(SidStruct)) - sizeof(int) + (SidMaxSubAuthorities * sizeof(int)); + public static readonly IntPtr UserSharedData = new IntPtr(0x7ffe0000); + + public static int CsrMakeApiNumber(int dllIndex, int apiIndex) + { + return (dllIndex << 16) | apiIndex; + } + + public static int CtlCode(DeviceType type, int function, DeviceControlMethod method, DeviceControlAccess access) + { + return ((int)type << 16) | + ((int)access << 14) | + (function << 2) | + (int)method; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Api/NativeEnums.cs b/branches/ph-plugins/ProcessHacker.Native/Api/NativeEnums.cs new file mode 100644 index 000000000..c8dda5eab --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Api/NativeEnums.cs @@ -0,0 +1,2146 @@ +/* + * Process Hacker - + * native API enumerations + * + * Copyright (C) 2009 Flavio Erlich + * Copyright (C) 2008-2009 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 file contains enumeration declarations for the Native API. + * Enumerations shared between the Native API and Win32 are placed + * in this file. + */ + +using System; +using System.Collections.Generic; + +namespace ProcessHacker.Native.Api +{ + [Flags] + public enum AceFlags : byte + { + ObjectInherit = 0x1, + ContainerInherit = 0x2, + NoPropagateInherit = 0x4, + InheritOnly = 0x8, + Inherited = 0x10, + Valid = 0x1f, + + // For SystemAudit and SystemAlarm ACEs. + SuccessfulAccess = 0x40, + FailedAccess = 0x80 + } + + public enum AceType : byte + { + //Mininum = 0x0, + AccessAllowed = 0x0, + AccessDenied = 0x1, + SystemAudit = 0x2, + SystemAlarm = 0x3, + //MaximumV2 = 0x3, + + AccessAllowedCompound = 0x4, + //MaximumV3 = 0x4, + + //MinimumObject = 0x5, + AccessAllowedObject = 0x5, + AccessDeniedObject = 0x6, + SystemAuditObject = 0x7, + SystemAlarmObject = 0x8, + //MaximumObject = 0x8, + //MaximumV4 = 0x8, + //Maximum = 0x8, + + AccessAllowedCallback = 0x9, + AccessDeniedCallback = 0xa, + AccessAllowedCallbackObject = 0xb, + AccessDeniedCallbackObject = 0xc, + SystemAuditCallback = 0xd, + SystemAlarmCallback = 0xe, + SystemAuditCallbackObject = 0xf, + SystemAlarmCallbackObject = 0x10, + //MaximumV5 = 0x10 + } + + public enum AclInformationClass : int + { + AclRevisionInformation = 1, + AclSizeInformation + } + + public enum AlternativeArchitectureType : int + { + StandardDesign, + Nec98x86, + EndAlternatives + } + + public enum BaseSrvApiNumber : int + { + BasepCreateProcess = Win32.BaseSrvFirstApiNumber, + BasepCreateThread, + BasepGetTempFile, + BasepExitProcess, + BasepDebugProcess, + BasepCheckVDM, + BasepUpdateVDMEntry, + BasepGetNextVDMCommand, + BasepExitVDM, + BasepIsFirstVDM, + BasepGetVDMExitCode, + BasepSetReenterCount, + BasepSetProcessShutdownParam, + BasepGetProcessShutdownParam, + BasepNlsSetUserInfo, + BasepNlsSetMultipleUserInfo, + BasepNlsCreateSortSection, + BasepNlsPreserveSection, + BasepSetVDMCurDirs, + BasepGetVDMCurDirs, + BasepBatNotification, + BasepRegisterWowExec, + BasepSoundSentryNotification, + BasepRefreshIniFileMapping, + BasepDefineDosDevice, + BasepMaxApiNumber + } + + public enum CompoundAceType : ushort + { + Impersonation = 1 + } + + /// + /// Generic context-related flags. + /// + [Flags] + public enum ContextFlagsGeneric : uint + { + // Context architecture + I386 = 0x00010000, + I486 = 0x00010000, + Amd64 = 0x00100000, + + // Context flags + Control = 0x00000001, + Integer = 0x00000002, + Segments = 0x00000004, + FloatingPoint = 0x00000008, + DebugRegisters = 0x00000010, + ExtendedRegisters = 0x00000020, + } + + /// + /// x86 context. + /// + [Flags] + public enum ContextFlags : uint + { + I386 = ContextFlagsGeneric.I386, + I486 = ContextFlagsGeneric.I486, + + Control = I386 | ContextFlagsGeneric.Control, + Integer = I386 | ContextFlagsGeneric.Integer, + Segments = I386 | ContextFlagsGeneric.Segments, + FloatingPoint = I386 | ContextFlagsGeneric.FloatingPoint, + DebugRegisters = I386 | ContextFlagsGeneric.DebugRegisters, + ExtendedRegisters = I386 | ContextFlagsGeneric.ExtendedRegisters, + + Full = Control | Integer | Segments, + All = Control | Integer | Segments | FloatingPoint | DebugRegisters | ExtendedRegisters + } + + /// + /// AMD64 context. + /// + [Flags] + public enum ContextFlagsAmd64 : uint + { + Amd64 = ContextFlagsGeneric.Amd64, + + Control = Amd64 | ContextFlagsGeneric.Control, + Integer = Amd64 | ContextFlagsGeneric.Integer, + Segments = Amd64 | ContextFlagsGeneric.Segments, + FloatingPoint = Amd64 | ContextFlagsGeneric.FloatingPoint, + DebugRegisters = Amd64 | ContextFlagsGeneric.DebugRegisters, + + Full = Control | Integer | FloatingPoint, + All = Control | Integer | Segments | FloatingPoint | DebugRegisters, + + ExceptionActive = 0x08000000, + ServiceActive = 0x10000000, + ExceptionRequest = 0x40000000, + ExceptionReporting = 0x80000000 + } + + [Flags] + public enum CrmProtocolOptions : int + { + ExplicitMarshalOnly = 0x1, + DynamicMarshalInfo = 0x2, + MaximumOption = 0x3 + } + + [Flags] + public enum DebugObjectFlags : uint + { + KillOnClose = 0x1 + } + + [Flags] + public enum DebugObjectInformationClass : int + { + DebugObjectFlags, + MaxDebugObjectInfoClass + } + + public enum DeviceControlAccess : int + { + Any = 0, + Special = Any, + Read = 1, + Write = 2 + } + + public enum DeviceControlMethod : int + { + Buffered = 0, + InDirect = 1, + OutDirect = 2, + Neither = 3 + } + + public enum DeviceType : int + { + Beep = 0x1, + CdRom = 0x2, + CdRomFileSystem = 0x3, + Controller = 0x4, + DataLink = 0x5, + Dfs = 0x6, + Disk = 0x7, + DiskFileSystem = 0x8, + FileSystem = 0x9, + InportPort = 0xa, + Keyboard = 0xb, + Mailslot = 0xc, + MidiIn = 0xd, + MidiOut = 0xe, + Mouse = 0xf, + MultiUncProvider = 0x10, + NamedPipe = 0x11, + Network = 0x12, + NetworkBrowser = 0x13, + NetworkFileSystem = 0x14, + Null = 0x15, + ParallelPort = 0x16, + PhysicalNetCard = 0x17, + Printer = 0x18, + Scanner = 0x19, + SerialMousePort = 0x1a, + SerialPort = 0x1b, + Screen = 0x1c, + Sound = 0x1d, + Streams = 0x1e, + Tape = 0x1f, + TapeFileSystem = 0x20, + Transport = 0x21, + Unknown = 0x22, + Video = 0x23, + VirtualDisk = 0x24, + WaveIn = 0x25, + WaveOut = 0x26, + EightZeroFourTwoPort = 0x27, + NetworkRedirector = 0x28, + Battery = 0x29, + BusExtender = 0x2a, + Modem = 0x2b, + Vdm = 0x2c, + MassStorage = 0x2d, + Smb = 0x2e, + Ks = 0x2f, + Changer = 0x30, + SmartCard = 0x31, + Acpi = 0x32, + Dvd = 0x33, + FullscreenVideo = 0x34, + DfsFileSystem = 0x35, + DfsVolume = 0x36, + Serenum = 0x37, + TermSrv = 0x38, + KSec = 0x39, + Fips = 0x3a, + Infiniband = 0x3b, + + MountMgr = 'm', + MountMgrDevice = 'M' + } + + [Flags] + public enum DbgState : int + { + DbgIdle, + DbgReplyPending, + DbgCreateThreadStateChange, + DbgCreateProcessStateChange, + DbgExitThreadStateChange, + DbgExitProcessStateChange, + DbgExceptionStateChange, + DbgBreakpointStateChange, + DbgSingleStepStateChange, + DbgLoadDllStateChange, + DbgUnloadDllStateChange + } + + [Flags] + public enum DuplicateOptions : int + { + CloseSource = 0x1, + SameAccess = 0x2, + SameAttributes = 0x4 + } + + public enum EnlistmentInformationClass : int + { + EnlistmentBasicInformation, + EnlistmentRecoveryInformation, + EnlistmentFullInformation + } + + [Flags] + public enum EnlistmentOptions : int + { + Superior = 0x1, + MaximumOption = 0x1 + } + + public enum EventInformationClass : int + { + EventBasicInformation + } + + public enum EventType : int + { + NotificationEvent, + SynchronizationEvent + } + + public enum FileAlignment : int + { + Byte = 0x0, + Word = 0x1, + Long = 0x3, + Quad = 0x7, + Octa = 0xf, + ThirtyTwoByte = 0x1f, + SixtyFourByte = 0x3f, + OneHundredAndTwentyEightByte = 0x7f, + TwoHundredAndFiftySixByte = 0xff, + FiveHundredAndTwelveByte = 0x1ff + } + + [Flags] + public enum FileAttributes : uint + { + ReadOnly = 0x1, + Hidden = 0x2, + System = 0x4, + + Directory = 0x10, + Archive = 0x20, + Device = 0x40, + Normal = 0x80, + + Temporary = 0x100, + SparseFile = 0x200, + ReparsePoint = 0x400, + Compressed = 0x800, + + Offline = 0x1000, + NotContextIndexed = 0x2000, + Encrypted = 0x4000 + } + + [Flags] + public enum FileCreateOptions : uint + { + DirectoryFile = 0x1, + WriteThrough = 0x2, + SequentialOnly = 0x4, + NoIntermediateBuffering = 0x8, + + SynchronousIoAlert = 0x10, + SynchronousIoNonAlert = 0x20, + NonDirectoryFile = 0x40, + CreateTreeConnection = 0x80, + + CompleteIfOpLocked = 0x100, + NoEaKnowledge = 0x200, + OpenForRecovery = 0x400, + RandomAccess = 0x800, + + DeleteOnClose = 0x1000, + OpenByFileId = 0x2000, + OpenForBackupIntent = 0x4000, + NoCompression = 0x8000, + + ReserveOpFilter = 0x100000, + OpenReparsePoint = 0x200000, + OpenNoRecall = 0x400000, + OpenForFreeSpaceQuery = 0x800000, + + CopyStructuredStorage = 0x41, + StructuredStorage = 0x441, + + ValidOptionFlags = 0xffffff, + ValidPipeOptionFlags = 0x32, + ValidMailslotOptionFlags = 0x32, + ValidSetFlags = 0x36 + } + + public enum FileCreationDisposition : int + { + Supersede = 0x0, + Open = 0x1, + Create = 0x2, + OpenIf = 0x3, + Overwrite = 0x4, + OverwriteIf = 0x5 + } + + public enum FileInformationClass : int + { + FileDirectoryInformation = 1, // dir + FileFullDirectoryInformation, // dir + FileBothDirectoryInformation, // dir + FileBasicInformation, + FileStandardInformation, + FileInternalInformation, + FileEaInformation, + FileAccessInformation, + FileNameInformation, + FileRenameInformation, // 10 + FileLinkInformation, + FileNamesInformation, // dir + FileDispositionInformation, + FilePositionInformation, + FileFullEaInformation, + FileModeInformation, + FileAlignmentInformation, + FileAllInformation, + FileAllocationInformation, + FileEndOfFileInformation, // 20 + FileAlternateNameInformation, + FileStreamInformation, + FilePipeInformation, + FilePipeLocalInformation, + FilePipeRemoteInformation, + FileMailslotQueryInformation, + FileMailslotSetInformation, + FileCompressionInformation, + FileObjectIdInformation, // dir + FileCompletionInformation, // 30 + FileMoveClusterInformation, + FileQuotaInformation, + FileReparsePointInformation, + FileNetworkOpenInformation, + FileAttributeTagInformation, + FileTrackingInformation, + FileIdBothDirectoryInformation, // dir + FileIdFullDirectoryInformation, // dir + FileValidDataLengthInformation, + FileShortNameInformation, // 40 + FileIoCompletionNotificationInformation, + FileIoStatusBlockRangeInformation, + FileIoPriorityHintInformation, + FileSfioReserveInformation, + FileSfioVolumeInformation, + FileHardLinkInformation, + FileProcessIdsUsingFileInformation, + FileNormalizedNameInformation, + FileNetworkPhysicalNameInformation, + FileIdGlobalTxDirectoryInformation, // 50 + FileMaximumInformation + } + + public enum FileIoStatus : int + { + Superseded = 0, + Opened = 1, + Created = 2, + Overwritten = 3, + Exists = 4, + DoesNotExist = 5 + } + + public enum FileNotifyAction : int + { + Added = 0x1, + Removed = 0x2, + Modified = 0x3, + RenamedOldName = 0x4, + RenamedNewName = 0x5, + AddedStream = 0x6, + RemovedStream = 0x7, + ModifiedStream = 0x8, + RemovedByDelete = 0x9, + IdNotTunnelled = 0xa, + TunnelledIdCollision = 0xb + } + + [Flags] + public enum FileNotifyFlags : int + { + FileName = 0x1, + DirName = 0x2, + Name = 0x3, + Attributes = 0x4, + Size = 0x8, + LastWrite = 0x10, + LastAccess = 0x20, + Creation = 0x40, + Ea = 0x80, + Security = 0x100, + StreamName = 0x200, + StreamSize = 0x400, + StreamWrite = 0x800, + Valid = 0xfff + } + + [Flags] + public enum FileObjectFlags : int + { + FileOpen = 0x00000001, + SynchronousIo = 0x00000002, + AlertableIo = 0x00000004, + NoIntermediateBuffering = 0x00000008, + WriteThrough = 0x00000010, + SequentialOnly = 0x00000020, + CacheSupported = 0x00000040, + NamedPipe = 0x00000080, + StreamFile = 0x00000100, + MailSlot = 0x00000200, + GenerateAuditOnClose = 0x00000400, + QueueIrpToThread = GenerateAuditOnClose, + DirectDeviceOpen = 0x00000800, + FileModified = 0x00001000, + FileSizeChanged = 0x00002000, + CleanupComplete = 0x00004000, + TemporaryFile = 0x00008000, + DeleteOnClose = 0x00010000, + OpenedCaseSensitivity = 0x00020000, + HandleCreated = 0x00040000, + FileFastIoRead = 0x00080000, + RandomAccess = 0x00100000, + FileOpenCancelled = 0x00200000, + VolumeOpen = 0x00400000, + RemoteOrigin = 0x01000000, + SkipCompletionPort = 0x02000000, + SkipSetEvent = 0x04000000, + SkipSetFastIo = 0x08000000 + } + + [Flags] + public enum FileShareMode : uint + { + Exclusive = 0x0, + Read = 0x1, + Write = 0x2, + Delete = 0x4, + + ReadWrite = Read | Write, + ReadWriteDelete = Read | Write | Delete + } + + public enum FsInformationClass : int + { + FileFsVolumeInformation = 1, + FileFsLabelInformation, + FileFsSizeInformation, + FileFsDeviceInformation, + FileFsAttributeInformation, + FileFsControlInformation, + FileFsFullSizeInformation, + FileFsObjectIdInformation, + FileFsDriverPathInformation, + FileFsVolumeFlagsInformation, // 10 + FileFsMaximumInformation + } + + [Flags] + public enum HandleFlags : byte + { + ProtectFromClose = 0x1, + Inherit = 0x2, + AuditObjectClose = 0x4 + } + + public enum HandleTraceType : int + { + Open = 1, + Close = 2, + BadRef = 3 + } + + [Flags] + public enum HashStringAlgorithm : int + { + Default = 0, + X65599 = 1, + Invalid = -1 + } + + [Flags] + public enum HeapFlags : uint + { + NoSerialize = 0x00000001, + Growable = 0x00000002, + GenerateExceptions = 0x00000004, + ZeroMemory = 0x00000008, + ReallocInPlaceOnly = 0x00000010, + TailCheckingEnabled = 0x00000020, + FreeCheckingEnabled = 0x00000040, + DisableCoalesceOnFree = 0x00000080, + + CreateAlign16 = 0x00010000, + CreateEnableTracing = 0x00020000, + CreateEnableExecute = 0x00040000, + + SettableUserValue = 0x00000100, + SettableUserFlag1 = 0x00000200, + SettableUserFlag2 = 0x00000400, + SettableUserFlag3 = 0x00000800, + SettableUserFlags = 0x00000e00, + + Class0 = 0x00000000, // Process heap + Class1 = 0x00001000, // Private heap + Class2 = 0x00002000, // Kernel heap + Class3 = 0x00003000, // GDI heap + Class4 = 0x00004000, // User heap + Class5 = 0x00005000, // Console heap + Class6 = 0x00006000, // User desktop heap + Class7 = 0x00007000, // CSRSS shared heap + Class8 = 0x00008000, // CSR port heap + ClassMask = 0x0000f000 + } + + public enum ImageBaseRelocationType : short + { + /// + /// The base relocation is skipped. This type can be used to pad a block. + /// + Absolute = 0, + + /// + /// The base relocation adds the high 16 bits of the difference to the 16-bit + /// field at offset. The 16-bit field represents the high value of a 32-bit word. + /// + High = 1, + + /// + /// The base relocation adds the low 16 bits of the difference to the 16-bit + /// field at offset. The 16-bit field represents the low half of a 32-bit word. + /// + Low = 2, + + /// + /// The base relocation applies all 32 bits of the difference to the 32-bit + /// field at offset. + /// + HighLow = 3, + + /// + /// The base relocation adds the high 16 bits of the difference to the 16-bit + /// field at offset. The 16-bit field represents the high value of a 32-bit word. + /// The low 16 bits of the 32-bit value are stored in the 16-bit word that follows + /// this base relocation. This means that this base relocation occupies two slots. + /// + HighAdj = 4, + + /// + /// The base relocation applies to a MIPS jump instruction. + /// + MipsJmpAddr = 5, + + /// + /// The base relocation applies to a MIPS16 jump instruction. + /// + MipsJmpAddr16 = 9, + Ia64Imm64 = 9, + + /// + /// The base relocation applies the difference to the 64-bit field at offset. + /// + Dir16 = 10 + } + + [Flags] + public enum ImageCharacteristics : ushort + { + /// + /// Image only, Windows CE, and Windows NT® and later. This indicates that the file does + /// not contain base relocations and must therefore be loaded at its preferred base address. + /// If the base address is not available, the loader reports an error. The default behavior + /// of the linker is to strip base relocations from executable (EXE) files. + /// + RelocsStripped = 0x0001, + + /// + /// Image only. This indicates that the image file is valid and can be run. If this flag + /// is not set, it indicates a linker error. + /// + ExecutableImage = 0x0002, + + /// + /// COFF line numbers have been removed. This flag is deprecated and should be zero. + /// + LineNumsStripped = 0x0004, + + /// + /// COFF symbol table entries for local symbols have been removed. This flag is deprecated + /// and should be zero. + /// + LocalSymsStripped = 0x0008, + + /// + /// Obsolete. Aggressively trim working set. This flag is deprecated for Windows 2000 and later + /// and must be zero. + /// + AggressiveWsTrim = 0x0010, + + /// + /// Application can handle > 2 GB addresses. + /// + LargeAddressAware = 0x0020, + + /// + /// This flag is reserved for future use. + /// + Reserved = 0x0040, + + /// + /// Little endian: the least significant bit (LSB) precedes the most significant bit (MSB) in + /// memory. This flag is deprecated and should be zero. + /// + BytesReversedLo = 0x0080, + + /// + /// Machine is based on a 32-bit-word architecture. + /// + ThirtyTwoBitMachine = 0x0100, + + /// + /// Debugging information is removed from the image file. + /// + DebugStripped = 0x0200, + + /// + /// If the image is on removable media, fully load it and copy it to the swap file. + /// + RemovableRunFromSwap = 0x0400, + + /// + /// If the image is on network media, fully load it and copy it to the swap file. + /// + NetRunFromSwap = 0x0800, + + /// + /// The image file is a system file, not a user program. + /// + System = 0x1000, + + /// + /// The image file is a dynamic-link library (DLL). Such files are considered + /// executable files for almost all purposes, although they cannot be directly run. + /// + DLL = 0x2000, + + /// + /// The file should be run only on a uniprocessor machine. + /// + UPSystemOnly = 0x4000, + + /// + /// Big endian: the MSB precedes the LSB in memory. This flag is deprecated and should be zero. + /// + BytesReversedHi = 0x8000 + } + + [Flags] + public enum ImageDllCharacteristics : ushort + { + DynamicBase = 0x0040, + ForceIntegrity = 0x0080, + NxCompat = 0x0100, + NoIsolation = 0x0200, + NoSeh = 0x0400, + NoBind = 0x0800, + WdmDriver = 0x2000, + TerminalServerAware = 0x8000 + } + + public enum ImageI386RelocationType : short + { + Absolute = 0x0, + Dir16 = 0x1, + Rel16 = 0x2, + Dir32 = 0x6, + Dir32Nb = 0x7, + Seg12 = 0x9, + Section = 0xa, + SecRel = 0xb, + Token = 0xc, + SecRel7 = 0xd, + Rel32 = 0x14 + } + + [Flags] + public enum ImageSectionFlags : uint + { + /// + /// Reserved for future use. + /// + Reserved1 = 0x00000000, + + /// + /// Reserved for future use. + /// + Reserved2 = 0x00000001, + + /// + /// Reserved for future use. + /// + Reserved3 = 0x00000002, + + /// + /// Reserved, must be zero. + /// + Reserved4 = 0x00000004, + + /// + /// The section should not be padded to the next boundary. + /// This flag is obsolete and is replaced by IMAGE_SCN_ALIGN_1BYTES. + /// This is valid only for object files. + /// + NoPad = 0x00000008, + + /// + /// The section contains executable code. + /// + Code = 0x00000020, + + /// + /// The section contains initialized data. + /// + InitializedData = 0x00000040, + + /// + /// The section contains uninitialized data. + /// + UninitializedData = 0x00000080, + + /// + /// Reserved for future use. + /// + Other = 0x00000100, + + /// + /// The section contains comments or other information. The + /// .drectve section has this type. This is valid for object + /// files only. + /// + Info = 0x00000200, + + /// + /// Reserved for future use. + /// + Reserved5 = 0x00000400, + + /// + /// The section will not become part of the image. This is valid + /// only for object files. + /// + Remove = 0x00000800, + + /// + /// The section contains COMDAT data. + /// + COMDAT = 0x00001000, + + /// + /// The section contains data referenced through the global pointer (GP). + /// + GPRel = 0x00008000, + + /// + /// Reserved for future use. + /// + MemoryPurgeable = 0x00010000, + + /// + /// Reserved for future use. + /// + Memory16Bit = 0x00020000, + + /// + /// Reserved for future use. + /// + MemoryLocked = 0x00040000, + + /// + /// Reserved for future use. + /// + MemoryPeload = 0x00080000, + + Align1Bytes = 0x00100000, + Align2Bytes = 0x00200000, + Align4Bytes = 0x00300000, + Align8Bytes = 0x00400000, + Align16Bytes = 0x00500000, + Align32Bytes = 0x00600000, + Align64Bytes = 0x00700000, + Align128Bytes = 0x00800000, + Align256Bytes = 0x00900000, + Align512Bytes = 0x00a00000, + Align1024Bytes = 0x00b00000, + Align2048Bytes = 0x00c00000, + Align4096Bytes = 0x00d00000, + Align8192Bytes = 0x00e00000, + + /// + /// The section contains extended relocations. + /// + NRelocOvfl = 0x01000000, + + /// + /// The section can be discarded as needed. + /// + MemoryDiscardable = 0x02000000, + + /// + /// The section cannot be cached. + /// + MemoryNotCached = 0x04000000, + + /// + /// The section is not pageable. + /// + MemoryNotPaged = 0x08000000, + + /// + /// The section can be shared in memory. + /// + MemoryShared = 0x10000000, + + /// + /// The section can be executed as code. + /// + MemoryExecute = 0x20000000, + + /// + /// The section can be read. + /// + MemoryRead = 0x40000000, + + /// + /// The section can be written to. + /// + MemoryWrite = 0x80000000 + } + + public enum ImageSubsystem : short + { + Unknown = 0, + Native = 1, + WindowsGui = 2, + WindowsCui = 3, + OS2Cui = 5, + PosixCui = 7, + NativeWindows = 8, + WindowsCeGui = 9, + EfiApplication = 10, + EfiBootServiceDriver = 11, + EfiRuntimeDriver = 12, + EfiRom = 13, + Xbox = 14, + WindowsBootApplication = 16 + } + + public enum IoCompletionInformationClass : int + { + IoCompletionBasicInformation + } + + [Flags] + public enum JobObjectBasicUiRestrictions : uint + { + Handles = 0x1, + ReadClipboard = 0x2, + WriteClipboard = 0x4, + SystemParameters = 0x8, + DisplaySettings = 0x10, + GlobalAtoms = 0x20, + Desktop = 0x40, + ExitWindows = 0x80 + } + + public enum JobObjectInformationClass : int + { + JobObjectBasicAccountingInformation = 1, + JobObjectBasicLimitInformation, + JobObjectBasicProcessIdList, + JobObjectBasicUIRestrictions, + JobObjectSecurityLimitInformation, + JobObjectEndOfJobTimeInformation, + JobObjectAssociateCompletionPortInformation, + JobObjectBasicAndIoAccountingInformation, + JobObjectExtendedLimitInformation, + JobObjectJobSetInformation + } + + [Flags] + public enum JobObjectLimitFlags : uint + { + WorkingSet = 0x1, + ProcessTime = 0x2, + JobTime = 0x4, + ActiveProcess = 0x8, + Affinity = 0x10, + PriorityClass = 0x20, + PreserveJobTime = 0x40, + SchedulingClass = 0x80, + ProcessMemory = 0x100, + JobMemory = 0x200, + DieOnUnhandledException = 0x400, + BreakawayOk = 0x800, + SilentBreakawayOk = 0x1000, + KillOnJobClose = 0x2000, + } + + [Flags] + public enum KeyCreationDisposition : int + { + CreatedNewKey = 0x1, + OpenedExistingKey = 0x2 + } + + public enum KeyInformationClass : int + { + KeyBasicInformation, + KeyNodeInformation, + KeyFullInformation, + KeyNameInformation, + KeyCachedInformation, + KeyFlagsInformation, + MaxKeyInfoClass + } + + public enum KeySetInformationClass : int + { + KeyWriteTimeInformation, + KeyUserFlagsInformation, + MaxKeySetInfoClass + } + + public enum KProcessorMode : byte + { + KernelMode = 0, + UserMode = 1 + } + + public enum KProfileSource : int + { + ProfileTime, + ProfileAlignmentFixup, + ProfileTotalIssues, + ProfilePipelineDry, + ProfileLoadInstructions, + ProfilePipelineFrozen, + ProfileBranchInstructions, + ProfileTotalNonissues, + ProfileDcacheMisses, + ProfileIcacheMisses, + ProfileCacheMisses, + ProfileBranchMispredictions, + ProfileStoreInstructions, + ProfileFpInstructions, + ProfileIntegerInstructions, + Profile2Issue, + Profile3Issue, + Profile4Issue, + ProfileSpecialInstructions, + ProfileTotalCycles, + ProfileIcacheIssues, + ProfileDcacheAccesses, + ProfileMemoryBarrierCycles, + ProfileLoadLinkedIssues, + ProfileMaximum + } + + public enum KtmObjectType : int + { + Transaction, + TransactionManager, + ResourceManager, + Enlistment, + Invalid + } + + public enum KWaitReason : int + { + Executive = 0, + FreePage = 1, + PageIn = 2, + PoolAllocation = 3, + DelayExecution = 4, + Suspended = 5, + UserRequest = 6, + WrExecutive = 7, + WrFreePage = 8, + WrPageIn = 9, + WrPoolAllocation = 10, + WrDelayExecution = 11, + WrSuspended = 12, + WrUserRequest = 13, + WrEventPair = 14, + WrQueue = 15, + WrLpcReceive = 16, + WrLpcReply = 17, + WrVirtualMemory = 18, + WrPageOut = 19, + WrRendezvous = 20, + Spare2 = 21, + Spare3 = 22, + Spare4 = 23, + Spare5 = 24, + WrCalloutStack = 25, + WrKernel = 26, + WrResource = 27, + WrPushLock = 28, + WrMutex = 29, + WrQuantumEnd = 30, + WrDispatchInt = 31, + WrPreempted = 32, + WrYieldExecution = 33, + WrFastMutex = 34, + WrGuardedMutex = 35, + WrRundown = 36, + MaximumWaitReason = 37 + } + + [Flags] + public enum LdrpDataTableEntryFlags : uint + { + StaticLink = 0x00000002, + ImageDll = 0x00000004, + Flag0x8 = 0x00000008, + Flag0x10 = 0x00000010, + LoadInProgress = 0x00001000, + UnloadInProgress = 0x00002000, + EntryProcessed = 0x00004000, + EntryInserted = 0x00008000, + CurrentLoad = 0x00010000, + FailedBuiltInLoad = 0x00020000, + DontCallForThreads = 0x00040000, + ProcessAttachCalled = 0x00080000, + DebugSymbolsLoaded = 0x00100000, + ImageNotAtBase = 0x00200000, + CorImage = 0x00400000, + CorOwnsUnmap = 0x00800000, + SystemMapped = 0x01000000, + ImageVerifying = 0x02000000, + DriverDependentDll = 0x04000000, + EntryNative = 0x08000000, + Redirected = 0x10000000, + NonPagedDebugInfo = 0x20000000, + MmLoaded = 0x40000000, + CompatDatabaseProcessed = 0x80000000 + } + + /// + /// Specifies an executable's target CPU type. + /// + public enum MachineType : ushort + { + /// + /// Assumed to be applicable to any machine type. + /// + Unknown = 0x0, + + /// + /// Matsushita AM33. + /// + Am33 = 0x1d3, + + /// + /// x64. + /// + Amd64 = 0x8664, + + /// + /// ARM little-endian. + /// + Arm = 0x1c0, + + /// + /// EFI byte code. + /// + Ebc = 0xebc, + + /// + /// Intel 386 or later processors and compatible processors. + /// + I386 = 0x14c, + + /// + /// Intel Itanium processor family. + /// + Ia64 = 0x200, + + /// + /// Mitsubishi M32R little endian. + /// + M32R = 0x9041, + + /// + /// MIPS16. + /// + Mips16 = 0x266, + + /// + /// MIPS with FPU. + /// + MipsFpu = 0x366, + + /// + /// MIPS16 with FPU. + /// + MipsFpu16 = 0x466, + + /// + /// PowerPC little-endian. + /// + PowerPc = 0x1f0, + + /// + /// PowerPC with floating point support. + /// + PowerPcFp = 0x1f1, + + /// + /// MIPS little-endian. + /// + R4000 = 0x166, + + /// + /// Hitachi SH3. + /// + Sh3 = 0x1a2, + + /// + /// Hitachi SH3 DSP. + /// + Sh3Dsp = 0x1a3, + + /// + /// Hitachi SH4. + /// + Sh4 = 0x1a6, + + /// + /// Hitachi SH5. + /// + Sh5 = 0x1a8, + + /// + /// Thumb. + /// + Thumb = 0x1c2, + + /// + /// MIPS little-endian WCE v2. + /// + WceMipsv2 = 0x169 + } + + [Flags] + public enum MemExecuteOptions : int + { + ExecuteDisable = 0x1, + ExecuteEnable = 0x2, + DisableThunkEmulation = 0x4, + Permanent = 0x8 + } + + [Flags] + public enum MemoryFlags : uint + { + Commit = 0x1000, + Reserve = 0x2000, + Decommit = 0x4000, + Release = 0x8000, + Free = 0x10000, + Private = 0x20000, + Mapped = 0x40000, + Reset = 0x80000, + TopDown = 0x100000, + WriteWatch = 0x200000, + Physical = 0x400000, + LargePages = 0x20000000, + DosLimit = 0x40000000, + FourMbPages = 0x80000000 + } + + public enum MemoryInformationClass : int + { + MemoryBasicInformation, + MemoryWorkingSetInformation, + MemoryMappedFilenameInformation, + MemoryRegionInformation, + MemoryWorkingSetExInformation + } + + public enum MemoryMapType : int + { + Process = 1, + System = 2 + } + + [Flags] + public enum MemoryProtection : uint + { + AccessDenied = 0x0, + Execute = 0x10, + ExecuteRead = 0x20, + ExecuteReadWrite = 0x40, + ExecuteWriteCopy = 0x80, + Guard = 0x100, + NoCache = 0x200, + WriteCombine = 0x400, + NoAccess = 0x01, + ReadOnly = 0x02, + ReadWrite = 0x04, + WriteCopy = 0x08 + } + + [Flags] + public enum MessageResourceFlags : ushort + { + Unicode = 0x1 + } + + public enum MutantInformationClass : int + { + MutantBasicInformation, + MutantOwnerInformation + } + + [Flags] + public enum NotificationMask : uint + { + Mask = 0x3fffffff, + PrePrepare = 0x00000001, + Prepare = 0x00000002, + Commit = 0x00000004, + Rollback = 0x00000008, + PrePrepareComplete = 0x00000010, + PrepareComplete = 0x00000020, + CommitComplete = 0x00000040, + RollbackComplete = 0x00000080, + Recover = 0x00000100, + SinglePhaseComplete = 0x00000200, + DelegateCommit = 0x00000400, + RecoverQuery = 0x00000800, + EnlistPrePrepare = 0x00001000, + LastRecover = 0x00002000, + Indoubt = 0x00004000, + PropagatePull = 0x00008000, + PropagatePush = 0x00010000, + Marshal = 0x00020000, + EnlistMask = 0x00040000, + RmDisconnected = 0x01000000, + TmOnline = 0x02000000, + CommitRequest = 0x04000000, + Promote = 0x08000000, + PromoteNew = 0x10000000, + RequestOutcome = 0x20000000, + + // For filter manager use only. DO NOT SPECIFY. + CommitFinalize = 0x40000000 + } + + [Flags] + public enum ObjectAceFlags : uint + { + ObjectTypePresent = 0x1, + InheritedObjectTypePresent = 0x2 + } + + [Flags] + public enum ObjectFlags : uint + { + Inherit = 0x2, + Permanent = 0x10, + Exclusive = 0x20, + CaseInsensitive = 0x40, + OpenIf = 0x80, + OpenLink = 0x100, + KernelHandle = 0x200, + ForceAccessCheck = 0x400, + ValidAttributes = 0x7f2 + } + + public enum ObjectInformationClass : int + { + ObjectBasicInformation = 0, + ObjectNameInformation = 1, + ObjectTypeInformation = 2, + ObjectTypesInformation = 3, + ObjectHandleFlagInformation = 4, + ObjectSessionInformation = 5 + } + + public enum PipeEnd : int + { + Client = 0, + Server = 1 + } + + public enum PipeCompletionMode : int + { + Queue = 0, + Complete = 1 + } + + public enum PipeConfiguration : int + { + Inbound = 0, + Outbound = 1, + FullDuplex = 2 + } + + public enum PipeState : uint + { + Disconnected = 1, + Listening = 2, + Connected = 3, + Closing = 4 + } + + public enum PipeType : int + { + ByteStream = 0, + Message = 1 + } + + public enum PortMessageType : short + { + Request = 1, + Reply = 2, + Datagram = 3, + LostReply = 4, + PortClosed = 5, + ClientDied = 6, + Exception = 7, + DebugEvent = 8, + ErrorEvent = 9, + ConnectionRequest = 10 + } + + [Flags] + public enum PrivilegeSetFlags : int + { + AnyNecessary = 0, + AllNecessary = 0x1 + } + + public enum ProcessInformationClass : int + { + ProcessBasicInformation, // 0 + ProcessQuotaLimits, + ProcessIoCounters, + ProcessVmCounters, + ProcessTimes, + ProcessBasePriority, + ProcessRaisePriority, + ProcessDebugPort, + ProcessExceptionPort, + ProcessAccessToken, + ProcessLdtInformation, // 10 + ProcessLdtSize, + ProcessDefaultHardErrorMode, + ProcessIoPortHandlers, + ProcessPooledUsageAndLimits, + ProcessWorkingSetWatch, + ProcessUserModeIOPL, + ProcessEnableAlignmentFaultFixup, + ProcessPriorityClass, + ProcessWx86Information, + ProcessHandleCount, // 20 + ProcessAffinityMask, + ProcessPriorityBoost, + ProcessDeviceMap, + ProcessSessionInformation, + ProcessForegroundInformation, + ProcessWow64Information, + ProcessImageFileName, + ProcessLUIDDeviceMapsEnabled, + ProcessBreakOnTermination, + ProcessDebugObjectHandle, // 30 + ProcessDebugFlags, + ProcessHandleTracing, + ProcessIoPriority, + ProcessExecuteFlags, + ProcessResourceManagement, + ProcessCookie, + ProcessImageInformation, + ProcessCycleTime, + ProcessPagePriority, + ProcessInstrumentationCallback, // 40 + ProcessThreadStackAllocation, + ProcessWorkingSetWatchEx, + ProcessImageFileNameWin32, + ProcessImageFileMapping, + ProcessAffinityUpdateMode, + ProcessMemoryAllocationMode, + MaxProcessInfoClass + } + + public enum ProcessPriorityClass : byte + { + Unknown = 0, + Idle = 1, + Normal = 2, + High = 3, + RealTime = 4, + BelowNormal = 5, + AboveNormal = 6 + } + + [Flags] + public enum RegHiveFormat : int + { + Standard = 0x1, + Latest = 0x2, + NoCompression = 0x4 + } + + [Flags] + public enum RegNotifyFilter : int + { + Name = 0x1, + Attributes = 0x2, + LastSet = 0x4, + Security = 0x8, + Legal = Name | Attributes | LastSet | Security + } + + [Flags] + public enum RegOptions : int + { + Reserved = 0x0, + NonVolatile = 0x0, + Volatile = 0x1, + CreateLink = 0x2, + BackupRestore = 0x4, + OpenLink = 0x8, + Legal = Reserved | NonVolatile | Volatile | CreateLink | BackupRestore | OpenLink + } + + [Flags] + public enum RegRestoreFlags : int + { + WholeHiveVolatile = 0x1, + RefreshHive = 0x2, + NoLazyFlush = 0x4, + ForceRestore = 0x8 + } + + [Flags] + public enum RegUnloadFlags : int + { + ForceUnload = 0x1 + } + + public enum ResourceManagerInformationClass : int + { + ResourceManagerBasicInformation, + ResourceManagerCompletionInformation, + ResourceManagerFullInformation + } + + [Flags] + public enum ResourceManagerOptions : int + { + Volatile = 0x1, + Communication = 0x2, + MaximumOption = 0x3 + } + + [Flags] + public enum RtlAcquirePrivilegeFlags : int + { + Revert = 0x1, + Process = 0x2 + } + + [Flags] + public enum RtlDuplicateUnicodeStringFlags : int + { + NullTerminate = 0x1, + AllocateNullString = 0x2 + } + + public enum RtlLockType : ushort + { + CriticalSection = 0, + Resource = 1 + } + + [Flags] + public enum RtlQueryProcessDebugFlags : uint + { + Modules = 0x00000001, + BackTraces = 0x00000002, + HeapSummary = 0x00000004, + HeapTags = 0x00000008, + HeapEntries = 0x00000010, + Locks = 0x00000020, + Modules32 = 0x00000040, + + NonInvasive = 0x80000000 + } + + [Flags] + public enum RtlUserProcessFlags : uint + { + ParamsNormalized = 0x00000001, + ProfileUser = 0x00000002, + ProfileKernel = 0x00000004, + ProfileServer = 0x00000008, + Reserve1Mb = 0x00000020, + Reserve16Mb = 0x00000040, + CaseSensitive = 0x00000080, + DisableHeapDecommit = 0x00000100, + DllRedirectionLocal = 0x00001000, + AppManifestPresent = 0x00002000, + ImageKeyMissing = 0x00004000, + OptInProcess = 0x00020000 + } + + [Flags] + public enum SectionAttributes : uint + { + Based = 0x200000, + NoChange = 0x400000, + File = 0x800000, + Image = 0x1000000, + Reserve = 0x4000000, + Commit = 0x8000000, + NoCache = 0x10000000, + Global = 0x20000000, + LargePages = 0x80000000 + } + + [Flags] + public enum SectionInformationClass : int + { + SectionBasicInformation, + SectionImageInformation + } + + public enum SectionInherit : int + { + ViewShare = 1, + ViewUnmap = 2 + } + + [Flags] + public enum SecurityDescriptorControlFlags : ushort + { + OwnerDefaulted = 0x0001, + GroupDefaulted = 0x0002, + DaclPresent = 0x0004, + DaclDefaulted = 0x0008, + SaclPresent = 0x0010, + SaclDefaulted = 0x0020, + DaclUntrusted = 0x0040, + ServerSecurity = 0x0080, + DaclAutoInheritReq = 0x0100, + SaclAutoInheritReq = 0x0200, + DaclAutoInherited = 0x0400, + SaclAutoInherited = 0x0800, + DaclProtected = 0x1000, + SaclProtected = 0x2000, + RmControlValid = 0x4000, + SelfRelative = 0x8000 + } + + public enum SecurityImpersonationLevel : int + { + SecurityAnonymous, + SecurityIdentification, + SecurityImpersonation, + SecurityDelegation + } + + [Flags] + public enum SecurityInformation : uint + { + Owner = 0x00000001, + Group = 0x00000002, + Dacl = 0x00000004, + Sacl = 0x00000008, + Label = 0x00000010, + + ProtectedDacl = 0x80000000, + ProtectedSacl = 0x40000000, + UnprotectedDacl = 0x20000000, + UnprotectedSacl = 0x10000000 + } + + public enum SemaphoreInformationClass : int + { + SemaphoreBasicInformation + } + + [Flags] + public enum SidAttributes : uint + { + Mandatory = 0x00000001, + EnabledByDefault = 0x00000002, + Enabled = 0x00000004, + Owner = 0x00000008, + UseForDenyOnly = 0x00000010, + Integrity = 0x00000020, + IntegrityEnabled = 0x00000040, + LogonId = 0xc0000000, + Resource = 0x20000000 + } + + public enum SidNameUse : int + { + User = 1, + Group, + Domain, + Alias, + WellKnownGroup, + DeletedAccount, + Invalid, + Unknown, + Computer, + Label + } + + [Flags] + public enum SiRequested : uint + { + OwnerSecurityInformation = 0x1, + GroupSecurityInformation = 0x2, + DaclSecurityInformation = 0x4, + SaclSecurityInformation = 0x8, + LabelSecurityInformation = 0x10 + } + + [Flags] + public enum SuiteType : uint + { + SmallBusiness = 0x00000001, + Enterprise = 0x00000002, + BackOffice = 0x00000004, + Communications = 0x00000008, + Terminal = 0x00000010, + SmallBusinessRestricted = 0x00000020, + EmbeddedNt = 0x00000040, + DataCenter = 0x00000080, + SingleUserTs = 0x00000100, + Personal = 0x00000200, + Blade = 0x00000400, + EmbeddedRestricted = 0x00000800, + SecurityAppliance = 0x00001000, + StorageServer = 0x00002000, + ComputeServer = 0x00004000, + + WorkstationNt = 0x40000000, + ServerNt = 0x80000000 + } + + public enum SystemInformationClass : int + { + SystemBasicInformation, + SystemProcessorInformation, + SystemPerformanceInformation, + SystemTimeOfDayInformation, + SystemPathInformation, + SystemProcessInformation, + SystemCallCountInformation, + SystemDeviceInformation, + SystemProcessorPerformanceInformation, + SystemFlagsInformation, + SystemCallTimeInformation, // 10 + SystemModuleInformation, + SystemLocksInformation, + SystemStackTraceInformation, + SystemPagedPoolInformation, + SystemNonPagedPoolInformation, + SystemHandleInformation, + SystemObjectInformation, + SystemPageFileInformation, + SystemVdmInstemulInformation, + SystemVdmBopInformation, // 20 + SystemFileCacheInformation, + SystemPoolTagInformation, + SystemInterruptInformation, + SystemDpcBehaviorInformation, + SystemFullMemoryInformation, + SystemLoadGdiDriverInformation, + SystemUnloadGdiDriverInformation, + SystemTimeAdjustmentInformation, + SystemSummaryMemoryInformation, + SystemMirrorMemoryInformation, // 30 + SystemPerformanceTraceInformation, + SystemCrashDumpInformation, + SystemExceptionInformation, + SystemCrashDumpStateInformation, + SystemKernelDebuggerInformation, + SystemContextSwitchInformation, + SystemRegistryQuotaInformation, + SystemExtendServiceTableInformation, // used to be SystemLoadAndCallImage + SystemPrioritySeparation, + SystemVerifierAddDriverInformation, // 40 + SystemVerifierRemoveDriverInformation, + SystemProcessorIdleInformation, + SystemLegacyDriverInformation, + SystemCurrentTimeZoneInformation, + SystemLookasideInformation, + SystemTimeSlipNotification, + SystemSessionCreate, + SystemSessionDetach, + SystemSessionInformation, + SystemRangeStartInformation, // 50 + SystemVerifierInformation, + SystemVerifierThunkExtend, + SystemSessionProcessInformation, + SystemLoadGdiDriverInSystemSpace, + SystemNumaProcessorMap, + SystemPrefetcherInformation, + SystemExtendedProcessInformation, + SystemRecommendedSharedDataAlignment, + SystemComPlusPackage, + SystemNumaAvailableMemory, // 60 + SystemProcessorPowerInformation, + SystemEmulationBasicInformation, + SystemEmulationProcessorInformation, + SystemExtendedHandleInformation, + SystemLostDelayedWriteInformation, + SystemBigPoolInformation, + SystemSessionPoolTagInformation, + SystemSessionMappedViewInformation, + SystemHotpatchInformation, + SystemObjectSecurityMode, // 70 + SystemWatchdogTimerHandler, // doesn't seem to be implemented + SystemWatchdogTimerInformation, + SystemLogicalProcessorInformation, + SystemWow64SharedInformation, + SystemRegisterFirmwareTableInformationHandler, + SystemFirmwareTableInformation, + SystemModuleInformationEx, + SystemVerifierTriageInformation, + SystemSuperfetchInformation, + SystemMemoryListInformation, // 80 + SystemFileCacheInformationEx, + SystemNotImplemented19, + SystemProcessorDebugInformation, + SystemVerifierInformation2, + SystemNotImplemented20, + SystemRefTraceInformation, + SystemSpecialPoolTag, // MmSpecialPoolTag, then MmSpecialPoolCatchOverruns != 0 + SystemProcessImageName, + SystemNotImplemented21, + SystemBootEnvironmentInformation, // 90 + SystemEnlightenmentInformation, + SystemVerifierInformationEx, + SystemNotImplemented22, + SystemNotImplemented23, + SystemCovInformation, + SystemNotImplemented24, + SystemNotImplemented25, + SystemPartitionInformation, + SystemSystemDiskInformation, // this and SystemPartitionInformation both call IoQuerySystemDeviceName + SystemPerformanceDistributionInformation, // 100 + SystemNumaProximityNodeInformation, + SystemTimeZoneInformation2, + SystemCodeIntegrityInformation, + SystemNotImplemented26, + SystemUnknownInformation, // No symbols for this case, very strange... + SystemVaInformation // 106, calls MmQuerySystemVaInformation + } + + public enum ThreadInformationClass : uint + { + ThreadBasicInformation, + ThreadTimes, + ThreadPriority, + ThreadBasePriority, + ThreadAffinityMask, + ThreadImpersonationToken, + ThreadDescriptorTableEntry, + ThreadEnableAlignmentFaultFixup, + ThreadEventPair, + ThreadQuerySetWin32StartAddress, + ThreadZeroTlsCell, // 10 + ThreadPerformanceCount, + ThreadAmILastThread, + ThreadIdealProcessor, + ThreadPriorityBoost, + ThreadSetTlsArrayAddress, + ThreadIsIoPending, + ThreadHideFromDebugger, + ThreadBreakOnTermination, + ThreadSwitchLegacyState, + ThreadIsTerminated, // 20 + ThreadLastSystemCall, + ThreadIoPriority, + ThreadCycleTime, + ThreadPagePriority, + ThreadActualBasePriority, + ThreadTebInformation, + ThreadCSwitchMon, + MaxThreadInfoClass + } + + public enum TimerInformationClass : int + { + TimerBasicInformation + } + + public enum TimerType : int + { + NotificationTimer, + SynchronizationTimer + } + + public enum TmInformationClass : int + { + TransactionManagerBasicInformation, + TransactionManagerLogInformation, + TransactionManagerLogPathInformation, + TransactionManagerOnlineProbeInformation, + TransactionManagerRecoveryInformation + } + + [Flags] + public enum TmOptions : int + { + Volatile = 0x1, + CommitDefault = 0x0, + CommitSystemVolume = 0x2, + CommitSystemHives = 0x4, + CommitLowest = 0x8, + CorruptForRecovery = 0x10, + CorruptForProgress = 0x20, + MaximumOption = 0x3f + } + + public enum TokenElevationType : int + { + Default = 1, + Full, + Limited + } + + public enum TokenInformationClass + { + TokenUser = 1, + TokenGroups, + TokenPrivileges, + TokenOwner, + TokenPrimaryGroup, + TokenDefaultDacl, + TokenSource, + TokenType, + TokenImpersonationLevel, + TokenStatistics, // 10 + TokenRestrictedSids, + TokenSessionId, + TokenGroupsAndPrivileges, + TokenSessionReference, + TokenSandBoxInert, + TokenAuditPolicy, + TokenOrigin, + TokenElevationType, + TokenLinkedToken, + TokenElevation, // 20 + TokenHasRestrictions, + TokenAccessInformation, + TokenVirtualizationAllowed, + TokenVirtualizationEnabled, + TokenIntegrityLevel, + TokenUIAccess, + TokenMandatoryPolicy, + TokenLogonSid, + MaxTokenInfoClass // MaxTokenInfoClass should always be the last enum + } + + public enum TokenType : int + { + Primary = 1, + Impersonation + } + + public enum TransactionInformationClass : int + { + TransactionBasicInformation, + TransactionPropertiesInformation, + TransactionEnlistmentInformation, + TransactionFullInformation + } + + [Flags] + public enum TransactionOptions : int + { + DoNotPromote = 0x1, + MaximumOption = 0x1 + } + + public enum TransactionOutcome : int + { + Undetermined = 1, + Committed, + Aborted + } + + public enum TransactionState : int + { + Normal = 1, + Indoubt, + CommittedNotify + } + + public enum WaitType : int + { + WaitAll, + WaitAny + } + + public enum WellKnownSidType : int + { + WinNullSid = 0, + WinWorldSid = 1, + WinLocalSid = 2, + WinCreatorOwnerSid = 3, + WinCreatorGroupSid = 4, + WinCreatorOwnerServerSid = 5, + WinCreatorGroupServerSid = 6, + WinNtAuthoritySid = 7, + WinDialupSid = 8, + WinNetworkSid = 9, + WinBatchSid = 10, + WinInteractiveSid = 11, + WinServiceSid = 12, + WinAnonymousSid = 13, + WinProxySid = 14, + WinEnterpriseControllersSid = 15, + WinSelfSid = 16, + WinAuthenticatedUserSid = 17, + WinRestrictedCodeSid = 18, + WinTerminalServerSid = 19, + WinRemoteLogonIdSid = 20, + WinLogonIdsSid = 21, + WinLocalSystemSid = 22, + WinLocalServiceSid = 23, + WinNetworkServiceSid = 24, + WinBuiltinDomainSid = 25, + WinBuiltinAdministratorsSid = 26, + WinBuiltinUsersSid = 27, + WinBuiltinGuestsSid = 28, + WinBuiltinPowerUsersSid = 29, + WinBuiltinAccountOperatorsSid = 30, + WinBuiltinSystemOperatorsSid = 31, + WinBuiltinPrintOperatorsSid = 32, + WinBuiltinBackupOperatorsSid = 33, + WinBuiltinReplicatorSid = 34, + WinBuiltinPreWindows2000CompatibleAccessSid = 35, + WinBuiltinRemoteDesktopUsersSid = 36, + WinBuiltinNetworkConfigurationOperatorsSid = 37, + WinAccountAdministratorSid = 38, + WinAccountGuestSid = 39, + WinAccountKrbtgtSid = 40, + WinAccountDomainAdminsSid = 41, + WinAccountDomainUsersSid = 42, + WinAccountDomainGuestsSid = 43, + WinAccountComputersSid = 44, + WinAccountControllersSid = 45, + WinAccountCertAdminsSid = 46, + WinAccountSchemaAdminsSid = 47, + WinAccountEnterpriseAdminsSid = 48, + WinAccountPolicyAdminsSid = 49, + WinAccountRasAndIasServersSid = 50, + WinNTLMAuthenticationSid = 51, + WinDigestAuthenticationSid = 52, + WinSChannelAuthenticationSid = 53, + WinThisOrganizationSid = 54, + WinOtherOrganizationSid = 55, + WinBuiltinIncomingForestTrustBuildersSid = 56, + WinBuiltinPerfMonitoringUsersSid = 57, + WinBuiltinPerfLoggingUsersSid = 58, + WinBuiltinAuthorizationAccessSid = 59, + WinBuiltinTerminalServerLicenseServersSid = 60, + WinBuiltinDCOMUsersSid = 61, + WinBuiltinIUsersSid = 62, + WinIUserSid = 63, + WinBuiltinCryptoOperatorsSid = 64, + WinUntrustedLabelSid = 65, + WinLowLabelSid = 66, + WinMediumLabelSid = 67, + WinHighLabelSid = 68, + WinSystemLabelSid = 69, + WinWriteRestrictedCodeSid = 70, + WinCreatorOwnerRightsSid = 71, + WinCacheablePrincipalsGroupSid = 72, + WinNonCacheablePrincipalsGroupSid = 73, + WinEnterpriseReadonlyControllersSid = 74, + WinAccountReadonlyControllersSid = 75, + WinBuiltinEventLogReadersGroup = 76, + WinNewEnterpriseReadonlyControllersSid = 77, + WinBuiltinCertSvcDComAccessGroup = 78 + } + + public enum WinNtProductType : int + { + WinNt = 1, + LanManNt, + Server + } + + [Flags] + public enum WtFlags : uint + { + ExecuteDefault = 0x0, + ExecuteInIoThread = 0x1, + ExecuteInUiThread = 0x2, + ExecuteInWaitThread = 0x4, + ExecuteOnlyOnce = 0x8, + ExecuteLongFunction = 0x10, + ExecuteInTimerThread = 0x20, + ExecuteInPersistentIoThread = 0x40, + ExecuteInPersistentThread = 0x80, + TransferImpersonation = 0x100 + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Api/NativeFunctions.cs b/branches/ph-plugins/ProcessHacker.Native/Api/NativeFunctions.cs new file mode 100644 index 000000000..a94d8d23a --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Api/NativeFunctions.cs @@ -0,0 +1,3771 @@ +/* + * Process Hacker - + * native API functions + * + * Copyright (C) 2009 Flavio Erlich + * Copyright (C) 2008-2009 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 file contains function declarations for the Native API. + * + * Only functions from ntdll.dll are considered to be part of the + * Native API. + */ + +// Parameter 'parameter' has no matching param tag in the XML comment for 'parameter' (but other parameters do) +#pragma warning disable 1573 + +using System; +using System.Runtime.InteropServices; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Api +{ + public static partial class Win32 + { + // IMPORTANT: All timeouts, etc. are in 100ns units except when stated otherwise. + + // These definitions were gathered from these sources: + // + // * The NT API headers - almost everything + // * Alex Ionescu's NDK + // * ReactOS source code + // * The Windows DDK - Kernel Transaction Manager (KTM) types + + #region System Calls + + [DllImport("ntdll.dll")] + public static extern NtStatus NtAcceptConnectPort( + [Out] out IntPtr PortHandle, + [In] [Optional] IntPtr PortContext, + [In] IntPtr ConnectionRequest, + [In] bool AcceptConnection, + [Optional] ref PortView ServerView, + [Optional] ref RemotePortView ClientView + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtAcceptConnectPort( + [Out] out IntPtr PortHandle, + [In] [Optional] IntPtr PortContext, + [In] IntPtr ConnectionRequest, + [In] bool AcceptConnection, + [Optional] IntPtr ServerView, + [Optional] IntPtr ClientView + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtAccessCheck( + [In] IntPtr SecurityDescriptor, + [In] IntPtr ClientToken, + [In] int DesiredAccess, + [In] ref GenericMapping GenericMapping, + [In] [Optional] IntPtr PrivilegeSet, // out PrivilegeSet* + ref int PrivilegeSetLength, + [Out] out int GrantedAccess, + [Out] out NtStatus AccessStatus + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtAdjustGroupsToken( + [In] IntPtr TokenHandle, + [In] bool ResetToDefault, + [In] ref TokenGroups NewState, + [In] [Optional] int BufferLength, + [In] [Optional] IntPtr PreviousState, // out TokenGroups* + [In] [Optional] IntPtr ReturnLength // out int* + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtAdjustPrivilegesToken( + [In] IntPtr TokenHandle, + [In] bool DisableAllPrivileges, + [In] [Optional] ref TokenPrivileges NewState, + [In] [Optional] int BufferLength, + [In] [Optional] IntPtr PreviousState, // out TokenPrivileges* + [In] [Optional] IntPtr ReturnLength // out int* + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtAlertThread( + [In] IntPtr ThreadHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtAlertResumeThread( + [In] IntPtr ThreadHandle, + [Out] [Optional] out int PreviousSuspendCount + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtAllocateLocallyUniqueId( + [Out] out Luid Luid + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtAllocateVirtualMemory( + [In] IntPtr ProcessHandle, + ref IntPtr BaseAddress, + [In] IntPtr ZeroBits, + ref IntPtr RegionSize, + [In] MemoryFlags AllocationType, + [In] MemoryProtection Protect + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtAreMappedFilesTheSame( + [In] IntPtr File1MappedAsAnImage, + [In] IntPtr File2MappedAsFile + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtAssignProcessToJobObject( + [In] IntPtr JobHandle, + [In] IntPtr ProcessHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCancelIoFile( + [In] IntPtr FileHandle, + [Out] out IoStatusBlock IoStatusBlock + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCancelIoFile( + [In] IntPtr FileHandle, + [In] IntPtr IoStatusBlock + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCancelTimer( + [In] IntPtr TimerHandle, + [Out] [Optional] out bool CurrentState + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtClearEvent( + [In] IntPtr EventHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtClose( + [In] IntPtr Handle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCommitComplete( + [In] IntPtr EnlistmentHandle, + [In] [Optional] ref long TmVirtualClock + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCommitEnlistment( + [In] IntPtr EnlistmentHandle, + [In] [Optional] ref long TmVirtualClock + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCommitTransaction( + [In] IntPtr TransactionHandle, + [In] bool Wait + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCompareTokens( + [In] IntPtr FirstTokenHandle, + [In] IntPtr SecondTokenHandle, + [MarshalAs(UnmanagedType.I1)] + [Out] out bool Equal + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCompleteConnectPort( + [In] IntPtr PortHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtConnectPort( + [Out] out IntPtr PortHandle, + [In] ref UnicodeString PortName, + [In] ref SecurityQualityOfService SecurityQos, + [Optional] ref PortView ClientView, + [Optional] ref RemotePortView ServerView, + [Out] [Optional] out int MaxMessageLength, + [Optional] IntPtr ConnectionInformation, + [Optional] ref int ConnectionInformationLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtConnectPort( + [Out] out IntPtr PortHandle, + [In] ref UnicodeString PortName, + [In] ref SecurityQualityOfService SecurityQos, + [Optional] IntPtr ClientView, + [Optional] IntPtr ServerView, + [Out] [Optional] out int MaxMessageLength, + [Optional] IntPtr ConnectionInformation, + [Optional] ref int ConnectionInformationLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtConnectPort( + [Out] out IntPtr PortHandle, + [In] ref UnicodeString PortName, + [In] ref SecurityQualityOfService SecurityQos, + [Optional] ref PortView ClientView, + [Optional] ref RemotePortView ServerView, + [Out] [Optional] IntPtr MaxMessageLength, + [Optional] IntPtr ConnectionInformation, + [Optional] IntPtr ConnectionInformationLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtConnectPort( + [Out] out IntPtr PortHandle, + [In] ref UnicodeString PortName, + [In] ref SecurityQualityOfService SecurityQos, + [Optional] IntPtr ClientView, + [Optional] IntPtr ServerView, + [Out] [Optional] IntPtr MaxMessageLength, + [Optional] IntPtr ConnectionInformation, + [Optional] IntPtr ConnectionInformationLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateDebugObject( + [Out] out IntPtr DebugObjectHandle, + [In] DebugObjectAccess DesiredAccess, + [In] [Optional] ref ObjectAttributes ObjectAttributes, + [In] DebugObjectFlags Flags + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateDebugObject( + [Out] out IntPtr DebugObjectHandle, + [In] DebugObjectAccess DesiredAccess, + [In] [Optional] IntPtr ObjectAttributes, + [In] DebugObjectFlags Flags + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateDirectoryObject( + [Out] out IntPtr DirectoryHandle, + [In] DirectoryAccess DesiredAccess, + [In] ref ObjectAttributes ObjectAttributes + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateEnlistment( + [Out] out IntPtr EnlistmentHandle, + [In] EnlistmentAccess DesiredAccess, + [In] IntPtr ResourceManagerHandle, + [In] IntPtr TransactionHandle, + [In] [Optional] ref ObjectAttributes ObjectAttributes, + [In] [Optional] EnlistmentOptions CreateOptions, + [In] NotificationMask NotificationMask, + [In] [Optional] IntPtr EnlistmentKey + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateEvent( + [Out] out IntPtr EventHandle, + [In] EventAccess DesiredAccess, + [In] [Optional] ref ObjectAttributes ObjectAttributes, + [In] EventType EventType, + [In] bool InitialState + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateEvent( + [Out] out IntPtr EventHandle, + [In] EventAccess DesiredAccess, + [In] [Optional] IntPtr ObjectAttributes, + [In] EventType EventType, + [In] bool InitialState + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateEventPair( + [Out] out IntPtr EventPairHandle, + [In] EventPairAccess DesiredAccess, + [In] [Optional] ref ObjectAttributes ObjectAttributes + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateEventPair( + [Out] out IntPtr EventPairHandle, + [In] EventPairAccess DesiredAccess, + [In] [Optional] IntPtr ObjectAttributes + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateFile( + [Out] out IntPtr FileHandle, + [In] FileAccess DesiredAccess, + [In] ref ObjectAttributes ObjectAttributes, + [Out] out IoStatusBlock IoStatusBlock, + [In] [Optional] ref long allocationSize, + [In] FileAttributes fileAttributes, + [In] FileShareMode shareAccess, + [In] FileCreationDisposition createDisposition, + [In] FileCreateOptions createOptions, + [In] [Optional] IntPtr EaBuffer, + [In] int EaLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateIoCompletion( + [Out] out IntPtr IoCompletionHandle, + [In] IoCompletionAccess DesiredAccess, + [In] [Optional] ref ObjectAttributes ObjectAttributes, + [In] [Optional] int Count + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateIoCompletion( + [Out] out IntPtr IoCompletionHandle, + [In] IoCompletionAccess DesiredAccess, + [In] [Optional] IntPtr ObjectAttributes, + [In] [Optional] int Count + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateJobObject( + [Out] out IntPtr JobHandle, + [In] JobObjectAccess DesiredAccess, + [In] [Optional] ref ObjectAttributes ObjectAttributes + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateJobObject( + [Out] out IntPtr JobHandle, + [In] JobObjectAccess DesiredAccess, + [In] [Optional] IntPtr ObjectAttributes + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateJobSet( + [In] int NumJob, + JobSetArray[] UserJobSet, + [In] int Flags + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateKey( + [Out] out IntPtr KeyHandle, + [In] KeyAccess DesiredAccess, + [In] ref ObjectAttributes ObjectAttributes, + [In] int TitleIndex, + [In] [Optional] ref UnicodeString Class, + [In] RegOptions CreateOptions, + [Out] [Optional] out KeyCreationDisposition Disposition + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateKey( + [Out] out IntPtr KeyHandle, + [In] KeyAccess DesiredAccess, + [In] ref ObjectAttributes ObjectAttributes, + [In] int TitleIndex, + [In] [Optional] IntPtr Class, + [In] RegOptions CreateOptions, + [Out] [Optional] out KeyCreationDisposition Disposition + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateKeyedEvent( + [Out] out IntPtr KeyedEventHandle, + [In] KeyedEventAccess DesiredAccess, + [In] [Optional] ref ObjectAttributes ObjectAttributes, + [In] int Flags + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateKeyedEvent( + [Out] out IntPtr KeyedEventHandle, + [In] KeyedEventAccess DesiredAccess, + [In] [Optional] IntPtr ObjectAttributes, + [In] int Flags + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateMailslotFile( + [Out] out IntPtr FileHandle, + [In] FileAccess DesiredAccess, + [In] ref ObjectAttributes ObjectAttributes, + [Out] out IoStatusBlock IoStatusBlock, + [In] FileCreateOptions CreateOptions, + [In] int MailslotQuota, + [In] int MaximumMessageSize, + [In] ref long ReadTimeout + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateMutant( + [Out] out IntPtr MutantHandle, + [In] MutantAccess DesiredAccess, + [In] [Optional] ref ObjectAttributes ObjectAttributes, + [In] bool InitialOwner + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateMutant( + [Out] out IntPtr MutantHandle, + [In] MutantAccess DesiredAccess, + [In] [Optional] IntPtr ObjectAttributes, + [In] bool InitialOwner + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateNamedPipeFile( + [Out] out IntPtr FileHandle, + [In] FileAccess DesiredAccess, + [In] ref ObjectAttributes ObjectAttributes, + [Out] out IoStatusBlock IoStatusBlock, + [In] FileShareMode ShareAccess, + [In] FileCreationDisposition CreateDisposition, + [In] FileCreateOptions CreateOptions, + [In] PipeType NamedPipeType, + [In] PipeType ReadMode, + [In] PipeCompletionMode CompletionMode, + [In] int MaximumInstances, + [In] int InboundQuota, + [In] int OutboundQuota, + [In] [Optional] ref long DefaultTimeout + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreatePort( + [Out] out IntPtr PortHandle, + [In] ref ObjectAttributes ObjectAttributes, + [In] int MaxConnectionInfoLength, + [In] int MaxMessageLength, + [In] [Optional] int MaxPoolUsage + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateProcess( + [Out] out IntPtr ProcessHandle, + [In] ProcessAccess DesiredAccess, + [In] [Optional] ref ObjectAttributes ObjectAttributes, + [In] IntPtr ParentProcess, + [In] bool InheritHandleTable, + [In] [Optional] IntPtr SectionHandle, + [In] [Optional] IntPtr DebugPort, + [In] [Optional] IntPtr ExceptionPort + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateProcess( + [Out] out IntPtr ProcessHandle, + [In] ProcessAccess DesiredAccess, + [In] [Optional] IntPtr ObjectAttributes, + [In] IntPtr ParentProcess, + [In] bool InheritHandleTable, + [In] [Optional] IntPtr SectionHandle, + [In] [Optional] IntPtr DebugPort, + [In] [Optional] IntPtr ExceptionPort + ); + + /// + /// Creates a profile object. + /// + /// A handle to the profile object. + /// + /// A handle to the process to profile. If NULL, all address spaces are profiled. + /// + /// + /// The first address at which to collect profiling information. + /// + /// + /// The size of the range to profile. ProfileBase <= address < + /// ProfileBase + ProfileSize will generate a hit. + /// + /// + /// A log2 value of each address bucket. Acceptable values are from 2 to 30. + /// + /// An array of int hit counters. + /// The size of the buffer, in bytes. + /// The profiling source. + /// The processors to profile. + /// A NTSTATUS value. + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateProfile( + [Out] out IntPtr ProfileHandle, + [In] [Optional] IntPtr ProcessHandle, + [In] IntPtr ProfileBase, + [In] IntPtr ProfileSize, + [In] int BucketSize, + [In] IntPtr Buffer, + [In] int BufferSize, + [In] KProfileSource ProfileSource, + [In] IntPtr Affinity + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateResourceManager( + [Out] out IntPtr ResourceManagerHandle, + [In] ResourceManagerAccess DesiredAccess, + [In] IntPtr TmHandle, + [In] [Optional] ref Guid ResourceManagerGuid, + [In] [Optional] ref ObjectAttributes ObjectAttributes, + [In] [Optional] ResourceManagerOptions CreateOptions, + [In] [Optional] ref UnicodeString Description // should be null-terminated + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateSection( + [Out] out IntPtr SectionHandle, + [In] SectionAccess DesiredAccess, + [In] [Optional] ref ObjectAttributes ObjectAttributes, + [In] [Optional] ref long MaximumSize, + [In] MemoryProtection PageAttributes, + [In] SectionAttributes SectionAttributes, + [In] [Optional] IntPtr FileHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateSection( + [Out] out IntPtr SectionHandle, + [In] SectionAccess DesiredAccess, + [In] [Optional] ref ObjectAttributes ObjectAttributes, + [In] [Optional] IntPtr MaximumSize, + [In] MemoryProtection PageAttributes, + [In] SectionAttributes SectionAttributes, + [In] [Optional] IntPtr FileHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateSection( + [Out] out IntPtr SectionHandle, + [In] SectionAccess DesiredAccess, + [In] [Optional] IntPtr ObjectAttributes, + [In] [Optional] ref long MaximumSize, + [In] int PageAttributes, + [In] int SectionAttributes, + [In] [Optional] IntPtr FileHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateSemaphore( + [Out] out IntPtr SemaphoreHandle, + [In] SemaphoreAccess DesiredAccess, + [In] [Optional] ref ObjectAttributes ObjectAttributes, + [In] int InitialCount, + [In] int MaximumCount + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateSemaphore( + [Out] out IntPtr SemaphoreHandle, + [In] SemaphoreAccess DesiredAccess, + [In] [Optional] IntPtr ObjectAttributes, + [In] int InitialCount, + [In] int MaximumCount + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateSymbolicLinkObject( + [Out] out IntPtr LinkHandle, + [In] SymbolicLinkAccess DesiredAccess, + [In] ref ObjectAttributes ObjectAttributes, + [In] ref UnicodeString LinkTarget + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateThread( + [Out] out IntPtr ThreadHandle, + [In] ThreadAccess DesiredAccess, + [In] [Optional] ref ObjectAttributes ObjectAttributes, + [In] IntPtr ProcessHandle, + [Out] out ClientId ClientId, + [In] ref Context ThreadContext, + [In] ref InitialTeb InitialTeb, + [In] bool CreateSuspended + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateThreadEx( + [Out] out IntPtr ThreadHandle, + [In] ThreadAccess DesiredAccess, + [In] [Optional] ref ObjectAttributes ObjectAttributes, + [In] IntPtr ProcessHandle, + [In] IntPtr StartAddress, + [In] IntPtr Parameter, + [In] int Flags, + [In] [Optional] int Reserved, + [In] [Optional] int StackCommit, + [In] [Optional] int StackReserve, + [In] [Optional] IntPtr Unknown + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateTimer( + [Out] out IntPtr TimerHandle, + [In] TimerAccess DesiredAccess, + [In] [Optional] ref ObjectAttributes ObjectAttributes, + [In] TimerType TimerType + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateTimer( + [Out] out IntPtr TimerHandle, + [In] TimerAccess DesiredAccess, + [In] [Optional] IntPtr ObjectAttributes, + [In] TimerType TimerType + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateToken( + [Out] out IntPtr TokenHandle, + [In] TokenAccess DesiredAccess, + [In] [Optional] ref ObjectAttributes ObjectAttributes, + [In] TokenType TokenType, + [In] ref Luid AuthenticationId, + [In] ref long ExpirationTime, + [In] ref TokenUser User, + [In] ref TokenGroups Groups, + [In] ref TokenPrivileges Privileges, + [In] [Optional] ref TokenOwner Owner, + [In] ref TokenPrimaryGroup PrimaryGroup, + [In] [Optional] ref TokenDefaultDacl DefaultDacl, + [In] ref TokenSource TokenSource + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateTransaction( + [Out] out IntPtr TransactionHandle, + [In] TransactionAccess DesiredAccess, + [In] [Optional] ref ObjectAttributes ObjectAttributes, + [In] [Optional] ref Guid Uow, // Unit of work identifier + [In] [Optional] IntPtr TmHandle, + [In] [Optional] TransactionOptions CreateOptions, + [In] [Optional] int IsolationLevel, // Reserved + [In] [Optional] int IsolationFlags, // Reserved + [In] [Optional] ref long Timeout, + [In] [Optional] ref UnicodeString Description + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateTransactionManager( + [Out] out IntPtr TmHandle, + [In] TmAccess DesiredAccess, + [In] [Optional] ref ObjectAttributes ObjectAttributes, + [In] [Optional] ref UnicodeString LogFileName, + [In] [Optional] TmOptions CreateOptions, + [In] [Optional] int CreateStrength // Reserved + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtCreateWaitablePort( + [Out] out IntPtr PortHandle, + [In] ref ObjectAttributes ObjectAttributes, + [In] int MaxConnectionInfoLength, + [In] int MaxMessageLength, + [In] [Optional] int MaxPoolUsage + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtDebugActiveProcess( + [In] IntPtr ProcessHandle, + [In] IntPtr DebugObjectHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtDebugContinue( + [In] IntPtr DebugObjectHandle, + [In] ref ClientId ClientId, + [In] NtStatus ContinueStatus + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtDelayExecution( + [In] bool Alertable, + [In] ref long DelayInterval + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtDeleteFile( + [In] ref ObjectAttributes ObjectAttributes + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtDeleteKey( + [In] IntPtr KeyHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtDeleteValueKey( + [In] IntPtr KeyHandle, + [In] ref UnicodeString ValueName + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtDeviceIoControlFile( + [In] IntPtr FileHandle, + [In] IntPtr Event, + [In] IoApcRoutine ApcRoutine, + [In] IntPtr ApcContext, + [Out] out IoStatusBlock IoStatusBlock, + [In] int IoControlCode, + [In] IntPtr InputBuffer, + [In] int InputBufferLength, + [In] IntPtr OutputBuffer, + [In] int OutputBufferLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtDeviceIoControlFile( + [In] IntPtr FileHandle, + [In] IntPtr Event, + [In] IoApcRoutine ApcRoutine, + [In] IntPtr ApcContext, + [In] IntPtr IoStatusBlock, + [In] int IoControlCode, + [In] IntPtr InputBuffer, + [In] int InputBufferLength, + [In] IntPtr OutputBuffer, + [In] int OutputBufferLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtDuplicateObject( + [In] IntPtr SourceProcessHandle, + [In] IntPtr SourceHandle, + [In] IntPtr TargetProcessHandle, + [Out] out IntPtr TargetHandle, + [In] int DesiredAccess, + [In] HandleFlags Attributes, + [In] DuplicateOptions Options + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtDuplicateToken( + [In] IntPtr ExistingTokenHandle, + [In] TokenAccess DesiredAccess, + [In] ref ObjectAttributes ObjectAttributes, + [In] bool EffectiveOnly, + [In] TokenType TokenType, + [Out] out IntPtr NewTokenHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtEnumerateTransactionObject( + [In] [Optional] IntPtr RootObjectHandle, + [In] KtmObjectType QueryType, + ref KtmObjectCursor ObjectCursor, + [In] int ObjectCursorLength, + [Out] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtExtendSection( + [In] IntPtr SectionHandle, + ref long NewSectionSize + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtFilterToken( + [In] IntPtr ExistingTokenHandle, + [In] int Flags, + [In] [Optional] ref TokenGroups SidsToDisable, + [In] [Optional] ref TokenPrivileges PrivilegesToDelete, + [In] [Optional] ref TokenGroups RestrictedSids, + [Out] out IntPtr NewTokenHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtFlushBuffersFile( + [In] IntPtr FileHandle, + [Out] out IoStatusBlock IoStatusBlock + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtFlushKey( + [In] IntPtr KeyHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtFlushVirtualMemory( + [In] IntPtr ProcessHandle, + ref IntPtr BaseAddress, + ref IntPtr RegionSize, + [Out] out IoStatusBlock IoStatus + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtFreeVirtualMemory( + [In] IntPtr ProcessHandle, + ref IntPtr BaseAddress, + ref IntPtr RegionSize, + [In] MemoryFlags FreeType + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtFsControlFile( + [In] IntPtr FileHandle, + [In] IntPtr Event, + [In] IoApcRoutine ApcRoutine, + [In] IntPtr ApcContext, + [Out] out IoStatusBlock IoStatusBlock, + [In] int FsControlCode, + [In] IntPtr InputBuffer, + [In] int InputBufferLength, + [In] IntPtr OutputBuffer, + [In] int OutputBufferLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtFsControlFile( + [In] IntPtr FileHandle, + [In] IntPtr Event, + [In] IoApcRoutine ApcRoutine, + [In] IntPtr ApcContext, + [In] IntPtr IoStatusBlock, + [In] int FsControlCode, + [In] IntPtr InputBuffer, + [In] int InputBufferLength, + [In] IntPtr OutputBuffer, + [In] int OutputBufferLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtGetContextThread( + [In] IntPtr ThreadHandle, + [In] IntPtr ThreadContext + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtGetContextThread( + [In] IntPtr ThreadHandle, + ref Context ThreadContext + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtGetContextThread( + [In] IntPtr ThreadHandle, + ref ContextAmd64 ThreadContext + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtGetCurrentProcessorNumber(); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtGetNextProcess( + [In] [Optional] IntPtr ProcessHandle, + [In] ProcessAccess DesiredAccess, + [In] HandleFlags HandleAttributes, + [In] int Flags, + [Out] out IntPtr NewProcessHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtGetNextThread( + [In] [Optional] IntPtr ProcessHandle, + [In] [Optional] IntPtr ThreadHandle, + [In] ThreadAccess DesiredAccess, + [In] HandleFlags HandleAttributes, + [In] int Flags, + [Out] out IntPtr NewThreadHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtGetNotificationResourceManager( + [In] IntPtr ResourceManagerHandle, + [In] IntPtr TransactionNotification, // TransactionNotification* + [In] int NotificationLength, + [In] ref long Timeout, + [Out] [Optional] out int ReturnLength, + [In] int Asynchronous, // Must be zero. + [In] [Optional] IntPtr AsynchronousContext + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtImpersonateAnonymousToken( + [In] IntPtr ThreadHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtImpersonateClientOfPort( + [In] IntPtr PortHandle, + [In] IntPtr Message + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtImpersonateThread( + [In] IntPtr ServerThreadHandle, + [In] IntPtr ClientThreadHandle, + [In] ref SecurityQualityOfService SecurityQos + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtIsProcessInJob( + [In] IntPtr ProcessHandle, + [In] [Optional] IntPtr JobHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtListenPort( + [In] IntPtr PortHandle, + [In] IntPtr ConnectionRequest + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtLoadDriver( + [In] ref UnicodeString DriverServiceName + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtLockFile( + [In] IntPtr FileHandle, + [In] [Optional] IntPtr Event, + [In] [Optional] IoApcRoutine ApcRoutine, + [In] [Optional] IntPtr ApcContext, + [Out] out IoStatusBlock IoStatusBlock, + [In] ref long ByteOffset, + [In] ref long Length, + [In] int Key, + [In] bool FailImmediately, + [In] bool ExclusiveLock + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtLockFile( + [In] IntPtr FileHandle, + [In] [Optional] IntPtr Event, + [In] [Optional] IoApcRoutine ApcRoutine, + [In] [Optional] IntPtr ApcContext, + [In] IntPtr IoStatusBlock, + [In] ref long ByteOffset, + [In] ref long Length, + [In] int Key, + [In] bool FailImmediately, + [In] bool ExclusiveLock + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtLockVirtualMemory( + [In] IntPtr ProcessHandle, + ref IntPtr BaseAddress, + ref IntPtr RegionSize, + [In] MemoryFlags MapType + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtMakePermanentObject( + [In] IntPtr Handle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtMakeTemporaryObject( + [In] IntPtr Handle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtMapViewOfSection( + [In] IntPtr SectionHandle, + [In] IntPtr ProcessHandle, + ref IntPtr BaseAddress, + [In] IntPtr ZeroBits, + [In] IntPtr CommitSize, + [Optional] ref long SectionOffset, + ref IntPtr ViewSize, + [In] SectionInherit InheritDisposition, + [In] MemoryFlags AllocationType, + [In] MemoryProtection Win32Protect + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtNotifyChangeDirectoryFile( + [In] IntPtr FileHandle, + [In] [Optional] IntPtr Event, + [In] [Optional] IoApcRoutine ApcRoutine, + [In] [Optional] IntPtr ApcContext, + [Out] out IoStatusBlock IoStatusBlock, + [In] IntPtr Buffer, + [In] int Length, + [In] FileNotifyFlags CompletionFilter, + [In] bool WatchTree + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtNotifyChangeDirectoryFile( + [In] IntPtr FileHandle, + [In] [Optional] IntPtr Event, + [In] [Optional] IoApcRoutine ApcRoutine, + [In] [Optional] IntPtr ApcContext, + [In] IntPtr IoStatusBlock, + [In] IntPtr Buffer, + [In] int Length, + [In] FileNotifyFlags CompletionFilter, + [In] bool WatchTree + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenDirectoryObject( + [Out] out IntPtr DirectoryHandle, + [In] DirectoryAccess DesiredAccess, + [In] ref ObjectAttributes ObjectAttributes + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenEnlistment( + [Out] out IntPtr EnlistmentHandle, + [In] EnlistmentAccess DesiredAccess, + [In] IntPtr RmHandle, + [In] ref Guid EnlistmentGuid, + [In] [Optional] ref ObjectAttributes ObjectAttributes + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenEvent( + [Out] out IntPtr EventHandle, + [In] EventAccess DesiredAccess, + [In] ref ObjectAttributes ObjectAttributes + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenEventPair( + [Out] out IntPtr EventPairHandle, + [In] EventPairAccess DesiredAccess, + [In] ref ObjectAttributes ObjectAttributes + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenFile( + [Out] out IntPtr FileHandle, + [In] FileAccess DesiredAccess, + [In] ref ObjectAttributes ObjectAttributes, + [Out] out IoStatusBlock IoStatusBlock, + [In] FileShareMode ShareAccess, + [In] FileCreateOptions OpenOptions + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenIoCompletion( + [Out] out IntPtr IoCompletionHandle, + [In] IoCompletionAccess DesiredAccess, + [In] ref ObjectAttributes ObjectAttributes + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenJobObject( + [Out] out IntPtr JobHandle, + [In] JobObjectAccess DesiredAccess, + [In] ref ObjectAttributes ObjectAttributes + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenKey( + [Out] out IntPtr KeyHandle, + [In] KeyAccess DesiredAccess, + [In] ref ObjectAttributes ObjectAttributes + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenKeyedEvent( + [Out] out IntPtr KeyedEventHandle, + [In] KeyedEventAccess DesiredAccess, + [In] ref ObjectAttributes ObjectAttributes + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenMutant( + [Out] out IntPtr MutantHandle, + [In] MutantAccess DesiredAccess, + [In] ref ObjectAttributes ObjectAttributes + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenProcess( + [Out] out IntPtr ProcessHandle, + [In] ProcessAccess DesiredAccess, + [In] ref ObjectAttributes ObjectAttributes, + [In] [Optional] ref ClientId ClientId + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenProcess( + [Out] out IntPtr ProcessHandle, + [In] ProcessAccess DesiredAccess, + [In] ref ObjectAttributes ObjectAttributes, + [In] [Optional] IntPtr ClientId + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenProcessToken( + [In] IntPtr ProcessHandle, + [In] TokenAccess DesiredAccess, + [Out] out IntPtr TokenHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenProcessTokenEx( + [In] IntPtr ProcessHandle, + [In] TokenAccess DesiredAccess, + [In] int HandleAttributes, + [Out] out IntPtr TokenHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenResourceManager( + [Out] out IntPtr ResourceManagerHandle, + [In] ResourceManagerAccess DesiredAccess, + [In] IntPtr TmHandle, + [In] ref Guid ResourceManagerGuid, + [In] [Optional] ref ObjectAttributes ObjectAttributes + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenSection( + [Out] out IntPtr SectionHandle, + [In] SectionAccess DesiredAccess, + [In] ref ObjectAttributes ObjectAttributes + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenSemaphore( + [Out] out IntPtr SemaphoreHandle, + [In] SemaphoreAccess DesiredAccess, + [In] ref ObjectAttributes ObjectAttributes + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenSymbolicLinkObject( + [Out] out IntPtr LinkHandle, + [In] SymbolicLinkAccess DesiredAccess, + [In] ref ObjectAttributes ObjectAttributes + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenThread( + [Out] out IntPtr ThreadHandle, + [In] ThreadAccess DesiredAccess, + [In] ref ObjectAttributes ObjectAttributes, + [In] [Optional] ref ClientId ClientId + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenThread( + [Out] out IntPtr ThreadHandle, + [In] ThreadAccess DesiredAccess, + [In] ref ObjectAttributes ObjectAttributes, + [In] [Optional] IntPtr ClientId + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenThreadToken( + [In] IntPtr ThreadHandle, + [In] TokenAccess DesiredAccess, + [In] bool OpenAsSelf, + [Out] out IntPtr TokenHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenThreadTokenEx( + [In] IntPtr ThreadHandle, + [In] TokenAccess DesiredAccess, + [In] bool OpenAsSelf, + [In] int HandleAttributes, + [Out] out IntPtr TokenHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenTimer( + [Out] out IntPtr TimerHandle, + [In] TimerAccess DesiredAccess, + [In] ref ObjectAttributes ObjectAttributes + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenTransaction( + [Out] out IntPtr TransactionHandle, + [In] TransactionAccess DesiredAccess, + [In] [Optional] ref ObjectAttributes ObjectAttributes, + [In] ref Guid Uow, + [In] [Optional] IntPtr TmHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenTransactionManager( + [Out] out IntPtr TmHandle, + [In] TmAccess DesiredAccess, + [In] [Optional] ref ObjectAttributes ObjectAttributes, + [In] [Optional] ref UnicodeString LogFileName, + [In] [Optional] ref Guid TmIdentity, + [In] [Optional] int OpenOptions // Must be zero. + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtOpenTransactionManager( + [Out] out IntPtr TmHandle, + [In] TmAccess DesiredAccess, + [In] [Optional] ref ObjectAttributes ObjectAttributes, + [In] [Optional] IntPtr LogFileName, + [In] [Optional] IntPtr TmIdentity, + [In] [Optional] int OpenOptions // Must be zero. + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtPrepareComplete( + [In] IntPtr EnlistmentHandle, + [In] [Optional] ref long TmVirtualClock + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtPrepareEnlistment( + [In] IntPtr EnlistmentHandle, + [In] [Optional] ref long TmVirtualClock + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtPrePrepareComplete( + [In] IntPtr EnlistmentHandle, + [In] [Optional] ref long TmVirtualClock + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtPrePrepareEnlistment( + [In] IntPtr EnlistmentHandle, + [In] [Optional] ref long TmVirtualClock + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtPrivilegeCheck( + [In] IntPtr ClientToken, + [In] IntPtr RequiredPrivileges, // PrivilegeSet* + [MarshalAs(UnmanagedType.U1)] + [Out] out bool Result + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtProtectVirtualMemory( + [In] IntPtr ProcessHandle, + ref IntPtr BaseAddress, + ref IntPtr RegionSize, + [In] MemoryProtection NewProtect, + [Out] out MemoryProtection OldProtect + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtPulseEvent( + [In] IntPtr EventHandle, + [Out] [Optional] out int PreviousState + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryDebugFilterState( + [In] int ComponentId, + [In] int Level + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryDirectoryFile( + [In] IntPtr FileHandle, + [In] [Optional] IntPtr Event, + [In] [Optional] IoApcRoutine ApcRoutine, + [In] [Optional] IntPtr ApcContext, + [Out] out IoStatusBlock IoStatusBlock, + [In] IntPtr FileInformation, + [In] int Length, + [In] FileInformationClass FileInformationClass, + [In] bool ReturnSingleEntry, + [In] [Optional] IntPtr FileName, + [In] bool RestartScan + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryDirectoryObject( + [In] IntPtr DirectoryHandle, + [In] IntPtr Buffer, + [In] int Length, + [In] bool ReturnSingleEntry, + [In] bool RestartScan, + ref int Context, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryEvent( + [In] IntPtr EventHandle, + [In] EventInformationClass EventInformationClass, + [Out] out EventBasicInformation EventInformation, + [In] int EventInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryInformationEnlistment( + [In] IntPtr EnlistmentHandle, + [In] EnlistmentInformationClass EnlistmentInformationClass, + [In] IntPtr EnlistmentInformation, + [In] int EnlistmentInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryInformationEnlistment( + [In] IntPtr EnlistmentHandle, + [In] EnlistmentInformationClass EnlistmentInformationClass, + [Out] out EnlistmentBasicInformation EnlistmentInformation, + [In] int EnlistmentInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryInformationFile( + [In] IntPtr FileHandle, + [Out] out IoStatusBlock IoStatusBlock, + [In] IntPtr FileInformation, + [In] int FileInformationLength, + [In] FileInformationClass FileInformationClass + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryInformationJobObject( + [In] [Optional] IntPtr JobHandle, + [In] JobObjectInformationClass JobObjectInformationClass, + [In] IntPtr JobObjectInformation, + [In] int JobObjectInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryInformationProcess( + [In] IntPtr ProcessHandle, + [In] ProcessInformationClass ProcessInformationClass, + IntPtr ProcessInformation, + [In] int ProcessInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryInformationProcess( + [In] IntPtr ProcessHandle, + [In] ProcessInformationClass ProcessInformationClass, + [Out] out int ProcessInformation, + [In] int ProcessInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryInformationProcess( + [In] IntPtr ProcessHandle, + [In] ProcessInformationClass ProcessInformationClass, + [Out] out IntPtr ProcessInformation, + [In] int ProcessInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryInformationProcess( + [In] IntPtr ProcessHandle, + [In] ProcessInformationClass ProcessInformationClass, + [Out] out IoCounters ProcessInformation, + [In] int ProcessInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryInformationProcess( + [In] IntPtr ProcessHandle, + [In] ProcessInformationClass ProcessInformationClass, + [Out] out PooledUsageAndLimits ProcessInformation, + [In] int ProcessInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryInformationProcess( + [In] IntPtr ProcessHandle, + [In] ProcessInformationClass ProcessInformationClass, + [Out] out ProcessPriorityClassStruct ProcessInformation, + [In] int ProcessInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryInformationProcess( + [In] IntPtr ProcessHandle, + [In] ProcessInformationClass ProcessInformationClass, + [Out] out QuotaLimits ProcessInformation, + [In] int ProcessInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryInformationProcess( + [In] IntPtr ProcessHandle, + [In] ProcessInformationClass ProcessInformationClass, + [Out] out VmCounters ProcessInformation, + [In] int ProcessInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryInformationProcess( + [In] IntPtr ProcessHandle, + [In] ProcessInformationClass ProcessInformationClass, + [Out] out MemExecuteOptions ProcessInformation, + [In] int ProcessInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryInformationProcess( + [In] IntPtr ProcessHandle, + [In] ProcessInformationClass ProcessInformationClass, + [Out] out ProcessBasicInformation ProcessInformation, + [In] int ProcessInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryInformationProcess( + [In] IntPtr ProcessHandle, + [In] ProcessInformationClass ProcessInformationClass, + [Out] out UnicodeString ProcessInformation, + [In] int ProcessInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryInformationResourceManager( + [In] IntPtr ResourceManagerHandle, + [In] ResourceManagerInformationClass ResourceManagerInformationClass, + [In] IntPtr ResourceManagerInformation, + [In] int ResourceManagerInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryInformationThread( + [In] IntPtr ThreadHandle, + [In] ThreadInformationClass ThreadInformationClass, + ref ThreadBasicInformation ThreadInformation, + [In] int ThreadInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryInformationThread( + [In] IntPtr ThreadHandle, + [In] ThreadInformationClass ThreadInformationClass, + [Out] out int ThreadInformation, + [In] int ThreadInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryInformationThread( + [In] IntPtr ThreadHandle, + [In] ThreadInformationClass ThreadInformationClass, + [Out] out IntPtr ThreadInformation, + [In] int ThreadInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryInformationThread( + [In] IntPtr ThreadHandle, + [In] ThreadInformationClass ThreadInformationClass, + IntPtr ThreadInformation, + [In] int ThreadInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public unsafe static extern NtStatus NtQueryInformationThread( + [In] IntPtr ThreadHandle, + [In] ThreadInformationClass ThreadInformationClass, + void* ThreadInformation, + [In] int ThreadInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryInformationToken( + [In] IntPtr TokenHandle, + [In] TokenInformationClass TokenInformationClass, + [In] IntPtr TokenInformation, + [In] int TokenInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryInformationTransaction( + [In] IntPtr TransactionHandle, + [In] TransactionInformationClass TransactionInformationClass, + [In] IntPtr TransactionInformation, + [In] int TransactionInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryInformationTransaction( + [In] IntPtr TransactionHandle, + [In] TransactionInformationClass TransactionInformationClass, + [Out] out TransactionBasicInformation TransactionInformation, + [In] int TransactionInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryInformationTransactionManager( + [In] IntPtr TransactionManagerHandle, + [In] TmInformationClass TransactionManagerInformationClass, + [In] IntPtr TransactionManagerInformation, + [In] int TransactionManagerInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryInformationTransactionManager( + [In] IntPtr TransactionManagerHandle, + [In] TmInformationClass TransactionManagerInformationClass, + [Out] out TmBasicInformation TransactionManagerInformation, + [In] int TransactionManagerInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryInformationTransactionManager( + [In] IntPtr TransactionManagerHandle, + [In] TmInformationClass TransactionManagerInformationClass, + [Out] out TmLogInformation TransactionManagerInformation, + [In] int TransactionManagerInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryInformationTransactionManager( + [In] IntPtr TransactionManagerHandle, + [In] TmInformationClass TransactionManagerInformationClass, + [Out] out TmRecoveryInformation TransactionManagerInformation, + [In] int TransactionManagerInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryIntervalProfile( + [In] KProfileSource Source, + [Out] out int Interval + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryIoCompletion( + [In] IntPtr IoCompletionHandle, + [In] IoCompletionInformationClass IoCompletionInformationClass, + [Out] out IoCompletionBasicInformation IoCompletionInformation, + [In] int IoCompletionInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryMutant( + [In] IntPtr MutantHandle, + [In] MutantInformationClass MutantInformationClass, + [Out] out MutantBasicInformation MutantInformation, + [In] int MutantInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryMutant( + [In] IntPtr MutantHandle, + [In] MutantInformationClass MutantInformationClass, + [Out] out MutantOwnerInformation MutantInformation, + [In] int MutantInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryObject( + [In] IntPtr Handle, + [In] ObjectInformationClass ObjectInformationClass, + [Out] IntPtr ObjectInformation, + [In] int ObjectInformationLength, + [Out] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryPortInformationProcess(); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQuerySection( + [In] IntPtr SectionHandle, + [In] SectionInformationClass SectionInformationClass, + [Out] out SectionBasicInformation SectionInformation, + [In] IntPtr SectionInformationLength, + [Out] [Optional] out IntPtr ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQuerySection( + [In] IntPtr SectionHandle, + [In] SectionInformationClass SectionInformationClass, + [Out] out SectionImageInformation SectionInformation, + [In] IntPtr SectionInformationLength, + [Out] [Optional] out IntPtr ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQuerySecurityObject( + [In] IntPtr Handle, + [In] SecurityInformation SecurityInformation, + [In] IntPtr SecurityDescriptor, + [In] int SecurityDescriptorLength, + [Out] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQuerySemaphore( + [In] IntPtr SemaphoreHandle, + [In] SemaphoreInformationClass SemaphoreInformationClass, + [Out] out SemaphoreBasicInformation SemaphoreInformation, + [In] int SemaphoreInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQuerySymbolicLinkObject( + [In] IntPtr LinkHandle, + ref UnicodeString LinkName, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQuerySystemInformation( + [In] SystemInformationClass SystemInformationClass, + [Out] out SystemBasicInformation SystemInformation, + [In] int SystemInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQuerySystemInformation( + [In] SystemInformationClass SystemInformationClass, + IntPtr SystemInformation, + [In] int SystemInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQuerySystemInformation( + [In] SystemInformationClass SystemInformationClass, + [MarshalAs(UnmanagedType.LPArray)] SystemProcessorPerformanceInformation[] SystemInformation, + [In] int SystemInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQuerySystemInformation( + [In] SystemInformationClass SystemInformationClass, + [Out] out SystemPerformanceInformation SystemInformation, + [In] int SystemInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQuerySystemInformation( + [In] SystemInformationClass SystemInformationClass, + [Out] out SystemTimeOfDayInformation SystemInformation, + [In] int SystemInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQuerySystemInformation( + [In] SystemInformationClass SystemInformationClass, + [Out] out SystemCacheInformation SystemInformation, + [In] int SystemInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryTimer( + [In] IntPtr TimerHandle, + [In] TimerInformationClass TimerInformationClass, + [Out] out TimerBasicInformation TimerInformation, + [In] int TimerInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryVirtualMemory( + [In] IntPtr ProcessHandle, + [In] IntPtr BaseAddress, + [In] MemoryInformationClass MemoryInformationClass, + [In] IntPtr Buffer, + [In] IntPtr MemoryInformationLength, + [Out] [Optional] out IntPtr ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryVirtualMemory( + [In] IntPtr ProcessHandle, + [In] IntPtr BaseAddress, + [In] MemoryInformationClass MemoryInformationClass, + [Out] out MemoryBasicInformation Buffer, + [In] IntPtr MemoryInformationLength, + [Out] [Optional] out IntPtr ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueryVolumeInformationFile( + [In] IntPtr FileHandle, + [Out] out IoStatusBlock IoStatusBlock, + [In] IntPtr FsInformation, + [In] int FsInformationLength, + [In] FsInformationClass FsInformationClass + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtQueueApcThread( + [In] IntPtr ThreadHandle, + [In] IntPtr ApcRoutine, + [In] [Optional] IntPtr ApcArgument1, + [In] [Optional] IntPtr ApcArgument2, + [In] [Optional] IntPtr ApcArgument3 + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtReadFile( + [In] IntPtr FileHandle, + [In] [Optional] IntPtr Event, + [In] [Optional] IoApcRoutine ApcRoutine, + [In] [Optional] IntPtr ApcContext, + [Out] out IoStatusBlock IoStatusBlock, + [In] IntPtr Buffer, + [In] int Length, + [In] [Optional] ref long ByteOffset, + [In] [Optional] ref int Key + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtReadFile( + [In] IntPtr FileHandle, + [In] [Optional] IntPtr Event, + [In] [Optional] IoApcRoutine ApcRoutine, + [In] [Optional] IntPtr ApcContext, + [Out] out IoStatusBlock IoStatusBlock, + [In] IntPtr Buffer, + [In] int Length, + [In] [Optional] IntPtr ByteOffset, + [In] [Optional] IntPtr Key + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtReadFile( + [In] IntPtr FileHandle, + [In] [Optional] IntPtr Event, + [In] [Optional] IoApcRoutine ApcRoutine, + [In] [Optional] IntPtr ApcContext, + [In] IntPtr IoStatusBlock, + [In] IntPtr Buffer, + [In] int Length, + [In] [Optional] IntPtr ByteOffset, + [In] [Optional] IntPtr Key + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtReadOnlyEnlistment( + [In] IntPtr EnlistmentHandle, + [In] [Optional] ref long TmVirtualClock + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtReadRequestData( + [In] IntPtr PortHandle, + [In] IntPtr Message, + [In] int DataEntryIndex, + [In] IntPtr Buffer, + [In] IntPtr BufferSize, + [Out] [Optional] out IntPtr ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtReadVirtualMemory( + [In] IntPtr ProcessHandle, + [In] [Optional] IntPtr BaseAddress, + [In] IntPtr Buffer, + [In] IntPtr BufferSize, + [Out] [Optional] out IntPtr ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtRecoverEnlistment( + [In] IntPtr EnlistmentHandle, + [In] [Optional] IntPtr EnlistmentKey + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtRecoverResourceManager( + [In] IntPtr ResourceManagerHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtRecoverTransactionManager( + [In] IntPtr TransactionManagerHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtRegisterThreadTerminatePort( + [In] IntPtr PortHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtReleaseKeyedEvent( + [In] IntPtr KeyedEventHandle, + [In] IntPtr KeyValue, + [In] bool Alertable, + [In] [Optional] ref long Timeout + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtReleaseMutant( + [In] IntPtr MutantHandle, + [Out] [Optional] out int PreviousCount + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtReleaseSemaphore( + [In] IntPtr SemaphoreHandle, + [In] int ReleaseCount, + [Out] [Optional] out int PreviousCount + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtRemoveIoCompletion( + [In] IntPtr IoCompletionHandle, + [Out] out IntPtr KeyContext, + [Out] out IntPtr ApcContext, + [Out] out IoStatusBlock IoStatusBlock, + [In] [Optional] ref long Timeout + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtRemoveProcessDebug( + [In] IntPtr ProcessHandle, + [In] IntPtr DebugObjectHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtReplyPort( + [In] IntPtr PortHandle, + [In] IntPtr ReplyMessage + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtReplyWaitReceivePort( + [In] IntPtr PortHandle, + [Out] [Optional] out IntPtr PortContext, + [In] [Optional] IntPtr ReplyMessage, + [In] IntPtr ReceiveMessage + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtReplyWaitReceivePortEx( + [In] IntPtr PortHandle, + [Out] [Optional] out IntPtr PortContext, + [In] [Optional] IntPtr ReplyMessage, + [In] IntPtr ReceiveMessage, + [In] [Optional] ref long Timeout + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtReplyWaitReplyPort( + [In] IntPtr PortHandle, + [In] IntPtr ReplyMessage + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtRequestPort( + [In] IntPtr PortHandle, + [In] IntPtr RequestMessage + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtRequestWaitReplyPort( + [In] IntPtr PortHandle, + [In] IntPtr RequestMessage, + [In] IntPtr ReplyMessage + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtResetEvent( + [In] IntPtr EventHandle, + [Out] [Optional] out int PreviousState + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtResumeProcess( + [In] IntPtr ProcessHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtResumeThread( + [In] IntPtr ThreadHandle, + [Out] [Optional] out int PreviousSuspendCount + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtRollbackComplete( + [In] IntPtr EnlistmentHandle, + [In] [Optional] ref long TmVirtualClock + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtRollbackEnlistment( + [In] IntPtr EnlistmentHandle, + [In] [Optional] ref long TmVirtualClock + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtRollbackTransaction( + [In] IntPtr TransactionHandle, + [In] bool Wait + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtRollforwardTransactionManager( + [In] IntPtr TransactionManagerHandle, + [In] [Optional] ref long TmVirtualClock + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSetContextThread( + [In] IntPtr ThreadHandle, + [In] IntPtr ThreadContext + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSetContextThread( + [In] IntPtr ThreadHandle, + [In] ref Context ThreadContext + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSetContextThread( + [In] IntPtr ThreadHandle, + [In] ref ContextAmd64 ThreadContext + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSetDebugFilterState( + [In] int ComponentId, + [In] int Level, + [In] bool State + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSetEvent( + [In] IntPtr EventHandle, + [Out] [Optional] out int PreviousState + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSetEventBoostPriority( + [In] IntPtr EventHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSetHighEventPair( + [In] IntPtr EventPairHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSetHighWaitLowEventPair( + [In] IntPtr EventPairHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSetInformationDebugObject( + [In] IntPtr DebugObjectHandle, + [In] DebugObjectInformationClass DebugObjectInformationClass, + [In] IntPtr DebugObjectInformation, + [In] int DebugObjectInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSetInformationFile( + [In] IntPtr FileHandle, + [Out] out IoStatusBlock IoStatusBlock, + [In] IntPtr FileInformation, + [In] int Length, + [In] FileInformationClass FileInformationClass + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSetInformationJobObject( + [In] IntPtr JobHandle, + [In] JobObjectInformationClass JobObjectInformationClass, + [In] IntPtr JobObjectInformation, + [In] int JobObjectInformationLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSetInformationObject( + [In] IntPtr Handle, + [In] ObjectInformationClass ObjectInformationClass, + [In] IntPtr ObjectInformation, + [In] int ObjectInformationLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSetInformationProcess( + [In] IntPtr ProcessHandle, + [In] ProcessInformationClass ProcessInformationClass, + [In] IntPtr ProcessInformation, + [In] int ProcessInformationLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSetInformationProcess( + [In] IntPtr ProcessHandle, + [In] ProcessInformationClass ProcessInformationClass, + [In] ref int ProcessInformation, + [In] int ProcessInformationLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSetInformationProcess( + [In] IntPtr ProcessHandle, + [In] ProcessInformationClass ProcessInformationClass, + [In] ref ProcessHandleTracingEnable ProcessInformation, + [In] int ProcessInformationLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSetInformationProcess( + [In] IntPtr ProcessHandle, + [In] ProcessInformationClass ProcessInformationClass, + [In] ref ProcessPriorityClassStruct ProcessInformation, + [In] int ProcessInformationLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSetInformationThread( + [In] IntPtr ThreadHandle, + [In] ThreadInformationClass ThreadInformationClass, + [In] IntPtr ThreadInformation, + [In] int ThreadInformationLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSetInformationThread( + [In] IntPtr ThreadHandle, + [In] ThreadInformationClass ThreadInformationClass, + [In] ref int ThreadInformation, + [In] int ThreadInformationLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSetInformationThread( + [In] IntPtr ThreadHandle, + [In] ThreadInformationClass ThreadInformationClass, + [In] ref IntPtr ThreadInformation, + [In] int ThreadInformationLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSetInformationToken( + [In] IntPtr TokenHandle, + [In] TokenInformationClass TokenInformationClass, + [In] IntPtr TokenInformation, + [In] int TokenInformationLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSetIntervalProfile( + [In] int Interval, + [In] KProfileSource Source + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSetIoCompletion( + [In] IntPtr IoCompletionHandle, + [In] IntPtr KeyContext, + [In] [Optional] IntPtr ApcContext, + [In] NtStatus IoStatus, + [In] IntPtr IoStatusInformation + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSetLowEventPair( + [In] IntPtr EventPairHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSetLowWaitHighEventPair( + [In] IntPtr EventPairHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSetSecurityObject( + [In] IntPtr Handle, + [In] SecurityInformation SecurityInformation, + [In] IntPtr SecurityDescriptor + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSetSystemInformation( + [In] SystemInformationClass SystemInformationClass, + [In] ref SystemLoadAndCallImage SystemInformation, + [In] int SystemInformationLength + ); + + /// Period, in milliseconds. + [DllImport("ntdll.dll")] + public static extern NtStatus NtSetTimer( + [In] IntPtr TimerHandle, + [In] ref long DueTime, + [In] [Optional] TimerApcRoutine TimerApcRoutine, + [In] [Optional] IntPtr TimerContext, + [In] bool ResumeTimer, + [In] [Optional] int Period, + [Out] [Optional] out bool PreviousState + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSignalAndWaitForSingleObject( + [In] IntPtr SignalHandle, + [In] IntPtr WaitHandle, + [In] bool Alertable, + [In] [Optional] ref long Timeout + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSinglePhaseReject( + [In] IntPtr EnlistmentHandle, + [In] [Optional] ref long TmVirtualClock + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtStartProfile( + [In] IntPtr ProfileHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtStopProfile( + [In] IntPtr ProfileHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSuspendProcess( + [In] IntPtr ProcessHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtSuspendThread( + [In] IntPtr ThreadHandle, + [Out] [Optional] out int PreviousSuspendCount + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtTerminateJobObject( + [In] IntPtr JobHandle, + [In] NtStatus ExitStatus + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtTerminateProcess( + [In] [Optional] IntPtr ProcessHandle, + [In] NtStatus ExitStatus + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtTerminateThread( + [In] [Optional] IntPtr ThreadHandle, + [In] NtStatus ExitStatus + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtTestAlert(); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtUnloadDriver( + [In] ref UnicodeString DriverServiceName + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtUnlockFile( + [In] IntPtr FileHandle, + [Out] out IoStatusBlock IoStatusBlock, + [In] ref long ByteOffset, + [In] ref long Length, + [In] int Key + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtUnlockVirtualMemory( + [In] IntPtr ProcessHandle, + ref IntPtr BaseAddress, + ref IntPtr RegionSize, + [In] MemoryFlags MapType + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtUnmapViewOfSection( + [In] IntPtr ProcessHandle, + [In] IntPtr BaseAddress + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtWaitForDebugEvent( + [In] IntPtr DebugObjectHandle, + [In] bool Alertable, + [In] [Optional] ref long Timeout, + [In] IntPtr WaitStateChange + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtWaitForKeyedEvent( + [In] IntPtr KeyedEventHandle, + [In] IntPtr KeyValue, + [In] bool Alertable, + [In] [Optional] ref long Timeout + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtWaitForMultipleObjects( + [In] int Count, + [In] IntPtr[] Handles, + [In] WaitType WaitType, + [In] bool Alertable, + [In] [Optional] ref long Timeout + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtWaitForMultipleObjects32( + [In] int Count, + [In] int[] Handles, + [In] WaitType WaitType, + [In] bool Alertable, + [In] [Optional] ref long Timeout + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtWaitForSingleObject( + [In] IntPtr Handle, + [In] bool Alertable, + [In] [Optional] ref long Timeout + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtWaitHighEventPair( + [In] IntPtr EventPairHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtWaitLowEventPair( + [In] IntPtr EventPairHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtWriteFile( + [In] IntPtr FileHandle, + [In] [Optional] IntPtr Event, + [In] [Optional] IoApcRoutine ApcRoutine, + [In] [Optional] IntPtr ApcContext, + [Out] out IoStatusBlock IoStatusBlock, + [In] IntPtr Buffer, + [In] int Length, + [In] [Optional] ref long ByteOffset, + [In] [Optional] ref int Key + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtWriteFile( + [In] IntPtr FileHandle, + [In] [Optional] IntPtr Event, + [In] [Optional] IoApcRoutine ApcRoutine, + [In] [Optional] IntPtr ApcContext, + [Out] out IoStatusBlock IoStatusBlock, + [In] IntPtr Buffer, + [In] int Length, + [In] [Optional] IntPtr ByteOffset, + [In] [Optional] IntPtr Key + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtWriteFile( + [In] IntPtr FileHandle, + [In] [Optional] IntPtr Event, + [In] [Optional] IoApcRoutine ApcRoutine, + [In] [Optional] IntPtr ApcContext, + [In] IntPtr IoStatusBlock, + [In] IntPtr Buffer, + [In] int Length, + [In] [Optional] IntPtr ByteOffset, + [In] [Optional] IntPtr Key + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtWriteRequestData( + [In] IntPtr PortHandle, + [In] IntPtr Message, + [In] int DataEntryIndex, + [In] IntPtr Buffer, + [In] IntPtr BufferSize, + [Out] [Optional] out IntPtr ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtWriteVirtualMemory( + [In] IntPtr ProcessHandle, + [In] [Optional] IntPtr BaseAddress, + [In] IntPtr Buffer, + [In] IntPtr BufferSize, + [Out] [Optional] out IntPtr ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus NtYieldExecution(); + + #endregion + + #region CSR + + [DllImport("ntdll.dll")] + // return: CsrCaptureHeader* + public static extern IntPtr CsrAllocateCaptureBuffer( + [In] int CountMessagePointers, + [In] int Size + ); + + [DllImport("ntdll.dll")] + public static extern int CsrAllocateMessagePointer( + [In] IntPtr CaptureBuffer, // CsrCaptureHeader* + [In] int Length, + [Out] out IntPtr Pointer + ); + + [DllImport("ntdll.dll")] + public static extern void CsrCaptureMessageBuffer( + [In] IntPtr CaptureBuffer, // CsrCaptureHeader* + [In] [Optional] IntPtr Buffer, + [In] int Length, + [Out] out IntPtr CapturedBuffer + ); + + [DllImport("ntdll.dll")] + public static extern void CsrCaptureMessageString( + [In] IntPtr CaptureBuffer, // CsrCaptureHeader* + [MarshalAs(UnmanagedType.LPStr)] + [In] string String, + [In] int Length, + [In] int MaximumLength, + [Out] out AnsiString CapturedString + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus CsrClientCallServer( + [In] IntPtr Message, // CsrApiMsg* + [In] [Optional] IntPtr CaptureBuffer, // CsrCaptureHeader* + [In] int ApiNumber, + [In] int ArgLength + ); + + [DllImport("ntdll.dll")] + public static extern void CsrFreeCaptureBuffer( + [In] IntPtr CaptureBuffer // CsrCaptureHeader* + ); + + #endregion + + #region Debugging + + [DllImport("ntdll.dll")] + public static extern void DbgBreakPoint(); + + [DllImport("ntdll.dll")] + public static extern void DbgBreakPointWithStatus( + [In] int Status + ); + + [DllImport("ntdll.dll")] + public static extern int DbgPrompt( + [MarshalAs(UnmanagedType.LPStr)] + [In] string Prompt, + [In] IntPtr Response, + [In] int MaximumResponseLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus DbgQueryDebugFilterState( + [In] int ComponentId, + [In] int Level + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus DbgSetDebugFilterState( + [In] int ComponentId, + [In] int Level, + [In] bool State + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus DbgUiConnectToDbg(); + + [DllImport("ntdll.dll")] + public static extern NtStatus DbgUiContinue( + [In] ref ClientId ClientId, + [In] NtStatus ContinueStatus + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus DbgUiConvertStateChangeStructure( + [In] IntPtr WaitStateChange, // DbgUiWaitStateChange* + [In] IntPtr Win32DebugEvent // DebugEvent* + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus DbgUiDebugActiveProcess( + [In] IntPtr ProcessHandle + ); + + [DllImport("ntdll.dll")] + public static extern IntPtr DbgUiGetThreadDebugObject(); + + [DllImport("ntdll.dll")] + public static extern NtStatus DbgUiIssueRemoteBreakin( + [In] IntPtr ProcessHandle + ); + + [DllImport("ntdll.dll")] + public static extern void DbgUiRemoteBreakin( + [In] IntPtr Parameter + ); + + [DllImport("ntdll.dll")] + public static extern void DbgUiSetThreadDebugObject( + [In] IntPtr DebugObjectHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus DbgUiStopDebugging( + [In] IntPtr ProcessHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus DbgUiWaitStateChange( + [In] IntPtr WaitStateChange, // DbgUiWaitStateChange* + [In] [Optional] ref long Timeout + ); + + #endregion + + #region Loader + + [DllImport("ntdll.dll", CharSet = CharSet.Unicode)] + public static extern NtStatus LdrGetDllHandle( + [In] [Optional] string DllPath, + [In] [Optional] ref int DllCharacteristics, + [In] ref UnicodeString DllName, + [Out] out IntPtr DllHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus LdrGetProcedureAddress( + [In] IntPtr DllHandle, + [In] [Optional] ref AnsiString ProcedureName, + [In] [Optional] int ProcedureNumber, + [Out] out IntPtr ProcedureAddress + ); + + [DllImport("ntdll.dll", CharSet = CharSet.Unicode)] + public static extern NtStatus LdrLoadDll( + [In] [Optional] string DllPath, + [In] [Optional] ref int DllCharacteristics, + [In] ref UnicodeString DllName, + [Out] out IntPtr DllHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus LdrQueryProcessModuleInformation( + [In] IntPtr ModuleInformation, // RtlProcessModules* + [In] int ModuleInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus LdrUnloadDll( + [In] IntPtr DllHandle + ); + + #endregion + + #region Misc. + + [DllImport("ntdll.dll")] + public static extern IntPtr NtCurrentTeb(); + + #endregion + + #region Run-Time Library + + #region Access Control + + #region Access Control Entries + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlAddAccessAllowedAce( + [In] IntPtr Acl, + [In] int AceRevision, + [In] int AccessMask, + [In] IntPtr Sid // Sid* + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlAddAccessAllowedAceEx( + [In] IntPtr Acl, + [In] int AceRevision, + [In] AceFlags AceFlags, + [In] int AccessMask, + [In] IntPtr Sid // Sid* + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlAddAccessDeniedAce( + [In] IntPtr Acl, + [In] int AceRevision, + [In] int AccessMask, + [In] IntPtr Sid // Sid* + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlAddAccessDeniedAceEx( + [In] IntPtr Acl, + [In] int AceRevision, + [In] AceFlags AceFlags, + [In] int AccessMask, + [In] IntPtr Sid // Sid* + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlAddAce( + [In] IntPtr Acl, + [In] int AceRevision, + [In] int StartingAceIndex, + [In] IntPtr AceList, // Ace** + [In] int AceListLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlAddAuditAccessAce( + [In] IntPtr Acl, + [In] int AceRevision, + [In] int AccessMask, + [In] IntPtr Sid, // Sid* + [In] bool AuditSuccess, + [In] bool AuditFailure + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlAddAuditAccessAceEx( + [In] IntPtr Acl, + [In] int AceRevision, + [In] AceFlags AceFlags, + [In] int AccessMask, + [In] IntPtr Sid, // Sid* + [In] bool AuditSuccess, + [In] bool AuditFailure + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlAddCompoundAce( + [In] IntPtr Acl, + [In] int AceRevision, + [In] AceType AceType, + [In] int AccessMask, + [In] IntPtr ServerSid, // Sid* + [In] IntPtr ClientSid + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlDeleteAce( + [In] IntPtr Acl, + [In] int AceIndex + ); + + [DllImport("ntdll.dll")] + public static extern bool RtlFirstFreeAce( + [In] IntPtr Acl, + [Out] out IntPtr FirstFree + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlGetAce( + [In] IntPtr Acl, + [In] int AceIndex, + [Out] out IntPtr Ace // Ace** + ); + + #endregion + + #region Access Control Lists + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlCreateAcl( + [In] IntPtr Acl, // Acl* + [In] int AclLength, + [In] int AclRevision + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlQueryInformationAcl( + [In] IntPtr Acl, + [In] IntPtr AclInformation, + [In] int AclInformationLength, + [In] AclInformationClass AclInformationClass + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlQueryInformationAcl( + [In] IntPtr Acl, + [Out] out AclRevisionInformation AclInformation, + [In] int AclInformationLength, + [In] AclInformationClass AclInformationClass + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlQueryInformationAcl( + [In] IntPtr Acl, + [Out] out AclSizeInformation AclInformation, + [In] int AclInformationLength, + [In] AclInformationClass AclInformationClass + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlSetInformationAcl( + [In] IntPtr Acl, + [In] IntPtr AclInformation, + [In] int AclInformationLength, + [In] AclInformationClass AclInformationClass + ); + + [DllImport("ntdll.dll")] + public static extern bool RtlValidAcl( + [In] IntPtr Acl + ); + + #endregion + + #region Access Masks + + [DllImport("ntdll.dll")] + public static extern bool RtlAreAllAccessesGranted( + [In] int GrantedAccess, + [In] int DesiredAccess + ); + + [DllImport("ntdll.dll")] + public static extern bool RtlAreAnyAccessesGranted( + [In] int GrantedAccess, + [In] int DesiredAccess + ); + + [DllImport("ntdll.dll")] + public static extern void RtlMapGenericMask( + ref int AccessMask, + [In] ref GenericMapping GenericMapping + ); + + #endregion + + #region Security Descriptors + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlAbsoluteToSelfRelativeSD( + [In] IntPtr AbsoluteSecurityDescriptor, + [In] IntPtr SelfRelativeSecurityDescriptor, + ref int BufferLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlCreateSecurityDescriptor( + [In] IntPtr SecurityDescriptor, // SecurityDescriptor* + [In] int Revision + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlCreateSecurityDescriptorRelative( + [In] IntPtr SecurityDescriptor, // SecurityDescriptorRelative* + [In] int Revision + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlGetControlSecurityDescriptor( + [In] IntPtr SecurityDescriptor, + [Out] out SecurityDescriptorControlFlags Control, + [Out] out int Revision + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlGetDaclSecurityDescriptor( + [In] IntPtr SecurityDescriptor, + [MarshalAs(UnmanagedType.U1)] + [Out] out bool DaclPresent, + [Out] out IntPtr Dacl, // Acl** + [MarshalAs(UnmanagedType.U1)] + [Out] out bool DaclDefaulted + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlGetGroupSecurityDescriptor( + [In] IntPtr SecurityDescriptor, + [Out] out IntPtr Group, // Sid** + [MarshalAs(UnmanagedType.U1)] + [Out] out bool GroupDefaulted + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlGetOwnerSecurityDescriptor( + [In] IntPtr SecurityDescriptor, + [Out] out IntPtr Owner, // Sid** + [MarshalAs(UnmanagedType.U1)] + [Out] out bool OwnerDefaulted + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlGetSaclSecurityDescriptor( + [In] IntPtr SecurityDescriptor, + [MarshalAs(UnmanagedType.U1)] + [Out] out bool SaclPresent, + [Out] out IntPtr Sacl, // Acl** + [MarshalAs(UnmanagedType.U1)] + [Out] out bool SaclDefaulted + ); + + [DllImport("ntdll.dll")] + public static extern bool RtlGetSecurityDescriptorRMControl( + [In] IntPtr SecurityDescriptor, + [Out] out byte RMControl + ); + + [DllImport("ntdll.dll")] + public static extern int RtlLengthSecurityDescriptor( + [In] IntPtr SecurityDescriptor + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlMakeSelfRelativeSD( + [In] IntPtr AbsoluteSecurityDescriptor, + [In] IntPtr SelfRelativeSecurityDescriptor, + ref int BufferLength + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlSelfRelativeToAbsoluteSD( + [In] IntPtr SelfRelativeSecurityDescriptor, + [In] IntPtr AbsoluteSecurityDescriptor, + ref int AbsoluteSecurityDescriptorSize, + [In] IntPtr Dacl, // Acl* + ref int DaclSize, + [In] IntPtr Sacl, // Acl* + ref int SaclSize, + [In] IntPtr Owner, // Sid* + ref int OwnerSize, + [In] IntPtr PrimaryGroup, // Sid* + ref int PrimaryGroupSize + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlSelfRelativeToAbsoluteSD2( + [In] IntPtr SelfRelativeSecurityDescriptor, + ref int BufferSize + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlSetAttributesSecurityDescriptor( + [In] IntPtr SecurityDescriptor, + [In] SecurityDescriptorControlFlags Control, + ref int Revision + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlSetControlSecurityDescriptor( + [In] IntPtr SecurityDescriptor, + [In] SecurityDescriptorControlFlags ControlBitsOfInterest, + [In] SecurityDescriptorControlFlags ControlBitsToSet + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlSetDaclSecurityDescriptor( + [In] IntPtr SecurityDescriptor, + [In] bool DaclPresent, + [In] IntPtr Dacl, // Acl* + [In] bool DaclDefaulted + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlSetGroupSecurityDescriptor( + [In] IntPtr SecurityDescriptor, + [In] IntPtr Group, // Sid* + [In] bool GroupDefaulted + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlSetOwnerSecurityDescriptor( + [In] IntPtr SecurityDescriptor, + [In] IntPtr Owner, // Sid* + [In] bool OwnerDefaulted + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlSetSaclSecurityDescriptor( + [In] IntPtr SecurityDescriptor, + [In] bool SaclPresent, + [In] IntPtr Sacl, // Acl* + [In] bool SaclDefaulted + ); + + [DllImport("ntdll.dll")] + public static extern void RtlSetSecurityDescriptorRMControl( + [In] IntPtr SecurityDescriptor, + [In] [Optional] ref byte RMControl + ); + + [DllImport("ntdll.dll")] + public static extern bool RtlValidRelativeSecurityDescriptor( + [In] IntPtr SecurityDescriptorInput, + [In] int SecurityDescriptorLength, + [In] SecurityInformation RequiredInformation + ); + + [DllImport("ntdll.dll")] + public static extern bool RtlValidSecurityDescriptor( + [In] IntPtr SecurityDescriptor + ); + + #endregion + + #region Security Objects + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlCopySecurityDescriptor( + [In] IntPtr InputSecurityDescriptor, + [Out] out IntPtr OutputSecurityDescriptor + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlCreateUserSecurityObject( + [In] RtlAceData[] AceData, + [In] int AceCount, + [In] IntPtr OwnerSid, // Sid* + [In] IntPtr GroupSid, // Sid* + [In] bool IsDirectoryObject, + [In] ref GenericMapping GenericMapping, + [Out] out IntPtr NewDescriptor // SecurityDescriptor** + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlDeleteSecurityObject( + ref IntPtr ObjectDescriptor // SecurityDescriptor** + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlNewSecurityObject( + [In] IntPtr ParentDescriptor, + [In] IntPtr CreatorDescriptor, + [Out] out IntPtr NewDescriptor, // SecurityDescriptor** + [In] bool IsDirectoryObject, + [In] IntPtr Token, + [In] ref GenericMapping GenericMapping + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlSetSecurityObject( + [In] SecurityInformation SecurityInformation, + [In] IntPtr ModificationDescriptor, + [Out] out IntPtr ObjectsSecurityDescriptor, // SecurityDescriptor** + [In] ref GenericMapping GenericMapping, + [In] IntPtr Token + ); + + #endregion + + #endregion + + #region Bitmaps + + [DllImport("ntdll.dll")] + public static extern bool RtlAreBitsClear( + [In] ref RtlBitmap BitMapHeader, + [In] int StartingIndex, + [In] int Length + ); + + [DllImport("ntdll.dll")] + public static extern bool RtlAreBitsSet( + [In] ref RtlBitmap BitMapHeader, + [In] int StartingIndex, + [In] int Length + ); + + public static int RtlCheckBit( + ref RtlBitmap BitMapHeader, + int BitPosition + ) + { + unsafe + { + int* buffer = (int*)BitMapHeader.Buffer; + + return (buffer[BitPosition / 32] >> (BitPosition % 32)) & 0x1; + } + } + + [DllImport("ntdll.dll")] + public static extern void RtlClearAllBits( + [In] ref RtlBitmap BitMapHeader + ); + + [DllImport("ntdll.dll")] + public static extern void RtlClearBit( + [In] ref RtlBitmap BitMapHeader, + [In] int BitNumber + ); + + [DllImport("ntdll.dll")] + public static extern void RtlClearBits( + [In] ref RtlBitmap BitMapHeader, + [In] int StartingIndex, + [In] int NumberToClear + ); + + [DllImport("ntdll.dll")] + public static extern int RtlFindClearBits( + [In] ref RtlBitmap BitMapHeader, + [In] int NumberToFind, + [In] int HintIndex + ); + + [DllImport("ntdll.dll")] + public static extern int RtlFindClearBitsAndSet( + [In] ref RtlBitmap BitMapHeader, + [In] int NumberToFind, + [In] int HintIndex + ); + + [DllImport("ntdll.dll")] + public static extern int RtlFindClearRuns( + [In] ref RtlBitmap BitMapHeader, + RtlBitmapRun[] RunArray, + [In] int SizeOfRunArray, + [In] bool LocateLongestRuns + ); + + [DllImport("ntdll.dll")] + public static extern int RtlFindLastBackwardRunClear( + [In] ref RtlBitmap BitMapHeader, + [In] int FromIndex, + [Out] out int StartingRunIndex + ); + + [DllImport("ntdll.dll")] + public static extern int RtlFindNextForwardRunClear( + [In] ref RtlBitmap BitMapHeader, + [In] int FromIndex, + [Out] out int StartingRunIndex + ); + + [DllImport("ntdll.dll")] + public static extern int RtlFindSetBits( + [In] ref RtlBitmap BitMapHeader, + [In] int NumberToFind, + [In] int HintIndex + ); + + [DllImport("ntdll.dll")] + public static extern int RtlFindSetBitsAndClear( + [In] ref RtlBitmap BitMapHeader, + [In] int NumberToFind, + [In] int HintIndex + ); + + [DllImport("ntdll.dll")] + public static extern void RtlInitializeBitMap( + [Out] out RtlBitmap BitMapHeader, + [In] IntPtr BitMapBuffer, // int* + [In] int SizeOfBitMap + ); + + [DllImport("ntdll.dll")] + public static extern int RtlFindFirstRunClear( + [In] ref RtlBitmap BitMapHeader, + [Out] out int StartingIndex + ); + + [DllImport("ntdll.dll")] + public static extern int RtlFindLongestRunClear( + [In] ref RtlBitmap BitMapHeader, + [Out] out int StartingIndex + ); + + [DllImport("ntdll.dll")] + public static extern int RtlNumberOfClearBits( + [In] ref RtlBitmap BitMapHeader + ); + + [DllImport("ntdll.dll")] + public static extern int RtlNumberOfSetBits( + [In] ref RtlBitmap BitMapHeader + ); + + [DllImport("ntdll.dll")] + public static extern void RtlSetBit( + [In] ref RtlBitmap BitMapHeader, + [In] int BitNumber + ); + + [DllImport("ntdll.dll")] + public static extern void RtlSetBits( + [In] ref RtlBitmap BitMapHeader, + [In] int StartingIndex, + [In] int NumberToSet + ); + + [DllImport("ntdll.dll")] + public static extern void RtlSetAllBits( + [In] ref RtlBitmap BitMapHeader + ); + + [DllImport("ntdll.dll")] + public static extern bool RtlTestBit( + [In] ref RtlBitmap BitMapHeader, + [In] int BitNumber + ); + + #endregion + + #region Bits + + [DllImport("ntdll.dll")] + public static extern sbyte RtlFindLeastSignificantBit( + [In] long Set + ); + + [DllImport("ntdll.dll")] + public static extern sbyte RtlFindMostSignificantBit( + [In] long Set + ); + + #endregion + + #region Debugging + + [DllImport("ntdll.dll")] + // return: RtlDebugInformation* + public static extern IntPtr RtlCreateQueryDebugBuffer( + [In] [Optional] int MaximumCommit, + [In] bool UseEventPair + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlDestroyQueryDebugBuffer( + [In] IntPtr Buffer // RtlDebugInformation* + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlQueryProcessBackTraceInformation( + [In] IntPtr Buffer // RtlDebugInformation* + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlQueryProcessDebugInformation( + [In] IntPtr UniqueProcessId, + [In] RtlQueryProcessDebugFlags Flags, + [In] IntPtr Buffer // RtlDebugInformation* + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlQueryProcessHeapInformation( + [In] IntPtr Buffer // RtlDebugInformation* + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlQueryProcessLockInformation( + [In] IntPtr Buffer // RtlDebugInformation* + ); + + // Not exported. + //[DllImport("ntdll.dll")] + //public static extern NtStatus RtlQueryProcessModuleInformation( + // [In] [Optional] IntPtr ProcessHandle, + // [In] RtlQueryProcessDebugFlags Flags, + // [In] IntPtr Buffer // RtlDebugInformation* + // ); + + #endregion + + #region Handle Tables + + [DllImport("ntdll.dll")] + public static extern IntPtr RtlAllocateHandle( + [In] ref RtlHandleTable HandleTable, + [Out] [Optional] out int HandleIndex + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlDestroyHandleTable( + ref RtlHandleTable HandleTable + ); + + [DllImport("ntdll.dll")] + [return: MarshalAs(UnmanagedType.I1)] + public static extern bool RtlFreeHandle( + [In] ref RtlHandleTable HandleTable, + [In] IntPtr Handle + ); + + [DllImport("ntdll.dll")] + public static extern void RtlInitializeHandleTable( + [In] int MaximumNumberOfHandles, + [In] int SizeOfHandleTableEntry, + [Out] out RtlHandleTable HandleTable + ); + + [DllImport("ntdll.dll")] + [return: MarshalAs(UnmanagedType.I1)] + public static extern bool RtlIsValidHandle( + [In] ref RtlHandleTable HandleTable, + [In] IntPtr Handle + ); + + [DllImport("ntdll.dll")] + [return: MarshalAs(UnmanagedType.I1)] + public static extern bool RtlIsValidIndexHandle( + [In] ref RtlHandleTable HandleTable, + [In] int HandleIndex, + [Out] out IntPtr Handle + ); + + #endregion + + #region Heaps + + [DllImport("ntdll.dll")] + public static extern IntPtr RtlAllocateHeap( + [In] IntPtr HeapHandle, + [In] HeapFlags Flags, + [In] IntPtr Size + ); + + [DllImport("ntdll.dll")] + public static extern IntPtr RtlCompactHeap( + [In] IntPtr HeapHandle, + [In] HeapFlags Flags + ); + + [DllImport("ntdll.dll")] + public static extern IntPtr RtlCreateHeap( + [In] HeapFlags Flags, + [In] [Optional] IntPtr HeapBase, + [In] [Optional] IntPtr ReserveSize, + [In] [Optional] IntPtr CommitSize, + [In] [Optional] IntPtr Lock, + [In] [Optional] IntPtr Parameters + ); + + [DllImport("ntdll.dll")] + public static extern IntPtr RtlDestroyHeap( + [In] IntPtr HeapHandle + ); + + [DllImport("ntdll.dll")] + [return: MarshalAs(UnmanagedType.U1)] + public static extern bool RtlFreeHeap( + [In] IntPtr HeapHandle, + [In] HeapFlags Flags, + [In] IntPtr BaseAddress + ); + + [DllImport("ntdll.dll")] + public static extern int RtlGetProcessHeaps( + [In] int NumberOfHeaps, + IntPtr[] ProcessHeaps + ); + + [DllImport("ntdll.dll")] + [return: MarshalAs(UnmanagedType.U1)] + public static extern bool RtlLockHeap( + [In] IntPtr HeapHandle + ); + + [DllImport("ntdll.dll")] + public static extern void RtlProtectHeap( + [In] IntPtr HeapHandle, + [In] bool MakeReadOnly + ); + + [DllImport("ntdll.dll")] + public static extern IntPtr RtlReAllocateHeap( + [In] IntPtr HeapHandle, + [In] HeapFlags Flags, + [In] IntPtr BaseAddress, + [In] IntPtr Size + ); + + [DllImport("ntdll.dll")] + public static extern IntPtr RtlSizeHeap( + [In] IntPtr HeapHandle, + [In] HeapFlags Flags, + [In] IntPtr BaseAddress + ); + + [DllImport("ntdll.dll")] + [return: MarshalAs(UnmanagedType.U1)] + public static extern bool RtlUnlockHeap( + [In] IntPtr HeapHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlZeroHeap( + [In] IntPtr HeapHandle, + [In] HeapFlags Flags + ); + + #endregion + + #region Memory + + [DllImport("ntdll.dll")] + public static extern IntPtr RtlCompareMemory( + [In] IntPtr Source1, + [In] IntPtr Source2, + [In] IntPtr Length + ); + + [DllImport("ntdll.dll")] + public static extern void RtlFillMemory( + [In] IntPtr Destination, + [In] IntPtr Length, + [In] byte Fill + ); + + [DllImport("ntdll.dll")] + public static extern void RtlMoveMemory( + [In] IntPtr Destination, + [In] IntPtr Source, + [In] IntPtr Length + ); + + [DllImport("ntdll.dll")] + public static extern void RtlZeroMemory( + [In] IntPtr Destination, + [In] IntPtr Length + ); + + #endregion + + #region Message Resources + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlFindMessage( + [In] IntPtr DllHandle, + [In] int MessageTableId, + [In] int MessageLanguageId, + [In] int MessageId, + [Out] out IntPtr MessageEntry // MessageResourceEntry* + ); + + #endregion + + #region Privileges + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlAcquirePrivilege( + [In] uint[] Privilege, + [In] int NumPriv, + [In] RtlAcquirePrivilegeFlags Flags, + [Out] out IntPtr ReturnedState + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlAdjustPrivilege( + [In] uint Privilege, + [In] bool Enable, + [In] bool Client, + [MarshalAs(UnmanagedType.I1)] + [Out] bool WasEnabled + ); + + [DllImport("ntdll.dll")] + public static extern void RtlReleasePrivilege( + [In] IntPtr StatePointer + ); + + #endregion + + #region Processes and Threads + + [DllImport("ntdll.dll")] + public static extern void RtlAcquirePebLock(); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlAllocateFromPeb( + [In] int Size, + [Out] out IntPtr Block + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlCreateEnvironment( + [In] bool CloneCurrentEnvironment, + [Out] out IntPtr Environment + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlCreateProcessParameters( + [Out] out IntPtr ProcessParameters, + [In] ref UnicodeString ImagePathName, + [In] ref UnicodeString DllPath, + [In] ref UnicodeString CurrentDirectory, + [In] ref UnicodeString CommandLine, + [In] IntPtr Environment, + [In] ref UnicodeString WindowTitle, + [In] ref UnicodeString DesktopInfo, + [In] ref UnicodeString ShellInfo, + [In] ref UnicodeString RuntimeData + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlCreateUserProcess( + [In] ref UnicodeString NtImagePathName, + [In] ObjectFlags Attributes, + [In] ref RtlUserProcessParameters ProcessParameters, + [In] IntPtr ProcessSecurityDescriptor, + [In] IntPtr ThreadSecurityDescriptor, + [In] IntPtr ParentProcess, + [In] bool InheritHandles, + [In] IntPtr DebugPort, + [In] IntPtr ExceptionPort, + [Out] out RtlUserProcessInformation ProcessInformation + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlCreateUserThread( + [In] IntPtr Process, + [In] IntPtr ThreadSecurityDescriptor, + [In] bool CreateSuspended, + [In] int StackZeroBits, + [In] [Optional] IntPtr MaximumStackSize, + [In] [Optional] IntPtr InitialStackSize, + [In] IntPtr StartAddress, + [In] IntPtr Parameter, + [Out] out IntPtr Thread, + [Out] out ClientId ClientId + ); + + [DllImport("ntdll.dll")] + public static extern IntPtr RtlDeNormalizeProcessParameters( + [In] IntPtr ProcessParameters + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlDestroyEnvironment( + [In] IntPtr Environment + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlDestroyProcessParameters( + [In] IntPtr ProcessParameters + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlExitUserProcess( + [In] NtStatus ExitStatus + ); + + [DllImport("ntdll.dll")] + public static extern void RtlExitUserThread( + [In] NtStatus ExitStatus + ); + + [DllImport("ntdll.dll")] + public static extern void RtlFreeUserThreadStack( + [In] IntPtr Process, + [In] IntPtr Thread + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlFreeToPeb( + [In] IntPtr Block, + [In] int Size + ); + + [DllImport("ntdll.dll")] + public static extern void RtlInitializeContext( + [In] IntPtr Process, + ref Context Context, + [In] IntPtr Parameter, + [In] IntPtr InitialPc, + [In] IntPtr InitialSp + ); + + [DllImport("ntdll.dll")] + public static extern IntPtr RtlNormalizeProcessParameters( + [In] IntPtr ProcessParameters + ); + + [DllImport("ntdll.dll")] + public static extern Win32Error RtlNtStatusToDosError( + [In] NtStatus Status + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlQueryEnvironmentVariable_U( + [In] [Optional] IntPtr Environment, + [In] ref UnicodeString Name, + ref UnicodeString Value + ); + + [DllImport("ntdll.dll")] + public static extern void RtlReleasePebLock(); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlRemoteCall( + [In] IntPtr Process, + [In] IntPtr Thread, + [In] IntPtr CallSite, + [In] int ArgumentCount, + [In] IntPtr[] Arguments, + [In] bool PassContext, + [In] bool AlreadySuspended + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlSetCurrentEnvironment( + [In] IntPtr Environment, + [Out] out IntPtr PreviousEnvironment + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlSetEnvironmentVariable( + ref IntPtr Environment, + [In] ref UnicodeString Name, + [In] [Optional] ref UnicodeString Value + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlSetEnvironmentVariable( + [In] [Optional] IntPtr Environment, + [In] ref UnicodeString Name, + [In] [Optional] ref UnicodeString Value + ); + + #endregion + + #region Security IDs + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlAllocateAndInitializeSid( + [In] ref SidIdentifierAuthority IdentifierAuthority, + [In] int SubAuthorityCount, + [In] int SubAuthority0, + [In] int SubAuthority1, + [In] int SubAuthority2, + [In] int SubAuthority3, + [In] int SubAuthority4, + [In] int SubAuthority5, + [In] int SubAuthority6, + [In] int SubAuthority7, + [Out] out IntPtr Sid + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlConvertSidToUnicodeString( + ref UnicodeString UnicodeString, + [In] IntPtr Sid, + [In] bool AllocateDestinationString + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlCopySid( + [In] int DestinationSidLength, + [In] IntPtr DestinationSid, + [In] IntPtr SourceSid + ); + + [DllImport("ntdll.dll")] + [return: MarshalAs(UnmanagedType.I1)] + public static extern bool RtlEqualSid( + [In] IntPtr Sid1, + [In] IntPtr Sid2 + ); + + [DllImport("ntdll.dll")] + [return: MarshalAs(UnmanagedType.I1)] + public static extern bool RtlEqualPrefixSid( + [In] IntPtr Sid1, + [In] IntPtr Sid2 + ); + + [DllImport("ntdll.dll")] + public static extern IntPtr RtlFreeSid( + [In] IntPtr Sid + ); + + [DllImport("ntdll.dll")] + public unsafe static extern SidIdentifierAuthority* RtlIdentifierAuthoritySid( + [In] IntPtr Sid + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlInitializeSid( + [In] IntPtr Sid, + [In] ref SidIdentifierAuthority IdentifierAuthority, + [In] int SubAuthorityCount + ); + + [DllImport("ntdll.dll")] + public static extern int RtlLengthRequiredSid( + [In] int SubAuthorityCount + ); + + [DllImport("ntdll.dll")] + public static extern int RtlLengthSid( + [In] IntPtr Sid + ); + + [DllImport("ntdll.dll")] + public unsafe static extern int* RtlSubAuthoritySid( + [In] IntPtr Sid, + [In] int SubAuthority + ); + + [DllImport("ntdll.dll")] + public unsafe static extern byte* RtlSubAuthorityCountSid( + [In] IntPtr Sid + ); + + [DllImport("ntdll.dll")] + [return: MarshalAs(UnmanagedType.I1)] + public static extern bool RtlValidSid( + [In] IntPtr Sid + ); + + #endregion + + #region Strings + + #region ANSI + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlAnsiStringToUnicodeString( + ref UnicodeString DestinationString, + [In] ref AnsiString SourceString, + [In] bool AllocateDestinationString + ); + + [DllImport("ntdll.dll")] + public static extern void RtlFreeAnsiString( + [In] ref AnsiString AnsiString + ); + + #endregion + + #region Unicode + + [DllImport("ntdll.dll")] + public static extern int RtlCompareUnicodeString( + [In] ref UnicodeString String1, + [In] ref UnicodeString String2, + [In] bool CaseInSensitive + ); + + [DllImport("ntdll.dll")] + [return: MarshalAs(UnmanagedType.I1)] + public static extern bool RtlCreateUnicodeString( + [Out] out UnicodeString DestinationString, + [MarshalAs(UnmanagedType.LPWStr)] + [In] string SourceString + ); + + [DllImport("ntdll.dll")] + [return: MarshalAs(UnmanagedType.I1)] + public static extern bool RtlCreateUnicodeStringFromAsciiz( + [Out] out UnicodeString DestinationString, + [MarshalAs(UnmanagedType.LPStr)] + [In] string SourceString + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlDuplicateUnicodeString( + [In] RtlDuplicateUnicodeStringFlags Flags, + [In] ref UnicodeString StringIn, + [Out] out UnicodeString StringOut + ); + + [DllImport("ntdll.dll")] + [return: MarshalAs(UnmanagedType.I1)] + public static extern bool RtlEqualUnicodeString( + [In] ref UnicodeString String1, + [In] ref UnicodeString String2, + [In] bool CaseInSensitive + ); + + [DllImport("ntdll.dll")] + public static extern void RtlFreeUnicodeString( + [In] ref UnicodeString UnicodeString + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlHashUnicodeString( + [In] ref UnicodeString String, + [In] bool CaseInSensitive, + [In] HashStringAlgorithm HashAlgorithm, + [Out] out int HashValue + ); + + [DllImport("ntdll.dll")] + [return: MarshalAs(UnmanagedType.I1)] + public static extern bool RtlPrefixUnicodeString( + [In] ref UnicodeString String1, + [In] ref UnicodeString String2, + [In] bool CaseInSensitive + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlUnicodeStringToAnsiString( + ref AnsiString DestinationString, + [In] ref UnicodeString SourceString, + [In] bool AllocateDestinationString + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlUpcaseUnicodeStringToAnsiString( + ref AnsiString DestinationString, + [In] ref UnicodeString SourceString, + [In] bool AllocateDestinationString + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlValidateUnicodeString( + [In] int Flags, + [In] ref UnicodeString String + ); + + #endregion + + #endregion + + #region Threading + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlCreateTimer( + [In] IntPtr TimerQueueHandle, + [Out] out IntPtr Handle, + [In] WaitOrTimerCallbackDelegate Function, + [In] IntPtr Context, + [In] int DueTime, + [In] int Period, + [In] WtFlags Flags + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlCreateTimerQueue( + [Out] out IntPtr TimerQueueHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlDeleteTimer( + [In] IntPtr TimerQueueHandle, + [In] IntPtr TimerToCancel, + [In] IntPtr Event + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlDeleteTimerQueue( + [In] IntPtr TimerQueueHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlDeleteTimerQueueEx( + [In] IntPtr TimerQueueHandle, + [In] IntPtr Event + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlDeregisterWait( + [In] IntPtr WaitHandle + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlDeregisterWaitEx( + [In] IntPtr WaitHandle, + [In] IntPtr Event + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlQueueWorkItem( + [MarshalAs(UnmanagedType.FunctionPtr)] + [In] WorkerCallbackDelegate Function, + [In] IntPtr Context, + [In] WtFlags Flags + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlRegisterWait( + [Out] out IntPtr WaitHandle, + [In] IntPtr Handle, + [MarshalAs(UnmanagedType.FunctionPtr)] + [In] WaitOrTimerCallbackDelegate Function, + [In] IntPtr Context, + [In] int Milliseconds, + [In] WtFlags Flags + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlSetIoCompletionCallback( + [In] IntPtr FileHandle, + [In] ApcCallbackDelegate CompletionProc, + [In] WtFlags Flags + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlUpdateTimer( + [In] IntPtr TimerQueueHandle, + [In] IntPtr TimerHandle, + [In] int DueTime, + [In] int Period + ); + + #endregion + + #region WOW64 + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlWow64GetThreadContext( + [In] IntPtr ThreadHandle, + ref Context ThreadContext + ); + + [DllImport("ntdll.dll")] + public static extern NtStatus RtlWow64SetThreadContext( + [In] IntPtr ThreadHandle, + [In] ref Context ThreadContext + ); + + #endregion + + #endregion + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Api/NativeStructs.cs b/branches/ph-plugins/ProcessHacker.Native/Api/NativeStructs.cs new file mode 100644 index 000000000..0765aaa1c --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Api/NativeStructs.cs @@ -0,0 +1,3206 @@ +/* + * Process Hacker - + * native API structs + * + * Copyright (C) 2009 Flavio Erlich + * Copyright (C) 2008-2009 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 file contains structure declarations for the Native API. + * Structures shared between the Native API and Win32 are placed + * in this file. + */ + +using System; +using System.Runtime.InteropServices; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; +using ProcessHacker.Native.Security.AccessControl; + +namespace ProcessHacker.Native.Api +{ + [StructLayout(LayoutKind.Sequential)] + public struct AccessAllowedAceStruct + { + public AceHeader Header; + public int Mask; + public int SidStart; + } + + [StructLayout(LayoutKind.Sequential)] + public struct AccessAllowedObjectAceStruct + { + public AceHeader Header; + public int Mask; + public ObjectAceFlags Flags; + public Guid ObjectType; + public Guid InheritedObjectType; + public int SidStart; + } + + [StructLayout(LayoutKind.Sequential)] + public struct AccessDeniedAceStruct + { + public AceHeader Header; + public int Mask; + public int SidStart; + } + + [StructLayout(LayoutKind.Sequential)] + public struct AccessDeniedObjectAceStruct + { + public AceHeader Header; + public int Mask; + public ObjectAceFlags Flags; + public Guid ObjectType; + public Guid InheritedObjectType; + public int SidStart; + } + + [StructLayout(LayoutKind.Sequential)] + public struct AceData + { + public AceType AceType; + public byte InheritFlags; + public AceFlags AceFlags; + public int Mask; + public IntPtr Sid; // Sid** + } + + [StructLayout(LayoutKind.Sequential)] + public struct AceHeader + { + public AceType AceType; + public AceFlags AceFlags; + public ushort AceSize; + } + + [StructLayout(LayoutKind.Sequential)] + public struct AclRevisionInformation + { + public int AclRevision; + } + + [StructLayout(LayoutKind.Sequential)] + public struct AclSizeInformation + { + public int AceCount; + public int AclBytesInUse; + public int AclBytesFree; + } + + [StructLayout(LayoutKind.Sequential)] + public struct AclStruct + { + public byte AclRevision; + public byte Sbz1; + public ushort AclSize; + public ushort AceCount; + public ushort Sbz2; + } + + [StructLayout(LayoutKind.Sequential)] + public struct AnsiString : IDisposable + { + public AnsiString(string str) + { + UnicodeString unicodeStr; + + unicodeStr = new UnicodeString(str); + this = unicodeStr.ToAnsiString(); + unicodeStr.Dispose(); + } + + public ushort Length; + public ushort MaximumLength; + public IntPtr Buffer; + + public void Dispose() + { + if (this.Buffer == IntPtr.Zero) + return; + + Win32.RtlFreeAnsiString(ref this); + this.Buffer = IntPtr.Zero; + } + + public UnicodeString ToUnicodeString() + { + NtStatus status; + UnicodeString unicodeStr = new UnicodeString(); + + if ((status = Win32.RtlAnsiStringToUnicodeString(ref unicodeStr, ref this, true)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return unicodeStr; + } + } + + [StructLayout(LayoutKind.Sequential)] + public struct BaseCreateProcessMsg + { + public IntPtr ProcessHandle; + public IntPtr ThreadHandle; + public ClientId ClientId; + public ClientId DebuggerClientId; + public ProcessCreationFlags CreationFlags; + public int IsVdm; + public IntPtr VdmHandle; + } + + [StructLayout(LayoutKind.Sequential)] + public struct BaseCreateThreadMsg + { + public IntPtr ThreadHandle; + public ClientId ClientId; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ClientId + { + public ClientId(int processId, int threadId) + { + this.UniqueProcess = new IntPtr(processId); + this.UniqueThread = new IntPtr(threadId); + } + + public IntPtr UniqueProcess; + public IntPtr UniqueThread; + + public int ProcessId { get { return this.UniqueProcess.ToInt32(); } } + public int ThreadId { get { return this.UniqueThread.ToInt32(); } } + } + + [StructLayout(LayoutKind.Sequential)] + public struct CompoundAccessAllowedAceStruct + { + public AceHeader Header; + public int Mask; + public CompoundAceType CompoundAceType; + public ushort Reserved; + public int SidStart; + } + + /// + /// x86 context + /// + [StructLayout(LayoutKind.Sequential)] + public struct Context + { + public ContextFlags ContextFlags; + + public int Dr0; + public int Dr1; + public int Dr2; + public int Dr3; + public int Dr6; + public int Dr7; + + [MarshalAs(UnmanagedType.Struct)] + public FloatingSaveArea FloatSave; + + public int SegGs; + public int SegFs; + public int SegEs; + public int SegDs; + + public int Edi; + public int Esi; + public int Ebx; + public int Edx; + public int Ecx; + public int Eax; + + public int Ebp; + public int Eip; + public int SegCs; + public int EFlags; + public int Esp; + public int SegSs; + + public unsafe fixed byte ExtendedRegisters[Win32.MaximumSupportedExtension]; + } + + /// + /// AMD64 context. + /// + [StructLayout(LayoutKind.Sequential)] + public struct ContextAmd64 + { + public long P1Home; + public long P2Home; + public long P3Home; + public long P4Home; + public long P5Home; + public long P6Home; + + public ContextFlagsAmd64 ContextFlags; + public int MxCsr; + + public ushort SegCs; + public ushort SegDs; + public ushort SegEs; + public ushort SegFs; + public ushort SegGs; + public ushort SegSs; + public int EFlags; + + public long Dr0; + public long Dr1; + public long Dr2; + public long Dr3; + public long Dr6; + public long Dr7; + + public long Rax; + public long Rcx; + public long Rdx; + public long Rbx; + public long Rsp; + public long Rbp; + public long Rsi; + public long Rdi; + public long R8; + public long R9; + public long R10; + public long R11; + public long R12; + public long R13; + public long R14; + public long R15; + + public long Rip; + + public XmmSaveArea32 FltSave; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 26)] + public M128A[] VectorRegister; + public long VectorControl; + + public long DebugControl; + public long LastBranchToRip; + public long LastBranchFromRip; + public long LastExceptionToRip; + public long LastExceptionFromRip; + } + + [StructLayout(LayoutKind.Sequential)] + public struct CsrApiMsg + { + public static readonly int ApiMessageDataOffset = + Marshal.OffsetOf(typeof(CsrApiMsg), "ApiMessageData").ToInt32(); + + public PortMessageStruct Header; + public IntPtr CaptureBuffer; // CsrCaptureHeader* + public int ApiNumber; + public int ReturnValue; + public int Reserved; + public int ApiMessageData; + // API message data follows. + } + + [StructLayout(LayoutKind.Sequential)] + public struct CsrCaptureHeader + { + public static readonly int MessagePointerOffsetsOffset = + Marshal.OffsetOf(typeof(CsrCaptureHeader), "MessagePointerOffsets").ToInt32(); + + public int Length; + public IntPtr RelatedCaptureBuffer; // CsrCaptureBuffer* + public int CountMessagePointers; + public IntPtr FreeSpace; + public IntPtr MessagePointerOffsets; + // Array of ULONG_PTRs follows. + } + + [StructLayout(LayoutKind.Sequential)] + public struct DbgKmCreateProcess + { + public int SubSystemKey; + public IntPtr FileHandle; + public IntPtr BaseOfImage; + public int DebugInfoFileOffset; + public int DebugInfoSize; + public DbgKmCreateThread InitialThread; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DbgKmCreateThread + { + public int SubSystemKey; + public IntPtr StartAddress; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DbgKmException + { + public ExceptionRecord ExceptionRecord; + public int FirstChance; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DbgKmExitProcess + { + public NtStatus ExitStatus; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DbgKmExitThread + { + public NtStatus ExitStatus; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DbgKmLoadDll + { + public IntPtr FileHandle; + public IntPtr BaseOfDll; + public int DebugInfoFileOffset; + public int DebugInfoSize; + public IntPtr NamePointer; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DbgKmUnloadDll + { + public IntPtr BaseAddress; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DbgUiCreateProcess + { + public IntPtr HandleToProcess; + public IntPtr HandleToThread; + public DbgKmCreateProcess NewProcess; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DbgUiCreateThread + { + public IntPtr HandleToThread; + public DbgKmCreateThread NewThread; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DbgUiWaitStateChange + { + // Overlapping objects and non-objects. Must manually marshal. + //[StructLayout(LayoutKind.Explicit, Pack = 1)] + //public struct StateInfoUnion + //{ + // [FieldOffset(0)] + // public DbgKmException Exception; + // [FieldOffset(0)] + // public DbgUiCreateThread CreateThread; + // [FieldOffset(0)] + // public DbgUiCreateProcess CreateProcess; + // [FieldOffset(0)] + // public DbgKmExitThread ExitThread; + // [FieldOffset(0)] + // public DbgKmExitProcess ExitProcess; + // [FieldOffset(0)] + // public DbgKmLoadDll LoadDll; + // [FieldOffset(0)] + // public DbgKmUnloadDll UnloadDll; + //} + + public DbgState NewState; + public ClientId AppClientId; + //public StateInfoUnion StateInfo; + } + + [StructLayout(LayoutKind.Sequential)] + public struct EnlistmentBasicInformation + { + public Guid EnlistmentId; + public Guid TransactionId; + public Guid ResourceManagerId; + } + + [StructLayout(LayoutKind.Sequential)] + public struct EventBasicInformation + { + public EventType EventType; + public int EventState; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ExceptionRecord + { + public NtStatus ExceptionCode; + public int ExceptionFlags; + public IntPtr ExceptionRecordPtr; + public IntPtr ExceptionAddress; + public int NumberParameters; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = Win32.ExceptionMaximumParameters)] + public IntPtr[] ExceptionInformation; + } + + [StructLayout(LayoutKind.Sequential)] + public struct FileAccessInformation + { + public FileAccess AccessFlags; + } + + [StructLayout(LayoutKind.Sequential)] + public struct FileAlignmentInformation + { + public FileAlignment AlignmentRequirement; + } + + [StructLayout(LayoutKind.Sequential)] + public struct FileAllInformation + { + public FileBasicInformation BasicInformation; + public FileStandardInformation StandardInformation; + public FileInternalInformation InternalInformation; + public FileEaInformation EaInformation; + public FileAccessInformation AccessInformation; + public FilePositionInformation PositionInformation; + public FileModeInformation ModeInformation; + public FileAlignmentInformation AlignmentInformation; + public FileNameInformation NameInformation; + } + + [StructLayout(LayoutKind.Sequential)] + public struct FileBasicInformation + { + public long CreationTime; + public long LastAccessTime; + public long LastWriteTime; + public long ChangeTime; + public FileAttributes FileAttributes; + } + + [StructLayout(LayoutKind.Sequential)] + public struct FileCompletionInformation + { + public IntPtr Port; + public IntPtr Key; + } + + [StructLayout(LayoutKind.Sequential)] + public struct FileDirectoryInformation + { + public static int FileNameOffset = + Marshal.OffsetOf(typeof(FileDirectoryInformation), "FileName").ToInt32(); + + public int NextEntryOffset; + public int FileIndex; + public long CreationTime; + public long LastAccessTime; + public long LastWriteTime; + public long ChangeTime; + public long EndOfFile; + public long AllocationSize; + public FileAttributes FileAttributes; + public int FileNameLength; + public short FileName; + // File name string follows (WCHAR). + } + + [StructLayout(LayoutKind.Sequential)] + public struct FileDispositionInformation + { + [MarshalAs(UnmanagedType.I1)] + public bool DeleteFile; + } + + [StructLayout(LayoutKind.Sequential)] + public struct FileEaInformation + { + public int EaSize; + } + + [StructLayout(LayoutKind.Sequential)] + public struct FileEndOfFileInformation + { + public long EndOfFile; + } + + [StructLayout(LayoutKind.Sequential)] + public struct FileFsAttributeInformation + { + public int FileSystemAttributes; + public int MaximumComponentNameLength; + public int FileSystemNameLength; + public short FileSystemName; + // File system name string follows (WCHAR). + } + + [StructLayout(LayoutKind.Sequential)] + public struct FileFsLabelInformation + { + public int VolumeLabelLength; + public short VolumeLabel; + // Volume label string follows (WCHAR). + } + + [StructLayout(LayoutKind.Sequential)] + public struct FileFsVolumeInformation + { + public long VolumeCreationTime; + public int VolumeSerialNumber; + public int VolumeLabelLength; + [MarshalAs(UnmanagedType.I1)] + public bool SupportsObjects; + public short VolumeLabel; + // Volume label string follows (WCHAR). + } + + [StructLayout(LayoutKind.Sequential)] + public struct FileInternalInformation + { + public long IndexNumber; + } + + [StructLayout(LayoutKind.Sequential)] + public struct FileMailslotQueryInformation + { + public int MaximumMessageSize; + public int MailslotQuota; + public int NextMessageSize; + public int MessagesAvailable; + public long ReadTimeout; + } + + [StructLayout(LayoutKind.Sequential)] + public struct FileMailslotSetInformation + { + public long ReadTimeout; + } + + [StructLayout(LayoutKind.Sequential)] + public struct FileModeInformation + { + public FileObjectFlags Mode; + } + + [StructLayout(LayoutKind.Sequential)] + public struct FileNameInformation + { + public static int FileNameOffset = + Marshal.OffsetOf(typeof(FileNameInformation), "FileName").ToInt32(); + + public int FileNameLength; + public short FileName; + // File name string follows (WCHAR). + } + + [StructLayout(LayoutKind.Sequential)] + public struct FileNamesInformation + { + public int NextEntryOffset; + public int FileIndex; + public int FileNameLength; + public short FileName; + // File name string follows (WCHAR). + } + + [StructLayout(LayoutKind.Sequential)] + public struct FileNotifyInformation + { + public static int FileNameOffset = + Marshal.OffsetOf(typeof(FileNotifyInformation), "FileName").ToInt32(); + + public int NextEntryOffset; + public FileNotifyAction Action; + public int FileNameLength; + public short FileName; + // Unicode file name string follows. + } + + [StructLayout(LayoutKind.Sequential)] + public struct FilePipeInformation + { + public PipeType ReadMode; + public PipeCompletionMode CompletionMode; + } + + [StructLayout(LayoutKind.Sequential)] + public struct FilePipeLocalInformation + { + public PipeType NamedPipeType; + public PipeConfiguration NamedPipeConfiguration; + public int MaximumInstances; + public int CurrentInstances; + public int InboundQuota; + public int ReadDataAvailable; + public int OutboundQuota; + public int WriteQuotaAvailable; + public PipeState NamedPipeState; + public PipeEnd NamedPipeEnd; + } + + [StructLayout(LayoutKind.Sequential)] + public struct FilePipePeekBuffer + { + public static readonly int DataOffset = + Marshal.OffsetOf(typeof(FilePipePeekBuffer), "Data").ToInt32(); + + public PipeState NamedPipeState; + public int ReadDataAvailable; + public int NumberOfMessages; + public int MessageLength; + public byte Data; + } + + [StructLayout(LayoutKind.Sequential)] + public struct FilePipeWaitForBuffer + { + public static readonly int NameOffset = + Marshal.OffsetOf(typeof(FilePipeWaitForBuffer), "Name").ToInt32(); + + public long Timeout; + public int NameLength; + [MarshalAs(UnmanagedType.I1)] + public bool TimeoutSpecified; + public short Name; + } + + [StructLayout(LayoutKind.Sequential)] + public struct FilePositionInformation + { + public long CurrentByteOffset; + } + + [StructLayout(LayoutKind.Sequential)] + public struct FileStandardInformation + { + public long AllocationSize; + public long EndOfFile; + public int NumberOfLinks; + [MarshalAs(UnmanagedType.I1)] + public bool DeletePending; + [MarshalAs(UnmanagedType.I1)] + public bool Directory; + } + + [StructLayout(LayoutKind.Sequential)] + public struct FileStreamInformation + { + public static int StreamNameOffset = + Marshal.OffsetOf(typeof(FileStreamInformation), "StreamName").ToInt32(); + + public int NextEntryOffset; + public int StreamNameLength; + public long StreamSize; + public long StreamAllocationSize; + public short StreamName; + // Stream name string follows (WCHAR). + } + + [StructLayout(LayoutKind.Sequential)] + public struct FloatingSaveArea + { + public int ControlWord; + public int StatusWord; + public int TagWord; + public int ErrorOffset; + public int ErrorSelector; + public int DataOffset; + public int DataSelector; + + public unsafe fixed byte RegisterArea[Win32.SizeOf80387Registers]; + + public int Cr0NpxState; + } + + [StructLayout(LayoutKind.Sequential)] + public struct GenericMapping + { + public int GenericRead; + public int GenericWrite; + public int GenericExecute; + public int GenericAll; + } + + [StructLayout(LayoutKind.Sequential)] + public struct GenericMapping + where T : struct + { + public GenericMapping(T read, T write, T execute, T all) + { + this.GenericRead = read; + this.GenericWrite = write; + this.GenericExecute = execute; + this.GenericAll = all; + } + + public T GenericRead; + public T GenericWrite; + public T GenericExecute; + public T GenericAll; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ImageBaseRelocation + { + public int VirtualAddress; + public int SizeOfBlock; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ImageBoundForwarderRef + { + public int TimeDateStamp; + public short OffsetModuleName; + public short Reserved; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ImageBoundImportDescriptor + { + public int TimeDateStamp; + public short OffsetModuleName; + public short NumberOfModuleForwarderRefs; + public ImageBoundForwarderRef ForwarderRefs; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ImageDataDirectory + { + public int VirtualAddress; + public int Size; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ImageExportDirectory + { + public int Characteristics; + public int TimeDateStamp; + public short MajorVersion; + public short MinorVersion; + public int Name; + public int Base; + public int NumberOfFunctions; + public int NumberOfNames; + public int AddressOfFunctions; + public int AddressOfNames; + public int AddressOfNameOrdinals; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ImageFileHeader + { + public MachineType Machine; + public short NumberOfSections; + public int TimeDateStamp; + public int PointerToSymbolTable; + public int NumberOfSymbols; + public short SizeOfOptionalHeader; + public ImageCharacteristics Characteristics; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ImageImportByName + { + public short Hint; + public byte Name; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ImageImportDescriptor + { + public int OriginalFirstThunk; // also Characteristics + public int TimeDateStamp; + public int ForwarderChain; + public int Name; + public int FirstThunk; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ImageLoadConfigDirectory + { + public int Size; + public int TimeDateStamp; + public short MajorVersion; + public short MinorVersion; + public int GlobalFlagsClear; + public int GlobalFlagsSet; + public int CriticalSectionDefaultTimeout; + public int DeCommitFreeBlockThreshold; + public int DeCommitTotalFreeThreshold; + public int LockPrefixTable; + public int MaximumAllocationSize; + public int VirtualMemoryThreshold; + public int ProcessHeapFlags; + public int ProcessAffinityMask; + public short CsdVersion; + public short Reserved1; + public int EditList; + public int SecurityCookie; + public int SEHandlerTable; + public int SEHandlerCount; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ImageLoadConfigDirectory64 + { + public int Size; + public int TimeDateStamp; + public short MajorVersion; + public short MinorVersion; + public int GlobalFlagsClear; + public int GlobalFlagsSet; + public int CriticalSectionDefaultTimeout; + public long DeCommitFreeBlockThreshold; + public long DeCommitTotalFreeThreshold; + public long LockPrefixTable; + public long MaximumAllocationSize; + public long VirtualMemoryThreshold; + public long ProcessAffinityMask; + public int ProcessHeapFlags; + public short CsdVersion; + public short Reserved1; + public long EditList; + public long SecurityCookie; + public long SEHandlerTable; + public long SEHandlerCount; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ImageNtHeaders + { + public int Signature; + public ImageFileHeader FileHeader; + public ImageOptionalHeader OptionalHeader; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ImageOptionalHeader + { + public short Magic; + public byte MajorLinkerVersion; + public byte MinorLinkerVersion; + public int SizeOfCode; + public int SizeOfInitializedData; + public int SizeOfUninitializedData; + public int AddressOfEntryPoint; + public int BaseOfCode; + public int BaseOfData; + public int ImageBase; + public int SectionAlignment; + public int FileAlignment; + public short MajorOperatingSystemVersion; + public short MinorOperatingSystemVersion; + public short MajorImageVersion; + public short MinorImageVersion; + public short MajorSubsystemVersion; + public short MinorSubsystemVersion; + public int Win32VersionValue; + public int SizeOfImage; + public int SizeOfHeaders; + public int CheckSum; + public ImageSubsystem Subsystem; + public ImageDllCharacteristics DllCharacteristics; + public int SizeOfStackReserve; + public int SizeOfStackCommit; + public int SizeOfHeapReserve; + public int SizeOfHeapCommit; + public int LoaderFlags; + public int NumberOfRvaAndSizes; + public ImageDataDirectory DataDirectory; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ImageOptionalHeader64 + { + public short Magic; + public byte MajorLinkerVersion; + public byte MinorLinkerVersion; + public int SizeOfCode; + public int SizeOfInitializedData; + public int SizeOfUninitializedData; + public int AddressOfEntryPoint; + public int BaseOfCode; + public long ImageBase; + public int SectionAlignment; + public int FileAlignment; + public short MajorOperatingSystemVersion; + public short MinorOperatingSystemVersion; + public short MajorImageVersion; + public short MinorImageVersion; + public short MajorSubsystemVersion; + public short MinorSubsystemVersion; + public int Win32VersionValue; + public int SizeOfImage; + public int SizeOfHeaders; + public int CheckSum; + public ImageSubsystem Subsystem; + public ImageDllCharacteristics DllCharacteristics; + public long SizeOfStackReserve; + public long SizeOfStackCommit; + public long SizeOfHeapReserve; + public long SizeOfHeapCommit; + public int LoaderFlags; + public int NumberOfRvaAndSizes; + public ImageDataDirectory DataDirectory; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ImageRelocation + { + public int VirtualAddress; + public int SymbolTableIndex; + public short Type; + } + + [StructLayout(LayoutKind.Sequential)] + public unsafe struct ImageSectionHeader + { + public fixed byte Name[8]; + public int Misc; // PhysicalAddress, VirtualSize + public int VirtualAddress; + public int SizeOfRawData; + public int PointerToRawData; + public int PointerToRelocations; + public int PointerToLinenumbers; + public short NumberOfRelocations; + public short NumberOfLinenumbers; + public ImageSectionFlags Characteristics; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ImageThunkData + { + public int ForwarderString; // byte* + public int Function; // int* + public int Ordinal; + public int AddressOfData; // ImageImportByName* + } + + [StructLayout(LayoutKind.Sequential)] + public struct ImageThunkData64 + { + public long ForwarderString; // byte* + public long Function; // int* + public long Ordinal; + public long AddressOfData; // ImageImportByName* + } + + [StructLayout(LayoutKind.Sequential)] + public struct InitialTeb + { + public struct OldInitialTebStruct + { + public IntPtr OldStackBase; + public IntPtr OldStackLimit; + } + + public OldInitialTebStruct OldInitialTeb; + public IntPtr StackBase; + public IntPtr StackLimit; + public IntPtr StackAllocationBase; + } + + [StructLayout(LayoutKind.Sequential)] + public struct IoCompletionBasicInformation + { + public int Depth; + } + + [StructLayout(LayoutKind.Sequential)] + public struct IoCounters + { + public ulong ReadOperationCount; + public ulong WriteOperationCount; + public ulong OtherOperationCount; + public ulong ReadTransferCount; + public ulong WriteTransferCount; + public ulong OtherTransferCount; + } + + [StructLayout(LayoutKind.Sequential)] + public struct IoStatusBlock + { + public IoStatusBlock(NtStatus status) + : this(status, IntPtr.Zero) + { } + + public IoStatusBlock(NtStatus status, IntPtr information) + { + this.Pointer = IntPtr.Zero; + this.Information = information; + this.Status = status; + } + + public IoStatusBlock(IntPtr pointer) + : this(pointer, IntPtr.Zero) + { } + + public IoStatusBlock(IntPtr pointer, IntPtr information) + { + this.Pointer = pointer; + this.Information = information; + } + + public IntPtr Pointer; + public IntPtr Information; + + public unsafe NtStatus Status + { + get + { + fixed (IoStatusBlock* thisPtr = &this) + return *(NtStatus*)&thisPtr->Pointer; + } + set + { + fixed (IoStatusBlock* thisPtr = &this) + *(NtStatus*)&thisPtr->Pointer = value; + } + } + } + + [StructLayout(LayoutKind.Sequential)] + public struct JobObjectBasicAccountingInformation + { + public long TotalUserTime; + public long TotalKernelTime; + public long ThisPeriodTotalUserTime; + public long ThisPeriodTotalKernelTime; + public int TotalPageFaultCount; + public int TotalProcesses; + public int ActiveProcesses; + public int TotalTerminatedProcesses; + } + + [StructLayout(LayoutKind.Sequential)] + public struct JobObjectBasicAndIoAccountingInformation + { + public JobObjectBasicAccountingInformation BasicInfo; + public IoCounters IoInfo; + } + + [StructLayout(LayoutKind.Sequential)] + public struct JobObjectBasicLimitInformation + { + public long PerProcessUserTimeLimit; + public long PerJobUserTimeLimit; + public JobObjectLimitFlags LimitFlags; + public int MinimumWorkingSetSize; + public int MaximumWorkingSetSize; + public int ActiveProcessLimit; + public int Affinity; + public int PriorityClass; + public int SchedulingClass; + } + + [StructLayout(LayoutKind.Sequential)] + public struct JobObjectBasicProcessIdList + { + public int NumberOfAssignedProcesses; + public int NumberOfProcessIdsInList; + /* an array follows */ + } + + [StructLayout(LayoutKind.Sequential)] + public struct JobObjectEndOfJobTimeInformation + { + public int EndOfJobTimeAction; // 0: Terminate, 1: Post + } + + [StructLayout(LayoutKind.Sequential)] + public struct JobObjectExtendedLimitInformation + { + public JobObjectBasicLimitInformation BasicLimitInformation; + public IoCounters IoInfo; + public int ProcessMemoryLimit; + public int JobMemoryLimit; + public int PeakProcessMemoryUsed; + public int PeakJobMemoryUsed; + } + + [StructLayout(LayoutKind.Sequential)] + public struct JobSetArray + { + public IntPtr JobHandle; + public uint MemberLevel; + public int Flags; // Unused + } + + [StructLayout(LayoutKind.Sequential)] + public struct KeyBasicInformation + { + public LargeInteger LastWriteTime; + public int TitleIndex; + public int NameLength; + public short Name; + // Variable length string follows. + } + + [StructLayout(LayoutKind.Sequential)] + public struct KeyCachedInformation + { + public LargeInteger LastWriteTime; + public int TitleIndex; + public int SubKeys; + public int MaxNameLen; + public int Values; + public int MaxValueNameLen; + public int MaxValueDataLen; + public int NameLength; + public short Name; + // Variable length string follows. + } + + [StructLayout(LayoutKind.Sequential)] + public struct KeyFlagsInformation + { + public int UserFlags; + } + + [StructLayout(LayoutKind.Sequential)] + public struct KeyFullInformation + { + public LargeInteger LastWriteTime; + public int TitleIndex; + public int ClassOffset; + public int ClassLength; + public int SubKeys; + public int MaxNameLen; + public int MaxClassLen; + public int Values; + public int MaxValueNameLen; + public int MaxValueDataLen; + public short Class; + // Variable length string follows. + } + + [StructLayout(LayoutKind.Sequential)] + public struct KeyNameInformation + { + public int NameLength; + public short Name; + // Variable length string follows. + } + + [StructLayout(LayoutKind.Sequential)] + public struct KeyNodeInformation + { + public LargeInteger LastWriteTime; + public int TitleIndex; + public int ClassOffset; + public int ClassLength; + public int NameLength; + public short Name; + // Variable length string follows. + } + + [StructLayout(LayoutKind.Sequential)] + public struct KeyUserFlagsInformation + { + public int UserFlags; + } + + [StructLayout(LayoutKind.Sequential)] + public struct KeyValueBasicInformation + { + public int TitleIndex; + public int Type; + public int NameLength; + public short Name; + // Variable length string follows. + } + + [StructLayout(LayoutKind.Sequential)] + public struct KeyValueEntry + { + public IntPtr ValueName; // pointer to UNICODE_STRING + public int DataLength; + public int DataOffset; + public int Type; + } + + [StructLayout(LayoutKind.Sequential)] + public struct KeyValueFullInformation + { + public int TitleIndex; + public int Type; + public int DataOffset; + public int DataLength; + public int NameLength; + public short Name; + // Variable length string follows. + } + + [StructLayout(LayoutKind.Sequential)] + public struct KeyValuePartialInformation + { + public int TitleIndex; + public int Type; + public int DataLength; + public byte Data; + // Variable length data follows. + } + + [StructLayout(LayoutKind.Sequential)] + public struct KeyWriteTimeInformation + { + public LargeInteger LastWriteTime; + } + + [StructLayout(LayoutKind.Sequential)] + public struct KnownAceStruct + { + public AceHeader Header; + public int Mask; + public int SidStart; + } + + [StructLayout(LayoutKind.Explicit, Size = 12)] + public struct KSystemTime + { + [FieldOffset(0)] + public uint LowPart; + [FieldOffset(4)] + public int High1Time; + [FieldOffset(8)] + public int High2Time; + + [FieldOffset(0)] + public long QuadPart; + } + + [StructLayout(LayoutKind.Sequential)] + public struct KtmObjectCursor + { + public Guid LastQuery; + public int ObjectIdCount; + public byte ObjectIds; + // Array of Guids follows. + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 4)] + public struct KUserSharedData + { + public static readonly int TickCountOffset = + Marshal.OffsetOf(typeof(KUserSharedData), "TickCount").ToInt32(); + public static readonly int TickCountMultiplierOffset = + Marshal.OffsetOf(typeof(KUserSharedData), "TickCountMultiplier").ToInt32(); + + public int TickCountLowDeprecated; + public int TickCountMultiplier; + public KSystemTime InterruptTime; + public KSystemTime SystemTime; + public KSystemTime TimeZoneBias; + public ushort ImageNumberLow; + public ushort ImageNumberHigh; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] + public string NtSystemRoot; + + public int MaxStackTraceDepth; + public int CryptoExponent; + public int TimeZoneId; + public int LargePageMinimum; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] + public int[] Reserved2; + + public WinNtProductType NtProductType; + [MarshalAs(UnmanagedType.U1)] + public bool ProductTypeIsValid; + + public int NtMajorVersion; + public int NtMinorVersion; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = Win32.ProcessorFeatureMax)] + public byte[] ProcessorFeatures; + + public int Reserved1; + public int Reserved3; + public int TimeSlip; + public AlternativeArchitectureType AlternativeArchitecture; + public int Padding1; + public long SystemExpirationDate; + public SuiteType SuiteMask; + [MarshalAs(UnmanagedType.U1)] + public bool KdDebuggerEnabled; + public byte NXSupportPolicy; + public int ActiveConsoleId; + public int DismountCount; + public int ComPlusPackage; + public int LastSystemRITEventTickCount; + public int NumberOfPhysicalPages; + [MarshalAs(UnmanagedType.U1)] + public bool SafeBootMode; + public int TraceLogging; + public int Padding3; + + public long TestRetInstruction; + public int SystemCall; + public int SystemCallReturn; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public long[] SystemCallPad; + + public KSystemTime TickCount; + + public int Cookie; + } + + [StructLayout(LayoutKind.Explicit, Size = 8)] + public struct LargeInteger + { + public static implicit operator long(LargeInteger li) + { + return li.QuadPart; + } + + public LargeInteger(long quadPart) + { + this.LowPart = 0; + this.HighPart = 0; + this.QuadPart = quadPart; + } + + [FieldOffset(0)] + public long QuadPart; + [FieldOffset(0)] + public uint LowPart; + [FieldOffset(4)] + public int HighPart; + } + + [StructLayout(LayoutKind.Sequential)] + public struct LdrDataTableEntry + { + public static readonly int LoadCountOffset = + Marshal.OffsetOf(typeof(LdrDataTableEntry), "LoadCount").ToInt32(); + + public ListEntry InLoadOrderLinks; + public ListEntry InMemoryOrderLinks; + public ListEntry InInitializationOrderLinks; + public IntPtr DllBase; + public IntPtr EntryPoint; + public int SizeOfImage; + public UnicodeString FullDllName; + public UnicodeString BaseDllName; + public LdrpDataTableEntryFlags Flags; + public short LoadCount; + public short TlsIndex; + public ListEntry HashTableEntry; + public int TimeDateStamp; + public IntPtr EntryPointActivationContext; + public IntPtr PatchInformation; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ListEntry + { + public IntPtr Flink; + public IntPtr Blink; + } + + /// + /// Represents a locally unique identifier (LUID), a value which + /// is unique on the currently running system. + /// + [StructLayout(LayoutKind.Explicit, Pack = 4)] + public struct Luid : IEquatable, IEquatable + { + public static readonly Luid Empty = new Luid(); + public static readonly Luid System = new Luid(0x3e7, 0); + public static readonly Luid AnonymousLogon = new Luid(0x3e6, 0); + public static readonly Luid LocalService = new Luid(0x3e5, 0); + public static readonly Luid NetworkService = new Luid(0x3e4, 0); + + /// + /// Creates a LUID from a single 64-bit value. + /// + /// The value. + public Luid(long quadPart) + { + this.LowPart = 0; + this.HighPart = 0; + this.QuadPart = quadPart; + } + + /// + /// Creates a LUID from two 32-bit values. + /// + /// The low 32 bits of the LUID. + /// The high 32 bits of the LUID. + public Luid(uint lowPart, int highPart) + { + this.QuadPart = 0; + this.LowPart = lowPart; + this.HighPart = highPart; + } + + /// + /// The 64-bit value of the LUID. + /// + [FieldOffset(0)] + public long QuadPart; + /// + /// The low 32 bits of the LUID. + /// + [FieldOffset(0)] + public uint LowPart; + /// + /// The high 32 bits of the LUID. + /// + [FieldOffset(4)] + public int HighPart; + + /// + /// Allocates a locally unique identifier (LUID) from + /// the kernel. + /// + /// A new LUID. + public static Luid Allocate() + { + NtStatus status; + Luid luid; + + if ((status = Win32.NtAllocateLocallyUniqueId(out luid)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return luid; + } + + public bool Equals(Luid other) + { + return this.QuadPart == other.QuadPart; + } + + public bool Equals(long other) + { + return this.QuadPart == other; + } + + public long ToLong() + { + return this.QuadPart; + } + + public override string ToString() + { + return this.QuadPart.ToString("x"); + } + + public uint ToUInt32() + { + return this.LowPart; + } + } + + [StructLayout(LayoutKind.Sequential)] + public struct M128A + { + public ulong Low; + public long High; + } + + [StructLayout(LayoutKind.Sequential)] + public struct MessageResourceEntry + { + public static readonly int TextOffset = Marshal.OffsetOf(typeof(MessageResourceEntry), "Text").ToInt32(); + + public ushort Length; + public MessageResourceFlags Flags; + public byte Text; + // ANSI/Unicode string follows. + } + + [StructLayout(LayoutKind.Sequential)] + public struct MutantBasicInformation + { + public int CurrentCount; + [MarshalAs(UnmanagedType.U1)] + public bool OwnedByCaller; + [MarshalAs(UnmanagedType.U1)] + public bool AbandonedState; + } + + [StructLayout(LayoutKind.Sequential)] + public struct MutantOwnerInformation + { + public ClientId ClientId; + } + + [StructLayout(LayoutKind.Sequential)] + public struct NtTib + { + public IntPtr ExceptionList; // ExceptionRegistrationRecord* + public IntPtr StackBase; + public IntPtr StackLimit; + public IntPtr SubSystemTib; + public IntPtr FiberData; + public IntPtr ArbitraryUserPointer; + public IntPtr Self; // NtTib* + } + + [StructLayout(LayoutKind.Sequential)] + public struct ObjectAttributes : IDisposable + { + public ObjectAttributes( + string objectName, + ObjectFlags attributes, + NativeHandle rootDirectory) + : this(objectName, attributes, rootDirectory, null, null) + { } + + public ObjectAttributes( + string objectName, + ObjectFlags attributes, + NativeHandle rootDirectory, + SecurityDescriptor securityDescriptor, + SecurityQualityOfService? securityQos + ) + { + this.Length = Marshal.SizeOf(typeof(ObjectAttributes)); + this.RootDirectory = IntPtr.Zero; + this.ObjectName = IntPtr.Zero; + this.SecurityDescriptor = IntPtr.Zero; + this.SecurityQualityOfService = IntPtr.Zero; + + // Object name + if (objectName != null) + { + UnicodeString unicodeString = new UnicodeString(objectName); + IntPtr unicodeStringMemory = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(UnicodeString))); + + Marshal.StructureToPtr(unicodeString, unicodeStringMemory, false); + this.ObjectName = unicodeStringMemory; + } + + // Object flags + this.Attributes = attributes; + + // Root directory + if (rootDirectory != null) + this.RootDirectory = rootDirectory; + + // Security descriptor + this.SecurityDescriptor = securityDescriptor ?? IntPtr.Zero; + + // Security QOS + if (securityQos.HasValue) + { + this.SecurityQualityOfService = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SecurityQualityOfService))); + Marshal.StructureToPtr(securityQos.Value, this.SecurityQualityOfService, false); + } + } + + public int Length; + public IntPtr RootDirectory; + public IntPtr ObjectName; + public ObjectFlags Attributes; + public IntPtr SecurityDescriptor; + public IntPtr SecurityQualityOfService; + + public void Dispose() + { + // Object name + if (this.ObjectName != IntPtr.Zero) + { + UnicodeString unicodeString = + (UnicodeString)Marshal.PtrToStructure(this.ObjectName, typeof(UnicodeString)); + + unicodeString.Dispose(); + Marshal.FreeHGlobal(this.ObjectName); + + this.ObjectName = IntPtr.Zero; + } + + // Security QOS + if (this.SecurityQualityOfService != null) + { + Marshal.FreeHGlobal(this.SecurityQualityOfService); + this.SecurityQualityOfService = IntPtr.Zero; + } + } + } + + [StructLayout(LayoutKind.Sequential)] + public struct ObjectBasicInformation + { + public uint Attributes; + public int GrantedAccess; + public uint HandleCount; + public uint PointerCount; + public uint PagedPoolUsage; + public uint NonPagedPoolUsage; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public uint[] Reserved; + + public uint NameInformationLength; + public uint TypeInformationLength; + public uint SecurityDescriptorLength; + public ulong CreateTime; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ObjectDirectoryInformation + { + public UnicodeString Name; + public UnicodeString TypeName; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ObjectNameInformation + { + public UnicodeString Name; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ObjectTypeInformation + { + public UnicodeString Name; + public int TotalNumberOfObjects; + public int TotalNumberOfHandles; + public int TotalPagedPoolUsage; + public int TotalNonPagedPoolUsage; + public int TotalNamePoolUsage; + public int TotalHandleTableUsage; + public int HighWaterNumberOfObjects; + public int HighWaterNumberOfHandles; + public int HighWaterPagedPoolUsage; + public int HighWaterNonPagedPoolUsage; + public int HighWaterNamePoolUsage; + public int HighWaterHandleTableUsage; + public int InvalidAttributes; + public GenericMapping GenericMapping; + public int ValidAccess; + public byte SecurityRequired; + public byte MaintainHandleCount; + public ushort MaintainTypeList; + public PoolType PoolType; + public int PagedPoolUsage; + public int NonPagedPoolUsage; + } + + [StructLayout(LayoutKind.Sequential)] + public struct Peb + { + public static readonly int ImageSubsystemOffset = + Marshal.OffsetOf(typeof(Peb), "ImageSubsystem").ToInt32(); + public static readonly int LdrOffset = + Marshal.OffsetOf(typeof(Peb), "Ldr").ToInt32(); + public static readonly int ProcessHeapOffset = + Marshal.OffsetOf(typeof(Peb), "ProcessHeap").ToInt32(); + public static readonly int ProcessParametersOffset = + Marshal.OffsetOf(typeof(Peb), "ProcessParameters").ToInt32(); + + [MarshalAs(UnmanagedType.I1)] + public bool InheritedAddressSpace; + [MarshalAs(UnmanagedType.I1)] + public bool ReadImageFileExecOptions; + [MarshalAs(UnmanagedType.I1)] + public bool BeingDebugged; + [MarshalAs(UnmanagedType.I1)] + public bool BitField; + public IntPtr Mutant; + + public IntPtr ImageBaseAddress; + public IntPtr Ldr; // PebLdrData* + public IntPtr ProcessParameters; // RtlUserProcessParameters* + public IntPtr SubSystemData; + public IntPtr ProcessHeap; + public IntPtr FastPebLock; + public IntPtr AtlThunkSListPtr; + public IntPtr SparePrt2; + public int EnvironmentUpdateCount; + public IntPtr KernelCallbackTable; + public int SystemReserved; + public int SpareUlong; + public IntPtr FreeList; + public int TlsExpansionCounter; + public IntPtr TlsBitmap; + public unsafe fixed int TlsBitmapBits[2]; + public IntPtr ReadOnlySharedMemoryBase; + public IntPtr ReadOnlySharedMemoryHeap; + public IntPtr ReadOnlyStaticServerData; + public IntPtr AnsiCodePageData; + public IntPtr OemCodePageData; + public IntPtr UnicodeCaseTableData; + + public int NumberOfProcessors; + public int NtGlobalFlag; + + public long CriticalSectionTimeout; + public IntPtr HeapSegmentReserve; + public IntPtr HeapSegmentCommit; + public IntPtr HeapDeCommitTotalFreeThreshold; + public IntPtr HeapDeCommitFreeBlockThreshold; + + public int NumberOfHeaps; + public int MaximumNumberOfHeaps; + public IntPtr ProcessHeaps; + + public IntPtr GdiSharedHandleTable; + public IntPtr ProcessStarterHelper; + public int GdiDCAttributeList; + public IntPtr LoaderLock; + + public int OSMajorVersion; + public int OSMinorVersion; + public short OSBuildNumber; + public short OSCSDVersion; + public int OSPlatformId; + public int ImageSubsystem; + public int ImageSubsystemMajorVersion; + public int ImageSubsystemMinorVersion; + public IntPtr ImageProcessAffinityMask; + public unsafe fixed byte GdiHandleBuffer[Win32.GdiHandleBufferSize]; + public IntPtr PostProcessInitRoutine; + + public IntPtr TlsExpansionBitmap; + public unsafe fixed int TlsExpansionBitmapBits[32]; + + public int SessionId; + + public long AppCompatFlags; + public long AppCompatFlagsUser; + public IntPtr pShimData; + public IntPtr AppCompatInfo; + + public UnicodeString CSDVersion; + + public IntPtr ActivationContextData; + public IntPtr ProcessAssemblyStorageMap; + public IntPtr SystemDefaultActivationContextData; + public IntPtr SystemAssemblyStorageMap; + + public IntPtr MinimumStackCommit; + + public IntPtr FlsCallback; + public ListEntry FlsListHead; + public IntPtr FlsBitmap; + public unsafe fixed int FlsBitmapBits[Win32.FlsMaximumAvailable / (sizeof(int) * 8)]; + public int FlsHighIndex; + } + + [StructLayout(LayoutKind.Sequential)] + public struct PebLdrData + { + public int Length; + [MarshalAs(UnmanagedType.I1)] + public bool Initialized; + public IntPtr SsHandle; + public ListEntry InLoadOrderModuleList; + public ListEntry InMemoryOrderModuleList; + public ListEntry InInitializationOrderModuleList; + } + + [StructLayout(LayoutKind.Sequential)] + public struct PooledUsageAndLimits + { + public int PeakPagedPoolUsage; + public int PagedPoolUsage; + public int PagedPoolLimit; + public int PeakNonPagedPoolUsage; + public int NonPagedPoolUsage; + public int NonPagedPoolLimit; + public int PeakPagefileUsage; + public int PagefileUsage; + public int PagefileLimit; + } + + [StructLayout(LayoutKind.Sequential)] + public struct PortMessageStruct + { + public short DataLength; + public short TotalLength; + public PortMessageType Type; + public short DataInfoOffset; + public ClientId ClientId; + public int MessageId; + public IntPtr ClientViewSize; + } + + [StructLayout(LayoutKind.Sequential)] + public struct PortView + { + public int Length; + public IntPtr SectionHandle; + public int SectionOffset; + public IntPtr ViewSize; + public IntPtr ViewBase; + public IntPtr ViewRemoteBase; + } + + [StructLayout(LayoutKind.Sequential)] + public struct PrivilegeSetStruct + { + public static int PrivilegesOffset = + Marshal.OffsetOf(typeof(PrivilegeSetStruct), "Privileges").ToInt32(); + + public int Count; + public PrivilegeSetFlags Flags; + public LuidAndAttributes Privileges; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ProcessBasicInformation + { + public NtStatus ExitStatus; + public IntPtr PebBaseAddress; + public IntPtr AffinityMask; + public int BasePriority; + public IntPtr UniqueProcessId; + public IntPtr InheritedFromUniqueProcessId; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ProcessForegroundBackground + { + [MarshalAs(UnmanagedType.I1)] + public bool Foreground; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ProcessHandleTracingEnable + { + public int Flags; // No flags. Set to 0. + } + + [StructLayout(LayoutKind.Sequential)] + public struct ProcessHandleTracingEnableEx + { + public int Flags; // No flags. Set to 0. + public int TotalSlots; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ProcessHandleTracingEntry + { + public IntPtr Handle; + public ClientId ClientId; + public HandleTraceType Type; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = Win32.ProcessHandleTracingMaxStacks)] + public IntPtr[] Stacks; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ProcessHandleTracingQuery + { + public static readonly int HandleTraceOffset = + Marshal.OffsetOf(typeof(ProcessHandleTracingQuery), "HandleTrace").ToInt32(); + + public IntPtr Handle; + public int TotalTraces; + public ProcessHandleTracingEntry HandleTrace; + // An array of ProcessHandleTracingEntry structures follows. + } + + [StructLayout(LayoutKind.Sequential)] + public struct ProcessPriorityClassStruct + { + [MarshalAs(UnmanagedType.I1)] + public bool Foreground; + public ProcessPriorityClass PriorityClass; + } + + [StructLayout(LayoutKind.Sequential)] + public struct RemotePortView + { + public int Length; + public IntPtr ViewSize; + public IntPtr ViewBase; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ResourceManagerBasicInformation + { + public static readonly int DescriptionOffset = + Marshal.OffsetOf(typeof(ResourceManagerBasicInformation), "Description").ToInt32(); + + /// + /// The GUID assigned to the resource manager. + /// + public Guid ResourceManagerId; + + /// + /// The length, in bytes, of the resource manager description string. + /// + public int DescriptionLength; + + /// + /// The first byte of the description string. + /// + public byte Description; // wchar[] + // Description string follows. + } + + [StructLayout(LayoutKind.Sequential)] + public struct RtlAceData + { + public AceType AceType; + public AceFlags InheritFlags; + public AceFlags AceFlags; + public int Mask; + public IntPtr Sid; // Sid** + } + + [StructLayout(LayoutKind.Sequential)] + public struct RtlBitmap + { + public int SizeOfBitMap; + public IntPtr Buffer; // int* + } + + [StructLayout(LayoutKind.Sequential)] + public struct RtlBitmapRun + { + public int StartingIndex; + public int NumberOfBits; + } + + [StructLayout(LayoutKind.Sequential)] + public struct RtlDebugInformation + { + public IntPtr SectionHandleClient; + public IntPtr ViewBaseClient; + public IntPtr ViewBaseTarget; + public IntPtr ViewBaseDelta; + public IntPtr EventPairClient; + public IntPtr EventPairTarget; + public IntPtr TargetProcessId; + public IntPtr TargetThreadHandle; + public int Flags; + public IntPtr OffsetFree; + public IntPtr CommitSize; + public IntPtr ViewSize; + public IntPtr Modules; // RtlProcessModules* + public IntPtr BackTraces; // RtlProcessBackTraces* + public IntPtr Heaps; // RtlProcessHeaps* + public IntPtr Locks; // RtlProcessLocks* + public IntPtr SpecificHeap; + public IntPtr TargetProcessHandle; +#if _X64 + public unsafe fixed long Reserved[6]; +#else + public unsafe fixed int Reserved[6]; +#endif + } + + [StructLayout(LayoutKind.Sequential)] + public struct RtlHandleTable + { + public int MaximumNumberOfHandles; + public int SizeOfHandleTableEntry; + public int Reserved1; + public int Reserved2; + public IntPtr FreeHandles; + public IntPtr CommittedHandles; + public IntPtr UnCommittedHandles; + public IntPtr MaxReservedHandles; + } + + [StructLayout(LayoutKind.Sequential)] + public struct RtlHeapInformation + { + public IntPtr BaseAddress; + public int Flags; + public ushort EntryOverhead; + public ushort CreatorBackTraceIndex; + public IntPtr BytesAllocated; + public IntPtr BytesCommitted; + public int NumberOfTags; + public int NumberOfEntries; + public int NumberOfPseudoTags; + public int PseudoTagGranularity; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] + public int[] Reserved; + public IntPtr Tags; + public IntPtr Entries; + } + + [StructLayout(LayoutKind.Sequential)] + public struct RtlProcessBackTraceInformation + { + public IntPtr SymbolicBackTrace; // PCHAR, always NULL. + public int TraceCount; + public ushort Index; + public ushort Depth; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = Win32.MaxStackDepth)] + public IntPtr[] BackTrace; + } + + [StructLayout(LayoutKind.Sequential)] + public struct RtlProcessBackTraces + { + public int CommittedMemory; + public int ReservedMemory; + public int NumberOfBackTraceLookups; + public int NumberOfBackTraces; + public byte BackTraces; // RtlProcessBackTraceInformation[] BackTraces + // Array of RtlProcessBackTraceInformation structures follows. + } + + [StructLayout(LayoutKind.Sequential)] + public struct RtlProcessHeaps + { + public static readonly int HeapsOffset = + Marshal.OffsetOf(typeof(RtlProcessHeaps), "Heaps").ToInt32(); + + public int NumberOfHeaps; + public RtlHeapInformation Heaps; + // Array of RtlHeapInformation structures follows. + } + + [StructLayout(LayoutKind.Sequential)] + public struct RtlProcessLockInformation + { + public IntPtr Address; + public RtlLockType Type; + public ushort CreatorBackTraceInformation; + + public IntPtr OwningThread; // TID + public int LockCount; + public int ContentionCount; + public int EntryCount; + + // Valid for critical sections + public int RecursionCount; + + // Valid for resources + public int NumberOfWaitingShared; + public int NumberOfWaitingExclusive; + } + + [StructLayout(LayoutKind.Sequential)] + public struct RtlProcessLocks + { + public int NumberOfLocks; + // RtlProcessLockInformation[] Locks + // Array of RtlProcessLockInformation structures follows. + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + public struct RtlProcessModuleInformation + { + public IntPtr Section; // empty + public IntPtr MappedBase; + public IntPtr ImageBase; + public int ImageSize; + public LdrpDataTableEntryFlags Flags; + public ushort LoadOrderIndex; + public ushort InitOrderIndex; + public ushort LoadCount; + public ushort OffsetToFileName; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] + public char[] FullPathName; + } + + [StructLayout(LayoutKind.Sequential)] + public struct RtlProcessModules + { + public static readonly int ModulesOffset = + Marshal.OffsetOf(typeof(RtlProcessModules), "Modules").ToInt32(); + + public int NumberOfModules; + public RtlProcessModuleInformation Modules; + // Array of RtlProcessModuleInformation structures follows. + } + + [StructLayout(LayoutKind.Sequential)] + public struct RtlUserProcessInformation + { + public int Length; + public IntPtr Process; + public IntPtr Thread; + public ClientId ClientId; + public SectionImageInformation ImageInformation; + } + + [StructLayout(LayoutKind.Sequential)] + public struct RtlUserProcessParameters + { + public static readonly int CurrentDirectoryOffset = + Marshal.OffsetOf(typeof(RtlUserProcessParameters), "CurrentDirectory").ToInt32(); + public static readonly int DllPathOffset = + Marshal.OffsetOf(typeof(RtlUserProcessParameters), "DllPath").ToInt32(); + public static readonly int ImagePathNameOffset = + Marshal.OffsetOf(typeof(RtlUserProcessParameters), "ImagePathName").ToInt32(); + public static readonly int CommandLineOffset = + Marshal.OffsetOf(typeof(RtlUserProcessParameters), "CommandLine").ToInt32(); + public static readonly int EnvironmentOffset = + Marshal.OffsetOf(typeof(RtlUserProcessParameters), "Environment").ToInt32(); + public static readonly int WindowTitleOffset = + Marshal.OffsetOf(typeof(RtlUserProcessParameters), "WindowTitle").ToInt32(); + public static readonly int DesktopInfoOffset = + Marshal.OffsetOf(typeof(RtlUserProcessParameters), "DesktopInfo").ToInt32(); + public static readonly int ShellInfoOffset = + Marshal.OffsetOf(typeof(RtlUserProcessParameters), "ShellInfo").ToInt32(); + public static readonly int RuntimeDataOffset = + Marshal.OffsetOf(typeof(RtlUserProcessParameters), "RuntimeData").ToInt32(); + public static readonly int CurrentDirectoriesOffset = + Marshal.OffsetOf(typeof(RtlUserProcessParameters), "CurrentDirectories").ToInt32(); + + public struct CurDir + { + public UnicodeString DosPath; + public IntPtr Handle; + } + + public struct RtlDriveLetterCurDir + { + public ushort Flags; + public ushort Length; + public uint TimeStamp; + public IntPtr DosPath; + } + + public int MaximumLength; + public int Length; + + public RtlUserProcessFlags Flags; + public int DebugFlags; + + public IntPtr ConsoleHandle; + public int ConsoleFlags; + public IntPtr StandardInput; + public IntPtr StandardOutput; + public IntPtr StandardError; + + public CurDir CurrentDirectory; + public UnicodeString DllPath; + public UnicodeString ImagePathName; + public UnicodeString CommandLine; + public IntPtr Environment; + + public int StartingX; + public int StartingY; + public int CountX; + public int CountY; + public int CountCharsX; + public int CountCharsY; + public int FillAttribute; + + public StartupFlags WindowFlags; + public int ShowWindowFlags; + public UnicodeString WindowTitle; + public UnicodeString DesktopInfo; + public UnicodeString ShellInfo; + public UnicodeString RuntimeData; + + //[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + //public RtlDriveLetterCurDir[] CurrentDirectories; + public RtlDriveLetterCurDir CurrentDirectories; + } + + [StructLayout(LayoutKind.Sequential)] + public struct SectionBasicInformation + { + public int Unknown; + public SectionAttributes SectionAttributes; + public long SectionSize; + } + + [StructLayout(LayoutKind.Sequential)] + public struct SectionImageInformation + { + public IntPtr TransferAddress; + public int StackZeroBits; + public IntPtr StackReserved; + public IntPtr StackCommit; + public int ImageSubsystem; + public short SubSystemVersionLow; + public short SubSystemVersionHigh; + public int GpValue; + public short ImageCharacteristics; + public short DllCharacteristics; + public int ImageMachineType; + [MarshalAs(UnmanagedType.I1)] + public bool ImageContainsCode; + [MarshalAs(UnmanagedType.I1)] + public bool Spare1; + public int LoaderFlags; + public int ImageFileSize; + public int Reserved; + } + + [StructLayout(LayoutKind.Sequential)] + public struct SecurityDescriptorStruct + { + public byte Revision; + public byte Sbz1; + public SecurityDescriptorControlFlags Control; + public IntPtr Owner; // Sid* + public IntPtr Group; // Sid* + public IntPtr Sacl; // Acl* + public IntPtr Dacl; // Acl* + } + + [StructLayout(LayoutKind.Sequential)] + public struct SecurityDescriptorRelativeStruct + { + public byte Revision; + public byte Sbz1; + public SecurityDescriptorControlFlags Control; + public int Owner; + public int Group; + public int Sacl; + public int Dacl; + } + + [StructLayout(LayoutKind.Sequential)] + public struct SecurityQualityOfService + { + public SecurityQualityOfService( + SecurityImpersonationLevel impersonationLevel, + bool dynamicTracking, + bool effectiveOnly + ) + { + this.Length = Marshal.SizeOf(typeof(SecurityQualityOfService)); + this.ImpersonationLevel = impersonationLevel; + this.ContextTrackingMode = dynamicTracking; + this.EffectiveOnly = effectiveOnly; + } + + public int Length; + public SecurityImpersonationLevel ImpersonationLevel; + [MarshalAs(UnmanagedType.I1)] + public bool ContextTrackingMode; // True for dynamic tracking, false for static tracking + [MarshalAs(UnmanagedType.I1)] + public bool EffectiveOnly; + } + + [StructLayout(LayoutKind.Sequential)] + public struct SemaphoreBasicInformation + { + public int CurrentCount; + public int MaximumCount; + } + + [StructLayout(LayoutKind.Sequential)] + public struct SidStruct + { + public byte Revision; + public byte SubAuthorityCount; + public SidIdentifierAuthority IdentifierAuthority; + + // Array of ULONG follows + } + + [StructLayout(LayoutKind.Sequential)] + public struct SidAndAttributes + { + public IntPtr Sid; // ptr to a SID object + public SidAttributes Attributes; + + public Sid ToSid() + { + return new Sid(this); + } + } + + [StructLayout(LayoutKind.Sequential)] + public struct SidIdentifierAuthority + { + public unsafe fixed byte Value[6]; + } + + [StructLayout(LayoutKind.Sequential)] + public struct SystemAlarmAceStruct + { + public AceHeader Header; + public int Mask; + public int SidStart; + } + + [StructLayout(LayoutKind.Sequential)] + public struct SystemAuditAceStruct + { + public AceHeader Header; + public int Mask; + public int SidStart; + } + + [StructLayout(LayoutKind.Sequential)] + public struct SystemBasicInformation + { + public int Reserved; + public int TimerResolution; + public int PageSize; + public int NumberOfPhysicalPages; + public int LowestPhysicalPageNumber; + public int HighestPhysicalPageNumber; + public int AllocationGranularity; + public IntPtr MinimumUserModeAddress; + public IntPtr MaximumUserModeAddress; + public IntPtr ActiveProcessorsAffinityMask; + public byte NumberOfProcessors; + } + + [StructLayout(LayoutKind.Sequential)] + public struct SystemCacheInformation + { + /// + /// The size of the system working set, in bytes. + /// + public IntPtr SystemCacheWsSize; + public IntPtr SystemCacheWsPeakSize; + public int SystemCacheWsFaults; + + /// + /// Measured in pages. + /// + public IntPtr SystemCacheWsMinimum; + + /// + /// Measured in pages. + /// + public IntPtr SystemCacheWsMaximum; + public IntPtr TransitionSharedPages; + public IntPtr TransitionSharedPagesPeak; + public int TransitionRePurposeCount; + public int Flags; + } + + [StructLayout(LayoutKind.Sequential)] + public struct SystemExtendedThreadInformation + { + public SystemThreadInformation ThreadInfo; + public IntPtr StackBase; // 16 + public IntPtr StackLimit; + public IntPtr Win32StartAddress; + public IntPtr TebAddress; // Vista+ + public IntPtr Unused1; + public IntPtr Unused2; + public IntPtr Unused3; + } + + [StructLayout(LayoutKind.Sequential)] + public struct SystemHandleEntry + { + public int ProcessId; + public byte ObjectTypeNumber; + public HandleFlags Flags; + public short Handle; + public IntPtr Object; + public int GrantedAccess; + } + + [StructLayout(LayoutKind.Sequential)] + public struct SystemHandleInformation + { + public static readonly int HandlesOffset = + Marshal.OffsetOf(typeof(SystemHandleInformation), "Handles").ToInt32(); + + public int NumberOfHandles; + public SystemHandleEntry Handles; + } + + [StructLayout(LayoutKind.Sequential)] + public struct SystemLoadAndCallImage + { + public UnicodeString ModuleName; + } + + [StructLayout(LayoutKind.Sequential)] + public struct SystemObjectInformation + { + public int NextEntryOffset; + public IntPtr Object; + public IntPtr CreatorUniqueProcess; + public ushort CreatorBackTraceIndex; + public ushort Flags; + public int PointerCount; + public int HandleCount; + public uint PagedPoolCharge; + public uint NonPagedPoolCharge; + public IntPtr ExclusiveProcessId; + public IntPtr SecurityDescriptor; + public ObjectNameInformation NameInfo; + } + + [StructLayout(LayoutKind.Sequential)] + public struct SystemObjectTypeInformation + { + public int NextEntryOffset; + public UnicodeString Name; + public int ObjectCount; + public int HandleCount; + public int TypeNumber; + public int InvalidAttributes; + public GenericMapping GenericMapping; + public int ValidAccessMask; + public PoolType PoolType; + } + + [StructLayout(LayoutKind.Sequential)] + public struct SystemPagefileInformation + { + public int NextEntryOffset; + public int TotalSize; + public int TotalInUse; + public int PeakUsage; + public UnicodeString PageFileName; + } + + [StructLayout(LayoutKind.Sequential)] + public struct SystemPerformanceInformation + { + /// + /// The total idle time of all processors in units of 100-nanoseconds. + /// + public long IdleProcessTime; + /// + /// Total bytes read by calls to NtReadFile. + /// + public long IoReadTransferCount; + /// + /// Total bytes written by calls to NtWriteFile. + /// + public long IoWriteTransferCount; + /// + /// Total bytes transferred by other I/O operations. + /// + public long IoOtherTransferCount; + /// + /// Number of calls to NtReadFile. + /// + public int IoReadOperationCount; + /// + /// Number of calls to NtWriteFile. + /// + public int IoWriteOperationCount; + /// + /// Number of calls to other I/O functions. + /// + public int IoOtherOperationCount; + /// + /// The number of pages of physical memory available. + /// + public int AvailablePages; + /// + /// The number of pages of committed virtual memory. + /// + public int CommittedPages; + /// + /// The number of pages of virtual memory that could be committed + /// without extending the system's pagefiles. + /// + public int CommitLimit; + /// + /// The peak number of pages of committed virtual memory. + /// + public int PeakCommitment; + /// + /// The total number of soft and hard page faults. + /// + public int PageFaultCount; + /// + /// The number of copy-on-write page faults. + /// + public int CopyOnWriteCount; + /// + /// The number of soft page faults. + /// + public int TransitionCount; + /// + /// Something that the Native API reference book doesn't have. + /// + public int CacheTransitionCount; + /// + /// The number of demand zero faults. + /// + public int DemandZeroCount; + /// + /// The number of pages read from disk to resolve page faults. + /// + public int PageReadCount; + /// + /// The number of read operations initiated to resolve page faults. + /// + public int PageReadIoCount; + public int CacheReadCount; + public int CacheIoCount; + /// + /// The number of pages written to the system's pagefiles. + /// + public int DirtyPagesWriteCount; + /// + /// The number of write operations performed on the system's pagefiles. + /// + public int DirtyWriteIoCount; + /// + /// The number of pages written to mapped files. + /// + public int MappedPagesWriteCount; + /// + /// The number of write operations performed on mapped files. + /// + public int MappedWriteIoCount; + /// + /// The number of pages used by the paged pool. + /// + public int PagedPoolPages; + /// + /// The number of pages used by the non-paged pool. + /// + public int NonPagedPoolPages; + /// + /// The number of allocations made from the paged pool. + /// + public int PagedPoolAllocs; + /// + /// The number of allocations returned to the paged pool. + /// + public int PagedPoolFrees; + /// + /// The number of allocations made from the non-paged pool. + /// + public int NonPagedPoolAllocs; + /// + /// The number of allocations returned to the non-paged pool. + /// + public int NonPagedPoolFrees; + /// + /// The number of available System Page Table Entries. + /// + public int FreeSystemPtes; + /// + /// The number of pages of pageable OS code and data in physical + /// memory. + /// + public int ResidentSystemCodePage; + /// + /// The number of pages of pageable driver code and data. + /// + public int TotalSystemDriverPages; + /// + /// The number of pages of OS driver code and data. + /// + public int TotalSystemCodePages; + /// + /// The number of times an allocation could be statisfied by one of the + /// small non-paged lookaside lists. + /// + public int NonPagedPoolLookasideHits; + /// + /// The number of times an allocation could be statisfied by one of the + /// small paged lookaside lists. + /// + public int PagedPoolLookasideHits; + /// + /// The number of pages available for use by the paged pool. + /// + public int AvailablePagedPoolPages; + /// + /// The number of pages of the system cache in physical memory. + /// + public int ResidentSystemCachePage; + /// + /// The number of pages of the paged pool in physical memory. + /// + public int ResidentPagedPoolPage; + /// + /// The number of pages of pageable driver code and data in physical memory. + /// + public int ResidentSystemDriverPage; + /// + /// The number of asynchronous fast read operations. + /// + public int CcFastReadNoWait; + /// + /// The number of synchronous fast read operations. + /// + public int CcFastReadWait; + /// + /// The number of fast read operations not possible because of resource + /// conflicts. + /// + public int CcFastReadResourceMiss; + public int CcFastReadNotPossible; + public int CcFastMdlReadNoWait; + public int CcFastMdlReadWait; + public int CcFastMdlReadResourceMiss; + public int CcFastMdlReadNotPossible; + public int CcMapDataNoWait; + public int CcMapDataWait; + public int CcMapDataNoWaitMiss; + public int CcMapDataWaitMiss; + public int CcPinMappedDataCount; + public int CcPinReadNoWait; + public int CcPinReadWait; + public int CcPinReadNoWaitMiss; + public int CcPinReadWaitMiss; + public int CcCopyReadNoWait; + public int CcCopyReadWait; + public int CcCopyReadNoWaitMiss; + public int CcCopyReadWaitMiss; + public int CcMdlReadNoWait; + public int CcMdlReadWait; + public int CcMdlReadNoWaitMiss; + public int CcMdlReadWaitMiss; + public int CcReadAheadIos; + public int CcLazyWriteIos; + public int CcLazyWritePages; + public int CcDataFlushes; + public int CcDataPages; + public int ContextSwitches; + public int FirstLevelTbFills; + public int SecondLevelTbFills; + public int SystemCalls; + } + + [StructLayout(LayoutKind.Sequential)] + public struct SystemProcessInformation + { + public int NextEntryOffset; + public int NumberOfThreads; + public long SpareLi1; + public long SpareLi2; + public long SpareLi3; + public long CreateTime; // 8 + public long UserTime; + public long KernelTime; + public UnicodeString ImageName; + public int BasePriority; + private IntPtr _processId; + private IntPtr _inheritedFromProcessId; + public int HandleCount; + public int SessionId; + public IntPtr PageDirectoryBase; + public VmCountersEx VirtualMemoryCounters; + public IoCounters IoCounters; + + public int ProcessId + { + get { return _processId.ToInt32(); } + set { _processId = value.ToIntPtr(); } + } + + public int InheritedFromProcessId + { + get { return _inheritedFromProcessId.ToInt32(); } + set { _inheritedFromProcessId = value.ToIntPtr(); } + } + } + + [StructLayout(LayoutKind.Sequential)] + public struct SystemProcessorPerformanceInformation + { + public long IdleTime; + public long KernelTime; + public long UserTime; + public long DpcTime; + public long InterruptTime; + public int InterruptCount; + } + + [StructLayout(LayoutKind.Sequential)] + public struct SystemSessionProcessInformation + { + public int SessionId; + public int BufferLength; + public IntPtr Buffer; + } + + [StructLayout(LayoutKind.Sequential)] + public struct SystemThreadInformation + { + public long KernelTime; + public long UserTime; + public long CreateTime; + public int WaitTime; + public IntPtr StartAddress; + public ClientId ClientId; + public int Priority; + public int BasePriority; + public int ContextSwitchCount; // 12 + public int State; // 13 + public KWaitReason WaitReason; // 14 + } + + [StructLayout(LayoutKind.Sequential)] + public struct SystemTimeOfDayInformation + { + public long BootTime; + public long CurrentTime; + public long TimeZoneBias; + public int TimeZoneId; + public int Reserved; + public long BootTimeBias; + public long SleepTimeBias; + } + + [StructLayout(LayoutKind.Sequential)] + public unsafe struct Teb + { + public NtTib NtTib; + public IntPtr EnvironmentPointer; + public ClientId ClientId; + public IntPtr ActiveRpcHandle; + public IntPtr ThreadLocalStoragePointer; + public IntPtr ProcessEnvironmentBlock; // Peb* + public Win32Error LastErrorValue; + public int CountOfOwnedCriticalSections; + public IntPtr CsrClientThread; + public IntPtr Win32ThreadInfo; + public fixed int User32Reserved[26]; + public fixed int UserReserved[5]; + public IntPtr Wow32Reserved; + public int CurrentLocale; + public int FpSoftwareStatusRegister; + // Variable size part follows + } + + [StructLayout(LayoutKind.Sequential)] + public struct ThreadBasicInformation + { + public NtStatus ExitStatus; + public IntPtr TebBaseAddress; + public ClientId ClientId; + public IntPtr AffinityMask; + public int Priority; + public int BasePriority; + } + + [StructLayout(LayoutKind.Sequential)] + public struct TimerBasicInformation + { + public LargeInteger RemainingTime; + [MarshalAs(UnmanagedType.I1)] + public bool TimerState; + } + + [StructLayout(LayoutKind.Sequential)] + public struct TmBasicInformation + { + public Guid TmIdentity; + public long VirtualClock; + } + + [StructLayout(LayoutKind.Sequential)] + public struct TmLogInformation + { + public Guid LogIdentity; + } + + [StructLayout(LayoutKind.Sequential)] + public struct TmLogPathInformation + { + public static readonly int LogPathOffset = Marshal.OffsetOf(typeof(TmLogPathInformation), "LogPath").ToInt32(); + + /// + /// The length, in characters, of the log path string. + /// + public int LogPathLength; + + /// + /// The first byte of the log path string. + /// + public short LogPath; // wchar[] + // Log path follows. + } + + [StructLayout(LayoutKind.Sequential)] + public struct TmRecoveryInformation + { + public long LastRecoveredLsn; + } + + [StructLayout(LayoutKind.Sequential)] + public struct TokenDefaultDacl + { + public TokenDefaultDacl(Acl defaultDacl) + { + this.DefaultDacl = defaultDacl ?? IntPtr.Zero; + } + + public IntPtr DefaultDacl; // Acl* + } + + [StructLayout(LayoutKind.Sequential)] + public struct TokenGroups + { + public static readonly int GroupsOffset = + Marshal.OffsetOf(typeof(TokenGroups), "Groups").ToInt32(); + + public TokenGroups(Sid[] sids) + { + this.GroupCount = sids.Length; + this.Groups = new SidAndAttributes[sids.Length]; + + for (int i = 0; i < sids.Length; i++) + this.Groups[i] = sids[i].ToSidAndAttributes(); + } + + public int GroupCount; + + [MarshalAs(UnmanagedType.ByValArray)] + public SidAndAttributes[] Groups; + } + + [StructLayout(LayoutKind.Sequential)] + public struct TokenOwner + { + public TokenOwner(Sid owner) + { + this.Owner = owner ?? IntPtr.Zero; + } + + public IntPtr Owner; + } + + [StructLayout(LayoutKind.Sequential)] + public struct TokenPrimaryGroup + { + public TokenPrimaryGroup(Sid primaryGroup) + { + this.PrimaryGroup = primaryGroup ?? IntPtr.Zero; + } + + public IntPtr PrimaryGroup; + } + + [StructLayout(LayoutKind.Sequential)] + public struct TokenPrivileges + { + public TokenPrivileges(PrivilegeSet privileges) + { + this = privileges.ToTokenPrivileges(); + } + + public int PrivilegeCount; + + [MarshalAs(UnmanagedType.ByValArray)] + public LuidAndAttributes[] Privileges; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + public struct TokenSource + { + public TokenSource(string sourceName, Luid sourceIdentifier) + { + if (sourceName.Length > 8) + throw new ArgumentException("Source name must be equal to or less than 8 characters long."); + + this.SourceName = sourceName; + this.SourceIdentifier = sourceIdentifier; + } + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)] + public string SourceName; + + public Luid SourceIdentifier; + } + + [StructLayout(LayoutKind.Sequential)] + public struct TokenStatistics + { + public Luid TokenId; + public Luid AuthenticationId; + public long ExpirationTime; + public TokenType TokenType; + public SecurityImpersonationLevel ImpersonationLevel; + public int DynamicCharged; + public int DynamicAvailable; + public int GroupCount; + public int PrivilegeCount; + public Luid ModifiedId; + } + + [StructLayout(LayoutKind.Sequential)] + public struct TokenUser + { + public TokenUser(Sid user) + { + this.User = user.ToSidAndAttributes(); + } + + public SidAndAttributes User; + } + + [StructLayout(LayoutKind.Sequential)] + public struct TransactionBasicInformation + { + public Guid TransactionId; + public TransactionState State; + public TransactionOutcome Outcome; + } + + [StructLayout(LayoutKind.Sequential)] + public struct TransactionEnlistmentPair + { + public Guid EnlistmentId; + public Guid ResourceManagerId; + } + + [StructLayout(LayoutKind.Sequential)] + public struct TransactionEnlistmentsInformation + { + public int NumberOfEnlistments; + public byte EnlistmentPair; // TransactionEnlistmentPair[] + // Array of TransactionEnlistmentPair structures follows. + } + + [StructLayout(LayoutKind.Sequential)] + public struct TransactionNotification + { + public IntPtr TransactionKey; + public NotificationMask Notification; // Original name: TransactionNotification + public long TmVirtualClock; + public int ArgumentLength; + } + + [StructLayout(LayoutKind.Sequential)] + public struct TransactionPropertiesInformation + { + public static readonly int DescriptionOffset = + Marshal.OffsetOf(typeof(TransactionPropertiesInformation), "Description").ToInt32(); + + public int IsolationLevel; + public int IsolationFlags; + public long Timeout; + public TransactionOutcome Outcome; + + /// + /// The length, in bytes, of the description string. + /// + public int DescriptionLength; + + /// + /// The first byte of the description string. + /// + public byte Description; // wchar[] + // Description string follows. + } + + [StructLayout(LayoutKind.Sequential)] + public struct UnicodeString : IComparable, IEquatable, IDisposable + { + public UnicodeString(string str) + { + if (str != null) + { + UnicodeString newString; + + if (!Win32.RtlCreateUnicodeString(out newString, str)) + throw new OutOfMemoryException(); + + this = newString; + } + else + { + this.Length = 0; + this.MaximumLength = 0; + this.Buffer = IntPtr.Zero; + } + } + + public ushort Length; + public ushort MaximumLength; + public IntPtr Buffer; + + public int CompareTo(UnicodeString unicodeString, bool caseInsensitive) + { + return Win32.RtlCompareUnicodeString(ref this, ref unicodeString, caseInsensitive); + } + + public int CompareTo(UnicodeString unicodeString) + { + return this.CompareTo(unicodeString, false); + } + + public void Dispose() + { + if (this.Buffer == IntPtr.Zero) + return; + + Win32.RtlFreeUnicodeString(ref this); + this.Buffer = IntPtr.Zero; + } + + /// + /// Copies the string to a newly allocated string. + /// + public UnicodeString Duplicate() + { + NtStatus status; + UnicodeString newString; + + if ((status = Win32.RtlDuplicateUnicodeString( + RtlDuplicateUnicodeStringFlags.AllocateNullString | + RtlDuplicateUnicodeStringFlags.NullTerminate, + ref this, out newString)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return newString; + } + + public bool Equals(UnicodeString unicodeString, bool caseInsensitive) + { + return Win32.RtlEqualUnicodeString(ref this, ref unicodeString, caseInsensitive); + } + + public bool Equals(UnicodeString unicodeString) + { + return this.Equals(unicodeString, false); + } + + public override int GetHashCode() + { + return this.Hash(); + } + + public int Hash(HashStringAlgorithm algorithm, bool caseInsensitive) + { + NtStatus status; + int hash; + + if ((status = Win32.RtlHashUnicodeString(ref this, + caseInsensitive, algorithm, out hash)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return hash; + } + + public int Hash(HashStringAlgorithm algorithm) + { + return this.Hash(algorithm, false); + } + + public int Hash() + { + return this.Hash(HashStringAlgorithm.Default); + } + + public string Read() + { + if (this.Length == 0) + return ""; + + return Marshal.PtrToStringUni(this.Buffer, this.Length / 2); + } + + public string Read(ProcessHandle processHandle) + { + if (this.Length == 0) + return ""; + + byte[] strData = processHandle.ReadMemory(this.Buffer, this.Length); + GCHandle strDataHandle = GCHandle.Alloc(strData, GCHandleType.Pinned); + + try + { + return Marshal.PtrToStringUni(strDataHandle.AddrOfPinnedObject(), this.Length / 2); + } + finally + { + strDataHandle.Free(); + } + } + + public bool StartsWith(UnicodeString unicodeString, bool caseInsensitive) + { + return Win32.RtlPrefixUnicodeString(ref this, ref unicodeString, caseInsensitive); + } + + public bool StartsWith(UnicodeString unicodeString) + { + return this.StartsWith(unicodeString, false); + } + + public AnsiString ToAnsiString() + { + NtStatus status; + AnsiString ansiStr = new AnsiString(); + + if ((status = Win32.RtlUnicodeStringToAnsiString(ref ansiStr, ref this, true)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return ansiStr; + } + + public override string ToString() + { + return this.Read(); + } + + public AnsiString ToUpperAnsiString() + { + NtStatus status; + AnsiString ansiStr = new AnsiString(); + + if ((status = Win32.RtlUpcaseUnicodeStringToAnsiString(ref ansiStr, ref this, true)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return ansiStr; + } + } + + [StructLayout(LayoutKind.Sequential)] + public struct VmCounters + { + public IntPtr PeakVirtualSize; + public IntPtr VirtualSize; + public int PageFaultCount; + public IntPtr PeakWorkingSetSize; + public IntPtr WorkingSetSize; + public IntPtr QuotaPeakPagedPoolUsage; + public IntPtr QuotaPagedPoolUsage; + public IntPtr QuotaPeakNonPagedPoolUsage; + public IntPtr QuotaNonPagedPoolUsage; + public IntPtr PagefileUsage; + public IntPtr PeakPagefileUsage; + } + + [StructLayout(LayoutKind.Sequential)] + public struct VmCountersEx + { + public IntPtr PeakVirtualSize; + public IntPtr VirtualSize; + public int PageFaultCount; + public IntPtr PeakWorkingSetSize; + public IntPtr WorkingSetSize; + public IntPtr QuotaPeakPagedPoolUsage; + public IntPtr QuotaPagedPoolUsage; + public IntPtr QuotaPeakNonPagedPoolUsage; + public IntPtr QuotaNonPagedPoolUsage; + public IntPtr PagefileUsage; + public IntPtr PeakPagefileUsage; + public IntPtr PrivatePageCount; + } + + [StructLayout(LayoutKind.Sequential)] + public struct XmmSaveArea32 + { + public ushort ControlWord; + public ushort StatusWord; + public byte TagWord; + public byte Reserved1; + public ushort ErrorOpcode; + public int ErrorOffset; + public ushort ErrorSelector; + public ushort Reserved2; + public int DataOffset; + public ushort DataSelector; + public ushort Reserved3; + public int MxCsr; + public int MxCsrMask; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public M128A[] FloatRegisters; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public M128A[] XmmRegisters; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 96)] + public byte[] Reserved4; + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Api/NtStatus.cs b/branches/ph-plugins/ProcessHacker.Native/Api/NtStatus.cs new file mode 100644 index 000000000..1e3aa3de3 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Api/NtStatus.cs @@ -0,0 +1,379 @@ +/* + * Process Hacker - + * NT status values + * + * Copyright (C) 2009 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 . + */ + +namespace ProcessHacker.Native.Api +{ + /// + /// A NT status value. + /// + public enum NtStatus : uint + { + // Success + Success = 0x00000000, + Wait0 = 0x00000000, + Wait1 = 0x00000001, + Wait2 = 0x00000002, + Wait3 = 0x00000003, + Wait63 = 0x0000003f, + Abandoned = 0x00000080, + AbandonedWait0 = 0x00000080, + AbandonedWait1 = 0x00000081, + AbandonedWait2 = 0x00000082, + AbandonedWait3 = 0x00000083, + AbandonedWait63 = 0x000000bf, + UserApc = 0x000000c0, + KernelApc = 0x00000100, + Alerted = 0x00000101, + Timeout = 0x00000102, + Pending = 0x00000103, + Reparse = 0x00000104, + MoreEntries = 0x00000105, + NotAllAssigned = 0x00000106, + SomeNotMapped = 0x00000107, + OpLockBreakInProgress = 0x00000108, + VolumeMounted = 0x00000109, + RxActCommitted = 0x0000010a, + NotifyCleanup = 0x0000010b, + NotifyEnumDir = 0x0000010c, + NoQuotasForAccount = 0x0000010d, + PrimaryTransportConnectFailed = 0x0000010e, + PageFaultTransition = 0x00000110, + PageFaultDemandZero = 0x00000111, + PageFaultCopyOnWrite = 0x00000112, + PageFaultGuardPage = 0x00000113, + PageFaultPagingFile = 0x00000114, + CrashDump = 0x00000116, + ReparseObject = 0x00000118, + NothingToTerminate = 0x00000122, + ProcessNotInJob = 0x00000123, + ProcessInJob = 0x00000124, + ProcessCloned = 0x00000129, + FileLockedWithOnlyReaders = 0x0000012a, + FileLockedWithWriters = 0x0000012b, + + // Informational + Informational = 0x40000000, + ObjectNameExists = 0x40000000, + ThreadWasSuspended = 0x40000001, + WorkingSetLimitRange = 0x40000002, + ImageNotAtBase = 0x40000003, + RegistryRecovered = 0x40000009, + + // Warning + Warning = 0x80000000, + GuardPageViolation = 0x80000001, + DatatypeMisalignment = 0x80000002, + Breakpoint = 0x80000003, + SingleStep = 0x80000004, + BufferOverflow = 0x80000005, + NoMoreFiles = 0x80000006, + HandlesClosed = 0x8000000a, + PartialCopy = 0x8000000d, + DeviceBusy = 0x80000011, + InvalidEaName = 0x80000013, + EaListInconsistent = 0x80000014, + NoMoreEntries = 0x8000001a, + LongJump = 0x80000026, + DllMightBeInsecure = 0x8000002b, + + // Error + Error = 0xc0000000, + Unsuccessful = 0xc0000001, + NotImplemented = 0xc0000002, + InvalidInfoClass = 0xc0000003, + InfoLengthMismatch = 0xc0000004, + AccessViolation = 0xc0000005, + InPageError = 0xc0000006, + PagefileQuota = 0xc0000007, + InvalidHandle = 0xc0000008, + BadInitialStack = 0xc0000009, + BadInitialPc = 0xc000000a, + InvalidCid = 0xc000000b, + TimerNotCanceled = 0xc000000c, + InvalidParameter = 0xc000000d, + NoSuchDevice = 0xc000000e, + NoSuchFile = 0xc000000f, + InvalidDeviceRequest = 0xc0000010, + EndOfFile = 0xc0000011, + WrongVolume = 0xc0000012, + NoMediaInDevice = 0xc0000013, + NoMemory = 0xc0000017, + NotMappedView = 0xc0000019, + UnableToFreeVm = 0xc000001a, + UnableToDeleteSection = 0xc000001b, + IllegalInstruction = 0xc000001d, + AlreadyCommitted = 0xc0000021, + AccessDenied = 0xc0000022, + BufferTooSmall = 0xc0000023, + ObjectTypeMismatch = 0xc0000024, + NonContinuableException = 0xc0000025, + BadStack = 0xc0000028, + NotLocked = 0xc000002a, + NotCommitted = 0xc000002d, + InvalidParameterMix = 0xc0000030, + ObjectNameInvalid = 0xc0000033, + ObjectNameNotFound = 0xc0000034, + ObjectNameCollision = 0xc0000035, + ObjectPathInvalid = 0xc0000039, + ObjectPathNotFound = 0xc000003a, + ObjectPathSyntaxBad = 0xc000003b, + DataOverrun = 0xc000003c, + DataLate = 0xc000003d, + DataError = 0xc000003e, + CrcError = 0xc000003f, + SectionTooBig = 0xc0000040, + PortConnectionRefused = 0xc0000041, + InvalidPortHandle = 0xc0000042, + SharingViolation = 0xc0000043, + QuotaExceeded = 0xc0000044, + InvalidPageProtection = 0xc0000045, + MutantNotOwned = 0xc0000046, + SemaphoreLimitExceeded = 0xc0000047, + PortAlreadySet = 0xc0000048, + SectionNotImage = 0xc0000049, + SuspendCountExceeded = 0xc000004a, + ThreadIsTerminating = 0xc000004b, + BadWorkingSetLimit = 0xc000004c, + IncompatibleFileMap = 0xc000004d, + SectionProtection = 0xc000004e, + EasNotSupported = 0xc000004f, + EaTooLarge = 0xc0000050, + NonExistentEaEntry = 0xc0000051, + NoEasOnFile = 0xc0000052, + EaCorruptError = 0xc0000053, + FileLockConflict = 0xc0000054, + LockNotGranted = 0xc0000055, + DeletePending = 0xc0000056, + CtlFileNotSupported = 0xc0000057, + UnknownRevision = 0xc0000058, + RevisionMismatch = 0xc0000059, + InvalidOwner = 0xc000005a, + InvalidPrimaryGroup = 0xc000005b, + NoImpersonationToken = 0xc000005c, + CantDisableMandatory = 0xc000005d, + NoLogonServers = 0xc000005e, + NoSuchLogonSession = 0xc000005f, + NoSuchPrivilege = 0xc0000060, + PrivilegeNotHeld = 0xc0000061, + InvalidAccountName = 0xc0000062, + UserExists = 0xc0000063, + NoSuchUser = 0xc0000064, + GroupExists = 0xc0000065, + NoSuchGroup = 0xc0000066, + MemberInGroup = 0xc0000067, + MemberNotInGroup = 0xc0000068, + LastAdmin = 0xc0000069, + WrongPassword = 0xc000006a, + IllFormedPassword = 0xc000006b, + PasswordRestriction = 0xc000006c, + LogonFailure = 0xc000006d, + AccountRestriction = 0xc000006e, + InvalidLogonHours = 0xc000006f, + InvalidWorkstation = 0xc0000070, + PasswordExpired = 0xc0000071, + AccountDisabled = 0xc0000072, + FileInvalid = 0xc0000098, + InstanceNotAvailable = 0xc00000ab, + PipeNotAvailable = 0xc00000ac, + InvalidPipeState = 0xc00000ad, + PipeBusy = 0xc00000ae, + IllegalFunction = 0xc00000af, + PipeDisconnected = 0xc00000b0, + PipeClosing = 0xc00000b1, + PipeConnected = 0xc00000b2, + PipeListening = 0xc00000b3, + InvalidReadMode = 0xc00000b4, + IoTimeout = 0xc00000b5, + FileForcedClosed = 0xc00000b6, + ProfilingNotStarted = 0xc00000b7, + ProfilingNotStopped = 0xc00000b8, + NotSameDevice = 0xc00000d4, + FileRenamed = 0xc00000d5, + CantWait = 0xc00000d8, + PipeEmpty = 0xc00000d9, + CantTerminateSelf = 0xc00000db, + InternalError = 0xc00000e5, + InvalidParameter1 = 0xc00000ef, + InvalidParameter2 = 0xc00000f0, + InvalidParameter3 = 0xc00000f1, + InvalidParameter4 = 0xc00000f2, + InvalidParameter5 = 0xc00000f3, + InvalidParameter6 = 0xc00000f4, + InvalidParameter7 = 0xc00000f5, + InvalidParameter8 = 0xc00000f6, + InvalidParameter9 = 0xc00000f7, + InvalidParameter10 = 0xc00000f8, + InvalidParameter11 = 0xc00000f9, + InvalidParameter12 = 0xc00000fa, + MappedFileSizeZero = 0xc000011e, + TooManyOpenedFiles = 0xc000011f, + Cancelled = 0xc0000120, + CannotDelete = 0xc0000121, + InvalidComputerName = 0xc0000122, + FileDeleted = 0xc0000123, + SpecialAccount = 0xc0000124, + SpecialGroup = 0xc0000125, + SpecialUser = 0xc0000126, + MembersPrimaryGroup = 0xc0000127, + FileClosed = 0xc0000128, + TooManyThreads = 0xc0000129, + ThreadNotInProcess = 0xc000012a, + TokenAlreadyInUse = 0xc000012b, + PagefileQuotaExceeded = 0xc000012c, + CommitmentLimit = 0xc000012d, + InvalidImageLeFormat = 0xc000012e, + InvalidImageNotMz = 0xc000012f, + InvalidImageProtect = 0xc0000130, + InvalidImageWin16 = 0xc0000131, + LogonServer = 0xc0000132, + DifferenceAtDc = 0xc0000133, + SynchronizationRequired = 0xc0000134, + DllNotFound = 0xc0000135, + IoPrivilegeFailed = 0xc0000137, + OrdinalNotFound = 0xc0000138, + EntryPointNotFound = 0xc0000139, + ControlCExit = 0xc000013a, + PortNotSet = 0xc0000353, + DebuggerInactive = 0xc0000354, + CallbackBypass = 0xc0000503, + PortClosed = 0xc0000700, + MessageLost = 0xc0000701, + InvalidMessage = 0xc0000702, + RequestCanceled = 0xc0000703, + RecursiveDispatch = 0xc0000704, + LpcReceiveBufferExpected = 0xc0000705, + LpcInvalidConnectionUsage = 0xc0000706, + LpcRequestsNotAllowed = 0xc0000707, + ResourceInUse = 0xc0000708, + ProcessIsProtected = 0xc0000712, + VolumeDirty = 0xc0000806, + FileCheckedOut = 0xc0000901, + CheckOutRequired = 0xc0000902, + BadFileType = 0xc0000903, + FileTooLarge = 0xc0000904, + FormsAuthRequired = 0xc0000905, + VirusInfected = 0xc0000906, + VirusDeleted = 0xc0000907, + + MaximumNtStatus = 0xffffffff + } + + public static class NtStatusExtensions + { + /// + /// Gets a string which describes the NT status value. + /// + /// The NT status value. + /// A message, or null if the message could not be retrieved. + public static string GetMessage(this NtStatus status) + { + string message; + + message = NativeUtils.GetMessage( + Loader.GetDllHandle("ntdll.dll"), + 0xb, + System.Threading.Thread.CurrentThread.CurrentUICulture.LCID, + (int)status + ); + + if (message != null) + { + // Fix those messages which are formatted like: + // {Asdf}\r\nAsdf asdf asdf... + if (message.StartsWith("{")) + { + string[] split = message.Split('\n'); + + if (split.Length > 1) + message = split[1]; + } + } + + return message; + } + + /// + /// Gets whether the NT status value indicates an error. + /// + /// The NT status value. + public static bool IsError(this NtStatus status) + { + return status >= NtStatus.Error && status <= NtStatus.MaximumNtStatus; + } + + /// + /// Gets whether the NT status value indicates information. + /// + /// The NT status value. + public static bool IsInformational(this NtStatus status) + { + return status >= NtStatus.Informational && status < NtStatus.Warning; + } + + /// + /// Gets whether the NT status value indicates success. + /// + /// The NT status value. + public static bool IsSuccess(this NtStatus status) + { + return status >= NtStatus.Success && status < NtStatus.Informational; + } + + /// + /// Gets whether the NT status value indicates a warning. + /// + /// The NT status value. + public static bool IsWarning(this NtStatus status) + { + return status >= NtStatus.Warning && status < NtStatus.Error; + } + + /// + /// Throws the NT status value as an exception. + /// + /// The NT status value. + public static void Throw(this NtStatus status) + { + throw new WindowsException(status); + } + + /// + /// Throws the NT status value as an exception if it is an error or warning. + /// + /// The NT status value. + public static void ThrowIf(this NtStatus status) + { + if (status.IsError() || status.IsWarning()) + status.Throw(); + } + + /// + /// Converts the NT status value to a DOS/Windows error code. + /// + /// The NT status value. + /// A DOS/Windows error code. + public static Win32Error ToDosError(this NtStatus status) + { + return Win32.RtlNtStatusToDosError(status); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Api/Structs.cs b/branches/ph-plugins/ProcessHacker.Native/Api/Structs.cs new file mode 100644 index 000000000..c644a958e --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Api/Structs.cs @@ -0,0 +1,834 @@ +/* + * Process Hacker - + * windows API structs + * + * Copyright (C) 2009 Uday Shanbhag + * Copyright (C) 2009 Dean + * Copyright (C) 2008-2009 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 file contains structure declarations for the Win32 API. + * + * All structures which do not belong in any other category + * are placed in this file. + */ + +using System; +using System.Drawing; +using System.Runtime.InteropServices; +using ProcessHacker.Native.Objects; + +namespace ProcessHacker.Native.Api +{ + [StructLayout(LayoutKind.Sequential)] + public struct Address64 + { + public ulong Offset; + public ushort Segment; + public AddressMode Mode; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + public struct CatalogInfo + { + public int Size; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public string CatalogFile; + } + + [StructLayout(LayoutKind.Sequential)] + public struct EnumServiceStatus + { + [MarshalAs(UnmanagedType.LPTStr)] + public string ServiceName; + + [MarshalAs(UnmanagedType.LPTStr)] + public string DisplayName; + + [MarshalAs(UnmanagedType.Struct)] + public ServiceStatus ServiceStatus; + } + + [StructLayout(LayoutKind.Sequential)] + public struct EnumServiceStatusProcess + { + [MarshalAs(UnmanagedType.LPTStr)] + public string ServiceName; + + [MarshalAs(UnmanagedType.LPTStr)] + public string DisplayName; + + [MarshalAs(UnmanagedType.Struct)] + public ServiceStatusProcess ServiceStatusProcess; + } + + [StructLayout(LayoutKind.Sequential)] + public struct FpoData + { + public int ulOffStart; + public int cbProcSize; + public int cdwLocals; + public short cdwParams; + + public long Part1; + public long Part2; + } + + [StructLayout(LayoutKind.Sequential)] + public struct HeapEntry32 + { + public int dwSize; + public IntPtr hHandle; + public IntPtr dwAddress; + public int dwBlockSize; + public HeapEntry32Flags dwFlags; + public int dwLockCount; + public int dwResvd; + public int th32ProcessID; + public int th32HeapID; + } + + [StructLayout(LayoutKind.Sequential)] + public struct HeapList32 + { + public int dwSize; + public int th32ProcessID; + public IntPtr th32HeapID; + public int dwFlags; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + public struct ImagehlpLine64 + { + public int SizeOfStruct; + public int Key; + public int LineNumber; + public string FileName; + public long Address; + } + + [StructLayout(LayoutKind.Explicit)] + public struct INet6Address + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + [FieldOffset(0)] + public byte[] Bytes; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + [FieldOffset(0)] + public ushort[] Words; + } + + [StructLayout(LayoutKind.Sequential)] + public struct KdHelp64 + { + public long Thread; + public int ThCallbackStack; + public int ThCallbackBSTore; + public int NextCallback; + public int FramePointer; + public long KiCallUserMode; + public long KeUserCallbackDispatcher; + public long SystemRangeStart; + public long KiUserExceptionDispatcher; + public long StackBase; + public long StackLimit; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)] + public long[] Reserved; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + public struct LoadedImage + { + public IntPtr ModuleName; + public IntPtr FileHandle; + public IntPtr MappedAddress; + public IntPtr FileHeader; // ImageNtHeaders32* + public IntPtr LastRvaSection; // ImageSectionHeader* + public int NumberOfSections; + public IntPtr Sections; // ImageSectionHeader* + public int Characteristics; + [MarshalAs(UnmanagedType.U1)] + public bool SystemImage; + [MarshalAs(UnmanagedType.U1)] + public bool DosImage; + [MarshalAs(UnmanagedType.U1)] + public bool ReadOnly; + public byte Version; + public ListEntry Links; + public int SizeOfImage; + } + + [StructLayout(LayoutKind.Sequential)] + public struct LuidAndAttributes + { + public Luid Luid; + public SePrivilegeAttributes Attributes; + } + + [StructLayout(LayoutKind.Sequential)] + public struct MemoryBasicInformation + { + public IntPtr BaseAddress; + public IntPtr AllocationBase; + public MemoryProtection AllocationProtect; + public IntPtr RegionSize; + public MemoryState State; + public MemoryProtection Protect; + public MemoryType Type; + } + + [StructLayout(LayoutKind.Sequential, Pack = 16)] + public struct MemoryBasicInformation64 + { + public IntPtr BaseAddress; + public IntPtr AllocationBase; + public MemoryProtection AllocationProtect; + private int _alignment1; + public ulong RegionSize; + public MemoryState State; + public MemoryProtection Protect; + public MemoryType Type; + private int _alignment2; + } + + [StructLayout(LayoutKind.Sequential)] + public struct MibTcpRow + { + public MibTcpState State; + public uint LocalAddress; + public int LocalPort; + public uint RemoteAddress; + public int RemotePort; + } + + [StructLayout(LayoutKind.Sequential)] + public struct MibTcp6Row + { + public MibTcpState State; + public uint LocalAddress; + public uint LocalScopeId; + public int LocalPort; + public uint RemoteAddr; + public int RemoteScopeId; + public int RemotePort; + } + + [StructLayout(LayoutKind.Sequential)] + public struct MibTcp6Row2 + { + public INet6Address LocalAddr; + public uint LocalScopeId; + public int LocalPort; + public INet6Address RemoteAddr; + public uint RemoteScopeId; + public int RemotePort; + public MibTcpState State; + public int OwningPid; + public TcpConnectionOffloadState OffloadState; + } + + [StructLayout(LayoutKind.Sequential)] + public struct MibTcpRowOwnerPid + { + public MibTcpState State; + public uint LocalAddress; + public int LocalPort; + public uint RemoteAddress; + public int RemotePort; + public int OwningProcessId; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + public struct MibTcp6RowOwnerPid + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] LocalAddress; + public uint LocalScopeId; + public int LocalPort; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] RemoteAddress; + public uint RemoteScopeId; + public int RemotePort; + public MibTcpState State; + public int OwningProcessId; + } + + [StructLayout(LayoutKind.Sequential)] + public struct MibTcpStats + { + public uint RtoAlgorithm; + public uint RtoMin; + public uint RtoMax; + public uint MaxConn; + public uint ActiveOpens; + public uint PassiveOpens; + public uint AttemptFails; + public uint EstabResets; + public uint CurrEstab; + public uint InSegs; + public uint OutSegs; + public uint RetransSegs; + public uint InErrs; + public uint OutRsts; + public uint NumConns; + } + + [StructLayout(LayoutKind.Sequential)] + public struct MibTcpTable + { + public int NumEntries; + public MibTcpRow[] Table; + } + + [StructLayout(LayoutKind.Sequential)] + public struct MibTcp6Table + { + public int NumEntries; + public MibTcp6Row[] Table; + } + + [StructLayout(LayoutKind.Sequential)] + public struct MibTcpTableOwnerPid + { + public int NumEntries; + public MibTcpRowOwnerPid[] Table; + } + + [StructLayout(LayoutKind.Sequential)] + public struct MibTcp6TableOwnerPid + { + public int NumEntries; + public MibTcp6RowOwnerPid[] Table; + } + + [StructLayout(LayoutKind.Sequential)] + public struct MibUdpRow + { + public uint LocalAddress; + public int LocalPort; + } + + [StructLayout(LayoutKind.Sequential)] + public struct MibUdp6Row + { + public INet6Address LocalAddress; + public uint LocalScopeId; + public int LocalPort; + } + + [StructLayout(LayoutKind.Sequential)] + public struct MibUdpTable + { + public uint NumEntries; + public MibUdpRow[] Table; + } + + [StructLayout(LayoutKind.Sequential)] + public struct MibUdp6Table + { + public int NumEntries; + public MibUdp6Row[] Table; + } + + [StructLayout(LayoutKind.Sequential)] + public struct MibUdpRowOwnerPid + { + public uint LocalAddress; + public int LocalPort; + public int OwningProcessId; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + public struct MibUdp6RowOwnerPid + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] LocalAddress; + public uint LocalScopeId; + public int LocalPort; + public int OwningProcessId; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + public struct MibUdp6RowOwnerModule + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] LocalAddress; + public uint LocalScopeId; + public int LocalPort; + public int OwningProcessId; + public long CreateTimestamp; + public int Flags; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public long[] OwningModuleInfo; + } + + [StructLayout(LayoutKind.Sequential)] + public struct MibUdpStats + { + public int InDatagrams; + public int NoPorts; + public int InErrors; + public int OutDatagrams; + public int NumAddrs; + } + + [StructLayout(LayoutKind.Sequential)] + public struct MibUdpTableOwnerPid + { + public int NumEntries; + public MibUdpRowOwnerPid[] Table; + } + + [StructLayout(LayoutKind.Sequential)] + public struct MibUdp6TableOwnerPid + { + public int NumEntries; + public MibUdp6RowOwnerPid[] Table; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ModuleEntry32 + { + public int dwSize; + public int th32ModuleID; + public int th32ProcessID; + public int GlblcntUsage; + public int ProccntUsage; + public int modBaseAddr; + public int modBaseSize; + public int hModule; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public string szModule; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public string szExePath; + + public int dwFlags; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ModuleInfo + { + public IntPtr BaseOfDll; + public int SizeOfImage; + public IntPtr EntryPoint; + } + + [StructLayout(LayoutKind.Sequential)] + public struct MonitorInformation + { + public uint Size; + public Rectangle MonitorRectangle; + public Rectangle WorkRectangle; + public uint Flags; + } + + [StructLayout(LayoutKind.Sequential)] + public struct PerformanceInformation + { + public int Size; + public IntPtr CommitTotal; + public IntPtr CommitLimit; + public IntPtr CommitPeak; + public IntPtr PhysicalTotal; + public IntPtr PhysicalAvailable; + public IntPtr SystemCache; + public IntPtr KernelTotal; + public IntPtr KernelPaged; + public IntPtr KernelNonPaged; + public IntPtr PageSize; + public int HandlesCount; + public int ProcessCount; + public int ThreadCount; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ProcessEntry32 + { + public int dwSize; + public int cntUsage; + public int th32ProcessID; + public int th32DefaultHeapID; + public int th32ModuleID; + public int cntThreads; + public int th32ParentProcessID; + public int pcPriClassBase; + public int dwFlags; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] + public string szExeFile; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ProcessInformation + { + public IntPtr ProcessHandle; + public IntPtr ThreadHandle; + public int ProcessId; + public int ThreadId; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + public struct ProfileInformation + { + public int Size; + public int Flags; + public string UserName; + public string ProfilePath; + public string DefaultPath; + public string ServerName; + public string PolicyPath; + public int ProfileHandle; + } + + [StructLayout(LayoutKind.Sequential)] + public struct QueryServiceConfig + { + public ServiceType ServiceType; + public ServiceStartType StartType; + public ServiceErrorControl ErrorControl; + + [MarshalAs(UnmanagedType.LPTStr)] + public string BinaryPathName; + + [MarshalAs(UnmanagedType.LPTStr)] + public string LoadOrderGroup; + + public int TagID; + public int Dependencies; // pointer to a string array + + [MarshalAs(UnmanagedType.LPTStr)] + public string ServiceStartName; + + [MarshalAs(UnmanagedType.LPTStr)] + public string DisplayName; + } + + [StructLayout(LayoutKind.Sequential)] + public struct Rect + { + public int Left; + public int Top; + public int Right; + public int Bottom; + + public Rectangle ToRectangle() + { + return Rectangle.FromLTRB(this.Left, this.Top, this.Right, this.Bottom); + } + + public Rect(int left, int top, int right, int bottom) + { + this.Left = left; + this.Top = top; + this.Right = right; + this.Bottom = bottom; + } + } + + [StructLayout(LayoutKind.Sequential)] + public struct ScAction + { + public ScActionType Type; + public int Delay; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ServiceDescription + { + [MarshalAs(UnmanagedType.LPWStr)] + public string Description; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ServiceStatus + { + public ServiceType ServiceType; + public ServiceState CurrentState; + public ServiceAccept ControlsAccepted; + public int Win32ExitCode; + public int ServiceSpecificExitCode; + public int CheckPoint; + public int WaitHint; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ServiceStatusProcess + { + public ServiceType ServiceType; + public ServiceState CurrentState; + public ServiceAccept ControlsAccepted; + public int Win32ExitCode; + public int ServiceSpecificExitCode; + public int CheckPoint; + public int WaitHint; + public int ProcessID; + public ServiceFlags ServiceFlags; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ShellExecuteInfo + { + public int cbSize; + public uint fMask; + public IntPtr hWnd; + public string lpVerb; + public string lpFile; + public string lpParameters; + public string lpDirectory; + public ShowWindowType nShow; + public IntPtr hInstApp; + + public IntPtr lpIDList; + public string lpClass; + public IntPtr hkeyClass; + public uint dwHotKey; + public IntPtr hIcon; + public IntPtr hProcess; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ShFileInfo + { + public IntPtr hIcon; + public IntPtr iIcon; + public uint dwAttributes; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] + public string szDisplayName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)] + public string szTypeName; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + public struct SiAccess + { + public IntPtr Guid; + public int Mask; + public IntPtr Name; // string + public SiAccessFlags Flags; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + public struct SiInheritType + { + public IntPtr Guid; + public int Flags; + public IntPtr Name; // string + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + public struct SiObjectInfo + { + public SiObjectInfoFlags Flags; + public IntPtr Instance; + public IntPtr ServerName; // string + public IntPtr ObjectName; // string + public IntPtr PageTitle; // string + public Guid ObjectType; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StackFrame64 + { + public Address64 AddrPC; + public Address64 AddrReturn; + public Address64 AddrFrame; + public Address64 AddrStack; + public Address64 AddrBStore; + + public IntPtr FuncTableEntry; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public long[] Params; + + public int Far; + public int Virtual; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public long[] Reserved; + + public KdHelp64 KdHelp; + } + + [StructLayout(LayoutKind.Sequential)] + public struct StartupInfo + { + public int Size; + [MarshalAs(UnmanagedType.LPWStr)] + public string Reserved; + [MarshalAs(UnmanagedType.LPWStr)] + public string Desktop; + [MarshalAs(UnmanagedType.LPWStr)] + public string Title; + public int X; + public int Y; + public int XSize; + public int YSize; + public int XCountChars; + public int YCountChars; + public int FillAttribute; + public StartupFlags Flags; + public short ShowWindow; + public short Reserved2; + public IntPtr Reserved3; + public IntPtr StdInputHandle; + public IntPtr StdOutputHandle; + public IntPtr StdErrorHandle; + } + + [StructLayout(LayoutKind.Sequential)] + public struct SymbolInfo + { + public int SizeOfStruct; + public int TypeIndex; + public unsafe fixed long Reserved[2]; + public int Index; + public int Size; + public ulong ModBase; + public SymbolFlags Flags; + public long Value; + public long Address; + public int Register; + public int Scope; + public int Tag; + public int NameLen; + public int MaxNameLen; + public char Name; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ThreadEntry32 + { + public int dwSize; + public int cntUsage; + public int th32ThreadID; + public int th32OwnerProcessID; + public int tpBasePri; + public int tpDeltaPri; + public int dwFlags; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] + public string szExeFile; + } + + [StructLayout(LayoutKind.Sequential)] + public struct WindowClass + { + public int Styles; + [MarshalAs(UnmanagedType.FunctionPtr)] + public WndProcDelegate WindowsProc; + private int ExtraClassData; + private int ExtraWindowData; + public IntPtr InstanceHandle; + public IntPtr IconHandle; + public IntPtr CursorHandle; + public IntPtr backgroundBrush; + [MarshalAs(UnmanagedType.LPTStr)] + public string MenuName; + [MarshalAs(UnmanagedType.LPTStr)] + public string ClassName; + } + + [StructLayout(LayoutKind.Sequential)] + public struct WindowPlacement + { + public int Length; + public WindowPlacementFlags Flags; + public ShowWindowType ShowState; + public Point MinPosition; + public Point MaxPosition; + public Rect NormalPosition; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + public struct WintrustCatalogInfo + { + public int Size; + public int CatalogVersion; + public string CatalogFilePath; + public string MemberTag; + public string MemberFilePath; + public IntPtr MemberFile; + public byte[] CalculatedFileHash; + public int CalculatedFileHashSize; + public IntPtr CatalogContext; + } + + [StructLayout(LayoutKind.Sequential)] + public struct WintrustData + { + public int Size; + public IntPtr PolicyCallbackData; + public IntPtr SIPClientData; + public int UIChoice; + public WtRevocationChecks RevocationChecks; + public int UnionChoice; + public IntPtr UnionData; + public int StateAction; + public IntPtr StateData; + public IntPtr URLReference; + public WtProvFlags ProvFlags; + public int UIContext; + } + + [StructLayout(LayoutKind.Sequential)] + public struct WintrustFileInfo + { + public int Size; + public IntPtr FilePath; + public IntPtr FileHandle; + public IntPtr KnownSubject; + } + + [StructLayout(LayoutKind.Sequential)] + public struct WtsClientAddress + { + public int AddressFamily; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] + public byte[] Address; + } + + [StructLayout(LayoutKind.Sequential)] + public struct WtsClientDisplay + { + public int HorizontalResolution; + public int VerticalResolution; + public int ColorDepth; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + public struct WtsProcessInfo + { + public int SessionId; + public int ProcessId; + public IntPtr ProcessName; + public IntPtr Sid; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + public struct WtsSessionInfo + { + public int SessionID; + public string WinStationName; + public WtsConnectStateClass State; + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Api/Win32.cs b/branches/ph-plugins/ProcessHacker.Native/Api/Win32.cs new file mode 100644 index 000000000..87a55cd02 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Api/Win32.cs @@ -0,0 +1,350 @@ +/* + * Process Hacker - + * windows API wrapper code + * + * Copyright (C) 2009 Flavio Erlich + * Copyright (C) 2009 Dean + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Security; +using System.Text; +using ProcessHacker.Common.Threading; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Api +{ + public delegate bool EnumWindowsProc(IntPtr hWnd, uint param); + public delegate bool EnumChildProc(IntPtr hWnd, uint param); + public delegate bool EnumThreadWndProc(IntPtr hWnd, uint param); + public delegate IntPtr WndProcDelegate(IntPtr hWnd, WindowMessage msg, IntPtr wParam, IntPtr lParam); + + public delegate bool SymEnumSymbolsProc(IntPtr SymInfo, int SymbolSize, int UserContext); + public unsafe delegate bool ReadProcessMemoryProc64(IntPtr ProcessHandle, ulong BaseAddress, IntPtr Buffer, + int Size, out int BytesRead); + public delegate IntPtr FunctionTableAccessProc64(IntPtr ProcessHandle, ulong AddrBase); + public delegate ulong GetModuleBaseProc64(IntPtr ProcessHandle, ulong Address); + + /// + /// Provides interfacing to the Win32 and Native APIs. + /// + [SuppressUnmanagedCodeSecurity] + public static partial class Win32 + { + private static FastMutex _dbgHelpLock = new FastMutex(); + + /// + /// A mutex which controls access to the dbghelp.dll functions. + /// + public static FastMutex DbgHelpLock + { + get { return _dbgHelpLock; } + } + + #region Consts + + public const int DontResolveDllReferences = 0x1; + public const int ErrorNoMoreItems = 259; + public const int SeeMaskInvokeIdList = 0xc; + public const uint ServiceNoChange = 0xffffffff; + public const uint ShgFiIcon = 0x100; + public const uint ShgFiLargeIcon = 0x0; + public const uint ShgFiSmallIcon = 0x1; + public static readonly int SymbolInfoNameOffset = Marshal.OffsetOf(typeof(SymbolInfo), "Name").ToInt32(); + + #endregion + + #region Errors + + public static Win32Error GetLastErrorCode() + { + return (Win32Error)Marshal.GetLastWin32Error(); + } + + /// + /// Gets the error message associated with the last error that occured. + /// + /// An error message. + public static string GetLastErrorMessage() + { + return GetLastErrorCode().GetMessage(); + } + + /// + /// Throws a WindowsException with the last error that occurred. + /// + public static void ThrowLastError() + { + ThrowLastError(GetLastErrorCode()); + } + + public static void ThrowLastError(NtStatus status) + { + throw new WindowsException(status); + } + + public static void ThrowLastError(int error) + { + ThrowLastError((Win32Error)error); + } + + public static void ThrowLastError(Win32Error error) + { + throw new WindowsException(error); + } + + #endregion + + #region Handles + + public unsafe static void DuplicateObject( + IntPtr sourceProcessHandle, + IntPtr sourceHandle, + int desiredAccess, + HandleFlags handleAttributes, + DuplicateOptions options + ) + { + IntPtr dummy; + + DuplicateObject( + sourceProcessHandle, + sourceHandle, + IntPtr.Zero, + out dummy, + desiredAccess, + handleAttributes, + options + ); + } + + public unsafe static void DuplicateObject( + IntPtr sourceProcessHandle, + IntPtr sourceHandle, + IntPtr targetProcessHandle, + out IntPtr targetHandle, + int desiredAccess, + HandleFlags handleAttributes, + DuplicateOptions options + ) + { + if (KProcessHacker.Instance != null) + { + int target; + + KProcessHacker.Instance.KphDuplicateObject( + sourceProcessHandle.ToInt32(), + sourceHandle.ToInt32(), + targetProcessHandle.ToInt32(), + out target, + desiredAccess, + handleAttributes, + options); + targetHandle = new IntPtr(target); + } + else + { + NtStatus status; + + if ((status = NtDuplicateObject( + sourceProcessHandle, + sourceHandle, + targetProcessHandle, + out targetHandle, + desiredAccess, + handleAttributes, + options)) >= NtStatus.Error) + ThrowLastError(status); + } + } + + #endregion + + #region Processes + + public static int GetProcessSessionId(int ProcessId) + { + int sessionId; + + try + { + if (!ProcessIdToSessionId(ProcessId, out sessionId)) + ThrowLastError(); + } + catch + { + using (ProcessHandle phandle = new ProcessHandle(ProcessId, OSVersion.MinProcessQueryInfoAccess)) + { + return phandle.GetToken(TokenAccess.Query).GetSessionId(); + } + } + + return sessionId; + } + + #endregion + + #region TCP + + public static MibTcpStats GetTcpStats() + { + MibTcpStats tcpStats; + GetTcpStatistics(out tcpStats); + return tcpStats; + } + + public static MibTcpTableOwnerPid GetTcpTable() + { + MibTcpTableOwnerPid table = new MibTcpTableOwnerPid(); + int length = 0; + + GetExtendedTcpTable(IntPtr.Zero, ref length, false, AiFamily.INet, TcpTableClass.OwnerPidAll, 0); + + using (MemoryAlloc mem = new MemoryAlloc(length)) + { + GetExtendedTcpTable(mem, ref length, false, AiFamily.INet, TcpTableClass.OwnerPidAll, 0); + + int count = mem.ReadInt32(0); + + table.NumEntries = count; + table.Table = new MibTcpRowOwnerPid[count]; + + for (int i = 0; i < count; i++) + table.Table[i] = mem.ReadStruct(sizeof(int), i); + } + + return table; + } + + #endregion + + #region Terminal Server + + public struct WtsEnumProcessesFastData + { + public int[] PIDs; + public IntPtr[] SIDs; + public WtsMemoryAlloc Memory; + } + + public unsafe static WtsEnumProcessesFastData TSEnumProcessesFast() + { + IntPtr processes; + int count; + int[] pids; + IntPtr[] sids; + + WTSEnumerateProcesses(IntPtr.Zero, 0, 1, out processes, out count); + + pids = new int[count]; + sids = new IntPtr[count]; + + WtsMemoryAlloc data = new WtsMemoryAlloc(processes); + WtsProcessInfo* dataP = (WtsProcessInfo*)data.Memory; + + for (int i = 0; i < count; i++) + { + pids[i] = dataP[i].ProcessId; + sids[i] = dataP[i].Sid; + } + + return new WtsEnumProcessesFastData() { PIDs = pids, SIDs = sids, Memory = data }; + } + + #endregion + + #region UDP + + public static MibUdpStats GetUdpStats() + { + MibUdpStats udpStats; + GetUdpStatistics(out udpStats); + return udpStats; + } + + public static MibUdpTableOwnerPid GetUdpTable() + { + MibUdpTableOwnerPid table = new MibUdpTableOwnerPid(); + int length = 0; + + GetExtendedUdpTable(IntPtr.Zero, ref length, false, AiFamily.INet, UdpTableClass.OwnerPid, 0); + + using (MemoryAlloc mem = new MemoryAlloc(length)) + { + GetExtendedUdpTable(mem, ref length, false, AiFamily.INet, UdpTableClass.OwnerPid, 0); + + int count = mem.ReadInt32(0); + + table.NumEntries = count; + table.Table = new MibUdpRowOwnerPid[count]; + + for (int i = 0; i < count; i++) + table.Table[i] = mem.ReadStruct(sizeof(int), i); + } + + return table; + } + + #endregion + + #region Unsafe + + /// + /// Converts a multi-string into a managed string array. A multi-string + /// consists of an array of null-terminated strings plus an extra null to + /// terminate the array. + /// + /// The pointer to the array. + /// A string array. + public unsafe static string[] GetMultiString(IntPtr ptr) + { + List list = new List(); + char* chptr = (char*)ptr; + StringBuilder currentString = new StringBuilder(); + + while (true) + { + while (*chptr != 0) + { + currentString.Append(*chptr); + chptr++; + } + + string str = currentString.ToString(); + + if (str == "") + { + break; + } + else + { + list.Add(str); + currentString = new StringBuilder(); + } + } + + return list.ToArray(); + } + + #endregion + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Api/Win32Error.cs b/branches/ph-plugins/ProcessHacker.Native/Api/Win32Error.cs new file mode 100644 index 000000000..5319aee49 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Api/Win32Error.cs @@ -0,0 +1,132 @@ +/* + * Process Hacker - + * Win32 error codes + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Native.Api +{ + /// + /// A Win32 error code. + /// + public enum Win32Error : uint + { + Success = 0x0, + InvalidFunction = 0x1, + FileNotFound = 0x2, + PathNotFound = 0x3, + TooManyOpenFiles = 0x4, + AccessDenied = 0x5, + InvalidHandle = 0x6, + ArenaTrashed = 0x7, + NotEnoughMemory = 0x8, + InvalidBlock = 0x9, + BadEnvironment = 0xa, + BadFormat = 0xb, + InvalidAccess = 0xc, + InvalidData = 0xd, + OutOfMemory = 0xe, + InvalidDrive = 0xf, + CurrentDirectory = 0x10, + NotSameDevice = 0x11, + NoMoreFiles = 0x12, + WriteProtect = 0x13, + BadUnit = 0x14, + NotReady = 0x15, + BadCommand = 0x16, + Crc = 0x17, + BadLength = 0x18, + Seek = 0x19, + NotDosDisk = 0x1a, + SectorNotFound = 0x1b, + OutOfPaper = 0x1c, + WriteFault = 0x1d, + ReadFault = 0x1e, + GenFailure = 0x1f, + SharingViolation = 0x20, + LockViolation = 0x21, + WrongDisk = 0x22, + SharingBufferExceeded = 0x24, + HandleEof = 0x26, + HandleDiskFull = 0x27, + NotSupported = 0x32, + RemNotList = 0x33, + DupName = 0x34, + BadNetPath = 0x35, + NetworkBusy = 0x36, + DevNotExist = 0x37, + TooManyCmds = 0x38, + FileExists = 0x50, + CannotMake = 0x52, + AlreadyAssigned = 0x55, + InvalidPassword = 0x56, + InvalidParameter = 0x57, + NetWriteFault = 0x58, + NoProcSlots = 0x59, + TooManySemaphores = 0x64, + ExclSemAlreadyOwned = 0x65, + SemIsSet = 0x66, + TooManySemRequests = 0x67, + InvalidAtInterruptTime = 0x68, + SemOwnerDied = 0x69, + SemUserLimit = 0x6a + } + + public static class Win32ErrorExtensions + { + public static HResult GetHResult(this Win32Error errorCode) + { + int error = (int)errorCode; + + if ((error & 0x80000000) == 0x80000000) + return (HResult)error; + + return (HResult)(0x80070000 | (uint)(error & 0xffff)); + } + + public static string GetMessage(this Win32Error errorCode) + { + StringBuilder buffer = new StringBuilder(0x100); + + if (Win32.FormatMessage(0x3200, IntPtr.Zero, (int)errorCode, 0, buffer, buffer.Capacity, IntPtr.Zero) == 0) + return "Unknown error (0x" + ((int)errorCode).ToString("x") + ")"; + + StringBuilder result = new StringBuilder(); + int i = 0; + + while (i < buffer.Length) + { + if (!char.IsLetterOrDigit(buffer[i]) && + !char.IsPunctuation(buffer[i]) && + !char.IsSymbol(buffer[i]) && + !char.IsWhiteSpace(buffer[i])) + break; + + result.Append(buffer[i]); + i++; + } + + return result.ToString().Replace("\r\n", ""); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Cryptography.cs b/branches/ph-plugins/ProcessHacker.Native/Cryptography.cs new file mode 100644 index 000000000..c24525110 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Cryptography.cs @@ -0,0 +1,241 @@ +/* + * Process Hacker - + * cryptography functions + * + * Copyright (C) 2009 Flavio Erlich + * Copyright (C) 2009 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 . + */ + +using System; +using System.Runtime.InteropServices; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using ProcessHacker.Common; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native +{ + public enum VerifyResult : int + { + Unknown = 0, + NoSignature, + Trusted, + TrustedInstaller, + Expired, + Revoked, + Distrust, + SecuritySettings + } + + public static class Cryptography + { + public static readonly Guid DriverActionVerify = + new Guid("{f750e6c3-38ee-11d1-85e5-00c04fc295ee}"); + public static readonly Guid HttpsProvAction = + new Guid("{573e31f8-aaba-11d0-8ccb-00c04fc295ee}"); + public static readonly Guid OfficeSignActionVerify = + new Guid("{5555c2cd-17fb-11d1-85c4-00c04fc295ee}"); + public static readonly Guid WintrustActionGenericCertVerify = + new Guid("{189a3842-3041-11d1-85e1-00c04fc295ee}"); + public static readonly Guid WintrustActionGenericChainVerify = + new Guid("{fc451c16-ac75-11d1-b4b8-00c04fb66ea0}"); + public static readonly Guid WintrustActionGenericVerifyV2 = + new Guid("{00aac56b-cd44-11d0-8cc2-00c04fc295ee}"); + public static readonly System.Guid WintrustActionTrustProviderTest = + new Guid("{573e31f8-ddba-11d0-8ccb-00c04fc295ee}"); + + public static string GetFileSubjectValue(string fileName, string keyName) + { + X509Certificate cert = X509Certificate.CreateFromSignedFile(fileName); + Tokenizer t = new Tokenizer(cert.Subject); + + // Use the "tokenizer" to get the Common Name (CN). + while (true) + { + t.EatWhitespace(); + string key = t.EatId(); + + if (string.IsNullOrEmpty(key)) + return null; + + t.EatWhitespace(); + string equals = t.EatSymbol(); + + if (equals != "=") + return null; + + t.EatWhitespace(); + string value = t.EatQuotedString(); + + if (string.IsNullOrEmpty(value)) + { + // The value probably isn't quoted. + value = t.EatUntil(','); + } + + if (string.IsNullOrEmpty(value)) + return null; + + if (key == keyName) + return value; + } + } + + public static VerifyResult StatusToVerifyResult(uint status) + { + if (status == 0) + return VerifyResult.Trusted; + else if (status == 0x800b0100) + return VerifyResult.NoSignature; + else if (status == 0x800b0101) + return VerifyResult.Expired; + else if (status == 0x800b010c) + return VerifyResult.Revoked; + else if (status == 0x800b0111) + return VerifyResult.Distrust; + else if (status == 0x80092026) + return VerifyResult.SecuritySettings; + else + return VerifyResult.SecuritySettings; + } + + public static VerifyResult VerifyFile(string fileName) + { + VerifyResult result = VerifyResult.NoSignature; + + using (MemoryAlloc strMem = new MemoryAlloc(fileName.Length * 2 + 2)) + { + WintrustFileInfo fileInfo = new WintrustFileInfo(); + + strMem.WriteUnicodeString(0, fileName); + strMem.WriteByte(fileName.Length * 2, 0); + strMem.WriteByte(fileName.Length * 2 + 1, 0); + + fileInfo.Size = Marshal.SizeOf(fileInfo); + fileInfo.FilePath = strMem; + + WintrustData trustData = new WintrustData(); + + trustData.Size = 12 * 4; + trustData.UIChoice = 2; // WTD_UI_NONE + trustData.UnionChoice = 1; // WTD_CHOICE_FILE + trustData.RevocationChecks = WtRevocationChecks.None; + trustData.ProvFlags = WtProvFlags.Safer; + + if (OSVersion.IsAboveOrEqual(WindowsVersion.Vista)) + trustData.ProvFlags |= WtProvFlags.CacheOnlyUrlRetrieval; + + using (MemoryAlloc mem = new MemoryAlloc(fileInfo.Size)) + { + Marshal.StructureToPtr(fileInfo, mem, false); + trustData.UnionData = mem; + + uint winTrustResult = Win32.WinVerifyTrust(IntPtr.Zero, WintrustActionGenericVerifyV2, ref trustData); + + result = StatusToVerifyResult(winTrustResult); + } + } + + if (result == VerifyResult.NoSignature) + { + using (FileHandle sourceFile = FileHandle.CreateWin32(fileName, FileAccess.GenericRead, FileShareMode.Read, + FileCreationDispositionWin32.OpenExisting)) + { + byte[] hash = new byte[256]; + int hashLength = 256; + + if (!Win32.CryptCATAdminCalcHashFromFileHandle(sourceFile, ref hashLength, hash, 0)) + { + hash = new byte[hashLength]; + + if (!Win32.CryptCATAdminCalcHashFromFileHandle(sourceFile, ref hashLength, hash, 0)) + return VerifyResult.NoSignature; + } + + StringBuilder memberTag = new StringBuilder(hashLength * 2); + + for (int i = 0; i < hashLength; i++) + memberTag.Append(hash[i].ToString("X2")); + + IntPtr catAdmin; + + if (!Win32.CryptCATAdminAcquireContext(out catAdmin, DriverActionVerify, 0)) + return VerifyResult.NoSignature; + + IntPtr catInfo = Win32.CryptCATAdminEnumCatalogFromHash(catAdmin, hash, hashLength, 0, IntPtr.Zero); + + if (catInfo == IntPtr.Zero) + { + Win32.CryptCATAdminReleaseContext(catAdmin, 0); + return VerifyResult.NoSignature; + } + + CatalogInfo ci; + + if (!Win32.CryptCATCatalogInfoFromContext(catInfo, out ci, 0)) + { + Win32.CryptCATAdminReleaseCatalogContext(catAdmin, catInfo, 0); + Win32.CryptCATAdminReleaseContext(catAdmin, 0); + return VerifyResult.NoSignature; + } + + WintrustCatalogInfo wci = new WintrustCatalogInfo(); + + wci.Size = Marshal.SizeOf(wci); + wci.CatalogFilePath = ci.CatalogFile; + wci.MemberFilePath = fileName; + wci.MemberTag = memberTag.ToString(); + + WintrustData trustData = new WintrustData(); + + trustData.Size = 12 * 4; + trustData.UIChoice = 1; + trustData.UnionChoice = 2; + trustData.RevocationChecks = WtRevocationChecks.None; + + if (OSVersion.IsAboveOrEqual(WindowsVersion.Vista)) + trustData.ProvFlags = WtProvFlags.CacheOnlyUrlRetrieval; + + using (MemoryAlloc mem = new MemoryAlloc(wci.Size)) + { + Marshal.StructureToPtr(wci, mem, false); + + try + { + trustData.UnionData = mem; + + uint winTrustResult = Win32.WinVerifyTrust(IntPtr.Zero, DriverActionVerify, ref trustData); + + result = StatusToVerifyResult(winTrustResult); + } + finally + { + Win32.CryptCATAdminReleaseCatalogContext(catAdmin, catInfo, 0); + Win32.CryptCATAdminReleaseContext(catAdmin, 0); + Marshal.DestroyStructure(mem, typeof(WintrustCatalogInfo)); + } + } + } + } + + return result; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Debugging/DebugBuffer.cs b/branches/ph-plugins/ProcessHacker.Native/Debugging/DebugBuffer.cs new file mode 100644 index 000000000..31eb0b8bd --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Debugging/DebugBuffer.cs @@ -0,0 +1,268 @@ +/* + * Process Hacker - + * run-time library debug buffer + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using ProcessHacker.Common.Objects; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; + +namespace ProcessHacker.Native.Debugging +{ + public delegate bool DebugEnumHeapsDelegate(HeapInformation heapInfo); + public delegate bool DebugEnumLocksDelegate(LockInformation lockInfo); + public delegate bool DebugEnumModulesDelegate(ModuleInformation moduleInfo); + + /// + /// Represents a debug buffer managed by the run-time library. + /// + public sealed class DebugBuffer : BaseObject + { + private IntPtr _buffer; + + /// + /// Creates a new debug buffer. + /// + public DebugBuffer() + { + _buffer = Win32.RtlCreateQueryDebugBuffer(0, true); + + if (_buffer == IntPtr.Zero) + { + this.DisableOwnership(false); + throw new WindowsException(NtStatus.Unsuccessful); + } + } + + protected override void DisposeObject(bool disposing) + { + Win32.RtlDestroyQueryDebugBuffer(_buffer); + } + + /// + /// Enumerates heap information. + /// + /// The callback for the enumeration. + public void EnumHeaps(DebugEnumHeapsDelegate callback) + { + var debugInfo = this.GetDebugInformation(); + + if (debugInfo.Heaps == IntPtr.Zero) + throw new InvalidOperationException("Heap information does not exist."); + + MemoryRegion heapInfo = new MemoryRegion(debugInfo.Heaps); + var heaps = heapInfo.ReadStruct(); + + for (int i = 0; i < heaps.NumberOfHeaps; i++) + { + var heap = heapInfo.ReadStruct(RtlProcessHeaps.HeapsOffset, i); + + if (!callback(new HeapInformation(heap))) + break; + } + } + + /// + /// Enumerates lock information. + /// + /// The callback for the enumeration. + public void EnumLocks(DebugEnumLocksDelegate callback) + { + var debugInfo = this.GetDebugInformation(); + + if (debugInfo.Locks == IntPtr.Zero) + throw new InvalidOperationException("Lock information does not exist."); + + MemoryRegion locksInfo = new MemoryRegion(debugInfo.Locks); + var locks = locksInfo.ReadStruct(); + + for (int i = 0; i < locks.NumberOfLocks; i++) + { + var lock_ = locksInfo.ReadStruct(sizeof(int), i); + + if (!callback(new LockInformation(lock_))) + break; + } + } + + /// + /// Enumerates module information. + /// + /// The callback for the enumeration. + public void EnumModules(DebugEnumModulesDelegate callback) + { + var debugInfo = this.GetDebugInformation(); + + if (debugInfo.Modules == IntPtr.Zero) + throw new InvalidOperationException("Module information does not exist."); + + MemoryRegion modulesInfo = new MemoryRegion(debugInfo.Modules); + var modules = modulesInfo.ReadStruct(); + + for (int i = 0; i < modules.NumberOfModules; i++) + { + var module = modulesInfo.ReadStruct(RtlProcessModules.ModulesOffset, i); + + if (!callback(new ModuleInformation(module))) + break; + } + } + + /// + /// Reads the debug information structure from the buffer. + /// + /// A RtlDebugInformation structure. + private RtlDebugInformation GetDebugInformation() + { + MemoryRegion data = new MemoryRegion(_buffer); + + return data.ReadStruct(); + } + + /// + /// Gets heap information. + /// + /// An array of heap information objects. + public HeapInformation[] GetHeaps() + { + List heaps = new List(); + + this.EnumHeaps((heap) => + { + heaps.Add(heap); + return true; + }); + + return heaps.ToArray(); + } + + /// + /// Gets lock information. + /// + /// An array of lock information objects. + public LockInformation[] GetLocks() + { + List locks = new List(); + + this.EnumLocks((lock_) => + { + locks.Add(lock_); + return true; + }); + + return locks.ToArray(); + } + + /// + /// Gets module information. + /// + /// An array of module information objects. + public ModuleInformation[] GetModules() + { + List modules = new List(); + + this.EnumModules((module) => + { + modules.Add(module); + return true; + }); + + return modules.ToArray(); + } + + /// + /// Queries debug information for the current process. + /// + /// The information to query. + public void Query(RtlQueryProcessDebugFlags flags) + { + this.Query(ProcessHandle.GetCurrentId(), flags); + } + + /// + /// Queries debug information for the specified process. + /// + /// The PID of the process to query. + /// The information to query. + public void Query(int pid, RtlQueryProcessDebugFlags flags) + { + NtStatus status; + + if ((status = Win32.RtlQueryProcessDebugInformation( + pid.ToIntPtr(), + flags, + _buffer + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + /// + /// Queries back trace information for the current process. + /// + public void QueryBackTraces() + { + NtStatus status; + + if ((status = Win32.RtlQueryProcessBackTraceInformation(_buffer)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + /// + /// Queries heap information for the current process. + /// + public void QueryHeaps() + { + NtStatus status; + + if ((status = Win32.RtlQueryProcessHeapInformation(_buffer)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + /// + /// Queries lock information for the current process. + /// + public void QueryLocks() + { + NtStatus status; + + if ((status = Win32.RtlQueryProcessLockInformation(_buffer)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + //public void QueryModules() + //{ + // this.QueryModules(null, RtlQueryProcessDebugFlags.Modules); + //} + + //public void QueryModules(ProcessHandle processHandle, RtlQueryProcessDebugFlags flags) + //{ + // NtStatus status; + + // if ((status = Win32.RtlQueryProcessModuleInformation( + // processHandle ?? IntPtr.Zero, + // flags, + // _buffer + // )) >= NtStatus.Error) + // Win32.ThrowLastError(status); + //} + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Debugging/HeapInformation.cs b/branches/ph-plugins/ProcessHacker.Native/Debugging/HeapInformation.cs new file mode 100644 index 000000000..2cd9dd0b3 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Debugging/HeapInformation.cs @@ -0,0 +1,63 @@ +/* + * Process Hacker - + * heap information + * + * Copyright (C) 2009 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 . + */ + +using System; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native.Debugging +{ + public class HeapInformation + { + internal HeapInformation(RtlHeapInformation heapInfo) + { + this.Address = heapInfo.BaseAddress; + this.BytesAllocated = heapInfo.BytesAllocated.ToInt64(); + this.BytesCommitted = heapInfo.BytesCommitted.ToInt64(); + this.TagCount = heapInfo.NumberOfTags; + this.EntryCount = heapInfo.NumberOfEntries; + this.PseudoTagCount = heapInfo.NumberOfPseudoTags; + } + + public HeapInformation( + IntPtr address, + long bytesAllocated, + long bytesCommitted, + int tagCount, + int entryCount, + int pseudoTagCount) + { + this.Address = address; + this.BytesAllocated = bytesAllocated; + this.BytesCommitted = bytesCommitted; + this.TagCount = tagCount; + this.EntryCount = entryCount; + this.PseudoTagCount = pseudoTagCount; + } + + public IntPtr Address { get; private set; } + public long BytesAllocated { get; private set; } + public long BytesCommitted { get; private set; } + public int TagCount { get; private set; } + public int EntryCount { get; private set; } + public int PseudoTagCount { get; private set; } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Debugging/LockInformation.cs b/branches/ph-plugins/ProcessHacker.Native/Debugging/LockInformation.cs new file mode 100644 index 000000000..7ffc182c7 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Debugging/LockInformation.cs @@ -0,0 +1,57 @@ +/* + * Process Hacker - + * lock information + * + * Copyright (C) 2009 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 . + */ + +using System; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native.Debugging +{ + public class LockInformation + { + internal LockInformation(RtlProcessLockInformation lockInfo) + { + this.Address = lockInfo.Address; + this.Type = lockInfo.Type; + this.OwningThreadId = lockInfo.OwningThread.ToInt32(); + this.LockCount = lockInfo.LockCount; + this.ContentionCount = lockInfo.ContentionCount; + this.EntryCount = lockInfo.EntryCount; + + this.RecursionCount = lockInfo.RecursionCount; + + this.SharedWaiters = lockInfo.NumberOfWaitingShared; + this.ExclusiveWaiters = lockInfo.NumberOfWaitingExclusive; + } + + public IntPtr Address { get; private set; } + public RtlLockType Type { get; private set; } + public int OwningThreadId { get; private set; } + public int LockCount { get; private set; } + public int ContentionCount { get; private set; } + public int EntryCount { get; private set; } + + public int RecursionCount { get; private set; } + + public int SharedWaiters { get; private set; } + public int ExclusiveWaiters { get; private set; } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Debugging/ModuleInformation.cs b/branches/ph-plugins/ProcessHacker.Native/Debugging/ModuleInformation.cs new file mode 100644 index 000000000..0beb03f84 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Debugging/ModuleInformation.cs @@ -0,0 +1,54 @@ +/* + * Process Hacker - + * module information + * + * Copyright (C) 2009 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 . + */ + +using System; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native.Debugging +{ + public class ModuleInformation : ILoadedModule + { + internal ModuleInformation(RtlProcessModuleInformation moduleInfo) + { + this.BaseAddress = moduleInfo.ImageBase; + this.Size = moduleInfo.ImageSize; + this.Flags = moduleInfo.Flags; + this.LoadCount = moduleInfo.LoadCount; + + int nullIndex = Array.IndexOf(moduleInfo.FullPathName, '\0'); + + if (nullIndex != -1) + this.FileName = new string(moduleInfo.FullPathName, 0, nullIndex); + else + this.FileName = new string(moduleInfo.FullPathName); + + this.BaseName = this.FileName.Substring(moduleInfo.OffsetToFileName); + } + + public IntPtr BaseAddress { get; private set; } + public int Size { get; private set; } + public LdrpDataTableEntryFlags Flags { get; private set; } + public ushort LoadCount { get; private set; } + public string BaseName { get; private set; } + public string FileName { get; private set; } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/FileUtils.cs b/branches/ph-plugins/ProcessHacker.Native/FileUtils.cs new file mode 100644 index 000000000..e142d8f99 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/FileUtils.cs @@ -0,0 +1,161 @@ +/* + * Process Hacker - + * file-related utility functions + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Text; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native +{ + /// + /// Provides utility methods for managing files. + /// + public static class FileUtils + { + static FileUtils() + { + RefreshFileNamePrefixes(); + } + + /// + /// Used to resolve device prefixes (\Device\Harddisk1) into DOS drive names. + /// + private static Dictionary _fileNamePrefixes = new Dictionary(); + + public static Icon GetFileIcon(string fileName) + { + return GetFileIcon(fileName, false); + } + + public static Icon GetFileIcon(string fileName, bool large) + { + ShFileInfo shinfo = new ShFileInfo(); + + if (string.IsNullOrEmpty(fileName)) + throw new Exception("File name cannot be empty."); + + try + { + if (Win32.SHGetFileInfo(fileName, 0, out shinfo, + (uint)Marshal.SizeOf(shinfo), + Win32.ShgFiIcon | + (large ? Win32.ShgFiLargeIcon : Win32.ShgFiSmallIcon)) == 0) + { + return null; + } + else + { + return Icon.FromHandle(shinfo.hIcon); + } + } + catch + { + return null; + } + } + + public static string GetFileName(string fileName) + { + return GetFileName(fileName, false); + } + + public static string GetFileName(string fileName, bool canonicalize) + { + bool alreadyCanonicalized = false; + + // If the path starts with "\SystemRoot", we can replace it with C:\ (or whatever it is). + if (fileName.ToLower().StartsWith("\\systemroot")) + { + fileName = System.IO.Path.GetFullPath(Environment.SystemDirectory + "\\.." + fileName.Substring(11)); + alreadyCanonicalized = true; + } + // If the path starts with "\??\", we can remove it and we will have the path. + else if (fileName.StartsWith("\\??\\")) + { + fileName = fileName.Substring(4); + } + + // If the path still starts with a backslash, we probably need to + // resolve any native object name to a DOS drive letter. + if (fileName.StartsWith("\\")) + { + var prefixes = _fileNamePrefixes; + + foreach (var pair in prefixes) + { + if (fileName.StartsWith(pair.Key + "\\")) + { + fileName = pair.Value + "\\" + fileName.Substring(pair.Key.Length + 1); + break; + } + else if (fileName == pair.Key) + { + fileName = pair.Value; + break; + } + } + } + + if (canonicalize && !alreadyCanonicalized) + fileName = System.IO.Path.GetFullPath(fileName); + + return fileName; + } + + public static void RefreshFileNamePrefixes() + { + // Just create a new dictionary to avoid having to lock the existing one. + var newPrefixes = new Dictionary(); + + for (char c = 'A'; c <= 'Z'; c++) + { + using (var data = new MemoryAlloc(1024)) + { + int length; + + if ((length = Win32.QueryDosDevice(c.ToString() + ":", data, data.Size / 2)) > 2) + { + newPrefixes.Add(data.ReadUnicodeString(0, length - 2), c.ToString() + ":"); + } + } + } + + _fileNamePrefixes = newPrefixes; + } + + public static void ShowProperties(string fileName) + { + var info = new ShellExecuteInfo(); + + info.cbSize = Marshal.SizeOf(info); + info.lpFile = fileName; + info.nShow = ShowWindowType.Show; + info.fMask = Win32.SeeMaskInvokeIdList; + info.lpVerb = "properties"; + + Win32.ShellExecuteEx(ref info); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/ILoadedModule.cs b/branches/ph-plugins/ProcessHacker.Native/ILoadedModule.cs new file mode 100644 index 000000000..5dd450ca2 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/ILoadedModule.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native +{ + public interface ILoadedModule + { + IntPtr BaseAddress { get; } + int Size { get; } + LdrpDataTableEntryFlags Flags { get; } + string BaseName { get; } + string FileName { get; } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Image/ImageDirectoryEntry.cs b/branches/ph-plugins/ProcessHacker.Native/Image/ImageDirectoryEntry.cs new file mode 100644 index 000000000..896327cff --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Image/ImageDirectoryEntry.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Native.Image +{ + public enum ImageDataEntry : int + { + Export = 0, + Import = 1, + Resource = 2, + Exception = 3, + Security = 4, + BaseRelocation = 5, + Debug = 6, + Copyright = 7, + Architecture = 7, + GlobalPtr = 8, + Tls = 9, + LoadConfig = 10, + BoundImport = 11, + Iat = 12, + DelayImport = 13, + ComDescriptor = 14 + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Image/ImageExports.cs b/branches/ph-plugins/ProcessHacker.Native/Image/ImageExports.cs new file mode 100644 index 000000000..8cb4349f0 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Image/ImageExports.cs @@ -0,0 +1,171 @@ +/* + * Process Hacker - + * image exports reader + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Image +{ + public unsafe sealed class ImageExports + { + public delegate bool EnumEntriesDelegate(ImageExportEntry entry); + + private MappedImage _mappedImage; + private ImageDataDirectory* _dataDirectory; + private ImageExportDirectory* _exportDirectory; + private int* _addressTable; + private int* _namePointerTable; + private short* _ordinalTable; + + internal ImageExports(MappedImage mappedImage) + { + _mappedImage = mappedImage; + _dataDirectory = mappedImage.GetDataEntry(ImageDataEntry.Export); + _exportDirectory = mappedImage.GetExportDirectory(); + + if (_exportDirectory != null) + { + _addressTable = (int*)mappedImage.RvaToVa(_exportDirectory->AddressOfFunctions); + _namePointerTable = (int*)mappedImage.RvaToVa(_exportDirectory->AddressOfNames); + _ordinalTable = (short*)mappedImage.RvaToVa(_exportDirectory->AddressOfNameOrdinals); + } + } + + public int Count + { + get + { + if (_exportDirectory != null) + return _exportDirectory->NumberOfFunctions; + else + return 0; + } + } + + public ImageExportEntry GetEntry(int index) + { + if (_exportDirectory == null || _namePointerTable == null || _ordinalTable == null) + return ImageExportEntry.Empty; + if (index >= _exportDirectory->NumberOfFunctions) + return ImageExportEntry.Empty; + + ImageExportEntry entry = new ImageExportEntry(); + + entry.Ordinal = (short)(_ordinalTable[index] + _exportDirectory->Base); + + if (index < _exportDirectory->NumberOfNames) + entry.Name = new string((sbyte*)_mappedImage.RvaToVa(_namePointerTable[index])); + + return entry; + } + + public ImageExportFunction GetFunction(string name) + { + if (_exportDirectory == null || _namePointerTable == null || _ordinalTable == null) + return ImageExportFunction.Empty; + + int index; + + index = this.LookupName(name); + + if (index == -1) + return ImageExportFunction.Empty; + + return this.GetFunction((short)(_ordinalTable[index] + _exportDirectory->Base)); + } + + public ImageExportFunction GetFunction(short ordinal) + { + if (_exportDirectory == null || _addressTable == null) + return ImageExportFunction.Empty; + if (ordinal - _exportDirectory->Base >= _exportDirectory->NumberOfFunctions) + return ImageExportFunction.Empty; + + int rva = _addressTable[ordinal - _exportDirectory->Base]; + + if ( + rva >= _dataDirectory->VirtualAddress && + rva < _dataDirectory->VirtualAddress + _dataDirectory->Size + ) + { + // This is a forwarder RVA. + return new ImageExportFunction() { ForwardedName = new string((sbyte*)_mappedImage.RvaToVa(rva)) }; + } + else + { + // This is a function RVA. + return new ImageExportFunction() { Function = (IntPtr)_mappedImage.RvaToVa(rva) }; + } + } + + private int LookupName(string name) + { + int low = 0; + int high = _exportDirectory->NumberOfNames - 1; + + // Do a binary search. + while (low <= high) + { + int i; + string n; + + i = (low + high) / 2; + n = new string((sbyte*)_mappedImage.RvaToVa(_namePointerTable[i])); + + if (name == n) + { + return i; + } + else if (name.CompareTo(n) > 0) + { + low = i + 1; + } + else + { + high = i - 1; + } + } + + return -1; + } + } + + public struct ImageExportEntry + { + public static readonly ImageExportEntry Empty = new ImageExportEntry(); + + public string Name; + public short Ordinal; + } + + public struct ImageExportFunction + { + public static readonly ImageExportFunction Empty = new ImageExportFunction(); + + public IntPtr Function; + public string ForwardedName; + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Image/ImageImports.cs b/branches/ph-plugins/ProcessHacker.Native/Image/ImageImports.cs new file mode 100644 index 000000000..db466a7fb --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Image/ImageImports.cs @@ -0,0 +1,200 @@ +/* + * Process Hacker - + * image imports reader + * + * Copyright (C) 2009 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 . + */ + +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native.Image +{ + public unsafe sealed class ImageImports + { + public delegate bool EnumEntriesDelegate(ImageExportEntry entry); + + private MappedImage _mappedImage; + private int _count; + private ImageImportDescriptor* _descriptorTable; + private ImageImportDll[] _dlls; + + internal ImageImports(MappedImage mappedImage) + { + _mappedImage = mappedImage; + _descriptorTable = mappedImage.GetImportDirectory(); + + // Do a quick scan. + if (_descriptorTable != null) + { + int i = 0; + + while (_descriptorTable[i].OriginalFirstThunk != 0 || _descriptorTable[i].FirstThunk != 0) + i++; + + _count = i; + _dlls = new ImageImportDll[i]; + } + } + + public ImageImportDll this[int index] + { + get { return this.GetDll(index); } + } + + public int Count + { + get { return _count; } + } + + public ImageImportDll GetDll(int index) + { + if (_descriptorTable == null) + return null; + + if (index < _count) + { + if (_dlls[index] == null) + _dlls[index] = new ImageImportDll(_mappedImage, &_descriptorTable[index]); + + return _dlls[index]; + } + else + { + return null; + } + } + } + + public unsafe sealed class ImageImportDll + { + private MappedImage _mappedImage; + private ImageImportDescriptor* _descriptor; + private string _name; + private void* _lookupTable; + private int _count; + + internal ImageImportDll(MappedImage mappedImage, ImageImportDescriptor* descriptor) + { + _mappedImage = mappedImage; + _descriptor = descriptor; + + if (_descriptor->OriginalFirstThunk != 0) + _lookupTable = _mappedImage.RvaToVa(_descriptor->OriginalFirstThunk); + else + _lookupTable = _mappedImage.RvaToVa(_descriptor->FirstThunk); + + // Do a quick scan. + if (_lookupTable != null) + { + int i = 0; + + if (_mappedImage.Magic == Win32.Pe32Magic) + { + while (((int*)_lookupTable)[i] != 0) + i++; + } + else if (_mappedImage.Magic == Win32.Pe32PlusMagic) + { + while (((long*)_lookupTable)[i] != 0) + i++; + } + + _count = i; + } + } + + public ImageImportEntry this[int index] + { + get { return this.GetEntry(index); } + } + + public int Count + { + get { return _count; } + } + + public string Name + { + get + { + if (_name == null) + _name = new string((sbyte*)_mappedImage.RvaToVa(_descriptor->Name)); + + return _name; + } + } + + public ImageImportEntry GetEntry(int index) + { + if (index >= _count) + return ImageImportEntry.Empty; + + if (_mappedImage.Magic == Win32.Pe32Magic) + { + int entry = ((int*)_lookupTable)[index]; + + // Is this entry using an ordinal? + if ((entry & 0x80000000) != 0) + { + return new ImageImportEntry() { Ordinal = (short)(entry & 0xffff) }; + } + else + { + ImageImportByName* nameEntry = (ImageImportByName*)_mappedImage.RvaToVa(entry); + + return new ImageImportEntry() + { + NameHint = nameEntry->Hint, + Name = new string((sbyte*)&nameEntry->Name) + }; + } + } + else if (_mappedImage.Magic == Win32.Pe32PlusMagic) + { + long entry = ((long*)_lookupTable)[index]; + + // Is this entry using an ordinal? + if (((ulong)entry & 0x8000000000000000) != 0) + { + return new ImageImportEntry() { Ordinal = (short)(entry & 0xffff) }; + } + else + { + ImageImportByName* nameEntry = (ImageImportByName*)_mappedImage.RvaToVa((int)(entry & 0xffffffff)); + + return new ImageImportEntry() + { + NameHint = nameEntry->Hint, + Name = new string((sbyte*)&nameEntry->Name) + }; + } + } + + return ImageImportEntry.Empty; + } + } + + public struct ImageImportEntry + { + public static readonly ImageImportEntry Empty; + + public short Ordinal; + public short NameHint; + public string Name; + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Image/MappedImage.cs b/branches/ph-plugins/ProcessHacker.Native/Image/MappedImage.cs new file mode 100644 index 000000000..f9ed43ac0 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Image/MappedImage.cs @@ -0,0 +1,314 @@ +/* + * Process Hacker - + * image mapper and reader + * + * Copyright (C) 2009 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 . + */ + +using System; +using ProcessHacker.Common.Objects; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Image +{ + public unsafe sealed class MappedImage : BaseObject + { + private SectionView _view; + private int _size; + private void* _memory; + private ImageNtHeaders* _ntHeaders; + private ImageSectionHeader* _sections; + private short _magic; + + private ImageExports _exports; + private ImageImports _imports; + + public MappedImage(string fileName) + : this(fileName, true) + { } + + public MappedImage(string fileName, bool readOnly) + { + using (var fhandle = FileHandle.CreateWin32( + fileName, + readOnly ? (FileAccess.Execute | FileAccess.ReadAttributes | FileAccess.ReadData) : + (FileAccess.AppendData | FileAccess.Execute | FileAccess.ReadAttributes | FileAccess.ReadData | FileAccess.WriteAttributes | FileAccess.WriteData), + FileShareMode.Read, + FileCreationDispositionWin32.OpenExisting + )) + this.MapAndLoad(fhandle, readOnly); + } + + public MappedImage(FileHandle fileHandle, bool readOnly) + { + this.MapAndLoad(fileHandle, readOnly); + } + + protected override void DisposeObject(bool disposing) + { + if (_view != null) + _view.Dispose(disposing); + } + + public ImageExports Exports + { + get + { + if (_exports == null) + _exports = new ImageExports(this); + + return _exports; + } + } + + public ImageImports Imports + { + get + { + if (_imports == null) + _imports = new ImageImports(this); + + return _imports; + } + } + + public short Magic + { + get { return _magic; } + } + + public void* Memory + { + get { return _memory; } + } + + public int NumberOfDataEntries + { + get + { + if (_magic == Win32.Pe32Magic) + return this.GetOptionalHeader()->NumberOfRvaAndSizes; + else if (_magic == Win32.Pe32PlusMagic) + return this.GetOptionalHeader64()->NumberOfRvaAndSizes; + else + return 0; + } + } + + public int NumberOfSections + { + get { return _ntHeaders->FileHeader.NumberOfSections; } + } + + public ImageNtHeaders* NtHeaders + { + get { return _ntHeaders; } + } + + public ImageSectionHeader* Sections + { + get { return _sections; } + } + + public int Size + { + get { return _size; } + } + + public int GetChecksum() + { + int oldChecksum; + + return this.GetChecksum(out oldChecksum); + } + + public int GetChecksum(out int oldChecksum) + { + int checksum; + + if (Win32.CheckSumMappedFile(_view, _size, out oldChecksum, out checksum) == IntPtr.Zero) + Win32.ThrowLastError(); + + return checksum; + } + + public ImageDataDirectory* GetDataEntry(ImageDataEntry entry) + { + if (_magic == Win32.Pe32Magic) + { + if ((int)entry >= _ntHeaders->OptionalHeader.NumberOfRvaAndSizes) + return null; + + return &(&_ntHeaders->OptionalHeader.DataDirectory)[(int)entry]; + } + else if (_magic == Win32.Pe32PlusMagic) + { + if ((int)entry >= this.GetOptionalHeader64()->NumberOfRvaAndSizes) + return null; + + return &(&this.GetOptionalHeader64()->DataDirectory)[(int)entry]; + } + else + { + return null; + } + } + + public ImageExportDirectory* GetExportDirectory() + { + ImageDataDirectory* dataEntry; + + dataEntry = this.GetDataEntry(ImageDataEntry.Export); + + return (ImageExportDirectory*)this.RvaToVa(dataEntry->VirtualAddress); + } + + public ImageImportDescriptor* GetImportDirectory() + { + ImageDataDirectory* dataEntry; + + dataEntry = this.GetDataEntry(ImageDataEntry.Import); + + return (ImageImportDescriptor*)this.RvaToVa(dataEntry->VirtualAddress); + } + + private void* GetLoadConfig(short magic) + { + ImageDataDirectory* dataEntry; + + if (_magic != magic) + return null; + + dataEntry = this.GetDataEntry(ImageDataEntry.LoadConfig); + + if (dataEntry == null) + return null; + + return this.RvaToVa(dataEntry->VirtualAddress); + } + + public ImageLoadConfigDirectory* GetLoadConfig() + { + return (ImageLoadConfigDirectory*)this.GetLoadConfig(Win32.Pe32Magic); + } + + public ImageLoadConfigDirectory64* GetLoadConfig64() + { + return (ImageLoadConfigDirectory64*)this.GetLoadConfig(Win32.Pe32PlusMagic); + } + + private ImageNtHeaders* GetNtHeaders() + { + int offset; + ImageNtHeaders* ntHeaders; + + offset = *((int*)((byte*)_memory + 0x3c)); + + if (offset == 0) + throw new Exception("Invalid NT headers offset."); + if (offset >= 0x10000000 || offset >= _size) + throw new Exception("The NT headers offset is too large."); + + ntHeaders = (ImageNtHeaders*)((byte*)_memory + offset); + + return ntHeaders; + } + + private void* GetOptionalHeader(short magic) + { + if (_magic != magic) + return null; + + return &_ntHeaders->OptionalHeader; + } + + public ImageOptionalHeader* GetOptionalHeader() + { + return (ImageOptionalHeader*)this.GetOptionalHeader(Win32.Pe32Magic); + } + + public ImageOptionalHeader64* GetOptionalHeader64() + { + return (ImageOptionalHeader64*)this.GetOptionalHeader(Win32.Pe32PlusMagic); + } + + public string GetSectionName(ImageSectionHeader* section) + { + return new string((sbyte*)section->Name, 0, 8).TrimEnd('\0'); + } + + private void MapAndLoad(FileHandle fileHandle, bool readOnly) + { + using (Section section = new Section( + fileHandle, + false, + readOnly ? MemoryProtection.ExecuteRead : MemoryProtection.ExecuteReadWrite + )) + { + _size = (int)fileHandle.GetSize(); + _view = section.MapView(_size); + _memory = _view; + + byte* start = (byte*)_memory; + + if (start[0] != 'M' || start[1] != 'Z') + throw new Exception("The file is not a valid executable image."); + + _ntHeaders = this.GetNtHeaders(); + _sections = (ImageSectionHeader*)((byte*)&_ntHeaders->OptionalHeader + _ntHeaders->FileHeader.SizeOfOptionalHeader); + _magic = _ntHeaders->OptionalHeader.Magic; + + if (_magic != Win32.Pe32Magic && _magic != Win32.Pe32PlusMagic) + throw new Exception("The file is not a PE32 or PE32+ image."); + } + } + + public ImageSectionHeader* RvaToSection(int rva) + { + if (_ntHeaders->FileHeader.NumberOfSections == 0) + return null; + + for (int i = 0; i < _ntHeaders->FileHeader.NumberOfSections; i++) + { + if ( + rva >= _sections[i].VirtualAddress && + rva < (_sections[i].VirtualAddress + _sections[i].SizeOfRawData) + ) + { + return &_sections[i]; + } + } + + return null; + } + + public void* RvaToVa(int rva) + { + ImageSectionHeader* section; + + section = this.RvaToSection(rva); + + if (section == null) + return null; + + return (byte*)_memory + section->PointerToRawData - section->VirtualAddress + rva; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/ImpersonationContext.cs b/branches/ph-plugins/ProcessHacker.Native/ImpersonationContext.cs new file mode 100644 index 000000000..a0d3a0d33 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/ImpersonationContext.cs @@ -0,0 +1,26 @@ +using System; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; + +namespace ProcessHacker.Native +{ + public class ImpersonationContext : IDisposable + { + private bool _disposed = false; + + public ImpersonationContext(TokenHandle token) + { + if (!Win32.ImpersonateLoggedOnUser(token)) + Win32.ThrowLastError(); + } + + public void Dispose() + { + if (!_disposed) + { + Win32.RevertToSelf(); + _disposed = true; + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/IntPtrExtensions.cs b/branches/ph-plugins/ProcessHacker.Native/IntPtrExtensions.cs new file mode 100644 index 000000000..f23e9f93a --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/IntPtrExtensions.cs @@ -0,0 +1,246 @@ +/* + * Process Hacker - + * IntPtr extension functions + * + * Copyright (C) 2009 wj32 + * Copyright (C) 2009 Flavio Erlich + * + * 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 . + */ + +using System; +using System.Runtime.InteropServices; + +namespace ProcessHacker.Native +{ + public static class IntPtrExtensions + { + public static IntPtr And(this IntPtr ptr, int value) + { + if (IntPtr.Size == sizeof(Int32)) + return new IntPtr(ptr.ToInt32() & value); + else + return new IntPtr(ptr.ToInt64() & value); + } + + public static IntPtr And(this IntPtr ptr, IntPtr value) + { + if (IntPtr.Size == sizeof(Int32)) + return new IntPtr(ptr.ToInt32() & value.ToInt32()); + else + return new IntPtr(ptr.ToInt64() & value.ToInt64()); + } + + public static int CompareTo(this IntPtr ptr, IntPtr ptr2) + { + if (ptr.ToUInt64() > ptr2.ToUInt64()) + return 1; + if (ptr.ToUInt64() < ptr2.ToUInt64()) + return -1; + return 0; + } + + public static int CompareTo(this IntPtr ptr, int ptr2) + { + return ptr.CompareTo((uint)ptr2); + } + + public static int CompareTo(this IntPtr ptr, uint ptr2) + { + if (ptr.ToUInt64() > ptr2) + return 1; + if (ptr.ToUInt64() < ptr2) + return -1; + return 0; + } + + public static IntPtr Decrement(this IntPtr ptr, IntPtr ptr2) + { + if (IntPtr.Size == sizeof(Int32)) + return new IntPtr(ptr.ToInt32() - ptr2.ToInt32()); + else + return new IntPtr(ptr.ToInt64() - ptr2.ToInt64()); + } + + public static IntPtr Decrement(this IntPtr ptr, int value) + { + return Increment(ptr, -value); + } + + public static IntPtr Decrement(this IntPtr ptr, long value) + { + return Increment(ptr, -value); + } + + public static T ElementAt(this IntPtr ptr, int index) + { + var offset = Marshal.SizeOf(typeof(T)) * index; + var offsetPtr = ptr.Increment(offset); + return (T)Marshal.PtrToStructure(offsetPtr, typeof(T)); + } + + public static bool Equals(this IntPtr ptr, IntPtr ptr2) + { + return ptr == ptr2; + } + + public static bool Equals(this IntPtr ptr, int value) + { + return ptr.ToInt32() == value; + } + + public static bool Equals(this IntPtr ptr, uint value) + { + return ptr.ToUInt32() == value; + } + + public static bool Equals(this IntPtr ptr, long value) + { + return ptr.ToInt64() == value; + } + + public static bool Equals(this IntPtr ptr, ulong value) + { + return ptr.ToUInt64() == value; + } + + public static IntPtr Increment(this IntPtr ptr, int value) + { + unchecked + { + if (IntPtr.Size == sizeof(Int32)) + return new IntPtr(ptr.ToInt32() + value); + else + return new IntPtr(ptr.ToInt64() + value); + } + } + + public static IntPtr Increment(this IntPtr ptr, long value) + { + unchecked + { + if (IntPtr.Size == sizeof(Int32)) + return new IntPtr((int)(ptr.ToInt32() + value)); + else + return new IntPtr(ptr.ToInt64() + value); + } + } + + public static IntPtr Increment(this IntPtr ptr, IntPtr ptr2) + { + unchecked + { + if (IntPtr.Size == sizeof(Int32)) + return new IntPtr(ptr.ToInt32() + ptr2.ToInt32()); + else + return new IntPtr(ptr.ToInt64() + ptr2.ToInt64()); + } + } + + public static IntPtr Increment(this IntPtr ptr) + { + return ptr.Increment(Marshal.SizeOf(typeof(T))); + } + + public static bool IsGreaterThanOrEqualTo(this IntPtr ptr, IntPtr ptr2) + { + return ptr.CompareTo(ptr2) >= 0; + } + + public static bool IsLessThanOrEqualTo(this IntPtr ptr, IntPtr ptr2) + { + return ptr.CompareTo(ptr2) <= 0; + } + + public static IntPtr Not(this IntPtr ptr) + { + if (IntPtr.Size == sizeof(Int32)) + return new IntPtr(~ptr.ToInt32()); + else + return new IntPtr(~ptr.ToInt64()); + } + + public static IntPtr Or(this IntPtr ptr, IntPtr value) + { + if (IntPtr.Size == sizeof(Int32)) + return new IntPtr(ptr.ToInt32() | value.ToInt32()); + else + return new IntPtr(ptr.ToInt64() | value.ToInt64()); + } + + public static uint ToUInt32(this IntPtr ptr) + { + // Avoid sign-extending the pointer - we want it zero-extended. + unsafe + { + void* voidPtr = (void*)ptr; + + return (uint)voidPtr; + } + } + + public static ulong ToUInt64(this IntPtr ptr) + { + // Avoid sign-extending the pointer - we want it zero-extended. + unsafe + { + void* voidPtr = (void*)ptr; + + return (ulong)voidPtr; + } + } + + public static IntPtr ToIntPtr(this int value) + { + return new IntPtr(value); + } + + public static IntPtr ToIntPtr(this uint value) + { + unchecked + { + return new IntPtr((int)value); + } + } + + public static IntPtr ToIntPtr(this long value) + { + unchecked + { + if (value > 0 && value <= 0xffffffff) + return new IntPtr((int)value); + } + + return new IntPtr(value); + } + + public static IntPtr ToIntPtr(this ulong value) + { + unchecked + { + return ((long)value).ToIntPtr(); + } + } + + public static IntPtr Xor(this IntPtr ptr, IntPtr value) + { + if (IntPtr.Size == sizeof(Int32)) + return new IntPtr(ptr.ToInt32() ^ value.ToInt32()); + else + return new IntPtr(ptr.ToInt64() ^ value.ToInt64()); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Io/BeepDevice.cs b/branches/ph-plugins/ProcessHacker.Native/Io/BeepDevice.cs new file mode 100644 index 000000000..d120109ea --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Io/BeepDevice.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Io +{ + public static class BeepDevice + { + public struct BeepSetParameters + { + public int Frequency; + public int Duration; + } + + public const int BeepFrequencyMinimum = 0x25; + public const int BeepFrequencyMaximum = 0x7fff; + + public static readonly int IoCtlSet = Win32.CtlCode(DeviceType.Beep, 0, DeviceControlMethod.Buffered, DeviceControlAccess.Any); + + public static void Beep(int frequency, int duration) + { + unsafe + { + BeepSetParameters p; + + p.Frequency = frequency; + p.Duration = duration; + + using (var fhandle = OpenBeep(FileAccess.GenericRead)) + fhandle.IoControl(IoCtlSet, &p, Marshal.SizeOf(typeof(BeepSetParameters)), null, 0); + } + } + + private static FileHandle OpenBeep(FileAccess access) + { + return new FileHandle( + Win32.BeepDeviceName, + FileShareMode.ReadWrite, + access + ); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Io/MountManager.cs b/branches/ph-plugins/ProcessHacker.Native/Io/MountManager.cs new file mode 100644 index 000000000..ed53ffd26 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Io/MountManager.cs @@ -0,0 +1,191 @@ +/* + * Process Hacker - + * mount point manager API + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Io +{ + public static class MountManager + { + // Input for IoCtlCreatePoint + public struct MountMgrCreatePointInput + { + public ushort SymbolicLinkNameOffset; + public ushort SymbolicLinkNameLength; + public ushort DeviceNameOffset; + public ushort DeviceNameLength; + } + + // Input for IoCtlDeletePoints, IoCtlQueryPoints and IoCtlDeletePointsDbOnly + public struct MountMgrMountPoint + { + public int SymbolicLinkNameOffset; + public ushort SymbolicLinkNameLength; + public int UniqueIdOffset; + public ushort UniqueIdLength; + public int DeviceNameOffset; + public ushort DeviceNameLength; + } + + // Output for IoCtlDeletePoints, IoCtlQueryPoints and IoCtlDeletePointsDbOnly + public struct MountMgrMountPoints + { + public static int MountPointsOffset = + Marshal.OffsetOf(typeof(MountMgrMountPoints), "MountPoints").ToInt32(); + + public int Size; + public int NumberOfMountPoints; + public MountMgrMountPoint MountPoints; + } + + // Input for IoCtlNextDriveLetter + public struct MountMgrDriveLetterTarget + { + public static int DeviceNameOffset = + Marshal.OffsetOf(typeof(MountMgrDriveLetterTarget), "DeviceName").ToInt32(); + + public ushort DeviceNameLength; + public short DeviceName; + } + + // Output for IoCtlNextDriveLetter + public struct MountMgrDriveLetterInformation + { + [MarshalAs(UnmanagedType.I1)] + public bool DriveLetterWasAssigned; + [MarshalAs(UnmanagedType.I1)] + public char CurrentDriveLetter; + } + + // Input for IoCtlVolumeMountPointCreated and IoCtlVolumeMountPointDeleted + public struct MountMgrVolumeMountPoint + { + public ushort SourceVolumeNameOffset; + public ushort SourceVolumeNameLength; + public ushort TargetVolumeNameOffset; + public ushort TargetVolumeNameLength; + } + + // Input, output for IoCtlChangeNotify + public struct MountMgrChangeNotifyInfo + { + public int EpicNumber; + } + + // Input for IoCtlKeepLinksWhenOffline, IoCtlVolumeArrivalNotification, + // IoCtlQueryDosVolumePath, IoCtlQueryDosVolumePaths + public struct MountMgrTargetName + { + public static int DeviceNameOffset = + Marshal.OffsetOf(typeof(MountMgrTargetName), "DeviceName").ToInt32(); + + public ushort DeviceNameLength; + public short DeviceName; + } + + // Output for IoCtlQueryDosVolumePath, IoCtlQueryDosVolumePaths + public struct MountMgrVolumePaths + { + public static int MultiSzOffset = + Marshal.OffsetOf(typeof(MountMgrVolumePaths), "MultiSz").ToInt32(); + + public int MultiSzLength; + public short MultiSz; + } + + // Output for IoCtlQueryDeviceName + public struct MountDevName + { + public static int NameOffset = + Marshal.OffsetOf(typeof(MountDevName), "Name").ToInt32(); + + public ushort NameLength; + public short Name; + } + + public static readonly int IoCtlCreatePoint = Win32.CtlCode(DeviceType.MountMgr, 0, DeviceControlMethod.Buffered, DeviceControlAccess.Read | DeviceControlAccess.Write); + public static readonly int IoCtlDeletePoints = Win32.CtlCode(DeviceType.MountMgr, 1, DeviceControlMethod.Buffered, DeviceControlAccess.Read | DeviceControlAccess.Write); + public static readonly int IoCtlQueryPoints = Win32.CtlCode(DeviceType.MountMgr, 2, DeviceControlMethod.Buffered, DeviceControlAccess.Any); + public static readonly int IoCtlDeletePointsDbOnly = Win32.CtlCode(DeviceType.MountMgr, 3, DeviceControlMethod.Buffered, DeviceControlAccess.Read | DeviceControlAccess.Write); + public static readonly int IoCtlNextDriveLetter = Win32.CtlCode(DeviceType.MountMgr, 4, DeviceControlMethod.Buffered, DeviceControlAccess.Read | DeviceControlAccess.Write); + public static readonly int IoCtlAutoDlAssignments = Win32.CtlCode(DeviceType.MountMgr, 5, DeviceControlMethod.Buffered, DeviceControlAccess.Read | DeviceControlAccess.Write); + public static readonly int IoCtlVolumeMountPointCreated = Win32.CtlCode(DeviceType.MountMgr, 6, DeviceControlMethod.Buffered, DeviceControlAccess.Read | DeviceControlAccess.Write); + public static readonly int IoCtlVolumeMountPointDeleted = Win32.CtlCode(DeviceType.MountMgr, 7, DeviceControlMethod.Buffered, DeviceControlAccess.Read | DeviceControlAccess.Write); + public static readonly int IoCtlChangeNotify = Win32.CtlCode(DeviceType.MountMgr, 8, DeviceControlMethod.Buffered, DeviceControlAccess.Read); + public static readonly int IoCtlKeepLinksWhenOffline = Win32.CtlCode(DeviceType.MountMgr, 9, DeviceControlMethod.Buffered, DeviceControlAccess.Read | DeviceControlAccess.Write); + public static readonly int IoCtlCheckUnprocessedVolumes = Win32.CtlCode(DeviceType.MountMgr, 10, DeviceControlMethod.Buffered, DeviceControlAccess.Read); + public static readonly int IoCtlVolumeArrivalNotification = Win32.CtlCode(DeviceType.MountMgr, 11, DeviceControlMethod.Buffered, DeviceControlAccess.Read); + public static readonly int IoCtlQueryDosVolumePath = Win32.CtlCode(DeviceType.MountMgr, 12, DeviceControlMethod.Buffered, DeviceControlAccess.Any); + public static readonly int IoCtlQueryDosVolumePaths = Win32.CtlCode(DeviceType.MountMgr, 13, DeviceControlMethod.Buffered, DeviceControlAccess.Any); + public static readonly int IoCtlScrubRegistry = Win32.CtlCode(DeviceType.MountMgr, 14, DeviceControlMethod.Buffered, DeviceControlAccess.Read | DeviceControlAccess.Write); + public static readonly int IoCtlQueryAutoMount = Win32.CtlCode(DeviceType.MountMgr, 15, DeviceControlMethod.Buffered, DeviceControlAccess.Any); + public static readonly int IoCtlSetAutoMount = Win32.CtlCode(DeviceType.MountMgr, 16, DeviceControlMethod.Buffered, DeviceControlAccess.Read | DeviceControlAccess.Write); + + public static readonly int IoCtlQueryDeviceName = Win32.CtlCode(DeviceType.MountMgrDevice, 2, DeviceControlMethod.Buffered, DeviceControlAccess.Any); + + public static bool IsDriveLetterPath(string path) + { + if ( + path.Length == 14 && + path.StartsWith(@"\DosDevices\") && + path[12] >= 'A' && path[12] <= 'Z' && + path[13] == ':' + ) + return true; + else + return false; + } + + public static bool IsVolumePath(string path) + { + if ( + (path.Length == 48 || (path.Length == 49 && path[48] == '\\')) && + (path.StartsWith(@"\??\Volume") || path.StartsWith(@"\\?\Volume")) && + path[10] == '{' && + path[19] == '-' && + path[24] == '-' && + path[29] == '-' && + path[34] == '-' && + path[47] == '}' + ) + return true; + else + return false; + } + + private static FileHandle OpenMountManager(FileAccess access) + { + return new FileHandle( + Win32.MountMgrDeviceName, + FileShareMode.ReadWrite, + access + ); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Ipc/IpcCircularBuffer.cs b/branches/ph-plugins/ProcessHacker.Native/Ipc/IpcCircularBuffer.cs new file mode 100644 index 000000000..d8f935285 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Ipc/IpcCircularBuffer.cs @@ -0,0 +1,223 @@ +/* + * Process Hacker - + * inter-process circular buffer + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Runtime.InteropServices; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; +using ProcessHacker.Native.Threading; + +namespace ProcessHacker.Native.Ipc +{ + public unsafe class IpcCircularBuffer + { + [StructLayout(LayoutKind.Sequential)] + private struct BufferHeader + { + public int BlockSize; + public int NumberOfBlocks; + + public long ReadSemaphoreId; + public long WriteSemaphoreId; + + public int ReadPosition; + public int WritePosition; + + public long Data; + } + + public static IpcCircularBuffer Create(string name, int blockSize, int numberOfBlocks) + { + Random r = new Random(); + long readSemaphoreId = ((long)r.Next() << 32) + r.Next(); + long writeSemaphoreId = ((long)r.Next() << 32) + r.Next(); + Section section; + + section = new Section(name, blockSize * numberOfBlocks, MemoryProtection.ReadWrite); + + using (var view = section.MapView(Marshal.SizeOf(typeof(BufferHeader)))) + { + BufferHeader header = new BufferHeader(); + + header.BlockSize = blockSize; + header.NumberOfBlocks = numberOfBlocks; + header.ReadSemaphoreId = readSemaphoreId; + header.WriteSemaphoreId = writeSemaphoreId; + header.ReadPosition = 0; + header.WritePosition = 0; + + view.WriteStruct(header); + } + + return new IpcCircularBuffer( + section, + name, + new Semaphore(name + "_" + readSemaphoreId.ToString("x"), 0, numberOfBlocks), + new Semaphore(name + "_" + writeSemaphoreId.ToString("x"), numberOfBlocks, numberOfBlocks) + ); + } + + public static IpcCircularBuffer Open(string name) + { + return new IpcCircularBuffer(new Section(name, SectionAccess.All), name, null, null); + } + + private Section _section; + private SectionView _sectionView; + private Semaphore _readSemaphore; + private Semaphore _writeSemaphore; + + private BufferHeader* _header; + private void* _data; + + private IpcCircularBuffer(Section section, string sectionName, Semaphore readSemaphore, Semaphore writeSemaphore) + { + BufferHeader header; + + _section = section; + + _sectionView = section.MapView(Marshal.SizeOf(typeof(BufferHeader))); + header = _sectionView.ReadStruct(); + _sectionView.Dispose(); + + if (readSemaphore == null || writeSemaphore == null) + { + _readSemaphore = new Semaphore(sectionName + "_" + header.ReadSemaphoreId.ToString("x")); + _writeSemaphore = new Semaphore(sectionName + "_" + header.WriteSemaphoreId.ToString("x")); + } + else + { + _readSemaphore = readSemaphore; + _writeSemaphore = writeSemaphore; + } + + _sectionView = _section.MapView(header.BlockSize * header.NumberOfBlocks); + _header = (BufferHeader*)_sectionView.Memory; + _data = &_header->Data; + } + + public T Read() + where T : struct + { + using (var data = this.Read()) + return data.ReadStruct(); + } + + public MemoryAlloc Read() + { + var data = new MemoryAlloc(_header->BlockSize); + + this.Read(data); + + return data; + } + + public void Read(MemoryRegion data) + { + this.Read((void*)data.Memory); + } + + public void Read(void* buffer) + { + int readPosition; + + // Wait for a block to read. + _readSemaphore.Wait(); + + // Get a read position while simultaneously incrementing it + // and wrapping it if necessary. + while (true) + { + readPosition = _header->ReadPosition; + + if (System.Threading.Interlocked.CompareExchange( + ref _header->ReadPosition, + (readPosition + 1) % _header->NumberOfBlocks, + readPosition + ) == readPosition) + break; + } + + // Copy the data across. + Win32.RtlMoveMemory( + new IntPtr(buffer), + (new IntPtr(_data)).Increment(readPosition * _header->BlockSize), + _header->BlockSize.ToIntPtr() + ); + + // Release the write semaphore to allow a writer to write one more block. + _writeSemaphore.Release(); + } + + public void Write(T s) + where T : struct + { + using (var data = new MemoryAlloc(Marshal.SizeOf(typeof(T)))) + { + data.WriteStruct(s); + this.Write((MemoryRegion)data); + } + } + + public void Write(MemoryRegion data) + { + this.Write(data, 0); + } + + public void Write(MemoryRegion data, int offset) + { + this.Write((void*)data.Memory.Increment(offset)); + } + + public void Write(void* buffer) + { + int writePosition; + + // Wait for an available write slot. + _writeSemaphore.Wait(); + + // Get a write position while simultaneously incrementing it + // and wrapping it if necessary. + while (true) + { + writePosition = _header->WritePosition; + + if (System.Threading.Interlocked.CompareExchange( + ref _header->WritePosition, + (writePosition + 1) % _header->NumberOfBlocks, + writePosition + ) == writePosition) + break; + } + + // Copy the data across. + Win32.RtlMoveMemory( + (new IntPtr(_data)).Increment(writePosition * _header->BlockSize), + new IntPtr(buffer), + _header->BlockSize.ToIntPtr() + ); + + // Release the read semaphore to allow a reader to read one more block. + _readSemaphore.Release(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/KProcessHacker.cs b/branches/ph-plugins/ProcessHacker.Native/KProcessHacker.cs new file mode 100644 index 000000000..ed4a0977b --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/KProcessHacker.cs @@ -0,0 +1,1258 @@ +/* + * Process Hacker - + * KProcessHacker interfacing code + * + * Copyright (C) 2009 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 private field 'field' is assigned but its value is never used +#pragma warning disable 0414 + +using System; +using System.Runtime.InteropServices; +using System.Text; +using System.Windows.Forms; +using ProcessHacker.Common.Objects; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native +{ + /// + /// Provides an interface to KProcessHacker. + /// + public sealed unsafe class KProcessHacker + { + private static KProcessHacker _instance; + + public static KProcessHacker Instance + { + get { return _instance; } + set { _instance = value; } + } + + /// + /// A control code used by KProcessHacker to represent a specific function. + /// + private enum Control : uint + { + ClientCloseHandle = 0, + SsQueryClientEntry, + Reserved1, + KphOpenProcess, + KphOpenThread, + KphOpenProcessToken, + GetProcessProtected, + SetProcessProtected, + KphTerminateProcess, + KphSuspendProcess, + KphResumeProcess, + KphReadVirtualMemory, + KphWriteVirtualMemory, + SetProcessToken, + GetThreadStartAddress, + SetHandleAttributes, + GetHandleObjectName, + KphOpenProcessJob, + KphGetContextThread, + KphSetContextThread, + KphGetThreadWin32Thread, + KphDuplicateObject, + ZwQueryObject, + KphGetProcessId, + KphGetThreadId, + KphTerminateThread, + GetFeatures, + KphSetHandleGrantedAccess, + KphAssignImpersonationToken, + ProtectAdd, + ProtectRemove, + ProtectQuery, + KphUnsafeReadVirtualMemory, + SetExecuteOptions, + KphQueryProcessHandles, + KphOpenThreadProcess, + KphCaptureStackBackTraceThread, + KphDangerousTerminateThread, + KphOpenDevice, + KphOpenDriver, + KphQueryInformationDriver, + KphOpenDirectoryObject, + SsRef, + SsUnref, + SsCreateClientEntry, + SsCreateRuleSetEntry, + SsRemoveRule, + SsAddProcessIdRule, + SsAddThreadIdRule, + SsAddPreviousModeRule, + SsAddNumberRule, + SsEnableClientEntry + } + + [Flags] + public enum KphFeatures : int + { + PsTerminateProcess = 0x1, + PspTerminateThreadByPointer = 0x2 + } + + private string _deviceName; + private FileHandle _fileHandle; + private uint _baseControlNumber; + private KphFeatures _features; + + /// + /// Creates a connection to KProcessHacker. + /// + public KProcessHacker() + : this("KProcessHacker") + { } + + /// + /// Creates a connection to KProcessHacker. + /// + /// The name of the KProcessHacker service and device. + public KProcessHacker(string deviceName) + : this(deviceName, Application.StartupPath + "\\kprocesshacker.sys") + { } + + /// + /// Creates a connection to KProcessHacker. + /// + /// The name of the KProcessHacker service and device. + /// The file name of the KProcessHacker driver. + public KProcessHacker(string deviceName, string fileName) + { + _deviceName = deviceName; + + if (IntPtr.Size != 4) + throw new NotSupportedException("KProcessHacker does not support 64-bit Windows."); + + try + { + _fileHandle = new FileHandle( + @"\Device\" + deviceName, + 0, + FileAccess.GenericRead | FileAccess.GenericWrite + ); + } + catch (WindowsException ex) + { + if ( + ex.Status == NtStatus.NoSuchDevice || + ex.Status == NtStatus.NoSuchFile || + ex.Status == NtStatus.ObjectNameNotFound + ) + { + // Attempt to load the driver, then try again. + ServiceHandle shandle; + + using (var scm = new ServiceManagerHandle(ScManagerAccess.CreateService)) + { + shandle = scm.CreateService( + deviceName, + deviceName, + ServiceType.KernelDriver, + fileName + ); + shandle.Start(); + } + + try + { + _fileHandle = new FileHandle( + @"\Device\" + deviceName, + 0, + FileAccess.GenericRead | FileAccess.GenericWrite + ); + } + finally + { + // The SCM will delete the service when it is stopped. + shandle.Delete(); + } + } + else + { + throw ex; + } + } + + _fileHandle.SetHandleFlags(Win32HandleFlags.ProtectFromClose, Win32HandleFlags.ProtectFromClose); + + byte[] bytes = _fileHandle.Read(4); + + fixed (byte* bytesPtr = bytes) + _baseControlNumber = *(uint*)bytesPtr; + + try + { + _features = this.GetFeatures(); + } + catch + { } + } + + public string DeviceName + { + get { return _deviceName; } + } + + public KphFeatures Features + { + get { return _features; } + } + + private int CtlCode(Control ctl) + { + return (int)(_baseControlNumber + ((uint)ctl * 4)); + } + + /// + /// Closes the connection to KProcessHacker. + /// + public void Close() + { + _fileHandle.SetHandleFlags(Win32HandleFlags.ProtectFromClose, 0); + _fileHandle.Dispose(); + } + + public void ClientCloseHandle(IntPtr handle) + { + byte* inData = stackalloc byte[4]; + + *(int*)inData = handle.ToInt32(); + + _fileHandle.IoControl(CtlCode(Control.ClientCloseHandle), inData, 4, null, 0); + } + + public KphFeatures GetFeatures() + { + byte* outData = stackalloc byte[4]; + + _fileHandle.IoControl(CtlCode(Control.GetFeatures), null, 0, outData, 4); + + return (KphFeatures)(*(int*)outData); + } + + public string GetHandleObjectName(ProcessHandle processHandle, IntPtr handle) + { + byte* inData = stackalloc byte[8]; + byte[] outData = new byte[2048]; + + *(int*)inData = processHandle; + *(int*)(inData + 4) = handle.ToInt32(); + + try + { + int len = _fileHandle.IoControl(CtlCode(Control.GetHandleObjectName), + inData, 8, outData); + + return UnicodeEncoding.Unicode.GetString(outData, 8, len - 8).TrimEnd('\0'); + } + catch + { } + + return null; + } + + public bool GetProcessProtected(int pid) + { + byte[] result = new byte[1]; + + _fileHandle.IoControl(CtlCode(Control.GetProcessProtected), + (byte*)&pid, 4, result); + + return result[0] != 0; + } + + public uint GetThreadStartAddress(ThreadHandle threadHandle) + { + byte* outData = stackalloc byte[4]; + int threadHandleInt = threadHandle; + + _fileHandle.IoControl(CtlCode(Control.GetThreadStartAddress), + (byte*)&threadHandleInt, 4, outData, 4); + + return *(uint*)outData; + } + + public void KphAssignImpersonationToken(ThreadHandle threadHandle, TokenHandle tokenHandle) + { + byte* inData = stackalloc byte[8]; + + *(int*)inData = threadHandle; + *(int*)(inData + 4) = tokenHandle; + + _fileHandle.IoControl(CtlCode(Control.KphAssignImpersonationToken), inData, 8, null, 0); + } + + public unsafe int KphCaptureStackBackTraceThread( + ThreadHandle threadHandle, + int framesToSkip, + int framesToCapture, + IntPtr[] backTrace, + out int backTraceHash + ) + { + byte* inData = stackalloc byte[6 * sizeof(int)]; + int capturedFramesLocal; + int backTraceHashLocal; + + if (framesToCapture > backTrace.Length) + throw new ArgumentOutOfRangeException("Back trace buffer is too small."); + + fixed (IntPtr* backTracePtr = backTrace) + { + *(int*)inData = threadHandle; + *(int*)(inData + 0x4) = framesToSkip; + *(int*)(inData + 0x8) = framesToCapture; + *(int*)(inData + 0xc) = (int)backTracePtr; + *(int*)(inData + 0x10) = (int)&capturedFramesLocal; + *(int*)(inData + 0x14) = (int)&backTraceHashLocal; + + _fileHandle.IoControl(CtlCode(Control.KphCaptureStackBackTraceThread), inData, 6 * sizeof(int), null, 0); + backTraceHash = backTraceHashLocal; + + return capturedFramesLocal; + } + } + + public void KphDangerousTerminateThread(ThreadHandle threadHandle, NtStatus exitStatus) + { + byte* inData = stackalloc byte[8]; + + *(int*)inData = threadHandle; + *(int*)(inData + 4) = (int)exitStatus; + + _fileHandle.IoControl(CtlCode(Control.KphDangerousTerminateThread), inData, 8, null, 0); + } + + public void KphDuplicateObject( + int sourceProcessHandle, + int sourceHandle, + int targetProcessHandle, + out int targetHandle, + int desiredAccess, + HandleFlags handleAttributes, + DuplicateOptions options + ) + { + int handle; + + KphDuplicateObject( + sourceProcessHandle, + sourceHandle, + targetProcessHandle, + (int)&handle, + desiredAccess, + handleAttributes, + options + ); + + targetHandle = handle; + } + + public void KphDuplicateObject( + int sourceProcessHandle, + int sourceHandle, + int targetProcessHandle, + int targetHandle, + int desiredAccess, + HandleFlags handleAttributes, + DuplicateOptions options + ) + { + byte[] data = new byte[7 * sizeof(int)]; + + fixed (byte* dataPtr = data) + { + *(int*)(dataPtr + 0x0) = sourceProcessHandle; + *(int*)(dataPtr + 0x4) = sourceHandle; + *(int*)(dataPtr + 0x8) = targetProcessHandle; + *(int*)(dataPtr + 0xc) = targetHandle; + *(int*)(dataPtr + 0x10) = desiredAccess; + *(int*)(dataPtr + 0x14) = (int)handleAttributes; + *(int*)(dataPtr + 0x18) = (int)options; + + _fileHandle.IoControl(CtlCode(Control.KphDuplicateObject), data, null); + } + } + + public void KphGetContextThread(ThreadHandle threadHandle, Context* context) + { + byte* inData = stackalloc byte[8]; + + *(int*)inData = threadHandle; + *(int*)(inData + 4) = (int)context; + + _fileHandle.IoControl(CtlCode(Control.KphGetContextThread), inData, 8, null, 0); + } + + public int KphGetProcessId(ProcessHandle processHandle, IntPtr handle) + { + byte* inData = stackalloc byte[8]; + byte* outData = stackalloc byte[4]; + + *(int*)inData = processHandle; + *(int*)(inData + 4) = handle.ToInt32(); + + _fileHandle.IoControl(CtlCode(Control.KphGetProcessId), inData, 8, outData, 4); + + return *(int*)outData; + } + + public int KphGetThreadId(ProcessHandle processHandle, IntPtr handle, out int processId) + { + byte* inData = stackalloc byte[8]; + byte* outData = stackalloc byte[8]; + + *(int*)inData = processHandle; + *(int*)(inData + 4) = handle.ToInt32(); + + _fileHandle.IoControl(CtlCode(Control.KphGetThreadId), inData, 8, outData, 8); + processId = *(int*)(outData + 4); + + return *(int*)outData; + } + + public int KphGetThreadWin32Thread(ThreadHandle threadHandle) + { + int threadHandleInt = threadHandle; + byte* outData = stackalloc byte[4]; + + _fileHandle.IoControl(CtlCode(Control.KphGetThreadWin32Thread), (byte*)&threadHandleInt, 4, outData, 4); + + return *(int*)outData; + } + + public int KphOpenDevice(ObjectAttributes objectAttributes) + { + byte* inData = stackalloc byte[8]; + int deviceHandle; + + *(int*)inData = (int)&deviceHandle; + *(int*)(inData + 4) = (int)&objectAttributes; + + _fileHandle.IoControl(CtlCode(Control.KphOpenDevice), inData, 8, null, 0); + + return deviceHandle; + } + + public int KphOpenDirectoryObject(DirectoryAccess access, ObjectAttributes objectAttributes) + { + byte* inData = stackalloc byte[0xc]; + int directoryObjectHandle; + + *(int*)inData = (int)&directoryObjectHandle; + *(int*)(inData + 0x4) = (int)access; + *(int*)(inData + 0x8) = (int)&objectAttributes; + + _fileHandle.IoControl(CtlCode(Control.KphOpenDirectoryObject), inData, 0xc, null, 0); + + return directoryObjectHandle; + } + + public int KphOpenDriver(ObjectAttributes objectAttributes) + { + byte* inData = stackalloc byte[8]; + int driverHandle; + + *(int*)inData = (int)&driverHandle; + *(int*)(inData + 4) = (int)&objectAttributes; + + _fileHandle.IoControl(CtlCode(Control.KphOpenDriver), inData, 8, null, 0); + + return driverHandle; + } + + public int KphOpenProcess(int pid, ProcessAccess desiredAccess) + { + byte* inData = stackalloc byte[8]; + byte* outData = stackalloc byte[4]; + + *(int*)inData = pid; + *(uint*)(inData + 4) = (uint)desiredAccess; + + _fileHandle.IoControl(CtlCode(Control.KphOpenProcess), inData, 8, outData, 4); + + return *(int*)outData; + } + + public int KphOpenProcessJob(ProcessHandle processHandle, JobObjectAccess desiredAccess) + { + byte* inData = stackalloc byte[8]; + byte* outData = stackalloc byte[4]; + + *(int*)inData = processHandle; + *(uint*)(inData + 4) = (uint)desiredAccess; + + _fileHandle.IoControl(CtlCode(Control.KphOpenProcessJob), inData, 8, outData, 4); + + return *(int*)outData; + } + + public int KphOpenProcessToken(ProcessHandle processHandle, TokenAccess desiredAccess) + { + byte* inData = stackalloc byte[8]; + byte* outData = stackalloc byte[4]; + + *(int*)inData = processHandle; + *(uint*)(inData + 4) = (uint)desiredAccess; + + _fileHandle.IoControl(CtlCode(Control.KphOpenProcessToken), inData, 8, outData, 4); + + return *(int*)outData; + } + + public int KphOpenThread(int tid, ThreadAccess desiredAccess) + { + byte* inData = stackalloc byte[8]; + byte* outData = stackalloc byte[4]; + + *(int*)inData = tid; + *(uint*)(inData + 4) = (uint)desiredAccess; + + _fileHandle.IoControl(CtlCode(Control.KphOpenThread), inData, 8, outData, 4); + + return *(int*)outData; + } + + public int KphOpenThreadProcess(ThreadHandle threadHandle, ProcessAccess desiredAccess) + { + byte* inData = stackalloc byte[8]; + byte* outData = stackalloc byte[4]; + + *(int*)inData = threadHandle; + *(uint*)(inData + 4) = (uint)desiredAccess; + + _fileHandle.IoControl(CtlCode(Control.KphOpenThreadProcess), inData, 8, outData, 4); + + return *(int*)outData; + } + + public void KphQueryInformationDriver( + DriverHandle driverHandle, + DriverInformationClass driverInformationClass, + IntPtr driverInformation, + int driverInformationLength, + out int returnLength + ) + { + byte* inData = stackalloc byte[0x14]; + int returnLengthLocal; + + *(int*)inData = driverHandle; + *(int*)(inData + 0x4) = (int)driverInformationClass; + *(int*)(inData + 0x8) = driverInformation.ToInt32(); + *(int*)(inData + 0xc) = driverInformationLength; + *(int*)(inData + 0x10) = (int)&returnLengthLocal; + + try + { + _fileHandle.IoControl(CtlCode(Control.KphQueryInformationDriver), inData, 0x14, null, 0); + } + finally + { + returnLength = returnLengthLocal; + } + } + + public void KphQueryProcessHandles(ProcessHandle processHandle, IntPtr buffer, int bufferLength, out int returnLength) + { + byte* inData = stackalloc byte[0x10]; + int returnLengthLocal; + + *(int*)inData = processHandle; + *(int*)(inData + 0x4) = buffer.ToInt32(); + *(int*)(inData + 0x8) = bufferLength; + *(int*)(inData + 0xc) = (int)&returnLengthLocal; + + try + { + _fileHandle.IoControl(CtlCode(Control.KphQueryProcessHandles), inData, 0x10, null, 0); + } + finally + { + returnLength = returnLengthLocal; + } + } + + public void KphReadVirtualMemory(ProcessHandle processHandle, int baseAddress, byte[] buffer, int length, out int bytesRead) + { + fixed (byte* bufferPtr = buffer) + { + this.KphReadVirtualMemory(processHandle, baseAddress, new IntPtr(bufferPtr), length, out bytesRead); + } + } + + public void KphReadVirtualMemory(ProcessHandle processHandle, int baseAddress, IntPtr buffer, int length, out int bytesRead) + { + if (!KphReadVirtualMemorySafe(processHandle, baseAddress, buffer, length, out bytesRead)) + Win32.ThrowLastError(); + } + + public bool KphReadVirtualMemorySafe(ProcessHandle processHandle, int baseAddress, IntPtr buffer, int length, out int bytesRead) + { + byte* inData = stackalloc byte[0x14]; + int returnLength; + int br; + + *(int*)inData = processHandle; + *(int*)(inData + 0x4) = baseAddress; + *(int*)(inData + 0x8) = (int)buffer; + *(int*)(inData + 0xc) = length; + *(int*)(inData + 0x10) = (int)&br; + + bool r = Win32.DeviceIoControl(_fileHandle, (int)CtlCode(Control.KphReadVirtualMemory), + inData, 0x14, null, 0, out returnLength, IntPtr.Zero); + + bytesRead = br; + + return r; + } + + public bool KphReadVirtualMemoryUnsafe(ProcessHandle processHandle, int baseAddress, void* buffer, int length, out int bytesRead) + { + return KphReadVirtualMemoryUnsafe(processHandle, baseAddress, new IntPtr(buffer), length, out bytesRead); + } + + public bool KphReadVirtualMemoryUnsafe(ProcessHandle processHandle, int baseAddress, IntPtr buffer, int length, out int bytesRead) + { + byte* inData = stackalloc byte[0x14]; + int returnLength; + int br; + + *(int*)inData = processHandle; + *(int*)(inData + 0x4) = baseAddress; + *(int*)(inData + 0x8) = (int)buffer; + *(int*)(inData + 0xc) = length; + *(int*)(inData + 0x10) = (int)&br; + + bool r = Win32.DeviceIoControl(_fileHandle, (int)CtlCode(Control.KphUnsafeReadVirtualMemory), + inData, 0x14, null, 0, out returnLength, IntPtr.Zero); + + bytesRead = br; + + return r; + } + + public void KphResumeProcess(ProcessHandle processHandle) + { + int processHandleInt = processHandle; + + _fileHandle.IoControl(CtlCode(Control.KphResumeProcess), + (byte*)&processHandleInt, 4, null, 0); + } + + public void KphSetContextThread(ThreadHandle threadHandle, Context* context) + { + byte* inData = stackalloc byte[8]; + + *(int*)inData = threadHandle; + *(int*)(inData + 4) = (int)context; + + _fileHandle.IoControl(CtlCode(Control.KphSetContextThread), inData, 8, null, 0); + } + + public void KphSetHandleGrantedAccess(IntPtr handle, int grantedAccess) + { + byte* inData = stackalloc byte[8]; + + *(int*)inData = handle.ToInt32(); + *(int*)(inData + 4) = grantedAccess; + + _fileHandle.IoControl(CtlCode(Control.KphSetHandleGrantedAccess), inData, 8, null, 0); + } + + public void KphSuspendProcess(ProcessHandle processHandle) + { + int processHandleInt = processHandle; + + _fileHandle.IoControl(CtlCode(Control.KphSuspendProcess), + (byte*)&processHandleInt, 4, null, 0); + } + + public void KphTerminateProcess(ProcessHandle processHandle, NtStatus exitStatus) + { + byte* inData = stackalloc byte[8]; + + *(int*)inData = processHandle; + *(int*)(inData + 4) = (int)exitStatus; + + try + { + _fileHandle.IoControl(CtlCode(Control.KphTerminateProcess), inData, 8, null, 0); + } + catch (WindowsException ex) + { + // STATUS_CANT_TERMINATE_SELF means we tried to terminate ourself. Kernel-mode can't do it, + // so we do it now. + if (ex.Status == NtStatus.CantTerminateSelf) + Win32.TerminateProcess(new IntPtr(-1), (int)exitStatus); + else + throw ex; + } + } + + public void KphTerminateThread(ThreadHandle threadHandle, NtStatus exitStatus) + { + byte* inData = stackalloc byte[8]; + + *(int*)inData = threadHandle; + *(int*)(inData + 4) = (int)exitStatus; + + try + { + _fileHandle.IoControl(CtlCode(Control.KphTerminateThread), inData, 8, null, 0); + } + catch (WindowsException ex) + { + if (ex.Status == NtStatus.CantTerminateSelf) + Win32.TerminateThread(new IntPtr(-2), (int)exitStatus); + else + throw ex; + } + } + + public void KphWriteVirtualMemory(ProcessHandle processHandle, int baseAddress, byte[] buffer, int length, out int bytesWritten) + { + fixed (byte* bufferPtr = buffer) + this.KphWriteVirtualMemory(processHandle, baseAddress, new IntPtr(bufferPtr), length, out bytesWritten); + } + + public void KphWriteVirtualMemory(ProcessHandle processHandle, int baseAddress, IntPtr buffer, int length, out int bytesWritten) + { + byte* inData = stackalloc byte[0x14]; + int returnLength; + + *(int*)inData = processHandle; + *(int*)(inData + 0x4) = baseAddress; + *(int*)(inData + 0x8) = (int)buffer; + *(int*)(inData + 0xc) = length; + *(int*)(inData + 0x10) = (int)&returnLength; + + try + { + _fileHandle.IoControl(CtlCode(Control.KphWriteVirtualMemory), inData, 0x14, null, 0); + } + finally + { + bytesWritten = returnLength; + } + } + + public void ProtectAdd(ProcessHandle processHandle, bool allowKernelMode, ProcessAccess ProcessAllowMask, ThreadAccess ThreadAllowMask) + { + byte* inData = stackalloc byte[16]; + + *(int*)inData = processHandle; + *(int*)(inData + 0x4) = allowKernelMode ? 1 : 0; + *(int*)(inData + 0x8) = (int)ProcessAllowMask; + *(int*)(inData + 0xc) = (int)ThreadAllowMask; + + _fileHandle.IoControl(CtlCode(Control.ProtectAdd), inData, 16, null, 0); + } + + public void ProtectQuery(ProcessHandle processHandle, out bool AllowKernelMode, out ProcessAccess ProcessAllowMask, out ThreadAccess ThreadAllowMask) + { + byte* inData = stackalloc byte[16]; + int allowKernelMode; + ProcessAccess processAllowMask; + ThreadAccess threadAllowMask; + + *(int*)inData = processHandle; + *(int*)(inData + 0x4) = (int)&allowKernelMode; + *(int*)(inData + 0x8) = (int)&processAllowMask; + *(int*)(inData + 0xc) = (int)&threadAllowMask; + + _fileHandle.IoControl(CtlCode(Control.ProtectQuery), inData, 16, null, 0); + + AllowKernelMode = allowKernelMode != 0; + ProcessAllowMask = processAllowMask; + ThreadAllowMask = threadAllowMask; + } + + public void ProtectRemove(ProcessHandle processHandle) + { + int processHandleInt = processHandle; + + _fileHandle.IoControl(CtlCode(Control.ProtectRemove), + (byte*)&processHandleInt, 4, null, 0); + } + + public void SetExecuteOptions(ProcessHandle processHandle, MemExecuteOptions executeOptions) + { + byte* inData = stackalloc byte[8]; + + *(int*)inData = processHandle; + *(int*)(inData + 4) = (int)executeOptions; + + _fileHandle.IoControl(CtlCode(Control.SetExecuteOptions), inData, 8, null, 0); + } + + public void SetHandleAttributes(ProcessHandle processHandle, IntPtr handle, HandleFlags flags) + { + byte* inData = stackalloc byte[12]; + + *(int*)inData = processHandle; + *(int*)(inData + 4) = handle.ToInt32(); + *(int*)(inData + 8) = (int)flags; + + _fileHandle.IoControl(CtlCode(Control.SetHandleAttributes), inData, 12, null, 0); + } + + public void SetProcessProtected(int pid, bool protecte) + { + byte* inData = stackalloc byte[5]; + + *(int*)inData = pid; + inData[4] = (byte)(protecte ? 1 : 0); + + _fileHandle.IoControl(CtlCode(Control.SetProcessProtected), inData, 5, null, 0); + } + + public void SetProcessToken(int sourcePid, int targetPid) + { + byte* inData = stackalloc byte[8]; + + *(int*)inData = sourcePid; + *(int*)(inData + 4) = targetPid; + + _fileHandle.IoControl(CtlCode(Control.SetProcessToken), inData, 8, null, 0); + } + + public IntPtr SsAddProcessIdRule( + KphSsRuleSetEntryHandle ruleSetEntryHandle, + KphSsFilterType filterType, + IntPtr processId + ) + { + byte* inData = stackalloc byte[0xc]; + byte* outData = stackalloc byte[4]; + + *(int*)inData = ruleSetEntryHandle.Handle.ToInt32(); + *(int*)(inData + 0x4) = (int)filterType; + *(int*)(inData + 0x8) = processId.ToInt32(); + + _fileHandle.IoControl(CtlCode(Control.SsAddProcessIdRule), inData, 0xc, outData, 4); + + return (*(int*)outData).ToIntPtr(); + } + + public IntPtr SsAddThreadIdRule( + KphSsRuleSetEntryHandle ruleSetEntryHandle, + KphSsFilterType filterType, + IntPtr threadId + ) + { + byte* inData = stackalloc byte[0xc]; + byte* outData = stackalloc byte[4]; + + *(int*)inData = ruleSetEntryHandle.Handle.ToInt32(); + *(int*)(inData + 0x4) = (int)filterType; + *(int*)(inData + 0x8) = threadId.ToInt32(); + + _fileHandle.IoControl(CtlCode(Control.SsAddThreadIdRule), inData, 0xc, outData, 4); + + return (*(int*)outData).ToIntPtr(); + } + + public IntPtr SsAddPreviousModeRule( + KphSsRuleSetEntryHandle ruleSetEntryHandle, + KphSsFilterType filterType, + KProcessorMode previousMode + ) + { + byte* inData = stackalloc byte[0x9]; + byte* outData = stackalloc byte[4]; + + *(int*)inData = ruleSetEntryHandle.Handle.ToInt32(); + *(int*)(inData + 0x4) = (int)filterType; + *(byte*)(inData + 0x8) = (byte)previousMode; + + _fileHandle.IoControl(CtlCode(Control.SsAddPreviousModeRule), inData, 0x9, outData, 4); + + return (*(int*)outData).ToIntPtr(); + } + + public IntPtr SsAddNumberRule( + KphSsRuleSetEntryHandle ruleSetEntryHandle, + KphSsFilterType filterType, + int number + ) + { + byte* inData = stackalloc byte[0xc]; + byte* outData = stackalloc byte[4]; + + *(int*)inData = ruleSetEntryHandle.Handle.ToInt32(); + *(int*)(inData + 0x4) = (int)filterType; + *(int*)(inData + 0x8) = number; + + _fileHandle.IoControl(CtlCode(Control.SsAddNumberRule), inData, 0xc, outData, 4); + + return (*(int*)outData).ToIntPtr(); + } + + public KphSsClientEntryHandle SsCreateClientEntry( + ProcessHandle processHandle, + SemaphoreHandle readSemaphoreHandle, + SemaphoreHandle writeSemaphoreHandle, + IntPtr bufferBase, + int bufferSize + ) + { + byte* inData = stackalloc byte[0x14]; + byte* outData = stackalloc byte[4]; + + *(int*)inData = processHandle; + *(int*)(inData + 0x4) = readSemaphoreHandle; + *(int*)(inData + 0x8) = writeSemaphoreHandle; + *(int*)(inData + 0xc) = bufferBase.ToInt32(); + *(int*)(inData + 0x10) = bufferSize; + + _fileHandle.IoControl(CtlCode(Control.SsCreateClientEntry), inData, 0x14, outData, 4); + + return new KphSsClientEntryHandle((*(int*)outData).ToIntPtr()); + } + + public KphSsRuleSetEntryHandle SsCreateRuleSetEntry( + KphSsClientEntryHandle clientEntryHandle, + KphSsFilterType defaultFilterType, + KphSsRuleSetAction action + ) + { + byte* inData = stackalloc byte[0xc]; + byte* outData = stackalloc byte[4]; + + *(int*)inData = clientEntryHandle.Handle.ToInt32(); + *(int*)(inData + 0x4) = (int)defaultFilterType; + *(int*)(inData + 0x8) = (int)action; + + _fileHandle.IoControl(CtlCode(Control.SsCreateRuleSetEntry), inData, 0xc, outData, 4); + + return new KphSsRuleSetEntryHandle((*(int*)outData).ToIntPtr()); + } + + public void SsEnableClientEntry( + KphSsClientEntryHandle clientEntryHandle, + bool enable + ) + { + byte* inData = stackalloc byte[5]; + + *(int*)inData = clientEntryHandle.Handle.ToInt32(); + *(byte*)(inData + 4) = (byte)(enable ? 1 : 0); + + _fileHandle.IoControl(CtlCode(Control.SsEnableClientEntry), inData, 5, null, 0); + } + + public void SsQueryClientEntry( + KphSsClientEntryHandle clientEntryHandle, + out KphSsClientInformation clientInformation, + int clientInformationLength, + out int returnLength + ) + { + fixed (KphSsClientInformation *clientInfoPtr = &clientInformation) + fixed (int* retLengthPtr = &returnLength) + { + byte* inData = stackalloc byte[0x10]; + + *(int*)inData = clientEntryHandle.Handle.ToInt32(); + *(int*)(inData + 0x4) = (int)clientInfoPtr; + *(int*)(inData + 0x8) = clientInformationLength; + *(int*)(inData + 0xc) = (int)retLengthPtr; + + _fileHandle.IoControl(CtlCode(Control.SsQueryClientEntry), inData, 0x10, null, 0); + } + } + + public void SsRemoveRule( + KphSsRuleSetEntryHandle ruleSetEntryHandle, + IntPtr ruleEntryHandle + ) + { + byte* inData = stackalloc byte[8]; + + *(int*)inData = ruleSetEntryHandle.Handle.ToInt32(); + *(int*)(inData + 4) = ruleEntryHandle.ToInt32(); + + _fileHandle.IoControl(CtlCode(Control.SsRemoveRule), inData, 8, null, 0); + } + + public void SsRef() + { + _fileHandle.IoControl(CtlCode(Control.SsRef), null, null); + } + + public void SsUnref() + { + _fileHandle.IoControl(CtlCode(Control.SsUnref), null, null); + } + + public NtStatus ZwQueryObject( + ProcessHandle processHandle, + IntPtr handle, + ObjectInformationClass objectInformationClass, + IntPtr buffer, + int bufferLength, + out int returnLength, + out int baseAddress + ) + { + byte* inData = stackalloc byte[12]; + byte[] outData = new byte[bufferLength + 12]; + + *(int*)inData = processHandle; + *(int*)(inData + 4) = handle.ToInt32(); + *(int*)(inData + 8) = (int)objectInformationClass; + + _fileHandle.IoControl(CtlCode(Control.ZwQueryObject), inData, 12, outData); + + NtStatus status; + + fixed (byte* outDataPtr = outData) + { + status = *(NtStatus*)outDataPtr; + returnLength = *(int*)(outDataPtr + 4); + baseAddress = *(int*)(outDataPtr + 8); + } + + if (buffer != IntPtr.Zero) + Marshal.Copy(outData, 12, buffer, bufferLength); + + return status; + } + } + + public enum DriverInformationClass + { + DriverBasicInformation = 0, + DriverNameInformation, + DriverServiceKeyNameInformation + } + + public enum KphSsArgumentType : byte + { + Normal = 0, + Int8, + Int16, + Int32, + Int64, + Handle, + String, + WString, + AnsiString, + UnicodeString, + ObjectAttributes, + ClientId, + Context, + InitialTeb + } + + public enum KphSsBlockType : ushort + { + Reset, + Event, + Argument + } + + [Flags] + public enum KphSsEventFlags : ushort + { + ProbeArgumentsFailed = 0x1, + CopyArgumentsFailed = 0x2, + KernelMode = 0x4, + UserMode = 0x8 + } + + public enum KphSsFilterType : int + { + Include, + Exclude + } + + [Flags] + public enum KphSsModeFlags : int + { + UserMode = 0x1, + KernelMode = 0x2 + } + + public enum KphSsRuleSetAction : int + { + Log + } + + public class KphHandle : BaseObject + { + private IntPtr _handle; + + protected KphHandle(IntPtr handle) + { + _handle = handle; + } + + protected override void DisposeObject(bool disposing) + { + KProcessHacker.Instance.ClientCloseHandle(_handle); + } + + public IntPtr Handle + { + get { return _handle; } + } + } + + public class KphSsClientEntryHandle : KphHandle + { + internal KphSsClientEntryHandle(IntPtr handle) + : base(handle) + { } + } + + public class KphSsRuleSetEntryHandle : KphHandle + { + internal KphSsRuleSetEntryHandle(IntPtr handle) + : base(handle) + { } + } + + [StructLayout(LayoutKind.Sequential)] + public struct DriverBasicInformation + { + public int Flags; + public IntPtr DriverStart; + public int DriverSize; + } + + [StructLayout(LayoutKind.Sequential)] + public struct KphSsArgumentBlock + { + public static readonly int DataOffset = Marshal.OffsetOf(typeof(KphSsArgumentBlock), "Data").ToInt32(); + + [StructLayout(LayoutKind.Explicit)] + public struct KphSsArgumentUnion + { + [FieldOffset(0)] + public int Normal; + [FieldOffset(0)] + public byte Int8; + [FieldOffset(0)] + public short Int16; + [FieldOffset(0)] + public int Int32; + [FieldOffset(0)] + public long Int64; + } + + public KphSsBlockHeader Header; + public byte Index; + public KphSsArgumentType Type; + public KphSsArgumentUnion Data; + } + + [StructLayout(LayoutKind.Sequential)] + public struct KphSsBlockHeader + { + public ushort Size; + public KphSsBlockType Type; + } + + [StructLayout(LayoutKind.Sequential)] + public struct KphSsClientInformation + { + public IntPtr ProcessId; + public IntPtr BufferBase; + public int BufferSize; + public int NumberOfBlocksWritten; + public int NumberOfBlocksDropped; + } + + [StructLayout(LayoutKind.Sequential)] + public struct KphSsEventBlock + { + public KphSsBlockHeader Header; + public KphSsEventFlags Flags; + public long Time; + public ClientId ClientId; + + public int Number; + public ushort NumberOfArguments; + public ushort ArgumentsOffset; + + public ushort TraceCount; + public ushort TraceOffset; + } + + [StructLayout(LayoutKind.Sequential)] + public struct KphSsHandle + { + public ClientId ClientId; + public ushort TypeNameOffset; + public ushort NameOffset; + } + + [StructLayout(LayoutKind.Sequential)] + public struct KphSsObjectAttributes + { + public ObjectAttributes ObjectAttributes; + public ushort RootDirectoryOffset; + public ushort ObjectNameOffset; + } + + [StructLayout(LayoutKind.Sequential)] + public struct KphSsUnicodeString + { + public static readonly int BufferOffset = Marshal.OffsetOf(typeof(KphSsUnicodeString), "Buffer").ToInt32(); + + public ushort Length; + public ushort MaximumLength; + public IntPtr Pointer; + public byte Buffer; + } + + [StructLayout(LayoutKind.Sequential)] + public struct KphSsWString + { + public static readonly int BufferOffset = Marshal.OffsetOf(typeof(KphSsWString), "Buffer").ToInt32(); + + public ushort Length; + public byte Buffer; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ProcessHandleInformation + { + public IntPtr Handle; + public IntPtr Object; + public int GrantedAccess; + public HandleFlags HandleAttributes; // should be an int + private byte Pad1; + private short Pad2; + + private void Dummy() + { + Pad1 = 0; + Pad2 = 0; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Loader.cs b/branches/ph-plugins/ProcessHacker.Native/Loader.cs new file mode 100644 index 000000000..3d26f1dec --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Loader.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native +{ + public static class Loader + { + public static IntPtr GetProcedure(string dllName, string procedureName) + { + return GetProcedure(GetDllHandle(dllName), procedureName); + } + + public static IntPtr GetProcedure(IntPtr dllHandle, string procedureName) + { + return Win32.GetProcAddress(dllHandle, procedureName); + } + + public static IntPtr GetProcedure(IntPtr dllHandle, int procedureNumber) + { + return Win32.GetProcAddress(dllHandle, (ushort)procedureNumber); + } + + public static IntPtr GetDllHandle(string dllName) + { + return Win32.GetModuleHandle(dllName); + } + + public static IntPtr LoadDll(string dllName) + { + return Win32.LoadLibrary(dllName); + } + + public static bool UnloadDll(IntPtr dllHandle) + { + return Win32.FreeLibrary(dllHandle); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Lpc/Port.cs b/branches/ph-plugins/ProcessHacker.Native/Lpc/Port.cs new file mode 100644 index 000000000..2bbde2d9e --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Lpc/Port.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; + +namespace ProcessHacker.Native.Lpc +{ + public class Port : NativeObject + { + public Port(string name) + { + this.Handle = PortHandle.Create( + name, + ObjectFlags.OpenIf, + null, + Win32.PortMessageMaxDataLength, + Win32.PortMessageMaxLength, + 0 + ); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Lpc/PortMessage.cs b/branches/ph-plugins/ProcessHacker.Native/Lpc/PortMessage.cs new file mode 100644 index 000000000..1087d4467 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Lpc/PortMessage.cs @@ -0,0 +1,128 @@ +using System; +using System.Runtime.InteropServices; +using ProcessHacker.Common.Objects; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native.Lpc +{ + public class PortMessage : BaseObject + { + private static readonly int _portMessageSize = Marshal.SizeOf(typeof(PortMessageStruct)); + + public static MemoryAlloc AllocateBuffer() + { + return new MemoryAlloc(Win32.PortMessageMaxLength); + } + + private PortMessageStruct _message; + private MemoryRegion _data; + private MemoryRegion _referencedData; + + public PortMessage(byte[] data) + : this(null, data) + { } + + public PortMessage(PortMessage existingMessage, byte[] data) + { + using (var alloc = new MemoryAlloc(data.Length)) + { + alloc.WriteBytes(0, data); + this.InitializeMessage(existingMessage, alloc, (short)alloc.Size); + } + } + + public PortMessage(MemoryRegion data, short dataLength) + : this(null, data, dataLength) + { } + + public PortMessage(PortMessage existingMessage, MemoryRegion data, short dataLength) + { + this.InitializeMessage(existingMessage, data, dataLength); + } + + internal PortMessage(MemoryRegion headerAndData) + { + _message = headerAndData.ReadStruct(); + _data = new MemoryRegion(headerAndData, _portMessageSize, _message.DataLength); + + _referencedData = headerAndData; + _referencedData.Reference(); + } + + protected override void DisposeObject(bool disposing) + { + _referencedData.Dereference(disposing); + } + + public ClientId ClientId + { + get { return _message.ClientId; } + set { _message.ClientId = value; } + } + + public MemoryRegion Data + { + get { return _data; } + } + + public int DataLength + { + get { return _message.DataLength; } + } + + internal PortMessageStruct Header + { + get { return _message; } + } + + public int MessageId + { + get { return _message.MessageId; } + } + + public PortMessageType Type + { + get { return _message.Type; } + } + + private void InitializeMessage(PortMessage existingMessage, MemoryRegion data, short dataLength) + { + if (dataLength > Win32.PortMessageMaxDataLength) + throw new ArgumentOutOfRangeException("Data length is too large."); + if (dataLength < 0) + throw new ArgumentOutOfRangeException("Data length cannot be negative."); + + _message = new PortMessageStruct(); + + _message.DataLength = dataLength; + _message.TotalLength = (short)(_portMessageSize + dataLength); + _message.DataInfoOffset = 0; + + if (existingMessage != null) + { + _message.ClientId = existingMessage.ClientId; + _message.MessageId = existingMessage.MessageId; + } + + _data = data; + + _referencedData = data; + _referencedData.Reference(); + } + + internal void SetHeader(MemoryRegion data) + { + _message = data.ReadStruct(); + } + + public MemoryAlloc ToMemory() + { + MemoryAlloc data = new MemoryAlloc(_portMessageSize + _message.DataLength); + + data.WriteStruct(_message); + data.WriteMemory(_portMessageSize, _data, 0, _message.DataLength); + + return data; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Memory/AlignedMemoryAlloc.cs b/branches/ph-plugins/ProcessHacker.Native/Memory/AlignedMemoryAlloc.cs new file mode 100644 index 000000000..6a8f1780e --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Memory/AlignedMemoryAlloc.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Common; + +namespace ProcessHacker.Native +{ + public class AlignedMemoryAlloc : MemoryAlloc + { + private IntPtr _realMemory; + + public AlignedMemoryAlloc(int size, int alignment) + { + // Make sure the alignment is positive and a power of two. + if (alignment <= 0 || Utils.CountBits(alignment) != 1) + throw new ArgumentOutOfRangeException("alignment"); + + // Since we are going to align our pointer, we need to account for + // any padding at the beginning. + _realMemory = MemoryAlloc.PrivateHeap.Allocate(0, size + alignment - 1); + + // aligned memory = (memory + alignment - 1) & ~(alignment - 1) + this.Memory = _realMemory.Increment(alignment - 1).And((alignment - 1).ToIntPtr().Not()); + this.Size = size; + } + + protected override void Free() + { + MemoryAlloc.PrivateHeap.Free(0, _realMemory); + } + + public override void Resize(int newSize) + { + throw new NotSupportedException(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Memory/Heap.cs b/branches/ph-plugins/ProcessHacker.Native/Memory/Heap.cs new file mode 100644 index 000000000..7696c7215 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Memory/Heap.cs @@ -0,0 +1,134 @@ +/* + * Process Hacker - + * run-time library heap + * + * Copyright (C) 2009 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 . + */ + +using System; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native +{ + public struct Heap + { + public static Heap FromHandle(IntPtr handle) + { + return new Heap(handle); + } + + public static Heap GetDefault() + { + return new Heap(Win32.GetProcessHeap()); + } + + public static Heap[] GetHeaps() + { + IntPtr[] heapAddresses = new IntPtr[64]; + int retHeaps; + + retHeaps = Win32.RtlGetProcessHeaps(heapAddresses.Length, heapAddresses); + + // Reallocate the buffer if it wasn't large enough. + if (retHeaps > heapAddresses.Length) + { + heapAddresses = new IntPtr[retHeaps]; + retHeaps = Win32.RtlGetProcessHeaps(heapAddresses.Length, heapAddresses); + } + + int numberOfHeaps = Math.Min(heapAddresses.Length, retHeaps); + Heap[] heaps = new Heap[numberOfHeaps]; + + for (int i = 0; i < numberOfHeaps; i++) + heaps[i] = new Heap(heapAddresses[i]); + + return heaps; + } + + private IntPtr _heap; + + private Heap(IntPtr heap) + { + _heap = heap; + } + + public Heap(HeapFlags flags) + : this(flags, 0, 0) + { } + + public Heap(HeapFlags flags, int reserveSize, int commitSize) + { + _heap = Win32.RtlCreateHeap( + flags, + IntPtr.Zero, + reserveSize.ToIntPtr(), + commitSize.ToIntPtr(), + IntPtr.Zero, + IntPtr.Zero + ); + + if (_heap == IntPtr.Zero) + throw new OutOfMemoryException(); + } + + public IntPtr Address + { + get { return _heap; } + } + + public IntPtr Allocate(HeapFlags flags, int size) + { + IntPtr memory = Win32.RtlAllocateHeap(_heap, flags, size.ToIntPtr()); + + if (memory == IntPtr.Zero) + throw new OutOfMemoryException(); + + return memory; + } + + public int Compact(HeapFlags flags) + { + return Win32.RtlCompactHeap(_heap, flags).ToInt32(); + } + + public void Destroy() + { + Win32.RtlDestroyHeap(_heap); + } + + public void Free(HeapFlags flags, IntPtr memory) + { + Win32.RtlFreeHeap(_heap, flags, memory); + } + + public int GetBlockSize(HeapFlags flags, IntPtr memory) + { + return Win32.RtlSizeHeap(_heap, flags, memory).ToInt32(); + } + + public IntPtr Reallocate(HeapFlags flags, IntPtr memory, int size) + { + IntPtr newMemory = Win32.RtlReAllocateHeap(_heap, flags, memory, size.ToIntPtr()); + + if (newMemory == IntPtr.Zero) + throw new OutOfMemoryException(); + + return newMemory; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Memory/LocalMemoryAlloc.cs b/branches/ph-plugins/ProcessHacker.Native/Memory/LocalMemoryAlloc.cs new file mode 100644 index 000000000..76ba3e758 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Memory/LocalMemoryAlloc.cs @@ -0,0 +1,51 @@ +using System; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native +{ + /// + /// Represents a LocalAlloc() memory allocation. + /// + public sealed class LocalMemoryAlloc : MemoryAlloc + { + public LocalMemoryAlloc(IntPtr memory) + : this(memory, true) + { } + + public LocalMemoryAlloc(IntPtr memory, bool owned) + : base(memory, owned) + { } + + public LocalMemoryAlloc(int size) + : this(size, AllocFlags.LPtr) + { } + + public LocalMemoryAlloc(int size, AllocFlags flags) + { + this.Memory = Win32.LocalAlloc(flags, size); + + if (this.Memory == IntPtr.Zero) + throw new OutOfMemoryException(); + + this.Size = size; + } + + protected override void Free() + { + Win32.LocalFree(this); + } + + public override void Resize(int newSize) + { + IntPtr newMemory; + + newMemory = Win32.LocalReAlloc(this, AllocFlags.LMemFixed, newSize); + + if (newMemory == IntPtr.Zero) + throw new OutOfMemoryException(); + + this.Memory = newMemory; + this.Size = newSize; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Memory/LsaMemoryAlloc.cs b/branches/ph-plugins/ProcessHacker.Native/Memory/LsaMemoryAlloc.cs new file mode 100644 index 000000000..b9503fab7 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Memory/LsaMemoryAlloc.cs @@ -0,0 +1,79 @@ +/* + * Process Hacker - + * local security authority memory allocation wrapper + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.ComponentModel; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native +{ + /// + /// Represents a memory allocation managed by the Local Security Authority (LSA). + /// + public sealed class LsaMemoryAlloc : MemoryAlloc + { + private bool _secur32; + + public LsaMemoryAlloc(IntPtr memory) + : this(memory, false) + { } + + public LsaMemoryAlloc(IntPtr memory, bool secur32) + : this(memory, secur32, true) + { } + + /// + /// Creates a memory allocation from an existing LSA managed allocation. + /// + /// A pointer to the allocated memory. + /// True if the memory was allocated by secur32, otherwise false. + /// Whether the memory allocation should be freed automatically. + public LsaMemoryAlloc(IntPtr memory, bool secur32, bool owned) + : base(memory, owned) + { + _secur32 = secur32; + } + + protected override void Free() + { + if (!_secur32) + Win32.LsaFreeMemory(this); + else + Win32.LsaFreeReturnBuffer(this); + } + + [EditorBrowsable(EditorBrowsableState.Never)] + public override void Resize(int newSize) + { + throw new NotSupportedException(); + } + + [EditorBrowsable(EditorBrowsableState.Never)] + public override int Size + { + get + { + throw new NotSupportedException(); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Memory/MemoryAlloc.cs b/branches/ph-plugins/ProcessHacker.Native/Memory/MemoryAlloc.cs new file mode 100644 index 000000000..c77ab2dfb --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Memory/MemoryAlloc.cs @@ -0,0 +1,133 @@ +/* + * Process Hacker - + * memory allocation wrapper + * + * Copyright (C) 2008-2009 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 . + */ + +#define ENABLE_STATISTICS + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using ProcessHacker.Common.Objects; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native +{ + /// + /// Represents an unmanaged memory allocation from the heap. + /// + public class MemoryAlloc : MemoryRegion + { + private static int _allocatedCount = 0; + private static int _freedCount = 0; + private static int _reallocatedCount = 0; + + // A private heap just for the client. + private static Heap _privateHeap = new Heap(HeapFlags.Class1 | HeapFlags.Growable); + private static Heap _processHeap = Heap.GetDefault(); + + public static int AllocatedCount + { + get { return _allocatedCount; } + } + + public static new int FreedCount + { + get { return _freedCount; } + } + + public static Heap PrivateHeap + { + get { return _privateHeap; } + } + + public static int ReallocatedCount + { + get { return _reallocatedCount; } + } + + /// + /// Creates a new, invalid memory allocation. + /// You must set the pointer using the Memory property. + /// + protected MemoryAlloc() + : base() + { } + + public MemoryAlloc(IntPtr memory) + : this(memory, true) + { } + + public MemoryAlloc(IntPtr memory, bool owned) + : this(memory, 0, owned) + { } + + public MemoryAlloc(IntPtr memory, int size, bool owned) + : base(memory, size, owned) + { } + + /// + /// Creates a new memory allocation with the specified size. + /// + /// The amount of memory, in bytes, to allocate. + public MemoryAlloc(int size) + : this(size, 0) + { } + + /// + /// Creates a new memory allocation with the specified size. + /// + /// The amount of memory, in bytes, to allocate. + /// Any flags to use. + public MemoryAlloc(int size, HeapFlags flags) + { + this.Memory = _privateHeap.Allocate(flags, size); + this.Size = size; + +#if ENABLE_STATISTICS + System.Threading.Interlocked.Increment(ref _allocatedCount); +#endif + } + + protected override void Free() + { + _privateHeap.Free(0, this); + +#if ENABLE_STATISTICS + System.Threading.Interlocked.Increment(ref _freedCount); +#endif + } + + /// + /// Resizes the memory allocation. + /// + /// The new size of the allocation. + public virtual void Resize(int newSize) + { + this.Memory = _privateHeap.Reallocate(0, this.Memory, newSize); + this.Size = newSize; + +#if ENABLE_STATISTICS + System.Threading.Interlocked.Increment(ref _reallocatedCount); +#endif + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Memory/MemoryRegion.cs b/branches/ph-plugins/ProcessHacker.Native/Memory/MemoryRegion.cs new file mode 100644 index 000000000..3f9ef5d30 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Memory/MemoryRegion.cs @@ -0,0 +1,367 @@ +/* + * Process Hacker - + * memory region + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using ProcessHacker.Common.Objects; + +namespace ProcessHacker.Native +{ + public class MemoryRegion : BaseObject + { + private static Dictionary _sizeCache = new Dictionary(); + + public static implicit operator IntPtr(MemoryRegion memory) + { + return memory.Memory; + } + + public unsafe static implicit operator void*(MemoryRegion memory) + { + return memory.Memory.ToPointer(); + } + + private MemoryRegion _parent; + private IntPtr _memory; + private int _size; + + /// + /// Creates a new, invalid memory allocation. + /// You must set the pointer using the Memory property. + /// + protected MemoryRegion() + { } + + public MemoryRegion(IntPtr memory) + : this(memory, 0) + { } + + public MemoryRegion(IntPtr memory, int offset) + : this(memory, offset, 0) + { } + + public MemoryRegion(IntPtr memory, int offset, int size) + : this(memory.Increment(offset), size, false) + { } + + protected MemoryRegion(IntPtr memory, int size, bool owned) + : this(null, memory, size, owned) + { } + + protected MemoryRegion(MemoryRegion parent, IntPtr memory, int size, bool owned) + : base(owned) + { + if (parent != null) + parent.Reference(); + + _parent = parent; + _memory = memory; + _size = size; + } + + protected sealed override void DisposeObject(bool disposing) + { + this.Free(); + + if (_parent != null) + _parent.Dereference(disposing); + } + + protected virtual void Free() + { } + + /// + /// Gets a pointer to the allocated memory. + /// + public IntPtr Memory + { + get { return _memory; } + protected set { _memory = value; } + } + + public MemoryRegion Parent + { + get { return _parent; } + } + + /// + /// Gets the size of the allocated memory. + /// + public virtual int Size + { + get { return _size; } + protected set { _size = value; } + } + + public void Fill(int offset, int length, byte value) + { + ProcessHacker.Native.Api.Win32.RtlFillMemory( + _memory.Increment(offset), + length.ToIntPtr(), + value + ); + } + + public MemoryRegionStream GetStream() + { + return new MemoryRegionStream(this); + } + + private int GetStructSizeCached(Type structType) + { + if (!_sizeCache.ContainsKey(structType)) + _sizeCache.Add(structType, Marshal.SizeOf(structType)); + + return _sizeCache[structType]; + } + + public MemoryRegion MakeChild(int offset, int size) + { + return new MemoryRegion(this, _memory.Increment(offset), size, true); + } + + public string ReadAnsiString(int offset) + { + return Marshal.PtrToStringAnsi(_memory.Increment(offset)); + } + + public string ReadAnsiString(int offset, int length) + { + return Marshal.PtrToStringAnsi(_memory.Increment(offset), length); + } + + public byte[] ReadBytes(int length) + { + return this.ReadBytes(0, length); + } + + public byte[] ReadBytes(int offset, int length) + { + byte[] buffer = new byte[length]; + + this.ReadBytes(offset, buffer, 0, length); + + return buffer; + } + + public void ReadBytes(byte[] buffer, int startIndex, int length) + { + this.ReadBytes(0, buffer, startIndex, length); + } + + public void ReadBytes(int offset, byte[] buffer, int startIndex, int length) + { + Marshal.Copy(_memory.Increment(offset), buffer, startIndex, length); + } + + /// + /// Reads a signed integer. + /// + /// The offset at which to begin reading. + /// The integer. + public int ReadInt32(int offset) + { + return this.ReadInt32(offset, 0); + } + + /// + /// Reads a signed integer. + /// + /// The offset at which to begin reading. + /// The index at which to begin reading, after the offset is added. + /// The integer. + public int ReadInt32(int offset, int index) + { + return Marshal.ReadInt32(_memory, offset + index * sizeof(int)); + } + + public IntPtr ReadIntPtr(int offset) + { + return this.ReadIntPtr(offset, 0); + } + + public IntPtr ReadIntPtr(int offset, int index) + { + return Marshal.ReadIntPtr(_memory, offset + index * IntPtr.Size); + } + + public void ReadMemory(IntPtr buffer, int destOffset, int srcOffset, int length) + { + ProcessHacker.Native.Api.Win32.RtlMoveMemory( + buffer.Increment(destOffset), + _memory.Increment(srcOffset), + length.ToIntPtr() + ); + } + + /// + /// Reads an unsigned integer. + /// + /// The offset at which to begin reading. + /// The integer. + public uint ReadUInt32(int offset) + { + return this.ReadUInt32(offset, 0); + } + + /// + /// Reads an unsigned integer. + /// + /// The offset at which to begin reading. + /// The index at which to begin reading, after the offset is added. + /// The integer. + public uint ReadUInt32(int offset, int index) + { + return (uint)this.ReadInt32(offset, index); + } + + /// + /// Creates a struct from the memory allocation. + /// + /// The type of the struct. + /// The new struct. + public T ReadStruct() + where T : struct + { + return this.ReadStruct(0); + } + + /// + /// Creates a struct from the memory allocation. + /// + /// The type of the struct. + /// The index at which to begin reading to the struct. This is multiplied by + /// the size of the struct. + /// The new struct. + public T ReadStruct(int index) + where T : struct + { + return this.ReadStruct(0, index); + } + + /// + /// Creates a struct from the memory allocation. + /// + /// The type of the struct. + /// The offset to add before reading. + /// The index at which to begin reading to the struct. This is multiplied by + /// the size of the struct. + /// The new struct. + public T ReadStruct(int offset, int index) + where T : struct + { + return (T)Marshal.PtrToStructure( + _memory.Increment(offset + this.GetStructSizeCached(typeof(T)) * index), typeof(T)); + } + + public string ReadUnicodeString(int offset) + { + return Marshal.PtrToStringUni(_memory.Increment(offset)); + } + + public string ReadUnicodeString(int offset, int length) + { + return Marshal.PtrToStringUni(_memory.Increment(offset), length); + } + + /// + /// Writes a single byte to the memory allocation. + /// + /// The offset at which to write. + /// The value of the byte. + public void WriteByte(int offset, byte b) + { + Marshal.WriteByte(this, offset, b); + } + + public void WriteBytes(int offset, byte[] b) + { + Marshal.Copy(b, 0, _memory.Increment(offset), b.Length); + } + + public void WriteInt16(int offset, short i) + { + Marshal.WriteInt16(this, offset, i); + } + + public void WriteInt32(int offset, int i) + { + Marshal.WriteInt32(this, offset, i); + } + + public void WriteIntPtr(int offset, IntPtr i) + { + Marshal.WriteIntPtr(this, offset, i); + } + + public void WriteMemory(int destOffset, IntPtr buffer, int srcOffset, int length) + { + ProcessHacker.Native.Api.Win32.RtlMoveMemory( + _memory.Increment(destOffset), + buffer.Increment(srcOffset), + length.ToIntPtr() + ); + } + + public void WriteStruct(T s) + where T : struct + { + this.WriteStruct(0, s); + } + + public void WriteStruct(int index, T s) + where T : struct + { + this.WriteStruct(0, index, s); + } + + public void WriteStruct(int offset, int index, T s) + where T : struct + { + Marshal.StructureToPtr(s, + _memory.Increment(offset + this.GetStructSizeCached(typeof(T)) * index), false); + } + + /// + /// Writes a Unicode string to the allocated memory. + /// + /// The offset to add. + /// The string to write. + public void WriteUnicodeString(int offset, string s) + { + byte[] b = UnicodeEncoding.Unicode.GetBytes(s); + + for (int i = 0; i < b.Length; i++) + Marshal.WriteByte(this.Memory, offset + i, b[i]); + } + + public void Zero(int offset, int length) + { + ProcessHacker.Native.Api.Win32.RtlZeroMemory( + _memory.Increment(offset), + length.ToIntPtr() + ); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Memory/MemoryRegionStream.cs b/branches/ph-plugins/ProcessHacker.Native/Memory/MemoryRegionStream.cs new file mode 100644 index 000000000..103fc20fe --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Memory/MemoryRegionStream.cs @@ -0,0 +1,114 @@ +/* + * Process Hacker - + * memory region stream + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.IO; +using System.Runtime.InteropServices; + +namespace ProcessHacker.Native +{ + public class MemoryRegionStream : Stream + { + private MemoryRegion _memory; + private long _position = 0; + + public MemoryRegionStream(MemoryRegion memory) + { + _memory = memory; + } + + public override bool CanRead + { + get { return true; } + } + + public override bool CanSeek + { + get { return true; } + } + + public override bool CanTimeout + { + get { return false; } + } + + public override bool CanWrite + { + get { return true; } + } + + public override void Flush() + { + // Do nothing + } + + public override long Length + { + get { return _memory.Size; } + } + + public override long Position + { + get { return _position; } + set { _position = value; } + } + + public override int Read(byte[] buffer, int offset, int count) + { + Marshal.Copy(_memory.Memory.Increment(_position += count), buffer, offset, count); + + return count; + } + + public override int ReadByte() + { + return Marshal.ReadByte(_memory.Memory.Increment(_position++)); + } + + public override long Seek(long offset, SeekOrigin origin) + { + if (origin == SeekOrigin.Begin) + _position = offset; + else if (origin == SeekOrigin.Current) + _position += offset; + else if (origin == SeekOrigin.End) + _position = _memory.Size + offset; + + return _position; + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + Marshal.Copy(buffer, offset, _memory.Memory.Increment(_position += count), count); + } + + public override void WriteByte(byte value) + { + Marshal.WriteByte(_memory.Memory.Increment(_position++), value); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Memory/PebMemoryAlloc.cs b/branches/ph-plugins/ProcessHacker.Native/Memory/PebMemoryAlloc.cs new file mode 100644 index 000000000..f160ecdf4 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Memory/PebMemoryAlloc.cs @@ -0,0 +1,60 @@ +/* + * Process Hacker - + * PEB memory allocation + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.ComponentModel; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native +{ + /// + /// Represents a memory allocation from the PEB. + /// + public sealed class PebMemoryAlloc : MemoryAlloc + { + public PebMemoryAlloc(int size) + { + NtStatus status; + IntPtr block; + + if ((status = Win32.RtlAllocateFromPeb(size, out block)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + this.Memory = block; + this.Size = size; + } + + protected override void Free() + { + NtStatus status; + + if ((status = Win32.RtlFreeToPeb(this, this.Size)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + [EditorBrowsable(EditorBrowsableState.Never)] + public override void Resize(int newSize) + { + throw new NotSupportedException(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Memory/PhysicalPages.cs b/branches/ph-plugins/ProcessHacker.Native/Memory/PhysicalPages.cs new file mode 100644 index 000000000..a0acc1032 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Memory/PhysicalPages.cs @@ -0,0 +1,132 @@ +using System; +using ProcessHacker.Common.Objects; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; + +namespace ProcessHacker.Native.Memory +{ + /// + /// Represents an allocation of physical pages. + /// + public sealed class PhysicalPages : BaseObject + { + private ProcessHandle _processHandle; + private int _count; + private IntPtr[] _pfnArray; + + /// + /// Allocates physical pages. + /// + /// The number of pages to allocate. + public PhysicalPages(int pageCount) + : this(pageCount, true) + { } + + /// + /// Allocates physical pages. + /// + /// + /// The number of bytes to allocate, or the number of pages to allocate + /// if is true. If a number of bytes is used, + /// it will be rounded up to the system page size. + /// + /// Whether specifies bytes or pages. + /// + public PhysicalPages(int count, bool pages) + : this(ProcessHandle.Current, count, pages) + { } + + /// + /// Allocates physical pages. + /// + /// The process to allocate the pages in. + /// The number of pages to allocate. + public PhysicalPages(ProcessHandle processHandle, int pageCount) + : this(processHandle, pageCount, true) + { } + + /// + /// Allocates physical pages. + /// + /// The process to allocate the pages in. + /// + /// The number of bytes to allocate, or the number of pages to allocate + /// if is true. If a number of bytes is used, + /// it will be rounded up to the system page size. + /// + /// Whether specifies bytes or pages. + /// + public PhysicalPages(ProcessHandle processHandle, int count, bool pages) + { + if (pages) + _count = count; + else + _count = Windows.BytesToPages(count); + + IntPtr pageCount = new IntPtr(_count); + + _pfnArray = new IntPtr[_count]; + + if (!Win32.AllocateUserPhysicalPages(processHandle, ref pageCount, _pfnArray)) + Win32.ThrowLastError(); + + if (pageCount.ToInt32() != _count) + throw new Exception("Could not allocate all pages."); + + _processHandle = processHandle; + _processHandle.Reference(); + } + + protected override void DisposeObject(bool disposing) + { + IntPtr freedPages = new IntPtr(_count); + + _processHandle.Dereference(); + + if (!Win32.FreeUserPhysicalPages(_processHandle, ref freedPages, _pfnArray)) + Win32.ThrowLastError(); + + if (freedPages.ToInt32() != _count) + throw new Exception("Could not free all pages."); + } + + public PhysicalPagesMapping Map(MemoryProtection protection) + { + return this.Map(IntPtr.Zero, protection); + } + + public PhysicalPagesMapping Map(IntPtr address, MemoryProtection protection) + { + // Reserve an address range. + IntPtr allocAddress = ProcessHandle.Current.AllocateMemory( + address, + _count * Windows.PageSize, + MemoryFlags.Reserve | MemoryFlags.Physical, + protection + ); + + // Map the physical memory into the address range. + if (!Win32.MapUserPhysicalPages( + allocAddress, + new IntPtr(_count), + _pfnArray + )) + Win32.ThrowLastError(); + + return new PhysicalPagesMapping(this, allocAddress); + } + + internal void Unmap(IntPtr address) + { + // Unmap the physical memory from the address range. + if (!Win32.MapUserPhysicalPages( + address, + new IntPtr(_count), + null + )) + Win32.ThrowLastError(); + + ProcessHandle.Current.FreeMemory(address, 0, false); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Memory/PhysicalPagesMapping.cs b/branches/ph-plugins/ProcessHacker.Native/Memory/PhysicalPagesMapping.cs new file mode 100644 index 000000000..ee1d5c134 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Memory/PhysicalPagesMapping.cs @@ -0,0 +1,23 @@ +using System; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native.Memory +{ + public sealed class PhysicalPagesMapping : MemoryAlloc + { + private PhysicalPages _physicalPages; + + internal PhysicalPagesMapping(PhysicalPages physicalPages, IntPtr baseAddress) + { + _physicalPages = physicalPages; + _physicalPages.Reference(); + this.Memory = baseAddress; + } + + protected override void Free() + { + _physicalPages.Unmap(this); + _physicalPages.Dereference(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Memory/PinnedObject.cs b/branches/ph-plugins/ProcessHacker.Native/Memory/PinnedObject.cs new file mode 100644 index 000000000..c1c675c22 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Memory/PinnedObject.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using ProcessHacker.Common.Objects; + +namespace ProcessHacker.Native +{ + public sealed class PinnedObject : BaseObject + { + private T _object; + private GCHandle _handle; + + public PinnedObject(T obj) + { + _object = obj; + _handle = GCHandle.Alloc(obj, GCHandleType.Pinned); + } + + protected override void DisposeObject(bool disposing) + { + _handle.Free(); + } + + public IntPtr Address + { + get { return _handle.AddrOfPinnedObject(); } + } + + public T Object + { + get { return _object; } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Memory/Section.cs b/branches/ph-plugins/ProcessHacker.Native/Memory/Section.cs new file mode 100644 index 000000000..7710ce9ce --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Memory/Section.cs @@ -0,0 +1,167 @@ +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native +{ + /// + /// Represents a section, a memory mapping. + /// + public sealed class Section : NativeObject + { + private MemoryProtection _originalProtection = MemoryProtection.ReadWrite; + + /// + /// Opens an existing section. + /// + /// The name of an existing section. + /// The desired access to the section. + public Section(string name, SectionAccess access) + { + this.Handle = new SectionHandle(name, access); + } + + /// + /// Creates a section backed by a file. + /// + /// A file handle. + public Section(FileHandle fileHandle) + : this(fileHandle, MemoryProtection.ReadWrite) + { } + + /// + /// Creates a section backed by a file. + /// + /// A file handle. + /// The page protection to apply to mappings. + public Section(FileHandle fileHandle, MemoryProtection protection) + : this(fileHandle, false, protection) + { } + + /// + /// Creates a section backed by a file. + /// + /// A file handle. + /// Whether to treat the file as an executable image. + /// The page protection to apply to mappings. + public Section(FileHandle fileHandle, bool image, MemoryProtection protection) + : this(null, fileHandle, image, protection) + { } + + /// + /// Creates a section backed by a file. + /// + /// The name of the section. + /// A file handle. + /// Whether to treat the file as an executable image. + /// The page protection to apply to mappings. + public Section(string name, FileHandle fileHandle, bool image, MemoryProtection protection) + { + _originalProtection = protection; + + this.Handle = SectionHandle.Create( + SectionAccess.All, + name, + ObjectFlags.OpenIf, + null, + fileHandle.GetSize(), + image ? SectionAttributes.Image : SectionAttributes.Commit, + protection, + fileHandle + ); + } + + /// + /// Creates a section backed by the page file (i.e. in memory). + /// + /// The maximum size of the section. + public Section(long maximumSize) + : this(maximumSize, MemoryProtection.ReadWrite) + { } + + /// + /// Creates a section backed by the page file (i.e. in memory). + /// + /// The maximum size of the section. + /// The page protection to apply to mappings. + public Section(long maximumSize, MemoryProtection protection) + : this(null, maximumSize, protection) + { } + + /// + /// Creates a section backed by the page file (i.e. in memory). + /// + /// The name of the section. + /// The maximum size of the section. + /// The page protection to apply to mappings. + public Section(string name, long maximumSize, MemoryProtection protection) + { + _originalProtection = protection; + + this.Handle = SectionHandle.Create( + SectionAccess.All, + name, + ObjectFlags.OpenIf, + null, + maximumSize, + SectionAttributes.Commit, + protection, + null + ); + } + + /// + /// Extends the size of the section. + /// + /// The new size of the section. + public void Extend(long newSize) + { + this.Handle.Extend(newSize); + } + + /// + /// Creates a view of the section. + /// + /// + /// The number of bytes to map. This value will be rounded up to the + /// page size. + /// + /// A view of the section. + public SectionView MapView(int size) + { + return this.MapView(size, _originalProtection); + } + + /// + /// Creates a view of the section. + /// + /// + /// The number of bytes to map. This value will be rounded up to the + /// page size. + /// + /// The page protection to apply to the mapping. + /// A view of the section. + public SectionView MapView(int size, MemoryProtection protection) + { + return this.Handle.MapView(0, size, protection); + } + + /// + /// Creates a view of the section. + /// + /// + /// The offset from the beginning of the section to map. This value + /// must be a multiple of 0x10000 (65536). + /// + /// + /// The number of bytes to map. This value will be rounded up to the + /// page size. + /// + /// The page protection to apply to the mapping. + /// A view of the section. + public SectionView MapView(int offset, int size, MemoryProtection protection) + { + return this.Handle.MapView(offset, size, protection); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Memory/SectionView.cs b/branches/ph-plugins/ProcessHacker.Native/Memory/SectionView.cs new file mode 100644 index 000000000..e43cd3e27 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Memory/SectionView.cs @@ -0,0 +1,78 @@ +/* + * Process Hacker - + * mapped view of section + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.ComponentModel; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; + +namespace ProcessHacker.Native +{ + /// + /// Represents a mapped view of a section. + /// + public sealed class SectionView : MemoryAlloc + { + internal SectionView(IntPtr baseAddress, IntPtr commitSize) + { + this.Memory = baseAddress; + this.Size = commitSize.ToInt32(); + } + + protected override void Free() + { + NtStatus status; + + if ((status = Win32.NtUnmapViewOfSection(ProcessHandle.Current, this)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + /// + /// Flushes the section view. + /// + /// A NT status value. + public NtStatus Flush() + { + return ProcessHandle.Current.FlushMemory(this, this.Size); + } + + /// + /// Determines whether the image section is the same as + /// another file section. + /// + /// A section mapped as a file. + /// Whether the two sections are the same. + public bool IsSameFile(SectionView mappedAsFile) + { + if ((uint)Win32.NtAreMappedFilesTheSame(this, mappedAsFile) == this.Memory.ToUInt32()) + return true; + else + return false; + } + + [EditorBrowsable(EditorBrowsableState.Never)] + public override void Resize(int newSize) + { + throw new NotSupportedException(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Memory/VirtualMemoryAlloc.cs b/branches/ph-plugins/ProcessHacker.Native/Memory/VirtualMemoryAlloc.cs new file mode 100644 index 000000000..f842a460c --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Memory/VirtualMemoryAlloc.cs @@ -0,0 +1,25 @@ +using System; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; + +namespace ProcessHacker.Native +{ + public class VirtualMemoryAlloc : MemoryAlloc + { + public VirtualMemoryAlloc(int size) + { + this.Memory = ProcessHandle.Current.AllocateMemory(size, MemoryProtection.ReadWrite); + this.Size = size; + } + + protected override void Free() + { + ProcessHandle.Current.FreeMemory(this, this.Size); + } + + public override void Resize(int newSize) + { + throw new NotSupportedException(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Memory/WtsMemoryAlloc.cs b/branches/ph-plugins/ProcessHacker.Native/Memory/WtsMemoryAlloc.cs new file mode 100644 index 000000000..170a86e9f --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Memory/WtsMemoryAlloc.cs @@ -0,0 +1,67 @@ +/* + * Process Hacker - + * terminal server memory allocation wrapper + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.ComponentModel; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native +{ + /// + /// Represents a memory allocation managed by the Terminal Server API. + /// + public class WtsMemoryAlloc : MemoryAlloc + { + public WtsMemoryAlloc(IntPtr memory) + : this(memory, true) + { } + + /// + /// Creates a memory allocation from an existing Terminal Server managed allocation. + /// + /// A pointer to the allocated memory. + /// Whether the memory allocation should be freed automatically. + public WtsMemoryAlloc(IntPtr memory, bool owned) + : base(memory, owned) + { } + + protected override void Free() + { + Win32.WTSFreeMemory(this); + } + + [EditorBrowsable(EditorBrowsableState.Never)] + public override void Resize(int newSize) + { + throw new NotSupportedException(); + } + + [EditorBrowsable(EditorBrowsableState.Never)] + public override int Size + { + get + { + throw new NotSupportedException(); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/NProcessHacker.cs b/branches/ph-plugins/ProcessHacker.Native/NProcessHacker.cs new file mode 100644 index 000000000..3783746de --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/NProcessHacker.cs @@ -0,0 +1,89 @@ +/* + * Process Hacker - + * interfacing code to native library + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Runtime.InteropServices; +using System.Security; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native +{ + [SuppressUnmanagedCodeSecurity] + public static class NProcessHacker + { + public enum WsInformationClass + { + WsCount = 0, + WsPrivateCount, + WsSharedCount, + WsShareableCount, + WsAllCounts + } + + [StructLayout(LayoutKind.Sequential)] + public struct WsAllCounts + { + public int Count; + public int PrivateCount; + public int SharedCount; + public int ShareableCount; + } + + [DllImport("nprocesshacker.dll")] + public static extern void KphHookDeinit(); + + [DllImport("nprocesshacker.dll")] + public static extern void KphHookInit(); + + [DllImport("nprocesshacker.dll", SetLastError = true)] + public static extern NtStatus PhQueryProcessWs( + [In] IntPtr ProcessHandle, + [In] WsInformationClass WsInformationClass, + [Out] out int WsInformation, + [In] int WsInformationLength, + [Out] out int ReturnLength + ); + + [DllImport("nprocesshacker.dll", SetLastError = true)] + public static extern NtStatus PhQueryProcessWs( + [In] IntPtr ProcessHandle, + [In] WsInformationClass WsInformationClass, + [Out] out WsAllCounts WsInformation, + [In] int WsInformationLength, + [Out] out int ReturnLength + ); + + [DllImport("nprocesshacker.dll", SetLastError = true)] + public static extern NtStatus PhQueryNameFileObject( + [In] IntPtr FileHandle, + [In] IntPtr FileObjectNameInformation, + [In] int FileObjectNameInformationLength, + [Out] [Optional] out int ReturnLength + ); + + [DllImport("nprocesshacker.dll")] + public static extern void PhVoid(); + + [DllImport("nprocesshacker.dll", CharSet = CharSet.Unicode)] + public static extern VerifyResult PhVerifyFile(string FileName); + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/NativeBitmap.cs b/branches/ph-plugins/ProcessHacker.Native/NativeBitmap.cs new file mode 100644 index 000000000..f0b5f4bff --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/NativeBitmap.cs @@ -0,0 +1,236 @@ +/* + * Process Hacker - + * bitmap + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Common; +using ProcessHacker.Common.Objects; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native +{ + public class NativeBitmap : BaseObject + { + public struct BitmapRun + { + public BitmapRun(int index, int length) + { + _index = index; + _length = length; + } + + private int _index; + private int _length; + + public int Index + { + get { return _index; } + set { _index = value; } + } + + public int Length + { + get { return _length; } + set { _length = value; } + } + } + + private RtlBitmap _bitmap; + private MemoryAlloc _buffer; + + public NativeBitmap(int bits) + { + if (bits <= 0) + throw new ArgumentOutOfRangeException("The number of bits must be positive."); + + _buffer = new MemoryAlloc(Utils.DivideUp(bits, 32) * 4); + Win32.RtlInitializeBitMap(out _bitmap, _buffer, bits); + } + + protected override void DisposeObject(bool disposing) + { + if (_buffer != null) + _buffer.Dispose(disposing); + } + + public bool AreClear(int index, int length) + { + return Win32.RtlAreBitsClear(ref _bitmap, index, length); + } + + public bool AreSet(int index, int length) + { + return Win32.RtlAreBitsSet(ref _bitmap, index, length); + } + + public int Check(int index) + { + return Win32.RtlCheckBit(ref _bitmap, index); + } + + public void Clear() + { + Win32.RtlClearAllBits(ref _bitmap); + } + + public void Clear(int index) + { + Win32.RtlClearBit(ref _bitmap, index); + } + + public void Clear(int index, int length) + { + Win32.RtlClearBits(ref _bitmap, index, length); + } + + public int FindClear(int length) + { + return this.FindClear(length, 0); + } + + public int FindClear(int length, int hintIndex) + { + return Win32.RtlFindClearBits(ref _bitmap, length, hintIndex); + } + + public int FindClearAndSet(int length) + { + return this.FindClearAndSet(length, 0); + } + + public int FindClearAndSet(int length, int hintIndex) + { + return Win32.RtlFindClearBitsAndSet(ref _bitmap, length, hintIndex); + } + + public BitmapRun[] FindClearRuns(int count) + { + return this.FindClearRuns(count, false); + } + + public BitmapRun[] FindClearRuns(int count, bool locateLongest) + { + RtlBitmapRun[] runs = new RtlBitmapRun[count]; + int numberOfRuns; + + numberOfRuns = Win32.RtlFindClearRuns(ref _bitmap, runs, count, locateLongest); + + BitmapRun[] returnRuns = new BitmapRun[numberOfRuns]; + + for (int i = 0; i < numberOfRuns; i++) + returnRuns[i] = new BitmapRun(runs[i].StartingIndex, runs[i].NumberOfBits); + + return returnRuns; + } + + public BitmapRun FindBackwardClearRun(int index) + { + int startingIndex; + int numberOfBits; + + numberOfBits = Win32.RtlFindLastBackwardRunClear(ref _bitmap, index, out startingIndex); + + return new BitmapRun(startingIndex, numberOfBits); + } + + public BitmapRun FindFirstClearRun() + { + int startingIndex; + int numberOfBits; + + numberOfBits = Win32.RtlFindFirstRunClear(ref _bitmap, out startingIndex); + + return new BitmapRun(startingIndex, numberOfBits); + } + + public BitmapRun FindForwardClearRun(int index) + { + int startingIndex; + int numberOfBits; + + numberOfBits = Win32.RtlFindNextForwardRunClear(ref _bitmap, index, out startingIndex); + + return new BitmapRun(startingIndex, numberOfBits); + } + + public BitmapRun FindLongestClearRun() + { + int startingIndex; + int numberOfBits; + + numberOfBits = Win32.RtlFindLongestRunClear(ref _bitmap, out startingIndex); + + return new BitmapRun(startingIndex, numberOfBits); + } + + public int FindSet(int length) + { + return this.FindSet(length, 0); + } + + public int FindSet(int length, int hintIndex) + { + return Win32.RtlFindSetBits(ref _bitmap, length, hintIndex); + } + + public int FindSetAndClear(int length) + { + return this.FindSetAndClear(length, 0); + } + + public int FindSetAndClear(int length, int hintIndex) + { + return Win32.RtlFindSetBitsAndClear(ref _bitmap, length, hintIndex); + } + + public int GetClearCount() + { + return Win32.RtlNumberOfClearBits(ref _bitmap); + } + + public int GetSetCount() + { + return Win32.RtlNumberOfSetBits(ref _bitmap); + } + + public void Set() + { + Win32.RtlSetAllBits(ref _bitmap); + } + + public void Set(int index) + { + Win32.RtlSetBit(ref _bitmap, index); + } + + public void Set(int index, int length) + { + Win32.RtlSetBits(ref _bitmap, index, length); + } + + public bool Test(int index) + { + return Win32.RtlTestBit(ref _bitmap, index); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/NativeObject.cs b/branches/ph-plugins/ProcessHacker.Native/NativeObject.cs new file mode 100644 index 000000000..c8760992b --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/NativeObject.cs @@ -0,0 +1,182 @@ +/* + * Process Hacker - + * native object wrapper code + * + * Copyright (C) 2009 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 . + */ + +using System; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; + +namespace ProcessHacker.Native +{ + public class NativeObject : IDisposable + { + public static void WaitAll(NativeObject[] objects) + { + NativeHandle.WaitAll(ObjectsToISync(objects)); + } + + public static void WaitAll(NativeObject[] objects, int timeout) + { + NativeHandle.WaitAll(ObjectsToISync(objects), false, timeout * Win32.TimeMsTo100Ns, true); + } + + public static void WaitAll(NativeObject[] objects, DateTime timeout) + { + NativeHandle.WaitAll(ObjectsToISync(objects), false, timeout.ToFileTime(), false); + } + + public static void WaitAny(NativeObject[] objects) + { + NativeHandle.WaitAny(ObjectsToISync(objects)); + } + + public static void WaitAny(NativeObject[] objects, int timeout) + { + NativeHandle.WaitAny(ObjectsToISync(objects), false, timeout * Win32.TimeMsTo100Ns, true); + } + + public static void WaitAny(NativeObject[] objects, DateTime timeout) + { + NativeHandle.WaitAny(ObjectsToISync(objects), false, timeout.ToFileTime(), false); + } + + private static ISynchronizable[] ObjectsToISync(NativeObject[] objects) + { + ISynchronizable[] newArray = new ISynchronizable[objects.Length]; + + for (int i = 0; i < newArray.Length; i++) + newArray[i] = objects[i].Handle; + + return newArray; + } + + private NativeHandle _handle; + + /// + /// Closes the reference to the object. + /// + public void Dispose() + { + _handle.Dispose(); + } + + /// + /// Gets the underlying handle for the object. + /// + public NativeHandle Handle + { + get { return _handle; } + protected set { _handle = value; } + } + + /// + /// Signals the object and waits for another. + /// + /// The object to wait for. + public WaitStatus SignalAndWait(NativeObject obj) + { + return (WaitStatus)_handle.SignalAndWait(obj.Handle); + } + + /// + /// Signals the object and waits for another. + /// + /// The object to wait for. + /// A timeout value, in milliseconds. + public WaitStatus SignalAndWait(NativeObject obj, int timeout) + { + return (WaitStatus)_handle.SignalAndWait(obj.Handle, false, timeout * Win32.TimeMsTo100Ns); + } + + /// + /// Signals the object and waits for another. + /// + /// The object to wait for. + /// A time to wait until. + public WaitStatus SignalAndWait(NativeObject obj, DateTime timeout) + { + return (WaitStatus)_handle.SignalAndWait(obj.Handle, false, timeout.ToFileTime(), false); + } + + /// + /// Waits for the object to be signaled. + /// + public WaitStatus Wait() + { + return (WaitStatus)_handle.Wait(); + } + + /// + /// Waits for the object to be signaled. + /// + /// A timeout value, in milliseconds. + public WaitStatus Wait(int timeout) + { + return (WaitStatus)_handle.Wait(timeout * Win32.TimeMsTo100Ns, true); + } + + /// + /// Waits for the object to be signaled. + /// + /// A time to wait until. + public WaitStatus Wait(DateTime timeout) + { + return (WaitStatus)_handle.Wait(timeout.ToFileTime(), false); + } + } + + public class NativeObject : NativeObject + where THandle : NativeHandle + { + protected new THandle Handle + { + get { return base.Handle as THandle; } + set { base.Handle = value; } + } + } + + public enum WaitStatus : uint + { + Wait0 = 0x00000000, + Wait1 = 0x00000001, + Wait2 = 0x00000002, + Wait3 = 0x00000003, + Wait4 = 0x00000004, + Wait5 = 0x00000005, + Wait6 = 0x00000006, + Wait7 = 0x00000007, + Wait63 = 0x0000003f, + Abandoned = 0x00000080, + AbandonedWait0 = 0x00000080, + AbandonedWait1 = 0x00000081, + AbandonedWait2 = 0x00000082, + AbandonedWait3 = 0x00000083, + AbandonedWait4 = 0x00000084, + AbandonedWait5 = 0x00000085, + AbandonedWait6 = 0x00000086, + AbandonedWait7 = 0x00000087, + AbandonedWait63 = 0x000000bf, + UserApc = 0x000000c0, + KernelApc = 0x00000100, + Alerted = 0x00000101, + Timeout = 0x00000102 + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/NativeTypeFactory.cs b/branches/ph-plugins/ProcessHacker.Native/NativeTypeFactory.cs new file mode 100644 index 000000000..e61bf6230 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/NativeTypeFactory.cs @@ -0,0 +1,607 @@ +/* + * Process Hacker - + * type factory + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Text; +using ProcessHacker.Common; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; +using ProcessHacker.Native.Security.AccessControl; + +namespace ProcessHacker.Native +{ + public static class NativeTypeFactory + { + private class FlagName + { + public string Name { get; set; } + public long Value { get; set; } + public bool Enabled { get; set; } + } + + public enum ObjectType + { + Adapter, + AlpcPort, + Callback, + DebugObject, + Desktop, + Device, + Directory, + Driver, + EtwRegistration, + Event, + EventPair, + File, + FilterCommunicationPort, + FilterConnectionPort, + IoCompletion, + Job, + Key, + KeyedEvent, + Mutant, + Process, + Profile, + Section, + Semaphore, + Service, + SymbolicLink, + Thread, + Timer, + TmEn, + TmRm, + TmTm, + TmTx, + Token, + TpWorkerFactory, + Type, + WindowStation, + WmiGuid + } + + #region Base Functions + + public static AccessEntry[] GetAccessEntries(ObjectType type) + { + AccessEntry[] entries; + + switch (type) + { + case ObjectType.AlpcPort: + entries = new AccessEntry[] + { + new AccessEntry("Full control", PortAccess.All, true, true), + new AccessEntry("Connect", PortAccess.Connect, true, true) + }; + break; + case ObjectType.DebugObject: + entries = new AccessEntry[] + { + new AccessEntry("Full control", DebugObjectAccess.All, true, true), + new AccessEntry("Read events", DebugObjectAccess.ReadEvent, true, true), + new AccessEntry("Assign processes", DebugObjectAccess.ProcessAssign, true, true), + new AccessEntry("Query information", DebugObjectAccess.QueryInformation, true, true), + new AccessEntry("Set information", DebugObjectAccess.SetInformation, true, true) + }; + break; + case ObjectType.Desktop: + entries = new AccessEntry[] + { + new AccessEntry("Full control", DesktopAccess.All, true, true), + new AccessEntry("Read", DesktopAccess.GenericRead, true, false), + new AccessEntry("Write", DesktopAccess.GenericWrite, true, false), + new AccessEntry("Execute", DesktopAccess.GenericExecute, true, false), + new AccessEntry("Enumerate", DesktopAccess.Enumerate, false, true), + new AccessEntry("Read objects", DesktopAccess.ReadObjects, false, true), + new AccessEntry("Playback journals", DesktopAccess.JournalPlayback, false, true), + new AccessEntry("Write objects", DesktopAccess.WriteObjects, false, true), + new AccessEntry("Create windows", DesktopAccess.CreateWindow, false, true), + new AccessEntry("Create menus", DesktopAccess.CreateMenu, false, true), + new AccessEntry("Create window hooks", DesktopAccess.HookControl, false, true), + new AccessEntry("Record journals", DesktopAccess.JournalRecord, false, true), + new AccessEntry("Switch desktop", DesktopAccess.SwitchDesktop, false, true) + }; + break; + case ObjectType.Directory: + entries = new AccessEntry[] + { + new AccessEntry("Full control", DirectoryAccess.All, true, true), + new AccessEntry("Query", DirectoryAccess.Query, true, true), + new AccessEntry("Traverse", DirectoryAccess.Traverse, true, true), + new AccessEntry("Create objects", DirectoryAccess.CreateObject, true, true), + new AccessEntry("Create subdirectories", DirectoryAccess.CreateSubdirectory, true, true) + }; + break; + case ObjectType.Event: + entries = new AccessEntry[] + { + new AccessEntry("Full control", EventAccess.All, true, true), + new AccessEntry("Query", EventAccess.QueryState, true, true), + new AccessEntry("Modify", EventAccess.ModifyState, true, true) + }; + break; + case ObjectType.EventPair: + entries = new AccessEntry[] + { + new AccessEntry("Full control", EventPairAccess.All, true, true) + }; + break; + case ObjectType.File: + entries = new AccessEntry[] + { + new AccessEntry("Full control", FileAccess.All, true, true), + new AccessEntry("Read & execute", FileAccess.GenericRead | FileAccess.GenericExecute, true, false), + new AccessEntry("Read", FileAccess.GenericRead, true, false), + new AccessEntry("Write", FileAccess.GenericWrite, true, false), + new AccessEntry("Traverse folder / execute file", FileAccess.Execute, false, true), + new AccessEntry("List folder / read data", FileAccess.ReadData, false, true), + new AccessEntry("Read attributes", FileAccess.ReadAttributes, false, true), + new AccessEntry("Read extended attributes", FileAccess.ReadEa, false, true), + new AccessEntry("Create files / write data", FileAccess.WriteData, false, true), + new AccessEntry("Create folders / append data", FileAccess.AppendData, false, true), + new AccessEntry("Write attributes", FileAccess.WriteAttributes, false, true), + new AccessEntry("Write extended attributes", FileAccess.WriteEa, false, true), + new AccessEntry("Delete subfolders and files", FileAccess.DeleteChild, false, true) + }; + break; + case ObjectType.IoCompletion: + entries = new AccessEntry[] + { + new AccessEntry("Full control", IoCompletionAccess.All, true, true), + new AccessEntry("Query", IoCompletionAccess.QueryState, true, true), + new AccessEntry("Modify", IoCompletionAccess.ModifyState, true, true) + }; + break; + case ObjectType.Job: + entries = new AccessEntry[] + { + new AccessEntry("Full control", JobObjectAccess.All, true, true), + new AccessEntry("Query", JobObjectAccess.Query, true, true), + new AccessEntry("Assign processes", JobObjectAccess.AssignProcess, true, true), + new AccessEntry("Set attributes", JobObjectAccess.SetAttributes, true, true), + new AccessEntry("Set security attributes", JobObjectAccess.SetSecurityAttributes, true, true), + new AccessEntry("Terminate", JobObjectAccess.Terminate, true, true) + }; + break; + case ObjectType.Key: + entries = new AccessEntry[] + { + new AccessEntry("Full control", KeyAccess.All, true, true), + new AccessEntry("Read", KeyAccess.GenericRead, true, false), + new AccessEntry("Write", KeyAccess.GenericWrite, true, false), + new AccessEntry("Execute", KeyAccess.GenericExecute, true, false), + new AccessEntry("Enumerate subkeys", KeyAccess.EnumerateSubKeys, false, true), + new AccessEntry("Query values", KeyAccess.QueryValue, false, true), + new AccessEntry("Notify", KeyAccess.Notify, false, true), + new AccessEntry("Set values", KeyAccess.SetValue, false, true), + new AccessEntry("Create subkeys", KeyAccess.CreateSubKey, false, true), + new AccessEntry("Create links", KeyAccess.CreateLink, false, true) + }; + break; + case ObjectType.KeyedEvent: + entries = new AccessEntry[] + { + new AccessEntry("Full control", KeyedEventAccess.All, true, true), + new AccessEntry("Wait", KeyedEventAccess.Wait, true, true), + new AccessEntry("Wake", KeyedEventAccess.Wake, true, true) + }; + break; + case ObjectType.Mutant: + entries = new AccessEntry[] + { + new AccessEntry("Full control", MutantAccess.All, true, true), + new AccessEntry("Query", MutantAccess.QueryState, true, true) + }; + break; + case ObjectType.Process: + entries = new AccessEntry[] + { + new AccessEntry("Full control", + OSVersion.HasQueryLimitedInformation ? + (ProcessAccess.All | ProcessAccess.QueryLimitedInformation) : + ProcessAccess.All, true, true), + OSVersion.HasQueryLimitedInformation ? + new AccessEntry("Query limited information", ProcessAccess.QueryLimitedInformation, true, true) : + new AccessEntry(null, 0, false, false), + new AccessEntry("Query information", + OSVersion.HasQueryLimitedInformation ? + (ProcessAccess.QueryInformation | ProcessAccess.QueryLimitedInformation) : + ProcessAccess.QueryInformation, true, true), + new AccessEntry("Set information", ProcessAccess.SetInformation, true, true), + new AccessEntry("Set quotas", ProcessAccess.SetQuota, true, true), + new AccessEntry("Set session ID", ProcessAccess.SetSessionId, true, true), + new AccessEntry("Create threads", ProcessAccess.CreateThread, true, true), + new AccessEntry("Create processes", ProcessAccess.CreateProcess, true, true), + new AccessEntry("Modify memory", ProcessAccess.VmOperation, true, true), + new AccessEntry("Read memory", ProcessAccess.VmRead, true, true), + new AccessEntry("Write memory", ProcessAccess.VmWrite, true, true), + new AccessEntry("Duplicate handles", ProcessAccess.DupHandle, true, true), + new AccessEntry("Suspend / resume / set port", ProcessAccess.SuspendResume, true, true), + new AccessEntry("Terminate", ProcessAccess.Terminate, true, true), + }; + break; + case ObjectType.Profile: + entries = new AccessEntry[] + { + new AccessEntry("Full control", ProfileAccess.All, true, true), + new AccessEntry("Control", ProfileAccess.Control, true, true) + }; + break; + case ObjectType.Section: + entries = new AccessEntry[] + { + new AccessEntry("Full control", SectionAccess.All, true, true), + new AccessEntry("Query", SectionAccess.Query, true, true), + new AccessEntry("Map for read", SectionAccess.MapRead, true, true), + new AccessEntry("Map for write", SectionAccess.MapWrite, true, true), + new AccessEntry("Map for execute", SectionAccess.MapExecute, true, true), + new AccessEntry("Map for execute (explicit)", SectionAccess.MapExecuteExplicit, true, true), + new AccessEntry("Extend size", SectionAccess.ExtendSize, true, true) + }; + break; + case ObjectType.Semaphore: + entries = new AccessEntry[] + { + new AccessEntry("Full control", SemaphoreAccess.All, true, true), + new AccessEntry("Query", SemaphoreAccess.QueryState, true, true), + new AccessEntry("Modify", SemaphoreAccess.ModifyState, true, true) + }; + break; + case ObjectType.Service: + entries = new AccessEntry[] + { + new AccessEntry("Full control", ServiceAccess.All, true, true), + new AccessEntry("Query status", ServiceAccess.QueryStatus, true, true), + new AccessEntry("Query configuration", ServiceAccess.QueryConfig, true, true), + new AccessEntry("Modify configuration", ServiceAccess.ChangeConfig, true, true), + new AccessEntry("Enumerate dependents", ServiceAccess.EnumerateDependents, true, true), + new AccessEntry("Start", ServiceAccess.Start, true, true), + new AccessEntry("Stop", ServiceAccess.Stop, true, true), + new AccessEntry("Pause / continue", ServiceAccess.PauseContinue, true, true), + new AccessEntry("Interrogate", ServiceAccess.Interrogate, true, true), + new AccessEntry("User-defined control", ServiceAccess.UserDefinedControl, true, true) + }; + break; + case ObjectType.SymbolicLink: + entries = new AccessEntry[] + { + new AccessEntry("Full control", SymbolicLinkAccess.All, true, true), + new AccessEntry("Query", SymbolicLinkAccess.Query, true, true) + }; + break; + case ObjectType.Thread: + entries = new AccessEntry[] + { + new AccessEntry("Full control", + OSVersion.HasQueryLimitedInformation ? + (ThreadAccess.All | ThreadAccess.QueryLimitedInformation | ThreadAccess.SetLimitedInformation) : + ThreadAccess.All, true, true), + OSVersion.HasQueryLimitedInformation ? + new AccessEntry("Query limited information", ThreadAccess.QueryLimitedInformation, true, true) : + new AccessEntry(null, 0, false, false), + new AccessEntry("Query information", ThreadAccess.QueryInformation, true, true), + OSVersion.HasQueryLimitedInformation ? + new AccessEntry("Set limited information", ThreadAccess.SetLimitedInformation, true, true) : + new AccessEntry(null, 0, false, false), + new AccessEntry("Set information", ThreadAccess.SetInformation, true, true), + new AccessEntry("Get context", ThreadAccess.GetContext, true, true), + new AccessEntry("Set context", ThreadAccess.SetContext, true, true), + new AccessEntry("Set token", ThreadAccess.SetThreadToken, true, true), + new AccessEntry("Alert", ThreadAccess.Alert, true, true), + new AccessEntry("Impersonate", ThreadAccess.Impersonate, true, true), + new AccessEntry("Direct impersonate", ThreadAccess.DirectImpersonation, true, true), + new AccessEntry("Suspend / resume", ThreadAccess.SuspendResume, true, true), + new AccessEntry("Terminate", ThreadAccess.Terminate, true, true), + }; + break; + case ObjectType.Timer: + entries = new AccessEntry[] + { + new AccessEntry("Full control", TimerAccess.All, true, true), + new AccessEntry("Query", TimerAccess.QueryState, true, true), + new AccessEntry("Modify", TimerAccess.ModifyState, true, true) + }; + break; + case ObjectType.TmEn: + entries = new AccessEntry[] + { + new AccessEntry("Full control", EnlistmentAccess.All, true, true), + new AccessEntry("Read", EnlistmentAccess.GenericRead, true, false), + new AccessEntry("Write", EnlistmentAccess.GenericWrite, true, false), + new AccessEntry("Execute", EnlistmentAccess.GenericExecute, true, false), + new AccessEntry("Query information", EnlistmentAccess.QueryInformation, false, true), + new AccessEntry("Set information", EnlistmentAccess.SetInformation, false, true), + new AccessEntry("Recover", EnlistmentAccess.Recover, false, true), + new AccessEntry("Subordinate rights", EnlistmentAccess.SubordinateRights, false, true), + new AccessEntry("Superior rights", EnlistmentAccess.SuperiorRights, false, true) + }; + break; + case ObjectType.TmRm: + entries = new AccessEntry[] + { + new AccessEntry("Full control", ResourceManagerAccess.All, true, true), + new AccessEntry("Read", ResourceManagerAccess.GenericRead, true, false), + new AccessEntry("Write", ResourceManagerAccess.GenericWrite, true, false), + new AccessEntry("Execute", ResourceManagerAccess.GenericExecute, true, false), + new AccessEntry("Query information", ResourceManagerAccess.QueryInformation, false, true), + new AccessEntry("Set information", ResourceManagerAccess.SetInformation, false, true), + new AccessEntry("Get notifications", ResourceManagerAccess.GetNotification, false, true), + new AccessEntry("Enlist", ResourceManagerAccess.Enlist, false, true), + new AccessEntry("Recover", ResourceManagerAccess.Recover, false, true), + new AccessEntry("Register protocols", ResourceManagerAccess.RegisterProtocol, false, true), + new AccessEntry("Complete propagation", ResourceManagerAccess.CompletePropagation, false, true) + }; + break; + case ObjectType.TmTm: + entries = new AccessEntry[] + { + new AccessEntry("Full control", TmAccess.All, true, true), + new AccessEntry("Read", TmAccess.GenericRead, true, false), + new AccessEntry("Write", TmAccess.GenericWrite, true, false), + new AccessEntry("Execute", TmAccess.GenericExecute, true, false), + new AccessEntry("Query information", TmAccess.QueryInformation, true, false), + new AccessEntry("Set information", TmAccess.SetInformation, true, false), + new AccessEntry("Recover", TmAccess.Recover, true, false), + new AccessEntry("Rename", TmAccess.Rename, true, false), + new AccessEntry("Create resource manager", TmAccess.CreateRm, true, false), + new AccessEntry("Bind transactions", TmAccess.BindTransaction, true, false) + }; + break; + case ObjectType.TmTx: + entries = new AccessEntry[] + { + new AccessEntry("Full control", TransactionAccess.All, true, true), + new AccessEntry("Read", TransactionAccess.GenericRead, true, false), + new AccessEntry("Write", TransactionAccess.GenericWrite, true, false), + new AccessEntry("Execute", TransactionAccess.GenericExecute, true, false), + new AccessEntry("Query information", TransactionAccess.QueryInformation, false, true), + new AccessEntry("Set information", TransactionAccess.SetInformation, false, true), + new AccessEntry("Enlist", TransactionAccess.Enlist, false, true), + new AccessEntry("Commit", TransactionAccess.Commit, false, true), + new AccessEntry("Rollback", TransactionAccess.Rollback, false, true), + new AccessEntry("Propagate", TransactionAccess.Propagate, false, true), + }; + break; + case ObjectType.Token: + entries = new AccessEntry[] + { + new AccessEntry("Full control", TokenAccess.All, true, true), + new AccessEntry("Read", TokenAccess.GenericRead, true, false), + new AccessEntry("Write", TokenAccess.GenericWrite, true, false), + new AccessEntry("Execute", TokenAccess.GenericExecute, true, false), + new AccessEntry("Adjust privileges", TokenAccess.AdjustPrivileges, false, true), + new AccessEntry("Adjust groups", TokenAccess.AdjustGroups, false, true), + new AccessEntry("Adjust defaults", TokenAccess.AdjustDefault, false, true), + new AccessEntry("Adjust session ID", TokenAccess.AdjustSessionId, false, true), + new AccessEntry("Assign as primary token", TokenAccess.AssignPrimary, false, true), + new AccessEntry("Duplicate", TokenAccess.Duplicate, false, true), + new AccessEntry("Impersonate", TokenAccess.Impersonate, false, true), + new AccessEntry("Query", TokenAccess.Query, false, true), + new AccessEntry("Query source", TokenAccess.QuerySource, false, true) + }; + break; + case ObjectType.Type: + entries = new AccessEntry[] + { + new AccessEntry("Full control", ObjectTypeAccess.All, true, true), + new AccessEntry("Create", ObjectTypeAccess.Create, true, true) + }; + break; + case ObjectType.WindowStation: + entries = new AccessEntry[] + { + new AccessEntry("Full control", WindowStationAccess.All, true, true), + new AccessEntry("Read", WindowStationAccess.GenericRead, true, false), + new AccessEntry("Write", WindowStationAccess.GenericWrite, true, false), + new AccessEntry("Execute", WindowStationAccess.GenericExecute, true, false), + new AccessEntry("Enumerate", WindowStationAccess.Enumerate, false, true), + new AccessEntry("Enumerate desktops", WindowStationAccess.EnumDesktops, false, true), + new AccessEntry("Read attributes", WindowStationAccess.ReadAttributes, false, true), + new AccessEntry("Read screen", WindowStationAccess.ReadScreen, false, true), + new AccessEntry("Access clipboard", WindowStationAccess.AccessClipboard, false, true), + new AccessEntry("Access global atoms", WindowStationAccess.AccessGlobalAtoms, false, true), + new AccessEntry("Create desktop", WindowStationAccess.CreateDesktop, false, true), + new AccessEntry("Write attributes", WindowStationAccess.WriteAttributes, false, true), + new AccessEntry("Exit windows", WindowStationAccess.ExitWindows, false, true) + }; + break; + default: + entries = null; + break; + } + + // Add the standard rights. + return Utils.Concat(entries, new AccessEntry[] + { + new AccessEntry("Synchronize", StandardRights.Synchronize, false, true), + new AccessEntry("Delete", StandardRights.Delete, false, true), + new AccessEntry("Read permissions", StandardRights.ReadControl, false, true), + new AccessEntry("Change permissions", StandardRights.WriteDac, false, true), + new AccessEntry("Take ownership", StandardRights.WriteOwner, false, true) + }); + } + + public static Type GetAccessType(ObjectType type) + { + switch (type) + { + case ObjectType.AlpcPort: + return typeof(PortAccess); + case ObjectType.DebugObject: + return typeof(DebugObjectAccess); + case ObjectType.Desktop: + return typeof(DesktopAccess); + case ObjectType.Directory: + return typeof(DirectoryAccess); + case ObjectType.Event: + return typeof(EventAccess); + case ObjectType.EventPair: + return typeof(EventPairAccess); + case ObjectType.File: + return typeof(FileAccess); + case ObjectType.FilterCommunicationPort: + case ObjectType.FilterConnectionPort: + return typeof(FltPortAccess); + case ObjectType.IoCompletion: + return typeof(IoCompletionAccess); + case ObjectType.Job: + return typeof(JobObjectAccess); + case ObjectType.Key: + return typeof(KeyAccess); + case ObjectType.KeyedEvent: + return typeof(KeyedEventAccess); + case ObjectType.Mutant: + return typeof(MutantAccess); + case ObjectType.Process: + return typeof(ProcessAccess); + case ObjectType.Profile: + return typeof(ProfileAccess); + case ObjectType.Section: + return typeof(SectionAccess); + case ObjectType.Semaphore: + return typeof(SemaphoreAccess); + case ObjectType.Service: + return typeof(ServiceAccess); + case ObjectType.SymbolicLink: + return typeof(SymbolicLinkAccess); + case ObjectType.Thread: + return typeof(ThreadAccess); + case ObjectType.Timer: + return typeof(TimerAccess); + case ObjectType.TmEn: + return typeof(EnlistmentAccess); + case ObjectType.TmRm: + return typeof(ResourceManagerAccess); + case ObjectType.TmTm: + return typeof(TmAccess); + case ObjectType.TmTx: + return typeof(TransactionAccess); + case ObjectType.Token: + return typeof(TokenAccess); + case ObjectType.Type: + return typeof(ObjectTypeAccess); + case ObjectType.WindowStation: + return typeof(WindowStationAccess); + default: + throw new NotSupportedException(); + } + } + + public static ObjectType GetObjectType(string typeName) + { + foreach (string value in Enum.GetNames(typeof(ObjectType))) + { + if (string.Equals(value, typeName, StringComparison.InvariantCultureIgnoreCase)) + return (ObjectType)Enum.Parse(typeof(ObjectType), value); + } + + if (string.Equals(typeName, "ALPC Port", StringComparison.InvariantCultureIgnoreCase)) + return ObjectType.AlpcPort; + if (string.Equals(typeName, "Port", StringComparison.InvariantCultureIgnoreCase)) + return ObjectType.AlpcPort; + if (string.Equals(typeName, "WaitablePort", StringComparison.InvariantCultureIgnoreCase)) + return ObjectType.AlpcPort; + + throw new NotSupportedException(); + } + + public static SeObjectType GetSeObjectType(ObjectType type) + { + switch (type) + { + case ObjectType.Desktop: + case ObjectType.WindowStation: + return SeObjectType.WindowObject; + case ObjectType.Service: + return SeObjectType.Service; + default: + return SeObjectType.KernelObject; + } + } + + #endregion + + public static string GetAccessString(Type accessType, object access) + { + StringBuilder accessSb = new StringBuilder(); + long accessLong = Convert.ToInt64(access); + var accessTypeNames = Utils.SortFlagNames(accessType). + ConvertAll((kvp) => new FlagName() { Name = kvp.Key, Value = kvp.Value, Enabled = true }); + var srNames = Utils.SortFlagNames(typeof(StandardRights)). + ConvertAll((kvp) => new FlagName() { Name = kvp.Key, Value = kvp.Value, Enabled = true }); + + // Get the strings for the matching bits in the given enum type. + foreach (var fn in accessTypeNames) + { + if ( + fn.Enabled && + (accessLong & fn.Value) == fn.Value + ) + { + accessSb.Append(fn.Name + ", "); + // Disable equal or more specific flag names in the lists. + accessTypeNames.ForEach((fn2) => + { + if ((fn.Value | fn2.Value) == fn.Value) + fn2.Enabled = false; + }); + srNames.ForEach((fn2) => + { + if ((fn.Value | fn2.Value) == fn.Value) + fn2.Enabled = false; + }); + } + } + + // Get the strings for the matching bits in standard rights. + foreach (var fn in srNames) + { + if ( + fn.Enabled && + (accessLong & fn.Value) == fn.Value + ) + { + accessSb.Append(fn.Name + ", "); + // Disable equal or more specific flag names in the lists. + srNames.ForEach((fn2) => + { + if ((fn.Value | fn2.Value) == fn.Value) + fn2.Enabled = false; + }); + } + } + + string accessString = accessSb.ToString(); + + // Removing trailing ", ". + if (accessString.EndsWith(", ")) + return accessString.Remove(accessString.Length - 2, 2); + else + return accessString; + } + + public static Type GetAccessType(string typeName) + { + return GetAccessType(GetObjectType(typeName)); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/NativeUtils.cs b/branches/ph-plugins/ProcessHacker.Native/NativeUtils.cs new file mode 100644 index 000000000..6a0c49bcd --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/NativeUtils.cs @@ -0,0 +1,229 @@ +using System; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using System.Runtime.InteropServices; + +namespace ProcessHacker.Native +{ + /// + /// Provides various utility methods. + /// + public static class NativeUtils + { + /// + /// Calls a function. + /// + /// The address of the function. + /// The first parameter to pass. + /// The second parameter to pass. + /// The third parameter to pass. + public static void Call(IntPtr address, IntPtr param1, IntPtr param2, IntPtr param3) + { + // Queue a user-mode APC to the current thread. + ThreadHandle.Current.QueueApc(address, param1, param2, param3); + // Flush the APC queue. + ThreadHandle.TestAlert(); + } + + public unsafe static void CopyProcessParameters( + ProcessHandle processHandle, + IntPtr peb, + ProcessCreationFlags creationFlags, + string imagePathName, + string dllPath, + string currentDirectory, + string commandLine, + EnvironmentBlock environment, + string windowTitle, + string desktopInfo, + string shellInfo, + string runtimeInfo, + ref StartupInfo startupInfo + ) + { + UnicodeString imagePathNameStr; + UnicodeString dllPathStr; + UnicodeString currentDirectoryStr; + UnicodeString commandLineStr; + UnicodeString windowTitleStr; + UnicodeString desktopInfoStr; + UnicodeString shellInfoStr; + UnicodeString runtimeInfoStr; + + // Create the unicode strings. + + imagePathNameStr = new UnicodeString(imagePathName); + dllPathStr = new UnicodeString(dllPath); + currentDirectoryStr = new UnicodeString(currentDirectory); + commandLineStr = new UnicodeString(commandLine); + windowTitleStr = new UnicodeString(windowTitle); + desktopInfoStr = new UnicodeString(desktopInfo); + shellInfoStr = new UnicodeString(shellInfo); + runtimeInfoStr = new UnicodeString(runtimeInfo); + + try + { + NtStatus status; + IntPtr processParameters; + + // Create the process parameter block. + + status = Win32.RtlCreateProcessParameters( + out processParameters, + ref imagePathNameStr, + ref dllPathStr, + ref currentDirectoryStr, + ref commandLineStr, + environment, + ref windowTitleStr, + ref desktopInfoStr, + ref shellInfoStr, + ref runtimeInfoStr + ); + + if (status >= NtStatus.Error) + Win32.ThrowLastError(status); + + try + { + // Allocate a new memory region in the remote process for + // the environment block and copy it over. + + int environmentLength; + IntPtr newEnvironment; + + environmentLength = environment.GetLength(); + newEnvironment = processHandle.AllocateMemory( + environmentLength, + MemoryProtection.ReadWrite + ); + + processHandle.WriteMemory( + newEnvironment, + environment, + environmentLength + ); + + // Copy over the startup info data. + RtlUserProcessParameters* paramsStruct = (RtlUserProcessParameters*)processParameters; + + paramsStruct->Environment = newEnvironment; + paramsStruct->StartingX = startupInfo.X; + paramsStruct->StartingY = startupInfo.Y; + paramsStruct->CountX = startupInfo.XSize; + paramsStruct->CountY = startupInfo.YSize; + paramsStruct->CountCharsX = startupInfo.XCountChars; + paramsStruct->CountCharsY = startupInfo.YCountChars; + paramsStruct->FillAttribute = startupInfo.FillAttribute; + paramsStruct->WindowFlags = startupInfo.Flags; + paramsStruct->ShowWindowFlags = startupInfo.ShowWindow; + + if ((startupInfo.Flags & StartupFlags.UseStdHandles) == StartupFlags.UseStdHandles) + { + paramsStruct->StandardInput = startupInfo.StdInputHandle; + paramsStruct->StandardOutput = startupInfo.StdOutputHandle; + paramsStruct->StandardError = startupInfo.StdErrorHandle; + } + + // TODO: Add console support. + + // Allocate a new memory region in the remote process for + // the process parameters. + + IntPtr newProcessParameters; + IntPtr regionSize = paramsStruct->Length.ToIntPtr(); + + newProcessParameters = processHandle.AllocateMemory( + IntPtr.Zero, + ref regionSize, + MemoryFlags.Commit, + MemoryProtection.ReadWrite + ); + + paramsStruct->MaximumLength = regionSize.ToInt32(); + + processHandle.WriteMemory(newProcessParameters, processParameters, paramsStruct->Length); + + // Modify the process parameters pointer in the PEB. + processHandle.WriteMemory( + peb.Increment(Peb.ProcessParametersOffset), + &newProcessParameters, + IntPtr.Size + ); + } + finally + { + Win32.RtlDestroyProcessParameters(processParameters); + } + } + finally + { + imagePathNameStr.Dispose(); + dllPathStr.Dispose(); + currentDirectoryStr.Dispose(); + commandLineStr.Dispose(); + windowTitleStr.Dispose(); + desktopInfoStr.Dispose(); + shellInfoStr.Dispose(); + runtimeInfoStr.Dispose(); + } + } + + public static string FormatNativeKeyName(string nativeKeyName) + { + const string hklmString = "\\registry\\machine"; + const string hkcrString = "\\registry\\machine\\software\\classes"; + string hkcuString = "\\registry\\user\\" + + System.Security.Principal.WindowsIdentity.GetCurrent().User.ToString().ToLower(); + string hkcucrString = "\\registry\\user\\" + + System.Security.Principal.WindowsIdentity.GetCurrent().User.ToString().ToLower() + "_classes"; + const string hkuString = "\\registry\\user"; + + if (nativeKeyName.ToLower().StartsWith(hkcrString)) + return "HKCR" + nativeKeyName.Substring(hkcrString.Length); + else if (nativeKeyName.ToLower().StartsWith(hklmString)) + return "HKLM" + nativeKeyName.Substring(hklmString.Length); + else if (nativeKeyName.ToLower().StartsWith(hkcucrString)) + return "HKCU\\Software\\Classes" + nativeKeyName.Substring(hkcucrString.Length); + else if (nativeKeyName.ToLower().StartsWith(hkcuString)) + return "HKCU" + nativeKeyName.Substring(hkcuString.Length); + else if (nativeKeyName.ToLower().StartsWith(hkuString)) + return "HKU" + nativeKeyName.Substring(hkuString.Length); + else + return nativeKeyName; + } + + public static string GetMessage(IntPtr dllHandle, int messageTableId, int messageLanguageId, int messageId) + { + NtStatus status; + IntPtr messageEntry; + string message; + + status = Win32.RtlFindMessage( + dllHandle, + messageTableId, + messageLanguageId, + messageId, + out messageEntry + ); + + if (status.IsError()) + return null; + + var region = new MemoryRegion(messageEntry); + var entry = region.ReadStruct(); + + // Read the message, depending on format. + if ((entry.Flags & MessageResourceFlags.Unicode) == MessageResourceFlags.Unicode) + { + message = region.ReadUnicodeString(MessageResourceEntry.TextOffset); + } + else + { + message = region.ReadAnsiString(MessageResourceEntry.TextOffset); + } + + return message; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/OSVersion.cs b/branches/ph-plugins/ProcessHacker.Native/OSVersion.cs new file mode 100644 index 000000000..fcd5159fb --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/OSVersion.cs @@ -0,0 +1,233 @@ +/* + * Process Hacker - + * operating system version information + * + * Copyright (C) 2009 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 . + */ + +using System; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native +{ + public enum OSArch + { + I386, + Amd64 + } + + public enum WindowsVersion + { + /// + /// Windows XP SP2, SP3. + /// + XP = 51, + + /// + /// Windows Server 2003. + /// + Server2003 = 52, + + /// + /// Windows Vista SP0, SP1, SP2, Windows Server 2008. + /// + Vista = 60, + + /// + /// Windows 7 SP0. + /// + Seven = 61, + + /// + /// An unreleased version of Windows. + /// + Unreleased = int.MaxValue + } + + public static class OSVersion + { + private static int _bits = IntPtr.Size * 8; + private static OSArch _arch = IntPtr.Size == 4 ? OSArch.I386 : OSArch.Amd64; + private static WindowsVersion _windowsVersion; + + private static ProcessAccess _minProcessQueryInfoAccess = ProcessAccess.QueryInformation; + private static ThreadAccess _minThreadQueryInfoAccess = ThreadAccess.QueryInformation; + private static ThreadAccess _minThreadSetInfoAccess = ThreadAccess.SetInformation; + + private static bool _hasCycleTime = false; + private static bool _hasExtendedTaskbar = false; + private static bool _hasProtectedProcesses = false; + private static bool _hasPsSuspendResumeProcess = false; + private static bool _hasQueryLimitedInformation = false; + private static bool _hasSetAccessToken = false; + private static bool _hasTaskDialogs = false; + private static bool _hasUac = false; + private static bool _hasWin32ImageFileName = false; + + static OSVersion() + { + System.Version version = Environment.OSVersion.Version; + + if (version.Major == 5 && version.Minor == 1) + _windowsVersion = WindowsVersion.XP; + else if (version.Major == 5 && version.Minor == 2) + _windowsVersion = WindowsVersion.Server2003; + else if (version.Major == 6 && version.Minor == 0) + _windowsVersion = WindowsVersion.Vista; + else if (version.Major == 6 && version.Minor == 1) + _windowsVersion = WindowsVersion.Seven; + else if ((version.Major == 6 && version.Minor > 1) || version.Major > 6) + _windowsVersion = WindowsVersion.Unreleased; + + if (IsBelow(WindowsVersion.Vista)) + { + _hasSetAccessToken = true; + } + + if (IsAboveOrEqual(WindowsVersion.Vista)) + { + _minProcessQueryInfoAccess = ProcessAccess.QueryLimitedInformation; + _minThreadQueryInfoAccess = ThreadAccess.QueryLimitedInformation; + _minThreadSetInfoAccess = ThreadAccess.SetLimitedInformation; + + _hasCycleTime = true; + _hasProtectedProcesses = true; + _hasPsSuspendResumeProcess = true; + _hasQueryLimitedInformation = true; + _hasTaskDialogs = true; + _hasUac = true; + _hasWin32ImageFileName = true; + } + + if (IsAboveOrEqual(WindowsVersion.Seven)) + { + _hasExtendedTaskbar = true; + } + } + + public static int Bits + { + get { return _bits; } + } + + public static string BitsString + { + get { return _bits.ToString() + "-" + "bit"; } + } + + public static OSArch Architecture + { + get { return _arch; } + } + + public static WindowsVersion WindowsVersion + { + get { return _windowsVersion; } + } + + public static ProcessAccess MinProcessQueryInfoAccess + { + get { return _minProcessQueryInfoAccess; } + } + + public static ThreadAccess MinThreadQueryInfoAccess + { + get { return _minThreadQueryInfoAccess; } + } + + public static ThreadAccess MinThreadSetInfoAccess + { + get { return _minThreadSetInfoAccess; } + } + + public static bool HasCycleTime + { + get { return _hasCycleTime; } + } + + public static bool HasExtendedTaskbar + { + get { return _hasExtendedTaskbar; } + } + + public static bool HasProtectedProcesses + { + get { return _hasProtectedProcesses; } + } + + public static bool HasPsSuspendResumeProcess + { + get { return _hasPsSuspendResumeProcess; } + } + + public static bool HasQueryLimitedInformation + { + get { return _hasQueryLimitedInformation; } + } + + public static bool HasSetAccessToken + { + get { return _hasSetAccessToken; } + } + + public static bool HasTaskDialogs + { + get { return _hasTaskDialogs; } + } + + public static bool HasUac + { + get { return _hasUac; } + } + + public static bool HasWin32ImageFileName + { + get { return _hasWin32ImageFileName; } + } + + public static bool IsAmd64() + { + return _arch == OSArch.Amd64; + } + + public static bool IsI386() + { + return _arch == OSArch.I386; + } + + public static bool IsAbove(WindowsVersion version) + { + return (int)_windowsVersion > (int)version; + } + + public static bool IsAboveOrEqual(WindowsVersion version) + { + return (int)_windowsVersion >= (int)version; + } + + public static bool IsBelowOrEqual(WindowsVersion version) + { + return (int)_windowsVersion <= (int)version; + } + + public static bool IsBelow(WindowsVersion version) + { + return (int)_windowsVersion < (int)version; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/DebugObjectHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/DebugObjectHandle.cs new file mode 100644 index 000000000..03f81eaed --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/DebugObjectHandle.cs @@ -0,0 +1,134 @@ +/* + * Process Hacker - + * debug object handle + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + public sealed class DebugObjectHandle : NativeHandle + { + public static DebugObjectHandle Create(DebugObjectAccess access, DebugObjectFlags flags) + { + return Create(access, null, flags); + } + + public static DebugObjectHandle Create(DebugObjectAccess access, string name, DebugObjectFlags flags) + { + return Create(access, name, 0, null, flags); + } + + public static DebugObjectHandle Create(DebugObjectAccess access, string name, ObjectFlags objectFlags, DirectoryHandle rootDirectory, DebugObjectFlags flags) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtCreateDebugObject( + out handle, + access, + ref oa, + flags + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + return new DebugObjectHandle(handle, true); + } + + public DebugObjectHandle FromHandle(IntPtr handle) + { + return new DebugObjectHandle(handle, false); + } + + internal DebugObjectHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + public DebugObjectHandle(ProcessHandle processHandle) + { + this.Handle = processHandle.GetDebugObjectHandle(); + + // Check if we got a handle. If we didn't the process is not being debugged. + if (this.Handle == IntPtr.Zero) + throw new WindowsException(NtStatus.DebuggerInactive); + } + + public void Continue(ClientId cid, NtStatus continueStatus) + { + NtStatus status; + + if ((status = Win32.NtDebugContinue( + this, + ref cid, + continueStatus + )) > NtStatus.Error) + Win32.ThrowLastError(status); + } + + public void SetFlags(DebugObjectFlags flags) + { + unsafe + { + NtStatus status; + int retLength; + + if ((status = Win32.NtSetInformationDebugObject( + this, + DebugObjectInformationClass.DebugObjectFlags, + new IntPtr(&flags), + sizeof(DebugObjectFlags), + out retLength + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + } + + public IntPtr WaitForDebugEvent(bool alertable, long timeout, bool timeoutRelative) + { + // FIXME + throw new NotImplementedException(); + + //NtStatus status; + //long realTimeout = timeoutRelative ? -timeout : timeout; + + //if ((status = Win32.NtWaitForDebugEvent( + // this, + // alertable, + // ref realTimeout, + // IntPtr.Zero + // )) >= NtStatus.Error) + // Win32.ThrowLastError(status); + + //return IntPtr.Zero; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/DesktopHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/DesktopHandle.cs new file mode 100644 index 000000000..3121bf3d6 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/DesktopHandle.cs @@ -0,0 +1,77 @@ +/* + * Process Hacker - + * desktop handle + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + public sealed class DesktopHandle : UserHandle + { + public static DesktopHandle GetCurrent() + { + return GetThreadDesktop(Win32.GetCurrentThreadId()); + } + + public static DesktopHandle GetThreadDesktop(int threadId) + { + IntPtr handle = Win32.GetThreadDesktop(threadId); + + if (handle == IntPtr.Zero) + Win32.ThrowLastError(); + + return new DesktopHandle(handle, false); + } + + public DesktopHandle(string name, bool allowOtherAccountHook, DesktopAccess access) + { + this.Handle = Win32.OpenDesktop(name, allowOtherAccountHook ? 1 : 0, false, access); + + if (this.Handle == IntPtr.Zero) + Win32.ThrowLastError(); + } + + private DesktopHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + protected override void Close() + { + Win32.CloseDesktop(this); + } + + public void SetCurrent() + { + if (!Win32.SetThreadDesktop(this)) + Win32.ThrowLastError(); + } + + public void Switch() + { + if (!Win32.SwitchDesktop(this)) + Win32.ThrowLastError(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/DirectoryHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/DirectoryHandle.cs new file mode 100644 index 000000000..92d0f35cf --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/DirectoryHandle.cs @@ -0,0 +1,181 @@ +/* + * Process Hacker - + * directory handle + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + /// + /// Represents a directory object, which contains a collection of objects. + /// + public class DirectoryHandle : NativeHandle + { + public delegate bool EnumObjectsDelegate(ObjectEntry obj); + + public struct ObjectEntry + { + private string _name; + private string _typeName; + + public ObjectEntry(string name, string typeName) + { + _name = name; + _typeName = typeName; + } + + public string Name { get { return _name; } } + public string TypeName { get { return _typeName; } } + } + + public static DirectoryHandle Create(DirectoryAccess access, string name) + { + return Create(access, name, 0, null); + } + + public static DirectoryHandle Create(DirectoryAccess access, string name, ObjectFlags objectFlags, DirectoryHandle rootDirectory) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtCreateDirectoryObject(out handle, access, ref oa)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + return new DirectoryHandle(handle, true); + } + + protected DirectoryHandle() + { } + + protected DirectoryHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + public DirectoryHandle(string name, ObjectFlags objectFlags, DirectoryHandle rootDirectory, DirectoryAccess access) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtOpenDirectoryObject(out handle, access, ref oa)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + this.Handle = handle; + } + + public DirectoryHandle(string name, DirectoryAccess access) + : this(name, 0, null, access) + { } + + public void EnumObjects(EnumObjectsDelegate callback) + { + NtStatus status; + int context = 0; + bool firstTime = true; + int retLength; + + using (var data = new MemoryAlloc(0x200)) + { + while (true) + { + while ((status = Win32.NtQueryDirectoryObject( + this, + data, + data.Size, + false, + firstTime, + ref context, + out retLength + )) == NtStatus.MoreEntries) + { + // Check if we have at least one entry. If not, + // we need to double the buffer size and try again. + if (data.ReadStruct(0).Name.Buffer != IntPtr.Zero) + break; + + if (data.Size > 16 * 1024 * 1024) + Win32.ThrowLastError(status); + + data.Resize(data.Size * 2); + } + + if (status >= NtStatus.Error) + Win32.ThrowLastError(status); + + int i = 0; + + while (true) + { + ObjectDirectoryInformation info = data.ReadStruct(i); + + if (info.Name.Buffer == IntPtr.Zero) + break; + + if (!callback(new ObjectEntry(info.Name.Read(), info.TypeName.Read()))) + return; + + i++; + } + + if (status != NtStatus.MoreEntries) + break; + + firstTime = false; + } + } + } + + /// + /// Gets the objects contained in the directory object. + /// + /// An array of object entries. + public ObjectEntry[] GetObjects() + { + var objects = new List(); + + this.EnumObjects((obj) => + { + objects.Add(obj); + return true; + }); + + return objects.ToArray(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/DriverHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/DriverHandle.cs new file mode 100644 index 000000000..cc77c30f1 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/DriverHandle.cs @@ -0,0 +1,111 @@ +/* + * Process Hacker - + * driver handle + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Runtime.InteropServices; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native.Objects +{ + public class DriverHandle : NativeHandle + { + public DriverHandle(string name) + : this(name, 0, null) + { } + + public DriverHandle(string name, ObjectFlags objectFlags, DirectoryHandle rootDirectory) + { + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + + try + { + this.Handle = KProcessHacker.Instance.KphOpenDriver(oa).ToIntPtr(); + } + finally + { + oa.Dispose(); + } + } + + public DriverBasicInformation GetBasicInformation() + { + unsafe + { + DriverBasicInformation basicInfo; + int retLength; + + KProcessHacker.Instance.KphQueryInformationDriver( + this, + DriverInformationClass.DriverBasicInformation, + new IntPtr(&basicInfo), + Marshal.SizeOf(typeof(DriverBasicInformation)), + out retLength + ); + + return basicInfo; + } + } + + public string GetDriverName() + { + return this.GetInformationUnicodeString(DriverInformationClass.DriverNameInformation); + } + + private string GetInformationUnicodeString(DriverInformationClass infoClass) + { + using (MemoryAlloc data = new MemoryAlloc(0x1000)) + { + int retLength = 0; + + try + { + KProcessHacker.Instance.KphQueryInformationDriver( + this, + infoClass, + data, + data.Size, + out retLength + ); + } + catch (WindowsException) + { + data.Resize(retLength); + + KProcessHacker.Instance.KphQueryInformationDriver( + this, + infoClass, + data, + data.Size, + out retLength + ); + } + + return data.ReadStruct().Read(); + } + } + + public string GetServiceKeyName() + { + return this.GetInformationUnicodeString(DriverInformationClass.DriverServiceKeyNameInformation); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/EnlistmentHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/EnlistmentHandle.cs new file mode 100644 index 000000000..a58d6723c --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/EnlistmentHandle.cs @@ -0,0 +1,217 @@ +/* + * Process Hacker - + * enlistment handle + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Runtime.InteropServices; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + public class EnlistmentHandle : NativeHandle + { + public static EnlistmentHandle Create( + EnlistmentAccess access, + string name, + ObjectFlags objectFlags, + DirectoryHandle rootDirectory, + ResourceManagerHandle resourceManagerHandle, + TransactionHandle transactionHandle, + EnlistmentOptions createOptions, + NotificationMask notificationMask, + IntPtr enlistmentKey + ) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtCreateEnlistment( + out handle, + access, + resourceManagerHandle, + transactionHandle, + ref oa, + createOptions, + notificationMask, + enlistmentKey + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + return new EnlistmentHandle(handle, true); + } + + public static EnlistmentHandle FromHandle(IntPtr handle) + { + return new EnlistmentHandle(handle, false); + } + + private EnlistmentHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + public EnlistmentHandle( + string name, + ObjectFlags objectFlags, + DirectoryHandle rootDirectory, + ResourceManagerHandle resourceManagerHandle, + Guid guid, + EnlistmentAccess access + ) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtOpenEnlistment( + out handle, + access, + resourceManagerHandle, + ref guid, + ref oa + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + this.Handle = handle; + } + + public void Commit(long virtualClock) + { + NtStatus status; + + if ((status = Win32.NtCommitEnlistment(this, ref virtualClock)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + public void CommitComplete(long virtualClock) + { + NtStatus status; + + if ((status = Win32.NtCommitComplete(this, ref virtualClock)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + public EnlistmentBasicInformation GetBasicInformation() + { + NtStatus status; + EnlistmentBasicInformation basicInfo; + int retLength; + + if ((status = Win32.NtQueryInformationEnlistment( + this, + EnlistmentInformationClass.EnlistmentBasicInformation, + out basicInfo, + Marshal.SizeOf(typeof(EnlistmentBasicInformation)), + out retLength + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return basicInfo; + } + + public void Prepare(long virtualClock) + { + NtStatus status; + + if ((status = Win32.NtPrepareEnlistment(this, ref virtualClock)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + public void PrepareComplete(long virtualClock) + { + NtStatus status; + + if ((status = Win32.NtPrepareComplete(this, ref virtualClock)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + public void PrePrepare(long virtualClock) + { + NtStatus status; + + if ((status = Win32.NtPrePrepareEnlistment(this, ref virtualClock)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + public void PrePrepareComplete(long virtualClock) + { + NtStatus status; + + if ((status = Win32.NtPrePrepareComplete(this, ref virtualClock)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + public void ReadOnly(long virtualClock) + { + NtStatus status; + + if ((status = Win32.NtReadOnlyEnlistment(this, ref virtualClock)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + public void Recover(IntPtr enlistmentKey) + { + NtStatus status; + + if ((status = Win32.NtRecoverEnlistment(this, enlistmentKey)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + public void RejectSinglePhase(long virtualClock) + { + NtStatus status; + + if ((status = Win32.NtSinglePhaseReject(this, ref virtualClock)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + public void Rollback(long virtualClock) + { + NtStatus status; + + if ((status = Win32.NtRollbackEnlistment(this, ref virtualClock)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + public void RollbackComplete(long virtualClock) + { + NtStatus status; + + if ((status = Win32.NtRollbackComplete(this, ref virtualClock)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/EnvironmentBlock.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/EnvironmentBlock.cs new file mode 100644 index 000000000..e02ae3007 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/EnvironmentBlock.cs @@ -0,0 +1,200 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Common.Objects; +using ProcessHacker.Native.Api; +using System.Runtime.InteropServices; + +namespace ProcessHacker.Native.Objects +{ + public struct EnvironmentBlock + { + public static EnvironmentBlock GetCurrent() + { + unsafe + { + return new EnvironmentBlock(ProcessHandle.GetCurrentProcessParameters()->Environment); + } + } + + public static string GetCurrentVariable(string name) + { + return GetCurrent().GetVariable(name); + } + + public static void SetCurrentVariable(string name, string value) + { + NtStatus status; + UnicodeString nameStr; + UnicodeString valueStr; + + nameStr = new UnicodeString(name); + + try + { + valueStr = new UnicodeString(value); + + try + { + if ((status = Win32.RtlSetEnvironmentVariable( + IntPtr.Zero, + ref nameStr, + ref valueStr + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + valueStr.Dispose(); + } + } + finally + { + nameStr.Dispose(); + } + } + + public static implicit operator IntPtr(EnvironmentBlock environmentBlock) + { + return environmentBlock.Memory; + } + + private IntPtr _environment; + + public EnvironmentBlock(bool cloneCurrent) + { + NtStatus status; + + if ((status = Win32.RtlCreateEnvironment( + cloneCurrent, + out _environment + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + public EnvironmentBlock(IntPtr environment) + { + _environment = environment; + } + + public IntPtr Memory + { + get { return _environment; } + } + + public void Destroy() + { + Win32.RtlDestroyEnvironment(this); + } + + public unsafe int GetLength() + { + short* ptr = (short*)_environment; + + while (*ptr != 0) + while (*ptr++ != 0) + ; + + ptr++; + + return (new IntPtr(ptr)).Decrement(_environment).ToInt32(); + } + + public string GetVariable(string name) + { + NtStatus status; + UnicodeString nameStr; + UnicodeString valueStr; + + nameStr = new UnicodeString(name); + + try + { + using (var data = new MemoryAlloc(100)) + { + valueStr = new UnicodeString(); + valueStr.Buffer = data; + valueStr.MaximumLength = (ushort)data.Size; + + status = Win32.RtlQueryEnvironmentVariable_U( + this, + ref nameStr, + ref valueStr + ); + + if (status == NtStatus.BufferTooSmall) + { + // Resize and try again (+2 for the null terminator). + data.Resize(valueStr.Length + 2); + valueStr.Buffer = data; + valueStr.MaximumLength = (ushort)(valueStr.Length + 2); + + status = Win32.RtlQueryEnvironmentVariable_U( + this, + ref nameStr, + ref valueStr + ); + } + + if (status >= NtStatus.Error) + Win32.ThrowLastError(status); + + return valueStr.Read(); + } + } + finally + { + nameStr.Dispose(); + } + } + + public EnvironmentBlock SetCurrent() + { + NtStatus status; + IntPtr previousEnvironment; + + if ((status = Win32.RtlSetCurrentEnvironment( + this, + out previousEnvironment + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return new EnvironmentBlock(previousEnvironment); + } + + public void SetVariable(string name, string value) + { + NtStatus status; + IntPtr environment = _environment; + UnicodeString nameStr; + UnicodeString valueStr; + + nameStr = new UnicodeString(name); + + try + { + valueStr = new UnicodeString(value); + + try + { + if ((status = Win32.RtlSetEnvironmentVariable( + ref environment, + ref nameStr, + ref valueStr + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + valueStr.Dispose(); + } + } + finally + { + nameStr.Dispose(); + } + + _environment = environment; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/EventHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/EventHandle.cs new file mode 100644 index 000000000..d8de8f698 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/EventHandle.cs @@ -0,0 +1,159 @@ +/* + * Process Hacker - + * event handle + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Runtime.InteropServices; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + public sealed class EventHandle : NativeHandle + { + public static EventHandle Create(EventAccess access, EventType type, bool initialState) + { + return Create(access, null, type, initialState); + } + + public static EventHandle Create(EventAccess access, string name, EventType type, bool initialState) + { + return Create(access, name, 0, null, type, initialState); + } + + public static EventHandle Create(EventAccess access, string name, ObjectFlags objectFlags, DirectoryHandle rootDirectory, EventType type, bool initialState) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtCreateEvent(out handle, access, ref oa, type, initialState)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + return new EventHandle(handle, true); + } + + public static EventHandle FromHandle(IntPtr handle) + { + return new EventHandle(handle, false); + } + + private EventHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + public EventHandle(string name, EventAccess access) + : this(name, 0, null, access) + { } + + public EventHandle(string name, ObjectFlags objectFlags, DirectoryHandle rootDirectory, EventAccess access) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtOpenEvent(out handle, access, ref oa)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + this.Handle = handle; + } + + public void Clear() + { + NtStatus status; + + if ((status = Win32.NtClearEvent(this)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + public EventBasicInformation GetBasicInformation() + { + NtStatus status; + EventBasicInformation ebi; + int retLength; + + if ((status = Win32.NtQueryEvent(this, EventInformationClass.EventBasicInformation, + out ebi, Marshal.SizeOf(typeof(EventBasicInformation)), out retLength)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return ebi; + } + + public int Pulse() + { + NtStatus status; + int previousState; + + if ((status = Win32.NtPulseEvent(this, out previousState)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return previousState; + } + + public int Reset() + { + NtStatus status; + int previousState; + + if ((status = Win32.NtResetEvent(this, out previousState)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return previousState; + } + + public int Set() + { + NtStatus status; + int previousState; + + if ((status = Win32.NtSetEvent(this, out previousState)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return previousState; + } + + /// + /// Sets the event and causes the waiting thread to be context switched + /// to regardless of its priority. + /// + public void SetBoostPriority() + { + NtStatus status; + + if ((status = Win32.NtSetEventBoostPriority(this)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/EventPairHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/EventPairHandle.cs new file mode 100644 index 000000000..2cae45480 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/EventPairHandle.cs @@ -0,0 +1,191 @@ +/* + * Process Hacker - + * event pair handle + * + * Copyright (C) 2009 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 . + */ + +using System; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + /// + /// Represents an event pair, an object consisting of two events, high and low. + /// + public sealed class EventPairHandle : NativeHandle + { + /// + /// Creates an unnamed event pair. + /// + /// The desired access to the event pair. + /// A handle to an event pair. + public static EventPairHandle Create(EventPairAccess access) + { + return Create(access, null, 0, null); + } + + /// + /// Creates an event pair. + /// + /// The desired access to the event pair. + /// + /// The name of the event pair. If rootDirectory is null, you must specify a fully + /// qualified name. Example: \BaseNamedObjects\MyEventPair. + /// + /// The flags to use when creating the object. + /// + /// The directory in which to place the event pair. This can be null. + /// + /// A handle to an event pair. + public static EventPairHandle Create(EventPairAccess access, string name, ObjectFlags objectFlags, DirectoryHandle rootDirectory) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtCreateEventPair(out handle, access, ref oa)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + return new EventPairHandle(handle, true); + } + + public static EventPairHandle FromHandle(IntPtr handle) + { + return new EventPairHandle(handle, false); + } + + private EventPairHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + /// + /// Opens a named event pair. + /// + /// + /// The name of the event pair. If rootDirectory is null, + /// you must specify a fully qualified name. + /// The flags to use when opening the object. + /// The directory object in which the event pair can be found. + /// The desired access to the event pair. + public EventPairHandle(string name, ObjectFlags objectFlags, DirectoryHandle rootDirectory, EventPairAccess access) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtOpenEventPair(out handle, access, ref oa)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + this.Handle = handle; + } + + public EventPairHandle(string name, EventPairAccess access) + : this(name, 0, null, access) + { } + + /// + /// Sets the high event. + /// + public void SetHigh() + { + NtStatus status; + + if ((status = Win32.NtSetHighEventPair(this)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + /// + /// Sets the high event and waits for the low event. + /// + public NtStatus SetHighWaitLow() + { + NtStatus status; + + if ((status = Win32.NtSetHighWaitLowEventPair(this)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return status; + } + + /// + /// Sets the low event. + /// + public void SetLow() + { + NtStatus status; + + if ((status = Win32.NtSetLowEventPair(this)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + /// + /// Sets the low event and waits for the high event. + /// + public NtStatus SetLowWaitHigh() + { + NtStatus status; + + if ((status = Win32.NtSetLowWaitHighEventPair(this)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return status; + } + + /// + /// Waits for the high event. + /// + public NtStatus WaitHigh() + { + NtStatus status; + + if ((status = Win32.NtWaitHighEventPair(this)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return status; + } + + /// + /// Waits for the low event. + /// + public NtStatus WaitLow() + { + NtStatus status; + + if ((status = Win32.NtWaitLowEventPair(this)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return status; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/FileHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/FileHandle.cs new file mode 100644 index 000000000..faa7becdf --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/FileHandle.cs @@ -0,0 +1,1813 @@ +/* + * Process Hacker - + * file handle + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using ProcessHacker.Common; +using ProcessHacker.Common.Objects; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + /// + /// Represents a handle to a file. + /// + public class FileHandle : NativeHandle + { + public delegate bool EnumFilesDelegate(FileEntry file); + public delegate bool EnumStreamsDelegate(FileStreamEntry stream); + + public static FileHandle FromFileStream(System.IO.FileStream fileStream) + { + return FromHandle(fileStream.SafeFileHandle.DangerousGetHandle()); + } + + public static FileHandle FromHandle(IntPtr handle) + { + return new FileHandle(handle, false); + } + + /// + /// Creates or opens a file. + /// + /// The desired access to the file. + /// + /// An object name identifying the file to open. To use a DOS format + /// file name, prepend "\??\" to the file name. + /// + /// Options to use when creating the file. + public static FileHandle Create(FileAccess access, string fileName, FileCreateOptions createOptions) + { + return Create(access, fileName, FileShareMode.Exclusive, FileCreationDisposition.OpenIf, createOptions); + } + + /// + /// Creates or opens a file. + /// + /// The desired access to the file. + /// + /// An object name identifying the file to open. To use a DOS format + /// file name, prepend "\??\" to the file name. + /// + /// The types of access to the file to grant to other threads. + /// Options to use when creating the file. + public static FileHandle Create(FileAccess access, string fileName, FileShareMode shareMode, FileCreateOptions createOptions) + { + return Create(access, fileName, shareMode, FileCreationDisposition.OpenIf, createOptions); + } + + public static FileHandle Create( + FileAccess access, + string fileName, + FileShareMode shareMode, + FileCreationDisposition creationDisposition, + FileCreateOptions createOptions + ) + { + return Create(access, fileName, null, shareMode, creationDisposition, createOptions); + } + + public static FileHandle Create( + FileAccess access, + string fileName, + FileHandle rootDirectory, + FileShareMode shareMode, + FileCreationDisposition creationDisposition, + FileCreateOptions createOptions + ) + { + FileIoStatus status; + + return Create( + access, + fileName, + ObjectFlags.CaseInsensitive, + rootDirectory, + shareMode, + creationDisposition, + 0, + FileAttributes.Normal, + createOptions, + out status + ); + } + + public static FileHandle Create( + FileAccess access, + string fileName, + ObjectFlags objectFlags, + FileHandle rootDirectory, + FileShareMode shareMode, + FileCreationDisposition creationDisposition, + long allocationSize, + FileAttributes attributes, + FileCreateOptions createOptions, + out FileIoStatus ioStatus + ) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(fileName, objectFlags, rootDirectory); + IoStatusBlock isb; + IntPtr handle; + + try + { + if ((status = Win32.NtCreateFile( + out handle, + access, + ref oa, + out isb, + ref allocationSize, + attributes, + shareMode, + creationDisposition, + createOptions, + IntPtr.Zero, + 0 + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + ioStatus = (FileIoStatus)isb.Information.ToInt32(); + } + finally + { + oa.Dispose(); + } + + return new FileHandle(handle, true); + } + + public static FileHandle CreateWin32(string fileName, FileAccess desiredAccess) + { + return CreateWin32(fileName, desiredAccess, FileShareMode.Exclusive); + } + + public static FileHandle CreateWin32(string fileName, FileAccess desiredAccess, FileShareMode shareMode) + { + return CreateWin32(fileName, desiredAccess, shareMode, FileCreationDispositionWin32.OpenAlways); + } + + public static FileHandle CreateWin32(string fileName, FileAccess desiredAccess, FileShareMode shareMode, + FileCreationDispositionWin32 creationDisposition) + { + IntPtr handle; + + handle = Win32.CreateFile(fileName, desiredAccess, shareMode, 0, creationDisposition, 0, IntPtr.Zero); + + if (handle == NativeHandle.MinusOne) + Win32.ThrowLastError(); + + return new FileHandle(handle, true); + } + + public static void Delete(string fileName, ObjectFlags objectFlags) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(fileName, objectFlags, null); + + try + { + if ((status = Win32.NtDeleteFile(ref oa)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + } + + protected FileHandle() + { } + + protected FileHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + /// + /// Opens an existing file for synchronous access. + /// + /// + /// An object name identifying the file to open. To use a DOS format + /// file name, prepend "\??\" to the file name. + /// + /// The desired access to the file. + public FileHandle(string fileName, FileAccess access) + : this(fileName, FileShareMode.Exclusive, access) + { } + + /// + /// Opens an existing file for synchronous access. + /// + /// + /// An object name identifying the file to open. To use a DOS format + /// file name, prepend "\??\" to the file name. + /// + /// The share mode to use. + /// The desired access to the file. + public FileHandle(string fileName, FileShareMode shareMode, FileAccess access) + : this(fileName, shareMode, FileCreateOptions.NonDirectoryFile | FileCreateOptions.SynchronousIoNonAlert, access | (FileAccess)StandardRights.Synchronize) + { } + + /// + /// Opens an existing file. + /// + /// + /// An object name identifying the file to open. To use a DOS format + /// file name, prepend "\??\" to the file name. + /// + /// The share mode to use. + /// Open options to use. + /// The desired access to the file. + public FileHandle(string fileName, FileShareMode shareMode, FileCreateOptions openOptions, FileAccess access) + : this(fileName, ObjectFlags.CaseInsensitive, null, shareMode, openOptions, access) + { } + + /// + /// Opens an existing file. + /// + /// + /// An object name identifying the file to open. To use a DOS format + /// file name, prepend "\??\" to the file name. + /// + /// Flags to use when opening the object. + /// The directory to open the file relative to. + /// The share mode to use. + /// Open options to use. + /// The desired access to the file. + public FileHandle( + string fileName, + ObjectFlags objectFlags, + FileHandle rootDirectory, + FileShareMode shareMode, + FileCreateOptions openOptions, + FileAccess access + ) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(fileName, objectFlags, rootDirectory); + IoStatusBlock isb; + IntPtr handle; + + try + { + if ((status = Win32.NtOpenFile( + out handle, + access, + ref oa, + out isb, + shareMode, + openOptions + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + this.Handle = handle; + } + + public AsyncIoContext BeginFsControl( + int controlCode, + byte[] inBuffer, + int inBufferOffset, + int inBufferLength, + byte[] outBuffer, + int outBufferOffset, + int outBufferLength + ) + { + AsyncIoContext asyncContext; + PinnedObject pinnedInBuffer = null; + PinnedObject pinnedOutBuffer = null; + + Utils.ValidateBuffer(inBuffer, inBufferOffset, inBufferLength, true); + Utils.ValidateBuffer(outBuffer, outBufferOffset, outBufferLength, true); + + asyncContext = new AsyncIoContext(this); + + if (inBuffer != null) + { + pinnedInBuffer = new PinnedObject(inBuffer); + asyncContext.KeepAlive(pinnedInBuffer); + } + + if (outBuffer != null) + { + pinnedOutBuffer = new PinnedObject(outBuffer); + asyncContext.KeepAlive(pinnedOutBuffer); + } + + this.BeginFsControl( + asyncContext, + controlCode, + pinnedInBuffer != null ? pinnedInBuffer.Address.Increment(inBufferOffset) : IntPtr.Zero, + inBufferLength, + pinnedOutBuffer != null ? pinnedOutBuffer.Address.Increment(outBufferOffset) : IntPtr.Zero, + outBufferLength + ); + + return asyncContext; + } + + public AsyncIoContext BeginFsControl(int controlCode, MemoryRegion inBuffer, MemoryRegion outBuffer) + { + AsyncIoContext asyncContext = new AsyncIoContext(this); + + asyncContext.KeepAlive(inBuffer); + asyncContext.KeepAlive(outBuffer); + this.BeginFsControl( + asyncContext, + controlCode, + inBuffer ?? IntPtr.Zero, + inBuffer != null ? inBuffer.Size : 0, + outBuffer ?? IntPtr.Zero, + outBuffer != null ? outBuffer.Size : 0 + ); + + return asyncContext; + } + + protected void BeginFsControl( + AsyncIoContext asyncContext, + int controlCode, + IntPtr inBuffer, + int inBufferLength, + IntPtr outBuffer, + int outBufferLength + ) + { + NtStatus status; + + status = Win32.NtFsControlFile( + this, + asyncContext.EventHandle, + null, + IntPtr.Zero, + asyncContext.StatusMemory, + controlCode, + inBuffer, + inBufferLength, + outBuffer, + outBufferLength + ); + + asyncContext.NotifyBegin(); + + if (status != NtStatus.Pending) + { + // The operation finished synchronously. + asyncContext.CompletedSynchronously = true; + asyncContext.Status = status; + } + } + + public AsyncIoContext BeginIoControl( + int controlCode, + byte[] inBuffer, + int inBufferOffset, + int inBufferLength, + byte[] outBuffer, + int outBufferOffset, + int outBufferLength + ) + { + AsyncIoContext asyncContext; + PinnedObject pinnedInBuffer = null; + PinnedObject pinnedOutBuffer = null; + + Utils.ValidateBuffer(inBuffer, inBufferOffset, inBufferLength, true); + Utils.ValidateBuffer(outBuffer, outBufferOffset, outBufferLength, true); + + asyncContext = new AsyncIoContext(this); + + if (inBuffer != null) + { + pinnedInBuffer = new PinnedObject(inBuffer); + asyncContext.KeepAlive(pinnedInBuffer); + } + + if (outBuffer != null) + { + pinnedOutBuffer = new PinnedObject(outBuffer); + asyncContext.KeepAlive(pinnedOutBuffer); + } + + this.BeginIoControl( + asyncContext, + controlCode, + pinnedInBuffer != null ? pinnedInBuffer.Address.Increment(inBufferOffset) : IntPtr.Zero, + inBufferLength, + pinnedOutBuffer != null ? pinnedOutBuffer.Address.Increment(outBufferOffset) : IntPtr.Zero, + outBufferLength + ); + + return asyncContext; + } + + public AsyncIoContext BeginIoControl(int controlCode, MemoryRegion inBuffer, MemoryRegion outBuffer) + { + AsyncIoContext asyncContext = new AsyncIoContext(this); + + asyncContext.KeepAlive(inBuffer); + asyncContext.KeepAlive(outBuffer); + this.BeginIoControl( + asyncContext, + controlCode, + inBuffer ?? IntPtr.Zero, + inBuffer != null ? inBuffer.Size : 0, + outBuffer ?? IntPtr.Zero, + outBuffer != null ? outBuffer.Size : 0 + ); + + return asyncContext; + } + + protected void BeginIoControl( + AsyncIoContext asyncContext, + int controlCode, + IntPtr inBuffer, + int inBufferLength, + IntPtr outBuffer, + int outBufferLength + ) + { + NtStatus status; + + status = Win32.NtDeviceIoControlFile( + this, + asyncContext.EventHandle, + null, + IntPtr.Zero, + asyncContext.StatusMemory, + controlCode, + inBuffer, + inBufferLength, + outBuffer, + outBufferLength + ); + + asyncContext.NotifyBegin(); + + if (status != NtStatus.Pending) + { + // The operation finished synchronously. + asyncContext.CompletedSynchronously = true; + asyncContext.Status = status; + } + } + + public AsyncIoContext BeginLock(long offset, long length) + { + return this.BeginLock(offset, length, false); + } + + public AsyncIoContext BeginLock(long offset, long length, bool wait) + { + return this.BeginLock(offset, length, wait, true); + } + + public AsyncIoContext BeginLock(long offset, long length, bool wait, bool exclusive) + { + NtStatus status; + AsyncIoContext asyncContext = new AsyncIoContext(this); + + status = Win32.NtLockFile( + this, + asyncContext.EventHandle, + null, + IntPtr.Zero, + asyncContext.StatusMemory, + ref offset, + ref length, + 0, + !wait, + exclusive + ); + + asyncContext.NotifyBegin(); + + if (status != NtStatus.Pending) + { + // The operation finished synchronously. + asyncContext.CompletedSynchronously = true; + asyncContext.Status = status; + } + + return asyncContext; + } + + public AsyncIoContext BeginRead(byte[] buffer) + { + return this.BeginRead(buffer, 0, buffer.Length); + } + + public AsyncIoContext BeginRead(byte[] buffer, int offset, int length) + { + AsyncIoContext asyncContext; + PinnedObject pinnedBuffer; + + Utils.ValidateBuffer(buffer, offset, length); + + // Pin the buffer because the I/O system may be writing to it after + // this call returns. + pinnedBuffer = new PinnedObject(buffer); + asyncContext = new AsyncIoContext(this); + asyncContext.KeepAlive(pinnedBuffer); + this.BeginRead(asyncContext, pinnedBuffer.Address.Increment(offset), length); + + return asyncContext; + } + + public AsyncIoContext BeginRead(MemoryRegion buffer) + { + AsyncIoContext asyncContext = new AsyncIoContext(this); + + asyncContext.KeepAlive(buffer); + this.BeginRead(asyncContext, buffer, buffer.Size); + + return asyncContext; + } + + protected void BeginRead(AsyncIoContext asyncContext, IntPtr buffer, int length) + { + NtStatus status; + + status = Win32.NtReadFile( + this, + asyncContext.EventHandle, + null, + IntPtr.Zero, + asyncContext.StatusMemory, + buffer, + length, + IntPtr.Zero, + IntPtr.Zero + ); + + asyncContext.NotifyBegin(); + + if (status != NtStatus.Pending) + { + // The operation finished synchronously. + asyncContext.CompletedSynchronously = true; + asyncContext.Status = status; + } + } + + public AsyncIoContext BeginWrite(byte[] buffer) + { + return this.BeginWrite(buffer, 0, buffer.Length); + } + + public AsyncIoContext BeginWrite(byte[] buffer, int offset, int length) + { + AsyncIoContext asyncContext; + PinnedObject pinnedBuffer; + + Utils.ValidateBuffer(buffer, offset, length); + + pinnedBuffer = new PinnedObject(buffer); + asyncContext = new AsyncIoContext(this); + asyncContext.KeepAlive(pinnedBuffer); + this.BeginWrite(asyncContext, pinnedBuffer.Address.Increment(offset), length); + + return asyncContext; + } + + public AsyncIoContext BeginWrite(MemoryRegion buffer) + { + AsyncIoContext asyncContext = new AsyncIoContext(this); + + asyncContext.KeepAlive(buffer); + this.BeginWrite(asyncContext, buffer, buffer.Size); + + return asyncContext; + } + + protected void BeginWrite(AsyncIoContext asyncContext, IntPtr buffer, int length) + { + NtStatus status; + + status = Win32.NtWriteFile( + this, + asyncContext.EventHandle, + null, + IntPtr.Zero, + asyncContext.StatusMemory, + buffer, + length, + IntPtr.Zero, + IntPtr.Zero + ); + + asyncContext.NotifyBegin(); + + if (status != NtStatus.Pending) + { + // The operation finished synchronously. + asyncContext.CompletedSynchronously = true; + asyncContext.Status = status; + } + } + + public IoStatusBlock CancelIo() + { + NtStatus status; + IoStatusBlock isb; + + if ((status = Win32.NtCancelIoFile(this, out isb)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return isb; + } + + internal void CancelIo(IntPtr isb) + { + NtStatus status; + + if ((status = Win32.NtCancelIoFile(this, isb)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + /// + /// Deletes the file when the handle is closed. + /// + public void Delete() + { + this.SetStruct( + FileInformationClass.FileDispositionInformation, + new FileDispositionInformation() { DeleteFile = true } + ); + } + + protected int EndCommonIo(AsyncIoContext asyncContext) + { + asyncContext.Wait(); + asyncContext.NotifyEnd(); + + if (asyncContext.Status >= NtStatus.Error) + Win32.ThrowLastError(asyncContext.Status); + + return asyncContext.StatusBlock.Information.ToInt32(); + } + + public int EndFsControl(AsyncIoContext asyncContext) + { + return this.EndCommonIo(asyncContext); + } + + public int EndIoControl(AsyncIoContext asyncContext) + { + return this.EndCommonIo(asyncContext); + } + + public bool EndLock(AsyncIoContext asyncContext) + { + asyncContext.Wait(); + asyncContext.NotifyEnd(); + + if (asyncContext.Status == NtStatus.LockNotGranted) + return false; + + if (asyncContext.Status >= NtStatus.Error) + Win32.ThrowLastError(asyncContext.Status); + + return true; + } + + public int EndRead(AsyncIoContext asyncContext) + { + return this.EndCommonIo(asyncContext); + } + + public int EndWrite(AsyncIoContext asyncContext) + { + return this.EndCommonIo(asyncContext); + } + + public void EnumFiles(EnumFilesDelegate callback) + { + NtStatus status; + IoStatusBlock isb; + bool firstTime = true; + + using (var data = new MemoryAlloc(0x400)) + { + while (true) + { + // Query the directory, doubling the buffer size each + // time NtQueryDirectoryFile fails. We will also handle + // any pending status. + + while (true) + { + status = Win32.NtQueryDirectoryFile( + this, + IntPtr.Zero, + null, + IntPtr.Zero, + out isb, + data, + data.Size, + FileInformationClass.FileDirectoryInformation, + false, + IntPtr.Zero, + firstTime + ); + + // Our ISB is on the stack, so we have to wait for the operation to complete + // before continuing. + if (status == NtStatus.Pending) + { + this.Wait(); + status = isb.Status; + } + + if (status == NtStatus.BufferOverflow || status == NtStatus.InfoLengthMismatch) + data.Resize(data.Size * 2); + else + break; + } + + // If we don't have any entries to read, exit. + if (status == NtStatus.NoMoreFiles) + break; + + // Handle any errors. + if (status >= NtStatus.Error) + Win32.ThrowLastError(status); + + // Read the list of files we got in this batch. + + int i = 0; + + while (true) + { + FileDirectoryInformation info = data.ReadStruct(i, 0); + string name = data.ReadUnicodeString( + i + FileDirectoryInformation.FileNameOffset, + info.FileNameLength / 2 + ); + + if (!callback(new FileEntry( + name, + info.FileIndex, + DateTime.FromFileTime(info.CreationTime), + DateTime.FromFileTime(info.LastAccessTime), + DateTime.FromFileTime(info.LastWriteTime), + DateTime.FromFileTime(info.ChangeTime), + info.EndOfFile, + info.AllocationSize, + info.FileAttributes + ))) + return; + + if (info.NextEntryOffset == 0) + break; + else + i += info.NextEntryOffset; + } + + firstTime = false; + + // Go back and get another batch of file entries. + } + } + } + + public void EnumStreams(EnumStreamsDelegate callback) + { + using (var data = this.QueryVariableSize(FileInformationClass.FileStreamInformation)) + { + int i = 0; + + while (true) + { + FileStreamInformation info = data.ReadStruct(i, 0); + string name = data.ReadUnicodeString( + i + FileStreamInformation.StreamNameOffset, + info.StreamNameLength / 2 + ); + + if (!callback(new FileStreamEntry(name, info.StreamSize, info.StreamAllocationSize))) + return; + + if (info.NextEntryOffset == 0) + break; + else + i += info.NextEntryOffset; + } + } + } + + public void Flush() + { + NtStatus status; + IoStatusBlock isb; + + status = Win32.NtFlushBuffersFile( + this, + out isb + ); + + if (status == NtStatus.Pending) + { + this.Wait(); + status = isb.Status; + } + + if (status >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + public int FsControl(int controlCode, byte[] inBuffer, byte[] outBuffer) + { + return this.FsControl( + controlCode, + inBuffer, + 0, + inBuffer != null ? inBuffer.Length : 0, + outBuffer, + 0, + outBuffer != null ? outBuffer.Length : 0 + ); + } + + public int FsControl( + int controlCode, + byte[] inBuffer, + int inBufferOffset, + int inBufferLength, + byte[] outBuffer, + int outBufferOffset, + int outBufferLength + ) + { + Utils.ValidateBuffer(inBuffer, inBufferOffset, inBufferLength, true); + Utils.ValidateBuffer(outBuffer, outBufferOffset, outBufferLength, true); + + unsafe + { + fixed (byte* inBufferPtr = inBuffer) + { + fixed (byte* outBufferPtr = outBuffer) + { + return this.FsControl( + controlCode, + &inBufferPtr[inBufferOffset], + inBuffer != null ? inBuffer.Length : 0, + &outBufferPtr[outBufferOffset], + outBuffer != null ? outBuffer.Length : 0 + ); + } + } + } + } + + public unsafe int FsControl( + int controlCode, + void* inBuffer, + int inBufferLength, + void* outBuffer, + int outBufferLength + ) + { + return this.FsControl(controlCode, new IntPtr(inBuffer), inBufferLength, new IntPtr(outBuffer), outBufferLength); + } + + public int FsControl( + int controlCode, + IntPtr inBuffer, + int inBufferLength, + IntPtr outBuffer, + int outBufferLength + ) + { + NtStatus status; + int returnLength; + + status = this.FsControl(controlCode, inBuffer, inBufferLength, outBuffer, outBufferLength, out returnLength); + + if (status >= NtStatus.Error) + Win32.ThrowLastError(status); + + return returnLength; + } + + public NtStatus FsControl( + int controlCode, + IntPtr inBuffer, + int inBufferLength, + IntPtr outBuffer, + int outBufferLength, + out int returnLength + ) + { + NtStatus status; + IoStatusBlock isb; + + status = Win32.NtFsControlFile( + this, + IntPtr.Zero, + null, + IntPtr.Zero, + out isb, + controlCode, + inBuffer, + inBufferLength, + outBuffer, + outBufferLength + ); + + if (status == NtStatus.Pending) + { + this.Wait(); + status = isb.Status; + } + + // Information contains the return length. + returnLength = isb.Information.ToInt32(); + + return status; + } + + public FileAttributes GetAttributes() + { + return this.GetBasicInformation().FileAttributes; + } + + public FileBasicInformation GetBasicInformation() + { + return this.QueryStruct(FileInformationClass.FileBasicInformation); + } + + public string GetFileName() + { + using (var data = this.QueryVariableSize(FileInformationClass.FileNameInformation)) + { + FileNameInformation info = data.ReadStruct(); + + return data.ReadUnicodeString( + FileNameInformation.FileNameOffset, + info.FileNameLength / 2 + ); + } + } + + public FileEntry[] GetFiles() + { + List files = new List(); + + this.EnumFiles((file) => + { + files.Add(file); + return true; + }); + + return files.ToArray(); + } + + public long GetPosition() + { + return this.QueryStruct(FileInformationClass.FilePositionInformation).CurrentByteOffset; + } + + public FileStreamEntry[] GetStreams() + { + List streams = new List(); + + this.EnumStreams((file) => + { + streams.Add(file); + return true; + }); + + return streams.ToArray(); + } + + public long GetSize() + { + return this.GetStandardInformation().EndOfFile; + } + + public FileStandardInformation GetStandardInformation() + { + return this.QueryStruct(FileInformationClass.FileStandardInformation); + } + + public string GetVolumeFsName() + { + NtStatus status; + IoStatusBlock isb; + + using (var data = new MemoryAlloc(0x200)) + { + if ((status = Win32.NtQueryVolumeInformationFile( + this, + out isb, + data, + data.Size, + FsInformationClass.FileFsAttributeInformation + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + FileFsAttributeInformation info = data.ReadStruct(); + + return Marshal.PtrToStringUni( + data.Memory.Increment(Marshal.OffsetOf(typeof(FileFsAttributeInformation), "FileSystemName")), + info.FileSystemNameLength / 2 + ); + } + } + + public string GetVolumeLabel() + { + NtStatus status; + IoStatusBlock isb; + + using (var data = new MemoryAlloc(0x200)) + { + if ((status = Win32.NtQueryVolumeInformationFile( + this, + out isb, + data, + data.Size, + FsInformationClass.FileFsVolumeInformation + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + FileFsVolumeInformation info = data.ReadStruct(); + + return Marshal.PtrToStringUni( + data.Memory.Increment(Marshal.OffsetOf(typeof(FileFsVolumeInformation), "VolumeLabel")), + info.VolumeLabelLength / 2 + ); + } + } + + /// + /// Sends an I/O control message to the device's associated driver. + /// + /// The device-specific control code. + /// The input. + /// The output buffer. + /// The bytes returned in the output buffer. + public int IoControl(int controlCode, byte[] inBuffer, byte[] outBuffer) + { + return this.IoControl( + controlCode, + inBuffer, + 0, + inBuffer != null ? inBuffer.Length : 0, + outBuffer, + 0, + outBuffer != null ? outBuffer.Length : 0 + ); + } + + public int IoControl( + int controlCode, + byte[] inBuffer, + int inBufferOffset, + int inBufferLength, + byte[] outBuffer, + int outBufferOffset, + int outBufferLength + ) + { + Utils.ValidateBuffer(inBuffer, inBufferOffset, inBufferLength, true); + Utils.ValidateBuffer(outBuffer, outBufferOffset, outBufferLength, true); + + unsafe + { + fixed (byte* inBufferPtr = inBuffer) + { + fixed (byte* outBufferPtr = outBuffer) + { + return this.IoControl( + controlCode, + &inBufferPtr[inBufferOffset], + inBuffer != null ? inBuffer.Length : 0, + &outBufferPtr[outBufferOffset], + outBuffer != null ? outBuffer.Length : 0 + ); + } + } + } + } + + public unsafe int IoControl( + int controlCode, + byte* inBuffer, + int inBufferLength, + byte[] outBuffer + ) + { + fixed (byte* outBufferPtr = outBuffer) + { + return this.IoControl( + controlCode, + inBuffer, + inBufferLength, + outBufferPtr, + outBuffer != null ? outBuffer.Length : 0 + ); + } + } + + public unsafe int IoControl( + int controlCode, + void* inBuffer, + int inBufferLength, + void* outBuffer, + int outBufferLength + ) + { + return this.IoControl(controlCode, new IntPtr(inBuffer), inBufferLength, new IntPtr(outBuffer), outBufferLength); + } + + public int IoControl( + int controlCode, + IntPtr inBuffer, + int inBufferLength, + IntPtr outBuffer, + int outBufferLength + ) + { + NtStatus status; + int returnLength; + + status = this.IoControl(controlCode, inBuffer, inBufferLength, outBuffer, outBufferLength, out returnLength); + + if (status >= NtStatus.Error) + Win32.ThrowLastError(status); + + return returnLength; + } + + public NtStatus IoControl( + int controlCode, + IntPtr inBuffer, + int inBufferLength, + IntPtr outBuffer, + int outBufferLength, + out int returnLength + ) + { + NtStatus status; + IoStatusBlock isb; + + status = Win32.NtDeviceIoControlFile( + this, + IntPtr.Zero, + null, + IntPtr.Zero, + out isb, + controlCode, + inBuffer, + inBufferLength, + outBuffer, + outBufferLength + ); + + if (status == NtStatus.Pending) + { + this.Wait(); + status = isb.Status; + } + + // Information contains the return length. + returnLength = isb.Information.ToInt32(); + + return status; + } + + public bool Lock(long offset, long length) + { + return this.Lock(offset, length, false); + } + + public bool Lock(long offset, long length, bool wait) + { + return this.Lock(offset, length, wait, true); + } + + public bool Lock(long offset, long length, bool wait, bool exclusive) + { + NtStatus status; + IoStatusBlock isb; + + status = Win32.NtLockFile( + this, + IntPtr.Zero, + null, + IntPtr.Zero, + out isb, + ref offset, + ref length, + 0, + !wait, + exclusive + ); + + if (status == NtStatus.Pending) + { + this.Wait(); + status = isb.Status; + } + + if (status == NtStatus.LockNotGranted) + return false; + + if (status >= NtStatus.Error) + Win32.ThrowLastError(status); + + return true; + } + + protected T QueryStruct(FileInformationClass infoClass) + where T : struct + { + NtStatus status; + IoStatusBlock isb; + + using (var data = new MemoryAlloc(Marshal.SizeOf(typeof(T)))) + { + if ((status = Win32.NtQueryInformationFile( + this, + out isb, + data, + data.Size, + infoClass + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return data.ReadStruct(); + } + } + + protected MemoryAlloc QueryVariableSize(FileInformationClass infoClass) + { + NtStatus status; + IoStatusBlock isb; + var data = new MemoryAlloc(0x200); + + while (true) + { + status = Win32.NtQueryInformationFile( + this, + out isb, + data, + data.Size, + infoClass + ); + + if ( + status == NtStatus.BufferOverflow || + status == NtStatus.BufferTooSmall || + status == NtStatus.InfoLengthMismatch + ) + data.Resize(data.Size * 2); + else + break; + } + + if (status >= NtStatus.Error) + { + data.Dispose(); + Win32.ThrowLastError(status); + } + + return data; + } + + /// + /// Reads data from the file. + /// + /// The length to read. + /// The read data. + public byte[] Read(int length) + { + byte[] buffer = new byte[length]; + + this.Read(buffer); + + return buffer; + } + + /// + /// Reads data from the file. + /// + /// The buffer to store the data in. + /// The number of bytes read from the file. + public int Read(byte[] buffer) + { + return this.Read(buffer, 0, buffer.Length); + } + + public int Read(byte[] buffer, int offset, int length) + { + Utils.ValidateBuffer(buffer, offset, length); + + unsafe + { + fixed (byte* bufferPtr = buffer) + { + return this.Read(&bufferPtr[offset], length); + } + } + } + + public unsafe int Read(void* buffer, int length) + { + return this.Read(new IntPtr(buffer), length); + } + + public int Read(IntPtr buffer, int length) + { + NtStatus status; + IoStatusBlock isb; + + status = Win32.NtReadFile( + this, + IntPtr.Zero, + null, + IntPtr.Zero, + out isb, + buffer, + length, + IntPtr.Zero, + IntPtr.Zero + ); + + if (status == NtStatus.Pending) + { + this.Wait(); + status = isb.Status; + } + + if (status >= NtStatus.Error) + Win32.ThrowLastError(status); + + return isb.Information.ToInt32(); + } + + public void SetEnd(long offset) + { + this.SetStruct( + FileInformationClass.FileEndOfFileInformation, + new FileEndOfFileInformation() { EndOfFile = offset } + ); + } + + public void SetIoCompletion(IoCompletionHandle ioCompletionHandle, IntPtr keyContext) + { + FileCompletionInformation info = new FileCompletionInformation(); + + info.Port = ioCompletionHandle; + info.Key = keyContext; + this.SetStruct(FileInformationClass.FileCompletionInformation, info); + } + + public void SetPosition(long offset) + { + this.SetStruct( + FileInformationClass.FilePositionInformation, + new FilePositionInformation() { CurrentByteOffset = offset } + ); + } + + public long SetPosition(long offset, PositionOrigin origin) + { + long currentPosition; + + currentPosition = this.GetPosition(); + + switch (origin) + { + case PositionOrigin.Current: + currentPosition += offset; + break; + case PositionOrigin.Start: + currentPosition = offset; + break; + case PositionOrigin.End: + currentPosition = this.GetSize() + offset; + break; + } + + this.SetPosition(currentPosition); + + return currentPosition; + } + + protected void SetStruct(FileInformationClass infoClass, T info) + where T : struct + { + NtStatus status; + IoStatusBlock isb; + + using (var data = new MemoryAlloc(Marshal.SizeOf(typeof(T)))) + { + data.WriteStruct(info); + + if ((status = Win32.NtSetInformationFile( + this, + out isb, + data, + data.Size, + infoClass + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + } + + public void Unlock(long offset, long length) + { + NtStatus status; + IoStatusBlock isb; + + status = Win32.NtUnlockFile( + this, + out isb, + ref offset, + ref length, + 0 + ); + + if (status >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + /// + /// Writes data to the file. + /// + /// The data. + /// The number of bytes written to the file. + public int Write(byte[] buffer) + { + return this.Write(buffer, 0, buffer.Length); + } + + public int Write(byte[] buffer, int offset, int length) + { + Utils.ValidateBuffer(buffer, offset, length); + + unsafe + { + fixed (byte* bufferPtr = buffer) + { + return this.Write(&bufferPtr[offset], length); + } + } + } + + public unsafe int Write(void* buffer, int length) + { + return this.Write(new IntPtr(buffer), length); + } + + /// + /// Writes data to the file. + /// + /// The data. + /// The number of bytes to write. + /// The number of bytes written to the file. + public int Write(IntPtr buffer, int length) + { + NtStatus status; + IoStatusBlock isb; + + status = Win32.NtWriteFile( + this, + IntPtr.Zero, + null, + IntPtr.Zero, + out isb, + buffer, + length, + IntPtr.Zero, + IntPtr.Zero + ); + + if (status == NtStatus.Pending) + { + this.Wait(); + status = isb.Status; + } + + if (status >= NtStatus.Error) + Win32.ThrowLastError(status); + + return isb.Information.ToInt32(); + } + } + + public enum PositionOrigin + { + Start, + Current, + End + } + + public sealed class AsyncIoContext : BaseObject, ISynchronizable + { + private unsafe sealed class UnmanagedIsb : BaseObject + { + private static readonly int _isbSize = Marshal.SizeOf(typeof(IoStatusBlock)); + + public static implicit operator IntPtr(UnmanagedIsb isb) + { + return isb.Memory; + } + + private IoStatusBlock* _ioStatusBlock; + + public UnmanagedIsb() + { + _ioStatusBlock = (IoStatusBlock*)MemoryAlloc.PrivateHeap.Allocate(0, _isbSize); + } + + protected override void DisposeObject(bool disposing) + { + if (_ioStatusBlock != null) + MemoryAlloc.PrivateHeap.Free(0, new IntPtr(_ioStatusBlock)); + } + + public IntPtr Information + { + get { return _ioStatusBlock->Information; } + set { _ioStatusBlock->Information = value; } + } + + public IntPtr Memory + { + get { return new IntPtr(_ioStatusBlock); } + } + + public IntPtr Pointer + { + get { return _ioStatusBlock->Pointer; } + set { _ioStatusBlock->Pointer = value; } + } + + public NtStatus Status + { + get { return _ioStatusBlock->Status; } + set { _ioStatusBlock->Status = value; } + } + + public IoStatusBlock Struct + { + get { return *_ioStatusBlock; } + set { *_ioStatusBlock = value; } + } + } + + private EventHandle _eventHandle; + private FileHandle _fileHandle; + private UnmanagedIsb _isb; + private bool _completedSynchronously = false; + private bool _started = false; + + private List _keepAliveList = new List(); + private object _tag; + + public AsyncIoContext(FileHandle fileHandle) + { + _eventHandle = EventHandle.Create(EventAccess.All, EventType.NotificationEvent, false); + _fileHandle = fileHandle; + _isb = new UnmanagedIsb(); + _isb.Status = NtStatus.Pending; + + _fileHandle.Reference(); + } + + protected override void DisposeObject(bool disposing) + { + if (_started && !this.Completed) + { + throw new InvalidOperationException( + "An attempt was made to dispose an asynchronous I/O context object " + + "before the I/O operation has finished." + ); + } + + this.ClearKeepAlive(); + + if (_eventHandle != null) + _eventHandle.Dispose(); + if (_fileHandle != null) + _fileHandle.Dereference(); + if (_isb != null) + _isb.Dispose(); + } + + public bool Cancelled + { + get { return this.Status == NtStatus.Cancelled; } + } + + public bool Completed + { + get + { + return _isb.Status != NtStatus.Pending; + } + } + + public bool CompletedSynchronously + { + get { return _completedSynchronously; } + internal set + { + _completedSynchronously = value; + _eventHandle.Set(); + } + } + + internal EventHandle EventHandle + { + get { return _eventHandle; } + } + + public FileHandle FileHandle + { + get { return _fileHandle; } + } + + public int Information + { + get { return _isb.Information.ToInt32(); } + } + + public bool Started + { + get { return _started; } + } + + public NtStatus Status + { + get { return _isb.Status; } + internal set { _isb.Status = value; } + } + + public IoStatusBlock StatusBlock + { + get + { + return _isb.Struct; + } + internal set + { + _isb.Struct = value; + } + } + + internal IntPtr StatusMemory + { + get { return _isb; } + } + + public object Tag + { + get { return _tag; } + set { _tag = value; } + } + + public void Cancel() + { + if (!_started) + return; + + _fileHandle.CancelIo(); + this.Wait(); + this.NotifyEnd(); + } + + private void ClearKeepAlive() + { + foreach (var obj in _keepAliveList) + obj.Dereference(); + + _keepAliveList.Clear(); + } + + internal void KeepAlive(BaseObject obj) + { + _keepAliveList.Add(obj); + obj.Reference(); + } + + internal void NotifyBegin() + { + _started = true; + } + + internal void NotifyEnd() + { + this.ClearKeepAlive(); + } + + #region ISynchronizable Members + + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + public IntPtr Handle + { + get { return _eventHandle.Handle; } + } + + public NtStatus Wait() + { + return _eventHandle.Wait(); + } + + public NtStatus Wait(bool alertable) + { + return _eventHandle.Wait(alertable); + } + + public NtStatus Wait(bool alertable, long timeout) + { + return _eventHandle.Wait(alertable, timeout); + } + + #endregion + } + + public class FileEntry + { + public FileEntry( + string name, + int index, + DateTime creationTime, + DateTime lastAccessTime, + DateTime lastWriteTime, + DateTime changeTime, + long size, + long allocationSize, + FileAttributes attributes + ) + { + this.Name = name; + this.Index = index; + this.CreationTime = creationTime; + this.LastAccessTime = lastAccessTime; + this.LastWriteTime = lastWriteTime; + this.ChangeTime = changeTime; + this.Size = size; + this.AllocationSize = allocationSize; + this.Attributes = attributes; + } + + public string Name { get; private set; } + public int Index { get; private set; } + + public DateTime CreationTime { get; private set; } + public DateTime LastAccessTime { get; private set; } + public DateTime LastWriteTime { get; private set; } + public DateTime ChangeTime { get; private set; } + + public long Size { get; private set; } + public long AllocationSize { get; private set; } + + public FileAttributes Attributes { get; private set; } + } + + public class FileStreamEntry + { + public FileStreamEntry(string name, long size, long allocationSize) + { + this.Name = name; + this.Size = size; + this.AllocationSize = allocationSize; + } + + public string Name { get; private set; } + public long Size { get; private set; } + public long AllocationSize { get; private set; } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/ISynchronizable.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/ISynchronizable.cs new file mode 100644 index 000000000..0b45e0698 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/ISynchronizable.cs @@ -0,0 +1,42 @@ +/* + * Process Hacker - + * object with synchronize functions + * + * Copyright (C) 2009 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 . + */ + +using System; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native.Objects +{ + /// + /// Represents a Windows object that can be synchronized with. + /// + public interface ISynchronizable + { + IntPtr Handle { get; } + + //NtStatus SignalAndWait(ISynchronizable waitObject); + //NtStatus SignalAndWait(ISynchronizable waitObject, bool alertable); + //NtStatus SignalAndWait(ISynchronizable waitObject, bool alertable, long timeout); + NtStatus Wait(); + NtStatus Wait(bool alertable); + NtStatus Wait(bool alertable, long timeout); + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/IWithToken.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/IWithToken.cs new file mode 100644 index 000000000..bdf209b6b --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/IWithToken.cs @@ -0,0 +1,49 @@ +/* + * Process Hacker - + * object with token + * + * Copyright (C) 2008 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 . + */ + +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + /// + /// Represents a Windows object that contains a token. + /// + /// + /// This interface is useful because both processes and threads have + /// tokens, but the method used to open their tokens are different. + /// + public interface IWithToken + { + /// + /// Opens and returns the object's token. + /// + /// A handle to the token. + TokenHandle GetToken(); + + /// + /// Opens and returns the object's token. + /// + /// Specifies the desired access to the token. + /// A handle to the token. + TokenHandle GetToken(TokenAccess access); + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/IoCompletionHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/IoCompletionHandle.cs new file mode 100644 index 000000000..a0e905c32 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/IoCompletionHandle.cs @@ -0,0 +1,122 @@ +/* + * Process Hacker - + * I/O completion handle + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + public sealed class IoCompletionHandle : NativeHandle + { + public static IoCompletionHandle Create(IoCompletionAccess access) + { + return Create(access, 0); + } + + public static IoCompletionHandle Create(IoCompletionAccess access, int count) + { + return Create(access, null, count); + } + + public static IoCompletionHandle Create(IoCompletionAccess access, string name, int count) + { + return Create(access, name, 0, null, count); + } + + public static IoCompletionHandle Create(IoCompletionAccess access, string name, ObjectFlags objectFlags, DirectoryHandle rootDirectory, int count) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtCreateIoCompletion(out handle, access, ref oa, count)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + return new IoCompletionHandle(handle, true); + } + + private IoCompletionHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + public IoCompletionHandle(string name, ObjectFlags objectFlags, DirectoryHandle rootDirectory, IoCompletionAccess access) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtOpenIoCompletion(out handle, access, ref oa)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + this.Handle = handle; + } + + public IoCompletionHandle(string name, IoCompletionAccess access) + : this(name, 0, null, access) + { } + + public IoStatusBlock Remove(out IntPtr keyContext, out IntPtr apcContext, long timeout) + { + return this.Remove(out keyContext, out apcContext, timeout, true); + } + + public IoStatusBlock Remove(out IntPtr keyContext, out IntPtr apcContext, long timeout, bool relative) + { + NtStatus status; + IoStatusBlock ioStatus; + long realTimeout = relative ? -timeout : timeout; + + if ((status = Win32.NtRemoveIoCompletion( + this, out keyContext, out apcContext, out ioStatus, ref realTimeout)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return ioStatus; + } + + public void Set(IntPtr keyContext, IntPtr apcContext, NtStatus ioStatus, IntPtr ioInformation) + { + NtStatus status; + + if ((status = Win32.NtSetIoCompletion( + this, keyContext, apcContext, ioStatus, ioInformation)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/JobObjectHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/JobObjectHandle.cs new file mode 100644 index 000000000..74d30e61f --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/JobObjectHandle.cs @@ -0,0 +1,226 @@ +/* + * Process Hacker - + * job handle + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + /// + /// Represents a handle to a Windows job object. + /// + public sealed class JobObjectHandle : NativeHandle + { + public static JobObjectHandle Create(JobObjectAccess access) + { + return Create(access, null); + } + + public static JobObjectHandle Create(JobObjectAccess access, string name) + { + return Create(access, name, 0, null); + } + + public static JobObjectHandle Create(JobObjectAccess access, string name, ObjectFlags objectFlags, DirectoryHandle rootDirectory) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtCreateJobObject( + out handle, + access, + ref oa + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + return new JobObjectHandle(handle, true); + } + + /// + /// Creates a service handle using an existing handle. + /// The handle will not be closed automatically. + /// + /// The handle value. + /// The job handle. + public static JobObjectHandle FromHandle(IntPtr handle) + { + return new JobObjectHandle(handle, false); + } + + private JobObjectHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + public JobObjectHandle(string name, ObjectFlags objectFlags, DirectoryHandle rootDirectory, JobObjectAccess access) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtOpenJobObject( + out handle, + access, + ref oa + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + this.Handle = handle; + } + + public JobObjectHandle(string name, JobObjectAccess access) + : this(name, 0, null, access) + { } + + /// + /// Opens the job object associated with the specified process. + /// + /// The process. + /// The desired access to the job object. + public JobObjectHandle(ProcessHandle processHandle, JobObjectAccess access) + { + try + { + this.Handle = new IntPtr(KProcessHacker.Instance.KphOpenProcessJob(processHandle, access)); + } + catch (WindowsException) + { + // Use KPH to set the handle's granted access. + this.Handle = new IntPtr(KProcessHacker.Instance.KphOpenProcessJob(processHandle, + (JobObjectAccess)StandardRights.Synchronize)); + if (this.Handle != IntPtr.Zero) + KProcessHacker.Instance.KphSetHandleGrantedAccess(this.Handle, (int)access); + } + + // If we don't have a handle assume the process isn't in a job. + if (this.Handle == IntPtr.Zero) + { + this.MarkAsInvalid(); + Win32.ThrowLastError(NtStatus.ProcessNotInJob); + } + } + + private T QueryStruct(JobObjectInformationClass informationClass) + where T : struct + { + int retLength; + + using (MemoryAlloc data = new MemoryAlloc(Marshal.SizeOf(typeof(T)))) + { + if (!Win32.QueryInformationJobObject(this, informationClass, data, data.Size, out retLength)) + { + data.Resize(retLength); + + if (!Win32.QueryInformationJobObject(this, informationClass, data, data.Size, out retLength)) + Win32.ThrowLastError(); + } + + return data.ReadStruct(); + } + } + + public JobObjectBasicAccountingInformation GetBasicAccountingInformation() + { + return this.QueryStruct( + JobObjectInformationClass.JobObjectBasicAccountingInformation); + } + + public JobObjectBasicAndIoAccountingInformation GetBasicAndIoAccountingInformation() + { + return this.QueryStruct( + JobObjectInformationClass.JobObjectBasicAndIoAccountingInformation); + } + + public JobObjectBasicLimitInformation GetBasicLimitInformation() + { + return this.QueryStruct(JobObjectInformationClass.JobObjectBasicLimitInformation); + } + + public int[] GetProcessIdList() + { + List processIds = new List(); + int retLength; + + // FIXME: Fixed buffer + using (MemoryAlloc data = new MemoryAlloc(0x1000)) + { + if (!Win32.QueryInformationJobObject(this, JobObjectInformationClass.JobObjectBasicProcessIdList, + data, data.Size, out retLength)) + Win32.ThrowLastError(); + + JobObjectBasicProcessIdList listInfo = data.ReadStruct(); + + for (int i = 0; i < listInfo.NumberOfProcessIdsInList; i++) + { + processIds.Add(data.ReadInt32(8, i)); + } + } + + return processIds.ToArray(); + } + + public JobObjectBasicUiRestrictions GetBasicUiRestrictions() + { + JobObjectBasicUiRestrictions uiRestrictions; + int retLength; + + if (!Win32.QueryInformationJobObject(this, JobObjectInformationClass.JobObjectBasicUIRestrictions, + out uiRestrictions, 4, out retLength)) + Win32.ThrowLastError(); + + return uiRestrictions; + } + + public JobObjectExtendedLimitInformation GetExtendedLimitInformation() + { + return this.QueryStruct(JobObjectInformationClass.JobObjectExtendedLimitInformation); + } + + public void Terminate() + { + this.Terminate(0); + } + + public void Terminate(int exitCode) + { + if (!Win32.TerminateJobObject(this, exitCode)) + Win32.ThrowLastError(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/KeyHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/KeyHandle.cs new file mode 100644 index 000000000..c926cc617 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/KeyHandle.cs @@ -0,0 +1,145 @@ +/* + * Process Hacker - + * key handle + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + public class KeyHandle : NativeHandle + { + public static KeyHandle Create( + KeyAccess access, + string name, + RegOptions createOptions + ) + { + return Create(access, name, 0, null, createOptions); + } + + public static KeyHandle Create( + KeyAccess access, + string name, + ObjectFlags objectFlags, + KeyHandle rootDirectory, + RegOptions createOptions + ) + { + KeyCreationDisposition creationDisposition; + + return Create(access, name, objectFlags, rootDirectory, createOptions, out creationDisposition); + } + + public static KeyHandle Create( + KeyAccess access, + string name, + ObjectFlags objectFlags, + KeyHandle rootDirectory, + RegOptions createOptions, + out KeyCreationDisposition creationDisposition + ) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtCreateKey( + out handle, + access, + ref oa, + 0, + IntPtr.Zero, + createOptions, + out creationDisposition + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + return new KeyHandle(handle, true); + } + + private KeyHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + public KeyHandle(string name, KeyAccess access) + : this(name, 0, null, access) + { } + + public KeyHandle(string name, ObjectFlags objectFlags, KeyHandle rootDirectory, KeyAccess access) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtOpenKey( + out handle, + access, + ref oa + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + this.Handle = handle; + } + + public void Delete() + { + NtStatus status; + + if ((status = Win32.NtDeleteKey(this)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + public void DeleteValue(string name) + { + NtStatus status; + UnicodeString nameStr = new UnicodeString(name); + + try + { + if ((status = Win32.NtDeleteValueKey(this, ref nameStr)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + nameStr.Dispose(); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/KeyedEventHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/KeyedEventHandle.cs new file mode 100644 index 000000000..5daea1837 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/KeyedEventHandle.cs @@ -0,0 +1,167 @@ +/* + * Process Hacker - + * keyed event handle + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + public sealed class KeyedEventHandle : NativeHandle + { + public static KeyedEventHandle Create(KeyedEventAccess access) + { + return Create(access, null); + } + + public static KeyedEventHandle Create(KeyedEventAccess access, string name) + { + return Create(access, name, 0, null); + } + + public static KeyedEventHandle Create(KeyedEventAccess access, string name, ObjectFlags objectFlags, DirectoryHandle rootDirectory) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtCreateKeyedEvent(out handle, access, ref oa, 0)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + return new KeyedEventHandle(handle, true); + } + + private KeyedEventHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + public KeyedEventHandle(string name, KeyedEventAccess access) + : this(name, null, 0, access) + { } + + public KeyedEventHandle(string name, DirectoryHandle rootDirectory, ObjectFlags objectFlags, KeyedEventAccess access) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtOpenKeyedEvent(out handle, access, ref oa)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + this.Handle = handle; + } + + public NtStatus ReleaseKey(int key) + { + return this.ReleaseKey(key, false); + } + + public NtStatus ReleaseKey(int key, long timeout) + { + return this.ReleaseKey(key, false, timeout); + } + + public NtStatus ReleaseKey(int key, bool alertable) + { + return this.ReleaseKey(new IntPtr(key), alertable, long.MinValue, false); + } + + public NtStatus ReleaseKey(int key, bool alertable, long timeout) + { + return this.ReleaseKey(new IntPtr(key), alertable, timeout, true); + } + + public NtStatus ReleaseKey(IntPtr key, bool alertable, long timeout, bool relative) + { + NtStatus status; + long realTimeout = relative ? -timeout : timeout; + + if (key.ToInt64() % 2 != 0) + throw new ArgumentException("Key must be divisible by 2."); + + if ((status = Win32.NtReleaseKeyedEvent( + this, + key, + alertable, + ref realTimeout + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return status; + } + + public NtStatus WaitKey(int key) + { + return this.WaitKey(key, false); + } + + public NtStatus WaitKey(int key, long timeout) + { + return this.WaitKey(key, false, timeout); + } + + public NtStatus WaitKey(int key, bool alertable) + { + return this.WaitKey(new IntPtr(key), alertable, long.MinValue, false); + } + + public NtStatus WaitKey(int key, bool alertable, long timeout) + { + return this.WaitKey(new IntPtr(key), alertable, timeout, true); + } + + public NtStatus WaitKey(IntPtr key, bool alertable, long timeout, bool relative) + { + NtStatus status; + long realTimeout = relative ? -timeout : timeout; + + if (key.ToInt64() % 2 != 0) + throw new ArgumentException("Key must be divisible by 2."); + + if ((status = Win32.NtWaitForKeyedEvent( + this, + key, + alertable, + ref realTimeout + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return status; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/LsaAccountHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/LsaAccountHandle.cs new file mode 100644 index 000000000..62215bed7 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/LsaAccountHandle.cs @@ -0,0 +1,185 @@ +/* + * Process Hacker - + * LSA account handle + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + /// + /// Represents a handle to a LSA account. + /// + public sealed class LsaAccountHandle : LsaHandle + { + public static LsaAccountHandle Create(LsaAccountAccess access, LsaPolicyHandle policyHandle, Sid sid) + { + NtStatus status; + IntPtr handle; + + if ((status = Win32.LsaCreateAccount( + policyHandle, + sid, + access, + out handle + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return new LsaAccountHandle(handle, true); + } + + private LsaAccountHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + /// + /// Opens a LSA account. + /// + /// A handle to a LSA policy. + /// The SID of the account to open. + /// The desired access to the account. + public LsaAccountHandle(LsaPolicyHandle policyHandle, Sid sid, LsaAccountAccess access) + { + NtStatus status; + IntPtr handle; + + if ((status = Win32.LsaOpenAccount( + policyHandle, + sid, + access, + out handle + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + this.Handle = handle; + } + + public void AddPrivileges(PrivilegeSet privileges) + { + NtStatus status; + + using (var privilegeSetMemory = privileges.ToMemory()) + { + if ((status = Win32.LsaAddPrivilegesToAccount( + this, + privilegeSetMemory + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + } + + public PrivilegeSet GetPrivileges() + { + NtStatus status; + IntPtr privileges; + + if ((status = Win32.LsaEnumeratePrivilegesOfAccount( + this, + out privileges + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + using (var privilegesAlloc = new LsaMemoryAlloc(privileges)) + { + return new PrivilegeSet(privilegesAlloc); + } + } + + public QuotaLimits GetQuotas() + { + NtStatus status; + QuotaLimits quotas; + + if ((status = Win32.LsaGetQuotasForAccount( + this, + out quotas + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return quotas; + } + + public SecuritySystemAccess GetSystemAccess() + { + NtStatus status; + SecuritySystemAccess access; + + if ((status = Win32.LsaGetSystemAccessAccount( + this, + out access + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return access; + } + + public void RemovePrivileges() + { + NtStatus status; + + if ((status = Win32.LsaRemovePrivilegesFromAccount( + this, + true, + IntPtr.Zero + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + private void RemovePrivileges(PrivilegeSet privileges) + { + NtStatus status; + + using (var privilegeSetMemory = privileges.ToMemory()) + { + if ((status = Win32.LsaRemovePrivilegesFromAccount( + this, + false, + privilegeSetMemory + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + } + + public void SetQuotas(QuotaLimits quotas) + { + NtStatus status; + + if ((status = Win32.LsaSetQuotasForAccount( + this, + ref quotas + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + public void SetSystemAccess(SecuritySystemAccess access) + { + NtStatus status; + + if ((status = Win32.LsaSetSystemAccessAccount( + this, + access + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/LsaHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/LsaHandle.cs new file mode 100644 index 000000000..47c2644bd --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/LsaHandle.cs @@ -0,0 +1,82 @@ +/* + * Process Hacker - + * local security authority handle + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security.AccessControl; + +namespace ProcessHacker.Native.Objects +{ + /// + /// Represents a handle managed by the Local Security Authority. + /// + public class LsaHandle : NativeHandle + where TAccess : struct + { + protected LsaHandle() + { } + + protected LsaHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + protected override void Close() + { + Win32.LsaClose(this); + } + + public void Delete() + { + NtStatus status; + + if ((status = Win32.LsaDelete(this)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + public override SecurityDescriptor GetSecurity(SecurityInformation securityInformation) + { + NtStatus status; + IntPtr securityDescriptor; + + if ((status = Win32.LsaQuerySecurityObject( + this, + securityInformation, + out securityDescriptor + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return new SecurityDescriptor(new LsaMemoryAlloc(securityDescriptor)); + } + + public override void SetSecurity(SecurityInformation securityInformation, SecurityDescriptor securityDescriptor) + { + NtStatus status; + + if ((status = Win32.LsaSetSecurityObject( + this, + securityInformation, + securityDescriptor + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/LsaPolicyHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/LsaPolicyHandle.cs new file mode 100644 index 000000000..3450c0c52 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/LsaPolicyHandle.cs @@ -0,0 +1,504 @@ +/* + * Process Hacker - + * LSA policy handle + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using ProcessHacker.Common; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + /// + /// Represents a handle to a LSA policy. + /// + public sealed class LsaPolicyHandle : LsaHandle + { + private static WeakReference _lookupPolicyHandle; + private static int _lookupPolicyHandleMisses = 0; + + public static LsaPolicyHandle LookupPolicyHandle + { + get + { + WeakReference weakRef = _lookupPolicyHandle; + LsaPolicyHandle policyHandle = null; + + if (weakRef != null) + { + policyHandle = weakRef.Target; + } + + if (policyHandle == null) + { + System.Threading.Interlocked.Increment(ref _lookupPolicyHandleMisses); + + policyHandle = new LsaPolicyHandle(LsaPolicyAccess.LookupNames); + + if (policyHandle != null) + _lookupPolicyHandle = new WeakReference(policyHandle); + } + + return policyHandle; + } + } + + public static int LookupPolicyHandleMisses + { + get { return _lookupPolicyHandleMisses; } + } + + public delegate bool EnumAccountsDelegate(Sid sid); + public delegate bool EnumPrivilegesDelegate(Privilege privilege); + + /// + /// Opens the local LSA policy object. + /// + /// The desired access to the policy. + public LsaPolicyHandle(LsaPolicyAccess access) + : this(null, access) + { } + + /// + /// Opens a LSA policy object. + /// + /// The name of the system on which the policy resides. + /// The desired access to the policy. + public LsaPolicyHandle(string systemName, LsaPolicyAccess access) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(); + UnicodeString systemNameStr; + IntPtr handle; + + systemNameStr = new UnicodeString(systemName); + + try + { + if ((status = Win32.LsaOpenPolicy( + ref systemNameStr, + ref oa, + access, + out handle + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + systemNameStr.Dispose(); + } + + this.Handle = handle; + } + + /// + /// Enumerates the accounts in the policy. This requires + /// ViewLocalInformation access. + /// + /// The callback for the enumeration. + public void EnumAccounts(EnumAccountsDelegate callback) + { + NtStatus status; + int enumerationContext = 0; + IntPtr buffer; + int count; + + while (true) + { + status = Win32.LsaEnumerateAccounts( + this, + ref enumerationContext, + out buffer, + 0x100, + out count + ); + + if (status == NtStatus.NoMoreEntries) + break; + if (status >= NtStatus.Error) + Win32.ThrowLastError(status); + + using (var bufferAlloc = new LsaMemoryAlloc(buffer)) + { + for (int i = 0; i < count; i++) + { + if (!callback(new Sid(bufferAlloc.ReadIntPtr(0, i)))) + return; + } + } + } + } + + /// + /// Enumerates the accounts in the policy with the specified privilege. + /// This requires LookupNames, ViewLocalInformation and usually + /// administrator access. + /// + /// The name of the required privilege. + /// The callback for the enumeration. + public void EnumAccountsWithPrivilege(string privilegeName, EnumAccountsDelegate callback) + { + NtStatus status; + UnicodeString privilegeNameStr; + IntPtr buffer; + int count; + + privilegeNameStr = new UnicodeString(privilegeName); + + try + { + if ((status = Win32.LsaEnumerateAccountsWithUserRight( + this, + ref privilegeNameStr, + out buffer, + out count + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + privilegeNameStr.Dispose(); + } + + Sid[] sids = new Sid[count]; + + using (var bufferAlloc = new LsaMemoryAlloc(buffer)) + { + for (int i = 0; i < count; i++) + { + if (!callback(new Sid(bufferAlloc.ReadIntPtr(0, i)))) + break; + } + } + } + + /// + /// Enumerates the privileges in the policy. This requires + /// ViewLocalInformation access. + /// + /// The callback for the enumeration. + public void EnumPrivileges(EnumPrivilegesDelegate callback) + { + NtStatus status; + int enumerationContext = 0; + IntPtr buffer; + int count; + + while (true) + { + status = Win32.LsaEnumeratePrivileges( + this, + ref enumerationContext, + out buffer, + 0x100, + out count + ); + + if (status == NtStatus.NoMoreEntries) + break; + if (status >= NtStatus.Error) + Win32.ThrowLastError(status); + + using (var bufferAlloc = new LsaMemoryAlloc(buffer)) + { + for (int i = 0; i < count; i++) + { + if (!callback(new Privilege(bufferAlloc.ReadStruct(i).Name.Read()))) + return; + } + } + } + } + + /// + /// Gets the accounts in the policy. This requires + /// ViewLocalInformation access. + /// + public Sid[] GetAccounts() + { + List sids = new List(); + + this.EnumAccounts((sid) => + { + sids.Add(sid); + return true; + }); + + return sids.ToArray(); + } + + /// + /// Gets the accounts in the policy with the specified privilege. + /// This requires LookupNames, ViewLocalInformation and usually + /// administrator access. + /// + /// The name of the required privilege. + public Sid[] GetAccountsWithPrivilege(string privilegeName) + { + List sids = new List(); + + this.EnumAccountsWithPrivilege(privilegeName, (sid) => + { + sids.Add(sid); + return true; + }); + + return sids.ToArray(); + } + + public Privilege[] GetPrivileges() + { + List privileges = new List(); + + this.EnumPrivileges((privilege) => + { + privileges.Add(privilege); + return true; + }); + + return privileges.ToArray(); + } + + public string LookupName(Sid sid) + { + SidNameUse nameUse; + + return this.LookupName(sid, out nameUse); + } + + public string LookupName(Sid sid, out SidNameUse nameUse) + { + string domainName; + + return this.LookupName(sid, out nameUse, out domainName); + } + + public string LookupName(Sid sid, out string domainName) + { + SidNameUse nameUse; + + return this.LookupName(sid, out nameUse, out domainName); + } + + public string LookupName(Sid sid, out SidNameUse nameUse, out string domainName) + { + NtStatus status; + IntPtr referencedDomains; + IntPtr names; + + if ((status = Win32.LsaLookupSids( + this, + 1, + new IntPtr[] { sid }, + out referencedDomains, + out names + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + using (var referencedDomainsAlloc = new LsaMemoryAlloc(referencedDomains)) + using (var namesAlloc = new LsaMemoryAlloc(names)) + { + LsaTranslatedName translatedName = namesAlloc.ReadStruct(); + + nameUse = translatedName.Use; + + if (nameUse == SidNameUse.Invalid || nameUse == SidNameUse.Unknown) + { + domainName = null; + + return null; + } + + if (translatedName.DomainIndex != -1) + { + LsaReferencedDomainList domains = referencedDomainsAlloc.ReadStruct(); + MemoryRegion trustArray = new MemoryRegion(domains.Domains); + LsaTrustInformation trustInfo = trustArray.ReadStruct(translatedName.DomainIndex); + + domainName = trustInfo.Name.Read(); + } + else + { + domainName = null; + } + + return translatedName.Name.Read(); + } + } + + public string LookupPrivilegeDisplayName(Luid value) + { + return this.LookupPrivilegeDisplayName(this.LookupPrivilegeName(value)); + } + + public string LookupPrivilegeDisplayName(string name) + { + NtStatus status; + UnicodeString nameStr; + IntPtr displayName; + short language; + + nameStr = new UnicodeString(name); + + try + { + if ((status = Win32.LsaLookupPrivilegeDisplayName( + this, + ref nameStr, + out displayName, + out language + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + nameStr.Dispose(); + } + + using (var displayNameAlloc = new LsaMemoryAlloc(displayName)) + { + return displayNameAlloc.ReadStruct().Read(); + } + } + + public string LookupPrivilegeName(Luid value) + { + NtStatus status; + IntPtr name; + + if ((status = Win32.LsaLookupPrivilegeName( + this, + ref value, + out name + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + using (var nameAlloc = new LsaMemoryAlloc(name)) + { + return nameAlloc.ReadStruct().Read(); + } + } + + public Luid LookupPrivilegeValue(string name) + { + NtStatus status; + UnicodeString nameStr; + Luid luid; + + nameStr = new UnicodeString(name); + + try + { + if ((status = Win32.LsaLookupPrivilegeValue( + this, + ref nameStr, + out luid + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + nameStr.Dispose(); + } + + return luid; + } + + public Sid LookupSid(string name) + { + SidNameUse nameUse; + + return this.LookupSid(name, out nameUse); + } + + public Sid LookupSid(string name, out SidNameUse nameUse) + { + string domainName; + + return this.LookupSid(name, out nameUse, out domainName); + } + + public Sid LookupSid(string name, out string domainName) + { + SidNameUse nameUse; + + return this.LookupSid(name, out nameUse, out domainName); + } + + public Sid LookupSid(string name, out SidNameUse nameUse, out string domainName) + { + NtStatus status; + UnicodeString nameStr; + IntPtr referencedDomains; + IntPtr sids; + + nameStr = new UnicodeString(name); + + try + { + if ((status = Win32.LsaLookupNames2( + this, + 0, + 1, + new UnicodeString[] { nameStr }, + out referencedDomains, + out sids + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + nameStr.Dispose(); + } + + using (var referencedDomainsAlloc = new LsaMemoryAlloc(referencedDomains)) + using (var sidsAlloc = new LsaMemoryAlloc(sids)) + { + LsaTranslatedSid2 translatedSid = sidsAlloc.ReadStruct(); + + nameUse = translatedSid.Use; + + if (nameUse == SidNameUse.Invalid || nameUse == SidNameUse.Unknown) + { + domainName = null; + + return null; + } + + if (translatedSid.DomainIndex != -1) + { + LsaReferencedDomainList domains = referencedDomainsAlloc.ReadStruct(); + MemoryRegion trustArray = new MemoryRegion(domains.Domains); + LsaTrustInformation trustInfo = trustArray.ReadStruct(translatedSid.DomainIndex); + + domainName = trustInfo.Name.Read(); + } + else + { + domainName = null; + } + + return new Sid(translatedSid.Sid); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/MailslotHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/MailslotHandle.cs new file mode 100644 index 000000000..2a4a825be --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/MailslotHandle.cs @@ -0,0 +1,113 @@ +/* + * Process Hacker - + * mailslot handle + * + * Copyright (C) 2009 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 . + */ + +using System; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + /// + /// Represents a handle to a mailslot. + /// + public sealed class MailslotHandle : FileHandle + { + public static MailslotHandle Create(FileAccess access, string fileName, int maxMessageSize, long readTimeout) + { + return Create( + access, + fileName, + ObjectFlags.CaseInsensitive, + null, + 0, + maxMessageSize, + readTimeout, + 0 + ); + } + + public static MailslotHandle Create( + FileAccess access, + string fileName, + ObjectFlags objectFlags, + FileHandle rootDirectory, + int quota, + int maxMessageSize, + long readTimeout, + FileCreateOptions createOptions + ) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(fileName, objectFlags, rootDirectory); + IoStatusBlock isb; + IntPtr handle; + + try + { + if ((status = Win32.NtCreateMailslotFile( + out handle, + access, + ref oa, + out isb, + createOptions, + quota, + maxMessageSize, + ref readTimeout + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + return new MailslotHandle(handle, true); + } + + private MailslotHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + public MailslotHandle(string fileName, FileAccess access) + : base(fileName, access) + { } + + public MailslotHandle(string fileName, FileShareMode shareMode, FileAccess access) + : base(fileName, shareMode, access) + { } + + public MailslotHandle(string fileName, FileShareMode shareMode, FileCreateOptions openOptions, FileAccess access) + : base(fileName, shareMode, openOptions, access) + { } + + public MailslotHandle( + string fileName, + ObjectFlags objectFlags, + FileHandle rootDirectory, + FileShareMode shareMode, + FileCreateOptions openOptions, + FileAccess access + ) + : base(fileName, objectFlags, rootDirectory, shareMode, openOptions, access) + { } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/MutantHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/MutantHandle.cs new file mode 100644 index 000000000..cba34ed8c --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/MutantHandle.cs @@ -0,0 +1,132 @@ +/* + * Process Hacker - + * mutant handle + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; +using System.Runtime.InteropServices; + +namespace ProcessHacker.Native.Objects +{ + public sealed class MutantHandle : NativeHandle + { + public static MutantHandle Create(MutantAccess access, bool initialOwner) + { + return Create(access, null, initialOwner); + } + + public static MutantHandle Create(MutantAccess access, string name, bool initialOwner) + { + return Create(access, name, 0, null, initialOwner); + } + + public static MutantHandle Create(MutantAccess access, string name, ObjectFlags objectFlags, DirectoryHandle rootDirectory, bool initialOwner) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtCreateMutant(out handle, access, ref oa, initialOwner)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + return new MutantHandle(handle, true); + } + + public static MutantHandle FromHandle(IntPtr handle) + { + return new MutantHandle(handle, false); + } + + private MutantHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + public MutantHandle(string name, ObjectFlags objectFlags, DirectoryHandle rootDirectory, MutantAccess access) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtOpenMutant(out handle, access, ref oa)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + this.Handle = handle; + } + + public MutantHandle(string name, MutantAccess access) + : this(name, 0, null, access) + { } + + public MutantBasicInformation GetBasicInformation() + { + NtStatus status; + MutantBasicInformation mbi; + int retLength; + + if ((status = Win32.NtQueryMutant(this, MutantInformationClass.MutantBasicInformation, + out mbi, Marshal.SizeOf(typeof(MutantBasicInformation)), out retLength)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return mbi; + } + + public MutantOwnerInformation GetOwnerInformation() + { + NtStatus status; + MutantOwnerInformation moi; + int retLength; + + if ((status = Win32.NtQueryMutant(this, MutantInformationClass.MutantOwnerInformation, + out moi, Marshal.SizeOf(typeof(MutantOwnerInformation)), out retLength)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return moi; + } + + public int Release() + { + NtStatus status; + int previousCount; + + if ((status = Win32.NtReleaseMutant(this, out previousCount)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return previousCount; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/NamedPipeHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/NamedPipeHandle.cs new file mode 100644 index 000000000..f10e8b91d --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/NamedPipeHandle.cs @@ -0,0 +1,400 @@ +/* + * Process Hacker - + * named pipe handle + * + * Copyright (C) 2009 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 . + */ + +using System; +using ProcessHacker.Common; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + /// + /// Represents a handle to a named pipe. + /// + public sealed class NamedPipeHandle : FileHandle + { + public static readonly int FsCtlAssignEvent = Win32.CtlCode(DeviceType.NamedPipe, 0, DeviceControlMethod.Buffered, DeviceControlAccess.Any); + public static readonly int FsCtlDisconnect = Win32.CtlCode(DeviceType.NamedPipe, 1, DeviceControlMethod.Buffered, DeviceControlAccess.Any); + public static readonly int FsCtlListen = Win32.CtlCode(DeviceType.NamedPipe, 2, DeviceControlMethod.Buffered, DeviceControlAccess.Any); + public static readonly int FsCtlPeek = Win32.CtlCode(DeviceType.NamedPipe, 3, DeviceControlMethod.Buffered, DeviceControlAccess.Read); + public static readonly int FsCtlQueryEvent = Win32.CtlCode(DeviceType.NamedPipe, 4, DeviceControlMethod.Buffered, DeviceControlAccess.Any); + public static readonly int FsCtlTransceive = Win32.CtlCode(DeviceType.NamedPipe, 5, DeviceControlMethod.Neither, DeviceControlAccess.Read | DeviceControlAccess.Write); + public static readonly int FsCtlWait = Win32.CtlCode(DeviceType.NamedPipe, 6, DeviceControlMethod.Buffered, DeviceControlAccess.Any); + public static readonly int FsCtlImpersonate = Win32.CtlCode(DeviceType.NamedPipe, 7, DeviceControlMethod.Buffered, DeviceControlAccess.Any); + public static readonly int FsCtlSetClientProcess = Win32.CtlCode(DeviceType.NamedPipe, 8, DeviceControlMethod.Buffered, DeviceControlAccess.Any); + public static readonly int FsCtlQueryClientProcess = Win32.CtlCode(DeviceType.NamedPipe, 9, DeviceControlMethod.Buffered, DeviceControlAccess.Any); + + public static NamedPipeHandle Create( + FileAccess access, + string fileName, + PipeType type, + int maximumInstances, + long defaultTimeout + ) + { + return Create( + access, + fileName, + ObjectFlags.CaseInsensitive, + null, + FileShareMode.ReadWrite, + FileCreationDisposition.OpenIf, + 0, + type, + type, + PipeCompletionMode.Queue, + maximumInstances, + 0, + 0, + defaultTimeout + ); + } + + public static NamedPipeHandle Create( + FileAccess access, + string fileName, + ObjectFlags objectFlags, + FileHandle rootDirectory, + FileShareMode shareMode, + FileCreationDisposition creationDisposition, + FileCreateOptions createOptions, + PipeType type, + PipeType readMode, + PipeCompletionMode completionMode, + int maximumInstances, + int inboundQuota, + int outboundQuota, + long defaultTimeout + ) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(fileName, objectFlags, rootDirectory); + IoStatusBlock isb; + IntPtr handle; + + try + { + if ((status = Win32.NtCreateNamedPipeFile( + out handle, + access, + ref oa, + out isb, + shareMode, + creationDisposition, + createOptions, + type, + readMode, + completionMode, + maximumInstances, + inboundQuota, + outboundQuota, + ref defaultTimeout + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + return new NamedPipeHandle(handle, true); + } + + public new static NamedPipeHandle FromHandle(IntPtr handle) + { + return new NamedPipeHandle(handle, false); + } + + public static bool Wait(string name) + { + return Wait(name, long.MinValue, false); + } + + /// + /// Waits for an instance of the specified named pipe to + /// become available for connection. + /// + /// The short name of the named pipe. + /// + /// The timeout, in 100ns units. + /// + /// + /// True if an instance of the pipe was available before the timeout + /// interval elapsed, otherwise false. + /// + public static bool Wait(string name, long timeout) + { + return Wait(name, timeout, true); + } + + public static bool Wait(string name, long timeout, bool relative) + { + using (var npfsHandle = new FileHandle( + Win32.NamedPipePath + "\\", + FileShareMode.ReadWrite, + FileCreateOptions.SynchronousIoNonAlert, + FileAccess.ReadAttributes | (FileAccess)StandardRights.Synchronize + )) + { + using (var data = new MemoryAlloc(FilePipeWaitForBuffer.NameOffset + name.Length * 2)) + { + FilePipeWaitForBuffer info = new FilePipeWaitForBuffer(); + + info.Timeout = timeout; + info.TimeoutSpecified = true; + info.NameLength = name.Length * 2; + data.WriteStruct(info); + data.WriteUnicodeString(FilePipeWaitForBuffer.NameOffset, name); + + NtStatus status; + int returnLength; + + status = npfsHandle.FsControl(FsCtlWait, data, data.Size, IntPtr.Zero, 0, out returnLength); + + if (status == NtStatus.IoTimeout) + return false; + + if (status >= NtStatus.Error) + Win32.ThrowLastError(status); + + return true; + } + } + } + + private NamedPipeHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + public NamedPipeHandle(string fileName, FileAccess access) + : base(fileName, access) + { } + + public NamedPipeHandle(string fileName, FileShareMode shareMode, FileAccess access) + : base(fileName, shareMode, access) + { } + + public NamedPipeHandle(string fileName, FileShareMode shareMode, FileCreateOptions openOptions, FileAccess access) + : base(fileName, shareMode, openOptions, access) + { } + + public NamedPipeHandle( + string fileName, + ObjectFlags objectFlags, + FileHandle rootDirectory, + FileShareMode shareMode, + FileCreateOptions openOptions, + FileAccess access + ) + : base(fileName, objectFlags, rootDirectory, shareMode, openOptions, access) + { } + + public AsyncIoContext BeginListen() + { + return this.BeginFsControl(FsCtlListen, null, null); + } + + public AsyncIoContext BeginTransceive( + byte[] inBuffer, + int inBufferOffset, + int inBufferLength, + byte[] outBuffer, + int outBufferOffset, + int outBufferLength + ) + { + return this.BeginFsControl( + FsCtlTransceive, + inBuffer, + inBufferOffset, + inBufferLength, + outBuffer, + outBufferOffset, + outBufferLength + ); + } + + public AsyncIoContext BeginTransceive(MemoryRegion inBuffer, MemoryRegion outBuffer) + { + return this.BeginFsControl(FsCtlTransceive, inBuffer, outBuffer); + } + + public bool EndListen(AsyncIoContext asyncContext) + { + asyncContext.Wait(); + asyncContext.NotifyEnd(); + + if (asyncContext.Status == NtStatus.PipeConnected) + return true; + + if (asyncContext.StatusBlock.Status >= NtStatus.Error) + Win32.ThrowLastError(asyncContext.StatusBlock.Status); + + return false; + } + + public int EndTransceive(AsyncIoContext asyncContext) + { + return this.EndCommonIo(asyncContext); + } + + public void Disconnect() + { + this.FsControl(FsCtlDisconnect, IntPtr.Zero, 0, IntPtr.Zero, 0); + } + + private FilePipeInformation GetInformation() + { + return this.QueryStruct(FileInformationClass.FilePipeInformation); + } + + private FilePipeLocalInformation GetLocalInformation() + { + return this.QueryStruct(FileInformationClass.FilePipeLocalInformation); + } + + public PipeType GetPipeType() + { + return this.GetInformation().ReadMode; + } + + public void ImpersonateClient() + { + this.FsControl(FsCtlImpersonate, null, null); + } + + public bool Listen() + { + NtStatus status; + int returnLength; + + status = this.FsControl(FsCtlListen, IntPtr.Zero, 0, IntPtr.Zero, 0, out returnLength); + + if (status == NtStatus.PipeConnected) + return true; + + if (status >= NtStatus.Error) + Win32.ThrowLastError(status); + + return false; + } + + public int Peek(byte[] buffer) + { + return this.Peek(buffer, 0, 0); + } + + public int Peek(byte[] buffer, int offset, int length) + { + int bytesAvailable; + + return this.Peek(buffer, offset, length, out bytesAvailable); + } + + public int Peek(IntPtr buffer, int length) + { + int bytesAvailable; + + return this.Peek(buffer, length, out bytesAvailable); + } + + public int Peek(byte[] buffer, out int bytesAvailable) + { + int bytesLeftInMessage; + + return this.Peek(buffer, out bytesAvailable, out bytesLeftInMessage); + } + + public int Peek(byte[] buffer, int offset, int length, out int bytesAvailable) + { + int bytesLeftInMessage; + + return this.Peek(buffer, offset, length, out bytesAvailable, out bytesLeftInMessage); + } + + public int Peek(IntPtr buffer, int length, out int bytesAvailable) + { + int bytesLeftInMessage; + + return this.Peek(buffer, length, out bytesAvailable, out bytesLeftInMessage); + } + + public int Peek(byte[] buffer, out int bytesAvailable, out int bytesLeftInMessage) + { + return this.Peek(buffer, 0, buffer.Length, out bytesAvailable, out bytesLeftInMessage); + } + + public int Peek(byte[] buffer, int offset, int length, out int bytesAvailable, out int bytesLeftInMessage) + { + Utils.ValidateBuffer(buffer, offset, length); + + unsafe + { + fixed (byte* bufferPtr = buffer) + { + return this.Peek(new IntPtr(&bufferPtr[offset]), length, out bytesAvailable, out bytesLeftInMessage); + } + } + } + + public int Peek(IntPtr buffer, int length, out int bytesAvailable, out int bytesLeftInMessage) + { + using (var data = new MemoryAlloc(FilePipePeekBuffer.DataOffset + length)) + { + NtStatus status; + int returnLength; + + status = this.FsControl(FsCtlPeek, IntPtr.Zero, 0, data, data.Size, out returnLength); + + // If we got a buffer overflow it simply means we didn't + // read all of the available bytes. + if (status == NtStatus.BufferOverflow) + status = NtStatus.Success; + + if (status >= NtStatus.Error) + Win32.ThrowLastError(status); + + FilePipePeekBuffer info = data.ReadStruct(); + int bytesRead; + + bytesAvailable = info.ReadDataAvailable; + bytesRead = returnLength - FilePipePeekBuffer.DataOffset; + bytesLeftInMessage = info.MessageLength - bytesRead; + + if (buffer != IntPtr.Zero) + data.ReadMemory(buffer, 0, FilePipePeekBuffer.DataOffset, bytesRead); + + return bytesRead; + } + } + + public int Transceive(byte[] inBuffer, byte[] outBuffer) + { + return this.FsControl(FsCtlTransceive, inBuffer, outBuffer); + } + + public int Transceive(IntPtr inBuffer, int inBufferLength, IntPtr outBuffer, int outBufferLength) + { + return this.FsControl(FsCtlTransceive, inBuffer, inBufferLength, outBuffer, outBufferLength); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/NativeHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/NativeHandle.cs new file mode 100644 index 000000000..7431a344d --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/NativeHandle.cs @@ -0,0 +1,663 @@ +/* + * Process Hacker - + * windows handle + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using ProcessHacker.Common.Objects; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; +using ProcessHacker.Native.Security.AccessControl; + +namespace ProcessHacker.Native.Objects +{ + /// + /// Represents a generic Windows handle which acts as a kernel handle by default. + /// + public class NativeHandle : BaseObject, IEquatable, ISecurable, ISynchronizable + { + public static IntPtr Invalid + { + get { return IntPtr.Zero; } + } + + public static IntPtr MinusOne + { + get { return (-1).ToIntPtr(); } + } + + public static bool IsInvalid(IntPtr handle) + { + return handle == Invalid; + } + + public static NtStatus WaitAll(ISynchronizable[] objects) + { + return WaitAll(objects, false, long.MinValue, false); + } + + public static NtStatus WaitAll(ISynchronizable[] objects, long timeout) + { + return WaitAll(objects, false, timeout); + } + + public static NtStatus WaitAll(ISynchronizable[] objects, bool alertable, long timeout) + { + return WaitAll(objects, alertable, timeout, true); + } + + public static NtStatus WaitAll(ISynchronizable[] objects, bool alertable, long timeout, bool relative) + { + return WaitForMultipleObjects(objects, WaitType.WaitAll, alertable, timeout, relative); + } + + public static NtStatus WaitAny(ISynchronizable[] objects) + { + return WaitAny(objects, false, long.MinValue, false); + } + + public static NtStatus WaitAny(ISynchronizable[] objects, long timeout) + { + return WaitAny(objects, false, timeout); + } + + public static NtStatus WaitAny(ISynchronizable[] objects, bool alertable, long timeout) + { + return WaitAny(objects, alertable, timeout, true); + } + + public static NtStatus WaitAny(ISynchronizable[] objects, bool alertable, long timeout, bool relative) + { + return WaitForMultipleObjects(objects, WaitType.WaitAny, alertable, timeout, relative); + } + + private static NtStatus WaitForMultipleObjects(ISynchronizable[] objects, WaitType waitType, bool alertable, long timeout, bool relative) + { + NtStatus status; + IntPtr[] handles = new IntPtr[objects.Length]; + long realTimeout = relative ? -timeout : timeout; + + for (int i = 0; i < objects.Length; i++) + handles[i] = objects[i].Handle; + + if ((status = Win32.NtWaitForMultipleObjects( + handles.Length, + handles, + waitType, + alertable, + ref realTimeout + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return status; + } + + public static implicit operator int(NativeHandle handle) + { + return handle.Handle.ToInt32(); + } + + public static implicit operator IntPtr(NativeHandle handle) + { + return handle.Handle; + } + + private IntPtr _handle; + + /// + /// Creates a new, invalid handle. You must set the handle using the Handle property. + /// + protected NativeHandle() + { } + + /// + /// Creates a new handle using the specified value. The handle will be closed when + /// this object is disposed or garbage-collected. + /// + /// The handle value. + public NativeHandle(IntPtr handle) + { + _handle = handle; + } + + /// + /// Creates a new handle using the specified value. If owned is set to false, the + /// handle will not be closed automatically. + /// + /// The handle value. + /// Specifies whether the handle will be closed automatically. + public NativeHandle(IntPtr handle, bool owned) + : base(owned) + { + _handle = handle; + } + + protected sealed override void DisposeObject(bool disposing) + { + this.Close(); + } + + /// + /// Closes the handle. This method must not be called directly; instead, + /// override this method in a derived class if your handle must be closed + /// with a method other than CloseHandle. + /// + protected virtual void Close() + { + if (_handle != IntPtr.Zero && _handle.ToInt32() != -1 && _handle.ToInt32() != -2) + Win32.NtClose(_handle); + } + + /// + /// Gets the handle value. + /// + public IntPtr Handle + { + get { return _handle; } + protected set { _handle = value; } + } + + /// + /// Determines if the specified object is equal to the current handle. + /// + /// The object to compare. + /// Whether the two objects are equal. + public override bool Equals(object obj) + { + return this.Equals(obj as NativeHandle); + } + + /// + /// Determines if the specified handle is equal to the current handle. + /// + /// The handle to compare. + /// Whether the two handles are equal. + public bool Equals(NativeHandle obj) + { + if (obj == null) + return false; + return obj.Handle == this.Handle; + } + + /// + /// Gets certain information about the handle. + /// + /// A HANDLE_FLAGS value. + public virtual Win32HandleFlags GetHandleFlags() + { + Win32HandleFlags flags; + + if (!Win32.GetHandleInformation(this, out flags)) + Win32.ThrowLastError(); + + return flags; + } + + /// + /// Gets a unique hash code for the handle. + /// + /// A hash code. + public override int GetHashCode() + { + return _handle.ToInt32(); + } + + /// + /// Gets the handle's name. + /// + /// A string. + public virtual string GetObjectName() + { + NtStatus status; + int retLength; + + status = Win32.NtQueryObject(this, ObjectInformationClass.ObjectNameInformation, + IntPtr.Zero, 0, out retLength); + + if (retLength > 0) + { + using (MemoryAlloc oniMem = new MemoryAlloc(retLength)) + { + if ((status = Win32.NtQueryObject(this, ObjectInformationClass.ObjectNameInformation, + oniMem, oniMem.Size, out retLength)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + var oni = oniMem.ReadStruct(); + + return oni.Name.Read(); + } + } + else + { + Win32.ThrowLastError(status); + } + + return null; + } + + /// + /// Gets the handle's type name. + /// + /// A string. + public virtual string GetObjectTypeName() + { + NtStatus status; + int retLength; + + status = Win32.NtQueryObject(this, ObjectInformationClass.ObjectTypeInformation, + IntPtr.Zero, 0, out retLength); + + if (retLength > 0) + { + using (MemoryAlloc otiMem = new MemoryAlloc(retLength)) + { + if ((status = Win32.NtQueryObject(this, ObjectInformationClass.ObjectTypeInformation, + otiMem, otiMem.Size, out retLength)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + var oni = otiMem.ReadStruct(); + + return oni.Name.Read(); + } + } + else + { + Win32.ThrowLastError(status); + } + + return null; + } + + /// + /// Gets the security descriptor of the object. + /// + /// The information to retrieve. + /// A security descriptor. + public virtual SecurityDescriptor GetSecurity(SecurityInformation securityInformation) + { + return SecurityDescriptor.GetSecurity(this, securityInformation); + } + + /// + /// Gets the security descriptor of the object. + /// + /// The type of the object. + /// The information to retrieve. + /// A security descriptor. + protected SecurityDescriptor GetSecurity(SeObjectType objectType, SecurityInformation securityInformation) + { + return SecurityDescriptor.GetSecurity(this, objectType, securityInformation); + } + + /// + /// Makes the object referenced by the handle permanent. + /// + public virtual void MakeObjectPermanent() + { + NtStatus status; + + if ((status = Win32.NtMakePermanentObject(this)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + /// + /// Makes the object referenced by the handle temporary. The object + /// will be deleted once the last handle to it is closed. This function + /// requires Delete access. + /// + public virtual void MakeObjectTemporary() + { + NtStatus status; + + if ((status = Win32.NtMakeTemporaryObject(this)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + /// + /// Marks the handle as invalid. This method must only be called from + /// within a derived class constructor. + /// + protected void MarkAsInvalid() + { + this.DisableOwnership(false); + } + + /// + /// Sets certain information about the handle. + /// + /// Specifies which flags to set. + /// The values of the flags to set. + public virtual void SetHandleFlags(Win32HandleFlags mask, Win32HandleFlags flags) + { + if (!Win32.SetHandleInformation(this, mask, flags)) + Win32.ThrowLastError(); + } + + /// + /// Sets the security descriptor of the object. + /// + /// The information to modify. + /// The security descriptor. + public virtual void SetSecurity(SecurityInformation securityInformation, SecurityDescriptor securityDescriptor) + { + SecurityDescriptor.SetSecurity(this, securityInformation, securityDescriptor); + } + + /// + /// Sets the security descriptor of the object. + /// + /// The type of the object. + /// The information to modify. + /// The security descriptor. + protected void SetSecurity(SeObjectType objectType, SecurityInformation securityInformation, SecurityDescriptor securityDescriptor) + { + SecurityDescriptor.SetSecurity(this, objectType, securityInformation, securityDescriptor); + } + + /// + /// Signals the object and waits for another. + /// + public virtual NtStatus SignalAndWait(ISynchronizable waitObject) + { + return this.SignalAndWait(waitObject, false); + } + + /// + /// Signals the object and waits for another. + /// + public virtual NtStatus SignalAndWait(ISynchronizable waitObject, bool alertable) + { + return this.SignalAndWait(waitObject, alertable, long.MinValue, false); + } + + /// + /// Signals the object and waits for another. + /// + public virtual NtStatus SignalAndWait(ISynchronizable waitObject, bool alertable, long timeout) + { + return this.SignalAndWait(waitObject, alertable, timeout, true); + } + + /// + /// Signals the object and waits for another. + /// + public virtual NtStatus SignalAndWait(ISynchronizable waitObject, bool alertable, long timeout, bool relative) + { + NtStatus status; + long realTimeout = relative ? -timeout : timeout; + + if ((status = Win32.NtSignalAndWaitForSingleObject( + this, + waitObject.Handle, + alertable, + ref timeout + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return status; + } + + /// + /// Closes the current handle and assigns a new handle to the NativeHandle instance. + /// + /// The new handle value. + protected void SwapHandle(IntPtr newHandle) + { + if (!this.Owned || this.Disposed) + throw new InvalidOperationException(); + + this.Close(); + _handle = newHandle; + } + + /// + /// Gets a string that represents the handle. + /// + /// A string. + public override string ToString() + { + return this.GetType().Name + ": " + _handle.ToString("x"); + } + + /// + /// Waits for the object to be signaled. + /// + public virtual NtStatus Wait() + { + return this.Wait(false); + } + + /// + /// Waits for the object to be signaled. + /// + /// + /// Whether user-mode APCs can be delivered during the wait. + /// + public virtual NtStatus Wait(bool alertable) + { + /* Note that in order to wait for an infinite amount of time + * NULL should be passed as the timeout parameter to + * KeWaitForSingleObject/MultipleObjects. However, + * long.MinValue = -9223372036854775808 + * = 9223372036854775808 100ns (relative) + * = 922337203685477580.8 microseconds + * = 922337203685477.5808 ms + * = 922337203685.4775808 s + * = 15372286728.091293013333333333333 minutes + * = 256204778.80152155022222222222222 hours + * = 10675199.116730064592592592592593 days + * = 7306.7755761328299743960250462646 4 years (including one leap year) + * = 29227.102304531319897584100185058 years (average) + * = 29.227102304531319897584100185058 millennia + * That's long enough, I think... + */ + return this.Wait(alertable, long.MinValue, false); + } + + /// + /// Waits for the object to be signaled. + /// + /// The timeout, in 100ns units. + public NtStatus Wait(long timeout) + { + return this.Wait(false, timeout); + } + + /// + /// Waits for the object to be signaled. + /// + /// + /// Whether user-mode APCs can be delivered during the wait. + /// + /// The timeout, in 100ns units. + public virtual NtStatus Wait(bool alertable, long timeout) + { + return this.Wait(alertable, timeout, true); + } + + /// + /// Waits for the object to be signaled. + /// + /// The timeout, in 100ns units. + /// Whether the timeout value is relative. + public NtStatus Wait(long timeout, bool relative) + { + return this.Wait(false, timeout, relative); + } + + /// + /// Waits for the object to be signaled. + /// + /// + /// Whether user-mode APCs can be delivered during the wait. + /// + /// The timeout, in 100ns units. + /// Whether the timeout value is relative. + public virtual NtStatus Wait(bool alertable, long timeout, bool relative) + { + NtStatus status; + long realTimeout = relative ? -timeout : timeout; + + if ((status = Win32.NtWaitForSingleObject( + this, + alertable, + ref realTimeout + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return status; + } +} + + /// + /// Represents a generic Windows handle which acts as a kernel handle by default. + /// + public class NativeHandle : NativeHandle + where TAccess : struct + { + /// + /// Creates a new, invalid handle. You must set the handle using the Handle property. + /// + protected NativeHandle() + { } + + /// + /// Creates a new handle using the specified value. The handle will be closed when + /// this object is disposed or garbage-collected. + /// + /// The handle value. + public NativeHandle(IntPtr handle) + : base(handle) + { } + + /// + /// Creates a new handle using the specified value. If owned is set to false, the + /// handle will not be closed automatically. + /// + /// The handle value. + /// Specifies whether the handle will be closed automatically. + public NativeHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + /// + /// Creates a new handle by duplicating an existing handle. + /// + /// The existing handle. + /// The desired access to the object. + public NativeHandle(IntPtr handle, TAccess access) + { + IntPtr newHandle; + + Win32.DuplicateObject(ProcessHandle.Current, handle, ProcessHandle.Current, out newHandle, + (int)Convert.ChangeType(access, typeof(int)), 0, 0); + this.Handle = newHandle; + } + + /// + /// Creates a new handle by duplicating an existing handle from another process. + /// + /// A handle to a process. It must have the PROCESS_DUP_HANDLE permission. + /// The existing handle. + /// The desired access to the object. + public NativeHandle(ProcessHandle processHandle, IntPtr handle, TAccess access) + { + IntPtr newHandle; + + Win32.DuplicateObject(processHandle, handle, ProcessHandle.Current, out newHandle, + (int)Convert.ChangeType(access, typeof(int)), 0, 0); + this.Handle = newHandle; + } + + /// + /// Attempts to duplicate the handle with different access rights. + /// + /// The new access rights. + public void ChangeAccess(TAccess access) + { + IntPtr newHandle; + + Win32.DuplicateObject(ProcessHandle.Current, this, ProcessHandle.Current, out newHandle, + (int)Convert.ChangeType(access, typeof(int)), 0, 0); + this.SwapHandle(newHandle); + } + + /// + /// Duplicates the handle. + /// + /// The desired access to the object. + /// A handle. + public NativeHandle Duplicate(TAccess access) + { + return new NativeHandle(ProcessHandle.Current, this, access); + } + } + + /// + /// Represents a generic Windows handle which acts as a kernel handle by default. + /// + public class GenericHandle : NativeHandle + { + /// + /// Creates a new, invalid handle. You must set the handle using the Handle property. + /// + protected GenericHandle() + : base() + { } + + /// + /// Creates a new handle using the specified value. The handle will be closed when + /// this object is disposed or garbage-collected. + /// + /// The handle value. + public GenericHandle(IntPtr handle) + : base(handle) + { } + + /// + /// Creates a new handle using the specified value. If owned is set to false, the + /// handle will not be closed automatically. + /// + /// The handle value. + /// Specifies whether the handle will be closed automatically. + public GenericHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + /// + /// Creates a new handle by duplicating an existing handle. + /// + /// The existing handle. + /// The desired access to the object. + public GenericHandle(IntPtr handle, int desiredAccess) + : base(handle, desiredAccess) + { } + + /// + /// Creates a new handle by duplicating an existing handle from another process. + /// + /// A handle to a process. It must have the PROCESS_DUP_HANDLE permission. + /// The existing handle. + /// The desired access to the object. + public GenericHandle(ProcessHandle processHandle, IntPtr handle, int desiredAccess) + : base(processHandle, handle, desiredAccess) + { } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/PortComHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/PortComHandle.cs new file mode 100644 index 000000000..73adfe161 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/PortComHandle.cs @@ -0,0 +1,168 @@ +/* + * Process Hacker - + * port communication handle + * + * Copyright (C) 2009 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 . + */ + +using System; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Lpc; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + public sealed class PortComHandle : NativeHandle + { + public static PortComHandle Connect(string portName) + { + NtStatus status; + UnicodeString portNameStr = new UnicodeString(portName); + SecurityQualityOfService securityQos = + new SecurityQualityOfService(SecurityImpersonationLevel.SecurityImpersonation, true, false); + IntPtr handle; + + try + { + if ((status = Win32.NtConnectPort( + out handle, + ref portNameStr, + ref securityQos, + IntPtr.Zero, + IntPtr.Zero, + IntPtr.Zero, + IntPtr.Zero, + IntPtr.Zero + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + portNameStr.Dispose(); + } + + return new PortComHandle(handle, true); + } + + internal PortComHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + public void Reply(PortMessage message) + { + NtStatus status; + + using (var messageMemory = message.ToMemory()) + { + if ((status = Win32.NtReplyPort(this, messageMemory)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + message.SetHeader(messageMemory); + } + } + + public PortMessage ReplyWaitReceive() + { + return this.ReplyWaitReceive(null); + } + + public PortMessage ReplyWaitReceive(PortMessage message) + { + NtStatus status; + IntPtr context; + + using (var buffer = PortMessage.AllocateBuffer()) + { + MemoryAlloc messageMemory = null; + + if (message != null) + messageMemory = message.ToMemory(); + + try + { + if ((status = Win32.NtReplyWaitReceivePort( + this, + out context, + messageMemory ?? IntPtr.Zero, + buffer + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + if (message != null) + message.SetHeader(messageMemory); + } + finally + { + if (messageMemory != null) + messageMemory.Dispose(); + } + + return new PortMessage(buffer); + } + } + + public PortMessage ReplyWaitReply(PortMessage message) + { + NtStatus status; + + using (var messageMemory = message.ToMemory()) + { + if ((status = Win32.NtReplyWaitReplyPort( + this, + messageMemory + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return new PortMessage(messageMemory); + } + } + + public void Request(PortMessage message) + { + NtStatus status; + + using (var messageMemory = message.ToMemory()) + { + if ((status = Win32.NtRequestPort(this, messageMemory)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + message.SetHeader(messageMemory); + } + } + + public PortMessage RequestWaitReply(PortMessage message) + { + NtStatus status; + + using (var buffer = PortMessage.AllocateBuffer()) + using (var messageMemory = message.ToMemory()) + { + if ((status = Win32.NtRequestWaitReplyPort( + this, + messageMemory, + buffer + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + message.SetHeader(messageMemory); + + return new PortMessage(buffer); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/PortHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/PortHandle.cs new file mode 100644 index 000000000..25e30284b --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/PortHandle.cs @@ -0,0 +1,177 @@ +/* + * Process Hacker - + * port handle + * + * Copyright (C) 2009 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 . + */ + +using System; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Lpc; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + public sealed class PortHandle : NativeHandle + { + public static PortHandle Create( + string name, + ObjectFlags objectFlags, + DirectoryHandle rootDirectory + ) + { + return Create( + name, + objectFlags, + rootDirectory, + Win32.PortMessageMaxDataLength, + Win32.PortMessageMaxLength, + 0 + ); + } + + public static PortHandle Create( + string name, + ObjectFlags objectFlags, + DirectoryHandle rootDirectory, + int maxConnectionInfoLength, + int maxMessageLength, + int maxPoolUsage + ) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtCreatePort( + out handle, + ref oa, + maxConnectionInfoLength, + maxMessageLength, + maxPoolUsage + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + return new PortHandle(handle, true); + } + + public static PortHandle CreateWaitable( + string name, + ObjectFlags objectFlags, + DirectoryHandle rootDirectory + ) + { + return CreateWaitable( + name, + objectFlags, + rootDirectory, + Win32.PortMessageMaxDataLength, + Win32.PortMessageMaxLength, + 0 + ); + } + + public static PortHandle CreateWaitable( + string name, + ObjectFlags objectFlags, + DirectoryHandle rootDirectory, + int maxConnectionInfoLength, + int maxMessageLength, + int maxPoolUsage + ) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtCreateWaitablePort( + out handle, + ref oa, + maxConnectionInfoLength, + maxMessageLength, + maxPoolUsage + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + return new PortHandle(handle, true); + } + + private PortHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + public PortComHandle AcceptConnect(PortMessage message, bool accept) + { + NtStatus status; + IntPtr portHandle; + + using (var messageMemory = message.ToMemory()) + { + if ((status = Win32.NtAcceptConnectPort( + out portHandle, + IntPtr.Zero, + messageMemory, + accept, + IntPtr.Zero, + IntPtr.Zero + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + if (!NativeHandle.IsInvalid(portHandle)) + return new PortComHandle(portHandle, true); + else + return null; + } + } + + public void CompleteConnect() + { + NtStatus status; + + if ((status = Win32.NtCompleteConnectPort(this)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + public PortMessage Listen() + { + NtStatus status; + + using (var buffer = PortMessage.AllocateBuffer()) + { + if ((status = Win32.NtListenPort(this, buffer)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return new PortMessage(buffer); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/PrivateNamespaceHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/PrivateNamespaceHandle.cs new file mode 100644 index 000000000..882e146c2 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/PrivateNamespaceHandle.cs @@ -0,0 +1,117 @@ +/* + * Process Hacker - + * private namespace handle + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using ProcessHacker.Common.Objects; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + /// + /// Represents a private namespace, a private directory object. + /// + public class PrivateNamespaceHandle : DirectoryHandle + { + public static PrivateNamespaceHandle Create(BoundaryDescriptor boundaryDescriptor, string aliasPrefix) + { + IntPtr handle = IntPtr.Zero; + + handle = Win32.CreatePrivateNamespace(IntPtr.Zero, boundaryDescriptor.Descriptor, aliasPrefix); + + if (handle == IntPtr.Zero) + Win32.ThrowLastError(); + + return new PrivateNamespaceHandle(handle, true); + } + + private bool _destroy = false; + + private PrivateNamespaceHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + public PrivateNamespaceHandle(BoundaryDescriptor boundaryDescriptor, string aliasPrefix) + { + this.Handle = Win32.OpenPrivateNamespace(boundaryDescriptor.Descriptor, aliasPrefix); + + if (this.Handle == IntPtr.Zero) + { + this.MarkAsInvalid(); + Win32.ThrowLastError(); + } + } + + protected override void Close() + { + Win32.ClosePrivateNamespace(this, _destroy ? PrivateNamespaceFlags.Destroy : 0); + } + + public void MarkForDestruction() + { + _destroy = true; + } + } + + public class BoundaryDescriptor : BaseObject + { + private IntPtr _descriptor; + + public BoundaryDescriptor(string name) + : this(name, null) + { } + + public BoundaryDescriptor(string name, IEnumerable sids) + { + _descriptor = Win32.CreateBoundaryDescriptor(name, 0); + + if (_descriptor == IntPtr.Zero) + { + this.DisableOwnership(false); + Win32.ThrowLastError(); + } + + if (sids != null) + { + foreach (Sid sid in sids) + this.Add(sid); + } + } + + protected override void DisposeObject(bool disposing) + { + Win32.DeleteBoundaryDescriptor(_descriptor); + } + + public IntPtr Descriptor + { + get { return _descriptor; } + } + + public void Add(Sid sid) + { + if (!Win32.AddSIDToBoundaryDescriptor(ref _descriptor, sid)) + Win32.ThrowLastError(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/ProcessHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/ProcessHandle.cs new file mode 100644 index 000000000..328223868 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/ProcessHandle.cs @@ -0,0 +1,2917 @@ +/* + * Process Hacker - + * process handle + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Runtime.InteropServices; +using System.Text; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + /// + /// Represents a handle to a Windows process. + /// + /// + /// The idea of a ProcessHandle class is + /// different to the class; + /// instead of opening the process with the right permissions every + /// time a query or set function is called, this lets the users control + /// when they want to open handles with certain permissions. This + /// means that handles can be cached (by the users). + /// + public sealed class ProcessHandle : NativeHandle, IWithToken + { + /// + /// The callback for enumerating process memory regions. + /// + /// The basic information for the memory region. + /// Return true to continue enumerating; return false to stop. + public delegate bool EnumMemoryDelegate(MemoryBasicInformation info); + + /// + /// The callback for enumerating process modules. + /// + /// The module information. + /// Return true to continue enumerating; return false to stop. + public delegate bool EnumModulesDelegate(ProcessModule module); + + private static readonly ProcessHandle _current = new ProcessHandle(new IntPtr(-1), false); + + /// + /// Gets a handle to the current process. + /// + public static ProcessHandle Current + { + get { return _current; } + } + + /// + /// Creates a process. + /// + /// The desired access to the new process. + /// The process to inherit the address space and handles from. + /// Specify true to inherit handles, otherwise false. + /// A section of an executable image. + /// A handle to the new process. + public static ProcessHandle Create( + ProcessAccess access, + ProcessHandle parentProcess, + bool inheritHandles, + SectionHandle sectionHandle) + { + return Create(access, null, 0, null, parentProcess, inheritHandles, sectionHandle, null); + } + + /// + /// Creates a process. + /// + /// The desired access to the new process. + /// The name of the process. + /// The flags to use when creating the object. + /// A handle to the directory in which to place the object. + /// The process to inherit the address space and handles from. + /// Specify true to inherit handles, otherwise false. + /// A section of an executable image. + /// A debug object to attach the process to. + /// A handle to the new process. + public static ProcessHandle Create( + ProcessAccess access, + string name, + ObjectFlags objectFlags, + DirectoryHandle rootDirectory, + ProcessHandle parentProcess, + bool inheritHandles, + SectionHandle sectionHandle, + DebugObjectHandle debugPort + ) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtCreateProcess( + out handle, + access, + ref oa, + parentProcess ?? IntPtr.Zero, + inheritHandles, + sectionHandle ?? IntPtr.Zero, + debugPort ?? IntPtr.Zero, + IntPtr.Zero + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + return new ProcessHandle(handle, true); + } + + public static ProcessHandle CreateExtended( + string fileName, + ProcessHandle parentProcess, + ProcessCreationFlags creationFlags, + bool inheritHandles, + string currentDirectory, + StartupInfo startupInfo, + out ClientId clientId, + out ThreadHandle threadHandle + ) + { + return CreateExtended( + fileName, + parentProcess, + creationFlags, + true, + inheritHandles, + EnvironmentBlock.GetCurrent(), + currentDirectory, + startupInfo, + out clientId, + out threadHandle + ); + } + + public static ProcessHandle CreateExtended( + string fileName, + ProcessHandle parentProcess, + ProcessCreationFlags creationFlags, + bool notifyCsr, + bool inheritHandles, + EnvironmentBlock environment, + string currentDirectory, + StartupInfo startupInfo, + out ClientId clientId, + out ThreadHandle threadHandle + ) + { + ProcessHandle phandle; + ThreadHandle thandle; + SectionImageInformation imageInfo; + + // If we don't have a desktop, use the current one. + if (startupInfo.Desktop == null) + startupInfo.Desktop = ProcessHandle.Current.GetPebString(PebOffset.DesktopName); + + // Open the file, create a section, and create a process. + using (var fhandle = new FileHandle( + fileName, + FileShareMode.Read | FileShareMode.Delete, + FileAccess.Execute | (FileAccess)StandardRights.Synchronize + )) + { + using (var shandle = SectionHandle.Create( + SectionAccess.All, + SectionAttributes.Image, + MemoryProtection.Execute, + fhandle + )) + { + imageInfo = shandle.GetImageInformation(); + + phandle = Create( + ProcessAccess.All, + parentProcess, + inheritHandles, + shandle + ); + } + } + + IntPtr peb = phandle.GetBasicInformation().PebBaseAddress; + + // Copy the process parameters across. + NativeUtils.CopyProcessParameters( + phandle, + peb, + creationFlags, + FileUtils.GetFileName(fileName), + ProcessHandle.Current.GetPebString(PebOffset.DllPath), + currentDirectory, + fileName, + environment, + startupInfo.Title != null ? startupInfo.Title : fileName, + startupInfo.Desktop != null ? startupInfo.Desktop : "", + startupInfo.Reserved != null ? startupInfo.Reserved : "", + "", + ref startupInfo + ); + + // TODO: Duplicate the console handles (stdin, stdout, stderr). + + // Create the initial thread. + thandle = ThreadHandle.CreateUserThread( + phandle, + true, + imageInfo.StackCommit.Increment(imageInfo.StackReserved).ToInt32(), + imageInfo.StackCommit.ToInt32(), + imageInfo.TransferAddress, + IntPtr.Zero, + out clientId + ); + + // Notify CSR. + + if (notifyCsr) + { + BaseCreateProcessMsg processMsg = new BaseCreateProcessMsg(); + + processMsg.ProcessHandle = phandle; + processMsg.ThreadHandle = thandle; + processMsg.ClientId = clientId; + processMsg.CreationFlags = creationFlags; + + if ((creationFlags & (ProcessCreationFlags.DebugProcess | + ProcessCreationFlags.DebugOnlyThisProcess)) != 0) + { + NtStatus status; + + status = Win32.DbgUiConnectToDbg(); + + if (status >= NtStatus.Error) + { + phandle.Terminate(status); + Win32.ThrowLastError(status); + } + + processMsg.DebuggerClientId = ThreadHandle.GetCurrentCid(); + } + + // If this is a GUI program, set the 1 and 2 bits to turn the + // hourglass cursor on. + if (imageInfo.ImageSubsystem == 2) + processMsg.ProcessHandle = processMsg.ProcessHandle.Or((1 | 2).ToIntPtr()); + // We still have to honor the startup info settings, though. + if ((startupInfo.Flags & StartupFlags.ForceOnFeedback) == + StartupFlags.ForceOnFeedback) + processMsg.ProcessHandle = processMsg.ProcessHandle.Or((1).ToIntPtr()); + if ((startupInfo.Flags & StartupFlags.ForceOffFeedback) == + StartupFlags.ForceOffFeedback) + processMsg.ProcessHandle = processMsg.ProcessHandle.And((1).ToIntPtr().Not()); + + using (var data = new MemoryAlloc( + CsrApiMsg.ApiMessageDataOffset + Marshal.SizeOf(typeof(BaseCreateProcessMsg)) + )) + { + data.WriteStruct(CsrApiMsg.ApiMessageDataOffset, 0, processMsg); + + Win32.CsrClientCallServer( + data, + IntPtr.Zero, + Win32.CsrMakeApiNumber(Win32.BaseSrvServerDllIndex, (int)BaseSrvApiNumber.BasepCreateProcess), + Marshal.SizeOf(typeof(BaseCreateProcessMsg)) + ); + + NtStatus status = (NtStatus)data.ReadStruct().ReturnValue; + + if (status >= NtStatus.Error) + { + phandle.Terminate(status); + Win32.ThrowLastError(status); + } + } + } + + if ((creationFlags & ProcessCreationFlags.CreateSuspended) == 0) + thandle.Resume(); + + threadHandle = thandle; + + return phandle; + } + + public static ProcessHandle CreateUserProcess(string fileName, out ClientId clientId, out ThreadHandle threadHandle) + { + NtStatus status; + UnicodeString fileNameStr = new UnicodeString(fileName); + RtlUserProcessParameters processParams = new RtlUserProcessParameters(); + RtlUserProcessInformation processInfo; + + processParams.Length = Marshal.SizeOf(processParams); + processParams.MaximumLength = processParams.Length; + processParams.ImagePathName = new UnicodeString(fileName); + processParams.CommandLine = new UnicodeString(fileName); + + Win32.RtlCreateEnvironment(true, out processParams.Environment); + + try + { + if ((status = Win32.RtlCreateUserProcess( + ref fileNameStr, + 0, + ref processParams, + IntPtr.Zero, + IntPtr.Zero, + IntPtr.Zero, + false, + IntPtr.Zero, + IntPtr.Zero, + out processInfo + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + clientId = processInfo.ClientId; + threadHandle = new ThreadHandle(processInfo.Thread, true); + + return new ProcessHandle(processInfo.Process, true); + } + finally + { + fileNameStr.Dispose(); + processParams.ImagePathName.Dispose(); + processParams.CommandLine.Dispose(); + Win32.RtlDestroyEnvironment(processParams.Environment); + } + } + + public static ProcessHandle CreateWin32( + string applicationName, + string commandLine, + bool inheritHandles, + ProcessCreationFlags creationFlags, + EnvironmentBlock environment, + string currentDirectory, + StartupInfo startupInfo, + out ClientId clientId, + out ThreadHandle threadHandle + ) + { + ProcessInformation processInformation; + + if (!Win32.CreateProcess( + applicationName, + commandLine, + IntPtr.Zero, + IntPtr.Zero, + inheritHandles, + creationFlags, + environment, + currentDirectory, + ref startupInfo, + out processInformation + )) + Win32.ThrowLastError(); + + clientId = new ClientId(processInformation.ProcessId, processInformation.ThreadId); + threadHandle = new ThreadHandle(processInformation.ThreadHandle, true); + + return new ProcessHandle(processInformation.ProcessHandle, true); + } + + /// + /// Creates a process handle using an existing handle. + /// The handle will not be closed automatically. + /// + /// The handle value. + /// The process handle. + public static ProcessHandle FromHandle(IntPtr handle) + { + return new ProcessHandle(handle, false); + } + + /// + /// Gets a handle to the current process. + /// + /// A process handle. + public static ProcessHandle GetCurrent() + { + return Current; + } + + /// + /// Gets the ID of the current process. + /// + /// The ID of the current process. + public static int GetCurrentId() + { + return Win32.GetCurrentProcessId(); + } + + /// + /// Gets a pointer to the current process' environment block. + /// + /// A pointer to the current PEB. + public unsafe static Peb* GetCurrentPeb() + { + return (Peb*)ThreadHandle.GetCurrentTeb()->ProcessEnvironmentBlock; + } + + public unsafe static RtlUserProcessParameters* GetCurrentProcessParameters() + { + return (RtlUserProcessParameters*)GetCurrentPeb()->ProcessParameters; + } + + private static int GetPebOffset(PebOffset offset) + { + switch (offset) + { + case PebOffset.CommandLine: + return RtlUserProcessParameters.CommandLineOffset; + case PebOffset.CurrentDirectoryPath: + return RtlUserProcessParameters.CurrentDirectoryOffset; + case PebOffset.DesktopName: + return RtlUserProcessParameters.DesktopInfoOffset; + case PebOffset.DllPath: + return RtlUserProcessParameters.DllPathOffset; + case PebOffset.ImagePathName: + return RtlUserProcessParameters.ImagePathNameOffset; + case PebOffset.RuntimeData: + return RtlUserProcessParameters.RuntimeDataOffset; + case PebOffset.ShellInfo: + return RtlUserProcessParameters.ShellInfoOffset; + case PebOffset.WindowTitle: + return RtlUserProcessParameters.WindowTitleOffset; + default: + throw new ArgumentException("offset"); + } + } + + /// + /// Opens processes with the specified name. + /// + /// The names of the processes to open. + /// The desired access to the processes. + /// An array of process handles. + public static ProcessHandle[] OpenByName(string processName, ProcessAccess access) + { + var processes = Windows.GetProcesses(); + List processHandles = new List(); + + foreach (var process in processes.Values) + { + if (string.Equals(process.Name, processName, StringComparison.InvariantCultureIgnoreCase)) + { + try + { + processHandles.Add(new ProcessHandle(process.Process.ProcessId, access)); + } + catch + { } + } + } + + return processHandles.ToArray(); + } + + /// + /// Opens a handle to the current process. + /// + /// The desired access to the current process. + /// A handle. + public static ProcessHandle OpenCurrent(ProcessAccess access) + { + return new ProcessHandle(GetCurrentId(), access); + } + + public static ProcessHandle OpenWithAnyAccess(int pid) + { + try + { + return new ProcessHandle(pid, OSVersion.MinProcessQueryInfoAccess); + } + catch + { + try + { + return new ProcessHandle(pid, (ProcessAccess)StandardRights.Synchronize); + } + catch + { + try + { + return new ProcessHandle(pid, (ProcessAccess)StandardRights.ReadControl); + } + catch + { + try + { + return new ProcessHandle(pid, (ProcessAccess)StandardRights.WriteDac); + } + catch + { + return new ProcessHandle(pid, (ProcessAccess)StandardRights.WriteOwner); + } + } + } + } + } + + private ProcessHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + /// + /// Opens a process. + /// + /// The ID of the process to open. + public ProcessHandle(int pid) + : this(pid, ProcessAccess.All) + { } + + /// + /// Opens a process. + /// + /// The ID of the process to open. + /// The desired access to the process. + public ProcessHandle(int pid, ProcessAccess access) + { + // If we have KPH, use it. + if (KProcessHacker.Instance != null) + { + try + { + this.Handle = new IntPtr(KProcessHacker.Instance.KphOpenProcess(pid, access)); + } + catch (WindowsException) + { + // This would only happen if the process is DRM-protected or if + // some part of ObReferenceObjectByHandle is hooked. We can + // open the process with SYNCHRONIZE access and set the granted access + // using KPH. + this.Handle = new IntPtr(KProcessHacker.Instance.KphOpenProcess(pid, + (ProcessAccess)StandardRights.Synchronize)); + KProcessHacker.Instance.KphSetHandleGrantedAccess(this.Handle, (int)access); + } + } + else + { + this.Handle = Win32.OpenProcess(access, false, pid); + } + + if (this.Handle == IntPtr.Zero) + { + this.MarkAsInvalid(); + Win32.ThrowLastError(); + } + } + + /// + /// Opens a thread's process. + /// + /// A handle to a thread. + /// The desired access to the process. + public ProcessHandle(ThreadHandle threadHandle, ProcessAccess access) + { + if (KProcessHacker.Instance == null) + throw new NotSupportedException(); + + this.Handle = new IntPtr(KProcessHacker.Instance.KphOpenThreadProcess(threadHandle, access)); + } + + /// + /// Opens a process. + /// + /// The name of the process. + /// The flags to use when opening the object. + /// + /// A handle to the directory in which the object is located. + /// + /// A Client ID structure describing the process. + /// The desired access to the process. + public ProcessHandle( + string name, + ObjectFlags objectFlags, + DirectoryHandle rootDirectory, + ClientId clientId, + ProcessAccess access + ) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + // NtOpenProcess fails when both a client ID and a name is specified. + if (name != null) + { + // Name specified, don't specify a CID. + if ((status = Win32.NtOpenProcess( + out handle, + access, + ref oa, + IntPtr.Zero + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + else + { + // No name, specify a CID. + if ((status = Win32.NtOpenProcess( + out handle, + access, + ref oa, + ref clientId + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + } + finally + { + oa.Dispose(); + } + + this.Handle = handle; + } + + /// + /// Opens a process. + /// + /// The name of the process. + /// The desired access to the process. + public ProcessHandle(string name, ProcessAccess access) + : this(name, 0, null, new ClientId(), access) + { } + + /// + /// Opens a process. + /// + /// A Client ID structure describing the process. + /// The desired access to the process. + public ProcessHandle(ClientId clientId, ProcessAccess access) + : this(null, 0, null, clientId, access) + { } + + /// + /// Allocates a memory region in the process' virtual memory. The function decides where + /// to allocate the memory. + /// + /// The size of the region. + /// The protection of the region. + /// The base address of the allocated pages. + public IntPtr AllocateMemory(int size, MemoryProtection protection) + { + return this.AllocateMemory(size, MemoryFlags.Commit, protection); + } + + /// + /// Allocates a memory region in the process' virtual memory. The function decides where + /// to allocate the memory. + /// + /// The size of the region. + /// The type of allocation. + /// The protection of the region. + /// The base address of the allocated pages. + public IntPtr AllocateMemory(int size, MemoryFlags type, MemoryProtection protection) + { + return this.AllocateMemory(IntPtr.Zero, size, type, protection); + } + + /// + /// Allocates a memory region in the process' virtual memory. + /// + /// The base address of the region. + /// The size of the region. + /// The type of allocation. + /// The protection of the region. + /// The base address of the allocated pages. + public IntPtr AllocateMemory(IntPtr baseAddress, int size, MemoryFlags type, MemoryProtection protection) + { + IntPtr sizeIntPtr = new IntPtr(size); + + return this.AllocateMemory(baseAddress, ref sizeIntPtr, type, protection); + } + + /// + /// Allocates a memory region in the process' virtual memory. + /// + /// The base address of the region. + /// + /// The size of the region. This variable will be modified to contain + /// the actual allocated size. + /// + /// The type of allocation. + /// The protection of the region. + /// The base address of the allocated pages. + public IntPtr AllocateMemory(IntPtr baseAddress, ref IntPtr size, MemoryFlags type, MemoryProtection protection) + { + NtStatus status; + + if ((status = Win32.NtAllocateVirtualMemory( + this, + ref baseAddress, + IntPtr.Zero, + ref size, + type, + protection + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return baseAddress; + } + + /// + /// Assigns the process to a job object. The job handle must have the + /// JOB_OBJECT_ASSIGN_PROCESS permission and the process handle must have + /// the PROCESS_SET_QUOTA and PROCESS_TERMINATE permissions. + /// + /// The job object to assign the process to. + public void AssignToJobObject(JobObjectHandle job) + { + if (!Win32.AssignProcessToJobObject(job, this)) + Win32.ThrowLastError(); + } + + /// + /// Creates a thread in the process. + /// + /// The address at which to begin execution. + /// The parameter to pass to the function. + /// A handle to the new thread. + /// This function will work across sessions, unlike CreateThreadWin32. + public ThreadHandle CreateThread(IntPtr startAddress, IntPtr parameter) + { + return this.CreateThread(startAddress, parameter, false); + } + + /// + /// Creates a thread in the process. + /// + /// The address at which to begin execution. + /// The parameter to pass to the function. + /// Whether to create the thread suspended. + /// A handle to the new thread. + /// This function will work across sessions, unlike CreateThreadWin32. + public ThreadHandle CreateThread(IntPtr startAddress, IntPtr parameter, bool createSuspended) + { + int threadId; + + return this.CreateThread(startAddress, parameter, createSuspended, out threadId); + } + + /// + /// Creates a thread in the process. + /// + /// The address at which to begin execution. + /// The parameter to pass to the function. + /// Whether to create the thread suspended. + /// The ID of the new thread. + /// A handle to the new thread. + /// This function will work across sessions, unlike CreateThreadWin32. + public ThreadHandle CreateThread(IntPtr startAddress, IntPtr parameter, bool createSuspended, out int threadId) + { + ClientId cid; + + ThreadHandle thandle = ThreadHandle.CreateUserThread( + this, + createSuspended, + 0, + 0, + startAddress, + parameter, + out cid + ); + + threadId = cid.ThreadId; + + return thandle; + } + + /// + /// Creates a thread in the process and notifies the Win32 subsystem. + /// + /// The address at which to begin execution. + /// The parameter to pass to the function. + /// A handle to the new thread. + public ThreadHandle CreateThreadWin32(IntPtr startAddress, IntPtr parameter) + { + return this.CreateThreadWin32(startAddress, parameter, false); + } + + /// + /// Creates a thread in the process and notifies the Win32 subsystem. + /// + /// The address at which to begin execution. + /// The parameter to pass to the function. + /// Whether to create the thread suspended. + /// A handle to the new thread. + public ThreadHandle CreateThreadWin32(IntPtr startAddress, IntPtr parameter, bool createSuspended) + { + int threadId; + + return this.CreateThreadWin32(startAddress, parameter, createSuspended, out threadId); + } + + /// + /// Creates a thread in the process and notifies the Win32 subsystem. + /// + /// The address at which to begin execution. + /// The parameter to pass to the function. + /// Whether to create the thread suspended. + /// The ID of the new thread. + /// A handle to the new thread. + public ThreadHandle CreateThreadWin32(IntPtr startAddress, IntPtr parameter, bool createSuspended, out int threadId) + { + IntPtr threadHandle; + + if ((threadHandle = Win32.CreateRemoteThread( + this, + IntPtr.Zero, + IntPtr.Zero, + startAddress, + parameter, + createSuspended ? ProcessCreationFlags.CreateSuspended : 0, + out threadId + )) == IntPtr.Zero) + Win32.ThrowLastError(); + + return new ThreadHandle(threadHandle, true); + } + + /// + /// Debugs the process with the specified debug object. This requires + /// PROCESS_SUSPEND_RESUME access. + /// + /// A handle to a debug object. + public void Debug(DebugObjectHandle debugObjectHandle) + { + NtStatus status; + + if ((status = Win32.NtDebugActiveProcess(this, debugObjectHandle)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + /// + /// Disables the collection of handle stack traces. This requires + /// PROCESS_SET_INFORMATION access. Note that this function is only + /// available on Windows Vista and above. + /// + public void DisableHandleTracing() + { + NtStatus status; + + // Length 0 and NULL disables handle tracing. + if ((status = Win32.NtSetInformationProcess( + this, + ProcessInformationClass.ProcessHandleTracing, + IntPtr.Zero, + 0 + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + /// + /// Removes as many pages as possible from the process' working set. This requires the + /// PROCESS_QUERY_INFORMATION and PROCESS_SET_INFORMATION permissions. + /// + public void EmptyWorkingSet() + { + if (!Win32.EmptyWorkingSet(this)) + Win32.ThrowLastError(); + } + + /// + /// Enables the collection of handle stack traces. This requires + /// PROCESS_SET_INFORMATION access. + /// + public void EnableHandleTracing() + { + NtStatus status; + ProcessHandleTracingEnable phte = new ProcessHandleTracingEnable(); + + if ((status = Win32.NtSetInformationProcess( + this, + ProcessInformationClass.ProcessHandleTracing, + ref phte, + Marshal.SizeOf(phte) + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + /// + /// Enumerates the memory regions of the process. + /// + /// The callback for the enumeration. + public void EnumMemory(EnumMemoryDelegate enumMemoryCallback) + { + IntPtr address = IntPtr.Zero; + MemoryBasicInformation mbi = new MemoryBasicInformation(); + int mbiSize = Marshal.SizeOf(mbi); + + while (Win32.VirtualQueryEx(this, address, out mbi, mbiSize) != 0) + { + if (!enumMemoryCallback(mbi)) + break; + + address = address.Increment(mbi.RegionSize); + } + } + + /// + /// Enumerates the modules loaded by the process. + /// + /// The callback for the enumeration. + public void EnumModules(EnumModulesDelegate enumModulesCallback) + { + this.EnumModulesNative(enumModulesCallback); + } + + /// + /// Enumerates the modules loaded by the process using PSAPI. + /// + /// The callback for the enumeration. + private void EnumModulesApi(EnumModulesDelegate enumModulesCallback) + { + IntPtr[] moduleHandles; + int requiredSize; + + Win32.EnumProcessModules(this, null, 0, out requiredSize); + moduleHandles = new IntPtr[requiredSize / 4]; + + if (!Win32.EnumProcessModules(this, moduleHandles, requiredSize, out requiredSize)) + Win32.ThrowLastError(); + + for (int i = 0; i < moduleHandles.Length; i++) + { + ModuleInfo moduleInfo = new ModuleInfo(); + StringBuilder baseName = new StringBuilder(0x400); + StringBuilder fileName = new StringBuilder(0x400); + + if (!Win32.GetModuleInformation(this, moduleHandles[i], moduleInfo, Marshal.SizeOf(moduleInfo))) + Win32.ThrowLastError(); + if (Win32.GetModuleBaseName(this, moduleHandles[i], baseName, baseName.Capacity * 2) == 0) + Win32.ThrowLastError(); + if (Win32.GetModuleFileNameEx(this, moduleHandles[i], fileName, fileName.Capacity * 2) == 0) + Win32.ThrowLastError(); + + if (!enumModulesCallback(new ProcessModule( + moduleInfo.BaseOfDll, moduleInfo.SizeOfImage, moduleInfo.EntryPoint, 0, + baseName.ToString(), FileUtils.GetFileName(fileName.ToString()) + ))) + break; + } + } + + /// + /// Enumerates the modules loaded by the process by reading the NT loader data. + /// + /// The callback for the enumeration. + private unsafe void EnumModulesNative(EnumModulesDelegate enumModulesCallback) + { + byte* buffer = stackalloc byte[IntPtr.Size]; + + // Get the loader data table address. + this.ReadMemory(this.GetBasicInformation().PebBaseAddress.Increment(Peb.LdrOffset), buffer, IntPtr.Size); + + IntPtr loaderData = *(IntPtr*)buffer; + + PebLdrData* data = stackalloc PebLdrData[1]; + // Read the loader data table structure. + this.ReadMemory(loaderData, data, Marshal.SizeOf(typeof(PebLdrData))); + + if (!data->Initialized) + throw new Exception("Loader data is not initialized."); + + IntPtr currentLink = data->InLoadOrderModuleList.Flink; + IntPtr startLink = currentLink; + LdrDataTableEntry* currentEntry = stackalloc LdrDataTableEntry[1]; + int i = 0; + + while (currentLink != IntPtr.Zero) + { + // Stop when we have reached the beginning of the linked list. + if (i > 0 && currentLink == startLink) + break; + // Safety guard. + if (i > 0x800) + break; + + // Read the loader data table entry. + this.ReadMemory(currentLink, currentEntry, Marshal.SizeOf(typeof(LdrDataTableEntry))); + + // Check if the entry is valid. + if (currentEntry->DllBase != IntPtr.Zero) + { + string baseDllName = null; + string fullDllName = null; + + // Read the two strings. + try + { + baseDllName = currentEntry->BaseDllName.Read(this).TrimEnd('\0'); + } + catch + { } + + try + { + fullDllName = FileUtils.GetFileName(currentEntry->FullDllName.Read(this).TrimEnd('\0')); + } + catch + { } + + // Execute the callback. + if (!enumModulesCallback(new ProcessModule( + currentEntry->DllBase, + currentEntry->SizeOfImage, + currentEntry->EntryPoint, + currentEntry->Flags, + baseDllName, + fullDllName + ))) + break; + } + + currentLink = currentEntry->InLoadOrderLinks.Flink; + i++; + } + } + + /// + /// Flushes the process' virtual memory. + /// + /// The base address of the region to flush. + /// The size of the region to flush. + /// A NT status value. + public NtStatus FlushMemory(IntPtr baseAddress, int size) + { + NtStatus status; + IntPtr sizeIntPtr = size.ToIntPtr(); + IoStatusBlock isb; + + if ((status = Win32.NtFlushVirtualMemory( + this, + ref baseAddress, + ref sizeIntPtr, + out isb + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return isb.Status; + } + + /// + /// Frees a memory region in the process' virtual memory. + /// + /// The address of the region to free. + /// The size to free. + public void FreeMemory(IntPtr baseAddress, int size) + { + this.FreeMemory(baseAddress, size, false); + } + + /// + /// Frees a memory region in the process' virtual memory. + /// + /// The address of the region to free. + /// The size to free. + /// Specifies whether or not to only + /// reserve the memory instead of freeing it. + public void FreeMemory(IntPtr baseAddress, int size, bool reserveOnly) + { + NtStatus status; + IntPtr sizeIntPtr = size.ToIntPtr(); + + // Size needs to be 0 if we're freeing. + if (!reserveOnly) + sizeIntPtr = IntPtr.Zero; + + if ((status = Win32.NtFreeVirtualMemory( + this, + ref baseAddress, + ref sizeIntPtr, + reserveOnly ? MemoryFlags.Decommit : MemoryFlags.Release + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + /// + /// Gets the processor affinity for the process. + /// + /// The processor affinity for the process. + public long GetAffinityMask() + { + long systemMask; + + return this.GetAffinityMask(out systemMask); + } + + /// + /// Gets the processor affinity for the process. + /// + /// Receives the processor affinity mask for the system. + /// The processor affinity for the process. + public long GetAffinityMask(out long systemMask) + { + IntPtr processMaskTemp; + IntPtr systemMaskTemp; + + if (!Win32.GetProcessAffinityMask(this, out processMaskTemp, out systemMaskTemp)) + Win32.ThrowLastError(); + + systemMask = systemMaskTemp.ToInt64(); + + return processMaskTemp.ToInt64(); + } + + /// + /// Gets the base priority of the process. + /// + public int GetBasePriority() + { + return this.GetInformationInt32(ProcessInformationClass.ProcessBasePriority); + } + + /// + /// Gets the process' basic information. This requires QueryLimitedInformation + /// access. + /// + /// A PROCESS_BASIC_INFORMATION structure. + public ProcessBasicInformation GetBasicInformation() + { + NtStatus status; + ProcessBasicInformation pbi; + int retLen; + + if ((status = Win32.NtQueryInformationProcess(this, ProcessInformationClass.ProcessBasicInformation, + out pbi, Marshal.SizeOf(typeof(ProcessBasicInformation)), out retLen)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return pbi; + } + + /// + /// Gets the command line used to start the process. This requires + /// the PROCESS_QUERY_LIMITED_INFORMATION and PROCESS_VM_READ permissions. + /// + /// A string. + public string GetCommandLine() + { + if (!this.IsPosix()) + return this.GetPebString(PebOffset.CommandLine); + else + return this.GetPosixCommandLine(); + } + + /// + /// Gets the process' cookie (a random value). + /// + public int GetCookie() + { + return this.GetInformationInt32(ProcessInformationClass.ProcessCookie); + } + + /// + /// Gets the creation time of the process. + /// + public DateTime GetCreateTime() + { + return DateTime.FromFileTime(this.GetTimes()[0]); + } + + /// + /// Gets the number of processor cycles consumed by the process' threads. + /// + public ulong GetCycleTime() + { + ulong cycles; + + if (!Win32.QueryProcessCycleTime(this, out cycles)) + Win32.ThrowLastError(); + + return cycles; + } + + /// + /// Opens the debug object associated with the process. + /// + /// A debug object handle. + public DebugObjectHandle GetDebugObject() + { + IntPtr handle; + + handle = this.GetDebugObjectHandle(); + + // Check if we got a handle. If we didn't the process is not being debugged. + if (handle == IntPtr.Zero) + return null; + + return new DebugObjectHandle(handle, true); + } + + internal IntPtr GetDebugObjectHandle() + { + return this.GetInformationIntPtr(ProcessInformationClass.ProcessDebugObjectHandle); + } + + /// + /// Gets the process' DEP policy. + /// + /// A DepStatus enum. + public DepStatus GetDepStatus() + { + MemExecuteOptions options; + + // If we're on 64-bit and the process isn't under + // WOW64, it must be under permanent DEP. + if (IntPtr.Size == 8) + { + if (!this.IsWow64()) + return DepStatus.Enabled | DepStatus.Permanent; + } + + options = (MemExecuteOptions)this.GetInformationInt32(ProcessInformationClass.ProcessExecuteFlags); + + DepStatus depStatus = 0; + + // Check if execution of data pages is enabled. + if ((options & MemExecuteOptions.ExecuteEnable) == MemExecuteOptions.ExecuteEnable) + return 0; + + // Check if execution of data pages is disabled. + if ((options & MemExecuteOptions.ExecuteDisable) == MemExecuteOptions.ExecuteDisable) + depStatus = DepStatus.Enabled; + // ExecuteDisable and ExecuteEnable are both disabled in OptOut mode. + else if ((options & MemExecuteOptions.ExecuteDisable) == 0 && + (options & MemExecuteOptions.ExecuteEnable) == 0) + depStatus = DepStatus.Enabled; + + if ((options & MemExecuteOptions.DisableThunkEmulation) == MemExecuteOptions.DisableThunkEmulation) + depStatus |= DepStatus.AtlThunkEmulationDisabled; + if ((options & MemExecuteOptions.Permanent) == MemExecuteOptions.Permanent) + depStatus |= DepStatus.Permanent; + + return depStatus; + } + + /// + /// Gets the process' environment variables. This requires the + /// PROCESS_QUERY_INFORMATION and PROCESS_VM_READ permissions. + /// + /// A dictionary of variables. + public unsafe IDictionary GetEnvironmentVariables() + { + IntPtr pebBaseAddress = this.GetBasicInformation().PebBaseAddress; + byte* buffer = stackalloc byte[IntPtr.Size]; + + // Get a pointer to the process parameters block. + this.ReadMemory(pebBaseAddress.Increment(Peb.ProcessParametersOffset), buffer, IntPtr.Size); + IntPtr processParameters = *(IntPtr*)buffer; + + // Get a pointer to the environment block. + this.ReadMemory(processParameters.Increment(RtlUserProcessParameters.EnvironmentOffset), buffer, IntPtr.Size); + IntPtr envBase = *(IntPtr*)buffer; + int length = 0; + + { + MemoryBasicInformation mbi = this.QueryMemory(envBase); + + if (mbi.Protect == MemoryProtection.NoAccess) + throw new WindowsException(); + + length = mbi.RegionSize.Decrement(envBase.Decrement(mbi.BaseAddress)).ToInt32(); + } + + // Now we read in the entire region of memory + // And yes, some memory is wasted. + byte[] memory = this.ReadMemory(envBase, length); + + /* The environment variables block is a series of Unicode strings separated by + * two null bytes. The entire block is terminated by four null bytes. + */ + Dictionary vars = new Dictionary(); + StringBuilder currentVariable = new StringBuilder(); + int i = 0; + + while (true) + { + if (i >= memory.Length) + break; + + char currentChar = + UnicodeEncoding.Unicode.GetChars(memory, i, 2)[0]; + + i += 2; + + if (currentChar == '\0') + { + // Two nulls in a row, the env. block is finished. + if (currentVariable.Length == 0) + break; + + string[] s = currentVariable.ToString().Split(new char[] { '=' }, 2); + + if (!vars.ContainsKey(s[0]) && s.Length > 1) + vars.Add(s[0], s[1]); + + currentVariable = new StringBuilder(); + } + else + { + currentVariable.Append(currentChar); + } + } + + return vars; + } + + /// + /// Gets the process' exit code. + /// + /// A number. + public int GetExitCode() + { + int exitCode; + + if (!Win32.GetExitCodeProcess(this, out exitCode)) + Win32.ThrowLastError(); + + return exitCode; + } + + /// + /// Gets the process' exit status. + /// + /// A NT status value. + public NtStatus GetExitStatus() + { + return this.GetBasicInformation().ExitStatus; + } + + /// + /// Gets the exit time of the process. + /// + public DateTime GetExitTime() + { + return DateTime.FromFileTime(this.GetTimes()[1]); + } + + /// + /// Gets a GUI handle count. + /// + /// If true, returns the number of USER handles. Otherwise, returns + /// the number of GDI handles. + /// A handle count. + public int GetGuiResources(bool userObjects) + { + return Win32.GetGuiResources(this, userObjects ? 1 : 0); + } + + /// + /// Gets the number of handles opened by the process. + /// + public int GetHandleCount() + { + return this.GetInformationInt32(ProcessInformationClass.ProcessHandleCount); + } + + /// + /// Gets the handles owned by the process. + /// + /// An array of handle information structures. + public ProcessHandleInformation[] GetHandles() + { + int returnLength = 0; + int attempts = 0; + + using (var data = new MemoryAlloc(0x1000)) + { + while (true) + { + try + { + KProcessHacker.Instance.KphQueryProcessHandles(this, data, data.Size, out returnLength); + } + catch (WindowsException ex) + { + if (attempts > 3) + throw ex; + + if ( + ex.Status == NtStatus.BufferTooSmall && + returnLength > data.Size + ) + data.Resize(returnLength); + + attempts++; + + continue; + } + + int handleCount = data.ReadInt32(0); + ProcessHandleInformation[] handles = new ProcessHandleInformation[handleCount]; + + for (int i = 0; i < handleCount; i++) + handles[i] = data.ReadStruct(sizeof(int), i); + + return handles; + } + } + } + + /// + /// Gets a collection of handle stack traces. This requires + /// PROCESS_QUERY_INFORMATION access. + /// + /// A collection of handle stack traces. + public ProcessHandleTraceCollection GetHandleTraces() + { + return this.GetHandleTraces(IntPtr.Zero); + } + + /// + /// Gets a collection of handle stack traces. This requires + /// PROCESS_QUERY_INFORMATION access. + /// + /// + /// A handle to the stack trace to retrieve. If this parameter is + /// zero, all stack traces will be retrieved. + /// + /// A collection of handle stack traces. + public ProcessHandleTraceCollection GetHandleTraces(IntPtr handle) + { + NtStatus status = NtStatus.Success; + int retLength; + + using (var data = new MemoryAlloc(0x10000)) + { + var query = new ProcessHandleTracingQuery(); + + // If Handle is not NULL, NtQueryInformationProcess will + // get a specific stack trace. Otherwise, it will get + // all of the stack traces. + query.Handle = handle; + data.WriteStruct(query); + + for (int i = 0; i < 8; i++) + { + status = Win32.NtQueryInformationProcess( + this, + ProcessInformationClass.ProcessHandleTracing, + data, + data.Size, + out retLength + ); + + if (status == NtStatus.InfoLengthMismatch) + { + data.Resize(data.Size * 4); + continue; + } + + if (status >= NtStatus.Error) + Win32.ThrowLastError(status); + + return new ProcessHandleTraceCollection(data); + } + + Win32.ThrowLastError(status); + return null; // Silences the compiler. + } + } + + /// + /// Gets the process' default heap. + /// + /// A pointer to a heap. + public unsafe IntPtr GetHeap() + { + IntPtr heap; + + this.ReadMemory( + this.GetBasicInformation().PebBaseAddress.Increment(Peb.ProcessHeapOffset), + &heap, + IntPtr.Size + ); + + return heap; + } + + /// + /// Gets the file name of the process' image. This requires + /// QueryLimitedInformation access. + /// + /// A file name, in native format. + public string GetImageFileName() + { + return this.GetInformationUnicodeString(ProcessInformationClass.ProcessImageFileName); + } + + /// + /// Gets the file name of the process' image. This requires + /// QueryLimitedInformation access. + /// + /// A file name, in DOS format. + public string GetImageFileNameWin32() + { + return this.GetInformationUnicodeString(ProcessInformationClass.ProcessImageFileNameWin32); + } + + /// + /// Gets information about the process in an Int32. + /// + /// The class of information to retrieve. + /// An int. + private int GetInformationInt32(ProcessInformationClass infoClass) + { + NtStatus status; + int value; + int retLength; + + if ((status = Win32.NtQueryInformationProcess( + this, infoClass, out value, sizeof(int), out retLength)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return value; + } + + /// + /// Gets information about the process in an IntPtr. + /// + /// The class of information to retrieve. + /// An IntPtr. + private IntPtr GetInformationIntPtr(ProcessInformationClass infoClass) + { + NtStatus status; + IntPtr value; + int retLength; + + if ((status = Win32.NtQueryInformationProcess( + this, infoClass, out value, IntPtr.Size, out retLength)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return value; + } + + private string GetInformationUnicodeString(ProcessInformationClass infoClass) + { + NtStatus status; + int retLen; + + Win32.NtQueryInformationProcess(this, infoClass, IntPtr.Zero, 0, out retLen); + + using (MemoryAlloc data = new MemoryAlloc(retLen)) + { + if ((status = Win32.NtQueryInformationProcess(this, infoClass, data, retLen, out retLen)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return data.ReadStruct().Read(); + } + } + + /// + /// Gets the process' I/O priority, ranging from 0-7. + /// + /// + public int GetIoPriority() + { + return this.GetInformationInt32(ProcessInformationClass.ProcessIoPriority); + } + + /// + /// Gets I/O statistics for the process. + /// + /// A IoCounters structure. + public IoCounters GetIoStatistics() + { + NtStatus status; + IoCounters counters; + int retLength; + + if ((status = Win32.NtQueryInformationProcess( + this, + ProcessInformationClass.ProcessIoCounters, + out counters, + Marshal.SizeOf(typeof(IoCounters)), + out retLength + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return counters; + } + + /// + /// Opens the job object associated with the process. + /// + /// A job object handle. + public JobObjectHandle GetJobObject(JobObjectAccess access) + { + try + { + return new JobObjectHandle(this, access); + } + catch (WindowsException ex) + { + if (ex.Status == NtStatus.ProcessNotInJob) + return null; + else + throw ex; + } + } + + /// + /// Gets the type of well-known process. + /// + /// A known process type. + public KnownProcess GetKnownProcessType() + { + if (this.GetBasicInformation().UniqueProcessId.Equals(4)) + return KnownProcess.System; + + string fileName = FileUtils.GetFileName(this.GetImageFileName()); + + if (fileName.ToLower().StartsWith(Environment.SystemDirectory.ToLower())) + { + string baseName = fileName.Remove(0, Environment.SystemDirectory.Length).TrimStart('\\').ToLower(); + + switch (baseName) + { + case "smss.exe": + return KnownProcess.SessionManager; + case "csrss.exe": + return KnownProcess.WindowsSubsystem; + case "wininit.exe": + return KnownProcess.WindowsStartup; + case "services.exe": + return KnownProcess.ServiceControlManager; + case "lsass.exe": + return KnownProcess.LocalSecurityAuthority; + case "lsm.exe": + return KnownProcess.LocalSessionManager; + default: + return KnownProcess.None; + } + } + else + { + return KnownProcess.None; + } + } + + /// + /// Gets the main module of the process. This requires the + /// PROCESS_QUERY_INFORMATION and PROCESS_VM_READ permissions. + /// + /// A ProcessModule. + public ProcessModule GetMainModule() + { + ProcessModule mainModule = null; + + this.EnumModules((module) => + { + mainModule = module; + return false; + }); + + return mainModule; + } + + /// + /// Gets the name of a file which the process has mapped. + /// + /// The address of the mapped section. + /// A filename. + public string GetMappedFileName(IntPtr address) + { + StringBuilder sb = new StringBuilder(0x400); + int length = Win32.GetMappedFileName(this, address, sb, sb.Capacity); + + if (length > 0) + { + string fileName = sb.ToString(0, length); + + return FileUtils.GetFileName(fileName, true); + } + + return null; + } + + /// + /// Gets memory statistics for the process. + /// + /// A VmCounters structure. + public VmCounters GetMemoryStatistics() + { + NtStatus status; + VmCounters counters; + int retLength; + + if ((status = Win32.NtQueryInformationProcess( + this, + ProcessInformationClass.ProcessVmCounters, + out counters, + Marshal.SizeOf(typeof(VmCounters)), + out retLength + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return counters; + } + + /// + /// Gets the modules loaded by the process. This requires the + /// PROCESS_QUERY_INFORMATION and PROCESS_VM_READ permissions. + /// + /// An array of ProcessModule objects. + public ProcessModule[] GetModules() + { + List modules = new List(); + + this.EnumModules((module) => + { + modules.Add(module); + return true; + }); + + return modules.ToArray(); + } + + /// + /// Opens the next linked process. + /// + /// The desired access to the next process. + /// A process handle. + public ProcessHandle GetNextProcess(ProcessAccess access) + { + NtStatus status; + IntPtr handle; + + if ((status = Win32.NtGetNextProcess( + this, + access, + 0, + 0, + out handle + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + if (handle != IntPtr.Zero) + return new ProcessHandle(handle, true); + else + return null; + } + + /// + /// Opens the next linked thread belonging to the process. + /// + /// A thread handle. You may specify null. + /// The desired access to the next thread. + /// A thread handle. + public ThreadHandle GetNextThread(ThreadHandle threadHandle, ThreadAccess access) + { + NtStatus status; + IntPtr handle; + + if ((status = Win32.NtGetNextThread( + this, + threadHandle != null ? threadHandle : IntPtr.Zero, + access, + 0, + 0, + out handle + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + if (handle != IntPtr.Zero) + return new ThreadHandle(handle, true); + else + return null; + } + + /// + /// Gets the process' page priority, ranging from 0-7. + /// + public int GetPagePriority() + { + return this.GetInformationInt32(ProcessInformationClass.ProcessPagePriority); + } + + /// + /// Gets the process' parent's process ID. This requires + /// the PROCESS_QUERY_LIMITED_INFORMATION permission. + /// + /// The process ID. + public int GetParentPid() + { + return this.GetBasicInformation().InheritedFromUniqueProcessId.ToInt32(); + } + + /// + /// Reads a UNICODE_STRING from the process' process environment block. + /// + /// The offset to the UNICODE_STRING structure. + /// A string. + public unsafe string GetPebString(PebOffset offset) + { + byte* buffer = stackalloc byte[IntPtr.Size]; + IntPtr pebBaseAddress = this.GetBasicInformation().PebBaseAddress; + + // Read the address of parameter information block. + this.ReadMemory(pebBaseAddress.Increment(Peb.ProcessParametersOffset), buffer, IntPtr.Size); + IntPtr processParameters = *(IntPtr*)buffer; + + // The offset of the UNICODE_STRING structure is specified in the enum. + int realOffset = GetPebOffset(offset); + + // Read the UNICODE_STRING structure. + UnicodeString pebStr; + + this.ReadMemory(processParameters.Increment(realOffset), &pebStr, Marshal.SizeOf(typeof(UnicodeString))); + + // read string and decode it + return UnicodeEncoding.Unicode.GetString( + this.ReadMemory(pebStr.Buffer, pebStr.Length), 0, pebStr.Length); + } + + /// + /// Gets the command line used to start the process. This + /// function is only valid for POSIX processes. + /// + /// A command line string. + public unsafe string GetPosixCommandLine() + { + byte* buffer = stackalloc byte[IntPtr.Size]; + IntPtr pebBaseAddress = this.GetBasicInformation().PebBaseAddress; + + this.ReadMemory(pebBaseAddress.Increment(Peb.ProcessParametersOffset), buffer, IntPtr.Size); + IntPtr processParameters = *(IntPtr*)buffer; + + // Read the command line UNICODE_STRING structure. + UnicodeString commandLineUs; + + this.ReadMemory( + processParameters.Increment(GetPebOffset(PebOffset.CommandLine)), + &commandLineUs, + Marshal.SizeOf(typeof(UnicodeString)) + ); + IntPtr stringAddr = commandLineUs.Buffer; + + /* + * In the POSIX subsystem the command line is actually split up into bits, as in + * argv. In the command line string we don't actually have the command line - + * instead, it is filled with pointers to each command line part. For example: + * CommandLine.Buffer = 0x12345678 + * at 0x12345678 we have: + * 0x12346000 0x12347000 0x12348000 0x00000000 0x12349000 + * ^ at 0x12346000: "cat" (ASCII) + * ^ at 0x12347000: "-o" (ASCII) + * ^ at 0x12348000: "myfile" (ASCII) + * ^ signifies that there are no more pointers + * ^ pointer to environment block + * - from this we can work out + * how much memory to read + */ + // Get the list of pointers. + List strPointers = new List(); + bool zeroReached = false; + int i = 0; + + while (true) + { + this.ReadMemory(stringAddr.Increment(i), buffer, IntPtr.Size); + IntPtr value = *(IntPtr*)buffer; + + if (value != IntPtr.Zero) + strPointers.Add(value); + + i += IntPtr.Size; + + if (zeroReached) + break; + else if (value == IntPtr.Zero) + zeroReached = true; + } + + // Work out the size of the command line and read the data. + IntPtr lastPointer = strPointers[strPointers.Count - 1]; + int partsSize = lastPointer.Decrement(strPointers[0]).ToInt32(); + + // FIXME: Lazy; optimize later. + StringBuilder commandLine = new StringBuilder(); + + for (i = 0; i < strPointers.Count - 1; i++) + { + byte[] data = this.ReadMemory(strPointers[i], partsSize); + + commandLine.Append(ASCIIEncoding.ASCII.GetString(data, 0, Array.IndexOf(data, 0)) + " "); + } + + string commandLineStr = commandLine.ToString(); + + if (commandLineStr.EndsWith(" ")) + commandLineStr = commandLineStr.Remove(commandLineStr.Length - 1, 1); + + return commandLineStr; + } + + /// + /// Gets the process' priority class. + /// + /// A ProcessPriorityClass enum. + public ProcessPriorityClass GetPriorityClass() + { + switch (Win32.GetPriorityClass(this)) + { + case ProcessPriorityClassWin32.AboveNormal: + return ProcessPriorityClass.AboveNormal; + case ProcessPriorityClassWin32.BelowNormal: + return ProcessPriorityClass.BelowNormal; + case ProcessPriorityClassWin32.High: + return ProcessPriorityClass.High; + case ProcessPriorityClassWin32.Idle: + return ProcessPriorityClass.Idle; + case ProcessPriorityClassWin32.Normal: + return ProcessPriorityClass.Normal; + case ProcessPriorityClassWin32.RealTime: + return ProcessPriorityClass.RealTime; + default: + Win32.ThrowLastError(); + // Stupid compiler + return ProcessPriorityClass.Unknown; + } + + // Datatype misalignment on x64 + + //NtStatus status; + //ProcessPriorityClassStruct priorityClass; + //int retLength; + + //if ((status = Win32.NtQueryInformationProcess( + // this, + // ProcessInformationClass.ProcessPriorityClass, + // out priorityClass, + // Marshal.SizeOf(typeof(ProcessPriorityClassStruct)), + // out retLength + // )) >= NtStatus.Error) + // Win32.ThrowLastError(status); + + //return priorityClass.PriorityClass; + } + + /// + /// Gets the process' unique identifier. + /// + public int GetProcessId() + { + return this.GetBasicInformation().UniqueProcessId.ToInt32(); + } + + /// + /// Gets the process' session ID. + /// + public int GetSessionId() + { + return this.GetInformationInt32(ProcessInformationClass.ProcessSessionInformation); + } + + /// + /// Gets an array of times for the process. + /// + /// An array of times: creation time, exit time, kernel time, user time. + private LargeInteger[] GetTimes() + { + LargeInteger[] times = new LargeInteger[4]; + + if (!Win32.GetProcessTimes(this, out times[0], out times[1], out times[2], out times[3])) + Win32.ThrowLastError(); + + return times; + } + + /// + /// Opens and returns a handle to the process' token. This requires + /// PROCESS_QUERY_LIMITED_INFORMATION access. + /// + /// A handle to the process' token. + public TokenHandle GetToken() + { + return this.GetToken(TokenAccess.All); + } + + /// + /// Opens and returns a handle to the process' token. This requires + /// PROCESS_QUERY_LIMITED_INFORMATION access. + /// + /// The desired access to the token. + /// A handle to the process' token. + public TokenHandle GetToken(TokenAccess access) + { + return new TokenHandle(this, access); + } + + /// + /// Forces the process to load the specified library. + /// + /// The path to the library. + public void InjectDll(string path) + { + this.InjectDll(path, 0xffffffff); + } + + /// + /// Forces the process to load the specified library. + /// + /// The path to the library. + /// The timeout, in milliseconds, for the process to load the library. + public void InjectDll(string path, uint timeout) + { + IntPtr stringPage = this.AllocateMemory(path.Length * 2 + 2, MemoryProtection.ReadWrite); + + this.WriteMemory(stringPage, UnicodeEncoding.Unicode.GetBytes(path)); + + // Vista seems to support non-Win32 threads better than XP can. + if (OSVersion.IsAboveOrEqual(WindowsVersion.Vista)) + { + using (var thandle = this.CreateThread( + Loader.GetProcedure("kernel32.dll", "LoadLibraryW"), + stringPage + )) + thandle.Wait(timeout * Win32.TimeMsTo100Ns); + } + else + { + using (var thandle = this.CreateThreadWin32( + Loader.GetProcedure("kernel32.dll", "LoadLibraryW"), + stringPage + )) + thandle.Wait(timeout * Win32.TimeMsTo100Ns); + } + + this.FreeMemory(stringPage, path.Length * 2 + 2, false); + } + + /// + /// Gets whether the process is currently being debugged. This requires + /// QueryInformation access. + /// + public bool IsBeingDebugged() + { + return this.GetInformationIntPtr(ProcessInformationClass.ProcessDebugPort) != IntPtr.Zero; + } + + /// + /// Gets whether the system will crash upon the process being terminated. + /// + public bool IsCritical() + { + return this.GetInformationInt32(ProcessInformationClass.ProcessBreakOnTermination) != 0; + } + + /// + /// Determines whether the process is running in a job. + /// + /// A boolean. + public bool IsInJob() + { + bool result; + + if (!Win32.IsProcessInJob(this, IntPtr.Zero, out result)) + Win32.ThrowLastError(); + + return result; + } + + /// + /// Determines whether the process is running in the specified job. + /// + /// The job object to check. + /// A boolean. + public bool IsInJob(JobObjectHandle jobObjectHandle) + { + bool result; + + if (!Win32.IsProcessInJob(this, jobObjectHandle, out result)) + Win32.ThrowLastError(); + + return result; + } + + /// + /// Gets whether the process is a NTVDM process. + /// + public bool IsNtVdmProcess() + { + return this.GetInformationInt32(ProcessInformationClass.ProcessWx86Information) != 0; + } + + /// + /// Gets whether the process is using the POSIX subsystem. + /// + public unsafe bool IsPosix() + { + int subsystem; + IntPtr pebBaseAddress = this.GetBasicInformation().PebBaseAddress; + + this.ReadMemory(pebBaseAddress.Increment(Peb.ImageSubsystemOffset), &subsystem, sizeof(int)); + + return subsystem == 7; + } + + /// + /// Gets whether the process has priority boost enabled. + /// + public bool IsPriorityBoostEnabled() + { + return this.GetInformationInt32(ProcessInformationClass.ProcessPriorityBoost) == 0; + } + + /// + /// Gets whether the process is running under WOW64. + /// + public bool IsWow64() + { + return this.GetInformationIntPtr(ProcessInformationClass.ProcessWow64Information) != IntPtr.Zero; + } + + /// + /// Sets the protection for a page in the process. + /// + /// The address to modify. + /// The number of bytes to modify. + /// The new memory protection. + /// The old memory protection. + public MemoryProtection ProtectMemory(IntPtr baseAddress, int size, MemoryProtection protection) + { + NtStatus status; + IntPtr sizeIntPtr = size.ToIntPtr(); + MemoryProtection oldProtection; + + if ((status = Win32.NtProtectVirtualMemory( + this, + ref baseAddress, + ref sizeIntPtr, + protection, + out oldProtection + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return oldProtection; + } + + /// + /// Gets information about the memory region starting at the specified address. + /// + /// The address to query. + /// A MEMORY_BASIC_INFORMATION structure. + public MemoryBasicInformation QueryMemory(IntPtr baseAddress) + { + NtStatus status; + MemoryBasicInformation mbi; + IntPtr retLength; + + if ((status = Win32.NtQueryVirtualMemory( + this, + baseAddress, + MemoryInformationClass.MemoryBasicInformation, + out mbi, + Marshal.SizeOf(typeof(MemoryBasicInformation)).ToIntPtr(), + out retLength + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return mbi; + } + + /// + /// Reads data from the process' virtual memory. + /// + /// The offset at which to begin reading. + /// The length, in bytes, to read. + /// An array of bytes. + public byte[] ReadMemory(IntPtr baseAddress, int length) + { + byte[] buffer = new byte[length]; + + this.ReadMemory(baseAddress, buffer, length); + + return buffer; + } + + /// + /// Reads data from the process' virtual memory. + /// + /// The offset at which to begin reading. + /// The buffer to write to. + /// The length to read. + /// The number of bytes read. + public unsafe int ReadMemory(IntPtr baseAddress, byte[] buffer, int length) + { + fixed (byte* bufferPtr = buffer) + return this.ReadMemory(baseAddress, bufferPtr, length); + } + + /// + /// Reads data from the process' virtual memory. + /// + /// The offset at which to begin reading. + /// The buffer to write to. + /// The length to read. + /// The number of bytes read. + public unsafe int ReadMemory(IntPtr baseAddress, void* buffer, int length) + { + return this.ReadMemory(baseAddress, new IntPtr(buffer), length); + } + + /// + /// Reads data from the process' virtual memory. + /// + /// The offset at which to begin reading. + /// The buffer to write to. + /// The length to read. + /// The number of bytes read. + public int ReadMemory(IntPtr baseAddress, IntPtr buffer, int length) + { + int retLength; + + if (this.Handle == Current) + { + Win32.RtlMoveMemory(buffer, baseAddress, length.ToIntPtr()); + return length; + } + + if (KProcessHacker.Instance != null) + { + KProcessHacker.Instance.KphReadVirtualMemory(this, baseAddress.ToInt32(), buffer, length, out retLength); + } + else + { + NtStatus status; + IntPtr retLengthIntPtr; + + if ((status = Win32.NtReadVirtualMemory( + this, + baseAddress, + buffer, + length.ToIntPtr(), + out retLengthIntPtr + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + retLength = retLengthIntPtr.ToInt32(); + } + + return retLength; + } + + /// + /// Calls the specified function in the context of the process. + /// + /// The function to call. + /// The arguments to pass to the function. + public ThreadHandle RemoteCall(IntPtr address, IntPtr[] arguments) + { + IntPtr rtlExitUserThread = Loader.GetProcedure("ntdll.dll", "RtlExitUserThread"); + + // Create a suspended thread at RtlExitUserThread. + var thandle = this.CreateThread(rtlExitUserThread, IntPtr.Zero, true); + + // Do the remote call on this thread. + thandle.RemoteCall(this, address, arguments, true); + // Resume the thread. It will execute the remote call then exit. + thandle.Resume(); + + return thandle; + } + + /// + /// Stops debugging the process attached to the specified debug object. This requires + /// PROCESS_SUSPEND_RESUME access. + /// + /// The debug object which was used to debug the process. + public void RemoveDebug(DebugObjectHandle debugObjectHandle) + { + NtStatus status; + + if ((status = Win32.NtRemoveProcessDebug(this, debugObjectHandle)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + /// + /// Resumes the process. This requires PROCESS_SUSPEND_RESUME access. + /// + public void Resume() + { + if (KProcessHacker.Instance != null && OSVersion.HasPsSuspendResumeProcess) + { + KProcessHacker.Instance.KphResumeProcess(this); + } + else + { + NtStatus status; + + if ((status = Win32.NtResumeProcess(this)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + } + + /// + /// Sets the processor affinity for the process. + /// + /// The processor affinity mask. + public void SetAffinityMask(long processMask) + { + if (!Win32.SetProcessAffinityMask(this, new IntPtr(processMask))) + Win32.ThrowLastError(); + } + + /// + /// Sets the process' base priority. + /// + /// The process' base priority. + public void SetBasePriority(int basePriority) + { + this.SetInformationInt32(ProcessInformationClass.ProcessBasePriority, basePriority); + } + + /// + /// Sets whether the system will crash upon the process being terminated. + /// This function requires SeTcbPrivilege. + /// + /// Whether the system will crash upon the process being terminated. + public void SetCritical(bool critical) + { + this.SetInformationInt32(ProcessInformationClass.ProcessBreakOnTermination, critical ? 1 : 0); + } + + /// + /// Sets the process' DEP policy. + /// + /// The DEP options. + public void SetDepStatus(DepStatus depStatus) + { + MemExecuteOptions executeOptions = 0; + + if ((depStatus & DepStatus.Enabled) == DepStatus.Enabled) + executeOptions |= MemExecuteOptions.ExecuteDisable; + else + executeOptions |= MemExecuteOptions.ExecuteEnable; + + if ((depStatus & DepStatus.AtlThunkEmulationDisabled) == DepStatus.AtlThunkEmulationDisabled) + executeOptions |= MemExecuteOptions.DisableThunkEmulation; + if ((depStatus & DepStatus.Permanent) == DepStatus.Permanent) + executeOptions |= MemExecuteOptions.Permanent; + + KProcessHacker.Instance.SetExecuteOptions(this, executeOptions); + } + + /// + /// Sets information about the process in an Int32. + /// + /// The class of information to set. + /// The value to set. + private void SetInformationInt32(ProcessInformationClass infoClass, int value) + { + NtStatus status; + + if ((status = Win32.NtSetInformationProcess( + this, infoClass, ref value, sizeof(int))) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + /// + /// Sets the reference count of a module. + /// + /// The base address of the module. + /// The new reference count. + public unsafe void SetModuleReferenceCount(IntPtr baseAddress, ushort count) + { + byte* buffer = stackalloc byte[IntPtr.Size]; + + this.ReadMemory( + this.GetBasicInformation().PebBaseAddress.Increment(Peb.LdrOffset), + buffer, + IntPtr.Size + ); + + IntPtr loaderData = *(IntPtr*)buffer; + + PebLdrData* data = stackalloc PebLdrData[1]; + this.ReadMemory(loaderData, data, Marshal.SizeOf(typeof(PebLdrData))); + + if (!data->Initialized) + throw new Exception("Loader data is not initialized."); + + List modules = new List(); + IntPtr currentLink = data->InLoadOrderModuleList.Flink; + IntPtr startLink = currentLink; + LdrDataTableEntry* currentEntry = stackalloc LdrDataTableEntry[1]; + int i = 0; + + while (currentLink != IntPtr.Zero) + { + if (modules.Count > 0 && currentLink == startLink) + break; + if (i > 0x800) + break; + + this.ReadMemory(currentLink, currentEntry, Marshal.SizeOf(typeof(LdrDataTableEntry))); + + if (currentEntry->DllBase == baseAddress) + { + this.WriteMemory(currentLink.Increment(LdrDataTableEntry.LoadCountOffset), &count, 2); + break; + } + + currentLink = currentEntry->InLoadOrderLinks.Flink; + i++; + } + } + + /// + /// Sets the process' priority boost. + /// + /// Whether priority boost will be enabled. + public void SetPriorityBoost(bool enabled) + { + // If priority boost is being enabled, we have to not disable it (hence the value of 0). + this.SetInformationInt32(ProcessInformationClass.ProcessPriorityBoost, enabled ? 0 : 1); + } + + /// + /// Sets the process' priority class. + /// + /// The process' priority class. + public void SetPriorityClass(ProcessPriorityClass priorityClass) + { + ProcessPriorityClassWin32 pcWin32; + + switch (priorityClass) + { + case ProcessPriorityClass.AboveNormal: + pcWin32 = ProcessPriorityClassWin32.AboveNormal; + break; + case ProcessPriorityClass.BelowNormal: + pcWin32 = ProcessPriorityClassWin32.BelowNormal; + break; + case ProcessPriorityClass.High: + pcWin32 = ProcessPriorityClassWin32.High; + break; + case ProcessPriorityClass.Idle: + pcWin32 = ProcessPriorityClassWin32.Idle; + break; + case ProcessPriorityClass.Normal: + pcWin32 = ProcessPriorityClassWin32.Normal; + break; + case ProcessPriorityClass.RealTime: + pcWin32 = ProcessPriorityClassWin32.RealTime; + break; + default: + throw new ArgumentException("priorityClass"); + } + + if (!Win32.SetPriorityClass(this, pcWin32)) + Win32.ThrowLastError(); + + // Datatype misalignment on x64. + //NtStatus status; + //ProcessPriorityClassStruct processPriority; + + //processPriority.Foreground = false; + //processPriority.PriorityClass = priorityClass; + + //if ((status = Win32.NtSetInformationProcess( + // this, + // ProcessInformationClass.ProcessPriorityClass, + // ref processPriority, + // Marshal.SizeOf(typeof(ProcessPriorityClassStruct)) + // )) >= NtStatus.Error) + // Win32.ThrowLastError(status); + } + + /// + /// Suspends the process. This requires PROCESS_SUSPEND_RESUME access. + /// + public void Suspend() + { + if (KProcessHacker.Instance != null && OSVersion.HasPsSuspendResumeProcess) + { + KProcessHacker.Instance.KphSuspendProcess(this); + } + else + { + NtStatus status; + + if ((status = Win32.NtSuspendProcess(this)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + } + + /// + /// Terminates the process. This requires PROCESS_TERMINATE access. + /// + public void Terminate() + { + this.Terminate(NtStatus.Success); + } + + /// + /// Terminates the process. This requires PROCESS_TERMINATE access. + /// + /// The exit status. + public void Terminate(NtStatus exitStatus) + { + if (KProcessHacker.Instance != null) + { + KProcessHacker.Instance.KphTerminateProcess(this, exitStatus); + } + else + { + NtStatus status; + + if ((status = Win32.NtTerminateProcess(this, exitStatus)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + } + + /// + /// Writes a minidump of the process to the specified file. + /// + /// The destination file. + public void WriteDump(string fileName) + { + // taskmgr uses these flags + this.WriteDump(fileName, + MinidumpType.WithFullMemory | + MinidumpType.WithHandleData | + MinidumpType.WithUnloadedModules | + MinidumpType.WithFullMemoryInfo | + MinidumpType.WithThreadInfo + ); + } + + /// + /// Writes a minidump of the process to the specified file. + /// + /// The destination file. + /// The type of minidump to write. + public void WriteDump(string fileName, MinidumpType type) + { + using (var fhandle = FileHandle.CreateWin32(fileName, FileAccess.GenericWrite)) + this.WriteDump(fhandle, type); + } + + /// + /// Writes a minidump of the process to the specified file. + /// + /// A handle to the destination file. + /// The type of minidump to write. + public void WriteDump(FileHandle fileHandle, MinidumpType type) + { + if (!Win32.MiniDumpWriteDump( + this, + this.GetProcessId(), + fileHandle, + type, + IntPtr.Zero, + IntPtr.Zero, + IntPtr.Zero + )) + Win32.ThrowLastError(); + } + + /// + /// Writes data to the process' virtual memory. + /// + /// The offset at which to begin writing. + /// The data to write. + /// The length, in bytes, that was written. + public int WriteMemory(IntPtr baseAddress, byte[] buffer) + { + unsafe + { + fixed (byte* dataPtr = buffer) + { + return WriteMemory(baseAddress, dataPtr, buffer.Length); + } + } + } + + /// + /// Writes data to the process' virtual memory. + /// + /// The offset at which to begin writing. + /// The data to write. + /// The length to be written. + /// The length, in bytes, that was written. + public unsafe int WriteMemory(IntPtr baseAddress, void* buffer, int length) + { + return this.WriteMemory(baseAddress, new IntPtr(buffer), length); + } + + /// + /// Writes data to the process' virtual memory. + /// + /// The offset at which to begin writing. + /// The data to write. + /// The length to be written. + /// The length, in bytes, that was written. + public int WriteMemory(IntPtr baseAddress, IntPtr buffer, int length) + { + int retLength; + + if (this.Handle == Current) + { + Win32.RtlMoveMemory(baseAddress, buffer, length.ToIntPtr()); + return length; + } + + if (KProcessHacker.Instance != null) + { + KProcessHacker.Instance.KphWriteVirtualMemory(this, baseAddress.ToInt32(), buffer, length, out retLength); + } + else + { + NtStatus status; + IntPtr retLengthIntPtr; + + if ((status = Win32.NtWriteVirtualMemory( + this, + baseAddress, + buffer, + length.ToIntPtr(), + out retLengthIntPtr + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + retLength = retLengthIntPtr.ToInt32(); + } + + return retLength; + } + } + + /// + /// Represents a stack trace collected during a handle trace event. + /// + public class ProcessHandleTrace + { + private ClientId _clientId; + private IntPtr _handle; + private IntPtr[] _stack; + private HandleTraceType _type; + + internal ProcessHandleTrace(ProcessHandleTracingEntry entry) + { + _clientId = entry.ClientId; + _handle = entry.Handle; + _type = entry.Type; + + // Find the first occurrence of a NULL to find where the trace stops. + int zeroIndex = Array.IndexOf(entry.Stacks, IntPtr.Zero); + + // If there was no NULL, copy the entire array. + if (zeroIndex == -1) + zeroIndex = entry.Stacks.Length; + + // Copy the actual stack trace, excluding NULLs. + _stack = new IntPtr[zeroIndex]; + Array.Copy(entry.Stacks, 0, _stack, 0, zeroIndex); + } + + /// + /// The client ID of the thread which produced the event. + /// + public ClientId ClientId + { + get { return _clientId; } + } + + /// + /// The handle value associated with the event. + /// + public IntPtr Handle + { + get { return _handle; } + } + + /// + /// A stack trace of the thread at the time of the event. + /// + public IntPtr[] Stack + { + get { return _stack; } + } + + /// + /// The type of handle trace event. + /// + public HandleTraceType Type + { + get { return _type; } + } + } + + /// + /// Represents a collection of handle trace events. + /// + public class ProcessHandleTraceCollection : ReadOnlyCollection + { + private IntPtr _handle; + + internal ProcessHandleTraceCollection(MemoryAlloc data) + : base(new List()) + { + if (data.Size < Marshal.SizeOf(typeof(ProcessHandleTracingQuery))) + throw new ArgumentException("Data memory allocation is too small."); + + // Read the structure. + var query = data.ReadStruct(); + + _handle = query.Handle; + + // Get the handle traces. + IList traces = this.Items; + + for (int i = 0; i < query.TotalTraces; i++) + { + var entry = data.ReadStruct( + ProcessHandleTracingQuery.HandleTraceOffset, + i + ); + + traces.Add(new ProcessHandleTrace(entry)); + } + } + + /// + /// A unique handle representing the collection. + /// + public IntPtr Handle + { + get { return _handle; } + } + } + + /// + /// Represents a module loaded by a process. + /// + public class ProcessModule : ILoadedModule + { + public ProcessModule( + IntPtr baseAddress, + int size, + IntPtr entryPoint, + LdrpDataTableEntryFlags flags, + string baseName, + string fileName + ) + { + this.BaseAddress = baseAddress; + this.Size = size; + this.EntryPoint = entryPoint; + this.Flags = flags; + this.BaseName = baseName; + this.FileName = fileName; + } + + /// + /// The base address of the module. + /// + public IntPtr BaseAddress { get; private set; } + /// + /// The size of the module. + /// + public int Size { get; private set; } + /// + /// The entry point of the module (usually its DllMain function). + /// + public IntPtr EntryPoint { get; private set; } + /// + /// The flags set by the NT loader for this module. + /// + public LdrpDataTableEntryFlags Flags { get; private set; } + /// + /// The base name of the module (e.g. module.dll). + /// + public string BaseName { get; private set; } + /// + /// The file name of the module (e.g. C:\Windows\system32\module.dll). + /// + public string FileName { get; private set; } + } + + /// + /// Specifies the DEP status of a process. + /// + [Flags] + public enum DepStatus + { + /// + /// DEP is enabled. + /// + Enabled = 0x1, + + /// + /// DEP is permanently enabled or disabled and cannot + /// be enabled or disabled. + /// + Permanent = 0x2, + + /// + /// DEP is enabled with DEP-ATL thunk emulation disabled. + /// + AtlThunkEmulationDisabled = 0x4 + } + + /// + /// A well-known Windows process. + /// + public enum KnownProcess + { + /// + /// The process is not well-known. + /// + None, + /// + /// System Idle Process. + /// + Idle, + /// + /// NT Kernel & System. + /// + System, + /// + /// Windows Session Manager (smss) + /// + SessionManager, + /// + /// Client Server Runtime Process (csrss) + /// + WindowsSubsystem, + /// + /// Windows Start-Up Application (wininit) + /// + WindowsStartup, + /// + /// Services and Controller app (services) + /// + ServiceControlManager, + /// + /// Local Security Authority Process (lsass) + /// + LocalSecurityAuthority, + /// + /// Local Session Manager Service (lsm) + /// + LocalSessionManager + } + + /// + /// Specifies an offset in a process' process environment block (PEB). + /// + public enum PebOffset + { + /// + /// The current directory of the process. This may, as the name + /// implies, change very often. + /// + CurrentDirectoryPath, + /// + /// A copy of the PATH environment variable for the process. + /// + DllPath, + /// + /// The image file name, in kernel format (e.g. \\?\C:\..., + /// \SystemRoot\..., \Device\Harddisk1\...). + /// + ImagePathName, + /// + /// The command used to start the program, including arguments. + /// + CommandLine, + /// + /// Usually blank. + /// + WindowTitle, + /// + /// For interactive programs, contains the window station and + /// desktop name of the first thread that was started, e.g. + /// WinSta0\Default. + /// + DesktopName, + /// + /// Usually blank. + /// + ShellInfo, + /// + /// Usually blank. + /// + RuntimeData + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/ProfileHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/ProfileHandle.cs new file mode 100644 index 000000000..c63eb4c75 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/ProfileHandle.cs @@ -0,0 +1,141 @@ +/* + * Process Hacker - + * profile handle + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Runtime.InteropServices; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + public sealed class ProfileHandle : NativeHandle + { + public static ProfileHandle Create( + ProcessHandle processHandle, + IntPtr rangeBase, + uint rangeSize, + int bucketSize, + KProfileSource profileSource, + IntPtr affinity + ) + { + NtStatus status; + IntPtr handle; + + if (bucketSize < 2 || bucketSize > 30) + throw new ArgumentException("Bucket size must be between 2 and 30, inclusive."); + + unchecked + { + uint realBucketSize = (uint)(2 << (bucketSize - 1)); + MemoryAlloc buffer = new MemoryAlloc((int)((rangeSize - 1) / realBucketSize + 1) * sizeof(int)); // divide, round up + + if ((status = Win32.NtCreateProfile( + out handle, + processHandle ?? IntPtr.Zero, + rangeBase, + new IntPtr(rangeSize), + bucketSize, + buffer, + buffer.Size, + profileSource, + affinity + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return new ProfileHandle(handle, true, rangeBase, rangeSize, realBucketSize, buffer); + } + } + + public static int GetInterval(KProfileSource profileSource) + { + NtStatus status; + int interval; + + if ((status = Win32.NtQueryIntervalProfile(profileSource, out interval)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return interval; + } + + public static void SetInterval(KProfileSource profileSource, int interval) + { + NtStatus status; + + if ((status = Win32.NtSetIntervalProfile(interval, profileSource)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + private IntPtr _rangeBase; + private uint _rangeSize; + private uint _bucketSize; // not logarithmic + private MemoryAlloc _buffer; + + private ProfileHandle( + IntPtr handle, + bool owned, + IntPtr rangeBase, + uint rangeSize, + uint bucketSize, + MemoryAlloc buffer + ) + : base(handle, owned) + { + _rangeBase = rangeBase; + _rangeSize = rangeSize; + _bucketSize = bucketSize; + _buffer = buffer; + } + + protected override void Close() + { + _buffer.Dispose(); + + base.Close(); + } + + public int[] Collect() + { + int[] counters = new int[_buffer.Size / sizeof(int)]; + + Marshal.Copy(_buffer, counters, 0, counters.Length); + + return counters; + } + + public void Start() + { + NtStatus status; + + if ((status = Win32.NtStartProfile(this)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + public void Stop() + { + NtStatus status; + + if ((status = Win32.NtStopProfile(this)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/RemoteHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/RemoteHandle.cs new file mode 100644 index 000000000..2e2e0f757 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/RemoteHandle.cs @@ -0,0 +1,66 @@ +/* + * Process Hacker - + * remote handle + * + * Copyright (C) 2008 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 . + */ + + +using System; +namespace ProcessHacker.Native.Objects +{ + /// + /// Represents a handle owned by another process. + /// + public class RemoteHandle + { + private ProcessHandle _phandle; + private IntPtr _handle; + + public RemoteHandle(ProcessHandle phandle, IntPtr handle) + { + _phandle = phandle; + _handle = handle; + } + + public ProcessHandle ProcessHandle + { + get { return _phandle; } + } + + public IntPtr Handle + { + get { return _handle; } + } + + /// + /// Duplicates the handle owned by the process. + /// + /// The desired access to the handle's object. + /// A local copy of the handle. + /// + /// We can't use a template for this because of C#'s rules for template + /// restrictions. Specifically, we can only specify that the type must have a + /// constructor with 0 arguments, but no more. + /// + public int GetHandle(int access) + { + return new GenericHandle(_phandle, _handle, access); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/RemoteTokenHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/RemoteTokenHandle.cs new file mode 100644 index 000000000..6f3b6ae82 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/RemoteTokenHandle.cs @@ -0,0 +1,63 @@ +/* + * Process Hacker - + * remote token handle + * + * Copyright (C) 2008 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 . + */ + +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; +using System; + +namespace ProcessHacker.Native.Objects +{ + /// + /// Represents a token handle owned by another process. + /// + /// + /// This is a wrapper class so that we can view information + /// about tokens other processes have handles to. TokenProperties + /// only takes an IWithToken object. + /// + public sealed class RemoteTokenHandle : RemoteHandle, IWithToken + { + public RemoteTokenHandle(ProcessHandle phandle, IntPtr handle) + : base(phandle, handle) + { } + + public new IntPtr GetHandle(int rights) + { + IntPtr newHandle = IntPtr.Zero; + + // We can use KPH here. RemoteHandle doesn't. + Win32.DuplicateObject(this.ProcessHandle, this.Handle, new IntPtr(-1), out newHandle, rights, 0, 0); + + return newHandle; + } + + public TokenHandle GetToken() + { + return GetToken(TokenAccess.All); + } + + public TokenHandle GetToken(TokenAccess access) + { + return new TokenHandle(this.GetHandle((int)access), true); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/ResourceManagerHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/ResourceManagerHandle.cs new file mode 100644 index 000000000..ef8d46fbc --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/ResourceManagerHandle.cs @@ -0,0 +1,184 @@ +/* + * Process Hacker - + * resource manager handle + * + * Copyright (C) 2009 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 . + */ + +using System; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + public class ResourceManagerHandle : NativeHandle + { + public static ResourceManagerHandle Create( + ResourceManagerAccess access, + string name, + ObjectFlags objectFlags, + DirectoryHandle rootDirectory, + TmHandle tmHandle, + Guid guid, + ResourceManagerOptions createOptions, + string description + ) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + UnicodeString descriptionStr = new UnicodeString(description); + + try + { + if ((status = Win32.NtCreateResourceManager( + out handle, + access, + tmHandle, + ref guid, + ref oa, + createOptions, + ref descriptionStr + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + descriptionStr.Dispose(); + } + } + finally + { + oa.Dispose(); + } + + return new ResourceManagerHandle(handle, true); + } + + public static ResourceManagerHandle FromHandle(IntPtr handle) + { + return new ResourceManagerHandle(handle, false); + } + + private ResourceManagerHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + public ResourceManagerHandle( + string name, + ObjectFlags objectFlags, + DirectoryHandle rootDirectory, + TmHandle tmHandle, + Guid guid, + ResourceManagerAccess access + ) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtOpenResourceManager( + out handle, + access, + tmHandle, + ref guid, + ref oa + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + this.Handle = handle; + } + + private MemoryAlloc GetBasicInformation() + { + NtStatus status; + int retLength; + + var data = new MemoryAlloc(0x1000); + + status = Win32.NtQueryInformationResourceManager( + this, + ResourceManagerInformationClass.ResourceManagerBasicInformation, + data, + data.Size, + out retLength + ); + + if (status == NtStatus.BufferTooSmall) + { + // Resize the buffer and try again. + data.Resize(retLength); + + status = Win32.NtQueryInformationResourceManager( + this, + ResourceManagerInformationClass.ResourceManagerBasicInformation, + data, + data.Size, + out retLength + ); + } + + if (status >= NtStatus.Error) + { + data.Dispose(); + Win32.ThrowLastError(status); + } + + return data; + } + + public string GetDescription() + { + using (var data = this.GetBasicInformation()) + { + var basicInfo = data.ReadStruct(); + + return data.ReadUnicodeString( + ResourceManagerBasicInformation.DescriptionOffset, + basicInfo.DescriptionLength / 2 + ); + } + } + + public Guid GetGuid() + { + using (var data = this.GetBasicInformation()) + { + return data.ReadStruct().ResourceManagerId; + } + } + + public void Recover() + { + NtStatus status; + + if ((status = Win32.NtRecoverResourceManager(this)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/SectionHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/SectionHandle.cs new file mode 100644 index 000000000..442cf9118 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/SectionHandle.cs @@ -0,0 +1,257 @@ +/* + * Process Hacker - + * section handle + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Runtime.InteropServices; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + public sealed class SectionHandle : NativeHandle + { + public static SectionHandle Create( + SectionAccess access, + SectionAttributes sectionAttributes, + MemoryProtection pageAttributes, + FileHandle fileHandle + ) + { + return Create(access, 0, sectionAttributes, pageAttributes, fileHandle); + } + + public static SectionHandle Create( + SectionAccess access, + long maximumSize, + SectionAttributes sectionAttributes, + MemoryProtection pageAttributes, + FileHandle fileHandle + ) + { + return Create(access, null, maximumSize, sectionAttributes, pageAttributes, fileHandle); + } + + public static SectionHandle Create( + SectionAccess access, + long maximumSize, + SectionAttributes sectionAttributes, + MemoryProtection pageAttributes + ) + { + return Create(access, null, maximumSize, sectionAttributes, pageAttributes, null); + } + + public static SectionHandle Create( + SectionAccess access, + string name, + long maximumSize, + SectionAttributes sectionAttributes, + MemoryProtection pageAttributes, + FileHandle fileHandle + ) + { + return Create(access, name, 0, null, maximumSize, sectionAttributes, pageAttributes, fileHandle); + } + + public static SectionHandle Create( + SectionAccess access, + string name, + ObjectFlags objectFlags, + DirectoryHandle rootDirectory, + long maximumSize, + SectionAttributes sectionAttributes, + MemoryProtection pageAttributes, + FileHandle fileHandle + ) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if (maximumSize != 0) + { + if ((status = Win32.NtCreateSection( + out handle, + access, + ref oa, + ref maximumSize, + pageAttributes, + sectionAttributes, + fileHandle ?? IntPtr.Zero + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + else + { + if ((status = Win32.NtCreateSection( + out handle, + access, + ref oa, + IntPtr.Zero, + pageAttributes, + sectionAttributes, + fileHandle ?? IntPtr.Zero + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + } + finally + { + oa.Dispose(); + } + + return new SectionHandle(handle, true); + } + + public static SectionHandle FromHandle(IntPtr handle) + { + return new SectionHandle(handle, false); + } + + private SectionHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + public SectionHandle(string name, ObjectFlags objectFlags, DirectoryHandle rootDirectory, SectionAccess access) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtOpenSection(out handle, access, ref oa)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + this.Handle = handle; + } + + public SectionHandle(string name, SectionAccess access) + : this(name, 0, null, access) + { } + + public long Extend(long newSize) + { + NtStatus status; + + if ((status = Win32.NtExtendSection(this, ref newSize)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return newSize; + } + + public SectionBasicInformation GetBasicInformation() + { + NtStatus status; + SectionBasicInformation sbi; + IntPtr retLength; + + if ((status = Win32.NtQuerySection(this, SectionInformationClass.SectionBasicInformation, + out sbi, new IntPtr(Marshal.SizeOf(typeof(SectionBasicInformation))), out retLength)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return sbi; + } + + public SectionImageInformation GetImageInformation() + { + NtStatus status; + SectionImageInformation sii; + IntPtr retLength; + + if ((status = Win32.NtQuerySection(this, SectionInformationClass.SectionImageInformation, + out sii, new IntPtr(Marshal.SizeOf(typeof(SectionImageInformation))), out retLength)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return sii; + } + + public SectionView MapView(int sectionOffset, int size, MemoryProtection protection) + { + return this.MapView(IntPtr.Zero, sectionOffset, new IntPtr(size), protection); + } + + public SectionView MapView(IntPtr baseAddress, long sectionOffset, IntPtr size, MemoryProtection protection) + { + return this.MapView(ProcessHandle.Current, baseAddress, sectionOffset, size, protection); + } + + public SectionView MapView( + ProcessHandle processHandle, + IntPtr baseAddress, + long sectionOffset, + IntPtr size, + MemoryProtection protection + ) + { + return this.MapView( + processHandle, + baseAddress, + size, + sectionOffset, + size, + SectionInherit.ViewShare, + 0, + protection + ); + } + + public SectionView MapView( + ProcessHandle processHandle, + IntPtr baseAddress, + IntPtr commitSize, + long sectionOffset, + IntPtr viewSize, + SectionInherit inheritDisposition, + MemoryFlags allocationType, + MemoryProtection protection + ) + { + NtStatus status; + + // sectionOffset requires 2 << 15 = 0x10000 = 65536 alignment. + // viewSize will be rounded up to the page size. + if ((status = Win32.NtMapViewOfSection( + this, + processHandle, + ref baseAddress, + IntPtr.Zero, + commitSize, + ref sectionOffset, + ref viewSize, + inheritDisposition, + allocationType, + protection + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return new SectionView(baseAddress, viewSize); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/SemaphoreHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/SemaphoreHandle.cs new file mode 100644 index 000000000..3f348a377 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/SemaphoreHandle.cs @@ -0,0 +1,123 @@ +/* + * Process Hacker - + * semaphore handle + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Runtime.InteropServices; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + public sealed class SemaphoreHandle : NativeHandle + { + public static SemaphoreHandle Create(SemaphoreAccess access, int initialCount, int maximumCount) + { + return Create(access, null, initialCount, maximumCount); + } + + public static SemaphoreHandle Create(SemaphoreAccess access, string name, int initialCount, int maximumCount) + { + return Create(access, name, 0, null, initialCount, maximumCount); + } + + public static SemaphoreHandle Create(SemaphoreAccess access, string name, ObjectFlags objectFlags, DirectoryHandle rootDirectory, int initialCount, int maximumCount) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtCreateSemaphore(out handle, access, ref oa, + initialCount, maximumCount)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + return new SemaphoreHandle(handle, true); + } + + public static SemaphoreHandle FromHandle(IntPtr handle) + { + return new SemaphoreHandle(handle, false); + } + + private SemaphoreHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + public SemaphoreHandle(string name, ObjectFlags objectFlags, DirectoryHandle rootDirectory, SemaphoreAccess access) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtOpenSemaphore(out handle, access, ref oa)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + this.Handle = handle; + } + + public SemaphoreHandle(string name, SemaphoreAccess access) + : this(name, 0, null, access) + { } + + public SemaphoreBasicInformation GetBasicInformation() + { + NtStatus status; + SemaphoreBasicInformation sbi; + int retLength; + + if ((status = Win32.NtQuerySemaphore(this, SemaphoreInformationClass.SemaphoreBasicInformation, + out sbi, Marshal.SizeOf(typeof(SemaphoreBasicInformation)), out retLength)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return sbi; + } + + public int Release() + { + return this.Release(1); + } + + public int Release(int count) + { + NtStatus status; + int previousCount; + + if ((status = Win32.NtReleaseSemaphore(this, count, out previousCount)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return previousCount; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/ServiceBaseHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/ServiceBaseHandle.cs new file mode 100644 index 000000000..f4a091612 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/ServiceBaseHandle.cs @@ -0,0 +1,46 @@ +/* + * Process Hacker - + * service-related handle + * + * Copyright (C) 2008 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 . + */ + +using ProcessHacker.Native.Api; +using System; + +namespace ProcessHacker.Native.Objects +{ + /// + /// Represents a handle managed by the Windows service manager. + /// + public class ServiceBaseHandle : NativeHandle + where TAccess : struct + { + public ServiceBaseHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + protected ServiceBaseHandle() + { } + + protected override void Close() + { + Win32.CloseServiceHandle(this); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/ServiceHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/ServiceHandle.cs new file mode 100644 index 000000000..49609f74d --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/ServiceHandle.cs @@ -0,0 +1,301 @@ +/* + * Process Hacker - + * service handle + * + * Copyright (C) 2008 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 . + */ + +using System; +using System.Runtime.InteropServices; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; +using ProcessHacker.Native.Security.AccessControl; + +namespace ProcessHacker.Native.Objects +{ + /// + /// Represents a handle to a Windows service. + /// + public sealed class ServiceHandle : ServiceBaseHandle + { + /// + /// Creates a service handle using an existing handle. + /// The handle will not be closed automatically. + /// + /// The handle value. + /// The service handle. + public static ServiceHandle FromHandle(IntPtr handle) + { + return new ServiceHandle(handle, false); + } + + public static ServiceHandle OpenWithAnyAccess(string serviceName) + { + try + { + return new ServiceHandle(serviceName, ServiceAccess.QueryStatus); + } + catch + { + try + { + return new ServiceHandle(serviceName, (ServiceAccess)StandardRights.Synchronize); + } + catch + { + try + { + return new ServiceHandle(serviceName, (ServiceAccess)StandardRights.ReadControl); + } + catch + { + try + { + return new ServiceHandle(serviceName, (ServiceAccess)StandardRights.WriteDac); + } + catch + { + return new ServiceHandle(serviceName, (ServiceAccess)StandardRights.WriteOwner); + } + } + } + } + } + + internal ServiceHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + /// + /// Creates a new service handle. + /// + /// The name of the service to open. + public ServiceHandle(string serviceName) + : this(serviceName, ServiceAccess.All) + { } + + /// + /// Creates a new service handle. + /// + /// The name of the service to open. + /// The desired access to the service. + public ServiceHandle(string serviceName, ServiceAccess access) + { + using (ServiceManagerHandle manager = + new ServiceManagerHandle(ScManagerAccess.Connect)) + { + this.Handle = Win32.OpenService(manager, serviceName, access); + + if (this.Handle == IntPtr.Zero) + { + this.MarkAsInvalid(); + Win32.ThrowLastError(); + } + } + } + + /// + /// Sends a control message to the service. + /// + /// The message. + public void Control(ServiceControl control) + { + ServiceStatus status = new ServiceStatus(); + + if (!Win32.ControlService(this, control, out status)) + Win32.ThrowLastError(); + } + + /// + /// Deletes the service. + /// + public void Delete() + { + if (!Win32.DeleteService(this)) + Win32.ThrowLastError(); + } + + /// + /// Gets the service's configuration. + /// + public QueryServiceConfig GetConfig() + { + int requiredSize = 0; + + Win32.QueryServiceConfig(this, IntPtr.Zero, 0, out requiredSize); + + using (MemoryAlloc data = new MemoryAlloc(requiredSize)) + { + if (!Win32.QueryServiceConfig(this, data, data.Size, out requiredSize)) + Win32.ThrowLastError(); + + return data.ReadStruct(); + } + } + + /// + /// Gets the service's description. + /// + /// A string. + public string GetDescription() + { + int retLen; + + Win32.QueryServiceConfig2(this, ServiceInfoLevel.Description, IntPtr.Zero, 0, out retLen); + + using (MemoryAlloc data = new MemoryAlloc(retLen)) + { + if (!Win32.QueryServiceConfig2(this, ServiceInfoLevel.Description, data, retLen, out retLen)) + Win32.ThrowLastError(); + + return data.ReadStruct().Description; + } + } + + public override SecurityDescriptor GetSecurity(SecurityInformation securityInformation) + { + return this.GetSecurity(SeObjectType.Service, securityInformation); + } + + /// + /// Gets the status of the service. + /// + /// A SERVICE_STATUS_PROCESS structure. + public ServiceStatusProcess GetStatus() + { + ServiceStatusProcess status; + int retLen; + + if (!Win32.QueryServiceStatusEx(this, 0, out status, Marshal.SizeOf(typeof(ServiceStatusProcess)), out retLen)) + Win32.ThrowLastError(); + + return status; + } + + public override void SetSecurity(SecurityInformation securityInformation, SecurityDescriptor securityDescriptor) + { + this.SetSecurity(SeObjectType.Service, securityInformation, securityDescriptor); + } + + /// + /// Starts the service. + /// + public void Start() + { + if (!Win32.StartService(this, 0, null)) + Win32.ThrowLastError(); + } + } + + public enum ServiceAccept : uint + { + NetBindChange = 0x10, + ParamChange = 0x8, + PauseContinue = 0x2, + PreShutdown = 0x100, + Shutdown = 0x4, + Stop = 0x1, + HardwareProfileChange = 0x20, + PowerEvent = 0x40, + SessionChange = 0x80 + } + + public enum ServiceControl : uint + { + Continue = 0x3, + Interrogate = 0x4, + NetBindAdd = 0x7, + NetBindDisable = 0xa, + NetBindEnable = 0x9, + NetBindRemove = 0x8, + ParamChange = 0x6, + Pause = 0x2, + Stop = 0x1 + } + + public enum ServiceErrorControl : uint + { + Critical = 0x3, + Ignore = 0x0, + Normal = 0x1, + Severe = 0x2 + } + + public enum ServiceFlags : uint + { + None = 0, + RunsInSystemProcess = 0x1 + } + + public enum ServiceInfoLevel : uint + { + Description = 1, + FailureActions = 2, + DelayedAutoStartInfo = 3, + FailureActionsFlag = 4, + SidInfo = 5, + RequiredPrivilegesInfo = 6, + PreShutdownInfo = 7, + TriggerInfo = 8, + PreferredNode = 9 + } + + public enum ServiceQueryState : uint + { + Active = 1, + Inactive = 2, + All = 3 + } + + [Flags] + public enum ServiceQueryType : uint + { + Driver = 0xb, + Win32 = 0x30 + } + + public enum ServiceStartType : uint + { + AutoStart = 0x2, + BootStart = 0x0, + DemandStart = 0x3, + Disabled = 0x4, + SystemStart = 0x1 + } + + public enum ServiceState : uint + { + ContinuePending = 0x5, + PausePending = 0x6, + Paused = 0x7, + Running = 0x4, + StartPending = 0x2, + StopPending = 0x3, + Stopped = 0x1 + } + + [Flags] + public enum ServiceType : uint + { + FileSystemDriver = 0x2, + KernelDriver = 0x1, + Win32OwnProcess = 0x10, + Win32ShareProcess = 0x20, + InteractiveProcess = 0x100 + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/ServiceManagerHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/ServiceManagerHandle.cs new file mode 100644 index 000000000..7909f4e59 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/ServiceManagerHandle.cs @@ -0,0 +1,77 @@ +/* + * Process Hacker - + * service manager handle + * + * Copyright (C) 2008 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 . + */ + +using System; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + /// + /// Represents a handle to the Windows service manager. + /// + public sealed class ServiceManagerHandle : ServiceBaseHandle + { + /// + /// Connects to the Windows service manager. + /// + /// The desired access to the service manager. + public ServiceManagerHandle(ScManagerAccess access) + { + this.Handle = Win32.OpenSCManager(null, null, access); + + if (this.Handle == IntPtr.Zero) + { + this.MarkAsInvalid(); + Win32.ThrowLastError(); + } + } + + public ServiceHandle CreateService(string name, string displayName, + ServiceType type, string binaryPath) + { + return this.CreateService(name, displayName, type, ServiceStartType.DemandStart, + ServiceErrorControl.Ignore, binaryPath, null, null, null); + } + + public ServiceHandle CreateService(string name, string displayName, + ServiceType type, ServiceStartType startType, string binaryPath) + { + return this.CreateService(name, displayName, type, startType, + ServiceErrorControl.Ignore, binaryPath, null, null, null); + } + + public ServiceHandle CreateService(string name, string displayName, + ServiceType type, ServiceStartType startType, ServiceErrorControl errorControl, + string binaryPath, string group, string accountName, string password) + { + IntPtr service; + + if ((service = Win32.CreateService(this, name, displayName, ServiceAccess.All, + type, startType, errorControl, binaryPath, group, + IntPtr.Zero, IntPtr.Zero, accountName, password)) == IntPtr.Zero) + Win32.ThrowLastError(); + + return new ServiceHandle(service, true); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/SymbolicLinkHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/SymbolicLinkHandle.cs new file mode 100644 index 000000000..7b2d353c4 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/SymbolicLinkHandle.cs @@ -0,0 +1,118 @@ +/* + * Process Hacker - + * symbolic link handle + * + * Copyright (C) 2009 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 . + */ + +using System; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + public sealed class SymbolicLinkHandle : NativeHandle + { + public static SymbolicLinkHandle Create(SymbolicLinkAccess access, string name, string linkTarget) + { + return Create(access, name, 0, null, linkTarget); + } + + public static SymbolicLinkHandle Create(SymbolicLinkAccess access, string name, ObjectFlags objectFlags, DirectoryHandle rootDirectory, string linkTarget) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + UnicodeString linkTargetString = new UnicodeString(linkTarget); + + try + { + if ((status = Win32.NtCreateSymbolicLinkObject(out handle, access, + ref oa, ref linkTargetString)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + linkTargetString.Dispose(); + } + } + finally + { + oa.Dispose(); + } + + return new SymbolicLinkHandle(handle, true); + } + + private SymbolicLinkHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + public SymbolicLinkHandle(string name, ObjectFlags objectFlags, DirectoryHandle rootDirectory, SymbolicLinkAccess access) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtOpenSymbolicLinkObject(out handle, access, ref oa)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + this.Handle = handle; + } + + public SymbolicLinkHandle(string name, SymbolicLinkAccess access) + : this(name, 0, null, access) + { } + + public string GetTarget() + { + NtStatus status; + int retLength; + UnicodeString str = new UnicodeString(); + + using (var buffer = new MemoryAlloc(0x200)) + { + str.Length = 0; + str.MaximumLength = (ushort)buffer.Size; + str.Buffer = buffer; + + if ((status = Win32.NtQuerySymbolicLinkObject(this, ref str, out retLength)) >= NtStatus.Error) + { + buffer.Resize(retLength); + str.MaximumLength = (ushort)retLength; + str.Buffer = buffer; + } + + if ((status = Win32.NtQuerySymbolicLinkObject(this, ref str, out retLength)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return str.Read(); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/TerminalServerHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/TerminalServerHandle.cs new file mode 100644 index 000000000..78bc4e3f8 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/TerminalServerHandle.cs @@ -0,0 +1,535 @@ +/* + * Process Hacker - + * terminal server handles and objects + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using ProcessHacker.Common.Objects; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + public sealed class TerminalServerHandle : NativeHandle + { + private static readonly TerminalServerHandle _current = new TerminalServerHandle(IntPtr.Zero, false); + + /// + /// Gets a handle to the local terminal server. + /// + public static TerminalServerHandle Current + { + get { return _current; } + } + + /// + /// Gets a handle to the local terminal server. + /// + /// A terminal server handle. + public static TerminalServerHandle GetCurrent() + { + return Current; + } + + /// + /// Registers the specified window to receieve terminal server notifications. + /// + /// The window to receieve the notifications. + /// Whether notifications should be created for all sessions. + public static void RegisterNotificationsCurrent(IWin32Window window, bool allSessions) + { + if (!Win32.WTSRegisterSessionNotification( + window.Handle, + allSessions ? WtsNotificationFlags.AllSessions : WtsNotificationFlags.ThisSession + )) + Win32.ThrowLastError(); + } + + /// + /// Unregisters terminal server notifications for the specified window. + /// + /// The window to stop receiving notifications. + public static void UnregisterNotificationsCurrent(IWin32Window window) + { + if (!Win32.WTSUnRegisterSessionNotification(window.Handle)) + Win32.ThrowLastError(); + } + + private string _systemName; + + private TerminalServerHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + /// + /// Opens a terminal server. + /// + /// The NetBIOS name of the server. + public TerminalServerHandle(string serverName) + { + this.Handle = Win32.WTSOpenServer(serverName); + _systemName = serverName; + + if (this.Handle == IntPtr.Zero) + Win32.ThrowLastError(); + } + + protected override void Close() + { + Win32.WTSCloseServer(this); + } + + /// + /// Gets the name of the terminal server. + /// This value can be null when the server is local. + /// + public string SystemName + { + get { return _systemName; } + } + + /// + /// Gets the processes running on the terminal server. + /// + /// An array of processes. + public TerminalServerProcess[] GetProcesses() + { + IntPtr dataPtr; + int count; + TerminalServerProcess[] processes; + + if (!Win32.WTSEnumerateProcesses(this, 0, 1, out dataPtr, out count)) + Win32.ThrowLastError(); + + using (var data = new WtsMemoryAlloc(dataPtr)) + { + processes = new TerminalServerProcess[count]; + + for (int i = 0; i < count; i++) + { + var process = data.ReadStruct(i); + processes[i] = new TerminalServerProcess( + process.ProcessId, + process.SessionId, + Marshal.PtrToStringUni(process.ProcessName), + process.Sid != IntPtr.Zero ? new Sid(process.Sid, _systemName) : null + ); + } + + return processes; + } + } + + /// + /// Gets information about a session on the terminal server. + /// + /// The ID of the session. + /// Information about the session. + public TerminalServerSession GetSession(int sessionId) + { + return new TerminalServerSession(this, sessionId); + } + + /// + /// Gets the sessions on the terminal server. + /// + /// An array of sessions. + public TerminalServerSession[] GetSessions() + { + IntPtr dataPtr; + int count; + TerminalServerSession[] sessions; + + if (!Win32.WTSEnumerateSessions(this, 0, 1, out dataPtr, out count)) + Win32.ThrowLastError(); + + using (var data = new WtsMemoryAlloc(dataPtr)) + { + sessions = new TerminalServerSession[count]; + + for (int i = 0; i < count; i++) + { + var session = data.ReadStruct(i); + sessions[i] = new TerminalServerSession( + this, + session.SessionID, + session.WinStationName, + session.State + ); + } + + return sessions; + } + } + + /// + /// Registers the specified window to receieve terminal server notifications. + /// + /// The window to receieve the notifications. + /// Whether notifications should be created for all sessions. + public void RegisterNotifications(IWin32Window window, bool allSessions) + { + if (!Win32.WTSRegisterSessionNotificationEx( + this, + window.Handle, + allSessions ? WtsNotificationFlags.AllSessions : WtsNotificationFlags.ThisSession + )) + Win32.ThrowLastError(); + } + + /// + /// Causes the terminal server to shutdown. + /// + /// The action to take. + public void Shutdown(WtsShutdownFlags flag) + { + if (!Win32.WTSShutdownSystem(this, flag)) + Win32.ThrowLastError(); + } + + /// + /// Terminates the specified process on the terminal server. + /// + /// The ID of the process to terminate. + /// The exit code. + public void TerminateProcess(int pid, int exitCode) + { + if (!Win32.WTSTerminateProcess(this, pid, exitCode)) + Win32.ThrowLastError(); + } + + /// + /// Unregisters terminal server notifications for the specified window. + /// + /// The window to stop receiving notifications. + public void UnregisterNotifications(IWin32Window window) + { + if (!Win32.WTSUnRegisterSessionNotificationEx(this, window.Handle)) + Win32.ThrowLastError(); + } + } + + public class TerminalServerSession : BaseObject + { + public static int GetActiveConsoleId() + { + return Win32.WTSGetActiveConsoleSessionId(); + } + + private TerminalServerHandle _serverHandle; + private int _sessionId; + private string _name; + private WtsConnectStateClass _state = (WtsConnectStateClass)(-1); + private string _initialProgram; + private string _applicationName; + private string _workingDirectory; + private string _userName; + private string _domainName; + private string _clientName; + private string _clientDirectory; + private System.Net.IPAddress _clientAddress; + private WtsClientDisplay? _clientDisplay; + + internal TerminalServerSession(TerminalServerHandle serverHandle, int sessionId) + { + _serverHandle = serverHandle; + _sessionId = sessionId; + _serverHandle.Reference(); + } + + internal TerminalServerSession(TerminalServerHandle serverHandle, int sessionId, string name, WtsConnectStateClass state) + { + _serverHandle = serverHandle; + _sessionId = sessionId; + _serverHandle.Reference(); + _name = name; + _state = state; + } + + protected override void DisposeObject(bool disposing) + { + _serverHandle.Dereference(disposing); + } + + public int SessionId { get { return _sessionId; } } + + public string Name + { + get + { + if (_name == null) + _name = this.GetInformationString(WtsInformationClass.WinStationName); + return _name; + } + } + + public WtsConnectStateClass State + { + get + { + if ((int)_state == -1) + { + IntPtr dataPtr; + int length; + + if (!Win32.WTSQuerySessionInformation( + _serverHandle, _sessionId, WtsInformationClass.ConnectState, out dataPtr, out length)) + Win32.ThrowLastError(); + + using (var data = new WtsMemoryAlloc(dataPtr)) + _state = (WtsConnectStateClass)data.ReadInt32(0); + } + + return _state; + } + } + + public string InitialProgram + { + get + { + if (_initialProgram == null) + _initialProgram = this.GetInformationString(WtsInformationClass.InitialProgram); + return _initialProgram; + } + } + + public string ApplicationName + { + get + { + if (_applicationName == null) + _applicationName = this.GetInformationString(WtsInformationClass.ApplicationName); + return _applicationName; + } + } + + public string WorkingDirectory + { + get + { + if (_workingDirectory == null) + _workingDirectory = this.GetInformationString(WtsInformationClass.WorkingDirectory); + return _workingDirectory; + } + } + + public string UserName + { + get + { + if (_userName == null) + _userName = this.GetInformationString(WtsInformationClass.UserName); + return _userName; + } + } + + public string DomainName + { + get + { + if (_domainName == null) + _domainName = this.GetInformationString(WtsInformationClass.DomainName); + return _domainName; + } + } + + public string ClientName + { + get + { + if (_clientName == null) + _clientName = this.GetInformationString(WtsInformationClass.ClientName); + return _clientName; + } + } + + public string ClientDirectory + { + get + { + if (_clientDirectory == null) + _clientDirectory = this.GetInformationString(WtsInformationClass.ClientDirectory); + return _clientDirectory; + } + } + + public System.Net.IPAddress ClientAddress + { + get + { + if (_clientAddress == null) + { + IntPtr dataPtr; + int length; + + if (!Win32.WTSQuerySessionInformation( + _serverHandle, _sessionId, WtsInformationClass.ClientAddress, out dataPtr, out length)) + Win32.ThrowLastError(); + + if (dataPtr != IntPtr.Zero) + { + unsafe + { + using (var data = new WtsMemoryAlloc(dataPtr)) + { + var address = data.ReadStruct(); + + if (address.AddressFamily != 0) + _clientAddress = new System.Net.IPAddress(data.ReadBytes(6, 4)); + } + } + } + } + + return _clientAddress; + } + } + + public WtsClientDisplay ClientDisplay + { + get + { + if (_clientDisplay == null) + { + IntPtr dataPtr; + int length; + + if (!Win32.WTSQuerySessionInformation( + _serverHandle, _sessionId, WtsInformationClass.ClientDisplay, out dataPtr, out length)) + Win32.ThrowLastError(); + + if (dataPtr != IntPtr.Zero) + { + using (var data = new WtsMemoryAlloc(dataPtr)) + _clientDisplay = data.ReadStruct(); + } + } + + return _clientDisplay.Value; + } + } + + public void Disconnect() + { + this.Disconnect(false); + } + + public void Disconnect(bool synchronous) + { + if (!Win32.WTSDisconnectSession(_serverHandle, _sessionId, synchronous)) + Win32.ThrowLastError(); + } + + public string GetInformationString(WtsInformationClass infoClass) + { + IntPtr data; + int length; + + if (!Win32.WTSQuerySessionInformation(_serverHandle, _sessionId, infoClass, out data, out length)) + Win32.ThrowLastError(); + + if (data == IntPtr.Zero) + return null; + + using (new WtsMemoryAlloc(data)) + return Marshal.PtrToStringUni(data); + } + + public void Logoff() + { + this.Logoff(false); + } + + public void Logoff(bool synchronous) + { + if (!Win32.WTSLogoffSession(_serverHandle, _sessionId, synchronous)) + Win32.ThrowLastError(); + } + + public DialogResult SendMessage(string title, string message) + { + return this.SendMessage(title, message, MessageBoxButtons.OK, MessageBoxIcon.None); + } + + public DialogResult SendMessage( + string title, + string message, + MessageBoxButtons buttons, + MessageBoxIcon icon + ) + { + return this.SendMessage(title, message, buttons, icon, 0, 0, 0, false); + } + + public DialogResult SendMessage( + string title, + string message, + MessageBoxButtons buttons, + MessageBoxIcon icon, + MessageBoxDefaultButton defaultButton, + MessageBoxOptions options, + int secondsTimeout, + bool synchronous + ) + { + DialogResult response; + + if (!Win32.WTSSendMessage( + _serverHandle, + _sessionId, + title, + title.Length * 2, + message, + message.Length * 2, + (int)buttons | (int)icon | (int)defaultButton | (int)options, + secondsTimeout, + out response, + synchronous + )) + Win32.ThrowLastError(); + + return response; + } + } + + public class TerminalServerProcess + { + private int _processId; + private int _sessionId; + private string _name; + private Sid _sid; + + internal TerminalServerProcess(int processId, int sessionId, string name, Sid sid) + { + _processId = processId; + _sessionId = sessionId; + _name = name; + _sid = sid; + } + + public int ProcessId { get { return _processId; } } + public int SessionId { get { return _sessionId; } } + public string Name { get { return _name; } } + public Sid Sid { get { return _sid; } } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/ThreadHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/ThreadHandle.cs new file mode 100644 index 000000000..8cf3d92ce --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/ThreadHandle.cs @@ -0,0 +1,1355 @@ +/* + * Process Hacker - + * thread handle + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.InteropServices; +using ProcessHacker.Common; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + /// + /// Represents a handle to a Windows thread. + /// + public sealed class ThreadHandle : NativeHandle, IWithToken + { + public delegate bool WalkStackDelegate(ThreadStackFrame stackFrame); + + private static readonly ThreadHandle _current = new ThreadHandle(new IntPtr(-2), false); + + /// + /// Gets a handle to the current thread. + /// + public static ThreadHandle Current + { + get { return _current; } + } + + public static ThreadHandle Create( + ThreadAccess access, + string name, + ObjectFlags objectFlags, + DirectoryHandle rootDirectory, + ProcessHandle processHandle, + out ClientId clientId, + ref Context threadContext, + ref InitialTeb initialTeb, + bool createSuspended + ) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtCreateThread( + out handle, + access, + ref oa, + processHandle, + out clientId, + ref threadContext, + ref initialTeb, + createSuspended + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + return new ThreadHandle(handle, true); + } + + public static ThreadHandle CreateUserThread(ProcessHandle processHandle, IntPtr startAddress, IntPtr parameter) + { + return CreateUserThread(processHandle, false, startAddress, parameter); + } + + public static ThreadHandle CreateUserThread( + ProcessHandle processHandle, + bool createSuspended, + IntPtr startAddress, + IntPtr parameter + ) + { + ClientId clientId; + + return CreateUserThread(processHandle, createSuspended, 0, 0, startAddress, parameter, out clientId); + } + + public static ThreadHandle CreateUserThread( + ProcessHandle processHandle, + bool createSuspended, + int maximumStackSize, + int initialStackSize, + IntPtr startAddress, + IntPtr parameter, + out ClientId clientId + ) + { + NtStatus status; + IntPtr threadHandle; + + if ((status = Win32.RtlCreateUserThread( + processHandle, + IntPtr.Zero, + createSuspended, + 0, + maximumStackSize.ToIntPtr(), + initialStackSize.ToIntPtr(), + startAddress, + parameter, + out threadHandle, + out clientId + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return new ThreadHandle(threadHandle, true); + } + + /// + /// Creates a thread handle using an existing handle. + /// The handle will not be closed automatically. + /// + /// The handle value. + /// The thread handle. + public static ThreadHandle FromHandle(IntPtr handle) + { + return new ThreadHandle(handle, false); + } + + /// + /// Gets a handle to the current thread. + /// + /// A thread handle. + public static ThreadHandle GetCurrent() + { + return Current; + } + + /// + /// Gets the client ID of the current thread. + /// + /// A client ID. + public static ClientId GetCurrentCid() + { + return new ClientId(ProcessHandle.GetCurrentId(), ThreadHandle.GetCurrentId()); + } + + /// + /// Gets the ID of the current thread. + /// + /// A thread ID. + public static int GetCurrentId() + { + return Win32.GetCurrentThreadId(); + } + + /// + /// Gets a pointer to the current thread's environment block. + /// + /// A pointer to the current TEB. + public unsafe static Teb* GetCurrentTeb() + { + return (Teb*)Win32.NtCurrentTeb(); + } + + /// + /// Opens the current thread. + /// + /// The desired access to the thread. + /// A handle to the current thread. + public static ThreadHandle OpenCurrent(ThreadAccess access) + { + return new ThreadHandle(GetCurrentId(), access); + } + + public static ThreadHandle OpenWithAnyAccess(int tid) + { + try + { + return new ThreadHandle(tid, OSVersion.MinThreadQueryInfoAccess); + } + catch + { + try + { + return new ThreadHandle(tid, (ThreadAccess)StandardRights.Synchronize); + } + catch + { + try + { + return new ThreadHandle(tid, (ThreadAccess)StandardRights.ReadControl); + } + catch + { + try + { + return new ThreadHandle(tid, (ThreadAccess)StandardRights.WriteDac); + } + catch + { + return new ThreadHandle(tid, (ThreadAccess)StandardRights.WriteOwner); + } + } + } + } + } + + /// + /// Registers a port which will be notified when the current thread terminates. + /// + /// A handle to a port. + public static void RegisterTerminationPort(PortHandle portHandle) + { + NtStatus status; + + if ((status = Win32.NtRegisterThreadTerminatePort(portHandle)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + /// + /// Sleeps the current thread. + /// + /// The timeout, in 100ns units. + /// Whether the timeout value is relative. + /// A NT status value. + public static NtStatus Sleep(long timeout, bool relative) + { + return Sleep(false, timeout, relative); + } + + /// + /// Sleeps the current thread. + /// + /// + /// Whether user-mode APCs can be delivered during the wait. + /// + /// The timeout, in 100ns units. + /// Whether the timeout value is relative. + /// A NT status value. + public static NtStatus Sleep(bool alertable, long timeout, bool relative) + { + if (timeout == 0) + { + Yield(); + return NtStatus.Success; + } + + long realTime = relative ? -timeout : timeout; + + return Win32.NtDelayExecution(alertable, ref realTime); + } + + /// + /// Checks whether the current thread is in an alerted state and + /// executes any pending user-mode APCs. + /// + /// + /// NtStatus.Alerted if the current thread was in an alerted state, + /// otherwise NtStatus.Success. + /// + public static NtStatus TestAlert() + { + NtStatus status; + + if ((status = Win32.NtTestAlert()) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return status; + } + + /// + /// Switches to another thread. + /// + public static void Yield() + { + Win32.NtYieldExecution(); + } + + internal ThreadHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + /// + /// Opens a thread. + /// + /// The ID of the thread to open. + public ThreadHandle(int tid) + : this(tid, ThreadAccess.All) + { } + + /// + /// Opens a thread. + /// + /// The ID of the thread to open. + /// The desired access to the thread. + public ThreadHandle(int tid, ThreadAccess access) + { + if (KProcessHacker.Instance != null) + { + try + { + this.Handle = new IntPtr(KProcessHacker.Instance.KphOpenThread(tid, access)); + } + catch (WindowsException) + { + // Open the thread with minimum access (SYNCHRONIZE) and set the granted access. + this.Handle = new IntPtr(KProcessHacker.Instance.KphOpenThread(tid, + (ThreadAccess)StandardRights.Synchronize)); + KProcessHacker.Instance.KphSetHandleGrantedAccess(this.Handle, (int)access); + } + } + else + { + this.Handle = Win32.OpenThread(access, false, tid); + } + + if (this.Handle == IntPtr.Zero) + { + this.MarkAsInvalid(); + Win32.ThrowLastError(); + } + } + + public ThreadHandle( + string name, + ObjectFlags objectFlags, + DirectoryHandle rootDirectory, + ClientId clientId, + ThreadAccess access + ) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if (clientId.ProcessId == 0 && clientId.ThreadId == 0) + { + if ((status = Win32.NtOpenThread( + out handle, + access, + ref oa, + IntPtr.Zero + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + else + { + if ((status = Win32.NtOpenThread( + out handle, + access, + ref oa, + ref clientId + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + } + finally + { + oa.Dispose(); + } + + this.Handle = handle; + } + + public ThreadHandle(string name, ThreadAccess access) + : this(name, 0, null, new ClientId(), access) + { } + + /// + /// Puts the thread in an alerted state. + /// + public void Alert() + { + NtStatus status; + + if ((status = Win32.NtAlertThread(this)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + /// + /// Resumes the thread in an alerted state. + /// + public int AlertResume() + { + NtStatus status; + int suspendCount; + + if ((status = Win32.NtAlertResumeThread(this, out suspendCount)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return suspendCount; + } + + /// + /// Captures a kernel-mode stack trace for the thread. + /// + /// An array of function addresses. + public IntPtr[] CaptureKernelStack() + { + return this.CaptureKernelStack(0); + } + + /// + /// Captures a kernel-mode stack trace for the thread. + /// + /// The number of frames to skip. + /// An array of function addresses. + public IntPtr[] CaptureKernelStack(int skipCount) + { + IntPtr[] stack = new IntPtr[62 - skipCount]; // 62 limit for XP and Server 2003 + int hash; + + // Capture a kernel-mode stack trace. + int captured = KProcessHacker.Instance.KphCaptureStackBackTraceThread( + this, + skipCount, + stack.Length, + stack, + out hash + ); + + // Create a new array with only the frames we captured. + IntPtr[] newStack = new IntPtr[captured]; + + Array.Copy(stack, 0, newStack, 0, captured); + + return newStack; + } + + /// + /// Captures a user-mode stack trace for the thread. + /// + /// An array of stack frames. + public ThreadStackFrame[] CaptureUserStack() + { + return this.CaptureUserStack(0); + } + + /// + /// Captures a user-mode stack trace for the thread. + /// + /// The number of frames to skip. + /// An array of stack frames. + public ThreadStackFrame[] CaptureUserStack(int skipCount) + { + List frames = new List(); + + // Walk the stack. + this.WalkStack((frame) => { frames.Add(frame); return true; }); + + // If we want to skip frames than we have, just return an empty array. + if (frames.Count <= skipCount) + return new ThreadStackFrame[0]; + + // Otherwise, create a new array with the frames, minus what we skipped. + ThreadStackFrame[] newFrames = new ThreadStackFrame[frames.Count - skipCount]; + + Array.Copy(frames.ToArray(), skipCount, newFrames, 0, newFrames.Length); + + return newFrames; + } + + /// + /// Attempts to terminate the thread using a dangerous method. This + /// operation may cause the system to crash. + /// + /// The exit status. + public void DangerousTerminate(NtStatus exitStatus) + { + KProcessHacker.Instance.KphDangerousTerminateThread(this, exitStatus); + } + + /// + /// Gets the thread's base priority. + /// + public int GetBasePriority() + { + return this.GetInformationInt32(ThreadInformationClass.ThreadBasePriority); + } + + /// + /// Gets the thread's base priority. + /// + /// A ThreadPriorityLevel enum. + public ThreadPriorityLevel GetBasePriorityWin32() + { + int priority = Win32.GetThreadPriority(this); + + if (priority == 0x7fffffff) + Win32.ThrowLastError(); + + return (ThreadPriorityLevel)priority; + } + + /// + /// Gets the thread's basic information. + /// + /// A THREAD_BASIC_INFORMATION structure. + public ThreadBasicInformation GetBasicInformation() + { + NtStatus status; + ThreadBasicInformation basicInfo = new ThreadBasicInformation(); + int retLen; + + if ((status = Win32.NtQueryInformationThread(this, ThreadInformationClass.ThreadBasicInformation, + ref basicInfo, Marshal.SizeOf(basicInfo), out retLen)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return basicInfo; + } + + /// + /// Gets the thread's context. + /// + /// A CONTEXT struct. + public Context GetContext(ContextFlags flags) + { + Context context = new Context(); + + context.ContextFlags = flags; + this.GetContext(ref context); + + return context; + } + + /// + /// Gets the thread's context. + /// + /// A Context structure. The ContextFlags must be set appropriately. + public unsafe void GetContext(ref Context context) + { + if (KProcessHacker.Instance != null) + { + fixed (Context* contextPtr = &context) + KProcessHacker.Instance.KphGetContextThread(this, contextPtr); + } + else + { + NtStatus status; + + if ((status = Win32.NtGetContextThread(this, ref context)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + } + + /// + /// Gets the thread's context. + /// + /// A CONTEXT struct. + public ContextAmd64 GetContext(ContextFlagsAmd64 flags) + { + ContextAmd64 context = new ContextAmd64(); + + context.ContextFlags = flags; + this.GetContext(ref context); + + return context; + } + + /// + /// Gets the thread's context. + /// + /// A Context structure. The ContextFlags must be set appropriately. + public void GetContext(ref ContextAmd64 context) + { + NtStatus status; + + // HACK: To avoid a datatype misalignment error, allocate some + // aligned memory. + using (var data = new AlignedMemoryAlloc(Utils.SizeOf(16), 16)) + { + data.WriteStruct(context); + + if ((status = Win32.NtGetContextThread(this, data)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + context = data.ReadStruct(); + } + } + + /// + /// Gets the thread's x86 context. The thread's process must be running + /// under WOW64. + /// + /// A Context structure. The ContextFlags must be set appropriately. + public void GetContextWow64(ref Context context) + { + NtStatus status; + + if ((status = Win32.RtlWow64GetThreadContext(this, ref context)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + /// + /// Gets the number of processor cycles consumed by the thread. + /// + public ulong GetCycleTime() + { + ulong cycles; + + if (!Win32.QueryThreadCycleTime(this, out cycles)) + Win32.ThrowLastError(); + + return cycles; + } + + /// + /// Gets the thread's exit code. + /// + /// A number. + public int GetExitCode() + { + int exitCode; + + if (!Win32.GetExitCodeThread(this, out exitCode)) + Win32.ThrowLastError(); + + return exitCode; + } + + /// + /// Gets the thread's exit status. + /// + /// A NT status value. + public NtStatus GetExitStatus() + { + return this.GetBasicInformation().ExitStatus; + } + + private int GetInformationInt32(ThreadInformationClass infoClass) + { + NtStatus status; + int value; + int retLength; + + if ((status = Win32.NtQueryInformationThread( + this, infoClass, out value, sizeof(int), out retLength)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return value; + } + + private IntPtr GetInformationIntPtr(ThreadInformationClass infoClass) + { + NtStatus status; + IntPtr value; + int retLength; + + if ((status = Win32.NtQueryInformationThread( + this, infoClass, out value, IntPtr.Size, out retLength)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return value; + } + + /// + /// Gets the thread's I/O priority. + /// + public int GetIoPriority() + { + return this.GetInformationInt32(ThreadInformationClass.ThreadIoPriority); + } + + /// + /// Gets the last system call the thread made. + /// + /// A system call number. + public int GetLastSystemCall() + { + int firstArgument; + + return this.GetLastSystemCall(out firstArgument); + } + + /// + /// Gets the last system call the thread made. + /// + /// The first argument to the last system call. + /// A system call number. + public unsafe int GetLastSystemCall(out int firstArgument) + { + NtStatus status; + int* data = stackalloc int[2]; + int retLength; + + if ((status = Win32.NtQueryInformationThread( + this, ThreadInformationClass.ThreadLastSystemCall, data, sizeof(int) * 2, out retLength)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + firstArgument = data[0]; + + return data[1]; + } + + /// + /// Gets the thread's page priority. + /// + public int GetPagePriority() + { + return this.GetInformationInt32(ThreadInformationClass.ThreadPagePriority); + } + + /// + /// Gets the thread's priority. + /// + public int GetPriority() + { + return this.GetInformationInt32(ThreadInformationClass.ThreadPriority); + } + + /// + /// Opens the thread's process. + /// + /// A process handle. + public ProcessHandle GetProcess(ProcessAccess access) + { + return new ProcessHandle(this, access); + } + + /// + /// Gets the thread's parent process' unique identifier. + /// + /// A process ID. + public int GetProcessId() + { + return this.GetBasicInformation().ClientId.ProcessId; + } + + /// + /// Gets the thread's unique identifier. + /// + /// A thread ID. + public int GetThreadId() + { + return this.GetBasicInformation().ClientId.ThreadId; + } + + /// + /// Opens and returns a handle to the thread's token. + /// + /// A handle to the thread's token. + public TokenHandle GetToken() + { + return GetToken(TokenAccess.All); + } + + /// + /// Opens and returns a handle to the thread's token. + /// + /// The desired access to the token. + /// A handle to the thread's token. + public TokenHandle GetToken(TokenAccess access) + { + return new TokenHandle(this, access); + } + + /// + /// Gets the thread's Win32 start address. + /// + public IntPtr GetWin32StartAddress() + { + return this.GetInformationIntPtr(ThreadInformationClass.ThreadQuerySetWin32StartAddress); + } + + /// + /// Causes the thread to impersonate a client thread. + /// + /// A handle to a client thread. + /// The impersonation level to request. + public void Impersonate(ThreadHandle clientThreadHandle, SecurityImpersonationLevel impersonationLevel) + { + NtStatus status; + SecurityQualityOfService securityQos = + new SecurityQualityOfService(impersonationLevel, false, false); + + if ((status = Win32.NtImpersonateThread(this, clientThreadHandle, ref securityQos)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + /// + /// Causes the thread to impersonate the anonymous account. + /// + public void ImpersonateAnonymous() + { + NtStatus status; + + if ((status = Win32.NtImpersonateAnonymousToken(this)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + /// + /// Gets whether the system will break (crash) upon the thread terminating. + /// + public bool IsCritical() + { + return this.GetInformationInt32(ThreadInformationClass.ThreadBreakOnTermination) != 0; + } + + /// + /// Gets whether any I/O request packets (IRPs) are still pending for the thread. + /// + public bool IsIoPending() + { + return this.GetInformationInt32(ThreadInformationClass.ThreadIsIoPending) != 0; + } + + /// + /// Gets whether the thread is the last in its process. + /// + public bool IsLastThread() + { + return this.GetInformationInt32(ThreadInformationClass.ThreadAmILastThread) != 0; + } + + /// + /// Gets whether priority boost is enabled for the thread. + /// + public bool IsPriorityBoostEnabled() + { + return this.GetInformationInt32(ThreadInformationClass.ThreadPriorityBoost) == 0; + } + + /// + /// Gets whether the thread has terminated. + /// + public bool IsTerminated() + { + return this.GetInformationInt32(ThreadInformationClass.ThreadIsTerminated) != 0; + } + + /// + /// Adds an user-mode asynchronous procedure call (APC) to the thread's APC queue. + /// This requires THREAD_SET_CONTEXT access. + /// + /// The address of the APC procedure. + /// The parameter to pass to the procedure. + public void QueueApc(IntPtr address, IntPtr parameter) + { + if (!Win32.QueueUserAPC(address, this, parameter)) + Win32.ThrowLastError(); + } + + /// + /// Adds an user-mode asynchronous procedure call (APC) to the thread's APC queue. + /// This requires THREAD_SET_CONTEXT access. + /// + /// The delegate to execute.. + /// The parameter to pass to the procedure. + public void QueueApc(ApcRoutine action, IntPtr parameter) + { + if (!Win32.QueueUserAPC(action, this, parameter)) + Win32.ThrowLastError(); + } + + /// + /// Queues a user-mode asynchronous procedure call (APC) to the thread. + /// + /// The address of the function to execute. + /// The first parameter to pass to the function. + /// The second parameter to pass to the function. + /// The third parameter to pass to the function. + public void QueueApc(IntPtr address, IntPtr param1, IntPtr param2, IntPtr param3) + { + NtStatus status; + + if ((status = Win32.NtQueueApcThread( + this, + address, + param1, + param2, + param3 + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + public void RemoteCall(IntPtr address, IntPtr[] arguments) + { + this.RemoteCall(address, arguments, false); + } + + public void RemoteCall(IntPtr address, IntPtr[] arguments, bool alreadySuspended) + { + ProcessHandle processHandle; + + if (KProcessHacker.Instance != null) + processHandle = this.GetProcess(ProcessAccess.VmWrite); + else + processHandle = new ProcessHandle(this.GetProcessId(), ProcessAccess.VmWrite); + + using (processHandle) + this.RemoteCall(processHandle, address, arguments, alreadySuspended); + } + + public void RemoteCall(ProcessHandle processHandle, IntPtr address, IntPtr[] arguments, bool alreadySuspended) + { + NtStatus status; + + if ((status = Win32.RtlRemoteCall( + processHandle, + this, + address, + arguments.Length, + arguments, + false, + alreadySuspended + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + /// + /// Resumes the thread. + /// + public int Resume() + { + NtStatus status; + int suspendCount; + + if ((status = Win32.NtResumeThread(this, out suspendCount)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return suspendCount; + } + + /// + /// Sets the thread's base priority. + /// + /// The thread's base priority. + public void SetBasePriority(int basePriority) + { + this.SetInformationInt32(ThreadInformationClass.ThreadBasePriority, basePriority); + } + + /// + /// Sets the thread's base priority. + /// + /// The base priority of the thread. + public void SetBasePriorityWin32(ThreadPriorityLevel basePriority) + { + if (!Win32.SetThreadPriority(this, (int)basePriority)) + Win32.ThrowLastError(); + } + + /// + /// Sets the thread's context. + /// + /// A CONTEXT struct. + public unsafe void SetContext(Context context) + { + if (KProcessHacker.Instance != null) + { + KProcessHacker.Instance.KphSetContextThread(this, &context); + } + else + { + NtStatus status; + + if ((status = Win32.NtSetContextThread(this, ref context)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + } + + /// + /// Sets the thread's context. + /// + /// A CONTEXT struct. + public void SetContext(ContextAmd64 context) + { + NtStatus status; + + // HACK: To avoid a datatype misalignment error, allocate + // some aligned memory. + using (var data = new AlignedMemoryAlloc(Utils.SizeOf(16), 16)) + { + data.WriteStruct(context); + + if ((status = Win32.NtSetContextThread(this, data)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + } + + /// + /// Sets the thread's x86 context. The thread's process must + /// be running under WOW64. + /// + /// A CONTEXT struct. + public void SetContextWow64(Context context) + { + NtStatus status; + + if ((status = Win32.RtlWow64SetThreadContext(this, ref context)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + /// + /// Sets whether the thread is critical. + /// + /// Whether the thread should be critical. + public void SetCritical(bool critical) + { + this.SetInformationInt32(ThreadInformationClass.ThreadBreakOnTermination, critical ? 1 : 0); + } + + private void SetInformationInt32(ThreadInformationClass infoClass, int value) + { + NtStatus status; + + if ((status = Win32.NtSetInformationThread( + this, infoClass, ref value, sizeof(int))) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + private void SetInformationIntPtr(ThreadInformationClass infoClass, IntPtr value) + { + NtStatus status; + + if ((status = Win32.NtSetInformationThread( + this, infoClass, ref value, sizeof(int))) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + /// + /// Sets the thread's priority. + /// + /// The thread's priority. + public void SetPriority(int priority) + { + this.SetInformationInt32(ThreadInformationClass.ThreadPriority, priority); + } + + /// + /// Sets the thread's priority boost. + /// + /// Whether priority boost will be enabled. + public void SetPriorityBoost(bool enabled) + { + this.SetInformationInt32(ThreadInformationClass.ThreadPriorityBoost, enabled ? 0 : 1); + } + + /// + /// Sets the thread's impersonation token. + /// + /// + /// A handle to a token. Specify null to cause the thread to stop + /// impersonating. + /// + public void SetToken(TokenHandle tokenHandle) + { + this.SetInformationIntPtr(ThreadInformationClass.ThreadImpersonationToken, tokenHandle ?? IntPtr.Zero); + } + + /// + /// Suspends the thread. + /// + public int Suspend() + { + NtStatus status; + int suspendCount; + + if ((status = Win32.NtSuspendThread(this, out suspendCount)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return suspendCount; + } + + /// + /// Terminates the thread. + /// + public void Terminate() + { + this.Terminate(NtStatus.Success); + } + + /// + /// Terminates the thread. + /// + /// The exit status. + public void Terminate(NtStatus exitStatus) + { + if (KProcessHacker.Instance != null) + { + try + { + KProcessHacker.Instance.KphTerminateThread(this, exitStatus); + return; + } + catch (WindowsException ex) + { + if (ex.ErrorCode != Win32Error.NotSupported) + throw ex; + } + } + + NtStatus status; + + if ((status = Win32.NtTerminateThread(this, exitStatus)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + /// + /// Walks the call stack for the thread. + /// + /// A callback to execute. + public void WalkStack(WalkStackDelegate walkStackCallback) + { + this.WalkStack(walkStackCallback, OSVersion.Architecture); + } + + /// + /// Walks the call stack for the thread. + /// + /// A callback to execute. + /// + /// The type of stack walk. On 32-bit systems, this value is ignored. + /// On 64-bit systems, this value can be set to I386 to walk the + /// 32-bit stack. + /// + public void WalkStack(WalkStackDelegate walkStackCallback, OSArch architecture) + { + if (KProcessHacker.Instance != null) + { + // Use KPH to open the parent process. + using (var phandle = this.GetProcess(ProcessAccess.QueryInformation | ProcessAccess.VmRead)) + this.WalkStack(phandle, walkStackCallback, architecture); + } + else + { + // We need to duplicate the handle to get QueryInformation access. + using (var dupThreadHandle = this.Duplicate(OSVersion.MinThreadQueryInfoAccess)) + using (var phandle = new ProcessHandle( + ThreadHandle.FromHandle(dupThreadHandle).GetBasicInformation().ClientId.ProcessId, + ProcessAccess.QueryInformation | ProcessAccess.VmRead + )) + { + this.WalkStack(phandle, walkStackCallback, architecture); + } + } + } + + /// + /// Walks the call stack for the thread. + /// + /// A handle to the thread's parent process. + /// A callback to execute. + public unsafe void WalkStack(ProcessHandle parentProcess, WalkStackDelegate walkStackCallback) + { + this.WalkStack(parentProcess, walkStackCallback, OSVersion.Architecture); + } + + /// + /// Walks the call stack for the thread. + /// + /// A handle to the thread's parent process. + /// A callback to execute. + /// + /// The type of stack walk. On 32-bit systems, this value is ignored. + /// On 64-bit systems, this value can be set to I386 to walk the + /// 32-bit stack. + /// + public unsafe void WalkStack(ProcessHandle parentProcess, WalkStackDelegate walkStackCallback, OSArch architecture) + { + bool suspended = false; + + // Suspend the thread to avoid inaccurate thread stacks. + try + { + this.Suspend(); + suspended = true; + } + catch (WindowsException) + { + suspended = false; + } + + // Use KPH for reading memory if we can. + ReadProcessMemoryProc64 readMemoryProc = null; + + if (KProcessHacker.Instance != null) + { + readMemoryProc = new ReadProcessMemoryProc64( + delegate(IntPtr processHandle, ulong baseAddress, IntPtr buffer, int size, out int bytesRead) + { + return KProcessHacker.Instance.KphReadVirtualMemorySafe( + ProcessHandle.FromHandle(processHandle), (int)baseAddress, buffer, size, out bytesRead); + }); + } + + try + { + // x86/WOW64 stack walk. + if (IntPtr.Size == 4 || (IntPtr.Size == 8 && architecture == OSArch.I386)) + { + Context context = new Context(); + + context.ContextFlags = ContextFlags.All; + + if (IntPtr.Size == 4) + { + // Get the context. + this.GetContext(ref context); + } + else + { + // Get the WOW64 x86 context. + this.GetContextWow64(ref context); + } + + // Set up the initial stack frame structure. + var stackFrame = new StackFrame64(); + + stackFrame.AddrPC.Mode = AddressMode.AddrModeFlat; + stackFrame.AddrPC.Offset = (ulong)context.Eip; + stackFrame.AddrStack.Mode = AddressMode.AddrModeFlat; + stackFrame.AddrStack.Offset = (ulong)context.Esp; + stackFrame.AddrFrame.Mode = AddressMode.AddrModeFlat; + stackFrame.AddrFrame.Offset = (ulong)context.Ebp; + + while (true) + { + using (Win32.DbgHelpLock.AcquireContext()) + { + if (!Win32.StackWalk64( + MachineType.I386, + parentProcess, + this, + ref stackFrame, + ref context, + readMemoryProc, + Win32.SymFunctionTableAccess64, + Win32.SymGetModuleBase64, + IntPtr.Zero + )) + break; + } + + // If we got an invalid eip, break. + if (stackFrame.AddrPC.Offset == 0) + break; + + // Execute the callback. + if (!walkStackCallback(new ThreadStackFrame(ref stackFrame))) + break; + } + } + // x64 stack walk. + else if (IntPtr.Size == 8) + { + ContextAmd64 context = new ContextAmd64(); + + context.ContextFlags = ContextFlagsAmd64.All; + // Get the context. + this.GetContext(ref context); + + // Set up the initial stack frame structure. + var stackFrame = new StackFrame64(); + + stackFrame.AddrPC.Mode = AddressMode.AddrModeFlat; + stackFrame.AddrPC.Offset = (ulong)context.Rip; + stackFrame.AddrStack.Mode = AddressMode.AddrModeFlat; + stackFrame.AddrStack.Offset = (ulong)context.Rsp; + stackFrame.AddrFrame.Mode = AddressMode.AddrModeFlat; + stackFrame.AddrFrame.Offset = (ulong)context.Rbp; + + while (true) + { + using (Win32.DbgHelpLock.AcquireContext()) + { + if (!Win32.StackWalk64( + MachineType.Amd64, + parentProcess, + this, + ref stackFrame, + ref context, + readMemoryProc, + Win32.SymFunctionTableAccess64, + Win32.SymGetModuleBase64, + IntPtr.Zero + )) + break; + } + + // If we got an invalid rip, break. + if (stackFrame.AddrPC.Offset == 0) + break; + + // Execute the callback. + if (!walkStackCallback(new ThreadStackFrame(ref stackFrame))) + break; + } + } + } + finally + { + // If we suspended the thread before, resume it. + if (suspended) + { + try + { + this.Resume(); + } + catch (WindowsException) + { } + } + } + } + } + + public class ThreadStackFrame + { + private IntPtr _pcAddress; + private IntPtr _returnAddress; + private IntPtr _frameAddress; + private IntPtr _stackAddress; + private IntPtr _bStoreAddress; + private IntPtr[] _params; + + internal ThreadStackFrame(ref StackFrame64 stackFrame) + { + _pcAddress = new IntPtr((long)stackFrame.AddrPC.Offset); + _returnAddress = new IntPtr((long)stackFrame.AddrReturn.Offset); + _frameAddress = new IntPtr((long)stackFrame.AddrFrame.Offset); + _stackAddress = new IntPtr((long)stackFrame.AddrStack.Offset); + _bStoreAddress = new IntPtr((long)stackFrame.AddrBStore.Offset); + _params = new IntPtr[4]; + + for (int i = 0; i < 4; i++) + _params[i] = new IntPtr(stackFrame.Params[i]); + } + + public IntPtr PcAddress { get { return _pcAddress; } } + public IntPtr ReturnAddress { get { return _returnAddress; } } + public IntPtr FrameAddress { get { return _frameAddress; } } + public IntPtr StackAddress { get { return _stackAddress; } } + public IntPtr BStoreAddress { get { return _bStoreAddress; } } + public IntPtr[] Params { get { return _params; } } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/TimerHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/TimerHandle.cs new file mode 100644 index 000000000..b9cde6bdc --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/TimerHandle.cs @@ -0,0 +1,230 @@ +using System; +using System.Runtime.InteropServices; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + public sealed class TimerHandle : NativeHandle + { + /// + /// Creates a timer. + /// + /// The desired access to the timer. + /// + /// The type of timer; synchronization timers will be reset once waiting threads are released. + /// + /// A handle to the timer. + public static TimerHandle Create(TimerAccess access, TimerType type) + { + return Create(access, null, type); + } + + /// + /// Creates a timer. + /// + /// The desired access to the timer. + /// A name for the timer in the object manager namespace. + /// + /// The type of timer; synchronization timers will be reset once waiting threads are released. + /// + /// A handle to the timer. + public static TimerHandle Create(TimerAccess access, string name, TimerType type) + { + return Create(access, name, 0, null, type); + } + + /// + /// Creates a timer. + /// + /// The desired access to the timer. + /// A name for the timer in the object manager namespace. + /// The flags to use when creating the object. + /// The directory in which to place the timer. This can be null. + /// + /// The type of timer; synchronization timers will be reset once waiting threads are released. + /// + /// A handle to the timer. + public static TimerHandle Create(TimerAccess access, string name, ObjectFlags objectFlags, DirectoryHandle rootDirectory, TimerType type) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtCreateTimer(out handle, access, ref oa, type)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + return new TimerHandle(handle, true); + } + + public static TimerHandle FromHandle(IntPtr handle) + { + return new TimerHandle(handle, false); + } + + private TimerApcRoutine _routine; + + private TimerHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + public TimerHandle(string name, ObjectFlags objectFlags, DirectoryHandle rootDirectory, TimerAccess access) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtOpenTimer(out handle, access, ref oa)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + this.Handle = handle; + } + + public TimerHandle(string name, TimerAccess access) + : this(name, 0, null, access) + { } + + /// + /// Cancels the timer, preventing it from being signaled. + /// + /// The state of the timer (whether it is signaled). + public bool Cancel() + { + NtStatus status; + bool currentState; + + if ((status = Win32.NtCancelTimer(this, out currentState)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return currentState; + } + + /// + /// Gets information about the timer. + /// + public TimerBasicInformation GetBasicInformation() + { + NtStatus status; + TimerBasicInformation tbi; + int retLength; + + if ((status = Win32.NtQueryTimer(this, TimerInformationClass.TimerBasicInformation, + out tbi, Marshal.SizeOf(typeof(TimerBasicInformation)), out retLength)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return tbi; + } + + /// + /// Sets the timer. + /// + /// The time at which the timer is to be signaled. + /// + /// The time interval for periodic signaling of the timer, in milliseconds. + /// Specify 0 for no periodic signaling. + /// + /// The state of the timer (whether it is signaled). + public bool Set(DateTime dueTime, int period) + { + return this.Set(dueTime.ToFileTime(), false, null, IntPtr.Zero, period); + } + + /// + /// Sets the timer. + /// + /// A relative due time, in 100ns units. + /// + /// The time interval for periodic signaling of the timer, in milliseconds. + /// Specify 0 for no periodic signaling. + /// + /// The state of the timer (whether it is signaled). + public bool Set(long dueTime, int period) + { + return this.Set(dueTime, null, period); + } + + /// + /// Sets the timer. + /// + /// A relative due time, in 100ns units. + /// A routine to call when the timer is signaled. + /// + /// The time interval for periodic signaling of the timer, in milliseconds. + /// Specify 0 for no periodic signaling. + /// + /// The state of the timer (whether it is signaled). + public bool Set(long dueTime, TimerApcRoutine routine, int period) + { + return this.Set(dueTime, true, routine, IntPtr.Zero, period); + } + + /// + /// Sets the timer. + /// + /// A due time, in 100ns units. + /// Whether the due time is relative. + /// A routine to call when the timer is signaled. + /// A value to pass to the timer callback routine. + /// + /// The time interval for periodic signaling of the timer, in milliseconds. + /// Specify 0 for no periodic signaling. + /// + /// The state of the timer (whether it is signaled). + public bool Set(long dueTime, bool relative, TimerApcRoutine routine, IntPtr context, int period) + { + return this.Set(dueTime, relative, routine, context, false, period); + } + + /// + /// Sets the timer. + /// + /// A due time, in 100ns units. + /// Whether the due time is relative. + /// A routine to call when the timer is signaled. + /// A value to pass to the timer callback routine. + /// + /// Whether the power manager should restore the system when the timer is signaled. + /// + /// + /// The time interval for periodic signaling of the timer, in milliseconds. + /// Specify 0 for no periodic signaling. + /// + /// The state of the timer (whether it is signaled). + public bool Set(long dueTime, bool relative, TimerApcRoutine routine, IntPtr context, bool resume, int period) + { + NtStatus status; + long realDueTime = relative ? -dueTime : dueTime; + bool previousState; + + // Keep the APC routine alive. + _routine = routine; + + if ((status = Win32.NtSetTimer( + this, + ref realDueTime, + routine, + context, + resume, + period, + out previousState + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return previousState; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/TmHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/TmHandle.cs new file mode 100644 index 000000000..fed50b2e6 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/TmHandle.cs @@ -0,0 +1,220 @@ +/* + * Process Hacker - + * transaction manager handle + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Runtime.InteropServices; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + public class TmHandle : NativeHandle + { + public static TmHandle Create( + TmAccess access, + string name, + ObjectFlags objectFlags, + DirectoryHandle rootDirectory, + string logFileName, + TmOptions createOptions + ) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + UnicodeString logFileNameStr = new UnicodeString(logFileName); + + try + { + if ((status = Win32.NtCreateTransactionManager( + out handle, + access, + ref oa, + ref logFileNameStr, + createOptions, + 0 + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + logFileNameStr.Dispose(); + } + } + finally + { + oa.Dispose(); + } + + return new TmHandle(handle, true); + } + + public static TmHandle FromHandle(IntPtr handle) + { + return new TmHandle(handle, false); + } + + private TmHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + public TmHandle(string name, ObjectFlags objectFlags, DirectoryHandle rootDirectory, TmAccess access) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtOpenTransactionManager( + out handle, + access, + ref oa, + IntPtr.Zero, + IntPtr.Zero, + 0 + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + this.Handle = handle; + } + + public TmBasicInformation GetBasicInformation() + { + NtStatus status; + TmBasicInformation basicInfo; + int retLength; + + if ((status = Win32.NtQueryInformationTransactionManager( + this, + TmInformationClass.TransactionManagerBasicInformation, + out basicInfo, + Marshal.SizeOf(typeof(TmBasicInformation)), + out retLength + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return basicInfo; + } + + public long GetLastRecoveredLsn() + { + NtStatus status; + TmRecoveryInformation recoveryInfo; + int retLength; + + if ((status = Win32.NtQueryInformationTransactionManager( + this, + TmInformationClass.TransactionManagerRecoveryInformation, + out recoveryInfo, + Marshal.SizeOf(typeof(TmRecoveryInformation)), + out retLength + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return recoveryInfo.LastRecoveredLsn; + } + + public string GetLogFileName() + { + NtStatus status; + int retLength; + + using (var data = new MemoryAlloc(0x1000)) + { + status = Win32.NtQueryInformationTransactionManager( + this, + TmInformationClass.TransactionManagerLogPathInformation, + data, + data.Size, + out retLength + ); + + if (status == NtStatus.BufferTooSmall) + { + // Resize the buffer and try again. + data.Resize(retLength); + + status = Win32.NtQueryInformationTransactionManager( + this, + TmInformationClass.TransactionManagerLogPathInformation, + data, + data.Size, + out retLength + ); + } + + if (status >= NtStatus.Error) + Win32.ThrowLastError(status); + + TmLogPathInformation logPathInfo = data.ReadStruct(); + + return data.ReadUnicodeString(TmLogPathInformation.LogPathOffset, logPathInfo.LogPathLength); + } + } + + public Guid GetLogIdentity() + { + NtStatus status; + TmLogInformation logInfo; + int retLength; + + if ((status = Win32.NtQueryInformationTransactionManager( + this, + TmInformationClass.TransactionManagerLogInformation, + out logInfo, + Marshal.SizeOf(typeof(TmLogInformation)), + out retLength + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return logInfo.LogIdentity; + } + + public void Recover() + { + NtStatus status; + + if ((status = Win32.NtRecoverTransactionManager(this)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + public void Rollforward(long virtualClock) + { + NtStatus status; + + if ((status = Win32.NtRollforwardTransactionManager( + this, + ref virtualClock + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/TokenHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/TokenHandle.cs new file mode 100644 index 000000000..455a2e830 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/TokenHandle.cs @@ -0,0 +1,595 @@ +/* + * Process Hacker - + * token handle + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Runtime.InteropServices; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; +using ProcessHacker.Native.Security.AccessControl; + +namespace ProcessHacker.Native.Objects +{ + /// + /// Represents a handle to a Windows token. + /// + public sealed class TokenHandle : NativeHandle, IEquatable + { + private static readonly TokenSource _phTokenSource = new TokenSource("PROCHACK", Luid.Allocate()); + + public static TokenHandle Create( + TokenAccess access, + TokenType tokenType, + Sid user, + Sid[] groups, + PrivilegeSet privileges + ) + { + using (var administratorsSid = Sid.GetWellKnownSid(WellKnownSidType.WinBuiltinAdministratorsSid)) + using (var thandle = TokenHandle.OpenCurrentPrimary(TokenAccess.Query)) + return Create(access, 0, thandle, tokenType, user, groups, privileges, administratorsSid, administratorsSid); + } + + public static TokenHandle Create( + TokenAccess access, + ObjectFlags objectFlags, + TokenHandle existingTokenHandle, + TokenType tokenType, + Sid user, + Sid[] groups, + PrivilegeSet privileges, + Sid owner, + Sid primaryGroup + ) + { + var statistics = existingTokenHandle.GetStatistics(); + + return Create( + access, + null, + objectFlags, + null, + tokenType, + statistics.AuthenticationId, + statistics.ExpirationTime, + user, + groups, + privileges, + owner, + primaryGroup, + null, + _phTokenSource + ); + } + + public static TokenHandle Create( + TokenAccess access, + string name, + ObjectFlags objectFlags, + DirectoryHandle rootDirectory, + TokenType tokenType, + Luid authenticationId, + long expirationTime, + Sid user, + Sid[] groups, + PrivilegeSet privileges, + Sid owner, + Sid primaryGroup, + Acl defaultDacl, + TokenSource source + ) + { + NtStatus status; + TokenUser tokenUser = new TokenUser(user); + TokenGroups tokenGroups = new TokenGroups(groups); + TokenPrivileges tokenPrivileges = new TokenPrivileges(privileges); + TokenOwner tokenOwner = new TokenOwner(owner); + TokenPrimaryGroup tokenPrimaryGroup = new TokenPrimaryGroup(primaryGroup); + TokenDefaultDacl tokenDefaultDacl = new TokenDefaultDacl(defaultDacl); + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtCreateToken( + out handle, + access, + ref oa, + tokenType, + ref authenticationId, + ref expirationTime, + ref tokenUser, + ref tokenGroups, + ref tokenPrivileges, + ref tokenOwner, + ref tokenPrimaryGroup, + ref tokenDefaultDacl, + ref source + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + return new TokenHandle(handle, true); + } + + /// + /// Creates a token handle using an existing handle. + /// The handle will not be closed automatically. + /// + /// The handle value. + /// The token handle. + public static TokenHandle FromHandle(IntPtr handle) + { + return new TokenHandle(handle, false); + } + + public static TokenHandle Logon(string username, string domain, string password, LogonType logonType, LogonProvider logonProvider) + { + IntPtr token; + + if (!Win32.LogonUser(username, domain, password, logonType, logonProvider, out token)) + Win32.ThrowLastError(); + + return new TokenHandle(token, true); + } + + public static TokenHandle OpenCurrent(TokenAccess access) + { + return new TokenHandle(ThreadHandle.GetCurrent(), access, false); + } + + public static TokenHandle OpenCurrentPrimary(TokenAccess access) + { + return new TokenHandle(ProcessHandle.Current, access); + } + + public static TokenHandle OpenSelf(TokenAccess access) + { + return new TokenHandle(ThreadHandle.GetCurrent(), access, true); + } + + public static TokenHandle OpenSystemToken(TokenAccess access) + { + using (var phandle = new ProcessHandle(4, OSVersion.MinProcessQueryInfoAccess)) + { + return phandle.GetToken(access); + } + } + + public static TokenHandle OpenSystemToken(TokenAccess access, SecurityImpersonationLevel impersonationLevel, TokenType type) + { + using (var phandle = new ProcessHandle(4, OSVersion.MinProcessQueryInfoAccess)) + { + using (var thandle = phandle.GetToken(TokenAccess.Duplicate | access)) + { + return thandle.Duplicate(access, impersonationLevel, type); + } + } + } + + public TokenHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + /// + /// Creates a new token handle from a process. + /// + /// The process handle. + /// The desired access to the token. + public TokenHandle(ProcessHandle handle, TokenAccess access) + { + IntPtr h; + + if (KProcessHacker.Instance != null) + { + h = new IntPtr(KProcessHacker.Instance.KphOpenProcessToken(handle, access)); + } + else + { + if (!Win32.OpenProcessToken(handle, access, out h)) + { + this.MarkAsInvalid(); + Win32.ThrowLastError(); + } + } + + this.Handle = h; + } + + /// + /// Creates a new token handle from a thread. + /// + /// The thread handle. + /// The desired access to the token. + public TokenHandle(ThreadHandle handle, TokenAccess access) + : this(handle, access, false) + { } + + /// + /// Creates a new token handle from a thread. + /// + /// The thread handle. + /// The desired access to the token. + /// If the thread is currently impersonating, opens the original token. + public TokenHandle(ThreadHandle handle, TokenAccess access, bool openAsSelf) + { + IntPtr h; + + if (!Win32.OpenThreadToken(handle, access, openAsSelf, out h)) + { + this.MarkAsInvalid(); + Win32.ThrowLastError(); + } + + this.Handle = h; + } + + public void AdjustGroups(Sid[] groups) + { + TokenGroups tokenGroups = new TokenGroups(); + + tokenGroups.GroupCount = groups.Length; + tokenGroups.Groups = new SidAndAttributes[groups.Length]; + + for (int i = 0; i < groups.Length; i++) + tokenGroups.Groups[i] = groups[i].ToSidAndAttributes(); + + if (!Win32.AdjustTokenGroups(this, false, ref tokenGroups, 0, IntPtr.Zero, IntPtr.Zero)) + Win32.ThrowLastError(); + } + + public void AdjustPrivileges(PrivilegeSet privileges) + { + var tokenPrivileges = privileges.ToTokenPrivileges(); + + Win32.AdjustTokenPrivileges(this, false, ref tokenPrivileges, 0, IntPtr.Zero, IntPtr.Zero); + + if (Marshal.GetLastWin32Error() != 0) + Win32.ThrowLastError(); + } + + public bool CheckPrivileges(PrivilegeSet privileges) + { + NtStatus status; + bool result; + + using (var privilegesMemory = privileges.ToMemory()) + { + if ((status = Win32.NtPrivilegeCheck( + this, + privilegesMemory, + out result + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return result; + } + } + + /// + /// Duplicates the token. + /// + /// The desired access to the new token. + /// The new impersonation level. + /// The new token type. + /// A new token. + public TokenHandle Duplicate(TokenAccess access, SecurityImpersonationLevel impersonationLevel, TokenType type) + { + IntPtr token; + + if (!Win32.DuplicateTokenEx(this, access, IntPtr.Zero, impersonationLevel, type, out token)) + Win32.ThrowLastError(); + + return new TokenHandle(token, true); + } + + /// + /// Determins whether the token is the same as another token. + /// + /// The other token. + /// Whether they are equal. + public bool Equals(TokenHandle other) + { + NtStatus status; + bool equal; + + if ((status = Win32.NtCompareTokens( + this, + other, + out equal + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return equal; + } + + /// + /// Gets the elevation type of the token. + /// + /// A TOKEN_ELEVATION_TYPE enum. + public TokenElevationType GetElevationType() + { + return (TokenElevationType)this.GetInformationInt32(TokenInformationClass.TokenElevationType); + } + + /// + /// Gets the token's groups. + /// + /// A TokenGroupsData struct. + public Sid[] GetGroups() + { + return this.GetGroupsInternal(TokenInformationClass.TokenGroups); + } + + private Sid[] GetGroupsInternal(TokenInformationClass infoClass) + { + int retLen = 0; + + Win32.GetTokenInformation(this, infoClass, IntPtr.Zero, 0, out retLen); + + using (MemoryAlloc data = new MemoryAlloc(retLen)) + { + if (!Win32.GetTokenInformation(this, infoClass, data, + data.Size, out retLen)) + Win32.ThrowLastError(); + + int count = data.ReadStruct().GroupCount; + Sid[] sids = new Sid[count]; + + for (int i = 0; i < count; i++) + { + var saa = data.ReadStruct(TokenGroups.GroupsOffset, i); + sids[i] = new Sid(saa.Sid, saa.Attributes); + } + + return sids; + } + } + + private int GetInformationInt32(TokenInformationClass infoClass) + { + int value; + int retLen; + + if (!Win32.GetTokenInformation(this, infoClass, out value, sizeof(int), out retLen)) + Win32.ThrowLastError(); + + return value; + } + + /// + /// Gets the token's owner. + /// + /// A WindowsSID instance. + public Sid GetOwner() + { + int retLen; + + Win32.GetTokenInformation(this, TokenInformationClass.TokenOwner, IntPtr.Zero, 0, out retLen); + + using (MemoryAlloc data = new MemoryAlloc(retLen)) + { + if (!Win32.GetTokenInformation(this, TokenInformationClass.TokenOwner, data, + data.Size, out retLen)) + Win32.ThrowLastError(); + + return new Sid(data.ReadIntPtr(0)); + } + } + + /// + /// Gets the token's primary group. + /// + /// A WindowsSID instance. + public Sid GetPrimaryGroup() + { + int retLen; + + Win32.GetTokenInformation(this, TokenInformationClass.TokenPrimaryGroup, IntPtr.Zero, 0, out retLen); + + using (MemoryAlloc data = new MemoryAlloc(retLen)) + { + if (!Win32.GetTokenInformation(this, TokenInformationClass.TokenPrimaryGroup, data, + data.Size, out retLen)) + Win32.ThrowLastError(); + + return new Sid(data.ReadIntPtr(0)); + } + } + + /// + /// Gets the token's privileges. + /// + /// A TOKEN_PRIVILEGES structure. + public Privilege[] GetPrivileges() + { + int retLen; + + Win32.GetTokenInformation(this, TokenInformationClass.TokenPrivileges, IntPtr.Zero, 0, out retLen); + + using (MemoryAlloc data = new MemoryAlloc(retLen)) + { + if (!Win32.GetTokenInformation(this, TokenInformationClass.TokenPrivileges, data, + data.Size, out retLen)) + Win32.ThrowLastError(); + + uint count = data.ReadUInt32(0); + Privilege[] privileges = new Privilege[count]; + + for (int i = 0; i < count; i++) + { + var laa = data.ReadStruct(sizeof(int), i); + privileges[i] = new Privilege(this, laa.Luid, laa.Attributes); + } + + return privileges; + } + } + + /// + /// Gets the restricted token's restricting SIDs. + /// + /// A TokenGroupsData struct. + public Sid[] GetRestrictingGroups() + { + return this.GetGroupsInternal(TokenInformationClass.TokenRestrictedSids); + } + + /// + /// Gets the token's session ID. + /// + /// The session ID. + public int GetSessionId() + { + return this.GetInformationInt32(TokenInformationClass.TokenSessionId); + } + + /// + /// Gets the token's source. + /// + /// A TOKEN_SOURCE struct. + public TokenSource GetSource() + { + TokenSource source; + int retLen; + + if (!Win32.GetTokenInformation(this, TokenInformationClass.TokenSource, + out source, Marshal.SizeOf(typeof(TokenSource)), out retLen)) + Win32.ThrowLastError(); + + return source; + } + + /// + /// Gets statistics about the token. + /// + /// A TOKEN_STATISTICS structure. + public TokenStatistics GetStatistics() + { + TokenStatistics statistics; + int retLen; + + if (!Win32.GetTokenInformation(this, TokenInformationClass.TokenStatistics, + out statistics, Marshal.SizeOf(typeof(TokenStatistics)), out retLen)) + Win32.ThrowLastError(); + + return statistics; + } + + /// + /// Gets the token's user. + /// + /// A WindowsSID instance. + public Sid GetUser() + { + int retLen; + + Win32.GetTokenInformation(this, TokenInformationClass.TokenUser, IntPtr.Zero, 0, out retLen); + + using (MemoryAlloc data = new MemoryAlloc(retLen)) + { + if (!Win32.GetTokenInformation(this.Handle, TokenInformationClass.TokenUser, data, + data.Size, out retLen)) + Win32.ThrowLastError(); + + TokenUser user = data.ReadStruct(); + + return new Sid(user.User.Sid, user.User.Attributes); + } + } + + /// + /// Gets whether the token has UAC elevation applied. + /// + /// A boolean. + public bool IsElevated() + { + return this.GetInformationInt32(TokenInformationClass.TokenElevation) != 0; + } + + /// + /// Gets whether virtualization is allowed. + /// + /// A boolean. + public bool IsVirtualizationAllowed() + { + return this.GetInformationInt32(TokenInformationClass.TokenVirtualizationAllowed) != 0; + } + + /// + /// Gets whether virtualization is enabled. + /// + /// A boolean. + public bool IsVirtualizationEnabled() + { + return this.GetInformationInt32(TokenInformationClass.TokenVirtualizationEnabled) != 0; + } + + /// + /// Sets a privilege's attributes. + /// + /// The name of the privilege. + /// The new attributes of the privilege. + public void SetPrivilege(string privilegeName, SePrivilegeAttributes attributes) + { + Luid privilegeLuid; + + if (!Win32.LookupPrivilegeValue(null, privilegeName, out privilegeLuid)) + throw new Exception("Invalid privilege name '" + privilegeName + "'."); + + this.SetPrivilege(privilegeLuid, attributes); + } + + public void SetPrivilege(Luid privilegeLuid, SePrivilegeAttributes attributes) + { + TokenPrivileges tkp = new TokenPrivileges(); + + tkp.Privileges = new LuidAndAttributes[1]; + + tkp.PrivilegeCount = 1; + tkp.Privileges[0].Attributes = attributes; + tkp.Privileges[0].Luid = privilegeLuid; + + Win32.AdjustTokenPrivileges(this, false, ref tkp, 0, IntPtr.Zero, IntPtr.Zero); + + if (Marshal.GetLastWin32Error() != 0) + Win32.ThrowLastError(); + } + + /// + /// Sets whether virtualization is enabled. + /// + /// Whether virtualization is enabled. + public void SetVirtualizationEnabled(bool enabled) + { + int value = enabled ? 1 : 0; + + if (!Win32.SetTokenInformation(this, TokenInformationClass.TokenVirtualizationEnabled, ref value, 4)) + { + Win32.ThrowLastError(); + } + } + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/TokenWithLinkedToken.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/TokenWithLinkedToken.cs new file mode 100644 index 000000000..7089a519c --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/TokenWithLinkedToken.cs @@ -0,0 +1,55 @@ +/* + * Process Hacker - + * a token with a linked token + * + * Copyright (C) 2008 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 . + */ + +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; +using System; + +namespace ProcessHacker.Native.Objects +{ + public sealed class TokenWithLinkedToken : IWithToken + { + private TokenHandle _token; + + public TokenWithLinkedToken(TokenHandle token) + { + _token = token; + } + + public TokenHandle GetToken() + { + IntPtr linkedToken; + int retLen; + + if (!Win32.GetTokenInformation(_token, TokenInformationClass.TokenLinkedToken, + out linkedToken, IntPtr.Size, out retLen)) + Win32.ThrowLastError(); + + return new TokenHandle(linkedToken, true); + } + + public TokenHandle GetToken(TokenAccess access) + { + return this.GetToken(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/TransactionHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/TransactionHandle.cs new file mode 100644 index 000000000..887893dbd --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/TransactionHandle.cs @@ -0,0 +1,213 @@ +/* + * Process Hacker - + * transaction handle + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Runtime.InteropServices; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + public class TransactionHandle : NativeHandle + { + public static TransactionHandle Create( + TransactionAccess access, + string name, + ObjectFlags objectFlags, + DirectoryHandle rootDirectory, + Guid unitOfWorkGuid, + TmHandle tmHandle, + TransactionOptions createOptions, + long timeout, + string description + ) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + UnicodeString descriptionStr = new UnicodeString(description); + + try + { + if ((status = Win32.NtCreateTransaction( + out handle, + access, + ref oa, + ref unitOfWorkGuid, + tmHandle ?? IntPtr.Zero, + createOptions, + 0, + 0, + ref timeout, + ref descriptionStr + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + descriptionStr.Dispose(); + } + } + finally + { + oa.Dispose(); + } + + return new TransactionHandle(handle, true); + } + + private TransactionHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + public TransactionHandle( + string name, + ObjectFlags objectFlags, + DirectoryHandle rootDirectory, + Guid unitOfWorkGuid, + TmHandle tmHandle, + TransactionAccess access + ) + { + NtStatus status; + ObjectAttributes oa = new ObjectAttributes(name, objectFlags, rootDirectory); + IntPtr handle; + + try + { + if ((status = Win32.NtOpenTransaction( + out handle, + access, + ref oa, + ref unitOfWorkGuid, + tmHandle ?? IntPtr.Zero + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + oa.Dispose(); + } + + this.Handle = handle; + } + + public static TransactionHandle FromHandle(IntPtr handle) + { + return new TransactionHandle(handle, false); + } + + public void Commit(bool wait) + { + NtStatus status; + + if ((status = Win32.NtCommitTransaction(this, wait)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + public TransactionBasicInformation GetBasicInformation() + { + NtStatus status; + TransactionBasicInformation basicInfo; + int retLength; + + if ((status = Win32.NtQueryInformationTransaction( + this, + TransactionInformationClass.TransactionBasicInformation, + out basicInfo, + Marshal.SizeOf(typeof(TransactionBasicInformation)), + out retLength + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return basicInfo; + } + + public string GetDescription() + { + using (var data = this.GetPropertiesInformation()) + { + var propertiesInfo = data.ReadStruct(); + + return data.ReadUnicodeString( + TransactionPropertiesInformation.DescriptionOffset, + propertiesInfo.DescriptionLength / 2 + ); + } + } + + private MemoryAlloc GetPropertiesInformation() + { + NtStatus status; + int retLength; + + var data = new MemoryAlloc(0x1000); + + status = Win32.NtQueryInformationTransaction( + this, + TransactionInformationClass.TransactionPropertiesInformation, + data, + data.Size, + out retLength + ); + + if (status == NtStatus.BufferTooSmall) + { + // Resize the buffer and try again. + data.Resize(retLength); + + status = Win32.NtQueryInformationTransaction( + this, + TransactionInformationClass.TransactionPropertiesInformation, + data, + data.Size, + out retLength + ); + } + + if (status >= NtStatus.Error) + { + data.Dispose(); + Win32.ThrowLastError(status); + } + + return data; + } + + public long GetTimeout() + { + using (var data = this.GetPropertiesInformation()) + return data.ReadStruct().Timeout; + } + + public void Rollback(bool wait) + { + NtStatus status; + + if ((status = Win32.NtRollbackTransaction(this, wait)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/UserHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/UserHandle.cs new file mode 100644 index 000000000..d93980054 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/UserHandle.cs @@ -0,0 +1,50 @@ +/* + * Process Hacker - + * USER handle + * + * Copyright (C) 2009 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 . + */ + +using System; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security.AccessControl; + +namespace ProcessHacker.Native.Objects +{ + public abstract class UserHandle : NativeHandle + where TAccess : struct + { + protected UserHandle() + : base() + { } + + protected UserHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + public override SecurityDescriptor GetSecurity(SecurityInformation securityInformation) + { + return this.GetSecurity(SeObjectType.WindowObject, securityInformation); + } + + public override void SetSecurity(SecurityInformation securityInformation, SecurityDescriptor securityDescriptor) + { + this.SetSecurity(SeObjectType.WindowObject, securityInformation, securityDescriptor); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/WindowHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/WindowHandle.cs new file mode 100644 index 000000000..df9774f5e --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/WindowHandle.cs @@ -0,0 +1,200 @@ +using System; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Text; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native.Objects +{ + public delegate bool EnumerateWindowsDelegate(WindowHandle windowHandle); + + public struct WindowHandle : IEquatable, IEquatable + { + private static WindowHandle _zero = new WindowHandle(IntPtr.Zero); + + public static WindowHandle Zero + { + get { return _zero; } + } + + public static bool Enumerate(EnumerateWindowsDelegate callback) + { + return Win32.EnumWindows((hWnd, param) => callback(new WindowHandle(hWnd)), 0); + } + + public static bool EnumerateByThreadId(int tid, EnumerateWindowsDelegate callback) + { + return Win32.EnumThreadWindows(tid, (hWnd, param) => callback(new WindowHandle(hWnd)), 0); + } + + public static WindowHandle Find(string className, string windowName) + { + IntPtr handle = Win32.FindWindow(className, windowName); + + return new WindowHandle(handle); + } + + public static WindowHandle GetDesktopWindow() + { + return new WindowHandle(Win32.GetDesktopWindow()); + } + + public static WindowHandle GetForegroundWindow() + { + return new WindowHandle(Win32.GetForegroundWindow()); + } + + public static WindowHandle GetShellWindow() + { + return new WindowHandle(Win32.GetShellWindow()); + } + + public static implicit operator IntPtr(WindowHandle windowHandle) + { + return windowHandle.Handle; + } + + private IntPtr _handle; + + public WindowHandle(IntPtr handle) + { + _handle = handle; + } + + public IntPtr Handle + { + get { return _handle; } + } + + public bool IsInvalid + { + get { return _handle == IntPtr.Zero; } + } + + public bool BringToTop() + { + return Win32.BringWindowToTop(this); + } + + public bool Close() + { + return Win32.CloseWindow(this); + } + + public bool Destroy() + { + return Win32.DestroyWindow(this); + } + + public bool EndTask(bool force) + { + return Win32.EndTask(this, false, force); + } + + public bool EnumerateChildren(EnumerateWindowsDelegate callback) + { + return Win32.EnumChildWindows(this, (hWnd, param) => callback(new WindowHandle(hWnd)), 0); + } + + public bool Equals(WindowHandle other) + { + return this.Handle.Equals(other.Handle); + } + + public bool Equals(IntPtr other) + { + return this.Handle.Equals(other); + } + + public ClientId GetClientId() + { + int tid, pid; + + tid = Win32.GetWindowThreadProcessId(this, out pid); + + return new ClientId(pid, tid); + } + + public WindowHandle GetParent() + { + return new WindowHandle(Win32.GetParent(this)); + } + + public WindowPlacement GetPlacement() + { + WindowPlacement placement = new WindowPlacement(); + + placement.Length = Marshal.SizeOf(placement); + Win32.GetWindowPlacement(this, ref placement); + + return placement; + } + + public Rectangle GetRectangle() + { + Rect rect; + + if (!Win32.GetWindowRect(this, out rect)) + return Rectangle.Empty; + else + return rect.ToRectangle(); + } + + public string GetText() + { + int retChars; + + using (var data = new MemoryAlloc(0x200)) + { + retChars = Win32.InternalGetWindowText(this, data, data.Size / 2); + + return data.ReadUnicodeString(0, retChars); + } + } + + public bool IsHung() + { + return Win32.IsHungAppWindow(this); + } + + public bool IsParent() + { + return this.GetParent().Equals(WindowHandle.Zero); + } + + public bool IsWindow() + { + return Win32.IsWindow(this); + } + + public bool IsVisible() + { + return Win32.IsWindowVisible(this); + } + + public bool PostMessage(WindowMessage message, int wParam, int lParam) + { + return Win32.PostMessage(this, message, wParam, lParam); + } + + public IntPtr SendMessage(WindowMessage message, int wParam, int lParam) + { + return Win32.SendMessage(this, message, wParam, lParam); + } + + public IntPtr SendMessageTimeout(WindowMessage message, int wParam, int lParam, SmtoFlags flags, int timeout, out int result) + { + return Win32.SendMessageTimeout(this, message, wParam, lParam, flags, timeout, out result); + } + + public bool SetForeground() + { + return Win32.SetForegroundWindow(this); + } + + public bool Show(ShowWindowType flags) + { + return Win32.ShowWindow(this, flags); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Objects/WindowStationHandle.cs b/branches/ph-plugins/ProcessHacker.Native/Objects/WindowStationHandle.cs new file mode 100644 index 000000000..e71a1c090 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Objects/WindowStationHandle.cs @@ -0,0 +1,66 @@ +/* + * Process Hacker - + * window station handle + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Objects +{ + public sealed class WindowStationHandle : UserHandle + { + public static WindowStationHandle GetCurrent() + { + IntPtr handle = Win32.GetProcessWindowStation(); + + if (handle == IntPtr.Zero) + Win32.ThrowLastError(); + + return new WindowStationHandle(handle, false); + } + + public WindowStationHandle(string name, WindowStationAccess access) + { + this.Handle = Win32.OpenWindowStation(name, false, access); + + if (this.Handle == System.IntPtr.Zero) + Win32.ThrowLastError(); + } + + private WindowStationHandle(IntPtr handle, bool owned) + : base(handle, owned) + { } + + protected override void Close() + { + Win32.CloseWindowStation(this); + } + + public void SetCurrent() + { + if (!Win32.SetProcessWindowStation(this)) + Win32.ThrowLastError(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/ProcessHacker.Native.csproj b/branches/ph-plugins/ProcessHacker.Native/ProcessHacker.Native.csproj new file mode 100644 index 000000000..402258d64 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/ProcessHacker.Native.csproj @@ -0,0 +1,262 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {8A448157-E1A7-4DDF-954E-287F1117832B} + Library + Properties + ProcessHacker.Native + ProcessHacker.Native + v2.0 + 512 + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + true + + + + + AnyCPU + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + true + bin\Release\ProcessHacker.Native.xml + 1591 + AnyCPU + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Form + + + ChooseProcessDialog.cs + + + Form + + + HandlePropertiesWindow.cs + + + + + + + + + + + + + ChooseProcessDialog.cs + + + HandlePropertiesWindow.cs + + + + + {8E10F5E8-D4FA-4980-BB23-2EDD134AC15E} + ProcessHacker.Common + + + + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker.Native/Properties/AssemblyInfo.cs b/branches/ph-plugins/ProcessHacker.Native/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..03666e843 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Process Hacker Native Library")] +[assembly: AssemblyDescription("Process Hacker Native Library")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("wj32")] +[assembly: AssemblyProduct("Process Hacker")] +[assembly: AssemblyCopyright("Licensed under the GNU GPL, v3.")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("55693337-3b82-490c-a33f-5cd16846b2f9")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.6.0.0")] +[assembly: AssemblyFileVersion("1.6.0.0")] diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/AccessControl/Ace.cs b/branches/ph-plugins/ProcessHacker.Native/Security/AccessControl/Ace.cs new file mode 100644 index 000000000..fc23705cb --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/AccessControl/Ace.cs @@ -0,0 +1,130 @@ +/* + * Process Hacker - + * access control entry + * + * Copyright (C) 2009 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 . + */ + +using System; +using ProcessHacker.Common.Objects; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native.Security.AccessControl +{ + public class Ace : BaseObject + { + public static Ace GetAce(IntPtr ace) + { + var type = GetType(ace); + + switch (type) + { + case AceType.AccessAllowed: + case AceType.AccessDenied: + case AceType.SystemAlarm: + case AceType.SystemAudit: + return new KnownAce(ace); + default: + return new Ace(ace); + } + } + + public static AceType GetType(IntPtr ace) + { + MemoryRegion memory = new MemoryRegion(ace); + + return memory.ReadStruct().AceType; + } + + public static implicit operator IntPtr(Ace ace) + { + return ace.Memory; + } + + private MemoryRegion _memory; + private AceFlags _flags; + private int _size; + private AceType _type; + + protected Ace() + { } + + public Ace(IntPtr memory) + : this(memory, false) + { } + + public Ace(IntPtr memory, bool copy) + : base(copy) + { + if (copy) + { + Ace existingAce = new Ace(memory); + + _memory = new MemoryAlloc(existingAce.Size); + _memory.WriteMemory(0, existingAce, 0, existingAce.Size); + } + else + { + _memory = new MemoryRegion(memory); + } + + this.Read(); + } + + protected override void DisposeObject(bool disposing) + { + if (_memory != null) + _memory.Dispose(); + } + + public AceFlags Flags + { + get { return _flags; } + } + + public IntPtr Memory + { + get { return _memory; } + } + + protected MemoryRegion MemoryRegion + { + get { return _memory; } + set { _memory = value; } + } + + public int Size + { + get { return _size; } + } + + public AceType Type + { + get { return _type; } + } + + protected virtual void Read() + { + var aceHeader = _memory.ReadStruct(); + + _flags = aceHeader.AceFlags; + _size = aceHeader.AceSize; + _type = aceHeader.AceType; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/AccessControl/Acl.cs b/branches/ph-plugins/ProcessHacker.Native/Security/AccessControl/Acl.cs new file mode 100644 index 000000000..ee20f7681 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/AccessControl/Acl.cs @@ -0,0 +1,322 @@ +/* + * Process Hacker - + * access control list + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using ProcessHacker.Common.Objects; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native.Security.AccessControl +{ + public sealed class Acl : BaseObject, IEnumerable + { + public static Acl FromPointer(IntPtr memory) + { + return new Acl(new MemoryRegion(memory)); + } + + public static implicit operator IntPtr(Acl acl) + { + return acl.Memory; + } + + private MemoryRegion _memory; + + public Acl(int size) + { + NtStatus status; + + // Reserve 8 bytes for the ACL header. + if (size < 8) + throw new ArgumentException("Size must be greater than or equal to 8 bytes."); + + // Allocate some memory. + _memory = new MemoryAlloc(size); + + // Initialize the ACL. + if ((status = Win32.RtlCreateAcl( + _memory, + size, + Win32.AclRevision + )) >= NtStatus.Error) + { + // Dispose memory and disable ownership. + _memory.Dispose(); + _memory = null; + this.DisableOwnership(false); + } + + _memory.Reference(); + _memory.Dispose(); + } + + public Acl(Acl existingAcl) + { + // Allocate memory for the new ACL. + _memory = new MemoryAlloc(existingAcl.Size); + // Copy the ACL. + _memory.WriteMemory(0, existingAcl, 0, existingAcl.Size); + _memory.Reference(); + _memory.Dispose(); + } + + public Acl(Acl existingAcl, int newSize) + : this(newSize) + { + this.AddRange(0, existingAcl); + } + + public Acl(MemoryRegion memory) + { + _memory = memory; + _memory.Reference(); + } + + protected override void DisposeObject(bool disposing) + { + if (_memory != null) + _memory.Dereference(disposing); + } + + public Ace this[int index] + { + get { return this.GetAt(index); } + } + + public int BytesFree + { + get { return this.GetSizeInformation().AclBytesFree; } + } + + public int BytesUsed + { + get { return this.GetSizeInformation().AclBytesInUse; } + } + + public int Count + { + get { return this.GetSizeInformation().AceCount; } + } + + public IntPtr Memory + { + get { return _memory; } + } + + public int Size + { + get + { + var sizeInfo = this.GetSizeInformation(); + + return sizeInfo.AclBytesInUse + sizeInfo.AclBytesFree; + } + } + + public bool IsValid() + { + return Win32.RtlValidAcl(this); + } + + public void AddAccessAllowed(int accessMask, Sid sid) + { + NtStatus status; + + if ((status = Win32.RtlAddAccessAllowedAce( + this, + Win32.AclRevision, + accessMask, + sid + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + public void AddAccessAllowed(int accessMask, Sid sid, AceFlags flags) + { + NtStatus status; + + if ((status = Win32.RtlAddAccessAllowedAceEx( + this, + Win32.AclRevision, + flags, + accessMask, + sid + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + public void AddAccessDenied(int accessMask, Sid sid) + { + NtStatus status; + + if ((status = Win32.RtlAddAccessDeniedAce( + this, + Win32.AclRevision, + accessMask, + sid + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + public void AddAccessDenied(int accessMask, Sid sid, AceFlags flags) + { + NtStatus status; + + if ((status = Win32.RtlAddAccessDeniedAceEx( + this, + Win32.AclRevision, + flags, + accessMask, + sid + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + public void AddAuditAccess(int accessMask, Sid sid, bool auditSuccess, bool auditFailure) + { + NtStatus status; + + if ((status = Win32.RtlAddAuditAccessAce( + this, + Win32.AclRevision, + accessMask, + sid, + auditSuccess, + auditFailure + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + public void AddAuditAccess(int accessMask, Sid sid, bool auditSuccess, bool auditFailure, AceFlags flags) + { + NtStatus status; + + if ((status = Win32.RtlAddAuditAccessAceEx( + this, + Win32.AclRevision, + flags, + accessMask, + sid, + auditSuccess, + auditFailure + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + public void AddCompound(AceType type, int accessMask, Sid serverSid, Sid clientSid) + { + NtStatus status; + + if ((status = Win32.RtlAddCompoundAce( + this, + Win32.AclRevision, + type, + accessMask, + serverSid, + clientSid + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + public void AddRange(int index, IEnumerable aceList) + { + int totalSize = 0; + + // Compute the total size, in bytes. + foreach (Ace ace in aceList) + { + totalSize += ace.Size; + } + + using (var aceListMemory = new MemoryAlloc(totalSize)) + { + int i = 0; + + // Copy the ACEs into one contiguous block. + foreach (Ace ace in aceList) + { + aceListMemory.WriteMemory(i, ace, 0, ace.Size); + i += ace.Size; + } + + NtStatus status; + + // Add the ACEs to the ACL. + if ((status = Win32.RtlAddAce( + this, + Win32.AclRevision, + index, + aceListMemory, + totalSize + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + } + + public Ace GetAt(int index) + { + NtStatus status; + IntPtr ace; + + if ((status = Win32.RtlGetAce(this, index, out ace)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return Ace.GetAce(ace); + } + + public IEnumerator GetEnumerator() + { + for (int i = 0; i < this.Count; i++) + yield return this[i]; + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + + public AclSizeInformation GetSizeInformation() + { + NtStatus status; + AclSizeInformation sizeInfo; + + if ((status = Win32.RtlQueryInformationAcl( + this, + out sizeInfo, + Marshal.SizeOf(typeof(AclSizeInformation)), + AclInformationClass.AclSizeInformation + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return sizeInfo; + } + + public void RemoveAt(int index) + { + NtStatus status; + + if ((status = Win32.RtlDeleteAce(this, index)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/AccessControl/KnownAce.cs b/branches/ph-plugins/ProcessHacker.Native/Security/AccessControl/KnownAce.cs new file mode 100644 index 000000000..a6ee717a0 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/AccessControl/KnownAce.cs @@ -0,0 +1,93 @@ +/* + * Process Hacker - + * known access control entry + * (access allowed, access denied, system alarm, system audit) + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Runtime.InteropServices; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native.Security.AccessControl +{ + public class KnownAce : Ace + { + private int _mask; + private Sid _sid; + + protected KnownAce() + { } + + public KnownAce(AceType type, AceFlags flags, int mask, Sid sid) + { + if ( + type != AceType.AccessAllowed && + type != AceType.AccessDenied && + type != AceType.SystemAlarm && + type != AceType.SystemAudit + ) + throw new ArgumentException("Invalid ACE type."); + + this.MemoryRegion = new MemoryAlloc( + Marshal.SizeOf(typeof(KnownAceStruct)) - // known ace struct size + sizeof(int) + // minus SidStart field + sid.Length // plus SID length + ); + + KnownAceStruct knownAce = new KnownAceStruct(); + + // Initialize the ACE (minus the SID). + knownAce.Header.AceType = type; + knownAce.Header.AceFlags = flags; + knownAce.Header.AceSize = (ushort)this.MemoryRegion.Size; + knownAce.Mask = mask; + // Write the ACE to memory. + this.MemoryRegion.WriteStruct(knownAce); + // Write the SID. + this.MemoryRegion.WriteMemory(Win32.KnownAceSidStartOffset.ToInt32(), sid, 0, sid.Length); + // Update the cached info. + this.Read(); + } + + public KnownAce(IntPtr memory) + : base(memory) + { } + + public int Mask + { + get { return _mask; } + } + + public Sid Sid + { + get { return _sid; } + } + + protected override void Read() + { + var knownAce = this.MemoryRegion.ReadStruct(); + + _mask = knownAce.Mask; + _sid = Sid.FromPointer(this.Memory.Increment(Win32.KnownAceSidStartOffset)); + + base.Read(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/AccessControl/SecurityDescriptor.cs b/branches/ph-plugins/ProcessHacker.Native/Security/AccessControl/SecurityDescriptor.cs new file mode 100644 index 000000000..9f007d43d --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/AccessControl/SecurityDescriptor.cs @@ -0,0 +1,599 @@ +/* + * Process Hacker - + * security descriptor + * + * Copyright (C) 2009 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 . + */ + +using System; +using ProcessHacker.Common.Objects; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; + +namespace ProcessHacker.Native.Security.AccessControl +{ + /// + /// Represents a security descriptor. + /// + public sealed class SecurityDescriptor : BaseObject + { + /// + /// Gets the security descriptor of a kernel object. + /// + /// A handle to a kernel object. + /// The information to retrieve. + /// A security descriptor. + public static SecurityDescriptor GetSecurity(IntPtr handle, SecurityInformation securityInformation) + { + NtStatus status; + int retLength; + + using (var data = new MemoryAlloc(0x100)) + { + status = Win32.NtQuerySecurityObject( + handle, + securityInformation, + data, + data.Size, + out retLength + ); + + if (status == NtStatus.BufferTooSmall) + { + data.Resize(retLength); + + status = Win32.NtQuerySecurityObject( + handle, + securityInformation, + data, + data.Size, + out retLength + ); + } + + if (status >= NtStatus.Error) + Win32.ThrowLastError(status); + + return new SecurityDescriptor(data); + } + } + + /// + /// Gets the security descriptor of an object. + /// + /// A handle to an object. + /// The type of the object. + /// The information to retrieve. + /// A security descriptor. + public static SecurityDescriptor GetSecurity(IntPtr handle, SeObjectType objectType, SecurityInformation securityInformation) + { + Win32Error result; + IntPtr dummy, securityDescriptor; + + if ((result = Win32.GetSecurityInfo( + handle, + objectType, + securityInformation, + out dummy, out dummy, out dummy, out dummy, + out securityDescriptor + )) != 0) + Win32.ThrowLastError(result); + + return new SecurityDescriptor(new LocalMemoryAlloc(securityDescriptor)); + } + + /// + /// Sets the security descriptor of a kernel object. + /// + /// A handle to a kernel object. + /// The information to modify. + /// The security descriptor. + public static void SetSecurity(IntPtr handle, SecurityInformation securityInformation, SecurityDescriptor securityDescriptor) + { + NtStatus status; + + if ((status = Win32.NtSetSecurityObject( + handle, + securityInformation, + securityDescriptor + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + + /// + /// Sets the security descriptor of an object. + /// + /// A handle to an object. + /// The type of the object. + /// The information to modify. + /// The security descriptor. + public static void SetSecurity(IntPtr handle, SeObjectType objectType, SecurityInformation securityInformation, SecurityDescriptor securityDescriptor) + { + Win32Error result; + IntPtr dacl = IntPtr.Zero; + IntPtr group = IntPtr.Zero; + IntPtr owner = IntPtr.Zero; + IntPtr sacl = IntPtr.Zero; + + if ((securityInformation & SecurityInformation.Dacl) == SecurityInformation.Dacl) + dacl = securityDescriptor.Dacl ?? IntPtr.Zero; + if ((securityInformation & SecurityInformation.Group) == SecurityInformation.Group) + group = securityDescriptor.Group; + if ((securityInformation & SecurityInformation.Owner) == SecurityInformation.Owner) + owner = securityDescriptor.Owner; + if ((securityInformation & SecurityInformation.Sacl) == SecurityInformation.Sacl) + sacl = securityDescriptor.Sacl ?? IntPtr.Zero; + + if ((result = Win32.SetSecurityInfo( + handle, + objectType, + securityInformation, + owner, + group, + dacl, + sacl + )) != 0) + Win32.ThrowLastError(result); + } + + public static implicit operator IntPtr(SecurityDescriptor securityDescriptor) + { + return securityDescriptor.Memory; + } + + private MemoryRegion _memory; + private Acl _dacl; + private Acl _sacl; + private Sid _owner; + private Sid _group; + + /// + /// Creates an empty security descriptor. + /// + public SecurityDescriptor() + { + NtStatus status; + + _memory = new MemoryAlloc(Win32.SecurityDescriptorMinLength); + + if ((status = Win32.RtlCreateSecurityDescriptor( + _memory, + Win32.SecurityDescriptorRevision + )) >= NtStatus.Error) + { + _memory.Dispose(); + _memory = null; + this.DisableOwnership(false); + Win32.ThrowLastError(status); + } + + _memory.Reference(); + _memory.Dispose(); + } + + /// + /// Creates a security descriptor with the specified components. + /// + /// A SID representing an owner. + /// A SID representing a group. + /// The discretionary access control list. + /// The system access control list. + public SecurityDescriptor(Sid owner, Sid group, Acl dacl, Acl sacl) + : this() + { + this.Owner = owner; + this.Group = group; + this.Dacl = dacl; + this.Sacl = sacl; + } + + /// + /// Creates a security descriptor from memory. + /// + /// The memory region to use. This object will be referenced. + public SecurityDescriptor(MemoryRegion memory) + { + _memory = memory; + _memory.Reference(); + this.Read(); + } + + protected override void DisposeObject(bool disposing) + { + if (_dacl != null) + _dacl.Dereference(disposing); + if (_sacl != null) + _sacl.Dereference(disposing); + if (_owner != null) + _owner.Dereference(disposing); + if (_group != null) + _group.Dereference(disposing); + if (_memory != null) + _memory.Dereference(disposing); + } + + /// + /// Gets or sets the control flags. + /// + public SecurityDescriptorControlFlags ControlFlags + { + get + { + NtStatus status; + SecurityDescriptorControlFlags control; + int revision; + + if ((status = Win32.RtlGetControlSecurityDescriptor( + this, + out control, + out revision + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return control; + } + set + { + NtStatus status; + + if ((status = Win32.RtlSetControlSecurityDescriptor( + this, + value, + value + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + } + + /// + /// Gets or sets the DACL. + /// + public Acl Dacl + { + get { return _dacl; } + set + { + NtStatus status; + + if ((status = Win32.RtlSetDaclSecurityDescriptor( + this, + value != null, + value ?? IntPtr.Zero, + false + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + this.SwapDacl(value); + } + } + + /// + /// Gets or sets whether the DACL has been defaulted. + /// + public bool DaclDefaulted + { + get + { + return (this.ControlFlags & SecurityDescriptorControlFlags.DaclDefaulted) == + SecurityDescriptorControlFlags.DaclDefaulted; + } + set + { + if (value) + this.ControlFlags |= SecurityDescriptorControlFlags.DaclDefaulted; + else + this.ControlFlags &= ~SecurityDescriptorControlFlags.DaclDefaulted; + } + } + + /// + /// Gets or sets the group. + /// + public Sid Group + { + get { return _group; } + set + { + NtStatus status; + + if ((status = Win32.RtlSetGroupSecurityDescriptor( + this, + value, + false + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + this.SwapGroup(value); + } + } + + /// + /// Gets or sets whether the group has been defaulted. + /// + public bool GroupDefaulted + { + get + { + return (this.ControlFlags & SecurityDescriptorControlFlags.GroupDefaulted) == + SecurityDescriptorControlFlags.GroupDefaulted; + } + set + { + if (value) + this.ControlFlags |= SecurityDescriptorControlFlags.GroupDefaulted; + else + this.ControlFlags &= ~SecurityDescriptorControlFlags.GroupDefaulted; + } + } + + /// + /// Gets the size of the security descriptor, in bytes. + /// + public int Length + { + get { return Win32.RtlLengthSecurityDescriptor(this); } + } + + /// + /// Gets a pointer to the associated memory of the security descriptor. + /// + public IntPtr Memory + { + get { return _memory; } + } + + /// + /// Gets or sets the owner. + /// + public Sid Owner + { + get { return _owner; } + set + { + NtStatus status; + + if ((status = Win32.RtlSetOwnerSecurityDescriptor( + this, + value, + false + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + this.SwapOwner(value); + } + } + + /// + /// Gets or sets whether the owner has been defaulted. + /// + public bool OwnerDefaulted + { + get + { + return (this.ControlFlags & SecurityDescriptorControlFlags.OwnerDefaulted) == + SecurityDescriptorControlFlags.OwnerDefaulted; + } + set + { + if (value) + this.ControlFlags |= SecurityDescriptorControlFlags.OwnerDefaulted; + else + this.ControlFlags &= ~SecurityDescriptorControlFlags.OwnerDefaulted; + } + } + + /// + /// Gets or sets the SACL. + /// + public Acl Sacl + { + get { return _sacl; } + set + { + NtStatus status; + + if ((status = Win32.RtlSetSaclSecurityDescriptor( + this, + value != null, + value ?? IntPtr.Zero, + false + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + this.SwapSacl(value); + } + } + + /// + /// Gets or sets whether the SACL has been defaulted. + /// + public bool SaclDefaulted + { + get + { + return (this.ControlFlags & SecurityDescriptorControlFlags.SaclDefaulted) == + SecurityDescriptorControlFlags.SaclDefaulted; + } + set + { + if (value) + this.ControlFlags |= SecurityDescriptorControlFlags.SaclDefaulted; + else + this.ControlFlags &= ~SecurityDescriptorControlFlags.SaclDefaulted; + } + } + + /// + /// Gets whether the security descriptor is in self-relative form. + /// + public bool SelfRelative + { + get + { + return (this.ControlFlags & SecurityDescriptorControlFlags.SelfRelative) == + SecurityDescriptorControlFlags.SelfRelative; + } + } + + /// + /// Checks whether the security descriptor grants a set of access rights to a client. + /// + /// A handle to a token which represents the client. + /// The access rights requested by the client. + /// A structure which defines how generic access rights are to be mapped. + /// A variable which receives the granted access rights. + /// Success if access was granted, otherwise another NT status value. + public NtStatus CheckAccess(TokenHandle tokenHandle, int desiredAccess, GenericMapping genericMapping, out int grantedAccess) + { + NtStatus status; + NtStatus accessStatus; + int privilegeSetLength = 0; + + if ((status = Win32.NtAccessCheck( + this, + tokenHandle, + desiredAccess, + ref genericMapping, + IntPtr.Zero, + ref privilegeSetLength, + out grantedAccess, + out accessStatus + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return accessStatus; + } + + /// + /// Checks whether the security descriptor is valid. + /// + /// True if the security descriptor is valid, otherwise false. + public bool IsValid() + { + return Win32.RtlValidSecurityDescriptor(this); + } + + private void Read() + { + NtStatus status; + bool present, defaulted; + IntPtr dacl, group, owner, sacl; + + // Read the DACL. + if ((status = Win32.RtlGetDaclSecurityDescriptor( + this, + out present, + out dacl, + out defaulted + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + if (present) + this.SwapDacl(new Acl(Acl.FromPointer(dacl))); + else + this.SwapDacl(null); + + // Read the SACL. + if ((status = Win32.RtlGetSaclSecurityDescriptor( + this, + out present, + out sacl, + out defaulted + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + if (present) + this.SwapSacl(new Acl(Acl.FromPointer(sacl))); + else + this.SwapSacl(null); + + // Read the group. + if ((status = Win32.RtlGetGroupSecurityDescriptor( + this, + out group, + out defaulted + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + if (group != IntPtr.Zero) + this.SwapGroup(new Sid(group)); + else + this.SwapGroup(null); + + // Read the owner. + if ((status = Win32.RtlGetOwnerSecurityDescriptor( + this, + out owner, + out defaulted + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + if (owner != IntPtr.Zero) + this.SwapOwner(new Sid(owner)); + else + this.SwapOwner(null); + } + + private void SwapDacl(Acl dacl) + { + BaseObject.SwapRef(ref _dacl, dacl); + } + + private void SwapGroup(Sid group) + { + BaseObject.SwapRef(ref _group, group); + } + + private void SwapOwner(Sid owner) + { + BaseObject.SwapRef(ref _owner, owner); + } + + private void SwapSacl(Acl sacl) + { + BaseObject.SwapRef(ref _sacl, sacl); + } + + /// + /// Creates a copy of the security descriptor in self-relative form. + /// + /// A new self-relative security descriptor. + public SecurityDescriptor ToSelfRelative() + { + NtStatus status; + int retLength; + + using (var data = new MemoryAlloc(Win32.SecurityDescriptorMinLength)) + { + retLength = data.Size; + status = Win32.RtlMakeSelfRelativeSD(this, data, ref retLength); + + if (status == NtStatus.BufferTooSmall) + { + data.Resize(retLength); + status = Win32.RtlMakeSelfRelativeSD(this, data, ref retLength); + } + + if (status >= NtStatus.Error) + Win32.ThrowLastError(status); + + return new SecurityDescriptor(data); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/AccessControl/SecurityEditor.cs b/branches/ph-plugins/ProcessHacker.Native/Security/AccessControl/SecurityEditor.cs new file mode 100644 index 000000000..7ae349ce0 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/AccessControl/SecurityEditor.cs @@ -0,0 +1,329 @@ +/* + * Process Hacker - + * ISecurityInformation implementation + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security.AccessControl; + +namespace ProcessHacker.Native.Security.AccessControl +{ + public class SecurityEditor : IDisposable, ISecurityInformation + { + private class GenericSecurableObject : ISecurable + { + private SeObjectType _objectType; + private Func _openMethod; + + public GenericSecurableObject(SeObjectType objectType, Func openMethod) + { + _objectType = objectType; + _openMethod = openMethod; + } + + public SecurityDescriptor GetSecurity(SecurityInformation securityInformation) + { + using (var dupHandle = _openMethod(StandardRights.ReadControl)) + return SecurityDescriptor.GetSecurity(dupHandle, _objectType, securityInformation); + } + + public void SetSecurity(SecurityInformation securityInformation, SecurityDescriptor securityDescriptor) + { + using (var dupHandle = _openMethod( + ((securityInformation & SecurityInformation.Dacl) != 0 ? StandardRights.WriteDac : 0) | + ((securityInformation & SecurityInformation.Owner) != 0 ? StandardRights.WriteOwner : 0) + )) + { + SecurityDescriptor.SetSecurity( + dupHandle, + _objectType, + securityInformation, + securityDescriptor + ); + } + } + } + + public static void EditSecurity(IWin32Window owner, ISecurable securable, string name, IEnumerable accessEntries) + { + using (var osi = new SecurityEditor(securable, name, accessEntries)) + Win32.EditSecurity(owner != null ? owner.Handle : IntPtr.Zero, osi); + } + + public static ISecurable GetSecurable(NativeTypeFactory.ObjectType objectType, IntPtr handle) + { + return GetSecurable(objectType, (access) => new NativeHandle(handle, access)); + } + + public static ISecurable GetSecurable(NativeTypeFactory.ObjectType objectType, Func openMethod) + { + return new GenericSecurableObject(NativeTypeFactory.GetSeObjectType(objectType), openMethod); + } + + private bool _disposed = false; + private ISecurable _securable; + private List _pool = new List(); + private string _name; + private MemoryAlloc _accessRights; + private int _accessRightCount; + + internal SecurityEditor(ISecurable securable, string name, IEnumerable accessEntries) + { + List accesses; + + _securable = securable; + _name = name; + + accesses = new List(); + + foreach (var entry in accessEntries) + { + if (entry.Mask != 0) + { + accesses.Add(new SiAccess() + { + Guid = IntPtr.Zero, + Mask = entry.Mask, + Flags = (entry.General ? SiAccessFlags.General : 0) | (entry.Specific ? SiAccessFlags.Specific : 0), + Name = this.AllocateStringFromPool(entry.Name) + }); + } + } + + _accessRights = this.AllocateStructArray(accesses.ToArray()); + _accessRightCount = accesses.Count; + } + + public void Dispose() + { + if (!_disposed) + { + _pool.ForEach((alloc) => alloc.Dispose()); + _pool.Clear(); + _disposed = true; + } + } + + private MemoryAlloc AllocateArray(IntPtr[] value) + { + MemoryAlloc alloc = new MemoryAlloc(IntPtr.Size * value.Length); + + for (int i = 0; i < value.Length; i++) + alloc.WriteIntPtr(i * IntPtr.Size, value[i]); + + return alloc; + } + + private MemoryAlloc AllocateArrayFromPool(IntPtr[] value) + { + MemoryAlloc m = this.AllocateArray(value); + _pool.Add(m); + return m; + } + + private MemoryAlloc AllocateString(string value) + { + MemoryAlloc alloc = new MemoryAlloc((value.Length + 1) * 2); + + alloc.WriteUnicodeString(0, value); + alloc.WriteInt16(value.Length * 2, 0); + + return alloc; + } + + private MemoryAlloc AllocateStringFromPool(string value) + { + MemoryAlloc m = this.AllocateString(value); + _pool.Add(m); + return m; + } + + private MemoryAlloc AllocateStruct(T value) + where T : struct + { + MemoryAlloc alloc = new MemoryAlloc(Marshal.SizeOf(typeof(T))); + + alloc.WriteStruct(0, value); + + return alloc; + } + + private MemoryAlloc AllocateStructFromPool(T value) + where T : struct + { + MemoryAlloc m = this.AllocateStruct(value); + _pool.Add(m); + return m; + } + + private MemoryAlloc AllocateStructArray(T[] value) + where T : struct + { + MemoryAlloc alloc = new MemoryAlloc(Marshal.SizeOf(typeof(T)) * value.Length); + + for (int i = 0; i < value.Length; i++) + alloc.WriteStruct(i, value[i]); + + return alloc; + } + + private MemoryAlloc AllocateStructArrayFromPool(T[] value) + where T : struct + { + MemoryAlloc m = this.AllocateStructArray(value); + _pool.Add(m); + return m; + } + + #region ISecurityInformation Members + + public HResult GetObjectInformation(out SiObjectInfo ObjectInfo) + { + SiObjectInfo soi = new SiObjectInfo(); + + soi.Flags = + SiObjectInfoFlags.EditAudits | + SiObjectInfoFlags.EditOwner | + SiObjectInfoFlags.EditPerms | + SiObjectInfoFlags.Advanced | + SiObjectInfoFlags.NoAclProtect | + SiObjectInfoFlags.NoTreeApply; + soi.Instance = IntPtr.Zero; + soi.ObjectName = this.AllocateStringFromPool(_name); + ObjectInfo = soi; + + return HResult.OK; + } + + public HResult GetSecurity(SecurityInformation RequestedInformation, out IntPtr SecurityDescriptor, bool Default) + { + try + { + using (var sd = _securable.GetSecurity(RequestedInformation)) + { + // Since the ACL editor will free the security descriptor using + // LocalFree, we need to use a local memory allocation and copy + // the security descriptor into it. + using (var localAlloc = new LocalMemoryAlloc(sd.Length)) + { + localAlloc.WriteMemory(0, sd.Memory, 0, sd.Length); + localAlloc.Reference(); // reference for ACL editor + SecurityDescriptor = localAlloc; + } + } + } + catch (WindowsException ex) + { + SecurityDescriptor = IntPtr.Zero; + + return ex.ErrorCode.GetHResult(); + } + + return HResult.OK; + } + + public HResult SetSecurity(SecurityInformation SecurityInformation, IntPtr SecurityDescriptor) + { + try + { + _securable.SetSecurity( + SecurityInformation, + new SecurityDescriptor(new MemoryRegion(SecurityDescriptor)) + ); + } + catch (WindowsException ex) + { + return ex.ErrorCode.GetHResult(); + } + + return HResult.OK; + } + + public HResult GetAccessRights(ref Guid ObjectType, SiObjectInfoFlags Flags, out IntPtr Access, out int Accesses, out int DefaultAccess) + { + Access = _accessRights; + Accesses = _accessRightCount; + DefaultAccess = 0; + + return HResult.OK; + } + + public HResult MapGeneric(ref Guid ObjectType, ref AceFlags AceFlags, ref int Mask) + { + return HResult.OK; + } + + public HResult GetInheritTypes(out IntPtr InheritTypes, out int InheritTypesCount) + { + InheritTypes = IntPtr.Zero; + InheritTypesCount = 0; + + return HResult.Fail; + } + + public HResult PropertySheetPageCallback(IntPtr hWnd, SiCallbackMessage Msg, SiPageType Page) + { + return HResult.OK; + } + + #endregion + } + + public struct AccessEntry + { + private bool _general; + private int _mask; + private string _name; + private bool _specific; + + public AccessEntry(string name, object mask, bool general, bool specific) + { + _name = name; + _mask = Convert.ToInt32(mask); + _general = general; + _specific = specific; + } + + public bool General + { + get { return _general; } + } + + public int Mask + { + get { return _mask; } + } + + public string Name + { + get { return _name; } + } + + public bool Specific + { + get { return _specific; } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/DebugObjectAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/DebugObjectAccess.cs new file mode 100644 index 000000000..4cef678bc --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/DebugObjectAccess.cs @@ -0,0 +1,15 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum DebugObjectAccess : uint + { + ReadEvent = 0x1, + ProcessAssign = 0x2, + SetInformation = 0x4, + QueryInformation = 0x8, + All = StandardRights.Required | StandardRights.Synchronize | + ReadEvent | ProcessAssign | SetInformation | QueryInformation + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/DesktopAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/DesktopAccess.cs new file mode 100644 index 000000000..e6268edbc --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/DesktopAccess.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum DesktopAccess : uint + { + ReadObjects = 0x0001, + CreateWindow = 0x0002, + CreateMenu = 0x0004, + HookControl = 0x0008, + JournalRecord = 0x0010, + JournalPlayback = 0x0020, + Enumerate = 0x0040, + WriteObjects = 0x0080, + SwitchDesktop = 0x0100, + All = CreateMenu | CreateWindow | Enumerate | HookControl | + JournalPlayback | JournalRecord | ReadObjects | SwitchDesktop | + WriteObjects | StandardRights.Required, + GenericRead = Enumerate | ReadObjects | StandardRights.Read, + GenericWrite = CreateMenu | CreateWindow | HookControl | JournalPlayback | + JournalRecord | WriteObjects | StandardRights.Write, + GenericExecute = SwitchDesktop | StandardRights.Execute + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/DirectoryAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/DirectoryAccess.cs new file mode 100644 index 000000000..14b8f51fd --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/DirectoryAccess.cs @@ -0,0 +1,15 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum DirectoryAccess : uint + { + Query = 0x1, + Traverse = 0x2, + CreateObject = 0x4, + CreateSubdirectory = 0x8, + All = StandardRights.Required | Query | Traverse | + CreateObject | CreateSubdirectory + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/EnlistmentAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/EnlistmentAccess.cs new file mode 100644 index 000000000..061fd1f79 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/EnlistmentAccess.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum EnlistmentAccess : uint + { + QueryInformation = 0x0001, + SetInformation = 0x0002, + Recover = 0x0004, + SubordinateRights = 0x0008, + SuperiorRights = 0x0010, + GenericRead = StandardRights.Read | QueryInformation, + GenericWrite = StandardRights.Write | SetInformation | Recover | + SubordinateRights | SuperiorRights, + GenericExecute = StandardRights.Execute | Recover | SubordinateRights | + SuperiorRights, + All = StandardRights.Required | GenericRead | GenericWrite | GenericExecute + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/EventAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/EventAccess.cs new file mode 100644 index 000000000..39353d524 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/EventAccess.cs @@ -0,0 +1,13 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum EventAccess : uint + { + QueryState = 0x1, + ModifyState = 0x2, + All = StandardRights.Required | StandardRights.Synchronize | + QueryState | ModifyState + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/EventPairAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/EventPairAccess.cs new file mode 100644 index 000000000..aa2da32cd --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/EventPairAccess.cs @@ -0,0 +1,10 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum EventPairAccess : uint + { + All = StandardRights.Required | StandardRights.Synchronize + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/FileAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/FileAccess.cs new file mode 100644 index 000000000..a2af7cc03 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/FileAccess.cs @@ -0,0 +1,39 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum FileAccess : uint + { + ReadData = 0x0001, // File, Named Pipe + ListDirectory = 0x0001, // Directory + + WriteData = 0x0002, // File, Named Pipe + AddFile = 0x0002, // Directory + + AppendData = 0x0004, // File + AddSubdirectory = 0x0004, // Directory + CreatePipeInstance = 0x0004, // Named Pipe + + ReadEa = 0x0008, // File, Directory + + WriteEa = 0x0010, // File, Directory + + Execute = 0x0020, // File + Traverse = 0x0020, // Directory + + DeleteChild = 0x0040, // Directory + + ReadAttributes = 0x0080, // All + + WriteAttributes = 0x0100, // All + + All = StandardRights.Required | StandardRights.Synchronize | 0x1ff, + GenericRead = StandardRights.Read | ReadData | ReadAttributes | ReadEa | + StandardRights.Synchronize, + GenericWrite = StandardRights.Write | WriteData | WriteAttributes | WriteEa | + AppendData | StandardRights.Synchronize, + GenericExecute = StandardRights.Execute | ReadAttributes | Execute | + StandardRights.Synchronize + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/FltPortAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/FltPortAccess.cs new file mode 100644 index 000000000..84d5d0295 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/FltPortAccess.cs @@ -0,0 +1,11 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum FltPortAccess : uint + { + Connect = 0x1, + All = Connect | StandardRights.All + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/ISecurable.cs b/branches/ph-plugins/ProcessHacker.Native/Security/ISecurable.cs new file mode 100644 index 000000000..1c28e4ad1 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/ISecurable.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security.AccessControl; + +namespace ProcessHacker.Native.Security +{ + public interface ISecurable + { + SecurityDescriptor GetSecurity(SecurityInformation securityInformation); + void SetSecurity(SecurityInformation securityInformation, SecurityDescriptor securityDescriptor); + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/IoCompletionAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/IoCompletionAccess.cs new file mode 100644 index 000000000..dc10c1ee0 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/IoCompletionAccess.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum IoCompletionAccess : uint + { + QueryState = 0x1, + ModifyState = 0x2, + All = StandardRights.Required | StandardRights.Synchronize | 0x3 + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/JobObjectAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/JobObjectAccess.cs new file mode 100644 index 000000000..d40245ee1 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/JobObjectAccess.cs @@ -0,0 +1,15 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum JobObjectAccess : uint + { + AssignProcess = 0x0001, + SetAttributes = 0x0002, + Query = 0x0004, + Terminate = 0x0008, + SetSecurityAttributes = 0x0010, + All = StandardRights.Required | StandardRights.Synchronize | 0x1f + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/KeyAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/KeyAccess.cs new file mode 100644 index 000000000..b68d0782a --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/KeyAccess.cs @@ -0,0 +1,23 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum KeyAccess : uint + { + QueryValue = 0x0001, + SetValue = 0x0002, + CreateSubKey = 0x0004, + EnumerateSubKeys = 0x0008, + Notify = 0x0010, + CreateLink = 0x0020, + Wow64_32Key = 0x0200, + Wow64_64Key = 0x0100, + Wow64_Res = 0x0300, + All = (StandardRights.All | QueryValue | SetValue | CreateSubKey | + EnumerateSubKeys | Notify | CreateLink) & ~StandardRights.Synchronize, + GenericRead = (StandardRights.Read | QueryValue | EnumerateSubKeys | Notify) & ~StandardRights.Synchronize, + GenericWrite = (StandardRights.Write | SetValue | CreateSubKey) & ~StandardRights.Synchronize, + GenericExecute = GenericRead & ~StandardRights.Synchronize + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/KeyedEventAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/KeyedEventAccess.cs new file mode 100644 index 000000000..e910ec783 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/KeyedEventAccess.cs @@ -0,0 +1,12 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum KeyedEventAccess : uint + { + Wait = 0x1, + Wake = 0x2, + All = StandardRights.Required | Wait | Wake + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/LsaAccountAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/LsaAccountAccess.cs new file mode 100644 index 000000000..34534a7f6 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/LsaAccountAccess.cs @@ -0,0 +1,19 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum LsaAccountAccess : uint + { + View = 0x00000001, + AdjustPrivileges = 0x00000002, + AdjustQuotas = 0x00000004, + AdjustSystemAccess = 0x00000008, + All = StandardRights.Required | View | AdjustPrivileges | AdjustQuotas | + AdjustSystemAccess, + GenericRead = StandardRights.Read | View, + GenericWrite = StandardRights.Write | AdjustPrivileges | AdjustQuotas | + AdjustSystemAccess, + GenericExecute = StandardRights.Execute + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/LsaPolicyAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/LsaPolicyAccess.cs new file mode 100644 index 000000000..adcf0d69c --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/LsaPolicyAccess.cs @@ -0,0 +1,31 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum LsaPolicyAccess : uint + { + ViewLocalInformation = 0x00000001, + ViewAuditInformation = 0x00000002, + GetPrivateInformation = 0x00000004, + TrustAdmin = 0x00000008, + CreateAccount = 0x00000010, + CreateSecret = 0x00000020, + CreatePrivilege = 0x00000040, + SetDefaultQuotaLimits = 0x00000080, + SetAuditRequirements = 0x00000100, + AuditLogAdmin = 0x00000200, + ServerAdmin = 0x00000400, + LookupNames = 0x00000800, + Notification = 0x00001000, + All = StandardRights.Required | ViewLocalInformation | ViewAuditInformation | + GetPrivateInformation | TrustAdmin | CreateAccount | CreateSecret | + CreatePrivilege | SetDefaultQuotaLimits | SetAuditRequirements | + AuditLogAdmin | ServerAdmin | LookupNames, + GenericRead = StandardRights.Read | ViewAuditInformation | GetPrivateInformation, + GenericWrite = StandardRights.Write | TrustAdmin | CreateAccount | CreateSecret | + CreatePrivilege | SetDefaultQuotaLimits | SetAuditRequirements | + AuditLogAdmin | ServerAdmin, + GenericExecute = StandardRights.Execute | ViewLocalInformation | LookupNames + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/LsaSecretAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/LsaSecretAccess.cs new file mode 100644 index 000000000..d065b3cc5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/LsaSecretAccess.cs @@ -0,0 +1,15 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum LsaSecretAccess : uint + { + SetValue = 0x00000001, + QueryValue = 0x00000002, + All = StandardRights.Required | SetValue | QueryValue, + GenericRead = StandardRights.Read | QueryValue, + GenericWrite = StandardRights.Write | SetValue, + GenericExecute = StandardRights.Execute + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/LsaTrustedAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/LsaTrustedAccess.cs new file mode 100644 index 000000000..6fc78a1ad --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/LsaTrustedAccess.cs @@ -0,0 +1,22 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum LsaTrustedAccess : uint + { + QueryDomainName = 0x00000001, + QueryControllers = 0x00000002, + SetControllers = 0x00000004, + QueryPosix = 0x00000008, + SetPosix = 0x00000010, + SetAuth = 0x00000020, + QueryAuth = 0x00000040, + All = StandardRights.Required | QueryDomainName | QueryControllers | + SetControllers | QueryPosix | SetPosix | SetAuth | QueryAuth, + GenericRead = StandardRights.Read | QueryDomainName, + GenericWrite = StandardRights.Write | SetControllers | SetPosix | + SetAuth, + GenericExecute = StandardRights.Execute | QueryControllers | QueryPosix + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/MutantAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/MutantAccess.cs new file mode 100644 index 000000000..07c1449e6 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/MutantAccess.cs @@ -0,0 +1,12 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum MutantAccess : uint + { + QueryState = 0x1, + All = StandardRights.Required | StandardRights.Synchronize | + QueryState + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/ObjectTypeAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/ObjectTypeAccess.cs new file mode 100644 index 000000000..34bb9bdf7 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/ObjectTypeAccess.cs @@ -0,0 +1,11 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum ObjectTypeAccess : uint + { + Create = 0x1, + All = StandardRights.Required | Create + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/PortAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/PortAccess.cs new file mode 100644 index 000000000..8c4b31e90 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/PortAccess.cs @@ -0,0 +1,12 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum PortAccess : uint + { + Connect = 0x1, + All = StandardRights.Required | StandardRights.Synchronize | + Connect + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/Privilege.cs b/branches/ph-plugins/ProcessHacker.Native/Security/Privilege.cs new file mode 100644 index 000000000..3b15299b3 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/Privilege.cs @@ -0,0 +1,274 @@ +/* + * Process Hacker - + * privilege + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Text; +using ProcessHacker.Common.Objects; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; + +namespace ProcessHacker.Native.Security +{ + /// + /// Represents a Windows security privilege. + /// + public sealed class Privilege : BaseObject + { + public static Privilege Enable(string name) + { + using (var thandle = ProcessHandle.Current.GetToken(TokenAccess.AdjustPrivileges)) + { + var privilege = new Privilege(thandle, name); + + privilege.Enable(); + + return privilege; + } + } + + private TokenHandle _tokenHandle; + private Luid _luid; + private SePrivilegeAttributes _attributes; + private string _name; + private string _displayName; + + public Privilege(string name) + : this(null, name) + { } + + public Privilege(TokenHandle tokenHandle, string name) + : this(tokenHandle, name, 0) + { } + + public Privilege(TokenHandle tokenHandle, string name, SePrivilegeAttributes attributes) + : this(tokenHandle, name, false, Luid.Empty, attributes) + { } + + public Privilege(Luid luid) + : this(null, luid) + { } + + public Privilege(LuidAndAttributes laa) + : this(null, laa.Luid, laa.Attributes) + { } + + public Privilege(TokenHandle tokenHandle, Luid luid) + : this(tokenHandle, luid, 0) + { } + + public Privilege(Luid luid, SePrivilegeAttributes attributes) + : this(null, luid, attributes) + { } + + public Privilege(TokenHandle tokenHandle, Luid luid, SePrivilegeAttributes attributes) + : this(tokenHandle, null, true, luid, attributes) + { } + + private Privilege(TokenHandle tokenHandle, string name, bool hasLuid, Luid luid, SePrivilegeAttributes attributes) + : base(tokenHandle != null) + { + _tokenHandle = tokenHandle; + + if (_tokenHandle != null) + _tokenHandle.Reference(); + + _name = name; + _attributes = attributes; + + if (!hasLuid) + { + if (_name == null) + throw new ArgumentException("You must specify either a LUID or a name."); + + _luid = LsaPolicyHandle.LookupPolicyHandle.LookupPrivilegeValue(_name); + } + else + { + _luid = luid; + } + } + + protected override void DisposeObject(bool disposing) + { + if (_tokenHandle != null) + _tokenHandle.Dereference(disposing); + } + + public SePrivilegeAttributes Attributes + { + get { return _attributes; } + } + + public bool Disabled + { + get + { + return (_attributes & SePrivilegeAttributes.Disabled) + != SePrivilegeAttributes.Disabled; + } + set + { + _attributes = SePrivilegeAttributes.Disabled; + } + } + + public string DisplayName + { + get + { + if (_displayName == null) + { + _displayName = LsaPolicyHandle.LookupPolicyHandle.LookupPrivilegeDisplayName(this.Name); + } + + return _displayName; + } + } + + public bool Enabled + { + get + { + return ((_attributes & SePrivilegeAttributes.Enabled) + == SePrivilegeAttributes.Enabled) || this.EnabledByDefault && !this.Disabled; + } + set + { + _attributes = SePrivilegeAttributes.Enabled; + } + } + + public bool EnabledByDefault + { + get + { + return ((_attributes & SePrivilegeAttributes.EnabledByDefault) == + SePrivilegeAttributes.EnabledByDefault) && !this.Disabled; + } + set + { + _attributes = SePrivilegeAttributes.EnabledByDefault; + } + } + + public Luid Luid + { + get { return _luid; } + } + + public string Name + { + get + { + if (_name == null) + { + _name = LsaPolicyHandle.LookupPolicyHandle.LookupPrivilegeName(_luid); + } + + return _name; + } + } + + public bool Removed + { + get + { + return (_attributes & SePrivilegeAttributes.Removed) == + SePrivilegeAttributes.Removed; + } + set + { + _attributes = SePrivilegeAttributes.Removed; + } + } + + public bool UsedForAccess + { + get + { + return (_attributes & SePrivilegeAttributes.UsedForAccess) + == SePrivilegeAttributes.UsedForAccess; + } + set + { + if (value) + _attributes |= SePrivilegeAttributes.UsedForAccess; + else + _attributes &= ~SePrivilegeAttributes.UsedForAccess; + } + } + + public void Disable() + { + if (_tokenHandle == null) + throw new InvalidOperationException( + "Cannot disable the privilege because there is no token associated with the instance."); + this.Disable(_tokenHandle); + } + + public void Disable(TokenHandle tokenHandle) + { + this.SetState(tokenHandle, SePrivilegeAttributes.Disabled); + } + + public void Enable() + { + if (_tokenHandle == null) + throw new InvalidOperationException( + "Cannot enable the privilege because there is no token associated with the instance."); + this.Enable(_tokenHandle); + } + + public void Enable(TokenHandle tokenHandle) + { + this.SetState(tokenHandle, SePrivilegeAttributes.Enabled); + } + + public void Remove() + { + if (_tokenHandle == null) + throw new InvalidOperationException( + "Cannot remove the privilege because there is no token associated with the instance."); + this.Remove(_tokenHandle); + } + + public void Remove(TokenHandle tokenHandle) + { + this.SetState(tokenHandle, SePrivilegeAttributes.Removed); + } + + private void SetState(TokenHandle tokenHandle, SePrivilegeAttributes attributes) + { + _attributes = attributes; + _tokenHandle.SetPrivilege(_luid, _attributes); + } + + public LuidAndAttributes ToLuidAndAttributes() + { + return new LuidAndAttributes() + { + Attributes = _attributes, + Luid = _luid + }; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/PrivilegeSet.cs b/branches/ph-plugins/ProcessHacker.Native/Security/PrivilegeSet.cs new file mode 100644 index 000000000..01c18e857 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/PrivilegeSet.cs @@ -0,0 +1,188 @@ +/* + * Process Hacker - + * privilege set + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native.Security +{ + public sealed class PrivilegeSet : IList + { + private static int _sizeOfLaa = Marshal.SizeOf(typeof(LuidAndAttributes)); + + private List _privileges; + private PrivilegeSetFlags _flags; + + public PrivilegeSet() + : this(null) + { } + + public PrivilegeSet(IEnumerable privileges) + : this(privileges, PrivilegeSetFlags.AllNecessary) + { } + + public PrivilegeSet(IEnumerable privileges, PrivilegeSetFlags flags) + { + if (privileges != null) + _privileges = new List(privileges); + else + _privileges = new List(); + + _flags = flags; + } + + public PrivilegeSet(IntPtr memory) + { + MemoryRegion memoryRegion = new MemoryRegion(memory); + PrivilegeSetStruct privilegeSet = memoryRegion.ReadStruct(); + + _flags = privilegeSet.Flags; + + _privileges = new List(privilegeSet.Count); + + for (int i = 0; i < privilegeSet.Count; i++) + { + _privileges.Add(new Privilege(memoryRegion.ReadStruct(PrivilegeSetStruct.PrivilegesOffset, i))); + } + } + + public PrivilegeSetFlags Flags + { + get { return _flags; } + set { _flags = value; } + } + + public MemoryAlloc ToMemory() + { + int requiredSize = 8 + _sizeOfLaa * _privileges.Count; + MemoryAlloc memory = new MemoryAlloc(requiredSize); + + memory.WriteInt32(0, _privileges.Count); + memory.WriteInt32(4, (int)_flags); + + for (int i = 0; i < _privileges.Count; i++) + memory.WriteStruct(8, i, _privileges[i].ToLuidAndAttributes()); + + return memory; + } + + public TokenPrivileges ToTokenPrivileges() + { + return new TokenPrivileges() + { + PrivilegeCount = _privileges.Count, + Privileges = _privileges.ConvertAll( + (privilege) => privilege.ToLuidAndAttributes()).ToArray() + }; + } + + #region IList Members + + public int IndexOf(Privilege item) + { + return _privileges.IndexOf(item); + } + + public void Insert(int index, Privilege item) + { + _privileges.Insert(index, item); + } + + public void RemoveAt(int index) + { + _privileges.RemoveAt(index); + } + + public Privilege this[int index] + { + get + { + return _privileges[index]; + } + set + { + _privileges[index] = value; + } + } + + #endregion + + #region ICollection Members + + public void Add(Privilege item) + { + _privileges.Add(item); + } + + public void Clear() + { + _privileges.Clear(); + } + + public bool Contains(Privilege item) + { + return _privileges.Contains(item); + } + + public void CopyTo(Privilege[] array, int arrayIndex) + { + _privileges.CopyTo(array, arrayIndex); + } + + public int Count + { + get { return _privileges.Count; } + } + + public bool IsReadOnly + { + get { return false; } + } + + public bool Remove(Privilege item) + { + return _privileges.Remove(item); + } + + #endregion + + #region IEnumerable Members + + public IEnumerator GetEnumerator() + { + return _privileges.GetEnumerator(); + } + + #endregion + + #region IEnumerable Members + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return _privileges.GetEnumerator(); + } + + #endregion + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/ProcessAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/ProcessAccess.cs new file mode 100644 index 000000000..1cd99f35e --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/ProcessAccess.cs @@ -0,0 +1,25 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum ProcessAccess : uint + { + Terminate = 0x0001, + CreateThread = 0x0002, + SetSessionId = 0x0004, + VmOperation = 0x0008, + VmRead = 0x0010, + VmWrite = 0x0020, + DupHandle = 0x0040, + CreateProcess = 0x0080, + SetQuota = 0x0100, + SetInformation = 0x0200, + QueryInformation = 0x0400, + SetPort = 0x0800, + SuspendResume = 0x0800, + QueryLimitedInformation = 0x1000, + // should be 0x1fff on Vista, but is 0xfff for backwards compatibility + All = StandardRights.Required | StandardRights.Synchronize | 0xfff + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/ProfileAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/ProfileAccess.cs new file mode 100644 index 000000000..58b06da8d --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/ProfileAccess.cs @@ -0,0 +1,11 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum ProfileAccess : uint + { + Control = 0x1, + All = StandardRights.Required | Control + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/ResourceManagerAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/ResourceManagerAccess.cs new file mode 100644 index 000000000..9f4408446 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/ResourceManagerAccess.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum ResourceManagerAccess : uint + { + QueryInformation = 0x0001, + SetInformation = 0x0002, + Recover = 0x0004, + Enlist = 0x0008, + GetNotification = 0x0010, + RegisterProtocol = 0x0020, + CompletePropagation = 0x0040, + GenericRead = StandardRights.Read | QueryInformation | StandardRights.Synchronize, + GenericWrite = StandardRights.Write | SetInformation | Recover | Enlist | + GetNotification | RegisterProtocol | CompletePropagation | StandardRights.Synchronize, + GenericExecute = StandardRights.Execute | Recover | Enlist | GetNotification | + CompletePropagation | StandardRights.Synchronize, + All = StandardRights.Required | GenericRead | GenericWrite | GenericExecute + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/ScManagerAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/ScManagerAccess.cs new file mode 100644 index 000000000..a847bf6ee --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/ScManagerAccess.cs @@ -0,0 +1,17 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum ScManagerAccess : uint + { + Connect = 0x0001, + CreateService = 0x0002, + EnumerateService = 0x0004, + Lock = 0x0008, + QueryLockStatus = 0x0010, + ModifyBootConfig = 0x0020, + All = StandardRights.Required | Connect | CreateService | EnumerateService | + Lock | QueryLockStatus | ModifyBootConfig + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/SectionAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/SectionAccess.cs new file mode 100644 index 000000000..8d303a7e6 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/SectionAccess.cs @@ -0,0 +1,16 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum SectionAccess : uint + { + Query = 0x0001, + MapWrite = 0x0002, + MapRead = 0x0004, + MapExecute = 0x0008, + ExtendSize = 0x0010, + MapExecuteExplicit = 0x0020, + All = StandardRights.Required | Query | MapWrite | MapRead | MapExecute | ExtendSize + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/SemaphoreAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/SemaphoreAccess.cs new file mode 100644 index 000000000..9781a8b40 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/SemaphoreAccess.cs @@ -0,0 +1,13 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum SemaphoreAccess : uint + { + QueryState = 0x1, + ModifyState = 0x2, + All = StandardRights.Required | StandardRights.Synchronize | + QueryState | ModifyState + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/ServiceAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/ServiceAccess.cs new file mode 100644 index 000000000..1bcb4045d --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/ServiceAccess.cs @@ -0,0 +1,20 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum ServiceAccess : uint + { + QueryConfig = 0x0001, + ChangeConfig = 0x0002, + QueryStatus = 0x0004, + EnumerateDependents = 0x0008, + Start = 0x0010, + Stop = 0x0020, + PauseContinue = 0x0040, + Interrogate = 0x0080, + UserDefinedControl = 0x0100, + All = StandardRights.Required | QueryConfig | ChangeConfig | QueryStatus | + EnumerateDependents | Start | Stop | PauseContinue | Interrogate | UserDefinedControl + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/Sid.cs b/branches/ph-plugins/ProcessHacker.Native/Security/Sid.cs new file mode 100644 index 000000000..0567a1fd3 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/Sid.cs @@ -0,0 +1,435 @@ +/* + * Process Hacker - + * security identifier + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Text; +using ProcessHacker.Common; +using ProcessHacker.Common.Objects; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; + +namespace ProcessHacker.Native.Security +{ + /// + /// Represents a Windows security identifier (SID). + /// + public sealed class Sid : BaseObject, IEquatable + { + private static readonly byte[] _nullSidAuthority = { 0, 0, 0, 0, 0, 0 }; + private static readonly byte[] _worldSidAuthority = { 0, 0, 0, 0, 0, 1 }; + private static readonly byte[] _localSidAuthority = { 0, 0, 0, 0, 0, 2 }; + private static readonly byte[] _creatorSidAuthority = { 0, 0, 0, 0, 0, 3 }; + private static readonly byte[] _nonUniqueAuthority = { 0, 0, 0, 0, 0, 4 }; + private static readonly byte[] _ntAuthority = { 0, 0, 0, 0, 0, 5 }; + private static readonly byte[] _resourceManagerAuthority = { 0, 0, 0, 0, 0, 9 }; + + public static Sid FromName(string name) + { + return LsaPolicyHandle.LookupPolicyHandle.LookupSid(name); + } + + public static Sid FromPointer(IntPtr sid) + { + return new Sid(new MemoryRegion(sid), false); + } + + public static Sid GetWellKnownSid(WellKnownSidType sidType) + { + using (MemoryAlloc memory = new MemoryAlloc(Win32.SecurityMaxSidSize)) + { + int memorySize = memory.Size; + + if (!Win32.CreateWellKnownSid(sidType, IntPtr.Zero, memory, ref memorySize)) + Win32.ThrowLastError(); + + return new Sid(memory); + } + } + + public static byte[] GetWellKnownSidIdentifierAuthority(WellKnownSidIdentifierAuthority sidAuthority) + { + return GetWellKnownSidIdentifierAuthority(sidAuthority, true); + } + + private static byte[] GetWellKnownSidIdentifierAuthority(WellKnownSidIdentifierAuthority sidAuthority, bool copy) + { + byte[] array; + + switch (sidAuthority) + { + case WellKnownSidIdentifierAuthority.Null: + array = _nullSidAuthority; + break; + case WellKnownSidIdentifierAuthority.World: + array = _worldSidAuthority; + break; + case WellKnownSidIdentifierAuthority.Local: + array = _localSidAuthority; + break; + case WellKnownSidIdentifierAuthority.Creator: + array = _creatorSidAuthority; + break; + case WellKnownSidIdentifierAuthority.NonUnique: + array = _nonUniqueAuthority; + break; + case WellKnownSidIdentifierAuthority.NtAuthority: + array = _ntAuthority; + break; + case WellKnownSidIdentifierAuthority.ResourceManager: + array = _resourceManagerAuthority; + break; + default: + throw new ArgumentException("sidAuthority"); + } + + if (copy) + return array.Duplicate(); + else + return array; + } + + public static implicit operator IntPtr(Sid sid) + { + return sid.Memory; + } + + private MemoryRegion _memory; + private string _systemName; + private bool _hasAttributes; + private SidAttributes _attributes; + + private string _stringSid; + private string _domain; + private string _name; + private SidNameUse _nameUse = 0; + + private Sid(MemoryRegion sid, bool owned) + : base(owned) + { + _memory = sid; + } + + /// + /// Creates a SID from a string representation. + /// + /// The SID string. + public Sid(string stringSid) + : this(stringSid, null) + { } + + /// + /// Creates a SID from a string representation. + /// + /// The SID string. + /// The name of the system on which the SID is located. + public Sid(string stringSid, string systemName) + { + IntPtr sidMemory; + + if (!Win32.ConvertStringSidToSid(stringSid, out sidMemory)) + Win32.ThrowLastError(); + + _memory = new LocalMemoryAlloc(sidMemory, true); + _hasAttributes = false; + } + + /// + /// Copies the specified SID. + /// + /// A pointer to an existing SID. + public Sid(IntPtr sid) + : this(sid, null) + { } + + /// + /// Copies the specified SID. + /// + /// A pointer to an existing SID. + /// The name of the system on which the SID is located. + public Sid(IntPtr sid, string systemName) + : this(sid, false, 0, systemName) + { } + + /// + /// Copies the specified SID. + /// + /// A SID_AND_ATTRIBUTES structure. + public Sid(SidAndAttributes saa) + : this(saa.Sid, saa.Attributes) + { } + + /// + /// Copies the specified SID. + /// + /// A pointer to an existing SID. + /// The attributes associated with the SID. + public Sid(IntPtr sid, SidAttributes attributes) + : this(sid, attributes, null) + { } + + /// + /// Copies the specified SID. + /// + /// A pointer to an existing SID. + /// The attributes associated with the SID. + /// The name of the system on which the SID is located. + public Sid(IntPtr sid, SidAttributes attributes, string systemName) + : this(sid, true, attributes, systemName) + { } + + private Sid(IntPtr sid, bool hasAttributes, SidAttributes attributes, string systemName) + { + NtStatus status; + + _memory = new MemoryAlloc(Win32.RtlLengthSid(sid)); + + if ((status = Win32.RtlCopySid(_memory.Size, _memory, sid)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + _hasAttributes = hasAttributes; + _attributes = attributes; + _systemName = systemName; + } + + protected override void DisposeObject(bool disposing) + { + _memory.Dispose(disposing); + } + + public SidAttributes Attributes + { + get { return _attributes; } + } + + public string DomainName + { + get + { + if (_domain == null) + this.GetNameAndUse(out _domain, out _name, out _nameUse); + return _domain; + } + } + + public byte[] IdentifierAuthority + { + get + { + unsafe + { + return Utils.Create((*Win32.RtlIdentifierAuthoritySid(this)).Value, 6); + } + } + } + + public bool HasAttributes + { + get { return _hasAttributes; } + } + + public int Length + { + get { return Win32.RtlLengthSid(this); } + } + + public IntPtr Memory + { + get { return _memory; } + } + + public SidNameUse NameUse + { + get + { + if (_nameUse == 0) + this.GetNameAndUse(out _domain, out _name, out _nameUse); + return _nameUse; + } + } + + public string UserName + { + get + { + if (_name == null) + this.GetNameAndUse(out _domain, out _name, out _nameUse); + return _name; + } + } + + public int[] SubAuthorities + { + get + { + unsafe + { + byte count = *Win32.RtlSubAuthorityCountSid(this); + int[] subAuthorities = new int[count]; + + for (int i = 0; i < count; i++) + subAuthorities[i] = *Win32.RtlSubAuthoritySid(this, i); + + return subAuthorities; + } + } + } + + public string StringSid + { + get + { + if (_stringSid == null) + _stringSid = this.GetString(); + return _stringSid; + } + } + + public string SystemName + { + get { return _systemName; } + } + + public Sid Clone() + { + return new Sid(this); + } + + public bool DomainEquals(Sid obj) + { + bool equal; + + if (!Win32.EqualDomainSid(this, obj, out equal)) + Win32.ThrowLastError(); + + return equal; + } + + public bool Equals(Sid obj) + { + return Win32.RtlEqualSid(this, obj); + } + + public string GetFullName(bool includeDomain) + { + try + { + if (string.IsNullOrEmpty(this.UserName)) + return this.StringSid; + if (includeDomain) + return this.DomainName + "\\" + this.UserName; + else + return this.UserName; + } + catch + { + return this.StringSid; + } + } + + public override int GetHashCode() + { + int hashCode = 0x12345678; + byte[] identifierAuthority = this.IdentifierAuthority; + int[] subAuthorities = this.SubAuthorities; + + for (int i = 0; i < subAuthorities.Length; i++) + { + hashCode ^= identifierAuthority[(uint)hashCode % identifierAuthority.Length]; + // Reverse and XOR. + hashCode ^= (hashCode >> 24) | ((hashCode >> 16) << 8) | ((hashCode >> 24) << 16) | (hashCode << 24); + hashCode ^= subAuthorities[(uint)hashCode % subAuthorities.Length]; + } + + return hashCode; + } + + private void GetNameAndUse(out string domain, out string name, out SidNameUse nameUse) + { + name = LsaPolicyHandle.LookupPolicyHandle.LookupName(this, out nameUse, out domain); + } + + public WellKnownSidIdentifierAuthority GetWellKnownIdentifierAuthority() + { + byte[] identifierAuthority = this.IdentifierAuthority; + + foreach (WellKnownSidIdentifierAuthority value in + Enum.GetValues(typeof(WellKnownSidIdentifierAuthority))) + { + if (value == WellKnownSidIdentifierAuthority.None) + continue; + + if (Utils.Equals(identifierAuthority, GetWellKnownSidIdentifierAuthority(value, false))) + return value; + } + + return WellKnownSidIdentifierAuthority.None; + } + + private string GetString() + { + NtStatus status; + UnicodeString str = new UnicodeString(); + + if ((status = Win32.RtlConvertSidToUnicodeString(ref str, this, true)) >= NtStatus.Error) + Win32.ThrowLastError(status); + + using (str) + return str.Read(); + } + + public bool IsValid() + { + return Win32.RtlValidSid(this); + } + + public bool PrefixEquals(Sid obj) + { + return Win32.RtlEqualPrefixSid(this, obj); + } + + public SidAndAttributes ToSidAndAttributes() + { + return new SidAndAttributes() + { + Attributes = _attributes, + Sid = this + }; + } + + public override string ToString() + { + return this.StringSid; + } + } + + public enum WellKnownSidIdentifierAuthority + { + None = 0, + Null, + World, + Local, + Creator, + NonUnique, + NtAuthority, + ResourceManager + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/StandardRights.cs b/branches/ph-plugins/ProcessHacker.Native/Security/StandardRights.cs new file mode 100644 index 000000000..4c878cd26 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/StandardRights.cs @@ -0,0 +1,27 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum StandardRights : uint + { + Delete = 0x00010000, + ReadControl = 0x00020000, + WriteDac = 0x00040000, + WriteOwner = 0x00080000, + Synchronize = 0x00100000, + Required = 0x000f0000, + Read = ReadControl, + Write = ReadControl, + Execute = ReadControl, + All = 0x001f0000, + + SpecificRightsAll = 0x0000ffff, + AccessSystemSecurity = 0x01000000, + MaximumAllowed = 0x02000000, + GenericRead = 0x80000000, + GenericWrite = 0x40000000, + GenericExecute = 0x20000000, + GenericAll = 0x10000000 + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/SymbolicLinkAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/SymbolicLinkAccess.cs new file mode 100644 index 000000000..e5ab7d6cf --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/SymbolicLinkAccess.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum SymbolicLinkAccess : uint + { + Query = 0x1, + All = StandardRights.Required | Query + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/ThreadAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/ThreadAccess.cs new file mode 100644 index 000000000..901dbc8d4 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/ThreadAccess.cs @@ -0,0 +1,23 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum ThreadAccess : uint + { + Terminate = 0x0001, + SuspendResume = 0x0002, + Alert = 0x0004, + GetContext = 0x0008, + SetContext = 0x0010, + SetInformation = 0x0020, + QueryInformation = 0x0040, + SetThreadToken = 0x0080, + Impersonate = 0x0100, + DirectImpersonation = 0x0200, + SetLimitedInformation = 0x0400, + QueryLimitedInformation = 0x0800, + // should be 0xfff on Vista, but is 0x3ff for backwards compatibility + All = StandardRights.Required | StandardRights.Synchronize | 0x3ff + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/TimerAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/TimerAccess.cs new file mode 100644 index 000000000..9e2a2d9cc --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/TimerAccess.cs @@ -0,0 +1,13 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum TimerAccess : uint + { + QueryState = 0x1, + ModifyState = 0x2, + All = StandardRights.Required | StandardRights.Synchronize | + QueryState | ModifyState + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/TmAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/TmAccess.cs new file mode 100644 index 000000000..7794c5ecc --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/TmAccess.cs @@ -0,0 +1,21 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum TmAccess : uint + { + QueryInformation = 0x0001, + SetInformation = 0x0002, + Recover = 0x0004, + Rename = 0x0008, + CreateRm = 0x0010, + // About to be deprecated - for DTC use only. + BindTransaction = 0x0020, + GenericRead = StandardRights.Read | QueryInformation, + GenericWrite = StandardRights.Write | SetInformation | Recover | Rename | CreateRm, + GenericExecute = StandardRights.Execute, + All = StandardRights.Required | GenericRead | GenericWrite | + GenericExecute | BindTransaction, + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/TokenAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/TokenAccess.cs new file mode 100644 index 000000000..fd6876858 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/TokenAccess.cs @@ -0,0 +1,24 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum TokenAccess : uint + { + AssignPrimary = 0x0001, + Duplicate = 0x0002, + Impersonate = 0x0004, + Query = 0x0008, + QuerySource = 0x0010, + AdjustPrivileges = 0x0020, + AdjustGroups = 0x0040, + AdjustDefault = 0x0080, + AdjustSessionId = 0x0100, + All = StandardRights.Required | AssignPrimary | Duplicate | Impersonate | + Query | QuerySource | AdjustPrivileges | AdjustGroups | AdjustDefault | + AdjustSessionId, + GenericRead = StandardRights.Read | Query, + GenericWrite = StandardRights.Write | AdjustPrivileges | AdjustGroups | AdjustDefault, + GenericExecute = StandardRights.Execute + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/TransactionAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/TransactionAccess.cs new file mode 100644 index 000000000..870a38b8c --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/TransactionAccess.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum TransactionAccess : uint + { + QueryInformation = 0x0001, + SetInformation = 0x0002, + Enlist = 0x0004, + Commit = 0x0008, + Rollback = 0x0010, + Propagate = 0x0020, + RightReserved1 = 0x0040, + GenericRead = StandardRights.Read | QueryInformation | StandardRights.Synchronize, + GenericWrite = StandardRights.Write | SetInformation | Commit | Enlist | Rollback | + Propagate | StandardRights.Synchronize, + GenericExecute = StandardRights.Execute | Commit | Rollback | StandardRights.Synchronize, + All = StandardRights.Required | GenericRead | GenericWrite | GenericExecute, + + ResourceManagerRights = GenericRead | StandardRights.Write | SetInformation | + Enlist | Rollback | Propagate | StandardRights.Synchronize + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Security/WindowStationAccess.cs b/branches/ph-plugins/ProcessHacker.Native/Security/WindowStationAccess.cs new file mode 100644 index 000000000..a94b8355f --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Security/WindowStationAccess.cs @@ -0,0 +1,27 @@ +using System; + +namespace ProcessHacker.Native.Security +{ + [Flags] + public enum WindowStationAccess : uint + { + EnumDesktops = 0x0001, + ReadAttributes = 0x0002, + AccessClipboard = 0x0004, + CreateDesktop = 0x0008, + WriteAttributes = 0x0010, + AccessGlobalAtoms = 0x0020, + ExitWindows = 0x0040, + Enumerate = 0x0100, + ReadScreen = 0x0200, + All = StandardRights.Required | AccessClipboard | + AccessGlobalAtoms | CreateDesktop | EnumDesktops | Enumerate | + ExitWindows | ReadAttributes | ReadScreen | WriteAttributes, + GenericRead = StandardRights.Read | EnumDesktops | Enumerate | + ReadAttributes | ReadScreen, + GenericWrite = StandardRights.Write | AccessClipboard | + CreateDesktop | WriteAttributes, + GenericExecute = StandardRights.Execute | AccessGlobalAtoms | + ExitWindows + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/SsLogging/FilterType.cs b/branches/ph-plugins/ProcessHacker.Native/SsLogging/FilterType.cs new file mode 100644 index 000000000..111c53720 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/SsLogging/FilterType.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Native.SsLogging +{ + public enum FilterType + { + Include, + Exclude + } + + public static class FilterTypeExtensions + { + public static KphSsFilterType ToKphSs(this FilterType filterType) + { + if (filterType == FilterType.Include) + return KphSsFilterType.Include; + else + return KphSsFilterType.Exclude; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/SsLogging/SsClientId.cs b/branches/ph-plugins/ProcessHacker.Native/SsLogging/SsClientId.cs new file mode 100644 index 000000000..7563d7766 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/SsLogging/SsClientId.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native.SsLogging +{ + public class SsClientId : SsData + { + public SsClientId(MemoryRegion data) + { + this.Original = data.ReadStruct(); + } + + public ClientId Original + { + get; + internal set; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/SsLogging/SsData.cs b/branches/ph-plugins/ProcessHacker.Native/SsLogging/SsData.cs new file mode 100644 index 000000000..2e2b40531 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/SsLogging/SsData.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Native.SsLogging +{ + public class SsData + { + public int Index + { + get; + internal set; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/SsLogging/SsEvent.cs b/branches/ph-plugins/ProcessHacker.Native/SsLogging/SsEvent.cs new file mode 100644 index 000000000..ec697de49 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/SsLogging/SsEvent.cs @@ -0,0 +1,62 @@ +using System; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native.SsLogging +{ + public sealed class SsEvent + { + public int[] Arguments + { + get; + internal set; + } + + public bool ArgumentsCopyFailed + { + get; + internal set; + } + + public bool ArgumentsProbeFailed + { + get; + internal set; + } + + public int CallNumber + { + get; + internal set; + } + + public KProcessorMode Mode + { + get; + internal set; + } + + public int ProcessId + { + get; + internal set; + } + + public IntPtr[] StackTrace + { + get; + internal set; + } + + public int ThreadId + { + get; + internal set; + } + + public DateTime Time + { + get; + internal set; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/SsLogging/SsHandle.cs b/branches/ph-plugins/ProcessHacker.Native/SsLogging/SsHandle.cs new file mode 100644 index 000000000..d964e09e4 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/SsLogging/SsHandle.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Native.SsLogging +{ + public sealed class SsHandle : SsData + { + internal SsHandle(MemoryRegion data) + { + KphSsHandle handleInfo = data.ReadStruct(); + + if (handleInfo.TypeNameOffset != 0) + { + this.TypeName = SsLogger.ReadWString(new MemoryRegion(data, handleInfo.TypeNameOffset)); + } + + if (handleInfo.NameOffset != 0) + { + this.Name = SsLogger.ReadWString(new MemoryRegion(data, handleInfo.NameOffset)); + } + + this.ProcessId = handleInfo.ClientId.ProcessId; + this.ThreadId = handleInfo.ClientId.ThreadId; + } + + public string Name + { + get; + private set; + } + + public int ProcessId + { + get; + private set; + } + + public int ThreadId + { + get; + private set; + } + + public string TypeName + { + get; + private set; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/SsLogging/SsLogger.cs b/branches/ph-plugins/ProcessHacker.Native/SsLogging/SsLogger.cs new file mode 100644 index 000000000..75f67b471 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/SsLogging/SsLogger.cs @@ -0,0 +1,341 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; +using System.Threading; +using ProcessHacker.Native.Threading; +using System.Runtime.InteropServices; + +namespace ProcessHacker.Native.SsLogging +{ + public delegate void ArgumentBlockReceivedDelegate(SsData argBlock); + public delegate void EventBlockReceivedDelegate(SsEvent eventBlock); + + public sealed class SsLogger + { + private const int _highBlockSize = 0x200; + + internal static string ReadWString(MemoryRegion data) + { + KphSsWString wString = data.ReadStruct(); + + return data.ReadUnicodeString(KphSsWString.BufferOffset, wString.Length / 2); + } + + public event ArgumentBlockReceivedDelegate ArgumentBlockReceived; + public event EventBlockReceivedDelegate EventBlockReceived; + + private bool _started = false; + private object _startLock = new object(); + + private bool _terminating = false; + private Thread _bufferWorkerThread; + private ThreadHandle _bufferWorkerThreadHandle; + private Event _bufferWorkerThreadReadyEvent = new Event(true, false); + + private VirtualMemoryAlloc _buffer; + private SemaphoreHandle _readSemaphore; + private SemaphoreHandle _writeSemaphore; + private KphSsClientEntryHandle _clientEntryHandle; + private KphSsRuleSetEntryHandle _ruleSetEntryHandle; + + public SsLogger(int bufferedBlockCount, bool includeAll) + { + // Allocate a buffer. + _buffer = new VirtualMemoryAlloc(_highBlockSize * bufferedBlockCount); + + // Create the read and write semaphores. + + // Read semaphore: no blocks initially, so 0 initial count. + _readSemaphore = SemaphoreHandle.Create(SemaphoreAccess.All, 0, bufferedBlockCount); + // Write semaphore: all buffer blocks available so max. initial count. + _writeSemaphore = SemaphoreHandle.Create(SemaphoreAccess.All, bufferedBlockCount, bufferedBlockCount); + + // Create the client entry. + _clientEntryHandle = KProcessHacker.Instance.SsCreateClientEntry( + ProcessHandle.Current, + _readSemaphore, + _writeSemaphore, + _buffer, + _buffer.Size + ); + + // Create the ruleset entry. + _ruleSetEntryHandle = KProcessHacker.Instance.SsCreateRuleSetEntry( + _clientEntryHandle, + includeAll ? KphSsFilterType.Include : KphSsFilterType.Exclude, + KphSsRuleSetAction.Log + ); + } + + public IntPtr AddNumberRule(FilterType filterType, int number) + { + return KProcessHacker.Instance.SsAddNumberRule( + _ruleSetEntryHandle, + filterType.ToKphSs(), + number + ); + } + + public IntPtr AddPreviousModeRule(FilterType filterType, KProcessorMode previousMode) + { + return KProcessHacker.Instance.SsAddPreviousModeRule( + _ruleSetEntryHandle, + filterType.ToKphSs(), + previousMode + ); + } + + public IntPtr AddProcessIdRule(FilterType filterType, int pid) + { + return KProcessHacker.Instance.SsAddProcessIdRule( + _ruleSetEntryHandle, + filterType.ToKphSs(), + pid.ToIntPtr() + ); + } + + public IntPtr AddThreadIdRule(FilterType filterType, int tid) + { + return KProcessHacker.Instance.SsAddProcessIdRule( + _ruleSetEntryHandle, + filterType.ToKphSs(), + tid.ToIntPtr() + ); + } + + private void BufferWorkerThreadStart() + { + int cursor = 0; + + // Open a handle to the current thread so other functions + // can alert us. + _bufferWorkerThreadHandle = ThreadHandle.OpenCurrent(ThreadAccess.All); + + // We're ready. + _bufferWorkerThreadReadyEvent.Set(); + + while (!_terminating) + { + NtStatus status; + KphSsBlockHeader blockHeader; + + // Wait for a block to read (enable alerting so we can + // be interrupted if someone wants us to stop). + status = _readSemaphore.Wait(true); + + // Did we get alerted? + if (status == NtStatus.Alerted) + return; + + // Check if we have an implicit cursor reset. + if (_buffer.Size - cursor < Marshal.SizeOf(typeof(KphSsBlockHeader))) + cursor = 0; + + // Read the block header. + blockHeader = _buffer.ReadStruct(cursor, 0); + + // Check if we have an explicit cursor reset. + if (blockHeader.Type == KphSsBlockType.Reset) + { + cursor = 0; + blockHeader = _buffer.ReadStruct(cursor, 0); + } + + // Process the block. + if (blockHeader.Type == KphSsBlockType.Event) + { + var eventBlock = _buffer.ReadStruct(cursor, 0); + int[] arguments; + IntPtr[] stackTrace; + + // Reconstruct the argument and stack trace arrays. + + arguments = new int[eventBlock.NumberOfArguments]; + stackTrace = new IntPtr[eventBlock.TraceCount]; + + for (int i = 0; i < arguments.Length; i++) + arguments[i] = _buffer.ReadInt32(cursor + eventBlock.ArgumentsOffset, i); + for (int i = 0; i < stackTrace.Length; i++) + stackTrace[i] = _buffer.ReadIntPtr(cursor + eventBlock.TraceOffset, i); + + // Create an event object. + SsEvent ssEvent = new SsEvent(); + + // Basic information + ssEvent.Time = DateTime.FromFileTime(eventBlock.Time); + ssEvent.ThreadId = eventBlock.ClientId.ThreadId; + ssEvent.ProcessId = eventBlock.ClientId.ProcessId; + ssEvent.Arguments = arguments; + ssEvent.StackTrace = stackTrace; + + // Flags + ssEvent.ArgumentsCopyFailed = + (eventBlock.Flags & KphSsEventFlags.CopyArgumentsFailed) == KphSsEventFlags.CopyArgumentsFailed; + ssEvent.ArgumentsProbeFailed = + (eventBlock.Flags & KphSsEventFlags.ProbeArgumentsFailed) == KphSsEventFlags.ProbeArgumentsFailed; + ssEvent.CallNumber = eventBlock.Number; + + if ((eventBlock.Flags & KphSsEventFlags.UserMode) == KphSsEventFlags.UserMode) + ssEvent.Mode = KProcessorMode.UserMode; + else + ssEvent.Mode = KProcessorMode.KernelMode; + + // Raise the event. + if (this.EventBlockReceived != null) + this.EventBlockReceived(ssEvent); + } + else if (blockHeader.Type == KphSsBlockType.Argument) + { + var argBlock = _buffer.ReadStruct(cursor, 0); + MemoryRegion dataRegion; + SsData ssArg = null; + + dataRegion = new MemoryRegion(_buffer, cursor + KphSsArgumentBlock.DataOffset); + + // Process the argument block based on its type. + switch (argBlock.Type) + { + case KphSsArgumentType.Int8: + { + SsSimple simpleArg = new SsSimple(); + + simpleArg.Argument = argBlock.Data.Int8; + simpleArg.Type = typeof(Byte); + ssArg = simpleArg; + } + break; + case KphSsArgumentType.Int16: + { + SsSimple simpleArg = new SsSimple(); + + simpleArg.Argument = argBlock.Data.Int16; + simpleArg.Type = typeof(Int16); + ssArg = simpleArg; + } + break; + case KphSsArgumentType.Int32: + { + SsSimple simpleArg = new SsSimple(); + + simpleArg.Argument = argBlock.Data.Int32; + simpleArg.Type = typeof(Int32); + ssArg = simpleArg; + } + break; + case KphSsArgumentType.Int64: + { + SsSimple simpleArg = new SsSimple(); + + simpleArg.Argument = argBlock.Data.Int64; + simpleArg.Type = typeof(Int64); + ssArg = simpleArg; + } + break; + case KphSsArgumentType.Handle: + { + ssArg = new SsHandle(dataRegion); + } + break; + case KphSsArgumentType.UnicodeString: + { + ssArg = new SsUnicodeString(dataRegion); + } + break; + case KphSsArgumentType.ObjectAttributes: + { + ssArg = new SsObjectAttributes(dataRegion); + } + break; + case KphSsArgumentType.ClientId: + { + ssArg = new SsClientId(dataRegion); + } + break; + } + + ssArg.Index = argBlock.Index; + + // Raise the event. + if (ssArg != null) + { + if (this.ArgumentBlockReceived != null) + this.ArgumentBlockReceived(ssArg); + } + } + + // Advance the cursor. + cursor += blockHeader.Size; + // Signal that a buffer block is available for writing. + _writeSemaphore.Release(); + } + } + + public void GetStatistics(out int blocksWritten, out int blocksDropped) + { + KphSsClientInformation info; + int retLength; + + KProcessHacker.Instance.SsQueryClientEntry( + _clientEntryHandle, + out info, + Marshal.SizeOf(typeof(KphSsClientInformation)), + out retLength + ); + + blocksWritten = info.NumberOfBlocksWritten; + blocksDropped = info.NumberOfBlocksDropped; + } + + public void RemoveRule(IntPtr handle) + { + KProcessHacker.Instance.SsRemoveRule(_ruleSetEntryHandle, handle); + } + + public void Start() + { + lock (_startLock) + { + if (!_started) + { + KProcessHacker.Instance.SsRef(); + KProcessHacker.Instance.SsEnableClientEntry(_clientEntryHandle, true); + _started = true; + + _terminating = false; + + // Create the buffer worker thread. + _bufferWorkerThread = new Thread(this.BufferWorkerThreadStart); + _bufferWorkerThread.IsBackground = true; + _bufferWorkerThread.Start(); + // Wait for the thread to initialize. + _bufferWorkerThreadReadyEvent.Wait(); + } + } + } + + public void Stop() + { + lock (_startLock) + { + if (_started) + { + KProcessHacker.Instance.SsEnableClientEntry(_clientEntryHandle, false); + KProcessHacker.Instance.SsUnref(); + _started = false; + + // Tell the worker thread to stop. + _terminating = true; + // Alert it just in case it is waiting. + _bufferWorkerThreadHandle.Alert(); + // Wait for the worker thread to terminate. + _bufferWorkerThreadHandle.Wait(); + // Close the thread handle. + _bufferWorkerThreadHandle.Dispose(); + } + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/SsLogging/SsObjectAttributes.cs b/branches/ph-plugins/ProcessHacker.Native/SsLogging/SsObjectAttributes.cs new file mode 100644 index 000000000..82e4cc591 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/SsLogging/SsObjectAttributes.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native.SsLogging +{ + public class SsObjectAttributes : SsData + { + internal SsObjectAttributes(MemoryRegion data) + { + KphSsObjectAttributes oaInfo = data.ReadStruct(); + + if (oaInfo.ObjectNameOffset != 0) + this.ObjectName = new SsUnicodeString(new MemoryRegion(data, oaInfo.ObjectNameOffset)); + + this.Original = oaInfo.ObjectAttributes; + + if (oaInfo.RootDirectoryOffset != 0) + this.RootDirectory = new SsHandle(new MemoryRegion(data, oaInfo.RootDirectoryOffset)); + } + + public SsUnicodeString ObjectName + { + get; + private set; + } + + public ObjectAttributes Original + { + get; + private set; + } + + public SsHandle RootDirectory + { + get; + private set; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/SsLogging/SsSimple.cs b/branches/ph-plugins/ProcessHacker.Native/SsLogging/SsSimple.cs new file mode 100644 index 000000000..6c8d4eaf2 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/SsLogging/SsSimple.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Native.SsLogging +{ + public sealed class SsSimple : SsData + { + public object Argument + { + get; + internal set; + } + + public Type Type + { + get; + internal set; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/SsLogging/SsUnicodeString.cs b/branches/ph-plugins/ProcessHacker.Native/SsLogging/SsUnicodeString.cs new file mode 100644 index 000000000..a224af7d4 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/SsLogging/SsUnicodeString.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native.SsLogging +{ + public sealed class SsUnicodeString : SsData + { + internal SsUnicodeString(MemoryRegion data) + { + KphSsUnicodeString unicodeStringInfo = data.ReadStruct(); + + this.Original = new UnicodeString() + { + Length = unicodeStringInfo.Length, + MaximumLength = unicodeStringInfo.MaximumLength, + Buffer = unicodeStringInfo.Pointer + }; + this.String = data.ReadUnicodeString( + KphSsUnicodeString.BufferOffset, + unicodeStringInfo.Length / 2 + ); + } + + public UnicodeString Original + { + get; + private set; + } + + public string String + { + get; + private set; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Symbols/SymbolInformation.cs b/branches/ph-plugins/ProcessHacker.Native/Symbols/SymbolInformation.cs new file mode 100644 index 000000000..f6c584178 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Symbols/SymbolInformation.cs @@ -0,0 +1,79 @@ +/* + * Process Hacker - + * symbol information + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Runtime.InteropServices; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native.Symbols +{ + public sealed class SymbolInformation + { + internal SymbolInformation(IntPtr symbolInfo, int symbolSize) + { + SymbolInfo si = (SymbolInfo)Marshal.PtrToStructure(symbolInfo, typeof(SymbolInfo)); + + this.Flags = si.Flags; + this.Index = si.Index; + this.ModuleBase = si.ModBase; + this.Name = Marshal.PtrToStringAnsi(symbolInfo.Increment(Win32.SymbolInfoNameOffset), si.NameLen); + this.Size = symbolSize; + this.Address = si.Address; + } + + public long Address + { + get; + private set; + } + + public SymbolFlags Flags + { + get; + private set; + } + + public int Index + { + get; + private set; + } + + public ulong ModuleBase + { + get; + private set; + } + + public string Name + { + get; + private set; + } + + public int Size + { + get; + private set; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Symbols/SymbolProvider.cs b/branches/ph-plugins/ProcessHacker.Native/Symbols/SymbolProvider.cs new file mode 100644 index 000000000..8003911c5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Symbols/SymbolProvider.cs @@ -0,0 +1,512 @@ +/* + * Process Hacker - + * dbghelp.dll wrapper code + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using ProcessHacker.Common; +using ProcessHacker.Common.Objects; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; + +namespace ProcessHacker.Native.Symbols +{ + public delegate bool SymbolEnumDelegate(SymbolInformation symbolInfo); + + public sealed class SymbolProvider : IDisposable + { + private sealed class SymbolHandle : BaseObject + { + private ProcessHandle _processHandle; + private IntPtr _handle; + + public static implicit operator IntPtr(SymbolHandle symbolHandle) + { + return symbolHandle.Handle; + } + + public SymbolHandle() + { + _handle = new IntPtr(_idGen.Pop()); + + using (Win32.DbgHelpLock.AcquireContext()) + { + if (!Win32.SymInitialize(_handle, null, false)) + Win32.ThrowLastError(); + } + } + + public SymbolHandle(ProcessHandle processHandle) + { + _processHandle = processHandle; + _handle = processHandle; + + using (Win32.DbgHelpLock.AcquireContext()) + { + if (!Win32.SymInitialize(_handle, null, false)) + Win32.ThrowLastError(); + } + + _processHandle.Reference(); + } + + protected override void DisposeObject(bool disposing) + { + Win32.DbgHelpLock.Acquire(); + + try + { + Win32.SymCleanup(_handle); + + // If we didn't use a process handle, we got it from the ID generator. + if (_processHandle == null) + _idGen.Push(_handle.ToInt32()); + // Otherwise, dereference the process handle. + else + _processHandle.Dereference(disposing); + } + finally + { + Win32.DbgHelpLock.Release(); + } + } + + public IntPtr Handle + { + get { return _handle; } + } + } + + private const int _maxNameLen = 0x100; + private static IdGenerator _idGen = new IdGenerator(); + + public static SymbolOptions Options + { + get + { + using (Win32.DbgHelpLock.AcquireContext()) + return Win32.SymGetOptions(); + } + + set + { + using (Win32.DbgHelpLock.AcquireContext()) + Win32.SymSetOptions(value); + } + } + + private SymbolHandle _handle; + private List> _modules = new List>(); + + public SymbolProvider() + { + _handle = new SymbolHandle(); + } + + public SymbolProvider(ProcessHandle processHandle) + { + _handle = new SymbolHandle(processHandle); + } + + public void Dispose() + { + _handle.Dispose(); + } + + public bool Busy + { + get + { + if (!Win32.DbgHelpLock.TryAcquire()) + { + return true; + } + else + { + Win32.DbgHelpLock.Release(); + return false; + } + } + } + + public IntPtr Handle + { + get { return _handle; } + } + + public bool PreloadModules { get; set; } + + public string SearchPath + { + get + { + StringBuilder data = new StringBuilder(0x1000); + + using (Win32.DbgHelpLock.AcquireContext()) + { + if (!Win32.SymGetSearchPath(_handle, data, data.Capacity)) + return ""; + } + + return data.ToString(); + } + + set + { + using (Win32.DbgHelpLock.AcquireContext()) + Win32.SymSetSearchPath(_handle, value); + } + } + + public void EnumSymbols(ulong moduleBase, SymbolEnumDelegate enumDelegate) + { + this.EnumSymbols(moduleBase, null, enumDelegate); + } + + public void EnumSymbols(string mask, SymbolEnumDelegate enumDelegate) + { + this.EnumSymbols(0, mask, enumDelegate); + } + + public void EnumSymbols(ulong moduleBase, string mask, SymbolEnumDelegate enumDelegate) + { + using (Win32.DbgHelpLock.AcquireContext()) + { + if (!Win32.SymEnumSymbols( + _handle, + moduleBase, + mask, + (symbolInfo, symbolSize, userContext) => + enumDelegate(new SymbolInformation(symbolInfo, symbolSize)), + IntPtr.Zero + )) + Win32.ThrowLastError(); + } + } + + public string GetLineFromAddress(ulong address) + { + string fileName; + int lineNumber; + + this.GetLineFromAddress(address, out fileName, out lineNumber); + + if (fileName != null) + return fileName + ": line " + lineNumber.ToString(); + else + return null; + } + + public void GetLineFromAddress(ulong address, out string fileName, out int lineNumber) + { + int displacement; + + this.GetLineFromAddress(address, out fileName, out lineNumber, out displacement); + } + + public void GetLineFromAddress(ulong address, out string fileName, out int lineNumber, out int lineDisplacement) + { + ImagehlpLine64 line; + int displacement; + + using (Win32.DbgHelpLock.AcquireContext()) + { + if (!Win32.SymGetLineFromAddr64(_handle, address, out displacement, out line)) + Win32.ThrowLastError(); + + fileName = line.FileName; + lineNumber = line.LineNumber; + lineDisplacement = displacement; + } + } + + public string GetModuleFromAddress(IntPtr address, out IntPtr baseAddress) + { + ulong baseAddressULong; + string fileName = this.GetModuleFromAddress(address.ToUInt64(), out baseAddressULong); + + baseAddress = baseAddressULong.ToIntPtr(); + + return fileName; + } + + public string GetModuleFromAddress(ulong address, out ulong baseAddress) + { + lock (_modules) + { + foreach (var kvp in _modules) + { + if (address >= kvp.Key) + { + baseAddress = kvp.Key; + return kvp.Value; + } + } + } + + baseAddress = 0; + + return null; + } + + public string GetSymbolFromAddress(ulong address) + { + SymbolFlags flags; + + return this.GetSymbolFromAddress(address, out flags); + } + + public string GetSymbolFromAddress(ulong address, out SymbolResolveLevel level) + { + SymbolFlags flags; + string fileName; + + return this.GetSymbolFromAddress(address, out level, out flags, out fileName); + } + + public string GetSymbolFromAddress(ulong address, out SymbolFlags flags) + { + SymbolResolveLevel level; + string fileName; + + return this.GetSymbolFromAddress(address, out level, out flags, out fileName); + } + + public string GetSymbolFromAddress(ulong address, out string fileName) + { + SymbolResolveLevel level; + SymbolFlags flags; + + return this.GetSymbolFromAddress(address, out level, out flags, out fileName); + } + + public string GetSymbolFromAddress(ulong address, out SymbolResolveLevel level, out SymbolFlags flags, out string fileName) + { + string symbolName; + ulong displacement; + + return this.GetSymbolFromAddress(address, out level, out flags, out fileName, out symbolName, out displacement); + } + + public string GetSymbolFromAddress(ulong address, out string fileName, out ulong displacement) + { + SymbolResolveLevel level; + SymbolFlags flags; + string symbolName; + + this.GetSymbolFromAddress(address, out level, out flags, out fileName, out symbolName, out displacement); + + return symbolName; + } + + public string GetSymbolFromAddress(ulong address, out SymbolResolveLevel level, out SymbolFlags flags, out string fileName, out string symbolName, out ulong displacement) + { + // Assume failure (and stop the compiler from complaining). + if (address == 0) + { + level = SymbolResolveLevel.Invalid; + flags = 0; + fileName = null; + } + + // Allocate some memory for the symbol information. + using (var data = new MemoryAlloc(Marshal.SizeOf(typeof(SymbolInfo)) + _maxNameLen)) + { + var info = new SymbolInfo(); + + info.SizeOfStruct = Marshal.SizeOf(info); + info.MaxNameLen = _maxNameLen - 1; + + Marshal.StructureToPtr(info, data, false); + + // Hack for drivers, since we don't get their module sizes. + // Preloading modules will fix this. + if (this.PreloadModules) + { + ulong b; + + this.GetModuleFromAddress(address, out b); + + using (Win32.DbgHelpLock.AcquireContext()) + Win32.SymFromAddr(_handle, b, out displacement, data); + + Marshal.StructureToPtr(info, data, false); + } + + // Get the symbol name. + using (Win32.DbgHelpLock.AcquireContext()) + { + if (Win32.SymFromAddr(_handle, address, out displacement, data)) + { + info = data.ReadStruct(); + } + } + + string modFileName; + ulong modBase; + + // Get the module name. + if (info.ModBase == 0) + { + modFileName = this.GetModuleFromAddress(address, out modBase); + } + else + { + modBase = info.ModBase; + + lock (_modules) + modFileName = _modules.Find(kvp => kvp.Key == info.ModBase).Value; + } + + // If we don't have a module name, return an address. + if (modFileName == null) + { + level = SymbolResolveLevel.Address; + flags = 0; + fileName = null; + symbolName = null; + + return Utils.FormatAddress(address); + } + + FileInfo fi = null; + + fileName = modFileName; + + try + { + fi = new FileInfo(modFileName); + fileName = fi.FullName; + } + catch + { } + + // If we have a module name but not a symbol name, + // return a module plus an offset: module+offset. + if (info.NameLen == 0) + { + level = SymbolResolveLevel.Module; + flags = 0; + symbolName = null; + + if (fi != null) + { + return fi.Name + "+0x" + (address - modBase).ToString("x"); + } + else + { + var s = modFileName.Split('\\'); + + return s[s.Length - 1] + "+0x" + (address - modBase).ToString("x"); + } + } + + // If we have everything, return the full symbol name: module!symbol+offset. + string name = Marshal.PtrToStringAnsi(data.Memory.Increment(Win32.SymbolInfoNameOffset), info.NameLen); + + level = SymbolResolveLevel.Function; + flags = info.Flags; + symbolName = name; + + if (displacement == 0) + return fi.Name + "!" + name; + else + return fi.Name + "!" + name + "+0x" + displacement.ToString("x"); + } + } + + public SymbolInformation GetSymbolFromName(string symbolName) + { + using (var data = new MemoryAlloc(Marshal.SizeOf(typeof(SymbolInfo)) + _maxNameLen)) + { + var info = new SymbolInfo(); + + info.SizeOfStruct = Marshal.SizeOf(info); + info.MaxNameLen = _maxNameLen - 1; + + Marshal.StructureToPtr(info, data, false); + + using (Win32.DbgHelpLock.AcquireContext()) + { + if (!Win32.SymFromName(_handle, symbolName, data)) + Win32.ThrowLastError(); + } + + return new SymbolInformation(data, 0); + } + } + + public void LoadModule(string fileName, IntPtr baseAddress) + { + this.LoadModule(fileName, baseAddress.ToUInt64()); + } + + public void LoadModule(string fileName, ulong baseAddress) + { + this.LoadModule(fileName, baseAddress, 0); + } + + public void LoadModule(string fileName, IntPtr baseAddress, int size) + { + this.LoadModule(fileName, baseAddress.ToUInt64(), size); + } + + public void LoadModule(string fileName, ulong baseAddress, int size) + { + using (Win32.DbgHelpLock.AcquireContext()) + { + if (Win32.SymLoadModule64(_handle, IntPtr.Zero, fileName, null, baseAddress, size) == 0) + Win32.ThrowLastError(); + } + + lock (_modules) + { + _modules.Add(new KeyValuePair(baseAddress, fileName)); + _modules.Sort((kvp1, kvp2) => kvp2.Key.CompareTo(kvp1.Key)); + } + } + + public void UnloadModule(string fileName) + { + KeyValuePair pair; + + lock (_modules) + pair = _modules.Find(kvp => string.Compare(kvp.Value, fileName, true) == 0); + + this.UnloadModule(pair.Key); + } + + public void UnloadModule(ulong baseAddress) + { + using (Win32.DbgHelpLock.AcquireContext()) + { + if (!Win32.SymUnloadModule64(_handle, baseAddress)) + Win32.ThrowLastError(); + } + + lock (_modules) + _modules.RemoveAll(kvp => kvp.Key == baseAddress); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Symbols/SymbolResolveLevel.cs b/branches/ph-plugins/ProcessHacker.Native/Symbols/SymbolResolveLevel.cs new file mode 100644 index 000000000..a5ac4bfa2 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Symbols/SymbolResolveLevel.cs @@ -0,0 +1,53 @@ +/* + * Process Hacker - + * symbol resolve-level + * + * Copyright (C) 2009 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 . + */ + +namespace ProcessHacker.Native.Symbols +{ + /// + /// Specifies the detail with which the address's name was resolved. + /// + public enum SymbolResolveLevel + { + /// + /// Indicates that the address was resolved to a module, a function and possibly an offset. + /// For example: mymodule.dll!MyExportedFunction+0x123 + /// + Function, + + /// + /// Indicates that the address was resolved to a module and an offset. + /// For example: mymodule.dll+0x4321 + /// + Module, + + /// + /// Indicates that the address was not resolved. + /// For example: 0x12345678 + /// + Address, + + /// + /// Indicates that the address was invalid (for example, 0x0). + /// + Invalid + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Threading/CurrentThread.cs b/branches/ph-plugins/ProcessHacker.Native/Threading/CurrentThread.cs new file mode 100644 index 000000000..a269c9e0f --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Threading/CurrentThread.cs @@ -0,0 +1,70 @@ +/* + * Process Hacker - + * thread functions + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; + +namespace ProcessHacker.Native.Threading +{ + /// + /// Provides methods for manipulating the current thread. + /// + public static class CurrentThread + { + /// + /// Switches to another thread. + /// + public static void Sleep() + { + Yield(); + } + + /// + /// Suspends execution of the current thread. + /// + /// The interval to sleep, in milliseconds. + public static void Sleep(int interval) + { + ThreadHandle.Sleep(interval * Win32.TimeMsTo100Ns, true); + } + + /// + /// Suspends execution of the current thread. + /// + /// The time at which wake up. + public static void Sleep(DateTime time) + { + ThreadHandle.Sleep(time.ToFileTime(), false); + } + + /// + /// Switches to another thread. + /// + public static void Yield() + { + ThreadHandle.Yield(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Threading/Event.cs b/branches/ph-plugins/ProcessHacker.Native/Threading/Event.cs new file mode 100644 index 000000000..19b716f82 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Threading/Event.cs @@ -0,0 +1,139 @@ +/* + * Process Hacker - + * event + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Threading +{ + /// + /// Represents a thread synchronization event. + /// + public sealed class Event : NativeObject + { + /// + /// Creates an event. + /// + public Event() + : this(null) + { } + + /// + /// Creates an event. + /// + /// + /// Whether the event should automatically reset to a non-signaled state + /// after all waiters are released. + /// + /// + /// Whether the event should be set to a signaled state initially. + /// + public Event(bool autoReset, bool initialState) + : this(null, autoReset, initialState) + { } + + /// + /// Creates or opens an event. + /// + /// + /// The name of the new event, or the name of an existing event to open. + /// + public Event(string name) + : this(name, false, false) + { } + + /// + /// Creates an event. + /// + /// + /// The name of the new event. + /// + /// + /// Whether the event should automatically reset to a non-signaled state + /// after all waiters are released. + /// + /// + /// Whether the event should be set to a signaled state initially. + /// + public Event(string name, bool autoReset, bool initialState) + { + this.Handle = EventHandle.Create( + EventAccess.All, + name, + ObjectFlags.OpenIf, + null, + autoReset ? EventType.SynchronizationEvent : EventType.NotificationEvent, + initialState + ); + } + + /// + /// Gets whether the event will automatically reset + /// after waiters are released. + /// + public bool AutoReset + { + get + { + return this.Handle.GetBasicInformation().EventType == + EventType.SynchronizationEvent; + } + } + + /// + /// Gets whether the event is in the signaled state. + /// + public bool Signaled + { + get { return this.Handle.GetBasicInformation().EventState != 0; } + } + + /// + /// Attempts to satisfy as many waits as possible and sets + /// the event's state to non-signaled. + /// + public void Pulse() + { + this.Handle.Pulse(); + } + + /// + /// Sets the event's state to non-signaled. + /// + public void Reset() + { + this.Handle.Reset(); + } + + /// + /// Sets the event's state to signaled. + /// + public void Set() + { + this.Handle.Set(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Threading/EventPair.cs b/branches/ph-plugins/ProcessHacker.Native/Threading/EventPair.cs new file mode 100644 index 000000000..4b78b733e --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Threading/EventPair.cs @@ -0,0 +1,109 @@ +/* + * Process Hacker - + * event pair + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Threading +{ + /// + /// Represents an event pair which contains two events, high and low. + /// + public sealed class EventPair : NativeObject + { + /// + /// Creates an event pair. + /// + public EventPair() + : this(null) + { } + + /// + /// Creates or opens an event pair. + /// + /// + /// The name of the new event pair, or the name of an + /// existing event pair. + /// + public EventPair(string name) + { + this.Handle = EventPairHandle.Create( + EventPairAccess.All, + name, + ObjectFlags.OpenIf, + null + ); + } + + /// + /// Sets the high event. + /// + public void SetHigh() + { + this.Handle.SetHigh(); + } + + /// + /// Sets the high event and waits for the low event. + /// + public WaitStatus SetHighWaitLow() + { + return (WaitStatus)this.Handle.SetHighWaitLow(); + } + + /// + /// Sets the low event. + /// + public void SetLow() + { + this.Handle.SetLow(); + } + + /// + /// Sets the low event and waits for the high event. + /// + public WaitStatus SetLowWaitHigh() + { + return (WaitStatus)this.Handle.SetLowWaitHigh(); + } + + /// + /// Waits for the high event. + /// + public WaitStatus WaitHigh() + { + return (WaitStatus)this.Handle.WaitHigh(); + } + + /// + /// Waits for the low event. + /// + public WaitStatus WaitLow() + { + return (WaitStatus)this.Handle.WaitLow(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Threading/KeyedEvent.cs b/branches/ph-plugins/ProcessHacker.Native/Threading/KeyedEvent.cs new file mode 100644 index 000000000..8c38b1f4c --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Threading/KeyedEvent.cs @@ -0,0 +1,122 @@ +/* + * Process Hacker - + * keyed event + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Threading +{ + /// + /// Represents a keyed event. + /// + public sealed class KeyedEvent : NativeObject + { + /// + /// Creates a new keyed event. + /// + public KeyedEvent() + : this(null) + { } + + /// + /// Creates or opens a keyed event. + /// + /// + /// The name of the new keyed event, or the name of an + /// existing keyed event. + /// + public KeyedEvent(string name) + { + this.Handle = KeyedEventHandle.Create( + KeyedEventAccess.All, + name, + ObjectFlags.OpenIf, + null + ); + } + + /// + /// Releases the specified key. If no other thread is waiting + /// on the key, the function blocks until a thread does. + /// + /// The key, which must be divisible by 2. + public void ReleaseKey(int key) + { + this.Handle.ReleaseKey(new IntPtr(key), false, long.MinValue, false); + } + + /// + /// Releases the specified key. If no other thread is waiting + /// on the key, the function blocks until a thread does. + /// + /// The key, which must be divisible by 2. + /// A timeout value, in milliseconds. + public void ReleaseKey(int key, int timeout) + { + this.Handle.ReleaseKey(new IntPtr(key), false, timeout * Win32.TimeMsTo100Ns, true); + } + + /// + /// Releases the specified key. If no other thread is waiting + /// on the key, the function blocks until a thread does. + /// + /// The key, which must be divisible by 2. + /// A time to wait until. + public void ReleaseKey(int key, DateTime timeout) + { + this.Handle.ReleaseKey(new IntPtr(key), false, timeout.ToFileTime(), false); + } + + /// + /// Waits for the specified key to be released. + /// + /// The key, which must be divisible by 2. + public void WaitKey(int key) + { + this.Handle.WaitKey(new IntPtr(key), false, long.MinValue, false); + } + + /// + /// Waits for the specified key to be released. + /// + /// The key, which must be divisible by 2. + /// A time to wait until. + public void WaitKey(int key, int timeout) + { + this.Handle.WaitKey(new IntPtr(key), false, timeout * Win32.TimeMsTo100Ns, true); + } + + /// + /// Waits for the specified key to be released. + /// + /// The key, which must be divisible by 2. + /// A time to wait until. + public void WaitKey(int key, DateTime timeout) + { + this.Handle.WaitKey(new IntPtr(key), false, timeout.ToFileTime(), false); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Threading/Mutant.cs b/branches/ph-plugins/ProcessHacker.Native/Threading/Mutant.cs new file mode 100644 index 000000000..f3841fcbf --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Threading/Mutant.cs @@ -0,0 +1,102 @@ +/* + * Process Hacker - + * mutant + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Threading +{ + /// + /// Represents a mutant which can be used to synchronize access to a shared resource. + /// + public sealed class Mutant : NativeObject + { + /// + /// Creates a mutant. + /// + public Mutant() + : this(null) + { } + + /// + /// Creates a mutant. + /// + /// + /// Whether the mutant should become owned by the current + /// thread when it is created. + /// + public Mutant(bool owned) + : this(null, owned) + { } + + /// + /// Creates or opens a mutant. + /// + /// + /// The name of the new mutant, or the name of an existing mutant to open. + /// + public Mutant(string name) + : this(name, false) + { } + + /// + /// Creates a mutant. + /// + /// + /// The name of the new mutant. + /// + /// + /// Whether the mutant should become owned by the current + /// thread when it is created. + /// + public Mutant(string name, bool owned) + { + this.Handle = MutantHandle.Create( + MutantAccess.All, + name, + ObjectFlags.OpenIf, + null, + owned + ); + } + + /// + /// Gets whether the mutant is currently owned. + /// + public bool Owned + { + get { return this.Handle.GetBasicInformation().CurrentCount <= 0; } + } + + /// + /// Releases the mutant, allowing other waiting threads to own it. + /// + public void Release() + { + this.Handle.Release(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Threading/NativeThreadPool.cs b/branches/ph-plugins/ProcessHacker.Native/Threading/NativeThreadPool.cs new file mode 100644 index 000000000..3074a7801 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Threading/NativeThreadPool.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; + +namespace ProcessHacker.Native.Threading +{ + public delegate void RegisterWaitCallback(object argument, bool timeout); + + public static class NativeThreadPool + { + public static void QueueWorkItem(Action work, object argument) + { + Win32.RtlQueueWorkItem((context) => work(argument), IntPtr.Zero, WtFlags.ExecuteDefault).ThrowIf(); + } + + public static IntPtr RegisterWait(IntPtr handle, RegisterWaitCallback callback, object argument, int timeoutMilliseconds) + { + IntPtr waitHandle; + + Win32.RtlRegisterWait( + out waitHandle, + handle, + (context, timeout) => callback(argument, timeout), + IntPtr.Zero, + timeoutMilliseconds, + WtFlags.ExecuteDefault + ).ThrowIf(); + + return waitHandle; + } + + public static void UnregisterWait(IntPtr waitHandle) + { + Win32.RtlDeregisterWait(waitHandle).ThrowIf(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Threading/Semaphore.cs b/branches/ph-plugins/ProcessHacker.Native/Threading/Semaphore.cs new file mode 100644 index 000000000..cfbf60aea --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Threading/Semaphore.cs @@ -0,0 +1,115 @@ +/* + * Process Hacker - + * semaphore + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Threading +{ + /// + /// Represents a semaphore which can be used to control access to a shared resource. + /// + public sealed class Semaphore : NativeObject + { + /// + /// Creates a binary semaphore. + /// + public Semaphore() + : this(null) + { } + + /// + /// Creates a binary semaphore. + /// + /// The initial count of the semaphore. + /// The maximum count of the semaphore. + public Semaphore(int initialCount, int maximumCount) + : this(null, initialCount, maximumCount) + { } + + /// + /// Creates or opens a semaphore. + /// + /// + /// The name of the new semaphore, or the name of an existing semaphore. + /// + public Semaphore(string name) + : this(name, 1, 1) + { } + + /// + /// Creates a semaphore. + /// + /// The name of the new semaphore. + /// The initial count of the semaphore. + /// The maximum count of the semaphore. + public Semaphore(string name, int initialCount, int maximumCount) + { + this.Handle = SemaphoreHandle.Create( + SemaphoreAccess.All, + name, + ObjectFlags.OpenIf, + null, + initialCount, + maximumCount + ); + } + + /// + /// Gets the current count of the semaphore. + /// + public int Count + { + get { return this.Handle.GetBasicInformation().CurrentCount; } + } + + /// + /// Gets the maximum count of the semaphore. + /// + public int MaximumCount + { + get { return this.Handle.GetBasicInformation().MaximumCount; } + } + + /// + /// Releases the semaphore, incrementing the count. + /// + public void Release() + { + this.Handle.Release(); + } + + /// + /// Releases the semaphore, incrementing the count by the + /// specified amount. + /// + /// The amount to increment the count by. + public void Release(int count) + { + this.Handle.Release(count); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Threading/Timer.cs b/branches/ph-plugins/ProcessHacker.Native/Threading/Timer.cs new file mode 100644 index 000000000..4e9b104a5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Threading/Timer.cs @@ -0,0 +1,216 @@ +/* + * Process Hacker - + * timer + * + * Copyright (C) 2009 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 . + */ + +using System; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Threading +{ + /// + /// Represents a callback to be called when a timer is signaled. + /// + /// The context passed when the timer was set. + public delegate void TimerCallback(IntPtr context); + + /// + /// Represents a timer. + /// + public sealed class Timer : NativeObject + { + private TimerCallback _callback; + + /// + /// Creates a timer. + /// + public Timer() + : this(null) + { } + + /// + /// Creates a timer. + /// + /// + /// Whether the timer should automatically reset to a + /// non-signaled state after waiters have been released. + /// + public Timer(bool autoReset) + : this(null, autoReset) + { } + + /// + /// Creates or opens a timer. + /// + /// + /// The name of the new timer, or the name of an existing timer. + /// + public Timer(string name) + : this(name, false) + { } + + /// + /// Creates a timer. + /// + /// The name of the new timer. + /// + /// Whether the timer should automatically reset to a + /// non-signaled state after waiters have been released. + /// + public Timer(string name, bool autoReset) + { + this.Handle = TimerHandle.Create( + TimerAccess.All, + name, + ObjectFlags.OpenIf, + null, + autoReset ? TimerType.SynchronizationTimer : TimerType.NotificationTimer + ); + } + + /// + /// Gets the remaining time before the timer is signaled. + /// + public TimeSpan RemainingTime + { + get { return new TimeSpan(this.Handle.GetBasicInformation().RemainingTime); } + } + + /// + /// Gets whether the timer is signaled. + /// + public bool Signaled + { + get { return this.Handle.GetBasicInformation().TimerState; } + } + + /// + /// Cancels the timer, preventing it from being signaled. + /// + public void Cancel() + { + this.Handle.Cancel(); + } + + /// + /// Starts the timer. + /// + /// The due time, in milliseconds. + public void Set(int dueTime) + { + this.Set(dueTime, 0); + } + + /// + /// Starts the timer. + /// + /// The due time, in milliseconds. + /// The interval to use for periodic signaling, in milliseconds. + public void Set(int dueTime, int period) + { + this.Set(null, dueTime, period); + } + + /// + /// Starts the timer. + /// + /// A function to be called when the timer is signaled. + /// The due time, in milliseconds. + /// The interval to use for periodic signaling, in milliseconds. + public void Set(TimerCallback callback, int dueTime, int period) + { + this.Set(callback, dueTime, period, IntPtr.Zero); + } + + /// + /// Starts the timer. + /// + /// A function to be called when the timer is signaled. + /// The due time, in milliseconds. + /// The interval to use for periodic signaling, in milliseconds. + /// A value to pass to the callback function. + public void Set(TimerCallback callback, int dueTime, int period, IntPtr context) + { + TimerApcRoutine apcRoutine = (context_, lowPart, highPart) => callback(context_); + + _callback = callback; + this.Handle.Set( + dueTime * Win32.TimeMsTo100Ns, + true, + callback != null ? apcRoutine : null, + context, + period + ); + } + + /// + /// Starts the timer. + /// + /// The time at which the timer will be signaled. + public void Set(DateTime dueTime) + { + this.Set(dueTime, 0); + } + + /// + /// Starts the timer. + /// + /// The time at which the timer will be signaled. + /// The interval to use for periodic signaling, in milliseconds. + public void Set(DateTime dueTime, int period) + { + this.Set(null, dueTime, period); + } + + /// + /// Starts the timer. + /// + /// A function to be called when the timer is signaled. + /// The time at which the timer will be signaled. + /// The interval to use for periodic signaling, in milliseconds. + public void Set(TimerCallback callback, DateTime dueTime, int period) + { + this.Set(callback, dueTime, period, IntPtr.Zero); + } + + /// + /// Starts the timer. + /// + /// A function to be called when the timer is signaled. + /// The time at which the timer will be signaled. + /// The interval to use for periodic signaling, in milliseconds. + /// A value to pass to the callback function. + public void Set(TimerCallback callback, DateTime dueTime, int period, IntPtr context) + { + TimerApcRoutine apcRoutine = (context_, lowPart, highPart) => callback(context_); + + _callback = callback; + this.Handle.Set( + dueTime.ToFileTime(), + false, + callback != null ? apcRoutine : null, + context, + period + ); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Threading/Waiter.cs b/branches/ph-plugins/ProcessHacker.Native/Threading/Waiter.cs new file mode 100644 index 000000000..2b4dc066e --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Threading/Waiter.cs @@ -0,0 +1,367 @@ +/* + * Process Hacker - + * wait manager + * + * Copyright (C) 2009 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 . + */ + +using System.Collections.Generic; +using System.Threading; +using ProcessHacker.Common.Objects; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Threading +{ + public delegate void ObjectSignaledDelegate(ISynchronizable obj); + + /// + /// Provides methods for waiting on dispatcher objects. + /// + public sealed class Waiter : BaseObject + { + private class WaiterThread : BaseObject + { + public event ObjectSignaledDelegate ObjectSignaled; + + private Waiter _owner; + private bool _terminating = false; + private Thread _thread; + private bool _threadInitialized = false; + private ThreadHandle _threadHandle; + private List _waitObjects = new List(); + + public WaiterThread(Waiter owner) + { + _owner = owner; + + // Create the waiter thread. + _thread = new Thread(this.WaiterThreadStart); + _thread.IsBackground = true; + _thread.SetApartmentState(ApartmentState.STA); + _thread.Start(); + + // Wait for the thread to initialize. + lock (_thread) + { + if (!_threadInitialized) + Monitor.Wait(_thread); + } + } + + protected override void DisposeObject(bool disposing) + { + lock (_thread) + { + if (_threadInitialized) + { + // Terminate the waiter thread. + this.Terminate(); + } + } + + if (_threadHandle != null) + { + // Close the thread handle. + _threadHandle.Dispose(); + } + + // Avoid hanging on to objects. + lock (_waitObjects) + _waitObjects.Clear(); + } + + public int Count + { + get + { + lock (_waitObjects) + return _waitObjects.Count; + } + } + + public ISynchronizable[] Objects + { + get + { + lock (_waitObjects) + return _waitObjects.ToArray(); + } + } + + public bool Add(ISynchronizable obj) + { + lock (_waitObjects) + { + // Check if we already have the maximum number of wait objects. + if (_waitObjects.Count >= Win32.MaximumWaitObjects) + return false; + + _waitObjects.Add(obj); + this.NotifyChange(); + return true; + } + } + + public void NotifyChange() + { + _threadHandle.Alert(); + } + + private void OnObjectSignaled(ISynchronizable obj) + { + if (this.ObjectSignaled != null) + this.ObjectSignaled(obj); + } + + public bool Remove(ISynchronizable obj) + { + lock (_waitObjects) + { + if (!_waitObjects.Contains(obj)) + return false; + + _waitObjects.Remove(obj); + this.NotifyChange(); + return true; + } + } + + public void Terminate() + { + _terminating = true; + this.NotifyChange(); + } + + private void WaiterThreadStart() + { + ISynchronizable[] waitObjects = null; + + // Open a handle to the current thread. + _threadHandle = ThreadHandle.OpenCurrent(ThreadAccess.Alert); + + // Signal that the thread has been initialized. + lock (_thread) + { + _threadInitialized = true; + Monitor.PulseAll(_thread); + } + + while (!_terminating) + { + bool doWait; + + lock (_waitObjects) + { + // Check if we have any objects to wait for. If we do, use WaitAny. + // Otherwise, wait forever (alertably). + if (_waitObjects.Count > 0) + { + waitObjects = _waitObjects.ToArray(); + doWait = true; + } + else + { + doWait = false; + } + } + + NtStatus waitStatus; + + if (doWait) + { + // Wait for the objects, (almost) forever. + waitStatus = NativeHandle.WaitAny(waitObjects, true, long.MinValue, false); + } + else + { + // Wait forever. + waitStatus = ThreadHandle.Sleep(true, long.MinValue, false); + } + + if (waitStatus == NtStatus.Alerted) + { + // The wait was changed. Go back to refresh the wait objects array. + // The thread is also alerted to notify that the thread should terminate. + continue; + } + else if (waitStatus >= NtStatus.Wait0 && waitStatus <= NtStatus.Wait63) + { + // One of the objects was signaled. + ISynchronizable signaledObject = waitObjects[(int)(waitStatus - NtStatus.Wait0)]; + + // Remove the object now that it is signaled. + lock (_waitObjects) + { + // Just in case someone already removed the object. + if (_waitObjects.Contains(signaledObject)) + _waitObjects.Remove(signaledObject); + } + + // Call the object-signaled event. + OnObjectSignaled(signaledObject); + + // Balance the threads (which may involve terminating the current one). + _owner.BalanceWaiterThreads(); + } + } + } + } + + /// + /// Raised when an object is signaled. + /// + public event ObjectSignaledDelegate ObjectSignaled; + + private List _waiterThreads = new List(); + private List _waitObjects = new List(); + + /// + /// Creates a waiter. + /// + public Waiter() + { + + } + + protected override void DisposeObject(bool disposing) + { + // Tell the waiter threads to terminate. + foreach (var waiterThread in _waiterThreads) + waiterThread.Terminate(); + _waiterThreads.Clear(); + } + + public int Count + { + get + { + lock (_waitObjects) + return _waitObjects.Count; + } + } + + public ISynchronizable[] Objects + { + get + { + lock (_waitObjects) + return _waitObjects.ToArray(); + } + } + + /// + /// Adds an object for the waiter to wait on. + /// + /// The object to wait for. + public void Add(ISynchronizable obj) + { + lock (_waitObjects) + _waitObjects.Add(obj); + + foreach (var waiterThread in this.GetWaiterThreads()) + { + if (waiterThread.Add(obj)) + return; + } + + // We couldn't add the object to any existing waiter thread. + // Create a new waiter thread and add the object to that. + this.CreateWaiterThread(obj); + } + + internal void BalanceWaiterThreads() + { + lock (_waitObjects) + { + // Eliminate waiter threads with no objects. + foreach (var waiterThread in this.GetWaiterThreads()) + { + if (waiterThread.Count == 0) + this.DeleteWaiterThread(waiterThread); + } + } + } + + private WaiterThread CreateWaiterThread() + { + return this.CreateWaiterThread(null); + } + + private WaiterThread CreateWaiterThread(ISynchronizable obj) + { + WaiterThread waiterThread = new WaiterThread(this); + + waiterThread.ObjectSignaled += this.OnObjectSignaled; + + if (obj != null) + waiterThread.Add(obj); + + lock (_waiterThreads) + _waiterThreads.Add(waiterThread); + + return waiterThread; + } + + private void DeleteWaiterThread(WaiterThread waiterThread) + { + lock (_waiterThreads) + { + _waiterThreads.Remove(waiterThread); + waiterThread.ObjectSignaled -= this.OnObjectSignaled; + waiterThread.Dispose(); + } + } + + private WaiterThread[] GetWaiterThreads() + { + lock (_waiterThreads) + return _waiterThreads.ToArray(); + } + + private void OnObjectSignaled(ISynchronizable obj) + { + if (ObjectSignaled != null) + ObjectSignaled(obj); + } + + /// + /// Removes an object the waiter is waiting on. + /// + /// An object which is currently being waited on. + /// Whether the object was successfully removed. + public bool Remove(ISynchronizable obj) + { + foreach (var waiterThread in this.GetWaiterThreads()) + { + if (waiterThread.Remove(obj)) + { + lock (_waitObjects) + _waitObjects.Remove(obj); + + this.BalanceWaiterThreads(); + return true; + } + } + + // We couldn't remove the object. + return false; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Ui/ChooseProcessDialog.Designer.cs b/branches/ph-plugins/ProcessHacker.Native/Ui/ChooseProcessDialog.Designer.cs new file mode 100644 index 000000000..f47da2a50 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Ui/ChooseProcessDialog.Designer.cs @@ -0,0 +1,156 @@ +namespace ProcessHacker.Native.Ui +{ + partial class ChooseProcessDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ChooseProcessDialog)); + this.listProcesses = new System.Windows.Forms.ListView(); + this.columnName = new System.Windows.Forms.ColumnHeader(); + this.columnPID = new System.Windows.Forms.ColumnHeader(); + this.columnUsername = new System.Windows.Forms.ColumnHeader(); + this.imageList = new System.Windows.Forms.ImageList(this.components); + this.buttonCancel = new System.Windows.Forms.Button(); + this.buttonOK = new System.Windows.Forms.Button(); + this.buttonRefresh = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // listProcesses + // + this.listProcesses.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listProcesses.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnName, + this.columnPID, + this.columnUsername}); + this.listProcesses.FullRowSelect = true; + this.listProcesses.HideSelection = false; + this.listProcesses.Location = new System.Drawing.Point(12, 12); + this.listProcesses.MultiSelect = false; + this.listProcesses.Name = "listProcesses"; + this.listProcesses.Size = new System.Drawing.Size(451, 350); + this.listProcesses.SmallImageList = this.imageList; + this.listProcesses.TabIndex = 0; + this.listProcesses.UseCompatibleStateImageBehavior = false; + this.listProcesses.View = System.Windows.Forms.View.Details; + this.listProcesses.SelectedIndexChanged += new System.EventHandler(this.listProcesses_SelectedIndexChanged); + this.listProcesses.DoubleClick += new System.EventHandler(this.listProcesses_DoubleClick); + // + // columnName + // + this.columnName.Text = "Name"; + this.columnName.Width = 200; + // + // columnPID + // + this.columnPID.Text = "PID"; + // + // columnUsername + // + this.columnUsername.Text = "Username"; + this.columnUsername.Width = 150; + // + // imageList + // + this.imageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList.ImageStream"))); + this.imageList.TransparentColor = System.Drawing.Color.Transparent; + this.imageList.Images.SetKeyName(0, "generic_process"); + // + // buttonCancel + // + this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonCancel.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonCancel.Location = new System.Drawing.Point(388, 368); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.TabIndex = 1; + this.buttonCancel.Text = "Cancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click); + // + // buttonOK + // + this.buttonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonOK.Enabled = false; + this.buttonOK.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonOK.Location = new System.Drawing.Point(307, 368); + this.buttonOK.Name = "buttonOK"; + this.buttonOK.Size = new System.Drawing.Size(75, 23); + this.buttonOK.TabIndex = 2; + this.buttonOK.Text = "OK"; + this.buttonOK.UseVisualStyleBackColor = true; + this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click); + // + // buttonRefresh + // + this.buttonRefresh.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.buttonRefresh.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonRefresh.Location = new System.Drawing.Point(12, 368); + this.buttonRefresh.Name = "buttonRefresh"; + this.buttonRefresh.Size = new System.Drawing.Size(75, 23); + this.buttonRefresh.TabIndex = 3; + this.buttonRefresh.Text = "Refresh"; + this.buttonRefresh.UseVisualStyleBackColor = true; + this.buttonRefresh.Click += new System.EventHandler(this.buttonRefresh_Click); + // + // ChooseProcessDialog + // + this.AcceptButton = this.buttonOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(475, 403); + this.Controls.Add(this.buttonRefresh); + this.Controls.Add(this.buttonOK); + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.listProcesses); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ChooseProcessDialog"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Choose Process"; + this.Load += new System.EventHandler(this.ChooseProcessDialog_Load); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.ListView listProcesses; + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.Button buttonOK; + private System.Windows.Forms.Button buttonRefresh; + private System.Windows.Forms.ColumnHeader columnName; + private System.Windows.Forms.ColumnHeader columnPID; + private System.Windows.Forms.ColumnHeader columnUsername; + private System.Windows.Forms.ImageList imageList; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker.Native/Ui/ChooseProcessDialog.cs b/branches/ph-plugins/ProcessHacker.Native/Ui/ChooseProcessDialog.cs new file mode 100644 index 000000000..12d82eb22 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Ui/ChooseProcessDialog.cs @@ -0,0 +1,122 @@ +using System; +using System.Drawing; +using System.Windows.Forms; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native.Ui +{ + public partial class ChooseProcessDialog : Form + { + private int _selectedPid; + + public ChooseProcessDialog() + { + InitializeComponent(); + } + + private void ChooseProcessDialog_Load(object sender, EventArgs e) + { + this.RefreshProcesses(); + } + + public int SelectedPid + { + get { return _selectedPid; } + } + + private void RefreshProcesses() + { + var processes = Windows.GetProcesses(); + + listProcesses.BeginUpdate(); + listProcesses.Items.Clear(); + + var generic_process = imageList.Images["generic_process"]; + imageList.Images.Clear(); + imageList.Images.Add("generic_process", generic_process); + + foreach (var process in processes.Values) + { + string userName = ""; + string fileName = null; + + try + { + using (var phandle = new ProcessHandle(process.Process.ProcessId, OSVersion.MinProcessQueryInfoAccess)) + { + using (var thandle = phandle.GetToken(TokenAccess.Query)) + using (var sid = thandle.GetUser()) + userName = sid.GetFullName(true); + + fileName = FileUtils.GetFileName(phandle.GetImageFileName()); + } + } + catch + { } + + ListViewItem item = new ListViewItem( + new string[] + { + process.Process.ProcessId == 0 ? "System Idle Process" : process.Name, + process.Process.ProcessId.ToString(), + userName + }); + + if (!string.IsNullOrEmpty(fileName)) + { + Icon fileIcon = FileUtils.GetFileIcon(fileName); + + if (fileIcon != null) + { + imageList.Images.Add(process.Process.ProcessId.ToString(), fileIcon); + item.ImageKey = process.Process.ProcessId.ToString(); + } + } + + if (string.IsNullOrEmpty(item.ImageKey)) + item.ImageKey = "generic_process"; + + listProcesses.Items.Add(item); + } + + listProcesses.EndUpdate(); + } + + private void ChooseProcess() + { + if (listProcesses.SelectedItems.Count != 1) + return; + + _selectedPid = int.Parse(listProcesses.SelectedItems[0].SubItems[1].Text); + this.DialogResult = DialogResult.OK; + this.Close(); + } + + private void buttonRefresh_Click(object sender, EventArgs e) + { + this.RefreshProcesses(); + } + + private void buttonOK_Click(object sender, EventArgs e) + { + this.ChooseProcess(); + } + + private void buttonCancel_Click(object sender, EventArgs e) + { + this.DialogResult = DialogResult.Cancel; + this.Close(); + } + + private void listProcesses_DoubleClick(object sender, EventArgs e) + { + this.ChooseProcess(); + } + + private void listProcesses_SelectedIndexChanged(object sender, EventArgs e) + { + buttonOK.Enabled = listProcesses.SelectedItems.Count == 1; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Ui/ChooseProcessDialog.resx b/branches/ph-plugins/ProcessHacker.Native/Ui/ChooseProcessDialog.resx new file mode 100644 index 000000000..242013521 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Ui/ChooseProcessDialog.resx @@ -0,0 +1,155 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj0yLjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAACc + BQAAAk1TRnQBSQFMAwEBAAEEAQABBAEAARABAAEQAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABQAMA + ARADAAEBAQABIAYAARD/AP8AFAABlwGSAY8B/wGXAZIBjwH/AZcBkgGPAf8BlwGSAY8B/wGXAZIBjwH/ + AZcBkgGPAf8BlwGSAY8B/wGXAZIBjwH/AZcBkgGPAf8BlwGSAY8B/wGXAZIBjwH/AZcBkgGPAf8BlwGS + AY8B/wGXAZIBjwH/AZcBkgGPAf8BlwGSAY8B/8AAAZcBkgGPCf8D/gH/A/wB/wP6Af8D+AH/A/UB/wPz + Af8D8QH/A+4B/wPsAf8D6QH/A+gB/wPmAf8BlwGSAY8B/8AAAZcBkgGPCf8D/gH/A/wB/wP6Af8D+AH/ + A/UB/wP1Af8D8wH/A/AB/wPuAf8D6wH/A+kB/wPnAf8BlwGSAY8B/8AAAZcBkgGPBf8BhwGdAVIB/wGC + AaIBVgH/AXoBqAFaAf8BdAGtAV4B/wFwAbEBYgH/A/cB/wHNAcwBygH/Ac0BzAHKAf8BzQHMAcoB/wHN + AcwBygH/A+0B/wPrAf8D6AH/AZcBkgGPAf/AAAGXAZIBjwX/AY0BlAFMAf8BiQGaAVAB/wGEAaABVAH/ + AXwBpQFYAf8BdwGqAVwB/wP5Af8D9gH/A/QB/wP0Af8D8QH/A+8B/wPsAf8D6gH/AZcBkgGPAf/AAAGX + AZIBjwX/AZMBiQFHAf8BjwGQAUoB/wGLAZcBTgH/AYcBnQFSAf8BggGiAVYB/wP7Af8BzQHMAcoB/wHN + AcwBygH/Ac0BzAHKAf8BzQHMAcoB/wPxAf8BeAGpAVsB/wPsAf8BlwGSAY8B/8AAAZcBkgGPBf8BmAF5 + AUEB/wGVAYQBRQH/AZEBjAFIAf8BjQGUAUwB/wGJAZoBUAH/A/wB/wP6Af8D+AH/A/gB/wP1Af8D8wH/ + AYsBlwFOAf8D7gH/AZcBkgGPAf/AAAGXAZIBjwX/AZ0BbwE8Af8BmgF2AT8B/wGWAYABQwH/AZMBiQFH + Af8BjwGQAUoB/wP9Af8BzQHMAcoB/wHNAcwBygH/Ac0BzAHKAf8BzQHMAcoB/wP1Af8BlwF7AUIB/wPv + Af8BlwGSAY8B/8AAAZcBkgGPBf8BoAFnATkB/wGeAWwBOwH/AZsBcgE+Af8BmAF5AUEB/wGVAYQBRQH/ + A/4B/wP+Af8D/QH/A/sB/wP5Af8D9gH/AaABZwE5Af8D8QH/AZcBkgGPAf/AAAGXAZIBjxn/A/4B/wP+ + Af8D/QH/A/sB/wP5Af8D9gH/A/QB/wPxAf8BlwGSAY8B/8AAAZcBkgGPAf8BzQHMAcoB/wHNAcwBygH/ + Ac0BzAHKAf8BzQHMAcoB/wHNAcwBygH/Ac0BzAHKAf8BzQHMAcoB/wHNAcwBygH/Ac0BzAHKAf8BzQHM + AcoB/wHNAcwBygH/Ac0BzAHKAf8BzQHMAcoB/wHNAcwBygH/AZcBkgGPAf/AAAGXAZIBjwH/AeAB2QHT + Af8B4AHZAdMB/wHgAdkB0wH/AeAB2QHTAf8B4AHZAdMB/wHgAdkB0wH/AeAB2QHTAf8B4AHZAdMB/wHg + AdkB0wH/AZEBdgFlAf8B4AHZAdMB/wGRAXYBZQH/AeAB2QHTAf8BkQF2AWUB/wGXAZIBjwH/wAABlwGS + AY8B/wGXAZIBjwH/AZcBkgGPAf8BlwGSAY8B/wGXAZIBjwH/AZcBkgGPAf8BlwGSAY8B/wGXAZIBjwH/ + AZcBkgGPAf8BlwGSAY8B/wGXAZIBjwH/AZcBkgGPAf8BlwGSAY8B/wGXAZIBjwH/AZcBkgGPAf8BlwGS + AY8B//8AwQABQgFNAT4HAAE+AwABKAMAAUADAAEQAwABAQEAAQEFAAGAFwAD/wEAAv8GAAL/bgAC/wYA + Cw== + + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker.Native/Ui/HandlePropertiesWindow.Designer.cs b/branches/ph-plugins/ProcessHacker.Native/Ui/HandlePropertiesWindow.Designer.cs new file mode 100644 index 000000000..3b5f6a828 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Ui/HandlePropertiesWindow.Designer.cs @@ -0,0 +1,327 @@ +namespace ProcessHacker.Native.Ui +{ + partial class HandlePropertiesWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.tabControl = new System.Windows.Forms.TabControl(); + this.tabDetails = new System.Windows.Forms.TabPage(); + this.groupObjectInfo = new System.Windows.Forms.GroupBox(); + this.groupQuotaCharges = new System.Windows.Forms.GroupBox(); + this.labelNonPaged = new System.Windows.Forms.Label(); + this.labelPaged = new System.Windows.Forms.Label(); + this.groupReferences = new System.Windows.Forms.GroupBox(); + this.labelHandles = new System.Windows.Forms.Label(); + this.labelReferences = new System.Windows.Forms.Label(); + this.groupBasicInfo = new System.Windows.Forms.GroupBox(); + this.textGrantedAccess = new System.Windows.Forms.TextBox(); + this.textAddress = new System.Windows.Forms.TextBox(); + this.textType = new System.Windows.Forms.TextBox(); + this.textName = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.buttonClose = new System.Windows.Forms.Button(); + this.buttonPermissions = new System.Windows.Forms.Button(); + this.tabControl.SuspendLayout(); + this.tabDetails.SuspendLayout(); + this.groupQuotaCharges.SuspendLayout(); + this.groupReferences.SuspendLayout(); + this.groupBasicInfo.SuspendLayout(); + this.SuspendLayout(); + // + // tabControl + // + this.tabControl.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.tabControl.Controls.Add(this.tabDetails); + this.tabControl.Location = new System.Drawing.Point(12, 12); + this.tabControl.Name = "tabControl"; + this.tabControl.SelectedIndex = 0; + this.tabControl.Size = new System.Drawing.Size(370, 382); + this.tabControl.TabIndex = 0; + // + // tabDetails + // + this.tabDetails.Controls.Add(this.groupObjectInfo); + this.tabDetails.Controls.Add(this.groupQuotaCharges); + this.tabDetails.Controls.Add(this.groupReferences); + this.tabDetails.Controls.Add(this.groupBasicInfo); + this.tabDetails.Location = new System.Drawing.Point(4, 22); + this.tabDetails.Name = "tabDetails"; + this.tabDetails.Padding = new System.Windows.Forms.Padding(3); + this.tabDetails.Size = new System.Drawing.Size(362, 356); + this.tabDetails.TabIndex = 0; + this.tabDetails.Text = "Details"; + this.tabDetails.UseVisualStyleBackColor = true; + // + // groupObjectInfo + // + this.groupObjectInfo.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupObjectInfo.Location = new System.Drawing.Point(6, 215); + this.groupObjectInfo.Name = "groupObjectInfo"; + this.groupObjectInfo.Size = new System.Drawing.Size(350, 135); + this.groupObjectInfo.TabIndex = 3; + this.groupObjectInfo.TabStop = false; + this.groupObjectInfo.Text = "Object Information"; + // + // groupQuotaCharges + // + this.groupQuotaCharges.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupQuotaCharges.Controls.Add(this.labelNonPaged); + this.groupQuotaCharges.Controls.Add(this.labelPaged); + this.groupQuotaCharges.Location = new System.Drawing.Point(179, 138); + this.groupQuotaCharges.Name = "groupQuotaCharges"; + this.groupQuotaCharges.Size = new System.Drawing.Size(177, 71); + this.groupQuotaCharges.TabIndex = 2; + this.groupQuotaCharges.TabStop = false; + this.groupQuotaCharges.Text = "Quota Charges"; + // + // labelNonPaged + // + this.labelNonPaged.AutoSize = true; + this.labelNonPaged.Location = new System.Drawing.Point(6, 42); + this.labelNonPaged.Name = "labelNonPaged"; + this.labelNonPaged.Size = new System.Drawing.Size(64, 13); + this.labelNonPaged.TabIndex = 2; + this.labelNonPaged.Text = "Non-Paged:"; + // + // labelPaged + // + this.labelPaged.AutoSize = true; + this.labelPaged.Location = new System.Drawing.Point(6, 21); + this.labelPaged.Name = "labelPaged"; + this.labelPaged.Size = new System.Drawing.Size(41, 13); + this.labelPaged.TabIndex = 2; + this.labelPaged.Text = "Paged:"; + // + // groupReferences + // + this.groupReferences.Controls.Add(this.labelHandles); + this.groupReferences.Controls.Add(this.labelReferences); + this.groupReferences.Location = new System.Drawing.Point(6, 138); + this.groupReferences.Name = "groupReferences"; + this.groupReferences.Size = new System.Drawing.Size(167, 71); + this.groupReferences.TabIndex = 1; + this.groupReferences.TabStop = false; + this.groupReferences.Text = "References"; + // + // labelHandles + // + this.labelHandles.AutoSize = true; + this.labelHandles.Location = new System.Drawing.Point(6, 42); + this.labelHandles.Name = "labelHandles"; + this.labelHandles.Size = new System.Drawing.Size(49, 13); + this.labelHandles.TabIndex = 2; + this.labelHandles.Text = "Handles:"; + // + // labelReferences + // + this.labelReferences.AutoSize = true; + this.labelReferences.Location = new System.Drawing.Point(6, 21); + this.labelReferences.Name = "labelReferences"; + this.labelReferences.Size = new System.Drawing.Size(65, 13); + this.labelReferences.TabIndex = 2; + this.labelReferences.Text = "References:"; + // + // groupBasicInfo + // + this.groupBasicInfo.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBasicInfo.Controls.Add(this.buttonPermissions); + this.groupBasicInfo.Controls.Add(this.textGrantedAccess); + this.groupBasicInfo.Controls.Add(this.textAddress); + this.groupBasicInfo.Controls.Add(this.textType); + this.groupBasicInfo.Controls.Add(this.textName); + this.groupBasicInfo.Controls.Add(this.label4); + this.groupBasicInfo.Controls.Add(this.label3); + this.groupBasicInfo.Controls.Add(this.label2); + this.groupBasicInfo.Controls.Add(this.label1); + this.groupBasicInfo.Location = new System.Drawing.Point(6, 6); + this.groupBasicInfo.Name = "groupBasicInfo"; + this.groupBasicInfo.Size = new System.Drawing.Size(350, 126); + this.groupBasicInfo.TabIndex = 0; + this.groupBasicInfo.TabStop = false; + this.groupBasicInfo.Text = "Basic Information"; + // + // textGrantedAccess + // + this.textGrantedAccess.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textGrantedAccess.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.textGrantedAccess.Location = new System.Drawing.Point(98, 76); + this.textGrantedAccess.Name = "textGrantedAccess"; + this.textGrantedAccess.Size = new System.Drawing.Size(246, 13); + this.textGrantedAccess.TabIndex = 1; + // + // textAddress + // + this.textAddress.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textAddress.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.textAddress.Location = new System.Drawing.Point(98, 57); + this.textAddress.Name = "textAddress"; + this.textAddress.Size = new System.Drawing.Size(246, 13); + this.textAddress.TabIndex = 1; + // + // textType + // + this.textType.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textType.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.textType.Location = new System.Drawing.Point(60, 38); + this.textType.Name = "textType"; + this.textType.Size = new System.Drawing.Size(284, 13); + this.textType.TabIndex = 1; + // + // textName + // + this.textName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textName.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.textName.Location = new System.Drawing.Point(60, 19); + this.textName.Name = "textName"; + this.textName.Size = new System.Drawing.Size(284, 13); + this.textName.TabIndex = 1; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(6, 76); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(86, 13); + this.label4.TabIndex = 0; + this.label4.Text = "Granted Access:"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(6, 57); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(82, 13); + this.label3.TabIndex = 0; + this.label3.Text = "Object Address:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(6, 38); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(34, 13); + this.label2.TabIndex = 0; + this.label2.Text = "Type:"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(6, 19); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(38, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Name:"; + // + // buttonClose + // + this.buttonClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonClose.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonClose.Location = new System.Drawing.Point(307, 400); + this.buttonClose.Name = "buttonClose"; + this.buttonClose.Size = new System.Drawing.Size(75, 23); + this.buttonClose.TabIndex = 1; + this.buttonClose.Text = "Close"; + this.buttonClose.UseVisualStyleBackColor = true; + this.buttonClose.Click += new System.EventHandler(this.buttonClose_Click); + // + // buttonPermissions + // + this.buttonPermissions.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonPermissions.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonPermissions.Location = new System.Drawing.Point(269, 97); + this.buttonPermissions.Name = "buttonPermissions"; + this.buttonPermissions.Size = new System.Drawing.Size(75, 23); + this.buttonPermissions.TabIndex = 2; + this.buttonPermissions.Text = "Permissions"; + this.buttonPermissions.UseVisualStyleBackColor = true; + this.buttonPermissions.Click += new System.EventHandler(this.buttonPermissions_Click); + // + // HandlePropertiesWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(394, 435); + this.Controls.Add(this.buttonClose); + this.Controls.Add(this.tabControl); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "HandlePropertiesWindow"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Handle Properties"; + this.Load += new System.EventHandler(this.HandlePropertiesWindow_Load); + this.tabControl.ResumeLayout(false); + this.tabDetails.ResumeLayout(false); + this.groupQuotaCharges.ResumeLayout(false); + this.groupQuotaCharges.PerformLayout(); + this.groupReferences.ResumeLayout(false); + this.groupReferences.PerformLayout(); + this.groupBasicInfo.ResumeLayout(false); + this.groupBasicInfo.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TabControl tabControl; + private System.Windows.Forms.TabPage tabDetails; + private System.Windows.Forms.Button buttonClose; + private System.Windows.Forms.GroupBox groupBasicInfo; + private System.Windows.Forms.TextBox textName; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox textGrantedAccess; + private System.Windows.Forms.TextBox textAddress; + private System.Windows.Forms.TextBox textType; + private System.Windows.Forms.GroupBox groupReferences; + private System.Windows.Forms.Label labelHandles; + private System.Windows.Forms.Label labelReferences; + private System.Windows.Forms.GroupBox groupQuotaCharges; + private System.Windows.Forms.Label labelNonPaged; + private System.Windows.Forms.Label labelPaged; + private System.Windows.Forms.GroupBox groupObjectInfo; + private System.Windows.Forms.Button buttonPermissions; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker.Native/Ui/HandlePropertiesWindow.cs b/branches/ph-plugins/ProcessHacker.Native/Ui/HandlePropertiesWindow.cs new file mode 100644 index 000000000..c38562225 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Ui/HandlePropertiesWindow.cs @@ -0,0 +1,151 @@ +/* + * Process Hacker - + * handle properties window + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Windows.Forms; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security.AccessControl; + +namespace ProcessHacker.Native.Ui +{ + public partial class HandlePropertiesWindow : Form + { + public delegate void HandlePropertiesDelegate(Control objectGroup, string name, string typeName); + + public event HandlePropertiesDelegate HandlePropertiesCallback; + + private string _name, _typeName; + private NativeHandle _objectHandle; + + public HandlePropertiesWindow(SystemHandleEntry handle) + { + InitializeComponent(); + this.KeyPreview = true; + this.KeyDown += (sender, e) => + { + if (e.KeyCode == Keys.Escape) + { + this.Close(); + e.Handled = true; + } + }; + + var handleInfo = handle.GetHandleInfo(); + + textName.Text = _name = handleInfo.BestName; + if (textName.Text == "") + textName.Text = "(unnamed object)"; + textType.Text = _typeName = handleInfo.TypeName; + textAddress.Text = "0x" + handle.Object.ToString("x"); + textGrantedAccess.Text = "0x" + handle.GrantedAccess.ToString("x"); + + if (handle.GrantedAccess != 0) + { + try + { + Type accessEnumType = NativeTypeFactory.GetAccessType(handleInfo.TypeName); + + textGrantedAccess.Text += " (" + + NativeTypeFactory.GetAccessString(accessEnumType, handle.GrantedAccess) + + ")"; + } + catch (NotSupportedException) + { } + } + + var basicInfo = handle.GetBasicInfo(); + + labelReferences.Text = "References: " + (basicInfo.PointerCount - 1).ToString(); + labelHandles.Text = "Handles: " + basicInfo.HandleCount.ToString(); + labelPaged.Text = "Paged: " + basicInfo.PagedPoolUsage.ToString(); + labelNonPaged.Text = "Non-Paged: " + basicInfo.NonPagedPoolUsage.ToString(); + } + + private void HandlePropertiesWindow_Load(object sender, EventArgs e) + { + if (HandlePropertiesCallback != null) + { + try + { + HandlePropertiesCallback(groupObjectInfo, _name, _typeName); + } + catch + { } + + if (groupObjectInfo.Controls.Count == 0) + { + groupObjectInfo.Visible = false; + } + else if (groupObjectInfo.Controls.Count == 1) + { + Control control = groupObjectInfo.Controls[0]; + + // If it's a user control, dock it. + if (control is UserControl) + { + control.Dock = DockStyle.Fill; + control.Margin = new Padding(3); + } + else + { + control.Location = new System.Drawing.Point(10, 20); + } + } + } + + if (this.ObjectHandle == null) + buttonPermissions.Visible = false; + } + + public NativeHandle ObjectHandle + { + get { return _objectHandle; } + set { _objectHandle = value; } + } + + private void buttonClose_Click(object sender, EventArgs e) + { + this.Close(); + } + + private void buttonPermissions_Click(object sender, EventArgs e) + { + if (_objectHandle != null) + { + try + { + SecurityEditor.EditSecurity( + this, + SecurityEditor.GetSecurable(NativeTypeFactory.GetObjectType(_typeName), _objectHandle), + _name, + NativeTypeFactory.GetAccessEntries(NativeTypeFactory.GetObjectType(_typeName)) + ); + } + catch (Exception ex) + { + MessageBox.Show("Unable to edit security: " + ex.Message, "Security Editor", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/Ui/HandlePropertiesWindow.resx b/branches/ph-plugins/ProcessHacker.Native/Ui/HandlePropertiesWindow.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Ui/HandlePropertiesWindow.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker.Native/Windows.cs b/branches/ph-plugins/ProcessHacker.Native/Windows.cs new file mode 100644 index 000000000..167c3b7fb --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/Windows.cs @@ -0,0 +1,1030 @@ +/* + * Process Hacker - + * system-related functions + * + * Copyright (C) 2009 Flavio Erlich + * Copyright (C) 2009 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 . + */ + +// 'member' is obsolete: 'text' +#pragma warning disable 0618 + +using System; +using System.Collections.Generic; +using System.Net; +using System.Runtime.InteropServices; +using ProcessHacker.Common; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Native +{ + /// + /// Provides methods for manipulating the operating system. + /// + public static class Windows + { + public delegate bool EnumKernelModulesDelegate(KernelModule kernelModule); + + public delegate string GetProcessNameCallback(int pid); + + public static GetProcessNameCallback GetProcessName; + + /// + /// A cache for type names; QuerySystemInformation with ALL_TYPES_INFORMATION fails for some + /// reason. The dictionary relates object type numbers to their names. + /// + internal static Dictionary ObjectTypes = new Dictionary(); + + [ThreadStatic] + private static MemoryAlloc _handlesBuffer; + [ThreadStatic] + private static MemoryAlloc _kernelModulesBuffer; + [ThreadStatic] + private static MemoryAlloc _processesBuffer; + [ThreadStatic] + private static MemoryAlloc _servicesBuffer; + + private static int _numberOfProcessors = 0; + private static int _pageSize = 0; + private static IntPtr _kernelBase = IntPtr.Zero; + private static string _kernelFileName = null; + + /// + /// Gets the number of active processors. + /// + public static int NumberOfProcessors + { + get + { + if (_numberOfProcessors == 0) + _numberOfProcessors = GetBasicInformation().NumberOfProcessors; + + return _numberOfProcessors; + } + } + + /// + /// Gets the page size. + /// + public static int PageSize + { + get + { + if (_pageSize == 0) + _pageSize = GetBasicInformation().PageSize; + + return _pageSize; + } + } + + /// + /// Gets the base address of the kernel. + /// + public static IntPtr KernelBase + { + get + { + if (_kernelBase == IntPtr.Zero) + _kernelBase = GetKernelBase(); + + return _kernelBase; + } + } + + /// + /// Gets the file name of the kernel. + /// + public static string KernelFileName + { + get + { + if (_kernelFileName == null) + _kernelFileName = GetKernelFileName(); + + return _kernelFileName; + } + } + + /// + /// Gets the number of pages needed to store the + /// specified number of bytes. + /// + /// The number of bytes. + /// The number of pages needed. + public static int BytesToPages(int bytes) + { + return Utils.DivideUp(bytes, PageSize); + } + + /// + /// Enumerates the modules loaded by the kernel. + /// + /// A callback for the enumeration. + public static void EnumKernelModules(EnumKernelModulesDelegate enumCallback) + { + NtStatus status; + int retLength; + + if (_kernelModulesBuffer == null) + _kernelModulesBuffer = new MemoryAlloc(0x1000); + + status = Win32.NtQuerySystemInformation( + SystemInformationClass.SystemModuleInformation, + _kernelModulesBuffer, + _kernelModulesBuffer.Size, + out retLength + ); + + if (status == NtStatus.InfoLengthMismatch) + { + _kernelModulesBuffer.Resize(retLength); + + status = Win32.NtQuerySystemInformation( + SystemInformationClass.SystemModuleInformation, + _kernelModulesBuffer, + _kernelModulesBuffer.Size, + out retLength + ); + } + + if (status >= NtStatus.Error) + Win32.ThrowLastError(status); + + RtlProcessModules modules = _kernelModulesBuffer.ReadStruct(); + + for (int i = 0; i < modules.NumberOfModules; i++) + { + var module = _kernelModulesBuffer.ReadStruct(RtlProcessModules.ModulesOffset, i); + var moduleInfo = new Debugging.ModuleInformation(module); + + if (!enumCallback(new KernelModule( + moduleInfo.BaseAddress, + moduleInfo.Size, + moduleInfo.Flags, + moduleInfo.BaseName, + FileUtils.GetFileName(moduleInfo.FileName) + ))) + break; + } + } + + /// + /// Gets basic information about the system. + /// + /// A structure containing basic information. + public static SystemBasicInformation GetBasicInformation() + { + NtStatus status; + SystemBasicInformation sbi; + int retLength; + + if ((status = Win32.NtQuerySystemInformation( + SystemInformationClass.SystemBasicInformation, + out sbi, + Marshal.SizeOf(typeof(SystemBasicInformation)), + out retLength + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + return sbi; + } + + /// + /// Enumerates the handles opened by every running process. + /// + /// An array containing information about the handles. + public static SystemHandleEntry[] GetHandles() + { + int retLength = 0; + int handleCount = 0; + SystemHandleEntry[] returnHandles; + + if (_handlesBuffer == null) + _handlesBuffer = new MemoryAlloc(0x1000); + + MemoryAlloc data = _handlesBuffer; + + NtStatus status; + + // This is needed because NtQuerySystemInformation with SystemHandleInformation doesn't + // actually give a real return length when called with an insufficient buffer. This code + // tries repeatedly to call the function, doubling the buffer size each time it fails. + while ((status = Win32.NtQuerySystemInformation( + SystemInformationClass.SystemHandleInformation, + data, + data.Size, + out retLength) + ) == NtStatus.InfoLengthMismatch) + { + data.Resize(data.Size * 2); + + // Fail if we've resized it to over 16MB - protect from infinite resizing + if (data.Size > 16 * 1024 * 1024) + throw new OutOfMemoryException(); + } + + if (status >= NtStatus.Error) + Win32.ThrowLastError(status); + + // The structure of the buffer is the handle count plus an array of SYSTEM_HANDLE_INFORMATION + // structures. + handleCount = data.ReadStruct().NumberOfHandles; + returnHandles = new SystemHandleEntry[handleCount]; + + for (int i = 0; i < handleCount; i++) + { + returnHandles[i] = data.ReadStruct(SystemHandleInformation.HandlesOffset, i); + } + + return returnHandles; + } + + /// + /// Gets the base address of the currently running kernel. + /// + /// The kernel's base address. + private static IntPtr GetKernelBase() + { + IntPtr kernelBase = IntPtr.Zero; + + Windows.EnumKernelModules((module) => + { + kernelBase = module.BaseAddress; + return false; + }); + + return kernelBase; + } + + /// + /// Gets the file name of the currently running kernel. + /// + /// The kernel file name. + private static string GetKernelFileName() + { + string kernelFileName = null; + + EnumKernelModules((module) => + { + kernelFileName = module.FileName; + return false; + }); + + return kernelFileName; + } + + /// + /// Gets the modules loaded by the kernel. + /// + /// A collection of module information structures. + public static KernelModule[] GetKernelModules() + { + List kernelModules = new List(); + + EnumKernelModules((kernelModule) => + { + kernelModules.Add(kernelModule); + return true; + }); + + return kernelModules.ToArray(); + } + + public static SystemLogonSession GetLogonSession(Luid logonId) + { + NtStatus status; + IntPtr logonSessionData; + + if ((status = Win32.LsaGetLogonSessionData( + ref logonId, + out logonSessionData + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + using (var logonSessionDataAlloc = new LsaMemoryAlloc(logonSessionData, true)) + { + var info = logonSessionDataAlloc.ReadStruct(); + + return new SystemLogonSession( + info.AuthenticationPackage.Read(), + info.DnsDomainName.Read(), + info.LogonDomain.Read(), + info.LogonId, + info.LogonServer.Read(), + DateTime.FromFileTime(info.LogonTime), + info.LogonType, + info.Session, + new Sid(info.Sid), + info.Upn.Read(), + info.UserName.Read() + ); + } + } + + public static Luid[] GetLogonSessions() + { + NtStatus status; + int logonSessionCount; + IntPtr logonSessionList; + + if ((status = Win32.LsaEnumerateLogonSessions( + out logonSessionCount, + out logonSessionList + )) >= NtStatus.Error) + Win32.ThrowLastError(status); + + Luid[] logonSessions = new Luid[logonSessionCount]; + + using (var logonSessionListAlloc = new LsaMemoryAlloc(logonSessionList, true)) + { + for (int i = 0; i < logonSessionCount; i++) + logonSessions[i] = logonSessionListAlloc.ReadStruct(i); + + return logonSessions; + } + } + + /// + /// Gets the network connections currently active. + /// + /// A dictionary of network connections. + public static Dictionary> GetNetworkConnections() + { + var retDict = new Dictionary>(); + int length; + + // TCP IPv4 + + length = 0; + Win32.GetExtendedTcpTable(IntPtr.Zero, ref length, false, AiFamily.INet, TcpTableClass.OwnerPidAll, 0); + + using (var mem = new MemoryAlloc(length)) + { + if (Win32.GetExtendedTcpTable(mem, ref length, false, AiFamily.INet, TcpTableClass.OwnerPidAll, 0) != 0) + Win32.ThrowLastError(); + + int count = mem.ReadInt32(0); + + for (int i = 0; i < count; i++) + { + var struc = mem.ReadStruct(sizeof(int), i); + + if (!retDict.ContainsKey(struc.OwningProcessId)) + retDict.Add(struc.OwningProcessId, new List()); + + retDict[struc.OwningProcessId].Add(new NetworkConnection() + { + Protocol = NetworkProtocol.Tcp, + Local = new IPEndPoint(struc.LocalAddress, ((ushort)struc.LocalPort).Reverse()), + Remote = new IPEndPoint(struc.RemoteAddress, ((ushort)struc.RemotePort).Reverse()), + State = struc.State, + Pid = struc.OwningProcessId + }); + } + } + + // UDP IPv4 + + length = 0; + Win32.GetExtendedUdpTable(IntPtr.Zero, ref length, false, AiFamily.INet, UdpTableClass.OwnerPid, 0); + + using (var mem = new MemoryAlloc(length)) + { + if (Win32.GetExtendedUdpTable(mem, ref length, false, AiFamily.INet, UdpTableClass.OwnerPid, 0) != 0) + Win32.ThrowLastError(); + + int count = mem.ReadInt32(0); + + for (int i = 0; i < count; i++) + { + var struc = mem.ReadStruct(sizeof(int), i); + + if (!retDict.ContainsKey(struc.OwningProcessId)) + retDict.Add(struc.OwningProcessId, new List()); + + retDict[struc.OwningProcessId].Add( + new NetworkConnection() + { + Protocol = NetworkProtocol.Udp, + Local = new IPEndPoint(struc.LocalAddress, ((ushort)struc.LocalPort).Reverse()), + Pid = struc.OwningProcessId + }); + } + } + + // TCP IPv6 + + length = 0; + Win32.GetExtendedTcpTable(IntPtr.Zero, ref length, false, AiFamily.INet6, TcpTableClass.OwnerPidAll, 0); + + using (var mem = new MemoryAlloc(length)) + { + if (Win32.GetExtendedTcpTable(mem, ref length, false, AiFamily.INet6, TcpTableClass.OwnerPidAll, 0) == 0) + { + int count = mem.ReadInt32(0); + + for (int i = 0; i < count; i++) + { + var struc = mem.ReadStruct(sizeof(int), i); + + if (!retDict.ContainsKey(struc.OwningProcessId)) + retDict.Add(struc.OwningProcessId, new List()); + + retDict[struc.OwningProcessId].Add(new NetworkConnection() + { + Protocol = NetworkProtocol.Tcp6, + Local = new IPEndPoint(new IPAddress(struc.LocalAddress, struc.LocalScopeId), ((ushort)struc.LocalPort).Reverse()), + Remote = new IPEndPoint(new IPAddress(struc.RemoteAddress, struc.RemoteScopeId), ((ushort)struc.RemotePort).Reverse()), + State = struc.State, + Pid = struc.OwningProcessId + }); + } + } + } + + // UDP IPv6 + + length = 0; + Win32.GetExtendedUdpTable(IntPtr.Zero, ref length, false, AiFamily.INet6, UdpTableClass.OwnerPid, 0); + + using (var mem = new MemoryAlloc(length)) + { + if (Win32.GetExtendedUdpTable(mem, ref length, false, AiFamily.INet6, UdpTableClass.OwnerPid, 0) == 0) + { + int count = mem.ReadInt32(0); + + for (int i = 0; i < count; i++) + { + var struc = mem.ReadStruct(sizeof(int), i); + + if (!retDict.ContainsKey(struc.OwningProcessId)) + retDict.Add(struc.OwningProcessId, new List()); + + retDict[struc.OwningProcessId].Add( + new NetworkConnection() + { + Protocol = NetworkProtocol.Udp6, + Local = new IPEndPoint(new IPAddress(struc.LocalAddress, struc.LocalScopeId), ((ushort)struc.LocalPort).Reverse()), + Pid = struc.OwningProcessId + }); + } + } + } + + return retDict; + } + + /// + /// Gets the page files currently active. + /// + /// A collection of page file information structures. + public static SystemPagefile[] GetPagefiles() + { + int retLength; + List pagefiles = new List(); + + using (MemoryAlloc data = new MemoryAlloc(0x200)) + { + NtStatus status; + + while ((status = Win32.NtQuerySystemInformation( + SystemInformationClass.SystemPageFileInformation, + data, + data.Size, + out retLength) + ) == NtStatus.InfoLengthMismatch) + { + data.Resize(data.Size * 2); + + // Fail if we've resized it to over 16MB - protect from infinite resizing + if (data.Size > 16 * 1024 * 1024) + throw new OutOfMemoryException(); + } + + if (status >= NtStatus.Error) + Win32.ThrowLastError(status); + + pagefiles = new List(2); + + int i = 0; + SystemPagefileInformation currentPagefile; + + do + { + currentPagefile = data.ReadStruct(i, 0); + + pagefiles.Add(new SystemPagefile( + currentPagefile.TotalSize, + currentPagefile.TotalInUse, + currentPagefile.PeakUsage, + FileUtils.GetFileName(currentPagefile.PageFileName.Read()) + )); + + i += currentPagefile.NextEntryOffset; + } while (currentPagefile.NextEntryOffset != 0); + + return pagefiles.ToArray(); + } + } + + /// + /// Gets a dictionary containing the currently running processes. + /// + /// A dictionary, indexed by process ID. + public static Dictionary GetProcesses() + { + return GetProcesses(false); + } + + /// + /// Gets a dictionary containing the currently running processes. + /// + /// Whether to get thread information. + /// A dictionary, indexed by process ID. + public static Dictionary GetProcesses(bool getThreads) + { + int retLength; + Dictionary returnProcesses; + + if (_processesBuffer == null) + _processesBuffer = new MemoryAlloc(0x10000); + + MemoryAlloc data = _processesBuffer; + + NtStatus status; + int attempts = 0; + + while (true) + { + attempts++; + + if ((status = Win32.NtQuerySystemInformation( + SystemInformationClass.SystemProcessInformation, + data, + data.Size, + out retLength + )) >= NtStatus.Error) + { + if (attempts > 3) + Win32.ThrowLastError(status); + + data.Resize(retLength); + } + else + { + break; + } + } + + returnProcesses = new Dictionary(32); // 32 processes on a computer? + + int i = 0; + SystemProcess currentProcess = new SystemProcess(); + + do + { + currentProcess.Process = data.ReadStruct(i, 0); + currentProcess.Name = currentProcess.Process.ImageName.Read(); + + if (getThreads && + currentProcess.Process.ProcessId != 0) + { + currentProcess.Threads = new Dictionary(); + + for (int j = 0; j < currentProcess.Process.NumberOfThreads; j++) + { + var thread = data.ReadStruct(i + + Marshal.SizeOf(typeof(SystemProcessInformation)), j); + + currentProcess.Threads.Add(thread.ClientId.ThreadId, thread); + } + } + + returnProcesses.Add(currentProcess.Process.ProcessId, currentProcess); + + i += currentProcess.Process.NextEntryOffset; + } while (currentProcess.Process.NextEntryOffset != 0); + + return returnProcesses; + } + + /// + /// Gets a dictionary containing the threads owned by the specified process. + /// + /// A process ID. + /// A dictionary, indexed by thread ID. + public static Dictionary GetProcessThreads(int pid) + { + int retLength; + + if (_processesBuffer == null) + _processesBuffer = new MemoryAlloc(0x10000); + + MemoryAlloc data = _processesBuffer; + + NtStatus status; + int attempts = 0; + + while (true) + { + attempts++; + + if ((status = Win32.NtQuerySystemInformation(SystemInformationClass.SystemProcessInformation, data.Memory, + data.Size, out retLength)) >= NtStatus.Error) + { + if (attempts > 3) + Win32.ThrowLastError(status); + + data.Resize(retLength); + } + else + { + break; + } + } + + int i = 0; + SystemProcessInformation process; + + do + { + process = data.ReadStruct(i, 0); + + if (process.ProcessId == pid) + { + var threads = new Dictionary(); + + for (int j = 0; j < process.NumberOfThreads; j++) + { + var thread = data.ReadStruct(i + + Marshal.SizeOf(typeof(SystemProcessInformation)), j); + + threads.Add(thread.ClientId.ThreadId, thread); + } + + return threads; + } + + i += process.NextEntryOffset; + + } while (process.NextEntryOffset != 0); + + return null; + } + + /// + /// Gets a dictionary containing the services on the system. + /// + /// A dictionary, indexed by service name. + public static Dictionary GetServices() + { + using (ServiceManagerHandle manager = + new ServiceManagerHandle(ScManagerAccess.EnumerateService)) + { + int requiredSize; + int servicesReturned; + int resume = 0; + + if (_servicesBuffer == null) + _servicesBuffer = new MemoryAlloc(0x10000); + + MemoryAlloc data = _servicesBuffer; + + if (!Win32.EnumServicesStatusEx(manager, IntPtr.Zero, ServiceQueryType.Win32 | ServiceQueryType.Driver, + ServiceQueryState.All, data, + data.Size, out requiredSize, out servicesReturned, + ref resume, null)) + { + // resize buffer + data.Resize(requiredSize); + + if (!Win32.EnumServicesStatusEx(manager, IntPtr.Zero, ServiceQueryType.Win32 | ServiceQueryType.Driver, + ServiceQueryState.All, data, + data.Size, out requiredSize, out servicesReturned, + ref resume, null)) + Win32.ThrowLastError(); + } + + var dictionary = new Dictionary(servicesReturned); + + for (int i = 0; i < servicesReturned; i++) + { + var service = data.ReadStruct(i); + + dictionary.Add(service.ServiceName, service); + } + + return dictionary; + } + } + + /// + /// Gets the 64-bit tick count. + /// + /// A 64-bit tick count. + public static long GetTickCount() + { + // Read the tick count multiplier. + int tickCountMultiplier = Marshal.ReadInt32(Win32.UserSharedData.Increment( + KUserSharedData.TickCountMultiplierOffset)); + + // Read the tick count. + var tickCount = QueryKSystemTime(Win32.UserSharedData.Increment( + KUserSharedData.TickCountOffset)); + + return (((long)tickCount.LowPart * tickCountMultiplier) >> (int)24) + + (((long)tickCount.HighPart * tickCountMultiplier) << (int)8); + } + + /// + /// Gets information about the system time. + /// + /// A time of day structure. + public static SystemTimeOfDayInformation GetTimeOfDay() + { + NtStatus status; + SystemTimeOfDayInformation timeOfDay; + int retLength; + + status = Win32.NtQuerySystemInformation( + SystemInformationClass.SystemTimeOfDayInformation, + out timeOfDay, + Marshal.SizeOf(typeof(SystemTimeOfDayInformation)), + out retLength + ); + + if (status >= NtStatus.Error) + Win32.ThrowLastError(status); + + return timeOfDay; + } + + /// + /// Gets the uptime of the system. + /// + /// A time span describing the time elapsed since the system was booted. + public static TimeSpan GetUptime() + { + var timeOfDay = GetTimeOfDay(); + + return new TimeSpan(timeOfDay.CurrentTime - timeOfDay.BootTime); + } + + /// + /// Loads a driver. + /// + /// The service name of the driver. + public static void LoadDriver(string serviceName) + { + var str = new UnicodeString( + "\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\" + serviceName); + + try + { + NtStatus status; + + if ((status = Win32.NtLoadDriver(ref str)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + str.Dispose(); + } + } + + /// + /// Reads a KSYSTEM_TIME value atomically. + /// + /// A pointer to a KSYSTEM_TIME value. + /// A 64-bit time value. + private static LargeInteger QueryKSystemTime(IntPtr time) + { + unsafe + { + return QueryKSystemTime((KSystemTime*)time); + } + } + + /// + /// Reads a KSYSTEM_TIME value atomically. + /// + /// A pointer to a KSYSTEM_TIME value. + /// A 64-bit time value. + private unsafe static LargeInteger QueryKSystemTime(KSystemTime* time) + { + LargeInteger localTime = new LargeInteger(); + + // If we're on 32-bit, we need to use a special + // method to read the time atomically. On 64-bit, + // we can simply read the time. + + if (IntPtr.Size == 4) + { + localTime.QuadPart = 0; + + while (true) + { + localTime.HighPart = time->High1Time; + localTime.LowPart = time->LowPart; + + // Check if someone started changing the time + // while we were reading the two values. + if (localTime.HighPart == time->High2Time) + break; + + System.Threading.Thread.SpinWait(1); + } + } + else + { + localTime.QuadPart = time->QuadPart; + } + + return localTime; + } + + /// + /// Unloads a driver. + /// + /// The service name of the driver. + public static void UnloadDriver(string serviceName) + { + var str = new UnicodeString( + "\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Services\\" + serviceName); + + try + { + NtStatus status; + + if ((status = Win32.NtUnloadDriver(ref str)) >= NtStatus.Error) + Win32.ThrowLastError(status); + } + finally + { + str.Dispose(); + } + } + } + + public enum NetworkProtocol + { + Tcp, + Udp, + Tcp6, + Udp6 + } + + public struct ObjectInformation + { + public string OrigName; + public string BestName; + public string TypeName; + } + + public struct NetworkConnection + { + public int Pid; + public NetworkProtocol Protocol; + public IPEndPoint Local; + public IPEndPoint Remote; + public MibTcpState State; + public object Tag; + + public void CloseTcpConnection() + { + MibTcpRow row = new MibTcpRow() + { + State = MibTcpState.DeleteTcb, + LocalAddress = (uint)this.Local.Address.Address, + LocalPort = ((ushort)this.Local.Port).Reverse(), + RemoteAddress = this.Remote != null ? (uint)this.Remote.Address.Address : 0, + RemotePort = this.Remote != null ? ((ushort)this.Remote.Port).Reverse() : 0 + }; + int result = Win32.SetTcpEntry(ref row); + + if (result != 0) + Win32.ThrowLastError(result); + } + } + + public struct SystemProcess + { + public string Name; + public SystemProcessInformation Process; + public Dictionary Threads; + } + + public class KernelModule : ILoadedModule + { + public KernelModule( + IntPtr baseAddress, + int size, + LdrpDataTableEntryFlags flags, + string baseName, + string fileName + ) + { + this.BaseAddress = baseAddress; + this.Size = size; + this.Flags = flags; + this.BaseName = baseName; + this.FileName = fileName; + } + + /// + /// The base address of the module. + /// + public IntPtr BaseAddress { get; private set; } + /// + /// The size of the module. + /// + public int Size { get; private set; } + /// + /// The flags set by the loader for this module. + /// + public LdrpDataTableEntryFlags Flags { get; private set; } + /// + /// The base name of the module (e.g. module.dll). + /// + public string BaseName { get; private set; } + /// + /// The file name of the module (e.g. C:\Windows\system32\module.dll). + /// + public string FileName { get; private set; } + } + + public class SystemLogonSession + { + public SystemLogonSession( + string authenticationPackage, + string dnsDomainName, + string logonDomain, + Luid logonId, + string logonServer, + DateTime logonTime, + LogonType logonType, + int session, + Sid sid, + string upn, + string userName + ) + { + this.AuthenticationPackage = authenticationPackage; + this.DnsDomainName = dnsDomainName; + this.LogonDomain = logonDomain; + this.LogonId = logonId; + this.LogonServer = logonServer; + this.LogonTime = logonTime; + this.LogonType = logonType; + this.Session = session; + this.Sid = sid; + this.Upn = upn; + this.UserName = userName; + } + + public string AuthenticationPackage { get; private set; } + public string DnsDomainName { get; private set; } + public string LogonDomain { get; private set; } + public Luid LogonId { get; private set; } + public string LogonServer { get; private set; } + public DateTime LogonTime { get; private set; } + public LogonType LogonType { get; private set; } + public int Session { get; private set; } + public Sid Sid { get; private set; } + public string Upn { get; private set; } + public string UserName { get; private set; } + } + + public class SystemPagefile + { + public SystemPagefile(int totalSize, int totalInUse, int peakUsage, string fileName) + { + this.TotalSize = totalSize; + this.TotalInUse = TotalInUse; + this.PeakUsage = peakUsage; + this.FileName = fileName; + } + + public int TotalSize { get; private set; } + public int TotalInUse { get; private set; } + public int PeakUsage { get; private set; } + public string FileName { get; private set; } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/WindowsException.cs b/branches/ph-plugins/ProcessHacker.Native/WindowsException.cs new file mode 100644 index 000000000..74dd7cfcd --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/WindowsException.cs @@ -0,0 +1,131 @@ +/* + * Process Hacker - + * windows exception + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Native +{ + /// + /// Represents a Win32 or Native exception. + /// + /// + /// Unlike the System.ComponentModel.Win32Exception class, + /// this class does not get the error's associated + /// message unless it is requested. + /// + public class WindowsException : Exception + { + private bool _isNtStatus = false; + private Win32Error _errorCode = 0; + private NtStatus _status; + private string _message = null; + + /// + /// Creates an exception with no error. + /// + public WindowsException() + { } + + /// + /// Creates an exception from a Win32 error code. + /// + /// The Win32 error code. + public WindowsException(Win32Error errorCode) + { + _errorCode = errorCode; + } + + /// + /// Creates an exception from a NT status value. + /// + /// The NT status value. + public WindowsException(NtStatus status) + { + _status = status; + _errorCode = status.ToDosError(); + _isNtStatus = true; + } + + /// + /// Gets whether the NT status value is valid. + /// + public bool IsNtStatus + { + get { return _isNtStatus; } + } + + /// + /// Gets a Win32 error code which represents the exception. + /// + public Win32Error ErrorCode + { + get { return _errorCode; } + } + + /// + /// Gets a NT status value which represents the exception. + /// + public NtStatus Status + { + get { return _status; } + } + + /// + /// Gets a message describing the exception. + /// + public override string Message + { + get + { + // No locking, for performance reasons. Getting the + // message doesn't have any side-effects anyway. + if (_message == null) + { + // We prefer native status messages because they are usually + // more detailed. However, for some status values we do + // prefer the shorter Win32 error message. + + if ( + _isNtStatus && + _status != NtStatus.AccessDenied && + _status != NtStatus.AccessViolation + ) + { + string message = _status.GetMessage(); + + if (message == null) + message = "Could not retrieve the error message (0x" + ((int)_status).ToString("x") + ")."; + + _message = message; + } + else + { + _message = _errorCode.GetMessage(); + } + } + + return _message; + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker.Native/app.config b/branches/ph-plugins/ProcessHacker.Native/app.config new file mode 100644 index 000000000..b7db28170 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.Native/app.config @@ -0,0 +1,3 @@ + + + diff --git a/branches/ph-plugins/ProcessHacker.sln b/branches/ph-plugins/ProcessHacker.sln new file mode 100644 index 000000000..c93bbacd6 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker.sln @@ -0,0 +1,47 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProcessHacker", "ProcessHacker\ProcessHacker.csproj", "{EEEA1778-1702-4964-8793-A98FE37E4D2B}" + ProjectSection(ProjectDependencies) = postProject + {0710ADEF-F89E-4CBC-8150-B340460BC9D6} = {0710ADEF-F89E-4CBC-8150-B340460BC9D6} + EndProjectSection +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Assistant", "Assistant\Assistant.csproj", "{0710ADEF-F89E-4CBC-8150-B340460BC9D6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProcessHacker.Common", "ProcessHacker.Common\ProcessHacker.Common.csproj", "{8E10F5E8-D4FA-4980-BB23-2EDD134AC15E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProcessHacker.Native", "ProcessHacker.Native\ProcessHacker.Native.csproj", "{8A448157-E1A7-4DDF-954E-287F1117832B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aga.Controls", "TreeViewAdv\Aga.Controls.csproj", "{E73BB233-D88B-44A7-A98F-D71EE158381D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EEEA1778-1702-4964-8793-A98FE37E4D2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EEEA1778-1702-4964-8793-A98FE37E4D2B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EEEA1778-1702-4964-8793-A98FE37E4D2B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EEEA1778-1702-4964-8793-A98FE37E4D2B}.Release|Any CPU.Build.0 = Release|Any CPU + {0710ADEF-F89E-4CBC-8150-B340460BC9D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0710ADEF-F89E-4CBC-8150-B340460BC9D6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0710ADEF-F89E-4CBC-8150-B340460BC9D6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0710ADEF-F89E-4CBC-8150-B340460BC9D6}.Release|Any CPU.Build.0 = Release|Any CPU + {8E10F5E8-D4FA-4980-BB23-2EDD134AC15E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8E10F5E8-D4FA-4980-BB23-2EDD134AC15E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8E10F5E8-D4FA-4980-BB23-2EDD134AC15E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8E10F5E8-D4FA-4980-BB23-2EDD134AC15E}.Release|Any CPU.Build.0 = Release|Any CPU + {8A448157-E1A7-4DDF-954E-287F1117832B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8A448157-E1A7-4DDF-954E-287F1117832B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8A448157-E1A7-4DDF-954E-287F1117832B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8A448157-E1A7-4DDF-954E-287F1117832B}.Release|Any CPU.Build.0 = Release|Any CPU + {E73BB233-D88B-44A7-A98F-D71EE158381D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E73BB233-D88B-44A7-A98F-D71EE158381D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E73BB233-D88B-44A7-A98F-D71EE158381D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E73BB233-D88B-44A7-A98F-D71EE158381D}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/branches/ph-plugins/ProcessHacker/Build/7za/7za.exe b/branches/ph-plugins/ProcessHacker/Build/7za/7za.exe new file mode 100644 index 000000000..12b9499a2 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Build/7za/7za.exe differ diff --git a/branches/ph-plugins/ProcessHacker/Build/7za/copying.txt b/branches/ph-plugins/ProcessHacker/Build/7za/copying.txt new file mode 100644 index 000000000..f3926a615 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Build/7za/copying.txt @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +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 +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser 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 Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/branches/ph-plugins/ProcessHacker/Build/7za/license.txt b/branches/ph-plugins/ProcessHacker/Build/7za/license.txt new file mode 100644 index 000000000..7b66cf7ab --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Build/7za/license.txt @@ -0,0 +1,30 @@ + 7-Zip Command line version + ~~~~~~~~~~~~~~~~~~~~~~~~~~ + License for use and distribution + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + 7-Zip Copyright (C) 1999-2009 Igor Pavlov. + + 7za.exe is distributed under the GNU LGPL license + + Notes: + You can use 7-Zip on any computer, including a computer in a commercial + organization. You don't need to register or pay for 7-Zip. + + + GNU LGPL information + -------------------- + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA diff --git a/branches/ph-plugins/ProcessHacker/Build/Installer/Custom_Messages.iss b/branches/ph-plugins/ProcessHacker/Build/Installer/Custom_Messages.iss new file mode 100644 index 000000000..a56d9596d --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Build/Installer/Custom_Messages.iss @@ -0,0 +1,81 @@ +;* Process Hacker - Installer custom messages +;* +;* Copyright (C) 2009 XhmikosR +;* +;* 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 . + + +[CustomMessages] +;sm=Start Menu, tsk=Task, com=Comment, msg=Message +;English +en.msg_SetupIsRunningWarning=Process Hacker Setup is already running! +en.msg_asknetdown=Process Hacker requires the .NET Framework 2.0. Please download and install the .NET Framework and run setup again. %n%nDo you want to download the .NET Framework 2.0 now? +en.msg_DeleteLogSettings=Do you also want to delete Process Hacker's logs and settings? %nIf you plan on reinstalling Process Hacker you do not have to delete them. +en.msg_createkprocesshacker=Creating KProcessHacker service... +en.msg_stopkprocesshacker=Stopping KProcessHacker service... +en.msg_startkprocesshacker=Starting KProcessHacker service... +en.msg_optimizingperformance=Optimizing performance... +en.msg_servicemanager=The service manager is not available +en.msg_servicemanager2=Only NT based systems support services +en.tsk_allusers=For all users +en.tsk_createKPHservice=Install KProcessHacker as a service +en.tsk_currentuser=For the current user only +en.tsk_deleteKPHservice=Delete KProcessHacker service +en.tsk_other=Other tasks: +en.tsk_removestartup=Remove Process Hacker from Windows startup +en.tsk_resetsettings=Reset Process Hacker's settings +en.tsk_restoretaskmgr=Restore Windows task manager +en.tsk_setdefaulttaskmgr=Set Process Hacker as the default task manager for Windows +en.tsk_startupdescr=Start Process Hacker on system startup +en.tsk_startupdescrmin=Minimized on system tray +en.tsk_startup=Startup options: +en.run_visitwebsite=Visit Process Hacker's Website +en.sm_changelog=Changelog +en.sm_com_changelog=Process Hacker's Changelog +en.sm_help=Help and Support +en.sm_helpfile=Process Hacker's Help +en.sm_readmefile=ReadMe +en.sm_com_readmefile=Process Hacker's ReadMe + +;Greek +gr.msg_SetupIsRunningWarning=Ç åãêáôÜóôáóç ôïõ Process Hacker ôñÝ÷åé Þäç! +gr.msg_asknetdown=Ôï Process Hacker ÷ñåéÜæåôáé ôï .NET Framework 2.0. Ðáñáêáëþ êáôåâÜóôå êáé åãêáôáóôÞóåôå ôï .NET Framework êáé ôñÝîôå ôçí åãêáôÜóôáóç ðÜëé. %n%nÈÝëåôå íá êáôåâÜóåôå ôï .NET Framework 2.0 ôþñá; +gr.msg_DeleteLogSettings=ÈÝëåôå íá äéáãñÜøåôå ôéò åðéëïãÝò êáé ôá áñ÷åßá êáôáãñáöÞò ôïõ Process Hacker; %nÁí óêïðåýåôå íá åãêáôáóôÞóåôå ðÜëé ôï Process Hacker äåí ÷ñåéÜæåôáé íá ôá äéáãñÜøåôå. +gr.msg_createkprocesshacker=Äçìéïõñãßá ôçò õðçñåóßáò KProcessHacker... +gr.msg_stopkprocesshacker=ÓôáìÜôçìá ôçò õðçñåóßáò KProcessHacker... +gr.msg_startkprocesshacker=Åêêßíçóç ôçò õðçñåóßáò KProcessHacker... +gr.msg_optimizingperformance=Âåëôßùóç åðéäüóåùí ôïõ Process Hacker... +gr.msg_servicemanager=The service manager is not available +gr.msg_servicemanager2=Only NT based systems support services +gr.tsk_allusers=Ãéá üëïõò ôïõò ÷ñÞóôåò +gr.tsk_createKPHservice=ÅãêáôÜóôáóç ôïõ KProcessHacker ùò õðçñåóßá +gr.tsk_currentuser=Ãéá ôïí ôñÝ÷ùí ÷ñÞóôç ìüíï +gr.tsk_deleteKPHservice=ÄéáãñáöÞ õðçñåóßáò ôïõ KProcessHacker +gr.tsk_other=¸îôñá: +gr.tsk_removestartup=Áöáßñåóç ôïõ Process Hacker áðü ôçí åêêßíçóç ôùí Windows +gr.tsk_resetsettings=ÅðáíáöïñÜ ôùí áñ÷éêþí ñõèìßóåùí ôïõ Process Hacker +gr.tsk_restoretaskmgr=ÅðáíáöïñÜ ôïõ Windows Task Manager +gr.tsk_setdefaulttaskmgr=Ïñéóìüò ôïõ Process Hacker ùò ôïí ðñïêáèïñéóìÝíï task manager %nôùí Windows +gr.tsk_startupdescr=¸íáñîç ìå ôçí åêêßíçóç ôùí Windows +gr.tsk_startupdescrmin=Åëá÷éóôïðïéçìÝíï óôï tray ôïõ óõóôÞìáôïò +gr.tsk_startup=ÅðéëïãÝò åêêßíçóçò: +gr.run_visitwebsite=Åðéóêåöôåßôå ôçí éóôïóåëßäá ôïõ Process Hacker +gr.sm_changelog=Éóôïñéêü Åêäüóåùí +gr.sm_com_changelog=Éóôïñéêü Åêäüóåùí ôïõ Process Hacker +gr.sm_help=ÂïÞèåéá êáé ÕðïóôÞñéîç +gr.sm_helpfile=Áñ÷åßï âïÞèåéáò ôïõ Process Hacker +gr.sm_readmefile=Áñ÷åßï ReadMe +gr.sm_com_readmefile=Áñ÷åßï ReadMe ôïõ Process Hacker diff --git a/branches/ph-plugins/ProcessHacker/Build/Installer/Icons/ProcessHacker.ico b/branches/ph-plugins/ProcessHacker/Build/Installer/Icons/ProcessHacker.ico new file mode 100644 index 000000000..583aad022 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Build/Installer/Icons/ProcessHacker.ico differ diff --git a/branches/ph-plugins/ProcessHacker/Build/Installer/Icons/ProcessHackerLarge.bmp b/branches/ph-plugins/ProcessHacker/Build/Installer/Icons/ProcessHackerLarge.bmp new file mode 100644 index 000000000..77fd73315 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Build/Installer/Icons/ProcessHackerLarge.bmp differ diff --git a/branches/ph-plugins/ProcessHacker/Build/Installer/Icons/ProcessHackerSmall.bmp b/branches/ph-plugins/ProcessHacker/Build/Installer/Icons/ProcessHackerSmall.bmp new file mode 100644 index 000000000..6b5018caf Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Build/Installer/Icons/ProcessHackerSmall.bmp differ diff --git a/branches/ph-plugins/ProcessHacker/Build/Installer/Icons/uninstall.ico b/branches/ph-plugins/ProcessHacker/Build/Installer/Icons/uninstall.ico new file mode 100644 index 000000000..a4debc837 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Build/Installer/Icons/uninstall.ico differ diff --git a/branches/ph-plugins/ProcessHacker/Build/Installer/Languages/Greek.isl b/branches/ph-plugins/ProcessHacker/Build/Installer/Languages/Greek.isl new file mode 100644 index 000000000..497a56acb --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Build/Installer/Languages/Greek.isl @@ -0,0 +1,366 @@ +; *** Inno Setup version 5.1.11+ Greek messages *** +; +; Note: When translating this text, do not add periods (.) to the end of +; messages that didn't have them already, because on those messages Inno +; Setup adds the periods automatically (appending a period would result in +; two periods being displayed). +; +; Translated by Anastasis Chatzioglou +; http://anasto.go.to +; baldycom@hotmail.com +; + +[LangOptions] +LanguageName=Greek +LanguageID=$408 +; If the language you are translating to requires special font faces or +; sizes, uncomment any of the following entries and change them accordingly. +;DialogFontName=MS Shell Dlg +;DialogFontSize=8 +;DialogFontStandardHeight=13 +;TitleFontName=Arial +;TitleFontSize=29 +;WelcomeFontName=Verdana +;WelcomeFontSize=12 +;CopyrightFontName=Arial +;CopyrightFontSize=8 +DialogFontName=MS Shell Dlg +DialogFontSize=8 +;4.1.4+ +;DialogFontStandardHeight=13 +TitleFontName=Arial +TitleFontSize=29 +WelcomeFontName=Arial +WelcomeFontSize=12 +CopyrightFontName=Arial +CopyrightFontSize=8 + +[Messages] +; *** Application titles +SetupAppTitle=ÅãêáôÜóôáóç +SetupWindowTitle=ÅãêáôÜóôáóç - %1 +UninstallAppTitle=ÁðåãêáôÜóôáóç +UninstallAppFullTitle=%1 ÁðåãêáôÜóôáóç +; 2.0.x +;DefaultUninstallIconName=ÁðåãêáôÜóôáóç %1 + +; *** Misc. common +InformationTitle=Ðëçñïöïñßåò +ConfirmTitle=Åðéâåâáßùóç +ErrorTitle=ÓöÜëìá + +; *** SetupLdr messages +SetupLdrStartupMessage=Èá åêôåëåóôåß ç åãêáôÜóôáóç ôïõ %1. ÈÝëåôå íá óõíå÷ßóåôå; +LdrCannotCreateTemp=ÓöÜëìá óôç äçìéïõñãßá ðñïóùñéíïý áñ÷åßïõ. Ç åãêáôÜóôáóç èá ôåñìáôéóôåß ôþñá. +LdrCannotExecTemp=ÓöÜëìá óôçí åêôÝëåóç áñ÷åßïõ óôïí ðñïóùñéíü êáôÜëïãï. Ç åãêáôÜóôáóç ôåñìáôßæåôáé. + +; *** Startup error messages +LastErrorMessage=%1.%n%nÓöÜëìá %2: %3 +SetupFileMissing=Äåí âñßóêåôáé ôï áñ÷åßï %1 óôïí êáôÜëïãï åãêáôÜóôáóçò. ºóùò ÷ñåéÜæåôáé íá ðñïìçèåõôåßôå Ýíá íÝï áíôßãñáöï ôïõ ðñïãñÜììáôïò. +SetupFileCorrupt=Ôï áñ÷åßï åãêáôÜóôáóçò åßíáé êáôåóôñáììÝíï. ºóùò ÷ñåéÜæåôáé íá ðñïìçèåõôåßôå Ýíá íÝï áíôßãñáöï ôïõ ðñïãñÜììáôïò. +SetupFileCorruptOrWrongVer=Ôï áñ÷åßï åãêáôÜóôáóçò åßíáé êáôåóôñáììÝíï ç åßíáé óå ëÜèïò Ýêäïóç. ºóùò ÷ñåéÜæåôáé íá ðñïìçèåõôåßôå Ýíá íÝï áíôßãñáöï ôïõ ðñïãñÜììáôïò. +NotOnThisPlatform=Áõôü ôï ðñüãñáììá äåí ìðïñåß íá åêôåëåóôåß óå %1. +OnlyOnThisPlatform=Áõôü ôï ðñüãñáììá åêôåëåßôáé ìüíï óå %1. +; 5.1.0+ +OnlyOnTheseArchitectures=Áõôü ôï ðñüãñáììá ìðïñåß íá åãêáôáóôáèåß ìïíü óå Windows ó÷åäéáóìÝíá ãéá åðåîåñãáóôÝò ìå áñ÷éôåêôïíéêÞ:%n%n%1 +MissingWOW64APIs=Ç Ýêäïóç ôùí Windows ðïõ åêôåëåßôáé äåí äéáèÝôåé ëåéôïõñãéêüôçôá 64-bit. Ãéá íá äéïñèùèåß ôï ðñüâëçìá åãêáôÝóôçóå ôï Service Pack %1. +WinVersionTooLowError=Áõôü ôï ðñüãñáììá áðáéôåß %1 Ýêäïóç ç íåüôåñç. +WinVersionTooHighError=Áõôü ôï ðñüãñáììá äåí ìðïñåß íá åêôåëåóôåß óå %1 Ýêäïóç ç íåüôåñç. +AdminPrivilegesRequired=ÐñÝðåé íá åßóôå ï Äéá÷åéñéóôÞò óõóôÞìáôïò ãéá íá åãêáôáóôÞóåôå áõôü ôï ðñüãñáììá. +PowerUserPrivilegesRequired=ÐñÝðåé íá åßóôå ï Äéá÷åéñéóôÞò óõóôÞìáôïò Þ Power User ãéá íá åãêáôáóôÞóåôå áõôü ôï ðñüãñáììá. +SetupAppRunningError=Ç åãêáôÜóôáóç åíôüðéóå üôé åêôåëåßôáé ç åöáñìïãÞ %1. Ðáñáêáëþ êëåßóôå ôçí åöáñìïãÞ ôþñá êáé ðáôÞóôå ÅíôÜîåé ãéá íá óõíå÷ßóåôå. +UninstallAppRunningError=Ç áðåãêáôÜóôáóç åíôüðéóå üôé åêôåëåßôáé ç åöáñìïãÞ %1. Ðáñáêáëþ êëåßóôå ôçí åöáñìïãÞ ôþñá êáé ðáôÞóôå ÅíôÜîåé ãéá íá óõíå÷ßóåôå. + +; *** Misc. errors +ErrorCreatingDir=Ç åãêáôÜóôáóç äåí ìðïñåß íá äçìéïõñãÞóåé ôïí êáôÜëïãï %1. +ErrorTooManyFilesInDir=Äåí ìðïñåß íá äçìéïõñãçèåß Ýíá áñ÷åßï óôïí êáôÜëïãï "%1" åðåéäÞ Þäç ðåñéÝ÷åé ðïëëÜ áñ÷åßá. + +; *** Setup common messages +ExitSetupTitle=ÔÝëïò ÅãêáôÜóôáóçò. +ExitSetupMessage=Ç åãêáôÜóôáóç äåí Ý÷åé ôåëåéþóåé. Áí ôç óôáìáôÞóåôå ôþñá ôï ðñüãñáììá ðïõ ðñïóðáèÞóáôå íá åãêáôáóôÞóåôå äåí èá ëåéôïõñãåß.%n%nÌðïñåßôå íá åêôåëÝóåôå îáíÜ ôçí åãêáôÜóôáóç áñãüôåñá. +AboutSetupMenuItem=&Ó÷åôéêÜ ìå ôçí ÅãêáôÜóôáóç... +AboutSetupTitle=Ó÷åôéêÜ ìå ôçí ÅãêáôÜóôáóç. +AboutSetupMessage=%1 Ýêäïóç %2%n%3%n%n%1 ðñïóùðéêÞ óåëßäá%n%4 +AboutSetupNote=Anasto +; 5.1.0+ +TranslatorNote=Anastasis Chatzioglou - baldycom@hotmail.com + +; *** Buttons +ButtonBack=< &Ðßóù +ButtonNext=&Åðüìåíï > +ButtonInstall=&ÅãêáôÜóôáóç +ButtonOK=Å&íôÜîåé +ButtonCancel=&Áêõñï +ButtonYes=Í&áé +ButtonYesToAll=Íáé óå &Ïëá +ButtonNo=Ï&÷é +ButtonNoToAll=Ï÷é &óå ïëá +ButtonFinish=&ÔÝëïò +ButtonBrowse=&ÁíáæÞôçóç... +;4.1.3 +ButtonWizardBrowse=&Åýñåóç... +ButtonNewFolder=&Äçìéïõñãßá íÝïõ öáêÝëïõ + +; *** "Select Language" dialog messages +; 4.0.x +SelectLanguageTitle=ÅðéëïãÞ ôçò ãëþóóáò åãêáôÜóôáóçò +SelectLanguageLabel=ÅðéëïãÞ ôçò ãëþóóáò ãéá ÷ñÞóç êáôÜ ôçí äéÜñêåéá ôçò åãêáôÜóôáóçò: + + +; *** Common wizard text +ClickNext=ÐáôÞóôå Åðüìåíï ãéá íá óõíå÷ßóåôå Þ ¢êõñï ãéá íá ôåñìáôßóåôå ôçí åãêáôÜóôáóç. +; 2.0.x +;ClickNextModern=ÐáôÞóôå Åðüìåíï ãéá íá óõíå÷ßóåôå Þ ¢êõñï ãéá íá ôåñìáôßóåôå ôçí åãêáôÜóôáóç. +;;; - anasto - +;4.1.3 +BrowseDialogTitle=Åýñåóç öáêÝëïõ +BrowseDialogLabel=ÅðéëÝîôå öÜêåëï óôçí ëßóôá êáé ìåôÜ ðáôÞóôå OK. +NewFolderName=ÍÝïò öÜêåëïò + +; *** "Welcome" wizard page +WelcomeLabel1=Êáëùóïñßóáôå óôçí åãêáôÜóôáóç ôïõ [name]. +WelcomeLabel2=Èá ãßíåé åãêáôÜóôáóç ôïõ [name/ver] óôïí õðïëïãéóôÞ óáò.%n%nÐñéí óõíå÷ßóåôå óáò óõíéóôïýìå íá êëåßóåôå êÜèå Üëëç åöáñìïãÞ ðïõ ðéèáíüí åêôåëåßôå. + +; *** "Password" wizard page +WizardPassword=ÅéóáãùãÞ Êùäéêïý +PasswordLabel1=ÁõôÞ ç åãêáôÜóôáóç ÷ñåéÜæåôáé êùäéêü ãéá íá åêôåëåóôåß. +PasswordLabel3=Ðáñáêáëþ äþóôå ôïí êùäéêü óáò êáé ðáôÞóôå Åðüìåíï ãéá íá óõíå÷ßóåôå. +PasswordEditLabel=&Êùäéêüò: +IncorrectPassword=Ï êùäéêüò ðïõ äþóáôå åßíáé ëÜèïò. ÎáíáðñïóðáèÞóôå. + +; *** "License Agreement" wizard page +WizardLicense=Áäåéá ×ñÞóçò +LicenseLabel=Ðáñáêáëþ äéáâÜóôå ðñïóåêôéêÜ ôéò ðáñáêÜôù ðëçñïöïñßåò ðñéí óõíå÷ßóåôå. +; 2.0.x +;LicenseLabel1=Ðáñáêáëþ äéáâÜóôå ðñïóåêôéêÜ ôéò ðáñáêÜôù ðëçñïöïñßåò ðñéí óõíå÷ßóåôå. ×ñçóéìïðïéÞóôå ôçí ìðÜñá êýëéóçò ãéá íá äåßôå üëï ôï êåßìåíï. +;LicenseLabel2=ÁðïäÝ÷åóôå ôïõò üñïõò ôçò ¢äåéáò ×ñÞóçò; Áí åðéëÝîåôå ü÷é ç åãêáôÜóôáóç èá ôåñìáôéóôåß. Ãéá íá óõíå÷éóôåß ç åãêáôÜóôáóç ðñÝðåé íá áðïäÝ÷åóôå ôïõò üñïõò ôçò ¢äåéáò ×ñÞóçò. +LicenseLabel3=Ðáñáêáëþ äéáâÜóôå ðñïóåêôéêÜ ôéò ðáñáêÜôù ðëçñïöïñßåò ðñéí óõíå÷ßóåôå. ÐñÝðåé íá áðïäÝ÷åóôå ôïõò üñïõò ôçò ¢äåéáò ×ñÞóçò ðñéí íá óõíå÷ßóåôå ôçí åãêáôÜóôáóç. +LicenseAccepted=&ÄÝ÷ïìáé ôïõò üñïõò ôçò ¢äåéáò ×ñÞóçò +LicenseNotAccepted=Äåí &áðïäÝ÷ïìáé ôïõò üñïõò ôçò ¢äåéáò ×ñÞóçò + +; *** "Information" wizard pages +WizardInfoBefore=Ðëçñïöïñßåò +InfoBeforeLabel=Ðáñáêáëþ äéáâÜóôå ðñïóåêôéêÜ ôéò ðáñáêÜôù ðëçñïöïñßåò ðñéí óõíå÷ßóåôå. +InfoBeforeClickLabel=Áí åßóôå Ýôïéìïé íá óõíå÷ßóåôå ðáôÞóôå Åðüìåíï. +WizardInfoAfter=Ðëçñïöïñßåò +InfoAfterLabel=Ðáñáêáëþ äéáâÜóôå ðñïóåêôéêÜ ôéò ðáñáêÜôù ðëçñïöïñßåò ðñéí óõíå÷ßóåôå. +InfoAfterClickLabel=Áí åßóôå Ýôïéìïé íá óõíå÷ßóåôå ðáôÞóôå Åðüìåíï. + +; *** "User Information" wizard page +WizardUserInfo=Ðëçñïöïñßåò ãéá ôïí ×ñÞóôç +UserInfoDesc=Ðáñáêáëþ äþóôå ôéò ðëçñïöïñßåò. +UserInfoName=&Ïíïìá ×ñÞóôç: +UserInfoOrg=&Åôáéñåßá: +UserInfoSerial=&Óåéñéáêü Áñéèìü: +UserInfoNameRequired=ÐñÝðåé íá äþóåôå üíïìá. + +; *** "Select Destination Location" wizard page +; 4.0.x +WizardSelectDir=ÅðéëÝîôå ôïí êáôÜëïãï ðïõ èá åãêáôáóôáèåß ôï ðñüãñáììá. +SelectDirDesc=Ðïý èá åãêáôáóôáèåß ôï [name]; +;SelectDirLabel=ÅðéëÝîôå ôïí êáôÜëïãï ðïõ èá åãêáôáóôáèåß ôï ðñüãñáììá. ÐáôÞóôå Åðüìåíï ãéá íá óõíå÷ßóåôå. +DiskSpaceMBLabel=Áõôü ôï ðñüãñáììá ÷ñåéÜæåôáé [mb] MB ÷þñï óôïí äßóêï. +ToUNCPathname=Ç åãêáôÜóôáóç äåí ìðïñåß íá ãßíåé óå äßóêï äéêôýïõ. Áí èÝëåôå íá ãßíåé ç åãêáôÜóôáóç óå äßóêï äéêôýïõ ðñÝðåé íá ïñßóåôå áõôüí ôï äßóêï. +InvalidPath=Äþóôå ôçí ðëÞñç äéáäñïìÞ.%nðáñÜäåéãìá:%n%nC:\APP +InvalidDrive=Ï ôïðéêüò äßóêïò ç ï äßóêïò äéêôýïõ ðïõ åðéëÝîáôå äåí õðÜñ÷åé ç äåí åßíáé ðñïóâÜóéìïò. ÅðéëÝîôå Üëëïí. +DiskSpaceWarningTitle=Äåí õðÜñ÷åé áñêåôüò ÷þñïò óôï äßóêï. +DiskSpaceWarning=Ç åãêáôÜóôáóç ÷ñåéÜæåôáé ôïõëÜ÷éóôïí %1 KB åëåýèåñï ÷þñï óôï äßóêï áëëÜ ï åðéëåãìÝíïò ïäçãüò äéáèÝôåé ìüíïí %2 KB.%n%nÈÝëåôå íá óõíå÷ßóåôå ïðùóäÞðïôå; +BadDirName32=Ïíüìáôá êáôáëüãùí äåí ìðïñïýí íá ðåñéÝ÷ïõí êÜðïéïí áðü ôïõò ðáñáêÜôù ÷áñáêôÞñåò:%n%n%1 +DirExistsTitle=Ï êáôÜëïãïò õðÜñ÷åé. +DirExists=Ï êáôÜëïãïò:%n%n%1%n%nõðÜñ÷åé Þäç. ÈÝëåôå íá ãßíåé ç åãêáôÜóôáóç óå áõôüí ôïí êáôÜëïãï; +DirDoesntExistTitle=Ï êáôÜëïãïò äåí õðÜñ÷åé. +DirDoesntExist=Ï êáôÜëïãïò:%n%n%1%n%näåí õðÜñ÷åé. ÈÝëåôå íá äçìéïõñãçèåß; +;4.1.3 +InvalidDirName=ËÜèïò üíïìá öáêÝëïõ. +;4.1.5 +DirNameTooLong=Ôï üíïìá ôïõ öáêÝëïõ åßíáé ðïëý ìåãÜëï. +;4.1.8 +;SelectDirLabel2=Ôï [name] èá åãêáôáóôáèåß óôïí áêüëïõèï öÜêåëï.%n%nÃéá óõíÝ÷åéá ðáôÞóôå Åðüìåíï. Áí èÝëåôå Üëëï öÜêåëï, ðáôÞóôå Åýñåóç. +SelectDirLabel3=Ôï [name] èá åãêáôáóôáèåß óôïí áêüëïõèï öÜêåëï. +SelectDirBrowseLabel=Ãéá óõíÝ÷åéá ðáôÞóôå Åðüìåíï. Áí èÝëåôå Üëëï öÜêåëï, ðáôÞóôå Åýñåóç. + +; *** "Select Components" wizard page +WizardSelectComponents=ÅðéëïãÞ Óõóôáôéêþí +SelectComponentsDesc=Ðïéá óõóôáôéêÜ èÝëåôå íá åãêáôáóôáèïýí; +SelectComponentsLabel2=ÅðéëÝîôå ôá óõóôáôéêÜ ðïõ èÝëåôå íá åãêáôáóôÞóåôå êáé ðáôÞóôå Åðüìåíï ãéá óõíÝ÷åéá ôçò åãêáôÜóôáóçò. +FullInstallation=ÐëÞñçò ÅãêáôÜóôáóç. +; if possible don't translate 'Compact' as 'Minimal' (I mean 'Minimal' in your language) +CompactInstallation=ÐåñéïñéóìÝíç ÅãêáôÜóôáóç. +CustomInstallation=ÐñïóáñìïóìÝíç ÅãêáôÜóôáóç. +NoUninstallWarningTitle=Ôá óõóôáôéêÜ õðÜñ÷ïõí. +NoUninstallWarning=Ç åãêáôÜóôáóç äéáðßóôùóå üôé ôá ðáñáêÜôù óõóôáôéêÜ åßíáé Þäç åãêáôåóôçìÝíá óôïí õðïëïãéóôÞ óáò:%n%n%1 +ComponentSize1=%1 KB +ComponentSize2=%1 MB +ComponentsDiskSpaceMBLabel=Ç óõãêåêñéìÝíç åðéëïãÞ áðáéôåß ôïõëÜ÷éóôïí [mb] MB åëåýèåñï ÷þñï óôïí äßóêï. + +; *** "Select Additional Tasks" wizard page +WizardSelectTasks=ÅðéëïãÞ ÐåñáéôÝñù Åíåñãåéþí +SelectTasksDesc=ÐïéÝò åðéðëÝïí åíÝñãåéåò èÝëåôå íá ãßíïõí; +SelectTasksLabel2=ÅðéëÝîôå ôéò åðéðëÝïí åíÝñãåéåò ðïõ èÝëåôå íá ãßíïõí êáôÜ ôçí åãêáôÜóôáóç ôïõ [name] êáé ðáôÞóôå Åðüìåíï. + +; *** "Select Start Menu Folder" wizard page +; 2.0.x +;ReadyMemoTasks=ÅðéðëÝïí ÅíÝñãåéåò: +WizardSelectProgramGroup=ÅðéëïãÞ Êáôáëüãïõ Óôï Ìåíïý Åêêßíçóç. +SelectStartMenuFolderDesc=Ðïý èá ôïðïèåôçèïýí ïé óõíôïìåýóåéò ôïõ ðñïãñÜììáôïò; +; 4.0.x +;SelectStartMenuFolderLabel=ÅðéëÝîôå ôïí êáôÜëïãï óôï ìåíïý åêêßíçóçò óôïí ïðïßï èÝëåôå äçìéïõñãçèïýí ïé óõíôïìåýóåéò ôïõ ðñïãñÜììáôïò êáé ðáôÞóôå Åðüìåíï. +; 5.1.0+ +;NoIconsCheck=&×ùñßò äçìéïõñãßá åéêïíéäßùí +MustEnterGroupName=ÐñÝðåé íá äþóåôå ôï üíïìá åíüò êáôáëüãïõ. +BadGroupName=Ïíüìáôá êáôáëüãùí äåí ìðïñïýí íá ðåñéÝ÷ïõí êÜðïéïí áðü ôïõò ðáñáêÜôù ÷áñáêôÞñåò:%n%n%1 +NoProgramGroupCheck2=&×ùñßò äçìéïõñãßá êáôáëüãïõ óôï ìåíïý åêêßíçóç. +;4.1.3 +InvalidGroupName=Ôï üíïìá ôïõ group äåí åßíáé óùóôü. +;4.1.4+ +GroupNameTooLong=Ôï üíïìá ôïõ group åéíáé ðïëý ìåãÜëï. +;4.1.8 +;SelectStartMenuFolderLabel2=Ç åãêáôÜóôáóç èá äçìéïõñãÞóåé ôéò óõíôïìåýóåéò ôïõ ðñïãñÜììáôïò óôçí áêüëïõèç ïìÜäá.%n%nÃéá óõíÝ÷åéá, ðáôÞóôå Åðüìåíï. Áí èÝëåôå Üëëç ïìÜäá, ðáôÞóôå åýñåóç. +SelectStartMenuFolderLabel3=Ç åãêáôÜóôáóç èá äçìéïõñãÞóåé ôéò óõíôïìåýóåéò ôïõ ðñïãñÜììáôïò óôçí áêüëïõèç ïìÜäá. +SelectStartMenuFolderBrowseLabel=Ãéá óõíÝ÷åéá, ðáôÞóôå Åðüìåíï. Áí èÝëåôå Üëëç ïìÜäá, ðáôÞóôå åýñåóç. + + +; *** "Ready to Install" wizard page +WizardReady=¸ôïéìïò ãéá åãêáôÜóôáóç +ReadyLabel1=Ç åãêáôÜóôáóç ôïõ [name] åßíáé Ýôïéìç íá åêôåëåóôåß óôïí õðïëïãéóôÞ óáò. +ReadyLabel2a=ÐáôÞóôå ÅãêáôÜóôáóç ãéá íá óõíå÷ßóåôå Þ Ðßóù áí èÝëåôå íá áëëÜîåôå êÜðïéåò ñõèìßóåéò. +ReadyLabel2b=ÐáôÞóôå ÅãêáôÜóôáóç ãéá íá óõíå÷ßóåôå. +ReadyMemoUserInfo=Ðëçñïöïñßåò ×ñÞóôç: +ReadyMemoDir=ÊáôÜëïãïò ðñïïñéóìïý: +ReadyMemoType=Åßäïò åãêáôÜóôáóçò: +ReadyMemoComponents=ÅðéëåãìÝíá óõóôáôéêÜ: +ReadyMemoGroup=ÊáôÜëïãïò óôï ìåíïý ÐñïãñÜììáôá: +ReadyMemoTasks=ÅðéðëÝïí ÅíÝñãåéåò: + +; *** "Preparing to Install" wizard page +WizardPreparing=Ðñïåôïéìáóßá ÅãêáôÜóôáóçò +PreparingDesc=Ç åãêáôÜóôáóç ðñïåôïéìÜæåé ôï ðñüãñáììá [name] íá ôïðïèåôçèåß óôïí õðïëïãéóôÞ. +PreviousInstallNotCompleted=The installation/removal of a previous program was not completed. You will need to restart your computer to complete that installation.%n%nAfter restarting your computer, run Setup again to complete the installation of [name]. +CannotContinue=Setup cannot continue. Please click Cancel to exit. + +; *** "Installing" wizard page +WizardInstalling=Ðñüïäïò ÅãêáôÜóôáóçò +InstallingLabel=Ðáñáêáëþ ðåñéìÝíåôå íá ïëïêëçñùèåß ç åãêáôÜóôáóç ôïõ [name] óôïí õðïëïãéóôÞ óáò. + +; *** "Setup Completed" wizard page +; 2.0.x +;WizardFinished=Ç ÅãêáôÜóôáóç Ïëïêëçñþèçêå +FinishedHeadingLabel=Completing the [name] Setup Wizard +FinishedLabelNoIcons=Ç åãêáôÜóôáóç ôïõ [name] óôïí õðïëïãéóôÞ óáò ôåëåßùóå ìå åðéôõ÷ßá. +FinishedLabel=Ç åãêáôÜóôáóç ôïõ [name] óôïí õðïëïãéóôÞ óáò ôåëåßùóå ìå åðéôõ÷ßá. Ìðïñåßôå íá îåêéíÞóåôå ôï ðñüãñáììá åðéëÝãïíôáò ôï åéêïíßäéï ðïõ äçìéïõñãÞèçêå óôï ìåíïý åêêßíçóç. +ClickFinish=ÐáôÞóôå ÔÝëïò ãéá íá ôåñìáôßóåôå ôï ðñüãñáììá åãêáôÜóôáóçò. +FinishedRestartLabel=Ãéá íá ïëïêëçñùèåß ç åãêáôÜóôáóç ôïõ [name] ðñÝðåé íá ãßíåé åðáíåêêßíçóç ôïõ õðïëïãéóôÞ óáò. ÈÝëåôå íá ãßíåé ôþñá; +FinishedRestartMessage=Ãéá íá ïëïêëçñùèåß ç åãêáôÜóôáóç ôïõ [name] ðñÝðåé íá ãßíåé åðáíåêêßíçóç ôïõ õðïëïãéóôÞ óáò.%n%nÈÝëåôå íá ãßíåé ôþñá; +ShowReadmeCheck=Íáé èÝëù íá äéáâÜóù ôéò ðëçñïöïñßåò ôïõ ðñïãñÜììáôïò +YesRadio=&Íáé íá ãßíåé åðáíåêêßíçóç ôþñá. +NoRadio=&Ï÷é èá êÜíù åðáíåêêßíçóç áñãüôåñá. +; used for example as 'Run MyProg.exe' +RunEntryExec=Íá åêôåëåóôåß ôï ðñüãñáììá %1 +; used for example as 'View Readme.txt' +RunEntryShellExec=Íá åêôåëåóôåß ôï %1 + +; *** "Setup Needs the Next Disk" stuff +ChangeDiskTitle=ÔïðïèåôÞóôå ôçí åðüìåíç äéóêÝôôá +; 4.0.x +;SelectDirectory=ÅðéëÝîôå êáôÜëïãï +SelectDiskLabel2=ÔïðïèåôÞóôå ôçí äéóêÝôôá %1 êáé ðáôÞóôå ÅíôÜîåé. +PathLabel=&ÄéáäñïìÞ +FileNotInDir2=Ôï áñ÷åßï "%1" äåí âñßóêåôáé óôï "%2". ÔïðïèåôÞóôå ôç óùóôÞ äéóêÝôôá. +SelectDirectoryLabel=Äþóôå ôçí ôïðïèåóßá ôçò åðüìåíçò äéóêÝôôáò. + +; *** Installation phase messages +SetupAborted=Ç åãêáôÜóôáóç äåí ïëïêëçñþèçêå.%n%nÄéïñèþóôå ôï ðñüâëçìá êáé åêôåëÝóôå îáíÜ ôçí åãêáôÜóôáóç. +EntryAbortRetryIgnore=ÐáôÞóôå Retry ãéá íá îáíáðñïóðáèÞóåôå, Ignore ãéá íá óõíå÷ßóåôå ç Abort ãéá íá ôåñìáôßóåôå ôçí åãêáôÜóôáóç. + +; *** Installation status messages +StatusCreateDirs=Äçìéïõñãßá êáôáëüãùí... +StatusExtractFiles=Áðïóõìðßåóç áñ÷åßùí... +StatusCreateIcons=Äçìéïõñãßá åéêïíéäßùí... +StatusCreateIniEntries=Êáôá÷þñçóç óôï ÉÍÉ áñ÷åßï óõóôÞìáôïò... +StatusCreateRegistryEntries=Êáôá÷þñçóç óôï ìçôñþï óõóôÞìáôïò... +StatusRegisterFiles=Êáôá÷þñçóç áñ÷åßùí +StatusSavingUninstall=Ðëçñïöïñßåò áðåãêáôÜóôáóçò... +StatusRunProgram=Ôåëåéþíïíôáò ôçí åãêáôÜóôáóç... +StatusRollback=Rolling back changes... + +; *** Misc. errors +; 2.0.x +;ErrorInternal=ÓöÜëìá %1 +ErrorInternal2=ÓöÜëìá %1 +ErrorFunctionFailedNoCode=%1 ÓöÜëìá +ErrorFunctionFailed=%1 ÓöÜëìá, êùä. %2 +ErrorFunctionFailedWithMessage=%1 ÓöÜëìá, êùä. %2%n%3 +ErrorExecutingProgram=Äåí ìðïñåß íá åêôåëåóôåß ôï áñ÷åßï:%n%1 + +;2.0.x +;ErrorDDEExecute=DDE: ÓöÜëìá êáôÜ ôçí åêôÝëåóç ôçò åíÝñãåéáò (code: %1) +;ErrorDDECommandFailed=DDE: Ç åíôïëÞ áðÝôõ÷å. +;ErrorDDERequest=DDE: ÓöÜëìá êáôÜ ôçí åêôÝëåóç ôçò åíÝñãåéáò (code: %1) + +; *** Registry errors +ErrorRegOpenKey=Äåí ìðïñåß íá äéáâáóôåß ôï êëåéäß ìçôñþïõ óõóôÞìáôïò:%n%1\%2 +ErrorRegCreateKey=Äåí ìðïñåß íá äçìéïõñãçèåß ôï êëåéäß ìçôñþïõ óõóôÞìáôïò:%n%1\%2 +ErrorRegWriteKey=Äåí ìðïñåß íá ãßíåé êáôá÷þñçóç óôï êëåéäß ìçôñþïõ óõóôÞìáôïò:%n%1\%2 + +; *** INI errors +ErrorIniEntry=Äåí ìðïñåß íá ãßíåé êáôá÷þñçóç óôï ÉÍÉ áñ÷åßï óõóôÞìáôïò "%1". + +; *** File copying errors +FileAbortRetryIgnore=ÐáôÞóôå Retry ãéá íá îáíáðñïóðáèÞóåôå, Ignore ãéá íá óõíå÷ßóåôå ç Abort ãéá íá ôåñìáôßóåôå ôçí åãêáôÜóôáóç. +FileAbortRetryIgnore2=ÐáôÞóôå Retry ãéá íá îáíáðñïóðáèÞóåôå, Ignore ãéá íá óõíå÷ßóåôå ç Abort ãéá íá ôåñìáôßóåôå ôçí åãêáôÜóôáóç. +SourceIsCorrupted=Ôï áñ÷åßï ðñïÝëåõóçò åßíáé êáôåóôñáììÝíï. +SourceDoesntExist=Ôï áñ÷åßï ðñïÝëåõóçò "%1" äåí õðÜñ÷åé. +ExistingFileReadOnly=Ôï áñ÷åßï åßíáé ìðáñêáñéóìÝíï ìüíï ãéá áíÜãíùóç.%n%nÐáôÞóôå Retry ãéá íá ôï îåìáñêÜñåôå êáé íá ðñïóðáèÞóåôå ðÜëé, Ignore ãéá íá ôï ðñïóðåñÜóåôå ç Abort ãéá íá ôåñìáôßóåôå ôçí åãêáôÜóôáóç. +ErrorReadingExistingDest=ÐáñïõóéÜóôçêå óöÜëìá êáôÜ ôçí áíÜãíùóç ôïõ áñ÷åßïõ: +FileExists=Ôï áñ÷åßï õðÜñ÷åé.%n%nÈÝëåôå íá îáíáãñáöôåß; +ExistingFileNewer=Åíá áñ÷åßï ðïõ âñÝèçêå óôïí õðïëïãéóôÞ óáò åßíáé íåüôåñçò Ýêäïóçò áðï åêåßíï ôçò åãêáôÜóôáóçò. Ðñïôåßíåôáé íá êñáôÞóåôå ôï õðÜñ÷ïí áñ÷åßï.%n%nÈÝëåôå íá êñáôÞóåôå ôï õðÜñ÷ïí áñ÷åßï; +ErrorChangingAttr=ÐñïÝêõøå óöÜëìá óôçí ðñïóðÜèåéá íá áëëá÷ôïýí ôá ÷áñáêôçñéóôéêÜ ôïõ áñ÷åßïõ: +ErrorCreatingTemp=ÐñïÝêõøå óöÜëìá óôçí ðñïóðÜèåéá íá äçìéïõñãçèåß Ýíá áñ÷åßï óôïí êáôÜëïãï ðñïïñéóìïý: +ErrorReadingSource=ÐñïÝêõøå óöÜëìá óôçí ðñïóðÜèåéá áíÜãíùóçò ôïõ áñ÷åßïõ ðñïÝëåõóçò: +ErrorCopying=ÐñïÝêõøå óöÜëìá óôçí ðñïóðÜèåéá íá áíôéãñáöåß ôï áñ÷åßï: +ErrorReplacingExistingFile=ÐñïÝêõøå óöÜëìá óôçí ðñïóðÜèåéá íá áíôéêáôáóôáèåß ôï õðÜñ÷ïí áñ÷åßï: +ErrorRestartReplace=ÐñïÝêõøå óöÜëìá óôçí ðñïóðÜèåéá íá ãßíåé åðáíåêêßíçóç êáé áíôéêáôÜóôáóç áñ÷åßïõ: +ErrorRenamingTemp=ÐñïÝêõøå óöÜëìá óôçí ðñïóðÜèåéá ìåôïíïìáóßáò åíüò áñ÷åßïõ óôïí êáôÜëïãï ðñïïñéóìïý: +ErrorRegisterServer=ÐñïÝêõøå óöÜëìá óôçí ðñïóðÜèåéá êáôá÷þñçóçò DLL/OCX: %1 +ErrorRegSvr32Failed=RegSvr32 failed with exit code %1 +ErrorRegisterTypeLib=Unable to register the type library: %1 + +; *** Post-installation errors +ErrorOpeningReadme=ÐñïÝêõøå óöÜëìá óôçí ðñïóðÜèåéá íá öïñôùèåß ôï áñ÷åßï ðëçñïöïñéþí. +ErrorRestartingComputer=ÐñïÝêõøå óöÜëìá óôçí ðñïóðÜèåéá åðáíåêêßíçóçò ôïõ õðïëïãéóôÞ.%nÐáñáêáëþ åðáíåêêéíÞóôå ôïí õðïëïãéóôÞ óáò. + +; *** Uninstaller messages +UninstallNotFound=Ôï áñ÷åßï "%1" äåí âñÝèçêå. Ç áðåãêáôÜóôáóç äåí ìðïñåß íá ãßíåé +; 4.0.x +UninstallOpenError=Ôï áñ÷åßï "%1" äåí ìðüñåóå íá öïñôùèåß. Ç áðåãêáôÜóôáóç äåí ìðïñåß íá ãßíåé +UninstallUnsupportedVer=Ôï áñ÷åßï "%1" äåí áíáãíùñßæåôáé áðü áõôÞ ôçí Ýêäïóç ôçò åãêáôÜóôáóçò, Ç áðåãêáôÜóôáóç äåí ìðïñåß íá åêôåëåóôåß +UninstallUnknownEntry=Ôï áñ÷åßï "%1" äåí áíáãíùñßæåôáé áðü áõôÞ ôçí Ýêäïóç ôçò åãêáôÜóôáóçò, Ç áðåãêáôÜóôáóç äåí ìðïñåß íá åêôåëåóôåß +ConfirmUninstall=Åßóôå óßãïõñïé üôé èÝëåôå íá äéáãñÜøåôå ôï %1 êáé üëá ôá óõóôáôéêÜ ôïõ; +; 5.1.0+ +UninstallOnlyOnWin64=ÁõôÞ ç åöáñìïãÞ ìðïñåß íá áðåãêáôáóôáèåß ìüíï óå 64-bit Windows. +OnlyAdminCanUninstall=Ç áðåãêáôÜóôáóç ìðïñåß íá åêôåëåóôåß ìüíï áðü ôïí Äéá÷åéñéóôÞ óõóôÞìáôïò +UninstallStatusLabel=Ðáñáêáëþ ðåñéìÝíåôå üóï ôï %1 äéáãñÜöåôå áðü ôïí õðïëïãéóôÞ óáò +UninstalledAll=Ç áðåãêáôÜóôáóç ôïõ %1 Ýãéíå ìå åðéôõ÷ßá. +UninstalledMost=Ç áðåãêáôÜóôáóç ôïõ %1 Ýãéíå ìå åðéôõ÷ßá.%n%nÊÜðïéá óõóôáôéêÜ ðïõ ðáñÝìåéíáí óôïí õðïëïãéóôÞ óáò èá ðñÝðåé íá ôá äéáãñÜøåôå åóåßò. +UninstalledAndNeedsRestart=To complete the uninstallation of %1, your computer must be restarted.%n%nWould you like to restart now? +UninstallDataCorrupted="%1" Áõôü ôï áñ÷åßï åßíáé êáôåóôñáììÝíï. Äåí ìðïñåß íá ãßíåé áðåãêáôÜóôáóç. + +; *** Uninstallation phase messages +ConfirmDeleteSharedFileTitle=ÈÝëåôå íá äéáãñáöïýí ôá êïéíÜ áñ÷åßá; +ConfirmDeleteSharedFile2=Ôá êïéíÜ áñ÷åßá äåí ÷ñçóéìïðïéïýíôáé áðü êÜðïéï ðñüãñáììá. ÈÝëåôå íá äéáãñáöïýí;%n%nÁí êÜðïéï ðñüãñáììá ôá ÷ñçóéìïðïéåß ßóùò äåí åêôåëåßôáé óùóôÜ áí ôá äéáãñÜøåôå. Áí äåí åßóôå óßãïõñïé áöÞóôå ôá óôï óýóôçìá óáò äåí ðñïêáëïýí êÜðïéï ðñüâëçìá. +SharedFileNameLabel=Ïíïìá Áñ÷åßïõ: +SharedFileLocationLabel=Ôïðïèåóßá: +WizardUninstalling=Ðñüïäïò ÁðåãêáôÜóôáóçò: +StatusUninstalling=ÁðåãêáôÜóôáóç ôïõ %1... + +[CustomMessages] +NameAndVersion=%1 Ýêäïóç %2 +AdditionalIcons=ÅðéðëÝïí åéêïíßäéá: +CreateDesktopIcon=Äçìéïõñãßá åíüò &åéêïíéäßïõ óôçí åðéöÜíåéá åñãáóßáò +CreateQuickLaunchIcon=Äçìéïõñãßá åíüò åéêïíéäßïõ óôç &ÃñÞãïñç Åêêßíçóç +ProgramOnTheWeb=Ôï %1 óôï Internet +UninstallProgram=ÁðåãêáôÜóôáóç ôïõ %1 +LaunchProgram=Åêêßíçóç ôïõ %1 +AssocFileExtension=%Áíôéóôïß÷éóç ôïõ %1 ìå ôçí %2 åðÝêôáóç áñ÷åßïõ +AssocingFileExtension=Ãßíåôáé áíôéóôïß÷çóç ôïõ %1 ìå ôçí %2 åðÝêôáóç áñ÷åßïõ... + diff --git a/branches/ph-plugins/ProcessHacker/Build/Installer/Process_Hacker_installer.iss b/branches/ph-plugins/ProcessHacker/Build/Installer/Process_Hacker_installer.iss new file mode 100644 index 000000000..7c05990ab --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Build/Installer/Process_Hacker_installer.iss @@ -0,0 +1,385 @@ +;* Process Hacker - Installer script +;* +;* Copyright (C) 2009 XhmikosR +;* +;* 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 . + + +; Inno Setup v5.3.5 +; +; Requirements: +; *Inno Setup QuickStart Pack: +; http://www.jrsoftware.org/isdl.php#qsp + + +#define installer_build_number "38" + +#define VerMajor +#define VerMinor +#define VerRevision +#define VerBuild + +#expr ParseVersion("..\..\bin\Release\ProcessHacker.exe", VerMajor, VerMinor, VerRevision, VerBuild) +#define app_version str(VerMajor) + "." + str(VerMinor) + "." + str(VerRevision) + "." + str(VerBuild) +#define simple_app_version str(VerMajor) + "." + str(VerMinor) +#define installer_build_date GetDateTimeString('dd/mm/yyyy', '.', '') + + +; From now on you'll probably won't have to change anything, so be careful +[Setup] +AppID=Process_Hacker +AppCopyright=Copyright © 2008-2009, Process Hacker Team. Licensed under the GNU GPL, v3. +AppContact=http://sourceforge.net/tracker/?group_id=242527 +AppName=Process Hacker +AppVerName=Process Hacker {#= simple_app_version} +AppVersion={#= simple_app_version} +AppPublisher=wj32 +AppPublisherURL=http://processhacker.sourceforge.net/ +AppSupportURL=http://sourceforge.net/tracker/?group_id=242527 +AppUpdatesURL=http://processhacker.sourceforge.net/ +UninstallDisplayName=Process Hacker {#= simple_app_version} +DefaultDirName={pf}\Process Hacker +DefaultGroupName=Process Hacker +VersionInfoCompany=wj32 +VersionInfoCopyright=Licensed under the GNU GPL, v3. +VersionInfoDescription=Process Hacker {#= simple_app_version} Setup +VersionInfoTextVersion={#= app_version} +VersionInfoVersion={#= app_version} +VersionInfoProductName=Process Hacker +VersionInfoProductVersion={#= app_version} +VersionInfoProductTextVersion={#= app_version} +MinVersion=0,5.01.2600 +AppReadmeFile={app}\README.txt +LicenseFile=..\..\..\LICENSE.txt +InfoAfterFile=..\..\..\CHANGELOG.txt +SetupIconFile=Icons\ProcessHacker.ico +UninstallDisplayIcon={app}\ProcessHacker.exe +WizardImageFile=Icons\ProcessHackerLarge.bmp +WizardSmallImageFile=Icons\ProcessHackerSmall.bmp +OutputDir=. +OutputBaseFilename=processhacker-{#= simple_app_version}-setup +AllowNoIcons=True +Compression=lzma/ultra64 +SolidCompression=True +InternalCompressLevel=ultra64 +EnableDirDoesntExistWarning=False +DirExistsWarning=No +ShowTasksTreeLines=True +AlwaysShowDirOnReadyPage=True +AlwaysShowGroupOnReadyPage=True +WizardImageStretch=False +PrivilegesRequired=Admin +ShowLanguageDialog=Auto +DisableDirPage=Auto +DisableProgramGroupPage=Auto +LanguageDetectionMethod=uilanguage +AppMutex=Global\ProcessHackerMutex +ArchitecturesInstallIn64BitMode=x64 + + +[Languages] +; Installer's languages +Name: en; MessagesFile: compiler:Default.isl +Name: gr; MessagesFile: Languages\Greek.isl + + +; Include the installer's custom messages and services stuff +#include "Custom_Messages.iss" +#include "Services.iss" + + +[Messages] +BeveledLabel=Process Hacker v{#= simple_app_version} by wj32 Setup v{#= installer_build_number} built on {#= installer_build_date} + + +[Files] +Source: ..\..\bin\Release\Assistant.exe; DestDir: {app}; Flags: ignoreversion +Source: ..\..\bin\Release\base.txt; DestDir: {app}; Flags: ignoreversion +Source: ..\..\bin\Release\CHANGELOG.txt; DestDir: {app}; Flags: ignoreversion +Source: ..\..\bin\Release\Help.htm; DestDir: {app}; Flags: ignoreversion +Source: ..\..\bin\Release\LICENSE.txt; DestDir: {app}; Flags: ignoreversion +Source: ..\..\bin\Release\kprocesshacker.sys; DestDir: {app}; Flags: ignoreversion; Check: NOT Is64BitInstallMode() +Source: ..\..\bin\Release\NProcessHacker.dll; DestDir: {app}; Flags: ignoreversion; Check: NOT Is64BitInstallMode() +Source: ..\..\bin\Release\NProcessHacker64.dll; DestName: NProcessHacker.dll; DestDir: {app}; Flags: ignoreversion; Check: Is64BitInstallMode() +Source: ..\..\bin\Release\ProcessHacker.exe; DestDir: {app}; Flags: ignoreversion +Source: ..\..\bin\Release\README.txt; DestDir: {app}; Flags: ignoreversion +Source: ..\..\bin\Release\structs.txt; DestDir: {app}; Flags: ignoreversion +Source: Icons\uninstall.ico; DestDir: {app}; Flags: ignoreversion + + +[Tasks] +Name: desktopicon; Description: {cm:CreateDesktopIcon}; GroupDescription: {cm:AdditionalIcons} +Name: desktopicon\user; Description: {cm:tsk_currentuser}; GroupDescription: {cm:AdditionalIcons}; Flags: exclusive +Name: desktopicon\common; Description: {cm:tsk_allusers}; GroupDescription: {cm:AdditionalIcons}; Flags: unchecked exclusive +Name: quicklaunchicon; Description: {cm:CreateQuickLaunchIcon}; GroupDescription: {cm:AdditionalIcons}; OnlyBelowVersion: 0,6.01; Flags: unchecked + +Name: startup_task; Description: {cm:tsk_startupdescr}; GroupDescription: {cm:tsk_startup}; Check: StartupCheck(); Flags: unchecked checkablealone +Name: startup_task\minimized; Description: {cm:tsk_startupdescrmin}; GroupDescription: {cm:tsk_startup}; Check: StartupCheck(); Flags: unchecked +Name: remove_startup_task; Description: {cm:tsk_removestartup}; GroupDescription: {cm:tsk_startup}; Check: NOT StartupCheck(); Flags: unchecked + +Name: create_KPH_service; Description: {cm:tsk_createKPHservice}; GroupDescription: {cm:tsk_other}; Check: NOT KProcessHackerStateCheck() AND NOT Is64BitInstallMode(); Flags: unchecked dontinheritcheck +Name: delete_KPH_service; Description: {cm:tsk_deleteKPHservice}; GroupDescription: {cm:tsk_other}; Check: KProcessHackerStateCheck() AND NOT Is64BitInstallMode(); Flags: unchecked dontinheritcheck + +Name: reset_settings; Description: {cm:tsk_resetsettings}; GroupDescription: {cm:tsk_other}; Check: SettingsExistCheck(); Flags: unchecked checkablealone + +Name: set_default_taskmgr; Description: {cm:tsk_setdefaulttaskmgr}; GroupDescription: {cm:tsk_other}; Check: PHDefaulTaskmgrCheck(); Flags: unchecked dontinheritcheck +Name: restore_taskmgr; Description: {cm:tsk_restoretaskmgr}; GroupDescription: {cm:tsk_other}; Check: NOT PHDefaulTaskmgrCheck(); Flags: unchecked dontinheritcheck + + +[Icons] +Name: {group}\Process Hacker; Filename: {app}\ProcessHacker.exe; Comment: Process Hacker {#= simple_app_version}; WorkingDir: {app}; IconFilename: {app}\ProcessHacker.exe; IconIndex: 0 +Name: {group}\{cm:sm_help}\{cm:sm_changelog}; Filename: {app}\CHANGELOG.txt; Comment: {cm:sm_com_changelog}; WorkingDir: {app} +Name: {group}\{cm:sm_help}\{cm:sm_helpfile}; Filename: {app}\Help.htm; Comment: {cm:sm_helpfile}; WorkingDir: {app} +Name: {group}\{cm:sm_help}\{cm:sm_readmefile}; Filename: {app}\README.txt; Comment: {cm:sm_com_readmefile}; WorkingDir: {app} +Name: {group}\{cm:sm_help}\{cm:ProgramOnTheWeb,Process Hacker}; Filename: http://processhacker.sourceforge.net/; Comment: {cm:ProgramOnTheWeb,Process Hacker} +Name: {group}\{cm:UninstallProgram,Process Hacker}; Filename: {uninstallexe}; IconFilename: {app}\uninstall.ico; Comment: {cm:UninstallProgram,Process Hacker}; WorkingDir: {app} + +Name: {commondesktop}\Process Hacker; Filename: {app}\ProcessHacker.exe; Tasks: desktopicon\common; Comment: Process Hacker {#= simple_app_version}; WorkingDir: {app}; IconFilename: {app}\ProcessHacker.exe; IconIndex: 0 +Name: {userdesktop}\Process Hacker; Filename: {app}\ProcessHacker.exe; Tasks: desktopicon\user; Comment: Process Hacker {#= simple_app_version}; WorkingDir: {app}; IconFilename: {app}\ProcessHacker.exe; IconIndex: 0 +Name: {userappdata}\Microsoft\Internet Explorer\Quick Launch\Process Hacker; Filename: {app}\ProcessHacker.exe; Tasks: quicklaunchicon; Comment: Process Hacker {#= simple_app_version}; WorkingDir: {app}; IconFilename: {app}\ProcessHacker.exe; IconIndex: 0 + + +[InstallDelete] +; Remove files from the install folder which are not needed anymore +Type: files; Name: {app}\ProcessHacker.exe.config +Type: files; Name: {app}\HACKING.txt +Type: files; Name: {app}\psvince.dll +Type: files; Name: {app}\Homepage.url +Type: files; Name: {app}\kprocesshacker.sys; Check: Is64BitInstallMode() + +Type: files; Name: {userdesktop}\Process Hacker.lnk; Check: NOT IsTaskSelected('desktopicon\user') +Type: files; Name: {commondesktop}\Process Hacker.lnk; Check: NOT IsTaskSelected('desktopicon\common') + +; Remove other languages' shortcuts in Start Menu +Type: files; Name: {group}\Process Hacker's Readme file.lnk +Type: files; Name: {group}\Process Hacker on the Web.url +Type: files; Name: {group}\Uninstall Process Hacker.lnk +Type: files; Name: {group}\Help and Support\Process Hacker on the Web.url +Type: files; Name: {group}\Help and Support\Change Log.lnk +Type: files; Name: {group}\Help and Support\Changelog.lnk +Type: files; Name: {group}\Help and Support\Process Hacker's Help.lnk +Type: files; Name: {group}\Help and Support\ReadMe File.lnk +Type: files; Name: {group}\Help and Support\ReadMe.lnk +Type: dirifempty; Name: {group}\Help and Support + +Type: files; Name: {group}\Áñ÷åßï âïÞèåéáò ôïõ Process Hacker.lnk +Type: files; Name: {group}\Ôï Process Hacker óôï Internet.url +Type: files; Name: {group}\ÁðåãêáôÜóôáóç ôïõ Process Hacker.lnk +Type: files; Name: {group}\ÂïÞèåéá êáé ÕðïóôÞñéîç\Ôï Process Hacker óôï Internet.url +Type: files; Name: {group}\ÂïÞèåéá êáé ÕðïóôÞñéîç\Éóôïñéêü Åêäüóåùí.lnk +Type: files; Name: {group}\ÂïÞèåéá êáé ÕðïóôÞñéîç\Áñ÷åßï âïÞèåéáò ôïõ Process Hacker.lnk +Type: files; Name: {group}\ÂïÞèåéá êáé ÕðïóôÞñéîç\Áñ÷åßï ReadMe.lnk +Type: dirifempty; Name: {group}\ÂïÞèåéá êáé ÕðïóôÞñéîç + +Type: filesandordirs; Name: {localappdata}\wj32; Tasks: reset_settings + + +[Registry] +Root: HKLM; Subkey: SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\taskmgr.exe; Flags: uninsdeletekeyifempty dontcreatekey +Root: HKCU; SubKey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: string; ValueName: Process Hacker; ValueData: """{app}\ProcessHacker.exe"""; Tasks: startup_task; Flags: uninsdeletevalue +Root: HKCU; SubKey: Software\Microsoft\Windows\CurrentVersion\Run; ValueType: string; ValueName: Process Hacker; ValueData: """{app}\ProcessHacker.exe"" -m"; Tasks: startup_task\minimized; Flags: uninsdeletevalue +Root: HKCU; SubKey: Software\Microsoft\Windows\CurrentVersion\Run; ValueName: Process Hacker; Tasks: remove_startup_task; Flags: deletevalue uninsdeletevalue +Root: HKLM; Subkey: SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\taskmgr.exe; ValueType: string; ValueName: Debugger; ValueData: """{app}\ProcessHacker.exe"""; Tasks: set_default_taskmgr +Root: HKLM; Subkey: SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\taskmgr.exe; ValueType: string; ValueName: Debugger; ValueData: """{app}\ProcessHacker.exe"""; Flags: uninsdeletevalue; Check: NOT PHDefaulTaskmgrCheck() +Root: HKLM; Subkey: SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\taskmgr.exe; ValueName: Debugger; Tasks: restore_taskmgr reset_settings; Flags: deletevalue uninsdeletevalue; Check: NOT PHDefaulTaskmgrCheck() + +; Windows Error Reporting keys +Root: HKLM; Subkey: SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps; ValueType: none; Flags: uninsdeletekeyifempty createvalueifdoesntexist; MinVersion: 0,6.0.6001 +Root: HKLM; Subkey: SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\ProcessHacker.exe; ValueType: none; Flags: uninsdeletekey; MinVersion: 0,6.0.6001 +Root: HKLM; Subkey: SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\ProcessHacker.exe; ValueType: dword; ValueName: DumpCount; ValueData: 5; Flags: uninsdeletevalue; MinVersion: 0,6.0.6001 +Root: HKLM; Subkey: SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\ProcessHacker.exe; ValueType: expandsz; ValueName: DumpFolder; ValueData: {sd}\ProgramData\wj32; Flags: uninsdeletevalue; MinVersion: 0,6.0.6001 +Root: HKLM; Subkey: SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\ProcessHacker.exe; ValueType: dword; ValueName: DumpType; ValueData: 1; Flags: uninsdeletevalue; MinVersion: 0,6.0.6001 + + +[Run] +Filename: {win}\Microsoft.NET\Framework\v2.0.50727\ngen.exe; Parameters: "install ""{app}\ProcessHacker.exe"""; StatusMsg: {cm:msg_optimizingperformance}; Flags: runhidden runascurrentuser skipifdoesntexist + +Filename: {app}\ProcessHacker.exe; Description: {cm:LaunchProgram,Process Hacker}; Flags: nowait postinstall skipifsilent runascurrentuser +Filename: http://processhacker.sourceforge.net/; Description: {cm:run_visitwebsite}; Flags: nowait postinstall skipifsilent shellexec runascurrentuser unchecked + + +[UninstallDelete] +Name: {app}\Homepage.url; Type: files +Name: {sd}\ProgramData\wj32\*.dmp; Type: files; MinVersion: 0,6.0.6001 +Name: {sd}\ProgramData\wj32; Type: dirifempty; MinVersion: 0,6.0.6001 + + +[Code] +// Create a mutex for the installer +const installer_mutex_name = 'process_hacker_setup_mutex'; + + +// Check if Process Hacker is configured to run on startup in order to control +// startup choice from within the installer +function StartupCheck(): Boolean; +begin + Result := True; + if RegValueExists(HKCU, 'Software\Microsoft\Windows\CurrentVersion\Run', 'Process Hacker') then + Result := False; +end; + + +// Check if Process Hacker's settings exist +function SettingsExistCheck(): Boolean; +begin + Result := False; + if DirExists(ExpandConstant('{localappdata}\wj32\')) then + Result := True; +end; + + +// Check if Process Hacker is set as the default Task Manager for Windows +function PHDefaulTaskmgrCheck(): Boolean; +var + svalue: String; +begin + Result := True; + if RegQueryStringValue(HKLM, + 'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\taskmgr.exe', 'Debugger', svalue) then begin + if svalue = (ExpandConstant('"{app}\ProcessHacker.exe"')) then + Result := False; + end; +end; + + +// Check if KProcessHacker is installed as a service +function KPHServiceCheck(): Boolean; +var + dvalue: DWORD; +begin + Result := False; + if RegQueryDWordValue(HKLM, 'SYSTEM\CurrentControlSet\Services\KProcessHacker', 'Start', dvalue) then begin + if dvalue = 1 then + Result := True; + end; +end; + + +// Check if Process Hacker's settings exist +function KProcessHackerStateCheck(): Boolean; +begin + Result := False; + if KPHServiceCheck AND IsServiceRunning('KProcessHacker') then + Result := True; +end; + + +procedure CurStepChanged(CurStep: TSetupStep); +begin + if CurStep = ssInstall then begin + if KProcessHackerStateCheck then begin + StopService('KProcessHacker'); + end; + if IsTaskSelected('delete_KPH_service') then begin + StopService('KProcessHacker'); + RemoveService('KProcessHacker'); + end; + end; + if CurStep = ssPostInstall then begin + if KPHServiceCheck AND NOT IsTaskSelected('delete_KPH_service') then begin + StartService('KProcessHacker'); + end; + if IsTaskSelected('create_KPH_service') then begin + StopService('KProcessHacker'); + RemoveService('KProcessHacker'); + InstallService(ExpandConstant('{app}\kprocesshacker.sys'),'KProcessHacker','KProcessHacker','KProcessHacker driver',SERVICE_KERNEL_DRIVER,SERVICE_SYSTEM_START); + StartService('KProcessHacker'); + end; + end; +end; + + +Procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep); +begin + // When uninstalling ask user to delete Process Hacker's logs and settings + // based on whether these files exist only + if CurUninstallStep = usUninstall then begin + if DirExists(ExpandConstant('{localappdata}\wj32\')) + or fileExists(ExpandConstant('{app}\Process Hacker Log.txt')) + or fileExists(ExpandConstant('{userdocs}\Process Hacker.txt')) + or fileExists(ExpandConstant('{userdocs}\Process Hacker.log')) + or fileExists(ExpandConstant('{userdocs}\Process Hacker.csv')) + or fileExists(ExpandConstant('{userdocs}\Process Hacker Log.txt')) + or fileExists(ExpandConstant('{userdocs}\CSR Processes.txt')) + or fileExists(ExpandConstant('{app}\scratchpad.txt'))then begin + if MsgBox(ExpandConstant('{cm:msg_DeleteLogSettings}'), + mbConfirmation, MB_YESNO or MB_DEFBUTTON2) = IDYES then begin + DelTree(ExpandConstant('{localappdata}\wj32\'), True, True, True); + DeleteFile(ExpandConstant('{app}\Process Hacker.txt')); + DeleteFile(ExpandConstant('{app}\Process Hacker.log')); + DeleteFile(ExpandConstant('{app}\Process Hacker.csv')); + DeleteFile(ExpandConstant('{app}\Process Hacker Log.txt')); + DeleteFile(ExpandConstant('{app}\CSR Processes.txt')); + DeleteFile(ExpandConstant('{userdocs}\Process Hacker Log.txt')); + DeleteFile(ExpandConstant('{userdocs}\CSR Processes.txt')); + DeleteFile(ExpandConstant('{app}\scratchpad.txt')); + end; + end; + end; +end; + + +function InitializeSetup(): Boolean; + +// Check if .NET Framework 2.0 is installed and if not offer to download it +var + ErrorCode: Integer; + NetFrameWorkInstalled : Boolean; + Result1 : Boolean; +begin + // Create a mutex for the installer and if it's already running then expose a message and stop installation + if CheckForMutexes(installer_mutex_name) then begin + if not WizardSilent() then + MsgBox(ExpandConstant('{cm:msg_SetupIsRunningWarning}'), mbCriticalError, MB_OK); + Result := False; + end + else begin + CreateMutex(installer_mutex_name); + + NetFrameWorkInstalled := RegKeyExists(HKLM,'SOFTWARE\Microsoft\.NETFramework\policy\v2.0'); + if NetFrameWorkInstalled then begin + Result := True; + end + else begin + Result1 := MsgBox(ExpandConstant('{cm:msg_asknetdown}'), mbCriticalError, MB_YESNO or MB_DEFBUTTON1) = IDYES; + if Result1 = False then begin + Result := False; + end + else begin + Result := False; + ShellExec('open', 'http://download.microsoft.com/download/5/6/7/567758a3-759e-473e-bf8f-52154438565a/dotnetfx.exe', + '','',SW_SHOWNORMAL,ewNoWait,ErrorCode); + end; + end; + end; +end; + + +function InitializeUninstall(): Boolean; +begin + Result := True; + if CheckForMutexes(installer_mutex_name) then begin + if not WizardSilent() then + MsgBox(ExpandConstant('{cm:msg_SetupIsRunningWarning}'), mbCriticalError, MB_OK); + Result := False; + end + else begin + CreateMutex(installer_mutex_name); + + StopService('KProcessHacker'); + RemoveService('KProcessHacker'); + end; +end; diff --git a/branches/ph-plugins/ProcessHacker/Build/Installer/Services.iss b/branches/ph-plugins/ProcessHacker/Build/Installer/Services.iss new file mode 100644 index 000000000..bb4b4ffeb --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Build/Installer/Services.iss @@ -0,0 +1,207 @@ +;* Process Hacker - Various services functions +;* +;* +;* 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 "Custom_Messages.iss" + +[Code] +// Various service related functions +// Source: http://tinyurl.com/ybwjpuq +type + SERVICE_STATUS = record + dwServiceType : cardinal; + dwCurrentState : cardinal; + dwControlsAccepted : cardinal; + dwWin32ExitCode : cardinal; + dwServiceSpecificExitCode : cardinal; + dwCheckPoint : cardinal; + dwWaitHint : cardinal; + end; + HANDLE = cardinal; + +const + SERVICE_QUERY_CONFIG = $1; + SERVICE_CHANGE_CONFIG = $2; + SERVICE_QUERY_STATUS = $4; + SERVICE_START = $10; + SERVICE_STOP = $20; + SERVICE_ALL_ACCESS = $f01ff; + SC_MANAGER_ALL_ACCESS = $f003f; + SERVICE_KERNEL_DRIVER = $1; + SERVICE_WIN32_OWN_PROCESS = $10; + SERVICE_WIN32_SHARE_PROCESS = $20; + SERVICE_WIN32 = $30; + SERVICE_INTERACTIVE_PROCESS = $100; + SERVICE_BOOT_START = $0; + SERVICE_SYSTEM_START = $1; + SERVICE_AUTO_START = $2; + SERVICE_DEMAND_START = $3; + SERVICE_DISABLED = $4; + SERVICE_DELETE = $10000; + SERVICE_CONTROL_STOP = $1; + SERVICE_CONTROL_PAUSE = $2; + SERVICE_CONTROL_CONTINUE = $3; + SERVICE_CONTROL_INTERROGATE = $4; + SERVICE_STOPPED = $1; + SERVICE_START_PENDING = $2; + SERVICE_STOP_PENDING = $3; + SERVICE_RUNNING = $4; + SERVICE_CONTINUE_PENDING = $5; + SERVICE_PAUSE_PENDING = $6; + SERVICE_PAUSED = $7; + +// ####################################################################################### +// nt based service utilities +// ####################################################################################### +function OpenSCManager(lpMachineName, lpDatabaseName: String; dwDesiredAccess :cardinal): HANDLE; +external 'OpenSCManagerA@advapi32.dll stdcall'; + +function OpenService(hSCManager :HANDLE;lpServiceName: String; dwDesiredAccess :cardinal): HANDLE; +external 'OpenServiceA@advapi32.dll stdcall'; + +function CloseServiceHandle(hSCObject :HANDLE): Boolean; +external 'CloseServiceHandle@advapi32.dll stdcall'; + +function CreateService(hSCManager :HANDLE;lpServiceName, lpDisplayName: String;dwDesiredAccess,dwServiceType,dwStartType,dwErrorControl: cardinal;lpBinaryPathName,lpLoadOrderGroup: String; lpdwTagId : cardinal;lpDependencies,lpServiceStartName,lpPassword :String): cardinal; +external 'CreateServiceA@advapi32.dll stdcall'; + +function DeleteService(hService :HANDLE): Boolean; +external 'DeleteService@advapi32.dll stdcall'; + +function StartNTService(hService :HANDLE;dwNumServiceArgs : cardinal;lpServiceArgVectors : cardinal) : Boolean; +external 'StartServiceA@advapi32.dll stdcall'; + +function ControlService(hService :HANDLE; dwControl :cardinal;var ServiceStatus :SERVICE_STATUS) : Boolean; +external 'ControlService@advapi32.dll stdcall'; + +function QueryServiceStatus(hService :HANDLE;var ServiceStatus :SERVICE_STATUS) : Boolean; +external 'QueryServiceStatus@advapi32.dll stdcall'; + +function QueryServiceStatusEx(hService :HANDLE;ServiceStatus :SERVICE_STATUS) : Boolean; +external 'QueryServiceStatus@advapi32.dll stdcall'; + + +function OpenServiceManager() : HANDLE; +begin + if UsingWinNT() = true then begin + Result := OpenSCManager('','ServicesActive',SC_MANAGER_ALL_ACCESS); + if Result = 0 then + MsgBox(ExpandConstant('{cm:msg_servicemanager}'), mbError, MB_OK) + end + else begin + MsgBox(ExpandConstant('{cm:msg_servicemanager2}'), mbError, MB_OK) + Result := 0; + end +end; + + +function InstallService(FileName, ServiceName, DisplayName, Description : String;ServiceType,StartType :cardinal) : Boolean; +var + hSCM : HANDLE; + hService: HANDLE; +begin + hSCM := OpenServiceManager(); + Result := False; + if hSCM <> 0 then begin + hService := CreateService(hSCM,ServiceName,DisplayName,SERVICE_ALL_ACCESS,ServiceType,StartType,0,FileName,'',0,'','',''); + if hService <> 0 then begin + Result := true; + // Win2K & WinXP supports aditional description text for services + if Description<> '' then + RegWriteStringValue(HKLM,'System\CurrentControlSet\Services\' + ServiceName,'Description',Description); + CloseServiceHandle(hService) + end; + CloseServiceHandle(hSCM) + end +end; + + +function RemoveService(ServiceName: String) : Boolean; +var + hSCM : HANDLE; + hService: HANDLE; +begin + hSCM := OpenServiceManager(); + Result := False; + if hSCM <> 0 then begin + hService := OpenService(hSCM,ServiceName,SERVICE_DELETE); + if hService <> 0 then begin + Result := DeleteService(hService); + CloseServiceHandle(hService) + end; + CloseServiceHandle(hSCM) + end +end; + + +function StartService(ServiceName: String) : Boolean; +var + hSCM : HANDLE; + hService: HANDLE; +begin + hSCM := OpenServiceManager(); + Result := False; + if hSCM <> 0 then begin + hService := OpenService(hSCM,ServiceName,SERVICE_START); + if hService <> 0 then begin + Result := StartNTService(hService,0,0); + CloseServiceHandle(hService) + end; + CloseServiceHandle(hSCM) + end; +end; + + +function StopService(ServiceName: String) : Boolean; +var + hSCM : HANDLE; + hService: HANDLE; + Status : SERVICE_STATUS; +begin + hSCM := OpenServiceManager(); + Result := False; + if hSCM <> 0 then begin + hService := OpenService(hSCM,ServiceName,SERVICE_STOP); + if hService <> 0 then begin + Result := ControlService(hService,SERVICE_CONTROL_STOP,Status); + CloseServiceHandle(hService) + end; + CloseServiceHandle(hSCM) + end; +end; + + +function IsServiceRunning(ServiceName: String) : Boolean; +var + hSCM : HANDLE; + hService: HANDLE; + Status : SERVICE_STATUS; +begin + hSCM := OpenServiceManager(); + Result := False; + if hSCM <> 0 then begin + hService := OpenService(hSCM,ServiceName,SERVICE_QUERY_STATUS); + if hService <> 0 then begin + if QueryServiceStatus(hService,Status) then begin + Result :=(Status.dwCurrentState = SERVICE_RUNNING) + end; + CloseServiceHandle(hService) + end; + CloseServiceHandle(hSCM) + end +end; diff --git a/branches/ph-plugins/ProcessHacker/Build/ngen.cmd b/branches/ph-plugins/ProcessHacker/Build/ngen.cmd new file mode 100644 index 000000000..672711e04 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Build/ngen.cmd @@ -0,0 +1 @@ +ngen.exe install ..\bin\Release\ProcessHacker.exe \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Build/release.cmd b/branches/ph-plugins/ProcessHacker/Build/release.cmd new file mode 100644 index 000000000..6874fd393 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Build/release.cmd @@ -0,0 +1,98 @@ +@ECHO OFF +REM Original script by wj32. +REM Modifications and additions by XhmikosR and Yzöwl. +SETLOCAL +SET outd=%~p1 +PUSHD %outd% + +REM Copy various files to the "Release" folder +FOR %%a IN ( + "CHANGELOG.txt" "LICENSE.txt" "README.txt" ^ + "KProcessHacker\i386\kprocesshacker.sys" ^ + "NProcessHacker\Release\NProcessHacker.dll" + ) DO COPY "..\..\..\%%a" >NUL + +REM Copy the 64-bit NPH to the "Release" folder +COPY "..\..\..\NProcessHacker\x64\Release\NProcessHacker.dll"^ + "NProcessHacker64.dll" >NUL + +REM Clear older files present in "Release" folder +DEL/f/a "ProcessHacker.exe.config" "processhacker-*-setup.exe"^ + "Assistant.dll" "processhacker-*.zip" >NUL 2>&1 + +REM Check if ILMerge is present in the default installation location or in PATH +SET ILMergePath="%PROGRAMFILES%\Microsoft\ILMerge\ILMerge.exe" +IF NOT EXIST %ILMergePath% (FOR %%a IN (ILMerge.exe) DO IF %%~$PATH:a' NEQ ' ( + SET ILMergePath="%%~$PATH:a") ELSE (SET "N_=T" + ECHO:ILMerge IS NOT INSTALLED!!!&&(GOTO CLEANUP))) + +SET RequiredDLLs="Aga.Controls.dll" "ProcessHacker.Common.dll"^ + "ProcessHacker.Native.dll" + +REM Create a temporary directory for the merged files +MD tmp >NUL 2>&1 + +REM Merge DLLs with "Assistant.exe" +%ILMergePath% /t:exe /out:"tmp\Assistant.exe" "Assistant.exe"^ + %RequiredDLLs% && ECHO:DLLs merged successfully with Assistant.exe! + +REM Merge DLLs with "ProcessHacker.exe" using ILMerge +%ILMergePath% /t:winexe /out:"tmp\ProcessHacker.exe" "ProcessHacker.exe"^ + %RequiredDLLs% && ECHO:DLLs merged successfully with ProcessHacker.exe! + +REM Delete the existing EXEs and PDBs +DEL ProcessHacker.exe Assistant.exe *.pdb >NUL 2>&1 + +REM Copy the merged files (2 EXEs and 2 PDBs) back into this directory +MOVE tmp\* .\ >NUL 2>&1 + +DEL/f/a %RequiredDLLs% "ProcessHacker.Common.xml"^ + "ProcessHacker.Native.xml" >NUL 2>&1 + +REM Delete the temporary directory +RD tmp >NUL 2>&1 + +REM Detect if we are running on 64bit WIN and use Wow6432Node, set the path +REM of Inno Setup accordingly and compile installer +IF "%PROGRAMFILES(x86)%zzz"=="zzz" (SET "U_=HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" +) ELSE ( +SET "U_=HKLM\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" +) + +SET "I_=Inno Setup" +SET "A_=%I_% 5" +SET "M_=Inno Setup IS NOT INSTALLED!!!" +FOR /f "delims=" %%a IN ( + 'REG QUERY "%U_%\%A_%_is1" /v "%I_%: App Path"2^>Nul^|FIND "REG_"') DO ( + SET "InnoSetupPath=%%a"&Call :Sub %%InnoSetupPath:*Z=%%) + +IF DEFINED InnoSetupPath ("%InnoSetupPath%\iscc.exe" /Q /O"..\..\bin\Release"^ + "..\..\Build\Installer\Process_Hacker_installer.iss"&&( + ECHO:Installer compiled successfully!)) ELSE (ECHO:%M_%) + +REM ZIP the files +IF NOT DEFINED N_ (START "" /B /WAIT "..\..\Build\7za\7za.exe" a -tzip -mx=9^ + "processhacker-bin.zip" "Assistant.exe" "base.txt" "CHANGELOG.txt"^ + "Help.htm" "kprocesshacker.sys" "LICENSE.txt" "NProcessHacker.dll"^ + "NProcessHacker64.dll" "ProcessHacker.exe" "README.txt" "structs.txt"^ + >NUL&&( + ECHO:ZIP created successfully!)) + + +:CLEANUP +REM Copy some PDBs over +FOR %%a IN ( + "KProcessHacker\i386\kprocesshacker.pdb" + "NProcessHacker\Release\NProcessHacker.pdb" + ) DO COPY "..\..\..\%%a" >NUL + +REM Make a PDB zip +"..\..\Build\7za\7za.exe" a -tzip -mx=9 "processhacker-pdb.zip"^ + "*.pdb" >NUL&&(ECHO:PDB ZIP created successfully!) + + +:END +ENDLOCAL && GOTO :EOF + +:Sub +SET InnoSetupPath=%* \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Build/testsign.cmd b/branches/ph-plugins/ProcessHacker/Build/testsign.cmd new file mode 100644 index 000000000..76b43bec3 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Build/testsign.cmd @@ -0,0 +1,3 @@ +signtool sign /a /d "Process Hacker" ..\bin\Release\ProcessHacker.exe +signtool sign /a /d "Process Hacker Assistant" ..\bin\Release\Assistant.exe +signtool sign /a /d "KProcessHacker" ..\bin\Release\kprocesshacker.sys \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Common/Extensions.cs b/branches/ph-plugins/ProcessHacker/Common/Extensions.cs new file mode 100644 index 000000000..7368f0440 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Common/Extensions.cs @@ -0,0 +1,87 @@ +/* + * Process Hacker - + * long extensions + * + * Copyright (C) 2009 Dean + * + * 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 . + */ + +using System; +using System.Collections.Generic; + +namespace ProcessHacker.Common +{ + public static class LongExtensions + { + /// + /// Gets the largest value in the specified array of longs. + /// + /// The source array. + /// The largest value in the specified array. + public static long Max(this IEnumerable source) + { + if (source == null) + throw new ArgumentNullException("source"); + + long max = 0; + bool afterFirst = false; + + foreach (long number in source) + { + if (afterFirst) + { + if (number > max) + max = number; + } + else + { + max = number; + afterFirst = true; + } + } + + return max; + } + + /// + /// Takes a number of elements from the specified array. + /// + /// The list to process. + /// The number of elements to take. + /// + /// A new list containing the first + /// elements from the specified array. + /// + public static IList Take(this IList source, int count) + { + if (source == null) + throw new ArgumentNullException("source"); + + // If we're trying to take more than we have, return the original set. + if (count >= source.Count) + return source; + + // Create a new list containing the elements. + IList newList = new List(); + + for (int i = 0; i < count; i++) + newList.Add(source[i]); + + return newList; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Common/PhUtils.cs b/branches/ph-plugins/ProcessHacker/Common/PhUtils.cs new file mode 100644 index 000000000..2d4e8c9f0 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Common/PhUtils.cs @@ -0,0 +1,528 @@ +/* + * Process Hacker - + * misc. functions + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Net; +using System.Windows.Forms; +using Aga.Controls.Tree; +using ProcessHacker.Components; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.UI; + +namespace ProcessHacker.Common +{ + public static class PhUtils + { + public static string[] DangerousNames = + { + "csrss.exe", "dwm.exe", "logonui.exe", "lsass.exe", "lsm.exe", "services.exe", + "smss.exe", "wininit.exe", "winlogon.exe" + }; + + /// + /// Adds Ctrl+C and Ctrl+A shortcuts to the specified ListView. + /// + /// The ListView to modify. + public static void AddShortcuts(this ListView lv) + { + lv.AddShortcuts(null); + } + + /// + /// Adds Ctrl+C and Ctrl+A shortcuts to the specified ListView. + /// + /// The ListView to modify. + /// A virtual item handler, if any. + public static void AddShortcuts(this ListView lv, RetrieveVirtualItemEventHandler retrieveVirtualItem) + { + lv.KeyDown += + (sender, e) => + { + if (e.Control && e.KeyCode == Keys.A) + { + if (retrieveVirtualItem != null) + { + for (int i = 0; i < lv.VirtualListSize; i++) + if (!lv.SelectedIndices.Contains(i)) + lv.SelectedIndices.Add(i); + } + else + { + lv.Items.SelectAll(); + } + } + + if (e.Control && e.KeyCode == Keys.C) + { + GenericViewMenu.ListViewCopy(lv, -1, retrieveVirtualItem); + } + }; + } + + /// + /// Gets whether the specified process is a system process. + /// + /// The PID of a process to check. + /// Whether the process is a system process. + public static bool IsDangerousPid(int pid) + { + if (pid == 4) + return true; + + try + { + using (var phandle = new ProcessHandle(pid, OSVersion.MinProcessQueryInfoAccess)) + { + foreach (string s in DangerousNames) + { + if ((Environment.SystemDirectory + "\\" + s).Equals( + FileUtils.GetFileName(FileUtils.GetFileName(phandle.GetImageFileName())), + StringComparison.InvariantCultureIgnoreCase)) + { + return true; + } + } + } + } + catch + { } + + return false; + } + + /// + /// Formats an error message. + /// + /// + /// The operation being performed, e.g. "Unable to X" + /// + /// The exception to use. + /// A formatted error message. + private static string FormatException(string operation, Exception ex) + { + if (!string.IsNullOrEmpty(operation)) + return operation + ": " + ex.Message; + else + return ex.Message; + } + + public static string FormatPriorityClass(ProcessPriorityClass priorityClass) + { + switch (priorityClass) + { + case ProcessPriorityClass.AboveNormal: + return "Above Normal"; + case ProcessPriorityClass.BelowNormal: + return "Below Normal"; + case ProcessPriorityClass.High: + return "High"; + case ProcessPriorityClass.Idle: + return "Idle"; + case ProcessPriorityClass.Normal: + return "Normal"; + case ProcessPriorityClass.RealTime: + return "Realtime"; + case ProcessPriorityClass.Unknown: + default: + return ""; + } + } + + /// + /// Gets an appropriate foreground color to be displayed on top of a + /// specified background color. + /// + /// The background color. + /// + /// Black if the background color's brightness is above 0.4, otherwise + /// White. + /// + public static Color GetForeColor(Color backColor) + { + if (backColor.GetBrightness() > 0.4) + return Color.Black; + else + return Color.White; + } + + public static string GetIntegrity(this TokenHandle tokenHandle, out int integrityLevel) + { + var groups = tokenHandle.GetGroups(); + string integrity = null; + + integrityLevel = 0; + + for (int i = 0; i < groups.Length; i++) + { + if ((groups[i].Attributes & SidAttributes.IntegrityEnabled) != 0) + { + integrity = groups[i].GetFullName(false).Replace(" Mandatory Level", ""); + + if (integrity == "Untrusted") + integrityLevel = 0; + else if (integrity == "Low") + integrityLevel = 1; + else if (integrity == "Medium") + integrityLevel = 2; + else if (integrity == "High") + integrityLevel = 3; + else if (integrity == "System") + integrityLevel = 4; + else if (integrity == "Installer") + integrityLevel = 5; + } + + groups[i].Dispose(); + } + + return integrity; + } + + public static bool IsEmpty(this IPEndPoint endPoint) + { + return endPoint.Address.GetAddressBytes().IsEmpty() && endPoint.Port == 0; + } + + public static void IsNetworkError(string url) + { + if (OSVersion.IsAboveOrEqual(WindowsVersion.Vista)) + { + IntPtr ndfhandle = IntPtr.Zero; + + HResult ndfCreate = Win32.NdfCreateWebIncident(url, ref ndfhandle); + ndfCreate.ThrowIf(); + + Win32.NdfExecuteDiagnosis(ndfhandle, IntPtr.Zero); //Will throw error if user cancels + Win32.NdfCloseIncident(ndfhandle); + } + } + + public static void IsNetworkError(string url, IntPtr hwnd) + { + if (OSVersion.IsAboveOrEqual(WindowsVersion.Vista)) + { + IntPtr ndfhandle = IntPtr.Zero; + + HResult ndfCreate = Win32.NdfCreateWebIncident(url, ref ndfhandle); + ndfCreate.ThrowIf(); + + Win32.NdfExecuteDiagnosis(ndfhandle, hwnd); //Will throw error if user cancels + Win32.NdfCloseIncident(ndfhandle); + } + } + + /// + /// Checks if a connection to the URL can be established. + /// + /// URL Address to check + /// true if established + public static bool IsInternetAddressReachable(string url) + { + return Win32.InternetCheckConnection(url, 1, 0); + } + + /// + /// Fast method of checking a connection to the Internet can be established. + /// + /// True if connected + public static bool IsInternetConnected + { + get + { + try + { + System.Net.IPHostEntry entry = System.Net.Dns.GetHostEntry("www.msftncsi.com"); + return true; + + //http://www.msftncsi.com/ncsi.txt + //Vista/Win7 Internet Connectivity test address, + //Every Vista/Win7 machine uses this for checking Internet Connectivity. + //Probably the most reliable internet address... + //More Info: http://technet.microsoft.com/en-us/library/cc766017%28WS.10%29.aspx + } + catch + { return false; } + } + } + + /// + /// Reliable but slower method of checking if a connection to the Internet can be established. + /// + /// True if connected + public static bool IsInternetConnectedEx + { + get { return Win32.InternetCheckConnection("http://www.msftncsi.com", 1, 0); } + } + + /// + /// Opens a registry key in the Registry Editor. + /// + /// + /// The path to the registry key, in either abbreviated (HKCU, HKLM, etc.) + /// or full (HKEY_CURRENT_USER, etc.) format. + /// + public static void OpenKeyInRegedit(string keyName) + { + OpenKeyInRegedit(null, keyName); + } + + /// + /// Opens a registry key in the Registry Editor. + /// + /// + /// The window in which the elevation dialog, if any, should be centered. + /// + /// + /// The path to the registry key, in either abbreviated (HKCU, HKLM, etc.) + /// or full (HKEY_CURRENT_USER, etc.) format. + /// + public static void OpenKeyInRegedit(IWin32Window window, string keyName) + { + string lastKey = keyName; + + // Expand the abbreviations. + if (lastKey.ToLowerInvariant().StartsWith("hkcu")) + lastKey = "HKEY_CURRENT_USER" + lastKey.Substring(4); + else if (lastKey.ToLowerInvariant().StartsWith("hku")) + lastKey = "HKEY_USERS" + lastKey.Substring(3); + else if (lastKey.ToLowerInvariant().StartsWith("hkcr")) + lastKey = "HKEY_CLASSES_ROOT" + lastKey.Substring(4); + else if (lastKey.ToLowerInvariant().StartsWith("hklm")) + lastKey = "HKEY_LOCAL_MACHINE" + lastKey.Substring(4); + + // Set the last opened key in regedit config. Note that if we are on + // Vista, we need to append "Computer\" to the beginning. + using (var regeditKey = + Microsoft.Win32.Registry.CurrentUser.CreateSubKey( + @"Software\Microsoft\Windows\CurrentVersion\Applets\Regedit", + Microsoft.Win32.RegistryKeyPermissionCheck.ReadWriteSubTree + )) + { + if (OSVersion.IsAboveOrEqual(WindowsVersion.Vista)) + regeditKey.SetValue("LastKey", "Computer\\" + lastKey); + else + regeditKey.SetValue("LastKey", lastKey); + } + + // If we have UAC and we aren't elevated, request that regedit be elevated + // and pass the window handle. This is so that we get the elevation + // dialog in the center of the specified window because it looks nice. + // Also, this makes sure we don't throw an exception if the user denies + // elevation. + if (OSVersion.HasUac && Program.ElevationType == TokenElevationType.Limited) + { + Program.StartProgramAdmin( + Environment.SystemDirectory + "\\..\\regedit.exe", + "", + null, + ShowWindowType.Normal, + window != null ? window.Handle : IntPtr.Zero + ); + } + else + { + System.Diagnostics.Process.Start(Environment.SystemDirectory + "\\..\\regedit.exe"); + } + } + + /// + /// Selects all of the specified nodes. + /// + /// The nodes. + public static void SelectAll(this IEnumerable nodes) + { + foreach (TreeNodeAdv node in nodes) + node.IsSelected = true; + } + + /// + /// Controls whether the UAC shield icon is displayed on the specified button. + /// + /// The button to modify. + /// Whether to show the UAC shield icon. + private static void SetShieldIconInternal(Button button, bool show) + { + Win32.SendMessage(button.Handle, + WindowMessage.BcmSetShield, 0, show ? 1 : 0); + } + + /// + /// Controls whether the UAC shield icon is displayed on the button. + /// + /// Whether the shield icon is visible. + public static void SetShieldIcon(this Button button, bool visible) + { + SetShieldIconInternal(button, visible); + } + + /// + /// Sets the theme of a control. + /// + /// The control to modify. + /// A name of a theme. + public static void SetTheme(this Control control, string theme) + { + Win32.SetWindowTheme(control.Handle, theme, null); + } + + /// + /// Asks if the user wants to perform an action. + /// + /// + /// The action to be performed, e.g. "Terminate" + /// + /// + /// The object for the action to be performed on, e.g. "the selected process" + /// + /// + /// Additional information to show to the user, e.g. "Terminating a process will ..." + /// + /// Whether the message is a warning. + /// Whether the user wants to continue with the operation. + public static bool ShowConfirmMessage(string verb, string obj, string message, bool warning) + { + // Make the sure the verb is all lowercase. + verb = verb.ToLower(); + + // "terminate" -> "Terminate" + string verbCaps = char.ToUpper(verb[0]) + verb.Substring(1); + // "terminate", "the process" -> "terminate the process" + string action = verb + " " + obj; + + // Example: + // __________________________________________________ + // | Process Hacker _ O x| + // | | + // | /\ Do you want to terminate the process? | + // | /||\ | + // | /_||_\ Terminating a process may result in...| + // | Are you sure you want to continue? | + // | | + // | | Terminate | | Cancel | | + // |_________________________________________________| + + if (OSVersion.HasTaskDialogs) + { + TaskDialog td = new TaskDialog(); + + td.WindowTitle = "Process Hacker"; + td.MainIcon = warning ? TaskDialogIcon.Warning : TaskDialogIcon.None; + td.MainInstruction = "Do you want to " + action + "?"; + + if (!string.IsNullOrEmpty(message)) + td.Content = message + " Are you sure you want to continue?"; + + td.Buttons = new TaskDialogButton[] + { + new TaskDialogButton((int)DialogResult.Yes, verbCaps), + new TaskDialogButton((int)DialogResult.No, "Cancel") + }; + td.DefaultButton = (int)DialogResult.No; + + return td.Show(Form.ActiveForm) == (int)DialogResult.Yes; + } + else + { + return MessageBox.Show( + message + " Are you sure you want to " + action + "?", + "Process Hacker", + MessageBoxButtons.YesNo, + MessageBoxIcon.Warning + ) == DialogResult.Yes; + } + } + + /// + /// Notifies the user of an error and asks whether the operation should + /// continue. + /// + /// + /// The operation being performed, e.g. "Unable to X" + /// + /// The exception to notify the user of. + /// + /// True if the user wants to continue the operation, otherwise false. + /// + public static bool ShowContinueMessage(string operation, Exception ex) + { + return MessageBox.Show( + FormatException(operation, ex), + "Process Hacker", + MessageBoxButtons.OKCancel, + MessageBoxIcon.Error + ) == DialogResult.OK; + } + + /// + /// Displays an error message to the user. + /// + /// The message to show. + public static void ShowError(string message) + { + MessageBox.Show(Form.ActiveForm, message, "Process Hacker", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + + /// + /// Notifies the user of an error. + /// + /// + /// The operation being performed, e.g. "Unable to X" + /// + /// The exception to notify the user of. + public static void ShowException(string operation, Exception ex) + { +#if !DEBUG + MessageBox.Show(Form.ActiveForm, FormatException(operation, ex), "Process Hacker", MessageBoxButtons.OK, MessageBoxIcon.Error); +#else + MessageBox.Show( + Form.ActiveForm, + operation + "\n\n" + ex.ToString(), + "Process Hacker", + MessageBoxButtons.OK, + MessageBoxIcon.Error + ); +#endif + } + + /// + /// Displays information to the user. + /// + /// The message to show. + public static void ShowInformation(string message) + { + MessageBox.Show(Form.ActiveForm, message, "Process Hacker", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + + /// + /// Displays a warning to the user. + /// + /// The message to show. + public static void ShowWarning(string message) + { + MessageBox.Show(Form.ActiveForm, message, "Process Hacker", MessageBoxButtons.OK, MessageBoxIcon.Warning); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/ByteCollection.cs b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/ByteCollection.cs new file mode 100644 index 000000000..5a828b20a --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/ByteCollection.cs @@ -0,0 +1,128 @@ +using System; + +using System.Collections; + +namespace Be.Windows.Forms +{ + /// + /// Represents a collection of bytes. + /// + public class ByteCollection : CollectionBase + { + /// + /// Initializes a new instance of ByteCollection class. + /// + public ByteCollection() + {} + + /// + /// Initializes a new instance of ByteCollection class. + /// + /// an array of bytes to add to collection + public ByteCollection(byte[] bs) + { AddRange(bs); } + + /// + /// Gets or sets the value of a byte + /// + public byte this[int index] + { + get { return (byte)List[index]; } + set { List[index] = value; } + } + + /// + /// Adds a byte into the collection. + /// + /// the byte to add + public void Add(byte b) + { List.Add(b); } + + /// + /// Adds a range of bytes to the collection. + /// + /// the bytes to add + public void AddRange(byte[] bs) + { InnerList.AddRange(bs); } + + /// + /// Removes a byte from the collection. + /// + /// the byte to remove + public void Remove(byte b) + { List.Remove(b); } + + /// + /// Removes a range of bytes from the collection. + /// + /// the index of the start byte + /// the count of the bytes to remove + public void RemoveRange(int index, int count) + { InnerList.RemoveRange(index, count); } + + /// + /// Inserts a range of bytes to the collection. + /// + /// the index of start byte + /// an array of bytes to insert + public void InsertRange(int index, byte[] bs) + { InnerList.InsertRange(index, bs); } + + /// + /// Gets all bytes in the array + /// + /// an array of bytes. + public byte[] GetBytes() + { + byte[] bytes = new byte[Count]; + InnerList.CopyTo(0, bytes, 0, bytes.Length); + return bytes; + } + + /// + /// Inserts a byte to the collection. + /// + /// the index + /// a byte to insert + public void Insert(int index, byte b) + { + InnerList.Insert(index, b); + } + + /// + /// Returns the index of the given byte. + /// + public int IndexOf(byte b) + { + return InnerList.IndexOf(b); + } + + /// + /// Returns true, if the byte exists in the collection. + /// + public bool Contains(bool b) + { + return InnerList.Contains(b); + } + + /// + /// Copies the content of the collection into the given array. + /// + public void CopyTo(byte[] bs, int index) + { + InnerList.CopyTo(bs, index); + } + + /// + /// Copies the content of the collection into an array. + /// + /// the array containing all bytes. + public byte[] ToArray() + { + byte[] data = new byte[this.Count]; + this.CopyTo(data, 0); + return data; + } + + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/DataBlock.cs b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/DataBlock.cs new file mode 100644 index 000000000..8b181c680 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/DataBlock.cs @@ -0,0 +1,42 @@ +using System; + +namespace Be.Windows.Forms +{ + internal abstract class DataBlock + { + internal DataMap _map; + internal DataBlock _nextBlock; + internal DataBlock _previousBlock; + + public abstract long Length + { + get; + } + + public DataMap Map + { + get + { + return _map; + } + } + + public DataBlock NextBlock + { + get + { + return _nextBlock; + } + } + + public DataBlock PreviousBlock + { + get + { + return _previousBlock; + } + } + + public abstract void RemoveBytes(long position, long count); + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/DataMap.cs b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/DataMap.cs new file mode 100644 index 000000000..f8fbccfcd --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/DataMap.cs @@ -0,0 +1,318 @@ +using System; +using System.Collections; +using System.Text; + +namespace Be.Windows.Forms +{ + internal class DataMap : ICollection, IEnumerable + { + readonly object _syncRoot = new object(); + internal int _count; + internal DataBlock _firstBlock; + internal int _version; + + public DataMap() + { + } + + public DataMap(IEnumerable collection) + { + if (collection == null) + { + throw new ArgumentNullException("collection"); + } + + foreach (DataBlock item in collection) + { + AddLast(item); + } + } + + public DataBlock FirstBlock + { + get + { + return _firstBlock; + } + } + + public void AddAfter(DataBlock block, DataBlock newBlock) + { + AddAfterInternal(block, newBlock); + } + + public void AddBefore(DataBlock block, DataBlock newBlock) + { + AddBeforeInternal(block, newBlock); + } + + public void AddFirst(DataBlock block) + { + if (_firstBlock == null) + { + AddBlockToEmptyMap(block); + } + else + { + AddBeforeInternal(_firstBlock, block); + } + } + + public void AddLast(DataBlock block) + { + if (_firstBlock == null) + { + AddBlockToEmptyMap(block); + } + else + { + AddAfterInternal(GetLastBlock(), block); + } + } + + public void Remove(DataBlock block) + { + RemoveInternal(block); + } + + public void RemoveFirst() + { + if (_firstBlock == null) + { + throw new InvalidOperationException("The collection is empty."); + } + RemoveInternal(_firstBlock); + } + + public void RemoveLast() + { + if (_firstBlock == null) + { + throw new InvalidOperationException("The collection is empty."); + } + RemoveInternal(GetLastBlock()); + } + + public DataBlock Replace(DataBlock block, DataBlock newBlock) + { + AddAfterInternal(block, newBlock); + RemoveInternal(block); + return newBlock; + } + + public void Clear() + { + DataBlock block = FirstBlock; + while (block != null) + { + DataBlock nextBlock = block.NextBlock; + InvalidateBlock(block); + block = nextBlock; + } + _firstBlock = null; + _count = 0; + _version++; + } + + void AddAfterInternal(DataBlock block, DataBlock newBlock) + { + newBlock._previousBlock = block; + newBlock._nextBlock = block._nextBlock; + newBlock._map = this; + + if (block._nextBlock != null) + { + block._nextBlock._previousBlock = newBlock; + } + block._nextBlock = newBlock; + + this._version++; + this._count++; + } + + void AddBeforeInternal(DataBlock block, DataBlock newBlock) + { + newBlock._nextBlock = block; + newBlock._previousBlock = block._previousBlock; + newBlock._map = this; + + if (block._previousBlock != null) + { + block._previousBlock._nextBlock = newBlock; + } + block._previousBlock = newBlock; + + if (_firstBlock == block) + { + _firstBlock = newBlock; + } + this._version++; + this._count++; + } + + void RemoveInternal(DataBlock block) + { + DataBlock previousBlock = block._previousBlock; + DataBlock nextBlock = block._nextBlock; + + if (previousBlock != null) + { + previousBlock._nextBlock = nextBlock; + } + + if (nextBlock != null) + { + nextBlock._previousBlock = previousBlock; + } + + if (_firstBlock == block) + { + _firstBlock = nextBlock; + } + + InvalidateBlock(block); + + _count--; + _version++; + } + + DataBlock GetLastBlock() + { + DataBlock lastBlock = null; + for (DataBlock block = FirstBlock; block != null; block = block.NextBlock) + { + lastBlock = block; + } + return lastBlock; + } + + void InvalidateBlock(DataBlock block) + { + block._map = null; + block._nextBlock = null; + block._previousBlock = null; + } + + void AddBlockToEmptyMap(DataBlock block) + { + block._map = this; + block._nextBlock = null; + block._previousBlock = null; + + _firstBlock = block; + _version++; + _count++; + } + + #region ICollection Members + public void CopyTo(Array array, int index) + { + DataBlock[] blockArray = array as DataBlock[]; + for (DataBlock block = FirstBlock; block != null; block = block.NextBlock) + { + blockArray[index++] = block; + } + } + + public int Count + { + get + { + return _count; + } + } + + public bool IsSynchronized + { + get + { + return false; + } + } + + public object SyncRoot + { + get + { + return _syncRoot; + } + } + #endregion + + #region IEnumerable Members + public IEnumerator GetEnumerator() + { + return new Enumerator(this); + } + #endregion + + #region Enumerator Nested Type + internal class Enumerator : IEnumerator, IDisposable + { + DataMap _map; + DataBlock _current; + int _index; + int _version; + + internal Enumerator(DataMap map) + { + _map = map; + _version = map._version; + _current = null; + _index = -1; + } + + object IEnumerator.Current + { + get + { + if (_index < 0 || _index > _map.Count) + { + throw new InvalidOperationException("Enumerator is positioned before the first element or after the last element of the collection."); + } + return _current; + } + } + + public bool MoveNext() + { + if (this._version != _map._version) + { + throw new InvalidOperationException("Collection was modified after the enumerator was instantiated."); + } + + if (_index >= _map.Count) + { + return false; + } + + if (++_index == 0) + { + _current = _map.FirstBlock; + } + else + { + _current = _current.NextBlock; + } + + return (_index < _map.Count); + } + + void IEnumerator.Reset() + { + if (this._version != this._map._version) + { + throw new InvalidOperationException("Collection was modified after the enumerator was instantiated."); + } + + this._index = -1; + this._current = null; + } + + public void Dispose() + { + } + } + #endregion + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/Design/HexFontEditor.cs b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/Design/HexFontEditor.cs new file mode 100644 index 000000000..e7bba5675 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/Design/HexFontEditor.cs @@ -0,0 +1,70 @@ +using System; +using System.Drawing; +using System.Drawing.Design; +using System.Windows.Forms; +using System.Windows.Forms.Design; + +namespace Be.Windows.Forms.Design +{ + /// + /// Display only fixed-piched fonts + /// + internal class HexFontEditor : FontEditor + { + object value; + + /// + /// Initializes an instance of HexFontEditor class. + /// + public HexFontEditor() + { + } + + /// + /// Edits the value + /// + public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, IServiceProvider provider, object value) + { + this.value = value; + if (provider != null) + { + IWindowsFormsEditorService service1 = (IWindowsFormsEditorService) provider.GetService(typeof(IWindowsFormsEditorService)); + if (service1 != null) + { + FontDialog fontDialog = new FontDialog(); + fontDialog.ShowApply = false; + fontDialog.ShowColor = false; + fontDialog.AllowVerticalFonts = false; + fontDialog.AllowScriptChange = false; + fontDialog.FixedPitchOnly = true; + fontDialog.ShowEffects = false; + fontDialog.ShowHelp = false; + + Font font = value as Font; + if(font != null) + { + fontDialog.Font = font; + } + if (fontDialog.ShowDialog() == DialogResult.OK) + { + this.value = fontDialog.Font; + } + + fontDialog.Dispose(); + } + } + + value = this.value; + this.value = null; + return value; + + } + + public override UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context) + { + return UITypeEditorEditStyle.Modal; + } + + + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/DynamicByteProvider.cs b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/DynamicByteProvider.cs new file mode 100644 index 000000000..7d09177c0 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/DynamicByteProvider.cs @@ -0,0 +1,175 @@ +using System; + +namespace Be.Windows.Forms +{ + /// + /// Byte provider for a small amount of data. + /// + public class DynamicByteProvider : IByteProvider + { + /// + /// Contains information about changes. + /// + bool _hasChanges; + /// + /// Contains a byte collection. + /// + ByteCollection _bytes; + + /// + /// Initializes a new instance of the DynamicByteProvider class. + /// + /// + public DynamicByteProvider(byte[] data) : this(new ByteCollection(data)) + { + } + + /// + /// Initializes a new instance of the DynamicByteProvider class. + /// + /// + public DynamicByteProvider(ByteCollection bytes) + { + _bytes = bytes; + } + + /// + /// Raises the Changed event. + /// + void OnChanged(EventArgs e) + { + _hasChanges = true; + + if(Changed != null) + Changed(this, e); + } + + /// + /// Raises the LengthChanged event. + /// + void OnLengthChanged(EventArgs e) + { + if(LengthChanged != null) + LengthChanged(this, e); + } + + /// + /// Gets the byte collection. + /// + public ByteCollection Bytes + { + get { return _bytes; } + } + + #region IByteProvider Members + /// + /// True, when changes are done. + /// + public bool HasChanges() + { + return _hasChanges; + } + + /// + /// Applies changes. + /// + public void ApplyChanges() + { + _hasChanges = false; + } + + /// + /// Occurs, when the write buffer contains new changes. + /// + public event EventHandler Changed; + + /// + /// Occurs, when InsertBytes or DeleteBytes method is called. + /// + public event EventHandler LengthChanged; + + + /// + /// Reads a byte from the byte collection. + /// + /// the index of the byte to read + /// the byte + public byte ReadByte(long index) + { return _bytes[(int)index]; } + + /// + /// Write a byte into the byte collection. + /// + /// the index of the byte to write. + /// the byte + public void WriteByte(long index, byte value) + { + _bytes[(int)index] = value; + OnChanged(EventArgs.Empty); + } + + /// + /// Deletes bytes from the byte collection. + /// + /// the start index of the bytes to delete. + /// the length of bytes to delete. + public void DeleteBytes(long index, long length) + { + int internal_index = (int)Math.Max(0, index); + int internal_length = (int)Math.Min((int)Length, length); + _bytes.RemoveRange(internal_index, internal_length); + + OnLengthChanged(EventArgs.Empty); + OnChanged(EventArgs.Empty); + } + + /// + /// Inserts byte into the byte collection. + /// + /// the start index of the bytes in the byte collection + /// the byte array to insert + public void InsertBytes(long index, byte[] bs) + { + _bytes.InsertRange((int)index, bs); + + OnLengthChanged(EventArgs.Empty); + OnChanged(EventArgs.Empty); + } + + /// + /// Gets the length of the bytes in the byte collection. + /// + public long Length + { + get + { + return _bytes.Count; + } + } + + /// + /// Returns true + /// + public bool SupportsWriteByte() + { + return true; + } + + /// + /// Returns true + /// + public bool SupportsInsertBytes() + { + return true; + } + + /// + /// Returns true + /// + public bool SupportsDeleteBytes() + { + return true; + } + #endregion + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/DynamicFileByteProvider.cs b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/DynamicFileByteProvider.cs new file mode 100644 index 000000000..f8d763e88 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/DynamicFileByteProvider.cs @@ -0,0 +1,548 @@ +using System; +using System.Text; +using System.IO; + +namespace Be.Windows.Forms +{ + /// + /// Implements a fully editable byte provider for file data of any size. + /// + /// + /// Only changes to the file are stored in memory with reads from the + /// original data occurring as required. + /// + public sealed class DynamicFileByteProvider : IByteProvider, IDisposable + { + const int COPY_BLOCK_SIZE = 4096; + + string _fileName; + FileStream _fileStream; + DataMap _dataMap; + long _totalLength; + bool _readOnly; + + /// + /// Constructs a new instance. + /// + /// The name of the file from which bytes should be provided. + public DynamicFileByteProvider(string fileName) : this(fileName, false) + {} + + /// + /// Constructs a new instance. + /// + /// The name of the file from which bytes should be provided. + public DynamicFileByteProvider(string fileName, bool readOnly) + { + _fileName = fileName; + + if (!readOnly) + { + _fileStream = File.Open(fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.Read); + } + else + { + _fileStream = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + } + + _readOnly = readOnly; + + ReInitialize(); + } + + #region IByteProvider Members + /// + /// See for more information. + /// + public event EventHandler LengthChanged; + + /// + /// See for more information. + /// + public event EventHandler Changed; + + /// + /// See for more information. + /// + public byte ReadByte(long index) + { + long blockOffset; + DataBlock block = GetDataBlock(index, out blockOffset); + FileDataBlock fileBlock = block as FileDataBlock; + if (fileBlock != null) + { + return ReadByteFromFile(fileBlock.FileOffset + index - blockOffset); + } + else + { + MemoryDataBlock memoryBlock = (MemoryDataBlock)block; + return memoryBlock.Data[index - blockOffset]; + } + } + + /// + /// See for more information. + /// + public void WriteByte(long index, byte value) + { + try + { + // Find the block affected. + long blockOffset; + DataBlock block = GetDataBlock(index, out blockOffset); + + // If the byte is already in a memory block, modify it. + MemoryDataBlock memoryBlock = block as MemoryDataBlock; + if (memoryBlock != null) + { + memoryBlock.Data[index - blockOffset] = value; + return; + } + + FileDataBlock fileBlock = (FileDataBlock)block; + + // If the byte changing is the first byte in the block and the previous block is a memory block, extend that. + if (blockOffset == index && block.PreviousBlock != null) + { + MemoryDataBlock previousMemoryBlock = block.PreviousBlock as MemoryDataBlock; + if (previousMemoryBlock != null) + { + previousMemoryBlock.AddByteToEnd(value); + fileBlock.RemoveBytesFromStart(1); + if (fileBlock.Length == 0) + { + _dataMap.Remove(fileBlock); + } + return; + } + } + + // If the byte changing is the last byte in the block and the next block is a memory block, extend that. + if (blockOffset + fileBlock.Length - 1 == index && block.NextBlock != null) + { + MemoryDataBlock nextMemoryBlock = block.NextBlock as MemoryDataBlock; + if (nextMemoryBlock != null) + { + nextMemoryBlock.AddByteToStart(value); + fileBlock.RemoveBytesFromEnd(1); + if (fileBlock.Length == 0) + { + _dataMap.Remove(fileBlock); + } + return; + } + } + + // Split the block into a prefix and a suffix and place a memory block in-between. + FileDataBlock prefixBlock = null; + if (index > blockOffset) + { + prefixBlock = new FileDataBlock(fileBlock.FileOffset, index - blockOffset); + } + + FileDataBlock suffixBlock = null; + if (index < blockOffset + fileBlock.Length - 1) + { + suffixBlock = new FileDataBlock( + fileBlock.FileOffset + index - blockOffset + 1, + fileBlock.Length - (index - blockOffset + 1)); + } + + block = _dataMap.Replace(block, new MemoryDataBlock(value)); + + if (prefixBlock != null) + { + _dataMap.AddBefore(block, prefixBlock); + } + + if (suffixBlock != null) + { + _dataMap.AddAfter(block, suffixBlock); + } + } + finally + { + OnChanged(EventArgs.Empty); + } + } + + /// + /// See for more information. + /// + public void InsertBytes(long index, byte[] bs) + { + try + { + // Find the block affected. + long blockOffset; + DataBlock block = GetDataBlock(index, out blockOffset); + + // If the insertion point is in a memory block, just insert it. + MemoryDataBlock memoryBlock = block as MemoryDataBlock; + if (memoryBlock != null) + { + memoryBlock.InsertBytes(index - blockOffset, bs); + return; + } + + FileDataBlock fileBlock = (FileDataBlock)block; + + // If the insertion point is at the start of a file block, and the previous block is a memory block, append it to that block. + if (blockOffset == index && block.PreviousBlock != null) + { + MemoryDataBlock previousMemoryBlock = block.PreviousBlock as MemoryDataBlock; + if (previousMemoryBlock != null) + { + previousMemoryBlock.InsertBytes(previousMemoryBlock.Length, bs); + return; + } + } + + // Split the block into a prefix and a suffix and place a memory block in-between. + FileDataBlock prefixBlock = null; + if (index > blockOffset) + { + prefixBlock = new FileDataBlock(fileBlock.FileOffset, index - blockOffset); + } + + FileDataBlock suffixBlock = null; + if (index < blockOffset + fileBlock.Length) + { + suffixBlock = new FileDataBlock( + fileBlock.FileOffset + index - blockOffset, + fileBlock.Length - (index - blockOffset)); + } + + block = _dataMap.Replace(block, new MemoryDataBlock(bs)); + + if (prefixBlock != null) + { + _dataMap.AddBefore(block, prefixBlock); + } + + if (suffixBlock != null) + { + _dataMap.AddAfter(block, suffixBlock); + } + } + finally + { + _totalLength += bs.Length; + OnLengthChanged(EventArgs.Empty); + OnChanged(EventArgs.Empty); + } + } + + /// + /// See for more information. + /// + public void DeleteBytes(long index, long length) + { + try + { + long bytesToDelete = length; + + // Find the first block affected. + long blockOffset; + DataBlock block = GetDataBlock(index, out blockOffset); + + // Truncate or remove each block as necessary. + while (bytesToDelete > 0) + { + long blockLength = block.Length; + DataBlock nextBlock = block.NextBlock; + + // Delete the appropriate section from the block (this may result in two blocks or a zero length block). + long count = Math.Min(bytesToDelete, blockLength - (index - blockOffset)); + block.RemoveBytes(index - blockOffset, count); + + if (block.Length == 0) + { + _dataMap.Remove(block); + if (_dataMap.FirstBlock == null) + { + _dataMap.AddFirst(new MemoryDataBlock(new byte[0])); + } + } + + bytesToDelete -= count; + blockOffset += block.Length; + block = (bytesToDelete > 0) ? nextBlock : null; + } + } + finally + { + _totalLength -= length; + OnLengthChanged(EventArgs.Empty); + OnChanged(EventArgs.Empty); + } + } + + /// + /// See for more information. + /// + public long Length + { + get + { + return _totalLength; + } + } + + /// + /// See for more information. + /// + public bool HasChanges() + { + if (_readOnly) + return false; + + if (_totalLength != _fileStream.Length) + { + return true; + } + + long offset = 0; + for (DataBlock block = _dataMap.FirstBlock; block != null; block = block.NextBlock) + { + FileDataBlock fileBlock = block as FileDataBlock; + if (fileBlock == null) + { + return true; + } + + if (fileBlock.FileOffset != offset) + { + return true; + } + + offset += fileBlock.Length; + } + return (offset != _fileStream.Length); + } + + /// + /// See for more information. + /// + public void ApplyChanges() + { + if (_readOnly) + throw new OperationCanceledException("File is in read-only mode"); + + // This method is implemented to efficiently save the changes to the same file stream opened for reading. + // Saving to a separate file would be a much simpler implementation. + + // Firstly, extend the file length (if necessary) to ensure that there is enough disk space. + if (_totalLength > _fileStream.Length) + { + _fileStream.SetLength(_totalLength); + } + + // Secondly, shift around any file sections that have moved. + long dataOffset = 0; + for (DataBlock block = _dataMap.FirstBlock; block != null; block = block.NextBlock) + { + FileDataBlock fileBlock = block as FileDataBlock; + if (fileBlock != null && fileBlock.FileOffset != dataOffset) + { + MoveFileBlock(fileBlock, dataOffset); + } + dataOffset += block.Length; + } + + // Next, write in-memory changes. + dataOffset = 0; + for (DataBlock block = _dataMap.FirstBlock; block != null; block = block.NextBlock) + { + MemoryDataBlock memoryBlock = block as MemoryDataBlock; + if (memoryBlock != null) + { + _fileStream.Position = dataOffset; + for (int memoryOffset = 0; memoryOffset < memoryBlock.Length; memoryOffset += COPY_BLOCK_SIZE) + { + _fileStream.Write(memoryBlock.Data, memoryOffset, (int)Math.Min(COPY_BLOCK_SIZE, memoryBlock.Length - memoryOffset)); + } + } + dataOffset += block.Length; + } + + // Finally, if the file has shortened, truncate the stream. + _fileStream.SetLength(_totalLength); + ReInitialize(); + } + + /// + /// See for more information. + /// + public bool SupportsWriteByte() + { + return !_readOnly; + } + + /// + /// See for more information. + /// + public bool SupportsInsertBytes() + { + return !_readOnly; + } + + /// + /// See for more information. + /// + public bool SupportsDeleteBytes() + { + return !_readOnly; + } + #endregion + + #region IDisposable Members + /// + /// See for more information. + /// + ~DynamicFileByteProvider() + { + Dispose(); + } + + /// + /// See for more information. + /// + public void Dispose() + { + if (_fileStream != null) + { + _fileStream.Close(); + _fileStream = null; + } + _fileName = null; + _dataMap = null; + GC.SuppressFinalize(this); + } + #endregion + + public bool ReadOnly + { + get { return _readOnly; } + set { _readOnly = value; } + } + + void OnLengthChanged(EventArgs e) + { + if (LengthChanged != null) + LengthChanged(this, e); + } + + void OnChanged(EventArgs e) + { + if (Changed != null) + { + Changed(this, e); + } + } + + DataBlock GetDataBlock(long findOffset, out long blockOffset) + { + if (findOffset < 0 || findOffset > _totalLength) + { + throw new ArgumentOutOfRangeException("index"); + } + + // Iterate over the blocks until the block containing the required offset is encountered. + blockOffset = 0; + for (DataBlock block = _dataMap.FirstBlock; block != null; block = block.NextBlock) + { + if ((blockOffset <= findOffset && blockOffset + block.Length > findOffset) || block.NextBlock == null) + { + return block; + } + blockOffset += block.Length; + } + return null; + } + + FileDataBlock GetNextFileDataBlock(DataBlock block, long dataOffset, out long nextDataOffset) + { + // Iterate over the remaining blocks until a file block is encountered. + nextDataOffset = dataOffset + block.Length; + block = block.NextBlock; + while (block != null) + { + FileDataBlock fileBlock = block as FileDataBlock; + if (fileBlock != null) + { + return fileBlock; + } + nextDataOffset += block.Length; + block = block.NextBlock; + } + return null; + } + + byte ReadByteFromFile(long fileOffset) + { + // Move to the correct position and read the byte. + if (_fileStream.Position != fileOffset) + { + _fileStream.Position = fileOffset; + } + return (byte)_fileStream.ReadByte(); + } + + void MoveFileBlock(FileDataBlock fileBlock, long dataOffset) + { + // First, determine whether the next file block needs to move before this one. + long nextDataOffset; + FileDataBlock nextFileBlock = GetNextFileDataBlock(fileBlock, dataOffset, out nextDataOffset); + if (nextFileBlock != null && dataOffset + fileBlock.Length > nextFileBlock.FileOffset) + { + // The next block needs to move first, so do that now. + MoveFileBlock(nextFileBlock, nextDataOffset); + } + + // Now, move the block. + if (fileBlock.FileOffset > dataOffset) + { + // Move the section to earlier in the file stream (done in chunks starting at the beginning of the section). + byte[] buffer = new byte[COPY_BLOCK_SIZE]; + for (long relativeOffset = 0; relativeOffset < fileBlock.Length; relativeOffset += buffer.Length) + { + long readOffset = fileBlock.FileOffset + relativeOffset; + int bytesToRead = (int)Math.Min(buffer.Length, fileBlock.Length - relativeOffset); + _fileStream.Position = readOffset; + _fileStream.Read(buffer, 0, bytesToRead); + + long writeOffset = dataOffset + relativeOffset; + _fileStream.Position = writeOffset; + _fileStream.Write(buffer, 0, bytesToRead); + } + } + else + { + // Move the section to later in the file stream (done in chunks starting at the end of the section). + byte[] buffer = new byte[COPY_BLOCK_SIZE]; + for (long relativeOffset = 0; relativeOffset < fileBlock.Length; relativeOffset += buffer.Length) + { + int bytesToRead = (int)Math.Min(buffer.Length, fileBlock.Length - relativeOffset); + long readOffset = fileBlock.FileOffset + fileBlock.Length - relativeOffset - bytesToRead; + _fileStream.Position = readOffset; + _fileStream.Read(buffer, 0, bytesToRead); + + long writeOffset = dataOffset + fileBlock.Length - relativeOffset - bytesToRead; + _fileStream.Position = writeOffset; + _fileStream.Write(buffer, 0, bytesToRead); + } + } + + // This block now points to a different position in the file. + fileBlock.SetFileOffset(dataOffset); + } + + void ReInitialize() + { + _dataMap = new DataMap(); + _dataMap.AddFirst(new FileDataBlock(0, _fileStream.Length)); + _totalLength = _fileStream.Length; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/FileByteProvider.cs b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/FileByteProvider.cs new file mode 100644 index 000000000..6ae12babc --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/FileByteProvider.cs @@ -0,0 +1,274 @@ +#pragma warning disable 0067 + +using System; +using System.IO; +using System.Collections; + +namespace Be.Windows.Forms +{ + /// + /// Byte provider for (big) files. + /// + public class FileByteProvider : IByteProvider, IDisposable + { + #region WriteCollection class + /// + /// Represents the write buffer class + /// + class WriteCollection : DictionaryBase + { + /// + /// Gets or sets a byte in the collection + /// + public byte this[long index] + { + get { return (byte)this.Dictionary[index]; } + set { Dictionary[index] = value; } + } + + /// + /// Adds a byte into the collection + /// + /// the index of the byte + /// the value of the byte + public void Add(long index, byte value) + { Dictionary.Add(index, value); } + + /// + /// Determines if a byte with the given index exists. + /// + /// the index of the byte + /// true, if the is in the collection + public bool Contains(long index) + { return Dictionary.Contains(index); } + + } + #endregion + + /// + /// Occurs, when the write buffer contains new changes. + /// + public event EventHandler Changed; + + /// + /// Contains all changes + /// + WriteCollection _writes = new WriteCollection(); + + /// + /// Contains the file name. + /// + string _fileName; + /// + /// Contains the file stream. + /// + FileStream _fileStream; + /// + /// Read-only access. + /// + bool _readOnly; + + /// + /// Initializes a new instance of the FileByteProvider class. + /// + /// + public FileByteProvider(string fileName) + { + _fileName = fileName; + + try + { + // try to open in write mode + _fileStream = File.Open(fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.Read); + } + catch + { + // write mode failed, try to open in read-only and fileshare friendly mode. + try + { + _fileStream = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + _readOnly = true; + } + catch + { + throw; + } + } + } + + /// + /// Terminates the instance of the FileByteProvider class. + /// + ~FileByteProvider() + { + Dispose(); + } + + /// + /// Raises the Changed event. + /// + /// Never used. + void OnChanged(EventArgs e) + { + if(Changed != null) + Changed(this, e); + } + + /// + /// Gets the name of the file the byte provider is using. + /// + public string FileName + { + get { return _fileName; } + } + + /// + /// Returns a value if there are some changes. + /// + /// true, if there are some changes + public bool HasChanges() + { + return (_writes.Count > 0); + } + + /// + /// Updates the file with all changes the write buffer contains. + /// + public void ApplyChanges() + { + if (this._readOnly) + { + throw new Exception("File is in read-only mode."); + } + + if(!HasChanges()) + return; + + IDictionaryEnumerator en = _writes.GetEnumerator(); + while(en.MoveNext()) + { + long index = (long)en.Key; + byte value = (byte)en.Value; + if(_fileStream.Position != index) + _fileStream.Position = index; + _fileStream.Write(new byte[]{value}, 0, 1); + } + _writes.Clear(); + } + + /// + /// Clears the write buffer and reject all changes made. + /// + public void RejectChanges() + { + _writes.Clear(); + } + + #region IByteProvider Members + + /// + /// Never used. + /// + public event EventHandler LengthChanged; + + /// + /// Reads a byte from the file. + /// + /// the index of the byte to read + /// the byte + public byte ReadByte(long index) + { + if(_writes.Contains(index)) + return _writes[index]; + + if(_fileStream.Position != index) + _fileStream.Position = index; + + byte res = (byte)_fileStream.ReadByte(); + return res; + } + + /// + /// Gets the length of the file. + /// + public long Length + { + get + { + return _fileStream.Length; + } + } + + /// + /// Writes a byte into write buffer + /// + public void WriteByte(long index, byte value) + { + if(_writes.Contains(index)) + _writes[index] = value; + else + _writes.Add(index, value); + + OnChanged(EventArgs.Empty); + } + + /// + /// Not supported + /// + public void DeleteBytes(long index, long length) + { + throw new NotSupportedException("FileByteProvider.DeleteBytes"); + } + + /// + /// Not supported + /// + public void InsertBytes(long index, byte[] bs) + { + throw new NotSupportedException("FileByteProvider.InsertBytes"); + } + + /// + /// Returns true + /// + public bool SupportsWriteByte() + { + return !_readOnly; + } + + /// + /// Returns false + /// + public bool SupportsInsertBytes() + { + return false; + } + + /// + /// Returns false + /// + public bool SupportsDeleteBytes() + { + return false; + } + #endregion + + #region IDisposable Members + /// + /// Releases the file handle used by the FileByteProvider. + /// + public void Dispose() + { + if(_fileStream != null) + { + _fileName = null; + + _fileStream.Close(); + _fileStream = null; + } + + GC.SuppressFinalize(this); + } + #endregion + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/FileDataBlock.cs b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/FileDataBlock.cs new file mode 100644 index 000000000..8ef737ced --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/FileDataBlock.cs @@ -0,0 +1,96 @@ +using System; + +namespace Be.Windows.Forms +{ + internal sealed class FileDataBlock : DataBlock + { + long _length; + long _fileOffset; + + public FileDataBlock(long fileOffset, long length) + { + _fileOffset = fileOffset; + _length = length; + } + + public long FileOffset + { + get + { + return _fileOffset; + } + } + + public override long Length + { + get + { + return _length; + } + } + + public void SetFileOffset(long value) + { + _fileOffset = value; + } + + public void RemoveBytesFromEnd(long count) + { + if (count > _length) + { + throw new ArgumentOutOfRangeException("count"); + } + + _length -= count; + } + + public void RemoveBytesFromStart(long count) + { + if (count > _length) + { + throw new ArgumentOutOfRangeException("count"); + } + + _fileOffset += count; + _length -= count; + } + + public override void RemoveBytes(long position, long count) + { + if (position > _length) + { + throw new ArgumentOutOfRangeException("offset"); + } + + if (position + count > _length) + { + throw new ArgumentOutOfRangeException("count"); + } + + long prefixLength = position; + long prefixFileOffset = _fileOffset; + + long suffixLength = _length - count - prefixLength; + long suffixFileOffset = _fileOffset + position + count; + + if (prefixLength > 0 && suffixLength > 0) + { + _fileOffset = prefixFileOffset; + _length = prefixLength; + _map.AddAfter(this, new FileDataBlock(suffixFileOffset, suffixLength)); + return; + } + + if (prefixLength > 0) + { + _fileOffset = prefixFileOffset; + _length = prefixLength; + } + else + { + _fileOffset = suffixFileOffset; + _length = suffixLength; + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/HexBox.bmp b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/HexBox.bmp new file mode 100644 index 000000000..02699d94a Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/HexBox.bmp differ diff --git a/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/HexBox.cs b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/HexBox.cs new file mode 100644 index 000000000..6aa75f59f --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/HexBox.cs @@ -0,0 +1,3454 @@ +using System; +using System.Drawing; +using System.Windows.Forms; +using System.Runtime.InteropServices; +using System.ComponentModel; +using System.Security.Permissions; +using System.Windows.Forms.VisualStyles; +using Be.Windows.Forms.Design; + +namespace Be.Windows.Forms +{ + #region HexCasing enumeration + /// + /// Specifies the case of hex characters in the HexBox control + /// + public enum HexCasing + { + /// + /// Converts all characters to uppercase. + /// + Upper = 0, + /// + /// Converts all characters to lowercase. + /// + Lower = 1 + } + #endregion + + #region BytePositionInfo structure + /// + /// Represents a position in the HexBox control + /// + struct BytePositionInfo + { + public BytePositionInfo(long index, int characterPosition) + { + _index = index; + _characterPosition = characterPosition; + } + + public int CharacterPosition + { + get { return _characterPosition; } + } int _characterPosition; + + public long Index + { + get { return _index; } + } long _index; + } + #endregion + + /// + /// Represents a hex box control. + /// + [ToolboxBitmap(typeof(HexBox), "HexBox.bmp")] + public class HexBox : Control + { + #region IKeyInterpreter interface + /// + /// Defines a user input handler such as for mouse and keyboard input + /// + interface IKeyInterpreter + { + /// + /// Activates mouse events + /// + void Activate(); + /// + /// Deactivate mouse events + /// + void Deactivate(); + /// + /// Preprocesses WM_KEYUP window message. + /// + /// the Message object to process. + /// True, if the message was processed. + bool PreProcessWmKeyUp(ref Message m); + /// + /// Preprocesses WM_CHAR window message. + /// + /// the Message object to process. + /// True, if the message was processed. + bool PreProcessWmChar(ref Message m); + /// + /// Preprocesses WM_KEYDOWN window message. + /// + /// the Message object to process. + /// True, if the message was processed. + bool PreProcessWmKeyDown(ref Message m); + /// + /// Gives some information about where to place the caret. + /// + /// the index of the byte + /// the position where the caret is to place. + PointF GetCaretPointF(long byteIndex); + } + #endregion + + #region EmptyKeyInterpreter class + /// + /// Represents an empty input handler without any functionality. + /// If is set ByteProvider to null, then this interpreter is used. + /// + class EmptyKeyInterpreter : IKeyInterpreter + { + HexBox _hexBox; + + public EmptyKeyInterpreter(HexBox hexBox) + { + _hexBox = hexBox; + } + + #region IKeyInterpreter Members + public void Activate(){} + public void Deactivate(){} + + public bool PreProcessWmKeyUp(ref Message m) + { return _hexBox.BasePreProcessMessage(ref m); } + + public bool PreProcessWmChar(ref Message m) + { return _hexBox.BasePreProcessMessage(ref m); } + + public bool PreProcessWmKeyDown(ref Message m) + { return _hexBox.BasePreProcessMessage(ref m); } + + public PointF GetCaretPointF(long byteIndex) + { return new PointF (); } + + #endregion + } + #endregion + + #region KeyInterpreter class + /// + /// Handles user input such as mouse and keyboard input during hex view edit + /// + class KeyInterpreter : IKeyInterpreter + { + #region Fields + /// + /// Contains the parent HexBox control + /// + protected HexBox _hexBox; + + /// + /// Contains True, if shift key is down + /// + protected bool _shiftDown; + /// + /// Contains True, if mouse is down + /// + bool _mouseDown; + /// + /// Contains the selection start position info + /// + BytePositionInfo _bpiStart; + /// + /// Contains the current mouse selection position info + /// + BytePositionInfo _bpi; + #endregion + + #region Ctors + public KeyInterpreter(HexBox hexBox) + { + _hexBox = hexBox; + } + #endregion + + #region Activate, Deactive methods + public virtual void Activate() + { + _hexBox.MouseDown += new MouseEventHandler(BeginMouseSelection); + _hexBox.MouseMove += new MouseEventHandler(UpdateMouseSelection); + _hexBox.MouseUp += new MouseEventHandler(EndMouseSelection); + } + + public virtual void Deactivate() + { + _hexBox.MouseDown -= new MouseEventHandler(BeginMouseSelection); + _hexBox.MouseMove -= new MouseEventHandler(UpdateMouseSelection); + _hexBox.MouseUp -= new MouseEventHandler(EndMouseSelection); + } + #endregion + + #region Mouse selection methods + void BeginMouseSelection(object sender, MouseEventArgs e) + { + System.Diagnostics.Debug.WriteLine("BeginMouseSelection()", "KeyInterpreter"); + + _mouseDown = true; + + if(!_shiftDown) + { + _bpiStart = new BytePositionInfo(_hexBox._bytePos, _hexBox._byteCharacterPos); + _hexBox.ReleaseSelection(); + } + else + { + UpdateMouseSelection(this, e); + } + } + + void UpdateMouseSelection(object sender, MouseEventArgs e) + { + if(!_mouseDown) + return; + + _bpi = GetBytePositionInfo(new Point(e.X, e.Y)); + long selEnd = _bpi.Index; + long realselStart; + long realselLength; + + if(selEnd < _bpiStart.Index) + { + realselStart = selEnd; + realselLength = _bpiStart.Index - selEnd; + } + else if(selEnd > _bpiStart.Index) + { + realselStart = _bpiStart.Index; + realselLength = selEnd - realselStart; + } + else + { + realselStart = _hexBox._bytePos; + realselLength = 0; + } + + if(realselStart != _hexBox._bytePos || realselLength != _hexBox._selectionLength) + { + _hexBox.InternalSelect(realselStart, realselLength); + } + } + + void EndMouseSelection(object sender, MouseEventArgs e) + { + _mouseDown = false; + } + #endregion + + #region PrePrcessWmKeyDown methods + public virtual bool PreProcessWmKeyDown(ref Message m) + { + System.Diagnostics.Debug.WriteLine("PreProcessWmKeyDown(ref Message m)", "KeyInterpreter"); + + Keys vc = (Keys)m.WParam.ToInt32(); + + Keys keyData = vc | Control.ModifierKeys; + + switch(keyData) + { + case Keys.Left: + case Keys.Up: + case Keys.Right: + case Keys.Down: + case Keys.PageUp: + case Keys.PageDown: + case Keys.Left | Keys.Shift: + case Keys.Up | Keys.Shift: + case Keys.Right | Keys.Shift: + case Keys.Down | Keys.Shift: + case Keys.Tab: + case Keys.Back: + case Keys.Delete: + case Keys.Home: + case Keys.End: + case Keys.ShiftKey | Keys.Shift: + case Keys.C | Keys.Control: + case Keys.X | Keys.Control: + case Keys.V | Keys.Control: + if(RaiseKeyDown(keyData)) + return true; + break; + } + + switch(keyData) + { + case Keys.Left: // move left + return PreProcessWmKeyDown_Left(ref m); + case Keys.Up: // move up + return PreProcessWmKeyDown_Up(ref m); + case Keys.Right: // move right + return PreProcessWmKeyDown_Right(ref m); + case Keys.Down: // move down + return PreProcessWmKeyDown_Down(ref m); + case Keys.PageUp: // move pageup + return PreProcessWmKeyDown_PageUp(ref m); + case Keys.PageDown: // move pagedown + return PreProcessWmKeyDown_PageDown(ref m); + case Keys.Left | Keys.Shift: // move left with selection + return PreProcessWmKeyDown_ShiftLeft(ref m); + case Keys.Up | Keys.Shift: // move up with selection + return PreProcessWmKeyDown_ShiftUp(ref m); + case Keys.Right | Keys.Shift: // move right with selection + return PreProcessWmKeyDown_ShiftRight(ref m); + case Keys.Down | Keys.Shift: // move down with selection + return PreProcessWmKeyDown_ShiftDown(ref m); + case Keys.Tab: // switch focus to string view + return PreProcessWmKeyDown_Tab(ref m); + case Keys.Back: // back + return PreProcessWmKeyDown_Back(ref m); + case Keys.Delete: // delete + return PreProcessWmKeyDown_Delete(ref m); + case Keys.Home: // move to home + return PreProcessWmKeyDown_Home(ref m); + case Keys.End: // move to end + return PreProcessWmKeyDown_End(ref m); + case Keys.ShiftKey | Keys.Shift: // begin selection process + return PreProcessWmKeyDown_ShiftShiftKey(ref m); + case Keys.C | Keys.Control: // copy + return PreProcessWmKeyDown_ControlC(ref m); + case Keys.X | Keys.Control: // cut + return PreProcessWmKeyDown_ControlX(ref m); + case Keys.V | Keys.Control: // paste + return PreProcessWmKeyDown_ControlV(ref m); + default: + _hexBox.ScrollByteIntoView(); + return _hexBox.BasePreProcessMessage(ref m); + } + } + + protected bool RaiseKeyDown(Keys keyData) + { + KeyEventArgs e = new KeyEventArgs(keyData); + _hexBox.OnKeyDown(e); + return e.Handled; + } + + protected virtual bool PreProcessWmKeyDown_Left(ref Message m) + { + return PerformPosMoveLeft(); + } + + protected virtual bool PreProcessWmKeyDown_Up(ref Message m) + { + long pos = _hexBox._bytePos; + int cp = _hexBox._byteCharacterPos; + + if( !(pos == 0 && cp == 0) ) + { + pos = Math.Max(-1, pos-_hexBox._iHexMaxHBytes); + if(pos == -1) + return true; + + _hexBox.SetPosition(pos); + + if(pos < _hexBox._startByte) + { + _hexBox.PerformScrollLineUp(); + } + + _hexBox.UpdateCaret(); + _hexBox.Invalidate(); + } + + _hexBox.ScrollByteIntoView(); + _hexBox.ReleaseSelection(); + + return true; + } + + protected virtual bool PreProcessWmKeyDown_Right(ref Message m) + { + return PerformPosMoveRight(); + } + + protected virtual bool PreProcessWmKeyDown_Down(ref Message m) + { + long pos = _hexBox._bytePos; + int cp = _hexBox._byteCharacterPos; + + if(pos == _hexBox._byteProvider.Length && cp == 0) + return true; + + pos = Math.Min(_hexBox._byteProvider.Length, pos+_hexBox._iHexMaxHBytes); + + if(pos == _hexBox._byteProvider.Length) + cp = 0; + + _hexBox.SetPosition(pos, cp); + + if(pos > _hexBox._endByte-1) + { + _hexBox.PerformScrollLineDown(); + } + + _hexBox.UpdateCaret(); + _hexBox.ScrollByteIntoView(); + _hexBox.ReleaseSelection(); + _hexBox.Invalidate(); + + return true; + } + + protected virtual bool PreProcessWmKeyDown_PageUp(ref Message m) + { + long pos = _hexBox._bytePos; + int cp = _hexBox._byteCharacterPos; + + if(pos == 0 && cp == 0) + return true; + + pos = Math.Max(0, pos-_hexBox._iHexMaxBytes); + if(pos == 0) + return true; + + _hexBox.SetPosition(pos); + + if(pos < _hexBox._startByte) + { + _hexBox.PerformScrollPageUp(); + } + + _hexBox.ReleaseSelection(); + _hexBox.UpdateCaret(); + _hexBox.Invalidate(); + return true; + } + + protected virtual bool PreProcessWmKeyDown_PageDown(ref Message m) + { + long pos = _hexBox._bytePos; + int cp = _hexBox._byteCharacterPos; + + if(pos == _hexBox._byteProvider.Length && cp == 0) + return true; + + pos = Math.Min(_hexBox._byteProvider.Length, pos+_hexBox._iHexMaxBytes); + + if(pos == _hexBox._byteProvider.Length) + cp = 0; + + _hexBox.SetPosition(pos, cp); + + if(pos > _hexBox._endByte-1) + { + _hexBox.PerformScrollPageDown(); + } + + _hexBox.ReleaseSelection(); + _hexBox.UpdateCaret(); + _hexBox.Invalidate(); + + return true; + } + + protected virtual bool PreProcessWmKeyDown_ShiftLeft(ref Message m) + { + long pos = _hexBox._bytePos; + long sel = _hexBox._selectionLength; + + if(pos + sel < 1) + return true; + + if(pos+sel <= _bpiStart.Index) + { + if(pos == 0) + return true; + + pos--; + sel++; + } + else + { + sel = Math.Max(0, sel-1); + } + + _hexBox.ScrollByteIntoView(); + _hexBox.InternalSelect(pos, sel); + + return true; + } + + protected virtual bool PreProcessWmKeyDown_ShiftUp(ref Message m) + { + long pos = _hexBox._bytePos; + long sel = _hexBox._selectionLength; + + if(pos-_hexBox._iHexMaxHBytes < 0 && pos <= _bpiStart.Index) + return true; + + if(_bpiStart.Index >= pos+sel) + { + pos = pos - _hexBox._iHexMaxHBytes; + sel += _hexBox._iHexMaxHBytes; + _hexBox.InternalSelect(pos, sel); + _hexBox.ScrollByteIntoView(); + } + else + { + sel -= _hexBox._iHexMaxHBytes; + if(sel < 0) + { + pos = _bpiStart.Index + sel; + sel = -sel; + _hexBox.InternalSelect(pos, sel); + _hexBox.ScrollByteIntoView(); + } + else + { + sel -= _hexBox._iHexMaxHBytes; + _hexBox.InternalSelect(pos, sel); + _hexBox.ScrollByteIntoView(pos+sel); + } + } + + return true; + } + + protected virtual bool PreProcessWmKeyDown_ShiftRight(ref Message m) + { + long pos = _hexBox._bytePos; + long sel = _hexBox._selectionLength; + + if(pos+sel >= _hexBox._byteProvider.Length) + return true; + + if(_bpiStart.Index <= pos) + { + sel++; + _hexBox.InternalSelect(pos, sel); + _hexBox.ScrollByteIntoView(pos+sel); + } + else + { + pos++; + sel = Math.Max(0, sel-1); + _hexBox.InternalSelect(pos, sel); + _hexBox.ScrollByteIntoView(); + } + + return true; + } + + protected virtual bool PreProcessWmKeyDown_ShiftDown(ref Message m) + { + long pos = _hexBox._bytePos; + long sel = _hexBox._selectionLength; + + long max = _hexBox._byteProvider.Length; + + if(pos+sel+_hexBox._iHexMaxHBytes > max) + return true; + + if(_bpiStart.Index <= pos) + { + sel += _hexBox._iHexMaxHBytes; + _hexBox.InternalSelect(pos, sel); + _hexBox.ScrollByteIntoView(pos+sel); + } + else + { + sel -= _hexBox._iHexMaxHBytes; + if(sel < 0) + { + pos = _bpiStart.Index; + sel = -sel; + } + else + { + pos += _hexBox._iHexMaxHBytes; + sel -= _hexBox._iHexMaxHBytes; + } + + _hexBox.InternalSelect(pos, sel); + _hexBox.ScrollByteIntoView(); + } + + return true; + } + + protected virtual bool PreProcessWmKeyDown_Tab(ref Message m) + { + if(_hexBox._stringViewVisible && _hexBox._keyInterpreter.GetType() == typeof(KeyInterpreter)) + { + _hexBox.ActivateStringKeyInterpreter(); + _hexBox.ScrollByteIntoView(); + _hexBox.ReleaseSelection(); + _hexBox.UpdateCaret(); + _hexBox.Invalidate(); + return true; + } + + if(_hexBox.Parent == null) return true; + _hexBox.Parent.SelectNextControl(_hexBox, true, true, true, true); + return true; + } + + protected virtual bool PreProcessWmKeyDown_ShiftTab(ref Message m) + { + if(_hexBox._keyInterpreter is StringKeyInterpreter) + { + _shiftDown = false; + _hexBox.ActivateKeyInterpreter(); + _hexBox.ScrollByteIntoView(); + _hexBox.ReleaseSelection(); + _hexBox.UpdateCaret(); + _hexBox.Invalidate(); + return true; + } + + if(_hexBox.Parent == null) return true; + _hexBox.Parent.SelectNextControl(_hexBox, false, true, true, true); + return true; + } + + protected virtual bool PreProcessWmKeyDown_Back(ref Message m) + { + if(!_hexBox._byteProvider.SupportsDeleteBytes()) + return true; + + long pos = _hexBox._bytePos; + long sel = _hexBox._selectionLength; + int cp = _hexBox._byteCharacterPos; + + long startDelete = (cp == 0 && sel == 0) ? pos-1 : pos; + if(startDelete < 0 && sel < 1) + return true; + + long bytesToDelete = (sel > 0) ? sel : 1; + _hexBox._byteProvider.DeleteBytes(Math.Max(0, startDelete), bytesToDelete); + _hexBox.UpdateScrollSize(); + + if(sel == 0) + PerformPosMoveLeftByte(); + + _hexBox.ReleaseSelection(); + _hexBox.Invalidate(); + + return true; + } + + protected virtual bool PreProcessWmKeyDown_Delete(ref Message m) + { + if(!_hexBox._byteProvider.SupportsDeleteBytes()) + return true; + + long pos = _hexBox._bytePos; + long sel = _hexBox._selectionLength; + + if(pos >= _hexBox._byteProvider.Length) + return true; + + long bytesToDelete = (sel > 0) ? sel : 1; + _hexBox._byteProvider.DeleteBytes(pos, bytesToDelete); + + _hexBox.UpdateScrollSize(); + _hexBox.ReleaseSelection(); + _hexBox.Invalidate(); + + return true; + } + + protected virtual bool PreProcessWmKeyDown_Home(ref Message m) + { + long pos = _hexBox._bytePos; + int cp = _hexBox._byteCharacterPos; + + if(pos < 1) + return true; + + pos = 0; + cp = 0; + _hexBox.SetPosition(pos, cp); + + _hexBox.ScrollByteIntoView(); + _hexBox.UpdateCaret(); + _hexBox.ReleaseSelection(); + + return true; + } + + protected virtual bool PreProcessWmKeyDown_End(ref Message m) + { + long pos = _hexBox._bytePos; + int cp = _hexBox._byteCharacterPos; + + if(pos >= _hexBox._byteProvider.Length-1) + return true; + + pos = _hexBox._byteProvider.Length; + cp = 0; + _hexBox.SetPosition(pos, cp); + + _hexBox.ScrollByteIntoView(); + _hexBox.UpdateCaret(); + _hexBox.ReleaseSelection(); + + return true; + } + + protected virtual bool PreProcessWmKeyDown_ShiftShiftKey(ref Message m) + { + if(_mouseDown) + return true; + if(_shiftDown) + return true; + + _shiftDown = true; + + if(_hexBox._selectionLength > 0) + return true; + + _bpiStart = new BytePositionInfo(_hexBox._bytePos, _hexBox._byteCharacterPos); + + return true; + } + + protected virtual bool PreProcessWmKeyDown_ControlC(ref Message m) + { + _hexBox.Copy(); + return true; + } + + protected virtual bool PreProcessWmKeyDown_ControlX(ref Message m) + { + _hexBox.Cut(); + return true; + } + + protected virtual bool PreProcessWmKeyDown_ControlV(ref Message m) + { + _hexBox.Paste(); + return true; + } + + #endregion + + #region PreProcessWmChar methods + public virtual bool PreProcessWmChar(ref Message m) + { + if(Control.ModifierKeys == Keys.Control) + { + return _hexBox.BasePreProcessMessage(ref m); + } + + bool sw = _hexBox._byteProvider.SupportsWriteByte(); + bool si = _hexBox._byteProvider.SupportsInsertBytes(); + bool sd = _hexBox._byteProvider.SupportsDeleteBytes(); + + long pos = _hexBox._bytePos; + long sel = _hexBox._selectionLength; + int cp = _hexBox._byteCharacterPos; + + if( + (!sw && pos != _hexBox._byteProvider.Length) || + (!si && pos == _hexBox._byteProvider.Length)) + { + return _hexBox.BasePreProcessMessage(ref m); + } + + char c = (char)m.WParam.ToInt32(); + + if(Uri.IsHexDigit(c)) + { + if(RaiseKeyPress(c)) + return true; + + if(_hexBox.ReadOnly) + return true; + + bool isInsertMode = (pos == _hexBox._byteProvider.Length); + + // do insert when insertActive = true + if(!isInsertMode && si && _hexBox._insertActive && cp == 0) + isInsertMode = true; + + if(sd && si && sel > 0) + { + _hexBox._byteProvider.DeleteBytes(pos, sel); + isInsertMode = true; + cp = 0; + _hexBox.SetPosition(pos, cp); + } + + _hexBox.ReleaseSelection(); + + byte currentByte; + if(isInsertMode) + currentByte = 0; + else + currentByte = _hexBox._byteProvider.ReadByte(pos); + + string sCb = currentByte.ToString("X", System.Threading.Thread.CurrentThread.CurrentCulture); + if(sCb.Length == 1) + sCb = "0" + sCb; + + string sNewCb = c.ToString(); + if(cp == 0) + sNewCb += sCb.Substring(1, 1); + else + sNewCb = sCb.Substring(0, 1) + sNewCb; + byte newcb = byte.Parse(sNewCb, System.Globalization.NumberStyles.AllowHexSpecifier, System.Threading.Thread.CurrentThread.CurrentCulture); + if(isInsertMode) + _hexBox._byteProvider.InsertBytes(pos, new byte[]{newcb}); + else + _hexBox._byteProvider.WriteByte(pos, newcb); + + PerformPosMoveRight(); + + _hexBox.Invalidate(); + return true; + } + else + { + return _hexBox.BasePreProcessMessage(ref m); + } + } + + protected bool RaiseKeyPress(char keyChar) + { + KeyPressEventArgs e = new KeyPressEventArgs(keyChar); + _hexBox.OnKeyPress(e); + return e.Handled; + } + #endregion + + #region PreProcessWmKeyUp methods + public virtual bool PreProcessWmKeyUp(ref Message m) + { + System.Diagnostics.Debug.WriteLine("PreProcessWmKeyUp(ref Message m)", "KeyInterpreter"); + + Keys vc = (Keys)m.WParam.ToInt32(); + + Keys keyData = vc | Control.ModifierKeys; + + switch(keyData) + { + case Keys.ShiftKey: + case Keys.Insert: + if(RaiseKeyUp(keyData)) + return true; + break; + } + + switch(keyData) + { + case Keys.ShiftKey: + _shiftDown = false; + return true; + case Keys.Insert: + return PreProcessWmKeyUp_Insert(ref m); + default: + return _hexBox.BasePreProcessMessage(ref m); + } + } + + protected virtual bool PreProcessWmKeyUp_Insert(ref Message m) + { + _hexBox._insertActive = !_hexBox._insertActive; + _hexBox.OnInsertActiveChanged(EventArgs.Empty); + return true; + } + + protected bool RaiseKeyUp(Keys keyData) + { + KeyEventArgs e = new KeyEventArgs(keyData); + _hexBox.OnKeyUp(e); + return e.Handled; + } + #endregion + + #region Misc + protected virtual bool PerformPosMoveLeft() + { + long pos = _hexBox._bytePos; + long sel = _hexBox._selectionLength; + int cp = _hexBox._byteCharacterPos; + + if(sel != 0) + { + cp = 0; + _hexBox.SetPosition(pos, cp); + _hexBox.ReleaseSelection(); + } + else + { + if(pos == 0 && cp == 0) + return true; + + if(cp > 0) + { + cp--; + } + else + { + pos = Math.Max(0, pos-1); + cp++; + } + + _hexBox.SetPosition(pos, cp); + + if(pos < _hexBox._startByte) + { + _hexBox.PerformScrollLineUp(); + } + _hexBox.UpdateCaret(); + _hexBox.Invalidate(); + } + + _hexBox.ScrollByteIntoView(); + return true; + } + protected virtual bool PerformPosMoveRight() + { + long pos = _hexBox._bytePos; + int cp = _hexBox._byteCharacterPos; + long sel = _hexBox._selectionLength; + + if(sel != 0) + { + pos += sel; + cp = 0; + _hexBox.SetPosition(pos, cp); + _hexBox.ReleaseSelection(); + } + else + { + if( !(pos == _hexBox._byteProvider.Length && cp == 0) ) + { + + if(cp > 0) + { + pos = Math.Min(_hexBox._byteProvider.Length, pos+1); + cp = 0; + } + else + { + cp++; + } + + _hexBox.SetPosition(pos, cp); + + if(pos > _hexBox._endByte-1) + { + _hexBox.PerformScrollLineDown(); + } + _hexBox.UpdateCaret(); + _hexBox.Invalidate(); + } + } + + _hexBox.ScrollByteIntoView(); + return true; + } + protected virtual bool PerformPosMoveLeftByte() + { + long pos = _hexBox._bytePos; + int cp = _hexBox._byteCharacterPos; + + if(pos == 0) + return true; + + pos = Math.Max(0, pos-1); + cp = 0; + + _hexBox.SetPosition(pos, cp); + + if(pos < _hexBox._startByte) + { + _hexBox.PerformScrollLineUp(); + } + _hexBox.UpdateCaret(); + _hexBox.ScrollByteIntoView(); + _hexBox.Invalidate(); + + return true; + } + + protected virtual bool PerformPosMoveRightByte() + { + long pos = _hexBox._bytePos; + int cp = _hexBox._byteCharacterPos; + + if(pos == _hexBox._byteProvider.Length) + return true; + + pos = Math.Min(_hexBox._byteProvider.Length, pos+1); + cp = 0; + + _hexBox.SetPosition(pos, cp); + + if(pos > _hexBox._endByte-1) + { + _hexBox.PerformScrollLineDown(); + } + _hexBox.UpdateCaret(); + _hexBox.ScrollByteIntoView(); + _hexBox.Invalidate(); + + return true; + } + + + public virtual PointF GetCaretPointF(long byteIndex) + { + System.Diagnostics.Debug.WriteLine("GetCaretPointF()", "KeyInterpreter"); + + return _hexBox.GetBytePointF(byteIndex); + } + + protected virtual BytePositionInfo GetBytePositionInfo(Point p) + { + return _hexBox.GetHexBytePositionInfo(p); + } + #endregion + } + #endregion + + #region StringKeyInterpreter class + /// + /// Handles user input such as mouse and keyboard input during string view edit + /// + class StringKeyInterpreter : KeyInterpreter + { + #region Ctors + public StringKeyInterpreter(HexBox hexBox) : base(hexBox) + { + _hexBox._byteCharacterPos = 0; + } + #endregion + + #region PreProcessWmKeyDown methods + public override bool PreProcessWmKeyDown(ref Message m) + { + Keys vc = (Keys)m.WParam.ToInt32(); + + Keys keyData = vc | Control.ModifierKeys; + + switch(keyData) + { + case Keys.Tab | Keys.Shift: + case Keys.Tab: + if(RaiseKeyDown(keyData)) + return true; + break; + } + + switch(keyData) + { + case Keys.Tab | Keys.Shift: + return PreProcessWmKeyDown_ShiftTab(ref m); + case Keys.Tab: + return PreProcessWmKeyDown_Tab(ref m); + default: + return base.PreProcessWmKeyDown(ref m); + } + } + + protected override bool PreProcessWmKeyDown_Left(ref Message m) + { + return PerformPosMoveLeftByte(); + } + + protected override bool PreProcessWmKeyDown_Right(ref Message m) + { + return PerformPosMoveRightByte(); + } + + #endregion + + #region PreProcessWmChar methods + public override bool PreProcessWmChar(ref Message m) + { + if(Control.ModifierKeys == Keys.Control) + { + return _hexBox.BasePreProcessMessage(ref m); + } + + bool sw = _hexBox._byteProvider.SupportsWriteByte(); + bool si = _hexBox._byteProvider.SupportsInsertBytes(); + bool sd = _hexBox._byteProvider.SupportsDeleteBytes(); + + long pos = _hexBox._bytePos; + long sel = _hexBox._selectionLength; + int cp = _hexBox._byteCharacterPos; + + if( + (!sw && pos != _hexBox._byteProvider.Length) || + (!si && pos == _hexBox._byteProvider.Length)) + { + return _hexBox.BasePreProcessMessage(ref m); + } + + char c = (char)m.WParam.ToInt32(); + + if(RaiseKeyPress(c)) + return true; + + if(_hexBox.ReadOnly) + return true; + + bool isInsertMode = (pos == _hexBox._byteProvider.Length); + + // do insert when insertActive = true + if(!isInsertMode && si && _hexBox._insertActive) + isInsertMode = true; + + if(sd && si && sel > 0) + { + _hexBox._byteProvider.DeleteBytes(pos, sel); + isInsertMode = true; + cp = 0; + _hexBox.SetPosition(pos, cp); + } + + _hexBox.ReleaseSelection(); + + if(isInsertMode) + _hexBox._byteProvider.InsertBytes(pos, new byte[]{(byte)c}); + else + _hexBox._byteProvider.WriteByte(pos, (byte)c); + + PerformPosMoveRightByte(); + _hexBox.Invalidate(); + + return true; + } + #endregion + + #region Misc + public override PointF GetCaretPointF(long byteIndex) + { + System.Diagnostics.Debug.WriteLine("GetCaretPointF()", "StringKeyInterpreter"); + + Point gp = _hexBox.GetGridBytePoint(byteIndex); + return _hexBox.GetByteStringPointF(gp); + } + + protected override BytePositionInfo GetBytePositionInfo(Point p) + { + return _hexBox.GetStringBytePositionInfo(p); + } + #endregion + } + #endregion + + #region Fields + /// + /// Contains the hole content bounds of all text + /// + Rectangle _recContent; + /// + /// Contains the line info bounds + /// + Rectangle _recLineInfo; + /// + /// Contains the hex data bounds + /// + Rectangle _recHex; + /// + /// Contains the string view bounds + /// + Rectangle _recStringView; + + /// + /// Contains string format information for text drawing + /// + StringFormat _stringFormat; + /// + /// Contains the width and height of a single char + /// + SizeF _charSize; + + /// + /// Contains the maximum of visible horizontal bytes + /// + int _iHexMaxHBytes; + /// + /// Contains the maximum of visible vertical bytes + /// + int _iHexMaxVBytes; + /// + /// Contains the maximum of visible bytes. + /// + int _iHexMaxBytes; + + /// + /// Contains the scroll bars minimum value + /// + long _scrollVmin; + /// + /// Contains the scroll bars maximum value + /// + long _scrollVmax; + /// + /// Contains the scroll bars current position + /// + long _scrollVpos; + /// + /// Contains a vertical scroll + /// + VScrollBar _vScrollBar; + /// + /// Contains a timer for thumbtrack scrolling + /// + Timer _thumbTrackTimer = new Timer(); + /// + /// Contains the thumbtrack scrolling position + /// + long _thumbTrackPosition; + /// + /// Contains the thumptrack delay for scrolling in milliseconds. + /// + const int THUMPTRACKDELAY = 50; + /// + /// Contains the Enviroment.TickCount of the last refresh + /// + int _lastThumbtrack; + /// + /// Contains the border´s left shift + /// + int _recBorderLeft = SystemInformation.Border3DSize.Width; + /// + /// Contains the border´s right shift + /// + int _recBorderRight = SystemInformation.Border3DSize.Width; + /// + /// Contains the border´s top shift + /// + int _recBorderTop = SystemInformation.Border3DSize.Height; + /// + /// Contains the border bottom shift + /// + int _recBorderBottom = SystemInformation.Border3DSize.Height; + + /// + /// Contains the index of the first visible byte + /// + long _startByte; + /// + /// Contains the index of the last visible byte + /// + long _endByte; + + /// + /// Contains the current byte position + /// + long _bytePos = -1; + /// + /// Contains the current char position in one byte + /// + /// + /// "1A" + /// "1" = char position of 0 + /// "A" = char position of 1 + /// + int _byteCharacterPos; + + /// + /// Contains string format information for hex values + /// + string _hexStringFormat = "X"; + + + /// + /// Contains the current key interpreter + /// + IKeyInterpreter _keyInterpreter; + /// + /// Contains an empty key interpreter without functionality + /// + EmptyKeyInterpreter _eki; + /// + /// Contains the default key interpreter + /// + KeyInterpreter _ki; + /// + /// Contains the string key interpreter + /// + StringKeyInterpreter _ski; + + /// + /// Contains True if caret is visible + /// + bool _caretVisible; + + /// + /// Contains true, if the find (Find method) should be aborted. + /// + bool _abortFind; + /// + /// Contains a value of the current finding position. + /// + long _findingPos; + + /// + /// Contains a state value about Insert or Write mode. When this value is true and the ByteProvider SupportsInsert is true bytes are inserted instead of overridden. + /// + bool _insertActive; + #endregion + + #region Events + /// + /// Occurs, when the value of InsertActive property has changed. + /// + [Description("Occurs, when the value of InsertActive property has changed.")] + public event EventHandler InsertActiveChanged; + /// + /// Occurs, when the value of ReadOnly property has changed. + /// + [Description("Occurs, when the value of ReadOnly property has changed.")] + public event EventHandler ReadOnlyChanged; + /// + /// Occurs, when the value of ByteProvider property has changed. + /// + [Description("Occurs, when the value of ByteProvider property has changed.")] + public event EventHandler ByteProviderChanged; + /// + /// Occurs, when the value of SelectionStart property has changed. + /// + [Description("Occurs, when the value of SelectionStart property has changed.")] + public event EventHandler SelectionStartChanged; + /// + /// Occurs, when the value of SelectionLength property has changed. + /// + [Description("Occurs, when the value of SelectionLength property has changed.")] + public event EventHandler SelectionLengthChanged; + /// + /// Occurs, when the value of LineInfoVisible property has changed. + /// + [Description("Occurs, when the value of LineInfoVisible property has changed.")] + public event EventHandler LineInfoVisibleChanged; + /// + /// Occurs, when the value of StringViewVisible property has changed. + /// + [Description("Occurs, when the value of StringViewVisible property has changed.")] + public event EventHandler StringViewVisibleChanged; + /// + /// Occurs, when the value of BorderStyle property has changed. + /// + [Description("Occurs, when the value of BorderStyle property has changed.")] + public event EventHandler BorderStyleChanged; + /// + /// Occurs, when the value of BytesPerLine property has changed. + /// + [Description("Occurs, when the value of BytesPerLine property has changed.")] + public event EventHandler BytesPerLineChanged; + /// + /// Occurs, when the value of UseFixedBytesPerLine property has changed. + /// + [Description("Occurs, when the value of UseFixedBytesPerLine property has changed.")] + public event EventHandler UseFixedBytesPerLineChanged; + /// + /// Occurs, when the value of VScrollBarVisible property has changed. + /// + [Description("Occurs, when the value of VScrollBarVisible property has changed.")] + public event EventHandler VScrollBarVisibleChanged; + /// + /// Occurs, when the value of HexCasing property has changed. + /// + [Description("Occurs, when the value of HexCasing property has changed.")] + public event EventHandler HexCasingChanged; + /// + /// Occurs, when the value of HorizontalByteCount property has changed. + /// + [Description("Occurs, when the value of HorizontalByteCount property has changed.")] + public event EventHandler HorizontalByteCountChanged; + /// + /// Occurs, when the value of VerticalByteCount property has changed. + /// + [Description("Occurs, when the value of VerticalByteCount property has changed.")] + public event EventHandler VerticalByteCountChanged; + /// + /// Occurs, when the value of CurrentLine property has changed. + /// + [Description("Occurs, when the value of CurrentLine property has changed.")] + public event EventHandler CurrentLineChanged; + /// + /// Occurs, when the value of CurrentPositionInLine property has changed. + /// + [Description("Occurs, when the value of CurrentPositionInLine property has changed.")] + public event EventHandler CurrentPositionInLineChanged; + #endregion + + #region Ctors + /// + /// Initializes a new instance of a HexBox class. + /// + public HexBox() + { + this._vScrollBar = new VScrollBar(); + this._vScrollBar.Scroll += new ScrollEventHandler(_vScrollBar_Scroll); + + BackColor = Color.White; + Font = new Font("Courier New", 9F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(0))); + _stringFormat = new StringFormat(StringFormat.GenericTypographic); + _stringFormat.FormatFlags = StringFormatFlags.MeasureTrailingSpaces; + + ActivateEmptyKeyInterpreter(); + + SetStyle(ControlStyles.UserPaint, true); + SetStyle(ControlStyles.DoubleBuffer, true); + SetStyle(ControlStyles.AllPaintingInWmPaint, true); + SetStyle(ControlStyles.ResizeRedraw, true); + + _thumbTrackTimer.Interval = 50; + _thumbTrackTimer.Tick += new EventHandler(PerformScrollThumbTrack); + } + + #endregion + + #region Scroll methods + void _vScrollBar_Scroll(object sender, ScrollEventArgs e) + { + switch(e.Type) + { + case ScrollEventType.Last: + break; + case ScrollEventType.EndScroll: + break; + case ScrollEventType.SmallIncrement: + PerformScrollLineDown(); + break; + case ScrollEventType.SmallDecrement: + PerformScrollLineUp(); + break; + case ScrollEventType.LargeIncrement: + PerformScrollPageDown(); + break; + case ScrollEventType.LargeDecrement: + PerformScrollPageUp(); + break; + case ScrollEventType.ThumbPosition: + long lPos = FromScrollPos(e.NewValue); + PerformScrollThumpPosition(lPos); + break; + case ScrollEventType.ThumbTrack: + // to avoid performance problems use a refresh delay implemented with a timer + if (_thumbTrackTimer.Enabled) // stop old timer + _thumbTrackTimer.Enabled = false; + + // perform scroll immediately only if last refresh is very old + int currentThumbTrack = System.Environment.TickCount; + if (currentThumbTrack - _lastThumbtrack > THUMPTRACKDELAY) + { + PerformScrollThumbTrack(null, null); + _lastThumbtrack = currentThumbTrack; + break; + } + + // start thumbtrack timer + _thumbTrackPosition = FromScrollPos(e.NewValue); + _thumbTrackTimer.Enabled = true; + break; + case ScrollEventType.First: + break; + default: + break; + } + + e.NewValue = ToScrollPos(_scrollVpos); + } + + /// + /// Performs the thumbtrack scrolling after an delay. + /// + void PerformScrollThumbTrack(object sender, EventArgs e) + { + _thumbTrackTimer.Enabled = false; + PerformScrollThumpPosition(_thumbTrackPosition); + _lastThumbtrack = Environment.TickCount; + } + + void UpdateScrollSize() + { + System.Diagnostics.Debug.WriteLine("UpdateScrollSize()", "HexBox"); + + // calc scroll bar info + if(VScrollBarVisible && _byteProvider != null && _byteProvider.Length > 0 && _iHexMaxHBytes != 0) + { + long scrollmax = (long)Math.Ceiling((double)_byteProvider.Length / (double)_iHexMaxHBytes - (double)_iHexMaxVBytes); + scrollmax = Math.Max(0, scrollmax); + + long scrollpos = _startByte / _iHexMaxHBytes; + + if(scrollmax == _scrollVmax && scrollpos == _scrollVpos) + return; + + _scrollVmin = 0; + _scrollVmax = scrollmax; + _scrollVpos = Math.Min(scrollpos, scrollmax); + UpdateVScroll(); + } + else if(VScrollBarVisible) + { + // disable scroll bar + _scrollVmin = 0; + _scrollVmax = 0; + _scrollVpos = 0; + UpdateVScroll(); + } + } + + void UpdateVScroll() + { + System.Diagnostics.Debug.WriteLine("UpdateVScroll()", "HexBox"); + + int max = ToScrollMax(_scrollVmax); + + if(max > 0) + { + _vScrollBar.Minimum = 0; + _vScrollBar.Maximum = max; + _vScrollBar.Value = ToScrollPos(_scrollVpos); + _vScrollBar.Enabled = true; + } + else + { + _vScrollBar.Enabled = false; + } + } + + int ToScrollPos(long value) + { + int max = 65535; + + if(_scrollVmax < max) + return (int)value; + else + { + double valperc = (double)value / (double)_scrollVmax * (double)100; + int res = (int)Math.Floor((double)max / (double)100 * valperc); + res = (int)Math.Max(_scrollVmin, res); + res = (int)Math.Min(_scrollVmax, res); + return res; + } + } + + long FromScrollPos(int value) + { + int max = 65535; + if(_scrollVmax < max) + { + return (long)value; + } + else + { + double valperc = (double)value / (double)max * (double)100; + long res = (int)Math.Floor((double)_scrollVmax / (double)100 * valperc); + return res; + } + } + + int ToScrollMax(long value) + { + long max = 65535; + if(value > max) + return (int)max; + else + return (int)value; + } + + void PerformScrollToLine(long pos) + { + if(pos < _scrollVmin || pos > _scrollVmax || pos == _scrollVpos ) + return; + + _scrollVpos = pos; + + UpdateVScroll(); + UpdateVisibilityBytes(); + UpdateCaret(); + Invalidate(); + } + + void PerformScrollLines(int lines) + { + long pos; + if(lines > 0) + { + pos = Math.Min(_scrollVmax, _scrollVpos+lines); + } + else if(lines < 0) + { + pos = Math.Max(_scrollVmin, _scrollVpos+lines); + } + else + { + return; + } + + PerformScrollToLine(pos); + } + + void PerformScrollLineDown() + { + this.PerformScrollLines(1); + } + + void PerformScrollLineUp() + { + this.PerformScrollLines(-1); + } + + void PerformScrollPageDown() + { + this.PerformScrollLines(_iHexMaxVBytes); + } + + void PerformScrollPageUp() + { + this.PerformScrollLines(-_iHexMaxVBytes); + } + + void PerformScrollThumpPosition(long pos) + { + // Bug fix: Scroll to end, do not scroll to end + int difference = (_scrollVmax > 65535) ? 10 : 9; + + if(ToScrollPos(pos) == ToScrollMax(_scrollVmax)-difference) + pos = _scrollVmax; + // End Bug fix + + + PerformScrollToLine(pos); + } + + /// + /// Scrolls the selection start byte into view + /// + public void ScrollByteIntoView() + { + System.Diagnostics.Debug.WriteLine("ScrollByteIntoView()", "HexBox"); + + ScrollByteIntoView(_bytePos); + } + + /// + /// Scrolls the specific byte into view + /// + /// the index of the byte + public void ScrollByteIntoView(long index) + { + System.Diagnostics.Debug.WriteLine("ScrollByteIntoView(long index)", "HexBox"); + + if(_byteProvider == null || _keyInterpreter == null) + return; + + if(index < _startByte) + { + long line = (long)Math.Floor((double)index / (double)_iHexMaxHBytes); + PerformScrollThumpPosition(line); + } + else if(index > _endByte) + { + long line = (long)Math.Floor((double)index / (double)_iHexMaxHBytes); + line -= _iHexMaxVBytes-1; + PerformScrollThumpPosition(line); + } + } + #endregion + + #region Selection methods + void ReleaseSelection() + { + System.Diagnostics.Debug.WriteLine("ReleaseSelection()", "HexBox"); + + if(_selectionLength == 0) + return; + _selectionLength = 0; + OnSelectionLengthChanged(EventArgs.Empty); + + if(!_caretVisible) + CreateCaret(); + else + UpdateCaret(); + + Invalidate(); + } + + /// + /// Selects the hex box. + /// + /// the start index of the selection + /// the length of the selection + public void Select(long start, long length) + { + InternalSelect(start, length); + ScrollByteIntoView(); + } + + void InternalSelect(long start, long length) + { + long pos = start; + long sel = length; + int cp = 0; + + if(sel > 0 && _caretVisible) + DestroyCaret(); + else if(sel == 0 && !_caretVisible) + CreateCaret(); + + SetPosition(pos, cp); + SetSelectionLength(sel); + + UpdateCaret(); + Invalidate(); + } + #endregion + + #region Key interpreter methods + void ActivateEmptyKeyInterpreter() + { + if(_eki == null) + _eki = new EmptyKeyInterpreter(this); + + if(_eki == _keyInterpreter) + return; + + if(_keyInterpreter != null) + _keyInterpreter.Deactivate(); + + _keyInterpreter = _eki; + _keyInterpreter.Activate(); + } + + void ActivateKeyInterpreter() + { + if(_ki == null) + _ki = new KeyInterpreter(this); + + if(_ki == _keyInterpreter) + return; + + if(_keyInterpreter != null) + _keyInterpreter.Deactivate(); + + _keyInterpreter = _ki; + _keyInterpreter.Activate(); + } + + void ActivateStringKeyInterpreter() + { + if(_ski == null) + _ski = new StringKeyInterpreter(this); + + if(_ski == _keyInterpreter) + return; + + if(_keyInterpreter != null) + _keyInterpreter.Deactivate(); + + _keyInterpreter = _ski; + _keyInterpreter.Activate(); + } + #endregion + + #region Caret methods + void CreateCaret() + { + if(_byteProvider == null || _keyInterpreter == null || _caretVisible || !this.Focused) + return; + + System.Diagnostics.Debug.WriteLine("CreateCaret()", "HexBox"); + + NativeMethods.CreateCaret(Handle, IntPtr.Zero, 1, (int)_charSize.Height); + + UpdateCaret(); + + NativeMethods.ShowCaret(Handle); + + _caretVisible = true; + } + + void UpdateCaret() + { + if(_byteProvider == null || _keyInterpreter == null ) + return; + + System.Diagnostics.Debug.WriteLine("UpdateCaret()", "HexBox"); + + long byteIndex =_bytePos - _startByte; + PointF p = _keyInterpreter.GetCaretPointF(byteIndex); + p.X += _byteCharacterPos*_charSize.Width; + NativeMethods.SetCaretPos((int)p.X, (int)p.Y); + } + + void DestroyCaret() + { + if(!_caretVisible) + return; + + System.Diagnostics.Debug.WriteLine("DestroyCaret()", "HexBox"); + + NativeMethods.DestroyCaret(); + _caretVisible = false; + } + + void SetCaretPosition(Point p) + { + System.Diagnostics.Debug.WriteLine("SetCaretPosition()", "HexBox"); + + if(_byteProvider == null || _keyInterpreter == null) + return; + + long pos = _bytePos; + int cp = _byteCharacterPos; + + if(_recHex.Contains(p)) + { + BytePositionInfo bpi = GetHexBytePositionInfo(p); + pos = bpi.Index; + cp = bpi.CharacterPosition; + + SetPosition(pos, cp); + + ActivateKeyInterpreter(); + UpdateCaret(); + Invalidate(); + } + else if(_recStringView.Contains(p)) + { + BytePositionInfo bpi = GetStringBytePositionInfo(p); + pos = bpi.Index; + cp = bpi.CharacterPosition; + + SetPosition(pos, cp); + + ActivateStringKeyInterpreter(); + UpdateCaret(); + Invalidate(); + } + } + + BytePositionInfo GetHexBytePositionInfo(Point p) + { + System.Diagnostics.Debug.WriteLine("GetHexBytePositionInfo()", "HexBox"); + + long bytePos; + int byteCharaterPos; + + float x = ((float)(p.X - _recHex.X) / _charSize.Width); + float y = ((float)(p.Y - _recHex.Y) / _charSize.Height); + int iX = (int)x; + int iY = (int)y; + + int hPos = (iX / 3 + 1); + + bytePos = Math.Min(_byteProvider.Length, + _startByte + (_iHexMaxHBytes * (iY+1) - _iHexMaxHBytes) + hPos - 1); + byteCharaterPos = (iX % 3); + if(byteCharaterPos > 1) + byteCharaterPos = 1; + + if(bytePos == _byteProvider.Length) + byteCharaterPos = 0; + + if(bytePos < 0) + return new BytePositionInfo(0, 0); + return new BytePositionInfo(bytePos, byteCharaterPos); + } + + BytePositionInfo GetStringBytePositionInfo(Point p) + { + System.Diagnostics.Debug.WriteLine("GetStringBytePositionInfo()", "HexBox"); + + long bytePos; + int byteCharacterPos; + + float x = ((float)(p.X - _recStringView.X) / _charSize.Width); + float y = ((float)(p.Y - _recStringView.Y) / _charSize.Height); + int iX = (int)x; + int iY = (int)y; + + int hPos = iX+1; + + bytePos = Math.Min(_byteProvider.Length, + _startByte + (_iHexMaxHBytes * (iY+1) - _iHexMaxHBytes) + hPos - 1); + byteCharacterPos = 0; + + if(bytePos < 0) + return new BytePositionInfo(0, 0); + return new BytePositionInfo(bytePos, byteCharacterPos); + } + #endregion + + #region PreProcessMessage methods + /// + /// Preprocesses windows messages. + /// + /// the message to process. + /// true, if the message was processed + [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode=true), SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode=true)] + public override bool PreProcessMessage(ref Message m) + { + switch(m.Msg) + { + case NativeMethods.WM_KEYDOWN: + return _keyInterpreter.PreProcessWmKeyDown(ref m); + case NativeMethods.WM_CHAR: + return _keyInterpreter.PreProcessWmChar(ref m); + case NativeMethods.WM_KEYUP: + return _keyInterpreter.PreProcessWmKeyUp(ref m); + default: + return base.PreProcessMessage (ref m); + } + } + + bool BasePreProcessMessage(ref Message m) + { + return base.PreProcessMessage(ref m); + } + #endregion + + #region Find methods + /// + /// Searches the current ByteProvider + /// + /// the array of bytes to find + /// the start index + /// the SelectionStart property value if find was successfull or + /// -1 if there is no match + /// -2 if Find was aborted. + public long Find(byte[] bytes, long startIndex) + { + int match = 0; + int bytesLength = bytes.Length; + + _abortFind = false; + + for(long pos = startIndex; pos < _byteProvider.Length; pos++) + { + if(_abortFind) + return -2; + + if(pos % 1000 == 0) // for performance reasons: DoEvents only 1 times per 1000 loops + Application.DoEvents(); + + if(_byteProvider.ReadByte(pos) != bytes[match]) + { + pos -= match; + match = 0; + _findingPos = pos; + continue; + } + + match++; + + if(match == bytesLength) + { + long bytePos = pos-bytesLength+1; + Select(bytePos, bytesLength); + ScrollByteIntoView(_bytePos+_selectionLength); + ScrollByteIntoView(_bytePos); + + return bytePos; + } + } + + return -1; + } + + /// + /// Aborts a working Find method. + /// + public void AbortFind() + { + _abortFind = true; + } + + /// + /// Gets a value that indicates the current position during Find method execution. + /// + [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public long CurrentFindingPosition + { + get + { + return _findingPos; + } + } + #endregion + + #region Copy, Cut and Paste methods + /// + /// Copies the current selection in the hex box to the Clipboard. + /// + public void Copy() + { + if(!CanCopy()) return; + + // put bytes into buffer + byte[] buffer = new byte[_selectionLength]; + int id = -1; + for(long i = _bytePos; i < _bytePos+_selectionLength; i++) + { + id++; + + buffer[id] = _byteProvider.ReadByte(i); + } + + DataObject da = new DataObject(); + + // set string buffer clipbard data + string sBuffer = System.Text.Encoding.ASCII.GetString(buffer, 0, buffer.Length); + da.SetData(typeof(string), sBuffer); + + //set memorystream (BinaryData) clipboard data + System.IO.MemoryStream ms = new System.IO.MemoryStream(buffer, 0, buffer.Length, false, true); + da.SetData("BinaryData", ms); + + Clipboard.SetDataObject(da, true); + UpdateCaret(); + ScrollByteIntoView(); + Invalidate(); + } + + /// + /// Return true if Copy method could be invoked. + /// + public bool CanCopy() + { + if(_selectionLength < 1 || _byteProvider == null) + return false; + + return true; + } + + /// + /// Moves the current selection in the hex box to the Clipboard. + /// + public void Cut() + { + if(!CanCut()) return; + + Copy(); + + _byteProvider.DeleteBytes(_bytePos, _selectionLength); + _byteCharacterPos = 0; + UpdateCaret(); + ScrollByteIntoView(); + ReleaseSelection(); + Invalidate(); + Refresh(); + } + + /// + /// Return true if Cut method could be invoked. + /// + public bool CanCut() + { + if (ReadOnly || !this.Enabled) + return false; + if(_byteProvider == null) + return false; + if(_selectionLength < 1 || !_byteProvider.SupportsDeleteBytes()) + return false; + + return true; + } + + /// + /// Replaces the current selection in the hex box with the contents of the Clipboard. + /// + public void Paste() + { + if(!CanPaste()) return; + + if(_selectionLength > 0) + _byteProvider.DeleteBytes(_bytePos, _selectionLength); + + byte[] buffer = null; + IDataObject da = Clipboard.GetDataObject(); + if(da.GetDataPresent("BinaryData")) + { + System.IO.MemoryStream ms = (System.IO.MemoryStream)da.GetData("BinaryData"); + buffer = new byte[ms.Length]; + ms.Read(buffer, 0, buffer.Length); + + } + else if(da.GetDataPresent(typeof(string))) + { + string sBuffer = (string)da.GetData(typeof(string)); + buffer = System.Text.Encoding.ASCII.GetBytes(sBuffer); + } + else + { + return; + } + + _byteProvider.InsertBytes(_bytePos, buffer); + + SetPosition(_bytePos + buffer.Length, 0); + + ReleaseSelection(); + ScrollByteIntoView(); + UpdateCaret(); + Invalidate(); + } + + /// + /// Return true if Paste method could be invoked. + /// + public bool CanPaste() + { + if (ReadOnly || !this.Enabled) return false; + + if(_byteProvider == null || !_byteProvider.SupportsInsertBytes()) + return false; + + if(!_byteProvider.SupportsDeleteBytes() && _selectionLength > 0) + return false; + + IDataObject da = Clipboard.GetDataObject(); + if(da.GetDataPresent("BinaryData")) + return true; + else if(da.GetDataPresent(typeof(string))) + return true; + else + return false; + } + + #endregion + + #region Paint methods + /// + /// Paints the background. + /// + /// A PaintEventArgs that contains the event data. + protected override void OnPaintBackground(PaintEventArgs e) + { + switch(_borderStyle) + { + case BorderStyle.Fixed3D: + { + if(TextBoxRenderer.IsSupported) + { + VisualStyleElement state = VisualStyleElement.TextBox.TextEdit.Normal; + Color backColor = this.BackColor; + + if (this.Enabled) + { + if (this.ReadOnly) + state = VisualStyleElement.TextBox.TextEdit.ReadOnly; + else if (this.Focused) + state = VisualStyleElement.TextBox.TextEdit.Focused; + } + else + { + state = VisualStyleElement.TextBox.TextEdit.Disabled; + backColor = this.BackColorDisabled; + } + + VisualStyleRenderer vsr = new VisualStyleRenderer(state); + vsr.DrawBackground(e.Graphics, this.ClientRectangle); + + Rectangle rectContent = vsr.GetBackgroundContentRectangle(e.Graphics, this.ClientRectangle); + e.Graphics.FillRectangle(new SolidBrush(backColor), rectContent); + } + else + { + // draw background + e.Graphics.FillRectangle(new SolidBrush(BackColor), ClientRectangle); + + // draw default border + ControlPaint.DrawBorder3D(e.Graphics, ClientRectangle, Border3DStyle.Sunken); + } + + break; + } + case BorderStyle.FixedSingle: + { + // draw background + e.Graphics.FillRectangle(new SolidBrush(BackColor), ClientRectangle); + + // draw fixed single border + ControlPaint.DrawBorder(e.Graphics, ClientRectangle, Color.Black, ButtonBorderStyle.Solid); + break; + } + } + } + + + /// + /// Paints the hex box. + /// + /// A PaintEventArgs that contains the event data. + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + + if(_byteProvider == null) + return; + + // draw only in the content rectangle, so exclude the border and the scrollbar. + Region r = new Region(ClientRectangle); + r.Exclude(_recContent); + e.Graphics.ExcludeClip(r); + + UpdateVisibilityBytes(); + + if(_lineInfoVisible) + PaintLineInfo(e.Graphics, _startByte, _endByte); + + if(!_stringViewVisible) + { + PaintHex(e.Graphics, _startByte, _endByte); + } + else + { + PaintHexAndStringView(e.Graphics, _startByte, _endByte); + if(_shadowSelectionVisible) + PaintCurrentBytesSign(e.Graphics); + } + } + + + void PaintLineInfo(Graphics g, long startByte, long endByte) + { + // Ensure endByte isn't > length of array. + endByte = Math.Min(_byteProvider.Length-1, endByte); + + Color lineInfoColor = (this.LineInfoForeColor != Color.Empty) ? this.LineInfoForeColor : this.ForeColor; + Brush brush = new SolidBrush(lineInfoColor); + + int maxLine = GetGridBytePoint(endByte-startByte).Y+1; + + for(int i = 0; i < maxLine; i++) + { + long firstLineByte = startByte + (_iHexMaxHBytes)*i; + + PointF bytePointF = GetBytePointF(new Point(0, 0+i)); + string info = firstLineByte.ToString(_hexStringFormat, System.Threading.Thread.CurrentThread.CurrentCulture); + int nulls = 8-info.Length; + string formattedInfo; + if(nulls > -1) + { + formattedInfo = new string('0', 8-info.Length) + info; + } + else + { + formattedInfo = new string('~', 8); + } + + g.DrawString(formattedInfo, Font, brush, new PointF(_recLineInfo.X, bytePointF.Y), _stringFormat); + } + } + + void PaintHex(Graphics g, long startByte, long endByte) + { + Brush brush = new SolidBrush(GetDefaultForeColor()); + Brush selBrush = new SolidBrush(_selectionForeColor); + Brush selBrushBack = new SolidBrush(_selectionBackColor); + + int counter = -1; + long intern_endByte = Math.Min(_byteProvider.Length-1, endByte+_iHexMaxHBytes); + + bool isKeyInterpreterActive = _keyInterpreter == null || _keyInterpreter.GetType() == typeof(KeyInterpreter); + + for(long i = startByte; i < intern_endByte+1; i++) + { + counter++; + Point gridPoint = GetGridBytePoint(counter); + byte b = _byteProvider.ReadByte(i); + + bool isSelectedByte = i >= _bytePos && i <= (_bytePos + _selectionLength-1) && _selectionLength != 0; + + if(isSelectedByte && isKeyInterpreterActive) + { + PaintHexStringSelected(g, b, selBrush, selBrushBack, gridPoint); + } + else + { + PaintHexString(g, b, brush, gridPoint); + } + } + } + + void PaintHexString(Graphics g, byte b, Brush brush, Point gridPoint) + { + PointF bytePointF = GetBytePointF(gridPoint); + + string sB = b.ToString(_hexStringFormat, System.Threading.Thread.CurrentThread.CurrentCulture); + if(sB.Length == 1) + sB = "0" + sB; + + g.DrawString(sB.Substring(0,1), Font, brush, bytePointF, _stringFormat); + bytePointF.X += _charSize.Width; + g.DrawString(sB.Substring(1,1), Font, brush, bytePointF, _stringFormat); + } + + void PaintHexStringSelected(Graphics g, byte b, Brush brush, Brush brushBack, Point gridPoint) + { + string sB = b.ToString(_hexStringFormat, System.Threading.Thread.CurrentThread.CurrentCulture); + if(sB.Length == 1) + sB = "0" + sB; + + PointF bytePointF = GetBytePointF(gridPoint); + + bool isLastLineChar = (gridPoint.X+1 == _iHexMaxHBytes); + float bcWidth = (isLastLineChar) ? _charSize.Width*2 : _charSize.Width*3; + + g.FillRectangle(brushBack, bytePointF.X, bytePointF.Y, bcWidth, _charSize.Height); + g.DrawString(sB.Substring(0,1), Font, brush, bytePointF, _stringFormat); + bytePointF.X += _charSize.Width; + g.DrawString(sB.Substring(1,1), Font, brush, bytePointF, _stringFormat); + } + + void PaintHexAndStringView(Graphics g, long startByte, long endByte) + { + Brush brush = new SolidBrush(GetDefaultForeColor()); + Brush selBrush = new SolidBrush(_selectionForeColor); + Brush selBrushBack = new SolidBrush(_selectionBackColor); + + int counter = -1; + long intern_endByte = Math.Min(_byteProvider.Length-1, endByte+_iHexMaxHBytes); + + bool isKeyInterpreterActive = _keyInterpreter == null || _keyInterpreter.GetType() == typeof(KeyInterpreter); + bool isStringKeyInterpreterActive = _keyInterpreter != null && _keyInterpreter.GetType() == typeof(StringKeyInterpreter); + + for(long i = startByte; i < intern_endByte+1; i++) + { + counter++; + Point gridPoint = GetGridBytePoint(counter); + PointF byteStringPointF = GetByteStringPointF(gridPoint); + byte b = _byteProvider.ReadByte(i); + + bool isSelectedByte = i >= _bytePos && i <= (_bytePos + _selectionLength-1) && _selectionLength != 0; + + if(isSelectedByte && isKeyInterpreterActive) + { + PaintHexStringSelected(g, b, selBrush, selBrushBack, gridPoint); + } + else + { + PaintHexString(g, b, brush, gridPoint); + } + + string s; + if(b > 0x1F && !(b > 0x7E && b < 0xA0) ) + { + s = ((char)b).ToString(); + } + else + { + s = "."; + } + + if(isSelectedByte && isStringKeyInterpreterActive) + { + g.FillRectangle(selBrushBack, byteStringPointF.X, byteStringPointF.Y, _charSize.Width, _charSize.Height); + g.DrawString(s, Font, selBrush, byteStringPointF, _stringFormat); + } + else + { + g.DrawString(s, Font, brush, byteStringPointF, _stringFormat); + } + } + } + + void PaintCurrentBytesSign(Graphics g) + { + if(_keyInterpreter != null && Focused && _bytePos != -1 && Enabled) + { + if(_keyInterpreter.GetType() == typeof(KeyInterpreter)) + { + if(_selectionLength == 0) + { + Point gp = GetGridBytePoint(_bytePos - _startByte); + PointF pf = GetByteStringPointF(gp); + Size s = new Size((int)_charSize.Width, (int)_charSize.Height); + Rectangle r = new Rectangle((int)pf.X, (int)pf.Y, s.Width, s.Height); + if(r.IntersectsWith(_recStringView)) + { + r.Intersect(_recStringView); + PaintCurrentByteSign(g, r); + } + } + else + { + int lineWidth = (int)(_recStringView.Width-_charSize.Width); + + Point startSelGridPoint = GetGridBytePoint(_bytePos-_startByte); + PointF startSelPointF = GetByteStringPointF(startSelGridPoint); + + Point endSelGridPoint = GetGridBytePoint(_bytePos-_startByte+_selectionLength-1); + PointF endSelPointF = GetByteStringPointF(endSelGridPoint); + + int multiLine = endSelGridPoint.Y - startSelGridPoint.Y; + if(multiLine == 0) + { + Rectangle singleLine = new Rectangle( + (int)startSelPointF.X, + (int)startSelPointF.Y, + (int)(endSelPointF.X-startSelPointF.X+_charSize.Width), + (int)_charSize.Height); + if(singleLine.IntersectsWith(_recStringView)) + { + singleLine.Intersect(_recStringView); + PaintCurrentByteSign(g, singleLine); + } + } + else + { + Rectangle firstLine = new Rectangle( + (int)startSelPointF.X, + (int)startSelPointF.Y, + (int)(_recStringView.X+lineWidth-startSelPointF.X+_charSize.Width), + (int)_charSize.Height); + if(firstLine.IntersectsWith(_recStringView)) + { + firstLine.Intersect(_recStringView); + PaintCurrentByteSign(g, firstLine); + } + + if(multiLine > 1) + { + Rectangle betweenLines = new Rectangle( + _recStringView.X, + (int)(startSelPointF.Y+_charSize.Height), + (int)(_recStringView.Width), + (int)(_charSize.Height*(multiLine-1))); + if(betweenLines.IntersectsWith(_recStringView)) + { + betweenLines.Intersect(_recStringView); + PaintCurrentByteSign(g, betweenLines); + } + + } + + Rectangle lastLine = new Rectangle( + _recStringView.X, + (int)endSelPointF.Y, + (int)(endSelPointF.X-_recStringView.X+_charSize.Width), + (int)_charSize.Height); + if(lastLine.IntersectsWith(_recStringView)) + { + lastLine.Intersect(_recStringView); + PaintCurrentByteSign(g, lastLine); + } + } + } + } + else + { + if(_selectionLength == 0) + { + Point gp = GetGridBytePoint(_bytePos - _startByte); + PointF pf = GetBytePointF(gp); + Size s = new Size((int)_charSize.Width * 2, (int)_charSize.Height); + Rectangle r = new Rectangle((int)pf.X, (int)pf.Y, s.Width, s.Height); + PaintCurrentByteSign(g, r); + } + else + { + int lineWidth = (int)(_recHex.Width-_charSize.Width*5); + + Point startSelGridPoint = GetGridBytePoint(_bytePos-_startByte); + PointF startSelPointF = GetBytePointF(startSelGridPoint); + + Point endSelGridPoint = GetGridBytePoint(_bytePos-_startByte+_selectionLength-1); + PointF endSelPointF = GetBytePointF(endSelGridPoint); + + int multiLine = endSelGridPoint.Y - startSelGridPoint.Y; + if(multiLine == 0) + { + Rectangle singleLine = new Rectangle( + (int)startSelPointF.X, + (int)startSelPointF.Y, + (int)(endSelPointF.X-startSelPointF.X+_charSize.Width*2), + (int)_charSize.Height); + if(singleLine.IntersectsWith(_recHex)) + { + singleLine.Intersect(_recHex); + PaintCurrentByteSign(g, singleLine); + } + } + else + { + Rectangle firstLine = new Rectangle( + (int)startSelPointF.X, + (int)startSelPointF.Y, + (int)(_recHex.X+lineWidth-startSelPointF.X+_charSize.Width*2), + (int)_charSize.Height); + if(firstLine.IntersectsWith(_recHex)) + { + firstLine.Intersect(_recHex); + PaintCurrentByteSign(g, firstLine); + } + + if(multiLine > 1) + { + Rectangle betweenLines = new Rectangle( + _recHex.X, + (int)(startSelPointF.Y+_charSize.Height), + (int)(lineWidth+_charSize.Width*2), + (int)(_charSize.Height*(multiLine-1))); + if(betweenLines.IntersectsWith(_recHex)) + { + betweenLines.Intersect(_recHex); + PaintCurrentByteSign(g, betweenLines); + } + + } + + Rectangle lastLine = new Rectangle( + _recHex.X, + (int)endSelPointF.Y, + (int)(endSelPointF.X-_recHex.X+_charSize.Width*2), + (int)_charSize.Height); + if(lastLine.IntersectsWith(_recHex)) + { + lastLine.Intersect(_recHex); + PaintCurrentByteSign(g, lastLine); + } + } + } + } + } + } + + void PaintCurrentByteSign(Graphics g, Rectangle rec) + { + // stack overflowexception on big files - workaround + if(rec.Top < 0 || rec.Left < 0 || rec.Width <= 0 || rec.Height <= 0) + return; + + Bitmap myBitmap = new Bitmap(rec.Width, rec.Height); + Graphics bitmapGraphics = Graphics.FromImage(myBitmap); + + SolidBrush greenBrush = new SolidBrush(_shadowSelectionColor); + + bitmapGraphics.FillRectangle(greenBrush, 0, + 0, rec.Width, rec.Height); + + g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.GammaCorrected; + + g.DrawImage(myBitmap, rec.Left, rec.Top); + } + + Color GetDefaultForeColor() + { + if(Enabled) + return ForeColor; + else + return Color.Gray; + } + void UpdateVisibilityBytes() + { + if(_byteProvider == null || _byteProvider.Length == 0) + return; + + _startByte = (_scrollVpos+1) * _iHexMaxHBytes - _iHexMaxHBytes; + _endByte = (long)Math.Min(_byteProvider.Length - 1, _startByte + _iHexMaxBytes); + } + #endregion + + #region Positioning methods + void UpdateRectanglePositioning() + { + // calc char size + SizeF charSize = this.CreateGraphics().MeasureString("A", Font, 100, _stringFormat); + _charSize = new SizeF((float)Math.Ceiling(charSize.Width), (float)Math.Ceiling(charSize.Height)); + + // calc content bounds + _recContent = ClientRectangle; + _recContent.X += _recBorderLeft; + _recContent.Y += _recBorderTop; + _recContent.Width -= _recBorderRight+_recBorderLeft; + _recContent.Height -= _recBorderBottom+_recBorderTop; + + if(_vScrollBarVisible) + { + _recContent.Width -= _vScrollBar.Width; + _vScrollBar.Left = _recContent.X+_recContent.Width; + _vScrollBar.Top = _recContent.Y; + _vScrollBar.Height = _recContent.Height; + } + + int marginLeft = 4; + + // calc line info bounds + if(_lineInfoVisible) + { + _recLineInfo = new Rectangle(_recContent.X+marginLeft, + _recContent.Y, + (int)(_charSize.Width*10), + _recContent.Height); + } + else + { + _recLineInfo = Rectangle.Empty; + _recLineInfo.X = marginLeft; + } + + // calc hex bounds and grid + _recHex = new Rectangle(_recLineInfo.X + _recLineInfo.Width, + _recLineInfo.Y, + _recContent.Width - _recLineInfo.Width, + _recContent.Height); + + if(UseFixedBytesPerLine) + { + SetHorizontalByteCount(_bytesPerLine); + _recHex.Width = (int)Math.Floor(((double)_iHexMaxHBytes)*_charSize.Width*3+(2*_charSize.Width)); + } + else + { + int hmax = (int)Math.Floor((double)_recHex.Width/(double)_charSize.Width); + if(hmax > 1) + SetHorizontalByteCount((int)Math.Floor((double)hmax/3)); + else + SetHorizontalByteCount(hmax); + } + + if(_stringViewVisible) + { + _recStringView = new Rectangle(_recHex.X + _recHex.Width, + _recHex.Y, + (int)(_charSize.Width*_iHexMaxHBytes), + _recHex.Height); + } + else + { + _recStringView = Rectangle.Empty; + } + + int vmax = (int)Math.Floor((double)_recHex.Height/(double)_charSize.Height); + SetVerticalByteCount(vmax); + + _iHexMaxBytes = _iHexMaxHBytes * _iHexMaxVBytes; + + UpdateScrollSize(); + } + + PointF GetBytePointF(long byteIndex) + { + Point gp = GetGridBytePoint(byteIndex); + + return GetBytePointF(gp); + } + + PointF GetBytePointF(Point gp) + { + float x = (3 * _charSize.Width) * gp.X + _recHex.X; + float y = (gp.Y+1)*_charSize.Height-_charSize.Height+_recHex.Y; + + return new PointF(x,y); + } + + PointF GetByteStringPointF(Point gp) + { + float x = (_charSize.Width) * gp.X + _recStringView.X; + float y = (gp.Y+1)*_charSize.Height-_charSize.Height+_recStringView.Y; + + return new PointF(x,y); + } + + Point GetGridBytePoint(long byteIndex) + { + int row = (int)Math.Floor((double)byteIndex/(double)_iHexMaxHBytes); + int column = (int)(byteIndex+_iHexMaxHBytes-_iHexMaxHBytes*(row+1)); + + Point res = new Point(column, row); + return res; + } + #endregion + + #region Overridden properties + /// + /// Gets or sets the background color for the control. + /// + [DefaultValue(typeof(Color), "White")] + public override Color BackColor + { + get + { + return base.BackColor; + } + set + { + base.BackColor = value; + } + } + + /// + /// The font used to display text in the hexbox. + /// + [Editor(typeof(HexFontEditor), typeof(System.Drawing.Design.UITypeEditor))] + public override Font Font + { + get + { + return base.Font; + } + set + { + base.Font = value; + } + } + + /// + /// Not used. + /// + [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Never), Bindable(false)] + public override string Text + { + get + { + return base.Text; + } + set + { + base.Text = value; + } + } + + /// + /// Not used. + /// + [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Never), Bindable(false)] + public override RightToLeft RightToLeft + { + get + { + return base.RightToLeft; + } + set + { + base.RightToLeft = value; + } + } + #endregion + + #region Properties + /// + /// Gets or sets the background color for the disabled control. + /// + [Category("Appearance"), DefaultValue(typeof(Color), "WhiteSmoke")] + public Color BackColorDisabled + { + get + { + return _backColorDisabled; + } + set + { + _backColorDisabled = value; + } + } Color _backColorDisabled = Color.FromName("WhiteSmoke"); + + /// + /// Gets or sets if the count of bytes in one line is fix. + /// + /// + /// When set to True, BytesPerLine property determine the maximum count of bytes in one line. + /// + [DefaultValue(false), Category("Hex"), Description("Gets or sets if the count of bytes in one line is fix.")] + public bool ReadOnly + { + get { return _readOnly; } + set + { + if(_readOnly == value) + return; + + _readOnly = value; + OnReadOnlyChanged(EventArgs.Empty); + Invalidate(); + } + } bool _readOnly; + + /// + /// Gets or sets the maximum count of bytes in one line. + /// + /// + /// UsedFixedBytesPerLine property must set to true + /// + [DefaultValue(16), Category("Hex"), Description("Gets or sets the maximum count of bytes in one line.")] + public int BytesPerLine + { + get { return _bytesPerLine; } + set + { + if(_bytesPerLine == value) + return; + + _bytesPerLine = value; + OnByteProviderChanged(EventArgs.Empty); + + UpdateRectanglePositioning(); + Invalidate(); + } + } int _bytesPerLine = 16; + + /// + /// Gets or sets if the count of bytes in one line is fix. + /// + /// + /// When set to True, BytesPerLine property determine the maximum count of bytes in one line. + /// + [DefaultValue(false), Category("Hex"), Description("Gets or sets if the count of bytes in one line is fix.")] + public bool UseFixedBytesPerLine + { + get { return _useFixedBytesPerLine; } + set + { + if(_useFixedBytesPerLine == value) + return; + + _useFixedBytesPerLine = value; + OnUseFixedBytesPerLineChanged(EventArgs.Empty); + + UpdateRectanglePositioning(); + Invalidate(); + } + } bool _useFixedBytesPerLine; + + /// + /// Gets or sets the visibility of a vertical scroll bar. + /// + [DefaultValue(false), Category("Hex"), Description("Gets or sets the visibility of a vertical scroll bar.")] + public bool VScrollBarVisible + { + get { return this._vScrollBarVisible; } + set + { + if(_vScrollBarVisible == value) + return; + + _vScrollBarVisible = value; + + if(_vScrollBarVisible) + Controls.Add(_vScrollBar); + else + Controls.Remove(_vScrollBar); + + UpdateRectanglePositioning(); + UpdateScrollSize(); + + OnVScrollBarVisibleChanged(EventArgs.Empty); + } + } bool _vScrollBarVisible; + + /// + /// Gets or sets the ByteProvider. + /// + [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IByteProvider ByteProvider + { + get { return _byteProvider; } + set + { + if(_byteProvider == value) + return; + + if(value == null) + ActivateEmptyKeyInterpreter(); + else + ActivateKeyInterpreter(); + + if(_byteProvider != null) + _byteProvider.LengthChanged -= new EventHandler(_byteProvider_LengthChanged); + + _byteProvider = value; + if(_byteProvider != null) + _byteProvider.LengthChanged += new EventHandler(_byteProvider_LengthChanged); + + OnByteProviderChanged(EventArgs.Empty); + + if(value == null) // do not raise events if value is null + { + _bytePos = -1; + _byteCharacterPos = 0; + _selectionLength = 0; + + DestroyCaret(); + } + else + { + SetPosition(0, 0); + SetSelectionLength(0); + + if(_caretVisible && Focused) + UpdateCaret(); + else + CreateCaret(); + } + + CheckCurrentLineChanged(); + CheckCurrentPositionInLineChanged(); + + _scrollVpos = 0; + + UpdateVisibilityBytes(); + UpdateRectanglePositioning(); + + + Invalidate(); + } + } IByteProvider _byteProvider; + + /// + /// Gets or sets the visibility of a line info. + /// + [DefaultValue(false), Category("Hex"), Description("Gets or sets the visibility of a line info.")] + public bool LineInfoVisible + { + get { return _lineInfoVisible; } + set + { + if(_lineInfoVisible == value) + return; + + _lineInfoVisible = value; + OnLineInfoVisibleChanged(EventArgs.Empty); + + UpdateRectanglePositioning(); + Invalidate(); + } + } bool _lineInfoVisible; + + /// + /// Gets or sets the hex box´s border style. + /// + [DefaultValue(typeof(BorderStyle), "Fixed3D"), Category("Hex"), Description("Gets or sets the hex box´s border style.")] + public BorderStyle BorderStyle + { + get { return _borderStyle;} + set + { + if(_borderStyle == value) + return; + + _borderStyle = value; + switch(_borderStyle) + { + case BorderStyle.None: + _recBorderLeft = _recBorderTop = _recBorderRight = _recBorderBottom = 0; + break; + case BorderStyle.Fixed3D: + _recBorderLeft = _recBorderRight = SystemInformation.Border3DSize.Width; + _recBorderTop = _recBorderBottom = SystemInformation.Border3DSize.Height; + break; + case BorderStyle.FixedSingle: + _recBorderLeft = _recBorderTop = _recBorderRight = _recBorderBottom = 1; + break; + } + + UpdateRectanglePositioning(); + + OnBorderStyleChanged(EventArgs.Empty); + + } + } BorderStyle _borderStyle = BorderStyle.Fixed3D; + + /// + /// Gets or sets the visibility of the string view. + /// + [DefaultValue(false), Category("Hex"), Description("Gets or sets the visibility of the string view.")] + public bool StringViewVisible + { + get { return _stringViewVisible; } + set + { + if(_stringViewVisible == value) + return; + + _stringViewVisible = value; + OnStringViewVisibleChanged(EventArgs.Empty); + + UpdateRectanglePositioning(); + Invalidate(); + } + } bool _stringViewVisible; + + /// + /// Gets or sets whether the HexBox control displays the hex characters in upper or lower case. + /// + [DefaultValue(typeof(HexCasing), "Upper"), Category("Hex"), Description("Gets or sets whether the HexBox control displays the hex characters in upper or lower case.")] + public HexCasing HexCasing + { + get + { + if(_hexStringFormat == "X") + return HexCasing.Upper; + else + return HexCasing.Lower; + } + set + { + string format; + if(value == HexCasing.Upper) + format = "X"; + else + format = "x"; + + if(_hexStringFormat == format) + return; + + _hexStringFormat = format; + OnHexCasingChanged(EventArgs.Empty); + + Invalidate(); + } + } + + /// + /// Gets and sets the starting point of the bytes selected in the hex box. + /// + [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public long SelectionStart + { + get { return _bytePos; } + set + { + SetPosition(value, 0); + ScrollByteIntoView(); + Invalidate(); + } + } + + /// + /// Gets and sets the number of bytes selected in the hex box. + /// + [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public long SelectionLength + { + get { return _selectionLength; } + set + { + SetSelectionLength(value); + ScrollByteIntoView(); + Invalidate(); + } + } long _selectionLength; + + + /// + /// Gets or sets the line info color. When this property is null, then ForeColor property is used. + /// + [DefaultValue(typeof(Color), "Empty"), Category("Hex"), Description("Gets or sets the line info color. When this property is null, then ForeColor property is used.")] + public Color LineInfoForeColor + { + get { return _lineInfoForeColor; } + set { _lineInfoForeColor = value; Invalidate(); } + } Color _lineInfoForeColor = Color.Empty; + + /// + /// Gets or sets the background color for the selected bytes. + /// + [DefaultValue(typeof(Color), "Blue"), Category("Hex"), Description("Gets or sets the background color for the selected bytes.")] + public Color SelectionBackColor + { + get { return _selectionBackColor; } + set { _selectionBackColor = value; Invalidate(); } + } Color _selectionBackColor = Color.Blue; + + /// + /// Gets or sets the foreground color for the selected bytes. + /// + [DefaultValue(typeof(Color), "White"), Category("Hex"), Description("Gets or sets the foreground color for the selected bytes.")] + public Color SelectionForeColor + { + get { return _selectionForeColor; } + set { _selectionForeColor = value; Invalidate(); } + } Color _selectionForeColor = Color.White; + + /// + /// Gets or sets the visibility of a shadow selection. + /// + [DefaultValue(true), Category("Hex"), Description("Gets or sets the visibility of a shadow selection.")] + public bool ShadowSelectionVisible + { + get { return _shadowSelectionVisible; } + set + { + if(_shadowSelectionVisible == value) + return; + _shadowSelectionVisible = value; + Invalidate(); + } + } bool _shadowSelectionVisible = true; + + /// + /// Gets or sets the color of the shadow selection. + /// + /// + /// A alpha component must be given! + /// Default alpha = 100 + /// + [Category("Hex"), Description("Gets or sets the color of the shadow selection.")] + public Color ShadowSelectionColor + { + get { return _shadowSelectionColor; } + set { _shadowSelectionColor = value; Invalidate(); } + } Color _shadowSelectionColor = Color.FromArgb(100, 60, 188, 255); + + /// + /// Gets the number bytes drawn horizontally. + /// + [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int HorizontalByteCount + { + get { return _iHexMaxHBytes; } + } + + /// + /// Gets the number bytes drawn vertically. + /// + [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public int VerticalByteCount + { + get { return _iHexMaxVBytes; } + } + + /// + /// Gets the current line + /// + [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public long CurrentLine + { + get { return _currentLine; } + } long _currentLine; + + /// + /// Gets the current position in the current line + /// + [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public long CurrentPositionInLine + { + get { return _currentPositionInLine; } + } int _currentPositionInLine; + + /// + /// Gets the a value if insertion mode is active or not. + /// + [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public bool InsertActive + { + get { return _insertActive; } + } + + #endregion + + #region Misc + void SetPosition(long bytePos) + { + SetPosition(bytePos, _byteCharacterPos); + } + + void SetPosition(long bytePos, int byteCharacterPos) + { + if(_byteCharacterPos != byteCharacterPos) + { + _byteCharacterPos = byteCharacterPos; + } + + if(bytePos != _bytePos) + { + _bytePos = bytePos; + CheckCurrentLineChanged(); + CheckCurrentPositionInLineChanged(); + + OnSelectionStartChanged(EventArgs.Empty); + } + } + + void SetSelectionLength(long selectionLength) + { + if(selectionLength != _selectionLength) + { + _selectionLength = selectionLength; + OnSelectionLengthChanged(EventArgs.Empty); + } + } + + void SetHorizontalByteCount(int value) + { + if(_iHexMaxHBytes == value) + return; + + _iHexMaxHBytes = value; + OnHorizontalByteCountChanged(EventArgs.Empty); + } + + void SetVerticalByteCount(int value) + { + if(_iHexMaxVBytes == value) + return; + + _iHexMaxVBytes = value; + OnVerticalByteCountChanged(EventArgs.Empty); + } + + void CheckCurrentLineChanged() + { + long currentLine = (long)Math.Floor((double)_bytePos / (double)_iHexMaxHBytes) + 1; + + if(_byteProvider == null && _currentLine != 0) + { + _currentLine = 0; + OnCurrentLineChanged(EventArgs.Empty); + } + else if(currentLine != _currentLine) + { + _currentLine = currentLine; + OnCurrentLineChanged(EventArgs.Empty); + } + } + + void CheckCurrentPositionInLineChanged() + { + Point gb = GetGridBytePoint(_bytePos); + int currentPositionInLine = gb.X + 1; + + if(_byteProvider == null && _currentPositionInLine != 0) + { + _currentPositionInLine = 0; + OnCurrentPositionInLineChanged(EventArgs.Empty); + } + else if(currentPositionInLine != _currentPositionInLine) + { + _currentPositionInLine = currentPositionInLine; + OnCurrentPositionInLineChanged(EventArgs.Empty); + } + } + + /// + /// Raises the InsertActiveChanged event. + /// + /// An EventArgs that contains the event data. + protected virtual void OnInsertActiveChanged(EventArgs e) + { + if(InsertActiveChanged != null) + InsertActiveChanged(this, e); + } + + /// + /// Raises the ReadOnlyChanged event. + /// + /// An EventArgs that contains the event data. + protected virtual void OnReadOnlyChanged(EventArgs e) + { + if(ReadOnlyChanged != null) + ReadOnlyChanged(this, e); + } + + /// + /// Raises the ByteProviderChanged event. + /// + /// An EventArgs that contains the event data. + protected virtual void OnByteProviderChanged(EventArgs e) + { + if(ByteProviderChanged != null) + ByteProviderChanged(this, e); + } + + /// + /// Raises the SelectionStartChanged event. + /// + /// An EventArgs that contains the event data. + protected virtual void OnSelectionStartChanged(EventArgs e) + { + if(SelectionStartChanged != null) + SelectionStartChanged(this, e); + } + + /// + /// Raises the SelectionLengthChanged event. + /// + /// An EventArgs that contains the event data. + protected virtual void OnSelectionLengthChanged(EventArgs e) + { + if(SelectionLengthChanged != null) + SelectionLengthChanged(this, e); + } + + /// + /// Raises the LineInfoVisibleChanged event. + /// + /// An EventArgs that contains the event data. + protected virtual void OnLineInfoVisibleChanged(EventArgs e) + { + if(LineInfoVisibleChanged != null) + LineInfoVisibleChanged(this, e); + } + + /// + /// Raises the StringViewVisibleChanged event. + /// + /// An EventArgs that contains the event data. + protected virtual void OnStringViewVisibleChanged(EventArgs e) + { + if(StringViewVisibleChanged != null) + StringViewVisibleChanged(this, e); + } + + /// + /// Raises the BorderStyleChanged event. + /// + /// An EventArgs that contains the event data. + protected virtual void OnBorderStyleChanged(EventArgs e) + { + if(BorderStyleChanged != null) + BorderStyleChanged(this, e); + } + + /// + /// Raises the UseFixedBytesPerLineChanged event. + /// + /// An EventArgs that contains the event data. + protected virtual void OnUseFixedBytesPerLineChanged(EventArgs e) + { + if(UseFixedBytesPerLineChanged != null) + UseFixedBytesPerLineChanged(this, e); + } + + /// + /// Raises the BytesPerLineChanged event. + /// + /// An EventArgs that contains the event data. + protected virtual void OnBytesPerLineChanged(EventArgs e) + { + if(BytesPerLineChanged != null) + BytesPerLineChanged(this, e); + } + + /// + /// Raises the VScrollBarVisibleChanged event. + /// + /// An EventArgs that contains the event data. + protected virtual void OnVScrollBarVisibleChanged(EventArgs e) + { + if(VScrollBarVisibleChanged != null) + VScrollBarVisibleChanged(this, e); + } + + /// + /// Raises the HexCasingChanged event. + /// + /// An EventArgs that contains the event data. + protected virtual void OnHexCasingChanged(EventArgs e) + { + if(HexCasingChanged != null) + HexCasingChanged(this, e); + } + + /// + /// Raises the HorizontalByteCountChanged event. + /// + /// An EventArgs that contains the event data. + protected virtual void OnHorizontalByteCountChanged(EventArgs e) + { + if(HorizontalByteCountChanged != null) + HorizontalByteCountChanged(this, e); + } + + /// + /// Raises the VerticalByteCountChanged event. + /// + /// An EventArgs that contains the event data. + protected virtual void OnVerticalByteCountChanged(EventArgs e) + { + if(VerticalByteCountChanged != null) + VerticalByteCountChanged(this, e); + } + + /// + /// Raises the CurrentLineChanged event. + /// + /// An EventArgs that contains the event data. + protected virtual void OnCurrentLineChanged(EventArgs e) + { + if(CurrentLineChanged != null) + CurrentLineChanged(this, e); + } + + /// + /// Raises the CurrentPositionInLineChanged event. + /// + /// An EventArgs that contains the event data. + protected virtual void OnCurrentPositionInLineChanged(EventArgs e) + { + if(CurrentPositionInLineChanged != null) + CurrentPositionInLineChanged(this, e); + } + + /// + /// Raises the MouseDown event. + /// + /// An EventArgs that contains the event data. + protected override void OnMouseDown(MouseEventArgs e) + { + System.Diagnostics.Debug.WriteLine("OnMouseDown()", "HexBox"); + + if(!Focused) + Focus(); + + SetCaretPosition(new Point(e.X, e.Y)); + + base.OnMouseDown (e); + } + + /// + /// Raises the MouseWhell event + /// + /// An EventArgs that contains the event data. + protected override void OnMouseWheel(MouseEventArgs e) + { + int linesToScroll = -(e.Delta * SystemInformation.MouseWheelScrollLines / 120); + this.PerformScrollLines(linesToScroll); + + base.OnMouseWheel (e); + } + + + /// + /// Raises the Resize event. + /// + /// An EventArgs that contains the event data. + protected override void OnResize(EventArgs e) + { + base.OnResize (e); + UpdateRectanglePositioning(); + } + + /// + /// Raises the GotFocus event. + /// + /// An EventArgs that contains the event data. + protected override void OnGotFocus(EventArgs e) + { + System.Diagnostics.Debug.WriteLine("OnGotFocus()", "HexBox"); + + base.OnGotFocus (e); + + CreateCaret(); + } + + /// + /// Raises the LostFocus event. + /// + /// An EventArgs that contains the event data. + protected override void OnLostFocus(EventArgs e) + { + System.Diagnostics.Debug.WriteLine("OnLostFocus()", "HexBox"); + + base.OnLostFocus (e); + + DestroyCaret(); + } + + void _byteProvider_LengthChanged(object sender, EventArgs e) + { + UpdateScrollSize(); + } + #endregion + + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/HexBox.resx b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/HexBox.resx new file mode 100644 index 000000000..dd0ea4d8e --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/HexBox.resx @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.0.0.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + diff --git a/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/HexBox.snk b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/HexBox.snk new file mode 100644 index 000000000..8c596985e Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/HexBox.snk differ diff --git a/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/IByteProvider.cs b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/IByteProvider.cs new file mode 100644 index 000000000..d31619f56 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/IByteProvider.cs @@ -0,0 +1,75 @@ +using System; + +namespace Be.Windows.Forms +{ + /// + /// Defines a byte provider for HexBox control + /// + public interface IByteProvider + { + /// + /// Reads a byte from the provider + /// + /// the index of the byte to read + /// the byte to read + byte ReadByte(long index); + /// + /// Writes a byte into the provider + /// + /// the index of the byte to write + /// the byte to write + void WriteByte(long index, byte value); + /// + /// Inserts bytes into the provider + /// + /// + /// + /// This method must raise the LengthChanged event. + void InsertBytes(long index, byte[] bs); + /// + /// Deletes bytes from the provider + /// + /// the start index of the bytes to delete + /// the length of the bytes to delete + /// This method must raise the LengthChanged event. + void DeleteBytes(long index, long length); + + /// + /// Returns the total length of bytes the byte provider is providing. + /// + long Length {get;} + /// + /// Occurs, when the Length property changed. + /// + event EventHandler LengthChanged; + + /// + /// True, when changes are done. + /// + bool HasChanges(); + /// + /// Applies changes. + /// + void ApplyChanges(); + /// + /// Occurs, when bytes are changed. + /// + event EventHandler Changed; + + /// + /// Returns a value if the WriteByte methods is supported by the provider. + /// + /// True, when it´s supported. + bool SupportsWriteByte(); + /// + /// Returns a value if the InsertBytes methods is supported by the provider. + /// + /// True, when it´s supported. + bool SupportsInsertBytes(); + /// + /// Returns a value if the DeleteBytes methods is supported by the provider. + /// + /// True, when it´s supported. + bool SupportsDeleteBytes(); + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/MemoryDataBlock.cs b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/MemoryDataBlock.cs new file mode 100644 index 000000000..8da76d598 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/MemoryDataBlock.cs @@ -0,0 +1,87 @@ +using System; + +namespace Be.Windows.Forms +{ + internal sealed class MemoryDataBlock : DataBlock + { + byte[] _data; + + public MemoryDataBlock(byte data) + { + _data = new byte[] { data }; + } + + public MemoryDataBlock(byte[] data) + { + if (data == null) + { + throw new ArgumentNullException("data"); + } + + _data = (byte[])data.Clone(); + } + + public override long Length + { + get + { + return _data.LongLength; + } + } + + public byte[] Data + { + get + { + return _data; + } + } + + public void AddByteToEnd(byte value) + { + byte[] newData = new byte[_data.LongLength + 1]; + _data.CopyTo(newData, 0); + newData[newData.LongLength - 1] = value; + _data = newData; + } + + public void AddByteToStart(byte value) + { + byte[] newData = new byte[_data.LongLength + 1]; + newData[0] = value; + _data.CopyTo(newData, 1); + _data = newData; + } + + public void InsertBytes(long position, byte[] data) + { + byte[] newData = new byte[_data.LongLength + data.LongLength]; + if (position > 0) + { + Array.Copy(_data, 0, newData, 0, position); + } + Array.Copy(data, 0, newData, position, data.LongLength); + if (position < _data.LongLength) + { + Array.Copy(_data, position, newData, position + data.LongLength, _data.LongLength - position); + } + _data = newData; + } + + public override void RemoveBytes(long position, long count) + { + byte[] newData = new byte[_data.LongLength - count]; + + if (position > 0) + { + Array.Copy(_data, 0, newData, 0, position); + } + if (position + count < _data.LongLength) + { + Array.Copy(_data, position + count, newData, position, newData.LongLength - position); + } + + _data = newData; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/NativeMethods.cs b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/NativeMethods.cs new file mode 100644 index 000000000..40f7f7f37 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/Be.Windows.Forms.HexBox/NativeMethods.cs @@ -0,0 +1,29 @@ +using System; +using System.Drawing; +using System.Runtime.InteropServices; + +namespace Be.Windows.Forms +{ + internal sealed class NativeMethods + { + static NativeMethods() {} + + // Caret definitions + [DllImport("user32.dll", SetLastError=true)] + public static extern bool CreateCaret(IntPtr hWnd, IntPtr hBitmap, int nWidth, int nHeight); + + [DllImport("user32.dll", SetLastError=true)] + public static extern bool ShowCaret(IntPtr hWnd); + + [DllImport("user32.dll", SetLastError=true)] + public static extern bool DestroyCaret(); + + [DllImport("user32.dll", SetLastError=true)] + public static extern bool SetCaretPos(int X, int Y); + + // Key definitions + public const int WM_KEYDOWN = 0x100; + public const int WM_KEYUP = 0x101; + public const int WM_CHAR = 0x102; + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/ColorModifier.Designer.cs b/branches/ph-plugins/ProcessHacker/Components/ColorModifier.Designer.cs new file mode 100644 index 000000000..e88d39489 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/ColorModifier.Designer.cs @@ -0,0 +1,61 @@ +namespace ProcessHacker.Components +{ + partial class ColorModifier + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.panelColor = new System.Windows.Forms.Panel(); + this.SuspendLayout(); + // + // panelColor + // + this.panelColor.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.panelColor.Dock = System.Windows.Forms.DockStyle.Fill; + this.panelColor.Location = new System.Drawing.Point(0, 0); + this.panelColor.Name = "panelColor"; + this.panelColor.Size = new System.Drawing.Size(40, 20); + this.panelColor.TabIndex = 0; + this.panelColor.MouseLeave += new System.EventHandler(this.panelColor_MouseLeave); + this.panelColor.Click += new System.EventHandler(this.panelColor_Click); + this.panelColor.MouseEnter += new System.EventHandler(this.panelColor_MouseEnter); + // + // ColorModifier + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.panelColor); + this.Name = "ColorModifier"; + this.Size = new System.Drawing.Size(40, 20); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Panel panelColor; + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/ColorModifier.cs b/branches/ph-plugins/ProcessHacker/Components/ColorModifier.cs new file mode 100644 index 000000000..ee93afa12 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/ColorModifier.cs @@ -0,0 +1,83 @@ +/* + * Process Hacker - + * user-friendly color modifier control + * + * Copyright (C) 2008 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 . + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Text; +using System.Windows.Forms; + +namespace ProcessHacker.Components +{ + public partial class ColorModifier : UserControl + { + public event EventHandler ColorChanged; + + private Color _color; + + public ColorModifier() + { + InitializeComponent(); + } + + private void panelColor_Click(object sender, EventArgs e) + { + ColorDialog cd = new ColorDialog(); + + cd.Color = panelColor.BackColor; + cd.FullOpen = true; + + if (cd.ShowDialog() == DialogResult.OK) + { + _color = cd.Color; + panelColor.BackColor = cd.Color; + + if (this.ColorChanged != null) + this.ColorChanged(this, new EventArgs()); + } + } + + public Color Color + { + get { return _color; } + set + { + _color = value; + panelColor.BackColor = value; + + if (this.ColorChanged != null) + this.ColorChanged(this, new EventArgs()); + } + } + + private void panelColor_MouseEnter(object sender, EventArgs e) + { + panelColor.BackColor = Color.FromArgb(0xcc, _color); + } + + private void panelColor_MouseLeave(object sender, EventArgs e) + { + panelColor.BackColor = _color; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/ColorModifier.resx b/branches/ph-plugins/ProcessHacker/Components/ColorModifier.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/ColorModifier.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/EventPairProperties.Designer.cs b/branches/ph-plugins/ProcessHacker/Components/EventPairProperties.Designer.cs new file mode 100644 index 000000000..b553dbdec --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/EventPairProperties.Designer.cs @@ -0,0 +1,78 @@ +namespace ProcessHacker.Components +{ + partial class EventPairProperties + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + _eventPairHandle.Dereference(disposing); + + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.buttonSetHigh = new System.Windows.Forms.Button(); + this.buttonSetLow = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // buttonSetHigh + // + this.buttonSetHigh.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonSetHigh.Location = new System.Drawing.Point(6, 6); + this.buttonSetHigh.Name = "buttonSetHigh"; + this.buttonSetHigh.Size = new System.Drawing.Size(75, 23); + this.buttonSetHigh.TabIndex = 0; + this.buttonSetHigh.Text = "Set High"; + this.buttonSetHigh.UseVisualStyleBackColor = true; + this.buttonSetHigh.Click += new System.EventHandler(this.buttonSetHigh_Click); + // + // buttonSetLow + // + this.buttonSetLow.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonSetLow.Location = new System.Drawing.Point(87, 6); + this.buttonSetLow.Name = "buttonSetLow"; + this.buttonSetLow.Size = new System.Drawing.Size(75, 23); + this.buttonSetLow.TabIndex = 0; + this.buttonSetLow.Text = "Set Low"; + this.buttonSetLow.UseVisualStyleBackColor = true; + this.buttonSetLow.Click += new System.EventHandler(this.buttonSetLow_Click); + // + // EventPairProperties + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.buttonSetLow); + this.Controls.Add(this.buttonSetHigh); + this.Name = "EventPairProperties"; + this.Padding = new System.Windows.Forms.Padding(3); + this.Size = new System.Drawing.Size(212, 63); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Button buttonSetHigh; + private System.Windows.Forms.Button buttonSetLow; + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/EventPairProperties.cs b/branches/ph-plugins/ProcessHacker/Components/EventPairProperties.cs new file mode 100644 index 000000000..e704736ca --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/EventPairProperties.cs @@ -0,0 +1,44 @@ +using System; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Native.Objects; + +namespace ProcessHacker.Components +{ + public partial class EventPairProperties : UserControl + { + private EventPairHandle _eventPairHandle; + + public EventPairProperties(EventPairHandle eventPairHandle) + { + InitializeComponent(); + + _eventPairHandle = eventPairHandle; + _eventPairHandle.Reference(); + } + + private void buttonSetHigh_Click(object sender, EventArgs e) + { + try + { + _eventPairHandle.SetHigh(); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to set the high event", ex); + } + } + + private void buttonSetLow_Click(object sender, EventArgs e) + { + try + { + _eventPairHandle.SetLow(); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to set the low event", ex); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/EventPairProperties.resx b/branches/ph-plugins/ProcessHacker/Components/EventPairProperties.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/EventPairProperties.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/EventProperties.Designer.cs b/branches/ph-plugins/ProcessHacker/Components/EventProperties.Designer.cs new file mode 100644 index 000000000..5d06e00bb --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/EventProperties.Designer.cs @@ -0,0 +1,155 @@ +namespace ProcessHacker.Components +{ + partial class EventProperties + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + _eventHandle.Dereference(disposing); + + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.labelType = new System.Windows.Forms.Label(); + this.labelSignaled = new System.Windows.Forms.Label(); + this.buttonClear = new System.Windows.Forms.Button(); + this.buttonSet = new System.Windows.Forms.Button(); + this.buttonPulse = new System.Windows.Forms.Button(); + this.buttonReset = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(6, 3); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(34, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Type:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(6, 26); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(51, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Signaled:"; + // + // labelType + // + this.labelType.AutoSize = true; + this.labelType.Location = new System.Drawing.Point(66, 3); + this.labelType.Name = "labelType"; + this.labelType.Size = new System.Drawing.Size(60, 13); + this.labelType.TabIndex = 2; + this.labelType.Text = "Notification"; + // + // labelSignaled + // + this.labelSignaled.AutoSize = true; + this.labelSignaled.Location = new System.Drawing.Point(66, 26); + this.labelSignaled.Name = "labelSignaled"; + this.labelSignaled.Size = new System.Drawing.Size(32, 13); + this.labelSignaled.TabIndex = 2; + this.labelSignaled.Text = "False"; + // + // buttonClear + // + this.buttonClear.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonClear.Location = new System.Drawing.Point(6, 79); + this.buttonClear.Name = "buttonClear"; + this.buttonClear.Size = new System.Drawing.Size(75, 23); + this.buttonClear.TabIndex = 3; + this.buttonClear.Text = "Clear"; + this.buttonClear.UseVisualStyleBackColor = true; + this.buttonClear.Click += new System.EventHandler(this.buttonClear_Click); + // + // buttonSet + // + this.buttonSet.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonSet.Location = new System.Drawing.Point(6, 50); + this.buttonSet.Name = "buttonSet"; + this.buttonSet.Size = new System.Drawing.Size(75, 23); + this.buttonSet.TabIndex = 3; + this.buttonSet.Text = "Set"; + this.buttonSet.UseVisualStyleBackColor = true; + this.buttonSet.Click += new System.EventHandler(this.buttonSet_Click); + // + // buttonPulse + // + this.buttonPulse.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonPulse.Location = new System.Drawing.Point(87, 50); + this.buttonPulse.Name = "buttonPulse"; + this.buttonPulse.Size = new System.Drawing.Size(75, 23); + this.buttonPulse.TabIndex = 3; + this.buttonPulse.Text = "Pulse"; + this.buttonPulse.UseVisualStyleBackColor = true; + this.buttonPulse.Click += new System.EventHandler(this.buttonPulse_Click); + // + // buttonReset + // + this.buttonReset.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonReset.Location = new System.Drawing.Point(87, 79); + this.buttonReset.Name = "buttonReset"; + this.buttonReset.Size = new System.Drawing.Size(75, 23); + this.buttonReset.TabIndex = 3; + this.buttonReset.Text = "Reset"; + this.buttonReset.UseVisualStyleBackColor = true; + this.buttonReset.Click += new System.EventHandler(this.buttonReset_Click); + // + // EventProperties + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.buttonReset); + this.Controls.Add(this.buttonPulse); + this.Controls.Add(this.buttonSet); + this.Controls.Add(this.buttonClear); + this.Controls.Add(this.labelSignaled); + this.Controls.Add(this.labelType); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.Name = "EventProperties"; + this.Padding = new System.Windows.Forms.Padding(3); + this.Size = new System.Drawing.Size(173, 117); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label labelType; + private System.Windows.Forms.Label labelSignaled; + private System.Windows.Forms.Button buttonClear; + private System.Windows.Forms.Button buttonSet; + private System.Windows.Forms.Button buttonPulse; + private System.Windows.Forms.Button buttonReset; + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/EventProperties.cs b/branches/ph-plugins/ProcessHacker/Components/EventProperties.cs new file mode 100644 index 000000000..3b57c78bf --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/EventProperties.cs @@ -0,0 +1,76 @@ +using System; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Components +{ + public partial class EventProperties : UserControl + { + private EventHandle _eventHandle; + + public EventProperties(EventHandle eventHandle) + { + InitializeComponent(); + + _eventHandle = eventHandle; + _eventHandle.Reference(); + this.UpdateInfo(); + } + + private void UpdateInfo() + { + var basicInfo = _eventHandle.GetBasicInformation(); + + labelType.Text = basicInfo.EventType.ToString(); + labelSignaled.Text = (basicInfo.EventState != 0).ToString(); + } + + private void TryExecute(MethodInvoker action) + { + try + { + action(); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to perform the operation", ex); + } + } + + private void UpgradeExecute(MethodInvoker action) + { + this.TryExecute(() => + { + _eventHandle.ChangeAccess(EventAccess.QueryState | EventAccess.ModifyState); + + action(); + }); + } + + private void buttonSet_Click(object sender, EventArgs e) + { + this.UpgradeExecute(() => _eventHandle.Set()); + this.UpdateInfo(); + } + + private void buttonPulse_Click(object sender, EventArgs e) + { + this.UpgradeExecute(() => _eventHandle.Pulse()); + this.UpdateInfo(); + } + + private void buttonClear_Click(object sender, EventArgs e) + { + this.UpgradeExecute(() => _eventHandle.Clear()); + this.UpdateInfo(); + } + + private void buttonReset_Click(object sender, EventArgs e) + { + this.UpgradeExecute(() => _eventHandle.Reset()); + this.UpdateInfo(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/EventProperties.resx b/branches/ph-plugins/ProcessHacker/Components/EventProperties.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/EventProperties.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/ExtendedListView.cs b/branches/ph-plugins/ProcessHacker/Components/ExtendedListView.cs new file mode 100644 index 000000000..2869ac996 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/ExtendedListView.cs @@ -0,0 +1,454 @@ +/* + * Process Hacker - + * ProcessHacker Extended ListView + * + * Copyright (C) 2009 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 . + * + */ + + +using System; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; + +namespace ProcessHacker +{ + public class ExtendedListView : ListView + { + private const int LVM_First = 0x1000; // ListView messages + private const int LVM_SetGroupInfo = (LVM_First + 147); // ListView messages Setinfo on Group + private const int LVM_SetExtendedListViewStyle = (LVM_First + 54); // Sets extended styles in list-view controls. + private const int LVS_Ex_DoubleBuffer = 0x00010000; // Paints via double-buffering, which reduces flicker. also enables alpha-blended marquee selection. + + private const int LVN_First = -100; + private const int LVN_LINKCLICK = (LVN_First - 84); + + private delegate void CallBackSetGroupState(ListViewGroup lvGroup, ListViewGroupState lvState, string task); + private delegate void CallbackSetGroupString(ListViewGroup lvGroup, string value); + + [DllImport("user32.dll", CharSet = CharSet.Auto)] + private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, ref LVGroup lParam); + + public ExtendedListView() + { + //Activate double buffering and + //Enable the OnNotifyMessage event so we get a chance to filter out + //Windows messages before they get to the form's WndProc + this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.EnableNotifyMessage, true); + } + + public void SetGroupState(ListViewGroupState state) + { + this.SetGroupState(state, null); + } + + public void SetGroupState(ListViewGroupState state, string taskLabel) + { + foreach (ListViewGroup lvg in this.Groups) + { + SetGrpState(lvg, state, taskLabel); + } + } + + private static int? GetGroupID(ListViewGroup lvGroup) + { + int? grpId = null; + Type grpType = lvGroup.GetType(); + if (grpType != null) + { + PropertyInfo pInfo = grpType.GetProperty("ID", BindingFlags.NonPublic | BindingFlags.Instance); + if (pInfo != null) + { + object tmprtnval = pInfo.GetValue(lvGroup, null); + if (tmprtnval != null) + { + grpId = tmprtnval as int?; + } + } + } + return grpId; + } + + private void SetGrpState(ListViewGroup lvGroup, ListViewGroupState grpState, string task) + { + if (OSVersion.IsBelow(WindowsVersion.Vista)) + return; + if (lvGroup == null || lvGroup.ListView == null) + return; + if (lvGroup.ListView.InvokeRequired) + lvGroup.ListView.Invoke(new CallBackSetGroupState(SetGrpState), lvGroup, grpState, task); + else + { + int? GrpId = GetGroupID(lvGroup); + int gIndex = lvGroup.ListView.Groups.IndexOf(lvGroup); + LVGroup group = new LVGroup(); + group.CbSize = Marshal.SizeOf(group); + group.Mask |= ListViewGroupMask.Task + | ListViewGroupMask.State + | ListViewGroupMask.Align; + + IntPtr taskString = Marshal.StringToHGlobalAuto(task); + + if (task.Length > 1) + { + group.Task = taskString; + group.CchTask = task.Length; + } + + group.GroupState = grpState; + + if (GrpId != null) + { + group.GroupId = GrpId.Value; + SendMessage(base.Handle, LVM_SetGroupInfo, GrpId.Value, ref group); + } + else + { + group.GroupId = gIndex; + SendMessage(base.Handle, LVM_SetGroupInfo, gIndex, ref group); + } + lvGroup.ListView.Refresh(); + + Marshal.FreeHGlobal(taskString); + } + } + + protected override void OnNotifyMessage(Message m) + { + //notification for linkclick never reaches here? + //http://msdn.microsoft.com/en-us/library/bb774851%28VS.85%29.aspx + + // + + //Filter out the WM_ERASEBKGND message and prevent any type of flickering + if (m.Msg != 0x14) + { + base.OnNotifyMessage(m); + } + } + + private const int WM_NOTIFY = 0x004E; + + protected override void WndProc(ref Message m) + { + switch (m.Msg) + { + case 0x1: /*WM_CREATE*/ + { + SubclassHWnd(base.Handle); + + HResult setThemeResult = Win32.SetWindowTheme(base.Handle, "explorer", null); + setThemeResult.ThrowIf(); + + unchecked + { + Win32.SendMessage(base.Handle, (WindowMessage)LVM_SetExtendedListViewStyle, LVS_Ex_DoubleBuffer, LVS_Ex_DoubleBuffer); + } + + break; + } + case 0x202: + case 0x205: + case 520: + case 0x203: + case 0x2a1: + { + base.DefWndProc(ref m); + return; + } + } + + base.WndProc(ref m); + } + + // Win32 API needed + [DllImport("user32")] + private static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, Win32WndProc newProc); + [DllImport("user32")] + private static extern int CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, int Msg, int wParam, int lParam); + + // A delegate that matches Win32 WNDPROC: + private delegate int Win32WndProc(IntPtr hWnd, int Msg, int wParam, int lParam); + + // from winuser.h: + private const int GWL_WNDPROC = -4; + private const int WM_LBUTTONDOWN = 0x0201; + + // program variables + private IntPtr oldWndProc = IntPtr.Zero; + private Win32WndProc newWndProc = null; + + void SubclassHWnd(IntPtr hWnd) + { + // hWnd is the window we want to subclass..., create a new delegate for the new wndproc + newWndProc = new Win32WndProc(MyWndProc); + // subclass + oldWndProc = SetWindowLong(hWnd, GWL_WNDPROC, newWndProc); + } + + // this is the new wndproc, just show a messagebox on left button down: + private int MyWndProc(IntPtr hWnd, int Msg, int wParam, int lParam) + { + System.Diagnostics.Debug.WriteLine(Msg.ToString()); + + + switch (Msg) + { + case 0x4e: + { + unsafe + { + NMHDR* hdr = (NMHDR*)lParam; + + if (hdr->code == LVN_LINKCLICK) + { + MessageBox.Show("Link clicked!"); + return 0; + } + } + break; + } + default: + break; + } + + return CallWindowProc(oldWndProc, hWnd, Msg, wParam, lParam); + } + + + //http://msdn.microsoft.com/en-us/library/bb774769(VS.85).aspx + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + private struct LVGroup + { + /// + /// Size of this structure, in bytes. + /// + public int CbSize; + + /// + /// Mask that specifies which members of the structure are valid input. One or more of the following values:LVGF_NONENo other items are valid. + /// + public ListViewGroupMask Mask; + + /// + /// Pointer to a null-terminated string that contains the header text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the header text. + /// + //[MarshalAs(UnmanagedType.LPWStr)] + public IntPtr pszHeader; + + /// + /// Size in TCHARs of the buffer pointed to by the pszHeader member. If the structure is not receiving information about a group, this member is ignored. + /// + public int CchHeader; + + /// + /// Pointer to a null-terminated string that contains the footer text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the footer text. + /// + //[MarshalAs(UnmanagedType.LPWStr)] + public IntPtr pszFooter; + + /// + /// Size in TCHARs of the buffer pointed to by the pszFooter member. If the structure is not receiving information about a group, this member is ignored. + /// + public int CchFooter; + + /// + /// ID of the group. + /// + public int GroupId; + + /// + /// Mask used with LVM_GETGROUPINFO (Microsoft Windows XP and Windows Vista) and LVM_SETGROUPINFO (Windows Vista only) to specify which flags in the state value are being retrieved or set. + /// + public uint stateMask; + + /// + /// Flag that can have one of the following values:LVGS_NORMALGroups are expanded, the group name is displayed, and all items in the group are displayed. + /// + public ListViewGroupState GroupState; + + /// + /// Indicates the alignment of the header or footer text for the group. It can have one or more of the following values. Use one of the header flags. Footer flags are optional. Windows XP: Footer flags are reserved.LVGA_FOOTER_CENTERReserved. + /// + public uint uAlign; + + /// + /// Windows Vista. Pointer to a null-terminated string that contains the subtitle text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the subtitle text. This element is drawn under the header text. + /// + //[MarshalAs(UnmanagedType.LPWStr)] + public IntPtr PszSubtitle; + + /// + /// Windows Vista. Size, in TCHARs, of the buffer pointed to by the pszSubtitle member. If the structure is not receiving information about a group, this member is ignored. + /// + public uint CchSubtitle; + + /// + /// Windows Vista. Pointer to a null-terminated string that contains the text for a task link when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the task text. This item is drawn right-aligned opposite the header text. When clicked by the user, the task link generates an LVN_LINKCLICK notification. + /// + //[MarshalAs(UnmanagedType.LPWStr)] + public IntPtr Task; + + /// + /// Windows Vista. Size in TCHARs of the buffer pointed to by the pszTask member. If the structure is not receiving information about a group, this member is ignored. + /// + public int CchTask; + + /// + /// Windows Vista. Pointer to a null-terminated string that contains the top description text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the top description text. This item is drawn opposite the title image when there is a title image, no extended image, and uAlign==LVGA_HEADER_CENTER. + /// + //[MarshalAs(UnmanagedType.LPWStr)] + public IntPtr DescriptionTop; + + /// + /// Windows Vista. Size in TCHARs of the buffer pointed to by the pszDescriptionTop member. If the structure is not receiving information about a group, this member is ignored. + /// + public uint CchDescriptionTop; + + /// + /// Windows Vista. Pointer to a null-terminated string that contains the bottom description text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the bottom description text. This item is drawn under the top description text when there is a title image, no extended image, and uAlign==LVGA_HEADER_CENTER. + /// + //[MarshalAs(UnmanagedType.LPWStr)] + public IntPtr DescriptionBottom; + + /// + /// Windows Vista. Size in TCHARs of the buffer pointed to by the pszDescriptionBottom member. If the structure is not receiving information about a group, this member is ignored. + /// + public uint CchDescriptionBottom; + + /// + /// Windows Vista. Index of the title image in the control imagelist. + /// + public int ITitleImage; + + /// + /// Windows Vista. Index of the extended image in the control imagelist. + /// + public int IExtendedImage; + + /// + /// Windows Vista. Read-only. + /// + public int IFirstItem; + + /// + /// Windows Vista. Read-only in non-owner data mode. + /// + public uint CItems; + + /// + /// Windows Vista. NULL if group is not a subset. Pointer to a null-terminated string that contains the subset title text when item information is being set. If group information is being retrieved, this member specifies the address of the buffer that receives the subset title text. + /// + //[MarshalAs(UnmanagedType.LPWStr)] + public IntPtr PszSubsetTitle; + + /// + /// Windows Vista. Size in TCHARs of the buffer pointed to by the pszSubsetTitle member. If the structure is not receiving information about a group, this member is ignored. + /// + public uint CchSubsetTitle; + } + + //http://msdn.microsoft.com/en-us/library/ms229669.aspx + //http://msdn.microsoft.com/en-us/magazine/dvdarchive/cc163384.aspx + /// + /// WM_NOTIFY notificaiton message header. + /// + [StructLayout(LayoutKind.Sequential)] + private struct NMHDR + { + /// + /// Window handle to the control sending a message. + /// + public IntPtr hwndFrom; + /// + /// Identifier of the control sending a message. + /// + public IntPtr idFrom; + /// + /// Notification code. This member can be a control-specific notification code or it can be one of the common notification codes. + /// + public int code; + } + + } + + [Flags] + public enum ListViewGroupMask : uint + { + None = 0x00000, + Header = 0x00001, + Footer = 0x00002, + State = 0x00004, + Align = 0x00008, + GroupId = 0x00010, + SubTitle = 0x00100, + Task = 0x00200, + DescriptionTop = 0x00400, + DescriptionBottom = 0x00800, + TitleImage = 0x01000, + ExtendedImage = 0x02000, + Items = 0x04000, + Subset = 0x08000, + SubsetItems = 0x10000 + } + + [Flags] + public enum ListViewGroupState : uint + { + /// + /// Groups are expanded, the group name is displayed, and all items in the group are displayed. + /// + Normal = 0, + /// + /// The group is collapsed. + /// + Collapsed = 1, + /// + /// The group is hidden. + /// + Hidden = 2, + /// + /// Version 6.00 and Windows Vista. The group does not display a header. + /// + NoHeader = 4, + /// + /// Version 6.00 and Windows Vista. The group can be collapsed. + /// + Collapsible = 8, + /// + /// Version 6.00 and Windows Vista. The group has keyboard focus. + /// + Focused = 16, + /// + /// Version 6.00 and Windows Vista. The group is selected. + /// + Selected = 32, + /// + /// Version 6.00 and Windows Vista. The group displays only a portion of its items. + /// + SubSeted = 64, + /// + /// Version 6.00 and Windows Vista. The subset link of the group has keyboard focus. + /// + SubSetLinkFocused = 128, + } + +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/ExtendedTreeView.cs b/branches/ph-plugins/ProcessHacker/Components/ExtendedTreeView.cs new file mode 100644 index 000000000..53a9d11b2 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/ExtendedTreeView.cs @@ -0,0 +1,49 @@ +/* + * Process Hacker - + * ProcessHacker Extended TreeView + * + * Copyright (C) 2009 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 . + * + */ + +using System.Runtime.InteropServices; +using ProcessHacker.Native.Api; +using ProcessHacker.Native; +using System; + +public class VistaTreeView : System.Windows.Forms.TreeView +{ + //http://www.danielmoth.com/Blog/2007/01/treeviewvista.html + //http://www.danielmoth.com/Blog/2006/12/tvsexautohscroll.html + + private const int TV_FIRST = 0x1100; + private const int TVM_SETEXTENDEDSTYLE = TV_FIRST + 44; + private const int TVS_EX_AUTOHSCROLL = 0x0020; //autoscroll horizontaly + private const int TVS_EX_FADEINOUTEXPANDOS = 0x0040; //auto hide the +/- signs + + protected override void OnHandleCreated(System.EventArgs e) + { + if (OSVersion.IsAboveOrEqual(WindowsVersion.Vista)) + { + Win32.SendMessage(this.Handle, (WindowMessage)TVM_SETEXTENDEDSTYLE, 0, TVS_EX_FADEINOUTEXPANDOS); + HResult setThemeResult = Win32.SetWindowTheme(this.Handle, "explorer", null); + setThemeResult.ThrowIf(); + } + base.OnHandleCreated(e); + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/FileNameBox.Designer.cs b/branches/ph-plugins/ProcessHacker/Components/FileNameBox.Designer.cs new file mode 100644 index 000000000..0b69e8137 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/FileNameBox.Designer.cs @@ -0,0 +1,96 @@ +namespace ProcessHacker.Components +{ + partial class FileNameBox + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.textFileName = new System.Windows.Forms.TextBox(); + this.buttonProperties = new System.Windows.Forms.Button(); + this.buttonExplore = new System.Windows.Forms.Button(); + this.toolTip = new System.Windows.Forms.ToolTip(this.components); + this.SuspendLayout(); + // + // textFileName + // + this.textFileName.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textFileName.Location = new System.Drawing.Point(0, 2); + this.textFileName.Name = "textFileName"; + this.textFileName.Size = new System.Drawing.Size(277, 20); + this.textFileName.TabIndex = 0; + this.textFileName.Leave += new System.EventHandler(this.textFileName_Leave); + // + // buttonProperties + // + this.buttonProperties.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Right))); + this.buttonProperties.Image = global::ProcessHacker.Properties.Resources.application_form_magnify; + this.buttonProperties.Location = new System.Drawing.Point(279, 0); + this.buttonProperties.Name = "buttonProperties"; + this.buttonProperties.Size = new System.Drawing.Size(24, 24); + this.buttonProperties.TabIndex = 1; + this.toolTip.SetToolTip(this.buttonProperties, "Properties"); + this.buttonProperties.UseVisualStyleBackColor = true; + this.buttonProperties.Click += new System.EventHandler(this.buttonProperties_Click); + // + // buttonExplore + // + this.buttonExplore.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Right))); + this.buttonExplore.Image = global::ProcessHacker.Properties.Resources.folder_explore; + this.buttonExplore.Location = new System.Drawing.Point(304, 0); + this.buttonExplore.Name = "buttonExplore"; + this.buttonExplore.Size = new System.Drawing.Size(24, 24); + this.buttonExplore.TabIndex = 2; + this.toolTip.SetToolTip(this.buttonExplore, "Open File Location"); + this.buttonExplore.UseVisualStyleBackColor = true; + this.buttonExplore.Click += new System.EventHandler(this.buttonExplore_Click); + // + // FileNameBox + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.buttonExplore); + this.Controls.Add(this.buttonProperties); + this.Controls.Add(this.textFileName); + this.Name = "FileNameBox"; + this.Size = new System.Drawing.Size(328, 24); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TextBox textFileName; + private System.Windows.Forms.Button buttonProperties; + private System.Windows.Forms.Button buttonExplore; + private System.Windows.Forms.ToolTip toolTip; + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/FileNameBox.cs b/branches/ph-plugins/ProcessHacker/Components/FileNameBox.cs new file mode 100644 index 000000000..7f2869f3c --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/FileNameBox.cs @@ -0,0 +1,92 @@ +/* + * Process Hacker - + * file name textbox with extra actions + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Native; + +namespace ProcessHacker.Components +{ + public partial class FileNameBox : UserControl + { + public FileNameBox() + { + InitializeComponent(); + } + + public event EventHandler TextBoxLeave; + + public bool TextBoxFocused + { + get { return textFileName.Focused; } + } + + public bool ReadOnly + { + get { return textFileName.ReadOnly; } + set { textFileName.ReadOnly = value; } + } + + public override string Text + { + get + { + return textFileName.Text; + } + set + { + textFileName.Text = value; + } + } + + private void buttonProperties_Click(object sender, EventArgs e) + { + try + { + FileUtils.ShowProperties(textFileName.Text); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to show properties for the file", ex); + } + } + + private void buttonExplore_Click(object sender, EventArgs e) + { + try + { + Utils.ShowFileInExplorer(textFileName.Text); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to show the file", ex); + } + } + + private void textFileName_Leave(object sender, EventArgs e) + { + if (TextBoxLeave != null) + TextBoxLeave(sender, e); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/FileNameBox.resx b/branches/ph-plugins/ProcessHacker/Components/FileNameBox.resx new file mode 100644 index 000000000..a5979aadf --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/FileNameBox.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/HandleList.Designer.cs b/branches/ph-plugins/ProcessHacker/Components/HandleList.Designer.cs new file mode 100644 index 000000000..e1aecfac9 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/HandleList.Designer.cs @@ -0,0 +1,164 @@ +namespace ProcessHacker.Components +{ + partial class HandleList + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + _highlightingContext.Dispose(); + this.Provider = null; + + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.listHandles = new System.Windows.Forms.ListView(); + this.columnType = new System.Windows.Forms.ColumnHeader(); + this.columnName = new System.Windows.Forms.ColumnHeader(); + this.columnHandle = new System.Windows.Forms.ColumnHeader(); + this.vistaMenu = new wyDay.Controls.VistaMenu(this.components); + this.closeHandleMenuItem = new System.Windows.Forms.MenuItem(); + this.copyHandleMenuItem = new System.Windows.Forms.MenuItem(); + this.menuHandle = new System.Windows.Forms.ContextMenu(); + this.protectedMenuItem = new System.Windows.Forms.MenuItem(); + this.inheritMenuItem = new System.Windows.Forms.MenuItem(); + this.menuItem11 = new System.Windows.Forms.MenuItem(); + this.propertiesHandleMenuItem = new System.Windows.Forms.MenuItem(); + ((System.ComponentModel.ISupportInitialize)(this.vistaMenu)).BeginInit(); + this.SuspendLayout(); + // + // listHandles + // + this.listHandles.AllowColumnReorder = true; + this.listHandles.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnType, + this.columnName, + this.columnHandle}); + this.listHandles.Dock = System.Windows.Forms.DockStyle.Fill; + this.listHandles.FullRowSelect = true; + this.listHandles.HideSelection = false; + this.listHandles.Location = new System.Drawing.Point(0, 0); + this.listHandles.Name = "listHandles"; + this.listHandles.ShowItemToolTips = true; + this.listHandles.Size = new System.Drawing.Size(450, 472); + this.listHandles.Sorting = System.Windows.Forms.SortOrder.Ascending; + this.listHandles.TabIndex = 3; + this.listHandles.UseCompatibleStateImageBehavior = false; + this.listHandles.View = System.Windows.Forms.View.Details; + // + // columnType + // + this.columnType.Text = "Type"; + this.columnType.Width = 100; + // + // columnName + // + this.columnName.Text = "Name"; + this.columnName.Width = 250; + // + // columnHandle + // + this.columnHandle.Text = "Handle"; + // + // vistaMenu + // + this.vistaMenu.ContainerControl = this; + this.vistaMenu.DelaySetImageCalls = false; + // + // closeHandleMenuItem + // + this.vistaMenu.SetImage(this.closeHandleMenuItem, global::ProcessHacker.Properties.Resources.cross); + this.closeHandleMenuItem.Index = 0; + this.closeHandleMenuItem.Text = "Close"; + this.closeHandleMenuItem.Click += new System.EventHandler(this.closeHandleMenuItem_Click); + // + // copyHandleMenuItem + // + this.vistaMenu.SetImage(this.copyHandleMenuItem, global::ProcessHacker.Properties.Resources.page_copy); + this.copyHandleMenuItem.Index = 4; + this.copyHandleMenuItem.Text = "&Copy"; + // + // menuHandle + // + this.menuHandle.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.closeHandleMenuItem, + this.protectedMenuItem, + this.inheritMenuItem, + this.menuItem11, + this.copyHandleMenuItem, + this.propertiesHandleMenuItem}); + this.menuHandle.Popup += new System.EventHandler(this.menuHandle_Popup); + // + // protectedMenuItem + // + this.protectedMenuItem.Index = 1; + this.protectedMenuItem.Text = "Protected"; + this.protectedMenuItem.Click += new System.EventHandler(this.protectedMenuItem_Click); + // + // inheritMenuItem + // + this.inheritMenuItem.Index = 2; + this.inheritMenuItem.Text = "Inherit"; + this.inheritMenuItem.Click += new System.EventHandler(this.inheritMenuItem_Click); + // + // menuItem11 + // + this.menuItem11.Index = 3; + this.menuItem11.Text = "-"; + // + // propertiesHandleMenuItem + // + this.propertiesHandleMenuItem.Index = 5; + this.propertiesHandleMenuItem.Text = "&Properties"; + this.propertiesHandleMenuItem.Click += new System.EventHandler(this.propertiesHandleMenuItem_Click); + // + // HandleList + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.listHandles); + this.DoubleBuffered = true; + this.Name = "HandleList"; + this.Size = new System.Drawing.Size(450, 472); + ((System.ComponentModel.ISupportInitialize)(this.vistaMenu)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.ListView listHandles; + private System.Windows.Forms.ColumnHeader columnType; + private System.Windows.Forms.ColumnHeader columnName; + private System.Windows.Forms.ColumnHeader columnHandle; + private wyDay.Controls.VistaMenu vistaMenu; + private System.Windows.Forms.ContextMenu menuHandle; + private System.Windows.Forms.MenuItem closeHandleMenuItem; + private System.Windows.Forms.MenuItem copyHandleMenuItem; + private System.Windows.Forms.MenuItem menuItem11; + private System.Windows.Forms.MenuItem propertiesHandleMenuItem; + private System.Windows.Forms.MenuItem protectedMenuItem; + private System.Windows.Forms.MenuItem inheritMenuItem; + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/HandleList.cs b/branches/ph-plugins/ProcessHacker/Components/HandleList.cs new file mode 100644 index 000000000..6ece3e100 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/HandleList.cs @@ -0,0 +1,620 @@ +/* + * Process Hacker - + * Handle list + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Reflection; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Common.Ui; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; +using ProcessHacker.Native.Ui; +using ProcessHacker.UI; + +namespace ProcessHacker.Components +{ + public partial class HandleList : UserControl + { + public static bool ConfirmHandleClose() + { + if (Properties.Settings.Default.WarnDangerous) + { + return PhUtils.ShowConfirmMessage( + "close", + "the selected handle(s)", + "Closing handles may cause system instability and data corruption.", + false + ); + } + else + { + return true; + } + } + + public static void ShowHandleProperties(SystemHandleEntry handleInfo) + { + try + { + HandlePropertiesWindow window = new HandlePropertiesWindow(handleInfo); + IntPtr handle = new IntPtr(handleInfo.Handle); + ProcessHandle phandle = new ProcessHandle(handleInfo.ProcessId, ProcessAccess.DupHandle); + GenericHandle dupHandle = null; + + window.HandlePropertiesCallback += (control, name, typeName) => + { + switch (typeName.ToLower()) + { + // Objects with separate property windows: + case "file": + case "job": + case "key": + case "token": + case "process": + { + Button b = new Button(); + + b.FlatStyle = FlatStyle.System; + b.Text = "Properties..."; + b.Click += (sender, e) => + { + try + { + switch (typeName.ToLower()) + { + case "file": + { + FileUtils.ShowProperties(name); + } + break; + case "job": + { + dupHandle = + new GenericHandle( + phandle, handle, + (int)JobObjectAccess.Query); + (new JobWindow(JobObjectHandle.FromHandle(dupHandle))).ShowDialog(); + } + break; + case "key": + { + try + { + PhUtils.OpenKeyInRegedit(Form.ActiveForm, name); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to open the Registry Editor", ex); + } + } + break; + case "token": + { + (new TokenWindow(new RemoteTokenHandle(phandle, + handle))).ShowDialog(); + } + break; + case "process": + { + int pid; + + if (KProcessHacker.Instance != null) + { + pid = KProcessHacker.Instance.KphGetProcessId(phandle, handle); + } + else + { + dupHandle = + new GenericHandle( + phandle, handle, + (int)OSVersion.MinProcessQueryInfoAccess); + pid = ProcessHandle.FromHandle(dupHandle).GetProcessId(); + } + + Program.GetProcessWindow(Program.ProcessProvider.Dictionary[pid], + (f) => Program.FocusWindow(f)); + } + break; + } + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to show object properties", ex); + } + }; + + control.Controls.Add(b); + } + break; + case "event": + { + dupHandle = new GenericHandle(phandle, handle, (int)EventAccess.QueryState); + var eventProps = new EventProperties(EventHandle.FromHandle(dupHandle)); + control.Controls.Add(eventProps); + } + break; + case "eventpair": + { + dupHandle = new GenericHandle(phandle, handle, (int)EventPairAccess.All); + var eventPairProps = new EventPairProperties(EventPairHandle.FromHandle(dupHandle)); + control.Controls.Add(eventPairProps); + } + break; + case "mutant": + { + dupHandle = new GenericHandle(phandle, handle, (int)MutantAccess.QueryState); + var mutantProps = new MutantProperties(MutantHandle.FromHandle(dupHandle)); + control.Controls.Add(mutantProps); + } + break; + case "section": + { + dupHandle = new GenericHandle(phandle, handle, (int)SectionAccess.Query); + var sectionProps = new SectionProperties(SectionHandle.FromHandle(dupHandle)); + control.Controls.Add(sectionProps); + } + break; + case "semaphore": + { + dupHandle = new GenericHandle(phandle, handle, (int)SemaphoreAccess.QueryState); + var semaphoreProps = new SemaphoreProperties(SemaphoreHandle.FromHandle(dupHandle)); + control.Controls.Add(semaphoreProps); + } + break; + case "timer": + { + dupHandle = new GenericHandle(phandle, handle, (int)TimerAccess.QueryState); + var timerProps = new TimerProperties(TimerHandle.FromHandle(dupHandle)); + control.Controls.Add(timerProps); + } + break; + case "tmrm": + { + dupHandle = new GenericHandle(phandle, handle, (int)ResourceManagerAccess.QueryInformation); + var tmRmProps = new TmRmProperties(ResourceManagerHandle.FromHandle(dupHandle)); + control.Controls.Add(tmRmProps); + } + break; + case "tmtm": + { + dupHandle = new GenericHandle(phandle, handle, (int)TmAccess.QueryInformation); + var tmTmProps = new TmTmProperties(TmHandle.FromHandle(dupHandle)); + control.Controls.Add(tmTmProps); + } + break; + } + }; + + if (dupHandle == null) + { + // Try to get a handle, since we need one for security editing. + try { dupHandle = new GenericHandle(phandle, handle, 0); } + catch { } + } + + window.ObjectHandle = dupHandle; + + window.ShowDialog(); + + if (dupHandle != null) + dupHandle.Dispose(); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to show handle properties", ex); + } + } + + private object _listLock = new object(); + private HandleProvider _provider; + private int _runCount = 0; + private List _needsAdd = new List(); + private HighlightingContext _highlightingContext; + public new event KeyEventHandler KeyDown; + public new event MouseEventHandler MouseDown; + public new event MouseEventHandler MouseUp; + public event EventHandler SelectedIndexChanged; + + public HandleList() + { + InitializeComponent(); + + _highlightingContext = new HighlightingContext(listHandles); + listHandles.KeyDown += new KeyEventHandler(listHandles_KeyDown); + listHandles.MouseDown += new MouseEventHandler(listHandles_MouseDown); + listHandles.MouseUp += new MouseEventHandler(listHandles_MouseUp); + listHandles.DoubleClick += new EventHandler(listHandles_DoubleClick); + listHandles.SelectedIndexChanged += new System.EventHandler(listHandles_SelectedIndexChanged); + + var comparer = (SortedListViewComparer) + (listHandles.ListViewItemSorter = new SortedListViewComparer(listHandles)); + + comparer.ColumnSortOrder.Add(0); + comparer.ColumnSortOrder.Add(2); + comparer.ColumnSortOrder.Add(1); + + listHandles.ContextMenu = menuHandle; + GenericViewMenu.AddMenuItems(copyHandleMenuItem.MenuItems, listHandles, null); + ColumnSettings.LoadSettings(Properties.Settings.Default.HandleListViewColumns, listHandles); + + if (KProcessHacker.Instance == null) + { + protectedMenuItem.Visible = false; + inheritMenuItem.Visible = false; + } + } + + private void listHandles_DoubleClick(object sender, EventArgs e) + { + propertiesHandleMenuItem_Click(sender, e); + } + + private void listHandles_MouseUp(object sender, MouseEventArgs e) + { + if (this.MouseUp != null) + this.MouseUp(sender, e); + } + + private void listHandles_MouseDown(object sender, MouseEventArgs e) + { + if (this.MouseDown != null) + this.MouseDown(sender, e); + } + + private void listHandles_SelectedIndexChanged(object sender, System.EventArgs e) + { + if (this.SelectedIndexChanged != null) + this.SelectedIndexChanged(sender, e); + } + + private void listHandles_KeyDown(object sender, KeyEventArgs e) + { + if (this.KeyDown != null) + this.KeyDown(sender, e); + + if (!e.Handled) + { + if (e.KeyCode == Keys.Enter) + { + propertiesHandleMenuItem_Click(null, null); + } + else if (e.KeyCode == Keys.Delete) + { + if (ConfirmHandleClose()) + { + closeHandleMenuItem_Click(null, null); + } + } + } + } + + #region Properties + + public new bool DoubleBuffered + { + get + { + return (bool)typeof(ListView).GetProperty("DoubleBuffered", + BindingFlags.NonPublic | BindingFlags.Instance).GetValue(listHandles, null); + } + set + { + typeof(ListView).GetProperty("DoubleBuffered", + BindingFlags.NonPublic | BindingFlags.Instance).SetValue(listHandles, value, null); + } + } + + public override bool Focused + { + get + { + return listHandles.Focused; + } + } + + public override ContextMenu ContextMenu + { + get { return listHandles.ContextMenu; } + set { listHandles.ContextMenu = value; } + } + + public override ContextMenuStrip ContextMenuStrip + { + get { return listHandles.ContextMenuStrip; } + set { listHandles.ContextMenuStrip = value; } + } + + public ListView List + { + get { return listHandles; } + } + + public HandleProvider Provider + { + get { return _provider; } + set + { + if (_provider != null) + { + _provider.DictionaryAdded -= provider_DictionaryAdded; + _provider.DictionaryModified -= provider_DictionaryModified; + _provider.DictionaryRemoved -= provider_DictionaryRemoved; + _provider.Updated -= provider_Updated; + } + + _provider = value; + + listHandles.Items.Clear(); + _pid = -1; + + if (_provider != null) + { + foreach (HandleItem item in _provider.Dictionary.Values) + { + provider_DictionaryAdded(item); + } + + _provider.DictionaryAdded += provider_DictionaryAdded; + _provider.DictionaryModified += provider_DictionaryModified; + _provider.DictionaryRemoved += provider_DictionaryRemoved; + _provider.Updated += provider_Updated; + _pid = _provider.Pid; + } + } + } + + #endregion + + #region Interfacing + + public void BeginUpdate() + { + listHandles.BeginUpdate(); + } + + public void EndUpdate() + { + listHandles.EndUpdate(); + } + + public ListView.ListViewItemCollection Items + { + get { return listHandles.Items; } + } + + public ListView.SelectedListViewItemCollection SelectedItems + { + get { return listHandles.SelectedItems; } + } + + #endregion + + private void provider_Updated() + { + lock (_needsAdd) + { + if (_needsAdd.Count > 0) + { + this.BeginInvoke(new MethodInvoker(() => + { + lock (_needsAdd) + { + listHandles.Items.AddRange(_needsAdd.ToArray()); + _needsAdd.Clear(); + _needsAdd.TrimExcess(); + } + })); + } + } + + _highlightingContext.Tick(); + _runCount++; + } + + private Color GetHandleColor(HandleItem item) + { + if (Properties.Settings.Default.UseColorProtectedHandles && + (item.Handle.Flags & HandleFlags.ProtectFromClose) != 0 + ) + return Properties.Settings.Default.ColorProtectedHandles; + else if (Properties.Settings.Default.UseColorInheritHandles && + (item.Handle.Flags & HandleFlags.Inherit) != 0 + ) + return Properties.Settings.Default.ColorInheritHandles; + else + return SystemColors.Window; + } + + private void provider_DictionaryAdded(HandleItem item) + { + HighlightedListViewItem litem = new HighlightedListViewItem(_highlightingContext, + item.RunId > 0 && _runCount > 0); + + litem.Name = item.Handle.Handle.ToString(); + litem.Text = item.ObjectInfo.TypeName; + litem.SubItems.Add(new ListViewItem.ListViewSubItem(litem, item.ObjectInfo.BestName)); + litem.SubItems.Add(new ListViewItem.ListViewSubItem(litem, "0x" + item.Handle.Handle.ToString("x"))); + litem.Tag = item; + + litem.NormalColor = this.GetHandleColor(item); + + lock (_needsAdd) + _needsAdd.Add(litem); + } + + private void provider_DictionaryModified(HandleItem oldItem, HandleItem newItem) + { + this.BeginInvoke(new MethodInvoker(() => + { + lock (_listLock) + { + (listHandles.Items[newItem.Handle.Handle.ToString()] as + HighlightedListViewItem).NormalColor = this.GetHandleColor(newItem); + } + })); + } + + private void provider_DictionaryRemoved(HandleItem item) + { + this.BeginInvoke(new MethodInvoker(() => + { + lock (_listLock) + listHandles.Items[item.Handle.Handle.ToString()].Remove(); + })); + } + + private int _pid; + + public void SaveSettings() + { + Properties.Settings.Default.HandleListViewColumns = ColumnSettings.SaveSettings(listHandles); + } + + private void menuHandle_Popup(object sender, EventArgs e) + { + protectedMenuItem.Checked = false; + inheritMenuItem.Checked = false; + + if (listHandles.SelectedItems.Count == 0) + { + menuHandle.DisableAll(); + } + else if (listHandles.SelectedItems.Count == 1) + { + menuHandle.EnableAll(); + + HandleItem item = (HandleItem)listHandles.SelectedItems[0].Tag; + + protectedMenuItem.Checked = (item.Handle.Flags & HandleFlags.ProtectFromClose) != 0; + inheritMenuItem.Checked = (item.Handle.Flags & HandleFlags.Inherit) != 0; + } + else + { + menuHandle.EnableAll(); + propertiesHandleMenuItem.Enabled = false; + protectedMenuItem.Enabled = false; + inheritMenuItem.Enabled = false; + } + } + + private void closeHandleMenuItem_Click(object sender, EventArgs e) + { + lock (_listLock) + { + bool allGood = true; + + foreach (ListViewItem item in listHandles.SelectedItems) + { + try + { + IntPtr handle = new IntPtr((int)BaseConverter.ToNumberParse(item.SubItems[2].Text)); + + using (ProcessHandle process = + new ProcessHandle(_pid, Program.MinProcessGetHandleInformationRights)) + { + Win32.DuplicateObject(process.Handle, handle, 0, 0, DuplicateOptions.CloseSource); + } + } + catch (Exception ex) + { + allGood = false; + + if (!PhUtils.ShowContinueMessage( + "Unable to close the handle \"" + item.SubItems[1].Text + "\"", + ex + )) + return; + } + } + + if (allGood) + { + foreach (ListViewItem item in listHandles.SelectedItems) + item.Selected = false; + } + } + } + + private void protectedMenuItem_Click(object sender, EventArgs e) + { + HandleItem item = (HandleItem)listHandles.SelectedItems[0].Tag; + HandleFlags flags = item.Handle.Flags; + + if ((flags & HandleFlags.ProtectFromClose) != 0) + flags &= ~HandleFlags.ProtectFromClose; + else + flags |= HandleFlags.ProtectFromClose; + + try + { + using (var phandle = new ProcessHandle(_pid, Program.MinProcessQueryRights)) + KProcessHacker.Instance.SetHandleAttributes(phandle, new IntPtr(item.Handle.Handle), flags); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to set handle attributes", ex); + } + } + + private void inheritMenuItem_Click(object sender, EventArgs e) + { + HandleItem item = (HandleItem)listHandles.SelectedItems[0].Tag; + HandleFlags flags = item.Handle.Flags; + + if ((flags & HandleFlags.Inherit) != 0) + flags &= ~HandleFlags.Inherit; + else + flags |= HandleFlags.Inherit; + + try + { + using (var phandle = new ProcessHandle(_pid, Program.MinProcessQueryRights)) + KProcessHacker.Instance.SetHandleAttributes(phandle, new IntPtr(item.Handle.Handle), flags); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to set handle attributes", ex); + } + } + + private void propertiesHandleMenuItem_Click(object sender, EventArgs e) + { + if (listHandles.SelectedItems.Count != 1) + return; + + var handleInfo = ((HandleItem)listHandles.SelectedItems[0].Tag).Handle; + + try + { + ShowHandleProperties(handleInfo); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to show handle properties", ex); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/HandleList.resx b/branches/ph-plugins/ProcessHacker/Components/HandleList.resx new file mode 100644 index 000000000..90ace843e --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/HandleList.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 125, 17 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/Indicator.Designer.cs b/branches/ph-plugins/ProcessHacker/Components/Indicator.Designer.cs new file mode 100644 index 000000000..ac897479a --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/Indicator.Designer.cs @@ -0,0 +1,47 @@ +using System.Windows.Forms; +using System.Drawing; +namespace ProcessHacker.Components +{ + partial class Indicator + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.SuspendLayout(); + // + // Indicator + // + this.BackColor = System.Drawing.Color.Black; + this.ForeColor = System.Drawing.Color.Lime; + this.Name = "Indicator"; + this.Size = new System.Drawing.Size(72, 74); + this.ResumeLayout(false); + + } + + #endregion + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/Indicator.cs b/branches/ph-plugins/ProcessHacker/Components/Indicator.cs new file mode 100644 index 000000000..b0ed69d94 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/Indicator.cs @@ -0,0 +1,203 @@ +/* + * Process Hacker - + * indicator component + * + * Copyright (C) 2009 Dean + * + * 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 . + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Text; +using System.Windows.Forms; +using System.Drawing.Drawing2D; + +namespace ProcessHacker.Components +{ + public partial class Indicator : UserControl + { + private Color _lineColor1 = Color.FromArgb(255, 0, 0); + public Color Color1 + { + get { return _lineColor1; } + set { _lineColor1 = value; } + } + private Color _lineColor2 = Color.FromArgb(0, 255, 0); + public Color Color2 + { + get { return _lineColor2; } + set { _lineColor2 = value; } + } + private long _data1; + public long Data1 + { + get { return _data1; } + set { _data1 = value; } + } + private long _data2; + public long Data2 + { + get { return _data2; } + set { _data2 = value; } + } + + + + public Indicator() + { + InitializeComponent(); + base.SetStyle(ControlStyles.ResizeRedraw | ControlStyles.UserPaint | + ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true); + } + protected override void OnPaint(PaintEventArgs e) + { + //SolidBrush brush = new SolidBrush(this.ForeColor); + SolidBrush brush1 = new SolidBrush(this.Color1); + SolidBrush brush2 = new SolidBrush(this.Color2); + int width = base.ClientSize.Width; + int height = base.ClientSize.Height; + int num1 = height; + num1 -= this.Font.Height + 4; + RectangleF layoutRectangle = new RectangleF(0f, (float)num1, (float)width, (float)height); + StringFormat format = new StringFormat(StringFormatFlags.NoWrap); + format.Alignment = StringAlignment.Center; + e.Graphics.DrawString(this.Text, this.Font, brush1, layoutRectangle, format); + int num2 = (((height - 6) - 4) - this.Font.Height) - 4; + num2++; + int num3 = num2 / 3; + byte red = (byte)(this.ForeColor.R / 2); + byte green = (byte)(this.ForeColor.G / 2); + byte blue = (byte)(this.ForeColor.B / 2); + + Pen pen = new Pen(Color.FromArgb(red, green, blue)); + pen.DashStyle = DashStyle.Dot; + + int num4 = (width - this.GraphWidth) / 2; + int num5 = ((height - 4) - this.Font.Height) - 7; + int num6 = this.GraphWidth / 2; + int x = num4; + int y = 0; + int num7 = 0; + int num8 = 0; + int num9 = (int)Math.Ceiling((double)(((this.Data1 - this.Minimum) * 1.0) / ((this.Maximum - (this.Minimum * 1.0)) / ((double)num3)))); + int num10 = (int)Math.Ceiling((double)(((this.Data1 + this.Data2 - this.Minimum) * 1.0) / ((this.Maximum - (this.Minimum * 1.0)) / ((double)num3)))); + + for (int i = 0; i < num3; i++) + { + x = num4; + y = (num5 - (i * 3)) - 1; + num7 = x + num6; + num8 = y; + if (i < num9) + { + e.Graphics.FillRectangle(brush1, x, y, num6, 2); + e.Graphics.FillRectangle(brush1, num7 + 1, y, num6, 2); + } + else if (i < num10) + { + e.Graphics.FillRectangle(brush2, x, y, num6, 2); + e.Graphics.FillRectangle(brush2, num7 + 1, y, num6, 2); + } + else + { + e.Graphics.DrawLine(pen, x, y, num7, num8); + e.Graphics.DrawLine(pen, x + 1, y + 1, num7, num8 + 1); + x = num7 + 1; + num7 = x + num6; + e.Graphics.DrawLine(pen, x, y, num7, num8); + e.Graphics.DrawLine(pen, x + 1, y + 1, num7, num8 + 1); + } + } + pen.Dispose(); + //brush.Dispose(); + brush1.Dispose(); + brush2.Dispose(); + } + protected override CreateParams CreateParams + { + get + { + CreateParams createParams = base.CreateParams; + createParams.ExStyle |= 0x200; + return createParams; + } + } + private int _GraphWidth=0x21; + private long _Maximum = long.MaxValue; + private long _Minimum = 0; + public int GraphWidth + { + get + { + return this._GraphWidth; + } + set + { + this._GraphWidth = value; + base.Invalidate(); + } + } + public long Maximum + { + get + { + return this._Maximum; + } + set + { + if (value < this.Minimum) + { + throw new ArgumentException(); + } + this._Maximum = value; + base.Invalidate(); + } + } + public long Minimum + { + get + { + return this._Minimum; + } + set + { + if (value < 0) + { + throw new ArgumentException(); + } + this._Minimum = value; + base.Invalidate(); + } + } + public string TextValue + { + get + { + return base.Text; + } + set + { + base.Text = value; + base.Invalidate(); + } + } + } +} + diff --git a/branches/ph-plugins/ProcessHacker/Components/Indicator.resx b/branches/ph-plugins/ProcessHacker/Components/Indicator.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/Indicator.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/JobProperties.Designer.cs b/branches/ph-plugins/ProcessHacker/Components/JobProperties.Designer.cs new file mode 100644 index 000000000..dfd7017d7 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/JobProperties.Designer.cs @@ -0,0 +1,815 @@ +namespace ProcessHacker.Components +{ + partial class JobProperties + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + _jobObject.Dereference(disposing); + + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.tabControl = new System.Windows.Forms.TabControl(); + this.tabGeneral = new System.Windows.Forms.TabPage(); + this.label3 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.textJobName = new System.Windows.Forms.TextBox(); + this.label1 = new System.Windows.Forms.Label(); + this.listLimits = new System.Windows.Forms.ListView(); + this.columnLimit = new System.Windows.Forms.ColumnHeader(); + this.columnValue = new System.Windows.Forms.ColumnHeader(); + this.listProcesses = new System.Windows.Forms.ListView(); + this.columnName = new System.Windows.Forms.ColumnHeader(); + this.columnPid = new System.Windows.Forms.ColumnHeader(); + this.tabStatistics = new System.Windows.Forms.TabPage(); + this.flowStatistics = new System.Windows.Forms.FlowLayoutPanel(); + this.groupGeneral = new System.Windows.Forms.GroupBox(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.label6 = new System.Windows.Forms.Label(); + this.label8 = new System.Windows.Forms.Label(); + this.label9 = new System.Windows.Forms.Label(); + this.labelGeneralActiveProcesses = new System.Windows.Forms.Label(); + this.labelGeneralTotalProcesses = new System.Windows.Forms.Label(); + this.labelGeneralTerminatedProcesses = new System.Windows.Forms.Label(); + this.groupTime = new System.Windows.Forms.GroupBox(); + this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); + this.label4 = new System.Windows.Forms.Label(); + this.label5 = new System.Windows.Forms.Label(); + this.label7 = new System.Windows.Forms.Label(); + this.labelTimeUserTime = new System.Windows.Forms.Label(); + this.labelTimeKernelTime = new System.Windows.Forms.Label(); + this.labelTimeUserTimePeriod = new System.Windows.Forms.Label(); + this.label13 = new System.Windows.Forms.Label(); + this.labelTimeKernelTimePeriod = new System.Windows.Forms.Label(); + this.groupMemory = new System.Windows.Forms.GroupBox(); + this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel(); + this.label10 = new System.Windows.Forms.Label(); + this.label11 = new System.Windows.Forms.Label(); + this.label12 = new System.Windows.Forms.Label(); + this.labelMemoryPageFaults = new System.Windows.Forms.Label(); + this.labelMemoryPeakProcessUsage = new System.Windows.Forms.Label(); + this.labelMemoryPeakJobUsage = new System.Windows.Forms.Label(); + this.groupIO = new System.Windows.Forms.GroupBox(); + this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel(); + this.label16 = new System.Windows.Forms.Label(); + this.label17 = new System.Windows.Forms.Label(); + this.label18 = new System.Windows.Forms.Label(); + this.label19 = new System.Windows.Forms.Label(); + this.label21 = new System.Windows.Forms.Label(); + this.label23 = new System.Windows.Forms.Label(); + this.labelIOReads = new System.Windows.Forms.Label(); + this.labelIOReadBytes = new System.Windows.Forms.Label(); + this.labelIOWrites = new System.Windows.Forms.Label(); + this.labelIOWriteBytes = new System.Windows.Forms.Label(); + this.labelIOOther = new System.Windows.Forms.Label(); + this.labelIOOtherBytes = new System.Windows.Forms.Label(); + this.timerUpdate = new System.Windows.Forms.Timer(this.components); + this.buttonTerminate = new System.Windows.Forms.Button(); + this.tabControl.SuspendLayout(); + this.tabGeneral.SuspendLayout(); + this.tabStatistics.SuspendLayout(); + this.flowStatistics.SuspendLayout(); + this.groupGeneral.SuspendLayout(); + this.tableLayoutPanel1.SuspendLayout(); + this.groupTime.SuspendLayout(); + this.tableLayoutPanel2.SuspendLayout(); + this.groupMemory.SuspendLayout(); + this.tableLayoutPanel3.SuspendLayout(); + this.groupIO.SuspendLayout(); + this.tableLayoutPanel4.SuspendLayout(); + this.SuspendLayout(); + // + // tabControl + // + this.tabControl.Controls.Add(this.tabGeneral); + this.tabControl.Controls.Add(this.tabStatistics); + this.tabControl.Dock = System.Windows.Forms.DockStyle.Fill; + this.tabControl.Location = new System.Drawing.Point(0, 0); + this.tabControl.Name = "tabControl"; + this.tabControl.SelectedIndex = 0; + this.tabControl.Size = new System.Drawing.Size(646, 434); + this.tabControl.TabIndex = 0; + // + // tabGeneral + // + this.tabGeneral.Controls.Add(this.buttonTerminate); + this.tabGeneral.Controls.Add(this.label3); + this.tabGeneral.Controls.Add(this.label2); + this.tabGeneral.Controls.Add(this.textJobName); + this.tabGeneral.Controls.Add(this.label1); + this.tabGeneral.Controls.Add(this.listLimits); + this.tabGeneral.Controls.Add(this.listProcesses); + this.tabGeneral.Location = new System.Drawing.Point(4, 22); + this.tabGeneral.Name = "tabGeneral"; + this.tabGeneral.Padding = new System.Windows.Forms.Padding(3); + this.tabGeneral.Size = new System.Drawing.Size(638, 408); + this.tabGeneral.TabIndex = 0; + this.tabGeneral.Text = "General"; + this.tabGeneral.UseVisualStyleBackColor = true; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(6, 149); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(36, 13); + this.label3.TabIndex = 4; + this.label3.Text = "Limits:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(6, 34); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(76, 13); + this.label2.TabIndex = 3; + this.label2.Text = "Process in job:"; + // + // textJobName + // + this.textJobName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textJobName.Location = new System.Drawing.Point(50, 6); + this.textJobName.Name = "textJobName"; + this.textJobName.ReadOnly = true; + this.textJobName.Size = new System.Drawing.Size(501, 20); + this.textJobName.TabIndex = 2; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(6, 9); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(38, 13); + this.label1.TabIndex = 1; + this.label1.Text = "Name:"; + // + // listLimits + // + this.listLimits.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listLimits.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnLimit, + this.columnValue}); + this.listLimits.FullRowSelect = true; + this.listLimits.HideSelection = false; + this.listLimits.Location = new System.Drawing.Point(6, 165); + this.listLimits.MultiSelect = false; + this.listLimits.Name = "listLimits"; + this.listLimits.ShowItemToolTips = true; + this.listLimits.Size = new System.Drawing.Size(626, 237); + this.listLimits.Sorting = System.Windows.Forms.SortOrder.Ascending; + this.listLimits.TabIndex = 0; + this.listLimits.UseCompatibleStateImageBehavior = false; + this.listLimits.View = System.Windows.Forms.View.Details; + // + // columnLimit + // + this.columnLimit.Text = "Limit"; + this.columnLimit.Width = 250; + // + // columnValue + // + this.columnValue.Text = "Value"; + this.columnValue.Width = 150; + // + // listProcesses + // + this.listProcesses.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listProcesses.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnName, + this.columnPid}); + this.listProcesses.FullRowSelect = true; + this.listProcesses.HideSelection = false; + this.listProcesses.Location = new System.Drawing.Point(6, 50); + this.listProcesses.MultiSelect = false; + this.listProcesses.Name = "listProcesses"; + this.listProcesses.ShowItemToolTips = true; + this.listProcesses.Size = new System.Drawing.Size(626, 96); + this.listProcesses.Sorting = System.Windows.Forms.SortOrder.Ascending; + this.listProcesses.TabIndex = 0; + this.listProcesses.UseCompatibleStateImageBehavior = false; + this.listProcesses.View = System.Windows.Forms.View.Details; + // + // columnName + // + this.columnName.Text = "Name"; + this.columnName.Width = 200; + // + // columnPid + // + this.columnPid.Text = "PID"; + // + // tabStatistics + // + this.tabStatistics.Controls.Add(this.flowStatistics); + this.tabStatistics.Location = new System.Drawing.Point(4, 22); + this.tabStatistics.Name = "tabStatistics"; + this.tabStatistics.Padding = new System.Windows.Forms.Padding(3); + this.tabStatistics.Size = new System.Drawing.Size(638, 408); + this.tabStatistics.TabIndex = 2; + this.tabStatistics.Text = "Statistics"; + this.tabStatistics.UseVisualStyleBackColor = true; + // + // flowStatistics + // + this.flowStatistics.Controls.Add(this.groupGeneral); + this.flowStatistics.Controls.Add(this.groupTime); + this.flowStatistics.Controls.Add(this.groupMemory); + this.flowStatistics.Controls.Add(this.groupIO); + this.flowStatistics.Dock = System.Windows.Forms.DockStyle.Fill; + this.flowStatistics.FlowDirection = System.Windows.Forms.FlowDirection.TopDown; + this.flowStatistics.Location = new System.Drawing.Point(3, 3); + this.flowStatistics.Name = "flowStatistics"; + this.flowStatistics.Size = new System.Drawing.Size(632, 402); + this.flowStatistics.TabIndex = 2; + // + // groupGeneral + // + this.groupGeneral.Controls.Add(this.tableLayoutPanel1); + this.groupGeneral.Location = new System.Drawing.Point(3, 3); + this.groupGeneral.Name = "groupGeneral"; + this.groupGeneral.Size = new System.Drawing.Size(195, 81); + this.groupGeneral.TabIndex = 1; + this.groupGeneral.TabStop = false; + this.groupGeneral.Text = "General"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 2; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.Controls.Add(this.label6, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.label8, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.label9, 0, 2); + this.tableLayoutPanel1.Controls.Add(this.labelGeneralActiveProcesses, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.labelGeneralTotalProcesses, 1, 1); + this.tableLayoutPanel1.Controls.Add(this.labelGeneralTerminatedProcesses, 1, 2); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(3, 16); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 3; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(189, 62); + this.tableLayoutPanel1.TabIndex = 1; + // + // label6 + // + this.label6.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(3, 3); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(89, 13); + this.label6.TabIndex = 1; + this.label6.Text = "Active Processes"; + // + // label8 + // + this.label8.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label8.AutoSize = true; + this.label8.Location = new System.Drawing.Point(3, 23); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(83, 13); + this.label8.TabIndex = 1; + this.label8.Text = "Total Processes"; + // + // label9 + // + this.label9.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label9.AutoSize = true; + this.label9.Location = new System.Drawing.Point(3, 44); + this.label9.Name = "label9"; + this.label9.Size = new System.Drawing.Size(112, 13); + this.label9.TabIndex = 1; + this.label9.Text = "Terminated Processes"; + // + // labelGeneralActiveProcesses + // + this.labelGeneralActiveProcesses.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelGeneralActiveProcesses.AutoSize = true; + this.labelGeneralActiveProcesses.Location = new System.Drawing.Point(153, 3); + this.labelGeneralActiveProcesses.Name = "labelGeneralActiveProcesses"; + this.labelGeneralActiveProcesses.Size = new System.Drawing.Size(33, 13); + this.labelGeneralActiveProcesses.TabIndex = 1; + this.labelGeneralActiveProcesses.Text = "value"; + // + // labelGeneralTotalProcesses + // + this.labelGeneralTotalProcesses.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelGeneralTotalProcesses.AutoSize = true; + this.labelGeneralTotalProcesses.Location = new System.Drawing.Point(153, 23); + this.labelGeneralTotalProcesses.Name = "labelGeneralTotalProcesses"; + this.labelGeneralTotalProcesses.Size = new System.Drawing.Size(33, 13); + this.labelGeneralTotalProcesses.TabIndex = 1; + this.labelGeneralTotalProcesses.Text = "value"; + // + // labelGeneralTerminatedProcesses + // + this.labelGeneralTerminatedProcesses.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelGeneralTerminatedProcesses.AutoSize = true; + this.labelGeneralTerminatedProcesses.Location = new System.Drawing.Point(153, 44); + this.labelGeneralTerminatedProcesses.Name = "labelGeneralTerminatedProcesses"; + this.labelGeneralTerminatedProcesses.Size = new System.Drawing.Size(33, 13); + this.labelGeneralTerminatedProcesses.TabIndex = 1; + this.labelGeneralTerminatedProcesses.Text = "value"; + // + // groupTime + // + this.groupTime.Controls.Add(this.tableLayoutPanel2); + this.groupTime.Location = new System.Drawing.Point(3, 90); + this.groupTime.Name = "groupTime"; + this.groupTime.Size = new System.Drawing.Size(195, 100); + this.groupTime.TabIndex = 2; + this.groupTime.TabStop = false; + this.groupTime.Text = "Time"; + // + // tableLayoutPanel2 + // + this.tableLayoutPanel2.ColumnCount = 2; + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel2.Controls.Add(this.label4, 0, 0); + this.tableLayoutPanel2.Controls.Add(this.label5, 0, 1); + this.tableLayoutPanel2.Controls.Add(this.label7, 0, 2); + this.tableLayoutPanel2.Controls.Add(this.labelTimeUserTime, 1, 0); + this.tableLayoutPanel2.Controls.Add(this.labelTimeKernelTime, 1, 1); + this.tableLayoutPanel2.Controls.Add(this.labelTimeUserTimePeriod, 1, 2); + this.tableLayoutPanel2.Controls.Add(this.label13, 0, 3); + this.tableLayoutPanel2.Controls.Add(this.labelTimeKernelTimePeriod, 1, 3); + this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 16); + this.tableLayoutPanel2.Name = "tableLayoutPanel2"; + this.tableLayoutPanel2.RowCount = 4; + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel2.Size = new System.Drawing.Size(189, 81); + this.tableLayoutPanel2.TabIndex = 1; + // + // label4 + // + this.label4.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(3, 3); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(55, 13); + this.label4.TabIndex = 1; + this.label4.Text = "User Time"; + // + // label5 + // + this.label5.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(3, 23); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(63, 13); + this.label5.TabIndex = 1; + this.label5.Text = "Kernel Time"; + // + // label7 + // + this.label7.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(3, 43); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(112, 13); + this.label7.TabIndex = 1; + this.label7.Text = "User Time (this period)"; + // + // labelTimeUserTime + // + this.labelTimeUserTime.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelTimeUserTime.AutoSize = true; + this.labelTimeUserTime.Location = new System.Drawing.Point(153, 3); + this.labelTimeUserTime.Name = "labelTimeUserTime"; + this.labelTimeUserTime.Size = new System.Drawing.Size(33, 13); + this.labelTimeUserTime.TabIndex = 1; + this.labelTimeUserTime.Text = "value"; + // + // labelTimeKernelTime + // + this.labelTimeKernelTime.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelTimeKernelTime.AutoSize = true; + this.labelTimeKernelTime.Location = new System.Drawing.Point(153, 23); + this.labelTimeKernelTime.Name = "labelTimeKernelTime"; + this.labelTimeKernelTime.Size = new System.Drawing.Size(33, 13); + this.labelTimeKernelTime.TabIndex = 1; + this.labelTimeKernelTime.Text = "value"; + // + // labelTimeUserTimePeriod + // + this.labelTimeUserTimePeriod.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelTimeUserTimePeriod.AutoSize = true; + this.labelTimeUserTimePeriod.Location = new System.Drawing.Point(153, 43); + this.labelTimeUserTimePeriod.Name = "labelTimeUserTimePeriod"; + this.labelTimeUserTimePeriod.Size = new System.Drawing.Size(33, 13); + this.labelTimeUserTimePeriod.TabIndex = 1; + this.labelTimeUserTimePeriod.Text = "value"; + // + // label13 + // + this.label13.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label13.AutoSize = true; + this.label13.Location = new System.Drawing.Point(3, 64); + this.label13.Name = "label13"; + this.label13.Size = new System.Drawing.Size(120, 13); + this.label13.TabIndex = 1; + this.label13.Text = "Kernel Time (this period)"; + // + // labelTimeKernelTimePeriod + // + this.labelTimeKernelTimePeriod.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelTimeKernelTimePeriod.AutoSize = true; + this.labelTimeKernelTimePeriod.Location = new System.Drawing.Point(153, 64); + this.labelTimeKernelTimePeriod.Name = "labelTimeKernelTimePeriod"; + this.labelTimeKernelTimePeriod.Size = new System.Drawing.Size(33, 13); + this.labelTimeKernelTimePeriod.TabIndex = 1; + this.labelTimeKernelTimePeriod.Text = "value"; + // + // groupMemory + // + this.groupMemory.Controls.Add(this.tableLayoutPanel3); + this.groupMemory.Location = new System.Drawing.Point(3, 196); + this.groupMemory.Name = "groupMemory"; + this.groupMemory.Size = new System.Drawing.Size(195, 78); + this.groupMemory.TabIndex = 2; + this.groupMemory.TabStop = false; + this.groupMemory.Text = "Memory"; + // + // tableLayoutPanel3 + // + this.tableLayoutPanel3.ColumnCount = 2; + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel3.Controls.Add(this.label10, 0, 0); + this.tableLayoutPanel3.Controls.Add(this.label11, 0, 1); + this.tableLayoutPanel3.Controls.Add(this.label12, 0, 2); + this.tableLayoutPanel3.Controls.Add(this.labelMemoryPageFaults, 1, 0); + this.tableLayoutPanel3.Controls.Add(this.labelMemoryPeakProcessUsage, 1, 1); + this.tableLayoutPanel3.Controls.Add(this.labelMemoryPeakJobUsage, 1, 2); + this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel3.Location = new System.Drawing.Point(3, 16); + this.tableLayoutPanel3.Name = "tableLayoutPanel3"; + this.tableLayoutPanel3.RowCount = 3; + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); + this.tableLayoutPanel3.Size = new System.Drawing.Size(189, 59); + this.tableLayoutPanel3.TabIndex = 1; + // + // label10 + // + this.label10.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label10.AutoSize = true; + this.label10.Location = new System.Drawing.Point(3, 3); + this.label10.Name = "label10"; + this.label10.Size = new System.Drawing.Size(63, 13); + this.label10.TabIndex = 1; + this.label10.Text = "Page Faults"; + // + // label11 + // + this.label11.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label11.AutoSize = true; + this.label11.Location = new System.Drawing.Point(3, 22); + this.label11.Name = "label11"; + this.label11.Size = new System.Drawing.Size(107, 13); + this.label11.TabIndex = 1; + this.label11.Text = "Peak Process Usage"; + // + // label12 + // + this.label12.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label12.AutoSize = true; + this.label12.Location = new System.Drawing.Point(3, 42); + this.label12.Name = "label12"; + this.label12.Size = new System.Drawing.Size(86, 13); + this.label12.TabIndex = 1; + this.label12.Text = "Peak Job Usage"; + // + // labelMemoryPageFaults + // + this.labelMemoryPageFaults.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelMemoryPageFaults.AutoSize = true; + this.labelMemoryPageFaults.Location = new System.Drawing.Point(153, 3); + this.labelMemoryPageFaults.Name = "labelMemoryPageFaults"; + this.labelMemoryPageFaults.Size = new System.Drawing.Size(33, 13); + this.labelMemoryPageFaults.TabIndex = 1; + this.labelMemoryPageFaults.Text = "value"; + // + // labelMemoryPeakProcessUsage + // + this.labelMemoryPeakProcessUsage.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelMemoryPeakProcessUsage.AutoSize = true; + this.labelMemoryPeakProcessUsage.Location = new System.Drawing.Point(153, 22); + this.labelMemoryPeakProcessUsage.Name = "labelMemoryPeakProcessUsage"; + this.labelMemoryPeakProcessUsage.Size = new System.Drawing.Size(33, 13); + this.labelMemoryPeakProcessUsage.TabIndex = 1; + this.labelMemoryPeakProcessUsage.Text = "value"; + // + // labelMemoryPeakJobUsage + // + this.labelMemoryPeakJobUsage.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelMemoryPeakJobUsage.AutoSize = true; + this.labelMemoryPeakJobUsage.Location = new System.Drawing.Point(153, 42); + this.labelMemoryPeakJobUsage.Name = "labelMemoryPeakJobUsage"; + this.labelMemoryPeakJobUsage.Size = new System.Drawing.Size(33, 13); + this.labelMemoryPeakJobUsage.TabIndex = 1; + this.labelMemoryPeakJobUsage.Text = "value"; + // + // groupIO + // + this.groupIO.Controls.Add(this.tableLayoutPanel4); + this.groupIO.Location = new System.Drawing.Point(204, 3); + this.groupIO.Name = "groupIO"; + this.groupIO.Size = new System.Drawing.Size(195, 136); + this.groupIO.TabIndex = 3; + this.groupIO.TabStop = false; + this.groupIO.Text = "I/O"; + // + // tableLayoutPanel4 + // + this.tableLayoutPanel4.ColumnCount = 2; + this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel4.Controls.Add(this.label16, 0, 5); + this.tableLayoutPanel4.Controls.Add(this.label17, 0, 4); + this.tableLayoutPanel4.Controls.Add(this.label18, 0, 0); + this.tableLayoutPanel4.Controls.Add(this.label19, 0, 1); + this.tableLayoutPanel4.Controls.Add(this.label21, 0, 2); + this.tableLayoutPanel4.Controls.Add(this.label23, 0, 3); + this.tableLayoutPanel4.Controls.Add(this.labelIOReads, 1, 0); + this.tableLayoutPanel4.Controls.Add(this.labelIOReadBytes, 1, 1); + this.tableLayoutPanel4.Controls.Add(this.labelIOWrites, 1, 2); + this.tableLayoutPanel4.Controls.Add(this.labelIOWriteBytes, 1, 3); + this.tableLayoutPanel4.Controls.Add(this.labelIOOther, 1, 4); + this.tableLayoutPanel4.Controls.Add(this.labelIOOtherBytes, 1, 5); + this.tableLayoutPanel4.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel4.Location = new System.Drawing.Point(3, 16); + this.tableLayoutPanel4.Name = "tableLayoutPanel4"; + this.tableLayoutPanel4.RowCount = 6; + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel4.Size = new System.Drawing.Size(189, 117); + this.tableLayoutPanel4.TabIndex = 1; + // + // label16 + // + this.label16.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label16.AutoSize = true; + this.label16.Location = new System.Drawing.Point(3, 99); + this.label16.Name = "label16"; + this.label16.Size = new System.Drawing.Size(62, 13); + this.label16.TabIndex = 5; + this.label16.Text = "Other Bytes"; + // + // label17 + // + this.label17.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label17.AutoSize = true; + this.label17.Location = new System.Drawing.Point(3, 79); + this.label17.Name = "label17"; + this.label17.Size = new System.Drawing.Size(33, 13); + this.label17.TabIndex = 3; + this.label17.Text = "Other"; + // + // label18 + // + this.label18.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label18.AutoSize = true; + this.label18.Location = new System.Drawing.Point(3, 3); + this.label18.Name = "label18"; + this.label18.Size = new System.Drawing.Size(38, 13); + this.label18.TabIndex = 1; + this.label18.Text = "Reads"; + // + // label19 + // + this.label19.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label19.AutoSize = true; + this.label19.Location = new System.Drawing.Point(3, 22); + this.label19.Name = "label19"; + this.label19.Size = new System.Drawing.Size(62, 13); + this.label19.TabIndex = 1; + this.label19.Text = "Read Bytes"; + // + // label21 + // + this.label21.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label21.AutoSize = true; + this.label21.Location = new System.Drawing.Point(3, 41); + this.label21.Name = "label21"; + this.label21.Size = new System.Drawing.Size(37, 13); + this.label21.TabIndex = 1; + this.label21.Text = "Writes"; + // + // label23 + // + this.label23.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label23.AutoSize = true; + this.label23.Location = new System.Drawing.Point(3, 60); + this.label23.Name = "label23"; + this.label23.Size = new System.Drawing.Size(61, 13); + this.label23.TabIndex = 1; + this.label23.Text = "Write Bytes"; + // + // labelIOReads + // + this.labelIOReads.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelIOReads.AutoSize = true; + this.labelIOReads.Location = new System.Drawing.Point(153, 3); + this.labelIOReads.Name = "labelIOReads"; + this.labelIOReads.Size = new System.Drawing.Size(33, 13); + this.labelIOReads.TabIndex = 1; + this.labelIOReads.Text = "value"; + // + // labelIOReadBytes + // + this.labelIOReadBytes.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelIOReadBytes.AutoSize = true; + this.labelIOReadBytes.Location = new System.Drawing.Point(153, 22); + this.labelIOReadBytes.Name = "labelIOReadBytes"; + this.labelIOReadBytes.Size = new System.Drawing.Size(33, 13); + this.labelIOReadBytes.TabIndex = 1; + this.labelIOReadBytes.Text = "value"; + // + // labelIOWrites + // + this.labelIOWrites.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelIOWrites.AutoSize = true; + this.labelIOWrites.Location = new System.Drawing.Point(153, 41); + this.labelIOWrites.Name = "labelIOWrites"; + this.labelIOWrites.Size = new System.Drawing.Size(33, 13); + this.labelIOWrites.TabIndex = 1; + this.labelIOWrites.Text = "value"; + // + // labelIOWriteBytes + // + this.labelIOWriteBytes.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelIOWriteBytes.AutoSize = true; + this.labelIOWriteBytes.Location = new System.Drawing.Point(153, 60); + this.labelIOWriteBytes.Name = "labelIOWriteBytes"; + this.labelIOWriteBytes.Size = new System.Drawing.Size(33, 13); + this.labelIOWriteBytes.TabIndex = 1; + this.labelIOWriteBytes.Text = "value"; + // + // labelIOOther + // + this.labelIOOther.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelIOOther.AutoSize = true; + this.labelIOOther.Location = new System.Drawing.Point(153, 79); + this.labelIOOther.Name = "labelIOOther"; + this.labelIOOther.Size = new System.Drawing.Size(33, 13); + this.labelIOOther.TabIndex = 1; + this.labelIOOther.Text = "value"; + // + // labelIOOtherBytes + // + this.labelIOOtherBytes.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelIOOtherBytes.AutoSize = true; + this.labelIOOtherBytes.Location = new System.Drawing.Point(153, 99); + this.labelIOOtherBytes.Name = "labelIOOtherBytes"; + this.labelIOOtherBytes.Size = new System.Drawing.Size(33, 13); + this.labelIOOtherBytes.TabIndex = 1; + this.labelIOOtherBytes.Text = "value"; + // + // timerUpdate + // + this.timerUpdate.Enabled = true; + this.timerUpdate.Interval = 1000; + this.timerUpdate.Tick += new System.EventHandler(this.timerUpdate_Tick); + // + // buttonTerminate + // + this.buttonTerminate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonTerminate.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonTerminate.Location = new System.Drawing.Point(557, 6); + this.buttonTerminate.Name = "buttonTerminate"; + this.buttonTerminate.Size = new System.Drawing.Size(75, 23); + this.buttonTerminate.TabIndex = 5; + this.buttonTerminate.Text = "Terminate"; + this.buttonTerminate.UseVisualStyleBackColor = true; + this.buttonTerminate.Click += new System.EventHandler(this.buttonTerminate_Click); + // + // JobProperties + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.tabControl); + this.DoubleBuffered = true; + this.Name = "JobProperties"; + this.Size = new System.Drawing.Size(646, 434); + this.tabControl.ResumeLayout(false); + this.tabGeneral.ResumeLayout(false); + this.tabGeneral.PerformLayout(); + this.tabStatistics.ResumeLayout(false); + this.flowStatistics.ResumeLayout(false); + this.groupGeneral.ResumeLayout(false); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.groupTime.ResumeLayout(false); + this.tableLayoutPanel2.ResumeLayout(false); + this.tableLayoutPanel2.PerformLayout(); + this.groupMemory.ResumeLayout(false); + this.tableLayoutPanel3.ResumeLayout(false); + this.tableLayoutPanel3.PerformLayout(); + this.groupIO.ResumeLayout(false); + this.tableLayoutPanel4.ResumeLayout(false); + this.tableLayoutPanel4.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TabControl tabControl; + private System.Windows.Forms.TabPage tabGeneral; + private System.Windows.Forms.TabPage tabStatistics; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox textJobName; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.ListView listProcesses; + private System.Windows.Forms.ColumnHeader columnName; + private System.Windows.Forms.ColumnHeader columnPid; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.ListView listLimits; + private System.Windows.Forms.ColumnHeader columnLimit; + private System.Windows.Forms.ColumnHeader columnValue; + private System.Windows.Forms.GroupBox groupGeneral; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.Label label8; + private System.Windows.Forms.Label label9; + private System.Windows.Forms.Label labelGeneralActiveProcesses; + private System.Windows.Forms.Label labelGeneralTotalProcesses; + private System.Windows.Forms.Label labelGeneralTerminatedProcesses; + private System.Windows.Forms.FlowLayoutPanel flowStatistics; + private System.Windows.Forms.Timer timerUpdate; + private System.Windows.Forms.GroupBox groupTime; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.Label labelTimeUserTime; + private System.Windows.Forms.Label labelTimeKernelTime; + private System.Windows.Forms.Label labelTimeUserTimePeriod; + private System.Windows.Forms.Label label13; + private System.Windows.Forms.Label labelTimeKernelTimePeriod; + private System.Windows.Forms.GroupBox groupMemory; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3; + private System.Windows.Forms.Label label10; + private System.Windows.Forms.Label label11; + private System.Windows.Forms.Label label12; + private System.Windows.Forms.Label labelMemoryPageFaults; + private System.Windows.Forms.Label labelMemoryPeakProcessUsage; + private System.Windows.Forms.Label labelMemoryPeakJobUsage; + private System.Windows.Forms.GroupBox groupIO; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel4; + private System.Windows.Forms.Label label16; + private System.Windows.Forms.Label label17; + private System.Windows.Forms.Label label18; + private System.Windows.Forms.Label label19; + private System.Windows.Forms.Label label21; + private System.Windows.Forms.Label label23; + private System.Windows.Forms.Label labelIOReads; + private System.Windows.Forms.Label labelIOReadBytes; + private System.Windows.Forms.Label labelIOWrites; + private System.Windows.Forms.Label labelIOWriteBytes; + private System.Windows.Forms.Label labelIOOther; + private System.Windows.Forms.Label labelIOOtherBytes; + private System.Windows.Forms.Button buttonTerminate; + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/JobProperties.cs b/branches/ph-plugins/ProcessHacker/Components/JobProperties.cs new file mode 100644 index 000000000..4dc63def6 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/JobProperties.cs @@ -0,0 +1,234 @@ +/* + * Process Hacker - + * job properties + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Components +{ + public partial class JobProperties : UserControl + { + private JobObjectHandle _jobObject; + + public JobProperties(JobObjectHandle jobObject) + { + InitializeComponent(); + + _jobObject = jobObject; + _jobObject.Reference(); + timerUpdate.Interval = Properties.Settings.Default.RefreshInterval; + this.UpdateStatistics(); + + try + { + string name = _jobObject.GetObjectName(); + + if (string.IsNullOrEmpty(name)) + textJobName.Text = "(unnamed job)"; + else + textJobName.Text = name; + } + catch + { } + + try + { + foreach (int pid in _jobObject.GetProcessIdList()) + { + ListViewItem item = new ListViewItem(); + + if (Program.ProcessProvider.Dictionary.ContainsKey(pid)) + item.Text = Program.ProcessProvider.Dictionary[pid].Name; + else + item.Text = "(unknown)"; + + item.SubItems.Add(new ListViewItem.ListViewSubItem(item, pid.ToString())); + + listProcesses.Items.Add(item); + } + } + catch + { } + + try + { + var extendedLimits = _jobObject.GetExtendedLimitInformation(); + var uiRestrictions = _jobObject.GetBasicUiRestrictions(); + var flags = extendedLimits.BasicLimitInformation.LimitFlags; + + if ((flags & JobObjectLimitFlags.ActiveProcess) != 0) + this.AddLimit("Active Processes", extendedLimits.BasicLimitInformation.ActiveProcessLimit.ToString()); + if ((flags & JobObjectLimitFlags.Affinity) != 0) + this.AddLimit("Affinity", extendedLimits.BasicLimitInformation.Affinity.ToString("x")); + if ((flags & JobObjectLimitFlags.BreakawayOk) != 0) + this.AddLimit("Breakaway OK", "Enabled"); + if ((flags & JobObjectLimitFlags.DieOnUnhandledException) != 0) + this.AddLimit("Die on Unhandled Exception", "Enabled"); + if ((flags & JobObjectLimitFlags.JobMemory) != 0) + this.AddLimit("Job Memory", Utils.FormatSize(extendedLimits.JobMemoryLimit)); + if ((flags & JobObjectLimitFlags.JobTime) != 0) + this.AddLimit("Job Time", + Utils.FormatTimeSpan(new TimeSpan(extendedLimits.BasicLimitInformation.PerJobUserTimeLimit))); + if ((flags & JobObjectLimitFlags.KillOnJobClose) != 0) + this.AddLimit("Kill on Job Close", "Enabled"); + if ((flags & JobObjectLimitFlags.PriorityClass) != 0) + this.AddLimit("Priority Class", + ((System.Diagnostics.ProcessPriorityClass)extendedLimits.BasicLimitInformation.PriorityClass).ToString()); + if ((flags & JobObjectLimitFlags.ProcessMemory) != 0) + this.AddLimit("Process Memory", Utils.FormatSize(extendedLimits.ProcessMemoryLimit)); + if ((flags & JobObjectLimitFlags.ProcessTime) != 0) + this.AddLimit("Process Time", + Utils.FormatTimeSpan(new TimeSpan(extendedLimits.BasicLimitInformation.PerProcessUserTimeLimit))); + if ((flags & JobObjectLimitFlags.SchedulingClass) != 0) + this.AddLimit("Scheduling Class", extendedLimits.BasicLimitInformation.SchedulingClass.ToString()); + if ((flags & JobObjectLimitFlags.SilentBreakawayOk) != 0) + this.AddLimit("Silent Breakaway OK", "Enabled"); + if ((flags & JobObjectLimitFlags.WorkingSet) != 0) + { + this.AddLimit("Minimum Working Set", Utils.FormatSize(extendedLimits.BasicLimitInformation.MinimumWorkingSetSize)); + this.AddLimit("Maximum Working Set", Utils.FormatSize(extendedLimits.BasicLimitInformation.MaximumWorkingSetSize)); + } + + if ((uiRestrictions & JobObjectBasicUiRestrictions.Desktop) != 0) + this.AddLimit("Desktop", "Limited"); + if ((uiRestrictions & JobObjectBasicUiRestrictions.DisplaySettings) != 0) + this.AddLimit("Display Settings", "Limited"); + if ((uiRestrictions & JobObjectBasicUiRestrictions.ExitWindows) != 0) + this.AddLimit("Exit Windows", "Limited"); + if ((uiRestrictions & JobObjectBasicUiRestrictions.GlobalAtoms) != 0) + this.AddLimit("Global Atoms", "Limited"); + if ((uiRestrictions & JobObjectBasicUiRestrictions.Handles) != 0) + this.AddLimit("Handles", "Limited"); + if ((uiRestrictions & JobObjectBasicUiRestrictions.ReadClipboard) != 0) + this.AddLimit("Read Clipboard", "Limited"); + if ((uiRestrictions & JobObjectBasicUiRestrictions.SystemParameters) != 0) + this.AddLimit("System Parameters", "Limited"); + if ((uiRestrictions & JobObjectBasicUiRestrictions.WriteClipboard) != 0) + this.AddLimit("Write Clipboard", "Limited"); + } + catch + { } + } + + private void AddLimit(string name, string value) + { + listLimits.Items.Add(new ListViewItem(new string[] { name, value })); + } + + public JobObjectHandle JobObject + { + get { return _jobObject; } + } + + public bool UpdateEnabled + { + get { return timerUpdate.Enabled; } + set { timerUpdate.Enabled = value; } + } + + public void SaveSettings() + { + + } + + private void UpdateStatistics() + { + try + { + var accounting = _jobObject.GetBasicAndIoAccountingInformation(); + var limits = _jobObject.GetExtendedLimitInformation(); + + labelGeneralActiveProcesses.Text = accounting.BasicInfo.ActiveProcesses.ToString("N0"); + labelGeneralTotalProcesses.Text = accounting.BasicInfo.TotalProcesses.ToString("N0"); + labelGeneralTerminatedProcesses.Text = accounting.BasicInfo.TotalTerminatedProcesses.ToString("N0"); + + labelTimeUserTime.Text = Utils.FormatTimeSpan(new TimeSpan(accounting.BasicInfo.TotalUserTime)); + labelTimeKernelTime.Text = Utils.FormatTimeSpan(new TimeSpan(accounting.BasicInfo.TotalKernelTime)); + labelTimeUserTimePeriod.Text = Utils.FormatTimeSpan(new TimeSpan(accounting.BasicInfo.ThisPeriodTotalUserTime)); + labelTimeKernelTimePeriod.Text = Utils.FormatTimeSpan(new TimeSpan(accounting.BasicInfo.ThisPeriodTotalKernelTime)); + + labelMemoryPageFaults.Text = accounting.BasicInfo.TotalPageFaultCount.ToString("N0"); + labelMemoryPeakProcessUsage.Text = Utils.FormatSize(limits.PeakProcessMemoryUsed); + labelMemoryPeakJobUsage.Text = Utils.FormatSize(limits.PeakJobMemoryUsed); + + labelIOReads.Text = accounting.IoInfo.ReadOperationCount.ToString("N0"); + labelIOReadBytes.Text = Utils.FormatSize(accounting.IoInfo.ReadTransferCount); + labelIOWrites.Text = accounting.IoInfo.WriteOperationCount.ToString("N0"); + labelIOWriteBytes.Text = Utils.FormatSize(accounting.IoInfo.WriteTransferCount); + labelIOOther.Text = accounting.IoInfo.OtherOperationCount.ToString("N0"); + labelIOOtherBytes.Text = Utils.FormatSize(accounting.IoInfo.OtherTransferCount); + } + catch + { } + } + + private void timerUpdate_Tick(object sender, EventArgs e) + { + this.UpdateStatistics(); + } + + private void buttonTerminate_Click(object sender, EventArgs e) + { + if (OSVersion.HasTaskDialogs) + { + TaskDialog td = new TaskDialog(); + + td.WindowTitle = "Process Hacker"; + td.MainIcon = TaskDialogIcon.Warning; + td.MainInstruction = "Do you want to terminate the job?"; + td.Content = "Terminating a job will terminate all processes assigned to it. Are you sure " + + "you want to continue?"; + td.Buttons = new TaskDialogButton[] + { + new TaskDialogButton((int)DialogResult.Yes, "Terminate"), + new TaskDialogButton((int)DialogResult.No, "Cancel") + }; + td.DefaultButton = (int)DialogResult.No; + + if (td.Show(this) == (int)DialogResult.No) + return; + } + else + { + if (MessageBox.Show("Are you sure you want to terminate the job? This action will " + + "terminate all processes associated with the job.", "Process Hacker", + MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.No) + return; + } + + try + { + using (var jhandle2 = _jobObject.Duplicate(JobObjectAccess.Terminate)) + JobObjectHandle.FromHandle(jhandle2).Terminate(); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to terminate the job", ex); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/JobProperties.resx b/branches/ph-plugins/ProcessHacker/Components/JobProperties.resx new file mode 100644 index 000000000..3add4121b --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/JobProperties.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/MemoryList.Designer.cs b/branches/ph-plugins/ProcessHacker/Components/MemoryList.Designer.cs new file mode 100644 index 000000000..27b8fe625 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/MemoryList.Designer.cs @@ -0,0 +1,203 @@ +namespace ProcessHacker.Components +{ + partial class MemoryList + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + this.Provider = null; + + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.listMemory = new System.Windows.Forms.ListView(); + this.columnName = new System.Windows.Forms.ColumnHeader(); + this.columnAddress = new System.Windows.Forms.ColumnHeader(); + this.columnSize = new System.Windows.Forms.ColumnHeader(); + this.columnProtection = new System.Windows.Forms.ColumnHeader(); + this.vistaMenu = new wyDay.Controls.VistaMenu(this.components); + this.changeMemoryProtectionMemoryMenuItem = new System.Windows.Forms.MenuItem(); + this.readWriteMemoryMemoryMenuItem = new System.Windows.Forms.MenuItem(); + this.readWriteAddressMemoryMenuItem = new System.Windows.Forms.MenuItem(); + this.copyMemoryMenuItem = new System.Windows.Forms.MenuItem(); + this.freeMenuItem = new System.Windows.Forms.MenuItem(); + this.decommitMenuItem = new System.Windows.Forms.MenuItem(); + this.dumpMemoryMenuItem = new System.Windows.Forms.MenuItem(); + this.menuMemory = new System.Windows.Forms.ContextMenu(); + this.menuItem2 = new System.Windows.Forms.MenuItem(); + this.selectAllMemoryMenuItem = new System.Windows.Forms.MenuItem(); + ((System.ComponentModel.ISupportInitialize)(this.vistaMenu)).BeginInit(); + this.SuspendLayout(); + // + // listMemory + // + this.listMemory.AllowColumnReorder = true; + this.listMemory.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnName, + this.columnAddress, + this.columnSize, + this.columnProtection}); + this.listMemory.Dock = System.Windows.Forms.DockStyle.Fill; + this.listMemory.FullRowSelect = true; + this.listMemory.HideSelection = false; + this.listMemory.Location = new System.Drawing.Point(0, 0); + this.listMemory.Name = "listMemory"; + this.listMemory.ShowItemToolTips = true; + this.listMemory.Size = new System.Drawing.Size(450, 472); + this.listMemory.TabIndex = 3; + this.listMemory.UseCompatibleStateImageBehavior = false; + this.listMemory.View = System.Windows.Forms.View.Details; + this.listMemory.DoubleClick += new System.EventHandler(this.listMemory_DoubleClick); + // + // columnName + // + this.columnName.Text = "Name"; + this.columnName.Width = 160; + // + // columnAddress + // + this.columnAddress.Text = "Address"; + this.columnAddress.Width = 80; + // + // columnSize + // + this.columnSize.Text = "Size"; + // + // columnProtection + // + this.columnProtection.Text = "Protection"; + // + // vistaMenu + // + this.vistaMenu.ContainerControl = this; + this.vistaMenu.DelaySetImageCalls = false; + // + // changeMemoryProtectionMemoryMenuItem + // + this.vistaMenu.SetImage(this.changeMemoryProtectionMemoryMenuItem, global::ProcessHacker.Properties.Resources.lock_edit); + this.changeMemoryProtectionMemoryMenuItem.Index = 2; + this.changeMemoryProtectionMemoryMenuItem.Text = "Change &Memory Protection..."; + this.changeMemoryProtectionMemoryMenuItem.Click += new System.EventHandler(this.changeMemoryProtectionMemoryMenuItem_Click); + // + // readWriteMemoryMemoryMenuItem + // + this.readWriteMemoryMemoryMenuItem.DefaultItem = true; + this.vistaMenu.SetImage(this.readWriteMemoryMemoryMenuItem, global::ProcessHacker.Properties.Resources.page_edit); + this.readWriteMemoryMemoryMenuItem.Index = 0; + this.readWriteMemoryMemoryMenuItem.Text = "Read/Write Memory"; + this.readWriteMemoryMemoryMenuItem.Click += new System.EventHandler(this.readWriteMemoryMemoryMenuItem_Click); + // + // readWriteAddressMemoryMenuItem + // + this.vistaMenu.SetImage(this.readWriteAddressMemoryMenuItem, global::ProcessHacker.Properties.Resources.pencil_go); + this.readWriteAddressMemoryMenuItem.Index = 6; + this.readWriteAddressMemoryMenuItem.Text = "Read/Write Address..."; + this.readWriteAddressMemoryMenuItem.Click += new System.EventHandler(this.readWriteAddressMemoryMenuItem_Click); + // + // copyMemoryMenuItem + // + this.vistaMenu.SetImage(this.copyMemoryMenuItem, global::ProcessHacker.Properties.Resources.page_copy); + this.copyMemoryMenuItem.Index = 7; + this.copyMemoryMenuItem.Text = "C&opy"; + // + // freeMenuItem + // + this.vistaMenu.SetImage(this.freeMenuItem, global::ProcessHacker.Properties.Resources.cross); + this.freeMenuItem.Index = 3; + this.freeMenuItem.Text = "&Free"; + this.freeMenuItem.Click += new System.EventHandler(this.freeMenuItem_Click); + // + // decommitMenuItem + // + this.vistaMenu.SetImage(this.decommitMenuItem, global::ProcessHacker.Properties.Resources.delete); + this.decommitMenuItem.Index = 4; + this.decommitMenuItem.Text = "&Decommit"; + this.decommitMenuItem.Click += new System.EventHandler(this.decommitMenuItem_Click); + // + // dumpMemoryMenuItem + // + this.vistaMenu.SetImage(this.dumpMemoryMenuItem, global::ProcessHacker.Properties.Resources.disk); + this.dumpMemoryMenuItem.Index = 1; + this.dumpMemoryMenuItem.Text = "Dump..."; + this.dumpMemoryMenuItem.Click += new System.EventHandler(this.dumpMemoryMenuItem_Click); + // + // menuMemory + // + this.menuMemory.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.readWriteMemoryMemoryMenuItem, + this.dumpMemoryMenuItem, + this.changeMemoryProtectionMemoryMenuItem, + this.freeMenuItem, + this.decommitMenuItem, + this.menuItem2, + this.readWriteAddressMemoryMenuItem, + this.copyMemoryMenuItem, + this.selectAllMemoryMenuItem}); + this.menuMemory.Popup += new System.EventHandler(this.menuMemory_Popup); + // + // menuItem2 + // + this.menuItem2.Index = 5; + this.menuItem2.Text = "-"; + // + // selectAllMemoryMenuItem + // + this.selectAllMemoryMenuItem.Index = 8; + this.selectAllMemoryMenuItem.Text = "Select &All"; + this.selectAllMemoryMenuItem.Click += new System.EventHandler(this.selectAllMemoryMenuItem_Click); + // + // MemoryList + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.listMemory); + this.DoubleBuffered = true; + this.Name = "MemoryList"; + this.Size = new System.Drawing.Size(450, 472); + ((System.ComponentModel.ISupportInitialize)(this.vistaMenu)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.ListView listMemory; + private System.Windows.Forms.ColumnHeader columnName; + private wyDay.Controls.VistaMenu vistaMenu; + private System.Windows.Forms.ColumnHeader columnSize; + private System.Windows.Forms.ColumnHeader columnAddress; + private System.Windows.Forms.ColumnHeader columnProtection; + private System.Windows.Forms.ContextMenu menuMemory; + private System.Windows.Forms.MenuItem changeMemoryProtectionMemoryMenuItem; + private System.Windows.Forms.MenuItem readWriteMemoryMemoryMenuItem; + private System.Windows.Forms.MenuItem readWriteAddressMemoryMenuItem; + private System.Windows.Forms.MenuItem menuItem2; + private System.Windows.Forms.MenuItem copyMemoryMenuItem; + private System.Windows.Forms.MenuItem selectAllMemoryMenuItem; + private System.Windows.Forms.MenuItem freeMenuItem; + private System.Windows.Forms.MenuItem decommitMenuItem; + private System.Windows.Forms.MenuItem dumpMemoryMenuItem; + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/MemoryList.cs b/branches/ph-plugins/ProcessHacker/Components/MemoryList.cs new file mode 100644 index 000000000..308e2a381 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/MemoryList.cs @@ -0,0 +1,605 @@ +/* + * Process Hacker - + * memory region list + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Common.Ui; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; +using ProcessHacker.UI; + +namespace ProcessHacker.Components +{ + public partial class MemoryList : UserControl + { + private object _listLock = new object(); + private int _runCount = 0; + private MemoryProvider _provider; + private bool _needsSort = false; + private List _needsAdd = new List(); + private HighlightingContext _highlightingContext; + public new event KeyEventHandler KeyDown; + public new event MouseEventHandler MouseDown; + public new event MouseEventHandler MouseUp; + private int _pid; + + public MemoryList() + { + InitializeComponent(); + + _highlightingContext = new HighlightingContext(listMemory); + listMemory.KeyDown += new KeyEventHandler(listMemory_KeyDown); + listMemory.MouseDown += new MouseEventHandler(listMemory_MouseDown); + listMemory.MouseUp += new MouseEventHandler(listMemory_MouseUp); + + ColumnSettings.LoadSettings(Properties.Settings.Default.MemoryListViewColumns, listMemory); + listMemory.ContextMenu = menuMemory; + GenericViewMenu.AddMenuItems(copyMemoryMenuItem.MenuItems, listMemory, null); + + listMemory.ListViewItemSorter = new SortedListViewComparer(listMemory) + { + SortColumn = 1, + SortOrder = SortOrder.Ascending + }; + + (listMemory.ListViewItemSorter as SortedListViewComparer).CustomSorters.Add(2, + (x, y) => + { + MemoryItem ix = (MemoryItem)x.Tag; + MemoryItem iy = (MemoryItem)y.Tag; + + return ix.Size.CompareTo(iy.Size); + }); + } + + private void listMemory_MouseUp(object sender, MouseEventArgs e) + { + if (this.MouseUp != null) + this.MouseUp(sender, e); + } + + private void listMemory_MouseDown(object sender, MouseEventArgs e) + { + if (this.MouseDown != null) + this.MouseDown(sender, e); + } + + private void listMemory_KeyDown(object sender, KeyEventArgs e) + { + if (this.KeyDown != null) + this.KeyDown(sender, e); + + if (!e.Handled) + { + if (e.KeyCode == Keys.Enter) + { + readWriteMemoryMemoryMenuItem_Click(null, null); + } + } + } + + #region Properties + + public new bool DoubleBuffered + { + get + { + return (bool)typeof(ListView).GetProperty("DoubleBuffered", + BindingFlags.NonPublic | BindingFlags.Instance).GetValue(listMemory, null); + } + set + { + typeof(ListView).GetProperty("DoubleBuffered", + BindingFlags.NonPublic | BindingFlags.Instance).SetValue(listMemory, value, null); + } + } + + public override bool Focused + { + get + { + return listMemory.Focused; + } + } + + public override ContextMenu ContextMenu + { + get { return listMemory.ContextMenu; } + set { listMemory.ContextMenu = value; } + } + + public override ContextMenuStrip ContextMenuStrip + { + get { return listMemory.ContextMenuStrip; } + set { listMemory.ContextMenuStrip = value; } + } + + public ListView List + { + get { return listMemory; } + } + + public MemoryProvider Provider + { + get { return _provider; } + set + { + if (_provider != null) + { + _provider.DictionaryAdded -= new MemoryProvider.ProviderDictionaryAdded(provider_DictionaryAdded); + _provider.DictionaryModified -= new MemoryProvider.ProviderDictionaryModified(provider_DictionaryModified); + _provider.DictionaryRemoved -= new MemoryProvider.ProviderDictionaryRemoved(provider_DictionaryRemoved); + _provider.Updated -= new MemoryProvider.ProviderUpdateOnce(provider_Updated); + } + + _provider = value; + + listMemory.Items.Clear(); + _pid = -1; + + if (_provider != null) + { + _provider.DictionaryAdded += new MemoryProvider.ProviderDictionaryAdded(provider_DictionaryAdded); + _provider.DictionaryModified += new MemoryProvider.ProviderDictionaryModified(provider_DictionaryModified); + _provider.DictionaryRemoved += new MemoryProvider.ProviderDictionaryRemoved(provider_DictionaryRemoved); + _provider.Updated += new MemoryProvider.ProviderUpdateOnce(provider_Updated); + _pid = _provider.Pid; + + foreach (MemoryItem item in _provider.Dictionary.Values) + { + provider_DictionaryAdded(item); + } + } + } + } + + #endregion + + #region Interfacing + + public void BeginUpdate() + { + listMemory.BeginUpdate(); + } + + public void EndUpdate() + { + listMemory.EndUpdate(); + } + + public ListView.ListViewItemCollection Items + { + get { return listMemory.Items; } + } + + public ListView.SelectedListViewItemCollection SelectedItems + { + get { return listMemory.SelectedItems; } + } + + #endregion + + private string GetProtectStr(MemoryProtection protect) + { + string protectStr; + + if (protect == MemoryProtection.AccessDenied) + protectStr = ""; + else if ((protect & MemoryProtection.Execute) != 0) + protectStr = "X"; + else if ((protect & MemoryProtection.ExecuteRead) != 0) + protectStr = "RX"; + else if ((protect & MemoryProtection.ExecuteReadWrite) != 0) + protectStr = "RWX"; + else if ((protect & MemoryProtection.ExecuteWriteCopy) != 0) + protectStr = "WCX"; + else if ((protect & MemoryProtection.NoAccess) != 0) + protectStr = "NA"; + else if ((protect & MemoryProtection.ReadOnly) != 0) + protectStr = "R"; + else if ((protect & MemoryProtection.ReadWrite) != 0) + protectStr = "RW"; + else if ((protect & MemoryProtection.WriteCopy) != 0) + protectStr = "WC"; + else + protectStr = "?"; + + if ((protect & MemoryProtection.Guard) != 0) + protectStr += "+G"; + if ((protect & MemoryProtection.NoCache) != 0) + protectStr += "+NC"; + if ((protect & MemoryProtection.WriteCombine) != 0) + protectStr = "+WCM"; + + return protectStr; + } + + private string GetStateStr(MemoryState state) + { + if (state == MemoryState.Commit) + return "Commit"; + else if (state == MemoryState.Free) + return "Free"; + else if (state == MemoryState.Reserve) + return "Reserve"; + else if (state == MemoryState.Reset) + return "Reset"; + else + return "Unknown"; + } + + private string GetTypeStr(MemoryType type) + { + if (type == MemoryType.Image) + return "Image"; + else if (type == MemoryType.Mapped) + return "Mapped"; + else if (type == MemoryType.Private) + return "Private"; + else + return "Unknown"; + } + + private void provider_Updated() + { + lock (_needsAdd) + { + if (_needsAdd.Count > 0) + { + this.BeginInvoke(new MethodInvoker(() => + { + lock (_needsAdd) + { + listMemory.Items.AddRange(_needsAdd.ToArray()); + _needsAdd.Clear(); + _needsAdd.TrimExcess(); + } + })); + } + } + + _highlightingContext.Tick(); + + if (_needsSort) + { + this.BeginInvoke(new MethodInvoker(() => + { + if (_needsSort) + { + listMemory.Sort(); + _needsSort = false; + } + })); + } + + _runCount++; + } + + private void FillMemoryListViewItem(ListViewItem litem, MemoryItem item) + { + if (item.State == MemoryState.Free) + { + litem.Text = "Free"; + } + else if (item.Type == MemoryType.Image) + { + if (item.ModuleName != null) + litem.Text = item.ModuleName; + else + litem.Text = "Image"; + + litem.Text += " (" + GetStateStr(item.State) + ")"; + } + else + { + litem.Text = GetTypeStr(item.Type); + litem.Text += " (" + GetStateStr(item.State) + ")"; + } + + litem.SubItems[1].Text = Utils.FormatAddress(item.Address); + litem.SubItems[2].Text = Utils.FormatSize(item.Size); + litem.SubItems[3].Text = GetProtectStr(item.Protection); + litem.Tag = item; + } + + private void provider_DictionaryAdded(MemoryItem item) + { + this.BeginInvoke(new MethodInvoker(() => + { + HighlightedListViewItem litem = new HighlightedListViewItem(_highlightingContext, + item.RunId > 0 && _runCount > 0); + + litem.Name = item.Address.ToString(); + + litem.SubItems.Add(new ListViewItem.ListViewSubItem(litem, "")); + litem.SubItems.Add(new ListViewItem.ListViewSubItem(litem, "")); + litem.SubItems.Add(new ListViewItem.ListViewSubItem(litem, "")); + + this.FillMemoryListViewItem(litem, item); + + _needsAdd.Add(litem); + })); + } + + private void provider_DictionaryModified(MemoryItem oldItem, MemoryItem newItem) + { + this.BeginInvoke(new MethodInvoker(() => + { + lock (listMemory) + { + ListViewItem litem = listMemory.Items[newItem.Address.ToString()]; + + if (litem != null) + this.FillMemoryListViewItem(litem, newItem); + } + })); + } + + private void provider_DictionaryRemoved(MemoryItem item) + { + this.BeginInvoke(new MethodInvoker(() => + { + lock (listMemory) + { + // FIXME + try + { + listMemory.Items[item.Address.ToString()].Remove(); + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + })); + } + + public void SaveSettings() + { + Properties.Settings.Default.MemoryListViewColumns = ColumnSettings.SaveSettings(listMemory); + } + + private void listMemory_DoubleClick(object sender, EventArgs e) + { + readWriteMemoryMemoryMenuItem_Click(sender, e); + } + + private void menuMemory_Popup(object sender, EventArgs e) + { + if (listMemory.SelectedIndices.Count == 1) + { + menuMemory.EnableAll(); + + MemoryItem item = (MemoryItem)listMemory.SelectedItems[0].Tag; + + if (item.State != MemoryState.Commit || + item.Type != MemoryType.Private) + { + freeMenuItem.Enabled = false; + decommitMenuItem.Enabled = false; + } + } + else + { + menuMemory.DisableAll(); + + dumpMemoryMenuItem.Enabled = true; + readWriteAddressMemoryMenuItem.Enabled = true; + + if (listMemory.SelectedIndices.Count > 1) + { + copyMemoryMenuItem.Enabled = true; + } + + if (listMemory.VirtualListSize > 0) + { + selectAllMemoryMenuItem.Enabled = true; + } + else + { + selectAllMemoryMenuItem.Enabled = false; + } + } + } + + private void changeMemoryProtectionMemoryMenuItem_Click(object sender, EventArgs e) + { + MemoryItem item = (MemoryItem)listMemory.SelectedItems[0].Tag; + VirtualProtectWindow w = new VirtualProtectWindow(_pid, item.Address, item.Size); + + w.ShowDialog(); + } + + private void readWriteMemoryMemoryMenuItem_Click(object sender, EventArgs e) + { + if (listMemory.SelectedIndices.Count != 1) + return; + + MemoryItem item = (MemoryItem)listMemory.SelectedItems[0].Tag; + + MemoryEditor.ReadWriteMemory(_pid, item.Address, (int)item.Size, false); + } + + private void dumpMemoryMenuItem_Click(object sender, EventArgs e) + { + SaveFileDialog sfd = new SaveFileDialog(); + + sfd.FileName = "Memory.bin"; + sfd.Filter = "Binary Files (*.bin)|*.bin|All Files (*.*)|*.*"; + + if (sfd.ShowDialog() == DialogResult.OK) + { + try + { + using (var phandle = new ProcessHandle(_pid, ProcessAccess.VmRead)) + using (var fhandle = FileHandle.CreateWin32(sfd.FileName, FileAccess.GenericWrite, FileShareMode.Read)) + { + foreach (ListViewItem litem in listMemory.SelectedItems) + { + MemoryItem item = (MemoryItem)litem.Tag; + + using (MemoryAlloc alloc = new MemoryAlloc((int)item.Size)) + { + try + { + unsafe + { + phandle.ReadMemory(item.Address, (IntPtr)alloc, (int)item.Size); + fhandle.Write(alloc.Memory, (int)item.Size); + } + } + catch (WindowsException) + { } + } + } + } + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to dump the selected memory regions", ex); + } + } + } + + private void readWriteAddressMemoryMenuItem_Click(object sender, EventArgs e) + { + PromptBox prompt = new PromptBox(); + + if (prompt.ShowDialog() == DialogResult.OK) + { + IntPtr address = new IntPtr(-1); + IntPtr regionAddress = IntPtr.Zero; + long regionSize = 0; + bool found = false; + + try + { + address = ((long)BaseConverter.ToNumberParse(prompt.Value)).ToIntPtr(); + } + catch + { + PhUtils.ShowError("You have entered an invalid address."); + + return; + } + + List items = new List(); + + foreach (MemoryItem item in _provider.Dictionary.Values) + items.Add(item); + + items.Sort((i1, i2) => i1.Address.CompareTo(i2.Address)); + + int i = 0; + + foreach (MemoryItem item in items) + { + if (item.Address.CompareTo(address) > 0) + { + MemoryItem regionItem = items[i - 1]; + + listMemory.Items[regionItem.Address.ToString()].Selected = true; + listMemory.Items[regionItem.Address.ToString()].EnsureVisible(); + regionAddress = regionItem.Address; + regionSize = regionItem.Size; + found = true; + + break; + } + + i++; + } + + if (!found) + { + PhUtils.ShowError("Unable to find the memory address."); + return; + } + + MemoryEditor m_e = MemoryEditor.ReadWriteMemory(_pid, regionAddress, (int)regionSize, false, + new Program.MemoryEditorInvokeAction(delegate(MemoryEditor f) { f.Select(address.Decrement(regionAddress).ToInt64(), 1); })); + } + } + + private void selectAllMemoryMenuItem_Click(object sender, EventArgs e) + { + Utils.SelectAll(listMemory); + } + + private void freeMenuItem_Click(object sender, EventArgs e) + { + if (PhUtils.ShowConfirmMessage( + "free", + "the memory region", + "Freeing memory regions may cause the process to crash.", + true + )) + { + try + { + using (var phandle = + new ProcessHandle(_pid, ProcessAccess.VmOperation)) + { + MemoryItem item = (MemoryItem)listMemory.SelectedItems[0].Tag; + + phandle.FreeMemory(item.Address, (int)item.Size, false); + } + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to free the memory region", ex); + } + } + } + + private void decommitMenuItem_Click(object sender, EventArgs e) + { + if (PhUtils.ShowConfirmMessage( + "decommit", + "the memory region", + "Decommitting memory regions may cause the process to crash.", + true + )) + { + try + { + using (ProcessHandle phandle = + new ProcessHandle(_pid, ProcessAccess.VmOperation)) + { + MemoryItem item = (MemoryItem)listMemory.SelectedItems[0].Tag; + + phandle.FreeMemory(item.Address, (int)item.Size, true); + } + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to decommit the memory region", ex); + } + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/MemoryList.resx b/branches/ph-plugins/ProcessHacker/Components/MemoryList.resx new file mode 100644 index 000000000..c7d3b3761 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/MemoryList.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 125, 17 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/ModuleList.Designer.cs b/branches/ph-plugins/ProcessHacker/Components/ModuleList.Designer.cs new file mode 100644 index 000000000..05a595408 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/ModuleList.Designer.cs @@ -0,0 +1,240 @@ +namespace ProcessHacker.Components +{ + partial class ModuleList + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + _highlightingContext.Dispose(); + this.Provider = null; + + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.listModules = new System.Windows.Forms.ListView(); + this.columnName = new System.Windows.Forms.ColumnHeader(); + this.columnBaseAddress = new System.Windows.Forms.ColumnHeader(); + this.columnSize = new System.Windows.Forms.ColumnHeader(); + this.columnDesc = new System.Windows.Forms.ColumnHeader(); + this.changeMemoryProtectionModuleMenuItem = new System.Windows.Forms.MenuItem(); + this.readMemoryModuleMenuItem = new System.Windows.Forms.MenuItem(); + this.inspectModuleMenuItem = new System.Windows.Forms.MenuItem(); + this.copyModuleMenuItem = new System.Windows.Forms.MenuItem(); + this.openContainingFolderMenuItem = new System.Windows.Forms.MenuItem(); + this.propertiesMenuItem = new System.Windows.Forms.MenuItem(); + this.unloadMenuItem = new System.Windows.Forms.MenuItem(); + this.menuModule = new System.Windows.Forms.ContextMenu(); + this.getFuncAddressMenuItem = new System.Windows.Forms.MenuItem(); + this.menuItem3 = new System.Windows.Forms.MenuItem(); + this.searchModuleMenuItem = new System.Windows.Forms.MenuItem(); + this.copyFileNameMenuItem = new System.Windows.Forms.MenuItem(); + this.menuItem6 = new System.Windows.Forms.MenuItem(); + this.selectAllModuleMenuItem = new System.Windows.Forms.MenuItem(); + this.vistaMenu = new wyDay.Controls.VistaMenu(this.components); + ((System.ComponentModel.ISupportInitialize)(this.vistaMenu)).BeginInit(); + this.SuspendLayout(); + // + // listModules + // + this.listModules.AllowColumnReorder = true; + this.listModules.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnName, + this.columnBaseAddress, + this.columnSize, + this.columnDesc}); + this.listModules.Dock = System.Windows.Forms.DockStyle.Fill; + this.listModules.FullRowSelect = true; + this.listModules.HideSelection = false; + this.listModules.Location = new System.Drawing.Point(0, 0); + this.listModules.Name = "listModules"; + this.listModules.ShowItemToolTips = true; + this.listModules.Size = new System.Drawing.Size(450, 472); + this.listModules.Sorting = System.Windows.Forms.SortOrder.Ascending; + this.listModules.TabIndex = 3; + this.listModules.UseCompatibleStateImageBehavior = false; + this.listModules.View = System.Windows.Forms.View.Details; + // + // columnName + // + this.columnName.Text = "Name"; + this.columnName.Width = 99; + // + // columnBaseAddress + // + this.columnBaseAddress.Text = "Base Address"; + this.columnBaseAddress.Width = 80; + // + // columnSize + // + this.columnSize.Text = "Size"; + this.columnSize.Width = 70; + // + // columnDesc + // + this.columnDesc.Text = "Description"; + this.columnDesc.Width = 188; + // + // changeMemoryProtectionModuleMenuItem + // + this.vistaMenu.SetImage(this.changeMemoryProtectionModuleMenuItem, global::ProcessHacker.Properties.Resources.lock_edit); + this.changeMemoryProtectionModuleMenuItem.Index = 0; + this.changeMemoryProtectionModuleMenuItem.Text = "Change &Memory Protection..."; + this.changeMemoryProtectionModuleMenuItem.Click += new System.EventHandler(this.changeMemoryProtectionModuleMenuItem_Click); + // + // readMemoryModuleMenuItem + // + this.vistaMenu.SetImage(this.readMemoryModuleMenuItem, global::ProcessHacker.Properties.Resources.page); + this.readMemoryModuleMenuItem.Index = 2; + this.readMemoryModuleMenuItem.Text = "Read Memory"; + this.readMemoryModuleMenuItem.Click += new System.EventHandler(this.readMemoryModuleMenuItem_Click); + // + // inspectModuleMenuItem + // + this.vistaMenu.SetImage(this.inspectModuleMenuItem, global::ProcessHacker.Properties.Resources.application_form_magnify); + this.inspectModuleMenuItem.Index = 5; + this.inspectModuleMenuItem.Text = "&Inspect"; + this.inspectModuleMenuItem.Click += new System.EventHandler(this.inspectModuleMenuItem_Click); + // + // copyModuleMenuItem + // + this.vistaMenu.SetImage(this.copyModuleMenuItem, global::ProcessHacker.Properties.Resources.page_copy); + this.copyModuleMenuItem.Index = 8; + this.copyModuleMenuItem.Text = "Copy"; + // + // openContainingFolderMenuItem + // + this.vistaMenu.SetImage(this.openContainingFolderMenuItem, global::ProcessHacker.Properties.Resources.folder_explore); + this.openContainingFolderMenuItem.Index = 9; + this.openContainingFolderMenuItem.Text = "&Open Containing Folder"; + this.openContainingFolderMenuItem.Click += new System.EventHandler(this.openContainingFolderMenuItem_Click); + // + // propertiesMenuItem + // + this.vistaMenu.SetImage(this.propertiesMenuItem, global::ProcessHacker.Properties.Resources.application_view_detail); + this.propertiesMenuItem.Index = 10; + this.propertiesMenuItem.Text = "Prope&rties"; + this.propertiesMenuItem.Click += new System.EventHandler(this.propertiesMenuItem_Click); + // + // unloadMenuItem + // + this.vistaMenu.SetImage(this.unloadMenuItem, global::ProcessHacker.Properties.Resources.cross); + this.unloadMenuItem.Index = 3; + this.unloadMenuItem.Text = "&Unload"; + this.unloadMenuItem.Click += new System.EventHandler(this.unloadMenuItem_Click); + // + // menuModule + // + this.menuModule.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.changeMemoryProtectionModuleMenuItem, + this.getFuncAddressMenuItem, + this.readMemoryModuleMenuItem, + this.unloadMenuItem, + this.menuItem3, + this.inspectModuleMenuItem, + this.searchModuleMenuItem, + this.copyFileNameMenuItem, + this.copyModuleMenuItem, + this.openContainingFolderMenuItem, + this.propertiesMenuItem, + this.menuItem6, + this.selectAllModuleMenuItem}); + this.menuModule.Popup += new System.EventHandler(this.menuModule_Popup); + // + // getFuncAddressMenuItem + // + this.getFuncAddressMenuItem.Index = 1; + this.getFuncAddressMenuItem.Text = "Get &Function Address..."; + this.getFuncAddressMenuItem.Click += new System.EventHandler(this.getFuncAddressMenuItem_Click); + // + // menuItem3 + // + this.menuItem3.Index = 4; + this.menuItem3.Text = "-"; + // + // searchModuleMenuItem + // + this.searchModuleMenuItem.Index = 6; + this.searchModuleMenuItem.Text = "&Search Online"; + this.searchModuleMenuItem.Click += new System.EventHandler(this.searchModuleMenuItem_Click); + // + // copyFileNameMenuItem + // + this.copyFileNameMenuItem.Index = 7; + this.copyFileNameMenuItem.Text = "&Copy File Name(s)"; + this.copyFileNameMenuItem.Click += new System.EventHandler(this.copyFileNameMenuItem_Click); + // + // menuItem6 + // + this.menuItem6.Index = 11; + this.menuItem6.Text = "-"; + // + // selectAllModuleMenuItem + // + this.selectAllModuleMenuItem.Index = 12; + this.selectAllModuleMenuItem.Text = "Select &All"; + this.selectAllModuleMenuItem.Click += new System.EventHandler(this.selectAllModuleMenuItem_Click); + // + // vistaMenu + // + this.vistaMenu.ContainerControl = this; + this.vistaMenu.DelaySetImageCalls = false; + // + // ModuleList + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.listModules); + this.DoubleBuffered = true; + this.Name = "ModuleList"; + this.Size = new System.Drawing.Size(450, 472); + ((System.ComponentModel.ISupportInitialize)(this.vistaMenu)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.ListView listModules; + private System.Windows.Forms.ColumnHeader columnBaseAddress; + private System.Windows.Forms.ColumnHeader columnName; + private System.Windows.Forms.ColumnHeader columnSize; + private System.Windows.Forms.ColumnHeader columnDesc; + private wyDay.Controls.VistaMenu vistaMenu; + private System.Windows.Forms.ContextMenu menuModule; + private System.Windows.Forms.MenuItem getFuncAddressMenuItem; + private System.Windows.Forms.MenuItem changeMemoryProtectionModuleMenuItem; + private System.Windows.Forms.MenuItem readMemoryModuleMenuItem; + private System.Windows.Forms.MenuItem inspectModuleMenuItem; + private System.Windows.Forms.MenuItem menuItem3; + private System.Windows.Forms.MenuItem searchModuleMenuItem; + private System.Windows.Forms.MenuItem copyFileNameMenuItem; + private System.Windows.Forms.MenuItem copyModuleMenuItem; + private System.Windows.Forms.MenuItem openContainingFolderMenuItem; + private System.Windows.Forms.MenuItem propertiesMenuItem; + private System.Windows.Forms.MenuItem menuItem6; + private System.Windows.Forms.MenuItem selectAllModuleMenuItem; + private System.Windows.Forms.MenuItem unloadMenuItem; + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/ModuleList.cs b/branches/ph-plugins/ProcessHacker/Components/ModuleList.cs new file mode 100644 index 000000000..b78a9a128 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/ModuleList.cs @@ -0,0 +1,632 @@ +/* + * Process Hacker - + * module list + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Reflection; +using System.Windows.Forms; +using Microsoft.Win32; +using ProcessHacker.Common; +using ProcessHacker.Common.Ui; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; +using ProcessHacker.UI; + +namespace ProcessHacker.Components +{ + public partial class ModuleList : UserControl + { + private ModuleProvider _provider; + private int _runCount = 0; + private List _needsAdd = new List(); + private HighlightingContext _highlightingContext; + public new event KeyEventHandler KeyDown; + public new event MouseEventHandler MouseDown; + public new event MouseEventHandler MouseUp; + public new event EventHandler DoubleClick; + private int _pid; + private string _mainModule; + + public ModuleList() + { + InitializeComponent(); + + _highlightingContext = new HighlightingContext(listModules); + listModules.KeyDown += new KeyEventHandler(ModuleList_KeyDown); + listModules.MouseDown += new MouseEventHandler(listModules_MouseDown); + listModules.MouseUp += new MouseEventHandler(listModules_MouseUp); + listModules.DoubleClick += new EventHandler(listModules_DoubleClick); + + ColumnSettings.LoadSettings(Properties.Settings.Default.ModuleListViewColumns, listModules); + listModules.ContextMenu = menuModule; + GenericViewMenu.AddMenuItems(copyModuleMenuItem.MenuItems, listModules, null); + } + + private void listModules_DoubleClick(object sender, EventArgs e) + { + if (this.DoubleClick != null) + this.DoubleClick(sender, e); + } + + private void listModules_MouseUp(object sender, MouseEventArgs e) + { + if (this.MouseUp != null) + this.MouseUp(sender, e); + } + + private void listModules_MouseDown(object sender, MouseEventArgs e) + { + if (this.MouseDown != null) + this.MouseDown(sender, e); + } + + private void ModuleList_KeyDown(object sender, KeyEventArgs e) + { + if (this.KeyDown != null) + this.KeyDown(sender, e); + } + + #region Properties + + public new bool DoubleBuffered + { + get + { + return (bool)typeof(ListView).GetProperty("DoubleBuffered", + BindingFlags.NonPublic | BindingFlags.Instance).GetValue(listModules, null); + } + set + { + typeof(ListView).GetProperty("DoubleBuffered", + BindingFlags.NonPublic | BindingFlags.Instance).SetValue(listModules, value, null); + } + } + + public override bool Focused + { + get + { + return listModules.Focused; + } + } + + public override ContextMenu ContextMenu + { + get { return listModules.ContextMenu; } + set { listModules.ContextMenu = value; } + } + + public override ContextMenuStrip ContextMenuStrip + { + get { return listModules.ContextMenuStrip; } + set { listModules.ContextMenuStrip = value; } + } + + public ListView List + { + get { return listModules; } + } + + public ModuleProvider Provider + { + get { return _provider; } + set + { + if (_provider != null) + { + _provider.DictionaryAdded -= new ModuleProvider.ProviderDictionaryAdded(provider_DictionaryAdded); + _provider.DictionaryRemoved -= new ModuleProvider.ProviderDictionaryRemoved(provider_DictionaryRemoved); + _provider.Updated -= new ModuleProvider.ProviderUpdateOnce(provider_Updated); + } + + _provider = value; + + listModules.Items.Clear(); + listModules.ListViewItemSorter = null; + _pid = -1; + _mainModule = null; + + if (_provider != null) + { + foreach (ModuleItem item in _provider.Dictionary.Values) + { + provider_DictionaryAdded(item); + } + + _provider.DictionaryAdded += new ModuleProvider.ProviderDictionaryAdded(provider_DictionaryAdded); + _provider.DictionaryRemoved += new ModuleProvider.ProviderDictionaryRemoved(provider_DictionaryRemoved); + _provider.Updated += new ModuleProvider.ProviderUpdateOnce(provider_Updated); + _pid = _provider.Pid; + + try + { + if (_pid == 4) + { + _mainModule = FileUtils.GetFileName(Windows.KernelFileName); + } + else + { + using (var phandle = + new ProcessHandle(_pid, + Program.MinProcessQueryRights | Program.MinProcessReadMemoryRights)) + _mainModule = FileUtils.GetFileName(phandle.GetMainModule().FileName); + } + + _mainModule = _mainModule.ToLower(); + SortedListViewComparer comparer = (SortedListViewComparer) + (listModules.ListViewItemSorter = new SortedListViewComparer(listModules) + { + TriState = true, + TriStateComparer = new ModuleListComparer(_mainModule), + SortColumn = 0, + SortOrder = SortOrder.None + }); + + comparer.ColumnSortOrder.Add(0); + comparer.ColumnSortOrder.Add(1); + comparer.ColumnSortOrder.Add(2); + + (listModules.ListViewItemSorter as SortedListViewComparer).CustomSorters.Add(2, + (x, y) => + { + ModuleItem ix = (ModuleItem)x.Tag; + ModuleItem iy = (ModuleItem)y.Tag; + + return ix.Size.CompareTo(iy.Size); + }); + } + catch + { } + } + } + } + + #endregion + + #region Interfacing + + public void BeginUpdate() + { + listModules.BeginUpdate(); + } + + public void EndUpdate() + { + listModules.EndUpdate(); + } + + public ListView.ListViewItemCollection Items + { + get { return listModules.Items; } + } + + public ListView.SelectedListViewItemCollection SelectedItems + { + get { return listModules.SelectedItems; } + } + + #endregion + + private void provider_Updated() + { + lock (_needsAdd) + { + if (_needsAdd.Count > 0) + { + this.BeginInvoke(new MethodInvoker(() => + { + lock (_needsAdd) + { + listModules.Items.AddRange(_needsAdd.ToArray()); + _needsAdd.Clear(); + } + })); + } + } + + _highlightingContext.Tick(); + _runCount++; + } + + private Color GetModuleColor(ModuleItem item) + { + if (Properties.Settings.Default.UseColorDotNetProcesses && + (item.Flags & LdrpDataTableEntryFlags.CorImage) != 0 + ) + return Properties.Settings.Default.ColorDotNetProcesses; + else if (Properties.Settings.Default.UseColorRelocatedDlls && + (item.Flags & LdrpDataTableEntryFlags.ImageNotAtBase) != 0 + ) + return Properties.Settings.Default.ColorRelocatedDlls; + else + return SystemColors.Window; + } + + private void provider_DictionaryAdded(ModuleItem item) + { + HighlightedListViewItem litem = new HighlightedListViewItem(_highlightingContext, + item.RunId > 0 && _runCount > 0); + + litem.Name = item.BaseAddress.ToString(); + litem.Text = item.Name; + litem.SubItems.Add(new ListViewItem.ListViewSubItem(litem, Utils.FormatAddress(item.BaseAddress))); + litem.SubItems.Add(new ListViewItem.ListViewSubItem(litem, Utils.FormatSize(item.Size))); + litem.SubItems.Add(new ListViewItem.ListViewSubItem(litem, item.FileDescription)); + litem.ToolTipText = item.FileName; + litem.Tag = item; + litem.NormalColor = this.GetModuleColor(item); + + if (item.FileName.Equals(_mainModule, StringComparison.InvariantCultureIgnoreCase)) + litem.Font = new System.Drawing.Font(litem.Font, System.Drawing.FontStyle.Bold); + + lock (_needsAdd) + _needsAdd.Add(litem); + } + + private void provider_DictionaryRemoved(ModuleItem item) + { + this.BeginInvoke(new MethodInvoker(() => + { + listModules.Items[item.BaseAddress.ToString()].Remove(); + })); + } + + public void SaveSettings() + { + Properties.Settings.Default.ModuleListViewColumns = ColumnSettings.SaveSettings(listModules); + } + + private void menuModule_Popup(object sender, EventArgs e) + { + if (listModules.SelectedItems.Count == 1) + { + if (_pid == 4) + { + menuModule.DisableAll(); + + if (KProcessHacker.Instance != null) + unloadMenuItem.Enabled = true; + + inspectModuleMenuItem.Enabled = true; + searchModuleMenuItem.Enabled = true; + copyFileNameMenuItem.Enabled = true; + copyModuleMenuItem.Enabled = true; + openContainingFolderMenuItem.Enabled = true; + propertiesMenuItem.Enabled = true; + } + else + { + menuModule.EnableAll(); + } + } + else + { + menuModule.DisableAll(); + + if (listModules.SelectedItems.Count > 1) + { + copyFileNameMenuItem.Enabled = true; + copyModuleMenuItem.Enabled = true; + } + } + + if (listModules.Items.Count > 0) + { + selectAllModuleMenuItem.Enabled = true; + } + else + { + selectAllModuleMenuItem.Enabled = false; + } + } + + private void searchModuleMenuItem_Click(object sender, EventArgs e) + { + try + { + Process.Start(Properties.Settings.Default.SearchEngine.Replace("%s", + listModules.SelectedItems[0].Text)); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to search for the module", ex); + } + } + + private void copyFileNameMenuItem_Click(object sender, EventArgs e) + { + string text = ""; + + for (int i = 0; i < listModules.SelectedItems.Count; i++) + { + text += listModules.SelectedItems[i].ToolTipText; + + if (i != listModules.SelectedItems.Count - 1) + text += "\r\n"; + } + + Clipboard.SetText(text); + } + + private void openContainingFolderMenuItem_Click(object sender, EventArgs e) + { + try + { + Utils.ShowFileInExplorer(listModules.SelectedItems[0].ToolTipText); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to show the file", ex); + } + } + + private void propertiesMenuItem_Click(object sender, EventArgs e) + { + FileUtils.ShowProperties(listModules.SelectedItems[0].ToolTipText); + } + + private void inspectModuleMenuItem_Click(object sender, EventArgs e) + { + try + { + PEWindow pw = Program.GetPEWindow(listModules.SelectedItems[0].ToolTipText, + new Program.PEWindowInvokeAction(delegate(PEWindow f) + { + if (!f.IsDisposed) + { + try + { + f.Show(); + f.Activate(); + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + })); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to inspect the module", ex); + } + } + + private void getFuncAddressMenuItem_Click(object sender, EventArgs e) + { + GetProcAddressWindow gpaWindow = new GetProcAddressWindow(listModules.SelectedItems[0].ToolTipText); + + gpaWindow.ShowDialog(); + } + + private void changeMemoryProtectionModuleMenuItem_Click(object sender, EventArgs e) + { + ModuleItem item = (ModuleItem)listModules.SelectedItems[0].Tag; + VirtualProtectWindow w = new VirtualProtectWindow(_pid, item.BaseAddress, item.Size); + + w.ShowDialog(); + } + + private void readMemoryModuleMenuItem_Click(object sender, EventArgs e) + { + ModuleItem item = (ModuleItem)listModules.SelectedItems[0].Tag; + + MemoryEditor.ReadWriteMemory(_pid, item.BaseAddress, item.Size, true); + } + + private void selectAllModuleMenuItem_Click(object sender, EventArgs e) + { + Utils.SelectAll(listModules.Items); + } + + private void unloadMenuItem_Click(object sender, EventArgs e) + { + if (!PhUtils.ShowConfirmMessage( + "Unload", + _pid != 4 ? "the selected module" : "the selected driver", + _pid != 4 ? + "Unloading a module may cause the process to crash." : + "Unloading a driver may cause system instability.", + true + )) + return; + + if (_pid == 4) + { + try + { + var moduleItem = (ModuleItem)listModules.SelectedItems[0].Tag; + string serviceName = null; + + // Try to find the name of the service key for the driver by + // looping through the objects in the Driver directory and + // opening each one. + using (var dhandle = new DirectoryHandle("\\Driver", DirectoryAccess.Query)) + { + foreach (var obj in dhandle.GetObjects()) + { + try + { + using (var driverHandle = new DriverHandle("\\Driver\\" + obj.Name)) + { + if (driverHandle.GetBasicInformation().DriverStart == moduleItem.BaseAddress) + { + serviceName = driverHandle.GetServiceKeyName(); + break; + } + } + } + catch + { } + } + } + + // If we didn't find the service name, use the driver base name. + if (serviceName == null) + { + if (moduleItem.Name.ToLower().EndsWith(".sys")) + serviceName = moduleItem.Name.Remove(moduleItem.Name.Length - 4, 4); + else + serviceName = moduleItem.Name; + } + + RegistryKey servicesKey = + Registry.LocalMachine.OpenSubKey("SYSTEM\\CurrentControlSet\\Services", true); + bool serviceKeyCreated; + RegistryKey serviceKey; + + // Check if the service key exists so that we don't delete it + // later if it does. + if (Array.Exists(servicesKey.GetSubKeyNames(), + (keyName) => (string.Compare(keyName, serviceName, true) == 0))) + { + serviceKeyCreated = false; + } + else + { + serviceKeyCreated = true; + // Create the service key. + serviceKey = servicesKey.CreateSubKey(serviceName); + + serviceKey.SetValue("ErrorControl", 1, RegistryValueKind.DWord); + serviceKey.SetValue("ImagePath", "\\??\\" + moduleItem.FileName, RegistryValueKind.ExpandString); + serviceKey.SetValue("Start", 1, RegistryValueKind.DWord); + serviceKey.SetValue("Type", 1, RegistryValueKind.DWord); + serviceKey.Close(); + servicesKey.Flush(); + } + + try + { + Windows.UnloadDriver(serviceName); + } + finally + { + if (serviceKeyCreated) + servicesKey.DeleteSubKeyTree(serviceName); + + servicesKey.Close(); + } + + listModules.SelectedItems.Clear(); + } + catch (Exception ex) + { + MessageBox.Show("Unable to unload the driver. Make sure Process Hacker " + + "is running with administrative privileges. Error:\n\n" + + ex.Message, "Process Hacker", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + else + { + try + { + using (ProcessHandle phandle = new ProcessHandle(_pid, + Program.MinProcessQueryRights | ProcessAccess.VmOperation | + ProcessAccess.VmRead | ProcessAccess.VmWrite | ProcessAccess.CreateThread)) + { + IntPtr baseAddress = ((ModuleItem)listModules.SelectedItems[0].Tag).BaseAddress; + + phandle.SetModuleReferenceCount(baseAddress, 1); + + ThreadHandle thread; + + if (OSVersion.IsAboveOrEqual(WindowsVersion.Vista)) + { + // Use RtlCreateUserThread to bypass session boundaries. Since + // LdrUnloadDll is a native function we don't need to notify CSR. + thread = phandle.CreateThread( + Loader.GetProcedure("ntdll.dll", "LdrUnloadDll"), + baseAddress + ); + } + else + { + // On XP it seems we need to notify CSR... + thread = phandle.CreateThreadWin32( + Loader.GetProcedure("kernel32.dll", "FreeLibrary"), + baseAddress + ); + } + + thread.Wait(1000 * Win32.TimeMsTo100Ns); + + NtStatus exitStatus = thread.GetExitStatus(); + + if (exitStatus == NtStatus.DllNotFound) + { + if (IntPtr.Size == 8) + { + PhUtils.ShowError("Unable to find the module to unload. This may be caused " + + "by an attempt to unload a mapped file or a 32-bit module."); + } + else + { + PhUtils.ShowError("Unable to find the module to unload. This may be caused " + + "by an attempt to unload a mapped file."); + } + } + else + { + exitStatus.ThrowIf(); + } + + thread.Dispose(); + } + + listModules.SelectedItems.Clear(); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to unload the module", ex); + } + } + } + } + + public class ModuleListComparer : ISortedListViewComparer + { + private string _mainModule; + + public ModuleListComparer(string mainModule) + { + _mainModule = mainModule.ToLower(); + } + + public int Compare(ListViewItem x, ListViewItem y, int column) + { + ModuleItem mx = (ModuleItem)x.Tag; + ModuleItem my = (ModuleItem)y.Tag; + + if (mx.FileName.Equals(_mainModule, StringComparison.InvariantCultureIgnoreCase)) + return -1; + if (my.FileName.Equals(_mainModule, StringComparison.InvariantCultureIgnoreCase)) + return 1; + + return 0; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/ModuleList.resx b/branches/ph-plugins/ProcessHacker/Components/ModuleList.resx new file mode 100644 index 000000000..70244693e --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/ModuleList.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 120, 20 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/MutantProperties.Designer.cs b/branches/ph-plugins/ProcessHacker/Components/MutantProperties.Designer.cs new file mode 100644 index 000000000..9fccd3850 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/MutantProperties.Designer.cs @@ -0,0 +1,125 @@ +namespace ProcessHacker.Components +{ + partial class MutantProperties + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + _mutantHandle.Dereference(disposing); + + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.labelCurrentCount = new System.Windows.Forms.Label(); + this.labelAbandoned = new System.Windows.Forms.Label(); + this.labelLabelOwner = new System.Windows.Forms.Label(); + this.labelOwner = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(6, 3); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(75, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Current Count:"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(6, 26); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(65, 13); + this.label3.TabIndex = 0; + this.label3.Text = "Abandoned:"; + // + // labelCurrentCount + // + this.labelCurrentCount.AutoSize = true; + this.labelCurrentCount.Location = new System.Drawing.Point(102, 3); + this.labelCurrentCount.Name = "labelCurrentCount"; + this.labelCurrentCount.Size = new System.Drawing.Size(13, 13); + this.labelCurrentCount.TabIndex = 0; + this.labelCurrentCount.Text = "0"; + // + // labelAbandoned + // + this.labelAbandoned.AutoSize = true; + this.labelAbandoned.Location = new System.Drawing.Point(102, 26); + this.labelAbandoned.Name = "labelAbandoned"; + this.labelAbandoned.Size = new System.Drawing.Size(32, 13); + this.labelAbandoned.TabIndex = 0; + this.labelAbandoned.Text = "False"; + // + // labelLabelOwner + // + this.labelLabelOwner.AutoSize = true; + this.labelLabelOwner.Location = new System.Drawing.Point(6, 49); + this.labelLabelOwner.Name = "labelLabelOwner"; + this.labelLabelOwner.Size = new System.Drawing.Size(41, 13); + this.labelLabelOwner.TabIndex = 1; + this.labelLabelOwner.Text = "Owner:"; + // + // labelOwner + // + this.labelOwner.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.labelOwner.AutoEllipsis = true; + this.labelOwner.Location = new System.Drawing.Point(102, 49); + this.labelOwner.Name = "labelOwner"; + this.labelOwner.Size = new System.Drawing.Size(104, 21); + this.labelOwner.TabIndex = 2; + this.labelOwner.Text = "Unknown"; + // + // MutantProperties + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.labelOwner); + this.Controls.Add(this.labelLabelOwner); + this.Controls.Add(this.label3); + this.Controls.Add(this.labelAbandoned); + this.Controls.Add(this.labelCurrentCount); + this.Controls.Add(this.label1); + this.Name = "MutantProperties"; + this.Padding = new System.Windows.Forms.Padding(3); + this.Size = new System.Drawing.Size(212, 78); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label labelCurrentCount; + private System.Windows.Forms.Label labelAbandoned; + private System.Windows.Forms.Label labelLabelOwner; + private System.Windows.Forms.Label labelOwner; + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/MutantProperties.cs b/branches/ph-plugins/ProcessHacker/Components/MutantProperties.cs new file mode 100644 index 000000000..374225f07 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/MutantProperties.cs @@ -0,0 +1,52 @@ +using System.Windows.Forms; +using ProcessHacker.Native; +using ProcessHacker.Native.Objects; + +namespace ProcessHacker.Components +{ + public partial class MutantProperties : UserControl + { + private MutantHandle _mutantHandle; + + public MutantProperties(MutantHandle mutantHandle) + { + InitializeComponent(); + + _mutantHandle = mutantHandle; + _mutantHandle.Reference(); + + this.UpdateInfo(); + } + + private void UpdateInfo() + { + var basicInfo = _mutantHandle.GetBasicInformation(); + + labelCurrentCount.Text = basicInfo.CurrentCount.ToString(); + labelAbandoned.Text = basicInfo.AbandonedState.ToString(); + + // Windows Vista and above have owner information. + if (OSVersion.IsAboveOrEqual(WindowsVersion.Vista)) + { + var ownerInfo = _mutantHandle.GetOwnerInformation(); + + if (ownerInfo.ClientId.ProcessId != 0) + { + labelOwner.Text = ownerInfo.ClientId.GetName(true); + } + else + { + labelOwner.Text = "N/A"; + } + + labelLabelOwner.Visible = true; + labelOwner.Visible = true; + } + else + { + labelLabelOwner.Visible = false; + labelOwner.Visible = false; + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/MutantProperties.resx b/branches/ph-plugins/ProcessHacker/Components/MutantProperties.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/MutantProperties.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/NetworkList.Designer.cs b/branches/ph-plugins/ProcessHacker/Components/NetworkList.Designer.cs new file mode 100644 index 000000000..9d62847ce --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/NetworkList.Designer.cs @@ -0,0 +1,137 @@ +namespace ProcessHacker.Components +{ + partial class NetworkList + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + _highlightingContext.Dispose(); + this.Provider = null; + + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(NetworkList)); + this.listNetwork = new System.Windows.Forms.ListView(); + this.columnProcess = new System.Windows.Forms.ColumnHeader(); + this.columnLocal = new System.Windows.Forms.ColumnHeader(); + this.columnLocalPort = new System.Windows.Forms.ColumnHeader(); + this.columnRemote = new System.Windows.Forms.ColumnHeader(); + this.columnRemotePort = new System.Windows.Forms.ColumnHeader(); + this.columnProtocol = new System.Windows.Forms.ColumnHeader(); + this.columnState = new System.Windows.Forms.ColumnHeader(); + this.imageList = new System.Windows.Forms.ImageList(this.components); + this.SuspendLayout(); + // + // listNetwork + // + this.listNetwork.AllowColumnReorder = true; + this.listNetwork.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnProcess, + this.columnLocal, + this.columnLocalPort, + this.columnRemote, + this.columnRemotePort, + this.columnProtocol, + this.columnState}); + this.listNetwork.Dock = System.Windows.Forms.DockStyle.Fill; + this.listNetwork.FullRowSelect = true; + this.listNetwork.HideSelection = false; + this.listNetwork.Location = new System.Drawing.Point(0, 0); + this.listNetwork.Name = "listNetwork"; + this.listNetwork.ShowItemToolTips = true; + this.listNetwork.Size = new System.Drawing.Size(685, 472); + this.listNetwork.SmallImageList = this.imageList; + this.listNetwork.Sorting = System.Windows.Forms.SortOrder.Ascending; + this.listNetwork.TabIndex = 1; + this.listNetwork.UseCompatibleStateImageBehavior = false; + this.listNetwork.View = System.Windows.Forms.View.Details; + // + // columnProcess + // + this.columnProcess.Text = "Process"; + this.columnProcess.Width = 137; + // + // columnLocal + // + this.columnLocal.Text = "Local Address"; + this.columnLocal.Width = 130; + // + // columnLocalPort + // + this.columnLocalPort.Text = "Local Port"; + this.columnLocalPort.Width = 52; + // + // columnRemote + // + this.columnRemote.Text = "Remote Address"; + this.columnRemote.Width = 140; + // + // columnRemotePort + // + this.columnRemotePort.Text = "Remote Port"; + this.columnRemotePort.Width = 52; + // + // columnProtocol + // + this.columnProtocol.Text = "Protocol"; + this.columnProtocol.Width = 80; + // + // columnState + // + this.columnState.Text = "State"; + this.columnState.Width = 70; + // + // imageList + // + this.imageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList.ImageStream"))); + this.imageList.TransparentColor = System.Drawing.Color.Transparent; + this.imageList.Images.SetKeyName(0, "generic_process"); + // + // NetworkList + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.listNetwork); + this.DoubleBuffered = true; + this.Name = "NetworkList"; + this.Size = new System.Drawing.Size(685, 472); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.ListView listNetwork; + private System.Windows.Forms.ColumnHeader columnLocal; + private System.Windows.Forms.ColumnHeader columnRemote; + private System.Windows.Forms.ColumnHeader columnRemotePort; + private System.Windows.Forms.ColumnHeader columnProtocol; + private System.Windows.Forms.ColumnHeader columnProcess; + private System.Windows.Forms.ImageList imageList; + private System.Windows.Forms.ColumnHeader columnLocalPort; + private System.Windows.Forms.ColumnHeader columnState; + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/NetworkList.cs b/branches/ph-plugins/ProcessHacker/Components/NetworkList.cs new file mode 100644 index 000000000..5de5be7e9 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/NetworkList.cs @@ -0,0 +1,496 @@ +/* + * Process Hacker - + * network list + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Reflection; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Common.Ui; +using ProcessHacker.UI; + +namespace ProcessHacker.Components +{ + public partial class NetworkList : UserControl + { + private NetworkProvider _provider; + private int _runCount = 0; + private List _needsAdd = new List(); + private HighlightingContext _highlightingContext; + private bool _needsSort = false; + private bool _needsImageKeyReset = false; + public new event KeyEventHandler KeyDown; + public new event MouseEventHandler MouseDown; + public new event MouseEventHandler MouseMove; + public new event MouseEventHandler MouseUp; + public new event EventHandler DoubleClick; + public event EventHandler SelectedIndexChanged; + + public NetworkList() + { + InitializeComponent(); + + _highlightingContext = new HighlightingContext(listNetwork); + listNetwork.SetTheme("explorer"); + listNetwork.ListViewItemSorter = new SortedListViewComparer(listNetwork); + listNetwork.KeyDown += new KeyEventHandler(NetworkList_KeyDown); + listNetwork.MouseDown += new MouseEventHandler(listNetwork_MouseDown); + listNetwork.MouseMove += new MouseEventHandler(listNetwork_MouseMove); + listNetwork.MouseUp += new MouseEventHandler(listNetwork_MouseUp); + listNetwork.DoubleClick += new EventHandler(listNetwork_DoubleClick); + listNetwork.SelectedIndexChanged += new System.EventHandler(listNetwork_SelectedIndexChanged); + } + + private void listNetwork_DoubleClick(object sender, EventArgs e) + { + if (this.DoubleClick != null) + this.DoubleClick(sender, e); + } + + private void listNetwork_MouseUp(object sender, MouseEventArgs e) + { + if (this.MouseUp != null) + this.MouseUp(sender, e); + } + + private void listNetwork_MouseDown(object sender, MouseEventArgs e) + { + if (this.MouseDown != null) + this.MouseDown(sender, e); + } + + private void listNetwork_MouseMove(object sender, MouseEventArgs e) + { + if (this.MouseMove != null) + this.MouseMove(sender, e); + + ListViewItem litem = listNetwork.GetItemAt(e.X, e.Y); + + if (litem != null) + { + NetworkItem item = (NetworkItem)litem.Tag; + var tree = Program.HackerWindow.ProcessTree; + + if (tree.Model.Nodes.ContainsKey(item.Connection.Pid)) + litem.ToolTipText = tree.Model.Nodes[item.Connection.Pid].GetTooltipText(tree.TooltipProvider); + } + } + + private void listNetwork_SelectedIndexChanged(object sender, System.EventArgs e) + { + if (this.SelectedIndexChanged != null) + this.SelectedIndexChanged(sender, e); + } + + private void NetworkList_KeyDown(object sender, KeyEventArgs e) + { + if (this.KeyDown != null) + this.KeyDown(sender, e); + } + + #region Properties + + public new bool DoubleBuffered + { + get + { + return (bool)typeof(ListView).GetProperty("DoubleBuffered", + BindingFlags.NonPublic | BindingFlags.Instance).GetValue(listNetwork, null); + } + set + { + typeof(ListView).GetProperty("DoubleBuffered", + BindingFlags.NonPublic | BindingFlags.Instance).SetValue(listNetwork, value, null); + } + } + + public override bool Focused + { + get + { + return listNetwork.Focused; + } + } + + public override ContextMenu ContextMenu + { + get { return listNetwork.ContextMenu; } + set { listNetwork.ContextMenu = value; } + } + + public override ContextMenuStrip ContextMenuStrip + { + get { return listNetwork.ContextMenuStrip; } + set { listNetwork.ContextMenuStrip = value; } + } + + public ListView List + { + get { return listNetwork; } + } + + public NetworkProvider Provider + { + get { return _provider; } + set + { + if (_provider != null) + { + _provider.DictionaryAdded -= provider_DictionaryAdded; + _provider.DictionaryModified -= provider_DictionaryModified; + _provider.DictionaryRemoved -= provider_DictionaryRemoved; + _provider.Updated -= provider_Updated; + Program.ProcessProvider.ProcessQueryReceived -= ProcessProvider_FileProcessingReceived; + } + + _provider = value; + + listNetwork.Items.Clear(); + + if (_provider != null) + { + Program.ProcessProvider.ProcessQueryReceived += ProcessProvider_FileProcessingReceived; + + foreach (NetworkItem item in _provider.Dictionary.Values) + { + provider_DictionaryAdded(item); + } + + _provider.DictionaryAdded += new NetworkProvider.ProviderDictionaryAdded(provider_DictionaryAdded); + _provider.DictionaryModified += new NetworkProvider.ProviderDictionaryModified(provider_DictionaryModified); + _provider.DictionaryRemoved += new NetworkProvider.ProviderDictionaryRemoved(provider_DictionaryRemoved); + _provider.Updated += new NetworkProvider.ProviderUpdateOnce(provider_Updated); + } + } + } + + #endregion + + #region Interfacing + + public void BeginUpdate() + { + listNetwork.BeginUpdate(); + } + + public void EndUpdate() + { + listNetwork.EndUpdate(); + } + + public ListView.ListViewItemCollection Items + { + get { return listNetwork.Items; } + } + + public ListView.SelectedListViewItemCollection SelectedItems + { + get { return listNetwork.SelectedItems; } + } + + #endregion + + private void ProcessProvider_FileProcessingReceived(int stage, int pid) + { + if (stage == 0x1) + { + // We just got the icon for the process. + this.BeginInvoke(new Action(this.RefreshIcons), pid); + _needsImageKeyReset = true; + } + } + + /// + /// Invalidates the cached icon indicies used in the list view. + /// + /// + /// When the image key of a ListViewItem is set, it looks up + /// the index corresponding to the image key and uses that + /// instead of the image key. When an image is removed from + /// the image list, the indicies will be wrong. + /// + private void ResetImageKeys() + { + lock (listNetwork) + { + foreach (ListViewItem lvItem in listNetwork.Items) + { + string t = lvItem.ImageKey; + + lvItem.ImageKey = ""; + lvItem.ImageKey = t; + } + } + } + + private void provider_Updated() + { + lock (_needsAdd) + { + if (_needsAdd.Count > 0) + { + this.BeginInvoke(new MethodInvoker(() => + { + lock (_needsAdd) + { + listNetwork.Items.AddRange(_needsAdd.ToArray()); + _needsAdd.Clear(); + } + })); + } + } + + _highlightingContext.Tick(); + + if (_needsSort) + { + this.BeginInvoke(new MethodInvoker(() => + { + if (_needsSort) + { + listNetwork.Sort(); + _needsSort = false; + } + })); + } + + if (_needsImageKeyReset) + { + this.BeginInvoke(new MethodInvoker(() => + { + if (_needsImageKeyReset) + { + this.ResetImageKeys(); + _needsImageKeyReset = false; + } + })); + } + + _runCount++; + } + + public void RefreshIcons() + { + this.RefreshIcons(0); + } + + public void RefreshIcons(int searchPid) + { + lock (listNetwork) + { + foreach (ListViewItem item in listNetwork.Items) + { + int pid = ((NetworkItem)item.Tag).Connection.Pid; + + if (searchPid != 0) + if (pid != searchPid) + continue; + // If the item already has an icon, continue searching. + if (item.ImageKey != "generic_process") + continue; + // If the PID is System Idle Process, continue searching. + if (pid < 4) + continue; + + if (Program.ProcessProvider.Dictionary.ContainsKey(pid) && + Program.ProcessProvider.Dictionary[pid].Icon != null) + { + if (!imageList.Images.ContainsKey(pid.ToString())) + imageList.Images.Add(pid.ToString(), + Program.ProcessProvider.Dictionary[pid].Icon); + + item.ImageKey = pid.ToString(); + } + } + } + } + + private void FillNetworkItemAddresses(ListViewItem litem, NetworkItem item) + { + if (item.Connection.Local != null && !item.Connection.Local.IsEmpty()) + { + string addressString = item.Connection.Local.Address.ToString(); + + if (item.LocalString != null && item.LocalString != addressString) + { + litem.SubItems[1].Text = item.LocalString + " (" + addressString + ")"; + } + else + { + litem.SubItems[1].Text = addressString; + } + } + + if (item.Connection.Remote != null && !item.Connection.Remote.IsEmpty()) + { + string addressString = item.Connection.Remote.Address.ToString(); + + if (item.RemoteString != null && item.RemoteString != addressString) + litem.SubItems[3].Text = item.RemoteString + " (" + addressString + ")"; + else + litem.SubItems[3].Text = addressString; + } + } + + private void provider_DictionaryAdded(NetworkItem item) + { + HighlightedListViewItem litem = new HighlightedListViewItem(_highlightingContext, (int)item.Tag > 0 && _runCount > 0); + + litem.Name = item.Id; + litem.Tag = item; + + Icon icon = null; + + if (Program.ProcessProvider.Dictionary.ContainsKey(item.Connection.Pid)) + { + lock (listNetwork) + { + if (imageList.Images.ContainsKey(item.Connection.Pid.ToString())) + imageList.Images.RemoveByKey(item.Connection.Pid.ToString()); + + icon = Program.ProcessProvider.Dictionary[item.Connection.Pid].Icon; + } + } + + if (icon != null) + { + lock (listNetwork) + imageList.Images.Add(item.Connection.Pid.ToString(), icon); + + litem.ImageKey = item.Connection.Pid.ToString(); + } + else + { + litem.ImageKey = "generic_process"; + } + + if (item.Connection.Pid == 0) + { + litem.Text = "Waiting Connections"; + } + else if (Program.ProcessProvider.Dictionary.ContainsKey(item.Connection.Pid)) + { + litem.Text = Program.ProcessProvider.Dictionary[item.Connection.Pid].Name + + " (" + item.Connection.Pid.ToString() + ")"; + } + else + { + litem.Text = "Unknown Process (" + item.Connection.Pid.ToString() + ")"; + } + + if (item.Connection.Local != null && !item.Connection.Local.IsEmpty()) + { + litem.SubItems.Add(new ListViewItem.ListViewSubItem(litem, item.Connection.Local.ToString())); + litem.SubItems.Add(new ListViewItem.ListViewSubItem(litem, item.Connection.Local.Port.ToString())); + } + else + { + litem.SubItems.Add(new ListViewItem.ListViewSubItem(litem, "")); + litem.SubItems.Add(new ListViewItem.ListViewSubItem(litem, "")); + } + + if (item.Connection.Remote != null && !item.Connection.Remote.IsEmpty()) + { + litem.SubItems.Add(new ListViewItem.ListViewSubItem(litem, item.Connection.Remote.ToString())); + litem.SubItems.Add(new ListViewItem.ListViewSubItem(litem, item.Connection.Remote.Port.ToString())); + } + else + { + litem.SubItems.Add(new ListViewItem.ListViewSubItem(litem, "")); + litem.SubItems.Add(new ListViewItem.ListViewSubItem(litem, "")); + } + + this.FillNetworkItemAddresses(litem, item); + + litem.SubItems.Add(new ListViewItem.ListViewSubItem(litem, item.Connection.Protocol.ToString().ToUpper())); + litem.SubItems.Add(new ListViewItem.ListViewSubItem(litem, item.Connection.State != 0 ? item.Connection.State.ToString() : "")); + + lock (_needsAdd) + _needsAdd.Add(litem); + _needsImageKeyReset = true; + } + + private void provider_DictionaryModified(NetworkItem oldItem, NetworkItem newItem) + { + this.BeginInvoke(new MethodInvoker(() => + { + lock (listNetwork) + { + ListViewItem litem = listNetwork.Items[newItem.Id]; + + if (litem == null) + return; + + this.FillNetworkItemAddresses(litem, newItem); + + litem.SubItems[6].Text = newItem.Connection.State != 0 ? newItem.Connection.State.ToString() : ""; + _needsSort = true; + } + })); + } + + private void provider_DictionaryRemoved(NetworkItem item) + { + this.BeginInvoke(new MethodInvoker(() => + { + lock (listNetwork) + { + if (!listNetwork.Items.ContainsKey(item.Id)) + return; + + ListViewItem litem = listNetwork.Items[item.Id]; + bool imageStillUsed = false; + + if (litem.ImageKey == "generic_process") + { + imageStillUsed = true; + } + else + { + foreach (ListViewItem lvItem in listNetwork.Items) + { + if (lvItem != litem && lvItem.ImageKey == item.Connection.Pid.ToString()) + { + imageStillUsed = true; + break; + } + } + } + + if (!imageStillUsed) + { + imageList.Images.RemoveByKey(item.Connection.Pid.ToString()); + + // Set the item's icon to generic_process, otherwise we are going to + // get a blank space for the icon. + litem.ImageKey = "generic_process"; + // Reset all the image keys (by now most items' icons have screwed up). + this.ResetImageKeys(); + } + + litem.Remove(); + } + })); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/NetworkList.resx b/branches/ph-plugins/ProcessHacker/Components/NetworkList.resx new file mode 100644 index 000000000..c680ceefe --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/NetworkList.resx @@ -0,0 +1,155 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj0yLjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAACc + BQAAAk1TRnQBSQFMAwEBAAEcAQABHAEAARABAAEQAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABQAMA + ARADAAEBAQABIAYAARD/AP8AFAABlwGSAY8B/wGXAZIBjwH/AZcBkgGPAf8BlwGSAY8B/wGXAZIBjwH/ + AZcBkgGPAf8BlwGSAY8B/wGXAZIBjwH/AZcBkgGPAf8BlwGSAY8B/wGXAZIBjwH/AZcBkgGPAf8BlwGS + AY8B/wGXAZIBjwH/AZcBkgGPAf8BlwGSAY8B/8AAAZcBkgGPCf8D/gH/A/wB/wP6Af8D+AH/A/UB/wPz + Af8D8QH/A+4B/wPsAf8D6QH/A+gB/wPmAf8BlwGSAY8B/8AAAZcBkgGPCf8D/gH/A/wB/wP6Af8D+AH/ + A/UB/wP1Af8D8wH/A/AB/wPuAf8D6wH/A+kB/wPnAf8BlwGSAY8B/8AAAZcBkgGPBf8BhwGdAU4B/wGC + AaIBUgH/AXYBqAFWAf8BcAGtAVoB/wFsAbEBXgH/A/cB/wHNAcwBygH/Ac0BzAHKAf8BzQHMAcoB/wHN + AcwBygH/A+0B/wPrAf8D6AH/AZcBkgGPAf/AAAGXAZIBjwX/AY0BlAFIAf8BiQGaAUwB/wGEAaABUAH/ + AXgBpQFUAf8BcwGqAVgB/wP5Af8D9gH/A/QB/wP0Af8D8QH/A+8B/wPsAf8D6gH/AZcBkgGPAf/AAAGX + AZIBjwX/AZMBiQFDAf8BjwGQAUYB/wGLAZcBSgH/AYcBnQFOAf8BggGiAVIB/wP7Af8BzQHMAcoB/wHN + AcwBygH/Ac0BzAHKAf8BzQHMAcoB/wPxAf8BdAGpAVcB/wPsAf8BlwGSAY8B/8AAAZcBkgGPBf8BmAF1 + AT0B/wGVAYQBQQH/AZEBjAFEAf8BjQGUAUgB/wGJAZoBTAH/A/wB/wP6Af8D+AH/A/gB/wP1Af8D8wH/ + AYsBlwFKAf8D7gH/AZcBkgGPAf/AAAGXAZIBjwX/AZ0BawE4Af8BmgFyATsB/wGWAYABPwH/AZMBiQFD + Af8BjwGQAUYB/wP9Af8BzQHMAcoB/wHNAcwBygH/Ac0BzAHKAf8BzQHMAcoB/wP1Af8BlwF3AT4B/wPv + Af8BlwGSAY8B/8AAAZcBkgGPBf8BoAFjATUB/wGeAWgBNwH/AZsBbgE6Af8BmAF1AT0B/wGVAYQBQQH/ + A/4B/wP+Af8D/QH/A/sB/wP5Af8D9gH/AaABYwE1Af8D8QH/AZcBkgGPAf/AAAGXAZIBjxn/A/4B/wP+ + Af8D/QH/A/sB/wP5Af8D9gH/A/QB/wPxAf8BlwGSAY8B/8AAAZcBkgGPAf8BzQHMAcoB/wHNAcwBygH/ + Ac0BzAHKAf8BzQHMAcoB/wHNAcwBygH/Ac0BzAHKAf8BzQHMAcoB/wHNAcwBygH/Ac0BzAHKAf8BzQHM + AcoB/wHNAcwBygH/Ac0BzAHKAf8BzQHMAcoB/wHNAcwBygH/AZcBkgGPAf/AAAGXAZIBjwH/AeAB2QHT + Af8B4AHZAdMB/wHgAdkB0wH/AeAB2QHTAf8B4AHZAdMB/wHgAdkB0wH/AeAB2QHTAf8B4AHZAdMB/wHg + AdkB0wH/AZEBcgFhAf8B4AHZAdMB/wGRAXIBYQH/AeAB2QHTAf8BkQFyAWEB/wGXAZIBjwH/wAABlwGS + AY8B/wGXAZIBjwH/AZcBkgGPAf8BlwGSAY8B/wGXAZIBjwH/AZcBkgGPAf8BlwGSAY8B/wGXAZIBjwH/ + AZcBkgGPAf8BlwGSAY8B/wGXAZIBjwH/AZcBkgGPAf8BlwGSAY8B/wGXAZIBjwH/AZcBkgGPAf8BlwGS + AY8B//8AwQABQgFNAT4HAAE+AwABKAMAAUADAAEQAwABAQEAAQEFAAGAFwAD/wEAAv8GAAL/bgAC/wYA + Cw== + + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/NodePlotter.cs b/branches/ph-plugins/ProcessHacker/Components/NodePlotter.cs new file mode 100644 index 000000000..0a14d66eb --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/NodePlotter.cs @@ -0,0 +1,98 @@ +/* + * Process Hacker - + * TreeViewAdv plotter adapter + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Text; +using Aga.Controls.Tree.NodeControls; +using System.Drawing; +using Aga.Controls.Tree; + +namespace ProcessHacker.Components +{ + public class NodePlotter : BindableControl + { + public class PlotterInfo + { + public bool UseLongData; + public bool UseSecondLine; + public bool OverlaySecondLine; + public IList Data1; + public IList Data2; + public IList LongData1; + public IList LongData2; + public Color LineColor1; + public Color LineColor2; + } + + private Plotter _plotter; + + public override Size MeasureSize(TreeNodeAdv node, DrawContext context) + { + return new Size(this.ParentColumn.Width, this.Parent.RowHeight); + } + + public override void Draw(TreeNodeAdv node, DrawContext context) + { + PlotterInfo info = GetValue(node) as PlotterInfo; + + if (_plotter == null) + { + _plotter = new Plotter(); + _plotter.BackColor = Color.Black; + _plotter.ShowGrid = false; + _plotter.OverlaySecondLine = false; + } + + if (info.UseLongData) + { + _plotter.UseLongData = true; + _plotter.LongData1 = info.LongData1; + _plotter.LongData2 = info.LongData2; + } + else + { + _plotter.UseLongData = false; + _plotter.Data1 = info.Data1; + _plotter.Data2 = info.Data2; + } + + _plotter.UseSecondLine = info.UseSecondLine; + _plotter.OverlaySecondLine = info.OverlaySecondLine; + _plotter.LineColor1 = info.LineColor1; + _plotter.LineColor2 = info.LineColor2; + + if ((_plotter.Width != context.Bounds.Width - 1 || + _plotter.Height != context.Bounds.Height - 1) && + context.Bounds.Width > 1 && context.Bounds.Height > 1) + _plotter.Size = new Size(context.Bounds.Width - 1, context.Bounds.Height - 1); + + _plotter.Draw(); + + using (Bitmap b = new Bitmap(_plotter.Width, _plotter.Height)) + { + _plotter.DrawToBitmap(b, new Rectangle(0, 0, b.Width, b.Height)); + context.Graphics.DrawImage(b, context.Bounds.Location); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/Plotter.Designer.cs b/branches/ph-plugins/ProcessHacker/Components/Plotter.Designer.cs new file mode 100644 index 000000000..9350da62c --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/Plotter.Designer.cs @@ -0,0 +1,63 @@ +namespace ProcessHacker.Components +{ + partial class Plotter + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + if (_managedBackBuffer != NO_MANAGED_BACK_BUFFER) + _managedBackBuffer.Dispose(); + + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.toolTip = new System.Windows.Forms.ToolTip(this.components); + this.SuspendLayout(); + // + // toolTip + // + this.toolTip.AutomaticDelay = 0; + this.toolTip.ShowAlways = true; + // + // Plotter + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Name = "Plotter"; + this.Size = new System.Drawing.Size(150, 163); + this.MouseLeave += new System.EventHandler(this.Plotter_MouseLeave); + this.Paint += new System.Windows.Forms.PaintEventHandler(this.Plotter_Paint); + this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.Plotter_MouseMove); + this.Resize += new System.EventHandler(this.Plotter_Resize); + this.MouseEnter += new System.EventHandler(this.Plotter_MouseEnter); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.ToolTip toolTip; + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/Plotter.cs b/branches/ph-plugins/ProcessHacker/Components/Plotter.cs new file mode 100644 index 000000000..64c4e3c2b --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/Plotter.cs @@ -0,0 +1,551 @@ +/* + * Process Hacker - + * plotter control + * + * Copyright (C) 2008-2009 wj32 + * Copyright (C) 2008 Dean + * + * 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 . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; +using ProcessHacker.Common; + +namespace ProcessHacker.Components +{ + public partial class Plotter : UserControl + { + private static int _globalMoveStep = 3; + + public static int GlobalMoveStep + { + get { return _globalMoveStep; } + set { _globalMoveStep = value; } + } + + public delegate string GetToolTipDelegate(int item); + + private const BufferedGraphics NO_MANAGED_BACK_BUFFER = null; + private BufferedGraphicsContext _graphicManager; + private BufferedGraphics _managedBackBuffer; + private bool _showToolTip; + private Point _mouseLocation; + private string _lastToolTip; + + public Plotter() + { + InitializeComponent(); + + SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true); + _graphicManager = BufferedGraphicsManager.Current; + _graphicManager.MaximumBuffer = + new Size(this.Width + 1, this.Height + 1); + _managedBackBuffer = + _graphicManager.Allocate(this.CreateGraphics(), this.ClientRectangle); + + this.Draw(); + } + + public GetToolTipDelegate GetToolTip; + + private int _gridStartPos = 0; + + private void Plotter_Paint(object sender, PaintEventArgs e) + { + try + { + this.Render(e.Graphics); + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + + public void Render(Graphics g) + { + _managedBackBuffer.Render(g); + } + + public void Draw() + { + this.Draw(_managedBackBuffer.Graphics); + + if (_showToolTip) + this.ShowToolTip(); + + this.Refresh(); + } + + public void Draw(Graphics g) + { + int tWidth = this.Width; + int tHeight = this.Height; + int moveStep = this.EffectiveMoveStep; + + g.SmoothingMode = Properties.Settings.Default.PlotterAntialias ? + SmoothingMode.AntiAlias : SmoothingMode.Default; + + g.FillRectangle(new SolidBrush(this.BackColor), 0, 0, tWidth, tHeight); + + // Draw the grid (if enabled). + + if (_showGrid) + { + int x = tWidth / _gridSize.Width; + int y = tHeight / _gridSize.Height; + + Pen pGrid = new Pen(_gridColor); + int pos; + + for (int i = 0; i <= x; i++) + { + pos = tWidth - (i * _gridSize.Width + _gridStartPos - 1); + g.DrawLine(pGrid, pos, 0, pos, tHeight); + } + + for (int i = 0; i <= y; i++) + { + pos = i * _gridSize.Height - 1; + g.DrawLine(pGrid, 0, pos, tWidth, pos); + } + } + + // Validate and if necessary, fix the data. + + if (_useLongData && (_longData1 == null || (this.UseSecondLine && _longData2 == null))) + return; + + if (_useLongData) + this.FixLongData(); + + if (_data1 == null || (this.UseSecondLine && _data2 == null)) + return; + + // Draw the lines. + + int px = tWidth - moveStep; + int start = 0; + Pen lGrid1 = new Pen(_lineColor1); + Pen lGrid2 = new Pen(_lineColor2); + + while (start < _data1.Count - 1) + { + float f = _data1[start + 1]; + float fPre = _data1[start]; + + int h = (int)(tHeight - (tHeight * f)); + int hPre = (int)(tHeight - (tHeight * fPre)); + + // Fill in the area below the line. + + g.FillPolygon(new SolidBrush(Color.FromArgb(100, _lineColor1)), + new Point[] { new Point(px, h), new Point(px + moveStep, hPre), + new Point(px + moveStep, tHeight), new Point(px, tHeight) }); + g.DrawLine(lGrid1, px, h, px + moveStep, hPre); + + if (this.UseSecondLine) + { + f = _data2[start + 1]; + fPre = _data2[start]; + + if (!this.OverlaySecondLine) + { + f += _data1[start + 1]; + fPre += _data1[start]; + + if (f > 1.0f) + f = 1.0f; + if (fPre > 1.0f) + fPre = 1.0f; + } + + h = (int)(tHeight - (tHeight * f)); + hPre = (int)(tHeight - (tHeight * fPre)); + + // Draw the second line. + + if (this.OverlaySecondLine) + { + g.FillPolygon(new SolidBrush(Color.FromArgb(100, _lineColor2)), + new Point[] { new Point(px, h), new Point(px + moveStep, hPre), + new Point(px + moveStep, tHeight), new Point(px, tHeight) }); + g.DrawLine(lGrid2, px, h, px + moveStep, hPre); + } + else + { + g.FillPolygon(new SolidBrush(Color.FromArgb(100, _lineColor2)), + new Point[] { new Point(px, h), new Point(px + moveStep, hPre), + new Point(px + moveStep, tHeight - (int)(tHeight * _data1[start])), + new Point(px, tHeight - (int)(tHeight * _data1[start + 1])) }); + g.DrawLine(lGrid2, px, h, px + moveStep, hPre); + } + } + + if (px < 0) + { + break; + } + + px -= moveStep; + start++; + } + + // Draw the text, if any. + if (!string.IsNullOrEmpty(_text)) + { + // Draw the background for the text. + g.FillRectangle(new SolidBrush(_textBoxColor), + new Rectangle(_boxPosition, _boxSize)); + + // Draw the text. + TextRenderer.DrawText(g, _text, this.Font, _textPosition, _textColor); + } + } + + private void ShowToolTip() + { + this.ShowToolTip(false); + } + + private void ShowToolTip(bool force) + { + if (this.GetToolTip != null) + { + int itemIndex = (this.Width - _mouseLocation.X) / this.EffectiveMoveStep; + + if (itemIndex < this.Data1.Count) + { + try + { + string currentToolTip = this.GetToolTip(itemIndex); + + if (currentToolTip != _lastToolTip || force) + toolTip.Show(currentToolTip, this, + new Point(_mouseLocation.X + 10, _mouseLocation.Y + 10), + int.MaxValue); + + _lastToolTip = currentToolTip; + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + else + { + toolTip.Hide(this); + } + } + } + + public void MoveGrid() + { + _gridStartPos += this.EffectiveMoveStep; + + if (_gridStartPos >= _gridSize.Width) + { + _gridStartPos -= _gridSize.Width; + } + } + + public void FixLongData() + { + // find the largest value + long max = 0; + // restrict scaling to the currently visible data points + int maxIndex = this.Width / this.EffectiveMoveStep; + + for (int i = 0; i < _longData1.Count && i <= maxIndex; i++) + if (_longData1[i] > max) + max = _longData1[i]; + for (int i = 0; i < _longData2.Count && i <= maxIndex; i++) + if (_longData2[i] > max) + max = _longData2[i]; + + if (max < _minMaxValue) + max = _minMaxValue; + + // redo the float list + _data1 = new List(); + _data2 = new List(); + + for (int i = 0; i < _longData1.Count && i <= maxIndex; i++) + { + if (max != 0) + _data1.Add((float)_longData1[i] / max); + else + _data1.Add(0); + } + + for (int i = 0; i < _longData2.Count && i <= maxIndex; i++) + { + if (max != 0) + _data2.Add((float)_longData2[i] / max); + else + _data2.Add(0); + } + } + + #region Text + + private Point _textPosition, _boxPosition; + private Size _textSize, _boxSize; + + private Padding _textMargin = new Padding(3, 3, 3, 3); + public Padding TextMargin + { + get { return _textMargin; } + set { _textMargin = value; } + } + + private Padding _textPadding = new Padding(3, 3, 3, 3); + public Padding TextPadding + { + get { return _textPadding; } + set { _textPadding = value; } + } + + private ContentAlignment _textAlign = ContentAlignment.TopLeft; + public ContentAlignment TextPosition + { + get { return _textAlign; } + set { _textAlign = value; } + } + + private string _text; + public override string Text + { + get + { + return _text; + } + set + { + base.Text = _text = value; + + _textSize = TextRenderer.MeasureText(this.Text, this.Font); + _boxSize = new Size( + _textSize.Width + _textPadding.Left + _textPadding.Right, + _textSize.Height + _textPadding.Top + _textPadding.Bottom); + + // work out Y + switch (_textAlign) + { + case ContentAlignment.BottomCenter: + case ContentAlignment.BottomLeft: + case ContentAlignment.BottomRight: + _boxPosition.Y = this.Size.Height - _boxSize.Height - _textMargin.Bottom; + break; + + case ContentAlignment.MiddleCenter: + case ContentAlignment.MiddleLeft: + case ContentAlignment.MiddleRight: + _boxPosition.Y = (this.Size.Height - _boxSize.Height) / 2; + break; + + case ContentAlignment.TopCenter: + case ContentAlignment.TopLeft: + case ContentAlignment.TopRight: + _boxPosition.Y = _textMargin.Top; + break; + } + + // work out X + switch (_textAlign) + { + case ContentAlignment.BottomLeft: + case ContentAlignment.MiddleLeft: + case ContentAlignment.TopLeft: + _boxPosition.X = _textMargin.Left; + break; + + case ContentAlignment.BottomCenter: + case ContentAlignment.MiddleCenter: + case ContentAlignment.TopCenter: + _boxPosition.X = (this.Size.Width - _boxSize.Width) / 2; + break; + + case ContentAlignment.BottomRight: + case ContentAlignment.MiddleRight: + case ContentAlignment.TopRight: + _boxPosition.X = this.Size.Width - _boxSize.Width - _textMargin.Right; + break; + } + + _textPosition = new Point( + _boxPosition.X + _textPadding.Left, + _boxPosition.Y + _textPadding.Top); + } + } + + private Color _textBoxColor = Color.FromArgb(127, Color.Black); + public Color TextBoxColor + { + get { return _textBoxColor; } + set { _textBoxColor = value; } + } + + private Color _textColor = Color.FromArgb(0, 255, 0); + public Color TextColor + { + get { return _textColor; } + set { _textColor = value; } + } + + #endregion + + public bool UseSecondLine { get; set; } + public bool OverlaySecondLine { get; set; } + + private Color _lineColor1 = Color.FromArgb(0, 255, 0); + public Color LineColor1 + { + get { return _lineColor1; } + set { _lineColor1 = value; } + } + + private Color _lineColor2 = Color.FromArgb(255, 0, 0); + public Color LineColor2 + { + get { return _lineColor2; } + set { _lineColor2 = value; } + } + + private bool _showGrid = true; + public bool ShowGrid + { + get { return _showGrid; } + set { _showGrid = value; } + } + + private Color _gridColor = Color.Green; + public Color GridColor + { + get { return _gridColor; } + set { _gridColor = value; } + } + + private Size _gridSize = new Size(12, 12); + public Size GridSize + { + get { return _gridSize; } + set { _gridSize = value; } + } + + private int _moveStep = -1; + public int MoveStep + { + get { return _moveStep; } + set { _moveStep = value; } + } + + public int EffectiveMoveStep + { + get { return _moveStep == -1 ? GlobalMoveStep : _moveStep; } + } + + private IList _data1; + public IList Data1 + { + get { return _data1; } + set { _data1 = value; } + } + + private IList _data2; + public IList Data2 + { + get { return _data2; } + set { _data2 = value; } + } + + private bool _useLongData; + public bool UseLongData + { + get { return _useLongData; } + set { _useLongData = value; } + } + + private IList _longData1; + public IList LongData1 + { + get { return _longData1; } + set { _longData1 = value; } + } + + private IList _longData2; + public IList LongData2 + { + get { return _longData2; } + set { _longData2 = value; } + } + + private long _minMaxValue = 0; + /// + /// The minimum scaling value to be used for long data. + /// + public long MinMaxValue + { + get { return _minMaxValue; } + set { _minMaxValue = value; } + } + + private void Plotter_Resize(object sender, EventArgs e) + { + if (_managedBackBuffer != NO_MANAGED_BACK_BUFFER) + _managedBackBuffer.Dispose(); + + if (_graphicManager == null) + _graphicManager = BufferedGraphicsManager.Current; + + _graphicManager.MaximumBuffer = + new Size(this.Width + 1, this.Height + 1); + _managedBackBuffer = + _graphicManager.Allocate(this.CreateGraphics(), this.ClientRectangle); + + this.Draw(); + } + + private void Plotter_MouseEnter(object sender, EventArgs e) + { + _showToolTip = true; + } + + private void Plotter_MouseLeave(object sender, EventArgs e) + { + _showToolTip = false; + toolTip.Hide(this); + } + + private void Plotter_MouseMove(object sender, MouseEventArgs e) + { + if (e.Location != _mouseLocation) + { + _mouseLocation = e.Location; + this.ShowToolTip(true); + } + else + { + _mouseLocation = e.Location; + this.ShowToolTip(); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/Plotter.resx b/branches/ph-plugins/ProcessHacker/Components/Plotter.resx new file mode 100644 index 000000000..a5979aadf --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/Plotter.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/ProcessStatistics.Designer.cs b/branches/ph-plugins/ProcessHacker/Components/ProcessStatistics.Designer.cs new file mode 100644 index 000000000..429319c24 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/ProcessStatistics.Designer.cs @@ -0,0 +1,852 @@ +namespace ProcessHacker.Components +{ + partial class ProcessStatistics + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.flowStats = new System.Windows.Forms.FlowLayoutPanel(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.label6 = new System.Windows.Forms.Label(); + this.label8 = new System.Windows.Forms.Label(); + this.label9 = new System.Windows.Forms.Label(); + this.label10 = new System.Windows.Forms.Label(); + this.labelCPUPriority = new System.Windows.Forms.Label(); + this.labelCPUKernelTime = new System.Windows.Forms.Label(); + this.labelCPUUserTime = new System.Windows.Forms.Label(); + this.labelCPUTotalTime = new System.Windows.Forms.Label(); + this.labelCPUCyclesText = new System.Windows.Forms.Label(); + this.labelCPUCycles = new System.Windows.Forms.Label(); + this.groupBox4 = new System.Windows.Forms.GroupBox(); + this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); + this.label24 = new System.Windows.Forms.Label(); + this.label22 = new System.Windows.Forms.Label(); + this.label20 = new System.Windows.Forms.Label(); + this.label11 = new System.Windows.Forms.Label(); + this.label12 = new System.Windows.Forms.Label(); + this.label13 = new System.Windows.Forms.Label(); + this.label14 = new System.Windows.Forms.Label(); + this.labelMemoryPB = new System.Windows.Forms.Label(); + this.labelMemoryWS = new System.Windows.Forms.Label(); + this.labelMemoryPWS = new System.Windows.Forms.Label(); + this.labelMemoryVS = new System.Windows.Forms.Label(); + this.labelMemoryPVS = new System.Windows.Forms.Label(); + this.labelMemoryPU = new System.Windows.Forms.Label(); + this.labelMemoryPPU = new System.Windows.Forms.Label(); + this.label25 = new System.Windows.Forms.Label(); + this.labelMemoryPF = new System.Windows.Forms.Label(); + this.label30 = new System.Windows.Forms.Label(); + this.labelMemoryPP = new System.Windows.Forms.Label(); + this.groupBox5 = new System.Windows.Forms.GroupBox(); + this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel(); + this.label16 = new System.Windows.Forms.Label(); + this.label17 = new System.Windows.Forms.Label(); + this.label18 = new System.Windows.Forms.Label(); + this.label19 = new System.Windows.Forms.Label(); + this.label21 = new System.Windows.Forms.Label(); + this.label23 = new System.Windows.Forms.Label(); + this.labelIOReads = new System.Windows.Forms.Label(); + this.labelIOReadBytes = new System.Windows.Forms.Label(); + this.labelIOWrites = new System.Windows.Forms.Label(); + this.labelIOWriteBytes = new System.Windows.Forms.Label(); + this.labelIOOther = new System.Windows.Forms.Label(); + this.labelIOOtherBytes = new System.Windows.Forms.Label(); + this.label31 = new System.Windows.Forms.Label(); + this.labelIOPriority = new System.Windows.Forms.Label(); + this.groupBox6 = new System.Windows.Forms.GroupBox(); + this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel(); + this.label27 = new System.Windows.Forms.Label(); + this.labelOtherHandles = new System.Windows.Forms.Label(); + this.label28 = new System.Windows.Forms.Label(); + this.label29 = new System.Windows.Forms.Label(); + this.labelOtherGDIHandles = new System.Windows.Forms.Label(); + this.labelOtherUSERHandles = new System.Windows.Forms.Label(); + this.buttonHandleDetails = new System.Windows.Forms.Button(); + this.flowStats.SuspendLayout(); + this.groupBox1.SuspendLayout(); + this.tableLayoutPanel1.SuspendLayout(); + this.groupBox4.SuspendLayout(); + this.tableLayoutPanel2.SuspendLayout(); + this.groupBox5.SuspendLayout(); + this.tableLayoutPanel3.SuspendLayout(); + this.groupBox6.SuspendLayout(); + this.tableLayoutPanel4.SuspendLayout(); + this.SuspendLayout(); + // + // flowStats + // + this.flowStats.Controls.Add(this.groupBox1); + this.flowStats.Controls.Add(this.groupBox4); + this.flowStats.Controls.Add(this.groupBox5); + this.flowStats.Controls.Add(this.groupBox6); + this.flowStats.Dock = System.Windows.Forms.DockStyle.Fill; + this.flowStats.FlowDirection = System.Windows.Forms.FlowDirection.TopDown; + this.flowStats.Location = new System.Drawing.Point(0, 0); + this.flowStats.Name = "flowStats"; + this.flowStats.Size = new System.Drawing.Size(433, 374); + this.flowStats.TabIndex = 1; + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.tableLayoutPanel1); + this.groupBox1.Location = new System.Drawing.Point(3, 3); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(195, 108); + this.groupBox1.TabIndex = 0; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "CPU"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 2; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.Controls.Add(this.label6, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.label8, 0, 2); + this.tableLayoutPanel1.Controls.Add(this.label9, 0, 3); + this.tableLayoutPanel1.Controls.Add(this.label10, 0, 4); + this.tableLayoutPanel1.Controls.Add(this.labelCPUPriority, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.labelCPUKernelTime, 1, 2); + this.tableLayoutPanel1.Controls.Add(this.labelCPUUserTime, 1, 3); + this.tableLayoutPanel1.Controls.Add(this.labelCPUTotalTime, 1, 4); + this.tableLayoutPanel1.Controls.Add(this.labelCPUCyclesText, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.labelCPUCycles, 1, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(3, 16); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 5; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 20F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 20F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 20F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 20F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 20F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(189, 89); + this.tableLayoutPanel1.TabIndex = 1; + // + // label6 + // + this.label6.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(3, 2); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(38, 13); + this.label6.TabIndex = 1; + this.label6.Text = "Priority"; + // + // label8 + // + this.label8.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label8.AutoSize = true; + this.label8.Location = new System.Drawing.Point(3, 36); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(63, 13); + this.label8.TabIndex = 1; + this.label8.Text = "Kernel Time"; + // + // label9 + // + this.label9.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label9.AutoSize = true; + this.label9.Location = new System.Drawing.Point(3, 53); + this.label9.Name = "label9"; + this.label9.Size = new System.Drawing.Size(55, 13); + this.label9.TabIndex = 1; + this.label9.Text = "User Time"; + // + // label10 + // + this.label10.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label10.AutoSize = true; + this.label10.Location = new System.Drawing.Point(3, 72); + this.label10.Name = "label10"; + this.label10.Size = new System.Drawing.Size(57, 13); + this.label10.TabIndex = 1; + this.label10.Text = "Total Time"; + // + // labelCPUPriority + // + this.labelCPUPriority.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelCPUPriority.AutoSize = true; + this.labelCPUPriority.Location = new System.Drawing.Point(153, 2); + this.labelCPUPriority.Name = "labelCPUPriority"; + this.labelCPUPriority.Size = new System.Drawing.Size(33, 13); + this.labelCPUPriority.TabIndex = 1; + this.labelCPUPriority.Text = "value"; + // + // labelCPUKernelTime + // + this.labelCPUKernelTime.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelCPUKernelTime.AutoSize = true; + this.labelCPUKernelTime.Location = new System.Drawing.Point(153, 36); + this.labelCPUKernelTime.Name = "labelCPUKernelTime"; + this.labelCPUKernelTime.Size = new System.Drawing.Size(33, 13); + this.labelCPUKernelTime.TabIndex = 1; + this.labelCPUKernelTime.Text = "value"; + // + // labelCPUUserTime + // + this.labelCPUUserTime.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelCPUUserTime.AutoSize = true; + this.labelCPUUserTime.Location = new System.Drawing.Point(153, 53); + this.labelCPUUserTime.Name = "labelCPUUserTime"; + this.labelCPUUserTime.Size = new System.Drawing.Size(33, 13); + this.labelCPUUserTime.TabIndex = 1; + this.labelCPUUserTime.Text = "value"; + // + // labelCPUTotalTime + // + this.labelCPUTotalTime.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelCPUTotalTime.AutoSize = true; + this.labelCPUTotalTime.Location = new System.Drawing.Point(153, 72); + this.labelCPUTotalTime.Name = "labelCPUTotalTime"; + this.labelCPUTotalTime.Size = new System.Drawing.Size(33, 13); + this.labelCPUTotalTime.TabIndex = 1; + this.labelCPUTotalTime.Text = "value"; + // + // labelCPUCyclesText + // + this.labelCPUCyclesText.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.labelCPUCyclesText.AutoSize = true; + this.labelCPUCyclesText.Location = new System.Drawing.Point(3, 19); + this.labelCPUCyclesText.Name = "labelCPUCyclesText"; + this.labelCPUCyclesText.Size = new System.Drawing.Size(38, 13); + this.labelCPUCyclesText.TabIndex = 1; + this.labelCPUCyclesText.Text = "Cycles"; + // + // labelCPUCycles + // + this.labelCPUCycles.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelCPUCycles.AutoSize = true; + this.labelCPUCycles.Location = new System.Drawing.Point(153, 19); + this.labelCPUCycles.Name = "labelCPUCycles"; + this.labelCPUCycles.Size = new System.Drawing.Size(33, 13); + this.labelCPUCycles.TabIndex = 1; + this.labelCPUCycles.Text = "value"; + // + // groupBox4 + // + this.groupBox4.Controls.Add(this.tableLayoutPanel2); + this.groupBox4.Location = new System.Drawing.Point(3, 117); + this.groupBox4.Name = "groupBox4"; + this.groupBox4.Size = new System.Drawing.Size(195, 194); + this.groupBox4.TabIndex = 0; + this.groupBox4.TabStop = false; + this.groupBox4.Text = "Memory"; + // + // tableLayoutPanel2 + // + this.tableLayoutPanel2.ColumnCount = 2; + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel2.Controls.Add(this.label24, 0, 6); + this.tableLayoutPanel2.Controls.Add(this.label22, 0, 5); + this.tableLayoutPanel2.Controls.Add(this.label20, 0, 4); + this.tableLayoutPanel2.Controls.Add(this.label11, 0, 0); + this.tableLayoutPanel2.Controls.Add(this.label12, 0, 1); + this.tableLayoutPanel2.Controls.Add(this.label13, 0, 2); + this.tableLayoutPanel2.Controls.Add(this.label14, 0, 3); + this.tableLayoutPanel2.Controls.Add(this.labelMemoryPB, 1, 0); + this.tableLayoutPanel2.Controls.Add(this.labelMemoryWS, 1, 1); + this.tableLayoutPanel2.Controls.Add(this.labelMemoryPWS, 1, 2); + this.tableLayoutPanel2.Controls.Add(this.labelMemoryVS, 1, 3); + this.tableLayoutPanel2.Controls.Add(this.labelMemoryPVS, 1, 4); + this.tableLayoutPanel2.Controls.Add(this.labelMemoryPU, 1, 5); + this.tableLayoutPanel2.Controls.Add(this.labelMemoryPPU, 1, 6); + this.tableLayoutPanel2.Controls.Add(this.label25, 0, 7); + this.tableLayoutPanel2.Controls.Add(this.labelMemoryPF, 1, 7); + this.tableLayoutPanel2.Controls.Add(this.label30, 0, 8); + this.tableLayoutPanel2.Controls.Add(this.labelMemoryPP, 1, 8); + this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 16); + this.tableLayoutPanel2.Name = "tableLayoutPanel2"; + this.tableLayoutPanel2.RowCount = 9; + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 11.11111F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 11.11111F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 11.11111F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 11.11111F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 11.11111F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 11.11111F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 11.11111F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 11.11111F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 11.11111F)); + this.tableLayoutPanel2.Size = new System.Drawing.Size(189, 175); + this.tableLayoutPanel2.TabIndex = 1; + // + // label24 + // + this.label24.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label24.AutoSize = true; + this.label24.Location = new System.Drawing.Point(3, 117); + this.label24.Name = "label24"; + this.label24.Size = new System.Drawing.Size(107, 13); + this.label24.TabIndex = 7; + this.label24.Text = "Peak Pagefile Usage"; + // + // label22 + // + this.label22.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label22.AutoSize = true; + this.label22.Location = new System.Drawing.Point(3, 98); + this.label22.Name = "label22"; + this.label22.Size = new System.Drawing.Size(79, 13); + this.label22.TabIndex = 5; + this.label22.Text = "Pagefile Usage"; + // + // label20 + // + this.label20.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label20.AutoSize = true; + this.label20.Location = new System.Drawing.Point(3, 79); + this.label20.Name = "label20"; + this.label20.Size = new System.Drawing.Size(87, 13); + this.label20.TabIndex = 3; + this.label20.Text = "Peak Virtual Size"; + // + // label11 + // + this.label11.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label11.AutoSize = true; + this.label11.Location = new System.Drawing.Point(3, 3); + this.label11.Name = "label11"; + this.label11.Size = new System.Drawing.Size(69, 13); + this.label11.TabIndex = 1; + this.label11.Text = "Private Bytes"; + // + // label12 + // + this.label12.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label12.AutoSize = true; + this.label12.Location = new System.Drawing.Point(3, 22); + this.label12.Name = "label12"; + this.label12.Size = new System.Drawing.Size(66, 13); + this.label12.TabIndex = 1; + this.label12.Text = "Working Set"; + // + // label13 + // + this.label13.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label13.AutoSize = true; + this.label13.Location = new System.Drawing.Point(3, 41); + this.label13.Name = "label13"; + this.label13.Size = new System.Drawing.Size(94, 13); + this.label13.TabIndex = 1; + this.label13.Text = "Peak Working Set"; + // + // label14 + // + this.label14.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label14.AutoSize = true; + this.label14.Location = new System.Drawing.Point(3, 60); + this.label14.Name = "label14"; + this.label14.Size = new System.Drawing.Size(59, 13); + this.label14.TabIndex = 1; + this.label14.Text = "Virtual Size"; + // + // labelMemoryPB + // + this.labelMemoryPB.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelMemoryPB.AutoSize = true; + this.labelMemoryPB.Location = new System.Drawing.Point(153, 3); + this.labelMemoryPB.Name = "labelMemoryPB"; + this.labelMemoryPB.Size = new System.Drawing.Size(33, 13); + this.labelMemoryPB.TabIndex = 1; + this.labelMemoryPB.Text = "value"; + // + // labelMemoryWS + // + this.labelMemoryWS.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelMemoryWS.AutoSize = true; + this.labelMemoryWS.Location = new System.Drawing.Point(153, 22); + this.labelMemoryWS.Name = "labelMemoryWS"; + this.labelMemoryWS.Size = new System.Drawing.Size(33, 13); + this.labelMemoryWS.TabIndex = 1; + this.labelMemoryWS.Text = "value"; + // + // labelMemoryPWS + // + this.labelMemoryPWS.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelMemoryPWS.AutoSize = true; + this.labelMemoryPWS.Location = new System.Drawing.Point(153, 41); + this.labelMemoryPWS.Name = "labelMemoryPWS"; + this.labelMemoryPWS.Size = new System.Drawing.Size(33, 13); + this.labelMemoryPWS.TabIndex = 1; + this.labelMemoryPWS.Text = "value"; + // + // labelMemoryVS + // + this.labelMemoryVS.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelMemoryVS.AutoSize = true; + this.labelMemoryVS.Location = new System.Drawing.Point(153, 60); + this.labelMemoryVS.Name = "labelMemoryVS"; + this.labelMemoryVS.Size = new System.Drawing.Size(33, 13); + this.labelMemoryVS.TabIndex = 1; + this.labelMemoryVS.Text = "value"; + // + // labelMemoryPVS + // + this.labelMemoryPVS.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelMemoryPVS.AutoSize = true; + this.labelMemoryPVS.Location = new System.Drawing.Point(153, 79); + this.labelMemoryPVS.Name = "labelMemoryPVS"; + this.labelMemoryPVS.Size = new System.Drawing.Size(33, 13); + this.labelMemoryPVS.TabIndex = 1; + this.labelMemoryPVS.Text = "value"; + // + // labelMemoryPU + // + this.labelMemoryPU.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelMemoryPU.AutoSize = true; + this.labelMemoryPU.Location = new System.Drawing.Point(153, 98); + this.labelMemoryPU.Name = "labelMemoryPU"; + this.labelMemoryPU.Size = new System.Drawing.Size(33, 13); + this.labelMemoryPU.TabIndex = 1; + this.labelMemoryPU.Text = "value"; + // + // labelMemoryPPU + // + this.labelMemoryPPU.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelMemoryPPU.AutoSize = true; + this.labelMemoryPPU.Location = new System.Drawing.Point(153, 117); + this.labelMemoryPPU.Name = "labelMemoryPPU"; + this.labelMemoryPPU.Size = new System.Drawing.Size(33, 13); + this.labelMemoryPPU.TabIndex = 1; + this.labelMemoryPPU.Text = "value"; + // + // label25 + // + this.label25.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label25.AutoSize = true; + this.label25.Location = new System.Drawing.Point(3, 136); + this.label25.Name = "label25"; + this.label25.Size = new System.Drawing.Size(63, 13); + this.label25.TabIndex = 7; + this.label25.Text = "Page Faults"; + // + // labelMemoryPF + // + this.labelMemoryPF.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelMemoryPF.AutoSize = true; + this.labelMemoryPF.Location = new System.Drawing.Point(153, 136); + this.labelMemoryPF.Name = "labelMemoryPF"; + this.labelMemoryPF.Size = new System.Drawing.Size(33, 13); + this.labelMemoryPF.TabIndex = 1; + this.labelMemoryPF.Text = "value"; + // + // label30 + // + this.label30.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label30.AutoSize = true; + this.label30.Location = new System.Drawing.Point(3, 157); + this.label30.Name = "label30"; + this.label30.Size = new System.Drawing.Size(66, 13); + this.label30.TabIndex = 7; + this.label30.Text = "Page Priority"; + // + // labelMemoryPP + // + this.labelMemoryPP.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelMemoryPP.AutoSize = true; + this.labelMemoryPP.Location = new System.Drawing.Point(153, 157); + this.labelMemoryPP.Name = "labelMemoryPP"; + this.labelMemoryPP.Size = new System.Drawing.Size(33, 13); + this.labelMemoryPP.TabIndex = 1; + this.labelMemoryPP.Text = "value"; + // + // groupBox5 + // + this.groupBox5.Controls.Add(this.tableLayoutPanel3); + this.groupBox5.Location = new System.Drawing.Point(204, 3); + this.groupBox5.Name = "groupBox5"; + this.groupBox5.Size = new System.Drawing.Size(195, 148); + this.groupBox5.TabIndex = 0; + this.groupBox5.TabStop = false; + this.groupBox5.Text = "I/O"; + // + // tableLayoutPanel3 + // + this.tableLayoutPanel3.ColumnCount = 2; + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel3.Controls.Add(this.label16, 0, 5); + this.tableLayoutPanel3.Controls.Add(this.label17, 0, 4); + this.tableLayoutPanel3.Controls.Add(this.label18, 0, 0); + this.tableLayoutPanel3.Controls.Add(this.label19, 0, 1); + this.tableLayoutPanel3.Controls.Add(this.label21, 0, 2); + this.tableLayoutPanel3.Controls.Add(this.label23, 0, 3); + this.tableLayoutPanel3.Controls.Add(this.labelIOReads, 1, 0); + this.tableLayoutPanel3.Controls.Add(this.labelIOReadBytes, 1, 1); + this.tableLayoutPanel3.Controls.Add(this.labelIOWrites, 1, 2); + this.tableLayoutPanel3.Controls.Add(this.labelIOWriteBytes, 1, 3); + this.tableLayoutPanel3.Controls.Add(this.labelIOOther, 1, 4); + this.tableLayoutPanel3.Controls.Add(this.labelIOOtherBytes, 1, 5); + this.tableLayoutPanel3.Controls.Add(this.label31, 0, 6); + this.tableLayoutPanel3.Controls.Add(this.labelIOPriority, 1, 6); + this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel3.Location = new System.Drawing.Point(3, 16); + this.tableLayoutPanel3.Name = "tableLayoutPanel3"; + this.tableLayoutPanel3.RowCount = 7; + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 14.28571F)); + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 14.28571F)); + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 14.28571F)); + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 14.28571F)); + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 14.28571F)); + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 14.28571F)); + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 14.28571F)); + this.tableLayoutPanel3.Size = new System.Drawing.Size(189, 129); + this.tableLayoutPanel3.TabIndex = 1; + // + // label16 + // + this.label16.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label16.AutoSize = true; + this.label16.Location = new System.Drawing.Point(3, 92); + this.label16.Name = "label16"; + this.label16.Size = new System.Drawing.Size(62, 13); + this.label16.TabIndex = 5; + this.label16.Text = "Other Bytes"; + // + // label17 + // + this.label17.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label17.AutoSize = true; + this.label17.Location = new System.Drawing.Point(3, 74); + this.label17.Name = "label17"; + this.label17.Size = new System.Drawing.Size(33, 13); + this.label17.TabIndex = 3; + this.label17.Text = "Other"; + // + // label18 + // + this.label18.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label18.AutoSize = true; + this.label18.Location = new System.Drawing.Point(3, 2); + this.label18.Name = "label18"; + this.label18.Size = new System.Drawing.Size(38, 13); + this.label18.TabIndex = 1; + this.label18.Text = "Reads"; + // + // label19 + // + this.label19.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label19.AutoSize = true; + this.label19.Location = new System.Drawing.Point(3, 20); + this.label19.Name = "label19"; + this.label19.Size = new System.Drawing.Size(62, 13); + this.label19.TabIndex = 1; + this.label19.Text = "Read Bytes"; + // + // label21 + // + this.label21.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label21.AutoSize = true; + this.label21.Location = new System.Drawing.Point(3, 38); + this.label21.Name = "label21"; + this.label21.Size = new System.Drawing.Size(37, 13); + this.label21.TabIndex = 1; + this.label21.Text = "Writes"; + // + // label23 + // + this.label23.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label23.AutoSize = true; + this.label23.Location = new System.Drawing.Point(3, 56); + this.label23.Name = "label23"; + this.label23.Size = new System.Drawing.Size(61, 13); + this.label23.TabIndex = 1; + this.label23.Text = "Write Bytes"; + // + // labelIOReads + // + this.labelIOReads.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelIOReads.AutoSize = true; + this.labelIOReads.Location = new System.Drawing.Point(153, 2); + this.labelIOReads.Name = "labelIOReads"; + this.labelIOReads.Size = new System.Drawing.Size(33, 13); + this.labelIOReads.TabIndex = 1; + this.labelIOReads.Text = "value"; + // + // labelIOReadBytes + // + this.labelIOReadBytes.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelIOReadBytes.AutoSize = true; + this.labelIOReadBytes.Location = new System.Drawing.Point(153, 20); + this.labelIOReadBytes.Name = "labelIOReadBytes"; + this.labelIOReadBytes.Size = new System.Drawing.Size(33, 13); + this.labelIOReadBytes.TabIndex = 1; + this.labelIOReadBytes.Text = "value"; + // + // labelIOWrites + // + this.labelIOWrites.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelIOWrites.AutoSize = true; + this.labelIOWrites.Location = new System.Drawing.Point(153, 38); + this.labelIOWrites.Name = "labelIOWrites"; + this.labelIOWrites.Size = new System.Drawing.Size(33, 13); + this.labelIOWrites.TabIndex = 1; + this.labelIOWrites.Text = "value"; + // + // labelIOWriteBytes + // + this.labelIOWriteBytes.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelIOWriteBytes.AutoSize = true; + this.labelIOWriteBytes.Location = new System.Drawing.Point(153, 56); + this.labelIOWriteBytes.Name = "labelIOWriteBytes"; + this.labelIOWriteBytes.Size = new System.Drawing.Size(33, 13); + this.labelIOWriteBytes.TabIndex = 1; + this.labelIOWriteBytes.Text = "value"; + // + // labelIOOther + // + this.labelIOOther.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelIOOther.AutoSize = true; + this.labelIOOther.Location = new System.Drawing.Point(153, 74); + this.labelIOOther.Name = "labelIOOther"; + this.labelIOOther.Size = new System.Drawing.Size(33, 13); + this.labelIOOther.TabIndex = 1; + this.labelIOOther.Text = "value"; + // + // labelIOOtherBytes + // + this.labelIOOtherBytes.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelIOOtherBytes.AutoSize = true; + this.labelIOOtherBytes.Location = new System.Drawing.Point(153, 92); + this.labelIOOtherBytes.Name = "labelIOOtherBytes"; + this.labelIOOtherBytes.Size = new System.Drawing.Size(33, 13); + this.labelIOOtherBytes.TabIndex = 1; + this.labelIOOtherBytes.Text = "value"; + // + // label31 + // + this.label31.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label31.AutoSize = true; + this.label31.Location = new System.Drawing.Point(3, 112); + this.label31.Name = "label31"; + this.label31.Size = new System.Drawing.Size(57, 13); + this.label31.TabIndex = 5; + this.label31.Text = "I/O Priority"; + // + // labelIOPriority + // + this.labelIOPriority.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelIOPriority.AutoSize = true; + this.labelIOPriority.Location = new System.Drawing.Point(153, 112); + this.labelIOPriority.Name = "labelIOPriority"; + this.labelIOPriority.Size = new System.Drawing.Size(33, 13); + this.labelIOPriority.TabIndex = 1; + this.labelIOPriority.Text = "value"; + // + // groupBox6 + // + this.groupBox6.Controls.Add(this.tableLayoutPanel4); + this.groupBox6.Location = new System.Drawing.Point(204, 157); + this.groupBox6.Name = "groupBox6"; + this.groupBox6.Size = new System.Drawing.Size(195, 99); + this.groupBox6.TabIndex = 0; + this.groupBox6.TabStop = false; + this.groupBox6.Text = "Other"; + // + // tableLayoutPanel4 + // + this.tableLayoutPanel4.ColumnCount = 2; + this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel4.Controls.Add(this.label27, 0, 0); + this.tableLayoutPanel4.Controls.Add(this.labelOtherHandles, 1, 0); + this.tableLayoutPanel4.Controls.Add(this.label28, 0, 1); + this.tableLayoutPanel4.Controls.Add(this.label29, 0, 2); + this.tableLayoutPanel4.Controls.Add(this.labelOtherGDIHandles, 1, 1); + this.tableLayoutPanel4.Controls.Add(this.labelOtherUSERHandles, 1, 2); + this.tableLayoutPanel4.Controls.Add(this.buttonHandleDetails, 1, 3); + this.tableLayoutPanel4.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel4.Location = new System.Drawing.Point(3, 16); + this.tableLayoutPanel4.Name = "tableLayoutPanel4"; + this.tableLayoutPanel4.RowCount = 4; + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33334F)); + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33334F)); + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 27F)); + this.tableLayoutPanel4.Size = new System.Drawing.Size(189, 80); + this.tableLayoutPanel4.TabIndex = 1; + // + // label27 + // + this.label27.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label27.AutoSize = true; + this.label27.Location = new System.Drawing.Point(3, 2); + this.label27.Name = "label27"; + this.label27.Size = new System.Drawing.Size(46, 13); + this.label27.TabIndex = 1; + this.label27.Text = "Handles"; + // + // labelOtherHandles + // + this.labelOtherHandles.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelOtherHandles.AutoSize = true; + this.labelOtherHandles.Location = new System.Drawing.Point(153, 2); + this.labelOtherHandles.Name = "labelOtherHandles"; + this.labelOtherHandles.Size = new System.Drawing.Size(33, 13); + this.labelOtherHandles.TabIndex = 1; + this.labelOtherHandles.Text = "value"; + // + // label28 + // + this.label28.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label28.AutoSize = true; + this.label28.Location = new System.Drawing.Point(3, 19); + this.label28.Name = "label28"; + this.label28.Size = new System.Drawing.Size(68, 13); + this.label28.TabIndex = 1; + this.label28.Text = "GDI Handles"; + // + // label29 + // + this.label29.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label29.AutoSize = true; + this.label29.Location = new System.Drawing.Point(3, 36); + this.label29.Name = "label29"; + this.label29.Size = new System.Drawing.Size(79, 13); + this.label29.TabIndex = 1; + this.label29.Text = "USER Handles"; + // + // labelOtherGDIHandles + // + this.labelOtherGDIHandles.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelOtherGDIHandles.AutoSize = true; + this.labelOtherGDIHandles.Location = new System.Drawing.Point(153, 19); + this.labelOtherGDIHandles.Name = "labelOtherGDIHandles"; + this.labelOtherGDIHandles.Size = new System.Drawing.Size(33, 13); + this.labelOtherGDIHandles.TabIndex = 1; + this.labelOtherGDIHandles.Text = "value"; + // + // labelOtherUSERHandles + // + this.labelOtherUSERHandles.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelOtherUSERHandles.AutoSize = true; + this.labelOtherUSERHandles.Location = new System.Drawing.Point(153, 36); + this.labelOtherUSERHandles.Name = "labelOtherUSERHandles"; + this.labelOtherUSERHandles.Size = new System.Drawing.Size(33, 13); + this.labelOtherUSERHandles.TabIndex = 1; + this.labelOtherUSERHandles.Text = "value"; + // + // buttonHandleDetails + // + this.buttonHandleDetails.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.buttonHandleDetails.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonHandleDetails.Location = new System.Drawing.Point(112, 54); + this.buttonHandleDetails.Name = "buttonHandleDetails"; + this.buttonHandleDetails.Size = new System.Drawing.Size(74, 23); + this.buttonHandleDetails.TabIndex = 2; + this.buttonHandleDetails.Text = "Details..."; + this.buttonHandleDetails.UseVisualStyleBackColor = true; + this.buttonHandleDetails.Click += new System.EventHandler(this.buttonHandleDetails_Click); + // + // ProcessStatistics + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.flowStats); + this.Name = "ProcessStatistics"; + this.Size = new System.Drawing.Size(433, 374); + this.flowStats.ResumeLayout(false); + this.groupBox1.ResumeLayout(false); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.groupBox4.ResumeLayout(false); + this.tableLayoutPanel2.ResumeLayout(false); + this.tableLayoutPanel2.PerformLayout(); + this.groupBox5.ResumeLayout(false); + this.tableLayoutPanel3.ResumeLayout(false); + this.tableLayoutPanel3.PerformLayout(); + this.groupBox6.ResumeLayout(false); + this.tableLayoutPanel4.ResumeLayout(false); + this.tableLayoutPanel4.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.FlowLayoutPanel flowStats; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.Label label8; + private System.Windows.Forms.Label label9; + private System.Windows.Forms.Label label10; + private System.Windows.Forms.Label labelCPUPriority; + private System.Windows.Forms.Label labelCPUKernelTime; + private System.Windows.Forms.Label labelCPUUserTime; + private System.Windows.Forms.Label labelCPUTotalTime; + private System.Windows.Forms.Label labelCPUCyclesText; + private System.Windows.Forms.Label labelCPUCycles; + private System.Windows.Forms.GroupBox groupBox4; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; + private System.Windows.Forms.Label label24; + private System.Windows.Forms.Label label22; + private System.Windows.Forms.Label label20; + private System.Windows.Forms.Label label11; + private System.Windows.Forms.Label label12; + private System.Windows.Forms.Label label13; + private System.Windows.Forms.Label label14; + private System.Windows.Forms.Label labelMemoryPB; + private System.Windows.Forms.Label labelMemoryWS; + private System.Windows.Forms.Label labelMemoryPWS; + private System.Windows.Forms.Label labelMemoryVS; + private System.Windows.Forms.Label labelMemoryPVS; + private System.Windows.Forms.Label labelMemoryPU; + private System.Windows.Forms.Label labelMemoryPPU; + private System.Windows.Forms.Label label25; + private System.Windows.Forms.Label labelMemoryPF; + private System.Windows.Forms.Label label30; + private System.Windows.Forms.Label labelMemoryPP; + private System.Windows.Forms.GroupBox groupBox5; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3; + private System.Windows.Forms.Label label16; + private System.Windows.Forms.Label label17; + private System.Windows.Forms.Label label18; + private System.Windows.Forms.Label label19; + private System.Windows.Forms.Label label21; + private System.Windows.Forms.Label label23; + private System.Windows.Forms.Label labelIOReads; + private System.Windows.Forms.Label labelIOReadBytes; + private System.Windows.Forms.Label labelIOWrites; + private System.Windows.Forms.Label labelIOWriteBytes; + private System.Windows.Forms.Label labelIOOther; + private System.Windows.Forms.Label labelIOOtherBytes; + private System.Windows.Forms.Label label31; + private System.Windows.Forms.Label labelIOPriority; + private System.Windows.Forms.GroupBox groupBox6; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel4; + private System.Windows.Forms.Label label27; + private System.Windows.Forms.Label labelOtherHandles; + private System.Windows.Forms.Label label28; + private System.Windows.Forms.Label label29; + private System.Windows.Forms.Label labelOtherGDIHandles; + private System.Windows.Forms.Label labelOtherUSERHandles; + private System.Windows.Forms.Button buttonHandleDetails; + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/ProcessStatistics.cs b/branches/ph-plugins/ProcessHacker/Components/ProcessStatistics.cs new file mode 100644 index 000000000..10632d2d4 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/ProcessStatistics.cs @@ -0,0 +1,170 @@ +/* + * Process Hacker - + * process statistics control + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Native; +using ProcessHacker.Native.Objects; + +namespace ProcessHacker.Components +{ + public partial class ProcessStatistics : UserControl + { + private int _pid; + + public ProcessStatistics(int pid) + { + InitializeComponent(); + + _pid = pid; + + if (OSVersion.HasCycleTime) + { + labelCPUCyclesText.Text = "Cycles"; + } + else + { + labelCPUCyclesText.Text = "N/A"; + } + + _dontCalculate = false; + } + + private bool _dontCalculate = true; + + protected override void OnResize(EventArgs e) + { + if (_dontCalculate) + return; + + base.OnResize(e); + } + + public void ClearStatistics() + { + labelCPUPriority.Text = ""; + labelCPUCycles.Text = ""; + labelCPUKernelTime.Text = ""; + labelCPUUserTime.Text = ""; + labelCPUTotalTime.Text = ""; + + labelMemoryPB.Text = ""; + labelMemoryWS.Text = ""; + labelMemoryPWS.Text = ""; + labelMemoryVS.Text = ""; + labelMemoryPVS.Text = ""; + labelMemoryPU.Text = ""; + labelMemoryPPU.Text = ""; + labelMemoryPF.Text = ""; + labelMemoryPP.Text = ""; + + labelIOReads.Text = ""; + labelIOReadBytes.Text = ""; + labelIOWrites.Text = ""; + labelIOWriteBytes.Text = ""; + labelIOOther.Text = ""; + labelIOOtherBytes.Text = ""; + labelIOPriority.Text = ""; + + labelOtherHandles.Text = ""; + labelOtherGDIHandles.Text = ""; + labelOtherUSERHandles.Text = ""; + } + + public void UpdateStatistics() + { + if (!Program.ProcessProvider.Dictionary.ContainsKey(_pid)) + return; + + ProcessItem item = Program.ProcessProvider.Dictionary[_pid]; + + labelCPUPriority.Text = item.Process.BasePriority.ToString(); + labelCPUKernelTime.Text = Utils.FormatTimeSpan(new TimeSpan(item.Process.KernelTime)); + labelCPUUserTime.Text = Utils.FormatTimeSpan(new TimeSpan(item.Process.UserTime)); + labelCPUTotalTime.Text = Utils.FormatTimeSpan(new TimeSpan(item.Process.KernelTime + item.Process.UserTime)); + + labelMemoryPB.Text = Utils.FormatSize(item.Process.VirtualMemoryCounters.PrivatePageCount); + labelMemoryWS.Text = Utils.FormatSize(item.Process.VirtualMemoryCounters.WorkingSetSize); + labelMemoryPWS.Text = Utils.FormatSize(item.Process.VirtualMemoryCounters.PeakWorkingSetSize); + labelMemoryVS.Text = Utils.FormatSize(item.Process.VirtualMemoryCounters.VirtualSize); + labelMemoryPVS.Text = Utils.FormatSize(item.Process.VirtualMemoryCounters.PeakVirtualSize); + labelMemoryPU.Text = Utils.FormatSize(item.Process.VirtualMemoryCounters.PagefileUsage); + labelMemoryPPU.Text = Utils.FormatSize(item.Process.VirtualMemoryCounters.PeakPagefileUsage); + labelMemoryPF.Text = ((ulong)item.Process.VirtualMemoryCounters.PageFaultCount).ToString("N0"); + + labelIOReads.Text = ((ulong)item.Process.IoCounters.ReadOperationCount).ToString("N0"); + labelIOReadBytes.Text = Utils.FormatSize(item.Process.IoCounters.ReadTransferCount); + labelIOWrites.Text = ((ulong)item.Process.IoCounters.WriteOperationCount).ToString("N0"); + labelIOWriteBytes.Text = Utils.FormatSize(item.Process.IoCounters.WriteTransferCount); + labelIOOther.Text = ((ulong)item.Process.IoCounters.OtherOperationCount).ToString("N0"); + labelIOOtherBytes.Text = Utils.FormatSize(item.Process.IoCounters.OtherTransferCount); + + labelOtherHandles.Text = ((ulong)item.Process.HandleCount).ToString("N0"); + + if (_pid > 0) + { + try + { + using (var phandle = new ProcessHandle(_pid, Program.MinProcessQueryRights)) + { + labelOtherGDIHandles.Text = phandle.GetGuiResources(false).ToString("N0"); + labelOtherUSERHandles.Text = phandle.GetGuiResources(true).ToString("N0"); + + if (OSVersion.HasCycleTime) + labelCPUCycles.Text = phandle.GetCycleTime().ToString("N0"); + else + labelCPUCycles.Text = "N/A"; + + if (OSVersion.IsAboveOrEqual(WindowsVersion.Vista)) + { + labelMemoryPP.Text = phandle.GetPagePriority().ToString(); + labelIOPriority.Text = phandle.GetIoPriority().ToString(); + } + } + } + catch + { } + } + else + { + labelOtherGDIHandles.Text = "0"; + labelOtherUSERHandles.Text = "0"; + labelCPUCycles.Text = "0"; + labelMemoryPP.Text = "0"; + labelIOPriority.Text = "0"; + } + } + + private void buttonHandleDetails_Click(object sender, EventArgs e) + { + try + { + (new HandleStatisticsWindow(_pid)).ShowDialog(); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to show handle statistics", ex); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/ProcessStatistics.resx b/branches/ph-plugins/ProcessHacker/Components/ProcessStatistics.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/ProcessStatistics.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/ProcessTree/ProcessNode.cs b/branches/ph-plugins/ProcessHacker/Components/ProcessTree/ProcessNode.cs new file mode 100644 index 000000000..8735447ef --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/ProcessTree/ProcessNode.cs @@ -0,0 +1,699 @@ +/* + * Process Hacker - + * Node implementation for the process tree + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using Aga.Controls.Tree; +using ProcessHacker.Common; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker +{ + public class ProcessNode : Node, IDisposable + { + private ProcessNode _parent = null; + private List _children = new List(); + private TreePath _treePath = null; + + private ProcessItem _pitem; + private bool _wasNoIcon = false; + private Bitmap _icon; + + private string _tooltipText; + private int _lastTooltipTickCount = 0; + + public ProcessNode(ProcessItem pitem) + { + _pitem = pitem; + this.Tag = pitem.Pid; + + if (_pitem.Icon == null) + { + _wasNoIcon = true; + _icon = global::ProcessHacker.Properties.Resources.Process_small.ToBitmap(); + } + else + { + try + { + _icon = _pitem.Icon.ToBitmap(); + } + catch + { + _wasNoIcon = true; + _icon = global::ProcessHacker.Properties.Resources.Process_small.ToBitmap(); + } + } + } + + ~ProcessNode() + { + if (_icon != null) + this.Dispose(); + } + + public void Dispose() + { + if (_icon != null) + { + _icon.Dispose(); + _icon = null; + } + } + + public ProcessItem ProcessItem + { + get { return _pitem; } + set + { + _pitem = value; + + if (_wasNoIcon && _pitem.Icon != null) + { + if (_icon != null) + _icon.Dispose(); + + _icon = new Bitmap(16, 16); + + try + { + using (Graphics g = Graphics.FromImage(_icon)) + g.DrawIcon(_pitem.Icon, new Rectangle(0, 0, 16, 16)); + + _wasNoIcon = false; + } + catch + { + _icon.Dispose(); + _icon = null; + } + } + } + } + + public new ProcessNode Parent + { + get { return _parent; } + set { _parent = value; } + } + + public List Children + { + get { return _children; } + } + + public TreePath TreePath + { + get { return _treePath; } + } + + public string GetTooltipText(ProcessToolTipProvider provider) + { + int tickCount = Environment.TickCount; + + if (tickCount - _lastTooltipTickCount >= Settings.RefreshInterval) + { + _tooltipText = provider.GetToolTip(this); + _lastTooltipTickCount = tickCount; + } + + return _tooltipText; + } + + public TreePath RefreshTreePath() + { + ProcessNode currentNode = this; + Stack stack = new Stack(); + + while (currentNode != null) + { + stack.Push(currentNode); + currentNode = currentNode.Parent; + } + + _treePath = new TreePath(stack.ToArray()); + + return _treePath; + } + + public void RefreshTreePathRecursive() + { + foreach (var child in _children) + child.RefreshTreePathRecursive(); + + this.RefreshTreePath(); + } + + public ProcessHacker.Components.NodePlotter.PlotterInfo CpuHistory + { + get + { + return new ProcessHacker.Components.NodePlotter.PlotterInfo() + { + UseSecondLine = true, + OverlaySecondLine = false, + UseLongData = false, + Data1 = _pitem.FloatHistoryManager[ProcessStats.CpuKernel], + Data2 = _pitem.FloatHistoryManager[ProcessStats.CpuUser], + LineColor1 = Properties.Settings.Default.PlotterCPUKernelColor, + LineColor2 = Properties.Settings.Default.PlotterCPUUserColor + }; + } + } + + public ProcessHacker.Components.NodePlotter.PlotterInfo IoHistory + { + get + { + return new ProcessHacker.Components.NodePlotter.PlotterInfo() + { + UseSecondLine = true, + OverlaySecondLine = true, + UseLongData = true, + LongData1 = _pitem.LongHistoryManager[ProcessStats.IoReadOther], + LongData2 = _pitem.LongHistoryManager[ProcessStats.IoWrite], + LineColor1 = Properties.Settings.Default.PlotterIOROColor, + LineColor2 = Properties.Settings.Default.PlotterIOWColor + }; + } + } + + public string Name + { + get { return _pitem.Name ?? ""; } + } + + public string DisplayPid + { + get + { + if (_pitem.Pid >= 0) + return _pitem.Pid.ToString(); + else + return ""; + } + } + + public int Pid + { + get { return _pitem.Pid; } + } + + public int PPid + { + get { if (_pitem.Pid == _pitem.ParentPid) return -1; else return _pitem.ParentPid; } + } + + public string PvtMemory + { + get { return Utils.FormatSize(_pitem.Process.VirtualMemoryCounters.PrivatePageCount); } + } + + public string WorkingSet + { + get + { + return Utils.FormatSize(_pitem.Process.VirtualMemoryCounters.WorkingSetSize); + } + } + + public string PeakWorkingSet + { + get { return Utils.FormatSize(_pitem.Process.VirtualMemoryCounters.PeakWorkingSetSize); } + } + + private int GetWorkingSetNumber(NProcessHacker.WsInformationClass WsInformationClass) + { + NtStatus status; + int wsInfo; + int retLen; + + try + { + using (var phandle = new ProcessHandle(_pitem.Pid, + ProcessAccess.QueryInformation | ProcessAccess.VmRead)) + { + if ((status = NProcessHacker.PhQueryProcessWs(phandle, WsInformationClass, out wsInfo, + 4, out retLen)) < NtStatus.Error) + return wsInfo * Program.ProcessProvider.System.PageSize; + } + } + catch + { } + + return 0; + } + + public int WorkingSetNumber + { + get { return this.GetWorkingSetNumber(NProcessHacker.WsInformationClass.WsCount); } + } + + public int PrivateWorkingSetNumber + { + get { return this.GetWorkingSetNumber(NProcessHacker.WsInformationClass.WsPrivateCount); } + } + + public string PrivateWorkingSet + { + get { return Utils.FormatSize(this.PrivateWorkingSetNumber); } + } + + public int SharedWorkingSetNumber + { + get { return this.GetWorkingSetNumber(NProcessHacker.WsInformationClass.WsSharedCount); } + } + + public string SharedWorkingSet + { + get { return Utils.FormatSize(this.SharedWorkingSetNumber); } + } + + public int ShareableWorkingSetNumber + { + get { return this.GetWorkingSetNumber(NProcessHacker.WsInformationClass.WsShareableCount); } + } + + public string ShareableWorkingSet + { + get { return Utils.FormatSize(this.ShareableWorkingSetNumber); } + } + + public string VirtualSize + { + get { return Utils.FormatSize(_pitem.Process.VirtualMemoryCounters.VirtualSize); } + } + + public string PeakVirtualSize + { + get { return Utils.FormatSize(_pitem.Process.VirtualMemoryCounters.PeakVirtualSize); } + } + + public string PagefileUsage + { + get { return Utils.FormatSize(_pitem.Process.VirtualMemoryCounters.PagefileUsage); } + } + + public string PeakPagefileUsage + { + get { return Utils.FormatSize(_pitem.Process.VirtualMemoryCounters.PeakPagefileUsage); } + } + + public string PageFaults + { + get { return _pitem.Process.VirtualMemoryCounters.PageFaultCount.ToString("N0"); } + } + + public string Cpu + { + get + { + if (_pitem.CpuUsage == 0) + return ""; + else + return _pitem.CpuUsage.ToString("F2"); + } + } + + private string GetBestUsername(string username, bool includeDomain) + { + if (username == null) + return ""; + + if (!username.Contains("\\")) + return username; + + string[] split = username.Split(new char[] { '\\' }, 2); + string domain = split[0]; + string user = split[1]; + + if (includeDomain) + return domain + "\\" + user; + else + return user; + } + + public string Username + { + get { return this.GetBestUsername(_pitem.Username, Settings.ShowAccountDomains); } + } + + public string SessionId + { + get + { + if (Pid < 4) + return ""; + else + return _pitem.SessionId.ToString(); + } + } + + public string PriorityClass + { + get + { + try + { + using (var phandle = new ProcessHandle(Pid, Program.MinProcessQueryRights)) + return PhUtils.FormatPriorityClass(phandle.GetPriorityClass()); + } + catch + { + return ""; + } + } + } + + public string BasePriority + { + get + { + if (Pid < 4) + return ""; + else + return _pitem.Process.BasePriority.ToString(); + } + } + + public string Description + { + get + { + if (Pid == 0) + return "System Idle Process"; + else if (Pid == -2) + return "Deferred Procedure Calls"; + else if (Pid == -3) + return "Interrupts"; + else if (_pitem.VersionInfo != null && _pitem.VersionInfo.FileDescription != null) + return _pitem.VersionInfo.FileDescription; + else + return ""; + } + } + + public string Company + { + get + { + if (_pitem.VersionInfo != null && _pitem.VersionInfo.CompanyName != null) + return _pitem.VersionInfo.CompanyName; + else + return ""; + } + } + + public string FileName + { + get + { + if (_pitem.FileName == null) + return ""; + else + return _pitem.FileName; + } + } + + public string CommandLine + { + get + { + if (_pitem.CmdLine == null) + return ""; + else + return _pitem.CmdLine.Replace("\0", ""); + } + } + + public string Threads + { + get + { + if (Pid < 4) + return ""; + else + return _pitem.Process.NumberOfThreads.ToString(); + } + } + + public string Handles + { + get + { + if (Pid < 4) + return ""; + else + return _pitem.Process.HandleCount.ToString(); + } + } + + public int GdiHandlesNumber + { + get + { + try + { + using (var phandle = new ProcessHandle(Pid, ProcessAccess.QueryInformation)) + return phandle.GetGuiResources(false); + } + catch + { + return 0; + } + } + } + + public string GdiHandles + { + get + { + if (Pid < 4) + return ""; + else + { + int number = this.GdiHandlesNumber; + + if (number == 0) + return ""; + else + return number.ToString(); + } + } + } + + public int UserHandlesNumber + { + get + { + try + { + using (var phandle = new ProcessHandle(Pid, ProcessAccess.QueryInformation)) + return phandle.GetGuiResources(true); + } + catch + { + return 0; + } + } + } + + public string UserHandles + { + get + { + if (Pid < 4) + return ""; + else + { + int number = this.UserHandlesNumber; + + if (number == 0) + return ""; + else + return number.ToString(); + } + } + } + + public long IoTotalNumber + { + get + { + if (_pitem.LongHistoryManager[ProcessStats.IoReadOther].Count == 0) + return 0; + else + return (_pitem.LongHistoryManager[ProcessStats.IoReadOther][0] + + _pitem.LongHistoryManager[ProcessStats.IoWrite][0]) * 1000 / + Settings.RefreshInterval; + } + } + + public string IoTotal + { + get + { + if (this.IoTotalNumber == 0) + return ""; + else + return Utils.FormatSize(this.IoTotalNumber) + "/s"; + } + } + + public long IoReadOtherNumber + { + get + { + if (_pitem.LongHistoryManager[ProcessStats.IoReadOther].Count == 0) + return 0; + else + return _pitem.LongHistoryManager[ProcessStats.IoReadOther][0] * 1000 / + Settings.RefreshInterval; + } + } + + public string IoReadOther + { + get + { + if (this.IoReadOtherNumber == 0) + return ""; + else + return Utils.FormatSize(this.IoReadOtherNumber) + "/s"; + } + } + + public long IoWriteNumber + { + get + { + if (_pitem.LongHistoryManager[ProcessStats.IoReadOther].Count == 0) + return 0; + else + return _pitem.LongHistoryManager[ProcessStats.IoWrite][0] * 1000 / + Settings.RefreshInterval; + } + } + + public string IoWrite + { + get + { + if (this.IoWriteNumber == 0) + return ""; + else + return Utils.FormatSize(this.IoWriteNumber) + "/s"; + } + } + + public string Integrity + { + get { return _pitem.Integrity; } + } + + public int IntegrityLevel + { + get { return _pitem.IntegrityLevel; } + } + + public int IoPriority + { + get + { + try + { + return _pitem.ProcessQueryHandle.GetIoPriority(); + } + catch + { + return 0; + } + } + } + + public int PagePriority + { + get + { + try + { + return _pitem.ProcessQueryHandle.GetPagePriority(); + } + catch + { + return 0; + } + } + } + + public Bitmap Icon + { + get { return _icon; } + } + + public string StartTime + { + get + { + if (Pid < 4 || _pitem.CreateTime.Year == 1) + return ""; + else + return _pitem.CreateTime.ToString(); + } + } + + public string RelativeStartTime + { + get + { + if (Pid < 4 || _pitem.CreateTime.Year == 1) + return ""; + else + return Utils.FormatRelativeDateTime(_pitem.CreateTime); + } + } + + public string TotalCpuTime + { + get { return Utils.FormatTimeSpan(new TimeSpan(_pitem.Process.KernelTime + _pitem.Process.UserTime)); } + } + + public string KernelCpuTime + { + get { return Utils.FormatTimeSpan(new TimeSpan(_pitem.Process.KernelTime)); } + } + + public string UserCpuTime + { + get { return Utils.FormatTimeSpan(new TimeSpan(_pitem.Process.UserTime)); } + } + + public string VerificationStatus + { + get { return _pitem.VerifyResult == VerifyResult.Trusted ? "Verified" : ""; } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/ProcessTree/ProcessToolTipProvider.cs b/branches/ph-plugins/ProcessHacker/Components/ProcessTree/ProcessToolTipProvider.cs new file mode 100644 index 000000000..ee8cf488d --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/ProcessTree/ProcessToolTipProvider.cs @@ -0,0 +1,234 @@ +/* + * Process Hacker - + * IToolTipProvider implementation for the process tree + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Diagnostics; +using Aga.Controls.Tree; +using ProcessHacker.Common; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; + +namespace ProcessHacker +{ + public class ProcessToolTipProvider : IToolTipProvider + { + private ProcessTree _tree; + + public ProcessToolTipProvider(ProcessTree owner) + { + _tree = owner; + } + + public string GetToolTip(TreeNodeAdv node, Aga.Controls.Tree.NodeControls.NodeControl nodeControl) + { + var pNode = _tree.FindNode(node); + + // Use the process node's tooltip mechanism to allow caching. + if (pNode != null) + return pNode.GetTooltipText(this); + else + return ""; + } + + public string GetToolTip(ProcessNode pNode) + { + try + { + string cmdText = (pNode.ProcessItem.CmdLine != null ? + (Utils.CreateEllipsis(pNode.ProcessItem.CmdLine.Replace("\0", ""), 100) + "\n") : ""); + + string fileText = ""; + + try + { + string filename = ""; + + if (pNode.Pid == 4) + { + filename = FileUtils.GetFileName(Windows.KernelFileName); + } + else + { + filename = pNode.ProcessItem.FileName; + } + + FileVersionInfo info = FileVersionInfo.GetVersionInfo(filename); + + fileText = "File:\n " + info.FileName + "\n " + + info.FileDescription + " " + info.FileVersion + "\n " + + info.CompanyName; + } + catch + { + if (pNode.ProcessItem.FileName != null) + fileText = "File:\n " + pNode.ProcessItem.FileName; + } + + string runDllText = ""; + + if (pNode.ProcessItem.FileName != null && + pNode.ProcessItem.FileName.Equals(Environment.SystemDirectory + "\\rundll32.exe", + StringComparison.InvariantCultureIgnoreCase) && + pNode.ProcessItem.CmdLine != null) + { + try + { + // TODO: fix crappy method + string targetFile = pNode.ProcessItem.CmdLine.Split(new char[] { ' ' }, 2)[1].Split(',')[0]; + + // if it doesn't specify an absolute path, assume it's in system32. + if (!targetFile.Contains(":")) + targetFile = Environment.SystemDirectory + "\\" + targetFile; + + FileVersionInfo info = FileVersionInfo.GetVersionInfo(targetFile); + + runDllText = "\nRunDLL target:\n " + info.FileName + "\n " + + info.FileDescription + " " + info.FileVersion + "\n " + + info.CompanyName; + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + + string dllhostText = ""; + + if (pNode.ProcessItem.FileName != null && + pNode.ProcessItem.FileName.Equals(Environment.SystemDirectory + "\\dllhost.exe", + StringComparison.InvariantCultureIgnoreCase) && + pNode.ProcessItem.CmdLine != null) + { + try + { + string clsid = pNode.ProcessItem.CmdLine.ToLowerInvariant().Split( + new string[] { "/processid:" }, StringSplitOptions.None)[1].Split(' ')[0]; + var key = Microsoft.Win32.Registry.ClassesRoot.OpenSubKey("CLSID\\" + clsid); + var inprocServer32 = key.OpenSubKey("InprocServer32"); + string name = key.GetValue("") as string; + string fileName = inprocServer32.GetValue("") as string; + + FileVersionInfo info = FileVersionInfo.GetVersionInfo(Environment.ExpandEnvironmentVariables(fileName)); + + dllhostText = "\nCOM Target:\n " + name + " (" + clsid.ToUpper() + ")\n " + + info.FileName + "\n " + + info.FileDescription + " " + info.FileVersion + "\n " + info.CompanyName; + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + + string servicesText = ""; + + try + { + if (Program.HackerWindow.ProcessServices.ContainsKey(pNode.Pid)) + { + foreach (string service in Program.HackerWindow.ProcessServices[pNode.Pid]) + { + if (Program.ServiceProvider.Dictionary.ContainsKey(service)) + { + if (Program.ServiceProvider.Dictionary[service].Status.DisplayName != "") + servicesText += " " + service + " (" + + Program.ServiceProvider.Dictionary[service].Status.DisplayName + ")\n"; + else + servicesText += " " + service + "\n"; + } + else + { + servicesText += " " + service + "\n"; + } + } + + servicesText = "\nServices:\n" + servicesText.TrimEnd('\n'); + } + } + catch (Exception ex) + { + Logging.Log(ex); + } + + string otherNotes = ""; + + try + { + if (pNode.ProcessItem.IsPacked && pNode.ProcessItem.ImportModules > 0) + otherNotes += "\n Image is probably packed - has " + + pNode.ProcessItem.ImportFunctions.ToString() + " imports over " + + pNode.ProcessItem.ImportModules.ToString() + " modules."; + else if (pNode.ProcessItem.IsPacked) + otherNotes += "\n Image is probably packed - error reading PE file."; + + if (pNode.ProcessItem.FileName != null) + { + if (pNode.ProcessItem.VerifyResult == VerifyResult.Trusted) + otherNotes += "\n Signature present and verified."; + else if (pNode.ProcessItem.VerifyResult == VerifyResult.TrustedInstaller) + otherNotes += "\n Verified Windows component."; + else if (pNode.ProcessItem.VerifyResult == VerifyResult.Unknown && + !Properties.Settings.Default.VerifySignatures) + otherNotes += ""; + else if (pNode.ProcessItem.VerifyResult == VerifyResult.Unknown && + Properties.Settings.Default.VerifySignatures) + otherNotes += "\n File has not been processed yet. Please wait..."; + else if (pNode.ProcessItem.VerifyResult != VerifyResult.NoSignature) + otherNotes += "\n Signature present but invalid."; + + if (Program.ImposterNames.Contains(pNode.Name.ToLower()) && + pNode.ProcessItem.VerifyResult != VerifyResult.Trusted && + pNode.ProcessItem.VerifyResult != VerifyResult.TrustedInstaller && + pNode.ProcessItem.VerifyResult != VerifyResult.Unknown) + otherNotes += "\n Process is using the name of a known process but its signature could not be verified."; + } + + if (pNode.ProcessItem.IsInJob) + otherNotes += "\n Process is in a job."; + if (pNode.ProcessItem.ElevationType == TokenElevationType.Full) + otherNotes += "\n Process is elevated."; + if (pNode.ProcessItem.IsDotNet) + otherNotes += "\n Process is managed (.NET)."; + if (pNode.ProcessItem.IsPosix) + otherNotes += "\n Process is POSIX."; + if (pNode.ProcessItem.IsWow64) + otherNotes += "\n Process is 32-bit (running under WOW64)."; + + if (otherNotes != "") + otherNotes = "\nNotes:" + otherNotes; + } + catch (Exception ex) + { + Logging.Log(ex); + } + + return (cmdText + fileText + otherNotes + runDllText + dllhostText + servicesText).Trim(' ', '\n', '\r'); + } + catch (Exception ex) + { + Logging.Log(ex); + } + + return string.Empty; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/ProcessTree/ProcessTree.Designer.cs b/branches/ph-plugins/ProcessHacker/Components/ProcessTree/ProcessTree.Designer.cs new file mode 100644 index 000000000..2bee85308 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/ProcessTree/ProcessTree.Designer.cs @@ -0,0 +1,1035 @@ +namespace ProcessHacker +{ + partial class ProcessTree + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.treeProcesses = new Aga.Controls.Tree.TreeViewAdv(); + this.columnName = new Aga.Controls.Tree.TreeColumn(); + this.columnPID = new Aga.Controls.Tree.TreeColumn(); + this.columnPvtMemory = new Aga.Controls.Tree.TreeColumn(); + this.columnWorkingSet = new Aga.Controls.Tree.TreeColumn(); + this.columnPeakWorkingSet = new Aga.Controls.Tree.TreeColumn(); + this.columnPrivateWorkingSet = new Aga.Controls.Tree.TreeColumn(); + this.columnSharedWorkingSet = new Aga.Controls.Tree.TreeColumn(); + this.columnShareableWorkingSet = new Aga.Controls.Tree.TreeColumn(); + this.columnVirtualSize = new Aga.Controls.Tree.TreeColumn(); + this.columnPeakVirtualSize = new Aga.Controls.Tree.TreeColumn(); + this.columnPagefileUsage = new Aga.Controls.Tree.TreeColumn(); + this.columnPeakPagefileUsage = new Aga.Controls.Tree.TreeColumn(); + this.columnPageFaults = new Aga.Controls.Tree.TreeColumn(); + this.columnCPU = new Aga.Controls.Tree.TreeColumn(); + this.columnIoTotal = new Aga.Controls.Tree.TreeColumn(); + this.columnUsername = new Aga.Controls.Tree.TreeColumn(); + this.columnSessionId = new Aga.Controls.Tree.TreeColumn(); + this.columnPriorityClass = new Aga.Controls.Tree.TreeColumn(); + this.columnBasePriority = new Aga.Controls.Tree.TreeColumn(); + this.columnDescription = new Aga.Controls.Tree.TreeColumn(); + this.columnCompany = new Aga.Controls.Tree.TreeColumn(); + this.columnFileName = new Aga.Controls.Tree.TreeColumn(); + this.columnCommandLine = new Aga.Controls.Tree.TreeColumn(); + this.columnThreads = new Aga.Controls.Tree.TreeColumn(); + this.columnHandles = new Aga.Controls.Tree.TreeColumn(); + this.columnGdiHandles = new Aga.Controls.Tree.TreeColumn(); + this.columnUserHandles = new Aga.Controls.Tree.TreeColumn(); + this.columnIoReadOther = new Aga.Controls.Tree.TreeColumn(); + this.columnIoWrite = new Aga.Controls.Tree.TreeColumn(); + this.columnIntegrity = new Aga.Controls.Tree.TreeColumn(); + this.columnIoPriority = new Aga.Controls.Tree.TreeColumn(); + this.columnPagePriority = new Aga.Controls.Tree.TreeColumn(); + this.columnStartTime = new Aga.Controls.Tree.TreeColumn(); + this.columnRelativeStartTime = new Aga.Controls.Tree.TreeColumn(); + this.columnTotalCpuTime = new Aga.Controls.Tree.TreeColumn(); + this.columnUserCpuTime = new Aga.Controls.Tree.TreeColumn(); + this.columnKernelCpuTime = new Aga.Controls.Tree.TreeColumn(); + this.columnVerificationStatus = new Aga.Controls.Tree.TreeColumn(); + this.nodeIcon = new Aga.Controls.Tree.NodeControls.NodeIcon(); + this.nodeName = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodePid = new Aga.Controls.Tree.NodeControls.NodeIntegerTextBox(); + this.nodePvtMemory = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodeWorkingSet = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodePeakWorkingSet = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodeVirtualSize = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodePeakVirtualSize = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodePrivateWorkingSet = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodeSharedWorkingSet = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodeShareableWorkingSet = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodePagefileUsage = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodePeakPagefileUsage = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodePageFaults = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodeCpu = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodeUsername = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodeSessionId = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodePriorityClass = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodeBasePriority = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodeDescription = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodeCompany = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodeFileName = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodeCommandLine = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodeThreads = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodeHandles = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodeGdiHandles = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodeUserHandles = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodeIoTotal = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodeIoReadOther = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodeIoWrite = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodeIntegrity = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodeIoPriority = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodePagePriority = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodeStartTime = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodeRelativeStartTime = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodeTotalCpuTime = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodeKernelCpuTime = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodeUserCpuTime = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodeVerificationStatus = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.SuspendLayout(); + // + // treeProcesses + // + this.treeProcesses.AllowColumnReorder = true; + this.treeProcesses.BackColor = System.Drawing.SystemColors.Window; + this.treeProcesses.Columns.Add(this.columnName); + this.treeProcesses.Columns.Add(this.columnPID); + this.treeProcesses.Columns.Add(this.columnPvtMemory); + this.treeProcesses.Columns.Add(this.columnWorkingSet); + this.treeProcesses.Columns.Add(this.columnPeakWorkingSet); + this.treeProcesses.Columns.Add(this.columnPrivateWorkingSet); + this.treeProcesses.Columns.Add(this.columnSharedWorkingSet); + this.treeProcesses.Columns.Add(this.columnShareableWorkingSet); + this.treeProcesses.Columns.Add(this.columnVirtualSize); + this.treeProcesses.Columns.Add(this.columnPeakVirtualSize); + this.treeProcesses.Columns.Add(this.columnPagefileUsage); + this.treeProcesses.Columns.Add(this.columnPeakPagefileUsage); + this.treeProcesses.Columns.Add(this.columnPageFaults); + this.treeProcesses.Columns.Add(this.columnCPU); + this.treeProcesses.Columns.Add(this.columnIoTotal); + this.treeProcesses.Columns.Add(this.columnUsername); + this.treeProcesses.Columns.Add(this.columnSessionId); + this.treeProcesses.Columns.Add(this.columnPriorityClass); + this.treeProcesses.Columns.Add(this.columnBasePriority); + this.treeProcesses.Columns.Add(this.columnDescription); + this.treeProcesses.Columns.Add(this.columnCompany); + this.treeProcesses.Columns.Add(this.columnFileName); + this.treeProcesses.Columns.Add(this.columnCommandLine); + this.treeProcesses.Columns.Add(this.columnThreads); + this.treeProcesses.Columns.Add(this.columnHandles); + this.treeProcesses.Columns.Add(this.columnGdiHandles); + this.treeProcesses.Columns.Add(this.columnUserHandles); + this.treeProcesses.Columns.Add(this.columnIoReadOther); + this.treeProcesses.Columns.Add(this.columnIoWrite); + this.treeProcesses.Columns.Add(this.columnIntegrity); + this.treeProcesses.Columns.Add(this.columnIoPriority); + this.treeProcesses.Columns.Add(this.columnPagePriority); + this.treeProcesses.Columns.Add(this.columnStartTime); + this.treeProcesses.Columns.Add(this.columnRelativeStartTime); + this.treeProcesses.Columns.Add(this.columnTotalCpuTime); + this.treeProcesses.Columns.Add(this.columnUserCpuTime); + this.treeProcesses.Columns.Add(this.columnKernelCpuTime); + this.treeProcesses.Columns.Add(this.columnVerificationStatus); + this.treeProcesses.DefaultToolTipProvider = null; + this.treeProcesses.DisplayDraggingNodes = true; + this.treeProcesses.Dock = System.Windows.Forms.DockStyle.Fill; + this.treeProcesses.DragDropMarkColor = System.Drawing.Color.Black; + this.treeProcesses.FullRowSelect = true; + this.treeProcesses.LineColor = System.Drawing.SystemColors.ControlDark; + this.treeProcesses.Location = new System.Drawing.Point(0, 0); + this.treeProcesses.Model = null; + this.treeProcesses.Name = "treeProcesses"; + this.treeProcesses.NodeControls.Add(this.nodeIcon); + this.treeProcesses.NodeControls.Add(this.nodeName); + this.treeProcesses.NodeControls.Add(this.nodePid); + this.treeProcesses.NodeControls.Add(this.nodePvtMemory); + this.treeProcesses.NodeControls.Add(this.nodeWorkingSet); + this.treeProcesses.NodeControls.Add(this.nodePeakWorkingSet); + this.treeProcesses.NodeControls.Add(this.nodeVirtualSize); + this.treeProcesses.NodeControls.Add(this.nodePeakVirtualSize); + this.treeProcesses.NodeControls.Add(this.nodePrivateWorkingSet); + this.treeProcesses.NodeControls.Add(this.nodeSharedWorkingSet); + this.treeProcesses.NodeControls.Add(this.nodeShareableWorkingSet); + this.treeProcesses.NodeControls.Add(this.nodePagefileUsage); + this.treeProcesses.NodeControls.Add(this.nodePeakPagefileUsage); + this.treeProcesses.NodeControls.Add(this.nodePageFaults); + this.treeProcesses.NodeControls.Add(this.nodeCpu); + this.treeProcesses.NodeControls.Add(this.nodeUsername); + this.treeProcesses.NodeControls.Add(this.nodeSessionId); + this.treeProcesses.NodeControls.Add(this.nodePriorityClass); + this.treeProcesses.NodeControls.Add(this.nodeBasePriority); + this.treeProcesses.NodeControls.Add(this.nodeDescription); + this.treeProcesses.NodeControls.Add(this.nodeCompany); + this.treeProcesses.NodeControls.Add(this.nodeFileName); + this.treeProcesses.NodeControls.Add(this.nodeCommandLine); + this.treeProcesses.NodeControls.Add(this.nodeThreads); + this.treeProcesses.NodeControls.Add(this.nodeHandles); + this.treeProcesses.NodeControls.Add(this.nodeGdiHandles); + this.treeProcesses.NodeControls.Add(this.nodeUserHandles); + this.treeProcesses.NodeControls.Add(this.nodeIoTotal); + this.treeProcesses.NodeControls.Add(this.nodeIoReadOther); + this.treeProcesses.NodeControls.Add(this.nodeIoWrite); + this.treeProcesses.NodeControls.Add(this.nodeIntegrity); + this.treeProcesses.NodeControls.Add(this.nodeIoPriority); + this.treeProcesses.NodeControls.Add(this.nodePagePriority); + this.treeProcesses.NodeControls.Add(this.nodeStartTime); + this.treeProcesses.NodeControls.Add(this.nodeRelativeStartTime); + this.treeProcesses.NodeControls.Add(this.nodeTotalCpuTime); + this.treeProcesses.NodeControls.Add(this.nodeKernelCpuTime); + this.treeProcesses.NodeControls.Add(this.nodeUserCpuTime); + this.treeProcesses.NodeControls.Add(this.nodeVerificationStatus); + this.treeProcesses.SelectedNode = null; + this.treeProcesses.SelectionMode = Aga.Controls.Tree.TreeSelectionMode.Multi; + this.treeProcesses.ShowNodeToolTips = true; + this.treeProcesses.Size = new System.Drawing.Size(808, 472); + this.treeProcesses.TabIndex = 2; + this.treeProcesses.UseColumns = true; + this.treeProcesses.NodeMouseDoubleClick += new System.EventHandler(this.treeProcesses_NodeMouseDoubleClick); + this.treeProcesses.SelectionChanged += new System.EventHandler(this.treeProcesses_SelectionChanged); + this.treeProcesses.ColumnClicked += new System.EventHandler(this.treeProcesses_ColumnClicked); + // + // columnName + // + this.columnName.Header = "Name"; + this.columnName.Sortable = true; + this.columnName.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnName.TooltipText = null; + this.columnName.Width = 245; + // + // columnPID + // + this.columnPID.Header = "PID"; + this.columnPID.Sortable = true; + this.columnPID.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnPID.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.columnPID.TooltipText = null; + // + // columnPvtMemory + // + this.columnPvtMemory.Header = "Pvt. Memory"; + this.columnPvtMemory.Sortable = true; + this.columnPvtMemory.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnPvtMemory.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.columnPvtMemory.TooltipText = null; + this.columnPvtMemory.Width = 70; + // + // columnWorkingSet + // + this.columnWorkingSet.Header = "Working Set"; + this.columnWorkingSet.IsVisible = false; + this.columnWorkingSet.Sortable = true; + this.columnWorkingSet.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnWorkingSet.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.columnWorkingSet.TooltipText = null; + this.columnWorkingSet.Width = 70; + // + // columnPeakWorkingSet + // + this.columnPeakWorkingSet.Header = "Peak Working Set"; + this.columnPeakWorkingSet.IsVisible = false; + this.columnPeakWorkingSet.Sortable = true; + this.columnPeakWorkingSet.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnPeakWorkingSet.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.columnPeakWorkingSet.TooltipText = null; + this.columnPeakWorkingSet.Width = 70; + // + // columnPrivateWorkingSet + // + this.columnPrivateWorkingSet.Header = "Private WS"; + this.columnPrivateWorkingSet.IsVisible = false; + this.columnPrivateWorkingSet.Sortable = true; + this.columnPrivateWorkingSet.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnPrivateWorkingSet.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.columnPrivateWorkingSet.TooltipText = null; + this.columnPrivateWorkingSet.Width = 70; + // + // columnSharedWorkingSet + // + this.columnSharedWorkingSet.Header = "Shared WS"; + this.columnSharedWorkingSet.IsVisible = false; + this.columnSharedWorkingSet.Sortable = true; + this.columnSharedWorkingSet.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnSharedWorkingSet.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.columnSharedWorkingSet.TooltipText = null; + this.columnSharedWorkingSet.Width = 70; + // + // columnShareableWorkingSet + // + this.columnShareableWorkingSet.Header = "Shareable WS"; + this.columnShareableWorkingSet.IsVisible = false; + this.columnShareableWorkingSet.Sortable = true; + this.columnShareableWorkingSet.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnShareableWorkingSet.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.columnShareableWorkingSet.TooltipText = null; + this.columnShareableWorkingSet.Width = 70; + // + // columnVirtualSize + // + this.columnVirtualSize.Header = "Virtual Size"; + this.columnVirtualSize.IsVisible = false; + this.columnVirtualSize.Sortable = true; + this.columnVirtualSize.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnVirtualSize.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.columnVirtualSize.TooltipText = null; + this.columnVirtualSize.Width = 70; + // + // columnPeakVirtualSize + // + this.columnPeakVirtualSize.Header = "Peak Virtual Size"; + this.columnPeakVirtualSize.IsVisible = false; + this.columnPeakVirtualSize.Sortable = true; + this.columnPeakVirtualSize.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnPeakVirtualSize.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.columnPeakVirtualSize.TooltipText = null; + this.columnPeakVirtualSize.Width = 70; + // + // columnPagefileUsage + // + this.columnPagefileUsage.Header = "Pagefile Usage"; + this.columnPagefileUsage.IsVisible = false; + this.columnPagefileUsage.Sortable = true; + this.columnPagefileUsage.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnPagefileUsage.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.columnPagefileUsage.TooltipText = null; + this.columnPagefileUsage.Width = 70; + // + // columnPeakPagefileUsage + // + this.columnPeakPagefileUsage.Header = "Peak Pagefile Usage"; + this.columnPeakPagefileUsage.IsVisible = false; + this.columnPeakPagefileUsage.Sortable = true; + this.columnPeakPagefileUsage.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnPeakPagefileUsage.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.columnPeakPagefileUsage.TooltipText = null; + this.columnPeakPagefileUsage.Width = 70; + // + // columnPageFaults + // + this.columnPageFaults.Header = "Page Faults"; + this.columnPageFaults.IsVisible = false; + this.columnPageFaults.Sortable = true; + this.columnPageFaults.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnPageFaults.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.columnPageFaults.TooltipText = null; + this.columnPageFaults.Width = 60; + // + // columnCPU + // + this.columnCPU.Header = "CPU"; + this.columnCPU.Sortable = true; + this.columnCPU.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnCPU.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.columnCPU.TooltipText = null; + this.columnCPU.Width = 40; + // + // columnIoTotal + // + this.columnIoTotal.Header = "I/O Total"; + this.columnIoTotal.Sortable = true; + this.columnIoTotal.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnIoTotal.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.columnIoTotal.TooltipText = null; + this.columnIoTotal.Width = 65; + // + // columnUsername + // + this.columnUsername.Header = "Username"; + this.columnUsername.Sortable = true; + this.columnUsername.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnUsername.TooltipText = null; + this.columnUsername.Width = 130; + // + // columnSessionId + // + this.columnSessionId.Header = "Session ID"; + this.columnSessionId.IsVisible = false; + this.columnSessionId.Sortable = true; + this.columnSessionId.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnSessionId.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.columnSessionId.TooltipText = null; + this.columnSessionId.Width = 20; + // + // columnPriorityClass + // + this.columnPriorityClass.Header = "Priority Class"; + this.columnPriorityClass.IsVisible = false; + this.columnPriorityClass.Sortable = true; + this.columnPriorityClass.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnPriorityClass.TooltipText = null; + this.columnPriorityClass.Width = 70; + // + // columnBasePriority + // + this.columnBasePriority.Header = "Base Priority"; + this.columnBasePriority.IsVisible = false; + this.columnBasePriority.Sortable = true; + this.columnBasePriority.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnBasePriority.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.columnBasePriority.TooltipText = null; + // + // columnDescription + // + this.columnDescription.Header = "Description"; + this.columnDescription.Sortable = true; + this.columnDescription.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnDescription.TooltipText = null; + this.columnDescription.Width = 170; + // + // columnCompany + // + this.columnCompany.Header = "Company"; + this.columnCompany.IsVisible = false; + this.columnCompany.Sortable = true; + this.columnCompany.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnCompany.TooltipText = null; + this.columnCompany.Width = 140; + // + // columnFileName + // + this.columnFileName.Header = "File Name"; + this.columnFileName.IsVisible = false; + this.columnFileName.Sortable = true; + this.columnFileName.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnFileName.TooltipText = null; + this.columnFileName.Width = 200; + // + // columnCommandLine + // + this.columnCommandLine.Header = "Command Line"; + this.columnCommandLine.IsVisible = false; + this.columnCommandLine.Sortable = true; + this.columnCommandLine.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnCommandLine.TooltipText = null; + this.columnCommandLine.Width = 200; + // + // columnThreads + // + this.columnThreads.Header = "Threads"; + this.columnThreads.IsVisible = false; + this.columnThreads.Sortable = true; + this.columnThreads.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnThreads.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.columnThreads.TooltipText = null; + this.columnThreads.Width = 35; + // + // columnHandles + // + this.columnHandles.Header = "Handles"; + this.columnHandles.IsVisible = false; + this.columnHandles.Sortable = true; + this.columnHandles.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnHandles.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.columnHandles.TooltipText = null; + this.columnHandles.Width = 35; + // + // columnGdiHandles + // + this.columnGdiHandles.Header = "GDI Handles"; + this.columnGdiHandles.IsVisible = false; + this.columnGdiHandles.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnGdiHandles.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.columnGdiHandles.TooltipText = null; + this.columnGdiHandles.Width = 35; + // + // columnUserHandles + // + this.columnUserHandles.Header = "USER Handles"; + this.columnUserHandles.IsVisible = false; + this.columnUserHandles.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnUserHandles.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.columnUserHandles.TooltipText = null; + this.columnUserHandles.Width = 35; + // + // columnIoReadOther + // + this.columnIoReadOther.Header = "I/O R+O"; + this.columnIoReadOther.IsVisible = false; + this.columnIoReadOther.Sortable = true; + this.columnIoReadOther.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnIoReadOther.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.columnIoReadOther.TooltipText = null; + this.columnIoReadOther.Width = 65; + // + // columnIoWrite + // + this.columnIoWrite.Header = "I/O W"; + this.columnIoWrite.IsVisible = false; + this.columnIoWrite.Sortable = true; + this.columnIoWrite.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnIoWrite.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.columnIoWrite.TooltipText = null; + this.columnIoWrite.Width = 65; + // + // columnIntegrity + // + this.columnIntegrity.Header = "Integrity"; + this.columnIntegrity.IsVisible = false; + this.columnIntegrity.Sortable = true; + this.columnIntegrity.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnIntegrity.TooltipText = null; + this.columnIntegrity.Width = 100; + // + // columnIoPriority + // + this.columnIoPriority.Header = "I/O Priority"; + this.columnIoPriority.IsVisible = false; + this.columnIoPriority.Sortable = true; + this.columnIoPriority.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnIoPriority.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.columnIoPriority.TooltipText = null; + // + // columnPagePriority + // + this.columnPagePriority.Header = "Page Priority"; + this.columnPagePriority.IsVisible = false; + this.columnPagePriority.Sortable = true; + this.columnPagePriority.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnPagePriority.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.columnPagePriority.TooltipText = null; + // + // columnStartTime + // + this.columnStartTime.Header = "Start Time"; + this.columnStartTime.IsVisible = false; + this.columnStartTime.Sortable = true; + this.columnStartTime.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnStartTime.TooltipText = null; + this.columnStartTime.Width = 100; + // + // columnRelativeStartTime + // + this.columnRelativeStartTime.Header = "Start Time (Relative)"; + this.columnRelativeStartTime.IsVisible = false; + this.columnRelativeStartTime.Sortable = true; + this.columnRelativeStartTime.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnRelativeStartTime.TooltipText = null; + this.columnRelativeStartTime.Width = 100; + // + // columnTotalCpuTime + // + this.columnTotalCpuTime.Header = "Total CPU Time"; + this.columnTotalCpuTime.IsVisible = false; + this.columnTotalCpuTime.Sortable = true; + this.columnTotalCpuTime.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnTotalCpuTime.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.columnTotalCpuTime.TooltipText = null; + this.columnTotalCpuTime.Width = 100; + // + // columnUserCpuTime + // + this.columnUserCpuTime.Header = "User CPU Time"; + this.columnUserCpuTime.IsVisible = false; + this.columnUserCpuTime.Sortable = true; + this.columnUserCpuTime.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnUserCpuTime.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.columnUserCpuTime.TooltipText = null; + this.columnUserCpuTime.Width = 100; + // + // columnKernelCpuTime + // + this.columnKernelCpuTime.Header = "Kernel CPU Time"; + this.columnKernelCpuTime.IsVisible = false; + this.columnKernelCpuTime.Sortable = true; + this.columnKernelCpuTime.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnKernelCpuTime.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.columnKernelCpuTime.TooltipText = null; + this.columnKernelCpuTime.Width = 100; + // + // columnVerificationStatus + // + this.columnVerificationStatus.Header = "Verification Status"; + this.columnVerificationStatus.IsVisible = false; + this.columnVerificationStatus.Sortable = true; + this.columnVerificationStatus.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnVerificationStatus.TooltipText = null; + this.columnVerificationStatus.Width = 60; + // + // nodeIcon + // + this.nodeIcon.DataPropertyName = "Icon"; + this.nodeIcon.LeftMargin = 1; + this.nodeIcon.ParentColumn = this.columnName; + // + // nodeName + // + this.nodeName.DataPropertyName = "Name"; + this.nodeName.EditEnabled = false; + this.nodeName.IncrementalSearchEnabled = true; + this.nodeName.LeftMargin = 3; + this.nodeName.ParentColumn = this.columnName; + this.nodeName.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodePid + // + this.nodePid.DataPropertyName = "DisplayPid"; + this.nodePid.EditEnabled = false; + this.nodePid.IncrementalSearchEnabled = true; + this.nodePid.LeftMargin = 3; + this.nodePid.ParentColumn = this.columnPID; + this.nodePid.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.nodePid.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodePvtMemory + // + this.nodePvtMemory.DataPropertyName = "PvtMemory"; + this.nodePvtMemory.EditEnabled = false; + this.nodePvtMemory.IncrementalSearchEnabled = true; + this.nodePvtMemory.LeftMargin = 3; + this.nodePvtMemory.ParentColumn = this.columnPvtMemory; + this.nodePvtMemory.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.nodePvtMemory.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodeWorkingSet + // + this.nodeWorkingSet.DataPropertyName = "WorkingSet"; + this.nodeWorkingSet.EditEnabled = false; + this.nodeWorkingSet.IncrementalSearchEnabled = true; + this.nodeWorkingSet.LeftMargin = 3; + this.nodeWorkingSet.ParentColumn = this.columnWorkingSet; + this.nodeWorkingSet.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.nodeWorkingSet.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodePeakWorkingSet + // + this.nodePeakWorkingSet.DataPropertyName = "PeakWorkingSet"; + this.nodePeakWorkingSet.EditEnabled = false; + this.nodePeakWorkingSet.IncrementalSearchEnabled = true; + this.nodePeakWorkingSet.LeftMargin = 3; + this.nodePeakWorkingSet.ParentColumn = this.columnPeakWorkingSet; + this.nodePeakWorkingSet.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.nodePeakWorkingSet.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodeVirtualSize + // + this.nodeVirtualSize.DataPropertyName = "VirtualSize"; + this.nodeVirtualSize.EditEnabled = false; + this.nodeVirtualSize.IncrementalSearchEnabled = true; + this.nodeVirtualSize.LeftMargin = 3; + this.nodeVirtualSize.ParentColumn = this.columnVirtualSize; + this.nodeVirtualSize.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.nodeVirtualSize.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodePeakVirtualSize + // + this.nodePeakVirtualSize.DataPropertyName = "PeakVirtualSize"; + this.nodePeakVirtualSize.EditEnabled = false; + this.nodePeakVirtualSize.IncrementalSearchEnabled = true; + this.nodePeakVirtualSize.LeftMargin = 3; + this.nodePeakVirtualSize.ParentColumn = this.columnPeakVirtualSize; + this.nodePeakVirtualSize.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.nodePeakVirtualSize.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodePrivateWorkingSet + // + this.nodePrivateWorkingSet.DataPropertyName = "PrivateWorkingSet"; + this.nodePrivateWorkingSet.EditEnabled = false; + this.nodePrivateWorkingSet.IncrementalSearchEnabled = true; + this.nodePrivateWorkingSet.LeftMargin = 3; + this.nodePrivateWorkingSet.ParentColumn = this.columnPrivateWorkingSet; + this.nodePrivateWorkingSet.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.nodePrivateWorkingSet.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodeSharedWorkingSet + // + this.nodeSharedWorkingSet.DataPropertyName = "SharedWorkingSet"; + this.nodeSharedWorkingSet.EditEnabled = false; + this.nodeSharedWorkingSet.IncrementalSearchEnabled = true; + this.nodeSharedWorkingSet.LeftMargin = 3; + this.nodeSharedWorkingSet.ParentColumn = this.columnSharedWorkingSet; + this.nodeSharedWorkingSet.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.nodeSharedWorkingSet.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodeShareableWorkingSet + // + this.nodeShareableWorkingSet.DataPropertyName = "ShareableWorkingSet"; + this.nodeShareableWorkingSet.EditEnabled = false; + this.nodeShareableWorkingSet.IncrementalSearchEnabled = true; + this.nodeShareableWorkingSet.LeftMargin = 3; + this.nodeShareableWorkingSet.ParentColumn = this.columnShareableWorkingSet; + this.nodeShareableWorkingSet.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.nodeShareableWorkingSet.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodePagefileUsage + // + this.nodePagefileUsage.DataPropertyName = "PagefileUsage"; + this.nodePagefileUsage.EditEnabled = false; + this.nodePagefileUsage.IncrementalSearchEnabled = true; + this.nodePagefileUsage.LeftMargin = 3; + this.nodePagefileUsage.ParentColumn = this.columnPagefileUsage; + this.nodePagefileUsage.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.nodePagefileUsage.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodePeakPagefileUsage + // + this.nodePeakPagefileUsage.DataPropertyName = "PeakPagefileUsage"; + this.nodePeakPagefileUsage.EditEnabled = false; + this.nodePeakPagefileUsage.IncrementalSearchEnabled = true; + this.nodePeakPagefileUsage.LeftMargin = 3; + this.nodePeakPagefileUsage.ParentColumn = this.columnPeakPagefileUsage; + this.nodePeakPagefileUsage.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.nodePeakPagefileUsage.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodePageFaults + // + this.nodePageFaults.DataPropertyName = "PageFaults"; + this.nodePageFaults.EditEnabled = false; + this.nodePageFaults.IncrementalSearchEnabled = true; + this.nodePageFaults.LeftMargin = 3; + this.nodePageFaults.ParentColumn = this.columnPageFaults; + this.nodePageFaults.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.nodePageFaults.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodeCpu + // + this.nodeCpu.DataPropertyName = "Cpu"; + this.nodeCpu.EditEnabled = false; + this.nodeCpu.IncrementalSearchEnabled = true; + this.nodeCpu.LeftMargin = 3; + this.nodeCpu.ParentColumn = this.columnCPU; + this.nodeCpu.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.nodeCpu.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodeUsername + // + this.nodeUsername.DataPropertyName = "Username"; + this.nodeUsername.EditEnabled = false; + this.nodeUsername.IncrementalSearchEnabled = true; + this.nodeUsername.LeftMargin = 3; + this.nodeUsername.ParentColumn = this.columnUsername; + this.nodeUsername.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodeSessionId + // + this.nodeSessionId.DataPropertyName = "SessionId"; + this.nodeSessionId.EditEnabled = false; + this.nodeSessionId.IncrementalSearchEnabled = true; + this.nodeSessionId.LeftMargin = 3; + this.nodeSessionId.ParentColumn = this.columnSessionId; + this.nodeSessionId.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.nodeSessionId.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodePriorityClass + // + this.nodePriorityClass.DataPropertyName = "PriorityClass"; + this.nodePriorityClass.EditEnabled = false; + this.nodePriorityClass.IncrementalSearchEnabled = true; + this.nodePriorityClass.LeftMargin = 3; + this.nodePriorityClass.ParentColumn = this.columnPriorityClass; + this.nodePriorityClass.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodeBasePriority + // + this.nodeBasePriority.DataPropertyName = "BasePriority"; + this.nodeBasePriority.EditEnabled = false; + this.nodeBasePriority.IncrementalSearchEnabled = true; + this.nodeBasePriority.LeftMargin = 3; + this.nodeBasePriority.ParentColumn = this.columnBasePriority; + this.nodeBasePriority.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.nodeBasePriority.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodeDescription + // + this.nodeDescription.DataPropertyName = "Description"; + this.nodeDescription.EditEnabled = false; + this.nodeDescription.IncrementalSearchEnabled = true; + this.nodeDescription.LeftMargin = 3; + this.nodeDescription.ParentColumn = this.columnDescription; + this.nodeDescription.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodeCompany + // + this.nodeCompany.DataPropertyName = "Company"; + this.nodeCompany.EditEnabled = false; + this.nodeCompany.IncrementalSearchEnabled = true; + this.nodeCompany.LeftMargin = 3; + this.nodeCompany.ParentColumn = this.columnCompany; + this.nodeCompany.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodeFileName + // + this.nodeFileName.DataPropertyName = "FileName"; + this.nodeFileName.EditEnabled = false; + this.nodeFileName.IncrementalSearchEnabled = true; + this.nodeFileName.LeftMargin = 3; + this.nodeFileName.ParentColumn = this.columnFileName; + this.nodeFileName.Trimming = System.Drawing.StringTrimming.EllipsisPath; + // + // nodeCommandLine + // + this.nodeCommandLine.DataPropertyName = "CommandLine"; + this.nodeCommandLine.EditEnabled = false; + this.nodeCommandLine.IncrementalSearchEnabled = true; + this.nodeCommandLine.LeftMargin = 3; + this.nodeCommandLine.ParentColumn = this.columnCommandLine; + this.nodeCommandLine.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodeThreads + // + this.nodeThreads.DataPropertyName = "Threads"; + this.nodeThreads.EditEnabled = false; + this.nodeThreads.IncrementalSearchEnabled = true; + this.nodeThreads.LeftMargin = 3; + this.nodeThreads.ParentColumn = this.columnThreads; + this.nodeThreads.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.nodeThreads.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodeHandles + // + this.nodeHandles.DataPropertyName = "Handles"; + this.nodeHandles.EditEnabled = false; + this.nodeHandles.IncrementalSearchEnabled = true; + this.nodeHandles.LeftMargin = 3; + this.nodeHandles.ParentColumn = this.columnHandles; + this.nodeHandles.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.nodeHandles.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodeGdiHandles + // + this.nodeGdiHandles.DataPropertyName = "GdiHandles"; + this.nodeGdiHandles.EditEnabled = false; + this.nodeGdiHandles.IncrementalSearchEnabled = true; + this.nodeGdiHandles.LeftMargin = 3; + this.nodeGdiHandles.ParentColumn = this.columnGdiHandles; + this.nodeGdiHandles.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.nodeGdiHandles.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodeUserHandles + // + this.nodeUserHandles.DataPropertyName = "UserHandles"; + this.nodeUserHandles.EditEnabled = false; + this.nodeUserHandles.IncrementalSearchEnabled = true; + this.nodeUserHandles.LeftMargin = 3; + this.nodeUserHandles.ParentColumn = this.columnUserHandles; + this.nodeUserHandles.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.nodeUserHandles.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodeIoTotal + // + this.nodeIoTotal.DataPropertyName = "IoTotal"; + this.nodeIoTotal.EditEnabled = false; + this.nodeIoTotal.IncrementalSearchEnabled = true; + this.nodeIoTotal.LeftMargin = 3; + this.nodeIoTotal.ParentColumn = this.columnIoTotal; + this.nodeIoTotal.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.nodeIoTotal.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodeIoReadOther + // + this.nodeIoReadOther.DataPropertyName = "IoReadOther"; + this.nodeIoReadOther.EditEnabled = false; + this.nodeIoReadOther.IncrementalSearchEnabled = true; + this.nodeIoReadOther.LeftMargin = 3; + this.nodeIoReadOther.ParentColumn = this.columnIoReadOther; + this.nodeIoReadOther.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.nodeIoReadOther.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodeIoWrite + // + this.nodeIoWrite.DataPropertyName = "IoWrite"; + this.nodeIoWrite.EditEnabled = false; + this.nodeIoWrite.IncrementalSearchEnabled = true; + this.nodeIoWrite.LeftMargin = 3; + this.nodeIoWrite.ParentColumn = this.columnIoWrite; + this.nodeIoWrite.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.nodeIoWrite.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodeIntegrity + // + this.nodeIntegrity.DataPropertyName = "Integrity"; + this.nodeIntegrity.EditEnabled = false; + this.nodeIntegrity.IncrementalSearchEnabled = true; + this.nodeIntegrity.LeftMargin = 3; + this.nodeIntegrity.ParentColumn = this.columnIntegrity; + this.nodeIntegrity.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodeIoPriority + // + this.nodeIoPriority.DataPropertyName = "IoPriority"; + this.nodeIoPriority.EditEnabled = false; + this.nodeIoPriority.IncrementalSearchEnabled = true; + this.nodeIoPriority.LeftMargin = 3; + this.nodeIoPriority.ParentColumn = this.columnIoPriority; + this.nodeIoPriority.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.nodeIoPriority.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodePagePriority + // + this.nodePagePriority.DataPropertyName = "PagePriority"; + this.nodePagePriority.EditEnabled = false; + this.nodePagePriority.IncrementalSearchEnabled = true; + this.nodePagePriority.LeftMargin = 3; + this.nodePagePriority.ParentColumn = this.columnPagePriority; + this.nodePagePriority.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.nodePagePriority.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodeStartTime + // + this.nodeStartTime.DataPropertyName = "StartTime"; + this.nodeStartTime.EditEnabled = false; + this.nodeStartTime.IncrementalSearchEnabled = true; + this.nodeStartTime.LeftMargin = 3; + this.nodeStartTime.ParentColumn = this.columnStartTime; + this.nodeStartTime.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodeRelativeStartTime + // + this.nodeRelativeStartTime.DataPropertyName = "RelativeStartTime"; + this.nodeRelativeStartTime.EditEnabled = false; + this.nodeRelativeStartTime.IncrementalSearchEnabled = true; + this.nodeRelativeStartTime.LeftMargin = 3; + this.nodeRelativeStartTime.ParentColumn = this.columnRelativeStartTime; + this.nodeRelativeStartTime.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodeTotalCpuTime + // + this.nodeTotalCpuTime.DataPropertyName = "TotalCpuTime"; + this.nodeTotalCpuTime.EditEnabled = false; + this.nodeTotalCpuTime.IncrementalSearchEnabled = true; + this.nodeTotalCpuTime.LeftMargin = 3; + this.nodeTotalCpuTime.ParentColumn = this.columnTotalCpuTime; + this.nodeTotalCpuTime.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.nodeTotalCpuTime.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodeKernelCpuTime + // + this.nodeKernelCpuTime.DataPropertyName = "KernelCpuTime"; + this.nodeKernelCpuTime.EditEnabled = false; + this.nodeKernelCpuTime.IncrementalSearchEnabled = true; + this.nodeKernelCpuTime.LeftMargin = 3; + this.nodeKernelCpuTime.ParentColumn = this.columnKernelCpuTime; + this.nodeKernelCpuTime.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.nodeKernelCpuTime.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodeUserCpuTime + // + this.nodeUserCpuTime.DataPropertyName = "UserCpuTime"; + this.nodeUserCpuTime.EditEnabled = false; + this.nodeUserCpuTime.IncrementalSearchEnabled = true; + this.nodeUserCpuTime.LeftMargin = 3; + this.nodeUserCpuTime.ParentColumn = this.columnUserCpuTime; + this.nodeUserCpuTime.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.nodeUserCpuTime.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodeVerificationStatus + // + this.nodeVerificationStatus.DataPropertyName = "VerificationStatus"; + this.nodeVerificationStatus.EditEnabled = false; + this.nodeVerificationStatus.IncrementalSearchEnabled = true; + this.nodeVerificationStatus.LeftMargin = 3; + this.nodeVerificationStatus.ParentColumn = this.columnVerificationStatus; + this.nodeVerificationStatus.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // ProcessTree + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.treeProcesses); + this.DoubleBuffered = true; + this.Name = "ProcessTree"; + this.Size = new System.Drawing.Size(808, 472); + this.ResumeLayout(false); + + } + + #endregion + + private Aga.Controls.Tree.TreeViewAdv treeProcesses; + private Aga.Controls.Tree.TreeColumn columnName; + private Aga.Controls.Tree.TreeColumn columnPID; + private Aga.Controls.Tree.TreeColumn columnPvtMemory; + private Aga.Controls.Tree.TreeColumn columnUsername; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeName; + private Aga.Controls.Tree.NodeControls.NodeIntegerTextBox nodePid; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodePvtMemory; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeCpu; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeUsername; + private Aga.Controls.Tree.NodeControls.NodeIcon nodeIcon; + private Aga.Controls.Tree.TreeColumn columnCPU; + private Aga.Controls.Tree.TreeColumn columnDescription; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeDescription; + private Aga.Controls.Tree.TreeColumn columnCompany; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeCompany; + private Aga.Controls.Tree.TreeColumn columnWorkingSet; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeWorkingSet; + private Aga.Controls.Tree.TreeColumn columnFileName; + private Aga.Controls.Tree.TreeColumn columnCommandLine; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeFileName; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeCommandLine; + private Aga.Controls.Tree.TreeColumn columnSessionId; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeSessionId; + private Aga.Controls.Tree.TreeColumn columnThreads; + private Aga.Controls.Tree.TreeColumn columnHandles; + private Aga.Controls.Tree.TreeColumn columnGdiHandles; + private Aga.Controls.Tree.TreeColumn columnUserHandles; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeThreads; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeHandles; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeGdiHandles; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeUserHandles; + private Aga.Controls.Tree.TreeColumn columnPriorityClass; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeBasePriority; + private Aga.Controls.Tree.TreeColumn columnVirtualSize; + private Aga.Controls.Tree.TreeColumn columnPeakVirtualSize; + private Aga.Controls.Tree.TreeColumn columnPeakWorkingSet; + private Aga.Controls.Tree.TreeColumn columnPageFaults; + private Aga.Controls.Tree.TreeColumn columnPagefileUsage; + private Aga.Controls.Tree.TreeColumn columnPeakPagefileUsage; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodePeakWorkingSet; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeVirtualSize; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodePeakVirtualSize; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodePagefileUsage; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodePeakPagefileUsage; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodePageFaults; + private Aga.Controls.Tree.TreeColumn columnIoTotal; + private Aga.Controls.Tree.TreeColumn columnIoReadOther; + private Aga.Controls.Tree.TreeColumn columnIoWrite; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeIoTotal; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeIoReadOther; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeIoWrite; + private Aga.Controls.Tree.TreeColumn columnPrivateWorkingSet; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodePrivateWorkingSet; + private Aga.Controls.Tree.TreeColumn columnSharedWorkingSet; + private Aga.Controls.Tree.TreeColumn columnShareableWorkingSet; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeSharedWorkingSet; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeShareableWorkingSet; + private Aga.Controls.Tree.TreeColumn columnIntegrity; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeIntegrity; + private Aga.Controls.Tree.TreeColumn columnIoPriority; + private Aga.Controls.Tree.TreeColumn columnPagePriority; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeIoPriority; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodePagePriority; + private Aga.Controls.Tree.TreeColumn columnBasePriority; + private Aga.Controls.Tree.TreeColumn columnStartTime; + private Aga.Controls.Tree.TreeColumn columnTotalCpuTime; + private Aga.Controls.Tree.TreeColumn columnUserCpuTime; + private Aga.Controls.Tree.TreeColumn columnKernelCpuTime; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodePriorityClass; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeStartTime; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeTotalCpuTime; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeKernelCpuTime; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeUserCpuTime; + private Aga.Controls.Tree.TreeColumn columnRelativeStartTime; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeRelativeStartTime; + private Aga.Controls.Tree.TreeColumn columnVerificationStatus; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeVerificationStatus; + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/ProcessTree/ProcessTree.cs b/branches/ph-plugins/ProcessHacker/Components/ProcessTree/ProcessTree.cs new file mode 100644 index 000000000..ffa960ca2 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/ProcessTree/ProcessTree.cs @@ -0,0 +1,485 @@ +/* + * Process Hacker - + * process tree control + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Windows.Forms; +using Aga.Controls.Tree; +using ProcessHacker.Common; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; + +namespace ProcessHacker +{ + public partial class ProcessTree : UserControl + { + private ProcessSystemProvider _provider; + private ProcessTreeModel _treeModel; + private ProcessToolTipProvider _tooltipProvider; + private int _runCount = 0; + public new event KeyEventHandler KeyDown; + public new event MouseEventHandler MouseDown; + public new event MouseEventHandler MouseUp; + public new event EventHandler DoubleClick; + public event EventHandler SelectionChanged; + public event EventHandler NodeMouseDoubleClick; + private object _listLock = new object(); + private bool _draw = true; + + public ProcessTree() + { + InitializeComponent(); + + var column = new TreeColumn("CPU History", 60); + + column.IsVisible = false; + column.MinColumnWidth = 10; + treeProcesses.Columns.Add(column); + treeProcesses.NodeControls.Add(new ProcessHacker.Components.NodePlotter() + { + DataPropertyName = "CpuHistory", + ParentColumn = column + }); + + column = new TreeColumn("I/O History", 60); + column.IsVisible = false; + column.MinColumnWidth = 10; + treeProcesses.Columns.Add(column); + treeProcesses.NodeControls.Add(new ProcessHacker.Components.NodePlotter() + { + DataPropertyName = "IoHistory", + ParentColumn = column + }); + + treeProcesses.KeyDown += new KeyEventHandler(ProcessTree_KeyDown); + treeProcesses.MouseDown += new MouseEventHandler(treeProcesses_MouseDown); + treeProcesses.MouseUp += new MouseEventHandler(treeProcesses_MouseUp); + treeProcesses.DoubleClick += new EventHandler(treeProcesses_DoubleClick); + + nodeName.ToolTipProvider = _tooltipProvider = new ProcessToolTipProvider(this); + + // make it draw when we want it to draw :) + treeProcesses.BeginUpdate(); + } + + private void treeProcesses_DoubleClick(object sender, EventArgs e) + { + if (this.DoubleClick != null) + this.DoubleClick(sender, e); + } + + private void treeProcesses_SelectionChanged(object sender, EventArgs e) + { + if (this.SelectionChanged != null) + this.SelectionChanged(sender, e); + } + + private void treeProcesses_MouseUp(object sender, MouseEventArgs e) + { + if (this.MouseUp != null) + this.MouseUp(sender, e); + } + + private void treeProcesses_MouseDown(object sender, MouseEventArgs e) + { + if (this.MouseDown != null) + this.MouseDown(sender, e); + } + + private void treeProcesses_NodeMouseDoubleClick(object sender, TreeNodeAdvMouseEventArgs e) + { + if (this.NodeMouseDoubleClick != null) + this.NodeMouseDoubleClick(sender, e); + } + + private void ProcessTree_KeyDown(object sender, KeyEventArgs e) + { + if (this.KeyDown != null) + this.KeyDown(sender, e); + } + + private void treeProcesses_ColumnClicked(object sender, TreeColumnEventArgs e) + { + if (e.Column.SortOrder == SortOrder.None) + { + e.Column.SortOrder = SortOrder.Descending; + } + else if (e.Column.SortOrder == SortOrder.Descending) + { + e.Column.SortOrder = SortOrder.Ascending; + } + else + { + e.Column.SortOrder = SortOrder.None; + } + + _treeModel.CallStructureChanged(new TreePathEventArgs(new TreePath())); + + treeProcesses.Root.ExpandAll(); + this.RefreshItems(); + } + + #region Properties + + public override bool Focused + { + get + { + return treeProcesses.Focused; + } + } + + public bool Draw + { + get { return _draw; } + set { _draw = value; } + } + + public override ContextMenu ContextMenu + { + get { return treeProcesses.ContextMenu; } + set { treeProcesses.ContextMenu = value; } + } + + public override ContextMenuStrip ContextMenuStrip + { + get { return treeProcesses.ContextMenuStrip; } + set { treeProcesses.ContextMenuStrip = value; } + } + + public TreeViewAdv Tree + { + get { return treeProcesses; } + } + + public ProcessTreeModel Model + { + get { return _treeModel; } + } + + public ProcessSystemProvider Provider + { + get { return _provider; } + set + { + if (_provider != null) + { + _provider.DictionaryAdded -= provider_DictionaryAdded; + _provider.DictionaryModified -= provider_DictionaryModified; + _provider.DictionaryRemoved -= provider_DictionaryRemoved; + _provider.Updated -= provider_Updated; + } + + _provider = value; + + treeProcesses.Model = _treeModel = new ProcessTreeModel(this); + + if (_provider != null) + { + // Do an interlocked execute so that we don't get corrupted state. + //_provider.InterlockedExecute(new MethodInvoker(() => + // { + _provider.DictionaryAdded += provider_DictionaryAdded; + _provider.DictionaryModified += provider_DictionaryModified; + _provider.DictionaryRemoved += provider_DictionaryRemoved; + _provider.Updated += provider_Updated; + + treeProcesses.BeginUpdate(); + treeProcesses.BeginCompleteUpdate(); + + foreach (ProcessItem item in _provider.Dictionary.Values) + { + provider_DictionaryAdded(item); + } + + treeProcesses.EndCompleteUpdate(); + treeProcesses.EndUpdate(); + //})); + } + } + } + + public ProcessToolTipProvider TooltipProvider + { + get { return _tooltipProvider; } + } + + #endregion + + private void provider_Updated() + { + if (_draw) + { + this.BeginInvoke(new MethodInvoker(delegate + { + if (_treeModel.GetSortColumn() != "") + { + _treeModel.CallStructureChanged(new TreePathEventArgs(new TreePath())); + } + + //treeProcesses.InvalidateNodeControlCache(); + treeProcesses.Invalidate(); + })); + } + + _runCount++; + } + + private void PerformDelayed(int delay, MethodInvoker action) + { + Timer t = new Timer(); + + t.Tick += new EventHandler(delegate(object o, EventArgs args) + { + t.Enabled = false; + action(); + t.Dispose(); + }); + + t.Interval = delay; + t.Enabled = true; + } + + private Color GetProcessColor(ProcessItem p) + { + if (Properties.Settings.Default.UseColorDebuggedProcesses && p.IsBeingDebugged) + return Properties.Settings.Default.ColorDebuggedProcesses; + else if (Properties.Settings.Default.UseColorElevatedProcesses && + p.ElevationType == TokenElevationType.Full) + return Properties.Settings.Default.ColorElevatedProcesses; + else if (Properties.Settings.Default.UseColorPosixProcesses && + p.IsPosix) + return Properties.Settings.Default.ColorPosixProcesses; + else if (Properties.Settings.Default.UseColorWow64Processes && + p.IsWow64) + return Properties.Settings.Default.ColorWow64Processes; + else if (Properties.Settings.Default.UseColorJobProcesses && p.IsInSignificantJob) + return Properties.Settings.Default.ColorJobProcesses; + else if (Properties.Settings.Default.UseColorPackedProcesses && + Properties.Settings.Default.VerifySignatures && + Program.ImposterNames.Contains(p.Name.ToLower()) && + p.VerifyResult != VerifyResult.Trusted && + p.VerifyResult != VerifyResult.TrustedInstaller && + p.VerifyResult != VerifyResult.Unknown && + p.FileName != null) + return Properties.Settings.Default.ColorPackedProcesses; + else if (Properties.Settings.Default.UseColorPackedProcesses && + Properties.Settings.Default.VerifySignatures && + p.VerifyResult != VerifyResult.Trusted && + p.VerifyResult != VerifyResult.TrustedInstaller && + p.VerifyResult != VerifyResult.NoSignature && + p.VerifyResult != VerifyResult.Unknown) + return Properties.Settings.Default.ColorPackedProcesses; + else if (Properties.Settings.Default.UseColorDotNetProcesses && p.IsDotNet) + return Properties.Settings.Default.ColorDotNetProcesses; + else if (Properties.Settings.Default.UseColorPackedProcesses && p.IsPacked) + return Properties.Settings.Default.ColorPackedProcesses; + else if (Properties.Settings.Default.UseColorServiceProcesses && + Program.HackerWindow.ProcessServices.ContainsKey(p.Pid) && + Program.HackerWindow.ProcessServices[p.Pid].Count > 0) + return Properties.Settings.Default.ColorServiceProcesses; + else if (Properties.Settings.Default.UseColorSystemProcesses && p.Username == "NT AUTHORITY\\SYSTEM") + return Properties.Settings.Default.ColorSystemProcesses; + else if (Properties.Settings.Default.UseColorOwnProcesses && p.Username == Program.CurrentUsername) + return Properties.Settings.Default.ColorOwnProcesses; + else + return SystemColors.Window; + } + + private void provider_DictionaryAdded(ProcessItem item) + { + this.BeginInvoke(new MethodInvoker(delegate + { + lock (_listLock) + { + _treeModel.Add(item); + + TreeNodeAdv node = this.FindTreeNode(item.Pid); + + if (node != null) + { + if (item.RunId > 0 && _runCount > 0) + { + node.State = TreeNodeAdv.NodeState.New; + this.PerformDelayed(Properties.Settings.Default.HighlightingDuration, + new MethodInvoker(delegate + { + node.State = TreeNodeAdv.NodeState.Normal; + treeProcesses.Invalidate(); + })); + } + + node.BackColor = this.GetProcessColor(item); + node.ExpandAll(); + } + } + })); + } + + private void provider_DictionaryModified(ProcessItem oldItem, ProcessItem newItem) + { + this.BeginInvoke(new MethodInvoker(delegate + { + lock (_listLock) + { + TreeNodeAdv node = this.FindTreeNode(newItem.Pid); + + if (node != null) + { + node.BackColor = this.GetProcessColor(newItem); + } + + _treeModel.Nodes[newItem.Pid].ProcessItem = newItem; + } + })); + } + + private void provider_DictionaryRemoved(ProcessItem item) + { + this.BeginInvoke(new MethodInvoker(delegate + { + lock (_listLock) + { + TreeNodeAdv node = this.FindTreeNode(item.Pid); + + if (node != null) + { + //if (this.StateHighlighting) + //{ + node.State = TreeNodeAdv.NodeState.Removed; + this.PerformDelayed(Properties.Settings.Default.HighlightingDuration, + new MethodInvoker(delegate + { + try + { + _treeModel.Remove(item); + this.RefreshItems(); + } + catch (Exception ex) + { + Logging.Log(ex); + } + })); + //} + //else + //{ + // _treeModel.Remove(item); + //} + + treeProcesses.Invalidate(); + } + } + })); + } + + public void RefreshItems() + { + lock (_listLock) + { + foreach (TreeNodeAdv node in treeProcesses.AllNodes) + { + try + { + ProcessNode pNode = this.FindNode(node); + + // May not be in the dictionary if the process has terminated but + // the node is still being highlighted. + if (_provider.Dictionary.ContainsKey(pNode.Pid)) + { + ProcessItem item = _provider.Dictionary[pNode.Pid]; + + node.BackColor = this.GetProcessColor(item); + } + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + } + } + + public Dictionary Nodes + { + get { return _treeModel.Nodes; } + } + + public TreeNodeAdv FindTreeNode(int pid) + { + if (_treeModel.Nodes.ContainsKey(pid)) + return treeProcesses.FindNode(_treeModel.GetPath(_treeModel.Nodes[pid])); + else + return null; + } + + public TreeNodeAdv FindTreeNode(ProcessNode node) + { + return this.FindTreeNode(node.Pid); + } + + public ProcessNode FindNode(TreeNodeAdv node) + { + return treeProcesses.GetPath(node).LastNode as ProcessNode; + } + + #region Interfacing + + public void BeginUpdate() + { + treeProcesses.BeginUpdate(); + } + + public void EndUpdate() + { + treeProcesses.EndUpdate(); + } + + public IEnumerable TreeNodes + { + get { return treeProcesses.AllNodes; } + } + + public System.Collections.ObjectModel.ReadOnlyCollection SelectedTreeNodes + { + get { return treeProcesses.SelectedNodes; } + } + + public System.Collections.ObjectModel.ReadOnlyCollection SelectedNodes + { + get + { + List nodes = new List(); + + foreach (TreeNodeAdv node in treeProcesses.SelectedNodes) + nodes.Add(treeProcesses.GetPath(node).LastNode as ProcessNode); + + System.Collections.ObjectModel.ReadOnlyCollection collection = + new System.Collections.ObjectModel.ReadOnlyCollection(nodes); + + return collection; + } + } + + #endregion + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/ProcessTree/ProcessTree.resx b/branches/ph-plugins/ProcessHacker/Components/ProcessTree/ProcessTree.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/ProcessTree/ProcessTree.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/ProcessTree/ProcessTreeModel.cs b/branches/ph-plugins/ProcessHacker/Components/ProcessTree/ProcessTreeModel.cs new file mode 100644 index 000000000..745c4d3b8 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/ProcessTree/ProcessTreeModel.cs @@ -0,0 +1,380 @@ +/* + * Process Hacker - + * ITreeModel implementation for the process tree + * + * Copyright (C) 2008-2009 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 event 'event' is never used +#pragma warning disable 0067 + +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using Aga.Controls.Tree; +using ProcessHacker.Common; +using ProcessHacker.Native; + +namespace ProcessHacker +{ + /// + /// The process tree model. None of the methods are thread-safe. + /// + public class ProcessTreeModel : ITreeModel + { + private ProcessTree _tree; + private Dictionary _processes = new Dictionary(); + private List _roots = new List(); + + public ProcessTreeModel(ProcessTree tree) + { + _tree = tree; + } + + public void Add(ProcessItem item) + { + ProcessNode itemNode = new ProcessNode(item); + + // Add the process to the list of all processes. + _processes.Add(item.Pid, itemNode); + + // Find the process' parent and add the process to it if we found it. + if (item.HasParent && _processes.ContainsKey(item.ParentPid)) + { + ProcessNode parent = _processes[item.ParentPid]; + + parent.Children.Add(itemNode); + itemNode.Parent = parent; + } + else + { + // The process doesn't have a parent, so add it to the root nodes. + _roots.Add(itemNode); + } + + itemNode.RefreshTreePath(); + + // Find this process' children and fix them up. + + // We need to create a copy of the array because we may need + // to modify the roots list. + ProcessNode[] roots = _roots.ToArray(); + + foreach (ProcessNode node in roots) + { + // Notice that we don't replace a node's parent if it + // already has one. This is to break potential cyclic + // references. + if (node.Parent == null && node.ProcessItem.HasParent && node.PPid == item.Pid) + { + // Remove the node from the root list and add it to our + // process' child list. + _roots.Remove(node); + itemNode.Children.Add(node); + node.Parent = itemNode; + node.RefreshTreePathRecursive(); + } + } + + this.StructureChanged(this, new TreePathEventArgs(new TreePath())); + } + + public void Modify(ProcessItem oldItem, ProcessItem newItem) + { + ProcessNode node = _processes[newItem.Pid]; + + node.ProcessItem = newItem; + + //if (node.ProcessItem.HasParent && node.PPID != -1) + // this.NodesChanged(this, new TreeModelEventArgs(this.GetPath( + // _processes.ContainsKey(node.PPID) ? _processes[node.PPID] : null), + // new object[] { node })); + } + + public void Remove(ProcessItem item) + { + ProcessNode itemNode = _processes[item.Pid]; + ProcessNode[] itemChildren = null; + + // Dispose of the process node we're removing. + itemNode.Dispose(); + + itemChildren = itemNode.Children.ToArray(); + + // Check if the node has a parent. + if (itemNode.Parent == null) + { + if (_roots.Contains(itemNode)) + { + // Remove the process from the roots and make its children root nodes. + _roots.Remove(itemNode); + this.MoveChildrenToRoot(itemNode); + } + } + else + { + if (itemNode.Parent.Children.Contains(itemNode)) + { + // Remove the node from its parent and make its children root nodes. + itemNode.Parent.Children.Remove(itemNode); + this.MoveChildrenToRoot(itemNode); + } + } + + // Remove the process from the process dictionary. + _processes.Remove(item.Pid); + this.StructureChanged(this, new TreePathEventArgs(new TreePath())); + + // Expand the children because TreeViewAdv collapses them by default. + if (itemChildren != null) + { + foreach (ProcessNode n in itemChildren) + { + try + { + _tree.FindTreeNode(n).ExpandAll(); + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + } + + _tree.Invalidate(); + } + + public TreePath GetPath(ProcessNode node) + { + if (node == null) + return TreePath.Empty; + + if (this.GetSortColumn() != "") + { + return new TreePath(node); + } + else + { + return node.TreePath; + } + } + + public void MoveChildrenToRoot(ProcessNode node) + { + ProcessNode[] children = node.Children.ToArray(); + + foreach (ProcessNode child in children) + { + child.Parent = null; + child.RefreshTreePathRecursive(); + } + + _roots.AddRange(children); + } + + public Dictionary Nodes + { + get { return _processes; } + } + + public ProcessNode[] Roots + { + get { return _roots.ToArray(); } + } + + public string GetSortColumn() + { + foreach (TreeColumn column in _tree.Tree.Columns) + if (column.SortOrder != SortOrder.None) + return column.Header.ToLower(); + + return ""; + } + + public SortOrder GetSortOrder() + { + foreach (TreeColumn column in _tree.Tree.Columns) + if (column.SortOrder != SortOrder.None) + return column.SortOrder; + + return SortOrder.None; + } + + public int ModifySort(int sortResult, SortOrder order) + { + if (order == SortOrder.Ascending) + return -sortResult; + else if (order == SortOrder.Descending) + return sortResult; + else + return 0; + } + + public System.Collections.IEnumerable GetChildren(TreePath treePath) + { + if (this.GetSortColumn() != "") + { + List nodes = new List(); + string sortC = this.GetSortColumn(); + SortOrder sortO = this.GetSortOrder(); + + nodes.AddRange(_processes.Values); + + nodes.Sort(new Comparison(delegate(ProcessNode n1, ProcessNode n2) + { + // We have a problem here - the GdiHandlesNumber and UserHandlesNumber + // properties are dynamically retrieved, so if n1 == n2 we may end up + // getting different values for the same process due to the timing. + // If we do, then Array.Sort will throw an exception. + // + // The temporary HACK used here is to return 0 whenever n1 == n2. + if (n1 == n2) + return 0; + + switch (sortC) + { + case "name": + return ModifySort(n1.Name.CompareTo(n2.Name), sortO); + case "pid": + return ModifySort(n1.Pid.CompareTo(n2.Pid), sortO); + case "pvt. memory": + return ModifySort(n1.ProcessItem.Process.VirtualMemoryCounters.PrivatePageCount.CompareTo( + n2.ProcessItem.Process.VirtualMemoryCounters.PrivatePageCount), sortO); + case "working set": + return ModifySort(n1.ProcessItem.Process.VirtualMemoryCounters.WorkingSetSize.CompareTo( + n2.ProcessItem.Process.VirtualMemoryCounters.WorkingSetSize), sortO); + case "peak working set": + return ModifySort(n1.ProcessItem.Process.VirtualMemoryCounters.PeakWorkingSetSize.CompareTo( + n2.ProcessItem.Process.VirtualMemoryCounters.PeakWorkingSetSize), sortO); + case "private ws": + return ModifySort(n1.PrivateWorkingSetNumber.CompareTo(n2.PrivateWorkingSetNumber), sortO); + case "shared ws": + return ModifySort(n1.SharedWorkingSetNumber.CompareTo(n2.SharedWorkingSetNumber), sortO); + case "shareable ws": + return ModifySort(n1.ShareableWorkingSetNumber.CompareTo(n2.ShareableWorkingSetNumber), sortO); + case "virtual size": + return ModifySort(n1.ProcessItem.Process.VirtualMemoryCounters.VirtualSize.CompareTo( + n2.ProcessItem.Process.VirtualMemoryCounters.VirtualSize), sortO); + case "peak virtual size": + return ModifySort(n1.ProcessItem.Process.VirtualMemoryCounters.PeakVirtualSize.CompareTo( + n2.ProcessItem.Process.VirtualMemoryCounters.PeakVirtualSize), sortO); + case "pagefile usage": + return ModifySort(n1.ProcessItem.Process.VirtualMemoryCounters.PagefileUsage.CompareTo( + n2.ProcessItem.Process.VirtualMemoryCounters.PagefileUsage), sortO); + case "peak pagefile usage": + return ModifySort(n1.ProcessItem.Process.VirtualMemoryCounters.PeakPagefileUsage.CompareTo( + n2.ProcessItem.Process.VirtualMemoryCounters.PeakPagefileUsage), sortO); + case "page faults": + return ModifySort(n1.ProcessItem.Process.VirtualMemoryCounters.PageFaultCount.CompareTo( + n2.ProcessItem.Process.VirtualMemoryCounters.PageFaultCount), sortO); + case "cpu": + return ModifySort(n1.ProcessItem.CpuUsage.CompareTo(n2.ProcessItem.CpuUsage), sortO); + case "username": + return ModifySort(n1.Username.CompareTo(n2.Username), sortO); + case "session id": + return ModifySort(n1.ProcessItem.SessionId.CompareTo(n2.ProcessItem.SessionId), sortO); + case "priority class": + case "base priority": + return ModifySort(n1.ProcessItem.Process.BasePriority.CompareTo( + n2.ProcessItem.Process.BasePriority), sortO); + case "description": + return ModifySort(n1.Description.CompareTo(n2.Description), sortO); + case "company": + return ModifySort(n1.Company.CompareTo(n2.Company), sortO); + case "file name": + return ModifySort(n1.FileName.CompareTo(n2.FileName), sortO); + case "command line": + return ModifySort(n1.CommandLine.CompareTo(n2.CommandLine), sortO); + case "threads": + return ModifySort(n1.ProcessItem.Process.NumberOfThreads.CompareTo( + n2.ProcessItem.Process.NumberOfThreads), sortO); + case "handles": + return ModifySort(n1.ProcessItem.Process.HandleCount.CompareTo( + n2.ProcessItem.Process.HandleCount), sortO); + case "gdi handles": + return ModifySort(n1.GdiHandlesNumber.CompareTo(n2.GdiHandlesNumber), sortO); + case "user handles": + return ModifySort(n1.UserHandlesNumber.CompareTo(n2.UserHandlesNumber), sortO); + case "i/o total": + return ModifySort(n1.IoTotalNumber.CompareTo(n2.IoTotalNumber), sortO); + case "i/o ro": + return ModifySort(n1.IoReadOtherNumber.CompareTo(n2.IoReadOtherNumber), sortO); + case "i/o w": + return ModifySort(n1.IoWriteNumber.CompareTo(n2.IoWriteNumber), sortO); + case "integrity": + return ModifySort(n1.IntegrityLevel.CompareTo(n2.IntegrityLevel), sortO); + case "i/o priority": + return ModifySort(n1.IoPriority.CompareTo(n2.IoPriority), sortO); + case "page priority": + return ModifySort(n1.PagePriority.CompareTo(n2.PagePriority), sortO); + case "start time": + return ModifySort(n1.ProcessItem.CreateTime.CompareTo(n2.ProcessItem.CreateTime), sortO); + case "start time (relative)": + // Invert the order - bigger dates are actually smaller if we use the relative time span. + return -ModifySort(n1.ProcessItem.CreateTime.CompareTo(n2.ProcessItem.CreateTime), sortO); + case "total cpu time": + return ModifySort((n1.ProcessItem.Process.KernelTime + n1.ProcessItem.Process.UserTime). + CompareTo(n2.ProcessItem.Process.KernelTime + n2.ProcessItem.Process.UserTime), sortO); + case "kernel cpu time": + return ModifySort(n1.ProcessItem.Process.KernelTime.CompareTo( + n2.ProcessItem.Process.KernelTime), sortO); + case "user cpu time": + return ModifySort(n1.ProcessItem.Process.UserTime.CompareTo( + n2.ProcessItem.Process.UserTime), sortO); + case "verification status": + return ModifySort(n1.VerificationStatus.CompareTo(n2.VerificationStatus), sortO); + default: + return 0; + } + })); + + return nodes; + } + + if (treePath.IsEmpty()) + return _roots; + else + return (treePath.LastNode as ProcessNode).Children; + } + + public bool IsLeaf(TreePath treePath) + { + // When we're sorting the whole tree is a flat list, so there are no children. + if (this.GetSortColumn() != "") + return true; + + if (treePath.IsEmpty()) + return false; + else + return (treePath.LastNode as ProcessNode).Children.Count == 0; + } + + public event EventHandler NodesChanged; + + public event EventHandler NodesInserted; + + public event EventHandler NodesRemoved; + + public event EventHandler StructureChanged; + + public void CallStructureChanged(TreePathEventArgs args) + { + this.StructureChanged(this, args); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/RestartRecoveryLib/RecoveryData.cs b/branches/ph-plugins/ProcessHacker/Components/RestartRecoveryLib/RecoveryData.cs new file mode 100644 index 000000000..d3e500410 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/RestartRecoveryLib/RecoveryData.cs @@ -0,0 +1,73 @@ +/* + * Process Hacker - + * ProcessHacker Restart and Recovery Extensions + * + * Copyright (C) 2009 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 . + * + */ + +using System; +using System.Runtime.InteropServices; + +namespace ProcessHackerRestartRecovery +{ + /// + /// The Delegate that represents the callback method invoked by the system when an application has registered for application recovery. + /// + /// An application-defined state object that is passed to the callback method. + /// The callback method will be invoked prior to the application being terminated by Windows Error Reporting (WER). + /// To keep WER from terminating the application before the callback method completes, the callback method must + /// periodically call the ApplicationRestartRecoveryManager.ApplicationRecoveryInProgress method. + public delegate int RecoveryCallback(object state); + + /// + /// Defines a class that contains a callback delegate and properties of the application as defined by the user. + /// + public class RecoveryData + { + /// + /// Initializes a recovery data wrapper with a callback method and the current state of the application. + /// + /// The callback delegate. + /// The current state of the application. + public RecoveryData(RecoveryCallback callback, object state) + { + Callback = callback; + State = state; + } + + /// + /// Gets or sets a value that determines the recovery callback function. + /// + public RecoveryCallback Callback { get; set; } + + /// + /// Gets or sets a value that determines the application state. + /// + public object State { get; set; } + + /// + /// Invokes the recovery callback function. + /// + public void Invoke() + { + if(Callback != null) + Callback(State); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/RestartRecoveryLib/RecoverySettings.cs b/branches/ph-plugins/ProcessHacker/Components/RestartRecoveryLib/RecoverySettings.cs new file mode 100644 index 000000000..0b7d57446 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/RestartRecoveryLib/RecoverySettings.cs @@ -0,0 +1,92 @@ +/* + * Process Hacker - + * ProcessHacker Restart and Recovery Extensions + * + * Copyright (C) 2009 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 . + * + */ + +using System; + +namespace ProcessHackerRestartRecovery +{ + /// + /// Defines methods and properties for recovery settings, and specifies options for an application that attempts + /// to perform final actions after a fatal event, such as an unhandled exception. + /// + /// This class is used to register for application recovery. + /// See the ApplicationRestartRecoveryManager class. + /// + public class RecoverySettings + { + private RecoveryData recoveryData; + private uint pingInterval; + + /// + /// Initializes a new instance of the RecoverySettings class. + /// + /// A recovery data object that contains the callback method (invoked by the system + /// before Windows Error Reporting terminates the application) and an optional state object. + /// The time interval within which the + /// callback method must invoke ApplicationRestartRecoveryManager.ApplicationRecoveryInProgress to + /// prevent WER from terminating the application. + public RecoverySettings(RecoveryData data, uint interval) + { + this.recoveryData = data; + this.pingInterval = interval; + } + + /// + /// Gets the recovery data object that contains the callback method and an optional + /// parameter (usually the state of the application) to be passed to the callback method. + /// + /// A RecoveryData object. + public RecoveryData RecoveryData + { + get { return recoveryData; } + } + + /// + /// Gets the time interval for notifying Windows Error Reporting. + /// The RecoveryCallback method must invoke ApplicationRestartRecoveryManager.ApplicationRecoveryInProgress + /// within this interval to prevent WER from terminating the application. + /// + /// + /// The recovery ping interval is specified in milliseconds. + /// By default, the interval is 5 seconds. + /// If you specify zero, the default interval is used. + /// + public uint PingInterval + { + get { return pingInterval; } + } + + /// + /// Returns a string representation of the current state of this object. + /// + /// A String object. + public override string ToString() + { + return String.Format("delegate: {0}, state: {1}, ping: {2}", + this.recoveryData.Callback.Method.ToString(), + this.recoveryData.State.ToString(), + this.PingInterval); + } + } +} + diff --git a/branches/ph-plugins/ProcessHacker/Components/RestartRecoveryLib/RestartRecoveryInterop.cs b/branches/ph-plugins/ProcessHacker/Components/RestartRecoveryLib/RestartRecoveryInterop.cs new file mode 100644 index 000000000..4878a6528 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/RestartRecoveryLib/RestartRecoveryInterop.cs @@ -0,0 +1,149 @@ +/* + * Process Hacker - + * ProcessHacker Restart and Recovery Extensions + * + * Copyright (C) 2009 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 . + * + */ + +using System.Runtime.InteropServices; +using ProcessHacker.Native.Api; +using System.Security; +using System; + +namespace ProcessHackerRestartRecovery +{ + [SuppressUnmanagedCodeSecurity] + internal static class AppRestartRecoveryNativeMethods + { + #region Application Restart and Recovery Definitions + + internal delegate UInt32 InternalRecoveryCallback(IntPtr state); + + internal static InternalRecoveryCallback internalCallback; + + static AppRestartRecoveryNativeMethods() + { + internalCallback = new InternalRecoveryCallback(InternalRecoveryHandler); + } + + private static UInt32 InternalRecoveryHandler(IntPtr parameter) + { + bool cancelled = false; + ApplicationRecoveryInProgress(out cancelled); + + GCHandle handle = GCHandle.FromIntPtr(parameter); + RecoveryData data = handle.Target as RecoveryData; + data.Invoke(); + handle.Free(); + + return 0; + } + + [DllImport("kernel32.dll")] + internal static extern void ApplicationRecoveryFinished( + [MarshalAs(UnmanagedType.Bool)] + bool success + ); + + [DllImport("kernel32.dll")] + [PreserveSig] + internal static extern HResult ApplicationRecoveryInProgress( + [Out, MarshalAs(UnmanagedType.Bool)] + out bool canceled + ); + + [DllImport("kernel32.dll")] + [PreserveSig] + internal static extern HResult GetApplicationRecoveryCallback( + IntPtr processHandle, + [Out] RecoveryCallback recoveryCallback, + [Out] out object state, + [Out] out uint pingInterval, + [Out] out uint flags + ); + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] + [PreserveSig] + internal static extern HResult RegisterApplicationRecoveryCallback( + InternalRecoveryCallback callback, IntPtr param, + uint pingInterval, + uint flags //Unused + ); + + + [DllImport("kernel32.dll")] + [PreserveSig] + internal static extern HResult RegisterApplicationRestart( + [MarshalAs(UnmanagedType.BStr)] + string commandLineArgs, + RestartRestrictions flags + ); + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + [PreserveSig] + internal static extern HResult GetApplicationRestartSettings( + IntPtr process, + IntPtr commandLine, + ref uint size, + [Out] out RestartRestrictions flags + ); + + [DllImport("kernel32.dll")] + [PreserveSig] + internal static extern HResult UnregisterApplicationRecoveryCallback(); + + [DllImport("kernel32.dll")] + [PreserveSig] + internal static extern HResult UnregisterApplicationRestart(); + + #endregion + } + + /// + /// Specifies the conditions when Windows Error Reporting + /// should not restart an application that has registered + /// for automatic restart. + /// + [Flags] + public enum RestartRestrictions + { + /// + /// Always restart the application. + /// + None = 0, + /// + /// Do not restart when the application has crashed. + /// + NotOnCrash = 1, + /// + /// Do not restart when the application is hung. + /// + NotOnHang = 2, + /// + /// Do not restart when the application is terminated + /// due to a system update. + /// + NotOnPatch = 4, + /// + /// Do not restart when the application is terminated + /// because of a system reboot. + /// + NotOnReboot = 8 + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/RestartRecoveryLib/RestartRecoveryManager.cs b/branches/ph-plugins/ProcessHacker/Components/RestartRecoveryLib/RestartRecoveryManager.cs new file mode 100644 index 000000000..e2ea8dad4 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/RestartRecoveryLib/RestartRecoveryManager.cs @@ -0,0 +1,229 @@ +/* + * Process Hacker - + * ProcessHacker Restart and Recovery Extensions + * + * Copyright (C) 2009 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 . + * + */ + +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.Diagnostics; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; + +namespace ProcessHackerRestartRecovery +{ + /// + /// Provides access to the Application Restart and Recovery + /// features available in Windows Vista or higher. Application Restart and Recovery lets an + /// application do some recovery work to save data before the process exits. + /// + public static class ApplicationRestartRecoveryManager + { + public static void RegisterForRestart() + { + // Register for automatic restart if the application was terminated for any reason other than a system reboot or a system update. + ApplicationRestartRecoveryManager.RegisterForApplicationRestart( + new RestartSettings("-recovered", + RestartRestrictions.NotOnReboot + | RestartRestrictions.NotOnPatch)); + } + + public static void RegisterForRecovery() + { + // Since this registration is being done on application startup, we don't have a state currently. + // In some cases it might make sense to pass this initial state. + // Another approach: When doing "auto-save", register for recovery everytime, and pass + // the current state I.E. data for recovery at that time. + RecoveryData data = new RecoveryData(new RecoveryCallback(RecoveryProcedure), null); + RecoverySettings settings = new RecoverySettings(data, 0); + ApplicationRestartRecoveryManager.RegisterForApplicationRecovery(settings); + } + + /// + /// This method is invoked by WER. + /// + /// Application state + /// A value for WER + private static int RecoveryProcedure(object state) + { + PingSystem(); + + // Do recovery work here. + // Do {Report Error to SF, SaveData} etc + // Write the contents to a file, as well as some other data that we need... + + try + { + // Remove the icons or they remain in the system try. + ProcessHacker.Program.HackerWindow.ExecuteOnIcons((icon) => icon.Visible = false); + ProcessHacker.Program.HackerWindow.ExecuteOnIcons((icon) => icon.Dispose()); + + // Make sure KPH connection is closed. + if (ProcessHacker.Native.KProcessHacker.Instance != null) + ProcessHacker.Native.KProcessHacker.Instance.Close(); + } + catch { } + + // Application is now shutting down... + // Signal to WER that the recovery has finished, only call this once. + // this is the very last call that will be made. + ApplicationRecoveryFinished(true); + + return 0; + } + + /// + /// This method is called periodically to ensure that WER knows that recovery is still in progress. + /// + private static void PingSystem() + { + // Find out if the user canceled recovery. + bool isCanceled = ApplicationRecoveryInProgress(); + + if (isCanceled) + { + System.Windows.Forms.MessageBox.Show("Recovery has been canceled by user."); + Environment.Exit(1); + } + } + + /// + /// This method gets called by main when the commandline arguments indicate that this application was automatically restarted by WER. + /// + public static void RecoverLastSession() + { + // TODO: Perform application state restoration actions here. + // Do {LoadData, ShowError, ShowRecovered} etc + } + + /// + /// Registers an application for recovery by Application Restart and Recovery. + /// + /// An object that specifies the callback method, an optional parameter to pass to the callback + /// method and a time interval. + /// The time interval is the period of time within which the recovery callback method calls + /// the ApplicationRecoveryInProgress method to indicate that it is still performing recovery work. + private static void RegisterForApplicationRecovery(RecoverySettings settings) + { + if (OSVersion.IsAboveOrEqual(WindowsVersion.Vista)) + { + if (settings == null) + throw new ArgumentNullException("settings"); + + GCHandle handle = GCHandle.Alloc(settings.RecoveryData); + + HResult hr = AppRestartRecoveryNativeMethods.RegisterApplicationRecoveryCallback(AppRestartRecoveryNativeMethods.internalCallback, (IntPtr)handle, settings.PingInterval, (uint)0); + + if (hr == HResult.InvalidArgument) + throw new ArgumentException("Application was not registered for recovery due to bad parameters."); + else if (hr == HResult.Fail) + throw new ExternalException("Application failed to register for recovery."); + } + } + + /// + /// Removes an application's recovery registration. + /// + private static void UnregisterApplicationRecovery() + { + if (OSVersion.IsAboveOrEqual(WindowsVersion.Vista)) + { + HResult hr = AppRestartRecoveryNativeMethods.UnregisterApplicationRecoveryCallback(); + + if (hr == HResult.Fail) + throw new ExternalException("Unregister for recovery failed."); + } + } + + /// + /// Removes an application's restart registration. + /// + private static void UnregisterApplicationRestart() + { + if (OSVersion.IsAboveOrEqual(WindowsVersion.Vista)) + { + HResult hr = AppRestartRecoveryNativeMethods.UnregisterApplicationRestart(); + + if (hr == HResult.Fail) + throw new ExternalException("Unregister for restart failed."); + } + } + + /// + /// Called by an application's RecoveryCallback method + /// to indicate that it is still performing recovery work. + /// + /// A Boolean value indicating whether the user canceled the recovery. + private static bool ApplicationRecoveryInProgress() + { + if (OSVersion.IsAboveOrEqual(WindowsVersion.Vista)) + { + bool canceled = false; + + HResult hr = AppRestartRecoveryNativeMethods.ApplicationRecoveryInProgress(out canceled); + + if (hr == HResult.Fail) + throw new InvalidOperationException("This method must be called from the registered callback method."); + + return canceled; + } + else + return true; + } + + /// + /// Called by an application's RecoveryCallback method to indicate that the recovery work is complete. + /// + /// + /// This should be the last call made by the RecoveryCallback method because + /// Windows Error Reporting will terminate the application after this method is invoked. + /// + /// true to indicate the the program was able to complete its recovery + /// work before terminating; otherwise false + private static void ApplicationRecoveryFinished(bool success) + { + if (OSVersion.IsAboveOrEqual(WindowsVersion.Vista)) + { + AppRestartRecoveryNativeMethods.ApplicationRecoveryFinished(success); + } + } + + /// + /// Registers an application for automatic restart if the application is terminated by Windows Error Reporting. + /// + /// An object that specifies the command line arguments used to restart the + /// application, and the conditions under which the application should not be restarted. + /// A registered application will not be restarted if it executed for less than 60 seconds before terminating. + private static void RegisterForApplicationRestart(RestartSettings settings) + { + if (OSVersion.IsAboveOrEqual(WindowsVersion.Vista)) + { + HResult hr = AppRestartRecoveryNativeMethods.RegisterApplicationRestart(settings.Command, settings.Restrictions); + + if (hr == HResult.Fail) + throw new InvalidOperationException("Application failed to registered for restart."); + else if (hr == HResult.InvalidArgument) + throw new ArgumentException("Failed to register application for restart due to bad parameters."); + } + } + } +} + diff --git a/branches/ph-plugins/ProcessHacker/Components/RestartRecoveryLib/RestartSettings.cs b/branches/ph-plugins/ProcessHacker/Components/RestartRecoveryLib/RestartSettings.cs new file mode 100644 index 000000000..877515386 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/RestartRecoveryLib/RestartSettings.cs @@ -0,0 +1,79 @@ +/* + * Process Hacker - + * ProcessHacker Restart and Recovery Extensions + * + * Copyright (C) 2009 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 . + * + */ + +using System; + +namespace ProcessHackerRestartRecovery +{ + /// + /// Specifies the options for an application to be automatically restarted by Windows Error Reporting. + /// + /// Regardless of these settings, the application will not be restarted if it executed for + /// less than 60 seconds beforeterminating. + public class RestartSettings + { + private string command; + private RestartRestrictions restrictions; + + /// + /// Creates a new instance of the RestartSettings class. + /// + /// The command line arguments used to restart the application. + /// A bitwise combination of the RestartRestrictions + /// values that specify when the application should not be restarted. + /// + public RestartSettings(string commandLine, RestartRestrictions restrict) + { + command = commandLine; + restrictions = restrict; + } + + /// + /// Gets the command line arguments used to restart the application. + /// + /// A String object. + public string Command + { + get { return command; } + } + + /// + /// Gets the set of conditions when the application should not be restarted. + /// + /// A set of RestartRestrictions values. + public RestartRestrictions Restrictions + { + get { return restrictions; } + } + + /// + /// Returns a string representation of the current state of this object. + /// + /// A String that displays the command line arguments and restrictions for restarting the application. + public override string ToString() + { + return String.Format("Command: {0} Restrictions: {1}", command, restrictions.ToString()); + } + } +} + diff --git a/branches/ph-plugins/ProcessHacker/Components/SectionProperties.Designer.cs b/branches/ph-plugins/ProcessHacker/Components/SectionProperties.Designer.cs new file mode 100644 index 000000000..8b9d45ebc --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/SectionProperties.Designer.cs @@ -0,0 +1,99 @@ +namespace ProcessHacker.Components +{ + partial class SectionProperties + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + _sectionHandle.Dereference(disposing); + + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.labelSize = new System.Windows.Forms.Label(); + this.labelAttributes = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(6, 3); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(54, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Attributes:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(6, 25); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(30, 13); + this.label2.TabIndex = 0; + this.label2.Text = "Size:"; + // + // labelSize + // + this.labelSize.AutoSize = true; + this.labelSize.Location = new System.Drawing.Point(75, 25); + this.labelSize.Name = "labelSize"; + this.labelSize.Size = new System.Drawing.Size(23, 13); + this.labelSize.TabIndex = 0; + this.labelSize.Text = "0 B"; + // + // labelAttributes + // + this.labelAttributes.AutoSize = true; + this.labelAttributes.Location = new System.Drawing.Point(75, 3); + this.labelAttributes.Name = "labelAttributes"; + this.labelAttributes.Size = new System.Drawing.Size(36, 13); + this.labelAttributes.TabIndex = 0; + this.labelAttributes.Text = "Image"; + // + // SectionProperties + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.labelAttributes); + this.Controls.Add(this.labelSize); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.Name = "SectionProperties"; + this.Padding = new System.Windows.Forms.Padding(3); + this.Size = new System.Drawing.Size(185, 50); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label labelSize; + private System.Windows.Forms.Label labelAttributes; + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/SectionProperties.cs b/branches/ph-plugins/ProcessHacker/Components/SectionProperties.cs new file mode 100644 index 000000000..3dcc0c788 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/SectionProperties.cs @@ -0,0 +1,29 @@ +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Native.Objects; + +namespace ProcessHacker.Components +{ + public partial class SectionProperties : UserControl + { + private SectionHandle _sectionHandle; + + public SectionProperties(SectionHandle sectionHandle) + { + InitializeComponent(); + + _sectionHandle = sectionHandle; + _sectionHandle.Reference(); + + this.UpdateInfo(); + } + + private void UpdateInfo() + { + var basicInfo = _sectionHandle.GetBasicInformation(); + + labelAttributes.Text = basicInfo.SectionAttributes.ToString(); + labelSize.Text = Utils.FormatSize(basicInfo.SectionSize); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/SectionProperties.resx b/branches/ph-plugins/ProcessHacker/Components/SectionProperties.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/SectionProperties.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/SemaphoreProperties.Designer.cs b/branches/ph-plugins/ProcessHacker/Components/SemaphoreProperties.Designer.cs new file mode 100644 index 000000000..d158aa1e9 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/SemaphoreProperties.Designer.cs @@ -0,0 +1,127 @@ +namespace ProcessHacker.Components +{ + partial class SemaphoreProperties + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + _semaphoreHandle.Dereference(disposing); + + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.labelCurrentCount = new System.Windows.Forms.Label(); + this.labelMaximumCount = new System.Windows.Forms.Label(); + this.buttonRelease = new System.Windows.Forms.Button(); + this.buttonAcquire = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(6, 3); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(75, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Current Count:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(6, 25); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(85, 13); + this.label2.TabIndex = 0; + this.label2.Text = "Maximum Count:"; + // + // labelCurrentCount + // + this.labelCurrentCount.AutoSize = true; + this.labelCurrentCount.Location = new System.Drawing.Point(97, 3); + this.labelCurrentCount.Name = "labelCurrentCount"; + this.labelCurrentCount.Size = new System.Drawing.Size(13, 13); + this.labelCurrentCount.TabIndex = 0; + this.labelCurrentCount.Text = "0"; + // + // labelMaximumCount + // + this.labelMaximumCount.AutoSize = true; + this.labelMaximumCount.Location = new System.Drawing.Point(97, 25); + this.labelMaximumCount.Name = "labelMaximumCount"; + this.labelMaximumCount.Size = new System.Drawing.Size(13, 13); + this.labelMaximumCount.TabIndex = 0; + this.labelMaximumCount.Text = "0"; + // + // buttonRelease + // + this.buttonRelease.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonRelease.Location = new System.Drawing.Point(87, 51); + this.buttonRelease.Name = "buttonRelease"; + this.buttonRelease.Size = new System.Drawing.Size(75, 23); + this.buttonRelease.TabIndex = 1; + this.buttonRelease.Text = "Release"; + this.buttonRelease.UseVisualStyleBackColor = true; + this.buttonRelease.Click += new System.EventHandler(this.buttonRelease_Click); + // + // buttonAcquire + // + this.buttonAcquire.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonAcquire.Location = new System.Drawing.Point(6, 51); + this.buttonAcquire.Name = "buttonAcquire"; + this.buttonAcquire.Size = new System.Drawing.Size(75, 23); + this.buttonAcquire.TabIndex = 2; + this.buttonAcquire.Text = "Acquire"; + this.buttonAcquire.UseVisualStyleBackColor = true; + this.buttonAcquire.Click += new System.EventHandler(this.buttonAcquire_Click); + // + // SemaphoreProperties + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.buttonAcquire); + this.Controls.Add(this.buttonRelease); + this.Controls.Add(this.label2); + this.Controls.Add(this.labelMaximumCount); + this.Controls.Add(this.labelCurrentCount); + this.Controls.Add(this.label1); + this.Name = "SemaphoreProperties"; + this.Padding = new System.Windows.Forms.Padding(3); + this.Size = new System.Drawing.Size(196, 80); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label labelCurrentCount; + private System.Windows.Forms.Label labelMaximumCount; + private System.Windows.Forms.Button buttonRelease; + private System.Windows.Forms.Button buttonAcquire; + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/SemaphoreProperties.cs b/branches/ph-plugins/ProcessHacker/Components/SemaphoreProperties.cs new file mode 100644 index 000000000..0cd493efe --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/SemaphoreProperties.cs @@ -0,0 +1,63 @@ +using System; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Components +{ + public partial class SemaphoreProperties : UserControl + { + private SemaphoreHandle _semaphoreHandle; + + public SemaphoreProperties(SemaphoreHandle semaphoreHandle) + { + InitializeComponent(); + + _semaphoreHandle = semaphoreHandle; + _semaphoreHandle.Reference(); + + this.UpdateInfo(); + } + + private void UpdateInfo() + { + var basicInfo = _semaphoreHandle.GetBasicInformation(); + + labelCurrentCount.Text = basicInfo.CurrentCount.ToString(); + labelMaximumCount.Text = basicInfo.MaximumCount.ToString(); + } + + private void buttonAcquire_Click(object sender, EventArgs e) + { + try + { + _semaphoreHandle.ChangeAccess((SemaphoreAccess)StandardRights.Synchronize); + // Try to acquire the semaphore. We don't want to wait on it though, + // so we specify a timeout of 0. + if (_semaphoreHandle.Wait(0) != NtStatus.Success) + throw new Exception("Could not acquire the semaphore."); + this.UpdateInfo(); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to acquire the semaphore", ex); + } + } + + private void buttonRelease_Click(object sender, EventArgs e) + { + try + { + _semaphoreHandle.ChangeAccess(SemaphoreAccess.QueryState | SemaphoreAccess.ModifyState); + _semaphoreHandle.Release(); + this.UpdateInfo(); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to release the semaphore", ex); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/SemaphoreProperties.resx b/branches/ph-plugins/ProcessHacker/Components/SemaphoreProperties.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/SemaphoreProperties.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/ServiceList.Designer.cs b/branches/ph-plugins/ProcessHacker/Components/ServiceList.Designer.cs new file mode 100644 index 000000000..33bd1aa98 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/ServiceList.Designer.cs @@ -0,0 +1,131 @@ +namespace ProcessHacker.Components +{ + partial class ServiceList + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + _highlightingContext.Dispose(); + this.Provider = null; + + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ServiceList)); + this.listServices = new System.Windows.Forms.ListView(); + this.columnName = new System.Windows.Forms.ColumnHeader(); + this.columnDescription = new System.Windows.Forms.ColumnHeader(); + this.columnType = new System.Windows.Forms.ColumnHeader(); + this.columnStatus = new System.Windows.Forms.ColumnHeader(); + this.columnStartType = new System.Windows.Forms.ColumnHeader(); + this.columnPID = new System.Windows.Forms.ColumnHeader(); + this.imageList = new System.Windows.Forms.ImageList(this.components); + this.SuspendLayout(); + // + // listServices + // + this.listServices.AllowColumnReorder = true; + this.listServices.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnName, + this.columnDescription, + this.columnType, + this.columnStatus, + this.columnStartType, + this.columnPID}); + this.listServices.Dock = System.Windows.Forms.DockStyle.Fill; + this.listServices.FullRowSelect = true; + this.listServices.HideSelection = false; + this.listServices.Location = new System.Drawing.Point(0, 0); + this.listServices.Name = "listServices"; + this.listServices.ShowItemToolTips = true; + this.listServices.Size = new System.Drawing.Size(685, 472); + this.listServices.SmallImageList = this.imageList; + this.listServices.Sorting = System.Windows.Forms.SortOrder.Ascending; + this.listServices.TabIndex = 1; + this.listServices.UseCompatibleStateImageBehavior = false; + this.listServices.View = System.Windows.Forms.View.Details; + // + // columnName + // + this.columnName.Text = "Name"; + this.columnName.Width = 150; + // + // columnDescription + // + this.columnDescription.Text = "Description"; + this.columnDescription.Width = 260; + // + // columnType + // + this.columnType.Text = "Type"; + this.columnType.Width = 120; + // + // columnStatus + // + this.columnStatus.Text = "Status"; + this.columnStatus.Width = 80; + // + // columnStartType + // + this.columnStartType.Text = "Start Type"; + this.columnStartType.Width = 80; + // + // columnPID + // + this.columnPID.Text = "PID"; + // + // imageList + // + this.imageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList.ImageStream"))); + this.imageList.TransparentColor = System.Drawing.Color.Transparent; + this.imageList.Images.SetKeyName(0, "Win32"); + this.imageList.Images.SetKeyName(1, "Driver"); + this.imageList.Images.SetKeyName(2, "Interactive"); + this.imageList.Images.SetKeyName(3, "FS"); + // + // ServiceList + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.listServices); + this.DoubleBuffered = true; + this.Name = "ServiceList"; + this.Size = new System.Drawing.Size(685, 472); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.ListView listServices; + private System.Windows.Forms.ColumnHeader columnName; + private System.Windows.Forms.ImageList imageList; + private System.Windows.Forms.ColumnHeader columnDescription; + private System.Windows.Forms.ColumnHeader columnStatus; + private System.Windows.Forms.ColumnHeader columnPID; + private System.Windows.Forms.ColumnHeader columnType; + private System.Windows.Forms.ColumnHeader columnStartType; + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/ServiceList.cs b/branches/ph-plugins/ProcessHacker/Components/ServiceList.cs new file mode 100644 index 000000000..4426867f4 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/ServiceList.cs @@ -0,0 +1,298 @@ +/* + * Process Hacker - + * service list + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Common.Ui; +using ProcessHacker.Native.Objects; +using ProcessHacker.UI; + +namespace ProcessHacker.Components +{ + public partial class ServiceList : UserControl + { + private ServiceProvider _provider; + private int _runCount = 0; + private HighlightingContext _highlightingContext; + private List _needsAdd = new List(); + private bool _needsSort = false; + public new event KeyEventHandler KeyDown; + public new event MouseEventHandler MouseDown; + public new event MouseEventHandler MouseUp; + public new event EventHandler DoubleClick; + public event EventHandler SelectedIndexChanged; + + public ServiceList() + { + InitializeComponent(); + + _highlightingContext = new HighlightingContext(listServices); + listServices.SetTheme("explorer"); + listServices.KeyDown += new KeyEventHandler(ServiceList_KeyDown); + listServices.MouseDown += new MouseEventHandler(listServices_MouseDown); + listServices.MouseUp += new MouseEventHandler(listServices_MouseUp); + listServices.DoubleClick += new EventHandler(listServices_DoubleClick); + listServices.SelectedIndexChanged += new System.EventHandler(listServices_SelectedIndexChanged); + listServices.ListViewItemSorter = new SortedListViewComparer(listServices); + } + + private void listServices_DoubleClick(object sender, EventArgs e) + { + if (this.DoubleClick != null) + this.DoubleClick(sender, e); + } + + private void listServices_MouseUp(object sender, MouseEventArgs e) + { + if (this.MouseUp != null) + this.MouseUp(sender, e); + } + + private void listServices_MouseDown(object sender, MouseEventArgs e) + { + if (this.MouseDown != null) + this.MouseDown(sender, e); + } + + private void listServices_SelectedIndexChanged(object sender, System.EventArgs e) + { + if (this.SelectedIndexChanged != null) + this.SelectedIndexChanged(sender, e); + } + + private void ServiceList_KeyDown(object sender, KeyEventArgs e) + { + if (this.KeyDown != null) + this.KeyDown(sender, e); + } + + #region Properties + + public new bool DoubleBuffered + { + get + { + return (bool)typeof(ListView).GetProperty("DoubleBuffered", + BindingFlags.NonPublic | BindingFlags.Instance).GetValue(listServices, null); + } + set + { + typeof(ListView).GetProperty("DoubleBuffered", + BindingFlags.NonPublic | BindingFlags.Instance).SetValue(listServices, value, null); + } + } + + public override bool Focused + { + get + { + return listServices.Focused; + } + } + + public override ContextMenu ContextMenu + { + get { return listServices.ContextMenu; } + set { listServices.ContextMenu = value; } + } + + public override ContextMenuStrip ContextMenuStrip + { + get { return listServices.ContextMenuStrip; } + set { listServices.ContextMenuStrip = value; } + } + + public ListView List + { + get { return listServices; } + } + + public ServiceProvider Provider + { + get { return _provider; } + set + { + if (_provider != null) + { + _provider.DictionaryAdded -= new ServiceProvider.ProviderDictionaryAdded(provider_DictionaryAdded); + _provider.DictionaryModified -= new ServiceProvider.ProviderDictionaryModified(provider_DictionaryModified); + _provider.DictionaryRemoved -= new ServiceProvider.ProviderDictionaryRemoved(provider_DictionaryRemoved); + _provider.Updated -= new ServiceProvider.ProviderUpdateOnce(provider_Updated); + } + + _provider = value; + + listServices.Items.Clear(); + + if (_provider != null) + { + //_provider.InterlockedExecute(new MethodInvoker(() => + //{ + _provider.DictionaryAdded += new ServiceProvider.ProviderDictionaryAdded(provider_DictionaryAdded); + _provider.DictionaryModified += new ServiceProvider.ProviderDictionaryModified(provider_DictionaryModified); + _provider.DictionaryRemoved += new ServiceProvider.ProviderDictionaryRemoved(provider_DictionaryRemoved); + _provider.Updated += new ServiceProvider.ProviderUpdateOnce(provider_Updated); + + foreach (ServiceItem item in _provider.Dictionary.Values) + { + provider_DictionaryAdded(item); + } + //})); + } + } + } + + #endregion + + #region Interfacing + + public void BeginUpdate() + { + listServices.BeginUpdate(); + } + + public void EndUpdate() + { + listServices.EndUpdate(); + } + + public ListView.ListViewItemCollection Items + { + get { return listServices.Items; } + } + + public ListView.SelectedListViewItemCollection SelectedItems + { + get { return listServices.SelectedItems; } + } + + #endregion + + private void provider_Updated() + { + lock (_needsAdd) + { + if (_needsAdd.Count > 0) + { + this.BeginInvoke(new MethodInvoker(() => + { + lock (_needsAdd) + { + listServices.Items.AddRange(_needsAdd.ToArray()); + _needsAdd.Clear(); + _needsAdd.TrimExcess(); + } + })); + } + } + + _highlightingContext.Tick(); + + if (_needsSort) + { + this.BeginInvoke(new MethodInvoker(() => + { + if (_needsSort) + { + listServices.Sort(); + _needsSort = false; + } + })); + } + + _runCount++; + } + + private void provider_DictionaryAdded(ServiceItem item) + { + HighlightedListViewItem litem = new HighlightedListViewItem(_highlightingContext, + item.RunId > 0 && _runCount > 0); + + litem.Name = item.Status.ServiceName; + litem.Text = item.Status.ServiceName; + litem.SubItems.Add(new ListViewItem.ListViewSubItem(litem, + item.Status.DisplayName)); + litem.SubItems.Add(new ListViewItem.ListViewSubItem(litem, + item.Status.ServiceStatusProcess.ServiceType.ToString())); + litem.SubItems.Add(new ListViewItem.ListViewSubItem(litem, + item.Status.ServiceStatusProcess.CurrentState.ToString())); + litem.SubItems.Add(new ListViewItem.ListViewSubItem(litem, + item.Config.StartType.ToString())); + litem.SubItems.Add(new ListViewItem.ListViewSubItem(litem, + item.Status.ServiceStatusProcess.ProcessID == 0 ? "" : + item.Status.ServiceStatusProcess.ProcessID.ToString())); + + if ((item.Status.ServiceStatusProcess.ServiceType & ServiceType.InteractiveProcess) != 0) + litem.ImageKey = "Interactive"; + else if (item.Status.ServiceStatusProcess.ServiceType == ServiceType.Win32OwnProcess || + item.Status.ServiceStatusProcess.ServiceType == ServiceType.Win32ShareProcess) + litem.ImageKey = "Win32"; + else if (item.Status.ServiceStatusProcess.ServiceType == ServiceType.FileSystemDriver) + litem.ImageKey = "FS"; + else + litem.ImageKey = "Driver"; + + lock (_needsAdd) + _needsAdd.Add(litem); + } + + private void provider_DictionaryModified(ServiceItem oldItem, ServiceItem newItem) + { + if (this.InvokeRequired) + { + this.BeginInvoke(new ServiceProvider.ProviderDictionaryModified(provider_DictionaryModified), oldItem, newItem); + return; + } + + lock (listServices) + { + ListViewItem litem = listServices.Items[newItem.Status.ServiceName]; + + if (litem == null) + return; + + litem.SubItems[1].Text = newItem.Status.DisplayName; + litem.SubItems[2].Text = newItem.Status.ServiceStatusProcess.ServiceType.ToString(); + litem.SubItems[3].Text = newItem.Status.ServiceStatusProcess.CurrentState.ToString(); + litem.SubItems[4].Text = newItem.Config.StartType.ToString(); + litem.SubItems[5].Text = newItem.Status.ServiceStatusProcess.ProcessID == 0 ? "" : + newItem.Status.ServiceStatusProcess.ProcessID.ToString(); + _needsSort = true; + } + } + + private void provider_DictionaryRemoved(ServiceItem item) + { + if (this.InvokeRequired) + { + this.BeginInvoke(new ServiceProvider.ProviderDictionaryRemoved(provider_DictionaryRemoved), item); + return; + } + + lock (listServices) + listServices.Items[item.Status.ServiceName].Remove(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/ServiceList.resx b/branches/ph-plugins/ProcessHacker/Components/ServiceList.resx new file mode 100644 index 000000000..6cdf0e270 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/ServiceList.resx @@ -0,0 +1,214 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj0yLjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAACa + EwAAAk1TRnQBSQFMAgEBBAEAAQwBAAEEAQABEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + AwABIAMAAQEBAAEgBgABIP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8AegADOwFjA1gBvwNX + Ab8DOwFjWAADQAFwAVICVAGmAVABZgF9AeoBOgGAAagB9wE6AYABqAH3AToBgAGoAfcBOgGAAagB9wE6 + AYABqAH3AToBgAGoAfcBOgGAAagB9wE6AYABqAH3AToBfwGoAfcBSQFyAZQB8QNMAZNUAAMdASkDCgEO + AwEBAgNkAeoDvQH/A7IB/wNcAeoDAQECAwoBDgMdASkUAAMKAQ0DDgETA04BmAFlAlgB4wGCAUYBPgH1 + AZUBTQEpAfoBlQFNASkB+gF9AUgBNgH2AWkBVQFRAeoBVwJVAboDEAEWAwoBDQgAAVgBagF5AeYBjgGW + AZgB8AGnAcYB3QH9AZ4B2wH0Af8BlgHaAfMB/wGOAdgB8wH/AYYB1wHzAf8BdwHUAfIB/wFxAdMB8gH/ + AWoB0gHxAf8BZAHQAfEB/wFhAc8B8QH/AbMB2wHpAf4BSwFuAYwB8AgAA1IBqQHDAY4BXgH/AcABiwFc + Af8BvgGIAVoB/wG7AYUBVwH/AbkBgwFVAf8BtAF0AVIB/wGyAXIBUAH/AbEBcQFOAf8BrgFvAU0B/wGt + AWwBTAH/AasBawFKAf8BqQFpAUkB/wGpAWcBRwH/A1IBqQwAA1ABmwNcAf0DZAHnAxIBGQNkAecDywH/ + A8cB/wNiAecDEgEZA1wB5wNFAf0DTwGbDAADRAF5ASYBXwGpAfsBdgJfAfsBvwFWASsB/wH+AbkBVwH/ + Af4BuQFYAf8B/gG5AVgB/wH+AbkBWAH/Af4BuQFXAf8B/gG5AVcB/wGxAT8BGgH/AWkBWQFgAfUBPgF0 + AZ8B+ANIAYMEAAE+AYUBqwH3Ae8B+gH+Af8BoQHpAfkB/wGRAeUB+AH/AYEB4QH3Af8BagHeAfYB/wFb + AdoB9QH/AUwB1wH0Af8BPwHTAfMB/wExAdAB8gH/ASYBzQHxAf8BHgHLAfAB/wHKAfIB+wH/AT4BhQGr + AfcIAAHIAZIBYjX/AakBaAFHAf8IAANEAXsDvAH/A94B/wOmAf8DagH0A38B/gPEAf8DwgH/A20B/gNl + AfQDpgH/A9IB/wOAAf8DRAF7CAABKQF9Ab4B/gGCAboB7gH/AZ8BXAFOAf8B9QG7AYQC/wGsAVEB/wH+ + AagBUAH/Af4BogFNAf8B/gGcAUkC/wGjAUsC/wGfAUYB/wH4Aa4BbgH/AaQBVAFAAf8BgwG8Ae8B/wEq + AXcBtwH+BAABPgGHAa8B+AHyAfoB/QH/AbMB7QH6Af8BpAHpAfkB/wGVAeYB+AH/AYUB4gH3Af8BgQHh + AfcB/wFyAeAB9wH/AWcB3QH2Af8BWgHaAfUB/wFMAdYB8wH/AT8B0wHyAf8B6AH5Af0B/wEtAZQB2gH/ + CAABygGUAWQL/wH+A/8B/QH/Av4B/QH/Av4B/AH/Av4B/AH/Av4B/AH/Av4B/AH/Av4B+gH/Av4B+gH/ + AvwB+QX/AaoBaQFJAf8IAANFAX0DkwH+A9UB/wPFAf8DywH/A9EB/wPJAf8DxwH/A8wB/wPFAf8DvQH/ + A8sB/wNuAf4DRQF9CAABKwFyAbUB/AFuAbMB6gH/AbMBngGUAv8BtwFWAv8BtgFZAf8B/gGyAVcB/wH+ + AawBUwH/Af4BpQFPAf8B/QGeAUkB/wH+AZcBRAL/AY0BOQH/AbwBjwGCAf8BdAG4Ae0B/wEqAWoBogH6 + BAABQQGMAbIB+QH2AfwB/gH/AcgB8gH8Af8BuQHvAfsB/wGsAewB+gH/AYwB5AH4Af8BigHjAfgB/wGC + AeEB9wH/AXEB3wH3Af8BZQHdAfYB/wFZAdoB9QH/AU8B1wH0Af8B5wH4Af0B/wEtAZQB2gH/CAABzAGX + AWUH/wH8A/8B/QH/Av4B/AH/Av4B/AH/Av4B+wH/Av0B+gH/Av0B+gH/Av0B+gH/Av0B+gH/AvwB9wH/ + AvsB9gX/AawBawFKAf8MAANIAYUDxQH/A8EB/wPFAf8DxwH/A6oB/wOnAf8DwQH/A74B/wO1Af8DqgH/ + A0gBhQwAAzIBUAGKAUoBOgH/AfwByAGrAv8B0QGYAf8B/gHHAWMB/wH+Ab8BXgH/Af4BuQFaAf8B/gGx + AVQB/wH+AagBTwH/Af0BoAFKAv8BtwFwAf8B/gGpAYAB/wGIAUYBOAH/AjoBOQFgBAABPwGVAbMB+gH+ + A/8B+AH9Av8B9gH9Av8B9QH8Av8B3gHbAdEB/wGtAcoBxQH/AaYBxQHAAf8BpAHDAb0B/wGeAb0BtgH/ + AZcBugGzAf8BkgG4AbIB/wHhAcsBtwH/AS0BlAHaAf8BwwGEAUoB/wJVAVMBsAHRAZwBaQX/Av4B/AH/ + Av4B/AH/Av4B/AH/Av0B+wH/Av0B+wH/Av0B+gH/Av0B+AH/AvsB+QH/AfsB+gH3Af8B+wH6AfYB/wH7 + AfgB9AX/AbABcAFOAf8EAANcAc0DYgHjA24B7gPPAf8DxgH/A8wB/wNbAcYDLAFEAywBRANbAcYDwQH/ + A7wB/wO5Af8DYQHuA1kB4wNaAc0HAAEBAjoBOQFgAcQBQgEVAf8B9gHkAdYC/wHkAaQC/wHUAWgC/wHJ + AV8C/wHAAVkC/wG2AVUC/wHBAYAB/wH2AdcBxgH/AcUBPwEVAf8DPQFpAwMBBAQAAT0BmgGzAfoB6AH2 + AfsB/wF2AcUB6gH/AVMBrgHjAf8BSQGoAeEB/wFZAa0B3wH/Ae0B9gH3Af8B7QH1AfYB/wHnAe8B8wH/ + AeUB7AHuAf8B5QHrAe0B/wHlAesB7QH/AfgB8wHvAf8BLQGUAdoB/wHwAeIB2AH/AbkBigFRAf0B1AGe + AWsF/wL+AfwB/wL9AfsB/wL9AfwB/wL9AfsB/wL9AfkB/wL8AfgB/wH7AfkB9wH/AfsB+QH1Af8B+wH4 + AfQB/wH7AfcB8gH/AfsB9QHyBf8BsgFyAVAB/wQAA7UB/QPiAf8D0gH/A8YB/wPNAf8DsQH/AywBRAgA + AywBRAOoAf8DwgH/A7cB/wPAAf8D0gH/A1EB/QgAAwUBBwM9AWkBvAE+ARIB/wH0AeIB1AH/AUQBcQGp + Af8BQwFxAagB/wFDAXEBqAH/AUQBcQGpAf8B8wHWAcMB/wG+ATwBEgH/AkABPwFvAwcBCggAAUoBgwGW + AfIB8QH6Af0B/wGUAd4B9QH/AZMB3AH0Af8BgQHVAfIB/wHAAakBlwH/AZEBwQHkAf8BLQGUAdoB/wEt + AZQB2gH/AS0BlAHaAf8BLQGUAdoB/wEtAZQB2gH/AS0BlAHaAf8BLQGUAdoB/wHwAeIB2AH/AcQBhgFM + Af8B1QGgAWwF/wL9AfwB/wL9AfsB/wL9AfoB/wL8AfkB/wH8AfsB9wH/AfsB+QH1Af8B+wH4AfQB/wH7 + AfcB8wH/AfsB9QHyAf8B+gHzAe8B/wH4AfIB7AX/AbUBdAFSAf8EAAO3Af0D6QH/A9YB/wPJAf8DzgH/ + A6UB/wMsAUQIAAMsAUQDrAH/A8QB/wO6Af8DxgH/A90B/wNYAf0MAAMEAQUDUQGiASoBYwGnAf8BnAHM + AfgB/wGvAdQB9wH/Aa8B1AH3Af8BpQHPAfYB/wEqAWoBrgH/AVUCUwGtAwcBCQwAAUwBfAGNAfAB9wH8 + Af4B/wGOAeQB+AH/AZEB3gH1Af8BnwHgAfUB/wHjAbEBjAH/AfoB9gHxAf8B6gHJAa4F/wHoAccBrBH/ + AfEB5QHbAf8BxgGGAU0B/wHYAaIBbwX/Av0B+gH/AvwB+gH/AfwB+wH5Af8B+wH6AfYB/wH7AfgB9QH/ + AfsB9wH0Af8B+wH2AfEB/wH4AfQB7gH/AfcB8gHrAf8B9wHwAeoB/wH2AewB6AX/AbcBgQFUAf8EAANc + Ac0DaAHjA3kB7gPYAf8DzQH/A7wB/wNbAcYDLAFEAywBRANbAcYDwwH/A8IB/wPNAf8DaQHuA2AB4wNc + Ac0QAAFZAlsBxAGmAcoB7gH/AasBzAHqAf8BpwHQAfYB/wGoAdAB9gH/AasBzAHqAf8BpwHNAe4B/wFZ + AlwBzBAAAT4BlwGvAfgB/QL+Af8B/gP/Av4C/wH9Af4C/wHlAbQBjwH/AfoB9gHyAf8B6QHGAaoB/wHp + AcYBrAH/AegBxwGsAf8B6AHHAawB/wHpAckBsAH/AegByAGwAf8B6AHMAbUB/wHyAecB3gH/AcgBigFR + Af8B2QGjAW8F/wH8AfsB+QH/AfwB+wH4Af8B+wH5AfcB/wH7AfcB9AH/AfoB9wHyAf8B+QH1AfAB/wH3 + AfMB7QH/AfYB7wHqAf8B9QHrAecB/wHzAeoB5AH/AfIB5wHeBf8BugGFAVYB/wwAA0gBhQPUAf8DzAH/ + A8kB/wO6Af8DnAH/A6EB/wPCAf8DxgH/A8EB/wO3Af8DSAGFGAABUAFdAW4B7QHZAegB9wH/AZcBxQHx + Af8BjgG7AeUB/wF1AakB0QH/AYkBtQHfAf8BzQHfAe4B/wFJAWQBewHxAwQBBgwAAVsBYAFiAdABUQGk + AbsB+gFSAaUBvAH6AVIBpQG8AfoBUgGlAbwB+gHnAbcBlAH/AfsB9wH0Af8B6QHDAaYF/wHoAccBrBH/ + AfcB8QHrAf8BywGPAVcB/wHbAaQBcDX/Ab0BhwFZAf8IAANFAX0DsQH+A9wB/wPUAf8D2QH/A9sB/wPW + Af8D1AH/A9kB/wPSAf8DywH/A8gB/wN5Af4DRQF9FAABAgE0AYcB/wFyAZcBuAH/AYoBtwHkAf8BZwGc + AcgB/wELATYBZAH/AQ8BOgFoAf8BGAE7AWEB/wEiAUUBUwH6AwUBByAAAekBugGYAf8B+wH3AfQB/wHp + AcMBpgH/AekBwwGmAf8B6QHDAaYB/wHpAcMBpgH/AekBwwGmAf8B6QHDAaYB/wHpAcMBpgH/AfsB9wH0 + Af8BzgGTAVwB/wHcAacBcQH/AdwBpwFxAf8B3AGnAXEB/wHcAacBcQH/AdwBpwFxAf8B3AGnAXEB/wHc + AacBcQH/AdwBpwFxAf8B3AGnAXEB/wHcAacBcQH/AdwBpwFxAf8B3AGnAXEB/wHcAacBcQH/AdwBpwFx + Af8BwAGLAVwB/wgAA0QBewPcAf8D7QH/A9sB/wOKAfQDqwH+A9YB/wPUAf8DnQH+A38B9APLAf8D5wH/ + A7cB/wNEAXsUAAEFAUEBlwH/AQgBTgGfAf8BBQFAAYoB/wEFAUEBhwH/AQcBQQGHAf8BCwFCAYUB/wEI + ATcBawH/AUUBUQFgAfEkAAHrAb0BmwH/AfsB9wH0Hf8B+wH3AfQB/wHRAZcBYgH/AcABqAGFAf0B6AG5 + AZIB/wHoAbkBkgH/AegBuQGSAf8B6AG5AZIB/wHoAbkBkgH/AegBuQGSAf8B6AG5AZIB/wHoAbkBkgH/ + AegBuQGSAf8B6AG5AZIB/wHoAbkBkgH/AegBuQGSAf8B6AG5AZIB/wG2AZABXAH9DAADUAGbA7oB/QNv + AecDEgEZA28B5wPeAf8D3QH/A20B5wMSARkDawHnA6cB/QNQAZsYAANDAXcBEQFOAYMB/gEIAU4BmwH/ + AQgBTgGZAf8BBwFJAZMB/wEFAUABhwH/AQ4BPgFxAf4CRgFHAYEkAAHsAb8BngH/AfsB9wH0Af8BnAHV + AaUB/wGYAdMBoQH/AYsBywGTAf8BggHGAYkB/wF2AcMBhAH/AXIBwQGAAf8BbgG+AXQB/wH7AfcB9AH/ + AdQBmwFnAf8DPgFrAZIBgQFyAfQB3AGnAXEB/wHcAaYBcAH/AdoBpAFwAf8B2AGiAW8B/wHVAaABbAH/ + AdQBngFrAf8B0gGdAWkB/wHPAZoBaAH/Ac4BmQFmAf8BywGWAWUB/wHJAZQBYgH/AYsBeQFlAfQDPgFr + EAADHQEpAwoBDgMBAQIDcgHqA+UB/wPkAf8DbAHqAwEBAgMKAQ4DHQEpIAADRQF9AT0BUgFyAfQBBgFB + AZAB/wEFAT4BigH/ATQBQwFqAfUDSAGEKAABigF9AXYB6wH7AfcB9AH/AfsB9wH0Af8B+wH3AfQB/wH7 + AfcB9AH/AfsB9wH0Af8B+wH3AfQB/wH7AfcB9AH/AfsB9wH0Af8B+wH3AfQB/wGsAY4BawH4WAADOwFj + A1kBvwNZAb8DOwFjbAADRgF+AXYBbQFoAeMB7QHAAZ8B/wHrAb4BnQH/AecBtwGTAf8B5AGyAYwB/wHi + Aa8BiAH/AeABrAGEAf8B3QGpAYAB/wHcAaUBdQH/A10BygFCAU0BPgcAAT4DAAEoAwABQAMAASADAAEB + AQABAQYAAQEWAAP/gQAC/wH8AT8C/wEAAQMC/wHgAQcBwAEDAQABAwEAAQEBwAEDAYABAQEAAQMBAAEB + AYABAQGAAQEBAAEDAQABAQGAAQEBgAEBAQABAwEAAQEBwAEDAYABAQMAAQECAAGAAQEDAAIBAYABwAED + AwACAQGAAeABBwMAAQECAAHwAQ8DAAEBAcABAwHwAQcDAAEBAYABAQHwAQcB+AIAAQEBgAEBAfABDwH4 + AgABAQHAAQMB8AEPAfgCAAEBAeABBwH4AR8B+AEAAv8B/AE/Av8B+AEACw== + + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/ServiceProperties.Designer.cs b/branches/ph-plugins/ProcessHacker/Components/ServiceProperties.Designer.cs new file mode 100644 index 000000000..8d374d3d0 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/ServiceProperties.Designer.cs @@ -0,0 +1,459 @@ +namespace ProcessHacker.Components +{ + partial class ServiceProperties + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + _provider.DictionaryModified -= new ServiceProvider.ProviderDictionaryModified(_provider_DictionaryModified); + _provider.DictionaryRemoved -= new ServiceProvider.ProviderDictionaryRemoved(_provider_DictionaryRemoved); + + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.listServices = new System.Windows.Forms.ListView(); + this.columnName = new System.Windows.Forms.ColumnHeader(); + this.columnDescription = new System.Windows.Forms.ColumnHeader(); + this.columnStatus = new System.Windows.Forms.ColumnHeader(); + this.panelService = new System.Windows.Forms.Panel(); + this.buttonPermissions = new System.Windows.Forms.Button(); + this.textServiceDll = new System.Windows.Forms.TextBox(); + this.label8 = new System.Windows.Forms.Label(); + this.checkChangePassword = new System.Windows.Forms.CheckBox(); + this.textPassword = new System.Windows.Forms.TextBox(); + this.label7 = new System.Windows.Forms.Label(); + this.buttonDependents = new System.Windows.Forms.Button(); + this.buttonDependencies = new System.Windows.Forms.Button(); + this.textDescription = new System.Windows.Forms.TextBox(); + this.buttonStart = new System.Windows.Forms.Button(); + this.buttonStop = new System.Windows.Forms.Button(); + this.textLoadOrderGroup = new System.Windows.Forms.TextBox(); + this.comboErrorControl = new System.Windows.Forms.ComboBox(); + this.comboStartType = new System.Windows.Forms.ComboBox(); + this.comboType = new System.Windows.Forms.ComboBox(); + this.label6 = new System.Windows.Forms.Label(); + this.label5 = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.buttonApply = new System.Windows.Forms.Button(); + this.label2 = new System.Windows.Forms.Label(); + this.textUserAccount = new System.Windows.Forms.TextBox(); + this.label1 = new System.Windows.Forms.Label(); + this.textServiceBinaryPath = new System.Windows.Forms.TextBox(); + this.labelServiceDisplayName = new System.Windows.Forms.Label(); + this.labelServiceName = new System.Windows.Forms.Label(); + this.toolTip = new System.Windows.Forms.ToolTip(this.components); + this.panelService.SuspendLayout(); + this.SuspendLayout(); + // + // listServices + // + this.listServices.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listServices.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnName, + this.columnDescription, + this.columnStatus}); + this.listServices.FullRowSelect = true; + this.listServices.HideSelection = false; + this.listServices.Location = new System.Drawing.Point(3, 3); + this.listServices.MultiSelect = false; + this.listServices.Name = "listServices"; + this.listServices.ShowItemToolTips = true; + this.listServices.Size = new System.Drawing.Size(387, 136); + this.listServices.Sorting = System.Windows.Forms.SortOrder.Ascending; + this.listServices.TabIndex = 3; + this.listServices.UseCompatibleStateImageBehavior = false; + this.listServices.View = System.Windows.Forms.View.Details; + this.listServices.SelectedIndexChanged += new System.EventHandler(this.listServices_SelectedIndexChanged); + // + // columnName + // + this.columnName.Text = "Name"; + this.columnName.Width = 100; + // + // columnDescription + // + this.columnDescription.Text = "Description"; + this.columnDescription.Width = 140; + // + // columnStatus + // + this.columnStatus.Text = "Status"; + this.columnStatus.Width = 100; + // + // panelService + // + this.panelService.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panelService.Controls.Add(this.buttonPermissions); + this.panelService.Controls.Add(this.textServiceDll); + this.panelService.Controls.Add(this.label8); + this.panelService.Controls.Add(this.checkChangePassword); + this.panelService.Controls.Add(this.textPassword); + this.panelService.Controls.Add(this.label7); + this.panelService.Controls.Add(this.buttonDependents); + this.panelService.Controls.Add(this.buttonDependencies); + this.panelService.Controls.Add(this.textDescription); + this.panelService.Controls.Add(this.buttonStart); + this.panelService.Controls.Add(this.buttonStop); + this.panelService.Controls.Add(this.textLoadOrderGroup); + this.panelService.Controls.Add(this.comboErrorControl); + this.panelService.Controls.Add(this.comboStartType); + this.panelService.Controls.Add(this.comboType); + this.panelService.Controls.Add(this.label6); + this.panelService.Controls.Add(this.label5); + this.panelService.Controls.Add(this.label4); + this.panelService.Controls.Add(this.label3); + this.panelService.Controls.Add(this.buttonApply); + this.panelService.Controls.Add(this.label2); + this.panelService.Controls.Add(this.textUserAccount); + this.panelService.Controls.Add(this.label1); + this.panelService.Controls.Add(this.textServiceBinaryPath); + this.panelService.Controls.Add(this.labelServiceDisplayName); + this.panelService.Controls.Add(this.labelServiceName); + this.panelService.Location = new System.Drawing.Point(3, 145); + this.panelService.Name = "panelService"; + this.panelService.Padding = new System.Windows.Forms.Padding(3, 5, 3, 3); + this.panelService.Size = new System.Drawing.Size(387, 312); + this.panelService.TabIndex = 2; + // + // buttonPermissions + // + this.buttonPermissions.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.buttonPermissions.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonPermissions.Location = new System.Drawing.Point(6, 253); + this.buttonPermissions.Name = "buttonPermissions"; + this.buttonPermissions.Size = new System.Drawing.Size(75, 23); + this.buttonPermissions.TabIndex = 24; + this.buttonPermissions.Text = "Permissions"; + this.buttonPermissions.UseVisualStyleBackColor = true; + this.buttonPermissions.Click += new System.EventHandler(this.buttonPermissions_Click); + // + // textServiceDll + // + this.textServiceDll.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textServiceDll.Location = new System.Drawing.Point(107, 222); + this.textServiceDll.Name = "textServiceDll"; + this.textServiceDll.ReadOnly = true; + this.textServiceDll.Size = new System.Drawing.Size(274, 20); + this.textServiceDll.TabIndex = 23; + // + // label8 + // + this.label8.AutoSize = true; + this.label8.Location = new System.Drawing.Point(6, 225); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(69, 13); + this.label8.TabIndex = 22; + this.label8.Text = "Service DLL:"; + // + // checkChangePassword + // + this.checkChangePassword.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.checkChangePassword.AutoSize = true; + this.checkChangePassword.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkChangePassword.Location = new System.Drawing.Point(364, 197); + this.checkChangePassword.Name = "checkChangePassword"; + this.checkChangePassword.Size = new System.Drawing.Size(35, 18); + this.checkChangePassword.TabIndex = 21; + this.checkChangePassword.Text = " "; + this.toolTip.SetToolTip(this.checkChangePassword, "Change Password"); + this.checkChangePassword.UseVisualStyleBackColor = true; + // + // textPassword + // + this.textPassword.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textPassword.Location = new System.Drawing.Point(107, 196); + this.textPassword.Name = "textPassword"; + this.textPassword.Size = new System.Drawing.Size(251, 20); + this.textPassword.TabIndex = 20; + this.textPassword.Text = "password"; + this.textPassword.UseSystemPasswordChar = true; + this.textPassword.TextChanged += new System.EventHandler(this.textPassword_TextChanged); + // + // label7 + // + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(6, 199); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(56, 13); + this.label7.TabIndex = 19; + this.label7.Text = "Password:"; + // + // buttonDependents + // + this.buttonDependents.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonDependents.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonDependents.Location = new System.Drawing.Point(126, 283); + this.buttonDependents.Name = "buttonDependents"; + this.buttonDependents.Size = new System.Drawing.Size(83, 23); + this.buttonDependents.TabIndex = 18; + this.buttonDependents.Text = "Dependents"; + this.buttonDependents.UseVisualStyleBackColor = true; + this.buttonDependents.Click += new System.EventHandler(this.buttonDependents_Click); + // + // buttonDependencies + // + this.buttonDependencies.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonDependencies.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonDependencies.Location = new System.Drawing.Point(215, 283); + this.buttonDependencies.Name = "buttonDependencies"; + this.buttonDependencies.Size = new System.Drawing.Size(85, 23); + this.buttonDependencies.TabIndex = 18; + this.buttonDependencies.Text = "Dependencies"; + this.buttonDependencies.UseVisualStyleBackColor = true; + this.buttonDependencies.Click += new System.EventHandler(this.buttonDependencies_Click); + // + // textDescription + // + this.textDescription.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textDescription.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.textDescription.Location = new System.Drawing.Point(6, 47); + this.textDescription.Multiline = true; + this.textDescription.Name = "textDescription"; + this.textDescription.ReadOnly = true; + this.textDescription.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.textDescription.Size = new System.Drawing.Size(375, 38); + this.textDescription.TabIndex = 17; + // + // buttonStart + // + this.buttonStart.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.buttonStart.Image = global::ProcessHacker.Properties.Resources.control_play_blue; + this.buttonStart.Location = new System.Drawing.Point(36, 282); + this.buttonStart.Name = "buttonStart"; + this.buttonStart.Size = new System.Drawing.Size(24, 24); + this.buttonStart.TabIndex = 16; + this.toolTip.SetToolTip(this.buttonStart, "Starts the service."); + this.buttonStart.UseVisualStyleBackColor = true; + this.buttonStart.Click += new System.EventHandler(this.buttonStart_Click); + // + // buttonStop + // + this.buttonStop.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.buttonStop.Image = global::ProcessHacker.Properties.Resources.control_stop_blue; + this.buttonStop.Location = new System.Drawing.Point(6, 282); + this.buttonStop.Name = "buttonStop"; + this.buttonStop.Size = new System.Drawing.Size(24, 24); + this.buttonStop.TabIndex = 16; + this.toolTip.SetToolTip(this.buttonStop, "Stops the service."); + this.buttonStop.UseVisualStyleBackColor = true; + this.buttonStop.Click += new System.EventHandler(this.buttonStop_Click); + // + // textLoadOrderGroup + // + this.textLoadOrderGroup.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textLoadOrderGroup.Location = new System.Drawing.Point(240, 118); + this.textLoadOrderGroup.Name = "textLoadOrderGroup"; + this.textLoadOrderGroup.Size = new System.Drawing.Size(141, 20); + this.textLoadOrderGroup.TabIndex = 15; + // + // comboErrorControl + // + this.comboErrorControl.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboErrorControl.FormattingEnabled = true; + this.comboErrorControl.Location = new System.Drawing.Point(80, 118); + this.comboErrorControl.Name = "comboErrorControl"; + this.comboErrorControl.Size = new System.Drawing.Size(109, 21); + this.comboErrorControl.TabIndex = 14; + // + // comboStartType + // + this.comboStartType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboStartType.FormattingEnabled = true; + this.comboStartType.Location = new System.Drawing.Point(260, 91); + this.comboStartType.Name = "comboStartType"; + this.comboStartType.Size = new System.Drawing.Size(121, 21); + this.comboStartType.TabIndex = 13; + // + // comboType + // + this.comboType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboType.FormattingEnabled = true; + this.comboType.Location = new System.Drawing.Point(46, 91); + this.comboType.Name = "comboType"; + this.comboType.Size = new System.Drawing.Size(143, 21); + this.comboType.TabIndex = 12; + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(195, 94); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(59, 13); + this.label6.TabIndex = 11; + this.label6.Text = "Start Type:"; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(6, 121); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(68, 13); + this.label5.TabIndex = 10; + this.label5.Text = "Error Control:"; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(6, 94); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(34, 13); + this.label4.TabIndex = 9; + this.label4.Text = "Type:"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(195, 121); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(39, 13); + this.label3.TabIndex = 8; + this.label3.Text = "Group:"; + // + // buttonApply + // + this.buttonApply.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonApply.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonApply.Location = new System.Drawing.Point(306, 283); + this.buttonApply.Name = "buttonApply"; + this.buttonApply.Size = new System.Drawing.Size(75, 23); + this.buttonApply.TabIndex = 7; + this.buttonApply.Text = "&Apply"; + this.buttonApply.UseVisualStyleBackColor = true; + this.buttonApply.Click += new System.EventHandler(this.buttonApply_Click); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(6, 147); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(64, 13); + this.label2.TabIndex = 5; + this.label2.Text = "Binary Path:"; + // + // textUserAccount + // + this.textUserAccount.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textUserAccount.Location = new System.Drawing.Point(107, 170); + this.textUserAccount.Name = "textUserAccount"; + this.textUserAccount.Size = new System.Drawing.Size(274, 20); + this.textUserAccount.TabIndex = 4; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(6, 173); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(75, 13); + this.label1.TabIndex = 3; + this.label1.Text = "User Account:"; + // + // textServiceBinaryPath + // + this.textServiceBinaryPath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textServiceBinaryPath.Location = new System.Drawing.Point(107, 144); + this.textServiceBinaryPath.Name = "textServiceBinaryPath"; + this.textServiceBinaryPath.Size = new System.Drawing.Size(274, 20); + this.textServiceBinaryPath.TabIndex = 2; + // + // labelServiceDisplayName + // + this.labelServiceDisplayName.AutoSize = true; + this.labelServiceDisplayName.Location = new System.Drawing.Point(6, 26); + this.labelServiceDisplayName.Name = "labelServiceDisplayName"; + this.labelServiceDisplayName.Size = new System.Drawing.Size(111, 13); + this.labelServiceDisplayName.TabIndex = 1; + this.labelServiceDisplayName.Text = "Service Display Name"; + // + // labelServiceName + // + this.labelServiceName.AutoSize = true; + this.labelServiceName.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.labelServiceName.Location = new System.Drawing.Point(6, 5); + this.labelServiceName.Name = "labelServiceName"; + this.labelServiceName.Size = new System.Drawing.Size(86, 13); + this.labelServiceName.TabIndex = 0; + this.labelServiceName.Text = "Service Name"; + // + // ServiceProperties + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.listServices); + this.Controls.Add(this.panelService); + this.Name = "ServiceProperties"; + this.Size = new System.Drawing.Size(393, 460); + this.panelService.ResumeLayout(false); + this.panelService.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.ListView listServices; + private System.Windows.Forms.ColumnHeader columnName; + private System.Windows.Forms.ColumnHeader columnDescription; + private System.Windows.Forms.ColumnHeader columnStatus; + private System.Windows.Forms.Panel panelService; + private System.Windows.Forms.Button buttonStart; + private System.Windows.Forms.Button buttonStop; + private System.Windows.Forms.Button buttonApply; + private System.Windows.Forms.Label labelServiceDisplayName; + private System.Windows.Forms.Label labelServiceName; + private System.Windows.Forms.TextBox textLoadOrderGroup; + private System.Windows.Forms.ComboBox comboErrorControl; + private System.Windows.Forms.ComboBox comboStartType; + private System.Windows.Forms.ComboBox comboType; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox textUserAccount; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox textServiceBinaryPath; + private System.Windows.Forms.TextBox textDescription; + private System.Windows.Forms.Button buttonDependents; + private System.Windows.Forms.Button buttonDependencies; + private System.Windows.Forms.ToolTip toolTip; + private System.Windows.Forms.TextBox textPassword; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.CheckBox checkChangePassword; + private System.Windows.Forms.TextBox textServiceDll; + private System.Windows.Forms.Label label8; + private System.Windows.Forms.Button buttonPermissions; + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/ServiceProperties.cs b/branches/ph-plugins/ProcessHacker/Components/ServiceProperties.cs new file mode 100644 index 000000000..12bcac2df --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/ServiceProperties.cs @@ -0,0 +1,495 @@ +/* + * Process Hacker - + * embeddable service properties control + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.ServiceProcess; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Common.Ui; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; +using ProcessHacker.Native.Security.AccessControl; +using ProcessHacker.UI; +using ProcessHacker.UI.Actions; + +namespace ProcessHacker.Components +{ + public partial class ServiceProperties : UserControl + { + private QueryServiceConfig _oldConfig; + private ServiceProvider _provider; + + public event EventHandler NeedsClose; + + public ServiceProperties(string service) + : this(new string[] { service }) + { } + + public ServiceProperties(string[] services) + { + InitializeComponent(); + + listServices.ListViewItemSorter = new SortedListViewComparer(listServices); + listServices.SetTheme("explorer"); + ColumnSettings.LoadSettings(Properties.Settings.Default.ServiceMiniListColumns, listServices); + + PID = -1; + + _provider = Program.ServiceProvider; + + if (services.Length == 1) + { + this.Text = "Service - " + services[0]; + } + else + { + this.Text = "Services"; + } + + foreach (string s in services) + { + listServices.Items.Add(new ListViewItem(new string[] { s, _provider.Dictionary[s].Status.DisplayName, + _provider.Dictionary[s].Status.ServiceStatusProcess.CurrentState.ToString() })).Name = s; + } + + _provider.DictionaryModified += new ServiceProvider.ProviderDictionaryModified(_provider_DictionaryModified); + _provider.DictionaryRemoved += new ServiceProvider.ProviderDictionaryRemoved(_provider_DictionaryRemoved); + + Utils.Fill(comboErrorControl, typeof(ServiceErrorControl)); + Utils.Fill(comboStartType, typeof(ServiceStartType)); + Utils.Fill(comboType, typeof(ProcessHacker.Native.Objects.ServiceType)); + comboType.Items.Add("Win32OwnProcess, InteractiveProcess"); + comboType.Items.Add("Win32ShareProcess, InteractiveProcess"); + + listServices.Visible = true; + if (listServices.Items.Count > 0) + listServices.Items[0].Selected = true; + + this.UpdateInformation(); + + if (Program.ElevationType == TokenElevationType.Limited) + buttonApply.SetShieldIcon(true); + } + + public int PID { get; set; } + + public ListView List + { + get { return listServices; } + } + + public string ApplyButtonText + { + get { return buttonApply.Text; } + set { buttonApply.Text = value; } + } + + public Button ApplyButton + { + get { return buttonApply; } + } + + public void SaveSettings() + { + Properties.Settings.Default.ServiceMiniListColumns = ColumnSettings.SaveSettings(listServices); + } + + private void Close() + { + this.SaveSettings(); + + if (this.NeedsClose != null) + this.NeedsClose(this, new EventArgs()); + } + + private void _provider_DictionaryRemoved(ServiceItem item) + { + this.BeginInvoke(new MethodInvoker(() => + { + // remove the item from the list if it's there + if (listServices.Items.ContainsKey(item.Status.ServiceName)) + listServices.Items[item.Status.ServiceName].Remove(); + })); + } + + private void _provider_DictionaryModified(ServiceItem oldItem, ServiceItem newItem) + { + if (!this.IsHandleCreated) + return; + + this.BeginInvoke(new MethodInvoker(() => + { + // update the state of the service + if (listServices.Items.ContainsKey(newItem.Status.ServiceName)) + listServices.Items[newItem.Status.ServiceName].SubItems[2].Text = + newItem.Status.ServiceStatusProcess.CurrentState.ToString(); + + // update the start and stop buttons if we have a service selected + if (listServices.SelectedItems.Count == 1) + { + if (listServices.SelectedItems[0].Name == newItem.Status.ServiceName) + { + buttonStart.Enabled = false; + buttonStop.Enabled = false; + + if (newItem.Status.ServiceStatusProcess.CurrentState == ServiceState.Running) + buttonStop.Enabled = true; + else if (newItem.Status.ServiceStatusProcess.CurrentState == ServiceState.Stopped) + buttonStart.Enabled = true; + } + } + + // if the service was just started in this process, add it to the list + if (newItem.Status.ServiceStatusProcess.ProcessID == this.PID && oldItem.Status.ServiceStatusProcess.ProcessID == 0) + { + if (!listServices.Items.ContainsKey(newItem.Status.ServiceName)) + { + listServices.Items.Add(new ListViewItem(new string[] { + newItem.Status.ServiceName, + newItem.Status.DisplayName, + newItem.Status.ServiceStatusProcess.CurrentState.ToString() + })).Name = newItem.Status.ServiceName; + } + } + })); + } + + private void listServices_SelectedIndexChanged(object sender, EventArgs e) + { + this.UpdateInformation(); + } + + private void UpdateInformation() + { + checkChangePassword.Checked = false; + + if (listServices.SelectedItems.Count == 0) + { + buttonApply.Enabled = false; + buttonStart.Enabled = false; + buttonStop.Enabled = false; + buttonDependents.Enabled = false; + buttonDependencies.Enabled = false; + buttonPermissions.Enabled = false; + comboType.Enabled = false; + comboStartType.Enabled = false; + comboErrorControl.Enabled = false; + _oldConfig = new QueryServiceConfig(); + this.ClearControls(); + } + else + { + try + { + buttonApply.Enabled = true; + buttonStart.Enabled = true; + buttonStop.Enabled = true; + buttonDependents.Enabled = true; + buttonDependencies.Enabled = true; + buttonPermissions.Enabled = true; + comboType.Enabled = true; + comboStartType.Enabled = true; + comboErrorControl.Enabled = true; + + try + { + using (var shandle = + new ServiceHandle(listServices.SelectedItems[0].Name, ServiceAccess.QueryConfig)) + _provider.UpdateServiceConfig(listServices.SelectedItems[0].Name, shandle.GetConfig()); + } + catch + { } + + ServiceItem item = _provider.Dictionary[listServices.SelectedItems[0].Name]; + + _oldConfig = item.Config; + _oldConfig.BinaryPathName = FileUtils.GetFileName(_oldConfig.BinaryPathName); + + buttonStart.Enabled = true; + buttonStop.Enabled = true; + + if (item.Status.ServiceStatusProcess.CurrentState == ServiceState.Running) + buttonStart.Enabled = false; + else if (item.Status.ServiceStatusProcess.CurrentState == ServiceState.Stopped) + buttonStop.Enabled = false; + + if ((item.Status.ServiceStatusProcess.ControlsAccepted & ServiceAccept.Stop) == 0) + buttonStop.Enabled = false; + + labelServiceName.Text = item.Status.ServiceName; + labelServiceDisplayName.Text = item.Status.DisplayName; + comboType.SelectedItem = item.Config.ServiceType.ToString(); + + if (item.Config.ServiceType == + (ProcessHacker.Native.Objects.ServiceType.Win32OwnProcess | + ProcessHacker.Native.Objects.ServiceType.InteractiveProcess)) + comboType.SelectedItem = "Win32OwnProcess, InteractiveProcess"; + else if (item.Config.ServiceType == + (ProcessHacker.Native.Objects.ServiceType.Win32ShareProcess | + ProcessHacker.Native.Objects.ServiceType.InteractiveProcess)) + comboType.SelectedItem = "Win32ShareProcess, InteractiveProcess"; + + comboStartType.SelectedItem = item.Config.StartType.ToString(); + comboErrorControl.SelectedItem = item.Config.ErrorControl.ToString(); + textServiceBinaryPath.Text = FileUtils.GetFileName(item.Config.BinaryPathName); + textUserAccount.Text = item.Config.ServiceStartName; + textLoadOrderGroup.Text = item.Config.LoadOrderGroup; + + try + { + using (var shandle + = new ServiceHandle(item.Status.ServiceName, ServiceAccess.QueryConfig)) + textDescription.Text = shandle.GetDescription(); + } + catch + { + textDescription.Text = ""; + } + + textServiceDll.Text = ""; + + if (item.Config.ServiceType == ProcessHacker.Native.Objects.ServiceType.Win32ShareProcess) + { + try + { + using (var key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey( + "SYSTEM\\CurrentControlSet\\Services\\" + item.Status.ServiceName + "\\Parameters")) + textServiceDll.Text = Environment.ExpandEnvironmentVariables((string)key.GetValue("ServiceDll")); + } + catch + { } + } + + try + { + using (ServiceController controller = new ServiceController( + listServices.SelectedItems[0].Name)) + { + if (controller.DependentServices.Length == 0) + buttonDependents.Enabled = false; + if (controller.ServicesDependedOn.Length == 0) + buttonDependencies.Enabled = false; + } + } + catch + { + buttonDependents.Enabled = false; + buttonDependencies.Enabled = false; + } + } + catch (Exception ex) + { + labelServiceName.Text = ex.Message; + _oldConfig = new QueryServiceConfig(); + this.ClearControls(); + } + } + } + + private void ClearControls() + { + labelServiceName.Text = ""; + labelServiceDisplayName.Text = ""; + comboType.Text = ""; + comboStartType.Text = ""; + comboErrorControl.Text = ""; + textServiceBinaryPath.Text = ""; + textUserAccount.Text = ""; + textPassword.Text = "password"; + textLoadOrderGroup.Text = ""; + textDescription.Text = ""; + textServiceDll.Text = ""; + } + + private void buttonApply_Click(object sender, EventArgs e) + { + try + { + string serviceName = listServices.SelectedItems[0].Name; + + ProcessHacker.Native.Objects.ServiceType type; + + if (comboType.SelectedItem.ToString() == "Win32OwnProcess, InteractiveProcess") + type = ProcessHacker.Native.Objects.ServiceType.Win32OwnProcess | + ProcessHacker.Native.Objects.ServiceType.InteractiveProcess; + else if (comboType.SelectedItem.ToString() == "Win32ShareProcess, InteractiveProcess") + type = ProcessHacker.Native.Objects.ServiceType.Win32ShareProcess | + ProcessHacker.Native.Objects.ServiceType.InteractiveProcess; + else + type = (ProcessHacker.Native.Objects.ServiceType) + Enum.Parse(typeof(ProcessHacker.Native.Objects.ServiceType), + comboType.SelectedItem.ToString()); + + string binaryPath = textServiceBinaryPath.Text; + string loadOrderGroup = textLoadOrderGroup.Text; + string userAccount = textUserAccount.Text; + string password = textPassword.Text; + var startType = (ServiceStartType) + Enum.Parse(typeof(ServiceStartType), comboStartType.SelectedItem.ToString()); + var errorControl = (ServiceErrorControl) + Enum.Parse(typeof(ServiceErrorControl), comboErrorControl.SelectedItem.ToString()); + + // Only change the items which the user modified. + if (binaryPath == _oldConfig.BinaryPathName) + binaryPath = null; + if (loadOrderGroup == _oldConfig.LoadOrderGroup) + loadOrderGroup = null; + if (userAccount == _oldConfig.ServiceStartName) + userAccount = null; + if (!checkChangePassword.Checked) + password = null; + + if (type == ProcessHacker.Native.Objects.ServiceType.KernelDriver || + type == ProcessHacker.Native.Objects.ServiceType.FileSystemDriver) + userAccount = null; + + if (Program.ElevationType == TokenElevationType.Full) + { + using (var shandle = new ServiceHandle(serviceName, ServiceAccess.ChangeConfig)) + { + if (!Win32.ChangeServiceConfig(shandle.Handle, + type, startType, errorControl, + binaryPath, loadOrderGroup, IntPtr.Zero, null, userAccount, password, null)) + Win32.ThrowLastError(); + } + } + else + { + string args = "-e -type service -action config -obj \"" + serviceName + "\" -hwnd " + + this.Handle.ToString(); + + args += " -servicetype \"" + comboType.SelectedItem.ToString() + "\""; + args += " -servicestarttype \"" + comboStartType.SelectedItem.ToString() + "\""; + args += " -serviceerrorcontrol \"" + comboErrorControl.SelectedItem.ToString() + "\""; + + if (binaryPath != null) + args += " -servicebinarypath \"" + binaryPath.Replace("\"", "\\\"") + "\""; + if (loadOrderGroup != null) + args += " -serviceloadordergroup \"" + loadOrderGroup.Replace("\"", "\\\"") + "\""; + if (userAccount != null) + args += " -serviceuseraccount \"" + userAccount.Replace("\"", "\\\"") + "\""; + if (password != null) + args += " -servicepassword \"" + password.Replace("\"", "\\\"") + "\""; + + var result = Program.StartProcessHackerAdminWait(args, this.Handle, 2000); + + if (result == WaitResult.Timeout || result == WaitResult.Abandoned) + return; + } + + using (var shandle = new ServiceHandle(serviceName, ServiceAccess.QueryConfig)) + _provider.UpdateServiceConfig(serviceName, shandle.GetConfig()); + + if (listServices.Items.Count == 1) + this.Close(); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to change service configuration", ex); + } + } + + private void buttonStart_Click(object sender, EventArgs e) + { + ServiceActions.Start(this, listServices.SelectedItems[0].Name, false); + } + + private void buttonStop_Click(object sender, EventArgs e) + { + ServiceActions.Stop(this, listServices.SelectedItems[0].Name, false); + } + + private void buttonDependents_Click(object sender, EventArgs e) + { + try + { + using (ServiceController controller = new ServiceController( + listServices.SelectedItems[0].Name)) + { + List dependents = new List(); + + foreach (var service in controller.DependentServices) + dependents.Add(service.ServiceName); + + ServiceWindow sw = new ServiceWindow(dependents.ToArray()); + + sw.ShowDialog(); + } + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to show dependents for the service", ex); + } + } + + private void buttonDependencies_Click(object sender, EventArgs e) + { + try + { + using (ServiceController controller = new ServiceController( + listServices.SelectedItems[0].Name)) + { + List dependencies = new List(); + + foreach (var service in controller.ServicesDependedOn) + dependencies.Add(service.ServiceName); + + ServiceWindow sw = new ServiceWindow(dependencies.ToArray()); + + sw.ShowDialog(); + } + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to show dependencies of the service", ex); + } + } + + private void textPassword_TextChanged(object sender, EventArgs e) + { + checkChangePassword.Checked = true; + } + + private void buttonPermissions_Click(object sender, EventArgs e) + { + try + { + SecurityEditor.EditSecurity( + this, + SecurityEditor.GetSecurable( + NativeTypeFactory.ObjectType.Service, + (access) => new ServiceHandle(listServices.SelectedItems[0].Name, (ServiceAccess)access) + ), + listServices.SelectedItems[0].Name, + NativeTypeFactory.GetAccessEntries(NativeTypeFactory.ObjectType.Service) + ); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to edit security", ex); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/ServiceProperties.resx b/branches/ph-plugins/ProcessHacker/Components/ServiceProperties.resx new file mode 100644 index 000000000..a5979aadf --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/ServiceProperties.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/SplitButton.cs b/branches/ph-plugins/ProcessHacker/Components/SplitButton.cs new file mode 100644 index 000000000..49f3c78ca --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/SplitButton.cs @@ -0,0 +1,855 @@ +//Copyright (c) 2008, wyDay +//All rights reserved. + +//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. + +//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. + +using System; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; +using System.Windows.Forms.VisualStyles; + + +//Get the latest version of SplitButton at: http://wyday.com/splitbutton/ + + +namespace wyDay.Controls +{ + public class SplitButton : Button + { + private PushButtonState _state; + + private const int SplitSectionWidth = 18; + + private static int BorderSize = SystemInformation.Border3DSize.Width * 2; + private bool skipNextOpen = false; + private Rectangle dropDownRectangle = new Rectangle(); + private bool showSplit = false; + + private bool isSplitMenuVisible = false; + + + private ContextMenuStrip m_SplitMenuStrip = null; + private ContextMenu m_SplitMenu = null; + + TextFormatFlags textFormatFlags = TextFormatFlags.Default; + + public SplitButton() + { + this.AutoSize = true; + } + + #region Properties + + [Browsable(false)] + public override ContextMenuStrip ContextMenuStrip + { + get + { + return m_SplitMenuStrip; + } + set + { + m_SplitMenuStrip = value; + } + } + + [DefaultValue(null)] + public ContextMenu SplitMenu + { + get { return m_SplitMenu; } + set + { + //remove the event handlers for the old SplitMenu + if (m_SplitMenu != null) + { + m_SplitMenu.Popup -= new EventHandler(SplitMenu_Popup); + } + + //add the event handlers for the new SplitMenu + if (value != null) + { + ShowSplit = true; + value.Popup += new EventHandler(SplitMenu_Popup); + } + else + ShowSplit = false; + + m_SplitMenu = value; + } + } + + [DefaultValue(null)] + public ContextMenuStrip SplitMenuStrip + { + get + { + return m_SplitMenuStrip; + } + set + { + //remove the event handlers for the old SplitMenuStrip + if (m_SplitMenuStrip != null) + { + m_SplitMenuStrip.Closing -= new ToolStripDropDownClosingEventHandler(SplitMenuStrip_Closing); + m_SplitMenuStrip.Opening -= new CancelEventHandler(SplitMenuStrip_Opening); + } + + //add the event handlers for the new SplitMenuStrip + if (value != null) + { + ShowSplit = true; + value.Closing += new ToolStripDropDownClosingEventHandler(SplitMenuStrip_Closing); + value.Opening += new CancelEventHandler(SplitMenuStrip_Opening); + } + else + ShowSplit = false; + + + m_SplitMenuStrip = value; + } + } + + [DefaultValue(false)] + public bool ShowSplit + { + set + { + if (value != showSplit) + { + showSplit = value; + Invalidate(); + if (this.Parent != null) + { + this.Parent.PerformLayout(); + } + } + } + } + + private PushButtonState State + { + get + { + return _state; + } + set + { + if (!_state.Equals(value)) + { + _state = value; + Invalidate(); + } + } + } + + #endregion Properties + + protected override bool IsInputKey(Keys keyData) + { + if (keyData.Equals(Keys.Down) && showSplit) + { + return true; + } + + else + { + return base.IsInputKey(keyData); + } + } + + protected override void OnGotFocus(EventArgs e) + { + if (!showSplit) + { + base.OnGotFocus(e); + return; + } + + if (!State.Equals(PushButtonState.Pressed) && !State.Equals(PushButtonState.Disabled)) + { + State = PushButtonState.Default; + } + } + + protected override void OnKeyDown(KeyEventArgs kevent) + { + if (showSplit) + { + if (kevent.KeyCode.Equals(Keys.Down) && !isSplitMenuVisible) + { + ShowContextMenuStrip(); + } + + else if (kevent.KeyCode.Equals(Keys.Space) && kevent.Modifiers == Keys.None) + { + State = PushButtonState.Pressed; + } + } + + base.OnKeyDown(kevent); + } + + protected override void OnKeyUp(KeyEventArgs kevent) + { + if (kevent.KeyCode.Equals(Keys.Space)) + { + if (Control.MouseButtons == MouseButtons.None) + { + State = PushButtonState.Normal; + } + } + else if (kevent.KeyCode.Equals(Keys.Apps)) + { + if (Control.MouseButtons == MouseButtons.None && !isSplitMenuVisible) + { + ShowContextMenuStrip(); + } + } + + base.OnKeyUp(kevent); + } + + protected override void OnEnabledChanged(EventArgs e) + { + if (Enabled) + State = PushButtonState.Normal; + else + State = PushButtonState.Disabled; + + base.OnEnabledChanged(e); + } + + protected override void OnLostFocus(EventArgs e) + { + if (!showSplit) + { + base.OnLostFocus(e); + return; + } + + if (!State.Equals(PushButtonState.Pressed) && !State.Equals(PushButtonState.Disabled)) + { + State = PushButtonState.Normal; + } + } + + bool isMouseEntered = false; + + protected override void OnMouseEnter(EventArgs e) + { + if (!showSplit) + { + base.OnMouseEnter(e); + return; + } + + isMouseEntered = true; + + if (!State.Equals(PushButtonState.Pressed) && !State.Equals(PushButtonState.Disabled)) + { + State = PushButtonState.Hot; + } + + } + + protected override void OnMouseLeave(EventArgs e) + { + if (!showSplit) + { + base.OnMouseLeave(e); + return; + } + + isMouseEntered = false; + + if (!State.Equals(PushButtonState.Pressed) && !State.Equals(PushButtonState.Disabled)) + { + if (Focused) + { + State = PushButtonState.Default; + } + + else + { + State = PushButtonState.Normal; + } + } + } + + protected override void OnMouseDown(MouseEventArgs e) + { + if (!showSplit) + { + base.OnMouseDown(e); + return; + } + + //handle ContextMenu re-clicking the drop-down region to close the menu + if (m_SplitMenu != null && e.Button == MouseButtons.Left && !isMouseEntered) + skipNextOpen = true; + + if (dropDownRectangle.Contains(e.Location) && !isSplitMenuVisible && e.Button == MouseButtons.Left) + { + ShowContextMenuStrip(); + } + else + { + State = PushButtonState.Pressed; + } + } + + protected override void OnMouseUp(MouseEventArgs mevent) + { + if (!showSplit) + { + base.OnMouseUp(mevent); + return; + } + + // if the right button was released inside the button + if (mevent.Button == MouseButtons.Right && ClientRectangle.Contains(mevent.Location) && !isSplitMenuVisible) + { + ShowContextMenuStrip(); + } + else if (m_SplitMenuStrip == null && m_SplitMenu == null || !isSplitMenuVisible) + { + SetButtonDrawState(); + + if (ClientRectangle.Contains(mevent.Location) && !dropDownRectangle.Contains(mevent.Location)) + { + OnClick(new EventArgs()); + } + } + } + + protected override void OnPaint(PaintEventArgs pevent) + { + base.OnPaint(pevent); + + if (!showSplit) + return; + + Graphics g = pevent.Graphics; + Rectangle bounds = this.ClientRectangle; + + // draw the button background as according to the current state. + if (State != PushButtonState.Pressed && IsDefault && !Application.RenderWithVisualStyles) + { + Rectangle backgroundBounds = bounds; + backgroundBounds.Inflate(-1, -1); + ButtonRenderer.DrawButton(g, backgroundBounds, State); + + // button renderer doesnt draw the black frame when themes are off + g.DrawRectangle(SystemPens.WindowFrame, 0, 0, bounds.Width - 1, bounds.Height - 1); + } + else + { + ButtonRenderer.DrawButton(g, bounds, State); + } + + // calculate the current dropdown rectangle. + dropDownRectangle = new Rectangle(bounds.Right - SplitSectionWidth, 0, SplitSectionWidth, bounds.Height); + + int internalBorder = BorderSize; + Rectangle focusRect = + new Rectangle(internalBorder - 1, + internalBorder - 1, + bounds.Width - dropDownRectangle.Width - internalBorder, + bounds.Height - (internalBorder * 2) + 2); + + bool drawSplitLine = (State == PushButtonState.Hot || State == PushButtonState.Pressed || !Application.RenderWithVisualStyles); + + + if (RightToLeft == RightToLeft.Yes) + { + dropDownRectangle.X = bounds.Left + 1; + focusRect.X = dropDownRectangle.Right; + + if (drawSplitLine) + { + // draw two lines at the edge of the dropdown button + g.DrawLine(SystemPens.ButtonShadow, bounds.Left + SplitSectionWidth, BorderSize, bounds.Left + SplitSectionWidth, bounds.Bottom - BorderSize); + g.DrawLine(SystemPens.ButtonFace, bounds.Left + SplitSectionWidth + 1, BorderSize, bounds.Left + SplitSectionWidth + 1, bounds.Bottom - BorderSize); + } + } + else + { + if (drawSplitLine) + { + // draw two lines at the edge of the dropdown button + g.DrawLine(SystemPens.ButtonShadow, bounds.Right - SplitSectionWidth, BorderSize, bounds.Right - SplitSectionWidth, bounds.Bottom - BorderSize); + g.DrawLine(SystemPens.ButtonFace, bounds.Right - SplitSectionWidth - 1, BorderSize, bounds.Right - SplitSectionWidth - 1, bounds.Bottom - BorderSize); + } + } + + // Draw an arrow in the correct location + PaintArrow(g, dropDownRectangle); + + //paint the image and text in the "button" part of the splitButton + PaintTextandImage(g, new Rectangle(0, 0, ClientRectangle.Width - SplitSectionWidth, ClientRectangle.Height)); + + // draw the focus rectangle. + if (State != PushButtonState.Pressed && Focused && ShowFocusCues) + { + ControlPaint.DrawFocusRectangle(g, focusRect); + } + } + + private void PaintTextandImage(Graphics g, Rectangle bounds) + { + // Figure out where our text and image should go + Rectangle text_rectangle; + Rectangle image_rectangle; + + CalculateButtonTextAndImageLayout(ref bounds, out text_rectangle, out image_rectangle); + + //draw the image + if (Image != null) + { + if (Enabled) + g.DrawImage(Image, image_rectangle.X, image_rectangle.Y, Image.Width, Image.Height); + else + ControlPaint.DrawImageDisabled(g, Image, image_rectangle.X, image_rectangle.Y, BackColor); + } + + // If we dont' use mnemonic, set formatFlag to NoPrefix as this will show ampersand. + if (!UseMnemonic) + textFormatFlags = textFormatFlags | TextFormatFlags.NoPrefix; + else if (!ShowKeyboardCues) + textFormatFlags = textFormatFlags | TextFormatFlags.HidePrefix; + + //draw the text + if (!string.IsNullOrEmpty(this.Text)) + { + if (Enabled) + TextRenderer.DrawText(g, Text, Font, text_rectangle, SystemColors.ControlText, textFormatFlags); + else + ControlPaint.DrawStringDisabled(g, Text, Font, BackColor, text_rectangle, textFormatFlags); + } + } + + private void PaintArrow(Graphics g, Rectangle dropDownRect) + { + Point middle = new Point(Convert.ToInt32(dropDownRect.Left + dropDownRect.Width / 2), Convert.ToInt32(dropDownRect.Top + dropDownRect.Height / 2)); + + //if the width is odd - favor pushing it over one pixel right. + middle.X += (dropDownRect.Width % 2); + + Point[] arrow = new Point[] { new Point(middle.X - 2, middle.Y - 1), new Point(middle.X + 3, middle.Y - 1), new Point(middle.X, middle.Y + 2) }; + + if (Enabled) + g.FillPolygon(SystemBrushes.ControlText, arrow); + else + g.FillPolygon(SystemBrushes.ButtonShadow, arrow); + } + + public override Size GetPreferredSize(Size proposedSize) + { + Size preferredSize = base.GetPreferredSize(proposedSize); + + //autosize correctly for splitbuttons + if (showSplit) + { + if (AutoSize) + return CalculateButtonAutoSize(); + else if (!string.IsNullOrEmpty(Text) && TextRenderer.MeasureText(Text, Font).Width + SplitSectionWidth > preferredSize.Width) + return preferredSize + new Size(SplitSectionWidth + BorderSize * 2, 0); + } + + return preferredSize; + } + + private Size CalculateButtonAutoSize() + { + Size ret_size = Size.Empty; + Size text_size = TextRenderer.MeasureText(Text, Font); + Size image_size = Image == null ? Size.Empty : Image.Size; + + // Pad the text size + if (Text.Length != 0) + { + text_size.Height += 4; + text_size.Width += 4; + } + + switch (TextImageRelation) + { + case TextImageRelation.Overlay: + ret_size.Height = Math.Max(Text.Length == 0 ? 0 : text_size.Height, image_size.Height); + ret_size.Width = Math.Max(text_size.Width, image_size.Width); + break; + case TextImageRelation.ImageAboveText: + case TextImageRelation.TextAboveImage: + ret_size.Height = text_size.Height + image_size.Height; + ret_size.Width = Math.Max(text_size.Width, image_size.Width); + break; + case TextImageRelation.ImageBeforeText: + case TextImageRelation.TextBeforeImage: + ret_size.Height = Math.Max(text_size.Height, image_size.Height); + ret_size.Width = text_size.Width + image_size.Width; + break; + } + + // Pad the result + ret_size.Height += (Padding.Vertical + 6); + ret_size.Width += (Padding.Horizontal + 6); + + //pad the splitButton arrow region + if (showSplit) + ret_size.Width += SplitSectionWidth; + + return ret_size; + } + + #region Button Layout Calculations + + //The following layout functions were taken from Mono's Windows.Forms + //implementation, specifically "ThemeWin32Classic.cs", + //then modified to fit the context of this splitButton + + private void CalculateButtonTextAndImageLayout(ref Rectangle content_rect, out Rectangle textRectangle, out Rectangle imageRectangle) + { + Size text_size = TextRenderer.MeasureText(Text, Font, content_rect.Size, textFormatFlags); + Size image_size = Image == null ? Size.Empty : Image.Size; + + textRectangle = Rectangle.Empty; + imageRectangle = Rectangle.Empty; + + switch (TextImageRelation) + { + case TextImageRelation.Overlay: + // Overlay is easy, text always goes here + textRectangle = OverlayObjectRect(ref content_rect, ref text_size, TextAlign); // Rectangle.Inflate(content_rect, -4, -4); + + //Offset on Windows 98 style when button is pressed + if (_state == PushButtonState.Pressed && !Application.RenderWithVisualStyles) + textRectangle.Offset(1, 1); + + // Image is dependent on ImageAlign + if (Image != null) + imageRectangle = OverlayObjectRect(ref content_rect, ref image_size, ImageAlign); + + break; + case TextImageRelation.ImageAboveText: + content_rect.Inflate(-4, -4); + LayoutTextAboveOrBelowImage(content_rect, false, text_size, image_size, out textRectangle, out imageRectangle); + break; + case TextImageRelation.TextAboveImage: + content_rect.Inflate(-4, -4); + LayoutTextAboveOrBelowImage(content_rect, true, text_size, image_size, out textRectangle, out imageRectangle); + break; + case TextImageRelation.ImageBeforeText: + content_rect.Inflate(-4, -4); + LayoutTextBeforeOrAfterImage(content_rect, false, text_size, image_size, out textRectangle, out imageRectangle); + break; + case TextImageRelation.TextBeforeImage: + content_rect.Inflate(-4, -4); + LayoutTextBeforeOrAfterImage(content_rect, true, text_size, image_size, out textRectangle, out imageRectangle); + break; + } + } + + private Rectangle OverlayObjectRect(ref Rectangle container, ref Size sizeOfObject, System.Drawing.ContentAlignment alignment) + { + int x, y; + + switch (alignment) + { + case System.Drawing.ContentAlignment.TopLeft: + x = 4; + y = 4; + break; + case System.Drawing.ContentAlignment.TopCenter: + x = (container.Width - sizeOfObject.Width) / 2; + y = 4; + break; + case System.Drawing.ContentAlignment.TopRight: + x = container.Width - sizeOfObject.Width - 4; + y = 4; + break; + case System.Drawing.ContentAlignment.MiddleLeft: + x = 4; + y = (container.Height - sizeOfObject.Height) / 2; + break; + case System.Drawing.ContentAlignment.MiddleCenter: + x = (container.Width - sizeOfObject.Width) / 2; + y = (container.Height - sizeOfObject.Height) / 2; + break; + case System.Drawing.ContentAlignment.MiddleRight: + x = container.Width - sizeOfObject.Width - 4; + y = (container.Height - sizeOfObject.Height) / 2; + break; + case System.Drawing.ContentAlignment.BottomLeft: + x = 4; + y = container.Height - sizeOfObject.Height - 4; + break; + case System.Drawing.ContentAlignment.BottomCenter: + x = (container.Width - sizeOfObject.Width) / 2; + y = container.Height - sizeOfObject.Height - 4; + break; + case System.Drawing.ContentAlignment.BottomRight: + x = container.Width - sizeOfObject.Width - 4; + y = container.Height - sizeOfObject.Height - 4; + break; + default: + x = 4; + y = 4; + break; + } + + return new Rectangle(x, y, sizeOfObject.Width, sizeOfObject.Height); + } + + private void LayoutTextBeforeOrAfterImage(Rectangle totalArea, bool textFirst, Size textSize, Size imageSize, out Rectangle textRect, out Rectangle imageRect) + { + int element_spacing = 0; // Spacing between the Text and the Image + int total_width = textSize.Width + element_spacing + imageSize.Width; + + if (!textFirst) + element_spacing += 2; + + // If the text is too big, chop it down to the size we have available to it + if (total_width > totalArea.Width) + { + textSize.Width = totalArea.Width - element_spacing - imageSize.Width; + total_width = totalArea.Width; + } + + int excess_width = totalArea.Width - total_width; + int offset = 0; + + Rectangle final_text_rect; + Rectangle final_image_rect; + + HorizontalAlignment h_text = GetHorizontalAlignment(TextAlign); + HorizontalAlignment h_image = GetHorizontalAlignment(ImageAlign); + + if (h_image == HorizontalAlignment.Left) + offset = 0; + else if (h_image == HorizontalAlignment.Right && h_text == HorizontalAlignment.Right) + offset = excess_width; + else if (h_image == HorizontalAlignment.Center && (h_text == HorizontalAlignment.Left || h_text == HorizontalAlignment.Center)) + offset += (int)(excess_width / 3); + else + offset += (int)(2 * (excess_width / 3)); + + if (textFirst) + { + final_text_rect = new Rectangle(totalArea.Left + offset, AlignInRectangle(totalArea, textSize, TextAlign).Top, textSize.Width, textSize.Height); + final_image_rect = new Rectangle(final_text_rect.Right + element_spacing, AlignInRectangle(totalArea, imageSize, ImageAlign).Top, imageSize.Width, imageSize.Height); + } + else + { + final_image_rect = new Rectangle(totalArea.Left + offset, AlignInRectangle(totalArea, imageSize, ImageAlign).Top, imageSize.Width, imageSize.Height); + final_text_rect = new Rectangle(final_image_rect.Right + element_spacing, AlignInRectangle(totalArea, textSize, TextAlign).Top, textSize.Width, textSize.Height); + } + + textRect = final_text_rect; + imageRect = final_image_rect; + } + + private void LayoutTextAboveOrBelowImage(Rectangle totalArea, bool textFirst, Size textSize, Size imageSize, out Rectangle textRect, out Rectangle imageRect) + { + int element_spacing = 0; // Spacing between the Text and the Image + int total_height = textSize.Height + element_spacing + imageSize.Height; + + if (textFirst) + element_spacing += 2; + + if (textSize.Width > totalArea.Width) + textSize.Width = totalArea.Width; + + // If the there isn't enough room and we're text first, cut out the image + if (total_height > totalArea.Height && textFirst) + { + imageSize = Size.Empty; + total_height = totalArea.Height; + } + + int excess_height = totalArea.Height - total_height; + int offset = 0; + + Rectangle final_text_rect; + Rectangle final_image_rect; + + VerticalAlignment v_text = GetVerticalAlignment(TextAlign); + VerticalAlignment v_image = GetVerticalAlignment(ImageAlign); + + if (v_image == VerticalAlignment.Top) + offset = 0; + else if (v_image == VerticalAlignment.Bottom && v_text == VerticalAlignment.Bottom) + offset = excess_height; + else if (v_image == VerticalAlignment.Center && (v_text == VerticalAlignment.Top || v_text == VerticalAlignment.Center)) + offset += (int)(excess_height / 3); + else + offset += (int)(2 * (excess_height / 3)); + + if (textFirst) + { + final_text_rect = new Rectangle(AlignInRectangle(totalArea, textSize, TextAlign).Left, totalArea.Top + offset, textSize.Width, textSize.Height); + final_image_rect = new Rectangle(AlignInRectangle(totalArea, imageSize, ImageAlign).Left, final_text_rect.Bottom + element_spacing, imageSize.Width, imageSize.Height); + } + else + { + final_image_rect = new Rectangle(AlignInRectangle(totalArea, imageSize, ImageAlign).Left, totalArea.Top + offset, imageSize.Width, imageSize.Height); + final_text_rect = new Rectangle(AlignInRectangle(totalArea, textSize, TextAlign).Left, final_image_rect.Bottom + element_spacing, textSize.Width, textSize.Height); + + if (final_text_rect.Bottom > totalArea.Bottom) + final_text_rect.Y = totalArea.Top; + } + + textRect = final_text_rect; + imageRect = final_image_rect; + } + + private HorizontalAlignment GetHorizontalAlignment(System.Drawing.ContentAlignment align) + { + switch (align) + { + case System.Drawing.ContentAlignment.BottomLeft: + case System.Drawing.ContentAlignment.MiddleLeft: + case System.Drawing.ContentAlignment.TopLeft: + return HorizontalAlignment.Left; + case System.Drawing.ContentAlignment.BottomCenter: + case System.Drawing.ContentAlignment.MiddleCenter: + case System.Drawing.ContentAlignment.TopCenter: + return HorizontalAlignment.Center; + case System.Drawing.ContentAlignment.BottomRight: + case System.Drawing.ContentAlignment.MiddleRight: + case System.Drawing.ContentAlignment.TopRight: + return HorizontalAlignment.Right; + } + + return HorizontalAlignment.Left; + } + + private VerticalAlignment GetVerticalAlignment(System.Drawing.ContentAlignment align) + { + switch (align) + { + case System.Drawing.ContentAlignment.TopLeft: + case System.Drawing.ContentAlignment.TopCenter: + case System.Drawing.ContentAlignment.TopRight: + return VerticalAlignment.Top; + case System.Drawing.ContentAlignment.MiddleLeft: + case System.Drawing.ContentAlignment.MiddleCenter: + case System.Drawing.ContentAlignment.MiddleRight: + return VerticalAlignment.Center; + case System.Drawing.ContentAlignment.BottomLeft: + case System.Drawing.ContentAlignment.BottomCenter: + case System.Drawing.ContentAlignment.BottomRight: + return VerticalAlignment.Bottom; + } + + return VerticalAlignment.Top; + } + + internal Rectangle AlignInRectangle(Rectangle outer, Size inner, System.Drawing.ContentAlignment align) + { + int x = 0; + int y = 0; + + if (align == System.Drawing.ContentAlignment.BottomLeft || align == System.Drawing.ContentAlignment.MiddleLeft || align == System.Drawing.ContentAlignment.TopLeft) + x = outer.X; + else if (align == System.Drawing.ContentAlignment.BottomCenter || align == System.Drawing.ContentAlignment.MiddleCenter || align == System.Drawing.ContentAlignment.TopCenter) + x = Math.Max(outer.X + ((outer.Width - inner.Width) / 2), outer.Left); + else if (align == System.Drawing.ContentAlignment.BottomRight || align == System.Drawing.ContentAlignment.MiddleRight || align == System.Drawing.ContentAlignment.TopRight) + x = outer.Right - inner.Width; + if (align == System.Drawing.ContentAlignment.TopCenter || align == System.Drawing.ContentAlignment.TopLeft || align == System.Drawing.ContentAlignment.TopRight) + y = outer.Y; + else if (align == System.Drawing.ContentAlignment.MiddleCenter || align == System.Drawing.ContentAlignment.MiddleLeft || align == System.Drawing.ContentAlignment.MiddleRight) + y = outer.Y + (outer.Height - inner.Height) / 2; + else if (align == System.Drawing.ContentAlignment.BottomCenter || align == System.Drawing.ContentAlignment.BottomRight || align == System.Drawing.ContentAlignment.BottomLeft) + y = outer.Bottom - inner.Height; + + return new Rectangle(x, y, Math.Min(inner.Width, outer.Width), Math.Min(inner.Height, outer.Height)); + } + + #endregion Button Layout Calculations + + + private void ShowContextMenuStrip() + { + if (skipNextOpen) + { + // we were called because we're closing the context menu strip + // when clicking the dropdown button. + skipNextOpen = false; + return; + } + + State = PushButtonState.Pressed; + + if (m_SplitMenu != null) + { + m_SplitMenu.Show(this, new Point(0, Height)); + } + else if (m_SplitMenuStrip != null) + { + m_SplitMenuStrip.Show(this, new Point(0, Height), ToolStripDropDownDirection.BelowRight); + } + } + + void SplitMenuStrip_Opening(object sender, CancelEventArgs e) + { + isSplitMenuVisible = true; + } + + void SplitMenuStrip_Closing(object sender, ToolStripDropDownClosingEventArgs e) + { + isSplitMenuVisible = false; + + SetButtonDrawState(); + + if (e.CloseReason == ToolStripDropDownCloseReason.AppClicked) + { + skipNextOpen = (dropDownRectangle.Contains(this.PointToClient(Cursor.Position))) && Control.MouseButtons == MouseButtons.Left; + } + } + + + void SplitMenu_Popup(object sender, EventArgs e) + { + isSplitMenuVisible = true; + } + + protected override void WndProc(ref Message m) + { + //0x0212 == WM_EXITMENULOOP + if (m.Msg == 0x0212) + { + //this message is only sent when a ContextMenu is closed (not a ContextMenuStrip) + isSplitMenuVisible = false; + SetButtonDrawState(); + } + + base.WndProc(ref m); + } + + private void SetButtonDrawState() + { + if (Bounds.Contains(Parent.PointToClient(Cursor.Position))) + { + State = PushButtonState.Hot; + } + else if (Focused) + { + State = PushButtonState.Default; + } + else if (!Enabled) + { + State = PushButtonState.Disabled; + } + else + { + State = PushButtonState.Normal; + } + } + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/StructViewer.Designer.cs b/branches/ph-plugins/ProcessHacker/Components/StructViewer.Designer.cs new file mode 100644 index 000000000..f9c95d1bc --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/StructViewer.Designer.cs @@ -0,0 +1,164 @@ +namespace ProcessHacker.Components +{ + partial class StructViewer + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.treeStruct = new Aga.Controls.Tree.TreeViewAdv(); + this.columnName = new Aga.Controls.Tree.TreeColumn(); + this.columnValue = new Aga.Controls.Tree.TreeColumn(); + this.nodeName = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.nodeValue = new Aga.Controls.Tree.NodeControls.NodeTextBox(); + this.menuStruct = new System.Windows.Forms.ContextMenu(); + this.numbersMenuItem = new System.Windows.Forms.MenuItem(); + this.decMenuItem = new System.Windows.Forms.MenuItem(); + this.hexMenuItem = new System.Windows.Forms.MenuItem(); + this.copyMenuItem = new System.Windows.Forms.MenuItem(); + this.vistaMenu = new wyDay.Controls.VistaMenu(this.components); + ((System.ComponentModel.ISupportInitialize)(this.vistaMenu)).BeginInit(); + this.SuspendLayout(); + // + // treeStruct + // + this.treeStruct.BackColor = System.Drawing.SystemColors.Window; + this.treeStruct.Columns.Add(this.columnName); + this.treeStruct.Columns.Add(this.columnValue); + this.treeStruct.DefaultToolTipProvider = null; + this.treeStruct.Dock = System.Windows.Forms.DockStyle.Fill; + this.treeStruct.DragDropMarkColor = System.Drawing.Color.Black; + this.treeStruct.FullRowSelect = true; + this.treeStruct.GridLineStyle = Aga.Controls.Tree.GridLineStyle.Horizontal; + this.treeStruct.LineColor = System.Drawing.SystemColors.ControlDark; + this.treeStruct.Location = new System.Drawing.Point(0, 0); + this.treeStruct.Model = null; + this.treeStruct.Name = "treeStruct"; + this.treeStruct.NodeControls.Add(this.nodeName); + this.treeStruct.NodeControls.Add(this.nodeValue); + this.treeStruct.SelectedNode = null; + this.treeStruct.SelectionMode = Aga.Controls.Tree.TreeSelectionMode.Multi; + this.treeStruct.ShowNodeToolTips = true; + this.treeStruct.Size = new System.Drawing.Size(362, 331); + this.treeStruct.TabIndex = 0; + this.treeStruct.UseColumns = true; + // + // columnName + // + this.columnName.Header = "Name"; + this.columnName.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnName.TooltipText = null; + this.columnName.Width = 200; + // + // columnValue + // + this.columnValue.Header = "Value"; + this.columnValue.SortOrder = System.Windows.Forms.SortOrder.None; + this.columnValue.TooltipText = null; + this.columnValue.Width = 200; + // + // nodeName + // + this.nodeName.DataPropertyName = "Name"; + this.nodeName.EditEnabled = false; + this.nodeName.IncrementalSearchEnabled = true; + this.nodeName.LeftMargin = 3; + this.nodeName.ParentColumn = this.columnName; + this.nodeName.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // nodeValue + // + this.nodeValue.DataPropertyName = "Value"; + this.nodeValue.EditEnabled = false; + this.nodeValue.IncrementalSearchEnabled = true; + this.nodeValue.LeftMargin = 3; + this.nodeValue.ParentColumn = this.columnValue; + this.nodeValue.Trimming = System.Drawing.StringTrimming.EllipsisCharacter; + // + // menuStruct + // + this.menuStruct.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.numbersMenuItem, + this.copyMenuItem}); + this.menuStruct.Popup += new System.EventHandler(this.menuStruct_Popup); + // + // numbersMenuItem + // + this.numbersMenuItem.Index = 0; + this.numbersMenuItem.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.decMenuItem, + this.hexMenuItem}); + this.numbersMenuItem.Text = "&Numbers"; + // + // decMenuItem + // + this.decMenuItem.Index = 0; + this.decMenuItem.Text = "&Decimal"; + this.decMenuItem.Click += new System.EventHandler(this.decMenuItem_Click); + // + // hexMenuItem + // + this.hexMenuItem.Index = 1; + this.hexMenuItem.Text = "&Hexadecimal"; + this.hexMenuItem.Click += new System.EventHandler(this.hexMenuItem_Click); + // + // copyMenuItem + // + this.vistaMenu.SetImage(this.copyMenuItem, global::ProcessHacker.Properties.Resources.page_copy); + this.copyMenuItem.Index = 1; + this.copyMenuItem.Text = "&Copy"; + // + // vistaMenu + // + this.vistaMenu.ContainerControl = this; + // + // StructViewer + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.treeStruct); + this.Name = "StructViewer"; + this.Size = new System.Drawing.Size(362, 331); + ((System.ComponentModel.ISupportInitialize)(this.vistaMenu)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private Aga.Controls.Tree.TreeViewAdv treeStruct; + private Aga.Controls.Tree.TreeColumn columnName; + private Aga.Controls.Tree.TreeColumn columnValue; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeName; + private Aga.Controls.Tree.NodeControls.NodeTextBox nodeValue; + private System.Windows.Forms.ContextMenu menuStruct; + private System.Windows.Forms.MenuItem numbersMenuItem; + private System.Windows.Forms.MenuItem decMenuItem; + private System.Windows.Forms.MenuItem hexMenuItem; + private System.Windows.Forms.MenuItem copyMenuItem; + private wyDay.Controls.VistaMenu vistaMenu; + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/StructViewer.cs b/branches/ph-plugins/ProcessHacker/Components/StructViewer.cs new file mode 100644 index 000000000..06a7ccc54 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/StructViewer.cs @@ -0,0 +1,215 @@ +/* + * Process Hacker - + * struct viewer control + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Windows.Forms; +using Aga.Controls.Tree; +using ProcessHacker.Common; +using ProcessHacker.Native; +using ProcessHacker.Structs; +using ProcessHacker.UI; + +namespace ProcessHacker.Components +{ + public partial class StructViewer : UserControl + { + private StructModel _model = new StructModel(); + int _pid; + IntPtr _address; + StructDef _struct; + + public StructViewer(int pid, IntPtr address, StructDef struc) + { + InitializeComponent(); + + _pid = pid; + _address = address; + _struct = struc; + treeStruct.Model = _model; + treeStruct.ContextMenu = menuStruct; + + GenericViewMenu.AddMenuItems(copyMenuItem.MenuItems, treeStruct); + + try + { + FieldValue[] values; + + _struct.Offset = address; + _struct.IOProvider = new ProcessMemoryIO(pid); + _struct.Structs = Program.Structs; + values = _struct.Read(); + + _model.Nodes.Add(new StructNode(new FieldValue() + { Name = "Struct", FieldType = FieldType.StringUTF16, Value = "" })); + + foreach (FieldValue val in values) + this.AddNode(_model.Nodes[0], val); + + treeStruct.Root.Children[0].IsExpanded = true; + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to view the struct", ex); + this.Error = true; + } + } + + private void AddNode(Node node, FieldValue value) + { + StructNode newNode = new StructNode(value); + + if (value.Value is FieldValue[]) + { + foreach (FieldValue val in (FieldValue[])value.Value) + AddNode(newNode, val); + } + + node.Nodes.Add(newNode); + } + + public bool Error { get; private set; } + + private void menuStruct_Popup(object sender, EventArgs e) + { + if (treeStruct.SelectedNodes.Count == 0) + { + copyMenuItem.Enabled = false; + } + else + { + copyMenuItem.Enabled = true; + } + + decMenuItem.Checked = false; + hexMenuItem.Checked = false; + + if (_model.IntegerDisplayBase == IntegerDisplayBase.Decimal) + decMenuItem.Checked = true; + else if (_model.IntegerDisplayBase == IntegerDisplayBase.Hexadecimal) + hexMenuItem.Checked = true; + } + + private void decMenuItem_Click(object sender, EventArgs e) + { + _model.IntegerDisplayBase = IntegerDisplayBase.Decimal; + _model.OnStructureChanged(new TreePathEventArgs(new TreePath())); + } + + private void hexMenuItem_Click(object sender, EventArgs e) + { + _model.IntegerDisplayBase = IntegerDisplayBase.Hexadecimal; + _model.OnStructureChanged(new TreePathEventArgs(new TreePath())); + } + } + + public enum IntegerDisplayBase + { + Decimal, + Hexadecimal + } + + public class StructModel : TreeModel + { + public IntegerDisplayBase IntegerDisplayBase { get; set; } + } + + public class StructNode : Node + { + private FieldValue _value; + + public StructNode(FieldValue value) + { + _value = value; + } + + public string Name + { + get { return _value.Name; } + } + + public string Value + { + get + { + FieldType type = _value.FieldType & (~FieldType.Array) & (~FieldType.Pointer); + + if ((_value.FieldType & FieldType.Array) != 0) + { + int memberCount = ((FieldValue[])_value.Value).Length; + + if (_value.StructName != null) + return _value.StructName + "[" + memberCount.ToString() + "]"; + else + return type.ToString() + "[" + memberCount.ToString() + "]"; + } + + if (_value.StructName != null) + return _value.StructName; + + if (_value.Value == null) + return "null"; + + IntegerDisplayBase b = (this.FindModel() as StructModel).IntegerDisplayBase; + string formatStr = "{0:d}"; + + switch (b) + { + case IntegerDisplayBase.Decimal: + formatStr = "{0:d}"; + break; + case IntegerDisplayBase.Hexadecimal: + formatStr = "0x{0:x}"; + break; + } + + switch (type) + { + case FieldType.Bool32: + case FieldType.Bool8: + return ((bool)_value.Value) ? "True" : "False"; + case FieldType.CharASCII: + case FieldType.CharUTF16: + return ((char)_value.Value).ToString(); + case FieldType.Double: + case FieldType.Single: + return ((double)_value.Value).ToString(); + case FieldType.Int16: + case FieldType.Int32: + case FieldType.Int64: + case FieldType.Int8: + case FieldType.UInt16: + case FieldType.UInt32: + case FieldType.UInt64: + case FieldType.UInt8: + return string.Format(formatStr, long.Parse(_value.Value.ToString())); + case FieldType.PVoid: + return Utils.FormatAddress(long.Parse(_value.Value.ToString()).ToIntPtr()); + case FieldType.StringASCII: + case FieldType.StringUTF16: + return _value.Value.ToString(); + default: + return _value.Value.ToString(); + } + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/StructViewer.resx b/branches/ph-plugins/ProcessHacker/Components/StructViewer.resx new file mode 100644 index 000000000..62e3a554d --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/StructViewer.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 132, 17 + + + 132, 17 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/TargetWindowButton.cs b/branches/ph-plugins/ProcessHacker/Components/TargetWindowButton.cs new file mode 100644 index 000000000..1c5723060 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/TargetWindowButton.cs @@ -0,0 +1,192 @@ +/* + * Process Hacker - + * easy window finder + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Windows.Forms; +using ProcessHacker.Native.Api; + +namespace ProcessHacker.Components +{ + public delegate void TargetWindowFoundDelegate(int pid, int tid); + + public class TargetWindowButton : ToolStripButton + { + public event TargetWindowFoundDelegate TargetWindowFound; + + private Control _parent; + private Control _dummy; + private IntPtr _currentHWnd; + private bool _targeting = false; + + public TargetWindowButton() + { + this.Image = Properties.Resources.application; + this.DisplayStyle = ToolStripItemDisplayStyle.Image; + this.Text = "Find Window"; + this.ToolTipText = "Find Window"; + + _dummy = new Control(); + _dummy.MouseMove += dummy_MouseMove; + _dummy.MouseUp += dummy_MouseUp; + } + + private Form FindParentForm(Control c) + { + if (c == null) + return null; + if (c is Form) + return c as Form; + + return this.FindParentForm(c.Parent); + } + + private void DrawWindowRectangle(IntPtr hWnd) + { + Rect rect; + + Win32.GetWindowRect(hWnd, out rect); + + IntPtr windowDc = Win32.GetWindowDC(hWnd); + + if (windowDc != IntPtr.Zero) + { + // Pen width of system border width times 3. + int penWidth = Win32.GetSystemMetrics(5) * 3; + // Save the DC. + int oldDc = Win32.SaveDC(windowDc); + // Get an inversion effect. + Win32.SetROP2(windowDc, GdiBlendMode.Not); + + // Create a pen. + IntPtr pen = Win32.CreatePen(GdiPenStyle.InsideFrame, penWidth, IntPtr.Zero); + Win32.SelectObject(windowDc, pen); + // Get the null brush. + IntPtr brush = Win32.GetStockObject(GdiStockObject.NullBrush); + Win32.SelectObject(windowDc, brush); + // Draw the rectangle. + Win32.Rectangle(windowDc, 0, 0, rect.Right - rect.Left, rect.Bottom - rect.Top); + + // Delete the pen. + Win32.DeleteObject(pen); + // Restore and release the old DC. + Win32.RestoreDC(windowDc, oldDc); + Win32.ReleaseDC(hWnd, windowDc); + } + } + + private void RedrawWindow(IntPtr hWnd) + { + this.RedrawWindow(hWnd, true); + } + + private void RedrawWindow(IntPtr hWnd, bool workaround) + { + if (!Win32.RedrawWindow( + hWnd, + IntPtr.Zero, + IntPtr.Zero, + RedrawWindowFlags.Invalidate | // redraws the window + RedrawWindowFlags.Erase | // for those toolbar backgrounds and empty forms + RedrawWindowFlags.UpdateNow | + RedrawWindowFlags.AllChildren | + RedrawWindowFlags.Frame // important, even more so without desktop composition + ) && workaround) + { + // Since the rectangle is just an inversion we can redo it. + DrawWindowRectangle(hWnd); + } + } + + protected override void OnParentChanged(ToolStrip oldParent, ToolStrip newParent) + { + _parent = newParent; + } + + protected override void OnMouseDown(MouseEventArgs e) + { + // Direct all mouse events to the dummy control. + Win32.SetCapture(_dummy.Handle); + _targeting = true; + this.FindParentForm(_parent).SendToBack(); + + dummy_MouseMove(null, null); + } + + protected override void OnClick(EventArgs e) + { + // Handles the case where the user simply clicks on the button. + dummy_MouseUp(null, null); + } + + void dummy_MouseMove(object sender, MouseEventArgs e) + { + if (!_targeting) + return; + + IntPtr oldHWnd = _currentHWnd; + + // Get the window at the mouse position. + _currentHWnd = Win32.WindowFromPoint(Control.MousePosition); + + // Don't paint the window again. + if (_currentHWnd == oldHWnd) + return; + + // Get the old window to repaint its border (since we painted all over it). + if (oldHWnd != IntPtr.Zero) + this.RedrawWindow(oldHWnd); + + bool isPhWindow = false; + int pid, tid; + + tid = Win32.GetWindowThreadProcessId(_currentHWnd, out pid); + isPhWindow = pid == Program.CurrentProcessId; + + // Draw a rectangle over the current window. + if ( + _currentHWnd != IntPtr.Zero && + !isPhWindow // don't paint on ourself + ) + this.DrawWindowRectangle(_currentHWnd); + } + + void dummy_MouseUp(object sender, MouseEventArgs e) + { + this.FindParentForm(_parent).BringToFront(); + _targeting = false; + Win32.ReleaseCapture(); + + if (_currentHWnd != IntPtr.Zero) + { + // Redraw the window we found. + this.RedrawWindow(_currentHWnd, false); + + int pid, tid; + + tid = Win32.GetWindowThreadProcessId(_currentHWnd, out pid); + + if (this.TargetWindowFound != null) + this.TargetWindowFound(pid, tid); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/TaskDialog/ActiveTaskDialog.cs b/branches/ph-plugins/ProcessHacker/Components/TaskDialog/ActiveTaskDialog.cs new file mode 100644 index 000000000..eb0272f19 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/TaskDialog/ActiveTaskDialog.cs @@ -0,0 +1,428 @@ +//------------------------------------------------------------------ +// +// A P/Invoke wrapper for TaskDialog. Usability was given preference to perf and size. +// +// +// +//------------------------------------------------------------------ + +namespace ProcessHacker.Components +{ + using System; + using System.Drawing; + using System.Windows.Forms; + using System.Runtime.InteropServices; + using System.Diagnostics.CodeAnalysis; + + /// + /// The active Task Dialog window. Provides several methods for acting on the active TaskDialog. + /// You should not use this object after the TaskDialog Destroy notification callback. Doing so + /// will result in undefined behavior and likely crash. + /// + public class ActiveTaskDialog : IWin32Window + { + /// + /// The Task Dialog's window handle. + /// + [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] // We don't own the window. + private IntPtr handle; + + /// + /// Creates a ActiveTaskDialog. + /// + /// The Task Dialog's window handle. + internal ActiveTaskDialog(IntPtr handle) + { + if (handle == IntPtr.Zero) + { + throw new ArgumentNullException("handle"); + } + + this.handle = handle; + } + + /// + /// The Task Dialog's window handle. + /// + public IntPtr Handle + { + get { return this.handle; } + } + + //// Not supported. Task Dialog Spec does not indicate what this is for. + ////public void NavigatePage() + ////{ + //// // TDM_NAVIGATE_PAGE = WM_USER+101, + //// UnsafeNativeMethods.SendMessage( + //// this.windowHandle, + //// (uint)UnsafeNativeMethods.TASKDIALOG_MESSAGES.TDM_NAVIGATE_PAGE, + //// IntPtr.Zero, + //// //a UnsafeNativeMethods.TASKDIALOGCONFIG value); + ////} + + /// + /// Simulate the action of a button click in the TaskDialog. This can be a DialogResult value + /// or the ButtonID set on a TasDialogButton set on TaskDialog.Buttons. + /// + /// Indicates the button ID to be selected. + /// If the function succeeds the return value is true. + public bool ClickButton(int buttonId) + { + // TDM_CLICK_BUTTON = WM_USER+102, // wParam = Button ID + return UnsafeNativeMethods.SendMessage( + this.handle, + (uint)UnsafeNativeMethods.TASKDIALOG_MESSAGES.TDM_CLICK_BUTTON, + (IntPtr)buttonId, + IntPtr.Zero) != IntPtr.Zero; + } + + /// + /// Used to indicate whether the hosted progress bar should be displayed in marquee mode or not. + /// + /// Specifies whether the progress bar sbould be shown in Marquee mode. + /// A value of true turns on Marquee mode. + /// If the function succeeds the return value is true. + public bool SetMarqueeProgressBar(bool marquee) + { + // TDM_SET_MARQUEE_PROGRESS_BAR = WM_USER+103, // wParam = 0 (nonMarque) wParam != 0 (Marquee) + return UnsafeNativeMethods.SendMessage( + this.handle, + (uint)UnsafeNativeMethods.TASKDIALOG_MESSAGES.TDM_SET_MARQUEE_PROGRESS_BAR, + (marquee ? (IntPtr)1 : IntPtr.Zero), + IntPtr.Zero) != IntPtr.Zero; + + // Future: get more detailed error from and throw. + } + + /// + /// Sets the state of the progress bar. + /// + /// The state to set the progress bar. + /// If the function succeeds the return value is true. + public bool SetProgressBarState(ProgressBarState newState) + { + // TDM_SET_PROGRESS_BAR_STATE = WM_USER+104, // wParam = new progress state + return UnsafeNativeMethods.SendMessage( + this.handle, + (uint)UnsafeNativeMethods.TASKDIALOG_MESSAGES.TDM_SET_PROGRESS_BAR_STATE, + (IntPtr)newState, + IntPtr.Zero) != IntPtr.Zero; + + // Future: get more detailed error from and throw. + } + + /// + /// Set the minimum and maximum values for the hosted progress bar. + /// + /// Minimum range value. By default, the minimum value is zero. + /// Maximum range value. By default, the maximum value is 100. + /// If the function succeeds the return value is true. + public bool SetProgressBarRange(Int16 minRange, Int16 maxRange) + { + // TDM_SET_PROGRESS_BAR_RANGE = WM_USER+105, // lParam = MAKELPARAM(nMinRange, nMaxRange) + // #define MAKELPARAM(l, h) ((LPARAM)(DWORD)MAKELONG(l, h)) + // #define MAKELONG(a, b) ((LONG)(((WORD)(((DWORD_PTR)(a)) & 0xffff)) | ((DWORD)((WORD)(((DWORD_PTR)(b)) & 0xffff))) << 16)) + IntPtr lparam = (IntPtr)((((Int32)minRange) & 0xffff) | ((((Int32)maxRange) & 0xffff) << 16)); + return UnsafeNativeMethods.SendMessage( + this.handle, + (uint)UnsafeNativeMethods.TASKDIALOG_MESSAGES.TDM_SET_PROGRESS_BAR_RANGE, + IntPtr.Zero, + lparam) != IntPtr.Zero; + + // Return value is actually prior range. + } + + /// + /// Set the current position for a progress bar. + /// + /// The new position. + /// Returns the previous value if successful, or zero otherwise. + public int SetProgressBarPosition(int newPosition) + { + // TDM_SET_PROGRESS_BAR_POS = WM_USER+106, // wParam = new position + return (int)UnsafeNativeMethods.SendMessage( + this.handle, + (uint)UnsafeNativeMethods.TASKDIALOG_MESSAGES.TDM_SET_PROGRESS_BAR_POS, + (IntPtr)newPosition, + IntPtr.Zero); + } + + /// + /// Sets the animation state of the Marquee Progress Bar. + /// + /// true starts the marquee animation and false stops it. + /// The time in milliseconds between refreshes. + public void SetProgressBarMarquee(bool startMarquee, uint speed) + { + // TDM_SET_PROGRESS_BAR_MARQUEE = WM_USER+107, // wParam = 0 (stop marquee), wParam != 0 (start marquee), lparam = speed (milliseconds between repaints) + UnsafeNativeMethods.SendMessage( + this.handle, + (uint)UnsafeNativeMethods.TASKDIALOG_MESSAGES.TDM_SET_PROGRESS_BAR_MARQUEE, + (startMarquee ? new IntPtr(1) : IntPtr.Zero), + (IntPtr)speed); + } + + /// + /// Updates the content text. + /// + /// The new value. + /// If the function succeeds the return value is true. + public bool SetContent(string content) + { + // TDE_CONTENT, + // TDM_SET_ELEMENT_TEXT = WM_USER+108 // wParam = element (TASKDIALOG_ELEMENTS), lParam = new element text (LPCWSTR) + return UnsafeNativeMethods.SendMessageWithString( + this.handle, + (uint)UnsafeNativeMethods.TASKDIALOG_MESSAGES.TDM_SET_ELEMENT_TEXT, + (IntPtr)UnsafeNativeMethods.TASKDIALOG_ELEMENTS.TDE_CONTENT, + content) != IntPtr.Zero; + } + + /// + /// Updates the Expanded Information text. + /// + /// The new value. + /// If the function succeeds the return value is true. + public bool SetExpandedInformation(string expandedInformation) + { + // TDE_EXPANDED_INFORMATION, + // TDM_SET_ELEMENT_TEXT = WM_USER+108 // wParam = element (TASKDIALOG_ELEMENTS), lParam = new element text (LPCWSTR) + return UnsafeNativeMethods.SendMessageWithString( + this.handle, + (uint)UnsafeNativeMethods.TASKDIALOG_MESSAGES.TDM_SET_ELEMENT_TEXT, + (IntPtr)UnsafeNativeMethods.TASKDIALOG_ELEMENTS.TDE_EXPANDED_INFORMATION, + expandedInformation) != IntPtr.Zero; + } + + /// + /// Updates the Footer text. + /// + /// The new value. + /// If the function succeeds the return value is true. + public bool SetFooter(string footer) + { + // TDE_FOOTER, + // TDM_SET_ELEMENT_TEXT = WM_USER+108 // wParam = element (TASKDIALOG_ELEMENTS), lParam = new element text (LPCWSTR) + return UnsafeNativeMethods.SendMessageWithString( + this.handle, + (uint)UnsafeNativeMethods.TASKDIALOG_MESSAGES.TDM_SET_ELEMENT_TEXT, + (IntPtr)UnsafeNativeMethods.TASKDIALOG_ELEMENTS.TDE_FOOTER, + footer) != IntPtr.Zero; + } + + /// + /// Updates the Main Instruction. + /// + /// The new value. + /// If the function succeeds the return value is true. + public bool SetMainInstruction(string mainInstruction) + { + // TDE_MAIN_INSTRUCTION + // TDM_SET_ELEMENT_TEXT = WM_USER+108 // wParam = element (TASKDIALOG_ELEMENTS), lParam = new element text (LPCWSTR) + return UnsafeNativeMethods.SendMessageWithString( + this.handle, + (uint)UnsafeNativeMethods.TASKDIALOG_MESSAGES.TDM_SET_ELEMENT_TEXT, + (IntPtr)UnsafeNativeMethods.TASKDIALOG_ELEMENTS.TDE_MAIN_INSTRUCTION, + mainInstruction) != IntPtr.Zero; + } + + /// + /// Simulate the action of a radio button click in the TaskDialog. + /// The passed buttonID is the ButtonID set on a TaskDialogButton set on TaskDialog.RadioButtons. + /// + /// Indicates the button ID to be selected. + public void ClickRadioButton(int buttonId) + { + // TDM_CLICK_RADIO_BUTTON = WM_USER+110, // wParam = Radio Button ID + UnsafeNativeMethods.SendMessage( + this.handle, + (uint)UnsafeNativeMethods.TASKDIALOG_MESSAGES.TDM_CLICK_RADIO_BUTTON, + (IntPtr)buttonId, + IntPtr.Zero); + } + + /// + /// Enable or disable a button in the TaskDialog. + /// The passed buttonID is the ButtonID set on a TaskDialogButton set on TaskDialog.Buttons + /// or a common button ID. + /// + /// Indicates the button ID to be enabled or diabled. + /// Enambe the button if true. Disable the button if false. + public void EnableButton(int buttonId, bool enable) + { + // TDM_ENABLE_BUTTON = WM_USER+111, // lParam = 0 (disable), lParam != 0 (enable), wParam = Button ID + UnsafeNativeMethods.SendMessage( + this.handle, + (uint)UnsafeNativeMethods.TASKDIALOG_MESSAGES.TDM_ENABLE_BUTTON, + (IntPtr)buttonId, + (IntPtr)(enable ? 1 : 0)); + } + + /// + /// Enable or disable a radio button in the TaskDialog. + /// The passed buttonID is the ButtonID set on a TaskDialogButton set on TaskDialog.RadioButtons. + /// + /// Indicates the button ID to be enabled or diabled. + /// Enambe the button if true. Disable the button if false. + public void EnableRadioButton(int buttonId, bool enable) + { + // TDM_ENABLE_RADIO_BUTTON = WM_USER+112, // lParam = 0 (disable), lParam != 0 (enable), wParam = Radio Button ID + UnsafeNativeMethods.SendMessage( + this.handle, + (uint)UnsafeNativeMethods.TASKDIALOG_MESSAGES.TDM_ENABLE_RADIO_BUTTON, + (IntPtr)buttonId, + (IntPtr)(enable ? 1 : 0)); + } + + /// + /// Check or uncheck the verification checkbox in the TaskDialog. + /// + /// The checked state to set the verification checkbox. + /// True to set the keyboard focus to the checkbox, and fasle otherwise. + public void ClickVerification(bool checkedState, bool setKeyboardFocusToCheckBox) + { + // TDM_CLICK_VERIFICATION = WM_USER+113, // wParam = 0 (unchecked), 1 (checked), lParam = 1 (set key focus) + UnsafeNativeMethods.SendMessage( + this.handle, + (uint)UnsafeNativeMethods.TASKDIALOG_MESSAGES.TDM_CLICK_VERIFICATION, + (checkedState ? new IntPtr(1) : IntPtr.Zero), + (setKeyboardFocusToCheckBox ? new IntPtr(1) : IntPtr.Zero)); + } + + /// + /// Updates the content text. + /// + /// The new value. + public void UpdateContent(string content) + { + // TDE_CONTENT, + // TDM_UPDATE_ELEMENT_TEXT = WM_USER+114, // wParam = element (TASKDIALOG_ELEMENTS), lParam = new element text (LPCWSTR) + UnsafeNativeMethods.SendMessageWithString( + this.handle, + (uint)UnsafeNativeMethods.TASKDIALOG_MESSAGES.TDM_UPDATE_ELEMENT_TEXT, + (IntPtr)UnsafeNativeMethods.TASKDIALOG_ELEMENTS.TDE_CONTENT, + content); + } + + /// + /// Updates the Expanded Information text. No effect if it was previously set to null. + /// + /// The new value. + public void UpdateExpandedInformation(string expandedInformation) + { + // TDE_EXPANDED_INFORMATION, + // TDM_UPDATE_ELEMENT_TEXT = WM_USER+114, // wParam = element (TASKDIALOG_ELEMENTS), lParam = new element text (LPCWSTR) + UnsafeNativeMethods.SendMessageWithString( + this.handle, + (uint)UnsafeNativeMethods.TASKDIALOG_MESSAGES.TDM_UPDATE_ELEMENT_TEXT, + (IntPtr)UnsafeNativeMethods.TASKDIALOG_ELEMENTS.TDE_EXPANDED_INFORMATION, + expandedInformation); + } + + /// + /// Updates the Footer text. No Effect if it was perviously set to null. + /// + /// The new value. + public void UpdateFooter(string footer) + { + // TDE_FOOTER, + // TDM_UPDATE_ELEMENT_TEXT = WM_USER+114, // wParam = element (TASKDIALOG_ELEMENTS), lParam = new element text (LPCWSTR) + UnsafeNativeMethods.SendMessageWithString( + this.handle, + (uint)UnsafeNativeMethods.TASKDIALOG_MESSAGES.TDM_UPDATE_ELEMENT_TEXT, + (IntPtr)UnsafeNativeMethods.TASKDIALOG_ELEMENTS.TDE_FOOTER, + footer); + } + + /// + /// Updates the Main Instruction. + /// + /// The new value. + public void UpdateMainInstruction(string mainInstruction) + { + // TDE_MAIN_INSTRUCTION + // TDM_UPDATE_ELEMENT_TEXT = WM_USER+114, // wParam = element (TASKDIALOG_ELEMENTS), lParam = new element text (LPCWSTR) + UnsafeNativeMethods.SendMessageWithString( + this.handle, + (uint)UnsafeNativeMethods.TASKDIALOG_MESSAGES.TDM_UPDATE_ELEMENT_TEXT, + (IntPtr)UnsafeNativeMethods.TASKDIALOG_ELEMENTS.TDE_MAIN_INSTRUCTION, + mainInstruction); + } + + /// + /// Designate whether a given Task Dialog button or command link should have a User Account Control (UAC) shield icon. + /// + /// ID of the push button or command link to be updated. + /// False to designate that the action invoked by the button does not require elevation; + /// true to designate that the action does require elevation. + public void SetButtonElevationRequiredState(int buttonId, bool elevationRequired) + { + // TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE = WM_USER+115, // wParam = Button ID, lParam = 0 (elevation not required), lParam != 0 (elevation required) + UnsafeNativeMethods.SendMessage( + this.handle, + (uint)UnsafeNativeMethods.TASKDIALOG_MESSAGES.TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, + (IntPtr)buttonId, + (IntPtr)(elevationRequired ? new IntPtr(1) : IntPtr.Zero)); + } + + /// + /// Updates the main instruction icon. Note the type (standard via enum or + /// custom via Icon type) must be used when upating the icon. + /// + /// Task Dialog standard icon. + public void UpdateMainIcon(TaskDialogIcon icon) + { + // TDM_UPDATE_ICON = WM_USER+116 // wParam = icon element (TASKDIALOG_ICON_ELEMENTS), lParam = new icon (hIcon if TDF_USE_HICON_* was set, PCWSTR otherwise) + UnsafeNativeMethods.SendMessage( + this.handle, + (uint)UnsafeNativeMethods.TASKDIALOG_MESSAGES.TDM_UPDATE_ICON, + (IntPtr)UnsafeNativeMethods.TASKDIALOG_ICON_ELEMENTS.TDIE_ICON_MAIN, + (IntPtr)icon); + } + + /// + /// Updates the main instruction icon. Note the type (standard via enum or + /// custom via Icon type) must be used when upating the icon. + /// + /// The icon to set. + public void UpdateMainIcon(Icon icon) + { + // TDM_UPDATE_ICON = WM_USER+116 // wParam = icon element (TASKDIALOG_ICON_ELEMENTS), lParam = new icon (hIcon if TDF_USE_HICON_* was set, PCWSTR otherwise) + UnsafeNativeMethods.SendMessage( + this.handle, + (uint)UnsafeNativeMethods.TASKDIALOG_MESSAGES.TDM_UPDATE_ICON, + (IntPtr)UnsafeNativeMethods.TASKDIALOG_ICON_ELEMENTS.TDIE_ICON_MAIN, + (icon == null ? IntPtr.Zero : icon.Handle)); + } + + /// + /// Updates the footer icon. Note the type (standard via enum or + /// custom via Icon type) must be used when upating the icon. + /// + /// Task Dialog standard icon. + public void UpdateFooterIcon(TaskDialogIcon icon) + { + // TDM_UPDATE_ICON = WM_USER+116 // wParam = icon element (TASKDIALOG_ICON_ELEMENTS), lParam = new icon (hIcon if TDF_USE_HICON_* was set, PCWSTR otherwise) + UnsafeNativeMethods.SendMessage( + this.handle, + (uint)UnsafeNativeMethods.TASKDIALOG_MESSAGES.TDM_UPDATE_ICON, + (IntPtr)UnsafeNativeMethods.TASKDIALOG_ICON_ELEMENTS.TDIE_ICON_FOOTER, + (IntPtr)icon); + } + + /// + /// Updates the footer icon. Note the type (standard via enum or + /// custom via Icon type) must be used when upating the icon. + /// + /// The icon to set. + public void UpdateFooterIcon(Icon icon) + { + // TDM_UPDATE_ICON = WM_USER+116 // wParam = icon element (TASKDIALOG_ICON_ELEMENTS), lParam = new icon (hIcon if TDF_USE_HICON_* was set, PCWSTR otherwise) + UnsafeNativeMethods.SendMessage( + this.handle, + (uint)UnsafeNativeMethods.TASKDIALOG_MESSAGES.TDM_UPDATE_ICON, + (IntPtr)UnsafeNativeMethods.TASKDIALOG_ICON_ELEMENTS.TDIE_ICON_FOOTER, + (icon == null ? IntPtr.Zero : icon.Handle)); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/TaskDialog/TaskDialog.cs b/branches/ph-plugins/ProcessHacker/Components/TaskDialog/TaskDialog.cs new file mode 100644 index 000000000..5feadabee --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/TaskDialog/TaskDialog.cs @@ -0,0 +1,1255 @@ +//------------------------------------------------------------------ +// +// A P/Invoke wrapper for TaskDialog. Usability was given preference to perf and size. +// +// +// +//------------------------------------------------------------------ + +namespace ProcessHacker.Components +{ + using System; + using System.Diagnostics.CodeAnalysis; + using System.Drawing; + using System.Runtime.InteropServices; + using System.Windows.Forms; + + /// + /// The signature of the callback that recieves notificaitons from the Task Dialog. + /// + /// The active task dialog which has methods that can be performed on an active Task Dialog. + /// The notification arguments including the type of notification and information for the notification. + /// The value set on TaskDialog.CallbackData + /// Return value meaning varies depending on the Notification member of args. + public delegate bool TaskDialogCallback(ActiveTaskDialog taskDialog, TaskDialogNotificationArgs args, object callbackData); + + /// + /// The TaskDialog common button flags used to specify the builtin bottons to show in the TaskDialog. + /// + [Flags] + public enum TaskDialogCommonButtons + { + /// + /// No common buttons. + /// + None = 0, + + /// + /// OK common button. If selected Task Dialog will return DialogResult.OK. + /// + Ok = 0x0001, + + /// + /// Yes common button. If selected Task Dialog will return DialogResult.Yes. + /// + Yes = 0x0002, + + /// + /// No common button. If selected Task Dialog will return DialogResult.No. + /// + No = 0x0004, + + /// + /// Cancel common button. If selected Task Dialog will return DialogResult.Cancel. + /// If this button is specified, the dialog box will respond to typical cancel actions (Alt-F4 and Escape). + /// + Cancel = 0x0008, + + /// + /// Retry common button. If selected Task Dialog will return DialogResult.Retry. + /// + Retry = 0x0010, + + /// + /// Close common button. If selected Task Dialog will return this value. + /// + Close = 0x0020, + } + + /// + /// The System icons the TaskDialog supports. + /// + [SuppressMessage("Microsoft.Design", "CA1028:EnumStorageShouldBeInt32")] // Type comes from CommCtrl.h + public enum TaskDialogIcon : uint + { + /// + /// No Icon. + /// + None = 0, + + /// + /// System warning icon. + /// + Warning = 0xFFFF, // MAKEINTRESOURCEW(-1) + + /// + /// System Error icon. + /// + Error = 0xFFFE, // MAKEINTRESOURCEW(-2) + + /// + /// System Information icon. + /// + Information = 0xFFFD, // MAKEINTRESOURCEW(-3) + + /// + /// Shield icon. + /// + Shield = 0xFFFC, // MAKEINTRESOURCEW(-4) + + //These are undocumented "Special Styled" TaskDialog Windows + SecurityStop = UInt16.MaxValue - 1, + SecurityInformation = UInt16.MaxValue - 2, + SecurityShield = UInt16.MaxValue - 3, + SecurityShieldBlue = UInt16.MaxValue - 4, + SecurityWarning = UInt16.MaxValue - 5, + SecurityError = UInt16.MaxValue - 6, + SecuritySuccess = UInt16.MaxValue - 7, + SecurityShieldGray = UInt16.MaxValue - 8, + ASecurityWarning = UInt16.MaxValue, + + //Other undocumented Icons + DefragWithShield = 195, + VideoIconWithoutVideo = 193, + WorldIconWithCable = 179, + MagnifyingGlass = 177, + FolderwithTwoArrowsPointingInwards = 175, + AppInstallUninstallIcon = 161, + AppearanceIcon = 151, + PerformanceMonitorIcon = 150, + MyComputerIconWithTick = 149, + ComputerJumpToComputerIcon = 147, + MonitorIconWithMagnifingGlass = 145, + InternetWorldWithClockIcon = 144, + BriefcaseWithUsericon = 130, + AppPageWithTicks = 121, + NetworkingIcon = 120, + CogWithTicks = 114, + DegragIcon = 111, + ShowDesktopIcon = 110, + ExclamationMarkShield = 107, + GreenTickShield = 106, + RedXShield = 105, + QuestionIcon = 104, + MonitorIcon = 101, + RunBoxIcon = 100, + CirleQuestion = 99, + CircleX = 98, + GreySmallX = 97, + FlashChip = 96, + TXTandBRIcon = 94, + BigRedX = 89, + AppInstallIcon = 87, + ExIcon = 84, + KeyIcon = 82, + InfoIcon = 81, + Startmenu = 80, + SharedIcon = 79, + WindowsDrive = 37, + CircleandTick = 24, + Network = 25, + RecycleBin = 55, + Padlock = 59, + DisplayLookingIcon = 65, + Picture = 70, + HDDQuestion = 75, + } + + /// + /// Task Dialog callback notifications. + /// + public enum TaskDialogNotification + { + /// + /// Sent by the Task Dialog once the dialog has been created and before it is displayed. + /// The value returned by the callback is ignored. + /// + Created = 0, + + //// Spec is not clear what this is so not supporting it. + ///// + ///// Sent by the Task Dialog when a navigation has occurred. + ///// The value returned by the callback is ignored. + ///// + // Navigated = 1, + + /// + /// Sent by the Task Dialog when the user selects a button or command link in the task dialog. + /// The button ID corresponding to the button selected will be available in the + /// TaskDialogNotificationArgs. To prevent the Task Dialog from closing, the application must + /// return true, otherwise the Task Dialog will be closed and the button ID returned to via + /// the original application call. + /// + ButtonClicked = 2, // wParam = Button ID + + /// + /// Sent by the Task Dialog when the user clicks on a hyperlink in the Task Dialog’s content. + /// The string containing the HREF of the hyperlink will be available in the + /// TaskDialogNotificationArgs. To prevent the TaskDialog from shell executing the hyperlink, + /// the application must return TRUE, otherwise ShellExecute will be called. + /// + HyperlinkClicked = 3, // lParam = (LPCWSTR)pszHREF + + /// + /// Sent by the Task Dialog approximately every 200 milliseconds when TaskDialog.CallbackTimer + /// has been set to true. The number of milliseconds since the dialog was created or the + /// notification returned true is available on the TaskDialogNotificationArgs. To reset + /// the tickcount, the application must return true, otherwise the tickcount will continue to + /// increment. + /// + Timer = 4, // wParam = Milliseconds since dialog created or timer reset + + /// + /// Sent by the Task Dialog when it is destroyed and its window handle no longer valid. + /// The value returned by the callback is ignored. + /// + Destroyed = 5, + + /// + /// Sent by the Task Dialog when the user selects a radio button in the task dialog. + /// The button ID corresponding to the button selected will be available in the + /// TaskDialogNotificationArgs. + /// The value returned by the callback is ignored. + /// + RadioButtonClicked = 6, // wParam = Radio Button ID + + /// + /// Sent by the Task Dialog once the dialog has been constructed and before it is displayed. + /// The value returned by the callback is ignored. + /// + DialogConstructed = 7, + + /// + /// Sent by the Task Dialog when the user checks or unchecks the verification checkbox. + /// The verificationFlagChecked value is available on the TaskDialogNotificationArgs. + /// The value returned by the callback is ignored. + /// + VerificationClicked = 8, // wParam = 1 if checkbox checked, 0 if not, lParam is unused and always 0 + + /// + /// Sent by the Task Dialog when the user presses F1 on the keyboard while the dialog has focus. + /// The value returned by the callback is ignored. + /// + Help = 9, + + /// + /// Sent by the task dialog when the user clicks on the dialog's expando button. + /// The expanded value is available on the TaskDialogNotificationArgs. + /// The value returned by the callback is ignored. + /// + ExpandoButtonClicked = 10 // wParam = 0 (dialog is now collapsed), wParam != 0 (dialog is now expanded) + } + + /// + /// Progress bar state. + /// + [SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue")] // Comes from CommCtrl.h PBST_* values which don't have a zero. + public enum ProgressBarState + { + /// + /// Normal. + /// + Normal = 1, + + /// + /// Error state. + /// + Error = 2, + + /// + /// Paused state. + /// + Paused = 3 + } + + /// + /// A custom button for the TaskDialog. + /// + [SuppressMessage("Microsoft.Performance", "CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes")] // Would be unused code as not required for usage. + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)] + public struct TaskDialogButton + { + /// + /// The ID of the button. This value is returned by TaskDialog.Show when the button is clicked. + /// + private int buttonId; + + /// + /// The string that appears on the button. + /// + [MarshalAs(UnmanagedType.LPWStr)] + private string buttonText; + + /// + /// Initialize the custom button. + /// + /// The ID of the button. This value is returned by TaskDialog.Show when + /// the button is clicked. Typically this will be a value in the DialogResult enum. + /// The string that appears on the button. + public TaskDialogButton(int id, string text) + { + this.buttonId = id; + this.buttonText = text; + } + + /// + /// The ID of the button. This value is returned by TaskDialog.Show when the button is clicked. + /// + public int ButtonId + { + get { return this.buttonId; } + set { this.buttonId = value; } + } + + /// + /// The string that appears on the button. + /// + public string ButtonText + { + get { return this.buttonText; } + set { this.buttonText = value; } + } + } + + /// + /// A Task Dialog. This is like a MessageBox but with many more features. TaskDialog requires Windows Longhorn or later. + /// + public class TaskDialog + { + /// + /// The string to be used for the dialog box title. If this parameter is NULL, the filename of the executable program is used. + /// + private string windowTitle; + + /// + /// The string to be used for the main instruction. + /// + private string mainInstruction; + + /// + /// The string to be used for the dialog’s primary content. If the EnableHyperlinks member is true, + /// then this string may contain hyperlinks in the form: Hyperlink Text. + /// WARNING: Enabling hyperlinks when using content from an unsafe source may cause security vulnerabilities. + /// + private string content; + + /// + /// Specifies the push buttons displayed in the dialog box. This parameter may be a combination of flags. + /// If no common buttons are specified and no custom buttons are specified using the Buttons member, the + /// dialog box will contain the OK button by default. + /// + private TaskDialogCommonButtons commonButtons; + + /// + /// Specifies a built in icon for the main icon in the dialog. If this is set to none + /// and the CustomMainIcon is null then no main icon will be displayed. + /// + private TaskDialogIcon mainIcon; + + /// + /// Specifies a custom in icon for the main icon in the dialog. If this is set to none + /// and the CustomMainIcon member is null then no main icon will be displayed. + /// + private Icon customMainIcon; + + /// + /// Specifies a built in icon for the icon to be displayed in the footer area of the + /// dialog box. If this is set to none and the CustomFooterIcon member is null then no + /// footer icon will be displayed. + /// + private TaskDialogIcon footerIcon; + + /// + /// Specifies a custom icon for the icon to be displayed in the footer area of the + /// dialog box. If this is set to none and the CustomFooterIcon member is null then no + /// footer icon will be displayed. + /// + private Icon customFooterIcon; + + /// + /// Specifies the custom push buttons to display in the dialog. Use CommonButtons member for + /// common buttons; OK, Yes, No, Retry and Cancel, and Buttons when you want different text + /// on the push buttons. + /// + private TaskDialogButton[] buttons; + + /// + /// Specifies the radio buttons to display in the dialog. + /// + private TaskDialogButton[] radioButtons; + + /// + /// The flags passed to TaskDialogIndirect. + /// + private UnsafeNativeMethods.TASKDIALOG_FLAGS flags; + + /// + /// Indicates the default button for the dialog. This may be any of the values specified + /// in ButtonId members of one of the TaskDialogButton structures in the Buttons array, + /// or one a DialogResult value that corresponds to a buttons specified in the CommonButtons Member. + /// If this member is zero or its value does not correspond to any button ID in the dialog, + /// then the first button in the dialog will be the default. + /// + private int defaultButton; + + /// + /// Indicates the default radio button for the dialog. This may be any of the values specified + /// in ButtonId members of one of the TaskDialogButton structures in the RadioButtons array. + /// If this member is zero or its value does not correspond to any radio button ID in the dialog, + /// then the first button in RadioButtons will be the default. + /// The property NoDefaultRadioButton can be set to have no default. + /// + private int defaultRadioButton; + + /// + /// The string to be used to label the verification checkbox. If this member is null, the + /// verification checkbox is not displayed in the dialog box. + /// + private string verificationText; + + /// + /// The string to be used for displaying additional information. The additional information is + /// displayed either immediately below the content or below the footer text depending on whether + /// the ExpandFooterArea member is true. If the EnableHyperlinks member is true, then this string + /// may contain hyperlinks in the form: Hyperlink Text. + /// WARNING: Enabling hyperlinks when using content from an unsafe source may cause security vulnerabilities. + /// + private string expandedInformation; + + /// + /// The string to be used to label the button for collapsing the expanded information. This + /// member is ignored when the ExpandedInformation member is null. If this member is null + /// and the CollapsedControlText is specified, then the CollapsedControlText value will be + /// used for this member as well. + /// + private string expandedControlText; + + /// + /// The string to be used to label the button for expanding the expanded information. This + /// member is ignored when the ExpandedInformation member is null. If this member is null + /// and the ExpandedControlText is specified, then the ExpandedControlText value will be + /// used for this member as well. + /// + private string collapsedControlText; + + /// + /// The string to be used in the footer area of the dialog box. If the EnableHyperlinks member + /// is true, then this string may contain hyperlinks in the form: + /// Hyperlink Text. + /// WARNING: Enabling hyperlinks when using content from an unsafe source may cause security vulnerabilities. + /// + private string footer; + + /// + /// The callback that receives messages from the Task Dialog when various events occur. + /// + private TaskDialogCallback callback; + + /// + /// Reference that is passed to the callback. + /// + private object callbackData; + + /// + /// Specifies the width of the Task Dialog’s client area in DLU’s. If 0, Task Dialog will calculate the ideal width. + /// + private uint width; + + /// + /// Creates a default Task Dialog. + /// + public TaskDialog() + { + this.Reset(); + } + + /// + /// Returns true if the current operating system supports TaskDialog. If false TaskDialog.Show should not + /// be called as the results are undefined but often results in a crash. + /// + public static bool IsAvailableOnThisOS + { + get + { + OperatingSystem os = Environment.OSVersion; + if (os.Platform != PlatformID.Win32NT) + { + return false; + } + + return (os.Version.CompareTo(TaskDialog.RequiredOSVersion) >= 0); + } + } + + /// + /// The minimum Windows version needed to support TaskDialog. + /// + public static Version RequiredOSVersion + { + get { return new Version(6, 0, 5243); } + } + + /// + /// The string to be used for the dialog box title. If this parameter is NULL, the filename of the executable program is used. + /// + public string WindowTitle + { + get { return this.windowTitle; } + set { this.windowTitle = value; } + } + + /// + /// The string to be used for the main instruction. + /// + public string MainInstruction + { + get { return this.mainInstruction; } + set { this.mainInstruction = value; } + } + + /// + /// The string to be used for the dialog’s primary content. If the EnableHyperlinks member is true, + /// then this string may contain hyperlinks in the form: Hyperlink Text. + /// WARNING: Enabling hyperlinks when using content from an unsafe source may cause security vulnerabilities. + /// + public string Content + { + get { return this.content; } + set { this.content = value; } + } + + /// + /// Specifies the push buttons displayed in the dialog box. This parameter may be a combination of flags. + /// If no common buttons are specified and no custom buttons are specified using the Buttons member, the + /// dialog box will contain the OK button by default. + /// + public TaskDialogCommonButtons CommonButtons + { + get { return this.commonButtons; } + set { this.commonButtons = value; } + } + + /// + /// Specifies a built in icon for the main icon in the dialog. If this is set to none + /// and the CustomMainIcon is null then no main icon will be displayed. + /// + public TaskDialogIcon MainIcon + { + get { return this.mainIcon; } + set { this.mainIcon = value; } + } + + /// + /// Specifies a custom in icon for the main icon in the dialog. If this is set to none + /// and the CustomMainIcon member is null then no main icon will be displayed. + /// + public Icon CustomMainIcon + { + get { return this.customMainIcon; } + set { this.customMainIcon = value; } + } + + /// + /// Specifies a built in icon for the icon to be displayed in the footer area of the + /// dialog box. If this is set to none and the CustomFooterIcon member is null then no + /// footer icon will be displayed. + /// + public TaskDialogIcon FooterIcon + { + get { return this.footerIcon; } + set { this.footerIcon = value; } + } + + /// + /// Specifies a custom icon for the icon to be displayed in the footer area of the + /// dialog box. If this is set to none and the CustomFooterIcon member is null then no + /// footer icon will be displayed. + /// + public Icon CustomFooterIcon + { + get { return this.customFooterIcon; } + set { this.customFooterIcon = value; } + } + + /// + /// Specifies the custom push buttons to display in the dialog. Use CommonButtons member for + /// common buttons; OK, Yes, No, Retry and Cancel, and Buttons when you want different text + /// on the push buttons. + /// + [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] // Style of use is like single value. Array is of value types. + [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] // Returns a reference, not a copy. + public TaskDialogButton[] Buttons + { + get + { + return this.buttons; + } + + set + { + if (value == null) + { + throw new ArgumentNullException("value"); + } + + this.buttons = value; + } + } + + /// + /// Specifies the radio buttons to display in the dialog. + /// + [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] // Style of use is like single value. Array is of value types. + [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")] // Returns a reference, not a copy. + public TaskDialogButton[] RadioButtons + { + get + { + return this.radioButtons; + } + + set + { + if (value == null) + { + throw new ArgumentNullException("value"); + } + + this.radioButtons = value; + } + } + + /// + /// Enables hyperlink processing for the strings specified in the Content, ExpandedInformation + /// and FooterText members. When enabled, these members may be strings that contain hyperlinks + /// in the form: Hyperlink Text. + /// WARNING: Enabling hyperlinks when using content from an unsafe source may cause security vulnerabilities. + /// Note: Task Dialog will not actually execute any hyperlinks. Hyperlink execution must be handled + /// in the callback function specified by Callback member. + /// + public bool EnableHyperlinks + { + get { return (this.flags & UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_ENABLE_HYPERLINKS) != 0; } + set { this.SetFlag(UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_ENABLE_HYPERLINKS, value); } + } + + /// + /// Indicates that the dialog should be able to be closed using Alt-F4, Escape and the title bar’s + /// close button even if no cancel button is specified in either the CommonButtons or Buttons members. + /// + public bool AllowDialogCancellation + { + get { return (this.flags & UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION) != 0; } + set { this.SetFlag(UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_ALLOW_DIALOG_CANCELLATION, value); } + } + + /// + /// Indicates that the buttons specified in the Buttons member should be displayed as command links + /// (using a standard task dialog glyph) instead of push buttons. When using command links, all + /// characters up to the first new line character in the ButtonText member (of the TaskDialogButton + /// structure) will be treated as the command link’s main text, and the remainder will be treated + /// as the command link’s note. This flag is ignored if the Buttons member has no entires. + /// + public bool UseCommandLinks + { + get { return (this.flags & UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_USE_COMMAND_LINKS) != 0; } + set { this.SetFlag(UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_USE_COMMAND_LINKS, value); } + } + + /// + /// Indicates that the buttons specified in the Buttons member should be displayed as command links + /// (without a glyph) instead of push buttons. When using command links, all characters up to the + /// first new line character in the ButtonText member (of the TaskDialogButton structure) will be + /// treated as the command link’s main text, and the remainder will be treated as the command link’s + /// note. This flag is ignored if the Buttons member has no entires. + /// + public bool UseCommandLinksNoIcon + { + get { return (this.flags & UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_USE_COMMAND_LINKS_NO_ICON) != 0; } + set { this.SetFlag(UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_USE_COMMAND_LINKS_NO_ICON, value); } + } + + /// + /// Indicates that the string specified by the ExpandedInformation member should be displayed at the + /// bottom of the dialog’s footer area instead of immediately after the dialog’s content. This flag + /// is ignored if the ExpandedInformation member is null. + /// + public bool ExpandFooterArea + { + get { return (this.flags & UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_EXPAND_FOOTER_AREA) != 0; } + set { this.SetFlag(UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_EXPAND_FOOTER_AREA, value); } + } + + /// + /// Indicates that the string specified by the ExpandedInformation member should be displayed + /// when the dialog is initially displayed. This flag is ignored if the ExpandedInformation member + /// is null. + /// + public bool ExpandedByDefault + { + get { return (this.flags & UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_EXPANDED_BY_DEFAULT) != 0; } + set { this.SetFlag(UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_EXPANDED_BY_DEFAULT, value); } + } + + /// + /// Indicates that the verification checkbox in the dialog should be checked when the dialog is + /// initially displayed. This flag is ignored if the VerificationText parameter is null. + /// + public bool VerificationFlagChecked + { + get { return (this.flags & UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED) != 0; } + set { this.SetFlag(UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_VERIFICATION_FLAG_CHECKED, value); } + } + + /// + /// Indicates that a Progress Bar should be displayed. + /// + public bool ShowProgressBar + { + get { return (this.flags & UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_SHOW_PROGRESS_BAR) != 0; } + set { this.SetFlag(UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_SHOW_PROGRESS_BAR, value); } + } + + /// + /// Indicates that an Marquee Progress Bar should be displayed. + /// + public bool ShowMarqueeProgressBar + { + get { return (this.flags & UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_SHOW_MARQUEE_PROGRESS_BAR) != 0; } + set { this.SetFlag(UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_SHOW_MARQUEE_PROGRESS_BAR, value); } + } + + /// + /// Indicates that the TaskDialog’s callback should be called approximately every 200 milliseconds. + /// + public bool CallbackTimer + { + get { return (this.flags & UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_CALLBACK_TIMER) != 0; } + set { this.SetFlag(UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_CALLBACK_TIMER, value); } + } + + /// + /// Indicates that the TaskDialog should be positioned (centered) relative to the owner window + /// passed when calling Show. If not set (or no owner window is passed), the TaskDialog is + /// positioned (centered) relative to the monitor. + /// + public bool PositionRelativeToWindow + { + get { return (this.flags & UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_POSITION_RELATIVE_TO_WINDOW) != 0; } + set { this.SetFlag(UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_POSITION_RELATIVE_TO_WINDOW, value); } + } + + /// + /// Indicates that the TaskDialog should have right to left layout. + /// + public bool RightToLeftLayout + { + get { return (this.flags & UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_RTL_LAYOUT) != 0; } + set { this.SetFlag(UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_RTL_LAYOUT, value); } + } + + /// + /// Indicates that the TaskDialog should have no default radio button. + /// + public bool NoDefaultRadioButton + { + get { return (this.flags & UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_NO_DEFAULT_RADIO_BUTTON) != 0; } + set { this.SetFlag(UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_NO_DEFAULT_RADIO_BUTTON, value); } + } + + /// + /// Indicates that the TaskDialog can be minimised. Works only if there if parent window is null. Will enable cancellation also. + /// + public bool CanBeMinimized + { + get { return (this.flags & UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_CAN_BE_MINIMIZED) != 0; } + set { this.SetFlag(UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_CAN_BE_MINIMIZED, value); } + } + + /// + /// Indicates the default button for the dialog. This may be any of the values specified + /// in ButtonId members of one of the TaskDialogButton structures in the Buttons array, + /// or one a DialogResult value that corresponds to a buttons specified in the CommonButtons Member. + /// If this member is zero or its value does not correspond to any button ID in the dialog, + /// then the first button in the dialog will be the default. + /// + public int DefaultButton + { + get { return this.defaultButton; } + set { this.defaultButton = value; } + } + + /// + /// Indicates the default radio button for the dialog. This may be any of the values specified + /// in ButtonId members of one of the TaskDialogButton structures in the RadioButtons array. + /// If this member is zero or its value does not correspond to any radio button ID in the dialog, + /// then the first button in RadioButtons will be the default. + /// The property NoDefaultRadioButton can be set to have no default. + /// + public int DefaultRadioButton + { + get { return this.defaultRadioButton; } + set { this.defaultRadioButton = value; } + } + + /// + /// The string to be used to label the verification checkbox. If this member is null, the + /// verification checkbox is not displayed in the dialog box. + /// + public string VerificationText + { + get { return this.verificationText; } + set { this.verificationText = value; } + } + + /// + /// The string to be used for displaying additional information. The additional information is + /// displayed either immediately below the content or below the footer text depending on whether + /// the ExpandFooterArea member is true. If the EnameHyperlinks member is true, then this string + /// may contain hyperlinks in the form: Hyperlink Text. + /// WARNING: Enabling hyperlinks when using content from an unsafe source may cause security vulnerabilities. + /// + public string ExpandedInformation + { + get { return this.expandedInformation; } + set { this.expandedInformation = value; } + } + + /// + /// The string to be used to label the button for collapsing the expanded information. This + /// member is ignored when the ExpandedInformation member is null. If this member is null + /// and the CollapsedControlText is specified, then the CollapsedControlText value will be + /// used for this member as well. + /// + public string ExpandedControlText + { + get { return this.expandedControlText; } + set { this.expandedControlText = value; } + } + + /// + /// The string to be used to label the button for expanding the expanded information. This + /// member is ignored when the ExpandedInformation member is null. If this member is null + /// and the ExpandedControlText is specified, then the ExpandedControlText value will be + /// used for this member as well. + /// + public string CollapsedControlText + { + get { return this.collapsedControlText; } + set { this.collapsedControlText = value; } + } + + /// + /// The string to be used in the footer area of the dialog box. If the EnableHyperlinks member + /// is true, then this string may contain hyperlinks in the form: + /// Hyperlink Text. + /// WARNING: Enabling hyperlinks when using content from an unsafe source may cause security vulnerabilities. + /// + public string Footer + { + get { return this.footer; } + set { this.footer = value; } + } + + /// + /// width of the Task Dialog's client area in DLU's. If 0, Task Dialog will calculate the ideal width. + /// + public uint Width + { + get { return this.width; } + set { this.width = value; } + } + + /// + /// The callback that receives messages from the Task Dialog when various events occur. + /// + public TaskDialogCallback Callback + { + get { return this.callback; } + set { this.callback = value; } + } + + /// + /// Reference that is passed to the callback. + /// + public object CallbackData + { + get { return this.callbackData; } + set { this.callbackData = value; } + } + + /// + /// Resets the Task Dialog to the state when first constructed, all properties set to their default value. + /// + public void Reset() + { + this.windowTitle = null; + this.mainInstruction = null; + this.content = null; + this.commonButtons = 0; + this.mainIcon = TaskDialogIcon.None; + this.customMainIcon = null; + this.footerIcon = TaskDialogIcon.None; + this.customFooterIcon = null; + this.buttons = new TaskDialogButton[0]; + this.radioButtons = new TaskDialogButton[0]; + this.flags = 0; + this.defaultButton = 0; + this.defaultRadioButton = 0; + this.verificationText = null; + this.expandedInformation = null; + this.expandedControlText = null; + this.collapsedControlText = null; + this.footer = null; + this.callback = null; + this.callbackData = null; + this.width = 0; + } + + /// + /// Creates, displays, and operates a task dialog. The task dialog contains application-defined messages, title, + /// verification check box, command links and push buttons, plus any combination of predefined icons and push buttons + /// as specified on the other members of the class before calling Show. + /// + /// The result of the dialog, either a DialogResult value for common push buttons set in the CommonButtons + /// member or the ButtonID from a TaskDialogButton structure set on the Buttons member. + public int Show() + { + bool verificationFlagChecked; + int radioButtonResult; + return this.Show(IntPtr.Zero, out verificationFlagChecked, out radioButtonResult); + } + + /// + /// Creates, displays, and operates a task dialog. The task dialog contains application-defined messages, title, + /// verification check box, command links and push buttons, plus any combination of predefined icons and push buttons + /// as specified on the other members of the class before calling Show. + /// + /// Owner window the task Dialog will modal to. + /// The result of the dialog, either a DialogResult value for common push buttons set in the CommonButtons + /// member or the ButtonID from a TaskDialogButton structure set on the Buttons member. + public int Show(IWin32Window owner) + { + bool verificationFlagChecked; + int radioButtonResult; + return this.Show((owner == null ? IntPtr.Zero : owner.Handle), out verificationFlagChecked, out radioButtonResult); + } + + /// + /// Creates, displays, and operates a task dialog. The task dialog contains application-defined messages, title, + /// verification check box, command links and push buttons, plus any combination of predefined icons and push buttons + /// as specified on the other members of the class before calling Show. + /// + /// Owner window the task Dialog will modal to. + /// The result of the dialog, either a DialogResult value for common push buttons set in the CommonButtons + /// member or the ButtonID from a TaskDialogButton structure set on the Buttons member. + public int Show(IntPtr hwndOwner) + { + bool verificationFlagChecked; + int radioButtonResult; + return this.Show(hwndOwner, out verificationFlagChecked, out radioButtonResult); + } + + /// + /// Creates, displays, and operates a task dialog. The task dialog contains application-defined messages, title, + /// verification check box, command links and push buttons, plus any combination of predefined icons and push buttons + /// as specified on the other members of the class before calling Show. + /// + /// Owner window the task Dialog will modal to. + /// Returns true if the verification checkbox was checked when the dialog + /// was dismissed. + /// The result of the dialog, either a DialogResult value for common push buttons set in the CommonButtons + /// member or the ButtonID from a TaskDialogButton structure set on the Buttons member. + public int Show(IWin32Window owner, out bool verificationFlagChecked) + { + int radioButtonResult; + return this.Show((owner == null ? IntPtr.Zero : owner.Handle), out verificationFlagChecked, out radioButtonResult); + } + + /// + /// Creates, displays, and operates a task dialog. The task dialog contains application-defined messages, title, + /// verification check box, command links and push buttons, plus any combination of predefined icons and push buttons + /// as specified on the other members of the class before calling Show. + /// + /// Owner window the task Dialog will modal to. + /// Returns true if the verification checkbox was checked when the dialog + /// was dismissed. + /// The result of the dialog, either a DialogResult value for common push buttons set in the CommonButtons + /// member or the ButtonID from a TaskDialogButton structure set on the Buttons member. + public int Show(IntPtr hwndOwner, out bool verificationFlagChecked) + { + // We have to call a private version or PreSharp gets upset about a unsafe + // block in a public method. (PreSharp error 56505) + int radioButtonResult; + return this.PrivateShow(hwndOwner, out verificationFlagChecked, out radioButtonResult); + } + + /// + /// Creates, displays, and operates a task dialog. The task dialog contains application-defined messages, title, + /// verification check box, command links and push buttons, plus any combination of predefined icons and push buttons + /// as specified on the other members of the class before calling Show. + /// + /// Owner window the task Dialog will modal to. + /// Returns true if the verification checkbox was checked when the dialog + /// was dismissed. + /// The radio botton selected by the user. + /// The result of the dialog, either a DialogResult value for common push buttons set in the CommonButtons + /// member or the ButtonID from a TaskDialogButton structure set on the Buttons member. + public int Show(IWin32Window owner, out bool verificationFlagChecked, out int radioButtonResult) + { + return this.Show((owner == null ? IntPtr.Zero : owner.Handle), out verificationFlagChecked, out radioButtonResult); + } + + /// + /// Creates, displays, and operates a task dialog. The task dialog contains application-defined messages, title, + /// verification check box, command links and push buttons, plus any combination of predefined icons and push buttons + /// as specified on the other members of the class before calling Show. + /// + /// Owner window the task Dialog will modal to. + /// Returns true if the verification checkbox was checked when the dialog + /// was dismissed. + /// The radio botton selected by the user. + /// The result of the dialog, either a DialogResult value for common push buttons set in the CommonButtons + /// member or the ButtonID from a TaskDialogButton structure set on the Buttons member. + public int Show(IntPtr hwndOwner, out bool verificationFlagChecked, out int radioButtonResult) + { + // We have to call a private version or PreSharp gets upset about a unsafe + // block in a public method. (PreSharp error 56505) + return this.PrivateShow(hwndOwner, out verificationFlagChecked, out radioButtonResult); + } + + /// + /// Creates, displays, and operates a task dialog. The task dialog contains application-defined messages, title, + /// verification check box, command links and push buttons, plus any combination of predefined icons and push buttons + /// as specified on the other members of the class before calling Show. + /// + /// Owner window the task Dialog will modal to. + /// Returns true if the verification checkbox was checked when the dialog + /// was dismissed. + /// The radio botton selected by the user. + /// The result of the dialog, either a DialogResult value for common push buttons set in the CommonButtons + /// member or the ButtonID from a TaskDialogButton structure set on the Buttons member. + private int PrivateShow(IntPtr hwndOwner, out bool verificationFlagChecked, out int radioButtonResult) + { + verificationFlagChecked = false; + radioButtonResult = 0; + int result = 0; + UnsafeNativeMethods.TASKDIALOGCONFIG config = new UnsafeNativeMethods.TASKDIALOGCONFIG(); + + try + { + config.cbSize = (uint)Marshal.SizeOf(typeof(UnsafeNativeMethods.TASKDIALOGCONFIG)); + config.hwndParent = hwndOwner; + config.dwFlags = this.flags; + config.dwCommonButtons = this.commonButtons; + + if (!string.IsNullOrEmpty(this.windowTitle)) + { + config.pszWindowTitle = this.windowTitle; + } + + config.MainIcon = (IntPtr)this.mainIcon; + if (this.customMainIcon != null) + { + config.dwFlags |= UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_USE_HICON_MAIN; + config.MainIcon = this.customMainIcon.Handle; + } + + if (!string.IsNullOrEmpty(this.mainInstruction)) + { + config.pszMainInstruction = this.mainInstruction; + } + + if (!string.IsNullOrEmpty(this.content)) + { + config.pszContent = this.content; + } + + TaskDialogButton[] customButtons = this.buttons; + if (customButtons.Length > 0) + { + // Hand marshal the buttons array. + int elementSize = Marshal.SizeOf(typeof(TaskDialogButton)); + config.pButtons = Marshal.AllocHGlobal(elementSize * (int)customButtons.Length); + for (int i = 0; i < customButtons.Length; i++) + { + unsafe // Unsafe because of pointer arithmatic. + { + byte* p = (byte*)config.pButtons; + Marshal.StructureToPtr(customButtons[i], (IntPtr)(p + (elementSize * i)), false); + } + + config.cButtons++; + } + } + + TaskDialogButton[] customRadioButtons = this.radioButtons; + if (customRadioButtons.Length > 0) + { + // Hand marshal the buttons array. + int elementSize = Marshal.SizeOf(typeof(TaskDialogButton)); + config.pRadioButtons = Marshal.AllocHGlobal(elementSize * (int)customRadioButtons.Length); + for (int i = 0; i < customRadioButtons.Length; i++) + { + unsafe // Unsafe because of pointer arithmatic. + { + byte* p = (byte*)config.pRadioButtons; + Marshal.StructureToPtr(customRadioButtons[i], (IntPtr)(p + (elementSize * i)), false); + } + + config.cRadioButtons++; + } + } + + config.nDefaultButton = this.defaultButton; + config.nDefaultRadioButton = this.defaultRadioButton; + + if (!string.IsNullOrEmpty(this.verificationText)) + { + config.pszVerificationText = this.verificationText; + } + + if (!string.IsNullOrEmpty(this.expandedInformation)) + { + config.pszExpandedInformation = this.expandedInformation; + } + + if (!string.IsNullOrEmpty(this.expandedControlText)) + { + config.pszExpandedControlText = this.expandedControlText; + } + + if (!string.IsNullOrEmpty(this.collapsedControlText)) + { + config.pszCollapsedControlText = this.CollapsedControlText; + } + + config.FooterIcon = (IntPtr)this.footerIcon; + if (this.customFooterIcon != null) + { + config.dwFlags |= UnsafeNativeMethods.TASKDIALOG_FLAGS.TDF_USE_HICON_FOOTER; + config.FooterIcon = this.customFooterIcon.Handle; + } + + if (!string.IsNullOrEmpty(this.footer)) + { + config.pszFooter = this.footer; + } + + // If our user has asked for a callback then we need to ask for one to + // translate to the friendly version. + if (this.callback != null) + { + config.pfCallback = new UnsafeNativeMethods.TaskDialogCallback(this.PrivateCallback); + } + + ////config.lpCallbackData = this.callbackData; // How do you do this? Need to pin the ref? + config.cxWidth = this.width; + + // The call all this mucking about is here for. + UnsafeNativeMethods.TaskDialogIndirect(ref config, out result, out radioButtonResult, out verificationFlagChecked); + } + finally + { + // Free the unmanged memory needed for the button arrays. + // There is the possiblity of leaking memory if the app-domain is destroyed in a non clean way + // and the hosting OS process is kept alive but fixing this would require using hardening techniques + // that are not required for the users of this class. + if (config.pButtons != IntPtr.Zero) + { + int elementSize = Marshal.SizeOf(typeof(TaskDialogButton)); + for (int i = 0; i < config.cButtons; i++) + { + unsafe + { + byte* p = (byte*)config.pButtons; + Marshal.DestroyStructure((IntPtr)(p + (elementSize * i)), typeof(TaskDialogButton)); + } + } + + Marshal.FreeHGlobal(config.pButtons); + } + + if (config.pRadioButtons != IntPtr.Zero) + { + int elementSize = Marshal.SizeOf(typeof(TaskDialogButton)); + for (int i = 0; i < config.cRadioButtons; i++) + { + unsafe + { + byte* p = (byte*)config.pRadioButtons; + Marshal.DestroyStructure((IntPtr)(p + (elementSize * i)), typeof(TaskDialogButton)); + } + } + + Marshal.FreeHGlobal(config.pRadioButtons); + } + } + + return result; + } + + /// + /// The callback from the native Task Dialog. This prepares the friendlier arguments and calls the simplier callback. + /// + /// The window handle of the Task Dialog that is active. + /// The notification. A TaskDialogNotification value. + /// Specifies additional noitification information. The contents of this parameter depends on the value of the msg parameter. + /// Specifies additional noitification information. The contents of this parameter depends on the value of the msg parameter. + /// Specifies the application-defined value given in the call to TaskDialogIndirect. + /// A HRESULT. It's not clear in the spec what a failed result will do. + private int PrivateCallback([In] IntPtr hwnd, [In] uint msg, [In] UIntPtr wparam, [In] IntPtr lparam, [In] IntPtr refData) + { + TaskDialogCallback callback = this.callback; + if (callback != null) + { + // Prepare arguments for the callback to the user we are insulating from Interop casting sillyness. + + // Future: Consider reusing a single ActiveTaskDialog object and mark it as destroyed on the destry notification. + ActiveTaskDialog activeDialog = new ActiveTaskDialog(hwnd); + TaskDialogNotificationArgs args = new TaskDialogNotificationArgs(); + args.Notification = (TaskDialogNotification)msg; + switch (args.Notification) + { + case TaskDialogNotification.ButtonClicked: + case TaskDialogNotification.RadioButtonClicked: + args.ButtonId = (int)wparam; + break; + case TaskDialogNotification.HyperlinkClicked: + args.Hyperlink = Marshal.PtrToStringUni(lparam); + break; + case TaskDialogNotification.Timer: + args.TimerTickCount = (uint)wparam; + break; + case TaskDialogNotification.VerificationClicked: + args.VerificationFlagChecked = (wparam != UIntPtr.Zero); + break; + case TaskDialogNotification.ExpandoButtonClicked: + args.Expanded = (wparam != UIntPtr.Zero); + break; + } + + return (callback(activeDialog, args, this.callbackData) ? 1 : 0); + } + + return 0; // false; + } + + /// + /// Helper function to set or clear a bit in the flags field. + /// + /// The Flag bit to set or clear. + /// True to set, false to clear the bit in the flags field. + private void SetFlag(UnsafeNativeMethods.TASKDIALOG_FLAGS flag, bool value) + { + if (value) + { + this.flags |= flag; + } + else + { + this.flags &= ~flag; + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/TaskDialog/TaskDialogCommonDialog.cs b/branches/ph-plugins/ProcessHacker/Components/TaskDialog/TaskDialogCommonDialog.cs new file mode 100644 index 000000000..e401e5d2b --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/TaskDialog/TaskDialogCommonDialog.cs @@ -0,0 +1,104 @@ +//------------------------------------------------------------------ +// +// A P/Invoke wrapper for TaskDialog. Usability was given preference to perf and size. +// +// +// +//------------------------------------------------------------------ + +namespace ProcessHacker.Components +{ + using System; + using System.Windows.Forms; + + /// + /// TaskDialog wrapped in a CommonDialog class. This is required to work well in + /// MMC 3.0. In MMC 3.0 you must use the ShowDialog methods on the MMC classes to + /// correctly show a modal dialog. This class will allow you to do this and keep access + /// to the results of the TaskDialog. + /// + public class TaskDialogCommonDialog : CommonDialog + { + /// + /// The TaskDialog we will display. + /// + private TaskDialog taskDialog; + + /// + /// The result of the dialog, either a DialogResult value for common push buttons set in the TaskDialog.CommonButtons + /// member or the ButtonID from a TaskDialogButton structure set on the TaskDialog.Buttons member. + /// + private int taskDialogResult; + + /// + /// The verification flag result of the dialog. True if the verification checkbox was checked when the dialog + /// was dismissed. + /// + private bool verificationFlagCheckedResult; + + /// + /// TaskDialog wrapped in a CommonDialog class. THis is required to work well in + /// MMC 2.1. In MMC 2.1 you must use the ShowDialog methods on the MMC classes to + /// correctly show a modal dialog. This class will allow you to do this and keep access + /// to the results of the TaskDialog. + /// + /// The TaskDialog to show. + public TaskDialogCommonDialog(TaskDialog taskDialog) + { + if (taskDialog == null) + { + throw new ArgumentNullException("taskDialog"); + } + + this.taskDialog = taskDialog; + } + + /// + /// The TaskDialog to show. + /// + public TaskDialog TaskDialog + { + get { return this.taskDialog; } + } + + /// + /// The result of the dialog, either a DialogResult value for common push buttons set in the TaskDialog.CommonButtons + /// member or the ButtonID from a TaskDialogButton structure set on the TaskDialog.Buttons member. + /// + public int TaskDialogResult + { + get { return this.taskDialogResult; } + } + + /// + /// The verification flag result of the dialog. True if the verification checkbox was checked when the dialog + /// was dismissed. + /// + public bool VerificationFlagCheckedResult + { + get { return this.verificationFlagCheckedResult; } + } + + /// + /// Reset the common dialog. + /// + public override void Reset() + { + this.taskDialog.Reset(); + } + + /// + /// The required implementation of CommonDialog that shows the Task Dialog. + /// + /// Owner window. This can be null. + /// If this method returns true, then ShowDialog will return DialogResult.OK. + /// If this method returns false, then ShowDialog will return DialogResult.Cancel. The + /// user of this class must use the TaskDialogResult member to get more information. + /// + protected override bool RunDialog(IntPtr hwndOwner) + { + this.taskDialogResult = this.taskDialog.Show(hwndOwner, out this.verificationFlagCheckedResult); + return (this.taskDialogResult != (int)DialogResult.Cancel); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/TaskDialog/TaskDialogNotificationArgs.cs b/branches/ph-plugins/ProcessHacker/Components/TaskDialog/TaskDialogNotificationArgs.cs new file mode 100644 index 000000000..17e491eb9 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/TaskDialog/TaskDialogNotificationArgs.cs @@ -0,0 +1,111 @@ +//------------------------------------------------------------------ +// +// A P/Invoke wrapper for TaskDialog. Usability was given preference to perf and size. +// +// +// +//------------------------------------------------------------------ + +namespace ProcessHacker.Components +{ + using System; + using System.Drawing; + using System.Windows.Forms; + using System.Runtime.InteropServices; + + /// + /// Arguments passed to the TaskDialog callback. + /// + public class TaskDialogNotificationArgs + { + /// + /// What the TaskDialog callback is a notification of. + /// + private TaskDialogNotification notification; + + /// + /// The button ID if the notification is about a button. This a DialogResult + /// value or the ButtonID member of a TaskDialogButton set in the + /// TaskDialog.Buttons or TaskDialog.RadioButtons members. + /// + private int buttonId; + + /// + /// The HREF string of the hyperlink the notification is about. + /// + private string hyperlink; + + /// + /// The number of milliseconds since the dialog was opened or the last time the + /// callback for a timer notification reset the value by returning true. + /// + private uint timerTickCount; + + /// + /// The state of the verification flag when the notification is about the verification flag. + /// + private bool verificationFlagChecked; + + /// + /// The state of the dialog expando when the notification is about the expando. + /// + private bool expanded; + + /// + /// What the TaskDialog callback is a notification of. + /// + public TaskDialogNotification Notification + { + get { return this.notification; } + set { this.notification = value; } + } + + /// + /// The button ID if the notification is about a button. This a DialogResult + /// value or the ButtonID member of a TaskDialogButton set in the + /// TaskDialog.Buttons member. + /// + public int ButtonId + { + get { return this.buttonId; } + set { this.buttonId = value; } + } + + /// + /// The HREF string of the hyperlink the notification is about. + /// + public string Hyperlink + { + get { return this.hyperlink; } + set { this.hyperlink = value; } + } + + /// + /// The number of milliseconds since the dialog was opened or the last time the + /// callback for a timer notification reset the value by returning true. + /// + public uint TimerTickCount + { + get { return this.timerTickCount; } + set { this.timerTickCount = value; } + } + + /// + /// The state of the verification flag when the notification is about the verification flag. + /// + public bool VerificationFlagChecked + { + get { return this.verificationFlagChecked; } + set { this.verificationFlagChecked = value; } + } + + /// + /// The state of the dialog expando when the notification is about the expando. + /// + public bool Expanded + { + get { return this.expanded; } + set { this.expanded = value; } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/TaskDialog/UnsafeNativeMethods.cs b/branches/ph-plugins/ProcessHacker/Components/TaskDialog/UnsafeNativeMethods.cs new file mode 100644 index 000000000..cd842b088 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/TaskDialog/UnsafeNativeMethods.cs @@ -0,0 +1,446 @@ +//------------------------------------------------------------------ +// +// A P/Invoke wrapper for TaskDialog. Usability was given preference to perf and size. +// +// +// +//------------------------------------------------------------------ + +namespace ProcessHacker.Components +{ + using System; + using System.Diagnostics.CodeAnalysis; + using System.Runtime.InteropServices; + + /// + /// Class to hold native code interop declarations. + /// + internal static partial class UnsafeNativeMethods + { + /// + /// WM_USER taken from WinUser.h + /// + internal const uint WM_USER = 0x0400; + + /// + /// The signature of the callback that receives messages from the Task Dialog when various events occur. + /// + /// The window handle of the + /// The message being passed. + /// wParam which is interpreted differently depending on the message. + /// wParam which is interpreted differently depending on the message. + /// The refrence data that was set to TaskDialog.CallbackData. + /// A HRESULT value. The return value is specific to the message being processed. + internal delegate int TaskDialogCallback([In] IntPtr hwnd, [In] uint msg, [In] UIntPtr wParam, [In] IntPtr lParam, [In] IntPtr refData); + + /// + /// TASKDIALOG_FLAGS taken from CommCtrl.h. + /// + [Flags] + internal enum TASKDIALOG_FLAGS + { + /// + /// Enable hyperlinks. + /// + TDF_ENABLE_HYPERLINKS = 0x0001, + + /// + /// Use icon handle for main icon. + /// + TDF_USE_HICON_MAIN = 0x0002, + + /// + /// Use icon handle for footer icon. + /// + TDF_USE_HICON_FOOTER = 0x0004, + + /// + /// Allow dialog to be cancelled, even if there is no cancel button. + /// + TDF_ALLOW_DIALOG_CANCELLATION = 0x0008, + + /// + /// Use command links rather than buttons. + /// + TDF_USE_COMMAND_LINKS = 0x0010, + + /// + /// Use command links with no icons rather than buttons. + /// + TDF_USE_COMMAND_LINKS_NO_ICON = 0x0020, + + /// + /// Show expanded info in the footer area. + /// + TDF_EXPAND_FOOTER_AREA = 0x0040, + + /// + /// Expand by default. + /// + TDF_EXPANDED_BY_DEFAULT = 0x0080, + + /// + /// Start with verification flag already checked. + /// + TDF_VERIFICATION_FLAG_CHECKED = 0x0100, + + /// + /// Show a progress bar. + /// + TDF_SHOW_PROGRESS_BAR = 0x0200, + + /// + /// Show a marquee progress bar. + /// + TDF_SHOW_MARQUEE_PROGRESS_BAR = 0x0400, + + /// + /// Callback every 200 milliseconds. + /// + TDF_CALLBACK_TIMER = 0x0800, + + /// + /// Center the dialog on the owner window rather than the monitor. + /// + TDF_POSITION_RELATIVE_TO_WINDOW = 0x1000, + + /// + /// Right to Left Layout. + /// + TDF_RTL_LAYOUT = 0x2000, + + /// + /// No default radio button. + /// + TDF_NO_DEFAULT_RADIO_BUTTON = 0x4000, + + /// + /// Task Dialog can be minimized. + /// + TDF_CAN_BE_MINIMIZED = 0x8000 + } + + /// + /// TASKDIALOG_ELEMENTS taken from CommCtrl.h + /// + internal enum TASKDIALOG_ELEMENTS + { + /// + /// The content element. + /// + TDE_CONTENT, + + /// + /// Expanded Information. + /// + TDE_EXPANDED_INFORMATION, + + /// + /// Footer. + /// + TDE_FOOTER, + + /// + /// Main Instructions + /// + TDE_MAIN_INSTRUCTION + } + + /// + /// TASKDIALOG_ICON_ELEMENTS taken from CommCtrl.h + /// + internal enum TASKDIALOG_ICON_ELEMENTS + { + /// + /// Main instruction icon. + /// + TDIE_ICON_MAIN, + + /// + /// Footer icon. + /// + TDIE_ICON_FOOTER + } + + /// + /// TASKDIALOG_MESSAGES taken from CommCtrl.h. + /// + internal enum TASKDIALOG_MESSAGES : uint + { + // Spec is not clear on what this is for. + ///// + ///// Navigate page. + ///// + ////TDM_NAVIGATE_PAGE = WM_USER + 101, + + /// + /// Click button. + /// + TDM_CLICK_BUTTON = WM_USER + 102, // wParam = Button ID + + /// + /// Set Progress bar to be marquee mode. + /// + TDM_SET_MARQUEE_PROGRESS_BAR = WM_USER + 103, // wParam = 0 (nonMarque) wParam != 0 (Marquee) + + /// + /// Set Progress bar state. + /// + TDM_SET_PROGRESS_BAR_STATE = WM_USER + 104, // wParam = new progress state + + /// + /// Set progress bar range. + /// + TDM_SET_PROGRESS_BAR_RANGE = WM_USER + 105, // lParam = MAKELPARAM(nMinRange, nMaxRange) + + /// + /// Set progress bar position. + /// + TDM_SET_PROGRESS_BAR_POS = WM_USER + 106, // wParam = new position + + /// + /// Set progress bar marquee (animation). + /// + TDM_SET_PROGRESS_BAR_MARQUEE = WM_USER + 107, // wParam = 0 (stop marquee), wParam != 0 (start marquee), lparam = speed (milliseconds between repaints) + + /// + /// Set a text element of the Task Dialog. + /// + TDM_SET_ELEMENT_TEXT = WM_USER + 108, // wParam = element (TASKDIALOG_ELEMENTS), lParam = new element text (LPCWSTR) + + /// + /// Click a radio button. + /// + TDM_CLICK_RADIO_BUTTON = WM_USER + 110, // wParam = Radio Button ID + + /// + /// Enable or disable a button. + /// + TDM_ENABLE_BUTTON = WM_USER + 111, // lParam = 0 (disable), lParam != 0 (enable), wParam = Button ID + + /// + /// Enable or disable a radio button. + /// + TDM_ENABLE_RADIO_BUTTON = WM_USER + 112, // lParam = 0 (disable), lParam != 0 (enable), wParam = Radio Button ID + + /// + /// Check or uncheck the verfication checkbox. + /// + TDM_CLICK_VERIFICATION = WM_USER + 113, // wParam = 0 (unchecked), 1 (checked), lParam = 1 (set key focus) + + /// + /// Update the text of an element (no effect if origially set as null). + /// + TDM_UPDATE_ELEMENT_TEXT = WM_USER + 114, // wParam = element (TASKDIALOG_ELEMENTS), lParam = new element text (LPCWSTR) + + /// + /// Designate whether a given Task Dialog button or command link should have a User Account Control (UAC) shield icon. + /// + TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE = WM_USER + 115, // wParam = Button ID, lParam = 0 (elevation not required), lParam != 0 (elevation required) + + /// + /// Refreshes the icon of the task dialog. + /// + TDM_UPDATE_ICON = WM_USER + 116 // wParam = icon element (TASKDIALOG_ICON_ELEMENTS), lParam = new icon (hIcon if TDF_USE_HICON_* was set, PCWSTR otherwise) + } + + ///// + ///// TaskDialog taken from commctrl.h. + ///// + ///// Parent window. + ///// Module instance to get resources from. + ///// Title of the Task Dialog window. + ///// The main instructions. + ///// Common push buttons to show. + ///// The main icon. + ///// The push button pressed. + ////[DllImport("ComCtl32", CharSet = CharSet.Unicode, PreserveSig = false)] + ////public static extern void TaskDialog( + //// [In] IntPtr hwndParent, + //// [In] IntPtr hInstance, + //// [In] String pszWindowTitle, + //// [In] String pszMainInstruction, + //// [In] TaskDialogCommonButtons dwCommonButtons, + //// [In] IntPtr pszIcon, + //// [Out] out int pnButton); + + /// + /// TaskDialogIndirect taken from commctl.h + /// + /// All the parameters about the Task Dialog to Show. + /// The push button pressed. + /// The radio button that was selected. + /// The state of the verification checkbox on dismiss of the Task Dialog. + [DllImport("comctl32.dll", CharSet = CharSet.Unicode, PreserveSig = false)] + internal static extern void TaskDialogIndirect( + [In] ref TASKDIALOGCONFIG pTaskConfig, + [Out] out int pnButton, + [Out] out int pnRadioButton, + [MarshalAs(UnmanagedType.Bool)] + [Out] out bool pfVerificationFlagChecked); + + /// + /// Win32 SendMessage. + /// + /// Window handle to send to. + /// The windows message to send. + /// Specifies additional message-specific information. + /// Specifies additional message-specific information. + /// The return value specifies the result of the message processing; it depends on the message sent. + [DllImport("user32.dll")] + internal static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); + + /// + /// Win32 SendMessage. + /// + /// Window handle to send to. + /// The windows message to send. + /// Specifies additional message-specific information. + /// Specifies additional message-specific information as a string. + /// The return value specifies the result of the message processing; it depends on the message sent. + [DllImport("user32.dll", EntryPoint="SendMessage")] + internal static extern IntPtr SendMessageWithString(IntPtr hWnd, uint Msg, IntPtr wParam, [MarshalAs(UnmanagedType.LPWStr)] string lParam); + + /// + /// TASKDIALOGCONFIG taken from commctl.h. + /// + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)] + internal struct TASKDIALOGCONFIG + { + /// + /// Size of the structure in bytes. + /// + public uint cbSize; + + /// + /// Parent window handle. + /// + [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] // Managed code owns actual resource. Passed to native in syncronous call. No lifetime issues. + public IntPtr hwndParent; + + /// + /// Module instance handle for resources. + /// + [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] // Managed code owns actual resource. Passed to native in syncronous call. No lifetime issues. + public IntPtr hInstance; + + /// + /// Flags. + /// + public TASKDIALOG_FLAGS dwFlags; // TASKDIALOG_FLAGS (TDF_XXX) flags + + /// + /// Bit flags for commonly used buttons. + /// + public TaskDialogCommonButtons dwCommonButtons; // TASKDIALOG_COMMON_BUTTON (TDCBF_XXX) flags + + /// + /// Window title. + /// + [MarshalAs(UnmanagedType.LPWStr)] + public string pszWindowTitle; // string or MAKEINTRESOURCE() + + /// + /// The Main icon. Overloaded member. Can be string, a handle, a special value or a resource ID. + /// + [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] // Managed code owns actual resource. Passed to native in syncronous call. No lifetime issues. + public IntPtr MainIcon; + + /// + /// Main Instruction. + /// + [MarshalAs(UnmanagedType.LPWStr)] + public string pszMainInstruction; + + /// + /// Content. + /// + [MarshalAs(UnmanagedType.LPWStr)] + public string pszContent; + + /// + /// Count of custom Buttons. + /// + public uint cButtons; + + /// + /// Array of custom buttons. + /// + [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] // Managed code owns actual resource. Passed to native in syncronous call. No lifetime issues. + public IntPtr pButtons; + + /// + /// ID of default button. + /// + public int nDefaultButton; + + /// + /// Count of radio Buttons. + /// + public uint cRadioButtons; + + /// + /// Array of radio buttons. + /// + [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] // Managed code owns actual resource. Passed to native in syncronous call. No lifetime issues. + public IntPtr pRadioButtons; + + /// + /// ID of default radio button. + /// + public int nDefaultRadioButton; + + /// + /// Text for verification check box. often "Don't ask be again". + /// + [MarshalAs(UnmanagedType.LPWStr)] + public string pszVerificationText; + + /// + /// Expanded Information. + /// + [MarshalAs(UnmanagedType.LPWStr)] + public string pszExpandedInformation; + + /// + /// Text for expanded control. + /// + [MarshalAs(UnmanagedType.LPWStr)] + public string pszExpandedControlText; + + /// + /// Text for expanded control. + /// + [MarshalAs(UnmanagedType.LPWStr)] + public string pszCollapsedControlText; + + /// + /// Icon for the footer. An overloaded member link MainIcon. + /// + [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] // Managed code owns actual resource. Passed to native in syncronous call. No lifetime issues. + public IntPtr FooterIcon; + + /// + /// Footer Text. + /// + [MarshalAs(UnmanagedType.LPWStr)] + public string pszFooter; + + /// + /// Function pointer for callback. + /// + public TaskDialogCallback pfCallback; + + /// + /// Data that will be passed to the call back. + /// + [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] // Managed code owns actual resource. Passed to native in syncronous call. No lifetime issues. + public IntPtr lpCallbackData; + + /// + /// Width of the Task Dialog's area in DLU's. + /// + public uint cxWidth; // width of the Task Dialog's client area in DLU's. If 0, Task Dialog will calculate the ideal width. + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/TaskbarLib/Interop/COMTypes.cs b/branches/ph-plugins/ProcessHacker/Components/TaskbarLib/Interop/COMTypes.cs new file mode 100644 index 000000000..3d938138b --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/TaskbarLib/Interop/COMTypes.cs @@ -0,0 +1,284 @@ +/* + * Process Hacker - + * ProcessHacker Taskbar Extensions + * + * Copyright (C) 2009 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 . + * + */ + +using System; +using System.Runtime.InteropServices; +using System.Text; +using System.Runtime.CompilerServices; +using ProcessHacker.Native.Api; + +namespace TaskbarLib.Interop +{ + #region "Interface Classes" + + [ComImportAttribute()] + [GuidAttribute("86C14003-4D6B-4EF3-A7B4-0506663B2E68")] + [ClassInterfaceAttribute(ClassInterfaceType.None)] + internal class CApplicationDestinations { } + + [ComImportAttribute()] + [GuidAttribute("86BEC222-30F2-47E0-9F25-60D11CD75C28")] + [ClassInterfaceAttribute(ClassInterfaceType.None)] + internal class CApplicationDocumentLists { } + + [ComImportAttribute()] + [GuidAttribute("56FDF344-FD6D-11d0-958A-006097C9A090")] + [ClassInterfaceAttribute(ClassInterfaceType.None)] + internal class CTaskbarList { } + + [ComImportAttribute()] + [GuidAttribute("00021401-0000-0000-C000-000000000046")] + [ClassInterfaceAttribute(ClassInterfaceType.None)] + internal class CShellLink { } + + [ComImportAttribute()] + [GuidAttribute("77F10CF0-3DB5-4966-B520-B7C54FD35ED6")] + [ClassInterfaceAttribute(ClassInterfaceType.None)] + internal class CDestinationList { } + + [ComImportAttribute()] + [GuidAttribute("2D3468C1-36A7-43B6-AC24-D3F02FD9607A")] + [ClassInterfaceAttribute(ClassInterfaceType.None)] + internal class CEnumerableObjectCollection { } + + #endregion + + #region "Interfaces" + + [ComImportAttribute()] + [GuidAttribute("92CA9DCD-5622-4BBA-A805-5E9F541BD8C9")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + internal interface IObjectArray + { + [PreserveSig] + HResult GetCount(out uint cObjects); + [PreserveSig] + HResult GetAt(uint iIndex, ref Guid riid, [Out(), MarshalAs(UnmanagedType.Interface)] out object ppvObject); + } + + [ComImportAttribute()] + [GuidAttribute(SafeNativeMethods.IID_IObjectCollection)] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + internal interface IObjectCollection + { + // IObjectArray + [PreserveSig] + HResult GetCount(out uint cObjects); + [PreserveSig] + HResult GetAt(uint iIndex, ref Guid riid, [Out(), MarshalAs(UnmanagedType.Interface)] out object ppvObject); + + // IObjectCollection + [PreserveSig] + HResult AddObject([MarshalAs(UnmanagedType.Interface)] object pvObject); + [PreserveSig] + HResult AddFromArray([MarshalAs(UnmanagedType.Interface)] IObjectArray poaSource); + [PreserveSig] + HResult RemoveObject(uint uiIndex); + [PreserveSig] + HResult Clear(); + } + + [ComImportAttribute()] + [GuidAttribute("886d8eeb-8cf2-4446-8d02-cdba1dbdcf99")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + internal interface IPropertyStore + { + [PreserveSig] + HResult GetCount(out UInt32 cProps); + [PreserveSig] + HResult GetAt(UInt32 iProp, [MarshalAs(UnmanagedType.Struct)] out PropertyKey pkey); + [PreserveSig] + HResult GetValue([In, MarshalAs(UnmanagedType.Struct)] ref PropertyKey pkey, [Out(), MarshalAs(UnmanagedType.Struct)] out PropVariant pv); + [PreserveSig] + HResult SetValue([In, MarshalAs(UnmanagedType.Struct)] ref PropertyKey pkey, [In, MarshalAs(UnmanagedType.Struct)] ref PropVariant pv); + [PreserveSig] + HResult Commit(); + } + + [ComImportAttribute()] + [GuidAttribute("6332DEBF-87B5-4670-90C0-5E57B408A49E")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + internal interface ICustomDestinationList + { + [PreserveSig] + HResult SetAppID([MarshalAs(UnmanagedType.LPWStr)] string pszAppID); + [PreserveSig] + HResult BeginList(out uint cMaxSlots, ref Guid riid, [Out(), MarshalAs(UnmanagedType.Interface)] out object ppvObject); + [PreserveSig] + HResult AppendCategory([MarshalAs(UnmanagedType.LPWStr)] string pszCategory, [MarshalAs(UnmanagedType.Interface)] IObjectArray poa); + HResult AppendKnownCategory([MarshalAs(UnmanagedType.I4)] KnownDestCategory category); + [PreserveSig] + HResult AddUserTasks([MarshalAs(UnmanagedType.Interface)] IObjectArray poa); + [PreserveSig] + HResult CommitList(); + [PreserveSig] + HResult GetRemovedDestinations(ref Guid riid, [Out(), MarshalAs(UnmanagedType.Interface)] out object ppvObject); + [PreserveSig] + HResult DeleteList([MarshalAs(UnmanagedType.LPWStr)] string pszAppID); + [PreserveSig] + HResult AbortList(); + } + + [ComImportAttribute()] + [GuidAttribute("12337D35-94C6-48A0-BCE7-6A9C69D4D600")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + internal interface IApplicationDestinations + { + [PreserveSig] + HResult SetAppID([MarshalAs(UnmanagedType.LPWStr)] string pszAppID); + [PreserveSig] + HResult RemoveDestination([MarshalAs(UnmanagedType.Interface)] object pvObject); + [PreserveSig] + HResult RemoveAllDestinations(); + } + + [ComImportAttribute()] + [GuidAttribute("3C594F9F-9F30-47A1-979A-C9E83D3D0A06")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + internal interface IApplicationDocumentLists + { + [PreserveSig] + HResult SetAppID([MarshalAs(UnmanagedType.LPWStr)] string pszAppID); + [PreserveSig] + HResult GetList([MarshalAs(UnmanagedType.I4)] AppDocListType listtype, uint cItemsDesired, ref Guid riid, [Out(), MarshalAs(UnmanagedType.Interface)] out object ppvObject); + } + + [ComImportAttribute()] + [GuidAttribute("ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + internal interface ITaskbarList3 + { + // ITaskbarList + [PreserveSig] + HResult HrInit(); + [PreserveSig] + HResult AddTab(IntPtr hwnd); + [PreserveSig] + HResult DeleteTab(IntPtr hwnd); + [PreserveSig] + HResult ActivateTab(IntPtr hwnd); + [PreserveSig] + HResult SetActiveAlt(IntPtr hwnd); + + // ITaskbarList2 + [PreserveSig] + HResult MarkFullscreenWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.Bool)] bool fFullscreen); + + // ITaskbarList3 + [PreserveSig] + HResult SetProgressValue(IntPtr hwnd, UInt64 ullCompleted, UInt64 ullTotal); + [PreserveSig] + HResult SetProgressState(IntPtr hwnd, uint tbpFlags); + [PreserveSig] + HResult RegisterTab(IntPtr hwndTab, IntPtr hwndMDI); + [PreserveSig] + HResult UnregisterTab(IntPtr hwndTab); + [PreserveSig] + HResult SetTabOrder(IntPtr hwndTab, IntPtr hwndInsertBefore); + [PreserveSig] + HResult SetTabActive(IntPtr hwndTab, IntPtr hwndMDI, Tbatflag tbatFlags); + [PreserveSig] + HResult ThumbBarAddButtons(IntPtr hwnd, int cButtons, [MarshalAs(UnmanagedType.LPArray)] THUMBBUTTON[] pButtons); + [PreserveSig] + HResult ThumbBarUpdateButtons(IntPtr hwnd, int cButtons, [MarshalAs(UnmanagedType.LPArray)] THUMBBUTTON[] pButtons); + [PreserveSig] + HResult ThumbBarSetImageList(IntPtr hwnd, IntPtr himl); + [PreserveSig] + HResult SetOverlayIcon(IntPtr hwnd, IntPtr hIcon, [MarshalAs(UnmanagedType.LPWStr)] string pszDescription); + [PreserveSig] + HResult SetThumbnailTooltip(IntPtr hwnd, [MarshalAs(UnmanagedType.LPWStr)] string pszTip); + [PreserveSig] + HResult SetThumbnailClip(IntPtr hwnd, ref Rect prcClip); + } + + [ComImportAttribute()] + [GuidAttribute("43826D1E-E718-42EE-BC55-A1E261C37BFE")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + internal interface IShellItem + { + //[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + [PreserveSig] + HResult BindToHandler([In, MarshalAs(UnmanagedType.Interface)] IntPtr pbc, [In] ref Guid bhid, [In] ref Guid riid, out IntPtr ppv); + + //[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + [PreserveSig] + HResult GetParent([MarshalAs(UnmanagedType.Interface)] out IShellItem ppsi); + + //[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + [PreserveSig] + HResult GetDisplayName([In] SIGDN sigdnName, [MarshalAs(UnmanagedType.LPWStr)] out string ppszName); + + //[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + [PreserveSig] + HResult GetAttributes([In] uint sfgaoMask, out uint psfgaoAttribs); + + //[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] + [PreserveSig] + HResult Compare([In, MarshalAs(UnmanagedType.Interface)] IShellItem psi, [In] uint hint, out int piOrder); + } + + [ComImportAttribute()] + [GuidAttribute("000214F9-0000-0000-C000-000000000046")] + [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)] + internal interface IShellLinkW + { + [PreserveSig] + HResult GetPath([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, IntPtr pfd, uint fFlags); + [PreserveSig] + HResult GetIDList(out IntPtr ppidl); + [PreserveSig] + HResult SetIDList(IntPtr pidl); + [PreserveSig] + HResult GetDescription([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxName); + [PreserveSig] + HResult SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName); + [PreserveSig] + HResult GetWorkingDirectory([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath); + [PreserveSig] + HResult SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir); + [PreserveSig] + HResult GetArguments([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath); + [PreserveSig] + HResult SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs); + [PreserveSig] + HResult GetHotKey(out short wHotKey); + [PreserveSig] + HResult SetHotKey(short wHotKey); + [PreserveSig] + HResult GetShowCmd(out uint iShowCmd); + [PreserveSig] + HResult SetShowCmd(uint iShowCmd); + [PreserveSig] + HResult GetIconLocation([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, int cchIconPath, out int iIcon); + [PreserveSig] + HResult SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon); + [PreserveSig] + HResult SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, uint dwReserved); + [PreserveSig] + HResult Resolve(IntPtr hwnd, uint fFlags); + [PreserveSig] + HResult SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile); + } + + #endregion +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/TaskbarLib/Interop/Interop.cs b/branches/ph-plugins/ProcessHacker/Components/TaskbarLib/Interop/Interop.cs new file mode 100644 index 000000000..1724f50d0 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/TaskbarLib/Interop/Interop.cs @@ -0,0 +1,257 @@ +/* + * Process Hacker - + * ProcessHacker Taskbar Extensions + * + * Copyright (C) 2009 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 . + * + */ + +using System; +using System.Runtime.InteropServices; +using System.Security; +using System.Text; +using ProcessHacker.Native.Api; + +namespace TaskbarLib.Interop +{ + [Flags] + internal enum KnownDestCategory + { + FREQUENT = 1, + RECENT + } + + [Flags] + internal enum AppDocListType + { + ADLT_RECENT = 0, + ADLT_FREQUENT + } + + [Flags] + internal enum Tbatflag + { + TBATF_USEMDITHUMBNAIL = 0x1, + TBATF_USEMDILIVEPREVIEW = 0x2 + } + + [Flags] + internal enum ThumbnailButtonMask + { + Bitmap = 0x1, + Icon = 0x2, + Tooltip = 0x4, + Flags = 0x8 + } + + [Flags] + internal enum ThumbnailButtonFlags + { + ENABLED = 0, + DISABLED = 0x1, + DISMISSONCLICK = 0x2, + NOBACKGROUND = 0x4, + HIDDEN = 0x8 + } + + [Flags] + internal enum SIGDN : uint + { + SIGDN_NORMALDISPLAY = 0x00000000, // SHGDN_NORMAL + SIGDN_PARENTRELATIVEPARSING = 0x80018001, // SHGDN_INFOLDER | SHGDN_FORPARSING + SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000, // SHGDN_FORPARSING + SIGDN_PARENTRELATIVEEDITING = 0x80031001, // SHGDN_INFOLDER | SHGDN_FOREDITING + SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000, // SHGDN_FORPARSING | SHGDN_FORADDRESSBAR + SIGDN_FILESYSPATH = 0x80058000, // SHGDN_FORPARSING + SIGDN_URL = 0x80068000, // SHGDN_FORPARSING + SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x8007c001, // SHGDN_INFOLDER | SHGDN_FORPARSING | SHGDN_FORADDRESSBAR + SIGDN_PARENTRELATIVE = 0x80080001 // SHGDN_INFOLDER + } + + [StructLayout(LayoutKind.Sequential)] + internal struct POINT + { + internal int X; + internal int Y; + + internal POINT(int x, int y) + { + this.X = x; + this.Y = y; + } + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + internal struct THUMBBUTTON + { + [MarshalAs(UnmanagedType.U4)] + public ThumbnailButtonMask dwMask; + public int iId; + public int iBitmap; + public IntPtr hIcon; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] + public string szTip; + [MarshalAs(UnmanagedType.U4)] + public ThumbnailButtonFlags dwFlags; + } + + [StructLayout(LayoutKind.Sequential, Pack = 4)] + internal struct PropertyKey + { + public Guid fmtid; + public uint pid; + + public PropertyKey(Guid fmtid, uint pid) + { + this.fmtid = fmtid; + this.pid = pid; + } + + public static PropertyKey PKEY_Title = new PropertyKey(new Guid("F29F85E0-4FF9-1068-AB91-08002B27B3D9"), 2); + public static PropertyKey PKEY_AppUserModel_ID = new PropertyKey(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 5); + public static PropertyKey PKEY_AppUserModel_IsDestListSeparator = new PropertyKey(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 6); + public static PropertyKey PKEY_AppUserModel_RelaunchCommand = new PropertyKey(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 2); + public static PropertyKey PKEY_AppUserModel_RelaunchDisplayNameResource = new PropertyKey(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 4); + public static PropertyKey PKEY_AppUserModel_RelaunchIconResource = new PropertyKey(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 3); + } + + [StructLayout(LayoutKind.Explicit)] + internal struct CALPWSTR + { + [FieldOffset(0)] + internal uint cElems; + [FieldOffset(4)] + internal IntPtr pElems; + } + + [StructLayout(LayoutKind.Explicit)] + internal struct PropVariant : IDisposable + { + [FieldOffset(0)] + private ushort vt; + [FieldOffset(8)] + private IntPtr pointerValue; + [FieldOffset(8)] + private byte byteValue; + [FieldOffset(8)] + private long longValue; + [FieldOffset(8)] + private short boolValue; + [MarshalAs(UnmanagedType.Struct)] + [FieldOffset(8)] + private CALPWSTR calpwstr; + + public VarEnum VarType + { + get { return (VarEnum)vt; } + } + + public void SetValue(String val) + { + this.Clear(); + this.vt = (ushort)VarEnum.VT_LPWSTR; + this.pointerValue = Marshal.StringToCoTaskMemUni(val); + } + + public void SetValue(bool val) + { + this.Clear(); + this.vt = (ushort)VarEnum.VT_BOOL; + this.boolValue = val ? (short)-1 : (short)0; + } + + public string GetValue() + { + return Marshal.PtrToStringUni(this.pointerValue); + } + + public void Clear() + { + HResult clearResult = UnsafeNativeMethods.PropVariantClear(ref this); + clearResult.ThrowIf(); + } + + public void Dispose() + { + Marshal.FreeCoTaskMem(this.pointerValue); + } + } + + [SuppressUnmanagedCodeSecurity] + internal static class SafeNativeMethods + { + //Obviously, these GUIDs shouldn't be modified. The reason they + //are not readonly is that they are passed with 'ref' to various + //native methods. + public static Guid IID_IObjectArray = new Guid("92CA9DCD-5622-4BBA-A805-5E9F541BD8C9"); + public const string IID_IObjectCollection = "5632B1A4-E38A-400A-928A-D4CD63230295"; + public static Guid IID_IPropertyStore = new Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99"); + public static Guid IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046"); + + public const int DWM_SIT_DISPLAYFRAME = 0x00000001; + public const int DWMWA_FORCE_ICONIC_REPRESENTATION = 7; + public const int DWMWA_HAS_ICONIC_BITMAP = 10; + + public const int WA_ACTIVE = 1; + public const int WA_CLICKACTIVE = 2; + + public const int SC_CLOSE = 0xF060; + + // Thumbbutton WM_COMMAND notification + public const uint THBN_CLICKED = 0x1800; + } + + [SuppressUnmanagedCodeSecurity] + internal static class UnsafeNativeMethods + { + public static readonly uint WM_TaskbarButtonCreated = RegisterWindowMessage("TaskbarButtonCreated"); + + [DllImport("ole32.dll")] + public static extern HResult PropVariantClear(ref PropVariant pvar); + + [DllImport("dwmapi.dll")] + public static extern HResult DwmSetIconicThumbnail(IntPtr hwnd, IntPtr hbitmap, uint flags); + + [DllImport("dwmapi.dll")] + public static extern HResult DwmSetIconicLivePreviewBitmap(IntPtr hwnd, IntPtr hbitmap, ref POINT ptClient, uint flags); + + [DllImport("dwmapi.dll")] + public static extern HResult DwmSetIconicLivePreviewBitmap(IntPtr hwnd, IntPtr hbitmap, IntPtr ptClient, uint flags); + + [DllImport("dwmapi.dll")] + internal static extern HResult DwmSetWindowAttribute(IntPtr hwnd, uint dwAttributeToSet, ref int pvAttributeValue, uint cbAttribute); + + [DllImport("dwmapi.dll")] + public static extern HResult DwmInvalidateIconicBitmaps(IntPtr hwnd); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + internal static extern uint RegisterWindowMessage(string lpString); + + [DllImport("shell32.dll")] + public static extern HResult SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID); + + [DllImport("shell32.dll")] + public static extern HResult GetCurrentProcessExplicitAppUserModelID([Out(), MarshalAs(UnmanagedType.LPWStr)] out string AppID); + + [DllImport("shell32.dll")] + public static extern HResult SHGetPropertyStoreForWindow(IntPtr hwnd, ref Guid iid /*IID_IPropertyStore*/, [Out(), MarshalAs(UnmanagedType.Interface)] out IPropertyStore propertyStore); + + [DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern HResult SHCreateItemFromParsingName(string path, /* The following parameter is not used - binding context. */ IntPtr pbc, ref Guid riid, [MarshalAs(UnmanagedType.Interface)] out IShellItem shellItem); + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/TaskbarLib/JumpLists/JumpListImpl.cs b/branches/ph-plugins/ProcessHacker/Components/TaskbarLib/JumpLists/JumpListImpl.cs new file mode 100644 index 000000000..4307ee361 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/TaskbarLib/JumpLists/JumpListImpl.cs @@ -0,0 +1,456 @@ +/* + * Process Hacker - + * ProcessHacker Taskbar Extensions + * + * Copyright (C) 2009 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 . + * + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using TaskbarLib.Interop; +using System.Runtime.InteropServices; +using ProcessHacker.Native.Api; + +namespace TaskbarLib +{ + /// + /// A collection of categorized jump list destinations. + /// + internal sealed class JumpListDestinations + { + //TODO: This is highly inefficient, but we want to maintain + //insertion order when adding the categories because the bottom + //categories are first to be truncated if screen estate is low. + private SortedDictionary> _categorizedDestinations = + new SortedDictionary>(); + + public void AddDestination(IJumpListDestination destination) + { + List destinations = + _categorizedDestinations.Values.FirstOrDefault( + list => list.First().Category == destination.Category); + if (destinations == null) + { + destinations = new List(); + _categorizedDestinations.Add( + _categorizedDestinations.Keys.LastOrDefault() + 1, destinations); + } + + destinations.Add(destination); + } + + public void DeleteDestination(IJumpListDestination destination) + { + List destinations = + _categorizedDestinations.Values.First( + list => list.First().Category == destination.Category); + IJumpListDestination toDelete = destinations.Find( + d => d.Path == destination.Path && d.Category == destination.Category && d.Title == destination.Title); + if (toDelete != null) + destinations.Remove(toDelete); + } + + internal void RefreshDestinations(ICustomDestinationList destinationList) + { + if (_categorizedDestinations.Count == 0) + return; + + foreach (int key in _categorizedDestinations.Keys) + { + IObjectCollection categoryContents = + (IObjectCollection)new CEnumerableObjectCollection(); + var destinations = _categorizedDestinations[key]; + foreach (IJumpListDestination destination in destinations) + { + HResult addObjectResult = categoryContents.AddObject(destination.GetShellRepresentation()); + addObjectResult.ThrowIf(); + } + + HResult appendCategoryResult = destinationList.AppendCategory( + destinations.First().Category, (IObjectArray)categoryContents); + appendCategoryResult.ThrowIf(); + } + } + + public IEnumerable Categories + { + get + { + return + (from d in _categorizedDestinations.Keys + select _categorizedDestinations[d].First().Category); + } + } + public IEnumerable GetDestinationsByCategory( + string category) + { + return + (from k in _categorizedDestinations.Keys + let d = _categorizedDestinations[k] + where d.First().Category == category + select d).Single(); + } + + public void Clear() + { + _categorizedDestinations.Clear(); + } + } + + /// + /// A collection of jump list tasks. + /// + internal sealed class JumpListTasks + { + private List _tasks = new List(); + + public void AddTask(IJumpListTask task) + { + _tasks.Add(task); + } + + public void DeleteTask(IJumpListTask task) + { + IJumpListTask toDelete = _tasks.Find(t => t.Path == task.Path && t.Arguments == task.Arguments); + if (toDelete != null) + _tasks.Remove(toDelete); + } + + internal void RefreshTasks(ICustomDestinationList destinationList) + { + if (_tasks.Count == 0) + return; + + IObjectCollection taskCollection = (IObjectCollection)new CEnumerableObjectCollection(); + foreach (IJumpListTask task in _tasks) + { + HResult addObjectResult = taskCollection.AddObject(task.GetShellRepresentation()); + addObjectResult.ThrowIf(); + } + HResult addUserTasksResult = destinationList.AddUserTasks((IObjectArray)taskCollection); + addUserTasksResult.ThrowIf(); + } + + public IEnumerable Tasks + { + get { return _tasks; } + } + + public void Clear() + { + _tasks.Clear(); + } + } + + /// + /// Represents a shell object that can be inserted to an application's + /// jump list. + /// + public interface IJumpListShellObject + { + /// + /// Gets or sets the object's title. + /// + string Title { get; } + /// + /// Gets or sets the object's path. + /// + string Path { get; } + + /// + /// Gets the shell representation of an object, such as + /// IShellLink or IShellItem. + /// + /// + object GetShellRepresentation(); + } + + /// + /// Represents a jump list destination. + /// + public interface IJumpListDestination : IJumpListShellObject + { + /// + /// Gets or sets the destination's category. + /// + string Category { get; } + } + + /// + /// Represents a jump list task. + /// + public interface IJumpListTask : IJumpListShellObject + { + /// + /// Gets or sets the task's command line arguments. + /// + string Arguments { get; } + } + + /// + /// Flags controlling the appearance of a window. + /// + [Flags] + public enum WindowShowCommand : uint + { + /// + /// Hides the window and activates another window. + /// + Hide = 0, + /// + /// Activates and displays the window (including restoring + /// it to its original size and position). + /// + Normal = 1, + /// + /// Minimizes the window. + /// + Minimized = 2, + /// + /// Maximizes the window. + /// + Maximized = 3, + /// + /// Similar to , except that the window + /// is not activated. + /// + ShowNoActivate = 4, + /// + /// Activates the window and displays it in its current size + /// and position. + /// + Show = 5, + /// + /// Minimizes the window and activates the next top-level window. + /// + Minimize = 6, + /// + /// Minimizes the window and does not activate it. + /// + ShowMinimizedNoActivate = 7, + /// + /// Similar to , except that the window is not + /// activated. + /// + ShowNA = 8, + /// + /// Activates and displays the window, restoring it to its original + /// size and position. + /// + Restore = 9, + /// + /// Sets the show state based on the initial value specified when + /// the process was created. + /// + Default = 10, + /// + /// Minimizes a window, even if the thread owning the window is not + /// responding. Use this only to minimize windows from a different + /// thread. + /// + ForceMinimize = 11 + } + + /// + /// Represents a separator in the task area of the jump list. + /// There is no need to set any properties on this class. + /// + public sealed class Separator : IJumpListTask + { + string IJumpListTask.Arguments + { + get { throw new NotImplementedException(); } + } + + string IJumpListShellObject.Title + { + get { throw new NotImplementedException(); } + } + + string IJumpListShellObject.Path + { + get { throw new NotImplementedException(); } + } + + object IJumpListShellObject.GetShellRepresentation() + { + ShellLink shellLink = new ShellLink + { + IsSeparator = true + }; + return shellLink.GetShellRepresentation(); + } + } + + /// + /// Represents a shell link (IShellLink) object. + /// + public sealed class ShellLink : IJumpListTask, IJumpListDestination + { + /// + /// Gets or sets the object's title. + /// + public string Title { get; set; } + /// + /// Gets or sets the object's category. + /// + public string Category { get; set; } + + /// + /// Gets or sets the object's path. + /// + public string Path { get; set; } + /// + /// Gets or sets the location of the object's icon. + /// + public string IconLocation { get; set; } + /// + /// Gets or sets the index of the object's icon in the specified + /// icon's location (). + /// + public int IconIndex { get; set; } + /// + /// Gets or sets the object's arguments (passed to the command + /// line). + /// + public string Arguments { get; set; } + /// + /// Gets or sets the object's working directory. + /// + public string WorkingDirectory { get; set; } + + /// + /// Gets or sets the show command of the launched application. + /// + public WindowShowCommand ShowCommand { get; set; } + + /// + /// Gets or sets a flag indicating that the shell link + /// is a menu separator. If this flag is set, all other + /// properties are ignored. + /// + internal bool IsSeparator { get; set; } + + /// + /// Gets the shell IShellLink representation + /// of the object. + /// + /// An IShellLink up-cast to object. + public object GetShellRepresentation() + { + IShellLinkW shellLink = (IShellLinkW)new CShellLink(); + IPropertyStore propertyStore = (IPropertyStore)shellLink; + PropVariant propVariant = new PropVariant(); + + if (IsSeparator) + { + propVariant.SetValue(true); + + HResult setValueResult = propertyStore.SetValue(ref PropertyKey.PKEY_AppUserModel_IsDestListSeparator, ref propVariant); + setValueResult.ThrowIf(); + + propVariant.Clear(); + propVariant.Dispose(); + } + else + { + HResult setPathResult = shellLink.SetPath(Path); + setPathResult.ThrowIf(); + + if (!String.IsNullOrEmpty(IconLocation)) + { + HResult setIconLocationResult = shellLink.SetIconLocation(IconLocation, IconIndex); + setIconLocationResult.ThrowIf(); + } + if (!String.IsNullOrEmpty(Arguments)) + { + HResult setArgumentsResult = shellLink.SetArguments(Arguments); + setArgumentsResult.ThrowIf(); + } + if (!String.IsNullOrEmpty(WorkingDirectory)) + { + HResult setWorkingDirectoryResult = shellLink.SetWorkingDirectory(WorkingDirectory); + setWorkingDirectoryResult.ThrowIf(); + } + + HResult setShowCmdResult = shellLink.SetShowCmd((uint)ShowCommand); + setShowCmdResult.ThrowIf(); + + propVariant.SetValue(Title); + + HResult setValueResult = propertyStore.SetValue(ref PropertyKey.PKEY_Title, ref propVariant); + setValueResult.ThrowIf(); + + propVariant.Clear(); + propVariant.Dispose(); + } + + HResult commitResult = propertyStore.Commit(); + commitResult.ThrowIf(); + + //Marshal.ReleaseComObject(propertyStore); + + return shellLink; + } + } + + /// + /// Represents a IShellItem object. + /// + public sealed class ShellItem : IJumpListDestination + { + string IJumpListShellObject.Title { get { return null; } } + + /// + /// Gets or sets the object's category. + /// + public string Category { get; set; } + + /// + /// Gets or sets the object's path. + /// + public string Path { get; set; } + + /// + /// Gets the shell IShellItem representation + /// of the object. + /// + /// An IShellItem up-cast to object. + public object GetShellRepresentation() + { + return GetShellItemFromPath(Path); + } + + internal static IShellItem GetShellItemFromPath(string path) + { + if (String.IsNullOrEmpty(path)) + throw new ArgumentNullException( + "path", "Shell item cannot be generated from null or empty path."); + + IShellItem resultItem = default(IShellItem); + Guid shellItemGuid = new Guid("43826D1E-E718-42EE-BC55-A1E261C37BFE"); + HResult result = UnsafeNativeMethods.SHCreateItemFromParsingName( + path, IntPtr.Zero, ref shellItemGuid, out resultItem); + result.ThrowIf(); + + return resultItem; + } + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/TaskbarLib/JumpLists/JumpListManager.cs b/branches/ph-plugins/ProcessHacker/Components/TaskbarLib/JumpLists/JumpListManager.cs new file mode 100644 index 000000000..dd058596b --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/TaskbarLib/JumpLists/JumpListManager.cs @@ -0,0 +1,567 @@ +/* + * Process Hacker - + * ProcessHacker Taskbar Extensions + * + * Copyright (C) 2009 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 . + * + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using Microsoft.Win32; +using TaskbarLib.Interop; +using System.Runtime.CompilerServices; +using ProcessHacker.Native.Api; + +namespace TaskbarLib +{ + /// + /// Provides services to manage taskbar jump lists, including + /// custom destinations and custom tasks. + /// + /// + /// This class mostly borrows the Windows Shell's concepts where + /// jump lists are concerned including: + /// Application destinations - Destinations added to the application's + /// recent and frequent categories by the shell or by the application. + /// Custom destinations - Destinations added to the application's + /// jump list in other categories by the application. + /// Tasks - Tasks added to the application's jump list. + /// The methods of this class are not thread-safe. + /// + public sealed class JumpListManager : IDisposable + { + #region Members + + string _appId; + uint _maxSlotsInList; + + JumpListTasks _tasks; + JumpListDestinations _destinations; + EventHandler _displaySettingsChangeHandler; + ICustomDestinationList _customDestinationList; + ApplicationDestinationType _enabledAutoDestinationType; // = ApplicationDestinationType.Recent; + + #endregion + + /// + /// Initializes a new instance of the jump list manager + /// with the specified application id. + /// + /// The application id. + public JumpListManager(string appId) + { + _appId = appId; + _destinations = new JumpListDestinations(); + _tasks = new JumpListTasks(); + + _customDestinationList = (ICustomDestinationList)new CDestinationList(); + + if (String.IsNullOrEmpty(_appId)) + { + _appId = Windows7Taskbar.ProcessAppId; + } + if (!String.IsNullOrEmpty(_appId)) + { + _customDestinationList.SetAppID(_appId); + } + + _displaySettingsChangeHandler = delegate + { + RefreshMaxSlots(); + }; + + SystemEvents.DisplaySettingsChanged += _displaySettingsChangeHandler; + } + + /// + /// Initializes a new instance of the jump list manager + /// with the specified window handle. + /// + public JumpListManager() + : this(Windows7Taskbar.AppId) + { + } + + /// + /// Adds a task to the application's jump list. + /// + /// An object implementing , + /// such as . + public void AddUserTask(IJumpListTask task) + { + _tasks.AddTask(task); + } + + /// + /// Retrieves the tasks currently present in the application's + /// jump list. If the tasks are modified through the use of this + /// property, the method must be called to + /// repopulate the application's jump list. + /// + public IEnumerable Tasks + { + get { return _tasks.Tasks; } + } + + /// + /// Deletes the specified task from the application's jump list. + /// + /// The task to delete. + public void DeleteTask(IJumpListTask task) + { + _tasks.DeleteTask(task); + } + + /// + /// Deletes all the tasks from the application's jump list. + /// + public void ClearTasks() + { + _tasks.Clear(); + } + + /// + /// Adds a custom destination to the application's jump list. + /// + /// An object implementing + /// such as + /// or . + public void AddCustomDestination(IJumpListDestination destination) + { + // Do not use CustomDestinations as they will cause an + // System.UnauthorizedAccessException: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED)) + // error when the user has recent document tracking disabled Via the Group Policy setting: + //“Do not keep history of recently opened documents”. or via the Users setting: + //“Store and display recently opened items in the Start menu and the taskbar” in the Start menu property dialog. + + //_destinations.AddDestination(destination); + } + + /// + /// Deletes the specified custom destination from the application's + /// jump list. + /// + /// The destination to delete. + public void DeleteCustomDestination(IJumpListDestination destination) + { + _destinations.DeleteDestination(destination); + } + + /// + /// The currently enabled automatic application destination type. + /// The supported values are the values of the + /// enumeration. + /// Only of the values can be set at any given time. + /// + public ApplicationDestinationType EnabledAutoDestinationType + { + get + { + return _enabledAutoDestinationType; + } + set + { + if (_enabledAutoDestinationType == value) + return; + + _enabledAutoDestinationType = value; + } + } + + /// + /// Removes all destinations from the application's jump list. + /// + public void ClearAllDestinations() + { + ClearApplicationDestinations(); + ClearCustomDestinations(); + } + + /// + /// Removes all application destinations (such as frequent and recent) + /// from the application's jump list. + /// + public void ClearApplicationDestinations() + { + IApplicationDestinations destinations = (IApplicationDestinations)new CApplicationDestinations(); + if (!String.IsNullOrEmpty(_appId)) + { + HResult setAppIDResult = destinations.SetAppID(_appId); + setAppIDResult.ThrowIf(); + } + try + { + //This does not remove pinned items. + HResult removeAllDestinationsResult = destinations.RemoveAllDestinations(); + removeAllDestinationsResult.ThrowIf(); + } + catch (FileNotFoundException) + { /* There are no destinations. That's cool. */ } + } + + /// + /// Retrieves all application destinations belonging to the specified + /// application destination type. + /// + /// The application destination type. + /// A copy of the application destinations belonging to + /// the specified type; modifying the returned objects has no effect + /// on the application's destination list. + public IEnumerable GetApplicationDestinations(ApplicationDestinationType type) + { + if (type == ApplicationDestinationType.None) + throw new ArgumentException("ApplicationDestinationType can't be NONE"); + + IApplicationDocumentLists destinations = (IApplicationDocumentLists)new CApplicationDocumentLists(); + Guid iidObjectArray = typeof(IObjectArray).GUID; + + object obj; + HResult getListResult = destinations.GetList((AppDocListType)type, 100, ref iidObjectArray, out obj); + getListResult.ThrowIf(); + + List returnValue = new List(); + + Guid iidShellItem = typeof(IShellItem).GUID; + Guid iidShellLink = typeof(IShellLinkW).GUID; + IObjectArray array = (IObjectArray)obj; + + uint count; + HResult getCountResult = array.GetCount(out count); + getCountResult.ThrowIf(); + + for (uint i = 0; i < count; ++i) + { + try + { + array.GetAt(i, ref iidShellItem, out obj); + } + catch (Exception) //Wrong type + { } + + if (obj == null) + { + HResult getAtResult = array.GetAt(i, ref iidShellLink, out obj); + getAtResult.ThrowIf(); + //This shouldn't fail since if it's not IShellItem + //then it must be IShellLink. + + IShellLinkW link = (IShellLinkW)obj; + ShellLink wrapper = new ShellLink(); + + StringBuilder sb = new StringBuilder(256); + HResult getPathResult = link.GetPath(sb, sb.Capacity, IntPtr.Zero, 2); + getPathResult.ThrowIf(); + wrapper.Path = sb.ToString(); + + HResult getArgumentsResult = link.GetArguments(sb, sb.Capacity); + getArgumentsResult.ThrowIf(); + wrapper.Arguments = sb.ToString(); + + int iconId; + HResult getIconLocationResult = link.GetIconLocation(sb, sb.Capacity, out iconId); + getIconLocationResult.ThrowIf(); + wrapper.IconIndex = iconId; + wrapper.IconLocation = sb.ToString(); + + uint showCmd; + HResult getShowCmdResult = link.GetShowCmd(out showCmd); + getShowCmdResult.ThrowIf(); + wrapper.ShowCommand = (WindowShowCommand)showCmd; + + HResult getWorkingDirectoryResult = link.GetWorkingDirectory(sb, sb.Capacity); + getWorkingDirectoryResult.ThrowIf(); + wrapper.WorkingDirectory = sb.ToString(); + + returnValue.Add(wrapper); + } + else //It's an IShellItem. + { + IShellItem item = (IShellItem)obj; + ShellItem wrapper = new ShellItem(); + + string path; + HResult getDisplayNameResult = item.GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out path); + getDisplayNameResult.ThrowIf(); + wrapper.Path = path; + + //Title and Category are irrelevant here, because it's + //an IShellItem. The user might want to see them, but he's + //free to go to the IShellItem and look at its property store. + + returnValue.Add(wrapper); + } + } + return returnValue; + } + + /// + /// Deletes the specified application destination from the application's + /// jump list. + /// + /// The application destination. + public void DeleteApplicationDestination(IJumpListDestination destination) + { + IApplicationDestinations destinations = (IApplicationDestinations)new CApplicationDestinations(); + if (!String.IsNullOrEmpty(_appId)) + { + HResult setAppIDResult = destinations.SetAppID(_appId); + setAppIDResult.ThrowIf(); + } + + HResult removeDestinationResult = destinations.RemoveDestination(destination.GetShellRepresentation()); + removeDestinationResult.ThrowIf(); + } + + /// + /// Deletes all custom destinations from the application's jump list. + /// + public void ClearCustomDestinations() + { + try + { + HResult deleteListResult = _customDestinationList.DeleteList(_appId); + deleteListResult.ThrowIf(); + } + catch (FileNotFoundException) + { /*Means the list is empty, that's cool. */ } + + _destinations.Clear(); + } + + /// + /// Repopulates the application's jump list. + /// Use this method after all current changes to + /// the application's jump list have been introduced, + /// and you want the list to be refreshed. + /// + /// true if the list was refreshed; false + /// if the operation was cancelled. The operation might have + /// been cancelled if the event + /// handler instructed us to cancel the operation. + /// + /// If the user removed items from the jump list between the + /// last refresh operation and this one, then the + /// event will be invoked. + /// If the event handler for this event instructed us to cancel + /// the operation, then the current transaction is aborted, + /// no items are added, and this method returns false. + /// Check the return value to determine whether the jump list + /// needs to be changed and the operation attempted again. + /// + public bool Refresh() + { + if (!BeginList()) + return false; //Operation was cancelled + + _tasks.RefreshTasks(_customDestinationList); + _destinations.RefreshDestinations(_customDestinationList); + + switch (EnabledAutoDestinationType) + { + case ApplicationDestinationType.Frequent: + HResult appendKnownCategoryFrequentResult = _customDestinationList.AppendKnownCategory(KnownDestCategory.FREQUENT); + appendKnownCategoryFrequentResult.ThrowIf(); + break; + case ApplicationDestinationType.Recent: + HResult appendKnownCategoryRecentResult = _customDestinationList.AppendKnownCategory(KnownDestCategory.RECENT); + appendKnownCategoryRecentResult.ThrowIf(); + break; + } + + CommitList(); + return true; + } + + /// + /// Returns the maximum number of items to be placed + /// in the application's jump list. This number depends + /// on factors such as the display resolution or monitor + /// change - do not assume it is always constant. + /// + public uint MaximumSlotsInList + { + get + { + if (_maxSlotsInList == 0) + { + RefreshMaxSlots(); + } + return _maxSlotsInList; + } + } + + /// + /// Cleans the resources associated with this jump list. + /// + public void Dispose() + { + SystemEvents.DisplaySettingsChanged -= _displaySettingsChangeHandler; + if (_customDestinationList != null) + Marshal.ReleaseComObject(_customDestinationList); + } + + /// + /// Register to this event to receive notifications when custom + /// destinations are being removed from your jump list by the user. + /// If you do not register to this event, you will not be able + /// to refresh the list. Additionally, if you attempt to add + /// items to the list which have been previously removed by the user, + /// the next refresh will fail to add your category. + /// + public event EventHandler UserRemovedItems; + + #region Implementation + + private void RefreshMaxSlots() + { + object obj; + _customDestinationList.BeginList(out _maxSlotsInList, ref SafeNativeMethods.IID_IObjectArray, out obj); + _customDestinationList.AbortList(); + } + + private bool BeginList() + { + if (UserRemovedItems == null) + { + throw new InvalidOperationException("You must register for the JumpListManager.UserRemovedItems event before adding any items"); + } + + object obj; + _customDestinationList.BeginList(out _maxSlotsInList, ref SafeNativeMethods.IID_IObjectArray, out obj); + + IObjectArray removedItems = (IObjectArray)obj; + uint count; + removedItems.GetCount(out count); + if (count == 0) + return true; + + string[] removedItemsArr = new string[count]; + for (uint i = 0; i < count; ++i) + { + object item; + removedItems.GetAt(i, ref SafeNativeMethods.IID_IUnknown, out item); + + try + { + IShellLinkW shellLink = (IShellLinkW)item; + if (shellLink != null) + { + StringBuilder sb = new StringBuilder(256); + shellLink.GetPath(sb, sb.Capacity, IntPtr.Zero, 2); + removedItemsArr[i] = sb.ToString(); + } + continue; + } + catch (InvalidCastException) //It's not a ShellLink + { } + + try + { + IShellItem shellItem = (IShellItem)item; + if (shellItem != null) + { + string path; + shellItem.GetDisplayName(SIGDN.SIGDN_FILESYSPATH, out path); + removedItemsArr[i] = path; + } + } + catch (InvalidCastException) + { + //It's neither a shell link nor a shell item. + //This is impossible. + Debug.Assert(false, + "List of removed items contains something that is neither a shell item nor a shell link"); + } + } + + UserRemovedItemsEventArgs args = new UserRemovedItemsEventArgs(removedItemsArr); + UserRemovedItems(this, args); + if (args.Cancel) + { + _customDestinationList.AbortList(); + } + return !args.Cancel; + } + + private void CommitList() + { + _customDestinationList.CommitList(); + } + + #endregion + } + + /// + /// The application destination type. + /// + public enum ApplicationDestinationType + { + /// + /// No application destination type is selected. + /// + None = -1, + /// + /// Destinations used recently. + /// + Recent = 0, + /// + /// Destinations used frequently. + /// + Frequent + } + + /// + /// The event arguments for the event that occurs + /// when the user removes items from the application's + /// jump list. + /// + public class UserRemovedItemsEventArgs : EventArgs + { + readonly string[] _removedItems; + + internal UserRemovedItemsEventArgs(string[] removedItems) + { + _removedItems = removedItems; + } + + /// + /// The collection of removed items. Each item is the path. + /// + public string[] RemovedItems + { + get + { + return _removedItems; + } + } + + /// + /// Set to true if the current operation + /// should be cancelled. Should be used by the application + /// if because of the items the user has removed + /// there is no real work to do with the jump list. + /// + public bool Cancel { get; set; } + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/TaskbarLib/ThumbnailButtons/ThumbButton.cs b/branches/ph-plugins/ProcessHacker/Components/TaskbarLib/ThumbnailButtons/ThumbButton.cs new file mode 100644 index 000000000..b3630b3ff --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/TaskbarLib/ThumbnailButtons/ThumbButton.cs @@ -0,0 +1,162 @@ +/* + * Process Hacker - + * ProcessHacker Taskbar Extensions + * + * Copyright (C) 2009 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 . + * + */ + +using System; +using System.Drawing; +using TaskbarLib.Interop; + +namespace TaskbarLib +{ + /// + /// Represents a taskbar thumbnail button in the thumbnail toolbar. + /// + public sealed class ThumbButton + { + private ThumbButtonManager _manager; + + internal ThumbButton(ThumbButtonManager manager, int id, Icon icon, string tooltip) + { + _manager = manager; + + Id = id; + Icon = icon; + Tooltip = tooltip; + } + + /// + /// The event that occurs when the taskbar thumbnail button + /// is clicked. + /// + public event EventHandler Click; + + /// + /// Gets or sets thumbnail button's id. + /// + public int Id { get; set; } + + /// + /// Gets or sets the thumbnail button's icon. + /// + public Icon Icon { get; set; } + + /// + /// Gets or sets the thumbnail button's tooltip. + /// + public string Tooltip { get; set; } + + internal ThumbnailButtonFlags Flags { get; set; } + + internal THUMBBUTTON Win32ThumbButton + { + get + { + THUMBBUTTON win32ThumbButton = new THUMBBUTTON(); + win32ThumbButton.iId = Id; + win32ThumbButton.szTip = Tooltip; + win32ThumbButton.hIcon = Icon.Handle; + win32ThumbButton.dwFlags = Flags | ThumbnailButtonFlags.DISMISSONCLICK; + + win32ThumbButton.dwMask = ThumbnailButtonMask.Flags; + if (Tooltip != null) + win32ThumbButton.dwMask |= ThumbnailButtonMask.Tooltip; + if (Icon != null) + win32ThumbButton.dwMask |= ThumbnailButtonMask.Icon; + + return win32ThumbButton; + } + } + + /// + /// Gets or sets the thumbnail button's visibility. + /// + public bool Visible + { + get + { + return (this.Flags & ThumbnailButtonFlags.HIDDEN) == 0; + } + set + { + if (value) + { + this.Flags &= ~(ThumbnailButtonFlags.HIDDEN); + } + else + { + this.Flags |= ThumbnailButtonFlags.HIDDEN; + } + _manager.RefreshThumbButtons(); + } + } + + public bool NoIconBackground + { + get + { + return (this.Flags & ThumbnailButtonFlags.NOBACKGROUND) == 0; + } + set + { + if (value) + { + this.Flags &= ~(ThumbnailButtonFlags.NOBACKGROUND); + } + else + { + this.Flags |= ThumbnailButtonFlags.NOBACKGROUND; + } + _manager.RefreshThumbButtons(); + } + } + + /// + /// Gets or sets the thumbnail button's enabled state. + /// + public bool Enabled + { + get + { + return (this.Flags & ThumbnailButtonFlags.DISABLED) == 0; + } + set + { + if (value) + { + this.Flags &= ~(ThumbnailButtonFlags.DISABLED); + } + else + { + this.Flags |= ThumbnailButtonFlags.DISABLED; + } + _manager.RefreshThumbButtons(); + } + } + + internal void OnClick() + { + if (Click != null) + Click(this, EventArgs.Empty); + } + } + +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/TaskbarLib/ThumbnailButtons/ThumbButtonManager.cs b/branches/ph-plugins/ProcessHacker/Components/TaskbarLib/ThumbnailButtons/ThumbButtonManager.cs new file mode 100644 index 000000000..69ba0de5a --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/TaskbarLib/ThumbnailButtons/ThumbButtonManager.cs @@ -0,0 +1,173 @@ +/* + * Process Hacker - + * ProcessHacker Taskbar Extensions + * + * Copyright (C) 2009 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 . + * + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; +using TaskbarLib.Interop; + +namespace TaskbarLib +{ + /// + /// Manages a set of taskbar thumbnail buttons in an application. + /// + public sealed class ThumbButtonManager : IDisposable + { + private sealed class MessageFilter : IMessageFilter + { + private ThumbButtonManager _manager; + + public MessageFilter(ThumbButtonManager manager) + { + _manager = manager; + } + + public bool PreFilterMessage(ref Message m) + { + if (m.Msg == (int)Windows7Taskbar.TaskbarButtonCreatedMessage) + { + _manager.OnTaskbarButtonCreated(); + return true; + } + else if (m.Msg == (int)ProcessHacker.Native.Api.WindowMessage.Command) + { + _manager.OnCommand(m.WParam); + } + + return false; + } + } + + public event EventHandler TaskbarButtonCreated; + + private Form _form; + private MessageFilter _filter; + private bool _disposed; + + /// + /// Initializes a new manager on the specified form. + /// + /// The form. + public ThumbButtonManager(Form form) + { + _form = form; + + Application.AddMessageFilter(_filter = new MessageFilter(this)); + } + + public void Dispose() + { + if (!_disposed) + { + Application.RemoveMessageFilter(_filter); + _disposed = true; + } + } + + /// + /// Creates a new taskbar thumbnail button. + /// + /// The button's id. + /// The button's icon. + /// The button's tooltip. + /// An object of type + /// representing the newly created thumbnail button. + public ThumbButton CreateThumbButton(int id, Icon icon, string tooltip) + { + return new ThumbButton(this, id, icon, tooltip); + } + + /// + /// Adds the specified taskbar thumbnail buttons to the application's + /// thumbnail toolbar. + /// + /// + /// Thumbnail buttons can only be added once - after being added, + /// they cannot be removed or deleted. However, they can be shown, + /// hidden, enabled and disabled. + /// + /// The buttons to add. + public void AddThumbButtons(params ThumbButton[] buttons) + { + Array.ForEach(buttons, b => _thumbButtons.Add(b.Id, b)); + + RefreshThumbButtons(); + } + + /// + /// Gets a specific thumbnail button by its id. + /// + /// The thumbnail button's id. + /// An object of type + /// with the specified id. + public ThumbButton this[int id] + { + get + { + return _thumbButtons[id]; + } + } + + internal void OnCommand(IntPtr wParam) + { + if (((wParam.ToInt32() >> 16) & 0xffff) == SafeNativeMethods.THBN_CLICKED) + { + _thumbButtons[wParam.ToInt32() & 0xffff].OnClick(); + } + } + + internal void OnTaskbarButtonCreated() + { + if (this.TaskbarButtonCreated != null) + this.TaskbarButtonCreated(this, new EventArgs()); + + _buttonsLoaded = false; + this.RefreshThumbButtons(); + } + + #region Implementation + + private bool _buttonsLoaded; + internal void RefreshThumbButtons() + { + THUMBBUTTON[] win32Buttons = (from thumbButton in _thumbButtons.Values select thumbButton.Win32ThumbButton).ToArray(); + + if (_buttonsLoaded) + { + Windows7Taskbar.TaskbarList.ThumbBarUpdateButtons(_form.Handle, win32Buttons.Length, win32Buttons); + } + else //First time + { + Windows7Taskbar.TaskbarList.ThumbBarAddButtons(_form.Handle, win32Buttons.Length, win32Buttons); + _buttonsLoaded = true; + } + } + + private Dictionary _thumbButtons = new Dictionary(); + + #endregion + } + +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/TaskbarLib/Windows7Taskbar.cs b/branches/ph-plugins/ProcessHacker/Components/TaskbarLib/Windows7Taskbar.cs new file mode 100644 index 000000000..274d2b785 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/TaskbarLib/Windows7Taskbar.cs @@ -0,0 +1,401 @@ +/* + * Process Hacker - + * ProcessHacker Taskbar Extensions + * + * Copyright (C) 2009 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 . + * + */ + +using System; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using ProcessHacker; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using TaskbarLib.Interop; + +namespace TaskbarLib +{ + /// + /// The primary coordinator of the Windows 7 taskbar-related activities. + /// For additional functionality, see the JumpListManager + /// and ThumbButtonManager classes. + /// + public static class Windows7Taskbar + { + #region Infrastructure + + // Use thread static to work around COM threading issues. + [ThreadStatic] + private static ITaskbarList3 _taskbarList; + internal static ITaskbarList3 TaskbarList + { + get + { + if (_taskbarList == null) + { + _taskbarList = (ITaskbarList3)new CTaskbarList(); + HResult result = _taskbarList.HrInit(); + + result.ThrowIf(); + } + return _taskbarList; + } + } + + /// + /// Creates a jump list manager for this form. + /// + /// An object of type + /// that can be used to manage the application's jump list. + public static JumpListManager CreateJumpListManager() + { + return new JumpListManager(); + } + + private static IPropertyStore InternalGetWindowPropertyStore(IntPtr hwnd) + { + IPropertyStore propStore; + HResult shGetPropertyStoreResult = UnsafeNativeMethods.SHGetPropertyStoreForWindow( + hwnd, ref SafeNativeMethods.IID_IPropertyStore, out propStore); + shGetPropertyStoreResult.ThrowIf(); + + return propStore; + } + + private static void InternalEnableCustomWindowPreview(IntPtr hwnd, bool enable) + { + int t = enable ? 1 : 0; + + HResult setFirstAttributeResult = UnsafeNativeMethods.DwmSetWindowAttribute( + hwnd, SafeNativeMethods.DWMWA_HAS_ICONIC_BITMAP, ref t, 4); + setFirstAttributeResult.ThrowIf(); + + HResult setSecondAttributeResult = UnsafeNativeMethods.DwmSetWindowAttribute( + hwnd, SafeNativeMethods.DWMWA_FORCE_ICONIC_REPRESENTATION, ref t, 4); + setSecondAttributeResult.ThrowIf(); + } + + #endregion + + #region Application Id + + /// + /// Gets/Sets the Taskbar window's application id. + /// + public static string AppId + { + get + { + IPropertyStore propStore = InternalGetWindowPropertyStore(Program.HackerWindowHandle); + + PropVariant pv; + HResult getValueResult = propStore.GetValue(ref PropertyKey.PKEY_AppUserModel_ID, out pv); + getValueResult.ThrowIf(); + + string appId = pv.GetValue(); + + Marshal.ReleaseComObject(propStore); + pv.Dispose(); + + return appId; + } + set + { + IPropertyStore propStore = InternalGetWindowPropertyStore(Program.HackerWindowHandle); + + PropVariant pv = new PropVariant(); + pv.SetValue(value); + + HResult setValueResult = propStore.SetValue(ref PropertyKey.PKEY_AppUserModel_ID, ref pv); + setValueResult.ThrowIf(); + + Marshal.ReleaseComObject(propStore); + pv.Dispose(); + } + } + + /// + /// Gets/Sets the current process' explicit application usermode id. + /// + public static string ProcessAppId + { + get + { + string appId; + HResult getProcessAppUserModeIDResult = UnsafeNativeMethods.GetCurrentProcessExplicitAppUserModelID(out appId); + getProcessAppUserModeIDResult.ThrowIf(); + return appId; + } + set + { + HResult setProcessAppUserModeIDResult = UnsafeNativeMethods.SetCurrentProcessExplicitAppUserModelID(value); + setProcessAppUserModeIDResult.ThrowIf(); + } + } + + #endregion + + #region DWM Iconic Thumbnail and Peek Bitmap + + /// + /// Indicates that the specified window requests the DWM + /// to demand live preview (thumbnail and peek) mode when necessary + /// instead of relying on default preview. + /// + public static void EnableCustomWindowPreview(this Form form) + { + InternalEnableCustomWindowPreview(form.Handle, true); + } + + /// + /// Indicates that the specified window does not require the DWM + /// to demand live preview (thumbnail and peek) mode when necessary, + /// i.e. this window relies on default preview. + /// + public static void DisableCustomWindowPreview(this Form form) + { + InternalEnableCustomWindowPreview(form.Handle, false); + } + + /// + /// Sets the specified iconic thumbnail for the specified window. + /// This is typically done in response to a DWM message. + /// + /// The thumbnail bitmap. + public static void SetIconicThumbnail(this Form form, Bitmap bitmap) + { + HResult dwmSetIconicThumbnailResult = UnsafeNativeMethods.DwmSetIconicThumbnail( + form.Handle, bitmap.GetHbitmap(), SafeNativeMethods.DWM_SIT_DISPLAYFRAME); + dwmSetIconicThumbnailResult.ThrowIf(); + } + + /// + /// Sets the specified peek (live preview) bitmap for the specified + /// window. This is typically done in response to a DWM message. + /// + /// The thumbnail bitmap. + /// Whether to display a standard window + /// frame around the bitmap. + public static void SetPeekBitmap(this Form form, Bitmap bitmap, bool displayFrame) + { + HResult dwmSetIconicLivePreviewBitmapResult = UnsafeNativeMethods.DwmSetIconicLivePreviewBitmap( + form.Handle, bitmap.GetHbitmap(), IntPtr.Zero, displayFrame ? SafeNativeMethods.DWM_SIT_DISPLAYFRAME : (uint)0); + dwmSetIconicLivePreviewBitmapResult.ThrowIf(); + } + + /// + /// Sets the specified peek (live preview) bitmap for the specified + /// window. This is typically done in response to a DWM message. + /// + /// The window handle. + /// The thumbnail bitmap. + /// The client area offset at which to display + /// the specified bitmap. The rest of the parent window will be + /// displayed as "remembered" by the DWM. + /// Whether to display a standard window + /// frame around the bitmap. + public static void SetPeekBitmap(this Form form, Bitmap bitmap, Point offset, bool displayFrame) + { + var nativePoint = new POINT(offset.X, offset.Y); + HResult dwmSetIconicLivePreviewResult = + UnsafeNativeMethods.DwmSetIconicLivePreviewBitmap( + form.Handle, bitmap.GetHbitmap(), ref nativePoint, displayFrame ? SafeNativeMethods.DWM_SIT_DISPLAYFRAME : (uint)0); + dwmSetIconicLivePreviewResult.ThrowIf(); + } + + #endregion + + #region Taskbar Overlay Icon + + /// + /// Draws the specified overlay icon on the specified window's + /// taskbar button. + /// + /// The overlay icon. + /// The overlay icon description. + public static void SetTaskbarOverlayIcon(Icon icon, string description) + { + HResult result = TaskbarList.SetOverlayIcon( + Program.HackerWindowHandle, icon == null ? IntPtr.Zero : icon.Handle, description); + + result.ThrowIf(); + } + + public static void SetTaskbarOverlayIcon(this Form form, Icon icon, string description) + { + HResult result = TaskbarList.SetOverlayIcon( + form.Handle, icon == null ? IntPtr.Zero : icon.Handle, description); + + result.ThrowIf(); + } + + #endregion + + #region Taskbar Progress Bar + + /// + /// Sets the progress bar in the containing form's taskbar button + /// to this progress bar's progress. + /// + /// The progress bar. + public static void SetTaskbarProgress(this Form form, ProgressBar progressBar) + { + if (!form.IsDisposed && form.IsHandleCreated) + { + ulong maximum = Convert.ToUInt64(progressBar.Maximum); + ulong progress = Convert.ToUInt64(progressBar.Value); + + SetTaskbarProgress(form.Handle, progress, maximum); + } + } + + /// + /// Sets the progress bar in the containing form's taskbar button + /// to this toolstrip progress bar's progress. + /// + /// The progress bar. + public static void SetTaskbarProgress(this Form form, ToolStripProgressBar progressBar) + { + if (!form.IsDisposed && form.IsHandleCreated) + { + ulong maximum = Convert.ToUInt64(progressBar.Maximum); + ulong progress = Convert.ToUInt64(progressBar.Value); + + SetTaskbarProgress(form.Handle, progress, maximum); + } + } + + public static void SetTaskbarProgress(IntPtr hwnd, ulong progress, ulong maximum) + { + HResult valueResult = TaskbarList.SetProgressValue(hwnd, progress, maximum); + valueResult.ThrowIf(); + } + + /// + /// Sets the progress state of the specified window's + /// taskbar button. + /// + /// The window handle. + /// The progress state. + public static void SetTaskbarProgressState(this Form form, ThumbnailProgressState state) + { + SetTaskbarProgressState(form.Handle, state); + } + + public static void SetTaskbarProgressState(IntPtr hwnd, ThumbnailProgressState state) + { + HResult result = TaskbarList.SetProgressState(hwnd, (uint)state); + result.ThrowIf(); + } + + /// + /// Represents the thumbnail progress bar state. + /// + [Flags] + public enum ThumbnailProgressState + { + /// + /// No progress is displayed. + /// + NoProgress = 0, + /// + /// The progress is indeterminate (marquee). + /// + Indeterminate = 0x1, + /// + /// Normal progress is displayed. + /// + Normal = 0x2, + /// + /// An error occurred (red). + /// + Error = 0x4, + /// + /// The operation is paused (yellow). + /// + Paused = 0x8 + } + + #endregion + + #region Taskbar Thumbnails + + /// + /// Specifies that only a portion of the window's client area + /// should be used in the window's thumbnail. + /// + /// The window. + /// The rectangle that specifies the clipped region. + private static void SetThumbnailClip(this Form form, Rectangle clipRect) + { + //Example: SetThumbnailClip(this, new Rectangle(button.Location, button.Size)); + Rect rect = new Rect(clipRect.Left, clipRect.Top, clipRect.Right, clipRect.Bottom); + HResult setThumbnailClipResult = TaskbarList.SetThumbnailClip(form.Handle, ref rect); + setThumbnailClipResult.ThrowIf(); + + } + + /// + /// Sets the specified window's thumbnail tooltip. + /// + /// The window. + /// The tooltip text. + private static void SetThumbnailTooltip(this Form form, string tooltip) + { + HResult setThumbnailTooltipResult = TaskbarList.SetThumbnailTooltip(form.Handle, tooltip); + setThumbnailTooltipResult.ThrowIf(); + + } + + #endregion + + #region Miscellaneous + + /// + /// Allow the taskbar and DWM-related windows messages + /// through the Windows UIPI mechanism. + /// Calling this method is not required unless the process is elevated. + /// + public static void AllowWindowMessagesThroughUipi() + { + // If it's Windows 7 or above and we're elevated. + if (OSVersion.HasTaskDialogs && Program.ElevationType == TokenElevationType.Full) + { + Win32.ChangeWindowMessageFilter((WindowMessage)UnsafeNativeMethods.WM_TaskbarButtonCreated, UipiFilterFlag.Add); + Win32.ChangeWindowMessageFilter(WindowMessage.DwmSendIconicThumbnail, UipiFilterFlag.Add); + Win32.ChangeWindowMessageFilter(WindowMessage.DwmSendIconicLivePreviewBitmap, UipiFilterFlag.Add); + Win32.ChangeWindowMessageFilter(WindowMessage.Command, UipiFilterFlag.Add); + Win32.ChangeWindowMessageFilter(WindowMessage.SysCommand, UipiFilterFlag.Add); + Win32.ChangeWindowMessageFilter(WindowMessage.Activate, UipiFilterFlag.Add); + } + } + + /// + /// The WM_TaskbarButtonCreated message number. + /// + public static uint TaskbarButtonCreatedMessage + { + get { return UnsafeNativeMethods.WM_TaskbarButtonCreated; } + } + + #endregion + + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/ThreadList.Designer.cs b/branches/ph-plugins/ProcessHacker/Components/ThreadList.Designer.cs new file mode 100644 index 000000000..9084658a7 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/ThreadList.Designer.cs @@ -0,0 +1,592 @@ +namespace ProcessHacker.Components +{ + partial class ThreadList + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + _highlightingContext.Dispose(); + this.Provider = null; + + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.listThreads = new System.Windows.Forms.ListView(); + this.columnThreadID = new System.Windows.Forms.ColumnHeader(); + this.columnContextSwitchesDelta = new System.Windows.Forms.ColumnHeader(); + this.columnStartAddress = new System.Windows.Forms.ColumnHeader(); + this.columnPriority = new System.Windows.Forms.ColumnHeader(); + this.menuThread = new System.Windows.Forms.ContextMenu(); + this.inspectThreadMenuItem = new System.Windows.Forms.MenuItem(); + this.terminateThreadMenuItem = new System.Windows.Forms.MenuItem(); + this.forceTerminateThreadMenuItem = new System.Windows.Forms.MenuItem(); + this.suspendThreadMenuItem = new System.Windows.Forms.MenuItem(); + this.resumeThreadMenuItem = new System.Windows.Forms.MenuItem(); + this.menuItem4 = new System.Windows.Forms.MenuItem(); + this.inspectTEBMenuItem = new System.Windows.Forms.MenuItem(); + this.tokenThreadMenuItem = new System.Windows.Forms.MenuItem(); + this.analyzeMenuItem = new System.Windows.Forms.MenuItem(); + this.analyzeWaitMenuItem = new System.Windows.Forms.MenuItem(); + this.priorityThreadMenuItem = new System.Windows.Forms.MenuItem(); + this.timeCriticalThreadMenuItem = new System.Windows.Forms.MenuItem(); + this.highestThreadMenuItem = new System.Windows.Forms.MenuItem(); + this.aboveNormalThreadMenuItem = new System.Windows.Forms.MenuItem(); + this.normalThreadMenuItem = new System.Windows.Forms.MenuItem(); + this.belowNormalThreadMenuItem = new System.Windows.Forms.MenuItem(); + this.lowestThreadMenuItem = new System.Windows.Forms.MenuItem(); + this.idleThreadMenuItem = new System.Windows.Forms.MenuItem(); + this.menuItem9 = new System.Windows.Forms.MenuItem(); + this.copyThreadMenuItem = new System.Windows.Forms.MenuItem(); + this.selectAllThreadMenuItem = new System.Windows.Forms.MenuItem(); + this.tableInformation = new System.Windows.Forms.TableLayoutPanel(); + this.label6 = new System.Windows.Forms.Label(); + this.label8 = new System.Windows.Forms.Label(); + this.label9 = new System.Windows.Forms.Label(); + this.labelState = new System.Windows.Forms.Label(); + this.labelKernelTime = new System.Windows.Forms.Label(); + this.labelUserTime = new System.Windows.Forms.Label(); + this.labelTotalTime = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.labelContextSwitches = new System.Windows.Forms.Label(); + this.labelBasePriority = new System.Windows.Forms.Label(); + this.labelPriority = new System.Windows.Forms.Label(); + this.label10 = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.labelTEBAddress = new System.Windows.Forms.Label(); + this.label7 = new System.Windows.Forms.Label(); + this.vistaMenu = new wyDay.Controls.VistaMenu(this.components); + this.fileModule = new ProcessHacker.Components.FileNameBox(); + this.permissionsThreadMenuItem = new System.Windows.Forms.MenuItem(); + this.tableInformation.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.vistaMenu)).BeginInit(); + this.SuspendLayout(); + // + // listThreads + // + this.listThreads.AllowColumnReorder = true; + this.listThreads.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listThreads.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnThreadID, + this.columnContextSwitchesDelta, + this.columnStartAddress, + this.columnPriority}); + this.listThreads.FullRowSelect = true; + this.listThreads.HideSelection = false; + this.listThreads.Location = new System.Drawing.Point(0, 0); + this.listThreads.Name = "listThreads"; + this.listThreads.ShowItemToolTips = true; + this.listThreads.Size = new System.Drawing.Size(450, 345); + this.listThreads.Sorting = System.Windows.Forms.SortOrder.Ascending; + this.listThreads.TabIndex = 3; + this.listThreads.UseCompatibleStateImageBehavior = false; + this.listThreads.View = System.Windows.Forms.View.Details; + this.listThreads.DoubleClick += new System.EventHandler(this.listThreads_DoubleClick); + // + // columnThreadID + // + this.columnThreadID.Text = "TID"; + this.columnThreadID.Width = 50; + // + // columnContextSwitchesDelta + // + this.columnContextSwitchesDelta.Text = "Context Switches Delta"; + this.columnContextSwitchesDelta.Width = 70; + // + // columnStartAddress + // + this.columnStartAddress.Text = "Start Address"; + this.columnStartAddress.Width = 220; + // + // columnPriority + // + this.columnPriority.Text = "Priority"; + this.columnPriority.Width = 100; + // + // menuThread + // + this.menuThread.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.inspectThreadMenuItem, + this.terminateThreadMenuItem, + this.forceTerminateThreadMenuItem, + this.suspendThreadMenuItem, + this.resumeThreadMenuItem, + this.menuItem4, + this.inspectTEBMenuItem, + this.permissionsThreadMenuItem, + this.tokenThreadMenuItem, + this.analyzeMenuItem, + this.priorityThreadMenuItem, + this.menuItem9, + this.copyThreadMenuItem, + this.selectAllThreadMenuItem}); + this.menuThread.Popup += new System.EventHandler(this.menuThread_Popup); + // + // inspectThreadMenuItem + // + this.inspectThreadMenuItem.DefaultItem = true; + this.vistaMenu.SetImage(this.inspectThreadMenuItem, global::ProcessHacker.Properties.Resources.application_form_magnify); + this.inspectThreadMenuItem.Index = 0; + this.inspectThreadMenuItem.Text = "&Inspect"; + this.inspectThreadMenuItem.Click += new System.EventHandler(this.inspectThreadMenuItem_Click); + // + // terminateThreadMenuItem + // + this.vistaMenu.SetImage(this.terminateThreadMenuItem, global::ProcessHacker.Properties.Resources.cross); + this.terminateThreadMenuItem.Index = 1; + this.terminateThreadMenuItem.Text = "&Terminate"; + this.terminateThreadMenuItem.Click += new System.EventHandler(this.terminateThreadMenuItem_Click); + // + // forceTerminateThreadMenuItem + // + this.forceTerminateThreadMenuItem.Index = 2; + this.forceTerminateThreadMenuItem.Text = "Force Terminate"; + this.forceTerminateThreadMenuItem.Click += new System.EventHandler(this.forceTerminateThreadMenuItem_Click); + // + // suspendThreadMenuItem + // + this.vistaMenu.SetImage(this.suspendThreadMenuItem, global::ProcessHacker.Properties.Resources.control_pause_blue); + this.suspendThreadMenuItem.Index = 3; + this.suspendThreadMenuItem.Text = "&Suspend"; + this.suspendThreadMenuItem.Click += new System.EventHandler(this.suspendThreadMenuItem_Click); + // + // resumeThreadMenuItem + // + this.vistaMenu.SetImage(this.resumeThreadMenuItem, global::ProcessHacker.Properties.Resources.control_play_blue); + this.resumeThreadMenuItem.Index = 4; + this.resumeThreadMenuItem.Text = "&Resume"; + this.resumeThreadMenuItem.Click += new System.EventHandler(this.resumeThreadMenuItem_Click); + // + // menuItem4 + // + this.menuItem4.Index = 5; + this.menuItem4.Text = "-"; + // + // inspectTEBMenuItem + // + this.inspectTEBMenuItem.Index = 6; + this.inspectTEBMenuItem.Text = "Inspect TEB"; + this.inspectTEBMenuItem.Click += new System.EventHandler(this.inspectTEBMenuItem_Click); + // + // tokenThreadMenuItem + // + this.vistaMenu.SetImage(this.tokenThreadMenuItem, global::ProcessHacker.Properties.Resources.locked); + this.tokenThreadMenuItem.Index = 8; + this.tokenThreadMenuItem.Text = "Token"; + this.tokenThreadMenuItem.Click += new System.EventHandler(this.tokenThreadMenuItem_Click); + // + // analyzeMenuItem + // + this.analyzeMenuItem.Index = 9; + this.analyzeMenuItem.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.analyzeWaitMenuItem}); + this.analyzeMenuItem.Text = "Analyze"; + // + // analyzeWaitMenuItem + // + this.analyzeWaitMenuItem.Index = 0; + this.analyzeWaitMenuItem.Text = "Wait"; + this.analyzeWaitMenuItem.Click += new System.EventHandler(this.analyzeWaitMenuItem_Click); + // + // priorityThreadMenuItem + // + this.priorityThreadMenuItem.Index = 10; + this.priorityThreadMenuItem.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.timeCriticalThreadMenuItem, + this.highestThreadMenuItem, + this.aboveNormalThreadMenuItem, + this.normalThreadMenuItem, + this.belowNormalThreadMenuItem, + this.lowestThreadMenuItem, + this.idleThreadMenuItem}); + this.priorityThreadMenuItem.Text = "&Priority"; + // + // timeCriticalThreadMenuItem + // + this.timeCriticalThreadMenuItem.Index = 0; + this.timeCriticalThreadMenuItem.RadioCheck = true; + this.timeCriticalThreadMenuItem.Text = "Time Critical"; + this.timeCriticalThreadMenuItem.Click += new System.EventHandler(this.timeCriticalThreadMenuItem_Click); + // + // highestThreadMenuItem + // + this.highestThreadMenuItem.Index = 1; + this.highestThreadMenuItem.RadioCheck = true; + this.highestThreadMenuItem.Text = "Highest"; + this.highestThreadMenuItem.Click += new System.EventHandler(this.highestThreadMenuItem_Click); + // + // aboveNormalThreadMenuItem + // + this.aboveNormalThreadMenuItem.Index = 2; + this.aboveNormalThreadMenuItem.RadioCheck = true; + this.aboveNormalThreadMenuItem.Text = "Above Normal"; + this.aboveNormalThreadMenuItem.Click += new System.EventHandler(this.aboveNormalThreadMenuItem_Click); + // + // normalThreadMenuItem + // + this.normalThreadMenuItem.Index = 3; + this.normalThreadMenuItem.RadioCheck = true; + this.normalThreadMenuItem.Text = "Normal"; + this.normalThreadMenuItem.Click += new System.EventHandler(this.normalThreadMenuItem_Click); + // + // belowNormalThreadMenuItem + // + this.belowNormalThreadMenuItem.Index = 4; + this.belowNormalThreadMenuItem.RadioCheck = true; + this.belowNormalThreadMenuItem.Text = "Below Normal"; + this.belowNormalThreadMenuItem.Click += new System.EventHandler(this.belowNormalThreadMenuItem_Click); + // + // lowestThreadMenuItem + // + this.lowestThreadMenuItem.Index = 5; + this.lowestThreadMenuItem.RadioCheck = true; + this.lowestThreadMenuItem.Text = "Lowest"; + this.lowestThreadMenuItem.Click += new System.EventHandler(this.lowestThreadMenuItem_Click); + // + // idleThreadMenuItem + // + this.idleThreadMenuItem.Index = 6; + this.idleThreadMenuItem.RadioCheck = true; + this.idleThreadMenuItem.Text = "Idle"; + this.idleThreadMenuItem.Click += new System.EventHandler(this.idleThreadMenuItem_Click); + // + // menuItem9 + // + this.menuItem9.Index = 11; + this.menuItem9.Text = "-"; + // + // copyThreadMenuItem + // + this.vistaMenu.SetImage(this.copyThreadMenuItem, global::ProcessHacker.Properties.Resources.page_copy); + this.copyThreadMenuItem.Index = 12; + this.copyThreadMenuItem.Text = "C&opy"; + // + // selectAllThreadMenuItem + // + this.selectAllThreadMenuItem.Index = 13; + this.selectAllThreadMenuItem.Text = "Select &All"; + this.selectAllThreadMenuItem.Click += new System.EventHandler(this.selectAllThreadMenuItem_Click); + // + // tableInformation + // + this.tableInformation.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.tableInformation.ColumnCount = 4; + this.tableInformation.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableInformation.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableInformation.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableInformation.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableInformation.Controls.Add(this.label6, 0, 0); + this.tableInformation.Controls.Add(this.label8, 0, 1); + this.tableInformation.Controls.Add(this.label9, 0, 2); + this.tableInformation.Controls.Add(this.labelState, 1, 0); + this.tableInformation.Controls.Add(this.labelKernelTime, 1, 1); + this.tableInformation.Controls.Add(this.labelUserTime, 1, 2); + this.tableInformation.Controls.Add(this.labelTotalTime, 1, 3); + this.tableInformation.Controls.Add(this.label1, 2, 3); + this.tableInformation.Controls.Add(this.label2, 2, 2); + this.tableInformation.Controls.Add(this.label3, 2, 1); + this.tableInformation.Controls.Add(this.labelContextSwitches, 3, 3); + this.tableInformation.Controls.Add(this.labelBasePriority, 3, 2); + this.tableInformation.Controls.Add(this.labelPriority, 3, 1); + this.tableInformation.Controls.Add(this.label10, 0, 3); + this.tableInformation.Controls.Add(this.label4, 2, 0); + this.tableInformation.Controls.Add(this.labelTEBAddress, 3, 0); + this.tableInformation.Location = new System.Drawing.Point(0, 381); + this.tableInformation.Name = "tableInformation"; + this.tableInformation.RowCount = 4; + this.tableInformation.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableInformation.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableInformation.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableInformation.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableInformation.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableInformation.Size = new System.Drawing.Size(450, 79); + this.tableInformation.TabIndex = 4; + // + // label6 + // + this.label6.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(3, 3); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(32, 13); + this.label6.TabIndex = 1; + this.label6.Text = "State"; + // + // label8 + // + this.label8.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label8.AutoSize = true; + this.label8.Location = new System.Drawing.Point(3, 22); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(63, 13); + this.label8.TabIndex = 1; + this.label8.Text = "Kernel Time"; + // + // label9 + // + this.label9.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label9.AutoSize = true; + this.label9.Location = new System.Drawing.Point(3, 41); + this.label9.Name = "label9"; + this.label9.Size = new System.Drawing.Size(55, 13); + this.label9.TabIndex = 1; + this.label9.Text = "User Time"; + // + // labelState + // + this.labelState.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelState.AutoSize = true; + this.labelState.Location = new System.Drawing.Point(188, 3); + this.labelState.Name = "labelState"; + this.labelState.Size = new System.Drawing.Size(33, 13); + this.labelState.TabIndex = 1; + this.labelState.Text = "value"; + // + // labelKernelTime + // + this.labelKernelTime.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelKernelTime.AutoSize = true; + this.labelKernelTime.Location = new System.Drawing.Point(188, 22); + this.labelKernelTime.Name = "labelKernelTime"; + this.labelKernelTime.Size = new System.Drawing.Size(33, 13); + this.labelKernelTime.TabIndex = 1; + this.labelKernelTime.Text = "value"; + // + // labelUserTime + // + this.labelUserTime.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelUserTime.AutoSize = true; + this.labelUserTime.Location = new System.Drawing.Point(188, 41); + this.labelUserTime.Name = "labelUserTime"; + this.labelUserTime.Size = new System.Drawing.Size(33, 13); + this.labelUserTime.TabIndex = 1; + this.labelUserTime.Text = "value"; + // + // labelTotalTime + // + this.labelTotalTime.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelTotalTime.AutoSize = true; + this.labelTotalTime.Location = new System.Drawing.Point(188, 61); + this.labelTotalTime.Name = "labelTotalTime"; + this.labelTotalTime.Size = new System.Drawing.Size(33, 13); + this.labelTotalTime.TabIndex = 1; + this.labelTotalTime.Text = "value"; + // + // label1 + // + this.label1.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(227, 61); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(89, 13); + this.label1.TabIndex = 6; + this.label1.Text = "Context Switches"; + // + // label2 + // + this.label2.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(227, 41); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(65, 13); + this.label2.TabIndex = 2; + this.label2.Text = "Base Priority"; + // + // label3 + // + this.label3.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(227, 22); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(38, 13); + this.label3.TabIndex = 5; + this.label3.Text = "Priority"; + // + // labelContextSwitches + // + this.labelContextSwitches.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelContextSwitches.AutoSize = true; + this.labelContextSwitches.Location = new System.Drawing.Point(414, 61); + this.labelContextSwitches.Name = "labelContextSwitches"; + this.labelContextSwitches.Size = new System.Drawing.Size(33, 13); + this.labelContextSwitches.TabIndex = 7; + this.labelContextSwitches.Text = "value"; + // + // labelBasePriority + // + this.labelBasePriority.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelBasePriority.AutoSize = true; + this.labelBasePriority.Location = new System.Drawing.Point(414, 41); + this.labelBasePriority.Name = "labelBasePriority"; + this.labelBasePriority.Size = new System.Drawing.Size(33, 13); + this.labelBasePriority.TabIndex = 4; + this.labelBasePriority.Text = "value"; + // + // labelPriority + // + this.labelPriority.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelPriority.AutoSize = true; + this.labelPriority.Location = new System.Drawing.Point(414, 22); + this.labelPriority.Name = "labelPriority"; + this.labelPriority.Size = new System.Drawing.Size(33, 13); + this.labelPriority.TabIndex = 3; + this.labelPriority.Text = "value"; + // + // label10 + // + this.label10.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label10.AutoSize = true; + this.label10.Location = new System.Drawing.Point(3, 61); + this.label10.Name = "label10"; + this.label10.Size = new System.Drawing.Size(57, 13); + this.label10.TabIndex = 1; + this.label10.Text = "Total Time"; + // + // label4 + // + this.label4.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(227, 3); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(69, 13); + this.label4.TabIndex = 5; + this.label4.Text = "TEB Address"; + // + // labelTEBAddress + // + this.labelTEBAddress.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.labelTEBAddress.AutoSize = true; + this.labelTEBAddress.Location = new System.Drawing.Point(414, 3); + this.labelTEBAddress.Name = "labelTEBAddress"; + this.labelTEBAddress.Size = new System.Drawing.Size(33, 13); + this.labelTEBAddress.TabIndex = 3; + this.labelTEBAddress.Text = "value"; + // + // label7 + // + this.label7.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(3, 356); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(70, 13); + this.label7.TabIndex = 5; + this.label7.Text = "Start Module:"; + // + // vistaMenu + // + this.vistaMenu.ContainerControl = this; + this.vistaMenu.DelaySetImageCalls = false; + // + // fileModule + // + this.fileModule.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.fileModule.Location = new System.Drawing.Point(79, 351); + this.fileModule.Name = "fileModule"; + this.fileModule.ReadOnly = false; + this.fileModule.Size = new System.Drawing.Size(368, 24); + this.fileModule.TabIndex = 6; + // + // permissionsThreadMenuItem + // + this.permissionsThreadMenuItem.Index = 7; + this.permissionsThreadMenuItem.Text = "Permissions"; + this.permissionsThreadMenuItem.Click += new System.EventHandler(this.permissionsThreadMenuItem_Click); + // + // ThreadList + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.fileModule); + this.Controls.Add(this.label7); + this.Controls.Add(this.tableInformation); + this.Controls.Add(this.listThreads); + this.DoubleBuffered = true; + this.Name = "ThreadList"; + this.Size = new System.Drawing.Size(450, 460); + this.tableInformation.ResumeLayout(false); + this.tableInformation.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.vistaMenu)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.ListView listThreads; + private System.Windows.Forms.ColumnHeader columnThreadID; + private System.Windows.Forms.ColumnHeader columnContextSwitchesDelta; + private System.Windows.Forms.ColumnHeader columnStartAddress; + private wyDay.Controls.VistaMenu vistaMenu; + private System.Windows.Forms.ContextMenu menuThread; + private System.Windows.Forms.MenuItem inspectThreadMenuItem; + private System.Windows.Forms.MenuItem terminateThreadMenuItem; + private System.Windows.Forms.MenuItem suspendThreadMenuItem; + private System.Windows.Forms.MenuItem resumeThreadMenuItem; + private System.Windows.Forms.MenuItem menuItem4; + private System.Windows.Forms.MenuItem priorityThreadMenuItem; + private System.Windows.Forms.MenuItem timeCriticalThreadMenuItem; + private System.Windows.Forms.MenuItem highestThreadMenuItem; + private System.Windows.Forms.MenuItem aboveNormalThreadMenuItem; + private System.Windows.Forms.MenuItem normalThreadMenuItem; + private System.Windows.Forms.MenuItem belowNormalThreadMenuItem; + private System.Windows.Forms.MenuItem lowestThreadMenuItem; + private System.Windows.Forms.MenuItem idleThreadMenuItem; + private System.Windows.Forms.MenuItem menuItem9; + private System.Windows.Forms.MenuItem copyThreadMenuItem; + private System.Windows.Forms.MenuItem selectAllThreadMenuItem; + private System.Windows.Forms.MenuItem inspectTEBMenuItem; + private System.Windows.Forms.ColumnHeader columnPriority; + private System.Windows.Forms.TableLayoutPanel tableInformation; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.Label label8; + private System.Windows.Forms.Label label9; + private System.Windows.Forms.Label label10; + private System.Windows.Forms.Label labelState; + private System.Windows.Forms.Label labelKernelTime; + private System.Windows.Forms.Label labelUserTime; + private System.Windows.Forms.Label labelTotalTime; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label labelBasePriority; + private System.Windows.Forms.Label labelPriority; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label labelContextSwitches; + private System.Windows.Forms.Label label7; + private ProcessHacker.Components.FileNameBox fileModule; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.Label labelTEBAddress; + private System.Windows.Forms.MenuItem analyzeMenuItem; + private System.Windows.Forms.MenuItem analyzeWaitMenuItem; + private System.Windows.Forms.MenuItem forceTerminateThreadMenuItem; + private System.Windows.Forms.MenuItem tokenThreadMenuItem; + private System.Windows.Forms.MenuItem permissionsThreadMenuItem; + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/ThreadList.cs b/branches/ph-plugins/ProcessHacker/Components/ThreadList.cs new file mode 100644 index 000000000..4b0c9284c --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/ThreadList.cs @@ -0,0 +1,1364 @@ +/* + * Process Hacker - + * thread list + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Text; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Common.Ui; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; +using ProcessHacker.Native.Security.AccessControl; +using ProcessHacker.UI; +using ProcessHacker.UI.Actions; + +namespace ProcessHacker.Components +{ + public partial class ThreadList : UserControl + { + private ThreadProvider _provider; + private int _runCount = 0; + private List _needsAdd = new List(); + private HighlightingContext _highlightingContext; + private bool _needsSort = false; + public new event KeyEventHandler KeyDown; + public new event MouseEventHandler MouseDown; + public new event MouseEventHandler MouseUp; + public event EventHandler SelectedIndexChanged; + private int _pid; + + public ThreadList() + { + InitializeComponent(); + + // Use Cycles instead of Context Switches on Vista + if (OSVersion.HasCycleTime) + listThreads.Columns[1].Text = "Cycles Delta"; + + // On x64, the first four arguments are passed in registers, + // which means Analyze won't work properly. + if (IntPtr.Size != 4) + { + analyzeWaitMenuItem.Visible = false; + analyzeMenuItem.Visible = false; + } + + _highlightingContext = new HighlightingContext(listThreads); + var comparer = (SortedListViewComparer) + (listThreads.ListViewItemSorter = new SortedListViewComparer(listThreads)); + + comparer.CustomSorters.Add(1, + (x, y) => + { + if (OSVersion.HasCycleTime) + { + return (x.Tag as ThreadItem).CyclesDelta.CompareTo((y.Tag as ThreadItem).CyclesDelta); + } + else + { + return (x.Tag as ThreadItem).ContextSwitchesDelta.CompareTo((y.Tag as ThreadItem).ContextSwitchesDelta); + } + }); + comparer.CustomSorters.Add(3, + (x, y) => + { + return (x.Tag as ThreadItem).PriorityI.CompareTo((y.Tag as ThreadItem).PriorityI); + }); + comparer.ColumnSortOrder.Add(0); + comparer.ColumnSortOrder.Add(2); + comparer.ColumnSortOrder.Add(3); + comparer.ColumnSortOrder.Add(1); + comparer.SortColumn = 1; + comparer.SortOrder = SortOrder.Descending; + + listThreads.KeyDown += new KeyEventHandler(ThreadList_KeyDown); + listThreads.MouseDown += new MouseEventHandler(listThreads_MouseDown); + listThreads.MouseUp += new MouseEventHandler(listThreads_MouseUp); + listThreads.SelectedIndexChanged += new System.EventHandler(listThreads_SelectedIndexChanged); + + ColumnSettings.LoadSettings(Properties.Settings.Default.ThreadListViewColumns, listThreads); + listThreads.ContextMenu = menuThread; + GenericViewMenu.AddMenuItems(copyThreadMenuItem.MenuItems, listThreads, null); + listThreads_SelectedIndexChanged(null, null); + + _dontCalculate = false; + } + + private bool _dontCalculate = true; + + protected override void OnResize(EventArgs e) + { + if (_dontCalculate) + return; + + base.OnResize(e); + } + + private void listThreads_MouseUp(object sender, MouseEventArgs e) + { + if (this.MouseUp != null) + this.MouseUp(sender, e); + } + + private void listThreads_MouseDown(object sender, MouseEventArgs e) + { + if (this.MouseDown != null) + this.MouseDown(sender, e); + } + + private void listThreads_SelectedIndexChanged(object sender, System.EventArgs e) + { + if (listThreads.SelectedItems.Count == 1) + { + try + { + int tid = int.Parse(listThreads.SelectedItems[0].Name); + var thread = Windows.GetProcessThreads(_pid)[tid]; + ProcessThread processThread = null; + + try + { + processThread = Utils.GetThreadFromId(Process.GetProcessById(_pid), tid); + } + catch + { } + + fileModule.Text = _provider.Dictionary[tid].FileName; + fileModule.Enabled = !string.IsNullOrEmpty(fileModule.Text); + + if (processThread != null) + { + try + { + if (processThread.ThreadState == ThreadState.Wait) + { + labelState.Text = "Wait: " + thread.WaitReason.ToString(); + } + else + { + labelState.Text = processThread.ThreadState.ToString(); + } + + labelKernelTime.Text = Utils.FormatTimeSpan(processThread.PrivilegedProcessorTime); + labelUserTime.Text = Utils.FormatTimeSpan(processThread.UserProcessorTime); + labelTotalTime.Text = Utils.FormatTimeSpan(processThread.TotalProcessorTime); + } + catch + { + labelState.Text = thread.WaitReason.ToString(); + } + } + + labelPriority.Text = thread.Priority.ToString(); + labelBasePriority.Text = thread.BasePriority.ToString(); + labelContextSwitches.Text = thread.ContextSwitchCount.ToString("N0"); + + using (ThreadHandle thandle = new ThreadHandle(tid, ThreadAccess.QueryInformation)) + labelTEBAddress.Text = Utils.FormatAddress(thandle.GetBasicInformation().TebBaseAddress); + } + catch + { } + } + else + { + fileModule.Text = ""; + fileModule.Enabled = false; + labelState.Text = ""; + labelKernelTime.Text = ""; + labelUserTime.Text = ""; + labelTotalTime.Text = ""; + labelTEBAddress.Text = ""; + labelPriority.Text = ""; + labelBasePriority.Text = ""; + labelContextSwitches.Text = ""; + } + + if (this.SelectedIndexChanged != null) + this.SelectedIndexChanged(sender, e); + } + + private void ThreadList_KeyDown(object sender, KeyEventArgs e) + { + if (this.KeyDown != null) + this.KeyDown(sender, e); + + if (!e.Handled) + { + if (e.KeyCode == Keys.Enter) + { + inspectThreadMenuItem_Click(null, null); + } + else if (e.KeyCode == Keys.Delete) + { + terminateThreadMenuItem_Click(null, null); + } + } + } + + #region Properties + + public new bool DoubleBuffered + { + get + { + return (bool)typeof(ListView).GetProperty("DoubleBuffered", + BindingFlags.NonPublic | BindingFlags.Instance).GetValue(listThreads, null); + } + set + { + typeof(ListView).GetProperty("DoubleBuffered", + BindingFlags.NonPublic | BindingFlags.Instance).SetValue(listThreads, value, null); + } + } + + public override bool Focused + { + get + { + return listThreads.Focused; + } + } + + public override ContextMenu ContextMenu + { + get { return listThreads.ContextMenu; } + set { listThreads.ContextMenu = value; } + } + + public override ContextMenuStrip ContextMenuStrip + { + get { return listThreads.ContextMenuStrip; } + set { listThreads.ContextMenuStrip = value; } + } + + public ListView List + { + get { return listThreads; } + } + + public ThreadProvider Provider + { + get { return _provider; } + set + { + _pid = -1; + + if (_provider != null) + { + _provider.DictionaryAdded -= new ThreadProvider.ProviderDictionaryAdded(provider_DictionaryAdded); + _provider.DictionaryModified -= new ThreadProvider.ProviderDictionaryModified(provider_DictionaryModified); + _provider.DictionaryRemoved -= new ThreadProvider.ProviderDictionaryRemoved(provider_DictionaryRemoved); + _provider.Updated -= new ThreadProvider.ProviderUpdateOnce(provider_Updated); + _provider.LoadingStateChanged -= new ThreadProvider.LoadingStateChangedDelegate(provider_LoadingStateChanged); + } + + _provider = value; + + listThreads.Items.Clear(); + + if (_provider != null) + { + foreach (ThreadItem item in _provider.Dictionary.Values) + { + provider_DictionaryAdded(item); + } + + _provider.DictionaryAdded += new ThreadProvider.ProviderDictionaryAdded(provider_DictionaryAdded); + _provider.DictionaryModified += new ThreadProvider.ProviderDictionaryModified(provider_DictionaryModified); + _provider.DictionaryRemoved += new ThreadProvider.ProviderDictionaryRemoved(provider_DictionaryRemoved); + _provider.Updated += new ThreadProvider.ProviderUpdateOnce(provider_Updated); + _provider.LoadingStateChanged += new ThreadProvider.LoadingStateChangedDelegate(provider_LoadingStateChanged); + + _pid = _provider.Pid; + + this.EnableDisableMenuItems(); + } + } + } + + #endregion + + #region Interfacing + + public void BeginUpdate() + { + listThreads.BeginUpdate(); + } + + public void EndUpdate() + { + listThreads.EndUpdate(); + } + + public ListView.ListViewItemCollection Items + { + get { return listThreads.Items; } + } + + public ListView.SelectedListViewItemCollection SelectedItems + { + get { return listThreads.SelectedItems; } + } + + #endregion + + private void provider_Updated() + { + lock (_needsAdd) + { + if (_needsAdd.Count > 0) + { + this.BeginInvoke(new MethodInvoker(() => + { + lock (_needsAdd) + { + listThreads.Items.AddRange(_needsAdd.ToArray()); + _needsAdd.Clear(); + } + })); + } + } + + _highlightingContext.Tick(); + + if (_needsSort) + { + this.BeginInvoke(new MethodInvoker(() => + { + if (_needsSort) + { + listThreads.Sort(); + _needsSort = false; + } + })); + } + + _runCount++; + } + + private void EnableDisableMenuItems() + { + if ( + // If KProcessHacker isn't available, hide Force Terminate. + KProcessHacker.Instance != null && + // Terminating a system thread is the same as Force Terminate, + // so hide it if we're viewing PID 4. + _pid != 4 + ) + forceTerminateThreadMenuItem.Visible = true; + else + forceTerminateThreadMenuItem.Visible = false; + } + + private System.Drawing.Color GetThreadColor(ThreadItem titem) + { + if (Properties.Settings.Default.UseColorSuspended && titem.WaitReason == KWaitReason.Suspended) + return Properties.Settings.Default.ColorSuspended; + else if (Properties.Settings.Default.UseColorGuiThreads && titem.IsGuiThread) + return Properties.Settings.Default.ColorGuiThreads; + + return System.Drawing.SystemColors.Window; + } + + private void provider_DictionaryAdded(ThreadItem item) + { + HighlightedListViewItem litem = new HighlightedListViewItem(_highlightingContext, + item.RunId > 0 && _runCount > 0); + + litem.Name = item.Tid.ToString(); + litem.Text = item.Tid.ToString(); + litem.SubItems.Add(new ListViewItem.ListViewSubItem(litem, "")); + litem.SubItems.Add(new ListViewItem.ListViewSubItem(litem, item.StartAddress)); + litem.SubItems.Add(new ListViewItem.ListViewSubItem(litem, item.Priority)); + litem.Tag = item; + litem.NormalColor = GetThreadColor(item); + + lock (_needsAdd) + _needsAdd.Add(litem); + } + + private void provider_DictionaryModified(ThreadItem oldItem, ThreadItem newItem) + { + this.BeginInvoke(new MethodInvoker(() => + { + lock (listThreads) + { + ListViewItem litem = listThreads.Items[newItem.Tid.ToString()]; + + if (litem == null) + return; + + if (!OSVersion.HasCycleTime) + { + if (newItem.ContextSwitchesDelta == 0) + litem.SubItems[1].Text = ""; + else + litem.SubItems[1].Text = newItem.ContextSwitchesDelta.ToString("N0"); + } + else + { + if (newItem.CyclesDelta == 0) + litem.SubItems[1].Text = ""; + else + litem.SubItems[1].Text = newItem.CyclesDelta.ToString("N0"); + } + + litem.SubItems[2].Text = newItem.StartAddress; + litem.SubItems[3].Text = newItem.Priority; + litem.Tag = newItem; + + (litem as HighlightedListViewItem).NormalColor = GetThreadColor(newItem); + _needsSort = true; + } + })); + } + + private void provider_DictionaryRemoved(ThreadItem item) + { + this.BeginInvoke(new MethodInvoker(() => + { + lock (listThreads) + { + if (listThreads.Items.ContainsKey(item.Tid.ToString())) + listThreads.Items[item.Tid.ToString()].Remove(); + } + })); + } + + private void provider_LoadingStateChanged(bool loading) + { + this.BeginInvoke(new MethodInvoker(() => + { + if (loading) + listThreads.Cursor = Cursors.AppStarting; + else + listThreads.Cursor = Cursors.Default; + })); + } + + public void SaveSettings() + { + Properties.Settings.Default.ThreadListViewColumns = ColumnSettings.SaveSettings(listThreads); + } + + private void SetThreadPriority(ThreadPriorityLevel priority) + { + try + { + int tid = int.Parse(listThreads.SelectedItems[0].SubItems[0].Text); + + using (var thandle = new ThreadHandle(tid, OSVersion.MinThreadSetInfoAccess)) + thandle.SetBasePriorityWin32(priority); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to set the priority of the thread", ex); + } + } + + private void listThreads_DoubleClick(object sender, EventArgs e) + { + inspectThreadMenuItem_Click(null, null); + } + + private void menuThread_Popup(object sender, EventArgs e) + { + if (listThreads.SelectedItems.Count == 0) + { + menuThread.DisableAll(); + + return; + } + else if (listThreads.SelectedItems.Count == 1) + { + menuThread.EnableAll(); + + timeCriticalThreadMenuItem.Checked = false; + highestThreadMenuItem.Checked = false; + aboveNormalThreadMenuItem.Checked = false; + normalThreadMenuItem.Checked = false; + belowNormalThreadMenuItem.Checked = false; + lowestThreadMenuItem.Checked = false; + idleThreadMenuItem.Checked = false; + terminateThreadMenuItem.Text = "&Terminate Thread"; + forceTerminateThreadMenuItem.Text = "Force Terminate Thread"; + suspendThreadMenuItem.Text = "&Suspend Thread"; + resumeThreadMenuItem.Text = "&Resume Thread"; + priorityThreadMenuItem.Text = "&Priority"; + + try + { + using (var thandle = new ThreadHandle( + int.Parse(listThreads.SelectedItems[0].SubItems[0].Text), + Program.MinThreadQueryRights)) + { + switch (thandle.GetBasePriorityWin32()) + { + case ThreadPriorityLevel.TimeCritical: + timeCriticalThreadMenuItem.Checked = true; + break; + + case ThreadPriorityLevel.Highest: + highestThreadMenuItem.Checked = true; + break; + + case ThreadPriorityLevel.AboveNormal: + aboveNormalThreadMenuItem.Checked = true; + break; + + case ThreadPriorityLevel.Normal: + normalThreadMenuItem.Checked = true; + break; + + case ThreadPriorityLevel.BelowNormal: + belowNormalThreadMenuItem.Checked = true; + break; + + case ThreadPriorityLevel.Lowest: + lowestThreadMenuItem.Checked = true; + break; + + case ThreadPriorityLevel.Idle: + idleThreadMenuItem.Checked = true; + break; + } + } + + priorityThreadMenuItem.Enabled = true; + } + catch (Exception ex) + { + priorityThreadMenuItem.Text = "(" + ex.Message + ")"; + priorityThreadMenuItem.Enabled = false; + } + + try + { + using (ThreadHandle thandle = new ThreadHandle( + int.Parse(listThreads.SelectedItems[0].Text), Program.MinThreadQueryRights + )) + { + using (TokenHandle tokenHandle = thandle.GetToken(TokenAccess.Query)) + { + tokenThreadMenuItem.Enabled = true; + } + } + } + catch (WindowsException) + { + tokenThreadMenuItem.Enabled = false; + } + } + else + { + menuThread.DisableAll(); + + terminateThreadMenuItem.Enabled = true; + forceTerminateThreadMenuItem.Enabled = true; + suspendThreadMenuItem.Enabled = true; + resumeThreadMenuItem.Enabled = true; + terminateThreadMenuItem.Text = "&Terminate Threads"; + forceTerminateThreadMenuItem.Text = "Force Terminate Threads"; + suspendThreadMenuItem.Text = "&Suspend Threads"; + resumeThreadMenuItem.Text = "&Resume Threads"; + copyThreadMenuItem.Enabled = true; + } + + if (listThreads.Items.Count == 0) + { + selectAllThreadMenuItem.Enabled = false; + } + else + { + selectAllThreadMenuItem.Enabled = true; + } + } + + private void inspectThreadMenuItem_Click(object sender, EventArgs e) + { + if (listThreads.SelectedItems.Count != 1) + return; + + // Can't view system thread stacks if KPH isn't present. + if ( + _pid == 4 && + KProcessHacker.Instance == null + ) + { + PhUtils.ShowError( + "Process Hacker cannot view system thread stacks without KProcessHacker. " + + "Make sure Process Hacker has administrative privileges and KProcessHacker " + + "supports your operating system." + ); + + return; + } + + // Suspending PH threads is not a good idea :( + if (_pid == ProcessHandle.GetCurrentId()) + { + if (!PhUtils.ShowConfirmMessage( + "inspect", + "Process Hacker's threads", + "Inspecting Process Hacker's threads may lead to instability.", + true + )) + return; + } + + try + { + ProcessHandle phandle = null; + + // If we have KPH, we don't need much access. + if (KProcessHacker.Instance != null) + { + if ((_provider.ProcessAccess & ProcessAccess.QueryLimitedInformation) != 0 || + (_provider.ProcessAccess & ProcessAccess.QueryInformation) != 0) + phandle = _provider.ProcessHandle; + } + else + { + if ((_provider.ProcessAccess & (ProcessAccess.QueryInformation | ProcessAccess.VmRead)) != 0) + phandle = _provider.ProcessHandle; + } + + // If we have KPH load kernel modules so we can get the kernel-mode stack. + try + { + _provider.LoadKernelSymbols(); + } + catch + { } + + (new ThreadWindow( + _pid, + Int32.Parse(listThreads.SelectedItems[0].SubItems[0].Text), + _provider.Symbols, + phandle + ) + ).ShowDialog(this); + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + + private void terminateThreadMenuItem_Click(object sender, EventArgs e) + { + if (listThreads.SelectedItems.Count == 0) + return; + + // Special case for system threads. + if ( + KProcessHacker.Instance != null && + _pid == 4 + ) + { + if (!PhUtils.ShowConfirmMessage( + "terminate", + "the selected system thread(s)", + "Forcibly terminating system threads may cause the system to crash.", + true + )) + return; + + foreach (ListViewItem item in listThreads.SelectedItems) + { + int tid = Int32.Parse(item.SubItems[0].Text); + + try + { + using (var thandle = new ThreadHandle(tid, ThreadAccess.Terminate)) + thandle.DangerousTerminate(NtStatus.Success); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to terminate the thread " + tid.ToString(), ex); + } + } + + return; + } + + if (!PhUtils.ShowConfirmMessage( + "terminate", + "the selected thread(s)", + "Terminating a thread may cause the process to stop working.", + false + )) + return; + + if (Program.ElevationType == TokenElevationType.Limited && + KProcessHacker.Instance == null && + Properties.Settings.Default.ElevationLevel != (int)ElevationLevel.Never) + { + try + { + foreach (ListViewItem item in listThreads.SelectedItems) + { + using (var thandle = new ThreadHandle(int.Parse(item.SubItems[0].Text), + ThreadAccess.Terminate)) + { } + } + } + catch + { + string objects = ""; + + foreach (ListViewItem item in listThreads.SelectedItems) + objects += item.SubItems[0].Text + ","; + + Program.StartProcessHackerAdmin("-e -type thread -action terminate -obj \"" + + objects + "\" -hwnd " + this.Handle.ToString(), null, this.Handle); + + return; + } + } + + foreach (ListViewItem item in listThreads.SelectedItems) + { + try + { + using (var thandle = new ThreadHandle(Int32.Parse(item.SubItems[0].Text), + ThreadAccess.Terminate)) + thandle.Terminate(); + } + catch (Exception ex) + { + if (!PhUtils.ShowContinueMessage( + "Unable to terminate the thread with ID " + item.SubItems[0].Text, + ex + )) + return; + } + } + } + + private void forceTerminateThreadMenuItem_Click(object sender, EventArgs e) + { + if (!PhUtils.ShowConfirmMessage( + "force terminate", + "the selected thread(s)", + "Forcibly terminating threads may cause the system to crash.", + true + )) + return; + + foreach (ListViewItem item in listThreads.SelectedItems) + { + int tid = Int32.Parse(item.SubItems[0].Text); + + try + { + using (var thandle = new ThreadHandle(tid, ThreadAccess.Terminate)) + thandle.DangerousTerminate(NtStatus.Success); + } + catch (Exception ex) + { + if (!PhUtils.ShowContinueMessage( + "Unable to force terminate the thread with ID " + item.SubItems[0].Text, + ex + )) + return; + } + } + } + + private void suspendThreadMenuItem_Click(object sender, EventArgs e) + { + //if (Properties.Settings.Default.WarnDangerous && PhUtils.IsDangerousPid(_pid)) + //{ + // DialogResult result = MessageBox.Show("The process with PID " + _pid + " is a system process. Are you" + + // " sure you want to suspend the selected thread(s)?", "Process Hacker", MessageBoxButtons.YesNo, + // MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button2); + + // if (result == DialogResult.No) + // return; + //} + + if (Program.ElevationType == TokenElevationType.Limited && + KProcessHacker.Instance == null && + Properties.Settings.Default.ElevationLevel != (int)ElevationLevel.Never) + { + try + { + foreach (ListViewItem item in listThreads.SelectedItems) + { + using (var thandle = new ThreadHandle(int.Parse(item.SubItems[0].Text), + ThreadAccess.SuspendResume)) + { } + } + } + catch + { + string objects = ""; + + foreach (ListViewItem item in listThreads.SelectedItems) + objects += item.SubItems[0].Text + ","; + + Program.StartProcessHackerAdmin("-e -type thread -action suspend -obj \"" + + objects + "\" -hwnd " + this.Handle.ToString(), null, this.Handle); + + return; + } + } + + foreach (ListViewItem item in listThreads.SelectedItems) + { + try + { + using (var thandle = new ThreadHandle(Int32.Parse(item.SubItems[0].Text), + ThreadAccess.SuspendResume)) + thandle.Suspend(); + } + catch (Exception ex) + { + if (!PhUtils.ShowContinueMessage( + "Unable to suspend the thread with ID " + item.SubItems[0].Text, + ex + )) + return; + } + } + } + + private void resumeThreadMenuItem_Click(object sender, EventArgs e) + { + //if (Properties.Settings.Default.WarnDangerous && PhUtils.IsDangerousPid(_pid)) + //{ + // DialogResult result = MessageBox.Show("The process with PID " + _pid + " is a system process. Are you" + + // " sure you want to resume the selected thread(s)?", "Process Hacker", MessageBoxButtons.YesNo, + // MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button2); + + // if (result == DialogResult.No) + // return; + //} + + if (Program.ElevationType == TokenElevationType.Limited && + KProcessHacker.Instance == null && + Properties.Settings.Default.ElevationLevel != (int)ElevationLevel.Never) + { + try + { + foreach (ListViewItem item in listThreads.SelectedItems) + { + using (var thandle = new ThreadHandle(int.Parse(item.SubItems[0].Text), + ThreadAccess.SuspendResume)) + { } + } + } + catch + { + string objects = ""; + + foreach (ListViewItem item in listThreads.SelectedItems) + objects += item.SubItems[0].Text + ","; + + Program.StartProcessHackerAdmin("-e -type thread -action resume -obj \"" + + objects + "\" -hwnd " + this.Handle.ToString(), null, this.Handle); + + return; + } + } + foreach (ListViewItem item in listThreads.SelectedItems) + { + try + { + using (var thandle = new ThreadHandle(Int32.Parse(item.SubItems[0].Text), + ThreadAccess.SuspendResume)) + thandle.Resume(); + } + catch (Exception ex) + { + if (!PhUtils.ShowContinueMessage( + "Unable to resume the thread with ID " + item.SubItems[0].Text, + ex + )) + return; + } + } + } + + private void inspectTEBMenuItem_Click(object sender, EventArgs e) + { + if (!Program.Structs.ContainsKey("TEB")) + { + PhUtils.ShowError("The struct 'TEB' has not been loaded. Make sure structs.txt was loaded successfully."); + return; + } + + try + { + using (ThreadHandle thandle = new ThreadHandle(int.Parse(listThreads.SelectedItems[0].Text))) + { + IntPtr tebBaseAddress = thandle.GetBasicInformation().TebBaseAddress; + + Program.HackerWindow.BeginInvoke(new MethodInvoker(delegate + { + StructWindow sw = new StructWindow(_pid, tebBaseAddress, Program.Structs["TEB"]); + + try + { + sw.Show(); + sw.Activate(); + } + catch (Exception ex) + { + Logging.Log(ex); + } + })); + } + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to inspect the TEB of the thread", ex); + } + } + + private void permissionsThreadMenuItem_Click(object sender, EventArgs e) + { + try + { + SecurityEditor.EditSecurity( + this, + SecurityEditor.GetSecurable( + NativeTypeFactory.ObjectType.Thread, + (access) => new ThreadHandle(int.Parse(listThreads.SelectedItems[0].Text), (ThreadAccess)access) + ), + "Thread " + listThreads.SelectedItems[0].Text, + NativeTypeFactory.GetAccessEntries(NativeTypeFactory.ObjectType.Thread) + ); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to edit security", ex); + } + } + + private void tokenThreadMenuItem_Click(object sender, EventArgs e) + { + try + { + using (ThreadHandle thandle = new ThreadHandle( + int.Parse(listThreads.SelectedItems[0].Text), Program.MinThreadQueryRights + )) + { + TokenWindow tokForm = new TokenWindow(thandle); + + tokForm.Text = "Thread Token"; + tokForm.ShowDialog(); + } + } + catch (ObjectDisposedException) + { } + catch (Exception ex) + { + PhUtils.ShowException("Unable to view the thread token", ex); + } + } + + private SystemHandleEntry GetShiForHandle(int pid, IntPtr handle) + { + short handleValue = (short)handle.ToInt32(); + var handles = Windows.GetHandles(); + + foreach (var handleInfo in handles) + { + if (handleInfo.ProcessId == pid && handleInfo.Handle == handleValue) + return handleInfo; + } + + return new SystemHandleEntry(); + } + + #region Analyze + + private string GetHandleString(int pid, IntPtr handle) + { + var shi = this.GetShiForHandle(pid, handle); + + try + { + var handleInfo = shi.GetHandleInfo(); + + return "Handle 0x" + handle.ToString("x") + " (" + handleInfo.TypeName + "): " + + (string.IsNullOrEmpty(handleInfo.BestName) ? "(unnamed object)" : handleInfo.BestName); + } + catch + { + return "Handle 0x" + handle.ToString("x") + ": (error querying name)"; + } + } + + private unsafe void analyzeWaitMenuItem_Click(object sender, EventArgs e) + { + try + { + StringBuilder sb = new StringBuilder(); + int tid = int.Parse(listThreads.SelectedItems[0].SubItems[0].Text); + ProcessHandle phandle = null; + + if ((_provider.ProcessAccess & (ProcessAccess.QueryInformation | ProcessAccess.VmRead)) != 0) + phandle = _provider.ProcessHandle; + else + phandle = new ProcessHandle(_pid, ProcessAccess.QueryInformation | ProcessAccess.VmRead); + + ProcessHandle processDupHandle = new ProcessHandle(_pid, ProcessAccess.DupHandle); + + bool found = false; + + using (var thandle = new ThreadHandle(tid, ThreadAccess.GetContext | ThreadAccess.SuspendResume)) + { + IntPtr[] lastParams = new IntPtr[4]; + + thandle.WalkStack(phandle, (stackFrame) => + { + uint address = stackFrame.PcAddress.ToUInt32(); + string name = _provider.Symbols.GetSymbolFromAddress(address).ToLower(); + + if (name == null) + { + // dummy + } + else if ( + name.StartsWith("kernel32.dll!sleep") + ) + { + found = true; + + sb.Append("Thread is sleeping. Timeout: " + + stackFrame.Params[0].ToInt32().ToString() + " milliseconds"); + } + else if ( + name.StartsWith("ntdll.dll!zwdelayexecution") || + name.StartsWith("ntdll.dll!ntdelayexecution") + ) + { + found = true; + + bool alertable = stackFrame.Params[0].ToInt32() != 0; + IntPtr timeoutAddress = stackFrame.Params[1]; + long timeout; + + phandle.ReadMemory(timeoutAddress, &timeout, sizeof(long)); + + if (timeout < 0) + { + sb.Append("Thread is sleeping. Timeout: " + + (new TimeSpan(-timeout)).TotalMilliseconds.ToString() + " milliseconds"); + } + else + { + sb.AppendLine("Thread is sleeping. Timeout: " + (new DateTime(timeout)).ToString()); + } + } + else if ( + name.StartsWith("ntdll.dll!zwdeviceiocontrolfile") || + name.StartsWith("ntdll.dll!ntdeviceiocontrolfile") + ) + { + found = true; + + IntPtr handle = stackFrame.Params[0]; + + sb.AppendLine("Thread " + tid.ToString() + " is waiting for an I/O control request:"); + + sb.AppendLine(this.GetHandleString(_pid, handle)); + } + else if ( + name.StartsWith("ntdll.dll!ntfscontrolfile") || + name.StartsWith("ntdll.dll!zwfscontrolfile") + ) + { + found = true; + + IntPtr handle = stackFrame.Params[0]; + + sb.AppendLine("Thread " + tid.ToString() + " is waiting for an FS control request:"); + + sb.AppendLine(this.GetHandleString(_pid, handle)); + } + else if ( + name.StartsWith("ntdll.dll!ntqueryobject") || + name.StartsWith("ntdll.dll!zwqueryobject") + ) + { + found = true; + + IntPtr handle = stackFrame.Params[0]; + + // Use the KiFastSystemCallRet args if the handle we have is wrong. + if (handle.ToInt32() % 2 != 0 || handle == IntPtr.Zero) + handle = lastParams[1]; + + sb.AppendLine("Thread " + tid.ToString() + " is querying an object (most likely a named pipe):"); + + sb.AppendLine(this.GetHandleString(_pid, handle)); + } + else if ( + name.StartsWith("ntdll.dll!zwreadfile") || + name.StartsWith("ntdll.dll!ntreadfile") || + name.StartsWith("ntdll.dll!zwwritefile") || + name.StartsWith("ntdll.dll!ntwritefile") + ) + { + found = true; + + IntPtr handle = stackFrame.Params[0]; + + sb.AppendLine("Thread " + tid.ToString() + " is waiting for a named pipe or a file:"); + + sb.AppendLine(this.GetHandleString(_pid, handle)); + } + else if ( + name.StartsWith("ntdll.dll!zwremoveiocompletion") || + name.StartsWith("ntdll.dll!ntremoveiocompletion") + ) + { + found = true; + + IntPtr handle = stackFrame.Params[0]; + + sb.AppendLine("Thread " + tid.ToString() + " is waiting for an I/O completion object:"); + + sb.AppendLine(this.GetHandleString(_pid, handle)); + } + else if ( + name.StartsWith("ntdll.dll!zwreplywaitreceiveport") || + name.StartsWith("ntdll.dll!ntreplywaitreceiveport") || + name.StartsWith("ntdll.dll!zwrequestwaitreplyport") || + name.StartsWith("ntdll.dll!ntrequestwaitreplyport") || + name.StartsWith("ntdll.dll!zwalpcsendwaitreceiveport") || + name.StartsWith("ntdll.dll!ntalpcsendwaitreceiveport") + ) + { + found = true; + + IntPtr handle = stackFrame.Params[0]; + + sb.AppendLine("Thread " + tid.ToString() + " is waiting for a LPC port:"); + + sb.AppendLine(this.GetHandleString(_pid, handle)); + } + else if + ( + name.StartsWith("ntdll.dll!zwsethighwaitloweventpair") || + name.StartsWith("ntdll.dll!ntsethighwaitloweventpair") || + name.StartsWith("ntdll.dll!zwsetlowwaithigheventpair") || + name.StartsWith("ntdll.dll!ntsetlowwaithigheventpair") || + name.StartsWith("ntdll.dll!zwwaithigheventpair") || + name.StartsWith("ntdll.dll!ntwaithigheventpair") || + name.StartsWith("ntdll.dll!zwwaitloweventpair") || + name.StartsWith("ntdll.dll!ntwaitloweventpair") + ) + { + found = true; + + IntPtr handle = stackFrame.Params[0]; + + // Use the KiFastSystemCallRet args if the handle we have is wrong. + if (handle.ToInt32() % 2 != 0) + handle = lastParams[1]; + + sb.AppendLine("Thread " + tid.ToString() + " is waiting (" + name + ") for an event pair:"); + + sb.AppendLine(this.GetHandleString(_pid, handle)); + } + else if ( + name.StartsWith("user32.dll!ntusergetmessage") || + name.StartsWith("user32.dll!ntuserwaitmessage") + ) + { + found = true; + + sb.AppendLine("Thread " + tid.ToString() + " is waiting for a USER message."); + } + else if ( + name.StartsWith("ntdll.dll!zwwaitfordebugevent") || + name.StartsWith("ntdll.dll!ntwaitfordebugevent") + ) + { + found = true; + + IntPtr handle = stackFrame.Params[0]; + + sb.AppendLine("Thread " + tid.ToString() + " is waiting for a debug event:"); + + sb.AppendLine(this.GetHandleString(_pid, handle)); + } + else if ( + name.StartsWith("ntdll.dll!zwwaitforkeyedevent") || + name.StartsWith("ntdll.dll!ntwaitforkeyedevent") || + name.StartsWith("ntdll.dll!zwreleasekeyedevent") || + name.StartsWith("ntdll.dll!ntreleasekeyedevent") + ) + { + found = true; + + IntPtr handle = stackFrame.Params[0]; + IntPtr key = stackFrame.Params[1]; + + sb.AppendLine("Thread " + tid.ToString() + + " is waiting (" + name + ") for a keyed event (key 0x" + + key.ToString("x") + "):"); + + sb.AppendLine(this.GetHandleString(_pid, handle)); + } + else if ( + name.StartsWith("ntdll.dll!zwwaitformultipleobjects") || + name.StartsWith("ntdll.dll!ntwaitformultipleobjects") || + name.StartsWith("kernel32.dll!waitformultipleobjects") + ) + { + found = true; + + int handleCount = stackFrame.Params[0].ToInt32(); + IntPtr handleAddress = stackFrame.Params[1]; + WaitType waitType = (WaitType)stackFrame.Params[2].ToInt32(); + bool alertable = stackFrame.Params[3].ToInt32() != 0; + + // use the KiFastSystemCallRet args if we have the wrong args + if (handleCount > 64) + { + handleCount = lastParams[1].ToInt32(); + handleAddress = lastParams[2]; + waitType = (WaitType)lastParams[3].ToInt32(); + } + + IntPtr* handles = stackalloc IntPtr[handleCount]; + + phandle.ReadMemory(handleAddress, handles, handleCount * IntPtr.Size); + + sb.AppendLine("Thread " + tid.ToString() + + " is waiting (alertable: " + alertable.ToString() + ", wait type: " + + waitType.ToString() + ") for:"); + + for (int i = 0; i < handleCount; i++) + { + sb.AppendLine(this.GetHandleString(_pid, handles[i])); + } + } + else if ( + name.StartsWith("ntdll.dll!zwwaitforsingleobject") || + name.StartsWith("ntdll.dll!ntwaitforsingleobject") || + name.StartsWith("kernel32.dll!waitforsingleobject") + ) + { + found = true; + + IntPtr handle = stackFrame.Params[0]; + bool alertable = stackFrame.Params[1].ToInt32() != 0; + + sb.AppendLine("Thread " + tid.ToString() + + " is waiting (alertable: " + alertable.ToString() + ") for:"); + + sb.AppendLine(this.GetHandleString(_pid, handle)); + } + else if ( + name.StartsWith("ntdll.dll!zwwaitforworkviaworkerfactory") || + name.StartsWith("ntdll.dll!ntwaitforworkviaworkerfactory") + ) + { + found = true; + + IntPtr handle = stackFrame.Params[0]; + + sb.AppendLine("Thread " + tid.ToString() + " is waiting for work from a worker factory:"); + + sb.AppendLine(this.GetHandleString(_pid, handle)); + } + + lastParams = stackFrame.Params; + + return !found; + }); + } + + if (found) + { + ScratchpadWindow.Create(sb.ToString()); + } + else + { + PhUtils.ShowInformation("The thread does not appear to be waiting."); + } + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to analyze the thread", ex); + } + } + + #endregion + + #region Priority + + private void timeCriticalThreadMenuItem_Click(object sender, EventArgs e) + { + SetThreadPriority(ThreadPriorityLevel.TimeCritical); + } + + private void highestThreadMenuItem_Click(object sender, EventArgs e) + { + SetThreadPriority(ThreadPriorityLevel.Highest); + } + + private void aboveNormalThreadMenuItem_Click(object sender, EventArgs e) + { + SetThreadPriority(ThreadPriorityLevel.AboveNormal); + } + + private void normalThreadMenuItem_Click(object sender, EventArgs e) + { + SetThreadPriority(ThreadPriorityLevel.Normal); + } + + private void belowNormalThreadMenuItem_Click(object sender, EventArgs e) + { + SetThreadPriority(ThreadPriorityLevel.BelowNormal); + } + + private void lowestThreadMenuItem_Click(object sender, EventArgs e) + { + SetThreadPriority(ThreadPriorityLevel.Lowest); + } + + private void idleThreadMenuItem_Click(object sender, EventArgs e) + { + SetThreadPriority(ThreadPriorityLevel.Idle); + } + + #endregion + + private void selectAllThreadMenuItem_Click(object sender, EventArgs e) + { + Utils.SelectAll(listThreads.Items); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/ThreadList.resx b/branches/ph-plugins/ProcessHacker/Components/ThreadList.resx new file mode 100644 index 000000000..737724d1f --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/ThreadList.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 125, 17 + + + 17, 17 + + + 17, 17 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/TimerProperties.Designer.cs b/branches/ph-plugins/ProcessHacker/Components/TimerProperties.Designer.cs new file mode 100644 index 000000000..d803079f0 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/TimerProperties.Designer.cs @@ -0,0 +1,123 @@ +namespace ProcessHacker.Components +{ + partial class TimerProperties + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + _timerHandle.Dereference(disposing); + + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.timerUpdate = new System.Windows.Forms.Timer(this.components); + this.label1 = new System.Windows.Forms.Label(); + this.labelTimeRemaining = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.labelSignaled = new System.Windows.Forms.Label(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // timerUpdate + // + this.timerUpdate.Interval = 1000; + this.timerUpdate.Tick += new System.EventHandler(this.timerUpdate_Tick); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(6, 3); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(51, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Signaled:"; + // + // labelTimeRemaining + // + this.labelTimeRemaining.AutoSize = true; + this.labelTimeRemaining.Location = new System.Drawing.Point(98, 25); + this.labelTimeRemaining.Name = "labelTimeRemaining"; + this.labelTimeRemaining.Size = new System.Drawing.Size(13, 13); + this.labelTimeRemaining.TabIndex = 1; + this.labelTimeRemaining.Text = "0"; + this.labelTimeRemaining.Visible = false; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(6, 25); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(86, 13); + this.label3.TabIndex = 0; + this.label3.Text = "Time Remaining:"; + this.label3.Visible = false; + // + // labelSignaled + // + this.labelSignaled.AutoSize = true; + this.labelSignaled.Location = new System.Drawing.Point(98, 3); + this.labelSignaled.Name = "labelSignaled"; + this.labelSignaled.Size = new System.Drawing.Size(32, 13); + this.labelSignaled.TabIndex = 1; + this.labelSignaled.Text = "False"; + // + // buttonCancel + // + this.buttonCancel.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonCancel.Location = new System.Drawing.Point(6, 52); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.TabIndex = 2; + this.buttonCancel.Text = "Cancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click); + // + // TimerProperties + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.labelSignaled); + this.Controls.Add(this.labelTimeRemaining); + this.Controls.Add(this.label3); + this.Controls.Add(this.label1); + this.Name = "TimerProperties"; + this.Padding = new System.Windows.Forms.Padding(3); + this.Size = new System.Drawing.Size(215, 81); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Timer timerUpdate; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label labelTimeRemaining; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label labelSignaled; + private System.Windows.Forms.Button buttonCancel; + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/TimerProperties.cs b/branches/ph-plugins/ProcessHacker/Components/TimerProperties.cs new file mode 100644 index 000000000..ad7164745 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/TimerProperties.cs @@ -0,0 +1,57 @@ +using System; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.Components +{ + public partial class TimerProperties : UserControl + { + private TimerHandle _timerHandle; + + public TimerProperties(TimerHandle timerHandle) + { + InitializeComponent(); + + _timerHandle = timerHandle; + _timerHandle.Reference(); + + this.UpdateInfo(); + } + + private void UpdateInfo() + { + try + { + var basicInfo = _timerHandle.GetBasicInformation(); + + labelSignaled.Text = basicInfo.TimerState.ToString(); + labelTimeRemaining.Text = (new TimeSpan(-basicInfo.RemainingTime)).ToString(); + } + catch (Exception ex) + { + labelSignaled.Text = "(" + ex.Message + ")"; + labelTimeRemaining.Text = "(" + ex.Message + ")"; + } + } + + private void buttonCancel_Click(object sender, EventArgs e) + { + try + { + _timerHandle.ChangeAccess(TimerAccess.QueryState | TimerAccess.ModifyState); + _timerHandle.Cancel(); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to cancel the timer", ex); + } + } + + private void timerUpdate_Tick(object sender, EventArgs e) + { + this.UpdateInfo(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/TimerProperties.resx b/branches/ph-plugins/ProcessHacker/Components/TimerProperties.resx new file mode 100644 index 000000000..3add4121b --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/TimerProperties.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/TmRmProperties.Designer.cs b/branches/ph-plugins/ProcessHacker/Components/TmRmProperties.Designer.cs new file mode 100644 index 000000000..e022334d4 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/TmRmProperties.Designer.cs @@ -0,0 +1,101 @@ +namespace ProcessHacker.Components +{ + partial class TmRmProperties + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + _rmHandle.Dispose(disposing); + + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.textDescription = new System.Windows.Forms.TextBox(); + this.textGuid = new System.Windows.Forms.TextBox(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(6, 9); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(63, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Description:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(6, 35); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(37, 13); + this.label2.TabIndex = 0; + this.label2.Text = "GUID:"; + // + // textDescription + // + this.textDescription.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textDescription.Location = new System.Drawing.Point(75, 6); + this.textDescription.Name = "textDescription"; + this.textDescription.ReadOnly = true; + this.textDescription.Size = new System.Drawing.Size(252, 20); + this.textDescription.TabIndex = 1; + // + // textGuid + // + this.textGuid.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textGuid.Location = new System.Drawing.Point(49, 32); + this.textGuid.Name = "textGuid"; + this.textGuid.ReadOnly = true; + this.textGuid.Size = new System.Drawing.Size(278, 20); + this.textGuid.TabIndex = 1; + // + // TmRmProperties + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.textGuid); + this.Controls.Add(this.textDescription); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.Name = "TmRmProperties"; + this.Padding = new System.Windows.Forms.Padding(3); + this.Size = new System.Drawing.Size(333, 62); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox textDescription; + private System.Windows.Forms.TextBox textGuid; + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/TmRmProperties.cs b/branches/ph-plugins/ProcessHacker/Components/TmRmProperties.cs new file mode 100644 index 000000000..20db152ad --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/TmRmProperties.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Text; +using System.Windows.Forms; +using ProcessHacker.Native.Objects; + +namespace ProcessHacker.Components +{ + public partial class TmRmProperties : UserControl + { + private ResourceManagerHandle _rmHandle; + + public TmRmProperties(ResourceManagerHandle rmHandle) + { + InitializeComponent(); + + _rmHandle = rmHandle; + _rmHandle.Reference(); + + this.UpdateInfo(); + } + + private void UpdateInfo() + { + try + { + textDescription.Text = _rmHandle.GetDescription(); + textGuid.Text = _rmHandle.GetGuid().ToString("B"); + } + catch (Exception ex) + { + textDescription.Text = "(" + ex.Message + ")"; + textGuid.Text = "(" + ex.Message + ")"; + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/TmRmProperties.resx b/branches/ph-plugins/ProcessHacker/Components/TmRmProperties.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/TmRmProperties.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/TmTmProperties.Designer.cs b/branches/ph-plugins/ProcessHacker/Components/TmTmProperties.Designer.cs new file mode 100644 index 000000000..2dfb45364 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/TmTmProperties.Designer.cs @@ -0,0 +1,101 @@ +namespace ProcessHacker.Components +{ + partial class TmTmProperties + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + _tmHandle.Dereference(disposing); + + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.textGuid = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.textLogFileName = new System.Windows.Forms.TextBox(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(6, 9); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(37, 13); + this.label1.TabIndex = 0; + this.label1.Text = "GUID:"; + // + // textGuid + // + this.textGuid.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textGuid.Location = new System.Drawing.Point(49, 6); + this.textGuid.Name = "textGuid"; + this.textGuid.ReadOnly = true; + this.textGuid.Size = new System.Drawing.Size(244, 20); + this.textGuid.TabIndex = 1; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(6, 35); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(78, 13); + this.label2.TabIndex = 0; + this.label2.Text = "Log File Name:"; + // + // textLogFileName + // + this.textLogFileName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textLogFileName.Location = new System.Drawing.Point(90, 32); + this.textLogFileName.Name = "textLogFileName"; + this.textLogFileName.ReadOnly = true; + this.textLogFileName.Size = new System.Drawing.Size(203, 20); + this.textLogFileName.TabIndex = 1; + // + // TmTmProperties + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.textLogFileName); + this.Controls.Add(this.textGuid); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.Name = "TmTmProperties"; + this.Padding = new System.Windows.Forms.Padding(3); + this.Size = new System.Drawing.Size(299, 62); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox textGuid; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox textLogFileName; + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/TmTmProperties.cs b/branches/ph-plugins/ProcessHacker/Components/TmTmProperties.cs new file mode 100644 index 000000000..6b6ad3bc7 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/TmTmProperties.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Text; +using System.Windows.Forms; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native; + +namespace ProcessHacker.Components +{ + public partial class TmTmProperties : UserControl + { + private TmHandle _tmHandle; + + public TmTmProperties(TmHandle tmHandle) + { + InitializeComponent(); + + _tmHandle = tmHandle; + _tmHandle.Reference(); + + this.UpdateInfo(); + } + + private void UpdateInfo() + { + try + { + textGuid.Text = _tmHandle.GetBasicInformation().TmIdentity.ToString("B"); + textLogFileName.Text = FileUtils.GetFileName(FileUtils.GetFileName(_tmHandle.GetLogFileName())); + } + catch (Exception ex) + { + textGuid.Text = "(" + ex.Message + ")"; + textLogFileName.Text = "(" + ex.Message + ")"; + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/TmTmProperties.resx b/branches/ph-plugins/ProcessHacker/Components/TmTmProperties.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/TmTmProperties.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/TokenGroupsList.Designer.cs b/branches/ph-plugins/ProcessHacker/Components/TokenGroupsList.Designer.cs new file mode 100644 index 000000000..120f3f5d5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/TokenGroupsList.Designer.cs @@ -0,0 +1,80 @@ +namespace ProcessHacker.Components +{ + partial class TokenGroupsList + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.listGroups = new System.Windows.Forms.ListView(); + this.columnGroupName = new System.Windows.Forms.ColumnHeader(); + this.columnFlags = new System.Windows.Forms.ColumnHeader(); + this.SuspendLayout(); + // + // listGroups + // + this.listGroups.AllowColumnReorder = true; + this.listGroups.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnGroupName, + this.columnFlags}); + this.listGroups.Dock = System.Windows.Forms.DockStyle.Fill; + this.listGroups.FullRowSelect = true; + this.listGroups.Location = new System.Drawing.Point(0, 0); + this.listGroups.Name = "listGroups"; + this.listGroups.ShowItemToolTips = true; + this.listGroups.Size = new System.Drawing.Size(431, 397); + this.listGroups.Sorting = System.Windows.Forms.SortOrder.Ascending; + this.listGroups.TabIndex = 4; + this.listGroups.UseCompatibleStateImageBehavior = false; + this.listGroups.View = System.Windows.Forms.View.Details; + // + // columnGroupName + // + this.columnGroupName.Text = "Name"; + this.columnGroupName.Width = 200; + // + // columnFlags + // + this.columnFlags.Text = "Flags"; + this.columnFlags.Width = 180; + // + // TokenGroups + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.listGroups); + this.Name = "TokenGroups"; + this.Size = new System.Drawing.Size(431, 397); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.ListView listGroups; + private System.Windows.Forms.ColumnHeader columnGroupName; + private System.Windows.Forms.ColumnHeader columnFlags; + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/TokenGroupsList.cs b/branches/ph-plugins/ProcessHacker/Components/TokenGroupsList.cs new file mode 100644 index 000000000..e2d53fbf6 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/TokenGroupsList.cs @@ -0,0 +1,108 @@ +/* + * Process Hacker - + * token groups viewer + * + * Copyright (C) 2008-2009 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 . + */ + +using System.Drawing; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Common.Ui; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Security; +using ProcessHacker.UI; + +namespace ProcessHacker.Components +{ + public partial class TokenGroupsList : UserControl + { + public TokenGroupsList(Sid[] groups) + { + InitializeComponent(); + + for (int i = 0; i < groups.Length; i++) + { + ListViewItem item = listGroups.Items.Add(new ListViewItem()); + + item.Text = groups[i].GetFullName(Properties.Settings.Default.ShowAccountDomains); + item.BackColor = GetAttributeColor(groups[i].Attributes); + item.SubItems.Add(new ListViewItem.ListViewSubItem(item, GetAttributeString(groups[i].Attributes))); + } + + listGroups.ListViewItemSorter = new SortedListViewComparer(listGroups); + listGroups.SetDoubleBuffered(true); + listGroups.ContextMenu = listGroups.GetCopyMenu(); + ColumnSettings.LoadSettings(Properties.Settings.Default.GroupListColumns, listGroups); + listGroups.AddShortcuts(); + } + + public void SaveSettings() + { + Properties.Settings.Default.GroupListColumns = ColumnSettings.SaveSettings(listGroups); + } + + private string GetAttributeString(SidAttributes Attributes) + { + string text = ""; + + if ((Attributes & SidAttributes.Integrity) != 0) + { + if ((Attributes & SidAttributes.IntegrityEnabled) != 0) + return "Integrity"; + else + return "Integrity (Disabled)"; + } + else if ((Attributes & SidAttributes.LogonId) != 0) + text = "Logon ID"; + else if ((Attributes & SidAttributes.Mandatory) != 0) + text = "Mandatory"; + else if ((Attributes & SidAttributes.Owner) != 0) + text = "Owner"; + else if ((Attributes & SidAttributes.Resource) != 0) + text = "Resource"; + else if ((Attributes & SidAttributes.UseForDenyOnly) != 0) + text = "Use for Deny Only"; + + if ((Attributes & SidAttributes.EnabledByDefault) != 0) + return text + " (Default Enabled)"; + else if ((Attributes & SidAttributes.Enabled) != 0) + return text; + else + return text + " (Disabled)"; + } + + private Color GetAttributeColor(SidAttributes Attributes) + { + if ((Attributes & SidAttributes.Integrity) != 0) + { + if ((Attributes & SidAttributes.IntegrityEnabled) == 0) + return Color.FromArgb(0xe0e0e0); + else + return Color.White; + } + + if ((Attributes & SidAttributes.EnabledByDefault) != 0) + return Color.FromArgb(0xe0f0e0); + else if ((Attributes & SidAttributes.Enabled) != 0) + return Color.White; + else + return Color.FromArgb(0xf0e0e0); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/TokenGroupsList.resx b/branches/ph-plugins/ProcessHacker/Components/TokenGroupsList.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/TokenGroupsList.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/TokenProperties.Designer.cs b/branches/ph-plugins/ProcessHacker/Components/TokenProperties.Designer.cs new file mode 100644 index 000000000..1684643a8 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/TokenProperties.Designer.cs @@ -0,0 +1,659 @@ +namespace ProcessHacker.Components +{ + partial class TokenProperties + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + if (_groups != null) + _groups.Dispose(); + + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.tabControl = new System.Windows.Forms.TabControl(); + this.tabGeneral = new System.Windows.Forms.TabPage(); + this.groupSource = new System.Windows.Forms.GroupBox(); + this.label7 = new System.Windows.Forms.Label(); + this.label6 = new System.Windows.Forms.Label(); + this.textSourceName = new System.Windows.Forms.TextBox(); + this.textSourceLUID = new System.Windows.Forms.TextBox(); + this.groupToken = new System.Windows.Forms.GroupBox(); + this.label9 = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.buttonLinkedToken = new System.Windows.Forms.Button(); + this.textPrimaryGroup = new System.Windows.Forms.TextBox(); + this.textUser = new System.Windows.Forms.TextBox(); + this.textElevated = new System.Windows.Forms.TextBox(); + this.label8 = new System.Windows.Forms.Label(); + this.textOwner = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.textVirtualized = new System.Windows.Forms.TextBox(); + this.textSessionID = new System.Windows.Forms.TextBox(); + this.labelVirtualization = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.labelElevated = new System.Windows.Forms.Label(); + this.textUserSID = new System.Windows.Forms.TextBox(); + this.tabAdvanced = new System.Windows.Forms.TabPage(); + this.textMemoryAvailable = new System.Windows.Forms.TextBox(); + this.textMemoryUsed = new System.Windows.Forms.TextBox(); + this.textAuthenticationId = new System.Windows.Forms.TextBox(); + this.textTokenId = new System.Windows.Forms.TextBox(); + this.textImpersonationLevel = new System.Windows.Forms.TextBox(); + this.textTokenType = new System.Windows.Forms.TextBox(); + this.label13 = new System.Windows.Forms.Label(); + this.label12 = new System.Windows.Forms.Label(); + this.label11 = new System.Windows.Forms.Label(); + this.label10 = new System.Windows.Forms.Label(); + this.label5 = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.tabGroups = new System.Windows.Forms.TabPage(); + this.tabPrivileges = new System.Windows.Forms.TabPage(); + this.listPrivileges = new System.Windows.Forms.ListView(); + this.columnName = new System.Windows.Forms.ColumnHeader(); + this.columnStatus = new System.Windows.Forms.ColumnHeader(); + this.columnDesc = new System.Windows.Forms.ColumnHeader(); + this.enableMenuItem = new System.Windows.Forms.MenuItem(); + this.disableMenuItem = new System.Windows.Forms.MenuItem(); + this.removeMenuItem = new System.Windows.Forms.MenuItem(); + this.copyMenuItem = new System.Windows.Forms.MenuItem(); + this.menuPrivileges = new System.Windows.Forms.ContextMenu(); + this.menuItem2 = new System.Windows.Forms.MenuItem(); + this.selectAllMenuItem = new System.Windows.Forms.MenuItem(); + this.vistaMenu = new wyDay.Controls.VistaMenu(this.components); + this.buttonPermissions = new System.Windows.Forms.Button(); + this.tabControl.SuspendLayout(); + this.tabGeneral.SuspendLayout(); + this.groupSource.SuspendLayout(); + this.groupToken.SuspendLayout(); + this.tabAdvanced.SuspendLayout(); + this.tabPrivileges.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.vistaMenu)).BeginInit(); + this.SuspendLayout(); + // + // tabControl + // + this.tabControl.Controls.Add(this.tabGeneral); + this.tabControl.Controls.Add(this.tabAdvanced); + this.tabControl.Controls.Add(this.tabGroups); + this.tabControl.Controls.Add(this.tabPrivileges); + this.tabControl.Dock = System.Windows.Forms.DockStyle.Fill; + this.tabControl.Location = new System.Drawing.Point(0, 0); + this.tabControl.Name = "tabControl"; + this.tabControl.SelectedIndex = 0; + this.tabControl.Size = new System.Drawing.Size(575, 433); + this.tabControl.TabIndex = 3; + // + // tabGeneral + // + this.tabGeneral.AutoScroll = true; + this.tabGeneral.Controls.Add(this.groupSource); + this.tabGeneral.Controls.Add(this.groupToken); + this.tabGeneral.Location = new System.Drawing.Point(4, 22); + this.tabGeneral.Name = "tabGeneral"; + this.tabGeneral.Padding = new System.Windows.Forms.Padding(3, 5, 3, 3); + this.tabGeneral.Size = new System.Drawing.Size(567, 407); + this.tabGeneral.TabIndex = 2; + this.tabGeneral.Text = "General"; + this.tabGeneral.UseVisualStyleBackColor = true; + // + // groupSource + // + this.groupSource.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupSource.Controls.Add(this.label7); + this.groupSource.Controls.Add(this.label6); + this.groupSource.Controls.Add(this.textSourceName); + this.groupSource.Controls.Add(this.textSourceLUID); + this.groupSource.Location = new System.Drawing.Point(6, 247); + this.groupSource.Name = "groupSource"; + this.groupSource.Size = new System.Drawing.Size(555, 75); + this.groupSource.TabIndex = 15; + this.groupSource.TabStop = false; + this.groupSource.Text = "Source"; + // + // label7 + // + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(6, 48); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(35, 13); + this.label7.TabIndex = 3; + this.label7.Text = "LUID:"; + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(6, 22); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(38, 13); + this.label6.TabIndex = 2; + this.label6.Text = "Name:"; + // + // textSourceName + // + this.textSourceName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textSourceName.Location = new System.Drawing.Point(73, 19); + this.textSourceName.Name = "textSourceName"; + this.textSourceName.ReadOnly = true; + this.textSourceName.Size = new System.Drawing.Size(476, 20); + this.textSourceName.TabIndex = 1; + // + // textSourceLUID + // + this.textSourceLUID.Location = new System.Drawing.Point(73, 45); + this.textSourceLUID.Name = "textSourceLUID"; + this.textSourceLUID.ReadOnly = true; + this.textSourceLUID.Size = new System.Drawing.Size(109, 20); + this.textSourceLUID.TabIndex = 4; + // + // groupToken + // + this.groupToken.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupToken.Controls.Add(this.buttonPermissions); + this.groupToken.Controls.Add(this.label9); + this.groupToken.Controls.Add(this.label1); + this.groupToken.Controls.Add(this.buttonLinkedToken); + this.groupToken.Controls.Add(this.textPrimaryGroup); + this.groupToken.Controls.Add(this.textUser); + this.groupToken.Controls.Add(this.textElevated); + this.groupToken.Controls.Add(this.label8); + this.groupToken.Controls.Add(this.textOwner); + this.groupToken.Controls.Add(this.label2); + this.groupToken.Controls.Add(this.textVirtualized); + this.groupToken.Controls.Add(this.textSessionID); + this.groupToken.Controls.Add(this.labelVirtualization); + this.groupToken.Controls.Add(this.label3); + this.groupToken.Controls.Add(this.labelElevated); + this.groupToken.Controls.Add(this.textUserSID); + this.groupToken.Location = new System.Drawing.Point(6, 8); + this.groupToken.Name = "groupToken"; + this.groupToken.Size = new System.Drawing.Size(555, 233); + this.groupToken.TabIndex = 14; + this.groupToken.TabStop = false; + this.groupToken.Text = "Token"; + // + // label9 + // + this.label9.AutoSize = true; + this.label9.Location = new System.Drawing.Point(6, 100); + this.label9.Name = "label9"; + this.label9.Size = new System.Drawing.Size(76, 13); + this.label9.TabIndex = 17; + this.label9.Text = "Primary Group:"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(6, 22); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(32, 13); + this.label1.TabIndex = 2; + this.label1.Text = "User:"; + // + // buttonLinkedToken + // + this.buttonLinkedToken.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonLinkedToken.Location = new System.Drawing.Point(203, 147); + this.buttonLinkedToken.Name = "buttonLinkedToken"; + this.buttonLinkedToken.Size = new System.Drawing.Size(105, 23); + this.buttonLinkedToken.TabIndex = 13; + this.buttonLinkedToken.Text = "Linked Token..."; + this.buttonLinkedToken.UseVisualStyleBackColor = true; + this.buttonLinkedToken.Click += new System.EventHandler(this.buttonLinkedToken_Click); + // + // textPrimaryGroup + // + this.textPrimaryGroup.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textPrimaryGroup.Location = new System.Drawing.Point(88, 97); + this.textPrimaryGroup.Name = "textPrimaryGroup"; + this.textPrimaryGroup.ReadOnly = true; + this.textPrimaryGroup.Size = new System.Drawing.Size(461, 20); + this.textPrimaryGroup.TabIndex = 16; + // + // textUser + // + this.textUser.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textUser.Location = new System.Drawing.Point(88, 19); + this.textUser.Name = "textUser"; + this.textUser.ReadOnly = true; + this.textUser.Size = new System.Drawing.Size(461, 20); + this.textUser.TabIndex = 1; + // + // textElevated + // + this.textElevated.Location = new System.Drawing.Point(88, 149); + this.textElevated.Name = "textElevated"; + this.textElevated.ReadOnly = true; + this.textElevated.Size = new System.Drawing.Size(109, 20); + this.textElevated.TabIndex = 12; + // + // label8 + // + this.label8.AutoSize = true; + this.label8.Location = new System.Drawing.Point(6, 74); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(41, 13); + this.label8.TabIndex = 15; + this.label8.Text = "Owner:"; + // + // textOwner + // + this.textOwner.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textOwner.Location = new System.Drawing.Point(88, 71); + this.textOwner.Name = "textOwner"; + this.textOwner.ReadOnly = true; + this.textOwner.Size = new System.Drawing.Size(461, 20); + this.textOwner.TabIndex = 14; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(6, 126); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(61, 13); + this.label2.TabIndex = 3; + this.label2.Text = "Session ID:"; + // + // textVirtualized + // + this.textVirtualized.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textVirtualized.Location = new System.Drawing.Point(88, 175); + this.textVirtualized.Name = "textVirtualized"; + this.textVirtualized.ReadOnly = true; + this.textVirtualized.Size = new System.Drawing.Size(461, 20); + this.textVirtualized.TabIndex = 11; + // + // textSessionID + // + this.textSessionID.Location = new System.Drawing.Point(88, 123); + this.textSessionID.Name = "textSessionID"; + this.textSessionID.ReadOnly = true; + this.textSessionID.Size = new System.Drawing.Size(109, 20); + this.textSessionID.TabIndex = 4; + // + // labelVirtualization + // + this.labelVirtualization.AutoSize = true; + this.labelVirtualization.Location = new System.Drawing.Point(6, 178); + this.labelVirtualization.Name = "labelVirtualization"; + this.labelVirtualization.Size = new System.Drawing.Size(69, 13); + this.labelVirtualization.TabIndex = 8; + this.labelVirtualization.Text = "Virtualization:"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(6, 48); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(53, 13); + this.label3.TabIndex = 5; + this.label3.Text = "User SID:"; + // + // labelElevated + // + this.labelElevated.AutoSize = true; + this.labelElevated.Location = new System.Drawing.Point(6, 152); + this.labelElevated.Name = "labelElevated"; + this.labelElevated.Size = new System.Drawing.Size(52, 13); + this.labelElevated.TabIndex = 7; + this.labelElevated.Text = "Elevated:"; + // + // textUserSID + // + this.textUserSID.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textUserSID.Location = new System.Drawing.Point(88, 45); + this.textUserSID.Name = "textUserSID"; + this.textUserSID.ReadOnly = true; + this.textUserSID.Size = new System.Drawing.Size(461, 20); + this.textUserSID.TabIndex = 6; + // + // tabAdvanced + // + this.tabAdvanced.Controls.Add(this.textMemoryAvailable); + this.tabAdvanced.Controls.Add(this.textMemoryUsed); + this.tabAdvanced.Controls.Add(this.textAuthenticationId); + this.tabAdvanced.Controls.Add(this.textTokenId); + this.tabAdvanced.Controls.Add(this.textImpersonationLevel); + this.tabAdvanced.Controls.Add(this.textTokenType); + this.tabAdvanced.Controls.Add(this.label13); + this.tabAdvanced.Controls.Add(this.label12); + this.tabAdvanced.Controls.Add(this.label11); + this.tabAdvanced.Controls.Add(this.label10); + this.tabAdvanced.Controls.Add(this.label5); + this.tabAdvanced.Controls.Add(this.label4); + this.tabAdvanced.Location = new System.Drawing.Point(4, 22); + this.tabAdvanced.Name = "tabAdvanced"; + this.tabAdvanced.Padding = new System.Windows.Forms.Padding(3); + this.tabAdvanced.Size = new System.Drawing.Size(567, 407); + this.tabAdvanced.TabIndex = 3; + this.tabAdvanced.Text = "Advanced"; + this.tabAdvanced.UseVisualStyleBackColor = true; + // + // textMemoryAvailable + // + this.textMemoryAvailable.Location = new System.Drawing.Point(118, 136); + this.textMemoryAvailable.Name = "textMemoryAvailable"; + this.textMemoryAvailable.ReadOnly = true; + this.textMemoryAvailable.Size = new System.Drawing.Size(191, 20); + this.textMemoryAvailable.TabIndex = 1; + // + // textMemoryUsed + // + this.textMemoryUsed.Location = new System.Drawing.Point(118, 110); + this.textMemoryUsed.Name = "textMemoryUsed"; + this.textMemoryUsed.ReadOnly = true; + this.textMemoryUsed.Size = new System.Drawing.Size(191, 20); + this.textMemoryUsed.TabIndex = 1; + // + // textAuthenticationId + // + this.textAuthenticationId.Location = new System.Drawing.Point(118, 84); + this.textAuthenticationId.Name = "textAuthenticationId"; + this.textAuthenticationId.ReadOnly = true; + this.textAuthenticationId.Size = new System.Drawing.Size(191, 20); + this.textAuthenticationId.TabIndex = 1; + // + // textTokenId + // + this.textTokenId.Location = new System.Drawing.Point(118, 58); + this.textTokenId.Name = "textTokenId"; + this.textTokenId.ReadOnly = true; + this.textTokenId.Size = new System.Drawing.Size(191, 20); + this.textTokenId.TabIndex = 1; + // + // textImpersonationLevel + // + this.textImpersonationLevel.Location = new System.Drawing.Point(118, 32); + this.textImpersonationLevel.Name = "textImpersonationLevel"; + this.textImpersonationLevel.ReadOnly = true; + this.textImpersonationLevel.Size = new System.Drawing.Size(191, 20); + this.textImpersonationLevel.TabIndex = 1; + // + // textTokenType + // + this.textTokenType.Location = new System.Drawing.Point(118, 6); + this.textTokenType.Name = "textTokenType"; + this.textTokenType.ReadOnly = true; + this.textTokenType.Size = new System.Drawing.Size(191, 20); + this.textTokenType.TabIndex = 1; + // + // label13 + // + this.label13.AutoSize = true; + this.label13.Location = new System.Drawing.Point(6, 139); + this.label13.Name = "label13"; + this.label13.Size = new System.Drawing.Size(93, 13); + this.label13.TabIndex = 0; + this.label13.Text = "Memory Available:"; + // + // label12 + // + this.label12.AutoSize = true; + this.label12.Location = new System.Drawing.Point(6, 113); + this.label12.Name = "label12"; + this.label12.Size = new System.Drawing.Size(75, 13); + this.label12.TabIndex = 0; + this.label12.Text = "Memory Used:"; + // + // label11 + // + this.label11.AutoSize = true; + this.label11.Location = new System.Drawing.Point(6, 87); + this.label11.Name = "label11"; + this.label11.Size = new System.Drawing.Size(106, 13); + this.label11.TabIndex = 0; + this.label11.Text = "Authentication LUID:"; + // + // label10 + // + this.label10.AutoSize = true; + this.label10.Location = new System.Drawing.Point(6, 61); + this.label10.Name = "label10"; + this.label10.Size = new System.Drawing.Size(69, 13); + this.label10.TabIndex = 0; + this.label10.Text = "Token LUID:"; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(6, 35); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(105, 13); + this.label5.TabIndex = 0; + this.label5.Text = "Impersonation Level:"; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(6, 9); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(34, 13); + this.label4.TabIndex = 0; + this.label4.Text = "Type:"; + // + // tabGroups + // + this.tabGroups.Location = new System.Drawing.Point(4, 22); + this.tabGroups.Name = "tabGroups"; + this.tabGroups.Padding = new System.Windows.Forms.Padding(3); + this.tabGroups.Size = new System.Drawing.Size(567, 407); + this.tabGroups.TabIndex = 1; + this.tabGroups.Text = "Groups"; + this.tabGroups.UseVisualStyleBackColor = true; + // + // tabPrivileges + // + this.tabPrivileges.Controls.Add(this.listPrivileges); + this.tabPrivileges.Location = new System.Drawing.Point(4, 22); + this.tabPrivileges.Name = "tabPrivileges"; + this.tabPrivileges.Padding = new System.Windows.Forms.Padding(3); + this.tabPrivileges.Size = new System.Drawing.Size(567, 407); + this.tabPrivileges.TabIndex = 0; + this.tabPrivileges.Text = "Privileges"; + this.tabPrivileges.UseVisualStyleBackColor = true; + // + // listPrivileges + // + this.listPrivileges.AllowColumnReorder = true; + this.listPrivileges.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnName, + this.columnStatus, + this.columnDesc}); + this.listPrivileges.Dock = System.Windows.Forms.DockStyle.Fill; + this.listPrivileges.FullRowSelect = true; + this.listPrivileges.Location = new System.Drawing.Point(3, 3); + this.listPrivileges.Name = "listPrivileges"; + this.listPrivileges.ShowItemToolTips = true; + this.listPrivileges.Size = new System.Drawing.Size(561, 401); + this.listPrivileges.Sorting = System.Windows.Forms.SortOrder.Ascending; + this.listPrivileges.TabIndex = 0; + this.listPrivileges.UseCompatibleStateImageBehavior = false; + this.listPrivileges.View = System.Windows.Forms.View.Details; + // + // columnName + // + this.columnName.Text = "Name"; + this.columnName.Width = 100; + // + // columnStatus + // + this.columnStatus.Text = "Status"; + this.columnStatus.Width = 120; + // + // columnDesc + // + this.columnDesc.Text = "Description"; + this.columnDesc.Width = 190; + // + // enableMenuItem + // + this.vistaMenu.SetImage(this.enableMenuItem, global::ProcessHacker.Properties.Resources.tick); + this.enableMenuItem.Index = 0; + this.enableMenuItem.Text = "&Enable"; + this.enableMenuItem.Click += new System.EventHandler(this.enableMenuItem_Click); + // + // disableMenuItem + // + this.vistaMenu.SetImage(this.disableMenuItem, global::ProcessHacker.Properties.Resources.cross); + this.disableMenuItem.Index = 1; + this.disableMenuItem.Text = "&Disable"; + this.disableMenuItem.Click += new System.EventHandler(this.disableMenuItem_Click); + // + // removeMenuItem + // + this.vistaMenu.SetImage(this.removeMenuItem, global::ProcessHacker.Properties.Resources.delete); + this.removeMenuItem.Index = 2; + this.removeMenuItem.Text = "&Remove"; + this.removeMenuItem.Click += new System.EventHandler(this.removeMenuItem_Click); + // + // copyMenuItem + // + this.vistaMenu.SetImage(this.copyMenuItem, global::ProcessHacker.Properties.Resources.page_copy); + this.copyMenuItem.Index = 4; + this.copyMenuItem.Text = "&Copy"; + // + // menuPrivileges + // + this.menuPrivileges.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.enableMenuItem, + this.disableMenuItem, + this.removeMenuItem, + this.menuItem2, + this.copyMenuItem, + this.selectAllMenuItem}); + this.menuPrivileges.Popup += new System.EventHandler(this.menuPrivileges_Popup); + // + // menuItem2 + // + this.menuItem2.Index = 3; + this.menuItem2.Text = "-"; + // + // selectAllMenuItem + // + this.selectAllMenuItem.Index = 5; + this.selectAllMenuItem.Text = "Select &All"; + this.selectAllMenuItem.Click += new System.EventHandler(this.selectAllMenuItem_Click); + // + // vistaMenu + // + this.vistaMenu.ContainerControl = this; + this.vistaMenu.DelaySetImageCalls = false; + // + // buttonPermissions + // + this.buttonPermissions.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonPermissions.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonPermissions.Location = new System.Drawing.Point(474, 201); + this.buttonPermissions.Name = "buttonPermissions"; + this.buttonPermissions.Size = new System.Drawing.Size(75, 23); + this.buttonPermissions.TabIndex = 18; + this.buttonPermissions.Text = "Permissions"; + this.buttonPermissions.UseVisualStyleBackColor = true; + this.buttonPermissions.Click += new System.EventHandler(this.buttonPermissions_Click); + // + // TokenProperties + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.tabControl); + this.Name = "TokenProperties"; + this.Size = new System.Drawing.Size(575, 433); + this.tabControl.ResumeLayout(false); + this.tabGeneral.ResumeLayout(false); + this.groupSource.ResumeLayout(false); + this.groupSource.PerformLayout(); + this.groupToken.ResumeLayout(false); + this.groupToken.PerformLayout(); + this.tabAdvanced.ResumeLayout(false); + this.tabAdvanced.PerformLayout(); + this.tabPrivileges.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.vistaMenu)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TabControl tabControl; + private System.Windows.Forms.TabPage tabGeneral; + private System.Windows.Forms.TextBox textSessionID; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox textUser; + private System.Windows.Forms.TabPage tabGroups; + private System.Windows.Forms.TabPage tabPrivileges; + private System.Windows.Forms.ListView listPrivileges; + private System.Windows.Forms.ColumnHeader columnName; + private System.Windows.Forms.ColumnHeader columnStatus; + private System.Windows.Forms.ColumnHeader columnDesc; + private wyDay.Controls.VistaMenu vistaMenu; + private System.Windows.Forms.MenuItem enableMenuItem; + private System.Windows.Forms.MenuItem disableMenuItem; + private System.Windows.Forms.MenuItem removeMenuItem; + private System.Windows.Forms.MenuItem copyMenuItem; + private System.Windows.Forms.ContextMenu menuPrivileges; + private System.Windows.Forms.MenuItem menuItem2; + private System.Windows.Forms.MenuItem selectAllMenuItem; + private System.Windows.Forms.TextBox textUserSID; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.TextBox textElevated; + private System.Windows.Forms.TextBox textVirtualized; + private System.Windows.Forms.Label labelVirtualization; + private System.Windows.Forms.Label labelElevated; + private System.Windows.Forms.Button buttonLinkedToken; + private System.Windows.Forms.GroupBox groupSource; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.TextBox textSourceName; + private System.Windows.Forms.TextBox textSourceLUID; + private System.Windows.Forms.GroupBox groupToken; + private System.Windows.Forms.Label label9; + private System.Windows.Forms.TextBox textPrimaryGroup; + private System.Windows.Forms.Label label8; + private System.Windows.Forms.TextBox textOwner; + private System.Windows.Forms.TabPage tabAdvanced; + private System.Windows.Forms.TextBox textTokenId; + private System.Windows.Forms.TextBox textImpersonationLevel; + private System.Windows.Forms.TextBox textTokenType; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.TextBox textMemoryAvailable; + private System.Windows.Forms.TextBox textMemoryUsed; + private System.Windows.Forms.TextBox textAuthenticationId; + private System.Windows.Forms.Label label10; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.Label label13; + private System.Windows.Forms.Label label12; + private System.Windows.Forms.Label label11; + private System.Windows.Forms.Button buttonPermissions; + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/TokenProperties.cs b/branches/ph-plugins/ProcessHacker/Components/TokenProperties.cs new file mode 100644 index 000000000..62a5d223a --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/TokenProperties.cs @@ -0,0 +1,412 @@ +/* + * Process Hacker - + * token properties viewer + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Drawing; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Common.Ui; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; +using ProcessHacker.Native.Security.AccessControl; +using ProcessHacker.UI; + +namespace ProcessHacker.Components +{ + public partial class TokenProperties : UserControl + { + private IWithToken _object; + private TokenGroupsList _groups; + + public TokenProperties(IWithToken obj) + { + InitializeComponent(); + + _object = obj; + + listPrivileges.SetDoubleBuffered(true); + listPrivileges.ListViewItemSorter = new SortedListViewComparer(listPrivileges); + GenericViewMenu.AddMenuItems(copyMenuItem.MenuItems, listPrivileges, null); + listPrivileges.ContextMenu = menuPrivileges; + + _object = obj; + + try + { + using (TokenHandle thandle = _object.GetToken(TokenAccess.Query)) + { + // "General" + try + { + textUser.Text = thandle.GetUser().GetFullName(true); + textUserSID.Text = thandle.GetUser().StringSid; + textOwner.Text = thandle.GetOwner().GetFullName(true); + textPrimaryGroup.Text = thandle.GetPrimaryGroup().GetFullName(true); + } + catch (Exception ex) + { + textUser.Text = "(" + ex.Message + ")"; + } + + try + { + textSessionID.Text = thandle.GetSessionId().ToString(); + } + catch (Exception ex) + { + textSessionID.Text = "(" + ex.Message + ")"; + } + + try + { + var type = thandle.GetElevationType(); + + if (type == TokenElevationType.Default) + textElevated.Text = "N/A"; + else if (type == TokenElevationType.Full) + textElevated.Text = "True"; + else if (type == TokenElevationType.Limited) + textElevated.Text = "False"; + } + catch (Exception ex) + { + textElevated.Text = "(" + ex.Message + ")"; + } + + try + { + TokenWithLinkedToken tokWLT = new TokenWithLinkedToken(thandle); + + tokWLT.GetToken().Dispose(); + } + catch + { + buttonLinkedToken.Visible = false; + } + + try + { + bool virtAllowed = thandle.IsVirtualizationAllowed(); + bool virtEnabled = thandle.IsVirtualizationEnabled(); + + if (virtEnabled) + textVirtualized.Text = "Enabled"; + else if (virtAllowed) + textVirtualized.Text = "Disabled"; + else + textVirtualized.Text = "Not Allowed"; + } + catch (Exception ex) + { + textVirtualized.Text = "(" + ex.Message + ")"; + } + + try + { + using (TokenHandle tokenSource = _object.GetToken(TokenAccess.QuerySource)) + { + var source = tokenSource.GetSource(); + + textSourceName.Text = source.SourceName.TrimEnd('\0', '\r', '\n', ' '); + + long luid = source.SourceIdentifier.QuadPart; + + textSourceLUID.Text = "0x" + luid.ToString("x"); + } + } + catch (Exception ex) + { + textSourceName.Text = "(" + ex.Message + ")"; + } + + // "Advanced" + try + { + var statistics = thandle.GetStatistics(); + + textTokenType.Text = statistics.TokenType.ToString(); + textImpersonationLevel.Text = statistics.ImpersonationLevel.ToString(); + textTokenId.Text = "0x" + statistics.TokenId.ToString(); + textAuthenticationId.Text = "0x" + statistics.AuthenticationId.ToString(); + textMemoryUsed.Text = Utils.FormatSize(statistics.DynamicCharged); + textMemoryAvailable.Text = Utils.FormatSize(statistics.DynamicAvailable); + } + catch (Exception ex) + { + textTokenType.Text = "(" + ex.Message + ")"; + } + + try + { + var groups = thandle.GetGroups(); + + _groups = new TokenGroupsList(groups); + + foreach (var group in groups) + group.Dispose(); + + _groups.Dock = DockStyle.Fill; + tabGroups.Controls.Add(_groups); + } + catch (Exception ex) + { + tabGroups.Text = "(" + ex.Message + ")"; + } + + try + { + var privileges = thandle.GetPrivileges(); + + for (int i = 0; i < privileges.Length; i++) + { + var privilege = privileges[i]; + + ListViewItem item = listPrivileges.Items.Add(privilege.Name.ToLower(), privilege.Name, 0); + + item.BackColor = GetAttributeColor(privilege.Attributes); + item.SubItems.Add(new ListViewItem.ListViewSubItem(item, GetAttributeString(privilege.Attributes))); + item.SubItems.Add(new ListViewItem.ListViewSubItem(item, privilege.DisplayName)); + } + } + catch (Exception ex) + { + tabPrivileges.Text = "(" + ex.Message + ")"; + } + } + } + catch (Exception ex) + { + tabControl.Visible = false; + + Label errorMessage = new Label(); + + errorMessage.Text = ex.Message; + + this.Padding = new Padding(15, 10, 0, 0); + this.Controls.Add(errorMessage); + } + + if (!OSVersion.HasUac) + { + labelElevated.Enabled = false; + textElevated.Enabled = false; + textElevated.Text = ""; + labelVirtualization.Enabled = false; + textVirtualized.Enabled = false; + textVirtualized.Text = ""; + } + + if (tabControl.TabPages[Properties.Settings.Default.TokenWindowTab] != null) + tabControl.SelectedTab = tabControl.TabPages[Properties.Settings.Default.TokenWindowTab]; + + ColumnSettings.LoadSettings(Properties.Settings.Default.PrivilegeListColumns, listPrivileges); + listPrivileges.AddShortcuts(); + } + + public IWithToken Object + { + get { return _object; } + } + + public void SaveSettings() + { + if (_groups != null) + _groups.SaveSettings(); + + Properties.Settings.Default.TokenWindowTab = tabControl.SelectedTab.Name; + Properties.Settings.Default.PrivilegeListColumns = ColumnSettings.SaveSettings(listPrivileges); + } + + private string GetAttributeString(SePrivilegeAttributes Attributes) + { + if ((Attributes & SePrivilegeAttributes.EnabledByDefault) != 0) + return "Default Enabled"; + else if ((Attributes & SePrivilegeAttributes.Enabled) != 0) + return "Enabled"; + else if (Attributes == SePrivilegeAttributes.Disabled) + return "Disabled"; + else + return "Unknown"; + } + + private Color GetAttributeColor(SePrivilegeAttributes Attributes) + { + if ((Attributes & SePrivilegeAttributes.EnabledByDefault) != 0) + return Color.FromArgb(0xc0f0c0); + else if ((Attributes & SePrivilegeAttributes.Enabled) != 0) + return Color.FromArgb(0xe0f0e0); + else if (Attributes == SePrivilegeAttributes.Disabled) + return Color.FromArgb(0xf0e0e0); + else + return Color.White; + } + + private void menuPrivileges_Popup(object sender, EventArgs e) + { + if (listPrivileges.SelectedItems.Count == 0) + { + menuPrivileges.DisableAll(); + } + else + { + menuPrivileges.EnableAll(); + } + + if (listPrivileges.Items.Count > 0) + { + selectAllMenuItem.Enabled = true; + } + else + { + selectAllMenuItem.Enabled = false; + } + } + + private void enableMenuItem_Click(object sender, EventArgs e) + { + foreach (ListViewItem item in listPrivileges.SelectedItems) + { + try + { + using (var thandle = _object.GetToken(TokenAccess.AdjustPrivileges)) + thandle.SetPrivilege(item.Text, SePrivilegeAttributes.Enabled); + + if (item.SubItems[1].Text != "Default Enabled") + { + item.BackColor = GetAttributeColor(SePrivilegeAttributes.Enabled); + item.SubItems[1].Text = GetAttributeString(SePrivilegeAttributes.Enabled); + } + } + catch (Exception ex) + { + if (!PhUtils.ShowContinueMessage( + "Unable to enable " + item.Text, + ex + )) + return; + } + } + } + + private void disableMenuItem_Click(object sender, EventArgs e) + { + foreach (ListViewItem item in listPrivileges.SelectedItems) + { + if (item.SubItems[1].Text == "Default Enabled") + { + if (!PhUtils.ShowContinueMessage( + "Unable to disable " + item.Text, + new Exception("Invalid operation.") + )) + return; + + continue; + } + + try + { + using (var thandle = _object.GetToken(TokenAccess.AdjustPrivileges)) + thandle.SetPrivilege(item.Text, SePrivilegeAttributes.Disabled); + + item.BackColor = GetAttributeColor(SePrivilegeAttributes.Disabled); + item.SubItems[1].Text = GetAttributeString(SePrivilegeAttributes.Disabled); + } + catch (Exception ex) + { + if (!PhUtils.ShowContinueMessage( + "Unable to disable " + item.Text, + ex + )) + return; + } + } + } + + private void removeMenuItem_Click(object sender, EventArgs e) + { + if (PhUtils.ShowConfirmMessage( + "remove", + "the selected privilege(s)", + "Removing privileges may reduce the functionality of the process, " + + "and is permanent for the lifetime of the process.", + false + )) + { + foreach (ListViewItem item in listPrivileges.SelectedItems) + { + try + { + using (var thandle = _object.GetToken(TokenAccess.AdjustPrivileges)) + thandle.SetPrivilege(item.Text, SePrivilegeAttributes.Removed); + + item.Remove(); + } + catch (Exception ex) + { + if (!PhUtils.ShowContinueMessage( + "Unable to remove " + item.Text, + ex + )) + return; + } + } + } + } + + private void selectAllMenuItem_Click(object sender, EventArgs e) + { + Utils.SelectAll(listPrivileges.Items); + } + + private void buttonLinkedToken_Click(object sender, EventArgs e) + { + using (var thandle = _object.GetToken(TokenAccess.Query)) + { + var token = new TokenWithLinkedToken(thandle); + TokenWindow window = new TokenWindow(token); + + window.ShowDialog(); + } + } + + private void buttonPermissions_Click(object sender, EventArgs e) + { + try + { + SecurityEditor.EditSecurity( + this, + SecurityEditor.GetSecurable( + NativeTypeFactory.ObjectType.Token, + (access) => _object.GetToken((TokenAccess)access)), + "Token", + NativeTypeFactory.GetAccessEntries(NativeTypeFactory.ObjectType.Token) + ); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to edit security", ex); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/TokenProperties.resx b/branches/ph-plugins/ProcessHacker/Components/TokenProperties.resx new file mode 100644 index 000000000..0bae7478e --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/TokenProperties.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 125, 17 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/UtilitiesButton.Designer.cs b/branches/ph-plugins/ProcessHacker/Components/UtilitiesButton.Designer.cs new file mode 100644 index 000000000..01f412b00 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/UtilitiesButton.Designer.cs @@ -0,0 +1,240 @@ +namespace ProcessHacker.Components +{ + partial class UtilitiesButton + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.buttonUtilities = new System.Windows.Forms.Button(); + this.menuUtilities = new System.Windows.Forms.ContextMenu(); + this.insertNumberMenuItem = new System.Windows.Forms.MenuItem(); + this.bitMenuItem = new System.Windows.Forms.MenuItem(); + this.bitLittleEndianMenuItem = new System.Windows.Forms.MenuItem(); + this.bitBigEndianMenuItem = new System.Windows.Forms.MenuItem(); + this.bitLittleEndianMenuItem1 = new System.Windows.Forms.MenuItem(); + this.bitBigEndianMenuItem1 = new System.Windows.Forms.MenuItem(); + this.bitLittleEndianMenuItem2 = new System.Windows.Forms.MenuItem(); + this.bitBigEndianMenuItem2 = new System.Windows.Forms.MenuItem(); + this.insertStringMenuItem = new System.Windows.Forms.MenuItem(); + this.aSCIIMenuItem = new System.Windows.Forms.MenuItem(); + this.uTF8MenuItem = new System.Windows.Forms.MenuItem(); + this.uTF16MenuItem = new System.Windows.Forms.MenuItem(); + this.uTF16BigEndianMenuItem = new System.Windows.Forms.MenuItem(); + this.uTF32MenuItem = new System.Windows.Forms.MenuItem(); + this.aSCIIMultilineMenuItem = new System.Windows.Forms.MenuItem(); + this.uTF8MultilineMenuItem = new System.Windows.Forms.MenuItem(); + this.uTF16MultilineMenuItem = new System.Windows.Forms.MenuItem(); + this.uTF16BigEndianMultilineMenuItem = new System.Windows.Forms.MenuItem(); + this.uTF32MultilineMenuItem = new System.Windows.Forms.MenuItem(); + this.toolTip = new System.Windows.Forms.ToolTip(this.components); + this.SuspendLayout(); + // + // buttonUtilities + // + this.buttonUtilities.Image = global::ProcessHacker.Properties.Resources.page_gear; + this.buttonUtilities.Location = new System.Drawing.Point(0, 0); + this.buttonUtilities.Name = "buttonUtilities"; + this.buttonUtilities.Size = new System.Drawing.Size(24, 24); + this.buttonUtilities.TabIndex = 0; + this.toolTip.SetToolTip(this.buttonUtilities, "Insert Data"); + this.buttonUtilities.UseVisualStyleBackColor = true; + this.buttonUtilities.Click += new System.EventHandler(this.buttonUtilities_Click); + // + // menuUtilities + // + this.menuUtilities.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.insertNumberMenuItem, + this.insertStringMenuItem}); + // + // insertNumberMenuItem + // + this.insertNumberMenuItem.Index = 0; + this.insertNumberMenuItem.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.bitMenuItem, + this.bitLittleEndianMenuItem, + this.bitBigEndianMenuItem, + this.bitLittleEndianMenuItem1, + this.bitBigEndianMenuItem1, + this.bitLittleEndianMenuItem2, + this.bitBigEndianMenuItem2}); + this.insertNumberMenuItem.Text = "Insert &Number"; + // + // bitMenuItem + // + this.bitMenuItem.Index = 0; + this.bitMenuItem.Text = "8-bit"; + this.bitMenuItem.Click += new System.EventHandler(this.bitMenuItem_Click); + // + // bitLittleEndianMenuItem + // + this.bitLittleEndianMenuItem.Index = 1; + this.bitLittleEndianMenuItem.Text = "16-bit (little-endian)"; + this.bitLittleEndianMenuItem.Click += new System.EventHandler(this.bitLittleEndianMenuItem_Click); + // + // bitBigEndianMenuItem + // + this.bitBigEndianMenuItem.Index = 2; + this.bitBigEndianMenuItem.Text = "16-bit (big-endian)"; + this.bitBigEndianMenuItem.Click += new System.EventHandler(this.bitBigEndianMenuItem_Click); + // + // bitLittleEndianMenuItem1 + // + this.bitLittleEndianMenuItem1.Index = 3; + this.bitLittleEndianMenuItem1.Text = "32-bit (little-endian)"; + this.bitLittleEndianMenuItem1.Click += new System.EventHandler(this.bitLittleEndianMenuItem1_Click); + // + // bitBigEndianMenuItem1 + // + this.bitBigEndianMenuItem1.Index = 4; + this.bitBigEndianMenuItem1.Text = "32-bit (big-endian)"; + this.bitBigEndianMenuItem1.Click += new System.EventHandler(this.bitBigEndianMenuItem1_Click); + // + // bitLittleEndianMenuItem2 + // + this.bitLittleEndianMenuItem2.Index = 5; + this.bitLittleEndianMenuItem2.Text = "64-bit (little-endian)"; + this.bitLittleEndianMenuItem2.Click += new System.EventHandler(this.bitLittleEndianMenuItem2_Click); + // + // bitBigEndianMenuItem2 + // + this.bitBigEndianMenuItem2.Index = 6; + this.bitBigEndianMenuItem2.Text = "64-bit (big-endian)"; + this.bitBigEndianMenuItem2.Click += new System.EventHandler(this.bitBigEndianMenuItem2_Click); + // + // insertStringMenuItem + // + this.insertStringMenuItem.Index = 1; + this.insertStringMenuItem.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.aSCIIMenuItem, + this.uTF8MenuItem, + this.uTF16MenuItem, + this.uTF16BigEndianMenuItem, + this.uTF32MenuItem, + this.aSCIIMultilineMenuItem, + this.uTF8MultilineMenuItem, + this.uTF16MultilineMenuItem, + this.uTF16BigEndianMultilineMenuItem, + this.uTF32MultilineMenuItem}); + this.insertStringMenuItem.Text = "Insert &String"; + // + // aSCIIMenuItem + // + this.aSCIIMenuItem.Index = 0; + this.aSCIIMenuItem.Text = "ASCII"; + this.aSCIIMenuItem.Click += new System.EventHandler(this.aSCIIMenuItem_Click); + // + // uTF8MenuItem + // + this.uTF8MenuItem.Index = 1; + this.uTF8MenuItem.Text = "UTF-8"; + this.uTF8MenuItem.Click += new System.EventHandler(this.uTF8MenuItem_Click); + // + // uTF16MenuItem + // + this.uTF16MenuItem.Index = 2; + this.uTF16MenuItem.Text = "UTF-16"; + this.uTF16MenuItem.Click += new System.EventHandler(this.uTF16MenuItem_Click); + // + // uTF16BigEndianMenuItem + // + this.uTF16BigEndianMenuItem.Index = 3; + this.uTF16BigEndianMenuItem.Text = "UTF-16 (big-endian)"; + this.uTF16BigEndianMenuItem.Click += new System.EventHandler(this.uTF16BigEndianMenuItem_Click); + // + // uTF32MenuItem + // + this.uTF32MenuItem.Index = 4; + this.uTF32MenuItem.Text = "UTF-32"; + this.uTF32MenuItem.Click += new System.EventHandler(this.uTF32MenuItem_Click); + // + // aSCIIMultilineMenuItem + // + this.aSCIIMultilineMenuItem.Index = 5; + this.aSCIIMultilineMenuItem.Text = "ASCII (multiline)"; + this.aSCIIMultilineMenuItem.Click += new System.EventHandler(this.aSCIIMultilineMenuItem_Click); + // + // uTF8MultilineMenuItem + // + this.uTF8MultilineMenuItem.Index = 6; + this.uTF8MultilineMenuItem.Text = "UTF-8 (multiline)"; + this.uTF8MultilineMenuItem.Click += new System.EventHandler(this.uTF8MultilineMenuItem_Click); + // + // uTF16MultilineMenuItem + // + this.uTF16MultilineMenuItem.Index = 7; + this.uTF16MultilineMenuItem.Text = "UTF-16 (multiline)"; + this.uTF16MultilineMenuItem.Click += new System.EventHandler(this.uTF16MultilineMenuItem_Click); + // + // uTF16BigEndianMultilineMenuItem + // + this.uTF16BigEndianMultilineMenuItem.Index = 8; + this.uTF16BigEndianMultilineMenuItem.Text = "UTF-16 (big-endian) (multiline)"; + this.uTF16BigEndianMultilineMenuItem.Click += new System.EventHandler(this.uTF16BigEndianMultilineMenuItem_Click); + // + // uTF32MultilineMenuItem + // + this.uTF32MultilineMenuItem.Index = 9; + this.uTF32MultilineMenuItem.Text = "UTF-32 (multiline)"; + this.uTF32MultilineMenuItem.Click += new System.EventHandler(this.uTF32MultilineMenuItem_Click); + // + // UtilitiesButton + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.buttonUtilities); + this.Name = "UtilitiesButton"; + this.Size = new System.Drawing.Size(24, 24); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Button buttonUtilities; + private System.Windows.Forms.ContextMenu menuUtilities; + private System.Windows.Forms.MenuItem insertNumberMenuItem; + private System.Windows.Forms.MenuItem bitMenuItem; + private System.Windows.Forms.MenuItem bitLittleEndianMenuItem; + private System.Windows.Forms.MenuItem bitBigEndianMenuItem; + private System.Windows.Forms.MenuItem bitLittleEndianMenuItem1; + private System.Windows.Forms.MenuItem bitBigEndianMenuItem1; + private System.Windows.Forms.MenuItem bitLittleEndianMenuItem2; + private System.Windows.Forms.MenuItem bitBigEndianMenuItem2; + private System.Windows.Forms.MenuItem insertStringMenuItem; + private System.Windows.Forms.MenuItem aSCIIMenuItem; + private System.Windows.Forms.MenuItem uTF8MenuItem; + private System.Windows.Forms.MenuItem uTF16MenuItem; + private System.Windows.Forms.MenuItem uTF16BigEndianMenuItem; + private System.Windows.Forms.MenuItem uTF32MenuItem; + private System.Windows.Forms.MenuItem aSCIIMultilineMenuItem; + private System.Windows.Forms.MenuItem uTF8MultilineMenuItem; + private System.Windows.Forms.MenuItem uTF16MultilineMenuItem; + private System.Windows.Forms.MenuItem uTF16BigEndianMultilineMenuItem; + private System.Windows.Forms.MenuItem uTF32MultilineMenuItem; + private System.Windows.Forms.ToolTip toolTip; + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/UtilitiesButton.cs b/branches/ph-plugins/ProcessHacker/Components/UtilitiesButton.cs new file mode 100644 index 000000000..ba530aba3 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/UtilitiesButton.cs @@ -0,0 +1,192 @@ +/* + * Process Hacker - + * button for inserting various data + * + * Copyright (C) 2008 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 . + */ + +using System; +using System.ComponentModel; +using System.Drawing; +using System.Text; +using System.Windows.Forms; +using Be.Windows.Forms; +using ProcessHacker.Common; + +namespace ProcessHacker.Components +{ + public partial class UtilitiesButton : UserControl + { + private HexBox _hexbox; + + public UtilitiesButton() + { + InitializeComponent(); + + this.Size = new Size(24, 24); + } + + [Category("General"), Description("The HexBox which is modified by this control")] + public HexBox HexBox + { + get { return _hexbox; } + set { _hexbox = value; } + } + + public override ContextMenu ContextMenu + { + get { return menuUtilities; } + } + + private void InsertNumber(HexBox _hexbox, int byteCount, bool BigEndian) + { + PromptBox prompt = new PromptBox(); + + if (prompt.ShowDialog() == DialogResult.OK) + { + byte[] bytes = new byte[byteCount]; + long number = (long)BaseConverter.ToNumberParse(prompt.Value); + + for (int i = 0; i < bytes.Length; i++) + { + bytes[BigEndian ? (bytes.Length - i - 1) : i] = (byte)((number >> (i * 8)) & 0xff); + } + + _hexbox.ByteProvider.DeleteBytes(_hexbox.SelectionStart, _hexbox.SelectionLength); + _hexbox.ByteProvider.InsertBytes(_hexbox.SelectionStart, bytes); + _hexbox.Select(_hexbox.SelectionStart, bytes.Length); + } + } + + private void InsertUsingEncoding(Encoding encoding, HexBox _hexbox, bool Multiline) + { + PromptBox prompt = new PromptBox(Multiline); + + if (prompt.ShowDialog() == DialogResult.OK) + { + byte[] bytes = new byte[prompt.Value.Length * encoding.GetByteCount("A")]; + + encoding.GetBytes(prompt.Value, 0, prompt.Value.Length, bytes, 0); + + _hexbox.ByteProvider.DeleteBytes(_hexbox.SelectionStart, _hexbox.SelectionLength); + _hexbox.ByteProvider.InsertBytes(_hexbox.SelectionStart, bytes); + _hexbox.Select(_hexbox.SelectionStart, bytes.Length); + } + } + + private void buttonUtilities_Click(object sender, System.EventArgs e) + { + menuUtilities.Show(buttonUtilities, new Point( + buttonUtilities.Size.Width, + 0)); + } + + #region Insert Number + + private void bitMenuItem_Click(object sender, EventArgs e) + { + InsertNumber(_hexbox, 1, false); + } + + private void bitLittleEndianMenuItem_Click(object sender, EventArgs e) + { + InsertNumber(_hexbox, 2, false); + } + + private void bitBigEndianMenuItem_Click(object sender, EventArgs e) + { + InsertNumber(_hexbox, 2, true); + } + + private void bitLittleEndianMenuItem1_Click(object sender, EventArgs e) + { + InsertNumber(_hexbox, 4, false); + } + + private void bitBigEndianMenuItem1_Click(object sender, EventArgs e) + { + InsertNumber(_hexbox, 4, true); + } + + private void bitLittleEndianMenuItem2_Click(object sender, EventArgs e) + { + InsertNumber(_hexbox, 8, false); + } + + private void bitBigEndianMenuItem2_Click(object sender, EventArgs e) + { + InsertNumber(_hexbox, 8, true); + } + + #endregion + + #region Insert String + + private void aSCIIMenuItem_Click(object sender, EventArgs e) + { + InsertUsingEncoding(UnicodeEncoding.ASCII, _hexbox, false); + } + + private void uTF8MenuItem_Click(object sender, EventArgs e) + { + InsertUsingEncoding(UnicodeEncoding.UTF8, _hexbox, false); + } + + private void uTF16MenuItem_Click(object sender, EventArgs e) + { + InsertUsingEncoding(UnicodeEncoding.Unicode, _hexbox, false); + } + + private void uTF16BigEndianMenuItem_Click(object sender, EventArgs e) + { + InsertUsingEncoding(UnicodeEncoding.BigEndianUnicode, _hexbox, false); + } + + private void uTF32MenuItem_Click(object sender, EventArgs e) + { + InsertUsingEncoding(UnicodeEncoding.UTF32, _hexbox, false); + } + + private void aSCIIMultilineMenuItem_Click(object sender, EventArgs e) + { + InsertUsingEncoding(UnicodeEncoding.ASCII, _hexbox, true); + } + + private void uTF8MultilineMenuItem_Click(object sender, EventArgs e) + { + InsertUsingEncoding(UnicodeEncoding.UTF8, _hexbox, true); + } + + private void uTF16MultilineMenuItem_Click(object sender, EventArgs e) + { + InsertUsingEncoding(UnicodeEncoding.Unicode, _hexbox, true); + } + + private void uTF16BigEndianMultilineMenuItem_Click(object sender, EventArgs e) + { + InsertUsingEncoding(UnicodeEncoding.BigEndianUnicode, _hexbox, true); + } + + private void uTF32MultilineMenuItem_Click(object sender, EventArgs e) + { + InsertUsingEncoding(UnicodeEncoding.UTF32, _hexbox, true); + } + + #endregion + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/UtilitiesButton.resx b/branches/ph-plugins/ProcessHacker/Components/UtilitiesButton.resx new file mode 100644 index 000000000..53acaa8bb --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/UtilitiesButton.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 140, 17 + + + 17, 17 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/VerticleProgressBar.Designer.cs b/branches/ph-plugins/ProcessHacker/Components/VerticleProgressBar.Designer.cs new file mode 100644 index 000000000..b39c4fdb9 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/VerticleProgressBar.Designer.cs @@ -0,0 +1,46 @@ +namespace ProcessHacker.Components +{ + partial class VerticleProgressBar + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.SuspendLayout(); + // + // VerticleProgressBar + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Name = "VerticleProgressBar"; + this.Size = new System.Drawing.Size(20, 150); + this.Paint += new System.Windows.Forms.PaintEventHandler(this.VerticleProgressBar_Paint); + this.ResumeLayout(false); + + } + + #endregion + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/VerticleProgressBar.cs b/branches/ph-plugins/ProcessHacker/Components/VerticleProgressBar.cs new file mode 100644 index 000000000..45693bae4 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/VerticleProgressBar.cs @@ -0,0 +1,61 @@ +/* + * Process Hacker - + * vertical progress bar + * + * Copyright (C) 2008 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 . + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Text; +using System.Windows.Forms; +using System.Windows.Forms.VisualStyles; + +namespace ProcessHacker.Components +{ + public partial class VerticleProgressBar : UserControl + { + public VerticleProgressBar() + { + InitializeComponent(); + } + + private float _value; + public float Value + { + get { return _value; } + set { _value = value; this.Invalidate(); } + } + + private void VerticleProgressBar_Paint(object sender, PaintEventArgs e) + { + VisualStyleRenderer rBar = new VisualStyleRenderer(VisualStyleElement.ProgressBar.BarVertical.Normal); + + rBar.DrawBackground(e.Graphics, e.ClipRectangle); + + VisualStyleRenderer rChunk = new VisualStyleRenderer(VisualStyleElement.ProgressBar.ChunkVertical.Normal); + + rChunk.DrawBackground(e.Graphics, new Rectangle( + new Point(e.ClipRectangle.Left + 1, e.ClipRectangle.Top + 1 + (int)(this.Size.Height * (1 - _value))), + new Size(this.Size.Width - 2, (int)(this.Size.Height * _value) - 2))); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/VerticleProgressBar.resx b/branches/ph-plugins/ProcessHacker/Components/VerticleProgressBar.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/VerticleProgressBar.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/VistaMenu/OwnerDrawnMenu.cs b/branches/ph-plugins/ProcessHacker/Components/VistaMenu/OwnerDrawnMenu.cs new file mode 100644 index 000000000..10cab6d31 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/VistaMenu/OwnerDrawnMenu.cs @@ -0,0 +1,235 @@ +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Windows.Forms; + + +namespace wyDay.Controls +{ + public partial class VistaMenu + { + ContainerControl ownerForm; + + //conditionally draw the little lines under menu items with keyboard accelators on Win 2000+ + private bool isUsingKeyboardAccel; + + + public VistaMenu(ContainerControl parentControl) + : this() + { + ownerForm = parentControl; + } + public ContainerControl ContainerControl + { + get { return ownerForm; } + set { ownerForm = value; } + } + public override ISite Site + { + set + { + // Runs at design time, ensures designer initializes ContainerControl + base.Site = value; + if (value == null) return; + IDesignerHost service = value.GetService(typeof(IDesignerHost)) as IDesignerHost; + if (service == null) return; + IComponent rootComponent = service.RootComponent; + ContainerControl = rootComponent as ContainerControl; + } + } + + + void ownerForm_ChangeUICues(object sender, UICuesEventArgs e) + { + isUsingKeyboardAccel = e.ShowKeyboard; + } + + + const int SEPARATOR_HEIGHT = 9; + const int BORDER_VERTICAL = 4; + const int LEFT_MARGIN = 4; + const int RIGHT_MARGIN = 6; + const int SHORTCUT_MARGIN = 20; + const int ARROW_MARGIN = 12; + const int ICON_SIZE = 16; + + + static void MenuItem_MeasureItem(object sender, MeasureItemEventArgs e) + { + Font font = ((MenuItem)sender).DefaultItem + ? new Font(SystemFonts.MenuFont, FontStyle.Bold) + : SystemFonts.MenuFont; + + if (((MenuItem)sender).Text == "-") + e.ItemHeight = SEPARATOR_HEIGHT; + else + { + e.ItemHeight = ((SystemFonts.MenuFont.Height > ICON_SIZE) ? SystemFonts.MenuFont.Height : ICON_SIZE) + + BORDER_VERTICAL; + + e.ItemWidth = LEFT_MARGIN + ICON_SIZE + RIGHT_MARGIN + + //item text width + + TextRenderer.MeasureText(((MenuItem)sender).Text, font, Size.Empty, TextFormatFlags.SingleLine | TextFormatFlags.NoClipping).Width + + SHORTCUT_MARGIN + + //shortcut text width + + TextRenderer.MeasureText(ShortcutToString(((MenuItem)sender).Shortcut), font, Size.Empty, TextFormatFlags.SingleLine | TextFormatFlags.NoClipping).Width + + //arrow width + + ((((MenuItem)sender).IsParent) ? ARROW_MARGIN : 0); + } + } + + void MenuItem_DrawItem(object sender, DrawItemEventArgs e) + { + e.Graphics.CompositingQuality = CompositingQuality.HighSpeed; + e.Graphics.InterpolationMode = InterpolationMode.Low; + + bool menuSelected = (e.State & DrawItemState.Selected) == DrawItemState.Selected; + + if (menuSelected) + e.Graphics.FillRectangle(SystemBrushes.Highlight, e.Bounds); + else + e.Graphics.FillRectangle(SystemBrushes.Menu, e.Bounds); + + if (((MenuItem)sender).Text == "-") + { + //draw the separator + int yCenter = e.Bounds.Top + (e.Bounds.Height / 2) - 1; + + e.Graphics.DrawLine(SystemPens.ControlDark, e.Bounds.Left + 1, yCenter, (e.Bounds.Left + e.Bounds.Width - 2), yCenter); + e.Graphics.DrawLine(SystemPens.ControlLightLight, e.Bounds.Left + 1, yCenter + 1, (e.Bounds.Left + e.Bounds.Width - 2), yCenter + 1); + } + else //regular menu items + { + //draw the item text + DrawText(sender, e, menuSelected); + + if (((MenuItem)sender).Checked) + { + if (((MenuItem)sender).RadioCheck) + { + //draw the bullet + ControlPaint.DrawMenuGlyph(e.Graphics, + e.Bounds.Left + (LEFT_MARGIN + ICON_SIZE + RIGHT_MARGIN - SystemInformation.MenuCheckSize.Width) / 2, + e.Bounds.Top + (e.Bounds.Height - SystemInformation.MenuCheckSize.Height) / 2 + 1, + SystemInformation.MenuCheckSize.Width, + SystemInformation.MenuCheckSize.Height, + MenuGlyph.Bullet, + menuSelected ? SystemColors.HighlightText : SystemColors.MenuText, + menuSelected ? SystemColors.Highlight : SystemColors.Menu); + } + else + { + //draw the check mark + ControlPaint.DrawMenuGlyph(e.Graphics, + e.Bounds.Left + (LEFT_MARGIN + ICON_SIZE + RIGHT_MARGIN - SystemInformation.MenuCheckSize.Width) / 2, + e.Bounds.Top + (e.Bounds.Height - SystemInformation.MenuCheckSize.Height) / 2 + 1, + SystemInformation.MenuCheckSize.Width, + SystemInformation.MenuCheckSize.Height, + MenuGlyph.Checkmark, + menuSelected ? SystemColors.HighlightText : SystemColors.MenuText, + menuSelected ? SystemColors.Highlight : SystemColors.Menu); + } + } + else + { + Image drawImg = EnsurePropertiesExists((MenuItem)sender).PreVistaBitmap; + + if (drawImg != null) + { + //draw the image + if (((MenuItem)sender).Enabled) + e.Graphics.DrawImage(drawImg, e.Bounds.Left + LEFT_MARGIN, + e.Bounds.Top + ((e.Bounds.Height - ICON_SIZE) / 2), + ICON_SIZE, ICON_SIZE); + else + ControlPaint.DrawImageDisabled(e.Graphics, drawImg, + e.Bounds.Left + LEFT_MARGIN, + e.Bounds.Top + ((e.Bounds.Height - ICON_SIZE) / 2), + SystemColors.Menu); + } + } + } + } + + + private static string ShortcutToString(Shortcut shortcut) + { + if (shortcut != Shortcut.None) + { + Keys keys = (Keys)shortcut; + return TypeDescriptor.GetConverter(keys.GetType()).ConvertToString(keys); + } + + return null; + } + + private void DrawText(object sender, DrawItemEventArgs e, bool isSelected) + { + string shortcutText = ShortcutToString(((MenuItem)sender).Shortcut); + + int yPos = e.Bounds.Top + (e.Bounds.Height - SystemFonts.MenuFont.Height) / 2; + + Font font = ((MenuItem)sender).DefaultItem + ? new Font(SystemFonts.MenuFont, FontStyle.Bold) + : SystemFonts.MenuFont; + + Size textSize = TextRenderer.MeasureText(((MenuItem)sender).Text, + font, Size.Empty, TextFormatFlags.SingleLine | TextFormatFlags.NoClipping); + + Rectangle textRect = new Rectangle(e.Bounds.Left + LEFT_MARGIN + ICON_SIZE + RIGHT_MARGIN, yPos, + textSize.Width, textSize.Height); + + if (!((MenuItem)sender).Enabled && !isSelected) // disabled and not selected + { + textRect.Offset(1, 1); + + TextRenderer.DrawText(e.Graphics, ((MenuItem)sender).Text, font, + textRect, + SystemColors.ControlLightLight, + TextFormatFlags.SingleLine | (isUsingKeyboardAccel ? 0 : TextFormatFlags.HidePrefix) | TextFormatFlags.NoClipping); + + textRect.Offset(-1, -1); + } + + //Draw the menu item text + TextRenderer.DrawText(e.Graphics, ((MenuItem)sender).Text, font, + textRect, + ((MenuItem)sender).Enabled ? (isSelected ? SystemColors.HighlightText : SystemColors.MenuText) : SystemColors.GrayText, + TextFormatFlags.SingleLine | (isUsingKeyboardAccel ? 0 : TextFormatFlags.HidePrefix) | TextFormatFlags.NoClipping); + + + + //Draw the shortcut text + if (shortcutText != null) + { + textSize = TextRenderer.MeasureText(shortcutText, + font, Size.Empty, TextFormatFlags.SingleLine | TextFormatFlags.NoClipping); + + + textRect = new Rectangle(e.Bounds.Width - textSize.Width - ARROW_MARGIN, yPos, textSize.Width, + textSize.Height); + + if (!((MenuItem)sender).Enabled && !isSelected) // disabled and not selected + { + textRect.Offset(1, 1); + + TextRenderer.DrawText(e.Graphics, shortcutText, font, + textRect, + SystemColors.ControlLightLight, + TextFormatFlags.SingleLine | (isUsingKeyboardAccel ? 0 : TextFormatFlags.HidePrefix) | TextFormatFlags.NoClipping); + + textRect.Offset(-1, -1); + } + + TextRenderer.DrawText(e.Graphics, shortcutText, font, + textRect, + ((MenuItem)sender).Enabled ? (isSelected ? SystemColors.HighlightText : SystemColors.MenuText) : SystemColors.GrayText, + TextFormatFlags.SingleLine | TextFormatFlags.NoClipping); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/VistaMenu/VistaMenu.cs b/branches/ph-plugins/ProcessHacker/Components/VistaMenu/VistaMenu.cs new file mode 100644 index 000000000..60c06b132 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/VistaMenu/VistaMenu.cs @@ -0,0 +1,411 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using ProcessHacker.Native; + + +//VistaMenu v1.7, created by Wyatt O'Day +//Visit: http://wyday.com/vistamenu/ + +namespace wyDay.Controls +{ + //Properties for the MenuItem + internal class Properties + { + public Image Image; + public IntPtr renderBmpHbitmap = IntPtr.Zero; + public Bitmap PreVistaBitmap; + } + + //enum WindowsType { VistaOrLater, XP, PreXP } + + [ProvideProperty("Image", typeof(MenuItem))] + public partial class VistaMenu : Component, IExtenderProvider, ISupportInitialize + { + private Container components; + private readonly Hashtable properties = new Hashtable(); + private readonly Hashtable menuParents = new Hashtable(); + + private bool formHasBeenIntialized; + + // performance hacks + private Queue> _pendingSetImageCalls = + new Queue>(); + + private static bool _firstVistaMenu = true; + private bool _delaySetImageCalls = false; + + public bool DelaySetImageCalls + { + get { return _delaySetImageCalls; } + set { _delaySetImageCalls = value; } + } + + #region Imports + + [DllImport("user32.dll", CharSet = CharSet.Auto)] + public static extern bool SetMenuItemInfo(HandleRef hMenu, int uItem, bool fByPosition, MENUITEMINFO_T_RW lpmii); + + [DllImport("user32.dll", CharSet = CharSet.Auto)] + public static extern bool SetMenuInfo(HandleRef hMenu, MENUINFO lpcmi); + + [DllImport("gdi32.dll")] + public static extern bool DeleteObject(IntPtr hObject); + + #endregion + + + public VistaMenu() + { + InitializeComponent(); + } + + public VistaMenu(IContainer container) + : this() + { + container.Add(this); + + if (_firstVistaMenu) + { + _delaySetImageCalls = true; + _firstVistaMenu = false; + } + } + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + components = new Container(); + } + + /// + /// Clean up any resources being used. + /// + protected override void Dispose(bool disposing) + { + if (disposing) + { + //release all the HBitmap handles created + foreach (DictionaryEntry de in properties) + { + if (((Properties)de.Value).renderBmpHbitmap != IntPtr.Zero) + DeleteObject(((Properties)de.Value).renderBmpHbitmap); + if (((Properties)de.Value).PreVistaBitmap != null) + ((Properties)de.Value).PreVistaBitmap.Dispose(); + } + + + if (components != null) + { + components.Dispose(); + } + } + base.Dispose(disposing); + } + + bool IExtenderProvider.CanExtend(object o) + { + if (o is MenuItem) + { + // reject the menuitem if it's a top level element on a MainMenu bar + if (((MenuItem)o).Parent != null) + return ((MenuItem)o).Parent.GetType() != typeof(MainMenu); + + // parent is null - meaning it's a context menu + return true; + } + + if (o is Form) + return true; + + return false; + } + + private Properties EnsurePropertiesExists(MenuItem key) + { + Properties p = (Properties)properties[key]; + + if (p == null) + { + p = new Properties(); + + properties[key] = p; + } + + return p; + } + + + #region MenuItem.Image + + [DefaultValue(null)] + [Description("The Image for the MenuItem")] + [Category("Appearance")] + public Image GetImage(MenuItem mnuItem) + { + return EnsurePropertiesExists(mnuItem).Image; + } + + [DefaultValue(null)] + public void SetImage(MenuItem mnuItem, Image value) + { + this.SetImage(mnuItem, value, false); + } + + public void SetImage(MenuItem mnuItem, Image value, bool ignorePending) + { + if (_delaySetImageCalls && !ignorePending) + { + _pendingSetImageCalls.Enqueue(new KeyValuePair(mnuItem, value)); + return; + } + + Properties prop = EnsurePropertiesExists(mnuItem); + + if (DesignMode) + prop.Image = value; + + if (!DesignMode && OSVersion.IsAboveOrEqual(WindowsVersion.Vista)) + { + //Destroy old bitmap object + if (prop.renderBmpHbitmap != IntPtr.Zero) + { + DeleteObject(prop.renderBmpHbitmap); + prop.renderBmpHbitmap = IntPtr.Zero; + } + + //if there's no Image, then just bail out + if (value == null) + { + // wj32: clean up resources before doing that... + RemoveVistaMenuItem(mnuItem); + return; + } + + //convert to 32bppPArgb (the 'P' means The red, green, and blue components are premultiplied, according to the alpha component.) + Bitmap renderBmp = new Bitmap(value.Width, value.Height, System.Drawing.Imaging.PixelFormat.Format32bppPArgb); + Graphics g = Graphics.FromImage(renderBmp); + + g.DrawImage(value, 0, 0, value.Width, value.Height); + g.Dispose(); + + prop.renderBmpHbitmap = renderBmp.GetHbitmap(Color.FromArgb(0, 0, 0, 0)); + renderBmp.Dispose(); + + if (formHasBeenIntialized) + { + AddVistaMenuItem(mnuItem); + } + } + else if (!DesignMode && OSVersion.IsBelow(WindowsVersion.Vista)) + { + if (prop.PreVistaBitmap != null) + { + prop.PreVistaBitmap.Dispose(); + prop.PreVistaBitmap = null; + } + + if (value == null) + { + RemoveVistaMenuItem(mnuItem); + return; + } + + Bitmap bmp = new Bitmap(value.Width, value.Height, System.Drawing.Imaging.PixelFormat.Format32bppPArgb); + Graphics g = Graphics.FromImage(bmp); + + g.DrawImage(value, 0, 0, value.Width, value.Height); + g.Dispose(); + + prop.PreVistaBitmap = bmp; + + //for every Pre-Vista Windows, add the parent of the menu item to the list of parents + if (formHasBeenIntialized) + { + AddPreVistaMenuItem(mnuItem); + } + } + } + + public void PerformPendingSetImageCalls() + { + while (_pendingSetImageCalls.Count > 0) + { + var call = _pendingSetImageCalls.Dequeue(); + + this.SetImage(call.Key, call.Value, true); + } + } + + #endregion + + + + void ISupportInitialize.BeginInit() + { + } + + readonly MENUINFO mnuInfo = new MENUINFO(); + + void AddVistaMenuItem(MenuItem mnuItem) + { + //get the bitmap children of the parent + List mnuBitmapChildren = (List)menuParents[mnuItem.Parent.Handle]; + + + if (mnuBitmapChildren == null) + { + if (mnuItem.Parent.GetType() == typeof(ContextMenu)) + ((ContextMenu)mnuItem.Parent).Popup += MenuItem_Popup; + else + ((MenuItem)mnuItem.Parent).Popup += MenuItem_Popup; + + //intialize all the topmost menus to be of type "MNS_CHECKORBMP" (for Vista classic theme) + SetMenuInfo(new HandleRef(null, mnuItem.Parent.Handle), mnuInfo); + + + mnuBitmapChildren = new List { mnuItem }; + + //set the new children list to the corresponding parent + menuParents[mnuItem.Parent.Handle] = mnuBitmapChildren; + } + else + { + mnuBitmapChildren.Add(mnuItem); + } + } + + void AddPreVistaMenuItem(MenuItem mnuItem) + { + if (menuParents[mnuItem.Parent] == null) + { + menuParents[mnuItem.Parent] = true; + + if (formHasBeenIntialized) + { + //add all the menu items with custom paint events + foreach (MenuItem menu in mnuItem.Parent.MenuItems) + { + menu.DrawItem += MenuItem_DrawItem; + menu.MeasureItem += MenuItem_MeasureItem; + menu.OwnerDraw = true; + } + } + } + } + + public void RemoveVistaMenuItem(MenuItem mnuItem) + { + if (menuParents[mnuItem.Parent.Handle] != null) + { + List mnuBitmapChildren = (List)menuParents[mnuItem.Parent.Handle]; + + mnuBitmapChildren.Remove(mnuItem); + } + } + + public void RemovePreVistaMenuItem(MenuItem mnuItem) + { + mnuItem.DrawItem -= MenuItem_DrawItem; + mnuItem.MeasureItem -= MenuItem_MeasureItem; + mnuItem.OwnerDraw = false; + } + + void ISupportInitialize.EndInit() + { + if (!DesignMode) + { + if (OSVersion.IsAboveOrEqual(WindowsVersion.Vista)) + { + foreach (DictionaryEntry de in properties) + { + AddVistaMenuItem((MenuItem)de.Key); + } + } + else // Pre-Vista menus + { + if (ownerForm != null) + ownerForm.ChangeUICues += ownerForm_ChangeUICues; + + foreach (DictionaryEntry de in properties) + { + AddPreVistaMenuItem((MenuItem)de.Key); + } + + //add event handle for each menu item's measure & draw routines + foreach (DictionaryEntry parent in menuParents) + { + foreach (MenuItem mnuItem in ((Menu)parent.Key).MenuItems) + { + mnuItem.DrawItem += MenuItem_DrawItem; + mnuItem.MeasureItem += MenuItem_MeasureItem; + mnuItem.OwnerDraw = true; + } + } + } + + formHasBeenIntialized = true; + } + } + + void MenuItem_Popup(object sender, EventArgs e) + { + //get the parentHandle + IntPtr parentHandle = ((Menu)sender).Handle; + + //get the list of children menuitems to "refresh" + List mnuBitmapChildren = (List)menuParents[parentHandle]; + + MENUITEMINFO_T_RW menuItemInfo = new MENUITEMINFO_T_RW(); + + foreach (MenuItem menuItem in mnuBitmapChildren) + { + //menuItem. + menuItemInfo.hbmpItem = ((Properties)properties[menuItem]).renderBmpHbitmap; + + //refresh the menu item + SetMenuItemInfo(new HandleRef(null, parentHandle), + (int)typeof(MenuItem).InvokeMember("MenuID", BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetProperty, null, menuItem, null), + false, + menuItemInfo); + } + } + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + public class MENUITEMINFO_T_RW + { + public int cbSize = Marshal.SizeOf(typeof(MENUITEMINFO_T_RW)); + public int fMask = 0x00000080; //MIIM_BITMAP = 0x00000080 + public int fType; + public int fState; + public int wID; + public IntPtr hSubMenu = IntPtr.Zero; + public IntPtr hbmpChecked = IntPtr.Zero; + public IntPtr hbmpUnchecked = IntPtr.Zero; + public IntPtr dwItemData = IntPtr.Zero; + public IntPtr dwTypeData = IntPtr.Zero; + public int cch; + public IntPtr hbmpItem = IntPtr.Zero; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + public class MENUINFO + { + public int cbSize = Marshal.SizeOf(typeof(MENUINFO)); + public int fMask = 0x00000010; //MIM_STYLE; + public int dwStyle = 0x04000000; //MNS_CHECKORBMP; + public uint cyMax; + public IntPtr hbrBack = IntPtr.Zero; + public int dwContextHelpID; + public IntPtr dwMenuData = IntPtr.Zero; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Components/VistaSearchBox.cs b/branches/ph-plugins/ProcessHacker/Components/VistaSearchBox.cs new file mode 100644 index 000000000..29b1a2b31 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/VistaSearchBox.cs @@ -0,0 +1,343 @@ +using System; +using System.ComponentModel; +using System.Drawing; +using System.Security.Permissions; +using System.Windows.Forms; +using System.Runtime.InteropServices; + +namespace ProcessHacker +{ + [DefaultEvent("TextChanged")] + [DefaultProperty("Text")] + public partial class VistaSearchBox : Control + { + private const string DefaultInactiveText = "Search"; + private string _inactiveText; + + private bool _active; + + private Color _hoverButtonColor; + private Color _activeBackColor; + private Color _activeForeColor; + private Color _inactiveBackColor; + private Color _inactiveForeColor; + + private Font _inactiveFont; + + protected override CreateParams CreateParams + { + [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] + get + { + int WS_BORDER = 0x00800000; + int WS_EX_CLIENTEDGE = 0x00000200; + int WS_EX_CONTROLPARENT = 0x00010000; + + CreateParams createParams = base.CreateParams; + createParams.ExStyle |= WS_EX_CONTROLPARENT; + createParams.ExStyle &= ~WS_EX_CLIENTEDGE; + + // make sure WS_BORDER is present in the style + createParams.Style |= WS_BORDER; + + return createParams; + } + } + + public VistaSearchBox() + { + _hoverButtonColor = SystemColors.GradientInactiveCaption; + _activeBackColor = SystemColors.Window; + _activeForeColor = SystemColors.WindowText; + _inactiveBackColor = SystemColors.InactiveBorder; + _inactiveForeColor = SystemColors.GrayText; + + _inactiveFont = new Font(this.Font, FontStyle.Italic); + + _inactiveText = DefaultInactiveText; + + InitializeComponent(); + + BackColor = InactiveBackColor; + ForeColor = InactiveForeColor; + + searchOverlayLabel.Font = InactiveFont; + searchOverlayLabel.ForeColor = InactiveForeColor; + searchOverlayLabel.BackColor = InactiveBackColor; + searchOverlayLabel.Text = InactiveText; + + searchText.Font = Font; + searchText.ForeColor = ActiveForeColor; + searchText.BackColor = InactiveBackColor; + + _active = false; + + SetTextActive(false); + SetActive(false); + } + + #region Events + + public new event EventHandler TextChanged + { + add { searchText.TextChanged += value; } + remove { searchText.TextChanged -= value; } + } + + #endregion + + #region Properties + + [Category("Appearance")] + [DefaultValue(typeof(Color), "GradientInactiveCaption")] + public Color HoverButtonColor + { + get { return _hoverButtonColor; } + set { _hoverButtonColor = value; } + } + + [Category("Appearance")] + [DefaultValue(typeof(Color), "WindowText")] + public Color ActiveForeColor + { + get { return _activeForeColor; } + set { _activeForeColor = value; } + } + + [Category("Appearance")] + [DefaultValue(typeof(Color), "Window")] + public Color ActiveBackColor + { + get { return _activeBackColor; } + set { _activeBackColor = value; } + } + + [Category("Appearance")] + [DefaultValue(typeof(Color), "GrayText")] + public Color InactiveForeColor + { + get { return _inactiveForeColor; } + set { _inactiveForeColor = value; } + } + + [Category("Appearance")] + [DefaultValue(typeof(Color), "InactiveBorder")] + public Color InactiveBackColor + { + get { return _inactiveBackColor; } + set { _inactiveBackColor = value; } + } + + [Category("Appearance")] + [DefaultValue(typeof(Cursor), "IBeam")] + public override Cursor Cursor + { + get { return base.Cursor; } + set { base.Cursor = value; } + } + + [Browsable(false)] + public override Color ForeColor + { + get { return base.ForeColor; } + set { base.ForeColor = value; } + } + + [Browsable(false)] + public override Color BackColor + { + get + { + return base.BackColor; + } + set + { + base.BackColor = value; + } + } + + [Category("Appearance")] + [DefaultValue(typeof(string), DefaultInactiveText)] + public string InactiveText + { + get + { + return _inactiveText; + } + set + { + _inactiveText = value; + + searchOverlayLabel.Text = value; + } + } + + [Category("Appearance")] + [DefaultValue(typeof(Font), "Microsoft Sans Serif, 8.25pt")] + public Font ActiveFont + { + get { return base.Font; } + set { base.Font = value; } + } + + [Category("Appearance")] + [DefaultValue(typeof(Font), "Microsoft Sans Serif, 8.25pt, Italic")] + public Font InactiveFont + { + get { return _inactiveFont; } + set { _inactiveFont = value; } + } + + [Browsable(false)] + public override Font Font + { + get { return base.Font; } + set { base.Font = value; } + } + + [Category("Appearance")] + public override string Text + { + get { return searchText.Text; } + set { searchText.Text = value; } + } + + protected bool TextEntered + { + get { return !String.IsNullOrEmpty(searchText.Text); } + } + + #endregion + + #region Methods + + private void SetActive(bool value) + { + if (TextEntered) + value = true; + + if (_active == value) + return; + + this.BackColor = value ? ActiveBackColor : InactiveBackColor; + this.ForeColor = value ? ActiveForeColor : InactiveForeColor; + + _active = value; + } + + private void SetTextActive(bool value) + { + bool active = value || TextEntered; + + this.searchOverlayLabel.Visible = !active; + this.searchText.Visible = active; + + if (value && !searchText.Focused) + this.searchText.Select(); + } + + #endregion + + #region Event Methods + + protected override void OnGotFocus(EventArgs e) + { + SetTextActive(true); + SetActive(true); + + base.OnGotFocus(e); + } + + protected override void OnLostFocus(EventArgs e) + { + if (this.searchText.Focused) + return; + + SetTextActive(false); + SetActive(false); + + base.OnLostFocus(e); + } + + protected override void OnClick(EventArgs e) + { + this.Select(); + + base.OnClick(e); + } + + protected override void OnForeColorChanged(EventArgs e) + { + this.searchText.ForeColor = this.ForeColor; + + base.OnForeColorChanged(e); + } + + protected override void OnBackColorChanged(EventArgs e) + { + this.searchOverlayLabel.BackColor = this.BackColor; + this.searchText.BackColor = this.BackColor; + + base.OnBackColorChanged(e); + } + + protected override void OnTextChanged(EventArgs e) + { + searchImage.Image = TextEntered ? ProcessHacker.Properties.Resources.active_search : ProcessHacker.Properties.Resources.inactive_search; + + base.OnTextChanged(e); + } + + [DllImport("user32.dll", EntryPoint = "ReleaseCapture")] + public static extern bool StopMouseCapture(); + [DllImport("user32.dll", EntryPoint = "SetCapture")] + public static extern IntPtr StartMouseCapture(IntPtr hWnd); + + private void searchImage_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e) + { + if (e.X < 0 || e.X > searchImage.Width || e.Y < 0 || e.Y > searchImage.Height) + { + StopMouseCapture(); + searchImage.BackColor = Color.Empty; + } + else + { + StartMouseCapture(searchImage.Handle); + if (TextEntered) + searchImage.BackColor = HoverButtonColor; + } + } + + private void searchImage_Click(object sender, System.EventArgs e) + { + if (TextEntered) + { + this.searchText.ResetText(); + OnLostFocus(EventArgs.Empty); + } + } + + private void searchText_TextChanged(object sender, EventArgs e) + { + OnTextChanged(e); + } + + private void searchText_LostFocus(object sender, System.EventArgs e) + { + OnLostFocus(e); + } + + private void searchText_GotFocus(object sender, System.EventArgs e) + { + OnGotFocus(e); + } + + private void searchOverlayLabel_Click(object sender, EventArgs e) + { + OnClick(EventArgs.Empty); + } + + #endregion + + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/VistaSearchBox.designer.cs b/branches/ph-plugins/ProcessHacker/Components/VistaSearchBox.designer.cs new file mode 100644 index 000000000..c47dc9345 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/VistaSearchBox.designer.cs @@ -0,0 +1,96 @@ +namespace ProcessHacker +{ + partial class VistaSearchBox + { + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing) + { + _inactiveFont.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.searchOverlayLabel = new System.Windows.Forms.Label(); + this.searchText = new System.Windows.Forms.TextBox(); + this.searchImage = new System.Windows.Forms.PictureBox(); + ((System.ComponentModel.ISupportInitialize)(this.searchImage)).BeginInit(); + this.SuspendLayout(); + // + // searchOverlayLabel + // + this.searchOverlayLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left))); + this.searchOverlayLabel.AutoSize = true; + this.searchOverlayLabel.Location = new System.Drawing.Point(2, 3); + this.searchOverlayLabel.Margin = new System.Windows.Forms.Padding(0); + this.searchOverlayLabel.Name = "searchOverlayLabel"; + this.searchOverlayLabel.Size = new System.Drawing.Size(0, 13); + this.searchOverlayLabel.TabIndex = 0; + this.searchOverlayLabel.Click += new System.EventHandler(this.searchOverlayLabel_Click); + // + // searchText + // + this.searchText.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.searchText.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.searchText.Location = new System.Drawing.Point(2, 3); + this.searchText.Margin = new System.Windows.Forms.Padding(0); + this.searchText.Name = "searchText"; + this.searchText.Size = new System.Drawing.Size(125, 13); + this.searchText.TabIndex = 0; + this.searchText.TabStop = false; + this.searchText.TextChanged += new System.EventHandler(this.searchText_TextChanged); + this.searchText.GotFocus += new System.EventHandler(this.searchText_GotFocus); + this.searchText.LostFocus += new System.EventHandler(this.searchText_LostFocus); + // + // searchImage + // + this.searchImage.AccessibleRole = System.Windows.Forms.AccessibleRole.PushButton; + this.searchImage.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Right))); + this.searchImage.Cursor = System.Windows.Forms.Cursors.Arrow; + this.searchImage.Image = global::ProcessHacker.Properties.Resources.inactive_search; + this.searchImage.Location = new System.Drawing.Point(127, 0); + this.searchImage.Margin = new System.Windows.Forms.Padding(0); + this.searchImage.Name = "searchImage"; + this.searchImage.Size = new System.Drawing.Size(23, 20); + this.searchImage.TabIndex = 1; + this.searchImage.TabStop = false; + this.searchImage.MouseMove += new System.Windows.Forms.MouseEventHandler(this.searchImage_MouseMove); + this.searchImage.Click += new System.EventHandler(this.searchImage_Click); + // + // SearchTextBox + // + this.BackColor = System.Drawing.SystemColors.Window; + this.Controls.Add(this.searchOverlayLabel); + this.Controls.Add(this.searchText); + this.Controls.Add(this.searchImage); + this.Cursor = System.Windows.Forms.Cursors.IBeam; + this.Size = new System.Drawing.Size(150, 20); + ((System.ComponentModel.ISupportInitialize)(this.searchImage)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label searchOverlayLabel; + private System.Windows.Forms.TextBox searchText; + private System.Windows.Forms.PictureBox searchImage; + } +} diff --git a/branches/ph-plugins/ProcessHacker/Components/VistaSearchBox.resx b/branches/ph-plugins/ProcessHacker/Components/VistaSearchBox.resx new file mode 100644 index 000000000..b3d38127e --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Components/VistaSearchBox.resx @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 95 + + + 17, 56 + + + 17, 17 + + + False + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/AboutWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/AboutWindow.Designer.cs new file mode 100644 index 000000000..3594afa1a --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/AboutWindow.Designer.cs @@ -0,0 +1,540 @@ +namespace ProcessHacker +{ + partial class AboutWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.buttonClose = new System.Windows.Forms.Button(); + this.pictureBox = new System.Windows.Forms.PictureBox(); + this.labelAppName = new System.Windows.Forms.Label(); + this.labelVersion = new System.Windows.Forms.Label(); + this.linkFamFamFam = new System.Windows.Forms.LinkLabel(); + this.linkVistaMenu = new System.Windows.Forms.LinkLabel(); + this.linkHexBox = new System.Windows.Forms.LinkLabel(); + this.labelBy = new System.Windows.Forms.Label(); + this.linkSourceforge = new System.Windows.Forms.LinkLabel(); + this.linkEmail = new System.Windows.Forms.LinkLabel(); + this.linkAsm = new System.Windows.Forms.LinkLabel(); + this.linkTreeViewAdv = new System.Windows.Forms.LinkLabel(); + this.flowCredits = new System.Windows.Forms.FlowLayoutPanel(); + this.label8 = new System.Windows.Forms.Label(); + this.label5 = new System.Windows.Forms.Label(); + this.label12 = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.label6 = new System.Windows.Forms.Label(); + this.label10 = new System.Windows.Forms.Label(); + this.label9 = new System.Windows.Forms.Label(); + this.label7 = new System.Windows.Forms.Label(); + this.label11 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.linkGamingMasteR = new System.Windows.Forms.LinkLabel(); + this.linkKerem = new System.Windows.Forms.LinkLabel(); + this.linkSysinternals = new System.Windows.Forms.LinkLabel(); + this.linkNtInternals = new System.Windows.Forms.LinkLabel(); + this.linkReactOS = new System.Windows.Forms.LinkLabel(); + this.label4 = new System.Windows.Forms.Label(); + this.linkTaskDialog = new System.Windows.Forms.LinkLabel(); + this.linkICSharpCode = new System.Windows.Forms.LinkLabel(); + this.label3 = new System.Windows.Forms.Label(); + this.labelFiller = new System.Windows.Forms.Label(); + this.buttonChangelog = new System.Windows.Forms.Button(); + this.buttonDiagnostics = new System.Windows.Forms.Button(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox)).BeginInit(); + this.flowCredits.SuspendLayout(); + this.SuspendLayout(); + // + // buttonClose + // + this.buttonClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonClose.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonClose.Location = new System.Drawing.Point(420, 320); + this.buttonClose.Name = "buttonClose"; + this.buttonClose.Size = new System.Drawing.Size(75, 23); + this.buttonClose.TabIndex = 7; + this.buttonClose.Text = "&Close"; + this.buttonClose.UseVisualStyleBackColor = true; + this.buttonClose.Click += new System.EventHandler(this.buttonClose_Click); + // + // pictureBox + // + this.pictureBox.Image = global::ProcessHacker.Properties.Resources.ProcessHacker; + this.pictureBox.Location = new System.Drawing.Point(12, 12); + this.pictureBox.Name = "pictureBox"; + this.pictureBox.Size = new System.Drawing.Size(156, 150); + this.pictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; + this.pictureBox.TabIndex = 1; + this.pictureBox.TabStop = false; + // + // labelAppName + // + this.labelAppName.AutoSize = true; + this.labelAppName.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.labelAppName.Location = new System.Drawing.Point(174, 12); + this.labelAppName.Name = "labelAppName"; + this.labelAppName.Size = new System.Drawing.Size(119, 16); + this.labelAppName.TabIndex = 0; + this.labelAppName.Text = "Process Hacker"; + // + // labelVersion + // + this.labelVersion.AutoSize = true; + this.labelVersion.Location = new System.Drawing.Point(174, 33); + this.labelVersion.Name = "labelVersion"; + this.labelVersion.Size = new System.Drawing.Size(42, 13); + this.labelVersion.TabIndex = 1; + this.labelVersion.Text = "Version"; + // + // linkFamFamFam + // + this.linkFamFamFam.AutoSize = true; + this.linkFamFamFam.LinkBehavior = System.Windows.Forms.LinkBehavior.NeverUnderline; + this.linkFamFamFam.Location = new System.Drawing.Point(6, 224); + this.linkFamFamFam.Name = "linkFamFamFam"; + this.linkFamFamFam.Size = new System.Drawing.Size(136, 13); + this.linkFamFamFam.TabIndex = 5; + this.linkFamFamFam.TabStop = true; + this.linkFamFamFam.Text = "famfamfam.com - Silk Icons"; + this.linkFamFamFam.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkFamFamFam_LinkClicked); + // + // linkVistaMenu + // + this.linkVistaMenu.AutoSize = true; + this.linkVistaMenu.LinkBehavior = System.Windows.Forms.LinkBehavior.NeverUnderline; + this.linkVistaMenu.Location = new System.Drawing.Point(6, 237); + this.linkVistaMenu.Name = "linkVistaMenu"; + this.linkVistaMenu.Size = new System.Drawing.Size(183, 13); + this.linkVistaMenu.TabIndex = 6; + this.linkVistaMenu.TabStop = true; + this.linkVistaMenu.Text = "Wyatt O\'Day - VistaMenu, SplitButton"; + this.linkVistaMenu.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkVistaMenu_LinkClicked); + // + // linkHexBox + // + this.linkHexBox.AutoSize = true; + this.linkHexBox.LinkBehavior = System.Windows.Forms.LinkBehavior.NeverUnderline; + this.linkHexBox.Location = new System.Drawing.Point(6, 211); + this.linkHexBox.Name = "linkHexBox"; + this.linkHexBox.Size = new System.Drawing.Size(151, 13); + this.linkHexBox.TabIndex = 7; + this.linkHexBox.TabStop = true; + this.linkHexBox.Text = "Bernhard Elbl - HexBox control"; + this.linkHexBox.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkHexBox_LinkClicked); + // + // labelBy + // + this.labelBy.Location = new System.Drawing.Point(174, 50); + this.labelBy.Name = "labelBy"; + this.labelBy.Size = new System.Drawing.Size(234, 17); + this.labelBy.TabIndex = 2; + this.labelBy.Text = "Licensed under the GNU GPL, v3."; + // + // linkSourceforge + // + this.linkSourceforge.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.linkSourceforge.AutoSize = true; + this.linkSourceforge.Location = new System.Drawing.Point(12, 325); + this.linkSourceforge.Name = "linkSourceforge"; + this.linkSourceforge.Size = new System.Drawing.Size(229, 13); + this.linkSourceforge.TabIndex = 4; + this.linkSourceforge.TabStop = true; + this.linkSourceforge.Text = "http://sourceforge.net/projects/processhacker"; + this.linkSourceforge.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkSourceforge_LinkClicked); + // + // linkEmail + // + this.linkEmail.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.linkEmail.AutoSize = true; + this.linkEmail.Location = new System.Drawing.Point(12, 307); + this.linkEmail.Name = "linkEmail"; + this.linkEmail.Size = new System.Drawing.Size(145, 13); + this.linkEmail.TabIndex = 3; + this.linkEmail.TabStop = true; + this.linkEmail.Text = "Post feedback on our tracker"; + this.linkEmail.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkEmail_LinkClicked); + // + // linkAsm + // + this.linkAsm.AutoSize = true; + this.linkAsm.LinkBehavior = System.Windows.Forms.LinkBehavior.NeverUnderline; + this.linkAsm.Location = new System.Drawing.Point(6, 250); + this.linkAsm.Name = "linkAsm"; + this.linkAsm.Size = new System.Drawing.Size(198, 13); + this.linkAsm.TabIndex = 12; + this.linkAsm.TabStop = true; + this.linkAsm.Text = "Oleh Yuschuk - Disassembler/Assembler"; + this.linkAsm.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkAsm_LinkClicked); + // + // linkTreeViewAdv + // + this.linkTreeViewAdv.AutoSize = true; + this.linkTreeViewAdv.LinkBehavior = System.Windows.Forms.LinkBehavior.NeverUnderline; + this.linkTreeViewAdv.Location = new System.Drawing.Point(6, 263); + this.linkTreeViewAdv.Name = "linkTreeViewAdv"; + this.linkTreeViewAdv.Size = new System.Drawing.Size(165, 13); + this.linkTreeViewAdv.TabIndex = 12; + this.linkTreeViewAdv.TabStop = true; + this.linkTreeViewAdv.Text = "Andrey Gliznetsov - TreeViewAdv"; + this.linkTreeViewAdv.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkTreeViewAdv_LinkClicked); + // + // flowCredits + // + this.flowCredits.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.flowCredits.AutoScroll = true; + this.flowCredits.Controls.Add(this.label8); + this.flowCredits.Controls.Add(this.label5); + this.flowCredits.Controls.Add(this.label12); + this.flowCredits.Controls.Add(this.label1); + this.flowCredits.Controls.Add(this.label6); + this.flowCredits.Controls.Add(this.label10); + this.flowCredits.Controls.Add(this.label9); + this.flowCredits.Controls.Add(this.label7); + this.flowCredits.Controls.Add(this.label11); + this.flowCredits.Controls.Add(this.label2); + this.flowCredits.Controls.Add(this.linkGamingMasteR); + this.flowCredits.Controls.Add(this.linkKerem); + this.flowCredits.Controls.Add(this.linkSysinternals); + this.flowCredits.Controls.Add(this.linkNtInternals); + this.flowCredits.Controls.Add(this.linkReactOS); + this.flowCredits.Controls.Add(this.label4); + this.flowCredits.Controls.Add(this.linkHexBox); + this.flowCredits.Controls.Add(this.linkFamFamFam); + this.flowCredits.Controls.Add(this.linkVistaMenu); + this.flowCredits.Controls.Add(this.linkAsm); + this.flowCredits.Controls.Add(this.linkTreeViewAdv); + this.flowCredits.Controls.Add(this.linkTaskDialog); + this.flowCredits.Controls.Add(this.linkICSharpCode); + this.flowCredits.Controls.Add(this.label3); + this.flowCredits.Controls.Add(this.labelFiller); + this.flowCredits.FlowDirection = System.Windows.Forms.FlowDirection.TopDown; + this.flowCredits.Location = new System.Drawing.Point(177, 70); + this.flowCredits.Name = "flowCredits"; + this.flowCredits.Padding = new System.Windows.Forms.Padding(3); + this.flowCredits.Size = new System.Drawing.Size(318, 215); + this.flowCredits.TabIndex = 14; + this.flowCredits.WrapContents = false; + this.flowCredits.MouseEnter += new System.EventHandler(this.flowCredits_MouseEnter); + // + // label8 + // + this.label8.AutoSize = true; + this.label8.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label8.Location = new System.Drawing.Point(6, 3); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(101, 13); + this.label8.TabIndex = 17; + this.label8.Text = "Project Members"; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(6, 16); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(116, 13); + this.label5.TabIndex = 18; + this.label5.Text = "wj32 - Project Manager"; + // + // label12 + // + this.label12.AutoSize = true; + this.label12.Location = new System.Drawing.Point(6, 29); + this.label12.Name = "label12"; + this.label12.Size = new System.Drawing.Size(90, 13); + this.label12.TabIndex = 29; + this.label12.Text = "dmex - Developer"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(6, 42); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(188, 13); + this.label1.TabIndex = 13; + this.label1.Text = "XhmikosR - Installer Developer, Tester"; + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(6, 55); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(91, 13); + this.label6.TabIndex = 18; + this.label6.Text = "Dean - Developer"; + // + // label10 + // + this.label10.AutoSize = true; + this.label10.Location = new System.Drawing.Point(6, 68); + this.label10.Name = "label10"; + this.label10.Size = new System.Drawing.Size(89, 13); + this.label10.TabIndex = 23; + this.label10.Text = "Fliser - Developer"; + // + // label9 + // + this.label9.AutoSize = true; + this.label9.Location = new System.Drawing.Point(6, 81); + this.label9.Name = "label9"; + this.label9.Size = new System.Drawing.Size(127, 13); + this.label9.TabIndex = 22; + this.label9.Text = "Mikalai Chaly - Developer"; + // + // label7 + // + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(6, 94); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(142, 13); + this.label7.TabIndex = 18; + this.label7.Text = "Uday Shanbhag - Developer"; + // + // label11 + // + this.label11.AutoSize = true; + this.label11.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label11.Location = new System.Drawing.Point(6, 107); + this.label11.Name = "label11"; + this.label11.Size = new System.Drawing.Size(68, 13); + this.label11.TabIndex = 17; + this.label11.Text = "Thanks to:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(6, 120); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(134, 13); + this.label2.TabIndex = 17; + this.label2.Text = "EricJH - Windows 7 testing"; + // + // linkGamingMasteR + // + this.linkGamingMasteR.AutoSize = true; + this.linkGamingMasteR.LinkBehavior = System.Windows.Forms.LinkBehavior.NeverUnderline; + this.linkGamingMasteR.Location = new System.Drawing.Point(6, 133); + this.linkGamingMasteR.Name = "linkGamingMasteR"; + this.linkGamingMasteR.Size = new System.Drawing.Size(210, 13); + this.linkGamingMasteR.TabIndex = 27; + this.linkGamingMasteR.TabStop = true; + this.linkGamingMasteR.Text = "GamingMasteR - Windows internals advice"; + this.linkGamingMasteR.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkGamingMasteR_LinkClicked); + // + // linkKerem + // + this.linkKerem.AutoSize = true; + this.linkKerem.LinkBehavior = System.Windows.Forms.LinkBehavior.NeverUnderline; + this.linkKerem.Location = new System.Drawing.Point(6, 146); + this.linkKerem.Name = "linkKerem"; + this.linkKerem.Size = new System.Drawing.Size(161, 13); + this.linkKerem.TabIndex = 28; + this.linkKerem.TabStop = true; + this.linkKerem.Text = "Kerem Gümrükcü - Bug reporting"; + this.linkKerem.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkKerem_LinkClicked); + // + // linkSysinternals + // + this.linkSysinternals.AutoSize = true; + this.linkSysinternals.LinkBehavior = System.Windows.Forms.LinkBehavior.NeverUnderline; + this.linkSysinternals.Location = new System.Drawing.Point(6, 159); + this.linkSysinternals.Name = "linkSysinternals"; + this.linkSysinternals.Size = new System.Drawing.Size(100, 13); + this.linkSysinternals.TabIndex = 17; + this.linkSysinternals.TabStop = true; + this.linkSysinternals.Text = "Sysinternals Forums"; + this.linkSysinternals.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkSysinternals_LinkClicked); + // + // linkNtInternals + // + this.linkNtInternals.AutoSize = true; + this.linkNtInternals.LinkBehavior = System.Windows.Forms.LinkBehavior.NeverUnderline; + this.linkNtInternals.Location = new System.Drawing.Point(6, 172); + this.linkNtInternals.Name = "linkNtInternals"; + this.linkNtInternals.Size = new System.Drawing.Size(61, 13); + this.linkNtInternals.TabIndex = 24; + this.linkNtInternals.TabStop = true; + this.linkNtInternals.Text = "NTinternals"; + this.linkNtInternals.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkNtInternals_LinkClicked); + // + // linkReactOS + // + this.linkReactOS.AutoSize = true; + this.linkReactOS.LinkBehavior = System.Windows.Forms.LinkBehavior.NeverUnderline; + this.linkReactOS.Location = new System.Drawing.Point(6, 185); + this.linkReactOS.Name = "linkReactOS"; + this.linkReactOS.Size = new System.Drawing.Size(237, 13); + this.linkReactOS.TabIndex = 25; + this.linkReactOS.TabStop = true; + this.linkReactOS.Text = "ReactOS - free, open source Windows NT clone"; + this.linkReactOS.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkReactOS_LinkClicked); + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label4.Location = new System.Drawing.Point(6, 198); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(80, 13); + this.label4.TabIndex = 26; + this.label4.Text = "Components:"; + // + // linkTaskDialog + // + this.linkTaskDialog.AutoSize = true; + this.linkTaskDialog.LinkBehavior = System.Windows.Forms.LinkBehavior.NeverUnderline; + this.linkTaskDialog.Location = new System.Drawing.Point(6, 276); + this.linkTaskDialog.Name = "linkTaskDialog"; + this.linkTaskDialog.Size = new System.Drawing.Size(114, 13); + this.linkTaskDialog.TabIndex = 21; + this.linkTaskDialog.TabStop = true; + this.linkTaskDialog.Text = "KevinGre - TaskDialog"; + this.linkTaskDialog.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkTaskDialog_LinkClicked); + // + // linkICSharpCode + // + this.linkICSharpCode.AutoSize = true; + this.linkICSharpCode.LinkBehavior = System.Windows.Forms.LinkBehavior.NeverUnderline; + this.linkICSharpCode.Location = new System.Drawing.Point(6, 289); + this.linkICSharpCode.Name = "linkICSharpCode"; + this.linkICSharpCode.Size = new System.Drawing.Size(144, 13); + this.linkICSharpCode.TabIndex = 19; + this.linkICSharpCode.TabStop = true; + this.linkICSharpCode.Text = "ic#code - .NET runtime code"; + this.linkICSharpCode.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkICSharpCode_LinkClicked); + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(6, 302); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(0, 13); + this.label3.TabIndex = 15; + // + // labelFiller + // + this.labelFiller.AutoSize = true; + this.labelFiller.Location = new System.Drawing.Point(6, 315); + this.labelFiller.Name = "labelFiller"; + this.labelFiller.Size = new System.Drawing.Size(31, 13); + this.labelFiller.TabIndex = 17; + this.labelFiller.Text = " "; + // + // buttonChangelog + // + this.buttonChangelog.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonChangelog.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonChangelog.Location = new System.Drawing.Point(339, 291); + this.buttonChangelog.Name = "buttonChangelog"; + this.buttonChangelog.Size = new System.Drawing.Size(75, 23); + this.buttonChangelog.TabIndex = 5; + this.buttonChangelog.Text = "Changelog"; + this.buttonChangelog.UseVisualStyleBackColor = true; + this.buttonChangelog.Click += new System.EventHandler(this.buttonChangelog_Click); + // + // buttonDiagnostics + // + this.buttonDiagnostics.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonDiagnostics.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonDiagnostics.Location = new System.Drawing.Point(420, 291); + this.buttonDiagnostics.Name = "buttonDiagnostics"; + this.buttonDiagnostics.Size = new System.Drawing.Size(75, 23); + this.buttonDiagnostics.TabIndex = 6; + this.buttonDiagnostics.Text = "Diagnostics"; + this.buttonDiagnostics.UseVisualStyleBackColor = true; + this.buttonDiagnostics.Click += new System.EventHandler(this.buttonDiagnostics_Click); + // + // AboutWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(507, 355); + this.Controls.Add(this.buttonDiagnostics); + this.Controls.Add(this.buttonChangelog); + this.Controls.Add(this.flowCredits); + this.Controls.Add(this.linkEmail); + this.Controls.Add(this.linkSourceforge); + this.Controls.Add(this.labelBy); + this.Controls.Add(this.labelVersion); + this.Controls.Add(this.labelAppName); + this.Controls.Add(this.pictureBox); + this.Controls.Add(this.buttonClose); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "AboutWindow"; + this.Padding = new System.Windows.Forms.Padding(9); + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "About"; + ((System.ComponentModel.ISupportInitialize)(this.pictureBox)).EndInit(); + this.flowCredits.ResumeLayout(false); + this.flowCredits.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button buttonClose; + private System.Windows.Forms.PictureBox pictureBox; + private System.Windows.Forms.Label labelAppName; + private System.Windows.Forms.Label labelVersion; + private System.Windows.Forms.LinkLabel linkFamFamFam; + private System.Windows.Forms.LinkLabel linkVistaMenu; + private System.Windows.Forms.LinkLabel linkHexBox; + private System.Windows.Forms.Label labelBy; + private System.Windows.Forms.LinkLabel linkSourceforge; + private System.Windows.Forms.LinkLabel linkEmail; + private System.Windows.Forms.LinkLabel linkAsm; + private System.Windows.Forms.LinkLabel linkTreeViewAdv; + private System.Windows.Forms.FlowLayoutPanel flowCredits; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label labelFiller; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.LinkLabel linkICSharpCode; + private System.Windows.Forms.Button buttonChangelog; + private System.Windows.Forms.LinkLabel linkTaskDialog; + private System.Windows.Forms.Label label9; + private System.Windows.Forms.Button buttonDiagnostics; + private System.Windows.Forms.Label label10; + private System.Windows.Forms.Label label11; + private System.Windows.Forms.LinkLabel linkSysinternals; + private System.Windows.Forms.Label label8; + private System.Windows.Forms.LinkLabel linkNtInternals; + private System.Windows.Forms.LinkLabel linkReactOS; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.LinkLabel linkGamingMasteR; + private System.Windows.Forms.LinkLabel linkKerem; + private System.Windows.Forms.Label label12; + + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/AboutWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/AboutWindow.cs new file mode 100644 index 000000000..7f7c24505 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/AboutWindow.cs @@ -0,0 +1,145 @@ +/* + * Process Hacker - + * about window + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Windows.Forms; +using ProcessHacker.Common; + +namespace ProcessHacker +{ + partial class AboutWindow : Form + { + public AboutWindow() + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + labelVersion.Text = Application.ProductVersion; + + buttonChangelog.Visible = System.IO.File.Exists(Application.StartupPath + "\\CHANGELOG.txt"); + } + + private void flowCredits_MouseEnter(object sender, EventArgs e) + { + flowCredits.Select(); + } + + private void buttonClose_Click(object sender, EventArgs e) + { + this.Close(); + } + + private void buttonChangelog_Click(object sender, EventArgs e) + { + try + { + InformationBox box = new InformationBox(System.IO.File.ReadAllText(Application.StartupPath + "\\CHANGELOG.txt")); + + box.ShowSaveButton = false; + box.Title = "Process Hacker Changelog"; + box.ShowDialog(); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to view the changelog", ex); + } + } + + private void buttonDiagnostics_Click(object sender, EventArgs e) + { + InformationBox box = new InformationBox(Program.GetDiagnosticInformation()); + + box.ShowDialog(); + } + + private void linkHexBox_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Program.TryStart("http://sourceforge.net/projects/hexbox"); + } + + private void linkVistaMenu_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Program.TryStart("http://wyday.com"); + } + + private void linkFamFamFam_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Program.TryStart("http://www.famfamfam.com/lab/icons/silk/"); + } + + private void linkSourceforge_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Program.TryStart("http://sourceforge.net/projects/processhacker"); + } + + private void linkEmail_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Program.TryStart("http://sourceforge.net/tracker2/?group_id=242527"); + } + + private void linkAsm_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Program.TryStart("http://www.ollydbg.de"); + } + + private void linkTreeViewAdv_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Program.TryStart("http://sourceforge.net/projects/treeviewadv"); + } + + private void linkICSharpCode_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Program.TryStart("http://www.icsharpcode.net"); + } + + private void linkTaskDialog_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Program.TryStart("http://www.codeproject.com/KB/vista/TaskDialogWinForms.aspx"); + } + + private void linkSysinternals_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Program.TryStart("http://forum.sysinternals.com"); + } + + private void linkNtInternals_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Program.TryStart("http://undocumented.ntinternals.net"); + } + + private void linkReactOS_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Program.TryStart("http://www.reactos.org"); + } + + private void linkGamingMasteR_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Program.TryStart("http://www.at4re.com/download.php?view.1"); + } + + private void linkKerem_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Program.TryStart("http://entwicklung.junetz.de"); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/AboutWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/AboutWindow.resx new file mode 100644 index 000000000..5ea0895e3 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/AboutWindow.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/ChooseColumnsWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/ChooseColumnsWindow.Designer.cs new file mode 100644 index 000000000..7765516fd --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ChooseColumnsWindow.Designer.cs @@ -0,0 +1,114 @@ +namespace ProcessHacker +{ + partial class ChooseColumnsWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.listColumns = new System.Windows.Forms.ListView(); + this.columnColumn = new System.Windows.Forms.ColumnHeader(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.buttonOK = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // listColumns + // + this.listColumns.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listColumns.CheckBoxes = true; + this.listColumns.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnColumn}); + this.listColumns.FullRowSelect = true; + this.listColumns.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None; + this.listColumns.Location = new System.Drawing.Point(12, 12); + this.listColumns.MultiSelect = false; + this.listColumns.Name = "listColumns"; + this.listColumns.ShowItemToolTips = true; + this.listColumns.Size = new System.Drawing.Size(368, 261); + this.listColumns.TabIndex = 0; + this.listColumns.UseCompatibleStateImageBehavior = false; + this.listColumns.View = System.Windows.Forms.View.Details; + // + // columnColumn + // + this.columnColumn.Text = "Column"; + this.columnColumn.Width = 200; + // + // buttonCancel + // + this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonCancel.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonCancel.Location = new System.Drawing.Point(305, 279); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.TabIndex = 2; + this.buttonCancel.Text = "&Cancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click); + // + // buttonOK + // + this.buttonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonOK.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonOK.Location = new System.Drawing.Point(224, 279); + this.buttonOK.Name = "buttonOK"; + this.buttonOK.Size = new System.Drawing.Size(75, 23); + this.buttonOK.TabIndex = 1; + this.buttonOK.Text = "&OK"; + this.buttonOK.UseVisualStyleBackColor = true; + this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click); + // + // ChooseColumnsWindow + // + this.AcceptButton = this.buttonOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(392, 314); + this.Controls.Add(this.buttonOK); + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.listColumns); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ChooseColumnsWindow"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Choose Columns"; + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.ListView listColumns; + private System.Windows.Forms.ColumnHeader columnColumn; + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.Button buttonOK; + + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/ChooseColumnsWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/ChooseColumnsWindow.cs new file mode 100644 index 000000000..000439a25 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ChooseColumnsWindow.cs @@ -0,0 +1,101 @@ +/* + * Process Hacker - + * column chooser + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Windows.Forms; +using Aga.Controls.Tree; +using ProcessHacker.Common; + +namespace ProcessHacker +{ + public partial class ChooseColumnsWindow : Form + { + private object _list; + + public ChooseColumnsWindow(ListView list) + : this() + { + _list = list; + + + foreach (ColumnHeader column in list.Columns) + { + listColumns.Items.Add(new ListViewItem() + { + Text = column.Text, + Name = column.Index.ToString() + }); + } + } + + public ChooseColumnsWindow(TreeViewAdv tree) + : this() + { + _list = tree; + + foreach (TreeColumn column in tree.Columns) + { + listColumns.Items.Add(new ListViewItem() + { + Text = column.Header, + Name = column.Header, + Checked = column.IsVisible + }); + } + } + + private ChooseColumnsWindow() + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + listColumns.SetDoubleBuffered(true); + listColumns.SetTheme("explorer"); + columnColumn.Width = listColumns.Width - 21; + } + + private void buttonCancel_Click(object sender, EventArgs e) + { + this.Close(); + } + + private void buttonOK_Click(object sender, EventArgs e) + { + if (_list is TreeViewAdv) + { + TreeViewAdv tree = _list as TreeViewAdv; + + foreach (TreeColumn column in tree.Columns) + { + column.IsVisible = listColumns.Items[column.Header].Checked; + } + } + else if (_list is ListView) + { + + } + + this.Close(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/ChooseColumnsWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/ChooseColumnsWindow.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ChooseColumnsWindow.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/ComboBoxPickerWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/ComboBoxPickerWindow.Designer.cs new file mode 100644 index 000000000..83ce192c8 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ComboBoxPickerWindow.Designer.cs @@ -0,0 +1,111 @@ +namespace ProcessHacker +{ + partial class ComboBoxPickerWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.labelText = new System.Windows.Forms.Label(); + this.comboBox = new System.Windows.Forms.ComboBox(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.buttonOK = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // labelText + // + this.labelText.AutoSize = true; + this.labelText.Location = new System.Drawing.Point(12, 9); + this.labelText.Name = "labelText"; + this.labelText.Size = new System.Drawing.Size(30, 13); + this.labelText.TabIndex = 0; + this.labelText.Text = "Item:"; + // + // comboBox + // + this.comboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.comboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboBox.FormattingEnabled = true; + this.comboBox.Location = new System.Drawing.Point(12, 35); + this.comboBox.Name = "comboBox"; + this.comboBox.Size = new System.Drawing.Size(318, 21); + this.comboBox.TabIndex = 1; + // + // buttonCancel + // + this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonCancel.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonCancel.Location = new System.Drawing.Point(255, 62); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.TabIndex = 3; + this.buttonCancel.Text = "&Cancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click); + // + // buttonOK + // + this.buttonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonOK.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonOK.Location = new System.Drawing.Point(174, 62); + this.buttonOK.Name = "buttonOK"; + this.buttonOK.Size = new System.Drawing.Size(75, 23); + this.buttonOK.TabIndex = 2; + this.buttonOK.Text = "&OK"; + this.buttonOK.UseVisualStyleBackColor = true; + this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click); + // + // ComboBoxPickerWindow + // + this.AcceptButton = this.buttonOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(342, 97); + this.Controls.Add(this.buttonOK); + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.comboBox); + this.Controls.Add(this.labelText); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ComboBoxPickerWindow"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Choose an item"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label labelText; + private System.Windows.Forms.ComboBox comboBox; + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.Button buttonOK; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/ComboBoxPickerWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/ComboBoxPickerWindow.cs new file mode 100644 index 000000000..7f6ddeb57 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ComboBoxPickerWindow.cs @@ -0,0 +1,77 @@ +/* + * Process Hacker - + * easy-to-use combobox window + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Text; +using System.Windows.Forms; + +namespace ProcessHacker +{ + public partial class ComboBoxPickerWindow : Form + { + public ComboBoxPickerWindow(string[] items) + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + comboBox.Items.AddRange(items); + + if (comboBox.Items.Count > 0) + comboBox.SelectedItem = comboBox.Items[0]; + } + + public string SelectedItem + { + get { return comboBox.SelectedItem as string; } + set { comboBox.SelectedItem = value; } + } + + public string Message + { + get + { + return labelText.Text; + } + set + { + labelText.Text = value; + } + } + + private void buttonOK_Click(object sender, EventArgs e) + { + this.DialogResult = DialogResult.OK; + this.Close(); + } + + private void buttonCancel_Click(object sender, EventArgs e) + { + this.DialogResult = DialogResult.Cancel; + this.Close(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/ComboBoxPickerWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/ComboBoxPickerWindow.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ComboBoxPickerWindow.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/CreateServiceWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/CreateServiceWindow.Designer.cs new file mode 100644 index 000000000..75926e5a6 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/CreateServiceWindow.Designer.cs @@ -0,0 +1,247 @@ +namespace ProcessHacker +{ + partial class CreateServiceWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.comboType = new System.Windows.Forms.ComboBox(); + this.label3 = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.comboStartType = new System.Windows.Forms.ComboBox(); + this.label5 = new System.Windows.Forms.Label(); + this.comboErrorControl = new System.Windows.Forms.ComboBox(); + this.label6 = new System.Windows.Forms.Label(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.buttonOK = new System.Windows.Forms.Button(); + this.textName = new System.Windows.Forms.TextBox(); + this.textDisplayName = new System.Windows.Forms.TextBox(); + this.textBinaryPath = new System.Windows.Forms.TextBox(); + this.buttonBrowse = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 15); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(38, 13); + this.label1.TabIndex = 9; + this.label1.Text = "Name:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(12, 41); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(75, 13); + this.label2.TabIndex = 10; + this.label2.Text = "Display Name:"; + // + // comboType + // + this.comboType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboType.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.comboType.FormattingEnabled = true; + this.comboType.Location = new System.Drawing.Point(100, 64); + this.comboType.Name = "comboType"; + this.comboType.Size = new System.Drawing.Size(156, 21); + this.comboType.TabIndex = 2; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(12, 67); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(34, 13); + this.label3.TabIndex = 11; + this.label3.Text = "Type:"; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(12, 94); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(59, 13); + this.label4.TabIndex = 12; + this.label4.Text = "Start Type:"; + // + // comboStartType + // + this.comboStartType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboStartType.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.comboStartType.FormattingEnabled = true; + this.comboStartType.Location = new System.Drawing.Point(100, 91); + this.comboStartType.Name = "comboStartType"; + this.comboStartType.Size = new System.Drawing.Size(156, 21); + this.comboStartType.TabIndex = 3; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(12, 121); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(68, 13); + this.label5.TabIndex = 13; + this.label5.Text = "Error Control:"; + // + // comboErrorControl + // + this.comboErrorControl.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboErrorControl.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.comboErrorControl.FormattingEnabled = true; + this.comboErrorControl.Location = new System.Drawing.Point(100, 118); + this.comboErrorControl.Name = "comboErrorControl"; + this.comboErrorControl.Size = new System.Drawing.Size(156, 21); + this.comboErrorControl.TabIndex = 4; + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(12, 148); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(64, 13); + this.label6.TabIndex = 14; + this.label6.Text = "Binary Path:"; + // + // buttonCancel + // + this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonCancel.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonCancel.Location = new System.Drawing.Point(329, 185); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.TabIndex = 8; + this.buttonCancel.Text = "Cancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click); + // + // buttonOK + // + this.buttonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonOK.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonOK.Location = new System.Drawing.Point(248, 185); + this.buttonOK.Name = "buttonOK"; + this.buttonOK.Size = new System.Drawing.Size(75, 23); + this.buttonOK.TabIndex = 7; + this.buttonOK.Text = "OK"; + this.buttonOK.UseVisualStyleBackColor = true; + this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click); + // + // textName + // + this.textName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textName.Location = new System.Drawing.Point(100, 12); + this.textName.Name = "textName"; + this.textName.Size = new System.Drawing.Size(304, 20); + this.textName.TabIndex = 0; + // + // textDisplayName + // + this.textDisplayName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textDisplayName.Location = new System.Drawing.Point(100, 38); + this.textDisplayName.Name = "textDisplayName"; + this.textDisplayName.Size = new System.Drawing.Size(304, 20); + this.textDisplayName.TabIndex = 1; + // + // textBinaryPath + // + this.textBinaryPath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBinaryPath.Location = new System.Drawing.Point(100, 145); + this.textBinaryPath.Name = "textBinaryPath"; + this.textBinaryPath.Size = new System.Drawing.Size(223, 20); + this.textBinaryPath.TabIndex = 5; + // + // buttonBrowse + // + this.buttonBrowse.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonBrowse.Location = new System.Drawing.Point(329, 143); + this.buttonBrowse.Name = "buttonBrowse"; + this.buttonBrowse.Size = new System.Drawing.Size(75, 23); + this.buttonBrowse.TabIndex = 6; + this.buttonBrowse.Text = "Browse..."; + this.buttonBrowse.UseVisualStyleBackColor = true; + this.buttonBrowse.Click += new System.EventHandler(this.buttonBrowse_Click); + // + // CreateServiceWindow + // + this.AcceptButton = this.buttonOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(416, 220); + this.Controls.Add(this.buttonBrowse); + this.Controls.Add(this.textBinaryPath); + this.Controls.Add(this.textDisplayName); + this.Controls.Add(this.textName); + this.Controls.Add(this.buttonOK); + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.label6); + this.Controls.Add(this.label5); + this.Controls.Add(this.label4); + this.Controls.Add(this.label3); + this.Controls.Add(this.comboErrorControl); + this.Controls.Add(this.comboStartType); + this.Controls.Add(this.comboType); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "CreateServiceWindow"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Create Service"; + this.Load += new System.EventHandler(this.CreateServiceWindow_Load); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.ComboBox comboType; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.ComboBox comboStartType; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.ComboBox comboErrorControl; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.Button buttonOK; + private System.Windows.Forms.TextBox textName; + private System.Windows.Forms.TextBox textDisplayName; + private System.Windows.Forms.TextBox textBinaryPath; + private System.Windows.Forms.Button buttonBrowse; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/CreateServiceWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/CreateServiceWindow.cs new file mode 100644 index 000000000..7e29a3cfd --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/CreateServiceWindow.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Text; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker +{ + public partial class CreateServiceWindow : Form + { + public CreateServiceWindow() + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + Utils.Fill(comboErrorControl, typeof(ServiceErrorControl)); + Utils.Fill(comboStartType, typeof(ServiceStartType)); + Utils.Fill(comboType, typeof(ServiceType)); + comboType.Items.Add("Win32OwnProcess, InteractiveProcess"); + comboErrorControl.SelectedItem = "Ignore"; + comboStartType.SelectedItem = "DemandStart"; + comboType.SelectedItem = "Win32OwnProcess"; + } + + private void CreateServiceWindow_Load(object sender, EventArgs e) + { + textName.Select(); + } + + private void buttonBrowse_Click(object sender, EventArgs e) + { + OpenFileDialog ofd = new OpenFileDialog(); + + ofd.Filter = "Executable Files (*.exe)|*.exe|All Files (*.*)|*.*"; + ofd.FileName = textBinaryPath.Text; + + if (ofd.ShowDialog() == DialogResult.OK) + textBinaryPath.Text = ofd.FileName; + } + + private void buttonOK_Click(object sender, EventArgs e) + { + try + { + using (var scmhandle = new ServiceManagerHandle(ScManagerAccess.CreateService)) + { + ServiceType serviceType; + + if (comboType.SelectedItem.ToString() == "Win32OwnProcess, InteractiveProcess") + serviceType = ServiceType.Win32OwnProcess | + ServiceType.InteractiveProcess; + else + serviceType = (ServiceType)Enum.Parse(typeof(ServiceType), comboType.SelectedItem.ToString()); + + var startType = (ServiceStartType) + Enum.Parse(typeof(ServiceStartType), comboStartType.SelectedItem.ToString()); + var errorControl = (ServiceErrorControl) + Enum.Parse(typeof(ServiceErrorControl), comboErrorControl.SelectedItem.ToString()); + + scmhandle.CreateService( + textName.Text, + textDisplayName.Text, + serviceType, + startType, + errorControl, + textBinaryPath.Text, + null, + null, + null + ).Dispose(); + this.Close(); + } + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to create the service", ex); + } + } + + private void buttonCancel_Click(object sender, EventArgs e) + { + this.Close(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/CreateServiceWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/CreateServiceWindow.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/CreateServiceWindow.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/EditDEPWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/EditDEPWindow.Designer.cs new file mode 100644 index 000000000..003cd449a --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/EditDEPWindow.Designer.cs @@ -0,0 +1,131 @@ +namespace ProcessHacker +{ + partial class EditDEPWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.comboStatus = new System.Windows.Forms.ComboBox(); + this.buttonOK = new System.Windows.Forms.Button(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.checkPermanent = new System.Windows.Forms.CheckBox(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 15); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(65, 13); + this.label1.TabIndex = 0; + this.label1.Text = "New Status:"; + // + // comboStatus + // + this.comboStatus.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.comboStatus.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboStatus.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.comboStatus.FormattingEnabled = true; + this.comboStatus.Items.AddRange(new object[] { + "Disabled", + "Enabled", + "Enabled, DEP-ATL thunk emulation disabled"}); + this.comboStatus.Location = new System.Drawing.Point(83, 12); + this.comboStatus.Name = "comboStatus"; + this.comboStatus.Size = new System.Drawing.Size(220, 21); + this.comboStatus.TabIndex = 1; + // + // buttonOK + // + this.buttonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonOK.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonOK.Location = new System.Drawing.Point(147, 69); + this.buttonOK.Name = "buttonOK"; + this.buttonOK.Size = new System.Drawing.Size(75, 23); + this.buttonOK.TabIndex = 3; + this.buttonOK.Text = "&OK"; + this.buttonOK.UseVisualStyleBackColor = true; + this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click); + // + // buttonCancel + // + this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonCancel.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonCancel.Location = new System.Drawing.Point(228, 69); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.TabIndex = 4; + this.buttonCancel.Text = "&Cancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click); + // + // checkPermanent + // + this.checkPermanent.AutoSize = true; + this.checkPermanent.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkPermanent.Location = new System.Drawing.Point(12, 39); + this.checkPermanent.Name = "checkPermanent"; + this.checkPermanent.Size = new System.Drawing.Size(83, 18); + this.checkPermanent.TabIndex = 2; + this.checkPermanent.Text = "Permanent"; + this.checkPermanent.UseVisualStyleBackColor = true; + this.checkPermanent.Visible = false; + // + // EditDEPWindow + // + this.AcceptButton = this.buttonOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(315, 104); + this.Controls.Add(this.checkPermanent); + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.buttonOK); + this.Controls.Add(this.comboStatus); + this.Controls.Add(this.label1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "EditDEPWindow"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Edit DEP Status"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.ComboBox comboStatus; + private System.Windows.Forms.Button buttonOK; + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.CheckBox checkPermanent; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/EditDEPWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/EditDEPWindow.cs new file mode 100644 index 000000000..62d29908a --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/EditDEPWindow.cs @@ -0,0 +1,179 @@ +/* + * Process Hacker - + * DEP status editor + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker +{ + public partial class EditDEPWindow : Form + { + private int _pid; + + public EditDEPWindow(int PID) + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + _pid = PID; + + try + { + using (ProcessHandle phandle + = new ProcessHandle(_pid, ProcessAccess.QueryInformation)) + { + var depStatus = phandle.GetDepStatus(); + string str; + + if ((depStatus & DepStatus.Enabled) != 0) + { + str = "Enabled"; + + if ((depStatus & DepStatus.AtlThunkEmulationDisabled) != 0) + str += ", DEP-ATL thunk emulation disabled"; + } + else + { + str = "Disabled"; + } + + comboStatus.SelectedItem = str; + + if (KProcessHacker.Instance != null) + checkPermanent.Visible = true; + } + } + catch + { } + } + + private void buttonOK_Click(object sender, EventArgs e) + { + if (KProcessHacker.Instance != null) + this.SetDepStatusKph(); + else + this.SetDepStatusNoKph(); + } + + private void SetDepStatusKph() + { + DepStatus depStatus = DepStatus.Enabled; + + if (comboStatus.SelectedItem.ToString() == "Disabled") + depStatus = 0; + else if (comboStatus.SelectedItem.ToString() == "Enabled") + depStatus = DepStatus.Enabled; + else if (comboStatus.SelectedItem.ToString() == "Enabled, DEP-ATL thunk emulation disabled") + depStatus = DepStatus.Enabled | DepStatus.AtlThunkEmulationDisabled; + else + { + PhUtils.ShowError("Invalid value."); + return; + } + + if (checkPermanent.Checked) + depStatus |= DepStatus.Permanent; + + try + { + using (var phandle = new ProcessHandle(_pid, Program.MinProcessQueryRights)) + phandle.SetDepStatus(depStatus); + + this.DialogResult = DialogResult.OK; + this.Close(); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to set the DEP status", ex); + } + } + + private void SetDepStatusNoKph() + { + if (comboStatus.SelectedItem.ToString().StartsWith("Enabled")) + if (!PhUtils.ShowConfirmMessage( + "set", + "the DEP status", + "Enabling DEP in a process is a permanent action.", + false)) + return; + + DepFlags flags = DepFlags.Enable; + + if (comboStatus.SelectedItem.ToString() == "Disabled") + flags = DepFlags.Disable; + else if (comboStatus.SelectedItem.ToString() == "Enabled") + flags = DepFlags.Enable; + else if (comboStatus.SelectedItem.ToString() == "Enabled, DEP-ATL thunk emulation disabled") + flags = DepFlags.Enable | DepFlags.DisableAtlThunkEmulation; + else + { + PhUtils.ShowError("Invalid value."); + return; + } + + try + { + IntPtr kernel32 = Win32.GetModuleHandle("kernel32.dll"); + IntPtr setProcessDepPolicy = Win32.GetProcAddress(kernel32, "SetProcessDEPPolicy"); + + if (setProcessDepPolicy == IntPtr.Zero) + throw new Exception("This feature is not supported on your version of Windows."); + + using (ProcessHandle phandle = new ProcessHandle(_pid, + Program.MinProcessQueryRights | ProcessAccess.VmOperation | + ProcessAccess.VmRead | ProcessAccess.CreateThread)) + { + var thread = phandle.CreateThreadWin32(setProcessDepPolicy, new IntPtr((int)flags)); + + thread.Wait(1000 * Win32.TimeMsTo100Ns); + + int exitCode = thread.GetExitCode(); + + if (exitCode == 0) + { + throw new Exception("Unspecified error."); + } + } + + this.DialogResult = DialogResult.OK; + this.Close(); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to set the DEP status", ex); + } + } + + private void buttonCancel_Click(object sender, EventArgs e) + { + this.DialogResult = DialogResult.Cancel; + this.Close(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/EditDEPWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/EditDEPWindow.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/EditDEPWindow.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/ErrorDialog.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/ErrorDialog.Designer.cs new file mode 100644 index 000000000..d894fef35 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ErrorDialog.Designer.cs @@ -0,0 +1,163 @@ +namespace ProcessHacker +{ + partial class ErrorDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.labelIntro = new System.Windows.Forms.Label(); + this.buttonContinue = new System.Windows.Forms.Button(); + this.buttonQuit = new System.Windows.Forms.Button(); + this.textException = new System.Windows.Forms.TextBox(); + this.buttonSubmitReport = new System.Windows.Forms.Button(); + this.statusLinkLabel = new System.Windows.Forms.LinkLabel(); + this.label1 = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // labelIntro + // + this.labelIntro.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.labelIntro.Location = new System.Drawing.Point(12, 26); + this.labelIntro.Name = "labelIntro"; + this.labelIntro.Size = new System.Drawing.Size(484, 32); + this.labelIntro.TabIndex = 0; + this.labelIntro.Text = "Please report this error to the Process Hacker team via our bug tracker hosted at" + + " SourceForge by clicking Send Report. You will recieve a tracker item for keeing" + + " track of its resolution status."; + // + // buttonContinue + // + this.buttonContinue.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonContinue.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonContinue.Location = new System.Drawing.Point(421, 331); + this.buttonContinue.Name = "buttonContinue"; + this.buttonContinue.Size = new System.Drawing.Size(75, 23); + this.buttonContinue.TabIndex = 4; + this.buttonContinue.Text = "&Continue"; + this.buttonContinue.UseVisualStyleBackColor = true; + this.buttonContinue.Click += new System.EventHandler(this.buttonContinue_Click); + // + // buttonQuit + // + this.buttonQuit.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonQuit.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonQuit.Location = new System.Drawing.Point(259, 331); + this.buttonQuit.Name = "buttonQuit"; + this.buttonQuit.Size = new System.Drawing.Size(75, 23); + this.buttonQuit.TabIndex = 0; + this.buttonQuit.Text = "&Quit"; + this.buttonQuit.UseVisualStyleBackColor = true; + this.buttonQuit.Click += new System.EventHandler(this.buttonQuit_Click); + // + // textException + // + this.textException.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textException.BackColor = System.Drawing.SystemColors.Control; + this.textException.Location = new System.Drawing.Point(12, 61); + this.textException.Multiline = true; + this.textException.Name = "textException"; + this.textException.ReadOnly = true; + this.textException.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.textException.Size = new System.Drawing.Size(484, 256); + this.textException.TabIndex = 10; + // + // buttonSubmitReport + // + this.buttonSubmitReport.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonSubmitReport.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonSubmitReport.Location = new System.Drawing.Point(340, 331); + this.buttonSubmitReport.Name = "buttonSubmitReport"; + this.buttonSubmitReport.Size = new System.Drawing.Size(75, 23); + this.buttonSubmitReport.TabIndex = 5; + this.buttonSubmitReport.Text = "&Send Report"; + this.buttonSubmitReport.UseVisualStyleBackColor = true; + this.buttonSubmitReport.Click += new System.EventHandler(this.submitReportButton_Click); + // + // statusLinkLabel + // + this.statusLinkLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.statusLinkLabel.AutoSize = true; + this.statusLinkLabel.Enabled = false; + this.statusLinkLabel.Location = new System.Drawing.Point(12, 336); + this.statusLinkLabel.Name = "statusLinkLabel"; + this.statusLinkLabel.Size = new System.Drawing.Size(199, 13); + this.statusLinkLabel.TabIndex = 6; + this.statusLinkLabel.TabStop = true; + this.statusLinkLabel.Text = "Please Wait, Reporting to Bug Tracker..."; + this.statusLinkLabel.Visible = false; + this.statusLinkLabel.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.statusLinkLabel_LinkClicked); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(12, 9); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(334, 13); + this.label1.TabIndex = 12; + this.label1.Text = "An unhandled exception has occured in Process Hacker. "; + // + // ErrorDialog + // + this.AcceptButton = this.buttonQuit; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.SystemColors.Control; + this.ClientSize = new System.Drawing.Size(508, 366); + this.Controls.Add(this.labelIntro); + this.Controls.Add(this.label1); + this.Controls.Add(this.statusLinkLabel); + this.Controls.Add(this.buttonSubmitReport); + this.Controls.Add(this.textException); + this.Controls.Add(this.buttonQuit); + this.Controls.Add(this.buttonContinue); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.MinimumSize = new System.Drawing.Size(524, 200); + this.Name = "ErrorDialog"; + this.ShowIcon = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "Error"; + this.TopMost = true; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label labelIntro; + private System.Windows.Forms.Button buttonContinue; + private System.Windows.Forms.Button buttonQuit; + private System.Windows.Forms.TextBox textException; + private System.Windows.Forms.Button buttonSubmitReport; + private System.Windows.Forms.LinkLabel statusLinkLabel; + private System.Windows.Forms.Label label1; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/ErrorDialog.cs b/branches/ph-plugins/ProcessHacker/Forms/ErrorDialog.cs new file mode 100644 index 000000000..b01c0e0a3 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ErrorDialog.cs @@ -0,0 +1,213 @@ +/* + * Process Hacker - + * unhandled exception dialog + * + * Copyright (C) 2008-2009 wj32 + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Specialized; +using System.Net; +using System.Text.RegularExpressions; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Native.Api; + +namespace ProcessHacker +{ + public partial class ErrorDialog : Form + { + private Exception _exception; + private string _trackerItem; + private bool _isTerminating; + + public ErrorDialog(Exception ex, bool terminating) + { + InitializeComponent(); + + _exception = ex; + _isTerminating = terminating; + + textException.AppendText(_exception.ToString()); + + if (_isTerminating) + buttonContinue.Enabled = false; + + textException.AppendText("\r\n\r\nDIAGNOSTIC INFORMATION\r\n" + Program.GetDiagnosticInformation()); + } + + private void statusLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + if (!string.IsNullOrEmpty(_trackerItem)) + Program.TryStart(_trackerItem); + else + Program.TryStart("http://sourceforge.net/tracker/?atid=1119665&group_id=242527&func=browse"); + } + + private void buttonContinue_Click(object sender, EventArgs e) + { + this.Close(); + } + + private void buttonQuit_Click(object sender, EventArgs e) + { + try + { + Properties.Settings.Default.Save(); + + // Remove the icons or they remain in the system try. + Program.HackerWindow.ExecuteOnIcons((icon) => icon.Visible = false); + Program.HackerWindow.ExecuteOnIcons((icon) => icon.Dispose()); + + // Make sure KPH connection is closed. + if (ProcessHacker.Native.KProcessHacker.Instance != null) + ProcessHacker.Native.KProcessHacker.Instance.Close(); + } + catch (Exception ex) + { + Logging.Log(ex); + } + + Win32.ExitProcess(1); + } + + private void submitReportButton_Click(object sender, EventArgs e) + { + this.buttonContinue.Enabled = false; + this.buttonQuit.Enabled = false; + this.buttonSubmitReport.Enabled = false; + this.statusLinkLabel.Visible = true; + + SFBugReporter wc = new SFBugReporter(); + wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(wc_DownloadProgressChanged); + wc.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wc_DownloadStringCompleted); + + NameValueCollection qc = new NameValueCollection(); + qc.Add("group_id", "242527"); //PH BugTracker ID: Required Do Not Change! + qc.Add("atid", "1119665"); //PH BugTracker group ID (bugs group): Required Do Not Change! + qc.Add("func", "postadd"); //PH BugTracker Function: Required Do Not Change! + qc.Add("category_id", "100"); //100 = null + qc.Add("artifact_group_id", "100"); //100 = null + qc.Add("assigned_to", "100"); //User this report is to be assigned, 100 = null + qc.Add("priority", "5"); //Bug Report Priority, 1 = Low (Blue) 5 = default (Green) + //summary must be completly unique to prevent duplicate submission errors. + qc.Add("summary", Uri.EscapeDataString(_exception.Message) + + " - " + DateTime.Now.ToString("F") + + " - " + DateTime.Now.Ticks.ToString("x")); + qc.Add("details", Uri.EscapeDataString(textException.Text)); + //qc.Add("input_file", FileName); + //qc.Add("file_description", "Error-Report"); + qc.Add("submit", "Add Artifact"); //PH BugTracker Function: Required Do Not Change! + + wc.QueryString = qc; + wc.DownloadStringAsync(new Uri("https://sourceforge.net/tracker/index.php")); + } + + private void wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) + { + //progressBar1.Value = e.ProgressPercentage; + } + + private void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) + { + if (!_isTerminating) + buttonContinue.Enabled = true; + buttonQuit.Enabled = true; + + if (e.Error != null || this.GetTitle(e.Result).Contains("ERROR")) + { + buttonSubmitReport.Enabled = true; + + if (e.Error != null) + { + if (e.Error.InnerException != null) + PhUtils.ShowError("Unable to submit the error report: " + e.Error.InnerException.Message); + else + PhUtils.ShowError("Unable to submit the error report: " + e.Error.Message); + } + else + { + PhUtils.ShowError("Unable to submit the error report: " + this.GetTitle(e.Result)); + } + } + else + { + statusLinkLabel.Enabled = true; + statusLinkLabel.Text = "View SourceForge error report"; + + _trackerItem = GetUrl(Regex.Replace(this.GetResult(e.Result), @"<(.|\n)*?>", string.Empty).Replace("&", "&")); + } + } + + private string GetTitle(string data) + { + //http://regexlib.com/ + Match m = Regex.Match(data, @"\s*(.+?)\s*", RegexOptions.IgnoreCase); + if (m.Success) + { + return m.Groups[1].Value; + } + else + { + return ""; + } + } + + private string GetResult(string data) + { + //http://regexlib.com/ + Match m = Regex.Match(data, @"\s*(.+?)\s*", RegexOptions.IgnoreCase); + if (m.Success) + { + return m.Groups[1].Value; + } + else + { + return ""; + } + } + + private string GetUrl(string data) + { + //http://regexlib.com/ + Match m = Regex.Match(data, @"\b([\d\w\.\/\+\-\?\:]*)((ht|f)tp(s|)\:\/\/|[\d\d\d|\d\d]\.[\d\d\d|\d\d]\.|www\.|\.com|\.net|\.org)([\d\w\.\/\%\+\-\=\&\?\:\\\"\'\,\|\~\;]*)\b", RegexOptions.IgnoreCase); + if (m.Success) + { + return m.Value; + } + else + { + return ""; + } + } + + public partial class SFBugReporter : WebClient + { + protected override WebRequest GetWebRequest(Uri uri) + { + System.Net.HttpWebRequest webRequest = (System.Net.HttpWebRequest)base.GetWebRequest(uri); + webRequest.UserAgent = "Process Hacker " + Application.ProductVersion; + webRequest.Timeout = System.Threading.Timeout.Infinite; + webRequest.ServicePoint.Expect100Continue = true; //fix for Sourceforge's lighttpd Server + webRequest.KeepAlive = true; + return webRequest; + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/ErrorDialog.resx b/branches/ph-plugins/ProcessHacker/Forms/ErrorDialog.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ErrorDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/GetProcAddressWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/GetProcAddressWindow.Designer.cs new file mode 100644 index 000000000..042fd6062 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/GetProcAddressWindow.Designer.cs @@ -0,0 +1,135 @@ +namespace ProcessHacker +{ + partial class GetProcAddressWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.textProcName = new System.Windows.Forms.TextBox(); + this.textProcAddress = new System.Windows.Forms.TextBox(); + this.buttonLookup = new System.Windows.Forms.Button(); + this.buttonClose = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 15); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(109, 13); + this.label1.TabIndex = 4; + this.label1.Text = "Export Name/Ordinal:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(12, 41); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(48, 13); + this.label2.TabIndex = 5; + this.label2.Text = "Address:"; + // + // textProcName + // + this.textProcName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textProcName.Location = new System.Drawing.Point(127, 12); + this.textProcName.Name = "textProcName"; + this.textProcName.Size = new System.Drawing.Size(255, 20); + this.textProcName.TabIndex = 0; + this.textProcName.Leave += new System.EventHandler(this.textProcName_Leave); + this.textProcName.Enter += new System.EventHandler(this.textProcName_Enter); + // + // textProcAddress + // + this.textProcAddress.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textProcAddress.Location = new System.Drawing.Point(127, 38); + this.textProcAddress.Name = "textProcAddress"; + this.textProcAddress.ReadOnly = true; + this.textProcAddress.Size = new System.Drawing.Size(255, 20); + this.textProcAddress.TabIndex = 1; + // + // buttonLookup + // + this.buttonLookup.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonLookup.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonLookup.Location = new System.Drawing.Point(226, 64); + this.buttonLookup.Name = "buttonLookup"; + this.buttonLookup.Size = new System.Drawing.Size(75, 23); + this.buttonLookup.TabIndex = 2; + this.buttonLookup.Text = "&Lookup"; + this.buttonLookup.UseVisualStyleBackColor = true; + this.buttonLookup.Click += new System.EventHandler(this.buttonLookup_Click); + // + // buttonClose + // + this.buttonClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonClose.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonClose.Location = new System.Drawing.Point(307, 64); + this.buttonClose.Name = "buttonClose"; + this.buttonClose.Size = new System.Drawing.Size(75, 23); + this.buttonClose.TabIndex = 3; + this.buttonClose.Text = "&Close"; + this.buttonClose.UseVisualStyleBackColor = true; + this.buttonClose.Click += new System.EventHandler(this.buttonClose_Click); + // + // GetProcAddressWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(394, 99); + this.Controls.Add(this.buttonClose); + this.Controls.Add(this.buttonLookup); + this.Controls.Add(this.textProcAddress); + this.Controls.Add(this.textProcName); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "GetProcAddressWindow"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Get Function Address"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox textProcName; + private System.Windows.Forms.TextBox textProcAddress; + private System.Windows.Forms.Button buttonLookup; + private System.Windows.Forms.Button buttonClose; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/GetProcAddressWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/GetProcAddressWindow.cs new file mode 100644 index 000000000..fccbc20c6 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/GetProcAddressWindow.cs @@ -0,0 +1,100 @@ +/* + * Process Hacker - + * get-procedure-address tool + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Native.Api; + +namespace ProcessHacker +{ + public partial class GetProcAddressWindow : Form + { + private string _fileName; + + public GetProcAddressWindow(string fileName) + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + _fileName = fileName; + + textProcName.Select(); + } + + private void buttonLookup_Click(object sender, EventArgs e) + { + IntPtr module = Win32.LoadLibraryEx(_fileName, IntPtr.Zero, Win32.DontResolveDllReferences); + IntPtr address = IntPtr.Zero; + int ordinal = 0; + + if (module == IntPtr.Zero) + { + textProcAddress.Text = "Could not load library!"; + } + + if ((textProcName.Text.Length > 0) && + (textProcName.Text[0] >= '0' && textProcName.Text[0] <= '9')) + ordinal = (int)BaseConverter.ToNumberParse(textProcName.Text, false); + + if (ordinal != 0) + { + address = Win32.GetProcAddress(module, (ushort)ordinal); + } + else + { + address = Win32.GetProcAddress(module, textProcName.Text); + } + + if (address != IntPtr.Zero) + { + textProcAddress.Text = "0x" + address.ToString("x"); + textProcAddress.SelectAll(); + textProcAddress.Focus(); + } + else + { + textProcAddress.Text = Win32.GetLastErrorMessage(); + } + + // don't unload libraries we didn't load + if (module != IntPtr.Zero) + Win32.FreeLibrary(module); + } + + private void textProcName_Enter(object sender, EventArgs e) + { + this.AcceptButton = buttonLookup; + } + + private void textProcName_Leave(object sender, EventArgs e) + { + this.AcceptButton = null; + } + + private void buttonClose_Click(object sender, EventArgs e) + { + this.Close(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/GetProcAddressWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/GetProcAddressWindow.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/GetProcAddressWindow.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/HackerWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/HackerWindow.Designer.cs new file mode 100644 index 000000000..1717653c8 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/HackerWindow.Designer.cs @@ -0,0 +1,1499 @@ +namespace ProcessHacker +{ + partial class HackerWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(HackerWindow)); + this.menuProcess = new System.Windows.Forms.ContextMenu(); + this.terminateMenuItem = new System.Windows.Forms.MenuItem(); + this.terminateProcessTreeMenuItem = new System.Windows.Forms.MenuItem(); + this.suspendMenuItem = new System.Windows.Forms.MenuItem(); + this.resumeMenuItem = new System.Windows.Forms.MenuItem(); + this.restartProcessMenuItem = new System.Windows.Forms.MenuItem(); + this.reduceWorkingSetProcessMenuItem = new System.Windows.Forms.MenuItem(); + this.virtualizationProcessMenuItem = new System.Windows.Forms.MenuItem(); + this.menuItem5 = new System.Windows.Forms.MenuItem(); + this.affinityProcessMenuItem = new System.Windows.Forms.MenuItem(); + this.createDumpFileProcessMenuItem = new System.Windows.Forms.MenuItem(); + this.terminatorProcessMenuItem = new System.Windows.Forms.MenuItem(); + this.miscellaneousProcessMenuItem = new System.Windows.Forms.MenuItem(); + this.analyzeWaitChainProcessMenuItem = new System.Windows.Forms.MenuItem(); + this.detachFromDebuggerProcessMenuItem = new System.Windows.Forms.MenuItem(); + this.heapsProcessMenuItem = new System.Windows.Forms.MenuItem(); + this.injectDllProcessMenuItem = new System.Windows.Forms.MenuItem(); + this.protectionProcessMenuItem = new System.Windows.Forms.MenuItem(); + this.setTokenProcessMenuItem = new System.Windows.Forms.MenuItem(); + this.VirusTotalMenuItem = new System.Windows.Forms.MenuItem(); + this.priorityMenuItem = new System.Windows.Forms.MenuItem(); + this.realTimeMenuItem = new System.Windows.Forms.MenuItem(); + this.highMenuItem = new System.Windows.Forms.MenuItem(); + this.aboveNormalMenuItem = new System.Windows.Forms.MenuItem(); + this.normalMenuItem = new System.Windows.Forms.MenuItem(); + this.belowNormalMenuItem = new System.Windows.Forms.MenuItem(); + this.idleMenuItem = new System.Windows.Forms.MenuItem(); + this.runAsProcessMenuItem = new System.Windows.Forms.MenuItem(); + this.launchAsUserProcessMenuItem = new System.Windows.Forms.MenuItem(); + this.launchAsThisUserProcessMenuItem = new System.Windows.Forms.MenuItem(); + this.windowProcessMenuItem = new System.Windows.Forms.MenuItem(); + this.bringToFrontProcessMenuItem = new System.Windows.Forms.MenuItem(); + this.restoreProcessMenuItem = new System.Windows.Forms.MenuItem(); + this.minimizeProcessMenuItem = new System.Windows.Forms.MenuItem(); + this.maximizeProcessMenuItem = new System.Windows.Forms.MenuItem(); + this.menuItem15 = new System.Windows.Forms.MenuItem(); + this.closeProcessMenuItem = new System.Windows.Forms.MenuItem(); + this.propertiesProcessMenuItem = new System.Windows.Forms.MenuItem(); + this.menuItem7 = new System.Windows.Forms.MenuItem(); + this.searchProcessMenuItem = new System.Windows.Forms.MenuItem(); + this.reanalyzeProcessMenuItem = new System.Windows.Forms.MenuItem(); + this.copyProcessMenuItem = new System.Windows.Forms.MenuItem(); + this.selectAllProcessMenuItem = new System.Windows.Forms.MenuItem(); + this.toolStripMenuItem9 = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem10 = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem11 = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem12 = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem13 = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem14 = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripMenuItem15 = new System.Windows.Forms.ToolStripMenuItem(); + this.mainMenu = new System.Windows.Forms.MainMenu(this.components); + this.hackerMenuItem = new System.Windows.Forms.MenuItem(); + this.runMenuItem = new System.Windows.Forms.MenuItem(); + this.runAsAdministratorMenuItem = new System.Windows.Forms.MenuItem(); + this.runAsMenuItem = new System.Windows.Forms.MenuItem(); + this.runAsServiceMenuItem = new System.Windows.Forms.MenuItem(); + this.showDetailsForAllProcessesMenuItem = new System.Windows.Forms.MenuItem(); + this.uacSeparatorMenuItem = new System.Windows.Forms.MenuItem(); + this.saveMenuItem = new System.Windows.Forms.MenuItem(); + this.findHandlesMenuItem = new System.Windows.Forms.MenuItem(); + this.inspectPEFileMenuItem = new System.Windows.Forms.MenuItem(); + this.reloadStructsMenuItem = new System.Windows.Forms.MenuItem(); + this.optionsMenuItem = new System.Windows.Forms.MenuItem(); + this.menuItem2 = new System.Windows.Forms.MenuItem(); + this.shutdownMenuItem = new System.Windows.Forms.MenuItem(); + this.exitMenuItem = new System.Windows.Forms.MenuItem(); + this.viewMenuItem = new System.Windows.Forms.MenuItem(); + this.toolbarMenuItem = new System.Windows.Forms.MenuItem(); + this.sysInfoMenuItem = new System.Windows.Forms.MenuItem(); + this.trayIconsMenuItem = new System.Windows.Forms.MenuItem(); + this.cpuHistoryMenuItem = new System.Windows.Forms.MenuItem(); + this.cpuUsageMenuItem = new System.Windows.Forms.MenuItem(); + this.ioHistoryMenuItem = new System.Windows.Forms.MenuItem(); + this.commitHistoryMenuItem = new System.Windows.Forms.MenuItem(); + this.physMemHistoryMenuItem = new System.Windows.Forms.MenuItem(); + this.menuItem3 = new System.Windows.Forms.MenuItem(); + this.updateNowMenuItem = new System.Windows.Forms.MenuItem(); + this.updateProcessesMenuItem = new System.Windows.Forms.MenuItem(); + this.updateServicesMenuItem = new System.Windows.Forms.MenuItem(); + this.toolsMenuItem = new System.Windows.Forms.MenuItem(); + this.createServiceMenuItem = new System.Windows.Forms.MenuItem(); + this.hiddenProcessesMenuItem = new System.Windows.Forms.MenuItem(); + this.verifyFileSignatureMenuItem = new System.Windows.Forms.MenuItem(); + this.usersMenuItem = new System.Windows.Forms.MenuItem(); + this.windowMenuItem = new System.Windows.Forms.MenuItem(); + this.helpMenu = new System.Windows.Forms.MenuItem(); + this.freeMemoryMenuItem = new System.Windows.Forms.MenuItem(); + this.checkForUpdatesMenuItem = new System.Windows.Forms.MenuItem(); + this.menuItem1 = new System.Windows.Forms.MenuItem(); + this.logMenuItem = new System.Windows.Forms.MenuItem(); + this.helpMenuItem = new System.Windows.Forms.MenuItem(); + this.donateMenuItem = new System.Windows.Forms.MenuItem(); + this.aboutMenuItem = new System.Windows.Forms.MenuItem(); + this.statusBar = new System.Windows.Forms.StatusBar(); + this.statusGeneral = new System.Windows.Forms.StatusBarPanel(); + this.statusCPU = new System.Windows.Forms.StatusBarPanel(); + this.statusMemory = new System.Windows.Forms.StatusBarPanel(); + this.tabControl = new System.Windows.Forms.TabControl(); + this.tabProcesses = new System.Windows.Forms.TabPage(); + this.treeProcesses = new ProcessHacker.ProcessTree(); + this.tabServices = new System.Windows.Forms.TabPage(); + this.listServices = new ProcessHacker.Components.ServiceList(); + this.tabNetwork = new System.Windows.Forms.TabPage(); + this.listNetwork = new ProcessHacker.Components.NetworkList(); + this.toolStrip = new System.Windows.Forms.ToolStrip(); + this.refreshToolStripButton = new System.Windows.Forms.ToolStripButton(); + this.optionsToolStripButton = new System.Windows.Forms.ToolStripButton(); + this.shutDownToolStripMenuItem = new System.Windows.Forms.ToolStripDropDownButton(); + this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); + this.findHandlesToolStripButton = new System.Windows.Forms.ToolStripButton(); + this.sysInfoToolStripButton = new System.Windows.Forms.ToolStripButton(); + this.menuService = new System.Windows.Forms.ContextMenu(); + this.goToProcessServiceMenuItem = new System.Windows.Forms.MenuItem(); + this.startServiceMenuItem = new System.Windows.Forms.MenuItem(); + this.continueServiceMenuItem = new System.Windows.Forms.MenuItem(); + this.pauseServiceMenuItem = new System.Windows.Forms.MenuItem(); + this.stopServiceMenuItem = new System.Windows.Forms.MenuItem(); + this.deleteServiceMenuItem = new System.Windows.Forms.MenuItem(); + this.propertiesServiceMenuItem = new System.Windows.Forms.MenuItem(); + this.menuItem8 = new System.Windows.Forms.MenuItem(); + this.copyServiceMenuItem = new System.Windows.Forms.MenuItem(); + this.selectAllServiceMenuItem = new System.Windows.Forms.MenuItem(); + this.menuIcon = new System.Windows.Forms.ContextMenu(); + this.showHideMenuItem = new System.Windows.Forms.MenuItem(); + this.sysInformationIconMenuItem = new System.Windows.Forms.MenuItem(); + this.networkInfomationMenuItem = new System.Windows.Forms.MenuItem(); + this.notificationsMenuItem = new System.Windows.Forms.MenuItem(); + this.enableAllNotificationsMenuItem = new System.Windows.Forms.MenuItem(); + this.disableAllNotificationsMenuItem = new System.Windows.Forms.MenuItem(); + this.menuItem4 = new System.Windows.Forms.MenuItem(); + this.NPMenuItem = new System.Windows.Forms.MenuItem(); + this.TPMenuItem = new System.Windows.Forms.MenuItem(); + this.NSMenuItem = new System.Windows.Forms.MenuItem(); + this.startedSMenuItem = new System.Windows.Forms.MenuItem(); + this.stoppedSMenuItem = new System.Windows.Forms.MenuItem(); + this.DSMenuItem = new System.Windows.Forms.MenuItem(); + this.processesMenuItem = new System.Windows.Forms.MenuItem(); + this.shutdownTrayMenuItem = new System.Windows.Forms.MenuItem(); + this.exitTrayMenuItem = new System.Windows.Forms.MenuItem(); + this.goToProcessNetworkMenuItem = new System.Windows.Forms.MenuItem(); + this.copyNetworkMenuItem = new System.Windows.Forms.MenuItem(); + this.closeNetworkMenuItem = new System.Windows.Forms.MenuItem(); + this.menuNetwork = new System.Windows.Forms.ContextMenu(); + this.toolsNetworkMenuItem = new System.Windows.Forms.MenuItem(); + this.whoisNetworkMenuItem = new System.Windows.Forms.MenuItem(); + this.tracertNetworkMenuItem = new System.Windows.Forms.MenuItem(); + this.pingNetworkMenuItem = new System.Windows.Forms.MenuItem(); + this.menuItem6 = new System.Windows.Forms.MenuItem(); + this.selectAllNetworkMenuItem = new System.Windows.Forms.MenuItem(); + this.vistaMenu = new wyDay.Controls.VistaMenu(this.components); + ((System.ComponentModel.ISupportInitialize)(this.statusGeneral)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.statusCPU)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.statusMemory)).BeginInit(); + this.tabControl.SuspendLayout(); + this.tabProcesses.SuspendLayout(); + this.tabServices.SuspendLayout(); + this.tabNetwork.SuspendLayout(); + this.toolStrip.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.vistaMenu)).BeginInit(); + this.SuspendLayout(); + // + // menuProcess + // + this.menuProcess.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.terminateMenuItem, + this.terminateProcessTreeMenuItem, + this.suspendMenuItem, + this.resumeMenuItem, + this.restartProcessMenuItem, + this.reduceWorkingSetProcessMenuItem, + this.virtualizationProcessMenuItem, + this.menuItem5, + this.affinityProcessMenuItem, + this.createDumpFileProcessMenuItem, + this.terminatorProcessMenuItem, + this.miscellaneousProcessMenuItem, + this.priorityMenuItem, + this.runAsProcessMenuItem, + this.windowProcessMenuItem, + this.propertiesProcessMenuItem, + this.menuItem7, + this.searchProcessMenuItem, + this.reanalyzeProcessMenuItem, + this.copyProcessMenuItem, + this.selectAllProcessMenuItem}); + this.menuProcess.Popup += new System.EventHandler(this.menuProcess_Popup); + // + // terminateMenuItem + // + this.vistaMenu.SetImage(this.terminateMenuItem, global::ProcessHacker.Properties.Resources.cross); + this.terminateMenuItem.Index = 0; + this.terminateMenuItem.Shortcut = System.Windows.Forms.Shortcut.Del; + this.terminateMenuItem.Text = "&Terminate"; + this.terminateMenuItem.Click += new System.EventHandler(this.terminateMenuItem_Click); + // + // terminateProcessTreeMenuItem + // + this.terminateProcessTreeMenuItem.Index = 1; + this.terminateProcessTreeMenuItem.Text = "Terminate Process Tree"; + this.terminateProcessTreeMenuItem.Click += new System.EventHandler(this.terminateProcessTreeMenuItem_Click); + // + // suspendMenuItem + // + this.vistaMenu.SetImage(this.suspendMenuItem, global::ProcessHacker.Properties.Resources.control_pause_blue); + this.suspendMenuItem.Index = 2; + this.suspendMenuItem.Text = "&Suspend"; + this.suspendMenuItem.Click += new System.EventHandler(this.suspendMenuItem_Click); + // + // resumeMenuItem + // + this.vistaMenu.SetImage(this.resumeMenuItem, global::ProcessHacker.Properties.Resources.control_play_blue); + this.resumeMenuItem.Index = 3; + this.resumeMenuItem.Text = "&Resume"; + this.resumeMenuItem.Click += new System.EventHandler(this.resumeMenuItem_Click); + // + // restartProcessMenuItem + // + this.restartProcessMenuItem.Index = 4; + this.restartProcessMenuItem.Text = "Restart"; + this.restartProcessMenuItem.Click += new System.EventHandler(this.restartProcessMenuItem_Click); + // + // reduceWorkingSetProcessMenuItem + // + this.reduceWorkingSetProcessMenuItem.Index = 5; + this.reduceWorkingSetProcessMenuItem.Text = "Reduce Working Set"; + this.reduceWorkingSetProcessMenuItem.Click += new System.EventHandler(this.reduceWorkingSetProcessMenuItem_Click); + // + // virtualizationProcessMenuItem + // + this.virtualizationProcessMenuItem.Index = 6; + this.virtualizationProcessMenuItem.Text = "Virtualization"; + this.virtualizationProcessMenuItem.Click += new System.EventHandler(this.virtualizationProcessMenuItem_Click); + // + // menuItem5 + // + this.menuItem5.Index = 7; + this.menuItem5.Text = "-"; + // + // affinityProcessMenuItem + // + this.affinityProcessMenuItem.Index = 8; + this.affinityProcessMenuItem.Text = "Affinity..."; + this.affinityProcessMenuItem.Click += new System.EventHandler(this.affinityProcessMenuItem_Click); + // + // createDumpFileProcessMenuItem + // + this.createDumpFileProcessMenuItem.Index = 9; + this.createDumpFileProcessMenuItem.Text = "Create Dump File..."; + this.createDumpFileProcessMenuItem.Click += new System.EventHandler(this.createDumpFileProcessMenuItem_Click); + // + // terminatorProcessMenuItem + // + this.terminatorProcessMenuItem.Index = 10; + this.terminatorProcessMenuItem.Text = "Terminator"; + this.terminatorProcessMenuItem.Click += new System.EventHandler(this.terminatorProcessMenuItem_Click); + // + // miscellaneousProcessMenuItem + // + this.miscellaneousProcessMenuItem.Index = 11; + this.miscellaneousProcessMenuItem.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.analyzeWaitChainProcessMenuItem, + this.detachFromDebuggerProcessMenuItem, + this.heapsProcessMenuItem, + this.injectDllProcessMenuItem, + this.protectionProcessMenuItem, + this.setTokenProcessMenuItem, + this.VirusTotalMenuItem}); + this.miscellaneousProcessMenuItem.Text = "Miscellaneous"; + // + // analyzeWaitChainProcessMenuItem + // + this.analyzeWaitChainProcessMenuItem.Index = 0; + this.analyzeWaitChainProcessMenuItem.Text = "Analyze Wait Chain"; + this.analyzeWaitChainProcessMenuItem.Click += new System.EventHandler(this.analyzeWaitChainProcessMenuItem_Click); + // + // detachFromDebuggerProcessMenuItem + // + this.detachFromDebuggerProcessMenuItem.Index = 1; + this.detachFromDebuggerProcessMenuItem.Text = "Detach from Debugger"; + this.detachFromDebuggerProcessMenuItem.Click += new System.EventHandler(this.detachFromDebuggerProcessMenuItem_Click); + // + // heapsProcessMenuItem + // + this.heapsProcessMenuItem.Index = 2; + this.heapsProcessMenuItem.Text = "Heaps"; + this.heapsProcessMenuItem.Click += new System.EventHandler(this.heapsProcessMenuItem_Click); + // + // injectDllProcessMenuItem + // + this.injectDllProcessMenuItem.Index = 3; + this.injectDllProcessMenuItem.Text = "Inject DLL..."; + this.injectDllProcessMenuItem.Click += new System.EventHandler(this.injectDllProcessMenuItem_Click); + // + // protectionProcessMenuItem + // + this.protectionProcessMenuItem.Index = 4; + this.protectionProcessMenuItem.Text = "Protection"; + this.protectionProcessMenuItem.Click += new System.EventHandler(this.protectionProcessMenuItem_Click); + // + // setTokenProcessMenuItem + // + this.setTokenProcessMenuItem.Index = 5; + this.setTokenProcessMenuItem.Text = "Set Token..."; + this.setTokenProcessMenuItem.Click += new System.EventHandler(this.setTokenProcessMenuItem_Click); + // + // VirusTotalMenuItem + // + this.VirusTotalMenuItem.Index = 6; + this.VirusTotalMenuItem.Text = "Upload to VirusTotal"; + this.VirusTotalMenuItem.Click += new System.EventHandler(this.virusTotalMenuItem_Click); + // + // priorityMenuItem + // + this.vistaMenu.SetImage(this.priorityMenuItem, global::ProcessHacker.Properties.Resources.control_equalizer_blue); + this.priorityMenuItem.Index = 12; + this.priorityMenuItem.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.realTimeMenuItem, + this.highMenuItem, + this.aboveNormalMenuItem, + this.normalMenuItem, + this.belowNormalMenuItem, + this.idleMenuItem}); + this.priorityMenuItem.Text = "&Priority"; + // + // realTimeMenuItem + // + this.realTimeMenuItem.Index = 0; + this.realTimeMenuItem.RadioCheck = true; + this.realTimeMenuItem.Text = "Real Time"; + this.realTimeMenuItem.Click += new System.EventHandler(this.realTimeMenuItem_Click); + // + // highMenuItem + // + this.highMenuItem.Index = 1; + this.highMenuItem.RadioCheck = true; + this.highMenuItem.Text = "High"; + this.highMenuItem.Click += new System.EventHandler(this.highMenuItem_Click); + // + // aboveNormalMenuItem + // + this.aboveNormalMenuItem.Index = 2; + this.aboveNormalMenuItem.RadioCheck = true; + this.aboveNormalMenuItem.Text = "Above Normal"; + this.aboveNormalMenuItem.Click += new System.EventHandler(this.aboveNormalMenuItem_Click); + // + // normalMenuItem + // + this.normalMenuItem.Index = 3; + this.normalMenuItem.RadioCheck = true; + this.normalMenuItem.Text = "Normal"; + this.normalMenuItem.Click += new System.EventHandler(this.normalMenuItem_Click); + // + // belowNormalMenuItem + // + this.belowNormalMenuItem.Index = 4; + this.belowNormalMenuItem.RadioCheck = true; + this.belowNormalMenuItem.Text = "Below Normal"; + this.belowNormalMenuItem.Click += new System.EventHandler(this.belowNormalMenuItem_Click); + // + // idleMenuItem + // + this.idleMenuItem.Index = 5; + this.idleMenuItem.RadioCheck = true; + this.idleMenuItem.Text = "Idle"; + this.idleMenuItem.Click += new System.EventHandler(this.idleMenuItem_Click); + // + // runAsProcessMenuItem + // + this.runAsProcessMenuItem.Index = 13; + this.runAsProcessMenuItem.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.launchAsUserProcessMenuItem, + this.launchAsThisUserProcessMenuItem}); + this.runAsProcessMenuItem.Text = "Run As"; + // + // launchAsUserProcessMenuItem + // + this.launchAsUserProcessMenuItem.Index = 0; + this.launchAsUserProcessMenuItem.Text = "Launch As User..."; + this.launchAsUserProcessMenuItem.Click += new System.EventHandler(this.launchAsUserProcessMenuItem_Click); + // + // launchAsThisUserProcessMenuItem + // + this.launchAsThisUserProcessMenuItem.Index = 1; + this.launchAsThisUserProcessMenuItem.Text = "Launch As This User..."; + this.launchAsThisUserProcessMenuItem.Click += new System.EventHandler(this.launchAsThisUserProcessMenuItem_Click); + // + // windowProcessMenuItem + // + this.windowProcessMenuItem.Index = 14; + this.windowProcessMenuItem.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.bringToFrontProcessMenuItem, + this.restoreProcessMenuItem, + this.minimizeProcessMenuItem, + this.maximizeProcessMenuItem, + this.menuItem15, + this.closeProcessMenuItem}); + this.windowProcessMenuItem.Text = "&Window"; + // + // bringToFrontProcessMenuItem + // + this.bringToFrontProcessMenuItem.Index = 0; + this.bringToFrontProcessMenuItem.Text = "&Bring to Front"; + this.bringToFrontProcessMenuItem.Click += new System.EventHandler(this.bringToFrontProcessMenuItem_Click); + // + // restoreProcessMenuItem + // + this.restoreProcessMenuItem.Index = 1; + this.restoreProcessMenuItem.Text = "&Restore"; + this.restoreProcessMenuItem.Click += new System.EventHandler(this.restoreProcessMenuItem_Click); + // + // minimizeProcessMenuItem + // + this.minimizeProcessMenuItem.Index = 2; + this.minimizeProcessMenuItem.Text = "&Minimize"; + this.minimizeProcessMenuItem.Click += new System.EventHandler(this.minimizeProcessMenuItem_Click); + // + // maximizeProcessMenuItem + // + this.maximizeProcessMenuItem.Index = 3; + this.maximizeProcessMenuItem.Text = "Ma&ximize"; + this.maximizeProcessMenuItem.Click += new System.EventHandler(this.maximizeProcessMenuItem_Click); + // + // menuItem15 + // + this.menuItem15.Index = 4; + this.menuItem15.Text = "-"; + // + // closeProcessMenuItem + // + this.closeProcessMenuItem.Index = 5; + this.closeProcessMenuItem.Text = "&Close"; + this.closeProcessMenuItem.Click += new System.EventHandler(this.closeProcessMenuItem_Click); + // + // propertiesProcessMenuItem + // + this.propertiesProcessMenuItem.DefaultItem = true; + this.vistaMenu.SetImage(this.propertiesProcessMenuItem, global::ProcessHacker.Properties.Resources.application_form_magnify); + this.propertiesProcessMenuItem.Index = 15; + this.propertiesProcessMenuItem.Text = "&Properties"; + this.propertiesProcessMenuItem.Click += new System.EventHandler(this.propertiesProcessMenuItem_Click); + // + // menuItem7 + // + this.menuItem7.Index = 16; + this.menuItem7.Text = "-"; + // + // searchProcessMenuItem + // + this.searchProcessMenuItem.Index = 17; + this.searchProcessMenuItem.Shortcut = System.Windows.Forms.Shortcut.CtrlM; + this.searchProcessMenuItem.Text = "&Search Online"; + this.searchProcessMenuItem.Click += new System.EventHandler(this.searchProcessMenuItem_Click); + // + // reanalyzeProcessMenuItem + // + this.reanalyzeProcessMenuItem.Index = 18; + this.reanalyzeProcessMenuItem.Text = "Re-analyze"; + this.reanalyzeProcessMenuItem.Click += new System.EventHandler(this.reanalyzeProcessMenuItem_Click); + // + // copyProcessMenuItem + // + this.vistaMenu.SetImage(this.copyProcessMenuItem, global::ProcessHacker.Properties.Resources.page_copy); + this.copyProcessMenuItem.Index = 19; + this.copyProcessMenuItem.Text = "&Copy"; + // + // selectAllProcessMenuItem + // + this.selectAllProcessMenuItem.Index = 20; + this.selectAllProcessMenuItem.Shortcut = System.Windows.Forms.Shortcut.CtrlA; + this.selectAllProcessMenuItem.Text = "Select &All"; + this.selectAllProcessMenuItem.Click += new System.EventHandler(this.selectAllProcessMenuItem_Click); + // + // toolStripMenuItem9 + // + this.toolStripMenuItem9.Name = "toolStripMenuItem9"; + this.toolStripMenuItem9.Size = new System.Drawing.Size(151, 22); + this.toolStripMenuItem9.Text = "Time Critical"; + // + // toolStripMenuItem10 + // + this.toolStripMenuItem10.Name = "toolStripMenuItem10"; + this.toolStripMenuItem10.Size = new System.Drawing.Size(151, 22); + this.toolStripMenuItem10.Text = "Highest"; + // + // toolStripMenuItem11 + // + this.toolStripMenuItem11.Name = "toolStripMenuItem11"; + this.toolStripMenuItem11.Size = new System.Drawing.Size(151, 22); + this.toolStripMenuItem11.Text = "Above Normal"; + // + // toolStripMenuItem12 + // + this.toolStripMenuItem12.Name = "toolStripMenuItem12"; + this.toolStripMenuItem12.Size = new System.Drawing.Size(151, 22); + this.toolStripMenuItem12.Text = "Normal"; + // + // toolStripMenuItem13 + // + this.toolStripMenuItem13.Name = "toolStripMenuItem13"; + this.toolStripMenuItem13.Size = new System.Drawing.Size(151, 22); + this.toolStripMenuItem13.Text = "Below Normal"; + // + // toolStripMenuItem14 + // + this.toolStripMenuItem14.Name = "toolStripMenuItem14"; + this.toolStripMenuItem14.Size = new System.Drawing.Size(151, 22); + this.toolStripMenuItem14.Text = "Lowest"; + // + // toolStripMenuItem15 + // + this.toolStripMenuItem15.Name = "toolStripMenuItem15"; + this.toolStripMenuItem15.Size = new System.Drawing.Size(151, 22); + this.toolStripMenuItem15.Text = "Idle"; + // + // mainMenu + // + this.mainMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.hackerMenuItem, + this.viewMenuItem, + this.toolsMenuItem, + this.usersMenuItem, + this.windowMenuItem, + this.helpMenu}); + // + // hackerMenuItem + // + this.hackerMenuItem.Index = 0; + this.hackerMenuItem.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.runMenuItem, + this.runAsAdministratorMenuItem, + this.runAsMenuItem, + this.runAsServiceMenuItem, + this.showDetailsForAllProcessesMenuItem, + this.uacSeparatorMenuItem, + this.saveMenuItem, + this.findHandlesMenuItem, + this.inspectPEFileMenuItem, + this.reloadStructsMenuItem, + this.optionsMenuItem, + this.menuItem2, + this.shutdownMenuItem, + this.exitMenuItem}); + this.hackerMenuItem.Text = "&Hacker"; + // + // runMenuItem + // + this.runMenuItem.Index = 0; + this.runMenuItem.Shortcut = System.Windows.Forms.Shortcut.CtrlR; + this.runMenuItem.Text = "&Run..."; + this.runMenuItem.Click += new System.EventHandler(this.runMenuItem_Click); + // + // runAsAdministratorMenuItem + // + this.runAsAdministratorMenuItem.Index = 1; + this.runAsAdministratorMenuItem.Text = "Run As Administrator..."; + this.runAsAdministratorMenuItem.Click += new System.EventHandler(this.runAsAdministratorMenuItem_Click); + // + // runAsMenuItem + // + this.runAsMenuItem.Index = 2; + this.runAsMenuItem.Text = "Run As..."; + this.runAsMenuItem.Visible = false; + this.runAsMenuItem.Click += new System.EventHandler(this.runAsMenuItem_Click); + // + // runAsServiceMenuItem + // + this.runAsServiceMenuItem.Index = 3; + this.runAsServiceMenuItem.Text = "Run As..."; + this.runAsServiceMenuItem.Click += new System.EventHandler(this.runAsServiceMenuItem_Click); + // + // showDetailsForAllProcessesMenuItem + // + this.showDetailsForAllProcessesMenuItem.Index = 4; + this.showDetailsForAllProcessesMenuItem.Text = "Show Details for All Processes"; + this.showDetailsForAllProcessesMenuItem.Click += new System.EventHandler(this.showDetailsForAllProcessesMenuItem_Click); + // + // uacSeparatorMenuItem + // + this.uacSeparatorMenuItem.Index = 5; + this.uacSeparatorMenuItem.Text = "-"; + // + // saveMenuItem + // + this.vistaMenu.SetImage(this.saveMenuItem, global::ProcessHacker.Properties.Resources.disk); + this.saveMenuItem.Index = 6; + this.saveMenuItem.Shortcut = System.Windows.Forms.Shortcut.CtrlS; + this.saveMenuItem.Text = "Save..."; + this.saveMenuItem.Click += new System.EventHandler(this.saveMenuItem_Click); + // + // findHandlesMenuItem + // + this.vistaMenu.SetImage(this.findHandlesMenuItem, global::ProcessHacker.Properties.Resources.find); + this.findHandlesMenuItem.Index = 7; + this.findHandlesMenuItem.Shortcut = System.Windows.Forms.Shortcut.CtrlF; + this.findHandlesMenuItem.Text = "&Find Handles or DLLs..."; + this.findHandlesMenuItem.Click += new System.EventHandler(this.findHandlesMenuItem_Click); + // + // inspectPEFileMenuItem + // + this.vistaMenu.SetImage(this.inspectPEFileMenuItem, global::ProcessHacker.Properties.Resources.application_form_magnify); + this.inspectPEFileMenuItem.Index = 8; + this.inspectPEFileMenuItem.Text = "Inspect &PE File..."; + this.inspectPEFileMenuItem.Click += new System.EventHandler(this.inspectPEFileMenuItem_Click); + // + // reloadStructsMenuItem + // + this.vistaMenu.SetImage(this.reloadStructsMenuItem, global::ProcessHacker.Properties.Resources.arrow_refresh); + this.reloadStructsMenuItem.Index = 9; + this.reloadStructsMenuItem.Text = "Reload Struct Definitions"; + this.reloadStructsMenuItem.Click += new System.EventHandler(this.reloadStructsMenuItem_Click); + // + // optionsMenuItem + // + this.vistaMenu.SetImage(this.optionsMenuItem, global::ProcessHacker.Properties.Resources.page_gear); + this.optionsMenuItem.Index = 10; + this.optionsMenuItem.Shortcut = System.Windows.Forms.Shortcut.CtrlO; + this.optionsMenuItem.Text = "&Options..."; + this.optionsMenuItem.Click += new System.EventHandler(this.optionsMenuItem_Click); + // + // menuItem2 + // + this.menuItem2.Index = 11; + this.menuItem2.Text = "-"; + // + // shutdownMenuItem + // + this.shutdownMenuItem.Index = 12; + this.shutdownMenuItem.Text = "Shutdown"; + // + // exitMenuItem + // + this.vistaMenu.SetImage(this.exitMenuItem, global::ProcessHacker.Properties.Resources.door_out); + this.exitMenuItem.Index = 13; + this.exitMenuItem.Text = "E&xit"; + this.exitMenuItem.Click += new System.EventHandler(this.exitMenuItem_Click); + // + // viewMenuItem + // + this.viewMenuItem.Index = 1; + this.viewMenuItem.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.toolbarMenuItem, + this.sysInfoMenuItem, + this.trayIconsMenuItem, + this.menuItem3, + this.updateNowMenuItem, + this.updateProcessesMenuItem, + this.updateServicesMenuItem}); + this.viewMenuItem.Text = "&View"; + // + // toolbarMenuItem + // + this.toolbarMenuItem.Index = 0; + this.toolbarMenuItem.Text = "Toolbar"; + this.toolbarMenuItem.Click += new System.EventHandler(this.toolbarMenuItem_Click); + // + // sysInfoMenuItem + // + this.sysInfoMenuItem.Index = 1; + this.sysInfoMenuItem.Shortcut = System.Windows.Forms.Shortcut.CtrlI; + this.sysInfoMenuItem.Text = "System &Information"; + this.sysInfoMenuItem.Click += new System.EventHandler(this.sysInfoMenuItem_Click); + // + // trayIconsMenuItem + // + this.trayIconsMenuItem.Index = 2; + this.trayIconsMenuItem.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.cpuHistoryMenuItem, + this.cpuUsageMenuItem, + this.ioHistoryMenuItem, + this.commitHistoryMenuItem, + this.physMemHistoryMenuItem}); + this.trayIconsMenuItem.Text = "Tray Icons"; + // + // cpuHistoryMenuItem + // + this.cpuHistoryMenuItem.Index = 0; + this.cpuHistoryMenuItem.Text = "CPU History"; + this.cpuHistoryMenuItem.Click += new System.EventHandler(this.cpuHistoryMenuItem_Click); + // + // cpuUsageMenuItem + // + this.cpuUsageMenuItem.Index = 1; + this.cpuUsageMenuItem.Text = "CPU Usage"; + this.cpuUsageMenuItem.Click += new System.EventHandler(this.cpuUsageMenuItem_Click); + // + // ioHistoryMenuItem + // + this.ioHistoryMenuItem.Index = 2; + this.ioHistoryMenuItem.Text = "I/O History"; + this.ioHistoryMenuItem.Click += new System.EventHandler(this.ioHistoryMenuItem_Click); + // + // commitHistoryMenuItem + // + this.commitHistoryMenuItem.Index = 3; + this.commitHistoryMenuItem.Text = "Commit History"; + this.commitHistoryMenuItem.Click += new System.EventHandler(this.commitHistoryMenuItem_Click); + // + // physMemHistoryMenuItem + // + this.physMemHistoryMenuItem.Index = 4; + this.physMemHistoryMenuItem.Text = "Physical Memory History"; + this.physMemHistoryMenuItem.Click += new System.EventHandler(this.physMemHistoryMenuItem_Click); + // + // menuItem3 + // + this.menuItem3.Index = 3; + this.menuItem3.Text = "-"; + // + // updateNowMenuItem + // + this.vistaMenu.SetImage(this.updateNowMenuItem, global::ProcessHacker.Properties.Resources.arrow_refresh); + this.updateNowMenuItem.Index = 4; + this.updateNowMenuItem.Shortcut = System.Windows.Forms.Shortcut.F5; + this.updateNowMenuItem.Text = "&Refresh"; + this.updateNowMenuItem.Click += new System.EventHandler(this.updateNowMenuItem_Click); + // + // updateProcessesMenuItem + // + this.updateProcessesMenuItem.Index = 5; + this.updateProcessesMenuItem.Text = "Update &Processes"; + this.updateProcessesMenuItem.Click += new System.EventHandler(this.updateProcessesMenuItem_Click); + // + // updateServicesMenuItem + // + this.updateServicesMenuItem.Index = 6; + this.updateServicesMenuItem.Text = "Update &Services"; + this.updateServicesMenuItem.Click += new System.EventHandler(this.updateServicesMenuItem_Click); + // + // toolsMenuItem + // + this.toolsMenuItem.Index = 2; + this.toolsMenuItem.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.createServiceMenuItem, + this.hiddenProcessesMenuItem, + this.verifyFileSignatureMenuItem}); + this.toolsMenuItem.Text = "&Tools"; + // + // createServiceMenuItem + // + this.createServiceMenuItem.Index = 0; + this.createServiceMenuItem.Text = "Create &Service..."; + this.createServiceMenuItem.Click += new System.EventHandler(this.createServiceMenuItem_Click); + // + // hiddenProcessesMenuItem + // + this.hiddenProcessesMenuItem.Index = 1; + this.hiddenProcessesMenuItem.Text = "&Hidden Processes"; + this.hiddenProcessesMenuItem.Click += new System.EventHandler(this.hiddenProcessesMenuItem_Click); + // + // verifyFileSignatureMenuItem + // + this.verifyFileSignatureMenuItem.Index = 2; + this.verifyFileSignatureMenuItem.Text = "&Verify File Signature..."; + this.verifyFileSignatureMenuItem.Click += new System.EventHandler(this.verifyFileSignatureMenuItem_Click); + // + // usersMenuItem + // + this.usersMenuItem.Index = 3; + this.usersMenuItem.Text = "&Users"; + // + // windowMenuItem + // + this.windowMenuItem.Index = 4; + this.windowMenuItem.Text = "&Window"; + // + // helpMenu + // + this.helpMenu.Index = 5; + this.helpMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.freeMemoryMenuItem, + this.checkForUpdatesMenuItem, + this.menuItem1, + this.logMenuItem, + this.helpMenuItem, + this.donateMenuItem, + this.aboutMenuItem}); + this.helpMenu.Text = "H&elp"; + // + // freeMemoryMenuItem + // + this.freeMemoryMenuItem.Index = 0; + this.freeMemoryMenuItem.Text = "Free Memory"; + this.freeMemoryMenuItem.Click += new System.EventHandler(this.freeMemoryMenuItem_Click); + // + // checkForUpdatesMenuItem + // + this.checkForUpdatesMenuItem.Index = 1; + this.checkForUpdatesMenuItem.Text = "Check for Updates"; + this.checkForUpdatesMenuItem.Click += new System.EventHandler(this.checkForUpdatesMenuItem_Click); + // + // menuItem1 + // + this.menuItem1.Index = 2; + this.menuItem1.Text = "-"; + // + // logMenuItem + // + this.vistaMenu.SetImage(this.logMenuItem, global::ProcessHacker.Properties.Resources.page_white_text); + this.logMenuItem.Index = 3; + this.logMenuItem.Shortcut = System.Windows.Forms.Shortcut.CtrlL; + this.logMenuItem.Text = "&Log"; + this.logMenuItem.Click += new System.EventHandler(this.logMenuItem_Click); + // + // helpMenuItem + // + this.vistaMenu.SetImage(this.helpMenuItem, global::ProcessHacker.Properties.Resources.help); + this.helpMenuItem.Index = 4; + this.helpMenuItem.Shortcut = System.Windows.Forms.Shortcut.F1; + this.helpMenuItem.Text = "&Help"; + this.helpMenuItem.Click += new System.EventHandler(this.helpMenuItem_Click); + // + // donateMenuItem + // + this.vistaMenu.SetImage(this.donateMenuItem, global::ProcessHacker.Properties.Resources.money); + this.donateMenuItem.Index = 5; + this.donateMenuItem.Text = "Donate"; + this.donateMenuItem.Click += new System.EventHandler(this.donateMenuItem_Click); + // + // aboutMenuItem + // + this.vistaMenu.SetImage(this.aboutMenuItem, global::ProcessHacker.Properties.Resources.information); + this.aboutMenuItem.Index = 6; + this.aboutMenuItem.Text = "&About"; + this.aboutMenuItem.Click += new System.EventHandler(this.aboutMenuItem_Click); + // + // statusBar + // + this.statusBar.Location = new System.Drawing.Point(0, 350); + this.statusBar.Name = "statusBar"; + this.statusBar.Panels.AddRange(new System.Windows.Forms.StatusBarPanel[] { + this.statusGeneral, + this.statusCPU, + this.statusMemory}); + this.statusBar.ShowPanels = true; + this.statusBar.Size = new System.Drawing.Size(804, 22); + this.statusBar.TabIndex = 5; + // + // statusGeneral + // + this.statusGeneral.AutoSize = System.Windows.Forms.StatusBarPanelAutoSize.Contents; + this.statusGeneral.Name = "statusGeneral"; + this.statusGeneral.Width = 10; + // + // statusCPU + // + this.statusCPU.Name = "statusCPU"; + this.statusCPU.Text = "CPU: 99.99%"; + this.statusCPU.Width = 80; + // + // statusMemory + // + this.statusMemory.Name = "statusMemory"; + this.statusMemory.Text = "Phys. Memory: 50%"; + this.statusMemory.Width = 120; + // + // tabControl + // + this.tabControl.Controls.Add(this.tabProcesses); + this.tabControl.Controls.Add(this.tabServices); + this.tabControl.Controls.Add(this.tabNetwork); + this.tabControl.Dock = System.Windows.Forms.DockStyle.Fill; + this.tabControl.Location = new System.Drawing.Point(0, 25); + this.tabControl.Name = "tabControl"; + this.tabControl.SelectedIndex = 0; + this.tabControl.Size = new System.Drawing.Size(804, 325); + this.tabControl.TabIndex = 6; + this.tabControl.SelectedIndexChanged += new System.EventHandler(this.tabControlBig_SelectedIndexChanged); + // + // tabProcesses + // + this.tabProcesses.Controls.Add(this.treeProcesses); + this.tabProcesses.Location = new System.Drawing.Point(4, 22); + this.tabProcesses.Name = "tabProcesses"; + this.tabProcesses.Padding = new System.Windows.Forms.Padding(3); + this.tabProcesses.Size = new System.Drawing.Size(796, 299); + this.tabProcesses.TabIndex = 0; + this.tabProcesses.Text = "Processes"; + this.tabProcesses.UseVisualStyleBackColor = true; + // + // treeProcesses + // + this.treeProcesses.Dock = System.Windows.Forms.DockStyle.Fill; + this.treeProcesses.Draw = true; + this.treeProcesses.Location = new System.Drawing.Point(3, 3); + this.treeProcesses.Name = "treeProcesses"; + this.treeProcesses.Provider = null; + this.treeProcesses.Size = new System.Drawing.Size(790, 293); + this.treeProcesses.TabIndex = 4; + this.treeProcesses.SelectionChanged += new System.EventHandler(this.treeProcesses_SelectionChanged); + this.treeProcesses.NodeMouseDoubleClick += new System.EventHandler(this.treeProcesses_NodeMouseDoubleClick); + this.treeProcesses.KeyDown += new System.Windows.Forms.KeyEventHandler(this.treeProcesses_KeyDown); + // + // tabServices + // + this.tabServices.Controls.Add(this.listServices); + this.tabServices.Location = new System.Drawing.Point(4, 22); + this.tabServices.Name = "tabServices"; + this.tabServices.Padding = new System.Windows.Forms.Padding(3); + this.tabServices.Size = new System.Drawing.Size(796, 299); + this.tabServices.TabIndex = 1; + this.tabServices.Text = "Services"; + this.tabServices.UseVisualStyleBackColor = true; + // + // listServices + // + this.listServices.Dock = System.Windows.Forms.DockStyle.Fill; + this.listServices.DoubleBuffered = true; + this.listServices.Location = new System.Drawing.Point(3, 3); + this.listServices.Name = "listServices"; + this.listServices.Provider = null; + this.listServices.Size = new System.Drawing.Size(790, 293); + this.listServices.TabIndex = 0; + this.listServices.DoubleClick += new System.EventHandler(this.listServices_DoubleClick); + this.listServices.KeyDown += new System.Windows.Forms.KeyEventHandler(this.listServices_KeyDown); + // + // tabNetwork + // + this.tabNetwork.Controls.Add(this.listNetwork); + this.tabNetwork.Location = new System.Drawing.Point(4, 22); + this.tabNetwork.Name = "tabNetwork"; + this.tabNetwork.Padding = new System.Windows.Forms.Padding(3); + this.tabNetwork.Size = new System.Drawing.Size(796, 299); + this.tabNetwork.TabIndex = 2; + this.tabNetwork.Text = "Network"; + this.tabNetwork.UseVisualStyleBackColor = true; + // + // listNetwork + // + this.listNetwork.Dock = System.Windows.Forms.DockStyle.Fill; + this.listNetwork.DoubleBuffered = true; + this.listNetwork.Location = new System.Drawing.Point(3, 3); + this.listNetwork.Name = "listNetwork"; + this.listNetwork.Provider = null; + this.listNetwork.Size = new System.Drawing.Size(790, 293); + this.listNetwork.TabIndex = 0; + this.listNetwork.DoubleClick += new System.EventHandler(this.listNetwork_DoubleClick); + this.listNetwork.KeyDown += new System.Windows.Forms.KeyEventHandler(this.listNetwork_KeyDown); + // + // toolStrip + // + this.toolStrip.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.toolStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.refreshToolStripButton, + this.optionsToolStripButton, + this.shutDownToolStripMenuItem, + this.toolStripSeparator1, + this.findHandlesToolStripButton, + this.sysInfoToolStripButton}); + this.toolStrip.Location = new System.Drawing.Point(0, 0); + this.toolStrip.Name = "toolStrip"; + this.toolStrip.Size = new System.Drawing.Size(804, 25); + this.toolStrip.TabIndex = 5; + this.toolStrip.Text = "toolStrip1"; + // + // refreshToolStripButton + // + this.refreshToolStripButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.refreshToolStripButton.Image = global::ProcessHacker.Properties.Resources.arrow_refresh; + this.refreshToolStripButton.ImageTransparentColor = System.Drawing.Color.Magenta; + this.refreshToolStripButton.Name = "refreshToolStripButton"; + this.refreshToolStripButton.Size = new System.Drawing.Size(23, 22); + this.refreshToolStripButton.Text = "Refresh"; + this.refreshToolStripButton.ToolTipText = "Refresh (F5)"; + this.refreshToolStripButton.Click += new System.EventHandler(this.refreshToolStripButton_Click); + // + // optionsToolStripButton + // + this.optionsToolStripButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.optionsToolStripButton.Image = global::ProcessHacker.Properties.Resources.cog_edit; + this.optionsToolStripButton.ImageTransparentColor = System.Drawing.Color.Magenta; + this.optionsToolStripButton.Name = "optionsToolStripButton"; + this.optionsToolStripButton.Size = new System.Drawing.Size(23, 22); + this.optionsToolStripButton.Text = "Options"; + this.optionsToolStripButton.ToolTipText = "Options... (Ctrl+O)"; + this.optionsToolStripButton.Click += new System.EventHandler(this.optionsToolStripButton_Click); + // + // shutDownToolStripMenuItem + // + this.shutDownToolStripMenuItem.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.shutDownToolStripMenuItem.Image = global::ProcessHacker.Properties.Resources.lightbulb_off; + this.shutDownToolStripMenuItem.ImageTransparentColor = System.Drawing.Color.Magenta; + this.shutDownToolStripMenuItem.Name = "shutDownToolStripMenuItem"; + this.shutDownToolStripMenuItem.Size = new System.Drawing.Size(29, 22); + this.shutDownToolStripMenuItem.Text = "Shutdown"; + // + // toolStripSeparator1 + // + this.toolStripSeparator1.Name = "toolStripSeparator1"; + this.toolStripSeparator1.Size = new System.Drawing.Size(6, 25); + // + // findHandlesToolStripButton + // + this.findHandlesToolStripButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.findHandlesToolStripButton.Image = global::ProcessHacker.Properties.Resources.find; + this.findHandlesToolStripButton.ImageTransparentColor = System.Drawing.Color.Magenta; + this.findHandlesToolStripButton.Name = "findHandlesToolStripButton"; + this.findHandlesToolStripButton.Size = new System.Drawing.Size(23, 22); + this.findHandlesToolStripButton.Text = "Find Handles or DLLs..."; + this.findHandlesToolStripButton.ToolTipText = "Find Handles or DLLs... (Ctrl+F)"; + this.findHandlesToolStripButton.Click += new System.EventHandler(this.findHandlesToolStripButton_Click); + // + // sysInfoToolStripButton + // + this.sysInfoToolStripButton.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.sysInfoToolStripButton.Image = global::ProcessHacker.Properties.Resources.chart_line; + this.sysInfoToolStripButton.ImageTransparentColor = System.Drawing.Color.Magenta; + this.sysInfoToolStripButton.Name = "sysInfoToolStripButton"; + this.sysInfoToolStripButton.Size = new System.Drawing.Size(23, 22); + this.sysInfoToolStripButton.Text = "System Information..."; + this.sysInfoToolStripButton.ToolTipText = "System Information... (Ctrl+I)"; + this.sysInfoToolStripButton.Click += new System.EventHandler(this.sysInfoToolStripButton_Click); + // + // menuService + // + this.menuService.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.goToProcessServiceMenuItem, + this.startServiceMenuItem, + this.continueServiceMenuItem, + this.pauseServiceMenuItem, + this.stopServiceMenuItem, + this.deleteServiceMenuItem, + this.propertiesServiceMenuItem, + this.menuItem8, + this.copyServiceMenuItem, + this.selectAllServiceMenuItem}); + this.menuService.Popup += new System.EventHandler(this.menuService_Popup); + // + // goToProcessServiceMenuItem + // + this.vistaMenu.SetImage(this.goToProcessServiceMenuItem, global::ProcessHacker.Properties.Resources.arrow_right); + this.goToProcessServiceMenuItem.Index = 0; + this.goToProcessServiceMenuItem.Text = "&Go to Process"; + this.goToProcessServiceMenuItem.Click += new System.EventHandler(this.goToProcessServiceMenuItem_Click); + // + // startServiceMenuItem + // + this.vistaMenu.SetImage(this.startServiceMenuItem, global::ProcessHacker.Properties.Resources.control_play_blue); + this.startServiceMenuItem.Index = 1; + this.startServiceMenuItem.Text = "&Start"; + this.startServiceMenuItem.Click += new System.EventHandler(this.startServiceMenuItem_Click); + // + // continueServiceMenuItem + // + this.continueServiceMenuItem.Index = 2; + this.continueServiceMenuItem.Text = "&Continue"; + this.continueServiceMenuItem.Click += new System.EventHandler(this.continueServiceMenuItem_Click); + // + // pauseServiceMenuItem + // + this.vistaMenu.SetImage(this.pauseServiceMenuItem, global::ProcessHacker.Properties.Resources.control_pause_blue); + this.pauseServiceMenuItem.Index = 3; + this.pauseServiceMenuItem.Text = "&Pause"; + this.pauseServiceMenuItem.Click += new System.EventHandler(this.pauseServiceMenuItem_Click); + // + // stopServiceMenuItem + // + this.vistaMenu.SetImage(this.stopServiceMenuItem, global::ProcessHacker.Properties.Resources.control_stop_blue); + this.stopServiceMenuItem.Index = 4; + this.stopServiceMenuItem.Text = "S&top"; + this.stopServiceMenuItem.Click += new System.EventHandler(this.stopServiceMenuItem_Click); + // + // deleteServiceMenuItem + // + this.vistaMenu.SetImage(this.deleteServiceMenuItem, global::ProcessHacker.Properties.Resources.cross); + this.deleteServiceMenuItem.Index = 5; + this.deleteServiceMenuItem.Shortcut = System.Windows.Forms.Shortcut.Del; + this.deleteServiceMenuItem.Text = "Delete"; + this.deleteServiceMenuItem.Click += new System.EventHandler(this.deleteServiceMenuItem_Click); + // + // propertiesServiceMenuItem + // + this.propertiesServiceMenuItem.DefaultItem = true; + this.vistaMenu.SetImage(this.propertiesServiceMenuItem, global::ProcessHacker.Properties.Resources.application_form_magnify); + this.propertiesServiceMenuItem.Index = 6; + this.propertiesServiceMenuItem.Text = "&Properties"; + this.propertiesServiceMenuItem.Click += new System.EventHandler(this.propertiesServiceMenuItem_Click); + // + // menuItem8 + // + this.menuItem8.Index = 7; + this.menuItem8.Text = "-"; + // + // copyServiceMenuItem + // + this.vistaMenu.SetImage(this.copyServiceMenuItem, global::ProcessHacker.Properties.Resources.page_copy); + this.copyServiceMenuItem.Index = 8; + this.copyServiceMenuItem.Text = "Copy"; + // + // selectAllServiceMenuItem + // + this.selectAllServiceMenuItem.Index = 9; + this.selectAllServiceMenuItem.Shortcut = System.Windows.Forms.Shortcut.CtrlA; + this.selectAllServiceMenuItem.Text = "Select &All"; + this.selectAllServiceMenuItem.Click += new System.EventHandler(this.selectAllServiceMenuItem_Click); + // + // menuIcon + // + this.menuIcon.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.showHideMenuItem, + this.sysInformationIconMenuItem, + this.networkInfomationMenuItem, + this.notificationsMenuItem, + this.processesMenuItem, + this.shutdownTrayMenuItem, + this.exitTrayMenuItem}); + this.menuIcon.Popup += new System.EventHandler(this.menuIcon_Popup); + // + // showHideMenuItem + // + this.showHideMenuItem.Index = 0; + this.showHideMenuItem.Text = "&Show/Hide Process Hacker"; + this.showHideMenuItem.Click += new System.EventHandler(this.showHideMenuItem_Click); + // + // sysInformationIconMenuItem + // + this.sysInformationIconMenuItem.Index = 1; + this.sysInformationIconMenuItem.Text = "System &Information"; + this.sysInformationIconMenuItem.Click += new System.EventHandler(this.sysInformationIconMenuItem_Click); + // + // networkInfomationMenuItem + // + this.networkInfomationMenuItem.Index = 2; + this.networkInfomationMenuItem.Text = "Network Infomation"; + this.networkInfomationMenuItem.Click += new System.EventHandler(this.networkInfomationMenuItem_Click); + // + // notificationsMenuItem + // + this.notificationsMenuItem.Index = 3; + this.notificationsMenuItem.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.enableAllNotificationsMenuItem, + this.disableAllNotificationsMenuItem, + this.menuItem4, + this.NPMenuItem, + this.TPMenuItem, + this.NSMenuItem, + this.startedSMenuItem, + this.stoppedSMenuItem, + this.DSMenuItem}); + this.notificationsMenuItem.Text = "&Notifications"; + // + // enableAllNotificationsMenuItem + // + this.enableAllNotificationsMenuItem.Index = 0; + this.enableAllNotificationsMenuItem.Text = "&Enable All"; + this.enableAllNotificationsMenuItem.Click += new System.EventHandler(this.enableAllNotificationsMenuItem_Click); + // + // disableAllNotificationsMenuItem + // + this.disableAllNotificationsMenuItem.Index = 1; + this.disableAllNotificationsMenuItem.Text = "&Disable All"; + this.disableAllNotificationsMenuItem.Click += new System.EventHandler(this.disableAllNotificationsMenuItem_Click); + // + // menuItem4 + // + this.menuItem4.Index = 2; + this.menuItem4.Text = "-"; + // + // NPMenuItem + // + this.NPMenuItem.Index = 3; + this.NPMenuItem.Text = "New Processes"; + // + // TPMenuItem + // + this.TPMenuItem.Index = 4; + this.TPMenuItem.Text = "Terminated Processes"; + // + // NSMenuItem + // + this.NSMenuItem.Index = 5; + this.NSMenuItem.Text = "New Services"; + // + // startedSMenuItem + // + this.startedSMenuItem.Index = 6; + this.startedSMenuItem.Text = "Started Services"; + // + // stoppedSMenuItem + // + this.stoppedSMenuItem.Index = 7; + this.stoppedSMenuItem.Text = "Stopped Services"; + // + // DSMenuItem + // + this.DSMenuItem.Index = 8; + this.DSMenuItem.Text = "Deleted Services"; + // + // processesMenuItem + // + this.processesMenuItem.Index = 4; + this.processesMenuItem.Text = "&Processes"; + // + // shutdownTrayMenuItem + // + this.shutdownTrayMenuItem.Index = 5; + this.shutdownTrayMenuItem.Text = "Shutdown"; + // + // exitTrayMenuItem + // + this.vistaMenu.SetImage(this.exitTrayMenuItem, global::ProcessHacker.Properties.Resources.door_out); + this.exitTrayMenuItem.Index = 6; + this.exitTrayMenuItem.Text = "E&xit"; + this.exitTrayMenuItem.Click += new System.EventHandler(this.exitTrayMenuItem_Click); + // + // goToProcessNetworkMenuItem + // + this.goToProcessNetworkMenuItem.DefaultItem = true; + this.vistaMenu.SetImage(this.goToProcessNetworkMenuItem, global::ProcessHacker.Properties.Resources.arrow_right); + this.goToProcessNetworkMenuItem.Index = 0; + this.goToProcessNetworkMenuItem.Text = "&Go to Process"; + this.goToProcessNetworkMenuItem.Click += new System.EventHandler(this.goToProcessNetworkMenuItem_Click); + // + // copyNetworkMenuItem + // + this.vistaMenu.SetImage(this.copyNetworkMenuItem, global::ProcessHacker.Properties.Resources.page_copy); + this.copyNetworkMenuItem.Index = 4; + this.copyNetworkMenuItem.Text = "&Copy"; + // + // closeNetworkMenuItem + // + this.vistaMenu.SetImage(this.closeNetworkMenuItem, global::ProcessHacker.Properties.Resources.cross); + this.closeNetworkMenuItem.Index = 2; + this.closeNetworkMenuItem.Text = "Close"; + this.closeNetworkMenuItem.Click += new System.EventHandler(this.closeNetworkMenuItem_Click); + // + // menuNetwork + // + this.menuNetwork.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.goToProcessNetworkMenuItem, + this.toolsNetworkMenuItem, + this.closeNetworkMenuItem, + this.menuItem6, + this.copyNetworkMenuItem, + this.selectAllNetworkMenuItem}); + this.menuNetwork.Popup += new System.EventHandler(this.menuNetwork_Popup); + // + // toolsNetworkMenuItem + // + this.toolsNetworkMenuItem.Index = 1; + this.toolsNetworkMenuItem.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.whoisNetworkMenuItem, + this.tracertNetworkMenuItem, + this.pingNetworkMenuItem}); + this.toolsNetworkMenuItem.Text = "Tools"; + // + // whoisNetworkMenuItem + // + this.whoisNetworkMenuItem.Index = 0; + this.whoisNetworkMenuItem.Text = "Whois"; + this.whoisNetworkMenuItem.Click += new System.EventHandler(this.whoisNetworkMenuItem_Click); + // + // tracertNetworkMenuItem + // + this.tracertNetworkMenuItem.Index = 1; + this.tracertNetworkMenuItem.Text = "Tracert"; + this.tracertNetworkMenuItem.Click += new System.EventHandler(this.tracertNetworkMenuItem_Click); + // + // pingNetworkMenuItem + // + this.pingNetworkMenuItem.Index = 2; + this.pingNetworkMenuItem.Text = "Ping"; + this.pingNetworkMenuItem.Click += new System.EventHandler(this.pingNetworkMenuItem_Click); + // + // menuItem6 + // + this.menuItem6.Index = 3; + this.menuItem6.Text = "-"; + // + // selectAllNetworkMenuItem + // + this.selectAllNetworkMenuItem.Index = 5; + this.selectAllNetworkMenuItem.Text = "Select &All"; + this.selectAllNetworkMenuItem.Click += new System.EventHandler(this.selectAllNetworkMenuItem_Click); + // + // vistaMenu + // + this.vistaMenu.ContainerControl = this; + this.vistaMenu.DelaySetImageCalls = false; + // + // HackerWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(804, 372); + this.Controls.Add(this.tabControl); + this.Controls.Add(this.toolStrip); + this.Controls.Add(this.statusBar); + this.DoubleBuffered = true; + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.KeyPreview = true; + this.Menu = this.mainMenu; + this.Name = "HackerWindow"; + this.Text = "Process Hacker"; + this.Load += new System.EventHandler(this.HackerWindow_Load); + this.SizeChanged += new System.EventHandler(this.HackerWindow_SizeChanged); + this.VisibleChanged += new System.EventHandler(this.HackerWindow_VisibleChanged); + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.HackerWindow_FormClosing); + ((System.ComponentModel.ISupportInitialize)(this.statusGeneral)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.statusCPU)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.statusMemory)).EndInit(); + this.tabControl.ResumeLayout(false); + this.tabProcesses.ResumeLayout(false); + this.tabServices.ResumeLayout(false); + this.tabNetwork.ResumeLayout(false); + this.toolStrip.ResumeLayout(false); + this.toolStrip.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.vistaMenu)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.ContextMenu menuProcess; + private System.Windows.Forms.MenuItem terminateMenuItem; + private System.Windows.Forms.MenuItem suspendMenuItem; + private System.Windows.Forms.MenuItem resumeMenuItem; + private System.Windows.Forms.MenuItem menuItem5; + private System.Windows.Forms.MenuItem priorityMenuItem; + private System.Windows.Forms.MenuItem menuItem7; + private System.Windows.Forms.MenuItem realTimeMenuItem; + private System.Windows.Forms.MenuItem highMenuItem; + private System.Windows.Forms.MenuItem aboveNormalMenuItem; + private System.Windows.Forms.MenuItem normalMenuItem; + private System.Windows.Forms.MenuItem belowNormalMenuItem; + private System.Windows.Forms.MenuItem idleMenuItem; + private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem9; + private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem10; + private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem11; + private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem12; + private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem13; + private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem14; + private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem15; + private wyDay.Controls.VistaMenu vistaMenu; + private System.Windows.Forms.MainMenu mainMenu; + private System.Windows.Forms.MenuItem hackerMenuItem; + private System.Windows.Forms.MenuItem aboutMenuItem; + private System.Windows.Forms.MenuItem optionsMenuItem; + private System.Windows.Forms.MenuItem helpMenuItem; + private System.Windows.Forms.MenuItem exitMenuItem; + private System.Windows.Forms.MenuItem windowMenuItem; + private ProcessHacker.ProcessTree treeProcesses; + private System.Windows.Forms.MenuItem inspectPEFileMenuItem; + private System.Windows.Forms.MenuItem propertiesProcessMenuItem; + private System.Windows.Forms.MenuItem searchProcessMenuItem; + private System.Windows.Forms.StatusBar statusBar; + private System.Windows.Forms.MenuItem logMenuItem; + private System.Windows.Forms.StatusBarPanel statusGeneral; + private System.Windows.Forms.TabControl tabControl; + private System.Windows.Forms.TabPage tabProcesses; + private System.Windows.Forms.TabPage tabServices; + private ProcessHacker.Components.ServiceList listServices; + private System.Windows.Forms.ContextMenu menuService; + private System.Windows.Forms.MenuItem propertiesServiceMenuItem; + private System.Windows.Forms.MenuItem startServiceMenuItem; + private System.Windows.Forms.MenuItem pauseServiceMenuItem; + private System.Windows.Forms.MenuItem stopServiceMenuItem; + private System.Windows.Forms.MenuItem deleteServiceMenuItem; + private System.Windows.Forms.MenuItem continueServiceMenuItem; + private System.Windows.Forms.MenuItem goToProcessServiceMenuItem; + private System.Windows.Forms.MenuItem menuItem8; + private System.Windows.Forms.MenuItem copyServiceMenuItem; + private System.Windows.Forms.MenuItem selectAllServiceMenuItem; + private System.Windows.Forms.MenuItem toolsMenuItem; + private System.Windows.Forms.ContextMenu menuIcon; + private System.Windows.Forms.MenuItem showHideMenuItem; + private System.Windows.Forms.MenuItem exitTrayMenuItem; + private System.Windows.Forms.MenuItem notificationsMenuItem; + private System.Windows.Forms.MenuItem NPMenuItem; + private System.Windows.Forms.MenuItem TPMenuItem; + private System.Windows.Forms.MenuItem NSMenuItem; + private System.Windows.Forms.MenuItem startedSMenuItem; + private System.Windows.Forms.MenuItem stoppedSMenuItem; + private System.Windows.Forms.MenuItem DSMenuItem; + private System.Windows.Forms.MenuItem findHandlesMenuItem; + private System.Windows.Forms.MenuItem affinityProcessMenuItem; + private System.Windows.Forms.MenuItem runAsServiceMenuItem; + private System.Windows.Forms.MenuItem runAsProcessMenuItem; + private System.Windows.Forms.MenuItem launchAsUserProcessMenuItem; + private System.Windows.Forms.MenuItem launchAsThisUserProcessMenuItem; + private System.Windows.Forms.MenuItem sysInfoMenuItem; + private System.Windows.Forms.MenuItem copyProcessMenuItem; + private System.Windows.Forms.MenuItem selectAllProcessMenuItem; + private System.Windows.Forms.MenuItem terminatorProcessMenuItem; + private System.Windows.Forms.MenuItem menuItem2; + private System.Windows.Forms.StatusBarPanel statusCPU; + private System.Windows.Forms.StatusBarPanel statusMemory; + private System.Windows.Forms.MenuItem reloadStructsMenuItem; + private System.Windows.Forms.TabPage tabNetwork; + private ProcessHacker.Components.NetworkList listNetwork; + private System.Windows.Forms.MenuItem sysInformationIconMenuItem; + private System.Windows.Forms.MenuItem hiddenProcessesMenuItem; + private System.Windows.Forms.MenuItem viewMenuItem; + private System.Windows.Forms.MenuItem updateNowMenuItem; + private System.Windows.Forms.MenuItem updateProcessesMenuItem; + private System.Windows.Forms.MenuItem updateServicesMenuItem; + private System.Windows.Forms.MenuItem processesMenuItem; + private System.Windows.Forms.MenuItem restartProcessMenuItem; + private System.Windows.Forms.MenuItem setTokenProcessMenuItem; + private System.Windows.Forms.MenuItem helpMenu; + private System.Windows.Forms.MenuItem menuItem3; + private System.Windows.Forms.MenuItem verifyFileSignatureMenuItem; + private System.Windows.Forms.MenuItem enableAllNotificationsMenuItem; + private System.Windows.Forms.MenuItem disableAllNotificationsMenuItem; + private System.Windows.Forms.MenuItem menuItem4; + private System.Windows.Forms.MenuItem shutdownTrayMenuItem; + private System.Windows.Forms.MenuItem shutdownMenuItem; + private System.Windows.Forms.MenuItem runAsAdministratorMenuItem; + private System.Windows.Forms.MenuItem showDetailsForAllProcessesMenuItem; + private System.Windows.Forms.MenuItem uacSeparatorMenuItem; + private System.Windows.Forms.MenuItem runMenuItem; + private System.Windows.Forms.MenuItem runAsMenuItem; + private System.Windows.Forms.MenuItem freeMemoryMenuItem; + private System.Windows.Forms.MenuItem menuItem1; + private System.Windows.Forms.MenuItem reanalyzeProcessMenuItem; + private System.Windows.Forms.MenuItem reduceWorkingSetProcessMenuItem; + private System.Windows.Forms.MenuItem virtualizationProcessMenuItem; + private System.Windows.Forms.ToolStrip toolStrip; + private System.Windows.Forms.ToolStripButton refreshToolStripButton; + private System.Windows.Forms.ToolStripButton findHandlesToolStripButton; + private System.Windows.Forms.ToolStripButton sysInfoToolStripButton; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; + private System.Windows.Forms.ToolStripDropDownButton shutDownToolStripMenuItem; + private System.Windows.Forms.ToolStripButton optionsToolStripButton; + private System.Windows.Forms.MenuItem toolbarMenuItem; + private System.Windows.Forms.MenuItem saveMenuItem; + private System.Windows.Forms.ContextMenu menuNetwork; + private System.Windows.Forms.MenuItem goToProcessNetworkMenuItem; + private System.Windows.Forms.MenuItem copyNetworkMenuItem; + private System.Windows.Forms.MenuItem menuItem6; + private System.Windows.Forms.MenuItem selectAllNetworkMenuItem; + private System.Windows.Forms.MenuItem injectDllProcessMenuItem; + private System.Windows.Forms.MenuItem terminateProcessTreeMenuItem; + private System.Windows.Forms.MenuItem trayIconsMenuItem; + private System.Windows.Forms.MenuItem cpuHistoryMenuItem; + private System.Windows.Forms.MenuItem cpuUsageMenuItem; + private System.Windows.Forms.MenuItem ioHistoryMenuItem; + private System.Windows.Forms.MenuItem commitHistoryMenuItem; + private System.Windows.Forms.MenuItem physMemHistoryMenuItem; + private System.Windows.Forms.MenuItem closeNetworkMenuItem; + private System.Windows.Forms.MenuItem protectionProcessMenuItem; + private System.Windows.Forms.MenuItem createDumpFileProcessMenuItem; + private System.Windows.Forms.MenuItem miscellaneousProcessMenuItem; + private System.Windows.Forms.MenuItem detachFromDebuggerProcessMenuItem; + private System.Windows.Forms.MenuItem usersMenuItem; + private System.Windows.Forms.MenuItem createServiceMenuItem; + private System.Windows.Forms.MenuItem heapsProcessMenuItem; + private System.Windows.Forms.MenuItem windowProcessMenuItem; + private System.Windows.Forms.MenuItem bringToFrontProcessMenuItem; + private System.Windows.Forms.MenuItem restoreProcessMenuItem; + private System.Windows.Forms.MenuItem minimizeProcessMenuItem; + private System.Windows.Forms.MenuItem maximizeProcessMenuItem; + private System.Windows.Forms.MenuItem menuItem15; + private System.Windows.Forms.MenuItem closeProcessMenuItem; + private System.Windows.Forms.MenuItem checkForUpdatesMenuItem; + private System.Windows.Forms.MenuItem toolsNetworkMenuItem; + private System.Windows.Forms.MenuItem whoisNetworkMenuItem; + private System.Windows.Forms.MenuItem tracertNetworkMenuItem; + private System.Windows.Forms.MenuItem pingNetworkMenuItem; + private System.Windows.Forms.MenuItem VirusTotalMenuItem; + private System.Windows.Forms.MenuItem networkInfomationMenuItem; + private System.Windows.Forms.MenuItem analyzeWaitChainProcessMenuItem; + private System.Windows.Forms.MenuItem donateMenuItem; + } +} + diff --git a/branches/ph-plugins/ProcessHacker/Forms/HackerWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/HackerWindow.cs new file mode 100644 index 000000000..338709e2c --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/HackerWindow.cs @@ -0,0 +1,3459 @@ +/* + * Process Hacker - + * main Process Hacker window + * + * Copyright (C) 2008-2009 Dean + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Threading; +using System.Windows.Forms; +using Aga.Controls.Tree; +using ProcessHacker.Common; +using ProcessHacker.Components; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Debugging; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; +using ProcessHacker.UI; +using ProcessHacker.UI.Actions; +using TaskbarLib; + +namespace ProcessHacker +{ + public partial class HackerWindow : Form + { + public delegate void LogUpdatedEventHandler(KeyValuePair? value); + + private ThumbButtonManager thumbButtonManager; + //private JumpListManager jumpListManager; //Reserved for future use + + private delegate void AddMenuItemDelegate(string text, EventHandler onClick); + + // This entire file is a big monolithic mess. + + #region Variables + + // One-instance windows. + public HelpWindow HelpWindow; + public HandleFilterWindow HandleFilterWindow; + public HiddenProcessesWindow HiddenProcessesWindow; + public LogWindow LogWindow; + public MiniSysInfo MiniSysInfoWindow; // Not used (yet) + + /// + /// The thread for the System Information window. This is to avoid + /// freezing the main window every second to update the graphs. + /// + Thread sysInfoThread; + /// + /// The System Information window. No methods should be called on + /// it directly because it belongs to another thread. + /// + public SysInfoWindow SysInfoWindow; + // The three main providers. They should be accessed using + // Program.ProcessProvider, ServiceProvider and NetworkProvider, + // rsepectively. However, these three variables are remnants of + // the old PH. + /// + /// The processes/system provider. + /// + public ProcessSystemProvider processP; + /// + /// The services provider. + /// + ServiceProvider serviceP; + /// + /// The network connections provider. + /// + NetworkProvider networkP; + + /// + /// The UAC shield bitmap. Used for the various menu items which + /// require UAC elevation. + /// + Bitmap uacShieldIcon; + /// + /// A black icon which all notification icons are set to initially + /// before their first paint. + /// + Icon blackIcon; + /// + /// A dummy UsageIcon to avoid null instance checks in the icon-related + /// functions. + /// + UsageIcon dummyIcon; + /// + /// The list of notification icons. + /// + List notifyIcons = new List(); + /// + /// The CPU history icon, with a history of CPU usage. + /// + CpuHistoryIcon cpuHistoryIcon; + /// + /// The CPU usage icon, which indicates the current CPU usage (no history). + /// Dedicated to those Process Explorer users who don't like the + /// CPU history icon. + /// + CpuUsageIcon cpuUsageIcon; + /// + /// The I/O history icon. + /// + IoHistoryIcon ioHistoryIcon; + /// + /// The commit history icon. + /// + CommitHistoryIcon commitHistoryIcon; + /// + /// The physical memory history icon. + /// + PhysMemHistoryIcon physMemHistoryIcon; + + /// + /// A dictionary relating services to processes. Each key is a PID and + /// each value is a list of service names hosted in that particular process. + /// + Dictionary> processServices = new Dictionary>(); + + /// + /// The number of selected processes. Not used. + /// + int processSelectedItems; + /// + /// The selected PID. + /// + int processSelectedPid = -1; + + /// + /// The PH log, with events such as process creation/termination and various + /// service events. + /// + List> _log = new List>(); + + /// + /// windowhandle owned by the currently selected process. + /// Only populated when the user right-clicks exactly one process. + /// + WindowHandle windowHandle = WindowHandle.Zero; + + #endregion + + #region Properties + + // The following two properties were used by the Window menu system. + // Not very useful, but still needed for now. + + public MenuItem WindowMenuItem + { + get { return windowMenuItem; } + } + + public wyDay.Controls.VistaMenu VistaMenu + { + get { return vistaMenu; } + } + + // Mostly used by Save.cs. + public ProcessTree ProcessTree + { + get { return treeProcesses; } + } + + public int SelectedPid + { + get { return processSelectedPid; } + } + + // The two properties below aren't used at all. + + public ListView ServiceList + { + get { return listServices.List; } + } + + public ListView NetworkList + { + get { return listNetwork.List; } + } + + /// + /// Provides a list of service names hosted by a process. + /// + public IDictionary> ProcessServices + { + get { return processServices; } + } + + /// + /// The PH log. + /// + public IList> Log + { + get { return _log; } + } + + #endregion + + #region Events + + public event LogUpdatedEventHandler LogUpdated; + + #endregion + + #region Event Handlers + + #region Lists + + private void listNetwork_DoubleClick(object sender, EventArgs e) + { + goToProcessNetworkMenuItem_Click(sender, e); + } + + private void listNetwork_KeyDown(object sender, KeyEventArgs e) + { + if (e.KeyCode == Keys.Enter) + { + goToProcessNetworkMenuItem_Click(null, null); + } + } + + private void listServices_DoubleClick(object sender, EventArgs e) + { + propertiesServiceMenuItem_Click(null, null); + } + + private void listServices_KeyDown(object sender, KeyEventArgs e) + { + if (e.KeyCode == Keys.Delete) + { + deleteServiceMenuItem_Click(null, null); + } + else if (e.KeyCode == Keys.Enter) + { + propertiesServiceMenuItem_Click(null, null); + } + } + + #endregion + + #region Main Menu + + private void runMenuItem_Click(object sender, EventArgs e) + { + Win32.RunFileDlg(this.Handle, IntPtr.Zero, null, null, null, 0); + } + + private void runAsMenuItem_Click(object sender, EventArgs e) + { + + } + + private void runAsAdministratorMenuItem_Click(object sender, EventArgs e) + { + PromptBox box = new PromptBox(); + + box.Text = "Enter the command to start"; + box.TextBox.AutoCompleteSource = AutoCompleteSource.AllSystemSources; + box.TextBox.AutoCompleteMode = AutoCompleteMode.SuggestAppend; + + if (box.ShowDialog() == DialogResult.OK) + { + Program.StartProgramAdmin(box.Value, "", null, ShowWindowType.Show, this.Handle); + } + } + + private void runAsServiceMenuItem_Click(object sender, EventArgs e) + { + RunWindow run = new RunWindow(); + run.ShowDialog(); + } + + private void showDetailsForAllProcessesMenuItem_Click(object sender, EventArgs e) + { + Program.StartProcessHackerAdmin("-v", () => + { + this.Exit(); + }, this.Handle); + } + + private void findHandlesMenuItem_Click(object sender, EventArgs e) + { + if (HandleFilterWindow == null) + HandleFilterWindow = new HandleFilterWindow(); + + HandleFilterWindow.Show(); + HandleFilterWindow.Activate(); + } + + private void inspectPEFileMenuItem_Click(object sender, EventArgs e) + { + OpenFileDialog ofd = new OpenFileDialog(); + + if (ofd.ShowDialog() == DialogResult.OK) + { + PEWindow pw = Program.GetPEWindow(ofd.FileName, new Program.PEWindowInvokeAction(delegate(PEWindow f) + { + try + { + f.Show(); + } + catch (Exception ex) + { + Logging.Log(ex); + } + })); + } + } + + private void reloadStructsMenuItem_Click(object sender, EventArgs e) + { + try + { + Program.Structs.Clear(); + Structs.StructParser parser = new ProcessHacker.Structs.StructParser(Program.Structs); + + parser.Parse(Application.StartupPath + "\\structs.txt"); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to load structs", ex); + } + } + + private void sysInfoMenuItem_Click(object sender, EventArgs e) + { + if (sysInfoThread == null || !sysInfoThread.IsAlive) + { + sysInfoThread = new Thread(() => + { + SysInfoWindow = new SysInfoWindow(); + + Application.Run(SysInfoWindow); + }); + sysInfoThread.Start(); + } + else + { + SysInfoWindow.BeginInvoke(new MethodInvoker(delegate + { + SysInfoWindow.Show(); + SysInfoWindow.Activate(); + })); + } + } + + private void logMenuItem_Click(object sender, EventArgs e) + { + if (LogWindow == null || LogWindow.IsDisposed) + { + LogWindow = new LogWindow(); + } + + LogWindow.Show(); + + if (LogWindow.WindowState == FormWindowState.Minimized) + LogWindow.WindowState = FormWindowState.Normal; + + LogWindow.Activate(); + } + + private void aboutMenuItem_Click(object sender, EventArgs e) + { + AboutWindow about = new AboutWindow(); + about.ShowDialog(); + } + + private void optionsMenuItem_Click(object sender, EventArgs e) + { + OptionsWindow options = new OptionsWindow(); + + DialogResult result = options.ShowDialog(); + + if (result == DialogResult.OK) + { + this.LoadOtherSettings(); + } + } + + private void freeMemoryMenuItem_Click(object sender, EventArgs e) + { + Program.CollectGarbage(); + } + + private void helpMenuItem_Click(object sender, EventArgs e) + { + if (HelpWindow == null) + HelpWindow = new HelpWindow(); + + HelpWindow.Show(); + HelpWindow.Activate(); + } + + private void exitMenuItem_Click(object sender, EventArgs e) + { + this.Exit(); + } + + private void toolbarMenuItem_Click(object sender, EventArgs e) + { + toolbarMenuItem.Checked = !toolbarMenuItem.Checked; + toolStrip.Visible = toolbarMenuItem.Checked; + + Properties.Settings.Default.ToolbarVisible = toolStrip.Visible; + Properties.Settings.Default.Save(); + } + + private void updateNowMenuItem_Click(object sender, EventArgs e) + { + if (processP.RunCount > 1) + processP.RunOnce(); + + if (serviceP.RunCount > 1) + serviceP.RunOnce(); + } + + private void updateProcessesMenuItem_Click(object sender, EventArgs e) + { + updateProcessesMenuItem.Checked = !updateProcessesMenuItem.Checked; + processP.Enabled = updateProcessesMenuItem.Checked; + } + + private void updateServicesMenuItem_Click(object sender, EventArgs e) + { + updateServicesMenuItem.Checked = !updateServicesMenuItem.Checked; + serviceP.Enabled = updateServicesMenuItem.Checked; + } + + private void hiddenProcessesMenuItem_Click(object sender, EventArgs e) + { + if (HiddenProcessesWindow == null || HiddenProcessesWindow.IsDisposed) + HiddenProcessesWindow = new HiddenProcessesWindow(); + + HiddenProcessesWindow.Show(); + + if (HiddenProcessesWindow.WindowState == FormWindowState.Minimized) + HiddenProcessesWindow.WindowState = FormWindowState.Normal; + + HiddenProcessesWindow.Activate(); + } + + private void verifyFileSignatureMenuItem_Click(object sender, EventArgs e) + { + OpenFileDialog ofd = new OpenFileDialog(); + + ofd.CheckFileExists = true; + ofd.CheckPathExists = true; + ofd.Filter = "Executable files (*.exe;*.dll;*.sys;*.scr;*.cpl)|*.exe;*.dll;*.sys;*.scr;*.cpl|All files (*.*)|*.*"; + + if (ofd.ShowDialog() == DialogResult.OK) + { + try + { + var result = Cryptography.VerifyFile(ofd.FileName); + string message = ""; + + switch (result) + { + case VerifyResult.Distrust: + message = "is not trusted"; + break; + case VerifyResult.Expired: + message = "has an expired certificate"; + break; + case VerifyResult.NoSignature: + message = "does not have a digital signature"; + break; + case VerifyResult.Revoked: + message = "has a revoked certificate"; + break; + case VerifyResult.SecuritySettings: + message = "could not be verified due to security settings"; + break; + case VerifyResult.Trusted: + message = "is trusted"; + break; + case VerifyResult.Unknown: + message = "could not be verified"; + break; + default: + message = "could not be verified"; + break; + } + + PhUtils.ShowInformation("The file \"" + ofd.FileName + "\" " + message + "."); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to verify the file", ex); + } + } + } + + private void saveMenuItem_Click(object sender, EventArgs e) + { + Save.SaveToFile(); + } + + private void createServiceMenuItem_Click(object sender, EventArgs e) + { + CreateServiceWindow createServiceWindow = new CreateServiceWindow(); + createServiceWindow.ShowDialog(); + } + + private void donateMenuItem_Click(object sender, EventArgs e) + { + Program.TryStart("http://sourceforge.net/project/project_donations.php?group_id=242527"); + } + + private void checkForUpdatesMenuItem_Click(object sender, EventArgs e) + { + this.UpdateProgram(true); + } + + #region View + + private void cpuHistoryMenuItem_Click(object sender, EventArgs e) + { + Properties.Settings.Default.CpuHistoryIconVisible = + cpuHistoryMenuItem.Checked = !cpuHistoryMenuItem.Checked; + this.ApplyIconVisibilities(); + } + + private void cpuUsageMenuItem_Click(object sender, EventArgs e) + { + Properties.Settings.Default.CpuUsageIconVisible = + cpuUsageMenuItem.Checked = !cpuUsageMenuItem.Checked; + this.ApplyIconVisibilities(); + } + + private void ioHistoryMenuItem_Click(object sender, EventArgs e) + { + Properties.Settings.Default.IoHistoryIconVisible = + ioHistoryMenuItem.Checked = !ioHistoryMenuItem.Checked; + this.ApplyIconVisibilities(); + } + + private void commitHistoryMenuItem_Click(object sender, EventArgs e) + { + Properties.Settings.Default.CommitHistoryIconVisible = + commitHistoryMenuItem.Checked = !commitHistoryMenuItem.Checked; + this.ApplyIconVisibilities(); + } + + private void physMemHistoryMenuItem_Click(object sender, EventArgs e) + { + Properties.Settings.Default.PhysMemHistoryIconVisible = + physMemHistoryMenuItem.Checked = !physMemHistoryMenuItem.Checked; + this.ApplyIconVisibilities(); + } + + #endregion + + #endregion + + #region Network Context Menu + + private void menuNetwork_Popup(object sender, EventArgs e) + { + if (listNetwork.SelectedItems.Count == 0) + { + menuNetwork.DisableAll(); + } + else if (listNetwork.SelectedItems.Count == 1) + { + menuNetwork.EnableAll(); + } + else + { + menuNetwork.EnableAll(); + goToProcessNetworkMenuItem.Enabled = false; + } + + if (listNetwork.Items.Count > 0) + selectAllNetworkMenuItem.Enabled = true; + else + selectAllNetworkMenuItem.Enabled = false; + + try + { + bool hasValid = false; + + foreach (ListViewItem item in listNetwork.SelectedItems) + { + if (item.SubItems[5].Text == "TCP") + { + if (item.SubItems[6].Text != "Listening" && + item.SubItems[6].Text != "CloseWait" && + item.SubItems[6].Text != "TimeWait") + { + hasValid = true; + break; + } + } + } + + if (!hasValid) + closeNetworkMenuItem.Enabled = false; + } + catch (Exception ex) + { + Logging.Log(ex); + } + + try + { + bool hasValid = false; + + foreach (ListViewItem item in listNetwork.SelectedItems) + { + if (item.SubItems[3].Text.Length > 0) + { + hasValid = true; + break; + } + } + + if (!hasValid) + { + whoisNetworkMenuItem.Enabled = false; + tracertNetworkMenuItem.Enabled = false; + pingNetworkMenuItem.Enabled = false; + } + else + { + whoisNetworkMenuItem.Enabled = true; + tracertNetworkMenuItem.Enabled = true; + pingNetworkMenuItem.Enabled = true; + } + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + + private void goToProcessNetworkMenuItem_Click(object sender, EventArgs e) + { + if (listNetwork.SelectedItems.Count != 1) + return; + + this.SelectProcess(((NetworkItem)listNetwork.SelectedItems[0].Tag).Connection.Pid); + } + + private void whoisNetworkMenuItem_Click(object sender, EventArgs e) + { + if (listNetwork.SelectedItems.Count != 1) + return; + + foreach (ListViewItem item in listNetwork.SelectedItems) + { + var remote = ((NetworkItem)item.Tag).Connection.Remote; + + if (remote != null) + { + IPInfoWindow iw = new IPInfoWindow(remote.Address, IpAction.Whois); + iw.ShowDialog(this); + } + } + } + + private void tracertNetworkMenuItem_Click(object sender, EventArgs e) + { + if (listNetwork.SelectedItems.Count != 1) + return; + + foreach (ListViewItem item in listNetwork.SelectedItems) + { + var remote = ((NetworkItem)item.Tag).Connection.Remote; + + if (remote != null) + { + IPInfoWindow iw = new IPInfoWindow(remote.Address, IpAction.Tracert); + iw.ShowDialog(this); + } + } + } + + private void pingNetworkMenuItem_Click(object sender, EventArgs e) + { + if (listNetwork.SelectedItems.Count != 1) + return; + + foreach (ListViewItem item in listNetwork.SelectedItems) + { + var remote = ((NetworkItem)item.Tag).Connection.Remote; + + if (remote != null) + { + IPInfoWindow iw = new IPInfoWindow(remote.Address, IpAction.Ping); + iw.ShowDialog(this); + } + } + } + + private void closeNetworkMenuItem_Click(object sender, EventArgs e) + { + if (listNetwork.SelectedItems.Count == 0) + return; + + bool allGood = true; + + try + { + foreach (ListViewItem item in listNetwork.SelectedItems) + { + if (item.SubItems[5].Text != "TCP" || + item.SubItems[6].Text != "Established") + continue; + + try + { + networkP.Dictionary[item.Name].Connection.CloseTcpConnection(); + } + catch + { + allGood = false; + + if (MessageBox.Show("Could not close the TCP connection. " + + "Make sure Process Hacker is running with administrative privileges.", "Process Hacker", + MessageBoxButtons.OKCancel, MessageBoxIcon.Error) == DialogResult.Cancel) + return; + } + } + } + catch (Exception ex) + { + Logging.Log(ex); + } + + if (allGood) + { + foreach (ListViewItem item in listNetwork.SelectedItems) + item.Selected = false; + } + + } + + private void selectAllNetworkMenuItem_Click(object sender, EventArgs e) + { + Utils.SelectAll(listNetwork.List.Items); + } + + #endregion + + #region Notification Icon & Menu + + private void notifyIcon_MouseDoubleClick(object sender, MouseEventArgs e) + { + showHideMenuItem_Click(null, null); + } + + private void menuIcon_Popup(object sender, EventArgs e) + { + List processes = new List(); + + // Clear the images so we don't get GDI+ handle leaks + foreach (MenuItem item in processesMenuItem.MenuItems) + vistaMenu.SetImage(item, null); + + processesMenuItem.MenuItems.DisposeAndClear(); + + // HACK: To be fixed later - we need some sort of locking for the process provider + try + { + foreach (var process in processP.Dictionary.Values) + { + if (process.Pid > 0) + { + processes.Add(process); + } + } + + // Remove zero CPU usage processes and processes running as other users + for (int i = 0; i < processes.Count && processes.Count > Properties.Settings.Default.IconMenuProcessCount; i++) + { + if (processes[i].CpuUsage == 0) + { + processes.RemoveAt(i); + i--; + } + else if (processes[i].Username != Program.CurrentUsername) + { + processes.RemoveAt(i); + i--; + } + } + + // Sort the processes by CPU usage and remove processes with low CPU usage + processes.Sort((i1, i2) => -i1.CpuUsage.CompareTo(i2.CpuUsage)); + + if (processes.Count > Properties.Settings.Default.IconMenuProcessCount) + { + int c = processes.Count; + processes.RemoveRange(Properties.Settings.Default.IconMenuProcessCount, + processes.Count - Properties.Settings.Default.IconMenuProcessCount); + } + + // Then sort the processes by name + processes.Sort((i1, i2) => i1.Name.CompareTo(i2.Name)); + + // Add the processes + foreach (var process in processes) + { + MenuItem processItem = new MenuItem(); + MenuItem terminateItem = new MenuItem(); + MenuItem suspendItem = new MenuItem(); + MenuItem resumeItem = new MenuItem(); + MenuItem propertiesItem = new MenuItem(); + + processItem.Text = process.Name + " (" + process.Pid.ToString() + ")"; + processItem.Tag = process; + + terminateItem.Click += new EventHandler((sender_, e_) => + { + ProcessItem item = (ProcessItem)((MenuItem)sender_).Parent.Tag; + + ProcessActions.Terminate(this, new int[] { item.Pid }, new string[] { item.Name }, true); + }); + terminateItem.Text = "Terminate"; + + suspendItem.Click += new EventHandler((sender_, e_) => + { + ProcessItem item = (ProcessItem)((MenuItem)sender_).Parent.Tag; + + ProcessActions.Suspend(this, new int[] { item.Pid }, new string[] { item.Name }, true); + }); + suspendItem.Text = "Suspend"; + + resumeItem.Click += new EventHandler((sender_, e_) => + { + ProcessItem item = (ProcessItem)((MenuItem)sender_).Parent.Tag; + + ProcessActions.Resume(this, new int[] { item.Pid }, new string[] { item.Name }, true); + }); + resumeItem.Text = "Resume"; + + propertiesItem.Click += new EventHandler((sender_, e_) => + { + try + { + ProcessItem item = (ProcessItem)((MenuItem)sender_).Parent.Tag; + + ProcessWindow pForm = Program.GetProcessWindow(processP.Dictionary[item.Pid], + new Program.PWindowInvokeAction(delegate(ProcessWindow f) + { + f.Show(); + f.Activate(); + })); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to inspect the process", ex); + } + }); + propertiesItem.Text = "Properties"; + + processItem.MenuItems.AddRange(new MenuItem[] { terminateItem, suspendItem, resumeItem, propertiesItem }); + processesMenuItem.MenuItems.Add(processItem); + + vistaMenu.SetImage(processItem, (treeProcesses.Tree.Model as ProcessTreeModel).Nodes[process.Pid].Icon); + } + } + catch + { + foreach (MenuItem item in processesMenuItem.MenuItems) + vistaMenu.SetImage(item, null); + + processesMenuItem.MenuItems.DisposeAndClear(); + } + } + + private void showHideMenuItem_Click(object sender, EventArgs e) + { + if (this.WindowState == FormWindowState.Normal && this.Visible) + { + Properties.Settings.Default.WindowLocation = this.Location; + Properties.Settings.Default.WindowSize = this.Size; + } + + this.Visible = !this.Visible; + + if (this.WindowState == FormWindowState.Minimized) + { + this.Location = Properties.Settings.Default.WindowLocation; + this.Size = Properties.Settings.Default.WindowSize; + this.WindowState = FormWindowState.Normal; + } + + this.Activate(); + } + + private void sysInformationIconMenuItem_Click(object sender, EventArgs e) + { + sysInfoMenuItem_Click(sender, e); + } + + private void networkInfomationMenuItem_Click(object sender, EventArgs e) + { + new NetInfoWindow().Show(); + } + + private void enableAllNotificationsMenuItem_Click(object sender, EventArgs e) + { + NPMenuItem.Checked = true; + TPMenuItem.Checked = true; + NSMenuItem.Checked = true; + startedSMenuItem.Checked = true; + stoppedSMenuItem.Checked = true; + DSMenuItem.Checked = true; + } + + private void disableAllNotificationsMenuItem_Click(object sender, EventArgs e) + { + NPMenuItem.Checked = false; + TPMenuItem.Checked = false; + NSMenuItem.Checked = false; + startedSMenuItem.Checked = false; + stoppedSMenuItem.Checked = false; + DSMenuItem.Checked = false; + } + + private void exitTrayMenuItem_Click(object sender, EventArgs e) + { + this.Exit(); + } + + #endregion + + #region Process Context Menu + + private void menuProcess_Popup(object sender, EventArgs e) + { + virtualizationProcessMenuItem.Checked = false; + + // Menu item fixup... + if (treeProcesses.SelectedTreeNodes.Count == 0) + { + // If nothing is selected, disable everything. + // The Select All menu item will be enabled later if + // we have at least one process in the tree. + menuProcess.DisableAll(); + } + else if (treeProcesses.SelectedTreeNodes.Count == 1) + { + // All actions should work with one process selected. + menuProcess.EnableAll(); + + // Singular nouns. + priorityMenuItem.Text = "&Priority"; + terminateMenuItem.Text = "&Terminate Process"; + suspendMenuItem.Text = "&Suspend Process"; + resumeMenuItem.Text = "&Resume Process"; + + // Check the appropriate priority level menu item. + realTimeMenuItem.Checked = false; + highMenuItem.Checked = false; + aboveNormalMenuItem.Checked = false; + normalMenuItem.Checked = false; + belowNormalMenuItem.Checked = false; + idleMenuItem.Checked = false; + + try + { + using (var phandle = new ProcessHandle(processSelectedPid, Program.MinProcessQueryRights)) + { + switch (phandle.GetPriorityClass()) + { + case ProcessPriorityClass.RealTime: + realTimeMenuItem.Checked = true; + break; + + case ProcessPriorityClass.High: + highMenuItem.Checked = true; + break; + + case ProcessPriorityClass.AboveNormal: + aboveNormalMenuItem.Checked = true; + break; + + case ProcessPriorityClass.Normal: + normalMenuItem.Checked = true; + break; + + case ProcessPriorityClass.BelowNormal: + belowNormalMenuItem.Checked = true; + break; + + case ProcessPriorityClass.Idle: + idleMenuItem.Checked = true; + break; + } + } + } + catch (Exception ex) + { + priorityMenuItem.Text = "(" + ex.Message + ")"; + priorityMenuItem.Enabled = false; + } + + // Check the virtualization menu item. + try + { + using (var phandle = new ProcessHandle(processSelectedPid, Program.MinProcessQueryRights)) + { + try + { + using (var thandle = phandle.GetToken(TokenAccess.Query)) + { + if (virtualizationProcessMenuItem.Enabled = thandle.IsVirtualizationAllowed()) + virtualizationProcessMenuItem.Checked = thandle.IsVirtualizationEnabled(); + } + } + catch + { } + } + } + catch + { + virtualizationProcessMenuItem.Enabled = false; + } + + // Enable/disable DLL injection based on the process' session ID. This only applies + // on XP and above. + try + { + if ( + OSVersion.IsBelowOrEqual(WindowsVersion.XP) && + processP.Dictionary[processSelectedPid].SessionId != Program.CurrentSessionId + ) + injectDllProcessMenuItem.Enabled = false; + else + injectDllProcessMenuItem.Enabled = true; + } + catch (Exception ex) + { + Logging.Log(ex); + } + + // Disable Terminate Process Tree if the selected process doesn't + // have any children. Note that this may also happen if the user + // is sorting the list (!). + try + { + if (treeProcesses.SelectedTreeNodes[0].IsLeaf && + (treeProcesses.Tree.Model as ProcessTreeModel).GetSortColumn() == "") + terminateProcessTreeMenuItem.Visible = false; + else + terminateProcessTreeMenuItem.Visible = true; + } + catch (Exception ex) + { + Logging.Log(ex); + } + + // Find the process' window (if any). + windowHandle = WindowHandle.Zero; + WindowHandle.Enumerate( + (handle) => + { + // GetWindowLong + // Shell_TrayWnd + if (handle.IsWindow() && handle.IsVisible() && handle.IsParent()) + { + int pid; + Win32.GetWindowThreadProcessId(handle, out pid); + + if (pid == processSelectedPid) + { + windowHandle = handle; + return false; + } + } + return true; + }); + + // Enable the Window submenu if we found window owned + // by the process. Otherwise, disable the submenu. + if (windowHandle.IsInvalid) + { + windowProcessMenuItem.Enabled = false; + } + else + { + windowProcessMenuItem.Enabled = true; + windowProcessMenuItem.EnableAll(); + + switch (windowHandle.GetPlacement().ShowState) + { + case ShowWindowType.ShowMinimized: + minimizeProcessMenuItem.Enabled = false; + break; + + case ShowWindowType.ShowMaximized: + maximizeProcessMenuItem.Enabled = false; + break; + + case ShowWindowType.ShowNormal: + restoreProcessMenuItem.Enabled = false; + break; + } + } + } + else + { + // Assume most process actions will not work with more than one process. + menuProcess.DisableAll(); + + // Use plural nouns. + terminateMenuItem.Text = "&Terminate Processes"; + suspendMenuItem.Text = "&Suspend Processes"; + resumeMenuItem.Text = "&Resume Processes"; + + // Enable a specific set of actions. + terminateMenuItem.Enabled = true; + suspendMenuItem.Enabled = true; + resumeMenuItem.Enabled = true; + reduceWorkingSetProcessMenuItem.Enabled = true; + copyProcessMenuItem.Enabled = true; + } + + // Special case for invalid PIDs. + if (processSelectedPid <= 0 && treeProcesses.SelectedNodes.Count == 1) + { + priorityMenuItem.Text = "&Priority"; + menuProcess.DisableAll(); + propertiesProcessMenuItem.Enabled = true; + } + + // Enable/disable the Select All menu item. + if (treeProcesses.Model.Nodes.Count == 0) + { + selectAllProcessMenuItem.Enabled = false; + } + else + { + selectAllProcessMenuItem.Enabled = true; + } + } + + private void terminateMenuItem_Click(object sender, EventArgs e) + { + if (treeProcesses.SelectedNodes.Count == 0) + return; + + int[] pids = new int[treeProcesses.SelectedNodes.Count]; + string[] names = new string[pids.Length]; + + for (int i = 0; i < treeProcesses.SelectedNodes.Count; i++) + { + pids[i] = treeProcesses.SelectedNodes[i].Pid; + names[i] = treeProcesses.SelectedNodes[i].Name; + } + + if (ProcessActions.Terminate(this, pids, names, true)) + { + try + { + TreeNodeAdv[] nodes = new TreeNodeAdv[treeProcesses.SelectedTreeNodes.Count]; + + treeProcesses.SelectedTreeNodes.CopyTo(nodes, 0); + + foreach (TreeNodeAdv node in nodes) + node.IsSelected = false; + } + catch + { } + } + } + + private void terminateProcessTreeMenuItem_Click(object sender, EventArgs e) + { + if (treeProcesses.SelectedNodes.Count == 0) + return; + + int[] pids = new int[treeProcesses.SelectedNodes.Count]; + string[] names = new string[pids.Length]; + + for (int i = 0; i < treeProcesses.SelectedNodes.Count; i++) + { + pids[i] = treeProcesses.SelectedNodes[i].Pid; + names[i] = treeProcesses.SelectedNodes[i].Name; + } + + if (ProcessActions.TerminateTree(this, pids, names, true)) + { + try + { + TreeNodeAdv[] nodes = new TreeNodeAdv[treeProcesses.SelectedTreeNodes.Count]; + + treeProcesses.SelectedTreeNodes.CopyTo(nodes, 0); + + foreach (TreeNodeAdv node in nodes) + node.IsSelected = false; + } + catch + { } + } + } + + private void suspendMenuItem_Click(object sender, EventArgs e) + { + if (treeProcesses.SelectedNodes.Count == 0) + return; + + int[] pids = new int[treeProcesses.SelectedNodes.Count]; + string[] names = new string[pids.Length]; + + for (int i = 0; i < treeProcesses.SelectedNodes.Count; i++) + { + pids[i] = treeProcesses.SelectedNodes[i].Pid; + names[i] = treeProcesses.SelectedNodes[i].Name; + } + + ProcessActions.Suspend(this, pids, names, true); + } + + private void resumeMenuItem_Click(object sender, EventArgs e) + { + if (treeProcesses.SelectedNodes.Count == 0) + return; + + int[] pids = new int[treeProcesses.SelectedNodes.Count]; + string[] names = new string[pids.Length]; + + for (int i = 0; i < treeProcesses.SelectedNodes.Count; i++) + { + pids[i] = treeProcesses.SelectedNodes[i].Pid; + names[i] = treeProcesses.SelectedNodes[i].Name; + } + + ProcessActions.Resume(this, pids, names, true); + } + + private void restartProcessMenuItem_Click(object sender, EventArgs e) + { + if (PhUtils.ShowConfirmMessage( + "restart", + "the selected process", + "The process will be restarted with the same command line and " + + "working directory, but if it is running under a different user it " + + "will be restarted under the current user.", + true + )) + { + try + { + using (var phandle = new ProcessHandle(processSelectedPid, + Program.MinProcessQueryRights | Program.MinProcessReadMemoryRights)) + { + string currentDirectory = phandle.GetPebString(PebOffset.CurrentDirectoryPath); + string cmdLine = phandle.GetPebString(PebOffset.CommandLine); + + try + { + using (var phandle2 = new ProcessHandle(processSelectedPid, ProcessAccess.Terminate)) + phandle2.Terminate(); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to terminate the process", ex); + return; + } + + try + { + var startupInfo = new StartupInfo(); + var procInfo = new ProcessInformation(); + + startupInfo.Size = Marshal.SizeOf(startupInfo); + + if (!Win32.CreateProcess(null, cmdLine, IntPtr.Zero, IntPtr.Zero, false, 0, IntPtr.Zero, currentDirectory, + ref startupInfo, out procInfo)) + Win32.ThrowLastError(); + + Win32.CloseHandle(procInfo.ProcessHandle); + Win32.CloseHandle(procInfo.ThreadHandle); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to start the command '" + cmdLine + "'", ex); + } + } + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to restart the process", ex); + } + } + } + + private void reduceWorkingSetProcessMenuItem_Click(object sender, EventArgs e) + { + if (treeProcesses.SelectedNodes.Count == 0) + return; + + int[] pids = new int[treeProcesses.SelectedNodes.Count]; + string[] names = new string[pids.Length]; + + for (int i = 0; i < treeProcesses.SelectedNodes.Count; i++) + { + pids[i] = treeProcesses.SelectedNodes[i].Pid; + names[i] = treeProcesses.SelectedNodes[i].Name; + } + + ProcessActions.ReduceWorkingSet(this, pids, names, false); + } + + private void virtualizationProcessMenuItem_Click(object sender, EventArgs e) + { + if (!PhUtils.ShowConfirmMessage( + "set", + "virtualization for the process", + "Enabling or disabling virtualization for a process may " + + "alter its functionality and produce undesirable effects.", + false + )) + return; + + try + { + using (var phandle = new ProcessHandle(processSelectedPid, Program.MinProcessQueryRights)) + { + using (var thandle = phandle.GetToken(TokenAccess.GenericWrite)) + { + thandle.SetVirtualizationEnabled(!virtualizationProcessMenuItem.Checked); + } + } + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to set process virtualization", ex); + } + } + + private void propertiesProcessMenuItem_Click(object sender, EventArgs e) + { + // user hasn't got any processes selected + if (processSelectedPid == -1) + return; + + ProcessActions.ShowProperties(this, processSelectedPid, treeProcesses.SelectedNodes[0].Name); + } + + private void affinityProcessMenuItem_Click(object sender, EventArgs e) + { + ProcessAffinity affForm = new ProcessAffinity(processSelectedPid); + + try + { + affForm.ShowDialog(); + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + + private void createDumpFileProcessMenuItem_Click(object sender, EventArgs e) + { + SaveFileDialog sfd = new SaveFileDialog(); + + sfd.Filter = "Dump Files (*.dmp)|*.dmp|All Files (*.*)|*.*"; + sfd.FileName = + processP.Dictionary[processSelectedPid].Name + + "_" + + DateTime.Now.ToString("yyMMdd") + + ".dmp"; + + if (sfd.ShowDialog() == DialogResult.OK) + { + this.Cursor = Cursors.WaitCursor; + + try + { + Exception exception = null; + + ThreadStart dumpProcess = () => + { + try + { + using (var phandle = new ProcessHandle(processSelectedPid, + ProcessAccess.DupHandle | ProcessAccess.QueryInformation | + ProcessAccess.SuspendResume | ProcessAccess.VmRead)) + phandle.WriteDump(sfd.FileName); + } + catch (Exception ex2) + { + exception = ex2; + } + }; + + if (OSVersion.HasTaskDialogs) + { + // Use a task dialog to display a fancy progress bar. + TaskDialog td = new TaskDialog(); + Thread t = new Thread(dumpProcess); + + td.AllowDialogCancellation = false; + td.Buttons = new TaskDialogButton[] { new TaskDialogButton((int)DialogResult.OK, "Close") }; + td.WindowTitle = "Process Hacker"; + td.MainInstruction = "Creating the dump file..."; + td.ShowMarqueeProgressBar = true; + td.EnableHyperlinks = true; + td.CallbackTimer = true; + td.Callback = (taskDialog, args, userData) => + { + if (args.Notification == TaskDialogNotification.Created) + { + taskDialog.SetMarqueeProgressBar(true); + taskDialog.SetProgressBarState(ProgressBarState.Normal); + taskDialog.SetProgressBarMarquee(true, 100); + taskDialog.EnableButton((int)DialogResult.OK, false); + } + else if (args.Notification == TaskDialogNotification.Timer) + { + if (!t.IsAlive) + { + taskDialog.EnableButton((int)DialogResult.OK, true); + taskDialog.SetProgressBarMarquee(false, 0); + taskDialog.SetMarqueeProgressBar(false); + + if (exception == null) + { + taskDialog.SetMainInstruction("The dump file has been created."); + taskDialog.SetContent( + "The dump file has been saved at: " + sfd.FileName + "."); + } + else + { + taskDialog.UpdateMainIcon(TaskDialogIcon.Warning); + taskDialog.SetMainInstruction("Unable to create the dump file."); + taskDialog.SetContent( + "The dump file could not be created: " + exception.Message + ); + } + } + } + else if (args.Notification == TaskDialogNotification.HyperlinkClicked) + { + if (args.Hyperlink == "file") + Utils.ShowFileInExplorer(sfd.FileName); + + return true; + } + + return false; + }; + + t.Start(); + td.Show(this); + } + else + { + // No task dialogs, do the thing on the GUI thread. + dumpProcess(); + + if (exception != null) + PhUtils.ShowException("Unable to create the dump file", exception); + } + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to create the dump file", ex); + } + finally + { + this.Cursor = Cursors.Default; + } + } + } + + private void terminatorProcessMenuItem_Click(object sender, EventArgs e) + { + TerminatorWindow w = new TerminatorWindow(processSelectedPid); + + w.Text = "Terminator - " + processP.Dictionary[processSelectedPid].Name + + " (PID " + processSelectedPid.ToString() + ")"; + w.ShowDialog(); + } + + #region Run As + + private void launchAsUserProcessMenuItem_Click(object sender, EventArgs e) + { + try + { + Properties.Settings.Default.RunAsCommand = processP.Dictionary[processSelectedPid].FileName; + + RunWindow run = new RunWindow(); + run.ShowDialog(); + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + + private void launchAsThisUserProcessMenuItem_Click(object sender, EventArgs e) + { + try + { + RunWindow run = new RunWindow(); + run.UsePID(processSelectedPid); + run.ShowDialog(); + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + + #endregion + + #region Miscellaneous + + private void detachFromDebuggerProcessMenuItem_Click(object sender, EventArgs e) + { + try + { + using (var phandle = new ProcessHandle(processSelectedPid, ProcessAccess.QueryInformation | ProcessAccess.SuspendResume)) + { + using (var dhandle = phandle.GetDebugObject()) + phandle.RemoveDebug(dhandle); + } + } + catch (WindowsException ex) + { + if (ex.Status == NtStatus.PortNotSet) + PhUtils.ShowInformation("The process is not being debugged."); + else + PhUtils.ShowException("Unable to detach the process", ex); + } + } + + private void heapsProcessMenuItem_Click(object sender, EventArgs e) + { + try + { + HeapsWindow heapsWindow; + + using (DebugBuffer buffer = new DebugBuffer()) + { + this.Cursor = Cursors.WaitCursor; + + try + { + buffer.Query( + processSelectedPid, + RtlQueryProcessDebugFlags.HeapSummary | + RtlQueryProcessDebugFlags.HeapEntries + ); + } + finally + { + this.Cursor = Cursors.Default; + } + + heapsWindow = new HeapsWindow(processSelectedPid, buffer.GetHeaps()); + } + heapsWindow.ShowDialog(); + } + catch (WindowsException ex) + { + PhUtils.ShowException("Unable to get heap information", ex); + } + } + + private void injectDllProcessMenuItem_Click(object sender, EventArgs e) + { + OpenFileDialog ofd = new OpenFileDialog(); + + ofd.Filter = "DLL Files (*.dll)|*.dll|All Files (*.*)|*.*"; + + if (ofd.ShowDialog() == DialogResult.OK) + { + try + { + using (var phandle = new ProcessHandle(processSelectedPid, + ProcessAccess.CreateThread | ProcessAccess.VmOperation | ProcessAccess.VmWrite)) + { + phandle.InjectDll(ofd.FileName, 5000); + } + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to inject the DLL", ex); + } + } + } + + private void protectionProcessMenuItem_Click(object sender, EventArgs e) + { + var protectProcessWindow = new ProtectProcessWindow(processSelectedPid); + protectProcessWindow.ShowDialog(); + } + + private void setTokenProcessMenuItem_Click(object sender, EventArgs e) + { + ProcessPickerWindow picker = new ProcessPickerWindow(); + + picker.Label = "Select the source of the token:"; + + if (picker.ShowDialog() == DialogResult.OK) + { + try + { + KProcessHacker.Instance.SetProcessToken(picker.SelectedPid, processSelectedPid); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to set the process token", ex); + } + } + } + + #endregion + + #region Priority + + private void realTimeMenuItem_Click(object sender, EventArgs e) + { + SetProcessPriority(ProcessPriorityClass.RealTime); + } + + private void highMenuItem_Click(object sender, EventArgs e) + { + SetProcessPriority(ProcessPriorityClass.High); + } + + private void aboveNormalMenuItem_Click(object sender, EventArgs e) + { + SetProcessPriority(ProcessPriorityClass.AboveNormal); + } + + private void normalMenuItem_Click(object sender, EventArgs e) + { + SetProcessPriority(ProcessPriorityClass.Normal); + } + + private void belowNormalMenuItem_Click(object sender, EventArgs e) + { + SetProcessPriority(ProcessPriorityClass.BelowNormal); + } + + private void idleMenuItem_Click(object sender, EventArgs e) + { + SetProcessPriority(ProcessPriorityClass.Idle); + } + + #endregion + + #region Window + + private void bringToFrontProcessMenuItem_Click(object sender, EventArgs e) + { + if (!windowHandle.IsInvalid && windowHandle.IsWindow()) + { + WindowPlacement placement = windowHandle.GetPlacement(); + + if (placement.ShowState == ShowWindowType.ShowMinimized) + windowHandle.Show(ShowWindowType.Restore); + else + windowHandle.SetForeground(); + } + } + + private void restoreProcessMenuItem_Click(object sender, EventArgs e) + { + if (!windowHandle.IsInvalid && windowHandle.IsWindow()) + { + windowHandle.Show(ShowWindowType.Restore); + } + } + + private void minimizeProcessMenuItem_Click(object sender, EventArgs e) + { + if (!windowHandle.IsInvalid && windowHandle.IsWindow()) + { + windowHandle.Show(ShowWindowType.ShowMinimized); + } + } + + private void maximizeProcessMenuItem_Click(object sender, EventArgs e) + { + if (!windowHandle.IsInvalid && windowHandle.IsWindow()) + { + windowHandle.Show(ShowWindowType.ShowMaximized); + } + } + + private void closeProcessMenuItem_Click(object sender, EventArgs e) + { + if (!windowHandle.IsInvalid && windowHandle.IsWindow()) + { + windowHandle.PostMessage(WindowMessage.Close, 0, 0); + //windowHandle.Close(); + } + } + + #endregion + + private void searchProcessMenuItem_Click(object sender, EventArgs e) + { + if (treeProcesses.SelectedNodes.Count != 1) + return; + + Program.TryStart(Properties.Settings.Default.SearchEngine.Replace("%s", + treeProcesses.SelectedNodes[0].Name)); + } + + private void reanalyzeProcessMenuItem_Click(object sender, EventArgs e) + { + try + { + processP.QueueProcessQuery(processSelectedPid); + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + + private void selectAllProcessMenuItem_Click(object sender, EventArgs e) + { + treeProcesses.Tree.AllNodes.SelectAll(); + treeProcesses.Tree.Invalidate(); + } + + private void virusTotalMenuItem_Click(object sender, EventArgs e) + { + if (treeProcesses.SelectedNodes.Count != 1) + return; + + if (PhUtils.IsInternetConnected) + { + if (string.IsNullOrEmpty(treeProcesses.SelectedNodes[0].FileName)) + { + PhUtils.ShowWarning("Unable to upload because the process' file location could not be determined."); + return; + } + + VirusTotalUploaderWindow vt = new VirusTotalUploaderWindow( + treeProcesses.SelectedNodes[0].Name, + treeProcesses.SelectedNodes[0].FileName + ); + + int Y = this.Top + (this.Height - vt.Height) / 2; + int X = this.Left + (this.Width - vt.Width) / 2; + + vt.Location = new Point(X, Y); + vt.Show(); + } + else + PhUtils.ShowWarning("An Internet session could not be established. Please verify connectivity."); + } + + private void analyzeWaitChainProcessMenuItem_Click(object sender, EventArgs e) + { + WaitChainWindow wcw = new WaitChainWindow( + treeProcesses.SelectedNodes[0].Name, + treeProcesses.SelectedNodes[0].Pid); + + int Y = this.Top + (this.Height - wcw.Height) / 2; + int X = this.Left + (this.Width - wcw.Width) / 2; + + wcw.Location = new Point(X, Y); + wcw.Show(); + } + + #endregion + + #region Providers + + private void processP_Updated() + { + processP.DictionaryAdded += processP_DictionaryAdded; + processP.DictionaryRemoved += processP_DictionaryRemoved; + processP.Updated -= processP_Updated; + + try { ProcessHandle.Current.SetPriorityClass(ProcessPriorityClass.High); } + catch { } + + if (processP.RunCount >= 1) + this.BeginInvoke(new MethodInvoker(delegate + { + treeProcesses.Tree.EndCompleteUpdate(); + treeProcesses.Tree.EndUpdate(); + + if (Properties.Settings.Default.ScrollDownProcessTree) + { + // HACK HACK HACK HACK + // HACK HACK HACK HACK + // HACK HACK HACK HACK + // HACK HACK HACK HACK + try + { + foreach (var process in treeProcesses.Model.Roots) + { + if ( + string.Equals(process.Name, "explorer.exe", + StringComparison.InvariantCultureIgnoreCase) && + process.ProcessItem.Username == Program.CurrentUsername) + { + treeProcesses.FindTreeNode(process).EnsureVisible2(); + + break; + } + } + } + catch + { } + } + + treeProcesses.Invalidate(); + processP.RunOnceAsync(); + this.Cursor = Cursors.Default; + this.UpdateCommon(); + })); + } + + private void processP_InfoUpdater() + { + this.BeginInvoke(new MethodInvoker(delegate + { + UpdateStatusInfo(); + })); + } + + private void processP_FileProcessingReceived(int stage, int pid) + { + // Check if we need to inspect a process at startup. + if (stage == 0x1 && Program.InspectPid != -1 && pid == Program.InspectPid) + { + processP.ProcessQueryReceived -= processP_FileProcessingReceived; + ProcessActions.ShowProperties(this, pid, processP.Dictionary[pid].Name); + } + } + + public void processP_DictionaryAdded(ProcessItem item) + { + ProcessItem parent = null; + string parentText = ""; + + if (item.HasParent && processP.Dictionary.ContainsKey(item.ParentPid)) + { + try + { + parent = processP.Dictionary[item.ParentPid]; + + parentText += " started by " + parent.Name + " (PID " + parent.Pid.ToString() + ")"; + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + + this.QueueMessage("New Process: " + item.Name + " (PID " + item.Pid.ToString() + ")" + parentText); + + if (NPMenuItem.Checked) + this.GetFirstIcon().ShowBalloonTip(2000, "New Process", + "The process " + item.Name + " (" + item.Pid.ToString() + + ") was started" + ((parentText != "") ? " by " + + parent.Name + " (" + parent.Pid.ToString() + ")" : "") + ".", ToolTipIcon.Info); + } + + public void processP_DictionaryRemoved(ProcessItem item) + { + this.QueueMessage("Terminated Process: " + item.Name + " (PID " + item.Pid.ToString() + ")"); + + if (processServices.ContainsKey(item.Pid)) + processServices.Remove(item.Pid); + + if (TPMenuItem.Checked) + this.GetFirstIcon().ShowBalloonTip(2000, "Terminated Process", + "The process " + item.Name + " (" + item.Pid.ToString() + ") was terminated.", ToolTipIcon.Info); + } + + private void serviceP_Updated() + { + listServices.BeginInvoke(new MethodInvoker(delegate + { + listServices.List.EndUpdate(); + })); + + HighlightingContext.StateHighlighting = true; + + serviceP.DictionaryAdded += serviceP_DictionaryAdded; + serviceP.DictionaryModified += serviceP_DictionaryModified; + serviceP.DictionaryRemoved += serviceP_DictionaryRemoved; + serviceP.Updated -= serviceP_Updated; + + if (processP.RunCount >= 1) + this.BeginInvoke(new MethodInvoker(UpdateCommon)); + } + + public void serviceP_DictionaryAdded(ServiceItem item) + { + this.QueueMessage("New Service: " + item.Status.ServiceName + + " (" + item.Status.ServiceStatusProcess.ServiceType.ToString() + ")" + + ((item.Status.DisplayName != "") ? + " (" + item.Status.DisplayName + ")" : + "")); + + if (NSMenuItem.Checked) + this.GetFirstIcon().ShowBalloonTip(2000, "New Service", + "The service " + item.Status.ServiceName + " (" + item.Status.DisplayName + ") has been created.", + ToolTipIcon.Info); + } + + public void serviceP_DictionaryAdded_Process(ServiceItem item) + { + if (item.Status.ServiceStatusProcess.ProcessID != 0) + { + if (!processServices.ContainsKey(item.Status.ServiceStatusProcess.ProcessID)) + processServices.Add(item.Status.ServiceStatusProcess.ProcessID, new List()); + + processServices[item.Status.ServiceStatusProcess.ProcessID].Add(item.Status.ServiceName); + } + } + + public void serviceP_DictionaryModified(ServiceItem oldItem, ServiceItem newItem) + { + var oldState = oldItem.Status.ServiceStatusProcess.CurrentState; + var newState = newItem.Status.ServiceStatusProcess.CurrentState; + + if ((oldState == ServiceState.Paused || oldState == ServiceState.Stopped || + oldState == ServiceState.StartPending) && + newState == ServiceState.Running) + { + this.QueueMessage("Service Started: " + newItem.Status.ServiceName + + " (" + newItem.Status.ServiceStatusProcess.ServiceType.ToString() + ")" + + ((newItem.Status.DisplayName != "") ? + " (" + newItem.Status.DisplayName + ")" : + "")); + + if (startedSMenuItem.Checked) + this.GetFirstIcon().ShowBalloonTip(2000, "Service Started", + "The service " + newItem.Status.ServiceName + " (" + newItem.Status.DisplayName + ") has been started.", + ToolTipIcon.Info); + } + + if (oldState == ServiceState.Running && + newState == ServiceState.Paused) + this.QueueMessage("Service Paused: " + newItem.Status.ServiceName + + " (" + newItem.Status.ServiceStatusProcess.ServiceType.ToString() + ")" + + ((newItem.Status.DisplayName != "") ? + " (" + newItem.Status.DisplayName + ")" : + "")); + + if (oldState == ServiceState.Running && + newState == ServiceState.Stopped) + { + this.QueueMessage("Service Stopped: " + newItem.Status.ServiceName + + " (" + newItem.Status.ServiceStatusProcess.ServiceType.ToString() + ")" + + ((newItem.Status.DisplayName != "") ? + " (" + newItem.Status.DisplayName + ")" : + "")); + + if (stoppedSMenuItem.Checked) + this.GetFirstIcon().ShowBalloonTip(2000, "Service Stopped", + "The service " + newItem.Status.ServiceName + " (" + newItem.Status.DisplayName + ") has been stopped.", + ToolTipIcon.Info); + } + } + + public void serviceP_DictionaryModified_Process(ServiceItem oldItem, ServiceItem newItem) + { + ServiceItem sitem = (ServiceItem)newItem; + + if (sitem.Status.ServiceStatusProcess.ProcessID != 0) + { + if (!processServices.ContainsKey(sitem.Status.ServiceStatusProcess.ProcessID)) + processServices.Add(sitem.Status.ServiceStatusProcess.ProcessID, new List()); + + if (!processServices[sitem.Status.ServiceStatusProcess.ProcessID].Contains( + sitem.Status.ServiceName)) + processServices[sitem.Status.ServiceStatusProcess.ProcessID].Add(sitem.Status.ServiceName); + + processServices[sitem.Status.ServiceStatusProcess.ProcessID].Sort(); + } + else + { + int oldId = ((ServiceItem)oldItem).Status.ServiceStatusProcess.ProcessID; + + if (processServices.ContainsKey(oldId)) + { + if (processServices[oldId].Contains( + sitem.Status.ServiceName)) + processServices[oldId].Remove(sitem.Status.ServiceName); + } + } + } + + public void serviceP_DictionaryRemoved(ServiceItem item) + { + this.QueueMessage("Deleted Service: " + item.Status.ServiceName + + " (" + item.Status.ServiceStatusProcess.ServiceType.ToString() + ")" + + ((item.Status.DisplayName != "") ? + " (" + item.Status.DisplayName + ")" : + "")); + + if (DSMenuItem.Checked) + this.GetFirstIcon().ShowBalloonTip(2000, "Service Deleted", + "The service " + item.Status.ServiceName + " (" + item.Status.DisplayName + ") has been deleted.", + ToolTipIcon.Info); + } + + public void serviceP_DictionaryRemoved_Process(ServiceItem item) + { + if (item.Status.ServiceStatusProcess.ProcessID != 0) + { + if (processServices.ContainsKey(item.Status.ServiceStatusProcess.ProcessID)) + { + if (processServices[item.Status.ServiceStatusProcess.ProcessID].Contains( + item.Status.ServiceName)) + processServices[item.Status.ServiceStatusProcess.ProcessID].Remove(item.Status.ServiceName); + } + } + } + + #endregion + + #region Service Context Menu + + private void menuService_Popup(object sender, EventArgs e) + { + if (listServices.SelectedItems.Count == 0) + { + menuService.DisableAll(); + goToProcessServiceMenuItem.Visible = true; + startServiceMenuItem.Visible = true; + continueServiceMenuItem.Visible = true; + pauseServiceMenuItem.Visible = true; + stopServiceMenuItem.Visible = true; + + selectAllServiceMenuItem.Enabled = true; + } + else if (listServices.SelectedItems.Count == 1) + { + menuService.EnableAll(); + + goToProcessServiceMenuItem.Visible = true; + startServiceMenuItem.Visible = true; + continueServiceMenuItem.Visible = true; + pauseServiceMenuItem.Visible = true; + stopServiceMenuItem.Visible = true; + + try + { + ServiceItem item = serviceP.Dictionary[listServices.SelectedItems[0].Name]; + + if (item.Status.ServiceStatusProcess.ProcessID != 0) + { + goToProcessServiceMenuItem.Enabled = true; + } + else + { + goToProcessServiceMenuItem.Enabled = false; + } + + if ((item.Status.ServiceStatusProcess.ControlsAccepted & ServiceAccept.PauseContinue) + == 0) + { + continueServiceMenuItem.Visible = false; + pauseServiceMenuItem.Visible = false; + } + else + { + continueServiceMenuItem.Visible = true; + pauseServiceMenuItem.Visible = true; + } + + if (item.Status.ServiceStatusProcess.CurrentState == ServiceState.Paused) + { + startServiceMenuItem.Enabled = false; + pauseServiceMenuItem.Enabled = false; + } + else if (item.Status.ServiceStatusProcess.CurrentState == ServiceState.Running) + { + startServiceMenuItem.Enabled = false; + continueServiceMenuItem.Enabled = false; + } + else if (item.Status.ServiceStatusProcess.CurrentState == ServiceState.Stopped) + { + pauseServiceMenuItem.Enabled = false; + stopServiceMenuItem.Enabled = false; + } + + if ((item.Status.ServiceStatusProcess.ControlsAccepted & ServiceAccept.Stop) == 0 && + item.Status.ServiceStatusProcess.CurrentState == ServiceState.Running) + { + stopServiceMenuItem.Enabled = false; + } + } + catch + { + menuService.DisableAll(); + copyServiceMenuItem.Enabled = true; + propertiesServiceMenuItem.Enabled = true; + } + } + else + { + menuService.DisableAll(); + + goToProcessServiceMenuItem.Visible = false; + startServiceMenuItem.Visible = false; + continueServiceMenuItem.Visible = false; + pauseServiceMenuItem.Visible = false; + stopServiceMenuItem.Visible = false; + + copyServiceMenuItem.Enabled = true; + propertiesServiceMenuItem.Enabled = true; + selectAllServiceMenuItem.Enabled = true; + } + + if (listServices.List.Items.Count == 0) + selectAllServiceMenuItem.Enabled = false; + } + + private void goToProcessServiceMenuItem_Click(object sender, EventArgs e) + { + this.SelectProcess( + serviceP.Dictionary[listServices.SelectedItems[0].Name]. + Status.ServiceStatusProcess.ProcessID); + } + + private void startServiceMenuItem_Click(object sender, EventArgs e) + { + ServiceActions.Start(this, listServices.SelectedItems[0].Name, false); + } + + private void continueServiceMenuItem_Click(object sender, EventArgs e) + { + ServiceActions.Continue(this, listServices.SelectedItems[0].Name, false); + } + + private void pauseServiceMenuItem_Click(object sender, EventArgs e) + { + ServiceActions.Pause(this, listServices.SelectedItems[0].Name, false); + } + + private void stopServiceMenuItem_Click(object sender, EventArgs e) + { + ServiceActions.Stop(this, listServices.SelectedItems[0].Name, false); + } + + private void deleteServiceMenuItem_Click(object sender, EventArgs e) + { + if (listServices.SelectedItems.Count != 1) + return; + + ServiceActions.Delete(this, listServices.SelectedItems[0].Name, true); + } + + private void propertiesServiceMenuItem_Click(object sender, EventArgs e) + { + if (listServices.SelectedItems.Count == 0) + return; + + List selected = new List(); + ServiceWindow sw; + + foreach (ListViewItem item in listServices.SelectedItems) + selected.Add(item.Name); + + if (selected.Count == 1) + { + sw = new ServiceWindow(selected[0]); + } + else + { + sw = new ServiceWindow(selected.ToArray()); + } + sw.ShowDialog(); + } + + private void selectAllServiceMenuItem_Click(object sender, EventArgs e) + { + Utils.SelectAll(listServices.Items); + } + + #endregion + + #region Tab Controls + + private void tabControlBig_SelectedIndexChanged(object sender, EventArgs e) + { + if (tabControl.SelectedTab == tabNetwork) + { + if (processP.RunCount > 0) + { + networkP.Enabled = true; + networkP.RunOnceAsync(); + } + } + else + { + networkP.Enabled = false; + } + } + + #endregion + + #region Thumbbuttons + + private void sysInfoButton_Clicked(object sender, EventArgs e) + { + sysInfoMenuItem_Click(sender, e); + } + + private void netInfoButton_Click(object sender, EventArgs e) + { + networkInfomationMenuItem_Click(sender, e); + } + + private void appHandleButton_Clicked(object sender, EventArgs e) + { + findHandlesMenuItem_Click(sender, e); + } + + private void appLogButton_Clicked(object sender, EventArgs e) + { + logMenuItem_Click(sender, e); + } + + #endregion + + #region Thumbbutton Managers + + private void thumbButtonManager_TaskbarButtonCreated(object sender, EventArgs e) + { + thumbButtonManager.TaskbarButtonCreated -= thumbButtonManager_TaskbarButtonCreated; + + //JumpListManager code works but has been commented out and reserved for future use + + //jumpListManager = Windows7Taskbar.CreateJumpListManager(); + //jumpListManager.UserRemovedItems += (o, e_) => + //{ + //QueueMessage("User removed " + e_.RemovedItems.Length + " items (cancelling refresh)"); + //e_.Cancel = true; + //}; + + //jumpListManager.ClearAllDestinations(); + //jumpListManager.EnabledAutoDestinationType = ApplicationDestinationType.Recent; + + //string shell32DllPath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "shell32.dll"); + + //jumpListManager.AddUserTask(new ShellLink + //{ + //Path = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "eventvwr.msc"), + //Arguments = "/s", + //Title = "Event Viewer", + //IconLocation = shell32DllPath, + //IconIndex = 14 + //}); + + //jumpListManager.AddUserTask(new Separator()); + + //jumpListManager.AddUserTask(new ShellLink + //{ + //Path = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "msinfo32.exe"), + //Title = "System Infomation", + //IconLocation = shell32DllPath, + //IconIndex = 15 + //}); + + //if (jumpListManager.Refresh()) + //{ + //QueueMessage("Maximum slots in JumpList: " + jumpListManager.MaximumSlotsInList); + //} + //jumpListManager.Dispose(); + + ThumbButton sysInfoButton = thumbButtonManager.CreateThumbButton(100, + Icon.FromHandle(ProcessHacker.Properties.Resources.chart_line.GetHicon()), + "System Infomation"); + sysInfoButton.Click += new EventHandler(sysInfoButton_Clicked); + + //ThumbButton netInfoButton = thumbButtonManager.CreateThumbButton(101, + //Icon.FromHandle(ProcessHacker.Properties.Resources.ProcessHacker.GetHicon()), + //"Network Infomation"); + //netInfoButton.Click += new EventHandler(netInfoButton_Click); + + ThumbButton appHandleButton = thumbButtonManager.CreateThumbButton(103, + Icon.FromHandle(ProcessHacker.Properties.Resources.find.GetHicon()), + "Find Handles or DLLs"); + appHandleButton.Click += new EventHandler(appHandleButton_Clicked); + + ThumbButton appLogButton = thumbButtonManager.CreateThumbButton(102, + Icon.FromHandle(ProcessHacker.Properties.Resources.report.GetHicon()), + "Application Log"); + appLogButton.Click += new EventHandler(appLogButton_Clicked); + + thumbButtonManager.AddThumbButtons(sysInfoButton, appHandleButton, appLogButton); + } + + #endregion + + #region ToolStrip Items + + private void findHandlesToolStripButton_Click(object sender, EventArgs e) + { + findHandlesMenuItem_Click(sender, e); + } + + private void refreshToolStripButton_Click(object sender, EventArgs e) + { + updateNowMenuItem_Click(sender, e); + } + + private void sysInfoToolStripButton_Click(object sender, EventArgs e) + { + sysInfoMenuItem_Click(sender, e); + } + + private void optionsToolStripButton_Click(object sender, EventArgs e) + { + optionsMenuItem_Click(sender, e); + } + + #endregion + + #region Trees + + private void treeProcesses_KeyDown(object sender, KeyEventArgs e) + { + if (e.KeyData == Keys.Delete) + { + terminateMenuItem_Click(null, null); + } + else if (e.KeyData == (Keys.Shift | Keys.Delete)) + { + terminateProcessTreeMenuItem_Click(null, null); + } + else if (e.KeyData == Keys.Enter) + { + propertiesProcessMenuItem_Click(null, null); + } + else if (e.KeyData == (Keys.Control | Keys.M)) + { + searchProcessMenuItem_Click(null, null); + } + } + + private void treeProcesses_NodeMouseDoubleClick(object sender, TreeNodeAdvMouseEventArgs e) + { + propertiesProcessMenuItem_Click(null, null); + } + + private void treeProcesses_SelectionChanged(object sender, EventArgs e) + { + processSelectedItems = treeProcesses.SelectedNodes.Count; + + if (processSelectedItems == 1) + { + processSelectedPid = treeProcesses.SelectedNodes[0].Pid; + } + else + { + processSelectedPid = -1; + } + } + + #endregion + + #endregion + + #region Form-related Helper functions + + public void ApplyFont(Font f) + { + treeProcesses.Tree.Font = f; + + if (f.Height > 16) + treeProcesses.Tree.RowHeight = f.Height; + else + treeProcesses.Tree.RowHeight = 16; + + listServices.List.Font = f; + listNetwork.List.Font = f; + } + + public void ClearLog() + { + _log.Clear(); + + if (this.LogUpdated != null) + this.LogUpdated(null); + } + + private void CreateShutdownMenuItems() + { + AddMenuItemDelegate addMenuItem = (string text, EventHandler onClick) => + { + shutdownMenuItem.MenuItems.Add(new MenuItem(text, onClick)); + shutdownTrayMenuItem.MenuItems.Add(new MenuItem(text, onClick)); + shutDownToolStripMenuItem.DropDownItems.Add(text, null, onClick); + }; + + addMenuItem("Lock", (sender, e) => { Win32.LockWorkStation(); }); + addMenuItem("Logoff", (sender, e) => { Win32.ExitWindowsEx(ExitWindowsFlags.Logoff, 0); }); + addMenuItem("-", null); + addMenuItem("Sleep", (sender, e) => { Win32.SetSuspendState(false, false, false); }); + addMenuItem("Hibernate", (sender, e) => { Win32.SetSuspendState(true, false, false); }); + addMenuItem("-", null); + addMenuItem("Restart", (sender, e) => + { + if (PhUtils.ShowConfirmMessage("restart", "the computer", null, false)) + Win32.ExitWindowsEx(ExitWindowsFlags.Reboot, 0); + }); + addMenuItem("Shutdown", (sender, e) => + { + if (PhUtils.ShowConfirmMessage("shutdown", "the computer", null, false)) + Win32.ExitWindowsEx(ExitWindowsFlags.Shutdown, 0); + }); + addMenuItem("Poweroff", (sender, e) => + { + if (PhUtils.ShowConfirmMessage("poweroff", "the computer", null, false)) + Win32.ExitWindowsEx(ExitWindowsFlags.Poweroff, 0); + }); + } + + public void DeselectAll(ListView list) + { + foreach (ListViewItem item in list.SelectedItems) + item.Selected = false; + } + + public void DeselectAll(TreeViewAdv tree) + { + foreach (TreeNodeAdv node in tree.AllNodes) + node.IsSelected = false; + } + + // Technique from http://www.vb-helper.com/howto_2008_uac_shield.html + private Bitmap GetUacShieldIcon() + { + const int width = 50; + const int height = 50; + const int margin = 4; + Bitmap shieldImage; + Button button = new Button() + { + Text = " ", + Size = new Size(width, height), + FlatStyle = FlatStyle.System + }; + + button.SetShieldIcon(true); + + Bitmap buttonImage = new Bitmap(width, height); + + button.Refresh(); + button.DrawToBitmap(buttonImage, new Rectangle(0, 0, width, height)); + + int minX = width; + int maxX = 0; + int minY = width; + int maxY = 0; + + for (int y = margin; y < height - margin; y++) + { + var targetColor = buttonImage.GetPixel(margin, y); + + for (int x = margin; x < width - margin; x++) + { + if (buttonImage.GetPixel(x, y).Equals(targetColor)) + { + buttonImage.SetPixel(x, y, Color.Transparent); + } + else + { + if (minY > y) minY = y; + if (minX > x) minX = x; + if (maxY < y) maxY = y; + if (maxX < x) maxX = x; + } + } + } + + int shieldWidth = maxX - minX + 1; + int shieldHeight = maxY - minY + 1; + + shieldImage = new Bitmap(shieldWidth, shieldHeight); + + using (Graphics g = Graphics.FromImage(shieldImage)) + g.DrawImage(buttonImage, 0, 0, new Rectangle(minX, minY, shieldWidth, shieldHeight), GraphicsUnit.Pixel); + + buttonImage.Dispose(); + + return shieldImage; + } + + private void LoadWindowSettings() + { + this.TopMost = Program.HackerWindowTopMost = Properties.Settings.Default.AlwaysOnTop; + + this.Size = Properties.Settings.Default.WindowSize; + this.Location = Utils.FitRectangle(new Rectangle( + Properties.Settings.Default.WindowLocation, this.Size), this).Location; + + if (Properties.Settings.Default.WindowState != FormWindowState.Minimized) + this.WindowState = Properties.Settings.Default.WindowState; + else + this.WindowState = FormWindowState.Normal; + } + + private void LoadOtherSettings() + { + Utils.UnitSpecifier = Properties.Settings.Default.UnitSpecifier; + + PromptBox.LastValue = Properties.Settings.Default.PromptBoxText; + toolbarMenuItem.Checked = toolStrip.Visible = Properties.Settings.Default.ToolbarVisible; + + if (Properties.Settings.Default.ToolStripDisplayStyle == 1) + { + findHandlesToolStripButton.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText; + sysInfoToolStripButton.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText; + refreshToolStripButton.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText; + optionsToolStripButton.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText; + shutDownToolStripMenuItem.DisplayStyle = ToolStripItemDisplayStyle.Image; + } + else if (Properties.Settings.Default.ToolStripDisplayStyle == 2) + { + refreshToolStripButton.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText; + optionsToolStripButton.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText; + shutDownToolStripMenuItem.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText; + findHandlesToolStripButton.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText; + sysInfoToolStripButton.DisplayStyle = ToolStripItemDisplayStyle.ImageAndText; + } + else + { + refreshToolStripButton.DisplayStyle = ToolStripItemDisplayStyle.Image; + optionsToolStripButton.DisplayStyle = ToolStripItemDisplayStyle.Image; + shutDownToolStripMenuItem.DisplayStyle = ToolStripItemDisplayStyle.Image; + findHandlesToolStripButton.DisplayStyle = ToolStripItemDisplayStyle.Image; + sysInfoToolStripButton.DisplayStyle = ToolStripItemDisplayStyle.Image; + } + + ColumnSettings.LoadSettings(Properties.Settings.Default.ProcessTreeColumns, treeProcesses.Tree); + ColumnSettings.LoadSettings(Properties.Settings.Default.ServiceListViewColumns, listServices.List); + ColumnSettings.LoadSettings(Properties.Settings.Default.NetworkListViewColumns, listNetwork.List); + + HighlightingContext.Colors[ListViewItemState.New] = Properties.Settings.Default.ColorNew; + HighlightingContext.Colors[ListViewItemState.Removed] = Properties.Settings.Default.ColorRemoved; + TreeNodeAdv.StateColors[TreeNodeAdv.NodeState.New] = Properties.Settings.Default.ColorNew; + TreeNodeAdv.StateColors[TreeNodeAdv.NodeState.Removed] = Properties.Settings.Default.ColorRemoved; + + Program.ImposterNames = new System.Collections.Specialized.StringCollection(); + + foreach (string s in Properties.Settings.Default.ImposterNames.Split(',')) + Program.ImposterNames.Add(s.Trim()); + + HistoryManager.GlobalMaxCount = Properties.Settings.Default.MaxSamples; + ProcessHacker.Components.Plotter.GlobalMoveStep = Properties.Settings.Default.PlotterStep; + + // Set up symbols... + + // If this is the first time Process Hacker is being run, try to + // set up symbols automatically to make the user happy :). + // We need the exception handler because some people have their + // ProgramFiles variable set incorrectly. + try + { + if (Properties.Settings.Default.FirstRun) + { + string defaultDbghelp = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + + "\\Debugging Tools for Windows (" + + (IntPtr.Size == 4 ? "x86" : "x64") + + ")\\dbghelp.dll"; + + if (System.IO.File.Exists(defaultDbghelp)) + Properties.Settings.Default.DbgHelpPath = defaultDbghelp; + } + } + catch (Exception ex) + { + Logging.Log(ex); + } + + // If we couldn't load dbghelp.dll from the user's location, load the default one + // in PATH (usually in system32). + if (Loader.LoadDll(Properties.Settings.Default.DbgHelpPath) == IntPtr.Zero) + Loader.LoadDll("dbghelp.dll"); + + // Find the location of the dbghelp.dll we loaded and load symsrv.dll. + try + { + ProcessHandle.GetCurrent().EnumModules((module) => + { + if (module.FileName.ToLowerInvariant().EndsWith("dbghelp.dll")) + { + // Load symsrv.dll from the same directory as dbghelp.dll. + + Loader.LoadDll(System.IO.Path.GetDirectoryName(module.FileName) + "\\symsrv.dll"); + + return false; + } + + return true; + }); + } + catch + { } + + // Set the first run setting here. + Properties.Settings.Default.FirstRun = false; + } + + public void QueueMessage(string message) + { + if (this.InvokeRequired) + { + this.BeginInvoke(new MethodInvoker(() => this.QueueMessage(message))); + return; + } + + var value = new KeyValuePair(DateTime.Now, message); + + _log.Add(value); + + if (this.LogUpdated != null) + this.LogUpdated(value); + } + + private void SaveSettings() + { + if (this.WindowState == FormWindowState.Normal && this.Visible) + { + Properties.Settings.Default.WindowLocation = this.Location; + Properties.Settings.Default.WindowSize = this.Size; + } + + Properties.Settings.Default.AlwaysOnTop = this.TopMost; + Properties.Settings.Default.WindowState = this.WindowState == FormWindowState.Minimized ? + FormWindowState.Normal : this.WindowState; + Properties.Settings.Default.ToolbarVisible = toolStrip.Visible; + + Properties.Settings.Default.PromptBoxText = PromptBox.LastValue; + + Properties.Settings.Default.ProcessTreeColumns = ColumnSettings.SaveSettings(treeProcesses.Tree); + Properties.Settings.Default.ServiceListViewColumns = ColumnSettings.SaveSettings(listServices.List); + Properties.Settings.Default.NetworkListViewColumns = ColumnSettings.SaveSettings(listNetwork.List); + + Properties.Settings.Default.NewProcesses = NPMenuItem.Checked; + Properties.Settings.Default.TerminatedProcesses = TPMenuItem.Checked; + Properties.Settings.Default.NewServices = NSMenuItem.Checked; + Properties.Settings.Default.StartedServices = startedSMenuItem.Checked; + Properties.Settings.Default.StoppedServices = stoppedSMenuItem.Checked; + Properties.Settings.Default.DeletedServices = DSMenuItem.Checked; + + try + { + Properties.Settings.Default.Save(); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to save settings", ex); + } + } + + public void SelectAll(TreeViewAdv tree) + { + foreach (TreeNodeAdv node in tree.AllNodes) + node.IsSelected = true; + } + + private void SelectProcess(int pid) + { + DeselectAll(treeProcesses.Tree); + + try + { + TreeNodeAdv node = treeProcesses.FindTreeNode(pid); + + node.EnsureVisible(); + node.IsSelected = true; + treeProcesses.Tree.FullUpdate(); + treeProcesses.Tree.Invalidate(); + + tabControl.SelectedTab = tabProcesses; + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + + private void UpdateProgram(bool interactive) + { + checkForUpdatesMenuItem.Enabled = false; + + Thread t = new Thread(new ThreadStart(() => + { + Updater.Update(this, interactive); + this.Invoke(new MethodInvoker(() => checkForUpdatesMenuItem.Enabled = true)); + })); + t.IsBackground = true; + t.Start(); + } + + private void UpdateSessions() + { + var currentServer = TerminalServerHandle.GetCurrent(); + + usersMenuItem.MenuItems.Clear(); + + foreach (var session in currentServer.GetSessions()) + { + string displayName = session.DomainName + "\\" + session.UserName; + + if (displayName == "\\") + { + // Probably the Services or RDP-Tcp session. + session.Dispose(); + continue; + } + + MenuItem userMenuItem = new MenuItem(); + + userMenuItem.Text = session.SessionId + ": " + displayName; + + MenuItem currentMenuItem; + + currentMenuItem = new MenuItem() { Text = "Disconnect", Tag = session.SessionId }; + currentMenuItem.Click += (sender, e) => + { + int sessionId = (int)((MenuItem)sender).Tag; + + SessionActions.Disconnect(this, sessionId, false); + }; + userMenuItem.MenuItems.Add(currentMenuItem); + currentMenuItem = new MenuItem() { Text = "Logoff", Tag = session.SessionId }; + currentMenuItem.Click += (sender, e) => + { + int sessionId = (int)((MenuItem)sender).Tag; + + SessionActions.Logoff(this, sessionId, true); + }; + userMenuItem.MenuItems.Add(currentMenuItem); + currentMenuItem = new MenuItem() { Text = "Send Message...", Tag = session.SessionId }; + currentMenuItem.Click += (sender, e) => + { + int sessionId = (int)((MenuItem)sender).Tag; + + try + { + var mbw = new MessageBoxWindow(); + + mbw.MessageBoxTitle = "Message from " + Program.CurrentUsername; + mbw.OkButtonClicked += () => + { + try + { + TerminalServerHandle.GetCurrent().GetSession(sessionId).SendMessage( + mbw.MessageBoxTitle, + mbw.MessageBoxText, + MessageBoxButtons.OK, + mbw.MessageBoxIcon, + 0, + 0, + mbw.MessageBoxTimeout, + false + ); + return true; + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to send the message", ex); + return false; + } + }; + mbw.ShowDialog(); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to show the message window", ex); + } + }; + userMenuItem.MenuItems.Add(currentMenuItem); + currentMenuItem = new MenuItem() { Text = "Properties...", Tag = session.SessionId }; + currentMenuItem.Click += (sender, e) => + { + int sessionId = (int)((MenuItem)sender).Tag; + + try + { + var sessionInformationWindow = + new SessionInformationWindow(TerminalServerHandle.GetCurrent().GetSession(sessionId)); + + sessionInformationWindow.ShowDialog(); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to show session properties", ex); + } + }; + userMenuItem.MenuItems.Add(currentMenuItem); + + usersMenuItem.MenuItems.Add(userMenuItem); + session.Dispose(); + } + } + + private void UpdateStatusInfo() + { + if (processP.RunCount >= 1) + statusGeneral.Text = string.Format("{0} processes", processP.Dictionary.Count - 2); + else + statusGeneral.Text = "Loading..."; + + statusCPU.Text = "CPU: " + (processP.CurrentCpuUsage * 100).ToString("N2") + "%"; + statusMemory.Text = "Phys. Memory: " + + ((float)(processP.System.NumberOfPhysicalPages - processP.Performance.AvailablePages) * 100 / + processP.System.NumberOfPhysicalPages).ToString("N2") + "%"; + } + + #endregion + + #region Helper functions + + private void SetProcessPriority(ProcessPriorityClass priority) + { + try + { + using (var phandle = new ProcessHandle(processSelectedPid, ProcessAccess.SetInformation)) + phandle.SetPriorityClass(priority); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to set process priority", ex); + } + } + + #endregion + + #region Notification Icons + + public void ExecuteOnIcons(Action action) + { + notifyIcons.ForEach(action); + } + + public UsageIcon GetFirstIcon() + { + foreach (var icon in notifyIcons) + if (icon.Visible) + return icon; + + return dummyIcon; + } + + public int GetIconsVisibleCount() + { + int count = 0; + + foreach (var icon in notifyIcons) + if (icon.Visible) + count++; + + return count; + } + + public void ApplyIconVisibilities() + { + cpuHistoryIcon.Visible = cpuHistoryIcon.Enabled = Properties.Settings.Default.CpuHistoryIconVisible; + cpuUsageIcon.Visible = cpuUsageIcon.Enabled = Properties.Settings.Default.CpuUsageIconVisible; + ioHistoryIcon.Visible = ioHistoryIcon.Enabled = Properties.Settings.Default.IoHistoryIconVisible; + commitHistoryIcon.Visible = commitHistoryIcon.Enabled = Properties.Settings.Default.CommitHistoryIconVisible; + physMemHistoryIcon.Visible = physMemHistoryIcon.Enabled = Properties.Settings.Default.PhysMemHistoryIconVisible; + + if (cpuHistoryIcon.Visible) + UsageIcon.ActiveUsageIcon = cpuHistoryIcon; + else + UsageIcon.ActiveUsageIcon = null; + } + + #endregion + + protected override void WndProc(ref Message m) + { + switch (m.Msg) + { + // Magic number - PH uses this to detect previous instances. + case 0x9991: + { + this.Visible = true; + + if (this.WindowState == FormWindowState.Minimized) + { + this.Location = Properties.Settings.Default.WindowLocation; + this.Size = Properties.Settings.Default.WindowSize; + this.WindowState = FormWindowState.Normal; + } + m.Result = new IntPtr(0x1119); + + return; + } + //break; + + case (int)WindowMessage.SysCommand: + { + if (m.WParam.ToInt32() == 0xf020) // SC_MINIMIZE + { + try + { + if (this.WindowState == FormWindowState.Normal && this.Visible) + { + Properties.Settings.Default.WindowLocation = this.Location; + Properties.Settings.Default.WindowSize = this.Size; + } + + if (this.GetIconsVisibleCount() > 0 && Properties.Settings.Default.HideWhenMinimized) + { + this.Visible = false; + + return; + } + } + catch + { } + } + } + break; + + case (int)WindowMessage.Paint: + this.Painting(); + break; + + case (int)WindowMessage.Activate: + case (int)WindowMessage.KillFocus: + { + if (treeProcesses != null && treeProcesses.Tree != null) + treeProcesses.Tree.Invalidate(); + } + break; + + case (int)WindowMessage.WtsSessionChange: + { + WtsSessionChangeEvent changeEvent = (WtsSessionChangeEvent)m.WParam.ToInt32(); + + if ( + changeEvent == WtsSessionChangeEvent.SessionLogon || + changeEvent == WtsSessionChangeEvent.SessionLogoff + ) + { + try + { + this.UpdateSessions(); + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + } + break; + + case (int)WindowMessage.SettingChange: + { + // Refresh icon sizes. + this.ExecuteOnIcons((icon) => icon.Size = UsageIcon.GetSmallIconSize()); + // Refresh the tree view visual style. + treeProcesses.Tree.RefreshVisualStyles(); + } + break; + } + + base.WndProc(ref m); + } + + public void Exit() + { + //processP.Dispose(); + //serviceP.Dispose(); + //networkP.Dispose(); + + this.ExecuteOnIcons((icon) => icon.Visible = false); + this.ExecuteOnIcons((icon) => icon.Dispose()); + SaveSettings(); + this.Visible = false; + + if (KProcessHacker.Instance != null) + KProcessHacker.Instance.Close(); + + try + { + Win32.ExitProcess(0); + } + catch + { } + } + + private void HackerWindow_FormClosing(object sender, FormClosingEventArgs e) + { + if (e.CloseReason == CloseReason.WindowsShutDown) + { + this.Exit(); + return; + } + + if (this.GetIconsVisibleCount() > 0 && + Properties.Settings.Default.HideWhenClosed) + { + e.Cancel = true; + showHideMenuItem_Click(sender, null); + return; + } + + this.Exit(); + } + + private void CheckedMenuItem_Click(object sender, EventArgs e) + { + ((MenuItem)sender).Checked = !((MenuItem)sender).Checked; + } + + private void UpdateCommon() + { + treeProcesses.RefreshItems(); + } + + public void LoadFixMenuItems() + { + if (!System.IO.File.Exists(Application.StartupPath + "\\Assistant.exe")) + { + runAsServiceMenuItem.Enabled = false; + runAsProcessMenuItem.Visible = false; + } + + if (KProcessHacker.Instance == null) + hiddenProcessesMenuItem.Visible = false; + + if (KProcessHacker.Instance == null || !OSVersion.HasSetAccessToken) + setTokenProcessMenuItem.Visible = false; + + if (KProcessHacker.Instance == null || !Properties.Settings.Default.EnableExperimentalFeatures) + protectionProcessMenuItem.Visible = false; + + if (!OSVersion.HasUac) + virtualizationProcessMenuItem.Visible = false; + + if (OSVersion.IsBelow(WindowsVersion.Vista)) + analyzeWaitChainProcessMenuItem.Visible = false; + } + + private void LoadFixNProcessHacker() + { + bool nphExists, nph32Exists, nph64Exists; + string startupPath = Application.StartupPath; + + try + { + nphExists = System.IO.File.Exists(startupPath + "\\NProcessHacker.dll"); + nph32Exists = System.IO.File.Exists(startupPath + "\\NProcessHacker32.dll"); + nph64Exists = System.IO.File.Exists(startupPath + "\\NProcessHacker64.dll"); + + // If we're on 32-bit and NPH32 exists, rename NPH to NPH64 and + // NPH32 to NPH. + if (IntPtr.Size == 4) + { + if (nph32Exists) + { + if (nphExists) + System.IO.File.Move(startupPath + "\\NProcessHacker.dll", startupPath + "\\NProcessHacker64.dll"); + + System.IO.File.Move(startupPath + "\\NProcessHacker32.dll", startupPath + "\\NProcessHacker.dll"); + } + } + // If we're on 64-bit and NPH64 exists, rename NPH to NPH32 and + // NPH64 to NPH. + else if (IntPtr.Size == 8) + { + if (nph64Exists) + { + if (nphExists) + System.IO.File.Move(startupPath + "\\NProcessHacker.dll", startupPath + "\\NProcessHacker32.dll"); + + System.IO.File.Move(startupPath + "\\NProcessHacker64.dll", startupPath + "\\NProcessHacker.dll"); + } + } + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + + private void LoadUac() + { + if (Program.ElevationType == TokenElevationType.Limited) + { + uacShieldIcon = this.GetUacShieldIcon(); + + vistaMenu.SetImage(showDetailsForAllProcessesMenuItem, uacShieldIcon); + //vistaMenu.SetImage(startServiceMenuItem, uacShieldIcon); + //vistaMenu.SetImage(continueServiceMenuItem, uacShieldIcon); + //vistaMenu.SetImage(pauseServiceMenuItem, uacShieldIcon); + //vistaMenu.SetImage(stopServiceMenuItem, uacShieldIcon); + //vistaMenu.SetImage(deleteServiceMenuItem, uacShieldIcon); + //runAsServiceMenuItem.Visible = false; + //runAsProcessMenuItem.Visible = false; + } + else + { + runAsAdministratorMenuItem.Visible = false; + showDetailsForAllProcessesMenuItem.Visible = false; + } + } + + private void LoadNotificationIcons() + { + using (Bitmap b = new Bitmap(16, 16)) + { + using (Graphics g = Graphics.FromImage(b)) + { + g.FillRectangle(new SolidBrush(Color.Black), 0, 0, b.Width, b.Height); + blackIcon = Icon.FromHandle(b.GetHicon()); + } + } + + dummyIcon = new UsageIcon(); + notifyIcons.Add(cpuHistoryIcon = new CpuHistoryIcon() { Parent = this }); + notifyIcons.Add(cpuUsageIcon = new CpuUsageIcon() { Parent = this }); + notifyIcons.Add(ioHistoryIcon = new IoHistoryIcon() { Parent = this }); + notifyIcons.Add(commitHistoryIcon = new CommitHistoryIcon() { Parent = this }); + notifyIcons.Add(physMemHistoryIcon = new PhysMemHistoryIcon() { Parent = this }); + + foreach (var icon in notifyIcons) + icon.Icon = (Icon)blackIcon.Clone(); + + this.ExecuteOnIcons((icon) => icon.ContextMenu = menuIcon); + this.ExecuteOnIcons((icon) => icon.MouseDoubleClick += notifyIcon_MouseDoubleClick); + cpuHistoryMenuItem.Checked = Properties.Settings.Default.CpuHistoryIconVisible; + cpuUsageMenuItem.Checked = Properties.Settings.Default.CpuUsageIconVisible; + ioHistoryMenuItem.Checked = Properties.Settings.Default.IoHistoryIconVisible; + commitHistoryMenuItem.Checked = Properties.Settings.Default.CommitHistoryIconVisible; + physMemHistoryMenuItem.Checked = Properties.Settings.Default.PhysMemHistoryIconVisible; + this.ApplyIconVisibilities(); + + NPMenuItem.Checked = Properties.Settings.Default.NewProcesses; + TPMenuItem.Checked = Properties.Settings.Default.TerminatedProcesses; + NSMenuItem.Checked = Properties.Settings.Default.NewServices; + startedSMenuItem.Checked = Properties.Settings.Default.StartedServices; + stoppedSMenuItem.Checked = Properties.Settings.Default.StoppedServices; + DSMenuItem.Checked = Properties.Settings.Default.DeletedServices; + + NPMenuItem.Click += new EventHandler(CheckedMenuItem_Click); + TPMenuItem.Click += new EventHandler(CheckedMenuItem_Click); + NSMenuItem.Click += new EventHandler(CheckedMenuItem_Click); + startedSMenuItem.Click += new EventHandler(CheckedMenuItem_Click); + stoppedSMenuItem.Click += new EventHandler(CheckedMenuItem_Click); + DSMenuItem.Click += new EventHandler(CheckedMenuItem_Click); + } + + private void LoadControls() + { + GenericViewMenu.AddMenuItems(copyProcessMenuItem.MenuItems, treeProcesses.Tree); + GenericViewMenu.AddMenuItems(copyServiceMenuItem.MenuItems, listServices.List, null); + GenericViewMenu.AddMenuItems(copyNetworkMenuItem.MenuItems, listNetwork.List, null); + + treeProcesses.ContextMenu = menuProcess; + listServices.ContextMenu = menuService; + listNetwork.ContextMenu = menuNetwork; + + processP.Interval = Properties.Settings.Default.RefreshInterval; + treeProcesses.Provider = processP; + treeProcesses.Tree.BeginUpdate(); + treeProcesses.Tree.BeginCompleteUpdate(); + this.Cursor = Cursors.WaitCursor; + processP.Updated += processP_Updated; + processP.Updated += processP_InfoUpdater; + if (Program.InspectPid != -1) processP.ProcessQueryReceived += processP_FileProcessingReceived; + processP.RunOnceAsync(); + processP.Enabled = true; + updateProcessesMenuItem.Checked = true; + + HighlightingContext.HighlightingDuration = Properties.Settings.Default.HighlightingDuration; + HighlightingContext.StateHighlighting = false; + + listServices.List.BeginUpdate(); + serviceP.Interval = Properties.Settings.Default.RefreshInterval; + listServices.Provider = serviceP; + serviceP.DictionaryAdded += serviceP_DictionaryAdded_Process; + serviceP.DictionaryModified += serviceP_DictionaryModified_Process; + serviceP.DictionaryRemoved += serviceP_DictionaryRemoved_Process; + serviceP.Updated += serviceP_Updated; + updateServicesMenuItem.Checked = true; + + networkP.Interval = Properties.Settings.Default.RefreshInterval; + listNetwork.Provider = networkP; + + treeProcesses.Tree.MouseDown += (sender, e) => + { + if (e.Button == MouseButtons.Right && e.Location.Y < treeProcesses.Tree.ColumnHeaderHeight) + { + ContextMenu menu = new ContextMenu(); + + menu.MenuItems.Add(new MenuItem("Choose Columns...", (sender_, e_) => + { + (new ChooseColumnsWindow(treeProcesses.Tree) + { }).ShowDialog(); + + copyProcessMenuItem.MenuItems.DisposeAndClear(); + GenericViewMenu.AddMenuItems(copyProcessMenuItem.MenuItems, treeProcesses.Tree); + treeProcesses.Tree.InvalidateNodeControlCache(); + treeProcesses.Tree.Invalidate(); + })); + + menu.Show(treeProcesses.Tree, e.Location); + } + }; + treeProcesses.Tree.ColumnClicked += (sender, e) => { DeselectAll(treeProcesses.Tree); }; + treeProcesses.Tree.ColumnReordered += (sender, e) => + { + copyProcessMenuItem.MenuItems.DisposeAndClear(); + GenericViewMenu.AddMenuItems(copyProcessMenuItem.MenuItems, treeProcesses.Tree); + }; + + tabControlBig_SelectedIndexChanged(null, null); + } + + private void LoadAddShortcuts() + { + treeProcesses.Tree.KeyDown += + (sender, e) => + { + if (e.Control && e.KeyCode == Keys.A) + { + treeProcesses.TreeNodes.SelectAll(); + treeProcesses.Tree.Invalidate(); + } + + if (e.Control && e.KeyCode == Keys.C) GenericViewMenu.TreeViewAdvCopy(treeProcesses.Tree, -1); + }; + listServices.List.AddShortcuts(); + listNetwork.List.AddShortcuts(); + } + + private void LoadApplyCommandLineArgs() + { + tabControl.SelectedTab = tabControl.TabPages["tab" + Program.SelectTab]; + } + + private void LoadStructs() + { + WorkQueue.GlobalQueueWorkItemTag(new Action(() => + { + try + { + if (System.IO.File.Exists(Application.StartupPath + "\\structs.txt")) + { + Structs.StructParser parser = new ProcessHacker.Structs.StructParser(Program.Structs); + + parser.Parse(Application.StartupPath + "\\structs.txt"); + } + } + catch (Exception ex) + { + QueueMessage("Error loading structure definitions: " + ex.Message); + } + }), "load-structs"); + } + + private void LoadOther() + { + try + { + using (var thandle = ProcessHandle.GetCurrent().GetToken(TokenAccess.Query)) + using (var sid = thandle.GetUser()) + this.Text += " [" + sid.GetFullName(true) + (KProcessHacker.Instance != null ? "+" : "") + "]"; + } + catch + { } + + // If it's Vista or above and we're elevated. + if (OSVersion.HasUac && Program.ElevationType == TokenElevationType.Full) + { + this.Text += " (Administrator)"; + // We enable the magic window message to Allow only one Application instance to work. + Win32.ChangeWindowMessageFilter((WindowMessage)0x9991, UipiFilterFlag.Add); + } + } + + public HackerWindow() + { + Program.HackerWindow = this; + processP = Program.ProcessProvider; + serviceP = Program.ServiceProvider; + networkP = Program.NetworkProvider; + + InitializeComponent(); + + // Force the handle to be created + { var handle = this.Handle; } + Program.HackerWindowHandle = this.Handle; + + if (OSVersion.HasExtendedTaskbar) + { + // We need to call this here or we dont recieve the TaskbarButtonCreated WindowMessage + Windows7Taskbar.AllowWindowMessagesThroughUipi(); + Windows7Taskbar.AppId = "ProcessHacker"; + Windows7Taskbar.ProcessAppId = "ProcessHacker"; + + thumbButtonManager = new ThumbButtonManager(this); + thumbButtonManager.TaskbarButtonCreated += new EventHandler(thumbButtonManager_TaskbarButtonCreated); + } + + this.AddEscapeToClose(); + + Logging.Logged += this.QueueMessage; + Settings.Refresh(); + this.LoadWindowSettings(); + this.LoadOtherSettings(); + this.LoadControls(); + this.LoadNotificationIcons(); + + if ((!Properties.Settings.Default.StartHidden && !Program.StartHidden) || + Program.StartVisible) + { + this.Visible = true; + } + + if (tabControl.SelectedTab == tabProcesses) + treeProcesses.Tree.Select(); + + this.LoadOther(); + this.LoadStructs(); + + vistaMenu.DelaySetImageCalls = false; + vistaMenu.PerformPendingSetImageCalls(); + serviceP.RunOnceAsync(); + serviceP.Enabled = true; + + _dontCalculate = false; + } + + private void HackerWindow_Load(object sender, EventArgs e) + { + Program.UpdateWindowMenu(windowMenuItem, this); + this.ApplyFont(Properties.Settings.Default.Font); + this.BeginInvoke(new MethodInvoker(this.LoadApplyCommandLineArgs)); + + //TODO: NetworkInfo unfinished, hidden for 1.6 release + networkInfomationMenuItem.Visible = false; + } + + private void HackerWindow_SizeChanged(object sender, EventArgs e) + { + tabControl.Invalidate(false); + } + + private void HackerWindow_VisibleChanged(object sender, EventArgs e) + { + treeProcesses.Draw = this.Visible; + } + + // ==== Performance hacks section ==== + private bool _dontCalculate = true; + private int _layoutCount = 0; + + protected override void OnLayout(LayoutEventArgs levent) + { + _layoutCount++; + + if (_layoutCount < 3) + return; + + base.OnLayout(levent); + } + + protected override void OnResize(EventArgs e) + { + if (_dontCalculate) + return; + + // + // Size grip bug fix as per + // http://jelle.druyts.net/2003/10/20/StatusBarResizeBug.aspx + // + if (statusBar != null) + { + statusBar.SizingGrip = (WindowState == FormWindowState.Normal); + } + + base.OnResize(e); + } + + private bool isFirstPaint = true; + + private void Painting() + { + if (isFirstPaint) + { + isFirstPaint = false; + + ProcessHackerRestartRecovery.ApplicationRestartRecoveryManager.RegisterForRestart(); + ProcessHackerRestartRecovery.ApplicationRestartRecoveryManager.RegisterForRecovery(); + + this.CreateShutdownMenuItems(); + this.LoadFixMenuItems(); + this.LoadUac(); + this.LoadAddShortcuts(); + this.LoadFixNProcessHacker(); + + toolStrip.Items.Add(new ToolStripSeparator()); + var targetButton = new TargetWindowButton(); + targetButton.TargetWindowFound += (pid, tid) => this.SelectProcess(pid); + toolStrip.Items.Add(targetButton); + + var targetThreadButton = new TargetWindowButton(); + targetThreadButton.TargetWindowFound += (pid, tid) => + { + Program.GetProcessWindow(processP.Dictionary[pid], (f) => + { + Program.FocusWindow(f); + f.SelectThread(tid); + }); + }; + targetThreadButton.Image = Properties.Resources.application_go; + targetThreadButton.Text = "Find window and select thread"; + targetThreadButton.ToolTipText = "Find window and select thread"; + toolStrip.Items.Add(targetThreadButton); + + try { TerminalServerHandle.RegisterNotificationsCurrent(this, true); } + catch (Exception ex) { Logging.Log(ex); } + try { this.UpdateSessions(); } + catch (Exception ex) { Logging.Log(ex); } + + try { Win32.SetProcessShutdownParameters(0x100, 0); } + catch { } + + if (Properties.Settings.Default.AppUpdateAutomatic) + this.UpdateProgram(false); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/HackerWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/HackerWindow.resx new file mode 100644 index 000000000..9f272f97e --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/HackerWindow.resx @@ -0,0 +1,1774 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 141, 17 + + + 113 + + + 586, 17 + + + + + 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 + /wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI+AAAAAAAAAAAAIj4j4gAAAAAAAAACIj/iIiA + AAAAAAAACPiIiIeIAAAAB3B3AIiId3eIgAAAiIh4dwB3eIiIgAAAeHiIeHiId3AHgAAAiIeHh3cAAgMA + gAAAiIeAAAAAJyRygAAAiIiAAicnInIniAAAiHiGNgAApycneAAAh4iAIyKjZyeneAAAh4iHICJCdzZ3 + eAAAcoiFAGMhd3o2OAAAh4+DAiJ2JjZ3eAAAAIj2cHIHd3d3eAAAAACHAAUneIiI+AAAAAAId3eIiI+P + gAAAAAAIjwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD////////////4 + ////wD///4Af//+AD//kwAf/wDAH/8AAB//AAAf/wAAH/8AAA//AAAP/wAAD/8AAA//AAAP/wAAD//AA + A//8AAP//gAH//4///////////////////8oAAAAEAAAACAAAAABAAQAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAgAAAgAAAAICAAIAAAACAAIAAgIAAAICAgADAwMAAAAD/AAD/AAAA//8A/wAAAP8A + /wD//wAA////AAAAAAAAAAAAd3AAiIeHgACHgAD4iIcAAIiAAACHcAAAiIiIiIiIeHiIiIiIiIiIiIiI + gAAAAAD3iIiAAAcncIiKeIBwAioniIF4iiAadaqIiI9wImd3dYgACIBKN3d3iAAIgDBHJWOIAAiHiHiI + iIgACI+IiIiIiAAAAAAAAAAA/////xwH//8cD///Hx///wAA//8AAP//AAD//wAA//8AAP//AAD//wAA + ///gAP//4AD//+AA///gAP///////ygAAAAwAAAAYAAAAAEACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAABwoHAAwMDAANFA0ACxkLABISEgAUGhQAGhoaACcAAgAKPQkAFSMVABYoFgAbJBsAHCocABI6 + EQAeMx4AIyQjACIpIgAsLCwAIjQiACM7IwAsMywAKzsrADQ0NAA0PjQAOzw7ABZLFQAGVBsAFlMVAA54 + DAATZBIAFWsTABNzEQAVeBMAGnoXABx0GgAgeB8AJUIlAChKJwArRSsAK0srACVVJQAtUi0ANEM0ADJL + MgA7QzsAPko+ADFTMQAzXDMAO1M7ADtcOwAmdiUANmM2ADpkOgA6azoANXY0AD1wPQA5ezgAQ0NDAEVL + RQBNTU0AVEtDAEFVQQBFWUUATldOAExeTABSUlIAU19TAFxcXABjRFUAQmJCAENtQwBNbU0AR3NHAFNs + UwBfYl8AW21bAFR0VABUeFQAXHRcAFp5WgBiYmIAamRkAGZsZgBmZ2gAampqAHxtbABjdmMAY3pjAGl1 + aQBre2sAcnJyAH1ydABzfHMAeHh3AHt7ewCDe3oADosLAA+dCwAUghIAGYYXAB6MHAAVnhMAEaoOABSi + EAAVqxIAHKQZABWwEQAesBwAHL8ZACKsHwAisx8AILweACSHIgAniCUAKI8mAC2ELAAlkiMAI5ohACuS + KQAsnyoAMpwvADaCNgAzjDEAOYo4ADOQMgA2mzQAPZQ8ADyaOgAmpiMAKKElACSrIgAprCYAK6IpACys + KQAlsiIAKLAlAC6xKwAsvSkAMLItADOjMQA9ojsAOb02AEGcPgBBrD8AHsAbACHAHgAkwiEAKcMmADTB + MQA+lGcARYJEAEmKRwBKhkgASYtIAEObQQBKlEgAWIpXAEajRABDs0AAUbJPAGiBZwBnkWYAc4JzAH6B + fgA0zX4AAP9rAISAfgB/f4EAf4GBAHS3mwBh25wAg4KCAIWFiQCIh4oAi4uLAJCLiwCNmYwAkJGPAIyN + kgCSj5UAi5GUAICdkACNlpsAk5OTAJmVlACTl5oAmJabAJScnwCbmpsAoZ2dAJWpnQCdnaIAqZygAJuk + pwCdpqoAkbunAKOjowCppaQAqamnAKSmqgCkqKwArKusALCsrACysK4Ap66xAKutsACxr7AAvK60AKyy + tQCvubwAs7OzALu1tgC0ursAu7q7AMOqsgDKp7oAw6y4AMG8vgC+wL4AvL7AAMO9wQC8wsQAucfJALzM + zwDDw8QAy8TFAM/IxwDEx8kAzMTIAMPIygDLy8sA0MnJAMbN0QDPz9AAxdHUAM3S0wDM1tgAy9nbANLT + 0wDU19gA09rbANvb2wDW3uAA3N/hANfg4gDb4OIA3+bpAOPj5ADi5+kA5+npAOnq6wDv8vMA8/T0APf3 + +AD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + 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 + FAAcHRwACzwKABckFwAZIxkAHCwcACMjIwAjKyMAKysrACIyIgAlOyQAKjIqACs8KwA1NTUANDs0ADw8 + PABHJi0AD0EOABpDGQAfWx4AIkYZACBXHwANZAoAEXUPABVlEwAVbRMAGW4WABNzEQAWfRQAG3cZACdF + JwAuRy4ALEosADNDMwA3TzcAOkU6ADpLOQA0VDQAM1wzADtWOwA6XDoAAHs5ACpuKQAwci8ANmQ2AD9h + NwA5YjkAO2w7AD1wPQA/fD4AQkJCAEdORwBLS0sAQlRBAFRXSgBVVFQAX19fAEBtQABAcEAASHhHAElz + SQBLeEsAVGVUAFxhXABUdFQAWXZRAFV4VQBZcVkAXHpcAHpfZwBlZWUAampqAGFzYQBiemIAaHZoAGJ4 + aQBtf20Ac3NzAHp0dwByfXIAe3t8ABKIDwAVhBIAGY4XAB6AHAAajBgAEpEQABycGgAiih8AEawNABWh + EwAUrBEAH6UcAB6pHAAZsBYAH7UcACG6HgAhhyAAKIYmACKLIAAlkCMAKJQmACSbIgApmCcAK5wpADGb + LwA5ijcAM5MxACenIwAupCsAMKgtACK0IAApsCYAI7ogAC6+KwAzqDEAQKs9AB/EGwAhwx8AJMogAC3G + KgAuyCsAMsEvAEuFSgBPiU4ARZtDAFWGVABMp0oARbxDAGiDaABziG8AcYVxAHmCdAB5gXkAfoh+AIJ5 + gAB/jI4Af5SKABXyhQBLxo4AgoKDAIqFhQCAjoAAiYmJAI2NjQCVg4oAjZaNAIqPlACRjpIAnI+XAIid + kwCIkZgAlJSUAJiXlwCRm5UAlpmaAJqZmgCdmpoAnZ2bAJ2bnQCdnJwAoJuaAIycowCVnaEAnJ6gAJil + pgCcrKIAlrSuAJmutQCko6MAqKanAKinrACkqqsArKysALCvrwCusK4AtbCvALGvsACqsbQArb2+ALGx + sQC2srIAsra2ALW1tQC7t7QAtrq3ALq1uQCxurwAubm5AL29vQDMtL4Awbu7AN+oxACux8wAssTHAL3C + wwC4xsoAvcnKALbM0gC8ztQAw8LCAMPDxADAxcYAxcXFAMrExQDExskAxMrLAMnJyQDJzc4Azs7OANHN + zADN0M4Aws7QAM3P0ADYxNAAw9HVAMrQ0gDL1NgAxdreAMjc3wDR0dEA0tTSANLS1ADR1dQA1dXVANzT + 0wDQ19kA3tbYANXa2gDZ2dkA2d3dAN3d3QDT3uEAzuDiAMzn7ADI6e0A0eHiANnj5QDa7O0A3u3uANTu + 9ADd+vwA4ODhAObm5gDg6OoA6urqAO3q6QD19fUA9fb5AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADi + 4uLVwwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADV6+v56+vr1cMAAAAAAAAAAAAAAAAAAAAAAAAAAAC9 + 6+vr+evi4vvV1eLDAAAAAAAAAAAAAAAAAAAAAAAAw+LR1eL5+eLV69HRvdG9AAAAAAAAAAAAAAAAAAAA + AADDvdHR4uvr4tXV0cOmltEAAAAAAAAAAAAAAAAAAAAAANXV0cPV4uLb0cOvkpKmpgAAAAAAAABWk54A + AAAAAAAAAL3i1b29s6aSTT1Mnr2zt9EAAAAApqa966Y6TLCmAAAAAACer59UU1OSqrjK3fP54rMAAACe + vpa34tGmkp6zngAAAACzmZ2ors3q1b2WTcPJwwAAAJ/Dr7Ozs9XrpkySU6nIzMfIvKaUUDsRBgYDmOG9 + AAAAptKvs6+emo6tzfb32q+KRCoRAwUCBgYNJSs3768AAACm2K+3sZ6xq6yKPBQHAgABAAIfZys0bjQr + EofvsAAAAKbnsLOzpt0QBgEAAAADDyQ0NWxlKhRsZxUTUO6wAAAApumws7ev4RoCC1pjNSwmEAkGImw0 + OHJ3Om6B7rAAAACm6a+zva/aNDIrXWEEAgMGBgVbcHE6dnFvczbruAAAAKbYpr3Dvd5HFw1hWAgDBSFc + H2JBfD93N3REReK5AAAApsSXvNXD1IghZF4eHAcZXTF7ZkF5gnhOTE1F2c0AAACbsaDF1c7RrwonLTB1 + LGlaDSB3U4R6gFBTU03RzdEAAJyQkcbr0dPJNDQqCWEGXBgHDINWU39+SkZCNcPdswAAjy9R3OrV29oM + OAcDVxhhEScrRkI2c31GUFVTs96mAACNFkvR6tHe1BQpESRqbXc0NC1SVZKShpKSkpKq6KEAAMJUs/7/ + +eLdPzQkEBlbIwwRPZqSkpKFSkhCNqbrqgAAAADJveL//+89AQYGB2EMERRJSkI2QUZPioyYn/myAAAA + AAAAAL2/2k0DCxImazU0NE+IjJaWlpaUk5JW+78AAAAAAAAAAADbnjQ0JhIREQ4TkpOTlZ6mr7C90eL9 + 0wAAAAAAAAAAAAC9AAYMEzg+U5q9w8PR09ne6O/z+vkAAAAAAAAAAAAAAMOTp73DyuHx8e/z8wAAAAAA + AAAAAAAAAAAAAAAAAAAA4vX1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////4P///4A///4 + AD//8AAf//AAH//wAB/H+AAHgD4AA4APAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AA + AAGAAAABgAAAAYAAAAGAAAAB4AAAAfwAAAH/AAAB/4AAA/+AB///j/////////////8oAAAAGAAAADAA + AAABAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUFBQAJCQkAAhcCAAIfAQAGGgYAERERABEV + EQAQGBAAERwRABYfFgAYGBgAHh4eAAIgAgALIwsADy8OAA8wDgAQNA8AFSEUABcnFwAZJBkAGioaABQx + FAAeNR4AICAgACQkJAAqKioALi4uADAtLQAiPyIALT0tADMzMwBBPT0AC18JABNrEgAXcxYAFHoRAB59 + GwAuTS4AKlAqADdONwAyWzIANVk1ADlYOQA+Xz4AEWU0ADJlMQA0YDQAN243ADhnOAA9YT0AOmo6AD1o + PQA8bTwAPHA8AEFBQQBKR0cATEhHAEtISABOTk4AUlJSAFVeVQBAcUAARndFAEhxSABeY14AUXRRAFJ5 + UgB5V2MAY2NjAGZmZgBlaGUAam1sAG5ubgBiemIAZXplAG94bwBxcXEAdXV1AHR+dAB6enoAfnt8AH9/ + fwAPgAwADYoKABCNDQAQng4AF4MUABSIEgAciRoAIJodABCgDQAcrhkAIYQgACaDJAAonCYALJ0qADiR + NQA8kjoAKaInACS1IAA0oTIAPag7AB/CGwApwyYAKscmAEyKSwBMn0kAQqFAAEeiRABNoUsAfYB9AICp + fAB/g4UAP8uFAIKCggCEhIQAgYmNAIyLigCOjo4AkI6OAIGWjACTkI8AiY+QAIiQkgCNlZcAkZGRAJWU + lACYl5cAl5ydAJmZmQCdnZ0Al5+gAJqgogCYr6UAoqKiAKSjowCmpaYAqKenAKeppwCuq6cAqKaoAK2l + qQCqqqkAq66vAK2trQCxp6kAtaSqALCpqwC0qq8AsK6vAKazsgCvs7MAq7S3ALKysgC2sbMAsbS2ALa1 + tQCztrgAt7i5ALC7vAC3uLwAs7y+ALq5ugC9vr4Awb69AMi7vgDFwL4AtL7BALnCwwC+xsYAvcfJALrI + yQDCwsIAxMPCAMPExQDFxcUAzMXGAMDIygDFyckAxszMAMnJyQDOyMkAys3NAM3NzQDZzdMAy9HTANHR + 0QDQ09QA1tLVANDU1QDV1dUA2dXXANPX2gDX2twA2dnZAN7a2ADe3t4A2N/hAN3i5ADe5OYA2ObpAOHh + 4QDh5ucA4O/vAPn8/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAv7MAAAAAAAAAAAAAAAAAAAAAAADAtcXK + xcW1tQAAAAAAAAAAAAAAAAAAALWztcXFu8C7raQAAAAAAAAAAAAAAAAAALuzrcDDu62PeI+IAAAAAAAA + AFGAAFGCAACknZ2Lf1FIe6CYjwAAAAAAioytrX5/f38AAIV+dYSkta3FswAAAAAAj52InZ6LcX6EnYuL + fnFGNwwfrAAAAAAAlqeNgoKXi39NOxsSDhAQFhIfoAAAAAAAnbGNj5QZCQMNDQUCFF4oKzA1kAAAAAAA + nbGPj5QHCSMdJy82X2crMmRjiLMAAAAAlqaNpKE1L1wXFQoHXGJiP2VAcKoAAAAAlpOKtaoaJSQhU1Yi + X0ZoamxGeKwAAAAAhnKWuawgJxBUVRJZQU1sbm5IdqgAAAAAeS2NwLI4GQJbWBkaTkxLaUNAPpgAAAAA + jUS5zbs4BxRZWio0NkBCZktMcZ0AAAAAAACtwMc4MSonXh49e3FxdHR/gq0AAAAAAAAAALV/AAcLFBpN + ioydscDAwMAAAAAAAAAAAACkPEZxg6e1tbXAwcPHyAAAAAAAAAAAAADDycwAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAP///wD///8A//j/AP/APwD/gB8A/4APAOTABwDAMAcAwAAHAMAABwDAAAcAwAADAMAA + AwDAAAMAwAADAMAAAwDAAAMA8AADAPwAAwD+AAcA/j//AP///wD///8A////ACgAAAAQAAAAIAAAAAEA + CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwsLAA0NDQASEhIAFRUVABkZGQAbHxsAHh4eACEh + IQAmJiYAKCgoACwsLAA0NDQAEngQABd8FQAyWzEAI2ohAENDQwBIREMAVlZWAFpaWgBdXV0AW3ZaAGBg + YABnZ2cAaWlpAGxsbABzc3MAdnZ2AHt5eQARpA4AF6gTABazEwAiph8ALIIqAC2fKwA5jjcAJrkiABvT + FwAP8goAEPALACbJIgAA8kgAYsKCAIqKigCRkJAAlJSUAJucnACenp4An6CgAJm/pQCgoKAApKSkAKqq + qgCrrKwAra2tALCxsQC0tbUAuLm5ALu8vAC+vr4AwMDAAMTGxgDFyMgAyMrKAMnLzADKzMwAzM7OAM7Q + 0ADQ0dIA1dbWANnZ2QDf398A6OjoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8AAAAAAAAAAAAAAAAAAAAAAC0dLQAAADs7OS8vMTMA + AAA9LTkAAABJQD07NTMAAAAANT0zAAAAAAA7LC8AAAAAADlFNUg9PTs7OTU1MzMzM0A1RTVFREBAQEBA + QEBAQEAvOUU1RTUAAQAAAQUFBQQ9MzhFNUU4BQUBBAoiIRELQDMyKitFNQoFBAQPJSMkEUAzNRIdRTMn + HgQFJhUVKSdANUc7REUzCg0OIBYZGBkYQDUAAABFMwMEHxAcHBwcGUA5AAAARTMEBQsMGRgVFRNAOQAA + AEUzMzMzMzU5OTk7QDkAAABIRUVFRUVFQEBAQEBHAAAAAAAAAAAAAAAAAAAAAP//AAAcBwAAHA8AAB8f + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4AAAAOAAAADgAAAA4AAAAP//AACJUE5HDQoaCgAA + AA1JSERSAAABAAAAAQAIBgAAAFxyqGYAAP//SURBVHja7L0HnCVHdS98Otw8Oc/uzkattEhkCT1nG2z8 + /WyThYQxGBxA5GQw/ghCJpv0MO/5+TOGRzbB2EgCCfvDgDEYlCWU0642zGyYnZ08c3N3v5Oquu6d2WUF + K+G3e0u6OzP39u2urq7zrxP+dY4HndZpnXbGNu/n3YFO67RO+/m1DgB0Wqedwa0DAJ3WaWdw6wBAp3Xa + Gdw6ANBpnXYGtw4AdFqnncGtAwCd1mlncOsAQKd12hncOgDQaZ12BrcOAHRap53BrQMAndZpZ3DrAECn + ddoZ3DoA0Gmddga3DgB0Wqedwa0DAJ3WaWdw6wBAp3XaGdw6ANBpnXYGtw4AdFqnncGtAwCd1mlncOsA + QKd12hncOgDQaZ12BrcOAHRap53BrQMAndZpZ3DrAECnddoZ3DoA0Gmddga3DgB0Wqedwa0DAJ3WaWdw + 6wBAp3XaGdw6ANBpnXYGtw4AdFqnncGtAwCd1mlncOsAQKd12hncOgDQaZ12BrcOAHRap53BrQMAndZp + Z3DrAECnddoZ3DoA0Gmddga30x4Avv/973sJwKYjhydfXKtVH49vdZ3K+/Y8D5IkeUTuha51urVHauz+ + CzW64XJXV/e1v/ZrT/kS/n5oaGgo/nl15vSbUU774X/+Jwn/9jiOX4/Cf3GSxIO+H/h41z49Bg8nX0y/ + 4P94DHhBkARBwOPiq2CbV+x5SYCjFfqB5/MxCUSxfMaDSMfhOYCE1IAC/iShpc/p/PSe7/tA546iSI+B + hI6yYmDORxcwEs8/ksSnrnpehOfA7+A9eF4AziGe5x8XJNz35VdvnWPWf18/S+TDls8TfXmeXoDH4yT6 + oH8n61zQnvM4nYm9tKPeOtdKZNjTr5tjTN/My+2XOWX7GOixiXst57vmsXnp++vdktM56QM9wyO9vX3X + 4O//A9++Z3Bw8OcCAqc1APzH977XjYJ2aZwkb8SRH6MnaAQazMpDD5jeo5++CpAKqhEu/A0S+gxfAQkw + yINM3MnnnNNOEAUDzxxP5/I8/n6TwEJBwjyIJBX+tG96DgMMHgk/9QVU6sznel3ut/36SQviTzzmZL7n + akMne+2f9P5P89nxhNz9bL331rsfdzzd77jvu8CyXp+Oo+Xg9PGW8OeVeK6/wp/3DwwMPOIgcFoDwHe+ + /e3HIgD8TRxFvwwse14rZLcPht+6gpq/zTv8Gb1HAGGE2xHAdoFuEW5zDgMcCghr+uJMFs9MMgeIPAUi + kBtqvT7IxHRXsZ9WEH9aUDjRuX+azx5K/9cT4LUr/ckBwHqCv97n64HeegBwvP7iZ8t4rr8Nw/BDPT09 + s/AIt9MdAH4Phf8LOMh97vtxuxYA5gH6LSBghLh1JSBNQVZxu8IbwV9H+M3fRgMANTv4nO7wO4Bg3vZU + JaV+ueaEO2GpL666C87njpKTvt/WN+dLrcc451rnML5e+8p3vNXf/VuO8Y7ThbVv8rivo1U/VA3FXbld + ofXd572OJtVqNhiMl2fte+1ag0B9+xidqG9qFj6QyWTejO99o6urK/rkJz/pveQlL3lEnCOnNwD82789 + EzWAL+KvRff9WG11fvjg64NVUKAHSMPie2BEAY1+FXo6RofMl9kQx/QAPTQN6HwBHSzDyoJEn0eOReuJ + MAMo5sQWhFJj2vTS40tYSME/YjqArhfg9RispF8y0awxzhOT3BSe9oWPSdixocB3HE3TTOgkVrBq+Yjv + jc4dW9xM0s8ALBAJYMEaIBHMNQJCo5Pwv0Yz8yyoOGPAgpis6SfYIT0RELQih+kfPycde+lrYsfKN4Bq + BsDznO+Zm5L+0jf8Fi1NAduMjZqV9hk72p0LMOTTQQ3gi/j7pagFlOn9T3ziE3yal770pQ8rEJzWAPBv + //qvl+Bq/5X292nQM9kMFAoFFNyAHyYJKr2SWCYNOQP9MGNX6YiEAj/3kgiFgD7D77E/UVdyFWizUuiU + oWlmBVNAh4Q3YIdhM2pAHMUCNuxz8BWU1AEZN/FnLFdgYfcd4cJJS4LM80hAiI7zCRgCM5l9vj/6ToTX + k/trsgDz+eh4uk/wWCuK9Rg6X0Dn8IJ0ilhEEGenKCUqxInRntTf4fgsxFciwk3jlmoaPt8bjakBR7Aa + i6zK4jiN9KkZQTQahK9aE2lU5nox2JH3PTtexvEaq9aXqBDzCq4wn2pSYAGAgdMTAPIVAOWe4hbtyrdm + mWqLPAYO/CQJj3/UbK5rJtDvCACHarXa62699dYrnvrUp/JNPxIgcFoDwLcIAOKYAcAd8GYU4cNoQK2+ + gg+rCUEYQhjk8GcOeIKT0OGsDjI+hCxEiU4EnydW6IcseGFIAiQTsdFoQBNfNCFJ7CWaEEATv9psoGBF + NNFjnqT0UcbP4CTx+Wg8iUywhH/lSUsCGEcklMCCQ0JNlwoDEV6e+BH2Hb+XRTDLZEPWTugy+DW8t7pM + OAUHmbl0vVCDB3I+D08QYof4uzRJ8csZGo9Mxk4QT1f9qFnHayeQw8/oO5FjQZEmFBM4Us+8RLSERPSp + OP1DBA7Hj7URdoQC/03jmKh2Q/dL36P+83jitQL6Do2XSBQOJX43ls9pPIIwYPDjfhKoEjgazYTBTq5H + 98hCGgg48thAwM+b/4vFz4ICyZ9L141zNmZtwVctgvucGK0lYQdx4sv9JrGARGx+6vXbfQtmbuL1kqWl + pe/ccccdbz1w4MBtl156ab0DAD9j+///9V8vTgQA0rgNPo1arQozMzOwZ99u/L0GXaUiCpzHK2oThYoa + CXCYCUUTYJQnITEros+CwBMokAnQRGloNmMbDRCBaKLw16CBgkOTOpPNiupO5wsETDQUyKsxr7ogQkL9 + YZTx1BSgieczBLH24Xkhnp+OD1ig6RwUWoxJKHilj2VVj3jq4QQTDSSO6dyhCL8v98VakGfWT+wnCUco + JgyFOuk96ptEMXzIZUMWknoz4qWOAIPuKaZpriaSWf2asZocSaSCgsKVyco1E9EkAkY9ERq67xA1r5jO + E4s5Rrcnz0dHh7UkEVgakZDuJ5T+0RiYZ5AQEKiQgpo+cgoCPV/ABgGR7z2Ru6f7o/sH/sxX0Ek0MhTI + 2AVieoVsSoCCitwHA0Ak16KxI0ClISiWumBwcGhdADCt2Wyu3HjjjVcfPHjwkwgKP0LBrzzcMnJaA8A3 + r7nmufjjK54qyqbVqlVYXpqH2++5H/btm4RiIc8mAa3SpJYnqiL7vqqS6i80aE6TgIQySkRgUvNAnXs+ + K+h4rpgnua+qauCJ8EWqElrfHV4gVPUysip3wsLEQkpgQCtNTJMN2GQIfGEPiLbtg5n3JAhBYEDD49WQ + XrQ6hRnf2tdsgpAAsxkggGcsmZg0FhZOUZBDBBsPzxvzCio+DQJH0apimfjYr0YkKm7AoOLzqkwHk3Zk + /Cr0ILKoQQRBhseggePteanvgtX1QCItMfc94vunFZk1IV80hUgBjhp9lgnFNIqassoHartzP/EZgfoW + ItYagAHN9aPEOBb0HGkcspmAx0VML3k+oJoIgY0PCoasIUQ67iEDIX1BVnrRfqivpL2Nj43BhRf+txPO + V7zX+Kabbjo6NTX1ffzzb/F1PYJA9eGUkdMaAK7+xjcuwh9f8XmJTBvZleXyClzzL9+C73z731klLyAI + 0OrYQNPAs3YiyEQOZAI12S5XVY8mIACvJLLyxOoDVu8yq/A6yIlMSlqJQvIdeOJwVDoPf8Yruw0tgaxg + SSz2eqC2PQu/cViCOq887g+tOvwWr0AxRxpIMNiOjcVOJ5CKWJ2Va4lTSo41DjqWU+soS2x0gu1ytrcF + JOiaEX0zUrWWsUCcpL46QXwFQzF/fOs4pUMzfpYBNIobPNYs+CJV/Heovr9GJA5LX+1+0y0BAPmdzBEB + a5/vvamkK+pGRohdAuoIOqwhJfIMGSQDsd8T0uDoXvDvTBjo+Msde2rmsQZGpkjiWdOElRsyfQKfNReP + zbAmP2ePPxdX5wXnPx7e8pa3nHC+EtghADQQABbwz2+AgMBtCALNh0tGTn8ASJKveAoAJvxD6nAFtYDP + fvYf4KqrrgIfET+Xy/Hk5lWeVm6IxWEXhNbBEyexQ9bx2H42TkI2SY0aGagDST1BAhYJGAKPrA30JS+1 + aXnFUl8Av6XhQlBzgQQwUQebag7sxGL/QSIaguOFjj0TRnQ4CqSNeL76BDzWHEQr8a1dzCYH3VWiIUZ1 + MnqJSKQq0QJ0arow6MgAgARY0rh3AsYeVoehiYYkvlX7m7HepzG1QIGJgFM1G7pHz4YWBEAZVzwBI+mo + aGgkyOyPUNIWC6xeNzaAog5FFm56TJFoFWwemL7zGMV8XYn2qO9f7RtxKnoCxKDOQFCLR8eHAQ/f//Xf + +DX42Ef++oTzlQDghhtuSA4dOkRLxxF8fR5f/wsB4ODDJSOnNQB88+qrLyYnIE4WL42NCwBU0fb/9Kf/ + Ab5+9VXQPdAPpZ4uUedIKBNRbcUJrGE9EK3AN7RRX2x0Y7WrpKjaLA8/UaeXeV+cRrGs1rGSiQJfz2lC + jDLRE+MX8D0zo3jCsaCGgQ0FJvZC5ko+mwGCAiCrsi99ZmGnFSyQldlH1T4fZqGQz0MO7XJatdi5peE+ + 32FH+hr6Eq9/YgFGmmgQBiD5fj1DpY5tiNN44G2UQ20rCWEmqZ2mYMEAYex+i2OJGXEeL0ui9lJ/ShKn + 4cnEJRZrH+zztGFAh4VpohF6LjuuibnT9H5NR3zPCSWbiyVpf2msz3v0efC6V772hPOVAOBHP/oRHD16 + lP5s4OtufH0QX1chCKw+HDJyugMARwFi9fyaFqIAlMtl+NwXvgjf+OY1MLxpA/QhCLA9moiX2o2Vm4lq + V1QnViwTUFYg8duJ/WpdVKr6mlAUe+81ns+gFPiqLcR6SUMqckg5xoluSCm+5wi8Tmf9R7zsZmGyKGQ1 + Ek9BjfqVRe0mn8lBIZfnn2TDZnzj+NQ+qwfdhjddUo9Z5Zzm0JnWvuetfe9M2AxEY3bWzrPgxS940QmP + azab8MMf/pAd1Pgdmg3ECfhXEBC4GUHglFOFT2sAQBPgkkQ0ALlZnbwkqKvlFfjCF78E37jmX2Bo4zgM + DPZDncN44iAS21fVal9iv16sbDCzIhk2iK7WPjirnwqoLmAiQIZFxvY3pH3yhU1oo9w2Jp3oiuvryukw + yJwHuIaN5sSgBRdU20hSIgzdYxYFvpgtQClfRADIsg2bCSQqYEwFWd38DgD8DI3GbOfOnfCiF/zhCY8j + DeDaa6+FI0eOgG5AIoEn9Z82DP09AsDyKe/bz3twHs72jauuugQn2FfaudghTuxqZRU+/8Uvw5VXXw0D + 46PQjxpAs9ng1dm30m0IOgCWaqfDZs9miX++JX0Ydp4c2rpdWPgkfquA+mLf+8YB4LmMwPQNo6K2CLwh + 3Xjud73WXjpMPfG2y6YmUvuL+QJ05Yr4e17i/7z6B1b4fWUvdgDgp28PBQBuvPFGmJqaMuNMg0NRgK/j + 6+0IALtPed9+3oPzcLarv/516wNw38+irVurVuBzX0IA+PrXoW/jMPT09ULSVGKKGRmjblsj1hk1awLI + G5YCamJ7jtClzTFGvdSutaZF27HuNlV7pPFLuCqA0w9wbHPP81qesN07gKiVwVU+l0UAyKEGQACQRQAI + BAACNRFMaK4DAD9bYxPgLDQBXnhiE4BM1ZtuugkOHDjgjjM5BG/F15vw9f1TTQo6rQHgmm984yIc1C8j + sobuxKU4b7VSgc/+wxfh6muugb7BEegmAIiVrOKnKr5QTiFdrs0PzxHCdOdwGiHwUo+9XZET47gCa8ez + BzkWs4Kpsn7SIjCyDnjp74H6FbQlqu97vrsT8QQA4AmzkOLZxOgjDaCIAFBwAMBfFwBSDSK9dgcATqbR + mG3fvh3++EV/dMLjCABuueUW2L9/v/s2DRB5BS/D1/8+1X6A0x0AnoXC/yUc2Ly9YXwY2UwIlUoZPvv5 + L8DV3/wmDPSMQU9vHzP3mM3GNrkIFiv2gWcnrBVIMM5ASLUFz6W7ahhJw1eGIcd8ct+x3WPrKbDmRot9 + 3/KUxGvtWxtBowXWltCD9b1EoxXGmmSCEnU79NnjT+NQypWghCCQz+XZJ+ATCJht0M6Ot/W2zHYA4OQa + A8A2BIAX/9EJj6OxuO2222DPnj3tH1EE4H34+gACQASnsJ3uAPAcBADSADItGgBO9JXlFfjcF/8BvvmD + f4G+bWgC9PRBVG8yqYNXPObNxyKUREON3FBRqhV4nrNrUHkA4BvHoZ+yyGLlsQcirUFiEoVInxJ7rsR6 + 633qg3r0/RiEF5CIv8Cw1GJfwmdeJM6IxNMtSIHZIajOyUQZjbSfIEN01wyOA5oAaPsXsgU2B0gjYEab + st0Mq9Fr6V+bSZMIyMlkSsEMNGwISlgy9+g7nyWu41PDmYmGQW1znaHmkyTF4NYkKmZnXgyWyWU0OXCB + S/71XLQFV4MCjaikH6dxfWjrXwpmBPJ+YugfhlwVM2GITIAXvvAFP3HO3nHHHXD//fe3v00hQSIRkB+g + fipl5HQHgItR+L+CL3ufrAHgJF+YXUQT4AvwrTv/DXqeMMAaQFRtQOTFYPeICSfYhuNiu9vPU4JP6tRj + MwBiFYjUdGDxo3NaH2Jq7/uQ7kwzgiKcnsQ666QbOrEgnfgGJMAzGOOGDkWkxDwgDSYRmkIkB5P1gUYA + YgS+Mh5kUPBzCAb5kByBBAyy2QcCx7kZQ7rrkTUbJhnI/SWpIKXWCcIQXUv2z/DvJhrBd25Cm0ZOaahj + 3Y9gxgEALOvfRFEs50GBx24AdFDBV+KSPYc0jsmDb0FLmcwWwAgdPSX1MHnIhF70/j1DRjJ0LusvUjMs + EapzrKCfRLK5KFvIwLnbz4M/fMYL18zR9u3Md911F9x7773th9EJ/z98vfFUU4NPbwD4+tcvieL4K7xB + xNywRxM+gMXZJfjUpz8L37n5u9C7awj6+k0UIBaKrsF54wgMdLWx9rhOTCWhecrUM+QVZscx/z9wZooM + OWv+fpICjTUBwGoWBkR8FTjQawmLTkOUeg7fCAP9Fau5wjF80O8kLPwScgTVbDQagILOwp/JQZY2K2WI + HJThiIAf+HbVlx7GCjhqw0Ak9B1diQ3rzZJtPMMcNGaQxQ9LKnIdqgAmYqIrviFIxR6komcIRGlylMS+ + BxZQXRhMVZH0M2kCLA59R+5RoFnNJrABXiKKsYj7JrmL5gUwGo6eNdaFQOihCAA9Obhw85PgT3/9T9bM + 0ZMEAGpEC/4zBIDaqZSR0xoArr7qKiYCRW35+ggAlhYW4VOf+Tx853vfhYHRUeglACCeeDOmBVNWKRag + NIEF8wBiHTKSzBCF3BeN04+FPMOrnq52slIFSvqRicMLlNkFSH8oud4LPcs0tEsXeEo49MRVIItbKmCB + r5qr+U4agbAQpvLomZUypD0IkgOBPsuhsOdzOTYD6Gcun4NSNo8mQU4TnCQW4IzQ0cl41xttXbK6uIIi + fhZ5TX4vYNQUcJJdBEboYzaJjA+Dxiz2YzvGvqEe42fNoKlqvtKHqQ+xjC9nSQ30vmMFB7XOjKfMaC2x + Fytvk74baZ9lxY+8RBWJRLcF+5Z4BX6i1GhHUzAAZsbec0hjxJI0+ydA6MXZUh4u3HU+XPKbF6+Zow8B + AP4XiAbQAYCTbd+48sqL8WH8Y5rtR1oeV7mlpUX45Oc/B9/9zvdgcGQUuskEiJpK0ZWhESFWYVIJFJVX + Vy7jHGTVMnASVujgqhlgiD2WkGQcc+5y6JvJoH4DawbIdWPPIQupAPLkjr2WkCKr7ep0FDUW5HyhUYE9 + 9i3Q93hLazaEbC7DTsASkYKyRWEG4ssPpS+UMkQ0GWMCxKzBsErP5xL1l7fO4h9Nr2m1G6NNkYAzpz4R + xEsdozLOLKCJrxttUudnzOJojCdfGZN6LQUNPzGruJdqYaDjEBtNTSnWcWKdpIbHH6lg+06f6MpNX4Ar + RHA3JC4BrNh+n59lrCYhCbzX1P6JDydqxJDJZeEx558Lv/uM310zR9sBgIT/7rvvbneO0o3+HXRMgIfW + vn7VVc9VJqDvsgHz+EBWVlbg45/6NHz3u9+FwQ0IAD09AgCM+sYpBfY76YC1OoD0AKteG3vZhv/aQoFm + aWol86zjYAucKxqvfuIcYeL9TqjPRhr89PzGZAE3s5ZmHwnUBAiDLAo9vgqoCaAGkM8UWAPIBhndUOPY + 3ADrOsLM++4YWU9/u2MPoEXI7Tm1r24kwXPs7MQ5Z+p4TZ19opYnaz5LDNoqVdp6NUHBVH0O7GDVk8le + hVicqmYjU2JMqITNJ8lFpKm94kR9NLHOAY9NAd4ZiGN73qMfBRc9+6J156mbJYgAgLQABwDoF1KpPoGv + N53qHAGnNQBcdeWVF+FAfhlBILQ3jINM+/8JAP7uk5+Cb3/n2zC4aUwAoKkpuFyhcmPqLQOX5rGT2WP2 + 2rdOdssklC85RCPnGDe8Zn4Y29iGGPXg2DjV09x7Fgzc/hngaRdUCxzyFm02ygQo9Nksr/y0LbqYExOA + HIKc/ELv80QZfX/a9jOHAdvA56SOPdHxxztfO8h5rSDnfpYYE45cLxBxFICYgC983h+svZzz7Oknrf73 + 3HNP+7iQzfJJEA3glG4KOr0B4Gtfew4O45dwMLNGBSf7u1gsoAmwAn/7dx+Hf/+PfxcA6O3WMKBO9jQj + pwpNuoTaVdUdPSOk1k5O3xetvnWFtwJuL+Gc00SzJOGPePPN4h7p9RO/BTTaBd1oH67GINddCzShn4EC + hQGzsjGoWCjwz2wmK3kFwewKTL/YvhK3t5/4+amK/7ef/pGmFawDKvbeEnGTEohu374NXvQH60cBXGC1 + YcCk5dz016dAnIBLD1f3T7v29SuueA5pAHGSZFyU7e4qwfzCAvzPv/lb+P4PfgCDw+PQ29/Nu7FSD3Ma + 7pO4maQM4z8TI6Fg/QTGde8ZqNDsYZ714qeraIofaVgtJRTpd+lX+pnBv0Oxt72mBwG+OJyX6JVsUtr1 + AGAdsHI0ALuBOPA5ElBAAGB6MAJAMZ9HrSAvGXB0J6M9AbSp6etMoxMDQJIGClrO1zrr275iP3JJWck6 + ANACtMfpbzthSVwHiZoaHpgMQj9NMwAgPIyY8yvu2L4DXvD7z19zbLsGQABwn3UCtnSANIA/e+mlp3ZD + 0OkNAFdeaX0A5mnSZO7D1X5ubg4++j//Bn7wg/9EABiD3t5eTmklMXvP7vRPHeuScEIWbt96ldlOpPdi + TaZh/AfqjfbVeZj4oNuBxVNOxB3fmg/yvcQR2FiFPy7g+QsSfgtquBpX8OwNX5NkeJxY1ItUuzA0Yt2g + xOHBON3Km/hpONI4u0xq6wyu9rkcaQEZcQYWxBlIkzfw03CgE0BLiYeObW0E2WpSxi+aKOkR0oQqrjpt + vwfQigNG+XHs+VjtdvOA/DYkYMejSwSCVtBIQczcjAs+5oHHLf3wnCNaQKdN40jvX0Kg5BvIIZieffZO + uPg5z7XHHa9SEdn/ZAY4XTeNeAAIAJd2nIAn26664oo1uwFpsg8N9sPC/CJ8+KMfhe/d/B/Q96gh6Onu + hWY91vp+iabMAuMQtg4ls7JKsEh/51RYvubiB9lRaIZWBdAAAGiykTiS/AEmpG62EPsmjk+qfyGBZjf+ + VdRce1X8zhICR5U8z4EKhi8xfmfiWiJR7OveAytFIP8q6IDZokzUYGECUsLPggGArOwQ5O3Bygw0acg9 + kzUoPa0ADKTjZf4zwsoR9kTB0jfswMSOcZD4FgZEhsVjGhg6JI9XzGQtzrHky/cZ72icI5Om3ZdraLQm + NkxFVzvwUs6Bl3hWU7PkHyVvpRwF44h1ND4wnIw07GfAgTMWccq0BPL5Aux81Nlw0XOetWaOukVI2gGg + rRET8I2XXnppZy/AybYrEABA6wKYG6XBHhkZgpXFFfjQhz4C/3bnd6H3CYPQ1V2CqK4JrzS8BDZDTyqg + Zj54SerRk5WQI/78fmxUfzUfJFuVZ6ML9M3IMM4c/dxky+EvU3y7lEBjoAnNftRMsgmESyFkZ0LwVgM0 + BQIbfrLrkwpdkkhqKxNLN0lLOMSmifQ4jMhfEx89pSknYackIcQFoNU/R0lCggxHC3yj1WhiT89satIB + SBPoaOjRChWAodlqWF366Fss0dx+uu9AKc/me+KZV5erJwQqAgDOQBQgDISxCGsTwbEZQiYJVPjBISTp + ShvpOElZJ8mwRDZ6rGOT1vCQFGSJAgm4GZASG2IVxkJsAYbAm+EnEfCi9KOUgowyLp33qPPg2U9bHwC0 + IC3/fvttt8F9990HbfYHXeC/o/C/6VTLyGkNAFeqBuDeKAPA6DAsLS7Dhz/03+E7130XBs8ahWJXgfP3 + m1GxoSclArkhN7PCmmNN0hBPJ3FiUlkxwQc0GaZOxMBT7dIktZbzCj7EVn1PsjjB+5pQH6tBdVsNor4I + 8gdRMO8vgb+MKzKaAzTpDYgkiekXON5+dVyaKAUYBiLY8BpTdIkPQDsEObNtwM6/Qi7HXIBQIwG+Myae + 5iBgpp8HlhxlVH5LxFEsS1RgRX1OufvmfLHhMNlKy84iCyYVqWFQEs8ggijA9TXEnxn8iWDp17Hf9Sxk + SDMiTSBO4dVWADIcAZtDUWx0P0mjKRCnwGbCis7sMXfGTy/UcY8h1YQSu2BomrQoYUC98JwL4QW/tr4P + wAWA2xQAHJ8OdYCiAH+NAPDnp1pGTncAuBiICARtADA8BPOLi/DBD30Yvv/9H8DI+DgUSl1oAjR5qGXf + PLDgkspp0N4KW5DYuSATJVXh/FCFX9N7eZLp0u7a44kYe+pw0pmuCUKYAUfzFM8f4erfHGpAbWMVaudV + oTHagPzuPJRu74LwGArlCmoBVRTMSLjIiSUP6WN1wMjyAhwevayESoX1hO5Km4CIGZgr5DhUSluFc7k8 + awFmh6DQJJM27UMEO/IidRaqAGqf2GepFX4MAShRQYy9lBLN+QO9dPEzJKtEAYwD4kEDmpkmNLI1qBQr + sNK7gmAA0DtfgvxqCbKNLPgNn8k77kYi0HTqxkSKFQxSrgColuGpp0efX2zGSEUb79FoaoHyA2JwuQap + mcXXIWZpPgNP3PlE+NOn/NGaOWpMAOMLuPPOOzkM6DQ6IW0AIibgn3dMgIfQrvza1y5GDeAfXQ85oe3Q + 4ADMzs/BBz/8Ec7BNrxhHDWAHgSAhtB2WWgd+9aokE44jptd5uSnBQ6j/hsAsCE+ryWCYHbJibquDjNi + DqO63+yJoDnWgOqWMtQeXYVoKILcbhTM23GSH0LVfCEEv4yrXd0XSrDvmhS6Khub3XMu18I8NOsVgBTY + CDhJKDmtSkQJJj8AggARgjJaG8Bs9jFchET3B6Sec8+uhNb8SPyWDXpGlfeUwuvrB7Ef2dyGduORSdHu + CwOPqMEEAPV8DRb6F2Bqy0F8L4YtezdCz3w/FKoFyFQzAgD2+Zk9HJ4VVLNHQTYbWWgXwAL3HuUksQFW + 9UukpptLTwKj8ggwJFIRKshmYMe2HfCi560fBjQaAAEB2f/kB3AanZrov3+PrzchADROpYyc/gAA8I/u + jRoAODZ7jH0A/3ndtTC8aRy6enqgQQCQOGq0ESbr/II0dOUw+oxTzVNBdsNuLf43zcZjo38toTJVrTOo + hBAAoN3fmMBV7txVqDyuwiZA7r4cdN3UDfl9OMkXMuCv+jw1JJ24PSm0xP8hBQVQQbL35HrhPZmAFA7M + cqZgvBYKP9VPJJMgS9cIJFfgiaJ15nprvO4JgPOGsu8csHAfUhujUP5AwSQHIAJArYDAWKjA3OAsPLhz + HzTx/e27t8LgsQEorhQhX8lDNsqIzW+AFUy3001J1knhBgwSV+tPjBsIHIMqfR8gdYTqZ+nWaNBCKjGH + Urds2wIveOFaIpBv6k7o79YJmEYX6LcynvDTIBpAJwpwsk01AC4NZhOC4mAPDw/CsZkZ+MAHPwQ/vP56 + GJ7YAKXuLtEALF02FZKWzDpe68Rsmey2QCTYxcG1ZUU7dmYjOOEgdbIxZ78A7PyrbatC+YnLUDl/FZq9 + BAB56P1+D/sBwjlUdZdxUtaNeeK3PM31SmPb39ueuo2QEC3Yl3wARJcuofB3FTRdmIkGtFXrXUvxXZ/2 + 2xL+cz8zKj60nHZNv3lFRQ2hmW1CpVSD1dIqzAzNwIHtB9hPs2nvBAzNDED3UjcUV7HPzYzkSGgjCngn + M+WTFue/8135d72kJ24/zTm4rgHeHyVe2bp9O7zweWt9AC4AsBPw9tvhfnICplekE67g67P4evOlL7u0 + QwU+2XblP//zRTh6BACBCwCjo8Ocevn9H/gAXHvdDZwWvNhVZCKQXdltQc21QuOuqDbMZcNtDhOwFTdU + JfdaVjrPOcIQf6AQQx3t/+r2mgDAE1dRA4gh+2AOuv+jG0r3dkE4nYNgKYCglmoVcCKhd38/HgBoGnCy + +SlLcKmQ52xBOcoYlMnp5473f522frzdfa/1t8SxmaHtc0cJswDQyNVhpasCSz0rcGjjITi4dRJCFPZN + ezfB4OwA9M73QPdyF+QaWVSl/DXEoIejrQsIdlcgAkAux0Sg33/uJWsOWw8A2AnYehiRfxQAXtYBgJNt + CABEBf4y/ppxV7kNYyMwOzcL737P+xEAroeR0U1QKBW4bhyYai+uym92fDlqn4kSpuIbKNGG97zJtQCE + qAOyrx3W5e476iQRAzL4KkRQH61D5awqVB6PJsDjyxD1RJDdh3b59V0MANlDWQjmQ3YE2nClyTNo+5SG + wOy9tOi7re+Zun5E/slnZG9AsZhnPwD5BgJPKuKamoHpaVIRcDX9462YjovNcZodp3nmDAmH/apo+y91 + L8PC4AIc2HEADm45CNlyHjbv3gxDs4PQP9cHPYs9kK8hYEVKhFoHAgxhx7MPGtRSadVG1tNwzPvJujqC + YQEmWigE2Kl61o6z4OJnpZuBXPIP77dQZyA5AckMSDVDblQfgKjAHQB4KO0KBABwAIAeBlV0HR8bFgB4 + 7wfh2puvZROAEmNGjciGcex+fs1EI9EB3+4/99TxxduHdVtopFWBeFBjiQ0Qk17SgEHq4HLVUi1L7Rm6 + LR4bFREAxmtQOwdNgCeUofzYMsTdCAD7EQBuKUHxnhLkDuYgPBaCvxrq7kMlLxnqncmgY8yOJBU2ZjkG + rbY3mxF8ec0XmM3xmJSKRd4cRFmUQk0b7vlOmW7jDDTZcrR+oZeY3XHmEp6NSPL7fgoVnqH/eaYcmsCH + bO/lAuMc/osIAEp1WOhdgNnhY7DvrANwZMsh8OoBbNozAZsOjsPgzCBqAX1QqOYFAIxD0VxCBYurGHmp + 03INJVkdhibmbz9r81O0Nrb80zRvDgCcc/bZLTwAFwC4hqMCANn/RAdu23hFTkDaDfjnL3vZyzo+gJNt + X/unf7oIR9LWBqRGE5jCgDPTM/C+D34Qrnvwehh44ggUwhJEVa3mq7FxFhVTajrWFF1Bksa0dcLblU6T + g2iyL57CAaj3OTYxcN9mmPFMrQGuSR+IgoA9jdAEqA3XobGtDrXHlKHyqCpECADhkQAKdxWhcG8J8gdQ + KI/hdyoCAJyURDKYyNzU8t58DepFpNcxDs1A+8NKjykAAnx/5LTK+lnoCskH0MUaAFVP5lyC5AtAO8VX + ujQ55hJNlUbMQ3qxx9+XsGDkC0DyZxoBofeZSm3yJSRaTYkYfp7uxlRWjqd0a47/Z9D+L1ZhbmAOZkaO + ov0/BUcnjkAURjC+fwNs270NRg4OQ99cLxQqBQijkIk8no0yqGbmpAuT8TDBPJP0BUAzh4GlVisuCP07 + sb4LFyTEeahMRWE0sR8iV8jCOeedDc942jPWzFESegIAaqQJ0Op/5x13avTItg4A/DTtn7/61Ys9AQDP + aACBAsDRw9Pw3vf9Fdy472boP39ETICmrgpc517jyCJZXLzDCLuNpCtRiMNMkQkzybB6gWGHySlijbl7 + ysBjQAH9fiIMOw6xZXDy5GOOAtQ3NaB+do2jAUkO+1YHVP3zDAJZ0gDmcfJUQ+EVUHBI2YrcA00gYn0T + SRoGtBXDPOmfLOI+37dkAQ64XDnRgikkSLsEc0GOQYGLpQZi0khWH6Hq+rqDiQg6UtocdZ84lGM82RZr + 03xFCdvtni/3z4E342nn5BtpbcBYV2nqcxRSBKAKswPzMDsyA0cmpuHY6CxEmQYMHRmBiQc3wfChYeiZ + 74UiAQCeK2zK+SLlPfCoG9DWPQOSxUzDmIkmYzWCDenvSdxaYMZTDcXUdDRj7Su7kWtN0vigObVz11nw + nOc+c80cbQcAWv3vZhPACRdLUtCP4+tNCACdjEAn2/7pq1+9xBcAABcARkeG4ciRw/D+930AbvzxLTA0 + MY62bgmaDU0/JbaCkHp8k2lGVWqatDTXzY49vZavZBxipVkyTswGgGxeycRgt/D6GvtW3gAvSFRBl0wF + FP641ITmaBOqO2tQPa8Kzb6GrNR5FLpFXJlvQhMAzYFwNsNcAKagRrKix6H0kfcUxKBbivEeMmJmJMbH + ESsV2NNcg9plWXh8Lh0WUtVknLx5pgVn2HyitOHkRwlUl2HV3FfhVgGgVY/O2fSbTJwR/gORlgIGDo7n + E1EWxzbA90PasxALCFKYTzINqerdFB8KrfKNbJ19AMv9q7DSvwwLI3Ow0L/IvgFy/g3h6j94ZABKS92Q + r+UhQFAOItEk4nZ/iJIhfNe8Uy0kNVc0buo52hoouMZeSi5SALC1n40VEXm2TPuuLbvgJU/74zVztB0A + 2AeAL8/z3cNIfyMAeOPLXt7RAE66EQCQBuCblDogdf9GEAAOTx9iALj5lh/DyNgm5mtH9Ui48onY4lxs + w1lFzQQ3eeeoXLRMBI/Dd9RsKB5EjRXjI2nJCcCmQqhDz0uF5pyjrb/duB72onhsqEH58WVYfUKZ2Yj+ + cghJD07OFR+61BGYOZQDf0VNE5rETc+aIPQ/asAorNJ/BolY6cAERiGYwLXa5TiBKS9hKMJAzD9KCFLI + 5KELwZHyBVLS0Ew25PqBsnqrMyxJNQ5WpjVlmImRmzGJGBBozDLqSJXcgbTKk4DzhFRwEhOCziXmQoKa + RTMTsQkwMzwDRzfOwNzYHKx2r2KfEQBme2Fochg1gSHoWSATIAtZIgNFviTptAKVtPxr9meRhsLPyrA4 + 1QcQW/ZAnGp+fmzZgjaPo8kunEQ8Hcx+COICBPkAdm08G97w5NevmaMGAIwzkHwAd6IWsE4jAPizl738 + 5eVTKSOnOwBcrABgXVEMAKPDcPToNLznve+Hm2+9FUY3b2K+NmUPTlyaq+eEA90IgEF4zdJrmHVgOPFJ + YiecLTLiBBYSdfZZJxp9jyYfCWAJV8feBqr9dVj5pRWoPKYM4QyuunMZiPoj8NEMKN5ZhMIDqAUczkGw + GIr631A+gFKYzaaVFpaLVjCy24dFKZEdOhqgEBVcypIHpAFQ5SAKB3Li0CJrBFk1A0xmY5/VfV+2vxqf + gEkklgigRIkIsnEachVlMOm7lU3npQ43Vv91s44oU6gBoKq/iKv/0fGjsHfbPlT/jwltOtuEwmoBNqIJ + sHFyAwzMDEIJ/85EgTgCQfogarxGFdhWT6xfRvL3y3hF1kGoXdEIEGs6mm/QN7kYKfVXKDtIEy3jzjUl + YhD/CJ03F8LWzZvhJc9amxWYU7KpBkA/TRQAYI1wEhHoDQgAi6dSRk53ALhIAcA6AQlxx0ZHYAYB4N3v + +ysEgFtgZPNG9noTWtvcb3ww2CSbLWEhN4TWwhhJwcJk/HH3yqe8Dof8o19jpxxpAAWc0H1o626uwMpv + rEJzUw3C/VnwlwJojjT5vIX7ipB/IA/Zw1kIF9EMqDo5AUCv6/AC1mQLMupwe0gQ7NclRwDtEKSQINGC + UUOieDYXEAlyTA1O7/VE00iTcZpbN+8pZ1oCGK0kISdAKoQajrDEUM9XYLlvGQFgFvYhACyi+p9DVZ98 + Axlc6UcOjcL41AYYPjoExZUuCGs+A4B5RpaGnSQ2ZGtSvWuQWDQkz6kRCRK1sZmL28ODdhNW6iMw3IZm + LBokaU5bt26G5z1/LQ/ABQD6nXgA995z73qS+Q/4ev3LX/7yY6dSRk53AHg2PpAv4ytrbXUc5LGxEZg+ + fBgB4P1w649/DMMTG/khxbFlgcu/DgXYjZW3DGALscaNt4MNI3JLlYJWwXTAhAGghK+BBlS2VVgDoC3B + mQMZTgtZH0cACBPI7c5DYXcRTQC0y+czEFQCcba1U4G9E/S5/fd1yEEcDUAA4IShVEI8m+fUYTZVmBek + t7wGBNbn0bV/vn5msKTla6RpNHCVJfrv8uASzIwcg6mJKaiUKuztj2gFRmEbmO2D0cMjHAosLaOJVMOx + aZpIgwPCdtde+hxc4LefOSFMlx/gftc4Nl36gKd84mYi+wEKuQLs2LEDnvuc56wZY0MEMuFA2g1IiUHX + MBc8+Cr++zoEgMMnNflPsp3uAPAsHNgvkWvNCIU4AYfg8KHD8J73vw9uvf1OGNm0kTPhRFFDJ3IAZt+M + 6Mytk8VdRfm9NnqvnWh2lXVWNmNWGK3CmhHiqEu6UXVEAKidVYHVJ62wwzF3IMfH1ydqwgd4EAXxPjQB + JtEmn0XzoIqvhjFb1ANxIvpye/owF4icRqSgLFcQJkegsAE5VyC+F+q+gPUApJUd71wIUuYfpLfddqwH + awAgiBEAmlBGgV8YWILZ0RmYHp9GjSCCfDUH9WwD6mENBuZ6YPTgGAwfGYLuRQSAejbNm9DWxzXdO8XN + 1Acgb0Eetadzdp4Nz376Wh6A6wOgn6QB3HP33e1OQJ7OQADwipcfOpX9PBMA4IukNbcAwOgQHJyagve+ + /wPw49vvgJGNGznUFUeSeYedUGYlNXLlbIAxpcJa+PfrzHnPUn9N+EhmvJT8UgpxoHYwfTWH06UbV45B + Cv9VoUwAgF8hCrCHE7m+pQa17WgSHKRIQBcU9+QhM4MmQCWjAGBI7GYDjNcGRGuFvR0M3Mb7AsgEoFRh + lB8gm5PiIbkslw8LbC2E1ma1D2ejj7uKrreXyKj77acz4b8GcQBQA1hEADiGADAzPgMNHK/CcgFq+Tos + 9M9B70I3bH5wAkbRFOha7IZcFYEqchKEOB1sMfWO26ufvgkAYN9RqyQT6txdj4JnnoAHIAVrMsoDWEME + opGhTW2vRwA4cso6eUrv+L9gUx/Al9lH7wAAmQBTCADvee8H4LYHboPBHWNQCAqsZvueZKSJTQJQUMeR + oQcbhmDk2XgxD2QaDdIVhya0qMjECbB+BHZI+3boPZN5hmgGebxuTwT1wSbUEACq56+yTNM2YL8WSGjw + vCp4VeBIQPHuEoQIAOEKagBNjUbYLEYKBO32v5o1ZiuuzeWnfghPAx9mrGhyZlkDwNWfQoJkBqgvgCsH + +WmINEXJlN4M5m0we+rbBU+aIRPJ73oe8bZBI9uEeqbBEQAK+x3dMA2zY7M4vDF0L/RAI2jC3MgsqvwB + TCAAbJrcxJGAfBk1AEoW4KQH85Wk1b5pidPBW+cNOP1o1Z7iNP1Hixlgoc0DSwri7cD4IhLVOWfvgoue + cWINIAWAO9uBkFwlCgCvmD6VMnK6AwBFAf7RLtIaahkbG4VDkwfhXe95H9w2dxsMPG4E8kGeBZoeSEQe + 3IbUCEjLvZpVVZmAsXDibfnv2BTMdFSGRPIKBh7oKm8DyVoSTHmBdCjxeXIJRF242vVH0MTVvvroKofR + M6gBBDi5k2IM9U11iLtwVdmbh9ydRcgeIy6Az59TIgxP6a+mYKiNaZvrmrRkEvtKNQVwqa9gtYaQ+ABZ + qSKcp/oBeUoUkmONidKJsxmgFXtMghNvTVJOQwvW9FsgEYM0j1j7bkAntx5xBjIIirkG7wCcHZ6DA9sm + YWF4Ee3/HLP+aOwX+5dQS6izI3Dzvgnon+2HQjkvANA0oKh8DZDVWTI4ScwizeRjjkzFWv40g9K6r9kU + Po21uIj1DSaeAkDEAr59x/Z1NwPRfDQ+AAMAd915F6yjWNGmNgKAjgZwss3wABzrVwBgfAQOTR2Cv/zL + d8OdR++GoXPHWM2lB0BU1ybO5UatDs2kmXqEjSptFiffpAtzEnIC2ESWdoL4YvObEl2egkFipI/3AIDU + /8vETPltDkTQ2Irq/q4aeCsemwBB3WcnYWOwDtFQkzcC5XYXIDeXBa/icYow2hrsNyXjEGkziUlQYvud + huWks9pTA0hOv813fHYGZiDn53B8ZJswmwKZHDsBqcKwyY4MnmHaiYYkpcrBqtzGE+9pwUKbNAS05Fos + NfsMjnL0nR2AQgKqFMtwFFf+B3c9CJWuCvQd64Pe+V5m+632rkKlVMb3+mF8/zgM4GelapHzBFIWZZMQ + mSneidTt5PKOic/DFYHUBZRya2kdRKH7aqZoJYAY7k9sNATDpUhS7SfRMGaCqwntrtyyfTM87w/W3w1o + ogDkW6Ew4N13tSYFVTD4Er7e0NEAHkI7HgCMj4+iCXAQLn/nO+Ge+++D0YlNnAGXVdswiwtGArVmjV+8 + RZjmpQqyp9WAY6OoapLMRB17FNKKHU88ee3BJtGINUZPzrPIkkko7TZnAiomvO+/STsBn1iG2uMquPqj + wN2TZxOAQoS18SrUxxsMAIUHUQuYzwLQ6r+KWsCyz0Dg1rZPVO031bO9wDx13dZrc5UlrG5r5N2mRaeP + iBFIVYOJAESJQql+QCaXYeKQ3L9TpFTDYEyh8TSjL4ANl5nU517s2TTlqfe9nYWXcN6/ZkacgFWiASMA + TG2f4v734upfWilxqG+1ZwXKCArkBxg4OIzA0A1F2hCEAOBHWt4rcZ6FAWQTHYj9dNWNRXszSeC4oIwB + eksjljGKlSgm+p2Mqa8mAIUFKbRM9Re3T2yDFz/7RS3zk85rzCyjAXBGIASBdUTzC/h6/Ste+YrZUykj + ZxYA6HZXAoDJqSl457veBXffgwCwaYIz35S4KGaOhb1aq0GlXIF6vcEPkb9u+PrgrJjGD6hbhlXzT+sJ + GAdcokkEecOPkGBA6bq0xRYyqBP00AtNgE01WPmNFaidW4XCzQUo3F0EvxJwfYDKjjL7B4LFDBTuK0Bm + jiIACACUMXg6wzkCoCmsP1tGzEQauOsSg/fSJV41g8RaLyaNmKzCkiuQwoH8ymcgXxBTIKcmgOxnT3S/ + AziFT+V6sVs9VwL71rtvN+GYz8C4MqTzxBBs4os8/cT6O7pxGmY2zHDWn+7FHg710ZeX+5b48945oQR3 + L/VArhpCQGNj042bLhmTxGw0TrRmA9jOJ6lIC1fAdfKqFhXr/oYWE8uArfqRYgSBsJiB88YeBS978kvX + zFHXB0AaAIUAaT9AGh6xs/fzIAAwdypl5MwDAPUBHD54CN757nfBHahujWzZBKVSibe9looF5grUalVY + WV2FarUGUTNK4+tm9TR2o9loo6ql+d2mCQMje2mcvsWcoPOQkyBLIUCcUr0NqKH6v/rrq9AcbkLhR0XI + HShAiAAQ5yKonl2G8pPKbEZk9+RYE6AVjqIBuck8g4DJFShpsEFYhg4fwRBiEgUAA1KW5aj59qV3kiSE + k4USBwBXftodSPkC8/gehwN9hw9gKwjLJUlEzPZna1k753YlU3L9K7swlv0EjaCBwl/jLEBEAjqy6TDM + jB2FrpUuFPY+yNRD3n8xPzgPK73L0E8mwIFx6FnoEScgAkSYhI42FFsA4DSsiVB7jYPSRE5MERNZ8eMU + HEywhXxFYLdYpt8FwxNI+N4JBMJiCOdOnAsv/q21OQFdHgBFWigZCIUC1yFIMBHoFa98ZYcIdLJtPQAI + 2QQYh4MHp+Bd73433HbnXTC6ZSN0lbrYuVUqlJgV2GjUYbmyAqurFWggCLBy7PupBmBNZc9ZWhyPsQUK + sOBhdrx5ujJasSDwcCIAFO6r/OIq1wIo/qALsjNZMQEQAGrbqwwAzdEGeEu0HRgn0GoA+ftReyGT4FAe + wsWA02T7mhMP1iMguc1EB6C9/+ZrHof9iABEaipVDqL6innDB+AJrArzOs6/FiIOgBbz0D0ETqbQtFKv + 2NvkWGuECIj5Gqr3ZVgeWIZp0gBGZqBvoRcGjw4iAGSgkY1gfniOAWBgRnwA5BsorBQgwM9D8gMYefIT + XaE99cUmFsxlJU/LibMPJVKNQf1ABDaMkdZvIosA71dIUpBlAOCUYDFrTRQFeM7TWncDSq3K1AdAWtV9 + 9yoAtJIU6ErsBEQAOHoqZeS0BoBvXnPNSyqVyidaASCEjRs3wNTUJPzlX74Lbr/7ThjZuok3vJAPoKur + xMwtUvtXqquwsrIK5XIVmlGDVzrPCIsLAMbg1hFtfU9FylHDW6jF9BY9f7Q8ol7KBIQAsLkmIUD8DqUA + y1KsH1f0Zi7Gz+pQfUwFao+q8LZhqg3go8AXbkYNhujBh8QsoCpCYgp4LQL+07ADqb9kBnDdACodlitw + /cB8Jg9BGPDGIbOKwRrNtZX881AaCRV5/2kHYLl7BRZGFmFq2xRTgMcPjCEADEEGhbuercPc0Dys9i9D + LwHA5CiHB4vLJdYQ/GaQZhlueVa6brcxAFPvv68WgQn1eur7UWehlpL3TY0BG8xQU0ZNAALOXY/aBc98 + +tNa7q8dAMgMvf+++7k4SNuYkXPki/jzDR0N4Ce0Wq02jj9+jV6Tk5PPu+3HPx50b5IGe+OmDXD48BG4 + 7LLL4Y47iQmIJkBXkQkbXaUidOdL/LDLaAYsryzDUnkVGrVGKkjGsWYE3U/tPkP4aRlYY2sbB5eboot3 + BlIqcHz1x5wKjDSA6uNW+Tul73aLbY8AEOfx/jYgAJyLAPC4MsRo/pLXP8lEkL8jD8XbuyG/vwghAQBq + Bl7d0zwFejlnV2Qq72sBIQ0NggU08p2QsFMkoESZgihXYCbPDkIqJkLA6vLg3XOeCACOV0RUEnEkuPoT + AaiM9v0yHNswB3vO3cN+gc33boaB2X4IIgWA4XmYH5mDnrkeNgEoK1BpEbW5mvgBTpgX0NIOkpb3WkDS + RHFbSwa2JAuxX02SFhCgHAo7d7amBLNfd3ICFotF2LNnD9x6yy0MHM4TIg1AnICveuX8zyojLVPzVJ7s + 59XQXp/AH0/GIftNHP1n4APooxj+oUOH4LYf3w5rAGDjRjhy+DC8/bLL4I6774WxsY246ksxzC4Egh40 + B+ih1BsN9gMsLywzGLDNZ8t7aajLN551yZHvJaa+n+YBzHDtGateijXgcfFPqjZM9jntQiMSUDRMqcBQ + wM9CALigDAFt/f12D4RHMpL4AwW+NlKH2tkVqKMGkOjW2ca2KoSzeOy1fVC4iwqHoFBSpiCqIdhUADCb + msxo+KkmYqnMZnU0Woy7D4JThUlGINKQCADIBKAtw1RYVKoHpSc42YmVOKtry3vqiKzl6lAurnKYb3pi + GvafvZ/Zf+N7NkHPchfnE2iGTYkObJ1Cuz8PE3s2Mx24tNAFuQqaKY1Qd++duA/28za8aiEorWU3r/1O + Iv4Mc24Px2bHtm3w/Oc+b8212wHgwQcfhFtuvrkFALSRE/DPXvmqM1wDqFTKJfyxE19bcXi34S08BUf5 + 19mFJrEXGTz8//CRI8Kqcr5vAODQ5BS87R2XwV3z98PgljEoekJzLZbIwdXFKi8VdaiW62gGlKFcWYZG + MxKvvcbTzKYPab7kAaTEmXFia4aw77+pWoFxIpLwEXg0JSzo5fB3ygKE6n9zYwPKj68yAGQfzCIAoEAf + yUG4kuH7oK3CtS1VPo6Ap5mNOSqQdEdQurULSjd28/GZZaoeJJmC2NtAti8DlWYgASWuBNCa/jzRJCXu + /gfVHILA43yBtC+AnIDFgmwMIkIQrXL0uetDSLxkjTABgI3/6x96uJMdSQWNulnLVqUC0MAKHN52BKY3 + HYGBIwMweHgYiuUCOwsbfgMWxxZh3zn7uWzY5t0TsHHfGPTMo/ZUK0BIZkBk03WkLMWk7SfYrgO0mALr + H3e81qoBJOwj2YYA8AcXXZKOp7mW57UAwL69e+Hmm25mzaGtfQmPfgP+PIogcMp2MfxfAQAo9CP448k4 + tL+K4/lbKIXbcJCzZsOFLXiZ6OBr2G766DTcffe9LTdKALBpw0Y4PHUQ3vb2d8Adzbuh79HDLPyUCZdy + 4JM3NutnWLgbzSav/pVymTWCOFYHlq52psClrf0XSvjNZLkSTSHR4z0bAfDVgQzqA6BqQPEQvsYasPqE + VRTqGqr1aJbciHb9TA6CVbJl8TjKF9CP/Sji+QsIGPh3fUMDook6Zwou3Yx270G0zREAwjIlxEik2pEm + uQBNuWVWWC5vRY4uTVHGgqtJTHmLMZsQsleewpVkClCSkO5sN/sBmBIckGkgjDbKJ+BrqrTYsCWYYuDb + kmCx5sxjFmGc5gCg7bYGBDiZBm0BztVgtWuVHYCHth3iEODIwREYOEx7/ou8utfDOgPEoW2HYalnGUYP + DsNm1BB65/ohT6nBqqG9tqQ/8KzWbtmb5jnaHVqSg0C4HamwxC1RDC/9jpeSBV0AiHD8Ka/C1m1b4QUX + rdUA3NJgFInav38/3HTDjTb07Ego+wBe+apXnRlOwHJ5ZRP+eAp28ZdxRJ+OKv24EXgwgp5oEgYQ0gX/ + Z37iZ5T4897772+5UQKAiQkBgMve/k748eQdMHT2BlRpS1AMc1wLL9+NwpPL8sRvNJqoBdRgpVqBSlSB + JkqLZzz4hmqr9fwgBPs+aKhIQm2RFSqZW+pc0hqDnCargIKNJkADTYDaeTWIe2LI3VmAzP4M7/n3yh7z + /YkNGJcijhBQ+vBmNwoJmgXNiQaDROFucgTi8ZUsbxDyDReAbNfEt/a9aNki4Cbvnq9SkWj83w6aaj30 + XuhR/UC8TibHZa+JIUipwsgHEGoZ8Vi1C99JyJmyflNCja/JP03+P0nIqVmXiAMQ4Hjk62j/l2GlZxVm + Nk3DsbEZGJgegaFDQ9C1hDZ+XXwAxAGY3TgH84OL0H+sFzY+uIEBoIBaQpZ8AJRajMg9sWH4iX0uOQHT + /Qwmp6IIoJduDiPzzgdbHlyyQwnImUKjximYeGYzUMzzMcxmYNOWTfD8563PBDTlwbu7u2HywCRcd911 + dhFLnwCbAG945atfdXr6AFZXl2nPKznwUOhplU9+D4ezhwcyjoU6qoIPNue6/B6bv+NWb8yx2Vm49x6p + smLULgMAFAa8/PJ3w2133AEj4xuhq0A8gAIUipIKO4vqLcex6xGUq1VYri/DSkWcgYluFLL5Aoz3Wxlh + AghqW/M80sJ4nPVH+eiRDn8Qs58g6UugtgFt/y01qJ9bAw/xJ38TAsBUlkk/5NWnSABThosRr/4RCj/R + hutoEtS31cBfCJg0RJmCwtWMsAKbQnmlDQk8MqaMgGYIpj7yVDNcWV/6m3D8X8bR7Iwk3ryvcf98LsNb + qAPmAvjKaQ+ddOGJ8u49C9Kp79OZdrEh4ICYUKyJBJCEkoCDCoHQJqBydwUWR+ZgaWgR+qYHoR/NALL3 + SQNohg2odJXx8yVY6l+C7rkeGDlEPgAci0qeTYCQNwUFnCOQwVo1M751TdySqK/GT2ItZe5riXDPRlO5 + 8rBTBCZmVc9jE4MBzzfFSD0BB7xGNszD1q3b4LmXrF8e3AWAgwcPwrU/utYFAOok5U77HJAP4NWvWjqV + cvdzA4CV1eVevPhv40g/KWF7Hs5FASbVvmhW8lStj1sEPza/2+NkdgXMqArED4Cv6SPTHFaxCTJokc4I + ABxApH0nhwHv4nwAZH9RXkASfvJyU7zb10zAtaiOIFCG1eUymwKNZkPk3XccaJz9V+1MQ7f1HGKM1Sw9 + SyPw2Y8gtQCJA0AMwNpZVQYAWum7/rMHMnvRxiayD1UDprRfoewaJE5Ag8KGI01onFNhx2AwG0L+NlwV + p3Blxu+ICRCICaBxa15/jRtAE5z6muCSyTAhaIFTdRnGnk0sSinLgFd7BJowy9WDwwKVFPeZxRb4Wc5B + aEt9BZLMI45iMCR6EhAxARK7c9Hk3otMAlGNq0ecA7AC5Z4yLKNgz2w8BuXeMq/u/WgCBLzfn/wgaDb1 + EgAscLXgnmPdCBD9UFpGIK/mOArAj4CStBpTjdE94VyDNpNy7Gu6b90oYO7fJHAFXdltIVZfyo/ZnYVi + +pCpJhyMREqDFXPw2E2PhT/81dbagCZZrVmcenp64BABwLXXcno6bQoAHgPAq/5vBoCV5cUNQKu7B7+I + 4/JUHMwdRoCN7W5LRal6b/6ONd9awsKtO/DYg5qRajX4H+29btaJv9/gY2aPzcLevfvbAADVsYlNvB34 + cvIBPHAPjCEgUAyWAaAkFXEpLTZv2yV1FCdKtVaFVRT+VQSCehWvEcfWk+56stdLGNIy0s5efalCTPY/ + MQDxtbEOdQSA6qPq/P3i9yish5N8CfuCAEAhP1Y2UDsg5iDtG6iN1qFxdhVqj61w2rDCrSU0G3JcMyCD + WoCHK6SUuzWqq69lw6GFi2+rHSVgC43KJiaNdSvRx/dCzhdIOQFIY6LQKfEBipmChALDtOS3ON4kVRbR + fllw6DKUq0859ZGmVdfaJnbchP5L9v8K2v+rcAxt//27DqCwR7DrprNg8PAQZDTzby1Xg6WBZZjddAwW + B9AEmO6DkalhzgqUIy2BQoGRn9rpvub0TxSQjMMt8TSnoXleYm4yGIVxusnT7npUzp9T1VhOQyxAkxsR + 51w+hMdvfgK86BdesAYAzOpPjQCA8lSQCSCgCdoJBACPS4MhALx6+VTK5MMOACj0W/HHU/AufglH/Gk4 + F0atCm+SQbr2fIt9n6r6Jt8aC32YsY4TEvZmo86bdgRAhNtFZsMxBICpyYMOACQMAOMbxmEKkfYdl70D + 7t23G8Y2bmTh5w1BhS4uhxUE6dDQt+v1JlQauBpVyrJHoNGwn6XFQb0WwW9h1bkAYN7UYqCQQ1W+D8Fr + QwMaWxAEzq2zz6D0PVzN90sNQH/Vs+onnyArxKHaKGoM59Sg/MurPHbF67ogfy+aDsdQA1gW/oBNcmr6 + ZgConbhjgMtSedPPeaJ6AgS0eSlL0YBsQXYG4tjRz1ALiNpbdZz9LhUZjL9BBdIkLzW77kS7QoDLUh1A + cQBOb5uGybMnIbeag5237uBdfwVU76n2QCVb5e3AxzYf5UzBtPqPEhlovhfyKzk0A/DVyIgqryw/TlAa + K0CpI8/UeOA13RQP0d2AsS8qnOfsAVHysmMB6mYw3eEgdQbwOtkAzj7rHLj49569Rj7MPKZ5TgBAC9MN + 11/vAgA1gvD/DQQAr3n16qmUz1MKAIuL8wW8mZ14P2fh/WzFk/8iCu7v4hAWXVU+cR15DgC0AoNOFF2F + WYP0dVMHrfSNJqfwIkEnzzyt/vSziaoTcffp59ISrgozMy3qG6n2GxEA9u7bB5dd/g7YPXUAxjZskEw3 + CADFQhG60AwguxY00SPb3fjdWgNtURR+0gQq1cpaANDaf2aXXeLMe69FAFIASBgAaDXH+9ko2YAJAEh9 + LvwQtZE9RfAXfXYCslfeOJwy+LMLbWTiBZyFK+WvLkNzqA7Fm7qgdHM3hIczkFnW2oHG3+D2w4JA6zRY + N12Y+V3V1YALiAacHISiACT8pBGQs4uyCPngtZynhTjjTj4vzcVnPPIG4CKtBLyMKv0KCvfRLTNoAhxF + 9b4XNj+wiWP8hTKaHDiA1Xwdj1uGI1uPwNGJaRT8HhjdOw4D0/1QXMmzryBbz4AhYrmUwJQbYTICgFZT + kptOnH9NJCExC4ra+rL4kwkjx5qy5DK3I/AzPmzbsR0uvkhyAraTpXyt19Db28sawPVrAYAapwVHAPiv + kxYcBZ6sXQrR/RbwCk+hOuAQHRgvqLXXwVHxnZCdY9cbtZ5XEqZHepyos14jtb6eHh+LjU+VfGi3Xp3A + IE6JF2Z1K5dXWwGA5Aa1h82o8j+4HwHgbe+A+x58EMZGxyXtFe0ILJagG7UA8hWwLRrHNkbdjJpQrqMp + sLoKZdoj0GyqOqh9N6nAzeSx+QLSlTXRCIJUAvLY2UU0YM4BMEEOQLTnH10DfzbgfQDFfXmuCQBlT/P+ + 6yTMSArxiLIHbaLtwyvQ2FGF3IMFKF7fDZmDWcig5iB+AItCLSu8XeXbp0Gb4IP2P81i4/Eed94cRACQ + EQ4Fcd4zXladh60gcKLm8vBNvzgCkGmy7b9MWYBQvZ8fmYf+o30wvm8DdC2UmORDDsN6vgkrPQgAmw+j + ljDFTr+JByZgdP8IlFaK4iysZ9IU5FYbSlLyE3ektb/uR/ZvzxSKST80/KcWLpBZ3OhoXEx2bN0Glzz7 + uem5nLExANDX18dOwOvRBCAfgNdyZfgkCAD8fE2A5eWFLPb1t/HX30JBvBBv+jzsfI/x0oMTihPhaV3p + GTQ1PCLbLI3Qy8YSmj0RCloVV9io2bARAGoEErTy12po9+IAsdqfQIsjxf1JgnoMAcAdbNIAtmyZgAOT + BxAALoc7d98LI6OjEtZCm7arq4sjAewEBGXSJVI9h6+PfatUKrC8iCBAfeQgulTm5fJYjkqdqEngg5Nx + 1jeeZ80BkMGxKOCEH42huqMM1V9Yhcb2BmTvzEPpB92QOygpv6AsHn0GAHLIZYHzA1AJsdpoA0FjlbcP + Z6bRNr8Rv7cfx3Mh4IzBniHB2OSlMvnTpKduHBzWbHgCZ4ylkKlEU/KhpgnXfIGkBWTIEeh7TqKU48y2 + Nt68fGy8o4ndAryMgr08uMgOwIXhJQaAjXvGobiEAFDNcbWhBmcLWoH5DbOwf9cURw0mHtgAG/ZugNIS + Ps9VcgZm0uSgSctjcnrRzvhxNYZ1PgaX/u3eE7AjOtG57+NYbdm82RKB3HnqNgIAYq9ef+11qRMwPezT + +HrDq1/zmp9PXYBGo/4YFEq8A+/piFiPI2Elpw8JcxkFjT3jcXrTYAbBCLxBXkVLJo1wtdmMeDnw+3Wi + 20aSiotUIAMotMLXUejrKPC04hvgsBtQAE4OAJwc7Xv37IO3X3453LV8NwzuGJHJjC9Of80cd1Vlm2BD + W+Lp96CGfVhdEQBoUEXhRItjJr6NGfNqqx5kIQs5CTCaeqwhABVxJR+LoELe/AtWmRmYux1V19uLrMqH + y4Hk/m+ot578E1S2rBDLBqKRBlQeW4b6eQQAGQQAyRgczmW4eCjxATgVV2DU0tan7/saAlOWnG/UXUgp + uRIZ0IKdvow9FQnJ5ULmTpD/hECANCxTQtyu6uZankP9NWPirMLm2FirANXyCAB9i7AwtAiz43MIBMsw + eHgANqBwUyEQyglA8X2KApSJK9CPWsCOwzCPxw8dGIKN+8ehNN8F+RXaE0D5AVtNNuu0M4lIrBw7ORwT + 5/kbk6kNAFqa82esSBNw5GlTCxHoeAAwNak+gFYeAJ31MwwAr32EAeCCCy54yoUXXvgafHD/T7lcLoAK + OK2Uo7hynnXWDvjN3/wtLrdVQ1V9aWGeVWOz8lPjGHGYke20AKyuk6ATysXNiNV8Ao+I7fmIBaxer7NN + Ty8GF9cZpec8nuCbhv0VAHDuh3azbdu6Bfbctxfe8va3w/3JAzBw9jATWojhRhWCKIMLbXLxPd+Wu04M + dRb/aWIfK9U6OwOpb5wYwhMfgKdFJsWbTscLZdhoKuxTMFV6SZCJ2JPHMRhuMvuPXsE8qtd7UZ2eyoE3 + g2OHq3/Izjyzf16LalIdwW5UlckM2IUAeXYFwqO4Mt9RgNzRLG8K8io47lWpkcdpt/xYi2H4ar+mCUSt + XyD27S5CphBrLhMJWQhAUMw/S2XC8LkSg1IAIC9VhH2JoJhyarFJ+MmhSMOPTPMEGu3I2NhUQowoznUq + BT64ALMjc3Bs4hjUuiqwYfc4jO3egGp9gXP+kVOONAAKDxJZ6OiWaTYVBg4OwdjUCHTNoQawhBpAPavl + 0RxHaOIIsJf2yuZ51CxCiZPhpD264+4PcFOcJZoSnIlAOZxzW7bC8571XDhR6+/vh8nJSQaAJN0LQL+Q + x5miAG9EAHjkTIAnPOEJv4M/rkCVN0fCSsJHK+hv//Zvw/T0NDsr6MFOTEzAU5/6VHj+858PGzZsQKGb + Zh59hjzDGXG+sGDjikn2vJgAxmaPUa2OOfEGJeGo1ppq64OmzPPXVfHbAWA9EFgXABCNt2zZDA8+uA/+ + 3ze/BfYuTMLgxhGm/lL8P99VgGxR0mFbu13r3PH89yTAU6/h6rS6DNVGBTXzGEy2KbL3bPPF/jOTyCSk + tOQhkmcUYi4HNoTaza4qNLY0wJ9G4TqA6vQ0AgDivVfzucCF9CHNOhRTGnHyA1Al4R11/r637EP+bgQy + zg5Ewo/fq5lkHykHwQKA4d+7ewFAhV0Flz3fkaoBupefOH/kpyGbn0qF0cagXCiaU5YYgV6o50usI5UX + +9iUDEts+W1ymiHkitnoaVnxLM6X7hqnAZ9F9Z8cfNSxbbdtg6HJIWb45cs5PmeDdgwqW3CaAGBsHjWA + ERg5MMz1AYrLaNJR7YRYCqhoPiYQl12c+kKUrsACbJN/yOCQr8HQGygnQOzmCQTlB3ix3R3IC53O8wBN + I1oon/P0tWnB2wHA+ADaAIA8zsQDeBMCwCMXBXjiE594Jd7YM0noKUSxsrLCAvmRj/41awB/8kcvZjWb + Bo9WfxL+D3/4w6g1nA8LC4vQqNdwJa/hz7qU3UpSoSfVuVKt4gs/V449Tzvf5KJLhflUAgAzATdthP2I + tH/+pjfD1JEjMDwyyptcisQDIB9AoWC3txrHnZ0YqhNSfoCFlSUoV1bRNMH+N3UwCQCCxKbi4nRUWorK + 19x/JvZOLoMI1XjayNMca0L1cWVo7GhAQACwGwVrEgVqDq9axcnXEE3CC8zKrGnEKRIw3GAiUOWCMq+8 + +ZtROO5HdXwpy+FDqKkPoG1MjXrPphsHrHVhVCKQ7HwSyiuvf5rO3FMzwM9INIAcggSs2VAShhAIpKp/ + omZLOuH4XBHYXIJsJ3NiURYvzhgWUR2A7ios96/A4hhqARtn0ebPw6a7J6DrWIkzAmdQrefS3yGCRbEC + qz1lmJ2YgyU8vu9gPwyiGUCZgzgxCI5hwDUMgzRCY5ilZE6y59FTNmdrhmfSGgK211RrcVKDh0loAcAS + vvRGE7F/ESizvB34mc/4vRMK48DAAPsArrv2Wk4mquehM1JFYPIB/PmrX/vaRy4KgADwLVz5n0or/Pnn + n88TmBxhv/O7T4cGdvDv//Z/wBEUoLm5OQYAcspt2bIF3vve98KuXbtgFjUBWtVJ+CksR6YBOfGqZM9r + rr3jCfhPAoD1QKAdDMg3cezYsZabJNWVmIB796MG8BdvgcnpQzAyOq673HLQ3dXDce3QD6zTq71xtpok + gpXVCqyUlzl/YLMRpfRgxz3sg5M6DFI7l8GEWX0ofEUCAATE8xEAdjUgRADI3JvlDD/BNIrGqjryVCMy + 8cUkB2ICjNahurMK5V9egWQogdzNRSjchNrMdFaKh9K24MRwCFS1MnY9KMlKdyq66m7imxi3+DE8BWde + NQMQx20o6cKodkCO8gXmCgIAnmgZnPfPT9KIiCcrI++T97Vyr1H3dJNQk/Ij5pqc5HNxcAmWR5dgZWAZ + uijhJ67qhcWcbPNtZrg/VDiklq9Aua8KCxvn+fju6R7oP0hhwCJzByhDUqAZixPV6ozAeiY1Ozj2v0Nm + kJTuurTzHgf9iMuY++kzNSaGgTlmWMYIlFQe/Bx4wW/+/k8GANYAWnwA1C2CJgoDvunVr3vtI1MeHAWe + RvdHCAAXjI2NwdLSEgt5qdQFf/G2y6FY6IIffv9bMDg4CIuLS3DXXXfC7t27WeB+6Zd+CT7ykY/A/Pws + l+AiJ15sQ4BeOpGPI/Dtwny8Yw0AHO/7BgCcVC1so27eMoEmwF5469svgwen9sPo+BivYqTGigaQZw3g + uIOmwFCrNmgPA5RrFbnHJC0eaUbXgpdxdDmhJtrQExcS3twTUdGPx6EJcE4dwsMIAPfhJN+LAHBUSEBc + +MOzmQjEwUAA0oUAgOYD8QdoC3F9ax2y+3JQuB4B4EAOgrksOxB9U8bc9bpr5WNbrMNUNjG0ZWPN6E5B + c98cr6fioV6Gx4mdgQVyoOagSDRqCuNyynBfEoX6oJtw1MkHpvpuG8BqOXDKAtwsNnlFnxudg4XxBc72 + 0zPTDUP7iODTDRkGAOFqcNnw0ioeswpHtx1ljaH3SB8MTg0iaHQxGYiTg0ayUyc2ZlgiVGVfQ4KS6lsF + TzM/2yShFthlrLhQqEkGosAZqzM49S2I6evlfdi1aRe8/Bde0jKP2hOlEACQCXDj9Tes5wT8G3y98TWv + e23jkQIA2pxzMwLAeZRDj1Z5UqkpX95l7/wr7vx73/lWBIAB+JVf+VUufkgUxm9/+1uo7pwNH//4x9lP + MDk5xavEQxH4U6UFEG/fAIAEFCQKsG3bFtiDAPC2yy+HB/bugeGxUc55x0UvigVODhqEqQnQPlpGoMmM + Ia5BFU2Zar3KICCHtcbQDYtuzbkyoDZ8xPv7a09Ac2h7HTIPZFgDyB1AIDqGtmvFYzeQZRRwiNHnSAA5 + EKM+fJEJ8dgqk4IoIUjhxwWmBIezWXYiCjmljdjTzlp0ojQt76tA2KkIAh4h5wAItHwYhVFx/LIFZ3NQ + YMOBFIWgFtsTpGDogWdVawaMMIZ6oQ4rfWWY3zAH86PzLNx9R3rYCdhDyUArOdkbgcAS5WLeLEQ5AQ/t + PATz43PQR3TgyRHome0WHwAVCq1JmTBT4ttoQ74lAgGXDPeM/W/vN+EqRLEKfwC+dWAmSiuWnIAJ+xj4 + d9V6yJb3cf5v37wdXvQ7rXsB2oScF1MyAW64bk0UgJoBgPrPKvRu+0kAcAMCwGNJA1hYWGAAoJjvm9/2 + Pj7mA+95C/sFyPZ/0YtezFVNrrnmajjnnHMcAJg8YbhuvfeOBwDrfXYiXwABwAwRgczcxUElVfWsHVvh + gd174G2XvQv27NsDQ6MjqBmEvAegyJlu8uwr8DVltk1skaTCz9MVH26tjitvnSjC+EINCQjxJaOGzXC7 + RtDUhidOP7H5iMxDgl95coWjAbkfFhgAslM53ghEpcA4v18bnZY0gIgiAT0RxKRBPAYBYGcNglkf8ncV + OIoQHA05aaivLMKW2LyXCviJSDsthUYdACBGoMkFQONKORVpT0AmyHL6MM5247cVEE0tDIdBma6axLlv + 5kmlr7Laf2zzHMwhCBAvYHTvMIzuG2FTIFvFa9A+hwSYMUgOQ9IYDu84CDNbZqB7tguPHcOfPVBcLDId + mNKDsYC2MfHshi3to93MFNtBEj9IYoyhdBxSy6C13FgCZu+Az2MxsWUjXHJRKxHI2fDDbWhoiDNVXXft + dexE1wPNx3+Hrz9DAKg8dDE/fjvuU7/ggguK+ONO7OS2kZERBgAiwBAAvOHN7+GOffQDb+PVjxyEf/In + fwoHDhyAK6+8AoaHh+HTn/40zM7OMqK5AGAH/SQAwD32JwHAep+Rg5KYgInWn49ZA8igtrJNAOCtl8Pk + /kno7x9mLaVQzHN24FxeACAEySXH3l2dGKbIhtGUqXoQFRBZoY1C5Qo0EQR4lyBI3L1daOyoE2eogK/u + REKA56IN/9QyT7TCvxchfACF/6Dk+ffqal/ax+XZc0S0M7CXAAABBE2I2mNwfiz6ULylC7IHHAAw+QFh + rYbigsK6xT7bBVjNXNrNGIQ4wTM+hwN5MxVFUggAAikc4msNgnYq9Hq5A3lHIAoze/WLq7A0vAiHz5mG + YxOzUJgvwsRdm2DgcD+TeygbMFX+pdbINKDehfePAHBk+xGYPHcSsmgiTNw9AT3TlBsQ+7SaY4YgOQFT + 299LhR3AAqSt9Ne2ycvkAmgBMmf8bKajWP0kej7yAWye2AS/f9HFLePavsozABw5Atf96NoUANLGTMDX + vP51j0wYEAGgF38cQADoIQ1gfn7eagCvftO7mbTzdx97N3vwyWv+0pe+DA4fPgRf+9o/c2aTz33uc7C8 + vMybG0zW01OhBaz3neNpAeQDmDl61CEmyWag7du3wAMP7IG3vu3tcLh8FHr7ByDElYEcWJQSrIAvVMJt + KSh3srh178hxRCojJw2p4IrF5kBFSlwlvibHAC1Go1EAs9uRVo4SToI+SQVWR/W98t+qkJlBm/qmHNvx + wWEct1UiACVpMVIw8VEBFEoUGvU1oTlWh/qja1D5lRWIMwmzCAt3kA+BIgE48WtiRthxsljipcVDYH0A + WKO9SByRd9OFWQSBXLo3gHwABZMmLJR03Oztd0sjtk07w8LnqAgxACkHAKr0tLFnatdBWB1chaGpIRjd + PQo9M71QXClwIhCvKaYVhwxLFQSAKhzbOAuTj57kUmJbbt8K/QgYzAUgPwBpAEmwtjipo93Y0K8BAUha + AaBdauzUauUAmLvi2pBUGWjLVrjkmc+xY2zzXDiNAOAwmQDX37BGO/CUCYgA8MgQgZ70pCcRAOzHTvYS + 4cf4ACgLzGv+4v0wc+QgfO4TH+GboL30BACHDh2EK674GgPAZz7zGV6BCQBOhrRzMp+1+xHc39cDATYB + 0AxxVT4u1Lh9K9x37wPwlre9FY6OzkL35j4OS2Vx1SqEBQa5kPIKBKbMVZImfIj1Yfu6stHfTeBEIbxT + sF6DmCjKTV1RTAIKzngjYTQ/0j3lqGPFPQk0B0h4KRNQEwU/Iz6ASeIBCAWYNABxvAd4bt2b4KlGkfOg + 2RVBcyiCaAcKzi+scAHRIlOJSxBO5iWhSE1TfxnhjyUUx85EdSj6ZvIqUcnYsTz2Wl0HTG4ArQIU5PFb + CABEnsqHWSgFRSZUZfxQ6gZ6qRaQTroUgFyGKMXXKfxH9n+1pwLHNszC4Z3TfE3i9Xcf7YYutOmJBZhp + SNpzOj8xAaslfHVVOGHI9PajnCJsbM8Y9B3ug+5jPZBfLkBIfAoCgLjVLGtR3R2HsZGQNZ9BO1Cm7Eoj + 3In6nWJedEI456yd8Ozfe0bL99qFnDRnkpebbrhhvaSgnyEAeO3rX7fwiADAhRde2Ic3sY8AgDpGGgCZ + APlCEV75xvfB9JFJ+NKnPmoB4GUvewUcPToNX/3qVxgkPvnJTzKbj26oncxzIoF/KM7A9QDAfY8A6yiq + VG64kY7buXM73H/vbnjrW94G08VZKG3o5aHIU6orNANyqAF4oTrbFAA8tbnNPgYi+AizTuJCxGIsE5mp + qvkItC6X1MbzuBglrzCBTKcYbV3aBAQFqgiMk3dnHaJzYrTb0fQ4gK8jCACzAWf2Nfn9zepCv8dmH0XG + 44pBUTdwJKGxrQKNLU0Iyng/16Og7EUwo12BFaI1y8YgyVMIAl6sy/tSPw+kom1Ldd9YVjbWhrw0asCR + ALy2R2ZMF/4sogZFZKqoBAX6z8ProhZFmYTJmPKVxWiIUIZcZfn5pEkFTSkFXkSNqg/NNwSAmZ3HOK// + 8N5Bduh1H+uG3GqRtzlzZMGT3AHVUp0BYHlgEeY2z8Hi2BL0Tw5A36F+/l5hEQGAioTGgb2m5PmPWzUT + L7Xn6Y/AS4k+J5SipPX3xGwLpvLgDADntAAAfb4eAFAYkDSANNGNHA6SFpwA4JGpDYgAcA7++DEKT546 + RhqAAYA/fc27UbWegn/63MfYsUY28x//8Z8yD+ALX/gc3+THPvYxBgZyAvqOI+hnMQPWA4H1IgLmfQKA + 6cOH2Z4yVFTyWJ9z9g64777d8I7L3wkHj0xDV3cvT9R8IcsmAN0jhbKMA8+Ws5ISeMICc3P88Y5btFtR + C6CEIbRtOIolKQlTYgNf7IVAjqVNQjFOdvIBANUDHMBJvxOB41ENBgAqCOofwVUbbfmg7intT2dCkFJV + uYXCJiRCEJUSa440oDHe5IxCWXIk7s/whiAfNQAKhVk2YGJyAYKE+SJfL6MMt6aukpGJX6rXXkOJPB6o + fQABQE/MOQxR3KGIwtlVKUE+/j+8vQeAJFW1Pn6qqnOYnrxpdndmNrJkAQOCiqIgopJEAUGCYFai8fn+ + pj8SFgxPRREDiqDPAA9URBEEMyi4hI1sTrM7qSd07q76nXPuubeqe3pmF4VtHWa2Y3XVPd894TvfQfDB + gwhT67CLj9RCfP5dT10LW2jFOrQizUFiAFZj6M7Hq5BvyXHyb3jJAISKYejY3MVCH5wAnKAKgM2jv+n0 + Vx0XKnHxADomYKhvELJzxqF1exu072yHDCcCYxApRFUfhuYDSOnOeD6GHOXVUc9dk9CTTcFYu1YYlqth + KWFTnTxkEMC15+Ca6+3rhXec4c8FaAYAlGvbjeuVmoG8qWXA/8Wfyz98xeUHZjw4AsCh+OtxBIAoHRgl + 9BgAYgl41/s/B0MIAHff+VU+0HAkAhdccBGfrB/+8PsGAIgtSCqnMwHAvwMK+5sQ1ABAwORIyyWVMZcu + Wwzr1z8Hn/nc52D7zgE0+hRnsmPxmJK7juLilcGXdNPqtpr6yRddRkypi2/zQioXMQwoK9GQcrHIbpyn + STeO5WvxU2gRpl0bF0gHLno02PKRRageWobIM1GIPou75zb8/OEQ04BtS5ej/aQVtymQPZMngUboZtAI + ZlVYG7CCoQDtsDQsJErzA8dxBy6SopCnxpqHxd3nrV0auLj8JjwNPU0opFeI9MALFnlhVxGYqIuRWYwI + OrPLuMM6kN6VVEo8ZQwDahEGBcdV3pJO/tme32tgKiWuGjFOij8UAuRbSjDWk4WRvgGIjiSgGwEghbt/ + fCIBoUKIR4Lb0rPApUPyHBAEqHQ41DcE490T0DKQhjYKAUZpShAeD+UBaJISz25wVI8Cq385hqNii2Cr + OT5VnOTPcrjbU4VvWjOVo0GtfARSDuQzq1SPqFs0FEIAWNQLZ55ZPxqMJ08HbhRqEwBQGbA2NQl4N37e + 5fh7O4LADO7ICwQAL3vZyw7GX/8kAKDkBHkARaoCoHt/7ns+C8ODO+GXP/kf7tojALjwwkvY6H7wg++x + wRMAUHWAJp3sKwfw7+YC9gUClAQc2LWLTzTt/BQKUHy/dPlSWL1mNXzmM5+HgdEhSKZTbOzkySRZEyDh + U4HdQInHJM8UHdaowXKcCyxEQj0NBDz5QpGbhvy8vSU7nqIDe0Tjba2Bi7E7qQDlX12AWo8LsUfQfUYQ + oH5+i0hAxYBct6uZaKrbTpFscKHE8O8MutBzy+xJ0Ngw6hhMPB6H6IYYdwXaBQITMKPOdTsyexNuwMW1 + BaC0fJcneQ7OE3hs/F7Yg2rSU8nHuVR9yENheQEiQ1FoX9WKO24GvQD0oioxBQCgQ0AwU5N5yIoAihbg + qETRiGMUzxeh0J6H4cXDMDZnDDLbMtCxpQMS4wmITlA23xF2HijxTarRR1T/QKGlAMMYAlDiMDWC13I4 + hbt/UuUAaFpwVeVxWEKOVYGUCClIpcgiVJUciK1debZ3xSQEoU1rEFO1f0epJnt6ZDj4nYQ1lQPoX9gH + 57zJnwtAr5sOAB7/22PN2oHvxZ8r8WfTRw4QAByJv/6GRhMhhhLlAIjWG8Hd8ayL/xtGh3bBb37+deYs + EwBcdNG72eW/7bZvcWXguuuu4wEcxA58oZKAM7EDm4FAfnISdmIIQvE5EYDorNEgi8VL+uGZ1Wvg05/+ + b8gWcpBuSfMCYCILegBJDAMcqVzUxXbym8HAFY4A3+exbj4tHKoGFMr4UyopYpDn+kkmD4wOIFACMFPj + IZ+VpWXInZjnbT3+AC7yDbhz7g2DNWqx6143RTf4nXX2ngRF0Juozinj7l+C4iFFfH+PcwDR9TE1Kiyn + WoqZUCRNRWZgsRh5PQNQaEf6MUnSaQ2DKh97WYHXy3JQOCQPocEItP+9Azq3dkDrCO66hRTEq5RQDSs+ + QOB0uuAa959dbtwuS3E1B5ASgONo+LsPHuAuv1nrZkM7xvNJjOOj4+T+h41+IJN3aIQ4AgcJg+QzORjq + H4IJ9AAMAOBPbCzOqkC2zGvwRL1XhUIAggo6PyqVDldz/+Qx1azEfR2aGlLzRDsSRD7dJ31ppWqqkiyZ + tQTee1w9E3AmD8AvA5r1fZ8BgCsvn8ISesEB4OUvf/lJ+Os3tGtSDoAYdeQBRNADOO1d/w0jQzvhoXu+ + wW4uGdz551/Ez/vWt77B7LjPfvazsHTpUtiwYcPzSgLu72PNQKAxH5CjMuS2bXyiqVTpSgjQ398Ha9at + hY9/8pOQq5QglWllAg9PBiJJsGSCCS7ayOooqwGWHFg+h0x/NjU+MTkIAYB+19yqEbzUZ5wSjJz8a3XZ + da4sx130NQVwBjAMeTQBkd1oMDQQdNziMd9apFO3JteV0bgr0GOJ8BqBSR8a0VF5cOfg9/krvte/EAAG + HZUIpKYiPSos+F2sAMfAhPx+jkPv3GysRD6i3oVONLh5eOx9eOxH5qHUV2DZspan26Dj2U5oH2iD9Hga + EiX0ZqwoJ9MM88/1cys6v0DedRk9gFK8AIXWAu7847B36R6u8c9ZMxcyVM7LxtGQSQocz49rmZCIyUNR + FQLkWidhz+I9sHfxXohOxqBrWxe07swgCCS5ezBUs31Md1UgVHO05h8YBXcVz6uTbv7NDD+XPQ6iH5tR + cCRj7gZVrVQ+gWyHPB0SBV00ux/efcJFdUnARgCgcrvyAJqGAP+HPzQZaMtHrrzixfcAEABOxl/31wFA + scAtvie//WMwOT4Mj9x3CwMAfal3vOM8WLBgAdxyy9dpkg8DwJIlS+oA4D8x+P1JCDY+TmXAHVu2KK4C + eid01igUWLJsCaxduxY+9vFPQQ5j9SSGKrQQSdEmGUtwGZMILnqEtU66aR6AEbGAgASYNJjQjlCuEAAU + oEgKxSRXFswg05/kXCTRkNpU3F5dhqBxXAFC60IQfTLOXACbfkgIpKqz8b5RBr8jJwUjQikmifAFaJhH + 0uzAEkSewnDiz+j67gpzHoApwaanILgC5H0bGYvmOWrn5+YlUjBuqTJ3odRXhNLB+NNfQlCo8vdPbE1B + 26o2aNvRDi1jaUgWY+igxDh+ptDFAGlgqCZFI6ReTkNASAa8iO7/RPckDPUO8fPnrpkH6T3oTRChR3j9 + jqgvsWAnAQB6JRX0AvIIAEMLh2HXYRj64f1z186Grk2dkBxS5UMeE0Z5AE3Q0MM9NBHCVf+hXd11JTzR + dF8qU6K3QYIlrBJsqy5G7jMoS2hRU8ECA5NXYwCgNde/oA/OOuP0umtXqdTT+gkAiAn4eBMeAN5+gT8f + QePf8UIZ/4wA8IpXvII9ADoQ6lPOUggwWQG34kFr5zywIzZkszvM1nbuueczAHzjG1+rA4D169e/IAAw + 3eMzhQKFXA62EQDgTkzxPbmhIQwFDjp4BaxZ/Sx88pMYAkzmOFlJi4kaWggAEqm4Erd0dfeb5ny7Kpll + GGSBz6xZBiiqbpXboEkxqEheQFUJlvJ6k0yzRzF0h8ttwBUSAjkBvatVIQivQlcV3X+begBytgIAN7A7 + Axi1HTYAjsuBh4VUO9E456BxLkJAOQI9CnyP+F8QULaorkB7UqkKGdA0W2GT8x3wBEwFJKLES6pUtZin + Yv8ShRvU/ozvXUlXmWnX8mwG2ja2cfY9PYEgUE0oVqWr26kb6uhU0icVIASAfLoEBYzfKfYnV574+z1P + 90BqL7rx48ToC6uR6IHmBMUfqAkA5GFsbhb2LNsDkwgknVvaYdYGRSCKoEcQKjjKYGVQCyc1a9Lxp113 + SvqR1yfnXXU0uvw5lKeooldCHkctWuPvS2FJNB/mcqUmbPFG4SoQoPBzUX8/nH6aXwZk76DByAkAqAz4 + j8f/wWsG6i/PTwQA9hwoAKBh5hR3QCu6yIPoAVQW5qD90BiUcriw1+Pi3RRTJSRcGOedewEsXNgL3/72 + LVwx+MQnPkHtxLzT7qsR6D8BgelKgvT3JIUAW7cyHyHMk2xDEEE3/5BDDoan//UMfObaz8MADEGyLcnu + IPWzxyNx6QaULLOuvasUtuyShsyufWO1QwcYZtVSlROChXKBQwECTl7ropfHO3aXq3IAlLg7oYjGH4HI + kzEI0zRgAoAJaeLRWXlZ8EGXncpOFFLwaDE0TKooEA+gfHiBjT3+OALKJukpIAAoWqa6Ya6+HfAAAqxA + w2yjuJfi/7hqPybxkuL8IuReOcmfF9mN5j3qQKWtxsCQ2BmH9qepBt8K6WwaUpUURDxfk6++3VYYgBic + lxMY/7eWINeBu/iiQfwZhhTu/D1PzVcAMBGDCBoalzON1wLcqMMAEq9BIVOAic4JGO3JwsScLBpnjHMI + rQOtDABhAoCqlEN1IB9MTkC990PAXxO33yWZMuIb4HFSkpI+K4rHlBlIMTvRKYaVdyGkMaVYrRLPixYv + gjPf5FcBGnd/DQDEm3nyH/9sAAc+HhoNdvnlV10xcqAA4GL89R0y3s62TnhywWMQPbUMZx7/cuhJdbEo + 5qaHBuHpb2Uhv92Dcy84HxYvXgK33vp1bgK68sor4fjjj4fVq1fvl3jHfwoGzZ5LSUDyAMgAWcMwHOGB + loccdjA8+8Sz8NnrPw/bUwMQn51kowjT3DuWBZNmFss2ohHGuG2lWWdJHRt4/p0nf+uGG3R1K7goy2go + 1RK3DRMgaD09VgNOUP1fSYGVF6Lb/rIShFeH0QuIsa5faATff8Ji39jWw0QovVyxZP4ASBJS+hwiHusD + ckluUQVKh+POXLEh/k/8Ppvw+1AlAEMKaixypC2Wj4MlwjSgWMHIxvQcsfcTxZ+UqlzwCPMlGKujl0Gf + Ed0a5o5FDx2pQn+BWXptzyIAbMG4fSwF6VIaom5UMuU+C09rO7osAoohRRIBoK2I7v8YDKwYgGzPGHSt + nwWz18yGFMXwE1EIYxxv4n8BZAInUhGm0iRRiCfbJjmEGF0wzB5UN75H684ONlZqCOI2Yi0N1iSaNsw/ + SfgRyFKeoJLA85qhScU5GFk4CpMINK3bWqEDvQwqfYYnI6w8ROVQrk54CgBo86G809vf4vMACAAayUXU + dUuy4E9MAQC+3Y4/V1x+1ZUHZjbgscceewn+uo0OctmS5fBccR3sWrEBFh4VhROOPRw627s4lH3qwZ3w + 8OW74MwzzoYjccf/5je/ZgDgla98JaxZs2a/koD/zn37AgEDABjnU1afEnspjO8PORQ9gKefhc989nMw + ZOEu0RJXUteRMHMBokklbmnJCuFkEMV8tFOFVQKIvzwZCinbVEF2alDCG1LmqYlyMakYU16Ac8o0M9CR + EKCdvADcsXtx5z4IvZTV6AEQBwB3U3sM36Oo6uO2HtNFx1KTvw0/XUIUDgPEC5hfhsohZdpWIboGF+V2 + NFAaFZZ12FBplwLNadAahZ5tDJ8ZgTwZWBJ0VPdP4B9S+qNZhLmjclCZX4HIxijLl/HMgrgHxQVFpji3 + bGyF1k2tLMmVLqQhVo0zK1Llx1T5wRU5LjLgahjBEt3/fFsesnNGYe/yvdzgMw/d/7btrRDLomfGO3jU + r0y4mg8hAIDHWUgVINc+CeOzJ2Cwf5DLfl0buhkAkuPoDRVlwpLQstnQZfpRvUmIZBkZP4FApAb5FvR8 + KcTA8IRyDHkMVWat7sb3n8UUZfI2YrmItB2rtUPiJ9x/0tsH55z+NmP05JU23ggASD+DqMC1mttonHfi + HVdgCHBgpgNrAKAFfMIJJ8DhBx8NW7Zugp3FjbAb1kKqD6Dr0CSEuqvw92sH4JWtZ8Exrzwabrnlq3Ue + ALUIP98cwH8CBsHnTI6Pw3YEAJrio70QSvAddPBBsAZDExoPniuUufxHZTyqEHBLMHoJWhOQY1ZHGT81 + 2VCrarmlArWUqic5BZtLbHzRq+qU6vkALg8poYlCRfYEiBdAi92KUAefB2Wi7i7AnyMRHHoqEP0TLtDV + Ss7bGnekeUft/qbyZ/sRCKv8SqMRZ+cxrKi006jwCgMAGURkY4RDCgvfk8qBNlcClFqNrXdBNgIJM7Qk + lhgGZ8VZd4DmENQYACq96AIfkQfc1CH2LO6qO6PqeQhAxd4C1Do8SG9PQ2ZDBlIjSUgU8KeSgIjIcemy + pmLfqSQbiYAWMyWYRKMiABhdOMIDPec+NReS6P5HJ0kDEAGyHFXqyKK2bEm2voohBIEAgUZOcgiDGEbQ + bty5sYvVgWiWAIUAdkXpAgitLyD8KaCqB3xqcKIZBckKgtMkHt8kU413IwCU2grQtrkdQWAutG9tg3g2 + wXmKUCGgMES9AJEQ9GJ4TACgAaeZB0Bt9WQ7j5EseLXBA7Dgp8AhwJW7DggA4O7NIQABwKte9Sp4zWte + zxeuhrHszm27YOPm9bA3uxOGiwMwOLAHTj7+TDjq6KM5BKDJux/60IcYODQANDPgF3L3bwYCVAbUSUAC + AGKzkYEvP2gZdwN+/BOfhKJbgTiCAi0GNeUmDkmStcKLpqb7elIqojgbF0JLGQpz0FWdW0LDRwPYE8Md + m4Zw4A5blDHUutmEetVrFS4J0oRhAiKaOU/uNLTjIqBZgEvQrXw1+uVpD2K/QiNZRz0A+NmjNrMA2ZvQ + FUmeuGuZioPFE4ilHwGNtErZ+dk1ZaAvLbJICAFAdDO63xinh0goNBdioLIkGcd8Gj05GDzDU7ACNFei + GlPDEfEWeBDJkiJU+/Cc7kaDfA535TGHAYDKg8XFJS4NRvGctKxugSTGx/Eiuu8VBAq1pfqzCBl0VHxd + juIPAkC+A3fYeWMwOXuc6bvdq2bh7q+m/EZKKtFGfQBMiJL6JJuro0Cgim56AQ1zonscQSTLswPbt3RA + y+4MVxGi+P3tcsjkd7Tyr+JB2CbHQwlfTu2Q1xdB76QFvR50+SnBONQ3wuFJJVnEXT8Oc56dC7PWdENy + iPgGeA3zITOSnQaQhqIhWLBwAbzjbX47cDMPgACAulepHdgvEZpcx88YAK6+cueBAoBr8MTcQCfnda97 + Hbz0pcfxQaXTKWa6Ub83sQCL+SKMT45BqiXFJJvbb78NNm58Di655BI444wz4KmnnvqPcwDPBwyCIKA9 + AEJbPWKMjHz5ihXw3HOb4b/+61Mw4RUgkUnzmYiEQxALx5kOTBeN37KmeOFVLn+hcbXjDtObh/HDJjCe + xp1uLe5Ou+LMgouMhw3lVjfPkJtbKeOizBe5LEg9AzV8L68dH5tbhtJSBIHjMJYuOxD7XVxx94dwkSMA + 2KWQyTXq/yg9Ai02Ikk6IiHR8aXRQLtpXDjupK/IM7U4RBODn0KQWoeGSvoCww7z6FXpUrYpsPyhIXpb + 1dkxsrWEyvxXOV9RZvFS0iCIP447KukWTqjGHPKKSkvw8cNyfFyZVRnIbG2BeB5BgFiBbshnRDriIqPx + 15j+i0DZVoJc1wRk+0cg317C12aga00nx/1R3P1p5/dIQTjgBnmiLkyVCGIoUiWAjZXCgJ4Jfl7rjjZI + 7sH1OY7XiNiABACUrddVHksp+dim58KVeYDUtEU8CxIcKbLW4Cga/9icCfQK1MBTOpMdz3VC9/ouSA6i + pzOK3mM+xOEXn2f8HIcAoGcBvPMsfy5AMw+AiHMEADQevNbAEQBVBbj8iquvOjC9AMcdd9znXNf9NC24 + E098PRx99MsRAFyWLXrwwV9BLJaEww8/ijXP9A5PmoE/+MFtzP67+OKL4cwzz2QAeCFyAP8OCOQmJ1UI + QB6AnicQCsFBKw6CjZu2whc+/wUYqmUhnlFJQG4ICse4FBiORtTir8mUI8qy4w5b7kAA6MvB6LEjUEkh + ID6dhuS6JMS34e4yhMZAKrxV4EYVS9x3miZEiUCSEC+7VS5Z1drwPedV0APAeP3oEti4O0cfC0N4VwRs + Yu6N43coO4FWVD8M0AlAlaBUxCJy02kHrnWoIaOFIzFefSnF4x5EVuHCXx1nbYDQIC5MGTJiuVqXT8DF + taQcpgyMXVhc5NTx51LsPwfd4MMVxyA0bPMg0uhmfN8RR2kjkEDpggrkXjIJLno0GfQAWjcjCGQVNThS + jfF54Tcmr4OMP1TjHAN1AE52o/HjDjuyaAhd+Sp0ru2CTozfI4UQRHjSsWIy2loOTVx3BoCwy2PWy4ky + 5FtzMNmJrjoaayVZho7NndCyIwPRbISVhB06rzU/fPBE6lzYPkyvJk+N+pdIboxZhiRQih7FcN8oA3gU + d3rmA8RqkNibgMx29HaGkuy1hPNyrOwFWDwzcVnXYrj4de/yCWPTAMDw0BD8+Y9/5rkZDbe7BAAOTA4A + AeAzeID/H/1NAHDMMcfiQXnQ3t4Kv/71PRgjR+BlLzveZCvpotCXuv32b7MHQABAHsDTTz89Y6nuxQQB + DQDGA5DHly5fBlsQAFbe9CXYVd0D8fYUrkeLM/+kGJSgARfRqKJ4utLgEcOLhgBQ6sxDbjG6qS/LQnFO + EeKb8eI/gRd/Nbp/A+g5jOPnl1WziZ6wQxeTaMGkHFSuljnhxdOA5xEJCP8+ogz2ViIBhSE0QEKeuFPS + 5lX1y32NtfO6Or50JNKcACIXVeegIS7DMODYHNTmVSG0mjQGo+iqU4chLn7SGCypTdTyc2Ey+chWOQyd + WyB7pfkDaTRS9Fjyx+Q52x9fFYMogkp0dxRCY6rRqoZGW5vtcYKQegSSW5KQ3tLCQzrTkymezkOdgaoT + 0JKKisu5lXICd9i55GLjLtszioBWg851XdCxpRvj/xCPOg8Xw0YEhMuS0nPPA1kQEGiWILUFF9pzuFtP + wMCK3ZCbnYMufJ+udbMgNYTXJxflfA13O1qeYQDy99WEL9A1fzyPqRKUUuhRZAowtHwvexXx8RjE8b24 + b6E7DzYae2ZLK6R3qbbjSC7C105pK1jMBDyoaxlccvyF5toFAUD/7unpgdGRUfjjo49iqD0FAO5gALjm + qgPTDnz88cczANDBKQB4pQBAG9x//90IAFEEgOMMANBFoD548gA2bFgPF154IZx11lkGAJoZ779j5Pu7 + +9ONeQABAPDkscVLFsO2zTtg5ZdvhpFSFuwFETYEh3TuSdgiosaEkeQV56ppPjwBQBoX2OwCTB46Abll + OSinK7igHGhZ1QJtT+AOsxM9B8rgF2x2AVkMs6bqwWUXXX23opKBTgUqmSpUehAAliMgHFoBBwEg8g9V + AnQoCThpKQDQenVWwOitQK1af20yVKoEoKFWuxFUMBbPvy4HlaUVBpfwMxivD4aYWuyRxFhJsdZU3C+5 + AMryiNAmhKT+HxKmIY0vm19SmoODEUg8id91Jx7vMMmW0zq3OAlII86KCBKFg/P4eZQHyLBGP5UDYyWM + 42sRLuNxF5+jAIAqK2U0ssk54zAxG8Mr/G3hOScPgHr6uQGI6vfSBGRp9WKQbjxL3stSoUSpHd+raxL2 + HjQA2fljkNnZArOfmQuZgQy3ElOuxqmosEWN8RZOgK1LvupclhN4vdJ5bk6amDMJuw7bDRX0VFp3tWCs + H+Xeg7EFo1DFddC2qQM61rVjGEAJS/TiSo6Z5kyy6f0LFsE5J59dRwQKqgLR3wQAY9ksPPKHR6CKa7ZB + Oem7+HMFAsD4AQUA+ptyAEcffSzQGersbIX77iMAiMHLX14PABQO/OhH34c1a56Ft73tbXDeeefBM888 + MyNb74V2+4N/NwMAWiy9/X2wbdMOuOGmlZCtjUHo6Bjvdk7E4jFO0RAaC0S5bKVaPMUAcIcrzCnA+Esm + oNJW4ZIaEXpiuAtm/pGBxMYkRPfiAhsP8UQe4DhTHQ/1updruDhrJSiG0JDay2oa8NIy1FbgLr09BPE/ + Jni0lz0uu7SW8qbkn20ZPYK6m0iDqS4+j2XCiV9QpkTgiTkoHVXmkCT0XJh7Ddg1rSlDl7mm/kQcSs5V + JTzgtA3VsVUJgkIA8iqIDRh5Ig5xmj40iCCZxfcrypxD4jZ0l6H4EgTJYyY5WZd5EkMA4gMQIaiIoVI1 + YkacqRhb8fgLLRj/zx7HMABj9wXjnJSb9fQsaNvSjjtqTHUA1sCURY24iACjyzMFRE+gFT2VDuIBjHIi + kPQBqVyX2ZVhw3UKYZUE5NZeOY/cpixDQ6gtGUO+IoISNSbRz/CiURhcNgzxkTh0bqZjCiFweZBFb2Vy + Tg4Swwno3Ijfc3cLhge4BvIhRVjCcx2nduB5i+C8N729rhdA/9ZAQCEAaW8+KgAQuNGTbyUAuPKaqw+M + KOirXvWqG/HAribDOfnkk+GQQ17CyTzyAO699+foKsfh2GOPDwCAan744Q+/B2vXrubXUBhATMB9cfZf + LBCgKsD2rVs5ean1+MiQehbMh12b9sB1N14Po7EswPtDPHuF84RhWynZuCGplwtFlJo/Yh4UZuPO2p/n + cVuRkQjGxSVuxkk9g+7uv9AF3ENeAO5ykw4nCVVLqSIN1WjUOfrehRDRXQtQWlDkTsDaIhcimxEAHkqg + kYaUm17UZBdt5xKj6q4iIeioWrjNApyUBKsl8ThJZmxuhQ2RZg2QbDiXKYuqtq9KfoF6N7fUgfANLH+S + D+2GRJOtWkpvAEOW8ADu/n9MQmQ97ubUsDRpMxmI+gTIAyBmYxGBIn/kJCsepzakoHVtG7RkWyGVp2pA + RIxPJTIJAIhgw/V/3K0pyZbD3Zbi6TlPzsHYvQ1jaordicEn5yDQGWlWMXP6a8ptb6lArgM9ibnq/ejz + KEmX3tGCLnqMBUboHFAMzx4OnceqpfI27LV7PJew2IoAQI1JPeOw95C9/N7dqzuhbWsrOMUQazFMzkag + WTjK75FGT6NlJ1GOwwxY5AXYJRuipEExZwlccty7jNHX9XMIABAPwABAudJond8WADgwo8EQAL6EB3Y5 + Gf0b3/hGWLHiSNbTa2trRQD4mQDAq5iwEASAO+74DnoACgAuuugiWLdu3YuWANzX/VwFQACgjKqeakMe + QM+CHhjYMAjXrrwOhmeNQPUu/A6TwDuMK66wnsWnlXQ5PnQwdqPYHRdCbEsUASAM1S405jll5gKkn0pD + YmsSY2I04glcsEVlWJbrmJ77Ci66Ej5QTBe5f79yCALIXI+FQCKPR3gsmI0xNekAsLuuOwBrVj2VVloM + vaqq51uSGCN+uhW3WGiEtAGJmktqPRCmSoHubpNSn5TA6H5PtP48qcurJB2IVqD6TSFgdEsYYs+ip4Lu + vz3isM4eZdSZK0/TimehO78Ad+DDMURaWsQQIQLdj3VBy0ArJCcSECuTKEeIwZYTeY4ytlx7HgYX74Wh + Q4dwF3ehC93/Wc+SDmAKHKL/lm3Tc+/pvotgFyMoACCSFoVm9H7jPWMwsnSEgbwb368FAYA6BClmV12E + RB5S35tKozYel2rzdjmXQGVJyicM4c4/vGQYjTvFXkkcwYnKkTRuONeZhyF8bHLOBMSHEew2tEFyMsYh + ICkxk6JT2InB0o6l8MGjL2sKAPrG8vujo/DIw3/gylHDjanAV3706gNDBUYAuBkP9AoNAAcf/BIu/bW1 + tQQA4DVTPIA77ritKQC8kIa/P3/TLSchAI0lCwLA/L4FsPPZAbj+SzfASNcIVL7psZvMMWBYjMNWNXHe + HSlRpRNEcY9RPbE+DiHcAak5pjQPF0pfkWPe9OMpiOyKMQhQrElVBEXlVcIVtG5KVFZqnYTiwhLUXlLi + CUFhjP9Jwssaw+fmlBAoa/nXlCF6Ou7Xu5+SHASjVK1HUlkgE4PQ0DMuhy6sGkSYEZKsnwp8xTsRmjE9 + 7irjt0MaDBy//EC/MQIIDYd553eyaCzjuNPRrlyT10fxs9oQAObRjII8FI7Ocfdg11+7oGNthxrVXYxz + OZDJRlQNQe+pmEbAwJidkmzZvjGM+ePQvqYLWrelIYkudwRddtqhdZji6f5q6asgNiN3RYJi7JXp/TK4 + cy9AAFg+xGFNx5pOLgdSOEClXRonRr0D1agieoUw7KFOQQu9AMJ8pv225GECw5Isuv+UD+hcjce0tR1B + RPUjUG9AAT2Nkb4sAsQQVwsy29oQtFrUWEUCFZrMHIrCiuQKuKb/w2ZtBkVt6gEgC394+GHmrtQbqPVj + AYAD0wz06le/2gAAGfOhhx6NBx3CECAD99xDwp8peOUrX4sAUGkAgO/wmDAdAhAV+IVK6j1fECAPYKfo + AZj3wBPfu2gh7Fw7ADd+4yYYDWehfDZwFtlG43diaiAI5QNox+fkErn/epoMutnkHYRHqKauZtOVu8ow + ccQE1NDgWv6UgtTTLTyeOzyBrmaJ1pfHk3w8jnddKFEuoXMCJg+fhPLBJbBGHVWq20CGhaaRU2KgDEIh + xfYzWXkQElAYjBvMeUFbGb6nBTdJrw9DFipTEcCoXV9LflHsK+/vKMUbS/cHiN4hi3/Qv8kTJW/IUtRU + yk3YGN7YGOOG8qIvoIdmhmVgaZcqB5aXFFnvILE5AR2rOyA9mIEoJwLDzPIjo6UZAOUMegBdORhePgxF + DAVSA2loobwBhlOJ4TiXAW3XkeGdsmo9PyzigSJUqaHvwglFdN/bFQAMLx1iz64DPQAaFxZG4yUwo3Ih + ufh5/FzymuKjSmyEvAVSP2JxkY5JNv78LAxJ8Ji6numGxJCaNUghFVVzKOE4jiHLCKkX9Y7i2ghDfBA9 + BOZYuHx+nEgYDqsdBp+J/pcx/OkAYGR4BB4lD0DnAPzlzABw1UevOWAAcBMCwJUEACeddBIcdtjRnPlv + bW2Bu+/+MQPAccediABQrjO8O+/8PvzrX0/Aa1/7WnjPe97DHkDQ5Xkh8wD7en4zAKAT37e4D3as2wU3 + 3fplGHWzUDkK70eDsXnIBRojAh0NClHTe1SzCc/9k9IRu54ksolxIJWRKq0VKCzPQ35pHmKbo5D+Zwbi + 23Cho/tLxmyLCg83rcTFRcXYceKocShhGOBskWnA1LQz5EjXniROjS6J57cSa8aeZb6scmNtS/jrNTWW + POEp7T5HPYcMnuiypPWnWH626abzHBVCWIpip+b5iYIvgYXNPfJ4f0V5QNz4RAW9mjJGGppO5TwSCqWc + A4UgbncZSr0UHqFntDHNmn6xYgRBgJhyDucNamholRQl7YowfNAI1JIlSG1FANjWoowtG2feQsgTlqUY + PHtVkktgeS9P0ayZFkzZe3y/iXkTMNKfZRn29ufaIbU3zQBAzym3lGFyFj6O7n0JASi9PQPpgRSEc0oI + kfgD4/PGYQx3d3Lnu3D3b1/XroBiMoKhT4i/b5GSl905/KxxyOHnURXC4yQqXQ+ZNJgKwVG5w+Gzzn+b + dRiUrgsCAE2z/uMfHm0UC6G3IR7AFVd97JpBeAFv0wLAa17zmq+i4X6I4n4KAZYtOxTi8RbIZJIIAHcJ + ALw+AADqC91113dh1aonSVSU6cCkCRicsPJ8jP35gkTjv6kKsJNyAKIKzN48eQD9vbB94064+Wtfhmxl + DLyDFO3XQSPg+fY0FyDkGCUYzq6z9pu4oRTPU2yPuxh14VUzFW6QmThyDKr475YncLE/m1JdfdSBJ2IR + LCqBIUQFn5+bj4vm8AmoUClxAwLOxjCEt0WYVMMtuxW7Ljuv0AvM7qclyUQbyzAEQQRMOJZHb5fmD/oM + IiW9xT0EwYSfpXIAWrJcMesIBzzNjZF+BFvlNMToQavk0rkNCcWZuhJb8Zyg8VcWUDKwAJRWTT+TgvQu + kgmLsfGwOEgUmGNPtfbxnkkYxvifDDuzvhVSGG/HRmNokBHzedrozQQekMSu6AwwGcpRk4XLbRiWdRch + u3ACvzZ6Zlvws4ejrAtI7L4SnveJnjHILskyACQGExjDJyA2pHZ38krGF2b5+FI709C2oZ2PKY7HFJ2I + qAw/5T9ZwryE71Fi4CHacDlcU6KxEqY5yRAcHj4Mrpj3IXMtpgMAIgI98vAjQSYgnWn6x08EAIYOFADc + hi79JdTL/OY3vxn6+pYzALS2JuEXv7gT/07D8ce/wTCWtOH96EffQQB4ggHggx/8IAPAv2PML8TfE2Nj + rAegPRD6TSeeeNnbtu2AG1euhGxxHGKL03wxHeoIDEXUaLCwpuGKEZBIhOawkwvNmpa4GDHGZYLQAgSA + o8ehgECQeioB6X+0IABgGJB1WKOfvAdmnSVICagKuYUIAIdOQjVVAWcdGj/1AGxHINIJQLdBBzCo1iON + O4YP0JARtyxfwoyN2tbCpgoMdKMKtxNrlWH93UCqC1p6jDyfmhg/fWPRPqA4WocNmoikxU5JMYhcf2I5 + 5o7P8ezCtsdaeQdNjqVYnjtUDXE+pYQ7cbEtB6NLRmHwiL0QGUlwviC1OwmxbEwxAMnzkhxNjUuerqmC + KIERqeFTqoCSgFEEZHLv5xVgdOkoDxtp2ZKGxN44zxMkJmYRXfcs7u6l9hLH/lyWjNQwbMPdHb0EqiSU + MkUEoSiTfIjlGRmJqhFj+ZDSFiS9R9oAYiqUAako1ELa+FWexYmG4ZCWQ+CDy99jACDYIKdvpAlIPICH + H3yIOTX6agsAkAdwJQLAgSECnXDCCQYATj31VOjvPwiSyVZoaYnDz3/+IwaDV71qegA45phjDAA0CwFe + jB2/8W8CAPIA3AYA6Jk/H3bs2glfvPZ6GCtOQKqnTU25CVkc5tCMO5pwq7vFLG5YkSy8jLPn/5C3SACQ + xJh+bhFyh+SgsCIH4cEIJB9L83juCHXgTYQ4I8wTZkkKrEMBQO5gBAB8rbMmzK3AoR0hngVIJcmgBJh/ + sSzf6I37H3is2VXV3kEQFDSA2A3YERQDCWTX1Wm1GmTJwHgooBV66VdcAKCzBtWFFcgfnePyYWYN7qLP + tKvBHqTMgwBAAiO0c+bb85BFV5yMNbktA+242yb2Kl49uduKU688Da7S6PZdW7oJRemYAYDERRNF9AAQ + kBdMwODhezDOLzIAZDZneDwYDRPNzZtE936MX5/YneY8T25WjnkE9NWI3OMgEHSsaYcWDA9IUzEyFuax + 5L6uokwNjgDnA5RMmKuSk4ZcRFUZB5ZnlsMVB39InVFZj0EQ0GXAMVyzDz34e1UGVOdZirTwA2AA+OiB + GQ3WCACLFq0wAPCzn93BAPDqV5/cAAAeVwEIAI4++mgOATZt2sQu+ExS3i/W3zoHwGwr7XrhcczvXQC7 + du2Gaz9/LYwW85BqaVFhNMb/RARKxuI81kplxxUxRJfNoCYAYHTycAdIoRs4S/ED8i9Bo864kPxHApLo + CUSoP4CIQUTsCQmltrMK+WV5KBwxyeSV8D/R7VyL4cIOdP8pZNDy3VZgHKhlGfc/eOWmAKLRDfICxmpN + ed6Uq2/B1PexAh/oBYDH8p+vZyPofxBrkAVK24nqXIbS8gI3CMUH4pBZ3QYtgy28q3NPQAI9AFIA6s7D + yEHDUJiVh/ZnO7iURrF2fDzKvHpmVQonQpX8A8ehhAXM3IEqKwuRB1BiPsHQikHILh6H5GAc2ta1MQmI + cg5k/PnuArr9MUjtSPO3JDESavGl+8sdBUjuSEH3P2czfyCWjUKUqh65sJJpo/XsyI6vexpsmSDh0Bw3 + W7wrl0OA/u5F8L5XX6JOpdT99dBc/W/qBiQA+MPvH24kAhHU8nDQqz/+0QPDA3jta19rAOBNb3qTAEAb + A8BPf/pD/DsjAOCXAel25523wRNPPM4AQB7A5s2bDd3xQIUA+t9NAQBP+uKli2H7tp3w+S9+AYZrE5Bs + SXE6jHMATgjiNB7cVpx1w76V3d/0scvaI5SvpVwodKLLOz8PuZegF7AYXcd1UWj5K4YBe4kuS4QZiysI + tTSGC7PKMHlUDvIvzYE9akHsz3Gw1+Luv91WJUDqd69I+U2ARyX4AhJWEAAFq/57m+Ye7cHY9cZswXRg + IM9RlMn654luvqkZQiBM0CfDEnmvBBpCGw08QUNcVmRCUmg8AplVuJvubmFdv1AtzF2GlKwb66Wdeogb + emb/tRsyG1uZshshd7zoSAtx4FhFqoiPQueXbBH4tFWlhZJ8VKIb6x2DkWWjXLnJbE6xoAi5/xRyUKWD + wCa1K8n5HKrSVOIlmJw/iV5DHpIDSWhf04nhSILFPpjgQzTvquqX0Mpq3OIdoBLzIYXU+DYKoZxYGHrn + 9sLFZ77THK9OTGsAoJ/56JlSL0ATJiDdiAl4YAEAD+oSEjQ85ZQ3YgiwAjKZbgSAGPzkJ7dDKtWKzzmF + J+PqxUaJszvv/B78/e9/giOOOBI+/OEPw5YtW0wS7sXe8ZvxAAwAyI2OcfkhB8H253bB526+FgbSeyDe + lVLtoPQdcCHRfHtKfjoy1NJzhYAigzksGSdnydgsoo1WWkiVF+POpQUo4q5HTMDEP9SIbqIHO5MiNJFE + F7W7BOPHTEDp4BK7/fEnEQDWoZdAeq8TFivMQs0T/8+rmzyjXHcxRs8Wu7ZkAKnkJfSQC9uqrxhoMJhu + FQRsGQRcdOhg8EOAwrIC2oRGXlyp81Dtn6Yekx4BlQJzJ0wywGYea0fjzkA8H4dwNQJenMqhBcguGYfh + Q4dZUmvOX7pwR0ZDJc4+GVzJH9Shj033dGgHwCRrWbZbyaQTt4BKipPzJmB0eZbLg8ndcW4oys8qoJFP + QDQbg9a1HZDYo4aGEMiTK19pLXKlhiYJUSkyOkpxf4RJT9yS7Mq0Jgh4g1opmo/PMvkjoiiTElXfPASA + s883p5xsQtsFfw18IxLVZSbgw39oAAB+DvcCIAAcmF6A173udQwApIyjAaCzczYkEhH48Y8VAJx44pug + XK4FAMAWAPgLLF68CK655hoWOTRU3AZDfaF3/Ma/yQPYtX17HQBQx9+KgxEANu+Ea2+6AXbCACQ6UmpB + OdS7jQCAYUDYCZtdV+vOeeAZAo7pIqOogAgtSTXjrzSPAKDIBhBdizHsGtzJRtHlzTvq9bg4S53onh6e + g9qsGoS2hiGyOQb2Njw/1OiJ+K4AQA6YE25+JWAKd9+yTL8AP6YbfAJDLdX0GzBkKK0vYAZzao6BeU+R + CnDAkKG0PJpxFCxNENJAoZ5D4p6sHkx05K4KVBZWEAAmEBwrkHomA61rSJgjCdFyFDyMtwkAxheNwwT+ + xPYkofNfGP+ju87JOFLaLcsMQXl/0xatjyvgEXleTY1Lo3NMA1fRA6BYf2TFCANAfG9crYueSS7HtqKn + kd6c4WoDgQ0n9lhmvcaVAvps6u0PFQiIwkzO4ooE2D742AHXRDuGtu8hco8JAkDvvAVw4TveWWdyQWFQ + uk4LFy7kEOCRhxAAgoIh6iW3AwPAxw6MJiACwHfRcC4iyeyTTz4JenuXQ3u7BoDvCQCcigBQBbUjEABY + CADfhcce+wuGDIvgqquuwlh7V527cyAMX9+oHXg3TQYKCCzSxVi2fBlsw/v//y9+EQZHxyCVblHjsigE + iDoQi8V4VLiSjfZnAvCFklIaA4CnynCsmUexvQBA/pA8lPorENkRhvg/cTEPqW42Vs2J4sKcU2ZBTcqO + k6ZeGL0EexABYhRdyZLipauLExhIIrucLZUBz9OxPQgAgLqzpozdkx4GT6YAK+6dpfQNtEHX/My/oiz7 + FQVuZ5Vz6okBanFU9WPaEtXzXcs/H+QBpIAFRKuzXMgdNQnFI/IQGYtAK4JAansaYoUYk4bISCf7JyCP + 4VNqawpan23jchx1AFK8Too+6vN16U+OUdp35cIrUPbk2sSokacKxU7a6cdg9OBRrtnHMRyrotdByUG6 + Hh1Pd2J8n2ZPIDwZUoNDbekRYPq1zRRklhGv4OMVT/gPvjdiGrT0dWno1jIA0LMQ3nXOeYEdnwCgXhWI + AIAmcP3x4UcYHIIBGKgk4BVXf+LAAcD/ouG8jQRAXv/6N6B7shja2mZj7B+Bu+76DqTT7Xj/mw1hQWc1 + qQrw97//GT2GftYFHBgYmAIALyQI7IsHMIAeSCMALKJ24B3b4fNf+AKMTtBosDa+Ig7pAqL7Hw3HIRJx + jI4/LUAeCQ6BScEAZqadEuNwuU+gNLfE2f38YQVOFiX+loT4+gR3CNIOU4mXodyDu+JL81Brq0BsTRxi + 6+Pg7HHAHcHFm8cfLnl5ZqCo+UxL7cjEAuRPlgGlnh7zZSvSD+/znvZaFEjYkgfwxJpNbgN8AKjTBTAe + h+XnPEQFWekceIruCjI7UCsk80n2uMZPnZJuKxr5sjx/XysJkH46BekNLRDNx5ipSPX6XB8CwJwCtDyX + gQx6CFSTp5g7XAirkebMTXKl+SmkGppAOyCeX9r01A5OmXzqLyh0FWGidwyGDx7hsCA2GOWyKyX5EoMx + 6FjdDsldKXbxqYefmpqYKW1XGeCph4PaubnXoWYZPkJdFUbi/iAAaPjWiVgimNFgkPPPPsdfn5TmaeD7 + EwAQD+BPj/6RB8oEjJ8+mXoBrrzmEx/LHhAAOPHEExkAaC7gSSedDD09/RgCzIV4PMyJvnS6A97whrc0 + AYDbDABcfvnlLHLYKMjxYht+UA+gGQD0L+qHHeiZfPZzX4CRwjhkWls5zg/jhSIeAM8QCDuqTONq5Swp + PYlLLtahNiQOAzDeS9ag0l2F/KIc5I+ZhOrcKsRWxREEWiBMSjwYP9ZwdyrNK3MCsNZWg/izCADP0vSe + EHhD+D6TaDQV5ePreN3T6e+gnL9i5nCJ0nP88IC5QCE/IadHnHPtnEaSOdp1l/MUDtTTg+xUuj/kj8XS + c/gU/94DrSdoBUaVe9ov5iYiT/UhoHNFZcDCwRgWdeL52BaD+NY4a/zRZ1QRACb78yy0SqXC9Cb0DkYT + nA8IlYT9VzMsZiWTXpMpaZ4SbLE8LZWmEoE1LQ3WUYKJhRMwcugwgwKRfKhbsoIgQKKlbeszkBxAsB+N + c3uvV1ZlOVfH9PiFHGEb8mCXmmU8IVZ3DiTwwNLeoZIX86c442twXS1aiADw9nPq1mzjbAAFAMPwp0ce + beQBlAUArkIAODA5AA0A5AEQAMyd2wvd3T0MAD/60bcZAE466a1TAOCOO77NANDX1wdXXHGFAYDn0xH4 + nxq+vpEs+O5mHsCiPvQAdsEXrr0ORvJjqgwIKolJcuAkCEpDRBi0JH2gd2HNtnPF1bMlScbDIxK4+3TW + oDivyO2w5eUlCO8OQRy9gPBAiDPIVKsuzq6qEiACABl/fA3GoKSsO2xBNY/xZ7WmEo5iT3VJOskB2Cbw + FqfTk9HWlgywlJ3KlvDMtdQXUePONCiIsQZ2fAYDx68g8H0EGiHRITRkKOCSHzEA+ZP0DHMRKCVSDUmf + k/YhSYmVlhWghoDoYBgQG0AvqxDh9uXSbDTSxTkG4I4n2nioSCQfFW1Fqz4sESAySr7CTbAtTxJyYqD4 + ndgLQFDJz83D2IpR7g8I405Pwq4UsqU3p6EFPRFS9mFmX15l91WrskquEv2btQNromBU1edPXQsesFIB + 6czUm4TFr/GzrsCy4L29C+Cd73yHWYesM1mdCgDcDfjQw/UegMUAcIcCgI8fGB7A61//+gAAnIIAsBC6 + uuYJANwKLS2d+wQA8gBejBBgfx8jABjYubOOV01x/qIli2Dz5u1ww8qVMFqYYFVg2klt2+HYn+YDEBDQ + BQ7GdDpRJvZmwEHPlyOaL8/7oxgf3d7iiiInlOL/SEBkS1RN50XjYAA4Mg+AO2T8iTiXDEO7MQzIoqHm + a2aUmJGrNmupPuOuEoANF1Snp2VR1rmr6ksIhVcZbPA9jbuvgSbg7nri/RhJcs6LWIH7NKBIWEJhAPUi + tHncllw6NM+ASIq8yW1JdPEjKls/pwi53hyEERi6/9oNsb1xxbSjNmP0mKgS49k6069ifA55wBU9P6WF + QoIr2gDVrMQaS3nlZ+VhYvkEFGchANH3xvMfwt0+vSGtjoP0AfK2mu3nSQLVE861uPY8H0GPgvf80eCq + QuSZv+1aoIVcVwRw6VFCefH8RXDRme8U4/dLgY0AQEzABh6ADgEUAHzy4wemHdgHgE445ZRTYc6cBQIA + Dvzwh7dCJkMAcFrd7hpCo/nxj78Ljz76ewSAfi4D7t27t74b7wAYvr7RbMApAIAgtWjZYtiybTvctPJm + GBoZx++UwOtbY3AgrcNoFL0ARwGAqveIKywTgPjyORL32soFZTJHVE38JR58sa8E+cNx0S8oQfwpNHKM + fWkqD9W6ySByx+Z4Wm/8j+gObyQAoFIhLvYChQA11lkwoYe5WA2Xy5rmvkCcOd3r6t7T0tl+P5atO5fB + 8qC+OSrxZlSF+VdDOEB9ATy2vATlwwpQOKaAhulBYlMSErvi3GhVQje93InnaDAOXY93QXQwwQk5agBi + vr18Hx2KsV2GQDwfT2+yCACeIWwRM4+brloKkJ+DHsDSCRhfMgbl7hKHFKktSciszUB8BwIAVQAKktgk + 110SvFrQ1dVjxEE4DlCT8eC26blgD0vGnWu2EhdhSCmZx4OHYfnsZfChV13mhwzQHABGR0a4F0ADgJxZ + WmkEAFccMAB4wxveYADg1FPfArNnEwDMhVjMgR/84JsIAF0IDKeje69GtFCSiQDgrru+B4888iDzmikE + oKnCmgnYrBT4n/4907/zCAB7mgBAP3oAVAW4eeWXEKDGIB5NsZEzFTga4d0/bIW5fkuGodxnz+yQnujo + gau3Zk8tDGq7TVosF1akRpgjclDCXc8ZDkFiVQKcUXwvdJlLy9ElPqoAoW1hSPw5waXA8F6trkMThhFE + 8Lx6rufbl4iC1F05vVNDg5FbU89Js/M00/37ZA7qu2xTHJTSmAIUNhwSIInjXd2KEDT5shxUF9b4uya3 + IOiGbSjMKoIVIeWgFuhc1QGxkSiXTEkRmUeYgSq9+SVAf0qzuumJzWJ8oHQPaIBLlTQcKRHYpyoBE8sn + IZINQ9tTbdCyLoPhBnpmI2peoOUGeiHcQM5FU49BJ1pFJFY3XOnngAoZOH/gqDZrjtYouZwIw6K5ffCB + N15WV5JuBADiAXAS8JE/TnkMbz/Cn8s/+smPH5hmoCAAvOUtp7Pxd3eTBxCC22+/RQDgTDzQIA8gxADw + 6KO/g7a2drj66qthBBGNZLk1AOhQoLEf+sXwBigE2CNlSH2zpRtw6+ZtcMNXV8JgZAyS7Rk0PBdCuAMQ + BZjCAGIEUhcb953UVPacNOPYCaDaGmeFbSWZpV1QWQy1FrXLF5YUIHdEHrzOKsRpgs6mKEtgUUKMxnfF + /oWewVMIADS0Y28IrJxUHAhkqjVusfVE+ZZ3XHHr69h/2iVvIPhYsmCnXHDNHtSvneb8TXdf05UT4ALo + Mp0nAMB5gnYMi2iewKGKFkzVjfjuKA8bKfSUMOZ3oP0fHdC6OsMDRaj8x7qEnqo46HBG6YD4YZipimjh + VH1cVAmIEAAg2FKSsWcCsoeMwdhBWfzcOHQ80QnJzSmIDaHxj4dZbwBktJsdaJDQzEur8UsHPDPdps3A + pEusfAzCFcH/h+0wGncPXHTB+XWnsHH+n64CcDtwIxPQslgWHAHgwMiCn3TSSQwAnZ1dDAAdHbNMEvD2 + 27/BrEACAPUlNACEuUT46KMPQnt7B3sABADNkoAaEPZVHfhPHtMAEDzR9HkLF86HTRu2wBe/sRKG5mUh + M6/VKPASHZh7AmylQKtm6HmsesuLsap2CE/P6KuJAdDvmmKiqdHfuPioP+AwpaMf3RLhMVosrLOowLFx + 7EmS1o7xGO/QHpkGTPV3V5SIidhC2FURO3ckiy+JQLML6mG5huEjRi718brdrK6hoB446rj++qlW4HP8 + idz1K0i/h6dpeSDNOR5XEtwMGuQCGVq6rIL/rkBkLMTsyQqCY2JvFNr/1Q7J9UncoaOs2UfNU7wrB66p + 5wU+XPITlhNwkuV7sr4BVRiIC5DBMKAnB6MIAIW5eUiQ+0+lxl0J5iWQlFuYBrC4vnGbc+AG/g3aC/F8 + bYbA44azoY/L0uVTj9ccDQa55MJ31X2fZgBAVGCSBKtOnRzE48E/+qlPHBhBkCAAnHbaWQwAXV09nAP4 + /ve/Dq2tszA0OKvBA6AS4XcwBPgtewAf+chHmNmkAUAbabA7MAgAjR1S/3EIMA0ALMATvXnLFrh25Q2Q + tXLQ2tHGl48FQSJo/Pgd7ZDq1yZqK2e6KbsryTBXd83Ziuttyl+0+IgDTpN0cXGXOigXUIDKQRXu7488 + R43oFpTnVzkBGFuLu89zlP0nHUD8XBICpbZhAgEaDsnjpVUiicVItAyY7FSamMOJqIpKPln+SfBbdrU3 + oMGjAgYnyFCULoBlWIDBMpgFAa9BY4cdWPAGMIQrqDULxBWm/ocq6QPMq0JlSQUKJFLajrt+NsIGSopH + KdyNiQMQ3xxno6T2XFvUizXlLghknuuDmAEtDUqi48oCqVEEGBo4On8SRo4Y5RJgam0aUjuo7z/Bsm2U + mHWqtgGuuiQoaEzwcxuN92lQqIvALB+UmAiEGwoNB73oHefvEwBow3w0oAkYgKVfgAKAAzMa7OSTT/5J + rVY9u6urG04//WxmAXZ1zeEcwHe/+zX8NwHA2eJeTwWATKYVPvCBD/AYMQoBZmoHbvx3Y7jw7wIBJQGb + AUBvXx9s2rYVvnj9DTCezUM61cKLlToFw6CSgAQEShjDYoopG5IwAzlJxDkAZnub0VTcAUbtoTSgI+Ny + iYsEMouHIwjMrnK/vzPqoDEQUaYGsafx0zbEeHAnT+2t2WoTdc0Wr5TBZSex9KLSI8ZdPy9h3FfalaRd + 1dILt6r0BWWSKMehLCTq2obXoNawEt5U7EHFSOQaO3sYjupPkLIXJUzNjqd7JQLhhRr9R9JlNAgVXzqH + ZgpWIHdMDmr9JfWccI1Vk1pWt0J6E+7KO3D3n8BzTzMAK75ysKflyCxl4Rpw9U5s6vCaD4DXjGYN8MTg + JIJOTwHGlk3wfanNCYgPJJR0d07LpIMK6Ywj4/nVD/D89/XqDZu9j4YqjDIq9TxWkcIb0en7EAAuPvf8 + 4JOmDAAlAKCc2Z8wBKgYD0AuJMC9+PPhj33qE9sOFADcXa1WTlu4sB/e/ObTIJVqxxBgLucAvvvd/8Ed + ngDg7dwOrE+QAoDbGABaW9vgfe97nwGA55sA1P/WXsF0nsFM/9YeQDDxwpJgi/pg4+YtsPLmm2ECQSKW + SCoqsKW6ASN4wRxH5tjpAaFSj1blP1fqxLJR0v/kOdwQGlWLvtJZgeK8EhRfNonxbwnswRCEd4R5gCcp + CSX+jiHA0zEI0SzAcWC6KV0Sfg9bdO70+Cvhl3NNPhK4cloyjA4kJNl8W9XjdU3c7NiaqqvpzaD4Qaqv + XurowhGw9CljB4/eK6S8HXoRA4pt2qO1EXDPvmf7ZTOdDY/hN+I8QA2KBxegdEgRKvPLDDKxjeiSr2qF + zPoWiO+Ms2QXze7jCUDa0MTA9WBUV3sFuuIA/neyRKCEevPdcBXcRA3KlJTtKvG/qSsxMhpVvQZlFXJp + Ypf2dEw1xJHzqr8fyPkLeBsGAAJMQF0+1tl+UpjqQ+O++JwLzDrkraNWjx6UBBzcOwh/ZibglLkAv2EA + +K9PPndAAOCNb3zjb9BwT1q8eAka+umQSGQ4EUg5gO985ysYEsxGYHj7lBCASEIaAEgTMAgA/06iL3hf + MERo/Gn2GgaA3bt5THc9APTD5m3b4KabboJsbgJiyZR6ja3Gg9EAUQYdy/ZjQd3q6Xpm2bmmS80z8R7F + 77RDUw2cSoI0N4CTX0eV+G2I8VfrcJmtF/8T7karouDsRc9g2DK1aN10RMDl1nTWGRT6uB63outSJO9C + 4jBwtUKUeUCXLS0Z8uHY/oJ2PKPiw0k0R74Pk4CANQOVO+9xSMMYGBidpROMnu3HvJ6U5Tx5r+BEIx4v + 3kpioVWo9qAnsLQEpeVF/ozYpjikVqeYmBOlrrwcnouqI7uymkmgwZfDnpq4/q4a7qnDIL3v2tKTUONz + 46pGrShJsVU5lCMeAsmME9eApyS7fjlTeRlKZswVgpWO7hSYeb44rDZLK8Ck1BUZzeAEBVbkUfYt6IV3 + n/cuH1ysqSEAAQBpAnIVYGo78O/w53L8WYMg4MELdJsRADB2P2nRoiXwlrecyf3/nZ0UAoTgttu+hAAw + F+9/R50gCO2aBAB/+MMDDACXXXYZAwANDd3fMmCjwU8HBkGDbgwZ9I3KgHubAEBvby/zAG68eSWMTo5D + KpMx7iR5AETcIMYgTxOy/AurL7Ln3+FzZizlKlPszv/GHZ4ahNgLWIIgcEyRh3VQvz8RhmiIaOIPSQiv + iXASkKYBe2VPWnYsw3YjN5JAx9UjrMlRd3xSivkJ3nQEYakFraNlQiwOExzlSRi+vyTAqJeetQAd2RVt + SbJZ6jFVkrQYS5joo6nJjpI89zSwSF7AHy2GP2mPqcAMAMvxfKAXQKScxHNxSKxLQWw3xv/ZGBOAlFGK + DqNn1/HtFR3XCmToJVkoWoEqTJIpUJ5PHCL2H0uel2weMWbTpKGKJUleUINRXMOdNA1WXlX3PIDP/SB2 + oGZKej4QmryK5V8X8qpoNmBv/0K49KKZAUCHAH98uKkewAP4cyX+rEUAaBJ4vGgAsJSTgKQARDkASgLe + eqsCgLe+9dwpOYAf/ehb8PDDCgAuvfRSKBQKUCwWm+7eMxn2vv493XP0Z9DvIn723p07JYb2AWDBgvmw + Zes2uI40AQuT0NrWoXYSvJAOWjGFAJQEDNJh6+xLv5+50H69XgGJx2QV6kqjIaDl/iIUEABKh5SglsDn + VV2IbghD/NEki4E6oyQFhkus5Jnvofvw2VVkT8D1E1FilKadt64kB/WZbH2oulSnWXvgP6Zq3ZbPfNMs + Qb2aa/7r2dUOvN7cLwlGTRMGCT9IoZgSjZB0uTJSm4de0YoS5F6Z4wRhelUSEuj+EwOQ1HlIbdlPKHpm + 9JknYh9a34D/1seoAcnw8nVZUqTCuVlKn1swwqacAxGwZdP3pNLg6QoEcD6EAFg1QAFrAXDXIKjn8edJ + J6Wlz7NmCpJp0HhwzgEshPe+62IfAEBNigregh4AJQH9hC7/9378uQJ/1h8QD+CUU05hAFi8eBkCwNvQ + jUlyDoCSgLfeejMDwGmnnTcFAO6441vGA7jkkkumJAEbd+p/J7u/r/v0/SUEnpG9e6fkAHrm98CW7dvg + i9evhLHxPHQgAIDEkSHc+SOhCJcDQaN5sClH1389adbhRWGCREMOUX3lwEy4Sk+Rd7zCSzH27auCkwV0 + /+MQfTIGzvYQ2Fn8ySkNfnP8np9lZ0+g5vpJN8vyS2/GXGa4up5/TgwoWIHX2VDvSVgNjwdfD/571r0f + NPw2n63OK4mF0shwrwN/99Vg8jUTTItOPpWC5JYUxEcSXJcnALACYYUhQFlqjqBJzlmBJCADhApF+Wsw + aLjyeouJQUYPMaRyLNoX1XRiS0CCPC76m5iFMk1OeiBA8ieW5n6Z10NgP/Cly9TEJs6rhGxY0r0IPnzK + ++quWTMA2DOwB/7ypz8ZTcCAid5vqRBgw8c+fQAA4E1vepMBAKoCRCIEAHMQCEIIACsxHJiH97+zDgAo + 23nHHbfCQw/dzwBAE4LJA9AhQGOmfyYgaBQSbSYs2jhiqfH+En72KLpUUwFgPmzfsRO+cP11MIYeQHtH + p2TelQcQtQUAAET0VrWkqqyuWoSuWx8aWBIbaooox+Mxi13fSmcZiv3o9r4Cz8XRRYz3bUj+KgWhNRT/ + Ozxg0y6pnVOrDtWV3Dw1dEVnlS2TEg8YMATq9TNc7WnpxNZ+Pj/4cLP8S2MJjZNpqk3Zi6vuQJjlQumw + EgNkbGuM5ynGxmKcAFR8DDDVDd79a365UZqRVWgkCTdwtVyJCeRB9M4VkNi6WuMJ0UeHEYpvYfoa5Hk8 + 6NZ2TSKQ7zcdmZJkFSl1FQYFGIE6eauvDnlr+D0XdffDR97wfn8Ny3cI3hoAIAjHdKMQ4MMf//Sn1sML + eJv26p566qkCAEvhjDPOQ8OPSQ7Ahm9+cyVzAggAdBWAbrFYnHsBaHw48QAuuOCCOg+gMQfQLJG3v7v8 + TIChb+QBZBsAgJ6zcGEvbNu6E6798nUw3DYKmdntSniZ40CSBAtxmUvFlqovnGJB7eKSbbMseM3PCPN+ + TdlxVylEsDtKri/3B2Dc21OB0pEYBhxRABvd/fhD6P6vVXMAnAmLRUM9N5BfEEMySS5LSZPX0WDp+0qW + v9HVD95nboG5AnoRmt0+GO4ETmMw065fGxQbncIqbHh//lN2WaDRYQn8ow1/z1btyWT0EdLbI9WdvK3c + cgEeBkO7/r2DXolRa3I9IwraWLNXZC7d7uwFxov7OR3LR1D/+DXJxwHTAqyTjTocAUvt8LaWJrL1dfKT + hUQJdsI29M3vg/ec824TfXH/gDtdFYDKgJXGM0oA8CEEgANTBdAAsGTJcgYAapIhD4BCgFtuuVEA4Pwp + APCTn3wXfv3rXzAAnH/++QwAjUSgZjvHTB5Bs39Pd1/wfu0BeIEcAANA30LYvmUXXPeVG2C4dRxSJAlG + F5ey32j4Ns19JCagpIAV/1uVmHg9UlKO1oalxULkEtV0FkjFmDpmJmGMGpXB5legOqvM0lKhzWHuAXBI + NpzmBhQsqccHyk41q64t2BK6qto5LBGlVPFqcPfTG6BW6DHEHM1es2STDEwXqmMBBsaQ6x00uBSbqwM3 + gEEwDyE5BdYpiODfSfzdohSaQ5UQhMp4LioIhCUFAMaTg/rrZu5rYN/R+SDPTTc0KS6/X9evy3XA1NyJ + 1hHQCV4OB2ras9Pio7r1G6RHQ0IHBhR9wWRz8Ky6WQzUW9KPm86l777IwClAcwAYGqRegEegUqoEmE78 + Rr/8y9//+pF7f/XLLYGX/MehwLQA8OY3vxkBoIwAcBCcddb5nOHXRKBbbrkBwWA+AsMFDQAQYw+AAKCl + JQNnn302P9YsBGhG8Nkfj+D5NLRoD6AOAPDi6sEgN9x8E4wV85BMp9iFh5AtuQx0+unviFxwLsNJNlq0 + 3005jGyKyD+OXvFyUW2ZVKOz4Al8JFPlCbp8Q6MPjSLYsBCFV6/9V1NGzoBDIQW5u/SY0JUZAGRSLru/ + ogOoSDkKkCyRrmYPRmr5zAOQARu60qCTVxAwMEcIQ6bUB1IV0F+R6Aq2JA1lhVpalUiWpUriaaABkxfh + 18bwfvQkSYCV5MEdVhlSzT+kzmt0jfUlDez8QSquJj6xG68Tpw0A4O/c6hi4x98L0M8bQpZg2GUkx+Rg + jAqw62lEmGKGftHIF3QLRRAAFvTCey9+t4CJQuGZAaAcQF2+WPf86a9/+ciDDz+0nZLqM9yeFyjsFwCc + ffa7IIJfor2dcgAWfOMb1yMALEBguMDwAOhGYcKPf/wdBoB0ugU9hNO5nEYH3GyHn44dOJO38HwAoIyf + S+2V0BACzJ+/ALbv2gU33rQShsfGmLVoLjLlMkIhHgxi6fFNphXVNaQZqFkmQaRlqdQJFb1AkeMiV5EE + KWkKDtGDeXgmPb1sMftPy0wpuSswbnpNtcCpRa6TgQ4EYlYwBkj/d3Qmv2bVxats4ELW8diD8KQaYPml + LzJOoQfT8xyZSuTJd6dR2HQKbQ0k+vXVhutY1fQcMRZLnTI9PYhBMqRAgMqtqtSqPCkaPOuQ3Jd4LXqY + i5FDF29Cf7cgU6++dVnCMpPl81e6JvUEZxlo5WT10kAOSbMtGVAU2AXxwgM/9DRmJM8xuVDJ+IejIVjU + uwjef9GlUqlwGYw9b1oA8MqlMpiPUYd89+YtW6786d0/3zY6Ovp8jHzG5+4TAJYuXYEAcCGGACGm/5IH + 8PWvX8cA8La3XchJwGAIcNdd3zYAcMYZZ/BJ0mXAmQg8M3EEng8QBB/nEGB4uO5L0v3zenpgx67dDACD + 46PQ0dmpFg0x/IgOjGBH7qlajLIo3EAZyVPxvhGp0O45X2/X37lcvVg8jn/J+Hl+ngAATQDm3Vp+DJEH + /IXuyZhyvbtSJyLP9iND0s+l+jbnAmxFXQbP5AbMTuzIAArLNXMCLH38jspnaGBR+QAxdFC5EFqs/Fsb + EP1UbRNdcN28FmDjSRelrtErtp1fLLctdPstFVKh6ePfUaW8o2n5NZkFSOQfXZ8Td1z3KLjSgak7+FR+ + RMDUWKKcO8v1HTTt3QSBBerLm3545BmcBRn1xYlAfY4MuoB/jAJUHCpQ1BMOw6L+fvjAxZeJ9+Y1BQDm + AQwSD+APbrm+GYhO093rn9tw5d3/d8+27FhTUaB9gULTx6e1ore85S0GAM455yIOAVpbu5gK/LWvfRFm + zVqIHsCFEgKAAEBMAODnCAAZeOtb38qGTSFAsx1/X40/ze5rNlNtOjAgAMgOD9e/J168np75sHXHDrh+ + 5UoYmRiDzlndisAjJSCqZnAOIOAf1p+9AB0U5MJrrYAAcchPSfl0Xs6GW2o3pSmyhkqrBUYtz8T6QUIN + L3DZgQ3TL5hwYzfblsSU7JK2+vFs32iIGafJPSaEERkvIgDxIFCT1bYUOPDnCcFJZg0C1+SVPj7I4bKr + 4Ygqjqe/v6xfzzPnSemshNj7cFyhelsRDAHkOokAJ68ZPRK86ikwYqqxrY6x6poeBp3sszStV4cx+jy5 + DbG/FUgC6uGi/D1Vzd/TXha4QqmWkMeV59mWwTNVZdBv7YcGekgIzZmkZqAPXXKZuU8/HrxxM9DwCDzy + +4c0AOhvYCOY3HP/7x644i9/++t2IRDNZPD7/dg+AWDZsoPh3HMvZgAgGTAFANcyAJx99sVTkoB33vlt + +NWvfsoAgO+hCDmBECBotM1c/f1hBe5P+MAAIDmAxseJB7Bt52744g3XQzY/AR1dBAA1BQDMaKR24JBi + xDW5UJ42ejl9ulnHlAUbJvjIijRnvq78ozvbXB8ugq/VbqQhkIhSsdnJAlcyyGCr6+ADWeReg95fMM+s + 39eyRTnY7xewxCvgGD6sd7iamjNgizdCz5bmJUtt64oLYek6u8+RIACizksq4XEsT6QpSr6yt2Obmrul + bViHYCDXXQ0I5D4GPpf4RLuq8h0mr6EbnWSnZk1/w/LToQmo/IkL/nmTSo8K+ywZ8Cl9FLa+VOIJGJDx + ezW49q/p4ZIoJFJZX/9C+OB7Lw14Js0BIIvu/cO/+30wBOBgynXde35+z91XPLHqyR3TGPN0Rj/j/dMC + AO7eAQC4hI2ipaUDASAC//M/n4fZs3vh7W+/ZEoIEAQAmirMhjhNErDxd7O/mz1nuvp/o7YA5QCylANo + 4BD0LJjPIcD1N94A2eIkZNraxAPwTPzqUEzq2E3ZgBoAgrFecAR6sBGkrowmL67TGdQ7f6DWrV8XTBKZ + 76wz8VYAKIKJLJ0W0DwBbbxBll/jsgjkLvXOZunnGM0/5YpbUiFgY7NsA2x2oJTmNbyPpghrySwGhLDD + 5TGbDV9l2Ok+6kNwQUIhrs27PrnK9sT9Vp/DiVam+gbLeKpzUHUmBsoArtUgkOKq8p8ZqqLA05J/a4EQ + bfXcN6BcIOXouOr5nk7euiopaevZkTJCnu/DzXNh3wL4wHvfzRwDfW4buwoUAGQRAB5EACjpK8lH7bq1 + e352z91XPrnqXzsCr5nO2Gd6rO6+/QKAd77zUhbMTKfbeDDIV79KANAH73iHBgD1GgoBSDD0l7/8KecA + CACCOYBGFaBGg21GFDJrdD+rAsF/k6jCeDbLTL3g62k4KE0HvuG6G2F8b5HbgXm4Y0gtMEJxyhQTctsR + qM/2BuJH1anmi0QE3XWTpJIFD36e0B8yUvM9BZNxDuzs/BnNdPqaXLVmhB1f7EMjhOW/1ms4dw0ei9X8 + Q+pf28AgNOw9AL8ZyOxhIIKZ8lHkBeCmQhuLEh1Gjyuskho+mNoMAIqUY6vWZK4maNltD7T6PlGvVXVG + NPocOe/BvgXt3hM92KkqUKMPclwJhfQG7Rk5dMYFRzEHVcuzXQeQOlGqwx5bz5DkaowCBeot6Z/VB5ef + 8QE/jxH4nhAAABIF/f1vH3QrBgDUWUa3/z4CgH89tWp74DXQ5O/n89j0HsBpp50WAIDL+ELRNCACgC9/ + +XMwd24/AsC7AwDgGQC47z4CgDQDQLAMGDTQ5/N7Jje/8d/Bv6mnepIAoIkHsG3HDlh5802QDdFw0AxA + AViPTzWi2GYoCKsEuY7q1RduOt/Klp+9191gQWJQSFzmmsr6i1XUqeoEST/BkpOpCFiBRaJ39YARBq9g + oyag/2fAg7GtKcthCguw4X3NIVoNz7OmXoeGN67/7OCxCRhauKk4/IPnmHdKxy9PyrG5AUDxx4A5ZiiK + Fkjhzdz1BAAUMnnyAhPGSMLCC6Csmt2nwEw7QVrXTwOHZXnGI6mx7oPrx/0CEmpSsKuCOEfHFyopa8ct + WNK5CK4+8XIw/RUwJQTwent7rYnxcfjtrx/wyuWStH6pFVOpVu/DEOCqVU8/tSNwlabb8ZsBQNPnzAQA + 9yMAnHzQQYcyANBJTaUykExG4Utf+iwCwCI455xLDRWYbtFohLsB77vvf9kDOOWUU/j+6cqAz+d34337 + 005MAJCjjKkRalOLYN68Hti2ZSfc/K2bYdf8IcjMa8ODVN1jROrwqioJZAdYY8QQpC4yT0+H4a8thkoV + AU5cucql5EYQRWElQKnpefbkiVQtGd9lGbopLwR6P9cfOc0P1MQ7twMZcJMbANPKGxwcEmwkMruvEwgJ + jKsPJnwItu6ax4KalGYfgnq6cTNvotmKsgCaeyg2i8lSxYWZACFHHxAEZbVMLiJY2pOToUFBE6gs4/r7 + GXpLQhZ9DrSQip7xaOtdXcDE0HuNhXt1IiysAMygIF6eFBj4NDpqQwAZHcdVirjNScDLz/WpwI2hIAgA + TE5Meg/86n5XQgB94pxKuXL3L+695xoEgN1QL0Myk7HvCwimDwFOP/30n1YqlbP6+hbBRRd9iDPjyWQL + egAEAJ9hADj33MugVqsEQoAwzwVQHkALdRTyhdmfMmCz+P75JgCDf9P7UEslAYBaK36egMqA27bugBu/ + ejMMuiPQMbuLS0rUbKJILi7HkGqqi8VEHlv3BsjOYjs6uy47EC9QJcFFIMFiD56fjbZcpfbrSWmMa+pV + NXmIef6uei23mWodQE9ZuqVBRSoGrgzoYHdTutU0g42BtqbyByZxZ6vj0Co+Bvr9NEFAAbf+MRM9CDlG + lx4bl1JwAnGwglHnSXgBEJOdkPOFtgoH2APQ4CUpO019Vi8PrOFA2AHymAYNJX7iqWsIsoPrUM2UExmC + QY9OU3kiW1f7BED18XqK5GnIVwLAjjox3C7syrUOtE1rR4NK6P2L+uCDH3yPHy5OjcgJAAA9AO+3v/6N + K0lAc2WKpeLdDz/6yMf+9tjfd6NdBlO4jX833jcjEMwEAP+Lu/vbZs+eC+9971VM8onH0+IBfAZ3UQUA + mghEJ4S0Amg24L33/sQAAC1E7QEEDXg6AJjOoBsN3sg0zRAWYBwFeXSpIPg8PI75C3qYCESSYCPD49DV + 3c319Zo2WvpGISX5pJNtvEuQwm1YJcJ0okn3vEMURJVG8kriJmqOuCVBI78vLRpwRaEHeEXVpHmFk2GU + XKpqg1SiGMYwJb7UNXbmJ8jUGj5OaVdVsl+yZQqLkK+Bfo+K6mdgigGimWupEprhMxjgsOoAhgAxaGCq + bTjgYTg6F6LBRA484MXoh/R7hkR8hdiA9P7qeun8iOXnT7TdNCYwg0u+bhlYJifA5VHX7woEbaQGCJSt + sVG7yvgNOFoqjNOOlgmHXP9QtD5AMBmsD4gqaIv7+uEj73+/aDu4jQDA/1q4cKE1ls16v3/gdzX0AALQ + C3ahUPj5/b994BNPrlq1p+bWPJhq+NOBwEwhwPQewBlnnMEAMGfOPHjPewgAomjgqSkAUAvIGkUiNtx+ + +61w//0/x3AhzQBANcsgADQz9n0Z//64+zMBgN5Z9P3zFy6ArTt3wBevux6yE5PQ0d3FoiFe1a3Prmvj + kQSmqhDIziSuIpcOgyvR9lQziK0MnZWCpXymjcNixRpXko6ywOhVIamxB+v82htxQGb+6R1Rdncd85oi + g19t0K69cds5xHGMwg55HY5ksNkzkanESo1HQEaXxKr62G0lpKF3T1ANU2rSsK2O0xFQqqnzwruzMChV + XkXOlygS2XoNcHnQUjux5QUy+QIynvAUPDA04+D39S+DXEA3cB31HIdA8lZ1BIIYvK4cNKQ6pNrDicU6 + 467/TON5up7vqXiSzObZgP1w+WUfaGaLBroUAIy5v3/gtxQC6MeYdZDL5X7+i3v/7xNr1q0dnMa4Z/r3 + tPftBwD0IABcyR5ALJZAAIgJACyG8867FA3cd9mJOUuCoQ8++EsGgJNPPplzBM0AoNFoGz2EfwcEGv9N + IUBxYkLVlhsAYNuOnXDtddfBeCkPbR0dCABVFRs2Jsp0rK0Xh8zgCxJJlIvvU0o9GeulDFAFiZ6JWXVi + KtCjLm69icv1qmIwcE2/uidPVgo8YCYB82OyYwdn+/FgDnkrfT/z/EnpyPHApAVcSagJEUiHHUH+PSdB + LV+YlF9Qtk09nSnDNSHkuK6UyMR7qilxDCWnJu24ntqfKcFqqc4qNuoQGj/fJ14Df6LlilahVjfSE479 + vdtX8xDDlj59BmJXQAgkx2J5RvBDf18lAwZ+mQ4aYnTJMwRzGXXKwFCvURgEB55G1YshwLvfx6Vlu65E + WQ8A42Nj7oO/+a1bKpZ0JMFCkePj4z+7+757P7Vuw/rhBmOe7gdg3yAB+wUAKgSI4s/0AEAnJ4TorQGA + moGICDSBBtisDDhTHN+sYtDo8u8LCHiZ4K5empw0CB4EgK3bd8B1118PE5UitLa1qoGcDT5kPcdcjk3r + BOpsNgS49xb4/fxyij09WSZI3Ak8r7E1FcS2ggniBtVpfXCy2P3PrusKpGXj1C9c6klQuytIwpCnbfOn + M/CFFKio1lnw431NJTZ9DypXYoHwAEy8r6k2fp5db8imvi5Zfq6Rk9svZTNVk7e5DyGkKHksi67AxRZJ + dHkuhzuWgInnn5+qPMeWJKDm72vVY+NZ6NeL0YOi5Xq8Ri3fSnTyFkDCuaDZeHXrQE8TqustkHVL37Of + RuVd+h4OBxrL4fqGAOAhAHi/u/8BAgBX3oOzUqPZ7E/vue//Pv3cpo16NJjOtswEAA2SpVOBYVoAOPPM + M+s8ACL5hMNR3Nnj04YA1EX3ve99HX7/+19ygw0BQDabnZIDmM7w97f0t78eAAFAOZ+fklikbsBN27bB + jTeuhLFiDgGgTRo0ZgCAJsfY7MZdfAEOAATWS/A46h5rTJ6ZDLF4I5raqz9TRmWZQ9VxffAS+yFoXXxs + SnPSX6AO2vI9CVvp//nlOMsf8uEJ194SSexQoFVYA4ZjQmtFmXUCvfjCEFSCm/7xU9xv8hOghrNYAMaA + zRPJaKsBz0ru4wxdTcIT/Z0DIQwnYKUpiSYOK5ffT/iZxiZPG628L+OPJbJknpB7ZK/XMb4V8Pbke4M+ + R5IjYg+AAOC97+VJwdPcPBkM4qkQoKwBgF5gjYyO/uKeX9773xs3bRzWVy1wZd0m9+0XKDwvAAiFIgwA + X/7yZxuSgOoWDjsGAEgRiHoBSORwf3gA0xnzTB5Cs9cF/yZ6L7EBg0Qgm5OA82HLjh3wpS9/BfaODmII + 0GUaMxq1A6a8Z4MnUlfLNYa7/7eg0AZ409zf+N30Irfq3sgHieByaJjmUzflJ5Cp5sfAMvLaQUAyBJ+g + PLZk/S3pY9CkG0v8av4U9kJ0Z5+8j6mhBxSXwkrolGnGtgIEju8dScQCBCYES6XGhAgQaOqRE9ZMDEWy + kpb2GDRVWBwaS3siWurcskSPAfhY2RmqeKLWLGCjezhcMO6/JbkUV4ctnDilEAAB4P3vZW2AadaISyHA + yPCI99Bvf6eZgOiU2AQA3mh29N577rv3M+gBDMFUQw8EYubKew1/NwWEaQHgrLPOMknAyy67kkk+jqMA + 4Ctf+VygDBicCxCC73//a/DQQ782ADA4ODilGaiZce3vrj6Tl9D4HDL8Kn42eQJ1AIAewOjYGPzq17+B + 3YN7uAowmZsE6rIqIGDERBac/h6fGOdEJpVBSS+wXKmogQ6Bj2zkdE9JyOnjAmtagGikEzc+NiPpxv8A + P4nZ+FDj64M7a9O3sgLPg/r3DH5OQ/a9jvwTfG3QdSYD1VN/AolBpgWDSiTyj2JjCVRYJo/BaQwvEJI4 + GiAkvhchUS0cSo08HHfz81zpdeCToroEeWGAKesGtf8gWE7UfRniTWiwNTwAcvertpIr57KvUjWmITNL + MWS+/LwPMvGp8dLr3wQAWfQAHnzgtwEAYA8A0AO4795f//JzG557jpKAjbt/MyCYzujrQGImAPgpAsBZ + c+f2wKWXXo7xf5zjl3Q6gQDweSECvdsM3lRNNGH4wQ98ADjttNNgz54903YD7k+5b6ZFPBN5SMW9uM7w + s2sBAKDfs+bMhngyjeHJGOSLeWhpaYGJyQkYGh6BIj4/gWBHt//X3pdA2VWcZ9a9771+vWttrQghIUAC + LLFYEhAMZvEEO8khMQaMPckwQ0Lm2FlsB+fEPknwsNnGBGzGSRwHOBOzOIlls2pBQkICA0YrWgBJaG3t + 6m6pu9X72+b//qr/vnrVdV+3hGRw6Drn9rt991u3/u/f/yK9SzW1aJsLABAZWi30f29vn6pIp/i6R48e + pXM7+HjMJwD/f1t7u+ru7WYQAXDAJYeqSFHcvzEY2cDRD0R8RBkEAx4XBxTFQB1brAiO+zpymjewxwcy + PieUqCyWyMwAECaimn+hEG3kYwlLLhOIIVLJtTQxF5NyzPFhMYjHdLT+AqGWLnQwllXfD4cZgyqnZ4c2 + 0ER6lAn20ZJRzsyOHUlbcm5BGx6TVUl1ztiz1B3X/aW2IZX2XQkAwAaweMEiGwDYCNjc3PLc/BcX3vve + 9m3NhYIpTll8+zjit4/xqQn52K984403Pk4D/L+PHj2GVYCqqmou2lBfX60efvhezgW45ZbbWAWwZwZ6 + /PF/Ui+/vJBLgqEgSCPp2gCJE5UABjL0ldvPJZyYY2cjqyuO4aCmunpVW1fLQRpaJdbEWlGR1NyDiLYv + k+X3Q4QauD+ArK39mMr0kUSQ1oTdcqRZHWvvAMvhayGAo6m5iYEkwdOLh3TMUdVJEob4pDu7uwhIMGlq + n0k9DlVHVycbTNEgSeFcgIZdOz6OKEsSj8rRbT8CtfrOtmArNaDEMdC3MBcddGMVwUQEcpagiRL0HFlc + i/Jqnd3imZGS5SJ9FIqTuojlsiAWV6P7W7VddEiwVA5nVSAfxXSwByavnaFsM5E5FIwnJm9UHZ5sJp1U + 0yadqb5205cZ5Dzgmcc3RCRgexsCgRaKG1BJ8vWhpqbnnl84/76du3bCCCgEPRgpIF/umHIA8K80wP8Y + hP8Xf/ENVUMcMwiQEVjD6cDIBrSTgdApuiz4jxgAMDswAGDnzp0RBz4ZAOCLFIwbiAwA9Hx5GwBoydLz + oCRzuiLNz6w92ohjqOBFPysKgyS5pjsaZgtOV1WpynTacICAy4dX0DV4SNH1srkM9UeGVAdIHcoM4ILq + IOmih4ABteIgAvb09pBIp2dN1imxIUQ8VjdkNON4SCS9vV28DUDU1k4SS1c3gYOewCRD9wJoZE3/Ajgg + gbjlpm0qC5z/bZop16f9SHAwABAdHN8KhkuK2M5JWExMYYkEoCnaMWjIauBsc26tLfrmXaXEmSTs2IbU + iGdKDQfrAvkSTSdyAkjUoEypJi5XmVyVDY/0zREJ+Odf+hMG/OJXCErkI44DONpaWLLoRRJce8VXwXEA + Bw8dfO7Z+S98Z8/ePUfVwERe7rdkif08N9100yMEALfB+Pfnf/43HAaMVl9fq/7pn75DADC5JB1YJABM + DLJ8+SIGAFQE2rZtGx/j8/PHuffswXSi0gCaDqvN6pmBbO8AbAO0TUJww1A+uan3lsubacI0ABQy+mNi + ltd0VYp/E/SuadqH2Agm9ABu0AQDiDLTS+F/GEaTPMlIyDDDUgYmH6Xn6evLqIyJPgRIwr6QzepnwjqI + G0SOp9OqxTECl27+lnjXrq4eBo5eApRMto/1zmMdnQQ4HfR+BEL0ft1dXaqjsxPJJGxdl9BsgI8KdO0D + BkWTenwcTHvgbzDoiwWRkVDGAkBOjxlfpShjyHNtJcryn8bduySIp1BcLV6k1DMjBG5LV/n+x0XzOChV + nDPQeFF4NqrJk9WXb79dVVZV6vcqRFeKXur0008PUA9g6YuLc70mFFhCw/bu2/vscwte+O7+AwfaVakE + EMf949ZNmJcycxzFNAEASABf/vJfswSAx4EEgKKgbkEQAYCnnvoxAwCmFYcEsGXLligu/f1KAAPt67cf + fwAACIu1PAdicIvsV5EIKLPLGHXJ1Njr68noYpLgSkljTCoUjCFdAnRCla5Mq5rqGp3UYsRNFBdFPjis + vzhXB4JoXzCID1JGBakO6cpKVrEgZWHuhYqU5hOZLIBBV6VBOgIAIZOBtKE4lDjHswZlSc3J83oPPSts + FdBM8YwAhDZSUWDkzBJI5EitOdbZRdLGMdXb18uyLYAIKkhvXw+rJVigwmToWLEVAjCkTJUEVhWcopZC + YAPSvVeyNxGBBgy4n8JEdLD9qcVd6zOWei2g7s0jktNs3MKCkueLrekQHeaoXMb9J+vKgBTGzemTTuea + gLU1NUYyjMSWCGo0ALQWXnrxRZMMJE7YIEGi/y+eXzD/gcPNTZ3KDwDluL1L/FlZj/1WN998cwQAt99+ + h6rjyrkB2wB+9KN/YACwawIGhptgZqDXX18WAcC77777gQIAVABEBEI8thOOoimkrA/db3ySgNRLxNCb + 6laF6oxKZCtUqqeKA1XynAKoogHEJezpw9bQB4YtIBIRjToho6KgBICK0hCDAQEE4iigaqCEFAqS4JeT + mrIwIGYZYCsqKvWxiYIGCUizhQRvr6xMM3gErDLQdwnwzrBV5FRXN4HAsQ4i4iyBSIF/8/ksgx3We2nJ + EpAkifMCGLq7exk8+uj9ARJQSY62HlVt8IoYqQTA0dWtgQPbMpBiCCTyZn5E/LJkosTo7hJSoKwyujx+ + WCoxYKCMeqQlniLNigRkt0I/Ki7fjs9ZK/dwxolPAnFvEOgS85NPNwBQW2ufXxKYYwBAvUQqQB+DM6rR + swqQ3L5zx9PPL1jwQHNLc5fyc/58mW0u8WfMb1kAeJQI939pAPgaPzjeHxLAI498XzU0TOoHACCAxx// + Z7Vy5S8jANi0aVM/vf1kqABx//erFgRxnwalG4BRzpouQbDQu48l2lR+UptKTyQu24xa/qNUVc8wQvWC + no7KEHfBuI8qOWS6UnNJ/VAlXgl+ttAUtaRtuVw+klpZwsC2vLZK5M005LwvDE0WGhF3nlMArTolJmcU + ufVJTTwpUkWqGIxgp0jQcyV1NiI/BKSQAoOILoOWpGcJWQ0JWSqBnpok4u5jj4e2KQA08tqgi76BzSOT + Z0kBD4bt3T19quVIq+rs6mbQAcB0dXcrGrQEKB18jTyBKtSYjq5WljD4XfPGbhGa0ls8iakWvENrfgZ9 + vuI6AiEH5uT5esoYEFUk2RWz+JRkEqpCEdgLxxetMRgPjW88SmMbwBlnqD/74z/liFrr+IK5Pj8ibADF + QCCdC4AoAnTD7sbG50kCePDg4UNiKIoDgTjiz5qlz1ovCwD/SAPwS+Aqt976F2rUqJHc+XV1Veqxx/4v + A4AuC150A2KBERAAMH78BEwuojZs2FDWXefrvJPhEYg6v6C5Iaz4g3K1KQMA1PXdxP1aaveq8PwmNWxy + UvUeIM789lhVc3QcF7HIh1kVCYjm3uBiEOdhP4jE2kLBWLXDSOXQ6bNhURx01BBlXVPAghOWABBZIZwC + BzthH8R2xCcANFg9AZEkNFGDs2ttGsQNCSMRzX3ICUEkeVQQGCTZPqEDvpLs+cDgzavq6mpVU1tPx1US + oIQseYDe8Om7egACOtYWoNjTnVEIYtOAaCzmxigJgu/pJaCAQRRp5DQ2u0jSaD/WrVrbjrHdIihgfw9H + kLa2tVI/411SLIm0HTuiuglctEShwRPvlzf9Expi5eCiMIzCrYsFPhWHAgd5AYoC+/6KhVwt+0GJec5j + K1CBsodbuViNkMbCtDOmqL/80y8ZVTRSYQrWmEQgUNjS3Jx/eclSAYBAvAAHDh1c/MLC+Q/u3rPHzQUo + p/fnVVHczxji77O2xRsBP//5z/8DcYevQeyEu2/ixEnc4QAARPu5E4OIKAsVYNWqX3LtfRQEWbt2bdnS + X+9HBSj3P5fAJmJASebAEMVxAUA+VN00IA9W71KdU3apsZNqVLKtTqV2jFdVLQ26mESQ8350GAKB9KHM + KxAFs6hIItDJRVZqtMWVovkIZCyad7Gt0HnDOXlh25e2AfCcebl8NJkowK+3p1fPzmTuz/0TzYQTDWf2 + SOCcHLt2czoUHrMl07tUECMA4SszN2Jt3XBVU1dDkgVi3TUYARDAkevrUyQxGhAsYJ49OpfGEeZbgITC + tokuPGMYSUpQcwBGsIkCvDAPBapP4ck6OqGSkOqSI+DIZ1Rn5zF1uOmoOnjoKM88lUrmCFg6VcvRI6qp + qZntJHDn4j3aj7Wp9s5OZl4JiR7EfXLZ6M1lYmSZkARSN9s3gnzUN6K6MUGbbyf9rlSplGCPQZbMKpAO + PE199X//mQHdvEiDNgCwBNDS3JJfhpJgfb2CRrA6hc0tLSsWLF70/fe2bztg4gDKcf6C6i/y96lSACgf + CEQA8CDd56sAgM9//n8qhATjwREJ+JOf/IglAHtuQAEAFAUFAEybdpa65ppr1Jo1a2JTgd1tcQk/cUVA + 4/7Hc4ITjx07Vg2rr1dHWlpU29Gj/WZiiQMA/iW9GgTVlNyvDgx7T42fUK+G5RpU5aEGFbZVseFNZ49F + juaIgyO/vbKqqqh22OqP3CMMo+0MEDY4hVZGWrGGdJEpSfaaBBY5AUUYH9q7oa8DMR46ZWCs5wWrz3EM + jtUeEVManaXqBIvQABLt3sypwOjkgfF/ZXN9xn+f1LP8hHp6rlSiwOpJjrmxmTsARlICkjoChuqqCtM/ + SVY3Ro6sUTU11QR8aXqGUM/jwjH0mKClhkhAR2bmeIp0EGbSTN2GcaHfVeanCZjA8+poazsBAqkaHSgH + DDtQF6knLWrfPhoLbR00PmCb0O5YlIjv6OxSNch3IWkIUklLawuPba5WlEwZz1GW3yth+oELQBnpJpCk + rygPpGjmAwCcQ/TwFQIAAW5rbJcEAtFYRT0AyQWADQAAkDzc3LRiwYuLHtq+c8ehQtHaOZDOnzFLr0X8 + GVWc5yneYHvLLbc8RIPhKwCAm2++VaEwCDoa2YCYAdidHFQG009/+oh6881X1UUXXazmzJmjVq9eXeRy + cRF7MQZC33rcrMFC3HCzjRgxggbVSDbIQUQEl9hPHzljgiuKxB4UrcCqyG3159AcsTfsVa2pQ6p6eFLV + Foap5LFqVejROrBtwnUBCVIAYgbES1CIrNxC41YNfwsc7PJlSpU+G4ObIX6+Zj5fXI+I33KFmQYpAG5F + OydisM0NT5b75o34XSLFGK6Ib4F9fL+wGAANAoYaAArn6ddQfh1eEBhoETWZDlSaAKG2Ok3cv5LoPMUE + WVub5mpTlaSepNI1JH3Uq6rKCt5XgOckrKD7polAA/aGAHehWnV2G2ZAIJE0RUjZ4BpqIOzLwnYhfZVX + xzq6VPORDtXe3qd6CDAL2Q7V3HxA7TvQoppaOuj9AAiksrQf4QjXg4ebGMg4AKwvo461H2NAKGgfjEmN + Vlz9eNrUqerPbvtTHeMQGLtNUQKIbAAkAUgugAAAxMFU4549i55fOP/hg4cOtVmEr1R/K7+t8/dai038 + UUJQOQD4Lj3cX+Mj3XDDF9Vpp03mj1pbW811/0aPBgB8sWR6cCzYt3btGwwAs2fPVitXrtTWXYfwyxH7 + 8Vj+tb4bsuENhspRo1C6vCoisozxp+/bt0+1HTmirfTJpAUBpvCEEF8JQITMAfKcJpvRM/9mAv2RbU+C + RJiJS5D14QQ/EwZ3Ie69LR2/37u5IOBIAjaxF0OMVT8AEPUBcQ+okejkor+vZicnlZQ6t14hqh5kxOVI + ZTFHYh9cnfmcnmId4n8qpTk8T/zJYIF4C1KraElAajDZggH3cTVJebVq+PA0g0qYSNFx1ay2kLBKagvK + edE3gErXBxAKCDySHJ8BCaO7N+SgLUwFV5kOWcHJZHR1YdhGklJMJtAZhUh/783k+RioPkeOtqmDB1tU + a5s2giaTxDBa96kDBwEQHSqfpftVFVRtTVJdcenlpgx6JAfamXmYGixobmoqLH9pWb6vx4QChxwKnCDO + /8ILCxf8kFSBDqVibQCusQ+E32N+xfJvnxsvAXzhC1/4Fn2cO7H+O7/zWYVZgnt7c9TR1STmP0qENlFd + f/0XjC5VLLj405/+WK1bt0pdfvnl6txzzz0lACCDH+vDhg0jMBrNRJ80hC1gBEPSgQMH+LfXJAWBK1dX + ptk3HwoSS0cERtuTCjvGeJciDgMwgH6dhetMqnXGAYBpFRwoVFliCxAiFn95aYy+JU0Yo1ZkGLS288jx + AIAQvGvlLhh1oa+7u0Tt+HW3IBBJx0xTZt4/IQVjURpNIvaU9p/r/ZJjLKm4dsn4AhOUVGzCOUkCgRDG + yjDPRksABQgXEuywuqQaPqyagAT5HiiFBpDXM0HV1aRUdW0NSxO4fDIFb0qaRP0kgaeW6RGg1IuYi4wu + Fc7TyCW0cTE08QvanVlUAbJ038OHW9R7770XBTvFAEDYdLgpv2LpslxfVBBE1wPYtmP7/BcWLfwhqTGd + qj8A2AY/0fd7VH/id5PGBwcAn/70HxAAnM3+4mHDatS///v/IwCYQABwS1QTUIgO04OvXv26uvrqa9S0 + adPUqlWrYlWA4sDobwOIC/mV7bBMQ8wfPnx4ZGOQX4j8SEM+Qhwfx4Pro0x5NxHAwYMHOTS4upr0zqo0 + f3ixqmOgmOhdY2XXRj4YwmBBh1ktV9BuMKlyLFw3sDq0YIJkQPjgRAAmIWZRlZTlHShRaez3tEZHiS3A + kgKUBxzsY6Sxy5FAkCP+PHaYX3ezVafABsMwjABBGXDgvja/XEQkmYjGCJ8PtcOu4ae0KxXvCm8OPBqh + uS7PM4ApxWBshBqS0nkeoqKl4MUhKaOyKsnfr6oqzdWwkAiXrlCsXrBkCBCi4xDVmSKggBSRzaaYsSAp + jsejsRUUghTniyAorqi+W75NSwJoOtRUYAAQN6BWAYJ3Nr/79ILFi/61rb29W8UTv4j9PdZSYvSzuj36 + Dt72R3/0R98i8flOdPR1112vzjjjbOb2w4fXEJH/mwGAz0dxAOhgWHIxO/DGjW+xAXAq6T1vvvmmDjc9 + Qcu/rd9jHRx1zJgxLO7LddnlY0JcQeDt7e38P9SBcePG8TnYB1DQ+1GlqFfV0TVGjhhBEgGLjHlNjEDy + IES1Y+is8GWzqymXLwlo0oacQlTsR8u1+ajwZF6mqObBGyhJAZEIwEj8lwEemIkyjD/bvHCp7m1zfNdl + KM9gfvP2/0r09pzOSvwQAUBBqRLbCBtAGYiDaOHvLPq76VORqoSwS+KANJroa0s/mjkJdRcW7Rq6UrLx + qhiSApcHMESFngJjKEroAqZpRHSm9LZQvi/AviLBpfE5B6Wgp5iH7aKKmFVPT0HtbjxsFZ4pflaznocE + 0Hy4mVQAdgPi6+YJREJS37rXrFvzb0tXLH+emFif6k/84MJi5ANACOfHklWl3oF+38Hbrr322i9NmDDh + HxHZddVV/01Nnz6LB8+IEbVq3rwneKrw3/3dm5noRbQ7dqxVPf30U2rz5rfVpz71KSa+devWxc4JYK/7 + tskAh3iPlF382qK+zDvY1tbGXB8cHpIBCB8AUcNhl1oqACi88847aseOHerwocOqk46n+3SSDtlBkkRu + 9KiGfGVVZWLYsPp0TXVNin5TCZIB6Q99c7Yts4UrbTg6wmrzDAy5SEfnyOGsjq7jsuAGvPRMsdpgJ5JF + loNgCuyykmSphAGASE8PZOJMmdyi6HEIokFfVENMp+m4gaA0VDcwgxzGwLwlXXzQrQQA5FeA3bx/whC/ + gGVC1k0/6MCqoms1GtiW4VX6T9SFghV7EblkzbNgHyz++Uha0pOgiuphB3iFRjURqT4nU6jrQ3g/R3iS + 6BBywFUJAJTU9zc2ALX8JVYBon2dnZ27V7z2y4fXvLV2c4atqF6xv0f15/y2xd/rA48dB6S/33bJJZc8 + QjdXn/jE1er88y8iFaCHCH+Y+vnPnyIgGEcAcJNJ9AnYzdTWdlQtWvQLEnXeZQCANX7jxo0lEsBg3IDK + DFZY0kH4EPU5ySb6iCGHnILwwdWxDsIH4EA6kPtJSi0stps3b+bEJLxPa2trLwHBpsOHD++h+9AYCitI + SiAhIJ0YMWJkRX39sMT48ROGjxw5YtS4ceNH1NbWJSoY2UOWGmpqoVLUkEhYyYAAoxXABhZh+K8jrgUA + YOLWGYgyVwFAoquzixN0uru7+PlZkjJcmusHkGoFcNWhtdkovDaqP6is/pI+LYk2DEut/uZY3DNnnkUI + sOxA+DUAQJGQimMhMMAXEb1JrS5RCSywiN7b9SjZ25UBDGfc2cSP/b3U5z3ETEQii8CZ6/nprMsgTBj1 + rdR7xAVWxT2sdK1BxCPgWB0FWJwXwHLncVfAC9BEzGm5VgF4jioCjMyBgwdfefnVV57atn3bwbwWh31u + vq7jJf6y3/1jH/vYn8yePfvHGKC/9VtXqRkzLqAB2UNEPZy4/E8NANwYBVS0th4lbtytFi78hdq5cxsk + CAYARAK6ABAHBNKJ6GCcC+KX0EmRIkAo0O2PchZcL+v2IHocnzZuNzE67t+/X23dupUBABICEX/3zp07 + N2zfvn1jR0cHOgwpjnAZSOQNOjZFqss0ev+z6NqVMviw5PMSOhtwGjD2JbWPuIvW2wiESKKoDElKSYwe + NSpZV1+XbBg9OkXSCC8EYgCSkM4JKlKpUGcR6sHHbjqOndcAgWpEAAtINfjNEMDC3qJDc7PsTmP3Xq8O + 8slwQlCOz2VVxVIlJHIuNHPh4TyWVIQgCsoatKpUorC+ma2anDQAsFzIEcFaapGoRkUXngUAFsH7sk1L + chAcO5R7rBgjcRwKvKAPxb4kFaXYkErfAd8+ZYWW+8Zyad9pf38iUSxwYLv/zP8FGnfB/r37CiuWvYx0 + YOj/+e6u7t3rNqx/YvW6Netp3Hc5xG8b+7CvWxVBYUDiHwgAbpgzZ848FLKYPfsyNWvWxcyNiCuqZ5/9 + D+ocAMDnGAC6u1HMop315UWLniUA2M4AAK4Mw8dA9QDRGQnjNsMi4r4cg48BYoe4D4t+lo141Szmg/gr + TQUf3AccHuAAXX/Xrl0g/AJJCvTvwfeI679G+1BQoZqWGloqDfGT6D9szNixY8dMnz59yrRp0yYmLB0T + HBP3x4Lrox/oN0/A0rRnz56dTU1Nu+kd0Ol0WiKg5wlGE+HTNZNjxoxN19bVVdTX1aWqSCFME0DQ4Akr + SdqoIpWjYcyYCpJw0gQ2FbU1tVUkRaSqq6qSABFIJASGAUkYQplM7HBDog84/r6rm0GglwFC+/tznFas + k6AgSQAwuDxaVrsCkSIMgMGxIjVEee3mm7iTs4oEYYvZ/sE+uBbZAKzrRqJ1ZPCT+QI0AIcCBkHRpx8R + YBhGxO56VmyPi+3xcUFBjLOYnw/G24kTJ2ojXiHPTAl91nT4MIvzlVZMv29M29v1+EZ/mnB0mUBW7zMe + 0nyBxl7YuHt3btnipRwJmMvlOxr3NC54feWvFu9ubDzcByt8kfjF2Ndtli5VGuY7IPEPBADXzZ07dyEI + +8ILZ6uLLprL6Ddq1Aj1/PM/J5F3hPq937uJc9GPHDnE54BQX3zxOdXYuJuNgPgf/vc4wpc0XdHb2WUm + BjFj2APBQcwHJ8Q2qAPjx4/XlXRkYKB+H+2Hfg9XC/LhQSgtLS0k+W9eTKL+XiIIdBhGDL5cFAhAYDPm + E5/4xKWXXXbZhQQoCQ5OSSYjoyKuC+kB18TS3t6ep/tsJsliPa03m4+RtMe0tbi12Ur6HhJBQ0ND5ciR + o6rq6mrTpGrUENGn8Rz0U0nbpo4cMXJCqiIVAOwg5UDi4b5KV/LsS+izquoqHVSTTEQfNWskBOiyWSMV + ABBQsajXAAaADJIASxB0PL4vz6VA7625XR/v68X/eZ18xLaHoquiSMRiZXcGfz8pT6kScT/yYthEaon4 + oTH4sThuVBsBAFeytKUIm8BtEIjubR9jeZGwHanSuPbECRM48zLkGIE0A8B+Gs8yZm139EAgIJKktg1J + T0SRgET/+cL5558f7mlszC2evyhP3yjb3ta2afVba+dt2LRxi7H+i7HP5voi+ovBL4rye78AcC0BwOJj + x44Fs2ZdRAAwm8VPDL4FC54mAqxUV1zxKZ1jnssaLwAkgOfUgQP71VVXXcWcc5/pMJ8rD4MaYha4vR2a + iv0gNnB7EJ8QPhacI8eCUAEQu3fv5gWcH89Az7yfOPOvCAx+1QfDBYn1qrQ+boaIafQnP/nJ36I2mzh/ + HRf9pOthAYHgvvhFEBEKm+I+9Hvw1VdffeHAgQNbVLEQtk3cEmUVqFLLqxswaE3NGc3KF83OR6B0Bj3X + 79D7TuTcfuoPPJ88YwUXLU1EIAgbhPQH+gfFWGpogI5uaNABUjW1CjaM+vo6Y8RMRcyRo/ayuvSZlioy + LFHkjNSVYzWjj/+HGsKAgJgKFBshcMS37+3pjSIupYSZeG4k+aWYEl0ahhzYAGAtoSlUIgDAAAepTOw7 + YhewpIfIpSoqjCv2O5KA7YlBE30fBmP0BYEzc3uWTqnfAIxNxIzQ/zYAuO8VE8dSMFJlYAKnJCi7YPqr + MHPmzMTePXtyC557IdPW2rZ/247tL65Zt/bNPfv2NtN+8ecL4XeWIf6Bk14GAgB6mJmkAqwkFSB97rkf + IwCYw1wCWYELFz7LADB37mWW0SPkwbB48Xzi2E2sAoCAoX/bHYIPig4E4YOblYaRaq4Djg+CE5AAxxfC + F5THQCTOzpZ93MeI5S1E+C8Th17XrfNPK4SoTAfhI9D7nDvt1ltv/T0S9cfiWnrSk3Q0qEH0htsz8ZP6 + cPitt95a8u67766iwd9h9ZtdXSXvrLuFGO0m1JCwgISvSarD+X/4h3/4FSKkGikkai/iVYi8C4ViHL/0 + b9KE1nIiVBCYGP2w6A+HT5sAAdWQScJQY8eMZQMm4vFR0KS+rpYrIUX+eDNcdY1CbX+Qb8XBUaZ2IUsO + UDOIKUAC4cpDrKZ0RWocCAvfNsvqh8bKQD+4qZRTKIr9lvgvklkoxkBLLSjh/jazsQndcjW6hkEhUnHP + 4rsDzDA+k6YaNKJH8T7wHsHgCwBgqvbUCPCouAVz/UD+10cbAEB2D22aNWtWSBJG7pmf/bz1vW3bXnlr + 44ZXduzaua8LD1N063WYBQDQ/X6IvywAnEftkksuWU33rpw+/VxWAzAAEHW3ePHz9DJpNWfOpSU+enCR + JUvmq7a2VlYBQDwgZh7pRseHfo/Os9FbLPp4T6zjOKAvJAOs84c3kgGuCd0evyBS+iidJGWspf93Hjly + ZDcNriMewu+bMGHC5M985jOXz5gxY/LUqVPHIYJQc88U3xMfV2wMsB/Qb4EkiNUbN258k0BlPQEDrptU + pSmW4oKRbfavAIJ8aZEGQutXJAA8SxX12f+4/PLLb6BnGiHEL4Qulnshdnex97nrLnBIS3DQSsg1A+Qb + RlF1xv2F/fCuoCLU6IbRBBZj9DesqmbVAwaxaLorQxBsc8gVmPhhr9B5CLqwCURg9noASHq1YZNVD96u + 1ZKMUT3wKxKFxJrwM7IklNDAZoheACGQJKvAqsFgjomMhoVCCSjIdrEBAKC6aEkaAJW+kW8CVQzj0pdd + 6jM0guBDU+FUiD8ISnOQSaIrEEMK9jTuaf/pE0+++6uVby7e+t7W7QRGHYWiyN9pFlSPtUEh1s9/wgBA + Lzj6s5/97HZ68PqpU6epCy74OKP/6NEj1UsvLeIc7Y9//JISAEAHLV26kAnziiuuYOJHGW0QmXBZ8eWj + s8ERgLbguPjQdnQfpAQxDuIeIHiI+Xv37uUPRPuyBBjbNmzYsIjusVtpLppURe6KB+ujjzWSRP25n/70 + py+dMmVKrQ7Y0MU/hfDB9eFZAOFDjSDC37B69epf0P3eNh0vVd5s14u9bgNC1jo2Z/rY1suk36M4FXrv + qrvvvvt7RGh/gHcTYncXW7z2Ebu75HI57zFx58iAtu8v4M2pwQkrSk+pEh1YQHvixNN4WrjRo0cxUMBO + ocueVUQcO0JErmWgXZ+IicibYq3617hEczqPIWsAQTweYuTUdo4c26JkOEtwjoo8pkWfPSQK2zsQivXf + KuCSM/eLntP0T5brKiZYMpDx6QOAODCweL9JD4kKgvDYJ0m3b+2aNZu+/9D3l7/zzttbW9va2kkyECNf + p7OIxd8ebycPAIhoR37uc5/bSS9cf8YZU0kCuJg7Bh926dIXOZHi4ovnOhJAlvYtZq8AcgEQhw/OLvor + AECID9wexIZr4n+k7gJZbR++6GMoK0ZcmAnVfIiuLVu2vNDY2LjWEGhKFcXovOmY1G//9m9/4vd///ev + OO200+pxD5EoxLgoBj6oKShfTiDTRCrFi2vXrl1IA63DEKhdQklcL1lrcQFBPoSAgoCRSAEyrqK+//rX + v34P6fxfxTPJgJBfOxJyML82x7SlBpvoBRh8UkUuKpbaHxzirmerIP2fXws8EoEHNQM2CljYIYVBuqgl + gqqvM4FekPhSSWU3O8VZUpYlMlPnOeQj0IDqIam7OZMABfdoDxs4s1zizSjdKqrrmNBpzFzXDR9dIjIt + 4pV3jFSsMh4t33axd5IgwCmAdhgG/sPYp/c/MO9n85b84AffX0l0c8wifhH58SucX3z9NrM5eSoAEUwd + AcBGIsTJKO5xwQUaAIDyL7+8hD8s1AJXAsA+VKch9YG5NQgYxCcGK45GM8UlRZfCQOACGkaUk7Bd6Pic + xdfWxseLGkHH5mhbNwHIQdq/nSSIZiLmoyRRHB0zZkzd2WefPemyyy6bSctZEjkohC+iPiQKSCf4JY6/ + k7j9m/S7gq65VxU5vltFRbKsMqoUAGzx37YD2KK/fPASCy2J/Vfdfvvt86h/hnFJLqPquIYkCUO2iSIw + 3MoGCRsQbGK1B7FrO4iTEGygsNdtsPABRs6EHGdN0JH82s8SZzEX9zji7+Fyxnx5IwgwGkY3sGQIsACI + sERJUkUQuucXLOmlYGI3HNuJKZTCHpA+beAUjwjqG6L7UOpMAqkilUgVJQIGCo/XI4zxhIgqYOcwyCOD + PggAekkCXXvfffcteGXFK/sJ1MS112EtEuYr406pUgnguCWBcgCQJgB4g4jnQpT3uuCCi/jFx4xpUMuX + L+NTERsgFVFEAli2bDF/7AsvvJADcaAOgPh14Yl8JEJB1BdVQDg+uDEIHjo+RHIBCoAEzhHfP4BDAoSg + PuBY4uI5etbu66+/Pk0glcKxxbBdbXjC9QEmUCUgUdC9NmzatGkhdHx65larP+wMKh8AuCK/dLqLxC7B + lyTpkdh/2dy5c5cQeFXbQOrLfvTtcwe+CxBxgOCK8K59oBxASO6HrNtAYC/2dgGAnCkaKjEM9rGuhGG/ + vwsO+tp5UyyVpAoaE9POnMZSBQybw4aNUKMIPBC0BiBhr0kQKmVV7I2mZy8UpZNiirVOXYZhLpuVwql9 + DCZgbrgvmIg2fPZGzy1RgfmCfCtNYua7FXwRr8SY8mCAfX2Z3U8//YvFDz744Bq6ly32t6uixV8MfsL5 + 7ZyAnLMMCgTKAUBw4403LiECugYFPi++eDa/KADglVeWc6fNnHmhhYYBW4dXrFjKLzhjxgwWrdFx8rIS + tScRe+K6ArfABCLw4/NEF2ZwJDgbq4qJXofcpvotFWYeP9wHwDBr1iwGCpyHa4DwxZ23fft2BhiSLI5u + 2LDhia1bt75CzyrKoy3muwBg6/mu3iU51nHzsinlED7+zJs3r5Z05Nfo+WbGiZOuRblccVX71z5O1uNK + VtngYovu7rm2UdKVEoR4hdjlf5+UIN9WyoyLZ8CVMOxfNB9QyKIjJLVkp9VMY5iM7BXauNnQMEZNmDCB + x+DIUaPU6FENBBZ1nBmK4rfazRqWfqlARUCh/faqBDh4bqCCia7Ma9tBZLPgd8zws7GEkcsWxO8AAyN9 + /wKN7QId10xq5xsPPfTQL99+++0mVdTzXc5vE75d2MM1PA8aBMqGbn3xi1/8d0Kom7F+3nkf4w6Err5i + xTLOr545c5Y1gEImsjfffI0J98wzz2QRO2NKcoMgAQAg5pSxruLjQ8wHR8axZrDk6JwEzhMCF9sBriPb + ZB2/2A/VBAs+MO6DDhdXHmwNCAmm+3SQWrIC9oPW1ta95jXzqrRckk30NijYYr4QvdvRceK+CwJq0aJF + f0ec/644oi8HCj4AKB+K2v+6cZWVJALSBgF3vUh42RKidO0IQriumuAeGwUcOWDgAoO7bgOBHI9riY7u + 1kkol3imTJFP/A9GMm78eFY7wPxGkDRRW1PbU19X31NdU52mcZdM6CIFpsKPmVnGVJcIrBvYfSdh82IX + wVgnibR51apVax999NE3Vq5cuZfeQwjf1fldSdNmMgIGYntyK/+cGABMmjTpwuuuu24JdewovBMm/Lz0 + 0kvVxo0bGNkACqICIDClvb1NrV6tC4CcdtppLG6HJgkiZYpj4Ffy8rEANHAMEeTbcOcRRwQCjiNinktg + MZWOD8RdZ3N9CdrB/4zopFJMmTKFA5UkX0DyABobG7du3rx5Gen7awgU9lmdJeK8CwC2ju+z7LtcvqSw + g/Jzfpv4z6Q+gAGz3kfwcYTt21cuCs2Nv4g71i7Y4uqw9kD2gUKc8bAcWPikCLSsiUq0JQRXzYizSbjA + YT+DNFf9cQ13vv6ThcZZ4aWXXlpCUuR6pb1NBSSOXXbZZaPOPuecETTeh40eNbpm1MhRdVXVVQjkrKis + TNNQrUgBJNKVtQE8IclkgkglyPf19fQ1Nu45MP+F59984onHNxFjOqqKHF/cfF3OWIyTMn0lwEtq/50Q + AKBdddVVt0yfPv0JEq9CfBQCBUZqTBk2Y8a5EQpjELW0NKsNG9YzUYIbgwNzmWzDwUH48AxIIo9xBe7d + v3//clIBfkXX7zWdm6NOT5OINJmWi4m459D5NWIkFADAOsR9GIoAAKhAhOsiHBgqBeL0af1pApY36OO3 + yThQ/XV7n3U/mj3FQ/R2kI/P8lq2059++ulb6P2esonTJcyBRP3BSAn29e1tQvB2vkMcEPWrNmStuzYE + W1Xw2RRKshCdba6bU67Va5KdXPuCTeguKNig4XsOVy2y/3dtKbKO8UZSatOTTz6J+TLEvSsHlqT1Wut5 + 6d/JZ0ypHlZfn5ow8bQqAoRMc1NTR+OePW379+2Fji8x/SB84foS4eeK9D4AyFnbfapqbBtU9gZJAfdN + nTr1G71mqm28EER5xAfA1yvx+LCob9y4njsLBAmCF8s/RHFJ3TXBP81EpPOION+idbywBO/YHck6DxH5 + aXSfWbTMoPXpBCgVUhMAlmFwfkgceCaUIKP7ZAhUlpCo/xQ9AxIVkqrUgCcEn3EWu5Syrdu7s67E6fe+ + //s1AoD7qA++8X64/mA4v23BlhYVJPHsdzPqfK4tVxKwXZBCuDJXhEt8st++jpwn22z1wd6fkRwFi7Bt + ALCNkzYIyPZ+xVNUf8Opvb0foWj1qPDYY4/9M3HrnaqY/1GuibvXnZrbrduHRQBAiF/GpK3zDwYAfDMA + xbaBXoA9H6RT11599dXfI1H7JuqIkfKR0CnwX2IBV4bID8t/Shs4mOixjSer1CJaF23bQmL+FhL/XyNE + 3aN0Rl44wHPwy9D9UlVVVZOI6OcQEDQQEDSQyD9x7NixI4j4AwKT/fRx3iSx/2W69tuqSIzSEbYV1SZ6 + m+PbLhVfZ/t0ezfWP7Y988wzGDi/pGVuv0w05QcAe3u5EuvlwEIi6ey6iW6hlnKFW+zmC1JyJQEBAZvr + o7nxAi4wuHEFrroh0oB4EnxBT3EGRduXb2chuv3s63s02LEWLlw4f8GCBfPMuFWqGNEZ0YtDW+64EAK1 + 6/SLBCARf7al3zflV0H5JVIfAGRUmTYYCSB6KRL/z77yyivvq6mpucFFVnuwgcPAkGIs7hh0BSL6V4gj + P066Popw4KXB8ZODuH/J2FNF5EzSvSroXpUEQFMIgIaTBLKapIlDqhhi6wvisQneF747WKI/oUbcfzI9 + 92ZaKgcj8pcT+8sZAUOJrTfNDl5xRX4bDFyAkV+f+G+v+6IUbQu+HGtfV7YJIdv3FwK3z3MlD7EZ2EBg + qxWuh8IGAgFEG3jLrWMBY9u1a9fG++6777sGoHz0UxL652yzubRIoHZQT7ngnjggsK/pFgsRWoltg03g + LuFw11577V3Tp0//OnVopQCBO/hg8IM00NjYuID0/mcIDNbneSI3jtobfOJ4fLNfXji5AIqLgu66PUNq + ORF/UEa942nPP//85dRvy0M99W3UX9zJA+j7g/EECBi7Rr84zm8TQZwKUNLpMR6BuCAjn2/fnalZOLsQ + pagofU4ugAsE/KEtg6HPPekCgw0ENqFLP8SBowAAqZeN3/jGN/6mt5erdoodwB0vNr2448glUtv2lFGl + BO1y/OMBALtuQGw7HgCIvhn+zJgx4+LTTz/9NpIKbqDBNUY+GhrqlpG+tnXNmjWPvPvuuy8YwkeFj4FE + /RNpLsHaRjufXu92kvJ0rlInieO77ZVXXvkMSUHzo44dBGd31QTfPtkmx5Xj/u4g9w1633XjvADyG5eM + ZOv1aClnolZxBdoGZRwjGYRxIOBKBK40EBfubMcquERu94Udli5ZrKRa7v2rv/qrO+i5ILJLYpdPQvRF + gSpVqma6hmbbpecypnISqg8AbKk3th0PJw6cX/6iI0eOnEx6+AWkg0+kf0dRx3ZTJ20kPXwzfVT4MmtU + qZ50KpprZHEnRnSB4ZSK+eXaG2+8cd2RI0cW2oNvIK5/vK4/O7oSLY7gXUlgMNd3ib9c1KCt39uzSKed + ajpi8YeRT64n3iPbG2DbBXzPIr9u+LEPjFyAEOK3+8yuOi3PQ+N62x133PHNPp6/OwIAH/NwubeMz7i0 + cXvM+gjeXS9nAxDmd9JUAPccGwxynv0wkEjlHZf4TyYQuOjqErctSvkCKE4pt/e1J5988tMNDQ0LMNjj + RP84o5y9fyDQ8Fn64wDAFoMHsi2UMwD6fPsuAKBJLr1cT5pUcpLtksCFBo+SJEvZz+E+k/2/ayj0SQV2 + QJGkFKNF6cWWBIDnXr9+/av33HPPA3SuiLxi5S+nq/t0eVcSLcfxfeqAm2iWc65nqxWx7UQBwF4Xg5v8 + hp7t7vEnqw0kerlimLvuu94pbT/4wQ+unj59+lJxh8YRc5w+Hmelt4nbJv5yAGCLvi7ouM8TZ8n3hef6 + MgltAICB2JUq8D9AESAg29BAdLAn4TqSz2F7DOTYODAQ1cCNF5B9rk0gDgCwIGb/Jz/5ybyf/exnjyot + 2cqYcSVQN24kF7MvThJw95WTCFzp1o0FcBl0STtRYowjapv4g5hjT3bzAYC9HmeM8Z1/ytsDDzxwxtSp + UzcRZ6uJUwN8AOCuo7k2AVtslWYXXnE5vfxfUlrLo05EHeUxxPnEfV86sVj00QAAts1ICBqEioIsQoxC + 4JLbgeNEEvB5CMqBgC+E2JfJaPejbReAHQUh5j/84Q//dfHixS8oLeW6erjPgOe6lcuJ/z7pwAciBc89 + XO4vv+8/EGiAFsT8+q5/qgHA/f+Eg3VOVbv//vvDCRMmLBs3btyV4Hhx3N5n+CtnBBRLfxyQlNP3ff9z + Jzm+cjeYxkf0cTYA2yUo2Zw+qz5CuKHv28FCnPFH5yDQS66F3BGRogajDtjSiS+l2ZZifAAAACLpI/u3 + f/u3f71nzx7kkQDBXN0+jsDjiH4gYPAR+UAg4xq8318o8CDbQFw+LijiZN3bd103QOcDI3q3/cu//Mtd + F1100d8hRgLNBYDjEf/tX1+tep+F35YSXGnAXfdFxXFneoJ/XGMbmusGBOcGMQtHd68PDo9Qcfs+EryD + PA/bRSjJZnKc/VwD/e/mFdhuQukjAVSsA3w2bty4/U5qJhRYxpSP+9sE6nPPuccWPPsGAgMfeLgSwIBj + /lRw5FNp7T/e9qEheruRGnATAcB/QLRFeLSPIAcbAGRvkwHrqgDudX3r9jHuffp1ahkjoAsAbmSfPadD + XHguErhcER/XA8ChJqVE8pnS72w7sM+X+9rP6j63/WwuGEi/2f5/2CEeeeSRp+bPn/9zpcX/OCu8zyWX + P47/3W1x4CA6lQTH2br/oDIB+TufigE+1Mq3733vewhjXjV37tzJGIwQe10fNNpgo/9sS3WcV6Bc9J9P + 5SgHAL7CIa404DMKyrmw7kOftputbshcELJdfgUEkGeCX7k2ws2lapT9XOUI391uuw9tt6CEta9atWoL + Afd3MLuUKnX/uZb6cgTu7nPn+fOJ8wXP//mY68TOAhzXhgDgA2rf+c53vkwD+YeonYi0aOi9PmPcYAHB + dmH5XIn2ernAn34zAsU0N+NvoHJj9nYQFSzqcSoGtiFr1Nbx7XvgPVFLUCQBLJAEkHsyGJtAOelA3IZo + eE4AFbYR8f/o9ddfRwAXrP82gflE9MFKADa3zg3yXNcG4CtDN2jJdwgAPqBGUkCaRNhlZ5555mXnnXce + h02LLxqtHEf2GQildLrvmMFE/cW5JOPaYEOB0eyEICFgJJDJfVzDIraBmEHUrgFSJAEpK2cTMSQpeBHk + ePs8WXeDiew6hbJd1A9kmuL/nTt39tx9991fpec5qIrh5q4HoJxxL1dm3XXfyXlxpeZcMPClqw+6DQHA + B9i++93vnkcD7Gdz5syZgUpGkASg1w4UCWiv24DhgofPsn8yAMAlrjhO71uXc2HQEw7uXltcgpACRCdH + c2sXyuQysg/nIY4A6gOIWN7BJ/LL/77oQpwn800SMHf/53/+549XrFjxotLBbfYDx0WgDsYm4ALAQGAQ + Fw14wsTP3/nkDOWhdqKNQOB0GnQrZ86cORaSADwDsIL71AG3cIgk+Mi+OCNeOVdfOaARYnCbLxR4MABg + nwMAkDkY4zwNMvmLPIuvTgAMijAMyrVxLIKFcK6AgI/ry//2/QE2eCbo/KZAbebxxx+/k/T/FbS7VvkD + 2WwpQCm/u84V+d0lH/MblxfgcwWeUBsCgA9B+/a3v/11GpT3EwhgTka2gkMEdqP60GzC9U2O6QvoGcjV + d7ziP1qcJwDNNfr5ioJIDYk4AMAzQJyHGmDr+j6pA/YEXM9WNaS0vM9NGGcERGwCJAqUqSPOn3/mmWfu + Xrp06TNKE79ELvkS2tyiH3Gc2sfx46SAcpGAvrD2E2pDAPAhaQQC36PBegdAYPbs2SwFgIuhxYnpAwGA + LyioXMShvX2g5iN6n2Tg1uYTa7tMr+Xq4HJtPAOMgFAD4vR2O0YAdSEBKHZhEBC/VKGSZt/Pfn48C6QJ + 9DtAZ/Xq1U8/9thjf6P0VPJ2Tosd7SrNjTdxiXYgsd/93xcKHCdlvC9X9xAAfFhdqfUAAAdvSURBVIja + fffddw0NynsnTJgwF5IALN0YjDBu+XR8O8cfrZx+79sv58aFAZdrrmjv0/Xd/ba7DWI2AoJ8Rji7QQqI + M+zZ4IN3k5mm7fRjeFfgIpSoS/scNCF8gAQMsWYG6AdoeY4kAZ5hShUncfWBgAsGbrKZy81tq70vPT0u + 4y8uc3UIAP4rNQKBM2gwvkTEfSZAYO7cuTyIoRZAL3WnTotzEbrVbuK2S3Pdf+V0f99vOb3f528H8UPc + 9rni7GcAYcI4Ggcm8r9tGLRBQCQBM5FsidSAYCQAACQtED8BzUbS+W9777333qJLDVO6ahU6wgcAdqKb + Ty0YTPZfOT3fLTevVCmxv2/ur9QQAHwo27333juJBulDNHBvOOecc3ieRei5EGdBDFKYNWXNXusStS+w + SPbH2QoGYweIi7F3JYE4UVv2yUzRdmahNHcbJCDo5b6YAPdZcIx4GCQJSQqOAARwjEQiYhsmi8F2Atd3 + H3300c/t2LHjHaWJ3yV4mXsysNZ9yW8l3aXiAaBc+O+vLZFtCAA+xO2ee+65lQbp14hTfgwlz6dNm8Yc + DsQgk5vaUWtxOv9AkoJP7y8nAch6XJXfuJBb+3/o6wAAl+u70gUaJCBw6XLqhn1tmYVaCB8L9kt9AfwP + XR8eF+L8G4jjP7dy5cp/3LVrF/z8VdIFqpToy6kAbmHQ6HVUqU0gLijIl8buS3X3tSEV4L9yu/vuu6tp + IN9OnOwOGtgTIRFcdNFFbB+ASItBDDAQsdZn3Y/zJNjH+dQCt7mE6uP6vn3udOM4DvYLSDU+APCpBFJd + 2gc2ck37WWQ7iB6gCVDA+ZgzAuoU/Z/ZunXrPzz55JP/h7ZLMoH4VYMBFh8A2OdFr6P6E3ecVd819Mn5 + 3k9xssbXEAD8hrS77rrrNBrY3yLudRsG89SpU9WVV17JU6GJywtcTaLY3DoAblrxQKK/TxWIC7H16eQ+ + AHD3gTBlm+8etioQlyVor8uvzAYtc0riPEwGCz3fzC0w79VXX/3+smXLXpMuUOXT2l0OH8Rsc8+LHlfF + c3pbvx/IsHfSk9uGAOA3rH3rW9/6HA3gr2QymY+TLps+66yzeCZmzNgEwsYAx4CHmlCctTaIQoXR4vz+ + gzUCovnce/Yxdhiwu1+OgQpg6/XlYvhhyMN7ucZEUYHQJHZfpoIHx8dM01gIOHN03DaSCL76zW9+c6H1 + WnE04HP12dsDdXwA4BPt7Xz9cka9U5bVOgQAv4HtzjvvDGmAn0vc/hoa1DfR4J7d0NAQnn766eH48eMD + 2AowNRuIBJ4DqAg2IPhqAaLFcX133Wf48/3vBgTZ+9CkMlBceK59Tzw73IGSIARAgzEPRA8uL+AHIyli + B6Ay4L3p+I10jx/TfszFuOHv//7vOzxdavvxg5h9gbUeOvvd81w1wF73cfpfO+H7HnSo/QY2EmuTS5Ys + mbNv375b9+7dewMN9DrSrZMzZswI4EacMmVKFC8PYxqIApxRquyKhBAHBmgDcWifFOAmAPnOgUFOyn/7 + 7AlS81+kCJkYVnz3OBZEjwloYM0XewhelYh+Eb3LPFqeJanp2HF2azlA8G0b6H+fMe8DI/pyDzrUfoPb + yy+/fA4Rwh/s2LHjehKX5xCXDDBlGuwFF1xwAU+iKi4yNBAWdGssMkW3zbXdNhDX92X/+WwDQvAgZHBy + d8YeNACQzCotBTnw3OLOw5Ty0OslX8BkGe4yhP/IXXfdteYUdHEwyO2DAQBvF5+CZz6hFxpqv8GNiCK1 + du3aa4lAPkmcfiqJxFOJM55DRFIzduxYBU8CQmdhhYceLnozCA1EJpVx7Om6feWzBsoClGYnFtmLzPCM + JvUMJO5fwAkqDNQXEDmiIkHwsAXQPnD1Rjqnkc55jxbo9a/de++9x8vtj7edbJr5QKtWDQHAR6ARAaV3 + 7do1jrjmpQQKc7Zs2XINEdBZtKsKhI8FojXy6ydOnMhSAtZhpce6cGG7ku+JNCFsARVwc7FPYLEJHPq+ + PRtwXs8n+Q49wyoi9lX0u4RA5MC3v/3t3vf1UO+/uTUp42jqQ1mebggAPoKNiKxy/fr1k4kAZxEgzCSV + YTZtPpeIbiQRXTW4M/RzgIKI3zDYSZitBNRgsesQ4hgR6SXqTvR0CcgBwUt9f7vEt1OPr4+IvI2WdbQg + LHcL/a6me2y+//77+97Xyw+1kjYEAEMNobYJIr7adevWjSWV4QJaP3PTpk3jiCtPJc57Ji0NRLxpIuQk + ETQ8EDg+RBMil8k5xcMAkEATYyJx/Rx0evo/R0uWjsvTgt+9tGCa+H30u5P2baFlO/2/48EHH2z/oPvm + v3obAoChFtsIGDA+aogwUyQdVJJoPpyIE1VxEC6bIoLnIhnAATo2SUsV7Q+Ig+cnTZrUge24Dv2fXb58 + eeeqVasKtbW1XfR/Bx2G4ppd+H344Yc/aDH+I9uGAGCoDbWPcBsCgKE21D7CbQgAhtpQ+wi3IQAYakPt + I9yGAGCoDbWPcBsCgKE21D7CbQgAhtpQ+wi3IQAYakPtI9z+P7mxIoD8Hq/OAAAAAElFTkSuQmCCKAAA + ADAAAABgAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACxsbEFu7u7HLOzs1WlpaWAsbGx + j7Kyspa0tLSZq6url42NjZKCgoKCeXl5XHJyciOBgYEHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjY2NGqioqHW8vLzRzc3N + /9XV1f/f39//5eXl/+Xl5f/h4eH/3Nzc/93d3f/e3t7/09PT/8DAwP+hoaHgjIyMh5aWliIAAAAAAAAA + AAAAAAAAAAAAAAAAAgAAAAIAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACPj49nt7e3 + 6tTU1P/X19f/29vb/9zc3P/b29v/2tra/9bW1v/R0dH/ycnJ/8zMzP/f39//2dnZ/8LCwv+/v7//ycnJ + /62trfljY2OGNTU1DwAAAAAAAAAWAAAAGQAAABcAAAANAAAABAAAAAIAAAABAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AKKioqbKysr/0NDQ/8vLy//Ly8v/0NDQ/9fX1//a2tr/29vb/9ra2v/U1NT/y8vL/9LS0v/k5OT/zc3N + /7Kysv/ExMT/yMjI/7m5uf/ExMT/fn5+yA0NDT0AAAAxAAAAPQAAADIAAAAiAAAAEwAAAAgAAAAEAAAA + AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAnZ2dhcXFxf/ExMT/wcHB/8fHx//MzMz/0NDQ/9fX1//c3Nz/3d3d/9zc3P/U1NT/yMjI + /9PT0//e3t7/wcHB/8LCwv/Kysr/tbW1/6ysrP+srKz/wsLC/25ubsgAAABIAAAASwAAAEAAAAAyAAAA + JAAAABUAAAALAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAtra27r29vf+9vb3/wcHB/8TExP/IyMj/zs7O/9XV1f/c3Nz/3d3d + /9ra2v/S0tL/x8fH/83Nzf/Nzc3/wcHB/8LCwv+0tLT/r6+v/6ioqP+ZmZn/pqam/5eXl+wNDQ1eAAAA + QQAAAEQAAAA2AAAAJwAAABwAAAASAAAACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtra27Le3t/+6urr/vb29/8DAwP/ExMT/ycnJ + /8/Pz//W1tb/19fX/9XV1f/Nzc3/xMTE/8XFxf/AwMD/vb29/7a2tv+urq7/oqKi/5SUlP+QkJD/paWl + /52dne8XFxdYAAAAMgAAADsAAAAxAAAAJgAAABwAAAASAAAACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsrKyrbu7u/+5ubn/ubm5 + /76+vv/AwMD/xMTE/8fHx//MzMz/zs7O/8zMzP/Hx8f/w8PD/8DAwP+6urr/sLCw/6Ojo/+UlJT/jo6O + /5GRkf+Xl5f/r6+v/3R0dMMAAAAiAAAAIg0NDTAAAAApAAAAIQAAABgAAAAPAAAACAAAAAAAAAAAKiop + KW9tb+KTkJH/WFlZxQ0ODkoAAAAaAAAAJQAAACcAAAA4AgIBOgAAAAgAAAAAAAAAAAAAAAAAAAAAuLi4 + GJ6entbKysr/xMTE/7i4uP+6urr/vr6+/8DAwP/BwcH/wcHB/8DAwP+4uLj/r6+v/6Ojo/+YmJj/g4OD + /21tbf9paWn/f4GB/5OSkv+jo6P/qqys/FxcXJJOTk94amprloODhIAvLy8pAAAAFgAAABEAAAAJAAAA + BAAAAABlZGUzX19e67KwsP+empn/4+Hh/9jY2f9GRkbTBQUFmg4ODrtjY2P/paWj/0tMSr0KCwhVAAAA + EQAAAAAAAAAAAAAAAFpaWg9QUFCApqam8sfHx/+5ubn/ra2t/6Wlpf+kpKT/pKSk/5eXl/+JiYn/fX17 + /3Fxcf9lZWX/XV5e/2lpav+CgoP/mpqb/62rrv+2trX/ube3+Li2tu7Z2dr/29vb/5+fn/h/f34sAAAA + AwAAAAUAAAADAAAAAQAAAACZmJuKsKys/6ikpP+WkZH/q6qr/8/P0P/CwsL/mJiY/4uLi/9eXl7ibW1t + s9HR0fnFxMH/VVVUyRISEF8AAAATAAAAAAAAAAAAAAAAQ0NDLk5OTZmNjY7moaGh/6ampf+fn57/hYWF + /3h4d/96enn/ent8/39/gf+IiYr/nZ2f/6urrf+vrq7/sa+w/7a3t/+ztLT/ucPF/8bT1P/Cw8X+wL6+ + /qenp/9wcHBJAAAAAAAAAAAAAAAAAAAAAAAAAACQj5GDqqen/6+qqv+fnJz/srCy/8jIzP+rrKz/rays + /7i4uP+EhITxLi4utRkZGY9xcnO30tLS9Le3t/9WVlO+GBgYawAAACcAAAAGAAAAAAAAAAAfICAIOTk6 + NHl5e4+UlZX6hYWJ/4uKjf+OjpL/kZCV/5eXmv+hoaT/qqqs/6itsP+vubz/ucfJ/8zV1//W29z/19fX + /9XT0//Jycn+wcXF/KqoqP+GhoZtAAAAAAAAAAAAAAAAAAAAAAAAAACRkJKDrqqr/7Wwsf+npaX/trS2 + /8C/wP+4uLj/urq6/6+vr//Nzc3/6enp/6ioqPo5ODizHBweloODhNr19vX/o6Ki/xkXF4UXFxgmSEhK + QHNzd3SDgYaliIiMzIqJjeyKio7/jIyS/4uPlP+LkZb/jZab/52mqv+2vL7/y87P/9HR0f/Hx8f/rKys + /4CAgP9SUlL/LS0t/yIiIv+wsLD/y9ja/Kelpf+fn5+NAAAAAAAAAAAAAAAAAAAAAAAAAACSkJODtrGy + /724uf+wqq3/vry9/7u7u/+Ojo7/mpqa/7W1tf+1tbX/wMDA/+vr6//19fX/kJCQ9lVVVu1gYWL0cXBz + 1YmHi9ifn6T1n5+m/5qdof+Sl5v/kJec/5Ocn/+bpKf/qK2v/66urv+xsbH/tLS0/5ubm/98fHz/W1tb + /y0tLf8WFhb/EhIS/xAQEP8PDw//Dw8P/xAQEP+kpKT/0Nvc/qqpqf+ZmZmxAAAAAAAAAAAAAAAAAAAA + AAAAAACRkpODvre3/8G6vf+uqqz/vLq7/7y8v/+fn5//mJiY/5CQkP+YmJn/lJOV/5GRk/+Ympr/mJab + /5ybof+kpqr/pKmt/6eusf+rsbT/rrS2/7W5u/+0tLX/ra2t/6SkpP+NjY3/aWlp/0NDQ/8hISH/Dg4O + /w4ODv8ODg7/Dw8P/xQUFP8YGRj/ICog/yg9KP8uSy7/M1oz/zlpOf+VlZX/09zd/rGurv+am5vMAAAA + AAAAAAAAAAAAAAAAAAAAAACTkZSFxL6//8a+wf+wrKv/vbq7/7u7vP+dnZ3/nZ2d/52dn/+OjpL/ko+V + /4uRkv+AnZD/lp2f/6isrv+7vr//x8fH/8HBwf+bm5v/fX19/2FhYf8/Pz//Hx8f/wsLC/8GBgb/BgYG + /wcHB/8JCQn/Fx0X/yY2Jv8sRyz/MlUy/zZlNv88bzz/N2A3/zJSMv8uRS7/Kzgr/x8uH/+DhYP/09rc + /7W1tP+amZndAAAAAAAAAAAAAAAAAAAAAAAAAACRkpWGysPD/8rExP+xrKz/vbq7/7u7vP+dnZ3/n5+f + /7Kys/+Wl5r/mZmZ/7S0tP+3t7f/m5ub/3R0dP9SUlL/Nzc3/xsbG/8MDAz/BAQE/wAAAP8BAQH/BwoH + /xMfE/8eMx7/KEon/zFeMf86bDr/OGU4/zVZNf8wSzD/LT8t/yozKv8oKCj/Kioq/ysrK/8sLCz/LS0t + /yQkJP9veG//1Nna/7m7u/+amZnqAAAAAAAAAAAAAAAAAAAAAAAAAACSkZWGzMfH/8zGxv+zrq7/u7u9 + /7y8vf+goKH/oaGh/7Ozs/+kqKv/mJiY/y8vL/8YGBj/Dw8P/wUFBf8CAgL/AQEB/wsVC/8WKBb/ITwh + /yxQLP81ZjX/OWo5/zBYMP8oRyj/IDUg/xkkGf8TFRP/ISEh/ysrK/8sLCz/Li4u/y8vL/8xMjH/ND40 + /zZLNv85Vjn/OmE6/ztqO/9ea17/0dPU/8TIyP+bmprwAAAAAAAAAAAAAAAAAAAAAAAAAACTkJSG0MnI + /8/Jyv+zsLH/u7m7/7+/v/+mpqT/paWl/6+vr/+yuLv/lJKS/xEWEf8SIBL/HzYf/yhJKP8yXDL/PHA8 + /zJdMv8oSij/Hjce/xcmF/8PFQ//CgoK/wwMDP8ODg7/EBAQ/xAQEP8UFBT/LTQt/zZGNv8ojyb/Ol06 + /ztnO/88bzz/PGU8/zxcPP89Uz3/Pkw+/zg9OP9TX1P/zMzM/8zT0/+cnJz0l5iYEwAAAAAAAAAAAAAA + AAAAAACTkJOG0MnK/87Iyf+zr7D/u7m6/7+/wf+pqaf/qamp/6ysrP+6vL3/o6Oj/zlqOf8wVjD/KkYq + /yA0IP8WIRb/CwsL/woKCv8HBwf/BwcH/wgICP8KCgr/DxIP/xklGf8iOCL/K0or/zNcM/86bDr/O2g7 + /yihJf8jrx//PlA+/z9IP/8thSz/K5Mo/0NDQ/9ERET/R0dH/0JCQv9OV07/y8vL/9DZ2/+fnp3+mpqa + PwAAAAAAAAAAAAAAAAAAAACTk5WGz8jH/8zFxv+ysa7/u7q7/8LCw/+sqqv/qqqq/7CwsP/AwcH/s7W3 + /yc8J/8PDw//GRkZ/xQUFP8TExP/EBAQ/xVrE/8cLhz/Iz8j/y1SLf82ZDb/OWo5/zJZMv8qSSr/Izgj + /xwnHP8fIh//PT09/yamI/8isx//Q09D/0dHR/8zizH/JrAj/0NgQ/9FWUX/RGFE/0BmQP87cjv/ysrK + /9Xd3/+koqL/mZmZaAAAAAAAAAAAAAAAAAAAAACTkpaGzMTI/8a+wP+lo6D/uba3/8bEx/+xr7D/srOy + /7m5uf/Dw8P/ur7A/zpVOv8bKRv/LEMs/y9PL/81XjX/JrEj/yKpH/8qTCr/ITkh/xkpGf8TGhP/EBAQ + /xEREf8TExP/FRUV/xYWFv8mJib/R0hH/yHAHv8snyr/OX84/0JlQv8soCr/LJ8q/yyiKv8osCX/R2RH + /yytKf85eDj/vb29/9be4P+mpaX/mZmZiwAAAAAAAAAAAAAAAAAAAACUkpSGxsDA/767u/+jn5//trS1 + /8nLyf+5u7n/ubm5/7y8vP/Gxsf/vMLE/zl8OP8wVjD/Mk8y/yo9Kv8hQSH/FZ4T/xGqDv8ICAj/CwsL + /w0NDf8QEBD/ERER/xUYFf8eKh7/Jjsm/y5NLv85Yjn/NoI2/yW1Iv8zkDL/Mpwv/0xeTP82mzT/RYFD + /y+wLP89lDz/PZg6/z2aO/9QUFD/rq6u/9fg4v+pqqr/lpaWswAAAAAAAAAAAAAAAAAAAACSk5WGvLi6 + /7uytP+hmZr/tLK0/8zNz/++wL7/vb29/7+/v//Gxsb/u8PF/1x0W/8PDw//LCws/yUlJf8cdxr/HXEb + /w6LC/8SOhH/HjAe/ydDJ/8vVC//N2U3/zprOv8zWzP/Lkwu/ydFJ/86RTr/RIVD/zuZOf9RbFH/MLIt + /11dXf88nTr/SoZI/2BgYP9fYl//KcMm/0ObQf9XV1f/nJyc/9rg4v+1tbX/l5eXyQAAAAAAAAAAAAAA + AAAAAACTkpWGvK60/8Oqsv+pnKD/s7G2/83Pz//DxML/wsLC/8TExP/Gxsb/v8bH/3CFcP8UGRT/M0ky + /zNKM/8cvxn/NmQ2/yqkKP8mkiX/LE0s/yU+Jf8eLh7/GR8Z/xNkEv8UghL/FKAR/xSnEf8skSr/QZw+ + /0mKR/9gYGD/Lbwq/15sXf89ojv/SYtI/1ZqVv9Ra1H/M6Mx/0VvRf8+bz7/kJCQ/9ve3/++wMD/lpaW + 1QAAAAAAAAAAAAAAAAAAAACcjJaGlamd/2HbnP+Ru6f/w6y4/9DR0f/Hx8f/xsbG/8fHx//Jycn/wsfK + /4uciv8krCH/HsAb/yWZI/8llCP/Hike/wo9Cf8OeAz/EBAQ/xISEv8TExP/FFQT/xRxEv8ZSBf/Gy0b + /yElIf8pqyf/MbMu/0aBRv9MbEz/LKwp/zSNMv8prSb/OYw4/05uTv9UblT/Wm5a/2VvZf9jZmP/iIiI + /9ve3v/Dxsf/lpWV5AAAAAAAAAAAAAAAAAAAAACfi5p9NM1+/wD/a/90t5v/yqe6/9PT0//Ly8v/ycnJ + /8vLy//Ly8v/ys3P/62trf8XJhf/NDQ0/yeIJf82Njb/DQ0N/wsZC/8PnQv/ExcT/xsmG/8kOCT/Howc + /yZ9JP82Xzb/O2w7/zprOv9Ca0L/LrIr/1RtVP9ZbVn/SpRI/0ajRP9BrD//WoxY/29vb/9wcHD/cXFx + /3Nzc/9ra2v/fX19/9zd3f/Iy83/lZWV8JubmyAAAAAAAAAAAAAAAACamp9uPpRn/wZUG/99cnT/w7rD + /9XY2f/Pz8//zMzM/83Nzf/Ozs7/0NPU/7u5uv8kKCT/NkA2/0FVQf80TjT/KUop/zNcM/8gux7/NXc0 + /zReNP8uTS7/HKUY/yVWJf8mMSb/JSgl/zMzM/9oaGj/dXV1/3Jycv9ycnL/aIFn/zm9Nv9DsUH/Wo5Z + /2h0aP9ec17/V3JX/1FyUf9HcEf/P3A//9vb2//N0dP/lpaW/Jubm0oAAAAAAAAAAAAAAACZl5xuY0RV + /ycAAv98bWz/vcDB/9XW1//Q0ND/z8/P/9HR0f/S0tL/1tfY/7u7u/87azv/O2U7/0FhQf8qRCr/HTEd + /xkjGf8TdRD/FFAT/xsbG/8eHx7/FbAR/yQkJP8nJyf/KSkp/0JCQv9rc2v/aHdo/190X/9Uc1T/TnJO + /yTCIf8lsiL/OYk5/0lySf9Uc1T/XHRc/2R2ZP9sdmz/Z2ln/9jY2P/T19n/mJeX/5qamnEAAAAAAAAA + AAAAAACenaF5aGRl/1RLQ/+HgH//ra6x/+Hh4v/Pz8//yMjI/87Ozv/S0tL/29vb/7y/wP8vLy//Ojo6 + /0FBQf8ODg7/EBAQ/xMTE/8UTxP/FXgT/yItIv8lVCX/HKQa/zJSMv83XTf/OWY5/zxwPP9Gckb/TXNN + /1V0Vf9gdmD/Z3dn/0KxQP9Et0H/Z5Fm/3p7ev9ueW7/Y3dj/1h2WP9Nc03/QG9A/8vLy//c4OL/mpub + /5mZmYsAAAAAAAAAAAAAAACloqU6kJGP/5KUkf+emZz/2tja///////4+Pj/5eXl/9nZ2f/T09P/09PT + /8HHx/8+QT7/OkQ6/zRHNP8kPST/K0or/zNcM/81dTX/Ib0e/zZfNv8esBz/JJAh/y5DLv8uOy7/LjYu + /11dXf+BgYH/fn5+/319ff91e3X/aXlp/1aEVf8rvyj/QX9B/z1wPf9Jc0n/VnVW/2J5Yv9wfXD/am5q + /7y8vP/i5+n/oKCg/5mZmZ4AAAAAAAAAAAAAAAAAAAAAtLSzQczOz5aztrfx1dXW/9zf3//09PT///// + ///////7+vr/6urq/8bN0f8+bz7/OGE4/zBQMP8lQCX/Izgj/x0oHf8bIBv/FKAQ/xpWGf8aehf/JCQk + /ycnJ/8sLyz/NkI2/1lvWf9ZeFn/SnNK/z9xP/9FckX/UXVR/114Xf80wTH/dn52/4GBgf+BgYH/gYGB + /4KCgv+FhYX/c3Nz/7Ozs//o7e//qqqq/5aWlq8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACvtLQqsbOz + QK+wsIm6vLz/yMrK/9rb2//z9PT//////9Xe3/91dXX/CAgI/w0NDf8QEBD/ExMT/xYWFv8ZGRn/GYYX + /yB4H/8khyL/NVo1/zpoOv87bDv/PWU9/1Z1Vv9ofWj/cn1y/3+Bf/+CgoL/goKC/4KCgv9Rsk//g4OD + /4SEhP9rfWv/XXpd/1F2Uf9IdEj/PnA+/zxwPP/v8vP/ubm5/5OTk8YAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAACvsrIdsbOzPa+zspi5u7v/xsfH/87V1/+GhIT/CQ4J/xooGv8kOyT/LU0t + /zReNP88cDz/LYQs/yKbIP8ncCb/LDss/ysxK/8sLCz/UFBQ/4SEhP+Ghob/hISE/3eAd/9me2b/VndW + /0l0Sf9CckL/PnA+/zxwPP8/cT//RHNE/0x1TP9Yelj/aHto/4+Wj//z9PX/xMXF/5KSktqbm5sPAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACztrYMrLCwI7zCxduWlZT/N2Y3 + /zBVMP8oRSj/IjYi/x4pHv8ZGRn/HSMc/xWrEv8jKiP/JiYm/zFDMf81UzX/R2xH/0h0SP8/cT//PHA8 + /z1wPf9AcUD/SHRI/1R4VP9ifGL/c4Jz/4eHh/+FhYX/g4OD/4CAgP9+fn7/cnJy/3p6ev/z9PX/0tPT + /42NjfCZmZk0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AMfO0WOoqqn/DQ0N/w4ODv8RERH/HCcc/yc+J/8wUTD/N2I3/yWrI/88bjz/PHA8/zttO/87aTv/SHBI + /1t8W/9sfmz/fYF9/4CAgP98fHz/eHh4/3Z2dv9zc3P/cHBw/2pqav9mZmb/ZWVl/2hoaP9sbGz/bW1t + /4KCgv/39/j/39/g/5SUlP2srKwqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAMjMzj2zubn/N2Q3/zpsOv88cDz/PG88/zprOv83Yjf/M1Qz/zBJMP8tOi3/Kioq + /ywsLP8uLi7/Wlpa/2hoaP9iYmL/YWFh/2BgYP9fX1//Y2Nj/3x8fP+FhIP/mpST/5qVk/+ppKP/srCv + /8TFxP/O0dL/2t/j/97m6fbl5eXj3t7ev7u7u2IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMLDxh68xcb/NFM0/x4xHv8UGBT/ExMT/xYWFv8WFhb/GBgY + /yIiIv8tLS3/RERE/1ZWVv9raWn/hYGA/52Zmf+lo6L/u7i4/7y7u//O0NL/0NPU/8/V1vjO09XxztPW + 387V18rT2dup09fYi9PV2F7LzM020NHRHNra2hbc3NwQ3t7eBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMHCxBK3vsHtTk5O/yQkJP9NS0v/bGRj + /4N7ev+Qi4v/pKam/7S8vv/D0NP/ytfY/8vb3P/L2Nr4y9LU58vP0NnLzs/Jyc3Oq83P0JDNztB1zs7O + RcnLyijIyMgJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKinqxGysbPlwcjJ + /7zMz//E0tb/xdHU9sfP0ujJz9DUyMvLvsjJy6vHyMiSycrKcsnJyVjLy8w3ysrKGAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AJubnwSnp6lmxMLEkMC+v3m7u71av72/PcPDwyfIyMkMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAACrq60I0tHSD8PCwwO7u70BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAP///////wAA////////AAD///////8AAP///AAf/wAA///wAAePAAD//+AAAQEA + AP//wAAAAAAA//+AAAAAAAD//4AAAAAAAP//gAAAAAAA//+AAAAAAADAB4AAAAAAAIABwAAAAAAAgABw + AAAPAACAAAwAAA8AAIAAAAAADwAAgAAAAAAPAACAAAAAAA8AAIAAAAAADwAAgAAAAAAPAACAAAAAAA8A + AIAAAAAABwAAgAAAAAAHAACAAAAAAAcAAIAAAAAABwAAgAAAAAAHAACAAAAAAAcAAIAAAAAABwAAgAAA + AAAHAACAAAAAAAMAAIAAAAAAAwAAgAAAAAADAACAAAAAAAMAAIAAAAAAAwAAwAAAAAADAADwAAAAAAMA + AP4AAAAAAQAA/8AAAAABAAD/8AAAAAEAAP/wAAAAAwAA//AAAAAHAAD/8AAAH/8AAP/wAB///wAA//AP + ////AAD/+H////8AAP///////wAA////////AAD///////8AACgAAAAgAAAAQAAAAAEAIAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsLCwBLi4uEqqqqqGtra2lrm5uZWhoaGVgYGB + h3d3d052dnYGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ6enmTHx8fZ1dXV/93d3f/i4uL/2tra + /9bW1v/c3Nz/yMjI/6Kior2Xl5dfAAAAAAAAAAAAAAAAAAAAAgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJeXlwuvr6/n2dnZ/9nZ2f/c3Nz/4ODg + /9/f3//Q0ND/z8/P/+rq6v/Nzc3/zs7O/9DQ0P+goKCsHR0dNgAAAAkAAAApAAAAFgAAAAQAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs7Oz59PT0//Hx8f/yMjI + /9TU1P/f39//4eHh/9LS0v/Pz8//2tra/729vf/Dw8P/tra2/8XFxf+wsLD/AAAAVAAAADoAAAAuAAAA + FwAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKqqqi69vb3/t7e3 + /76+vv/Gxsb/z8/P/9ra2v/b29v/z8/P/8fHx//Kysr/xsbG/7m5uf+enp7/jo6O/8nJyf8hISFxAAAA + IQAAADIAAAAfAAAAEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AMXFxeHOzs7/v7+//7+/v//Jycn/0NDQ/9LS1P/Pz8//xsbG/76+vv+ioqL/hYWF/4SEhP+bm5v/lZWV + 7wAAABcMDAwYCAgJFQAAABMAAAAMAAAAADk7PBpVVVfIiYeH/1FQUJ4BAQE6AAAANhMTE3EUFBRkQ0NB + DQAAAAAAAAAAAAAAAImJiaPT09T/y8vL/7a2tf+wsLD/r6+t/5qZmf+DhIP/ampq/1NSUv9nZ2f/lZOT + /7S0tf+koaHepaKk28PDxP9fX11aAAAAAAAAAAUAAAAAfXx9yJ6bmf+3srH/4ODh/5ubm/9HR0f7aGho + /6WlpPiNjYvaHh4dc0xMTQ4AAAAAAAAAACEgHklycnC+m5ub7pyamf93d3X/c3Bz/3RxdP+AgYP/np+h + /6uytv+4xsr/xdTV/9jh4v/h4eH/09PU/15eXoAAAAAAAAAAAAAAAACNjI3pu7e0/46Njv+tra7/0tTS + /8TExP+QkJHsUlJSunl5esisrK35iIiK5isrK3kAAAAKAAAAADMxNR9jY2aEio+U/YiRmP+MnKP/ma61 + /7/P0//T3N3/y83N/7Ozs/+NjY3/aWlp/7y8vP+8x8f/k5ORmAAAAAAAAAAAAAAAAIeFhdnAurv/pKGk + /62srP+urq3/qqmp/8/Pz//X19f/jIuM3VNRUuGEg4T/amxu8Y2Wmu2xwsf/tc3U/67HzP+zxsf/sra2 + /52fnP+AjoD/ZHdk/0JUQf8lMSX/FRUV/xEREf8NGQ3/jZaN/8jc3/+YlJS1AAAAAAAAAAAAAAAAjIqL + 3MrExf+no6X/rK2u/6KkpP+SkZH/kY6S/3+Mjv+WtK7/uc7T/9Tu9P/d+vz/w8/Q/6KhoP94g3X/VWdU + /zxLO/8nLCf/EBAQ/xAQEP8QEBD/ERER/xQYFP8iMCL/Lkcu/zFVMf8/fz7/zuDi/5KPjswAAAAAAAAA + AAAAAACRjY7g0s3M/6aiof+urK//qamp/5eXl/+op6z/mKWm/5ysov97gXP/VFdK/zE6MP8gICD/Dw8P + /wUFBf8EBAT/BQUF/wkJCf8VbRP/IYcg/zVWNf85ZTn/LJsq/zheOP82UTb/LT0t/2iDaP/Q4eL/l5OS + 1gAAAAAAAAAAAAAAAJOPkuHa0tL/pqSl/6yur/+sqqz/nJyc/8LT1/8mPCT/ERER/woKCv8CAgL/AAAA + /wAAAP8MFAz/Gy8b/ydFJ/8zXDP/PG88/ySZI/8ftRz/OEs4/zc/N/8jnCD/KIYm/zw8PP82Njb/YHRg + /9Tf4P+dnp7mk5OTEgAAAAAAAAAAkZGS4d7W2P+opqf/rrCu/7Gwsf+goKD/x9rf/yJGGf8JDwn/Gywb + /x6AHP8eqRz/Oms6/zRfNP8qSir/Ijgi/xsmG/8TExP/Fn0U/yeeJP86YDr/Q0ND/yenI/8huB//R05H + /yqeKP9PiU7/2N7e/6Koqf+UkJAuAAAAAAAAAACTkJLh3tTV/6WjpP+wr6//tLS1/6ampv/D0NL/P2E3 + /zdlN/8yVTL/G5sZ/xWrEv8PHg//CwsL/w8PD/8SEhL/FRUV/xUVFf8ajBj/OYo3/zKUMP9OTk7/KbAm + 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 + QeAArEH//6xB + + + + 249, 17 + + + 359, 17 + + + 480, 17 + + + 684, 17 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/HandleFilterWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/HandleFilterWindow.Designer.cs new file mode 100644 index 000000000..476c399f1 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/HandleFilterWindow.Designer.cs @@ -0,0 +1,219 @@ +namespace ProcessHacker +{ + partial class HandleFilterWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(HandleFilterWindow)); + this.label1 = new System.Windows.Forms.Label(); + this.textFilter = new System.Windows.Forms.TextBox(); + this.buttonFind = new System.Windows.Forms.Button(); + this.listHandles = new System.Windows.Forms.ListView(); + this.columnProcess = new System.Windows.Forms.ColumnHeader(); + this.columnType = new System.Windows.Forms.ColumnHeader(); + this.columnName = new System.Windows.Forms.ColumnHeader(); + this.columnHandle = new System.Windows.Forms.ColumnHeader(); + this.menuHandle = new System.Windows.Forms.ContextMenu(); + this.closeMenuItem = new System.Windows.Forms.MenuItem(); + this.processPropertiesMenuItem = new System.Windows.Forms.MenuItem(); + this.propertiesMenuItem = new System.Windows.Forms.MenuItem(); + this.copyMenuItem = new System.Windows.Forms.MenuItem(); + this.progress = new System.Windows.Forms.ProgressBar(); + this.vistaMenu = new wyDay.Controls.VistaMenu(this.components); + ((System.ComponentModel.ISupportInitialize)(this.vistaMenu)).BeginInit(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 17); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(32, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Filter:"; + // + // textFilter + // + this.textFilter.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textFilter.Location = new System.Drawing.Point(50, 14); + this.textFilter.Name = "textFilter"; + this.textFilter.Size = new System.Drawing.Size(395, 20); + this.textFilter.TabIndex = 1; + this.textFilter.TextChanged += new System.EventHandler(this.textFilter_TextChanged); + this.textFilter.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.textFilter_KeyPress); + this.textFilter.Enter += new System.EventHandler(this.textFilter_Enter); + // + // buttonFind + // + this.buttonFind.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonFind.Enabled = false; + this.buttonFind.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonFind.Location = new System.Drawing.Point(451, 12); + this.buttonFind.Name = "buttonFind"; + this.buttonFind.Size = new System.Drawing.Size(75, 23); + this.buttonFind.TabIndex = 2; + this.buttonFind.Text = "&Find"; + this.buttonFind.UseVisualStyleBackColor = true; + this.buttonFind.Click += new System.EventHandler(this.buttonFind_Click); + // + // listHandles + // + this.listHandles.AllowColumnReorder = true; + this.listHandles.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listHandles.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnProcess, + this.columnType, + this.columnName, + this.columnHandle}); + this.listHandles.FullRowSelect = true; + this.listHandles.HideSelection = false; + this.listHandles.Location = new System.Drawing.Point(12, 41); + this.listHandles.Name = "listHandles"; + this.listHandles.ShowItemToolTips = true; + this.listHandles.Size = new System.Drawing.Size(514, 374); + this.listHandles.Sorting = System.Windows.Forms.SortOrder.Ascending; + this.listHandles.TabIndex = 3; + this.listHandles.UseCompatibleStateImageBehavior = false; + this.listHandles.View = System.Windows.Forms.View.Details; + this.listHandles.DoubleClick += new System.EventHandler(this.listHandles_DoubleClick); + this.listHandles.KeyDown += new System.Windows.Forms.KeyEventHandler(this.listHandles_KeyDown); + // + // columnProcess + // + this.columnProcess.Text = "Process"; + this.columnProcess.Width = 120; + // + // columnType + // + this.columnType.Text = "Type"; + this.columnType.Width = 80; + // + // columnName + // + this.columnName.Text = "Name"; + this.columnName.Width = 240; + // + // columnHandle + // + this.columnHandle.Text = "Handle"; + // + // menuHandle + // + this.menuHandle.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.closeMenuItem, + this.processPropertiesMenuItem, + this.propertiesMenuItem, + this.copyMenuItem}); + this.menuHandle.Popup += new System.EventHandler(this.menuHandle_Popup); + // + // closeMenuItem + // + this.vistaMenu.SetImage(this.closeMenuItem, global::ProcessHacker.Properties.Resources.cross); + this.closeMenuItem.Index = 0; + this.closeMenuItem.Text = "Close"; + this.closeMenuItem.Click += new System.EventHandler(this.closeMenuItem_Click); + // + // processPropertiesMenuItem + // + this.processPropertiesMenuItem.Index = 1; + this.processPropertiesMenuItem.Text = "Process Properties..."; + this.processPropertiesMenuItem.Click += new System.EventHandler(this.processPropertiesMenuItem_Click); + // + // propertiesMenuItem + // + this.propertiesMenuItem.Index = 2; + this.propertiesMenuItem.Text = "&Properties..."; + this.propertiesMenuItem.Click += new System.EventHandler(this.propertiesMenuItem_Click); + // + // copyMenuItem + // + this.vistaMenu.SetImage(this.copyMenuItem, global::ProcessHacker.Properties.Resources.page_copy); + this.copyMenuItem.Index = 3; + this.copyMenuItem.Text = "&Copy"; + // + // progress + // + this.progress.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.progress.Location = new System.Drawing.Point(50, 11); + this.progress.Name = "progress"; + this.progress.Size = new System.Drawing.Size(395, 23); + this.progress.TabIndex = 4; + this.progress.Visible = false; + // + // vistaMenu + // + this.vistaMenu.ContainerControl = this; + this.vistaMenu.DelaySetImageCalls = false; + // + // HandleFilterWindow + // + this.AcceptButton = this.buttonFind; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(538, 427); + this.Controls.Add(this.progress); + this.Controls.Add(this.listHandles); + this.Controls.Add(this.buttonFind); + this.Controls.Add(this.textFilter); + this.Controls.Add(this.label1); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Name = "HandleFilterWindow"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Find Handles or DLLs"; + this.Load += new System.EventHandler(this.HandleFilterWindow_Load); + this.VisibleChanged += new System.EventHandler(this.HandleFilterWindow_VisibleChanged); + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.HandleFilterWindow_FormClosing); + ((System.ComponentModel.ISupportInitialize)(this.vistaMenu)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox textFilter; + private System.Windows.Forms.Button buttonFind; + private System.Windows.Forms.ListView listHandles; + private System.Windows.Forms.ColumnHeader columnProcess; + private System.Windows.Forms.ColumnHeader columnType; + private System.Windows.Forms.ColumnHeader columnName; + private System.Windows.Forms.ColumnHeader columnHandle; + private System.Windows.Forms.ContextMenu menuHandle; + private System.Windows.Forms.MenuItem closeMenuItem; + private wyDay.Controls.VistaMenu vistaMenu; + private System.Windows.Forms.MenuItem copyMenuItem; + private System.Windows.Forms.ProgressBar progress; + private System.Windows.Forms.MenuItem propertiesMenuItem; + private System.Windows.Forms.MenuItem processPropertiesMenuItem; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/HandleFilterWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/HandleFilterWindow.cs new file mode 100644 index 000000000..dfc9ca586 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/HandleFilterWindow.cs @@ -0,0 +1,333 @@ +/* + * Process Hacker - + * handle filter user interface + * + * Copyright (C) 2008 Dean + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Common.Ui; +using ProcessHacker.Components; +using ProcessHacker.FormHelper; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; +using ProcessHacker.UI; +using ProcessHacker.UI.Actions; + +namespace ProcessHacker +{ + public partial class HandleFilterWindow : Form + { + private HandleFilter currWorker; + + public HandleFilterWindow() + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + listHandles.SetDoubleBuffered(true); + listHandles.SetTheme("explorer"); + GenericViewMenu.AddMenuItems(copyMenuItem.MenuItems, listHandles, null); + listHandles.ContextMenu = menuHandle; + + var comparer = (SortedListViewComparer)(listHandles.ListViewItemSorter = new SortedListViewComparer(listHandles)); + + comparer.ColumnSortOrder.Add(0); + comparer.ColumnSortOrder.Add(1); + comparer.ColumnSortOrder.Add(2); + comparer.ColumnSortOrder.Add(3); + } + + private void HandleFilterWindow_Load(object sender, EventArgs e) + { + ColumnSettings.LoadSettings(Properties.Settings.Default.HandleFilterWindowListViewColumns, listHandles); + this.Size = Properties.Settings.Default.HandleFilterWindowSize; + this.Location = Utils.FitRectangle(new System.Drawing.Rectangle( + Properties.Settings.Default.HandleFilterWindowLocation, this.Size), this).Location; + listHandles.AddShortcuts(); + } + + private void HandleFilterWindow_FormClosing(object sender, FormClosingEventArgs e) + { + if (OSVersion.HasExtendedTaskbar) + { + TaskbarLib.Windows7Taskbar.SetTaskbarProgressState( + Program.HackerWindowHandle, + TaskbarLib.Windows7Taskbar.ThumbnailProgressState.NoProgress + ); + } + + Properties.Settings.Default.HandleFilterWindowListViewColumns = ColumnSettings.SaveSettings(listHandles); + + if (this.WindowState == FormWindowState.Normal) + { + Properties.Settings.Default.HandleFilterWindowSize = this.Size; + Properties.Settings.Default.HandleFilterWindowLocation = this.Location; + } + + e.Cancel = true; + this.Visible = false; + } + + private void HandleFilterWindow_VisibleChanged(object sender, EventArgs e) + { + if (this.Visible) + { + this.SetPhParent(); + textFilter.SelectAll(); + } + } + + private void menuHandle_Popup(object sender, EventArgs e) + { + if (listHandles.SelectedItems.Count == 0) + { + menuHandle.DisableAll(); + } + else if (listHandles.SelectedItems.Count == 1) + { + menuHandle.EnableAll(); + + string type = listHandles.SelectedItems[0].SubItems[1].Text; + + if (type == "DLL" || type == "Mapped File") + closeMenuItem.Enabled = false; + } + else + { + menuHandle.EnableAll(); + processPropertiesMenuItem.Enabled = false; + propertiesMenuItem.Enabled = false; + } + } + + private void closeMenuItem_Click(object sender, EventArgs e) + { + List remove = new List(); + + foreach (int index in listHandles.SelectedIndices) + { + if (listHandles.Items[index].SubItems[1].Text == "DLL" || + listHandles.Items[index].SubItems[1].Text == "Mapped File") + continue; + + try + { + IntPtr handle = new IntPtr((int)BaseConverter.ToNumberParse(listHandles.Items[index].SubItems[3].Text)); + + using (ProcessHandle process = + new ProcessHandle(((SystemHandleEntry)listHandles.SelectedItems[0].Tag).ProcessId, + ProcessAccess.DupHandle)) + { + Win32.DuplicateObject(process.Handle, handle, 0, 0, DuplicateOptions.CloseSource); + remove.Add(listHandles.Items[index]); + } + } + catch (Exception ex) + { + if (!PhUtils.ShowContinueMessage( + "Unable to close the handle \"" + listHandles.Items[index].SubItems[2].Text + "\"", + ex + )) + return; + } + } + + foreach (ListViewItem item in remove) + item.Remove(); + } + + private void buttonFind_Click(object sender, EventArgs e) + { + if (currWorker == null) + { + progress.Visible = true; + progress.Minimum = 0; + listHandles.Items.Clear(); + currWorker = new HandleFilter(this, textFilter.Text); + currWorker.Completed += new EventHandler(Filter_Finished); + currWorker.Cancelled += new EventHandler(Filter_Cancelled); + currWorker.MatchListView += new HandleFilter.MatchListViewEvent(ListView_Result); + currWorker.MatchProgress += new HandleFilter.MatchProgressEvent(Progress_Result); + currWorker.Failed += new System.Threading.ThreadExceptionEventHandler(Filter_Failed); + buttonFind.Text = "&Cancel"; + Cursor = Cursors.AppStarting; + currWorker.Start(); + } + else + { + if (OSVersion.HasExtendedTaskbar) + { + TaskbarLib.Windows7Taskbar.SetTaskbarProgressState( + Program.HackerWindowHandle, + TaskbarLib.Windows7Taskbar.ThumbnailProgressState.NoProgress + ); + } + + progress.Visible = false; + Cursor = Cursors.WaitCursor; + currWorker.CancelAndWait(); + Cursor = Cursors.Default; + } + } + + private void Filter_Finished(object sender, EventArgs e) + { + progress.Visible = false; + ResetCtls(); + } + + private void Filter_Cancelled(object sender, EventArgs e) + { + ResetCtls(); + } + + private void Filter_Failed(object sender, System.Threading.ThreadExceptionEventArgs e) + { + progress.Visible = false; + ResetCtls(); + //log + } + + private void ResetCtls() + { + if (OSVersion.HasExtendedTaskbar) + { + TaskbarLib.Windows7Taskbar.SetTaskbarProgressState( + Program.HackerWindowHandle, + TaskbarLib.Windows7Taskbar.ThumbnailProgressState.NoProgress + ); + } + + buttonFind.Text = "&Find"; + currWorker = null; + Cursor = Cursors.Default; + } + + private void ListView_Result(List items) + { + listHandles.Items.AddRange(items.ToArray()); + } + + private void Progress_Result(int currentValue, int count) + { + progress.Value = currentValue; + progress.Maximum = count; + + if (OSVersion.HasExtendedTaskbar) + { + TaskbarLib.Windows7Taskbar.SetTaskbarProgress( + Program.HackerWindowHandle, + (ulong)currentValue, + (ulong)count + ); + } + } + + private void processPropertiesMenuItem_Click(object sender, EventArgs e) + { + string type = listHandles.SelectedItems[0].SubItems[1].Text; + int pid; + + if (type == "DLL" || type == "Mapped File") + pid = (int)listHandles.SelectedItems[0].Tag; + else + pid = ((SystemHandleEntry)listHandles.SelectedItems[0].Tag).ProcessId; + + if (Program.ProcessProvider.Dictionary.ContainsKey(pid)) + { + ProcessActions.ShowProperties(this, pid, Program.ProcessProvider.Dictionary[pid].Name); + } + else + { + PhUtils.ShowError("The process does not exist."); + } + } + + private void propertiesMenuItem_Click(object sender, EventArgs e) + { + string type = listHandles.SelectedItems[0].SubItems[1].Text; + + if (type == "DLL" || type == "Mapped File") + { + FileUtils.ShowProperties(listHandles.SelectedItems[0].SubItems[2].Text); + return; + } + + try + { + HandleList.ShowHandleProperties( + (SystemHandleEntry)listHandles.SelectedItems[0].Tag + ); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to show handle properties", ex); + } + } + + private void listHandles_DoubleClick(object sender, EventArgs e) + { + propertiesMenuItem_Click(sender, e); + } + + private void listHandles_KeyDown(object sender, KeyEventArgs e) + { + if (e.KeyCode == Keys.Delete) + { + if (listHandles.SelectedIndices.Count == 0) + return; + + if (HandleList.ConfirmHandleClose()) + { + closeMenuItem_Click(sender, null); + } + } + } + + private void textFilter_TextChanged(object sender, EventArgs e) + { + if (textFilter.Text == "") + buttonFind.Enabled = false; + else + buttonFind.Enabled = true; + } + + private void textFilter_Enter(object sender, EventArgs e) + { + // Select all *after* this event, since the selection due to + // the user's mouse click will be made after this code + // executes. + this.BeginInvoke(new MethodInvoker(textFilter.SelectAll)); + } + + private void textFilter_KeyPress(object sender, KeyPressEventArgs e) + { + // Prevent the beep when the user presses Escape. + if (e.KeyChar == (char)Keys.Escape) + e.Handled = true; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/HandleFilterWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/HandleFilterWindow.resx new file mode 100644 index 000000000..f917f4d06 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/HandleFilterWindow.resx @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 138, 17 + + + + + AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAANadccTTmG300ZVn/86RYv/LjV3/yYla/8eGVf/Cg1H/woNR/8KDUf/Cg1H/woNR/8KD + Uf+6dkGwAAAAAAAAAADXoHT/+PLt//fw6v/27eb/9Ori//Pn3v/x5Nv/8OLY//Di2P/w4tj/8OLY//Di + 2P/w4tj/xIlc/QAAAAAAAAAA2aN5//nz7v/r0r3//////+vTvv/////////////////qx6z///////// + ////////8OLY/8WLXv8AAAAAAAAAAN2nff/58+//69C5/+vQuv/r0Lr/69C6/+vQuv/r0bz/6s20/+rN + tP/qzbT/6s20//Di2P/FiVv/AAAAAAAAAADfqYH/+fPv/+rOtv//////69C6/////////////////+rP + uf/79vL////////////w4tj/yIxe/wAAAAAAAAAA4a2G//r08P/qy7H/6syy/+rMsv/qzLL/6syy/+rO + tv/ox6v/6Mer/+jIr//oyK3/8OLY/8OFU/8AAAAAAAAAAOOwi//69vH/6smt///////qya////////// + ////////6Mer//////////////////Hl2//FhVT/AAAAAAAAAADls47/+vby/+nFqf/pxav/6ser/+nH + rP/pya3/6cmv/+jHq//pya//6Miv/+jMtP/y597/yIlY/wAAAAAAAAAA57aT//v39P/pwqX//////+jD + qP/////////////////ox6v/////////////////9/Hr/8uOXv8AAAAAAAAAAOm5l//79/T/6cKl/+nC + pf/pwqX/6cKl/+nCpf/pwqX/6cKl/+nCpf/pwqX/6cKl//v39P/OkmP/AAAAAAAAAADrvJr/+/f0//// + ///////////////////////////////////////////////////79/T/0ZZp/wAAAAAAAAAA7L6d//v3 + 9P+b1aT/l9Og/5PQnP+Pzpf/isuS/4bJjf+BxYj/fcKD/3nAf/91vXv/+/f0/9Sabv8AAAAAAAAAAO7A + oOv79/T/+/f0//v39P/79/T/+/f0//v39P/79/T/+/f0//v39P/79/T/+/f0//v39P/Xn3P4AAAAAAAA + AADvwaJ+78Ch4+2/nv/rvZz/67uZ/+m5lf/ntpL/5rSP/+Sxi//irof/4KuD/92of//cpHz/2qJ5ygAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA//+sQYABrEGAAaxBgAGsQYABrEGAAaxBgAGsQYABrEGAAaxBgAGsQYABrEGAAaxBgAGsQYAB + rEGAAaxB//+sQQ== + + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/HandleStatisticsWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/HandleStatisticsWindow.Designer.cs new file mode 100644 index 000000000..1272243fe --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/HandleStatisticsWindow.Designer.cs @@ -0,0 +1,104 @@ +namespace ProcessHacker +{ + partial class HandleStatisticsWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.buttonClose = new System.Windows.Forms.Button(); + this.listTypes = new System.Windows.Forms.ListView(); + this.columnType = new System.Windows.Forms.ColumnHeader(); + this.columnNumber = new System.Windows.Forms.ColumnHeader(); + this.SuspendLayout(); + // + // buttonClose + // + this.buttonClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonClose.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonClose.Location = new System.Drawing.Point(264, 268); + this.buttonClose.Name = "buttonClose"; + this.buttonClose.Size = new System.Drawing.Size(75, 23); + this.buttonClose.TabIndex = 0; + this.buttonClose.Text = "Close"; + this.buttonClose.UseVisualStyleBackColor = true; + this.buttonClose.Click += new System.EventHandler(this.buttonClose_Click); + // + // listTypes + // + this.listTypes.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listTypes.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnType, + this.columnNumber}); + this.listTypes.FullRowSelect = true; + this.listTypes.HideSelection = false; + this.listTypes.Location = new System.Drawing.Point(12, 12); + this.listTypes.Name = "listTypes"; + this.listTypes.ShowItemToolTips = true; + this.listTypes.Size = new System.Drawing.Size(327, 250); + this.listTypes.Sorting = System.Windows.Forms.SortOrder.Ascending; + this.listTypes.TabIndex = 1; + this.listTypes.UseCompatibleStateImageBehavior = false; + this.listTypes.View = System.Windows.Forms.View.Details; + // + // columnType + // + this.columnType.Text = "Type"; + this.columnType.Width = 150; + // + // columnNumber + // + this.columnNumber.Text = "Number"; + this.columnNumber.Width = 100; + // + // HandleStatisticsWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(351, 303); + this.Controls.Add(this.listTypes); + this.Controls.Add(this.buttonClose); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "HandleStatisticsWindow"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Handle Statistics"; + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Button buttonClose; + private System.Windows.Forms.ListView listTypes; + private System.Windows.Forms.ColumnHeader columnType; + private System.Windows.Forms.ColumnHeader columnNumber; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/HandleStatisticsWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/HandleStatisticsWindow.cs new file mode 100644 index 000000000..8431841c0 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/HandleStatisticsWindow.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Common.Ui; +using ProcessHacker.Native; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; +using ProcessHacker.UI; + +namespace ProcessHacker +{ + public partial class HandleStatisticsWindow : Form + { + private int _pid; + + public HandleStatisticsWindow(int pid) + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + _pid = pid; + + listTypes.SetDoubleBuffered(true); + listTypes.SetTheme("explorer"); + listTypes.AddShortcuts(); + listTypes.ContextMenu = listTypes.GetCopyMenu(); + listTypes.ListViewItemSorter = new SortedListViewComparer(listTypes); + + var typeStats = new Dictionary(); + + using (var phandle = new ProcessHandle(pid, ProcessAccess.DupHandle)) + { + var handles = Windows.GetHandles(); + + foreach (var handle in handles) + { + if (pid != -1 && handle.ProcessId != pid) + continue; + + ObjectInformation info; + + try + { + if (pid != -1) + { + info = handle.GetHandleInfo(phandle, false); + } + else + { + info = handle.GetHandleInfo(false); + } + } + catch (Exception ex) + { + Logging.Log(ex); + info = new ObjectInformation() { TypeName = "(unknown)" }; + } + + if (typeStats.ContainsKey(info.TypeName)) + typeStats[info.TypeName]++; + else + typeStats.Add(info.TypeName, 1); + } + } + + foreach (var pair in typeStats) + { + listTypes.Items.Add(new ListViewItem(new string[] + { + pair.Key, + pair.Value.ToString("N0") + })); + } + } + + private void buttonClose_Click(object sender, System.EventArgs e) + { + this.Close(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/HandleStatisticsWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/HandleStatisticsWindow.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/HandleStatisticsWindow.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/HeapsWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/HeapsWindow.Designer.cs new file mode 100644 index 000000000..01a3f1238 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/HeapsWindow.Designer.cs @@ -0,0 +1,173 @@ +namespace ProcessHacker +{ + partial class HeapsWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.buttonClose = new System.Windows.Forms.Button(); + this.listHeaps = new System.Windows.Forms.ListView(); + this.columnAddress = new System.Windows.Forms.ColumnHeader(); + this.columnUsed = new System.Windows.Forms.ColumnHeader(); + this.columnCommitted = new System.Windows.Forms.ColumnHeader(); + this.columnEntries = new System.Windows.Forms.ColumnHeader(); + this.menuHeap = new System.Windows.Forms.ContextMenu(); + this.destroyMenuItem = new System.Windows.Forms.MenuItem(); + this.copyMenuItem = new System.Windows.Forms.MenuItem(); + this.vistaMenu = new wyDay.Controls.VistaMenu(this.components); + this.checkSizesInBytes = new System.Windows.Forms.CheckBox(); + ((System.ComponentModel.ISupportInitialize)(this.vistaMenu)).BeginInit(); + this.SuspendLayout(); + // + // buttonClose + // + this.buttonClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonClose.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonClose.Location = new System.Drawing.Point(416, 419); + this.buttonClose.Name = "buttonClose"; + this.buttonClose.Size = new System.Drawing.Size(75, 23); + this.buttonClose.TabIndex = 2; + this.buttonClose.Text = "Close"; + this.buttonClose.UseVisualStyleBackColor = true; + this.buttonClose.Click += new System.EventHandler(this.buttonClose_Click); + // + // listHeaps + // + this.listHeaps.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listHeaps.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnAddress, + this.columnUsed, + this.columnCommitted, + this.columnEntries}); + this.listHeaps.FullRowSelect = true; + this.listHeaps.HideSelection = false; + this.listHeaps.Location = new System.Drawing.Point(12, 12); + this.listHeaps.Name = "listHeaps"; + this.listHeaps.Size = new System.Drawing.Size(479, 401); + this.listHeaps.TabIndex = 0; + this.listHeaps.UseCompatibleStateImageBehavior = false; + this.listHeaps.View = System.Windows.Forms.View.Details; + // + // columnAddress + // + this.columnAddress.Text = "Address"; + this.columnAddress.Width = 80; + // + // columnUsed + // + this.columnUsed.Text = "Used"; + this.columnUsed.Width = 140; + // + // columnCommitted + // + this.columnCommitted.Text = "Committed"; + this.columnCommitted.Width = 140; + // + // columnEntries + // + this.columnEntries.Text = "Entries"; + // + // menuHeap + // + this.menuHeap.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.destroyMenuItem, + this.copyMenuItem}); + this.menuHeap.Popup += new System.EventHandler(this.menuHeap_Popup); + // + // destroyMenuItem + // + this.vistaMenu.SetImage(this.destroyMenuItem, global::ProcessHacker.Properties.Resources.cross); + this.destroyMenuItem.Index = 0; + this.destroyMenuItem.Text = "&Destroy"; + this.destroyMenuItem.Click += new System.EventHandler(this.destroyMenuItem_Click); + // + // copyMenuItem + // + this.vistaMenu.SetImage(this.copyMenuItem, global::ProcessHacker.Properties.Resources.page_copy); + this.copyMenuItem.Index = 1; + this.copyMenuItem.Text = "&Copy"; + // + // vistaMenu + // + this.vistaMenu.ContainerControl = this; + this.vistaMenu.DelaySetImageCalls = false; + // + // checkSizesInBytes + // + this.checkSizesInBytes.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.checkSizesInBytes.AutoSize = true; + this.checkSizesInBytes.Checked = true; + this.checkSizesInBytes.CheckState = System.Windows.Forms.CheckState.Checked; + this.checkSizesInBytes.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkSizesInBytes.Location = new System.Drawing.Point(12, 423); + this.checkSizesInBytes.Name = "checkSizesInBytes"; + this.checkSizesInBytes.Size = new System.Drawing.Size(96, 18); + this.checkSizesInBytes.TabIndex = 1; + this.checkSizesInBytes.Text = "Sizes in bytes"; + this.checkSizesInBytes.UseVisualStyleBackColor = true; + this.checkSizesInBytes.CheckedChanged += new System.EventHandler(this.checkSizesInBytes_CheckedChanged); + // + // HeapsWindow + // + this.AcceptButton = this.buttonClose; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(503, 454); + this.Controls.Add(this.checkSizesInBytes); + this.Controls.Add(this.listHeaps); + this.Controls.Add(this.buttonClose); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "HeapsWindow"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Process Heaps"; + ((System.ComponentModel.ISupportInitialize)(this.vistaMenu)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button buttonClose; + private System.Windows.Forms.ListView listHeaps; + private System.Windows.Forms.ColumnHeader columnAddress; + private System.Windows.Forms.ColumnHeader columnUsed; + private System.Windows.Forms.ColumnHeader columnCommitted; + private System.Windows.Forms.ColumnHeader columnEntries; + private System.Windows.Forms.ContextMenu menuHeap; + private System.Windows.Forms.MenuItem destroyMenuItem; + private wyDay.Controls.VistaMenu vistaMenu; + private System.Windows.Forms.MenuItem copyMenuItem; + private System.Windows.Forms.CheckBox checkSizesInBytes; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/HeapsWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/HeapsWindow.cs new file mode 100644 index 000000000..e3f0b3025 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/HeapsWindow.cs @@ -0,0 +1,209 @@ +/* + * Process Hacker - + * heaps window + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Drawing; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Common.Ui; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Debugging; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; +using ProcessHacker.UI; + +namespace ProcessHacker +{ + public partial class HeapsWindow : Form + { + private int _pid; + + public HeapsWindow(int pid, HeapInformation[] heaps) + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + listHeaps.SetDoubleBuffered(true); + listHeaps.SetTheme("explorer"); + listHeaps.AddShortcuts(); + listHeaps.ContextMenu = menuHeap; + GenericViewMenu.AddMenuItems(copyMenuItem.MenuItems, listHeaps, null); + + // Native threads don't work properly on XP. + if (OSVersion.IsBelowOrEqual(WindowsVersion.XP)) + destroyMenuItem.Visible = false; + + var comparer = new SortedListViewComparer(listHeaps); + listHeaps.ListViewItemSorter = comparer; + comparer.CustomSorters.Add(1, (l1, l2) => + { + HeapInformation heap1 = l1.Tag as HeapInformation; + HeapInformation heap2 = l2.Tag as HeapInformation; + + return heap1.BytesAllocated.CompareTo(heap2.BytesAllocated); + }); + comparer.CustomSorters.Add(2, (l1, l2) => + { + HeapInformation heap1 = l1.Tag as HeapInformation; + HeapInformation heap2 = l2.Tag as HeapInformation; + + return heap1.BytesCommitted.CompareTo(heap2.BytesCommitted); + }); + + _pid = pid; + + IntPtr defaultHeap = IntPtr.Zero; + + try + { + using (var phandle = new ProcessHandle( + pid, + Program.MinProcessQueryRights | Program.MinProcessReadMemoryRights)) + defaultHeap = phandle.GetHeap(); + } + catch (WindowsException) + { } + + long allocatedTotal = 0, committedTotal = 0; + int entriesTotal = 0, tagsTotal = 0, pseudoTagsTotal = 0; + + foreach (HeapInformation heap in heaps) + { + ListViewItem litem = listHeaps.Items.Add(new ListViewItem( + new string[] + { + Utils.FormatAddress(heap.Address), + heap.BytesAllocated.ToString("N0") + " B", + heap.BytesCommitted.ToString("N0") + " B", + heap.EntryCount.ToString("N0") + //heap.TagCount.ToString("N0"), + //heap.PseudoTagCount.ToString("N0") + })); + + litem.Tag = heap; + // Make the default heap bold. + if (heap.Address == defaultHeap) + litem.Font = new Font(litem.Font, FontStyle.Bold); + + // Sum everything up. + allocatedTotal += heap.BytesAllocated; + committedTotal += heap.BytesCommitted; + entriesTotal += heap.EntryCount; + tagsTotal += heap.TagCount; + pseudoTagsTotal += heap.PseudoTagCount; + } + + // Totals row. + listHeaps.Items.Add(new ListViewItem( + new string[] + { + "Totals", + allocatedTotal.ToString("N0") + " B", + committedTotal.ToString("N0") + " B", + entriesTotal.ToString("N0") + //tagsTotal.ToString("N0"), + //pseudoTagsTotal.ToString("N0") + })).Tag = new HeapInformation( + IntPtr.Zero, allocatedTotal, committedTotal, + tagsTotal, entriesTotal, pseudoTagsTotal + ); + } + + private void buttonClose_Click(object sender, EventArgs e) + { + this.Close(); + } + + private void menuHeap_Popup(object sender, EventArgs e) + { + if (listHeaps.SelectedItems.Count == 0) + { + menuHeap.DisableAll(); + } + else if (listHeaps.SelectedItems.Count == 1) + { + menuHeap.EnableAll(); + + if (listHeaps.SelectedItems[0].Text == "Totals") + destroyMenuItem.Enabled = false; + } + else + { + menuHeap.DisableAll(); + copyMenuItem.Enabled = true; + } + } + + private void destroyMenuItem_Click(object sender, EventArgs e) + { + if (!PhUtils.ShowConfirmMessage( + "destroy", + "the selected heap", + "Destroying a heap may cause the process to crash.", + true + )) + return; + + try + { + using (var phandle = new ProcessHandle(_pid, + ProcessAccess.CreateThread | ProcessAccess.QueryInformation | ProcessAccess.VmOperation)) + { + // Use RtlCreateUserThread to cross session boundaries. RtlDestroyHeap doesn't need + // the Win32 subsystem so we don't have to notify CSR. + phandle.CreateThread( + Win32.GetProcAddress(Win32.GetModuleHandle("ntdll.dll"), "RtlDestroyHeap"), + ((HeapInformation)listHeaps.SelectedItems[0].Tag).Address + ).Dispose(); + } + + listHeaps.SelectedItems[0].ForeColor = Color.Red; + listHeaps.SelectedItems.Clear(); + } + catch (WindowsException ex) + { + PhUtils.ShowException("Unable to destroy the heap", ex); + } + } + + private void checkSizesInBytes_CheckedChanged(object sender, EventArgs e) + { + foreach (ListViewItem item in listHeaps.Items) + { + HeapInformation heap = item.Tag as HeapInformation; + + if (checkSizesInBytes.Checked) + { + item.SubItems[1].Text = heap.BytesAllocated.ToString("N0") + " B"; + item.SubItems[2].Text = heap.BytesCommitted.ToString("N0") + " B"; + } + else + { + item.SubItems[1].Text = Utils.FormatSize(heap.BytesAllocated); + item.SubItems[2].Text = Utils.FormatSize(heap.BytesCommitted); + } + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/HeapsWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/HeapsWindow.resx new file mode 100644 index 000000000..aae741422 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/HeapsWindow.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 128, 17 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/HelpWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/HelpWindow.Designer.cs new file mode 100644 index 000000000..a7872fa97 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/HelpWindow.Designer.cs @@ -0,0 +1,84 @@ +namespace ProcessHacker +{ + partial class HelpWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(HelpWindow)); + this.webBrowser = new System.Windows.Forms.WebBrowser(); + this.listBoxContents = new System.Windows.Forms.ListBox(); + this.SuspendLayout(); + // + // webBrowser + // + this.webBrowser.AllowNavigation = false; + this.webBrowser.AllowWebBrowserDrop = false; + this.webBrowser.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.webBrowser.IsWebBrowserContextMenuEnabled = false; + this.webBrowser.Location = new System.Drawing.Point(201, 12); + this.webBrowser.MinimumSize = new System.Drawing.Size(20, 20); + this.webBrowser.Name = "webBrowser"; + this.webBrowser.Size = new System.Drawing.Size(535, 490); + this.webBrowser.TabIndex = 0; + this.webBrowser.PreviewKeyDown += new System.Windows.Forms.PreviewKeyDownEventHandler(this.webBrowser_PreviewKeyDown); + // + // listBoxContents + // + this.listBoxContents.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left))); + this.listBoxContents.FormattingEnabled = true; + this.listBoxContents.IntegralHeight = false; + this.listBoxContents.Location = new System.Drawing.Point(12, 12); + this.listBoxContents.Name = "listBoxContents"; + this.listBoxContents.Size = new System.Drawing.Size(183, 490); + this.listBoxContents.TabIndex = 1; + this.listBoxContents.SelectedIndexChanged += new System.EventHandler(this.listBoxContents_SelectedIndexChanged); + // + // HelpWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(748, 514); + this.Controls.Add(this.listBoxContents); + this.Controls.Add(this.webBrowser); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Name = "HelpWindow"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Help"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.HelpWindow_FormClosing); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.WebBrowser webBrowser; + private System.Windows.Forms.ListBox listBoxContents; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/HelpWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/HelpWindow.cs new file mode 100644 index 000000000..a73343122 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/HelpWindow.cs @@ -0,0 +1,107 @@ +/* + * Process Hacker - + * help window + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.IO; +using System.Reflection; +using System.Windows.Forms; + +namespace ProcessHacker +{ + public partial class HelpWindow : Form + { + public string[][] contents = { + new string[] {"Introduction", "intro"}, + new string[] {"Options", "options"}, + new string[] {"Number Input", "numberinput"}, + new string[] {"Process Tree", "proctree"}, + new string[] {"Process Properties", "procprops"}, + new string[] {"Searching Memory", "memsearch"}, + new string[] {"Results Window", "results"}, + new string[] {"Glossary", "glossary"}, + new string[] {"Copyright Information", "copyright"} + }; + + public HelpWindow() + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + Assembly assembly = Assembly.GetExecutingAssembly(); + Stream resource = assembly.GetManifestResourceStream(assembly.GetName().Name + ".Help.htm"); + + webBrowser.DocumentStream = resource; + + foreach (string[] s in contents) + { + listBoxContents.Items.Add(s[0]); + } + + webBrowser.Navigating += (sender, e) => e.Cancel = true; + } + + private void listBoxContents_SelectedIndexChanged(object sender, EventArgs e) + { + if (listBoxContents.SelectedItems.Count == 1) + { + foreach (string[] s in contents) + { + if (s[0] == listBoxContents.SelectedItem.ToString()) + { + HtmlElement element = webBrowser.Document.GetElementById(s[1]); + + if (element != null) + element.ScrollIntoView(true); + + break; + } + } + } + } + + public void SelectById(string id) + { + webBrowser.Document.GetElementById(id).ScrollIntoView(true); + } + + private void HelpWindow_FormClosing(object sender, FormClosingEventArgs e) + { + e.Cancel = true; + + this.Hide(); + } + + private void webBrowser_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e) + { + // HACK + if (e.KeyData != Keys.F5) + { + webBrowser.WebBrowserShortcutsEnabled = true; + } + else + { + webBrowser.WebBrowserShortcutsEnabled = false; + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/HelpWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/HelpWindow.resx new file mode 100644 index 000000000..a9216861a --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/HelpWindow.resx @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAKxzQyOrcUB9qW8+26dsO/OmajnzpGg226NnNH2iZTIjAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAALR9UFOye03m17qi/+nayv/s4NH/7ODR/+jYyP/TtJv/pms55qVp + N1MAAAAAAAAAAAAAAAAAAAAAAAAAALyIXlO6hlr059XD/+XSvv/JpYT/t41m/7WJZP/EoH//4My5/+PQ + vf+qbz/0qG08UwAAAAAAAAAAAAAAAMWUbCLCkWnl6tjJ/+PNuf+/k2r/uYth/8+vk//Pr5P/tohe/7GG + YP/av6n/5NG//610ReWsckIiAAAAAAAAAADMnXd+5My4/+rWxP/HmHD/vo9l/76PZf/38ez/9vDq/7aI + Xv+2iF7/tIhi/+LOuv/ZvKX/sXpMfgAAAAAAAAAA06aD2+/h0//ZtJT/x5dr/8KUaP/Akmb/vo9l/76P + Zf+6imL/uIli/7eJYf/LpoX/6tzM/7eCVtsAAAAAAAAAANmvjvby5Nn/0aR5/8SYav/Dlmn/w5Vo//r2 + 8v/z6uH/wZRs/72OZP+9jmP/v5Rs/+/j1f++i2D2AAAAAAAAAADguJj28uXa/9Glff/MnHD/x5lr/8SX + av/izLX/+PPu//bu6P/ZvKD/wZNn/8SacP/w4tb/xJRr9gAAAAAAAAAA5sCi2/Pl2f/fup3/z590/82d + cf/16+P/5Muz/+fTvv/7+Pb/5dO+/8OXav/Ws5D/7uDS/8ydd9sAAAAAAAAAAOvJrH7049T/79zN/9Wn + ff/Qn3b/+/j1//z49f/8+PX/+/j1/9GngP/Po3r/6tXC/+rUwf/SpoJ+AAAAAAAAAADx0LQi786y5fbp + 3f/s2MX/16uA/9y6mf/27OP/9ezi/+TIrf/Spnr/5s65//Hi1f/bspDl2a+NIgAAAAAAAAAAAAAAAPTU + ulPy0rf09+rf/+7e0P/jwKb/2K2I/9erhf/dupv/69bH//Pm2f/jvZ704bqbUwAAAAAAAAAAAAAAAAAA + AAAAAAAA9ti+U/XWvOb56dz/9ujd//Pl2v/z5dr/9efc//Xk1v/ryKvm6cWoUwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAD528Mj+NrBfffYv9v2173z9NW78/PTuNvx0bZ98M+zIwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA//+sQfAPrEHgB6xBwAOsQYABrEGAAaxBgAGsQYABrEGAAaxBgAGsQYABrEGAAaxBwAOsQeAH + rEHwD6xB//+sQQ== + + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/HiddenProcessesWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/HiddenProcessesWindow.Designer.cs new file mode 100644 index 000000000..73655bf0d --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/HiddenProcessesWindow.Designer.cs @@ -0,0 +1,195 @@ +namespace ProcessHacker +{ + partial class HiddenProcessesWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(HiddenProcessesWindow)); + this.listProcesses = new System.Windows.Forms.ListView(); + this.columnProcess = new System.Windows.Forms.ColumnHeader(); + this.columnPID = new System.Windows.Forms.ColumnHeader(); + this.buttonClose = new System.Windows.Forms.Button(); + this.buttonScan = new System.Windows.Forms.Button(); + this.label2 = new System.Windows.Forms.Label(); + this.buttonTerminate = new System.Windows.Forms.Button(); + this.buttonSave = new System.Windows.Forms.Button(); + this.labelCount = new System.Windows.Forms.Label(); + this.comboMethod = new System.Windows.Forms.ComboBox(); + this.SuspendLayout(); + // + // listProcesses + // + this.listProcesses.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listProcesses.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnProcess, + this.columnPID}); + this.listProcesses.FullRowSelect = true; + this.listProcesses.HideSelection = false; + this.listProcesses.Location = new System.Drawing.Point(12, 44); + this.listProcesses.Name = "listProcesses"; + this.listProcesses.ShowItemToolTips = true; + this.listProcesses.Size = new System.Drawing.Size(487, 296); + this.listProcesses.Sorting = System.Windows.Forms.SortOrder.Ascending; + this.listProcesses.TabIndex = 1; + this.listProcesses.UseCompatibleStateImageBehavior = false; + this.listProcesses.View = System.Windows.Forms.View.Details; + this.listProcesses.SelectedIndexChanged += new System.EventHandler(this.listProcesses_SelectedIndexChanged); + // + // columnProcess + // + this.columnProcess.Text = "Process"; + this.columnProcess.Width = 340; + // + // columnPID + // + this.columnPID.Text = "PID"; + // + // buttonClose + // + this.buttonClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonClose.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonClose.Location = new System.Drawing.Point(424, 361); + this.buttonClose.Name = "buttonClose"; + this.buttonClose.Size = new System.Drawing.Size(75, 23); + this.buttonClose.TabIndex = 7; + this.buttonClose.Text = "&Close"; + this.buttonClose.UseVisualStyleBackColor = true; + this.buttonClose.Click += new System.EventHandler(this.buttonClose_Click); + // + // buttonScan + // + this.buttonScan.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonScan.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonScan.Location = new System.Drawing.Point(343, 361); + this.buttonScan.Name = "buttonScan"; + this.buttonScan.Size = new System.Drawing.Size(75, 23); + this.buttonScan.TabIndex = 6; + this.buttonScan.Text = "&Scan"; + this.buttonScan.UseVisualStyleBackColor = true; + this.buttonScan.Click += new System.EventHandler(this.buttonScan_Click); + // + // label2 + // + this.label2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label2.AutoEllipsis = true; + this.label2.Location = new System.Drawing.Point(12, 9); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(487, 32); + this.label2.TabIndex = 0; + this.label2.Text = "Processes highlighted red are hidden while those highlighted gray have terminated" + + " but are still being referenced by other processes."; + // + // buttonTerminate + // + this.buttonTerminate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonTerminate.Enabled = false; + this.buttonTerminate.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonTerminate.Location = new System.Drawing.Point(181, 361); + this.buttonTerminate.Name = "buttonTerminate"; + this.buttonTerminate.Size = new System.Drawing.Size(75, 23); + this.buttonTerminate.TabIndex = 4; + this.buttonTerminate.Text = "T&erminate"; + this.buttonTerminate.UseVisualStyleBackColor = true; + this.buttonTerminate.Click += new System.EventHandler(this.buttonTerminate_Click); + // + // buttonSave + // + this.buttonSave.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonSave.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonSave.Location = new System.Drawing.Point(262, 361); + this.buttonSave.Name = "buttonSave"; + this.buttonSave.Size = new System.Drawing.Size(75, 23); + this.buttonSave.TabIndex = 5; + this.buttonSave.Text = "Save..."; + this.buttonSave.UseVisualStyleBackColor = true; + this.buttonSave.Click += new System.EventHandler(this.buttonSave_Click); + // + // labelCount + // + this.labelCount.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.labelCount.Location = new System.Drawing.Point(12, 343); + this.labelCount.Name = "labelCount"; + this.labelCount.Size = new System.Drawing.Size(487, 15); + this.labelCount.TabIndex = 2; + this.labelCount.Text = "Count"; + this.labelCount.TextAlign = System.Drawing.ContentAlignment.TopRight; + // + // comboMethod + // + this.comboMethod.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.comboMethod.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboMethod.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.comboMethod.FormattingEnabled = true; + this.comboMethod.Items.AddRange(new object[] { + "Brute Force", + "CSR Handles"}); + this.comboMethod.Location = new System.Drawing.Point(12, 363); + this.comboMethod.Name = "comboMethod"; + this.comboMethod.Size = new System.Drawing.Size(121, 21); + this.comboMethod.TabIndex = 3; + // + // HiddenProcessesWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(511, 396); + this.Controls.Add(this.comboMethod); + this.Controls.Add(this.labelCount); + this.Controls.Add(this.buttonSave); + this.Controls.Add(this.buttonTerminate); + this.Controls.Add(this.label2); + this.Controls.Add(this.buttonScan); + this.Controls.Add(this.buttonClose); + this.Controls.Add(this.listProcesses); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.KeyPreview = true; + this.Name = "HiddenProcessesWindow"; + this.Text = "Hidden Processes"; + this.Load += new System.EventHandler(this.HiddenProcessesWindow_Load); + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.HiddenProcessesWindow_FormClosing); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.ListView listProcesses; + private System.Windows.Forms.ColumnHeader columnProcess; + private System.Windows.Forms.ColumnHeader columnPID; + private System.Windows.Forms.Button buttonClose; + private System.Windows.Forms.Button buttonScan; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Button buttonTerminate; + private System.Windows.Forms.Button buttonSave; + private System.Windows.Forms.Label labelCount; + private System.Windows.Forms.ComboBox comboMethod; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/HiddenProcessesWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/HiddenProcessesWindow.cs new file mode 100644 index 000000000..62e2b557a --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/HiddenProcessesWindow.cs @@ -0,0 +1,510 @@ +/* + * Process Hacker - + * hidden processes scanner + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Common.Ui; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; +using ProcessHacker.UI; + +namespace ProcessHacker +{ + public partial class HiddenProcessesWindow : Form + { + public HiddenProcessesWindow() + { + this.SetPhParent(); + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + listProcesses.ListViewItemSorter = new SortedListViewComparer(listProcesses); + listProcesses.ContextMenu = listProcesses.GetCopyMenu(); + listProcesses.AddShortcuts(); + listProcesses.SetDoubleBuffered(true); + listProcesses.SetTheme("explorer"); + + comboMethod.SelectedItem = "CSR Handles"; + labelCount.Text = ""; + } + + private void HiddenProcessesWindow_Load(object sender, EventArgs e) + { + buttonScan.Select(); + ColumnSettings.LoadSettings(Properties.Settings.Default.HiddenProcessesColumns, listProcesses); + + this.Size = Properties.Settings.Default.HiddenProcessesWindowSize; + this.Location = Utils.FitRectangle(new Rectangle( + Properties.Settings.Default.HiddenProcessesWindowLocation, this.Size), this).Location; + } + + private void HiddenProcessesWindow_FormClosing(object sender, FormClosingEventArgs e) + { + Properties.Settings.Default.HiddenProcessesColumns = ColumnSettings.SaveSettings(listProcesses); + + if (this.WindowState == FormWindowState.Normal) + { + Properties.Settings.Default.HiddenProcessesWindowSize = this.Size; + Properties.Settings.Default.HiddenProcessesWindowLocation = this.Location; + } + } + + private void AddProcessItem( + ProcessHandle phandle, + int pid, + ref int totalCount, ref int hiddenCount, ref int terminatedCount, + Func exists + ) + { + string fileName = phandle.GetImageFileName(); + + if (fileName != null) + fileName = FileUtils.GetFileName(fileName); + + if (pid == 0) + pid = phandle.GetBasicInformation().UniqueProcessId.ToInt32(); + + var item = listProcesses.Items.Add(new ListViewItem(new string[] + { + fileName, + pid.ToString() + })); + + // Check if the process has terminated. This is possible because + // a process can be terminated while its object is still being + // referenced. + DateTime exitTime = DateTime.FromFileTime(0); + + try { exitTime = phandle.GetExitTime(); } + catch { } + + if (exitTime.ToFileTime() != 0) + { + item.BackColor = Color.DarkGray; + item.ForeColor = Color.White; + terminatedCount++; + } + else + { + totalCount++; + + if (!exists(pid)) + { + item.BackColor = Color.Red; + item.ForeColor = Color.White; + hiddenCount++; + } + } + } + + private void AddErrorItem( + WindowsException ex, + int pid, + ref int totalCount, ref int hiddenCount, ref int terminatedCount + ) + { + if (ex.ErrorCode == Win32Error.InvalidParameter) + return; + + var item = listProcesses.Items.Add(new ListViewItem(new string[] + { + "(" + ex.Message + ")", + pid.ToString() + })); + + item.BackColor = Color.Red; + item.ForeColor = Color.White; + totalCount++; + } + + private void ScanBruteForce() + { + this.Cursor = Cursors.WaitCursor; + listProcesses.BeginUpdate(); + listProcesses.Items.Clear(); + + var processes = Windows.GetProcesses(); + int totalCount = 0; + int hiddenCount = 0; + int terminatedCount = 0; + + for (int pid = 8; pid <= 65536; pid += 4) + { + try + { + using (var phandle = new ProcessHandle(pid, Program.MinProcessQueryRights)) + AddProcessItem( + phandle, + pid, + ref totalCount, ref hiddenCount, ref terminatedCount, + (pid_) => processes.ContainsKey(pid_) + ); + } + catch (WindowsException ex) + { + AddErrorItem(ex, pid, ref totalCount, ref hiddenCount, ref terminatedCount); + } + } + + labelCount.Text = totalCount.ToString() + " running processes (excl. kernel and idle), " + + hiddenCount.ToString() + " hidden, " + terminatedCount.ToString() + " terminated."; + + if (hiddenCount > 0) + labelCount.ForeColor = Color.Red; + else + labelCount.ForeColor = SystemColors.WindowText; + + listProcesses.EndUpdate(); + this.Cursor = Cursors.Default; + } + + private void ScanCsrHandles() + { + this.Cursor = Cursors.WaitCursor; + listProcesses.BeginUpdate(); + listProcesses.Items.Clear(); + + try + { + var processes = Windows.GetProcesses(); + int totalCount = 0; + int hiddenCount = 0; + int terminatedCount = 0; + + processes.Remove(0); + + List foundPids = new List(); + + var csrProcesses = this.GetCsrProcesses(); + + // Duplicate each process handle and check if they exist in the normal list. + foreach (var csrhandle in csrProcesses) + { + try + { + var handles = csrhandle.GetHandles(); + + foreach (var handle in handles) + { + int pid = 0; + bool isThread = false; + + try + { + pid = KProcessHacker.Instance.KphGetProcessId(csrhandle, handle.Handle); + + // HACK: Using exception for program flow! + if (pid == 0) + throw new Exception(); + } + catch + { + // Probably not a process handle. + // Try opening it as a thread. + try + { + int tid = KProcessHacker.Instance.KphGetThreadId(csrhandle, handle.Handle, out pid); + isThread = true; + + if (tid == 0) + throw new Exception(); + } + catch + { + continue; + } + } + + // Avoid duplicate PIDs. + if (foundPids.Contains(pid)) + continue; + + foundPids.Add(pid); + + try + { + ProcessHandle phandle; + + if (!isThread) + { + var dupHandle = + new NativeHandle(csrhandle, + handle.Handle, + Program.MinProcessQueryRights); + phandle = ProcessHandle.FromHandle(dupHandle); + } + else + { + using (var dupHandle = + new NativeHandle(csrhandle, + handle.Handle, + Program.MinThreadQueryRights)) + phandle = ThreadHandle.FromHandle(dupHandle). + GetProcess(Program.MinProcessQueryRights); + } + + AddProcessItem( + phandle, + pid, + ref totalCount, ref hiddenCount, ref terminatedCount, + (pid_) => processes.ContainsKey(pid_) + ); + phandle.Dispose(); + } + catch (WindowsException ex2) + { + AddErrorItem(ex2, pid, ref totalCount, ref hiddenCount, ref terminatedCount); + } + } + } + catch (WindowsException ex) + { + PhUtils.ShowException("Unable to get the CSR handle list", ex); + return; + } + + csrhandle.Dispose(); + } + + labelCount.Text = totalCount.ToString() + " running processes (excl. kernel, idle, non-Windows), " + + hiddenCount.ToString() + " hidden, " + terminatedCount.ToString() + " terminated."; + + if (hiddenCount > 0) + labelCount.ForeColor = Color.Red; + else + labelCount.ForeColor = SystemColors.WindowText; + } + finally + { + listProcesses.EndUpdate(); + this.Cursor = Cursors.Default; + } + } + + private List GetCsrProcesses() + { + List csrProcesses = new List(); + + try + { + foreach (var process in Windows.GetProcesses()) + { + if (process.Key <= 4) + continue; + + try + { + var phandle = new ProcessHandle(process.Key, + Program.MinProcessQueryRights | ProcessAccess.DupHandle + ); + + if (phandle.GetKnownProcessType() == KnownProcess.WindowsSubsystem) + csrProcesses.Add(phandle); + else + phandle.Dispose(); + } + catch + { } + } + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to get the list of CSR processes", ex); + return new List(); + } + + return csrProcesses; + } + + private ProcessHandle OpenProcessCsr(int pid, ProcessAccess access) + { + var csrProcesses = this.GetCsrProcesses(); + + foreach (var csrProcess in csrProcesses) + { + foreach (var handle in csrProcess.GetHandles()) + { + try + { + // Assume that the handle is a process handle. + int handlePid = KProcessHacker.Instance.KphGetProcessId(csrProcess, handle.Handle); + + if (handlePid == pid) + return ProcessHandle.FromHandle( + new NativeHandle(csrProcess, handle.Handle, access) + ); + else if (handlePid == 0) + throw new Exception(); // HACK + } + catch + { + try + { + // Assume that the handle is a thread handle. + int handlePid; + + int tid = KProcessHacker.Instance.KphGetThreadId(csrProcess, handle.Handle, out handlePid); + + if (tid == 0) + throw new Exception(); + + if (handlePid == pid) + { + using (var dupHandle = + new NativeHandle(csrProcess, handle.Handle, Program.MinThreadQueryRights)) + return ThreadHandle.FromHandle(dupHandle).GetProcess(access); + } + } + catch + { } + } + } + + csrProcess.Dispose(); + } + + throw new Exception("Could not find process (hidden from handle table)."); + } + + private ProcessHandle OpenProcess(int pid, ProcessAccess access) + { + switch (comboMethod.SelectedItem.ToString()) + { + case "Brute Force": + return new ProcessHandle(pid, access); + case "CSR Handles": + return this.OpenProcessCsr(pid, access); + } + + return null; + } + + private void Scan() + { + switch (comboMethod.SelectedItem.ToString()) + { + case "Brute Force": + this.ScanBruteForce(); + break; + case "CSR Handles": + this.ScanCsrHandles(); + break; + } + } + + private void buttonScan_Click(object sender, EventArgs e) + { + buttonTerminate.Enabled = false; + this.Scan(); + } + + private void buttonClose_Click(object sender, EventArgs e) + { + this.Close(); + } + + private void buttonTerminate_Click(object sender, EventArgs e) + { + string promptMessage = "the selected processes"; + + if (listProcesses.SelectedIndices.Count == 1) + promptMessage = listProcesses.SelectedItems[0].SubItems[0].Text; + + if (MessageBox.Show("Are you sure you want to terminate " + promptMessage + "?\n" + + "WARNING: Terminating a hidden process may cause the system to crash or become " + + "unstable because of modifications made by rootkit activity.", + "Process Hacker", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation, + MessageBoxDefaultButton.Button2) == DialogResult.Yes) + { + foreach (ListViewItem item in listProcesses.SelectedItems) + { + int pid = int.Parse(item.SubItems[1].Text); + + try + { + using (var phandle = + this.OpenProcess(pid, ProcessAccess.Terminate)) + phandle.Terminate(); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to terminate " + item.SubItems[0].Text, ex); + } + } + + // Wait a bit to avoid BSODs + System.Threading.Thread.Sleep(200); + buttonTerminate.Enabled = false; + this.Scan(); + } + } + + private void listProcesses_SelectedIndexChanged(object sender, EventArgs e) + { + if (listProcesses.SelectedItems.Count == 0) + buttonTerminate.Enabled = false; + else + buttonTerminate.Enabled = true; + } + + private void buttonSave_Click(object sender, EventArgs e) + { + SaveFileDialog sfd = new SaveFileDialog(); + + sfd.FileName = "Process Scan.txt"; + sfd.Filter = "Text Files (*.txt)|*.txt|All Files (*.*)|*.*"; + sfd.OverwritePrompt = true; + + if (sfd.ShowDialog() == DialogResult.OK) + { + try + { + using (var sw = new StreamWriter(sfd.FileName)) + { + sw.WriteLine("Process Hacker Hidden Processes Scan"); + sw.WriteLine("Method: " + comboMethod.SelectedItem.ToString()); + sw.WriteLine(); + + foreach (ListViewItem item in listProcesses.Items) + { + sw.WriteLine( + (item.BackColor == Color.Red ? "[HIDDEN] " : "") + + (item.BackColor == Color.DarkGray ? "[Terminated] " : "") + + item.SubItems[1].Text + ": " + item.SubItems[0].Text); + } + } + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to save the scan results", ex); + } + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/HiddenProcessesWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/HiddenProcessesWindow.resx new file mode 100644 index 000000000..912b30118 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/HiddenProcessesWindow.resx @@ -0,0 +1,1750 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + 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 + /wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI+AAAAAAAAAAAAIj4j4gAAAAAAAAACIj/iIiA + AAAAAAAACPiIiIeIAAAAB3B3AIiId3eIgAAAiIh4dwB3eIiIgAAAeHiIeHiId3AHgAAAiIeHh3cAAgMA + gAAAiIeAAAAAJyRygAAAiIiAAicnInIniAAAiHiGNgAApycneAAAh4iAIyKjZyeneAAAh4iHICJCdzZ3 + eAAAcoiFAGMhd3o2OAAAh4+DAiJ2JjZ3eAAAAIj2cHIHd3d3eAAAAACHAAUneIiI+AAAAAAId3eIiI+P + gAAAAAAIjwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD////////////4 + ////wD///4Af//+AD//kwAf/wDAH/8AAB//AAAf/wAAH/8AAA//AAAP/wAAD/8AAA//AAAP/wAAD//AA + A//8AAP//gAH//4///////////////////8oAAAAEAAAACAAAAABAAQAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAgAAAgAAAAICAAIAAAACAAIAAgIAAAICAgADAwMAAAAD/AAD/AAAA//8A/wAAAP8A + /wD//wAA////AAAAAAAAAAAAd3AAiIeHgACHgAD4iIcAAIiAAACHcAAAiIiIiIiIeHiIiIiIiIiIiIiI + gAAAAAD3iIiAAAcncIiKeIBwAioniIF4iiAadaqIiI9wImd3dYgACIBKN3d3iAAIgDBHJWOIAAiHiHiI + iIgACI+IiIiIiAAAAAAAAAAA/////xwH//8cD///Hx///wAA//8AAP//AAD//wAA//8AAP//AAD//wAA + ///gAP//4AD//+AA///gAP///////ygAAAAwAAAAYAAAAAEACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAABwoHAAwMDAANFA0ACxkLABISEgAUGhQAGhoaACcAAgAKPQkAFSMVABYoFgAbJBsAHCocABI6 + EQAeMx4AIyQjACIpIgAsLCwAIjQiACM7IwAsMywAKzsrADQ0NAA0PjQAOzw7ABZLFQAGVBsAFlMVAA54 + DAATZBIAFWsTABNzEQAVeBMAGnoXABx0GgAgeB8AJUIlAChKJwArRSsAK0srACVVJQAtUi0ANEM0ADJL + MgA7QzsAPko+ADFTMQAzXDMAO1M7ADtcOwAmdiUANmM2ADpkOgA6azoANXY0AD1wPQA5ezgAQ0NDAEVL + RQBNTU0AVEtDAEFVQQBFWUUATldOAExeTABSUlIAU19TAFxcXABjRFUAQmJCAENtQwBNbU0AR3NHAFNs + UwBfYl8AW21bAFR0VABUeFQAXHRcAFp5WgBiYmIAamRkAGZsZgBmZ2gAampqAHxtbABjdmMAY3pjAGl1 + aQBre2sAcnJyAH1ydABzfHMAeHh3AHt7ewCDe3oADosLAA+dCwAUghIAGYYXAB6MHAAVnhMAEaoOABSi + EAAVqxIAHKQZABWwEQAesBwAHL8ZACKsHwAisx8AILweACSHIgAniCUAKI8mAC2ELAAlkiMAI5ohACuS + KQAsnyoAMpwvADaCNgAzjDEAOYo4ADOQMgA2mzQAPZQ8ADyaOgAmpiMAKKElACSrIgAprCYAK6IpACys + KQAlsiIAKLAlAC6xKwAsvSkAMLItADOjMQA9ojsAOb02AEGcPgBBrD8AHsAbACHAHgAkwiEAKcMmADTB + MQA+lGcARYJEAEmKRwBKhkgASYtIAEObQQBKlEgAWIpXAEajRABDs0AAUbJPAGiBZwBnkWYAc4JzAH6B + fgA0zX4AAP9rAISAfgB/f4EAf4GBAHS3mwBh25wAg4KCAIWFiQCIh4oAi4uLAJCLiwCNmYwAkJGPAIyN + kgCSj5UAi5GUAICdkACNlpsAk5OTAJmVlACTl5oAmJabAJScnwCbmpsAoZ2dAJWpnQCdnaIAqZygAJuk + pwCdpqoAkbunAKOjowCppaQAqamnAKSmqgCkqKwArKusALCsrACysK4Ap66xAKutsACxr7AAvK60AKyy + tQCvubwAs7OzALu1tgC0ursAu7q7AMOqsgDKp7oAw6y4AMG8vgC+wL4AvL7AAMO9wQC8wsQAucfJALzM + zwDDw8QAy8TFAM/IxwDEx8kAzMTIAMPIygDLy8sA0MnJAMbN0QDPz9AAxdHUAM3S0wDM1tgAy9nbANLT + 0wDU19gA09rbANvb2wDW3uAA3N/hANfg4gDb4OIA3+bpAOPj5ADi5+kA5+npAOnq6wDv8vMA8/T0APf3 + +AD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + 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 + FAAcHRwACzwKABckFwAZIxkAHCwcACMjIwAjKyMAKysrACIyIgAlOyQAKjIqACs8KwA1NTUANDs0ADw8 + PABHJi0AD0EOABpDGQAfWx4AIkYZACBXHwANZAoAEXUPABVlEwAVbRMAGW4WABNzEQAWfRQAG3cZACdF + JwAuRy4ALEosADNDMwA3TzcAOkU6ADpLOQA0VDQAM1wzADtWOwA6XDoAAHs5ACpuKQAwci8ANmQ2AD9h + NwA5YjkAO2w7AD1wPQA/fD4AQkJCAEdORwBLS0sAQlRBAFRXSgBVVFQAX19fAEBtQABAcEAASHhHAElz + SQBLeEsAVGVUAFxhXABUdFQAWXZRAFV4VQBZcVkAXHpcAHpfZwBlZWUAampqAGFzYQBiemIAaHZoAGJ4 + aQBtf20Ac3NzAHp0dwByfXIAe3t8ABKIDwAVhBIAGY4XAB6AHAAajBgAEpEQABycGgAiih8AEawNABWh + EwAUrBEAH6UcAB6pHAAZsBYAH7UcACG6HgAhhyAAKIYmACKLIAAlkCMAKJQmACSbIgApmCcAK5wpADGb + LwA5ijcAM5MxACenIwAupCsAMKgtACK0IAApsCYAI7ogAC6+KwAzqDEAQKs9AB/EGwAhwx8AJMogAC3G + KgAuyCsAMsEvAEuFSgBPiU4ARZtDAFWGVABMp0oARbxDAGiDaABziG8AcYVxAHmCdAB5gXkAfoh+AIJ5 + gAB/jI4Af5SKABXyhQBLxo4AgoKDAIqFhQCAjoAAiYmJAI2NjQCVg4oAjZaNAIqPlACRjpIAnI+XAIid + kwCIkZgAlJSUAJiXlwCRm5UAlpmaAJqZmgCdmpoAnZ2bAJ2bnQCdnJwAoJuaAIycowCVnaEAnJ6gAJil + pgCcrKIAlrSuAJmutQCko6MAqKanAKinrACkqqsArKysALCvrwCusK4AtbCvALGvsACqsbQArb2+ALGx + sQC2srIAsra2ALW1tQC7t7QAtrq3ALq1uQCxurwAubm5AL29vQDMtL4Awbu7AN+oxACux8wAssTHAL3C + wwC4xsoAvcnKALbM0gC8ztQAw8LCAMPDxADAxcYAxcXFAMrExQDExskAxMrLAMnJyQDJzc4Azs7OANHN + zADN0M4Aws7QAM3P0ADYxNAAw9HVAMrQ0gDL1NgAxdreAMjc3wDR0dEA0tTSANLS1ADR1dQA1dXVANzT + 0wDQ19kA3tbYANXa2gDZ2dkA2d3dAN3d3QDT3uEAzuDiAMzn7ADI6e0A0eHiANnj5QDa7O0A3u3uANTu + 9ADd+vwA4ODhAObm5gDg6OoA6urqAO3q6QD19fUA9fb5AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADi + 4uLVwwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADV6+v56+vr1cMAAAAAAAAAAAAAAAAAAAAAAAAAAAC9 + 6+vr+evi4vvV1eLDAAAAAAAAAAAAAAAAAAAAAAAAw+LR1eL5+eLV69HRvdG9AAAAAAAAAAAAAAAAAAAA + AADDvdHR4uvr4tXV0cOmltEAAAAAAAAAAAAAAAAAAAAAANXV0cPV4uLb0cOvkpKmpgAAAAAAAABWk54A + AAAAAAAAAL3i1b29s6aSTT1Mnr2zt9EAAAAApqa966Y6TLCmAAAAAACer59UU1OSqrjK3fP54rMAAACe + vpa34tGmkp6zngAAAACzmZ2ors3q1b2WTcPJwwAAAJ/Dr7Ozs9XrpkySU6nIzMfIvKaUUDsRBgYDmOG9 + AAAAptKvs6+emo6tzfb32q+KRCoRAwUCBgYNJSs3768AAACm2K+3sZ6xq6yKPBQHAgABAAIfZys0bjQr + EofvsAAAAKbnsLOzpt0QBgEAAAADDyQ0NWxlKhRsZxUTUO6wAAAApumws7ev4RoCC1pjNSwmEAkGImw0 + OHJ3Om6B7rAAAACm6a+zva/aNDIrXWEEAgMGBgVbcHE6dnFvczbruAAAAKbYpr3Dvd5HFw1hWAgDBSFc + H2JBfD93N3REReK5AAAApsSXvNXD1IghZF4eHAcZXTF7ZkF5gnhOTE1F2c0AAACbsaDF1c7RrwonLTB1 + LGlaDSB3U4R6gFBTU03RzdEAAJyQkcbr0dPJNDQqCWEGXBgHDINWU39+SkZCNcPdswAAjy9R3OrV29oM + OAcDVxhhEScrRkI2c31GUFVTs96mAACNFkvR6tHe1BQpESRqbXc0NC1SVZKShpKSkpKq6KEAAMJUs/7/ + +eLdPzQkEBlbIwwRPZqSkpKFSkhCNqbrqgAAAADJveL//+89AQYGB2EMERRJSkI2QUZPioyYn/myAAAA + AAAAAL2/2k0DCxImazU0NE+IjJaWlpaUk5JW+78AAAAAAAAAAADbnjQ0JhIREQ4TkpOTlZ6mr7C90eL9 + 0wAAAAAAAAAAAAC9AAYMEzg+U5q9w8PR09ne6O/z+vkAAAAAAAAAAAAAAMOTp73DyuHx8e/z8wAAAAAA + AAAAAAAAAAAAAAAAAAAA4vX1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////4P///4A///4 + AD//8AAf//AAH//wAB/H+AAHgD4AA4APAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AA + AAGAAAABgAAAAYAAAAGAAAAB4AAAAfwAAAH/AAAB/4AAA/+AB///j/////////////8oAAAAGAAAADAA + AAABAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUFBQAJCQkAAhcCAAIfAQAGGgYAERERABEV + EQAQGBAAERwRABYfFgAYGBgAHh4eAAIgAgALIwsADy8OAA8wDgAQNA8AFSEUABcnFwAZJBkAGioaABQx + FAAeNR4AICAgACQkJAAqKioALi4uADAtLQAiPyIALT0tADMzMwBBPT0AC18JABNrEgAXcxYAFHoRAB59 + GwAuTS4AKlAqADdONwAyWzIANVk1ADlYOQA+Xz4AEWU0ADJlMQA0YDQAN243ADhnOAA9YT0AOmo6AD1o + PQA8bTwAPHA8AEFBQQBKR0cATEhHAEtISABOTk4AUlJSAFVeVQBAcUAARndFAEhxSABeY14AUXRRAFJ5 + UgB5V2MAY2NjAGZmZgBlaGUAam1sAG5ubgBiemIAZXplAG94bwBxcXEAdXV1AHR+dAB6enoAfnt8AH9/ + fwAPgAwADYoKABCNDQAQng4AF4MUABSIEgAciRoAIJodABCgDQAcrhkAIYQgACaDJAAonCYALJ0qADiR + NQA8kjoAKaInACS1IAA0oTIAPag7AB/CGwApwyYAKscmAEyKSwBMn0kAQqFAAEeiRABNoUsAfYB9AICp + fAB/g4UAP8uFAIKCggCEhIQAgYmNAIyLigCOjo4AkI6OAIGWjACTkI8AiY+QAIiQkgCNlZcAkZGRAJWU + lACYl5cAl5ydAJmZmQCdnZ0Al5+gAJqgogCYr6UAoqKiAKSjowCmpaYAqKenAKeppwCuq6cAqKaoAK2l + qQCqqqkAq66vAK2trQCxp6kAtaSqALCpqwC0qq8AsK6vAKazsgCvs7MAq7S3ALKysgC2sbMAsbS2ALa1 + tQCztrgAt7i5ALC7vAC3uLwAs7y+ALq5ugC9vr4Awb69AMi7vgDFwL4AtL7BALnCwwC+xsYAvcfJALrI + yQDCwsIAxMPCAMPExQDFxcUAzMXGAMDIygDFyckAxszMAMnJyQDOyMkAys3NAM3NzQDZzdMAy9HTANHR + 0QDQ09QA1tLVANDU1QDV1dUA2dXXANPX2gDX2twA2dnZAN7a2ADe3t4A2N/hAN3i5ADe5OYA2ObpAOHh + 4QDh5ucA4O/vAPn8/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAv7MAAAAAAAAAAAAAAAAAAAAAAADAtcXK + xcW1tQAAAAAAAAAAAAAAAAAAALWztcXFu8C7raQAAAAAAAAAAAAAAAAAALuzrcDDu62PeI+IAAAAAAAA + AFGAAFGCAACknZ2Lf1FIe6CYjwAAAAAAioytrX5/f38AAIV+dYSkta3FswAAAAAAj52InZ6LcX6EnYuL + fnFGNwwfrAAAAAAAlqeNgoKXi39NOxsSDhAQFhIfoAAAAAAAnbGNj5QZCQMNDQUCFF4oKzA1kAAAAAAA + nbGPj5QHCSMdJy82X2crMmRjiLMAAAAAlqaNpKE1L1wXFQoHXGJiP2VAcKoAAAAAlpOKtaoaJSQhU1Yi + X0ZoamxGeKwAAAAAhnKWuawgJxBUVRJZQU1sbm5IdqgAAAAAeS2NwLI4GQJbWBkaTkxLaUNAPpgAAAAA + jUS5zbs4BxRZWio0NkBCZktMcZ0AAAAAAACtwMc4MSonXh49e3FxdHR/gq0AAAAAAAAAALV/AAcLFBpN + ioydscDAwMAAAAAAAAAAAACkPEZxg6e1tbXAwcPHyAAAAAAAAAAAAADDycwAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAP///wD///8A//j/AP/APwD/gB8A/4APAOTABwDAMAcAwAAHAMAABwDAAAcAwAADAMAA + AwDAAAMAwAADAMAAAwDAAAMA8AADAPwAAwD+AAcA/j//AP///wD///8A////ACgAAAAQAAAAIAAAAAEA + CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwsLAA0NDQASEhIAFRUVABkZGQAbHxsAHh4eACEh + IQAmJiYAKCgoACwsLAA0NDQAEngQABd8FQAyWzEAI2ohAENDQwBIREMAVlZWAFpaWgBdXV0AW3ZaAGBg + YABnZ2cAaWlpAGxsbABzc3MAdnZ2AHt5eQARpA4AF6gTABazEwAiph8ALIIqAC2fKwA5jjcAJrkiABvT + FwAP8goAEPALACbJIgAA8kgAYsKCAIqKigCRkJAAlJSUAJucnACenp4An6CgAJm/pQCgoKAApKSkAKqq + qgCrrKwAra2tALCxsQC0tbUAuLm5ALu8vAC+vr4AwMDAAMTGxgDFyMgAyMrKAMnLzADKzMwAzM7OAM7Q + 0ADQ0dIA1dbWANnZ2QDf398A6OjoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8AAAAAAAAAAAAAAAAAAAAAAC0dLQAAADs7OS8vMTMA + AAA9LTkAAABJQD07NTMAAAAANT0zAAAAAAA7LC8AAAAAADlFNUg9PTs7OTU1MzMzM0A1RTVFREBAQEBA + QEBAQEAvOUU1RTUAAQAAAQUFBQQ9MzhFNUU4BQUBBAoiIRELQDMyKitFNQoFBAQPJSMkEUAzNRIdRTMn + HgQFJhUVKSdANUc7REUzCg0OIBYZGBkYQDUAAABFMwMEHxAcHBwcGUA5AAAARTMEBQsMGRgVFRNAOQAA + AEUzMzMzMzU5OTk7QDkAAABIRUVFRUVFQEBAQEBHAAAAAAAAAAAAAAAAAAAAAP//AAAcBwAAHA8AAB8f + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4AAAAOAAAADgAAAA4AAAAP//AACJUE5HDQoaCgAA + AA1JSERSAAABAAAAAQAIBgAAAFxyqGYAAP//SURBVHja7L0HnCVHdS98Otw8Oc/uzkattEhkCT1nG2z8 + /WyThYQxGBxA5GQw/ghCJpv0MO/5+TOGRzbB2EgCCfvDgDEYlCWU0642zGyYnZ08c3N3v5Oquu6d2WUF + K+G3e0u6OzP39u2urq7zrxP+dY4HndZpnXbGNu/n3YFO67RO+/m1DgB0Wqedwa0DAJ3WaWdw6wBAp3Xa + Gdw6ANBpnXYGtw4AdFqnncGtAwCd1mlncOsAQKd12hncOgDQaZ12BrcOAHRap53BrQMAndZpZ3DrAECn + ddoZ3DoA0Gmddga3DgB0Wqedwa0DAJ3WaWdw6wBAp3XaGdw6ANBpnXYGtw4AdFqnncGtAwCd1mlncOsA + QKd12hncOgDQaZ12BrcOAHRap53BrQMAndZpZ3DrAECnddoZ3DoA0Gmddga3DgB0Wqedwa0DAJ3WaWdw + 6wBAp3XaGdw6ANBpnXYGtw4AdFqnncGtAwCd1mlncOsAQKd12hncOgDQaZ12BrcOAHRap53BrQMAndZp + Z3DrAECnddoZ3DoA0Gmddga30x4Avv/973sJwKYjhydfXKtVH49vdZ3K+/Y8D5IkeUTuha51urVHauz+ + CzW64XJXV/e1v/ZrT/kS/n5oaGgo/nl15vSbUU774X/+Jwn/9jiOX4/Cf3GSxIO+H/h41z49Bg8nX0y/ + 4P94DHhBkARBwOPiq2CbV+x5SYCjFfqB5/MxCUSxfMaDSMfhOYCE1IAC/iShpc/p/PSe7/tA546iSI+B + hI6yYmDORxcwEs8/ksSnrnpehOfA7+A9eF4AziGe5x8XJNz35VdvnWPWf18/S+TDls8TfXmeXoDH4yT6 + oH8n61zQnvM4nYm9tKPeOtdKZNjTr5tjTN/My+2XOWX7GOixiXst57vmsXnp++vdktM56QM9wyO9vX3X + 4O//A9++Z3Bw8OcCAqc1APzH977XjYJ2aZwkb8SRH6MnaAQazMpDD5jeo5++CpAKqhEu/A0S+gxfAQkw + yINM3MnnnNNOEAUDzxxP5/I8/n6TwEJBwjyIJBX+tG96DgMMHgk/9QVU6sznel3ut/36SQviTzzmZL7n + akMne+2f9P5P89nxhNz9bL331rsfdzzd77jvu8CyXp+Oo+Xg9PGW8OeVeK6/wp/3DwwMPOIgcFoDwHe+ + /e3HIgD8TRxFvwwse14rZLcPht+6gpq/zTv8Gb1HAGGE2xHAdoFuEW5zDgMcCghr+uJMFs9MMgeIPAUi + kBtqvT7IxHRXsZ9WEH9aUDjRuX+azx5K/9cT4LUr/ckBwHqCv97n64HeegBwvP7iZ8t4rr8Nw/BDPT09 + s/AIt9MdAH4Phf8LOMh97vtxuxYA5gH6LSBghLh1JSBNQVZxu8IbwV9H+M3fRgMANTv4nO7wO4Bg3vZU + JaV+ueaEO2GpL666C87njpKTvt/WN+dLrcc451rnML5e+8p3vNXf/VuO8Y7ThbVv8rivo1U/VA3FXbld + ofXd572OJtVqNhiMl2fte+1ag0B9+xidqG9qFj6QyWTejO99o6urK/rkJz/pveQlL3lEnCOnNwD82789 + EzWAL+KvRff9WG11fvjg64NVUKAHSMPie2BEAY1+FXo6RofMl9kQx/QAPTQN6HwBHSzDyoJEn0eOReuJ + MAMo5sQWhFJj2vTS40tYSME/YjqArhfg9RispF8y0awxzhOT3BSe9oWPSdixocB3HE3TTOgkVrBq+Yjv + jc4dW9xM0s8ALBAJYMEaIBHMNQJCo5Pwv0Yz8yyoOGPAgpis6SfYIT0RELQih+kfPycde+lrYsfKN4Bq + BsDznO+Zm5L+0jf8Fi1NAduMjZqV9hk72p0LMOTTQQ3gi/j7pagFlOn9T3ziE3yal770pQ8rEJzWAPBv + //qvl+Bq/5X292nQM9kMFAoFFNyAHyYJKr2SWCYNOQP9MGNX6YiEAj/3kgiFgD7D77E/UVdyFWizUuiU + oWlmBVNAh4Q3YIdhM2pAHMUCNuxz8BWU1AEZN/FnLFdgYfcd4cJJS4LM80hAiI7zCRgCM5l9vj/6ToTX + k/trsgDz+eh4uk/wWCuK9Rg6X0Dn8IJ0ilhEEGenKCUqxInRntTf4fgsxFciwk3jlmoaPt8bjakBR7Aa + i6zK4jiN9KkZQTQahK9aE2lU5nox2JH3PTtexvEaq9aXqBDzCq4wn2pSYAGAgdMTAPIVAOWe4hbtyrdm + mWqLPAYO/CQJj3/UbK5rJtDvCACHarXa62699dYrnvrUp/JNPxIgcFoDwLcIAOKYAcAd8GYU4cNoQK2+ + gg+rCUEYQhjk8GcOeIKT0OGsDjI+hCxEiU4EnydW6IcseGFIAiQTsdFoQBNfNCFJ7CWaEEATv9psoGBF + NNFjnqT0UcbP4CTx+Wg8iUywhH/lSUsCGEcklMCCQ0JNlwoDEV6e+BH2Hb+XRTDLZEPWTugy+DW8t7pM + OAUHmbl0vVCDB3I+D08QYof4uzRJ8csZGo9Mxk4QT1f9qFnHayeQw8/oO5FjQZEmFBM4Us+8RLSERPSp + OP1DBA7Hj7URdoQC/03jmKh2Q/dL36P+83jitQL6Do2XSBQOJX43ls9pPIIwYPDjfhKoEjgazYTBTq5H + 98hCGgg48thAwM+b/4vFz4ICyZ9L141zNmZtwVctgvucGK0lYQdx4sv9JrGARGx+6vXbfQtmbuL1kqWl + pe/ccccdbz1w4MBtl156ab0DAD9j+///9V8vTgQA0rgNPo1arQozMzOwZ99u/L0GXaUiCpzHK2oThYoa + CXCYCUUTYJQnITEros+CwBMokAnQRGloNmMbDRCBaKLw16CBgkOTOpPNiupO5wsETDQUyKsxr7ogQkL9 + YZTx1BSgieczBLH24Xkhnp+OD1ig6RwUWoxJKHilj2VVj3jq4QQTDSSO6dyhCL8v98VakGfWT+wnCUco + JgyFOuk96ptEMXzIZUMWknoz4qWOAIPuKaZpriaSWf2asZocSaSCgsKVyco1E9EkAkY9ERq67xA1r5jO + E4s5Rrcnz0dHh7UkEVgakZDuJ5T+0RiYZ5AQEKiQgpo+cgoCPV/ABgGR7z2Ru6f7o/sH/sxX0Ek0MhTI + 2AVieoVsSoCCitwHA0Ak16KxI0ClISiWumBwcGhdADCt2Wyu3HjjjVcfPHjwkwgKP0LBrzzcMnJaA8A3 + r7nmufjjK54qyqbVqlVYXpqH2++5H/btm4RiIc8mAa3SpJYnqiL7vqqS6i80aE6TgIQySkRgUvNAnXs+ + K+h4rpgnua+qauCJ8EWqElrfHV4gVPUysip3wsLEQkpgQCtNTJMN2GQIfGEPiLbtg5n3JAhBYEDD49WQ + XrQ6hRnf2tdsgpAAsxkggGcsmZg0FhZOUZBDBBsPzxvzCio+DQJH0apimfjYr0YkKm7AoOLzqkwHk3Zk + /Cr0ILKoQQRBhseggePteanvgtX1QCItMfc94vunFZk1IV80hUgBjhp9lgnFNIqassoHartzP/EZgfoW + ItYagAHN9aPEOBb0HGkcspmAx0VML3k+oJoIgY0PCoasIUQ67iEDIX1BVnrRfqivpL2Nj43BhRf+txPO + V7zX+Kabbjo6NTX1ffzzb/F1PYJA9eGUkdMaAK7+xjcuwh9f8XmJTBvZleXyClzzL9+C73z731klLyAI + 0OrYQNPAs3YiyEQOZAI12S5XVY8mIACvJLLyxOoDVu8yq/A6yIlMSlqJQvIdeOJwVDoPf8Yruw0tgaxg + SSz2eqC2PQu/cViCOq887g+tOvwWr0AxRxpIMNiOjcVOJ5CKWJ2Va4lTSo41DjqWU+soS2x0gu1ytrcF + JOiaEX0zUrWWsUCcpL46QXwFQzF/fOs4pUMzfpYBNIobPNYs+CJV/Heovr9GJA5LX+1+0y0BAPmdzBEB + a5/vvamkK+pGRohdAuoIOqwhJfIMGSQDsd8T0uDoXvDvTBjo+Msde2rmsQZGpkjiWdOElRsyfQKfNReP + zbAmP2ePPxdX5wXnPx7e8pa3nHC+EtghADQQABbwz2+AgMBtCALNh0tGTn8ASJKveAoAJvxD6nAFtYDP + fvYf4KqrrgIfET+Xy/Hk5lWeVm6IxWEXhNbBEyexQ9bx2H42TkI2SY0aGagDST1BAhYJGAKPrA30JS+1 + aXnFUl8Av6XhQlBzgQQwUQebag7sxGL/QSIaguOFjj0TRnQ4CqSNeL76BDzWHEQr8a1dzCYH3VWiIUZ1 + MnqJSKQq0QJ0arow6MgAgARY0rh3AsYeVoehiYYkvlX7m7HepzG1QIGJgFM1G7pHz4YWBEAZVzwBI+mo + aGgkyOyPUNIWC6xeNzaAog5FFm56TJFoFWwemL7zGMV8XYn2qO9f7RtxKnoCxKDOQFCLR8eHAQ/f//Xf + +DX42Ef++oTzlQDghhtuSA4dOkRLxxF8fR5f/wsB4ODDJSOnNQB88+qrLyYnIE4WL42NCwBU0fb/9Kf/ + Ab5+9VXQPdAPpZ4uUedIKBNRbcUJrGE9EK3AN7RRX2x0Y7WrpKjaLA8/UaeXeV+cRrGs1rGSiQJfz2lC + jDLRE+MX8D0zo3jCsaCGgQ0FJvZC5ko+mwGCAiCrsi99ZmGnFSyQldlH1T4fZqGQz0MO7XJatdi5peE+ + 32FH+hr6Eq9/YgFGmmgQBiD5fj1DpY5tiNN44G2UQ20rCWEmqZ2mYMEAYex+i2OJGXEeL0ui9lJ/ShKn + 4cnEJRZrH+zztGFAh4VpohF6LjuuibnT9H5NR3zPCSWbiyVpf2msz3v0efC6V772hPOVAOBHP/oRHD16 + lP5s4OtufH0QX1chCKw+HDJyugMARwFi9fyaFqIAlMtl+NwXvgjf+OY1MLxpA/QhCLA9moiX2o2Vm4lq + V1QnViwTUFYg8duJ/WpdVKr6mlAUe+81ns+gFPiqLcR6SUMqckg5xoluSCm+5wi8Tmf9R7zsZmGyKGQ1 + Ek9BjfqVRe0mn8lBIZfnn2TDZnzj+NQ+qwfdhjddUo9Z5Zzm0JnWvuetfe9M2AxEY3bWzrPgxS940QmP + azab8MMf/pAd1Pgdmg3ECfhXEBC4GUHglFOFT2sAQBPgkkQ0ALlZnbwkqKvlFfjCF78E37jmX2Bo4zgM + DPZDncN44iAS21fVal9iv16sbDCzIhk2iK7WPjirnwqoLmAiQIZFxvY3pH3yhU1oo9w2Jp3oiuvryukw + yJwHuIaN5sSgBRdU20hSIgzdYxYFvpgtQClfRADIsg2bCSQqYEwFWd38DgD8DI3GbOfOnfCiF/zhCY8j + DeDaa6+FI0eOgG5AIoEn9Z82DP09AsDyKe/bz3twHs72jauuugQn2FfaudghTuxqZRU+/8Uvw5VXXw0D + 46PQjxpAs9ng1dm30m0IOgCWaqfDZs9miX++JX0Ydp4c2rpdWPgkfquA+mLf+8YB4LmMwPQNo6K2CLwh + 3Xjud73WXjpMPfG2y6YmUvuL+QJ05Yr4e17i/7z6B1b4fWUvdgDgp28PBQBuvPFGmJqaMuNMg0NRgK/j + 6+0IALtPed9+3oPzcLarv/516wNw38+irVurVuBzX0IA+PrXoW/jMPT09ULSVGKKGRmjblsj1hk1awLI + G5YCamJ7jtClzTFGvdSutaZF27HuNlV7pPFLuCqA0w9wbHPP81qesN07gKiVwVU+l0UAyKEGQACQRQAI + BAACNRFMaK4DAD9bYxPgLDQBXnhiE4BM1ZtuugkOHDjgjjM5BG/F15vw9f1TTQo6rQHgmm984yIc1C8j + sobuxKU4b7VSgc/+wxfh6muugb7BEegmAIiVrOKnKr5QTiFdrs0PzxHCdOdwGiHwUo+9XZET47gCa8ez + BzkWs4Kpsn7SIjCyDnjp74H6FbQlqu97vrsT8QQA4AmzkOLZxOgjDaCIAFBwAMBfFwBSDSK9dgcATqbR + mG3fvh3++EV/dMLjCABuueUW2L9/v/s2DRB5BS/D1/8+1X6A0x0AnoXC/yUc2Ly9YXwY2UwIlUoZPvv5 + L8DV3/wmDPSMQU9vHzP3mM3GNrkIFiv2gWcnrBVIMM5ASLUFz6W7ahhJw1eGIcd8ct+x3WPrKbDmRot9 + 3/KUxGvtWxtBowXWltCD9b1EoxXGmmSCEnU79NnjT+NQypWghCCQz+XZJ+ATCJht0M6Ot/W2zHYA4OQa + A8A2BIAX/9EJj6OxuO2222DPnj3tH1EE4H34+gACQASnsJ3uAPAcBADSADItGgBO9JXlFfjcF/8BvvmD + f4G+bWgC9PRBVG8yqYNXPObNxyKUREON3FBRqhV4nrNrUHkA4BvHoZ+yyGLlsQcirUFiEoVInxJ7rsR6 + 633qg3r0/RiEF5CIv8Cw1GJfwmdeJM6IxNMtSIHZIajOyUQZjbSfIEN01wyOA5oAaPsXsgU2B0gjYEab + st0Mq9Fr6V+bSZMIyMlkSsEMNGwISlgy9+g7nyWu41PDmYmGQW1znaHmkyTF4NYkKmZnXgyWyWU0OXCB + S/71XLQFV4MCjaikH6dxfWjrXwpmBPJ+YugfhlwVM2GITIAXvvAFP3HO3nHHHXD//fe3v00hQSIRkB+g + fipl5HQHgItR+L+CL3ufrAHgJF+YXUQT4AvwrTv/DXqeMMAaQFRtQOTFYPeICSfYhuNiu9vPU4JP6tRj + MwBiFYjUdGDxo3NaH2Jq7/uQ7kwzgiKcnsQ666QbOrEgnfgGJMAzGOOGDkWkxDwgDSYRmkIkB5P1gUYA + YgS+Mh5kUPBzCAb5kByBBAyy2QcCx7kZQ7rrkTUbJhnI/SWpIKXWCcIQXUv2z/DvJhrBd25Cm0ZOaahj + 3Y9gxgEALOvfRFEs50GBx24AdFDBV+KSPYc0jsmDb0FLmcwWwAgdPSX1MHnIhF70/j1DRjJ0LusvUjMs + EapzrKCfRLK5KFvIwLnbz4M/fMYL18zR9u3Md911F9x7773th9EJ/z98vfFUU4NPbwD4+tcvieL4K7xB + xNywRxM+gMXZJfjUpz8L37n5u9C7awj6+k0UIBaKrsF54wgMdLWx9rhOTCWhecrUM+QVZscx/z9wZooM + OWv+fpICjTUBwGoWBkR8FTjQawmLTkOUeg7fCAP9Fau5wjF80O8kLPwScgTVbDQagILOwp/JQZY2K2WI + HJThiIAf+HbVlx7GCjhqw0Ak9B1diQ3rzZJtPMMcNGaQxQ9LKnIdqgAmYqIrviFIxR6komcIRGlylMS+ + BxZQXRhMVZH0M2kCLA59R+5RoFnNJrABXiKKsYj7JrmL5gUwGo6eNdaFQOihCAA9Obhw85PgT3/9T9bM + 0ZMEAGpEC/4zBIDaqZSR0xoArr7qKiYCRW35+ggAlhYW4VOf+Tx853vfhYHRUeglACCeeDOmBVNWKRag + NIEF8wBiHTKSzBCF3BeN04+FPMOrnq52slIFSvqRicMLlNkFSH8oud4LPcs0tEsXeEo49MRVIItbKmCB + r5qr+U4agbAQpvLomZUypD0IkgOBPsuhsOdzOTYD6Gcun4NSNo8mQU4TnCQW4IzQ0cl41xttXbK6uIIi + fhZ5TX4vYNQUcJJdBEboYzaJjA+Dxiz2YzvGvqEe42fNoKlqvtKHqQ+xjC9nSQ30vmMFB7XOjKfMaC2x + Fytvk74baZ9lxY+8RBWJRLcF+5Z4BX6i1GhHUzAAZsbec0hjxJI0+ydA6MXZUh4u3HU+XPKbF6+Zow8B + AP4XiAbQAYCTbd+48sqL8WH8Y5rtR1oeV7mlpUX45Oc/B9/9zvdgcGQUuskEiJpK0ZWhESFWYVIJFJVX + Vy7jHGTVMnASVujgqhlgiD2WkGQcc+5y6JvJoH4DawbIdWPPIQupAPLkjr2WkCKr7ep0FDUW5HyhUYE9 + 9i3Q93hLazaEbC7DTsASkYKyRWEG4ssPpS+UMkQ0GWMCxKzBsErP5xL1l7fO4h9Nr2m1G6NNkYAzpz4R + xEsdozLOLKCJrxttUudnzOJojCdfGZN6LQUNPzGruJdqYaDjEBtNTSnWcWKdpIbHH6lg+06f6MpNX4Ar + RHA3JC4BrNh+n59lrCYhCbzX1P6JDydqxJDJZeEx558Lv/uM310zR9sBgIT/7rvvbneO0o3+HXRMgIfW + vn7VVc9VJqDvsgHz+EBWVlbg45/6NHz3u9+FwQ0IAD09AgCM+sYpBfY76YC1OoD0AKteG3vZhv/aQoFm + aWol86zjYAucKxqvfuIcYeL9TqjPRhr89PzGZAE3s5ZmHwnUBAiDLAo9vgqoCaAGkM8UWAPIBhndUOPY + 3ADrOsLM++4YWU9/u2MPoEXI7Tm1r24kwXPs7MQ5Z+p4TZ19opYnaz5LDNoqVdp6NUHBVH0O7GDVk8le + hVicqmYjU2JMqITNJ8lFpKm94kR9NLHOAY9NAd4ZiGN73qMfBRc9+6J156mbJYgAgLQABwDoF1KpPoGv + N53qHAGnNQBcdeWVF+FAfhlBILQ3jINM+/8JAP7uk5+Cb3/n2zC4aUwAoKkpuFyhcmPqLQOX5rGT2WP2 + 2rdOdssklC85RCPnGDe8Zn4Y29iGGPXg2DjV09x7Fgzc/hngaRdUCxzyFm02ygQo9Nksr/y0LbqYExOA + HIKc/ELv80QZfX/a9jOHAdvA56SOPdHxxztfO8h5rSDnfpYYE45cLxBxFICYgC983h+svZzz7Oknrf73 + 3HNP+7iQzfJJEA3glG4KOr0B4Gtfew4O45dwMLNGBSf7u1gsoAmwAn/7dx+Hf/+PfxcA6O3WMKBO9jQj + pwpNuoTaVdUdPSOk1k5O3xetvnWFtwJuL+Gc00SzJOGPePPN4h7p9RO/BTTaBd1oH67GINddCzShn4EC + hQGzsjGoWCjwz2wmK3kFwewKTL/YvhK3t5/4+amK/7ef/pGmFawDKvbeEnGTEohu374NXvQH60cBXGC1 + YcCk5dz016dAnIBLD1f3T7v29SuueA5pAHGSZFyU7e4qwfzCAvzPv/lb+P4PfgCDw+PQ29/Nu7FSD3Ma + 7pO4maQM4z8TI6Fg/QTGde8ZqNDsYZ714qeraIofaVgtJRTpd+lX+pnBv0Oxt72mBwG+OJyX6JVsUtr1 + AGAdsHI0ALuBOPA5ElBAAGB6MAJAMZ9HrSAvGXB0J6M9AbSp6etMoxMDQJIGClrO1zrr275iP3JJWck6 + ANACtMfpbzthSVwHiZoaHpgMQj9NMwAgPIyY8yvu2L4DXvD7z19zbLsGQABwn3UCtnSANIA/e+mlp3ZD + 0OkNAFdeaX0A5mnSZO7D1X5ubg4++j//Bn7wg/9EABiD3t5eTmklMXvP7vRPHeuScEIWbt96ldlOpPdi + TaZh/AfqjfbVeZj4oNuBxVNOxB3fmg/yvcQR2FiFPy7g+QsSfgtquBpX8OwNX5NkeJxY1ItUuzA0Yt2g + xOHBON3Km/hpONI4u0xq6wyu9rkcaQEZcQYWxBlIkzfw03CgE0BLiYeObW0E2WpSxi+aKOkR0oQqrjpt + vwfQigNG+XHs+VjtdvOA/DYkYMejSwSCVtBIQczcjAs+5oHHLf3wnCNaQKdN40jvX0Kg5BvIIZieffZO + uPg5z7XHHa9SEdn/ZAY4XTeNeAAIAJd2nIAn26664oo1uwFpsg8N9sPC/CJ8+KMfhe/d/B/Q96gh6Onu + hWY91vp+iabMAuMQtg4ls7JKsEh/51RYvubiB9lRaIZWBdAAAGiykTiS/AEmpG62EPsmjk+qfyGBZjf+ + VdRce1X8zhICR5U8z4EKhi8xfmfiWiJR7OveAytFIP8q6IDZokzUYGECUsLPggGArOwQ5O3Bygw0acg9 + kzUoPa0ADKTjZf4zwsoR9kTB0jfswMSOcZD4FgZEhsVjGhg6JI9XzGQtzrHky/cZ72icI5Om3ZdraLQm + NkxFVzvwUs6Bl3hWU7PkHyVvpRwF44h1ND4wnIw07GfAgTMWccq0BPL5Aux81Nlw0XOetWaOukVI2gGg + rRET8I2XXnppZy/AybYrEABA6wKYG6XBHhkZgpXFFfjQhz4C/3bnd6H3CYPQ1V2CqK4JrzS8BDZDTyqg + Zj54SerRk5WQI/78fmxUfzUfJFuVZ6ML9M3IMM4c/dxky+EvU3y7lEBjoAnNftRMsgmESyFkZ0LwVgM0 + BQIbfrLrkwpdkkhqKxNLN0lLOMSmifQ4jMhfEx89pSknYackIcQFoNU/R0lCggxHC3yj1WhiT89satIB + SBPoaOjRChWAodlqWF366Fss0dx+uu9AKc/me+KZV5erJwQqAgDOQBQgDISxCGsTwbEZQiYJVPjBISTp + ShvpOElZJ8mwRDZ6rGOT1vCQFGSJAgm4GZASG2IVxkJsAYbAm+EnEfCi9KOUgowyLp33qPPg2U9bHwC0 + IC3/fvttt8F9990HbfYHXeC/o/C/6VTLyGkNAFeqBuDeKAPA6DAsLS7Dhz/03+E7130XBs8ahWJXgfP3 + m1GxoSclArkhN7PCmmNN0hBPJ3FiUlkxwQc0GaZOxMBT7dIktZbzCj7EVn1PsjjB+5pQH6tBdVsNor4I + 8gdRMO8vgb+MKzKaAzTpDYgkiekXON5+dVyaKAUYBiLY8BpTdIkPQDsEObNtwM6/Qi7HXIBQIwG+Myae + 5iBgpp8HlhxlVH5LxFEsS1RgRX1OufvmfLHhMNlKy84iCyYVqWFQEs8ggijA9TXEnxn8iWDp17Hf9Sxk + SDMiTSBO4dVWADIcAZtDUWx0P0mjKRCnwGbCis7sMXfGTy/UcY8h1YQSu2BomrQoYUC98JwL4QW/tr4P + wAWA2xQAHJ8OdYCiAH+NAPDnp1pGTncAuBiICARtADA8BPOLi/DBD30Yvv/9H8DI+DgUSl1oAjR5qGXf + PLDgkspp0N4KW5DYuSATJVXh/FCFX9N7eZLp0u7a44kYe+pw0pmuCUKYAUfzFM8f4erfHGpAbWMVaudV + oTHagPzuPJRu74LwGArlCmoBVRTMSLjIiSUP6WN1wMjyAhwevayESoX1hO5Km4CIGZgr5DhUSluFc7k8 + awFmh6DQJJM27UMEO/IidRaqAGqf2GepFX4MAShRQYy9lBLN+QO9dPEzJKtEAYwD4kEDmpkmNLI1qBQr + sNK7gmAA0DtfgvxqCbKNLPgNn8k77kYi0HTqxkSKFQxSrgColuGpp0efX2zGSEUb79FoaoHyA2JwuQap + mcXXIWZpPgNP3PlE+NOn/NGaOWpMAOMLuPPOOzkM6DQ6IW0AIibgn3dMgIfQrvza1y5GDeAfXQ85oe3Q + 4ADMzs/BBz/8Ec7BNrxhHDWAHgSAhtB2WWgd+9aokE44jptd5uSnBQ6j/hsAsCE+ryWCYHbJibquDjNi + DqO63+yJoDnWgOqWMtQeXYVoKILcbhTM23GSH0LVfCEEv4yrXd0XSrDvmhS6Khub3XMu18I8NOsVgBTY + CDhJKDmtSkQJJj8AggARgjJaG8Bs9jFchET3B6Sec8+uhNb8SPyWDXpGlfeUwuvrB7Ef2dyGduORSdHu + CwOPqMEEAPV8DRb6F2Bqy0F8L4YtezdCz3w/FKoFyFQzAgD2+Zk9HJ4VVLNHQTYbWWgXwAL3HuUksQFW + 9UukpptLTwKj8ggwJFIRKshmYMe2HfCi560fBjQaAAEB2f/kB3AanZrov3+PrzchADROpYyc/gAA8I/u + jRoAODZ7jH0A/3ndtTC8aRy6enqgQQCQOGq0ESbr/II0dOUw+oxTzVNBdsNuLf43zcZjo38toTJVrTOo + hBAAoN3fmMBV7txVqDyuwiZA7r4cdN3UDfl9OMkXMuCv+jw1JJ24PSm0xP8hBQVQQbL35HrhPZmAFA7M + cqZgvBYKP9VPJJMgS9cIJFfgiaJ15nprvO4JgPOGsu8csHAfUhujUP5AwSQHIAJArYDAWKjA3OAsPLhz + HzTx/e27t8LgsQEorhQhX8lDNsqIzW+AFUy3001J1knhBgwSV+tPjBsIHIMqfR8gdYTqZ+nWaNBCKjGH + Urds2wIveOFaIpBv6k7o79YJmEYX6LcynvDTIBpAJwpwsk01AC4NZhOC4mAPDw/CsZkZ+MAHPwQ/vP56 + GJ7YAKXuLtEALF02FZKWzDpe68Rsmey2QCTYxcG1ZUU7dmYjOOEgdbIxZ78A7PyrbatC+YnLUDl/FZq9 + BAB56P1+D/sBwjlUdZdxUtaNeeK3PM31SmPb39ueuo2QEC3Yl3wARJcuofB3FTRdmIkGtFXrXUvxXZ/2 + 2xL+cz8zKj60nHZNv3lFRQ2hmW1CpVSD1dIqzAzNwIHtB9hPs2nvBAzNDED3UjcUV7HPzYzkSGgjCngn + M+WTFue/8135d72kJ24/zTm4rgHeHyVe2bp9O7zweWt9AC4AsBPw9tvhfnICplekE67g67P4evOlL7u0 + QwU+2XblP//zRTh6BACBCwCjo8Ocevn9H/gAXHvdDZwWvNhVZCKQXdltQc21QuOuqDbMZcNtDhOwFTdU + JfdaVjrPOcIQf6AQQx3t/+r2mgDAE1dRA4gh+2AOuv+jG0r3dkE4nYNgKYCglmoVcCKhd38/HgBoGnCy + +SlLcKmQ52xBOcoYlMnp5473f522frzdfa/1t8SxmaHtc0cJswDQyNVhpasCSz0rcGjjITi4dRJCFPZN + ezfB4OwA9M73QPdyF+QaWVSl/DXEoIejrQsIdlcgAkAux0Sg33/uJWsOWw8A2AnYehiRfxQAXtYBgJNt + CABEBf4y/ppxV7kNYyMwOzcL737P+xEAroeR0U1QKBW4bhyYai+uym92fDlqn4kSpuIbKNGG97zJtQCE + qAOyrx3W5e476iQRAzL4KkRQH61D5awqVB6PJsDjyxD1RJDdh3b59V0MANlDWQjmQ3YE2nClyTNo+5SG + wOy9tOi7re+Zun5E/slnZG9AsZhnPwD5BgJPKuKamoHpaVIRcDX9462YjovNcZodp3nmDAmH/apo+y91 + L8PC4AIc2HEADm45CNlyHjbv3gxDs4PQP9cHPYs9kK8hYEVKhFoHAgxhx7MPGtRSadVG1tNwzPvJujqC + YQEmWigE2Kl61o6z4OJnpZuBXPIP77dQZyA5AckMSDVDblQfgKjAHQB4KO0KBABwAIAeBlV0HR8bFgB4 + 7wfh2puvZROAEmNGjciGcex+fs1EI9EB3+4/99TxxduHdVtopFWBeFBjiQ0Qk17SgEHq4HLVUi1L7Rm6 + LR4bFREAxmtQOwdNgCeUofzYMsTdCAD7EQBuKUHxnhLkDuYgPBaCvxrq7kMlLxnqncmgY8yOJBU2ZjkG + rbY3mxF8ec0XmM3xmJSKRd4cRFmUQk0b7vlOmW7jDDTZcrR+oZeY3XHmEp6NSPL7fgoVnqH/eaYcmsCH + bO/lAuMc/osIAEp1WOhdgNnhY7DvrANwZMsh8OoBbNozAZsOjsPgzCBqAX1QqOYFAIxD0VxCBYurGHmp + 03INJVkdhibmbz9r81O0Nrb80zRvDgCcc/bZLTwAFwC4hqMCANn/RAdu23hFTkDaDfjnL3vZyzo+gJNt + X/unf7oIR9LWBqRGE5jCgDPTM/C+D34Qrnvwehh44ggUwhJEVa3mq7FxFhVTajrWFF1Bksa0dcLblU6T + g2iyL57CAaj3OTYxcN9mmPFMrQGuSR+IgoA9jdAEqA3XobGtDrXHlKHyqCpECADhkQAKdxWhcG8J8gdQ + KI/hdyoCAJyURDKYyNzU8t58DepFpNcxDs1A+8NKjykAAnx/5LTK+lnoCskH0MUaAFVP5lyC5AtAO8VX + ujQ55hJNlUbMQ3qxx9+XsGDkC0DyZxoBofeZSm3yJSRaTYkYfp7uxlRWjqd0a47/Z9D+L1ZhbmAOZkaO + ov0/BUcnjkAURjC+fwNs270NRg4OQ99cLxQqBQijkIk8no0yqGbmpAuT8TDBPJP0BUAzh4GlVisuCP07 + sb4LFyTEeahMRWE0sR8iV8jCOeedDc942jPWzFESegIAaqQJ0Op/5x13avTItg4A/DTtn7/61Ys9AQDP + aACBAsDRw9Pw3vf9Fdy472boP39ETICmrgpc517jyCJZXLzDCLuNpCtRiMNMkQkzybB6gWGHySlijbl7 + ysBjQAH9fiIMOw6xZXDy5GOOAtQ3NaB+do2jAUkO+1YHVP3zDAJZ0gDmcfJUQ+EVUHBI2YrcA00gYn0T + SRoGtBXDPOmfLOI+37dkAQ64XDnRgikkSLsEc0GOQYGLpQZi0khWH6Hq+rqDiQg6UtocdZ84lGM82RZr + 03xFCdvtni/3z4E342nn5BtpbcBYV2nqcxRSBKAKswPzMDsyA0cmpuHY6CxEmQYMHRmBiQc3wfChYeiZ + 74UiAQCeK2zK+SLlPfCoG9DWPQOSxUzDmIkmYzWCDenvSdxaYMZTDcXUdDRj7Su7kWtN0vigObVz11nw + nOc+c80cbQcAWv3vZhPACRdLUtCP4+tNCACdjEAn2/7pq1+9xBcAABcARkeG4ciRw/D+930AbvzxLTA0 + MY62bgmaDU0/JbaCkHp8k2lGVWqatDTXzY49vZavZBxipVkyTswGgGxeycRgt/D6GvtW3gAvSFRBl0wF + FP641ITmaBOqO2tQPa8Kzb6GrNR5FLpFXJlvQhMAzYFwNsNcAKagRrKix6H0kfcUxKBbivEeMmJmJMbH + ESsV2NNcg9plWXh8Lh0WUtVknLx5pgVn2HyitOHkRwlUl2HV3FfhVgGgVY/O2fSbTJwR/gORlgIGDo7n + E1EWxzbA90PasxALCFKYTzINqerdFB8KrfKNbJ19AMv9q7DSvwwLI3Ow0L/IvgFy/g3h6j94ZABKS92Q + r+UhQFAOItEk4nZ/iJIhfNe8Uy0kNVc0buo52hoouMZeSi5SALC1n40VEXm2TPuuLbvgJU/74zVztB0A + 2AeAL8/z3cNIfyMAeOPLXt7RAE66EQCQBuCblDogdf9GEAAOTx9iALj5lh/DyNgm5mtH9Ui48onY4lxs + w1lFzQQ3eeeoXLRMBI/Dd9RsKB5EjRXjI2nJCcCmQqhDz0uF5pyjrb/duB72onhsqEH58WVYfUKZ2Yj+ + cghJD07OFR+61BGYOZQDf0VNE5rETc+aIPQ/asAorNJ/BolY6cAERiGYwLXa5TiBKS9hKMJAzD9KCFLI + 5KELwZHyBVLS0Ew25PqBsnqrMyxJNQ5WpjVlmImRmzGJGBBozDLqSJXcgbTKk4DzhFRwEhOCziXmQoKa + RTMTsQkwMzwDRzfOwNzYHKx2r2KfEQBme2Fochg1gSHoWSATIAtZIgNFviTptAKVtPxr9meRhsLPyrA4 + 1QcQW/ZAnGp+fmzZgjaPo8kunEQ8Hcx+COICBPkAdm08G97w5NevmaMGAIwzkHwAd6IWsE4jAPizl738 + 5eVTKSOnOwBcrABgXVEMAKPDcPToNLznve+Hm2+9FUY3b2K+NmUPTlyaq+eEA90IgEF4zdJrmHVgOPFJ + YiecLTLiBBYSdfZZJxp9jyYfCWAJV8feBqr9dVj5pRWoPKYM4QyuunMZiPoj8NEMKN5ZhMIDqAUczkGw + GIr631A+gFKYzaaVFpaLVjCy24dFKZEdOhqgEBVcypIHpAFQ5SAKB3Li0CJrBFk1A0xmY5/VfV+2vxqf + gEkklgigRIkIsnEachVlMOm7lU3npQ43Vv91s44oU6gBoKq/iKv/0fGjsHfbPlT/jwltOtuEwmoBNqIJ + sHFyAwzMDEIJ/85EgTgCQfogarxGFdhWT6xfRvL3y3hF1kGoXdEIEGs6mm/QN7kYKfVXKDtIEy3jzjUl + YhD/CJ03F8LWzZvhJc9amxWYU7KpBkA/TRQAYI1wEhHoDQgAi6dSRk53ALhIAcA6AQlxx0ZHYAYB4N3v + +ysEgFtgZPNG9noTWtvcb3ww2CSbLWEhN4TWwhhJwcJk/HH3yqe8Dof8o19jpxxpAAWc0H1o626uwMpv + rEJzUw3C/VnwlwJojjT5vIX7ipB/IA/Zw1kIF9EMqDo5AUCv6/AC1mQLMupwe0gQ7NclRwDtEKSQINGC + UUOieDYXEAlyTA1O7/VE00iTcZpbN+8pZ1oCGK0kISdAKoQajrDEUM9XYLlvGQFgFvYhACyi+p9DVZ98 + Axlc6UcOjcL41AYYPjoExZUuCGs+A4B5RpaGnSQ2ZGtSvWuQWDQkz6kRCRK1sZmL28ODdhNW6iMw3IZm + LBokaU5bt26G5z1/LQ/ABQD6nXgA995z73qS+Q/4ev3LX/7yY6dSRk53AHg2PpAv4ytrbXUc5LGxEZg+ + fBgB4P1w649/DMMTG/khxbFlgcu/DgXYjZW3DGALscaNt4MNI3JLlYJWwXTAhAGghK+BBlS2VVgDoC3B + mQMZTgtZH0cACBPI7c5DYXcRTQC0y+czEFQCcba1U4G9E/S5/fd1yEEcDUAA4IShVEI8m+fUYTZVmBek + t7wGBNbn0bV/vn5msKTla6RpNHCVJfrv8uASzIwcg6mJKaiUKuztj2gFRmEbmO2D0cMjHAosLaOJVMOx + aZpIgwPCdtde+hxc4LefOSFMlx/gftc4Nl36gKd84mYi+wEKuQLs2LEDnvuc56wZY0MEMuFA2g1IiUHX + MBc8+Cr++zoEgMMnNflPsp3uAPAsHNgvkWvNCIU4AYfg8KHD8J73vw9uvf1OGNm0kTPhRFFDJ3IAZt+M + 6Mytk8VdRfm9NnqvnWh2lXVWNmNWGK3CmhHiqEu6UXVEAKidVYHVJ62wwzF3IMfH1ydqwgd4EAXxPjQB + JtEmn0XzoIqvhjFb1ANxIvpye/owF4icRqSgLFcQJkegsAE5VyC+F+q+gPUApJUd71wIUuYfpLfddqwH + awAgiBEAmlBGgV8YWILZ0RmYHp9GjSCCfDUH9WwD6mENBuZ6YPTgGAwfGYLuRQSAejbNm9DWxzXdO8XN + 1Acgb0Eetadzdp4Nz376Wh6A6wOgn6QB3HP33e1OQJ7OQADwipcfOpX9PBMA4IukNbcAwOgQHJyagve+ + /wPw49vvgJGNGznUFUeSeYedUGYlNXLlbIAxpcJa+PfrzHnPUn9N+EhmvJT8UgpxoHYwfTWH06UbV45B + Cv9VoUwAgF8hCrCHE7m+pQa17WgSHKRIQBcU9+QhM4MmQCWjAGBI7GYDjNcGRGuFvR0M3Mb7AsgEoFRh + lB8gm5PiIbkslw8LbC2E1ma1D2ejj7uKrreXyKj77acz4b8GcQBQA1hEADiGADAzPgMNHK/CcgFq+Tos + 9M9B70I3bH5wAkbRFOha7IZcFYEqchKEOB1sMfWO26ufvgkAYN9RqyQT6txdj4JnnoAHIAVrMsoDWEME + opGhTW2vRwA4cso6eUrv+L9gUx/Al9lH7wAAmQBTCADvee8H4LYHboPBHWNQCAqsZvueZKSJTQJQUMeR + oQcbhmDk2XgxD2QaDdIVhya0qMjECbB+BHZI+3boPZN5hmgGebxuTwT1wSbUEACq56+yTNM2YL8WSGjw + vCp4VeBIQPHuEoQIAOEKagBNjUbYLEYKBO32v5o1ZiuuzeWnfghPAx9mrGhyZlkDwNWfQoJkBqgvgCsH + +WmINEXJlN4M5m0we+rbBU+aIRPJ73oe8bZBI9uEeqbBEQAK+x3dMA2zY7M4vDF0L/RAI2jC3MgsqvwB + TCAAbJrcxJGAfBk1AEoW4KQH85Wk1b5pidPBW+cNOP1o1Z7iNP1Hixlgoc0DSwri7cD4IhLVOWfvgoue + cWINIAWAO9uBkFwlCgCvmD6VMnK6AwBFAf7RLtIaahkbG4VDkwfhXe95H9w2dxsMPG4E8kGeBZoeSEQe + 3IbUCEjLvZpVVZmAsXDibfnv2BTMdFSGRPIKBh7oKm8DyVoSTHmBdCjxeXIJRF242vVH0MTVvvroKofR + M6gBBDi5k2IM9U11iLtwVdmbh9ydRcgeIy6Az59TIgxP6a+mYKiNaZvrmrRkEvtKNQVwqa9gtYaQ+ABZ + qSKcp/oBeUoUkmONidKJsxmgFXtMghNvTVJOQwvW9FsgEYM0j1j7bkAntx5xBjIIirkG7wCcHZ6DA9sm + YWF4Ee3/HLP+aOwX+5dQS6izI3Dzvgnon+2HQjkvANA0oKh8DZDVWTI4ScwizeRjjkzFWv40g9K6r9kU + Po21uIj1DSaeAkDEAr59x/Z1NwPRfDQ+AAMAd915F6yjWNGmNgKAjgZwss3wABzrVwBgfAQOTR2Cv/zL + d8OdR++GoXPHWM2lB0BU1ybO5UatDs2kmXqEjSptFiffpAtzEnIC2ESWdoL4YvObEl2egkFipI/3AIDU + /8vETPltDkTQ2Irq/q4aeCsemwBB3WcnYWOwDtFQkzcC5XYXIDeXBa/icYow2hrsNyXjEGkziUlQYvud + huWks9pTA0hOv813fHYGZiDn53B8ZJswmwKZHDsBqcKwyY4MnmHaiYYkpcrBqtzGE+9pwUKbNAS05Fos + NfsMjnL0nR2AQgKqFMtwFFf+B3c9CJWuCvQd64Pe+V5m+632rkKlVMb3+mF8/zgM4GelapHzBFIWZZMQ + mSneidTt5PKOic/DFYHUBZRya2kdRKH7aqZoJYAY7k9sNATDpUhS7SfRMGaCqwntrtyyfTM87w/W3w1o + ogDkW6Ew4N13tSYFVTD4Er7e0NEAHkI7HgCMj4+iCXAQLn/nO+Ge+++D0YlNnAGXVdswiwtGArVmjV+8 + RZjmpQqyp9WAY6OoapLMRB17FNKKHU88ee3BJtGINUZPzrPIkkko7TZnAiomvO+/STsBn1iG2uMquPqj + wN2TZxOAQoS18SrUxxsMAIUHUQuYzwLQ6r+KWsCyz0Dg1rZPVO031bO9wDx13dZrc5UlrG5r5N2mRaeP + iBFIVYOJAESJQql+QCaXYeKQ3L9TpFTDYEyh8TSjL4ANl5nU517s2TTlqfe9nYWXcN6/ZkacgFWiASMA + TG2f4v734upfWilxqG+1ZwXKCArkBxg4OIzA0A1F2hCEAOBHWt4rcZ6FAWQTHYj9dNWNRXszSeC4oIwB + eksjljGKlSgm+p2Mqa8mAIUFKbRM9Re3T2yDFz/7RS3zk85rzCyjAXBGIASBdUTzC/h6/Ste+YrZUykj + ZxYA6HZXAoDJqSl457veBXffgwCwaYIz35S4KGaOhb1aq0GlXIF6vcEPkb9u+PrgrJjGD6hbhlXzT+sJ + GAdcokkEecOPkGBA6bq0xRYyqBP00AtNgE01WPmNFaidW4XCzQUo3F0EvxJwfYDKjjL7B4LFDBTuK0Bm + jiIACACUMXg6wzkCoCmsP1tGzEQauOsSg/fSJV41g8RaLyaNmKzCkiuQwoH8ymcgXxBTIKcmgOxnT3S/ + AziFT+V6sVs9VwL71rtvN+GYz8C4MqTzxBBs4os8/cT6O7pxGmY2zHDWn+7FHg710ZeX+5b48945oQR3 + L/VArhpCQGNj042bLhmTxGw0TrRmA9jOJ6lIC1fAdfKqFhXr/oYWE8uArfqRYgSBsJiB88YeBS978kvX + zFHXB0AaAIUAaT9AGh6xs/fzIAAwdypl5MwDAPUBHD54CN757nfBHahujWzZBKVSibe9looF5grUalVY + WV2FarUGUTNK4+tm9TR2o9loo6ql+d2mCQMje2mcvsWcoPOQkyBLIUCcUr0NqKH6v/rrq9AcbkLhR0XI + HShAiAAQ5yKonl2G8pPKbEZk9+RYE6AVjqIBuck8g4DJFShpsEFYhg4fwRBiEgUAA1KW5aj59qV3kiSE + k4USBwBXftodSPkC8/gehwN9hw9gKwjLJUlEzPZna1k753YlU3L9K7swlv0EjaCBwl/jLEBEAjqy6TDM + jB2FrpUuFPY+yNRD3n8xPzgPK73L0E8mwIFx6FnoEScgAkSYhI42FFsA4DSsiVB7jYPSRE5MERNZ8eMU + HEywhXxFYLdYpt8FwxNI+N4JBMJiCOdOnAsv/q21OQFdHgBFWigZCIUC1yFIMBHoFa98ZYcIdLJtPQAI + 2QQYh4MHp+Bd73433HbnXTC6ZSN0lbrYuVUqlJgV2GjUYbmyAqurFWggCLBy7PupBmBNZc9ZWhyPsQUK + sOBhdrx5ujJasSDwcCIAFO6r/OIq1wIo/qALsjNZMQEQAGrbqwwAzdEGeEu0HRgn0GoA+ftReyGT4FAe + wsWA02T7mhMP1iMguc1EB6C9/+ZrHof9iABEaipVDqL6innDB+AJrArzOs6/FiIOgBbz0D0ETqbQtFKv + 2NvkWGuECIj5Gqr3ZVgeWIZp0gBGZqBvoRcGjw4iAGSgkY1gfniOAWBgRnwA5BsorBQgwM9D8gMYefIT + XaE99cUmFsxlJU/LibMPJVKNQf1ABDaMkdZvIosA71dIUpBlAOCUYDFrTRQFeM7TWncDSq3K1AdAWtV9 + 9yoAtJIU6ErsBEQAOHoqZeS0BoBvXnPNSyqVyidaASCEjRs3wNTUJPzlX74Lbr/7ThjZuok3vJAPoKur + xMwtUvtXqquwsrIK5XIVmlGDVzrPCIsLAMbg1hFtfU9FylHDW6jF9BY9f7Q8ol7KBIQAsLkmIUD8DqUA + y1KsH1f0Zi7Gz+pQfUwFao+q8LZhqg3go8AXbkYNhujBh8QsoCpCYgp4LQL+07ADqb9kBnDdACodlitw + /cB8Jg9BGPDGIbOKwRrNtZX881AaCRV5/2kHYLl7BRZGFmFq2xRTgMcPjCEADEEGhbuercPc0Dys9i9D + LwHA5CiHB4vLJdYQ/GaQZhlueVa6brcxAFPvv68WgQn1eur7UWehlpL3TY0BG8xQU0ZNAALOXY/aBc98 + +tNa7q8dAMgMvf+++7k4SNuYkXPki/jzDR0N4Ce0Wq02jj9+jV6Tk5PPu+3HPx50b5IGe+OmDXD48BG4 + 7LLL4Y47iQmIJkBXkQkbXaUidOdL/LDLaAYsryzDUnkVGrVGKkjGsWYE3U/tPkP4aRlYY2sbB5eboot3 + BlIqcHz1x5wKjDSA6uNW+Tul73aLbY8AEOfx/jYgAJyLAPC4MsRo/pLXP8lEkL8jD8XbuyG/vwghAQBq + Bl7d0zwFejlnV2Qq72sBIQ0NggU08p2QsFMkoESZgihXYCbPDkIqJkLA6vLg3XOeCACOV0RUEnEkuPoT + AaiM9v0yHNswB3vO3cN+gc33boaB2X4IIgWA4XmYH5mDnrkeNgEoK1BpEbW5mvgBTpgX0NIOkpb3WkDS + RHFbSwa2JAuxX02SFhCgHAo7d7amBLNfd3ICFotF2LNnD9x6yy0MHM4TIg1AnICveuX8zyojLVPzVJ7s + 59XQXp/AH0/GIftNHP1n4APooxj+oUOH4LYf3w5rAGDjRjhy+DC8/bLL4I6774WxsY246ksxzC4Egh40 + B+ih1BsN9gMsLywzGLDNZ8t7aajLN551yZHvJaa+n+YBzHDtGateijXgcfFPqjZM9jntQiMSUDRMqcBQ + wM9CALigDAFt/f12D4RHMpL4AwW+NlKH2tkVqKMGkOjW2ca2KoSzeOy1fVC4iwqHoFBSpiCqIdhUADCb + msxo+KkmYqnMZnU0Woy7D4JThUlGINKQCADIBKAtw1RYVKoHpSc42YmVOKtry3vqiKzl6lAurnKYb3pi + GvafvZ/Zf+N7NkHPchfnE2iGTYkObJ1Cuz8PE3s2Mx24tNAFuQqaKY1Qd++duA/28za8aiEorWU3r/1O + Iv4Mc24Px2bHtm3w/Oc+b8212wHgwQcfhFtuvrkFALSRE/DPXvmqM1wDqFTKJfyxE19bcXi34S08BUf5 + 19mFJrEXGTz8//CRI8Kqcr5vAODQ5BS87R2XwV3z98PgljEoekJzLZbIwdXFKi8VdaiW62gGlKFcWYZG + MxKvvcbTzKYPab7kAaTEmXFia4aw77+pWoFxIpLwEXg0JSzo5fB3ygKE6n9zYwPKj68yAGQfzCIAoEAf + yUG4kuH7oK3CtS1VPo6Ap5mNOSqQdEdQurULSjd28/GZZaoeJJmC2NtAti8DlWYgASWuBNCa/jzRJCXu + /gfVHILA43yBtC+AnIDFgmwMIkIQrXL0uetDSLxkjTABgI3/6x96uJMdSQWNulnLVqUC0MAKHN52BKY3 + HYGBIwMweHgYiuUCOwsbfgMWxxZh3zn7uWzY5t0TsHHfGPTMo/ZUK0BIZkBk03WkLMWk7SfYrgO0mALr + H3e81qoBJOwj2YYA8AcXXZKOp7mW57UAwL69e+Hmm25mzaGtfQmPfgP+PIogcMp2MfxfAQAo9CP448k4 + tL+K4/lbKIXbcJCzZsOFLXiZ6OBr2G766DTcffe9LTdKALBpw0Y4PHUQ3vb2d8Adzbuh79HDLPyUCZdy + 4JM3NutnWLgbzSav/pVymTWCOFYHlq52psClrf0XSvjNZLkSTSHR4z0bAfDVgQzqA6BqQPEQvsYasPqE + VRTqGqr1aJbciHb9TA6CVbJl8TjKF9CP/Sji+QsIGPh3fUMDook6Zwou3Yx270G0zREAwjIlxEik2pEm + uQBNuWVWWC5vRY4uTVHGgqtJTHmLMZsQsleewpVkClCSkO5sN/sBmBIckGkgjDbKJ+BrqrTYsCWYYuDb + kmCx5sxjFmGc5gCg7bYGBDiZBm0BztVgtWuVHYCHth3iEODIwREYOEx7/ou8utfDOgPEoW2HYalnGUYP + DsNm1BB65/ohT6nBqqG9tqQ/8KzWbtmb5jnaHVqSg0C4HamwxC1RDC/9jpeSBV0AiHD8Ka/C1m1b4QUX + rdUA3NJgFInav38/3HTDjTb07Ego+wBe+apXnRlOwHJ5ZRP+eAp28ZdxRJ+OKv24EXgwgp5oEgYQ0gX/ + Z37iZ5T4897772+5UQKAiQkBgMve/k748eQdMHT2BlRpS1AMc1wLL9+NwpPL8sRvNJqoBdRgpVqBSlSB + JkqLZzz4hmqr9fwgBPs+aKhIQm2RFSqZW+pc0hqDnCargIKNJkADTYDaeTWIe2LI3VmAzP4M7/n3yh7z + /YkNGJcijhBQ+vBmNwoJmgXNiQaDROFucgTi8ZUsbxDyDReAbNfEt/a9aNki4Cbvnq9SkWj83w6aaj30 + XuhR/UC8TibHZa+JIUipwsgHEGoZ8Vi1C99JyJmyflNCja/JP03+P0nIqVmXiAMQ4Hjk62j/l2GlZxVm + Nk3DsbEZGJgegaFDQ9C1hDZ+XXwAxAGY3TgH84OL0H+sFzY+uIEBoIBaQpZ8AJRajMg9sWH4iX0uOQHT + /Qwmp6IIoJduDiPzzgdbHlyyQwnImUKjximYeGYzUMzzMcxmYNOWTfD8563PBDTlwbu7u2HywCRcd911 + dhFLnwCbAG945atfdXr6AFZXl2nPKznwUOhplU9+D4ezhwcyjoU6qoIPNue6/B6bv+NWb8yx2Vm49x6p + smLULgMAFAa8/PJ3w2133AEj4xuhq0A8gAIUipIKO4vqLcex6xGUq1VYri/DSkWcgYluFLL5Aoz3Wxlh + AghqW/M80sJ4nPVH+eiRDn8Qs58g6UugtgFt/y01qJ9bAw/xJ38TAsBUlkk/5NWnSABThosRr/4RCj/R + hutoEtS31cBfCJg0RJmCwtWMsAKbQnmlDQk8MqaMgGYIpj7yVDNcWV/6m3D8X8bR7Iwk3ryvcf98LsNb + qAPmAvjKaQ+ddOGJ8u49C9Kp79OZdrEh4ICYUKyJBJCEkoCDCoHQJqBydwUWR+ZgaWgR+qYHoR/NALL3 + SQNohg2odJXx8yVY6l+C7rkeGDlEPgAci0qeTYCQNwUFnCOQwVo1M751TdySqK/GT2ItZe5riXDPRlO5 + 8rBTBCZmVc9jE4MBzzfFSD0BB7xGNszD1q3b4LmXrF8e3AWAgwcPwrU/utYFAOok5U77HJAP4NWvWjqV + cvdzA4CV1eVevPhv40g/KWF7Hs5FASbVvmhW8lStj1sEPza/2+NkdgXMqArED4Cv6SPTHFaxCTJokc4I + ABxApH0nhwHv4nwAZH9RXkASfvJyU7zb10zAtaiOIFCG1eUymwKNZkPk3XccaJz9V+1MQ7f1HGKM1Sw9 + SyPw2Y8gtQCJA0AMwNpZVQYAWum7/rMHMnvRxiayD1UDprRfoewaJE5Ag8KGI01onFNhx2AwG0L+NlwV + p3Blxu+ICRCICaBxa15/jRtAE5z6muCSyTAhaIFTdRnGnk0sSinLgFd7BJowy9WDwwKVFPeZxRb4Wc5B + aEt9BZLMI45iMCR6EhAxARK7c9Hk3otMAlGNq0ecA7AC5Z4yLKNgz2w8BuXeMq/u/WgCBLzfn/wgaDb1 + EgAscLXgnmPdCBD9UFpGIK/mOArAj4CStBpTjdE94VyDNpNy7Gu6b90oYO7fJHAFXdltIVZfyo/ZnYVi + +pCpJhyMREqDFXPw2E2PhT/81dbagCZZrVmcenp64BABwLXXcno6bQoAHgPAq/5vBoCV5cUNQKu7B7+I + 4/JUHMwdRoCN7W5LRal6b/6ONd9awsKtO/DYg5qRajX4H+29btaJv9/gY2aPzcLevfvbAADVsYlNvB34 + cvIBPHAPjCEgUAyWAaAkFXEpLTZv2yV1FCdKtVaFVRT+VQSCehWvEcfWk+56stdLGNIy0s5efalCTPY/ + MQDxtbEOdQSA6qPq/P3i9yish5N8CfuCAEAhP1Y2UDsg5iDtG6iN1qFxdhVqj61w2rDCrSU0G3JcMyCD + WoCHK6SUuzWqq69lw6GFi2+rHSVgC43KJiaNdSvRx/dCzhdIOQFIY6LQKfEBipmChALDtOS3ON4kVRbR + fllw6DKUq0859ZGmVdfaJnbchP5L9v8K2v+rcAxt//27DqCwR7DrprNg8PAQZDTzby1Xg6WBZZjddAwW + B9AEmO6DkalhzgqUIy2BQoGRn9rpvub0TxSQjMMt8TSnoXleYm4yGIVxusnT7npUzp9T1VhOQyxAkxsR + 51w+hMdvfgK86BdesAYAzOpPjQCA8lSQCSCgCdoJBACPS4MhALx6+VTK5MMOACj0W/HHU/AufglH/Gk4 + F0atCm+SQbr2fIt9n6r6Jt8aC32YsY4TEvZmo86bdgRAhNtFZsMxBICpyYMOACQMAOMbxmEKkfYdl70D + 7t23G8Y2bmTh5w1BhS4uhxUE6dDQt+v1JlQauBpVyrJHoNGwn6XFQb0WwW9h1bkAYN7UYqCQQ1W+D8Fr + QwMaWxAEzq2zz6D0PVzN90sNQH/Vs+onnyArxKHaKGoM59Sg/MurPHbF67ogfy+aDsdQA1gW/oBNcmr6 + ZgConbhjgMtSedPPeaJ6AgS0eSlL0YBsQXYG4tjRz1ALiNpbdZz9LhUZjL9BBdIkLzW77kS7QoDLUh1A + cQBOb5uGybMnIbeag5237uBdfwVU76n2QCVb5e3AxzYf5UzBtPqPEhlovhfyKzk0A/DVyIgqryw/TlAa + K0CpI8/UeOA13RQP0d2AsS8qnOfsAVHysmMB6mYw3eEgdQbwOtkAzj7rHLj49569Rj7MPKZ5TgBAC9MN + 11/vAgA1gvD/DQQAr3n16qmUz1MKAIuL8wW8mZ14P2fh/WzFk/8iCu7v4hAWXVU+cR15DgC0AoNOFF2F + WYP0dVMHrfSNJqfwIkEnzzyt/vSziaoTcffp59ISrgozMy3qG6n2GxEA9u7bB5dd/g7YPXUAxjZskEw3 + CADFQhG60AwguxY00SPb3fjdWgNtURR+0gQq1cpaANDaf2aXXeLMe69FAFIASBgAaDXH+9ko2YAJAEh9 + LvwQtZE9RfAXfXYCslfeOJwy+LMLbWTiBZyFK+WvLkNzqA7Fm7qgdHM3hIczkFnW2oHG3+D2w4JA6zRY + N12Y+V3V1YALiAacHISiACT8pBGQs4uyCPngtZynhTjjTj4vzcVnPPIG4CKtBLyMKv0KCvfRLTNoAhxF + 9b4XNj+wiWP8hTKaHDiA1Xwdj1uGI1uPwNGJaRT8HhjdOw4D0/1QXMmzryBbz4AhYrmUwJQbYTICgFZT + kptOnH9NJCExC4ra+rL4kwkjx5qy5DK3I/AzPmzbsR0uvkhyAraTpXyt19Db28sawPVrAYAapwVHAPiv + kxYcBZ6sXQrR/RbwCk+hOuAQHRgvqLXXwVHxnZCdY9cbtZ5XEqZHepyos14jtb6eHh+LjU+VfGi3Xp3A + IE6JF2Z1K5dXWwGA5Aa1h82o8j+4HwHgbe+A+x58EMZGxyXtFe0ILJagG7UA8hWwLRrHNkbdjJpQrqMp + sLoKZdoj0GyqOqh9N6nAzeSx+QLSlTXRCIJUAvLY2UU0YM4BMEEOQLTnH10DfzbgfQDFfXmuCQBlT/P+ + 6yTMSArxiLIHbaLtwyvQ2FGF3IMFKF7fDZmDWcig5iB+AItCLSu8XeXbp0Gb4IP2P81i4/Eed94cRACQ + EQ4Fcd4zXladh60gcKLm8vBNvzgCkGmy7b9MWYBQvZ8fmYf+o30wvm8DdC2UmORDDsN6vgkrPQgAmw+j + ljDFTr+JByZgdP8IlFaK4iysZ9IU5FYbSlLyE3ektb/uR/ZvzxSKST80/KcWLpBZ3OhoXEx2bN0Glzz7 + uem5nLExANDX18dOwOvRBCAfgNdyZfgkCAD8fE2A5eWFLPb1t/HX30JBvBBv+jzsfI/x0oMTihPhaV3p + GTQ1PCLbLI3Qy8YSmj0RCloVV9io2bARAGoEErTy12po9+IAsdqfQIsjxf1JgnoMAcAdbNIAtmyZgAOT + BxAALoc7d98LI6OjEtZCm7arq4sjAewEBGXSJVI9h6+PfatUKrC8iCBAfeQgulTm5fJYjkqdqEngg5Nx + 1jeeZ80BkMGxKOCEH42huqMM1V9Yhcb2BmTvzEPpB92QOygpv6AsHn0GAHLIZYHzA1AJsdpoA0FjlbcP + Z6bRNr8Rv7cfx3Mh4IzBniHB2OSlMvnTpKduHBzWbHgCZ4ylkKlEU/KhpgnXfIGkBWTIEeh7TqKU48y2 + Nt68fGy8o4ndAryMgr08uMgOwIXhJQaAjXvGobiEAFDNcbWhBmcLWoH5DbOwf9cURw0mHtgAG/ZugNIS + Ps9VcgZm0uSgSctjcnrRzvhxNYZ1PgaX/u3eE7AjOtG57+NYbdm82RKB3HnqNgIAYq9ef+11qRMwPezT + +HrDq1/zmp9PXYBGo/4YFEq8A+/piFiPI2Elpw8JcxkFjT3jcXrTYAbBCLxBXkVLJo1wtdmMeDnw+3Wi + 20aSiotUIAMotMLXUejrKPC04hvgsBtQAE4OAJwc7Xv37IO3X3453LV8NwzuGJHJjC9Of80cd1Vlm2BD + W+Lp96CGfVhdEQBoUEXhRItjJr6NGfNqqx5kIQs5CTCaeqwhABVxJR+LoELe/AtWmRmYux1V19uLrMqH + y4Hk/m+ot578E1S2rBDLBqKRBlQeW4b6eQQAGQQAyRgczmW4eCjxATgVV2DU0tan7/saAlOWnG/UXUgp + uRIZ0IKdvow9FQnJ5ULmTpD/hECANCxTQtyu6uZankP9NWPirMLm2FirANXyCAB9i7AwtAiz43MIBMsw + eHgANqBwUyEQyglA8X2KApSJK9CPWsCOwzCPxw8dGIKN+8ehNN8F+RXaE0D5AVtNNuu0M4lIrBw7ORwT + 5/kbk6kNAFqa82esSBNw5GlTCxHoeAAwNak+gFYeAJ31MwwAr32EAeCCCy54yoUXXvgafHD/T7lcLoAK + OK2Uo7hynnXWDvjN3/wtLrdVQ1V9aWGeVWOz8lPjGHGYke20AKyuk6ATysXNiNV8Ao+I7fmIBaxer7NN + Ty8GF9cZpec8nuCbhv0VAHDuh3azbdu6Bfbctxfe8va3w/3JAzBw9jATWojhRhWCKIMLbXLxPd+Wu04M + dRb/aWIfK9U6OwOpb5wYwhMfgKdFJsWbTscLZdhoKuxTMFV6SZCJ2JPHMRhuMvuPXsE8qtd7UZ2eyoE3 + g2OHq3/Izjyzf16LalIdwW5UlckM2IUAeXYFwqO4Mt9RgNzRLG8K8io47lWpkcdpt/xYi2H4ar+mCUSt + XyD27S5CphBrLhMJWQhAUMw/S2XC8LkSg1IAIC9VhH2JoJhyarFJ+MmhSMOPTPMEGu3I2NhUQowoznUq + BT64ALMjc3Bs4hjUuiqwYfc4jO3egGp9gXP+kVOONAAKDxJZ6OiWaTYVBg4OwdjUCHTNoQawhBpAPavl + 0RxHaOIIsJf2yuZ51CxCiZPhpD264+4PcFOcJZoSnIlAOZxzW7bC8571XDhR6+/vh8nJSQaAJN0LQL+Q + x5miAG9EAHjkTIAnPOEJv4M/rkCVN0fCSsJHK+hv//Zvw/T0NDsr6MFOTEzAU5/6VHj+858PGzZsQKGb + Zh59hjzDGXG+sGDjikn2vJgAxmaPUa2OOfEGJeGo1ppq64OmzPPXVfHbAWA9EFgXABCNt2zZDA8+uA/+ + 3ze/BfYuTMLgxhGm/lL8P99VgGxR0mFbu13r3PH89yTAU6/h6rS6DNVGBTXzGEy2KbL3bPPF/jOTyCSk + tOQhkmcUYi4HNoTaza4qNLY0wJ9G4TqA6vQ0AgDivVfzucCF9CHNOhRTGnHyA1Al4R11/r637EP+bgQy + zg5Ewo/fq5lkHykHwQKA4d+7ewFAhV0Flz3fkaoBupefOH/kpyGbn0qF0cagXCiaU5YYgV6o50usI5UX + +9iUDEts+W1ymiHkitnoaVnxLM6X7hqnAZ9F9Z8cfNSxbbdtg6HJIWb45cs5PmeDdgwqW3CaAGBsHjWA + ERg5MMz1AYrLaNJR7YRYCqhoPiYQl12c+kKUrsACbJN/yOCQr8HQGygnQOzmCQTlB3ix3R3IC53O8wBN + I1oon/P0tWnB2wHA+ADaAIA8zsQDeBMCwCMXBXjiE594Jd7YM0noKUSxsrLCAvmRj/41awB/8kcvZjWb + Bo9WfxL+D3/4w6g1nA8LC4vQqNdwJa/hz7qU3UpSoSfVuVKt4gs/V449Tzvf5KJLhflUAgAzATdthP2I + tH/+pjfD1JEjMDwyyptcisQDIB9AoWC3txrHnZ0YqhNSfoCFlSUoV1bRNMH+N3UwCQCCxKbi4nRUWorK + 19x/JvZOLoMI1XjayNMca0L1cWVo7GhAQACwGwVrEgVqDq9axcnXEE3CC8zKrGnEKRIw3GAiUOWCMq+8 + +ZtROO5HdXwpy+FDqKkPoG1MjXrPphsHrHVhVCKQ7HwSyiuvf5rO3FMzwM9INIAcggSs2VAShhAIpKp/ + omZLOuH4XBHYXIJsJ3NiURYvzhgWUR2A7ios96/A4hhqARtn0ebPw6a7J6DrWIkzAmdQrefS3yGCRbEC + qz1lmJ2YgyU8vu9gPwyiGUCZgzgxCI5hwDUMgzRCY5ilZE6y59FTNmdrhmfSGgK211RrcVKDh0loAcAS + vvRGE7F/ESizvB34mc/4vRMK48DAAPsArrv2Wk4mquehM1JFYPIB/PmrX/vaRy4KgADwLVz5n0or/Pnn + n88TmBxhv/O7T4cGdvDv//Z/wBEUoLm5OQYAcspt2bIF3vve98KuXbtgFjUBWtVJ+CksR6YBOfGqZM9r + rr3jCfhPAoD1QKAdDMg3cezYsZabJNWVmIB796MG8BdvgcnpQzAyOq673HLQ3dXDce3QD6zTq71xtpok + gpXVCqyUlzl/YLMRpfRgxz3sg5M6DFI7l8GEWX0ofEUCAATE8xEAdjUgRADI3JvlDD/BNIrGqjryVCMy + 8cUkB2ICjNahurMK5V9egWQogdzNRSjchNrMdFaKh9K24MRwCFS1MnY9KMlKdyq66m7imxi3+DE8BWde + NQMQx20o6cKodkCO8gXmCgIAnmgZnPfPT9KIiCcrI++T97Vyr1H3dJNQk/Ij5pqc5HNxcAmWR5dgZWAZ + uijhJ67qhcWcbPNtZrg/VDiklq9Aua8KCxvn+fju6R7oP0hhwCJzByhDUqAZixPV6ozAeiY1Ozj2v0Nm + kJTuurTzHgf9iMuY++kzNSaGgTlmWMYIlFQe/Bx4wW/+/k8GANYAWnwA1C2CJgoDvunVr3vtI1MeHAWe + RvdHCAAXjI2NwdLSEgt5qdQFf/G2y6FY6IIffv9bMDg4CIuLS3DXXXfC7t27WeB+6Zd+CT7ykY/A/Pws + l+AiJ15sQ4BeOpGPI/Dtwny8Yw0AHO/7BgCcVC1so27eMoEmwF5469svgwen9sPo+BivYqTGigaQZw3g + uIOmwFCrNmgPA5RrFbnHJC0eaUbXgpdxdDmhJtrQExcS3twTUdGPx6EJcE4dwsMIAPfhJN+LAHBUSEBc + +MOzmQjEwUAA0oUAgOYD8QdoC3F9ax2y+3JQuB4B4EAOgrksOxB9U8bc9bpr5WNbrMNUNjG0ZWPN6E5B + c98cr6fioV6Gx4mdgQVyoOagSDRqCuNyynBfEoX6oJtw1MkHpvpuG8BqOXDKAtwsNnlFnxudg4XxBc72 + 0zPTDUP7iODTDRkGAOFqcNnw0ioeswpHtx1ljaH3SB8MTg0iaHQxGYiTg0ayUyc2ZlgiVGVfQ4KS6lsF + TzM/2yShFthlrLhQqEkGosAZqzM49S2I6evlfdi1aRe8/Bde0jKP2hOlEACQCXDj9Tes5wT8G3y98TWv + e23jkQIA2pxzMwLAeZRDj1Z5UqkpX95l7/wr7vx73/lWBIAB+JVf+VUufkgUxm9/+1uo7pwNH//4x9lP + MDk5xavEQxH4U6UFEG/fAIAEFCQKsG3bFtiDAPC2yy+HB/bugeGxUc55x0UvigVODhqEqQnQPlpGoMmM + Ia5BFU2Zar3KICCHtcbQDYtuzbkyoDZ8xPv7a09Ac2h7HTIPZFgDyB1AIDqGtmvFYzeQZRRwiNHnSAA5 + EKM+fJEJ8dgqk4IoIUjhxwWmBIezWXYiCjmljdjTzlp0ojQt76tA2KkIAh4h5wAItHwYhVFx/LIFZ3NQ + YMOBFIWgFtsTpGDogWdVawaMMIZ6oQ4rfWWY3zAH86PzLNx9R3rYCdhDyUArOdkbgcAS5WLeLEQ5AQ/t + PATz43PQR3TgyRHome0WHwAVCq1JmTBT4ttoQ74lAgGXDPeM/W/vN+EqRLEKfwC+dWAmSiuWnIAJ+xj4 + d9V6yJb3cf5v37wdXvQ7rXsB2oScF1MyAW64bk0UgJoBgPrPKvRu+0kAcAMCwGNJA1hYWGAAoJjvm9/2 + Pj7mA+95C/sFyPZ/0YtezFVNrrnmajjnnHMcAJg8YbhuvfeOBwDrfXYiXwABwAwRgczcxUElVfWsHVvh + gd174G2XvQv27NsDQ6MjqBmEvAegyJlu8uwr8DVltk1skaTCz9MVH26tjitvnSjC+EINCQjxJaOGzXC7 + RtDUhidOP7H5iMxDgl95coWjAbkfFhgAslM53ghEpcA4v18bnZY0gIgiAT0RxKRBPAYBYGcNglkf8ncV + OIoQHA05aaivLMKW2LyXCviJSDsthUYdACBGoMkFQONKORVpT0AmyHL6MM5247cVEE0tDIdBma6axLlv + 5kmlr7Laf2zzHMwhCBAvYHTvMIzuG2FTIFvFa9A+hwSYMUgOQ9IYDu84CDNbZqB7tguPHcOfPVBcLDId + mNKDsYC2MfHshi3to93MFNtBEj9IYoyhdBxSy6C13FgCZu+Az2MxsWUjXHJRKxHI2fDDbWhoiDNVXXft + dexE1wPNx3+Hrz9DAKg8dDE/fjvuU7/ggguK+ONO7OS2kZERBgAiwBAAvOHN7+GOffQDb+PVjxyEf/In + fwoHDhyAK6+8AoaHh+HTn/40zM7OMqK5AGAH/SQAwD32JwHAep+Rg5KYgInWn49ZA8igtrJNAOCtl8Pk + /kno7x9mLaVQzHN24FxeACAEySXH3l2dGKbIhtGUqXoQFRBZoY1C5Qo0EQR4lyBI3L1daOyoE2eogK/u + REKA56IN/9QyT7TCvxchfACF/6Dk+ffqal/ax+XZc0S0M7CXAAABBE2I2mNwfiz6ULylC7IHHAAw+QFh + rYbigsK6xT7bBVjNXNrNGIQ4wTM+hwN5MxVFUggAAikc4msNgnYq9Hq5A3lHIAoze/WLq7A0vAiHz5mG + YxOzUJgvwsRdm2DgcD+TeygbMFX+pdbINKDehfePAHBk+xGYPHcSsmgiTNw9AT3TlBsQ+7SaY4YgOQFT + 299LhR3AAqSt9Ne2ycvkAmgBMmf8bKajWP0kej7yAWye2AS/f9HFLePavsozABw5Atf96NoUANLGTMDX + vP51j0wYEAGgF38cQADoIQ1gfn7eagCvftO7mbTzdx97N3vwyWv+0pe+DA4fPgRf+9o/c2aTz33uc7C8 + vMybG0zW01OhBaz3neNpAeQDmDl61CEmyWag7du3wAMP7IG3vu3tcLh8FHr7ByDElYEcWJQSrIAvVMJt + KSh3srh178hxRCojJw2p4IrF5kBFSlwlvibHAC1Go1EAs9uRVo4SToI+SQVWR/W98t+qkJlBm/qmHNvx + wWEct1UiACVpMVIw8VEBFEoUGvU1oTlWh/qja1D5lRWIMwmzCAt3kA+BIgE48WtiRthxsljipcVDYH0A + WKO9SByRd9OFWQSBXLo3gHwABZMmLJR03Oztd0sjtk07w8LnqAgxACkHAKr0tLFnatdBWB1chaGpIRjd + PQo9M71QXClwIhCvKaYVhwxLFQSAKhzbOAuTj57kUmJbbt8K/QgYzAUgPwBpAEmwtjipo93Y0K8BAUha + AaBdauzUauUAmLvi2pBUGWjLVrjkmc+xY2zzXDiNAOAwmQDX37BGO/CUCYgA8MgQgZ70pCcRAOzHTvYS + 4cf4ACgLzGv+4v0wc+QgfO4TH+GboL30BACHDh2EK674GgPAZz7zGV6BCQBOhrRzMp+1+xHc39cDATYB + 0AxxVT4u1Lh9K9x37wPwlre9FY6OzkL35j4OS2Vx1SqEBQa5kPIKBKbMVZImfIj1Yfu6stHfTeBEIbxT + sF6DmCjKTV1RTAIKzngjYTQ/0j3lqGPFPQk0B0h4KRNQEwU/Iz6ASeIBCAWYNABxvAd4bt2b4KlGkfOg + 2RVBcyiCaAcKzi+scAHRIlOJSxBO5iWhSE1TfxnhjyUUx85EdSj6ZvIqUcnYsTz2Wl0HTG4ArQIU5PFb + CABEnsqHWSgFRSZUZfxQ6gZ6qRaQTroUgFyGKMXXKfxH9n+1pwLHNszC4Z3TfE3i9Xcf7YYutOmJBZhp + SNpzOj8xAaslfHVVOGHI9PajnCJsbM8Y9B3ug+5jPZBfLkBIfAoCgLjVLGtR3R2HsZGQNZ9BO1Cm7Eoj + 3In6nWJedEI456yd8Ozfe0bL99qFnDRnkpebbrhhvaSgnyEAeO3rX7fwiADAhRde2Ic3sY8AgDpGGgCZ + APlCEV75xvfB9JFJ+NKnPmoB4GUvewUcPToNX/3qVxgkPvnJTzKbj26oncxzIoF/KM7A9QDAfY8A6yiq + VG64kY7buXM73H/vbnjrW94G08VZKG3o5aHIU6orNANyqAF4oTrbFAA8tbnNPgYi+AizTuJCxGIsE5mp + qvkItC6X1MbzuBglrzCBTKcYbV3aBAQFqgiMk3dnHaJzYrTb0fQ4gK8jCACzAWf2Nfn9zepCv8dmH0XG + 44pBUTdwJKGxrQKNLU0Iyng/16Og7EUwo12BFaI1y8YgyVMIAl6sy/tSPw+kom1Ldd9YVjbWhrw0asCR + ALy2R2ZMF/4sogZFZKqoBAX6z8ProhZFmYTJmPKVxWiIUIZcZfn5pEkFTSkFXkSNqg/NNwSAmZ3HOK// + 8N5Bduh1H+uG3GqRtzlzZMGT3AHVUp0BYHlgEeY2z8Hi2BL0Tw5A36F+/l5hEQGAioTGgb2m5PmPWzUT + L7Xn6Y/AS4k+J5SipPX3xGwLpvLgDADntAAAfb4eAFAYkDSANNGNHA6SFpwA4JGpDYgAcA7++DEKT546 + RhqAAYA/fc27UbWegn/63MfYsUY28x//8Z8yD+ALX/gc3+THPvYxBgZyAvqOI+hnMQPWA4H1IgLmfQKA + 6cOH2Z4yVFTyWJ9z9g64777d8I7L3wkHj0xDV3cvT9R8IcsmAN0jhbKMA8+Ws5ISeMICc3P88Y5btFtR + C6CEIbRtOIolKQlTYgNf7IVAjqVNQjFOdvIBANUDHMBJvxOB41ENBgAqCOofwVUbbfmg7intT2dCkFJV + uYXCJiRCEJUSa440oDHe5IxCWXIk7s/whiAfNQAKhVk2YGJyAYKE+SJfL6MMt6aukpGJX6rXXkOJPB6o + fQABQE/MOQxR3KGIwtlVKUE+/j+8vQeAJFW1Pn6qqnOYnrxpdndmNrJkAQOCiqIgopJEAUGCYFai8fn+ + pj8SFgxPRREDiqDPAA9URBEEMyi4hI1sTrM7qSd07q76nXPuubeqe3pmF4VtHWa2Y3XVPd894TvfQfDB + gwhT67CLj9RCfP5dT10LW2jFOrQizUFiAFZj6M7Hq5BvyXHyb3jJAISKYejY3MVCH5wAnKAKgM2jv+n0 + Vx0XKnHxADomYKhvELJzxqF1exu072yHDCcCYxApRFUfhuYDSOnOeD6GHOXVUc9dk9CTTcFYu1YYlqth + KWFTnTxkEMC15+Ca6+3rhXec4c8FaAYAlGvbjeuVmoG8qWXA/8Wfyz98xeUHZjw4AsCh+OtxBIAoHRgl + 9BgAYgl41/s/B0MIAHff+VU+0HAkAhdccBGfrB/+8PsGAIgtSCqnMwHAvwMK+5sQ1ABAwORIyyWVMZcu + Wwzr1z8Hn/nc52D7zgE0+hRnsmPxmJK7juLilcGXdNPqtpr6yRddRkypi2/zQioXMQwoK9GQcrHIbpyn + STeO5WvxU2gRpl0bF0gHLno02PKRRageWobIM1GIPou75zb8/OEQ04BtS5ej/aQVtymQPZMngUboZtAI + ZlVYG7CCoQDtsDQsJErzA8dxBy6SopCnxpqHxd3nrV0auLj8JjwNPU0opFeI9MALFnlhVxGYqIuRWYwI + OrPLuMM6kN6VVEo8ZQwDahEGBcdV3pJO/tme32tgKiWuGjFOij8UAuRbSjDWk4WRvgGIjiSgGwEghbt/ + fCIBoUKIR4Lb0rPApUPyHBAEqHQ41DcE490T0DKQhjYKAUZpShAeD+UBaJISz25wVI8Cq385hqNii2Cr + OT5VnOTPcrjbU4VvWjOVo0GtfARSDuQzq1SPqFs0FEIAWNQLZ55ZPxqMJ08HbhRqEwBQGbA2NQl4N37e + 5fh7O4LADO7ICwQAL3vZyw7GX/8kAKDkBHkARaoCoHt/7ns+C8ODO+GXP/kf7tojALjwwkvY6H7wg++x + wRMAUHWAJp3sKwfw7+YC9gUClAQc2LWLTzTt/BQKUHy/dPlSWL1mNXzmM5+HgdEhSKZTbOzkySRZEyDh + U4HdQInHJM8UHdaowXKcCyxEQj0NBDz5QpGbhvy8vSU7nqIDe0Tjba2Bi7E7qQDlX12AWo8LsUfQfUYQ + oH5+i0hAxYBct6uZaKrbTpFscKHE8O8MutBzy+xJ0Ngw6hhMPB6H6IYYdwXaBQITMKPOdTsyexNuwMW1 + BaC0fJcneQ7OE3hs/F7Yg2rSU8nHuVR9yENheQEiQ1FoX9WKO24GvQD0oioxBQCgQ0AwU5N5yIoAihbg + qETRiGMUzxeh0J6H4cXDMDZnDDLbMtCxpQMS4wmITlA23xF2HijxTarRR1T/QKGlAMMYAlDiMDWC13I4 + hbt/UuUAaFpwVeVxWEKOVYGUCClIpcgiVJUciK1debZ3xSQEoU1rEFO1f0epJnt6ZDj4nYQ1lQPoX9gH + 57zJnwtAr5sOAB7/22PN2oHvxZ8r8WfTRw4QAByJv/6GRhMhhhLlAIjWG8Hd8ayL/xtGh3bBb37+deYs + EwBcdNG72eW/7bZvcWXguuuu4wEcxA58oZKAM7EDm4FAfnISdmIIQvE5EYDorNEgi8VL+uGZ1Wvg05/+ + b8gWcpBuSfMCYCILegBJDAMcqVzUxXbym8HAFY4A3+exbj4tHKoGFMr4UyopYpDn+kkmD4wOIFACMFPj + IZ+VpWXInZjnbT3+AC7yDbhz7g2DNWqx6143RTf4nXX2ngRF0Juozinj7l+C4iFFfH+PcwDR9TE1Kiyn + WoqZUCRNRWZgsRh5PQNQaEf6MUnSaQ2DKh97WYHXy3JQOCQPocEItP+9Azq3dkDrCO66hRTEq5RQDSs+ + QOB0uuAa959dbtwuS3E1B5ASgONo+LsPHuAuv1nrZkM7xvNJjOOj4+T+h41+IJN3aIQ4AgcJg+QzORjq + H4IJ9AAMAOBPbCzOqkC2zGvwRL1XhUIAggo6PyqVDldz/+Qx1azEfR2aGlLzRDsSRD7dJ31ppWqqkiyZ + tQTee1w9E3AmD8AvA5r1fZ8BgCsvn8ISesEB4OUvf/lJ+Os3tGtSDoAYdeQBRNADOO1d/w0jQzvhoXu+ + wW4uGdz551/Ez/vWt77B7LjPfvazsHTpUtiwYcPzSgLu72PNQKAxH5CjMuS2bXyiqVTpSgjQ398Ha9at + hY9/8pOQq5QglWllAg9PBiJJsGSCCS7ayOooqwGWHFg+h0x/NjU+MTkIAYB+19yqEbzUZ5wSjJz8a3XZ + da4sx130NQVwBjAMeTQBkd1oMDQQdNziMd9apFO3JteV0bgr0GOJ8BqBSR8a0VF5cOfg9/krvte/EAAG + HZUIpKYiPSos+F2sAMfAhPx+jkPv3GysRD6i3oVONLh5eOx9eOxH5qHUV2DZspan26Dj2U5oH2iD9Hga + EiX0ZqwoJ9MM88/1cys6v0DedRk9gFK8AIXWAu7847B36R6u8c9ZMxcyVM7LxtGQSQocz49rmZCIyUNR + FQLkWidhz+I9sHfxXohOxqBrWxe07swgCCS5ezBUs31Md1UgVHO05h8YBXcVz6uTbv7NDD+XPQ6iH5tR + cCRj7gZVrVQ+gWyHPB0SBV00ux/efcJFdUnARgCgcrvyAJqGAP+HPzQZaMtHrrzixfcAEABOxl/31wFA + scAtvie//WMwOT4Mj9x3CwMAfal3vOM8WLBgAdxyy9dpkg8DwJIlS+oA4D8x+P1JCDY+TmXAHVu2KK4C + eid01igUWLJsCaxduxY+9vFPQQ5j9SSGKrQQSdEmGUtwGZMILnqEtU66aR6AEbGAgASYNJjQjlCuEAAU + oEgKxSRXFswg05/kXCTRkNpU3F5dhqBxXAFC60IQfTLOXACbfkgIpKqz8b5RBr8jJwUjQikmifAFaJhH + 0uzAEkSewnDiz+j67gpzHoApwaanILgC5H0bGYvmOWrn5+YlUjBuqTJ3odRXhNLB+NNfQlCo8vdPbE1B + 26o2aNvRDi1jaUgWY+igxDh+ptDFAGlgqCZFI6ReTkNASAa8iO7/RPckDPUO8fPnrpkH6T3oTRChR3j9 + jqgvsWAnAQB6JRX0AvIIAEMLh2HXYRj64f1z186Grk2dkBxS5UMeE0Z5AE3Q0MM9NBHCVf+hXd11JTzR + dF8qU6K3QYIlrBJsqy5G7jMoS2hRU8ECA5NXYwCgNde/oA/OOuP0umtXqdTT+gkAiAn4eBMeAN5+gT8f + QePf8UIZ/4wA8IpXvII9ADoQ6lPOUggwWQG34kFr5zywIzZkszvM1nbuueczAHzjG1+rA4D169e/IAAw + 3eMzhQKFXA62EQDgTkzxPbmhIQwFDjp4BaxZ/Sx88pMYAkzmOFlJi4kaWggAEqm4Erd0dfeb5ny7Kpll + GGSBz6xZBiiqbpXboEkxqEheQFUJlvJ6k0yzRzF0h8ttwBUSAjkBvatVIQivQlcV3X+begBytgIAN7A7 + Axi1HTYAjsuBh4VUO9E456BxLkJAOQI9CnyP+F8QULaorkB7UqkKGdA0W2GT8x3wBEwFJKLES6pUtZin + Yv8ShRvU/ozvXUlXmWnX8mwG2ja2cfY9PYEgUE0oVqWr26kb6uhU0icVIASAfLoEBYzfKfYnV574+z1P + 90BqL7rx48ToC6uR6IHmBMUfqAkA5GFsbhb2LNsDkwgknVvaYdYGRSCKoEcQKjjKYGVQCyc1a9Lxp113 + SvqR1yfnXXU0uvw5lKeooldCHkctWuPvS2FJNB/mcqUmbPFG4SoQoPBzUX8/nH6aXwZk76DByAkAqAz4 + j8f/wWsG6i/PTwQA9hwoAKBh5hR3QCu6yIPoAVQW5qD90BiUcriw1+Pi3RRTJSRcGOedewEsXNgL3/72 + LVwx+MQnPkHtxLzT7qsR6D8BgelKgvT3JIUAW7cyHyHMk2xDEEE3/5BDDoan//UMfObaz8MADEGyLcnu + IPWzxyNx6QaULLOuvasUtuyShsyufWO1QwcYZtVSlROChXKBQwECTl7ropfHO3aXq3IAlLg7oYjGH4HI + kzEI0zRgAoAJaeLRWXlZ8EGXncpOFFLwaDE0TKooEA+gfHiBjT3+OALKJukpIAAoWqa6Ya6+HfAAAqxA + w2yjuJfi/7hqPybxkuL8IuReOcmfF9mN5j3qQKWtxsCQ2BmH9qepBt8K6WwaUpUURDxfk6++3VYYgBic + lxMY/7eWINeBu/iiQfwZhhTu/D1PzVcAMBGDCBoalzON1wLcqMMAEq9BIVOAic4JGO3JwsScLBpnjHMI + rQOtDABhAoCqlEN1IB9MTkC990PAXxO33yWZMuIb4HFSkpI+K4rHlBlIMTvRKYaVdyGkMaVYrRLPixYv + gjPf5FcBGnd/DQDEm3nyH/9sAAc+HhoNdvnlV10xcqAA4GL89R0y3s62TnhywWMQPbUMZx7/cuhJdbEo + 5qaHBuHpb2Uhv92Dcy84HxYvXgK33vp1bgK68sor4fjjj4fVq1fvl3jHfwoGzZ5LSUDyAMgAWcMwHOGB + loccdjA8+8Sz8NnrPw/bUwMQn51kowjT3DuWBZNmFss2ohHGuG2lWWdJHRt4/p0nf+uGG3R1K7goy2go + 1RK3DRMgaD09VgNOUP1fSYGVF6Lb/rIShFeH0QuIsa5faATff8Ji39jWw0QovVyxZP4ASBJS+hwiHusD + ckluUQVKh+POXLEh/k/8Ppvw+1AlAEMKaixypC2Wj4MlwjSgWMHIxvQcsfcTxZ+UqlzwCPMlGKujl0Gf + Ed0a5o5FDx2pQn+BWXptzyIAbMG4fSwF6VIaom5UMuU+C09rO7osAoohRRIBoK2I7v8YDKwYgGzPGHSt + nwWz18yGFMXwE1EIYxxv4n8BZAInUhGm0iRRiCfbJjmEGF0wzB5UN75H684ONlZqCOI2Yi0N1iSaNsw/ + SfgRyFKeoJLA85qhScU5GFk4CpMINK3bWqEDvQwqfYYnI6w8ROVQrk54CgBo86G809vf4vMACAAayUXU + dUuy4E9MAQC+3Y4/V1x+1ZUHZjbgscceewn+uo0OctmS5fBccR3sWrEBFh4VhROOPRw627s4lH3qwZ3w + 8OW74MwzzoYjccf/5je/ZgDgla98JaxZs2a/koD/zn37AgEDABjnU1afEnspjO8PORQ9gKefhc989nMw + ZOEu0RJXUteRMHMBokklbmnJCuFkEMV8tFOFVQKIvzwZCinbVEF2alDCG1LmqYlyMakYU16Ac8o0M9CR + EKCdvADcsXtx5z4IvZTV6AEQBwB3U3sM36Oo6uO2HtNFx1KTvw0/XUIUDgPEC5hfhsohZdpWIboGF+V2 + NFAaFZZ12FBplwLNadAahZ5tDJ8ZgTwZWBJ0VPdP4B9S+qNZhLmjclCZX4HIxijLl/HMgrgHxQVFpji3 + bGyF1k2tLMmVLqQhVo0zK1Llx1T5wRU5LjLgahjBEt3/fFsesnNGYe/yvdzgMw/d/7btrRDLomfGO3jU + r0y4mg8hAIDHWUgVINc+CeOzJ2Cwf5DLfl0buhkAkuPoDRVlwpLQstnQZfpRvUmIZBkZP4FApAb5FvR8 + KcTA8IRyDHkMVWat7sb3n8UUZfI2YrmItB2rtUPiJ9x/0tsH55z+NmP05JU23ggASD+DqMC1mttonHfi + HVdgCHBgpgNrAKAFfMIJJ8DhBx8NW7Zugp3FjbAb1kKqD6Dr0CSEuqvw92sH4JWtZ8Exrzwabrnlq3Ue + ALUIP98cwH8CBsHnTI6Pw3YEAJrio70QSvAddPBBsAZDExoPniuUufxHZTyqEHBLMHoJWhOQY1ZHGT81 + 2VCrarmlArWUqic5BZtLbHzRq+qU6vkALg8poYlCRfYEiBdAi92KUAefB2Wi7i7AnyMRHHoqEP0TLtDV + Ss7bGnekeUft/qbyZ/sRCKv8SqMRZ+cxrKi006jwCgMAGURkY4RDCgvfk8qBNlcClFqNrXdBNgIJM7Qk + lhgGZ8VZd4DmENQYACq96AIfkQfc1CH2LO6qO6PqeQhAxd4C1Do8SG9PQ2ZDBlIjSUgU8KeSgIjIcemy + pmLfqSQbiYAWMyWYRKMiABhdOMIDPec+NReS6P5HJ0kDEAGyHFXqyKK2bEm2voohBIEAgUZOcgiDGEbQ + bty5sYvVgWiWAIUAdkXpAgitLyD8KaCqB3xqcKIZBckKgtMkHt8kU413IwCU2grQtrkdQWAutG9tg3g2 + wXmKUCGgMES9AJEQ9GJ4TACgAaeZB0Bt9WQ7j5EseLXBA7Dgp8AhwJW7DggA4O7NIQABwKte9Sp4zWte + zxeuhrHszm27YOPm9bA3uxOGiwMwOLAHTj7+TDjq6KM5BKDJux/60IcYODQANDPgF3L3bwYCVAbUSUAC + AGKzkYEvP2gZdwN+/BOfhKJbgTiCAi0GNeUmDkmStcKLpqb7elIqojgbF0JLGQpz0FWdW0LDRwPYE8Md + m4Zw4A5blDHUutmEetVrFS4J0oRhAiKaOU/uNLTjIqBZgEvQrXw1+uVpD2K/QiNZRz0A+NmjNrMA2ZvQ + FUmeuGuZioPFE4ilHwGNtErZ+dk1ZaAvLbJICAFAdDO63xinh0goNBdioLIkGcd8Gj05GDzDU7ACNFei + GlPDEfEWeBDJkiJU+/Cc7kaDfA535TGHAYDKg8XFJS4NRvGctKxugSTGx/Eiuu8VBAq1pfqzCBl0VHxd + juIPAkC+A3fYeWMwOXuc6bvdq2bh7q+m/EZKKtFGfQBMiJL6JJuro0Cgim56AQ1zonscQSTLswPbt3RA + y+4MVxGi+P3tcsjkd7Tyr+JB2CbHQwlfTu2Q1xdB76QFvR50+SnBONQ3wuFJJVnEXT8Oc56dC7PWdENy + iPgGeA3zITOSnQaQhqIhWLBwAbzjbX47cDMPgACAulepHdgvEZpcx88YAK6+cueBAoBr8MTcQCfnda97 + Hbz0pcfxQaXTKWa6Ub83sQCL+SKMT45BqiXFJJvbb78NNm58Di655BI444wz4KmnnvqPcwDPBwyCIKA9 + AEJbPWKMjHz5ihXw3HOb4b/+61Mw4RUgkUnzmYiEQxALx5kOTBeN37KmeOFVLn+hcbXjDtObh/HDJjCe + xp1uLe5Ou+LMgouMhw3lVjfPkJtbKeOizBe5LEg9AzV8L68dH5tbhtJSBIHjMJYuOxD7XVxx94dwkSMA + 2KWQyTXq/yg9Ai02Ikk6IiHR8aXRQLtpXDjupK/IM7U4RBODn0KQWoeGSvoCww7z6FXpUrYpsPyhIXpb + 1dkxsrWEyvxXOV9RZvFS0iCIP447KukWTqjGHPKKSkvw8cNyfFyZVRnIbG2BeB5BgFiBbshnRDriIqPx + 15j+i0DZVoJc1wRk+0cg317C12aga00nx/1R3P1p5/dIQTjgBnmiLkyVCGIoUiWAjZXCgJ4Jfl7rjjZI + 7sH1OY7XiNiABACUrddVHksp+dim58KVeYDUtEU8CxIcKbLW4Cga/9icCfQK1MBTOpMdz3VC9/ouSA6i + pzOK3mM+xOEXn2f8HIcAoGcBvPMsfy5AMw+AiHMEADQevNbAEQBVBbj8iquvOjC9AMcdd9znXNf9NC24 + E098PRx99MsRAFyWLXrwwV9BLJaEww8/ijXP9A5PmoE/+MFtzP67+OKL4cwzz2QAeCFyAP8OCOQmJ1UI + QB6AnicQCsFBKw6CjZu2whc+/wUYqmUhnlFJQG4ICse4FBiORtTir8mUI8qy4w5b7kAA6MvB6LEjUEkh + ID6dhuS6JMS34e4yhMZAKrxV4EYVS9x3miZEiUCSEC+7VS5Z1drwPedV0APAeP3oEti4O0cfC0N4VwRs + Yu6N43coO4FWVD8M0AlAlaBUxCJy02kHrnWoIaOFIzFefSnF4x5EVuHCXx1nbYDQIC5MGTJiuVqXT8DF + taQcpgyMXVhc5NTx51LsPwfd4MMVxyA0bPMg0uhmfN8RR2kjkEDpggrkXjIJLno0GfQAWjcjCGQVNThS + jfF54Tcmr4OMP1TjHAN1AE52o/HjDjuyaAhd+Sp0ru2CTozfI4UQRHjSsWIy2loOTVx3BoCwy2PWy4ky + 5FtzMNmJrjoaayVZho7NndCyIwPRbISVhB06rzU/fPBE6lzYPkyvJk+N+pdIboxZhiRQih7FcN8oA3gU + d3rmA8RqkNibgMx29HaGkuy1hPNyrOwFWDwzcVnXYrj4de/yCWPTAMDw0BD8+Y9/5rkZDbe7BAAOTA4A + AeAzeID/H/1NAHDMMcfiQXnQ3t4Kv/71PRgjR+BlLzveZCvpotCXuv32b7MHQABAHsDTTz89Y6nuxQQB + DQDGA5DHly5fBlsQAFbe9CXYVd0D8fYUrkeLM/+kGJSgARfRqKJ4utLgEcOLhgBQ6sxDbjG6qS/LQnFO + EeKb8eI/gRd/Nbp/A+g5jOPnl1WziZ6wQxeTaMGkHFSuljnhxdOA5xEJCP8+ogz2ViIBhSE0QEKeuFPS + 5lX1y32NtfO6Or50JNKcACIXVeegIS7DMODYHNTmVSG0mjQGo+iqU4chLn7SGCypTdTyc2Ey+chWOQyd + WyB7pfkDaTRS9Fjyx+Q52x9fFYMogkp0dxRCY6rRqoZGW5vtcYKQegSSW5KQ3tLCQzrTkymezkOdgaoT + 0JKKisu5lXICd9i55GLjLtszioBWg851XdCxpRvj/xCPOg8Xw0YEhMuS0nPPA1kQEGiWILUFF9pzuFtP + wMCK3ZCbnYMufJ+udbMgNYTXJxflfA13O1qeYQDy99WEL9A1fzyPqRKUUuhRZAowtHwvexXx8RjE8b24 + b6E7DzYae2ZLK6R3qbbjSC7C105pK1jMBDyoaxlccvyF5toFAUD/7unpgdGRUfjjo49iqD0FAO5gALjm + qgPTDnz88cczANDBKQB4pQBAG9x//90IAFEEgOMMANBFoD548gA2bFgPF154IZx11lkGAJoZ779j5Pu7 + +9ONeQABAPDkscVLFsO2zTtg5ZdvhpFSFuwFETYEh3TuSdgiosaEkeQV56ppPjwBQBoX2OwCTB46Abll + OSinK7igHGhZ1QJtT+AOsxM9B8rgF2x2AVkMs6bqwWUXXX23opKBTgUqmSpUehAAliMgHFoBBwEg8g9V + AnQoCThpKQDQenVWwOitQK1af20yVKoEoKFWuxFUMBbPvy4HlaUVBpfwMxivD4aYWuyRxFhJsdZU3C+5 + AMryiNAmhKT+HxKmIY0vm19SmoODEUg8id91Jx7vMMmW0zq3OAlII86KCBKFg/P4eZQHyLBGP5UDYyWM + 42sRLuNxF5+jAIAqK2U0ssk54zAxG8Mr/G3hOScPgHr6uQGI6vfSBGRp9WKQbjxL3stSoUSpHd+raxL2 + HjQA2fljkNnZArOfmQuZgQy3ElOuxqmosEWN8RZOgK1LvupclhN4vdJ5bk6amDMJuw7bDRX0VFp3tWCs + H+Xeg7EFo1DFddC2qQM61rVjGEAJS/TiSo6Z5kyy6f0LFsE5J59dRwQKqgLR3wQAY9ksPPKHR6CKa7ZB + Oem7+HMFAsD4AQUA+ptyAEcffSzQGersbIX77iMAiMHLX14PABQO/OhH34c1a56Ft73tbXDeeefBM888 + MyNb74V2+4N/NwMAWiy9/X2wbdMOuOGmlZCtjUHo6Bjvdk7E4jFO0RAaC0S5bKVaPMUAcIcrzCnA+Esm + oNJW4ZIaEXpiuAtm/pGBxMYkRPfiAhsP8UQe4DhTHQ/1updruDhrJSiG0JDay2oa8NIy1FbgLr09BPE/ + Jni0lz0uu7SW8qbkn20ZPYK6m0iDqS4+j2XCiV9QpkTgiTkoHVXmkCT0XJh7Ddg1rSlDl7mm/kQcSs5V + JTzgtA3VsVUJgkIA8iqIDRh5Ig5xmj40iCCZxfcrypxD4jZ0l6H4EgTJYyY5WZd5EkMA4gMQIaiIoVI1 + YkacqRhb8fgLLRj/zx7HMABj9wXjnJSb9fQsaNvSjjtqTHUA1sCURY24iACjyzMFRE+gFT2VDuIBjHIi + kPQBqVyX2ZVhw3UKYZUE5NZeOY/cpixDQ6gtGUO+IoISNSbRz/CiURhcNgzxkTh0bqZjCiFweZBFb2Vy + Tg4Swwno3Ijfc3cLhge4BvIhRVjCcx2nduB5i+C8N729rhdA/9ZAQCEAaW8+KgAQuNGTbyUAuPKaqw+M + KOirXvWqG/HAribDOfnkk+GQQ17CyTzyAO699+foKsfh2GOPDwCAan744Q+/B2vXrubXUBhATMB9cfZf + LBCgKsD2rVs5ean1+MiQehbMh12b9sB1N14Po7EswPtDPHuF84RhWynZuCGplwtFlJo/Yh4UZuPO2p/n + cVuRkQjGxSVuxkk9g+7uv9AF3ENeAO5ykw4nCVVLqSIN1WjUOfrehRDRXQtQWlDkTsDaIhcimxEAHkqg + kYaUm17UZBdt5xKj6q4iIeioWrjNApyUBKsl8ThJZmxuhQ2RZg2QbDiXKYuqtq9KfoF6N7fUgfANLH+S + D+2GRJOtWkpvAEOW8ADu/n9MQmQ97ubUsDRpMxmI+gTIAyBmYxGBIn/kJCsepzakoHVtG7RkWyGVp2pA + RIxPJTIJAIhgw/V/3K0pyZbD3Zbi6TlPzsHYvQ1jaordicEn5yDQGWlWMXP6a8ptb6lArgM9ibnq/ejz + KEmX3tGCLnqMBUboHFAMzx4OnceqpfI27LV7PJew2IoAQI1JPeOw95C9/N7dqzuhbWsrOMUQazFMzkag + WTjK75FGT6NlJ1GOwwxY5AXYJRuipEExZwlccty7jNHX9XMIABAPwABAudJond8WADgwo8EQAL6EB3Y5 + Gf0b3/hGWLHiSNbTa2trRQD4mQDAq5iwEASAO+74DnoACgAuuugiWLdu3YuWANzX/VwFQACgjKqeakMe + QM+CHhjYMAjXrrwOhmeNQPUu/A6TwDuMK66wnsWnlXQ5PnQwdqPYHRdCbEsUASAM1S405jll5gKkn0pD + YmsSY2I04glcsEVlWJbrmJ77Ci66Ej5QTBe5f79yCALIXI+FQCKPR3gsmI0xNekAsLuuOwBrVj2VVloM + vaqq51uSGCN+uhW3WGiEtAGJmktqPRCmSoHubpNSn5TA6H5PtP48qcurJB2IVqD6TSFgdEsYYs+ip4Lu + vz3isM4eZdSZK0/TimehO78Ad+DDMURaWsQQIQLdj3VBy0ArJCcSECuTKEeIwZYTeY4ytlx7HgYX74Wh + Q4dwF3ehC93/Wc+SDmAKHKL/lm3Tc+/pvotgFyMoACCSFoVm9H7jPWMwsnSEgbwb368FAYA6BClmV12E + RB5S35tKozYel2rzdjmXQGVJyicM4c4/vGQYjTvFXkkcwYnKkTRuONeZhyF8bHLOBMSHEew2tEFyMsYh + ICkxk6JT2InB0o6l8MGjL2sKAPrG8vujo/DIw3/gylHDjanAV3706gNDBUYAuBkP9AoNAAcf/BIu/bW1 + tQQA4DVTPIA77ritKQC8kIa/P3/TLSchAI0lCwLA/L4FsPPZAbj+SzfASNcIVL7psZvMMWBYjMNWNXHe + HSlRpRNEcY9RPbE+DiHcAak5pjQPF0pfkWPe9OMpiOyKMQhQrElVBEXlVcIVtG5KVFZqnYTiwhLUXlLi + CUFhjP9Jwssaw+fmlBAoa/nXlCF6Ou7Xu5+SHASjVK1HUlkgE4PQ0DMuhy6sGkSYEZKsnwp8xTsRmjE9 + 7irjt0MaDBy//EC/MQIIDYd553eyaCzjuNPRrlyT10fxs9oQAObRjII8FI7Ocfdg11+7oGNthxrVXYxz + OZDJRlQNQe+pmEbAwJidkmzZvjGM+ePQvqYLWrelIYkudwRddtqhdZji6f5q6asgNiN3RYJi7JXp/TK4 + cy9AAFg+xGFNx5pOLgdSOEClXRonRr0D1agieoUw7KFOQQu9AMJ8pv225GECw5Isuv+UD+hcjce0tR1B + RPUjUG9AAT2Nkb4sAsQQVwsy29oQtFrUWEUCFZrMHIrCiuQKuKb/w2ZtBkVt6gEgC394+GHmrtQbqPVj + AYAD0wz06le/2gAAGfOhhx6NBx3CECAD99xDwp8peOUrX4sAUGkAgO/wmDAdAhAV+IVK6j1fECAPYKfo + AZj3wBPfu2gh7Fw7ADd+4yYYDWehfDZwFtlG43diaiAI5QNox+fkErn/epoMutnkHYRHqKauZtOVu8ow + ccQE1NDgWv6UgtTTLTyeOzyBrmaJ1pfHk3w8jnddKFEuoXMCJg+fhPLBJbBGHVWq20CGhaaRU2KgDEIh + xfYzWXkQElAYjBvMeUFbGb6nBTdJrw9DFipTEcCoXV9LflHsK+/vKMUbS/cHiN4hi3/Qv8kTJW/IUtRU + yk3YGN7YGOOG8qIvoIdmhmVgaZcqB5aXFFnvILE5AR2rOyA9mIEoJwLDzPIjo6UZAOUMegBdORhePgxF + DAVSA2loobwBhlOJ4TiXAW3XkeGdsmo9PyzigSJUqaHvwglFdN/bFQAMLx1iz64DPQAaFxZG4yUwo3Ih + ufh5/FzymuKjSmyEvAVSP2JxkY5JNv78LAxJ8Ji6numGxJCaNUghFVVzKOE4jiHLCKkX9Y7i2ghDfBA9 + BOZYuHx+nEgYDqsdBp+J/pcx/OkAYGR4BB4lD0DnAPzlzABw1UevOWAAcBMCwJUEACeddBIcdtjRnPlv + bW2Bu+/+MQPAccediABQrjO8O+/8PvzrX0/Aa1/7WnjPe97DHkDQ5Xkh8wD7en4zAKAT37e4D3as2wU3 + 3fplGHWzUDkK70eDsXnIBRojAh0NClHTe1SzCc/9k9IRu54ksolxIJWRKq0VKCzPQ35pHmKbo5D+Zwbi + 23Cho/tLxmyLCg83rcTFRcXYceKocShhGOBskWnA1LQz5EjXniROjS6J57cSa8aeZb6scmNtS/jrNTWW + POEp7T5HPYcMnuiypPWnWH626abzHBVCWIpip+b5iYIvgYXNPfJ4f0V5QNz4RAW9mjJGGppO5TwSCqWc + A4UgbncZSr0UHqFntDHNmn6xYgRBgJhyDucNamholRQl7YowfNAI1JIlSG1FANjWoowtG2feQsgTlqUY + PHtVkktgeS9P0ayZFkzZe3y/iXkTMNKfZRn29ufaIbU3zQBAzym3lGFyFj6O7n0JASi9PQPpgRSEc0oI + kfgD4/PGYQx3d3Lnu3D3b1/XroBiMoKhT4i/b5GSl905/KxxyOHnURXC4yQqXQ+ZNJgKwVG5w+Gzzn+b + dRiUrgsCAE2z/uMfHm0UC6G3IR7AFVd97JpBeAFv0wLAa17zmq+i4X6I4n4KAZYtOxTi8RbIZJIIAHcJ + ALw+AADqC91113dh1aonSVSU6cCkCRicsPJ8jP35gkTjv6kKsJNyAKIKzN48eQD9vbB94064+Wtfhmxl + DLyDFO3XQSPg+fY0FyDkGCUYzq6z9pu4oRTPU2yPuxh14VUzFW6QmThyDKr475YncLE/m1JdfdSBJ2IR + LCqBIUQFn5+bj4vm8AmoUClxAwLOxjCEt0WYVMMtuxW7Ljuv0AvM7qclyUQbyzAEQQRMOJZHb5fmD/oM + IiW9xT0EwYSfpXIAWrJcMesIBzzNjZF+BFvlNMToQavk0rkNCcWZuhJb8Zyg8VcWUDKwAJRWTT+TgvQu + kgmLsfGwOEgUmGNPtfbxnkkYxvifDDuzvhVSGG/HRmNokBHzedrozQQekMSu6AwwGcpRk4XLbRiWdRch + u3ACvzZ6Zlvws4ejrAtI7L4SnveJnjHILskyACQGExjDJyA2pHZ38krGF2b5+FI709C2oZ2PKY7HFJ2I + qAw/5T9ZwryE71Fi4CHacDlcU6KxEqY5yRAcHj4Mrpj3IXMtpgMAIgI98vAjQSYgnWn6x08EAIYOFADc + hi79JdTL/OY3vxn6+pYzALS2JuEXv7gT/07D8ce/wTCWtOH96EffQQB4ggHggx/8IAPAv2PML8TfE2Nj + rAegPRD6TSeeeNnbtu2AG1euhGxxHGKL03wxHeoIDEXUaLCwpuGKEZBIhOawkwvNmpa4GDHGZYLQAgSA + o8ehgECQeioB6X+0IABgGJB1WKOfvAdmnSVICagKuYUIAIdOQjVVAWcdGj/1AGxHINIJQLdBBzCo1iON + O4YP0JARtyxfwoyN2tbCpgoMdKMKtxNrlWH93UCqC1p6jDyfmhg/fWPRPqA4WocNmoikxU5JMYhcf2I5 + 5o7P8ezCtsdaeQdNjqVYnjtUDXE+pYQ7cbEtB6NLRmHwiL0QGUlwviC1OwmxbEwxAMnzkhxNjUuerqmC + KIERqeFTqoCSgFEEZHLv5xVgdOkoDxtp2ZKGxN44zxMkJmYRXfcs7u6l9hLH/lyWjNQwbMPdHb0EqiSU + MkUEoSiTfIjlGRmJqhFj+ZDSFiS9R9oAYiqUAako1ELa+FWexYmG4ZCWQ+CDy99jACDYIKdvpAlIPICH + H3yIOTX6agsAkAdwJQLAgSECnXDCCQYATj31VOjvPwiSyVZoaYnDz3/+IwaDV71qegA45phjDAA0CwFe + jB2/8W8CAPIA3AYA6Jk/H3bs2glfvPZ6GCtOQKqnTU25CVkc5tCMO5pwq7vFLG5YkSy8jLPn/5C3SACQ + xJh+bhFyh+SgsCIH4cEIJB9L83juCHXgTYQ4I8wTZkkKrEMBQO5gBAB8rbMmzK3AoR0hngVIJcmgBJh/ + sSzf6I37H3is2VXV3kEQFDSA2A3YERQDCWTX1Wm1GmTJwHgooBV66VdcAKCzBtWFFcgfnePyYWYN7qLP + tKvBHqTMgwBAAiO0c+bb85BFV5yMNbktA+242yb2Kl49uduKU688Da7S6PZdW7oJRemYAYDERRNF9AAQ + kBdMwODhezDOLzIAZDZneDwYDRPNzZtE936MX5/YneY8T25WjnkE9NWI3OMgEHSsaYcWDA9IUzEyFuax + 5L6uokwNjgDnA5RMmKuSk4ZcRFUZB5ZnlsMVB39InVFZj0EQ0GXAMVyzDz34e1UGVOdZirTwA2AA+OiB + GQ3WCACLFq0wAPCzn93BAPDqV5/cAAAeVwEIAI4++mgOATZt2sQu+ExS3i/W3zoHwGwr7XrhcczvXQC7 + du2Gaz9/LYwW85BqaVFhNMb/RARKxuI81kplxxUxRJfNoCYAYHTycAdIoRs4S/ED8i9Bo864kPxHApLo + CUSoP4CIQUTsCQmltrMK+WV5KBwxyeSV8D/R7VyL4cIOdP8pZNDy3VZgHKhlGfc/eOWmAKLRDfICxmpN + ed6Uq2/B1PexAh/oBYDH8p+vZyPofxBrkAVK24nqXIbS8gI3CMUH4pBZ3QYtgy28q3NPQAI9AFIA6s7D + yEHDUJiVh/ZnO7iURrF2fDzKvHpmVQonQpX8A8ehhAXM3IEqKwuRB1BiPsHQikHILh6H5GAc2ta1MQmI + cg5k/PnuArr9MUjtSPO3JDESavGl+8sdBUjuSEH3P2czfyCWjUKUqh65sJJpo/XsyI6vexpsmSDh0Bw3 + W7wrl0OA/u5F8L5XX6JOpdT99dBc/W/qBiQA+MPvH24kAhHU8nDQqz/+0QPDA3jta19rAOBNb3qTAEAb + A8BPf/pD/DsjAOCXAel25523wRNPPM4AQB7A5s2bDd3xQIUA+t9NAQBP+uKli2H7tp3w+S9+AYZrE5Bs + SXE6jHMATgjiNB7cVpx1w76V3d/0scvaI5SvpVwodKLLOz8PuZegF7AYXcd1UWj5K4YBe4kuS4QZiysI + tTSGC7PKMHlUDvIvzYE9akHsz3Gw1+Luv91WJUDqd69I+U2ARyX4AhJWEAAFq/57m+Ye7cHY9cZswXRg + IM9RlMn654luvqkZQiBM0CfDEnmvBBpCGw08QUNcVmRCUmg8AplVuJvubmFdv1AtzF2GlKwb66Wdeogb + emb/tRsyG1uZshshd7zoSAtx4FhFqoiPQueXbBH4tFWlhZJ8VKIb6x2DkWWjXLnJbE6xoAi5/xRyUKWD + wCa1K8n5HKrSVOIlmJw/iV5DHpIDSWhf04nhSILFPpjgQzTvquqX0Mpq3OIdoBLzIYXU+DYKoZxYGHrn + 9sLFZ77THK9OTGsAoJ/56JlSL0ATJiDdiAl4YAEAD+oSEjQ85ZQ3YgiwAjKZbgSAGPzkJ7dDKtWKzzmF + J+PqxUaJszvv/B78/e9/giOOOBI+/OEPw5YtW0wS7sXe8ZvxAAwAyI2OcfkhB8H253bB526+FgbSeyDe + lVLtoPQdcCHRfHtKfjoy1NJzhYAigzksGSdnydgsoo1WWkiVF+POpQUo4q5HTMDEP9SIbqIHO5MiNJFE + F7W7BOPHTEDp4BK7/fEnEQDWoZdAeq8TFivMQs0T/8+rmzyjXHcxRs8Wu7ZkAKnkJfSQC9uqrxhoMJhu + FQRsGQRcdOhg8EOAwrIC2oRGXlyp81Dtn6Yekx4BlQJzJ0wywGYea0fjzkA8H4dwNQJenMqhBcguGYfh + Q4dZUmvOX7pwR0ZDJc4+GVzJH9Shj033dGgHwCRrWbZbyaQTt4BKipPzJmB0eZbLg8ndcW4oys8qoJFP + QDQbg9a1HZDYo4aGEMiTK19pLXKlhiYJUSkyOkpxf4RJT9yS7Mq0Jgh4g1opmo/PMvkjoiiTElXfPASA + s883p5xsQtsFfw18IxLVZSbgw39oAAB+DvcCIAAcmF6A173udQwApIyjAaCzczYkEhH48Y8VAJx44pug + XK4FAMAWAPgLLF68CK655hoWOTRU3AZDfaF3/Ma/yQPYtX17HQBQx9+KgxEANu+Ea2+6AXbCACQ6UmpB + OdS7jQCAYUDYCZtdV+vOeeAZAo7pIqOogAgtSTXjrzSPAKDIBhBdizHsGtzJRtHlzTvq9bg4S53onh6e + g9qsGoS2hiGyOQb2Njw/1OiJ+K4AQA6YE25+JWAKd9+yTL8AP6YbfAJDLdX0GzBkKK0vYAZzao6BeU+R + CnDAkKG0PJpxFCxNENJAoZ5D4p6sHkx05K4KVBZWEAAmEBwrkHomA61rSJgjCdFyFDyMtwkAxheNwwT+ + xPYkofNfGP+ju87JOFLaLcsMQXl/0xatjyvgEXleTY1Lo3NMA1fRA6BYf2TFCANAfG9crYueSS7HtqKn + kd6c4WoDgQ0n9lhmvcaVAvps6u0PFQiIwkzO4ooE2D742AHXRDuGtu8hco8JAkDvvAVw4TveWWdyQWFQ + uk4LFy7kEOCRhxAAgoIh6iW3AwPAxw6MJiACwHfRcC4iyeyTTz4JenuXQ3u7BoDvCQCcigBQBbUjEABY + CADfhcce+wuGDIvgqquuwlh7V527cyAMX9+oHXg3TQYKCCzSxVi2fBlsw/v//y9+EQZHxyCVblHjsigE + iDoQi8V4VLiSjfZnAvCFklIaA4CnynCsmUexvQBA/pA8lPorENkRhvg/cTEPqW42Vs2J4sKcU2ZBTcqO + k6ZeGL0EexABYhRdyZLipauLExhIIrucLZUBz9OxPQgAgLqzpozdkx4GT6YAK+6dpfQNtEHX/My/oiz7 + FQVuZ5Vz6okBanFU9WPaEtXzXcs/H+QBpIAFRKuzXMgdNQnFI/IQGYtAK4JAansaYoUYk4bISCf7JyCP + 4VNqawpan23jchx1AFK8Too+6vN16U+OUdp35cIrUPbk2sSokacKxU7a6cdg9OBRrtnHMRyrotdByUG6 + Hh1Pd2J8n2ZPIDwZUoNDbekRYPq1zRRklhGv4OMVT/gPvjdiGrT0dWno1jIA0LMQ3nXOeYEdnwCgXhWI + AIAmcP3x4UcYHIIBGKgk4BVXf+LAAcD/ouG8jQRAXv/6N6B7shja2mZj7B+Bu+76DqTT7Xj/mw1hQWc1 + qQrw97//GT2GftYFHBgYmAIALyQI7IsHMIAeSCMALKJ24B3b4fNf+AKMTtBosDa+Ig7pAqL7Hw3HIRJx + jI4/LUAeCQ6BScEAZqadEuNwuU+gNLfE2f38YQVOFiX+loT4+gR3CNIOU4mXodyDu+JL81Brq0BsTRxi + 6+Pg7HHAHcHFm8cfLnl5ZqCo+UxL7cjEAuRPlgGlnh7zZSvSD+/znvZaFEjYkgfwxJpNbgN8AKjTBTAe + h+XnPEQFWekceIruCjI7UCsk80n2uMZPnZJuKxr5sjx/XysJkH46BekNLRDNx5ipSPX6XB8CwJwCtDyX + gQx6CFSTp5g7XAirkebMTXKl+SmkGppAOyCeX9r01A5OmXzqLyh0FWGidwyGDx7hsCA2GOWyKyX5EoMx + 6FjdDsldKXbxqYefmpqYKW1XGeCph4PaubnXoWYZPkJdFUbi/iAAaPjWiVgimNFgkPPPPsdfn5TmaeD7 + EwAQD+BPj/6RB8oEjJ8+mXoBrrzmEx/LHhAAOPHEExkAaC7gSSedDD09/RgCzIV4PMyJvnS6A97whrc0 + AYDbDABcfvnlLHLYKMjxYht+UA+gGQD0L+qHHeiZfPZzX4CRwjhkWls5zg/jhSIeAM8QCDuqTONq5Swp + PYlLLtahNiQOAzDeS9ag0l2F/KIc5I+ZhOrcKsRWxREEWiBMSjwYP9ZwdyrNK3MCsNZWg/izCADP0vSe + EHhD+D6TaDQV5ePreN3T6e+gnL9i5nCJ0nP88IC5QCE/IadHnHPtnEaSOdp1l/MUDtTTg+xUuj/kj8XS + c/gU/94DrSdoBUaVe9ov5iYiT/UhoHNFZcDCwRgWdeL52BaD+NY4a/zRZ1QRACb78yy0SqXC9Cb0DkYT + nA8IlYT9VzMsZiWTXpMpaZ4SbLE8LZWmEoE1LQ3WUYKJhRMwcugwgwKRfKhbsoIgQKKlbeszkBxAsB+N + c3uvV1ZlOVfH9PiFHGEb8mCXmmU8IVZ3DiTwwNLeoZIX86c442twXS1aiADw9nPq1mzjbAAFAMPwp0ce + beQBlAUArkIAODA5AA0A5AEQAMyd2wvd3T0MAD/60bcZAE466a1TAOCOO77NANDX1wdXXHGFAYDn0xH4 + nxq+vpEs+O5mHsCiPvQAdsEXrr0ORvJjqgwIKolJcuAkCEpDRBi0JH2gd2HNtnPF1bMlScbDIxK4+3TW + oDivyO2w5eUlCO8OQRy9gPBAiDPIVKsuzq6qEiACABl/fA3GoKSsO2xBNY/xZ7WmEo5iT3VJOskB2Cbw + FqfTk9HWlgywlJ3KlvDMtdQXUePONCiIsQZ2fAYDx68g8H0EGiHRITRkKOCSHzEA+ZP0DHMRKCVSDUmf + k/YhSYmVlhWghoDoYBgQG0AvqxDh9uXSbDTSxTkG4I4n2nioSCQfFW1Fqz4sESAySr7CTbAtTxJyYqD4 + ndgLQFDJz83D2IpR7g8I405Pwq4UsqU3p6EFPRFS9mFmX15l91WrskquEv2btQNromBU1edPXQsesFIB + 6czUm4TFr/GzrsCy4L29C+Cd73yHWYesM1mdCgDcDfjQw/UegMUAcIcCgI8fGB7A61//+gAAnIIAsBC6 + uuYJANwKLS2d+wQA8gBejBBgfx8jABjYubOOV01x/qIli2Dz5u1ww8qVMFqYYFVg2klt2+HYn+YDEBDQ + BQ7GdDpRJvZmwEHPlyOaL8/7oxgf3d7iiiInlOL/SEBkS1RN50XjYAA4Mg+AO2T8iTiXDEO7MQzIoqHm + a2aUmJGrNmupPuOuEoANF1Snp2VR1rmr6ksIhVcZbPA9jbuvgSbg7nri/RhJcs6LWIH7NKBIWEJhAPUi + tHncllw6NM+ASIq8yW1JdPEjKls/pwi53hyEERi6/9oNsb1xxbSjNmP0mKgS49k6069ifA55wBU9P6WF + QoIr2gDVrMQaS3nlZ+VhYvkEFGchANH3xvMfwt0+vSGtjoP0AfK2mu3nSQLVE861uPY8H0GPgvf80eCq + QuSZv+1aoIVcVwRw6VFCefH8RXDRme8U4/dLgY0AQEzABh6ADgEUAHzy4wemHdgHgE445ZRTYc6cBQIA + Dvzwh7dCJkMAcFrd7hpCo/nxj78Ljz76ewSAfi4D7t27t74b7wAYvr7RbMApAIAgtWjZYtiybTvctPJm + GBoZx++UwOtbY3AgrcNoFL0ARwGAqveIKywTgPjyORL32soFZTJHVE38JR58sa8E+cNx0S8oQfwpNHKM + fWkqD9W6ySByx+Z4Wm/8j+gObyQAoFIhLvYChQA11lkwoYe5WA2Xy5rmvkCcOd3r6t7T0tl+P5atO5fB + 8qC+OSrxZlSF+VdDOEB9ATy2vATlwwpQOKaAhulBYlMSErvi3GhVQje93InnaDAOXY93QXQwwQk5agBi + vr18Hx2KsV2GQDwfT2+yCACeIWwRM4+brloKkJ+DHsDSCRhfMgbl7hKHFKktSciszUB8BwIAVQAKktgk + 110SvFrQ1dVjxEE4DlCT8eC26blgD0vGnWu2EhdhSCmZx4OHYfnsZfChV13mhwzQHABGR0a4F0ADgJxZ + WmkEAFccMAB4wxveYADg1FPfArNnEwDMhVjMgR/84JsIAF0IDKeje69GtFCSiQDgrru+B4888iDzmikE + oKnCmgnYrBT4n/4907/zCAB7mgBAP3oAVAW4eeWXEKDGIB5NsZEzFTga4d0/bIW5fkuGodxnz+yQnujo + gau3Zk8tDGq7TVosF1akRpgjclDCXc8ZDkFiVQKcUXwvdJlLy9ElPqoAoW1hSPw5waXA8F6trkMThhFE + 8Lx6rufbl4iC1F05vVNDg5FbU89Js/M00/37ZA7qu2xTHJTSmAIUNhwSIInjXd2KEDT5shxUF9b4uya3 + IOiGbSjMKoIVIeWgFuhc1QGxkSiXTEkRmUeYgSq9+SVAf0qzuumJzWJ8oHQPaIBLlTQcKRHYpyoBE8sn + IZINQ9tTbdCyLoPhBnpmI2peoOUGeiHcQM5FU49BJ1pFJFY3XOnngAoZOH/gqDZrjtYouZwIw6K5ffCB + N15WV5JuBADiAXAS8JE/TnkMbz/Cn8s/+smPH5hmoCAAvOUtp7Pxd3eTBxCC22+/RQDgTDzQIA8gxADw + 6KO/g7a2drj66qthBBGNZLk1AOhQoLEf+sXwBigE2CNlSH2zpRtw6+ZtcMNXV8JgZAyS7Rk0PBdCuAMQ + BZjCAGIEUhcb953UVPacNOPYCaDaGmeFbSWZpV1QWQy1FrXLF5YUIHdEHrzOKsRpgs6mKEtgUUKMxnfF + /oWewVMIADS0Y28IrJxUHAhkqjVusfVE+ZZ3XHHr69h/2iVvIPhYsmCnXHDNHtSvneb8TXdf05UT4ALo + Mp0nAMB5gnYMi2iewKGKFkzVjfjuKA8bKfSUMOZ3oP0fHdC6OsMDRaj8x7qEnqo46HBG6YD4YZipimjh + VH1cVAmIEAAg2FKSsWcCsoeMwdhBWfzcOHQ80QnJzSmIDaHxj4dZbwBktJsdaJDQzEur8UsHPDPdps3A + pEusfAzCFcH/h+0wGncPXHTB+XWnsHH+n64CcDtwIxPQslgWHAHgwMiCn3TSSQwAnZ1dDAAdHbNMEvD2 + 27/BrEACAPUlNACEuUT46KMPQnt7B3sABADNkoAaEPZVHfhPHtMAEDzR9HkLF86HTRu2wBe/sRKG5mUh + M6/VKPASHZh7AmylQKtm6HmsesuLsap2CE/P6KuJAdDvmmKiqdHfuPioP+AwpaMf3RLhMVosrLOowLFx + 7EmS1o7xGO/QHpkGTPV3V5SIidhC2FURO3ckiy+JQLML6mG5huEjRi718brdrK6hoB446rj++qlW4HP8 + idz1K0i/h6dpeSDNOR5XEtwMGuQCGVq6rIL/rkBkLMTsyQqCY2JvFNr/1Q7J9UncoaOs2UfNU7wrB66p + 5wU+XPITlhNwkuV7sr4BVRiIC5DBMKAnB6MIAIW5eUiQ+0+lxl0J5iWQlFuYBrC4vnGbc+AG/g3aC/F8 + bYbA44azoY/L0uVTj9ccDQa55MJ31X2fZgBAVGCSBKtOnRzE48E/+qlPHBhBkCAAnHbaWQwAXV09nAP4 + /ve/Dq2tszA0OKvBA6AS4XcwBPgtewAf+chHmNmkAUAbabA7MAgAjR1S/3EIMA0ALMATvXnLFrh25Q2Q + tXLQ2tHGl48FQSJo/Pgd7ZDq1yZqK2e6KbsryTBXd83Ziuttyl+0+IgDTpN0cXGXOigXUIDKQRXu7488 + R43oFpTnVzkBGFuLu89zlP0nHUD8XBICpbZhAgEaDsnjpVUiicVItAyY7FSamMOJqIpKPln+SfBbdrU3 + oMGjAgYnyFCULoBlWIDBMpgFAa9BY4cdWPAGMIQrqDULxBWm/ocq6QPMq0JlSQUKJFLajrt+NsIGSopH + KdyNiQMQ3xxno6T2XFvUizXlLghknuuDmAEtDUqi48oCqVEEGBo4On8SRo4Y5RJgam0aUjuo7z/Bsm2U + mHWqtgGuuiQoaEzwcxuN92lQqIvALB+UmAiEGwoNB73oHefvEwBow3w0oAkYgKVfgAKAAzMa7OSTT/5J + rVY9u6urG04//WxmAXZ1zeEcwHe/+zX8NwHA2eJeTwWATKYVPvCBD/AYMQoBZmoHbvx3Y7jw7wIBJQGb + AUBvXx9s2rYVvnj9DTCezUM61cKLlToFw6CSgAQEShjDYoopG5IwAzlJxDkAZnub0VTcAUbtoTSgI+Ny + iYsEMouHIwjMrnK/vzPqoDEQUaYGsafx0zbEeHAnT+2t2WoTdc0Wr5TBZSex9KLSI8ZdPy9h3FfalaRd + 1dILt6r0BWWSKMehLCTq2obXoNawEt5U7EHFSOQaO3sYjupPkLIXJUzNjqd7JQLhhRr9R9JlNAgVXzqH + ZgpWIHdMDmr9JfWccI1Vk1pWt0J6E+7KO3D3n8BzTzMAK75ysKflyCxl4Rpw9U5s6vCaD4DXjGYN8MTg + JIJOTwHGlk3wfanNCYgPJJR0d07LpIMK6Ywj4/nVD/D89/XqDZu9j4YqjDIq9TxWkcIb0en7EAAuPvf8 + 4JOmDAAlAKCc2Z8wBKgYD0AuJMC9+PPhj33qE9sOFADcXa1WTlu4sB/e/ObTIJVqxxBgLucAvvvd/8Ed + ngDg7dwOrE+QAoDbGABaW9vgfe97nwGA55sA1P/WXsF0nsFM/9YeQDDxwpJgi/pg4+YtsPLmm2ECQSKW + SCoqsKW6ASN4wRxH5tjpAaFSj1blP1fqxLJR0v/kOdwQGlWLvtJZgeK8EhRfNonxbwnswRCEd4R5gCcp + CSX+jiHA0zEI0SzAcWC6KV0Sfg9bdO70+Cvhl3NNPhK4cloyjA4kJNl8W9XjdU3c7NiaqqvpzaD4Qaqv + XurowhGw9CljB4/eK6S8HXoRA4pt2qO1EXDPvmf7ZTOdDY/hN+I8QA2KBxegdEgRKvPLDDKxjeiSr2qF + zPoWiO+Ms2QXze7jCUDa0MTA9WBUV3sFuuIA/neyRKCEevPdcBXcRA3KlJTtKvG/qSsxMhpVvQZlFXJp + Ypf2dEw1xJHzqr8fyPkLeBsGAAJMQF0+1tl+UpjqQ+O++JwLzDrkraNWjx6UBBzcOwh/ZibglLkAv2EA + +K9PPndAAOCNb3zjb9BwT1q8eAka+umQSGQ4EUg5gO985ysYEsxGYHj7lBCASEIaAEgTMAgA/06iL3hf + MERo/Gn2GgaA3bt5THc9APTD5m3b4KabboJsbgJiyZR6ja3Gg9EAUQYdy/ZjQd3q6Xpm2bmmS80z8R7F + 77RDUw2cSoI0N4CTX0eV+G2I8VfrcJmtF/8T7karouDsRc9g2DK1aN10RMDl1nTWGRT6uB63outSJO9C + 4jBwtUKUeUCXLS0Z8uHY/oJ2PKPiw0k0R74Pk4CANQOVO+9xSMMYGBidpROMnu3HvJ6U5Tx5r+BEIx4v + 3kpioVWo9qAnsLQEpeVF/ozYpjikVqeYmBOlrrwcnouqI7uymkmgwZfDnpq4/q4a7qnDIL3v2tKTUONz + 46pGrShJsVU5lCMeAsmME9eApyS7fjlTeRlKZswVgpWO7hSYeb44rDZLK8Ck1BUZzeAEBVbkUfYt6IV3 + n/cuH1ysqSEAAQBpAnIVYGo78O/w53L8WYMg4MELdJsRADB2P2nRoiXwlrecyf3/nZ0UAoTgttu+hAAw + F+9/R50gCO2aBAB/+MMDDACXXXYZAwANDd3fMmCjwU8HBkGDbgwZ9I3KgHubAEBvby/zAG68eSWMTo5D + KpMx7iR5AETcIMYgTxOy/AurL7Ln3+FzZizlKlPszv/GHZ4ahNgLWIIgcEyRh3VQvz8RhmiIaOIPSQiv + iXASkKYBe2VPWnYsw3YjN5JAx9UjrMlRd3xSivkJ3nQEYakFraNlQiwOExzlSRi+vyTAqJeetQAd2RVt + SbJZ6jFVkrQYS5joo6nJjpI89zSwSF7AHy2GP2mPqcAMAMvxfKAXQKScxHNxSKxLQWw3xv/ZGBOAlFGK + DqNn1/HtFR3XCmToJVkoWoEqTJIpUJ5PHCL2H0uel2weMWbTpKGKJUleUINRXMOdNA1WXlX3PIDP/SB2 + oGZKej4QmryK5V8X8qpoNmBv/0K49KKZAUCHAH98uKkewAP4cyX+rEUAaBJ4vGgAsJSTgKQARDkASgLe + eqsCgLe+9dwpOYAf/ehb8PDDCgAuvfRSKBQKUCwWm+7eMxn2vv493XP0Z9DvIn723p07JYb2AWDBgvmw + Zes2uI40AQuT0NrWoXYSvJAOWjGFAJQEDNJh6+xLv5+50H69XgGJx2QV6kqjIaDl/iIUEABKh5SglsDn + VV2IbghD/NEki4E6oyQFhkus5Jnvofvw2VVkT8D1E1FilKadt64kB/WZbH2oulSnWXvgP6Zq3ZbPfNMs + Qb2aa/7r2dUOvN7cLwlGTRMGCT9IoZgSjZB0uTJSm4de0YoS5F6Z4wRhelUSEuj+EwOQ1HlIbdlPKHpm + 9JknYh9a34D/1seoAcnw8nVZUqTCuVlKn1swwqacAxGwZdP3pNLg6QoEcD6EAFg1QAFrAXDXIKjn8edJ + J6Wlz7NmCpJp0HhwzgEshPe+62IfAEBNigregh4AJQH9hC7/9378uQJ/1h8QD+CUU05hAFi8eBkCwNvQ + jUlyDoCSgLfeejMDwGmnnTcFAO6441vGA7jkkkumJAEbd+p/J7u/r/v0/SUEnpG9e6fkAHrm98CW7dvg + i9evhLHxPHQgAIDEkSHc+SOhCJcDQaN5sClH1389adbhRWGCREMOUX3lwEy4Sk+Rd7zCSzH27auCkwV0 + /+MQfTIGzvYQ2Fn8ySkNfnP8np9lZ0+g5vpJN8vyS2/GXGa4up5/TgwoWIHX2VDvSVgNjwdfD/571r0f + NPw2n63OK4mF0shwrwN/99Vg8jUTTItOPpWC5JYUxEcSXJcnALACYYUhQFlqjqBJzlmBJCADhApF+Wsw + aLjyeouJQUYPMaRyLNoX1XRiS0CCPC76m5iFMk1OeiBA8ieW5n6Z10NgP/Cly9TEJs6rhGxY0r0IPnzK + ++quWTMA2DOwB/7ypz8ZTcCAid5vqRBgw8c+fQAA4E1vepMBAKoCRCIEAHMQCEIIACsxHJiH97+zDgAo + 23nHHbfCQw/dzwBAE4LJA9AhQGOmfyYgaBQSbSYs2jhiqfH+En72KLpUUwFgPmzfsRO+cP11MIYeQHtH + p2TelQcQtQUAAET0VrWkqqyuWoSuWx8aWBIbaooox+Mxi13fSmcZiv3o9r4Cz8XRRYz3bUj+KgWhNRT/ + Ozxg0y6pnVOrDtWV3Dw1dEVnlS2TEg8YMATq9TNc7WnpxNZ+Pj/4cLP8S2MJjZNpqk3Zi6vuQJjlQumw + EgNkbGuM5ynGxmKcAFR8DDDVDd79a365UZqRVWgkCTdwtVyJCeRB9M4VkNi6WuMJ0UeHEYpvYfoa5Hk8 + 6NZ2TSKQ7zcdmZJkFSl1FQYFGIE6eauvDnlr+D0XdffDR97wfn8Ny3cI3hoAIAjHdKMQ4MMf//Sn1sML + eJv26p566qkCAEvhjDPOQ8OPSQ7Ahm9+cyVzAggAdBWAbrFYnHsBaHw48QAuuOCCOg+gMQfQLJG3v7v8 + TIChb+QBZBsAgJ6zcGEvbNu6E6798nUw3DYKmdntSniZ40CSBAtxmUvFlqovnGJB7eKSbbMseM3PCPN+ + TdlxVylEsDtKri/3B2Dc21OB0pEYBhxRABvd/fhD6P6vVXMAnAmLRUM9N5BfEEMySS5LSZPX0WDp+0qW + v9HVD95nboG5AnoRmt0+GO4ETmMw065fGxQbncIqbHh//lN2WaDRYQn8ow1/z1btyWT0EdLbI9WdvK3c + cgEeBkO7/r2DXolRa3I9IwraWLNXZC7d7uwFxov7OR3LR1D/+DXJxwHTAqyTjTocAUvt8LaWJrL1dfKT + hUQJdsI29M3vg/ec824TfXH/gDtdFYDKgJXGM0oA8CEEgANTBdAAsGTJcgYAapIhD4BCgFtuuVEA4Pwp + APCTn3wXfv3rXzAAnH/++QwAjUSgZjvHTB5Bs39Pd1/wfu0BeIEcAANA30LYvmUXXPeVG2C4dRxSJAlG + F5ey32j4Ns19JCagpIAV/1uVmHg9UlKO1oalxULkEtV0FkjFmDpmJmGMGpXB5legOqvM0lKhzWHuAXBI + NpzmBhQsqccHyk41q64t2BK6qto5LBGlVPFqcPfTG6BW6DHEHM1es2STDEwXqmMBBsaQ6x00uBSbqwM3 + gEEwDyE5BdYpiODfSfzdohSaQ5UQhMp4LioIhCUFAMaTg/rrZu5rYN/R+SDPTTc0KS6/X9evy3XA1NyJ + 1hHQCV4OB2ras9Pio7r1G6RHQ0IHBhR9wWRz8Ky6WQzUW9KPm86l777IwClAcwAYGqRegEegUqoEmE78 + Rr/8y9//+pF7f/XLLYGX/MehwLQA8OY3vxkBoIwAcBCcddb5nOHXRKBbbrkBwWA+AsMFDQAQYw+AAKCl + JQNnn302P9YsBGhG8Nkfj+D5NLRoD6AOAPDi6sEgN9x8E4wV85BMp9iFh5AtuQx0+unviFxwLsNJNlq0 + 3005jGyKyD+OXvFyUW2ZVKOz4Al8JFPlCbp8Q6MPjSLYsBCFV6/9V1NGzoBDIQW5u/SY0JUZAGRSLru/ + ogOoSDkKkCyRrmYPRmr5zAOQARu60qCTVxAwMEcIQ6bUB1IV0F+R6Aq2JA1lhVpalUiWpUriaaABkxfh + 18bwfvQkSYCV5MEdVhlSzT+kzmt0jfUlDez8QSquJj6xG68Tpw0A4O/c6hi4x98L0M8bQpZg2GUkx+Rg + jAqw62lEmGKGftHIF3QLRRAAFvTCey9+t4CJQuGZAaAcQF2+WPf86a9/+ciDDz+0nZLqM9yeFyjsFwCc + ffa7IIJfor2dcgAWfOMb1yMALEBguMDwAOhGYcKPf/wdBoB0ugU9hNO5nEYH3GyHn44dOJO38HwAoIyf + S+2V0BACzJ+/ALbv2gU33rQShsfGmLVoLjLlMkIhHgxi6fFNphXVNaQZqFkmQaRlqdQJFb1AkeMiV5EE + KWkKDtGDeXgmPb1sMftPy0wpuSswbnpNtcCpRa6TgQ4EYlYwBkj/d3Qmv2bVxats4ELW8diD8KQaYPml + LzJOoQfT8xyZSuTJd6dR2HQKbQ0k+vXVhutY1fQcMRZLnTI9PYhBMqRAgMqtqtSqPCkaPOuQ3Jd4LXqY + i5FDF29Cf7cgU6++dVnCMpPl81e6JvUEZxlo5WT10kAOSbMtGVAU2AXxwgM/9DRmJM8xuVDJ+IejIVjU + uwjef9GlUqlwGYw9b1oA8MqlMpiPUYd89+YtW6786d0/3zY6Ovp8jHzG5+4TAJYuXYEAcCGGACGm/5IH + 8PWvX8cA8La3XchJwGAIcNdd3zYAcMYZZ/BJ0mXAmQg8M3EEng8QBB/nEGB4uO5L0v3zenpgx67dDACD + 46PQ0dmpFg0x/IgOjGBH7qlajLIo3EAZyVPxvhGp0O45X2/X37lcvVg8jn/J+Hl+ngAATQDm3Vp+DJEH + /IXuyZhyvbtSJyLP9iND0s+l+jbnAmxFXQbP5AbMTuzIAArLNXMCLH38jspnaGBR+QAxdFC5EFqs/Fsb + EP1UbRNdcN28FmDjSRelrtErtp1fLLctdPstFVKh6ePfUaW8o2n5NZkFSOQfXZ8Td1z3KLjSgak7+FR+ + RMDUWKKcO8v1HTTt3QSBBerLm3545BmcBRn1xYlAfY4MuoB/jAJUHCpQ1BMOw6L+fvjAxZeJ9+Y1BQDm + AQwSD+APbrm+GYhO093rn9tw5d3/d8+27FhTUaB9gULTx6e1ore85S0GAM455yIOAVpbu5gK/LWvfRFm + zVqIHsCFEgKAAEBMAODnCAAZeOtb38qGTSFAsx1/X40/ze5rNlNtOjAgAMgOD9e/J168np75sHXHDrh+ + 5UoYmRiDzlndisAjJSCqZnAOIOAf1p+9AB0U5MJrrYAAcchPSfl0Xs6GW2o3pSmyhkqrBUYtz8T6QUIN + L3DZgQ3TL5hwYzfblsSU7JK2+vFs32iIGafJPSaEERkvIgDxIFCT1bYUOPDnCcFJZg0C1+SVPj7I4bKr + 4Ygqjqe/v6xfzzPnSemshNj7cFyhelsRDAHkOokAJ68ZPRK86ikwYqqxrY6x6poeBp3sszStV4cx+jy5 + DbG/FUgC6uGi/D1Vzd/TXha4QqmWkMeV59mWwTNVZdBv7YcGekgIzZmkZqAPXXKZuU8/HrxxM9DwCDzy + +4c0AOhvYCOY3HP/7x644i9/++t2IRDNZPD7/dg+AWDZsoPh3HMvZgAgGTAFANcyAJx99sVTkoB33vlt + +NWvfsoAgO+hCDmBECBotM1c/f1hBe5P+MAAIDmAxseJB7Bt52744g3XQzY/AR1dBAA1BQDMaKR24JBi + xDW5UJ42ejl9ulnHlAUbJvjIijRnvq78ozvbXB8ugq/VbqQhkIhSsdnJAlcyyGCr6+ADWeReg95fMM+s + 39eyRTnY7xewxCvgGD6sd7iamjNgizdCz5bmJUtt64oLYek6u8+RIACizksq4XEsT6QpSr6yt2Obmrul + bViHYCDXXQ0I5D4GPpf4RLuq8h0mr6EbnWSnZk1/w/LToQmo/IkL/nmTSo8K+ywZ8Cl9FLa+VOIJGJDx + ezW49q/p4ZIoJFJZX/9C+OB7Lw14Js0BIIvu/cO/+30wBOBgynXde35+z91XPLHqyR3TGPN0Rj/j/dMC + AO7eAQC4hI2ipaUDASAC//M/n4fZs3vh7W+/ZEoIEAQAmirMhjhNErDxd7O/mz1nuvp/o7YA5QCylANo + 4BD0LJjPIcD1N94A2eIkZNraxAPwTPzqUEzq2E3ZgBoAgrFecAR6sBGkrowmL67TGdQ7f6DWrV8XTBKZ + 76wz8VYAKIKJLJ0W0DwBbbxBll/jsgjkLvXOZunnGM0/5YpbUiFgY7NsA2x2oJTmNbyPpghrySwGhLDD + 5TGbDV9l2Ok+6kNwQUIhrs27PrnK9sT9Vp/DiVam+gbLeKpzUHUmBsoArtUgkOKq8p8ZqqLA05J/a4EQ + bfXcN6BcIOXouOr5nk7euiopaevZkTJCnu/DzXNh3wL4wHvfzRwDfW4buwoUAGQRAB5EACjpK8lH7bq1 + e352z91XPrnqXzsCr5nO2Gd6rO6+/QKAd77zUhbMTKfbeDDIV79KANAH73iHBgD1GgoBSDD0l7/8KecA + CACCOYBGFaBGg21GFDJrdD+rAsF/k6jCeDbLTL3g62k4KE0HvuG6G2F8b5HbgXm4Y0gtMEJxyhQTctsR + qM/2BuJH1anmi0QE3XWTpJIFD36e0B8yUvM9BZNxDuzs/BnNdPqaXLVmhB1f7EMjhOW/1ms4dw0ei9X8 + Q+pf28AgNOw9AL8ZyOxhIIKZ8lHkBeCmQhuLEh1Gjyuskho+mNoMAIqUY6vWZK4maNltD7T6PlGvVXVG + NPocOe/BvgXt3hM92KkqUKMPclwJhfQG7Rk5dMYFRzEHVcuzXQeQOlGqwx5bz5DkaowCBeot6Z/VB5ef + 8QE/jxH4nhAAABIF/f1vH3QrBgDUWUa3/z4CgH89tWp74DXQ5O/n89j0HsBpp50WAIDL+ELRNCACgC9/ + +XMwd24/AsC7AwDgGQC47z4CgDQDQLAMGDTQ5/N7Jje/8d/Bv6mnepIAoIkHsG3HDlh5802QDdFw0AxA + AViPTzWi2GYoCKsEuY7q1RduOt/Klp+9191gQWJQSFzmmsr6i1XUqeoEST/BkpOpCFiBRaJ39YARBq9g + oyag/2fAg7GtKcthCguw4X3NIVoNz7OmXoeGN67/7OCxCRhauKk4/IPnmHdKxy9PyrG5AUDxx4A5ZiiK + Fkjhzdz1BAAUMnnyAhPGSMLCC6Csmt2nwEw7QVrXTwOHZXnGI6mx7oPrx/0CEmpSsKuCOEfHFyopa8ct + WNK5CK4+8XIw/RUwJQTwent7rYnxcfjtrx/wyuWStH6pFVOpVu/DEOCqVU8/tSNwlabb8ZsBQNPnzAQA + 9yMAnHzQQYcyANBJTaUykExG4Utf+iwCwCI455xLDRWYbtFohLsB77vvf9kDOOWUU/j+6cqAz+d34337 + 005MAJCjjKkRalOLYN68Hti2ZSfc/K2bYdf8IcjMa8ODVN1jROrwqioJZAdYY8QQpC4yT0+H4a8thkoV + AU5cucql5EYQRWElQKnpefbkiVQtGd9lGbopLwR6P9cfOc0P1MQ7twMZcJMbANPKGxwcEmwkMruvEwgJ + jKsPJnwItu6ax4KalGYfgnq6cTNvotmKsgCaeyg2i8lSxYWZACFHHxAEZbVMLiJY2pOToUFBE6gs4/r7 + GXpLQhZ9DrSQip7xaOtdXcDE0HuNhXt1IiysAMygIF6eFBj4NDpqQwAZHcdVirjNScDLz/WpwI2hIAgA + TE5Meg/86n5XQgB94pxKuXL3L+695xoEgN1QL0Myk7HvCwimDwFOP/30n1YqlbP6+hbBRRd9iDPjyWQL + egAEAJ9hADj33MugVqsEQoAwzwVQHkALdRTyhdmfMmCz+P75JgCDf9P7UEslAYBaK36egMqA27bugBu/ + ejMMuiPQMbuLS0rUbKJILi7HkGqqi8VEHlv3BsjOYjs6uy47EC9QJcFFIMFiD56fjbZcpfbrSWmMa+pV + NXmIef6uei23mWodQE9ZuqVBRSoGrgzoYHdTutU0g42BtqbyByZxZ6vj0Co+Bvr9NEFAAbf+MRM9CDlG + lx4bl1JwAnGwglHnSXgBEJOdkPOFtgoH2APQ4CUpO019Vi8PrOFA2AHymAYNJX7iqWsIsoPrUM2UExmC + QY9OU3kiW1f7BED18XqK5GnIVwLAjjox3C7syrUOtE1rR4NK6P2L+uCDH3yPHy5OjcgJAAA9AO+3v/6N + K0lAc2WKpeLdDz/6yMf+9tjfd6NdBlO4jX833jcjEMwEAP+Lu/vbZs+eC+9971VM8onH0+IBfAZ3UQUA + mghEJ4S0Amg24L33/sQAAC1E7QEEDXg6AJjOoBsN3sg0zRAWYBwFeXSpIPg8PI75C3qYCESSYCPD49DV + 3c319Zo2WvpGISX5pJNtvEuQwm1YJcJ0okn3vEMURJVG8kriJmqOuCVBI78vLRpwRaEHeEXVpHmFk2GU + XKpqg1SiGMYwJb7UNXbmJ8jUGj5OaVdVsl+yZQqLkK+Bfo+K6mdgigGimWupEprhMxjgsOoAhgAxaGCq + bTjgYTg6F6LBRA484MXoh/R7hkR8hdiA9P7qeun8iOXnT7TdNCYwg0u+bhlYJifA5VHX7woEbaQGCJSt + sVG7yvgNOFoqjNOOlgmHXP9QtD5AMBmsD4gqaIv7+uEj73+/aDu4jQDA/1q4cKE1ls16v3/gdzX0AALQ + C3ahUPj5/b994BNPrlq1p+bWPJhq+NOBwEwhwPQewBlnnMEAMGfOPHjPewgAomjgqSkAUAvIGkUiNtx+ + +61w//0/x3AhzQBANcsgADQz9n0Z//64+zMBgN5Z9P3zFy6ArTt3wBevux6yE5PQ0d3FoiFe1a3Prmvj + kQSmqhDIziSuIpcOgyvR9lQziK0MnZWCpXymjcNixRpXko6ywOhVIamxB+v82htxQGb+6R1Rdncd85oi + g19t0K69cds5xHGMwg55HY5ksNkzkanESo1HQEaXxKr62G0lpKF3T1ANU2rSsK2O0xFQqqnzwruzMChV + XkXOlygS2XoNcHnQUjux5QUy+QIynvAUPDA04+D39S+DXEA3cB31HIdA8lZ1BIIYvK4cNKQ6pNrDicU6 + 467/TON5up7vqXiSzObZgP1w+WUfaGaLBroUAIy5v3/gtxQC6MeYdZDL5X7+i3v/7xNr1q0dnMa4Z/r3 + tPftBwD0IABcyR5ALJZAAIgJACyG8867FA3cd9mJOUuCoQ8++EsGgJNPPplzBM0AoNFoGz2EfwcEGv9N + IUBxYkLVlhsAYNuOnXDtddfBeCkPbR0dCABVFRs2Jsp0rK0Xh8zgCxJJlIvvU0o9GeulDFAFiZ6JWXVi + KtCjLm69icv1qmIwcE2/uidPVgo8YCYB82OyYwdn+/FgDnkrfT/z/EnpyPHApAVcSagJEUiHHUH+PSdB + LV+YlF9Qtk09nSnDNSHkuK6UyMR7qilxDCWnJu24ntqfKcFqqc4qNuoQGj/fJ14Df6LlilahVjfSE479 + vdtX8xDDlj59BmJXQAgkx2J5RvBDf18lAwZ+mQ4aYnTJMwRzGXXKwFCvURgEB55G1YshwLvfx6Vlu65E + WQ8A42Nj7oO/+a1bKpZ0JMFCkePj4z+7+757P7Vuw/rhBmOe7gdg3yAB+wUAKgSI4s/0AEAnJ4TorQGA + moGICDSBBtisDDhTHN+sYtDo8u8LCHiZ4K5empw0CB4EgK3bd8B1118PE5UitLa1qoGcDT5kPcdcjk3r + BOpsNgS49xb4/fxyij09WSZI3Ak8r7E1FcS2ggniBtVpfXCy2P3PrusKpGXj1C9c6klQuytIwpCnbfOn + M/CFFKio1lnw431NJTZ9DypXYoHwAEy8r6k2fp5db8imvi5Zfq6Rk9svZTNVk7e5DyGkKHksi67AxRZJ + dHkuhzuWgInnn5+qPMeWJKDm72vVY+NZ6NeL0YOi5Xq8Ri3fSnTyFkDCuaDZeHXrQE8TqustkHVL37Of + RuVd+h4OBxrL4fqGAOAhAHi/u/8BAgBX3oOzUqPZ7E/vue//Pv3cpo16NJjOtswEAA2SpVOBYVoAOPPM + M+s8ACL5hMNR3Nnj04YA1EX3ve99HX7/+19ygw0BQDabnZIDmM7w97f0t78eAAFAOZ+fklikbsBN27bB + jTeuhLFiDgGgTRo0ZgCAJsfY7MZdfAEOAATWS/A46h5rTJ6ZDLF4I5raqz9TRmWZQ9VxffAS+yFoXXxs + SnPSX6AO2vI9CVvp//nlOMsf8uEJ194SSexQoFVYA4ZjQmtFmXUCvfjCEFSCm/7xU9xv8hOghrNYAMaA + zRPJaKsBz0ru4wxdTcIT/Z0DIQwnYKUpiSYOK5ffT/iZxiZPG628L+OPJbJknpB7ZK/XMb4V8Pbke4M+ + R5IjYg+AAOC97+VJwdPcPBkM4qkQoKwBgF5gjYyO/uKeX9773xs3bRzWVy1wZd0m9+0XKDwvAAiFIgwA + X/7yZxuSgOoWDjsGAEgRiHoBSORwf3gA0xnzTB5Cs9cF/yZ6L7EBg0Qgm5OA82HLjh3wpS9/BfaODmII + 0GUaMxq1A6a8Z4MnUlfLNYa7/7eg0AZ409zf+N30Irfq3sgHieByaJjmUzflJ5Cp5sfAMvLaQUAyBJ+g + PLZk/S3pY9CkG0v8av4U9kJ0Z5+8j6mhBxSXwkrolGnGtgIEju8dScQCBCYES6XGhAgQaOqRE9ZMDEWy + kpb2GDRVWBwaS3siWurcskSPAfhY2RmqeKLWLGCjezhcMO6/JbkUV4ctnDilEAAB4P3vZW2AadaISyHA + yPCI99Bvf6eZgOiU2AQA3mh29N577rv3M+gBDMFUQw8EYubKew1/NwWEaQHgrLPOMknAyy67kkk+jqMA + 4Ctf+VygDBicCxCC73//a/DQQ782ADA4ODilGaiZce3vrj6Tl9D4HDL8Kn42eQJ1AIAewOjYGPzq17+B + 3YN7uAowmZsE6rIqIGDERBac/h6fGOdEJpVBSS+wXKmogQ6Bj2zkdE9JyOnjAmtagGikEzc+NiPpxv8A + P4nZ+FDj64M7a9O3sgLPg/r3DH5OQ/a9jvwTfG3QdSYD1VN/AolBpgWDSiTyj2JjCVRYJo/BaQwvEJI4 + GiAkvhchUS0cSo08HHfz81zpdeCToroEeWGAKesGtf8gWE7UfRniTWiwNTwAcvertpIr57KvUjWmITNL + MWS+/LwPMvGp8dLr3wQAWfQAHnzgtwEAYA8A0AO4795f//JzG557jpKAjbt/MyCYzujrQGImAPgpAsBZ + c+f2wKWXXo7xf5zjl3Q6gQDweSECvdsM3lRNNGH4wQ98ADjttNNgz54903YD7k+5b6ZFPBN5SMW9uM7w + s2sBAKDfs+bMhngyjeHJGOSLeWhpaYGJyQkYGh6BIj4/gWBHt//X3pdA2VWcZ9a9771+vWttrQghIUAC + LLFYEhAMZvEEO8khMQaMPckwQ0Lm2FlsB+fEPknwsNnGBGzGSRwHOBOzOIlls2pBQkICA0YrWgBJaG3t + 6m6pu9X72+b//qr/vnrVdV+3hGRw6Drn9rt991u3/u/f/yK9SzW1aJsLABAZWi30f29vn6pIp/i6R48e + pXM7+HjMJwD/f1t7u+ru7WYQAXDAJYeqSFHcvzEY2cDRD0R8RBkEAx4XBxTFQB1brAiO+zpymjewxwcy + PieUqCyWyMwAECaimn+hEG3kYwlLLhOIIVLJtTQxF5NyzPFhMYjHdLT+AqGWLnQwllXfD4cZgyqnZ4c2 + 0ER6lAn20ZJRzsyOHUlbcm5BGx6TVUl1ztiz1B3X/aW2IZX2XQkAwAaweMEiGwDYCNjc3PLc/BcX3vve + 9m3NhYIpTll8+zjit4/xqQn52K984403Pk4D/L+PHj2GVYCqqmou2lBfX60efvhezgW45ZbbWAWwZwZ6 + /PF/Ui+/vJBLgqEgSCPp2gCJE5UABjL0ldvPJZyYY2cjqyuO4aCmunpVW1fLQRpaJdbEWlGR1NyDiLYv + k+X3Q4QauD+ArK39mMr0kUSQ1oTdcqRZHWvvAMvhayGAo6m5iYEkwdOLh3TMUdVJEob4pDu7uwhIMGlq + n0k9DlVHVycbTNEgSeFcgIZdOz6OKEsSj8rRbT8CtfrOtmArNaDEMdC3MBcddGMVwUQEcpagiRL0HFlc + i/Jqnd3imZGS5SJ9FIqTuojlsiAWV6P7W7VddEiwVA5nVSAfxXSwByavnaFsM5E5FIwnJm9UHZ5sJp1U + 0yadqb5205cZ5Dzgmcc3RCRgexsCgRaKG1BJ8vWhpqbnnl84/76du3bCCCgEPRgpIF/umHIA8K80wP8Y + hP8Xf/ENVUMcMwiQEVjD6cDIBrSTgdApuiz4jxgAMDswAGDnzp0RBz4ZAOCLFIwbiAwA9Hx5GwBoydLz + oCRzuiLNz6w92ohjqOBFPysKgyS5pjsaZgtOV1WpynTacICAy4dX0DV4SNH1srkM9UeGVAdIHcoM4ILq + IOmih4ABteIgAvb09pBIp2dN1imxIUQ8VjdkNON4SCS9vV28DUDU1k4SS1c3gYOewCRD9wJoZE3/Ajgg + gbjlpm0qC5z/bZop16f9SHAwABAdHN8KhkuK2M5JWExMYYkEoCnaMWjIauBsc26tLfrmXaXEmSTs2IbU + iGdKDQfrAvkSTSdyAkjUoEypJi5XmVyVDY/0zREJ+Odf+hMG/OJXCErkI44DONpaWLLoRRJce8VXwXEA + Bw8dfO7Z+S98Z8/ePUfVwERe7rdkif08N9100yMEALfB+Pfnf/43HAaMVl9fq/7pn75DADC5JB1YJABM + DLJ8+SIGAFQE2rZtGx/j8/PHuffswXSi0gCaDqvN6pmBbO8AbAO0TUJww1A+uan3lsubacI0ABQy+mNi + ltd0VYp/E/SuadqH2Agm9ABu0AQDiDLTS+F/GEaTPMlIyDDDUgYmH6Xn6evLqIyJPgRIwr6QzepnwjqI + G0SOp9OqxTECl27+lnjXrq4eBo5eApRMto/1zmMdnQQ4HfR+BEL0ft1dXaqjsxPJJGxdl9BsgI8KdO0D + BkWTenwcTHvgbzDoiwWRkVDGAkBOjxlfpShjyHNtJcryn8bduySIp1BcLV6k1DMjBG5LV/n+x0XzOChV + nDPQeFF4NqrJk9WXb79dVVZV6vcqRFeKXur0008PUA9g6YuLc70mFFhCw/bu2/vscwte+O7+AwfaVakE + EMf949ZNmJcycxzFNAEASABf/vJfswSAx4EEgKKgbkEQAYCnnvoxAwCmFYcEsGXLligu/f1KAAPt67cf + fwAACIu1PAdicIvsV5EIKLPLGHXJ1Njr68noYpLgSkljTCoUjCFdAnRCla5Mq5rqGp3UYsRNFBdFPjis + vzhXB4JoXzCID1JGBakO6cpKVrEgZWHuhYqU5hOZLIBBV6VBOgIAIZOBtKE4lDjHswZlSc3J83oPPSts + FdBM8YwAhDZSUWDkzBJI5EitOdbZRdLGMdXb18uyLYAIKkhvXw+rJVigwmToWLEVAjCkTJUEVhWcopZC + YAPSvVeyNxGBBgy4n8JEdLD9qcVd6zOWei2g7s0jktNs3MKCkueLrekQHeaoXMb9J+vKgBTGzemTTuea + gLU1NUYyjMSWCGo0ALQWXnrxRZMMJE7YIEGi/y+eXzD/gcPNTZ3KDwDluL1L/FlZj/1WN998cwQAt99+ + h6rjyrkB2wB+9KN/YACwawIGhptgZqDXX18WAcC77777gQIAVABEBEI8thOOoimkrA/db3ySgNRLxNCb + 6laF6oxKZCtUqqeKA1XynAKoogHEJezpw9bQB4YtIBIRjToho6KgBICK0hCDAQEE4iigaqCEFAqS4JeT + mrIwIGYZYCsqKvWxiYIGCUizhQRvr6xMM3gErDLQdwnwzrBV5FRXN4HAsQ4i4iyBSIF/8/ksgx3We2nJ + EpAkifMCGLq7exk8+uj9ARJQSY62HlVt8IoYqQTA0dWtgQPbMpBiCCTyZn5E/LJkosTo7hJSoKwyujx+ + WCoxYKCMeqQlniLNigRkt0I/Ki7fjs9ZK/dwxolPAnFvEOgS85NPNwBQW2ufXxKYYwBAvUQqQB+DM6rR + swqQ3L5zx9PPL1jwQHNLc5fyc/58mW0u8WfMb1kAeJQI939pAPgaPzjeHxLAI498XzU0TOoHACCAxx// + Z7Vy5S8jANi0aVM/vf1kqABx//erFgRxnwalG4BRzpouQbDQu48l2lR+UptKTyQu24xa/qNUVc8wQvWC + no7KEHfBuI8qOWS6UnNJ/VAlXgl+ttAUtaRtuVw+klpZwsC2vLZK5M005LwvDE0WGhF3nlMArTolJmcU + ufVJTTwpUkWqGIxgp0jQcyV1NiI/BKSQAoOILoOWpGcJWQ0JWSqBnpok4u5jj4e2KQA08tqgi76BzSOT + Z0kBD4bt3T19quVIq+rs6mbQAcB0dXcrGrQEKB18jTyBKtSYjq5WljD4XfPGbhGa0ls8iakWvENrfgZ9 + vuI6AiEH5uT5esoYEFUk2RWz+JRkEqpCEdgLxxetMRgPjW88SmMbwBlnqD/74z/liFrr+IK5Pj8ibADF + QCCdC4AoAnTD7sbG50kCePDg4UNiKIoDgTjiz5qlz1ovCwD/SAPwS+Aqt976F2rUqJHc+XV1Veqxx/4v + A4AuC150A2KBERAAMH78BEwuojZs2FDWXefrvJPhEYg6v6C5Iaz4g3K1KQMA1PXdxP1aaveq8PwmNWxy + UvUeIM789lhVc3QcF7HIh1kVCYjm3uBiEOdhP4jE2kLBWLXDSOXQ6bNhURx01BBlXVPAghOWABBZIZwC + BzthH8R2xCcANFg9AZEkNFGDs2ttGsQNCSMRzX3ICUEkeVQQGCTZPqEDvpLs+cDgzavq6mpVU1tPx1US + oIQseYDe8Om7egACOtYWoNjTnVEIYtOAaCzmxigJgu/pJaCAQRRp5DQ2u0jSaD/WrVrbjrHdIihgfw9H + kLa2tVI/411SLIm0HTuiuglctEShwRPvlzf9Expi5eCiMIzCrYsFPhWHAgd5AYoC+/6KhVwt+0GJec5j + K1CBsodbuViNkMbCtDOmqL/80y8ZVTRSYQrWmEQgUNjS3Jx/eclSAYBAvAAHDh1c/MLC+Q/u3rPHzQUo + p/fnVVHczxji77O2xRsBP//5z/8DcYevQeyEu2/ixEnc4QAARPu5E4OIKAsVYNWqX3LtfRQEWbt2bdnS + X+9HBSj3P5fAJmJASebAEMVxAUA+VN00IA9W71KdU3apsZNqVLKtTqV2jFdVLQ26mESQ8350GAKB9KHM + KxAFs6hIItDJRVZqtMWVovkIZCyad7Gt0HnDOXlh25e2AfCcebl8NJkowK+3p1fPzmTuz/0TzYQTDWf2 + SOCcHLt2czoUHrMl07tUECMA4SszN2Jt3XBVU1dDkgVi3TUYARDAkevrUyQxGhAsYJ49OpfGEeZbgITC + tokuPGMYSUpQcwBGsIkCvDAPBapP4ck6OqGSkOqSI+DIZ1Rn5zF1uOmoOnjoKM88lUrmCFg6VcvRI6qp + qZntJHDn4j3aj7Wp9s5OZl4JiR7EfXLZ6M1lYmSZkARSN9s3gnzUN6K6MUGbbyf9rlSplGCPQZbMKpAO + PE199X//mQHdvEiDNgCwBNDS3JJfhpJgfb2CRrA6hc0tLSsWLF70/fe2bztg4gDKcf6C6i/y96lSACgf + CEQA8CDd56sAgM9//n8qhATjwREJ+JOf/IglAHtuQAEAFAUFAEybdpa65ppr1Jo1a2JTgd1tcQk/cUVA + 4/7Hc4ITjx07Vg2rr1dHWlpU29Gj/WZiiQMA/iW9GgTVlNyvDgx7T42fUK+G5RpU5aEGFbZVseFNZ49F + juaIgyO/vbKqqqh22OqP3CMMo+0MEDY4hVZGWrGGdJEpSfaaBBY5AUUYH9q7oa8DMR46ZWCs5wWrz3EM + jtUeEVManaXqBIvQABLt3sypwOjkgfF/ZXN9xn+f1LP8hHp6rlSiwOpJjrmxmTsARlICkjoChuqqCtM/ + SVY3Ro6sUTU11QR8aXqGUM/jwjH0mKClhkhAR2bmeIp0EGbSTN2GcaHfVeanCZjA8+poazsBAqkaHSgH + DDtQF6knLWrfPhoLbR00PmCb0O5YlIjv6OxSNch3IWkIUklLawuPba5WlEwZz1GW3yth+oELQBnpJpCk + rygPpGjmAwCcQ/TwFQIAAW5rbJcEAtFYRT0AyQWADQAAkDzc3LRiwYuLHtq+c8ehQtHaOZDOnzFLr0X8 + GVWc5yneYHvLLbc8RIPhKwCAm2++VaEwCDoa2YCYAdidHFQG009/+oh6881X1UUXXazmzJmjVq9eXeRy + cRF7MQZC33rcrMFC3HCzjRgxggbVSDbIQUQEl9hPHzljgiuKxB4UrcCqyG3159AcsTfsVa2pQ6p6eFLV + Foap5LFqVejROrBtwnUBCVIAYgbES1CIrNxC41YNfwsc7PJlSpU+G4ObIX6+Zj5fXI+I33KFmQYpAG5F + OydisM0NT5b75o34XSLFGK6Ib4F9fL+wGAANAoYaAArn6ddQfh1eEBhoETWZDlSaAKG2Ok3cv5LoPMUE + WVub5mpTlaSepNI1JH3Uq6rKCt5XgOckrKD7polAA/aGAHehWnV2G2ZAIJE0RUjZ4BpqIOzLwnYhfZVX + xzq6VPORDtXe3qd6CDAL2Q7V3HxA7TvQoppaOuj9AAiksrQf4QjXg4ebGMg4AKwvo461H2NAKGgfjEmN + Vlz9eNrUqerPbvtTHeMQGLtNUQKIbAAkAUgugAAAxMFU4549i55fOP/hg4cOtVmEr1R/K7+t8/dai038 + UUJQOQD4Lj3cX+Mj3XDDF9Vpp03mj1pbW811/0aPBgB8sWR6cCzYt3btGwwAs2fPVitXrtTWXYfwyxH7 + 8Vj+tb4bsuENhspRo1C6vCoisozxp+/bt0+1HTmirfTJpAUBpvCEEF8JQITMAfKcJpvRM/9mAv2RbU+C + RJiJS5D14QQ/EwZ3Ie69LR2/37u5IOBIAjaxF0OMVT8AEPUBcQ+okejkor+vZicnlZQ6t14hqh5kxOVI + ZTFHYh9cnfmcnmId4n8qpTk8T/zJYIF4C1KraElAajDZggH3cTVJebVq+PA0g0qYSNFx1ay2kLBKagvK + edE3gErXBxAKCDySHJ8BCaO7N+SgLUwFV5kOWcHJZHR1YdhGklJMJtAZhUh/783k+RioPkeOtqmDB1tU + a5s2giaTxDBa96kDBwEQHSqfpftVFVRtTVJdcenlpgx6JAfamXmYGixobmoqLH9pWb6vx4QChxwKnCDO + /8ILCxf8kFSBDqVibQCusQ+E32N+xfJvnxsvAXzhC1/4Fn2cO7H+O7/zWYVZgnt7c9TR1STmP0qENlFd + f/0XjC5VLLj405/+WK1bt0pdfvnl6txzzz0lACCDH+vDhg0jMBrNRJ80hC1gBEPSgQMH+LfXJAWBK1dX + ptk3HwoSS0cERtuTCjvGeJciDgMwgH6dhetMqnXGAYBpFRwoVFliCxAiFn95aYy+JU0Yo1ZkGLS288jx + AIAQvGvlLhh1oa+7u0Tt+HW3IBBJx0xTZt4/IQVjURpNIvaU9p/r/ZJjLKm4dsn4AhOUVGzCOUkCgRDG + yjDPRksABQgXEuywuqQaPqyagAT5HiiFBpDXM0HV1aRUdW0NSxO4fDIFb0qaRP0kgaeW6RGg1IuYi4wu + Fc7TyCW0cTE08QvanVlUAbJ038OHW9R7770XBTvFAEDYdLgpv2LpslxfVBBE1wPYtmP7/BcWLfwhqTGd + qj8A2AY/0fd7VH/id5PGBwcAn/70HxAAnM3+4mHDatS///v/IwCYQABwS1QTUIgO04OvXv26uvrqa9S0 + adPUqlWrYlWA4sDobwOIC/mV7bBMQ8wfPnx4ZGOQX4j8SEM+Qhwfx4Pro0x5NxHAwYMHOTS4upr0zqo0 + f3ixqmOgmOhdY2XXRj4YwmBBh1ktV9BuMKlyLFw3sDq0YIJkQPjgRAAmIWZRlZTlHShRaez3tEZHiS3A + kgKUBxzsY6Sxy5FAkCP+PHaYX3ezVafABsMwjABBGXDgvja/XEQkmYjGCJ8PtcOu4ae0KxXvCm8OPBqh + uS7PM4ApxWBshBqS0nkeoqKl4MUhKaOyKsnfr6oqzdWwkAiXrlCsXrBkCBCi4xDVmSKggBSRzaaYsSAp + jsejsRUUghTniyAorqi+W75NSwJoOtRUYAAQN6BWAYJ3Nr/79ILFi/61rb29W8UTv4j9PdZSYvSzuj36 + Dt72R3/0R98i8flOdPR1112vzjjjbOb2w4fXEJH/mwGAz0dxAOhgWHIxO/DGjW+xAXAq6T1vvvmmDjc9 + Qcu/rd9jHRx1zJgxLO7LddnlY0JcQeDt7e38P9SBcePG8TnYB1DQ+1GlqFfV0TVGjhhBEgGLjHlNjEDy + IES1Y+is8GWzqymXLwlo0oacQlTsR8u1+ajwZF6mqObBGyhJAZEIwEj8lwEemIkyjD/bvHCp7m1zfNdl + KM9gfvP2/0r09pzOSvwQAUBBqRLbCBtAGYiDaOHvLPq76VORqoSwS+KANJroa0s/mjkJdRcW7Rq6UrLx + qhiSApcHMESFngJjKEroAqZpRHSm9LZQvi/AviLBpfE5B6Wgp5iH7aKKmFVPT0HtbjxsFZ4pflaznocE + 0Hy4mVQAdgPi6+YJREJS37rXrFvzb0tXLH+emFif6k/84MJi5ANACOfHklWl3oF+38Hbrr322i9NmDDh + HxHZddVV/01Nnz6LB8+IEbVq3rwneKrw3/3dm5noRbQ7dqxVPf30U2rz5rfVpz71KSa+devWxc4JYK/7 + tskAh3iPlF382qK+zDvY1tbGXB8cHpIBCB8AUcNhl1oqACi88847aseOHerwocOqk46n+3SSDtlBkkRu + 9KiGfGVVZWLYsPp0TXVNin5TCZIB6Q99c7Yts4UrbTg6wmrzDAy5SEfnyOGsjq7jsuAGvPRMsdpgJ5JF + loNgCuyykmSphAGASE8PZOJMmdyi6HEIokFfVENMp+m4gaA0VDcwgxzGwLwlXXzQrQQA5FeA3bx/whC/ + gGVC1k0/6MCqoms1GtiW4VX6T9SFghV7EblkzbNgHyz++Uha0pOgiuphB3iFRjURqT4nU6jrQ3g/R3iS + 6BBywFUJAJTU9zc2ALX8JVYBon2dnZ27V7z2y4fXvLV2c4atqF6xv0f15/y2xd/rA48dB6S/33bJJZc8 + QjdXn/jE1er88y8iFaCHCH+Y+vnPnyIgGEcAcJNJ9AnYzdTWdlQtWvQLEnXeZQCANX7jxo0lEsBg3IDK + DFZY0kH4EPU5ySb6iCGHnILwwdWxDsIH4EA6kPtJSi0stps3b+bEJLxPa2trLwHBpsOHD++h+9AYCitI + SiAhIJ0YMWJkRX39sMT48ROGjxw5YtS4ceNH1NbWJSoY2UOWGmpqoVLUkEhYyYAAoxXABhZh+K8jrgUA + YOLWGYgyVwFAoquzixN0uru7+PlZkjJcmusHkGoFcNWhtdkovDaqP6is/pI+LYk2DEut/uZY3DNnnkUI + sOxA+DUAQJGQimMhMMAXEb1JrS5RCSywiN7b9SjZ25UBDGfc2cSP/b3U5z3ETEQii8CZ6/nprMsgTBj1 + rdR7xAVWxT2sdK1BxCPgWB0FWJwXwHLncVfAC9BEzGm5VgF4jioCjMyBgwdfefnVV57atn3bwbwWh31u + vq7jJf6y3/1jH/vYn8yePfvHGKC/9VtXqRkzLqAB2UNEPZy4/E8NANwYBVS0th4lbtytFi78hdq5cxsk + CAYARAK6ABAHBNKJ6GCcC+KX0EmRIkAo0O2PchZcL+v2IHocnzZuNzE67t+/X23dupUBABICEX/3zp07 + N2zfvn1jR0cHOgwpjnAZSOQNOjZFqss0ev+z6NqVMviw5PMSOhtwGjD2JbWPuIvW2wiESKKoDElKSYwe + NSpZV1+XbBg9OkXSCC8EYgCSkM4JKlKpUGcR6sHHbjqOndcAgWpEAAtINfjNEMDC3qJDc7PsTmP3Xq8O + 8slwQlCOz2VVxVIlJHIuNHPh4TyWVIQgCsoatKpUorC+ma2anDQAsFzIEcFaapGoRkUXngUAFsH7sk1L + chAcO5R7rBgjcRwKvKAPxb4kFaXYkErfAd8+ZYWW+8Zyad9pf38iUSxwYLv/zP8FGnfB/r37CiuWvYx0 + YOj/+e6u7t3rNqx/YvW6Netp3Hc5xG8b+7CvWxVBYUDiHwgAbpgzZ848FLKYPfsyNWvWxcyNiCuqZ5/9 + D+ocAMDnGAC6u1HMop315UWLniUA2M4AAK4Mw8dA9QDRGQnjNsMi4r4cg48BYoe4D4t+lo141Szmg/gr + TQUf3AccHuAAXX/Xrl0g/AJJCvTvwfeI679G+1BQoZqWGloqDfGT6D9szNixY8dMnz59yrRp0yYmLB0T + HBP3x4Lrox/oN0/A0rRnz56dTU1Nu+kd0Ol0WiKg5wlGE+HTNZNjxoxN19bVVdTX1aWqSCFME0DQ4Akr + SdqoIpWjYcyYCpJw0gQ2FbU1tVUkRaSqq6qSABFIJASGAUkYQplM7HBDog84/r6rm0GglwFC+/tznFas + k6AgSQAwuDxaVrsCkSIMgMGxIjVEee3mm7iTs4oEYYvZ/sE+uBbZAKzrRqJ1ZPCT+QI0AIcCBkHRpx8R + YBhGxO56VmyPi+3xcUFBjLOYnw/G24kTJ2ojXiHPTAl91nT4MIvzlVZMv29M29v1+EZ/mnB0mUBW7zMe + 0nyBxl7YuHt3btnipRwJmMvlOxr3NC54feWvFu9ubDzcByt8kfjF2Ndtli5VGuY7IPEPBADXzZ07dyEI + +8ILZ6uLLprL6Ddq1Aj1/PM/J5F3hPq937uJc9GPHDnE54BQX3zxOdXYuJuNgPgf/vc4wpc0XdHb2WUm + BjFj2APBQcwHJ8Q2qAPjx4/XlXRkYKB+H+2Hfg9XC/LhQSgtLS0k+W9eTKL+XiIIdBhGDL5cFAhAYDPm + E5/4xKWXXXbZhQQoCQ5OSSYjoyKuC+kB18TS3t6ep/tsJsliPa03m4+RtMe0tbi12Ur6HhJBQ0ND5ciR + o6rq6mrTpGrUENGn8Rz0U0nbpo4cMXJCqiIVAOwg5UDi4b5KV/LsS+izquoqHVSTTEQfNWskBOiyWSMV + ABBQsajXAAaADJIASxB0PL4vz6VA7625XR/v68X/eZ18xLaHoquiSMRiZXcGfz8pT6kScT/yYthEaon4 + oTH4sThuVBsBAFeytKUIm8BtEIjubR9jeZGwHanSuPbECRM48zLkGIE0A8B+Gs8yZm139EAgIJKktg1J + T0SRgET/+cL5558f7mlszC2evyhP3yjb3ta2afVba+dt2LRxi7H+i7HP5voi+ovBL4rye78AcC0BwOJj + x44Fs2ZdRAAwm8VPDL4FC54mAqxUV1zxKZ1jnssaLwAkgOfUgQP71VVXXcWcc5/pMJ8rD4MaYha4vR2a + iv0gNnB7EJ8QPhacI8eCUAEQu3fv5gWcH89Az7yfOPOvCAx+1QfDBYn1qrQ+boaIafQnP/nJ36I2mzh/ + HRf9pOthAYHgvvhFEBEKm+I+9Hvw1VdffeHAgQNbVLEQtk3cEmUVqFLLqxswaE3NGc3KF83OR6B0Bj3X + 79D7TuTcfuoPPJ88YwUXLU1EIAgbhPQH+gfFWGpogI5uaNABUjW1CjaM+vo6Y8RMRcyRo/ayuvSZlioy + LFHkjNSVYzWjj/+HGsKAgJgKFBshcMS37+3pjSIupYSZeG4k+aWYEl0ahhzYAGAtoSlUIgDAAAepTOw7 + YhewpIfIpSoqjCv2O5KA7YlBE30fBmP0BYEzc3uWTqnfAIxNxIzQ/zYAuO8VE8dSMFJlYAKnJCi7YPqr + MHPmzMTePXtyC557IdPW2rZ/247tL65Zt/bNPfv2NtN+8ecL4XeWIf6Bk14GAgB6mJmkAqwkFSB97rkf + IwCYw1wCWYELFz7LADB37mWW0SPkwbB48Xzi2E2sAoCAoX/bHYIPig4E4YOblYaRaq4Djg+CE5AAxxfC + F5THQCTOzpZ93MeI5S1E+C8Th17XrfNPK4SoTAfhI9D7nDvt1ltv/T0S9cfiWnrSk3Q0qEH0htsz8ZP6 + cPitt95a8u67766iwd9h9ZtdXSXvrLuFGO0m1JCwgISvSarD+X/4h3/4FSKkGikkai/iVYi8C4ViHL/0 + b9KE1nIiVBCYGP2w6A+HT5sAAdWQScJQY8eMZQMm4vFR0KS+rpYrIUX+eDNcdY1CbX+Qb8XBUaZ2IUsO + UDOIKUAC4cpDrKZ0RWocCAvfNsvqh8bKQD+4qZRTKIr9lvgvklkoxkBLLSjh/jazsQndcjW6hkEhUnHP + 4rsDzDA+k6YaNKJH8T7wHsHgCwBgqvbUCPCouAVz/UD+10cbAEB2D22aNWtWSBJG7pmf/bz1vW3bXnlr + 44ZXduzaua8LD1N063WYBQDQ/X6IvywAnEftkksuWU33rpw+/VxWAzAAEHW3ePHz9DJpNWfOpSU+enCR + JUvmq7a2VlYBQDwgZh7pRseHfo/Os9FbLPp4T6zjOKAvJAOs84c3kgGuCd0evyBS+iidJGWspf93Hjly + ZDcNriMewu+bMGHC5M985jOXz5gxY/LUqVPHIYJQc88U3xMfV2wMsB/Qb4EkiNUbN258k0BlPQEDrptU + pSmW4oKRbfavAIJ8aZEGQutXJAA8SxX12f+4/PLLb6BnGiHEL4Qulnshdnex97nrLnBIS3DQSsg1A+Qb + RlF1xv2F/fCuoCLU6IbRBBZj9DesqmbVAwaxaLorQxBsc8gVmPhhr9B5CLqwCURg9noASHq1YZNVD96u + 1ZKMUT3wKxKFxJrwM7IklNDAZoheACGQJKvAqsFgjomMhoVCCSjIdrEBAKC6aEkaAJW+kW8CVQzj0pdd + 6jM0guBDU+FUiD8ISnOQSaIrEEMK9jTuaf/pE0+++6uVby7e+t7W7QRGHYWiyN9pFlSPtUEh1s9/wgBA + Lzj6s5/97HZ68PqpU6epCy74OKP/6NEj1UsvLeIc7Y9//JISAEAHLV26kAnziiuuYOJHGW0QmXBZ8eWj + s8ERgLbguPjQdnQfpAQxDuIeIHiI+Xv37uUPRPuyBBjbNmzYsIjusVtpLppURe6KB+ujjzWSRP25n/70 + py+dMmVKrQ7Y0MU/hfDB9eFZAOFDjSDC37B69epf0P3eNh0vVd5s14u9bgNC1jo2Z/rY1suk36M4FXrv + qrvvvvt7RGh/gHcTYncXW7z2Ebu75HI57zFx58iAtu8v4M2pwQkrSk+pEh1YQHvixNN4WrjRo0cxUMBO + ocueVUQcO0JErmWgXZ+IicibYq3617hEczqPIWsAQTweYuTUdo4c26JkOEtwjoo8pkWfPSQK2zsQivXf + KuCSM/eLntP0T5brKiZYMpDx6QOAODCweL9JD4kKgvDYJ0m3b+2aNZu+/9D3l7/zzttbW9va2kkyECNf + p7OIxd8ebycPAIhoR37uc5/bSS9cf8YZU0kCuJg7Bh926dIXOZHi4ovnOhJAlvYtZq8AcgEQhw/OLvor + AECID9wexIZr4n+k7gJZbR++6GMoK0ZcmAnVfIiuLVu2vNDY2LjWEGhKFcXovOmY1G//9m9/4vd///ev + OO200+pxD5EoxLgoBj6oKShfTiDTRCrFi2vXrl1IA63DEKhdQklcL1lrcQFBPoSAgoCRSAEyrqK+//rX + v34P6fxfxTPJgJBfOxJyML82x7SlBpvoBRh8UkUuKpbaHxzirmerIP2fXws8EoEHNQM2CljYIYVBuqgl + gqqvM4FekPhSSWU3O8VZUpYlMlPnOeQj0IDqIam7OZMABfdoDxs4s1zizSjdKqrrmNBpzFzXDR9dIjIt + 4pV3jFSsMh4t33axd5IgwCmAdhgG/sPYp/c/MO9n85b84AffX0l0c8wifhH58SucX3z9NrM5eSoAEUwd + AcBGIsTJKO5xwQUaAIDyL7+8hD8s1AJXAsA+VKch9YG5NQgYxCcGK45GM8UlRZfCQOACGkaUk7Bd6Pic + xdfWxseLGkHH5mhbNwHIQdq/nSSIZiLmoyRRHB0zZkzd2WefPemyyy6bSctZEjkohC+iPiQKSCf4JY6/ + k7j9m/S7gq65VxU5vltFRbKsMqoUAGzx37YD2KK/fPASCy2J/Vfdfvvt86h/hnFJLqPquIYkCUO2iSIw + 3MoGCRsQbGK1B7FrO4iTEGygsNdtsPABRs6EHGdN0JH82s8SZzEX9zji7+Fyxnx5IwgwGkY3sGQIsACI + sERJUkUQuucXLOmlYGI3HNuJKZTCHpA+beAUjwjqG6L7UOpMAqkilUgVJQIGCo/XI4zxhIgqYOcwyCOD + PggAekkCXXvfffcteGXFK/sJ1MS112EtEuYr406pUgnguCWBcgCQJgB4g4jnQpT3uuCCi/jFx4xpUMuX + L+NTERsgFVFEAli2bDF/7AsvvJADcaAOgPh14Yl8JEJB1BdVQDg+uDEIHjo+RHIBCoAEzhHfP4BDAoSg + PuBY4uI5etbu66+/Pk0glcKxxbBdbXjC9QEmUCUgUdC9NmzatGkhdHx65larP+wMKh8AuCK/dLqLxC7B + lyTpkdh/2dy5c5cQeFXbQOrLfvTtcwe+CxBxgOCK8K59oBxASO6HrNtAYC/2dgGAnCkaKjEM9rGuhGG/ + vwsO+tp5UyyVpAoaE9POnMZSBQybw4aNUKMIPBC0BiBhr0kQKmVV7I2mZy8UpZNiirVOXYZhLpuVwql9 + DCZgbrgvmIg2fPZGzy1RgfmCfCtNYua7FXwRr8SY8mCAfX2Z3U8//YvFDz744Bq6ly32t6uixV8MfsL5 + 7ZyAnLMMCgTKAUBw4403LiECugYFPi++eDa/KADglVeWc6fNnHmhhYYBW4dXrFjKLzhjxgwWrdFx8rIS + tScRe+K6ArfABCLw4/NEF2ZwJDgbq4qJXofcpvotFWYeP9wHwDBr1iwGCpyHa4DwxZ23fft2BhiSLI5u + 2LDhia1bt75CzyrKoy3muwBg6/mu3iU51nHzsinlED7+zJs3r5Z05Nfo+WbGiZOuRblccVX71z5O1uNK + VtngYovu7rm2UdKVEoR4hdjlf5+UIN9WyoyLZ8CVMOxfNB9QyKIjJLVkp9VMY5iM7BXauNnQMEZNmDCB + x+DIUaPU6FENBBZ1nBmK4rfazRqWfqlARUCh/faqBDh4bqCCia7Ma9tBZLPgd8zws7GEkcsWxO8AAyN9 + /wKN7QId10xq5xsPPfTQL99+++0mVdTzXc5vE75d2MM1PA8aBMqGbn3xi1/8d0Kom7F+3nkf4w6Err5i + xTLOr545c5Y1gEImsjfffI0J98wzz2QRO2NKcoMgAQAg5pSxruLjQ8wHR8axZrDk6JwEzhMCF9sBriPb + ZB2/2A/VBAs+MO6DDhdXHmwNCAmm+3SQWrIC9oPW1ta95jXzqrRckk30NijYYr4QvdvRceK+CwJq0aJF + f0ec/644oi8HCj4AKB+K2v+6cZWVJALSBgF3vUh42RKidO0IQriumuAeGwUcOWDgAoO7bgOBHI9riY7u + 1kkol3imTJFP/A9GMm78eFY7wPxGkDRRW1PbU19X31NdU52mcZdM6CIFpsKPmVnGVJcIrBvYfSdh82IX + wVgnibR51apVax999NE3Vq5cuZfeQwjf1fldSdNmMgIGYntyK/+cGABMmjTpwuuuu24JdewovBMm/Lz0 + 0kvVxo0bGNkACqICIDClvb1NrV6tC4CcdtppLG6HJgkiZYpj4Ffy8rEANHAMEeTbcOcRRwQCjiNinktg + MZWOD8RdZ3N9CdrB/4zopFJMmTKFA5UkX0DyABobG7du3rx5Gen7awgU9lmdJeK8CwC2ju+z7LtcvqSw + g/Jzfpv4z6Q+gAGz3kfwcYTt21cuCs2Nv4g71i7Y4uqw9kD2gUKc8bAcWPikCLSsiUq0JQRXzYizSbjA + YT+DNFf9cQ13vv6ThcZZ4aWXXlpCUuR6pb1NBSSOXXbZZaPOPuecETTeh40eNbpm1MhRdVXVVQjkrKis + TNNQrUgBJNKVtQE8IclkgkglyPf19fQ1Nu45MP+F59984onHNxFjOqqKHF/cfF3OWIyTMn0lwEtq/50Q + AKBdddVVt0yfPv0JEq9CfBQCBUZqTBk2Y8a5EQpjELW0NKsNG9YzUYIbgwNzmWzDwUH48AxIIo9xBe7d + v3//clIBfkXX7zWdm6NOT5OINJmWi4m459D5NWIkFADAOsR9GIoAAKhAhOsiHBgqBeL0af1pApY36OO3 + yThQ/XV7n3U/mj3FQ/R2kI/P8lq2059++ulb6P2esonTJcyBRP3BSAn29e1tQvB2vkMcEPWrNmStuzYE + W1Xw2RRKshCdba6bU67Va5KdXPuCTeguKNig4XsOVy2y/3dtKbKO8UZSatOTTz6J+TLEvSsHlqT1Wut5 + 6d/JZ0ypHlZfn5ow8bQqAoRMc1NTR+OePW379+2Fji8x/SB84foS4eeK9D4AyFnbfapqbBtU9gZJAfdN + nTr1G71mqm28EER5xAfA1yvx+LCob9y4njsLBAmCF8s/RHFJ3TXBP81EpPOION+idbywBO/YHck6DxH5 + aXSfWbTMoPXpBCgVUhMAlmFwfkgceCaUIKP7ZAhUlpCo/xQ9AxIVkqrUgCcEn3EWu5Syrdu7s67E6fe+ + //s1AoD7qA++8X64/mA4v23BlhYVJPHsdzPqfK4tVxKwXZBCuDJXhEt8st++jpwn22z1wd6fkRwFi7Bt + ALCNkzYIyPZ+xVNUf8Opvb0foWj1qPDYY4/9M3HrnaqY/1GuibvXnZrbrduHRQBAiF/GpK3zDwYAfDMA + xbaBXoA9H6RT11599dXfI1H7JuqIkfKR0CnwX2IBV4bID8t/Shs4mOixjSer1CJaF23bQmL+FhL/XyNE + 3aN0Rl44wHPwy9D9UlVVVZOI6OcQEDQQEDSQyD9x7NixI4j4AwKT/fRx3iSx/2W69tuqSIzSEbYV1SZ6 + m+PbLhVfZ/t0ezfWP7Y988wzGDi/pGVuv0w05QcAe3u5EuvlwEIi6ey6iW6hlnKFW+zmC1JyJQEBAZvr + o7nxAi4wuHEFrroh0oB4EnxBT3EGRduXb2chuv3s63s02LEWLlw4f8GCBfPMuFWqGNEZ0YtDW+64EAK1 + 6/SLBCARf7al3zflV0H5JVIfAGRUmTYYCSB6KRL/z77yyivvq6mpucFFVnuwgcPAkGIs7hh0BSL6V4gj + P066Popw4KXB8ZODuH/J2FNF5EzSvSroXpUEQFMIgIaTBLKapIlDqhhi6wvisQneF747WKI/oUbcfzI9 + 92ZaKgcj8pcT+8sZAUOJrTfNDl5xRX4bDFyAkV+f+G+v+6IUbQu+HGtfV7YJIdv3FwK3z3MlD7EZ2EBg + qxWuh8IGAgFEG3jLrWMBY9u1a9fG++6777sGoHz0UxL652yzubRIoHZQT7ngnjggsK/pFgsRWoltg03g + LuFw11577V3Tp0//OnVopQCBO/hg8IM00NjYuID0/mcIDNbneSI3jtobfOJ4fLNfXji5AIqLgu66PUNq + ORF/UEa942nPP//85dRvy0M99W3UX9zJA+j7g/EECBi7Rr84zm8TQZwKUNLpMR6BuCAjn2/fnalZOLsQ + pagofU4ugAsE/KEtg6HPPekCgw0ENqFLP8SBowAAqZeN3/jGN/6mt5erdoodwB0vNr2448glUtv2lFGl + BO1y/OMBALtuQGw7HgCIvhn+zJgx4+LTTz/9NpIKbqDBNUY+GhrqlpG+tnXNmjWPvPvuuy8YwkeFj4FE + /RNpLsHaRjufXu92kvJ0rlInieO77ZVXXvkMSUHzo44dBGd31QTfPtkmx5Xj/u4g9w1633XjvADyG5eM + ZOv1aClnolZxBdoGZRwjGYRxIOBKBK40EBfubMcquERu94Udli5ZrKRa7v2rv/qrO+i5ILJLYpdPQvRF + gSpVqma6hmbbpecypnISqg8AbKk3th0PJw6cX/6iI0eOnEx6+AWkg0+kf0dRx3ZTJ20kPXwzfVT4MmtU + qZ50KpprZHEnRnSB4ZSK+eXaG2+8cd2RI0cW2oNvIK5/vK4/O7oSLY7gXUlgMNd3ib9c1KCt39uzSKed + ajpi8YeRT64n3iPbG2DbBXzPIr9u+LEPjFyAEOK3+8yuOi3PQ+N62x133PHNPp6/OwIAH/NwubeMz7i0 + cXvM+gjeXS9nAxDmd9JUAPccGwxynv0wkEjlHZf4TyYQuOjqErctSvkCKE4pt/e1J5988tMNDQ0LMNjj + RP84o5y9fyDQ8Fn64wDAFoMHsi2UMwD6fPsuAKBJLr1cT5pUcpLtksCFBo+SJEvZz+E+k/2/ayj0SQV2 + QJGkFKNF6cWWBIDnXr9+/av33HPPA3SuiLxi5S+nq/t0eVcSLcfxfeqAm2iWc65nqxWx7UQBwF4Xg5v8 + hp7t7vEnqw0kerlimLvuu94pbT/4wQ+unj59+lJxh8YRc5w+Hmelt4nbJv5yAGCLvi7ouM8TZ8n3hef6 + MgltAICB2JUq8D9AESAg29BAdLAn4TqSz2F7DOTYODAQ1cCNF5B9rk0gDgCwIGb/Jz/5ybyf/exnjyot + 2cqYcSVQN24kF7MvThJw95WTCFzp1o0FcBl0STtRYowjapv4g5hjT3bzAYC9HmeM8Z1/ytsDDzxwxtSp + UzcRZ6uJUwN8AOCuo7k2AVtslWYXXnE5vfxfUlrLo05EHeUxxPnEfV86sVj00QAAts1ICBqEioIsQoxC + 4JLbgeNEEvB5CMqBgC+E2JfJaPejbReAHQUh5j/84Q//dfHixS8oLeW6erjPgOe6lcuJ/z7pwAciBc89 + XO4vv+8/EGiAFsT8+q5/qgHA/f+Eg3VOVbv//vvDCRMmLBs3btyV4Hhx3N5n+CtnBBRLfxyQlNP3ff9z + Jzm+cjeYxkf0cTYA2yUo2Zw+qz5CuKHv28FCnPFH5yDQS66F3BGRogajDtjSiS+l2ZZifAAAACLpI/u3 + f/u3f71nzx7kkQDBXN0+jsDjiH4gYPAR+UAg4xq8318o8CDbQFw+LijiZN3bd103QOcDI3q3/cu//Mtd + F1100d8hRgLNBYDjEf/tX1+tep+F35YSXGnAXfdFxXFneoJ/XGMbmusGBOcGMQtHd68PDo9Qcfs+EryD + PA/bRSjJZnKc/VwD/e/mFdhuQukjAVSsA3w2bty4/U5qJhRYxpSP+9sE6nPPuccWPPsGAgMfeLgSwIBj + /lRw5FNp7T/e9qEheruRGnATAcB/QLRFeLSPIAcbAGRvkwHrqgDudX3r9jHuffp1ahkjoAsAbmSfPadD + XHguErhcER/XA8ChJqVE8pnS72w7sM+X+9rP6j63/WwuGEi/2f5/2CEeeeSRp+bPn/9zpcX/OCu8zyWX + P47/3W1x4CA6lQTH2br/oDIB+TufigE+1Mq3733vewhjXjV37tzJGIwQe10fNNpgo/9sS3WcV6Bc9J9P + 5SgHAL7CIa404DMKyrmw7kOftputbshcELJdfgUEkGeCX7k2ws2lapT9XOUI391uuw9tt6CEta9atWoL + Afd3MLuUKnX/uZb6cgTu7nPn+fOJ8wXP//mY68TOAhzXhgDgA2rf+c53vkwD+YeonYi0aOi9PmPcYAHB + dmH5XIn2ernAn34zAsU0N+NvoHJj9nYQFSzqcSoGtiFr1Nbx7XvgPVFLUCQBLJAEkHsyGJtAOelA3IZo + eE4AFbYR8f/o9ddfRwAXrP82gflE9MFKADa3zg3yXNcG4CtDN2jJdwgAPqBGUkCaRNhlZ5555mXnnXce + h02LLxqtHEf2GQildLrvmMFE/cW5JOPaYEOB0eyEICFgJJDJfVzDIraBmEHUrgFSJAEpK2cTMSQpeBHk + ePs8WXeDiew6hbJd1A9kmuL/nTt39tx9991fpec5qIrh5q4HoJxxL1dm3XXfyXlxpeZcMPClqw+6DQHA + B9i++93vnkcD7Gdz5syZgUpGkASg1w4UCWiv24DhgofPsn8yAMAlrjhO71uXc2HQEw7uXltcgpACRCdH + c2sXyuQysg/nIY4A6gOIWN7BJ/LL/77oQpwn800SMHf/53/+549XrFjxotLBbfYDx0WgDsYm4ALAQGAQ + Fw14wsTP3/nkDOWhdqKNQOB0GnQrZ86cORaSADwDsIL71AG3cIgk+Mi+OCNeOVdfOaARYnCbLxR4MABg + nwMAkDkY4zwNMvmLPIuvTgAMijAMyrVxLIKFcK6AgI/ry//2/QE2eCbo/KZAbebxxx+/k/T/FbS7VvkD + 2WwpQCm/u84V+d0lH/MblxfgcwWeUBsCgA9B+/a3v/11GpT3EwhgTka2gkMEdqP60GzC9U2O6QvoGcjV + d7ziP1qcJwDNNfr5ioJIDYk4AMAzQJyHGmDr+j6pA/YEXM9WNaS0vM9NGGcERGwCJAqUqSPOn3/mmWfu + Xrp06TNKE79ELvkS2tyiH3Gc2sfx46SAcpGAvrD2E2pDAPAhaQQC36PBegdAYPbs2SwFgIuhxYnpAwGA + LyioXMShvX2g5iN6n2Tg1uYTa7tMr+Xq4HJtPAOMgFAD4vR2O0YAdSEBKHZhEBC/VKGSZt/Pfn48C6QJ + 9DtAZ/Xq1U8/9thjf6P0VPJ2Tosd7SrNjTdxiXYgsd/93xcKHCdlvC9X9xAAfFhdqfUAAAdvSURBVIja + fffddw0NynsnTJgwF5IALN0YjDBu+XR8O8cfrZx+79sv58aFAZdrrmjv0/Xd/ba7DWI2AoJ8Rji7QQqI + M+zZ4IN3k5mm7fRjeFfgIpSoS/scNCF8gAQMsWYG6AdoeY4kAZ5hShUncfWBgAsGbrKZy81tq70vPT0u + 4y8uc3UIAP4rNQKBM2gwvkTEfSZAYO7cuTyIoRZAL3WnTotzEbrVbuK2S3Pdf+V0f99vOb3f528H8UPc + 9rni7GcAYcI4Ggcm8r9tGLRBQCQBM5FsidSAYCQAACQtED8BzUbS+W9777333qJLDVO6ahU6wgcAdqKb + Ty0YTPZfOT3fLTevVCmxv2/ur9QQAHwo27333juJBulDNHBvOOecc3ieRei5EGdBDFKYNWXNXusStS+w + SPbH2QoGYweIi7F3JYE4UVv2yUzRdmahNHcbJCDo5b6YAPdZcIx4GCQJSQqOAARwjEQiYhsmi8F2Atd3 + H3300c/t2LHjHaWJ3yV4mXsysNZ9yW8l3aXiAaBc+O+vLZFtCAA+xO2ee+65lQbp14hTfgwlz6dNm8Yc + DsQgk5vaUWtxOv9AkoJP7y8nAch6XJXfuJBb+3/o6wAAl+u70gUaJCBw6XLqhn1tmYVaCB8L9kt9AfwP + XR8eF+L8G4jjP7dy5cp/3LVrF/z8VdIFqpToy6kAbmHQ6HVUqU0gLijIl8buS3X3tSEV4L9yu/vuu6tp + IN9OnOwOGtgTIRFcdNFFbB+ASItBDDAQsdZn3Y/zJNjH+dQCt7mE6uP6vn3udOM4DvYLSDU+APCpBFJd + 2gc2ck37WWQ7iB6gCVDA+ZgzAuoU/Z/ZunXrPzz55JP/h7ZLMoH4VYMBFh8A2OdFr6P6E3ecVd819Mn5 + 3k9xssbXEAD8hrS77rrrNBrY3yLudRsG89SpU9WVV17JU6GJywtcTaLY3DoAblrxQKK/TxWIC7H16eQ+ + AHD3gTBlm+8etioQlyVor8uvzAYtc0riPEwGCz3fzC0w79VXX/3+smXLXpMuUOXT2l0OH8Rsc8+LHlfF + c3pbvx/IsHfSk9uGAOA3rH3rW9/6HA3gr2QymY+TLps+66yzeCZmzNgEwsYAx4CHmlCctTaIQoXR4vz+ + gzUCovnce/Yxdhiwu1+OgQpg6/XlYvhhyMN7ucZEUYHQJHZfpoIHx8dM01gIOHN03DaSCL76zW9+c6H1 + WnE04HP12dsDdXwA4BPt7Xz9cka9U5bVOgQAv4HtzjvvDGmAn0vc/hoa1DfR4J7d0NAQnn766eH48eMD + 2AowNRuIBJ4DqAg2IPhqAaLFcX133Wf48/3vBgTZ+9CkMlBceK59Tzw73IGSIARAgzEPRA8uL+AHIyli + B6Ay4L3p+I10jx/TfszFuOHv//7vOzxdavvxg5h9gbUeOvvd81w1wF73cfpfO+H7HnSo/QY2EmuTS5Ys + mbNv375b9+7dewMN9DrSrZMzZswI4EacMmVKFC8PYxqIApxRquyKhBAHBmgDcWifFOAmAPnOgUFOyn/7 + 7AlS81+kCJkYVnz3OBZEjwloYM0XewhelYh+Eb3LPFqeJanp2HF2azlA8G0b6H+fMe8DI/pyDzrUfoPb + yy+/fA4Rwh/s2LHjehKX5xCXDDBlGuwFF1xwAU+iKi4yNBAWdGssMkW3zbXdNhDX92X/+WwDQvAgZHBy + d8YeNACQzCotBTnw3OLOw5Ty0OslX8BkGe4yhP/IXXfdteYUdHEwyO2DAQBvF5+CZz6hFxpqv8GNiCK1 + du3aa4lAPkmcfiqJxFOJM55DRFIzduxYBU8CQmdhhYceLnozCA1EJpVx7Om6feWzBsoClGYnFtmLzPCM + JvUMJO5fwAkqDNQXEDmiIkHwsAXQPnD1Rjqnkc55jxbo9a/de++9x8vtj7edbJr5QKtWDQHAR6ARAaV3 + 7do1jrjmpQQKc7Zs2XINEdBZtKsKhI8FojXy6ydOnMhSAtZhpce6cGG7ku+JNCFsARVwc7FPYLEJHPq+ + PRtwXs8n+Q49wyoi9lX0u4RA5MC3v/3t3vf1UO+/uTUp42jqQ1mebggAPoKNiKxy/fr1k4kAZxEgzCSV + YTZtPpeIbiQRXTW4M/RzgIKI3zDYSZitBNRgsesQ4hgR6SXqTvR0CcgBwUt9f7vEt1OPr4+IvI2WdbQg + LHcL/a6me2y+//77+97Xyw+1kjYEAEMNobYJIr7adevWjSWV4QJaP3PTpk3jiCtPJc57Ji0NRLxpIuQk + ETQ8EDg+RBMil8k5xcMAkEATYyJx/Rx0evo/R0uWjsvTgt+9tGCa+H30u5P2baFlO/2/48EHH2z/oPvm + v3obAoChFtsIGDA+aogwUyQdVJJoPpyIE1VxEC6bIoLnIhnAATo2SUsV7Q+Ig+cnTZrUge24Dv2fXb58 + eeeqVasKtbW1XfR/Bx2G4ppd+H344Yc/aDH+I9uGAGCoDbWPcBsCgKE21D7CbQgAhtpQ+wi3IQAYakPt + I9yGAGCoDbWPcBsCgKE21D7CbQgAhtpQ+wi3IQAYakPtI9z+P7mxIoD8Hq/OAAAAAElFTkSuQmCCKAAA + ADAAAABgAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACxsbEFu7u7HLOzs1WlpaWAsbGx + j7Kyspa0tLSZq6url42NjZKCgoKCeXl5XHJyciOBgYEHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjY2NGqioqHW8vLzRzc3N + /9XV1f/f39//5eXl/+Xl5f/h4eH/3Nzc/93d3f/e3t7/09PT/8DAwP+hoaHgjIyMh5aWliIAAAAAAAAA + AAAAAAAAAAAAAAAAAgAAAAIAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACPj49nt7e3 + 6tTU1P/X19f/29vb/9zc3P/b29v/2tra/9bW1v/R0dH/ycnJ/8zMzP/f39//2dnZ/8LCwv+/v7//ycnJ + /62trfljY2OGNTU1DwAAAAAAAAAWAAAAGQAAABcAAAANAAAABAAAAAIAAAABAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AKKioqbKysr/0NDQ/8vLy//Ly8v/0NDQ/9fX1//a2tr/29vb/9ra2v/U1NT/y8vL/9LS0v/k5OT/zc3N + /7Kysv/ExMT/yMjI/7m5uf/ExMT/fn5+yA0NDT0AAAAxAAAAPQAAADIAAAAiAAAAEwAAAAgAAAAEAAAA + AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAnZ2dhcXFxf/ExMT/wcHB/8fHx//MzMz/0NDQ/9fX1//c3Nz/3d3d/9zc3P/U1NT/yMjI + /9PT0//e3t7/wcHB/8LCwv/Kysr/tbW1/6ysrP+srKz/wsLC/25ubsgAAABIAAAASwAAAEAAAAAyAAAA + JAAAABUAAAALAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAtra27r29vf+9vb3/wcHB/8TExP/IyMj/zs7O/9XV1f/c3Nz/3d3d + /9ra2v/S0tL/x8fH/83Nzf/Nzc3/wcHB/8LCwv+0tLT/r6+v/6ioqP+ZmZn/pqam/5eXl+wNDQ1eAAAA + QQAAAEQAAAA2AAAAJwAAABwAAAASAAAACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtra27Le3t/+6urr/vb29/8DAwP/ExMT/ycnJ + /8/Pz//W1tb/19fX/9XV1f/Nzc3/xMTE/8XFxf/AwMD/vb29/7a2tv+urq7/oqKi/5SUlP+QkJD/paWl + /52dne8XFxdYAAAAMgAAADsAAAAxAAAAJgAAABwAAAASAAAACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsrKyrbu7u/+5ubn/ubm5 + /76+vv/AwMD/xMTE/8fHx//MzMz/zs7O/8zMzP/Hx8f/w8PD/8DAwP+6urr/sLCw/6Ojo/+UlJT/jo6O + /5GRkf+Xl5f/r6+v/3R0dMMAAAAiAAAAIg0NDTAAAAApAAAAIQAAABgAAAAPAAAACAAAAAAAAAAAKiop + KW9tb+KTkJH/WFlZxQ0ODkoAAAAaAAAAJQAAACcAAAA4AgIBOgAAAAgAAAAAAAAAAAAAAAAAAAAAuLi4 + GJ6entbKysr/xMTE/7i4uP+6urr/vr6+/8DAwP/BwcH/wcHB/8DAwP+4uLj/r6+v/6Ojo/+YmJj/g4OD + /21tbf9paWn/f4GB/5OSkv+jo6P/qqys/FxcXJJOTk94amprloODhIAvLy8pAAAAFgAAABEAAAAJAAAA + BAAAAABlZGUzX19e67KwsP+empn/4+Hh/9jY2f9GRkbTBQUFmg4ODrtjY2P/paWj/0tMSr0KCwhVAAAA + EQAAAAAAAAAAAAAAAFpaWg9QUFCApqam8sfHx/+5ubn/ra2t/6Wlpf+kpKT/pKSk/5eXl/+JiYn/fX17 + /3Fxcf9lZWX/XV5e/2lpav+CgoP/mpqb/62rrv+2trX/ube3+Li2tu7Z2dr/29vb/5+fn/h/f34sAAAA + AwAAAAUAAAADAAAAAQAAAACZmJuKsKys/6ikpP+WkZH/q6qr/8/P0P/CwsL/mJiY/4uLi/9eXl7ibW1t + s9HR0fnFxMH/VVVUyRISEF8AAAATAAAAAAAAAAAAAAAAQ0NDLk5OTZmNjY7moaGh/6ampf+fn57/hYWF + /3h4d/96enn/ent8/39/gf+IiYr/nZ2f/6urrf+vrq7/sa+w/7a3t/+ztLT/ucPF/8bT1P/Cw8X+wL6+ + /qenp/9wcHBJAAAAAAAAAAAAAAAAAAAAAAAAAACQj5GDqqen/6+qqv+fnJz/srCy/8jIzP+rrKz/rays + /7i4uP+EhITxLi4utRkZGY9xcnO30tLS9Le3t/9WVlO+GBgYawAAACcAAAAGAAAAAAAAAAAfICAIOTk6 + NHl5e4+UlZX6hYWJ/4uKjf+OjpL/kZCV/5eXmv+hoaT/qqqs/6itsP+vubz/ucfJ/8zV1//W29z/19fX + /9XT0//Jycn+wcXF/KqoqP+GhoZtAAAAAAAAAAAAAAAAAAAAAAAAAACRkJKDrqqr/7Wwsf+npaX/trS2 + /8C/wP+4uLj/urq6/6+vr//Nzc3/6enp/6ioqPo5ODizHBweloODhNr19vX/o6Ki/xkXF4UXFxgmSEhK + QHNzd3SDgYaliIiMzIqJjeyKio7/jIyS/4uPlP+LkZb/jZab/52mqv+2vL7/y87P/9HR0f/Hx8f/rKys + /4CAgP9SUlL/LS0t/yIiIv+wsLD/y9ja/Kelpf+fn5+NAAAAAAAAAAAAAAAAAAAAAAAAAACSkJODtrGy + /724uf+wqq3/vry9/7u7u/+Ojo7/mpqa/7W1tf+1tbX/wMDA/+vr6//19fX/kJCQ9lVVVu1gYWL0cXBz + 1YmHi9ifn6T1n5+m/5qdof+Sl5v/kJec/5Ocn/+bpKf/qK2v/66urv+xsbH/tLS0/5ubm/98fHz/W1tb + /y0tLf8WFhb/EhIS/xAQEP8PDw//Dw8P/xAQEP+kpKT/0Nvc/qqpqf+ZmZmxAAAAAAAAAAAAAAAAAAAA + AAAAAACRkpODvre3/8G6vf+uqqz/vLq7/7y8v/+fn5//mJiY/5CQkP+YmJn/lJOV/5GRk/+Ympr/mJab + /5ybof+kpqr/pKmt/6eusf+rsbT/rrS2/7W5u/+0tLX/ra2t/6SkpP+NjY3/aWlp/0NDQ/8hISH/Dg4O + /w4ODv8ODg7/Dw8P/xQUFP8YGRj/ICog/yg9KP8uSy7/M1oz/zlpOf+VlZX/09zd/rGurv+am5vMAAAA + AAAAAAAAAAAAAAAAAAAAAACTkZSFxL6//8a+wf+wrKv/vbq7/7u7vP+dnZ3/nZ2d/52dn/+OjpL/ko+V + /4uRkv+AnZD/lp2f/6isrv+7vr//x8fH/8HBwf+bm5v/fX19/2FhYf8/Pz//Hx8f/wsLC/8GBgb/BgYG + /wcHB/8JCQn/Fx0X/yY2Jv8sRyz/MlUy/zZlNv88bzz/N2A3/zJSMv8uRS7/Kzgr/x8uH/+DhYP/09rc + /7W1tP+amZndAAAAAAAAAAAAAAAAAAAAAAAAAACRkpWGysPD/8rExP+xrKz/vbq7/7u7vP+dnZ3/n5+f + /7Kys/+Wl5r/mZmZ/7S0tP+3t7f/m5ub/3R0dP9SUlL/Nzc3/xsbG/8MDAz/BAQE/wAAAP8BAQH/BwoH + /xMfE/8eMx7/KEon/zFeMf86bDr/OGU4/zVZNf8wSzD/LT8t/yozKv8oKCj/Kioq/ysrK/8sLCz/LS0t + /yQkJP9veG//1Nna/7m7u/+amZnqAAAAAAAAAAAAAAAAAAAAAAAAAACSkZWGzMfH/8zGxv+zrq7/u7u9 + /7y8vf+goKH/oaGh/7Ozs/+kqKv/mJiY/y8vL/8YGBj/Dw8P/wUFBf8CAgL/AQEB/wsVC/8WKBb/ITwh + /yxQLP81ZjX/OWo5/zBYMP8oRyj/IDUg/xkkGf8TFRP/ISEh/ysrK/8sLCz/Li4u/y8vL/8xMjH/ND40 + /zZLNv85Vjn/OmE6/ztqO/9ea17/0dPU/8TIyP+bmprwAAAAAAAAAAAAAAAAAAAAAAAAAACTkJSG0MnI + /8/Jyv+zsLH/u7m7/7+/v/+mpqT/paWl/6+vr/+yuLv/lJKS/xEWEf8SIBL/HzYf/yhJKP8yXDL/PHA8 + /zJdMv8oSij/Hjce/xcmF/8PFQ//CgoK/wwMDP8ODg7/EBAQ/xAQEP8UFBT/LTQt/zZGNv8ojyb/Ol06 + /ztnO/88bzz/PGU8/zxcPP89Uz3/Pkw+/zg9OP9TX1P/zMzM/8zT0/+cnJz0l5iYEwAAAAAAAAAAAAAA + AAAAAACTkJOG0MnK/87Iyf+zr7D/u7m6/7+/wf+pqaf/qamp/6ysrP+6vL3/o6Oj/zlqOf8wVjD/KkYq + /yA0IP8WIRb/CwsL/woKCv8HBwf/BwcH/wgICP8KCgr/DxIP/xklGf8iOCL/K0or/zNcM/86bDr/O2g7 + /yihJf8jrx//PlA+/z9IP/8thSz/K5Mo/0NDQ/9ERET/R0dH/0JCQv9OV07/y8vL/9DZ2/+fnp3+mpqa + PwAAAAAAAAAAAAAAAAAAAACTk5WGz8jH/8zFxv+ysa7/u7q7/8LCw/+sqqv/qqqq/7CwsP/AwcH/s7W3 + /yc8J/8PDw//GRkZ/xQUFP8TExP/EBAQ/xVrE/8cLhz/Iz8j/y1SLf82ZDb/OWo5/zJZMv8qSSr/Izgj + /xwnHP8fIh//PT09/yamI/8isx//Q09D/0dHR/8zizH/JrAj/0NgQ/9FWUX/RGFE/0BmQP87cjv/ysrK + /9Xd3/+koqL/mZmZaAAAAAAAAAAAAAAAAAAAAACTkpaGzMTI/8a+wP+lo6D/uba3/8bEx/+xr7D/srOy + /7m5uf/Dw8P/ur7A/zpVOv8bKRv/LEMs/y9PL/81XjX/JrEj/yKpH/8qTCr/ITkh/xkpGf8TGhP/EBAQ + /xEREf8TExP/FRUV/xYWFv8mJib/R0hH/yHAHv8snyr/OX84/0JlQv8soCr/LJ8q/yyiKv8osCX/R2RH + /yytKf85eDj/vb29/9be4P+mpaX/mZmZiwAAAAAAAAAAAAAAAAAAAACUkpSGxsDA/767u/+jn5//trS1 + /8nLyf+5u7n/ubm5/7y8vP/Gxsf/vMLE/zl8OP8wVjD/Mk8y/yo9Kv8hQSH/FZ4T/xGqDv8ICAj/CwsL + /w0NDf8QEBD/ERER/xUYFf8eKh7/Jjsm/y5NLv85Yjn/NoI2/yW1Iv8zkDL/Mpwv/0xeTP82mzT/RYFD + /y+wLP89lDz/PZg6/z2aO/9QUFD/rq6u/9fg4v+pqqr/lpaWswAAAAAAAAAAAAAAAAAAAACSk5WGvLi6 + /7uytP+hmZr/tLK0/8zNz/++wL7/vb29/7+/v//Gxsb/u8PF/1x0W/8PDw//LCws/yUlJf8cdxr/HXEb + /w6LC/8SOhH/HjAe/ydDJ/8vVC//N2U3/zprOv8zWzP/Lkwu/ydFJ/86RTr/RIVD/zuZOf9RbFH/MLIt + /11dXf88nTr/SoZI/2BgYP9fYl//KcMm/0ObQf9XV1f/nJyc/9rg4v+1tbX/l5eXyQAAAAAAAAAAAAAA + AAAAAACTkpWGvK60/8Oqsv+pnKD/s7G2/83Pz//DxML/wsLC/8TExP/Gxsb/v8bH/3CFcP8UGRT/M0ky + /zNKM/8cvxn/NmQ2/yqkKP8mkiX/LE0s/yU+Jf8eLh7/GR8Z/xNkEv8UghL/FKAR/xSnEf8skSr/QZw+ + /0mKR/9gYGD/Lbwq/15sXf89ojv/SYtI/1ZqVv9Ra1H/M6Mx/0VvRf8+bz7/kJCQ/9ve3/++wMD/lpaW + 1QAAAAAAAAAAAAAAAAAAAACcjJaGlamd/2HbnP+Ru6f/w6y4/9DR0f/Hx8f/xsbG/8fHx//Jycn/wsfK + /4uciv8krCH/HsAb/yWZI/8llCP/Hike/wo9Cf8OeAz/EBAQ/xISEv8TExP/FFQT/xRxEv8ZSBf/Gy0b + /yElIf8pqyf/MbMu/0aBRv9MbEz/LKwp/zSNMv8prSb/OYw4/05uTv9UblT/Wm5a/2VvZf9jZmP/iIiI + /9ve3v/Dxsf/lpWV5AAAAAAAAAAAAAAAAAAAAACfi5p9NM1+/wD/a/90t5v/yqe6/9PT0//Ly8v/ycnJ + /8vLy//Ly8v/ys3P/62trf8XJhf/NDQ0/yeIJf82Njb/DQ0N/wsZC/8PnQv/ExcT/xsmG/8kOCT/Howc + /yZ9JP82Xzb/O2w7/zprOv9Ca0L/LrIr/1RtVP9ZbVn/SpRI/0ajRP9BrD//WoxY/29vb/9wcHD/cXFx + /3Nzc/9ra2v/fX19/9zd3f/Iy83/lZWV8JubmyAAAAAAAAAAAAAAAACamp9uPpRn/wZUG/99cnT/w7rD + /9XY2f/Pz8//zMzM/83Nzf/Ozs7/0NPU/7u5uv8kKCT/NkA2/0FVQf80TjT/KUop/zNcM/8gux7/NXc0 + /zReNP8uTS7/HKUY/yVWJf8mMSb/JSgl/zMzM/9oaGj/dXV1/3Jycv9ycnL/aIFn/zm9Nv9DsUH/Wo5Z + /2h0aP9ec17/V3JX/1FyUf9HcEf/P3A//9vb2//N0dP/lpaW/Jubm0oAAAAAAAAAAAAAAACZl5xuY0RV + /ycAAv98bWz/vcDB/9XW1//Q0ND/z8/P/9HR0f/S0tL/1tfY/7u7u/87azv/O2U7/0FhQf8qRCr/HTEd + /xkjGf8TdRD/FFAT/xsbG/8eHx7/FbAR/yQkJP8nJyf/KSkp/0JCQv9rc2v/aHdo/190X/9Uc1T/TnJO + /yTCIf8lsiL/OYk5/0lySf9Uc1T/XHRc/2R2ZP9sdmz/Z2ln/9jY2P/T19n/mJeX/5qamnEAAAAAAAAA + AAAAAACenaF5aGRl/1RLQ/+HgH//ra6x/+Hh4v/Pz8//yMjI/87Ozv/S0tL/29vb/7y/wP8vLy//Ojo6 + /0FBQf8ODg7/EBAQ/xMTE/8UTxP/FXgT/yItIv8lVCX/HKQa/zJSMv83XTf/OWY5/zxwPP9Gckb/TXNN + /1V0Vf9gdmD/Z3dn/0KxQP9Et0H/Z5Fm/3p7ev9ueW7/Y3dj/1h2WP9Nc03/QG9A/8vLy//c4OL/mpub + /5mZmYsAAAAAAAAAAAAAAACloqU6kJGP/5KUkf+emZz/2tja///////4+Pj/5eXl/9nZ2f/T09P/09PT + /8HHx/8+QT7/OkQ6/zRHNP8kPST/K0or/zNcM/81dTX/Ib0e/zZfNv8esBz/JJAh/y5DLv8uOy7/LjYu + /11dXf+BgYH/fn5+/319ff91e3X/aXlp/1aEVf8rvyj/QX9B/z1wPf9Jc0n/VnVW/2J5Yv9wfXD/am5q + /7y8vP/i5+n/oKCg/5mZmZ4AAAAAAAAAAAAAAAAAAAAAtLSzQczOz5aztrfx1dXW/9zf3//09PT///// + ///////7+vr/6urq/8bN0f8+bz7/OGE4/zBQMP8lQCX/Izgj/x0oHf8bIBv/FKAQ/xpWGf8aehf/JCQk + /ycnJ/8sLyz/NkI2/1lvWf9ZeFn/SnNK/z9xP/9FckX/UXVR/114Xf80wTH/dn52/4GBgf+BgYH/gYGB + /4KCgv+FhYX/c3Nz/7Ozs//o7e//qqqq/5aWlq8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACvtLQqsbOz + QK+wsIm6vLz/yMrK/9rb2//z9PT//////9Xe3/91dXX/CAgI/w0NDf8QEBD/ExMT/xYWFv8ZGRn/GYYX + /yB4H/8khyL/NVo1/zpoOv87bDv/PWU9/1Z1Vv9ofWj/cn1y/3+Bf/+CgoL/goKC/4KCgv9Rsk//g4OD + /4SEhP9rfWv/XXpd/1F2Uf9IdEj/PnA+/zxwPP/v8vP/ubm5/5OTk8YAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAACvsrIdsbOzPa+zspi5u7v/xsfH/87V1/+GhIT/CQ4J/xooGv8kOyT/LU0t + /zReNP88cDz/LYQs/yKbIP8ncCb/LDss/ysxK/8sLCz/UFBQ/4SEhP+Ghob/hISE/3eAd/9me2b/VndW + /0l0Sf9CckL/PnA+/zxwPP8/cT//RHNE/0x1TP9Yelj/aHto/4+Wj//z9PX/xMXF/5KSktqbm5sPAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACztrYMrLCwI7zCxduWlZT/N2Y3 + /zBVMP8oRSj/IjYi/x4pHv8ZGRn/HSMc/xWrEv8jKiP/JiYm/zFDMf81UzX/R2xH/0h0SP8/cT//PHA8 + /z1wPf9AcUD/SHRI/1R4VP9ifGL/c4Jz/4eHh/+FhYX/g4OD/4CAgP9+fn7/cnJy/3p6ev/z9PX/0tPT + /42NjfCZmZk0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AMfO0WOoqqn/DQ0N/w4ODv8RERH/HCcc/yc+J/8wUTD/N2I3/yWrI/88bjz/PHA8/zttO/87aTv/SHBI + /1t8W/9sfmz/fYF9/4CAgP98fHz/eHh4/3Z2dv9zc3P/cHBw/2pqav9mZmb/ZWVl/2hoaP9sbGz/bW1t + /4KCgv/39/j/39/g/5SUlP2srKwqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAMjMzj2zubn/N2Q3/zpsOv88cDz/PG88/zprOv83Yjf/M1Qz/zBJMP8tOi3/Kioq + /ywsLP8uLi7/Wlpa/2hoaP9iYmL/YWFh/2BgYP9fX1//Y2Nj/3x8fP+FhIP/mpST/5qVk/+ppKP/srCv + /8TFxP/O0dL/2t/j/97m6fbl5eXj3t7ev7u7u2IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMLDxh68xcb/NFM0/x4xHv8UGBT/ExMT/xYWFv8WFhb/GBgY + /yIiIv8tLS3/RERE/1ZWVv9raWn/hYGA/52Zmf+lo6L/u7i4/7y7u//O0NL/0NPU/8/V1vjO09XxztPW + 387V18rT2dup09fYi9PV2F7LzM020NHRHNra2hbc3NwQ3t7eBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMHCxBK3vsHtTk5O/yQkJP9NS0v/bGRj + /4N7ev+Qi4v/pKam/7S8vv/D0NP/ytfY/8vb3P/L2Nr4y9LU58vP0NnLzs/Jyc3Oq83P0JDNztB1zs7O + RcnLyijIyMgJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKinqxGysbPlwcjJ + /7zMz//E0tb/xdHU9sfP0ujJz9DUyMvLvsjJy6vHyMiSycrKcsnJyVjLy8w3ysrKGAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AJubnwSnp6lmxMLEkMC+v3m7u71av72/PcPDwyfIyMkMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAACrq60I0tHSD8PCwwO7u70BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAP///////wAA////////AAD///////8AAP///AAf/wAA///wAAePAAD//+AAAQEA + AP//wAAAAAAA//+AAAAAAAD//4AAAAAAAP//gAAAAAAA//+AAAAAAADAB4AAAAAAAIABwAAAAAAAgABw + AAAPAACAAAwAAA8AAIAAAAAADwAAgAAAAAAPAACAAAAAAA8AAIAAAAAADwAAgAAAAAAPAACAAAAAAA8A + AIAAAAAABwAAgAAAAAAHAACAAAAAAAcAAIAAAAAABwAAgAAAAAAHAACAAAAAAAcAAIAAAAAABwAAgAAA + AAAHAACAAAAAAAMAAIAAAAAAAwAAgAAAAAADAACAAAAAAAMAAIAAAAAAAwAAwAAAAAADAADwAAAAAAMA + AP4AAAAAAQAA/8AAAAABAAD/8AAAAAEAAP/wAAAAAwAA//AAAAAHAAD/8AAAH/8AAP/wAB///wAA//AP + ////AAD/+H////8AAP///////wAA////////AAD///////8AACgAAAAgAAAAQAAAAAEAIAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsLCwBLi4uEqqqqqGtra2lrm5uZWhoaGVgYGB + h3d3d052dnYGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ6enmTHx8fZ1dXV/93d3f/i4uL/2tra + /9bW1v/c3Nz/yMjI/6Kior2Xl5dfAAAAAAAAAAAAAAAAAAAAAgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJeXlwuvr6/n2dnZ/9nZ2f/c3Nz/4ODg + /9/f3//Q0ND/z8/P/+rq6v/Nzc3/zs7O/9DQ0P+goKCsHR0dNgAAAAkAAAApAAAAFgAAAAQAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs7Oz59PT0//Hx8f/yMjI + /9TU1P/f39//4eHh/9LS0v/Pz8//2tra/729vf/Dw8P/tra2/8XFxf+wsLD/AAAAVAAAADoAAAAuAAAA + FwAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKqqqi69vb3/t7e3 + /76+vv/Gxsb/z8/P/9ra2v/b29v/z8/P/8fHx//Kysr/xsbG/7m5uf+enp7/jo6O/8nJyf8hISFxAAAA + IQAAADIAAAAfAAAAEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AMXFxeHOzs7/v7+//7+/v//Jycn/0NDQ/9LS1P/Pz8//xsbG/76+vv+ioqL/hYWF/4SEhP+bm5v/lZWV + 7wAAABcMDAwYCAgJFQAAABMAAAAMAAAAADk7PBpVVVfIiYeH/1FQUJ4BAQE6AAAANhMTE3EUFBRkQ0NB + DQAAAAAAAAAAAAAAAImJiaPT09T/y8vL/7a2tf+wsLD/r6+t/5qZmf+DhIP/ampq/1NSUv9nZ2f/lZOT + /7S0tf+koaHepaKk28PDxP9fX11aAAAAAAAAAAUAAAAAfXx9yJ6bmf+3srH/4ODh/5ubm/9HR0f7aGho + /6WlpPiNjYvaHh4dc0xMTQ4AAAAAAAAAACEgHklycnC+m5ub7pyamf93d3X/c3Bz/3RxdP+AgYP/np+h + /6uytv+4xsr/xdTV/9jh4v/h4eH/09PU/15eXoAAAAAAAAAAAAAAAACNjI3pu7e0/46Njv+tra7/0tTS + /8TExP+QkJHsUlJSunl5esisrK35iIiK5isrK3kAAAAKAAAAADMxNR9jY2aEio+U/YiRmP+MnKP/ma61 + /7/P0//T3N3/y83N/7Ozs/+NjY3/aWlp/7y8vP+8x8f/k5ORmAAAAAAAAAAAAAAAAIeFhdnAurv/pKGk + /62srP+urq3/qqmp/8/Pz//X19f/jIuM3VNRUuGEg4T/amxu8Y2Wmu2xwsf/tc3U/67HzP+zxsf/sra2 + /52fnP+AjoD/ZHdk/0JUQf8lMSX/FRUV/xEREf8NGQ3/jZaN/8jc3/+YlJS1AAAAAAAAAAAAAAAAjIqL + 3MrExf+no6X/rK2u/6KkpP+SkZH/kY6S/3+Mjv+WtK7/uc7T/9Tu9P/d+vz/w8/Q/6KhoP94g3X/VWdU + /zxLO/8nLCf/EBAQ/xAQEP8QEBD/ERER/xQYFP8iMCL/Lkcu/zFVMf8/fz7/zuDi/5KPjswAAAAAAAAA + AAAAAACRjY7g0s3M/6aiof+urK//qamp/5eXl/+op6z/mKWm/5ysov97gXP/VFdK/zE6MP8gICD/Dw8P + /wUFBf8EBAT/BQUF/wkJCf8VbRP/IYcg/zVWNf85ZTn/LJsq/zheOP82UTb/LT0t/2iDaP/Q4eL/l5OS + 1gAAAAAAAAAAAAAAAJOPkuHa0tL/pqSl/6yur/+sqqz/nJyc/8LT1/8mPCT/ERER/woKCv8CAgL/AAAA + /wAAAP8MFAz/Gy8b/ydFJ/8zXDP/PG88/ySZI/8ftRz/OEs4/zc/N/8jnCD/KIYm/zw8PP82Njb/YHRg + /9Tf4P+dnp7mk5OTEgAAAAAAAAAAkZGS4d7W2P+opqf/rrCu/7Gwsf+goKD/x9rf/yJGGf8JDwn/Gywb + /x6AHP8eqRz/Oms6/zRfNP8qSir/Ijgi/xsmG/8TExP/Fn0U/yeeJP86YDr/Q0ND/yenI/8huB//R05H + /yqeKP9PiU7/2N7e/6Koqf+UkJAuAAAAAAAAAACTkJLh3tTV/6WjpP+wr6//tLS1/6ampv/D0NL/P2E3 + /zdlN/8yVTL/G5sZ/xWrEv8PHg//CwsL/w8PD/8SEhL/FRUV/xUVFf8ajBj/OYo3/zKUMP9OTk7/KbAm + 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 + QeAArEH//6xB + + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/IPInfoWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/IPInfoWindow.Designer.cs new file mode 100644 index 000000000..fb32d053d --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/IPInfoWindow.Designer.cs @@ -0,0 +1,113 @@ +namespace ProcessHacker +{ + partial class IPInfoWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(IPInfoWindow)); + this.buttonClose = new System.Windows.Forms.Button(); + this.listInfo = new System.Windows.Forms.ListView(); + this.labelInfo = new System.Windows.Forms.Label(); + this.labelStatus = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // buttonClose + // + this.buttonClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonClose.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonClose.Location = new System.Drawing.Point(376, 329); + this.buttonClose.Name = "buttonClose"; + this.buttonClose.Size = new System.Drawing.Size(75, 23); + this.buttonClose.TabIndex = 1; + this.buttonClose.Text = "Close"; + this.buttonClose.UseVisualStyleBackColor = true; + this.buttonClose.Click += new System.EventHandler(this.buttonClose_Click); + // + // listInfo + // + this.listInfo.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listInfo.FullRowSelect = true; + this.listInfo.Location = new System.Drawing.Point(12, 31); + this.listInfo.Name = "listInfo"; + this.listInfo.ShowItemToolTips = true; + this.listInfo.Size = new System.Drawing.Size(439, 292); + this.listInfo.TabIndex = 2; + this.listInfo.UseCompatibleStateImageBehavior = false; + this.listInfo.View = System.Windows.Forms.View.Details; + // + // labelInfo + // + this.labelInfo.AutoSize = true; + this.labelInfo.Location = new System.Drawing.Point(12, 9); + this.labelInfo.Name = "labelInfo"; + this.labelInfo.Size = new System.Drawing.Size(35, 13); + this.labelInfo.TabIndex = 3; + this.labelInfo.Text = "label1"; + // + // labelStatus + // + this.labelStatus.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.labelStatus.AutoSize = true; + this.labelStatus.Location = new System.Drawing.Point(12, 334); + this.labelStatus.Name = "labelStatus"; + this.labelStatus.Size = new System.Drawing.Size(56, 13); + this.labelStatus.TabIndex = 4; + this.labelStatus.Text = "Working..."; + // + // IPInfoWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(463, 364); + this.Controls.Add(this.listInfo); + this.Controls.Add(this.labelStatus); + this.Controls.Add(this.labelInfo); + this.Controls.Add(this.buttonClose); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.MinimumSize = new System.Drawing.Size(479, 402); + this.Name = "IPInfoWindow"; + this.ShowIcon = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "IP information"; + this.Load += new System.EventHandler(this.IPInfoWindow_Load); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button buttonClose; + private System.Windows.Forms.ListView listInfo; + private System.Windows.Forms.Label labelInfo; + private System.Windows.Forms.Label labelStatus; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/IPInfoWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/IPInfoWindow.cs new file mode 100644 index 000000000..19f75b9ec --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/IPInfoWindow.cs @@ -0,0 +1,329 @@ +/* + * Process Hacker - + * IP information window + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Diagnostics; +using System.IO; +using System.Net; +using System.Net.NetworkInformation; +using System.Net.Sockets; +using System.Threading; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.UI; + +namespace ProcessHacker +{ + public enum IpAction : int + { + Whois = 0, + Ping = 1, + Tracert = 2 + } + + public partial class IPInfoWindow : Form + { + private IPAddress _ipAddress; + private IpAction _ipAction; + + public IPInfoWindow(IPAddress ipAddress, IpAction action) + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + _ipAddress = ipAddress; + _ipAction = action; + + listInfo.AddShortcuts(); + listInfo.ContextMenu = listInfo.GetCopyMenu(); + listInfo.SetTheme("explorer"); + listInfo.SetDoubleBuffered(true); + } + + private void IPInfoWindow_Load(object sender, EventArgs e) + { + Thread t = null; + + if (_ipAction == IpAction.Whois) + { + t = new Thread(new ParameterizedThreadStart(Whois)); + labelInfo.Text = "Whois host infomation for address: " + _ipAddress.ToString(); + labelStatus.Text = "Checking..."; + listInfo.Columns.Add("Results", 410); + } + else if (_ipAction == IpAction.Tracert) + { + t = new Thread(new ParameterizedThreadStart(Tracert)); + labelStatus.Text = "Tracing route..."; + listInfo.Columns.Add("Count", 30); + listInfo.Columns.Add("Reply Time", 60); + listInfo.Columns.Add("IP Address", 100); + listInfo.Columns.Add("Hostname", 200); + } + else if (_ipAction == IpAction.Ping) + { + t = new Thread(new ParameterizedThreadStart(Ping)); + labelStatus.Text = "Pinging..."; + listInfo.Columns.Add("Results", 400); + } + + t.IsBackground = true; + t.Start(_ipAddress); + } + + private void buttonClose_Click(object sender, EventArgs e) + { + this.Close(); + } + + private void Ping(object ip) + { + using (Ping pingSender = new Ping()) + { + PingOptions pingOptions = new PingOptions(); + PingReply pingReply = null; + + IPAddress ipAddress = (IPAddress)ip; + int numberOfPings = 4; + int pingTimeout = 1000; + int byteSize = 32; + byte[] buffer = new byte[byteSize]; + int sentPings = 0; + int receivedPings = 0; + int lostPings = 0; + long minPingResponse = 0; + long maxPingResponse = 0; + + //pingOptions.DontFragment = true; + //pingOptions.Ttl = 128; + + WriteStatus(string.Format("Pinging {0} with {1} bytes of data:", ipAddress, byteSize) + Environment.NewLine, true); + + for (int i = 0; i < numberOfPings; i++) + { + sentPings++; + + try + { + pingReply = pingSender.Send(ipAddress, pingTimeout, buffer, pingOptions); + } + catch (Exception ex) + { + WriteStatus("Ping error: " + ex.Message, false); + break; + } + + if (pingReply.Status == IPStatus.Success) + { + if (pingReply.Options != null) //IPv6 ping causes pingReply.Options to become null + { + WriteResult(string.Format("Reply from {0}: bytes={1} time={2}ms TTL={3}", ipAddress, byteSize, pingReply.RoundtripTime, pingReply.Options.Ttl), "", ""); + } + else + { + WriteResult(string.Format("Reply from {0}: bytes={1} time={2}ms TTL={3}", ipAddress, byteSize, pingReply.RoundtripTime, pingOptions.Ttl), "", ""); + } + + if (minPingResponse == 0) + { + minPingResponse = pingReply.RoundtripTime; + maxPingResponse = minPingResponse; + } + else if (pingReply.RoundtripTime < minPingResponse) + { + minPingResponse = pingReply.RoundtripTime; + } + else if (pingReply.RoundtripTime > maxPingResponse) + { + maxPingResponse = pingReply.RoundtripTime; + } + + receivedPings++; + } + else + { + WriteResult(pingReply.Status.ToString(), "", ""); + lostPings++; + } + } + WriteResult("", "", ""); + WriteResult(string.Format("Ping statistics for {0}:", ipAddress), "", ""); + WriteResult(string.Format(" Packets: Sent = {0}, Received = {1}, Lost = {2}", sentPings, receivedPings, lostPings), "", ""); + WriteResult("Approximate round trip times in milli-seconds:", "", ""); + WriteResult(string.Format(" Minimum = {0}ms, Maximum = {1}ms", minPingResponse, maxPingResponse), "", ""); + } + WriteStatus("Ping complete.", false); + } + + private void Tracert(object ip) + { + IPAddress ipAddress = (IPAddress)ip; + + using (Ping pingSender = new Ping()) + { + PingOptions pingOptions = new PingOptions(); + Stopwatch stopWatch = new Stopwatch(); + byte[] bytes = new byte[32]; + + pingOptions.DontFragment = true; + pingOptions.Ttl = 1; + int maxHops = 30; + + WriteStatus(string.Format("Tracing route to {0} over a maximum of {1} hops:", ipAddress, maxHops), true); + + for (int i = 1; i < maxHops + 1; i++) + { + stopWatch.Reset(); + stopWatch.Start(); + + PingReply pingReply; + + try + { + pingReply = pingSender.Send(ipAddress, 5000, new byte[32], pingOptions); + } + catch (Exception ex) + { + WriteStatus("Trace error: " + ex.Message, false); + break; + } + finally + { + stopWatch.Stop(); + } + + WriteResult(string.Format("{0}" , i), string.Format("{0} ms", stopWatch.ElapsedMilliseconds), string.Format("{0}", pingReply.Address)); + + WorkQueue.GlobalQueueWorkItemTag(new Action((address, hopNumber) => + { + string hostName; + + try + { + hostName = Dns.GetHostEntry(address).HostName; + } + catch + { + hostName = ""; + } + + if (this.IsHandleCreated) + { + this.BeginInvoke(new MethodInvoker(() => + { + foreach (ListViewItem item in listInfo.Items) + { + if (item.Text == hopNumber.ToString()) + { + item.SubItems[3].Text = hostName; + break; + } + } + })); + } + }), "ipinfowindow-resolveaddress", pingReply.Address, i); + + if (pingReply.Status == IPStatus.Success) + { + WriteStatus("Trace complete.", false); + break; + } + + pingOptions.Ttl++; + } + } + WriteStatus("Trace complete.", false); + } + + private void Whois(object ip) + { + try + { + using (TcpClient tcpClinetWhois = new TcpClient("wq.apnic.net", 43)) + using (NetworkStream networkStreamWhois = tcpClinetWhois.GetStream()) + using (BufferedStream bufferedStreamWhois = new BufferedStream(networkStreamWhois)) + using (StreamWriter streamWriter = new StreamWriter(bufferedStreamWhois)) + { + streamWriter.WriteLine(((IPAddress)ip).ToString()); + streamWriter.Flush(); + + StreamReader streamReaderReceive = new StreamReader(bufferedStreamWhois); + + while (!streamReaderReceive.EndOfStream) + { + string data = streamReaderReceive.ReadLine(); + if (!data.Contains("#") | !data.Contains("?")) + { + WriteResult(data, "", ""); + } + } + } + WriteStatus("Whois complete.", false); + } + catch (Exception ex) + { + WriteStatus("Whois error: " + ex.Message, false); + } + } + + private void WriteStatus(string info, bool title) + { + if (!this.IsHandleCreated) + return; + + if (this.InvokeRequired) + { + this.BeginInvoke(new MethodInvoker(() => WriteStatus(info, title))); + return; + } + + if (title) + { + labelInfo.Text = info; + } + else + { + labelStatus.Text = info; + } + } + + private void WriteResult(string hop, string time, string ip) + { + if (!this.IsHandleCreated) + return; + + if (this.InvokeRequired) + { + this.BeginInvoke(new MethodInvoker(() => WriteResult(hop, time, ip))); + return; + } + + ListViewItem litem = new ListViewItem(hop); + litem.SubItems.Add(time); + litem.SubItems.Add(ip); + litem.SubItems.Add(""); + + listInfo.Items.Add(litem); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/IPInfoWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/IPInfoWindow.resx new file mode 100644 index 000000000..4a18a8b93 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/IPInfoWindow.resx @@ -0,0 +1,1750 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + 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 + /wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI+AAAAAAAAAAAAIj4j4gAAAAAAAAACIj/iIiA + AAAAAAAACPiIiIeIAAAAB3B3AIiId3eIgAAAiIh4dwB3eIiIgAAAeHiIeHiId3AHgAAAiIeHh3cAAgMA + gAAAiIeAAAAAJyRygAAAiIiAAicnInIniAAAiHiGNgAApycneAAAh4iAIyKjZyeneAAAh4iHICJCdzZ3 + eAAAcoiFAGMhd3o2OAAAh4+DAiJ2JjZ3eAAAAIj2cHIHd3d3eAAAAACHAAUneIiI+AAAAAAId3eIiI+P + gAAAAAAIjwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD////////////4 + ////wD///4Af//+AD//kwAf/wDAH/8AAB//AAAf/wAAH/8AAA//AAAP/wAAD/8AAA//AAAP/wAAD//AA + A//8AAP//gAH//4///////////////////8oAAAAEAAAACAAAAABAAQAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAgAAAgAAAAICAAIAAAACAAIAAgIAAAICAgADAwMAAAAD/AAD/AAAA//8A/wAAAP8A + /wD//wAA////AAAAAAAAAAAAd3AAiIeHgACHgAD4iIcAAIiAAACHcAAAiIiIiIiIeHiIiIiIiIiIiIiI + gAAAAAD3iIiAAAcncIiKeIBwAioniIF4iiAadaqIiI9wImd3dYgACIBKN3d3iAAIgDBHJWOIAAiHiHiI + iIgACI+IiIiIiAAAAAAAAAAA/////xwH//8cD///Hx///wAA//8AAP//AAD//wAA//8AAP//AAD//wAA + ///gAP//4AD//+AA///gAP///////ygAAAAwAAAAYAAAAAEACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAABwoHAAwMDAANFA0ACxkLABISEgAUGhQAGhoaACcAAgAKPQkAFSMVABYoFgAbJBsAHCocABI6 + EQAeMx4AIyQjACIpIgAsLCwAIjQiACM7IwAsMywAKzsrADQ0NAA0PjQAOzw7ABZLFQAGVBsAFlMVAA54 + DAATZBIAFWsTABNzEQAVeBMAGnoXABx0GgAgeB8AJUIlAChKJwArRSsAK0srACVVJQAtUi0ANEM0ADJL + MgA7QzsAPko+ADFTMQAzXDMAO1M7ADtcOwAmdiUANmM2ADpkOgA6azoANXY0AD1wPQA5ezgAQ0NDAEVL + RQBNTU0AVEtDAEFVQQBFWUUATldOAExeTABSUlIAU19TAFxcXABjRFUAQmJCAENtQwBNbU0AR3NHAFNs + UwBfYl8AW21bAFR0VABUeFQAXHRcAFp5WgBiYmIAamRkAGZsZgBmZ2gAampqAHxtbABjdmMAY3pjAGl1 + aQBre2sAcnJyAH1ydABzfHMAeHh3AHt7ewCDe3oADosLAA+dCwAUghIAGYYXAB6MHAAVnhMAEaoOABSi + EAAVqxIAHKQZABWwEQAesBwAHL8ZACKsHwAisx8AILweACSHIgAniCUAKI8mAC2ELAAlkiMAI5ohACuS + KQAsnyoAMpwvADaCNgAzjDEAOYo4ADOQMgA2mzQAPZQ8ADyaOgAmpiMAKKElACSrIgAprCYAK6IpACys + KQAlsiIAKLAlAC6xKwAsvSkAMLItADOjMQA9ojsAOb02AEGcPgBBrD8AHsAbACHAHgAkwiEAKcMmADTB + MQA+lGcARYJEAEmKRwBKhkgASYtIAEObQQBKlEgAWIpXAEajRABDs0AAUbJPAGiBZwBnkWYAc4JzAH6B + fgA0zX4AAP9rAISAfgB/f4EAf4GBAHS3mwBh25wAg4KCAIWFiQCIh4oAi4uLAJCLiwCNmYwAkJGPAIyN + kgCSj5UAi5GUAICdkACNlpsAk5OTAJmVlACTl5oAmJabAJScnwCbmpsAoZ2dAJWpnQCdnaIAqZygAJuk + pwCdpqoAkbunAKOjowCppaQAqamnAKSmqgCkqKwArKusALCsrACysK4Ap66xAKutsACxr7AAvK60AKyy + tQCvubwAs7OzALu1tgC0ursAu7q7AMOqsgDKp7oAw6y4AMG8vgC+wL4AvL7AAMO9wQC8wsQAucfJALzM + zwDDw8QAy8TFAM/IxwDEx8kAzMTIAMPIygDLy8sA0MnJAMbN0QDPz9AAxdHUAM3S0wDM1tgAy9nbANLT + 0wDU19gA09rbANvb2wDW3uAA3N/hANfg4gDb4OIA3+bpAOPj5ADi5+kA5+npAOnq6wDv8vMA8/T0APf3 + +AD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + 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 + FAAcHRwACzwKABckFwAZIxkAHCwcACMjIwAjKyMAKysrACIyIgAlOyQAKjIqACs8KwA1NTUANDs0ADw8 + PABHJi0AD0EOABpDGQAfWx4AIkYZACBXHwANZAoAEXUPABVlEwAVbRMAGW4WABNzEQAWfRQAG3cZACdF + JwAuRy4ALEosADNDMwA3TzcAOkU6ADpLOQA0VDQAM1wzADtWOwA6XDoAAHs5ACpuKQAwci8ANmQ2AD9h + NwA5YjkAO2w7AD1wPQA/fD4AQkJCAEdORwBLS0sAQlRBAFRXSgBVVFQAX19fAEBtQABAcEAASHhHAElz + SQBLeEsAVGVUAFxhXABUdFQAWXZRAFV4VQBZcVkAXHpcAHpfZwBlZWUAampqAGFzYQBiemIAaHZoAGJ4 + aQBtf20Ac3NzAHp0dwByfXIAe3t8ABKIDwAVhBIAGY4XAB6AHAAajBgAEpEQABycGgAiih8AEawNABWh + EwAUrBEAH6UcAB6pHAAZsBYAH7UcACG6HgAhhyAAKIYmACKLIAAlkCMAKJQmACSbIgApmCcAK5wpADGb + LwA5ijcAM5MxACenIwAupCsAMKgtACK0IAApsCYAI7ogAC6+KwAzqDEAQKs9AB/EGwAhwx8AJMogAC3G + KgAuyCsAMsEvAEuFSgBPiU4ARZtDAFWGVABMp0oARbxDAGiDaABziG8AcYVxAHmCdAB5gXkAfoh+AIJ5 + gAB/jI4Af5SKABXyhQBLxo4AgoKDAIqFhQCAjoAAiYmJAI2NjQCVg4oAjZaNAIqPlACRjpIAnI+XAIid + kwCIkZgAlJSUAJiXlwCRm5UAlpmaAJqZmgCdmpoAnZ2bAJ2bnQCdnJwAoJuaAIycowCVnaEAnJ6gAJil + pgCcrKIAlrSuAJmutQCko6MAqKanAKinrACkqqsArKysALCvrwCusK4AtbCvALGvsACqsbQArb2+ALGx + sQC2srIAsra2ALW1tQC7t7QAtrq3ALq1uQCxurwAubm5AL29vQDMtL4Awbu7AN+oxACux8wAssTHAL3C + wwC4xsoAvcnKALbM0gC8ztQAw8LCAMPDxADAxcYAxcXFAMrExQDExskAxMrLAMnJyQDJzc4Azs7OANHN + zADN0M4Aws7QAM3P0ADYxNAAw9HVAMrQ0gDL1NgAxdreAMjc3wDR0dEA0tTSANLS1ADR1dQA1dXVANzT + 0wDQ19kA3tbYANXa2gDZ2dkA2d3dAN3d3QDT3uEAzuDiAMzn7ADI6e0A0eHiANnj5QDa7O0A3u3uANTu + 9ADd+vwA4ODhAObm5gDg6OoA6urqAO3q6QD19fUA9fb5AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADi + 4uLVwwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADV6+v56+vr1cMAAAAAAAAAAAAAAAAAAAAAAAAAAAC9 + 6+vr+evi4vvV1eLDAAAAAAAAAAAAAAAAAAAAAAAAw+LR1eL5+eLV69HRvdG9AAAAAAAAAAAAAAAAAAAA + AADDvdHR4uvr4tXV0cOmltEAAAAAAAAAAAAAAAAAAAAAANXV0cPV4uLb0cOvkpKmpgAAAAAAAABWk54A + AAAAAAAAAL3i1b29s6aSTT1Mnr2zt9EAAAAApqa966Y6TLCmAAAAAACer59UU1OSqrjK3fP54rMAAACe + vpa34tGmkp6zngAAAACzmZ2ors3q1b2WTcPJwwAAAJ/Dr7Ozs9XrpkySU6nIzMfIvKaUUDsRBgYDmOG9 + AAAAptKvs6+emo6tzfb32q+KRCoRAwUCBgYNJSs3768AAACm2K+3sZ6xq6yKPBQHAgABAAIfZys0bjQr + EofvsAAAAKbnsLOzpt0QBgEAAAADDyQ0NWxlKhRsZxUTUO6wAAAApumws7ev4RoCC1pjNSwmEAkGImw0 + OHJ3Om6B7rAAAACm6a+zva/aNDIrXWEEAgMGBgVbcHE6dnFvczbruAAAAKbYpr3Dvd5HFw1hWAgDBSFc + H2JBfD93N3REReK5AAAApsSXvNXD1IghZF4eHAcZXTF7ZkF5gnhOTE1F2c0AAACbsaDF1c7RrwonLTB1 + LGlaDSB3U4R6gFBTU03RzdEAAJyQkcbr0dPJNDQqCWEGXBgHDINWU39+SkZCNcPdswAAjy9R3OrV29oM + OAcDVxhhEScrRkI2c31GUFVTs96mAACNFkvR6tHe1BQpESRqbXc0NC1SVZKShpKSkpKq6KEAAMJUs/7/ + +eLdPzQkEBlbIwwRPZqSkpKFSkhCNqbrqgAAAADJveL//+89AQYGB2EMERRJSkI2QUZPioyYn/myAAAA + AAAAAL2/2k0DCxImazU0NE+IjJaWlpaUk5JW+78AAAAAAAAAAADbnjQ0JhIREQ4TkpOTlZ6mr7C90eL9 + 0wAAAAAAAAAAAAC9AAYMEzg+U5q9w8PR09ne6O/z+vkAAAAAAAAAAAAAAMOTp73DyuHx8e/z8wAAAAAA + AAAAAAAAAAAAAAAAAAAA4vX1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////4P///4A///4 + AD//8AAf//AAH//wAB/H+AAHgD4AA4APAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AA + AAGAAAABgAAAAYAAAAGAAAAB4AAAAfwAAAH/AAAB/4AAA/+AB///j/////////////8oAAAAGAAAADAA + AAABAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUFBQAJCQkAAhcCAAIfAQAGGgYAERERABEV + EQAQGBAAERwRABYfFgAYGBgAHh4eAAIgAgALIwsADy8OAA8wDgAQNA8AFSEUABcnFwAZJBkAGioaABQx + FAAeNR4AICAgACQkJAAqKioALi4uADAtLQAiPyIALT0tADMzMwBBPT0AC18JABNrEgAXcxYAFHoRAB59 + GwAuTS4AKlAqADdONwAyWzIANVk1ADlYOQA+Xz4AEWU0ADJlMQA0YDQAN243ADhnOAA9YT0AOmo6AD1o + PQA8bTwAPHA8AEFBQQBKR0cATEhHAEtISABOTk4AUlJSAFVeVQBAcUAARndFAEhxSABeY14AUXRRAFJ5 + UgB5V2MAY2NjAGZmZgBlaGUAam1sAG5ubgBiemIAZXplAG94bwBxcXEAdXV1AHR+dAB6enoAfnt8AH9/ + fwAPgAwADYoKABCNDQAQng4AF4MUABSIEgAciRoAIJodABCgDQAcrhkAIYQgACaDJAAonCYALJ0qADiR + NQA8kjoAKaInACS1IAA0oTIAPag7AB/CGwApwyYAKscmAEyKSwBMn0kAQqFAAEeiRABNoUsAfYB9AICp + fAB/g4UAP8uFAIKCggCEhIQAgYmNAIyLigCOjo4AkI6OAIGWjACTkI8AiY+QAIiQkgCNlZcAkZGRAJWU + lACYl5cAl5ydAJmZmQCdnZ0Al5+gAJqgogCYr6UAoqKiAKSjowCmpaYAqKenAKeppwCuq6cAqKaoAK2l + qQCqqqkAq66vAK2trQCxp6kAtaSqALCpqwC0qq8AsK6vAKazsgCvs7MAq7S3ALKysgC2sbMAsbS2ALa1 + tQCztrgAt7i5ALC7vAC3uLwAs7y+ALq5ugC9vr4Awb69AMi7vgDFwL4AtL7BALnCwwC+xsYAvcfJALrI + yQDCwsIAxMPCAMPExQDFxcUAzMXGAMDIygDFyckAxszMAMnJyQDOyMkAys3NAM3NzQDZzdMAy9HTANHR + 0QDQ09QA1tLVANDU1QDV1dUA2dXXANPX2gDX2twA2dnZAN7a2ADe3t4A2N/hAN3i5ADe5OYA2ObpAOHh + 4QDh5ucA4O/vAPn8/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAv7MAAAAAAAAAAAAAAAAAAAAAAADAtcXK + xcW1tQAAAAAAAAAAAAAAAAAAALWztcXFu8C7raQAAAAAAAAAAAAAAAAAALuzrcDDu62PeI+IAAAAAAAA + AFGAAFGCAACknZ2Lf1FIe6CYjwAAAAAAioytrX5/f38AAIV+dYSkta3FswAAAAAAj52InZ6LcX6EnYuL + fnFGNwwfrAAAAAAAlqeNgoKXi39NOxsSDhAQFhIfoAAAAAAAnbGNj5QZCQMNDQUCFF4oKzA1kAAAAAAA + nbGPj5QHCSMdJy82X2crMmRjiLMAAAAAlqaNpKE1L1wXFQoHXGJiP2VAcKoAAAAAlpOKtaoaJSQhU1Yi + X0ZoamxGeKwAAAAAhnKWuawgJxBUVRJZQU1sbm5IdqgAAAAAeS2NwLI4GQJbWBkaTkxLaUNAPpgAAAAA + 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 + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACxsbEFu7u7HLOzs1WlpaWAsbGx + j7Kyspa0tLSZq6url42NjZKCgoKCeXl5XHJyciOBgYEHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjY2NGqioqHW8vLzRzc3N + /9XV1f/f39//5eXl/+Xl5f/h4eH/3Nzc/93d3f/e3t7/09PT/8DAwP+hoaHgjIyMh5aWliIAAAAAAAAA + AAAAAAAAAAAAAAAAAgAAAAIAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACPj49nt7e3 + 6tTU1P/X19f/29vb/9zc3P/b29v/2tra/9bW1v/R0dH/ycnJ/8zMzP/f39//2dnZ/8LCwv+/v7//ycnJ + /62trfljY2OGNTU1DwAAAAAAAAAWAAAAGQAAABcAAAANAAAABAAAAAIAAAABAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AKKioqbKysr/0NDQ/8vLy//Ly8v/0NDQ/9fX1//a2tr/29vb/9ra2v/U1NT/y8vL/9LS0v/k5OT/zc3N + /7Kysv/ExMT/yMjI/7m5uf/ExMT/fn5+yA0NDT0AAAAxAAAAPQAAADIAAAAiAAAAEwAAAAgAAAAEAAAA + AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAnZ2dhcXFxf/ExMT/wcHB/8fHx//MzMz/0NDQ/9fX1//c3Nz/3d3d/9zc3P/U1NT/yMjI + /9PT0//e3t7/wcHB/8LCwv/Kysr/tbW1/6ysrP+srKz/wsLC/25ubsgAAABIAAAASwAAAEAAAAAyAAAA + JAAAABUAAAALAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAtra27r29vf+9vb3/wcHB/8TExP/IyMj/zs7O/9XV1f/c3Nz/3d3d + /9ra2v/S0tL/x8fH/83Nzf/Nzc3/wcHB/8LCwv+0tLT/r6+v/6ioqP+ZmZn/pqam/5eXl+wNDQ1eAAAA + QQAAAEQAAAA2AAAAJwAAABwAAAASAAAACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtra27Le3t/+6urr/vb29/8DAwP/ExMT/ycnJ + /8/Pz//W1tb/19fX/9XV1f/Nzc3/xMTE/8XFxf/AwMD/vb29/7a2tv+urq7/oqKi/5SUlP+QkJD/paWl + /52dne8XFxdYAAAAMgAAADsAAAAxAAAAJgAAABwAAAASAAAACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsrKyrbu7u/+5ubn/ubm5 + /76+vv/AwMD/xMTE/8fHx//MzMz/zs7O/8zMzP/Hx8f/w8PD/8DAwP+6urr/sLCw/6Ojo/+UlJT/jo6O + /5GRkf+Xl5f/r6+v/3R0dMMAAAAiAAAAIg0NDTAAAAApAAAAIQAAABgAAAAPAAAACAAAAAAAAAAAKiop + KW9tb+KTkJH/WFlZxQ0ODkoAAAAaAAAAJQAAACcAAAA4AgIBOgAAAAgAAAAAAAAAAAAAAAAAAAAAuLi4 + GJ6entbKysr/xMTE/7i4uP+6urr/vr6+/8DAwP/BwcH/wcHB/8DAwP+4uLj/r6+v/6Ojo/+YmJj/g4OD + /21tbf9paWn/f4GB/5OSkv+jo6P/qqys/FxcXJJOTk94amprloODhIAvLy8pAAAAFgAAABEAAAAJAAAA + BAAAAABlZGUzX19e67KwsP+empn/4+Hh/9jY2f9GRkbTBQUFmg4ODrtjY2P/paWj/0tMSr0KCwhVAAAA + EQAAAAAAAAAAAAAAAFpaWg9QUFCApqam8sfHx/+5ubn/ra2t/6Wlpf+kpKT/pKSk/5eXl/+JiYn/fX17 + /3Fxcf9lZWX/XV5e/2lpav+CgoP/mpqb/62rrv+2trX/ube3+Li2tu7Z2dr/29vb/5+fn/h/f34sAAAA + AwAAAAUAAAADAAAAAQAAAACZmJuKsKys/6ikpP+WkZH/q6qr/8/P0P/CwsL/mJiY/4uLi/9eXl7ibW1t + s9HR0fnFxMH/VVVUyRISEF8AAAATAAAAAAAAAAAAAAAAQ0NDLk5OTZmNjY7moaGh/6ampf+fn57/hYWF + /3h4d/96enn/ent8/39/gf+IiYr/nZ2f/6urrf+vrq7/sa+w/7a3t/+ztLT/ucPF/8bT1P/Cw8X+wL6+ + /qenp/9wcHBJAAAAAAAAAAAAAAAAAAAAAAAAAACQj5GDqqen/6+qqv+fnJz/srCy/8jIzP+rrKz/rays + /7i4uP+EhITxLi4utRkZGY9xcnO30tLS9Le3t/9WVlO+GBgYawAAACcAAAAGAAAAAAAAAAAfICAIOTk6 + NHl5e4+UlZX6hYWJ/4uKjf+OjpL/kZCV/5eXmv+hoaT/qqqs/6itsP+vubz/ucfJ/8zV1//W29z/19fX + /9XT0//Jycn+wcXF/KqoqP+GhoZtAAAAAAAAAAAAAAAAAAAAAAAAAACRkJKDrqqr/7Wwsf+npaX/trS2 + /8C/wP+4uLj/urq6/6+vr//Nzc3/6enp/6ioqPo5ODizHBweloODhNr19vX/o6Ki/xkXF4UXFxgmSEhK + QHNzd3SDgYaliIiMzIqJjeyKio7/jIyS/4uPlP+LkZb/jZab/52mqv+2vL7/y87P/9HR0f/Hx8f/rKys + /4CAgP9SUlL/LS0t/yIiIv+wsLD/y9ja/Kelpf+fn5+NAAAAAAAAAAAAAAAAAAAAAAAAAACSkJODtrGy + /724uf+wqq3/vry9/7u7u/+Ojo7/mpqa/7W1tf+1tbX/wMDA/+vr6//19fX/kJCQ9lVVVu1gYWL0cXBz + 1YmHi9ifn6T1n5+m/5qdof+Sl5v/kJec/5Ocn/+bpKf/qK2v/66urv+xsbH/tLS0/5ubm/98fHz/W1tb + /y0tLf8WFhb/EhIS/xAQEP8PDw//Dw8P/xAQEP+kpKT/0Nvc/qqpqf+ZmZmxAAAAAAAAAAAAAAAAAAAA + AAAAAACRkpODvre3/8G6vf+uqqz/vLq7/7y8v/+fn5//mJiY/5CQkP+YmJn/lJOV/5GRk/+Ympr/mJab + /5ybof+kpqr/pKmt/6eusf+rsbT/rrS2/7W5u/+0tLX/ra2t/6SkpP+NjY3/aWlp/0NDQ/8hISH/Dg4O + /w4ODv8ODg7/Dw8P/xQUFP8YGRj/ICog/yg9KP8uSy7/M1oz/zlpOf+VlZX/09zd/rGurv+am5vMAAAA + AAAAAAAAAAAAAAAAAAAAAACTkZSFxL6//8a+wf+wrKv/vbq7/7u7vP+dnZ3/nZ2d/52dn/+OjpL/ko+V + /4uRkv+AnZD/lp2f/6isrv+7vr//x8fH/8HBwf+bm5v/fX19/2FhYf8/Pz//Hx8f/wsLC/8GBgb/BgYG + /wcHB/8JCQn/Fx0X/yY2Jv8sRyz/MlUy/zZlNv88bzz/N2A3/zJSMv8uRS7/Kzgr/x8uH/+DhYP/09rc + /7W1tP+amZndAAAAAAAAAAAAAAAAAAAAAAAAAACRkpWGysPD/8rExP+xrKz/vbq7/7u7vP+dnZ3/n5+f + /7Kys/+Wl5r/mZmZ/7S0tP+3t7f/m5ub/3R0dP9SUlL/Nzc3/xsbG/8MDAz/BAQE/wAAAP8BAQH/BwoH + /xMfE/8eMx7/KEon/zFeMf86bDr/OGU4/zVZNf8wSzD/LT8t/yozKv8oKCj/Kioq/ysrK/8sLCz/LS0t + /yQkJP9veG//1Nna/7m7u/+amZnqAAAAAAAAAAAAAAAAAAAAAAAAAACSkZWGzMfH/8zGxv+zrq7/u7u9 + /7y8vf+goKH/oaGh/7Ozs/+kqKv/mJiY/y8vL/8YGBj/Dw8P/wUFBf8CAgL/AQEB/wsVC/8WKBb/ITwh + /yxQLP81ZjX/OWo5/zBYMP8oRyj/IDUg/xkkGf8TFRP/ISEh/ysrK/8sLCz/Li4u/y8vL/8xMjH/ND40 + /zZLNv85Vjn/OmE6/ztqO/9ea17/0dPU/8TIyP+bmprwAAAAAAAAAAAAAAAAAAAAAAAAAACTkJSG0MnI + /8/Jyv+zsLH/u7m7/7+/v/+mpqT/paWl/6+vr/+yuLv/lJKS/xEWEf8SIBL/HzYf/yhJKP8yXDL/PHA8 + /zJdMv8oSij/Hjce/xcmF/8PFQ//CgoK/wwMDP8ODg7/EBAQ/xAQEP8UFBT/LTQt/zZGNv8ojyb/Ol06 + /ztnO/88bzz/PGU8/zxcPP89Uz3/Pkw+/zg9OP9TX1P/zMzM/8zT0/+cnJz0l5iYEwAAAAAAAAAAAAAA + AAAAAACTkJOG0MnK/87Iyf+zr7D/u7m6/7+/wf+pqaf/qamp/6ysrP+6vL3/o6Oj/zlqOf8wVjD/KkYq + /yA0IP8WIRb/CwsL/woKCv8HBwf/BwcH/wgICP8KCgr/DxIP/xklGf8iOCL/K0or/zNcM/86bDr/O2g7 + /yihJf8jrx//PlA+/z9IP/8thSz/K5Mo/0NDQ/9ERET/R0dH/0JCQv9OV07/y8vL/9DZ2/+fnp3+mpqa + PwAAAAAAAAAAAAAAAAAAAACTk5WGz8jH/8zFxv+ysa7/u7q7/8LCw/+sqqv/qqqq/7CwsP/AwcH/s7W3 + /yc8J/8PDw//GRkZ/xQUFP8TExP/EBAQ/xVrE/8cLhz/Iz8j/y1SLf82ZDb/OWo5/zJZMv8qSSr/Izgj + /xwnHP8fIh//PT09/yamI/8isx//Q09D/0dHR/8zizH/JrAj/0NgQ/9FWUX/RGFE/0BmQP87cjv/ysrK + /9Xd3/+koqL/mZmZaAAAAAAAAAAAAAAAAAAAAACTkpaGzMTI/8a+wP+lo6D/uba3/8bEx/+xr7D/srOy + /7m5uf/Dw8P/ur7A/zpVOv8bKRv/LEMs/y9PL/81XjX/JrEj/yKpH/8qTCr/ITkh/xkpGf8TGhP/EBAQ + /xEREf8TExP/FRUV/xYWFv8mJib/R0hH/yHAHv8snyr/OX84/0JlQv8soCr/LJ8q/yyiKv8osCX/R2RH + /yytKf85eDj/vb29/9be4P+mpaX/mZmZiwAAAAAAAAAAAAAAAAAAAACUkpSGxsDA/767u/+jn5//trS1 + /8nLyf+5u7n/ubm5/7y8vP/Gxsf/vMLE/zl8OP8wVjD/Mk8y/yo9Kv8hQSH/FZ4T/xGqDv8ICAj/CwsL + /w0NDf8QEBD/ERER/xUYFf8eKh7/Jjsm/y5NLv85Yjn/NoI2/yW1Iv8zkDL/Mpwv/0xeTP82mzT/RYFD + /y+wLP89lDz/PZg6/z2aO/9QUFD/rq6u/9fg4v+pqqr/lpaWswAAAAAAAAAAAAAAAAAAAACSk5WGvLi6 + /7uytP+hmZr/tLK0/8zNz/++wL7/vb29/7+/v//Gxsb/u8PF/1x0W/8PDw//LCws/yUlJf8cdxr/HXEb + /w6LC/8SOhH/HjAe/ydDJ/8vVC//N2U3/zprOv8zWzP/Lkwu/ydFJ/86RTr/RIVD/zuZOf9RbFH/MLIt + /11dXf88nTr/SoZI/2BgYP9fYl//KcMm/0ObQf9XV1f/nJyc/9rg4v+1tbX/l5eXyQAAAAAAAAAAAAAA + AAAAAACTkpWGvK60/8Oqsv+pnKD/s7G2/83Pz//DxML/wsLC/8TExP/Gxsb/v8bH/3CFcP8UGRT/M0ky + /zNKM/8cvxn/NmQ2/yqkKP8mkiX/LE0s/yU+Jf8eLh7/GR8Z/xNkEv8UghL/FKAR/xSnEf8skSr/QZw+ + /0mKR/9gYGD/Lbwq/15sXf89ojv/SYtI/1ZqVv9Ra1H/M6Mx/0VvRf8+bz7/kJCQ/9ve3/++wMD/lpaW + 1QAAAAAAAAAAAAAAAAAAAACcjJaGlamd/2HbnP+Ru6f/w6y4/9DR0f/Hx8f/xsbG/8fHx//Jycn/wsfK + /4uciv8krCH/HsAb/yWZI/8llCP/Hike/wo9Cf8OeAz/EBAQ/xISEv8TExP/FFQT/xRxEv8ZSBf/Gy0b + /yElIf8pqyf/MbMu/0aBRv9MbEz/LKwp/zSNMv8prSb/OYw4/05uTv9UblT/Wm5a/2VvZf9jZmP/iIiI + /9ve3v/Dxsf/lpWV5AAAAAAAAAAAAAAAAAAAAACfi5p9NM1+/wD/a/90t5v/yqe6/9PT0//Ly8v/ycnJ + /8vLy//Ly8v/ys3P/62trf8XJhf/NDQ0/yeIJf82Njb/DQ0N/wsZC/8PnQv/ExcT/xsmG/8kOCT/Howc + /yZ9JP82Xzb/O2w7/zprOv9Ca0L/LrIr/1RtVP9ZbVn/SpRI/0ajRP9BrD//WoxY/29vb/9wcHD/cXFx + /3Nzc/9ra2v/fX19/9zd3f/Iy83/lZWV8JubmyAAAAAAAAAAAAAAAACamp9uPpRn/wZUG/99cnT/w7rD + /9XY2f/Pz8//zMzM/83Nzf/Ozs7/0NPU/7u5uv8kKCT/NkA2/0FVQf80TjT/KUop/zNcM/8gux7/NXc0 + /zReNP8uTS7/HKUY/yVWJf8mMSb/JSgl/zMzM/9oaGj/dXV1/3Jycv9ycnL/aIFn/zm9Nv9DsUH/Wo5Z + /2h0aP9ec17/V3JX/1FyUf9HcEf/P3A//9vb2//N0dP/lpaW/Jubm0oAAAAAAAAAAAAAAACZl5xuY0RV + /ycAAv98bWz/vcDB/9XW1//Q0ND/z8/P/9HR0f/S0tL/1tfY/7u7u/87azv/O2U7/0FhQf8qRCr/HTEd + /xkjGf8TdRD/FFAT/xsbG/8eHx7/FbAR/yQkJP8nJyf/KSkp/0JCQv9rc2v/aHdo/190X/9Uc1T/TnJO + /yTCIf8lsiL/OYk5/0lySf9Uc1T/XHRc/2R2ZP9sdmz/Z2ln/9jY2P/T19n/mJeX/5qamnEAAAAAAAAA + AAAAAACenaF5aGRl/1RLQ/+HgH//ra6x/+Hh4v/Pz8//yMjI/87Ozv/S0tL/29vb/7y/wP8vLy//Ojo6 + /0FBQf8ODg7/EBAQ/xMTE/8UTxP/FXgT/yItIv8lVCX/HKQa/zJSMv83XTf/OWY5/zxwPP9Gckb/TXNN + /1V0Vf9gdmD/Z3dn/0KxQP9Et0H/Z5Fm/3p7ev9ueW7/Y3dj/1h2WP9Nc03/QG9A/8vLy//c4OL/mpub + /5mZmYsAAAAAAAAAAAAAAACloqU6kJGP/5KUkf+emZz/2tja///////4+Pj/5eXl/9nZ2f/T09P/09PT + /8HHx/8+QT7/OkQ6/zRHNP8kPST/K0or/zNcM/81dTX/Ib0e/zZfNv8esBz/JJAh/y5DLv8uOy7/LjYu + /11dXf+BgYH/fn5+/319ff91e3X/aXlp/1aEVf8rvyj/QX9B/z1wPf9Jc0n/VnVW/2J5Yv9wfXD/am5q + /7y8vP/i5+n/oKCg/5mZmZ4AAAAAAAAAAAAAAAAAAAAAtLSzQczOz5aztrfx1dXW/9zf3//09PT///// + ///////7+vr/6urq/8bN0f8+bz7/OGE4/zBQMP8lQCX/Izgj/x0oHf8bIBv/FKAQ/xpWGf8aehf/JCQk + /ycnJ/8sLyz/NkI2/1lvWf9ZeFn/SnNK/z9xP/9FckX/UXVR/114Xf80wTH/dn52/4GBgf+BgYH/gYGB + /4KCgv+FhYX/c3Nz/7Ozs//o7e//qqqq/5aWlq8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACvtLQqsbOz + QK+wsIm6vLz/yMrK/9rb2//z9PT//////9Xe3/91dXX/CAgI/w0NDf8QEBD/ExMT/xYWFv8ZGRn/GYYX + /yB4H/8khyL/NVo1/zpoOv87bDv/PWU9/1Z1Vv9ofWj/cn1y/3+Bf/+CgoL/goKC/4KCgv9Rsk//g4OD + /4SEhP9rfWv/XXpd/1F2Uf9IdEj/PnA+/zxwPP/v8vP/ubm5/5OTk8YAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAACvsrIdsbOzPa+zspi5u7v/xsfH/87V1/+GhIT/CQ4J/xooGv8kOyT/LU0t + /zReNP88cDz/LYQs/yKbIP8ncCb/LDss/ysxK/8sLCz/UFBQ/4SEhP+Ghob/hISE/3eAd/9me2b/VndW + /0l0Sf9CckL/PnA+/zxwPP8/cT//RHNE/0x1TP9Yelj/aHto/4+Wj//z9PX/xMXF/5KSktqbm5sPAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACztrYMrLCwI7zCxduWlZT/N2Y3 + /zBVMP8oRSj/IjYi/x4pHv8ZGRn/HSMc/xWrEv8jKiP/JiYm/zFDMf81UzX/R2xH/0h0SP8/cT//PHA8 + /z1wPf9AcUD/SHRI/1R4VP9ifGL/c4Jz/4eHh/+FhYX/g4OD/4CAgP9+fn7/cnJy/3p6ev/z9PX/0tPT + /42NjfCZmZk0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AMfO0WOoqqn/DQ0N/w4ODv8RERH/HCcc/yc+J/8wUTD/N2I3/yWrI/88bjz/PHA8/zttO/87aTv/SHBI + /1t8W/9sfmz/fYF9/4CAgP98fHz/eHh4/3Z2dv9zc3P/cHBw/2pqav9mZmb/ZWVl/2hoaP9sbGz/bW1t + /4KCgv/39/j/39/g/5SUlP2srKwqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAMjMzj2zubn/N2Q3/zpsOv88cDz/PG88/zprOv83Yjf/M1Qz/zBJMP8tOi3/Kioq + /ywsLP8uLi7/Wlpa/2hoaP9iYmL/YWFh/2BgYP9fX1//Y2Nj/3x8fP+FhIP/mpST/5qVk/+ppKP/srCv + /8TFxP/O0dL/2t/j/97m6fbl5eXj3t7ev7u7u2IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMLDxh68xcb/NFM0/x4xHv8UGBT/ExMT/xYWFv8WFhb/GBgY + /yIiIv8tLS3/RERE/1ZWVv9raWn/hYGA/52Zmf+lo6L/u7i4/7y7u//O0NL/0NPU/8/V1vjO09XxztPW + 387V18rT2dup09fYi9PV2F7LzM020NHRHNra2hbc3NwQ3t7eBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMHCxBK3vsHtTk5O/yQkJP9NS0v/bGRj + /4N7ev+Qi4v/pKam/7S8vv/D0NP/ytfY/8vb3P/L2Nr4y9LU58vP0NnLzs/Jyc3Oq83P0JDNztB1zs7O + RcnLyijIyMgJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKinqxGysbPlwcjJ + /7zMz//E0tb/xdHU9sfP0ujJz9DUyMvLvsjJy6vHyMiSycrKcsnJyVjLy8w3ysrKGAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AJubnwSnp6lmxMLEkMC+v3m7u71av72/PcPDwyfIyMkMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAACrq60I0tHSD8PCwwO7u70BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAP///////wAA////////AAD///////8AAP///AAf/wAA///wAAePAAD//+AAAQEA + AP//wAAAAAAA//+AAAAAAAD//4AAAAAAAP//gAAAAAAA//+AAAAAAADAB4AAAAAAAIABwAAAAAAAgABw + AAAPAACAAAwAAA8AAIAAAAAADwAAgAAAAAAPAACAAAAAAA8AAIAAAAAADwAAgAAAAAAPAACAAAAAAA8A + AIAAAAAABwAAgAAAAAAHAACAAAAAAAcAAIAAAAAABwAAgAAAAAAHAACAAAAAAAcAAIAAAAAABwAAgAAA + AAAHAACAAAAAAAMAAIAAAAAAAwAAgAAAAAADAACAAAAAAAMAAIAAAAAAAwAAwAAAAAADAADwAAAAAAMA + AP4AAAAAAQAA/8AAAAABAAD/8AAAAAEAAP/wAAAAAwAA//AAAAAHAAD/8AAAH/8AAP/wAB///wAA//AP + ////AAD/+H////8AAP///////wAA////////AAD///////8AACgAAAAgAAAAQAAAAAEAIAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsLCwBLi4uEqqqqqGtra2lrm5uZWhoaGVgYGB + h3d3d052dnYGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ6enmTHx8fZ1dXV/93d3f/i4uL/2tra + /9bW1v/c3Nz/yMjI/6Kior2Xl5dfAAAAAAAAAAAAAAAAAAAAAgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJeXlwuvr6/n2dnZ/9nZ2f/c3Nz/4ODg + /9/f3//Q0ND/z8/P/+rq6v/Nzc3/zs7O/9DQ0P+goKCsHR0dNgAAAAkAAAApAAAAFgAAAAQAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs7Oz59PT0//Hx8f/yMjI + /9TU1P/f39//4eHh/9LS0v/Pz8//2tra/729vf/Dw8P/tra2/8XFxf+wsLD/AAAAVAAAADoAAAAuAAAA + FwAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKqqqi69vb3/t7e3 + /76+vv/Gxsb/z8/P/9ra2v/b29v/z8/P/8fHx//Kysr/xsbG/7m5uf+enp7/jo6O/8nJyf8hISFxAAAA + IQAAADIAAAAfAAAAEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AMXFxeHOzs7/v7+//7+/v//Jycn/0NDQ/9LS1P/Pz8//xsbG/76+vv+ioqL/hYWF/4SEhP+bm5v/lZWV + 7wAAABcMDAwYCAgJFQAAABMAAAAMAAAAADk7PBpVVVfIiYeH/1FQUJ4BAQE6AAAANhMTE3EUFBRkQ0NB + DQAAAAAAAAAAAAAAAImJiaPT09T/y8vL/7a2tf+wsLD/r6+t/5qZmf+DhIP/ampq/1NSUv9nZ2f/lZOT + /7S0tf+koaHepaKk28PDxP9fX11aAAAAAAAAAAUAAAAAfXx9yJ6bmf+3srH/4ODh/5ubm/9HR0f7aGho + /6WlpPiNjYvaHh4dc0xMTQ4AAAAAAAAAACEgHklycnC+m5ub7pyamf93d3X/c3Bz/3RxdP+AgYP/np+h + /6uytv+4xsr/xdTV/9jh4v/h4eH/09PU/15eXoAAAAAAAAAAAAAAAACNjI3pu7e0/46Njv+tra7/0tTS + /8TExP+QkJHsUlJSunl5esisrK35iIiK5isrK3kAAAAKAAAAADMxNR9jY2aEio+U/YiRmP+MnKP/ma61 + /7/P0//T3N3/y83N/7Ozs/+NjY3/aWlp/7y8vP+8x8f/k5ORmAAAAAAAAAAAAAAAAIeFhdnAurv/pKGk + /62srP+urq3/qqmp/8/Pz//X19f/jIuM3VNRUuGEg4T/amxu8Y2Wmu2xwsf/tc3U/67HzP+zxsf/sra2 + /52fnP+AjoD/ZHdk/0JUQf8lMSX/FRUV/xEREf8NGQ3/jZaN/8jc3/+YlJS1AAAAAAAAAAAAAAAAjIqL + 3MrExf+no6X/rK2u/6KkpP+SkZH/kY6S/3+Mjv+WtK7/uc7T/9Tu9P/d+vz/w8/Q/6KhoP94g3X/VWdU + /zxLO/8nLCf/EBAQ/xAQEP8QEBD/ERER/xQYFP8iMCL/Lkcu/zFVMf8/fz7/zuDi/5KPjswAAAAAAAAA + AAAAAACRjY7g0s3M/6aiof+urK//qamp/5eXl/+op6z/mKWm/5ysov97gXP/VFdK/zE6MP8gICD/Dw8P + /wUFBf8EBAT/BQUF/wkJCf8VbRP/IYcg/zVWNf85ZTn/LJsq/zheOP82UTb/LT0t/2iDaP/Q4eL/l5OS + 1gAAAAAAAAAAAAAAAJOPkuHa0tL/pqSl/6yur/+sqqz/nJyc/8LT1/8mPCT/ERER/woKCv8CAgL/AAAA + /wAAAP8MFAz/Gy8b/ydFJ/8zXDP/PG88/ySZI/8ftRz/OEs4/zc/N/8jnCD/KIYm/zw8PP82Njb/YHRg + /9Tf4P+dnp7mk5OTEgAAAAAAAAAAkZGS4d7W2P+opqf/rrCu/7Gwsf+goKD/x9rf/yJGGf8JDwn/Gywb + /x6AHP8eqRz/Oms6/zRfNP8qSir/Ijgi/xsmG/8TExP/Fn0U/yeeJP86YDr/Q0ND/yenI/8huB//R05H + /yqeKP9PiU7/2N7e/6Koqf+UkJAuAAAAAAAAAACTkJLh3tTV/6WjpP+wr6//tLS1/6ampv/D0NL/P2E3 + /zdlN/8yVTL/G5sZ/xWrEv8PHg//CwsL/w8PD/8SEhL/FRUV/xUVFf8ajBj/OYo3/zKUMP9OTk7/KbAm + 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 + QeAArEH//6xB + + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/InformationBox.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/InformationBox.Designer.cs new file mode 100644 index 000000000..3eea860c3 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/InformationBox.Designer.cs @@ -0,0 +1,120 @@ +namespace ProcessHacker +{ + partial class InformationBox + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.textValues = new System.Windows.Forms.TextBox(); + this.buttonClose = new System.Windows.Forms.Button(); + this.buttonSave = new System.Windows.Forms.Button(); + this.buttonCopy = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // textValues + // + this.textValues.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textValues.HideSelection = false; + this.textValues.Location = new System.Drawing.Point(12, 12); + this.textValues.Multiline = true; + this.textValues.Name = "textValues"; + this.textValues.ReadOnly = true; + this.textValues.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.textValues.Size = new System.Drawing.Size(525, 288); + this.textValues.TabIndex = 0; + // + // buttonClose + // + this.buttonClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonClose.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonClose.Location = new System.Drawing.Point(462, 306); + this.buttonClose.Name = "buttonClose"; + this.buttonClose.Size = new System.Drawing.Size(75, 23); + this.buttonClose.TabIndex = 3; + this.buttonClose.Text = "&Close"; + this.buttonClose.UseVisualStyleBackColor = true; + this.buttonClose.Click += new System.EventHandler(this.buttonClose_Click); + // + // buttonSave + // + this.buttonSave.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonSave.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonSave.Location = new System.Drawing.Point(300, 306); + this.buttonSave.Name = "buttonSave"; + this.buttonSave.Size = new System.Drawing.Size(75, 23); + this.buttonSave.TabIndex = 1; + this.buttonSave.Text = "Save..."; + this.buttonSave.UseVisualStyleBackColor = true; + this.buttonSave.Click += new System.EventHandler(this.buttonSave_Click); + // + // buttonCopy + // + this.buttonCopy.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonCopy.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonCopy.Location = new System.Drawing.Point(381, 306); + this.buttonCopy.Name = "buttonCopy"; + this.buttonCopy.Size = new System.Drawing.Size(75, 23); + this.buttonCopy.TabIndex = 2; + this.buttonCopy.Text = "Copy"; + this.buttonCopy.UseVisualStyleBackColor = true; + this.buttonCopy.Click += new System.EventHandler(this.buttonCopy_Click); + // + // InformationBox + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(549, 341); + this.Controls.Add(this.buttonCopy); + this.Controls.Add(this.buttonSave); + this.Controls.Add(this.buttonClose); + this.Controls.Add(this.textValues); + this.KeyPreview = true; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "InformationBox"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Information"; + this.Load += new System.EventHandler(this.InformationBox_Load); + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.InformationBox_FormClosing); + this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.InformationBox_KeyDown); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TextBox textValues; + private System.Windows.Forms.Button buttonClose; + private System.Windows.Forms.Button buttonSave; + private System.Windows.Forms.Button buttonCopy; + + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/InformationBox.cs b/branches/ph-plugins/ProcessHacker/Forms/InformationBox.cs new file mode 100644 index 000000000..a85f1bbe2 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/InformationBox.cs @@ -0,0 +1,114 @@ +/* + * Process Hacker - + * simple-to-use text display box + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Windows.Forms; + +namespace ProcessHacker +{ + public partial class InformationBox : Form + { + public InformationBox(string values) + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + if (!Program.BadConfig) + this.Size = Properties.Settings.Default.InformationBoxSize; + + textValues.Text = values; + textValues.Select(0, 0); + } + + private void InformationBox_Load(object sender, EventArgs e) + { + // doesn't work??? + textValues.Select(); + textValues.ScrollToCaret(); + } + + private void InformationBox_FormClosing(object sender, FormClosingEventArgs e) + { + if (!Program.BadConfig) + Properties.Settings.Default.InformationBoxSize = this.Size; + } + + public TextBox TextBox { get { return textValues; } } + + public string DefaultFileName { get; set; } + + public string Title + { + get { return this.Text; } + set { this.Text = value; } + } + + public bool ShowSaveButton + { + get { return buttonSave.Visible; } + set { buttonSave.Visible = value; } + } + + private void buttonClose_Click(object sender, EventArgs e) + { + this.Close(); + } + + private void buttonSave_Click(object sender, EventArgs e) + { + SaveFileDialog sfd = new SaveFileDialog(); + + sfd.FileName = DefaultFileName; + sfd.Filter = "Text Files (*.txt)|*.txt|All Files (*.*)|*.*"; + + if (sfd.ShowDialog() == DialogResult.OK) + System.IO.File.WriteAllText(sfd.FileName, textValues.Text); + } + + private void buttonCopy_Click(object sender, EventArgs e) + { + if (textValues.Text.Length == 0) + return; + + if (textValues.SelectionLength == 0) + { + Clipboard.SetText(textValues.Text); + textValues.Select(); + textValues.SelectAll(); + } + else + { + Clipboard.SetText(textValues.SelectedText); + } + } + + private void InformationBox_KeyDown(object sender, KeyEventArgs e) + { + if (e.Control && e.KeyCode == Keys.A) + { + textValues.SelectAll(); + e.Handled = true; + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/InformationBox.resx b/branches/ph-plugins/ProcessHacker/Forms/InformationBox.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/InformationBox.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/JobWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/JobWindow.Designer.cs new file mode 100644 index 000000000..dd7b2f571 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/JobWindow.Designer.cs @@ -0,0 +1,84 @@ +namespace ProcessHacker +{ + partial class JobWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + _jobProps.Dispose(); + + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.panelJob = new System.Windows.Forms.Panel(); + this.buttonClose = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // panelJob + // + this.panelJob.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panelJob.Location = new System.Drawing.Point(12, 12); + this.panelJob.Name = "panelJob"; + this.panelJob.Size = new System.Drawing.Size(444, 372); + this.panelJob.TabIndex = 0; + // + // buttonClose + // + this.buttonClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonClose.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonClose.Location = new System.Drawing.Point(381, 390); + this.buttonClose.Name = "buttonClose"; + this.buttonClose.Size = new System.Drawing.Size(75, 23); + this.buttonClose.TabIndex = 1; + this.buttonClose.Text = "Close"; + this.buttonClose.UseVisualStyleBackColor = true; + this.buttonClose.Click += new System.EventHandler(this.buttonClose_Click); + // + // JobWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(468, 425); + this.Controls.Add(this.buttonClose); + this.Controls.Add(this.panelJob); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "JobWindow"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Job"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.JobWindow_FormClosing); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Panel panelJob; + private System.Windows.Forms.Button buttonClose; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/JobWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/JobWindow.cs new file mode 100644 index 000000000..b0b83e3ca --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/JobWindow.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Text; +using System.Windows.Forms; +using ProcessHacker.Components; +using ProcessHacker.Native.Objects; + +namespace ProcessHacker +{ + public partial class JobWindow : Form + { + JobProperties _jobProps; + + public JobWindow(JobObjectHandle jobHandle) + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + _jobProps = new JobProperties(jobHandle); + _jobProps.Dock = DockStyle.Fill; + + panelJob.Controls.Add(_jobProps); + } + + private void JobWindow_FormClosing(object sender, FormClosingEventArgs e) + { + _jobProps.SaveSettings(); + } + + private void buttonClose_Click(object sender, EventArgs e) + { + this.Close(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/JobWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/JobWindow.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/JobWindow.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/ListPickerWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/ListPickerWindow.Designer.cs new file mode 100644 index 000000000..907e29d57 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ListPickerWindow.Designer.cs @@ -0,0 +1,100 @@ +namespace ProcessHacker +{ + partial class ListPickerWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.listItems = new System.Windows.Forms.ListBox(); + this.buttonOK = new System.Windows.Forms.Button(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // listItems + // + this.listItems.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listItems.FormattingEnabled = true; + this.listItems.IntegralHeight = false; + this.listItems.Location = new System.Drawing.Point(12, 12); + this.listItems.Name = "listItems"; + this.listItems.Size = new System.Drawing.Size(382, 118); + this.listItems.TabIndex = 0; + this.listItems.SelectedIndexChanged += new System.EventHandler(this.listItems_SelectedIndexChanged); + // + // buttonOK + // + this.buttonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonOK.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonOK.Location = new System.Drawing.Point(238, 136); + this.buttonOK.Name = "buttonOK"; + this.buttonOK.Size = new System.Drawing.Size(75, 23); + this.buttonOK.TabIndex = 1; + this.buttonOK.Text = "&OK"; + this.buttonOK.UseVisualStyleBackColor = true; + this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click); + // + // buttonCancel + // + this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonCancel.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonCancel.Location = new System.Drawing.Point(319, 136); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.TabIndex = 2; + this.buttonCancel.Text = "&Cancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click); + // + // ListPickerWindow + // + this.AcceptButton = this.buttonOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(406, 171); + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.buttonOK); + this.Controls.Add(this.listItems); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ListPickerWindow"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Select an Item"; + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.ListBox listItems; + private System.Windows.Forms.Button buttonOK; + private System.Windows.Forms.Button buttonCancel; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/ListPickerWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/ListPickerWindow.cs new file mode 100644 index 000000000..eaa632b2d --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ListPickerWindow.cs @@ -0,0 +1,67 @@ +/* + * Process Hacker - + * simple-to-use list picker box + * + * Copyright (C) 2008 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 . + */ + +using System; +using System.Windows.Forms; + +namespace ProcessHacker +{ + public partial class ListPickerWindow : Form + { + public ListPickerWindow(string[] items) + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + listItems.Items.AddRange(items); + + if (listItems.Items.Count > 0) + listItems.SelectedItem = listItems.Items[0]; + } + + public string SelectedItem + { + get { return listItems.SelectedItem as string; } + } + + private void buttonOK_Click(object sender, EventArgs e) + { + this.DialogResult = DialogResult.OK; + this.Close(); + } + + private void buttonCancel_Click(object sender, EventArgs e) + { + this.DialogResult = DialogResult.Cancel; + this.Close(); + } + + private void listItems_SelectedIndexChanged(object sender, EventArgs e) + { + if (listItems.SelectedItem == null) + buttonOK.Enabled = false; + else + buttonOK.Enabled = true; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/ListPickerWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/ListPickerWindow.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ListPickerWindow.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/ListWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/ListWindow.Designer.cs new file mode 100644 index 000000000..de2be5cbf --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ListWindow.Designer.cs @@ -0,0 +1,103 @@ +namespace ProcessHacker +{ + partial class ListWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.buttonClose = new System.Windows.Forms.Button(); + this.listView = new System.Windows.Forms.ListView(); + this.columnName = new System.Windows.Forms.ColumnHeader(); + this.columnValue = new System.Windows.Forms.ColumnHeader(); + this.SuspendLayout(); + // + // buttonClose + // + this.buttonClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonClose.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonClose.Location = new System.Drawing.Point(424, 275); + this.buttonClose.Name = "buttonClose"; + this.buttonClose.Size = new System.Drawing.Size(75, 23); + this.buttonClose.TabIndex = 1; + this.buttonClose.Text = "&Close"; + this.buttonClose.UseVisualStyleBackColor = true; + this.buttonClose.Click += new System.EventHandler(this.buttonClose_Click); + // + // listView + // + this.listView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnName, + this.columnValue}); + this.listView.FullRowSelect = true; + this.listView.Location = new System.Drawing.Point(12, 12); + this.listView.Name = "listView"; + this.listView.ShowItemToolTips = true; + this.listView.Size = new System.Drawing.Size(487, 257); + this.listView.TabIndex = 0; + this.listView.UseCompatibleStateImageBehavior = false; + this.listView.View = System.Windows.Forms.View.Details; + // + // columnName + // + this.columnName.Text = "Name"; + this.columnName.Width = 150; + // + // columnValue + // + this.columnValue.Text = "Value"; + this.columnValue.Width = 300; + // + // ListWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(511, 310); + this.Controls.Add(this.listView); + this.Controls.Add(this.buttonClose); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ListWindow"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "List"; + this.Load += new System.EventHandler(this.ListWindow_Load); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Button buttonClose; + private System.Windows.Forms.ListView listView; + private System.Windows.Forms.ColumnHeader columnName; + private System.Windows.Forms.ColumnHeader columnValue; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/ListWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/ListWindow.cs new file mode 100644 index 000000000..777fc1d00 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ListWindow.cs @@ -0,0 +1,62 @@ +/* + * Process Hacker - + * simple-to-use list display box + * + * Copyright (C) 2008 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 . + */ + +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.UI; + +namespace ProcessHacker +{ + public partial class ListWindow : Form + { + public ListWindow(List> list) + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + foreach (KeyValuePair kvp in list) + { + ListViewItem item = new ListViewItem(); + + item.Text = kvp.Key; + item.SubItems.Add(new ListViewItem.ListViewSubItem(item, kvp.Value)); + + listView.Items.Add(item); + } + + listView.ContextMenu = listView.GetCopyMenu(); + } + + private void ListWindow_Load(object sender, EventArgs e) + { + listView.SetTheme("explorer"); + } + + private void buttonClose_Click(object sender, EventArgs e) + { + this.Close(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/ListWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/ListWindow.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ListWindow.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/LogWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/LogWindow.Designer.cs new file mode 100644 index 000000000..bbc6bfa84 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/LogWindow.Designer.cs @@ -0,0 +1,175 @@ +namespace ProcessHacker +{ + partial class LogWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.listLog = new System.Windows.Forms.ListView(); + this.columnTime = new System.Windows.Forms.ColumnHeader(); + this.columnMessage = new System.Windows.Forms.ColumnHeader(); + this.buttonClose = new System.Windows.Forms.Button(); + this.timerScroll = new System.Windows.Forms.Timer(this.components); + this.buttonCopy = new System.Windows.Forms.Button(); + this.buttonSave = new System.Windows.Forms.Button(); + this.buttonClear = new System.Windows.Forms.Button(); + this.checkAutoscroll = new System.Windows.Forms.CheckBox(); + this.SuspendLayout(); + // + // listLog + // + this.listLog.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listLog.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnTime, + this.columnMessage}); + this.listLog.FullRowSelect = true; + this.listLog.HideSelection = false; + this.listLog.Location = new System.Drawing.Point(12, 12); + this.listLog.Name = "listLog"; + this.listLog.ShowItemToolTips = true; + this.listLog.Size = new System.Drawing.Size(555, 419); + this.listLog.TabIndex = 0; + this.listLog.UseCompatibleStateImageBehavior = false; + this.listLog.View = System.Windows.Forms.View.Details; + this.listLog.VirtualMode = true; + this.listLog.DoubleClick += new System.EventHandler(this.listLog_DoubleClick); + this.listLog.RetrieveVirtualItem += new System.Windows.Forms.RetrieveVirtualItemEventHandler(this.listLog_RetrieveVirtualItem); + // + // columnTime + // + this.columnTime.Text = "Time"; + this.columnTime.Width = 130; + // + // columnMessage + // + this.columnMessage.Text = "Message"; + this.columnMessage.Width = 400; + // + // buttonClose + // + this.buttonClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonClose.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonClose.Location = new System.Drawing.Point(492, 437); + this.buttonClose.Name = "buttonClose"; + this.buttonClose.Size = new System.Drawing.Size(75, 23); + this.buttonClose.TabIndex = 5; + this.buttonClose.Text = "Close"; + this.buttonClose.UseVisualStyleBackColor = true; + this.buttonClose.Click += new System.EventHandler(this.buttonClose_Click); + // + // timerScroll + // + this.timerScroll.Enabled = true; + this.timerScroll.Interval = 1000; + this.timerScroll.Tick += new System.EventHandler(this.timerScroll_Tick); + // + // buttonCopy + // + this.buttonCopy.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonCopy.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonCopy.Location = new System.Drawing.Point(411, 437); + this.buttonCopy.Name = "buttonCopy"; + this.buttonCopy.Size = new System.Drawing.Size(75, 23); + this.buttonCopy.TabIndex = 4; + this.buttonCopy.Text = "Copy"; + this.buttonCopy.UseVisualStyleBackColor = true; + this.buttonCopy.Click += new System.EventHandler(this.buttonCopy_Click); + // + // buttonSave + // + this.buttonSave.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonSave.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonSave.Location = new System.Drawing.Point(330, 437); + this.buttonSave.Name = "buttonSave"; + this.buttonSave.Size = new System.Drawing.Size(75, 23); + this.buttonSave.TabIndex = 3; + this.buttonSave.Text = "Save..."; + this.buttonSave.UseVisualStyleBackColor = true; + this.buttonSave.Click += new System.EventHandler(this.buttonSave_Click); + // + // buttonClear + // + this.buttonClear.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.buttonClear.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonClear.Location = new System.Drawing.Point(12, 437); + this.buttonClear.Name = "buttonClear"; + this.buttonClear.Size = new System.Drawing.Size(75, 23); + this.buttonClear.TabIndex = 1; + this.buttonClear.Text = "Clear"; + this.buttonClear.UseVisualStyleBackColor = true; + this.buttonClear.Click += new System.EventHandler(this.buttonClear_Click); + // + // checkAutoscroll + // + this.checkAutoscroll.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.checkAutoscroll.AutoSize = true; + this.checkAutoscroll.Checked = true; + this.checkAutoscroll.CheckState = System.Windows.Forms.CheckState.Checked; + this.checkAutoscroll.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkAutoscroll.Location = new System.Drawing.Point(93, 440); + this.checkAutoscroll.Name = "checkAutoscroll"; + this.checkAutoscroll.Size = new System.Drawing.Size(81, 18); + this.checkAutoscroll.TabIndex = 2; + this.checkAutoscroll.Text = "Auto-scroll"; + this.checkAutoscroll.UseVisualStyleBackColor = true; + // + // LogWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(579, 472); + this.Controls.Add(this.checkAutoscroll); + this.Controls.Add(this.buttonClear); + this.Controls.Add(this.buttonSave); + this.Controls.Add(this.buttonCopy); + this.Controls.Add(this.buttonClose); + this.Controls.Add(this.listLog); + this.Name = "LogWindow"; + this.ShowIcon = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.Manual; + this.Text = "Log"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.LogWindow_FormClosing); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.ListView listLog; + private System.Windows.Forms.ColumnHeader columnTime; + private System.Windows.Forms.ColumnHeader columnMessage; + private System.Windows.Forms.Button buttonClose; + private System.Windows.Forms.Timer timerScroll; + private System.Windows.Forms.Button buttonCopy; + private System.Windows.Forms.Button buttonSave; + private System.Windows.Forms.Button buttonClear; + private System.Windows.Forms.CheckBox checkAutoscroll; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/LogWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/LogWindow.cs new file mode 100644 index 000000000..445aec0d6 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/LogWindow.cs @@ -0,0 +1,165 @@ +/* + * Process Hacker - + * log window + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Text; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.UI; + +namespace ProcessHacker +{ + public partial class LogWindow : Form + { + public LogWindow() + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + listLog.SetDoubleBuffered(true); + listLog.SetTheme("explorer"); + listLog.ContextMenu = listLog.GetCopyMenu(listLog_RetrieveVirtualItem); + listLog.AddShortcuts(listLog_RetrieveVirtualItem); + + this.UpdateLog(); + + if (listLog.SelectedIndices.Count == 0 && listLog.VirtualListSize > 0) + listLog.EnsureVisible(listLog.VirtualListSize - 1); + + Program.HackerWindow.LogUpdated += new HackerWindow.LogUpdatedEventHandler(HackerWindow_LogUpdated); + + this.Size = Properties.Settings.Default.LogWindowSize; + this.Location = Utils.FitRectangle(new Rectangle( + Properties.Settings.Default.LogWindowLocation, this.Size), this).Location; + checkAutoscroll.Checked = Properties.Settings.Default.LogWindowAutoScroll; + } + + private void HackerWindow_LogUpdated(KeyValuePair? value) + { + this.UpdateLog(); + } + + private void UpdateLog() + { + // HACK. Not my fault though, .NET wants to throw an exception when + // I set VirtualListSize and the window is minimized... + try + { + listLog.VirtualListSize = Program.HackerWindow.Log.Count; + } + catch + { + // Do not put Logging.Log(ex) because this will cause a recursive call. + } + } + + private void LogWindow_FormClosing(object sender, FormClosingEventArgs e) + { + if (this.WindowState == FormWindowState.Normal) + { + Properties.Settings.Default.LogWindowLocation = this.Location; + Properties.Settings.Default.LogWindowSize = this.Size; + } + + Properties.Settings.Default.LogWindowAutoScroll = checkAutoscroll.Checked; + + Program.HackerWindow.LogUpdated -= new HackerWindow.LogUpdatedEventHandler(HackerWindow_LogUpdated); + } + + private void buttonClose_Click(object sender, EventArgs e) + { + this.Close(); + } + + private void listLog_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e) + { + e.Item = new ListViewItem(new string[] + { + Program.HackerWindow.Log[e.ItemIndex].Key.ToString(), + Program.HackerWindow.Log[e.ItemIndex].Value + }); + } + + private void timerScroll_Tick(object sender, EventArgs e) + { + if (checkAutoscroll.Checked) + { + if (!listLog.Focused) + listLog.SelectedIndices.Clear(); + + if (listLog.SelectedIndices.Count == 0 && listLog.VirtualListSize > 0) + listLog.EnsureVisible(listLog.VirtualListSize - 1); + } + } + + private void buttonCopy_Click(object sender, EventArgs e) + { + if (listLog.SelectedIndices.Count == 0) + for (int i = 0; i < listLog.VirtualListSize; i++) + listLog.SelectedIndices.Add(i); + + GenericViewMenu.ListViewCopy(listLog, -1, listLog_RetrieveVirtualItem); + } + + private void buttonSave_Click(object sender, EventArgs e) + { + SaveFileDialog sfd = new SaveFileDialog(); + + sfd.FileName = "Process Hacker Log.txt"; + sfd.Filter = "Text Files (*.txt)|*.txt|All Files (*.*)|*.*"; + + if (sfd.ShowDialog() == DialogResult.OK) + { + StringBuilder sb = new StringBuilder(); + + foreach (var value in Program.HackerWindow.Log) + { + sb.AppendLine(value.Key.ToString() + ": " + value.Value); + } + + try + { + System.IO.File.WriteAllText(sfd.FileName, sb.ToString()); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to save the log", ex); + } + } + } + + private void buttonClear_Click(object sender, EventArgs e) + { + Program.HackerWindow.ClearLog(); + } + + private void listLog_DoubleClick(object sender, EventArgs e) + { + InformationBox info = new InformationBox(Program.HackerWindow.Log[listLog.SelectedIndices[0]].Value); + + info.ShowDialog(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/LogWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/LogWindow.resx new file mode 100644 index 000000000..c4b54ad1e --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/LogWindow.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/MemoryEditor.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/MemoryEditor.Designer.cs new file mode 100644 index 000000000..a4ab33a23 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/MemoryEditor.Designer.cs @@ -0,0 +1,315 @@ +using System; + +namespace ProcessHacker +{ + partial class MemoryEditor + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + _data = null; + hexBoxMemory.ByteProvider = null; + + Program.MemoryEditors.Remove(this.Id); + + Program.CollectGarbage(); + + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MemoryEditor)); + this.labelHexSelection = new System.Windows.Forms.TextBox(); + this.buttonValues = new System.Windows.Forms.Button(); + this.buttonGoToMemory = new System.Windows.Forms.Button(); + this.textGoTo = new System.Windows.Forms.TextBox(); + this.buttonTopFind = new System.Windows.Forms.Button(); + this.buttonNextFind = new System.Windows.Forms.Button(); + this.textSearchMemory = new System.Windows.Forms.TextBox(); + this.labelFind = new System.Windows.Forms.Label(); + this.mainMenu = new System.Windows.Forms.MainMenu(this.components); + this.menuItem1 = new System.Windows.Forms.MenuItem(); + this.menuItem6 = new System.Windows.Forms.MenuItem(); + this.writeMenuItem = new System.Windows.Forms.MenuItem(); + this.menuItem2 = new System.Windows.Forms.MenuItem(); + this.menuItem5 = new System.Windows.Forms.MenuItem(); + this.menuItem4 = new System.Windows.Forms.MenuItem(); + this.windowMenuItem = new System.Windows.Forms.MenuItem(); + this.buttonStruct = new System.Windows.Forms.Button(); + this.hexBoxMemory = new Be.Windows.Forms.HexBox(); + this.utilitiesButtonMemory = new ProcessHacker.Components.UtilitiesButton(); + this.vistaMenu = new wyDay.Controls.VistaMenu(this.components); + this.toolTip = new System.Windows.Forms.ToolTip(this.components); + ((System.ComponentModel.ISupportInitialize)(this.vistaMenu)).BeginInit(); + this.SuspendLayout(); + // + // labelHexSelection + // + this.labelHexSelection.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.labelHexSelection.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.labelHexSelection.Location = new System.Drawing.Point(12, 2); + this.labelHexSelection.Name = "labelHexSelection"; + this.labelHexSelection.ReadOnly = true; + this.labelHexSelection.Size = new System.Drawing.Size(751, 13); + this.labelHexSelection.TabIndex = 0; + this.labelHexSelection.Text = "Selection:"; + // + // buttonValues + // + this.buttonValues.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonValues.Image = global::ProcessHacker.Properties.Resources.information; + this.buttonValues.Location = new System.Drawing.Point(709, 328); + this.buttonValues.Name = "buttonValues"; + this.buttonValues.Size = new System.Drawing.Size(24, 24); + this.buttonValues.TabIndex = 9; + this.toolTip.SetToolTip(this.buttonValues, "Show Data Representations"); + this.buttonValues.UseVisualStyleBackColor = true; + this.buttonValues.Click += new System.EventHandler(this.buttonValues_Click); + // + // buttonGoToMemory + // + this.buttonGoToMemory.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.buttonGoToMemory.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonGoToMemory.Location = new System.Drawing.Point(275, 330); + this.buttonGoToMemory.Name = "buttonGoToMemory"; + this.buttonGoToMemory.Size = new System.Drawing.Size(47, 23); + this.buttonGoToMemory.TabIndex = 7; + this.buttonGoToMemory.Text = "&Go"; + this.toolTip.SetToolTip(this.buttonGoToMemory, "Go to the specified address"); + this.buttonGoToMemory.UseVisualStyleBackColor = true; + this.buttonGoToMemory.Click += new System.EventHandler(this.buttonGoToMemory_Click); + // + // textGoTo + // + this.textGoTo.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.textGoTo.Location = new System.Drawing.Point(188, 332); + this.textGoTo.Name = "textGoTo"; + this.textGoTo.Size = new System.Drawing.Size(81, 20); + this.textGoTo.TabIndex = 6; + this.textGoTo.Leave += new System.EventHandler(this.textGoTo_Leave); + this.textGoTo.Enter += new System.EventHandler(this.textGoTo_Enter); + // + // buttonTopFind + // + this.buttonTopFind.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.buttonTopFind.Image = global::ProcessHacker.Properties.Resources.arrow_up; + this.buttonTopFind.Location = new System.Drawing.Point(159, 330); + this.buttonTopFind.Name = "buttonTopFind"; + this.buttonTopFind.Size = new System.Drawing.Size(23, 23); + this.buttonTopFind.TabIndex = 5; + this.toolTip.SetToolTip(this.buttonTopFind, "Top"); + this.buttonTopFind.UseVisualStyleBackColor = true; + this.buttonTopFind.Click += new System.EventHandler(this.buttonTopFind_Click); + // + // buttonNextFind + // + this.buttonNextFind.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.buttonNextFind.Image = global::ProcessHacker.Properties.Resources.arrow_right; + this.buttonNextFind.Location = new System.Drawing.Point(130, 330); + this.buttonNextFind.Name = "buttonNextFind"; + this.buttonNextFind.Size = new System.Drawing.Size(23, 23); + this.buttonNextFind.TabIndex = 4; + this.toolTip.SetToolTip(this.buttonNextFind, "Next Result"); + this.buttonNextFind.UseVisualStyleBackColor = true; + this.buttonNextFind.Click += new System.EventHandler(this.buttonNextFind_Click); + // + // textSearchMemory + // + this.textSearchMemory.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.textSearchMemory.Location = new System.Drawing.Point(48, 332); + this.textSearchMemory.Name = "textSearchMemory"; + this.textSearchMemory.Size = new System.Drawing.Size(76, 20); + this.textSearchMemory.TabIndex = 3; + this.textSearchMemory.TextChanged += new System.EventHandler(this.textSearchMemory_TextChanged); + this.textSearchMemory.Leave += new System.EventHandler(this.textSearchMemory_Leave); + this.textSearchMemory.Enter += new System.EventHandler(this.textSearchMemory_Enter); + // + // labelFind + // + this.labelFind.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.labelFind.AutoSize = true; + this.labelFind.Location = new System.Drawing.Point(12, 335); + this.labelFind.Name = "labelFind"; + this.labelFind.Size = new System.Drawing.Size(30, 13); + this.labelFind.TabIndex = 2; + this.labelFind.Text = "Find:"; + // + // mainMenu + // + this.mainMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.menuItem1, + this.windowMenuItem}); + // + // menuItem1 + // + this.menuItem1.Index = 0; + this.menuItem1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.menuItem6, + this.writeMenuItem, + this.menuItem2, + this.menuItem5, + this.menuItem4}); + this.menuItem1.Text = "&Data"; + // + // menuItem6 + // + this.vistaMenu.SetImage(this.menuItem6, global::ProcessHacker.Properties.Resources.page); + this.menuItem6.Index = 0; + this.menuItem6.Shortcut = System.Windows.Forms.Shortcut.F5; + this.menuItem6.Text = "&Read"; + this.menuItem6.Click += new System.EventHandler(this.menuItem6_Click); + // + // writeMenuItem + // + this.vistaMenu.SetImage(this.writeMenuItem, global::ProcessHacker.Properties.Resources.page_edit); + this.writeMenuItem.Index = 1; + this.writeMenuItem.Text = "&Write"; + this.writeMenuItem.Click += new System.EventHandler(this.writeMenuItem_Click); + // + // menuItem2 + // + this.vistaMenu.SetImage(this.menuItem2, global::ProcessHacker.Properties.Resources.disk); + this.menuItem2.Index = 2; + this.menuItem2.Shortcut = System.Windows.Forms.Shortcut.CtrlS; + this.menuItem2.Text = "&Save..."; + this.menuItem2.Click += new System.EventHandler(this.menuItem2_Click); + // + // menuItem5 + // + this.menuItem5.Index = 3; + this.menuItem5.Text = "-"; + // + // menuItem4 + // + this.vistaMenu.SetImage(this.menuItem4, global::ProcessHacker.Properties.Resources.door_out); + this.menuItem4.Index = 4; + this.menuItem4.Text = "&Close"; + this.menuItem4.Click += new System.EventHandler(this.menuItem4_Click); + // + // windowMenuItem + // + this.windowMenuItem.Index = 1; + this.windowMenuItem.Text = "&Window"; + // + // buttonStruct + // + this.buttonStruct.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonStruct.Image = global::ProcessHacker.Properties.Resources.bricks; + this.buttonStruct.Location = new System.Drawing.Point(679, 328); + this.buttonStruct.Name = "buttonStruct"; + this.buttonStruct.Size = new System.Drawing.Size(24, 24); + this.buttonStruct.TabIndex = 8; + this.toolTip.SetToolTip(this.buttonStruct, "View Struct..."); + this.buttonStruct.UseVisualStyleBackColor = true; + this.buttonStruct.Click += new System.EventHandler(this.buttonStruct_Click); + // + // hexBoxMemory + // + this.hexBoxMemory.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.hexBoxMemory.Font = new System.Drawing.Font("Courier New", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.hexBoxMemory.HexCasing = Be.Windows.Forms.HexCasing.Lower; + this.hexBoxMemory.LineInfoForeColor = System.Drawing.Color.Empty; + this.hexBoxMemory.LineInfoVisible = true; + this.hexBoxMemory.Location = new System.Drawing.Point(12, 21); + this.hexBoxMemory.Name = "hexBoxMemory"; + this.hexBoxMemory.ShadowSelectionColor = System.Drawing.Color.FromArgb(((int)(((byte)(100)))), ((int)(((byte)(60)))), ((int)(((byte)(188)))), ((int)(((byte)(255))))); + this.hexBoxMemory.Size = new System.Drawing.Size(751, 301); + this.hexBoxMemory.StringViewVisible = true; + this.hexBoxMemory.TabIndex = 1; + this.hexBoxMemory.UseFixedBytesPerLine = true; + this.hexBoxMemory.VScrollBarVisible = true; + this.hexBoxMemory.SelectionStartChanged += new System.EventHandler(this.hexBoxMemory_SelectionStartChanged); + this.hexBoxMemory.SelectionLengthChanged += new System.EventHandler(this.hexBoxMemory_SelectionLengthChanged); + // + // utilitiesButtonMemory + // + this.utilitiesButtonMemory.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.utilitiesButtonMemory.HexBox = this.hexBoxMemory; + this.utilitiesButtonMemory.Location = new System.Drawing.Point(739, 328); + this.utilitiesButtonMemory.Name = "utilitiesButtonMemory"; + this.utilitiesButtonMemory.Size = new System.Drawing.Size(24, 24); + this.utilitiesButtonMemory.TabIndex = 10; + this.toolTip.SetToolTip(this.utilitiesButtonMemory, "Insert Data"); + // + // vistaMenu + // + this.vistaMenu.ContainerControl = this; + this.vistaMenu.DelaySetImageCalls = false; + // + // MemoryEditor + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(775, 364); + this.Controls.Add(this.hexBoxMemory); + this.Controls.Add(this.labelFind); + this.Controls.Add(this.utilitiesButtonMemory); + this.Controls.Add(this.textGoTo); + this.Controls.Add(this.textSearchMemory); + this.Controls.Add(this.buttonGoToMemory); + this.Controls.Add(this.labelHexSelection); + this.Controls.Add(this.buttonTopFind); + this.Controls.Add(this.buttonNextFind); + this.Controls.Add(this.buttonStruct); + this.Controls.Add(this.buttonValues); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Menu = this.mainMenu; + this.Name = "MemoryEditor"; + this.Text = "Memory Editor"; + this.Load += new System.EventHandler(this.MemoryEditor_Load); + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MemoryEditor_FormClosing); + ((System.ComponentModel.ISupportInitialize)(this.vistaMenu)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private ProcessHacker.Components.UtilitiesButton utilitiesButtonMemory; + private System.Windows.Forms.TextBox labelHexSelection; + private System.Windows.Forms.Button buttonValues; + private System.Windows.Forms.Button buttonGoToMemory; + private System.Windows.Forms.TextBox textGoTo; + private System.Windows.Forms.Button buttonTopFind; + private System.Windows.Forms.Button buttonNextFind; + private System.Windows.Forms.TextBox textSearchMemory; + private System.Windows.Forms.Label labelFind; + private Be.Windows.Forms.HexBox hexBoxMemory; + private System.Windows.Forms.MainMenu mainMenu; + private System.Windows.Forms.MenuItem menuItem1; + private System.Windows.Forms.MenuItem menuItem2; + private wyDay.Controls.VistaMenu vistaMenu; + private System.Windows.Forms.MenuItem writeMenuItem; + private System.Windows.Forms.MenuItem menuItem5; + private System.Windows.Forms.MenuItem menuItem4; + private System.Windows.Forms.MenuItem menuItem6; + private System.Windows.Forms.MenuItem windowMenuItem; + private System.Windows.Forms.Button buttonStruct; + private System.Windows.Forms.ToolTip toolTip; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/MemoryEditor.cs b/branches/ph-plugins/ProcessHacker/Forms/MemoryEditor.cs new file mode 100644 index 000000000..531b91b0b --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/MemoryEditor.cs @@ -0,0 +1,422 @@ +/* + * Process Hacker - + * memory editor window + * + * Copyright (C) 2008 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 . + */ + +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; + +namespace ProcessHacker +{ + public partial class MemoryEditor : Form + { + public static MemoryEditor ReadWriteMemory(int pid, IntPtr address, int size, bool RO) + { + return ReadWriteMemory(pid, address, size, RO, + new Program.MemoryEditorInvokeAction(delegate(MemoryEditor f) { })); + } + + public static MemoryEditor ReadWriteMemory(int pid, IntPtr address, int size, bool RO, + Program.MemoryEditorInvokeAction action) + { + try + { + MemoryEditor ed = null; + + ed = Program.GetMemoryEditor(pid, address, size, + new Program.MemoryEditorInvokeAction(delegate(MemoryEditor f) + { + if (!f.IsDisposed) + { + f.ReadOnly = RO; + f.Show(); + action(f); + f.Activate(); + } + })); + + return ed; + } + catch + { + return null; + } + } + + private int _pid; + private long _length; + private IntPtr _address; + private byte[] _data; + + public string Id + { + get { return _pid.ToString() + "-" + _address.ToString() + "-" + _length.ToString(); } + } + + public MemoryEditor(int PID, IntPtr Address, long Length) + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + _pid = PID; + _address = Address; + _length = Length; + + Program.MemoryEditors.Add(this.Id, this); + + this.Text = Program.ProcessProvider.Dictionary[_pid].Name + " (PID " + _pid.ToString() + + "), " + Utils.FormatAddress(_address) + "-" + + Utils.FormatAddress(_address.Increment(_length)) + " - Memory Editor"; + + try + { + ReadMemory(); + } + catch + { + this.Visible = false; + MessageBox.Show("Could not read process memory:\n\n" + Win32.GetLastErrorMessage(), + "Process Hacker", MessageBoxButtons.OK, MessageBoxIcon.Error); + this.Close(); + } + + hexBoxMemory.Select(); + } + + private void MemoryEditor_Load(object sender, EventArgs e) + { + Program.UpdateWindowMenu(windowMenuItem, this); + + this.Size = Properties.Settings.Default.MemoryWindowSize; + this.SetPhParent(false); + } + + private void MemoryEditor_FormClosing(object sender, FormClosingEventArgs e) + { + this.Visible = false; + + if (this.WindowState == FormWindowState.Normal) + Properties.Settings.Default.MemoryWindowSize = this.Size; + } + + public bool ReadOnly + { + get { return hexBoxMemory.ReadOnly; } + set + { + hexBoxMemory.ReadOnly = value; + + try + { + if (!value) + { + writeMenuItem.Enabled = true; + utilitiesButtonMemory.Enabled = true; + } + else + { + writeMenuItem.Enabled = false; + utilitiesButtonMemory.Enabled = false; + } + } + catch + { } + } + } + + public void Select(long start, long length) + { + hexBoxMemory.Select(start, length); + } + + private void ReadMemory() + { + using (var phandle = new ProcessHandle(_pid, Program.MinProcessReadMemoryRights)) + { + _data = new byte[_length]; + + if (phandle.ReadMemory(_address, _data, (int)_length) == 0) + throw new Exception("Unknown error."); + + hexBoxMemory.ByteProvider = new Be.Windows.Forms.DynamicByteProvider(_data); + } + } + + private void WriteMemory() + { + using (var phandle = new ProcessHandle(_pid, Program.MinProcessWriteMemoryRights)) + { + for (long i = 0; i < hexBoxMemory.ByteProvider.Length; i++) + { + _data[i] = hexBoxMemory.ByteProvider.ReadByte(i); + } + + if (phandle.WriteMemory(_address, _data) == 0) + throw new Exception("Unknown error."); + } + } + + private void buttonValues_Click(object sender, EventArgs e) + { + string values = ""; + InformationBox valuesForm; + long addr = hexBoxMemory.SelectionStart; + long space = hexBoxMemory.ByteProvider.Length - hexBoxMemory.SelectionStart; + + if (space >= 1) + values += "\r\n\r\n8-bit Integer: " + hexBoxMemory.ByteProvider.ReadByte(addr).ToString(); + + if (space >= 2) + { + ushort value = 0; + + value = (ushort)(hexBoxMemory.ByteProvider.ReadByte(addr + 1) << 8 | hexBoxMemory.ByteProvider.ReadByte(addr)); + values += "\r\n\r\n16-bit Integer, little-endian, unsigned: " + value.ToString(); + values += "\r\n16-bit Integer, little-endian, signed: " + ((short)value).ToString(); + + value = (ushort)(hexBoxMemory.ByteProvider.ReadByte(addr) << 8 | hexBoxMemory.ByteProvider.ReadByte(addr + 1)); + values += "\r\n16-bit Integer, big-endian, unsigned: " + value.ToString(); + values += "\r\n16-bit Integer, big-endian, signed: " + ((short)value).ToString(); + } + + if (space >= 4) + { + uint value = 0; + + value = ((uint)hexBoxMemory.ByteProvider.ReadByte(addr + 3) << 24) + + ((uint)hexBoxMemory.ByteProvider.ReadByte(addr + 2) << 16) + + ((uint)hexBoxMemory.ByteProvider.ReadByte(addr + 1) << 8) + + ((uint)hexBoxMemory.ByteProvider.ReadByte(addr)); + values += "\r\n\r\n32-bit Integer, little-endian, unsigned: " + value.ToString(); + values += "\r\n32-bit Integer, little-endian, signed: " + ((int)value).ToString(); + + value = ((uint)hexBoxMemory.ByteProvider.ReadByte(addr) << 24) + + ((uint)hexBoxMemory.ByteProvider.ReadByte(addr + 1) << 16) + + ((uint)hexBoxMemory.ByteProvider.ReadByte(addr + 2) << 8) + + ((uint)hexBoxMemory.ByteProvider.ReadByte(addr + 3)); + values += "\r\n32-bit Integer, big-endian, unsigned: " + value.ToString(); + values += "\r\n32-bit Integer, big-endian, signed: " + ((int)value).ToString(); + } + + if (space >= 8) + { + ulong value = 0; + + value = ((ulong)hexBoxMemory.ByteProvider.ReadByte(addr + 7) << 56) | + ((ulong)hexBoxMemory.ByteProvider.ReadByte(addr + 6) << 48) | + ((ulong)hexBoxMemory.ByteProvider.ReadByte(addr + 5) << 40) | + ((ulong)hexBoxMemory.ByteProvider.ReadByte(addr + 4) << 32) | + ((ulong)hexBoxMemory.ByteProvider.ReadByte(addr + 3) << 24) | + ((ulong)hexBoxMemory.ByteProvider.ReadByte(addr + 2) << 16) | + ((ulong)hexBoxMemory.ByteProvider.ReadByte(addr + 1) << 8) | + ((ulong)hexBoxMemory.ByteProvider.ReadByte(addr)); + values += "\r\n\r\n64-bit Integer, little-endian, unsigned: " + value.ToString(); + values += "\r\n64-bit Integer, little-endian, signed: " + ((long)value).ToString(); + + value = ((ulong)hexBoxMemory.ByteProvider.ReadByte(addr) << 56) | + ((ulong)hexBoxMemory.ByteProvider.ReadByte(addr + 1) << 48) | + ((ulong)hexBoxMemory.ByteProvider.ReadByte(addr + 2) << 40) | + ((ulong)hexBoxMemory.ByteProvider.ReadByte(addr + 3) << 32) | + ((ulong)hexBoxMemory.ByteProvider.ReadByte(addr + 4) << 24) | + ((ulong)hexBoxMemory.ByteProvider.ReadByte(addr + 5) << 16) | + ((ulong)hexBoxMemory.ByteProvider.ReadByte(addr + 6) << 8) | + ((ulong)hexBoxMemory.ByteProvider.ReadByte(addr + 7)); + values += "\r\n64-bit Integer, big-endian, unsigned: " + value.ToString(); + values += "\r\n64-bit Integer, big-endian, signed: " + ((long)value).ToString(); + } + + valuesForm = new InformationBox(values.Trim()); + valuesForm.ShowDialog(); + } + + private void UpdateHexBoxSelectionInfo() + { + labelHexSelection.Text = + string.Format("Selection: 0x{0:x}, length 0x{1:x}", + hexBoxMemory.SelectionStart, hexBoxMemory.SelectionLength); + } + + private void hexBoxMemory_SelectionLengthChanged(object sender, EventArgs e) + { + UpdateHexBoxSelectionInfo(); + } + + private void hexBoxMemory_SelectionStartChanged(object sender, EventArgs e) + { + UpdateHexBoxSelectionInfo(); + } + + private void menuItem6_Click(object sender, EventArgs e) + { + try + { + _data = null; + ReadMemory(); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to read process memory", ex); + } + } + + private void writeMenuItem_Click(object sender, EventArgs e) + { + try + { + WriteMemory(); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to write to process memory", ex); + } + } + + private void menuItem2_Click(object sender, EventArgs e) + { + SaveFileDialog sfd = new SaveFileDialog(); + + try + { + using (var phandle = new ProcessHandle(_pid, Program.MinProcessQueryRights)) + { + string fileName = phandle.GetImageFileName(); + + sfd.FileName = fileName.Substring(fileName.LastIndexOf('\\') + 1) + "-" + Utils.FormatAddress(_address) + ".bin"; + } + } + catch + { + sfd.FileName = "memory.bin"; + } + + if (sfd.ShowDialog() == DialogResult.OK) + { + for (long i = 0; i < hexBoxMemory.ByteProvider.Length; i++) + { + _data[i] = hexBoxMemory.ByteProvider.ReadByte(i); + } + + System.IO.File.WriteAllBytes(sfd.FileName, _data); + } + } + + private void menuItem4_Click(object sender, EventArgs e) + { + this.Close(); + } + + private void textGoTo_Enter(object sender, EventArgs e) + { + this.AcceptButton = buttonGoToMemory; + } + + private void textGoTo_Leave(object sender, EventArgs e) + { + this.AcceptButton = null; + } + + private void textSearchMemory_Enter(object sender, EventArgs e) + { + this.AcceptButton = buttonNextFind; + } + + private void textSearchMemory_Leave(object sender, EventArgs e) + { + this.AcceptButton = null; + } + + private void textSearchMemory_TextChanged(object sender, EventArgs e) + { + try + { + byte[] data = new byte[textSearchMemory.Text.Length]; + + for (int i = 0; i < textSearchMemory.Text.Length; i++) + data[i] = (byte)textSearchMemory.Text[i]; + + hexBoxMemory.Find(data, hexBoxMemory.SelectionStart + hexBoxMemory.SelectionLength); + } + catch { } + } + + private void buttonNextFind_Click(object sender, EventArgs e) + { + hexBoxMemory.Select(hexBoxMemory.SelectionStart + hexBoxMemory.SelectionLength, 0); + textSearchMemory_TextChanged(null, null); + } + + private void buttonTopFind_Click(object sender, EventArgs e) + { + hexBoxMemory.Select(0, 1); + } + + private void buttonGoToMemory_Click(object sender, EventArgs e) + { + try + { + int location = (int)BaseConverter.ToNumberParse(textGoTo.Text); + + if (location < hexBoxMemory.ByteProvider.Length) + hexBoxMemory.Select(location, 1); + } + catch { } + } + + private void buttonStruct_Click(object sender, EventArgs e) + { + int selectionStart = (int)hexBoxMemory.SelectionStart; + + List structNames = new List(Program.Structs.Keys); + + structNames.Sort(); + + ListPickerWindow lpw = new ListPickerWindow(structNames.ToArray()); + + lpw.Text = "Select a Struct"; + + if (lpw.ShowDialog() == DialogResult.OK) + { + if (Program.Structs.ContainsKey(lpw.SelectedItem)) + { + // stupid TreeViewAdv only works on the one thread + Program.HackerWindow.BeginInvoke(new MethodInvoker(delegate + { + StructWindow sw = new StructWindow(_pid, (_address.Increment(selectionStart)), + Program.Structs[lpw.SelectedItem]); + + try + { + sw.Show(); + sw.Activate(); + } + catch + { } + })); + } + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/MemoryEditor.resx b/branches/ph-plugins/ProcessHacker/Forms/MemoryEditor.resx new file mode 100644 index 000000000..434f2b895 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/MemoryEditor.resx @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 235, 17 + + + 17, 17 + + + 127, 17 + + + + + AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAumkza7lkL7y6ZTDtuWUv97llL/e5ZS/3uWQv97lkLve4ZC33uGQt97hjLfe4Yy3vtmErvbZh + LWMAAAAAAAAAALtoMt748ery9+zf/fbr3v/26t7/9urc//bq3P/68+v/+vPr//ry6v/89/P//Pj0/f7+ + /fC2XynVAAAAAAAAAAC+cDf19evf/v2+Z//8vGb/+71k//y9Y//8vWP//Lxh//u8Yv/7u2D//L1f//y7 + Yf/9+/j9uGMs8wAAAAAAAAAAwHc79/ft4//9wW3/F0FW/ypghv9LiLv/b56y/+PJmf//1pT//9WT///U + kv/7vWT/+/f0/7pmMPcAAAAAAAAAAMN7P/f38Ob/+LNU/y1lgf+Tx/n/kMn5/0CEyf8lZ6X/0qdk//ex + UP/3sU7/97FO//z59f++bjX3AAAAAAAAAADEf0H3+PHo//7l1f9CiKn/4PL//1OZ2P8Zeb3/SJfE/0eL + wf/a0s3/++DJ//vhyP/9+vf/wHU69wAAAAAAAAAAxIFE9/jy6//+59b/pbW+/3m11f+PttH/VMnk/1rf + 9f930O3/UJrZ/+HWzf/74cn/+/fy/8R7PvcAAAAAAAAAAMWDRvf58+z//ujW//7o1/+yxcz/dbjW/8H2 + /f9i3/f/XOL4/3jT8P9Il9r/4tXI//ry6v/Ff0H3AAAAAAAAAADFh0j3+fTt//7o2P/+6Nj//ujX/6/F + zP92y+f/x/f9/13c9f9Z4ff/etTx/0qY2//S3+n/xYFE9wAAAAAAAAAAxYdJ9/n07//+59f//efW//3n + 1f/95tT/vNbV/3jT7v/H9/3/Xtz1/1ri9/951vL/UKDg/6yEX/kAAAAAAAAAAMWISvf59PD//ObT//zm + 1P/959P//OTR//vjzf+91ND/fNTu/8P2/f9r3fb/bMrt/2Ki1/9jmMj+UJHKJgAAAADFiEr3+fXx//zj + z//75ND//OTP//zjzf/64cr/+d3D/67Nyf+A1e7/seP5/4q/5/+t0/b/w+D8/2We0/cAAAAAxYhL9vn1 + 8f/8483/++PO//vjzf/74sv/+eDI//jcwf/11rn/ruPx/3a95/+z0vD/5fP//6vS7/9Hi8foAAAAAMSH + Sur69vL8+uDH//vhyf/74sn/++DI//nfxP/428D/9Na3///7+P+1y8H/V6TY/4Sw2/9FnND/KpTRXgAA + AADDhEjD9/Ls7Pj07vz49O3/+PPt//jz7f/48+3/+PLs//fy7P/y5tf/4rF8/9uTZPWyZzoHAAAAAAAA + AAAAAAAAwHxDYMiKTLvIi07uyItO9siLTvfIi073yIxO98mLTvfHik73xIhK1MN1OpGyZzsGAAAAAAAA + AAAAAAAAgAGsQYABrEGAAaxBgAGsQYABrEGAAaxBgAGsQYABrEGAAaxBgAGsQYAArEGAAKxBgACsQYAA + rEGAA6xBgAesQQ== + + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/MessageBoxWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/MessageBoxWindow.Designer.cs new file mode 100644 index 000000000..0ba239b6a --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/MessageBoxWindow.Designer.cs @@ -0,0 +1,191 @@ +namespace ProcessHacker +{ + partial class MessageBoxWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.textTitle = new System.Windows.Forms.TextBox(); + this.textText = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.comboIcon = new System.Windows.Forms.ComboBox(); + this.textTimeout = new System.Windows.Forms.TextBox(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.buttonOK = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 15); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(30, 13); + this.label1.TabIndex = 6; + this.label1.Text = "Title:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(12, 41); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(31, 13); + this.label2.TabIndex = 7; + this.label2.Text = "Text:"; + // + // textTitle + // + this.textTitle.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textTitle.Location = new System.Drawing.Point(49, 12); + this.textTitle.Name = "textTitle"; + this.textTitle.Size = new System.Drawing.Size(354, 20); + this.textTitle.TabIndex = 0; + // + // textText + // + this.textText.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textText.Location = new System.Drawing.Point(49, 38); + this.textText.Multiline = true; + this.textText.Name = "textText"; + this.textText.Size = new System.Drawing.Size(354, 108); + this.textText.TabIndex = 1; + // + // label3 + // + this.label3.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(12, 155); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(31, 13); + this.label3.TabIndex = 8; + this.label3.Text = "Icon:"; + // + // label4 + // + this.label4.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(12, 182); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(62, 13); + this.label4.TabIndex = 9; + this.label4.Text = "Timeout (s):"; + // + // comboIcon + // + this.comboIcon.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.comboIcon.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboIcon.FormattingEnabled = true; + this.comboIcon.Items.AddRange(new object[] { + "None", + "Error", + "Information", + "Question", + "Warning"}); + this.comboIcon.Location = new System.Drawing.Point(49, 152); + this.comboIcon.Name = "comboIcon"; + this.comboIcon.Size = new System.Drawing.Size(354, 21); + this.comboIcon.TabIndex = 2; + // + // textTimeout + // + this.textTimeout.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.textTimeout.Location = new System.Drawing.Point(80, 179); + this.textTimeout.Name = "textTimeout"; + this.textTimeout.Size = new System.Drawing.Size(100, 20); + this.textTimeout.TabIndex = 3; + // + // buttonCancel + // + this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonCancel.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonCancel.Location = new System.Drawing.Point(328, 205); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.TabIndex = 5; + this.buttonCancel.Text = "Cancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click); + // + // buttonOK + // + this.buttonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonOK.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonOK.Location = new System.Drawing.Point(247, 205); + this.buttonOK.Name = "buttonOK"; + this.buttonOK.Size = new System.Drawing.Size(75, 23); + this.buttonOK.TabIndex = 4; + this.buttonOK.Text = "OK"; + this.buttonOK.UseVisualStyleBackColor = true; + this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click); + // + // MessageBoxWindow + // + this.AcceptButton = this.buttonOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(415, 240); + this.Controls.Add(this.buttonOK); + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.textTimeout); + this.Controls.Add(this.comboIcon); + this.Controls.Add(this.label4); + this.Controls.Add(this.label3); + this.Controls.Add(this.textText); + this.Controls.Add(this.textTitle); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "MessageBoxWindow"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Message Box"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox textTitle; + private System.Windows.Forms.TextBox textText; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.ComboBox comboIcon; + private System.Windows.Forms.TextBox textTimeout; + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.Button buttonOK; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/MessageBoxWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/MessageBoxWindow.cs new file mode 100644 index 000000000..d7f0aee79 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/MessageBoxWindow.cs @@ -0,0 +1,84 @@ +using System.Windows.Forms; + +namespace ProcessHacker +{ + public delegate bool DialogButtonClickedDelegate(); + + public partial class MessageBoxWindow : Form + { + public event DialogButtonClickedDelegate OkButtonClicked; + + public MessageBoxWindow() + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + comboIcon.SelectedItem = "None"; + } + + public MessageBoxIcon MessageBoxIcon + { + get + { + switch (comboIcon.SelectedItem.ToString()) + { + case "None": + return MessageBoxIcon.None; + case "Error": + return MessageBoxIcon.Error; + case "Information": + return MessageBoxIcon.Information; + case "Question": + return MessageBoxIcon.Question; + case "Warning": + return MessageBoxIcon.Warning; + default: + return MessageBoxIcon.None; + } + } + } + + public string MessageBoxText + { + get { return textText.Text; } + set { textText.Text = value; } + } + + public int MessageBoxTimeout + { + get + { + int timeout = 0; + + int.TryParse(textTimeout.Text, out timeout); + + return timeout; + } + } + + public string MessageBoxTitle + { + get { return textTitle.Text; } + set { textTitle.Text = value; } + } + + private void buttonOK_Click(object sender, System.EventArgs e) + { + if (OkButtonClicked != null) + { + if (OkButtonClicked()) + { + this.DialogResult = DialogResult.OK; + this.Close(); + } + } + } + + private void buttonCancel_Click(object sender, System.EventArgs e) + { + this.DialogResult = DialogResult.Cancel; + this.Close(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/MessageBoxWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/MessageBoxWindow.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/MessageBoxWindow.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/MiniSysInfo.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/MiniSysInfo.Designer.cs new file mode 100644 index 000000000..4e9ff9048 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/MiniSysInfo.Designer.cs @@ -0,0 +1,117 @@ +namespace ProcessHacker +{ + partial class MiniSysInfo + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.plotterCPU = new ProcessHacker.Components.Plotter(); + this.plotterIO = new ProcessHacker.Components.Plotter(); + this.SuspendLayout(); + // + // plotterCPU + // + this.plotterCPU.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.plotterCPU.Data1 = null; + this.plotterCPU.Data2 = null; + this.plotterCPU.GridColor = System.Drawing.Color.Green; + this.plotterCPU.GridSize = new System.Drawing.Size(12, 12); + this.plotterCPU.LineColor1 = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(255)))), ((int)(((byte)(0))))); + this.plotterCPU.LineColor2 = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(0)))), ((int)(((byte)(0))))); + this.plotterCPU.Location = new System.Drawing.Point(0, 0); + this.plotterCPU.LongData1 = null; + this.plotterCPU.LongData2 = null; + this.plotterCPU.MinMaxValue = ((long)(0)); + this.plotterCPU.MoveStep = 3; + this.plotterCPU.Name = "plotterCPU"; + this.plotterCPU.OverlaySecondLine = false; + this.plotterCPU.ShowGrid = true; + this.plotterCPU.Size = new System.Drawing.Size(238, 50); + this.plotterCPU.TabIndex = 0; + this.plotterCPU.TextBoxColor = System.Drawing.Color.FromArgb(((int)(((byte)(127)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0))))); + this.plotterCPU.TextColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(255)))), ((int)(((byte)(0))))); + this.plotterCPU.TextMargin = new System.Windows.Forms.Padding(3); + this.plotterCPU.TextPadding = new System.Windows.Forms.Padding(3); + this.plotterCPU.TextPosition = System.Drawing.ContentAlignment.TopLeft; + this.plotterCPU.UseLongData = false; + this.plotterCPU.UseSecondLine = true; + // + // plotterIO + // + this.plotterIO.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.plotterIO.Data1 = null; + this.plotterIO.Data2 = null; + this.plotterIO.GridColor = System.Drawing.Color.Green; + this.plotterIO.GridSize = new System.Drawing.Size(12, 12); + this.plotterIO.LineColor1 = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(255)))), ((int)(((byte)(0))))); + this.plotterIO.LineColor2 = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(0)))), ((int)(((byte)(0))))); + this.plotterIO.Location = new System.Drawing.Point(0, 56); + this.plotterIO.LongData1 = null; + this.plotterIO.LongData2 = null; + this.plotterIO.MinMaxValue = ((long)(0)); + this.plotterIO.MoveStep = 3; + this.plotterIO.Name = "plotterIO"; + this.plotterIO.OverlaySecondLine = false; + this.plotterIO.ShowGrid = true; + this.plotterIO.Size = new System.Drawing.Size(238, 50); + this.plotterIO.TabIndex = 1; + this.plotterIO.TextBoxColor = System.Drawing.Color.FromArgb(((int)(((byte)(127)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0))))); + this.plotterIO.TextColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(255)))), ((int)(((byte)(0))))); + this.plotterIO.TextMargin = new System.Windows.Forms.Padding(3); + this.plotterIO.TextPadding = new System.Windows.Forms.Padding(3); + this.plotterIO.TextPosition = System.Drawing.ContentAlignment.TopLeft; + this.plotterIO.UseLongData = true; + this.plotterIO.UseSecondLine = true; + // + // MiniSysInfo + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.Black; + this.ClientSize = new System.Drawing.Size(238, 192); + this.Controls.Add(this.plotterIO); + this.Controls.Add(this.plotterCPU); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "MiniSysInfo"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.Manual; + this.Deactivate += new System.EventHandler(this.MiniSysInfo_Deactivate); + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MiniSysInfo_FormClosing); + this.ResumeLayout(false); + + } + + #endregion + + private ProcessHacker.Components.Plotter plotterCPU; + private ProcessHacker.Components.Plotter plotterIO; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/MiniSysInfo.cs b/branches/ph-plugins/ProcessHacker/Forms/MiniSysInfo.cs new file mode 100644 index 000000000..e091e9d07 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/MiniSysInfo.cs @@ -0,0 +1,107 @@ +/* + * Process Hacker - + * mini-graph + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using ProcessHacker.Native.Api; + +namespace ProcessHacker +{ + public partial class MiniSysInfo : Form + { + [StructLayout(LayoutKind.Sequential)] + struct MARGINS + { + public int Left; + public int Right; + public int Top; + public int Bottom; + } + + [DllImport("dwmapi.dll", SetLastError = true)] + static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS inset); + + MARGINS margins = new MARGINS() { Left = -1, Right = -1, Top = -1, Bottom = -1 }; + + public MiniSysInfo() + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + DwmExtendFrameIntoClientArea(this.Handle, ref margins); + + plotterCPU.BackColor = Color.FromArgb(255, 0, 0, 0); + plotterCPU.Draw(); + plotterCPU.Data1 = Program.ProcessProvider.FloatHistory["Kernel"]; + plotterCPU.Data2 = Program.ProcessProvider.FloatHistory["User"]; + + plotterIO.BackColor = Color.FromArgb(255, 0, 0, 0); + plotterIO.Draw(); + plotterIO.LongData1 = Program.ProcessProvider.LongHistory[SystemStats.IoReadOther]; + plotterIO.LongData2 = Program.ProcessProvider.LongHistory[SystemStats.IoWrite]; + + Program.ProcessProvider.Updated += new ProcessSystemProvider.ProviderUpdateOnce(ProcessProvider_Updated); + } + + protected override void WndProc(ref Message m) + { + base.WndProc(ref m); + + if (m.Msg == (int)WindowMessage.NcCalcSize) + { + if (m.WParam.ToInt32() != 0) + { + m.Result = new IntPtr(0); + } + } + } + + private void MiniSysInfo_Deactivate(object sender, EventArgs e) + { + this.Close(); + } + + private void MiniSysInfo_FormClosing(object sender, FormClosingEventArgs e) + { + Program.ProcessProvider.Updated -= new ProcessSystemProvider.ProviderUpdateOnce(ProcessProvider_Updated); + } + + private void ProcessProvider_Updated() + { + this.BeginInvoke(new MethodInvoker(delegate + { + plotterCPU.LineColor1 = Properties.Settings.Default.PlotterCPUKernelColor; + plotterCPU.LineColor2 = Properties.Settings.Default.PlotterCPUUserColor; + plotterCPU.MoveGrid(); + plotterCPU.Draw(); + + plotterIO.LineColor1 = Properties.Settings.Default.PlotterIOROColor; + plotterIO.LineColor2 = Properties.Settings.Default.PlotterIOWColor; + plotterIO.MoveGrid(); + plotterIO.Draw(); + })); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/MiniSysInfo.resx b/branches/ph-plugins/ProcessHacker/Forms/MiniSysInfo.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/MiniSysInfo.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/NetInfoWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/NetInfoWindow.Designer.cs new file mode 100644 index 000000000..549b40492 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/NetInfoWindow.Designer.cs @@ -0,0 +1,445 @@ +namespace ProcessHacker +{ + partial class NetInfoWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.label15 = new System.Windows.Forms.Label(); + this.label14 = new System.Windows.Forms.Label(); + this.label13 = new System.Windows.Forms.Label(); + this.label12 = new System.Windows.Forms.Label(); + this.label11 = new System.Windows.Forms.Label(); + this.label10 = new System.Windows.Forms.Label(); + this.label9 = new System.Windows.Forms.Label(); + this.label8 = new System.Windows.Forms.Label(); + this.label7 = new System.Windows.Forms.Label(); + this.label6 = new System.Windows.Forms.Label(); + this.label5 = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.groupBox3 = new System.Windows.Forms.GroupBox(); + this.label20 = new System.Windows.Forms.Label(); + this.label19 = new System.Windows.Forms.Label(); + this.label18 = new System.Windows.Forms.Label(); + this.label17 = new System.Windows.Forms.Label(); + this.label16 = new System.Windows.Forms.Label(); + this.timer1 = new System.Windows.Forms.Timer(this.components); + this.label21 = new System.Windows.Forms.Label(); + this.label22 = new System.Windows.Forms.Label(); + this.label23 = new System.Windows.Forms.Label(); + this.label24 = new System.Windows.Forms.Label(); + this.label25 = new System.Windows.Forms.Label(); + this.label26 = new System.Windows.Forms.Label(); + this.plotter1 = new ProcessHacker.Components.Plotter(); + this.groupBox1.SuspendLayout(); + this.groupBox2.SuspendLayout(); + this.groupBox3.SuspendLayout(); + this.SuspendLayout(); + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.label15); + this.groupBox1.Controls.Add(this.label14); + this.groupBox1.Controls.Add(this.label13); + this.groupBox1.Controls.Add(this.label12); + this.groupBox1.Controls.Add(this.label11); + this.groupBox1.Controls.Add(this.label10); + this.groupBox1.Controls.Add(this.label9); + this.groupBox1.Controls.Add(this.label8); + this.groupBox1.Controls.Add(this.label7); + this.groupBox1.Controls.Add(this.label6); + this.groupBox1.Controls.Add(this.label5); + this.groupBox1.Controls.Add(this.label4); + this.groupBox1.Controls.Add(this.label3); + this.groupBox1.Controls.Add(this.label2); + this.groupBox1.Controls.Add(this.label1); + this.groupBox1.Location = new System.Drawing.Point(12, 111); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(355, 186); + this.groupBox1.TabIndex = 1; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "TCP Stats"; + // + // label15 + // + this.label15.AutoSize = true; + this.label15.Location = new System.Drawing.Point(122, 157); + this.label15.Name = "label15"; + this.label15.Size = new System.Drawing.Size(41, 13); + this.label15.TabIndex = 14; + this.label15.Text = "label15"; + // + // label14 + // + this.label14.AutoSize = true; + this.label14.Location = new System.Drawing.Point(122, 133); + this.label14.Name = "label14"; + this.label14.Size = new System.Drawing.Size(41, 13); + this.label14.TabIndex = 13; + this.label14.Text = "label14"; + // + // label13 + // + this.label13.AutoSize = true; + this.label13.Location = new System.Drawing.Point(122, 105); + this.label13.Name = "label13"; + this.label13.Size = new System.Drawing.Size(41, 13); + this.label13.TabIndex = 12; + this.label13.Text = "label13"; + // + // label12 + // + this.label12.AutoSize = true; + this.label12.Location = new System.Drawing.Point(6, 157); + this.label12.Name = "label12"; + this.label12.Size = new System.Drawing.Size(41, 13); + this.label12.TabIndex = 11; + this.label12.Text = "label12"; + // + // label11 + // + this.label11.AutoSize = true; + this.label11.Location = new System.Drawing.Point(6, 133); + this.label11.Name = "label11"; + this.label11.Size = new System.Drawing.Size(41, 13); + this.label11.TabIndex = 10; + this.label11.Text = "label11"; + // + // label10 + // + this.label10.AutoSize = true; + this.label10.Location = new System.Drawing.Point(6, 105); + this.label10.Name = "label10"; + this.label10.Size = new System.Drawing.Size(41, 13); + this.label10.TabIndex = 9; + this.label10.Text = "label10"; + // + // label9 + // + this.label9.AutoSize = true; + this.label9.Location = new System.Drawing.Point(231, 75); + this.label9.Name = "label9"; + this.label9.Size = new System.Drawing.Size(35, 13); + this.label9.TabIndex = 8; + this.label9.Text = "label9"; + // + // label8 + // + this.label8.AutoSize = true; + this.label8.Location = new System.Drawing.Point(231, 51); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(35, 13); + this.label8.TabIndex = 7; + this.label8.Text = "label8"; + // + // label7 + // + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(231, 28); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(35, 13); + this.label7.TabIndex = 6; + this.label7.Text = "label7"; + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(122, 75); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(35, 13); + this.label6.TabIndex = 5; + this.label6.Text = "label6"; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(122, 51); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(35, 13); + this.label5.TabIndex = 4; + this.label5.Text = "label5"; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(122, 28); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(35, 13); + this.label4.TabIndex = 3; + this.label4.Text = "label4"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(6, 75); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(35, 13); + this.label3.TabIndex = 2; + this.label3.Text = "label3"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(6, 51); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(35, 13); + this.label2.TabIndex = 1; + this.label2.Text = "label2"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(6, 28); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(35, 13); + this.label1.TabIndex = 0; + this.label1.Text = "label1"; + // + // groupBox2 + // + this.groupBox2.Controls.Add(this.plotter1); + this.groupBox2.Location = new System.Drawing.Point(12, 5); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(551, 100); + this.groupBox2.TabIndex = 2; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "Network Usage"; + // + // groupBox3 + // + this.groupBox3.Controls.Add(this.label20); + this.groupBox3.Controls.Add(this.label19); + this.groupBox3.Controls.Add(this.label18); + this.groupBox3.Controls.Add(this.label17); + this.groupBox3.Controls.Add(this.label16); + this.groupBox3.Location = new System.Drawing.Point(373, 111); + this.groupBox3.Name = "groupBox3"; + this.groupBox3.Size = new System.Drawing.Size(190, 186); + this.groupBox3.TabIndex = 3; + this.groupBox3.TabStop = false; + this.groupBox3.Text = "UDP Stats"; + // + // label20 + // + this.label20.AutoSize = true; + this.label20.Location = new System.Drawing.Point(6, 105); + this.label20.Name = "label20"; + this.label20.Size = new System.Drawing.Size(41, 13); + this.label20.TabIndex = 11; + this.label20.Text = "label20"; + // + // label19 + // + this.label19.AutoSize = true; + this.label19.Location = new System.Drawing.Point(114, 28); + this.label19.Name = "label19"; + this.label19.Size = new System.Drawing.Size(41, 13); + this.label19.TabIndex = 10; + this.label19.Text = "label19"; + // + // label18 + // + this.label18.AutoSize = true; + this.label18.Location = new System.Drawing.Point(114, 64); + this.label18.Name = "label18"; + this.label18.Size = new System.Drawing.Size(41, 13); + this.label18.TabIndex = 9; + this.label18.Text = "label18"; + // + // label17 + // + this.label17.AutoSize = true; + this.label17.Location = new System.Drawing.Point(6, 64); + this.label17.Name = "label17"; + this.label17.Size = new System.Drawing.Size(41, 13); + this.label17.TabIndex = 8; + this.label17.Text = "label17"; + // + // label16 + // + this.label16.AutoSize = true; + this.label16.Location = new System.Drawing.Point(6, 28); + this.label16.Name = "label16"; + this.label16.Size = new System.Drawing.Size(41, 13); + this.label16.TabIndex = 7; + this.label16.Text = "label16"; + // + // timer1 + // + this.timer1.Enabled = true; + this.timer1.Interval = 1000; + this.timer1.Tick += new System.EventHandler(this.timer1_Tick); + // + // label21 + // + this.label21.AutoSize = true; + this.label21.Location = new System.Drawing.Point(18, 309); + this.label21.Name = "label21"; + this.label21.Size = new System.Drawing.Size(41, 13); + this.label21.TabIndex = 16; + this.label21.Text = "label21"; + // + // label22 + // + this.label22.AutoSize = true; + this.label22.Location = new System.Drawing.Point(18, 331); + this.label22.Name = "label22"; + this.label22.Size = new System.Drawing.Size(41, 13); + this.label22.TabIndex = 15; + this.label22.Text = "label22"; + // + // label23 + // + this.label23.AutoSize = true; + this.label23.Location = new System.Drawing.Point(169, 309); + this.label23.Name = "label23"; + this.label23.Size = new System.Drawing.Size(41, 13); + this.label23.TabIndex = 18; + this.label23.Text = "label23"; + // + // label24 + // + this.label24.AutoSize = true; + this.label24.Location = new System.Drawing.Point(169, 331); + this.label24.Name = "label24"; + this.label24.Size = new System.Drawing.Size(41, 13); + this.label24.TabIndex = 17; + this.label24.Text = "label24"; + // + // label25 + // + this.label25.AutoSize = true; + this.label25.Location = new System.Drawing.Point(308, 309); + this.label25.Name = "label25"; + this.label25.Size = new System.Drawing.Size(41, 13); + this.label25.TabIndex = 20; + this.label25.Text = "label25"; + // + // label26 + // + this.label26.AutoSize = true; + this.label26.Location = new System.Drawing.Point(308, 331); + this.label26.Name = "label26"; + this.label26.Size = new System.Drawing.Size(41, 13); + this.label26.TabIndex = 19; + this.label26.Text = "label26"; + // + // plotter1 + // + this.plotter1.BackColor = System.Drawing.Color.Black; + this.plotter1.Data1 = null; + this.plotter1.Data2 = null; + this.plotter1.GridColor = System.Drawing.Color.Green; + this.plotter1.GridSize = new System.Drawing.Size(12, 12); + this.plotter1.LineColor1 = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(255)))), ((int)(((byte)(0))))); + this.plotter1.LineColor2 = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(0)))), ((int)(((byte)(0))))); + this.plotter1.Location = new System.Drawing.Point(6, 19); + this.plotter1.LongData1 = null; + this.plotter1.LongData2 = null; + this.plotter1.MinMaxValue = ((long)(0)); + this.plotter1.MoveStep = -1; + this.plotter1.Name = "plotter1"; + this.plotter1.OverlaySecondLine = true; + this.plotter1.ShowGrid = true; + this.plotter1.Size = new System.Drawing.Size(538, 71); + this.plotter1.TabIndex = 0; + this.plotter1.TextBoxColor = System.Drawing.Color.FromArgb(((int)(((byte)(127)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0))))); + this.plotter1.TextColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(255)))), ((int)(((byte)(0))))); + this.plotter1.TextMargin = new System.Windows.Forms.Padding(3); + this.plotter1.TextPadding = new System.Windows.Forms.Padding(3); + this.plotter1.TextPosition = System.Drawing.ContentAlignment.TopLeft; + this.plotter1.UseLongData = false; + this.plotter1.UseSecondLine = true; + // + // NetInfoWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(573, 353); + this.Controls.Add(this.label25); + this.Controls.Add(this.label26); + this.Controls.Add(this.label23); + this.Controls.Add(this.label24); + this.Controls.Add(this.label21); + this.Controls.Add(this.label22); + this.Controls.Add(this.groupBox3); + this.Controls.Add(this.groupBox2); + this.Controls.Add(this.groupBox1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.Name = "NetInfoWindow"; + this.Text = "Network Infomation"; + this.Load += new System.EventHandler(this.NetInfoWindow_Load); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.groupBox2.ResumeLayout(false); + this.groupBox3.ResumeLayout(false); + this.groupBox3.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private ProcessHacker.Components.Plotter plotter1; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.Label label15; + private System.Windows.Forms.Label label14; + private System.Windows.Forms.Label label13; + private System.Windows.Forms.Label label12; + private System.Windows.Forms.Label label11; + private System.Windows.Forms.Label label10; + private System.Windows.Forms.Label label9; + private System.Windows.Forms.Label label8; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.GroupBox groupBox2; + private System.Windows.Forms.GroupBox groupBox3; + private System.Windows.Forms.Label label20; + private System.Windows.Forms.Label label19; + private System.Windows.Forms.Label label18; + private System.Windows.Forms.Label label17; + private System.Windows.Forms.Label label16; + private System.Windows.Forms.Timer timer1; + private System.Windows.Forms.Label label21; + private System.Windows.Forms.Label label22; + private System.Windows.Forms.Label label23; + private System.Windows.Forms.Label label24; + private System.Windows.Forms.Label label25; + private System.Windows.Forms.Label label26; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/NetInfoWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/NetInfoWindow.cs new file mode 100644 index 000000000..5d1ea3f61 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/NetInfoWindow.cs @@ -0,0 +1,377 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Text; +using System.Windows.Forms; +using ProcessHacker.Native.Api; +using System.Diagnostics; +using System.Timers; +using System.Collections; +using System.Net.NetworkInformation; +using ProcessHacker.Common; + +namespace ProcessHacker +{ + public partial class NetInfoWindow : Form + { + public NetInfoWindow() + { + InitializeComponent(); + } + + public HistoryManager FloatHistory { get { return _floatHistory; } } + + private HistoryManager _floatHistory = new HistoryManager(); + + private void NetInfoWindow_Load(object sender, EventArgs e) + { + _floatHistory.Add("up"); + _floatHistory.Add("down"); + plotter1.Data1 = FloatHistory["up"]; + plotter1.Data2 = FloatHistory["down"]; + + this._monitor = new NetworkMonitor(); + this._monitor.StopMonitoring(); + this._monitor.StartMonitoring(); + } + + private ProcessHacker.NetworkMonitor _monitor; + + private void getStats() + { + MibTcpStats mtcp = Win32.GetTcpStats(); + label1.Text = String.Format("ActiveOpens: {0}", mtcp.ActiveOpens); + label2.Text = String.Format("AttemptFails: {0}", mtcp.AttemptFails); + label3.Text = String.Format("CurrEstab: {0}", mtcp.CurrEstab); + label4.Text = String.Format("EstabResets: {0}", mtcp.EstabResets); + label5.Text = String.Format("InErrs: {0}", mtcp.InErrs); + label6.Text = String.Format("InSegs: {0}", mtcp.InSegs); + label7.Text = String.Format("MaxConn: {0}", mtcp.MaxConn); + label8.Text = String.Format("NumConns: {0}", mtcp.NumConns); + label9.Text = String.Format("OutRsts: {0}", mtcp.OutRsts); + label10.Text = String.Format("OutSegs: {0}", mtcp.OutSegs); + label11.Text = String.Format("PassiveOpens: {0}", mtcp.PassiveOpens); + label12.Text = String.Format("RetransSegs: {0}", mtcp.RetransSegs); + label13.Text = String.Format("RtoAlgorithm: {0}", mtcp.RtoAlgorithm); + label14.Text = String.Format("RtoMax: {0}", mtcp.RtoMax); + label15.Text = String.Format("RtoMin: {0}", mtcp.RtoMin); + + MibUdpStats mudp = Win32.GetUdpStats(); + label16.Text = String.Format("InDatagrams: {0}", mudp.InDatagrams); + label17.Text = String.Format("InErrors: {0}", mudp.InErrors); + label18.Text = String.Format("NoPorts: {0}", mudp.NoPorts); + label19.Text = String.Format("NumAddrs: {0}", mudp.NumAddrs); + label20.Text = String.Format("OutDatagrams: {0}", mudp.OutDatagrams); + } + + private void timer1_Tick(object sender, EventArgs e) + { + getStats(); + + foreach (NetworkAdapter i in _monitor.Adapters) + { + try + { + int down = unchecked((int)Convert.ToInt32(Math.Round(i.DownloadSpeedKbps, 0))); + int up = unchecked((int)Convert.ToInt32(Math.Round(i.DownloadSpeedKbps, 0))); + + this.label25.Text = up.ToString(); + this.label26.Text = down.ToString(); + + plotter1.Data1 = FloatHistory["up"]; + plotter1.Data2 = FloatHistory["down"]; + _floatHistory.Update("up", (float)i.UploadSpeedKbps); + _floatHistory.Update("down", (float)i.DownloadSpeedKbps); + plotter1.MoveGrid(); + plotter1.Draw(); + + this.label21.Text = String.Format("U: {0:n}kbps", i.UploadSpeedKbps); + this.label22.Text = String.Format("D: {0:n}kbps", i.DownloadSpeedKbps); + + NetworkInformation nic = new NetworkInformation(); + + this.label23.Text = "TSen: " + nic.BytesSent(0).ToString(); + this.label24.Text = "TRec: " + nic.BytesReceived(0).ToString(); + + } + catch (Exception) + { + } + } + } + } + +/// +/// Represents a network adapter installed on the machine. +/// Properties of this class can be used to obtain current network speed. +/// +public class NetworkAdapter +{ + + //http://www.dotnet247.com/247reference/System/Net/NetworkInformation/System.Net.NetworkInformation.aspx + //MibTcpStats plus others are locatated in NetworkInfomation class + + /// + /// Instances of this class are supposed to be created only in an NetworkMonitor. + /// + internal NetworkAdapter(string name) + { + this.name = name; + } + + private long dlSpeed, ulSpeed; // Download\Upload speed in bytes per second. + private long dlValue, ulValue; // Download\Upload counter value in bytes. + private long dlValueOld, ulValueOld; // Download\Upload counter value one second earlier, in bytes. + + internal string name; // The name of the adapter. + internal PerformanceCounter dlCounter, ulCounter; // Performance counters to monitor download and upload speed. + + /// + /// Preparations for monitoring. + /// + internal void init() + { + // Since dlValueOld and ulValueOld are used in method refresh() to calculate network speed, they must have be initialized. + this.dlValueOld = this.dlCounter.NextSample().RawValue; + this.ulValueOld = this.ulCounter.NextSample().RawValue; + } + + /// + /// Obtain new sample from performance counters, and refresh the values saved in dlSpeed, ulSpeed, etc. + /// This method is supposed to be called only in NetworkMonitor, one time every second. + /// + internal void refresh() + { + this.dlValue = this.dlCounter.NextSample().RawValue; + this.ulValue = this.ulCounter.NextSample().RawValue; + + // Calculates download and upload speed. + this.dlSpeed = this.dlValue - this.dlValueOld; + this.ulSpeed = this.ulValue - this.ulValueOld; + + this.dlValueOld = this.dlValue; + this.ulValueOld = this.ulValue; + } + + /// + /// Overrides method to return the name of the adapter. + /// + /// The name of the adapter. + public override string ToString() + { + return this.name; + } + + /// + /// The name of the network adapter. + /// + public string Name + { + get + { + return this.name; + } + } + + /// + /// Current download speed in bytes per second. + /// + public long DownloadSpeed + { + get + { + return this.dlSpeed; + } + } + + /// + /// Current upload speed in bytes per second. + /// + public long UploadSpeed + { + get + { + return this.ulSpeed; + } + } + + /// + /// Current download speed in kbytes per second. + /// + public double DownloadSpeedKbps + { + get + { + return this.dlSpeed/1024.0; + } + } + + /// + /// Current upload speed in kbytes per second. + /// + public double UploadSpeedKbps + { + get + { + return this.ulSpeed/1024.0; + } + } +} + +public class NetworkInformation +{ + private static NetworkInterface[] NIC; + + public NetworkInformation() + { + NIC = NetworkInterface.GetAllNetworkInterfaces(); + } + + public string BytesReceived(int index) + { + return NIC[index].GetIPv4Statistics().BytesReceived.ToString(); + } + + public string BytesSent(int index) + { + return NIC[index].GetIPv4Statistics().BytesSent.ToString(); + } + + public string IncomingPacketsDiscarded(int index) + { + return NIC[index].GetIPv4Statistics().IncomingPacketsDiscarded.ToString(); + } + + public string IncomingPacketsWithErrors(int index) + { + return NIC[index].GetIPv4Statistics().IncomingPacketsWithErrors.ToString(); + } + + public string Description(int index) + { + return NIC[index].Description; + } + + public string Speed(int index) + { + return NIC[index].Speed.ToString(); + } + + +} + +/// +/// The NetworkMonitor class monitors network speed for each network adapter on the computer, using classes for Performance counter in .NET library. +/// +public class NetworkMonitor +{ + private System.Timers.Timer timer; // The timer event executes every second to refresh the values in adapters. + private ArrayList adapters; // The list of adapters on the computer. + private ArrayList monitoredAdapters; // The list of currently monitored adapters. + + /// + /// NetworkMonitor + /// + public NetworkMonitor() + { + this.adapters = new ArrayList(); + this.monitoredAdapters = new ArrayList(); + this.EnumerateNetworkAdapters(); + + this.timer = new System.Timers.Timer(1000); + this.timer.Elapsed += new ElapsedEventHandler(this.timer_Elapsed); + } + + /// + /// Enumerates network adapters installed on the computer. + /// + private void EnumerateNetworkAdapters() + { + PerformanceCounterCategory category = new PerformanceCounterCategory("Network Interface"); + + foreach (string name in category.GetInstanceNames()) + { + // This one exists on every computer. + if (name == "MS TCP Loopback interface") + { continue; } + // Create an instance of NetworkAdapter class, and create performance counters for it. + NetworkAdapter adapter = new NetworkAdapter(name); + adapter.dlCounter = new PerformanceCounter("Network Interface", "Bytes Received/sec", name); + adapter.ulCounter = new PerformanceCounter("Network Interface", "Bytes Sent/sec", name); + this.adapters.Add(adapter); // Add it to ArrayList adapter + } + } + + private void timer_Elapsed(object sender, ElapsedEventArgs e) + { + foreach (NetworkAdapter adapter in this.monitoredAdapters) + { adapter.refresh(); } + } + + /// + /// Get instances of NetworkAdapter for installed adapters on this computer. + /// + public NetworkAdapter[] Adapters + { + get + { + return (NetworkAdapter[])this.adapters.ToArray(typeof(NetworkAdapter)); + } + } + + /// + /// Enable the timer and add all adapters to the monitoredAdapters list, unless the adapters list is empty. + /// + public void StartMonitoring() + { + if (this.adapters.Count > 0) + { + foreach (NetworkAdapter adapter in this.adapters) + if (!this.monitoredAdapters.Contains(adapter)) + { + this.monitoredAdapters.Add(adapter); + adapter.init(); + } + + this.timer.Enabled = true; + } + } + + /// + /// Enable the timer, and add the specified adapter to the monitoredAdapters list + /// + /// + public void StartMonitoring(NetworkAdapter adapter) + { + if (!this.monitoredAdapters.Contains(adapter)) + { + this.monitoredAdapters.Add(adapter); + adapter.init(); + } + this.timer.Enabled = true; + } + + /// + /// Disable the timer, and clear the monitoredAdapters list. + /// + public void StopMonitoring() + { + this.monitoredAdapters.Clear(); + this.timer.Enabled = false; + } + + /// + /// Remove the specified adapter from the monitoredAdapters list, and disable the timer if the monitoredAdapters list is empty. + /// + /// + public void StopMonitoring(NetworkAdapter adapter) + { + if (this.monitoredAdapters.Contains(adapter)) + { this.monitoredAdapters.Remove(adapter); } + if (this.monitoredAdapters.Count == 0) + { this.timer.Enabled = false; } + } +} +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/NetInfoWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/NetInfoWindow.resx new file mode 100644 index 000000000..93f75a972 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/NetInfoWindow.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/OptionsWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/OptionsWindow.Designer.cs new file mode 100644 index 000000000..7c24bb248 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/OptionsWindow.Designer.cs @@ -0,0 +1,1212 @@ +namespace ProcessHacker +{ + partial class OptionsWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.textUpdateInterval = new System.Windows.Forms.NumericUpDown(); + this.buttonOK = new System.Windows.Forms.Button(); + this.checkShowProcessDomains = new System.Windows.Forms.CheckBox(); + this.checkWarnDangerous = new System.Windows.Forms.CheckBox(); + this.label2 = new System.Windows.Forms.Label(); + this.textSearchEngine = new System.Windows.Forms.TextBox(); + this.tabControl = new System.Windows.Forms.TabControl(); + this.tabGeneral = new System.Windows.Forms.TabPage(); + this.textMaxSamples = new System.Windows.Forms.NumericUpDown(); + this.label6 = new System.Windows.Forms.Label(); + this.label20 = new System.Windows.Forms.Label(); + this.comboToolbarStyle = new System.Windows.Forms.ComboBox(); + this.checkFloatChildWindows = new System.Windows.Forms.CheckBox(); + this.checkScrollDownProcessTree = new System.Windows.Forms.CheckBox(); + this.checkAllowOnlyOneInstance = new System.Windows.Forms.CheckBox(); + this.buttonFont = new System.Windows.Forms.Button(); + this.textImposterNames = new System.Windows.Forms.TextBox(); + this.label21 = new System.Windows.Forms.Label(); + this.comboSizeUnits = new System.Windows.Forms.ComboBox(); + this.label18 = new System.Windows.Forms.Label(); + this.checkStartHidden = new System.Windows.Forms.CheckBox(); + this.checkHideWhenClosed = new System.Windows.Forms.CheckBox(); + this.checkHideWhenMinimized = new System.Windows.Forms.CheckBox(); + this.label23 = new System.Windows.Forms.Label(); + this.textIconMenuProcesses = new System.Windows.Forms.NumericUpDown(); + this.tabAdvanced = new System.Windows.Forms.TabPage(); + this.comboElevationLevel = new System.Windows.Forms.ComboBox(); + this.label22 = new System.Windows.Forms.Label(); + this.checkEnableExperimentalFeatures = new System.Windows.Forms.CheckBox(); + this.checkHidePhConnections = new System.Windows.Forms.CheckBox(); + this.buttonChangeReplaceTaskManager = new System.Windows.Forms.Button(); + this.checkReplaceTaskManager = new System.Windows.Forms.CheckBox(); + this.checkEnableKPH = new System.Windows.Forms.CheckBox(); + this.checkHideHandlesWithNoName = new System.Windows.Forms.CheckBox(); + this.checkVerifySignatures = new System.Windows.Forms.CheckBox(); + this.tabHighlighting = new System.Windows.Forms.TabPage(); + this.label11 = new System.Windows.Forms.Label(); + this.buttonDisableAll = new System.Windows.Forms.Button(); + this.buttonEnableAll = new System.Windows.Forms.Button(); + this.listHighlightingColors = new System.Windows.Forms.ListView(); + this.columnDescription = new System.Windows.Forms.ColumnHeader(); + this.textHighlightingDuration = new System.Windows.Forms.NumericUpDown(); + this.label7 = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.colorRemovedProcesses = new ProcessHacker.Components.ColorModifier(); + this.colorNewProcesses = new ProcessHacker.Components.ColorModifier(); + this.tabPlotting = new System.Windows.Forms.TabPage(); + this.textStep = new System.Windows.Forms.NumericUpDown(); + this.label8 = new System.Windows.Forms.Label(); + this.checkPlotterAntialias = new System.Windows.Forms.CheckBox(); + this.label12 = new System.Windows.Forms.Label(); + this.label13 = new System.Windows.Forms.Label(); + this.label14 = new System.Windows.Forms.Label(); + this.label15 = new System.Windows.Forms.Label(); + this.label16 = new System.Windows.Forms.Label(); + this.label17 = new System.Windows.Forms.Label(); + this.colorIORO = new ProcessHacker.Components.ColorModifier(); + this.colorIOW = new ProcessHacker.Components.ColorModifier(); + this.colorMemoryWS = new ProcessHacker.Components.ColorModifier(); + this.colorMemoryPB = new ProcessHacker.Components.ColorModifier(); + this.colorCPUUT = new ProcessHacker.Components.ColorModifier(); + this.colorCPUKT = new ProcessHacker.Components.ColorModifier(); + this.tabSymbols = new System.Windows.Forms.TabPage(); + this.checkUndecorate = new System.Windows.Forms.CheckBox(); + this.textSearchPath = new System.Windows.Forms.TextBox(); + this.label10 = new System.Windows.Forms.Label(); + this.buttonDbghelpBrowse = new System.Windows.Forms.Button(); + this.textDbghelpPath = new System.Windows.Forms.TextBox(); + this.label9 = new System.Windows.Forms.Label(); + this.tabUpdates = new System.Windows.Forms.TabPage(); + this.UpdaterSettingsGroupBox = new System.Windows.Forms.GroupBox(); + this.checkUpdateAutomatically = new System.Windows.Forms.CheckBox(); + this.label5 = new System.Windows.Forms.Label(); + this.optUpdateStable = new System.Windows.Forms.RadioButton(); + this.optUpdateAlpha = new System.Windows.Forms.RadioButton(); + this.optUpdateBeta = new System.Windows.Forms.RadioButton(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.buttonApply = new System.Windows.Forms.Button(); + ((System.ComponentModel.ISupportInitialize)(this.textUpdateInterval)).BeginInit(); + this.tabControl.SuspendLayout(); + this.tabGeneral.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.textMaxSamples)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.textIconMenuProcesses)).BeginInit(); + this.tabAdvanced.SuspendLayout(); + this.tabHighlighting.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.textHighlightingDuration)).BeginInit(); + this.tabPlotting.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.textStep)).BeginInit(); + this.tabSymbols.SuspendLayout(); + this.tabUpdates.SuspendLayout(); + this.UpdaterSettingsGroupBox.SuspendLayout(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(6, 8); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(83, 13); + this.label1.TabIndex = 13; + this.label1.Text = "Update Interval:"; + // + // textUpdateInterval + // + this.textUpdateInterval.Increment = new decimal(new int[] { + 250, + 0, + 0, + 0}); + this.textUpdateInterval.Location = new System.Drawing.Point(134, 6); + this.textUpdateInterval.Maximum = new decimal(new int[] { + 10000, + 0, + 0, + 0}); + this.textUpdateInterval.Minimum = new decimal(new int[] { + 250, + 0, + 0, + 0}); + this.textUpdateInterval.Name = "textUpdateInterval"; + this.textUpdateInterval.Size = new System.Drawing.Size(66, 20); + this.textUpdateInterval.TabIndex = 0; + this.textUpdateInterval.Value = new decimal(new int[] { + 1000, + 0, + 0, + 0}); + this.textUpdateInterval.Leave += new System.EventHandler(this.textUpdateInterval_Leave); + // + // buttonOK + // + this.buttonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonOK.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonOK.Location = new System.Drawing.Point(264, 352); + this.buttonOK.Name = "buttonOK"; + this.buttonOK.Size = new System.Drawing.Size(75, 23); + this.buttonOK.TabIndex = 1; + this.buttonOK.Text = "&OK"; + this.buttonOK.UseVisualStyleBackColor = true; + this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click); + // + // checkShowProcessDomains + // + this.checkShowProcessDomains.AutoSize = true; + this.checkShowProcessDomains.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkShowProcessDomains.Location = new System.Drawing.Point(211, 245); + this.checkShowProcessDomains.Name = "checkShowProcessDomains"; + this.checkShowProcessDomains.Size = new System.Drawing.Size(156, 18); + this.checkShowProcessDomains.TabIndex = 12; + this.checkShowProcessDomains.Text = "Show user/group domains"; + this.checkShowProcessDomains.UseVisualStyleBackColor = true; + // + // checkWarnDangerous + // + this.checkWarnDangerous.AutoSize = true; + this.checkWarnDangerous.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkWarnDangerous.Location = new System.Drawing.Point(6, 102); + this.checkWarnDangerous.Name = "checkWarnDangerous"; + this.checkWarnDangerous.Size = new System.Drawing.Size(228, 18); + this.checkWarnDangerous.TabIndex = 5; + this.checkWarnDangerous.Text = "Warn about potentially dangerous actions"; + this.checkWarnDangerous.UseVisualStyleBackColor = true; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(6, 61); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(80, 13); + this.label2.TabIndex = 15; + this.label2.Text = "Search Engine:"; + // + // textSearchEngine + // + this.textSearchEngine.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textSearchEngine.Location = new System.Drawing.Point(134, 58); + this.textSearchEngine.Name = "textSearchEngine"; + this.textSearchEngine.Size = new System.Drawing.Size(341, 20); + this.textSearchEngine.TabIndex = 2; + // + // tabControl + // + this.tabControl.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.tabControl.Controls.Add(this.tabGeneral); + this.tabControl.Controls.Add(this.tabAdvanced); + this.tabControl.Controls.Add(this.tabHighlighting); + this.tabControl.Controls.Add(this.tabPlotting); + this.tabControl.Controls.Add(this.tabSymbols); + this.tabControl.Controls.Add(this.tabUpdates); + this.tabControl.Location = new System.Drawing.Point(12, 12); + this.tabControl.Name = "tabControl"; + this.tabControl.SelectedIndex = 0; + this.tabControl.Size = new System.Drawing.Size(489, 334); + this.tabControl.TabIndex = 0; + // + // tabGeneral + // + this.tabGeneral.Controls.Add(this.textMaxSamples); + this.tabGeneral.Controls.Add(this.label6); + this.tabGeneral.Controls.Add(this.label20); + this.tabGeneral.Controls.Add(this.comboToolbarStyle); + this.tabGeneral.Controls.Add(this.checkFloatChildWindows); + this.tabGeneral.Controls.Add(this.checkScrollDownProcessTree); + this.tabGeneral.Controls.Add(this.checkAllowOnlyOneInstance); + this.tabGeneral.Controls.Add(this.buttonFont); + this.tabGeneral.Controls.Add(this.textImposterNames); + this.tabGeneral.Controls.Add(this.label21); + this.tabGeneral.Controls.Add(this.comboSizeUnits); + this.tabGeneral.Controls.Add(this.label18); + this.tabGeneral.Controls.Add(this.checkStartHidden); + this.tabGeneral.Controls.Add(this.checkHideWhenClosed); + this.tabGeneral.Controls.Add(this.checkHideWhenMinimized); + this.tabGeneral.Controls.Add(this.label23); + this.tabGeneral.Controls.Add(this.label1); + this.tabGeneral.Controls.Add(this.textSearchEngine); + this.tabGeneral.Controls.Add(this.textIconMenuProcesses); + this.tabGeneral.Controls.Add(this.textUpdateInterval); + this.tabGeneral.Controls.Add(this.label2); + this.tabGeneral.Controls.Add(this.checkShowProcessDomains); + this.tabGeneral.Location = new System.Drawing.Point(4, 22); + this.tabGeneral.Name = "tabGeneral"; + this.tabGeneral.Padding = new System.Windows.Forms.Padding(3); + this.tabGeneral.Size = new System.Drawing.Size(481, 308); + this.tabGeneral.TabIndex = 0; + this.tabGeneral.Text = "General"; + this.tabGeneral.UseVisualStyleBackColor = true; + // + // textMaxSamples + // + this.textMaxSamples.Increment = new decimal(new int[] { + 100, + 0, + 0, + 0}); + this.textMaxSamples.Location = new System.Drawing.Point(320, 6); + this.textMaxSamples.Maximum = new decimal(new int[] { + 10000, + 0, + 0, + 0}); + this.textMaxSamples.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.textMaxSamples.Name = "textMaxSamples"; + this.textMaxSamples.Size = new System.Drawing.Size(72, 20); + this.textMaxSamples.TabIndex = 20; + this.textMaxSamples.Value = new decimal(new int[] { + 1000, + 0, + 0, + 0}); + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(208, 8); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(106, 13); + this.label6.TabIndex = 21; + this.label6.Text = "Max. Sample History:"; + // + // label20 + // + this.label20.AutoSize = true; + this.label20.Location = new System.Drawing.Point(6, 140); + this.label20.Name = "label20"; + this.label20.Size = new System.Drawing.Size(109, 13); + this.label20.TabIndex = 19; + this.label20.Text = "Toolbar Display Style:"; + // + // comboToolbarStyle + // + this.comboToolbarStyle.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboToolbarStyle.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.comboToolbarStyle.FormattingEnabled = true; + this.comboToolbarStyle.Items.AddRange(new object[] { + "Show Only Icons", + "Show Selective Text", + "Show All Text Labels"}); + this.comboToolbarStyle.Location = new System.Drawing.Point(134, 137); + this.comboToolbarStyle.Name = "comboToolbarStyle"; + this.comboToolbarStyle.Size = new System.Drawing.Size(135, 21); + this.comboToolbarStyle.TabIndex = 18; + // + // checkFloatChildWindows + // + this.checkFloatChildWindows.AutoSize = true; + this.checkFloatChildWindows.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkFloatChildWindows.Location = new System.Drawing.Point(211, 198); + this.checkFloatChildWindows.Name = "checkFloatChildWindows"; + this.checkFloatChildWindows.Size = new System.Drawing.Size(124, 18); + this.checkFloatChildWindows.TabIndex = 10; + this.checkFloatChildWindows.Text = "Float child windows"; + this.checkFloatChildWindows.UseVisualStyleBackColor = true; + // + // checkScrollDownProcessTree + // + this.checkScrollDownProcessTree.AutoSize = true; + this.checkScrollDownProcessTree.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkScrollDownProcessTree.Location = new System.Drawing.Point(211, 221); + this.checkScrollDownProcessTree.Name = "checkScrollDownProcessTree"; + this.checkScrollDownProcessTree.Size = new System.Drawing.Size(213, 18); + this.checkScrollDownProcessTree.TabIndex = 11; + this.checkScrollDownProcessTree.Text = "Scroll down the process tree at startup"; + this.checkScrollDownProcessTree.UseVisualStyleBackColor = true; + // + // checkAllowOnlyOneInstance + // + this.checkAllowOnlyOneInstance.AutoSize = true; + this.checkAllowOnlyOneInstance.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkAllowOnlyOneInstance.Location = new System.Drawing.Point(6, 269); + this.checkAllowOnlyOneInstance.Name = "checkAllowOnlyOneInstance"; + this.checkAllowOnlyOneInstance.Size = new System.Drawing.Size(143, 18); + this.checkAllowOnlyOneInstance.TabIndex = 9; + this.checkAllowOnlyOneInstance.Text = "Allow only one instance"; + this.checkAllowOnlyOneInstance.UseVisualStyleBackColor = true; + // + // buttonFont + // + this.buttonFont.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonFont.Location = new System.Drawing.Point(6, 168); + this.buttonFont.Name = "buttonFont"; + this.buttonFont.Size = new System.Drawing.Size(75, 23); + this.buttonFont.TabIndex = 5; + this.buttonFont.Text = "Font..."; + this.buttonFont.UseVisualStyleBackColor = true; + this.buttonFont.Click += new System.EventHandler(this.buttonFont_Click); + // + // textImposterNames + // + this.textImposterNames.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textImposterNames.Location = new System.Drawing.Point(134, 84); + this.textImposterNames.Name = "textImposterNames"; + this.textImposterNames.Size = new System.Drawing.Size(341, 20); + this.textImposterNames.TabIndex = 3; + // + // label21 + // + this.label21.AutoSize = true; + this.label21.Location = new System.Drawing.Point(6, 87); + this.label21.Name = "label21"; + this.label21.Size = new System.Drawing.Size(100, 13); + this.label21.TabIndex = 16; + this.label21.Text = "Require Signatures:"; + // + // comboSizeUnits + // + this.comboSizeUnits.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboSizeUnits.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.comboSizeUnits.FormattingEnabled = true; + this.comboSizeUnits.Items.AddRange(new object[] { + "B", + "kB", + "MB", + "GB", + "TB", + "PB", + "EB"}); + this.comboSizeUnits.Location = new System.Drawing.Point(134, 110); + this.comboSizeUnits.Name = "comboSizeUnits"; + this.comboSizeUnits.Size = new System.Drawing.Size(67, 21); + this.comboSizeUnits.TabIndex = 4; + // + // label18 + // + this.label18.AutoSize = true; + this.label18.Location = new System.Drawing.Point(6, 113); + this.label18.Name = "label18"; + this.label18.Size = new System.Drawing.Size(78, 13); + this.label18.TabIndex = 17; + this.label18.Text = "Max. Size Unit:"; + // + // checkStartHidden + // + this.checkStartHidden.AutoSize = true; + this.checkStartHidden.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkStartHidden.Location = new System.Drawing.Point(6, 245); + this.checkStartHidden.Name = "checkStartHidden"; + this.checkStartHidden.Size = new System.Drawing.Size(89, 18); + this.checkStartHidden.TabIndex = 8; + this.checkStartHidden.Text = "Start hidden"; + this.checkStartHidden.UseVisualStyleBackColor = true; + // + // checkHideWhenClosed + // + this.checkHideWhenClosed.AutoSize = true; + this.checkHideWhenClosed.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkHideWhenClosed.Location = new System.Drawing.Point(6, 221); + this.checkHideWhenClosed.Name = "checkHideWhenClosed"; + this.checkHideWhenClosed.Size = new System.Drawing.Size(117, 18); + this.checkHideWhenClosed.TabIndex = 7; + this.checkHideWhenClosed.Text = "Hide when closed"; + this.checkHideWhenClosed.UseVisualStyleBackColor = true; + // + // checkHideWhenMinimized + // + this.checkHideWhenMinimized.AutoSize = true; + this.checkHideWhenMinimized.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkHideWhenMinimized.Location = new System.Drawing.Point(6, 197); + this.checkHideWhenMinimized.Name = "checkHideWhenMinimized"; + this.checkHideWhenMinimized.Size = new System.Drawing.Size(131, 18); + this.checkHideWhenMinimized.TabIndex = 6; + this.checkHideWhenMinimized.Text = "Hide when minimized"; + this.checkHideWhenMinimized.UseVisualStyleBackColor = true; + // + // label23 + // + this.label23.AutoSize = true; + this.label23.Location = new System.Drawing.Point(6, 34); + this.label23.Name = "label23"; + this.label23.Size = new System.Drawing.Size(122, 13); + this.label23.TabIndex = 14; + this.label23.Text = "Processes in icon menu:"; + // + // textIconMenuProcesses + // + this.textIconMenuProcesses.Location = new System.Drawing.Point(134, 32); + this.textIconMenuProcesses.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.textIconMenuProcesses.Name = "textIconMenuProcesses"; + this.textIconMenuProcesses.Size = new System.Drawing.Size(66, 20); + this.textIconMenuProcesses.TabIndex = 1; + this.textIconMenuProcesses.Value = new decimal(new int[] { + 10, + 0, + 0, + 0}); + this.textIconMenuProcesses.Leave += new System.EventHandler(this.textIconMenuProcesses_Leave); + // + // tabAdvanced + // + this.tabAdvanced.Controls.Add(this.comboElevationLevel); + this.tabAdvanced.Controls.Add(this.label22); + this.tabAdvanced.Controls.Add(this.checkEnableExperimentalFeatures); + this.tabAdvanced.Controls.Add(this.checkHidePhConnections); + this.tabAdvanced.Controls.Add(this.buttonChangeReplaceTaskManager); + this.tabAdvanced.Controls.Add(this.checkReplaceTaskManager); + this.tabAdvanced.Controls.Add(this.checkWarnDangerous); + this.tabAdvanced.Controls.Add(this.checkEnableKPH); + this.tabAdvanced.Controls.Add(this.checkHideHandlesWithNoName); + this.tabAdvanced.Controls.Add(this.checkVerifySignatures); + this.tabAdvanced.Location = new System.Drawing.Point(4, 22); + this.tabAdvanced.Name = "tabAdvanced"; + this.tabAdvanced.Padding = new System.Windows.Forms.Padding(3); + this.tabAdvanced.Size = new System.Drawing.Size(481, 308); + this.tabAdvanced.TabIndex = 3; + this.tabAdvanced.Text = "Advanced"; + this.tabAdvanced.UseVisualStyleBackColor = true; + // + // comboElevationLevel + // + this.comboElevationLevel.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboElevationLevel.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.comboElevationLevel.FormattingEnabled = true; + this.comboElevationLevel.Items.AddRange(new object[] { + "Never elevate", + "Prompt for elevation", + "Always elevate"}); + this.comboElevationLevel.Location = new System.Drawing.Point(66, 174); + this.comboElevationLevel.Name = "comboElevationLevel"; + this.comboElevationLevel.Size = new System.Drawing.Size(194, 21); + this.comboElevationLevel.TabIndex = 11; + // + // label22 + // + this.label22.AutoSize = true; + this.label22.Location = new System.Drawing.Point(6, 177); + this.label22.Name = "label22"; + this.label22.Size = new System.Drawing.Size(54, 13); + this.label22.TabIndex = 10; + this.label22.Text = "Elevation:"; + // + // checkEnableExperimentalFeatures + // + this.checkEnableExperimentalFeatures.AutoSize = true; + this.checkEnableExperimentalFeatures.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkEnableExperimentalFeatures.Location = new System.Drawing.Point(6, 30); + this.checkEnableExperimentalFeatures.Name = "checkEnableExperimentalFeatures"; + this.checkEnableExperimentalFeatures.Size = new System.Drawing.Size(168, 18); + this.checkEnableExperimentalFeatures.TabIndex = 1; + this.checkEnableExperimentalFeatures.Text = "Enable experimental features"; + this.checkEnableExperimentalFeatures.UseVisualStyleBackColor = true; + // + // checkHidePhConnections + // + this.checkHidePhConnections.AutoSize = true; + this.checkHidePhConnections.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkHidePhConnections.Location = new System.Drawing.Point(6, 150); + this.checkHidePhConnections.Name = "checkHidePhConnections"; + this.checkHidePhConnections.Size = new System.Drawing.Size(235, 18); + this.checkHidePhConnections.TabIndex = 7; + this.checkHidePhConnections.Text = "Hide Process Hacker network connections"; + this.checkHidePhConnections.UseVisualStyleBackColor = true; + // + // buttonChangeReplaceTaskManager + // + this.buttonChangeReplaceTaskManager.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonChangeReplaceTaskManager.Location = new System.Drawing.Point(257, 75); + this.buttonChangeReplaceTaskManager.Name = "buttonChangeReplaceTaskManager"; + this.buttonChangeReplaceTaskManager.Size = new System.Drawing.Size(89, 23); + this.buttonChangeReplaceTaskManager.TabIndex = 4; + this.buttonChangeReplaceTaskManager.Text = "Change..."; + this.buttonChangeReplaceTaskManager.UseVisualStyleBackColor = true; + this.buttonChangeReplaceTaskManager.Click += new System.EventHandler(this.buttonChangeReplaceTaskManager_Click); + // + // checkReplaceTaskManager + // + this.checkReplaceTaskManager.AutoSize = true; + this.checkReplaceTaskManager.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkReplaceTaskManager.Location = new System.Drawing.Point(6, 78); + this.checkReplaceTaskManager.Name = "checkReplaceTaskManager"; + this.checkReplaceTaskManager.Size = new System.Drawing.Size(245, 18); + this.checkReplaceTaskManager.TabIndex = 3; + this.checkReplaceTaskManager.Text = "Replace Task Manager with Process Hacker"; + this.checkReplaceTaskManager.UseVisualStyleBackColor = true; + // + // checkEnableKPH + // + this.checkEnableKPH.AutoSize = true; + this.checkEnableKPH.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkEnableKPH.Location = new System.Drawing.Point(6, 6); + this.checkEnableKPH.Name = "checkEnableKPH"; + this.checkEnableKPH.Size = new System.Drawing.Size(155, 18); + this.checkEnableKPH.TabIndex = 0; + this.checkEnableKPH.Text = "Enable kernel-mode driver"; + this.checkEnableKPH.UseVisualStyleBackColor = true; + // + // checkHideHandlesWithNoName + // + this.checkHideHandlesWithNoName.AutoSize = true; + this.checkHideHandlesWithNoName.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkHideHandlesWithNoName.Location = new System.Drawing.Point(6, 126); + this.checkHideHandlesWithNoName.Name = "checkHideHandlesWithNoName"; + this.checkHideHandlesWithNoName.Size = new System.Drawing.Size(160, 18); + this.checkHideHandlesWithNoName.TabIndex = 6; + this.checkHideHandlesWithNoName.Text = "Hide handles with no name"; + this.checkHideHandlesWithNoName.UseVisualStyleBackColor = true; + // + // checkVerifySignatures + // + this.checkVerifySignatures.AutoSize = true; + this.checkVerifySignatures.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkVerifySignatures.Location = new System.Drawing.Point(6, 54); + this.checkVerifySignatures.Name = "checkVerifySignatures"; + this.checkVerifySignatures.Size = new System.Drawing.Size(254, 18); + this.checkVerifySignatures.TabIndex = 2; + this.checkVerifySignatures.Text = "Verify signatures and perform additional checks"; + this.checkVerifySignatures.UseVisualStyleBackColor = true; + // + // tabHighlighting + // + this.tabHighlighting.Controls.Add(this.label11); + this.tabHighlighting.Controls.Add(this.buttonDisableAll); + this.tabHighlighting.Controls.Add(this.buttonEnableAll); + this.tabHighlighting.Controls.Add(this.listHighlightingColors); + this.tabHighlighting.Controls.Add(this.textHighlightingDuration); + this.tabHighlighting.Controls.Add(this.label7); + this.tabHighlighting.Controls.Add(this.label4); + this.tabHighlighting.Controls.Add(this.label3); + this.tabHighlighting.Controls.Add(this.colorRemovedProcesses); + this.tabHighlighting.Controls.Add(this.colorNewProcesses); + this.tabHighlighting.Location = new System.Drawing.Point(4, 22); + this.tabHighlighting.Name = "tabHighlighting"; + this.tabHighlighting.Padding = new System.Windows.Forms.Padding(3); + this.tabHighlighting.Size = new System.Drawing.Size(481, 308); + this.tabHighlighting.TabIndex = 1; + this.tabHighlighting.Text = "Highlighting"; + this.tabHighlighting.UseVisualStyleBackColor = true; + // + // label11 + // + this.label11.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.label11.AutoSize = true; + this.label11.Location = new System.Drawing.Point(6, 284); + this.label11.Name = "label11"; + this.label11.Size = new System.Drawing.Size(165, 13); + this.label11.TabIndex = 9; + this.label11.Text = "Double-click an item to change it."; + // + // buttonDisableAll + // + this.buttonDisableAll.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonDisableAll.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonDisableAll.Location = new System.Drawing.Point(400, 279); + this.buttonDisableAll.Name = "buttonDisableAll"; + this.buttonDisableAll.Size = new System.Drawing.Size(75, 23); + this.buttonDisableAll.TabIndex = 5; + this.buttonDisableAll.Text = "&Disable All"; + this.buttonDisableAll.UseVisualStyleBackColor = true; + this.buttonDisableAll.Click += new System.EventHandler(this.buttonDisableAll_Click); + // + // buttonEnableAll + // + this.buttonEnableAll.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonEnableAll.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonEnableAll.Location = new System.Drawing.Point(319, 279); + this.buttonEnableAll.Name = "buttonEnableAll"; + this.buttonEnableAll.Size = new System.Drawing.Size(75, 23); + this.buttonEnableAll.TabIndex = 4; + this.buttonEnableAll.Text = "&Enable All"; + this.buttonEnableAll.UseVisualStyleBackColor = true; + this.buttonEnableAll.Click += new System.EventHandler(this.buttonEnableAll_Click); + // + // listHighlightingColors + // + this.listHighlightingColors.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listHighlightingColors.CheckBoxes = true; + this.listHighlightingColors.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnDescription}); + this.listHighlightingColors.FullRowSelect = true; + this.listHighlightingColors.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None; + this.listHighlightingColors.HideSelection = false; + this.listHighlightingColors.Location = new System.Drawing.Point(6, 60); + this.listHighlightingColors.MultiSelect = false; + this.listHighlightingColors.Name = "listHighlightingColors"; + this.listHighlightingColors.ShowItemToolTips = true; + this.listHighlightingColors.Size = new System.Drawing.Size(469, 213); + this.listHighlightingColors.TabIndex = 3; + this.listHighlightingColors.UseCompatibleStateImageBehavior = false; + this.listHighlightingColors.View = System.Windows.Forms.View.Details; + this.listHighlightingColors.DoubleClick += new System.EventHandler(this.listHighlightingColors_DoubleClick); + // + // columnDescription + // + this.columnDescription.Text = "Description"; + this.columnDescription.Width = 250; + // + // textHighlightingDuration + // + this.textHighlightingDuration.Increment = new decimal(new int[] { + 250, + 0, + 0, + 0}); + this.textHighlightingDuration.Location = new System.Drawing.Point(127, 7); + this.textHighlightingDuration.Maximum = new decimal(new int[] { + 10000, + 0, + 0, + 0}); + this.textHighlightingDuration.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.textHighlightingDuration.Name = "textHighlightingDuration"; + this.textHighlightingDuration.Size = new System.Drawing.Size(66, 20); + this.textHighlightingDuration.TabIndex = 0; + this.textHighlightingDuration.Value = new decimal(new int[] { + 1, + 0, + 0, + 0}); + // + // label7 + // + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(6, 9); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(108, 13); + this.label7.TabIndex = 6; + this.label7.Text = "Highlighting Duration:"; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(230, 36); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(95, 13); + this.label4.TabIndex = 8; + this.label4.Text = "Removed Objects:"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(6, 36); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(71, 13); + this.label3.TabIndex = 7; + this.label3.Text = "New Objects:"; + // + // colorRemovedProcesses + // + this.colorRemovedProcesses.Color = System.Drawing.Color.Transparent; + this.colorRemovedProcesses.Location = new System.Drawing.Point(351, 34); + this.colorRemovedProcesses.Name = "colorRemovedProcesses"; + this.colorRemovedProcesses.Size = new System.Drawing.Size(40, 20); + this.colorRemovedProcesses.TabIndex = 2; + // + // colorNewProcesses + // + this.colorNewProcesses.Color = System.Drawing.Color.Transparent; + this.colorNewProcesses.Location = new System.Drawing.Point(127, 33); + this.colorNewProcesses.Name = "colorNewProcesses"; + this.colorNewProcesses.Size = new System.Drawing.Size(40, 20); + this.colorNewProcesses.TabIndex = 1; + // + // tabPlotting + // + this.tabPlotting.Controls.Add(this.textStep); + this.tabPlotting.Controls.Add(this.label8); + this.tabPlotting.Controls.Add(this.checkPlotterAntialias); + this.tabPlotting.Controls.Add(this.label12); + this.tabPlotting.Controls.Add(this.label13); + this.tabPlotting.Controls.Add(this.label14); + this.tabPlotting.Controls.Add(this.label15); + this.tabPlotting.Controls.Add(this.label16); + this.tabPlotting.Controls.Add(this.label17); + this.tabPlotting.Controls.Add(this.colorIORO); + this.tabPlotting.Controls.Add(this.colorIOW); + this.tabPlotting.Controls.Add(this.colorMemoryWS); + this.tabPlotting.Controls.Add(this.colorMemoryPB); + this.tabPlotting.Controls.Add(this.colorCPUUT); + this.tabPlotting.Controls.Add(this.colorCPUKT); + this.tabPlotting.Location = new System.Drawing.Point(4, 22); + this.tabPlotting.Name = "tabPlotting"; + this.tabPlotting.Padding = new System.Windows.Forms.Padding(3); + this.tabPlotting.Size = new System.Drawing.Size(481, 308); + this.tabPlotting.TabIndex = 2; + this.tabPlotting.Text = "Plotting"; + this.tabPlotting.UseVisualStyleBackColor = true; + // + // textStep + // + this.textStep.Location = new System.Drawing.Point(44, 30); + this.textStep.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.textStep.Name = "textStep"; + this.textStep.Size = new System.Drawing.Size(69, 20); + this.textStep.TabIndex = 1; + this.textStep.Value = new decimal(new int[] { + 3, + 0, + 0, + 0}); + // + // label8 + // + this.label8.AutoSize = true; + this.label8.Location = new System.Drawing.Point(6, 32); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(32, 13); + this.label8.TabIndex = 8; + this.label8.Text = "Step:"; + // + // checkPlotterAntialias + // + this.checkPlotterAntialias.AutoSize = true; + this.checkPlotterAntialias.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkPlotterAntialias.Location = new System.Drawing.Point(6, 6); + this.checkPlotterAntialias.Name = "checkPlotterAntialias"; + this.checkPlotterAntialias.Size = new System.Drawing.Size(110, 18); + this.checkPlotterAntialias.TabIndex = 0; + this.checkPlotterAntialias.Text = "Use Anti-aliasing"; + this.checkPlotterAntialias.UseVisualStyleBackColor = true; + // + // label12 + // + this.label12.AutoSize = true; + this.label12.Location = new System.Drawing.Point(6, 165); + this.label12.Name = "label12"; + this.label12.Size = new System.Drawing.Size(92, 13); + this.label12.TabIndex = 13; + this.label12.Text = "I/O Reads+Other:"; + // + // label13 + // + this.label13.AutoSize = true; + this.label13.Location = new System.Drawing.Point(6, 190); + this.label13.Name = "label13"; + this.label13.Size = new System.Drawing.Size(59, 13); + this.label13.TabIndex = 14; + this.label13.Text = "I/O Writes:"; + // + // label14 + // + this.label14.AutoSize = true; + this.label14.Location = new System.Drawing.Point(6, 139); + this.label14.Name = "label14"; + this.label14.Size = new System.Drawing.Size(69, 13); + this.label14.TabIndex = 12; + this.label14.Text = "Working Set:"; + // + // label15 + // + this.label15.AutoSize = true; + this.label15.Location = new System.Drawing.Point(6, 113); + this.label15.Name = "label15"; + this.label15.Size = new System.Drawing.Size(72, 13); + this.label15.TabIndex = 11; + this.label15.Text = "Private Bytes:"; + // + // label16 + // + this.label16.AutoSize = true; + this.label16.Location = new System.Drawing.Point(6, 88); + this.label16.Name = "label16"; + this.label16.Size = new System.Drawing.Size(83, 13); + this.label16.TabIndex = 10; + this.label16.Text = "CPU User Time:"; + // + // label17 + // + this.label17.AutoSize = true; + this.label17.Location = new System.Drawing.Point(6, 62); + this.label17.Name = "label17"; + this.label17.Size = new System.Drawing.Size(91, 13); + this.label17.TabIndex = 9; + this.label17.Text = "CPU Kernel Time:"; + // + // colorIORO + // + this.colorIORO.Color = System.Drawing.Color.Transparent; + this.colorIORO.Location = new System.Drawing.Point(124, 163); + this.colorIORO.Name = "colorIORO"; + this.colorIORO.Size = new System.Drawing.Size(40, 20); + this.colorIORO.TabIndex = 6; + // + // colorIOW + // + this.colorIOW.Color = System.Drawing.Color.Transparent; + this.colorIOW.Location = new System.Drawing.Point(124, 189); + this.colorIOW.Name = "colorIOW"; + this.colorIOW.Size = new System.Drawing.Size(40, 20); + this.colorIOW.TabIndex = 7; + // + // colorMemoryWS + // + this.colorMemoryWS.Color = System.Drawing.Color.Transparent; + this.colorMemoryWS.Location = new System.Drawing.Point(124, 137); + this.colorMemoryWS.Name = "colorMemoryWS"; + this.colorMemoryWS.Size = new System.Drawing.Size(40, 20); + this.colorMemoryWS.TabIndex = 5; + // + // colorMemoryPB + // + this.colorMemoryPB.Color = System.Drawing.Color.Transparent; + this.colorMemoryPB.Location = new System.Drawing.Point(124, 111); + this.colorMemoryPB.Name = "colorMemoryPB"; + this.colorMemoryPB.Size = new System.Drawing.Size(40, 20); + this.colorMemoryPB.TabIndex = 4; + // + // colorCPUUT + // + this.colorCPUUT.Color = System.Drawing.Color.Transparent; + this.colorCPUUT.Location = new System.Drawing.Point(124, 85); + this.colorCPUUT.Name = "colorCPUUT"; + this.colorCPUUT.Size = new System.Drawing.Size(40, 20); + this.colorCPUUT.TabIndex = 3; + // + // colorCPUKT + // + this.colorCPUKT.Color = System.Drawing.Color.Transparent; + this.colorCPUKT.Location = new System.Drawing.Point(124, 59); + this.colorCPUKT.Name = "colorCPUKT"; + this.colorCPUKT.Size = new System.Drawing.Size(40, 20); + this.colorCPUKT.TabIndex = 2; + // + // tabSymbols + // + this.tabSymbols.Controls.Add(this.checkUndecorate); + this.tabSymbols.Controls.Add(this.textSearchPath); + this.tabSymbols.Controls.Add(this.label10); + this.tabSymbols.Controls.Add(this.buttonDbghelpBrowse); + this.tabSymbols.Controls.Add(this.textDbghelpPath); + this.tabSymbols.Controls.Add(this.label9); + this.tabSymbols.Location = new System.Drawing.Point(4, 22); + this.tabSymbols.Name = "tabSymbols"; + this.tabSymbols.Padding = new System.Windows.Forms.Padding(3); + this.tabSymbols.Size = new System.Drawing.Size(481, 308); + this.tabSymbols.TabIndex = 4; + this.tabSymbols.Text = "Symbols"; + this.tabSymbols.UseVisualStyleBackColor = true; + // + // checkUndecorate + // + this.checkUndecorate.AutoSize = true; + this.checkUndecorate.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkUndecorate.Location = new System.Drawing.Point(6, 60); + this.checkUndecorate.Name = "checkUndecorate"; + this.checkUndecorate.Size = new System.Drawing.Size(128, 18); + this.checkUndecorate.TabIndex = 3; + this.checkUndecorate.Text = "Undecorate symbols"; + this.checkUndecorate.UseVisualStyleBackColor = true; + // + // textSearchPath + // + this.textSearchPath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textSearchPath.Location = new System.Drawing.Point(99, 34); + this.textSearchPath.Name = "textSearchPath"; + this.textSearchPath.Size = new System.Drawing.Size(376, 20); + this.textSearchPath.TabIndex = 2; + // + // label10 + // + this.label10.AutoSize = true; + this.label10.Location = new System.Drawing.Point(6, 37); + this.label10.Name = "label10"; + this.label10.Size = new System.Drawing.Size(68, 13); + this.label10.TabIndex = 5; + this.label10.Text = "Search path:"; + // + // buttonDbghelpBrowse + // + this.buttonDbghelpBrowse.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonDbghelpBrowse.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonDbghelpBrowse.Location = new System.Drawing.Point(400, 6); + this.buttonDbghelpBrowse.Name = "buttonDbghelpBrowse"; + this.buttonDbghelpBrowse.Size = new System.Drawing.Size(75, 23); + this.buttonDbghelpBrowse.TabIndex = 1; + this.buttonDbghelpBrowse.Text = "Browse..."; + this.buttonDbghelpBrowse.UseVisualStyleBackColor = true; + this.buttonDbghelpBrowse.Click += new System.EventHandler(this.buttonDbghelpBrowse_Click); + // + // textDbghelpPath + // + this.textDbghelpPath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textDbghelpPath.Location = new System.Drawing.Point(99, 8); + this.textDbghelpPath.Name = "textDbghelpPath"; + this.textDbghelpPath.Size = new System.Drawing.Size(295, 20); + this.textDbghelpPath.TabIndex = 0; + // + // label9 + // + this.label9.AutoSize = true; + this.label9.Location = new System.Drawing.Point(6, 11); + this.label9.Name = "label9"; + this.label9.Size = new System.Drawing.Size(87, 13); + this.label9.TabIndex = 4; + this.label9.Text = "Dbghelp.dll path:"; + // + // tabUpdates + // + this.tabUpdates.Controls.Add(this.UpdaterSettingsGroupBox); + this.tabUpdates.Location = new System.Drawing.Point(4, 22); + this.tabUpdates.Name = "tabUpdates"; + this.tabUpdates.Padding = new System.Windows.Forms.Padding(3); + this.tabUpdates.Size = new System.Drawing.Size(481, 308); + this.tabUpdates.TabIndex = 5; + this.tabUpdates.Text = "Updates"; + this.tabUpdates.UseVisualStyleBackColor = true; + // + // UpdaterSettingsGroupBox + // + this.UpdaterSettingsGroupBox.Controls.Add(this.checkUpdateAutomatically); + this.UpdaterSettingsGroupBox.Controls.Add(this.label5); + this.UpdaterSettingsGroupBox.Controls.Add(this.optUpdateStable); + this.UpdaterSettingsGroupBox.Controls.Add(this.optUpdateAlpha); + this.UpdaterSettingsGroupBox.Controls.Add(this.optUpdateBeta); + this.UpdaterSettingsGroupBox.Location = new System.Drawing.Point(11, 11); + this.UpdaterSettingsGroupBox.Name = "UpdaterSettingsGroupBox"; + this.UpdaterSettingsGroupBox.Size = new System.Drawing.Size(456, 100); + this.UpdaterSettingsGroupBox.TabIndex = 30; + this.UpdaterSettingsGroupBox.TabStop = false; + this.UpdaterSettingsGroupBox.Text = "Updater Settings"; + // + // checkUpdateAutomatically + // + this.checkUpdateAutomatically.AutoSize = true; + this.checkUpdateAutomatically.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkUpdateAutomatically.Location = new System.Drawing.Point(10, 19); + this.checkUpdateAutomatically.Name = "checkUpdateAutomatically"; + this.checkUpdateAutomatically.Size = new System.Drawing.Size(186, 18); + this.checkUpdateAutomatically.TabIndex = 27; + this.checkUpdateAutomatically.Text = " Check for updates automatically"; + this.checkUpdateAutomatically.UseVisualStyleBackColor = true; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(278, 21); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(56, 13); + this.label5.TabIndex = 24; + this.label5.Text = "Check for:"; + // + // optUpdateStable + // + this.optUpdateStable.AutoSize = true; + this.optUpdateStable.Checked = true; + this.optUpdateStable.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.optUpdateStable.Location = new System.Drawing.Point(340, 19); + this.optUpdateStable.Name = "optUpdateStable"; + this.optUpdateStable.Size = new System.Drawing.Size(103, 18); + this.optUpdateStable.TabIndex = 21; + this.optUpdateStable.TabStop = true; + this.optUpdateStable.Text = "Stable releases"; + this.optUpdateStable.UseVisualStyleBackColor = true; + // + // optUpdateAlpha + // + this.optUpdateAlpha.AutoSize = true; + this.optUpdateAlpha.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.optUpdateAlpha.Location = new System.Drawing.Point(340, 67); + this.optUpdateAlpha.Name = "optUpdateAlpha"; + this.optUpdateAlpha.Size = new System.Drawing.Size(100, 18); + this.optUpdateAlpha.TabIndex = 23; + this.optUpdateAlpha.Text = "Alpha releases"; + this.optUpdateAlpha.UseVisualStyleBackColor = true; + // + // optUpdateBeta + // + this.optUpdateBeta.AutoSize = true; + this.optUpdateBeta.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.optUpdateBeta.Location = new System.Drawing.Point(340, 43); + this.optUpdateBeta.Name = "optUpdateBeta"; + this.optUpdateBeta.Size = new System.Drawing.Size(95, 18); + this.optUpdateBeta.TabIndex = 22; + this.optUpdateBeta.Text = "Beta releases"; + this.optUpdateBeta.UseVisualStyleBackColor = true; + // + // buttonCancel + // + this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonCancel.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonCancel.Location = new System.Drawing.Point(345, 352); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.TabIndex = 2; + this.buttonCancel.Text = "&Cancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click); + // + // buttonApply + // + this.buttonApply.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonApply.Enabled = false; + this.buttonApply.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonApply.Location = new System.Drawing.Point(426, 352); + this.buttonApply.Name = "buttonApply"; + this.buttonApply.Size = new System.Drawing.Size(75, 23); + this.buttonApply.TabIndex = 3; + this.buttonApply.Text = "&Apply"; + this.buttonApply.UseVisualStyleBackColor = true; + this.buttonApply.Click += new System.EventHandler(this.buttonApply_Click); + // + // OptionsWindow + // + this.AcceptButton = this.buttonOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(513, 387); + this.Controls.Add(this.buttonApply); + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.tabControl); + this.Controls.Add(this.buttonOK); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "OptionsWindow"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Options"; + this.Load += new System.EventHandler(this.OptionsWindow_Load); + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.OptionsWindow_FormClosing); + ((System.ComponentModel.ISupportInitialize)(this.textUpdateInterval)).EndInit(); + this.tabControl.ResumeLayout(false); + this.tabGeneral.ResumeLayout(false); + this.tabGeneral.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.textMaxSamples)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.textIconMenuProcesses)).EndInit(); + this.tabAdvanced.ResumeLayout(false); + this.tabAdvanced.PerformLayout(); + this.tabHighlighting.ResumeLayout(false); + this.tabHighlighting.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.textHighlightingDuration)).EndInit(); + this.tabPlotting.ResumeLayout(false); + this.tabPlotting.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.textStep)).EndInit(); + this.tabSymbols.ResumeLayout(false); + this.tabSymbols.PerformLayout(); + this.tabUpdates.ResumeLayout(false); + this.UpdaterSettingsGroupBox.ResumeLayout(false); + this.UpdaterSettingsGroupBox.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.NumericUpDown textUpdateInterval; + private System.Windows.Forms.Button buttonOK; + private System.Windows.Forms.CheckBox checkShowProcessDomains; + private System.Windows.Forms.CheckBox checkWarnDangerous; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox textSearchEngine; + private System.Windows.Forms.TabControl tabControl; + private System.Windows.Forms.TabPage tabGeneral; + private System.Windows.Forms.TabPage tabHighlighting; + private System.Windows.Forms.Label label3; + private ProcessHacker.Components.ColorModifier colorNewProcesses; + private ProcessHacker.Components.ColorModifier colorRemovedProcesses; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.NumericUpDown textHighlightingDuration; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.CheckBox checkHideWhenMinimized; + private System.Windows.Forms.TabPage tabPlotting; + private System.Windows.Forms.Label label12; + private System.Windows.Forms.Label label13; + private ProcessHacker.Components.ColorModifier colorIORO; + private ProcessHacker.Components.ColorModifier colorIOW; + private ProcessHacker.Components.ColorModifier colorMemoryWS; + private ProcessHacker.Components.ColorModifier colorMemoryPB; + private System.Windows.Forms.Label label14; + private ProcessHacker.Components.ColorModifier colorCPUUT; + private System.Windows.Forms.Label label15; + private System.Windows.Forms.Label label16; + private ProcessHacker.Components.ColorModifier colorCPUKT; + private System.Windows.Forms.Label label17; + private System.Windows.Forms.CheckBox checkPlotterAntialias; + private System.Windows.Forms.ComboBox comboSizeUnits; + private System.Windows.Forms.Label label18; + private System.Windows.Forms.CheckBox checkStartHidden; + private System.Windows.Forms.TextBox textImposterNames; + private System.Windows.Forms.Label label21; + private System.Windows.Forms.Button buttonFont; + private System.Windows.Forms.NumericUpDown textIconMenuProcesses; + private System.Windows.Forms.Label label23; + private System.Windows.Forms.CheckBox checkHideWhenClosed; + private System.Windows.Forms.TabPage tabAdvanced; + private System.Windows.Forms.CheckBox checkReplaceTaskManager; + private System.Windows.Forms.CheckBox checkEnableKPH; + private System.Windows.Forms.CheckBox checkHideHandlesWithNoName; + private System.Windows.Forms.CheckBox checkVerifySignatures; + private System.Windows.Forms.ListView listHighlightingColors; + private System.Windows.Forms.ColumnHeader columnDescription; + private System.Windows.Forms.Button buttonChangeReplaceTaskManager; + private System.Windows.Forms.CheckBox checkAllowOnlyOneInstance; + private System.Windows.Forms.NumericUpDown textStep; + private System.Windows.Forms.Label label8; + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.Button buttonDisableAll; + private System.Windows.Forms.Button buttonEnableAll; + private System.Windows.Forms.TabPage tabSymbols; + private System.Windows.Forms.Label label9; + private System.Windows.Forms.TextBox textSearchPath; + private System.Windows.Forms.Label label10; + private System.Windows.Forms.Button buttonDbghelpBrowse; + private System.Windows.Forms.TextBox textDbghelpPath; + private System.Windows.Forms.CheckBox checkUndecorate; + private System.Windows.Forms.Button buttonApply; + private System.Windows.Forms.CheckBox checkHidePhConnections; + private System.Windows.Forms.CheckBox checkEnableExperimentalFeatures; + private System.Windows.Forms.Label label11; + private System.Windows.Forms.CheckBox checkScrollDownProcessTree; + private System.Windows.Forms.CheckBox checkFloatChildWindows; + private System.Windows.Forms.TabPage tabUpdates; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.RadioButton optUpdateAlpha; + private System.Windows.Forms.RadioButton optUpdateBeta; + private System.Windows.Forms.RadioButton optUpdateStable; + private System.Windows.Forms.Label label20; + private System.Windows.Forms.ComboBox comboToolbarStyle; + private System.Windows.Forms.CheckBox checkUpdateAutomatically; + private System.Windows.Forms.ComboBox comboElevationLevel; + private System.Windows.Forms.Label label22; + private System.Windows.Forms.GroupBox UpdaterSettingsGroupBox; + private System.Windows.Forms.NumericUpDown textMaxSamples; + private System.Windows.Forms.Label label6; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/OptionsWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/OptionsWindow.cs new file mode 100644 index 000000000..b82fd7331 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/OptionsWindow.cs @@ -0,0 +1,681 @@ +/* + * Process Hacker - + * options window + * + * Copyright (C) 2009 dmex + * Copyright (C) 2008 Dean + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Drawing; +using System.Threading; +using System.Windows.Forms; +using Aga.Controls.Tree; +using ProcessHacker.Common; +using ProcessHacker.Components; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.UI; +using System.Runtime.InteropServices; +using System.Net; +using System.Collections.Generic; +using System.Text.RegularExpressions; + +namespace ProcessHacker +{ + public partial class OptionsWindow : Form + { + private bool _isFirstPaint = true; + private string _oldDbghelp; + private string _oldTaskMgrDebugger; + private Font _font; + private bool _dontApply; + + public OptionsWindow() + : this(false) + { } + + public OptionsWindow(bool dontApply) + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + _dontApply = dontApply; + } + + public TabPage SelectedTab + { + get { return tabControl.SelectedTab; } + set { tabControl.SelectedTab = value; } + } + + public TabControl.TabPageCollection TabPages + { + get { return tabControl.TabPages; } + } + + private void OptionsWindow_Load(object sender, EventArgs e) + { + if (Program.ElevationType == TokenElevationType.Limited) + { + buttonChangeReplaceTaskManager.SetShieldIcon(true); + } + else + { + buttonChangeReplaceTaskManager.Visible = false; + } + } + + protected override void WndProc(ref Message m) + { + switch (m.Msg) + { + case (int)WindowMessage.Paint: + { + if (_isFirstPaint) + { + this.LoadStage1(); + } + + _isFirstPaint = false; + } + break; + } + + base.WndProc(ref m); + } + + private void LoadStage1() + { + this.InitializeHighlightingColors(); + this.LoadSettings(); + + if (!OSVersion.HasUac) + comboElevationLevel.Enabled = false; + + bool visualStyles = Application.RenderWithVisualStyles; + + foreach (TabPage tab in tabControl.TabPages) + { + foreach (Control c in tab.Controls) + { + // If we don't have visual styles or we're on XP, fix control backgrounds. + if (!visualStyles || OSVersion.IsBelowOrEqual(WindowsVersion.XP)) + { + if (c is CheckBox) + (c as CheckBox).FlatStyle = FlatStyle.Standard; + if (c is RadioButton) + (c as RadioButton).FlatStyle = FlatStyle.Standard; + } + + // Add event handlers to enable the apply button. + if (c is CheckBox || c is ListView || c is NumericUpDown) + c.Click += (sender, e) => this.EnableApplyButton(); + else if (c is TextBox) + (c as TextBox).TextChanged += (sender, e) => this.EnableApplyButton(); + else if (c is ComboBox) + (c as ComboBox).SelectedIndexChanged += (sender, e) => this.EnableApplyButton(); + else if (c is NumericUpDown) + (c as NumericUpDown).ValueChanged += (sender, e) => this.EnableApplyButton(); + else if (c is ColorModifier) + (c as ColorModifier).ColorChanged += (sender, e) => this.EnableApplyButton(); + else if (c is Button || c is Label || c is GroupBox) + Program.Void(); // Nothing + else + c.Click += (sender, e) => this.EnableApplyButton(); + } + } + + foreach (Control c in UpdaterSettingsGroupBox.Controls) + { + // If we don't have visual styles or we're on XP, fix control backgrounds. + if (!visualStyles || OSVersion.IsBelowOrEqual(WindowsVersion.XP)) + { + if (c is CheckBox) + (c as CheckBox).FlatStyle = FlatStyle.Standard; + if (c is RadioButton) + (c as RadioButton).FlatStyle = FlatStyle.Standard; + } + + c.Click += (sender, e) => this.EnableApplyButton(); + } + } + + private void OptionsWindow_FormClosing(object sender, FormClosingEventArgs e) + { + //e.Cancel = !buttonCancel.Enabled; + } + + private void EnableApplyButton() + { + if (!_dontApply) + buttonApply.Enabled = true; + } + + private void AddToList(string key, string description, string longDescription) + { + listHighlightingColors.Items.Add(new ListViewItem() + { + Name = key, + Text = description, + ToolTipText = longDescription + }); + } + + private void InitializeHighlightingColors() + { + AddToList("ColorOwnProcesses", "Own Processes", + "Processes running under the same user account as Process Hacker."); + AddToList("ColorSystemProcesses", "System Processes", + "Processes running under the NT AUTHORITY\\SYSTEM user account."); + AddToList("ColorServiceProcesses", "Service Processes", + "Processes which host one or more services."); + AddToList("ColorDebuggedProcesses", "Debugged Processes", + "Processes that are currently being debugged."); + AddToList("ColorElevatedProcesses", "Elevated Processes", + "Processes with full privileges on a Windows Vista system with UAC enabled."); + AddToList("ColorJobProcesses", "Job Processes", + "Processes associated with a job."); + AddToList("ColorDotNetProcesses", ".NET Processes and DLLs", + ".NET, or managed processes and DLLs."); + AddToList("ColorPosixProcesses", "POSIX Processes", + "Processes running under the POSIX subsystem."); + AddToList("ColorPackedProcesses", "Packed/Dangerous Processes", + "Executables are sometimes \"packed\" to reduce their size.\n" + + "\"Dangerous processes\" includes processes with invalid signatures and unverified " + + "processes with the name of a system process."); + + // WOW64, 64-bit only. + if (IntPtr.Size == 8) + { + AddToList("ColorWow64Processes", "32-bit Processes", + "Processes running under WOW64, i.e. 32-bit."); + } + + AddToList("ColorSuspended", "Suspended Threads", + "Threads that are suspended from execution."); + AddToList("ColorGuiThreads", "GUI Threads", + "Threads that have made at least one GUI-related system call."); + AddToList("ColorRelocatedDlls", "Relocated DLLs", + "DLLs that were not loaded at their preferred image bases."); + AddToList("ColorProtectedHandles", "Protected Handles", + "Handles that are protected from being closed."); + AddToList("ColorInheritHandles", "Inherit Handles", + "Handles that are to be inherited by any child processes."); + } + + private void listHighlightingColors_DoubleClick(object sender, EventArgs e) + { + listHighlightingColors.SelectedItems[0].Checked = !listHighlightingColors.SelectedItems[0].Checked; + + ColorDialog cd = new ColorDialog(); + + cd.Color = listHighlightingColors.SelectedItems[0].BackColor; + cd.FullOpen = true; + + if (cd.ShowDialog() == DialogResult.OK) + { + listHighlightingColors.SelectedItems[0].BackColor = cd.Color; + listHighlightingColors.SelectedItems[0].ForeColor = TreeNodeAdv.GetForeColor(cd.Color); + } + } + + private void textUpdateInterval_Leave(object sender, EventArgs e) + { + try + { + Properties.Settings.Default.RefreshInterval = Int32.Parse(textUpdateInterval.Value.ToString()); + } + catch + { + PhUtils.ShowError("The entered value is not valid."); + textUpdateInterval.Select(); + } + } + + private void textIconMenuProcesses_Leave(object sender, EventArgs e) + { + try + { + Properties.Settings.Default.IconMenuProcessCount = Int32.Parse(textIconMenuProcesses.Value.ToString()); + } + catch + { + PhUtils.ShowError("The entered value is not valid."); + textIconMenuProcesses.Select(); + } + } + + private void LoadSettings() + { + // General + _font = Properties.Settings.Default.Font; + buttonFont.Font = _font; + textUpdateInterval.Value = Properties.Settings.Default.RefreshInterval; + textIconMenuProcesses.Value = Properties.Settings.Default.IconMenuProcessCount; + textMaxSamples.Value = Properties.Settings.Default.MaxSamples; + textStep.Value = Properties.Settings.Default.PlotterStep; + textSearchEngine.Text = Properties.Settings.Default.SearchEngine; + comboSizeUnits.SelectedItem = + Utils.SizeUnitNames[Properties.Settings.Default.UnitSpecifier]; + checkWarnDangerous.Checked = Properties.Settings.Default.WarnDangerous; + checkShowProcessDomains.Checked = Properties.Settings.Default.ShowAccountDomains; + checkHideWhenMinimized.Checked = Properties.Settings.Default.HideWhenMinimized; + checkHideWhenClosed.Checked = Properties.Settings.Default.HideWhenClosed; + checkAllowOnlyOneInstance.Checked = Properties.Settings.Default.AllowOnlyOneInstance; + checkVerifySignatures.Checked = Properties.Settings.Default.VerifySignatures; + checkHideHandlesWithNoName.Checked = Properties.Settings.Default.HideHandlesWithNoName; + checkEnableKPH.Checked = Properties.Settings.Default.EnableKPH; + checkEnableExperimentalFeatures.Checked = Properties.Settings.Default.EnableExperimentalFeatures; + checkStartHidden.Checked = Properties.Settings.Default.StartHidden; + checkScrollDownProcessTree.Checked = Properties.Settings.Default.ScrollDownProcessTree; + checkFloatChildWindows.Checked = Properties.Settings.Default.FloatChildWindows; + checkHidePhConnections.Checked = Properties.Settings.Default.HideProcessHackerNetworkConnections; + + if (OSVersion.HasUac) + { + comboElevationLevel.SelectedIndex = Properties.Settings.Default.ElevationLevel; + } + else + { + comboElevationLevel.SelectedIndex = 0; + } + + textImposterNames.Text = Properties.Settings.Default.ImposterNames; + + switch (Properties.Settings.Default.ToolStripDisplayStyle) + { + case 0: + comboToolbarStyle.SelectedIndex = 0; + break; + case 1: + comboToolbarStyle.SelectedIndex = 1; + break; + case 2: + comboToolbarStyle.SelectedIndex = 2; + break; + default: + comboToolbarStyle.SelectedIndex = 1; + break; + } + + // Highlighting + textHighlightingDuration.Value = Properties.Settings.Default.HighlightingDuration; + colorNewProcesses.Color = Properties.Settings.Default.ColorNew; + colorRemovedProcesses.Color = Properties.Settings.Default.ColorRemoved; + + foreach (ListViewItem item in listHighlightingColors.Items) + { + Color c = (Color)Properties.Settings.Default[item.Name]; + bool use = (bool)Properties.Settings.Default["Use" + item.Name]; + + item.BackColor = c; + item.ForeColor = TreeNodeAdv.GetForeColor(item.BackColor); + item.Checked = use; + } + + // Plotting + checkPlotterAntialias.Checked = Properties.Settings.Default.PlotterAntialias; + colorCPUKT.Color = Properties.Settings.Default.PlotterCPUKernelColor; + colorCPUUT.Color = Properties.Settings.Default.PlotterCPUUserColor; + colorMemoryPB.Color = Properties.Settings.Default.PlotterMemoryPrivateColor; + colorMemoryWS.Color = Properties.Settings.Default.PlotterMemoryWSColor; + colorIORO.Color = Properties.Settings.Default.PlotterIOROColor; + colorIOW.Color = Properties.Settings.Default.PlotterIOWColor; + + // Replace Task Manager + // See if we can write to the key. + try + { + var key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey( + "Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options", + true + ); + + try + { + if (!Array.Exists(key.GetSubKeyNames(), s => s.Equals("taskmgr.exe", StringComparison.InvariantCultureIgnoreCase))) + key.CreateSubKey("taskmgr.exe"); + + Microsoft.Win32.Registry.LocalMachine.OpenSubKey( + "Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\taskmgr.exe", + true + ).Close(); + } + finally + { + key.Close(); + } + } + catch + { + checkReplaceTaskManager.Enabled = false; + } + + try + { + using (var key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey( + "Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\taskmgr.exe", + false + )) + { + if ((_oldTaskMgrDebugger = (string)key.GetValue("Debugger", "")).ToLower().Trim('"') == + ProcessHandle.GetCurrent().GetMainModule().FileName.ToLower()) + { + checkReplaceTaskManager.Checked = true; + } + else + { + checkReplaceTaskManager.Checked = false; + } + } + } + catch + { + checkReplaceTaskManager.Enabled = false; + } + + // Symbols + try + { + _oldDbghelp = textDbghelpPath.Text = Properties.Settings.Default.DbgHelpPath; + textSearchPath.Text = Properties.Settings.Default.DbgHelpSearchPath; + checkUndecorate.Checked = Properties.Settings.Default.DbgHelpUndecorate; + } + catch + { } + + checkUpdateAutomatically.Checked = Properties.Settings.Default.AppUpdateAutomatic; + + switch ((AppUpdateLevel)Properties.Settings.Default.AppUpdateLevel) + { + case AppUpdateLevel.Stable: + default: + optUpdateStable.Checked = true; + break; + case AppUpdateLevel.Beta: + optUpdateBeta.Checked = true; + break; + case AppUpdateLevel.Alpha: + optUpdateAlpha.Checked = true; + break; + } + } + + private void SaveSettings() + { + Properties.Settings.Default.Font = _font; + Properties.Settings.Default.SearchEngine = textSearchEngine.Text; + Properties.Settings.Default.WarnDangerous = checkWarnDangerous.Checked; + Properties.Settings.Default.ShowAccountDomains = checkShowProcessDomains.Checked; + Properties.Settings.Default.HideWhenMinimized = checkHideWhenMinimized.Checked; + Properties.Settings.Default.HideWhenClosed = checkHideWhenClosed.Checked; + Properties.Settings.Default.AllowOnlyOneInstance = checkAllowOnlyOneInstance.Checked; + Properties.Settings.Default.UnitSpecifier = + Array.IndexOf(Utils.SizeUnitNames, comboSizeUnits.SelectedItem); + Properties.Settings.Default.VerifySignatures = checkVerifySignatures.Checked; + Properties.Settings.Default.HideHandlesWithNoName = checkHideHandlesWithNoName.Checked; + Properties.Settings.Default.ScrollDownProcessTree = checkScrollDownProcessTree.Checked; + Properties.Settings.Default.FloatChildWindows = checkFloatChildWindows.Checked; + Properties.Settings.Default.StartHidden = checkStartHidden.Checked; + Properties.Settings.Default.EnableKPH = checkEnableKPH.Checked; + Properties.Settings.Default.EnableExperimentalFeatures = checkEnableExperimentalFeatures.Checked; + Properties.Settings.Default.ImposterNames = textImposterNames.Text.ToLower(); + Properties.Settings.Default.HideProcessHackerNetworkConnections = checkHidePhConnections.Checked; + Properties.Settings.Default.ElevationLevel = comboElevationLevel.SelectedIndex; + + Properties.Settings.Default.MaxSamples = (int)textMaxSamples.Value; + HistoryManager.GlobalMaxCount = Properties.Settings.Default.MaxSamples; + Properties.Settings.Default.PlotterStep = (int)textStep.Value; + ProcessHacker.Components.Plotter.GlobalMoveStep = Properties.Settings.Default.PlotterStep; + + Properties.Settings.Default.HighlightingDuration = (int)textHighlightingDuration.Value; + Properties.Settings.Default.ColorNew = colorNewProcesses.Color; + Properties.Settings.Default.ColorRemoved = colorRemovedProcesses.Color; + + foreach (ListViewItem item in listHighlightingColors.Items) + { + Properties.Settings.Default[item.Name] = item.BackColor; + Properties.Settings.Default["Use" + item.Name] = item.Checked; + } + + Properties.Settings.Default.PlotterAntialias = checkPlotterAntialias.Checked; + Properties.Settings.Default.PlotterCPUKernelColor = colorCPUKT.Color; + Properties.Settings.Default.PlotterCPUUserColor = colorCPUUT.Color; + Properties.Settings.Default.PlotterMemoryPrivateColor = colorMemoryPB.Color; + Properties.Settings.Default.PlotterMemoryWSColor = colorMemoryWS.Color; + Properties.Settings.Default.PlotterIOROColor = colorIORO.Color; + Properties.Settings.Default.PlotterIOWColor = colorIOW.Color; + + Properties.Settings.Default.DbgHelpPath = textDbghelpPath.Text; + Properties.Settings.Default.DbgHelpSearchPath = textSearchPath.Text; + Properties.Settings.Default.DbgHelpUndecorate = checkUndecorate.Checked; + + if (optUpdateStable.Checked) + { + Properties.Settings.Default.AppUpdateLevel = (int)AppUpdateLevel.Stable; + } + else if (optUpdateBeta.Checked) + { + Properties.Settings.Default.AppUpdateLevel = (int)AppUpdateLevel.Beta; + } + else if (optUpdateAlpha.Checked) + { + Properties.Settings.Default.AppUpdateLevel = (int)AppUpdateLevel.Alpha; + } + + Properties.Settings.Default.AppUpdateAutomatic = checkUpdateAutomatically.Checked; + + switch (comboToolbarStyle.SelectedIndex) + { + case 0: + Properties.Settings.Default.ToolStripDisplayStyle = 0; + break; + case 1: + Properties.Settings.Default.ToolStripDisplayStyle = 1; + break; + case 2: + Properties.Settings.Default.ToolStripDisplayStyle = 2; + break; + default: + Properties.Settings.Default.ToolStripDisplayStyle = 0; + break; + } + + Properties.Settings.Default.Save(); + + if (checkReplaceTaskManager.Enabled) + { + try + { + string fileName = ProcessHandle.GetCurrent().GetMainModule().FileName; + + using (var key = Microsoft.Win32.Registry.LocalMachine.OpenSubKey( + "Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\taskmgr.exe", + true + )) + { + if (checkReplaceTaskManager.Checked) + { + key.SetValue("Debugger", "\"" + fileName + "\""); + // In case the user presses Apply and then OK. + _oldTaskMgrDebugger = "\"" + fileName + "\""; + } + else + { + if (_oldTaskMgrDebugger.ToLower().Trim('"') == fileName.ToLower()) + { + key.DeleteValue("Debugger"); + _oldTaskMgrDebugger = ""; + } + else if (_oldTaskMgrDebugger != "") + { + key.SetValue("Debugger", _oldTaskMgrDebugger); + } + } + } + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to replace Task Manager with Process Hacker", ex); + } + } + } + + private void ApplySettings() + { + Settings.Refresh(); + + Program.ImposterNames = new System.Collections.Specialized.StringCollection(); + Utils.UnitSpecifier = Properties.Settings.Default.UnitSpecifier; + + foreach (string s in Properties.Settings.Default.ImposterNames.Split(',')) + Program.ImposterNames.Add(s.Trim()); + + Program.HackerWindow.ApplyIconVisibilities(); + Program.HackerWindow.LoadFixMenuItems(); + Program.ProcessProvider.Interval = Properties.Settings.Default.RefreshInterval; + Program.ServiceProvider.Interval = Properties.Settings.Default.RefreshInterval; + Program.NetworkProvider.Interval = Properties.Settings.Default.RefreshInterval; + + HighlightingContext.HighlightingDuration = Properties.Settings.Default.HighlightingDuration; + HighlightingContext.Colors[ListViewItemState.New] = Properties.Settings.Default.ColorNew; + HighlightingContext.Colors[ListViewItemState.Removed] = Properties.Settings.Default.ColorRemoved; + + TreeNodeAdv.StateColors[TreeNodeAdv.NodeState.New] = Properties.Settings.Default.ColorNew; + TreeNodeAdv.StateColors[TreeNodeAdv.NodeState.Removed] = Properties.Settings.Default.ColorRemoved; + + Program.ProcessProvider.Interval = Properties.Settings.Default.RefreshInterval; + Program.ServiceProvider.Interval = Properties.Settings.Default.RefreshInterval; + Program.NetworkProvider.Interval = Properties.Settings.Default.RefreshInterval; + Program.SharedThreadProvider.Interval = Properties.Settings.Default.RefreshInterval; + Program.SecondarySharedThreadProvider.Interval = Properties.Settings.Default.RefreshInterval; + + Program.HackerWindow.ProcessTree.RefreshItems(); + Program.ApplyFont(Properties.Settings.Default.Font); + + if (_oldDbghelp != textDbghelpPath.Text) + PhUtils.ShowInformation("One or more options you have changed require a restart of Process Hacker."); + } + + private void buttonOK_Click(object sender, EventArgs e) + { + this.SaveSettings(); + + if (!this._dontApply) + this.ApplySettings(); + + DialogResult = DialogResult.OK; + + this.Close(); + } + + private void buttonCancel_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.Cancel; + + this.Close(); + } + + private void buttonFont_Click(object sender, EventArgs e) + { + FontDialog fd = new FontDialog(); + + fd.Font = _font; + fd.FontMustExist = true; + fd.ShowEffects = true; + + if (fd.ShowDialog() == DialogResult.OK) + { + _font = fd.Font; + buttonFont.Font = _font; + this.EnableApplyButton(); + } + } + + private void buttonChangeReplaceTaskManager_Click(object sender, EventArgs e) + { + this.SaveSettings(); + if (!_dontApply) + this.ApplySettings(); + buttonApply.Enabled = false; + + string args = "-o -hwnd " + this.Handle.ToString() + + " -rect " + this.Location.X.ToString() + "," + this.Location.Y.ToString() + "," + + this.Size.Width.ToString() + "," + this.Size.Height.ToString(); + + // Avoid cross-thread operation. + IntPtr thisHandle = this.Handle; + + Thread t = new Thread(() => + { + Program.StartProcessHackerAdminWait(args, thisHandle, 0xffffffff); + + this.BeginInvoke(new MethodInvoker(() => + { + Properties.Settings.Default.Reload(); + this.LoadSettings(); + if (!_dontApply) + this.ApplySettings(); + buttonApply.Enabled = false; + buttonOK.Select(); + })); + }); + + t.Start(); + } + + private void buttonEnableAll_Click(object sender, EventArgs e) + { + foreach (ListViewItem item in listHighlightingColors.Items) + item.Checked = true; + + this.EnableApplyButton(); + } + + private void buttonDisableAll_Click(object sender, EventArgs e) + { + foreach (ListViewItem item in listHighlightingColors.Items) + item.Checked = false; + + this.EnableApplyButton(); + } + + private void buttonDbghelpBrowse_Click(object sender, EventArgs e) + { + OpenFileDialog ofd = new OpenFileDialog(); + + ofd.Filter = "dbghelp.dll|dbghelp.dll|DLL files (*.dll)|*.dll|All files (*.*)|*.*"; + ofd.FileName = textDbghelpPath.Text; + + if (ofd.ShowDialog() == DialogResult.OK) + textDbghelpPath.Text = ofd.FileName; + } + + private void buttonApply_Click(object sender, EventArgs e) + { + this.SaveSettings(); + this.ApplySettings(); + this.buttonApply.Enabled = false; + this.buttonOK.Select(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/OptionsWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/OptionsWindow.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/OptionsWindow.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/PEWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/PEWindow.Designer.cs new file mode 100644 index 000000000..5b15c0fa3 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/PEWindow.Designer.cs @@ -0,0 +1,411 @@ +namespace ProcessHacker +{ + partial class PEWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + Program.PEWindows.Remove(Id); + + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PEWindow)); + this.tabControl = new System.Windows.Forms.TabControl(); + this.tabCOFFHeader = new System.Windows.Forms.TabPage(); + this.listCOFFHeader = new System.Windows.Forms.ListView(); + this.columnCHName = new System.Windows.Forms.ColumnHeader(); + this.columnCHValue = new System.Windows.Forms.ColumnHeader(); + this.tabCOFFOptionalHeader = new System.Windows.Forms.TabPage(); + this.listCOFFOptionalHeader = new System.Windows.Forms.ListView(); + this.columnCOHName = new System.Windows.Forms.ColumnHeader(); + this.columnCOHValue = new System.Windows.Forms.ColumnHeader(); + this.tabImageData = new System.Windows.Forms.TabPage(); + this.listImageData = new System.Windows.Forms.ListView(); + this.columnIDName = new System.Windows.Forms.ColumnHeader(); + this.columnIDRVA = new System.Windows.Forms.ColumnHeader(); + this.columnIDSize = new System.Windows.Forms.ColumnHeader(); + this.tabSections = new System.Windows.Forms.TabPage(); + this.listSections = new System.Windows.Forms.ListView(); + this.columnSectionName = new System.Windows.Forms.ColumnHeader(); + this.columnSectionVA = new System.Windows.Forms.ColumnHeader(); + this.columnSectionVS = new System.Windows.Forms.ColumnHeader(); + this.columnSectionFileAddress = new System.Windows.Forms.ColumnHeader(); + this.columnSectionCharacteristics = new System.Windows.Forms.ColumnHeader(); + this.tabExports = new System.Windows.Forms.TabPage(); + this.listExports = new System.Windows.Forms.ListView(); + this.columnExportName = new System.Windows.Forms.ColumnHeader(); + this.columnExportOrdinal = new System.Windows.Forms.ColumnHeader(); + this.columnExportFileAddress = new System.Windows.Forms.ColumnHeader(); + this.tabImports = new System.Windows.Forms.TabPage(); + this.listImports = new ProcessHacker.ExtendedListView(); + this.columnImportName = new System.Windows.Forms.ColumnHeader(); + this.columnImportHint = new System.Windows.Forms.ColumnHeader(); + this.vistaMenu = new wyDay.Controls.VistaMenu(this.components); + this.tabControl.SuspendLayout(); + this.tabCOFFHeader.SuspendLayout(); + this.tabCOFFOptionalHeader.SuspendLayout(); + this.tabImageData.SuspendLayout(); + this.tabSections.SuspendLayout(); + this.tabExports.SuspendLayout(); + this.tabImports.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.vistaMenu)).BeginInit(); + this.SuspendLayout(); + // + // tabControl + // + this.tabControl.Controls.Add(this.tabCOFFHeader); + this.tabControl.Controls.Add(this.tabCOFFOptionalHeader); + this.tabControl.Controls.Add(this.tabImageData); + this.tabControl.Controls.Add(this.tabSections); + this.tabControl.Controls.Add(this.tabExports); + this.tabControl.Controls.Add(this.tabImports); + this.tabControl.Dock = System.Windows.Forms.DockStyle.Fill; + this.tabControl.Location = new System.Drawing.Point(0, 0); + this.tabControl.Name = "tabControl"; + this.tabControl.SelectedIndex = 0; + this.tabControl.Size = new System.Drawing.Size(423, 402); + this.tabControl.TabIndex = 0; + // + // tabCOFFHeader + // + this.tabCOFFHeader.Controls.Add(this.listCOFFHeader); + this.tabCOFFHeader.Location = new System.Drawing.Point(4, 22); + this.tabCOFFHeader.Name = "tabCOFFHeader"; + this.tabCOFFHeader.Padding = new System.Windows.Forms.Padding(3); + this.tabCOFFHeader.Size = new System.Drawing.Size(415, 376); + this.tabCOFFHeader.TabIndex = 0; + this.tabCOFFHeader.Text = "COFF Header"; + this.tabCOFFHeader.UseVisualStyleBackColor = true; + // + // listCOFFHeader + // + this.listCOFFHeader.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnCHName, + this.columnCHValue}); + this.listCOFFHeader.Dock = System.Windows.Forms.DockStyle.Fill; + this.listCOFFHeader.FullRowSelect = true; + this.listCOFFHeader.HideSelection = false; + this.listCOFFHeader.Location = new System.Drawing.Point(3, 3); + this.listCOFFHeader.Name = "listCOFFHeader"; + this.listCOFFHeader.ShowItemToolTips = true; + this.listCOFFHeader.Size = new System.Drawing.Size(409, 370); + this.listCOFFHeader.Sorting = System.Windows.Forms.SortOrder.Ascending; + this.listCOFFHeader.TabIndex = 0; + this.listCOFFHeader.UseCompatibleStateImageBehavior = false; + this.listCOFFHeader.View = System.Windows.Forms.View.Details; + // + // columnCHName + // + this.columnCHName.Text = "Name"; + this.columnCHName.Width = 160; + // + // columnCHValue + // + this.columnCHValue.Text = "Value"; + this.columnCHValue.Width = 200; + // + // tabCOFFOptionalHeader + // + this.tabCOFFOptionalHeader.Controls.Add(this.listCOFFOptionalHeader); + this.tabCOFFOptionalHeader.Location = new System.Drawing.Point(4, 22); + this.tabCOFFOptionalHeader.Name = "tabCOFFOptionalHeader"; + this.tabCOFFOptionalHeader.Padding = new System.Windows.Forms.Padding(3); + this.tabCOFFOptionalHeader.Size = new System.Drawing.Size(415, 376); + this.tabCOFFOptionalHeader.TabIndex = 1; + this.tabCOFFOptionalHeader.Text = "COFF Optional Header"; + this.tabCOFFOptionalHeader.UseVisualStyleBackColor = true; + // + // listCOFFOptionalHeader + // + this.listCOFFOptionalHeader.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnCOHName, + this.columnCOHValue}); + this.listCOFFOptionalHeader.Dock = System.Windows.Forms.DockStyle.Fill; + this.listCOFFOptionalHeader.FullRowSelect = true; + this.listCOFFOptionalHeader.HideSelection = false; + this.listCOFFOptionalHeader.Location = new System.Drawing.Point(3, 3); + this.listCOFFOptionalHeader.Name = "listCOFFOptionalHeader"; + this.listCOFFOptionalHeader.ShowItemToolTips = true; + this.listCOFFOptionalHeader.Size = new System.Drawing.Size(409, 370); + this.listCOFFOptionalHeader.Sorting = System.Windows.Forms.SortOrder.Ascending; + this.listCOFFOptionalHeader.TabIndex = 1; + this.listCOFFOptionalHeader.UseCompatibleStateImageBehavior = false; + this.listCOFFOptionalHeader.View = System.Windows.Forms.View.Details; + // + // columnCOHName + // + this.columnCOHName.Text = "Name"; + this.columnCOHName.Width = 160; + // + // columnCOHValue + // + this.columnCOHValue.Text = "Value"; + this.columnCOHValue.Width = 200; + // + // tabImageData + // + this.tabImageData.Controls.Add(this.listImageData); + this.tabImageData.Location = new System.Drawing.Point(4, 22); + this.tabImageData.Name = "tabImageData"; + this.tabImageData.Padding = new System.Windows.Forms.Padding(3); + this.tabImageData.Size = new System.Drawing.Size(415, 376); + this.tabImageData.TabIndex = 5; + this.tabImageData.Text = "Image Data"; + this.tabImageData.UseVisualStyleBackColor = true; + // + // listImageData + // + this.listImageData.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnIDName, + this.columnIDRVA, + this.columnIDSize}); + this.listImageData.Dock = System.Windows.Forms.DockStyle.Fill; + this.listImageData.FullRowSelect = true; + this.listImageData.HideSelection = false; + this.listImageData.Location = new System.Drawing.Point(3, 3); + this.listImageData.Name = "listImageData"; + this.listImageData.ShowItemToolTips = true; + this.listImageData.Size = new System.Drawing.Size(409, 370); + this.listImageData.TabIndex = 2; + this.listImageData.UseCompatibleStateImageBehavior = false; + this.listImageData.View = System.Windows.Forms.View.Details; + // + // columnIDName + // + this.columnIDName.Text = "Name"; + this.columnIDName.Width = 120; + // + // columnIDRVA + // + this.columnIDRVA.Text = "RVA"; + this.columnIDRVA.Width = 100; + // + // columnIDSize + // + this.columnIDSize.Text = "Size"; + this.columnIDSize.Width = 100; + // + // tabSections + // + this.tabSections.Controls.Add(this.listSections); + this.tabSections.Location = new System.Drawing.Point(4, 22); + this.tabSections.Name = "tabSections"; + this.tabSections.Padding = new System.Windows.Forms.Padding(3); + this.tabSections.Size = new System.Drawing.Size(415, 376); + this.tabSections.TabIndex = 2; + this.tabSections.Text = "Sections"; + this.tabSections.UseVisualStyleBackColor = true; + // + // listSections + // + this.listSections.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnSectionName, + this.columnSectionVA, + this.columnSectionVS, + this.columnSectionFileAddress, + this.columnSectionCharacteristics}); + this.listSections.Dock = System.Windows.Forms.DockStyle.Fill; + this.listSections.FullRowSelect = true; + this.listSections.HideSelection = false; + this.listSections.Location = new System.Drawing.Point(3, 3); + this.listSections.Name = "listSections"; + this.listSections.ShowItemToolTips = true; + this.listSections.Size = new System.Drawing.Size(409, 370); + this.listSections.TabIndex = 1; + this.listSections.UseCompatibleStateImageBehavior = false; + this.listSections.View = System.Windows.Forms.View.Details; + // + // columnSectionName + // + this.columnSectionName.Text = "Name"; + this.columnSectionName.Width = 70; + // + // columnSectionVA + // + this.columnSectionVA.Text = "Virtual Address"; + this.columnSectionVA.Width = 80; + // + // columnSectionVS + // + this.columnSectionVS.Text = "Virtual Size"; + // + // columnSectionFileAddress + // + this.columnSectionFileAddress.Text = "File Address"; + this.columnSectionFileAddress.Width = 80; + // + // columnSectionCharacteristics + // + this.columnSectionCharacteristics.Text = "Characteristics"; + this.columnSectionCharacteristics.Width = 100; + // + // tabExports + // + this.tabExports.Controls.Add(this.listExports); + this.tabExports.Location = new System.Drawing.Point(4, 22); + this.tabExports.Name = "tabExports"; + this.tabExports.Padding = new System.Windows.Forms.Padding(3); + this.tabExports.Size = new System.Drawing.Size(415, 376); + this.tabExports.TabIndex = 3; + this.tabExports.Text = "Exports"; + this.tabExports.UseVisualStyleBackColor = true; + // + // listExports + // + this.listExports.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnExportOrdinal, + this.columnExportName, + this.columnExportFileAddress}); + this.listExports.Dock = System.Windows.Forms.DockStyle.Fill; + this.listExports.FullRowSelect = true; + this.listExports.HideSelection = false; + this.listExports.Location = new System.Drawing.Point(3, 3); + this.listExports.Name = "listExports"; + this.listExports.ShowItemToolTips = true; + this.listExports.Size = new System.Drawing.Size(409, 370); + this.listExports.Sorting = System.Windows.Forms.SortOrder.Ascending; + this.listExports.TabIndex = 0; + this.listExports.UseCompatibleStateImageBehavior = false; + this.listExports.View = System.Windows.Forms.View.Details; + this.listExports.VirtualMode = true; + this.listExports.DoubleClick += new System.EventHandler(this.listExports_DoubleClick); + this.listExports.RetrieveVirtualItem += new System.Windows.Forms.RetrieveVirtualItemEventHandler(this.listExports_RetrieveVirtualItem); + // + // columnExportName + // + this.columnExportName.Text = "Name"; + this.columnExportName.Width = 220; + // + // columnExportOrdinal + // + this.columnExportOrdinal.Text = "Ordinal"; + // + // columnExportFileAddress + // + this.columnExportFileAddress.Text = "File Address"; + this.columnExportFileAddress.Width = 80; + // + // tabImports + // + this.tabImports.Controls.Add(this.listImports); + this.tabImports.Location = new System.Drawing.Point(4, 22); + this.tabImports.Name = "tabImports"; + this.tabImports.Padding = new System.Windows.Forms.Padding(3); + this.tabImports.Size = new System.Drawing.Size(415, 376); + this.tabImports.TabIndex = 4; + this.tabImports.Text = "Imports"; + this.tabImports.UseVisualStyleBackColor = true; + // + // listImports + // + this.listImports.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnImportName, + this.columnImportHint}); + this.listImports.Dock = System.Windows.Forms.DockStyle.Fill; + this.listImports.FullRowSelect = true; + this.listImports.HideSelection = false; + this.listImports.Location = new System.Drawing.Point(3, 3); + this.listImports.Name = "listImports"; + this.listImports.ShowItemToolTips = true; + this.listImports.Size = new System.Drawing.Size(409, 370); + this.listImports.Sorting = System.Windows.Forms.SortOrder.Ascending; + this.listImports.TabIndex = 2; + this.listImports.UseCompatibleStateImageBehavior = false; + this.listImports.View = System.Windows.Forms.View.Details; + // + // columnImportName + // + this.columnImportName.Text = "Name"; + this.columnImportName.Width = 160; + // + // columnImportHint + // + this.columnImportHint.Text = "Hint"; + this.columnImportHint.Width = 80; + // + // vistaMenu + // + this.vistaMenu.ContainerControl = this; + this.vistaMenu.DelaySetImageCalls = false; + // + // PEWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(423, 402); + this.Controls.Add(this.tabControl); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Name = "PEWindow"; + this.Text = "PE File"; + this.Load += new System.EventHandler(this.PEWindow_Load); + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.PEWindow_FormClosing); + this.tabControl.ResumeLayout(false); + this.tabCOFFHeader.ResumeLayout(false); + this.tabCOFFOptionalHeader.ResumeLayout(false); + this.tabImageData.ResumeLayout(false); + this.tabSections.ResumeLayout(false); + this.tabExports.ResumeLayout(false); + this.tabImports.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.vistaMenu)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private wyDay.Controls.VistaMenu vistaMenu; + private System.Windows.Forms.TabControl tabControl; + private System.Windows.Forms.TabPage tabCOFFHeader; + private System.Windows.Forms.TabPage tabCOFFOptionalHeader; + private System.Windows.Forms.TabPage tabSections; + private System.Windows.Forms.TabPage tabExports; + private System.Windows.Forms.TabPage tabImports; + private System.Windows.Forms.ListView listExports; + private System.Windows.Forms.ColumnHeader columnExportName; + private System.Windows.Forms.ColumnHeader columnExportOrdinal; + private System.Windows.Forms.ColumnHeader columnExportFileAddress; + private System.Windows.Forms.ListView listCOFFHeader; + private System.Windows.Forms.ColumnHeader columnCHName; + private System.Windows.Forms.ColumnHeader columnCHValue; + private System.Windows.Forms.ListView listCOFFOptionalHeader; + private System.Windows.Forms.ColumnHeader columnCOHName; + private System.Windows.Forms.ColumnHeader columnCOHValue; + private System.Windows.Forms.ListView listSections; + private System.Windows.Forms.ColumnHeader columnSectionName; + private System.Windows.Forms.ColumnHeader columnSectionVA; + private System.Windows.Forms.ColumnHeader columnSectionFileAddress; + private System.Windows.Forms.ColumnHeader columnSectionCharacteristics; + private System.Windows.Forms.ColumnHeader columnSectionVS; + private System.Windows.Forms.TabPage tabImageData; + private System.Windows.Forms.ListView listImageData; + private System.Windows.Forms.ColumnHeader columnIDName; + private System.Windows.Forms.ColumnHeader columnIDRVA; + private System.Windows.Forms.ColumnHeader columnIDSize; + private ExtendedListView listImports; + private System.Windows.Forms.ColumnHeader columnImportName; + private System.Windows.Forms.ColumnHeader columnImportHint; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/PEWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/PEWindow.cs new file mode 100644 index 000000000..842867479 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/PEWindow.cs @@ -0,0 +1,334 @@ +/* + * Process Hacker - + * PE window + * + * Copyright (C) 2008 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 . + */ + +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.UI; +using ProcessHacker.Native; +using ProcessHacker.Native.Image; +using ProcessHacker.Native.Api; + +namespace ProcessHacker +{ + public partial class PEWindow : Form + { + private string _path; + private MappedImage _mappedImage; + + public PEWindow(string path) + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + _path = path; + this.Text = "PE File - " + path; + Program.PEWindows.Add(Id, this); + + this.InitializeLists(); + + try + { + _mappedImage = new MappedImage(path); + this.Read(); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to load the specified file", ex); + + this.Close(); + } + } + + private void PEWindow_Load(object sender, EventArgs e) + { + this.Size = Properties.Settings.Default.PEWindowSize; + + this.SetPhParent(); + } + + private void PEWindow_FormClosing(object sender, FormClosingEventArgs e) + { + this.Visible = false; + + Properties.Settings.Default.PECOFFHColumns = ColumnSettings.SaveSettings(listCOFFHeader); + Properties.Settings.Default.PECOFFOHColumns = ColumnSettings.SaveSettings(listCOFFOptionalHeader); + Properties.Settings.Default.PEImageDataColumns = ColumnSettings.SaveSettings(listImageData); + Properties.Settings.Default.PESectionsColumns = ColumnSettings.SaveSettings(listSections); + Properties.Settings.Default.PEExportsColumns = ColumnSettings.SaveSettings(listExports); + Properties.Settings.Default.PEImportsColumns = ColumnSettings.SaveSettings(listImports); + Properties.Settings.Default.PEWindowSize = this.Size; + + if (_mappedImage != null) + _mappedImage.Dispose(); + } + + private void InitializeLists() + { + listCOFFHeader.SetDoubleBuffered(true); + listCOFFHeader.SetTheme("explorer"); + listCOFFHeader.ContextMenu = listCOFFHeader.GetCopyMenu(); + listCOFFHeader.AddShortcuts(); + ColumnSettings.LoadSettings(Properties.Settings.Default.PECOFFHColumns, listCOFFHeader); + + listCOFFOptionalHeader.SetDoubleBuffered(true); + listCOFFOptionalHeader.SetTheme("explorer"); + listCOFFOptionalHeader.ContextMenu = listCOFFOptionalHeader.GetCopyMenu(); + listCOFFOptionalHeader.AddShortcuts(); + ColumnSettings.LoadSettings(Properties.Settings.Default.PECOFFOHColumns, listCOFFOptionalHeader); + + listImageData.SetDoubleBuffered(true); + listImageData.SetTheme("explorer"); + listImageData.ContextMenu = listImageData.GetCopyMenu(); + listImageData.AddShortcuts(); + ColumnSettings.LoadSettings(Properties.Settings.Default.PEImageDataColumns, listImageData); + + listSections.SetDoubleBuffered(true); + listSections.SetTheme("explorer"); + listSections.ContextMenu = listSections.GetCopyMenu(); + listSections.AddShortcuts(); + ColumnSettings.LoadSettings(Properties.Settings.Default.PESectionsColumns, listSections); + + listExports.SetDoubleBuffered(true); + listExports.SetTheme("explorer"); + listExports.ContextMenu = listExports.GetCopyMenu(listExports_RetrieveVirtualItem); + listExports.AddShortcuts(this.listExports_RetrieveVirtualItem); + ColumnSettings.LoadSettings(Properties.Settings.Default.PEExportsColumns, listExports); + + listImports.ContextMenu = listImports.GetCopyMenu(); + listImports.AddShortcuts(); + ColumnSettings.LoadSettings(Properties.Settings.Default.PEImportsColumns, listImports); + } + + public string Id + { + get { return _path; } + } + + private unsafe void Read() + { + // Preprare lists + + #region COFF Header + + // COFF header + listCOFFHeader.Items.Clear(); + listCOFFHeader.Items.Add(new ListViewItem(new string[] { "Target Machine", + _mappedImage.NtHeaders->FileHeader.Machine.ToString() })); + listCOFFHeader.Items.Add(new ListViewItem(new string[] { "Number of Sections", + _mappedImage.NtHeaders->FileHeader.NumberOfSections.ToString() })); + listCOFFHeader.Items.Add(new ListViewItem(new string[] { "Time/Date Stamp", + Utils.GetDateTimeFromUnixTime((uint)_mappedImage.NtHeaders->FileHeader.TimeDateStamp).ToString() })); + listCOFFHeader.Items.Add(new ListViewItem(new string[] { "Pointer to Symbol Table", + Utils.FormatAddress(_mappedImage.NtHeaders->FileHeader.PointerToSymbolTable) })); + listCOFFHeader.Items.Add(new ListViewItem(new string[] { "Number of Symbols", + _mappedImage.NtHeaders->FileHeader.NumberOfSymbols.ToString() })); + listCOFFHeader.Items.Add(new ListViewItem(new string[] { "Size of Optional Header", + _mappedImage.NtHeaders->FileHeader.SizeOfOptionalHeader.ToString() })); + listCOFFHeader.Items.Add(new ListViewItem(new string[] { "Characteristics", + _mappedImage.NtHeaders->FileHeader.Characteristics.ToString() })); + + #endregion + + #region COFF Optional Header + + // COFF optional header + listCOFFOptionalHeader.Items.Clear(); + listCOFFOptionalHeader.Items.Add(new ListViewItem(new string[] { "Magic", + _mappedImage.NtHeaders->OptionalHeader.Magic == Win32.Pe32Magic ? "PE32 (0x10b)" : + (_mappedImage.NtHeaders->OptionalHeader.Magic == Win32.Pe32PlusMagic ? "PE32+ (0x20b)" : + "Unknown (0x" + _mappedImage.NtHeaders->OptionalHeader.Magic.ToString("x") + ")") })); + listCOFFOptionalHeader.Items.Add(new ListViewItem(new string[] { "Linker Version", + _mappedImage.NtHeaders->OptionalHeader.MajorLinkerVersion.ToString() + "." + + _mappedImage.NtHeaders->OptionalHeader.MinorLinkerVersion.ToString() })); + listCOFFOptionalHeader.Items.Add(new ListViewItem(new string[] { "Size of Code", + "0x" + _mappedImage.NtHeaders->OptionalHeader.SizeOfCode.ToString("x") })); + listCOFFOptionalHeader.Items.Add(new ListViewItem(new string[] { "Size of Initialized Data", + "0x" + _mappedImage.NtHeaders->OptionalHeader.SizeOfInitializedData.ToString("x") })); + listCOFFOptionalHeader.Items.Add(new ListViewItem(new string[] { "Size of Uninitialized Data", + "0x" + _mappedImage.NtHeaders->OptionalHeader.SizeOfUninitializedData.ToString("x") })); + listCOFFOptionalHeader.Items.Add(new ListViewItem(new string[] { "Entry Point RVA", + "0x" + _mappedImage.NtHeaders->OptionalHeader.AddressOfEntryPoint.ToString("x") })); + listCOFFOptionalHeader.Items.Add(new ListViewItem(new string[] { "Base of Code", + "0x" + _mappedImage.NtHeaders->OptionalHeader.BaseOfCode.ToString("x") })); + listCOFFOptionalHeader.Items.Add(new ListViewItem(new string[] { "Preferred Image Base", + "0x" + _mappedImage.NtHeaders->OptionalHeader.ImageBase.ToString("x") })); + listCOFFOptionalHeader.Items.Add(new ListViewItem(new string[] { "Section Alignment", + _mappedImage.NtHeaders->OptionalHeader.SectionAlignment.ToString() })); + listCOFFOptionalHeader.Items.Add(new ListViewItem(new string[] { "File Alignment", + _mappedImage.NtHeaders->OptionalHeader.FileAlignment.ToString() })); + listCOFFOptionalHeader.Items.Add(new ListViewItem(new string[] { "Operating System Version", + _mappedImage.NtHeaders->OptionalHeader.MajorOperatingSystemVersion.ToString() + "." + + _mappedImage.NtHeaders->OptionalHeader.MinorOperatingSystemVersion.ToString() })); + listCOFFOptionalHeader.Items.Add(new ListViewItem(new string[] { "Image Version", + _mappedImage.NtHeaders->OptionalHeader.MajorImageVersion.ToString() + "." + + _mappedImage.NtHeaders->OptionalHeader.MinorImageVersion.ToString() })); + listCOFFOptionalHeader.Items.Add(new ListViewItem(new string[] { "Subsystem Version", + _mappedImage.NtHeaders->OptionalHeader.MajorSubsystemVersion.ToString() + "." + + _mappedImage.NtHeaders->OptionalHeader.MinorSubsystemVersion.ToString() })); + listCOFFOptionalHeader.Items.Add(new ListViewItem(new string[] { "Size of Image", + "0x" + _mappedImage.NtHeaders->OptionalHeader.SizeOfImage.ToString("x") })); + listCOFFOptionalHeader.Items.Add(new ListViewItem(new string[] { "Size of Headers", + "0x" + _mappedImage.NtHeaders->OptionalHeader.SizeOfHeaders.ToString("x") })); + listCOFFOptionalHeader.Items.Add(new ListViewItem(new string[] { "Checksum", + "0x" + _mappedImage.NtHeaders->OptionalHeader.CheckSum.ToString("x") })); + listCOFFOptionalHeader.Items.Add(new ListViewItem(new string[] { "Subsystem", + _mappedImage.NtHeaders->OptionalHeader.Subsystem.ToString() })); + listCOFFOptionalHeader.Items.Add(new ListViewItem(new string[] { "DLL Characteristics", + _mappedImage.NtHeaders->OptionalHeader.DllCharacteristics.ToString() })); + listCOFFOptionalHeader.Items.Add(new ListViewItem(new string[] { "Size of Stack Reserve", + "0x" + _mappedImage.NtHeaders->OptionalHeader.SizeOfStackReserve.ToString("x") })); + listCOFFOptionalHeader.Items.Add(new ListViewItem(new string[] { "Size of Stack Commit", + "0x" + _mappedImage.NtHeaders->OptionalHeader.SizeOfStackCommit.ToString("x") })); + listCOFFOptionalHeader.Items.Add(new ListViewItem(new string[] { "Size of Heap Reserve", + "0x" + _mappedImage.NtHeaders->OptionalHeader.SizeOfHeapReserve.ToString("x") })); + listCOFFOptionalHeader.Items.Add(new ListViewItem(new string[] { "Size of Heap Commit", + "0x" + _mappedImage.NtHeaders->OptionalHeader.SizeOfHeapCommit.ToString("x") })); + listCOFFOptionalHeader.Items.Add(new ListViewItem(new string[] { "Number of Data Directory Entries", + _mappedImage.NtHeaders->OptionalHeader.NumberOfRvaAndSizes.ToString() })); + + #endregion + + #region Image Data + + listImageData.Items.Clear(); + + for (int i = 0; i < _mappedImage.NumberOfDataEntries; i++) + { + ImageDataDirectory* dataEntry; + + dataEntry = _mappedImage.GetDataEntry((ImageDataEntry)i); + + if (dataEntry != null && dataEntry->VirtualAddress != 0) + { + ListViewItem item = new ListViewItem(); + + item.Text = ((ImageDataEntry)i).ToString(); + item.SubItems.Add(new ListViewItem.ListViewSubItem(item, "0x" + dataEntry->VirtualAddress.ToString("x"))); + item.SubItems.Add(new ListViewItem.ListViewSubItem(item, "0x" + dataEntry->Size.ToString("x"))); + + listImageData.Items.Add(item); + } + } + + #endregion + + #region Sections + + listSections.Items.Clear(); + + for (int i = 0; i < _mappedImage.NumberOfSections; i++) + { + ImageSectionHeader* section = &_mappedImage.Sections[i]; + ListViewItem item = new ListViewItem(); + + item.Text = _mappedImage.GetSectionName(section); + item.SubItems.Add(new ListViewItem.ListViewSubItem(item, "0x" + section->VirtualAddress.ToString("x"))); + item.SubItems.Add(new ListViewItem.ListViewSubItem(item, "0x" + section->SizeOfRawData.ToString("x"))); + item.SubItems.Add(new ListViewItem.ListViewSubItem(item, "0x" + section->PointerToRawData.ToString("x"))); + item.SubItems.Add(new ListViewItem.ListViewSubItem(item, section->Characteristics.ToString())); + + listSections.Items.Add(item); + } + + #endregion + + #region Exports + + listExports.VirtualListSize = _mappedImage.Exports.Count; + + #endregion + + #region Imports + + listImports.Items.Clear(); + listImports.Groups.Clear(); + + var list = new List>(); + + for (int i = 0; i < _mappedImage.Imports.Count; i++) + list.Add(new KeyValuePair(_mappedImage.Imports[i].Name, i)); + + list.Sort((kvp1, kvp2) => StringComparer.CurrentCultureIgnoreCase.Compare(kvp1.Key, kvp2.Key)); + + for (int i = 0; i < list.Count; i++) + { + var dll = _mappedImage.Imports[list[i].Value]; + int index = list[i].Value; + + listImports.Groups.Add(new ListViewGroup(list[i].Key)); + + for (int j = 0; j < dll.Count; j++) + { + var entry = dll[j]; + ListViewItem item = new ListViewItem(listImports.Groups[listImports.Groups.Count - 1]); + + if (entry.Name == null) + { + item.Text = "(Ordinal " + entry.Ordinal.ToString() + ")"; + item.SubItems.Add(new ListViewItem.ListViewSubItem()); + } + else + { + item.Text = entry.Name; + item.SubItems.Add(new ListViewItem.ListViewSubItem(item, entry.NameHint.ToString())); + } + + listImports.Items.Add(item); + } + } + + //we set Groupstate here else there are no groups to set state + listImports.SetGroupState(ListViewGroupState.Collapsed | ListViewGroupState.Collapsible, "Properties"); + + #endregion + } + + private void listExports_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e) + { + unsafe + { + var entry = _mappedImage.Exports.GetEntry(e.ItemIndex); + var function = _mappedImage.Exports.GetFunction(entry.Ordinal); + + e.Item = new ListViewItem(new string[] + { + entry.Ordinal.ToString(), + function.ForwardedName != null ? entry.Name + " > " + function.ForwardedName : entry.Name, + function.ForwardedName == null ? + "0x" + function.Function.Decrement(new IntPtr(_mappedImage.Memory)).ToString("x") : + "" + }); + } + } + + private void listExports_DoubleClick(object sender, EventArgs e) + { + //DisassemblyWindow dw = new DisassemblyWindow(new FileStream(_path, FileMode.Open, FileAccess.Read), + // _exportVAs[_peFile.ExportData.ExportOrdinalTable[listExports.SelectedIndices[0]]], -1); + + //dw.Show(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/PEWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/PEWindow.resx new file mode 100644 index 000000000..d2605a850 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/PEWindow.resx @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 127, 17 + + + + + AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAwpBsm8KNZ/+/imX/vYdj/7qEYP+4gl7/tX9d/7N9W/+xe1n/sHpX/614Vv+sdVX/qnRT/6hy + Uv+ocFD/om9Qm8iRa//Ozs7/1tbW/9TU1P/S0tL/0NDQ/83Nzf/Ly8v/ysrK/8jIyP/FxcX/xMTE/8LC + wv/BwcH/rq6u/6hxUP/Kk23///////////////////////////////////////////////////////// + //////////////////+pclL/zJZu///////39/f/9fX1//T09P/z8/P/8vLy//Ly8v/y8vL/8vLy//Ly + 8v/y8vL/8vLy//Ly8v//////q3RT/8+Zcf//////+vr6//j4+P/39/f/9fX1//T09P/z8/P/8vLy//Ly + 8v/y8vL/8vLy//Ly8v/y8vL//////6x3Vf/Rm3L///////z8/P/7+/v/+vr6//j4+P/39/f/9fX1//T0 + 9P/z8/P/8vLy//Ly8v/y8vL/8vLy//////+veVf/1J10///////9/f3//f39//z8/P/7+/v/+vr6//j4 + +P/39/f/9fX1//T09P/z8/P/8vLy//Ly8v//////sXtZ/9Wfdf///////f39//39/f/9/f3//f39//z8 + /P/7+/v/+vr6//j4+P/39/f/9fX1//T09P/z8/P//////7R9W//YoXj///////39/f/9/f3//f39//39 + /f/9/f3//f39//z8/P/7+/v/+vr6//j4+P/39/f/9fX1//////+2gF3/2aJ4//////////////////// + ////////////////////////////////////////////////////////uYRf/9ujef/U1NT/1NTU/9TU + 1P/U1NT/1NTU/9TU1P/U1NT/1NTU/9TU1P/U1NT/1NTU/9PT0//T09P/09PT/7yGYv/cpnr/26N5/9qi + eP/YoXj/16B3/9Wedf/TnXP/0Zty/8+Zcf/Nlm//y5Rt/8mTa//HkGr/w45o/8KMZv+/imX/3auE/fHc + zv/qwJ//6LiR/+i4kf/ouJH/6LiR/+i4kf/ouJH/zcjE/+i4kf/NyMT/6LiR/0Nj///ow6b/wI9u/d2r + hcLdsIz03KZ6/9ylef/ao3n/2KF4/9igeP/Vn3X/1J10/9Kccv/PmXH/zphv/8uVbv/Jk2v/w5l59MKS + cMIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA//+sQQAArEEAAKxBAACsQQAArEEAAKxBAACsQQAArEEAAKxBAACsQQAArEEAAKxBAACsQQAA + rEEAAKxB//+sQQ== + + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/ProcessAffinity.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/ProcessAffinity.Designer.cs new file mode 100644 index 000000000..6be25606b --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ProcessAffinity.Designer.cs @@ -0,0 +1,99 @@ +namespace ProcessHacker +{ + partial class ProcessAffinity + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.buttonCancel = new System.Windows.Forms.Button(); + this.flowPanel = new System.Windows.Forms.FlowLayoutPanel(); + this.buttonOK = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // buttonCancel + // + this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonCancel.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonCancel.Location = new System.Drawing.Point(361, 187); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.TabIndex = 2; + this.buttonCancel.Text = "&Cancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click); + // + // flowPanel + // + this.flowPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.flowPanel.AutoScroll = true; + this.flowPanel.FlowDirection = System.Windows.Forms.FlowDirection.TopDown; + this.flowPanel.Location = new System.Drawing.Point(12, 12); + this.flowPanel.Name = "flowPanel"; + this.flowPanel.Size = new System.Drawing.Size(424, 169); + this.flowPanel.TabIndex = 0; + // + // buttonOK + // + this.buttonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonOK.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonOK.Location = new System.Drawing.Point(280, 187); + this.buttonOK.Name = "buttonOK"; + this.buttonOK.Size = new System.Drawing.Size(75, 23); + this.buttonOK.TabIndex = 1; + this.buttonOK.Text = "&OK"; + this.buttonOK.UseVisualStyleBackColor = true; + this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click); + // + // ProcessAffinity + // + this.AcceptButton = this.buttonOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(448, 222); + this.Controls.Add(this.buttonOK); + this.Controls.Add(this.flowPanel); + this.Controls.Add(this.buttonCancel); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ProcessAffinity"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Affinity"; + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.FlowLayoutPanel flowPanel; + private System.Windows.Forms.Button buttonOK; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/ProcessAffinity.cs b/branches/ph-plugins/ProcessHacker/Forms/ProcessAffinity.cs new file mode 100644 index 000000000..b157c4d33 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ProcessAffinity.cs @@ -0,0 +1,106 @@ +/* + * Process Hacker - + * process affinity editor + * + * Copyright (C) 2008 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 . + */ + +using System; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker +{ + public partial class ProcessAffinity : Form + { + private int _pid; + + public ProcessAffinity(int pid) + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + _pid = pid; + + try + { + using (ProcessHandle phandle = new ProcessHandle(pid, ProcessAccess.QueryInformation)) + { + long systemMask; + long processMask; + + processMask = phandle.GetAffinityMask(out systemMask); + + for (int i = 0; (systemMask & (1 << i)) != 0; i++) + { + CheckBox c = new CheckBox(); + + c.Name = "cpu" + i.ToString(); + c.Text = "CPU " + i.ToString(); + c.Tag = i; + + c.FlatStyle = FlatStyle.System; + c.Checked = (processMask & (1 << i)) != 0; + c.Margin = new Padding(3, 3, 3, 0); + + flowPanel.Controls.Add(c); + } + } + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to get process affinity", ex); + + this.Close(); + return; + } + } + + private void buttonCancel_Click(object sender, EventArgs e) + { + this.Close(); + } + + private void buttonOK_Click(object sender, EventArgs e) + { + long newMask = 0; + + for (int i = 0; i < flowPanel.Controls.Count; i++) + { + CheckBox c = (CheckBox)flowPanel.Controls["cpu" + i.ToString()]; + + newMask |= ((long)(c.Checked ? 1 : 0) << i); + } + + try + { + using (ProcessHandle phandle = new ProcessHandle(_pid, ProcessAccess.SetInformation)) + phandle.SetAffinityMask(newMask); + + this.Close(); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to set process affinity", ex); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/ProcessAffinity.resx b/branches/ph-plugins/ProcessHacker/Forms/ProcessAffinity.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ProcessAffinity.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/ProcessPickerWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/ProcessPickerWindow.Designer.cs new file mode 100644 index 000000000..75dfdf22c --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ProcessPickerWindow.Designer.cs @@ -0,0 +1,117 @@ +namespace ProcessHacker +{ + partial class ProcessPickerWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.buttonCancel = new System.Windows.Forms.Button(); + this.buttonOK = new System.Windows.Forms.Button(); + this.treeProcesses = new ProcessHacker.ProcessTree(); + this.labelLabel = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // buttonCancel + // + this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonCancel.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonCancel.Location = new System.Drawing.Point(398, 357); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.TabIndex = 3; + this.buttonCancel.Text = "&Cancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click); + // + // buttonOK + // + this.buttonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonOK.Enabled = false; + this.buttonOK.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonOK.Location = new System.Drawing.Point(317, 357); + this.buttonOK.Name = "buttonOK"; + this.buttonOK.Size = new System.Drawing.Size(75, 23); + this.buttonOK.TabIndex = 2; + this.buttonOK.Text = "&OK"; + this.buttonOK.UseVisualStyleBackColor = true; + this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click); + // + // treeProcesses + // + this.treeProcesses.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.treeProcesses.Draw = true; + this.treeProcesses.Location = new System.Drawing.Point(12, 28); + this.treeProcesses.Name = "treeProcesses"; + this.treeProcesses.Provider = null; + this.treeProcesses.Size = new System.Drawing.Size(461, 323); + this.treeProcesses.TabIndex = 1; + this.treeProcesses.DoubleClick += new System.EventHandler(this.treeProcesses_DoubleClick); + this.treeProcesses.SelectionChanged += new System.EventHandler(this.treeProcesses_SelectionChanged); + // + // labelLabel + // + this.labelLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.labelLabel.AutoEllipsis = true; + this.labelLabel.Location = new System.Drawing.Point(12, 9); + this.labelLabel.Name = "labelLabel"; + this.labelLabel.Size = new System.Drawing.Size(461, 16); + this.labelLabel.TabIndex = 0; + this.labelLabel.Text = "Select a process:"; + // + // ProcessPickerWindow + // + this.AcceptButton = this.buttonOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(485, 392); + this.Controls.Add(this.labelLabel); + this.Controls.Add(this.treeProcesses); + this.Controls.Add(this.buttonOK); + this.Controls.Add(this.buttonCancel); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ProcessPickerWindow"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Choose a Process"; + this.Load += new System.EventHandler(this.ProcessPickerWindow_Load); + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.ProcessPickerWindow_FormClosing); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.Button buttonOK; + private ProcessTree treeProcesses; + private System.Windows.Forms.Label labelLabel; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/ProcessPickerWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/ProcessPickerWindow.cs new file mode 100644 index 000000000..2a3576757 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ProcessPickerWindow.cs @@ -0,0 +1,89 @@ +/* + * + * Process Hacker - + * process picker window + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Text; +using System.Windows.Forms; + +namespace ProcessHacker +{ + public partial class ProcessPickerWindow : Form + { + public ProcessPickerWindow() + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + } + + public int SelectedPid { get; private set; } + + public string Label + { + get { return labelLabel.Text; } + set { labelLabel.Text = value; } + } + + private void ProcessPickerWindow_Load(object sender, EventArgs e) + { + treeProcesses.Tree.SelectionMode = Aga.Controls.Tree.TreeSelectionMode.Single; + treeProcesses.Provider = Program.ProcessProvider; + } + + private void ProcessPickerWindow_FormClosing(object sender, FormClosingEventArgs e) + { + treeProcesses.Provider = null; + } + + private void buttonOK_Click(object sender, EventArgs e) + { + this.SelectedPid = treeProcesses.SelectedNodes[0].Pid; + this.DialogResult = DialogResult.OK; + this.Close(); + } + + private void buttonCancel_Click(object sender, EventArgs e) + { + this.DialogResult = DialogResult.Cancel; + this.Close(); + } + + private void treeProcesses_SelectionChanged(object sender, EventArgs e) + { + if (treeProcesses.SelectedNodes.Count == 1) + buttonOK.Enabled = true; + else + buttonOK.Enabled = false; + } + + private void treeProcesses_DoubleClick(object sender, EventArgs e) + { + if (treeProcesses.SelectedNodes.Count == 1) + buttonOK_Click(sender, e); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/ProcessPickerWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/ProcessPickerWindow.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ProcessPickerWindow.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/ProcessWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/ProcessWindow.Designer.cs new file mode 100644 index 000000000..603f476a2 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ProcessWindow.Designer.cs @@ -0,0 +1,1238 @@ +using ProcessHacker.Common; +namespace ProcessHacker +{ + partial class ProcessWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + Program.PWindows.Remove(_pid); + + if (_processHandle != null) + _processHandle.Dispose(); + + if (_threadP != null) + { + Program.SecondarySharedThreadProvider.Remove(_threadP); + // May take a very, very long time + WorkQueue.GlobalQueueWorkItemTag( + new System.Windows.Forms.MethodInvoker(_threadP.Dispose), + "threadprovider-dispose" + ); + _threadP = null; + } + + if (_moduleP != null) + { + Program.SecondarySharedThreadProvider.Remove(_moduleP); + _moduleP.Dispose(); + _moduleP = null; + } + + if (_memoryP != null) + { + Program.SecondarySharedThreadProvider.Remove(_memoryP); + _memoryP.Dispose(); + _memoryP = null; + } + + if (_handleP != null) + { + Program.SecondarySharedThreadProvider.Remove(_handleP); + _handleP.Dispose(); + _handleP = null; + } + + if (_tokenProps != null) + _tokenProps.Dispose(); + + if (_serviceProps != null) + _serviceProps.Dispose(); + + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.mainMenu = new System.Windows.Forms.MainMenu(this.components); + this.processMenuItem = new System.Windows.Forms.MenuItem(); + this.inspectImageFileMenuItem = new System.Windows.Forms.MenuItem(); + this.windowMenuItem = new System.Windows.Forms.MenuItem(); + this.tabControl = new System.Windows.Forms.TabControl(); + this.tabGeneral = new System.Windows.Forms.TabPage(); + this.groupProcess = new System.Windows.Forms.GroupBox(); + this.buttonPermissions = new System.Windows.Forms.Button(); + this.labelProcessTypeValue = new System.Windows.Forms.Label(); + this.labelProcessType = new System.Windows.Forms.Label(); + this.fileCurrentDirectory = new ProcessHacker.Components.FileNameBox(); + this.label26 = new System.Windows.Forms.Label(); + this.label7 = new System.Windows.Forms.Label(); + this.textProtected = new System.Windows.Forms.TextBox(); + this.labelProtected = new System.Windows.Forms.Label(); + this.textDEP = new System.Windows.Forms.TextBox(); + this.labelDEP = new System.Windows.Forms.Label(); + this.buttonTerminate = new System.Windows.Forms.Button(); + this.buttonInspectPEB = new System.Windows.Forms.Button(); + this.buttonEditProtected = new System.Windows.Forms.Button(); + this.buttonInspectParent = new System.Windows.Forms.Button(); + this.buttonEditDEP = new System.Windows.Forms.Button(); + this.label5 = new System.Windows.Forms.Label(); + this.textParent = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.textPEBAddress = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.textStartTime = new System.Windows.Forms.TextBox(); + this.textCmdLine = new System.Windows.Forms.TextBox(); + this.groupFile = new System.Windows.Forms.GroupBox(); + this.fileImage = new ProcessHacker.Components.FileNameBox(); + this.pictureIcon = new System.Windows.Forms.PictureBox(); + this.textFileDescription = new System.Windows.Forms.TextBox(); + this.textFileCompany = new System.Windows.Forms.TextBox(); + this.label1 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.textFileVersion = new System.Windows.Forms.TextBox(); + this.tabStatistics = new System.Windows.Forms.TabPage(); + this.tabPerformance = new System.Windows.Forms.TabPage(); + this.tablePerformance = new System.Windows.Forms.TableLayoutPanel(); + this.groupBoxIO = new System.Windows.Forms.GroupBox(); + this.indicatorIO = new ProcessHacker.Components.Indicator(); + this.groupBoxPvt = new System.Windows.Forms.GroupBox(); + this.indicatorPvt = new ProcessHacker.Components.Indicator(); + this.groupCPUUsage = new System.Windows.Forms.GroupBox(); + this.plotterCPUUsage = new ProcessHacker.Components.Plotter(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.plotterMemory = new ProcessHacker.Components.Plotter(); + this.groupBox3 = new System.Windows.Forms.GroupBox(); + this.plotterIO = new ProcessHacker.Components.Plotter(); + this.groupBoxCpu = new System.Windows.Forms.GroupBox(); + this.indicatorCpu = new ProcessHacker.Components.Indicator(); + this.tabThreads = new System.Windows.Forms.TabPage(); + this.listThreads = new ProcessHacker.Components.ThreadList(); + this.tabToken = new System.Windows.Forms.TabPage(); + this.tabModules = new System.Windows.Forms.TabPage(); + this.listModules = new ProcessHacker.Components.ModuleList(); + this.tabMemory = new System.Windows.Forms.TabPage(); + this.label15 = new System.Windows.Forms.Label(); + this.checkHideFreeRegions = new System.Windows.Forms.CheckBox(); + this.buttonSearch = new wyDay.Controls.SplitButton(); + this.menuSearch = new System.Windows.Forms.ContextMenu(); + this.newWindowSearchMenuItem = new System.Windows.Forms.MenuItem(); + this.literalSearchMenuItem = new System.Windows.Forms.MenuItem(); + this.regexSearchMenuItem = new System.Windows.Forms.MenuItem(); + this.stringScanMenuItem = new System.Windows.Forms.MenuItem(); + this.heapScanMenuItem = new System.Windows.Forms.MenuItem(); + this.structSearchMenuItem = new System.Windows.Forms.MenuItem(); + this.listMemory = new ProcessHacker.Components.MemoryList(); + this.tabEnvironment = new System.Windows.Forms.TabPage(); + this.listEnvironment = new System.Windows.Forms.ListView(); + this.columnVarName = new System.Windows.Forms.ColumnHeader(); + this.columnVarValue = new System.Windows.Forms.ColumnHeader(); + this.tabHandles = new System.Windows.Forms.TabPage(); + this.checkHideHandlesNoName = new System.Windows.Forms.CheckBox(); + this.listHandles = new ProcessHacker.Components.HandleList(); + this.tabJob = new System.Windows.Forms.TabPage(); + this.tabServices = new System.Windows.Forms.TabPage(); + this.toolTip = new System.Windows.Forms.ToolTip(this.components); + this.vistaMenu = new wyDay.Controls.VistaMenu(this.components); + this.tabControl.SuspendLayout(); + this.tabGeneral.SuspendLayout(); + this.groupProcess.SuspendLayout(); + this.groupFile.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureIcon)).BeginInit(); + this.tabPerformance.SuspendLayout(); + this.tablePerformance.SuspendLayout(); + this.groupBoxIO.SuspendLayout(); + this.groupBoxPvt.SuspendLayout(); + this.groupCPUUsage.SuspendLayout(); + this.groupBox2.SuspendLayout(); + this.groupBox3.SuspendLayout(); + this.groupBoxCpu.SuspendLayout(); + this.tabThreads.SuspendLayout(); + this.tabModules.SuspendLayout(); + this.tabMemory.SuspendLayout(); + this.tabEnvironment.SuspendLayout(); + this.tabHandles.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.vistaMenu)).BeginInit(); + this.SuspendLayout(); + // + // mainMenu + // + this.mainMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.processMenuItem, + this.windowMenuItem}); + // + // processMenuItem + // + this.processMenuItem.Index = 0; + this.processMenuItem.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.inspectImageFileMenuItem}); + this.processMenuItem.Text = "&Process"; + // + // inspectImageFileMenuItem + // + this.inspectImageFileMenuItem.Index = 0; + this.inspectImageFileMenuItem.Text = "&Inspect Image File..."; + this.inspectImageFileMenuItem.Click += new System.EventHandler(this.inspectImageFileMenuItem_Click); + // + // windowMenuItem + // + this.windowMenuItem.Index = 1; + this.windowMenuItem.Text = "&Window"; + // + // tabControl + // + this.tabControl.Controls.Add(this.tabGeneral); + this.tabControl.Controls.Add(this.tabStatistics); + this.tabControl.Controls.Add(this.tabPerformance); + this.tabControl.Controls.Add(this.tabThreads); + this.tabControl.Controls.Add(this.tabToken); + this.tabControl.Controls.Add(this.tabModules); + this.tabControl.Controls.Add(this.tabMemory); + this.tabControl.Controls.Add(this.tabEnvironment); + this.tabControl.Controls.Add(this.tabHandles); + this.tabControl.Controls.Add(this.tabJob); + this.tabControl.Controls.Add(this.tabServices); + this.tabControl.Dock = System.Windows.Forms.DockStyle.Fill; + this.tabControl.ItemSize = new System.Drawing.Size(80, 18); + this.tabControl.Location = new System.Drawing.Point(0, 0); + this.tabControl.Multiline = true; + this.tabControl.Name = "tabControl"; + this.tabControl.SelectedIndex = 0; + this.tabControl.Size = new System.Drawing.Size(488, 431); + this.tabControl.SizeMode = System.Windows.Forms.TabSizeMode.FillToRight; + this.tabControl.TabIndex = 0; + this.tabControl.SelectedIndexChanged += new System.EventHandler(this.tabControl_SelectedIndexChanged); + // + // tabGeneral + // + this.tabGeneral.AutoScroll = true; + this.tabGeneral.Controls.Add(this.groupProcess); + this.tabGeneral.Controls.Add(this.groupFile); + this.tabGeneral.ImageKey = "(none)"; + this.tabGeneral.Location = new System.Drawing.Point(4, 40); + this.tabGeneral.Name = "tabGeneral"; + this.tabGeneral.Padding = new System.Windows.Forms.Padding(3); + this.tabGeneral.Size = new System.Drawing.Size(480, 387); + this.tabGeneral.TabIndex = 2; + this.tabGeneral.Text = "General"; + this.tabGeneral.UseVisualStyleBackColor = true; + // + // groupProcess + // + this.groupProcess.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupProcess.Controls.Add(this.buttonPermissions); + this.groupProcess.Controls.Add(this.labelProcessTypeValue); + this.groupProcess.Controls.Add(this.labelProcessType); + this.groupProcess.Controls.Add(this.fileCurrentDirectory); + this.groupProcess.Controls.Add(this.label26); + this.groupProcess.Controls.Add(this.label7); + this.groupProcess.Controls.Add(this.textProtected); + this.groupProcess.Controls.Add(this.labelProtected); + this.groupProcess.Controls.Add(this.textDEP); + this.groupProcess.Controls.Add(this.labelDEP); + this.groupProcess.Controls.Add(this.buttonTerminate); + this.groupProcess.Controls.Add(this.buttonInspectPEB); + this.groupProcess.Controls.Add(this.buttonEditProtected); + this.groupProcess.Controls.Add(this.buttonInspectParent); + this.groupProcess.Controls.Add(this.buttonEditDEP); + this.groupProcess.Controls.Add(this.label5); + this.groupProcess.Controls.Add(this.textParent); + this.groupProcess.Controls.Add(this.label4); + this.groupProcess.Controls.Add(this.textPEBAddress); + this.groupProcess.Controls.Add(this.label2); + this.groupProcess.Controls.Add(this.textStartTime); + this.groupProcess.Controls.Add(this.textCmdLine); + this.groupProcess.Location = new System.Drawing.Point(8, 126); + this.groupProcess.Name = "groupProcess"; + this.groupProcess.Size = new System.Drawing.Size(466, 255); + this.groupProcess.TabIndex = 1; + this.groupProcess.TabStop = false; + this.groupProcess.Text = "Process"; + // + // buttonPermissions + // + this.buttonPermissions.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonPermissions.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonPermissions.Location = new System.Drawing.Point(304, 206); + this.buttonPermissions.Name = "buttonPermissions"; + this.buttonPermissions.Size = new System.Drawing.Size(75, 23); + this.buttonPermissions.TabIndex = 21; + this.buttonPermissions.Text = "Permissions"; + this.buttonPermissions.UseVisualStyleBackColor = true; + this.buttonPermissions.Click += new System.EventHandler(this.buttonPermissions_Click); + // + // labelProcessTypeValue + // + this.labelProcessTypeValue.AutoSize = true; + this.labelProcessTypeValue.Location = new System.Drawing.Point(98, 208); + this.labelProcessTypeValue.Name = "labelProcessTypeValue"; + this.labelProcessTypeValue.Size = new System.Drawing.Size(16, 13); + this.labelProcessTypeValue.TabIndex = 20; + this.labelProcessTypeValue.Text = "..."; + this.labelProcessTypeValue.Visible = false; + // + // labelProcessType + // + this.labelProcessType.AutoSize = true; + this.labelProcessType.Location = new System.Drawing.Point(6, 208); + this.labelProcessType.Name = "labelProcessType"; + this.labelProcessType.Size = new System.Drawing.Size(75, 13); + this.labelProcessType.TabIndex = 19; + this.labelProcessType.Text = "Process Type:"; + this.labelProcessType.Visible = false; + // + // fileCurrentDirectory + // + this.fileCurrentDirectory.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.fileCurrentDirectory.Location = new System.Drawing.Point(101, 71); + this.fileCurrentDirectory.Name = "fileCurrentDirectory"; + this.fileCurrentDirectory.ReadOnly = true; + this.fileCurrentDirectory.Size = new System.Drawing.Size(359, 24); + this.fileCurrentDirectory.TabIndex = 3; + // + // label26 + // + this.label26.AutoSize = true; + this.label26.Location = new System.Drawing.Point(6, 22); + this.label26.Name = "label26"; + this.label26.Size = new System.Drawing.Size(44, 13); + this.label26.TabIndex = 12; + this.label26.Text = "Started:"; + this.toolTip.SetToolTip(this.label26, "The time at which the program was started."); + // + // label7 + // + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(6, 104); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(72, 13); + this.label7.TabIndex = 15; + this.label7.Text = "PEB Address:"; + this.toolTip.SetToolTip(this.label7, "The address of the Process Environment Block (PEB)."); + // + // textProtected + // + this.textProtected.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textProtected.BackColor = System.Drawing.SystemColors.Control; + this.textProtected.Location = new System.Drawing.Point(101, 179); + this.textProtected.Name = "textProtected"; + this.textProtected.ReadOnly = true; + this.textProtected.Size = new System.Drawing.Size(329, 20); + this.textProtected.TabIndex = 10; + // + // labelProtected + // + this.labelProtected.AutoSize = true; + this.labelProtected.Location = new System.Drawing.Point(6, 182); + this.labelProtected.Name = "labelProtected"; + this.labelProtected.Size = new System.Drawing.Size(56, 13); + this.labelProtected.TabIndex = 18; + this.labelProtected.Text = "Protected:"; + this.toolTip.SetToolTip(this.labelProtected, "Whether the process is DRM-protected."); + // + // textDEP + // + this.textDEP.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textDEP.BackColor = System.Drawing.SystemColors.Control; + this.textDEP.Location = new System.Drawing.Point(101, 153); + this.textDEP.Name = "textDEP"; + this.textDEP.ReadOnly = true; + this.textDEP.Size = new System.Drawing.Size(329, 20); + this.textDEP.TabIndex = 8; + // + // labelDEP + // + this.labelDEP.AutoSize = true; + this.labelDEP.Location = new System.Drawing.Point(6, 156); + this.labelDEP.Name = "labelDEP"; + this.labelDEP.Size = new System.Drawing.Size(32, 13); + this.labelDEP.TabIndex = 17; + this.labelDEP.Text = "DEP:"; + this.toolTip.SetToolTip(this.labelDEP, "The status of Data Execution Prevention (DEP) for this process."); + // + // buttonTerminate + // + this.buttonTerminate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonTerminate.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonTerminate.Location = new System.Drawing.Point(385, 206); + this.buttonTerminate.Name = "buttonTerminate"; + this.buttonTerminate.Size = new System.Drawing.Size(75, 23); + this.buttonTerminate.TabIndex = 1; + this.buttonTerminate.Text = "Terminate"; + this.buttonTerminate.UseVisualStyleBackColor = true; + this.buttonTerminate.Click += new System.EventHandler(this.buttonTerminate_Click); + // + // buttonInspectPEB + // + this.buttonInspectPEB.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonInspectPEB.Image = global::ProcessHacker.Properties.Resources.application_form_magnify; + this.buttonInspectPEB.Location = new System.Drawing.Point(436, 98); + this.buttonInspectPEB.Name = "buttonInspectPEB"; + this.buttonInspectPEB.Size = new System.Drawing.Size(24, 24); + this.buttonInspectPEB.TabIndex = 5; + this.toolTip.SetToolTip(this.buttonInspectPEB, "Inspects the PEB."); + this.buttonInspectPEB.UseVisualStyleBackColor = true; + this.buttonInspectPEB.Click += new System.EventHandler(this.buttonInspectPEB_Click); + // + // buttonEditProtected + // + this.buttonEditProtected.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonEditProtected.Image = global::ProcessHacker.Properties.Resources.cog_edit; + this.buttonEditProtected.Location = new System.Drawing.Point(436, 176); + this.buttonEditProtected.Name = "buttonEditProtected"; + this.buttonEditProtected.Size = new System.Drawing.Size(24, 24); + this.buttonEditProtected.TabIndex = 11; + this.toolTip.SetToolTip(this.buttonEditProtected, "Allows you to protect or unprotect the process."); + this.buttonEditProtected.UseVisualStyleBackColor = true; + this.buttonEditProtected.Click += new System.EventHandler(this.buttonEditProtected_Click); + // + // buttonInspectParent + // + this.buttonInspectParent.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonInspectParent.Image = global::ProcessHacker.Properties.Resources.application_form_magnify; + this.buttonInspectParent.Location = new System.Drawing.Point(436, 124); + this.buttonInspectParent.Name = "buttonInspectParent"; + this.buttonInspectParent.Size = new System.Drawing.Size(24, 24); + this.buttonInspectParent.TabIndex = 7; + this.toolTip.SetToolTip(this.buttonInspectParent, "Inspects the parent process."); + this.buttonInspectParent.UseVisualStyleBackColor = true; + this.buttonInspectParent.Click += new System.EventHandler(this.buttonInspectParent_Click); + // + // buttonEditDEP + // + this.buttonEditDEP.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonEditDEP.Image = global::ProcessHacker.Properties.Resources.cog_edit; + this.buttonEditDEP.Location = new System.Drawing.Point(436, 150); + this.buttonEditDEP.Name = "buttonEditDEP"; + this.buttonEditDEP.Size = new System.Drawing.Size(24, 24); + this.buttonEditDEP.TabIndex = 9; + this.toolTip.SetToolTip(this.buttonEditDEP, "Allows you to change the process\' DEP policy."); + this.buttonEditDEP.UseVisualStyleBackColor = true; + this.buttonEditDEP.Click += new System.EventHandler(this.buttonEditDEP_Click); + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(6, 130); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(41, 13); + this.label5.TabIndex = 16; + this.label5.Text = "Parent:"; + this.toolTip.SetToolTip(this.label5, "The name and ID of the process which started this process."); + // + // textParent + // + this.textParent.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textParent.BackColor = System.Drawing.SystemColors.Control; + this.textParent.Location = new System.Drawing.Point(101, 127); + this.textParent.Name = "textParent"; + this.textParent.ReadOnly = true; + this.textParent.Size = new System.Drawing.Size(329, 20); + this.textParent.TabIndex = 6; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(6, 76); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(89, 13); + this.label4.TabIndex = 14; + this.label4.Text = "Current Directory:"; + this.toolTip.SetToolTip(this.label4, "The program\'s current directory."); + // + // textPEBAddress + // + this.textPEBAddress.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textPEBAddress.Location = new System.Drawing.Point(101, 101); + this.textPEBAddress.Name = "textPEBAddress"; + this.textPEBAddress.ReadOnly = true; + this.textPEBAddress.Size = new System.Drawing.Size(329, 20); + this.textPEBAddress.TabIndex = 4; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(6, 48); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(80, 13); + this.label2.TabIndex = 13; + this.label2.Text = "Command Line:"; + this.toolTip.SetToolTip(this.label2, "The command used to start the program."); + // + // textStartTime + // + this.textStartTime.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textStartTime.Location = new System.Drawing.Point(101, 19); + this.textStartTime.Name = "textStartTime"; + this.textStartTime.ReadOnly = true; + this.textStartTime.Size = new System.Drawing.Size(359, 20); + this.textStartTime.TabIndex = 0; + // + // textCmdLine + // + this.textCmdLine.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textCmdLine.Location = new System.Drawing.Point(101, 45); + this.textCmdLine.Name = "textCmdLine"; + this.textCmdLine.ReadOnly = true; + this.textCmdLine.Size = new System.Drawing.Size(359, 20); + this.textCmdLine.TabIndex = 2; + // + // groupFile + // + this.groupFile.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupFile.Controls.Add(this.fileImage); + this.groupFile.Controls.Add(this.pictureIcon); + this.groupFile.Controls.Add(this.textFileDescription); + this.groupFile.Controls.Add(this.textFileCompany); + this.groupFile.Controls.Add(this.label1); + this.groupFile.Controls.Add(this.label3); + this.groupFile.Controls.Add(this.textFileVersion); + this.groupFile.Location = new System.Drawing.Point(6, 7); + this.groupFile.Name = "groupFile"; + this.groupFile.Size = new System.Drawing.Size(468, 114); + this.groupFile.TabIndex = 0; + this.groupFile.TabStop = false; + this.groupFile.Text = "File"; + // + // fileImage + // + this.fileImage.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.fileImage.Location = new System.Drawing.Point(103, 83); + this.fileImage.Name = "fileImage"; + this.fileImage.ReadOnly = true; + this.fileImage.Size = new System.Drawing.Size(359, 24); + this.fileImage.TabIndex = 1; + // + // pictureIcon + // + this.pictureIcon.Location = new System.Drawing.Point(6, 19); + this.pictureIcon.Name = "pictureIcon"; + this.pictureIcon.Size = new System.Drawing.Size(32, 32); + this.pictureIcon.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; + this.pictureIcon.TabIndex = 1; + this.pictureIcon.TabStop = false; + // + // textFileDescription + // + this.textFileDescription.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textFileDescription.BackColor = System.Drawing.SystemColors.Window; + this.textFileDescription.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.textFileDescription.Location = new System.Drawing.Point(44, 20); + this.textFileDescription.Name = "textFileDescription"; + this.textFileDescription.ReadOnly = true; + this.textFileDescription.Size = new System.Drawing.Size(418, 13); + this.textFileDescription.TabIndex = 2; + this.textFileDescription.Text = "File Description"; + // + // textFileCompany + // + this.textFileCompany.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textFileCompany.BackColor = System.Drawing.SystemColors.Window; + this.textFileCompany.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.textFileCompany.Location = new System.Drawing.Point(44, 38); + this.textFileCompany.Name = "textFileCompany"; + this.textFileCompany.ReadOnly = true; + this.textFileCompany.Size = new System.Drawing.Size(418, 13); + this.textFileCompany.TabIndex = 3; + this.textFileCompany.Text = "File Company"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(6, 60); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(77, 13); + this.label1.TabIndex = 4; + this.label1.Text = "Image Version:"; + this.toolTip.SetToolTip(this.label1, "The version of the program."); + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(6, 88); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(89, 13); + this.label3.TabIndex = 5; + this.label3.Text = "Image File Name:"; + this.toolTip.SetToolTip(this.label3, "The file name of the program."); + // + // textFileVersion + // + this.textFileVersion.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textFileVersion.Location = new System.Drawing.Point(103, 57); + this.textFileVersion.Name = "textFileVersion"; + this.textFileVersion.ReadOnly = true; + this.textFileVersion.Size = new System.Drawing.Size(359, 20); + this.textFileVersion.TabIndex = 0; + // + // tabStatistics + // + this.tabStatistics.ImageKey = "(none)"; + this.tabStatistics.Location = new System.Drawing.Point(4, 40); + this.tabStatistics.Name = "tabStatistics"; + this.tabStatistics.Padding = new System.Windows.Forms.Padding(3); + this.tabStatistics.Size = new System.Drawing.Size(480, 387); + this.tabStatistics.TabIndex = 9; + this.tabStatistics.Text = "Statistics"; + this.tabStatistics.UseVisualStyleBackColor = true; + // + // tabPerformance + // + this.tabPerformance.Controls.Add(this.tablePerformance); + this.tabPerformance.ImageKey = "(none)"; + this.tabPerformance.Location = new System.Drawing.Point(4, 40); + this.tabPerformance.Name = "tabPerformance"; + this.tabPerformance.Padding = new System.Windows.Forms.Padding(3); + this.tabPerformance.Size = new System.Drawing.Size(480, 387); + this.tabPerformance.TabIndex = 8; + this.tabPerformance.Text = "Performance"; + this.tabPerformance.UseVisualStyleBackColor = true; + // + // tablePerformance + // + this.tablePerformance.ColumnCount = 2; + this.tablePerformance.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 86F)); + this.tablePerformance.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tablePerformance.Controls.Add(this.groupBoxIO, 0, 2); + this.tablePerformance.Controls.Add(this.groupBoxPvt, 0, 1); + this.tablePerformance.Controls.Add(this.groupCPUUsage, 1, 0); + this.tablePerformance.Controls.Add(this.groupBox2, 1, 1); + this.tablePerformance.Controls.Add(this.groupBox3, 1, 2); + this.tablePerformance.Controls.Add(this.groupBoxCpu, 0, 0); + this.tablePerformance.Dock = System.Windows.Forms.DockStyle.Fill; + this.tablePerformance.Location = new System.Drawing.Point(3, 3); + this.tablePerformance.Name = "tablePerformance"; + this.tablePerformance.RowCount = 3; + this.tablePerformance.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); + this.tablePerformance.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); + this.tablePerformance.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); + this.tablePerformance.Size = new System.Drawing.Size(474, 381); + this.tablePerformance.TabIndex = 1; + // + // groupBoxIO + // + this.groupBoxIO.Controls.Add(this.indicatorIO); + this.groupBoxIO.Dock = System.Windows.Forms.DockStyle.Fill; + this.groupBoxIO.Location = new System.Drawing.Point(3, 257); + this.groupBoxIO.Name = "groupBoxIO"; + this.groupBoxIO.Size = new System.Drawing.Size(80, 121); + this.groupBoxIO.TabIndex = 3; + this.groupBoxIO.TabStop = false; + this.groupBoxIO.Text = "I/O (R+O)"; + // + // indicatorIO + // + this.indicatorIO.BackColor = System.Drawing.Color.Black; + this.indicatorIO.Color1 = System.Drawing.Color.Cyan; + this.indicatorIO.Color2 = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(255)))), ((int)(((byte)(0))))); + this.indicatorIO.Data1 = ((long)(0)); + this.indicatorIO.Data2 = ((long)(0)); + this.indicatorIO.Dock = System.Windows.Forms.DockStyle.Fill; + this.indicatorIO.ForeColor = System.Drawing.Color.Lime; + this.indicatorIO.GraphWidth = 33; + this.indicatorIO.Location = new System.Drawing.Point(3, 16); + this.indicatorIO.Maximum = ((long)(2147483647)); + this.indicatorIO.Minimum = ((long)(0)); + this.indicatorIO.Name = "indicatorIO"; + this.indicatorIO.Size = new System.Drawing.Size(74, 102); + this.indicatorIO.TabIndex = 1; + this.indicatorIO.TextValue = ""; + // + // groupBoxPvt + // + this.groupBoxPvt.Controls.Add(this.indicatorPvt); + this.groupBoxPvt.Dock = System.Windows.Forms.DockStyle.Fill; + this.groupBoxPvt.Location = new System.Drawing.Point(3, 130); + this.groupBoxPvt.Name = "groupBoxPvt"; + this.groupBoxPvt.Size = new System.Drawing.Size(80, 121); + this.groupBoxPvt.TabIndex = 2; + this.groupBoxPvt.TabStop = false; + this.groupBoxPvt.Text = "Pvt. Pages"; + // + // indicatorPvt + // + this.indicatorPvt.BackColor = System.Drawing.Color.Black; + this.indicatorPvt.Color1 = System.Drawing.Color.Orange; + this.indicatorPvt.Color2 = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(255)))), ((int)(((byte)(0))))); + this.indicatorPvt.Data1 = ((long)(0)); + this.indicatorPvt.Data2 = ((long)(0)); + this.indicatorPvt.Dock = System.Windows.Forms.DockStyle.Fill; + this.indicatorPvt.ForeColor = System.Drawing.Color.Lime; + this.indicatorPvt.GraphWidth = 33; + this.indicatorPvt.Location = new System.Drawing.Point(3, 16); + this.indicatorPvt.Maximum = ((long)(2147483647)); + this.indicatorPvt.Minimum = ((long)(0)); + this.indicatorPvt.Name = "indicatorPvt"; + this.indicatorPvt.Size = new System.Drawing.Size(74, 102); + this.indicatorPvt.TabIndex = 1; + this.indicatorPvt.TextValue = ""; + // + // groupCPUUsage + // + this.groupCPUUsage.Controls.Add(this.plotterCPUUsage); + this.groupCPUUsage.Dock = System.Windows.Forms.DockStyle.Fill; + this.groupCPUUsage.Location = new System.Drawing.Point(89, 3); + this.groupCPUUsage.Name = "groupCPUUsage"; + this.groupCPUUsage.Size = new System.Drawing.Size(382, 121); + this.groupCPUUsage.TabIndex = 0; + this.groupCPUUsage.TabStop = false; + this.groupCPUUsage.Text = "CPU Usage (Kernel, User)"; + // + // plotterCPUUsage + // + this.plotterCPUUsage.BackColor = System.Drawing.Color.Black; + this.plotterCPUUsage.Data1 = null; + this.plotterCPUUsage.Data2 = null; + this.plotterCPUUsage.Dock = System.Windows.Forms.DockStyle.Fill; + this.plotterCPUUsage.GridColor = System.Drawing.Color.Green; + this.plotterCPUUsage.GridSize = new System.Drawing.Size(12, 12); + this.plotterCPUUsage.LineColor1 = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(255)))), ((int)(((byte)(0))))); + this.plotterCPUUsage.LineColor2 = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(0)))), ((int)(((byte)(0))))); + this.plotterCPUUsage.Location = new System.Drawing.Point(3, 16); + this.plotterCPUUsage.LongData1 = null; + this.plotterCPUUsage.LongData2 = null; + this.plotterCPUUsage.MinMaxValue = ((long)(0)); + this.plotterCPUUsage.MoveStep = -1; + this.plotterCPUUsage.Name = "plotterCPUUsage"; + this.plotterCPUUsage.OverlaySecondLine = false; + this.plotterCPUUsage.ShowGrid = true; + this.plotterCPUUsage.Size = new System.Drawing.Size(376, 102); + this.plotterCPUUsage.TabIndex = 0; + this.plotterCPUUsage.TextBoxColor = System.Drawing.Color.FromArgb(((int)(((byte)(127)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0))))); + this.plotterCPUUsage.TextColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(255)))), ((int)(((byte)(0))))); + this.plotterCPUUsage.TextMargin = new System.Windows.Forms.Padding(3); + this.plotterCPUUsage.TextPadding = new System.Windows.Forms.Padding(3); + this.plotterCPUUsage.TextPosition = System.Drawing.ContentAlignment.TopLeft; + this.plotterCPUUsage.UseLongData = false; + this.plotterCPUUsage.UseSecondLine = true; + // + // groupBox2 + // + this.groupBox2.Controls.Add(this.plotterMemory); + this.groupBox2.Dock = System.Windows.Forms.DockStyle.Fill; + this.groupBox2.Location = new System.Drawing.Point(89, 130); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(382, 121); + this.groupBox2.TabIndex = 0; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "Memory (Private Pages, Working Set)"; + // + // plotterMemory + // + this.plotterMemory.BackColor = System.Drawing.Color.Black; + this.plotterMemory.Data1 = null; + this.plotterMemory.Data2 = null; + this.plotterMemory.Dock = System.Windows.Forms.DockStyle.Fill; + this.plotterMemory.GridColor = System.Drawing.Color.Green; + this.plotterMemory.GridSize = new System.Drawing.Size(12, 12); + this.plotterMemory.LineColor1 = System.Drawing.Color.Orange; + this.plotterMemory.LineColor2 = System.Drawing.Color.Cyan; + this.plotterMemory.Location = new System.Drawing.Point(3, 16); + this.plotterMemory.LongData1 = null; + this.plotterMemory.LongData2 = null; + this.plotterMemory.MinMaxValue = ((long)(0)); + this.plotterMemory.MoveStep = -1; + this.plotterMemory.Name = "plotterMemory"; + this.plotterMemory.OverlaySecondLine = true; + this.plotterMemory.ShowGrid = true; + this.plotterMemory.Size = new System.Drawing.Size(376, 102); + this.plotterMemory.TabIndex = 0; + this.plotterMemory.TextBoxColor = System.Drawing.Color.FromArgb(((int)(((byte)(127)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0))))); + this.plotterMemory.TextColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(255)))), ((int)(((byte)(0))))); + this.plotterMemory.TextMargin = new System.Windows.Forms.Padding(3); + this.plotterMemory.TextPadding = new System.Windows.Forms.Padding(3); + this.plotterMemory.TextPosition = System.Drawing.ContentAlignment.TopLeft; + this.plotterMemory.UseLongData = true; + this.plotterMemory.UseSecondLine = true; + // + // groupBox3 + // + this.groupBox3.Controls.Add(this.plotterIO); + this.groupBox3.Dock = System.Windows.Forms.DockStyle.Fill; + this.groupBox3.Location = new System.Drawing.Point(89, 257); + this.groupBox3.Name = "groupBox3"; + this.groupBox3.Size = new System.Drawing.Size(382, 121); + this.groupBox3.TabIndex = 0; + this.groupBox3.TabStop = false; + this.groupBox3.Text = "I/O (R+O, W)"; + // + // plotterIO + // + this.plotterIO.BackColor = System.Drawing.Color.Black; + this.plotterIO.Data1 = null; + this.plotterIO.Data2 = null; + this.plotterIO.Dock = System.Windows.Forms.DockStyle.Fill; + this.plotterIO.GridColor = System.Drawing.Color.Green; + this.plotterIO.GridSize = new System.Drawing.Size(12, 12); + this.plotterIO.LineColor1 = System.Drawing.Color.Yellow; + this.plotterIO.LineColor2 = System.Drawing.Color.Purple; + this.plotterIO.Location = new System.Drawing.Point(3, 16); + this.plotterIO.LongData1 = null; + this.plotterIO.LongData2 = null; + this.plotterIO.MinMaxValue = ((long)(0)); + this.plotterIO.MoveStep = -1; + this.plotterIO.Name = "plotterIO"; + this.plotterIO.OverlaySecondLine = true; + this.plotterIO.ShowGrid = true; + this.plotterIO.Size = new System.Drawing.Size(376, 102); + this.plotterIO.TabIndex = 0; + this.plotterIO.TextBoxColor = System.Drawing.Color.FromArgb(((int)(((byte)(127)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0))))); + this.plotterIO.TextColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(255)))), ((int)(((byte)(0))))); + this.plotterIO.TextMargin = new System.Windows.Forms.Padding(3); + this.plotterIO.TextPadding = new System.Windows.Forms.Padding(3); + this.plotterIO.TextPosition = System.Drawing.ContentAlignment.TopLeft; + this.plotterIO.UseLongData = true; + this.plotterIO.UseSecondLine = true; + // + // groupBoxCpu + // + this.groupBoxCpu.Controls.Add(this.indicatorCpu); + this.groupBoxCpu.Dock = System.Windows.Forms.DockStyle.Fill; + this.groupBoxCpu.Location = new System.Drawing.Point(3, 3); + this.groupBoxCpu.Name = "groupBoxCpu"; + this.groupBoxCpu.Size = new System.Drawing.Size(80, 121); + this.groupBoxCpu.TabIndex = 1; + this.groupBoxCpu.TabStop = false; + this.groupBoxCpu.Text = "CPU Usage"; + // + // indicatorCpu + // + this.indicatorCpu.BackColor = System.Drawing.Color.Black; + this.indicatorCpu.Color1 = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(0)))), ((int)(((byte)(0))))); + this.indicatorCpu.Color2 = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(255)))), ((int)(((byte)(0))))); + this.indicatorCpu.Data1 = ((long)(0)); + this.indicatorCpu.Data2 = ((long)(0)); + this.indicatorCpu.Dock = System.Windows.Forms.DockStyle.Fill; + this.indicatorCpu.ForeColor = System.Drawing.Color.Lime; + this.indicatorCpu.GraphWidth = 33; + this.indicatorCpu.Location = new System.Drawing.Point(3, 16); + this.indicatorCpu.Maximum = ((long)(2147483647)); + this.indicatorCpu.Minimum = ((long)(0)); + this.indicatorCpu.Name = "indicatorCpu"; + this.indicatorCpu.Size = new System.Drawing.Size(74, 102); + this.indicatorCpu.TabIndex = 0; + this.indicatorCpu.TextValue = ""; + // + // tabThreads + // + this.tabThreads.Controls.Add(this.listThreads); + this.tabThreads.ImageKey = "(none)"; + this.tabThreads.Location = new System.Drawing.Point(4, 40); + this.tabThreads.Name = "tabThreads"; + this.tabThreads.Size = new System.Drawing.Size(480, 387); + this.tabThreads.TabIndex = 3; + this.tabThreads.Text = "Threads"; + this.tabThreads.UseVisualStyleBackColor = true; + // + // listThreads + // + this.listThreads.Cursor = System.Windows.Forms.Cursors.Default; + this.listThreads.Dock = System.Windows.Forms.DockStyle.Fill; + this.listThreads.DoubleBuffered = true; + this.listThreads.Location = new System.Drawing.Point(0, 0); + this.listThreads.Name = "listThreads"; + this.listThreads.Provider = null; + this.listThreads.Size = new System.Drawing.Size(480, 387); + this.listThreads.TabIndex = 0; + // + // tabToken + // + this.tabToken.ImageKey = "(none)"; + this.tabToken.Location = new System.Drawing.Point(4, 40); + this.tabToken.Name = "tabToken"; + this.tabToken.Padding = new System.Windows.Forms.Padding(3); + this.tabToken.Size = new System.Drawing.Size(480, 387); + this.tabToken.TabIndex = 1; + this.tabToken.Text = "Token"; + this.tabToken.UseVisualStyleBackColor = true; + // + // tabModules + // + this.tabModules.Controls.Add(this.listModules); + this.tabModules.ImageKey = "(none)"; + this.tabModules.Location = new System.Drawing.Point(4, 40); + this.tabModules.Name = "tabModules"; + this.tabModules.Size = new System.Drawing.Size(480, 387); + this.tabModules.TabIndex = 6; + this.tabModules.Text = "Modules"; + this.tabModules.UseVisualStyleBackColor = true; + // + // listModules + // + this.listModules.Dock = System.Windows.Forms.DockStyle.Fill; + this.listModules.DoubleBuffered = true; + this.listModules.Location = new System.Drawing.Point(0, 0); + this.listModules.Name = "listModules"; + this.listModules.Provider = null; + this.listModules.Size = new System.Drawing.Size(480, 387); + this.listModules.TabIndex = 0; + // + // tabMemory + // + this.tabMemory.Controls.Add(this.label15); + this.tabMemory.Controls.Add(this.checkHideFreeRegions); + this.tabMemory.Controls.Add(this.buttonSearch); + this.tabMemory.Controls.Add(this.listMemory); + this.tabMemory.ImageKey = "(none)"; + this.tabMemory.Location = new System.Drawing.Point(4, 40); + this.tabMemory.Name = "tabMemory"; + this.tabMemory.Padding = new System.Windows.Forms.Padding(3); + this.tabMemory.Size = new System.Drawing.Size(480, 387); + this.tabMemory.TabIndex = 4; + this.tabMemory.Text = "Memory"; + this.tabMemory.UseVisualStyleBackColor = true; + // + // label15 + // + this.label15.AutoSize = true; + this.label15.Location = new System.Drawing.Point(8, 11); + this.label15.Name = "label15"; + this.label15.Size = new System.Drawing.Size(44, 13); + this.label15.TabIndex = 3; + this.label15.Text = "Search:"; + // + // checkHideFreeRegions + // + this.checkHideFreeRegions.AutoSize = true; + this.checkHideFreeRegions.Checked = true; + this.checkHideFreeRegions.CheckState = System.Windows.Forms.CheckState.Checked; + this.checkHideFreeRegions.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkHideFreeRegions.Location = new System.Drawing.Point(6, 35); + this.checkHideFreeRegions.Name = "checkHideFreeRegions"; + this.checkHideFreeRegions.Size = new System.Drawing.Size(120, 18); + this.checkHideFreeRegions.TabIndex = 1; + this.checkHideFreeRegions.Text = "Hide Free Regions"; + this.checkHideFreeRegions.UseVisualStyleBackColor = true; + this.checkHideFreeRegions.CheckedChanged += new System.EventHandler(this.checkHideFreeRegions_CheckedChanged); + // + // buttonSearch + // + this.buttonSearch.AutoSize = true; + this.buttonSearch.Location = new System.Drawing.Point(58, 7); + this.buttonSearch.Name = "buttonSearch"; + this.buttonSearch.Size = new System.Drawing.Size(117, 25); + this.buttonSearch.SplitMenu = this.menuSearch; + this.buttonSearch.TabIndex = 0; + this.buttonSearch.Text = "&String Scan..."; + this.buttonSearch.UseVisualStyleBackColor = true; + this.buttonSearch.Click += new System.EventHandler(this.buttonSearch_Click); + // + // menuSearch + // + this.menuSearch.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.newWindowSearchMenuItem, + this.literalSearchMenuItem, + this.regexSearchMenuItem, + this.stringScanMenuItem, + this.heapScanMenuItem, + this.structSearchMenuItem}); + // + // newWindowSearchMenuItem + // + this.newWindowSearchMenuItem.Index = 0; + this.newWindowSearchMenuItem.Text = "&New Window..."; + this.newWindowSearchMenuItem.Click += new System.EventHandler(this.newWindowSearchMenuItem_Click); + // + // literalSearchMenuItem + // + this.literalSearchMenuItem.Index = 1; + this.literalSearchMenuItem.Text = "&Literal..."; + this.literalSearchMenuItem.Click += new System.EventHandler(this.literalSearchMenuItem_Click); + // + // regexSearchMenuItem + // + this.regexSearchMenuItem.Index = 2; + this.regexSearchMenuItem.Text = "&Regex..."; + this.regexSearchMenuItem.Click += new System.EventHandler(this.regexSearchMenuItem_Click); + // + // stringScanMenuItem + // + this.stringScanMenuItem.Index = 3; + this.stringScanMenuItem.Text = "&String Scan..."; + this.stringScanMenuItem.Click += new System.EventHandler(this.stringScanMenuItem_Click); + // + // heapScanMenuItem + // + this.heapScanMenuItem.Index = 4; + this.heapScanMenuItem.Text = "&Heap Scan..."; + this.heapScanMenuItem.Click += new System.EventHandler(this.heapScanMenuItem_Click); + // + // structSearchMenuItem + // + this.structSearchMenuItem.Index = 5; + this.structSearchMenuItem.Text = "S&truct..."; + this.structSearchMenuItem.Click += new System.EventHandler(this.structSearchMenuItem_Click); + // + // listMemory + // + this.listMemory.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listMemory.DoubleBuffered = true; + this.listMemory.Location = new System.Drawing.Point(6, 59); + this.listMemory.Name = "listMemory"; + this.listMemory.Provider = null; + this.listMemory.Size = new System.Drawing.Size(469, 322); + this.listMemory.TabIndex = 2; + // + // tabEnvironment + // + this.tabEnvironment.Controls.Add(this.listEnvironment); + this.tabEnvironment.ImageKey = "(none)"; + this.tabEnvironment.Location = new System.Drawing.Point(4, 40); + this.tabEnvironment.Name = "tabEnvironment"; + this.tabEnvironment.Padding = new System.Windows.Forms.Padding(3); + this.tabEnvironment.Size = new System.Drawing.Size(480, 387); + this.tabEnvironment.TabIndex = 10; + this.tabEnvironment.Text = "Environment"; + this.tabEnvironment.UseVisualStyleBackColor = true; + // + // listEnvironment + // + this.listEnvironment.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnVarName, + this.columnVarValue}); + this.listEnvironment.Dock = System.Windows.Forms.DockStyle.Fill; + this.listEnvironment.FullRowSelect = true; + this.listEnvironment.HideSelection = false; + this.listEnvironment.Location = new System.Drawing.Point(3, 3); + this.listEnvironment.Name = "listEnvironment"; + this.listEnvironment.ShowItemToolTips = true; + this.listEnvironment.Size = new System.Drawing.Size(474, 381); + this.listEnvironment.Sorting = System.Windows.Forms.SortOrder.Ascending; + this.listEnvironment.TabIndex = 0; + this.listEnvironment.UseCompatibleStateImageBehavior = false; + this.listEnvironment.View = System.Windows.Forms.View.Details; + // + // columnVarName + // + this.columnVarName.Text = "Name"; + this.columnVarName.Width = 150; + // + // columnVarValue + // + this.columnVarValue.Text = "Value"; + this.columnVarValue.Width = 250; + // + // tabHandles + // + this.tabHandles.Controls.Add(this.checkHideHandlesNoName); + this.tabHandles.Controls.Add(this.listHandles); + this.tabHandles.ImageKey = "(none)"; + this.tabHandles.Location = new System.Drawing.Point(4, 40); + this.tabHandles.Name = "tabHandles"; + this.tabHandles.Padding = new System.Windows.Forms.Padding(3); + this.tabHandles.Size = new System.Drawing.Size(480, 387); + this.tabHandles.TabIndex = 5; + this.tabHandles.Text = "Handles"; + this.tabHandles.UseVisualStyleBackColor = true; + // + // checkHideHandlesNoName + // + this.checkHideHandlesNoName.AutoSize = true; + this.checkHideHandlesNoName.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkHideHandlesNoName.Location = new System.Drawing.Point(6, 7); + this.checkHideHandlesNoName.Name = "checkHideHandlesNoName"; + this.checkHideHandlesNoName.Size = new System.Drawing.Size(160, 18); + this.checkHideHandlesNoName.TabIndex = 0; + this.checkHideHandlesNoName.Text = "Hide handles with no name"; + this.checkHideHandlesNoName.UseVisualStyleBackColor = true; + this.checkHideHandlesNoName.CheckedChanged += new System.EventHandler(this.checkHideHandlesNoName_CheckedChanged); + // + // listHandles + // + this.listHandles.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listHandles.DoubleBuffered = true; + this.listHandles.Location = new System.Drawing.Point(6, 30); + this.listHandles.Name = "listHandles"; + this.listHandles.Provider = null; + this.listHandles.Size = new System.Drawing.Size(469, 351); + this.listHandles.TabIndex = 1; + // + // tabJob + // + this.tabJob.ImageKey = "(none)"; + this.tabJob.Location = new System.Drawing.Point(4, 40); + this.tabJob.Name = "tabJob"; + this.tabJob.Size = new System.Drawing.Size(480, 387); + this.tabJob.TabIndex = 11; + this.tabJob.Text = "Job"; + this.tabJob.UseVisualStyleBackColor = true; + // + // tabServices + // + this.tabServices.ImageKey = "(none)"; + this.tabServices.Location = new System.Drawing.Point(4, 40); + this.tabServices.Name = "tabServices"; + this.tabServices.Size = new System.Drawing.Size(480, 387); + this.tabServices.TabIndex = 7; + this.tabServices.Text = "Services"; + this.tabServices.UseVisualStyleBackColor = true; + // + // vistaMenu + // + this.vistaMenu.ContainerControl = this; + this.vistaMenu.DelaySetImageCalls = false; + // + // ProcessWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(488, 431); + this.Controls.Add(this.tabControl); + this.KeyPreview = true; + this.Menu = this.mainMenu; + this.MinimumSize = new System.Drawing.Size(454, 433); + this.Name = "ProcessWindow"; + this.StartPosition = System.Windows.Forms.FormStartPosition.Manual; + this.Text = "Process"; + this.Load += new System.EventHandler(this.ProcessWindow_Load); + this.SizeChanged += new System.EventHandler(this.ProcessWindow_SizeChanged); + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.ProcessWindow_FormClosing); + this.tabControl.ResumeLayout(false); + this.tabGeneral.ResumeLayout(false); + this.groupProcess.ResumeLayout(false); + this.groupProcess.PerformLayout(); + this.groupFile.ResumeLayout(false); + this.groupFile.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureIcon)).EndInit(); + this.tabPerformance.ResumeLayout(false); + this.tablePerformance.ResumeLayout(false); + this.groupBoxIO.ResumeLayout(false); + this.groupBoxPvt.ResumeLayout(false); + this.groupCPUUsage.ResumeLayout(false); + this.groupBox2.ResumeLayout(false); + this.groupBox3.ResumeLayout(false); + this.groupBoxCpu.ResumeLayout(false); + this.tabThreads.ResumeLayout(false); + this.tabModules.ResumeLayout(false); + this.tabMemory.ResumeLayout(false); + this.tabMemory.PerformLayout(); + this.tabEnvironment.ResumeLayout(false); + this.tabHandles.ResumeLayout(false); + this.tabHandles.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.vistaMenu)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.MainMenu mainMenu; + private wyDay.Controls.VistaMenu vistaMenu; + private System.Windows.Forms.MenuItem processMenuItem; + private System.Windows.Forms.MenuItem windowMenuItem; + private System.Windows.Forms.MenuItem inspectImageFileMenuItem; + private System.Windows.Forms.TabControl tabControl; + private System.Windows.Forms.TabPage tabToken; + private System.Windows.Forms.TabPage tabGeneral; + private System.Windows.Forms.TabPage tabThreads; + private ProcessHacker.Components.ThreadList listThreads; + private System.Windows.Forms.TabPage tabModules; + private System.Windows.Forms.TabPage tabMemory; + private System.Windows.Forms.TabPage tabHandles; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.PictureBox pictureIcon; + private System.Windows.Forms.TextBox textFileDescription; + private System.Windows.Forms.TextBox textFileVersion; + private System.Windows.Forms.TextBox textFileCompany; + private System.Windows.Forms.TextBox textCmdLine; + private System.Windows.Forms.GroupBox groupFile; + private System.Windows.Forms.GroupBox groupProcess; + private System.Windows.Forms.TabPage tabServices; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label4; + private ProcessHacker.Components.ModuleList listModules; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.TextBox textParent; + private ProcessHacker.Components.HandleList listHandles; + private ProcessHacker.Components.MemoryList listMemory; + private System.Windows.Forms.Button buttonTerminate; + private System.Windows.Forms.TextBox textDEP; + private System.Windows.Forms.Label labelDEP; + private System.Windows.Forms.Button buttonEditDEP; + private System.Windows.Forms.Button buttonInspectParent; + private System.Windows.Forms.ContextMenu menuSearch; + private System.Windows.Forms.MenuItem newWindowSearchMenuItem; + private System.Windows.Forms.MenuItem literalSearchMenuItem; + private System.Windows.Forms.MenuItem regexSearchMenuItem; + private System.Windows.Forms.MenuItem stringScanMenuItem; + private System.Windows.Forms.MenuItem heapScanMenuItem; + private System.Windows.Forms.CheckBox checkHideFreeRegions; + private System.Windows.Forms.CheckBox checkHideHandlesNoName; + private wyDay.Controls.SplitButton buttonSearch; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.TextBox textPEBAddress; + private System.Windows.Forms.Button buttonInspectPEB; + private System.Windows.Forms.TabPage tabPerformance; + private System.Windows.Forms.GroupBox groupCPUUsage; + private ProcessHacker.Components.Plotter plotterCPUUsage; + private System.Windows.Forms.TabPage tabStatistics; + private System.Windows.Forms.GroupBox groupBox2; + private ProcessHacker.Components.Plotter plotterMemory; + private System.Windows.Forms.TableLayoutPanel tablePerformance; + private System.Windows.Forms.GroupBox groupBox3; + private ProcessHacker.Components.Plotter plotterIO; + private System.Windows.Forms.Label label15; + private System.Windows.Forms.Label label26; + private System.Windows.Forms.TextBox textStartTime; + private ProcessHacker.Components.FileNameBox fileCurrentDirectory; + private ProcessHacker.Components.FileNameBox fileImage; + private System.Windows.Forms.MenuItem structSearchMenuItem; + private System.Windows.Forms.TextBox textProtected; + private System.Windows.Forms.Label labelProtected; + private System.Windows.Forms.Button buttonEditProtected; + private System.Windows.Forms.ToolTip toolTip; + private System.Windows.Forms.TabPage tabEnvironment; + private System.Windows.Forms.ListView listEnvironment; + private System.Windows.Forms.ColumnHeader columnVarName; + private System.Windows.Forms.ColumnHeader columnVarValue; + private System.Windows.Forms.TabPage tabJob; + private System.Windows.Forms.GroupBox groupBoxIO; + private ProcessHacker.Components.Indicator indicatorIO; + private System.Windows.Forms.GroupBox groupBoxPvt; + private ProcessHacker.Components.Indicator indicatorPvt; + private System.Windows.Forms.GroupBox groupBoxCpu; + private ProcessHacker.Components.Indicator indicatorCpu; + private System.Windows.Forms.Label labelProcessType; + private System.Windows.Forms.Label labelProcessTypeValue; + private System.Windows.Forms.Button buttonPermissions; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/ProcessWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/ProcessWindow.cs new file mode 100644 index 000000000..69dd739f5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ProcessWindow.cs @@ -0,0 +1,1389 @@ +/* + * Process Hacker - + * process properties window + * + * Copyright (C) 2008-2009 wj32 + * Copyright (C) 2009 Dean + * + * 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 . + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Drawing; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Common.Ui; +using ProcessHacker.Components; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; +using ProcessHacker.Native.Symbols; +using ProcessHacker.UI; +using ProcessHacker.UI.Actions; +using ProcessHacker.Native.Security.AccessControl; + +namespace ProcessHacker +{ + public partial class ProcessWindow : Form + { + private bool _isFirstPaint = true; + private ProcessHacker.Native.Threading.Event _loadFinishedEvent = + new ProcessHacker.Native.Threading.Event(); + private ProcessItem _processItem; + private int _pid; + private ProcessHandle _processHandle; + private Bitmap _processImage; + + private ThreadProvider _threadP; + private ModuleProvider _moduleP; + private MemoryProvider _memoryP; + private HandleProvider _handleP; + + private ProcessStatistics _processStats; + private TokenProperties _tokenProps; + private JobProperties _jobProps; + private ServiceProperties _serviceProps; + + public ProcessWindow(ProcessItem process) + { + this.SetPhParent(); + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + _processItem = process; + _pid = process.Pid; + + if (process.Icon != null) + this.Icon = process.Icon; + else + this.Icon = Program.HackerWindow.Icon; + + textFileDescription.Text = ""; + textFileCompany.Text = ""; + textFileVersion.Text = ""; + + Program.PWindows.Add(_pid, this); + + this.FixTabs(); + + _dontCalculate = false; + } + + private void ProcessWindow_Load(object sender, EventArgs e) + { + // Load settings. + this.Size = Properties.Settings.Default.ProcessWindowSize; + buttonSearch.Text = Properties.Settings.Default.SearchType; + checkHideHandlesNoName.Checked = Properties.Settings.Default.HideHandlesWithNoName; + + if (tabControl.TabPages[Properties.Settings.Default.ProcessWindowSelectedTab] != null) + tabControl.SelectedTab = tabControl.TabPages[Properties.Settings.Default.ProcessWindowSelectedTab]; + + // Load location, cascade if possible. + Rectangle bounds = Screen.GetWorkingArea(this); + Point location = Properties.Settings.Default.ProcessWindowLocation; + + if (Program.PWindows.Count > 1) + { + location.X += 20; + location.Y += 20; + } + + Properties.Settings.Default.ProcessWindowLocation = this.Location = + Utils.FitRectangle(new Rectangle(location, this.Size), this).Location; + + // Update the Window menu. + Program.UpdateWindowMenu(windowMenuItem, this); + + SymbolProviderExtensions.ShowWarning(this, false); + } + + public ListView ThreadListView + { + get { return listThreads.List; } + } + + public ListView ModuleListView + { + get { return listModules.List; } + } + + public ListView MemoryListView + { + get { return listMemory.List; } + } + + public ListView HandleListView + { + get { return listHandles.List; } + } + + public ListView ServiceListView + { + get { return _serviceProps.List; } + } + + // ==== Performance hacks ==== + protected override void WndProc(ref Message m) + { + switch (m.Msg) + { + case (int)WindowMessage.Paint: + { + if (_isFirstPaint) + { + _isFirstPaint = false; + this.LoadStage1(); + } + } + break; + } + + if (!this.IsDisposed) + base.WndProc(ref m); + } + + private bool _dontCalculate = true; + + protected override void OnResize(EventArgs e) + { + if (_dontCalculate) + return; + + base.OnResize(e); + } + + private void FixTabs() + { + if (_pid <= 0) + { + // this "process" is probably DPCs or Interrupts, so we won't try to load any more information + buttonEditDEP.Enabled = false; + buttonEditProtected.Enabled = false; + buttonInspectParent.Enabled = false; + buttonInspectPEB.Enabled = false; + + if (fileCurrentDirectory.Text != "") + fileCurrentDirectory.Enabled = false; + + if (_pid != 4) + fileImage.Enabled = false; + + buttonSearch.Enabled = false; + buttonTerminate.Enabled = false; + + // remove tab controls not relevant to DPCs/Interrupts + tabControl.TabPages.Remove(tabHandles); + tabControl.TabPages.Remove(tabMemory); + tabControl.TabPages.Remove(tabModules); + tabControl.TabPages.Remove(tabServices); + tabControl.TabPages.Remove(tabThreads); + tabControl.TabPages.Remove(tabToken); + if (tabControl.TabPages.Contains(tabJob)) + tabControl.TabPages.Remove(tabJob); + tabControl.TabPages.Remove(tabEnvironment); + } + else + { + try + { + using (var phandle = new ProcessHandle(_pid, Program.MinProcessQueryRights)) + { + // Check if the process is in a job. + if (phandle.GetJobObject(JobObjectAccess.Query) == null) + tabControl.TabPages.Remove(tabJob); + } + } + catch + { + tabControl.TabPages.Remove(tabJob); + } + + if (Program.HackerWindow != null) + { + if (Program.HackerWindow.ProcessServices.ContainsKey(_pid)) + { + if (Program.HackerWindow.ProcessServices[_pid].Count == 0) + tabControl.TabPages.Remove(tabServices); + } + else + { + tabControl.TabPages.Remove(tabServices); + } + } + } + } + + private void LoadStage1() + { + // May fail. + if (_pid > 4) + { + try + { + _processHandle = new ProcessHandle( + _pid, + (ProcessAccess)StandardRights.Synchronize | + Program.MinProcessQueryRights | + Program.MinProcessReadMemoryRights + ); + } + catch (WindowsException) + { } + } + + // Get the shared waiter to wait on the process. + if (_processHandle != null) + { + Program.SharedWaiter.Add(_processHandle); + Program.SharedWaiter.ObjectSignaled += SharedWaiter_ObjectSignaled; + } + + this.UpdateProcessProperties(); + + // System Idle Process, DPCs, or Interrupts + if (_pid <= 0) + { + this.Text = _processItem.Name; + textFileDescription.Text = _processItem.Name; + textFileCompany.Text = ""; + } + else + { + this.Text = _processItem.Name + " (PID " + _pid.ToString() + ")"; + } + + Application.DoEvents(); + + // add our handler to the process provider + Program.ProcessProvider.Updated += + new ProcessSystemProvider.ProviderUpdateOnce(ProcessProvider_Updated); + + // Check if window was closed before this began executing, bail out if true. + if (!this.IsHandleCreated) + return; + + this.BeginInvoke(new MethodInvoker(this.LoadStage2)); + } + + private void LoadStage2() + { + this.SuspendLayout(); + + plotterCPUUsage.Data1 = _processItem.FloatHistoryManager[ProcessStats.CpuKernel]; + plotterCPUUsage.Data2 = _processItem.FloatHistoryManager[ProcessStats.CpuUser]; + plotterCPUUsage.GetToolTip = i => + ((plotterCPUUsage.Data1[i] + plotterCPUUsage.Data2[i]) * 100).ToString("N2") + + "% (K: " + (plotterCPUUsage.Data1[i] * 100).ToString("N2") + + "%, U: " + (plotterCPUUsage.Data2[i] * 100).ToString("N2") + "%)" + "\n" + + Program.ProcessProvider.TimeHistory[i].ToString(); + plotterMemory.LongData1 = _processItem.LongHistoryManager[ProcessStats.PrivateMemory]; + plotterMemory.LongData2 = _processItem.LongHistoryManager[ProcessStats.WorkingSet]; + plotterMemory.GetToolTip = i => + "Pvt. Memory: " + Utils.FormatSize(plotterMemory.LongData1[i]) + "\n" + + "Working Set: " + Utils.FormatSize(plotterMemory.LongData2[i]) + "\n" + + Program.ProcessProvider.TimeHistory[i].ToString(); + plotterIO.LongData1 = _processItem.LongHistoryManager[ProcessStats.IoReadOther]; + plotterIO.LongData2 = _processItem.LongHistoryManager[ProcessStats.IoWrite]; + plotterIO.GetToolTip = i => + "R+O: " + Utils.FormatSize(plotterIO.LongData1[i]) + "\n" + + "W: " + Utils.FormatSize(plotterIO.LongData2[i]) + "\n" + + Program.ProcessProvider.TimeHistory[i].ToString(); + + // Set the indicator colors. + indicatorCpu.Color1 = Properties.Settings.Default.PlotterCPUKernelColor; + indicatorCpu.Color2 = Properties.Settings.Default.PlotterCPUUserColor; + indicatorPvt.Color1 = Properties.Settings.Default.PlotterMemoryPrivateColor; + indicatorIO.Color1 = Properties.Settings.Default.PlotterIOROColor; + + this.ApplyFont(Properties.Settings.Default.Font); + + this.InitializeSubControls(); + + try + { + this.InitializeProviders(); + } + catch (Exception ex) + { + Logging.Log(ex); + } + + this.UpdateEnvironmentVariables(); + + // disable providers which aren't in use + tabControl_SelectedIndexChanged(null, null); + + this.ResumeLayout(); + + _loadFinishedEvent.Set(); + } + + private void ProcessWindow_FormClosing(object sender, FormClosingEventArgs e) + { + if (this.WindowState == FormWindowState.Normal) + { + Properties.Settings.Default.ProcessWindowSize = this.Size; + + Point p = Properties.Settings.Default.ProcessWindowLocation; + + if ( + (this.Location.X < p.X && this.Location.Y < p.Y && + Program.PWindows.Count > 1) || + Program.PWindows.Count <= 1) + Properties.Settings.Default.ProcessWindowLocation = this.Location; + } + + this.Visible = false; + + _loadFinishedEvent.Dispose(); + + if (_pid >= 0) + { + listThreads.SaveSettings(); + listModules.SaveSettings(); + listMemory.SaveSettings(); + listHandles.SaveSettings(); + } + + if (_tokenProps != null) + { + _tokenProps.SaveSettings(); + (_tokenProps.Object as ProcessHandle).Dispose(); + } + + if (_jobProps != null) + { + _jobProps.SaveSettings(); + _jobProps.JobObject.Dispose(); + } + + if (_serviceProps != null) + { + _serviceProps.SaveSettings(); + } + + if (_processStats != null) + _processStats.Dispose(); + + // Remove the process handle from the shared waiter. + if (_processHandle != null) + Program.SharedWaiter.Remove(_processHandle); + + if (_processImage != null) + { + pictureIcon.Image = null; + _processImage.Dispose(); + } + + Program.ProcessProvider.Updated -= + new ProcessSystemProvider.ProviderUpdateOnce(ProcessProvider_Updated); + + Properties.Settings.Default.EnvironmentListViewColumns = ColumnSettings.SaveSettings(listEnvironment); + Properties.Settings.Default.ProcessWindowSelectedTab = tabControl.SelectedTab.Name; + Properties.Settings.Default.SearchType = buttonSearch.Text; + } + + private void ProcessWindow_SizeChanged(object sender, EventArgs e) + { + this.Invalidate(true); + } + + public void ApplyFont(Font f) + { + listThreads.List.Font = f; + listModules.List.Font = f; + listMemory.List.Font = f; + listHandles.List.Font = f; + listEnvironment.Font = f; + + if (_serviceProps != null) + _serviceProps.List.Font = f; + } + + private void UpdateProcessProperties() + { + try + { + string fileName; + + if (_pid == 4) + fileName = Windows.KernelFileName; + else + fileName = _processItem.FileName; + + if (fileName == null) + { + pictureIcon.Image = _processImage = ProcessHacker.Properties.Resources.Process.ToBitmap(); + return; + } + + FileVersionInfo info = _processItem.VersionInfo; + + textFileDescription.Text = info.FileDescription; + textFileCompany.Text = info.CompanyName; + textFileVersion.Text = info.FileVersion; + fileImage.Text = info.FileName; + + try + { + pictureIcon.Image = _processImage = _processItem.LargeIcon.ToBitmap(); + } + catch + { + pictureIcon.Image = _processImage = ProcessHacker.Properties.Resources.Process.ToBitmap(); + } + + var verifyResult = _processItem.VerifyResult; + + if (verifyResult == VerifyResult.Unknown) + textFileCompany.Text += ""; + else if (verifyResult == VerifyResult.Trusted) + textFileCompany.Text += " (verified)"; + else if (verifyResult == VerifyResult.TrustedInstaller) + textFileCompany.Text += " (verified, Windows component)"; + else if (verifyResult == VerifyResult.NoSignature) + textFileCompany.Text += " (not verified, no signature)"; + else if (verifyResult == VerifyResult.Distrust) + textFileCompany.Text += " (not verified, distrusted)"; + else if (verifyResult == VerifyResult.Expired) + textFileCompany.Text += " (not verified, expired)"; + else if (verifyResult == VerifyResult.Revoked) + textFileCompany.Text += " (not verified, revoked)"; + else if (verifyResult == VerifyResult.SecuritySettings) + textFileCompany.Text += " (not verified, security settings)"; + else + textFileCompany.Text += " (not verified)"; + } + catch + { + fileImage.Text = _processItem.FileName; + textFileDescription.Text = ""; + textFileCompany.Text = ""; + } + + // Update WOW64 info. + if (IntPtr.Size == 4) + { + // 32-bit. Hide the labels. + labelProcessType.Visible = false; + labelProcessTypeValue.Visible = false; + } + else + { + // 64-bit. Show the label. + labelProcessType.Visible = true; + labelProcessTypeValue.Visible = true; + + try + { + using (ProcessHandle phandle = new ProcessHandle(_pid, Program.MinProcessQueryRights)) + { + labelProcessTypeValue.Text = phandle.IsWow64() ? "32-bit" : "64-bit"; + } + } + catch (Exception ex) + { + labelProcessTypeValue.Text = "(" + ex.Message + ")"; + } + } + + if (_pid <= 0) + return; + + if (_processItem.CmdLine != null) + textCmdLine.Text = _processItem.CmdLine.Replace("\0", ""); + + try + { + DateTime startTime = DateTime.FromFileTime(_processItem.Process.CreateTime); + + textStartTime.Text = Utils.FormatRelativeDateTime(startTime) + + " (" + startTime.ToString() + ")"; + } + catch (Exception ex) + { + textStartTime.Text = "(" + ex.Message + ")"; + } + + // The System process doesn't have a current directory or PEB address. + if (_pid > 4) + { + try + { + using (ProcessHandle phandle + = new ProcessHandle(_pid, Program.MinProcessQueryRights | Program.MinProcessReadMemoryRights)) + { + fileCurrentDirectory.Text = + phandle.GetPebString(PebOffset.CurrentDirectoryPath); + } + + fileCurrentDirectory.Enabled = true; + } + catch (Exception ex) + { + fileCurrentDirectory.Text = "(" + ex.Message + ")"; + fileCurrentDirectory.Enabled = false; + } + + try + { + using (ProcessHandle phandle = new ProcessHandle(_pid, Program.MinProcessQueryRights)) + { + textPEBAddress.Text = Utils.FormatAddress(phandle.GetBasicInformation().PebBaseAddress); + } + } + catch (Exception ex) + { + textPEBAddress.Text = "(" + ex.Message + ")"; + buttonInspectPEB.Enabled = false; + } + } + else + { + fileCurrentDirectory.Enabled = false; + buttonInspectPEB.Enabled = false; + } + + if (_processItem.HasParent) + { + if (Program.ProcessProvider.Dictionary.ContainsKey(_processItem.ParentPid)) + { + textParent.Text = + Program.ProcessProvider.Dictionary[_processItem.ParentPid].Name + + " (" + _processItem.ParentPid.ToString() + ")"; + } + else + { + textParent.Text = "Non-existent Process (" + _processItem.ParentPid.ToString() + ")"; + buttonInspectParent.Enabled = false; + } + } + else if (_processItem.ParentPid == -1) + { + // this process doesn't actually have a parent + textParent.Text = "No Parent Process"; + buttonInspectParent.Enabled = false; + } + else + { + // This process had a parent and it's dead, but + // another running process has the same PID as + // its parent. We checked their creation times + // back in ProcessSystemProvider.cs. + textParent.Text = "Non-existent Process (" + _processItem.ParentPid.ToString() + ")"; + buttonInspectParent.Enabled = false; + } + + this.UpdateProtected(); + this.UpdateDepStatus(); + } + + private void InitializeSubControls() + { + var processStats = new ProcessStatistics(_pid); + processStats.Dock = DockStyle.Fill; + tabStatistics.Controls.Add(processStats); + _processStats = processStats; + + // If this is a non-process, we need to clear the statistics first. + if (_pid <= 0) + _processStats.ClearStatistics(); + + try + { + _tokenProps = new TokenProperties(new ProcessHandle(_pid, Program.MinProcessQueryRights)); + _tokenProps.Dock = DockStyle.Fill; + tabToken.Controls.Add(_tokenProps); + } + catch + { } + + try + { + using (var phandle = new ProcessHandle(_pid, Program.MinProcessQueryRights)) + { + var jhandle = phandle.GetJobObject(JobObjectAccess.Query); + + if (jhandle != null) + { + using (jhandle) + { + _jobProps = new JobProperties(jhandle); + _jobProps.Dock = DockStyle.Fill; + tabJob.Controls.Add(_jobProps); + } + } + } + } + catch + { } + + if (Program.HackerWindow != null) + { + if (Program.HackerWindow.ProcessServices.ContainsKey(_pid)) + { + if (Program.HackerWindow.ProcessServices[_pid].Count > 0) + { + _serviceProps = new ServiceProperties( + Program.HackerWindow.ProcessServices.ContainsKey(_pid) ? + Program.HackerWindow.ProcessServices[_pid].ToArray() : + new string[0]); + _serviceProps.Dock = DockStyle.Fill; + _serviceProps.PID = _pid; + tabServices.Controls.Add(_serviceProps); + } + } + } + + listEnvironment.ListViewItemSorter = new SortedListViewComparer(listEnvironment); + listEnvironment.SetDoubleBuffered(true); + listEnvironment.SetTheme("explorer"); + listEnvironment.ContextMenu = listEnvironment.GetCopyMenu(); + ColumnSettings.LoadSettings(Properties.Settings.Default.EnvironmentListViewColumns, listEnvironment); + } + + private void InitializeProviders() + { + listThreads.BeginUpdate(); + _threadP = new ThreadProvider(_pid); + Program.SecondarySharedThreadProvider.Add(_threadP); + _threadP.Interval = Properties.Settings.Default.RefreshInterval; + _threadP.Updated += new ThreadProvider.ProviderUpdateOnce(_threadP_Updated); + listThreads.Provider = _threadP; + //_threadP.RunOnceAsync(); + + listModules.BeginUpdate(); + _moduleP = new ModuleProvider(_pid); + Program.SecondarySharedThreadProvider.Add(_moduleP); + _moduleP.Interval = Properties.Settings.Default.RefreshInterval; + _moduleP.Updated += new ModuleProvider.ProviderUpdateOnce(_moduleP_Updated); + listModules.Provider = _moduleP; + //_moduleP.RunOnceAsync(); + + listMemory.BeginUpdate(); + _memoryP = new MemoryProvider(_pid); + Program.SecondarySharedThreadProvider.Add(_memoryP); + _memoryP.IgnoreFreeRegions = true; + _memoryP.Interval = Properties.Settings.Default.RefreshInterval; + _memoryP.Updated += new MemoryProvider.ProviderUpdateOnce(_memoryP_Updated); + listMemory.Provider = _memoryP; + //_memoryP.RunOnceAsync(); + + listHandles.BeginUpdate(); + _handleP = new HandleProvider(_pid); + Program.SecondarySharedThreadProvider.Add(_handleP); + _handleP.HideHandlesWithNoName = Properties.Settings.Default.HideHandlesWithNoName; + _handleP.Interval = Properties.Settings.Default.RefreshInterval; + _handleP.Updated += new HandleProvider.ProviderUpdateOnce(_handleP_Updated); + listHandles.Provider = _handleP; + //_handleP.RunOnceAsync(); + + listThreads.List.SetTheme("explorer"); + listModules.List.SetTheme("explorer"); + listMemory.List.SetTheme("explorer"); + listHandles.List.SetTheme("explorer"); + + this.InitializeShortcuts(); + } + + private void InitializeShortcuts() + { + listThreads.List.AddShortcuts(); + listModules.List.AddShortcuts(); + listMemory.List.AddShortcuts(); + listHandles.List.AddShortcuts(); + listEnvironment.AddShortcuts(); + } + + private void UpdateEnvironmentVariables() + { + listEnvironment.Items.Clear(); + + listEnvironment.BeginUpdate(); + + WorkQueue.GlobalQueueWorkItemTag(new Action(() => + { + try + { + using (ProcessHandle phandle = new ProcessHandle(_pid, + ProcessAccess.QueryInformation | Program.MinProcessReadMemoryRights)) + { + foreach (var pair in phandle.GetEnvironmentVariables()) + { + if (pair.Key != "") + { + if (this.IsHandleCreated) + { + // Work around delegate variable capturing. + var localPair = pair; + + this.BeginInvoke(new MethodInvoker(() => + { + listEnvironment.Items.Add( + new ListViewItem(new string[] { localPair.Key, localPair.Value })); + })); + } + } + } + } + } + catch + { } + + if (this.IsHandleCreated) + { + this.BeginInvoke(new MethodInvoker(() => listEnvironment.EndUpdate())); + } + }), "process-update-environment-variables"); + } + + public void UpdateProtected() + { + labelProtected.Enabled = true; + textProtected.Enabled = true; + buttonEditProtected.Enabled = true; + + if (KProcessHacker.Instance != null && OSVersion.HasProtectedProcesses) + { + try + { + textProtected.Text = KProcessHacker.Instance.GetProcessProtected(_pid) ? "Protected" : "Not Protected"; + } + catch (Exception ex) + { + textProtected.Text = "(" + ex.Message + ")"; + buttonEditProtected.Enabled = false; + } + } + else + { + labelProtected.Enabled = false; + textProtected.Enabled = false; + buttonEditProtected.Enabled = false; + } + } + + public void UpdateDepStatus() + { + labelDEP.Enabled = true; + textDEP.Enabled = true; + try + { + using (var phandle = new ProcessHandle(_pid, ProcessAccess.QueryInformation)) + { + var depStatus = phandle.GetDepStatus(); + string str; + + if ((depStatus & DepStatus.Enabled) != 0) + { + str = "Enabled"; + } + else + { + str = "Disabled"; + } + + if ((depStatus & DepStatus.Permanent) != 0) + { + buttonEditDEP.Enabled = false; + str += ", Permanent"; + } + + if ((depStatus & DepStatus.AtlThunkEmulationDisabled) != 0) + str += ", DEP-ATL thunk emulation disabled"; + + textDEP.Text = str; + } + } + catch (EntryPointNotFoundException) + { + labelDEP.Enabled = false; + textDEP.Enabled = false; + textDEP.Text = ""; + //textDEP.Text = "(This feature is not supported on your version of Windows)"; + buttonEditDEP.Enabled = false; + } + catch (Exception ex) + { + textDEP.Text = "(" + ex.Message + ")"; + buttonEditDEP.Enabled = false; + } + + // Can't set DEP status on processes in other sessions without KPH. + if ( + KProcessHacker.Instance == null && + _processItem.SessionId != Program.CurrentSessionId + ) + buttonEditDEP.Enabled = false; + } + + private void PerformSearch(string text) + { + Point location = this.Location; + System.Drawing.Size size = this.Size; + + ResultsWindow rw = Program.GetResultsWindow(_pid, + new Program.ResultsWindowInvokeAction(delegate(ResultsWindow f) + { + if (text == "&New Results Window...") + { + f.Show(); + } + else if (text == "&Literal...") + { + if (f.EditSearch(SearchType.Literal, location, size) == DialogResult.OK) + { + f.Show(); + f.StartSearch(); + } + else + { + f.Close(); + } + } + else if (text == "&Regex...") + { + if (f.EditSearch(SearchType.Regex, location, size) == DialogResult.OK) + { + f.Show(); + f.StartSearch(); + } + else + { + f.Close(); + } + } + else if (text == "&String Scan...") + { + f.SearchOptions.Type = SearchType.String; + f.Show(); + f.StartSearch(); + } + else if (text == "&Heap Scan...") + { + f.SearchOptions.Type = SearchType.Heap; + f.Show(); + f.StartSearch(); + } + else if (text == "S&truct...") + { + if (f.EditSearch(SearchType.Struct, location, size) == DialogResult.OK) + { + f.Show(); + f.StartSearch(); + } + else + { + f.Close(); + } + } + })); + + buttonSearch.Text = text; + } + + private void UpdatePerformance() + { + ProcessSystemProvider sysProvider = Program.ProcessProvider; + + if (!sysProvider.Dictionary.ContainsKey(_pid)) + return; + + ProcessItem item = sysProvider.Dictionary[_pid]; + + plotterCPUUsage.LineColor1 = Properties.Settings.Default.PlotterCPUKernelColor; + plotterCPUUsage.LineColor2 = Properties.Settings.Default.PlotterCPUUserColor; + plotterMemory.LineColor1 = Properties.Settings.Default.PlotterMemoryPrivateColor; + plotterMemory.LineColor2 = Properties.Settings.Default.PlotterMemoryWSColor; + plotterIO.LineColor1 = Properties.Settings.Default.PlotterIOROColor; + plotterIO.LineColor2 = Properties.Settings.Default.PlotterIOWColor; + + // Update the graphs. + long sysTotal = sysProvider.LongDeltas[SystemStats.CpuKernel] + sysProvider.LongDeltas[SystemStats.CpuUser] + + sysProvider.LongDeltas[SystemStats.CpuOther]; + float procKernel = (float)item.DeltaManager[ProcessStats.CpuKernel] / sysTotal; + float procUser = (float)item.DeltaManager[ProcessStats.CpuUser] / sysTotal; + long ioRO = item.DeltaManager[ProcessStats.IoRead] + item.DeltaManager[ProcessStats.IoOther]; + long ioW = item.DeltaManager[ProcessStats.IoWrite]; + + string cpuStr = ((procKernel + procUser) * 100).ToString("F2") + "%"; + plotterCPUUsage.Text = cpuStr + + " (K: " + (procKernel * 100).ToString("F2") + + "%, U: " + (procUser * 100).ToString("F2") + "%)"; + + string pvtString = Utils.FormatSize(item.Process.VirtualMemoryCounters.PrivatePageCount); + plotterMemory.Text = "Pvt: " + pvtString + + ", WS: " + Utils.FormatSize(item.Process.VirtualMemoryCounters.WorkingSetSize); + + string ioROString = Utils.FormatSize(ioRO); + plotterIO.Text = "R+O: " + ioROString + ", W: " + Utils.FormatSize(ioW); + + plotterCPUUsage.MoveGrid(); + plotterCPUUsage.Draw(); + plotterMemory.MoveGrid(); + plotterMemory.Draw(); + plotterIO.MoveGrid(); + plotterIO.Draw(); + + // Update the CPU indicator. + indicatorCpu.Maximum = (int)((procKernel + procUser) * int.MaxValue); + indicatorCpu.Data1 = (int)(procKernel * indicatorCpu.Maximum); + indicatorCpu.Data2 = (int)(procUser * indicatorCpu.Maximum); + indicatorCpu.TextValue = cpuStr; + + // Update the Pvt. Memory indicator. + int count = plotterIO.Width / plotterIO.EffectiveMoveStep; + long maxPvt = _processItem.LongHistoryManager[ProcessStats.PrivateMemory].Take(count).Max(); + long maxWS = _processItem.LongHistoryManager[ProcessStats.WorkingSet].Take(count).Max(); + if(maxPvt>maxWS) + indicatorPvt.Maximum = maxPvt; + else + indicatorPvt.Maximum = maxWS; + indicatorPvt.Data1 = item.Process.VirtualMemoryCounters.PrivatePageCount.ToInt64(); + indicatorPvt.TextValue = pvtString; + + // Update the I/O Bytes indicator. + long maxRO = _processItem.LongHistoryManager[ProcessStats.IoReadOther].Take(count).Max(); + long maxW = _processItem.LongHistoryManager[ProcessStats.IoWrite].Take(count).Max(); + if (maxRO > maxW) + indicatorIO.Maximum = maxRO; + else + indicatorIO.Maximum = maxW; + indicatorIO.Data1 = ioRO; + indicatorIO.TextValue = ioROString; + } + + // Start: HACK HACK HACK HACK + private int _selectTid; + + public void SelectThread(int tid) + { + _selectTid = tid; + + WorkQueue.GlobalQueueWorkItemTag(new MethodInvoker(() => + { + _loadFinishedEvent.Wait(); + _threadP.Updated += SelectThread_threadP_Updated; + _threadP.RunOnce(); + }), "select-thread"); + } + + void SelectThread_threadP_Updated() + { + _threadP.Updated -= SelectThread_threadP_Updated; + + if (this.IsHandleCreated) + { + this.BeginInvoke(new MethodInvoker(() => + { + tabControl.SelectedTab = tabThreads; + var litem = listThreads.Items[_selectTid.ToString()]; + + Program.HackerWindow.DeselectAll(listThreads.List); + litem.Selected = true; + litem.EnsureVisible(); + })); + } + } + + // End: HACK HACK HACK HACK + + #region Buttons + + private void buttonTerminate_Click(object sender, EventArgs e) + { + ProcessActions.Terminate(this, new int[] { _processItem.Pid }, new string[] { _processItem.Name }, true); + } + + private void buttonEditDEP_Click(object sender, EventArgs e) + { + EditDEPWindow w = new EditDEPWindow(_pid); + + w.TopMost = this.TopMost; + w.ShowDialog(); + + this.UpdateDepStatus(); + } + + private void buttonEditProtected_Click(object sender, EventArgs e) + { + try + { + ComboBoxPickerWindow picker = new ComboBoxPickerWindow(new string[] { "Protect", "Unprotect" }); + + picker.Message = "Select an action below:"; + picker.SelectedItem = (textProtected.Text == "Protected") ? "Protect" : "Unprotect"; + + if (picker.ShowDialog() == DialogResult.OK) + { + KProcessHacker.Instance.SetProcessProtected(_pid, picker.SelectedItem == "Protect"); + this.UpdateProtected(); + } + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to change process protection", ex); + } + } + + private void buttonInspectPEB_Click(object sender, EventArgs e) + { + try + { + if (!Program.Structs.ContainsKey("PEB")) + throw new Exception("The struct 'PEB' has not been loaded. Make sure structs.txt was loaded successfully."); + + using (ProcessHandle phandle = new ProcessHandle(_pid, Program.MinProcessQueryRights)) + { + IntPtr baseAddress = phandle.GetBasicInformation().PebBaseAddress; + + Program.HackerWindow.BeginInvoke(new MethodInvoker(delegate + { + StructWindow sw = new StructWindow(_pid, baseAddress, Program.Structs["PEB"]); + + try + { + sw.Show(); + sw.Activate(); + } + catch + { } + })); + } + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to inspect the PEB", ex); + } + } + + private void buttonInspectParent_Click(object sender, EventArgs e) + { + try + { + ProcessActions.ShowProperties( + this, + _processItem.ParentPid, + Program.ProcessProvider.Dictionary[_processItem.ParentPid].Name + ); + } + catch (KeyNotFoundException) + { + PhUtils.ShowError("The process could not be found."); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to inspect the parent process", ex); + } + } + + private void buttonSearch_Click(object sender, EventArgs e) + { + PerformSearch(buttonSearch.Text); + } + + private void buttonPermissions_Click(object sender, EventArgs e) + { + try + { + SecurityEditor.EditSecurity( + this, + SecurityEditor.GetSecurable( + NativeTypeFactory.ObjectType.Process, + (access) => new ProcessHandle(_pid, (ProcessAccess)access)), + _processItem.Name, + NativeTypeFactory.GetAccessEntries(NativeTypeFactory.ObjectType.Process) + ); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to edit permissions", ex); + } + } + + #endregion + + #region Check Boxes + + private void checkHideFreeRegions_CheckedChanged(object sender, EventArgs e) + { + checkHideFreeRegions.Enabled = false; + this.Cursor = Cursors.WaitCursor; + listMemory.BeginUpdate(); + _memoryP.IgnoreFreeRegions = checkHideFreeRegions.Checked; + _memoryP.Updated += new MemoryProvider.ProviderUpdateOnce(_memoryP_Updated); + _memoryP.RunOnceAsync(); + } + + private void checkHideHandlesNoName_CheckedChanged(object sender, EventArgs e) + { + if (_handleP != null) + { + checkHideHandlesNoName.Enabled = false; + this.Cursor = Cursors.WaitCursor; + Program.SecondarySharedThreadProvider.Remove(_handleP); + _handleP.Dispose(); + listHandles.BeginUpdate(); + _handleP = new HandleProvider(_pid); + Program.SecondarySharedThreadProvider.Add(_handleP); + _handleP.HideHandlesWithNoName = checkHideHandlesNoName.Checked; + _handleP.Interval = Properties.Settings.Default.RefreshInterval; + _handleP.Updated += new HandleProvider.ProviderUpdateOnce(_handleP_Updated); + _handleP.RunOnceAsync(); + listHandles.Provider = _handleP; + _handleP.Enabled = true; + } + } + + #endregion + + #region Menu Items + + private void inspectImageFileMenuItem_Click(object sender, EventArgs e) + { + try + { + string path; + + if (_pid == 4) + { + path = Windows.KernelFileName; + } + else + { + path = _processItem.FileName; + } + + PEWindow pw = Program.GetPEWindow(path, + new Program.PEWindowInvokeAction(delegate(PEWindow f) + { + try + { + f.Show(); + f.Activate(); + } + catch + { } + })); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to inspect the image file", ex); + } + } + + #endregion + + #region Providers + + private void ProcessProvider_Updated() + { + try + { + this.BeginInvoke(new MethodInvoker(delegate + { + if (tabControl.SelectedTab == tabStatistics) + { + if (_processStats != null) + _processStats.UpdateStatistics(); + } + else if (tabControl.SelectedTab == tabPerformance) + { + this.UpdatePerformance(); + } + })); + } + catch + { } + } + + private void _memoryP_Updated() + { + if (_memoryP.RunCount > 1) + { + this.BeginInvoke(new MethodInvoker(delegate + { + listMemory.EndUpdate(); + listMemory.Refresh(); + checkHideFreeRegions.Enabled = true; + this.Cursor = Cursors.Default; + })); + _memoryP.Updated -= new MemoryProvider.ProviderUpdateOnce(_memoryP_Updated); + } + } + + private void _handleP_Updated() + { + if (_handleP.RunCount > 1) + { + this.BeginInvoke(new MethodInvoker(delegate + { + listHandles.EndUpdate(); + listHandles.Refresh(); + checkHideHandlesNoName.Enabled = true; + this.Cursor = Cursors.Default; + })); + _handleP.Updated -= new HandleProvider.ProviderUpdateOnce(_handleP_Updated); + } + } + + private void _moduleP_Updated() + { + if (_moduleP.RunCount > 1) + { + this.BeginInvoke(new MethodInvoker(delegate + { + listModules.EndUpdate(); + listModules.Refresh(); + })); + _moduleP.Updated -= new ModuleProvider.ProviderUpdateOnce(_moduleP_Updated); + } + } + + private void _threadP_Updated() + { + if (_threadP.RunCount > 1) + { + this.BeginInvoke(new MethodInvoker(delegate + { + listThreads.EndUpdate(); + listThreads.Refresh(); + })); + _threadP.Updated -= new ThreadProvider.ProviderUpdateOnce(_threadP_Updated); + } + } + + #endregion + + #region Search Menu Items + + private void newWindowSearchMenuItem_Click(object sender, EventArgs e) + { + PerformSearch(newWindowSearchMenuItem.Text); + } + + private void literalSearchMenuItem_Click(object sender, EventArgs e) + { + PerformSearch(literalSearchMenuItem.Text); + } + + private void regexSearchMenuItem_Click(object sender, EventArgs e) + { + PerformSearch(regexSearchMenuItem.Text); + } + + private void stringScanMenuItem_Click(object sender, EventArgs e) + { + PerformSearch(stringScanMenuItem.Text); + } + + private void heapScanMenuItem_Click(object sender, EventArgs e) + { + PerformSearch(heapScanMenuItem.Text); + } + + private void structSearchMenuItem_Click(object sender, EventArgs e) + { + PerformSearch(structSearchMenuItem.Text); + } + + #endregion + + #region Tab Controls + + private void tabControl_SelectedIndexChanged(object sender, EventArgs e) + { + if (_threadP != null) + if (_threadP.Enabled = tabControl.SelectedTab == tabThreads) + _threadP.RunOnceAsync(); + if (_moduleP != null) + if (_moduleP.Enabled = tabControl.SelectedTab == tabModules) + _moduleP.RunOnceAsync(); + if (_memoryP != null) + if (_memoryP.Enabled = tabControl.SelectedTab == tabMemory) + _memoryP.RunOnceAsync(); + if (_handleP != null) + if (_handleP.Enabled = tabControl.SelectedTab == tabHandles) + _handleP.RunOnceAsync(); + + if (tabControl.SelectedTab == tabStatistics) + { + if (_processStats != null) + _processStats.UpdateStatistics(); + } + + if (tabControl.SelectedTab == tabPerformance) + { + this.UpdatePerformance(); + } + + if (_jobProps != null) + { + if (tabControl.SelectedTab == tabJob) + { + _jobProps.UpdateEnabled = true; + } + else + { + _jobProps.UpdateEnabled = false; + } + } + } + + #endregion + + #region Waiters + + private void SharedWaiter_ObjectSignaled(ISynchronizable obj) + { + // Check if the object is our process handle. + if (obj == _processHandle) + { + if (this.IsHandleCreated) + { + this.BeginInvoke(new MethodInvoker(() => + { + NtStatus exitStatus = _processHandle.GetExitStatus(); + string exitString = exitStatus.ToString(); + long exitLong; + + // We want "Success" instead of "Wait0" (both are 0x0). + if (exitString == "Wait0") + exitString = "Success"; + + // If we have a NT status string, display it. + // Otherwise, display the NT status value in hex. + if (!long.TryParse(exitString, out exitLong)) + { + this.Text += " (exited with status " + exitString + ")"; + } + else + { + this.Text += " (exited with status 0x" + exitLong.ToString("x8") + ")"; + } + })); + } + } + } + + #endregion + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/ProcessWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/ProcessWindow.resx new file mode 100644 index 000000000..5339804c0 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ProcessWindow.resx @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 354, 17 + + + 235, 17 + + + 354, 17 + + + 127, 17 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/PromptBox.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/PromptBox.Designer.cs new file mode 100644 index 000000000..68142185e --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/PromptBox.Designer.cs @@ -0,0 +1,107 @@ +namespace ProcessHacker +{ + partial class PromptBox + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.labelValue = new System.Windows.Forms.Label(); + this.textValue = new System.Windows.Forms.TextBox(); + this.buttonOK = new System.Windows.Forms.Button(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // labelValue + // + this.labelValue.AutoSize = true; + this.labelValue.Location = new System.Drawing.Point(12, 15); + this.labelValue.Name = "labelValue"; + this.labelValue.Size = new System.Drawing.Size(37, 13); + this.labelValue.TabIndex = 3; + this.labelValue.Text = "Value:"; + // + // textValue + // + this.textValue.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textValue.Location = new System.Drawing.Point(55, 12); + this.textValue.Name = "textValue"; + this.textValue.Size = new System.Drawing.Size(319, 20); + this.textValue.TabIndex = 0; + // + // buttonOK + // + this.buttonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonOK.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonOK.Location = new System.Drawing.Point(218, 38); + this.buttonOK.Name = "buttonOK"; + this.buttonOK.Size = new System.Drawing.Size(75, 23); + this.buttonOK.TabIndex = 1; + this.buttonOK.Text = "&OK"; + this.buttonOK.UseVisualStyleBackColor = true; + this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click); + // + // buttonCancel + // + this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.buttonCancel.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonCancel.Location = new System.Drawing.Point(299, 38); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.TabIndex = 2; + this.buttonCancel.Text = "&Cancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click); + // + // PromptBox + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(386, 73); + this.ControlBox = false; + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.buttonOK); + this.Controls.Add(this.textValue); + this.Controls.Add(this.labelValue); + this.Name = "PromptBox"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Enter Value"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label labelValue; + private System.Windows.Forms.TextBox textValue; + private System.Windows.Forms.Button buttonOK; + private System.Windows.Forms.Button buttonCancel; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/PromptBox.cs b/branches/ph-plugins/ProcessHacker/Forms/PromptBox.cs new file mode 100644 index 000000000..da630878f --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/PromptBox.cs @@ -0,0 +1,95 @@ +/* + * Process Hacker - + * easy-to-use prompt box + * + * Copyright (C) 2008 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 . + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Text; +using System.Windows.Forms; + +namespace ProcessHacker +{ + public partial class PromptBox : Form + { + private string _value; + public static string LastValue; + + public string Value + { + get { return _value; } + } + + public PromptBox() : this("", false) { } + + public PromptBox(string value) : this(value, false) { } + + public PromptBox(bool multiline) : this("", multiline) { } + + public PromptBox(string value, bool multiline) + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + if (value == "") + { + textValue.Text = LastValue; + } + else + { + textValue.Text = value; + } + + if (multiline) + { + textValue.Multiline = true; + textValue.ScrollBars = ScrollBars.Vertical; + this.Size = new Size(this.Size.Width, this.Size.Height + 100); + this.AcceptButton = null; + } + else + { + this.AcceptButton = buttonOK; + } + } + + public TextBox TextBox + { + get { return textValue; } + } + + private void buttonOK_Click(object sender, EventArgs e) + { + _value = textValue.Text; + LastValue = _value; + this.DialogResult = DialogResult.OK; + this.Close(); + } + + private void buttonCancel_Click(object sender, EventArgs e) + { + this.DialogResult = DialogResult.Cancel; + this.Close(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/PromptBox.resx b/branches/ph-plugins/ProcessHacker/Forms/PromptBox.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/PromptBox.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/ProtectProcessWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/ProtectProcessWindow.Designer.cs new file mode 100644 index 000000000..b6371a1a9 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ProtectProcessWindow.Designer.cs @@ -0,0 +1,167 @@ +namespace ProcessHacker +{ + partial class ProtectProcessWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.checkProtect = new System.Windows.Forms.CheckBox(); + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.listProcessAccess = new System.Windows.Forms.CheckedListBox(); + this.listThreadAccess = new System.Windows.Forms.CheckedListBox(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.buttonOK = new System.Windows.Forms.Button(); + this.checkDontAllowKernelMode = new System.Windows.Forms.CheckBox(); + this.SuspendLayout(); + // + // checkProtect + // + this.checkProtect.AutoSize = true; + this.checkProtect.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkProtect.Location = new System.Drawing.Point(12, 12); + this.checkProtect.Name = "checkProtect"; + this.checkProtect.Size = new System.Drawing.Size(125, 18); + this.checkProtect.TabIndex = 0; + this.checkProtect.Text = "Protect this process"; + this.checkProtect.UseVisualStyleBackColor = true; + this.checkProtect.CheckedChanged += new System.EventHandler(this.checkProtect_CheckedChanged); + // + // label1 + // + this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 62); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(124, 13); + this.label1.TabIndex = 2; + this.label1.Text = "Allowed process access:"; + // + // label2 + // + this.label2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(12, 175); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(117, 13); + this.label2.TabIndex = 4; + this.label2.Text = "Allowed thread access:"; + // + // listProcessAccess + // + this.listProcessAccess.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listProcessAccess.FormattingEnabled = true; + this.listProcessAccess.Location = new System.Drawing.Point(12, 78); + this.listProcessAccess.Name = "listProcessAccess"; + this.listProcessAccess.Size = new System.Drawing.Size(474, 94); + this.listProcessAccess.TabIndex = 3; + // + // listThreadAccess + // + this.listThreadAccess.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listThreadAccess.FormattingEnabled = true; + this.listThreadAccess.Location = new System.Drawing.Point(12, 191); + this.listThreadAccess.Name = "listThreadAccess"; + this.listThreadAccess.Size = new System.Drawing.Size(474, 94); + this.listThreadAccess.TabIndex = 5; + // + // buttonCancel + // + this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonCancel.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonCancel.Location = new System.Drawing.Point(411, 291); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.TabIndex = 7; + this.buttonCancel.Text = "Cancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click); + // + // buttonOK + // + this.buttonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonOK.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonOK.Location = new System.Drawing.Point(330, 291); + this.buttonOK.Name = "buttonOK"; + this.buttonOK.Size = new System.Drawing.Size(75, 23); + this.buttonOK.TabIndex = 6; + this.buttonOK.Text = "OK"; + this.buttonOK.UseVisualStyleBackColor = true; + this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click); + // + // checkDontAllowKernelMode + // + this.checkDontAllowKernelMode.AutoSize = true; + this.checkDontAllowKernelMode.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkDontAllowKernelMode.Location = new System.Drawing.Point(12, 36); + this.checkDontAllowKernelMode.Name = "checkDontAllowKernelMode"; + this.checkDontAllowKernelMode.Size = new System.Drawing.Size(270, 18); + this.checkDontAllowKernelMode.TabIndex = 1; + this.checkDontAllowKernelMode.Text = "Don\'t allow kernel-mode code to bypass protection"; + this.checkDontAllowKernelMode.UseVisualStyleBackColor = true; + // + // ProtectProcessWindow + // + this.AcceptButton = this.buttonOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(498, 326); + this.Controls.Add(this.checkDontAllowKernelMode); + this.Controls.Add(this.buttonOK); + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.listThreadAccess); + this.Controls.Add(this.listProcessAccess); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.Controls.Add(this.checkProtect); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ProtectProcessWindow"; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Protect Process"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.CheckBox checkProtect; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.CheckedListBox listProcessAccess; + private System.Windows.Forms.CheckedListBox listThreadAccess; + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.Button buttonOK; + private System.Windows.Forms.CheckBox checkDontAllowKernelMode; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/ProtectProcessWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/ProtectProcessWindow.cs new file mode 100644 index 000000000..d28bb0c3b --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ProtectProcessWindow.cs @@ -0,0 +1,131 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Text; +using System.Windows.Forms; +using ProcessHacker.Native; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker +{ + public partial class ProtectProcessWindow : Form + { + private int _pid; + private bool _isProtected; + + public ProtectProcessWindow(int pid) + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + _pid = pid; + + bool allowKernelMode; + ProcessAccess processAccess; + ThreadAccess threadAccess; + + if (ProtectQuery(_pid, out allowKernelMode, out processAccess, out threadAccess)) + { + checkProtect.Checked = _isProtected = true; + checkDontAllowKernelMode.Checked = !allowKernelMode; + } + + foreach (string value in Enum.GetNames(typeof(ProcessAccess))) + { + if (value == "All") + continue; + + listProcessAccess.Items.Add(value, + (processAccess & (ProcessAccess)Enum.Parse(typeof(ProcessAccess), value)) != 0); + } + + foreach (string value in Enum.GetNames(typeof(ThreadAccess))) + { + if (value == "All") + continue; + + listThreadAccess.Items.Add(value, + (threadAccess & (ThreadAccess)Enum.Parse(typeof(ThreadAccess), value)) != 0); + } + + checkProtect_CheckedChanged(null, null); + } + + private bool ProtectQuery(int pid, out bool allowKernelMode, out ProcessAccess processAccess, out ThreadAccess threadAccess) + { + try + { + using (var phandle = new ProcessHandle(pid, Program.MinProcessQueryRights)) + KProcessHacker.Instance.ProtectQuery(phandle, out allowKernelMode, out processAccess, out threadAccess); + + return true; + } + catch + { + allowKernelMode = true; + processAccess = 0; + threadAccess = 0; + + return false; + } + } + + private void buttonCancel_Click(object sender, EventArgs e) + { + this.Close(); + } + + private void buttonOK_Click(object sender, EventArgs e) + { + // remove protection + if (_isProtected) + { + try + { + using (var phandle = new ProcessHandle(_pid, Program.MinProcessQueryRights)) + KProcessHacker.Instance.ProtectRemove(phandle); + } + catch + { } + } + + // re-add protection (with new masks) + if (checkProtect.Checked) + { + ProcessAccess processAccess = 0; + ThreadAccess threadAccess = 0; + + foreach (string value in listProcessAccess.CheckedItems) + processAccess |= (ProcessAccess)Enum.Parse(typeof(ProcessAccess), value); + foreach (string value in listThreadAccess.CheckedItems) + threadAccess |= (ThreadAccess)Enum.Parse(typeof(ThreadAccess), value); + + try + { + using (var phandle = new ProcessHandle(_pid, Program.MinProcessQueryRights)) + KProcessHacker.Instance.ProtectAdd( + phandle, + !checkDontAllowKernelMode.Checked, + processAccess, + threadAccess + ); + } + catch + { } + } + + this.Close(); + } + + private void checkProtect_CheckedChanged(object sender, EventArgs e) + { + checkDontAllowKernelMode.Enabled = checkProtect.Checked; + listProcessAccess.Enabled = checkProtect.Checked; + listThreadAccess.Enabled = checkProtect.Checked; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/ProtectProcessWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/ProtectProcessWindow.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ProtectProcessWindow.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/ResultsWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/ResultsWindow.Designer.cs new file mode 100644 index 000000000..b821be6c8 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ResultsWindow.Designer.cs @@ -0,0 +1,235 @@ +using System; + +namespace ProcessHacker +{ + partial class ResultsWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + if (_searchThread != null) + _searchThread.Abort(); + + _so = null; + + Program.ResultsWindows.Remove(Id); + Program.ResultsIds.Push(_id); + + Program.CollectGarbage(); + + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ResultsWindow)); + this.listResults = new System.Windows.Forms.ListView(); + this.columnAddress = new System.Windows.Forms.ColumnHeader(); + this.columnOffset = new System.Windows.Forms.ColumnHeader(); + this.columnLength = new System.Windows.Forms.ColumnHeader(); + this.columnString = new System.Windows.Forms.ColumnHeader(); + this.labelText = new System.Windows.Forms.Label(); + this.mainMenu = new System.Windows.Forms.MainMenu(this.components); + this.windowMenuItem = new System.Windows.Forms.MenuItem(); + this.buttonFilter = new System.Windows.Forms.Button(); + this.buttonIntersect = new System.Windows.Forms.Button(); + this.buttonEdit = new System.Windows.Forms.Button(); + this.buttonFind = new System.Windows.Forms.Button(); + this.buttonSave = new System.Windows.Forms.Button(); + this.vistaMenu = new wyDay.Controls.VistaMenu(this.components); + this.toolTip = new System.Windows.Forms.ToolTip(this.components); + ((System.ComponentModel.ISupportInitialize)(this.vistaMenu)).BeginInit(); + this.SuspendLayout(); + // + // listResults + // + this.listResults.AllowColumnReorder = true; + this.listResults.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listResults.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnAddress, + this.columnOffset, + this.columnLength, + this.columnString}); + this.listResults.FullRowSelect = true; + this.listResults.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; + this.listResults.HideSelection = false; + this.listResults.Location = new System.Drawing.Point(12, 35); + this.listResults.Name = "listResults"; + this.listResults.ShowItemToolTips = true; + this.listResults.Size = new System.Drawing.Size(464, 296); + this.listResults.Sorting = System.Windows.Forms.SortOrder.Ascending; + this.listResults.TabIndex = 6; + this.listResults.UseCompatibleStateImageBehavior = false; + this.listResults.View = System.Windows.Forms.View.Details; + this.listResults.VirtualMode = true; + this.listResults.DoubleClick += new System.EventHandler(this.listResults_DoubleClick); + this.listResults.RetrieveVirtualItem += new System.Windows.Forms.RetrieveVirtualItemEventHandler(this.listResults_RetrieveVirtualItem); + // + // columnAddress + // + this.columnAddress.Text = "Address"; + this.columnAddress.Width = 100; + // + // columnOffset + // + this.columnOffset.Text = "+ Offset"; + this.columnOffset.Width = 100; + // + // columnLength + // + this.columnLength.Text = "Length"; + this.columnLength.Width = 100; + // + // columnString + // + this.columnString.Text = "String"; + this.columnString.Width = 160; + // + // labelText + // + this.labelText.AutoSize = true; + this.labelText.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.labelText.Location = new System.Drawing.Point(72, 11); + this.labelText.Name = "labelText"; + this.labelText.Size = new System.Drawing.Size(32, 13); + this.labelText.TabIndex = 2; + this.labelText.Text = "Text"; + // + // mainMenu + // + this.mainMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { + this.windowMenuItem}); + // + // windowMenuItem + // + this.windowMenuItem.Index = 0; + this.windowMenuItem.Text = "&Window"; + // + // buttonFilter + // + this.buttonFilter.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonFilter.Image = global::ProcessHacker.Properties.Resources.table_sort; + this.buttonFilter.Location = new System.Drawing.Point(392, 5); + this.buttonFilter.Name = "buttonFilter"; + this.buttonFilter.Size = new System.Drawing.Size(24, 24); + this.buttonFilter.TabIndex = 3; + this.toolTip.SetToolTip(this.buttonFilter, "Filter"); + this.buttonFilter.UseVisualStyleBackColor = true; + this.buttonFilter.Click += new System.EventHandler(this.buttonFilter_Click); + // + // buttonIntersect + // + this.buttonIntersect.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonIntersect.Image = global::ProcessHacker.Properties.Resources.table_relationship; + this.buttonIntersect.Location = new System.Drawing.Point(422, 5); + this.buttonIntersect.Name = "buttonIntersect"; + this.buttonIntersect.Size = new System.Drawing.Size(24, 24); + this.buttonIntersect.TabIndex = 4; + this.toolTip.SetToolTip(this.buttonIntersect, "Intersect"); + this.buttonIntersect.UseVisualStyleBackColor = true; + this.buttonIntersect.Click += new System.EventHandler(this.buttonIntersect_Click); + // + // buttonEdit + // + this.buttonEdit.Image = global::ProcessHacker.Properties.Resources.pencil; + this.buttonEdit.Location = new System.Drawing.Point(42, 5); + this.buttonEdit.Name = "buttonEdit"; + this.buttonEdit.Size = new System.Drawing.Size(24, 24); + this.buttonEdit.TabIndex = 1; + this.toolTip.SetToolTip(this.buttonEdit, "Edit Search..."); + this.buttonEdit.UseVisualStyleBackColor = true; + this.buttonEdit.Click += new System.EventHandler(this.buttonEdit_Click); + // + // buttonFind + // + this.buttonFind.Image = global::ProcessHacker.Properties.Resources.arrow_refresh; + this.buttonFind.Location = new System.Drawing.Point(12, 5); + this.buttonFind.Name = "buttonFind"; + this.buttonFind.Size = new System.Drawing.Size(24, 24); + this.buttonFind.TabIndex = 0; + this.toolTip.SetToolTip(this.buttonFind, "Search"); + this.buttonFind.UseVisualStyleBackColor = true; + this.buttonFind.Click += new System.EventHandler(this.buttonFind_Click); + // + // buttonSave + // + this.buttonSave.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonSave.Image = global::ProcessHacker.Properties.Resources.disk; + this.buttonSave.Location = new System.Drawing.Point(452, 5); + this.buttonSave.Name = "buttonSave"; + this.buttonSave.Size = new System.Drawing.Size(24, 24); + this.buttonSave.TabIndex = 5; + this.toolTip.SetToolTip(this.buttonSave, "Save..."); + this.buttonSave.UseVisualStyleBackColor = true; + this.buttonSave.Click += new System.EventHandler(this.buttonSave_Click); + // + // vistaMenu + // + this.vistaMenu.ContainerControl = this; + this.vistaMenu.DelaySetImageCalls = false; + // + // ResultsWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(488, 343); + this.Controls.Add(this.buttonFilter); + this.Controls.Add(this.buttonIntersect); + this.Controls.Add(this.buttonEdit); + this.Controls.Add(this.buttonFind); + this.Controls.Add(this.labelText); + this.Controls.Add(this.buttonSave); + this.Controls.Add(this.listResults); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Menu = this.mainMenu; + this.Name = "ResultsWindow"; + this.Text = "Results"; + this.Load += new System.EventHandler(this.ResultsWindow_Load); + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.ResultsWindow_FormClosing); + ((System.ComponentModel.ISupportInitialize)(this.vistaMenu)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.ListView listResults; + private System.Windows.Forms.ColumnHeader columnAddress; + private System.Windows.Forms.ColumnHeader columnOffset; + private System.Windows.Forms.ColumnHeader columnLength; + private System.Windows.Forms.ColumnHeader columnString; + private System.Windows.Forms.Button buttonSave; + private System.Windows.Forms.Label labelText; + private System.Windows.Forms.Button buttonFind; + private System.Windows.Forms.Button buttonEdit; + private System.Windows.Forms.Button buttonIntersect; + private wyDay.Controls.VistaMenu vistaMenu; + private System.Windows.Forms.MainMenu mainMenu; + private System.Windows.Forms.MenuItem windowMenuItem; + private System.Windows.Forms.Button buttonFilter; + private System.Windows.Forms.ToolTip toolTip; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/ResultsWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/ResultsWindow.cs new file mode 100644 index 000000000..3bfe83248 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ResultsWindow.cs @@ -0,0 +1,575 @@ +/* + * Process Hacker - + * search results window + * + * Copyright (C) 2008 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 . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Threading; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; +using ProcessHacker.UI; + +namespace ProcessHacker +{ + public partial class ResultsWindow : Form + { + private delegate bool Matcher(string s1, string s2); + + private int _pid; + private SearchOptions _so; + private Thread _searchThread; + private int _id; + + public string Id + { + get { return _pid + "-" + _id; } + } + + public ResultsWindow(int PID) + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + listResults.SetDoubleBuffered(true); + listResults.SetTheme("explorer"); + + Thread.CurrentThread.Priority = ThreadPriority.Highest; + + _pid = PID; + + _id = Program.ResultsIds.Pop(); + + Program.ResultsWindows.Add(Id, this); + + this.Text = Program.ProcessProvider.Dictionary[_pid].Name + " (PID " + _pid.ToString() + + ") - Results - " + _id; + + labelText.Text = "Ready."; + + _so = new SearchOptions(_pid, SearchType.String); + + listResults.AddShortcuts(this.listResults_RetrieveVirtualItem); + } + + private void ResultsWindow_Load(object sender, EventArgs e) + { + Program.UpdateWindowMenu(windowMenuItem, this); + + listResults.ContextMenu = listResults.GetCopyMenu(listResults_RetrieveVirtualItem); + + this.Size = Properties.Settings.Default.ResultsWindowSize; + + ColumnSettings.LoadSettings(Properties.Settings.Default.ResultsListViewColumns, listResults); + this.SetPhParent(false); + } + + private void ResultsWindow_FormClosing(object sender, FormClosingEventArgs e) + { + this.Visible = false; + + if (this.WindowState == FormWindowState.Normal) + Properties.Settings.Default.ResultsWindowSize = this.Size; + + Properties.Settings.Default.ResultsListViewColumns = ColumnSettings.SaveSettings(listResults); + } + + public ListView ResultsList + { + get { return listResults; } + } + + public List Results + { + get { return _so.Searcher.Results; } + } + + public SearchOptions SearchOptions + { + get { return _so; } + set { _so = value; } + } + + public string Label + { + get { return labelText.Text; } + set { labelText.Text = value; } + } + + public void EditSearch() + { + EditSearch(_so.Type); + } + + public DialogResult EditSearch(SearchType type) + { + return EditSearch(type, this.Location, this.Size); + } + + public DialogResult EditSearch(SearchType type, System.Drawing.Point location, System.Drawing.Size size) + { + DialogResult dr = DialogResult.Cancel; + + _so.Type = type; + + SearchWindow sw = new SearchWindow(_pid, _so); + + sw.StartPosition = FormStartPosition.Manual; + sw.Location = new System.Drawing.Point( + location.X + (size.Width - sw.Width) / 2, + location.Y + (size.Height - sw.Height) / 2); + + Rectangle newRect = Utils.FitRectangle(new Rectangle(sw.Location, sw.Size), Screen.GetWorkingArea(sw)); + + sw.Location = newRect.Location; + sw.Size = newRect.Size; + + if ((dr = sw.ShowDialog()) == DialogResult.OK) + { + _so = sw.SearchOptions; + } + + return dr; + } + + public void StartSearch() + { + if (_searchThread != null) + { + buttonFind.Enabled = false; + _searchThread.Abort(); + _searchThread = null; + + Searcher_SearchFinished(); + } + else + { + this.Cursor = Cursors.WaitCursor; + + buttonFind.Image = global::ProcessHacker.Properties.Resources.cross; + toolTip.SetToolTip(buttonFind, "Cancel"); + buttonEdit.Enabled = false; + buttonFilter.Enabled = false; + buttonIntersect.Enabled = false; + buttonSave.Enabled = false; + + listResults.Items.Clear(); + labelText.Text = "Searching..."; + + // refresh + _so.Type = _so.Type; + _so.Searcher.SearchFinished += new SearchFinished(Searcher_SearchFinished); + _so.Searcher.SearchProgressChanged += new SearchProgressChanged(Searcher_SearchProgressChanged); + _so.Searcher.SearchError += new SearchError(SearchError); + + _searchThread = new Thread(new ThreadStart(_so.Searcher.Search)); + + _searchThread.Start(); + } + } + + private void SearchError(string message) + { + this.Invoke(new MethodInvoker(delegate + { + PhUtils.ShowError("Unable to search memory: " + message); + _searchThread = null; + Searcher_SearchFinished(); + })); + } + + private void Searcher_SearchProgressChanged(string progress) + { + this.BeginInvoke(new MethodInvoker(delegate + { + labelText.Text = progress; + })); + } + + private void Searcher_SearchFinished() + { + this.Invoke(new MethodInvoker(delegate + { + listResults.VirtualListSize = _so.Searcher.Results.Count; + + labelText.Text = String.Format("{0} results.", listResults.Items.Count); + + buttonFind.Image = global::ProcessHacker.Properties.Resources.arrow_refresh; + toolTip.SetToolTip(buttonFind, "Search"); + this.Cursor = Cursors.Default; + buttonEdit.Enabled = true; + buttonFilter.Enabled = true; + buttonIntersect.Enabled = true; + buttonSave.Enabled = true; + buttonFind.Enabled = true; + })); + + _searchThread = null; + } + + private void listResults_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e) + { + try + { + if (e.ItemIndex < _so.Searcher.Results.Count) + e.Item = new ListViewItem(_so.Searcher.Results[e.ItemIndex]); + else + e.Item = new ListViewItem(new string[4]); + } + catch + { + e.Item = new ListViewItem(new string[4]); + } + } + + private void buttonSave_Click(object sender, EventArgs e) + { + string filename = ""; + DialogResult dr = DialogResult.Cancel; + ResultsWindow rw = this; + + SaveFileDialog sfd = new SaveFileDialog(); + + sfd.Filter = "Text Document (*.txt)|*.txt|All Files (*.*)|*.*"; + dr = sfd.ShowDialog(); + filename = sfd.FileName; + + if (dr == DialogResult.OK) + { + System.IO.StreamWriter sw = new System.IO.StreamWriter(filename); + + foreach (string[] s in _so.Searcher.Results) + { + sw.Write("0x{0:x} ({1}){2}\r\n", Int32.Parse(s[0].Replace("0x", ""), + System.Globalization.NumberStyles.HexNumber) + Int32.Parse(s[1].Replace("0x", ""), + System.Globalization.NumberStyles.HexNumber), Int32.Parse(s[2]), + s[3] != "" ? (": " + s[3]) : ""); + } + + sw.Close(); + } + } + + private void buttonFind_Click(object sender, EventArgs e) + { + StartSearch(); + } + + private void buttonEdit_Click(object sender, EventArgs e) + { + EditSearch(); + } + + private void listResults_DoubleClick(object sender, EventArgs e) + { + this.Cursor = Cursors.WaitCursor; + + try + { + long s_a = (long)BaseConverter.ToNumberParse(_so.Searcher.Results[listResults.SelectedIndices[0]][0]) + + (long)BaseConverter.ToNumberParse(_so.Searcher.Results[listResults.SelectedIndices[0]][1]); + + var lastInfo = new MemoryBasicInformation(); + ProcessHandle phandle; + + try + { + phandle = new ProcessHandle(_pid, ProcessAccess.QueryInformation); + } + catch + { + this.Cursor = Cursors.Default; + return; + } + + phandle.EnumMemory((info) => + { + if (info.BaseAddress.ToInt64() > s_a) + { + long selectlength = + (long)BaseConverter.ToNumberParse(_so.Searcher.Results[listResults.SelectedIndices[0]][2]); + + MemoryEditor ed = Program.GetMemoryEditor(_pid, + lastInfo.BaseAddress, + lastInfo.RegionSize.ToInt64(), + new Program.MemoryEditorInvokeAction(delegate(MemoryEditor f) + { + try + { + f.ReadOnly = false; + f.Activate(); + f.Select(s_a - lastInfo.BaseAddress.ToInt64(), selectlength); + } + catch + { } + })); + + return false; + } + + lastInfo = info; + + return true; + }); + } + catch { } + + this.Cursor = Cursors.Default; + } + + private void intersectItemClicked(object sender, EventArgs e) + { + List newitems = new List(); + List windowitems = new List(); + string id = ((MenuItem)sender).Tag.ToString(); + ResultsWindow window = Program.ResultsWindows[id]; + + this.Cursor = Cursors.WaitCursor; + + foreach (string[] s in window.Results) + { + windowitems.Add((long)BaseConverter.ToNumberParse(s[0]) + + (long)BaseConverter.ToNumberParse(s[1])); + } + + ResultsWindow rw = Program.GetResultsWindow(_pid, new Program.ResultsWindowInvokeAction(delegate(ResultsWindow f) + { + f.ResultsList.VirtualListSize = 0; + + foreach (string[] s in Results) + { + long location = (long)BaseConverter.ToNumberParse(s[0]) + + (long)BaseConverter.ToNumberParse(s[1]); + + if (windowitems.Contains(location)) + { + f.Results.Add(s); + f.ResultsList.VirtualListSize++; + } + } + + f.Label = "Intersection: " + f.Results.Count + " results."; + + f.Show(); + })); + + this.Cursor = Cursors.Default; + } + + private void buttonIntersect_Click(object sender, EventArgs e) + { + // this is a bit complex because the list needs to be sorted as well + ContextMenu menu = new ContextMenu(); + Dictionary TextToId = new Dictionary(); + List Texts = new List(); + + foreach (string s in Program.ResultsWindows.Keys) + { + ResultsWindow window = Program.ResultsWindows[s]; + + Texts.Add(window.Text); + TextToId.Add(window.Text, s); + } + + Texts.Sort(); + + foreach (string s in Texts) + { + MenuItem item = new MenuItem(s); + + item.Tag = TextToId[s]; + item.Click += new EventHandler(intersectItemClicked); + menu.MenuItems.Add(item); + + vistaMenu.SetImage(item, global::ProcessHacker.Properties.Resources.table); + } + + menu.Show(buttonIntersect, new System.Drawing.Point(buttonIntersect.Size.Width, 0)); + } + + private void buttonFilter_Click(object sender, EventArgs e) + { + ContextMenu menu = new ContextMenu(); + + foreach (ColumnHeader ch in listResults.Columns) + { + MenuItem columnMenu = new MenuItem(ch.Text); + MenuItem item; + + columnMenu.Tag = ch.Index; + + item = new MenuItem("Contains...", new EventHandler(filterMenuItem_Clicked)); + item.Tag = new Matcher(delegate(string s1, string s2) + { + return s1.Contains(s2); + }); + columnMenu.MenuItems.Add(item); + + item = new MenuItem("Contains (case-insensitive)...", new EventHandler(filterMenuItem_Clicked)); + item.Tag = new Matcher(delegate(string s1, string s2) + { + return s1.ToLower().Contains(s2.ToLower()); + }); + columnMenu.MenuItems.Add(item); + + item = new MenuItem("Regex...", new EventHandler(filterMenuItem_Clicked)); + item.Tag = new Matcher(delegate(string s1, string s2) + { + try + { + System.Text.RegularExpressions.Regex r = new System.Text.RegularExpressions.Regex(s2); + + return r.IsMatch(s1); + } + catch + { + return false; + } + }); + columnMenu.MenuItems.Add(item); + + item = new MenuItem("Regex (case-insensitive)...", new EventHandler(filterMenuItem_Clicked)); + item.Tag = new Matcher(delegate(string s1, string s2) + { + try + { + System.Text.RegularExpressions.Regex r = + new System.Text.RegularExpressions.Regex(s2, System.Text.RegularExpressions.RegexOptions.IgnoreCase); + + return r.IsMatch(s1); + } + catch + { + return false; + } + }); + columnMenu.MenuItems.Add(item); + + columnMenu.MenuItems.Add(new MenuItem("-")); + + item = new MenuItem("Numerical relation...", new EventHandler(filterMenuItem_Clicked)); + item.Tag = new Matcher(delegate(string s1, string s2) + { + if (s2.Contains("!=")) + { + decimal n1 = BaseConverter.ToNumberParse(s1); + decimal n2 = BaseConverter.ToNumberParse(s2.Split(new string[] { "!=" }, StringSplitOptions.None)[1]); + + return n1 != n2; + } + else if (s2.Contains("<=")) + { + decimal n1 = BaseConverter.ToNumberParse(s1); + decimal n2 = BaseConverter.ToNumberParse(s2.Split(new string[] { "<=" }, StringSplitOptions.None)[1]); + + return n1 <= n2; + } + else if (s2.Contains(">=")) + { + decimal n1 = BaseConverter.ToNumberParse(s1); + decimal n2 = BaseConverter.ToNumberParse(s2.Split(new string[] { ">=" }, StringSplitOptions.None)[1]); + + return n1 >= n2; + } + else if (s2.Contains("<")) + { + decimal n1 = BaseConverter.ToNumberParse(s1); + decimal n2 = BaseConverter.ToNumberParse(s2.Split(new string[] { "<" }, StringSplitOptions.None)[1]); + + return n1 < n2; + } + else if (s2.Contains(">")) + { + decimal n1 = BaseConverter.ToNumberParse(s1); + decimal n2 = BaseConverter.ToNumberParse(s2.Split(new string[] { ">" }, StringSplitOptions.None)[1]); + + return n1 > n2; + } + else if (s2.Contains("=")) + { + decimal n1 = BaseConverter.ToNumberParse(s1); + decimal n2 = BaseConverter.ToNumberParse(s2.Split(new string[] { "=" }, StringSplitOptions.None)[1]); + + return n1 == n2; + } + else + { + return false; + } + }); + columnMenu.MenuItems.Add(item); + + menu.MenuItems.Add(columnMenu); + } + + menu.Show(buttonFilter, new System.Drawing.Point(buttonFilter.Size.Width, 0)); + } + + private void filterMenuItem_Clicked(object sender, EventArgs e) + { + MenuItem item = (MenuItem)sender; + int index = (int)item.Parent.Tag; + + try + { + Filter(index, (Matcher)item.Tag); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to filter the search results", ex); + } + } + + private void Filter(int index, Matcher m) + { + PromptBox prompt = new PromptBox(); + + if (prompt.ShowDialog() == DialogResult.OK) + { + this.Cursor = Cursors.WaitCursor; + + ResultsWindow rw = Program.GetResultsWindow(_pid, new Program.ResultsWindowInvokeAction(delegate(ResultsWindow f) + { + f.ResultsList.VirtualListSize = 0; + + foreach (string[] s in Results) + { + if (m(s[index], prompt.Value)) + { + f.Results.Add(s); + f.ResultsList.VirtualListSize++; + } + } + + f.Label = "Filter: " + f.Results.Count + " results."; + + f.Show(); + })); + + this.Cursor = Cursors.Default; + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/ResultsWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/ResultsWindow.resx new file mode 100644 index 000000000..694764c12 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ResultsWindow.resx @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 125, 17 + + + 235, 17 + + + 17, 17 + + + + + AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAANadccTTmG300ZVn/86RYv/LjV3/yYla/8eGVf/Cg1H/woNR/8KDUf/Cg1H/woNR/8KD + Uf+6dkGwAAAAAAAAAADXoHT/+PLt//fw6v/27eb/9Ori//Pn3v/x5Nv/8OLY//Di2P/w4tj/8OLY//Di + 2P/w4tj/xIlc/QAAAAAAAAAA2aN5//nz7v/r0r3//////+vTvv/////////////////qx6z///////// + ////////8OLY/8WLXv8AAAAAAAAAAN2nff/58+//69C5/+vQuv/r0Lr/69C6/+vQuv/r0bz/6s20/+rN + tP/qzbT/6s20//Di2P/FiVv/AAAAAAAAAADfqYH/+fPv/+rOtv//////69C6/////////////////+rP + uf/79vL////////////w4tj/yIxe/wAAAAAAAAAA4a2G//r08P/qy7H/6syy/+rMsv/qzLL/6syy/+rO + tv/ox6v/6Mer/+jIr//oyK3/8OLY/8OFU/8AAAAAAAAAAOOwi//69vH/6smt///////qya////////// + ////////6Mer//////////////////Hl2//FhVT/AAAAAAAAAADls47/+vby/+nFqf/pxav/6ser/+nH + rP/pya3/6cmv/+jHq//pya//6Miv/+jMtP/y597/yIlY/wAAAAAAAAAA57aT//v39P/pwqX//////+jD + qP/////////////////ox6v/////////////////9/Hr/8uOXv8AAAAAAAAAAOm5l//79/T/6cKl/+nC + pf/pwqX/6cKl/+nCpf/pwqX/6cKl/+nCpf/pwqX/6cKl//v39P/OkmP/AAAAAAAAAADrvJr/+/f0//// + ///////////////////////////////////////////////////79/T/0ZZp/wAAAAAAAAAA7L6d//v3 + 9P+b1aT/l9Og/5PQnP+Pzpf/isuS/4bJjf+BxYj/fcKD/3nAf/91vXv/+/f0/9Sabv8AAAAAAAAAAO7A + oOv79/T/+/f0//v39P/79/T/+/f0//v39P/79/T/+/f0//v39P/79/T/+/f0//v39P/Xn3P4AAAAAAAA + AADvwaJ+78Ch4+2/nv/rvZz/67uZ/+m5lf/ntpL/5rSP/+Sxi//irof/4KuD/92of//cpHz/2qJ5ygAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA//+sQYABrEGAAaxBgAGsQYABrEGAAaxBgAGsQYABrEGAAaxBgAGsQYABrEGAAaxBgAGsQYAB + rEGAAaxB//+sQQ== + + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/RunWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/RunWindow.Designer.cs new file mode 100644 index 000000000..c0363a7f3 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/RunWindow.Designer.cs @@ -0,0 +1,257 @@ +namespace ProcessHacker +{ + partial class RunWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.textCmdLine = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.comboUsername = new System.Windows.Forms.ComboBox(); + this.label3 = new System.Windows.Forms.Label(); + this.textSessionID = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.textPassword = new System.Windows.Forms.TextBox(); + this.buttonOK = new System.Windows.Forms.Button(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.buttonBrowse = new System.Windows.Forms.Button(); + this.label5 = new System.Windows.Forms.Label(); + this.buttonSessions = new System.Windows.Forms.Button(); + this.label6 = new System.Windows.Forms.Label(); + this.comboType = new System.Windows.Forms.ComboBox(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 49); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(49, 13); + this.label1.TabIndex = 10; + this.label1.Text = "Program:"; + // + // textCmdLine + // + this.textCmdLine.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textCmdLine.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.SuggestAppend; + this.textCmdLine.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.AllSystemSources; + this.textCmdLine.Location = new System.Drawing.Point(79, 46); + this.textCmdLine.Name = "textCmdLine"; + this.textCmdLine.Size = new System.Drawing.Size(230, 20); + this.textCmdLine.TabIndex = 0; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(12, 75); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(58, 13); + this.label2.TabIndex = 11; + this.label2.Text = "Username:"; + // + // comboUsername + // + this.comboUsername.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.comboUsername.FormattingEnabled = true; + this.comboUsername.Location = new System.Drawing.Point(79, 72); + this.comboUsername.Name = "comboUsername"; + this.comboUsername.Size = new System.Drawing.Size(154, 21); + this.comboUsername.TabIndex = 2; + this.comboUsername.TextChanged += new System.EventHandler(this.comboUsername_TextChanged); + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(12, 128); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(61, 13); + this.label3.TabIndex = 14; + this.label3.Text = "Session ID:"; + // + // textSessionID + // + this.textSessionID.Location = new System.Drawing.Point(79, 125); + this.textSessionID.Name = "textSessionID"; + this.textSessionID.Size = new System.Drawing.Size(100, 20); + this.textSessionID.TabIndex = 5; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(12, 102); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(56, 13); + this.label4.TabIndex = 13; + this.label4.Text = "Password:"; + // + // textPassword + // + this.textPassword.Location = new System.Drawing.Point(79, 99); + this.textPassword.Name = "textPassword"; + this.textPassword.Size = new System.Drawing.Size(154, 20); + this.textPassword.TabIndex = 4; + this.textPassword.UseSystemPasswordChar = true; + // + // buttonOK + // + this.buttonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonOK.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonOK.Location = new System.Drawing.Point(234, 155); + this.buttonOK.Name = "buttonOK"; + this.buttonOK.Size = new System.Drawing.Size(75, 23); + this.buttonOK.TabIndex = 7; + this.buttonOK.Text = "&OK"; + this.buttonOK.UseVisualStyleBackColor = true; + this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click); + // + // buttonCancel + // + this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonCancel.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonCancel.Location = new System.Drawing.Point(315, 155); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.TabIndex = 8; + this.buttonCancel.Text = "&Cancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click); + // + // buttonBrowse + // + this.buttonBrowse.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.buttonBrowse.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonBrowse.Location = new System.Drawing.Point(315, 44); + this.buttonBrowse.Name = "buttonBrowse"; + this.buttonBrowse.Size = new System.Drawing.Size(75, 23); + this.buttonBrowse.TabIndex = 1; + this.buttonBrowse.Text = "&Browse..."; + this.buttonBrowse.UseVisualStyleBackColor = true; + this.buttonBrowse.Click += new System.EventHandler(this.buttonBrowse_Click); + // + // label5 + // + this.label5.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.label5.Location = new System.Drawing.Point(12, 9); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(378, 30); + this.label5.TabIndex = 9; + this.label5.Text = "Enter the command to start as the specified user. Note that the program may take " + + "a while to start as Windows loads the user\'s profile."; + // + // buttonSessions + // + this.buttonSessions.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonSessions.Location = new System.Drawing.Point(185, 122); + this.buttonSessions.Name = "buttonSessions"; + this.buttonSessions.Size = new System.Drawing.Size(24, 24); + this.buttonSessions.TabIndex = 6; + this.buttonSessions.Text = "..."; + this.buttonSessions.UseVisualStyleBackColor = true; + this.buttonSessions.Click += new System.EventHandler(this.buttonSessions_Click); + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(239, 75); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(34, 13); + this.label6.TabIndex = 12; + this.label6.Text = "Type:"; + // + // comboType + // + this.comboType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboType.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.comboType.FormattingEnabled = true; + this.comboType.Items.AddRange(new object[] { + "Batch", + "Interactive", + "Network", + "NetworkCleartext", + "NewCredentials", + "Service", + "Unlock"}); + this.comboType.Location = new System.Drawing.Point(279, 72); + this.comboType.Name = "comboType"; + this.comboType.Size = new System.Drawing.Size(111, 21); + this.comboType.TabIndex = 3; + // + // RunWindow + // + this.AcceptButton = this.buttonOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(402, 190); + this.Controls.Add(this.comboType); + this.Controls.Add(this.label6); + this.Controls.Add(this.buttonSessions); + this.Controls.Add(this.label5); + this.Controls.Add(this.buttonBrowse); + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.buttonOK); + this.Controls.Add(this.textPassword); + this.Controls.Add(this.label4); + this.Controls.Add(this.textSessionID); + this.Controls.Add(this.label3); + this.Controls.Add(this.comboUsername); + this.Controls.Add(this.label2); + this.Controls.Add(this.textCmdLine); + this.Controls.Add(this.label1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "RunWindow"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Run As..."; + this.Load += new System.EventHandler(this.RunWindow_Load); + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.RunWindow_FormClosing); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox textCmdLine; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.ComboBox comboUsername; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.TextBox textSessionID; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.TextBox textPassword; + private System.Windows.Forms.Button buttonOK; + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.Button buttonBrowse; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.Button buttonSessions; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.ComboBox comboType; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/RunWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/RunWindow.cs new file mode 100644 index 000000000..b99561ec2 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/RunWindow.cs @@ -0,0 +1,287 @@ +/* + * Process Hacker - + * run as window + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker +{ + public partial class RunWindow : Form + { + private int _pid = -1; + + public RunWindow() + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + textSessionID.Text = Program.CurrentSessionId.ToString(); + comboType.SelectedItem = "Interactive"; + + if (Program.ElevationType == TokenElevationType.Limited) + buttonOK.SetShieldIcon(true); + + List users = new List(); + + users.Add("NT AUTHORITY\\SYSTEM"); + users.Add("NT AUTHORITY\\LOCAL SERVICE"); + users.Add("NT AUTHORITY\\NETWORK SERVICE"); + + try + { + using (var phandle = new LsaPolicyHandle(LsaPolicyAccess.ViewLocalInformation)) + { + foreach (var sid in phandle.GetAccounts()) + if (sid.NameUse == SidNameUse.User) + users.Add(sid.GetFullName(true)); + } + } + catch + { } + + users.Sort(); + + comboUsername.Items.AddRange(users.ToArray()); + } + + public void UsePID(int PID) + { + _pid = PID; + + try + { + comboUsername.Text = Program.ProcessProvider.Dictionary[PID].Username; + } + catch + { + _pid = -1; + return; + } + + comboUsername.Enabled = false; + comboType.Enabled = false; + textPassword.Enabled = false; + } + + private void RunWindow_Load(object sender, EventArgs e) + { + if (_pid == -1) + { + comboUsername.Text = Properties.Settings.Default.RunAsUsername; + } + + textCmdLine.Text = Properties.Settings.Default.RunAsCommand; + textCmdLine.Select(); + } + + private void RunWindow_FormClosing(object sender, FormClosingEventArgs e) + { + Properties.Settings.Default.RunAsCommand = textCmdLine.Text; + Properties.Settings.Default.RunAsUsername = comboUsername.Text; + } + + private void buttonBrowse_Click(object sender, EventArgs e) + { + OpenFileDialog ofd = new OpenFileDialog(); + + try + { + ofd.FileName = textCmdLine.Text; + } + catch + { } + + ofd.CheckFileExists = true; + ofd.CheckPathExists = true; + ofd.Multiselect = false; + + if (ofd.ShowDialog() == DialogResult.OK) + textCmdLine.Text = ofd.FileName; + } + + private void buttonCancel_Click(object sender, EventArgs e) + { + this.Close(); + } + + private void buttonOK_Click(object sender, EventArgs e) + { + this.Cursor = Cursors.WaitCursor; + Application.DoEvents(); + + try + { + System.Diagnostics.ProcessStartInfo info = new System.Diagnostics.ProcessStartInfo(); + + info.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; + info.FileName = Application.StartupPath + "\\Assistant.exe"; + info.Arguments = "-w"; + + System.Diagnostics.Process.Start(info); + } + catch + { } + + try + { + string binPath; + string mailslotName; + bool omitUserAndType = false; + + if (_pid != -1) + omitUserAndType = true; + + mailslotName = "ProcessHackerAssistant" + Utils.CreateRandomString(8); + binPath = "\"" + Application.StartupPath + "\\Assistant.exe\" " + + (omitUserAndType ? "" : + ("-u \"" + comboUsername.Text + "\" -t " + comboType.SelectedItem.ToString().ToLower() + " ")) + + (_pid != -1 ? ("-P " + _pid.ToString() + " ") : "") + "-p \"" + + textPassword.Text.Replace("\"", "\\\"") + "\" -s " + textSessionID.Text + " -c \"" + + textCmdLine.Text.Replace("\"", "\\\"") + "\" -E " + mailslotName; + + if (Program.ElevationType == TokenElevationType.Limited) + { + var result = Program.StartProcessHackerAdminWait( + "-e -type processhacker -action runas -obj \"" + binPath.Replace("\"", "\\\"") + + "\" -mailslot " + mailslotName + + " -hwnd " + this.Handle.ToString(), this.Handle, 5000); + + if (result == WaitResult.Object0) + this.Close(); + } + else + { + string serviceName = Utils.CreateRandomString(8); + + using (var manager = new ServiceManagerHandle(ScManagerAccess.CreateService)) + { + using (var service = manager.CreateService( + serviceName, + serviceName + " (Process Hacker Assistant)", + ServiceType.Win32OwnProcess, + ServiceStartType.DemandStart, + ServiceErrorControl.Ignore, + binPath, + "", + "LocalSystem", + null)) + { + // Create a mailslot so we can receive the error code for Assistant. + using (var mhandle = MailslotHandle.Create( + FileAccess.GenericRead, @"\Device\Mailslot\" + mailslotName, 0, 5000) + ) + { + try { service.Start(); } + catch { } + service.Delete(); + + Win32Error errorCode = (Win32Error)mhandle.Read(4).ToInt32(); + + if (errorCode != Win32Error.Success) + throw new WindowsException(errorCode); + } + } + } + + this.Close(); + } + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to start the program", ex); + } + + this.Cursor = Cursors.Default; + } + + private bool isServiceUser() + { + if (comboUsername.Text.ToUpper() == "NT AUTHORITY\\SYSTEM" || + comboUsername.Text.ToUpper() == "NT AUTHORITY\\LOCAL SERVICE" || + comboUsername.Text.ToUpper() == "NT AUTHORITY\\NETWORK SERVICE") + return true; + else + return false; + } + + private void comboUsername_TextChanged(object sender, EventArgs e) + { + if (_pid == -1) + { + if (isServiceUser()) + { + textPassword.Enabled = false; + comboType.SelectedItem = "Service"; + + // hack for XP + if (comboUsername.Text.ToUpper() == "NT AUTHORITY\\SYSTEM" && + OSVersion.IsBelowOrEqual(WindowsVersion.XP)) + comboType.SelectedItem = "NewCredentials"; + } + else + { + textPassword.Enabled = true; + comboType.SelectedItem = "Interactive"; + } + } + } + + private void buttonSessions_Click(object sender, EventArgs e) + { + ContextMenu menu = new ContextMenu(); + + foreach (var session in TerminalServerHandle.GetCurrent().GetSessions()) + { + MenuItem item = new MenuItem(); + + string userName = session.DomainName + "\\" + session.UserName; + string displayName = session.SessionId.ToString(); + + if (!string.IsNullOrEmpty(session.Name)) + displayName += ": " + session.Name + (userName != "\\" ? (" (" + userName + ")") : ""); + else if (userName != "\\") + displayName += ": " + userName; + + item.Text = displayName; + item.Tag = session.SessionId; + item.Click += new EventHandler(item_Click); + + menu.MenuItems.Add(item); + } + + menu.Show(buttonSessions, new Point(buttonSessions.Width, 0)); + } + + private void item_Click(object sender, EventArgs e) + { + textSessionID.Text = ((MenuItem)sender).Tag.ToString(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/RunWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/RunWindow.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/RunWindow.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/ScratchpadWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/ScratchpadWindow.Designer.cs new file mode 100644 index 000000000..3cec867b0 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ScratchpadWindow.Designer.cs @@ -0,0 +1,97 @@ +namespace ProcessHacker +{ + partial class ScratchpadWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ScratchpadWindow)); + this.textText = new System.Windows.Forms.TextBox(); + this.buttonCopy = new System.Windows.Forms.Button(); + this.buttonSave = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // textText + // + this.textText.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textText.Location = new System.Drawing.Point(12, 12); + this.textText.Multiline = true; + this.textText.Name = "textText"; + this.textText.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.textText.Size = new System.Drawing.Size(530, 305); + this.textText.TabIndex = 0; + // + // buttonCopy + // + this.buttonCopy.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonCopy.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonCopy.Location = new System.Drawing.Point(467, 323); + this.buttonCopy.Name = "buttonCopy"; + this.buttonCopy.Size = new System.Drawing.Size(75, 23); + this.buttonCopy.TabIndex = 2; + this.buttonCopy.Text = "Copy"; + this.buttonCopy.UseVisualStyleBackColor = true; + this.buttonCopy.Click += new System.EventHandler(this.buttonCopy_Click); + // + // buttonSave + // + this.buttonSave.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonSave.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonSave.Location = new System.Drawing.Point(386, 323); + this.buttonSave.Name = "buttonSave"; + this.buttonSave.Size = new System.Drawing.Size(75, 23); + this.buttonSave.TabIndex = 1; + this.buttonSave.Text = "Save..."; + this.buttonSave.UseVisualStyleBackColor = true; + this.buttonSave.Click += new System.EventHandler(this.buttonSave_Click); + // + // ScratchpadWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(554, 358); + this.Controls.Add(this.buttonSave); + this.Controls.Add(this.buttonCopy); + this.Controls.Add(this.textText); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.KeyPreview = true; + this.Name = "ScratchpadWindow"; + this.Text = "Scratchpad"; + this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.ScratchpadWindow_KeyDown); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TextBox textText; + private System.Windows.Forms.Button buttonCopy; + private System.Windows.Forms.Button buttonSave; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/ScratchpadWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/ScratchpadWindow.cs new file mode 100644 index 000000000..572044eeb --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ScratchpadWindow.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Text; +using System.Windows.Forms; + +namespace ProcessHacker +{ + public partial class ScratchpadWindow : Form + { + public static void Create(string text) + { + // Create the window on the main thread. + Program.HackerWindow.BeginInvoke(new MethodInvoker(delegate + { + (new ScratchpadWindow(text)).Show(); + })); + } + + public ScratchpadWindow() + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + } + + public ScratchpadWindow(string text) + { + InitializeComponent(); + + textText.Text = text; + textText.Select(0, 0); + } + + private void buttonCopy_Click(object sender, EventArgs e) + { + if (textText.Text.Length == 0) + return; + + if (textText.SelectionLength == 0) + { + Clipboard.SetText(textText.Text); + textText.Select(); + textText.SelectAll(); + } + else + { + Clipboard.SetText(textText.SelectedText); + } + } + + private void buttonSave_Click(object sender, EventArgs e) + { + SaveFileDialog sfd = new SaveFileDialog(); + + sfd.FileName = "scratchpad.txt"; + sfd.Filter = "Text Files (*.txt)|*.txt|All Files (*.*)|*.*"; + + if (sfd.ShowDialog() == DialogResult.OK) + System.IO.File.WriteAllText(sfd.FileName, textText.Text); + } + + private void ScratchpadWindow_KeyDown(object sender, KeyEventArgs e) + { + if (e.Control && e.KeyCode == Keys.A) + { + textText.SelectAll(); + e.Handled = true; + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/ScratchpadWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/ScratchpadWindow.resx new file mode 100644 index 000000000..b1bcc39c8 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ScratchpadWindow.resx @@ -0,0 +1,909 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAA8AMDAQAAEABABoBgAA9gAAACAgEAABAAQA6AIAAF4HAAAQEBAAAQAEACgBAABGCgAAAAAAAAEA + CABqDQAAbgsAADAwAAABAAgAqA4AANgYAAAgIAAAAQAIAKgIAACAJwAAEBAAAAEACABoBQAAKDAAAAAA + AAABABgAOQ0AAJA1AAAwMAAAAQAYAKgcAADJQgAAICAAAAEAGACoDAAAcV8AABAQAAABABgAaAMAABls + AAAAAAAAAQAgAHANAACBbwAAMDAAAAEAIACoJQAA8XwAACAgAAABACAAqBAAAJmiAAAQEAAAAQAgAGgE + AABBswAAKAAAADAAAABgAAAAAQAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAIAAAACA + gACAAAAAgACAAICAAACAgIAAAAD/AAD/AAAA//8A/wAAAP8A/wD//wAAwMDAAP///wDwAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFRGVGVlZGVkdGVlAAAA + AAAAAAAAAAAAAFZGtkZLa2Rka0a0AAAAAAAAAAAAAAAAAGtka2tka2trZkZHAAAAAAAAAAAAAAAAAGRr + a2tmtmtra2tkAAAAAAAAAAAAAAAAAFZrZma2a2a2a2tnAAAAAAAAAAAAAAAAAEa2a2tra2tra2ZkAAAA + AAAAAAAAAAAAAGa2trZra2a2a2tlAAAAAAAAAAAAAAAAAHa2bbZrZttmtmtmAAAAAAABODE4ExgxAFa2 + tra2tra2tmtlAAAAAAABgxg4E4OBAEZrZrZr1rZr29tmAAAAAAADgTETgxMTAHvWvb22tmvba2tlAAAA + AAADE4ODgxg4AGRr272729tr29vUAAAAAAAIE4MTgTgxAF2729vb22bb29tnAAAAAAABODg4ODgxAEbb + 29vb29u2vb22AAAAAAADg4ODg4ODAEZmZmZmZm1mZmZlAAAAAAABODg4ODg4AHR2VlZWR1ZHRlZWAAAA + AAAIODg4ODg4AAAAAAAAAAAAAAAAAAAAAAADg4ODg4ODM4ODiDiDg4ODg4OIOIODg44BODiDioOBiuiu + p6euinqK6K6np66o6j4BioODg4ODOurqjq6nrq6urqeup3qK6h4Dg4OKg4ODjoruqK6o6o6o6uqOqurq + 6o4Bg4ODiDg4Oq6orqeup66np6iuqOqOqD4Dg4qIOKg4h6eup66Kenp6eurqeup66j4Biog4qDiDPqen + p66urq6np66K6np6eo4DiKg4OKiBiq6nrqiuqKeup6p6enp66j4Bg4OIODgzOup66nrqeup6eurqenrq + eo4BMRMTgTGBh66orqenp6rorop66np66j4AAAAAAAAAOup66np66nrqrqrqenrqeo4AAAAAAAAAinp6 + eup6enrqeurqeup66j4AAAAAAAAAPqrq6qeq6up6euqK6q6uqh4AAAAAAAAAiup6eup6eqeup66urqiu + 6j4AAAAAAAAAOup66np66n6qeqeqenrqqo4AAAAAAAAAGq6q6q6q6qrq6urqrqrq6j4AAAAAAAAAPq6u + qurq6urq6uqurq6q6o4AAAAAAAAAiq6q6uqq6q6qququqq6q6j4AAAAAAAAAOuqurqrq6uqurq6urq6u + ro4AAAAAAAAAiurqqurq6q6urqrqrqquqj4AAAAAAAAAPq6q6urqququqq6q6q6uro4AAAAAAAAAOqrq + 6qqurq6q6urqrq6q6j4AAAAAAAAAOurqqurqrqququqq6uquqj4AAAAAAAAAiuqurqrqrq6q6q6uqq6q + 6o4AAAAAAAAAOuququrqrqrq6q6q6uquqn4AAAAAAAAAeq6uququrqrqrq6q6q6uqo4AAAAAAAAAOq6q + rqquqq6qrqquqq6qrj4AAAAAAAAAgzODM4MzgzODM4MzgzODMT8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AA9///////4AAP///////wAA//8AAAP/AAD//wAAA/8AAP//AAAD/wAA//8AAAP/AAD//wAAA/8AAP// + AAAD/wAA//8AAAP/AAD//wAAA/8AAIADAAAD/wAAgAMAAAP/AACAAwAAA/8AAIADAAAD/wAAgAMAAAP/ + AACAAwAAA/8AAIADAAAD/wAAgAMAAAP/AACAA/////8AAIAAAAAAAAAAgAAAAAAAAACAAAAAAAAAAIAA + AAAAAAAAgAAAAAAAAACAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAACAAAAAAAAAAIAAAAAAAAAA//wAAAAA + AAD//AAAAAAAAP/8AAAAAAAA//wAAAAAAAD//AAAAAAAAP/8AAAAAAAA//wAAAAAAAD//AAAAAAAAP/8 + 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 + Hx8fHx8fHx8fGwAAARQXFxcXFxcXFxcXFxcXFxcXFxcXAQAAAAAAAAAAAAAAGyAhISEhISEhISEgGwAA + ARYZGRkZGRkZGRkZGRkZGRkZGRkZAQAAAAAAAAAAAAAAGyEhISEhISEhISEhGwAAARgaGhoaGhoaGhoa + GhoaGhoaGhoaAQAAAAAAAAAAAAAAGyIiIyIjIyIjIyMiGwAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAA + AAAAAAAAAAAAGyUlJSUlJSUlJSUlGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGyYm + JiYmJiYmJiYmGyQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJEIAGyYnJygnKCcoJycnHCQv + Ly8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vJEEAGygpKSkpKSkpKSkpHCQwLzAwMDAwMDAwMDAw + MDAwMDAwMDAwMDAwMDAwMDAvJEEAGykrKiorKisqKyoqHCQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw + MDAwMDAwJEEAGyosLCwsLCwsLCwsGyQwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwJEEAGywt + LS0tLS0tLS0tHCQxMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExJEEAGy0uLi4uLi4uLi4uHCQy + MjIxMjEyMTIxMjEyMTIxMjEyMTIxMjEyMTIxMjEyJEEAGy4uLi4uLi4uLi4uGyQyMjIyMjIyMjIyMjIy + MjIyMjIyMjIyMjIyMjIyMjIyJEEAGyorKysrKysrKysrGyQzMzQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0 + NDQ0NDQzJEEAGxsbGxsbGxsbGxsbHCQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDU0JEEAAAAA + AAAAAAAAAAAAACQ1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1JEEAAAAAAAAAAAAAAAAAACQ1 + NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1NTU1JEEAAAAAAAAAAAAAAAAAACQ2Njc3Nzc3Nzc3Nzc3 + Nzc3Nzc3Nzc3Nzc3Nzc3NzY2JEEAAAAAAAAAAAAAAAAAACQ3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3Nzc3 + Nzc3Nzg3JEEAAAAAAAAAAAAAAAAAACQ4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4JEEAAAAA + AAAAAAAAAAAAACQ4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4JEEAAAAAAAAAAAAAAAAAACQ5 + OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5OTk5JEEAAAAAAAAAAAAAAAAAACQ6Ojo6Ojo6Ojo6Ojo6 + Ojo6Ojo6Ojo6Ojo6Ojo6Ojo6JEEAAAAAAAAAAAAAAAAAACQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7 + Ozs7Ozs7JEEAAAAAAAAAAAAAAAAAACQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7JEEAAAAA + AAAAAAAAAAAAACQ8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8JEEAAAAAAAAAAAAAAAAAACQ9 + PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09JEEAAAAAAAAAAAAAAAAAACQ9PT09PT09PT09PT09 + PT09PT09PT09PT09PT09PT09JEEAAAAAAAAAAAAAAAAAACQ+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+Pj4+ + Pj4+Pj4+JEEAAAAAAAAAAAAAAAAAACQ/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/JEEAAAAA + AAAAAAAAAAAAACQ/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/Pz8/JEEAAAAAAAAAAAAAAAAAACRA + QEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAJEEAAAAAAAAAAAAAAAAAACQkJCQkJCQkJCQkJCQk + JCQkJCQkJCQkJCQkJCQkJCQkJEMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAER///////4O7v///////w7u//8AAAP/Du7//wAAA/8O7v//AAAD/w7u//8AAAP/Du7//wAA + A/8O7v//AAAD/w7u//8AAAP/Du7//wAAA/8O7oADAAAD/w7ugAMAAAP/Du6AAwAAA/8O7oADAAAD/w7u + gAMAAAP/Du6AAwAAA/8O7oADAAAD/w7ugAMAAAP/Du6AA/////8O7oAAAAAAAA7ugAAAAAAADu6AAAAA + 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 + HBwcHBwcHBwcHBwcHBwcHBwcEBktCxYWFhYWFgsQHR0dHR0dHR0dHR0dHR0dHR0dHR0QGS0LCwsLCwsL + CxAeHh4eHh4eHh4eHh4eHh4eHh4eHhAZAAAAAAAAAAAAEB8fHx8fHx8fHx8fHx8fHx8fHx8fEBkAAAAA + AAAAAAAQICAgICAgICAgICAgICAgICAgICAQGQAAAAAAAAAAABAhISEhISEhISEhISEhISEhISEhIRAZ + AAAAAAAAAAAAECIiIiIiIiIiIiIiIiIiIiIiIiIiEBkAAAAAAAAAAAAQIyMjIyMjIyMjIyMjIyMjIyMj + IyMQGQAAAAAAAAAAABAkJCQkJCQkJCQkJCQkJCQkJCQkJBAZAAAAAAAAAAAAECUkJSQlJCQkJCQkJCQk + JCQkJCQkEBkAAAAAAAAAAAAQJSUlJSUlJSUlJSUlJSUlJSUlJSUQGQAAAAAAAAAAABAmJiYmJiYmJiYm + JiYmJiYmJiYmJhAZAAAAAAAAAAAAECcnJycnJycnJycnJycnJycnJycnEBkAAAAAAAAAAAAQKCgoKCgo + KCgoKCgoKCgoKCgoKCgQGQAAAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBArAAAAAAAAAAAALy4u + Li4uLi4uLi4uLi4uLi4uLi4uLjD//////+AAf//gAD//4AA//+AAP//gAD//4AA/AGAAPwAgAD8AIAA/ + ACAAPwAgAD8AP///AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA + /4AAAP+AAAD/gAAA/4AAAP+AAAD/gAAA/4AAACgAAAAQAAAAIAAAAAEACAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAoj8AAK5OAAC6XQAAr2MPAMZtAACqbEwAsHNMALZ7TACwflQAvINMALKDbwC2h28A + uYxvAL2RbwC2jnQAADerAAA8tgAQUL8AQGi9AABCwgAAR80AEFPEAABM2AAlW8AAQGrDAD6w3wA+tuEA + PrzkAHiGwgB4iMUAcIzKAHiJyQB4jM0AZI3QAHCT2QBftdwAX7neAGCt2ABgstoAR7zmAF+/4QA9wucA + PcjqADzO7QA81O8AO9ryAEfD6QBGyuwAXsLhAEbR7wBG2PIARd/1AEXl+ABE7PwAu7zZALu93ACBuuAA + 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 + ADAAAABgAAAAAQAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7i4gAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7g + 4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAGYzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2Yz + M2YzM2YzM2YzM2YzM2YzM2YzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM5o5A546AJ46AJ46AJ46AJ46AJ46 + AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AJ46AGYzMwAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AGYzM54+A6I/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/AKI/ + AKI/AGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM6JCA6ZDAKZDAKZDAKZDAKZDAKZDAKZDAKZDAKZDAKZD + AKZDAKZDAKZDAKZDAKZDAKZDAKZDAKZDAKZDAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM6ZHA6pJAKpJ + AKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAKpJAGYzMwAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAGYzM6lMA65OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5OAK5O + AK5OAK5OAK5OAK5OAK5OAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM61RA7JTALJTALJTALJTALJTALJT + ALJTALJTALJTALJTALJTALJTALJTALJTALJTALJTALJTALJTALJTAGYzMwAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AGYzM7FWA7ZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZALZZ + ALZZAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQAzoQAzoQAzoQAzoQAzoQAz + oQAzoQAzoQAzoQAzoQAzoQAzoQAAAAAAAGYzM7RaA7pdALpdALpdALpdALpdALpdALpdALpdALpdALpd + ALpdALpdALpdALpdALpdALpdALpdALpdALpdAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAzoQA0owA0pAA0pAA0pAA0pAA0pAA0pAA0pAA0pAA0pAA0pAAzoQAAAAAAAGYzM7hfA75iAL5i + AL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAL5iAGYzMwAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQA2pwA2qAA2qAA2qAA2qAA2qAA2qAA2qAA2qAA2 + qAA2qAAzoQAAAAAAAGYzM7xkA8JoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJoAMJo + AMJoAMJoAMJoAMJoAMJoAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQA3qwA3 + qwA3qwA3qwA3qwA3qwA3qwA3qwA3qwA3qwA3qwAzoQAAAAAAAGYzM8BpA8ZtAMZtAMZtAMZtAMZtAMZt + AMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAMZtAGYzMwAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAzoQA5rgA5rwA5rwA5rwA5rwA5rwA5rwA5rwA5rwA5rwA5rwAzoQAAAAAA + AGYzM8NuA8pyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpyAMpy + AMpyAGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQA6sQA7swA7swA7swA7swA7 + swA7swA7swA7swA7swA7swAzoQAAAAAAAGYzM8dzA853AM53AM53AM53AM53AM53AM53AM53AM53AM53 + AM53AM53AM53AM53AM53AM53AM53AM53AM53AGYzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAzoQA8tQA8tgA8tgA8tgA8tgA8tgA8tgA8tgA8tgA8tgA8tgAzoQAAAAAAAGYzM8t3A9J8ANJ8 + ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8ANJ8AGYzMwAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQA9uAA+ugA+ugA+ugA+ugA+ugA+ugA+ugA+ugA+ + ugA+ugAzoQAAAAAAAGYzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2YzM2Yz + M2YzM2YzM2YzM2YzM2YzM2YzMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzoQA/vABA + vgBAvgBAvgBAvgBAvgBAvgBAvgBAvgBAvgBAvgAzoQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAzoQBBvwBBwQBBwQBBwQBBwQBBwQBBwQBBwQBBwQBBwQBBwQAzoQBbrwBb + rwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBb + rwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbr7rH3wAAAAAzoQBCwwBDxQBDxQBDxQBDxQBD + xQBDxQBDxQBDxQBDxQBDxQAzoQBbr0i45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei4 + 5Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45Ei45ABbr6y8 + 2QAAAAAzoQBExgBFyQBFyQBFyQBFyQBFyQBFyQBFyQBFyQBFyQBFyQAzoQBbr0i65Ui65Ui65Ui65Ui6 + 5Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui65Ui6 + 5Ui65Ui65Ui65Ui65Ui65Ui65QBbr6y82QAAAAAzoQBFygBHzABHzABHzABHzABHzABHzABHzABHzABH + zABHzAAzoQBbr0i85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki8 + 5ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85ki85gBbr6y82QAAAAAzoQBHzQBI + 0ABI0ABI0ABI0ABI0ABI0ABI0ABI0ABI0ABI0AAzoQBbr0i/50i/50i/50i/50i/50i/50i/50i/50i/ + 50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/50i/ + 50i/50i/5wBbr6y82QAAAAAzoQBI0QBK1ABK1ABK1ABK1ABK1ABK1ABK1ABK1ABK1ABK1AAzoQBbr0fB + 6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB + 6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6EfB6ABbr6y82QAAAAAzoQBK1ABM2ABM2ABM2ABM2ABM + 2ABM2ABM2ABM2ABM2ABM2AAzoQBbr0fD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD + 6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6UfD6QBbr6y8 + 2QAAAAAzoQBM2ABN2wBN2wBN2wBN2wBN2wBN2wBN2wBN2wBN2wBN2wAzoQBbr0fF6kfF6kfF6kfF6kfF + 6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF6kfF + 6kfF6kfF6kfF6kfF6kfF6kfF6gBbr6y82QAAAAAzoQBGzABIzwBIzwBIzwBIzwBIzwBIzwBIzwBIzwBI + zwBIzwAzoQBbr0fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI + 60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI60fI6wBbr6y82QAAAAAzoQAzoQAz + oQAzoQAzoQAzoQAzoQAzoQAzoQAzoQAzoQAzoQAzoQBbr0fK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK + 7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK7EfK + 7EfK7EfK7ABbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0fM + 7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM + 7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7UfM7QBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAABbr0bO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO + 7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7kbO7gBbr6y8 + 2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0bR70bR70bR70bR70bR + 70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR70bR + 70bR70bR70bR70bR70bR70bR7wBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAABbr0bT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT + 8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8EbT8ABbr6y82QAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0bV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV + 8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV8kbV + 8kbV8kbV8gBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0bX + 80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX + 80bX80bX80bX80bX80bX80bX80bX80bX80bX80bX8wBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAABbr0ba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba + 9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9Eba9ABbr6y8 + 2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Xc9UXc9UXc9UXc9UXc + 9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc9UXc + 9UXc9UXc9UXc9UXc9UXc9UXc9QBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAABbr0Xe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe + 9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9kXe9gBbr6y82QAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg + 90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg90Xg + 90Xg90Xg9wBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Xj + +EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj + +EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+EXj+ABbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAABbr0Xl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl + +UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+UXl+QBbr6y8 + 2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Xn+kXn+kXn+kXn+kXn + +kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn+kXn + +kXn+kXn+kXn+kXn+kXn+kXn+gBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAABbr0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp + +0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+0Tp+wBbr6y82QAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Ts/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs + /ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs/ETs + /ETs/ETs/ABbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr0Tu + /UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu + /UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/UTu/QBbr6y82QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAABbr0Tw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw + /kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/kTw/gBbr669 + 2QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbrwBbrwBbrwBbrwBbrwBb + rwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBbrwBb + rwBbrwBbrwBbrwBbrwBbrwBbrwBbr+XZ4gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7i4n///////g7u//// + ////Du7//wAAA/8O7v//AAAD/w7u//8AAAP/Du7//wAAA/8O7v//AAAD/w7u//8AAAP/Du7//wAAA/8O + 7v//AAAD/w7ugAMAAAP/Du6AAwAAA/8O7oADAAAD/w7ugAMAAAP/Du6AAwAAA/8O7oADAAAD/w7ugAMA + AAP/Du6AAwAAA/8O7oAD/////w7ugAAAAAAADu6AAAAAAAAO7oAAAAAAAA7ugAAAAAAADu6AAAAAAAAO + 7oAAAAAAAA7ugAAAAAAADu6AAAAAAAAO7oAAAAAAAA7ugAAAAAAADu7//AAAAAAO7v/8AAAAAA7u//wA + AAAADu7//AAAAAAO7v/8AAAAAA7u//wAAAAADu7//AAAAAAO7v/8AAAAAA7u//wAAAAADu7//AAAAAAO + 7v/8AAAAAA7u//wAAAAADu7//AAAAAAO7v/8AAAAAA7u//wAAAAADu7//AAAAAAO7v/8AAAAAA7u//wA + AAAADu7///////4O7igAAAAgAAAAQAAAAAEAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzMAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmMzOfOwCfOwCfOwCfOwCfOwCfOwCf + OwCfOwCfOwCfOwCfOwCfOwBmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABmMzOkQQCkQQCkQQCkQQCkQQCkQQCkQQCkQQCkQQCkQQCkQQCkQQBmMzOxmJgA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmMzOrSgCrSgCr + SgCrSgCrSgCrSgCrSgCrSgCrSgCrSgCrSgCrSgBmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmMzOwUQCwUQCwUQCwUQCwUQCwUQCwUQCwUQCwUQCwUQCw + UQCwUQBmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AABmMzO3WgC3WgC3WgC3WgC3WgC3WgC3WgC3WgC3WgC3WgC3WgC3WgBmMzOxmJgAAAAAAAAAAAAAAAAA + AAAAAADHu9QAM6EAM6EAM6EAM6EAM6EAM6EAM6EAM6EAAAAAAABmMzO8YAC8YAC8YAC8YAC8YAC8YAC8 + YAC8YAC8YAC8YAC8YAC8YABmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAADHu9QAM6EANqkANqkANqkANqkA + NqkANqkAM6F/mM8AAABmMzPDaQDDaQDDaQDDaQDDaQDDaQDDaQDDaQDDaQDDaQDDaQDDaQBmMzOxmJgA + AAAAAAAAAAAAAAAAAAAAAADHu9QAM6EAOK0AOK0AOK0AOK0AOK0AOK0AM6F/mM8AAABmMzPIcADIcADI + cADIcADIcADIcADIcADIcADIcADIcADIcADIcABmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAADHu9QAM6EA + O7QAO7QAO7QAO7QAO7QAO7QAM6F/mM8AAABmMzPPeADPeADPeADPeADPeADPeADPeADPeADPeADPeADP + eADPeABmMzOxmJgAAAAAAAAAAAAAAAAAAAAAAADHu9QAM6EAPbgAPbgAPbgAPbgAPbgAPbgAM6F/mM8A + AABmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzNmMzOxmJgAAAAAAAAAAAAAAAAA + AAAAAADHu9QAM6EAQL8AQL8AQL8AQL8AQL8AQL8AM6FVfMEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADHu9QAM6EAQsMAQsMAQsMAQsMA + QsMAQsMAM6EAW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68AW68A + W68AW68AW68AW68AW6+BpM7Hu9QAM6EARcoARcoARcoARcoARcoARcoAM6EAW69IuuVIuuVIuuVIuuVI + uuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuVIuuUAW698oMzHu9QAM6EA + R84AR84AR84AR84AR84AR84AM6EAW69IvuZIvuZIvuZIvuZIvuZIvuZIvuZIvuZIvuZIvuZIvuZIvuZI + vuZIvuZIvuZIvuZIvuZIvuZIvuZIvuYAW698oMzHu9QAM6EAStUAStUAStUAStUAStUAStUAM6EAW69H + wehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwehHwegA + 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 + SH08XNsEAFaMAdioj++z4Eh9MkLbBABWjAHYsLfvs+BIzR6pbQIAK8YAbEAAYqPmEACUwBiAFr18nwVH + au4obRMAWDEGYP2evs+CI/XpaG0TAFgxBmC9Hr7PgiM1b4y2CQCsGAOwLgGIjfqMAKAExgCss6fvs+BI + fT5W2wQAVowBaL6H77PgSH0xTtsEAFaMAWjW3fdZcKS+HK9tAgArxgA07e77LDhS88drmwDAijEAa3fz + fRYcqQVV2iYAsGIMQJOuvs+CI/XVBG0TAFgxBmCtLr7PgiP19URtEwBYIQDlgQCgJMYArNnZ91lwpL6Z + pG0CACvGAKzRyfdZcKQWTtY2AYAVYwBW7+j7LDhSi6q1TQBgxRiA1QhAbNRiAoASGAPQuIPvs+BILZmi + bQIAK8YArNre91lwpL6t0TYBgBVjAFZp5/ssOFLfTdU2AYAVYwBWJgCxUd8TAJTAGIBGbX2fBUfqh2na + JgCwYgzASm18nwVHaul0bRMAWDEFAPEjALBCAMoTAYAVAlCeCACsEIDyRAAARI8AAAkjAEDCCACQMAIA + JIwAAAkjAEDCCACQMFMAAKRlbv1PNdVF4Jm637at+5rUfY3qvrL4iScADfsZgOX03tj+IOMAAAAASUVO + RK5CYIIoAAAAMAAAAGAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/svLi/7Ly2D+y8tb/svL + W/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svL + W/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svL + W/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8tb/svLW/7Ly1v+y8uU/svL + ev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AGUyMhxlMjIgZTIyIGUyMiBlMjIgZTIyIGUyMiBlMjIgZTIyIGUyMiBlMjIgZTIyIGUyMiBlMjIgZTIy + IGUyMiBlMjIgZTIyIGUyMiBlMjIgZTIyIGUyMiBlMjIIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAGYzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz + /2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM/+aOQP/njoA/546AP+eOgD/njoA/546AP+eOgD/njoA + /546AP+eOgD/njoA/546AP+eOgD/njoA/546AP+eOgD/njoA/546AP+eOgD/njoA/2YzM/9lMjJAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM/+ePgP/oj8A/6I/AP+iPwD/oj8A + /6I/AP+iPwD/oj8A/6I/AP+iPwD/oj8A/6I/AP+iPwD/oj8A/6I/AP+iPwD/oj8A/6I/AP+iPwD/oj8A + /2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLev7LywgAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM/+iQgP/pkMA + /6ZDAP+mQwD/pkMA/6ZDAP+mQwD/pkMA/6ZDAP+mQwD/pkMA/6ZDAP+mQwD/pkMA/6ZDAP+mQwD/pkMA + /6ZDAP+mQwD/pkMA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svL + ev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AGYzM/+mRwP/qkkA/6pJAP+qSQD/qkkA/6pJAP+qSQD/qkkA/6pJAP+qSQD/qkkA/6pJAP+qSQD/qkkA + /6pJAP+qSQD/qkkA/6pJAP+qSQD/qkkA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAGYzM/+pTAP/rk4A/65OAP+uTgD/rk4A/65OAP+uTgD/rk4A/65OAP+uTgD/rk4A + /65OAP+uTgD/rk4A/65OAP+uTgD/rk4A/65OAP+uTgD/rk4A/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM/+tUQP/slMA/7JTAP+yUwD/slMA/7JTAP+yUwD/slMA + /7JTAP+yUwD/slMA/7JTAP+yUwD/slMA/7JTAP+yUwD/slMA/7JTAP+yUwD/slMA/2YzM/9lMjJAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM/+xVgP/tlkA/7ZZAP+2WQD/tlkA + /7ZZAP+2WQD/tlkA/7ZZAP+2WQD/tlkA/7ZZAP+2WQD/tlkA/7ZZAP+2WQD/tlkA/7ZZAP+2WQD/tlkA + /2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AM6H/ADOh + /wAzof8AM6H/ADOh/wAzof8AM6H/ADOh/wAzof8AM6H/ADOh/wAzof8AMqAsAAAAAGYzM/+0WgP/ul0A + /7pdAP+6XQD/ul0A/7pdAP+6XQD/ul0A/7pdAP+6XQD/ul0A/7pdAP+6XQD/ul0A/7pdAP+6XQD/ul0A + /7pdAP+6XQD/ul0A/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svL + egAzof8ANKP/ADSk/wA0pP8ANKT/ADSk/wA0pP8ANKT/ADSk/wA0pP8ANKT/ADSk/wAzof8AMqBAAAAA + AGYzM/+4XwP/vmIA/75iAP++YgD/vmIA/75iAP++YgD/vmIA/75iAP++YgD/vmIA/75iAP++YgD/vmIA + /75iAP++YgD/vmIA/75iAP++YgD/vmIA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAD+y8tb/svLegAzof8ANqf/ADao/wA2qP8ANqj/ADao/wA2qP8ANqj/ADao/wA2qP8ANqj/ADao + /wAzof8AMqBAAAAAAGYzM/+8ZAP/wmgA/8JoAP/CaAD/wmgA/8JoAP/CaAD/wmgA/8JoAP/CaAD/wmgA + /8JoAP/CaAD/wmgA/8JoAP/CaAD/wmgA/8JoAP/CaAD/wmgA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AN6v/ADer/wA3q/8AN6v/ADer/wA3q/8AN6v/ADer + /wA3q/8AN6v/ADer/wAzof8AMqBAAAAAAGYzM//AaQP/xm0A/8ZtAP/GbQD/xm0A/8ZtAP/GbQD/xm0A + /8ZtAP/GbQD/xm0A/8ZtAP/GbQD/xm0A/8ZtAP/GbQD/xm0A/8ZtAP/GbQD/xm0A/2YzM/9lMjJAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AOa7/ADmv/wA5r/8AOa//ADmv + /wA5r/8AOa//ADmv/wA5r/8AOa//ADmv/wAzof8AMqBAAAAAAGYzM//DbgP/ynIA/8pyAP/KcgD/ynIA + /8pyAP/KcgD/ynIA/8pyAP/KcgD/ynIA/8pyAP/KcgD/ynIA/8pyAP/KcgD/ynIA/8pyAP/KcgD/ynIA + /2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AOrH/ADuz + /wA7s/8AO7P/ADuz/wA7s/8AO7P/ADuz/wA7s/8AO7P/ADuz/wAzof8AMqBAAAAAAGYzM//HcwP/zncA + /853AP/OdwD/zncA/853AP/OdwD/zncA/853AP/OdwD/zncA/853AP/OdwD/zncA/853AP/OdwD/zncA + /853AP/OdwD/zncA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svL + egAzof8APLX/ADy2/wA8tv8APLb/ADy2/wA8tv8APLb/ADy2/wA8tv8APLb/ADy2/wAzof8AMqBAAAAA + AGYzM//LdwP/0nwA/9J8AP/SfAD/0nwA/9J8AP/SfAD/0nwA/9J8AP/SfAD/0nwA/9J8AP/SfAD/0nwA + /9J8AP/SfAD/0nwA/9J8AP/SfAD/0nwA/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAD+y8tb/svLegAzof8APbj/AD66/wA+uv8APrr/AD66/wA+uv8APrr/AD66/wA+uv8APrr/AD66 + /wAzof8AMqBAAAAAAGYzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz + /2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9lMjJAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AP7z/AEC+/wBAvv8AQL7/AEC+/wBAvv8AQL7/AEC+ + /wBAvv8AQL7/AEC+/wAzof8AMqBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tb/svLegAzof8AQb//AEHB/wBBwf8AQcH/AEHB + /wBBwf8AQcH/AEHB/wBBwf8AQcH/AEHB/wAzof8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/+InsiS/svLegAzof8AQsP/AEPF + /wBDxf8AQ8X/AEPF/wBDxf8AQ8X/AEPF/wBDxf8AQ8X/AEPF/wAzof8AW6//SLjk/0i45P9IuOT/SLjk + /0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/0i45P9IuOT/SLjk + /0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/0i45P9IuOT/SLjk/wBbr/9+mMWk/svL + egAzof8ARMb/AEXJ/wBFyf8ARcn/AEXJ/wBFyf8ARcn/AEXJ/wBFyf8ARcn/AEXJ/wAzof8AW6//SLrl + /0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl + /0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl + /wBbr/9+mMWk/svLegAzof8ARcr/AEfM/wBHzP8AR8z/AEfM/wBHzP8AR8z/AEfM/wBHzP8AR8z/AEfM + /wAzof8AW6//SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm + /0i85v9IvOb/SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm/0i85v9IvOb/SLzm + /0i85v9IvOb/SLzm/wBbr/9+mMWk/svLegAzof8AR83/AEjQ/wBI0P8ASND/AEjQ/wBI0P8ASND/AEjQ + /wBI0P8ASND/AEjQ/wAzof8AW6//SL/n/0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n + /0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n + /0i/5/9Iv+f/SL/n/0i/5/9Iv+f/SL/n/wBbr/9+mMWk/svLegAzof8ASNH/AErU/wBK1P8AStT/AErU + /wBK1P8AStT/AErU/wBK1P8AStT/AErU/wAzof8AW6//R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho + /0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho + /0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/wBbr/9+mMWk/8zMegAzof8AStT/AEzY + /wBM2P8ATNj/AEzY/wBM2P8ATNj/AEzY/wBM2P8ATNj/AEzY/wAzof8AW6//R8Pp/0fD6f9Hw+n/R8Pp + /0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp + /0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/0fD6f9Hw+n/R8Pp/wBbr/9+mMWk/8zM + egAzof8ATNj/AE3b/wBN2/8ATdv/AE3b/wBN2/8ATdv/AE3b/wBN2/8ATdv/AE3b/wAzof8AW6//R8Xq + /0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq + /0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq/0fF6v9Hxer/R8Xq + /wBbr/9+mMWk/8zMegAzof8ARsz/AEjP/wBIz/8ASM//AEjP/wBIz/8ASM//AEjP/wBIz/8ASM//AEjP + /wAzof8AW6//R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr + /0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr + /0fI6/9HyOv/R8jr/wBbr/9+mMWk/8zMegAzof8AM6H/ADOh/wAzof8AM6H/ADOh/wAzof8AM6H/ADOh + /wAzof8AM6H/ADOh/wAzof8AW6//R8rs/0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs + /0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs + /0fK7P9Hyuz/R8rs/0fK7P9Hyuz/R8rs/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//R8zt/0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt + /0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt + /0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt/0fM7f9HzO3/R8zt/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Rs7u/0bO7v9Gzu7/Rs7u + /0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u + /0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/0bO7v9Gzu7/Rs7u/wBbr/9+mMWk/8zM + ev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//RtHv + /0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv + /0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv/0bR7/9G0e//RtHv + /wBbr/9+mMWk/8zMev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAW6//RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw + /0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw/0bT8P9G0/D/RtPw + /0bT8P9G0/D/RtPw/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAW6//RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy + /0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy + /0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Rtfz/0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz + /0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz + /0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz/0bX8/9G1/P/Rtfz/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Rtr0/0ba9P9G2vT/Rtr0 + /0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0 + /0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/0ba9P9G2vT/Rtr0/wBbr/9+mMWk/svL + ev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Rdz1 + /0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1 + /0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1 + /wBbr/9+mMWk/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAW6//Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72 + /0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72/0Xe9v9F3vb/Rd72 + /0Xe9v9F3vb/Rd72/wBbr/9+mMWk/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAW6//ReD3/0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3 + /0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3 + /0Xg9/9F4Pf/ReD3/0Xg9/9F4Pf/ReD3/wBbr/9+mMWk/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4 + /0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4 + /0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/wBbr/9+mMWk/svLev7LywgAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//ReX5/0Xl+f9F5fn/ReX5 + /0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5 + /0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/0Xl+f9F5fn/ReX5/wBbr/9+mMWk/svL + ev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Ref6 + /0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6 + /0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6/0Xn+v9F5/r/Ref6 + /wBbr/9+mMWk/svLev7LywgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAW6//ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7 + /0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7/0Tp+/9E6fv/ROn7 + /0Tp+/9E6fv/ROn7/wBbr/9+mMWk/8zMev/MzAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAW6//ROz8/0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8 + /0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8 + /0Ts/P9E7Pz/ROz8/0Ts/P9E7Pz/ROz8/wBbr/9+mMWk/svLev/LywgAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//RO79/0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79 + /0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79 + /0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79/0Tu/f9E7v3/RO79/wBbr/9+mMWk/svLev7LywgAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//RPD+/0Tw/v9E8P7/RPD+ + /0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+ + /0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/0Tw/v9E8P7/RPD+/wBbr/+BmMSi/svL + ev7Lyw7+y8sI/8zMCP/MzAj+y8sI/svLCP7Lywj+y8sI/svLCP7Lywj+y8sI/8zMCP/MzAgAW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr//NtcaA/svLfP/Ly3r+y8t6/8zMev/MzHr+y8t6/svLev7Ly3r+y8t6/svLev7Ly3r+y8t6/8zM + ev/MzHr/zMx6/8zMev/MzHr/zMx6/8zMev/MzHr/zMx6/8zMev/MzHr+y8t6/svLev7Ly3r+y8t6/svL + ev7Ly3r+y8t6/svLev7Ly3r+y8t6/svLev7Ly3r+y8t6/svLev7Ly3r+y8t6/svLev7Ly3r+y8t6/svL + ev7Ly3r+y8t6/svLev7Ly3r+y8uLAAAAAAAADu4//wAAAf4O7j//AAAB/g7uP/8AAAH+Du4//wAAAf4O + 7j//AAAB/g7uP/8AAAH+Du4//wAAAf4O7j//AAAB/g7uP/8AAAH+Du4AAQAAAf4O7gABAAAB/g7uAAEA + AAH+Du4AAQAAAf4O7gABAAAB/g7uAAEAAAH+Du4AAQAAAf4O7gABAAAB/g7uAAH////+Du4AAAAAAAAO + 7gAAAAAAAA7uAAAAAAAADu4AAAAAAAAO7gAAAAAAAA7uAAAAAAAADu4AAAAAAAAO7gAAAAAAAA7uAAAA + AAAADu4AAAAAAAAO7j/8AAAAAA7uP/wAAAAADu4//AAAAAAO7j/8AAAAAA7uP/wAAAAADu4//AAAAAAO + 7j/8AAAAAA7uP/wAAAAADu4//AAAAAAO7j/8AAAAAA7uP/wAAAAADu4//AAAAAAO7j/8AAAAAA7uP/wA + AAAADu4//AAAAAAO7j/8AAAAAA7uP/wAAAAADu4AAAAAAAAO7gAAAAAAAA7uKAAAACAAAABAAAAAAQAg + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP7Ly2/+y8s//svLPf7Lyz3+y8s9/svLPf7Lyz3+y8s9/svL + Pf7Lyz3hrq5Ay5iYR8uYmEfLmJhHy5iYR8uYmEfLmJhHy5iYR8uYmEfLmJhHy5iYR8uYmEfLmJhHy5iY + R8uYmEfLmJhC/svLPf7Lyz3+y8s9/svLPf7Lyz3+y8tq/svLVP7LywMAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAGUyMjxmMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz + /2YzM/9mMzP/ZjMz/2UyMloAAAAAAAAAAAAAAAAAAAAAAAAAAP7Lyz3+y8tU/svLAwAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAZjMzVWYzM/+fOwD/nzsA/587AP+fOwD/nzsA/587AP+fOwD/nzsA + /587AP+fOwD/nzsA/587AP9mMzP/ZTIygAAAAAAAAAAAAAAAAAAAAAAAAAAA/svLPf7Ly1T+y8sDAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmMzNVZjMz/6RBAP+kQQD/pEEA/6RBAP+kQQD/pEEA + /6RBAP+kQQD/pEEA/6RBAP+kQQD/pEEA/2YzM/9lMjKAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8s9/svL + VP7LywMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGYzM1VmMzP/q0oA/6tKAP+rSgD/q0oA + /6tKAP+rSgD/q0oA/6tKAP+rSgD/q0oA/6tKAP+rSgD/ZjMz/2UyMoAAAAAAAAAAAAAAAAAAAAAAAAAA + AP7Lyz3+y8tU/svLAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZjMzVWYzM/+wUQD/sFEA + /7BRAP+wUQD/sFEA/7BRAP+wUQD/sFEA/7BRAP+wUQD/sFEA/7BRAP9mMzP/ZTIygAAAAAAAAAAAAAAA + AAAAAAAAAAAA/svLPeG6xm9da7BXADOhVQAzoVUAM6FVADOhVQAzoVUAM6FVADOhVQAyoCZmMzNVZjMz + /7daAP+3WgD/t1oA/7daAP+3WgD/t1oA/7daAP+3WgD/t1oA/7daAP+3WgD/t1oA/2YzM/9lMjKAAAAA + AAAAAAAAAAAAAAAAAAAAAAD+y8s9qZi9pgAzof8AM6H/ADOh/wAzof8AM6H/ADOh/wAzof8AM6H/ADKg + e2YzM1VmMzP/vGAA/7xgAP+8YAD/vGAA/7xgAP+8YAD/vGAA/7xgAP+8YAD/vGAA/7xgAP+8YAD/ZjMz + /2UyMoAAAAAAAAAAAAAAAAAAAAAAAAAAAP7Lyz2pmL2mADOh/wA2qf8ANqn/ADap/wA2qf8ANqn/ADap + /wAzof8AMqCAZjMzVWYzM//DaQD/w2kA/8NpAP/DaQD/w2kA/8NpAP/DaQD/w2kA/8NpAP/DaQD/w2kA + /8NpAP9mMzP/ZTIygAAAAAAAAAAAAAAAAAAAAAAAAAAA/svLPamYvaYAM6H/ADit/wA4rf8AOK3/ADit + /wA4rf8AOK3/ADOh/wAyoIBmMzNVZjMz/8hwAP/IcAD/yHAA/8hwAP/IcAD/yHAA/8hwAP/IcAD/yHAA + /8hwAP/IcAD/yHAA/2YzM/9lMjKAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8s9qZi9pgAzof8AO7T/ADu0 + /wA7tP8AO7T/ADu0/wA7tP8AM6H/ADKggGYzM1VmMzP/z3gA/894AP/PeAD/z3gA/894AP/PeAD/z3gA + /894AP/PeAD/z3gA/894AP/PeAD/ZjMz/2UyMoAAAAAAAAAAAAAAAAAAAAAAAAAAAP7Lyz2pmL2mADOh + /wA9uP8APbj/AD24/wA9uP8APbj/AD24/wAzof8AMqCAZjMzVWYzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz + /2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZTIygAAAAAAAAAAAAAAAAAAAAAAAAAAA/svL + PamYvaYAM6H/AEC//wBAv/8AQL//AEC//wBAv/8AQL//ADOh/wA7o6oAW69VAFuvVQBbr1UAW69VAFuv + VQBbr1UAW69VAFuvVQBbr1UAW69VAFuvVQBbr1UAW69VAFuvVQBbr1UAW69VAFuvVQBbr1UAW69VAFuv + VQBbr1WsqMRlqZi9pgAzof8AQsP/AELD/wBCw/8AQsP/AELD/wBCw/8AM6H/AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/1aFvr6pmL2mADOh/wBFyv8ARcr/AEXK/wBFyv8ARcr/AEXK/wAzof8AW6//SLrl + /0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl/0i65f9IuuX/SLrl + /0i65f9IuuX/SLrl/0i65f8AW6//VIO9wqmYvaYAM6H/AEfO/wBHzv8AR87/AEfO/wBHzv8AR87/ADOh + /wBbr/9Ivub/SL7m/0i+5v9Ivub/SL7m/0i+5v9Ivub/SL7m/0i+5v9Ivub/SL7m/0i+5v9Ivub/SL7m + /0i+5v9Ivub/SL7m/0i+5v9Ivub/SL7m/wBbr/9Ug73CqZi9pgAzof8AStX/AErV/wBK1f8AStX/AErV + /wBK1f8AM6H/AFuv/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho + /0fB6P9Hwej/R8Ho/0fB6P9Hwej/R8Ho/0fB6P9Hwej/AFuv/1SDvcKqmb2mADOh/wBM2v8ATNr/AEza + /wBM2v8ATNr/AEza/wAzof8AW6//R8Tp/0fE6f9HxOn/R8Tp/0fE6f9HxOn/R8Tp/0fE6f9HxOn/R8Tp + /0fE6f9HxOn/R8Tp/0fE6f9HxOn/R8Tp/0fE6f9HxOn/R8Tp/0fE6f8AW6//VIO9wqqZvaYAM6H/ADOh + /wAzof8AM6H/ADOh/wAzof8AM6H/ADOh/wBbr/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr + /0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/0fI6/9HyOv/R8jr/wBbr/9Ug73C4rvH + b15rsFcAM6FVADOhVQAzoVUAM6FVADOhVQAzoVUAM6FVAFuv/0fL7P9Hy+z/R8vs/0fL7P9Hy+z/R8vs + /0fL7P9Hy+z/R8vs/0fL7P9Hy+z/R8vs/0fL7P9Hy+z/R8vs/0fL7P9Hy+z/R8vs/0fL7P9Hy+z/AFuv + /1SDvcL/zMxU/8zMAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//Rs/u/0bP7v9Gz+7/Rs/u + /0bP7v9Gz+7/Rs/u/0bP7v9Gz+7/Rs/u/0bP7v9Gz+7/Rs/u/0bP7v9Gz+7/Rs/u/0bP7v9Gz+7/Rs/u + /0bP7v8AW6//VIO9wv/MzFT/zMwDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr/9G0u//RtLv + /0bS7/9G0u//RtLv/0bS7/9G0u//RtLv/0bS7/9G0u//RtLv/0bS7/9G0u//RtLv/0bS7/9G0u//RtLv + /0bS7/9G0u//RtLv/wBbr/9Ug73C/8zMVP/MzAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFuv + /0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy/0bV8v9G1fL/RtXy + /0bV8v9G1fL/RtXy/0bV8v9G1fL/AFuv/1SDvcL/zMxU/8zMAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAW6//Rtnz/0bZ8/9G2fP/Rtnz/0bZ8/9G2fP/Rtnz/0bZ8/9G2fP/Rtnz/0bZ8/9G2fP/Rtnz + /0bZ8/9G2fP/Rtnz/0bZ8/9G2fP/Rtnz/0bZ8/8AW6//VIO9wv7Ly1T+y8sDAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAABbr/9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1 + /0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/0Xc9f9F3PX/Rdz1/wBbr/9Ug73C/svLVP7LywMAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAFuv/0Xf9v9F3/b/Rd/2/0Xf9v9F3/b/Rd/2/0Xf9v9F3/b/Rd/2 + /0Xf9v9F3/b/Rd/2/0Xf9v9F3/b/Rd/2/0Xf9v9F3/b/Rd/2/0Xf9v9F3/b/AFuv/1SDvcL+y8tU/svL + AwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4 + /0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P9F4/j/ReP4/0Xj+P8AW6//VIO9 + wv7Ly1T+y8sDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbr/9F5vn/Reb5/0Xm+f9F5vn/Reb5 + /0Xm+f9F5vn/Reb5/0Xm+f9F5vn/Reb5/0Xm+f9F5vn/Reb5/0Xm+f9F5vn/Reb5/0Xm+f9F5vn/Reb5 + /wBbr/9Ug73C/svLVP7LywMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFuv/0Tq+/9E6vv/ROr7 + /0Tq+/9E6vv/ROr7/0Tq+/9E6vv/ROr7/0Tq+/9E6vv/ROr7/0Tq+/9E6vv/ROr7/0Tq+/9E6vv/ROr7 + /0Tq+/9E6vv/AFuv/1SDvcL+y8tU/8vLAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW6//RO38 + /0Tt/P9E7fz/RO38/0Tt/P9E7fz/RO38/0Tt/P9E7fz/RO38/0Tt/P9E7fz/RO38/0Tt/P9E7fz/RO38 + /0Tt/P9E7fz/RO38/0Tt/P8AW6//VIO9wv7Ly1X+y8sF/8zMA/7LywP+y8sD/svLA/7LywP+y8sD/8zM + AwBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/9mir25/svLb/7Ly1X/zMxU/svLVP7Ly1T+y8tU/svL + VP7Ly1T/zMxUxrLFi6qmwqaqpsKmqqbCpqqmwqaqpsKmqaXBpqmlwaappcGmqaXBpqmlwaappcGmqaXB + pqmlwaappcGmqaXBpqmlwaappcGmqaXBpqmlwaappcGmqaXBpta5xpIAAAAAP8AAPj/AAD4/wAA+P8AA + Pj/AAD4AAAA+AAAAPgAAAD4AAAA+AAAAPgAAAD4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAA/gAAAP4AAAD+AAAAAAAAAAAAAACgAAAAQAAAAIAAA + AAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD+y8tB/svLHv7Lyx7+y8se/svLHp1qanCYZWWjmGVl + o5hlZaOYZWWjmGVlo5hlZaOYZWV4/svLHv7Lyx7+y8s5/svLLAAAAAAAAAAAAAAAAAAAAABmMzP/ZjMz + /2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/wAAAAAAAAAA/svLHv7LyywAAAAAAAAAAAAAAAAAAAAAZjMz + /61NAP+tTQD/rU0A/61NAP+tTQD/rU0A/2YzM/8AAAAAAAAAAP7Lyx4AM6H/ADOh/wAzof8AM6H/ADOh + /2YzM/+5XQD/uV0A/7ldAP+5XQD/uV0A/7ldAP9mMzP/AAAAAAAAAAD+y8seADOh/wA3q/8AN6v/ADer + /wAzof9mMzP/xWwA/8VsAP/FbAD/xWwA/8VsAP/FbAD/ZjMz/wAAAAAAAAAA/svLHgAzof8APLb/ADy2 + /wA8tv8AM6H/ZjMz/2YzM/9mMzP/ZjMz/2YzM/9mMzP/ZjMz/2YzM/8AAAAAAAAAAP7Lyx4AM6H/AEHB + /wBBwf8AQcH/ADOh/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//ADOh + /wBGzP8ARsz/AEbM/wAzof9IvOX/SLzl/0i85f9IvOX/SLzl/0i85f9IvOX/SLzl/0i85f9IvOX/AFuv + /wAzof8AS9f/AEvX/wBL1/8AM6H/R8Lo/0fC6P9Hwuj/R8Lo/0fC6P9Hwuj/R8Lo/0fC6P9Hwuj/R8Lo + /wBbr/8AM6H/ADOh/wAzof8AM6H/ADOh/0fJ6/9Hyev/R8nr/0fJ6/9Hyev/R8nr/0fJ6/9Hyev/R8nr + /0fJ6/8AW6///8zMLAAAAAAAAAAAAAAAAABbr/9G0O7/RtDu/0bQ7v9G0O7/RtDu/0bQ7v9G0O7/RtDu + /0bQ7v9G0O7/AFuv///MzCwAAAAAAAAAAAAAAAAAW6//Rtfy/0bX8v9G1/L/Rtfy/0bX8v9G1/L/Rtfy + /0bX8v9G1/L/Rtfy/wBbr//+y8ssAAAAAAAAAAAAAAAAAFuv/0Xd9f9F3fX/Rd31/0Xd9f9F3fX/Rd31 + /0Xd9f9F3fX/Rd31/0Xd9f8AW6///svLLAAAAAAAAAAAAAAAAABbr/9F5Pj/ReT4/0Xk+P9F5Pj/ReT4 + /0Xk+P9F5Pj/ReT4/0Xk+P9F5Pj/AFuv//7LyywAAAAAAAAAAAAAAAAAW6//ROv7/0Tr+/9E6/v/ROv7 + /0Tr+/9E6/v/ROv7/0Tr+/9E6/v/ROv7/wBbr//+y8tI/svLLP7Lyyz+y8ssAFuv/wBbr/8AW6//AFuv + /wBbr/8AW6//AFuv/wBbr/8AW6//AFuv/wBbr/8AW6//AACsQXgGrEF4BqxBAAasQQAGrEEABqxBAACs + QQAArEEAAKxBAACsQXAArEFwAKxBcACsQXAArEFwAKxBAACsQQ== + + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/SearchWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/SearchWindow.Designer.cs new file mode 100644 index 000000000..8097dde5d --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/SearchWindow.Designer.cs @@ -0,0 +1,424 @@ +namespace ProcessHacker +{ + partial class SearchWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.tabControl = new System.Windows.Forms.TabControl(); + this.tabLiteral = new System.Windows.Forms.TabPage(); + this.checkNoOverlap = new System.Windows.Forms.CheckBox(); + this.utilitiesButtonLiteral = new ProcessHacker.Components.UtilitiesButton(); + this.hexBoxSearch = new Be.Windows.Forms.HexBox(); + this.tabRegex = new System.Windows.Forms.TabPage(); + this.checkIgnoreCase = new System.Windows.Forms.CheckBox(); + this.textRegex = new System.Windows.Forms.TextBox(); + this.tabString = new System.Windows.Forms.TabPage(); + this.checkUnicode = new System.Windows.Forms.CheckBox(); + this.textStringMS = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.tabHeap = new System.Windows.Forms.TabPage(); + this.textHeapMS = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.tabStruct = new System.Windows.Forms.TabPage(); + this.textStructAlign = new System.Windows.Forms.TextBox(); + this.label5 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.listStructName = new System.Windows.Forms.ListBox(); + this.checkPrivate = new System.Windows.Forms.CheckBox(); + this.checkImage = new System.Windows.Forms.CheckBox(); + this.checkMapped = new System.Windows.Forms.CheckBox(); + this.label1 = new System.Windows.Forms.Label(); + this.buttonOK = new System.Windows.Forms.Button(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.tabControl.SuspendLayout(); + this.tabLiteral.SuspendLayout(); + this.tabRegex.SuspendLayout(); + this.tabString.SuspendLayout(); + this.tabHeap.SuspendLayout(); + this.tabStruct.SuspendLayout(); + this.SuspendLayout(); + // + // tabControl + // + this.tabControl.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.tabControl.Controls.Add(this.tabLiteral); + this.tabControl.Controls.Add(this.tabRegex); + this.tabControl.Controls.Add(this.tabString); + this.tabControl.Controls.Add(this.tabHeap); + this.tabControl.Controls.Add(this.tabStruct); + this.tabControl.Location = new System.Drawing.Point(12, 12); + this.tabControl.Name = "tabControl"; + this.tabControl.SelectedIndex = 0; + this.tabControl.Size = new System.Drawing.Size(493, 311); + this.tabControl.TabIndex = 0; + this.tabControl.SelectedIndexChanged += new System.EventHandler(this.tabControl_SelectedIndexChanged); + // + // tabLiteral + // + this.tabLiteral.Controls.Add(this.checkNoOverlap); + this.tabLiteral.Controls.Add(this.utilitiesButtonLiteral); + this.tabLiteral.Controls.Add(this.hexBoxSearch); + this.tabLiteral.Location = new System.Drawing.Point(4, 22); + this.tabLiteral.Name = "tabLiteral"; + this.tabLiteral.Padding = new System.Windows.Forms.Padding(3); + this.tabLiteral.Size = new System.Drawing.Size(485, 285); + this.tabLiteral.TabIndex = 0; + this.tabLiteral.Text = "Literal Search"; + this.tabLiteral.UseVisualStyleBackColor = true; + // + // checkNoOverlap + // + this.checkNoOverlap.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.checkNoOverlap.AutoSize = true; + this.checkNoOverlap.Location = new System.Drawing.Point(6, 262); + this.checkNoOverlap.Name = "checkNoOverlap"; + this.checkNoOverlap.Size = new System.Drawing.Size(154, 17); + this.checkNoOverlap.TabIndex = 1; + this.checkNoOverlap.Text = "Prevent overlapping results"; + this.checkNoOverlap.UseVisualStyleBackColor = true; + // + // utilitiesButtonLiteral + // + this.utilitiesButtonLiteral.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.utilitiesButtonLiteral.HexBox = this.hexBoxSearch; + this.utilitiesButtonLiteral.Location = new System.Drawing.Point(455, 255); + this.utilitiesButtonLiteral.Name = "utilitiesButtonLiteral"; + this.utilitiesButtonLiteral.Size = new System.Drawing.Size(24, 24); + this.utilitiesButtonLiteral.TabIndex = 2; + // + // hexBoxSearch + // + this.hexBoxSearch.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.hexBoxSearch.BytesPerLine = 8; + this.hexBoxSearch.Font = new System.Drawing.Font("Courier New", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.hexBoxSearch.HexCasing = Be.Windows.Forms.HexCasing.Lower; + this.hexBoxSearch.LineInfoForeColor = System.Drawing.Color.Empty; + this.hexBoxSearch.LineInfoVisible = true; + this.hexBoxSearch.Location = new System.Drawing.Point(6, 6); + this.hexBoxSearch.Name = "hexBoxSearch"; + this.hexBoxSearch.ShadowSelectionColor = System.Drawing.Color.FromArgb(((int)(((byte)(100)))), ((int)(((byte)(60)))), ((int)(((byte)(188)))), ((int)(((byte)(255))))); + this.hexBoxSearch.Size = new System.Drawing.Size(473, 243); + this.hexBoxSearch.StringViewVisible = true; + this.hexBoxSearch.TabIndex = 0; + this.hexBoxSearch.UseFixedBytesPerLine = true; + this.hexBoxSearch.VScrollBarVisible = true; + // + // tabRegex + // + this.tabRegex.Controls.Add(this.checkIgnoreCase); + this.tabRegex.Controls.Add(this.textRegex); + this.tabRegex.Location = new System.Drawing.Point(4, 22); + this.tabRegex.Name = "tabRegex"; + this.tabRegex.Padding = new System.Windows.Forms.Padding(3); + this.tabRegex.Size = new System.Drawing.Size(485, 285); + this.tabRegex.TabIndex = 1; + this.tabRegex.Text = "Regex Search"; + this.tabRegex.UseVisualStyleBackColor = true; + // + // checkIgnoreCase + // + this.checkIgnoreCase.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.checkIgnoreCase.AutoSize = true; + this.checkIgnoreCase.Location = new System.Drawing.Point(6, 262); + this.checkIgnoreCase.Name = "checkIgnoreCase"; + this.checkIgnoreCase.Size = new System.Drawing.Size(83, 17); + this.checkIgnoreCase.TabIndex = 1; + this.checkIgnoreCase.Text = "Ignore Case"; + this.checkIgnoreCase.UseVisualStyleBackColor = true; + // + // textRegex + // + this.textRegex.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textRegex.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.textRegex.Location = new System.Drawing.Point(6, 6); + this.textRegex.Multiline = true; + this.textRegex.Name = "textRegex"; + this.textRegex.Size = new System.Drawing.Size(473, 250); + this.textRegex.TabIndex = 0; + // + // tabString + // + this.tabString.Controls.Add(this.checkUnicode); + this.tabString.Controls.Add(this.textStringMS); + this.tabString.Controls.Add(this.label2); + this.tabString.Location = new System.Drawing.Point(4, 22); + this.tabString.Name = "tabString"; + this.tabString.Padding = new System.Windows.Forms.Padding(5); + this.tabString.Size = new System.Drawing.Size(485, 285); + this.tabString.TabIndex = 2; + this.tabString.Text = "String Scan"; + this.tabString.UseVisualStyleBackColor = true; + // + // checkUnicode + // + this.checkUnicode.AutoSize = true; + this.checkUnicode.Location = new System.Drawing.Point(8, 34); + this.checkUnicode.Name = "checkUnicode"; + this.checkUnicode.Size = new System.Drawing.Size(122, 17); + this.checkUnicode.TabIndex = 1; + this.checkUnicode.Text = "Find Unicode strings"; + this.checkUnicode.UseVisualStyleBackColor = true; + // + // textStringMS + // + this.textStringMS.Location = new System.Drawing.Point(88, 8); + this.textStringMS.Name = "textStringMS"; + this.textStringMS.Size = new System.Drawing.Size(100, 20); + this.textStringMS.TabIndex = 0; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(8, 11); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(74, 13); + this.label2.TabIndex = 2; + this.label2.Text = "Minimum Size:"; + // + // tabHeap + // + this.tabHeap.Controls.Add(this.textHeapMS); + this.tabHeap.Controls.Add(this.label4); + this.tabHeap.Location = new System.Drawing.Point(4, 22); + this.tabHeap.Name = "tabHeap"; + this.tabHeap.Padding = new System.Windows.Forms.Padding(5); + this.tabHeap.Size = new System.Drawing.Size(485, 285); + this.tabHeap.TabIndex = 3; + this.tabHeap.Text = "Heap Scan"; + this.tabHeap.UseVisualStyleBackColor = true; + // + // textHeapMS + // + this.textHeapMS.Location = new System.Drawing.Point(88, 8); + this.textHeapMS.Name = "textHeapMS"; + this.textHeapMS.Size = new System.Drawing.Size(100, 20); + this.textHeapMS.TabIndex = 0; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(8, 11); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(74, 13); + this.label4.TabIndex = 1; + this.label4.Text = "Minimum Size:"; + // + // tabStruct + // + this.tabStruct.Controls.Add(this.textStructAlign); + this.tabStruct.Controls.Add(this.label5); + this.tabStruct.Controls.Add(this.label3); + this.tabStruct.Controls.Add(this.listStructName); + this.tabStruct.Location = new System.Drawing.Point(4, 22); + this.tabStruct.Name = "tabStruct"; + this.tabStruct.Padding = new System.Windows.Forms.Padding(3); + this.tabStruct.Size = new System.Drawing.Size(485, 285); + this.tabStruct.TabIndex = 4; + this.tabStruct.Text = "Struct Search"; + this.tabStruct.UseVisualStyleBackColor = true; + // + // textStructAlign + // + this.textStructAlign.Location = new System.Drawing.Point(68, 259); + this.textStructAlign.Name = "textStructAlign"; + this.textStructAlign.Size = new System.Drawing.Size(100, 20); + this.textStructAlign.TabIndex = 1; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(6, 262); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(56, 13); + this.label5.TabIndex = 3; + this.label5.Text = "Alignment:"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(6, 6); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(38, 13); + this.label3.TabIndex = 2; + this.label3.Text = "Struct:"; + // + // listStructName + // + this.listStructName.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listStructName.FormattingEnabled = true; + this.listStructName.IntegralHeight = false; + this.listStructName.Location = new System.Drawing.Point(50, 6); + this.listStructName.Name = "listStructName"; + this.listStructName.Size = new System.Drawing.Size(429, 247); + this.listStructName.TabIndex = 0; + // + // checkPrivate + // + this.checkPrivate.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.checkPrivate.AutoSize = true; + this.checkPrivate.Checked = true; + this.checkPrivate.CheckState = System.Windows.Forms.CheckState.Checked; + this.checkPrivate.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkPrivate.Location = new System.Drawing.Point(73, 328); + this.checkPrivate.Name = "checkPrivate"; + this.checkPrivate.Size = new System.Drawing.Size(65, 18); + this.checkPrivate.TabIndex = 2; + this.checkPrivate.Text = "Private"; + this.checkPrivate.UseVisualStyleBackColor = true; + // + // checkImage + // + this.checkImage.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.checkImage.AutoSize = true; + this.checkImage.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkImage.Location = new System.Drawing.Point(138, 328); + this.checkImage.Name = "checkImage"; + this.checkImage.Size = new System.Drawing.Size(61, 18); + this.checkImage.TabIndex = 3; + this.checkImage.Text = "Image"; + this.checkImage.UseVisualStyleBackColor = true; + // + // checkMapped + // + this.checkMapped.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.checkMapped.AutoSize = true; + this.checkMapped.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkMapped.Location = new System.Drawing.Point(199, 328); + this.checkMapped.Name = "checkMapped"; + this.checkMapped.Size = new System.Drawing.Size(71, 18); + this.checkMapped.TabIndex = 4; + this.checkMapped.Text = "Mapped"; + this.checkMapped.UseVisualStyleBackColor = true; + // + // label1 + // + this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 330); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(55, 13); + this.label1.TabIndex = 1; + this.label1.Text = "Search in:"; + // + // buttonOK + // + this.buttonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonOK.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonOK.Location = new System.Drawing.Point(349, 342); + this.buttonOK.Name = "buttonOK"; + this.buttonOK.Size = new System.Drawing.Size(75, 23); + this.buttonOK.TabIndex = 5; + this.buttonOK.Text = "&OK"; + this.buttonOK.UseVisualStyleBackColor = true; + this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click); + // + // buttonCancel + // + this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonCancel.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonCancel.Location = new System.Drawing.Point(430, 342); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.TabIndex = 6; + this.buttonCancel.Text = "Cancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click); + // + // SearchWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(517, 377); + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.buttonOK); + this.Controls.Add(this.label1); + this.Controls.Add(this.checkMapped); + this.Controls.Add(this.checkImage); + this.Controls.Add(this.checkPrivate); + this.Controls.Add(this.tabControl); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "SearchWindow"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "Edit Search"; + this.tabControl.ResumeLayout(false); + this.tabLiteral.ResumeLayout(false); + this.tabLiteral.PerformLayout(); + this.tabRegex.ResumeLayout(false); + this.tabRegex.PerformLayout(); + this.tabString.ResumeLayout(false); + this.tabString.PerformLayout(); + this.tabHeap.ResumeLayout(false); + this.tabHeap.PerformLayout(); + this.tabStruct.ResumeLayout(false); + this.tabStruct.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TabControl tabControl; + private System.Windows.Forms.TabPage tabLiteral; + private System.Windows.Forms.TabPage tabRegex; + private System.Windows.Forms.TabPage tabString; + private System.Windows.Forms.TabPage tabHeap; + private Be.Windows.Forms.HexBox hexBoxSearch; + private ProcessHacker.Components.UtilitiesButton utilitiesButtonLiteral; + private System.Windows.Forms.CheckBox checkPrivate; + private System.Windows.Forms.CheckBox checkImage; + private System.Windows.Forms.CheckBox checkMapped; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Button buttonOK; + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.CheckBox checkIgnoreCase; + private System.Windows.Forms.TextBox textRegex; + private System.Windows.Forms.TextBox textStringMS; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox textHeapMS; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.CheckBox checkNoOverlap; + private System.Windows.Forms.TabPage tabStruct; + private System.Windows.Forms.TextBox textStructAlign; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.ListBox listStructName; + private System.Windows.Forms.CheckBox checkUnicode; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/SearchWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/SearchWindow.cs new file mode 100644 index 000000000..d742edfba --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/SearchWindow.cs @@ -0,0 +1,184 @@ +/* + * Process Hacker - + * search options window + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Text; +using System.Windows.Forms; + +namespace ProcessHacker +{ + public partial class SearchWindow : Form + { + private SearchOptions _so; + private List _oldresults; + private int _pid; + + public SearchWindow(int PID, SearchOptions so) + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + foreach (string s in Program.Structs.Keys) + listStructName.Items.Add(s); + + if (listStructName.Items.Count > 0) + listStructName.SelectedItem = listStructName.Items[0]; + + _pid = PID; + + hexBoxSearch.ByteProvider = new Be.Windows.Forms.DynamicByteProvider((byte[])so.Searcher.Params["text"]); + textRegex.Text = (string)so.Searcher.Params["regex"]; + textStringMS.Text = (string)so.Searcher.Params["s_ms"]; + checkUnicode.Checked = (bool)so.Searcher.Params["unicode"]; + textHeapMS.Text = (string)so.Searcher.Params["h_ms"]; + checkNoOverlap.Checked = (bool)so.Searcher.Params["nooverlap"]; + checkIgnoreCase.Checked = (bool)so.Searcher.Params["ignorecase"]; + checkPrivate.Checked = (bool)so.Searcher.Params["private"]; + checkImage.Checked = (bool)so.Searcher.Params["image"]; + checkMapped.Checked = (bool)so.Searcher.Params["mapped"]; + listStructName.SelectedItem = so.Searcher.Params["struct"]; + textStructAlign.Text = (string)so.Searcher.Params["struct_align"]; + + switch (so.Type) + { + case SearchType.Literal: + tabControl.SelectedTab = tabLiteral; + break; + case SearchType.Regex: + tabControl.SelectedTab = tabRegex; + break; + case SearchType.String: + tabControl.SelectedTab = tabString; + break; + case SearchType.Heap: + tabControl.SelectedTab = tabHeap; + break; + case SearchType.Struct: + tabControl.SelectedTab = tabStruct; + break; + } + + _oldresults = so.Searcher.Results; + + FocusTab(); + } + + public SearchOptions SearchOptions + { + get { return _so; } + } + + private void buttonOK_Click(object sender, EventArgs e) + { + byte[] text = new byte[hexBoxSearch.ByteProvider.Length]; + + for (int i = 0; i < hexBoxSearch.ByteProvider.Length; i++) + text[i] = hexBoxSearch.ByteProvider.ReadByte(i); + + if (tabControl.SelectedTab == tabLiteral) + { + _so = new SearchOptions(_pid, SearchType.Literal); + } + else if (tabControl.SelectedTab == tabRegex) + { + _so = new SearchOptions(_pid, SearchType.Regex); + } + else if (tabControl.SelectedTab == tabString) + { + _so = new SearchOptions(_pid, SearchType.String); + } + else if (tabControl.SelectedTab == tabHeap) + { + _so = new SearchOptions(_pid, SearchType.Heap); + } + else if (tabControl.SelectedTab == tabStruct) + { + _so = new SearchOptions(_pid, SearchType.Struct); + } + + _so.Searcher.Params["text"] = text; + _so.Searcher.Params["regex"] = textRegex.Text; + _so.Searcher.Params["s_ms"] = textStringMS.Text; + _so.Searcher.Params["unicode"] = checkUnicode.Checked; + _so.Searcher.Params["h_ms"] = textHeapMS.Text; + _so.Searcher.Params["nooverlap"] = checkNoOverlap.Checked; + _so.Searcher.Params["ignorecase"] = checkIgnoreCase.Checked; + _so.Searcher.Params["private"] = checkPrivate.Checked; + _so.Searcher.Params["image"] = checkImage.Checked; + _so.Searcher.Params["mapped"] = checkMapped.Checked; + if (listStructName.SelectedItem != null) + _so.Searcher.Params["struct"] = listStructName.SelectedItem.ToString(); + _so.Searcher.Params["struct_align"] = textStructAlign.Text; + + _so.Searcher.Results = _oldresults; + + this.DialogResult = DialogResult.OK; + this.Close(); + } + + private void buttonCancel_Click(object sender, EventArgs e) + { + this.DialogResult = DialogResult.Cancel; + this.Close(); + } + + private void tabControl_SelectedIndexChanged(object sender, EventArgs e) + { + FocusTab(); + } + + private void FocusTab() + { + if (tabControl.SelectedTab != tabLiteral && tabControl.SelectedTab != tabRegex) + this.AcceptButton = buttonOK; + else + this.AcceptButton = null; + + if (tabControl.SelectedTab == tabLiteral) + { + hexBoxSearch.Select(); + } + else if (tabControl.SelectedTab == tabRegex) + { + // HACK + textRegex.Focus(); + textRegex.Select(); + textRegex.Select(textRegex.Text.Length, 0); + textRegex.Focus(); + } + else if (tabControl.SelectedTab == tabString) + { + textStringMS.SelectAll(); + textStringMS.Select(); + } + else if (tabControl.SelectedTab == tabHeap) + { + textHeapMS.SelectAll(); + textHeapMS.Select(); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/SearchWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/SearchWindow.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/SearchWindow.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/ServiceWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/ServiceWindow.Designer.cs new file mode 100644 index 000000000..0c7ec4cdb --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ServiceWindow.Designer.cs @@ -0,0 +1,60 @@ +namespace ProcessHacker +{ + partial class ServiceWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + _serviceProps.Dispose(); + + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ServiceWindow)); + this.SuspendLayout(); + // + // ServiceWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(412, 398); + this.DoubleBuffered = true; + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ServiceWindow"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Service"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.ServiceWindow_FormClosing); + this.ResumeLayout(false); + + } + + #endregion + + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/ServiceWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/ServiceWindow.cs new file mode 100644 index 000000000..e08460fdf --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ServiceWindow.cs @@ -0,0 +1,65 @@ +/* + * Process Hacker - + * service properties window + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Windows.Forms; +using ProcessHacker.Components; + +namespace ProcessHacker +{ + public partial class ServiceWindow : Form + { + private ServiceProperties _serviceProps; + + public ServiceWindow(string service) + : this(new string[] { service }) + { } + + public ServiceWindow(string[] services) + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + _serviceProps = new ServiceProperties(services); + _serviceProps.Dock = DockStyle.Fill; + _serviceProps.NeedsClose += new EventHandler(_serviceProps_NeedsClose); + this.Controls.Add(_serviceProps); + this.Text = _serviceProps.Text; + this.AcceptButton = _serviceProps.ApplyButton; + + if (services.Length == 1) + _serviceProps.ApplyButtonText = "&OK"; + } + + private void _serviceProps_NeedsClose(object sender, EventArgs e) + { + this.Close(); + } + + private void ServiceWindow_FormClosing(object sender, FormClosingEventArgs e) + { + _serviceProps.SaveSettings(); + _serviceProps.Dispose(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/ServiceWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/ServiceWindow.resx new file mode 100644 index 000000000..8b9ee9a60 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ServiceWindow.resx @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABsbGxjV1dXv1BQUL9RUVFjAHwg6wN6Hf8AeBQEAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAbm5uKWlpaQ55eXkCgICA6ry8vP+xsbH/Wlpa6gGCKutCoF7/A3gg1AB4 + GAYAAAAAAAAAAAAAAAAAAAAAgICAm25ubv1jY2PndXV1GSGWUP8bkEn/FY5D/xCKOv85nl3/f8CV/0Wi + Yf8JdiPtAHgYBwAAAAAAAAAAo6Oje7u7u//e3t7/paWl/4KCgvQomlr/j8qo/4zIpP+JxaD/h8Sd/2m1 + hP+BwZb/R6Rl/wd4JOoAeBoJAAAAAKqqqn2lpaX+1dXV/8TExP/Ly8v/MJ5i/5PNrP9uuY3/areI/2W1 + hP9gsn//ZrSB/4LBl/87n1v/AH4k+QAAAAAAAAAAq6urhcTExP/AwMD/xMTE/zaiav+Vzq//k82s/5DL + qf+Py6f/c7uP/4nHoP9FpGf/B4Y0+wGCLAGioqLNjo6O45+fn+7Pz8//xcXF/8zMzP88pG7/NqJs/DKg + ZvwvnGH+VK57/5DLqf9OqnP/F41E/1dXV+NSUlLNvr6+/eLi4v/S0tL/xcXF/83Nzf+wsLD/kpKSRAAA + AAAAAAAAlJSURDmfZ/9ZsoD/J5dW/7+/v//S0tL/YGBg/cPDw/3p6en/1tbW/8nJyf/Ozs7/pKSk/4OD + g0QAAAAAAAAAAJmZmUQ/o2//MJ5k/7m5uf/FxcX/3d3d/2pqav3IyMjNw8PD47+/v+7Y2Nj/zc3N/7u7 + u/+BgYHGdnZ2RH19fUSOjo7GwsLC/8HBwf/Nzc3/i4uL7oaGhuOCgoLNAAAAAAAAAADExMSF1NTU/8zM + zP/Jycn/ubm5/5ubm/+goKD/wcHB/8XFxf/AwMD/tra2/4iIiIUAAAAAAAAAAAAAAADKysp9w8PD/tzc + 3P/U1NT/2dnZ/9vb2//W1tb/1NTU/9nZ2f/S0tL/y8vL/8jIyP94eHj+cHBwfQAAAAAAAAAA0NDQe9zc + 3P/t7e3/29vb/8HBwfS9vb3+1tbW/9TU1P+vr6/+q6ur9MvLy//n5+f/tra2/4qKinsAAAAAAAAAAAAA + AADR0dGbzs7O/crKyufFxcUZwcHB597e3v/d3d3/sbGx57CwsBmrq6vnpqam/aKiopsAAAAAAAAAAAAA + AAAAAAAAAAAAANHR0SnOzs4Oy8vLAsfHx+rl5eX/5OTk/6urq+q1tbUCsbGxDqysrCkAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADLy8tjx8fHv8PDw7++vr5jAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA/AesQeADrEHAAaxBgACsQYAArEHAAKxBAACsQQGArEEBgKxBAACsQcADrEGAAaxBgAGsQcAD + rEHgB6xB/D+sQQ== + + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/SessionInformationWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/SessionInformationWindow.Designer.cs new file mode 100644 index 000000000..bede8aeb2 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/SessionInformationWindow.Designer.cs @@ -0,0 +1,251 @@ +namespace ProcessHacker +{ + partial class SessionInformationWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.label5 = new System.Windows.Forms.Label(); + this.label6 = new System.Windows.Forms.Label(); + this.labelUsername = new System.Windows.Forms.Label(); + this.labelSessionId = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.labelState = new System.Windows.Forms.Label(); + this.labelClientName = new System.Windows.Forms.Label(); + this.labelClientAddress = new System.Windows.Forms.Label(); + this.labelClientDisplayResolution = new System.Windows.Forms.Label(); + this.buttonClose = new System.Windows.Forms.Button(); + this.tableLayoutPanel1.SuspendLayout(); + this.SuspendLayout(); + // + // label1 + // + this.label1.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(3, 4); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(61, 13); + this.label1.TabIndex = 0; + this.label1.Text = "User name:"; + // + // label2 + // + this.label2.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(3, 26); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(61, 13); + this.label2.TabIndex = 0; + this.label2.Text = "Session ID:"; + // + // label3 + // + this.label3.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(3, 48); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(35, 13); + this.label3.TabIndex = 0; + this.label3.Text = "State:"; + // + // label4 + // + this.label4.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(3, 70); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(65, 13); + this.label4.TabIndex = 0; + this.label4.Text = "Client name:"; + // + // label5 + // + this.label5.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(3, 92); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(76, 13); + this.label5.TabIndex = 0; + this.label5.Text = "Client address:"; + // + // label6 + // + this.label6.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(3, 114); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(119, 13); + this.label6.TabIndex = 0; + this.label6.Text = "Client display resolution:"; + // + // labelUsername + // + this.labelUsername.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.labelUsername.AutoSize = true; + this.labelUsername.Location = new System.Drawing.Point(128, 4); + this.labelUsername.Name = "labelUsername"; + this.labelUsername.Size = new System.Drawing.Size(24, 13); + this.labelUsername.TabIndex = 1; + this.labelUsername.Text = "n/a"; + // + // labelSessionId + // + this.labelSessionId.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.labelSessionId.AutoSize = true; + this.labelSessionId.Location = new System.Drawing.Point(128, 26); + this.labelSessionId.Name = "labelSessionId"; + this.labelSessionId.Size = new System.Drawing.Size(24, 13); + this.labelSessionId.TabIndex = 1; + this.labelSessionId.Text = "n/a"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.tableLayoutPanel1.ColumnCount = 2; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Controls.Add(this.label1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.label2, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.labelUsername, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.label3, 0, 2); + this.tableLayoutPanel1.Controls.Add(this.label6, 0, 5); + this.tableLayoutPanel1.Controls.Add(this.label4, 0, 3); + this.tableLayoutPanel1.Controls.Add(this.label5, 0, 4); + this.tableLayoutPanel1.Controls.Add(this.labelSessionId, 1, 1); + this.tableLayoutPanel1.Controls.Add(this.labelState, 1, 2); + this.tableLayoutPanel1.Controls.Add(this.labelClientName, 1, 3); + this.tableLayoutPanel1.Controls.Add(this.labelClientAddress, 1, 4); + this.tableLayoutPanel1.Controls.Add(this.labelClientDisplayResolution, 1, 5); + this.tableLayoutPanel1.Location = new System.Drawing.Point(12, 12); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 6; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(309, 132); + this.tableLayoutPanel1.TabIndex = 2; + // + // labelState + // + this.labelState.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.labelState.AutoSize = true; + this.labelState.Location = new System.Drawing.Point(128, 48); + this.labelState.Name = "labelState"; + this.labelState.Size = new System.Drawing.Size(24, 13); + this.labelState.TabIndex = 1; + this.labelState.Text = "n/a"; + // + // labelClientName + // + this.labelClientName.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.labelClientName.AutoSize = true; + this.labelClientName.Location = new System.Drawing.Point(128, 70); + this.labelClientName.Name = "labelClientName"; + this.labelClientName.Size = new System.Drawing.Size(24, 13); + this.labelClientName.TabIndex = 1; + this.labelClientName.Text = "n/a"; + // + // labelClientAddress + // + this.labelClientAddress.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.labelClientAddress.AutoSize = true; + this.labelClientAddress.Location = new System.Drawing.Point(128, 92); + this.labelClientAddress.Name = "labelClientAddress"; + this.labelClientAddress.Size = new System.Drawing.Size(24, 13); + this.labelClientAddress.TabIndex = 1; + this.labelClientAddress.Text = "n/a"; + // + // labelClientDisplayResolution + // + this.labelClientDisplayResolution.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.labelClientDisplayResolution.AutoSize = true; + this.labelClientDisplayResolution.Location = new System.Drawing.Point(128, 114); + this.labelClientDisplayResolution.Name = "labelClientDisplayResolution"; + this.labelClientDisplayResolution.Size = new System.Drawing.Size(24, 13); + this.labelClientDisplayResolution.TabIndex = 1; + this.labelClientDisplayResolution.Text = "n/a"; + // + // buttonClose + // + this.buttonClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonClose.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonClose.Location = new System.Drawing.Point(246, 152); + this.buttonClose.Name = "buttonClose"; + this.buttonClose.Size = new System.Drawing.Size(75, 23); + this.buttonClose.TabIndex = 3; + this.buttonClose.Text = "Close"; + this.buttonClose.UseVisualStyleBackColor = true; + this.buttonClose.Click += new System.EventHandler(this.buttonClose_Click); + // + // SessionInformationWindow + // + this.AcceptButton = this.buttonClose; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(333, 187); + this.Controls.Add(this.buttonClose); + this.Controls.Add(this.tableLayoutPanel1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "SessionInformationWindow"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Session Information"; + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.Label labelUsername; + private System.Windows.Forms.Label labelSessionId; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.Label labelState; + private System.Windows.Forms.Label labelClientName; + private System.Windows.Forms.Label labelClientAddress; + private System.Windows.Forms.Label labelClientDisplayResolution; + private System.Windows.Forms.Button buttonClose; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/SessionInformationWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/SessionInformationWindow.cs new file mode 100644 index 000000000..605f9687c --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/SessionInformationWindow.cs @@ -0,0 +1,36 @@ +using System; +using System.Windows.Forms; +using ProcessHacker.Native.Objects; + +namespace ProcessHacker +{ + public partial class SessionInformationWindow : Form + { + public SessionInformationWindow(TerminalServerSession session) + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + labelUsername.Text = session.DomainName + "\\" + session.UserName; + labelSessionId.Text = session.SessionId.ToString(); + labelState.Text = session.State.ToString(); + + if (!string.IsNullOrEmpty(session.ClientName)) + labelClientName.Text = session.ClientName; + if (session.ClientAddress != null) + labelClientAddress.Text = session.ClientAddress.ToString(); + if (session.ClientDisplay.ColorDepth != 0 && + session.ClientDisplay.ColorDepth != 2) // HACK + labelClientDisplayResolution.Text = + session.ClientDisplay.HorizontalResolution + "x" + + session.ClientDisplay.VerticalResolution + "@" + + session.ClientDisplay.ColorDepth; + } + + private void buttonClose_Click(object sender, EventArgs e) + { + this.Close(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/SessionInformationWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/SessionInformationWindow.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/SessionInformationWindow.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/StructWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/StructWindow.Designer.cs new file mode 100644 index 000000000..574beb547 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/StructWindow.Designer.cs @@ -0,0 +1,78 @@ +namespace ProcessHacker +{ + partial class StructWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(StructWindow)); + this.buttonClose = new System.Windows.Forms.Button(); + this.panel = new System.Windows.Forms.Panel(); + this.SuspendLayout(); + // + // buttonClose + // + this.buttonClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonClose.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonClose.Location = new System.Drawing.Point(485, 410); + this.buttonClose.Name = "buttonClose"; + this.buttonClose.Size = new System.Drawing.Size(75, 23); + this.buttonClose.TabIndex = 0; + this.buttonClose.Text = "&Close"; + this.buttonClose.UseVisualStyleBackColor = true; + this.buttonClose.Click += new System.EventHandler(this.buttonClose_Click); + // + // panel + // + this.panel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel.Location = new System.Drawing.Point(12, 12); + this.panel.Name = "panel"; + this.panel.Size = new System.Drawing.Size(548, 392); + this.panel.TabIndex = 1; + // + // StructWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(572, 445); + this.Controls.Add(this.panel); + this.Controls.Add(this.buttonClose); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.Name = "StructWindow"; + this.Text = "Struct"; + this.Load += new System.EventHandler(this.StructWindow_Load); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Button buttonClose; + private System.Windows.Forms.Panel panel; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/StructWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/StructWindow.cs new file mode 100644 index 000000000..5864a8fc3 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/StructWindow.cs @@ -0,0 +1,63 @@ +/* + * Process Hacker - + * struct viewer window + * + * Copyright (C) 2008 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 . + */ + +using System; +using System.Windows.Forms; +using ProcessHacker.Components; +using ProcessHacker.Structs; + +namespace ProcessHacker +{ + public partial class StructWindow : Form + { + private int _pid; + private IntPtr _address; + private StructDef _struct; + + public StructWindow(int pid, IntPtr address, StructDef struc) + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + _pid = pid; + _address = address; + _struct = struc; + } + + private void StructWindow_Load(object sender, EventArgs e) + { + StructViewer sv = new StructViewer(_pid, _address, _struct); + + if (sv.Error) + this.Close(); + + sv.Dock = DockStyle.Fill; + panel.Controls.Add(sv); + } + + private void buttonClose_Click(object sender, EventArgs e) + { + this.Close(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/StructWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/StructWindow.resx new file mode 100644 index 000000000..117a2c160 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/StructWindow.resx @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9/f3AZl8Z2Sgd1b0sX9V/659Uf+gdFL2lHZfcwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlntlPZ96WuexgFf/y6qI/9GzlP+6jWL/tIZZ/6p2 + TP+adFXrknVgRgAAAAAAAAAAAAAAAAAAAABrjW0Ua45tCKx+Vf7Vup7/1rqd/9O3m//RspP/tohc/7mN + Yf+3jGD/sYBV/6d0TP4AAAAA9/f3AWyPbmNglGT0YqFp/2CgaP+wfVH/4c23/9i/pP/Yv6b/1Lmc/7eL + X/+2iV//t4xg/7mNYf+wfVH/bY5xPWeVa+dlomv/kr+Y/53Ho/9wq3f/rn1Q/+PQu//awqr/07ed/8ei + fP/Al27/tYhb/7aJX/+5jWH/sH9T/2Keav6oza7/pcyr/6HJqP+YxJ7/aqhz/617Tv/cyK//vp6A/7eM + ZP/Rso7/0bKO/7qPZf+7kGf/tolf/7B9Uf9hoGj/v9rE/6zQsv+qzrD/ncil/2ypdf+Uen3/WWDI/09X + 4/9OVeD/V17I/493g/+6j2X/0bKO/8Whev+od07+X59n/8Teyf+z1Lj/o8mp/4Cqmf9gbML/T1fg/2Vn + 6/+SkvT/YGLq/1da5P9IUdz/X2K9/6WIfv/AmXD/pIRqyFyeZP+41r3/hrmO/3Crd/9SWNz/ZWnr/5eV + 9P+QkPP/iInw/1pe5/9eYen/XGDo/1BX5P9IU9j+lX11Q6WLdgpjn2r+hbmO/5jFof9zrHv/Tlbi/7Ow + +f+WlfT/kpL0/4uM8P9bX+j/W2Dn/1xg6P9eYen/Tlbi/2x0ujAAAAAAdJ15yHuzhP91rn3/bqp3/01T + 4f+zsPn/lJX1/2Vp6/9ucOz/bXHs/1lb5f9bYOf/XmHp/1BX4v9sdLowAAAAAH2efwpylHQ7a45uW22n + dv9LUeD/oaH0/2lr7P9gYur/lpL3/5aS9/9jZ+n/ZGXq/1tg5/9OVuL/bHS6MAAAAAAAAAAAAAAAAAAA + AAAAAAAAU1nb/nt78v+Wkvf/Y2fp/1FX4/9RV+P/Y2fp/5aS9/97e/L/TFXZ/mx0uiYAAAAAAAAAAAAA + AAAAAAAAAAAAAHJ3zshtbuz/ZWfr/15h6f93d/D/c3Pw/15h6f9oauv/bnDs/3F2zMgAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAB/h8oKc3vAO2xzvFtgYuP/UFbi/1BW4v9eYeP/a3O7XnN6wDt/h8oKAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA/gOsQfwArEHwAKxBgACsQQAArEEAAKxBAACsQQAArEEAAKxBAAGsQQABrEEAAaxB8AGsQfAD + rEHwA6xB//+sQQ== + + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/SysInfoWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/SysInfoWindow.Designer.cs new file mode 100644 index 000000000..aa45adb08 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/SysInfoWindow.Designer.cs @@ -0,0 +1,1715 @@ +namespace ProcessHacker +{ + partial class SysInfoWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SysInfoWindow)); + this.gboxCPUPlotter = new System.Windows.Forms.GroupBox(); + this.tableCPUs = new System.Windows.Forms.TableLayoutPanel(); + this.plotterCPU = new ProcessHacker.Components.Plotter(); + this.tableGraphs = new System.Windows.Forms.TableLayoutPanel(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.plotterIO = new ProcessHacker.Components.Plotter(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.plotterMemory = new ProcessHacker.Components.Plotter(); + this.groupBox11 = new System.Windows.Forms.GroupBox(); + this.indicatorPhysical = new ProcessHacker.Components.Indicator(); + this.groupBox12 = new System.Windows.Forms.GroupBox(); + this.indicatorIO = new ProcessHacker.Components.Indicator(); + this.groupBox13 = new System.Windows.Forms.GroupBox(); + this.indicatorCpu = new ProcessHacker.Components.Indicator(); + this.checkShowOneGraphPerCPU = new System.Windows.Forms.CheckBox(); + this.flowInfo = new System.Windows.Forms.FlowLayoutPanel(); + this.groupBox3 = new System.Windows.Forms.GroupBox(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.labelTotalsUptime = new System.Windows.Forms.Label(); + this.label6 = new System.Windows.Forms.Label(); + this.label8 = new System.Windows.Forms.Label(); + this.label9 = new System.Windows.Forms.Label(); + this.labelTotalsProcesses = new System.Windows.Forms.Label(); + this.labelTotalsThreads = new System.Windows.Forms.Label(); + this.labelTotalsHandles = new System.Windows.Forms.Label(); + this.label34 = new System.Windows.Forms.Label(); + this.groupBox4 = new System.Windows.Forms.GroupBox(); + this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.labelCCC = new System.Windows.Forms.Label(); + this.labelCCP = new System.Windows.Forms.Label(); + this.labelCCL = new System.Windows.Forms.Label(); + this.groupBox5 = new System.Windows.Forms.GroupBox(); + this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel(); + this.label4 = new System.Windows.Forms.Label(); + this.label7 = new System.Windows.Forms.Label(); + this.labelPMC = new System.Windows.Forms.Label(); + this.labelPMT = new System.Windows.Forms.Label(); + this.label19 = new System.Windows.Forms.Label(); + this.labelPSC = new System.Windows.Forms.Label(); + this.groupBox6 = new System.Windows.Forms.GroupBox(); + this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel(); + this.label15 = new System.Windows.Forms.Label(); + this.labelCacheMaximum = new System.Windows.Forms.Label(); + this.label13 = new System.Windows.Forms.Label(); + this.labelCacheMinimum = new System.Windows.Forms.Label(); + this.label5 = new System.Windows.Forms.Label(); + this.label10 = new System.Windows.Forms.Label(); + this.labelCacheCurrent = new System.Windows.Forms.Label(); + this.labelCachePeak = new System.Windows.Forms.Label(); + this.groupBox7 = new System.Windows.Forms.GroupBox(); + this.tableLayoutPanel5 = new System.Windows.Forms.TableLayoutPanel(); + this.label14 = new System.Windows.Forms.Label(); + this.label17 = new System.Windows.Forms.Label(); + this.label18 = new System.Windows.Forms.Label(); + this.labelKPPPU = new System.Windows.Forms.Label(); + this.labelKPPA = new System.Windows.Forms.Label(); + this.label12 = new System.Windows.Forms.Label(); + this.labelKPPVU = new System.Windows.Forms.Label(); + this.labelKPPF = new System.Windows.Forms.Label(); + this.label29 = new System.Windows.Forms.Label(); + this.labelKPPL = new System.Windows.Forms.Label(); + this.label33 = new System.Windows.Forms.Label(); + this.labelKPNPL = new System.Windows.Forms.Label(); + this.labelKPNPF = new System.Windows.Forms.Label(); + this.label23 = new System.Windows.Forms.Label(); + this.labelKPNPA = new System.Windows.Forms.Label(); + this.label21 = new System.Windows.Forms.Label(); + this.labelKPNPU = new System.Windows.Forms.Label(); + this.label11 = new System.Windows.Forms.Label(); + this.groupBox8 = new System.Windows.Forms.GroupBox(); + this.tableLayoutPanel6 = new System.Windows.Forms.TableLayoutPanel(); + this.label20 = new System.Windows.Forms.Label(); + this.labelPFCache = new System.Windows.Forms.Label(); + this.label24 = new System.Windows.Forms.Label(); + this.label25 = new System.Windows.Forms.Label(); + this.labelPFDZ = new System.Windows.Forms.Label(); + this.label27 = new System.Windows.Forms.Label(); + this.label28 = new System.Windows.Forms.Label(); + this.labelPFTotal = new System.Windows.Forms.Label(); + this.labelPFTrans = new System.Windows.Forms.Label(); + this.label31 = new System.Windows.Forms.Label(); + this.labelPFCOW = new System.Windows.Forms.Label(); + this.labelPFCacheTrans = new System.Windows.Forms.Label(); + this.groupBox9 = new System.Windows.Forms.GroupBox(); + this.tableLayoutPanel7 = new System.Windows.Forms.TableLayoutPanel(); + this.label16 = new System.Windows.Forms.Label(); + this.labelIOOB = new System.Windows.Forms.Label(); + this.label22 = new System.Windows.Forms.Label(); + this.label26 = new System.Windows.Forms.Label(); + this.labelIOO = new System.Windows.Forms.Label(); + this.label30 = new System.Windows.Forms.Label(); + this.label32 = new System.Windows.Forms.Label(); + this.labelIOR = new System.Windows.Forms.Label(); + this.labelIOW = new System.Windows.Forms.Label(); + this.label35 = new System.Windows.Forms.Label(); + this.labelIORB = new System.Windows.Forms.Label(); + this.labelIOWB = new System.Windows.Forms.Label(); + this.groupBox10 = new System.Windows.Forms.GroupBox(); + this.tableLayoutPanel8 = new System.Windows.Forms.TableLayoutPanel(); + this.label37 = new System.Windows.Forms.Label(); + this.label38 = new System.Windows.Forms.Label(); + this.labelCPUContextSwitches = new System.Windows.Forms.Label(); + this.labelCPUSystemCalls = new System.Windows.Forms.Label(); + this.label41 = new System.Windows.Forms.Label(); + this.labelCPUInterrupts = new System.Windows.Forms.Label(); + this.checkAlwaysOnTop = new System.Windows.Forms.CheckBox(); + this.gboxCPUPlotter.SuspendLayout(); + this.tableGraphs.SuspendLayout(); + this.groupBox2.SuspendLayout(); + this.groupBox1.SuspendLayout(); + this.groupBox11.SuspendLayout(); + this.groupBox12.SuspendLayout(); + this.groupBox13.SuspendLayout(); + this.flowInfo.SuspendLayout(); + this.groupBox3.SuspendLayout(); + this.tableLayoutPanel1.SuspendLayout(); + this.groupBox4.SuspendLayout(); + this.tableLayoutPanel2.SuspendLayout(); + this.groupBox5.SuspendLayout(); + this.tableLayoutPanel3.SuspendLayout(); + this.groupBox6.SuspendLayout(); + this.tableLayoutPanel4.SuspendLayout(); + this.groupBox7.SuspendLayout(); + this.tableLayoutPanel5.SuspendLayout(); + this.groupBox8.SuspendLayout(); + this.tableLayoutPanel6.SuspendLayout(); + this.groupBox9.SuspendLayout(); + this.tableLayoutPanel7.SuspendLayout(); + this.groupBox10.SuspendLayout(); + this.tableLayoutPanel8.SuspendLayout(); + this.SuspendLayout(); + // + // gboxCPUPlotter + // + this.gboxCPUPlotter.Controls.Add(this.tableCPUs); + this.gboxCPUPlotter.Controls.Add(this.plotterCPU); + this.gboxCPUPlotter.Dock = System.Windows.Forms.DockStyle.Fill; + this.gboxCPUPlotter.Location = new System.Drawing.Point(89, 3); + this.gboxCPUPlotter.Name = "gboxCPUPlotter"; + this.gboxCPUPlotter.Size = new System.Drawing.Size(726, 62); + this.gboxCPUPlotter.TabIndex = 2; + this.gboxCPUPlotter.TabStop = false; + this.gboxCPUPlotter.Text = "CPU Usage (Kernel, User)"; + // + // tableCPUs + // + this.tableCPUs.ColumnCount = 1; + this.tableCPUs.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableCPUs.Location = new System.Drawing.Point(436, 34); + this.tableCPUs.Name = "tableCPUs"; + this.tableCPUs.RowCount = 1; + this.tableCPUs.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableCPUs.Size = new System.Drawing.Size(46, 20); + this.tableCPUs.TabIndex = 3; + this.tableCPUs.Visible = false; + // + // plotterCPU + // + this.plotterCPU.BackColor = System.Drawing.Color.Black; + this.plotterCPU.Data1 = null; + this.plotterCPU.Data2 = null; + this.plotterCPU.Dock = System.Windows.Forms.DockStyle.Fill; + this.plotterCPU.GridColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(128)))), ((int)(((byte)(64))))); + this.plotterCPU.GridSize = new System.Drawing.Size(12, 12); + this.plotterCPU.LineColor1 = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(255)))), ((int)(((byte)(0))))); + this.plotterCPU.LineColor2 = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(0)))), ((int)(((byte)(0))))); + this.plotterCPU.Location = new System.Drawing.Point(3, 16); + this.plotterCPU.LongData1 = null; + this.plotterCPU.LongData2 = null; + this.plotterCPU.MinMaxValue = ((long)(0)); + this.plotterCPU.MoveStep = -1; + this.plotterCPU.Name = "plotterCPU"; + this.plotterCPU.OverlaySecondLine = false; + this.plotterCPU.ShowGrid = true; + this.plotterCPU.Size = new System.Drawing.Size(720, 43); + this.plotterCPU.TabIndex = 0; + this.plotterCPU.TextBoxColor = System.Drawing.Color.FromArgb(((int)(((byte)(127)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0))))); + this.plotterCPU.TextColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(255)))), ((int)(((byte)(0))))); + this.plotterCPU.TextMargin = new System.Windows.Forms.Padding(3); + this.plotterCPU.TextPadding = new System.Windows.Forms.Padding(3); + this.plotterCPU.TextPosition = System.Drawing.ContentAlignment.TopLeft; + this.plotterCPU.UseLongData = false; + this.plotterCPU.UseSecondLine = true; + // + // tableGraphs + // + this.tableGraphs.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.tableGraphs.ColumnCount = 2; + this.tableGraphs.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 86F)); + this.tableGraphs.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableGraphs.Controls.Add(this.gboxCPUPlotter, 1, 0); + this.tableGraphs.Controls.Add(this.groupBox2, 1, 2); + this.tableGraphs.Controls.Add(this.groupBox1, 1, 3); + this.tableGraphs.Controls.Add(this.groupBox11, 0, 3); + this.tableGraphs.Controls.Add(this.groupBox12, 0, 2); + this.tableGraphs.Controls.Add(this.groupBox13, 0, 0); + this.tableGraphs.Controls.Add(this.checkShowOneGraphPerCPU, 1, 1); + this.tableGraphs.Location = new System.Drawing.Point(12, 12); + this.tableGraphs.Name = "tableGraphs"; + this.tableGraphs.RowCount = 4; + this.tableGraphs.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); + this.tableGraphs.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableGraphs.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); + this.tableGraphs.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); + this.tableGraphs.Size = new System.Drawing.Size(818, 228); + this.tableGraphs.TabIndex = 3; + // + // groupBox2 + // + this.groupBox2.Controls.Add(this.plotterIO); + this.groupBox2.Dock = System.Windows.Forms.DockStyle.Fill; + this.groupBox2.Location = new System.Drawing.Point(89, 95); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(726, 62); + this.groupBox2.TabIndex = 5; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "I/O (R+O, W)"; + // + // plotterIO + // + this.plotterIO.BackColor = System.Drawing.Color.Black; + this.plotterIO.Data1 = null; + this.plotterIO.Data2 = null; + this.plotterIO.Dock = System.Windows.Forms.DockStyle.Fill; + this.plotterIO.GridColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(128)))), ((int)(((byte)(64))))); + this.plotterIO.GridSize = new System.Drawing.Size(12, 12); + this.plotterIO.LineColor1 = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(255)))), ((int)(((byte)(0))))); + this.plotterIO.LineColor2 = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(0)))), ((int)(((byte)(0))))); + this.plotterIO.Location = new System.Drawing.Point(3, 16); + this.plotterIO.LongData1 = null; + this.plotterIO.LongData2 = null; + this.plotterIO.MinMaxValue = ((long)(0)); + this.plotterIO.MoveStep = -1; + this.plotterIO.Name = "plotterIO"; + this.plotterIO.OverlaySecondLine = true; + this.plotterIO.ShowGrid = true; + this.plotterIO.Size = new System.Drawing.Size(720, 43); + this.plotterIO.TabIndex = 5; + this.plotterIO.TextBoxColor = System.Drawing.Color.FromArgb(((int)(((byte)(127)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0))))); + this.plotterIO.TextColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(255)))), ((int)(((byte)(0))))); + this.plotterIO.TextMargin = new System.Windows.Forms.Padding(3); + this.plotterIO.TextPadding = new System.Windows.Forms.Padding(3); + this.plotterIO.TextPosition = System.Drawing.ContentAlignment.TopLeft; + this.plotterIO.UseLongData = true; + this.plotterIO.UseSecondLine = true; + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.plotterMemory); + this.groupBox1.Dock = System.Windows.Forms.DockStyle.Fill; + this.groupBox1.Location = new System.Drawing.Point(89, 163); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(726, 62); + this.groupBox1.TabIndex = 7; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Commit, Physical Memory"; + // + // plotterMemory + // + this.plotterMemory.BackColor = System.Drawing.Color.Black; + this.plotterMemory.Data1 = null; + this.plotterMemory.Data2 = null; + this.plotterMemory.Dock = System.Windows.Forms.DockStyle.Fill; + this.plotterMemory.GridColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(128)))), ((int)(((byte)(64))))); + this.plotterMemory.GridSize = new System.Drawing.Size(12, 12); + this.plotterMemory.LineColor1 = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(255)))), ((int)(((byte)(0))))); + this.plotterMemory.LineColor2 = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(0)))), ((int)(((byte)(0))))); + this.plotterMemory.Location = new System.Drawing.Point(3, 16); + this.plotterMemory.LongData1 = null; + this.plotterMemory.LongData2 = null; + this.plotterMemory.MinMaxValue = ((long)(0)); + this.plotterMemory.MoveStep = -1; + this.plotterMemory.Name = "plotterMemory"; + this.plotterMemory.OverlaySecondLine = true; + this.plotterMemory.ShowGrid = true; + this.plotterMemory.Size = new System.Drawing.Size(720, 43); + this.plotterMemory.TabIndex = 5; + this.plotterMemory.TextBoxColor = System.Drawing.Color.FromArgb(((int)(((byte)(127)))), ((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0))))); + this.plotterMemory.TextColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(255)))), ((int)(((byte)(0))))); + this.plotterMemory.TextMargin = new System.Windows.Forms.Padding(3); + this.plotterMemory.TextPadding = new System.Windows.Forms.Padding(3); + this.plotterMemory.TextPosition = System.Drawing.ContentAlignment.TopLeft; + this.plotterMemory.UseLongData = true; + this.plotterMemory.UseSecondLine = true; + // + // groupBox11 + // + this.groupBox11.Controls.Add(this.indicatorPhysical); + this.groupBox11.Dock = System.Windows.Forms.DockStyle.Fill; + this.groupBox11.Location = new System.Drawing.Point(3, 163); + this.groupBox11.Name = "groupBox11"; + this.groupBox11.Size = new System.Drawing.Size(80, 62); + this.groupBox11.TabIndex = 9; + this.groupBox11.TabStop = false; + this.groupBox11.Text = "Physical"; + // + // indicatorPhysical + // + this.indicatorPhysical.BackColor = System.Drawing.Color.Black; + this.indicatorPhysical.Color1 = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(0)))), ((int)(((byte)(0))))); + this.indicatorPhysical.Color2 = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(255)))), ((int)(((byte)(0))))); + this.indicatorPhysical.Data1 = ((long)(0)); + this.indicatorPhysical.Data2 = ((long)(0)); + this.indicatorPhysical.Dock = System.Windows.Forms.DockStyle.Fill; + this.indicatorPhysical.ForeColor = System.Drawing.Color.Lime; + this.indicatorPhysical.GraphWidth = 33; + this.indicatorPhysical.Location = new System.Drawing.Point(3, 16); + this.indicatorPhysical.Maximum = ((long)(2147483647)); + this.indicatorPhysical.Minimum = ((long)(0)); + this.indicatorPhysical.Name = "indicatorPhysical"; + this.indicatorPhysical.Size = new System.Drawing.Size(74, 43); + this.indicatorPhysical.TabIndex = 8; + this.indicatorPhysical.TextValue = ""; + // + // groupBox12 + // + this.groupBox12.Controls.Add(this.indicatorIO); + this.groupBox12.Dock = System.Windows.Forms.DockStyle.Fill; + this.groupBox12.Location = new System.Drawing.Point(3, 95); + this.groupBox12.Name = "groupBox12"; + this.groupBox12.Size = new System.Drawing.Size(80, 62); + this.groupBox12.TabIndex = 10; + this.groupBox12.TabStop = false; + this.groupBox12.Text = "I/O (R+O)"; + // + // indicatorIO + // + this.indicatorIO.BackColor = System.Drawing.Color.Black; + this.indicatorIO.Color1 = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(0)))), ((int)(((byte)(0))))); + this.indicatorIO.Color2 = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(255)))), ((int)(((byte)(0))))); + this.indicatorIO.Data1 = ((long)(0)); + this.indicatorIO.Data2 = ((long)(0)); + this.indicatorIO.Dock = System.Windows.Forms.DockStyle.Fill; + this.indicatorIO.ForeColor = System.Drawing.Color.Lime; + this.indicatorIO.GraphWidth = 33; + this.indicatorIO.Location = new System.Drawing.Point(3, 16); + this.indicatorIO.Maximum = ((long)(2147483647)); + this.indicatorIO.Minimum = ((long)(0)); + this.indicatorIO.Name = "indicatorIO"; + this.indicatorIO.Size = new System.Drawing.Size(74, 43); + this.indicatorIO.TabIndex = 8; + this.indicatorIO.TextValue = ""; + // + // groupBox13 + // + this.groupBox13.Controls.Add(this.indicatorCpu); + this.groupBox13.Dock = System.Windows.Forms.DockStyle.Fill; + this.groupBox13.Location = new System.Drawing.Point(3, 3); + this.groupBox13.Name = "groupBox13"; + this.groupBox13.Size = new System.Drawing.Size(80, 62); + this.groupBox13.TabIndex = 11; + this.groupBox13.TabStop = false; + this.groupBox13.Text = "CPU Usage"; + // + // indicatorCpu + // + this.indicatorCpu.BackColor = System.Drawing.Color.Black; + this.indicatorCpu.Color1 = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(0)))), ((int)(((byte)(0))))); + this.indicatorCpu.Color2 = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(255)))), ((int)(((byte)(0))))); + this.indicatorCpu.Data1 = ((long)(500000000)); + this.indicatorCpu.Data2 = ((long)(500000000)); + this.indicatorCpu.Dock = System.Windows.Forms.DockStyle.Fill; + this.indicatorCpu.ForeColor = System.Drawing.Color.Lime; + this.indicatorCpu.GraphWidth = 33; + this.indicatorCpu.Location = new System.Drawing.Point(3, 16); + this.indicatorCpu.Maximum = ((long)(2147483647)); + this.indicatorCpu.Minimum = ((long)(0)); + this.indicatorCpu.Name = "indicatorCpu"; + this.indicatorCpu.Size = new System.Drawing.Size(74, 43); + this.indicatorCpu.TabIndex = 8; + this.indicatorCpu.TextValue = ""; + // + // checkShowOneGraphPerCPU + // + this.checkShowOneGraphPerCPU.AutoSize = true; + this.checkShowOneGraphPerCPU.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkShowOneGraphPerCPU.Location = new System.Drawing.Point(89, 71); + this.checkShowOneGraphPerCPU.Name = "checkShowOneGraphPerCPU"; + this.checkShowOneGraphPerCPU.Size = new System.Drawing.Size(153, 18); + this.checkShowOneGraphPerCPU.TabIndex = 3; + this.checkShowOneGraphPerCPU.Text = "Show one graph per CPU"; + this.checkShowOneGraphPerCPU.UseVisualStyleBackColor = true; + this.checkShowOneGraphPerCPU.CheckedChanged += new System.EventHandler(this.checkShowOneGraphPerCPU_CheckedChanged); + // + // flowInfo + // + this.flowInfo.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.flowInfo.AutoScroll = true; + this.flowInfo.Controls.Add(this.groupBox3); + this.flowInfo.Controls.Add(this.groupBox4); + this.flowInfo.Controls.Add(this.groupBox5); + this.flowInfo.Controls.Add(this.groupBox6); + this.flowInfo.Controls.Add(this.groupBox7); + this.flowInfo.Controls.Add(this.groupBox8); + this.flowInfo.Controls.Add(this.groupBox9); + this.flowInfo.Controls.Add(this.groupBox10); + this.flowInfo.FlowDirection = System.Windows.Forms.FlowDirection.TopDown; + this.flowInfo.Location = new System.Drawing.Point(12, 246); + this.flowInfo.Name = "flowInfo"; + this.flowInfo.Size = new System.Drawing.Size(818, 256); + this.flowInfo.TabIndex = 4; + // + // groupBox3 + // + this.groupBox3.Controls.Add(this.tableLayoutPanel1); + this.groupBox3.Location = new System.Drawing.Point(3, 3); + this.groupBox3.Name = "groupBox3"; + this.groupBox3.Size = new System.Drawing.Size(195, 84); + this.groupBox3.TabIndex = 1; + this.groupBox3.TabStop = false; + this.groupBox3.Text = "System"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 2; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel1.Controls.Add(this.labelTotalsUptime, 0, 3); + this.tableLayoutPanel1.Controls.Add(this.label6, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.label8, 0, 1); + this.tableLayoutPanel1.Controls.Add(this.label9, 0, 2); + this.tableLayoutPanel1.Controls.Add(this.labelTotalsProcesses, 1, 0); + this.tableLayoutPanel1.Controls.Add(this.labelTotalsThreads, 1, 1); + this.tableLayoutPanel1.Controls.Add(this.labelTotalsHandles, 1, 2); + this.tableLayoutPanel1.Controls.Add(this.label34, 0, 3); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(3, 16); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 4; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(189, 65); + this.tableLayoutPanel1.TabIndex = 1; + // + // labelTotalsUptime + // + this.labelTotalsUptime.AutoEllipsis = true; + this.labelTotalsUptime.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelTotalsUptime.Location = new System.Drawing.Point(65, 48); + this.labelTotalsUptime.Name = "labelTotalsUptime"; + this.labelTotalsUptime.Size = new System.Drawing.Size(121, 17); + this.labelTotalsUptime.TabIndex = 2; + this.labelTotalsUptime.Text = "value"; + this.labelTotalsUptime.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // label6 + // + this.label6.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(3, 1); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(56, 13); + this.label6.TabIndex = 1; + this.label6.Text = "Processes"; + // + // label8 + // + this.label8.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label8.AutoSize = true; + this.label8.Location = new System.Drawing.Point(3, 17); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(46, 13); + this.label8.TabIndex = 1; + this.label8.Text = "Threads"; + // + // label9 + // + this.label9.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label9.AutoSize = true; + this.label9.Location = new System.Drawing.Point(3, 33); + this.label9.Name = "label9"; + this.label9.Size = new System.Drawing.Size(46, 13); + this.label9.TabIndex = 1; + this.label9.Text = "Handles"; + // + // labelTotalsProcesses + // + this.labelTotalsProcesses.AutoEllipsis = true; + this.labelTotalsProcesses.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelTotalsProcesses.Location = new System.Drawing.Point(65, 0); + this.labelTotalsProcesses.Name = "labelTotalsProcesses"; + this.labelTotalsProcesses.Size = new System.Drawing.Size(121, 16); + this.labelTotalsProcesses.TabIndex = 1; + this.labelTotalsProcesses.Text = "value"; + this.labelTotalsProcesses.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // labelTotalsThreads + // + this.labelTotalsThreads.AutoEllipsis = true; + this.labelTotalsThreads.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelTotalsThreads.Location = new System.Drawing.Point(65, 16); + this.labelTotalsThreads.Name = "labelTotalsThreads"; + this.labelTotalsThreads.Size = new System.Drawing.Size(121, 16); + this.labelTotalsThreads.TabIndex = 1; + this.labelTotalsThreads.Text = "value"; + this.labelTotalsThreads.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // labelTotalsHandles + // + this.labelTotalsHandles.AutoEllipsis = true; + this.labelTotalsHandles.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelTotalsHandles.Location = new System.Drawing.Point(65, 32); + this.labelTotalsHandles.Name = "labelTotalsHandles"; + this.labelTotalsHandles.Size = new System.Drawing.Size(121, 16); + this.labelTotalsHandles.TabIndex = 1; + this.labelTotalsHandles.Text = "value"; + this.labelTotalsHandles.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // label34 + // + this.label34.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label34.AutoSize = true; + this.label34.Location = new System.Drawing.Point(3, 50); + this.label34.Name = "label34"; + this.label34.Size = new System.Drawing.Size(40, 13); + this.label34.TabIndex = 1; + this.label34.Text = "Uptime"; + // + // groupBox4 + // + this.groupBox4.Controls.Add(this.tableLayoutPanel2); + this.groupBox4.Location = new System.Drawing.Point(3, 93); + this.groupBox4.Name = "groupBox4"; + this.groupBox4.Size = new System.Drawing.Size(195, 78); + this.groupBox4.TabIndex = 2; + this.groupBox4.TabStop = false; + this.groupBox4.Text = "Commit Charge"; + // + // tableLayoutPanel2 + // + this.tableLayoutPanel2.ColumnCount = 2; + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel2.Controls.Add(this.label1, 0, 0); + this.tableLayoutPanel2.Controls.Add(this.label2, 0, 1); + this.tableLayoutPanel2.Controls.Add(this.label3, 0, 2); + this.tableLayoutPanel2.Controls.Add(this.labelCCC, 1, 0); + this.tableLayoutPanel2.Controls.Add(this.labelCCP, 1, 1); + this.tableLayoutPanel2.Controls.Add(this.labelCCL, 1, 2); + this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 16); + this.tableLayoutPanel2.Name = "tableLayoutPanel2"; + this.tableLayoutPanel2.RowCount = 3; + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel2.Size = new System.Drawing.Size(189, 59); + this.tableLayoutPanel2.TabIndex = 1; + // + // label1 + // + this.label1.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(3, 3); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(41, 13); + this.label1.TabIndex = 1; + this.label1.Text = "Current"; + // + // label2 + // + this.label2.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(3, 22); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(32, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Peak"; + // + // label3 + // + this.label3.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(3, 42); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(28, 13); + this.label3.TabIndex = 1; + this.label3.Text = "Limit"; + // + // labelCCC + // + this.labelCCC.AutoEllipsis = true; + this.labelCCC.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelCCC.Location = new System.Drawing.Point(50, 0); + this.labelCCC.Name = "labelCCC"; + this.labelCCC.Size = new System.Drawing.Size(136, 19); + this.labelCCC.TabIndex = 1; + this.labelCCC.Text = "value"; + this.labelCCC.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // labelCCP + // + this.labelCCP.AutoEllipsis = true; + this.labelCCP.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelCCP.Location = new System.Drawing.Point(50, 19); + this.labelCCP.Name = "labelCCP"; + this.labelCCP.Size = new System.Drawing.Size(136, 19); + this.labelCCP.TabIndex = 1; + this.labelCCP.Text = "value"; + this.labelCCP.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // labelCCL + // + this.labelCCL.AutoEllipsis = true; + this.labelCCL.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelCCL.Location = new System.Drawing.Point(50, 38); + this.labelCCL.Name = "labelCCL"; + this.labelCCL.Size = new System.Drawing.Size(136, 21); + this.labelCCL.TabIndex = 1; + this.labelCCL.Text = "value"; + this.labelCCL.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // groupBox5 + // + this.groupBox5.Controls.Add(this.tableLayoutPanel3); + this.groupBox5.Location = new System.Drawing.Point(3, 177); + this.groupBox5.Name = "groupBox5"; + this.groupBox5.Size = new System.Drawing.Size(195, 75); + this.groupBox5.TabIndex = 3; + this.groupBox5.TabStop = false; + this.groupBox5.Text = "Physical Memory"; + // + // tableLayoutPanel3 + // + this.tableLayoutPanel3.ColumnCount = 2; + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel3.Controls.Add(this.label4, 0, 0); + this.tableLayoutPanel3.Controls.Add(this.label7, 0, 2); + this.tableLayoutPanel3.Controls.Add(this.labelPMC, 1, 0); + this.tableLayoutPanel3.Controls.Add(this.labelPMT, 1, 2); + this.tableLayoutPanel3.Controls.Add(this.label19, 0, 1); + this.tableLayoutPanel3.Controls.Add(this.labelPSC, 1, 1); + this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel3.Location = new System.Drawing.Point(3, 16); + this.tableLayoutPanel3.Name = "tableLayoutPanel3"; + this.tableLayoutPanel3.RowCount = 3; + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 33.33333F)); + this.tableLayoutPanel3.Size = new System.Drawing.Size(189, 56); + this.tableLayoutPanel3.TabIndex = 1; + // + // label4 + // + this.label4.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(3, 2); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(41, 13); + this.label4.TabIndex = 1; + this.label4.Text = "Current"; + // + // label7 + // + this.label7.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(3, 39); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(31, 13); + this.label7.TabIndex = 1; + this.label7.Text = "Total"; + // + // labelPMC + // + this.labelPMC.AutoEllipsis = true; + this.labelPMC.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelPMC.Location = new System.Drawing.Point(84, 0); + this.labelPMC.Name = "labelPMC"; + this.labelPMC.Size = new System.Drawing.Size(102, 18); + this.labelPMC.TabIndex = 1; + this.labelPMC.Text = "value"; + this.labelPMC.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // labelPMT + // + this.labelPMT.AutoEllipsis = true; + this.labelPMT.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelPMT.Location = new System.Drawing.Point(84, 36); + this.labelPMT.Name = "labelPMT"; + this.labelPMT.Size = new System.Drawing.Size(102, 20); + this.labelPMT.TabIndex = 1; + this.labelPMT.Text = "value"; + this.labelPMT.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // label19 + // + this.label19.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label19.AutoSize = true; + this.label19.Location = new System.Drawing.Point(3, 20); + this.label19.Name = "label19"; + this.label19.Size = new System.Drawing.Size(75, 13); + this.label19.TabIndex = 1; + this.label19.Text = "System Cache"; + // + // labelPSC + // + this.labelPSC.AutoEllipsis = true; + this.labelPSC.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelPSC.Location = new System.Drawing.Point(84, 18); + this.labelPSC.Name = "labelPSC"; + this.labelPSC.Size = new System.Drawing.Size(102, 18); + this.labelPSC.TabIndex = 1; + this.labelPSC.Text = "value"; + this.labelPSC.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // groupBox6 + // + this.groupBox6.Controls.Add(this.tableLayoutPanel4); + this.groupBox6.Location = new System.Drawing.Point(204, 3); + this.groupBox6.Name = "groupBox6"; + this.groupBox6.Size = new System.Drawing.Size(195, 85); + this.groupBox6.TabIndex = 4; + this.groupBox6.TabStop = false; + this.groupBox6.Text = "File Cache"; + // + // tableLayoutPanel4 + // + this.tableLayoutPanel4.ColumnCount = 2; + this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel4.Controls.Add(this.label15, 0, 3); + this.tableLayoutPanel4.Controls.Add(this.labelCacheMaximum, 0, 3); + this.tableLayoutPanel4.Controls.Add(this.label13, 0, 2); + this.tableLayoutPanel4.Controls.Add(this.labelCacheMinimum, 0, 2); + this.tableLayoutPanel4.Controls.Add(this.label5, 0, 0); + this.tableLayoutPanel4.Controls.Add(this.label10, 0, 1); + this.tableLayoutPanel4.Controls.Add(this.labelCacheCurrent, 1, 0); + this.tableLayoutPanel4.Controls.Add(this.labelCachePeak, 1, 1); + this.tableLayoutPanel4.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel4.Location = new System.Drawing.Point(3, 16); + this.tableLayoutPanel4.Name = "tableLayoutPanel4"; + this.tableLayoutPanel4.RowCount = 4; + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 25F)); + this.tableLayoutPanel4.Size = new System.Drawing.Size(189, 66); + this.tableLayoutPanel4.TabIndex = 1; + // + // label15 + // + this.label15.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label15.AutoSize = true; + this.label15.Location = new System.Drawing.Point(3, 50); + this.label15.Name = "label15"; + this.label15.Size = new System.Drawing.Size(51, 13); + this.label15.TabIndex = 5; + this.label15.Text = "Maximum"; + // + // labelCacheMaximum + // + this.labelCacheMaximum.AutoEllipsis = true; + this.labelCacheMaximum.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelCacheMaximum.Location = new System.Drawing.Point(60, 48); + this.labelCacheMaximum.Name = "labelCacheMaximum"; + this.labelCacheMaximum.Size = new System.Drawing.Size(130, 18); + this.labelCacheMaximum.TabIndex = 4; + this.labelCacheMaximum.Text = "value"; + this.labelCacheMaximum.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // label13 + // + this.label13.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label13.AutoSize = true; + this.label13.Location = new System.Drawing.Point(3, 33); + this.label13.Name = "label13"; + this.label13.Size = new System.Drawing.Size(48, 13); + this.label13.TabIndex = 3; + this.label13.Text = "Minimum"; + // + // labelCacheMinimum + // + this.labelCacheMinimum.AutoEllipsis = true; + this.labelCacheMinimum.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelCacheMinimum.Location = new System.Drawing.Point(60, 32); + this.labelCacheMinimum.Name = "labelCacheMinimum"; + this.labelCacheMinimum.Size = new System.Drawing.Size(130, 16); + this.labelCacheMinimum.TabIndex = 2; + this.labelCacheMinimum.Text = "value"; + this.labelCacheMinimum.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // label5 + // + this.label5.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(3, 1); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(41, 13); + this.label5.TabIndex = 1; + this.label5.Text = "Current"; + // + // label10 + // + this.label10.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label10.AutoSize = true; + this.label10.Location = new System.Drawing.Point(3, 17); + this.label10.Name = "label10"; + this.label10.Size = new System.Drawing.Size(32, 13); + this.label10.TabIndex = 1; + this.label10.Text = "Peak"; + // + // labelCacheCurrent + // + this.labelCacheCurrent.AutoEllipsis = true; + this.labelCacheCurrent.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelCacheCurrent.Location = new System.Drawing.Point(60, 0); + this.labelCacheCurrent.Name = "labelCacheCurrent"; + this.labelCacheCurrent.Size = new System.Drawing.Size(130, 16); + this.labelCacheCurrent.TabIndex = 1; + this.labelCacheCurrent.Text = "value"; + this.labelCacheCurrent.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // labelCachePeak + // + this.labelCachePeak.AutoEllipsis = true; + this.labelCachePeak.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelCachePeak.Location = new System.Drawing.Point(60, 16); + this.labelCachePeak.Name = "labelCachePeak"; + this.labelCachePeak.Size = new System.Drawing.Size(130, 16); + this.labelCachePeak.TabIndex = 1; + this.labelCachePeak.Text = "value"; + this.labelCachePeak.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // groupBox7 + // + this.groupBox7.Controls.Add(this.tableLayoutPanel5); + this.groupBox7.Location = new System.Drawing.Point(204, 94); + this.groupBox7.Name = "groupBox7"; + this.groupBox7.Size = new System.Drawing.Size(195, 157); + this.groupBox7.TabIndex = 5; + this.groupBox7.TabStop = false; + this.groupBox7.Text = "Kernel Pools"; + // + // tableLayoutPanel5 + // + this.tableLayoutPanel5.ColumnCount = 2; + this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel5.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel5.Controls.Add(this.label14, 0, 3); + this.tableLayoutPanel5.Controls.Add(this.label17, 0, 0); + this.tableLayoutPanel5.Controls.Add(this.label18, 0, 2); + this.tableLayoutPanel5.Controls.Add(this.labelKPPPU, 1, 0); + this.tableLayoutPanel5.Controls.Add(this.labelKPPA, 1, 2); + this.tableLayoutPanel5.Controls.Add(this.label12, 0, 1); + this.tableLayoutPanel5.Controls.Add(this.labelKPPVU, 1, 1); + this.tableLayoutPanel5.Controls.Add(this.labelKPPF, 1, 3); + this.tableLayoutPanel5.Controls.Add(this.label29, 0, 4); + this.tableLayoutPanel5.Controls.Add(this.labelKPPL, 1, 4); + this.tableLayoutPanel5.Controls.Add(this.label33, 0, 8); + this.tableLayoutPanel5.Controls.Add(this.labelKPNPL, 1, 8); + this.tableLayoutPanel5.Controls.Add(this.labelKPNPF, 1, 7); + this.tableLayoutPanel5.Controls.Add(this.label23, 0, 7); + this.tableLayoutPanel5.Controls.Add(this.labelKPNPA, 1, 6); + this.tableLayoutPanel5.Controls.Add(this.label21, 0, 6); + this.tableLayoutPanel5.Controls.Add(this.labelKPNPU, 1, 5); + this.tableLayoutPanel5.Controls.Add(this.label11, 0, 5); + this.tableLayoutPanel5.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel5.Location = new System.Drawing.Point(3, 16); + this.tableLayoutPanel5.Name = "tableLayoutPanel5"; + this.tableLayoutPanel5.RowCount = 9; + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 11.11111F)); + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 11.11111F)); + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 11.11111F)); + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 11.11111F)); + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 11.11111F)); + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 11.11111F)); + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 11.11111F)); + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 11.11111F)); + this.tableLayoutPanel5.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 11.11111F)); + this.tableLayoutPanel5.Size = new System.Drawing.Size(189, 138); + this.tableLayoutPanel5.TabIndex = 1; + // + // label14 + // + this.label14.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label14.AutoSize = true; + this.label14.Location = new System.Drawing.Point(3, 46); + this.label14.Name = "label14"; + this.label14.Size = new System.Drawing.Size(67, 13); + this.label14.TabIndex = 3; + this.label14.Text = "Paged Frees"; + // + // label17 + // + this.label17.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label17.AutoSize = true; + this.label17.Location = new System.Drawing.Point(3, 1); + this.label17.Name = "label17"; + this.label17.Size = new System.Drawing.Size(67, 13); + this.label17.TabIndex = 1; + this.label17.Text = "Paged Phys."; + // + // label18 + // + this.label18.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label18.AutoSize = true; + this.label18.Location = new System.Drawing.Point(3, 31); + this.label18.Name = "label18"; + this.label18.Size = new System.Drawing.Size(69, 13); + this.label18.TabIndex = 1; + this.label18.Text = "Paged Allocs"; + // + // labelKPPPU + // + this.labelKPPPU.AutoEllipsis = true; + this.labelKPPPU.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelKPPPU.Location = new System.Drawing.Point(104, 0); + this.labelKPPPU.Name = "labelKPPPU"; + this.labelKPPPU.Size = new System.Drawing.Size(82, 15); + this.labelKPPPU.TabIndex = 1; + this.labelKPPPU.Text = "value"; + this.labelKPPPU.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // labelKPPA + // + this.labelKPPA.AutoEllipsis = true; + this.labelKPPA.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelKPPA.Location = new System.Drawing.Point(104, 30); + this.labelKPPA.Name = "labelKPPA"; + this.labelKPPA.Size = new System.Drawing.Size(82, 15); + this.labelKPPA.TabIndex = 1; + this.labelKPPA.Text = "value"; + this.labelKPPA.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // label12 + // + this.label12.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label12.AutoSize = true; + this.label12.Location = new System.Drawing.Point(3, 16); + this.label12.Name = "label12"; + this.label12.Size = new System.Drawing.Size(59, 13); + this.label12.TabIndex = 1; + this.label12.Text = "Paged Virt."; + // + // labelKPPVU + // + this.labelKPPVU.AutoEllipsis = true; + this.labelKPPVU.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelKPPVU.Location = new System.Drawing.Point(104, 15); + this.labelKPPVU.Name = "labelKPPVU"; + this.labelKPPVU.Size = new System.Drawing.Size(82, 15); + this.labelKPPVU.TabIndex = 1; + this.labelKPPVU.Text = "value"; + this.labelKPPVU.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // labelKPPF + // + this.labelKPPF.AutoEllipsis = true; + this.labelKPPF.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelKPPF.Location = new System.Drawing.Point(104, 45); + this.labelKPPF.Name = "labelKPPF"; + this.labelKPPF.Size = new System.Drawing.Size(82, 15); + this.labelKPPF.TabIndex = 2; + this.labelKPPF.Text = "value"; + this.labelKPPF.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // label29 + // + this.label29.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label29.AutoSize = true; + this.label29.Location = new System.Drawing.Point(3, 61); + this.label29.Name = "label29"; + this.label29.Size = new System.Drawing.Size(62, 13); + this.label29.TabIndex = 3; + this.label29.Text = "Paged Limit"; + // + // labelKPPL + // + this.labelKPPL.AutoEllipsis = true; + this.labelKPPL.AutoSize = true; + this.labelKPPL.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelKPPL.Location = new System.Drawing.Point(104, 60); + this.labelKPPL.Name = "labelKPPL"; + this.labelKPPL.Size = new System.Drawing.Size(82, 15); + this.labelKPPL.TabIndex = 10; + this.labelKPPL.Text = "value"; + this.labelKPPL.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // label33 + // + this.label33.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label33.AutoSize = true; + this.label33.Location = new System.Drawing.Point(3, 122); + this.label33.Name = "label33"; + this.label33.Size = new System.Drawing.Size(85, 13); + this.label33.TabIndex = 9; + this.label33.Text = "Non-Paged Limit"; + // + // labelKPNPL + // + this.labelKPNPL.AutoEllipsis = true; + this.labelKPNPL.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelKPNPL.Location = new System.Drawing.Point(104, 120); + this.labelKPNPL.Name = "labelKPNPL"; + this.labelKPNPL.Size = new System.Drawing.Size(82, 18); + this.labelKPNPL.TabIndex = 8; + this.labelKPNPL.Text = "value"; + this.labelKPNPL.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // labelKPNPF + // + this.labelKPNPF.AutoEllipsis = true; + this.labelKPNPF.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelKPNPF.Location = new System.Drawing.Point(104, 105); + this.labelKPNPF.Name = "labelKPNPF"; + this.labelKPNPF.Size = new System.Drawing.Size(82, 15); + this.labelKPNPF.TabIndex = 8; + this.labelKPNPF.Text = "value"; + this.labelKPNPF.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // label23 + // + this.label23.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label23.AutoSize = true; + this.label23.Location = new System.Drawing.Point(3, 106); + this.label23.Name = "label23"; + this.label23.Size = new System.Drawing.Size(90, 13); + this.label23.TabIndex = 9; + this.label23.Text = "Non-Paged Frees"; + // + // labelKPNPA + // + this.labelKPNPA.AutoEllipsis = true; + this.labelKPNPA.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelKPNPA.Location = new System.Drawing.Point(104, 90); + this.labelKPNPA.Name = "labelKPNPA"; + this.labelKPNPA.Size = new System.Drawing.Size(82, 15); + this.labelKPNPA.TabIndex = 6; + this.labelKPNPA.Text = "value"; + this.labelKPNPA.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // label21 + // + this.label21.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label21.AutoSize = true; + this.label21.Location = new System.Drawing.Point(3, 91); + this.label21.Name = "label21"; + this.label21.Size = new System.Drawing.Size(92, 13); + this.label21.TabIndex = 7; + this.label21.Text = "Non-Paged Allocs"; + // + // labelKPNPU + // + this.labelKPNPU.AutoEllipsis = true; + this.labelKPNPU.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelKPNPU.Location = new System.Drawing.Point(104, 75); + this.labelKPNPU.Name = "labelKPNPU"; + this.labelKPNPU.Size = new System.Drawing.Size(82, 15); + this.labelKPNPU.TabIndex = 4; + this.labelKPNPU.Text = "value"; + this.labelKPNPU.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // label11 + // + this.label11.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label11.AutoSize = true; + this.label11.Location = new System.Drawing.Point(3, 76); + this.label11.Name = "label11"; + this.label11.Size = new System.Drawing.Size(95, 13); + this.label11.TabIndex = 5; + this.label11.Text = "Non-Paged Usage"; + // + // groupBox8 + // + this.groupBox8.Controls.Add(this.tableLayoutPanel6); + this.groupBox8.Location = new System.Drawing.Point(405, 3); + this.groupBox8.Name = "groupBox8"; + this.groupBox8.Size = new System.Drawing.Size(195, 121); + this.groupBox8.TabIndex = 6; + this.groupBox8.TabStop = false; + this.groupBox8.Text = "Page Faults"; + // + // tableLayoutPanel6 + // + this.tableLayoutPanel6.ColumnCount = 2; + this.tableLayoutPanel6.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel6.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel6.Controls.Add(this.label20, 0, 5); + this.tableLayoutPanel6.Controls.Add(this.labelPFCache, 0, 5); + this.tableLayoutPanel6.Controls.Add(this.label24, 0, 4); + this.tableLayoutPanel6.Controls.Add(this.label25, 0, 3); + this.tableLayoutPanel6.Controls.Add(this.labelPFDZ, 0, 4); + this.tableLayoutPanel6.Controls.Add(this.label27, 0, 0); + this.tableLayoutPanel6.Controls.Add(this.label28, 0, 2); + this.tableLayoutPanel6.Controls.Add(this.labelPFTotal, 1, 0); + this.tableLayoutPanel6.Controls.Add(this.labelPFTrans, 1, 2); + this.tableLayoutPanel6.Controls.Add(this.label31, 0, 1); + this.tableLayoutPanel6.Controls.Add(this.labelPFCOW, 1, 1); + this.tableLayoutPanel6.Controls.Add(this.labelPFCacheTrans, 1, 3); + this.tableLayoutPanel6.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel6.Location = new System.Drawing.Point(3, 16); + this.tableLayoutPanel6.Name = "tableLayoutPanel6"; + this.tableLayoutPanel6.RowCount = 6; + this.tableLayoutPanel6.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel6.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel6.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel6.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel6.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel6.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel6.Size = new System.Drawing.Size(189, 102); + this.tableLayoutPanel6.TabIndex = 1; + // + // label20 + // + this.label20.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label20.AutoSize = true; + this.label20.Location = new System.Drawing.Point(3, 84); + this.label20.Name = "label20"; + this.label20.Size = new System.Drawing.Size(38, 13); + this.label20.TabIndex = 7; + this.label20.Text = "Cache"; + // + // labelPFCache + // + this.labelPFCache.AutoEllipsis = true; + this.labelPFCache.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelPFCache.Location = new System.Drawing.Point(96, 80); + this.labelPFCache.Name = "labelPFCache"; + this.labelPFCache.Size = new System.Drawing.Size(90, 22); + this.labelPFCache.TabIndex = 6; + this.labelPFCache.Text = "value"; + this.labelPFCache.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // label24 + // + this.label24.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label24.AutoSize = true; + this.label24.Location = new System.Drawing.Point(3, 65); + this.label24.Name = "label24"; + this.label24.Size = new System.Drawing.Size(72, 13); + this.label24.TabIndex = 5; + this.label24.Text = "Demand Zero"; + // + // label25 + // + this.label25.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label25.AutoSize = true; + this.label25.Location = new System.Drawing.Point(3, 49); + this.label25.Name = "label25"; + this.label25.Size = new System.Drawing.Size(87, 13); + this.label25.TabIndex = 3; + this.label25.Text = "Cache Transition"; + // + // labelPFDZ + // + this.labelPFDZ.AutoEllipsis = true; + this.labelPFDZ.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelPFDZ.Location = new System.Drawing.Point(96, 64); + this.labelPFDZ.Name = "labelPFDZ"; + this.labelPFDZ.Size = new System.Drawing.Size(90, 16); + this.labelPFDZ.TabIndex = 4; + this.labelPFDZ.Text = "value"; + this.labelPFDZ.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // label27 + // + this.label27.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label27.AutoSize = true; + this.label27.Location = new System.Drawing.Point(3, 1); + this.label27.Name = "label27"; + this.label27.Size = new System.Drawing.Size(31, 13); + this.label27.TabIndex = 1; + this.label27.Text = "Total"; + // + // label28 + // + this.label28.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label28.AutoSize = true; + this.label28.Location = new System.Drawing.Point(3, 33); + this.label28.Name = "label28"; + this.label28.Size = new System.Drawing.Size(53, 13); + this.label28.TabIndex = 1; + this.label28.Text = "Transition"; + // + // labelPFTotal + // + this.labelPFTotal.AutoEllipsis = true; + this.labelPFTotal.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelPFTotal.Location = new System.Drawing.Point(96, 0); + this.labelPFTotal.Name = "labelPFTotal"; + this.labelPFTotal.Size = new System.Drawing.Size(90, 16); + this.labelPFTotal.TabIndex = 1; + this.labelPFTotal.Text = "value"; + this.labelPFTotal.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // labelPFTrans + // + this.labelPFTrans.AutoEllipsis = true; + this.labelPFTrans.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelPFTrans.Location = new System.Drawing.Point(96, 32); + this.labelPFTrans.Name = "labelPFTrans"; + this.labelPFTrans.Size = new System.Drawing.Size(90, 16); + this.labelPFTrans.TabIndex = 1; + this.labelPFTrans.Text = "value"; + this.labelPFTrans.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // label31 + // + this.label31.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label31.AutoSize = true; + this.label31.Location = new System.Drawing.Point(3, 17); + this.label31.Name = "label31"; + this.label31.Size = new System.Drawing.Size(76, 13); + this.label31.TabIndex = 1; + this.label31.Text = "Copy-On-Write"; + // + // labelPFCOW + // + this.labelPFCOW.AutoEllipsis = true; + this.labelPFCOW.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelPFCOW.Location = new System.Drawing.Point(96, 16); + this.labelPFCOW.Name = "labelPFCOW"; + this.labelPFCOW.Size = new System.Drawing.Size(90, 16); + this.labelPFCOW.TabIndex = 1; + this.labelPFCOW.Text = "value"; + this.labelPFCOW.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // labelPFCacheTrans + // + this.labelPFCacheTrans.AutoEllipsis = true; + this.labelPFCacheTrans.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelPFCacheTrans.Location = new System.Drawing.Point(96, 48); + this.labelPFCacheTrans.Name = "labelPFCacheTrans"; + this.labelPFCacheTrans.Size = new System.Drawing.Size(90, 16); + this.labelPFCacheTrans.TabIndex = 2; + this.labelPFCacheTrans.Text = "value"; + this.labelPFCacheTrans.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // groupBox9 + // + this.groupBox9.Controls.Add(this.tableLayoutPanel7); + this.groupBox9.Location = new System.Drawing.Point(405, 130); + this.groupBox9.Name = "groupBox9"; + this.groupBox9.Size = new System.Drawing.Size(195, 121); + this.groupBox9.TabIndex = 7; + this.groupBox9.TabStop = false; + this.groupBox9.Text = "I/O"; + // + // tableLayoutPanel7 + // + this.tableLayoutPanel7.ColumnCount = 2; + this.tableLayoutPanel7.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel7.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel7.Controls.Add(this.label16, 0, 5); + this.tableLayoutPanel7.Controls.Add(this.labelIOOB, 0, 5); + this.tableLayoutPanel7.Controls.Add(this.label22, 0, 4); + this.tableLayoutPanel7.Controls.Add(this.label26, 0, 3); + this.tableLayoutPanel7.Controls.Add(this.labelIOO, 0, 4); + this.tableLayoutPanel7.Controls.Add(this.label30, 0, 0); + this.tableLayoutPanel7.Controls.Add(this.label32, 0, 2); + this.tableLayoutPanel7.Controls.Add(this.labelIOR, 1, 0); + this.tableLayoutPanel7.Controls.Add(this.labelIOW, 1, 2); + this.tableLayoutPanel7.Controls.Add(this.label35, 0, 1); + this.tableLayoutPanel7.Controls.Add(this.labelIORB, 1, 1); + this.tableLayoutPanel7.Controls.Add(this.labelIOWB, 1, 3); + this.tableLayoutPanel7.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel7.Location = new System.Drawing.Point(3, 16); + this.tableLayoutPanel7.Name = "tableLayoutPanel7"; + this.tableLayoutPanel7.RowCount = 6; + this.tableLayoutPanel7.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel7.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel7.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel7.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel7.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel7.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel7.Size = new System.Drawing.Size(189, 102); + this.tableLayoutPanel7.TabIndex = 1; + // + // label16 + // + this.label16.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label16.AutoSize = true; + this.label16.Location = new System.Drawing.Point(3, 84); + this.label16.Name = "label16"; + this.label16.Size = new System.Drawing.Size(62, 13); + this.label16.TabIndex = 7; + this.label16.Text = "Other Bytes"; + // + // labelIOOB + // + this.labelIOOB.AutoEllipsis = true; + this.labelIOOB.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelIOOB.Location = new System.Drawing.Point(71, 80); + this.labelIOOB.Name = "labelIOOB"; + this.labelIOOB.Size = new System.Drawing.Size(115, 22); + this.labelIOOB.TabIndex = 6; + this.labelIOOB.Text = "value"; + this.labelIOOB.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // label22 + // + this.label22.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label22.AutoSize = true; + this.label22.Location = new System.Drawing.Point(3, 65); + this.label22.Name = "label22"; + this.label22.Size = new System.Drawing.Size(33, 13); + this.label22.TabIndex = 5; + this.label22.Text = "Other"; + // + // label26 + // + this.label26.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label26.AutoSize = true; + this.label26.Location = new System.Drawing.Point(3, 49); + this.label26.Name = "label26"; + this.label26.Size = new System.Drawing.Size(61, 13); + this.label26.TabIndex = 3; + this.label26.Text = "Write Bytes"; + // + // labelIOO + // + this.labelIOO.AutoEllipsis = true; + this.labelIOO.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelIOO.Location = new System.Drawing.Point(71, 64); + this.labelIOO.Name = "labelIOO"; + this.labelIOO.Size = new System.Drawing.Size(115, 16); + this.labelIOO.TabIndex = 4; + this.labelIOO.Text = "value"; + this.labelIOO.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // label30 + // + this.label30.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label30.AutoSize = true; + this.label30.Location = new System.Drawing.Point(3, 1); + this.label30.Name = "label30"; + this.label30.Size = new System.Drawing.Size(38, 13); + this.label30.TabIndex = 1; + this.label30.Text = "Reads"; + // + // label32 + // + this.label32.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label32.AutoSize = true; + this.label32.Location = new System.Drawing.Point(3, 33); + this.label32.Name = "label32"; + this.label32.Size = new System.Drawing.Size(37, 13); + this.label32.TabIndex = 1; + this.label32.Text = "Writes"; + // + // labelIOR + // + this.labelIOR.AutoEllipsis = true; + this.labelIOR.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelIOR.Location = new System.Drawing.Point(71, 0); + this.labelIOR.Name = "labelIOR"; + this.labelIOR.Size = new System.Drawing.Size(115, 16); + this.labelIOR.TabIndex = 1; + this.labelIOR.Text = "value"; + this.labelIOR.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // labelIOW + // + this.labelIOW.AutoEllipsis = true; + this.labelIOW.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelIOW.Location = new System.Drawing.Point(71, 32); + this.labelIOW.Name = "labelIOW"; + this.labelIOW.Size = new System.Drawing.Size(115, 16); + this.labelIOW.TabIndex = 1; + this.labelIOW.Text = "value"; + this.labelIOW.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // label35 + // + this.label35.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label35.AutoSize = true; + this.label35.Location = new System.Drawing.Point(3, 17); + this.label35.Name = "label35"; + this.label35.Size = new System.Drawing.Size(62, 13); + this.label35.TabIndex = 1; + this.label35.Text = "Read Bytes"; + // + // labelIORB + // + this.labelIORB.AutoEllipsis = true; + this.labelIORB.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelIORB.Location = new System.Drawing.Point(71, 16); + this.labelIORB.Name = "labelIORB"; + this.labelIORB.Size = new System.Drawing.Size(115, 16); + this.labelIORB.TabIndex = 1; + this.labelIORB.Text = "value"; + this.labelIORB.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // labelIOWB + // + this.labelIOWB.AutoEllipsis = true; + this.labelIOWB.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelIOWB.Location = new System.Drawing.Point(71, 48); + this.labelIOWB.Name = "labelIOWB"; + this.labelIOWB.Size = new System.Drawing.Size(115, 16); + this.labelIOWB.TabIndex = 2; + this.labelIOWB.Text = "value"; + this.labelIOWB.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // groupBox10 + // + this.groupBox10.AutoSize = true; + this.groupBox10.Controls.Add(this.tableLayoutPanel8); + this.groupBox10.Location = new System.Drawing.Point(606, 3); + this.groupBox10.MinimumSize = new System.Drawing.Size(195, 76); + this.groupBox10.Name = "groupBox10"; + this.groupBox10.Size = new System.Drawing.Size(195, 76); + this.groupBox10.TabIndex = 8; + this.groupBox10.TabStop = false; + this.groupBox10.Text = "CPU"; + // + // tableLayoutPanel8 + // + this.tableLayoutPanel8.AutoSize = true; + this.tableLayoutPanel8.ColumnCount = 2; + this.tableLayoutPanel8.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel8.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel8.Controls.Add(this.label37, 0, 0); + this.tableLayoutPanel8.Controls.Add(this.label38, 0, 2); + this.tableLayoutPanel8.Controls.Add(this.labelCPUContextSwitches, 1, 0); + this.tableLayoutPanel8.Controls.Add(this.labelCPUSystemCalls, 1, 2); + this.tableLayoutPanel8.Controls.Add(this.label41, 0, 1); + this.tableLayoutPanel8.Controls.Add(this.labelCPUInterrupts, 1, 1); + this.tableLayoutPanel8.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel8.Location = new System.Drawing.Point(3, 16); + this.tableLayoutPanel8.Name = "tableLayoutPanel8"; + this.tableLayoutPanel8.RowCount = 3; + this.tableLayoutPanel8.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel8.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel8.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 16.66667F)); + this.tableLayoutPanel8.Size = new System.Drawing.Size(189, 57); + this.tableLayoutPanel8.TabIndex = 1; + // + // label37 + // + this.label37.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label37.AutoSize = true; + this.label37.Location = new System.Drawing.Point(3, 3); + this.label37.Name = "label37"; + this.label37.Size = new System.Drawing.Size(89, 13); + this.label37.TabIndex = 1; + this.label37.Text = "Context Switches"; + // + // label38 + // + this.label38.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label38.AutoSize = true; + this.label38.Location = new System.Drawing.Point(3, 41); + this.label38.Name = "label38"; + this.label38.Size = new System.Drawing.Size(66, 13); + this.label38.TabIndex = 1; + this.label38.Text = "System Calls"; + // + // labelCPUContextSwitches + // + this.labelCPUContextSwitches.AutoEllipsis = true; + this.labelCPUContextSwitches.AutoSize = true; + this.labelCPUContextSwitches.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelCPUContextSwitches.Location = new System.Drawing.Point(98, 0); + this.labelCPUContextSwitches.Name = "labelCPUContextSwitches"; + this.labelCPUContextSwitches.Size = new System.Drawing.Size(88, 19); + this.labelCPUContextSwitches.TabIndex = 1; + this.labelCPUContextSwitches.Text = "value"; + this.labelCPUContextSwitches.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // labelCPUSystemCalls + // + this.labelCPUSystemCalls.AutoEllipsis = true; + this.labelCPUSystemCalls.AutoSize = true; + this.labelCPUSystemCalls.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelCPUSystemCalls.Location = new System.Drawing.Point(98, 38); + this.labelCPUSystemCalls.Name = "labelCPUSystemCalls"; + this.labelCPUSystemCalls.Size = new System.Drawing.Size(88, 19); + this.labelCPUSystemCalls.TabIndex = 1; + this.labelCPUSystemCalls.Text = "value"; + this.labelCPUSystemCalls.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // label41 + // + this.label41.Anchor = System.Windows.Forms.AnchorStyles.Left; + this.label41.AutoSize = true; + this.label41.Location = new System.Drawing.Point(3, 22); + this.label41.Name = "label41"; + this.label41.Size = new System.Drawing.Size(51, 13); + this.label41.TabIndex = 1; + this.label41.Text = "Interrupts"; + // + // labelCPUInterrupts + // + this.labelCPUInterrupts.AutoEllipsis = true; + this.labelCPUInterrupts.AutoSize = true; + this.labelCPUInterrupts.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelCPUInterrupts.Location = new System.Drawing.Point(98, 19); + this.labelCPUInterrupts.Name = "labelCPUInterrupts"; + this.labelCPUInterrupts.Size = new System.Drawing.Size(88, 19); + this.labelCPUInterrupts.TabIndex = 1; + this.labelCPUInterrupts.Text = "value"; + this.labelCPUInterrupts.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // checkAlwaysOnTop + // + this.checkAlwaysOnTop.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.checkAlwaysOnTop.AutoSize = true; + this.checkAlwaysOnTop.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.checkAlwaysOnTop.Location = new System.Drawing.Point(728, 508); + this.checkAlwaysOnTop.Name = "checkAlwaysOnTop"; + this.checkAlwaysOnTop.Size = new System.Drawing.Size(102, 18); + this.checkAlwaysOnTop.TabIndex = 5; + this.checkAlwaysOnTop.Text = "Always on Top"; + this.checkAlwaysOnTop.UseVisualStyleBackColor = true; + this.checkAlwaysOnTop.CheckedChanged += new System.EventHandler(this.checkAlwaysOnTop_CheckedChanged); + // + // SysInfoWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(842, 538); + this.Controls.Add(this.checkAlwaysOnTop); + this.Controls.Add(this.flowInfo); + this.Controls.Add(this.tableGraphs); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MinimumSize = new System.Drawing.Size(200, 500); + this.Name = "SysInfoWindow"; + this.StartPosition = System.Windows.Forms.FormStartPosition.Manual; + this.Text = "System Information"; + this.Paint += new System.Windows.Forms.PaintEventHandler(this.SysInfoWindow_Paint); + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.SysInfoWindow_FormClosing); + this.gboxCPUPlotter.ResumeLayout(false); + this.tableGraphs.ResumeLayout(false); + this.tableGraphs.PerformLayout(); + this.groupBox2.ResumeLayout(false); + this.groupBox1.ResumeLayout(false); + this.groupBox11.ResumeLayout(false); + this.groupBox12.ResumeLayout(false); + this.groupBox13.ResumeLayout(false); + this.flowInfo.ResumeLayout(false); + this.flowInfo.PerformLayout(); + this.groupBox3.ResumeLayout(false); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.groupBox4.ResumeLayout(false); + this.tableLayoutPanel2.ResumeLayout(false); + this.tableLayoutPanel2.PerformLayout(); + this.groupBox5.ResumeLayout(false); + this.tableLayoutPanel3.ResumeLayout(false); + this.tableLayoutPanel3.PerformLayout(); + this.groupBox6.ResumeLayout(false); + this.tableLayoutPanel4.ResumeLayout(false); + this.tableLayoutPanel4.PerformLayout(); + this.groupBox7.ResumeLayout(false); + this.tableLayoutPanel5.ResumeLayout(false); + this.tableLayoutPanel5.PerformLayout(); + this.groupBox8.ResumeLayout(false); + this.tableLayoutPanel6.ResumeLayout(false); + this.tableLayoutPanel6.PerformLayout(); + this.groupBox9.ResumeLayout(false); + this.tableLayoutPanel7.ResumeLayout(false); + this.tableLayoutPanel7.PerformLayout(); + this.groupBox10.ResumeLayout(false); + this.groupBox10.PerformLayout(); + this.tableLayoutPanel8.ResumeLayout(false); + this.tableLayoutPanel8.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private ProcessHacker.Components.Plotter plotterCPU; + private System.Windows.Forms.GroupBox gboxCPUPlotter; + private System.Windows.Forms.TableLayoutPanel tableCPUs; + private System.Windows.Forms.TableLayoutPanel tableGraphs; + private System.Windows.Forms.CheckBox checkShowOneGraphPerCPU; + private System.Windows.Forms.GroupBox groupBox2; + private ProcessHacker.Components.Plotter plotterIO; + private System.Windows.Forms.GroupBox groupBox1; + private ProcessHacker.Components.Plotter plotterMemory; + private System.Windows.Forms.FlowLayoutPanel flowInfo; + private System.Windows.Forms.GroupBox groupBox3; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.Label label8; + private System.Windows.Forms.Label label9; + private System.Windows.Forms.Label labelTotalsProcesses; + private System.Windows.Forms.Label labelTotalsThreads; + private System.Windows.Forms.Label labelTotalsHandles; + private System.Windows.Forms.GroupBox groupBox4; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label labelCCC; + private System.Windows.Forms.Label labelCCP; + private System.Windows.Forms.Label labelCCL; + private System.Windows.Forms.GroupBox groupBox5; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.Label labelPMC; + private System.Windows.Forms.Label labelPMT; + private System.Windows.Forms.GroupBox groupBox6; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel4; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.Label label10; + private System.Windows.Forms.Label labelCacheCurrent; + private System.Windows.Forms.Label labelCachePeak; + private System.Windows.Forms.Label label15; + private System.Windows.Forms.Label labelCacheMaximum; + private System.Windows.Forms.Label label13; + private System.Windows.Forms.Label labelCacheMinimum; + private System.Windows.Forms.GroupBox groupBox7; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel5; + private System.Windows.Forms.Label label11; + private System.Windows.Forms.Label labelKPNPU; + private System.Windows.Forms.Label label14; + private System.Windows.Forms.Label labelKPPF; + private System.Windows.Forms.Label label17; + private System.Windows.Forms.Label label18; + private System.Windows.Forms.Label labelKPPPU; + private System.Windows.Forms.Label labelKPPA; + private System.Windows.Forms.Label label23; + private System.Windows.Forms.Label labelKPNPF; + private System.Windows.Forms.Label label21; + private System.Windows.Forms.Label labelKPNPA; + private System.Windows.Forms.Label label12; + private System.Windows.Forms.Label labelKPPVU; + private System.Windows.Forms.GroupBox groupBox8; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel6; + private System.Windows.Forms.Label label20; + private System.Windows.Forms.Label labelPFCache; + private System.Windows.Forms.Label label24; + private System.Windows.Forms.Label label25; + private System.Windows.Forms.Label labelPFDZ; + private System.Windows.Forms.Label label27; + private System.Windows.Forms.Label label28; + private System.Windows.Forms.Label labelPFTotal; + private System.Windows.Forms.Label labelPFTrans; + private System.Windows.Forms.Label label31; + private System.Windows.Forms.Label labelPFCOW; + private System.Windows.Forms.Label labelPFCacheTrans; + private System.Windows.Forms.GroupBox groupBox9; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel7; + private System.Windows.Forms.Label label16; + private System.Windows.Forms.Label labelIOOB; + private System.Windows.Forms.Label label22; + private System.Windows.Forms.Label label26; + private System.Windows.Forms.Label labelIOO; + private System.Windows.Forms.Label label30; + private System.Windows.Forms.Label label32; + private System.Windows.Forms.Label labelIOR; + private System.Windows.Forms.Label labelIOW; + private System.Windows.Forms.Label label35; + private System.Windows.Forms.Label labelIORB; + private System.Windows.Forms.Label labelIOWB; + private System.Windows.Forms.GroupBox groupBox10; + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel8; + private System.Windows.Forms.Label label37; + private System.Windows.Forms.Label label38; + private System.Windows.Forms.Label labelCPUContextSwitches; + private System.Windows.Forms.Label labelCPUSystemCalls; + private System.Windows.Forms.Label label41; + private System.Windows.Forms.Label labelCPUInterrupts; + private System.Windows.Forms.CheckBox checkAlwaysOnTop; + private System.Windows.Forms.Label label19; + private System.Windows.Forms.Label labelPSC; + private ProcessHacker.Components.Indicator indicatorCpu; + private ProcessHacker.Components.Indicator indicatorIO; + private ProcessHacker.Components.Indicator indicatorPhysical; + private System.Windows.Forms.GroupBox groupBox11; + private System.Windows.Forms.GroupBox groupBox12; + private System.Windows.Forms.GroupBox groupBox13; + private System.Windows.Forms.Label label29; + private System.Windows.Forms.Label labelKPPL; + private System.Windows.Forms.Label label33; + private System.Windows.Forms.Label labelKPNPL; + private System.Windows.Forms.Label labelTotalsUptime; + private System.Windows.Forms.Label label34; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/SysInfoWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/SysInfoWindow.cs new file mode 100644 index 000000000..26be3bb9f --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/SysInfoWindow.cs @@ -0,0 +1,403 @@ +/* + * Process Hacker - + * system information window + * + * Copyright (C) 2008-2009 wj32 + * Copyright (C) 2008-2009 Dean + * + * 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 . + */ + +using System; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Components; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Symbols; + +namespace ProcessHacker +{ + public partial class SysInfoWindow : Form + { + private static IntPtr _mmSizeOfPagedPoolInBytes; + private static IntPtr _mmMaximumNonPagedPoolInBytes; + + private bool _isFirstPaint = true; + private Components.Plotter[] _cpuPlotters; + private uint _noOfCPUs = Program.ProcessProvider.System.NumberOfProcessors; + private uint _pages = (uint)Program.ProcessProvider.System.NumberOfPhysicalPages; + private uint _pageSize = (uint)Program.ProcessProvider.System.PageSize; + + public SysInfoWindow() + { + InitializeComponent(); + this.AddEscapeToClose(); + + this.Size = Properties.Settings.Default.SysInfoWindowSize; + this.Location = Utils.FitRectangle(new Rectangle( + Properties.Settings.Default.SysInfoWindowLocation, this.Size), this).Location; + + // Load the pool limit addresses. + if ( + _mmSizeOfPagedPoolInBytes == IntPtr.Zero && + KProcessHacker.Instance != null + ) + { + WorkQueue.GlobalQueueWorkItemTag(new Action(() => + { + try + { + SymbolProvider symbols = new SymbolProvider(); + + symbols.LoadModule(Windows.KernelFileName, Windows.KernelBase); + _mmSizeOfPagedPoolInBytes = + symbols.GetSymbolFromName("MmSizeOfPagedPoolInBytes").Address.ToIntPtr(); + _mmMaximumNonPagedPoolInBytes = + symbols.GetSymbolFromName("MmMaximumNonPagedPoolInBytes").Address.ToIntPtr(); + } + catch + { } + }), "load-mm-addresses"); + } + } + + private void SysInfoWindow_Paint(object sender, PaintEventArgs e) + { + if (_isFirstPaint) + { + this.LoadStage1(); + } + + _isFirstPaint = false; + } + + private void LoadStage1() + { + // Maximum physical memory. + indicatorPhysical.Maximum = (int)_pages; + + // Set indicators color + indicatorCpu.Color1 = Properties.Settings.Default.PlotterCPUKernelColor; + indicatorCpu.Color2 = Properties.Settings.Default.PlotterCPUUserColor; + indicatorIO.Color1 = Properties.Settings.Default.PlotterIOROColor; + indicatorPhysical.Color1 = Properties.Settings.Default.PlotterMemoryWSColor; + + + // Set up the plotter controls. + plotterCPU.Data1 = Program.ProcessProvider.FloatHistory["Kernel"]; + plotterCPU.Data2 = Program.ProcessProvider.FloatHistory["User"]; + plotterCPU.GetToolTip = i => + Program.ProcessProvider.MostCpuHistory[i] + "\n" + + ((plotterCPU.Data1[i] + plotterCPU.Data2[i]) * 100).ToString("N2") + + "% (K " + (plotterCPU.Data1[i] * 100).ToString("N2") + + "%, U " + (plotterCPU.Data2[i] * 100).ToString("N2") + "%)" + "\n" + + Program.ProcessProvider.TimeHistory[i].ToString(); + plotterIO.LongData1 = Program.ProcessProvider.LongHistory[SystemStats.IoReadOther]; + plotterIO.LongData2 = Program.ProcessProvider.LongHistory[SystemStats.IoWrite]; + plotterIO.GetToolTip = i => + Program.ProcessProvider.MostIoHistory[i] + "\n" + + "R+O: " + Utils.FormatSize(plotterIO.LongData1[i]) + "\n" + + "W: " + Utils.FormatSize(plotterIO.LongData2[i]) + "\n" + + Program.ProcessProvider.TimeHistory[i].ToString(); + plotterMemory.LongData1 = Program.ProcessProvider.LongHistory[SystemStats.Commit]; + plotterMemory.LongData2 = Program.ProcessProvider.LongHistory[SystemStats.PhysicalMemory]; + plotterMemory.GetToolTip = i => + "Commit: " + Utils.FormatSize(plotterMemory.LongData1[i]) + "\n" + + "Phys. Memory: " + Utils.FormatSize(plotterMemory.LongData2[i]) + "\n" + + Program.ProcessProvider.TimeHistory[i].ToString(); + + // Create a plotter per CPU. + _cpuPlotters = new Plotter[_noOfCPUs]; + tableCPUs.ColumnCount = (int)_noOfCPUs; + tableCPUs.ColumnStyles.Clear(); + tableCPUs.Dock = DockStyle.Fill; + + for (int i = 0; i < _cpuPlotters.Length; i++) + { + Plotter plotter; + + tableCPUs.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 1.0f / _noOfCPUs)); + _cpuPlotters[i] = plotter = new ProcessHacker.Components.Plotter(); + plotter.BackColor = Color.Black; + plotter.Dock = DockStyle.Fill; + plotter.Margin = new Padding(i == 0 ? 0 : 3, 0, 0, 0); // nice spacing + plotter.UseSecondLine = true; + plotter.Data1 = Program.ProcessProvider.FloatHistory[i.ToString() + " Kernel"]; + plotter.Data2 = Program.ProcessProvider.FloatHistory[i.ToString() + " User"]; + plotter.GetToolTip = j => + Program.ProcessProvider.MostCpuHistory[j] + "\n" + + ((plotter.Data1[j] + plotter.Data2[j]) * 100).ToString("N2") + + "% (K " + (plotter.Data1[j] * 100).ToString("N2") + + "%, U " + (plotter.Data2[j] * 100).ToString("N2") + "%)" + "\n" + + Program.ProcessProvider.TimeHistory[j].ToString(); + tableCPUs.Controls.Add(plotter, i, 0); + } + + tableCPUs.Visible = true; + tableCPUs.Visible = false; + checkShowOneGraphPerCPU.Checked = Properties.Settings.Default.ShowOneGraphPerCPU; + + if (_noOfCPUs == 1) + checkShowOneGraphPerCPU.Enabled = false; + + this.UpdateGraphs(); + this.UpdateInfo(); + + Program.ProcessProvider.Updated += + new ProcessSystemProvider.ProviderUpdateOnce(ProcessProvider_Updated); + + //We need todo this here or TopMost property gets over-rided + //by AlwaysOnTopCheckbox + this.SetTopMost(); + } + + private void SysInfoWindow_FormClosing(object sender, FormClosingEventArgs e) + { + if (this.WindowState == FormWindowState.Normal) + { + Properties.Settings.Default.SysInfoWindowLocation = this.Location; + Properties.Settings.Default.SysInfoWindowSize = this.Size; + } + + Program.ProcessProvider.Updated -= + new ProcessSystemProvider.ProviderUpdateOnce(ProcessProvider_Updated); + Properties.Settings.Default.ShowOneGraphPerCPU = checkShowOneGraphPerCPU.Checked; + } + + private void UpdateGraphs() + { + // Update the CPU indicator. + indicatorCpu.Data1 = (int)(Program.ProcessProvider.CurrentCpuKernelUsage * indicatorCpu.Maximum); + indicatorCpu.Data2 = (int)(Program.ProcessProvider.CurrentCpuUserUsage * indicatorCpu.Maximum); + indicatorCpu.TextValue = (Program.ProcessProvider.CurrentCpuUsage * 100).ToString("F2") + "%"; + + // Update the I/O indicator. + int count = plotterIO.Width / plotterIO.EffectiveMoveStep; + long maxRO = Program.ProcessProvider.LongHistory[SystemStats.IoReadOther].Take(count).Max(); + long maxW = Program.ProcessProvider.LongHistory[SystemStats.IoWrite].Take(count).Max(); + if(maxRO>maxW) + indicatorIO.Maximum = maxRO; + else + indicatorIO.Maximum = maxW; + indicatorIO.Data1 = Program.ProcessProvider.LongHistory[SystemStats.IoReadOther][0]; + indicatorIO.TextValue = Utils.FormatSize(Program.ProcessProvider.LongHistory[SystemStats.IoReadOther][0]); + + // Update the plotter settings. + plotterIO.LongData1 = Program.ProcessProvider.LongHistory[SystemStats.IoReadOther]; + plotterIO.LongData2 = Program.ProcessProvider.LongHistory[SystemStats.IoWrite]; + + plotterCPU.LineColor1 = Properties.Settings.Default.PlotterCPUKernelColor; + plotterCPU.LineColor2 = Properties.Settings.Default.PlotterCPUUserColor; + plotterIO.LineColor1 = Properties.Settings.Default.PlotterIOROColor; + plotterIO.LineColor2 = Properties.Settings.Default.PlotterIOWColor; + plotterMemory.LineColor1 = Properties.Settings.Default.PlotterMemoryPrivateColor; + plotterMemory.LineColor2 = Properties.Settings.Default.PlotterMemoryWSColor; + + for (int i = 0; i < _cpuPlotters.Length; i++) + { + _cpuPlotters[i].LineColor1 = Properties.Settings.Default.PlotterCPUKernelColor; + _cpuPlotters[i].LineColor2 = Properties.Settings.Default.PlotterCPUUserColor; + _cpuPlotters[i].Text = ((_cpuPlotters[i].Data1[0] + _cpuPlotters[i].Data2[0]) * 100).ToString("F2") + + "% (K: " + (_cpuPlotters[i].Data1[0] * 100).ToString("F2") + + "%, U: " + (_cpuPlotters[i].Data2[0] * 100).ToString("F2") + "%)"; + _cpuPlotters[i].MoveGrid(); + _cpuPlotters[i].Draw(); + } + + plotterCPU.Text = ((plotterCPU.Data1[0] + plotterCPU.Data2[0]) * 100).ToString("F2") + + "% (K: " + (plotterCPU.Data1[0] * 100).ToString("F2") + + "%, U: " + (plotterCPU.Data2[0] * 100).ToString("F2") + "%)"; + + // update the I/O graph text + plotterIO.Text = "R+O: " + Utils.FormatSize(plotterIO.LongData1[0]) + + ", W: " + Utils.FormatSize(plotterIO.LongData2[0]); + + // update the memory graph text + plotterMemory.Text = "Commit: " + Utils.FormatSize(plotterMemory.LongData1[0]) + + ", Phys. Mem: " + Utils.FormatSize(plotterMemory.LongData2[0]); + + plotterCPU.MoveGrid(); + plotterCPU.Draw(); + plotterIO.MoveGrid(); + plotterIO.Draw(); + plotterMemory.MoveGrid(); + plotterMemory.Draw(); + } + + private unsafe void GetPoolLimits(out int paged, out int nonPaged) + { + int pagedLocal, nonPagedLocal; + int retLength; + + // Read the two variables, stored in kernel-mode memory. + KProcessHacker.Instance.KphReadVirtualMemoryUnsafe( + ProcessHacker.Native.Objects.ProcessHandle.GetCurrent(), + _mmSizeOfPagedPoolInBytes.ToInt32(), + &pagedLocal, + sizeof(int), + out retLength + ); + KProcessHacker.Instance.KphReadVirtualMemoryUnsafe( + ProcessHacker.Native.Objects.ProcessHandle.GetCurrent(), + _mmMaximumNonPagedPoolInBytes.ToInt32(), + &nonPagedLocal, + sizeof(int), + out retLength + ); + + paged = pagedLocal; + nonPaged = nonPagedLocal; + } + + private void UpdateInfo() + { + var perfInfo = Program.ProcessProvider.Performance; + var info = new PerformanceInformation(); + + Win32.GetPerformanceInfo(out info, System.Runtime.InteropServices.Marshal.SizeOf(info)); + + SystemCacheInformation cacheInfo; + int retLen; + + Win32.NtQuerySystemInformation(SystemInformationClass.SystemFileCacheInformation, + out cacheInfo, Marshal.SizeOf(typeof(SystemCacheInformation)), out retLen); + + // Totals + labelTotalsProcesses.Text = ((ulong)info.ProcessCount).ToString("N0"); + labelTotalsThreads.Text = ((ulong)info.ThreadCount).ToString("N0"); + labelTotalsHandles.Text = ((ulong)info.HandlesCount).ToString("N0"); + labelTotalsUptime.Text = Utils.FormatLongTimeSpan(Windows.GetUptime()); + + // Commit + labelCCC.Text = Utils.FormatSize((ulong)perfInfo.CommittedPages * _pageSize); + labelCCP.Text = Utils.FormatSize((ulong)perfInfo.PeakCommitment * _pageSize); + labelCCL.Text = Utils.FormatSize((ulong)perfInfo.CommitLimit * _pageSize); + + // Physical Memory + string physMemText = Utils.FormatSize((ulong)(_pages - perfInfo.AvailablePages) * _pageSize); + + labelPMC.Text = physMemText; + labelPSC.Text = Utils.FormatSize((ulong)info.SystemCache * _pageSize); + labelPMT.Text = Utils.FormatSize((ulong)_pages * _pageSize); + + // Update the physical memory indicator here because we have perfInfo available. + + indicatorPhysical.Data1 = _pages - perfInfo.AvailablePages; + indicatorPhysical.TextValue = physMemText; + + // File cache + labelCacheCurrent.Text = Utils.FormatSize(cacheInfo.SystemCacheWsSize); + labelCachePeak.Text = Utils.FormatSize(cacheInfo.SystemCacheWsPeakSize); + labelCacheMinimum.Text = Utils.FormatSize((ulong)cacheInfo.SystemCacheWsMinimum * _pageSize); + labelCacheMaximum.Text = Utils.FormatSize((ulong)cacheInfo.SystemCacheWsMaximum * _pageSize); + + // Paged/Non-paged pools + labelKPPPU.Text = Utils.FormatSize((ulong)perfInfo.ResidentPagedPoolPage * _pageSize); + labelKPPVU.Text = Utils.FormatSize((ulong)perfInfo.PagedPoolPages * _pageSize); + labelKPPA.Text = ((ulong)perfInfo.PagedPoolAllocs).ToString("N0"); + labelKPPF.Text = ((ulong)perfInfo.PagedPoolFrees).ToString("N0"); + labelKPNPU.Text = Utils.FormatSize((ulong)perfInfo.NonPagedPoolPages * _pageSize); + labelKPNPA.Text = ((ulong)perfInfo.NonPagedPoolAllocs).ToString("N0"); + labelKPNPF.Text = ((ulong)perfInfo.NonPagedPoolFrees).ToString("N0"); + + // Get the pool limits + long pagedLimit = 0; + long nonPagedLimit = 0; + + if ( + _mmSizeOfPagedPoolInBytes != IntPtr.Zero && + _mmMaximumNonPagedPoolInBytes != IntPtr.Zero && + KProcessHacker.Instance != null + ) + { + try + { + int pl, npl; + + this.GetPoolLimits(out pl, out npl); + pagedLimit = pl; + nonPagedLimit = npl; + } + catch + { } + } + + if (pagedLimit != 0) + labelKPPL.Text = Utils.FormatSize(pagedLimit); + else if (KProcessHacker.Instance == null) + labelKPPL.Text = "no driver"; + else + labelKPPL.Text = "no symbols"; + + if (nonPagedLimit != 0) + labelKPNPL.Text = Utils.FormatSize(nonPagedLimit); + else if (KProcessHacker.Instance == null) + labelKPNPL.Text = "no driver"; + else + labelKPNPL.Text = "no symbols"; + + // Page faults + labelPFTotal.Text = ((ulong)perfInfo.PageFaultCount).ToString("N0"); + labelPFCOW.Text = ((ulong)perfInfo.CopyOnWriteCount).ToString("N0"); + labelPFTrans.Text = ((ulong)perfInfo.TransitionCount).ToString("N0"); + labelPFCacheTrans.Text = ((ulong)perfInfo.CacheTransitionCount).ToString("N0"); + labelPFDZ.Text = ((ulong)perfInfo.CacheTransitionCount).ToString("N0"); + labelPFCache.Text = ((ulong)cacheInfo.SystemCacheWsFaults).ToString("N0"); + + // I/O + labelIOR.Text = ((ulong)perfInfo.IoReadOperationCount).ToString("N0"); + labelIORB.Text = Utils.FormatSize(perfInfo.IoReadTransferCount); + labelIOW.Text = ((ulong)perfInfo.IoWriteOperationCount).ToString("N0"); + labelIOWB.Text = Utils.FormatSize(perfInfo.IoWriteTransferCount); + labelIOO.Text = ((ulong)perfInfo.IoOtherOperationCount).ToString("N0"); + labelIOOB.Text = Utils.FormatSize(perfInfo.IoOtherTransferCount); + + // CPU + labelCPUContextSwitches.Text = ((ulong)perfInfo.ContextSwitches).ToString("N0"); + labelCPUInterrupts.Text = ((ulong)Program.ProcessProvider.ProcessorPerf.InterruptCount).ToString("N0"); + labelCPUSystemCalls.Text = ((ulong)perfInfo.SystemCalls).ToString("N0"); + } + + private void ProcessProvider_Updated() + { + this.BeginInvoke(new MethodInvoker(delegate + { + this.UpdateGraphs(); + this.UpdateInfo(); + })); + } + + private void checkShowOneGraphPerCPU_CheckedChanged(object sender, EventArgs e) + { + if (checkShowOneGraphPerCPU.Checked) + { + tableCPUs.Visible = true; + } + else + { + tableCPUs.Visible = false; + } + } + + private void checkAlwaysOnTop_CheckedChanged(object sender, EventArgs e) + { + this.TopMost = checkAlwaysOnTop.Checked; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/SysInfoWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/SysInfoWindow.resx new file mode 100644 index 000000000..4283d8b1c --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/SysInfoWindow.resx @@ -0,0 +1,624 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + 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 + AAAAAAAAAAAAAAAAAAAAAAj4AAAAAAAAAAAAiPiPiAAAAAAAAAAIiP+IiIAAAAAAAAAI+IiIh4gAAAAH + cHcAiIh3d4iAAACIiHh3AHd4iIiAAAB4eIh4eIh3cAeAAACIh4eHdwACAwCAAACIh4AAAAAnJHKAAACI + iIACJycicieIAACIeIY2AACnJyd4AACHiIAjIqNnJ6d4AACHiIcgIkJ3Nnd4AAByiIUAYyF3ejY4AACH + j4MCInYmNnd4AAAAiPZwcgd3d3d4AAAAAIcABSd4iIj4AAAAAAh3d4iIj4+AAAAAAAiPAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP////////////j////AP///gB///4AP/+TA + B//AMAf/wAAH/8AAB//AAAf/wAAD/8AAA//AAAP/wAAD/8AAA//AAAP/8AAD//wAA//+AAf//j////// + /////////////ygAAAAQAAAAIAAAAAEABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAACA + AAAAgIAAgAAAAIAAgACAgAAAgICAAMDAwAAAAP8AAP8AAAD//wD/AAAA/wD/AP//AAD///8AAAAAAAAA + AAB3cACIh4eAAIeAAPiIhwAAiIAAAIdwAACIiIiIiIh4eIiIiIiIiIiIiIiAAAAAAPeIiIAABydwiIp4 + gHACKieIgXiKIBp1qoiIj3AiZ3d1iAAIgEo3d3eIAAiAMEclY4gACIeIeIiIiAAIj4iIiIiIAAAAAAAA + AAD/////HAf//xwP//8fH///AAD//wAA//8AAP//AAD//wAA//8AAP//AAD//+AA///gAP//4AD//+AA + ////////KAAAADAAAABgAAAAAQAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHCgcADAwMAA0U + DQALGQsAEhISABQaFAAaGhoAJwACAAo9CQAVIxUAFigWABskGwAcKhwAEjoRAB4zHgAjJCMAIikiACws + LAAiNCIAIzsjACwzLAArOysANDQ0ADQ+NAA7PDsAFksVAAZUGwAWUxUADngMABNkEgAVaxMAE3MRABV4 + EwAaehcAHHQaACB4HwAlQiUAKEonACtFKwArSysAJVUlAC1SLQA0QzQAMksyADtDOwA+Sj4AMVMxADNc + MwA7UzsAO1w7ACZ2JQA2YzYAOmQ6ADprOgA1djQAPXA9ADl7OABDQ0MARUtFAE1NTQBUS0MAQVVBAEVZ + RQBOV04ATF5MAFJSUgBTX1MAXFxcAGNEVQBCYkIAQ21DAE1tTQBHc0cAU2xTAF9iXwBbbVsAVHRUAFR4 + VABcdFwAWnlaAGJiYgBqZGQAZmxmAGZnaABqamoAfG1sAGN2YwBjemMAaXVpAGt7awBycnIAfXJ0AHN8 + cwB4eHcAe3t7AIN7egAOiwsAD50LABSCEgAZhhcAHowcABWeEwARqg4AFKIQABWrEgAcpBkAFbARAB6w + HAAcvxkAIqwfACKzHwAgvB4AJIciACeIJQAojyYALYQsACWSIwAjmiEAK5IpACyfKgAynC8ANoI2ADOM + MQA5ijgAM5AyADabNAA9lDwAPJo6ACamIwAooSUAJKsiACmsJgAroikALKwpACWyIgAosCUALrErACy9 + KQAwsi0AM6MxAD2iOwA5vTYAQZw+AEGsPwAewBsAIcAeACTCIQApwyYANMExAD6UZwBFgkQASYpHAEqG + SABJi0gAQ5tBAEqUSABYilcARqNEAEOzQABRsk8AaIFnAGeRZgBzgnMAfoF+ADTNfgAA/2sAhIB+AH9/ + gQB/gYEAdLebAGHbnACDgoIAhYWJAIiHigCLi4sAkIuLAI2ZjACQkY8AjI2SAJKPlQCLkZQAgJ2QAI2W + mwCTk5MAmZWUAJOXmgCYlpsAlJyfAJuamwChnZ0AlamdAJ2dogCpnKAAm6SnAJ2mqgCRu6cAo6OjAKml + pACpqacApKaqAKSorACsq6wAsKysALKwrgCnrrEAq62wALGvsAC8rrQArLK1AK+5vACzs7MAu7W2ALS6 + uwC7ursAw6qyAMqnugDDrLgAwby+AL7AvgC8vsAAw73BALzCxAC5x8kAvMzPAMPDxADLxMUAz8jHAMTH + yQDMxMgAw8jKAMvLywDQyckAxs3RAM/P0ADF0dQAzdLTAMzW2ADL2dsA0tPTANTX2ADT2tsA29vbANbe + 4ADc3+EA1+DiANvg4gDf5ukA4+PkAOLn6QDn6ekA6errAO/y8wDz9PQA9/f4AP///wAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + 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 + GQAcLBwAIyMjACMrIwArKysAIjIiACU7JAAqMioAKzwrADU1NQA0OzQAPDw8AEcmLQAPQQ4AGkMZAB9b + HgAiRhkAIFcfAA1kCgARdQ8AFWUTABVtEwAZbhYAE3MRABZ9FAAbdxkAJ0UnAC5HLgAsSiwAM0MzADdP + NwA6RToAOks5ADRUNAAzXDMAO1Y7ADpcOgAAezkAKm4pADByLwA2ZDYAP2E3ADliOQA7bDsAPXA9AD98 + PgBCQkIAR05HAEtLSwBCVEEAVFdKAFVUVABfX18AQG1AAEBwQABIeEcASXNJAEt4SwBUZVQAXGFcAFR0 + VABZdlEAVXhVAFlxWQBcelwAel9nAGVlZQBqamoAYXNhAGJ6YgBodmgAYnhpAG1/bQBzc3MAenR3AHJ9 + cgB7e3wAEogPABWEEgAZjhcAHoAcABqMGAASkRAAHJwaACKKHwARrA0AFaETABSsEQAfpRwAHqkcABmw + FgAftRwAIboeACGHIAAohiYAIosgACWQIwAolCYAJJsiACmYJwArnCkAMZsvADmKNwAzkzEAJ6cjAC6k + KwAwqC0AIrQgACmwJgAjuiAALr4rADOoMQBAqz0AH8QbACHDHwAkyiAALcYqAC7IKwAywS8AS4VKAE+J + TgBFm0MAVYZUAEynSgBFvEMAaINoAHOIbwBxhXEAeYJ0AHmBeQB+iH4AgnmAAH+MjgB/lIoAFfKFAEvG + jgCCgoMAioWFAICOgACJiYkAjY2NAJWDigCNlo0Aio+UAJGOkgCcj5cAiJ2TAIiRmACUlJQAmJeXAJGb + lQCWmZoAmpmaAJ2amgCdnZsAnZudAJ2cnACgm5oAjJyjAJWdoQCcnqAAmKWmAJysogCWtK4Ama61AKSj + owCopqcAqKesAKSqqwCsrKwAsK+vAK6wrgC1sK8Asa+wAKqxtACtvb4AsbGxALaysgCytrYAtbW1ALu3 + tAC2urcAurW5ALG6vAC5ubkAvb29AMy0vgDBu7sA36jEAK7HzACyxMcAvcLDALjGygC9ycoAtszSALzO + 1ADDwsIAw8PEAMDFxgDFxcUAysTFAMTGyQDEyssAycnJAMnNzgDOzs4A0c3MAM3QzgDCztAAzc/QANjE + 0ADD0dUAytDSAMvU2ADF2t4AyNzfANHR0QDS1NIA0tLUANHV1ADV1dUA3NPTANDX2QDe1tgA1draANnZ + 2QDZ3d0A3d3dANPe4QDO4OIAzOfsAMjp7QDR4eIA2ePlANrs7QDe7e4A1O70AN36/ADg4OEA5ubmAODo + 6gDq6uoA7erpAPX19QD19vkA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOLi4tXDAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAANXr6/nr6+vVwwAAAAAAAAAAAAAAAAAAAAAAAAAAAL3r6+v56+Li+9XV4sMAAAAA + AAAAAAAAAAAAAAAAAADD4tHV4vn54tXr0dG90b0AAAAAAAAAAAAAAAAAAAAAAMO90dHi6+vi1dXRw6aW + 0QAAAAAAAAAAAAAAAAAAAAAA1dXRw9Xi4tvRw6+SkqamAAAAAAAAAFaTngAAAAAAAAAAveLVvb2zppJN + PUyevbO30QAAAACmpr3rpjpMsKYAAAAAAJ6vn1RTU5KquMrd8/niswAAAJ6+lrfi0aaSnrOeAAAAALOZ + naiuzerVvZZNw8nDAAAAn8Ovs7Oz1eumTJJTqcjMx8i8ppRQOxEGBgOY4b0AAACm0q+zr56ajq3N9vfa + r4pEKhEDBQIGBg0lKzfvrwAAAKbYr7exnrGrrIo8FAcCAAEAAh9nKzRuNCsSh++wAAAApuews7Om3RAG + AQAAAAMPJDQ1bGUqFGxnFRNQ7rAAAACm6bCzt6/hGgILWmM1LCYQCQYibDQ4cnc6boHusAAAAKbpr7O9 + r9o0MitdYQQCAwYGBVtwcTp2cW9zNuu4AAAAptimvcO93kcXDWFYCAMFIVwfYkF8P3c3dERF4rkAAACm + xJe81cPUiCFkXh4cBxldMXtmQXmCeE5MTUXZzQAAAJuxoMXVztGvCictMHUsaVoNIHdThHqAUFNTTdHN + 0QAAnJCRxuvR08k0NCoJYQZcGAcMg1ZTf35KRkI1w92zAACPL1Hc6tXb2gw4BwNXGGERJytGQjZzfUZQ + VVOz3qYAAI0WS9Hq0d7UFCkRJGptdzQ0LVJVkpKGkpKSkqrooQAAwlSz/v/54t0/NCQQGVsjDBE9mpKS + koVKSEI2puuqAAAAAMm94v//7z0BBgYHYQwRFElKQjZBRk+KjJif+bIAAAAAAAAAvb/aTQMLEiZrNTQ0 + T4iMlpaWlpSTklb7vwAAAAAAAAAAANueNDQmEhERDhOSk5OVnqavsL3R4v3TAAAAAAAAAAAAAL0ABgwT + OD5Tmr3Dw9HT2d7o7/P6+QAAAAAAAAAAAAAAw5OnvcPK4fHx7/PzAAAAAAAAAAAAAAAAAAAAAAAAAADi + 9fUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////////////g////gD///gAP//wAB//8AAf//AAH8f4 + AAeAPgADgA8AA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAAYAAAAGAAAABgAAAAYAA + AAHgAAAB/AAAAf8AAAH/gAAD/4AH//+P/////////////ygAAAAYAAAAMAAAAAEACAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAABQUFAAkJCQACFwIAAh8BAAYaBgAREREAERURABAYEAARHBEAFh8WABgY + GAAeHh4AAiACAAsjCwAPLw4ADzAOABA0DwAVIRQAFycXABkkGQAaKhoAFDEUAB41HgAgICAAJCQkACoq + KgAuLi4AMC0tACI/IgAtPS0AMzMzAEE9PQALXwkAE2sSABdzFgAUehEAHn0bAC5NLgAqUCoAN043ADJb + MgA1WTUAOVg5AD5fPgARZTQAMmUxADRgNAA3bjcAOGc4AD1hPQA6ajoAPWg9ADxtPAA8cDwAQUFBAEpH + RwBMSEcAS0hIAE5OTgBSUlIAVV5VAEBxQABGd0UASHFIAF5jXgBRdFEAUnlSAHlXYwBjY2MAZmZmAGVo + ZQBqbWwAbm5uAGJ6YgBlemUAb3hvAHFxcQB1dXUAdH50AHp6egB+e3wAf39/AA+ADAANigoAEI0NABCe + DgAXgxQAFIgSAByJGgAgmh0AEKANAByuGQAhhCAAJoMkACicJgAsnSoAOJE1ADySOgApoicAJLUgADSh + MgA9qDsAH8IbACnDJgAqxyYATIpLAEyfSQBCoUAAR6JEAE2hSwB9gH0AgKl8AH+DhQA/y4UAgoKCAISE + hACBiY0AjIuKAI6OjgCQjo4AgZaMAJOQjwCJj5AAiJCSAI2VlwCRkZEAlZSUAJiXlwCXnJ0AmZmZAJ2d + nQCXn6AAmqCiAJivpQCioqIApKOjAKalpgCop6cAp6mnAK6rpwCopqgAraWpAKqqqQCrrq8Ara2tALGn + qQC1pKoAsKmrALSqrwCwrq8AprOyAK+zswCrtLcAsrKyALaxswCxtLYAtrW1ALO2uAC3uLkAsLu8ALe4 + vACzvL4Aurm6AL2+vgDBvr0AyLu+AMXAvgC0vsEAucLDAL7GxgC9x8kAusjJAMLCwgDEw8IAw8TFAMXF + xQDMxcYAwMjKAMXJyQDGzMwAycnJAM7IyQDKzc0Azc3NANnN0wDL0dMA0dHRANDT1ADW0tUA0NTVANXV + 1QDZ1dcA09faANfa3ADZ2dkA3trYAN7e3gDY3+EA3eLkAN7k5gDY5ukA4eHhAOHm5wDg7+8A+fz8AAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAMC/swAAAAAAAAAAAAAAAAAAAAAAAMC1xcrFxbW1AAAAAAAAAAAAAAAA + AAAAtbO1xcW7wLutpAAAAAAAAAAAAAAAAAAAu7OtwMO7rY94j4gAAAAAAAAAUYAAUYIAAKSdnYt/UUh7 + oJiPAAAAAACKjK2tfn9/fwAAhX51hKS1rcWzAAAAAACPnYidnotxfoSdi4t+cUY3DB+sAAAAAACWp42C + gpeLf007GxIOEBAWEh+gAAAAAACdsY2PlBkJAw0NBQIUXigrMDWQAAAAAACdsY+PlAcJIx0nLzZfZysy + ZGOIswAAAACWpo2koTUvXBcVCgdcYmI/ZUBwqgAAAACWk4q1qholJCFTViJfRmhqbEZ4rAAAAACGcpa5 + rCAnEFRVEllBTWxubkh2qAAAAAB5LY3AsjgZAltYGRpOTEtpQ0A+mAAAAACNRLnNuzgHFFlaKjQ2QEJm + S0xxnQAAAAAAAK3AxzgxKideHj17cXF0dH+CrQAAAAAAAAAAtX8ABwsUGk2KjJ2xwMDAwAAAAAAAAAAA + AKQ8RnGDp7W1tcDBw8fIAAAAAAAAAAAAAMPJzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP// + /wD/+P8A/8A/AP+AHwD/gA8A5MAHAMAwBwDAAAcAwAAHAMAABwDAAAMAwAADAMAAAwDAAAMAwAADAMAA + AwDwAAMA/AADAP4ABwD+P/8A////AP///wD///8AKAAAABAAAAAgAAAAAQAIAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAALCwsADQ0NABISEgAVFRUAGRkZABsfGwAeHh4AISEhACYmJgAoKCgALCwsADQ0 + NAASeBAAF3wVADJbMQAjaiEAQ0NDAEhEQwBWVlYAWlpaAF1dXQBbdloAYGBgAGdnZwBpaWkAbGxsAHNz + cwB2dnYAe3l5ABGkDgAXqBMAFrMTACKmHwAsgioALZ8rADmONwAmuSIAG9MXAA/yCgAQ8AsAJskiAADy + SABiwoIAioqKAJGQkACUlJQAm5ycAJ6engCfoKAAmb+lAKCgoACkpKQAqqqqAKusrACtra0AsLGxALS1 + tQC4ubkAu7y8AL6+vgDAwMAAxMbGAMXIyADIysoAycvMAMrMzADMzs4AztDQANDR0gDV1tYA2dnZAN/f + 3wDo6OgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAP///wAAAAAAAAAAAAAAAAAAAAAALR0tAAAAOzs5Ly8xMwAAAD0tOQAAAElAPTs1MwAA + AAA1PTMAAAAAADssLwAAAAAAOUU1SD09Ozs5NTUzMzMzQDVFNUVEQEBAQEBAQEBAQC85RTVFNQABAAAB + BQUFBD0zOEU1RTgFBQEECiIhEQtAMzIqK0U1CgUEBA8lIyQRQDM1Eh1FMyceBAUmFRUpJ0A1RztERTMK + DQ4gFhkYGRhANQAAAEUzAwQfEBwcHBwZQDkAAABFMwQFCwwZGBUVE0A5AAAARTMzMzMzNTk5OTtAOQAA + AEhFRUVFRUVAQEBAQEcAAAAAAAAAAAAAAAAAAAAA//8AABwHAAAcDwAAHx8AAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADgAAAA4AAAAOAAAADgAAAA//8AACgAAAAwAAAAYAAAAAEAIAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAsbGxBbu7uxyzs7NVpaWlgLGxsY+ysrKWtLS0maurq5eNjY2SgoKCgnl5 + eVxycnIjgYGBBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAI2NjRqoqKh1vLy80c3Nzf/V1dX/39/f/+Xl5f/l5eX/4eHh/9zc + 3P/d3d3/3t7e/9PT0//AwMD/oaGh4IyMjIeWlpYiAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAACAAAAAQAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAj4+PZ7e3t+rU1NT/19fX/9vb2//c3Nz/29vb/9ra + 2v/W1tb/0dHR/8nJyf/MzMz/39/f/9nZ2f/CwsL/v7+//8nJyf+tra35Y2NjhjU1NQ8AAAAAAAAAFgAA + ABkAAAAXAAAADQAAAAQAAAACAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACioqKmysrK/9DQ0P/Ly8v/y8vL/9DQ + 0P/X19f/2tra/9vb2//a2tr/1NTU/8vLy//S0tL/5OTk/83Nzf+ysrL/xMTE/8jIyP+5ubn/xMTE/35+ + fsgNDQ09AAAAMQAAAD0AAAAyAAAAIgAAABMAAAAIAAAABAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ2dnYXFxcX/xMTE/8HB + wf/Hx8f/zMzM/9DQ0P/X19f/3Nzc/93d3f/c3Nz/1NTU/8jIyP/T09P/3t7e/8HBwf/CwsL/ysrK/7W1 + tf+srKz/rKys/8LCwv9ubm7IAAAASAAAAEsAAABAAAAAMgAAACQAAAAVAAAACwAAAAUAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALa2 + tu69vb3/vb29/8HBwf/ExMT/yMjI/87Ozv/V1dX/3Nzc/93d3f/a2tr/0tLS/8fHx//Nzc3/zc3N/8HB + wf/CwsL/tLS0/6+vr/+oqKj/mZmZ/6ampv+Xl5fsDQ0NXgAAAEEAAABEAAAANgAAACcAAAAcAAAAEgAA + AAkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAALa2tuy3t7f/urq6/729vf/AwMD/xMTE/8nJyf/Pz8//1tbW/9fX1//V1dX/zc3N/8TE + xP/FxcX/wMDA/729vf+2trb/rq6u/6Kiov+UlJT/kJCQ/6Wlpf+dnZ3vFxcXWAAAADIAAAA7AAAAMQAA + ACYAAAAcAAAAEgAAAAkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAALKysq27u7v/ubm5/7m5uf++vr7/wMDA/8TExP/Hx8f/zMzM/87O + zv/MzMz/x8fH/8PDw//AwMD/urq6/7CwsP+jo6P/lJSU/46Ojv+RkZH/l5eX/6+vr/90dHTDAAAAIgAA + ACINDQ0wAAAAKQAAACEAAAAYAAAADwAAAAgAAAAAAAAAACoqKSlvbW/ik5CR/1hZWcUNDg5KAAAAGgAA + ACUAAAAnAAAAOAICAToAAAAIAAAAAAAAAAAAAAAAAAAAALi4uBienp7WysrK/8TExP+4uLj/urq6/76+ + vv/AwMD/wcHB/8HBwf/AwMD/uLi4/6+vr/+jo6P/mJiY/4ODg/9tbW3/aWlp/3+Bgf+TkpL/o6Oj/6qs + rPxcXFySTk5PeGpqa5aDg4SALy8vKQAAABYAAAARAAAACQAAAAQAAAAAZWRlM19fXuuysLD/npqZ/+Ph + 4f/Y2Nn/RkZG0wUFBZoODg67Y2Nj/6Wlo/9LTEq9CgsIVQAAABEAAAAAAAAAAAAAAABaWloPUFBQgKam + pvLHx8f/ubm5/62trf+lpaX/pKSk/6SkpP+Xl5f/iYmJ/319e/9xcXH/ZWVl/11eXv9paWr/goKD/5qa + m/+tq67/tra1/7m3t/i4trbu2dna/9vb2/+fn5/4f39+LAAAAAMAAAAFAAAAAwAAAAEAAAAAmZibirCs + rP+opKT/lpGR/6uqq//Pz9D/wsLC/5iYmP+Li4v/Xl5e4m1tbbPR0dH5xcTB/1VVVMkSEhBfAAAAEwAA + AAAAAAAAAAAAAENDQy5OTk2ZjY2O5qGhof+mpqX/n5+e/4WFhf94eHf/enp5/3p7fP9/f4H/iImK/52d + n/+rq63/r66u/7GvsP+2t7f/s7S0/7nDxf/G09T/wsPF/sC+vv6np6f/cHBwSQAAAAAAAAAAAAAAAAAA + AAAAAAAAkI+Rg6qnp/+vqqr/n5yc/7Kwsv/IyMz/q6ys/62srP+4uLj/hISE8S4uLrUZGRmPcXJzt9LS + 0vS3t7f/VlZTvhgYGGsAAAAnAAAABgAAAAAAAAAAHyAgCDk5OjR5eXuPlJWV+oWFif+Lio3/jo6S/5GQ + lf+Xl5r/oaGk/6qqrP+orbD/r7m8/7nHyf/M1df/1tvc/9fX1//V09P/ycnJ/sHFxfyqqKj/hoaGbQAA + AAAAAAAAAAAAAAAAAAAAAAAAkZCSg66qq/+1sLH/p6Wl/7a0tv/Av8D/uLi4/7q6uv+vr6//zc3N/+np + 6f+oqKj6OTg4sxwcHpaDg4Ta9fb1/6Oiov8ZFxeFFxcYJkhISkBzc3d0g4GGpYiIjMyKiY3sioqO/4yM + kv+Lj5T/i5GW/42Wm/+dpqr/try+/8vOz//R0dH/x8fH/6ysrP+AgID/UlJS/y0tLf8iIiL/sLCw/8vY + 2vynpaX/n5+fjQAAAAAAAAAAAAAAAAAAAAAAAAAAkpCTg7axsv+9uLn/sKqt/768vf+7u7v/jo6O/5qa + mv+1tbX/tbW1/8DAwP/r6+v/9fX1/5CQkPZVVVbtYGFi9HFwc9WJh4vYn5+k9Z+fpv+anaH/kpeb/5CX + nP+TnJ//m6Sn/6itr/+urq7/sbGx/7S0tP+bm5v/fHx8/1tbW/8tLS3/FhYW/xISEv8QEBD/Dw8P/w8P + D/8QEBD/pKSk/9Db3P6qqan/mZmZsQAAAAAAAAAAAAAAAAAAAAAAAAAAkZKTg763t//Bur3/rqqs/7y6 + u/+8vL//n5+f/5iYmP+QkJD/mJiZ/5STlf+RkZP/mJqa/5iWm/+cm6H/pKaq/6Sprf+nrrH/q7G0/660 + tv+1ubv/tLS1/62trf+kpKT/jY2N/2lpaf9DQ0P/ISEh/w4ODv8ODg7/Dg4O/w8PD/8UFBT/GBkY/yAq + IP8oPSj/Lksu/zNaM/85aTn/lZWV/9Pc3f6xrq7/mpubzAAAAAAAAAAAAAAAAAAAAAAAAAAAk5GUhcS+ + v//GvsH/sKyr/726u/+7u7z/nZ2d/52dnf+dnZ//jo6S/5KPlf+LkZL/gJ2Q/5adn/+orK7/u76//8fH + x//BwcH/m5ub/319ff9hYWH/Pz8//x8fH/8LCwv/BgYG/wYGBv8HBwf/CQkJ/xcdF/8mNib/LEcs/zJV + Mv82ZTb/PG88/zdgN/8yUjL/LkUu/ys4K/8fLh//g4WD/9Pa3P+1tbT/mpmZ3QAAAAAAAAAAAAAAAAAA + AAAAAAAAkZKVhsrDw//KxMT/says/726u/+7u7z/nZ2d/5+fn/+ysrP/lpea/5mZmf+0tLT/t7e3/5ub + m/90dHT/UlJS/zc3N/8bGxv/DAwM/wQEBP8AAAD/AQEB/wcKB/8THxP/HjMe/yhKJ/8xXjH/Omw6/zhl + OP81WTX/MEsw/y0/Lf8qMyr/KCgo/yoqKv8rKyv/LCws/y0tLf8kJCT/b3hv/9TZ2v+5u7v/mpmZ6gAA + AAAAAAAAAAAAAAAAAAAAAAAAkpGVhszHx//Mxsb/s66u/7u7vf+8vL3/oKCh/6Ghof+zs7P/pKir/5iY + mP8vLy//GBgY/w8PD/8FBQX/AgIC/wEBAf8LFQv/FigW/yE8If8sUCz/NWY1/zlqOf8wWDD/KEco/yA1 + IP8ZJBn/ExUT/yEhIf8rKyv/LCws/y4uLv8vLy//MTIx/zQ+NP82Szb/OVY5/zphOv87ajv/Xmte/9HT + 1P/EyMj/m5qa8AAAAAAAAAAAAAAAAAAAAAAAAAAAk5CUhtDJyP/Pycr/s7Cx/7u5u/+/v7//pqak/6Wl + pf+vr6//sri7/5SSkv8RFhH/EiAS/x82H/8oSSj/Mlwy/zxwPP8yXTL/KEoo/x43Hv8XJhf/DxUP/woK + Cv8MDAz/Dg4O/xAQEP8QEBD/FBQU/y00Lf82Rjb/KI8m/zpdOv87Zzv/PG88/zxlPP88XDz/PVM9/z5M + Pv84PTj/U19T/8zMzP/M09P/nJyc9JeYmBMAAAAAAAAAAAAAAAAAAAAAk5CThtDJyv/OyMn/s6+w/7u5 + uv+/v8H/qamn/6mpqf+srKz/ury9/6Ojo/85ajn/MFYw/ypGKv8gNCD/FiEW/wsLC/8KCgr/BwcH/wcH + B/8ICAj/CgoK/w8SD/8ZJRn/Ijgi/ytKK/8zXDP/Omw6/ztoO/8ooSX/I68f/z5QPv8/SD//LYUs/yuT + KP9DQ0P/RERE/0dHR/9CQkL/TldO/8vLy//Q2dv/n56d/pqamj8AAAAAAAAAAAAAAAAAAAAAk5OVhs/I + x//Mxcb/srGu/7u6u//CwsP/rKqr/6qqqv+wsLD/wMHB/7O1t/8nPCf/Dw8P/xkZGf8UFBT/ExMT/xAQ + EP8VaxP/HC4c/yM/I/8tUi3/NmQ2/zlqOf8yWTL/Kkkq/yM4I/8cJxz/HyIf/z09Pf8mpiP/IrMf/0NP + Q/9HR0f/M4sx/yawI/9DYEP/RVlF/0RhRP9AZkD/O3I7/8rKyv/V3d//pKKi/5mZmWgAAAAAAAAAAAAA + AAAAAAAAk5KWhszEyP/GvsD/paOg/7m2t//GxMf/sa+w/7Kzsv+5ubn/w8PD/7q+wP86VTr/Gykb/yxD + LP8vTy//NV41/yaxI/8iqR//Kkwq/yE5If8ZKRn/ExoT/xAQEP8RERH/ExMT/xUVFf8WFhb/JiYm/0dI + R/8hwB7/LJ8q/zl/OP9CZUL/LKAq/yyfKv8soir/KLAl/0dkR/8srSn/OXg4/729vf/W3uD/pqWl/5mZ + mYsAAAAAAAAAAAAAAAAAAAAAlJKUhsbAwP++u7v/o5+f/7a0tf/Jy8n/ubu5/7m5uf+8vLz/xsbH/7zC + xP85fDj/MFYw/zJPMv8qPSr/IUEh/xWeE/8Rqg7/CAgI/wsLC/8NDQ3/EBAQ/xEREf8VGBX/Hioe/yY7 + Jv8uTS7/OWI5/zaCNv8ltSL/M5Ay/zKcL/9MXkz/Nps0/0WBQ/8vsCz/PZQ8/z2YOv89mjv/UFBQ/66u + rv/X4OL/qaqq/5aWlrMAAAAAAAAAAAAAAAAAAAAAkpOVhry4uv+7srT/oZma/7SytP/Mzc//vsC+/729 + vf+/v7//xsbG/7vDxf9cdFv/Dw8P/ywsLP8lJSX/HHca/x1xG/8Oiwv/EjoR/x4wHv8nQyf/L1Qv/zdl + N/86azr/M1sz/y5MLv8nRSf/OkU6/0SFQ/87mTn/UWxR/zCyLf9dXV3/PJ06/0qGSP9gYGD/X2Jf/ynD + Jv9Dm0H/V1dX/5ycnP/a4OL/tbW1/5eXl8kAAAAAAAAAAAAAAAAAAAAAk5KVhryutP/DqrL/qZyg/7Ox + tv/Nz8//w8TC/8LCwv/ExMT/xsbG/7/Gx/9whXD/FBkU/zNJMv8zSjP/HL8Z/zZkNv8qpCj/JpIl/yxN + LP8lPiX/Hi4e/xkfGf8TZBL/FIIS/xSgEf8UpxH/LJEq/0GcPv9Jikf/YGBg/y28Kv9ebF3/PaI7/0mL + SP9Walb/UWtR/zOjMf9Fb0X/Pm8+/5CQkP/b3t//vsDA/5aWltUAAAAAAAAAAAAAAAAAAAAAnIyWhpWp + nf9h25z/kbun/8OsuP/Q0dH/x8fH/8bGxv/Hx8f/ycnJ/8LHyv+LnIr/JKwh/x7AG/8lmSP/JZQj/x4p + Hv8KPQn/DngM/xAQEP8SEhL/ExMT/xRUE/8UcRL/GUgX/xstG/8hJSH/Kasn/zGzLv9GgUb/TGxM/yys + Kf80jTL/Ka0m/zmMOP9Obk7/VG5U/1puWv9lb2X/Y2Zj/4iIiP/b3t7/w8bH/5aVleQAAAAAAAAAAAAA + AAAAAAAAn4uafTTNfv8A/2v/dLeb/8qnuv/T09P/y8vL/8nJyf/Ly8v/y8vL/8rNz/+tra3/FyYX/zQ0 + NP8niCX/NjY2/w0NDf8LGQv/D50L/xMXE/8bJhv/JDgk/x6MHP8mfST/Nl82/ztsO/86azr/QmtC/y6y + K/9UbVT/WW1Z/0qUSP9Go0T/Qaw//1qMWP9vb2//cHBw/3Fxcf9zc3P/a2tr/319ff/c3d3/yMvN/5WV + lfCbm5sgAAAAAAAAAAAAAAAAmpqfbj6UZ/8GVBv/fXJ0/8O6w//V2Nn/z8/P/8zMzP/Nzc3/zs7O/9DT + 1P+7ubr/JCgk/zZANv9BVUH/NE40/ylKKf8zXDP/ILse/zV3NP80XjT/Lk0u/xylGP8lViX/JjEm/yUo + Jf8zMzP/aGho/3V1df9ycnL/cnJy/2iBZ/85vTb/Q7FB/1qOWf9odGj/XnNe/1dyV/9RclH/R3BH/z9w + P//b29v/zdHT/5aWlvybm5tKAAAAAAAAAAAAAAAAmZecbmNEVf8nAAL/fG1s/73Awf/V1tf/0NDQ/8/P + z//R0dH/0tLS/9bX2P+7u7v/O2s7/ztlO/9BYUH/KkQq/x0xHf8ZIxn/E3UQ/xRQE/8bGxv/Hh8e/xWw + Ef8kJCT/Jycn/ykpKf9CQkL/a3Nr/2h3aP9fdF//VHNU/05yTv8kwiH/JbIi/zmJOf9Jckn/VHNU/1x0 + XP9kdmT/bHZs/2dpZ//Y2Nj/09fZ/5iXl/+amppxAAAAAAAAAAAAAAAAnp2heWhkZf9US0P/h4B//62u + sf/h4eL/z8/P/8jIyP/Ozs7/0tLS/9vb2/+8v8D/Ly8v/zo6Ov9BQUH/Dg4O/xAQEP8TExP/FE8T/xV4 + E/8iLSL/JVQl/xykGv8yUjL/N103/zlmOf88cDz/RnJG/01zTf9VdFX/YHZg/2d3Z/9CsUD/RLdB/2eR + Zv96e3r/bnlu/2N3Y/9Ydlj/TXNN/0BvQP/Ly8v/3ODi/5qbm/+ZmZmLAAAAAAAAAAAAAAAApaKlOpCR + j/+SlJH/npmc/9rY2v//////+Pj4/+Xl5f/Z2dn/09PT/9PT0//Bx8f/PkE+/zpEOv80RzT/JD0k/ytK + K/8zXDP/NXU1/yG9Hv82Xzb/HrAc/ySQIf8uQy7/Ljsu/y42Lv9dXV3/gYGB/35+fv99fX3/dXt1/2l5 + af9WhFX/K78o/0F/Qf89cD3/SXNJ/1Z1Vv9ieWL/cH1w/2puav+8vLz/4ufp/6CgoP+ZmZmeAAAAAAAA + AAAAAAAAAAAAALS0s0HMzs+Ws7a38dXV1v/c39//9PT0////////////+/r6/+rq6v/GzdH/Pm8+/zhh + OP8wUDD/JUAl/yM4I/8dKB3/GyAb/xSgEP8aVhn/GnoX/yQkJP8nJyf/LC8s/zZCNv9Zb1n/WXhZ/0pz + Sv8/cT//RXJF/1F1Uf9deF3/NMEx/3Z+dv+BgYH/gYGB/4GBgf+CgoL/hYWF/3Nzc/+zs7P/6O3v/6qq + qv+WlpavAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAr7S0KrGzs0CvsLCJury8/8jKyv/a29v/8/T0//// + ///V3t//dXV1/wgICP8NDQ3/EBAQ/xMTE/8WFhb/GRkZ/xmGF/8geB//JIci/zVaNf86aDr/O2w7/z1l + Pf9WdVb/aH1o/3J9cv9/gX//goKC/4KCgv+CgoL/UbJP/4ODg/+EhIT/a31r/116Xf9RdlH/SHRI/z5w + Pv88cDz/7/Lz/7m5uf+Tk5PGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAr7KyHbGz + sz2vs7KYubu7/8bHx//O1df/hoSE/wkOCf8aKBr/JDsk/y1NLf80XjT/PHA8/y2ELP8imyD/J3Am/yw7 + LP8rMSv/LCws/1BQUP+EhIT/hoaG/4SEhP93gHf/Zntm/1Z3Vv9JdEn/QnJC/z5wPv88cDz/P3E//0Rz + RP9MdUz/WHpY/2h7aP+Plo//8/T1/8TFxf+SkpLam5ubDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAs7a2DKywsCO8wsXblpWU/zdmN/8wVTD/KEUo/yI2Iv8eKR7/GRkZ/x0j + HP8VqxL/Iyoj/yYmJv8xQzH/NVM1/0dsR/9IdEj/P3E//zxwPP89cD3/QHFA/0h0SP9UeFT/Ynxi/3OC + c/+Hh4f/hYWF/4ODg/+AgID/fn5+/3Jycv96enr/8/T1/9LT0/+NjY3wmZmZNAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADHztFjqKqp/w0NDf8ODg7/ERER/xwn + HP8nPif/MFEw/zdiN/8lqyP/PG48/zxwPP87bTv/O2k7/0hwSP9bfFv/bH5s/32Bff+AgID/fHx8/3h4 + eP92dnb/c3Nz/3BwcP9qamr/ZmZm/2VlZf9oaGj/bGxs/21tbf+CgoL/9/f4/9/f4P+UlJT9rKysKgAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADIzM49s7m5/zdk + N/86bDr/PHA8/zxvPP86azr/N2I3/zNUM/8wSTD/LTot/yoqKv8sLCz/Li4u/1paWv9oaGj/YmJi/2Fh + Yf9gYGD/X19f/2NjY/98fHz/hYSD/5qUk/+alZP/qaSj/7Kwr//ExcT/ztHS/9rf4//e5un25eXl497e + 3r+7u7tiAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AADCw8YevMXG/zRTNP8eMR7/FBgU/xMTE/8WFhb/FhYW/xgYGP8iIiL/LS0t/0RERP9WVlb/a2lp/4WB + gP+dmZn/paOi/7u4uP+8u7v/ztDS/9DT1P/P1db4ztPV8c7T1t/O1dfK09nbqdPX2IvT1dhey8zNNtDR + 0Rza2toW3NzcEN7e3gcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAADBwsQSt77B7U5OTv8kJCT/TUtL/2xkY/+De3r/kIuL/6Smpv+0vL7/w9DT/8rX + 2P/L29z/y9ja+MvS1OfLz9DZy87PycnNzqvNz9CQzc7Qdc7OzkXJy8ooyMjICQAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACop6sRsrGz5cHIyf+8zM//xNLW/8XR1PbHz9Loyc/Q1MjL + y77Iycurx8jIksnKynLJyclYy8vMN8rKyhgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACbm58Ep6epZsTCxJDAvr95u7u9Wr+9 + vz3Dw8MnyMjJDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAq6utCNLR + 0g/DwsMDu7u9AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////8AAP// + /////wAA////////AAD///wAH/8AAP//8AAHjwAA///gAAEBAAD//8AAAAAAAP//gAAAAAAA//+AAAAA + AAD//4AAAAAAAP//gAAAAAAAwAeAAAAAAACAAcAAAAAAAIAAcAAADwAAgAAMAAAPAACAAAAAAA8AAIAA + AAAADwAAgAAAAAAPAACAAAAAAA8AAIAAAAAADwAAgAAAAAAPAACAAAAAAAcAAIAAAAAABwAAgAAAAAAH + AACAAAAAAAcAAIAAAAAABwAAgAAAAAAHAACAAAAAAAcAAIAAAAAABwAAgAAAAAADAACAAAAAAAMAAIAA + AAAAAwAAgAAAAAADAACAAAAAAAMAAMAAAAAAAwAA8AAAAAADAAD+AAAAAAEAAP/AAAAAAQAA//AAAAAB + AAD/8AAAAAMAAP/wAAAABwAA//AAAB//AAD/8AAf//8AAP/wD////wAA//h/////AAD///////8AAP// + /////wAA////////AAAoAAAAIAAAAEAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAALCwsAS4uLhKqqqqhra2tpa5ubmVoaGhlYGBgYd3d3dOdnZ2BgAAAAAAAAAAAAAAAAAA + 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 + AAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkZCQ/3t5ef+RkJD/AAAAAAAA + AAAAAAAAu7y8/7u8vP+0tbX/m5yc/5ucnP+foKD/oKCg/wAAAAAAAAAAAAAAALS0tNOUlJT/np6ezQAA + AAAAAAAAAAAAANLS0oLIycn/xMbG/7m6uv+qq6v/oKCg/6CgoGEAAAAAAAAAAAAAAACrq6v3v7+//6Wl + pf8AAAAAAAAAAAAAAAAAAAAA3t7eNrm6uv+Kior/l5eX7KCgoDYAAAAAAAAAAAAAAAAAAAAArq6u99HR + 0f+rq6v/w8TEhsDBwf++v7//u7y8/7i5uf+1trb/qqqq/6ioqP+mpqb/pKSk/6Kiov+goKD/oKCgla2t + rffR0dH/q6ur/83Pz//Nz8//zc7P/8zOzv/Lzc3/yszM/8fJyf/Gycn/xsnJ/8XIyP/FyMj/xMfH/6Cg + oP+tra330dHR/6urq//O0ND/ra6u/wEBAf8DAwP/AQEB/wMDA/8LCwv/GBgY/xkZGf8bGxv/FBQU/8XI + yP+hoaH/rq6u99HR0f+srKz/z9HR/6usrP8YGBj/GRkZ/wwMDP8RERH/JiYm/yyCKv8iph//Q0ND/yws + LP/Ex8f/o6Oj/5a9o/cA8kj/YsKC/8/R0f+pqan/KCgo/xsbG/8PDw//FhYW/zJbMf8muSL/LZ8r/zmO + N/9DQ0P/xcjI/6Wlpf+rq6v3SERD/3t5ef/R0tL/o6Oj/w/yCv8RpA7/ExMT/xsfG/8b0xf/Xl5e/1pa + Wv8mySL/EPAL/8fKyv+rq6v/vr6+lL6+vv++vr7A0NLS/6Kiov8hISH/EngQ/xd8Ff8WsxP/W3Za/2lp + af9nZ2f/aWlp/2FhYf/Hysr/ra6u/wAAAAAAAAAAAAAAANHS0/+goKD/EhIS/xgYGP8XqBP/I2oh/3Z2 + dv9zc3P/dXV1/3d3d/9sbGz/yMrL/7Cxsf8AAAAAAAAAAAAAAADR0tP/oKCg/xMTE/8eHh7/KCgo/zQ0 + NP9paWn/YWFh/2BgYP9dXV3/VlZW/8nLy/+ys7P/AAAAAAAAAAAAAAAA0dLT/6CgoP+goKD/oKCg/6Ki + ov+kpKT/ra6u/7CwsP+ys7P/tba2/7i5uf/Jy8z/tba2/wAAAAAAAAAAAAAAANHS03jR0tP/0dLT/9HS + 0//Q0tL/0NHS/87Q0P/Nz8//zc/P/8zOzv/Lzc3/yszM/7i5uZUAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//+sQRwHrEEcB6xBHg+sQQAA + rEEAAKxBAACsQQAArEEAAKxBAACsQQAArEHgAKxB4ACsQeAArEHgAKxB//+sQQ== + + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/TerminatorWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/TerminatorWindow.Designer.cs new file mode 100644 index 000000000..4706d16e3 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/TerminatorWindow.Designer.cs @@ -0,0 +1,128 @@ +namespace ProcessHacker +{ + partial class TerminatorWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TerminatorWindow)); + this.labelProgress = new System.Windows.Forms.Label(); + this.listTests = new System.Windows.Forms.ListView(); + this.columnID = new System.Windows.Forms.ColumnHeader(); + this.columnDescription = new System.Windows.Forms.ColumnHeader(); + this.imageList = new System.Windows.Forms.ImageList(this.components); + this.buttonRun = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // labelProgress + // + this.labelProgress.AutoSize = true; + this.labelProgress.Location = new System.Drawing.Point(12, 9); + this.labelProgress.Name = "labelProgress"; + this.labelProgress.Size = new System.Drawing.Size(53, 13); + this.labelProgress.TabIndex = 0; + this.labelProgress.Text = "Message."; + // + // listTests + // + this.listTests.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnID, + this.columnDescription}); + this.listTests.FullRowSelect = true; + this.listTests.Location = new System.Drawing.Point(12, 38); + this.listTests.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.listTests.Name = "listTests"; + this.listTests.ShowItemToolTips = true; + this.listTests.Size = new System.Drawing.Size(442, 356); + this.listTests.SmallImageList = this.imageList; + this.listTests.TabIndex = 1; + this.listTests.UseCompatibleStateImageBehavior = false; + this.listTests.View = System.Windows.Forms.View.Details; + this.listTests.DoubleClick += new System.EventHandler(this.listTests_DoubleClick); + // + // columnID + // + this.columnID.Text = "ID"; + // + // columnDescription + // + this.columnDescription.Text = "Description"; + this.columnDescription.Width = 350; + // + // imageList + // + this.imageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList.ImageStream"))); + this.imageList.TransparentColor = System.Drawing.Color.Transparent; + this.imageList.Images.SetKeyName(0, "tick"); + this.imageList.Images.SetKeyName(1, "cross"); + // + // buttonRun + // + this.buttonRun.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonRun.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonRun.Location = new System.Drawing.Point(379, 402); + this.buttonRun.Margin = new System.Windows.Forms.Padding(3, 4, 3, 4); + this.buttonRun.Name = "buttonRun"; + this.buttonRun.Size = new System.Drawing.Size(75, 22); + this.buttonRun.TabIndex = 2; + this.buttonRun.Text = "&Run"; + this.buttonRun.UseVisualStyleBackColor = true; + this.buttonRun.Click += new System.EventHandler(this.buttonRun_Click); + // + // TerminatorWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(466, 437); + this.Controls.Add(this.buttonRun); + this.Controls.Add(this.listTests); + this.Controls.Add(this.labelProgress); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.Margin = new System.Windows.Forms.Padding(2, 4, 2, 4); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "TerminatorWindow"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Process Terminator"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label labelProgress; + private System.Windows.Forms.ListView listTests; + private System.Windows.Forms.Button buttonRun; + private System.Windows.Forms.ColumnHeader columnDescription; + private System.Windows.Forms.ImageList imageList; + private System.Windows.Forms.ColumnHeader columnID; + + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/TerminatorWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/TerminatorWindow.cs new file mode 100644 index 000000000..cf09ec588 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/TerminatorWindow.cs @@ -0,0 +1,440 @@ +/* + * Process Hacker - + * terminator tool + * + * Copyright (C) 2008 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 . + */ + +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker +{ + public partial class TerminatorWindow : Form + { + private int _pid; + private List _tests = new List(); + + public TerminatorWindow(int PID) + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + _pid = PID; + + labelProgress.Text = ""; + + this.AddTest("TP1", "Terminates the process using NtTerminateProcess"); + this.AddTest("TP2", "Creates a remote thread in the process which terminates the process"); + this.AddTest("TT1", "Terminates the process' threads"); + this.AddTest("TT2", "Modifies the process' threads with contexts which terminate the process"); + if (OSVersion.IsAboveOrEqual(WindowsVersion.Vista)) + { + this.AddTest("TP1a", "Terminates the process using NtTerminateProcess (alternative method)"); + this.AddTest("TT1a", "Terminates the process' threads (alternative method)"); + } + this.AddTest("CH1", "Closes the process' handles"); + this.AddTest("W1", "Sends the WM_DESTROY message to the process' windows"); + this.AddTest("W2", "Sends the WM_QUIT message to the process' windows"); + this.AddTest("TJ1", "Assigns the process to a job object and terminates the job"); + this.AddTest("TD1", "Debugs the process and closes the debug object"); + this.AddTest("TP3", "Terminates the process in kernel-mode (if possible)"); + this.AddTest("TT3", "Terminates the process' threads in kernel-mode (if possible)"); + if (KProcessHacker.Instance != null) + this.AddTest("TT4", "Terminates the process' threads using a dangerous kernel-mode method"); + this.AddTest("M1", "Writes garbage to the process' memory regions"); + this.AddTest("M2", "Sets the page protection of the process' memory regions to PAGE_NOACCESS"); + } + + private void AddTest(string id, string description) + { + ListViewItem item = new ListViewItem(); + + item.Name = id; + item.Text = id; + item.Tag = Delegate.CreateDelegate(typeof(MethodInvoker), this, id); + item.ImageKey = ""; + + item.SubItems.Add(new ListViewItem.ListViewSubItem(item, description)); + + listTests.Items.Add(item); + _tests.Add(id); + } + + private bool RunTest(string id) + { + this.Cursor = Cursors.WaitCursor; + + ListViewItem item = listTests.Items[id]; + + bool hadException = false; + + try + { + (item.Tag as Delegate).DynamicInvoke(null); + } + catch (Exception ex) + { + item.ToolTipText = ex.InnerException.Message; + item.ImageKey = "cross"; + hadException = true; + } + + this.Cursor = Cursors.Default; + + System.Threading.Thread.Sleep(1000); + + try + { + System.Diagnostics.Process.GetProcessById(_pid); + + if (!hadException) + { + item.ToolTipText = "Process was not terminated."; + item.ImageKey = "cross"; + } + } + catch + { + // the process doesn't exist (or at least we think it doesn't) + labelProgress.Text = "Process was terminated."; + + item.ToolTipText = "This test succeeded"; + item.ImageKey = "tick"; + + return true; + } + + // HACK + Application.DoEvents(); + + return false; + } + + private void CH1() + { + using (ProcessHandle phandle = new ProcessHandle(_pid, ProcessAccess.DupHandle)) + { + int i = 0; + + while (true) + { + if (i >= 0x1000) + break; + + try + { + Win32.DuplicateObject(phandle, new IntPtr(i), 0, 0, DuplicateOptions.CloseSource); + } + catch + { } + + i++; + } + } + } + + private void M1() + { + this.M1Internal(); + } + + private unsafe void M1Internal() + { + using (MemoryAlloc alloc = new MemoryAlloc(0x1000)) + { + using (ProcessHandle phandle = new ProcessHandle(_pid, + ProcessAccess.QueryInformation | + Program.MinProcessWriteMemoryRights)) + { + phandle.EnumMemory((info) => + { + for (int i = 0; i < info.RegionSize.ToInt32(); i += 0x1000) + { + try + { + phandle.WriteMemory(info.BaseAddress.Increment(i), (IntPtr)alloc, 0x1000); + } + catch + { } + } + + return true; + }); + } + } + } + + private void M2() + { + using (ProcessHandle phandle = new ProcessHandle(_pid, + ProcessAccess.QueryInformation | ProcessAccess.VmOperation)) + { + phandle.EnumMemory((info) => + { + phandle.ProtectMemory(info.BaseAddress, info.RegionSize.ToInt32(), MemoryProtection.NoAccess); + return true; + }); + } + } + + private void TD1() + { + using (var dhandle = + DebugObjectHandle.Create(DebugObjectAccess.ProcessAssign, DebugObjectFlags.KillOnClose)) + { + using (var phandle = new ProcessHandle(_pid, ProcessAccess.SuspendResume)) + phandle.Debug(dhandle); + } + } + + private void TJ1() + { + if (KProcessHacker.Instance != null) + { + try + { + using (var phandle = new ProcessHandle(_pid, Program.MinProcessQueryRights)) + { + var jhandle = phandle.GetJobObject(JobObjectAccess.Query | JobObjectAccess.Terminate); + + if (jhandle != null) + { + // Make sure we're not terminating more than one process + if (jhandle.GetProcessIdList().Length == 1) + { + jhandle.Terminate(); + return; + } + } + } + } + catch + { } + } + + using (var jhandle = JobObjectHandle.Create(JobObjectAccess.AssignProcess | JobObjectAccess.Terminate)) + { + using (ProcessHandle phandle = + new ProcessHandle(_pid, ProcessAccess.SetQuota | ProcessAccess.Terminate)) + { + phandle.AssignToJobObject(jhandle); + } + + jhandle.Terminate(); + } + } + + private void TP1() + { + using (ProcessHandle phandle = new ProcessHandle(_pid, ProcessAccess.Terminate)) + { + // Don't use KPH. + Win32.NtTerminateProcess(phandle, NtStatus.Success).ThrowIf(); + } + } + + private void TP1a() + { + ProcessHandle phandle = ProcessHandle.Current; + bool found = false; + + // Loop through the processes until we find our target process. + for (int count = 0; count < 1000; count++) + { + try + { + phandle = phandle.GetNextProcess(Program.MinProcessQueryRights | ProcessAccess.Terminate); + + if (phandle.GetProcessId() == _pid) + { + found = true; + break; + } + } + catch + { } + } + + if (found) + phandle.Terminate(); + } + + private void TP2() + { + using (ProcessHandle phandle = new ProcessHandle(_pid, + ProcessAccess.CreateThread | ProcessAccess.VmOperation | ProcessAccess.VmWrite)) + { + if (OSVersion.IsAboveOrEqual(WindowsVersion.Vista)) + { + // Vista and above export. + phandle.CreateThread(Loader.GetProcedure("ntdll.dll", "RtlExitUserProcess"), IntPtr.Zero); + } + else + { + phandle.CreateThread(Loader.GetProcedure("kernel32.dll", "ExitProcess"), IntPtr.Zero); + } + } + } + + private void TP3() + { + using (ProcessHandle phandle = new ProcessHandle(_pid, Program.MinProcessQueryRights)) + { + phandle.Terminate(); + } + } + + private void TT1() + { + foreach (var thread in Windows.GetProcessThreads(_pid).Values) + { + using (ThreadHandle thandle = new ThreadHandle(thread.ClientId.ThreadId, ThreadAccess.Terminate)) + { + // Don't use KPH. + Win32.NtTerminateThread(thandle, NtStatus.Success).ThrowIf(); + } + } + } + + private void TT1a() + { + using (var phandle = new ProcessHandle(_pid, ProcessAccess.QueryInformation)) + { + ThreadHandle thandle = null; + + // Loop through the process' threads and terminate each one. + for (int count = 0; count < 1000; count++) + { + try + { + thandle = phandle.GetNextThread(thandle, ThreadAccess.Terminate); + thandle.Terminate(); + } + catch + { } + } + } + } + + private void TT2() + { + Context context; + IntPtr exitProcess = Loader.GetProcedure("kernel32.dll", "ExitProcess"); + + foreach (var thread in Windows.GetProcessThreads(_pid).Values) + { + using (ThreadHandle thandle = new ThreadHandle(thread.ClientId.ThreadId, + ThreadAccess.GetContext | ThreadAccess.SetContext)) + { + try + { + context = thandle.GetContext(ContextFlags.Control); + context.ContextFlags = ContextFlags.Control; + context.Eip = exitProcess.ToInt32(); + thandle.SetContext(context); + } + catch + { } + } + } + } + + private void TT3() + { + foreach (var thread in Windows.GetProcessThreads(_pid).Values) + { + using (ThreadHandle thandle = new ThreadHandle(thread.ClientId.ThreadId, ThreadAccess.Terminate)) + { + thandle.Terminate(); + } + } + } + + private void TT4() + { + foreach (var thread in Windows.GetProcessThreads(_pid).Values) + { + using (ThreadHandle thandle = new ThreadHandle(thread.ClientId.ThreadId, ThreadAccess.Terminate)) + { + thandle.DangerousTerminate(NtStatus.Success); + } + } + } + + private void W1() + { + WindowHandle.Enumerate((window) => + { + if (window.GetClientId().ProcessId == _pid) + window.PostMessage(WindowMessage.Destroy, 0, 0); + + return true; + }); + } + + private void W2() + { + WindowHandle.Enumerate((window) => + { + if (window.GetClientId().ProcessId == _pid) + window.PostMessage(WindowMessage.Quit, 0, 0); + + return true; + }); + } + + private void buttonRun_Click(object sender, EventArgs e) + { + if (!PhUtils.ShowConfirmMessage("run", "the tests", null, false)) + return; + + foreach (string test in _tests) + { + if (test == "TT4") + { + if (!PhUtils.ShowConfirmMessage( + "run", + "the TT4 test", + "This test may cause the system to crash.", + true + )) + continue; + } + + if (this.RunTest(test)) + return; + } + } + + private void listTests_DoubleClick(object sender, EventArgs e) + { + if (!PhUtils.ShowConfirmMessage("run", "the selected test", null, false)) + return; + + this.RunTest(listTests.SelectedItems[0].Name); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/TerminatorWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/TerminatorWindow.resx new file mode 100644 index 000000000..009bf9b6f --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/TerminatorWindow.resx @@ -0,0 +1,161 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj0yLjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAAi + BwAAAk1TRnQBSQFMAgEBAgEAAQQBAAEEAQABEAEAARABAAT/ASEBAAj/AUIBTQE2BwABNgMAASgDAAFA + AwABEAMAAQEBAAEgBgABEP8AJwADBwEKAwUBBzAAAyoBQQMGAQgYAAMGAQgDKgFBnAADBwEKATABgwE2 + Af8BMgFnATIB+wMFAQcoAAMqAUEBSAFFAfIB/wJAAdkB/QMGAQgQAAMGAQgBKwEpAcgB/AEqASgB6gH/ + AyoBQZQAAwcBCgE5AY4BQAH/AU0BowFVAf8BSAGfAVAB/wEyAXwBOAH+AwYBCCAAAyoBQQFRAU8B9QH/ + AVwBWgH6Af8BUQFOAfYB/wE6ATkBzgH8AwYBCAgAAwYBCAIrAcoB/AE6ATgB8QH/AUUBQwH2Af8BKgEo + AeoB/wMqAUGMAAMHAQoBQgGaAUoB/wFUAawBXQH/AXABygGCAf8BbQHIAXcB/wFKAaABUgH/ATMBfQE5 + Af4DBgEIHAADHgErAVQBUQH2Af8BXgFbAfoB/wFqAWkC/wFSAU8B9gH/AToBOQHOAfwDBgEIAwYBCAEv + ASwBywH8AUABPgHyAf8BXAFbAv8BQwFBAfQB/wEoASYB6QH/Ax4BK4gAAwcBCgFKAaYBUwH/AVwBtQFm + Af8BdwHOAYkB/wF0AcwBhwH/AW8BygGBAf8BbwHJAYEB/wFLAaIBUwH/ATQBfgE6Af4DBgEIHAADHgEr + AVQBUgH2Af8BXwFcAfoB/wFtAWoC/wFTAVEB9gH/ATsBOgHOAfwCQAHYAf0BSQFGAfQB/wFhAWAC/wFJ + AUcB9QH/AS8BLQHrAf8DHgEriAADBwEJAVIBsAFcAf8BZAG9AW8B/wGEAdIBkAH/AXMByQGFAf8BWQGy + AWMB/wFcAbQBZgH/AXEByQGDAf8BcQHLAYIB/wFMAaMBVQH/ATsBcwFAAf0DBgEIHAADHgErAVUBUwH2 + Af8BYAFdAfoB/wFtAWsC/wFsAWkC/wFpAWcC/wFnAWUC/wFQAU4B9wH/ATgBNgHuAf8DHgErjAADLQFG + AVoBcAFhAeQBcgHJAYYB/wGAAc4BjQH/AUQBkgFRAfwDQAFvA0oBiwFVAa0BYAH/AXUBzAGGAf8BcgHL + AYUB/wFNAaQBVgH/AS8BeAE1AfwDBgEIHAADHgErAVYBVAH3Af8BcgFvAv8BUgFPAv8BUAFNAv8BawFp + Av8BQQE/AfAB/wMeASuUAAMoATwBYQF4AWEB5gFmAcABcgH/A0ABbwgAAUwCTQGRAVcBrgFhAf8BdgHN + AYkB/wF1Ac0BhwH/AU8BpQFYAf8BMAF5ATYB/AMGAQgYAAMGAQgBUgFRAeIB/QF2AXIC/wFXAVQC/wFU + AVEC/wFvAW0C/wJAAdsB/QMGAQiYAAMsAUMDOwFlEAABTAJNAZEBWAGvAWIB/wF4Ac4BigH/AXcBzgGJ + Af8BUAGmAVkB/wExAXkBNwH8AwYBCBAAAwYBCAFfAVwB1wH8AWkBZgH7Af8BgAF3Av8BdwF0Av8BdQFy + Av8BcgFwAv8BVwFVAfcB/wE9ATsBzwH8AwYBCLAAAUwCTQGRAVkBsAFjAf8BgQHPAY0B/wF4Ac8BiwH/ + AVEBpwFaAf8BMgGFATkB/wMGAQgIAAMGAQgBZwFkAdoB/AFwAW0B/QH/AYYBggL/AW8BbAH8Af8BXQFb + AfgB/wFZAVYB9wH/AWYBYwH6Af8BdAFyAv8BWQFWAfcB/wE9ATwBzwH8AwYBCLAAAUwCTQGRAVsBsgFl + Af8BggHRAY8B/wFzAcgBhQH/AVABpgFZAf8DRAF7BAADBgEIAWcBZAHqAf0BdgFzAf4B/wGKAYcC/wF1 + AXIB/QH/AWUBYgH7Af8DHgErAx4BKwFaAVcB+AH/AWcBZQH6Af8BdgFzAv8BWgFYAfcB/wE+ATwB0AH8 + AwQBBbAAA00BkQFcAbMBZgH/AVgBrwFiAf8DRAF5CAADFgEfAXMBcAL/AYEBdwL/AYEBdwH+Af8BbQFq + Af0B/wMeASsIAAMeASsBWwFYAfgB/wFoAWYB+wH/AXcBdQL/AVsBWAH4Af8DQAFvAwEBArAAA00BkQNG + AX8QAAMWAR8BcwFwAv8BcgFvAf4B/wMeASsQAAMeASsBXQFaAfgB/wFjAWEB+QH/AVMBUgFTAagDHQEp + 0AADFgEfAx4BKxgAAx4BKwNAAW8DKQE++AADBwEKjAABQgFNAT4HAAE+AwABKAMAAUADAAEQAwABAQEA + AQEFAAGAFwAD/wEABP8EAAH5Af8C5wQAAfAB/wLDBAAB4AF/AoEEAAHAAT8BgAEBBAABgAEfAcABAwUA + AQ8B4AEHBQABBwHwAQ8EAAGGAQMB8AEPBAABzwEBAeABBwQAAf8BgAHAAQMEAAH/AcABgAEBBAAB/wHh + AYEBgAQAAf8B8wHDAcEEAAL/AecB4wQAA/8B9wQACw== + + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/ThreadWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/ThreadWindow.Designer.cs new file mode 100644 index 000000000..2f69e5a1f --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ThreadWindow.Designer.cs @@ -0,0 +1,148 @@ +namespace ProcessHacker +{ + partial class ThreadWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + if (_phandle != null && _processHandleOwned) + _phandle.Dispose(); + if (_thandle != null) + _thandle.Dispose(); + + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ThreadWindow)); + this.vistaMenu = new wyDay.Controls.VistaMenu(this.components); + this.fileModule = new ProcessHacker.Components.FileNameBox(); + this.label1 = new System.Windows.Forms.Label(); + this.buttonWalk = new System.Windows.Forms.Button(); + this.listViewCallStack = new System.Windows.Forms.ListView(); + this.columnHeader3 = new System.Windows.Forms.ColumnHeader(); + this.columnHeader4 = new System.Windows.Forms.ColumnHeader(); + ((System.ComponentModel.ISupportInitialize)(this.vistaMenu)).BeginInit(); + this.SuspendLayout(); + // + // vistaMenu + // + this.vistaMenu.ContainerControl = this; + this.vistaMenu.DelaySetImageCalls = false; + // + // fileModule + // + this.fileModule.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.fileModule.Location = new System.Drawing.Point(63, 347); + this.fileModule.Name = "fileModule"; + this.fileModule.ReadOnly = false; + this.fileModule.Size = new System.Drawing.Size(243, 24); + this.fileModule.TabIndex = 9; + // + // label1 + // + this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 353); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(45, 13); + this.label1.TabIndex = 8; + this.label1.Text = "Module:"; + // + // buttonWalk + // + this.buttonWalk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonWalk.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonWalk.Location = new System.Drawing.Point(312, 348); + this.buttonWalk.Name = "buttonWalk"; + this.buttonWalk.Size = new System.Drawing.Size(75, 23); + this.buttonWalk.TabIndex = 7; + this.buttonWalk.Text = "&Refresh"; + this.buttonWalk.UseVisualStyleBackColor = true; + this.buttonWalk.Click += new System.EventHandler(this.buttonWalk_Click); + // + // listViewCallStack + // + this.listViewCallStack.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listViewCallStack.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeader3, + this.columnHeader4}); + this.listViewCallStack.FullRowSelect = true; + this.listViewCallStack.HideSelection = false; + this.listViewCallStack.Location = new System.Drawing.Point(12, 12); + this.listViewCallStack.Name = "listViewCallStack"; + this.listViewCallStack.ShowItemToolTips = true; + this.listViewCallStack.Size = new System.Drawing.Size(375, 329); + this.listViewCallStack.TabIndex = 6; + this.listViewCallStack.UseCompatibleStateImageBehavior = false; + this.listViewCallStack.View = System.Windows.Forms.View.Details; + this.listViewCallStack.SelectedIndexChanged += new System.EventHandler(this.listViewCallStack_SelectedIndexChanged); + // + // columnHeader3 + // + this.columnHeader3.Text = "Address"; + this.columnHeader3.Width = 100; + // + // columnHeader4 + // + this.columnHeader4.Text = "Symbol Name"; + this.columnHeader4.Width = 220; + // + // ThreadWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(399, 383); + this.Controls.Add(this.fileModule); + this.Controls.Add(this.label1); + this.Controls.Add(this.buttonWalk); + this.Controls.Add(this.listViewCallStack); + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ThreadWindow"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Thread"; + this.Load += new System.EventHandler(this.ThreadWindow_Load); + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.ThreadWindow_FormClosing); + ((System.ComponentModel.ISupportInitialize)(this.vistaMenu)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private wyDay.Controls.VistaMenu vistaMenu; + private ProcessHacker.Components.FileNameBox fileModule; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Button buttonWalk; + private System.Windows.Forms.ListView listViewCallStack; + private System.Windows.Forms.ColumnHeader columnHeader3; + private System.Windows.Forms.ColumnHeader columnHeader4; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/ThreadWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/ThreadWindow.cs new file mode 100644 index 000000000..72d6a6b97 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ThreadWindow.cs @@ -0,0 +1,331 @@ +/* + * Process Hacker - + * thread properties window + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Reflection; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Native; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; +using ProcessHacker.Native.Symbols; +using ProcessHacker.UI; + +namespace ProcessHacker +{ + public partial class ThreadWindow : Form + { + private int _pid; + private int _tid; + private ProcessHandle _phandle; + private bool _processHandleOwned = true; + private ThreadHandle _thandle; + private SymbolProvider _symbols; + + public const string DisplayFormat = "0x{0:x}"; + + public string Id + { + get { return _pid + "-" + _tid; } + } + + public ThreadWindow(int PID, int TID, SymbolProvider symbols, ProcessHandle processHandle) + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + listViewCallStack_SelectedIndexChanged(null, null); + + _pid = PID; + _tid = TID; + _symbols = symbols; + + this.Text = Program.ProcessProvider.Dictionary[_pid].Name + " (PID " + _pid.ToString() + + ") - Thread " + _tid.ToString(); + + PropertyInfo property = typeof(ListView).GetProperty("DoubleBuffered", + BindingFlags.NonPublic | BindingFlags.Instance); + + property.SetValue(listViewCallStack, true, null); + + listViewCallStack.ContextMenu = listViewCallStack.GetCopyMenu(); + + try + { + if (processHandle != null) + { + _phandle = processHandle; + _processHandleOwned = false; + } + else + { + try + { + _phandle = new ProcessHandle(_pid, + ProcessAccess.QueryInformation | ProcessAccess.VmRead + ); + } + catch + { + if (KProcessHacker.Instance != null) + { + _phandle = new ProcessHandle(_pid, Program.MinProcessReadMemoryRights); + } + else + { + throw; + } + } + } + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to open the process", ex); + + this.Close(); + + return; + } + + try + { + try + { + _thandle = new ThreadHandle(_tid, ThreadAccess.GetContext | ThreadAccess.SuspendResume); + } + catch + { + if (KProcessHacker.Instance != null) + { + _thandle = new ThreadHandle(_tid, + Program.MinThreadQueryRights | ThreadAccess.SuspendResume + ); + } + else + { + throw; + } + } + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to open the thread", ex); + + this.Close(); + + return; + } + } + + private void ThreadWindow_Load(object sender, EventArgs e) + { + listViewCallStack.SetTheme("explorer"); + listViewCallStack.AddShortcuts(); + + this.Size = Properties.Settings.Default.ThreadWindowSize; + ColumnSettings.LoadSettings(Properties.Settings.Default.CallStackColumns, listViewCallStack); + + this.WalkCallStack(); + } + + private void ThreadWindow_FormClosing(object sender, FormClosingEventArgs e) + { + Properties.Settings.Default.ThreadWindowSize = this.Size; + Properties.Settings.Default.CallStackColumns = ColumnSettings.SaveSettings(listViewCallStack); + _symbols = null; + } + + private void WalkCallStack() + { + try + { + // Clear the existing frames. + listViewCallStack.BeginUpdate(); + listViewCallStack.Items.Clear(); + + bool suspended; + + try + { + _thandle.Suspend(); + suspended = true; + } + catch + { + suspended = false; + } + + try + { + // Process the kernel-mode stack (if KPH is present). + if (KProcessHacker.Instance != null) + { + this.WalkKernelStack(); + } + + // Process the user-mode stack. + // If we're on 64-bit and the process is running + // under WOW64, get the 32-bit stack as well. + + _thandle.WalkStack(_phandle, this.WalkStackCallback); + + if (IntPtr.Size == 8 && _phandle.IsWow64()) + { + _thandle.WalkStack(_phandle, this.WalkStackCallback, OSArch.I386); + } + } + finally + { + if (suspended) + _thandle.Resume(); + } + } + catch (Exception ex) + { + Logging.Log(ex); + } + finally + { + listViewCallStack.EndUpdate(); + } + } + + private void WalkKernelStack() + { + try + { + IntPtr[] frames = _thandle.CaptureKernelStack(1); // skip the KPH frame + + foreach (IntPtr frame in frames) + { + ulong address = frame.ToUInt64(); + + try + { + ListViewItem newItem = listViewCallStack.Items.Add(new ListViewItem( + new string[] + { + Utils.FormatAddress(address), + _symbols.GetSymbolFromAddress(address) + })); + + newItem.Tag = address; + } + catch (Exception ex2) + { + Logging.Log(ex2); + } + } + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + + private bool WalkStackCallback(ThreadStackFrame stackFrame) + { + ulong address = stackFrame.PcAddress.ToUInt64(); + + // HACK for XP where the top user-mode frame for system threads is always 0xffffffff + if (_pid == 4) + { + if (OSVersion.WindowsVersion == WindowsVersion.XP && address == 0xffffffff) + return true; + } + + try + { + ListViewItem newItem = listViewCallStack.Items.Add(new ListViewItem( + new string[] + { + Utils.FormatAddress(address), + _symbols.GetSymbolFromAddress(address) + })); + + newItem.Tag = address; + + try + { + if (stackFrame.Params.Length > 0) + newItem.ToolTipText = "Parameters: "; + + foreach (IntPtr arg in stackFrame.Params) + newItem.ToolTipText += Utils.FormatAddress(arg) + ", "; + + if (newItem.ToolTipText.EndsWith(", ")) + newItem.ToolTipText = newItem.ToolTipText.Remove(newItem.ToolTipText.Length - 2); + + try + { + string fileAndLine = _symbols.GetLineFromAddress(address); + + if (fileAndLine != null) + newItem.ToolTipText += "\nFile: " + fileAndLine; + } + catch + { } + } + catch (Exception ex2) + { + Logging.Log(ex2); + } + } + catch (Exception ex) + { + Logging.Log(ex); + + ListViewItem newItem = listViewCallStack.Items.Add(new ListViewItem(new string[] { + Utils.FormatAddress(address), + "???" + })); + + newItem.Tag = address; + } + + return true; + } + + private void buttonWalk_Click(object sender, EventArgs e) + { + this.WalkCallStack(); + } + + private void listViewCallStack_SelectedIndexChanged(object sender, EventArgs e) + { + if (listViewCallStack.SelectedItems.Count == 1) + { + string fileName; + + _symbols.GetSymbolFromAddress((ulong)listViewCallStack.SelectedItems[0].Tag, out fileName); + fileModule.Text = fileName; + fileModule.Enabled = true; + } + else + { + fileModule.Text = ""; + fileModule.Enabled = false; + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/ThreadWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/ThreadWindow.resx new file mode 100644 index 000000000..b98da9944 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/ThreadWindow.resx @@ -0,0 +1,176 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + + + 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 + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADCkGybwo1n/7+KZf+9h2P/uoRg/7iC + Xv+1f13/s31b/7F7Wf+welf/rXhW/6x1Vf+qdFP/qHJS/6hwUP+ib1CbyJFr/1FRUf9SUlL/U1NT/1RU + VP9VVVX/VlZW/1ZWVv9XV1f/WFhY/1lZWf9aWlr/W1tb/1tbW/9cXFz/qHFQ/8qTbf9NTU3/PDw8/zw8 + PP89PT3/Pj4+/0BAQP9BQUH/QkJC/0NDQ/9ERET/RUVF/0VFRf9HR0f/WVlZ/6lyUv/Mlm7/SkpK/zc3 + N/84ODj/OTk5/zs7O/88PDz/Pj4+/z4+Pv9AQED/QUFB/0FBQf9DQ0P/RERE/1ZWVv+rdFP/z5lx/0ZG + Rv8yMjL/MzMz/zU1Nf82Njb/ODg4/zk5Of86Ojr/Ozs7/z09Pf8+Pj7/Pz8//0BAQP9UVFT/rHdV/9Gb + cv9BQUH/Li4u/y8vL/8wMDD/MjIy/zMzM/81NTX/NTU1/zc3N/85OTn/Ojo6/zw8PP88PDz/UVFR/695 + V//UnXT/PDw8/ygoKP/R0dH/rKys/y0tLf8uLi7/MDAw/zExMf8zMzP/NTU1/zY2Nv83Nzf/OTk5/01N + Tf+xe1n/1Z91/zg4OP8kJCT/JSUl/97e3v9zc3P/KSkp/ysrK/8sLCz/Li4u/zAwMP8xMTH/MzMz/zQ0 + NP9KSkr/tH1b/9iheP8zMzP/Hx8f/8/Pz/+np6f/IyMj/yQkJP8lJSX/Jycn/ykpKf8rKyv/LCws/y4u + Lv8wMDD/RUVF/7aAXf/Zonj/MzMz/x8fH/8gICD/ISEh/yMjI/8kJCT/JSUl/ycnJ/8pKSn/Kysr/yws + LP8uLi7/MDAw/0VFRf+5hF//26N5/zAwMP8xMTH/MjIy/zMzM/80NDT/NTU1/zY2Nv84ODj/Ojo6/zs7 + O/88PDz/Pj4+/0BAQP9CQkL/vIZi/9ymev/bo3n/2qJ4/9iheP/XoHf/1Z51/9Odc//Rm3L/z5lx/82W + b//LlG3/yZNr/8eQav/Djmj/woxm/7+KZf/dq4T98dzO/+rAn//ouJH/6LiR/+i4kf/ouJH/6LiR/+i4 + kf/NyMT/6LiR/83IxP/ouJH/Q2P//+jDpv/Aj2793auFwt2wjPTcpnr/3KV5/9qjef/YoXj/2KB4/9Wf + df/UnXT/0pxy/8+Zcf/OmG//y5Vu/8mTa//DmXn0wpJwwgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD//6xBAACsQQAArEEAAKxBAACsQQAA + rEEAAKxBAACsQQAArEEAAKxBAACsQQAArEEAAKxBAACsQQAArEH//6xB + + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/TokenWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/TokenWindow.Designer.cs new file mode 100644 index 000000000..74f377046 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/TokenWindow.Designer.cs @@ -0,0 +1,85 @@ +namespace ProcessHacker +{ + partial class TokenWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + + _tokenProps.Dispose(); + + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.buttonClose = new System.Windows.Forms.Button(); + this.panelToken = new System.Windows.Forms.Panel(); + this.SuspendLayout(); + // + // buttonClose + // + this.buttonClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonClose.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonClose.Location = new System.Drawing.Point(378, 397); + this.buttonClose.Name = "buttonClose"; + this.buttonClose.Size = new System.Drawing.Size(75, 23); + this.buttonClose.TabIndex = 1; + this.buttonClose.Text = "&Close"; + this.buttonClose.UseVisualStyleBackColor = true; + this.buttonClose.Click += new System.EventHandler(this.buttonClose_Click); + // + // panelToken + // + this.panelToken.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panelToken.Location = new System.Drawing.Point(12, 12); + this.panelToken.Name = "panelToken"; + this.panelToken.Size = new System.Drawing.Size(441, 379); + this.panelToken.TabIndex = 2; + // + // TokenWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(465, 432); + this.Controls.Add(this.panelToken); + this.Controls.Add(this.buttonClose); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "TokenWindow"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Token"; + this.Load += new System.EventHandler(this.TokenWindow_Load); + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.TokenWindow_FormClosing); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Button buttonClose; + private System.Windows.Forms.Panel panelToken; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/TokenWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/TokenWindow.cs new file mode 100644 index 000000000..8dc756b6a --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/TokenWindow.cs @@ -0,0 +1,67 @@ +/* + * Process Hacker - + * token properties window + * + * Copyright (C) 2008 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 . + */ + +using System; +using System.Windows.Forms; +using ProcessHacker.Components; +using ProcessHacker.Native.Objects; + +namespace ProcessHacker +{ + public partial class TokenWindow : Form + { + TokenProperties _tokenProps; + + public TokenWindow(IWithToken obj) + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + _tokenProps = new TokenProperties(obj); + _tokenProps.Dock = DockStyle.Fill; + + panelToken.Controls.Add(_tokenProps); + } + + public TokenProperties TokenProperties + { + get { return _tokenProps; } + } + + private void TokenWindow_Load(object sender, EventArgs e) + { + this.Size = Properties.Settings.Default.TokenWindowSize; + } + + private void TokenWindow_FormClosing(object sender, FormClosingEventArgs e) + { + _tokenProps.SaveSettings(); + Properties.Settings.Default.TokenWindowSize = this.Size; + } + + private void buttonClose_Click(object sender, EventArgs e) + { + this.Close(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/TokenWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/TokenWindow.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/TokenWindow.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/UpdaterDownloadWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/UpdaterDownloadWindow.Designer.cs new file mode 100644 index 000000000..21ef7a944 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/UpdaterDownloadWindow.Designer.cs @@ -0,0 +1,169 @@ +namespace ProcessHacker +{ + partial class UpdaterDownloadWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(UpdaterDownloadWindow)); + this.labelProgress = new System.Windows.Forms.Label(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.pictureBox2 = new System.Windows.Forms.PictureBox(); + this.labelTitle = new System.Windows.Forms.Label(); + this.labelReleased = new System.Windows.Forms.Label(); + this.buttonStop = new System.Windows.Forms.Button(); + this.buttonInstall = new System.Windows.Forms.Button(); + this.progressDownload = new System.Windows.Forms.ProgressBar(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).BeginInit(); + this.SuspendLayout(); + // + // labelProgress + // + this.labelProgress.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.labelProgress.AutoSize = true; + this.labelProgress.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.labelProgress.Location = new System.Drawing.Point(12, 92); + this.labelProgress.Name = "labelProgress"; + this.labelProgress.Size = new System.Drawing.Size(101, 13); + this.labelProgress.TabIndex = 17; + this.labelProgress.Text = "Starting download..."; + // + // pictureBox1 + // + this.pictureBox1.Image = global::ProcessHacker.Properties.Resources.ProcessHacker; + this.pictureBox1.Location = new System.Drawing.Point(12, 12); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(48, 48); + this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; + this.pictureBox1.TabIndex = 19; + this.pictureBox1.TabStop = false; + // + // pictureBox2 + // + this.pictureBox2.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox2.Image"))); + this.pictureBox2.Location = new System.Drawing.Point(299, 12); + this.pictureBox2.Name = "pictureBox2"; + this.pictureBox2.Size = new System.Drawing.Size(80, 20); + this.pictureBox2.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; + this.pictureBox2.TabIndex = 21; + this.pictureBox2.TabStop = false; + // + // labelTitle + // + this.labelTitle.AutoSize = true; + this.labelTitle.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.labelTitle.Location = new System.Drawing.Point(66, 12); + this.labelTitle.Name = "labelTitle"; + this.labelTitle.Size = new System.Drawing.Size(169, 13); + this.labelTitle.TabIndex = 22; + this.labelTitle.Text = "Downloading: Process Hacker 0.0"; + // + // labelReleased + // + this.labelReleased.AutoSize = true; + this.labelReleased.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.labelReleased.Location = new System.Drawing.Point(66, 31); + this.labelReleased.Name = "labelReleased"; + this.labelReleased.Size = new System.Drawing.Size(180, 13); + this.labelReleased.TabIndex = 23; + this.labelReleased.Text = "Released: 00/00/0000 00:00:00 AM"; + // + // buttonStop + // + this.buttonStop.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonStop.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonStop.Location = new System.Drawing.Point(304, 83); + this.buttonStop.Name = "buttonStop"; + this.buttonStop.Size = new System.Drawing.Size(75, 23); + this.buttonStop.TabIndex = 1; + this.buttonStop.Text = "Stop"; + this.buttonStop.UseVisualStyleBackColor = true; + this.buttonStop.Click += new System.EventHandler(this.buttonStop_Click); + // + // buttonInstall + // + this.buttonInstall.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonInstall.Enabled = false; + this.buttonInstall.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonInstall.Location = new System.Drawing.Point(304, 54); + this.buttonInstall.Name = "buttonInstall"; + this.buttonInstall.Size = new System.Drawing.Size(75, 23); + this.buttonInstall.TabIndex = 0; + this.buttonInstall.Text = "Install"; + this.buttonInstall.UseVisualStyleBackColor = true; + this.buttonInstall.Click += new System.EventHandler(this.buttonInstall_Click); + // + // progressDownload + // + this.progressDownload.Location = new System.Drawing.Point(12, 112); + this.progressDownload.Name = "progressDownload"; + this.progressDownload.Size = new System.Drawing.Size(367, 23); + this.progressDownload.TabIndex = 25; + // + // UpdaterDownloadWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.WhiteSmoke; + this.ClientSize = new System.Drawing.Size(391, 147); + this.Controls.Add(this.progressDownload); + this.Controls.Add(this.buttonInstall); + this.Controls.Add(this.buttonStop); + this.Controls.Add(this.labelReleased); + this.Controls.Add(this.labelTitle); + this.Controls.Add(this.pictureBox2); + this.Controls.Add(this.pictureBox1); + this.Controls.Add(this.labelProgress); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MaximizeBox = false; + this.Name = "UpdaterDownloadWindow"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Process Hacker Update"; + this.Load += new System.EventHandler(this.UpdaterDownload_Load); + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.UpdaterDownloadWindow_FormClosing); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label labelProgress; + private System.Windows.Forms.PictureBox pictureBox1; + private System.Windows.Forms.PictureBox pictureBox2; + private System.Windows.Forms.Label labelTitle; + private System.Windows.Forms.Label labelReleased; + private System.Windows.Forms.Button buttonStop; + private System.Windows.Forms.Button buttonInstall; + private System.Windows.Forms.ProgressBar progressDownload; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/UpdaterDownloadWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/UpdaterDownloadWindow.cs new file mode 100644 index 000000000..932c2526d --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/UpdaterDownloadWindow.cs @@ -0,0 +1,329 @@ +/* + * Process Hacker - + * ProcessHacker Updater Download + * + * Copyright (C) 2009 wj32 + * Copyright (C) 2009 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 . + */ + +using System; +using System.ComponentModel; +using System.IO; +using System.Net; +using System.Text; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Common.Threading; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; + +namespace ProcessHacker +{ + public partial class UpdaterDownloadWindow : Form + { + private Updater.UpdateItem _updateItem; + private WebClient _webClient; + private string _fileName; + private ThreadTask _verifyTask; + private bool _redirected = false; + + public UpdaterDownloadWindow(Updater.UpdateItem updateItem) + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + _updateItem = updateItem; + } + + private void UpdaterDownload_Load(object sender, EventArgs e) + { + string version; + + version = _updateItem.Version.Major + "." + _updateItem.Version.Minor; + _fileName = Path.GetTempPath() + "processhacker-" + version + "-setup.exe"; + + labelTitle.Text = "Downloading: Process Hacker " + version; + labelReleased.Text = "Released: " + _updateItem.Date.ToString(); + + _webClient = new WebClient(); + _webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(webClient_DownloadProgressChanged); + _webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(webClient_DownloadFileCompleted); + _webClient.Headers.Add("User-Agent", "PH/" + version + " (compatible; PH " + + version + "; PH " + version + "; .NET CLR " + Environment.Version.ToString() + ";)"); + + try + { + _webClient.DownloadFileAsync(new Uri(_updateItem.Url), _fileName); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to download Process Hacker", ex); + this.Close(); + } + } + + private void UpdaterDownloadWindow_FormClosing(object sender, FormClosingEventArgs e) + { + if (_verifyTask != null) + _verifyTask.Cancel(); + + if (OSVersion.HasExtendedTaskbar) + { + TaskbarLib.Windows7Taskbar.SetTaskbarProgressState( + Program.HackerWindowHandle, + TaskbarLib.Windows7Taskbar.ThumbnailProgressState.NoProgress + ); + } + } + + private void webClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e) + { + // Check if the file is actually an executable file. + if (!_redirected) + { + _redirected = true; + + try + { + bool isHtml = false; + + using (var file = new BinaryReader(File.OpenRead(_fileName))) + { + if (!file.ReadChars(2).Equals("MZ".ToCharArray())) + { + isHtml = true; + } + } + + if (isHtml) + { + string text = File.ReadAllText(_fileName); + + // Assume this is from Ohloh. + int iframeIndex = text.IndexOf("window.delayed_iframe"); + + if (iframeIndex == -1) + return; + + int httpIndex = text.IndexOf("http://", iframeIndex); + + if (httpIndex == -1) + return; + + int quoteIndex = text.IndexOf("'", httpIndex); + + if (quoteIndex == -1) + return; + + _webClient.DownloadFileAsync(new Uri(text.Substring(httpIndex, quoteIndex - httpIndex)), _fileName); + + return; + } + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + + if (!e.Cancelled) + { + _verifyTask = new ThreadTask(); + _verifyTask.RunTask += verifyTask_RunTask; + _verifyTask.Completed += verifyTask_Completed; + _verifyTask.Start(); + } + else + { + var webException = e.Error as WebException; + + if (webException != null && webException.Status != WebExceptionStatus.RequestCanceled) + { + PhUtils.ShowException("Unable to download the update", webException); + } + } + } + + private void webClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) + { + labelProgress.Text = + "Downloaded " + + Utils.FormatSize(e.BytesReceived) + "/" + + Utils.FormatSize(e.TotalBytesToReceive) + + " (" + e.ProgressPercentage.ToString() + "%)"; + + progressDownload.Value = e.ProgressPercentage; + + if (OSVersion.HasExtendedTaskbar) + TaskbarLib.Windows7Taskbar.SetTaskbarProgress(Program.HackerWindow, this.progressDownload); + } + + private void verifyTask_RunTask(object param, ref object result) + { + byte[] buffer; + byte[] oldBuffer; + int bytesRead; + int oldBytesRead; + long size; + long totalBytesRead = 0; + + using (Stream stream = File.OpenRead(_fileName)) //Change to MD5.Create for MD5 verification + using (System.Security.Cryptography.HashAlgorithm hashAlgorithm = System.Security.Cryptography.SHA1.Create()) + { + size = stream.Length; + + buffer = new byte[4096]; + + bytesRead = stream.Read(buffer, 0, buffer.Length); + totalBytesRead += bytesRead; + + do + { + if (_verifyTask.Cancelled) + return; + + oldBytesRead = bytesRead; + oldBuffer = buffer; + + buffer = new byte[4096]; + bytesRead = stream.Read(buffer, 0, buffer.Length); + + totalBytesRead += bytesRead; + + if (bytesRead == 0) + { + hashAlgorithm.TransformFinalBlock(oldBuffer, 0, oldBytesRead); + } + else + { + hashAlgorithm.TransformBlock(oldBuffer, 0, oldBytesRead, oldBuffer, 0); + } + + if (this.IsHandleCreated) + { + this.BeginInvoke(new MethodInvoker(() => + { + this.progressDownload.Value = (int)((double)totalBytesRead * 100 / size); + })); + } + } while (bytesRead != 0); + + result = hashAlgorithm.Hash; + } + } + + private void verifyTask_Completed(object result) + { + if (this.InvokeRequired) + { + this.BeginInvoke(new ThreadTaskCompletedDelegate(verifyTask_Completed), result); + return; + } + + StringBuilder sb = new StringBuilder(); + + foreach (byte b in (byte[])result) + { + sb.AppendFormat("{0:x2}", b); + } + + if (_updateItem.Hash.Equals(sb.ToString(), StringComparison.InvariantCultureIgnoreCase)) + { + labelProgress.Text = "Download completed and SHA1 verified successfully."; + buttonInstall.Select(); + } + else + { + labelProgress.Text = "SHA1 hash verification failed!"; + labelProgress.Font = new System.Drawing.Font(labelProgress.Font, System.Drawing.FontStyle.Bold); + } + + // Allow the user to install in both cases, just in case our supplied hash is wrong. + buttonInstall.Enabled = true; + buttonStop.Text = "Close"; + + // Is elevation needed? + if (OSVersion.HasUac && Program.ElevationType == TokenElevationType.Limited) + buttonInstall.SetShieldIcon(true); + } + + private void buttonInstall_Click(object sender, EventArgs e) + { + // We need to close our handle to the PH mutex in order to + // let the installer continue. + if (Program.GlobalMutex != null) + { + Program.GlobalMutex.Dispose(); + Program.GlobalMutex = null; + } + + bool success = false; + + // Force elevation if required to prevent an exception if the user + // clicks no. Otherwise, start it normally. + if (OSVersion.HasUac && Program.ElevationType == TokenElevationType.Limited) + { + Program.StartProgramAdmin( + _fileName, + "", + new MethodInvoker(() => success = true), + ShowWindowType.Normal, + this.Handle + ); + } + else + { + try + { + System.Diagnostics.Process.Start(_fileName); + success = true; + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to start the installer", ex); + } + } + + if (success) + { + Program.HackerWindow.Exit(); + } + else + { + // User canceled. Re-open the mutex. + try + { + Program.GlobalMutex = new ProcessHacker.Native.Threading.Mutant(Program.GlobalMutexName); + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + } + + private void buttonStop_Click(object sender, EventArgs e) + { + if (_webClient.IsBusy) + _webClient.CancelAsync(); + + this.Close(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/UpdaterDownloadWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/UpdaterDownloadWindow.resx new file mode 100644 index 000000000..21f86819c --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/UpdaterDownloadWindow.resx @@ -0,0 +1,1783 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + iVBORw0KGgoAAAANSUhEUgAAAHgAAAAeCAMAAADQFyqnAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 + YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAwBQTFRF////AAAA + I6vgIajdXMLqAQEBAH2sMDExA4CvBYOzQ0REFhYWBwcHDg4OgIGBISEhAwMDx+j2B4a2Do/BEZLEH6TZ + E5XIgICACom6DIy9ysrKwMDAUbTbFZjLwcHBHKHWGp7SwsLCiszlGJvPgczq8PDw7/f6kJCQUFBQhsbf + g8LazMzMw8PDZGVl8Pj7icrjxOXyxebzisvlmJiYweDsxcXF0dHR0NDQi4uLyMjIiMjhhMTcICAgwuPv + 1O33WVlZi83nxOTxLarb6urqoKCgwuLu9fX1jdDqRUVFw+PwEBAQQUFBjM7oULLYhcXe8Pn8U7bdTq/V + tt/vvLy8SkpKi4yMgYGBV7vjy8vLiYmJ0urzoaKitbW1X7rdZ2dnII22MDAwKqfYQkJCfMbk4ODgFIq3 + RkZG3+DgTK3Tqqurhsfgv8DAh4eHSbXgcnNzfsjmExMT4eHhg4ODweHtHBwcKysrHR0dcXFxuePzWbLU + lJWVlpaW2NnZO7Dekcfc8fHxLJ3Iz+bv0OfwxMTEacfsKJfCUqjIWb7mSqvRjtDqF426tt/wXbbZuLm5 + 0+v1mpqaGZC+Ly8vMjIyjIyMQ6HFH5nIls7kU6nKVazNHZbEsdjn4fH34vL4Ozs7T1BQM6XSMpe+QEBA + tra2VbnghoaGYGBg6Ojora2tJSUlt+HxPj4+JpW/XrjbwuLvJqHSsNjnNjY2gsHZ5PX8xuf0hISE09PT + kZGRUrTb5eXlkpKSYmJic8bnlc7j29vbioqKQavUSqvQf73VSKjNtNzsl9DmTrDW8Pj8sLCwgMro7/f7 + v9/qR7Pdq93xdsrst7e3NZzDTa3Tq6urY7/ij9LsfMXi1e74u+b2ndfvRKLGcbbQUafIEoi0AAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfhtDEwAAAyhJREFUSEvtkOdX + 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 + AAAAAAAACPiIiIeIAAAAB3B3AIiId3eIgAAAiIh4dwB3eIiIgAAAeHiIeHiId3AHgAAAiIeHh3cAAgMA + gAAAiIeAAAAAJyRygAAAiIiAAicnInIniAAAiHiGNgAApycneAAAh4iAIyKjZyeneAAAh4iHICJCdzZ3 + eAAAcoiFAGMhd3o2OAAAh4+DAiJ2JjZ3eAAAAIj2cHIHd3d3eAAAAACHAAUneIiI+AAAAAAId3eIiI+P + gAAAAAAIjwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD////////////4 + ////wD///4Af//+AD//kwAf/wDAH/8AAB//AAAf/wAAH/8AAA//AAAP/wAAD/8AAA//AAAP/wAAD//AA + A//8AAP//gAH//4///////////////////8oAAAAEAAAACAAAAABAAQAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAgAAAgAAAAICAAIAAAACAAIAAgIAAAICAgADAwMAAAAD/AAD/AAAA//8A/wAAAP8A + /wD//wAA////AAAAAAAAAAAAd3AAiIeHgACHgAD4iIcAAIiAAACHcAAAiIiIiIiIeHiIiIiIiIiIiIiI + gAAAAAD3iIiAAAcncIiKeIBwAioniIF4iiAadaqIiI9wImd3dYgACIBKN3d3iAAIgDBHJWOIAAiHiHiI + iIgACI+IiIiIiAAAAAAAAAAA/////xwH//8cD///Hx///wAA//8AAP//AAD//wAA//8AAP//AAD//wAA + ///gAP//4AD//+AA///gAP///////ygAAAAwAAAAYAAAAAEACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAABwoHAAwMDAANFA0ACxkLABISEgAUGhQAGhoaACcAAgAKPQkAFSMVABYoFgAbJBsAHCocABI6 + EQAeMx4AIyQjACIpIgAsLCwAIjQiACM7IwAsMywAKzsrADQ0NAA0PjQAOzw7ABZLFQAGVBsAFlMVAA54 + DAATZBIAFWsTABNzEQAVeBMAGnoXABx0GgAgeB8AJUIlAChKJwArRSsAK0srACVVJQAtUi0ANEM0ADJL + MgA7QzsAPko+ADFTMQAzXDMAO1M7ADtcOwAmdiUANmM2ADpkOgA6azoANXY0AD1wPQA5ezgAQ0NDAEVL + RQBNTU0AVEtDAEFVQQBFWUUATldOAExeTABSUlIAU19TAFxcXABjRFUAQmJCAENtQwBNbU0AR3NHAFNs + UwBfYl8AW21bAFR0VABUeFQAXHRcAFp5WgBiYmIAamRkAGZsZgBmZ2gAampqAHxtbABjdmMAY3pjAGl1 + aQBre2sAcnJyAH1ydABzfHMAeHh3AHt7ewCDe3oADosLAA+dCwAUghIAGYYXAB6MHAAVnhMAEaoOABSi + EAAVqxIAHKQZABWwEQAesBwAHL8ZACKsHwAisx8AILweACSHIgAniCUAKI8mAC2ELAAlkiMAI5ohACuS + KQAsnyoAMpwvADaCNgAzjDEAOYo4ADOQMgA2mzQAPZQ8ADyaOgAmpiMAKKElACSrIgAprCYAK6IpACys + KQAlsiIAKLAlAC6xKwAsvSkAMLItADOjMQA9ojsAOb02AEGcPgBBrD8AHsAbACHAHgAkwiEAKcMmADTB + MQA+lGcARYJEAEmKRwBKhkgASYtIAEObQQBKlEgAWIpXAEajRABDs0AAUbJPAGiBZwBnkWYAc4JzAH6B + fgA0zX4AAP9rAISAfgB/f4EAf4GBAHS3mwBh25wAg4KCAIWFiQCIh4oAi4uLAJCLiwCNmYwAkJGPAIyN + kgCSj5UAi5GUAICdkACNlpsAk5OTAJmVlACTl5oAmJabAJScnwCbmpsAoZ2dAJWpnQCdnaIAqZygAJuk + pwCdpqoAkbunAKOjowCppaQAqamnAKSmqgCkqKwArKusALCsrACysK4Ap66xAKutsACxr7AAvK60AKyy + tQCvubwAs7OzALu1tgC0ursAu7q7AMOqsgDKp7oAw6y4AMG8vgC+wL4AvL7AAMO9wQC8wsQAucfJALzM + zwDDw8QAy8TFAM/IxwDEx8kAzMTIAMPIygDLy8sA0MnJAMbN0QDPz9AAxdHUAM3S0wDM1tgAy9nbANLT + 0wDU19gA09rbANvb2wDW3uAA3N/hANfg4gDb4OIA3+bpAOPj5ADi5+kA5+npAOnq6wDv8vMA8/T0APf3 + +AD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + 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 + PABHJi0AD0EOABpDGQAfWx4AIkYZACBXHwANZAoAEXUPABVlEwAVbRMAGW4WABNzEQAWfRQAG3cZACdF + JwAuRy4ALEosADNDMwA3TzcAOkU6ADpLOQA0VDQAM1wzADtWOwA6XDoAAHs5ACpuKQAwci8ANmQ2AD9h + NwA5YjkAO2w7AD1wPQA/fD4AQkJCAEdORwBLS0sAQlRBAFRXSgBVVFQAX19fAEBtQABAcEAASHhHAElz + SQBLeEsAVGVUAFxhXABUdFQAWXZRAFV4VQBZcVkAXHpcAHpfZwBlZWUAampqAGFzYQBiemIAaHZoAGJ4 + aQBtf20Ac3NzAHp0dwByfXIAe3t8ABKIDwAVhBIAGY4XAB6AHAAajBgAEpEQABycGgAiih8AEawNABWh + EwAUrBEAH6UcAB6pHAAZsBYAH7UcACG6HgAhhyAAKIYmACKLIAAlkCMAKJQmACSbIgApmCcAK5wpADGb + LwA5ijcAM5MxACenIwAupCsAMKgtACK0IAApsCYAI7ogAC6+KwAzqDEAQKs9AB/EGwAhwx8AJMogAC3G + KgAuyCsAMsEvAEuFSgBPiU4ARZtDAFWGVABMp0oARbxDAGiDaABziG8AcYVxAHmCdAB5gXkAfoh+AIJ5 + gAB/jI4Af5SKABXyhQBLxo4AgoKDAIqFhQCAjoAAiYmJAI2NjQCVg4oAjZaNAIqPlACRjpIAnI+XAIid + kwCIkZgAlJSUAJiXlwCRm5UAlpmaAJqZmgCdmpoAnZ2bAJ2bnQCdnJwAoJuaAIycowCVnaEAnJ6gAJil + pgCcrKIAlrSuAJmutQCko6MAqKanAKinrACkqqsArKysALCvrwCusK4AtbCvALGvsACqsbQArb2+ALGx + sQC2srIAsra2ALW1tQC7t7QAtrq3ALq1uQCxurwAubm5AL29vQDMtL4Awbu7AN+oxACux8wAssTHAL3C + wwC4xsoAvcnKALbM0gC8ztQAw8LCAMPDxADAxcYAxcXFAMrExQDExskAxMrLAMnJyQDJzc4Azs7OANHN + zADN0M4Aws7QAM3P0ADYxNAAw9HVAMrQ0gDL1NgAxdreAMjc3wDR0dEA0tTSANLS1ADR1dQA1dXVANzT + 0wDQ19kA3tbYANXa2gDZ2dkA2d3dAN3d3QDT3uEAzuDiAMzn7ADI6e0A0eHiANnj5QDa7O0A3u3uANTu + 9ADd+vwA4ODhAObm5gDg6OoA6urqAO3q6QD19fUA9fb5AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADi + 4uLVwwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADV6+v56+vr1cMAAAAAAAAAAAAAAAAAAAAAAAAAAAC9 + 6+vr+evi4vvV1eLDAAAAAAAAAAAAAAAAAAAAAAAAw+LR1eL5+eLV69HRvdG9AAAAAAAAAAAAAAAAAAAA + AADDvdHR4uvr4tXV0cOmltEAAAAAAAAAAAAAAAAAAAAAANXV0cPV4uLb0cOvkpKmpgAAAAAAAABWk54A + AAAAAAAAAL3i1b29s6aSTT1Mnr2zt9EAAAAApqa966Y6TLCmAAAAAACer59UU1OSqrjK3fP54rMAAACe + vpa34tGmkp6zngAAAACzmZ2ors3q1b2WTcPJwwAAAJ/Dr7Ozs9XrpkySU6nIzMfIvKaUUDsRBgYDmOG9 + AAAAptKvs6+emo6tzfb32q+KRCoRAwUCBgYNJSs3768AAACm2K+3sZ6xq6yKPBQHAgABAAIfZys0bjQr + EofvsAAAAKbnsLOzpt0QBgEAAAADDyQ0NWxlKhRsZxUTUO6wAAAApumws7ev4RoCC1pjNSwmEAkGImw0 + OHJ3Om6B7rAAAACm6a+zva/aNDIrXWEEAgMGBgVbcHE6dnFvczbruAAAAKbYpr3Dvd5HFw1hWAgDBSFc + H2JBfD93N3REReK5AAAApsSXvNXD1IghZF4eHAcZXTF7ZkF5gnhOTE1F2c0AAACbsaDF1c7RrwonLTB1 + LGlaDSB3U4R6gFBTU03RzdEAAJyQkcbr0dPJNDQqCWEGXBgHDINWU39+SkZCNcPdswAAjy9R3OrV29oM + OAcDVxhhEScrRkI2c31GUFVTs96mAACNFkvR6tHe1BQpESRqbXc0NC1SVZKShpKSkpKq6KEAAMJUs/7/ + +eLdPzQkEBlbIwwRPZqSkpKFSkhCNqbrqgAAAADJveL//+89AQYGB2EMERRJSkI2QUZPioyYn/myAAAA + AAAAAL2/2k0DCxImazU0NE+IjJaWlpaUk5JW+78AAAAAAAAAAADbnjQ0JhIREQ4TkpOTlZ6mr7C90eL9 + 0wAAAAAAAAAAAAC9AAYMEzg+U5q9w8PR09ne6O/z+vkAAAAAAAAAAAAAAMOTp73DyuHx8e/z8wAAAAAA + AAAAAAAAAAAAAAAAAAAA4vX1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////4P///4A///4 + AD//8AAf//AAH//wAB/H+AAHgD4AA4APAAOAAAADgAAAA4AAAAOAAAADgAAAA4AAAAOAAAADgAAAA4AA + AAGAAAABgAAAAYAAAAGAAAAB4AAAAfwAAAH/AAAB/4AAA/+AB///j/////////////8oAAAAGAAAADAA + AAABAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUFBQAJCQkAAhcCAAIfAQAGGgYAERERABEV + EQAQGBAAERwRABYfFgAYGBgAHh4eAAIgAgALIwsADy8OAA8wDgAQNA8AFSEUABcnFwAZJBkAGioaABQx + FAAeNR4AICAgACQkJAAqKioALi4uADAtLQAiPyIALT0tADMzMwBBPT0AC18JABNrEgAXcxYAFHoRAB59 + GwAuTS4AKlAqADdONwAyWzIANVk1ADlYOQA+Xz4AEWU0ADJlMQA0YDQAN243ADhnOAA9YT0AOmo6AD1o + PQA8bTwAPHA8AEFBQQBKR0cATEhHAEtISABOTk4AUlJSAFVeVQBAcUAARndFAEhxSABeY14AUXRRAFJ5 + UgB5V2MAY2NjAGZmZgBlaGUAam1sAG5ubgBiemIAZXplAG94bwBxcXEAdXV1AHR+dAB6enoAfnt8AH9/ + fwAPgAwADYoKABCNDQAQng4AF4MUABSIEgAciRoAIJodABCgDQAcrhkAIYQgACaDJAAonCYALJ0qADiR + NQA8kjoAKaInACS1IAA0oTIAPag7AB/CGwApwyYAKscmAEyKSwBMn0kAQqFAAEeiRABNoUsAfYB9AICp + fAB/g4UAP8uFAIKCggCEhIQAgYmNAIyLigCOjo4AkI6OAIGWjACTkI8AiY+QAIiQkgCNlZcAkZGRAJWU + lACYl5cAl5ydAJmZmQCdnZ0Al5+gAJqgogCYr6UAoqKiAKSjowCmpaYAqKenAKeppwCuq6cAqKaoAK2l + qQCqqqkAq66vAK2trQCxp6kAtaSqALCpqwC0qq8AsK6vAKazsgCvs7MAq7S3ALKysgC2sbMAsbS2ALa1 + tQCztrgAt7i5ALC7vAC3uLwAs7y+ALq5ugC9vr4Awb69AMi7vgDFwL4AtL7BALnCwwC+xsYAvcfJALrI + yQDCwsIAxMPCAMPExQDFxcUAzMXGAMDIygDFyckAxszMAMnJyQDOyMkAys3NAM3NzQDZzdMAy9HTANHR + 0QDQ09QA1tLVANDU1QDV1dUA2dXXANPX2gDX2twA2dnZAN7a2ADe3t4A2N/hAN3i5ADe5OYA2ObpAOHh + 4QDh5ucA4O/vAPn8/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAv7MAAAAAAAAAAAAAAAAAAAAAAADAtcXK + xcW1tQAAAAAAAAAAAAAAAAAAALWztcXFu8C7raQAAAAAAAAAAAAAAAAAALuzrcDDu62PeI+IAAAAAAAA + AFGAAFGCAACknZ2Lf1FIe6CYjwAAAAAAioytrX5/f38AAIV+dYSkta3FswAAAAAAj52InZ6LcX6EnYuL + fnFGNwwfrAAAAAAAlqeNgoKXi39NOxsSDhAQFhIfoAAAAAAAnbGNj5QZCQMNDQUCFF4oKzA1kAAAAAAA + nbGPj5QHCSMdJy82X2crMmRjiLMAAAAAlqaNpKE1L1wXFQoHXGJiP2VAcKoAAAAAlpOKtaoaJSQhU1Yi + X0ZoamxGeKwAAAAAhnKWuawgJxBUVRJZQU1sbm5IdqgAAAAAeS2NwLI4GQJbWBkaTkxLaUNAPpgAAAAA + jUS5zbs4BxRZWio0NkBCZktMcZ0AAAAAAACtwMc4MSonXh49e3FxdHR/gq0AAAAAAAAAALV/AAcLFBpN + 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 + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACxsbEFu7u7HLOzs1WlpaWAsbGx + j7Kyspa0tLSZq6url42NjZKCgoKCeXl5XHJyciOBgYEHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjY2NGqioqHW8vLzRzc3N + /9XV1f/f39//5eXl/+Xl5f/h4eH/3Nzc/93d3f/e3t7/09PT/8DAwP+hoaHgjIyMh5aWliIAAAAAAAAA + AAAAAAAAAAAAAAAAAgAAAAIAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACPj49nt7e3 + 6tTU1P/X19f/29vb/9zc3P/b29v/2tra/9bW1v/R0dH/ycnJ/8zMzP/f39//2dnZ/8LCwv+/v7//ycnJ + /62trfljY2OGNTU1DwAAAAAAAAAWAAAAGQAAABcAAAANAAAABAAAAAIAAAABAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AKKioqbKysr/0NDQ/8vLy//Ly8v/0NDQ/9fX1//a2tr/29vb/9ra2v/U1NT/y8vL/9LS0v/k5OT/zc3N + /7Kysv/ExMT/yMjI/7m5uf/ExMT/fn5+yA0NDT0AAAAxAAAAPQAAADIAAAAiAAAAEwAAAAgAAAAEAAAA + AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAnZ2dhcXFxf/ExMT/wcHB/8fHx//MzMz/0NDQ/9fX1//c3Nz/3d3d/9zc3P/U1NT/yMjI + /9PT0//e3t7/wcHB/8LCwv/Kysr/tbW1/6ysrP+srKz/wsLC/25ubsgAAABIAAAASwAAAEAAAAAyAAAA + JAAAABUAAAALAAAABQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAtra27r29vf+9vb3/wcHB/8TExP/IyMj/zs7O/9XV1f/c3Nz/3d3d + /9ra2v/S0tL/x8fH/83Nzf/Nzc3/wcHB/8LCwv+0tLT/r6+v/6ioqP+ZmZn/pqam/5eXl+wNDQ1eAAAA + QQAAAEQAAAA2AAAAJwAAABwAAAASAAAACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAtra27Le3t/+6urr/vb29/8DAwP/ExMT/ycnJ + /8/Pz//W1tb/19fX/9XV1f/Nzc3/xMTE/8XFxf/AwMD/vb29/7a2tv+urq7/oqKi/5SUlP+QkJD/paWl + /52dne8XFxdYAAAAMgAAADsAAAAxAAAAJgAAABwAAAASAAAACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsrKyrbu7u/+5ubn/ubm5 + /76+vv/AwMD/xMTE/8fHx//MzMz/zs7O/8zMzP/Hx8f/w8PD/8DAwP+6urr/sLCw/6Ojo/+UlJT/jo6O + /5GRkf+Xl5f/r6+v/3R0dMMAAAAiAAAAIg0NDTAAAAApAAAAIQAAABgAAAAPAAAACAAAAAAAAAAAKiop + KW9tb+KTkJH/WFlZxQ0ODkoAAAAaAAAAJQAAACcAAAA4AgIBOgAAAAgAAAAAAAAAAAAAAAAAAAAAuLi4 + GJ6entbKysr/xMTE/7i4uP+6urr/vr6+/8DAwP/BwcH/wcHB/8DAwP+4uLj/r6+v/6Ojo/+YmJj/g4OD + /21tbf9paWn/f4GB/5OSkv+jo6P/qqys/FxcXJJOTk94amprloODhIAvLy8pAAAAFgAAABEAAAAJAAAA + BAAAAABlZGUzX19e67KwsP+empn/4+Hh/9jY2f9GRkbTBQUFmg4ODrtjY2P/paWj/0tMSr0KCwhVAAAA + EQAAAAAAAAAAAAAAAFpaWg9QUFCApqam8sfHx/+5ubn/ra2t/6Wlpf+kpKT/pKSk/5eXl/+JiYn/fX17 + /3Fxcf9lZWX/XV5e/2lpav+CgoP/mpqb/62rrv+2trX/ube3+Li2tu7Z2dr/29vb/5+fn/h/f34sAAAA + AwAAAAUAAAADAAAAAQAAAACZmJuKsKys/6ikpP+WkZH/q6qr/8/P0P/CwsL/mJiY/4uLi/9eXl7ibW1t + s9HR0fnFxMH/VVVUyRISEF8AAAATAAAAAAAAAAAAAAAAQ0NDLk5OTZmNjY7moaGh/6ampf+fn57/hYWF + /3h4d/96enn/ent8/39/gf+IiYr/nZ2f/6urrf+vrq7/sa+w/7a3t/+ztLT/ucPF/8bT1P/Cw8X+wL6+ + /qenp/9wcHBJAAAAAAAAAAAAAAAAAAAAAAAAAACQj5GDqqen/6+qqv+fnJz/srCy/8jIzP+rrKz/rays + /7i4uP+EhITxLi4utRkZGY9xcnO30tLS9Le3t/9WVlO+GBgYawAAACcAAAAGAAAAAAAAAAAfICAIOTk6 + NHl5e4+UlZX6hYWJ/4uKjf+OjpL/kZCV/5eXmv+hoaT/qqqs/6itsP+vubz/ucfJ/8zV1//W29z/19fX + /9XT0//Jycn+wcXF/KqoqP+GhoZtAAAAAAAAAAAAAAAAAAAAAAAAAACRkJKDrqqr/7Wwsf+npaX/trS2 + /8C/wP+4uLj/urq6/6+vr//Nzc3/6enp/6ioqPo5ODizHBweloODhNr19vX/o6Ki/xkXF4UXFxgmSEhK + QHNzd3SDgYaliIiMzIqJjeyKio7/jIyS/4uPlP+LkZb/jZab/52mqv+2vL7/y87P/9HR0f/Hx8f/rKys + /4CAgP9SUlL/LS0t/yIiIv+wsLD/y9ja/Kelpf+fn5+NAAAAAAAAAAAAAAAAAAAAAAAAAACSkJODtrGy + /724uf+wqq3/vry9/7u7u/+Ojo7/mpqa/7W1tf+1tbX/wMDA/+vr6//19fX/kJCQ9lVVVu1gYWL0cXBz + 1YmHi9ifn6T1n5+m/5qdof+Sl5v/kJec/5Ocn/+bpKf/qK2v/66urv+xsbH/tLS0/5ubm/98fHz/W1tb + /y0tLf8WFhb/EhIS/xAQEP8PDw//Dw8P/xAQEP+kpKT/0Nvc/qqpqf+ZmZmxAAAAAAAAAAAAAAAAAAAA + AAAAAACRkpODvre3/8G6vf+uqqz/vLq7/7y8v/+fn5//mJiY/5CQkP+YmJn/lJOV/5GRk/+Ympr/mJab + /5ybof+kpqr/pKmt/6eusf+rsbT/rrS2/7W5u/+0tLX/ra2t/6SkpP+NjY3/aWlp/0NDQ/8hISH/Dg4O + /w4ODv8ODg7/Dw8P/xQUFP8YGRj/ICog/yg9KP8uSy7/M1oz/zlpOf+VlZX/09zd/rGurv+am5vMAAAA + AAAAAAAAAAAAAAAAAAAAAACTkZSFxL6//8a+wf+wrKv/vbq7/7u7vP+dnZ3/nZ2d/52dn/+OjpL/ko+V + /4uRkv+AnZD/lp2f/6isrv+7vr//x8fH/8HBwf+bm5v/fX19/2FhYf8/Pz//Hx8f/wsLC/8GBgb/BgYG + /wcHB/8JCQn/Fx0X/yY2Jv8sRyz/MlUy/zZlNv88bzz/N2A3/zJSMv8uRS7/Kzgr/x8uH/+DhYP/09rc + /7W1tP+amZndAAAAAAAAAAAAAAAAAAAAAAAAAACRkpWGysPD/8rExP+xrKz/vbq7/7u7vP+dnZ3/n5+f + /7Kys/+Wl5r/mZmZ/7S0tP+3t7f/m5ub/3R0dP9SUlL/Nzc3/xsbG/8MDAz/BAQE/wAAAP8BAQH/BwoH + /xMfE/8eMx7/KEon/zFeMf86bDr/OGU4/zVZNf8wSzD/LT8t/yozKv8oKCj/Kioq/ysrK/8sLCz/LS0t + /yQkJP9veG//1Nna/7m7u/+amZnqAAAAAAAAAAAAAAAAAAAAAAAAAACSkZWGzMfH/8zGxv+zrq7/u7u9 + /7y8vf+goKH/oaGh/7Ozs/+kqKv/mJiY/y8vL/8YGBj/Dw8P/wUFBf8CAgL/AQEB/wsVC/8WKBb/ITwh + /yxQLP81ZjX/OWo5/zBYMP8oRyj/IDUg/xkkGf8TFRP/ISEh/ysrK/8sLCz/Li4u/y8vL/8xMjH/ND40 + /zZLNv85Vjn/OmE6/ztqO/9ea17/0dPU/8TIyP+bmprwAAAAAAAAAAAAAAAAAAAAAAAAAACTkJSG0MnI + /8/Jyv+zsLH/u7m7/7+/v/+mpqT/paWl/6+vr/+yuLv/lJKS/xEWEf8SIBL/HzYf/yhJKP8yXDL/PHA8 + /zJdMv8oSij/Hjce/xcmF/8PFQ//CgoK/wwMDP8ODg7/EBAQ/xAQEP8UFBT/LTQt/zZGNv8ojyb/Ol06 + /ztnO/88bzz/PGU8/zxcPP89Uz3/Pkw+/zg9OP9TX1P/zMzM/8zT0/+cnJz0l5iYEwAAAAAAAAAAAAAA + AAAAAACTkJOG0MnK/87Iyf+zr7D/u7m6/7+/wf+pqaf/qamp/6ysrP+6vL3/o6Oj/zlqOf8wVjD/KkYq + /yA0IP8WIRb/CwsL/woKCv8HBwf/BwcH/wgICP8KCgr/DxIP/xklGf8iOCL/K0or/zNcM/86bDr/O2g7 + /yihJf8jrx//PlA+/z9IP/8thSz/K5Mo/0NDQ/9ERET/R0dH/0JCQv9OV07/y8vL/9DZ2/+fnp3+mpqa + PwAAAAAAAAAAAAAAAAAAAACTk5WGz8jH/8zFxv+ysa7/u7q7/8LCw/+sqqv/qqqq/7CwsP/AwcH/s7W3 + /yc8J/8PDw//GRkZ/xQUFP8TExP/EBAQ/xVrE/8cLhz/Iz8j/y1SLf82ZDb/OWo5/zJZMv8qSSr/Izgj + /xwnHP8fIh//PT09/yamI/8isx//Q09D/0dHR/8zizH/JrAj/0NgQ/9FWUX/RGFE/0BmQP87cjv/ysrK + /9Xd3/+koqL/mZmZaAAAAAAAAAAAAAAAAAAAAACTkpaGzMTI/8a+wP+lo6D/uba3/8bEx/+xr7D/srOy + /7m5uf/Dw8P/ur7A/zpVOv8bKRv/LEMs/y9PL/81XjX/JrEj/yKpH/8qTCr/ITkh/xkpGf8TGhP/EBAQ + /xEREf8TExP/FRUV/xYWFv8mJib/R0hH/yHAHv8snyr/OX84/0JlQv8soCr/LJ8q/yyiKv8osCX/R2RH + /yytKf85eDj/vb29/9be4P+mpaX/mZmZiwAAAAAAAAAAAAAAAAAAAACUkpSGxsDA/767u/+jn5//trS1 + /8nLyf+5u7n/ubm5/7y8vP/Gxsf/vMLE/zl8OP8wVjD/Mk8y/yo9Kv8hQSH/FZ4T/xGqDv8ICAj/CwsL + /w0NDf8QEBD/ERER/xUYFf8eKh7/Jjsm/y5NLv85Yjn/NoI2/yW1Iv8zkDL/Mpwv/0xeTP82mzT/RYFD + /y+wLP89lDz/PZg6/z2aO/9QUFD/rq6u/9fg4v+pqqr/lpaWswAAAAAAAAAAAAAAAAAAAACSk5WGvLi6 + /7uytP+hmZr/tLK0/8zNz/++wL7/vb29/7+/v//Gxsb/u8PF/1x0W/8PDw//LCws/yUlJf8cdxr/HXEb + /w6LC/8SOhH/HjAe/ydDJ/8vVC//N2U3/zprOv8zWzP/Lkwu/ydFJ/86RTr/RIVD/zuZOf9RbFH/MLIt + /11dXf88nTr/SoZI/2BgYP9fYl//KcMm/0ObQf9XV1f/nJyc/9rg4v+1tbX/l5eXyQAAAAAAAAAAAAAA + AAAAAACTkpWGvK60/8Oqsv+pnKD/s7G2/83Pz//DxML/wsLC/8TExP/Gxsb/v8bH/3CFcP8UGRT/M0ky + /zNKM/8cvxn/NmQ2/yqkKP8mkiX/LE0s/yU+Jf8eLh7/GR8Z/xNkEv8UghL/FKAR/xSnEf8skSr/QZw+ + /0mKR/9gYGD/Lbwq/15sXf89ojv/SYtI/1ZqVv9Ra1H/M6Mx/0VvRf8+bz7/kJCQ/9ve3/++wMD/lpaW + 1QAAAAAAAAAAAAAAAAAAAACcjJaGlamd/2HbnP+Ru6f/w6y4/9DR0f/Hx8f/xsbG/8fHx//Jycn/wsfK + /4uciv8krCH/HsAb/yWZI/8llCP/Hike/wo9Cf8OeAz/EBAQ/xISEv8TExP/FFQT/xRxEv8ZSBf/Gy0b + /yElIf8pqyf/MbMu/0aBRv9MbEz/LKwp/zSNMv8prSb/OYw4/05uTv9UblT/Wm5a/2VvZf9jZmP/iIiI + /9ve3v/Dxsf/lpWV5AAAAAAAAAAAAAAAAAAAAACfi5p9NM1+/wD/a/90t5v/yqe6/9PT0//Ly8v/ycnJ + /8vLy//Ly8v/ys3P/62trf8XJhf/NDQ0/yeIJf82Njb/DQ0N/wsZC/8PnQv/ExcT/xsmG/8kOCT/Howc + /yZ9JP82Xzb/O2w7/zprOv9Ca0L/LrIr/1RtVP9ZbVn/SpRI/0ajRP9BrD//WoxY/29vb/9wcHD/cXFx + /3Nzc/9ra2v/fX19/9zd3f/Iy83/lZWV8JubmyAAAAAAAAAAAAAAAACamp9uPpRn/wZUG/99cnT/w7rD + /9XY2f/Pz8//zMzM/83Nzf/Ozs7/0NPU/7u5uv8kKCT/NkA2/0FVQf80TjT/KUop/zNcM/8gux7/NXc0 + /zReNP8uTS7/HKUY/yVWJf8mMSb/JSgl/zMzM/9oaGj/dXV1/3Jycv9ycnL/aIFn/zm9Nv9DsUH/Wo5Z + /2h0aP9ec17/V3JX/1FyUf9HcEf/P3A//9vb2//N0dP/lpaW/Jubm0oAAAAAAAAAAAAAAACZl5xuY0RV + /ycAAv98bWz/vcDB/9XW1//Q0ND/z8/P/9HR0f/S0tL/1tfY/7u7u/87azv/O2U7/0FhQf8qRCr/HTEd + /xkjGf8TdRD/FFAT/xsbG/8eHx7/FbAR/yQkJP8nJyf/KSkp/0JCQv9rc2v/aHdo/190X/9Uc1T/TnJO + /yTCIf8lsiL/OYk5/0lySf9Uc1T/XHRc/2R2ZP9sdmz/Z2ln/9jY2P/T19n/mJeX/5qamnEAAAAAAAAA + AAAAAACenaF5aGRl/1RLQ/+HgH//ra6x/+Hh4v/Pz8//yMjI/87Ozv/S0tL/29vb/7y/wP8vLy//Ojo6 + /0FBQf8ODg7/EBAQ/xMTE/8UTxP/FXgT/yItIv8lVCX/HKQa/zJSMv83XTf/OWY5/zxwPP9Gckb/TXNN + /1V0Vf9gdmD/Z3dn/0KxQP9Et0H/Z5Fm/3p7ev9ueW7/Y3dj/1h2WP9Nc03/QG9A/8vLy//c4OL/mpub + /5mZmYsAAAAAAAAAAAAAAACloqU6kJGP/5KUkf+emZz/2tja///////4+Pj/5eXl/9nZ2f/T09P/09PT + /8HHx/8+QT7/OkQ6/zRHNP8kPST/K0or/zNcM/81dTX/Ib0e/zZfNv8esBz/JJAh/y5DLv8uOy7/LjYu + /11dXf+BgYH/fn5+/319ff91e3X/aXlp/1aEVf8rvyj/QX9B/z1wPf9Jc0n/VnVW/2J5Yv9wfXD/am5q + /7y8vP/i5+n/oKCg/5mZmZ4AAAAAAAAAAAAAAAAAAAAAtLSzQczOz5aztrfx1dXW/9zf3//09PT///// + ///////7+vr/6urq/8bN0f8+bz7/OGE4/zBQMP8lQCX/Izgj/x0oHf8bIBv/FKAQ/xpWGf8aehf/JCQk + /ycnJ/8sLyz/NkI2/1lvWf9ZeFn/SnNK/z9xP/9FckX/UXVR/114Xf80wTH/dn52/4GBgf+BgYH/gYGB + /4KCgv+FhYX/c3Nz/7Ozs//o7e//qqqq/5aWlq8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACvtLQqsbOz + QK+wsIm6vLz/yMrK/9rb2//z9PT//////9Xe3/91dXX/CAgI/w0NDf8QEBD/ExMT/xYWFv8ZGRn/GYYX + /yB4H/8khyL/NVo1/zpoOv87bDv/PWU9/1Z1Vv9ofWj/cn1y/3+Bf/+CgoL/goKC/4KCgv9Rsk//g4OD + /4SEhP9rfWv/XXpd/1F2Uf9IdEj/PnA+/zxwPP/v8vP/ubm5/5OTk8YAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAACvsrIdsbOzPa+zspi5u7v/xsfH/87V1/+GhIT/CQ4J/xooGv8kOyT/LU0t + /zReNP88cDz/LYQs/yKbIP8ncCb/LDss/ysxK/8sLCz/UFBQ/4SEhP+Ghob/hISE/3eAd/9me2b/VndW + /0l0Sf9CckL/PnA+/zxwPP8/cT//RHNE/0x1TP9Yelj/aHto/4+Wj//z9PX/xMXF/5KSktqbm5sPAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACztrYMrLCwI7zCxduWlZT/N2Y3 + /zBVMP8oRSj/IjYi/x4pHv8ZGRn/HSMc/xWrEv8jKiP/JiYm/zFDMf81UzX/R2xH/0h0SP8/cT//PHA8 + /z1wPf9AcUD/SHRI/1R4VP9ifGL/c4Jz/4eHh/+FhYX/g4OD/4CAgP9+fn7/cnJy/3p6ev/z9PX/0tPT + /42NjfCZmZk0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AMfO0WOoqqn/DQ0N/w4ODv8RERH/HCcc/yc+J/8wUTD/N2I3/yWrI/88bjz/PHA8/zttO/87aTv/SHBI + /1t8W/9sfmz/fYF9/4CAgP98fHz/eHh4/3Z2dv9zc3P/cHBw/2pqav9mZmb/ZWVl/2hoaP9sbGz/bW1t + /4KCgv/39/j/39/g/5SUlP2srKwqAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAMjMzj2zubn/N2Q3/zpsOv88cDz/PG88/zprOv83Yjf/M1Qz/zBJMP8tOi3/Kioq + /ywsLP8uLi7/Wlpa/2hoaP9iYmL/YWFh/2BgYP9fX1//Y2Nj/3x8fP+FhIP/mpST/5qVk/+ppKP/srCv + /8TFxP/O0dL/2t/j/97m6fbl5eXj3t7ev7u7u2IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMLDxh68xcb/NFM0/x4xHv8UGBT/ExMT/xYWFv8WFhb/GBgY + /yIiIv8tLS3/RERE/1ZWVv9raWn/hYGA/52Zmf+lo6L/u7i4/7y7u//O0NL/0NPU/8/V1vjO09XxztPW + 387V18rT2dup09fYi9PV2F7LzM020NHRHNra2hbc3NwQ3t7eBwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMHCxBK3vsHtTk5O/yQkJP9NS0v/bGRj + /4N7ev+Qi4v/pKam/7S8vv/D0NP/ytfY/8vb3P/L2Nr4y9LU58vP0NnLzs/Jyc3Oq83P0JDNztB1zs7O + RcnLyijIyMgJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKinqxGysbPlwcjJ + /7zMz//E0tb/xdHU9sfP0ujJz9DUyMvLvsjJy6vHyMiSycrKcsnJyVjLy8w3ysrKGAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AJubnwSnp6lmxMLEkMC+v3m7u71av72/PcPDwyfIyMkMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAACrq60I0tHSD8PCwwO7u70BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAP///////wAA////////AAD///////8AAP///AAf/wAA///wAAePAAD//+AAAQEA + AP//wAAAAAAA//+AAAAAAAD//4AAAAAAAP//gAAAAAAA//+AAAAAAADAB4AAAAAAAIABwAAAAAAAgABw + AAAPAACAAAwAAA8AAIAAAAAADwAAgAAAAAAPAACAAAAAAA8AAIAAAAAADwAAgAAAAAAPAACAAAAAAA8A + AIAAAAAABwAAgAAAAAAHAACAAAAAAAcAAIAAAAAABwAAgAAAAAAHAACAAAAAAAcAAIAAAAAABwAAgAAA + AAAHAACAAAAAAAMAAIAAAAAAAwAAgAAAAAADAACAAAAAAAMAAIAAAAAAAwAAwAAAAAADAADwAAAAAAMA + AP4AAAAAAQAA/8AAAAABAAD/8AAAAAEAAP/wAAAAAwAA//AAAAAHAAD/8AAAH/8AAP/wAB///wAA//AP + ////AAD/+H////8AAP///////wAA////////AAD///////8AACgAAAAgAAAAQAAAAAEAIAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsLCwBLi4uEqqqqqGtra2lrm5uZWhoaGVgYGB + h3d3d052dnYGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ6enmTHx8fZ1dXV/93d3f/i4uL/2tra + /9bW1v/c3Nz/yMjI/6Kior2Xl5dfAAAAAAAAAAAAAAAAAAAAAgAAAAEAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJeXlwuvr6/n2dnZ/9nZ2f/c3Nz/4ODg + /9/f3//Q0ND/z8/P/+rq6v/Nzc3/zs7O/9DQ0P+goKCsHR0dNgAAAAkAAAApAAAAFgAAAAQAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAs7Oz59PT0//Hx8f/yMjI + /9TU1P/f39//4eHh/9LS0v/Pz8//2tra/729vf/Dw8P/tra2/8XFxf+wsLD/AAAAVAAAADoAAAAuAAAA + FwAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKqqqi69vb3/t7e3 + /76+vv/Gxsb/z8/P/9ra2v/b29v/z8/P/8fHx//Kysr/xsbG/7m5uf+enp7/jo6O/8nJyf8hISFxAAAA + IQAAADIAAAAfAAAAEgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AMXFxeHOzs7/v7+//7+/v//Jycn/0NDQ/9LS1P/Pz8//xsbG/76+vv+ioqL/hYWF/4SEhP+bm5v/lZWV + 7wAAABcMDAwYCAgJFQAAABMAAAAMAAAAADk7PBpVVVfIiYeH/1FQUJ4BAQE6AAAANhMTE3EUFBRkQ0NB + DQAAAAAAAAAAAAAAAImJiaPT09T/y8vL/7a2tf+wsLD/r6+t/5qZmf+DhIP/ampq/1NSUv9nZ2f/lZOT + /7S0tf+koaHepaKk28PDxP9fX11aAAAAAAAAAAUAAAAAfXx9yJ6bmf+3srH/4ODh/5ubm/9HR0f7aGho + /6WlpPiNjYvaHh4dc0xMTQ4AAAAAAAAAACEgHklycnC+m5ub7pyamf93d3X/c3Bz/3RxdP+AgYP/np+h + /6uytv+4xsr/xdTV/9jh4v/h4eH/09PU/15eXoAAAAAAAAAAAAAAAACNjI3pu7e0/46Njv+tra7/0tTS + /8TExP+QkJHsUlJSunl5esisrK35iIiK5isrK3kAAAAKAAAAADMxNR9jY2aEio+U/YiRmP+MnKP/ma61 + /7/P0//T3N3/y83N/7Ozs/+NjY3/aWlp/7y8vP+8x8f/k5ORmAAAAAAAAAAAAAAAAIeFhdnAurv/pKGk + /62srP+urq3/qqmp/8/Pz//X19f/jIuM3VNRUuGEg4T/amxu8Y2Wmu2xwsf/tc3U/67HzP+zxsf/sra2 + /52fnP+AjoD/ZHdk/0JUQf8lMSX/FRUV/xEREf8NGQ3/jZaN/8jc3/+YlJS1AAAAAAAAAAAAAAAAjIqL + 3MrExf+no6X/rK2u/6KkpP+SkZH/kY6S/3+Mjv+WtK7/uc7T/9Tu9P/d+vz/w8/Q/6KhoP94g3X/VWdU + /zxLO/8nLCf/EBAQ/xAQEP8QEBD/ERER/xQYFP8iMCL/Lkcu/zFVMf8/fz7/zuDi/5KPjswAAAAAAAAA + AAAAAACRjY7g0s3M/6aiof+urK//qamp/5eXl/+op6z/mKWm/5ysov97gXP/VFdK/zE6MP8gICD/Dw8P + /wUFBf8EBAT/BQUF/wkJCf8VbRP/IYcg/zVWNf85ZTn/LJsq/zheOP82UTb/LT0t/2iDaP/Q4eL/l5OS + 1gAAAAAAAAAAAAAAAJOPkuHa0tL/pqSl/6yur/+sqqz/nJyc/8LT1/8mPCT/ERER/woKCv8CAgL/AAAA + /wAAAP8MFAz/Gy8b/ydFJ/8zXDP/PG88/ySZI/8ftRz/OEs4/zc/N/8jnCD/KIYm/zw8PP82Njb/YHRg + /9Tf4P+dnp7mk5OTEgAAAAAAAAAAkZGS4d7W2P+opqf/rrCu/7Gwsf+goKD/x9rf/yJGGf8JDwn/Gywb + /x6AHP8eqRz/Oms6/zRfNP8qSir/Ijgi/xsmG/8TExP/Fn0U/yeeJP86YDr/Q0ND/yenI/8huB//R05H + /yqeKP9PiU7/2N7e/6Koqf+UkJAuAAAAAAAAAACTkJLh3tTV/6WjpP+wr6//tLS1/6ampv/D0NL/P2E3 + /zdlN/8yVTL/G5sZ/xWrEv8PHg//CwsL/w8PD/8SEhL/FRUV/xUVFf8ajBj/OYo3/zKUMP9OTk7/KbAm + /zSTMv8xmy//LaEq/0BvQP/Z29v/qbGy/5KRkUkAAAAAAAAAAJKOkOHRzc3/nZub/7Kxsf+/wMD/s7Oz + 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 + QeAArEH//6xB + + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/VirtualProtectWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/VirtualProtectWindow.Designer.cs new file mode 100644 index 000000000..066fc2e07 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/VirtualProtectWindow.Designer.cs @@ -0,0 +1,123 @@ +namespace ProcessHacker +{ + partial class VirtualProtectWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(VirtualProtectWindow)); + this.labelVirtualProtectInfo = new System.Windows.Forms.Label(); + this.buttonCloseVirtualProtect = new System.Windows.Forms.Button(); + this.buttonVirtualProtect = new System.Windows.Forms.Button(); + this.textNewProtection = new System.Windows.Forms.TextBox(); + this.labelNewValue = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // labelVirtualProtectInfo + // + this.labelVirtualProtectInfo.Location = new System.Drawing.Point(12, 9); + this.labelVirtualProtectInfo.Name = "labelVirtualProtectInfo"; + this.labelVirtualProtectInfo.Size = new System.Drawing.Size(399, 165); + this.labelVirtualProtectInfo.TabIndex = 1; + this.labelVirtualProtectInfo.Text = resources.GetString("labelVirtualProtectInfo.Text"); + // + // buttonCloseVirtualProtect + // + this.buttonCloseVirtualProtect.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonCloseVirtualProtect.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonCloseVirtualProtect.Location = new System.Drawing.Point(336, 184); + this.buttonCloseVirtualProtect.Name = "buttonCloseVirtualProtect"; + this.buttonCloseVirtualProtect.Size = new System.Drawing.Size(75, 23); + this.buttonCloseVirtualProtect.TabIndex = 9; + this.buttonCloseVirtualProtect.Text = "Close"; + this.buttonCloseVirtualProtect.UseVisualStyleBackColor = true; + this.buttonCloseVirtualProtect.Click += new System.EventHandler(this.buttonCloseVirtualProtect_Click); + // + // buttonVirtualProtect + // + this.buttonVirtualProtect.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonVirtualProtect.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonVirtualProtect.Location = new System.Drawing.Point(255, 184); + this.buttonVirtualProtect.Name = "buttonVirtualProtect"; + this.buttonVirtualProtect.Size = new System.Drawing.Size(75, 23); + this.buttonVirtualProtect.TabIndex = 8; + this.buttonVirtualProtect.Text = "&Change"; + this.buttonVirtualProtect.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText; + this.buttonVirtualProtect.UseVisualStyleBackColor = true; + this.buttonVirtualProtect.Click += new System.EventHandler(this.buttonVirtualProtect_Click); + // + // textNewProtection + // + this.textNewProtection.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.textNewProtection.Location = new System.Drawing.Point(167, 186); + this.textNewProtection.Name = "textNewProtection"; + this.textNewProtection.Size = new System.Drawing.Size(82, 20); + this.textNewProtection.TabIndex = 7; + this.textNewProtection.Leave += new System.EventHandler(this.textNewProtection_Leave); + this.textNewProtection.Enter += new System.EventHandler(this.textNewProtection_Enter); + // + // labelNewValue + // + this.labelNewValue.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.labelNewValue.AutoSize = true; + this.labelNewValue.Location = new System.Drawing.Point(100, 189); + this.labelNewValue.Name = "labelNewValue"; + this.labelNewValue.Size = new System.Drawing.Size(61, 13); + this.labelNewValue.TabIndex = 6; + this.labelNewValue.Text = "New value:"; + // + // VirtualProtectWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(423, 219); + this.Controls.Add(this.buttonCloseVirtualProtect); + this.Controls.Add(this.buttonVirtualProtect); + this.Controls.Add(this.textNewProtection); + this.Controls.Add(this.labelNewValue); + this.Controls.Add(this.labelVirtualProtectInfo); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "VirtualProtectWindow"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Change Memory Protection"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label labelVirtualProtectInfo; + private System.Windows.Forms.Button buttonCloseVirtualProtect; + private System.Windows.Forms.Button buttonVirtualProtect; + private System.Windows.Forms.TextBox textNewProtection; + private System.Windows.Forms.Label labelNewValue; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/VirtualProtectWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/VirtualProtectWindow.cs new file mode 100644 index 000000000..874b11675 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/VirtualProtectWindow.cs @@ -0,0 +1,101 @@ +/* + * Process Hacker - + * memory protection modifier tool + * + * Copyright (C) 2008 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 . + */ + +using System; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker +{ + public partial class VirtualProtectWindow : Form + { + private int _pid; + private long _size; + private IntPtr _address; + + public VirtualProtectWindow(int pid, IntPtr address, long size) + { + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + _pid = pid; + _address = address; + _size = size; + } + + private void textNewProtection_Enter(object sender, EventArgs e) + { + this.AcceptButton = buttonVirtualProtect; + } + + private void buttonCloseVirtualProtect_Click(object sender, EventArgs e) + { + this.Close(); + } + + private void buttonVirtualProtect_Click(object sender, EventArgs e) + { + try + { + int newprotect; + + try + { + newprotect = (int)BaseConverter.ToNumberParse(textNewProtection.Text); + } + catch + { + return; + } + + using (ProcessHandle phandle = + new ProcessHandle(_pid, ProcessAccess.VmOperation)) + { + try + { + phandle.ProtectMemory(_address, (int)_size, (MemoryProtection)newprotect); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to set memory protection", ex); + return; + } + } + + this.Close(); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to set memory protection", ex); + } + } + + private void textNewProtection_Leave(object sender, EventArgs e) + { + this.AcceptButton = null; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/VirtualProtectWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/VirtualProtectWindow.resx new file mode 100644 index 000000000..481674719 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/VirtualProtectWindow.resx @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Possible values: + +0x10 - PAGE_EXECUTE +0x20 - PAGE_EXECUTE_READ +0x40 - PAGE_EXECUTE_READWRITE +0x80 - PAGE_EXECUTE_WRITECOPY +0x01 - PAGE_NOACCESS +0x02 - PAGE_READONLY +0x04 - PAGE_READWRITE +0x08 - PAGE_WRITECOPY + +For example, input 0x01 to protect the area from any access. + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/VirusTotalUploaderWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/VirusTotalUploaderWindow.Designer.cs new file mode 100644 index 000000000..6408048fe --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/VirusTotalUploaderWindow.Designer.cs @@ -0,0 +1,145 @@ +namespace ProcessHacker +{ + partial class VirusTotalUploaderWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.LogoImg = new System.Windows.Forms.PictureBox(); + this.labelFile = new System.Windows.Forms.Label(); + this.uploadedLabel = new System.Windows.Forms.Label(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.speedLabel = new System.Windows.Forms.Label(); + this.totalSizeLabel = new System.Windows.Forms.Label(); + this.progressUpload = new System.Windows.Forms.ProgressBar(); + ((System.ComponentModel.ISupportInitialize)(this.LogoImg)).BeginInit(); + this.SuspendLayout(); + // + // LogoImg + // + this.LogoImg.Image = global::ProcessHacker.Properties.Resources.VirusTotal_logo; + this.LogoImg.Location = new System.Drawing.Point(319, 7); + this.LogoImg.Name = "LogoImg"; + this.LogoImg.Size = new System.Drawing.Size(103, 36); + this.LogoImg.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; + this.LogoImg.TabIndex = 0; + this.LogoImg.TabStop = false; + // + // labelFile + // + this.labelFile.AutoSize = true; + this.labelFile.Location = new System.Drawing.Point(12, 9); + this.labelFile.Name = "labelFile"; + this.labelFile.Size = new System.Drawing.Size(58, 13); + this.labelFile.TabIndex = 2; + this.labelFile.Text = "Uploading:"; + // + // uploadedLabel + // + this.uploadedLabel.AutoSize = true; + this.uploadedLabel.Location = new System.Drawing.Point(12, 54); + this.uploadedLabel.Name = "uploadedLabel"; + this.uploadedLabel.Size = new System.Drawing.Size(56, 13); + this.uploadedLabel.TabIndex = 3; + this.uploadedLabel.Text = "Uploaded:"; + // + // buttonCancel + // + this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonCancel.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonCancel.Location = new System.Drawing.Point(343, 75); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.TabIndex = 5; + this.buttonCancel.Text = "Cancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click); + // + // speedLabel + // + this.speedLabel.AutoSize = true; + this.speedLabel.Location = new System.Drawing.Point(213, 54); + this.speedLabel.Name = "speedLabel"; + this.speedLabel.Size = new System.Drawing.Size(41, 13); + this.speedLabel.TabIndex = 6; + this.speedLabel.Text = "Speed:"; + // + // totalSizeLabel + // + this.totalSizeLabel.AutoSize = true; + this.totalSizeLabel.Location = new System.Drawing.Point(12, 32); + this.totalSizeLabel.Name = "totalSizeLabel"; + this.totalSizeLabel.Size = new System.Drawing.Size(57, 13); + this.totalSizeLabel.TabIndex = 7; + this.totalSizeLabel.Text = "Total Size:"; + // + // progressUpload + // + this.progressUpload.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.progressUpload.Location = new System.Drawing.Point(12, 75); + this.progressUpload.Name = "progressUpload"; + this.progressUpload.Size = new System.Drawing.Size(325, 23); + this.progressUpload.TabIndex = 0; + // + // VirusTotalUploaderWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(430, 110); + this.Controls.Add(this.progressUpload); + this.Controls.Add(this.totalSizeLabel); + this.Controls.Add(this.speedLabel); + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.uploadedLabel); + this.Controls.Add(this.labelFile); + this.Controls.Add(this.LogoImg); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "VirusTotalUploaderWindow"; + this.ShowIcon = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.Manual; + this.Text = "VirusTotal Uploader"; + this.Load += new System.EventHandler(this.VirusTotalUploaderWindow_Load); + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.VirusTotalUploaderWindow_FormClosing); + ((System.ComponentModel.ISupportInitialize)(this.LogoImg)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.PictureBox LogoImg; + private System.Windows.Forms.Label labelFile; + private System.Windows.Forms.Label uploadedLabel; + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.Label speedLabel; + private System.Windows.Forms.Label totalSizeLabel; + private System.Windows.Forms.ProgressBar progressUpload; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/VirusTotalUploaderWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/VirusTotalUploaderWindow.cs new file mode 100644 index 000000000..4f369b7e9 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/VirusTotalUploaderWindow.cs @@ -0,0 +1,355 @@ +/* + * Process Hacker - + * ProcessHacker VirusTotal Implementation + * + * Copyright (C) 2009 dmex + * + * ProcessHacker permission to implement VirusTotal service authorized by: + * Julio Canto | VirusTotal.com | Hispasec Sistemas Lab | Tlf: +34.902.161.025 + * Fax: +34.952.028.694 | PGP Key ID: EF618D2B | jcanto@hispasec.com + * 26/09/2009 - 2:39PM + * + * 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 . + * + */ + +using System; +using System.Diagnostics; +using System.IO; +using System.Net; +using System.Text; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Common.Threading; +using ProcessHacker.Components; +using ProcessHacker.Native; +using TaskbarLib; + +namespace ProcessHacker +{ + public partial class VirusTotalUploaderWindow : Form + { + string fileName; + string processName; + + long totalFileSize; + long bytesPerSecond; + long bytesTransferred; + Stopwatch uploadStopwatch; + + ThreadTask uploadTask; + + public VirusTotalUploaderWindow(string procName, string procPath) + { + this.SetPhParent(); + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + processName = procName; + fileName = procPath; + + this.Icon = Program.HackerWindow.Icon; + } + + private void VirusTotalUploaderWindow_Load(object sender, EventArgs e) + { + labelFile.Text = string.Format("Uploading: {0}", processName); + + FileInfo finfo = new FileInfo(fileName); + if (!finfo.Exists) + { + if (OSVersion.HasTaskDialogs) + { + TaskDialog td = new TaskDialog(); + td.PositionRelativeToWindow = true; + td.Content = "The selected file doesn't exist or couldnt be found!"; + td.MainInstruction = "File Location not Available!"; + td.WindowTitle = "System Error"; + td.MainIcon = TaskDialogIcon.CircleX; + td.CommonButtons = TaskDialogCommonButtons.Ok; + td.Show(Program.HackerWindow.Handle); + } + else + { + MessageBox.Show( + this, "The selected file doesn't exist or couldnt be found!", + "System Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation + ); + } + + this.Close(); + } + else if (finfo.Length >= 20971520 /* 20MB */) + { + if (OSVersion.HasTaskDialogs) + { + TaskDialog td = new TaskDialog(); + td.PositionRelativeToWindow = true; + td.Content = "This file is larger than 20MB, above the VirusTotal limit!"; + td.MainInstruction = "File is too large"; + td.WindowTitle = "VirusTotal Error"; + td.MainIcon = TaskDialogIcon.CircleX; + td.CommonButtons = TaskDialogCommonButtons.Ok; + td.Show(Program.HackerWindow.Handle); + } + else + { + MessageBox.Show( + this, "This file is larger than 20MB and is above the VirusTotal size limit!", + "VirusTotal Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation + ); + } + + this.Close(); + } + else + { + totalFileSize = finfo.Length; + } + + uploadedLabel.Text = "Uploaded: Initializing"; + speedLabel.Text = "Speed: Initializing"; + + ThreadTask getSessionTokenTask = new ThreadTask(); + + getSessionTokenTask.RunTask += new ThreadTaskRunTaskDelegate(getSessionTokenTask_RunTask); + getSessionTokenTask.Completed += new ThreadTaskCompletedDelegate(getSessionTokenTask_Completed); + getSessionTokenTask.Start(); + } + + private void VirusTotalUploaderWindow_FormClosing(object sender, FormClosingEventArgs e) + { + if (uploadTask != null) + uploadTask.Cancel(); + + if (OSVersion.HasExtendedTaskbar) + { + Windows7Taskbar.SetTaskbarProgressState( + Program.HackerWindowHandle, + Windows7Taskbar.ThumbnailProgressState.NoProgress + ); + } + } + + private void getSessionTokenTask_RunTask(object param, ref object result) + { + try + { + HttpWebRequest sessionRequest = (HttpWebRequest)HttpWebRequest.Create("http://www.virustotal.com/vt/en/identificador"); + sessionRequest.ServicePoint.ConnectionLimit = 20; + sessionRequest.UserAgent = "Process Hacker " + Application.ProductVersion; + sessionRequest.Timeout = System.Threading.Timeout.Infinite; + sessionRequest.KeepAlive = true; + + using (WebResponse Response = sessionRequest.GetResponse()) + using (Stream WebStream = Response.GetResponseStream()) + using (StreamReader Reader = new StreamReader(WebStream)) + { + result = Reader.ReadToEnd(); + } + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to contact VirusTotal", ex); + + if (this.IsHandleCreated) + this.BeginInvoke(new MethodInvoker(this.Close)); + } + } + + private void getSessionTokenTask_Completed(object result) + { + if (result != null) //incase theres an expcetion getting sessiontoken + { + uploadTask = new ThreadTask(); + uploadTask.RunTask += uploadTask_RunTask; + uploadTask.Completed += uploadTask_Completed; + uploadTask.Start(result); + } + } + + private void uploadTask_RunTask(object param, ref object result) + { + string boundary = "----------" + DateTime.Now.Ticks.ToString("x"); + + HttpWebRequest uploadRequest = (HttpWebRequest)WebRequest.Create( + "http://www.virustotal.com/vt/en/recepcionf?" + (string)param); + uploadRequest.ServicePoint.ConnectionLimit = 20; + uploadRequest.UserAgent = "ProcessHacker " + Application.ProductVersion; + uploadRequest.ContentType = "multipart/form-data; boundary=" + boundary; + uploadRequest.Timeout = System.Threading.Timeout.Infinite; + uploadRequest.KeepAlive = true; + uploadRequest.Method = WebRequestMethods.Http.Post; + + // Build up the 'post' message header + StringBuilder sb = new StringBuilder(); + sb.Append("--"); + sb.Append(boundary); + sb.Append("\r\n"); + sb.Append(@"Content-Disposition: form-data; name=""archivo""; filename=" + processName + ""); + sb.Append("\r\n"); + sb.Append("Content-Type: application/octet-stream"); + sb.Append("\r\n"); + sb.Append("\r\n"); + + string postHeader = sb.ToString(); + byte[] postHeaderBytes = Encoding.UTF8.GetBytes(postHeader); + + // Build the trailing boundary string as a byte array + // ensuring the boundary appears on a line by itself + byte[] boundaryBytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n"); + + if (uploadTask.Cancelled) + { + uploadRequest.Abort(); + return; + } + + try + { + uploadStopwatch = new Stopwatch(); + uploadStopwatch.Start(); + + using (FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read)) + { + uploadRequest.ContentLength = postHeaderBytes.Length + fileStream.Length + boundaryBytes.Length; + + using (Stream requestStream = uploadRequest.GetRequestStream()) + { + // Write out our post header + requestStream.Write(postHeaderBytes, 0, postHeaderBytes.Length); + // Write out the file contents + byte[] buffer = new Byte[checked((uint)Math.Min(32, (int)fileStream.Length))]; + + int bytesRead = 0; + + while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0) + { + if (uploadTask.Cancelled) + { + uploadRequest.Abort(); + return; + } + + requestStream.Write(buffer, 0, bytesRead); + + int progress = (int)(((double)fileStream.Position * 100 / fileStream.Length)); + + if (uploadStopwatch.ElapsedMilliseconds > 0) + bytesPerSecond = fileStream.Position * 1000 / uploadStopwatch.ElapsedMilliseconds; + + bytesTransferred = fileStream.Position; + + if (this.IsHandleCreated) + this.BeginInvoke(new Action(this.ChangeProgress), progress); + } + + if (uploadTask.Cancelled) + { + uploadRequest.Abort(); + return; + } + + // Write out the trailing boundary + requestStream.Write(boundaryBytes, 0, boundaryBytes.Length); + + requestStream.Close(); + } + } + } + catch (WebException ex) + { + // RequestCanceled will occour when we cancel the WebRequest. + // Filter out that exception but log all others. + if (ex != null) + { + if (ex.Status != WebExceptionStatus.RequestCanceled) + { + PhUtils.ShowException("Unable to upload the file", ex); + Logging.Log(ex); + + if (this.IsHandleCreated) + this.BeginInvoke(new MethodInvoker(this.Close)); + } + } + } + + if (uploadTask.Cancelled) + { + uploadRequest.Abort(); + return; + } + + WebResponse response = uploadRequest.GetResponse(); + + //Stream s = responce.GetResponseStream(); + //StreamReader sr = new StreamReader(s); + //sr.ReadToEnd(); + + //Return the response URL + result = response.ResponseUri.AbsoluteUri; + } + + private void ChangeProgress(int progress) + { + uploadedLabel.Text = "Uploaded: " + Utils.FormatSize(bytesTransferred) + + " (" + ((double)bytesTransferred * 100 / totalFileSize).ToString("F2") + "%)"; + totalSizeLabel.Text = "Total Size: " + Utils.FormatSize(totalFileSize); + speedLabel.Text = "Speed: " + Utils.FormatSize(bytesPerSecond) + "/s"; + progressUpload.Value = progress; + + if (OSVersion.HasExtendedTaskbar) + Windows7Taskbar.SetTaskbarProgress(Program.HackerWindow, this.progressUpload); + } + + private void uploadTask_Completed(object result) + { + if (this.InvokeRequired) + { + this.BeginInvoke(new ThreadTaskCompletedDelegate(uploadTask_Completed), result); + return; + } + + //TODO: future additions will parse the page and + //display the appropriate infomation but for now just mirror + //the functionality of the VirusTotal desktop client and + //launch the URL in the default browser + + var webException = uploadTask.Exception as WebException; + + if (webException != null && webException.Status != WebExceptionStatus.Success) + { + if (webException.Status != WebExceptionStatus.RequestCanceled) + { + PhUtils.ShowException("Unable to upload the file", webException); + this.Close(); + } + } + else if (result != null && !uploadTask.Cancelled) //sanity check + { + Program.TryStart(result.ToString()); + } + + this.Close(); + } + + private void buttonCancel_Click(object sender, EventArgs e) + { + this.Close(); + } + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/VirusTotalUploaderWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/VirusTotalUploaderWindow.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/VirusTotalUploaderWindow.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/WaitChainWindow.Designer.cs b/branches/ph-plugins/ProcessHacker/Forms/WaitChainWindow.Designer.cs new file mode 100644 index 000000000..b1b9298d0 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/WaitChainWindow.Designer.cs @@ -0,0 +1,154 @@ +namespace ProcessHacker +{ + partial class WaitChainWindow + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.textDescription = new System.Windows.Forms.TextBox(); + this.labelIntro = new System.Windows.Forms.Label(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.buttonEndThread = new System.Windows.Forms.Button(); + this.moreInfoLink = new System.Windows.Forms.LinkLabel(); + this.buttonProperties = new System.Windows.Forms.Button(); + this.threadTree = new VistaTreeView(); + this.SuspendLayout(); + // + // textDescription + // + this.textDescription.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textDescription.BackColor = System.Drawing.SystemColors.Control; + this.textDescription.Location = new System.Drawing.Point(12, 12); + this.textDescription.Name = "textDescription"; + this.textDescription.Size = new System.Drawing.Size(361, 20); + this.textDescription.TabIndex = 1; + // + // labelIntro + // + this.labelIntro.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.labelIntro.Location = new System.Drawing.Point(12, 253); + this.labelIntro.Name = "labelIntro"; + this.labelIntro.Size = new System.Drawing.Size(390, 41); + this.labelIntro.TabIndex = 2; + this.labelIntro.Text = "Analyzing the Wait Chain for a process helps diagnose application hangs and deadl" + + "ocks caused by a process using or waiting to use a resource that is being used b" + + "y another process."; + this.labelIntro.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // + // buttonCancel + // + this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonCancel.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonCancel.Location = new System.Drawing.Point(328, 294); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 23); + this.buttonCancel.TabIndex = 3; + this.buttonCancel.Text = "Cancel"; + this.buttonCancel.UseVisualStyleBackColor = true; + this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click); + // + // buttonEndThread + // + this.buttonEndThread.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonEndThread.Enabled = false; + this.buttonEndThread.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.buttonEndThread.Location = new System.Drawing.Point(247, 294); + this.buttonEndThread.Name = "buttonEndThread"; + this.buttonEndThread.Size = new System.Drawing.Size(75, 23); + this.buttonEndThread.TabIndex = 4; + this.buttonEndThread.Text = "End Thread"; + this.buttonEndThread.UseVisualStyleBackColor = true; + // + // moreInfoLink + // + this.moreInfoLink.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.moreInfoLink.AutoSize = true; + this.moreInfoLink.Location = new System.Drawing.Point(9, 304); + this.moreInfoLink.Name = "moreInfoLink"; + this.moreInfoLink.Size = new System.Drawing.Size(121, 13); + this.moreInfoLink.TabIndex = 5; + this.moreInfoLink.TabStop = true; + this.moreInfoLink.Text = "More about Wait Chains"; + this.moreInfoLink.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.moreInfoLink_LinkClicked); + // + // buttonProperties + // + this.buttonProperties.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Right))); + this.buttonProperties.Image = global::ProcessHacker.Properties.Resources.application_form_magnify; + this.buttonProperties.Location = new System.Drawing.Point(379, 9); + this.buttonProperties.Name = "buttonProperties"; + this.buttonProperties.Size = new System.Drawing.Size(24, 24); + this.buttonProperties.TabIndex = 7; + this.buttonProperties.UseVisualStyleBackColor = true; + this.buttonProperties.Click += new System.EventHandler(this.buttonProperties_Click); + // + // threadTree + // + this.threadTree.CheckBoxes = true; + this.threadTree.Location = new System.Drawing.Point(12, 38); + this.threadTree.Name = "threadTree"; + this.threadTree.Size = new System.Drawing.Size(390, 212); + this.threadTree.TabIndex = 9; + // + // WaitChainWindow + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(415, 329); + this.Controls.Add(this.threadTree); + this.Controls.Add(this.buttonProperties); + this.Controls.Add(this.moreInfoLink); + this.Controls.Add(this.buttonEndThread); + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.labelIntro); + this.Controls.Add(this.textDescription); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "WaitChainWindow"; + this.ShowIcon = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.Manual; + this.Text = "WaitChainWindow"; + this.Load += new System.EventHandler(this.WaitChainWindow_Load); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TextBox textDescription; + private System.Windows.Forms.Label labelIntro; + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.Button buttonEndThread; + private System.Windows.Forms.LinkLabel moreInfoLink; + private System.Windows.Forms.Button buttonProperties; + private VistaTreeView threadTree; + } +} \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Forms/WaitChainWindow.cs b/branches/ph-plugins/ProcessHacker/Forms/WaitChainWindow.cs new file mode 100644 index 000000000..60ba4b5d4 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/WaitChainWindow.cs @@ -0,0 +1,452 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Text; +using System.Windows.Forms; +using ProcessHacker.Common; +using Microsoft.Win32.SafeHandles; +using System.Runtime.InteropServices; +using System.Diagnostics; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; + +namespace ProcessHacker +{ + public partial class WaitChainWindow : Form + { + int processPid; + string processName; + + TreeNode threadNode; //static reference to Nodes + + public WaitChainWindow(string procName, int procPid) + { + this.SetPhParent(); + InitializeComponent(); + this.AddEscapeToClose(); + this.SetTopMost(); + + processPid = procPid; + processName = procName; + } + + private void moreInfoLink_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Program.TryStart("http://go.microsoft.com/fwlink/?LinkID=136333"); + } + + private void WaitChainWindow_Load(object sender, EventArgs e) + { + using (WaitChainTraversal wct = new WaitChainTraversal()) + { + ShowProcessWaitChains(wct, false); + } + } + + private void ShowProcessWaitChains(WaitChainTraversal wct, bool showAllData) + { + var threads = Windows.GetProcessThreads(processPid); + + if (threads == null) + { + PhUtils.ShowWarning(string.Format("The process ID {0} does not exist", processPid)); + this.Close(); + } + + textDescription.AppendText(string.Format("Process: {0}, PID: {1}", processName, processPid)); + + threadNode = threadTree.Nodes.Add(string.Format("Process: {0}, PID: {1}", processName, processPid)); + + foreach (var thread in threads) + { + //Get the wait chains for this thread. + int currThreadId = thread.Key; + + WaitData data = wct.GetThreadWaitChain(currThreadId); + + if (data != null) + { + DisplayThreadData(data, showAllData); + } + else //This happens when running without admin rights. + { + threadNode.Nodes.Add(string.Format("TID:{0} Unable to retrieve wait chains for this thread without Admin rights", currThreadId)); + threadNode.ExpandAll(); + } + } + } + + private void DisplayThreadData(WaitData data, bool allData) + { + // Save the process id value for the first item as this is the + // process that owns the thread. we'll use this to check for + // items used by other threads, from other processes later. + int startingPID = data.Nodes[0].ProcessId; + StringBuilder sb = new StringBuilder(); + + if (data.IsDeadlock) + { + sb.Append("DEADLOCKED: "); + } + + for (int i = 0; i < data.NodeCount; i++) + { + WaitChainNativeMethods.WAITCHAIN_NODE_INFO node = data.Nodes[i]; + + if (WaitChainNativeMethods.WCT_OBJECT_TYPE.Thread == node.ObjectType) + { + var processes = Windows.GetProcesses(); + String procName = processes.ContainsKey(node.ProcessId) ? processes[node.ProcessId].Name : "???"; + + switch (node.ObjectStatus) + { + case WaitChainNativeMethods.WCT_OBJECT_STATUS.PidOnly: + case WaitChainNativeMethods.WCT_OBJECT_STATUS.PidOnlyRpcss: + sb.Append(string.Format(" PID: {0} {1}", node.ProcessId, procName)); + break; + default: + { + sb.Append(string.Format(" TID: {0}", node.ThreadId)); + + //Is this a block on a thread from another process? + if ((i > 0) && (startingPID != node.ProcessId)) + { + // Yes, so show the PID and name. + sb.Append(string.Format(" PID:{0} {1}", node.ProcessId, procName)); + } + + if (allData) + { + sb.Append(string.Format(" Status: {0} Wait: {1} CS: {2:N0}", node.ObjectStatus, node.WaitTime, node.ContextSwitches)); + } + else if (node.ObjectStatus != WaitChainNativeMethods.WCT_OBJECT_STATUS.Blocked) + { + sb.Append(string.Format(" Status: {0}", node.ObjectStatus)); + } + break; + } + } + } + else + { + switch (node.ObjectType) + { + case WaitChainNativeMethods.WCT_OBJECT_TYPE.CriticalSection: + case WaitChainNativeMethods.WCT_OBJECT_TYPE.SendMessage: + case WaitChainNativeMethods.WCT_OBJECT_TYPE.Mutex: + case WaitChainNativeMethods.WCT_OBJECT_TYPE.Alpc: + case WaitChainNativeMethods.WCT_OBJECT_TYPE.COM: + case WaitChainNativeMethods.WCT_OBJECT_TYPE.ThreadWait: + case WaitChainNativeMethods.WCT_OBJECT_TYPE.ProcessWait: + case WaitChainNativeMethods.WCT_OBJECT_TYPE.COMActivation: + case WaitChainNativeMethods.WCT_OBJECT_TYPE.Unknown: + { + sb.Append(string.Format(" {0} Status: {1}", node.ObjectType, node.ObjectStatus)); + + String name = node.ObjectName(); + + if (!String.IsNullOrEmpty(name)) + { + sb.Append(string.Format(" Name: {0}", name)); + } + } + break; + default: + { + sb.Append(string.Format(" UNKNOWN Object Type Enum: {0}", node.ObjectType.ToString())); + break; + } + } + } + threadNode.Nodes.Add(sb.ToString()); + threadNode.ExpandAll(); + } + } + + private void buttonCancel_Click(object sender, EventArgs e) + { + this.Close(); + } + + private void buttonProperties_Click(object sender, EventArgs e) + { + try + { + ProcessWindow pForm = Program.GetProcessWindow(Program.HackerWindow.processP.Dictionary[processPid], + new Program.PWindowInvokeAction(delegate(ProcessWindow f) + { + Properties.Settings.Default.ProcessWindowSelectedTab = "tabThreads"; + f.Show(); + f.Activate(); + })); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to inspect the process", ex); + } + } + } + + /// + /// Wraps all the native Wait Chain Traversal code. + /// + public static partial class WaitChainNativeMethods + { + // Keep the module handle around for the life of the application as the WCT code has pointers into it. + private static SafeModuleHandle oleModule; + + // Max. number of nodes in the wait chain + public const int WCT_MAX_NODE_COUNT = 16; + // Max. length of a named object. + private const int WCT_OBJNAME_LENGTH = 128; + + public static SafeWaitChainHandle OpenThreadWaitChainSession() + { + // Get the COM APIs into WCT. I have no idea why WCT just doesn't do this itself. + if (oleModule == null) + { + oleModule = LoadLibraryW("OLE32.DLL"); + IntPtr coGetCallState = GetProcAddress(oleModule, "CoGetCallState"); + IntPtr coGetActivationState = GetProcAddress(oleModule, "CoGetActivationState"); + // Register these functions with WCT. + RegisterWaitChainCOMCallback(coGetCallState, coGetActivationState); + } + + SafeWaitChainHandle wctHandle = RealOpenThreadWaitChainSession(0, IntPtr.Zero); + if (wctHandle.IsInvalid == true) + { + throw new InvalidOperationException("Unable to open the Wait Thread Chain."); + } + return (wctHandle); + } + + public static bool GetThreadWaitChain(SafeWaitChainHandle chainHandle, int threadId, ref int NodeCount, WAITCHAIN_NODE_INFO[] NodeInfoArray, out int IsCycle) + { + return RealGetThreadWaitChain(chainHandle, IntPtr.Zero, WCT_FLAGS.All, threadId, ref NodeCount, NodeInfoArray, out IsCycle); + } + + public static void CloseThreadWaitChainSession(IntPtr handle) + { + RealCloseThreadWaitChainSession(handle); + } + + /// + /// The data structure returned indicating blocked threads. + /// + /// + /// Even though the ObjectName field is a character array, it's declared + /// as a ushort because of a bug in the VS05 CLR marshalling with character + /// arrays and the fixed keyword. By using the ushort, the structure is + /// now blittable, meaning the managed and native types are the same. + /// A char is not blittable because it has multiple representations in + /// native code (ANSI and UNICODE). + /// Fortunately, to get the actual character array in ObjectName, you + /// can cast the ushort pointer to a char pointer passed to the String + /// constructor. + /// + [StructLayout(LayoutKind.Explicit, Size = 280)] + public unsafe struct WAITCHAIN_NODE_INFO + { + [FieldOffset(0x0)] + public WCT_OBJECT_TYPE ObjectType; + [FieldOffset(0x4)] + public WCT_OBJECT_STATUS ObjectStatus; + + // The name union. + [FieldOffset(0x8)] + private fixed ushort RealObjectName[WCT_OBJNAME_LENGTH]; + [FieldOffset(0x108)] + public int TimeOutLowPart; + [FieldOffset(0x10C)] + public int TimeOutHiPart; + [FieldOffset(0x110)] + public int Alertable; + + // The thread union. + [FieldOffset(0x8)] + public int ProcessId; + [FieldOffset(0xC)] + public int ThreadId; + [FieldOffset(0x10)] + public int WaitTime; + [FieldOffset(0x14)] + public int ContextSwitches; + + //TODO: fix this... fixes old VS05 bug thats now non-existent + //Does the work to get the ObjectName field. + public String ObjectName() + { + fixed (WAITCHAIN_NODE_INFO* p = &this) + { + string str = (p->RealObjectName[0] != '\0') ? new string((char*)p->RealObjectName) : string.Empty; + return str; + } + } + } + + [Flags] + public enum WCT_OBJECT_TYPE + { + CriticalSection = 1, + SendMessage, + Mutex, + Alpc, + COM, + ThreadWait, + ProcessWait, + Thread, + COMActivation, + Unknown, + } ; + + [Flags] + public enum WCT_OBJECT_STATUS + { + NoAccess = 1, // ACCESS_DENIED for this object + Running, // Thread status + Blocked, // Thread status + PidOnly, // Thread status + PidOnlyRpcss, // Thread status + Owned, // Dispatcher object status + NotOwned, // Dispatcher object status + Abandoned, // Dispatcher object status + Unknown, // All objects + Error, // All objects + } ; + + [Flags] + public enum WCT_FLAGS + { + Flag = 0x1, + COM = 0x2, + Proc = 0x4, + All = Flag | COM | Proc + } + + [DllImport("advapi32.dll", SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode, EntryPoint = "CloseThreadWaitChainSession")] + private static extern void RealCloseThreadWaitChainSession(IntPtr wctHandle); + + [DllImport("advapi32.dll", EntryPoint = "OpenThreadWaitChainSession")] + private static extern SafeWaitChainHandle RealOpenThreadWaitChainSession(int flags, IntPtr callback); + + [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)] + private static extern void RegisterWaitChainCOMCallback(IntPtr callStateCallback, IntPtr activationStateCallback); + + [DllImport("advapi32.dll", EntryPoint = "GetThreadWaitChain")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool RealGetThreadWaitChain(SafeWaitChainHandle WctHandle, IntPtr Context, WCT_FLAGS Flags, int ThreadId, ref int NodeCount, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 4)] [In, Out] WAITCHAIN_NODE_INFO[] NodeInfoArray, out int IsCycle); + + [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)] + internal static extern SafeModuleHandle LoadLibraryW(String lpFileName); + + [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool FreeLibrary(IntPtr hModule); + + [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true, CharSet = CharSet.Ansi)] + internal static extern IntPtr GetProcAddress(SafeModuleHandle hModule, string lpProcName); + } + + public class SafeModuleHandle : SafeHandleZeroOrMinusOneIsInvalid + { + public SafeModuleHandle() + : base(true) + { + } + + protected override Boolean ReleaseHandle() + { + return (WaitChainNativeMethods.FreeLibrary(this.handle)); + } + } + + public class SafeWaitChainHandle : SafeHandleZeroOrMinusOneIsInvalid + { + private SafeWaitChainHandle() + : base(true) + { + } + + protected override bool ReleaseHandle() + { + WaitChainNativeMethods.CloseThreadWaitChainSession(this.handle); + return (true); + } + } + + public sealed class WaitData + { + private WaitChainNativeMethods.WAITCHAIN_NODE_INFO[] data; + private bool isDeadlock; + private int nodeCount; + + public WaitData(WaitChainNativeMethods.WAITCHAIN_NODE_INFO[] data, int nodeCount, bool isDeadlock) + { + this.data = data; + this.nodeCount = nodeCount; + this.isDeadlock = isDeadlock; + } + + public WaitChainNativeMethods.WAITCHAIN_NODE_INFO[] Nodes + { + get + { + return (data); + } + } + + public int NodeCount + { + get + { + return (nodeCount); + } + } + + public bool IsDeadlock + { + get + { + return (isDeadlock); + } + } + } + + public sealed class WaitChainTraversal : IDisposable + { + private SafeWaitChainHandle waitChainHandle; + + public WaitChainTraversal() + { + waitChainHandle = WaitChainNativeMethods.OpenThreadWaitChainSession(); + } + + public WaitData GetThreadWaitChain(int threadId) + { + WaitChainNativeMethods.WAITCHAIN_NODE_INFO[] data = new WaitChainNativeMethods.WAITCHAIN_NODE_INFO[WaitChainNativeMethods.WCT_MAX_NODE_COUNT]; + int isDeadlock = 0; + int nodeCount = WaitChainNativeMethods.WCT_MAX_NODE_COUNT; + + WaitData retData = null; + + if (WaitChainNativeMethods.GetThreadWaitChain(waitChainHandle, threadId, ref nodeCount, data, out isDeadlock)) + { + retData = new WaitData(data, (int)nodeCount, isDeadlock == 1); + } + + return (retData); + } + + #region IDisposable Members + + public void Dispose() + { + waitChainHandle.Dispose(); + } + + #endregion + } + +} diff --git a/branches/ph-plugins/ProcessHacker/Forms/WaitChainWindow.resx b/branches/ph-plugins/ProcessHacker/Forms/WaitChainWindow.resx new file mode 100644 index 000000000..ff31a6db5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Forms/WaitChainWindow.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Help.htm b/branches/ph-plugins/ProcessHacker/Help.htm new file mode 100644 index 000000000..98780ec05 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Help.htm @@ -0,0 +1,757 @@ + + + + Process Hacker Help + + + +

Process Hacker

+ +

Introduction

+

Process Hacker is a tool to view and manipulate processes and services. It can display process' threads, + modules, memory regions and handles, search through process memory, and read/write memory using + a built-in hex editor.

+ +

System Requirements

+
    +
  • Microsoft Windows XP SP2, Vista or 7 (Windows XP SP3 and Windows Vista SP1 required for certain features)
  • +
  • .NET Framework 2.0
  • +
+ +

Configuration Files

+

On Windows Vista, the configuration files for Process Hacker are stored in + AppData\Local\wj32. On Windows XP, they are stored in + Local Settings\Application Data\wj32.

+ +

Command Line Options

+
+
-a
+
Aggressive mode. Attempts to unhook all system call stubs and hooks certain system calls + to use KProcessHacker.
+
-e
+
Enables extended command line processing (not documented at the present time).
+
-elevate
+
Starts Process Hacker elevated.
+
-h, -help, -?
+
Shows a list of available command line options.
+
-installkph
+
Installs the KProcessHacker service.
+
-ip pid
+
Opens process properties for the specified process after all other loading has completed.
+
-m
+
Starts Process Hacker hidden, regardless of any settings.
+
-nokph
+
Disables KProcessHacker.
+
-o [-hwnd hWnd] [-rect x,y,width,height]
+
Opens Process Hacker options without the main window. Note that the width and height parts of + the rectangle parameter are ignored.
+
-pw pid
+
Opens process properties for the specified process without the main window.
+
-pt pid
+
Opens token properties for the token of the specified process without the main window.
+
-t tab
+
Opens the specified tab at startup. Use 0 for Processes, 1 for Services and 2 for Network.
+
-uninstallkph
+
Uninstalls the KProcessHacker service.
+
-v
+
Starts Process Hacker visible, regardless of any settings.
+
+ +

Options

+

Process Hacker's options are accessible from the Options menu item + in the Hacker menu.

+ +

General

+
+
Update Interval
+
The amount of time in milliseconds between each update; i.e, when + Process Hacker looks for new, modified or removed processes, services and other objects.
+ +
Processes in icon menu
+
The number of processes to display in the notification icon menu.
+ +
Search Engine
+
This is used by the Search Online... menu item in the process and module + context menus. %s is replaced by the name of the selected process or module.
+ +
Require Signatures
+
If Verify signatures and perform additional checks is enabled, this + specifies the processes that must have a valid signature. Processes with a name + that is specified in this field and do not have a valid signature will be highlighted + as a Packed/Dangerous Process (see Higlighting options).
+ +
Max. Size Unit
+
Specifies the maximum unit of size; sizes which can be displayed as 1024 or less in a + smaller unit will be displayed in that smaller unit, while sizes requiring a larger unit will + use units up to the maximum unit specified here.
+ +
Hide when minimized
+
If enabled, Process Hacker will automatically hide itself when it is minimized. You + can double-click on the notification icon to show Process Hacker.
+ +
Hide when closed
+
If enabled, Process Hacker will automatically hide itself when it is closed. You + can double-click on the notification icon to show Process Hacker.
+ +
Start hidden
+
If enabled, Process Hacker will start hidden. You can double-click on the notification + icon to show Process Hacker.
+ +
Allow only one instance
+
If enabled, Process Hacker will allow only one instance of itself. Any attempts to start + a new instance will show the existing instance.
+ +
Float child windows
+
If enabled, child windows such as process properties and the memory editor will float + above the main Process Hacker window.
+ +
Scroll down the process tree at startup
+
If enabled, Process Hacker will scroll down the process tree to the first instance of + explorer.exe running as the current user at startup.
+ +
Show user/group domains
+
If enabled, Process Hacker will show the domain of users and groups: user + would be shown as machine-name\user.
+
+ +

Advanced

+
+
Enable kernel-mode driver
+
Some handles cannot be displayed by a user-mode program like Process Hacker; this + option enables KProcessHacker which allows Process Hacker + to display all handles and bypass rootkits/security software. If enabled, it will be + loaded the next time Process Hacker is started.
+ +
Enable experimental features
+
Enables experimental features such as process protection.
+ +
Verify signatures and perform additional checks
+
This option affects newly created processes, and controls whether Process Hacker will + attempt to verify the digital signatures of processes and detect packed images.
+ +
Replace Task Manager with Process Hacker
+
If enabled, any attempt to start Task Manager will start Process Hacker instead.
+ +
Warn about potentially dangerous actions
+
If disabled, Process Hacker will not show confirmation prompts for most actions.
+ +
Hide handles with no name
+
If enabled, unnamed handles will be hidden by default. This can be changed in each + process properties window.
+ +
Hide Process Hacker network connections
+
If enabled, network connections made by Process Hacker will be hidden in the network + connections list.
+ +
Elevation
+
Controls how Process Hacker will prompt for elevation in operations where the user + does not have required permissions.
+ +
Max. Sample History
+
Specifies the maximum number of performance-related samples to be retained. This includes + CPU, I/O and memory usage data for the system and all processes.
+
+ +

Highlighting

+
+
Highlighting Duration
+
This specifies the amount of time for which new and removed objects (processes, threads and services) + are highlighted in a different color.
+ +
New Objects
+
New processes, services, threads, modules, memory regions, and handles.
+ +
Removed Objects
+
Terminated/deleted processes, services, threads, modules, memory regions and + handles.
+ +
Own Processes
+
Processes running under the same user account as Process Hacker.
+ +
System Processes
+
Processes running under the SYSTEM user account.
+ +
Service Processes
+
Processes hosting one or more services.
+ +
Debugged Processes
+
Processes currently being debugged.
+ +
Elevated Processes
+
Processes running with full privileges on a computer with + User Account Control (UAC) enabled.
+ +
Job Processes
+
Processes associated with a job object.
+ +
.NET Processes and DLLs
+
Managed (.NET) processes and DLLs/modules.
+ +
POSIX Processes
+
POSIX subsystem processes (also known as Subsystem for UNIX-based Applications).
+ +
Packed/Dangerous Processes
+
Packed images and images with invalid signatures. These processes + are often, but not always malicious - normal executables are often packed to reduce their + size.
+ +
Suspended Threads
+
Threads which have been suspended.
+ +
GUI Threads
+
Threads which have made at least one GUI-related system call.
+ +
Relocated DLLs
+
DLLs which were not loaded at their preferred base address.
+ +
Protected Handles
+
Handles which are protected from being closed.
+ +
Inherit Handles
+
Handles which will be inherited by child processes.
+
+ +

Plotting

+
+
Use Anti-aliasing
+
If enabled, Process Hacker will draw graphs with anti-aliasing. This will + usually consume much more system resources than normal.
+ +
Step
+
This option controls the distance in pixels between each data point.
+
+ +

Symbols

+
+
Dbghelp.dll path
+
Select the path to the most recent version of dbghelp.dll you have + installed on your computer. If you do not have the latest version, go to + http://www.microsoft.com/whdc/devtools/debugging/default.mspx and + download Debugging Tools for Windows.
+ +
Search path
+
Type in a symbol server path. Most users will want to use the following: + SRV*C:\Users\USERNAME\Symbols*http://msdl.microsoft.com/download/symbols. + This will have any needed symbols downloaded from Microsoft's symbol server to + the specified directory (in bold).
+ +
Undecorate symbols
+
If enabled, C++ symbol names will be undecorated (unmangled). This is most + useful for methods with complex signatures.
+
+ +

Number Input

+

Process Hacker supports the input of numbers in various bases (including some non-standard + extensions). This is allowed in: Get Function Address, Change Memory Protection, the Go To + box in Read/Write Memory, and the insertion of numbers through the Utilities + button.

+

A number is assumed to be in base 10 unless:

+
    +
  • It starts with 0 (zero) - octal (base 8)
  • +
  • It starts with 0x - hexadecimal (base 16)
  • +
  • It starts with b - binary (base 2)
  • +
  • It starts with t - ternary (base 3)
  • +
  • It starts with q - quaternary (base 4)
  • +
  • It starts with w - base 12
  • +
  • It starts with r - base 32
  • +
+ +

Process Tree

+

The process tree displays processes running on the system as a tree; processes started by a + particular parent process are shown indented below it. Processes with a non-existent parent + (where its parent has terminated) are shown on the far left. You can manipulate processes by + right-clicking on them, and you can show detailed properties for a process by double-clicking + it or selecting the "Properties..." menu item.

+ +

You can sort by the various columns by clicking on them - the tree view will temporarily + become a flat list. You can click the same column again to sort in the reverse order, and + once more to return to the tree view.

+ +

Like Process Explorer, Process Hacker shows Deferred Procedure Calls (DPCs) and Interrupts + in the process tree. The only information these "processes" show is their CPU usage.

+ +

Context Menu

+

Warning: Manipulating csrss.exe, dwm.exe, lsass.exe, lsm.exe, smss.exe, + winlogon.exe or any other system processes is not recommended and may lead to system instability or + a crash.

+ +
+
Terminate Process(es)
+
Terminates the selected process(es). If KProcessHacker is enabled, Process Hacker + will, except under extraordinary circumstances, be able to terminate any process, + including ones protected by rootkits or security software.
+ +
Terminate Process Tree
+
Terminates the selected process and its descendants.
+ +
Suspend Process(es)
+
Suspends the selected process(es). If KProcessHacker is enabled and running on + Windows Vista, Process Hacker will be able to suspend any process, including ones + protected by rootkits or security software.
+ +
Resume Process(es)
+
Resumes the selected process(es). If KProcessHacker is enabled and running on + Windows Vista, Process Hacker will be able to resume any process, including ones + protected by rootkits or security software.
+ +
Restart
+
Restarts the selected process with the same command line arguments and working + directory.
+ +
Reduce Working Set
+
Empties the selected process(es)' working set(s). + This is a safe function; the process will eventually reclaim most of its working set.
+ +
Virtualization
+
Allows you to enable or disable virtualization for the selected process, if allowed.
+ +
Affinity...
+
Allows you to view and modify the process' CPU affinity (the CPUs on which it is allowed + to run).
+ +
Create Dump File...
+
Allows you to create a crash dump file for the process. This operation does not actually + cause the process to crash or terminate.
+ +
Terminator...
+
A tool which tries to terminate the selected process using many different techniques.
+ +
Detach from Debugger
+
Detaches the process from any debugger. This will cause any attached debuggers to stop working.
+ +
Heaps...
+
Shows the heaps created by the process. Note that this action causes a temporary thread + to be created in the process and should be used with caution.
+ +
Inject DLL...
+
Allows you to select a DLL file (or any other PE image) that will be injected into + the selected process. This option is only available for processes running in the same + session as Process Hacker (usually processes in the same user account).
+ +
Priority
+
Sets the process's priority - Real Time, High, Above Normal, Normal, Below Normal, Idle. + This option is not available when multiple processes are selected.
+ +
Run As
+
These tools require Assistant.exe (distributed with Process Hacker) to be in the same directory + as ProcessHacker.exe.
+ Launch As User... - This allows you to run the selected process as another user.
+ Launch As This User... - This allows you to run a program under the selected process' user. This + is useful when you want to start a program as another user but you do not have that user's password.
+ +
Search Online...
+
Opens the default web browser with the search engine specified in Process Hacker's options.
+ +
Re-analyze
+
Re-examines the process to determine if it is signed, packed, or a .NET process.
+ +
Select All
+
Selects all items in the list.
+
+ +

Terminator tests

+
+
TP1
+
Terminates the process using the NtTerminateProcess function.
+ +
TP2
+
Uses the RtlCreateUserThread function to create a thread in the process which calls + ExitProcess, terminating the process. On Vista and above, the thread calls + RtlExitUserProcess.
+ +
TT1
+
Terminates the process' threads by using the NtTerminateThread function.
+ +
TT2
+
Sets the contexts of the process' threads to point to the ExitProcess function. The + process will be terminated when one of the threads are context switched to.
+ +
TP1a
+
(Vista only.) Uses NtGetNextProcess to open a handle to the process and terminate it + using NtTerminateProcess.
+ +
TT1a
+
(Vista only.) Uses NtGetNextThread to open a handle to each of the process' threads and + terminates them using NtTerminateThread.
+ +
CH1
+
Uses NtDuplicateObject to close the process' handles. This method works best for + complex programs.
+ +
TJ1
+
Creates a job, assigns the process to it, and terminates the job, terminating the process.
+ +
TD1
+
Creates a debug object, assigns the process to it, and closes the debug object, + terminating the process.
+ +
TP3
+
Uses the internal kernel-mode function PsTerminateProcess to terminate the process.
+ +
TT3
+
Uses the internal kernel-mode function PspTerminateThreadByPointer to terminate the process' + threads.
+ +
TT4
+
Queues a kernel-mode special asynchronous procedure calls (APCs) to each of the process' threads. + This APC calls PspTerminateThreadByPointer to directly terminate the threads. This method will + terminate threads hanging due to kernel-mode code, but the system may crash or freeze because + kernel-mode code is not given the chance to release any resources. Use this option with + extreme caution.
+ +
M1
+
Uses WriteProcessMemory to write random data to the process' memory, crashing the process.
+ +
M2
+
Uses VirtualProtectEx to prevent the process' pages from being used, crashing the process.
+
+ + +

Process Properties

+
+
General
+
Displays basic information about the process and its image file. You can also view the + process' PEB contents, view/change its DEP status (requires Windows XP SP3 or higher, and + changing DEP status uses remote thread injection), and protect/unprotect it (requires + Windows Vista).
+ +
Statistics
+
Displays statistics and performance information.
+ +
Performance
+
Displays three graphs relating to the process' performance - CPU Usage, + Memory Usage, and I/O activity. You can hover your mouse over the graphs to view details.
+ +
Threads
+
Displays the process' threads, including their symbolic start addresses. You can click on + a thread to view more information, or double-click a thread to view its call stack.
+ +
Token
+
Displays the process' primary token. On Windows Vista with UAC enabled, you can also + click on the Linked Token... button to view the token associated with + the process' token. You can also enable and disable privileges.
+ +
Modules
+
Displays the modules loaded by the process. Right-click a module for more options.
+ +
Memory
+
Displays the process' virtual memory regions. Double-click a memory region to + read/write its contents, and right-click a memory region to perform other actions. You can + also search memory using the search button (see below).
+ +
Environment
+
Displays the process' environment variables.
+ +
Handles
+
Displays the process' handles - resources it has opened. You can right-click a handle and + close it.
+ +
Services
+
Displays services that are registered in the process.
+
+ +

Searching Memory

+

Process Hacker supports searching using a literal string or regular expressions. To + perform a search, open a Properties window for a process, select the Memory + tab and select an option in the search button. A window will appear in which you can + enter the data to search for. You can also control the types of memory regions to search.

+ +
+
Literal Search
+
Allows you to enter a sequence of bytes to search for.
+ +
Regex Search
+
Allows you to search using regular expressions.
+ +
String Scan
+
Scans for strings inside the process' memory.
+ +
Heap Scan
+
Displays a list of heap blocks.
+ +
Struct Search
+
Allows you to search for addresses which match the selected struct.
+
+ +

In the Literal tab, there is a small button in the bottom-right + which allows you to insert data in various formats.

+ +
+
Insert Number
+
This allows you to insert numbers in various formats - 8 to 64-bit, little or big endian.
+ +
Insert String
+
Similarly, this allows you to insert strings in various encodings - ASCII, UTF-8 to UTF-32. + If a multiline item is selected, the prompt box will have a multiline textbox.
+
+ +

In the search results list, double-clicking an item will open the Memory Editor with + the search result highlighted.

+ +

Sample Regex Searches

+

All of these samples must have Ignore Case selected.

+ +

A valid filesystem character is [ a-z0-9`~';!@#\$%\^&\-_=+\,\.\(\)\[\]\{\}] + +

+
Email address
+
[a-z0-9_\-\.]+@[a-z0-9_\-\.]+\.(au|biz|ca|com|info|net|org|uk|zh)
+ +
Path name
+
[A-Z]:\\([ a-z0-9`~'!@#\$%\^&\-_=+\,\.\(\)\[\]\{\}]*\\)*([ a-z0-9`~'!@#\$%\^&\-_=+\,\.\(\)\[\]\{\}]*)(\\)*
+ +
Executable file
+
([ a-z0-9`~'!@#\$%\^&\-_=+\,\.\(\)\[\]\{\}])+\.(bat|com|dll|exe)
+ +
URL
+
(file|ftp|http):///*[a-z0-9%\/ .\-_:\(\)\[\]]+
+
+ +

Results Window

+

The Results Window is displayed when searching for data, scanning for strings or + scanning for heaps. There are five buttons at the top of the window:

+ +
+
Refresh
+
This performs the search again.
+ +
Edit Search
+
This allows you to edit the search type and data associated with the Results Window.
+ +
Filter
+
This allows you to filter the search results, creating a new Results Window containing + the matching items. To filter using a numerical relation, enter the relation (for example, + greater than or equal to >=) followed by the number. If the filter + (>=10) is applied to the Length column, all items with a + length greater than or equal 10 will be displayed.
+ +
Intersect
+
This allows you to select another Results Window. It then creates a third Results Window + in which the search results present in both Results Windows are displayed. This allows you + to filter search results.
+ +
Save...
+
This allows you to save the search results to a text file.
+
+ +

Glossary

+
+
Affinity
+
The set of processors on which a thread or collection of threads (process) is allowed to + execute on.
+
Child Process
+
A new process started by an existing one.
+
Command Line
+
A string describing a program to start and any parameters to pass to it. Examples: + C:\Windows\notepad.exe C:\Windows\win.ini, cmd /TF0
+
Commit
+
A committed page or memory region contains actual data. Compare with reserve.
+
Context Switch
+
The act of switching a processor to run another thread. Since processors can only run one task + at a time, context switching gives the illusion of multi-tasking.
+
Data Execution Prevention
+
The Windows implementation of NX (No eXecute) technology, designed to prevent the execution of data + regions as code. This can prevent certain types of software attacks.
+
Elevation (UAC)
+
Under UAC, a process which is elevated has full administrative rights to system resources.
+
Environment Variable
+
A variable accessible to processes describing the operating system environment. Environment variables + are normally inherited by child processes.
+
Handle
+
A reference to a shared operating object or resource, e.g. a handle to an event, file or process.
+
Heap
+
A process-managed structure from which memory can be allocated. Since pages can only be + allocated in large chunks, using a heap will reduce wastage of memory for small allocations.
+
Image
+
A "package" containing executable code.
+
Interrupt
+
An event, usually signaled by hardware, that is handled by the operating system through a + interrupt handler.
+
Kernel
+
A collection of code that manages system-wide resources such as I/O, processes and threads, and + security. System calls are also handled by the kernel.
+
Kernel-mode
+
A processor mode in which code can access hardware directly and access all memory. For example, when + a system call is made, the processor switches to kernel-mode in order to perform an action on + the requester's behalf. When the system call finishes, it switches back to user-mode and the requester + continues normal execution.
+
Kernel-mode thread
+
A thread that runs solely in kernel-mode. These are usually worker threads that carry out delayed + operating system tasks. Most kernel-mode threads are contained in the System process, but in some systems + csrss.exe also runs kernel-mode threads.
+
LPC
+
Local inter-Process Communication (or Local Procedure Call). A Windows NT mechanism which enables + processes to communicate with each other.
+
LUID
+
Locally Unique IDentifier. A value which is unique on the local system until it is rebooted.
+
Module
+
An executable image which can be loaded by processes. Through this mechanism, code and resources + may be shared.
+
Page
+
A block of memory, 4 kB in size on x86 and AMD64 processors.
+
PEB
+
Process Environment Block. The PEB contains a variety of data used by the process.
+
Privilege
+
A privilege belonging to a process. It can be enabled or disabled, and certain system calls require + the presence of specific privileges to work.
+
Process
+
A collection of threads along with virtual memory, handles and other resources.
+
Protection (DRM)
+
Process and thread protection introduced in Windows Vista, designed to enhance support for digital + restrictions management. Examples of processes protected by this mechanism include System and audiodg.exe.
+
Reserve
+
A reserved page or memory region does not contain data and has not been allocated storage in physical + memory. Reserving pages is commonly done to ensure a certain amount of contiguous address space is available + without actually allocating storage. Compare with commit.
+
Service
+
A operating system managed program which runs in the background. They can be in shared processes + (in svchost.exe instances), in separate processes, or drivers loaded into kernel-mode space.
+
SID
+
Security IDentifier. A unique identifier assigned to security-related objects such as users and groups.
+
String
+
A sequence of characters - text.
+
System Call
+
A request that is made by a thread to the kernel to perform a task on the thread's behalf. This done + because most threads run in user-mode and are unable to access hardware directly. See kernel-mode.
+
System Thread
+
See kernel-mode thread.
+
Thread
+
A unit of execution belonging to a process, running code concurrently. Most threads run in user-mode, + but some are kernel-mode threads.
+
User Account Control
+
Refers to restrictions on normal processes preventing them from modifying system-wide files and settings. + Processes which are elevated have full administrative access to system resources.
+
Virtualization (UAC)
+
A technology which redirects writes to the file system and registry for processes which are not + elevated.
+
Working set
+
The collection of pages recently referenced by a process. These pages are in physical + memory, while other pages may be in the pagefile.
+
WOW64
+
A technology which enables 32-bit programs to run on 64-bit Windows systems.
+
+ +

Copyright Information

+

Process Hacker

+
+      Process Hacker
+
+      Copyright (C) 2008-2009 various authors (see README.txt for the full list)
+
+      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 <http://www.gnu.org/licenses/>.
+ +

HexBox

+

Process Hacker uses the HexBox component by Bernhard Elbl, licensed under the + Microsoft Public License:

+
This license governs use of the accompanying software. If you use the software, you
+accept this license. If you do not accept the license, do not use the software.
+
+1. Definitions
+The terms "reproduce," "reproduction," "derivative works," and "distribution" have the
+same meaning here as under U.S. copyright law.
+A "contribution" is the original software, or any additions or changes to the software.
+A "contributor" is any person that distributes its contribution under this license.
+"Licensed patents" are a contributor's patent claims that read directly on its contribution.
+
+2. Grant of Rights
+(A) Copyright Grant- Subject to the terms of this license, including the license conditions 
+    and limitations in section 3, each contributor grants you a non-exclusive, worldwide, 
+    royalty-free copyright license to reproduce its contribution, prepare derivative works 
+    of its contribution, and distribute its contribution or any derivative works that you 
+    create.
+(B) Patent Grant- Subject to the terms of this license, including the license conditions 
+    and limitations in section 3, each contributor grants you a non-exclusive, worldwide, 
+    royalty-free license under its licensed patents to make, have made, use, sell, offer 
+    for sale, import, and/or otherwise dispose of its contribution in the software or 
+    derivative works of the contribution in the software.
+
+3. Conditions and Limitations
+(A) No Trademark License- This license does not grant you rights to use any contributors' 
+    name, logo, or trademarks.
+(B) If you bring a patent claim against any contributor over patents that you claim are 
+    infringed by the software, your patent license from such contributor to the software 
+    ends automatically.
+(C) If you distribute any portion of the software, you must retain all copyright, patent, 
+    trademark, and attribution notices that are present in the software.
+(D) If you distribute any portion of the software in source code form, you may do so only 
+    under this license by including a complete copy of this license with your distribution. 
+    If you distribute any portion of the software in compiled or object code form, you may 
+    only do so under a license that complies with this license.
+(E) The software is licensed "as-is." You bear the risk of using it. The contributors give 
+    no express warranties, guarantees or conditions. You may have additional consumer rights 
+    under your local laws which this license cannot change. To the extent permitted under your 
+    local laws, the contributors exclude the implied warranties of merchantability, fitness for 
+    a particular purpose and non-infringement.
+ +

VistaMenu and SplitButton

+

Process Hacker uses the VistaMenu and SplitButton components by Wyatt O'Day, licensed under + the following terms:

+
Copyright (c) 2008, wyDay
+All rights reserved.
+
+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.
+
+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.
+ +

LINQBridge

+

Process Hacker uses the LINQBridge component by Joseph Albahari, licensed under the + following terms:

+
LINQBridge Copyright (c) 2007-2008 Joseph Albahari
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+ + diff --git a/branches/ph-plugins/ProcessHacker/Icons/ApplicationXP.ico b/branches/ph-plugins/ProcessHacker/Icons/ApplicationXP.ico new file mode 100644 index 000000000..ef5b8345d Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Icons/ApplicationXP.ico differ diff --git a/branches/ph-plugins/ProcessHacker/Icons/Bricks.ico b/branches/ph-plugins/ProcessHacker/Icons/Bricks.ico new file mode 100644 index 000000000..8ccffe079 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Icons/Bricks.ico differ diff --git a/branches/ph-plugins/ProcessHacker/Icons/CogGo.ico b/branches/ph-plugins/ProcessHacker/Icons/CogGo.ico new file mode 100644 index 000000000..335384a70 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Icons/CogGo.ico differ diff --git a/branches/ph-plugins/ProcessHacker/Icons/Help.ico b/branches/ph-plugins/ProcessHacker/Icons/Help.ico new file mode 100644 index 000000000..4b70c517c Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Icons/Help.ico differ diff --git a/branches/ph-plugins/ProcessHacker/Icons/Keyboard.ico b/branches/ph-plugins/ProcessHacker/Icons/Keyboard.ico new file mode 100644 index 000000000..5533d8b16 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Icons/Keyboard.ico differ diff --git a/branches/ph-plugins/ProcessHacker/Icons/PageEdit.ico b/branches/ph-plugins/ProcessHacker/Icons/PageEdit.ico new file mode 100644 index 000000000..74fb351b2 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Icons/PageEdit.ico differ diff --git a/branches/ph-plugins/ProcessHacker/Icons/Process.ico b/branches/ph-plugins/ProcessHacker/Icons/Process.ico new file mode 100644 index 000000000..d7f44e87a Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Icons/Process.ico differ diff --git a/branches/ph-plugins/ProcessHacker/Icons/ProcessHacker.ico b/branches/ph-plugins/ProcessHacker/Icons/ProcessHacker.ico new file mode 100644 index 000000000..583aad022 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Icons/ProcessHacker.ico differ diff --git a/branches/ph-plugins/ProcessHacker/Icons/ProcessHacker.png b/branches/ph-plugins/ProcessHacker/Icons/ProcessHacker.png new file mode 100644 index 000000000..73f282b4c Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Icons/ProcessHacker.png differ diff --git a/branches/ph-plugins/ProcessHacker/Icons/ProcessHacker_small.ico b/branches/ph-plugins/ProcessHacker/Icons/ProcessHacker_small.ico new file mode 100644 index 000000000..63d723f44 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Icons/ProcessHacker_small.ico differ diff --git a/branches/ph-plugins/ProcessHacker/Icons/Process_small.ico b/branches/ph-plugins/ProcessHacker/Icons/Process_small.ico new file mode 100644 index 000000000..f7ddee3ea Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Icons/Process_small.ico differ diff --git a/branches/ph-plugins/ProcessHacker/Icons/Table.ico b/branches/ph-plugins/ProcessHacker/Icons/Table.ico new file mode 100644 index 000000000..571329c41 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Icons/Table.ico differ diff --git a/branches/ph-plugins/ProcessHacker/Icons/Terminal.ico b/branches/ph-plugins/ProcessHacker/Icons/Terminal.ico new file mode 100644 index 000000000..4de3c2043 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Icons/Terminal.ico differ diff --git a/branches/ph-plugins/ProcessHacker/ProcessHacker.csproj b/branches/ph-plugins/ProcessHacker/ProcessHacker.csproj new file mode 100644 index 000000000..50bf8356c --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/ProcessHacker.csproj @@ -0,0 +1,1010 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {EEEA1778-1702-4964-8793-A98FE37E4D2B} + WinExe + Properties + ProcessHacker + ProcessHacker + v2.0 + 512 + ProcessHacker.ico + ProcessHacker.Program + app.manifest + OnBuildSuccess + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + true + AnyCPU + + + pdbonly + true + bin\Release\ + + + prompt + 4 + true + false + AnyCPU + + + + + + + + + + + + + + + + + + + + + + + Component + + + + + + Form + + + HelpWindow.cs + + + Form + + + HackerWindow.cs + + + + Form + + + PromptBox.cs + + + + HackerWindow.cs + Designer + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + True + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + Component + + + Component + + + + + + HexBox.cs + Designer + + + ColorModifier.cs + Designer + + + EventPairProperties.cs + + + EventProperties.cs + + + Indicator.cs + + + JobProperties.cs + + + MutantProperties.cs + + + NetworkList.cs + Designer + + + FileNameBox.cs + + + MemoryList.cs + Designer + + + ModuleList.cs + Designer + + + HandleList.cs + Designer + + + Plotter.cs + + + ProcessStatistics.cs + + + SectionProperties.cs + + + SemaphoreProperties.cs + + + ServiceList.cs + Designer + + + ServiceProperties.cs + Designer + + + StructViewer.cs + + + ThreadList.cs + Designer + + + ProcessTree.cs + Designer + + + TimerProperties.cs + + + TmRmProperties.cs + + + TmTmProperties.cs + + + TokenGroupsList.cs + Designer + + + TokenProperties.cs + Designer + + + UtilitiesButton.cs + Designer + + + VerticleProgressBar.cs + + + VistaSearchBox.cs + + + AboutWindow.cs + Designer + + + ChooseColumnsWindow.cs + + + ComboBoxPickerWindow.cs + + + CreateServiceWindow.cs + + + HandleStatisticsWindow.cs + + + HeapsWindow.cs + + + HiddenProcessesWindow.cs + + + EditDEPWindow.cs + + + GetProcAddressWindow.cs + Designer + + + IPInfoWindow.cs + + + JobWindow.cs + + + ListPickerWindow.cs + + + ListWindow.cs + Designer + + + LogWindow.cs + + + MessageBoxWindow.cs + + + MiniSysInfo.cs + + + ProcessPickerWindow.cs + + + ProcessWindow.cs + Designer + + + ProtectProcessWindow.cs + + + ScratchpadWindow.cs + + + SessionInformationWindow.cs + + + StructWindow.cs + + + SysInfoWindow.cs + + + TerminatorWindow.cs + + + TokenWindow.cs + Designer + + + ProcessAffinity.cs + Designer + + + ErrorDialog.cs + Designer + + + HandleFilterWindow.cs + Designer + + + HelpWindow.cs + Designer + + + MemoryEditor.cs + Designer + + + OptionsWindow.cs + Designer + + + InformationBox.cs + Designer + + + PEWindow.cs + Designer + + + PromptBox.cs + Designer + + + ResultsWindow.cs + Designer + + + RunWindow.cs + Designer + + + SearchWindow.cs + Designer + + + ServiceWindow.cs + Designer + + + ThreadWindow.cs + Designer + + + VirtualProtectWindow.cs + Designer + + + VirusTotalUploaderWindow.cs + + + Form + Always + + + UpdaterDownloadWindow.cs + + + NetInfoWindow.cs + + + WaitChainWindow.cs + + + + + + + + + + + + + + + + UserControl + + + EventPairProperties.cs + + + UserControl + + + EventProperties.cs + + + Component + + + UserControl + + + Indicator.cs + + + UserControl + + + MutantProperties.cs + + + UserControl + + + ProcessStatistics.cs + + + UserControl + + + SectionProperties.cs + + + UserControl + + + SemaphoreProperties.cs + + + Component + + + + + + + + + + UserControl + + + TimerProperties.cs + + + UserControl + + + TmRmProperties.cs + + + UserControl + + + TmTmProperties.cs + + + Component + + + VistaSearchBox.cs + + + Component + + + Form + + + CreateServiceWindow.cs + + + Form + + + HandleStatisticsWindow.cs + + + Form + + + HeapsWindow.cs + + + Form + + + IPInfoWindow.cs + + + Form + + + JobWindow.cs + + + Form + + + MessageBoxWindow.cs + + + Form + + + ProtectProcessWindow.cs + + + Form + + + ScratchpadWindow.cs + + + Form + + + SessionInformationWindow.cs + + + Form + + + VirusTotalUploaderWindow.cs + + + Form + + + NetInfoWindow.cs + + + + + Form + + + UpdaterDownloadWindow.cs + + + + + + + + + + + + + + + UserControl + + + ColorModifier.cs + + + UserControl + + + JobProperties.cs + + + UserControl + + + NetworkList.cs + + + UserControl + + + FileNameBox.cs + + + UserControl + + + MemoryList.cs + + + UserControl + + + ModuleList.cs + + + UserControl + + + HandleList.cs + + + Component + + + + + + UserControl + + + ServiceList.cs + + + UserControl + + + Plotter.cs + + + UserControl + + + ServiceProperties.cs + + + UserControl + + + StructViewer.cs + + + + + Component + + + + + UserControl + + + ThreadList.cs + + + UserControl + + + ProcessTree.cs + + + UserControl + + + TokenGroupsList.cs + + + UserControl + + + TokenProperties.cs + + + UserControl + + + VerticleProgressBar.cs + + + + Code + + + Code + + + Form + + + ChooseColumnsWindow.cs + + + Form + + + ComboBoxPickerWindow.cs + + + Form + + + HiddenProcessesWindow.cs + + + Form + + + EditDEPWindow.cs + + + Form + + + GetProcAddressWindow.cs + + + Form + + + ListPickerWindow.cs + + + Form + + + ListWindow.cs + + + Form + + + LogWindow.cs + + + Form + + + MiniSysInfo.cs + + + Form + + + ProcessPickerWindow.cs + + + Form + + + ProcessWindow.cs + + + Form + + + StructWindow.cs + + + Form + + + SysInfoWindow.cs + + + Form + + + TerminatorWindow.cs + + + Form + + + TokenWindow.cs + + + Form + + + ProcessAffinity.cs + + + Form + + + ErrorDialog.cs + + + Form + + + HandleFilterWindow.cs + + + Form + + + PEWindow.cs + + + Form + + + RunWindow.cs + + + Form + + + ServiceWindow.cs + + + Form + + + VirtualProtectWindow.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Component + + + UserControl + + + UtilitiesButton.cs + + + Form + + + MemoryEditor.cs + + + Form + + + ResultsWindow.cs + + + Form + + + SearchWindow.cs + + + Form + + + ThreadWindow.cs + + + + + + + + + + + + + Form + + + AboutWindow.cs + + + Form + + + OptionsWindow.cs + + + Form + + + InformationBox.cs + + + + + + + + + + Form + + + WaitChainWindow.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Always + + + + + + + + + + + + + + + + + + Always + + + + + + + + + + + + + + + + {8E10F5E8-D4FA-4980-BB23-2EDD134AC15E} + ProcessHacker.Common + + + {8A448157-E1A7-4DDF-954E-287F1117832B} + ProcessHacker.Native + + + {E73BB233-D88B-44A7-A98F-D71EE158381D} + Aga.Controls + + + + + + if $(ConfigurationName)==Release "$(SolutionDir)\ProcessHacker\Build\release.cmd" "$(SolutionDir)\ProcessHacker\$(OutDir)" + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/ProcessHacker.ico b/branches/ph-plugins/ProcessHacker/ProcessHacker.ico new file mode 100644 index 000000000..5225637d7 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/ProcessHacker.ico differ diff --git a/branches/ph-plugins/ProcessHacker/Program/ExtendedCmd.cs b/branches/ph-plugins/ProcessHacker/Program/ExtendedCmd.cs new file mode 100644 index 000000000..c625e2029 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Program/ExtendedCmd.cs @@ -0,0 +1,329 @@ +/* + * Process Hacker - + * extended command line options + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; +using ProcessHacker.UI; +using ProcessHacker.UI.Actions; + +namespace ProcessHacker +{ + public static class ExtendedCmd + { + public static void Run(IDictionary args) + { + try + { + ThemingScope.Activate(); + } + catch + { } + + if (!args.ContainsKey("-type")) + throw new Exception("-type switch required."); + + string type = args["-type"].ToLower(); + + if (!args.ContainsKey("-obj")) + throw new Exception("-obj switch required."); + + string obj = args["-obj"]; + + if (!args.ContainsKey("-action")) + throw new Exception("-action switch required."); + + string action = args["-action"].ToLower(); + + WindowFromHandle window = new WindowFromHandle(IntPtr.Zero); + + if (args.ContainsKey("-hwnd")) + window = new WindowFromHandle(new IntPtr(int.Parse(args["-hwnd"]))); + + try + { + switch (type) + { + case "processhacker": + { + switch (action) + { + case "runas": + { + using (var manager = new ServiceManagerHandle(ScManagerAccess.CreateService)) + { + Random r = new Random((int)(DateTime.Now.ToFileTime() & 0xffffffff)); + string serviceName = ""; + + for (int i = 0; i < 8; i++) + serviceName += (char)('A' + r.Next(25)); + + using (var service = manager.CreateService( + serviceName, + serviceName + " (Process Hacker Assistant)", + ServiceType.Win32OwnProcess, + ServiceStartType.DemandStart, + ServiceErrorControl.Ignore, + obj, + "", + "LocalSystem", + null)) + { + // Create a mailslot so we can receive the error code for Assistant. + using (var mhandle = MailslotHandle.Create( + FileAccess.GenericRead, @"\Device\Mailslot\" + args["-mailslot"], 0, 5000) + ) + { + try { service.Start(); } + catch { } + service.Delete(); + + Win32Error errorCode = (Win32Error)mhandle.Read(4).ToInt32(); + + if (errorCode != Win32Error.Success) + throw new WindowsException(errorCode); + } + } + } + } + break; + default: + throw new Exception("Unknown action '" + action + "'"); + } + } + break; + + case "process": + { + var processes = Windows.GetProcesses(); + string[] pidStrings = obj.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + int[] pids = new int[pidStrings.Length]; + string[] names = new string[pidStrings.Length]; + + for (int i = 0; i < pidStrings.Length; i++) + { + pids[i] = int.Parse(pidStrings[i]); + names[i] = processes[pids[i]].Name; + } + + switch (action) + { + case "terminate": + ProcessActions.Terminate(window, pids, names, true); + break; + case "suspend": + ProcessActions.Suspend(window, pids, names, true); + break; + case "resume": + ProcessActions.Resume(window, pids, names, true); + break; + case "reduceworkingset": + ProcessActions.ReduceWorkingSet(window, pids, names, false); + break; + default: + throw new Exception("Unknown action '" + action + "'"); + } + } + break; + + case "thread": + { + foreach (string tid in obj.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) + { + switch (action) + { + case "terminate": + { + try + { + using (var thandle = + new ThreadHandle(int.Parse(tid), ThreadAccess.Terminate)) + thandle.Terminate(); + } + catch (Exception ex) + { + DialogResult result = MessageBox.Show(window, + "Could not terminate thread with ID " + tid + ":\n\n" + + ex.Message, "Process Hacker", MessageBoxButtons.OKCancel, MessageBoxIcon.Error); + + if (result == DialogResult.Cancel) + return; + } + } + break; + case "suspend": + { + try + { + using (var thandle = + new ThreadHandle(int.Parse(tid), ThreadAccess.SuspendResume)) + thandle.Suspend(); + } + catch (Exception ex) + { + DialogResult result = MessageBox.Show(window, + "Could not suspend thread with ID " + tid + ":\n\n" + + ex.Message, "Process Hacker", MessageBoxButtons.OKCancel, MessageBoxIcon.Error); + + if (result == DialogResult.Cancel) + return; + } + } + break; + case "resume": + { + try + { + using (var thandle = + new ThreadHandle(int.Parse(tid), ThreadAccess.SuspendResume)) + thandle.Resume(); + } + catch (Exception ex) + { + DialogResult result = MessageBox.Show(window, + "Could not resume thread with ID " + tid + ":\n\n" + + ex.Message, "Process Hacker", MessageBoxButtons.OKCancel, MessageBoxIcon.Error); + + if (result == DialogResult.Cancel) + return; + } + } + break; + default: + throw new Exception("Unknown action '" + action + "'"); + } + } + } + break; + + case "service": + { + switch (action) + { + case "start": + { + ServiceActions.Start(window, obj, false); + } + break; + case "continue": + { + ServiceActions.Continue(window, obj, false); + } + break; + case "pause": + { + ServiceActions.Pause(window, obj, false); + } + break; + case "stop": + { + ServiceActions.Stop(window, obj, false); + } + break; + case "delete": + { + ServiceActions.Delete(window, obj, true); + } + break; + case "config": + { + using (ServiceHandle service = new ServiceHandle(obj, ServiceAccess.ChangeConfig)) + { + ServiceType serviceType; + + if (args["-servicetype"] == "Win32OwnProcess, InteractiveProcess") + serviceType = ServiceType.Win32OwnProcess | ServiceType.InteractiveProcess; + else if (args["-servicetype"] == "Win32ShareProcess, InteractiveProcess") + serviceType = ServiceType.Win32ShareProcess | ServiceType.InteractiveProcess; + else + serviceType = (ServiceType)Enum.Parse(typeof(ServiceType), args["-servicetype"]); + + var startType = (ServiceStartType) + Enum.Parse(typeof(ServiceStartType), args["-servicestarttype"]); + var errorControl = (ServiceErrorControl) + Enum.Parse(typeof(ServiceErrorControl), args["-serviceerrorcontrol"]); + + string binaryPath = null; + string loadOrderGroup = null; + string userAccount = null; + string password = null; + + if (args.ContainsKey("-servicebinarypath")) + binaryPath = args["-servicebinarypath"]; + if (args.ContainsKey("-serviceloadordergroup")) + loadOrderGroup = args["-serviceloadordergroup"]; + if (args.ContainsKey("-serviceuseraccount")) + userAccount = args["-serviceuseraccount"]; + if (args.ContainsKey("-servicepassword")) + password = args["-servicepassword"]; + + if (!Win32.ChangeServiceConfig(service, + serviceType, startType, errorControl, + binaryPath, loadOrderGroup, IntPtr.Zero, null, userAccount, password, null)) + Win32.ThrowLastError(); + } + } + break; + default: + throw new Exception("Unknown action '" + action + "'"); + } + } + break; + + case "session": + { + int sessionId = int.Parse(obj); + + switch (action) + { + case "disconnect": + { + SessionActions.Disconnect(window, sessionId, false); + } + break; + case "logoff": + { + SessionActions.Logoff(window, sessionId, false); + } + break; + default: + throw new Exception("Unknown action '" + action + "'"); + } + } + break; + + default: + throw new Exception("Unknown object type '" + type + "'"); + } + } + catch (Exception ex) + { + MessageBox.Show(window, ex.Message, "Process Hacker", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Program/Program.cs b/branches/ph-plugins/ProcessHacker/Program/Program.cs new file mode 100644 index 000000000..0db16d57d --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Program/Program.cs @@ -0,0 +1,1405 @@ +/* + * Process Hacker - + * static variables and user interface thread management + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Security.Principal; +using System.Text; +using System.Threading; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Common.Objects; +using ProcessHacker.Components; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; +using ProcessHacker.UI; + +namespace ProcessHacker +{ + public static class Program + { + /// + /// The main Process Hacker window instance. + /// + public static HackerWindow HackerWindow; + public static IntPtr HackerWindowHandle; + public static bool HackerWindowTopMost; + + public static ProcessAccess MinProcessQueryRights = ProcessAccess.QueryInformation; + public static ProcessAccess MinProcessReadMemoryRights = ProcessAccess.VmRead; + public static ProcessAccess MinProcessWriteMemoryRights = ProcessAccess.VmWrite | ProcessAccess.VmOperation; + public static ProcessAccess MinProcessGetHandleInformationRights = ProcessAccess.DupHandle; + public static ThreadAccess MinThreadQueryRights = ThreadAccess.QueryInformation; + + public static int CurrentProcessId; + public static int CurrentSessionId; + public static string CurrentUsername; + + /// + /// The Results Window ID Generator + /// + public static IdGenerator ResultsIds = new IdGenerator() { Sort = true }; + + public static Dictionary Structs = new Dictionary(); + + public static bool MemoryEditorsThreaded = true; + public static Dictionary MemoryEditors = new Dictionary(); + public static Dictionary MemoryEditorsThreads = new Dictionary(); + + public static bool ResultsWindowsThreaded = true; + public static Dictionary ResultsWindows = new Dictionary(); + public static Dictionary ResultsThreads = new Dictionary(); + + public static bool PEWindowsThreaded = false; + public static Dictionary PEWindows = new Dictionary(); + public static Dictionary PEThreads = new Dictionary(); + + public static bool PWindowsThreaded = true; + public static Dictionary PWindows = new Dictionary(); + public static Dictionary PThreads = new Dictionary(); + + public delegate void ResultsWindowInvokeAction(ResultsWindow f); + public delegate void MemoryEditorInvokeAction(MemoryEditor f); + public delegate void ThreadWindowInvokeAction(ThreadWindow f); + public delegate void PEWindowInvokeAction(PEWindow f); + public delegate void PWindowInvokeAction(ProcessWindow f); + public delegate void UpdateWindowAction(Form f); + + public static ProcessSystemProvider ProcessProvider; + public static ServiceProvider ServiceProvider; + public static NetworkProvider NetworkProvider; + + public static bool BadConfig = false; + public static TokenElevationType ElevationType; + public static ProcessHacker.Native.Threading.Mutant GlobalMutex; + public static string GlobalMutexName = @"\BaseNamedObjects\ProcessHackerMutex"; + public static System.Collections.Specialized.StringCollection ImposterNames = + new System.Collections.Specialized.StringCollection(); + public static int InspectPid = -1; + public static bool NoKph = false; + public static string SelectTab = "Processes"; + public static bool StartHidden = false; + public static bool StartVisible = false; + public static SharedThreadProvider SecondarySharedThreadProvider; + public static SharedThreadProvider SharedThreadProvider; + public static ProcessHacker.Native.Threading.Waiter SharedWaiter; + + private static object CollectWorkerThreadsLock = new object(); + + /// + /// The main entry point for the application. + /// + [STAThread] + public static void Main(string[] args) + { + Dictionary pArgs = null; + + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + + if (Environment.Version.Major < 2) + { + PhUtils.ShowError("You must have .NET Framework 2.0 or higher to use Process Hacker."); + Environment.Exit(1); + } + +#if !DEBUG + // Setup exception handling at first opportunity to catch exceptions generatable anywhere. + Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException); + AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException); + Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException, true); + +#endif + try + { + pArgs = ParseArgs(args); + } + catch + { + ShowCommandLineUsage(); + pArgs = new Dictionary(); + } + + if (pArgs.ContainsKey("-h") || pArgs.ContainsKey("-help") || pArgs.ContainsKey("-?")) + { + ShowCommandLineUsage(); + return; + } + + if (pArgs.ContainsKey("-recovered")) //used for Windows Error Reporting recovery + { + ProcessHackerRestartRecovery.ApplicationRestartRecoveryManager.RecoverLastSession(); + } + + if (pArgs.ContainsKey("-elevate")) + { + StartProcessHackerAdmin(); + return; + } + + // In case the settings file is corrupt PH won't crash here - it will be dealt with later. + try + { + if (pArgs.ContainsKey("-nokph")) + NoKph = true; + if (Properties.Settings.Default.AllowOnlyOneInstance && + !(pArgs.ContainsKey("-e") || pArgs.ContainsKey("-o") || + pArgs.ContainsKey("-pw") || pArgs.ContainsKey("-pt")) + ) + CheckForPreviousInstance(); + } + catch + { } + + // Try to upgrade settings. + try + { + if (Properties.Settings.Default.NeedsUpgrade) + { + try + { + Properties.Settings.Default.Upgrade(); + } + catch (Exception ex) + { + Logging.Log(ex); + PhUtils.ShowWarning("Process Hacker could not upgrade its settings from a previous version."); + } + + Properties.Settings.Default.NeedsUpgrade = false; + } + } + catch + { } + + VerifySettings(); + + ThreadPool.SetMinThreads(1, 1); + ThreadPool.SetMaxThreads(2, 2); + WorkQueue.GlobalWorkQueue.MaxWorkerThreads = 3; + + // Create or open the Process Hacker mutex, used only by the installer. + try + { + GlobalMutex = new ProcessHacker.Native.Threading.Mutant(GlobalMutexName); + } + catch (Exception ex) + { + Logging.Log(ex); + } + + try + { + using (var thandle = ProcessHandle.GetCurrent().GetToken()) + { + try { thandle.SetPrivilege("SeDebugPrivilege", SePrivilegeAttributes.Enabled); } + catch { } + try { thandle.SetPrivilege("SeIncreaseBasePriorityPrivilege", SePrivilegeAttributes.Enabled); } + catch { } + try { thandle.SetPrivilege("SeLoadDriverPrivilege", SePrivilegeAttributes.Enabled); } + catch { } + try { thandle.SetPrivilege("SeRestorePrivilege", SePrivilegeAttributes.Enabled); } + catch { } + try { thandle.SetPrivilege("SeShutdownPrivilege", SePrivilegeAttributes.Enabled); } + catch { } + try { thandle.SetPrivilege("SeTakeOwnershipPrivilege", SePrivilegeAttributes.Enabled); } + catch { } + + if (OSVersion.HasUac) + { + try { ElevationType = thandle.GetElevationType(); } + catch { ElevationType = TokenElevationType.Full; } + + if (ElevationType == TokenElevationType.Default && + !(new WindowsPrincipal(WindowsIdentity.GetCurrent())). + IsInRole(WindowsBuiltInRole.Administrator)) + ElevationType = TokenElevationType.Limited; + else if (ElevationType == TokenElevationType.Default) + ElevationType = TokenElevationType.Full; + } + else + { + ElevationType = TokenElevationType.Full; + } + } + } + catch (Exception ex) + { + Logging.Log(ex); + } + + try + { + if ( + // Only load KPH if we're on 32-bit and it's enabled. + IntPtr.Size == 4 && + Properties.Settings.Default.EnableKPH && + !NoKph && + // Don't load KPH if we're going to install/uninstall it. + !pArgs.ContainsKey("-installkph") && !pArgs.ContainsKey("-uninstallkph") + ) + KProcessHacker.Instance = new KProcessHacker("KProcessHacker"); + } + catch + { } + + MinProcessQueryRights = OSVersion.MinProcessQueryInfoAccess; + MinThreadQueryRights = OSVersion.MinThreadQueryInfoAccess; + + if (KProcessHacker.Instance != null) + { + MinProcessGetHandleInformationRights = MinProcessQueryRights; + MinProcessReadMemoryRights = MinProcessQueryRights; + MinProcessWriteMemoryRights = MinProcessQueryRights; + } + + try + { + CurrentUsername = System.Security.Principal.WindowsIdentity.GetCurrent().Name; + } + catch (Exception ex) + { + Logging.Log(ex); + } + + try + { + CurrentProcessId = Win32.GetCurrentProcessId(); + CurrentSessionId = Win32.GetProcessSessionId(Win32.GetCurrentProcessId()); + System.Threading.Thread.CurrentThread.Priority = ThreadPriority.Highest; + } + catch (Exception ex) + { + Logging.Log(ex); + } + + if (ProcessCommandLine(pArgs)) + return; + + Win32.FileIconInit(true); + LoadProviders(); + Windows.GetProcessName = (pid) => + ProcessProvider.Dictionary.ContainsKey(pid) ? + ProcessProvider.Dictionary[pid].Name : + null; + + // Create the shared waiter. + SharedWaiter = new ProcessHacker.Native.Threading.Waiter(); + + new HackerWindow(); + Application.Run(); + } + + private static void ShowCommandLineUsage() + { + PhUtils.ShowInformation( + "Option: \tUsage:\n" + + "-a\tAggressive mode.\n" + + "-elevate\tStarts Process Hacker elevated.\n" + + "-h\tDisplays command line usage information.\n" + + "-installkph\tInstalls the KProcessHacker service.\n" + + "-ip pid\tDisplays the main window, then properties for the specified process.\n" + + "-m\tStarts Process Hacker hidden.\n" + + "-nokph\tDisables KProcessHacker. Use this if you encounter BSODs.\n" + + "-o\tShows Options.\n" + + "-pw pid\tDisplays properties for the specified process.\n" + + "-pt pid\tDisplays properties for the specified process' token.\n" + + "-t n\tShows the specified tab. 0 is Processes, 1 is Services and 2 is Network.\n" + + "-uninstallkph\tUninstalls the KProcessHacker service.\n" + + "-v\tStarts Process Hacker visible.\n" + + "" + ); + } + + private static void LoadProviders() + { + ProcessProvider = new ProcessSystemProvider(); + ServiceProvider = new ServiceProvider(); + NetworkProvider = new NetworkProvider(); + Program.SharedThreadProvider = + new SharedThreadProvider(Properties.Settings.Default.RefreshInterval); + Program.SharedThreadProvider.Add(ProcessProvider); + Program.SharedThreadProvider.Add(ServiceProvider); + Program.SharedThreadProvider.Add(NetworkProvider); + Program.SecondarySharedThreadProvider = + new SharedThreadProvider(Properties.Settings.Default.RefreshInterval); + } + + private static void DeleteSettings() + { + if (System.IO.Directory.Exists(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + + "\\wj32")) + System.IO.Directory.Delete(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + + "\\wj32", true); + if (System.IO.Directory.Exists(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + + "\\wj32")) + System.IO.Directory.Delete(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + + "\\wj32", true); + } + + private static void VerifySettings() + { + // Try to get a setting. If the file is corrupt, we can reset the settings. + try + { + var a = Properties.Settings.Default.AlwaysOnTop; + } + catch (Exception ex) + { + Logging.Log(ex); + + try { ThemingScope.Activate(); } + catch { } + + BadConfig = true; + + if (OSVersion.HasTaskDialogs) + { + TaskDialog td = new TaskDialog(); + + td.WindowTitle = "Process Hacker"; + td.MainInstruction = "Process Hacker could not initialize the configuration manager"; + td.Content = "The Process Hacker configuration file is corrupt or the configuration manager " + + "could not be initialized. Do you want Process Hacker to reset your settings?"; + td.MainIcon = TaskDialogIcon.Warning; + td.CommonButtons = TaskDialogCommonButtons.Cancel; + td.Buttons = new TaskDialogButton[] + { + new TaskDialogButton((int)DialogResult.Yes, "Yes, reset the settings and restart Process Hacker"), + new TaskDialogButton((int)DialogResult.No, "No, attempt to start Process Hacker anyway"), + new TaskDialogButton((int)DialogResult.Retry, "Show me the error message") + }; + td.UseCommandLinks = true; + td.Callback = (taskDialog, args, userData) => + { + if (args.Notification == TaskDialogNotification.ButtonClicked) + { + if (args.ButtonId == (int)DialogResult.Yes) + { + taskDialog.SetMarqueeProgressBar(true); + taskDialog.SetProgressBarMarquee(true, 1000); + + try + { + DeleteSettings(); + System.Diagnostics.Process.Start(Application.ExecutablePath); + } + catch (Exception ex2) + { + taskDialog.SetProgressBarMarquee(false, 1000); + PhUtils.ShowException("Unable to reset the settings", ex2); + return true; + } + + return false; + } + else if (args.ButtonId == (int)DialogResult.Retry) + { + InformationBox box = new InformationBox(ex.ToString()); + + box.ShowDialog(); + + return true; + } + } + + return false; + }; + + int result = td.Show(); + + if (result == (int)DialogResult.No) + { + return; + } + } + else + { + if (MessageBox.Show("Process Hacker cannot start because your configuration file is corrupt. " + + "Do you want Process Hacker to reset your settings?", "Process Hacker", MessageBoxButtons.YesNo, + MessageBoxIcon.Exclamation) == DialogResult.Yes) + { + try + { + DeleteSettings(); + MessageBox.Show("Process Hacker has reset your settings and will now restart.", "Process Hacker", + MessageBoxButtons.OK, MessageBoxIcon.Information); + System.Diagnostics.Process.Start(Application.ExecutablePath); + } + catch (Exception ex2) + { + Logging.Log(ex2); + + MessageBox.Show("Process Hacker could not reset your settings. Please delete the folder " + + "'wj32' in your Application Data/Local Application Data directories.", + "Process Hacker", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + } + } + + Win32.ExitProcess(0); + } + } + + private static bool ProcessCommandLine(Dictionary pArgs) + { + if (pArgs.ContainsKey("-e")) + { + try + { + ExtendedCmd.Run(pArgs); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to complete the operation", ex); + } + + return true; + } + + if (pArgs.ContainsKey("-installkph")) + { + try + { + using (var scm = new ServiceManagerHandle(ScManagerAccess.CreateService)) + { + using (var shandle = scm.CreateService( + "KProcessHacker", + "KProcessHacker", + ServiceType.KernelDriver, + ServiceStartType.SystemStart, + ServiceErrorControl.Ignore, + Application.StartupPath + "\\kprocesshacker.sys", + null, + null, + null + )) + { + shandle.Start(); + } + } + } + catch (WindowsException ex) + { + // Need to pass status back. + Environment.Exit((int)ex.ErrorCode); + } + + return true; + } + + if (pArgs.ContainsKey("-uninstallkph")) + { + try + { + using (var shandle = new ServiceHandle("KProcessHacker", ServiceAccess.Stop | (ServiceAccess)StandardRights.Delete)) + { + try { shandle.Control(ServiceControl.Stop); } + catch { } + + shandle.Delete(); + } + } + catch (WindowsException ex) + { + // Need to pass status back. + Environment.Exit((int)ex.ErrorCode); + } + + return true; + } + + if (pArgs.ContainsKey("-ip")) + InspectPid = int.Parse(pArgs["-ip"]); + + if (pArgs.ContainsKey("-pw")) + { + int pid = int.Parse(pArgs["-pw"]); + + SharedThreadProvider = new SharedThreadProvider(Properties.Settings.Default.RefreshInterval); + SecondarySharedThreadProvider = new SharedThreadProvider(Properties.Settings.Default.RefreshInterval); + + ProcessProvider = new ProcessSystemProvider(); + ServiceProvider = new ServiceProvider(); + SharedThreadProvider.Add(ProcessProvider); + SharedThreadProvider.Add(ServiceProvider); + ProcessProvider.RunOnce(); + ServiceProvider.RunOnce(); + ProcessProvider.Enabled = true; + ServiceProvider.Enabled = true; + + Win32.LoadLibrary(Properties.Settings.Default.DbgHelpPath); + + if (!ProcessProvider.Dictionary.ContainsKey(pid)) + { + PhUtils.ShowError("The process (PID " + pid.ToString() + ") does not exist."); + Environment.Exit(0); + return true; + } + + ProcessWindow pw = new ProcessWindow(ProcessProvider.Dictionary[pid]); + + Application.Run(pw); + + SharedThreadProvider.Dispose(); + ProcessProvider.Dispose(); + ServiceProvider.Dispose(); + + Environment.Exit(0); + + return true; + } + + if (pArgs.ContainsKey("-pt")) + { + int pid = int.Parse(pArgs["-pt"]); + + try + { + using (var phandle = new ProcessHandle(pid, Program.MinProcessQueryRights)) + Application.Run(new TokenWindow(phandle)); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to show token properties", ex); + } + + return true; + } + + if (pArgs.ContainsKey("-o")) + { + OptionsWindow options = new OptionsWindow(true) + { + StartPosition = FormStartPosition.CenterScreen + }; + IWin32Window window; + + if (pArgs.ContainsKey("-hwnd")) + window = new WindowFromHandle(new IntPtr(int.Parse(pArgs["-hwnd"]))); + else + window = new WindowFromHandle(IntPtr.Zero); + + if (pArgs.ContainsKey("-rect")) + { + Rectangle rect = Utils.GetRectangle(pArgs["-rect"]); + + options.Location = new Point(rect.X + 20, rect.Y + 20); + options.StartPosition = FormStartPosition.Manual; + } + + options.SelectedTab = options.TabPages["tabAdvanced"]; + options.ShowDialog(window); + + return true; + } + + if (pArgs.ContainsKey("")) + if (pArgs[""].Replace("\"", "").Trim().ToLower().EndsWith("taskmgr.exe")) + StartVisible = true; + + if (pArgs.ContainsKey("-m")) + StartHidden = true; + if (pArgs.ContainsKey("-v")) + StartVisible = true; + + if (pArgs.ContainsKey("-a")) + { + try { Unhook(); } + catch { } + try { NProcessHacker.KphHookInit(); } + catch { } + } + + if (pArgs.ContainsKey("-t")) + { + if (pArgs["-t"] == "0") + SelectTab = "Processes"; + else if (pArgs["-t"] == "1") + SelectTab = "Services"; + else if (pArgs["-t"] == "2") + SelectTab = "Network"; + } + + return false; + } + + public static void Unhook() + { + ProcessHacker.Native.Image.MappedImage file = + new ProcessHacker.Native.Image.MappedImage(Environment.SystemDirectory + "\\ntdll.dll"); + IntPtr ntdll = Win32.GetModuleHandle("ntdll.dll"); + MemoryProtection oldProtection; + + oldProtection = ProcessHandle.GetCurrent().ProtectMemory( + ntdll, + (int)file.Size, + MemoryProtection.ExecuteReadWrite + ); + + for (int i = 0; i < file.Exports.Count; i++) + { + var entry = file.Exports.GetEntry(i); + + if (!entry.Name.StartsWith("Nt") || entry.Name.StartsWith("Ntdll")) + continue; + + byte[] fileData = new byte[5]; + + unsafe + { + IntPtr function = file.Exports.GetFunction(entry.Ordinal).Function; + + Win32.RtlMoveMemory( + function.Decrement(new IntPtr(file.Memory)).Increment(ntdll), + function, + (5).ToIntPtr() + ); + } + } + + ProcessHandle.GetCurrent().ProtectMemory( + ntdll, + (int)file.Size, + oldProtection + ); + + file.Dispose(); + } + + private static void CheckForPreviousInstance() + { + bool found = false; + + WindowHandle.Enumerate((window) => + { + if (window.GetText().Contains("Process Hacker [")) + { + int result; + + window.SendMessageTimeout((WindowMessage)0x9991, 0, 0, SmtoFlags.Block, 5000, out result); + + if (result == 0x1119) + { + window.SetForeground(); + found = true; + return false; + } + } + + return true; + }); + + if (found) + Environment.Exit(0); + } + + public static void StartProcessHackerAdmin() + { + StartProcessHackerAdmin("", null, IntPtr.Zero); + } + + public static void StartProcessHackerAdmin(string args, MethodInvoker successAction) + { + StartProcessHackerAdmin(args, successAction, IntPtr.Zero); + } + + public static void StartProcessHackerAdmin(string args, MethodInvoker successAction, IntPtr hWnd) + { + StartProgramAdmin(ProcessHandle.GetCurrent().GetMainModule().FileName, + args, successAction, ShowWindowType.Show, hWnd); + } + + public static WaitResult StartProcessHackerAdminWait(string args, IntPtr hWnd, uint timeout) + { + return StartProcessHackerAdminWait(args, null, hWnd, timeout); + } + + public static WaitResult StartProcessHackerAdminWait(string args, MethodInvoker successAction, IntPtr hWnd, uint timeout) + { + var info = new ShellExecuteInfo(); + + info.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(info); + info.lpFile = ProcessHandle.GetCurrent().GetMainModule().FileName; + info.nShow = ShowWindowType.Show; + info.fMask = 0x40; // SEE_MASK_NOCLOSEPROCESS + info.lpVerb = "runas"; + info.lpParameters = args; + info.hWnd = hWnd; + + if (Win32.ShellExecuteEx(ref info)) + { + if (successAction != null) + successAction(); + + var result = Win32.WaitForSingleObject(info.hProcess, timeout); + + Win32.CloseHandle(info.hProcess); + + return result; + } + else + { + // An error occured - the user probably canceled the elevation dialog. + return WaitResult.Abandoned; + } + } + + public static void StartProgramAdmin(string program, string args, + MethodInvoker successAction, ShowWindowType showType, IntPtr hWnd) + { + var info = new ShellExecuteInfo(); + + info.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(info); + info.lpFile = program; + info.nShow = showType; + info.lpVerb = "runas"; + info.lpParameters = args; + info.hWnd = hWnd; + + if (Win32.ShellExecuteEx(ref info)) + { + if (successAction != null) + successAction(); + } + } + + public static void TryStart(string command) + { + try + { + System.Diagnostics.Process.Start(command); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to start the process", ex); + } + } + + private static Dictionary ParseArgs(string[] args) + { + Dictionary dict = new Dictionary(); + string argPending = null; + + foreach (string s in args) + { + if (s.StartsWith("-")) + { + if (dict.ContainsKey(s)) + throw new Exception("Option already specified."); + + dict.Add(s, ""); + argPending = s; + } + else + { + if (argPending != null) + { + dict[argPending] = s; + argPending = null; + } + else + { + // On Windows 7 if PH replaces Task Manager, PH will be + // started with a command line of: + // ProcessHacker.exe "C:\...\taskmgr.exe" /4 + // The following two lines are commented out due to this. + + //if (dict.ContainsKey("")) + // throw new Exception("Input file already specified."); + + if (!dict.ContainsKey("")) + dict.Add("", s); + } + } + } + + return dict; + } + + public static void ApplyFont(Font font) + { + HackerWindow.BeginInvoke(new MethodInvoker(() => { HackerWindow.ApplyFont(font); })); + + foreach (var processWindow in PWindows.Values) + { + processWindow.BeginInvoke(new MethodInvoker(() => { processWindow.ApplyFont(font); })); + } + } + + public static void CollectGarbage() + { + // Garbage collections + GC.Collect(); + GC.WaitForPendingFinalizers(); + GC.Collect(); + // Compact the native heaps + CompactNativeHeaps(); + // Terminate any unused threadpool threads + CollectWorkerThreads(); + } + + public static void CollectWorkerThreads() + { + lock (CollectWorkerThreadsLock) + { + int workerThreads, completionPortThreads, maxWorkerThreads, maxCompletionPortThreads; + + ThreadPool.GetMaxThreads(out maxWorkerThreads, out maxCompletionPortThreads); + ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads); + + workerThreads = maxWorkerThreads - workerThreads; + completionPortThreads = maxCompletionPortThreads - completionPortThreads; + + ThreadPool.SetMaxThreads(0, 0); + ThreadPool.SetMaxThreads(workerThreads, completionPortThreads); + } + } + + public static void CompactNativeHeaps() + { + foreach (var heap in Heap.GetHeaps()) + heap.Compact(0); + } + + public static string GetDiagnosticInformation() + { + StringBuilder info = new StringBuilder(); + AppDomain app = System.AppDomain.CurrentDomain; + + info.AppendLine("Process Hacker " + Application.ProductVersion); + info.AppendLine("Process Hacker Build Time: " + Utils.GetAssemblyBuildDate(System.Reflection.Assembly.GetExecutingAssembly(), false)); + info.AppendLine("Application Base: " + app.SetupInformation.ApplicationBase); + info.AppendLine("Configuration File: " + app.SetupInformation.ConfigurationFile); + info.AppendLine("CLR Version: " + Environment.Version.ToString()); + info.AppendLine("OS Version: " + Environment.OSVersion.VersionString + " (" + OSVersion.BitsString + ")"); + info.AppendLine("Elevation: " + ElevationType.ToString()); + info.AppendLine("Working set: " + Utils.FormatSize(Environment.WorkingSet)); + + if (KProcessHacker.Instance == null) + info.AppendLine("KProcessHacker: not running"); + else + info.AppendLine("KProcessHacker: " + KProcessHacker.Instance.Features.ToString()); + + info.AppendLine(); + info.AppendLine("OBJECTS"); + + int objectsCreatedCount = BaseObject.CreatedCount; + int objectsFreedCount = BaseObject.FreedCount; + + info.AppendLine("Live: " + (objectsCreatedCount - objectsFreedCount).ToString()); + info.AppendLine("Created: " + objectsCreatedCount.ToString()); + info.AppendLine("Freed: " + objectsFreedCount.ToString()); + info.AppendLine("Disposed: " + BaseObject.DisposedCount.ToString()); + info.AppendLine("Finalized: " + BaseObject.FinalizedCount.ToString()); + info.AppendLine("Referenced: " + BaseObject.ReferencedCount.ToString()); + info.AppendLine("Dereferenced: " + BaseObject.DereferencedCount.ToString()); + + info.AppendLine(); + info.AppendLine("PRIVATE HEAP"); + + int heapAllocatedCount = MemoryAlloc.AllocatedCount; + int heapFreedCount = MemoryAlloc.FreedCount; + int heapReallocatedCount = MemoryAlloc.ReallocatedCount; + + info.AppendLine("Address: 0x" + MemoryAlloc.PrivateHeap.Address.ToString("x")); + info.AppendLine("Live: " + (heapAllocatedCount - heapFreedCount).ToString()); + info.AppendLine("Allocated: " + heapAllocatedCount.ToString()); + info.AppendLine("Freed: " + heapFreedCount.ToString()); + info.AppendLine("Reallocated: " + heapReallocatedCount.ToString()); + + info.AppendLine(); + info.AppendLine("MISCELLANEOUS COUNTERS"); + info.AppendLine("LSA lookup policy handle misses: " + LsaPolicyHandle.LookupPolicyHandleMisses.ToString()); + + info.AppendLine(); + info.AppendLine("PROCESS HACKER THREAD POOL"); + info.AppendLine("Worker thread maximum: " + WorkQueue.GlobalWorkQueue.MaxWorkerThreads.ToString()); + info.AppendLine("Worker thread minimum: " + WorkQueue.GlobalWorkQueue.MinWorkerThreads.ToString()); + info.AppendLine("Busy worker threads: " + WorkQueue.GlobalWorkQueue.BusyCount.ToString()); + info.AppendLine("Total worker threads: " + WorkQueue.GlobalWorkQueue.WorkerCount.ToString()); + info.AppendLine("Queued work items: " + WorkQueue.GlobalWorkQueue.QueuedCount.ToString()); + + foreach (WorkQueue.WorkItem workItem in WorkQueue.GlobalWorkQueue.GetQueuedWorkItems()) + if (workItem.Tag != null) + info.AppendLine("[" + workItem.Tag + "]: " + workItem.Work.Method.Name); + else + info.AppendLine(workItem.Work.Method.Name); + + info.AppendLine(); + info.AppendLine("CLR THREAD POOL"); + int maxWt, maxIoc, minWt, minIoc, wt, ioc; + ThreadPool.GetAvailableThreads(out wt, out ioc); + ThreadPool.GetMinThreads(out minWt, out minIoc); + ThreadPool.GetMaxThreads(out maxWt, out maxIoc); + info.AppendLine("Worker threads: " + (maxWt - wt).ToString() + " current, " + + maxWt.ToString() + " max, " + minWt.ToString() + " min"); + info.AppendLine("I/O completion threads: " + (maxIoc - ioc).ToString() + " current, " + + maxIoc.ToString() + " max, " + minIoc.ToString() + " min"); + + info.AppendLine(); + info.AppendLine("PRIMARY SHARED THREAD PROVIDER"); + + if (SharedThreadProvider != null) + { + info.AppendLine("Count: " + SharedThreadProvider.Count.ToString()); + + foreach (var provider in SharedThreadProvider.Providers) + info.AppendLine(provider.GetType().FullName + + " (Enabled: " + provider.Enabled + + ", Busy: " + provider.Busy.ToString() + + ", CreateThread: " + provider.CreateThread.ToString() + + ")"); + } + else + { + info.AppendLine("(null)"); + } + + info.AppendLine(); + info.AppendLine("SECONDARY SHARED THREAD PROVIDER"); + + if (SecondarySharedThreadProvider != null) + { + info.AppendLine("Count: " + SecondarySharedThreadProvider.Count.ToString()); + + foreach (var provider in SecondarySharedThreadProvider.Providers) + info.AppendLine(provider.GetType().FullName + + " (Enabled: " + provider.Enabled + + ", Busy: " + provider.Busy.ToString() + + ", CreateThread: " + provider.CreateThread.ToString() + + ")"); + } + else + { + info.AppendLine("(null)"); + } + + info.AppendLine(); + info.AppendLine("WINDOWS"); + info.AppendLine("MemoryEditors: " + MemoryEditors.Count.ToString() + ", " + MemoryEditorsThreads.Count.ToString()); + info.AppendLine("PEWindows: " + PEWindows.Count.ToString() + ", " + PEThreads.Count.ToString()); + info.AppendLine("PWindows: " + PWindows.Count.ToString() + ", " + PThreads.Count.ToString()); + info.AppendLine("ResultsWindows: " + ResultsWindows.Count.ToString() + ", " + ResultsThreads.Count.ToString()); + + info.AppendLine(); + info.AppendLine("LOADED MODULES"); + info.AppendLine(); + + foreach (ProcessModule module in ProcessHandle.Current.GetModules()) + { + info.AppendLine("Module: " + module.BaseName); + info.AppendLine("Location: " + module.FileName); + + DateTime fileCreatedInfo = System.IO.File.GetCreationTime(module.FileName); + info.AppendLine( + "Created: " + fileCreatedInfo.ToLongDateString() + " " + + fileCreatedInfo.ToLongTimeString() + ); + + DateTime fileModifiedInfo = System.IO.File.GetLastWriteTime(module.FileName); + info.AppendLine( + "Modified: " + fileModifiedInfo.ToLongDateString() + " " + + fileModifiedInfo.ToLongTimeString() + ); + + info.AppendLine("Version: " + System.Diagnostics.FileVersionInfo.GetVersionInfo(module.FileName).FileVersion); + info.AppendLine(); + } + + return info.ToString(); + } + + private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) + { + UnhandledException(e.ExceptionObject as Exception, e.IsTerminating); + } + + private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e) + { + UnhandledException(e.Exception, false); + } + + private static void UnhandledException(Exception ex, bool terminating) + { + Logging.Log(Logging.Importance.Critical, ex.ToString()); + + ErrorDialog ed = new ErrorDialog(ex, terminating); + + ed.ShowDialog(); + } + + /// + /// Creates an instance of the memory editor form. + /// + /// The PID of the process to edit + /// The address to start editing at + /// The length to edit + public static MemoryEditor GetMemoryEditor(int PID, IntPtr address, long length) + { + return GetMemoryEditor(PID, address, length, new MemoryEditorInvokeAction(delegate {})); + } + + /// + /// Creates an instance of the memory editor form and invokes an action on the memory editor's thread. + /// + /// The PID of the process to edit + /// The address to start editing at + /// The length to edit + /// The action to be invoked on the memory editor's thread + /// Memory editor form + public static MemoryEditor GetMemoryEditor(int PID, IntPtr address, long length, MemoryEditorInvokeAction action) + { + MemoryEditor ed = null; + string id = PID.ToString() + "-" + address.ToString() + "-" + length.ToString(); + + if (MemoryEditors.ContainsKey(id)) + { + ed = MemoryEditors[id]; + + ed.Invoke(action, ed); + + return ed; + } + + if (MemoryEditorsThreaded) + { + Thread t = new Thread(new ThreadStart(delegate + { + ed = new MemoryEditor(PID, address, length); + + if (!ed.IsDisposed) + action(ed); + if (!ed.IsDisposed) + Application.Run(ed); + + Program.MemoryEditorsThreads.Remove(id); + })); + + t.SetApartmentState(ApartmentState.STA); + t.Start(); + + Program.MemoryEditorsThreads.Add(id, t); + } + else + { + ed = new MemoryEditor(PID, address, length); + if (!ed.IsDisposed) + action(ed); + if (!ed.IsDisposed) + ed.Show(); + } + + return ed; + } + + /// + /// Creates an instance of the results window on a separate thread. + /// + public static ResultsWindow GetResultsWindow(int PID) + { + return GetResultsWindow(PID, new ResultsWindowInvokeAction(delegate { })); + } + + /// + /// Creates an instance of the results window on a separate thread and invokes an action on that thread. + /// + /// The action to be performed. + public static ResultsWindow GetResultsWindow(int PID, ResultsWindowInvokeAction action) + { + ResultsWindow rw = null; + string id = ""; + + if (ResultsWindowsThreaded) + { + Thread t = new Thread(new ThreadStart(delegate + { + rw = new ResultsWindow(PID); + + id = rw.Id; + + if (!rw.IsDisposed) + action(rw); + if (!rw.IsDisposed) + Application.Run(rw); + + Program.ResultsThreads.Remove(id); + })); + + t.SetApartmentState(ApartmentState.STA); + t.Start(); + + while (id == "") Thread.Sleep(1); + Program.ResultsThreads.Add(id, t); + } + else + { + rw = new ResultsWindow(PID); + if (!rw.IsDisposed) + action(rw); + if (!rw.IsDisposed) + rw.Show(); + } + + return rw; + } + + /// + /// Creates an instance of the PE window on a separate thread. + /// + public static PEWindow GetPEWindow(string path) + { + return GetPEWindow(path, new PEWindowInvokeAction(delegate { })); + } + + /// + /// Creates an instance of the thread window on a separate thread and invokes an action on that thread. + /// + /// The action to be performed. + public static PEWindow GetPEWindow(string path, PEWindowInvokeAction action) + { + PEWindow pw = null; + + if (PEWindows.ContainsKey(path)) + { + pw = PEWindows[path]; + + pw.Invoke(action, pw); + + return pw; + } + + if (PEWindowsThreaded) + { + Thread t = new Thread(new ThreadStart(delegate + { + pw = new PEWindow(path); + + if (!pw.IsDisposed) + action(pw); + if (!pw.IsDisposed) + Application.Run(pw); + + Program.PEThreads.Remove(path); + })); + + t.SetApartmentState(ApartmentState.STA); + t.Start(); + + Program.PEThreads.Add(path, t); + } + else + { + pw = new PEWindow(path); + if (!pw.IsDisposed) + action(pw); + if (!pw.IsDisposed) + pw.Show(); + } + + return pw; + } + + /// + /// Creates an instance of the process window on a separate thread. + /// + public static ProcessWindow GetProcessWindow(ProcessItem process) + { + return GetProcessWindow(process, new PWindowInvokeAction(delegate { })); + } + + /// + /// Creates an instance of the process window on a separate thread and invokes an action on that thread. + /// + /// The action to be performed. + public static ProcessWindow GetProcessWindow(ProcessItem process, PWindowInvokeAction action) + { + ProcessWindow pw = null; + + if (PWindows.ContainsKey(process.Pid)) + { + pw = PWindows[process.Pid]; + + pw.Invoke(action, pw); + + return pw; + } + + if (PWindowsThreaded) + { + Thread t = new Thread(new ThreadStart(delegate + { + pw = new ProcessWindow(process); + + if (!pw.IsDisposed) + action(pw); + if (!pw.IsDisposed) + Application.Run(pw); + + Program.PThreads.Remove(process.Pid); + })); + + t.SetApartmentState(ApartmentState.STA); + t.Start(); + + Program.PThreads.Add(process.Pid, t); + } + else + { + pw = new ProcessWindow(process); + if (!pw.IsDisposed) + action(pw); + if (!pw.IsDisposed) + pw.Show(); + } + + return pw; + } + + /// + /// Does nothing. + /// + [System.Diagnostics.Conditional("NOT_DEFINED")] + public static void Void() + { + // Do nothing + int a = 0; + int b = a * (a + 0); + + for (a = 0; a < b; a++) + a += a * (a + b); + } + + public static void FocusWindow(Form f) + { + if (f.InvokeRequired) + { + f.BeginInvoke(new MethodInvoker(delegate { Program.FocusWindow(f); })); + + return; + } + + f.Visible = true; // just in case it's hidden right now + + if (f.WindowState == FormWindowState.Minimized) + f.WindowState = FormWindowState.Normal; + + f.Activate(); + } + + public static void UpdateWindowMenu(Menu windowMenuItem, Form f) + { + WeakReference
fRef = new WeakReference(f); + + windowMenuItem.MenuItems.DisposeAndClear(); + + MenuItem item; + + item = new MenuItem("&Always On Top"); + item.Tag = fRef; + item.Click += new EventHandler(windowAlwaysOnTopItemClicked); + item.Checked = f.TopMost; + windowMenuItem.MenuItems.Add(item); + + item = new MenuItem("&Close"); + item.Tag = fRef; + item.Click += new EventHandler(windowCloseItemClicked); + windowMenuItem.MenuItems.Add(item); + } + + public static void AddEscapeToClose(this Form f) + { + f.KeyPreview = true; + f.KeyDown += (sender, e) => + { + if (e.KeyCode == Keys.Escape) + { + f.Close(); + e.Handled = true; + } + }; + } + + public static void SetTopMost(this Form f) + { + if (HackerWindowTopMost) + f.TopMost = true; + } + + /// + /// Floats the window on top of the main Process Hacker window. + /// + /// The form to float. + /// + /// Always call this method before calling InitializeComponent in order for the + /// parent to be restored properly. + /// + public static void SetPhParent(this Form f) + { + f.SetPhParent(true); + } + + public static void SetPhParent(this Form f, bool hideInTaskbar) + { + if (Properties.Settings.Default.FloatChildWindows) + { + if (hideInTaskbar) + f.ShowInTaskbar = false; + + IntPtr oldParent = Win32.SetWindowLongPtr(f.Handle, GetWindowLongOffset.HwndParent, Program.HackerWindowHandle); + + f.FormClosing += (sender, e) => Win32.SetWindowLongPtr(f.Handle, GetWindowLongOffset.HwndParent, oldParent); + } + } + + private static void windowAlwaysOnTopItemClicked(object sender, EventArgs e) + { + Form f = ((WeakReference)((MenuItem)sender).Tag).Target; + + if (f == null) + return; + + f.Invoke(new MethodInvoker(delegate + { + f.TopMost = !f.TopMost; + + if (f == HackerWindow) + HackerWindowTopMost = f.TopMost; + })); + + UpdateWindowMenu(((MenuItem)sender).Parent, f); + } + + private static void windowCloseItemClicked(object sender, EventArgs e) + { + Form f = ((WeakReference)((MenuItem)sender).Tag).Target; + + if (f == null) + return; + + f.Invoke(new MethodInvoker(delegate { f.Close(); })); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Program/Save.cs b/branches/ph-plugins/ProcessHacker/Program/Save.cs new file mode 100644 index 000000000..89e03c5af --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Program/Save.cs @@ -0,0 +1,423 @@ +/* + * Process Hacker - + * save processes + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; +using System.Windows.Forms; +using Aga.Controls.Tree; +using Aga.Controls.Tree.NodeControls; +using ProcessHacker.Common; +using ProcessHacker.Native; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker +{ + internal static class Save + { + private const int TabSize = 8; + + public static void SaveToFile() + { + SaveFileDialog sfd = new SaveFileDialog(); + + //sfd.Filter = "Text Files (*.txt;*.log)|*.txt;*.log|Comma-separated values (*.csv)|*.csv|HTML Files (*.htm;*.html)|*.htm;*.html|All Files (*.*)|*.*"; + sfd.Filter = "Text Files (*.txt;*.log)|*.txt;*.log|Comma-separated values (*.csv)|*.csv|All Files (*.*)|*.*"; + + if (Program.HackerWindow.SelectedPid == -1) + { + sfd.FileName = "Process List.txt"; + } + else + { + string processName = Windows.GetProcessName(Program.HackerWindow.SelectedPid); + + if (processName != null) + sfd.FileName = processName + ".txt"; + else + sfd.FileName = "Process Info.txt"; + } + + if (sfd.ShowDialog() == DialogResult.OK) + { + FileInfo fi = new FileInfo(sfd.FileName); + string ext = fi.Extension.ToLower(); + + try + { + using (StreamWriter sw = new StreamWriter(fi.FullName)) + { + Program.HackerWindow.ProcessTree.Tree.ExpandAll(); + + if (ext == ".htm" || ext == ".html") + { + + } + else if (ext == ".csv") + { + sw.Write(GetProcessTreeText(false)); + } + else + { + sw.Write(GetEnvironmentInfo()); + sw.WriteLine(); + sw.Write(GetProcessTreeText(true)); + sw.WriteLine(); + + if (Program.HackerWindow.SelectedPid != -1) + { + sw.Write(GetProcessDetailsText(Program.HackerWindow.SelectedPid)); + sw.WriteLine(); + } + } + } + } + catch (IOException ex) + { + PhUtils.ShowException("Unable to save the process list", ex); + } + } + } + + private static string GetEnvironmentInfo() + { + StringBuilder sb = new StringBuilder(); + + sb.AppendLine("Process Hacker version " + Application.ProductVersion); + sb.AppendLine(Environment.OSVersion.ToString() + " (" + OSVersion.BitsString + ")"); + + return sb.ToString(); + } + + private static string GetProcessTreeText(bool tabs) + { + // This function builds a table of strings, formats it, and returns it. + + // The string builder which will contain the result. + StringBuilder sb = new StringBuilder(); + // The number of rows in the table. We add 1 for the column headers. + int items = Program.HackerWindow.ProcessTree.Tree.ItemCount + 1; + // The number of columns. + int columns = 0; + // The column to column index map. + Dictionary columnIndexMap = new Dictionary(); + // The table. + string[][] str = new string[items][]; + + // Create the column index map which will map columns to their corresponding + // columns in the table. Note that we cannot currently convert graph columns + // to text (so we ignore CPU History and I/O history). + foreach (TreeColumn column in Program.HackerWindow.ProcessTree.Tree.Columns) + { + if (column.IsVisible && column.Header != "CPU History" && column.Header != "I/O History") + { + columnIndexMap[column] = columns; + columns++; + } + } + + // At this point the columns variable will contain the number of columns. + + // Create the rows. + for (int i = 0; i < items; i++) + str[i] = new string[columns]; + + // Populate the first row with the column headers. + foreach (var column in Program.HackerWindow.ProcessTree.Tree.Columns) + { + if (columnIndexMap.ContainsKey(column)) + str[0][columnIndexMap[column]] = column.Header; + } + + // Go through the nodes in the process tree and populate each cell of the table. + { + int i = 0; + + // Go through each node. + foreach (var node in Program.HackerWindow.ProcessTree.Tree.AllNodes) + { + // Go through each node control, find the column which corresponds to it, + // find the column index for the column, and fill in the cell. + foreach (var control in Program.HackerWindow.ProcessTree.Tree.NodeControls) + { + // Make sure the node control is visible, and make sure it's text. + if (!control.ParentColumn.IsVisible || !(control is BaseTextControl)) + continue; + + // Get the text contained in the node control. + string text = (control as BaseTextControl).GetLabel(node); + // Get the column index corresponding with the node control's column. + int columnIndex = columnIndexMap[control.ParentColumn]; + + // Fill in the cell. + str[i + 1][columnIndex] = + // If this is the first column in the row, add some indentation. + (columnIndex == 0 ? (new string(' ', (node.Level - 1) * 2)) : "") + + (text != null ? text : ""); + } + + i++; + } + } + + // Create the tab count array. This will contain the number of tabs needed + // to fill the biggest row cell in each column. + // Note that this is ignored if tabs is false. + int[] tabCount = new int[columns]; + + for (int i = 0; i < items; i++) + { + for (int j = 0; j < columns; j++) + { + int newCount = str[i][j].Length / TabSize; + + // Replace the existing count if this tab count is bigger. + if (newCount > tabCount[j]) + tabCount[j] = newCount; + } + } + + // Create the final string by going through each cell and appending the + // proper tab count (if we are using tabs). That will make sure each + // column is properly aligned. + for (int i = 0; i < items; i++) + { + for (int j = 0; j < columns; j++) + { + if (tabs) + { + // Append the cell contents. + sb.Append(str[i][j]); + // Append the proper tab count. + sb.Append('\t', tabCount[j] - str[i][j].Length / TabSize + 1); + } + else + { + // Append the quotes, escape and append the cell contents. + sb.Append("\""); + sb.Append(str[i][j].Replace("\"", "\\\"")); + sb.Append("\""); + + // Append the comma separator. + if (j != columns - 1) + sb.Append(","); + } + } + + sb.AppendLine(); + } + + return sb.ToString(); + } + + private static string GetProcessDetailsText(int pid) + { + // This function returns a string containing details about a process. + + // The string builder which will contain the result. + StringBuilder sb = new StringBuilder(); + + sb.AppendLine("Process PID " + pid.ToString() + ":"); + sb.AppendLine(); + + try + { + using (var phandle = new ProcessHandle(pid, ProcessAccess.QueryLimitedInformation)) + { + var fileName = phandle.GetImageFileName(); + + sb.AppendLine("Native file name: " + fileName); + fileName = FileUtils.GetFileName(fileName); + sb.AppendLine("DOS file name: " + fileName); + + try + { + var fileInfo = FileVersionInfo.GetVersionInfo(fileName); + + sb.AppendLine("Description: " + fileInfo.FileDescription); + sb.AppendLine("Company: " + fileInfo.CompanyName); + sb.AppendLine("Version: " + fileInfo.FileVersion); + } + catch (Exception ex2) + { + sb.AppendLine("Version info section failed! " + ex2.Message); + } + + sb.AppendLine("Started: " + phandle.GetCreateTime().ToString()); + + var memoryInfo = phandle.GetMemoryStatistics(); + + sb.AppendLine("WS: " + Utils.FormatSize(memoryInfo.WorkingSetSize)); + sb.AppendLine("Pagefile usage: " + Utils.FormatSize(memoryInfo.PagefileUsage)); + } + } + catch (Exception ex) + { + sb.AppendLine("Basic info section failed! " + ex.Message); + } + + try + { + using (var phandle = new ProcessHandle(pid, ProcessAccess.QueryLimitedInformation | ProcessAccess.VmRead)) + { + var commandLine = phandle.GetCommandLine(); + var currentDirectory = phandle.GetPebString(PebOffset.CurrentDirectoryPath); + + sb.AppendLine("Command line: " + commandLine); + sb.AppendLine("Current directory: " + currentDirectory); + } + } + catch (Exception ex) + { + sb.AppendLine("PEB info section failed! " + ex.Message); + } + + sb.AppendLine(); + sb.AppendLine("Modules:"); + sb.AppendLine(); + + try + { + using (var phandle = new ProcessHandle(pid, ProcessAccess.QueryLimitedInformation | ProcessAccess.VmRead)) + { + foreach (var module in phandle.GetModules()) + { + sb.AppendLine(module.FileName); + sb.Append(" [0x" + module.BaseAddress.ToInt32().ToString("x") + ", "); + sb.AppendLine(Utils.FormatSize(module.Size) + "] "); + sb.AppendLine(" Flags: " + module.Flags.ToString()); + + try + { + var fileInfo = FileVersionInfo.GetVersionInfo(module.FileName); + + sb.AppendLine(" Description: " + fileInfo.FileDescription); + sb.AppendLine(" Company: " + fileInfo.CompanyName); + sb.AppendLine(" Version: " + fileInfo.FileVersion); + } + catch (Exception ex2) + { + sb.AppendLine(" Version info failed! " + ex2.Message); + } + + sb.AppendLine(); + } + } + } + catch (Exception ex) + { + sb.AppendLine("Modules section failed! " + ex.Message); + } + + sb.AppendLine("Token:"); + sb.AppendLine(); + + try + { + using (var phandle = new ProcessHandle(pid, ProcessAccess.QueryLimitedInformation)) + using (var thandle = phandle.GetToken(TokenAccess.Query)) + { + sb.AppendLine("User: " + thandle.GetUser().GetFullName(true)); + sb.AppendLine("Owner: " + thandle.GetOwner().GetFullName(true)); + sb.AppendLine("Primary group: " + thandle.GetPrimaryGroup().GetFullName(true)); + + foreach (var group in thandle.GetGroups()) + { + sb.AppendLine("Group " + group.GetFullName(true)); + } + + foreach (var privilege in thandle.GetPrivileges()) + { + sb.AppendLine("Privilege " + privilege.Name + ": " + privilege.Attributes.ToString()); + } + } + } + catch (Exception ex) + { + sb.AppendLine("Token section failed! " + ex.Message); + } + + sb.AppendLine(); + sb.AppendLine("Environment:"); + sb.AppendLine(); + + try + { + using (var phandle = new ProcessHandle(pid, ProcessAccess.QueryInformation | ProcessAccess.VmRead)) + { + var vars = phandle.GetEnvironmentVariables(); + + foreach (var kvp in vars) + { + sb.AppendLine(kvp.Key + " = " + kvp.Value); + } + } + } + catch (Exception ex) + { + sb.AppendLine("Environment section failed! " + ex.Message); + } + + sb.AppendLine(); + sb.AppendLine("Handles:"); + sb.AppendLine(); + + try + { + using (var phandle = new ProcessHandle(pid, ProcessAccess.DupHandle)) + { + var handles = Windows.GetHandles(); + + foreach (var handle in handles) + { + if (handle.ProcessId != pid) + continue; + + sb.Append("[0x" + handle.Handle.ToString("x") + ", "); + + try + { + var info = handle.GetHandleInfo(phandle); + + sb.Append(info.TypeName + "] "); + sb.AppendLine(!string.IsNullOrEmpty(info.BestName) ? info.BestName : "(no name)"); + } + catch (Exception ex2) + { + sb.Append(handle.ObjectTypeNumber.ToString() + "] "); + sb.AppendLine("Error: " + ex2.Message); + } + } + } + } + catch (Exception ex) + { + sb.AppendLine("Handles section failed! " + ex.Message); + } + + return sb.ToString(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Program/Settings.cs b/branches/ph-plugins/ProcessHacker/Program/Settings.cs new file mode 100644 index 000000000..3ca885f24 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Program/Settings.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker +{ + public static class Settings + { + public static void Refresh() + { + RefreshInterval = Properties.Settings.Default.RefreshInterval; + ShowAccountDomains = Properties.Settings.Default.ShowAccountDomains; + } + + private static int _refreshInterval; + public static int RefreshInterval + { + get { return _refreshInterval; } + set + { + Properties.Settings.Default.RefreshInterval = _refreshInterval = value; + } + } + + private static bool _showAccountDomains; + public static bool ShowAccountDomains + { + get { return _showAccountDomains; } + set + { + Properties.Settings.Default.ShowAccountDomains = _showAccountDomains = value; + } + } + + } +} diff --git a/branches/ph-plugins/ProcessHacker/Program/ThemingScope.cs b/branches/ph-plugins/ProcessHacker/Program/ThemingScope.cs new file mode 100644 index 000000000..5d260e836 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Program/ThemingScope.cs @@ -0,0 +1,27 @@ +using System; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Windows.Forms; + +namespace ProcessHacker +{ + public static class ThemingScope + { + [DllImport("kernel32.dll")] + private static extern bool ActivateActCtx(IntPtr hActCtx, out IntPtr lpCookie); + + public static void Activate() + { + IntPtr zero = IntPtr.Zero; + Assembly windowsForms = Assembly.GetAssembly(typeof(Control)); + + // HACK + IntPtr hActCtx = (IntPtr)windowsForms.GetType("System.Windows.Forms.UnsafeNativeMethods", true). + GetNestedType("ThemingScope", BindingFlags.NonPublic | BindingFlags.Static). + GetField("hActCtx", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null); + + if (OSFeature.Feature.IsPresent(OSFeature.Themes)) + ActivateActCtx(hActCtx, out zero); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Program/Updater.cs b/branches/ph-plugins/ProcessHacker/Program/Updater.cs new file mode 100644 index 000000000..cd8f2f9ef --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Program/Updater.cs @@ -0,0 +1,267 @@ +/* + * Process Hacker - + * Process Hacker updater + * + * Copyright (C) 2009 wj32 + * Copyright (C) 2009 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 . + */ + +using System; +using System.Globalization; +using System.Windows.Forms; +using System.Xml; +using ProcessHacker.Common; +using ProcessHacker.Components; +using ProcessHacker.Native; +using System.Net; +using System.IO; + +namespace ProcessHacker +{ + public enum AppUpdateLevel + { + Stable = 0, + Beta = 1, + Alpha = 2 + } + + /// + /// Application Updater Class for Process Hacker + /// + public static class Updater + { + public class UpdateItem + { + public UpdateItem() + { + this.Version = new Version(Application.ProductVersion); + this.Date = GetAssemblyBuildDate(); + } + + public UpdateItem(XmlNode node) + { + this.Name = node["title"].InnerText; + this.Version = new Version(node["version"].InnerText); + this.Date = DateTime.Parse(node["released"].InnerText, DateTimeFormatInfo.InvariantInfo); + this.Type = GetUpdateLevel(node["type"].InnerText); + this.Message = node["description"].InnerText; + this.Url = node["updateurl"].InnerText; + this.Hash = node["hash"].InnerText; + } + + public string Name { get; private set; } + public Version Version { get; private set; } + public DateTime Date { get; private set; } + public AppUpdateLevel Type { get; private set; } + public string Message { get; private set; } + public string Url { get; private set; } + public string Hash { get; private set; } + + public bool IsBetterThan(UpdateItem update, AppUpdateLevel preferredType) + { + if (update == null) + return true; + if ((int)this.Type > (int)preferredType) + return false; + + return this.Version > update.Version || this.Date > update.Date; + } + } + + private static AppUpdateLevel GetUpdateLevel(string level) + { + switch (level.ToLowerInvariant()) + { + case "stable": + return AppUpdateLevel.Stable; + case "beta": + return AppUpdateLevel.Beta; + case "alpha": + default: + return AppUpdateLevel.Alpha; + } + } + + public static void Update(Form form, bool interactive) + { + if (PhUtils.IsInternetConnected) + { + XmlDocument xDoc = new XmlDocument(); + + try + { + xDoc.Load(Properties.Settings.Default.AppUpdateUrl); + } + catch (Exception ex) + { + if (interactive) + PhUtils.ShowException("Unable to download update information", ex); + else + Program.HackerWindow.QueueMessage("Unable to download update information: " + ex.Message); + + return; + } + + UpdateItem currentVersion = new UpdateItem(); + UpdateItem bestUpdate = currentVersion; + + XmlNodeList nodes = xDoc.SelectNodes("//update"); + foreach (XmlNode node in nodes) + { + try + { + UpdateItem update = new UpdateItem(node); + + // Check if this update is better than the one we already have. + if (update.IsBetterThan(bestUpdate, (AppUpdateLevel)Properties.Settings.Default.AppUpdateLevel)) + bestUpdate = update; + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + + PromptWithUpdate(form, bestUpdate, currentVersion, interactive); + } + else if (interactive) + PhUtils.ShowWarning("An Internet session could not be established. Please verify connectivity."); + } + + private static void PromptWithUpdate(Form form, UpdateItem bestUpdate, UpdateItem currentVersion, bool interactive) + { + if (form.InvokeRequired) + { + form.BeginInvoke(new MethodInvoker(() => PromptWithUpdate(form, bestUpdate, currentVersion, interactive))); + return; + } + + if (bestUpdate != currentVersion) + { + DialogResult dialogResult; + + if (OSVersion.HasTaskDialogs) + { + TaskDialog td = new TaskDialog(); + td.PositionRelativeToWindow = true; + td.Content = + "Your Version: " + currentVersion.Version.ToString() + + "\nServer Version: " + bestUpdate.Version.ToString() + "\n\n" + "\n" + bestUpdate.Message; + td.MainInstruction = "Process Hacker update available"; + td.WindowTitle = "Update available"; + td.MainIcon = TaskDialogIcon.SecurityWarning; + td.Buttons = new TaskDialogButton[] + { + new TaskDialogButton((int)DialogResult.Yes, "Download"), + new TaskDialogButton((int)DialogResult.No, "Cancel"), + }; + + dialogResult = (DialogResult)td.Show(form); + } + else + { + dialogResult = MessageBox.Show( + form, + "Your Version: " + currentVersion.Version.ToString() + + "\nServer Version: " + bestUpdate.Version.ToString() + "\n\n" + bestUpdate.Message + + "\n\nDo you want to download the update now?", + "Update available", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation + ); + } + + if (dialogResult == DialogResult.Yes) + { + DownloadUpdate(form, bestUpdate); + } + + } + else if (interactive) + { + if (OSVersion.HasTaskDialogs) + { + TaskDialog td = new TaskDialog(); + td.PositionRelativeToWindow = true; + td.Content = + "Your Version: " + currentVersion.Version.ToString() + + "\nServer Version: " + bestUpdate.Version.ToString(); + td.MainInstruction = "Process Hacker is up-to-date"; + td.WindowTitle = "No updates available"; + td.MainIcon = TaskDialogIcon.SecuritySuccess; + td.CommonButtons = TaskDialogCommonButtons.Ok; + td.Show(form); + } + else + { + MessageBox.Show( + form, + "Process Hacker is up-to-date.", + "No updates available", MessageBoxButtons.OK, MessageBoxIcon.Information + ); + } + } + } + + private static void DownloadUpdate(Form form, UpdateItem updateItem) + { + if (form.InvokeRequired) + { + form.BeginInvoke(new MethodInvoker(() => DownloadUpdate(form, updateItem))); + return; + } + + new UpdaterDownloadWindow(updateItem).ShowDialog(form); + } + + private static DateTime? AssemblyBuildDate = null; + private static DateTime GetAssemblyBuildDate() + { + if (AssemblyBuildDate != null) //Performance fix - Prevent reading current Assembly multiple times + { + return (DateTime)AssemblyBuildDate; + } + else + { + const int PeHeaderOffset = 60; + const int LinkerTimestampOffset = 8; + + byte[] b = new byte[2048]; + System.IO.Stream s = default(System.IO.Stream); + try + { + s = new System.IO.FileStream(System.Reflection.Assembly.GetExecutingAssembly().Location, System.IO.FileMode.Open, System.IO.FileAccess.Read); + s.Read(b, 0, 2048); + } + finally + { + if ((s != null)) + s.Close(); + } + + int i = BitConverter.ToInt32(b, PeHeaderOffset); + int SecondsSince1970 = BitConverter.ToInt32(b, i + LinkerTimestampOffset); + DateTime dt = new DateTime(1970, 1, 1, 0, 0, 0); + dt = dt.AddSeconds(SecondsSince1970); + dt = dt.AddHours(TimeZone.CurrentTimeZone.GetUtcOffset(dt).Hours); + + AssemblyBuildDate = dt; + + return (DateTime)AssemblyBuildDate; + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Properties/AssemblyInfo.cs b/branches/ph-plugins/ProcessHacker/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..173b233a4 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Properties/AssemblyInfo.cs @@ -0,0 +1,37 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Process Hacker")] +[assembly: AssemblyDescription("Process Hacker")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("wj32")] +[assembly: AssemblyProduct("Process Hacker")] +[assembly: AssemblyCopyright("Licensed under the GNU GPL, v3.")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("64bdf3bc-ab3b-46a5-a700-8e6c2c6a68cf")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.6.0.0")] +[assembly: AssemblyFileVersion("1.6.0.0")] +[assembly: StringFreezing] diff --git a/branches/ph-plugins/ProcessHacker/Properties/Resources.Designer.cs b/branches/ph-plugins/ProcessHacker/Properties/Resources.Designer.cs new file mode 100644 index 000000000..3f70bbd33 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Properties/Resources.Designer.cs @@ -0,0 +1,476 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.4016 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace ProcessHacker.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ProcessHacker.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + internal static System.Drawing.Bitmap active_search { + get { + object obj = ResourceManager.GetObject("active_search", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap application { + get { + object obj = ResourceManager.GetObject("application", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap application_delete { + get { + object obj = ResourceManager.GetObject("application_delete", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap application_form_magnify { + get { + object obj = ResourceManager.GetObject("application_form_magnify", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap application_go { + get { + object obj = ResourceManager.GetObject("application_go", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap application_view_detail { + get { + object obj = ResourceManager.GetObject("application_view_detail", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap arrow_refresh { + get { + object obj = ResourceManager.GetObject("arrow_refresh", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap arrow_right { + get { + object obj = ResourceManager.GetObject("arrow_right", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap arrow_up { + get { + object obj = ResourceManager.GetObject("arrow_up", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap asterisk_orange { + get { + object obj = ResourceManager.GetObject("asterisk_orange", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap bricks { + get { + object obj = ResourceManager.GetObject("bricks", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap chart_curve { + get { + object obj = ResourceManager.GetObject("chart_curve", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap chart_line { + get { + object obj = ResourceManager.GetObject("chart_line", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap cog { + get { + object obj = ResourceManager.GetObject("cog", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap cog_edit { + get { + object obj = ResourceManager.GetObject("cog_edit", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap control_equalizer { + get { + object obj = ResourceManager.GetObject("control_equalizer", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap control_equalizer_blue { + get { + object obj = ResourceManager.GetObject("control_equalizer_blue", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap control_pause { + get { + object obj = ResourceManager.GetObject("control_pause", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap control_pause_blue { + get { + object obj = ResourceManager.GetObject("control_pause_blue", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap control_play { + get { + object obj = ResourceManager.GetObject("control_play", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap control_play_blue { + get { + object obj = ResourceManager.GetObject("control_play_blue", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap control_stop { + get { + object obj = ResourceManager.GetObject("control_stop", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap control_stop_blue { + get { + object obj = ResourceManager.GetObject("control_stop_blue", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap cross { + get { + object obj = ResourceManager.GetObject("cross", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap delete { + get { + object obj = ResourceManager.GetObject("delete", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap disk { + get { + object obj = ResourceManager.GetObject("disk", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap door_out { + get { + object obj = ResourceManager.GetObject("door_out", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap find { + get { + object obj = ResourceManager.GetObject("find", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap folder_explore { + get { + object obj = ResourceManager.GetObject("folder_explore", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap folder_go { + get { + object obj = ResourceManager.GetObject("folder_go", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap group { + get { + object obj = ResourceManager.GetObject("group", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap help { + get { + object obj = ResourceManager.GetObject("help", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap inactive_search { + get { + object obj = ResourceManager.GetObject("inactive_search", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap information { + get { + object obj = ResourceManager.GetObject("information", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap lightbulb_off { + get { + object obj = ResourceManager.GetObject("lightbulb_off", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap lock_edit { + get { + object obj = ResourceManager.GetObject("lock_edit", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap locked { + get { + object obj = ResourceManager.GetObject("locked", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap money { + get { + object obj = ResourceManager.GetObject("money", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap mouse { + get { + object obj = ResourceManager.GetObject("mouse", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap page { + get { + object obj = ResourceManager.GetObject("page", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap page_copy { + get { + object obj = ResourceManager.GetObject("page_copy", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap page_edit { + get { + object obj = ResourceManager.GetObject("page_edit", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap page_gear { + get { + object obj = ResourceManager.GetObject("page_gear", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap page_save { + get { + object obj = ResourceManager.GetObject("page_save", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap page_white_text { + get { + object obj = ResourceManager.GetObject("page_white_text", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap pencil { + get { + object obj = ResourceManager.GetObject("pencil", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap pencil_go { + get { + object obj = ResourceManager.GetObject("pencil_go", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Icon Process { + get { + object obj = ResourceManager.GetObject("Process", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + internal static System.Drawing.Icon Process_small { + get { + object obj = ResourceManager.GetObject("Process_small", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + internal static System.Drawing.Bitmap ProcessHacker { + get { + object obj = ResourceManager.GetObject("ProcessHacker", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap report { + get { + object obj = ResourceManager.GetObject("report", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap report_user { + get { + object obj = ResourceManager.GetObject("report_user", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap sflogo { + get { + object obj = ResourceManager.GetObject("sflogo", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap table { + get { + object obj = ResourceManager.GetObject("table", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap table_relationship { + get { + object obj = ResourceManager.GetObject("table_relationship", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap table_sort { + get { + object obj = ResourceManager.GetObject("table_sort", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap tick { + get { + object obj = ResourceManager.GetObject("tick", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap user { + get { + object obj = ResourceManager.GetObject("user", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap VirusTotal_logo { + get { + object obj = ResourceManager.GetObject("VirusTotal_logo", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Properties/Resources.resx b/branches/ph-plugins/ProcessHacker/Properties/Resources.resx new file mode 100644 index 000000000..140cf3551 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Properties/Resources.resx @@ -0,0 +1,298 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\application_go.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\asterisk_orange.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\report.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\control_play_blue.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\table_sort.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\door_out.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\page_copy.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\resources\virustotal-logo.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\group.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Icons\ProcessHacker.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\lock.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\find.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\cog.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\arrow_right.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\tick.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\control_stop.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\pencil_go.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\page_white_text.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\arrow_up.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\arrow_refresh.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\inactive_search.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\page_save.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\control_pause_blue.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\page_gear.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\bricks.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\table.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\mouse.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\chart_curve.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\control_play.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\control_equalizer_blue.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\application_view_detail.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\information.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\user.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\control_pause.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\application_form_magnify.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\lock_edit.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\page.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\sflogo.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\application_delete.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\control_stop_blue.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\lightbulb_off.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\help.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Icons\Process_small.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\table_relationship.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\cog_edit.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\page_edit.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\cross.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\pencil.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\folder_go.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\report_user.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\folder_explore.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\control_equalizer.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\application.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Icons\Process.ico;System.Drawing.Icon, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\delete.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\disk.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\active_search.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\chart_line.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\money.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Properties/Settings.Designer.cs b/branches/ph-plugins/ProcessHacker/Properties/Settings.Designer.cs new file mode 100644 index 000000000..73fc715f3 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Properties/Settings.Designer.cs @@ -0,0 +1,1744 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.4927 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace ProcessHacker.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("1000")] + public int RefreshInterval { + get { + return ((int)(this["RefreshInterval"])); + } + set { + this["RefreshInterval"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("844, 550")] + public global::System.Drawing.Size WindowSize { + get { + return ((global::System.Drawing.Size)(this["WindowSize"])); + } + set { + this["WindowSize"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("200, 200")] + public global::System.Drawing.Point WindowLocation { + get { + return ((global::System.Drawing.Point)(this["WindowLocation"])); + } + set { + this["WindowLocation"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("355")] + public int SplitterDistance { + get { + return ((int)(this["SplitterDistance"])); + } + set { + this["SplitterDistance"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("Normal")] + public global::System.Windows.Forms.FormWindowState WindowState { + get { + return ((global::System.Windows.Forms.FormWindowState)(this["WindowState"])); + } + set { + this["WindowState"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool DebugMem { + get { + return ((bool)(this["DebugMem"])); + } + set { + this["DebugMem"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("&String Scan...")] + public string SearchType { + get { + return ((string)(this["SearchType"])); + } + set { + this["SearchType"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool ShowAccountDomains { + get { + return ((bool)(this["ShowAccountDomains"])); + } + set { + this["ShowAccountDomains"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool WarnDangerous { + get { + return ((bool)(this["WarnDangerous"])); + } + set { + this["WarnDangerous"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string ProcessTreeColumns { + get { + return ((string)(this["ProcessTreeColumns"])); + } + set { + this["ProcessTreeColumns"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string ThreadListViewColumns { + get { + return ((string)(this["ThreadListViewColumns"])); + } + set { + this["ThreadListViewColumns"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("504, 482")] + public global::System.Drawing.Size ResultsWindowSize { + get { + return ((global::System.Drawing.Size)(this["ResultsWindowSize"])); + } + set { + this["ResultsWindowSize"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("0,115|1,80|2,70|3,188|")] + public string ModuleListViewColumns { + get { + return ((string)(this["ModuleListViewColumns"])); + } + set { + this["ModuleListViewColumns"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string MemoryListViewColumns { + get { + return ((string)(this["MemoryListViewColumns"])); + } + set { + this["MemoryListViewColumns"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("791, 503")] + public global::System.Drawing.Size MemoryWindowSize { + get { + return ((global::System.Drawing.Size)(this["MemoryWindowSize"])); + } + set { + this["MemoryWindowSize"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string ResultsListViewColumns { + get { + return ((string)(this["ResultsListViewColumns"])); + } + set { + this["ResultsListViewColumns"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("tabGeneral")] + public string ProcessWindowSelectedTab { + get { + return ((string)(this["ProcessWindowSelectedTab"])); + } + set { + this["ProcessWindowSelectedTab"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string PrivilegeListColumns { + get { + return ((string)(this["PrivilegeListColumns"])); + } + set { + this["PrivilegeListColumns"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string GroupListColumns { + get { + return ((string)(this["GroupListColumns"])); + } + set { + this["GroupListColumns"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("481, 468")] + public global::System.Drawing.Size TokenWindowSize { + get { + return ((global::System.Drawing.Size)(this["TokenWindowSize"])); + } + set { + this["TokenWindowSize"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("439, 413")] + public global::System.Drawing.Size PEWindowSize { + get { + return ((global::System.Drawing.Size)(this["PEWindowSize"])); + } + set { + this["PEWindowSize"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string PECOFFHColumns { + get { + return ((string)(this["PECOFFHColumns"])); + } + set { + this["PECOFFHColumns"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string PECOFFOHColumns { + get { + return ((string)(this["PECOFFOHColumns"])); + } + set { + this["PECOFFOHColumns"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string PEImageDataColumns { + get { + return ((string)(this["PEImageDataColumns"])); + } + set { + this["PEImageDataColumns"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string PESectionsColumns { + get { + return ((string)(this["PESectionsColumns"])); + } + set { + this["PESectionsColumns"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string PEExportsColumns { + get { + return ((string)(this["PEExportsColumns"])); + } + set { + this["PEExportsColumns"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string PEImportsColumns { + get { + return ((string)(this["PEImportsColumns"])); + } + set { + this["PEImportsColumns"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("http://www.google.com/search?q=%s")] + public string SearchEngine { + get { + return ((string)(this["SearchEngine"])); + } + set { + this["SearchEngine"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("Chartreuse")] + public global::System.Drawing.Color ColorNew { + get { + return ((global::System.Drawing.Color)(this["ColorNew"])); + } + set { + this["ColorNew"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("255, 60, 40")] + public global::System.Drawing.Color ColorRemoved { + get { + return ((global::System.Drawing.Color)(this["ColorRemoved"])); + } + set { + this["ColorRemoved"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("255, 255, 170")] + public global::System.Drawing.Color ColorOwnProcesses { + get { + return ((global::System.Drawing.Color)(this["ColorOwnProcesses"])); + } + set { + this["ColorOwnProcesses"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("255, 170, 0")] + public global::System.Drawing.Color ColorElevatedProcesses { + get { + return ((global::System.Drawing.Color)(this["ColorElevatedProcesses"])); + } + set { + this["ColorElevatedProcesses"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("170, 204, 255")] + public global::System.Drawing.Color ColorSystemProcesses { + get { + return ((global::System.Drawing.Color)(this["ColorSystemProcesses"])); + } + set { + this["ColorSystemProcesses"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("1000")] + public int HighlightingDuration { + get { + return ((int)(this["HighlightingDuration"])); + } + set { + this["HighlightingDuration"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool AlwaysOnTop { + get { + return ((bool)(this["AlwaysOnTop"])); + } + set { + this["AlwaysOnTop"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("415, 503")] + public global::System.Drawing.Size ThreadWindowSize { + get { + return ((global::System.Drawing.Size)(this["ThreadWindowSize"])); + } + set { + this["ThreadWindowSize"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string CallStackColumns { + get { + return ((string)(this["CallStackColumns"])); + } + set { + this["CallStackColumns"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool UseToolhelpModules { + get { + return ((bool)(this["UseToolhelpModules"])); + } + set { + this["UseToolhelpModules"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool NewProcesses { + get { + return ((bool)(this["NewProcesses"])); + } + set { + this["NewProcesses"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool TerminatedProcesses { + get { + return ((bool)(this["TerminatedProcesses"])); + } + set { + this["TerminatedProcesses"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool NewServices { + get { + return ((bool)(this["NewServices"])); + } + set { + this["NewServices"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool StartedServices { + get { + return ((bool)(this["StartedServices"])); + } + set { + this["StartedServices"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool StoppedServices { + get { + return ((bool)(this["StoppedServices"])); + } + set { + this["StoppedServices"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool DeletedServices { + get { + return ((bool)(this["DeletedServices"])); + } + set { + this["DeletedServices"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("0,150|1,300|2,120|3,80|4,80|5,60|")] + public string ServiceListViewColumns { + get { + return ((string)(this["ServiceListViewColumns"])); + } + set { + this["ServiceListViewColumns"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string HandleListViewColumns { + get { + return ((string)(this["HandleListViewColumns"])); + } + set { + this["HandleListViewColumns"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string HandleFilterWindowListViewColumns { + get { + return ((string)(this["HandleFilterWindowListViewColumns"])); + } + set { + this["HandleFilterWindowListViewColumns"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("554, 463")] + public global::System.Drawing.Size HandleFilterWindowSize { + get { + return ((global::System.Drawing.Size)(this["HandleFilterWindowSize"])); + } + set { + this["HandleFilterWindowSize"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("204, 187, 255")] + public global::System.Drawing.Color ColorDebuggedProcesses { + get { + return ((global::System.Drawing.Color)(this["ColorDebuggedProcesses"])); + } + set { + this["ColorDebuggedProcesses"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("204, 255, 255")] + public global::System.Drawing.Color ColorServiceProcesses { + get { + return ((global::System.Drawing.Color)(this["ColorServiceProcesses"])); + } + set { + this["ColorServiceProcesses"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string PromptBoxText { + get { + return ((string)(this["PromptBoxText"])); + } + set { + this["PromptBoxText"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string RunAsUsername { + get { + return ((string)(this["RunAsUsername"])); + } + set { + this["RunAsUsername"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string RunAsCommand { + get { + return ((string)(this["RunAsCommand"])); + } + set { + this["RunAsCommand"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("tabPrivileges")] + public string TokenWindowTab { + get { + return ((string)(this["TokenWindowTab"])); + } + set { + this["TokenWindowTab"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool HideWhenMinimized { + get { + return ((bool)(this["HideWhenMinimized"])); + } + set { + this["HideWhenMinimized"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("505, 512")] + public global::System.Drawing.Size ProcessWindowSize { + get { + return ((global::System.Drawing.Size)(this["ProcessWindowSize"])); + } + set { + this["ProcessWindowSize"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool PlotterAntialias { + get { + return ((bool)(this["PlotterAntialias"])); + } + set { + this["PlotterAntialias"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("Lime")] + public global::System.Drawing.Color PlotterCPUKernelColor { + get { + return ((global::System.Drawing.Color)(this["PlotterCPUKernelColor"])); + } + set { + this["PlotterCPUKernelColor"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("Red")] + public global::System.Drawing.Color PlotterCPUUserColor { + get { + return ((global::System.Drawing.Color)(this["PlotterCPUUserColor"])); + } + set { + this["PlotterCPUUserColor"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("Orange")] + public global::System.Drawing.Color PlotterMemoryPrivateColor { + get { + return ((global::System.Drawing.Color)(this["PlotterMemoryPrivateColor"])); + } + set { + this["PlotterMemoryPrivateColor"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("Cyan")] + public global::System.Drawing.Color PlotterMemoryWSColor { + get { + return ((global::System.Drawing.Color)(this["PlotterMemoryWSColor"])); + } + set { + this["PlotterMemoryWSColor"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("Yellow")] + public global::System.Drawing.Color PlotterIOROColor { + get { + return ((global::System.Drawing.Color)(this["PlotterIOROColor"])); + } + set { + this["PlotterIOROColor"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("DarkViolet")] + public global::System.Drawing.Color PlotterIOWColor { + get { + return ((global::System.Drawing.Color)(this["PlotterIOWColor"])); + } + set { + this["PlotterIOWColor"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("Peru")] + public global::System.Drawing.Color ColorJobProcesses { + get { + return ((global::System.Drawing.Color)(this["ColorJobProcesses"])); + } + set { + this["ColorJobProcesses"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool ShowOneGraphPerCPU { + get { + return ((bool)(this["ShowOneGraphPerCPU"])); + } + set { + this["ShowOneGraphPerCPU"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("6")] + public int UnitSpecifier { + get { + return ((int)(this["UnitSpecifier"])); + } + set { + this["UnitSpecifier"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("222, 255, 0")] + public global::System.Drawing.Color ColorDotNetProcesses { + get { + return ((global::System.Drawing.Color)(this["ColorDotNetProcesses"])); + } + set { + this["ColorDotNetProcesses"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("DeepPink")] + public global::System.Drawing.Color ColorPackedProcesses { + get { + return ((global::System.Drawing.Color)(this["ColorPackedProcesses"])); + } + set { + this["ColorPackedProcesses"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool VerifySignatures { + get { + return ((bool)(this["VerifySignatures"])); + } + set { + this["VerifySignatures"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("0,137|1,160|2,71|3,195|4,75|5,80|6,70|")] + public string NetworkListViewColumns { + get { + return ((string)(this["NetworkListViewColumns"])); + } + set { + this["NetworkListViewColumns"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool EnableKPH { + get { + return ((bool)(this["EnableKPH"])); + } + set { + this["EnableKPH"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool StartHidden { + get { + return ((bool)(this["StartHidden"])); + } + set { + this["StartHidden"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("audiodg.exe, csrss.exe, dwm.exe, explorer.exe, logonui.exe, lsass.exe, lsm.exe, n" + + "tkrnlpa.exe, ntoskrnl.exe, procexp.exe, rundll32.exe, services.exe, smss.exe, sp" + + "oolsv.exe, svchost.exe, taskeng.exe, taskmgr.exe, wininit.exe, winlogon.exe")] + public string ImposterNames { + get { + return ((string)(this["ImposterNames"])); + } + set { + this["ImposterNames"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("Microsoft Sans Serif, 8.25pt")] + public global::System.Drawing.Font Font { + get { + return ((global::System.Drawing.Font)(this["Font"])); + } + set { + this["Font"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool HideHandlesWithNoName { + get { + return ((bool)(this["HideHandlesWithNoName"])); + } + set { + this["HideHandlesWithNoName"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string HiddenProcessesColumns { + get { + return ((string)(this["HiddenProcessesColumns"])); + } + set { + this["HiddenProcessesColumns"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("10")] + public int IconMenuProcessCount { + get { + return ((int)(this["IconMenuProcessCount"])); + } + set { + this["IconMenuProcessCount"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool HideWhenClosed { + get { + return ((bool)(this["HideWhenClosed"])); + } + set { + this["HideWhenClosed"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool UseColorOwnProcesses { + get { + return ((bool)(this["UseColorOwnProcesses"])); + } + set { + this["UseColorOwnProcesses"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool UseColorElevatedProcesses { + get { + return ((bool)(this["UseColorElevatedProcesses"])); + } + set { + this["UseColorElevatedProcesses"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool UseColorSystemProcesses { + get { + return ((bool)(this["UseColorSystemProcesses"])); + } + set { + this["UseColorSystemProcesses"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool UseColorDebuggedProcesses { + get { + return ((bool)(this["UseColorDebuggedProcesses"])); + } + set { + this["UseColorDebuggedProcesses"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool UseColorServiceProcesses { + get { + return ((bool)(this["UseColorServiceProcesses"])); + } + set { + this["UseColorServiceProcesses"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool UseColorJobProcesses { + get { + return ((bool)(this["UseColorJobProcesses"])); + } + set { + this["UseColorJobProcesses"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool UseColorDotNetProcesses { + get { + return ((bool)(this["UseColorDotNetProcesses"])); + } + set { + this["UseColorDotNetProcesses"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool UseColorPackedProcesses { + get { + return ((bool)(this["UseColorPackedProcesses"])); + } + set { + this["UseColorPackedProcesses"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool AllowOnlyOneInstance { + get { + return ((bool)(this["AllowOnlyOneInstance"])); + } + set { + this["AllowOnlyOneInstance"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string EnvironmentListViewColumns { + get { + return ((string)(this["EnvironmentListViewColumns"])); + } + set { + this["EnvironmentListViewColumns"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("300, 300")] + public global::System.Drawing.Point LogWindowLocation { + get { + return ((global::System.Drawing.Point)(this["LogWindowLocation"])); + } + set { + this["LogWindowLocation"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("595, 508")] + public global::System.Drawing.Size LogWindowSize { + get { + return ((global::System.Drawing.Size)(this["LogWindowSize"])); + } + set { + this["LogWindowSize"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool ToolbarVisible { + get { + return ((bool)(this["ToolbarVisible"])); + } + set { + this["ToolbarVisible"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("858, 574")] + public global::System.Drawing.Size SysInfoWindowSize { + get { + return ((global::System.Drawing.Size)(this["SysInfoWindowSize"])); + } + set { + this["SysInfoWindowSize"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("100, 100")] + public global::System.Drawing.Point SysInfoWindowLocation { + get { + return ((global::System.Drawing.Point)(this["SysInfoWindowLocation"])); + } + set { + this["SysInfoWindowLocation"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool NeedsUpgrade { + get { + return ((bool)(this["NeedsUpgrade"])); + } + set { + this["NeedsUpgrade"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("600")] + public int MaxSamples { + get { + return ((int)(this["MaxSamples"])); + } + set { + this["MaxSamples"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("2")] + public int PlotterStep { + get { + return ((int)(this["PlotterStep"])); + } + set { + this["PlotterStep"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string ServiceMiniListColumns { + get { + return ((string)(this["ServiceMiniListColumns"])); + } + set { + this["ServiceMiniListColumns"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("Silver")] + public global::System.Drawing.Color ColorSuspended { + get { + return ((global::System.Drawing.Color)(this["ColorSuspended"])); + } + set { + this["ColorSuspended"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool UseColorSuspended { + get { + return ((bool)(this["UseColorSuspended"])); + } + set { + this["UseColorSuspended"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("255, 255, 128")] + public global::System.Drawing.Color ColorGuiThreads { + get { + return ((global::System.Drawing.Color)(this["ColorGuiThreads"])); + } + set { + this["ColorGuiThreads"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool UseColorGuiThreads { + get { + return ((bool)(this["UseColorGuiThreads"])); + } + set { + this["UseColorGuiThreads"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("dbghelp.dll")] + public string DbgHelpPath { + get { + return ((string)(this["DbgHelpPath"])); + } + set { + this["DbgHelpPath"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string DbgHelpSearchPath { + get { + return ((string)(this["DbgHelpSearchPath"])); + } + set { + this["DbgHelpSearchPath"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool DbgHelpUndecorate { + get { + return ((bool)(this["DbgHelpUndecorate"])); + } + set { + this["DbgHelpUndecorate"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool DbgHelpWarningShown { + get { + return ((bool)(this["DbgHelpWarningShown"])); + } + set { + this["DbgHelpWarningShown"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("Gray")] + public global::System.Drawing.Color ColorProtectedHandles { + get { + return ((global::System.Drawing.Color)(this["ColorProtectedHandles"])); + } + set { + this["ColorProtectedHandles"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool UseColorProtectedHandles { + get { + return ((bool)(this["UseColorProtectedHandles"])); + } + set { + this["UseColorProtectedHandles"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("128, 255, 255")] + public global::System.Drawing.Color ColorInheritHandles { + get { + return ((global::System.Drawing.Color)(this["ColorInheritHandles"])); + } + set { + this["ColorInheritHandles"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool UseColorInheritHandles { + get { + return ((bool)(this["UseColorInheritHandles"])); + } + set { + this["UseColorInheritHandles"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("200, 200")] + public global::System.Drawing.Point ProcessWindowLocation { + get { + return ((global::System.Drawing.Point)(this["ProcessWindowLocation"])); + } + set { + this["ProcessWindowLocation"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool CpuHistoryIconVisible { + get { + return ((bool)(this["CpuHistoryIconVisible"])); + } + set { + this["CpuHistoryIconVisible"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool IoHistoryIconVisible { + get { + return ((bool)(this["IoHistoryIconVisible"])); + } + set { + this["IoHistoryIconVisible"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool CpuUsageIconVisible { + get { + return ((bool)(this["CpuUsageIconVisible"])); + } + set { + this["CpuUsageIconVisible"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool CommitHistoryIconVisible { + get { + return ((bool)(this["CommitHistoryIconVisible"])); + } + set { + this["CommitHistoryIconVisible"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool PhysMemHistoryIconVisible { + get { + return ((bool)(this["PhysMemHistoryIconVisible"])); + } + set { + this["PhysMemHistoryIconVisible"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("200, 200")] + public global::System.Drawing.Point HandleFilterWindowLocation { + get { + return ((global::System.Drawing.Point)(this["HandleFilterWindowLocation"])); + } + set { + this["HandleFilterWindowLocation"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("200, 200")] + public global::System.Drawing.Point HiddenProcessesWindowLocation { + get { + return ((global::System.Drawing.Point)(this["HiddenProcessesWindowLocation"])); + } + set { + this["HiddenProcessesWindowLocation"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("527, 429")] + public global::System.Drawing.Size HiddenProcessesWindowSize { + get { + return ((global::System.Drawing.Size)(this["HiddenProcessesWindowSize"])); + } + set { + this["HiddenProcessesWindowSize"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool HideProcessHackerNetworkConnections { + get { + return ((bool)(this["HideProcessHackerNetworkConnections"])); + } + set { + this["HideProcessHackerNetworkConnections"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool EnableExperimentalFeatures { + get { + return ((bool)(this["EnableExperimentalFeatures"])); + } + set { + this["EnableExperimentalFeatures"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("565, 377")] + public global::System.Drawing.Size InformationBoxSize { + get { + return ((global::System.Drawing.Size)(this["InformationBoxSize"])); + } + set { + this["InformationBoxSize"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool ScrollDownProcessTree { + get { + return ((bool)(this["ScrollDownProcessTree"])); + } + set { + this["ScrollDownProcessTree"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("DarkSlateBlue")] + public global::System.Drawing.Color ColorPosixProcesses { + get { + return ((global::System.Drawing.Color)(this["ColorPosixProcesses"])); + } + set { + this["ColorPosixProcesses"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool UseColorPosixProcesses { + get { + return ((bool)(this["UseColorPosixProcesses"])); + } + set { + this["UseColorPosixProcesses"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool LogWindowAutoScroll { + get { + return ((bool)(this["LogWindowAutoScroll"])); + } + set { + this["LogWindowAutoScroll"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool FloatChildWindows { + get { + return ((bool)(this["FloatChildWindows"])); + } + set { + this["FloatChildWindows"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool FirstRun { + get { + return ((bool)(this["FirstRun"])); + } + set { + this["FirstRun"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("255, 192, 128")] + public global::System.Drawing.Color ColorRelocatedDlls { + get { + return ((global::System.Drawing.Color)(this["ColorRelocatedDlls"])); + } + set { + this["ColorRelocatedDlls"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool UseColorRelocatedDlls { + get { + return ((bool)(this["UseColorRelocatedDlls"])); + } + set { + this["UseColorRelocatedDlls"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("RosyBrown")] + public global::System.Drawing.Color ColorWow64Processes { + get { + return ((global::System.Drawing.Color)(this["ColorWow64Processes"])); + } + set { + this["ColorWow64Processes"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool UseColorWow64Processes { + get { + return ((bool)(this["UseColorWow64Processes"])); + } + set { + this["UseColorWow64Processes"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("0")] + public int AppUpdateLevel { + get { + return ((int)(this["AppUpdateLevel"])); + } + set { + this["AppUpdateLevel"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("http://processhacker.sourceforge.net/AppUpdate.xml")] + public string AppUpdateUrl { + get { + return ((string)(this["AppUpdateUrl"])); + } + set { + this["AppUpdateUrl"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("1")] + public int ToolStripDisplayStyle { + get { + return ((int)(this["ToolStripDisplayStyle"])); + } + set { + this["ToolStripDisplayStyle"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool AppUpdateAutomatic { + get { + return ((bool)(this["AppUpdateAutomatic"])); + } + set { + this["AppUpdateAutomatic"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("1")] + public int ElevationLevel { + get { + return ((int)(this["ElevationLevel"])); + } + set { + this["ElevationLevel"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool ProxyUse { + get { + return ((bool)(this["ProxyUse"])); + } + set { + this["ProxyUse"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool ProxyBypassOnLocal { + get { + return ((bool)(this["ProxyBypassOnLocal"])); + } + set { + this["ProxyBypassOnLocal"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string ProxyUsername { + get { + return ((string)(this["ProxyUsername"])); + } + set { + this["ProxyUsername"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string ProxyPassword { + get { + return ((string)(this["ProxyPassword"])); + } + set { + this["ProxyPassword"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string ProxyAddress { + get { + return ((string)(this["ProxyAddress"])); + } + set { + this["ProxyAddress"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string ProxyPort { + get { + return ((string)(this["ProxyPort"])); + } + set { + this["ProxyPort"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("False")] + public bool ProxyUseCredentials { + get { + return ((bool)(this["ProxyUseCredentials"])); + } + set { + this["ProxyUseCredentials"] = value; + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Properties/Settings.settings b/branches/ph-plugins/ProcessHacker/Properties/Settings.settings new file mode 100644 index 000000000..c0d3d4233 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Properties/Settings.settings @@ -0,0 +1,435 @@ + + + + + + 1000 + + + 844, 550 + + + 200, 200 + + + 355 + + + Normal + + + False + + + &String Scan... + + + False + + + True + + + + + + + + + 504, 482 + + + 0,115|1,80|2,70|3,188| + + + + + + 791, 503 + + + + + + tabGeneral + + + + + + + + + 481, 468 + + + 439, 413 + + + + + + + + + + + + + + + + + + + + + http://www.google.com/search?q=%s + + + Chartreuse + + + 255, 60, 40 + + + 255, 255, 170 + + + 255, 170, 0 + + + 170, 204, 255 + + + 1000 + + + False + + + 415, 503 + + + + + + False + + + False + + + False + + + True + + + False + + + False + + + True + + + 0,150|1,300|2,120|3,80|4,80|5,60| + + + + + + + + + 554, 463 + + + 204, 187, 255 + + + 204, 255, 255 + + + + + + + + + + + + tabPrivileges + + + False + + + 505, 512 + + + False + + + Lime + + + Red + + + Orange + + + Cyan + + + Yellow + + + DarkViolet + + + Peru + + + False + + + 6 + + + 222, 255, 0 + + + DeepPink + + + False + + + 0,137|1,160|2,71|3,195|4,75|5,80|6,70| + + + True + + + False + + + audiodg.exe, csrss.exe, dwm.exe, explorer.exe, logonui.exe, lsass.exe, lsm.exe, ntkrnlpa.exe, ntoskrnl.exe, procexp.exe, rundll32.exe, services.exe, smss.exe, spoolsv.exe, svchost.exe, taskeng.exe, taskmgr.exe, wininit.exe, winlogon.exe + + + Microsoft Sans Serif, 8.25pt + + + True + + + + + + 10 + + + False + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + False + + + + + + 300, 300 + + + 595, 508 + + + False + + + 858, 574 + + + 100, 100 + + + True + + + 600 + + + 2 + + + + + + Silver + + + True + + + 255, 255, 128 + + + True + + + dbghelp.dll + + + + + + True + + + False + + + Gray + + + True + + + 128, 255, 255 + + + True + + + 200, 200 + + + True + + + False + + + False + + + False + + + False + + + 200, 200 + + + 200, 200 + + + 527, 429 + + + True + + + False + + + 565, 377 + + + False + + + DarkSlateBlue + + + True + + + False + + + True + + + True + + + 255, 192, 128 + + + True + + + RosyBrown + + + True + + + 0 + + + http://processhacker.sourceforge.net/AppUpdate.xml + + + 1 + + + True + + + 1 + + + False + + + False + + + + + + + + + + + + + + + False + + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/Providers/HandleProvider.cs b/branches/ph-plugins/ProcessHacker/Providers/HandleProvider.cs new file mode 100644 index 000000000..8a013f8ab --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Providers/HandleProvider.cs @@ -0,0 +1,147 @@ +/* + * Process Hacker - + * handle provider + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; + +namespace ProcessHacker +{ + public class HandleItem : ICloneable + { + public object Clone() + { + return this.MemberwiseClone(); + } + + public int RunId; + public SystemHandleEntry Handle; + public ObjectInformation ObjectInfo; + } + + public class HandleProvider : Provider + { + private ProcessHandle _processHandle; + private int _pid; + + public HandleProvider(int pid) + : base() + { + this.Name = this.GetType().Name; + _pid = pid; + + try + { + _processHandle = new ProcessHandle(_pid, ProcessHacker.Native.Security.ProcessAccess.DupHandle); + } + catch + { + try + { + _processHandle = new ProcessHandle(_pid, Program.MinProcessGetHandleInformationRights); + } + catch + { } + } + + this.ProviderUpdate += new ProviderUpdateOnce(UpdateOnce); + this.Disposed += (provider) => { if (_processHandle != null) _processHandle.Dispose(); }; + } + + private void UpdateOnce() + { + var handles = Windows.GetHandles(); + var processHandles = new Dictionary(); + var newdictionary = new Dictionary(this.Dictionary); + + foreach (var handle in handles) + { + if (handle.ProcessId == _pid) + { + processHandles.Add(handle.Handle, handle); + } + } + + // look for closed handles + foreach (short h in this.Dictionary.Keys) + { + // If a handle now points to a different object, force a re-add. + if (!processHandles.ContainsKey(h) || + processHandles[h].Object != this.Dictionary[h].Handle.Object) + { + this.OnDictionaryRemoved(this.Dictionary[h]); + newdictionary.Remove(h); + } + } + + // look for new handles + foreach (short h in processHandles.Keys) + { + if (!this.Dictionary.ContainsKey(h)) + { + ObjectInformation info; + HandleItem item = new HandleItem(); + + try + { + info = processHandles[h].GetHandleInfo(_processHandle); + + if ((info.BestName == null || info.BestName == "") && + HideHandlesWithNoName) + continue; + } + catch + { + continue; + } + + item.RunId = this.RunCount; + item.Handle = processHandles[h]; + item.ObjectInfo = info; + + newdictionary.Add(h, item); + this.OnDictionaryAdded(item); + } + else + { + // check if the handle has been modified + if (this.Dictionary[h].Handle.Flags != processHandles[h].Flags) + { + this.Dictionary[h].Handle.Flags = processHandles[h].Flags; + this.OnDictionaryModified(null, this.Dictionary[h]); + } + } + } + + this.Dictionary = newdictionary; + } + + public bool HideHandlesWithNoName { get; set; } + + public int Pid + { + get { return _pid; } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Providers/Internal/IProvider.cs b/branches/ph-plugins/ProcessHacker/Providers/Internal/IProvider.cs new file mode 100644 index 000000000..519792ee2 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Providers/Internal/IProvider.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker +{ + public interface IProvider + { + event Action Disposed; + bool Busy { get; } + bool CreateThread { get; set; } + bool Enabled { get; set; } + void RunOnce(); + void RunOnceAsync(); + void InterlockedExecute(Delegate action, params object[] args); + void InterlockedExecute(Delegate action, int timeout, params object[] args); + void Wait(); + bool Wait(int timeout); + } +} diff --git a/branches/ph-plugins/ProcessHacker/Providers/Internal/Provider.cs b/branches/ph-plugins/ProcessHacker/Providers/Internal/Provider.cs new file mode 100644 index 000000000..bcfb3bdff --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Providers/Internal/Provider.cs @@ -0,0 +1,400 @@ +/* + * Process Hacker - + * provider base class + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Threading; +using ProcessHacker.Common; +using ProcessHacker.Common.Objects; + +namespace ProcessHacker +{ + /// + /// Provides services for continuously updating a dictionary. + /// + public abstract class Provider : BaseObject, IProvider + { + /// + /// A generic delegate which is used when updating the dictionary. + /// + public delegate void ProviderUpdateOnce(); + + /// + /// Represents a handler called when a dictionary item is added. + /// + /// The added item. + public delegate void ProviderDictionaryAdded(TValue item); + + /// + /// Represents a handler called when a dictionary item is modified. + /// + /// The modified item. + public delegate void ProviderDictionaryModified(TValue oldItem, TValue newItem); + + /// + /// Represents a handler called when a dictionary item is removed. + /// + /// The removed item. + public delegate void ProviderDictionaryRemoved(TValue item); + + /// + /// Represents a handler called when an error occurs while updating. + /// + /// The raised exception. + public delegate void ProviderError(Exception ex); + + /// + /// Occurs when the provider needs to update the dictionary (after waiting the duration of the interval). + /// + protected event ProviderUpdateOnce ProviderUpdate; + + public new event Action Disposed; + + public event ProviderUpdateOnce BeforeUpdate; + + /// + /// Occurs when the provider has been updated. + /// + public event ProviderUpdateOnce Updated; + + /// + /// Occurs when the provider adds an item to the dictionary. + /// + public event ProviderDictionaryAdded DictionaryAdded; + + /// + /// Occurs when the provider modifies an item in the dictionary. + /// + public event ProviderDictionaryModified DictionaryModified; + + /// + /// Occurs when the provider removes an item from the dictionary. + /// + public event ProviderDictionaryRemoved DictionaryRemoved; + + /// + /// Occurs when an exception is raised while updating. + /// + public event ProviderError Error; + + private string _name = string.Empty; + private Thread _thread; + private IDictionary _dictionary; + + private object _busyLock = new object(); + private bool _disposing = false; + private bool _busy = false; + private bool _createThread = true; + private bool _enabled = false; + private int _runCount = 0; + private int _interval; + + /// + /// Creates a new instance of the Provider class. + /// + public Provider() + : this(new Dictionary()) + { } + + /// + /// Creates a new instance of the Provider class, specifying a + /// custom equality comparer. + /// + public Provider(IEqualityComparer comparer) + : this(new Dictionary(comparer)) + { } + + /// + /// Creates a new instance of the Provider class, specifying a + /// custom instance. + /// + public Provider(IDictionary dictionary) + { + if (dictionary == null) + throw new ArgumentNullException("dictionary"); + + _dictionary = dictionary; + } + + protected override void DisposeObject(bool disposing) + { + Logging.Log(Logging.Importance.Information, "Provider (" + this.Name + "): disposing (" + disposing.ToString() + ")"); + + _disposing = true; + + if (disposing) + Monitor.Enter(_busyLock); + + //if (_thread != null) + //{ + // _thread.Abort(); + // _thread = null; + //} + + if (this.Disposed != null) + { + try + { + this.Disposed(this); + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + + if (disposing) + Monitor.Exit(_busyLock); + + Logging.Log(Logging.Importance.Information, "Provider (" + this.Name + "): finished disposing (" + disposing.ToString() + ")"); + } + + public string Name + { + get { return _name; } + protected set + { + _name = value; + if (_name == null) + _name = string.Empty; + } + } + + /// + /// Determines whether the provider is currently updating. + /// + public bool Busy + { + get { return _busy; } + } + + /// + /// If enabled, the provider manages a background thread for the updater. + /// + public bool CreateThread + { + get { return _createThread; } + set { _createThread = value; } + } + + /// + /// Determines whether the provider should update. + /// + public bool Enabled + { + get { return _enabled; } + set + { + _enabled = value; + + if (_enabled && _createThread && _thread == null) + { + _thread = new Thread(new ThreadStart(Update)); + _thread.IsBackground = true; + _thread.SetApartmentState(ApartmentState.STA); + _thread.Start(); + _thread.Priority = ThreadPriority.Lowest; + } + } + } + + /// + /// Gets the number of times this provider has updated. + /// + public int RunCount + { + get { return _runCount; } + } + + /// + /// Gets or sets the interval to wait between each update. + /// + public int Interval + { + get { return _interval; } + set { _interval = value; } + } + + /// + /// Gets the dictionary. + /// + public IDictionary Dictionary + { + get { return _dictionary; } + protected set { _dictionary = value; } + } + + /// + /// Updates the provider if it is enabled. + /// + private void Update() + { + while (true) + { + if (_enabled && !_disposing) + { + this.RunOnce(); + } + + Thread.Sleep(_interval); + } + } + + /// + /// Updates the provider. If it is already updating, this function waits until it finishes. + /// + public void RunOnce() + { + lock (_busyLock) + { + // Bail out if we are disposing + if (_disposing) + { + Logging.Log(Logging.Importance.Warning, "Provider (" + _name + "): RunOnce: currently disposing"); + return; + } + + _busy = true; + + if (ProviderUpdate != null) + { + try + { + if (BeforeUpdate != null) + BeforeUpdate(); + } + catch + { } + + try + { + ProviderUpdate(); + _runCount++; + } + catch (Exception ex) + { + try + { + if (Error != null) + Error(ex); + } + catch + { } + + Logging.Log(ex); + } + + try + { + if (Updated != null) + Updated(); + } + catch + { } + } + + _busy = false; + } + } + + /// + /// Updates the provider in an internal worker thread. + /// + public void RunOnceAsync() + { + WorkQueue.GlobalQueueWorkItemTag(new Action(this.RunOnce), "provider-runonceasync"); + } + + /// + /// Executes code as soon as no updater is running. + /// + public void InterlockedExecute(Delegate action, params object[] args) + { + this.InterlockedExecute(action, -1, args); + } + + /// + /// Executes code as soon as no updater is running. + /// + public void InterlockedExecute(Delegate action, int timeout, params object[] args) + { + lock (_busyLock) + action.DynamicInvoke(args); + } + + /// + /// Waits for the current update process to finish. If an update process is not currently + /// running, this function returns immediately. + /// + public void Wait() + { + this.Wait(-1); + } + + /// + /// Waits for the current update process to finish. If an update process is not currently + /// running, this function returns immediately. You may specify a timeout for the wait. + /// + /// The time in milliseconds to wait for the update process to finish. + /// Whether the update process was finished before the timeout. + public bool Wait(int timeout) + { + if (Monitor.TryEnter(_busyLock, timeout)) + { + Monitor.Exit(_busyLock); + return true; + } + + return false; + } + + private void CallEvent(Delegate e, params object[] args) + { + if (e != null) + { + try + { + e.DynamicInvoke(args); + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + } + + protected void OnDictionaryAdded(TValue item) + { + this.CallEvent(this.DictionaryAdded, item); + } + + protected void OnDictionaryModified(TValue oldItem, TValue newItem) + { + this.CallEvent(this.DictionaryModified, oldItem, newItem); + } + + protected void OnDictionaryRemoved(TValue item) + { + this.CallEvent(this.DictionaryRemoved, item); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Providers/Internal/SharedThreadProvider.cs b/branches/ph-plugins/ProcessHacker/Providers/Internal/SharedThreadProvider.cs new file mode 100644 index 000000000..e6823aaff --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Providers/Internal/SharedThreadProvider.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Threading; + +namespace ProcessHacker +{ + public class SharedThreadProvider : IDisposable + { + private object _disposeLock = new object(); + private bool _disposed; + private List _providers = new List(); + private Thread _thread; + private int _interval; + + public SharedThreadProvider(int interval) + { + _interval = interval; + _thread = new Thread(new ThreadStart(this.Update)); + _thread.IsBackground = true; + _thread.SetApartmentState(ApartmentState.STA); + _thread.Start(); + _thread.Priority = ThreadPriority.Lowest; + } + + ~SharedThreadProvider() + { + this.Dispose(false); + } + + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool disposing) + { + try + { + if (disposing) + { + Monitor.Enter(_disposeLock); + Monitor.Enter(_providers); + } + + if (!_disposed) + { + _thread.Abort(); + _thread = null; + + IProvider[] providers = _providers.ToArray(); + + foreach (IProvider provider in providers) + this.Remove(provider); + + _disposed = true; + } + } + finally + { + if (disposing) + { + Monitor.Exit(_disposeLock); + Monitor.Exit(_providers); + } + } + } + + public int Count + { + get { return _providers.Count; } + } + + public ReadOnlyCollection Providers + { + get { return new ReadOnlyCollection(_providers); } + } + + public int Interval + { + get { return _interval; } + set { _interval = value; } + } + + public void Add(IProvider provider) + { + provider.CreateThread = false; + provider.Disposed += provider_Disposed; + + lock (_providers) + _providers.Add(provider); + } + + public void Remove(IProvider provider) + { + lock (_providers) + _providers.Remove(provider); + + provider.CreateThread = true; + provider.Disposed -= provider_Disposed; + } + + private void provider_Disposed(IProvider provider) + { + if (_providers.Contains(provider)) + this.Remove(provider); + } + + private void Update() + { + while (true) + { + IProvider[] providers; + + lock (_providers) + providers = _providers.ToArray(); + + foreach (var provider in providers) + if (provider.Enabled) + provider.RunOnce(); + + Thread.Sleep(_interval); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Providers/MemoryProvider.cs b/branches/ph-plugins/ProcessHacker/Providers/MemoryProvider.cs new file mode 100644 index 000000000..f05b32bcf --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Providers/MemoryProvider.cs @@ -0,0 +1,177 @@ +/* + * Process Hacker - + * memory provider + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker +{ + public class MemoryItem : ICloneable + { + public object Clone() + { + return this.MemberwiseClone(); + } + + public int RunId; + public IntPtr Address; + public string ModuleName; + public long Size; + public MemoryType Type; + public MemoryState State; + public MemoryProtection Protection; + + } + + public class MemoryProvider : Provider + { + private ProcessHandle _processHandle; + private int _pid; + + public MemoryProvider(int pid) + : base() + { + this.Name = this.GetType().Name; + _pid = pid; + + try + { + _processHandle = new ProcessHandle(_pid, ProcessAccess.QueryInformation | + Program.MinProcessReadMemoryRights); + } + catch + { } + + this.ProviderUpdate += new ProviderUpdateOnce(UpdateOnce); + this.Disposed += (provider) => { if (_processHandle != null) _processHandle.Dispose(); }; + } + + private void UpdateOnce() + { + var modules = new Dictionary(); + + try + { + foreach (var m in _processHandle.GetModules()) + modules.Add(m.BaseAddress, m); + } + catch + { } + + var memoryInfo = new Dictionary(); + var newdictionary = new Dictionary(this.Dictionary); + + _processHandle.EnumMemory((info) => + { + if ((this.IgnoreFreeRegions && info.State != MemoryState.Free) || + !this.IgnoreFreeRegions) + memoryInfo.Add(info.BaseAddress, info); + + return true; + }); + + // look for freed memory regions + foreach (IntPtr address in Dictionary.Keys) + { + if (!memoryInfo.ContainsKey(address)) + { + this.OnDictionaryRemoved(this.Dictionary[address]); + newdictionary.Remove(address); + } + } + + string lastModuleName = null; + IntPtr lastModuleAddress = IntPtr.Zero; + int lastModuleSize = 0; + + foreach (IntPtr address in memoryInfo.Keys) + { + var info = memoryInfo[address]; + + if (!this.Dictionary.ContainsKey(address)) + { + MemoryItem item = new MemoryItem(); + + item.RunId = this.RunCount; + item.Address = address; + item.Size = info.RegionSize.ToInt64(); + item.Type = info.Type; + item.State = info.State; + item.Protection = info.Protect; + + if (modules.ContainsKey(item.Address)) + { + lastModuleName = modules[item.Address].BaseName; + lastModuleAddress = modules[item.Address].BaseAddress; + lastModuleSize = modules[item.Address].Size; + } + + if ( + item.Address.IsGreaterThanOrEqualTo(lastModuleAddress) && + item.Address.CompareTo(lastModuleAddress.Increment(lastModuleSize)) == -1 + ) + item.ModuleName = lastModuleName; + else + item.ModuleName = null; + + newdictionary.Add(address, item); + this.OnDictionaryAdded(item); + } + else + { + MemoryItem item = this.Dictionary[address]; + + if ( + info.RegionSize.ToInt64() != item.Size || + info.Type != item.Type || + info.State != item.State || + info.Protect != item.Protection + ) + { + MemoryItem newitem = item.Clone() as MemoryItem; + + newitem.Size = info.RegionSize.ToInt64(); + newitem.Type = info.Type; + newitem.State = info.State; + newitem.Protection = info.Protect; + + newdictionary[address] = newitem; + this.OnDictionaryModified(item, newitem); + } + } + } + + this.Dictionary = newdictionary; + } + + public bool IgnoreFreeRegions { get; set; } + + public int Pid + { + get { return _pid; } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Providers/ModuleProvider.cs b/branches/ph-plugins/ProcessHacker/Providers/ModuleProvider.cs new file mode 100644 index 000000000..3f492d1b3 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Providers/ModuleProvider.cs @@ -0,0 +1,243 @@ +/* + * Process Hacker - + * module provider + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using ProcessHacker.Common; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Debugging; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker +{ + public class ModuleItem : ICloneable + { + public object Clone() + { + return this.MemberwiseClone(); + } + + public int RunId; + public IntPtr BaseAddress; + public int Size; + public LdrpDataTableEntryFlags Flags; + public string Name; + public string FileName; + public string FileDescription; + public string FileVersion; + } + + public class ModuleProvider : Provider + { + private ProcessHandle _processHandle; + private int _pid; + private bool _isWow64 = false; + + public ModuleProvider(int pid) + : base() + { + this.Name = this.GetType().Name; + _pid = pid; + + try + { + _processHandle = new ProcessHandle(_pid, + ProcessAccess.QueryInformation | Program.MinProcessReadMemoryRights); + } + catch + { + try + { + _processHandle = new ProcessHandle(_pid, + Program.MinProcessQueryRights | Program.MinProcessReadMemoryRights); + } + catch + { } + } + + if (_processHandle != null && IntPtr.Size == 8) + { + try + { + _isWow64 = _processHandle.IsWow64(); + } + catch + { } + } + + this.ProviderUpdate += new ProviderUpdateOnce(UpdateOnce); + this.Disposed += (provider) => { if (_processHandle != null) _processHandle.Dispose(); }; + } + + private void UpdateOnce() + { + if (_pid != 4 && _processHandle == null) + { + Logging.Log(Logging.Importance.Warning, "ModuleProvider: Process Handle is null, exiting..."); + return; + } + + var modules = new Dictionary(); + var newdictionary = new Dictionary(this.Dictionary); + + if (_pid != 4) + { + // Is this a WOW64 process? If it is, get the 32-bit modules. + if (!_isWow64) + { + _processHandle.EnumModules((module) => + { + if (!modules.ContainsKey(module.BaseAddress)) + modules.Add(module.BaseAddress, module); + + return true; + }); + } + else + { + using (DebugBuffer buffer = new DebugBuffer()) + { + buffer.Query(_pid, RtlQueryProcessDebugFlags.Modules32); + + var processModules = buffer.GetModules(); + + foreach (var m in processModules) + { + // Most of the time we will get a duplicate entry - + // the main executable image. Guard against that. + if (!modules.ContainsKey(m.BaseAddress)) + { + modules.Add( + m.BaseAddress, + new ProcessModule( + m.BaseAddress, + m.Size, + IntPtr.Zero, + m.Flags, + System.IO.Path.GetFileName(m.FileName), + m.FileName + ) + ); + } + } + } + } + + // add mapped files + _processHandle.EnumMemory((info) => + { + if (info.Type == MemoryType.Mapped) + { + try + { + string fileName = _processHandle.GetMappedFileName(info.BaseAddress); + + if (fileName != null) + { + var fi = new System.IO.FileInfo(fileName); + + modules.Add(info.BaseAddress, + new ProcessModule( + info.BaseAddress, + info.RegionSize.ToInt32(), + IntPtr.Zero, + 0, + fi.Name, fi.FullName)); + } + } + catch + { } + } + + return true; + }); + } + else + { + // Add loaded kernel modules. + Windows.EnumKernelModules((module) => + { + if (!modules.ContainsKey(module.BaseAddress)) + modules.Add(module.BaseAddress, module); + + return true; + }); + } + + // look for unloaded modules + foreach (IntPtr b in Dictionary.Keys) + { + if (!modules.ContainsKey(b)) + { + this.OnDictionaryRemoved(this.Dictionary[b]); + newdictionary.Remove(b); + } + } + + // look for new modules + foreach (IntPtr b in modules.Keys) + { + if (!Dictionary.ContainsKey(b)) + { + var m = modules[b]; + ModuleItem item = new ModuleItem(); + + item.RunId = this.RunCount; + item.Name = m.BaseName; + + try + { + item.FileName = FileUtils.GetFileName(m.FileName); + } + catch + { } + + item.BaseAddress = b; + item.Size = m.Size; + item.Flags = m.Flags; + + try + { + var info = System.Diagnostics.FileVersionInfo.GetVersionInfo(item.FileName); + + item.FileDescription = info.FileDescription; + item.FileVersion = info.FileVersion; + } + catch + { } + + newdictionary.Add(b, item); + this.OnDictionaryAdded(item); + } + } + + this.Dictionary = newdictionary; + } + + public int Pid + { + get { return _pid; } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Providers/NetworkProvider.cs b/branches/ph-plugins/ProcessHacker/Providers/NetworkProvider.cs new file mode 100644 index 000000000..027b43177 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Providers/NetworkProvider.cs @@ -0,0 +1,270 @@ +/* + * Process Hacker - + * network provider + * + * Copyright (C) 2009 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 . + */ + +// 'member' is obsolete: 'text' +#pragma warning disable 0618 + +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using ProcessHacker.Common; +using ProcessHacker.Common.Messaging; +using ProcessHacker.Native; + +namespace ProcessHacker +{ + public class NetworkItem : ICloneable + { + public object Clone() + { + return this.MemberwiseClone(); + } + + public int Tag; + public string Id; + public NetworkConnection Connection; + public string LocalString; + public string RemoteString; + public bool LocalTouched; + public bool RemoteTouched; + public bool JustProcessed; + } + + public class NetworkProvider : Provider + { + private class AddressResolveMessage : Message + { + public string Id; + public bool Remote; + public string HostName; + } + + private MessageQueue _messageQueue = new MessageQueue(); + private Dictionary _resolveCache = new Dictionary(); + + public NetworkProvider() + : base() + { + this.Name = this.GetType().Name; + this.ProviderUpdate += new ProviderUpdateOnce(UpdateOnce); + + _messageQueue.AddListener( + new MessageQueueListener((message) => + { + if (Dictionary.ContainsKey(message.Id)) + { + var item = Dictionary[message.Id]; + + if (message.Remote) + item.RemoteString = message.HostName; + else + item.LocalString = message.HostName; + + item.JustProcessed = true; + } + })); + } + + private void UpdateOnce() + { + var networkDict = Windows.GetNetworkConnections(); + var preKeyDict = new Dictionary>(); + var keyDict = new Dictionary(); + Dictionary newDict = + new Dictionary(this.Dictionary); + + // Flattens list, assigns IDs and counts + foreach (var list in networkDict.Values) + { + foreach (var connection in list) + { + if (connection.Pid == Program.CurrentProcessId && + Properties.Settings.Default.HideProcessHackerNetworkConnections) + continue; + + string id = connection.Pid.ToString() + "-" + connection.Local.ToString() + "-" + + (connection.Remote != null ? connection.Remote.ToString() : "") + "-" + connection.Protocol.ToString(); + + if (preKeyDict.ContainsKey(id)) + preKeyDict[id] = new KeyValuePair( + preKeyDict[id].Key + 1, preKeyDict[id].Value); + else + preKeyDict.Add(id, new KeyValuePair(1, connection)); + } + } + + // Merges counts into IDs + foreach (string s in preKeyDict.Keys) + { + var connection = preKeyDict[s].Value; + NetworkItem item = new NetworkItem(); + + item.Id = s + "-" + preKeyDict[s].Key.ToString(); + item.Connection = connection; + keyDict.Add(s + "-" + preKeyDict[s].Key.ToString(), item); + } + + foreach (var connection in this.Dictionary.Values) + { + if (!keyDict.ContainsKey(connection.Id)) + { + OnDictionaryRemoved(connection); + newDict.Remove(connection.Id); + } + } + + // Get resolve results. + _messageQueue.Listen(); + + foreach (var connection in keyDict.Values) + { + if (!this.Dictionary.ContainsKey(connection.Id)) + { + connection.Tag = this.RunCount; + + // Resolve the IP addresses. + if (connection.Connection.Local != null) + { + if (!connection.Connection.Local.Address.GetAddressBytes().IsEmpty()) + { + // See if IP address is in the cache. + lock (_resolveCache) + { + if (_resolveCache.ContainsKey(connection.Connection.Local.Address)) + { + // We have the resolved address. + connection.LocalString = _resolveCache[connection.Connection.Local.Address]; + } + else + { + // Queue for resolve. + WorkQueue.GlobalQueueWorkItemTag( + new Action(this.ResolveAddresses), + "network-resolve-local", + connection.Id, + false, + connection.Connection.Local.Address + ); + } + } + } + } + + if (connection.Connection.Remote != null) + { + if (!connection.Connection.Remote.Address.GetAddressBytes().IsEmpty()) + { + lock (_resolveCache) + { + if (_resolveCache.ContainsKey(connection.Connection.Remote.Address)) + { + // We have the resolved address. + connection.RemoteString = _resolveCache[connection.Connection.Remote.Address]; + } + else + { + WorkQueue.GlobalQueueWorkItemTag( + new Action(this.ResolveAddresses), + "network-resolve-remote", + connection.Id, + true, + connection.Connection.Remote.Address + ); + } + } + } + } + + // Update the dictionary. + newDict.Add(connection.Id, connection); + OnDictionaryAdded(connection); + } + else + { + if ( + connection.Connection.State != Dictionary[connection.Id].Connection.State || + Dictionary[connection.Id].JustProcessed + ) + { + NetworkItem oldConnection = Dictionary[connection.Id].Clone() as NetworkItem; + + newDict[connection.Id].Connection.State = connection.Connection.State; + newDict[connection.Id].JustProcessed = false; + + OnDictionaryModified(oldConnection, newDict[connection.Id]); + } + } + } + + this.Dictionary = newDict; + } + + private void ResolveAddresses(string id, bool remote, IPAddress address) + { + string hostName = null; + bool inCache = false; + + // Last minute check of the cache. + lock (_resolveCache) + { + if (_resolveCache.ContainsKey(address)) + { + hostName = _resolveCache[address]; + inCache = true; + } + } + + // If it wasn't in the cache, resolve the address. + if (!inCache) + { + try + { + hostName = Dns.GetHostEntry(address).HostName; + } + catch (SocketException) + { + // Host was not found. + return; + } + + // Update the cache. + lock (_resolveCache) + { + // Add the name if not present already. + if (!string.IsNullOrEmpty(hostName)) + { + if (!_resolveCache.ContainsKey(address)) + _resolveCache.Add(address, hostName); + } + } + } + + _messageQueue.Enqueue(new AddressResolveMessage() + { + Id = id, + Remote = remote, + HostName = hostName + }); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Providers/ProcessSystemProvider.cs b/branches/ph-plugins/ProcessHacker/Providers/ProcessSystemProvider.cs new file mode 100644 index 000000000..19ff24f43 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Providers/ProcessSystemProvider.cs @@ -0,0 +1,1211 @@ +/* + * Process Hacker - + * processes and system performance information provider + * + * Copyright (C) 2009 Flavio Erlich + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Drawing; +using System.Runtime.InteropServices; +using ProcessHacker.Common; +using ProcessHacker.Common.Messaging; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Image; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker +{ + public enum ProcessStats + { + CpuKernel, CpuUser, IoRead, IoWrite, IoOther, IoReadOther, PrivateMemory, WorkingSet + } + + public class ProcessItem : ICloneable + { + public object Clone() + { + return base.MemberwiseClone(); + } + + public int RunId; + public int Pid; + + public Icon Icon; + public Icon LargeIcon; + public string CmdLine; + public float CpuUsage; + public string FileName; + public FileVersionInfo VersionInfo; + public string Name; + public string Username; + public string JobName; + public string Integrity; + public int IntegrityLevel; + public SystemProcessInformation Process; + public DateTime CreateTime; + + public TokenElevationType ElevationType; + public bool HasParent; + public bool IsBeingDebugged; + public bool IsDotNet; + public bool IsElevated; + public bool IsInJob; + public bool IsInSignificantJob; + public bool IsPacked; + public bool IsPosix; + public bool IsWow64; + public int SessionId; + public int ParentPid; + + public VerifyResult VerifyResult; + public string VerifySignerName; + public int ImportFunctions; + public int ImportModules; + + public bool JustProcessed; + public int ProcessingAttempts; + + public ProcessHandle ProcessQueryHandle; + + public DeltaManager DeltaManager; + public HistoryManager FloatHistoryManager; + public HistoryManager LongHistoryManager; + } + + public enum SystemStats + { + CpuKernel, CpuUser, CpuOther, IoRead, IoWrite, IoOther, IoReadOther, Commit, PhysicalMemory + } + + public class ProcessSystemProvider : Provider + { + public class ProcessQueryMessage : Message + { + public int Stage; + public int Pid; + public string FileName; + public TokenElevationType ElevationType; + public bool IsElevated; + public string Integrity; + public int IntegrityLevel; + public string JobName; + public bool IsInJob; + public bool IsInSignificantJob; + public bool IsWow64; + public Icon Icon; + public Icon LargeIcon; + public FileVersionInfo VersionInfo; + public string CmdLine; + + public bool IsDotNet; + public bool IsPacked; + public bool IsPosix; + + public VerifyResult VerifyResult; + public string VerifySignerName; + public int ImportFunctions; + public int ImportModules; + } + + public delegate void ProcessQueryDelegate(int stage, int pid); + + public event ProcessQueryDelegate ProcessQueryComplete; + public event ProcessQueryDelegate ProcessQueryReceived; + + private SystemBasicInformation _system; + public SystemBasicInformation System + { + get { return _system; } + } + + private SystemPerformanceInformation _performance; + public SystemPerformanceInformation Performance + { + get { return _performance; } + } + + private int _processorPerfArraySize; + private MemoryAlloc _processorPerfBuffer; + private SystemProcessorPerformanceInformation[] _processorPerfArray; + public SystemProcessorPerformanceInformation[] ProcessorPerfArray + { + get { return _processorPerfArray; } + } + + private SystemProcessorPerformanceInformation _processorPerf; + public SystemProcessorPerformanceInformation ProcessorPerf + { + get { return _processorPerf; } + } + + public float CurrentCpuKernelUsage { get; private set; } + public float CurrentCpuUserUsage { get; private set; } + public float CurrentCpuUsage { get { return this.CurrentCpuKernelUsage + this.CurrentCpuUserUsage; } } + public int PIDWithMostIoActivity { get; private set; } + public int PIDWithMostCpuUsage { get; private set; } + public DeltaManager CpuDeltas { get { return _cpuDeltas; } } + public DeltaManager LongDeltas { get { return _longDeltas; } } + public HistoryManager FloatHistory { get { return _floatHistory; } } + public HistoryManager LongHistory { get { return _longHistory; } } + public ReadOnlyCollection TimeHistory { get { return _timeHistory[false]; } } + public ReadOnlyCollection MostCpuHistory { get { return _mostUsageHistory[false]; } } + public ReadOnlyCollection MostIoHistory { get { return _mostUsageHistory[true]; } } + + private delegate ProcessQueryMessage QueryProcessDelegate(int pid, string fileName, bool useCache); + + private MessageQueue _messageQueue = new MessageQueue(); + private Dictionary _fileResults = new Dictionary(); + private DeltaManager _longDeltas = + new DeltaManager(Subtractor.Int64Subtractor, EnumComparer.Instance); + private DeltaManager _cpuDeltas = new DeltaManager(Subtractor.Int64Subtractor); + private HistoryManager _timeHistory = new HistoryManager(); + private HistoryManager _longHistory = + new HistoryManager(EnumComparer.Instance); + private HistoryManager _floatHistory = new HistoryManager(); + private HistoryManager _mostUsageHistory = new HistoryManager(); + + private SystemProcess _dpcs = new SystemProcess() + { + Name = "DPCs", + Process = new SystemProcessInformation() + { + ProcessId = -2, + InheritedFromProcessId = 0, + SessionId = -1 + } + }; + + private SystemProcess _interrupts = new SystemProcess() + { + Name = "Interrupts", + Process = new SystemProcessInformation() + { + ProcessId = -3, + InheritedFromProcessId = 0, + SessionId = -1 + } + }; + + public ProcessSystemProvider() + : base() + { + this.Name = this.GetType().Name; + this.ProviderUpdate += new ProviderUpdateOnce(UpdateOnce); + + // Add the file processing results listener. + _messageQueue.AddListener( + new MessageQueueListener((message) => + { + if (this.Dictionary.ContainsKey(message.Pid)) + { + ProcessItem item = this.Dictionary[message.Pid]; + + this.FillPqResult(item, message); + item.JustProcessed = true; + } + })); + + SystemBasicInformation basic; + int retLen; + + Win32.NtQuerySystemInformation(SystemInformationClass.SystemBasicInformation, out basic, + Marshal.SizeOf(typeof(SystemBasicInformation)), out retLen); + _system = basic; + _processorPerfArraySize = Marshal.SizeOf(typeof(SystemProcessorPerformanceInformation)) * + _system.NumberOfProcessors; + _processorPerfBuffer = new MemoryAlloc(_processorPerfArraySize); + _processorPerfArray = new SystemProcessorPerformanceInformation[_system.NumberOfProcessors]; + + this.UpdateProcessorPerf(); + + _timeHistory.Add(false); + + _mostUsageHistory = new HistoryManager(); + _mostUsageHistory.Add(false); + _mostUsageHistory.Add(true); + + _longDeltas.Add(SystemStats.CpuKernel, this.ProcessorPerf.KernelTime); + _longDeltas.Add(SystemStats.CpuUser, this.ProcessorPerf.UserTime); + _longDeltas.Add(SystemStats.CpuOther, + this.ProcessorPerf.IdleTime + this.ProcessorPerf.DpcTime + this.ProcessorPerf.InterruptTime); + _longDeltas.Add(SystemStats.IoRead, this.Performance.IoReadTransferCount); + _longDeltas.Add(SystemStats.IoWrite, this.Performance.IoWriteTransferCount); + _longDeltas.Add(SystemStats.IoOther, this.Performance.IoOtherTransferCount); + + _floatHistory.Add("Kernel"); + _floatHistory.Add("User"); + _floatHistory.Add("Other"); + + for (int i = 0; i < this.System.NumberOfProcessors; i++) + { + _cpuDeltas.Add(i.ToString() + " Kernel", this.ProcessorPerfArray[i].KernelTime); + _cpuDeltas.Add(i.ToString() + " User", this.ProcessorPerfArray[i].UserTime); + _cpuDeltas.Add(i.ToString() + " Other", + this.ProcessorPerfArray[i].IdleTime + this.ProcessorPerfArray[i].DpcTime + + this.ProcessorPerfArray[i].InterruptTime); + _floatHistory.Add(i.ToString() + " Kernel"); + _floatHistory.Add(i.ToString() + " User"); + _floatHistory.Add(i.ToString() + " Other"); + } + + _longHistory.Add(SystemStats.IoRead); + _longHistory.Add(SystemStats.IoWrite); + _longHistory.Add(SystemStats.IoOther); + _longHistory.Add(SystemStats.IoReadOther); + _longHistory.Add(SystemStats.Commit); + _longHistory.Add(SystemStats.PhysicalMemory); + } + + private void UpdateProcessorPerf() + { + int retLen; + + Win32.NtQuerySystemInformation(SystemInformationClass.SystemProcessorPerformanceInformation, + _processorPerfBuffer, _processorPerfArraySize, out retLen); + + _processorPerf = new SystemProcessorPerformanceInformation(); + + // Thanks to: + // http://www.netperf.org/svn/netperf2/trunk/src/netcpu_ntperf.c + // for the critical information: + // "KernelTime needs to be fixed-up; it includes both idle & true kernel time". + // This is why I love free software. + for (int i = 0; i < _processorPerfArray.Length; i++) + { + var cpuPerf = _processorPerfBuffer.ReadStruct(i); + + cpuPerf.KernelTime -= cpuPerf.IdleTime + cpuPerf.DpcTime + cpuPerf.InterruptTime; + _processorPerf.DpcTime += cpuPerf.DpcTime; + _processorPerf.IdleTime += cpuPerf.IdleTime; + _processorPerf.InterruptCount += cpuPerf.InterruptCount; + _processorPerf.InterruptTime += cpuPerf.InterruptTime; + _processorPerf.KernelTime += cpuPerf.KernelTime; + _processorPerf.UserTime += cpuPerf.UserTime; + _processorPerfArray[i] = cpuPerf; + } + } + + private void UpdatePerformance() + { + int retLen; + + Win32.NtQuerySystemInformation(SystemInformationClass.SystemPerformanceInformation, + out _performance, Marshal.SizeOf(typeof(SystemPerformanceInformation)), out retLen); + } + + private ProcessQueryMessage QueryProcessStage1(int pid, string fileName, bool forced) + { + return QueryProcessStage1(pid, fileName, forced, true); + } + + /// + /// Stage 1 Process Querying - gets the process file name, icon and command line. + /// + private ProcessQueryMessage QueryProcessStage1(int pid, string fileName, bool forced, bool addToQueue) + { + ProcessQueryMessage fpResult = new ProcessQueryMessage(); + + fpResult.Pid = pid; + fpResult.Stage = 0x1; + + if (fileName == null) + fileName = this.GetFileName(pid); + + if (fileName == null) + Logging.Log(Logging.Importance.Warning, "Could not get file name for PID " + pid.ToString()); + + fpResult.FileName = fileName; + + try + { + using (var queryLimitedHandle = new ProcessHandle(pid, Program.MinProcessQueryRights)) + { + try + { + // Get a handle to the process' token and get its + // elevation type, and integrity. + + using (var thandle = queryLimitedHandle.GetToken(TokenAccess.Query)) + { + try { fpResult.ElevationType = thandle.GetElevationType(); } + catch { } + try { fpResult.IsElevated = thandle.IsElevated(); } + catch { } + + // Try to get the integrity level. + try + { + fpResult.Integrity = thandle.GetIntegrity(out fpResult.IntegrityLevel); + } + catch + { } + } + } + catch + { } + + // Is the process running under WOW64? + if (IntPtr.Size == 8) + { + try + { + fpResult.IsWow64 = queryLimitedHandle.IsWow64(); + } + catch + { } + } + + // Get the process' job if we have KProcessHacker. + // Otherwise, don't do anything. + + if (KProcessHacker.Instance != null) + { + try + { + var jhandle = queryLimitedHandle.GetJobObject(JobObjectAccess.Query); + + if (jhandle != null) + { + using (jhandle) + { + var limits = jhandle.GetBasicLimitInformation(); + + fpResult.IsInJob = true; + fpResult.JobName = jhandle.GetObjectName(); + + // This is what Process Explorer does... + if (limits.LimitFlags != JobObjectLimitFlags.SilentBreakawayOk) + { + fpResult.IsInSignificantJob = true; + } + } + } + } + catch (Exception ex) + { + Logging.Log(ex); + fpResult.IsInJob = false; + fpResult.IsInSignificantJob = false; + } + } + else + { + try { fpResult.IsInJob = queryLimitedHandle.IsInJob(); } + catch { } + } + } + } + catch + { } + + if (fileName != null) + { + try + { + fpResult.Icon = FileUtils.GetFileIcon(fileName); + fpResult.LargeIcon = FileUtils.GetFileIcon(fileName, true); + } + catch + { } + + try + { + fpResult.VersionInfo = FileVersionInfo.GetVersionInfo(fileName); + } + catch + { } + } + + try + { + using (var phandle = new ProcessHandle(pid, + Program.MinProcessQueryRights | Program.MinProcessReadMemoryRights)) + { + fpResult.CmdLine = phandle.GetCommandLine(); + fpResult.IsPosix = phandle.IsPosix(); + } + } + catch + { } + + if (addToQueue) + _messageQueue.Enqueue(fpResult); + + WorkQueue.GlobalQueueWorkItemTag( + new QueryProcessDelegate(this.QueryProcessStage1a), + "process-stage1a", + pid, fileName, forced + ); + WorkQueue.GlobalQueueWorkItemTag( + new QueryProcessDelegate(this.QueryProcessStage2), + "process-stage2", + pid, fileName, forced + ); + + if (this.ProcessQueryComplete != null) + this.ProcessQueryComplete(fpResult.Stage, pid); + + return fpResult; + } + + /// + /// Stage 1A Process Querying - gets whether the process is managed. + /// + private ProcessQueryMessage QueryProcessStage1a(int pid, string fileName, bool forced) + { + ProcessQueryMessage fpResult = new ProcessQueryMessage(); + + fpResult.Pid = pid; + fpResult.Stage = 0x1a; + + if (pid > 4) + { + try + { + var publish = new Debugger.Core.Wrappers.CorPub.ICorPublish(); + Debugger.Core.Wrappers.CorPub.ICorPublishProcess process = null; + + try + { + process = publish.GetProcess(pid); + fpResult.IsDotNet = process.IsManaged; + } + finally + { + if (process != null) + { + Debugger.Wrappers.ResourceManager.ReleaseCOMObject(process, process.GetType()); + } + } + } + catch + { } + } + + _messageQueue.Enqueue(fpResult); + + if (this.ProcessQueryComplete != null) + this.ProcessQueryComplete(fpResult.Stage, pid); + + return fpResult; + } + + /// + /// Stage 2 Process Querying - gets whether the process file is packed or signed. + /// + private ProcessQueryMessage QueryProcessStage2(int pid, string fileName, bool forced) + { + ProcessQueryMessage fpResult = new ProcessQueryMessage(); + + fpResult.Pid = pid; + fpResult.Stage = 0x2; + fpResult.IsPacked = false; + + if (fileName == null) + return null; + + // Find out if it's packed. + // An image is packed if: + // 1. It references less than 3 libraries + // 2. It imports less than 5 functions + // or: + // 1. The function-to-library ratio is lower than 4 + // (on average less than 4 functions are imported from each library) + // 2. It references more than 3 libraries but less than 14 libraries. + if (fileName != null && (Properties.Settings.Default.VerifySignatures || forced)) + { + try + { + using (var mappedImage = new MappedImage(fileName)) + { + int libraryTotal = mappedImage.Imports.Count; + int funcTotal = 0; + + for (int i = 0; i < mappedImage.Imports.Count; i++) + funcTotal += mappedImage.Imports[i].Count; + + fpResult.ImportModules = libraryTotal; + fpResult.ImportFunctions = funcTotal; + + if ( + libraryTotal < 3 && funcTotal < 5 || + ((float)funcTotal / libraryTotal < 4) && libraryTotal > 3 && libraryTotal < 30 + ) + fpResult.IsPacked = true; + } + } + catch (AccessViolationException) + { + if (pid > 4) + fpResult.IsPacked = true; + } + catch + { } + } + + try + { + if (Properties.Settings.Default.VerifySignatures || forced) + { + if (fileName != null) + { + string uniName = global::System.IO.Path.GetFullPath(fileName).ToLower(); + + // No lock needed; verify results are never removed, only added. + if (!forced && _fileResults.ContainsKey(uniName)) + { + fpResult.VerifyResult = _fileResults[uniName]; + } + else + { + try + { + fpResult.VerifyResult = Cryptography.VerifyFile(fileName); + } + catch + { + fpResult.VerifyResult = VerifyResult.NoSignature; + } + + if (!_fileResults.ContainsKey(uniName)) + _fileResults.Add(uniName, fpResult.VerifyResult); + else + _fileResults[uniName] = fpResult.VerifyResult; + } + + //if (fpResult.VerifyResult != VerifyResult.NoSignature) + // fpResult.VerifySignerName = Cryptography.GetFileSubjectValue(fileName, "CN"); + } + } + } + catch + { } + + _messageQueue.Enqueue(fpResult); + + if (this.ProcessQueryComplete != null) + this.ProcessQueryComplete(fpResult.Stage, pid); + + return fpResult; + } + + private string GetFileName(int pid) + { + string fileName = null; + + if (pid != 4) + { + try + { + using (var phandle = new ProcessHandle(pid, Program.MinProcessQueryRights)) + { + // First try to get the native file name, to prevent PEB + // file name spoofing. + try + { + fileName = FileUtils.GetFileName(phandle.GetImageFileName()); + } + catch + { } + + // If we couldn't get it or we couldn't resolve the \Device prefix, + // we'll use the Win32 variant. + if ((fileName == null || fileName.StartsWith("\\")) && + OSVersion.HasWin32ImageFileName) + { + try + { + fileName = phandle.GetImageFileNameWin32(); + } + catch + { } + } + } + } + catch + { } + + if (fileName == null || fileName.StartsWith("\\Device\\")) + { + try + { + using (var phandle = + new ProcessHandle(pid, ProcessAccess.QueryInformation | ProcessAccess.VmRead)) + { + // We can try to use the PEB. + try + { + fileName = FileUtils.GetFileName( + FileUtils.GetFileName(phandle.GetPebString(PebOffset.ImagePathName))); + } + catch + { } + + // If all else failed, we get the main module file name. + try + { + fileName = phandle.GetMainModule().FileName; + } + catch + { } + } + } + catch + { } + } + } + else + { + try + { + fileName = Windows.KernelFileName; + } + catch + { } + } + + return fileName; + } + + public void QueueProcessQuery(int pid) + { + WorkQueue.GlobalQueueWorkItemTag( + new QueryProcessDelegate(this.QueryProcessStage1), + "process-stage1", + pid, this.Dictionary[pid].FileName, true + ); + } + + private void FillPqResult(ProcessItem item, ProcessQueryMessage result) + { + if (result.Stage == 0x1) + { + item.FileName = result.FileName; + item.ElevationType = result.ElevationType; + item.IsElevated = result.IsElevated; + item.Integrity = result.Integrity; + item.IntegrityLevel = result.IntegrityLevel; + item.IsWow64 = result.IsWow64; + item.IsInJob = result.IsInJob; + item.JobName = result.JobName; + item.IsInSignificantJob = result.IsInSignificantJob; + item.Icon = result.Icon; + item.LargeIcon = result.LargeIcon; + item.VersionInfo = result.VersionInfo; + item.CmdLine = result.CmdLine; + item.IsPosix = result.IsPosix; + } + else if (result.Stage == 0x1a) + { + item.IsDotNet = result.IsDotNet; + + if (item.IsDotNet) + item.IsPacked = false; + } + else if (result.Stage == 0x2) + { + item.IsPacked = (item.IsDotNet || result.IsDotNet) ? false : result.IsPacked; + item.VerifyResult = result.VerifyResult; + item.VerifySignerName = result.VerifySignerName; + item.ImportFunctions = result.ImportFunctions; + item.ImportModules = result.ImportModules; + } + else + { + Logging.Log(Logging.Importance.Warning, "Unknown stage " + result.Stage.ToString("x")); + } + + if (this.ProcessQueryReceived != null) + this.ProcessQueryReceived(result.Stage, result.Pid); + } + + private void UpdateOnce() + { + this.UpdatePerformance(); + this.UpdateProcessorPerf(); + //this.UpdateFrozenWindows(); + + if (this.RunCount % 3 == 0) + FileUtils.RefreshFileNamePrefixes(); + + var tsProcesses = new Dictionary(); + var procs = Windows.GetProcesses(); + Dictionary newdictionary = new Dictionary(this.Dictionary); + Win32.WtsEnumProcessesFastData wtsEnumData = new Win32.WtsEnumProcessesFastData(); + + _longDeltas.Update(SystemStats.CpuKernel, _processorPerf.KernelTime); + long sysKernelTime = _longDeltas[SystemStats.CpuKernel]; + + _longDeltas.Update(SystemStats.CpuUser, _processorPerf.UserTime); + long sysUserTime = _longDeltas[SystemStats.CpuUser]; + + _longDeltas.Update(SystemStats.CpuOther, + _processorPerf.IdleTime + _processorPerf.DpcTime + _processorPerf.InterruptTime); + long otherTime = _longDeltas[SystemStats.CpuOther]; + + if (sysKernelTime + sysUserTime + otherTime == 0) + { + Logging.Log(Logging.Importance.Warning, "Total systimes are 0, returning!"); + return; + } + + _longDeltas.Update(SystemStats.IoRead, _performance.IoReadTransferCount); + _longDeltas.Update(SystemStats.IoWrite, _performance.IoWriteTransferCount); + _longDeltas.Update(SystemStats.IoOther, _performance.IoOtherTransferCount); + + if (_processorPerf.KernelTime != 0 && _processorPerf.UserTime != 0) + { + this.CurrentCpuKernelUsage = (float)sysKernelTime / (sysKernelTime + sysUserTime + otherTime); + this.CurrentCpuUserUsage = (float)sysUserTime / (sysKernelTime + sysUserTime + otherTime); + + _floatHistory.Update("Kernel", this.CurrentCpuKernelUsage); + _floatHistory.Update("User", this.CurrentCpuUserUsage); + _floatHistory.Update("Other", (float)otherTime / (sysKernelTime + sysUserTime + otherTime)); + } + + for (int i = 0; i < this.System.NumberOfProcessors; i++) + { + long cpuKernelTime = _cpuDeltas.Update(i.ToString() + " Kernel", _processorPerfArray[i].KernelTime); + long cpuUserTime = _cpuDeltas.Update(i.ToString() + " User", _processorPerfArray[i].UserTime); + long cpuOtherTime = _cpuDeltas.Update(i.ToString() + " Other", + _processorPerfArray[i].IdleTime + _processorPerfArray[i].DpcTime + + _processorPerfArray[i].InterruptTime); + _floatHistory.Update(i.ToString() + " Kernel", + (float)cpuKernelTime / (cpuKernelTime + cpuUserTime + cpuOtherTime)); + _floatHistory.Update(i.ToString() + " User", + (float)cpuUserTime / (cpuKernelTime + cpuUserTime + cpuOtherTime)); + _floatHistory.Update(i.ToString() + " Other", + (float)cpuOtherTime / (cpuKernelTime + cpuUserTime + cpuOtherTime)); + } + + if (this.RunCount < 3) + { + _longDeltas[SystemStats.IoRead] = 0; + _longDeltas[SystemStats.IoWrite] = 0; + _longDeltas[SystemStats.IoOther] = 0; + } + + _longHistory.Update(SystemStats.IoRead, _longDeltas[SystemStats.IoRead]); + _longHistory.Update(SystemStats.IoWrite, _longDeltas[SystemStats.IoWrite]); + _longHistory.Update(SystemStats.IoOther, _longDeltas[SystemStats.IoOther]); + _longHistory.Update(SystemStats.IoReadOther, + _longDeltas[SystemStats.IoRead] + _longDeltas[SystemStats.IoOther]); + _longHistory.Update(SystemStats.Commit, (long)_performance.CommittedPages * _system.PageSize); + _longHistory.Update(SystemStats.PhysicalMemory, + (long)(_system.NumberOfPhysicalPages - _performance.AvailablePages) * _system.PageSize); + + // set System Idle Process CPU time + if (procs.ContainsKey(0)) + { + SystemProcess proc = procs[0]; + proc.Process.KernelTime = _processorPerf.IdleTime; + procs[0] = proc; + } + + // add fake processes (DPCs and Interrupts) + _dpcs.Process.KernelTime = _processorPerf.DpcTime; + procs.Add(-2, _dpcs); + + _interrupts.Process.KernelTime = _processorPerf.InterruptTime; + procs.Add(-3, _interrupts); + + float mostCPUUsage = 0; + long mostIOActivity = 0; + + // look for dead processes + foreach (int pid in Dictionary.Keys) + { + if (!procs.ContainsKey(pid)) + { + ProcessItem item = this.Dictionary[pid]; + + this.OnDictionaryRemoved(item); + + if (item.ProcessQueryHandle != null) + item.ProcessQueryHandle.Dispose(); + + if (item.Icon != null) + Win32.DestroyIcon(item.Icon.Handle); + if (item.LargeIcon != null) + Win32.DestroyIcon(item.LargeIcon.Handle); + + // Remove process protection if needed. + if (KProcessHacker.Instance != null) + { + try + { + using (var phandle = new ProcessHandle(pid, Program.MinProcessQueryRights)) + KProcessHacker.Instance.ProtectRemove(phandle); + } + catch + { } + } + + newdictionary.Remove(pid); + } + } + + // Receive any processing results. + _messageQueue.Listen(); + + // look for new processes + foreach (int pid in procs.Keys) + { + var processInfo = procs[pid].Process; + + if (!Dictionary.ContainsKey(pid)) + { + ProcessItem item = new ProcessItem(); + + // Set up basic process information. + item.RunId = this.RunCount; + item.Pid = pid; + item.Process = processInfo; + item.SessionId = processInfo.SessionId; + item.ProcessingAttempts = 1; + + item.Name = procs[pid].Name; + + // Create the delta and history managers. + item.DeltaManager = new DeltaManager( + Subtractor.Int64Subtractor, EnumComparer.Instance); + item.DeltaManager.Add(ProcessStats.CpuKernel, processInfo.KernelTime); + item.DeltaManager.Add(ProcessStats.CpuUser, processInfo.UserTime); + item.DeltaManager.Add(ProcessStats.IoRead, (long)processInfo.IoCounters.ReadTransferCount); + item.DeltaManager.Add(ProcessStats.IoWrite, (long)processInfo.IoCounters.WriteTransferCount); + item.DeltaManager.Add(ProcessStats.IoOther, (long)processInfo.IoCounters.OtherTransferCount); + item.FloatHistoryManager = + new HistoryManager(EnumComparer.Instance); + item.LongHistoryManager = + new HistoryManager(EnumComparer.Instance); + item.FloatHistoryManager.Add(ProcessStats.CpuKernel); + item.FloatHistoryManager.Add(ProcessStats.CpuUser); + item.LongHistoryManager.Add(ProcessStats.IoReadOther); + item.LongHistoryManager.Add(ProcessStats.IoRead); + item.LongHistoryManager.Add(ProcessStats.IoWrite); + item.LongHistoryManager.Add(ProcessStats.IoOther); + item.LongHistoryManager.Add(ProcessStats.PrivateMemory); + item.LongHistoryManager.Add(ProcessStats.WorkingSet); + + // HACK: Shouldn't happen, but it does - sometimes + // the process name is null. + if (item.Name == null) + { + try + { + using (var phandle = + new ProcessHandle(pid, ProcessAccess.QueryInformation | ProcessAccess.VmRead)) + item.Name = phandle.GetMainModule().BaseName; + } + catch + { + item.Name = ""; + } + } + + // Get the process' creation time and check the + // parent process ID. + + try + { + item.CreateTime = DateTime.FromFileTime(processInfo.CreateTime); + } + catch + { } + + if (pid > 0) + { + item.ParentPid = processInfo.InheritedFromProcessId; + item.HasParent = true; + + if (!procs.ContainsKey(item.ParentPid) || item.ParentPid == pid) + { + item.HasParent = false; + } + else if (procs.ContainsKey(item.ParentPid)) + { + // Check the parent's creation time to see if it's actually the parent. + ulong parentStartTime = (ulong)procs[item.ParentPid].Process.CreateTime; + ulong thisStartTime = (ulong)processInfo.CreateTime; + + if (parentStartTime > thisStartTime) + item.HasParent = false; + } + + // Get the process' token's username. + + try + { + using (var queryLimitedHandle = new ProcessHandle(pid, Program.MinProcessQueryRights)) + { + try + { + using (var thandle = queryLimitedHandle.GetToken(TokenAccess.Query)) + { + try + { + using (var sid = thandle.GetUser()) + item.Username = sid.GetFullName(true); + } + catch + { } + } + } + catch + { } + } + } + catch + { } + + // Get a process handle with QUERY_INFORMATION access, and + // see if it's being debugged. + + try + { + item.ProcessQueryHandle = new ProcessHandle(pid, ProcessAccess.QueryInformation); + + try + { + item.IsBeingDebugged = item.ProcessQueryHandle.IsBeingDebugged(); + } + catch + { } + } + catch + { } + } + + // Update the process name if it's a fake process. + + if (pid == 0) + { + item.Name = "System Idle Process"; + } + else if (pid == -2) + { + item.ParentPid = 0; + item.HasParent = true; + } + else if (pid == -3) + { + item.ParentPid = 0; + item.HasParent = true; + } + + // If this is not the first run, we process the item immediately. + if (this.RunCount > 0) + { + this.FillPqResult(item, this.QueryProcessStage1(pid, null, false, false)); + } + else + { + if (pid > 0) + { + WorkQueue.GlobalQueueWorkItemTag( + new QueryProcessDelegate(this.QueryProcessStage1), + "process-stage1", + pid, item.FileName, false); + } + } + + // Set the username for System Idle Process and System. + if (pid == 0 || pid == 4) + { + // TODO: Potential localization problem. Need to create + // a well-known SID and use that. + item.Username = "NT AUTHORITY\\SYSTEM"; + } + + // If we didn't get a username, try to use Terminal Services + // to get the SID of the process' token's user. + if (item.Username == null) + { + if (tsProcesses.Count == 0) + { + // delay loading until this point + wtsEnumData = Win32.TSEnumProcessesFast(); + + for (int i = 0; i < wtsEnumData.PIDs.Length; i++) + tsProcesses.Add(wtsEnumData.PIDs[i], wtsEnumData.SIDs[i]); + } + + try + { + item.Username = Sid.FromPointer(tsProcesses[pid]).GetFullName(true); + } + catch + { } + } + + newdictionary.Add(pid, item); + this.OnDictionaryAdded(item); + } + // look for modified processes + else + { + ProcessItem item = this.Dictionary[pid]; + bool fullUpdate = false; + + // Update process performance information. + + item.DeltaManager.Update(ProcessStats.CpuKernel, processInfo.KernelTime); + item.DeltaManager.Update(ProcessStats.CpuUser, processInfo.UserTime); + item.DeltaManager.Update(ProcessStats.IoRead, (long)processInfo.IoCounters.ReadTransferCount); + item.DeltaManager.Update(ProcessStats.IoWrite, (long)processInfo.IoCounters.WriteTransferCount); + item.DeltaManager.Update(ProcessStats.IoOther, (long)processInfo.IoCounters.OtherTransferCount); + + item.FloatHistoryManager.Update(ProcessStats.CpuKernel, + (float)item.DeltaManager[ProcessStats.CpuKernel] / + (sysKernelTime + sysUserTime + otherTime)); + item.FloatHistoryManager.Update(ProcessStats.CpuUser, + (float)item.DeltaManager[ProcessStats.CpuUser] / + (sysKernelTime + sysUserTime + otherTime)); + item.LongHistoryManager.Update(ProcessStats.IoRead, item.DeltaManager[ProcessStats.IoRead]); + item.LongHistoryManager.Update(ProcessStats.IoWrite, item.DeltaManager[ProcessStats.IoWrite]); + item.LongHistoryManager.Update(ProcessStats.IoOther, item.DeltaManager[ProcessStats.IoOther]); + item.LongHistoryManager.Update(ProcessStats.IoReadOther, + item.DeltaManager[ProcessStats.IoRead] + item.DeltaManager[ProcessStats.IoOther]); + item.LongHistoryManager.Update(ProcessStats.PrivateMemory, processInfo.VirtualMemoryCounters.PrivatePageCount.ToInt64()); + item.LongHistoryManager.Update(ProcessStats.WorkingSet, processInfo.VirtualMemoryCounters.WorkingSetSize.ToInt64()); + + // Update the struct. + item.Process = processInfo; + + // Update CPU usage, and update PIDs with most activity. + + try + { + item.CpuUsage = (float) + (item.DeltaManager[ProcessStats.CpuUser] + + item.DeltaManager[ProcessStats.CpuKernel]) * 100 / + (sysKernelTime + sysUserTime + otherTime); + + // HACK. + + if (item.CpuUsage > 400.0f) + item.CpuUsage /= 8.0f; + else if (item.CpuUsage > 200.0f) + item.CpuUsage /= 4.0f; + else if (item.CpuUsage > 100.0f) + item.CpuUsage /= 2.0f; + + if (pid != 0 && item.CpuUsage > mostCPUUsage) + { + mostCPUUsage = item.CpuUsage; + this.PIDWithMostCpuUsage = pid; + } + + if (pid != 0 && (item.LongHistoryManager[ProcessStats.IoReadOther][0] + + item.LongHistoryManager[ProcessStats.IoWrite][0]) > mostIOActivity) + { + mostIOActivity = item.LongHistoryManager[ProcessStats.IoReadOther][0] + + item.LongHistoryManager[ProcessStats.IoWrite][0]; + this.PIDWithMostIoActivity = pid; + } + } + catch + { } + + // Determine whether the process is being debugged. + + if (item.ProcessQueryHandle != null) + { + try + { + bool isBeingDebugged = item.ProcessQueryHandle.IsBeingDebugged(); + + if (isBeingDebugged != item.IsBeingDebugged) + { + item.IsBeingDebugged = isBeingDebugged; + fullUpdate = true; + } + } + catch + { } + } + + // Processes sometimes mistakenly get labeled as packed. + // Try again if it is packed. + if (pid > 0) + { + if (item.IsPacked && item.ProcessingAttempts < 3) + { + WorkQueue.GlobalQueueWorkItemTag( + new QueryProcessDelegate(this.QueryProcessStage2), + "process-stage2", + pid, item.FileName, true + ); + item.ProcessingAttempts++; + } + } + + if (item.JustProcessed) + fullUpdate = true; + + // If we need a full update, call the dictionary modified + // event so the process tree updates the process' + // highlighting color. + if (fullUpdate) + { + this.OnDictionaryModified(null, item); + } + + item.JustProcessed = false; + } + } + + try + { + _mostUsageHistory.Update(false, newdictionary[this.PIDWithMostCpuUsage].Name + ": " + + newdictionary[this.PIDWithMostCpuUsage].CpuUsage.ToString("N2") + "%"); + } + catch + { + _mostUsageHistory.Update(false, ""); + } + + try + { + _mostUsageHistory.Update(true, newdictionary[this.PIDWithMostIoActivity].Name + ": " + + "R+O: " + Utils.FormatSize( + newdictionary[this.PIDWithMostIoActivity].LongHistoryManager[ProcessStats.IoReadOther][0]) + + ", W: " + Utils.FormatSize( + newdictionary[this.PIDWithMostIoActivity].LongHistoryManager[ProcessStats.IoWrite][0])); + } + catch + { + _mostUsageHistory.Update(true, ""); + } + + _timeHistory.Update(false, DateTime.Now); + + Dictionary = newdictionary; + + if (wtsEnumData.Memory != null) + wtsEnumData.Memory.Dispose(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Providers/ServiceProvider.cs b/branches/ph-plugins/ProcessHacker/Providers/ServiceProvider.cs new file mode 100644 index 000000000..0da3c5a22 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Providers/ServiceProvider.cs @@ -0,0 +1,150 @@ +/* + * Process Hacker - + * service provider + * + * Copyright (C) 2008 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 . + */ + +using System; +using System.Collections.Generic; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker +{ + public class ServiceItem : ICloneable + { + public object Clone() + { + return this.MemberwiseClone(); + } + + public int RunId; + public EnumServiceStatusProcess Status; + public QueryServiceConfig Config; + } + + public class ServiceProvider : Provider + { + public ServiceProvider() + : base(StringComparer.InvariantCultureIgnoreCase) // Windows is case-insensitive with services + { + this.Name = this.GetType().Name; + this.ProviderUpdate += new ProviderUpdateOnce(UpdateOnce); + } + + public void UpdateServiceConfig(string name, QueryServiceConfig config) + { + ServiceItem item = Dictionary[name]; + + Dictionary[name] = new ServiceItem() + { + Config = config, + Status = item.Status + }; + + this.OnDictionaryModified(item, Dictionary[name]); + } + + private void UpdateOnce() + { + var newdictionary = Windows.GetServices(); + + // check for removed services + foreach (string s in Dictionary.Keys) + { + if (!newdictionary.ContainsKey(s)) + { + ServiceItem service = Dictionary[s]; + + this.OnDictionaryRemoved(service); + Dictionary.Remove(s); + } + } + + // check for new services + foreach (string s in newdictionary.Keys) + { + if (!Dictionary.ContainsKey(s)) + { + ServiceItem item = new ServiceItem(); + + item.RunId = this.RunCount; + item.Status = newdictionary[s]; + + try + { + using (var shandle = new ServiceHandle(s, ServiceAccess.QueryConfig)) + item.Config = shandle.GetConfig(); + } + catch + { } + + this.OnDictionaryAdded(item); + Dictionary.Add(s, item); + } + } + + var toModify = new Dictionary(); + + // check for modified services + foreach (ServiceItem service in Dictionary.Values) + { + var newStatus = newdictionary[service.Status.ServiceName]; + + bool modified = false; + + if (service.Status.DisplayName != newStatus.DisplayName) + modified = true; + else if (service.Status.ServiceStatusProcess.ControlsAccepted != + newStatus.ServiceStatusProcess.ControlsAccepted) + modified = true; + else if (service.Status.ServiceStatusProcess.CurrentState != + newStatus.ServiceStatusProcess.CurrentState) + modified = true; + else if (service.Status.ServiceStatusProcess.ProcessID != + newStatus.ServiceStatusProcess.ProcessID) + modified = true; + else if (service.Status.ServiceStatusProcess.ServiceFlags != + newStatus.ServiceStatusProcess.ServiceFlags) + modified = true; + else if (service.Status.ServiceStatusProcess.ServiceType != + newStatus.ServiceStatusProcess.ServiceType) + modified = true; + + if (modified) + { + var newServiceItem = new ServiceItem() + { + RunId = service.RunId, + Status = newStatus, + Config = service.Config + }; + + this.OnDictionaryModified(service, newServiceItem); + toModify.Add(service.Status.ServiceName, newServiceItem); + } + } + + foreach (string serviceName in toModify.Keys) + Dictionary[serviceName] = toModify[serviceName]; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Providers/ThreadProvider.cs b/branches/ph-plugins/ProcessHacker/Providers/ThreadProvider.cs new file mode 100644 index 000000000..e684608ee --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Providers/ThreadProvider.cs @@ -0,0 +1,599 @@ +/* + * Process Hacker - + * thread provider + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Threading; +using ProcessHacker.Common; +using ProcessHacker.Common.Messaging; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; +using ProcessHacker.Native.Symbols; + +namespace ProcessHacker +{ + public class ThreadItem : ICloneable + { + public object Clone() + { + return this.MemberwiseClone(); + } + + public int RunId; + public int Tid; + + public long ContextSwitches; + public long ContextSwitchesDelta; + public ulong Cycles; + public ulong CyclesDelta; + public int PriorityI; + public string Priority; + public IntPtr StartAddressI; + public string StartAddress; + public string FileName; + public SymbolResolveLevel StartAddressLevel; + public KWaitReason WaitReason; + public bool IsGuiThread; + public bool JustResolved; + + public ThreadHandle ThreadQueryLimitedHandle; + } + + public class ThreadProvider : Provider + { + private class ResolveMessage : Message + { + public int Tid; + public string Symbol; + public string FileName; + public SymbolResolveLevel ResolveLevel; + } + + public delegate void LoadingStateChangedDelegate(bool loading); + private delegate void ResolveThreadStartAddressDelegate(int tid, ulong startAddress); + + private static readonly WorkQueue _symbolsWorkQueue = new WorkQueue() { MaxWorkerThreads = 1 }; + + public event LoadingStateChangedDelegate LoadingStateChanged; + + private ProcessHandle _processHandle; + private ProcessAccess _processAccess; + private SymbolProvider _symbols; + private bool _kernelSymbolsLoaded = false; + private int _pid; + private int _loading = 0; + private MessageQueue _messageQueue = new MessageQueue(); + private EventWaitHandle _moduleLoadCompletedEvent = new EventWaitHandle(false, EventResetMode.ManualReset); + private bool _waitedForLoad = false; + + public ThreadProvider(int pid) + : base() + { + this.Name = this.GetType().Name; + _pid = pid; + + _messageQueue.AddListener( + new MessageQueueListener((message) => + { + if (message.Symbol != null) + { + this.Dictionary[message.Tid].StartAddress = message.Symbol; + this.Dictionary[message.Tid].FileName = message.FileName; + this.Dictionary[message.Tid].StartAddressLevel = message.ResolveLevel; + this.Dictionary[message.Tid].JustResolved = true; + } + })); + + this.ProviderUpdate += new ProviderUpdateOnce(UpdateOnce); + this.Disposed += ThreadProvider_Disposed; + + try + { + // Try to get a good process handle we can use the same handle for stack walking. + try + { + _processAccess = ProcessAccess.QueryInformation | ProcessAccess.VmRead; + _processHandle = new ProcessHandle(_pid, _processAccess); + } + catch + { + try + { + if (KProcessHacker.Instance != null) + { + _processAccess = Program.MinProcessReadMemoryRights; + _processHandle = new ProcessHandle(_pid, _processAccess); + } + else + { + _processAccess = Program.MinProcessQueryRights; + _processHandle = new ProcessHandle(_pid, _processAccess); + } + } + catch (WindowsException ex) + { + Logging.Log(ex); + } + } + + // Start loading symbols; avoid the UI blocking on the dbghelp call lock. + _symbolsWorkQueue.QueueWorkItemTag(new Action(() => + { + try + { + // Needed (maybe) to display the EULA + Win32.SymbolServerSetOptions(SymbolServerOption.Unattended, 0); + } + catch (Exception ex) + { + Logging.Log(ex); + } + + try + { + // Use the process handle if we have one, otherwise use the default ID generator. + if (_processHandle != null) + _symbols = new SymbolProvider(_processHandle); + else + _symbols = new SymbolProvider(); + + SymbolProvider.Options = SymbolOptions.DeferredLoads | + (Properties.Settings.Default.DbgHelpUndecorate ? SymbolOptions.UndName : 0); + + if (Properties.Settings.Default.DbgHelpSearchPath != "") + _symbols.SearchPath = Properties.Settings.Default.DbgHelpSearchPath; + + try + { + if (_pid != 4) + { + using (var phandle = + new ProcessHandle(_pid, Program.MinProcessQueryRights | Program.MinProcessReadMemoryRights)) + { + if (IntPtr.Size == 4 || !phandle.IsWow64()) + { + // Load the process' modules. + try { _symbols.LoadProcessModules(phandle); } + catch { } + } + else + { + // Load the process' WOW64 modules. + try { _symbols.LoadProcessWow64Modules(_pid); } + catch { } + } + + // If the process is CSRSS we should load kernel modules + // due to the presence of kernel-mode threads. + if (phandle.GetKnownProcessType() == KnownProcess.WindowsSubsystem) + this.LoadKernelSymbols(true); + } + } + else + { + this.LoadKernelSymbols(true); + } + } + catch (WindowsException ex) + { + // Did we get Access Denied? At least load + // kernel32.dll and ntdll.dll. + try + { + ProcessHandle.Current.EnumModules((module) => + { + if (module.BaseName == "kernel32.dll" || module.BaseName == "ntdll.dll") + { + _symbols.LoadModule(module.FileName, module.BaseAddress, module.Size); + } + + return true; + }); + } + catch (Exception ex2) + { + Logging.Log(ex2); + } + + Logging.Log(ex); + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + finally + { + lock (_moduleLoadCompletedEvent) + { + if (!_moduleLoadCompletedEvent.SafeWaitHandle.IsClosed) + _moduleLoadCompletedEvent.Set(); + } + } + }), "symbols-load"); + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + + public ProcessAccess ProcessAccess + { + get { return _processAccess; } + } + + public ProcessHandle ProcessHandle + { + get { return _processHandle; } + } + + public void LoadKernelSymbols() + { + this.LoadKernelSymbols(false); + } + + public void LoadKernelSymbols(bool force) + { + lock (_symbols) + { + if (!_kernelSymbolsLoaded) + { + if (KProcessHacker.Instance != null || force) + _symbols.LoadKernelModules(); + + _kernelSymbolsLoaded = true; + } + } + } + + private void ThreadProvider_Disposed(IProvider provider) + { + if (_symbols != null) + _symbols.Dispose(); + if (_processHandle != null) + _processHandle.Dispose(); + _symbols = null; + + lock (_moduleLoadCompletedEvent) + _moduleLoadCompletedEvent.Close(); + + foreach (int tid in this.Dictionary.Keys) + { + ThreadItem item = this.Dictionary[tid]; + + if (item.ThreadQueryLimitedHandle != null) + item.ThreadQueryLimitedHandle.Dispose(); + } + } + + private void ResolveThreadStartAddress(int tid, ulong startAddress) + { + ResolveMessage result = new ResolveMessage(); + + result.Tid = tid; + + if (!_moduleLoadCompletedEvent.SafeWaitHandle.IsClosed) + { + try + { + _moduleLoadCompletedEvent.WaitOne(); + } + catch + { } + } + + if (_symbols == null) + return; + + try + { + Interlocked.Increment(ref _loading); + + if (this.LoadingStateChanged != null) + this.LoadingStateChanged(Thread.VolatileRead(ref _loading) > 0); + + try + { + SymbolFlags flags; + string fileName; + + result.Symbol = _symbols.GetSymbolFromAddress( + startAddress, + out result.ResolveLevel, + out flags, + out fileName + ); + result.FileName = fileName; + _messageQueue.Enqueue(result); + } + catch + { } + } + finally + { + Interlocked.Decrement(ref _loading); + + if (this.LoadingStateChanged != null) + this.LoadingStateChanged(Thread.VolatileRead(ref _loading) > 0); + } + } + + public void QueueThreadResolveStartAddress(int tid) + { + this.QueueThreadResolveStartAddress(tid, this.Dictionary[tid].StartAddressI.ToUInt64()); + } + + public void QueueThreadResolveStartAddress(int tid, ulong startAddress) + { + _symbolsWorkQueue.QueueWorkItemTag( + new ResolveThreadStartAddressDelegate(this.ResolveThreadStartAddress), + "thread-resolve", + tid, startAddress + ); + } + + private string GetThreadBasicStartAddress(ulong startAddress, out SymbolResolveLevel level) + { + ulong modBase; + string fileName = _symbols.GetModuleFromAddress(startAddress, out modBase); + + if (fileName == null) + { + level = SymbolResolveLevel.Address; + return "0x" + startAddress.ToString("x"); + } + else + { + level = SymbolResolveLevel.Module; + return System.IO.Path.GetFileName(fileName) + "+0x" + + (startAddress - modBase).ToString("x"); + } + } + + private void UpdateOnce() + { + var threads = Windows.GetProcessThreads(_pid); + Dictionary newdictionary = new Dictionary(this.Dictionary); + + if (threads == null) + threads = new Dictionary(); + + // look for dead threads + foreach (int tid in Dictionary.Keys) + { + if (!threads.ContainsKey(tid)) + { + ThreadItem item = this.Dictionary[tid]; + + if (item.ThreadQueryLimitedHandle != null) + item.ThreadQueryLimitedHandle.Dispose(); + + this.OnDictionaryRemoved(item); + newdictionary.Remove(tid); + } + } + + // Get resolve results. + _messageQueue.Listen(); + + // look for new threads + foreach (int tid in threads.Keys) + { + var t = threads[tid]; + + if (!Dictionary.ContainsKey(tid)) + { + ThreadItem item = new ThreadItem(); + + item.RunId = this.RunCount; + item.Tid = tid; + item.ContextSwitches = t.ContextSwitchCount; + item.WaitReason = t.WaitReason; + + try + { + item.ThreadQueryLimitedHandle = new ThreadHandle(tid, Program.MinThreadQueryRights); + + try + { + item.PriorityI = (int)item.ThreadQueryLimitedHandle.GetBasePriorityWin32(); + item.Priority = item.ThreadQueryLimitedHandle.GetBasePriorityWin32().ToString(); + } + catch + { } + + if (KProcessHacker.Instance != null) + { + try + { + item.IsGuiThread = KProcessHacker.Instance.KphGetThreadWin32Thread(item.ThreadQueryLimitedHandle) != 0; + } + catch + { } + } + + if (OSVersion.HasCycleTime) + { + try + { + item.Cycles = item.ThreadQueryLimitedHandle.GetCycleTime(); + } + catch + { } + } + } + catch + { } + + if (KProcessHacker.Instance != null && item.ThreadQueryLimitedHandle != null) + { + try + { + item.StartAddressI = + KProcessHacker.Instance.GetThreadStartAddress(item.ThreadQueryLimitedHandle).ToIntPtr(); + } + catch + { } + } + else + { + try + { + using (ThreadHandle thandle = + new ThreadHandle(tid, ThreadAccess.QueryInformation)) + { + item.StartAddressI = thandle.GetWin32StartAddress(); + } + } + catch + { + item.StartAddressI = t.StartAddress; + } + } + + if (!_waitedForLoad) + { + _waitedForLoad = true; + + try + { + if (_moduleLoadCompletedEvent.WaitOne(0, false)) + { + item.StartAddress = this.GetThreadBasicStartAddress( + item.StartAddressI.ToUInt64(), out item.StartAddressLevel); + } + } + catch + { } + } + + if (string.IsNullOrEmpty(item.StartAddress)) + { + item.StartAddress = Utils.FormatAddress(item.StartAddressI); + item.StartAddressLevel = SymbolResolveLevel.Address; + } + + this.QueueThreadResolveStartAddress(tid, item.StartAddressI.ToUInt64()); + + newdictionary.Add(tid, item); + this.OnDictionaryAdded(item); + } + // look for modified threads + else + { + ThreadItem item = Dictionary[tid]; + ThreadItem newitem = item.Clone() as ThreadItem; + + newitem.JustResolved = false; + newitem.ContextSwitchesDelta = t.ContextSwitchCount - newitem.ContextSwitches; + newitem.ContextSwitches = t.ContextSwitchCount; + newitem.WaitReason = t.WaitReason; + + try + { + newitem.PriorityI = (int)newitem.ThreadQueryLimitedHandle.GetBasePriorityWin32(); + newitem.Priority = newitem.ThreadQueryLimitedHandle.GetBasePriorityWin32().ToString(); + } + catch + { } + + if (KProcessHacker.Instance != null) + { + try + { + newitem.IsGuiThread = KProcessHacker.Instance.KphGetThreadWin32Thread(newitem.ThreadQueryLimitedHandle) != 0; + } + catch + { } + } + + if (OSVersion.HasCycleTime) + { + try + { + ulong thisCycles = newitem.ThreadQueryLimitedHandle.GetCycleTime(); + + newitem.CyclesDelta = thisCycles - newitem.Cycles; + newitem.Cycles = thisCycles; + } + catch + { } + } + + if (newitem.StartAddressLevel == SymbolResolveLevel.Address) + { + if (_moduleLoadCompletedEvent.WaitOne(0, false)) + { + newitem.StartAddress = this.GetThreadBasicStartAddress( + newitem.StartAddressI.ToUInt64(), out newitem.StartAddressLevel); + } + + // If we couldn't resolve it to a module+offset, + // use the StartAddress (instead of the Win32StartAddress) + // and queue the resolve again. + if ( + item.StartAddressLevel == SymbolResolveLevel.Address && + item.JustResolved) + { + if (item.StartAddressI != t.StartAddress) + { + item.StartAddressI = t.StartAddress; + this.QueueThreadResolveStartAddress(tid, item.StartAddressI.ToUInt64()); + } + } + } + + if ( + newitem.ContextSwitches != item.ContextSwitches || + newitem.ContextSwitchesDelta != item.ContextSwitchesDelta || + newitem.Cycles != item.Cycles || + newitem.CyclesDelta != item.CyclesDelta || + newitem.IsGuiThread != item.IsGuiThread || + newitem.Priority != item.Priority || + newitem.StartAddress != item.StartAddress || + newitem.WaitReason != item.WaitReason || + item.JustResolved + ) + { + newdictionary[tid] = newitem; + this.OnDictionaryModified(item, newitem); + } + } + } + + Dictionary = newdictionary; + } + + public SymbolProvider Symbols + { + get { return _symbols; } + } + + public int Pid + { + get { return _pid; } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Resources/VirusTotal-logo.png b/branches/ph-plugins/ProcessHacker/Resources/VirusTotal-logo.png new file mode 100644 index 000000000..e87e7c1f3 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/VirusTotal-logo.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/active_search.png b/branches/ph-plugins/ProcessHacker/Resources/active_search.png new file mode 100644 index 000000000..6a0bb18b7 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/active_search.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/application.png b/branches/ph-plugins/ProcessHacker/Resources/application.png new file mode 100644 index 000000000..1dee9e366 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/application.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/application_delete.png b/branches/ph-plugins/ProcessHacker/Resources/application_delete.png new file mode 100644 index 000000000..0a335acf6 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/application_delete.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/application_form_magnify.png b/branches/ph-plugins/ProcessHacker/Resources/application_form_magnify.png new file mode 100644 index 000000000..7b7fbd17e Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/application_form_magnify.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/application_go.png b/branches/ph-plugins/ProcessHacker/Resources/application_go.png new file mode 100644 index 000000000..5cc2b0dd3 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/application_go.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/application_view_detail.png b/branches/ph-plugins/ProcessHacker/Resources/application_view_detail.png new file mode 100644 index 000000000..aba044bbc Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/application_view_detail.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/arrow_refresh.png b/branches/ph-plugins/ProcessHacker/Resources/arrow_refresh.png new file mode 100644 index 000000000..0de26566d Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/arrow_refresh.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/arrow_right.png b/branches/ph-plugins/ProcessHacker/Resources/arrow_right.png new file mode 100644 index 000000000..b1a181923 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/arrow_right.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/arrow_up.png b/branches/ph-plugins/ProcessHacker/Resources/arrow_up.png new file mode 100644 index 000000000..1ebb19324 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/arrow_up.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/asterisk_orange.png b/branches/ph-plugins/ProcessHacker/Resources/asterisk_orange.png new file mode 100644 index 000000000..1ebebde54 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/asterisk_orange.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/bricks.png b/branches/ph-plugins/ProcessHacker/Resources/bricks.png new file mode 100644 index 000000000..0905f933b Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/bricks.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/chart_curve.png b/branches/ph-plugins/ProcessHacker/Resources/chart_curve.png new file mode 100644 index 000000000..01e933a61 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/chart_curve.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/chart_line.png b/branches/ph-plugins/ProcessHacker/Resources/chart_line.png new file mode 100644 index 000000000..85020f320 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/chart_line.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/cog.png b/branches/ph-plugins/ProcessHacker/Resources/cog.png new file mode 100644 index 000000000..67de2c6cc Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/cog.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/cog_edit.png b/branches/ph-plugins/ProcessHacker/Resources/cog_edit.png new file mode 100644 index 000000000..47b75a456 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/cog_edit.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/control_equalizer.png b/branches/ph-plugins/ProcessHacker/Resources/control_equalizer.png new file mode 100644 index 000000000..46060872c Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/control_equalizer.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/control_equalizer_blue.png b/branches/ph-plugins/ProcessHacker/Resources/control_equalizer_blue.png new file mode 100644 index 000000000..1b2e6a374 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/control_equalizer_blue.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/control_pause.png b/branches/ph-plugins/ProcessHacker/Resources/control_pause.png new file mode 100644 index 000000000..2d9ce9c4e Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/control_pause.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/control_pause_blue.png b/branches/ph-plugins/ProcessHacker/Resources/control_pause_blue.png new file mode 100644 index 000000000..ec61099b0 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/control_pause_blue.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/control_play.png b/branches/ph-plugins/ProcessHacker/Resources/control_play.png new file mode 100644 index 000000000..0846555d0 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/control_play.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/control_play_blue.png b/branches/ph-plugins/ProcessHacker/Resources/control_play_blue.png new file mode 100644 index 000000000..f8c8ec683 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/control_play_blue.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/control_stop.png b/branches/ph-plugins/ProcessHacker/Resources/control_stop.png new file mode 100644 index 000000000..893bb60e5 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/control_stop.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/control_stop_blue.png b/branches/ph-plugins/ProcessHacker/Resources/control_stop_blue.png new file mode 100644 index 000000000..e6f75d232 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/control_stop_blue.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/cross.png b/branches/ph-plugins/ProcessHacker/Resources/cross.png new file mode 100644 index 000000000..1514d51a3 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/cross.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/delete.png b/branches/ph-plugins/ProcessHacker/Resources/delete.png new file mode 100644 index 000000000..08f249365 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/delete.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/disk.png b/branches/ph-plugins/ProcessHacker/Resources/disk.png new file mode 100644 index 000000000..99d532e8b Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/disk.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/door_out.png b/branches/ph-plugins/ProcessHacker/Resources/door_out.png new file mode 100644 index 000000000..2541d2bcb Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/door_out.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/find.png b/branches/ph-plugins/ProcessHacker/Resources/find.png new file mode 100644 index 000000000..154747964 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/find.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/folder_explore.png b/branches/ph-plugins/ProcessHacker/Resources/folder_explore.png new file mode 100644 index 000000000..0ba939184 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/folder_explore.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/folder_go.png b/branches/ph-plugins/ProcessHacker/Resources/folder_go.png new file mode 100644 index 000000000..34a736f70 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/folder_go.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/group.png b/branches/ph-plugins/ProcessHacker/Resources/group.png new file mode 100644 index 000000000..7fb4e1f1e Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/group.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/help.png b/branches/ph-plugins/ProcessHacker/Resources/help.png new file mode 100644 index 000000000..5c870176d Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/help.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/inactive_search.png b/branches/ph-plugins/ProcessHacker/Resources/inactive_search.png new file mode 100644 index 000000000..a90891192 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/inactive_search.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/information.png b/branches/ph-plugins/ProcessHacker/Resources/information.png new file mode 100644 index 000000000..12cd1aef9 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/information.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/lightbulb_off.png b/branches/ph-plugins/ProcessHacker/Resources/lightbulb_off.png new file mode 100644 index 000000000..e95b8c5b1 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/lightbulb_off.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/lock.png b/branches/ph-plugins/ProcessHacker/Resources/lock.png new file mode 100644 index 000000000..2ebc4f6f9 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/lock.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/lock_edit.png b/branches/ph-plugins/ProcessHacker/Resources/lock_edit.png new file mode 100644 index 000000000..116aa5b7f Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/lock_edit.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/money.png b/branches/ph-plugins/ProcessHacker/Resources/money.png new file mode 100644 index 000000000..42c52d05f Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/money.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/mouse.png b/branches/ph-plugins/ProcessHacker/Resources/mouse.png new file mode 100644 index 000000000..63a92fa91 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/mouse.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/page.png b/branches/ph-plugins/ProcessHacker/Resources/page.png new file mode 100644 index 000000000..03ddd799f Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/page.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/page_copy.png b/branches/ph-plugins/ProcessHacker/Resources/page_copy.png new file mode 100644 index 000000000..195dc6d6c Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/page_copy.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/page_edit.png b/branches/ph-plugins/ProcessHacker/Resources/page_edit.png new file mode 100644 index 000000000..046811ed7 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/page_edit.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/page_gear.png b/branches/ph-plugins/ProcessHacker/Resources/page_gear.png new file mode 100644 index 000000000..8e83281c5 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/page_gear.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/page_save.png b/branches/ph-plugins/ProcessHacker/Resources/page_save.png new file mode 100644 index 000000000..caea546af Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/page_save.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/page_white_text.png b/branches/ph-plugins/ProcessHacker/Resources/page_white_text.png new file mode 100644 index 000000000..813f712f7 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/page_white_text.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/pencil.png b/branches/ph-plugins/ProcessHacker/Resources/pencil.png new file mode 100644 index 000000000..0bfecd50e Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/pencil.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/pencil_go.png b/branches/ph-plugins/ProcessHacker/Resources/pencil_go.png new file mode 100644 index 000000000..937bded9d Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/pencil_go.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/report.png b/branches/ph-plugins/ProcessHacker/Resources/report.png new file mode 100644 index 000000000..779ad58ef Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/report.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/report_user.png b/branches/ph-plugins/ProcessHacker/Resources/report_user.png new file mode 100644 index 000000000..7766edd74 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/report_user.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/sflogo.png b/branches/ph-plugins/ProcessHacker/Resources/sflogo.png new file mode 100644 index 000000000..b54718faf Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/sflogo.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/table.png b/branches/ph-plugins/ProcessHacker/Resources/table.png new file mode 100644 index 000000000..abcd93689 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/table.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/table_relationship.png b/branches/ph-plugins/ProcessHacker/Resources/table_relationship.png new file mode 100644 index 000000000..28b8505c0 Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/table_relationship.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/table_sort.png b/branches/ph-plugins/ProcessHacker/Resources/table_sort.png new file mode 100644 index 000000000..ed6785a6a Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/table_sort.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/tick.png b/branches/ph-plugins/ProcessHacker/Resources/tick.png new file mode 100644 index 000000000..a9925a06a Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/tick.png differ diff --git a/branches/ph-plugins/ProcessHacker/Resources/user.png b/branches/ph-plugins/ProcessHacker/Resources/user.png new file mode 100644 index 000000000..79f35ccbd Binary files /dev/null and b/branches/ph-plugins/ProcessHacker/Resources/user.png differ diff --git a/branches/ph-plugins/ProcessHacker/Searchers/HeapSearcher.cs b/branches/ph-plugins/ProcessHacker/Searchers/HeapSearcher.cs new file mode 100644 index 000000000..4e7e269f1 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Searchers/HeapSearcher.cs @@ -0,0 +1,81 @@ +/* + * Process Hacker - + * heap searcher + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Runtime.InteropServices; +using ProcessHacker.Common; +using ProcessHacker.Native.Api; + +namespace ProcessHacker +{ + public class HeapSearcher : Searcher + { + public HeapSearcher(int PID) : base(PID) { } + + public override void Search() + { + Results.Clear(); + + IntPtr snapshot; + var hlist = new HeapList32(); + var heap = new HeapEntry32(); + int minsize = (int)BaseConverter.ToNumberParse((string)Params["h_ms"]); + int count = 0; + + snapshot = Win32.CreateToolhelp32Snapshot(SnapshotFlags.HeapList, PID); + + hlist.dwSize = Marshal.SizeOf(hlist); + heap.dwSize = Marshal.SizeOf(heap); + + if (snapshot != IntPtr.Zero && Marshal.GetLastWin32Error() == 0) + { + Win32.Heap32ListFirst(snapshot, ref hlist); + + do + { + Win32.Heap32First(ref heap, hlist.th32ProcessID, hlist.th32HeapID); + + do + { + CallSearchProgressChanged( + String.Format("Searching 0x{0} ({1} found)...", heap.dwAddress.ToString("x"), count)); + + if (heap.dwBlockSize <= minsize) + continue; + + Results.Add(new string[] { Utils.FormatAddress(heap.dwAddress), + "0x0", heap.dwBlockSize.ToString(), heap.dwFlags.ToString().Replace("LF32_", "") }); + + count++; + } while (Win32.Heap32Next(out heap) != 0); + } while (Win32.Heap32ListNext(snapshot, out hlist)); + } + else + { + CallSearchError(Win32.GetLastErrorMessage()); + return; + } + + CallSearchFinished(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Searchers/LiteralSearcher.cs b/branches/ph-plugins/ProcessHacker/Searchers/LiteralSearcher.cs new file mode 100644 index 000000000..4928ec9e6 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Searchers/LiteralSearcher.cs @@ -0,0 +1,141 @@ +/* + * Process Hacker - + * literal searcher + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Runtime.InteropServices; +using ProcessHacker.Common; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker +{ + public class LiteralSearcher : Searcher + { + public LiteralSearcher(int PID) : base(PID) { } + + public override void Search() + { + Results.Clear(); + + byte[] text = (byte[])Params["text"]; + ProcessHandle phandle; + int count = 0; + + bool opt_priv = (bool)Params["private"]; + bool opt_img = (bool)Params["image"]; + bool opt_map = (bool)Params["mapped"]; + + bool nooverlap = (bool)Params["nooverlap"]; + + if (text.Length == 0) + { + CallSearchFinished(); + return; + } + + try + { + phandle = new ProcessHandle(PID, + ProcessAccess.QueryInformation | + Program.MinProcessReadMemoryRights); + } + catch + { + CallSearchError("Could not open process: " + Win32.GetLastErrorMessage()); + return; + } + + phandle.EnumMemory((info) => + { + // skip unreadable areas + if (info.Protect == MemoryProtection.AccessDenied) + return true; + if (info.State != MemoryState.Commit) + return true; + + if ((!opt_priv) && (info.Type == MemoryType.Private)) + return true; + + if ((!opt_img) && (info.Type == MemoryType.Image)) + return true; + + if ((!opt_map) && (info.Type == MemoryType.Mapped)) + return true; + + byte[] data = new byte[info.RegionSize.ToInt32()]; + int bytesRead = 0; + + CallSearchProgressChanged( + String.Format("Searching 0x{0} ({1} found)...", info.BaseAddress.ToString("x"), count)); + + try + { + bytesRead = phandle.ReadMemory(info.BaseAddress, data, data.Length); + + if (bytesRead == 0) + return true; + } + catch + { + return true; + } + + for (int i = 0; i < bytesRead; i++) + { + bool good = true; + + for (int j = 0; j < text.Length; j++) + { + if (i + j > bytesRead - 1) + continue; + + if (data[i + j] != text[j]) + { + good = false; + break; + } + } + + if (good) + { + Results.Add(new string[] { Utils.FormatAddress(info.BaseAddress), + String.Format("0x{0:x}", i), text.Length.ToString(), "" }); + + count++; + + if (nooverlap) + i += text.Length - 1; + } + } + + data = null; + + return true; + }); + + phandle.Dispose(); + + CallSearchFinished(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Searchers/RegexSearcher.cs b/branches/ph-plugins/ProcessHacker/Searchers/RegexSearcher.cs new file mode 100644 index 000000000..125388133 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Searchers/RegexSearcher.cs @@ -0,0 +1,148 @@ +/* + * Process Hacker - + * regex searcher + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Text; +using System.Text.RegularExpressions; +using ProcessHacker.Common; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker +{ + public class RegexSearcher : Searcher + { + public RegexSearcher(int PID) : base(PID) { } + + public override void Search() + { + Results.Clear(); + + string regex = (string)Params["regex"]; + ProcessHandle phandle; + int count = 0; + + RegexOptions options = RegexOptions.Singleline | RegexOptions.Compiled; + Regex rx = null; + + bool opt_priv = (bool)Params["private"]; + bool opt_img = (bool)Params["image"]; + bool opt_map = (bool)Params["mapped"]; + + if (regex.Length == 0) + { + CallSearchFinished(); + return; + } + + try + { + if ((bool)Params["ignorecase"]) + options |= RegexOptions.IgnoreCase; + + rx = new Regex(regex, options); + } + catch (Exception ex) + { + CallSearchError("Could not initialize regex: " + ex.Message); + return; + } + + try + { + phandle = new ProcessHandle(PID, + ProcessAccess.QueryInformation | + Program.MinProcessReadMemoryRights); + } + catch + { + CallSearchError("Could not open process: " + Win32.GetLastErrorMessage()); + return; + } + + phandle.EnumMemory((info) => + { + // skip unreadable areas + if (info.Protect == MemoryProtection.AccessDenied) + return true; + if (info.State != MemoryState.Commit) + return true; + + if ((!opt_priv) && (info.Type == MemoryType.Private)) + return true; + + if ((!opt_img) && (info.Type == MemoryType.Image)) + return true; + + if ((!opt_map) && (info.Type == MemoryType.Mapped)) + return true; + + byte[] data = new byte[info.RegionSize.ToInt32()]; + int bytesRead = 0; + + CallSearchProgressChanged( + String.Format("Searching 0x{0} ({1} found)...", info.BaseAddress.ToString("x"), count)); + + try + { + bytesRead = phandle.ReadMemory(info.BaseAddress, data, data.Length); + + if (bytesRead == 0) + return true; + } + catch + { + return true; + } + + StringBuilder sdata = new StringBuilder(); + string sdata2 = ""; + + for (int i = 0; i < data.Length; i++) + sdata.Append((char)data[i]); + + sdata2 = sdata.ToString(); + sdata = null; + + MatchCollection mc = rx.Matches(sdata2); + + foreach (Match m in mc) + { + Results.Add(new string[] { Utils.FormatAddress(info.BaseAddress), + String.Format("0x{0:x}", m.Index), m.Length.ToString(), + Utils.MakePrintable(m.Value) }); + + count++; + } + + data = null; + + return true; + }); + + phandle.Dispose(); + + CallSearchFinished(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Searchers/SearchOptions.cs b/branches/ph-plugins/ProcessHacker/Searchers/SearchOptions.cs new file mode 100644 index 000000000..d948c4617 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Searchers/SearchOptions.cs @@ -0,0 +1,139 @@ +/* + * Process Hacker - + * wrapper around the Searcher class + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker +{ + /// + /// The type of search to be performed. + /// + public enum SearchType + { + Literal, Regex, String, Heap, Struct + } + + /// + /// Contains a class, a search type and a PID. + /// + public class SearchOptions + { + private int _pid; + private SearchType _type = SearchType.Literal; + private Searcher _searcher; + + /// + /// Creates a search with the specified PID and search type. + /// + /// The PID of the process to be searched. + /// The type of search () to be performed. + public SearchOptions(int PID, SearchType type) + { + _pid = PID; + + _searcher = new Searcher(_pid); + + // defaults + _searcher.Params.Add("text", new byte[0]); + _searcher.Params.Add("regex", ""); + _searcher.Params.Add("s_ms", "10"); + _searcher.Params.Add("unicode", true); + _searcher.Params.Add("h_ms", "1024"); + _searcher.Params.Add("nooverlap", true); + _searcher.Params.Add("ignorecase", false); + _searcher.Params.Add("private", true); + _searcher.Params.Add("image", false); + _searcher.Params.Add("mapped", false); + _searcher.Params.Add("struct", ""); + _searcher.Params.Add("struct_align", "4"); + + Type = type; + } + + /// + /// The PID associated with this search. + /// + public int PID + { + get { return _pid; } + } + + /// + /// The type of search to be performed. + /// + public SearchType Type + { + get { return _type; } + set + { + _type = value; + + Dictionary oldparams = _searcher.Params; + List oldresults = _searcher.Results; + + switch (_type) + { + case SearchType.Literal: + _searcher = new LiteralSearcher(PID); + break; + + case SearchType.Regex: + _searcher = new RegexSearcher(PID); + break; + + case SearchType.String: + _searcher = new StringSearcher(PID); + break; + + case SearchType.Heap: + _searcher = new HeapSearcher(PID); + break; + + case SearchType.Struct: + _searcher = new StructSearcher(PID); + break; + + default: + _searcher = new Searcher(PID); + break; + } + + foreach (string s in oldparams.Keys) + { + _searcher.Params.Add(s, oldparams[s]); + } + + _searcher.Results = oldresults; + } + } + + /// + /// The class. + /// + public Searcher Searcher + { + get { return _searcher; } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Searchers/Searcher.cs b/branches/ph-plugins/ProcessHacker/Searchers/Searcher.cs new file mode 100644 index 000000000..3e08d9d04 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Searchers/Searcher.cs @@ -0,0 +1,122 @@ +/* + * Process Hacker - + * searcher base class + * + * Copyright (C) 2008 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 . + */ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace ProcessHacker +{ + public delegate void SearchFinished(); + public delegate void SearchProgressChanged(string progress); + public delegate void SearchError(string message); + + /// + /// Defines a generic process memory searcher with status events. + /// + public interface ISearcher + { + event SearchFinished SearchFinished; + event SearchProgressChanged SearchProgressChanged; + event SearchError SearchError; + int PID { get; } + Dictionary Params { get; } + List Results { get; } + void Search(); + } + + /// + /// A base process memory searcher. All searchers should inherit from this class. + /// + public class Searcher : ISearcher + { + private int _pid; + private Dictionary _params; + private List _results; + + public event SearchFinished SearchFinished; + public event SearchProgressChanged SearchProgressChanged; + public event SearchError SearchError; + + /// + /// Creates a dummy searcher which does nothing. + /// + /// This parameter has no effect. + public Searcher(int PID) + { + _pid = PID; + _params = new Dictionary(); + _results = new List(); + } + + /// + /// The PID of the process to be searched. + /// + public int PID + { + get { return _pid; } + } + + /// + /// The parameters of the search. + /// + public Dictionary Params + { + get { return _params; } + } + + /// + /// A containing the search results. + /// + public List Results + { + get { return _results; } + set { _results = value; } + } + + /// + /// This is a dummy function, and should be overridden. + /// + public virtual void Search() + { + } + + protected void CallSearchFinished() + { + if (SearchFinished != null) + SearchFinished(); + } + + protected void CallSearchProgressChanged(string progress) + { + if (SearchProgressChanged != null) + SearchProgressChanged(progress); + } + + protected void CallSearchError(string message) + { + if (SearchError != null) + SearchError(message); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Searchers/StringSearcher.cs b/branches/ph-plugins/ProcessHacker/Searchers/StringSearcher.cs new file mode 100644 index 000000000..295feeba6 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Searchers/StringSearcher.cs @@ -0,0 +1,173 @@ +/* + * Process Hacker - + * string searcher + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Text; +using ProcessHacker.Common; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker +{ + public class StringSearcher : Searcher + { + public StringSearcher(int PID) : base(PID) { } + + private bool IsChar(byte b) + { + return (b >= ' ' && b <= '~') || b == '\n' || b == '\r' || b == '\t'; + } + + public override void Search() + { + Results.Clear(); + + byte[] text = (byte[])Params["text"]; + ProcessHandle phandle; + int count = 0; + + int minsize = (int)BaseConverter.ToNumberParse((string)Params["s_ms"]); + bool unicode = (bool)Params["unicode"]; + + bool opt_priv = (bool)Params["private"]; + bool opt_img = (bool)Params["image"]; + bool opt_map = (bool)Params["mapped"]; + + try + { + phandle = new ProcessHandle(PID, + ProcessAccess.QueryInformation | + Program.MinProcessReadMemoryRights); + } + catch + { + CallSearchError("Could not open process: " + Win32.GetLastErrorMessage()); + return; + } + + phandle.EnumMemory((info) => + { + // skip unreadable areas + if (info.Protect == MemoryProtection.AccessDenied) + return true; + if (info.State != MemoryState.Commit) + return true; + + if ((!opt_priv) && (info.Type == MemoryType.Private)) + return true; + + if ((!opt_img) && (info.Type == MemoryType.Image)) + return true; + + if ((!opt_map) && (info.Type == MemoryType.Mapped)) + return true; + + byte[] data = new byte[info.RegionSize.ToInt32()]; + int bytesRead = 0; + + CallSearchProgressChanged( + String.Format("Searching 0x{0} ({1} found)...", info.BaseAddress.ToString("x"), count)); + + try + { + bytesRead = phandle.ReadMemory(info.BaseAddress, data, data.Length); + + if (bytesRead == 0) + return true; + } + catch + { + return true; + } + + StringBuilder curstr = new StringBuilder(); + bool isUnicode = false; + byte byte2 = 0; + byte byte1 = 0; + + for (int i = 0; i < bytesRead; i++) + { + bool isChar = IsChar(data[i]); + + if (unicode && isChar && isUnicode && byte1 != 0) + { + isUnicode = false; + + if (curstr.Length > 0) + curstr.Remove(curstr.Length - 1, 1); + + curstr.Append((char)data[i]); + } + else if (isChar) + { + curstr.Append((char)data[i]); + } + else if (unicode && data[i] == 0 && IsChar(byte1) && !IsChar(byte2)) + { + // skip null byte + isUnicode = true; + } + else if (unicode && + data[i] == 0 && IsChar(byte1) && IsChar(byte2) && curstr.Length < minsize) + { + // ... [char] [char] *[null]* ([char] [null] [char] [null]) ... + // ^ we are here + isUnicode = true; + curstr = new StringBuilder(); + curstr.Append((char)byte1); + } + else + { + if (curstr.Length >= minsize) + { + int length = curstr.Length; + + if (isUnicode) + length *= 2; + + Results.Add(new string[] { Utils.FormatAddress(info.BaseAddress), + String.Format("0x{0:x}", i - length), length.ToString(), + curstr.ToString() }); + + count++; + } + + isUnicode = false; + curstr = new StringBuilder(); + } + + byte2 = byte1; + byte1 = data[i]; + } + + data = null; + + return true; + }); + + phandle.Dispose(); + + CallSearchFinished(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Searchers/StructSearcher.cs b/branches/ph-plugins/ProcessHacker/Searchers/StructSearcher.cs new file mode 100644 index 000000000..76257558e --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Searchers/StructSearcher.cs @@ -0,0 +1,115 @@ +/* + * Process Hacker - + * struct searcher + * + * Copyright (C) 2009 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 . + */ + +using System; +using ProcessHacker.Common; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Structs; + +namespace ProcessHacker +{ + public class StructSearcher : Searcher + { + public StructSearcher(int PID) : base(PID) { } + + public override void Search() + { + Results.Clear(); + + ProcessHandle phandle; + int count = 0; + + bool opt_priv = (bool)Params["private"]; + bool opt_img = (bool)Params["image"]; + bool opt_map = (bool)Params["mapped"]; + + string structName = (string)Params["struct"]; + int align = (int)BaseConverter.ToNumberParse((string)Params["struct_align"]); + + if (!Program.Structs.ContainsKey(structName)) + { + CallSearchError("Struct '" + structName + "' is not defined."); + return; + } + + StructDef structDef = Program.Structs[structName]; + string structLen = structDef.Size.ToString(); + + structDef.IOProvider = new ProcessMemoryIO(PID); + + try + { + phandle = new ProcessHandle(PID, ProcessHacker.Native.Security.ProcessAccess.QueryInformation); + } + catch + { + CallSearchError("Could not open process: " + Win32.GetLastErrorMessage()); + return; + } + + phandle.EnumMemory((info) => + { + // skip unreadable areas + if (info.Protect == MemoryProtection.AccessDenied) + return true; + if (info.State != MemoryState.Commit) + return true; + + if ((!opt_priv) && (info.Type == MemoryType.Private)) + return true; + + if ((!opt_img) && (info.Type == MemoryType.Image)) + return true; + + if ((!opt_map) && (info.Type == MemoryType.Mapped)) + return true; + + CallSearchProgressChanged( + String.Format("Searching 0x{0} ({1} found)...", info.BaseAddress.ToString("x"), count)); + + for (int i = 0; i < info.RegionSize.ToInt32(); i += align) + { + try + { + structDef.Offset = info.BaseAddress.Increment(i); + structDef.Read(); + + // read succeeded, add it to the results + Results.Add(new string[] { Utils.FormatAddress(info.BaseAddress), + String.Format("0x{0:x}", i), structLen, "" }); + count++; + } + catch + { } + } + + return true; + }); + + phandle.Dispose(); + + CallSearchFinished(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/SharpDevelop/LICENSE.txt b/branches/ph-plugins/ProcessHacker/SharpDevelop/LICENSE.txt new file mode 100644 index 000000000..fce74132e --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/SharpDevelop/LICENSE.txt @@ -0,0 +1,458 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +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 this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +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 +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser 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 Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/branches/ph-plugins/ProcessHacker/SharpDevelop/MTA2STA.cs b/branches/ph-plugins/ProcessHacker/SharpDevelop/MTA2STA.cs new file mode 100644 index 000000000..1c358eea6 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/SharpDevelop/MTA2STA.cs @@ -0,0 +1,252 @@ +// +// +// +// +// $Revision: 2903 $ +// + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Threading; +using System.Windows.Forms; + +namespace Debugger.Interop +{ + public delegate T MethodInvokerWithReturnValue(); + + public enum CallMethod {DirectCall, Manual, HiddenForm, HiddenFormWithTimeout}; + + public class MTA2STA + { + Form hiddenForm; + IntPtr hiddenFormHandle; + + System.Threading.Thread targetThread; + CallMethod callMethod = CallMethod.HiddenFormWithTimeout; + + Queue pendingCalls = new Queue(); + ManualResetEvent pendingCallsNotEmpty = new ManualResetEvent(false); + + WaitHandle EnqueueCall(MethodInvoker callDelegate) + { + lock (pendingCalls) { + ManualResetEvent callDone = new ManualResetEvent(false); + pendingCalls.Enqueue(delegate{ + callDelegate(); + callDone.Set(); + }); + pendingCallsNotEmpty.Set(); + return callDone; + } + } + + /// + /// Wait until a call a made + /// + public void WaitForCall() + { + pendingCallsNotEmpty.WaitOne(); + } + + public void WaitForCall(TimeSpan timeout) + { + pendingCallsNotEmpty.WaitOne(timeout, false); + } + + /// + /// Performs all waiting calls on the current thread + /// + public void PerformAllCalls() + { + while (true) { + if (!PerformCall()) { + return; + } + } + } + + /// + /// Performs all waiting calls on the current thread + /// + public bool PerformCall() + { + MethodInvoker nextMethod; + lock (pendingCalls) { + if (pendingCalls.Count > 0) { + nextMethod = pendingCalls.Dequeue(); + } else { + pendingCallsNotEmpty.Reset(); + return false; + } + } + nextMethod(); + return true; + } + + public CallMethod CallMethod { + get { + return callMethod; + } + set { + callMethod = value; + } + } + + public MTA2STA() + { + targetThread = System.Threading.Thread.CurrentThread; + + hiddenForm = new Form(); + // Force handle creation + hiddenFormHandle = hiddenForm.Handle; + } + + /// + /// SoftWait waits for any of the given WaitHandles and allows processing of calls during the wait + /// + public int SoftWait(params WaitHandle[] waitFor) + { + List waits = new List (waitFor); + waits.Add(pendingCallsNotEmpty); + while(true) { + int i = WaitHandle.WaitAny(waits.ToArray()); + PerformAllCalls(); + if (i < waits.Count - 1) { // If not pendingCallsNotEmpty + return i; + } + } + } + + /// + /// Schedules invocation of method and returns immediately + /// + public WaitHandle AsyncCall(MethodInvoker callDelegate) + { + WaitHandle callDone = EnqueueCall(callDelegate); + TriggerInvoke(); + return callDone; + } + + public T Call(MethodInvokerWithReturnValue callDelegate) + { + T returnValue = default(T); + Call(delegate { returnValue = callDelegate(); }, true); + return returnValue; + } + + public void Call(MethodInvoker callDelegate) + { + Call(callDelegate, false); + } + + void Call(MethodInvoker callDelegate, bool hasReturnValue) + { + // Enqueue the call + WaitHandle callDone = EnqueueCall(callDelegate); + + if (targetThread == System.Threading.Thread.CurrentThread) { + PerformAllCalls(); + return; + } + + // We have the call waiting in queue, we need to call it (not waiting for it to finish) + TriggerInvoke(); + + // Wait for the call to finish + if (!hasReturnValue && callMethod == CallMethod.HiddenFormWithTimeout) { + // Give it 5 seconds to run + if (!callDone.WaitOne(5000, true)) { + System.Console.WriteLine("Call time out! (continuing)"); + System.Console.WriteLine(new System.Diagnostics.StackTrace(true).ToString()); + } + } else { + callDone.WaitOne(); + } + } + + void TriggerInvoke() + { + switch (callMethod) { + case CallMethod.DirectCall: + PerformAllCalls(); + break; + case CallMethod.Manual: + // Nothing we can do - someone else must call SoftWait or Pulse + break; + case CallMethod.HiddenForm: + case CallMethod.HiddenFormWithTimeout: + hiddenForm.BeginInvoke((MethodInvoker)PerformAllCalls); + break; + } + } + + public static object MarshalParamTo(object param, Type outputType) + { + if (param is IntPtr) { + return MarshalIntPtrTo((IntPtr)param, outputType); + } else { + return param; + } + } + + public static T MarshalIntPtrTo(IntPtr param) + { + return (T)MarshalIntPtrTo(param, typeof(T)); + } + + public static object MarshalIntPtrTo(IntPtr param, Type outputType) + { + // IntPtr requested as output (must be before the null check so that we pass IntPtr.Zero) + if (outputType == typeof(IntPtr)) { + return param; + } + // The parameter is null pointer + if ((IntPtr)param == IntPtr.Zero) { + return null; + } + // String requested as output + if (outputType == typeof(string)) { + return Marshal.PtrToStringAuto((IntPtr)param); + } + // Marshal a COM object + object comObject = Marshal.GetObjectForIUnknown(param); + return Activator.CreateInstance(outputType, comObject); + } + + /// + /// Uses reflection to call method. Automaticaly marshals parameters. + /// + /// Targed object which contains the method. In case of static mehod pass the Type + /// The name of the function to call + /// Parameters which should be send to the function. Parameters will be marshaled to proper type. + /// Return value of the called function + public static object InvokeMethod(object targetObject, string functionName, object[] functionParameters) + { + System.Reflection.MethodInfo method; + if (targetObject is Type) { + method = ((Type)targetObject).GetMethod(functionName); + } else { + method = targetObject.GetType().GetMethod(functionName); + } + + ParameterInfo[] methodParamsInfo = method.GetParameters(); + object[] convertedParams = new object[methodParamsInfo.Length]; + + for (int i = 0; i < convertedParams.Length; i++) { + convertedParams[i] = MarshalParamTo(functionParameters[i], methodParamsInfo[i].ParameterType); + } + + try { + if (targetObject is Type) { + return method.Invoke(null, convertedParams); + } else { + return method.Invoke(targetObject, convertedParams); + } + } catch (System.Exception exception) { + throw new Exception("Invoke of " + functionName + " failed.", exception); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/SharpDevelop/NDebugger.cs b/branches/ph-plugins/ProcessHacker/SharpDevelop/NDebugger.cs new file mode 100644 index 000000000..174f1770c --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/SharpDevelop/NDebugger.cs @@ -0,0 +1,89 @@ +using System; +using System.Diagnostics; + +namespace Debugger +{ + [Serializable] + public class DebuggerEventArgs : EventArgs + { + object debugger; + + public object Debugger + { + get { + return debugger; + } + } + + public DebuggerEventArgs(object debugger) + { + this.debugger = debugger; + } + } + + [Serializable] + public class ProcessEventArgs : DebuggerEventArgs + { + Process process; + + public Process Process + { + get + { + return process; + } + } + + public ProcessEventArgs(Process process) + : base(null) + { + this.process = process; + } + } + + [Serializable] + public class MessageEventArgs : ProcessEventArgs + { + int level; + string message; + string category; + + public int Level + { + get + { + return level; + } + } + + public string Message + { + get + { + return message; + } + } + + public string Category + { + get + { + return category; + } + } + + public MessageEventArgs(Process process, string message) + : this(process, 0, message, String.Empty) + { + this.message = message; + } + + public MessageEventArgs(Process process, int level, string message, string category) + : base(process) + { + this.level = level; + this.message = message; + this.category = category; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/Autogenerated/CorPublishClass.cs b/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/Autogenerated/CorPublishClass.cs new file mode 100644 index 000000000..7785149c1 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/Autogenerated/CorPublishClass.cs @@ -0,0 +1,60 @@ +// +// +// +// +// $Revision: 3165 $ +// + +#pragma warning disable 108, 1591 + +namespace Debugger.Interop.CorPub +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + using System.Text; + + [ComImport, TypeLibType((short) 2), ClassInterface((short) 0), Guid("047A9A40-657E-11D3-8D5B-00104B35E7EF")] + public class CorpubPublishClass : ICorPublish, CorpubPublish, ICorPublishProcess, ICorPublishAppDomain, ICorPublishProcessEnum, ICorPublishAppDomainEnum + { + // Methods + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + public virtual extern void Clone([MarshalAs(UnmanagedType.Interface)] out ICorPublishEnum ppEnum); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + public virtual extern void EnumAppDomains([MarshalAs(UnmanagedType.Interface)] out ICorPublishAppDomainEnum ppEnum); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + public virtual extern void EnumProcesses([In, ComAliasName("CorpubProcessLib.COR_PUB_ENUMPROCESS")] COR_PUB_ENUMPROCESS Type, [MarshalAs(UnmanagedType.Interface)] out ICorPublishProcessEnum ppIEnum); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + public virtual extern void GetCount(out uint pcelt); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + public virtual extern void GetDisplayName([In] uint cchName, out uint pcchName, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder szName); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + public virtual extern void GetID(out uint puId); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + public virtual extern void GetName([In] uint cchName, out uint pcchName, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder szName); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + public virtual extern void GetProcess([In] uint pid, [MarshalAs(UnmanagedType.Interface)] out ICorPublishProcess ppProcess); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + public virtual extern void GetProcessID(out uint pid); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + public virtual extern void ICorPublishAppDomainEnum_Clone([MarshalAs(UnmanagedType.Interface)] out ICorPublishEnum ppEnum); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + public virtual extern void ICorPublishAppDomainEnum_GetCount(out uint pcelt); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + public virtual extern void ICorPublishAppDomainEnum_Reset(); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + public virtual extern void ICorPublishAppDomainEnum_Skip([In] uint celt); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + public virtual extern void IsManaged(out int pbManaged); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + public virtual extern void Next([In] uint celt, [MarshalAs(UnmanagedType.Interface)] out ICorPublishAppDomain objects, out uint pceltFetched); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + public virtual extern void Next([In] uint celt, [MarshalAs(UnmanagedType.Interface)] out ICorPublishProcess objects, out uint pceltFetched); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + public virtual extern void Reset(); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + public virtual extern void Skip([In] uint celt); + } +} + +#pragma warning restore 108, 1591 \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/Autogenerated/CorpubPublish.cs b/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/Autogenerated/CorpubPublish.cs new file mode 100644 index 000000000..d71d4953a --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/Autogenerated/CorpubPublish.cs @@ -0,0 +1,23 @@ +// +// +// +// +// $Revision: 3165 $ +// + +#pragma warning disable 108, 1591 + +namespace Debugger.Interop.CorPub +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + [ComImport, CoClass(typeof(CorpubPublishClass)), Guid("9613A0E7-5A68-11D3-8F84-00A0C9B4D50C")] + public interface CorpubPublish : ICorPublish + { + } +} + +#pragma warning restore 108, 1591 + diff --git a/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/Autogenerated/ICorPublish.cs b/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/Autogenerated/ICorPublish.cs new file mode 100644 index 000000000..cd221916a --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/Autogenerated/ICorPublish.cs @@ -0,0 +1,31 @@ +// +// +// +// +// $Revision: 3165 $ +// + +#pragma warning disable 108, 1591 + +namespace Debugger.Interop.CorPub +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + public enum COR_PUB_ENUMPROCESS + { + COR_PUB_MANAGEDONLY = 1 + } + + [ComImport, Guid("9613A0E7-5A68-11D3-8F84-00A0C9B4D50C"), InterfaceType((short) 1)] + public interface ICorPublish + { + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + void EnumProcesses([In, ComAliasName("CorpubProcessLib.COR_PUB_ENUMPROCESS")] COR_PUB_ENUMPROCESS Type, [MarshalAs(UnmanagedType.Interface)] out ICorPublishProcessEnum ppIEnum); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + void GetProcess([In] uint pid, [MarshalAs(UnmanagedType.Interface)] out ICorPublishProcess ppProcess); + } +} + +#pragma warning restore 108, 1591 \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/Autogenerated/ICorPublishAppDomain.cs b/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/Autogenerated/ICorPublishAppDomain.cs new file mode 100644 index 000000000..fc0e2cf95 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/Autogenerated/ICorPublishAppDomain.cs @@ -0,0 +1,27 @@ +// +// +// +// +// $Revision: 3165 $ +// + +#pragma warning disable 108, 1591 + +namespace Debugger.Interop.CorPub +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + using System.Text; + + [ComImport, Guid("D6315C8F-5A6A-11D3-8F84-00A0C9B4D50C"), InterfaceType((short) 1)] + public interface ICorPublishAppDomain + { + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + void GetID(out uint puId); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + void GetName([In] uint cchName, out uint pcchName, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder szName); + } +} + +#pragma warning restore 108, 1591 \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/Autogenerated/ICorPublishAppDomainEnum.cs b/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/Autogenerated/ICorPublishAppDomainEnum.cs new file mode 100644 index 000000000..e0e81a88c --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/Autogenerated/ICorPublishAppDomainEnum.cs @@ -0,0 +1,35 @@ +// +// +// +// +// $Revision: 3165 $ +// + +#pragma warning disable 108, 1591 + +namespace Debugger.Interop.CorPub +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + [ComImport, Guid("9F0C98F5-5A6A-11D3-8F84-00A0C9B4D50C"), InterfaceType((short) 1),] + public interface ICorPublishAppDomainEnum : ICorPublishEnum + { + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + void Skip([In] uint celt); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + void Reset(); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + void Clone([MarshalAs(UnmanagedType.Interface)] out ICorPublishEnum ppEnum); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + void GetCount(out uint pcelt); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + void Next([In] uint celt, [MarshalAs(UnmanagedType.Interface)] out ICorPublishAppDomain objects, out uint pceltFetched); + } +} + +#pragma warning restore 108, 1591 + + + diff --git a/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/Autogenerated/ICorPublishEnum.cs b/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/Autogenerated/ICorPublishEnum.cs new file mode 100644 index 000000000..859dc1000 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/Autogenerated/ICorPublishEnum.cs @@ -0,0 +1,30 @@ +// +// +// +// +// $Revision: 3165 $ +// + +#pragma warning disable 108, 1591 + +namespace Debugger.Interop.CorPub +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + [ComImport, Guid("C0B22967-5A69-11D3-8F84-00A0C9B4D50C"), InterfaceType((short) 1)] + public interface ICorPublishEnum + { + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + void Skip([In] uint celt); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + void Reset(); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + void Clone([MarshalAs(UnmanagedType.Interface)] out ICorPublishEnum ppEnum); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + void GetCount(out uint pcelt); + } +} + +#pragma warning restore 108, 1591 diff --git a/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/Autogenerated/ICorPublishProcess.cs b/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/Autogenerated/ICorPublishProcess.cs new file mode 100644 index 000000000..aaf20cfba --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/Autogenerated/ICorPublishProcess.cs @@ -0,0 +1,31 @@ +// +// +// +// +// $Revision: 3165 $ +// + +#pragma warning disable 108, 1591 + +namespace Debugger.Interop.CorPub +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + using System.Text; + + [ComImport, Guid("18D87AF1-5A6A-11D3-8F84-00A0C9B4D50C"), InterfaceType((short) 1)] + public interface ICorPublishProcess + { + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + void IsManaged(out int pbManaged); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + void EnumAppDomains([MarshalAs(UnmanagedType.Interface)] out ICorPublishAppDomainEnum ppEnum); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + void GetProcessID(out uint pid); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + void GetDisplayName([In] uint cchName, out uint pcchName, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder szName); + } +} + +#pragma warning restore 108, 1591 \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/Autogenerated/ICorPublishProcessEnum.cs b/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/Autogenerated/ICorPublishProcessEnum.cs new file mode 100644 index 000000000..89c3bf473 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/Autogenerated/ICorPublishProcessEnum.cs @@ -0,0 +1,32 @@ +// +// +// +// +// $Revision: 3165 $ +// + +#pragma warning disable 108, 1591 + +namespace Debugger.Interop.CorPub +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + + [ComImport, Guid("A37FBD41-5A69-11D3-8F84-00A0C9B4D50C"), InterfaceType((short) 1)] + public interface ICorPublishProcessEnum : ICorPublishEnum + { + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + void Skip([In] uint celt); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + void Reset(); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + void Clone([MarshalAs(UnmanagedType.Interface)] out ICorPublishEnum ppEnum); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + void GetCount(out uint pcelt); + [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType=MethodCodeType.Runtime)] + void Next([In] uint celt, [MarshalAs(UnmanagedType.Interface)] out ICorPublishProcess objects, out uint pceltFetched); + } +} + +#pragma warning restore 108, 1591 \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/ICorPublish.cs b/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/ICorPublish.cs new file mode 100644 index 000000000..d73cbdf1e --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/ICorPublish.cs @@ -0,0 +1,34 @@ +// +// +// +// +// $Revision: 3165 $ +// + +#pragma warning disable 1591 + +namespace Debugger.Core.Wrappers.CorPub +{ + using System; + using System.Runtime.InteropServices; + using Debugger.Wrappers; + + public partial class ICorPublish + { + private Debugger.Interop.CorPub.CorpubPublishClass corpubPublishClass; + + public ICorPublish() + { + corpubPublishClass = new Debugger.Interop.CorPub.CorpubPublishClass(); + } + + public ICorPublishProcess GetProcess(int id) + { + Debugger.Interop.CorPub.ICorPublishProcess process; + this.corpubPublishClass.GetProcess((uint)id, out process); + return ICorPublishProcess.Wrap(process); + } + } +} + +#pragma warning restore 1591 diff --git a/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/ICorPublishProcess.cs b/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/ICorPublishProcess.cs new file mode 100644 index 000000000..ec20015f6 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/CorPub/ICorPublishProcess.cs @@ -0,0 +1,68 @@ +// +// +// +// +// $Revision: 3165 $ +// + +#pragma warning disable 1591 + +namespace Debugger.Core.Wrappers.CorPub +{ + using System; + using System.Runtime.InteropServices; + using System.Text; + using Debugger.Wrappers; + + public partial class ICorPublishProcess + { + private Debugger.Interop.CorPub.ICorPublishProcess wrappedObject; + + internal Debugger.Interop.CorPub.ICorPublishProcess WrappedObject + { + get + { + return this.wrappedObject; + } + } + + public ICorPublishProcess(Debugger.Interop.CorPub.ICorPublishProcess wrappedObject) + { + this.wrappedObject = wrappedObject; + ResourceManager.TrackCOMObject(wrappedObject, typeof(ICorPublishProcess)); + } + + public static ICorPublishProcess Wrap(Debugger.Interop.CorPub.ICorPublishProcess objectToWrap) + { + if ((objectToWrap != null)) + { + return new ICorPublishProcess(objectToWrap); + } else + { + return null; + } + } + + public int ProcessId + { + get + { + uint id; + wrappedObject.GetProcessID(out id); + return (int)id; + } + } + + public bool IsManaged + { + get + { + int managed; + wrappedObject.IsManaged(out managed); + return managed != 0; + } + } + } +} + +#pragma warning restore 1591 diff --git a/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/NativeMethods.cs b/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/NativeMethods.cs new file mode 100644 index 000000000..68df8641a --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/NativeMethods.cs @@ -0,0 +1,29 @@ +// +// +// +// +// $Revision: 2185 $ +// + +#pragma warning disable 1591 + +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace Debugger.Interop +{ + public static class NativeMethods + { + [DllImport("kernel32.dll")] + public static extern bool CloseHandle(IntPtr handle); + + [DllImport("mscoree.dll", CharSet=CharSet.Unicode)] + public static extern int GetCORVersion([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder szName, Int32 cchBuffer, out Int32 dwLength); + + [DllImport("mscoree.dll", CharSet=CharSet.Unicode)] + public static extern int GetRequestedRuntimeVersion(string exeFilename, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pVersion, Int32 cchBuffer, out Int32 dwLength); + } +} + +#pragma warning restore 1591 diff --git a/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/ResourceManager.cs b/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/ResourceManager.cs new file mode 100644 index 000000000..d2e496f06 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/ResourceManager.cs @@ -0,0 +1,114 @@ +// +// +// +// +// $Revision: 3132 $ +// + +#pragma warning disable 1591 + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +using Debugger.Interop; + +namespace Debugger.Wrappers +{ + class TrackedObjectMetaData + { + public Type ObjectType; + public int RefCount; + + public TrackedObjectMetaData(Type objectType, int refCount) + { + this.ObjectType = objectType; + this.RefCount = refCount; + } + } + + public static class ResourceManager + { + static MTA2STA mta2sta = new MTA2STA(); + static bool trace = false; + static Dictionary trackedCOMObjects = new Dictionary(); + + public static bool TraceMessagesEnabled { + get { + return trace; + } + set { + trace = value; + } + } + + public static void TrackCOMObject(object comObject, Type type) + { + if (comObject == null || !Marshal.IsComObject(comObject)) { + if (trace) Trace("Will not be tracked: {0}", type.Name); + } else { + TrackedObjectMetaData metaData; + if (trackedCOMObjects.TryGetValue(comObject, out metaData)) { + metaData.RefCount += 1; + } else { + metaData = new TrackedObjectMetaData(type,1); + trackedCOMObjects.Add(comObject, metaData); + } + if (trace) Trace("AddRef {0,2}: {1}", metaData.RefCount, type.Name); + } + } + + public static void ReleaseCOMObject(object comObject, Type type) + { + // Ensure that the release is done synchronosly + try { + mta2sta.AsyncCall(delegate { + ReleaseCOMObjectInternal(comObject, type); + }); + } catch (InvalidOperationException) { + // This might happen when the application is shuting down + } + } + + static void ReleaseCOMObjectInternal(object comObject, Type type) + { + TrackedObjectMetaData metaData; + if (comObject != null && trackedCOMObjects.TryGetValue(comObject, out metaData)) { + metaData.RefCount -= 1; + if (metaData.RefCount == 0) { + Marshal.FinalReleaseComObject(comObject); + trackedCOMObjects.Remove(comObject); + } + if (trace) Trace("Release {0,2}: {1}", metaData.RefCount, type.Name); + } else { + if (trace) Trace("Was not tracked: {0}", type.Name); + } + } + + public static void ReleaseAllTrackedCOMObjects() + { + if (trace) Trace("Releasing {0} tracked COM objects... ", trackedCOMObjects.Count); + while(trackedCOMObjects.Count > 0) { + foreach (KeyValuePair pair in trackedCOMObjects) { + Marshal.FinalReleaseComObject(pair.Key); + if (trace) Trace(" * Releasing {0} ({1} references)", pair.Value.ObjectType.Name, pair.Value.RefCount); + trackedCOMObjects.Remove(pair.Key); + break; + } + } + if (trace) Trace(" * Done"); + } + + public static event EventHandler TraceMessage; + + static void Trace(string msg, params object[] pars) + { + if (TraceMessage != null && trace) { + string message = String.Format("COM({0,-3}): {1}", trackedCOMObjects.Count, String.Format(msg, pars)); + TraceMessage(null, new MessageEventArgs(null, message)); + } + } + } +} + +#pragma warning restore 1591 diff --git a/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/Util.cs b/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/Util.cs new file mode 100644 index 000000000..5b0b2814e --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/SharpDevelop/Wrappers/Util.cs @@ -0,0 +1,54 @@ +// +// +// +// +// $Revision: 2284 $ +// + +#pragma warning disable 1591 + +using System; +using System.Runtime.InteropServices; + +namespace Debugger.Wrappers +{ + public delegate void UnmanagedStringGetter(uint pStringLenght, out uint stringLenght, System.IntPtr pString); + + public static class Util + { + public static string GetString(UnmanagedStringGetter getter) + { + return GetString(getter, 64, true); + } + + public static string GetString(UnmanagedStringGetter getter, uint defaultLenght, bool trim) + { + string managedString; + IntPtr unmanagedString; + uint exactLenght; + + // First attempt + unmanagedString = Marshal.AllocHGlobal((int)defaultLenght * 2 + 2); // + 2 for terminating zero + getter(defaultLenght, out exactLenght, defaultLenght > 0 ? unmanagedString : IntPtr.Zero); + + if(exactLenght > defaultLenght) { + // Second attempt + Marshal.FreeHGlobal(unmanagedString); + unmanagedString = Marshal.AllocHGlobal((int)exactLenght * 2 + 2); // + 2 for terminating zero + getter(exactLenght, out exactLenght, unmanagedString); + } + + // Return managed string and free unmanaged memory + managedString = Marshal.PtrToStringUni(unmanagedString, (int)exactLenght); + //Console.WriteLine("Marshaled string from COM: \"" + managedString + "\" lenght=" + managedString.Length + " arrayLenght=" + exactLenght); + // The API might or might not include terminating null at the end + if (trim) { + managedString = managedString.TrimEnd('\0'); + } + Marshal.FreeHGlobal(unmanagedString); + return managedString; + } + } +} + +#pragma warning restore 1591 diff --git a/branches/ph-plugins/ProcessHacker/Structs/FieldType.cs b/branches/ph-plugins/ProcessHacker/Structs/FieldType.cs new file mode 100644 index 000000000..d32b1b304 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Structs/FieldType.cs @@ -0,0 +1,52 @@ +/* + * Process Hacker - + * struct field types + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Structs +{ + public enum FieldType : uint + { + Bool8 = 0x1, + Bool32, + CharASCII, + CharUTF16, + Int8, + Int16, + Int32, + Int64, + UInt8, + UInt16, + UInt32, + UInt64, + Single, + Double, + StringASCII, + StringUTF16, + Struct, + PVoid, + Pointer = 0x4000000, + Array = 0x8000000 + } +} diff --git a/branches/ph-plugins/ProcessHacker/Structs/FieldValue.cs b/branches/ph-plugins/ProcessHacker/Structs/FieldValue.cs new file mode 100644 index 000000000..0310a4558 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Structs/FieldValue.cs @@ -0,0 +1,37 @@ +/* + * Process Hacker - + * struct field value + * + * Copyright (C) 2008 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 . + */ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Structs +{ + public struct FieldValue + { + public string Name; + public FieldType FieldType; + public object Value; + public string StructName; + public int PointerValue; + } +} diff --git a/branches/ph-plugins/ProcessHacker/Structs/IStructIOProvider.cs b/branches/ph-plugins/ProcessHacker/Structs/IStructIOProvider.cs new file mode 100644 index 000000000..23349fb60 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Structs/IStructIOProvider.cs @@ -0,0 +1,34 @@ +/* + * Process Hacker - + * basic I/O interface + * + * Copyright (C) 2008 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 . + */ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Structs +{ + public interface IStructIOProvider + { + byte[] ReadBytes(IntPtr offset, int length); + void WriteBytes(IntPtr offset, byte[] bytes); + } +} diff --git a/branches/ph-plugins/ProcessHacker/Structs/ProcessMemoryIO.cs b/branches/ph-plugins/ProcessHacker/Structs/ProcessMemoryIO.cs new file mode 100644 index 000000000..8145910ad --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Structs/ProcessMemoryIO.cs @@ -0,0 +1,54 @@ +/* + * Process Hacker - + * process memory I/O interface + * + * Copyright (C) 2008 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 . + */ + +using ProcessHacker.Native.Objects; +using System; + +namespace ProcessHacker.Structs +{ + public class ProcessMemoryIO : IStructIOProvider + { + private ProcessHandle _phandleR; + private ProcessHandle _phandleW; + + public ProcessMemoryIO(int pid) + { + try { _phandleR = new ProcessHandle(pid, Program.MinProcessReadMemoryRights); } + catch { } + try + { + _phandleW = new ProcessHandle(pid, Program.MinProcessWriteMemoryRights); + } + catch { } + } + + public byte[] ReadBytes(IntPtr offset, int length) + { + return _phandleR.ReadMemory(offset, length); + } + + public void WriteBytes(IntPtr offset, byte[] bytes) + { + _phandleW.WriteMemory(offset, bytes); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Structs/StructDef.cs b/branches/ph-plugins/ProcessHacker/Structs/StructDef.cs new file mode 100644 index 000000000..617a79593 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Structs/StructDef.cs @@ -0,0 +1,346 @@ +/* + * Process Hacker - + * struct definition class and reader + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Common; +using ProcessHacker.Native; + +namespace ProcessHacker.Structs +{ + public class StructDef + { + private List _fields = new List(); + private Dictionary _fieldsByName = new Dictionary(); + + public IStructIOProvider IOProvider { get; set; } + + public int Size + { + get + { + int size = 0; + + foreach (StructField field in _fields) + size += field.Size; + + return size; + } + } + + public IntPtr Offset { get; set; } + + public Dictionary Structs { get; set; } + + public StructField AddField(StructField field) + { + _fieldsByName.Add(field.Name, field); + _fields.Add(field); + + return field; + } + + public bool ContainsField(string name) + { + return _fieldsByName.ContainsKey(name); + } + + public StructField GetField(int index) + { + return _fields[index]; + } + + public StructField GetField(string name) + { + return _fieldsByName[name]; + } + + public void RemoveField(int index) + { + _fieldsByName.Remove(_fields[index].Name); + _fields.RemoveAt(index); + } + + public void RemoveField(string name) + { + _fields.Remove(_fieldsByName[name]); + _fieldsByName.Remove(name); + } + + public void RemoveField(StructField field) + { + _fieldsByName.Remove(field.Name); + _fields.Remove(field); + } + + public FieldValue[] Read() + { + FieldValue[] values; + + this.Read(out values); + + return values; + } + + private int Read(StructField field, IntPtr offset, out FieldValue valueOut) + { + if (!field.IsArray) + return this.ReadOnce(field, offset, out valueOut); + + // read array + FieldValue value = new FieldValue() { FieldType = field.RawType, Name = field.Name }; + int readSize = 0; + List valueArray = new List(); + + for (int i = 0; i < field.VarArrayLength; i++) + { + FieldValue elementValue; + + readSize += this.ReadOnce(field, offset.Increment(readSize), out elementValue); + elementValue.Name = "[" + i.ToString() + "]"; + + valueArray.Add(elementValue); + } + + value.Value = valueArray.ToArray(); + value.StructName = field.StructName; + valueOut = value; + + return readSize; + } + + private unsafe int ReadOnce(StructField field, IntPtr offset, out FieldValue valueOut) + { + FieldValue value = new FieldValue() { FieldType = field.Type, Name = field.Name }; + int readSize = 0; + + switch (field.Type) + { + case FieldType.Bool32: + value.Value = Utils.ToInt32(IOProvider.ReadBytes(offset, 4), + Utils.Endianness.Little) != 0; + readSize = 4; + break; + case FieldType.Bool8: + value.Value = IOProvider.ReadBytes(offset, 1)[0] != 0; + readSize = 1; + break; + case FieldType.CharASCII: + value.Value = (char)IOProvider.ReadBytes(offset, 1)[0]; + readSize = 1; + break; + case FieldType.CharUTF16: + value.Value = UnicodeEncoding.Unicode.GetString(IOProvider.ReadBytes(offset, 2))[0]; + readSize = 2; + break; + case FieldType.Double: + { + long data = Utils.ToInt64( + IOProvider.ReadBytes(offset, 8), Utils.Endianness.Little); + + value.Value = *(double*)&data; + readSize = 8; + } + break; + case FieldType.Int16: + value.Value = (short)Utils.ToUInt16( + IOProvider.ReadBytes(offset, 2), Utils.Endianness.Little); + readSize = 2; + break; + case FieldType.Int32: + value.Value = Utils.ToInt32( + IOProvider.ReadBytes(offset, 4), Utils.Endianness.Little); + readSize = 4; + break; + case FieldType.Int64: + value.Value = Utils.ToInt64( + IOProvider.ReadBytes(offset, 8), Utils.Endianness.Little); + readSize = 8; + break; + case FieldType.Int8: + value.Value = (sbyte)IOProvider.ReadBytes(offset, 1)[0]; + readSize = 1; + break; + case FieldType.PVoid: + value.Value = IOProvider.ReadBytes(offset, IntPtr.Size).ToIntPtr(); + readSize = IntPtr.Size; + break; + case FieldType.Single: + { + int data = Utils.ToInt32( + IOProvider.ReadBytes(offset, 4), Utils.Endianness.Little); + + value.Value = *(float*)&data; + readSize = 4; + } + break; + case FieldType.StringASCII: + { + StringBuilder str = new StringBuilder(); + + if (field.VarLength == -1) + { + int i; + + for (i = 0; ; i++) + { + byte b = IOProvider.ReadBytes(offset.Increment(i), 1)[0]; + + if (b == 0) + break; + + str.Append((char)b); + } + + readSize = i; + } + else + { + str.Append(ASCIIEncoding.ASCII.GetString( + IOProvider.ReadBytes(offset, field.VarLength))); + readSize = field.VarLength; + } + + value.Value = str.ToString(); + } + + break; + case FieldType.StringUTF16: + { + StringBuilder str = new StringBuilder(); + + if (field.VarLength == -1) + { + int i; + + for (i = 0; ; i += 2) + { + byte[] b = IOProvider.ReadBytes(offset.Increment(i), 2); + + if (Utils.IsEmpty(b)) + break; + + str.Append(UnicodeEncoding.Unicode.GetString(b)); + } + + readSize = i; + } + else + { + str.Append(UnicodeEncoding.Unicode.GetString( + IOProvider.ReadBytes(offset, field.VarLength * 2))); // each char is 2 bytes + readSize = field.VarLength; + } + + value.Value = str.ToString(); + } + + break; + case FieldType.Struct: + { + FieldValue[] valuesOut; + StructDef struc = Structs[field.StructName]; + + struc.IOProvider = this.IOProvider; + struc.Offset = offset; + struc.Structs = this.Structs; + readSize = struc.Read(out valuesOut); + value.Value = valuesOut; + value.StructName = field.StructName; + } + + break; + case FieldType.UInt16: + value.Value = Utils.ToUInt16( + IOProvider.ReadBytes(offset, 2), Utils.Endianness.Little); + readSize = 2; + break; + case FieldType.UInt32: + value.Value = Utils.ToUInt32( + IOProvider.ReadBytes(offset, 4), Utils.Endianness.Little); + readSize = 4; + break; + case FieldType.UInt64: + value.Value = (ulong)Utils.ToInt64( + IOProvider.ReadBytes(offset, 8), Utils.Endianness.Little); + readSize = 8; + break; + case FieldType.UInt8: + value.Value = IOProvider.ReadBytes(offset, 1)[0]; + readSize = 1; + break; + default: + readSize = 0; + break; + } + + valueOut = value; + + return readSize; + } + + public int Read(out FieldValue[] values) + { + List list = new List(); + int localOffset = 0; + + foreach (StructField field in _fields) + { + FieldValue value; + + // resolve pointer + if (field.IsPointer) + { + int pointingTo = Utils.ToInt32(IOProvider.ReadBytes(Offset.Increment(localOffset), 4), Utils.Endianness.Little); + + localOffset += 4; + + if (pointingTo == 0) + value = new FieldValue() { Name = field.Name, FieldType = field.RawType, Value = null }; + else + Read(field, new IntPtr(pointingTo), out value); + + value.PointerValue = pointingTo; + } + else + { + localOffset += Read(field, Offset.Increment(localOffset), out value); + } + + if (field.SetsVarOn != null) + { + _fieldsByName[field.SetsVarOn].VarLength = + field.SetsVarOnAdd + (int)(int.Parse(value.Value.ToString()) * (decimal)field.SetsVarOnMultiply); + _fieldsByName[field.SetsVarOn].VarArrayLength = + field.SetsVarOnAdd + (int)(int.Parse(value.Value.ToString()) * (decimal)field.SetsVarOnMultiply); + } + + list.Add(value); + } + + values = list.ToArray(); + + return localOffset; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Structs/StructField.cs b/branches/ph-plugins/ProcessHacker/Structs/StructField.cs new file mode 100644 index 000000000..3aa3f3bfa --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Structs/StructField.cs @@ -0,0 +1,159 @@ +/* + * Process Hacker - + * struct field data + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.Structs +{ + public class StructField + { + private FieldType _type; + + public StructField(string name, FieldType type) + { + VarLength = -1; + VarArrayLength = 0; + Name = name; + _type = type; + } + + public bool IsArray + { + get { return (_type & FieldType.Array) != 0; } + } + + public bool IsPointer + { + get { return (_type & FieldType.Pointer) != 0; } + } + + /// + /// Gets the size of the field, in bytes. + /// + public int Size + { + get + { + if (this.IsPointer) + { + return 4; // 32-bit only + } + else + { + int size; + + switch (_type) + { + case FieldType.Bool32: + size = 4; + break; + case FieldType.Bool8: + size = 1; + break; + case FieldType.CharASCII: + size = 1; + break; + case FieldType.CharUTF16: + size = 2; // UCS-2 + break; + case FieldType.Double: + size = 8; + break; + case FieldType.Int16: + size = 2; + break; + case FieldType.Int32: + size = 4; + break; + case FieldType.Int64: + size = 8; + break; + case FieldType.Int8: + size = 1; + break; + case FieldType.PVoid: + size = 4; + break; + case FieldType.Single: + size = 4; + break; + case FieldType.StringASCII: + size = VarLength; + break; + case FieldType.StringUTF16: + size = VarLength * 2; + break; + case FieldType.Struct: + size = 0; + break; + case FieldType.UInt16: + size = 2; + break; + case FieldType.UInt32: + size = 4; + break; + case FieldType.UInt64: + size = 8; + break; + case FieldType.UInt8: + size = 1; + break; + default: + size = 0; + break; + } + + if (this.IsArray) + return size * VarArrayLength; + else + return size; + } + } + } + + public string Name { get; set; } + + internal int VarArrayLength { get; set; } + + internal int VarLength { get; set; } + + public string SetsVarOn { get; set; } + + public int SetsVarOnAdd { get; set; } + + public float SetsVarOnMultiply { get; set; } + + public string StructName { get; set; } + + public FieldType Type + { + get { return _type & (~FieldType.Pointer) & (~FieldType.Array); } + } + + public FieldType RawType + { + get { return _type; } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Structs/StructParser.cs b/branches/ph-plugins/ProcessHacker/Structs/StructParser.cs new file mode 100644 index 000000000..cf57e6d03 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Structs/StructParser.cs @@ -0,0 +1,615 @@ +/* + * Process Hacker - + * struct definition file parser + * + * Copyright (C) 2008 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 . + */ + +using System; +using System.Collections.Generic; +using System.Text; +using ProcessHacker.Common; + +namespace ProcessHacker.Structs +{ + public class ParserException : Exception + { + public ParserException(string fileName, int line, string message) : + base((new System.IO.FileInfo(fileName)).Name + ": " + line.ToString() + ": " + message) { } + } + + public class StructParser + { + private Dictionary _structs; + + private string _fileName = ""; + private int _lineNumber = 1; + private Dictionary _typeDefs = new Dictionary(); + private bool _eatResult = false; + + public Dictionary Structs + { + get { return _structs; } + } + + public StructParser(Dictionary structs) + { + _structs = structs; + + foreach (string s in Enum.GetNames(typeof(FieldType))) + if (s != "Pointer") + _typeDefs.Add(s.ToLower(), (FieldType)Enum.Parse(typeof(FieldType), s)); + } + + private FieldType GetType(string typeName) + { + if (_typeDefs.ContainsKey(typeName)) + return _typeDefs[typeName]; + else + throw new ParserException(_fileName, _lineNumber, "Unknown identifier '" + typeName + "' (type name)"); + } + + private bool IsTypePointer(FieldType type) + { + return (type & FieldType.Pointer) != 0; + } + + public void Parse(string fileName) + { + List defs = new List(); + int i = 0; + string text = System.IO.File.ReadAllText(fileName); + + _lineNumber = 1; + _fileName = fileName; + + while (true) + { + if (EatWhitespace(text, ref i)) break; + + string modeName = EatId(text, ref i); + + if (modeName == "") + throw new ParserException(_fileName, _lineNumber, "Expected keyword"); + + if (modeName == "typedef") + { + this.ParseTypeDef(text, ref i); + } + else if (modeName == "struct") + { + this.ParseStructDef(text, ref i); + } + else if (modeName == "include") + { + _eatResult = EatWhitespace(text, ref i); + string includeFile = EatQuotedString(text, ref i); + + if (_eatResult || includeFile == "") + throw new ParserException(_fileName, _lineNumber, "String expected (file name)"); + + _eatResult = EatWhitespace(text, ref i); + string endSemicolon = EatSymbol(text, ref i); + + if (_eatResult || endSemicolon != ";") + throw new ParserException(_fileName, _lineNumber, "Expected ';'"); + + System.IO.FileInfo info = new System.IO.FileInfo(_fileName); + + // if the filename contains ':', use the absolute path. otherwise, append it to the + // current filename's directory + string oldFileName = _fileName; + int oldLine = _lineNumber; + + try + { + if (includeFile.Contains(":")) + this.Parse(includeFile); + else + this.Parse(info.DirectoryName + "\\" + includeFile); + } + catch (System.IO.FileNotFoundException) + { + throw new ParserException(_fileName, _lineNumber, "Could not find the file '" + includeFile + "'"); + } + + _fileName = oldFileName; + _lineNumber = oldLine; + } + else + { + throw new ParserException(_fileName, _lineNumber, "Expected keyword"); + } + } + } + + private void ParseTypeDef(string text, ref int i) + { + _eatResult = EatWhitespace(text, ref i); + string existingType = EatId(text, ref i); + + if (_eatResult || existingType == "") + throw new ParserException(_fileName, _lineNumber, "Expected identifier (type name)"); + + if (!_typeDefs.ContainsKey(existingType)) + throw new ParserException(_fileName, _lineNumber, "Unknown identifier '" + existingType + "' (type name)"); + + // check for asterisk (pointer) + _eatResult = EatWhitespace(text, ref i); + string asterisk = EatSymbol(text, ref i); + + if (asterisk != "*" && asterisk.Length > 0) + throw new ParserException(_fileName, _lineNumber, "Unexpected '" + asterisk + "'"); + + _eatResult = EatWhitespace(text, ref i); + string newType = EatId(text, ref i); + + if (_eatResult || existingType == "") + throw new ParserException(_fileName, _lineNumber, "Expected identifier (new type name)"); + + if (_typeDefs.ContainsKey(newType)) + throw new ParserException(_fileName, _lineNumber, "Type name '" + newType + "' already used"); + + if (this.IsTypePointer(this.GetType(existingType)) && asterisk == "*") + throw new ParserException(_fileName, _lineNumber, "Invalid '*'; type '" + existingType + "' is already a pointer"); + + _typeDefs.Add(newType, this.GetType(existingType) | (asterisk == "*" ? FieldType.Pointer : 0)); + + _eatResult = EatWhitespace(text, ref i); + string endSemicolon = EatSymbol(text, ref i); + + if (_eatResult || endSemicolon != ";") + throw new ParserException(_fileName, _lineNumber, "Expected ';'"); + } + + private void ParseStructDef(string text, ref int i) + { + StructDef def = new StructDef(); + + _eatResult = EatWhitespace(text, ref i); + string structName = EatId(text, ref i); + + if (_eatResult || structName == "") + throw new ParserException(_fileName, _lineNumber, "Expected identifier (struct name)"); + + if (_structs.ContainsKey(structName)) + throw new ParserException(_fileName, _lineNumber, "Struct name '" + structName + "' already used"); + + // add it first so that structs can be self-referential + _structs.Add(structName, null); + + // { + _eatResult = EatWhitespace(text, ref i); + string openingBrace = EatSymbol(text, ref i); + + if (_eatResult || openingBrace != "{") + throw new ParserException(_fileName, _lineNumber, "Expected '{'"); + + while (true) + { + // } + _eatResult = EatWhitespace(text, ref i); + string endBrace = EatSymbol(text, ref i); + + if (_eatResult) + throw new ParserException(_fileName, _lineNumber, "Expected type name or '}'"); + if (endBrace == "}") + break; + if (endBrace.Length > 0) + throw new ParserException(_fileName, _lineNumber, "Unexpected '" + endBrace + "'"); + + // TYPE + _eatResult = EatWhitespace(text, ref i); + string typeName = EatId(text, ref i); + + if (_eatResult || typeName == "") + throw new ParserException(_fileName, _lineNumber, "Expected type name"); + + FieldType type; + + if (_typeDefs.ContainsKey(typeName)) + { + type = this.GetType(typeName); + } + else + { + type = FieldType.Struct; + + if (!_structs.ContainsKey(typeName)) + throw new ParserException(_fileName, _lineNumber, "Unknown identifier '" + typeName + "' (type or struct name)"); + } + + // type, without the pointer or array flag + FieldType justType = type; + + // TYPE* + // optional asterisk (pointer) + _eatResult = EatWhitespace(text, ref i); + + if (EatSymbol(text, ref i) == "*") + { + if (this.IsTypePointer(type)) + throw new ParserException(_fileName, _lineNumber, "Invalid '*'; type '" + typeName + "' is already a pointer"); + + type |= FieldType.Pointer; + } + + // TYPE* FIELDNAME + _eatResult = EatWhitespace(text, ref i); + string fieldName = EatId(text, ref i); + + if (_eatResult || fieldName == "") + throw new ParserException(_fileName, _lineNumber, "Expected identifier (struct field name)"); + + if (def.ContainsField(fieldName)) + throw new ParserException(_fileName, _lineNumber, "Field name '" + fieldName + "' already used"); + + _eatResult = EatWhitespace(text, ref i); + string leftSqBracket = EatSymbol(text, ref i); + int varLength = 0; + + if (leftSqBracket == "[") + { + _eatResult = EatWhitespace(text, ref i); + string fieldRefName = EatId(text, ref i); + string fieldSizeSpec = EatNumber(text, ref i); + + if (fieldRefName != "") + { + if (!def.ContainsField(fieldRefName)) + throw new ParserException(_fileName, _lineNumber, "Unknown identifier '" + fieldRefName + "' (field name)"); + + def.GetField(fieldRefName).SetsVarOn = fieldName; + + // const add/multiply + int iSave = i; + + _eatResult = EatWhitespace(text, ref i); + string plusOrMulOrDivSign = EatSymbol(text, ref i); + + if (plusOrMulOrDivSign == "+") + { + def.GetField(fieldRefName).SetsVarOnAdd = EatParseInt(text, ref i); + } + else if (plusOrMulOrDivSign == "*") + { + def.GetField(fieldRefName).SetsVarOnMultiply = EatParseFloat(text, ref i); + + int iSave2 = i; + _eatResult = EatWhitespace(text, ref i); + string plusSign = EatSymbol(text, ref i); + + if (plusSign == "+") + def.GetField(fieldRefName).SetsVarOnAdd = EatParseInt(text, ref i); + else if (plusSign == "-") + def.GetField(fieldRefName).SetsVarOnAdd = -EatParseInt(text, ref i); + else + i = iSave2; + } + else if (plusOrMulOrDivSign == "/") + { + // here we just set SetsVarOnMultiply to 1 / value + def.GetField(fieldRefName).SetsVarOnMultiply = 1 / EatParseFloat(text, ref i); + + int iSave2 = i; + _eatResult = EatWhitespace(text, ref i); + string plusSign = EatSymbol(text, ref i); + + if (plusSign == "+") + def.GetField(fieldRefName).SetsVarOnAdd = EatParseInt(text, ref i); + else if (plusSign == "-") + def.GetField(fieldRefName).SetsVarOnAdd = -EatParseInt(text, ref i); + else + i = iSave2; + } + else + { + // that didn't work; restore the index + i = iSave; + } + } + else if (fieldSizeSpec != "") + { + try + { + varLength = (int)BaseConverter.ToNumberParse(fieldSizeSpec); + varLength = (int)BaseConverter.ToNumberParse(fieldSizeSpec); + } + catch + { + throw new ParserException(_fileName, _lineNumber, "Could not parse number '" + fieldSizeSpec + "'"); + } + } + else + { + throw new ParserException(_fileName, _lineNumber, "Number or identifier expected (size specifier)"); + } + + // if it's not a string, it's an array + if (justType != FieldType.StringASCII && justType != FieldType.StringUTF16) + type |= FieldType.Array; + + _eatResult = EatWhitespace(text, ref i); + string rightSqBracket = EatSymbol(text, ref i); + + if (_eatResult || rightSqBracket != "]") + throw new ParserException(_fileName, _lineNumber, "Expected ']'"); + + // fix up the semicolon + _eatResult = EatWhitespace(text, ref i); + leftSqBracket = EatSymbol(text, ref i); + } + + // TYPE* FIELDNAME; + string endSemicolon = leftSqBracket; + + if (_eatResult || endSemicolon != ";") + throw new ParserException(_fileName, _lineNumber, "Expected ';'"); + + StructField field = new StructField(fieldName, type); + + if (field.Type == FieldType.Struct) + field.StructName = typeName; + + field.VarArrayLength = varLength; + field.VarLength = varLength; + + def.AddField(field); + } + + _structs[structName] = def; + } + + private float EatParseFloat(string text, ref int i) + { + _eatResult = EatWhitespace(text, ref i); + string number = EatNumber(text, ref i); + + if (_eatResult || number == "") + throw new ParserException(_fileName, _lineNumber, "Expected floating-point number"); + + try + { + return float.Parse(number); + } + catch + { + throw new ParserException(_fileName, _lineNumber, "Could not parse number '" + number + "'"); + } + } + + private int EatParseInt(string text, ref int i) + { + _eatResult = EatWhitespace(text, ref i); + string number = EatNumber(text, ref i); + + if (_eatResult || number == "") + throw new ParserException(_fileName, _lineNumber, "Expected integer"); + + try + { + return (int)BaseConverter.ToNumberParse(number); + } + catch + { + throw new ParserException(_fileName, _lineNumber, "Could not parse number '" + number + "'"); + } + } + + // my idea of a tokenizer follows... + private bool EatWhitespace(string text, ref int i) // and comments + { + bool ranOut = true; + bool preComment = false; // '/' + bool inComment = false; // '*' + bool prePostComment = false; // '*' + + while (i < text.Length) + { + if (inComment && text[i] == '*') + { + prePostComment = true; + i++; + continue; + } + else if (prePostComment && text[i] == '/') + { + prePostComment = false; + inComment = false; + i++; + continue; + } + else if (!inComment && text[i] == '/') + { + preComment = true; + i++; + continue; + } + else if (preComment) + { + if (text[i] == '*') + { + preComment = false; + inComment = true; + i++; + continue; + } + else + { + // it's a mistake, revert! + i -= 1; + break; + } + } + else + { + preComment = false; + prePostComment = false; + } + + if (text[i] == '\n') + _lineNumber++; + + if (!(text[i] == '\r' || text[i] == '\n' || text[i] == ' ' || text[i] == '\t') && !inComment) + { + ranOut = false; + break; + } + + i++; + } + + return ranOut; + } + + private string EatQuotedString(string text, ref int i) + { + StringBuilder sb = new StringBuilder(); + bool inEscape = false; + + if (text[i] == '"') + { + i++; + } + else + return ""; + + while (i < text.Length) + { + if (text[i] == '\\') + { + inEscape = true; + i++; + continue; + } + else if (inEscape) + { + if (text[i] == '\\') + sb.Append('\\'); + else if (text[i] == '"') + sb.Append('"'); + else if (text[i] == '\'') + sb.Append('\''); + else if (text[i] == 'r') + sb.Append('\r'); + else if (text[i] == 'n') + sb.Append('\n'); + else if (text[i] == 't') + sb.Append('\t'); + else + throw new ParserException(_fileName, _lineNumber, "Unrecognized escape sequence '\\" + text[i] + "'"); + + i++; + inEscape = false; + continue; + } + else if (text[i] == '"') + { + i++; + break; + } + + sb.Append(text[i]); + i++; + } + + return sb.ToString(); + } + + private string EatId(string text, ref int i) + { + StringBuilder sb = new StringBuilder(); + + while (i < text.Length) + { + // identifiers can't start with a number- + if (sb.Length == 0) + { + if (!(char.IsLetter(text[i]) || text[i] == '_')) + break; + } + else + { + if (!(char.IsLetterOrDigit(text[i]) || text[i] == '_')) + break; + } + + sb.Append(text[i]); + i++; + } + + return sb.ToString(); + } + + private string EatNumber(string text, ref int i) + { + StringBuilder sb = new StringBuilder(); + + while (i < text.Length) + { + // allow hex numbers and floating-point numbers + if (sb.Length == 1 && sb[0] == '0') + { + if (!char.IsDigit(text[i]) && char.ToLower(text[i]) != 'x' && text[i] != '.') + break; + } + else if (sb.Length >= 2 && sb[0] == '0' && char.ToLower(sb[1]) == 'x') + { + if (!(char.IsDigit(text[i]) || + char.ToLower(text[i]) == 'a' || + char.ToLower(text[i]) == 'b' || + char.ToLower(text[i]) == 'c' || + char.ToLower(text[i]) == 'd' || + char.ToLower(text[i]) == 'e' || + char.ToLower(text[i]) == 'f')) + break; + } + else + { + if (!char.IsDigit(text[i])) + break; + } + + sb.Append(text[i]); + i++; + } + + return sb.ToString(); + } + + private string EatSymbol(string text, ref int i) + { + StringBuilder sb = new StringBuilder(); + + while (i < text.Length && sb.Length < 1) // we need a proper parser to solve this + { + char c = text[i]; + + if (c < ' ' || c > '~') // check if its an ASCII character + break; + if (char.IsLetterOrDigit(c) || c == '_') // check if its eligible to be an identifier + break; + + sb.Append(c); + i++; + } + + return sb.ToString(); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/Symbols/SymbolProviderExtensions.cs b/branches/ph-plugins/ProcessHacker/Symbols/SymbolProviderExtensions.cs new file mode 100644 index 000000000..cdfe6604c --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/Symbols/SymbolProviderExtensions.cs @@ -0,0 +1,171 @@ +/* + * Process Hacker - + * symbols extension functions + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.IO; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Components; +using ProcessHacker.Native.Objects; + +namespace ProcessHacker.Native.Symbols +{ + public static class SymbolProviderExtensions + { + public static void ShowWarning(IWin32Window window, bool force) + { + if (Properties.Settings.Default.DbgHelpWarningShown && !force) + return; + + try + { + var modules = ProcessHandle.GetCurrent().GetModules(); + + foreach (var module in modules) + { + if (module.FileName.ToLowerInvariant().EndsWith("dbghelp.dll")) + { + if (!File.Exists(Path.GetDirectoryName(module.FileName) + "\\symsrv.dll")) + { + if (!force) + Properties.Settings.Default.DbgHelpWarningShown = true; + + if (OSVersion.HasTaskDialogs) + { + TaskDialog td = new TaskDialog(); + bool verificationChecked; + + td.CommonButtons = TaskDialogCommonButtons.Ok; + td.WindowTitle = "Process Hacker"; + td.MainIcon = TaskDialogIcon.Warning; + td.MainInstruction = "Microsoft Symbol Server not supported"; + td.Content = "The Microsoft Symbol Server is not supported by your version of dbghelp.dll " + + "or could not be loaded. " + + "To ensure you have the latest version of dbghelp.dll, download " + + "Debugging " + + "Tools for Windows and configure Process Hacker to " + + "use its version of dbghelp.dll. If you have the latest version of dbghelp.dll, " + + "ensure that symsrv.dll resides in the same directory as dbghelp.dll."; + td.EnableHyperlinks = true; + td.Callback = (taskDialog, args, callbackData) => + { + if (args.Notification == TaskDialogNotification.HyperlinkClicked) + { + try + { + System.Diagnostics.Process.Start( + "http://www.microsoft.com/whdc/devtools/debugging/default.mspx"); + } + catch (Exception ex) + { + MessageBox.Show("Could not open the hyperlink: " + ex.ToString(), + "Process Hacker", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + + return true; + } + + return false; + }; + td.VerificationText = force ? null : "Do not display this warning again"; + td.VerificationFlagChecked = true; + + td.Show(window, out verificationChecked); + + if (!force) + Properties.Settings.Default.DbgHelpWarningShown = verificationChecked; + } + else + { + MessageBox.Show(window, "The Microsoft Symbol Server is not supported by your version of dbghelp.dll " + + "or could not be loaded. To ensure you have the latest version of dbghelp.dll, download " + + "Debugging Tools for Windows and configure Process Hacker to use its version of dbghelp.dll. " + + "If you have the latest version of dbghelp.dll, ensure that symsrv.dll resides in the same " + + "directory as dbghelp.dll.", "Process Hacker", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + } + } + + break; + } + } + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + + public static void LoadKernelModules(this SymbolProvider symbols) + { + // hack for drivers, whose sizes never load properly because of dbghelp.dll's dumb guessing + symbols.PreloadModules = true; + + // load driver symbols + foreach (var module in Windows.GetKernelModules()) + { + try + { + symbols.LoadModule(module.FileName, module.BaseAddress); + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + } + + public static void LoadProcessModules(this SymbolProvider symbols, ProcessHandle phandle) + { + foreach (var module in phandle.GetModules()) + { + try + { + symbols.LoadModule(module.FileName, module.BaseAddress, module.Size); + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + } + + public static void LoadProcessWow64Modules(this SymbolProvider symbols, int pid) + { + using (var buffer = new ProcessHacker.Native.Debugging.DebugBuffer()) + { + buffer.Query(pid, ProcessHacker.Native.Api.RtlQueryProcessDebugFlags.Modules32); + + foreach (var module in buffer.GetModules()) + { + try + { + symbols.LoadModule(module.FileName, module.BaseAddress, module.Size); + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/UI/Actions/ElevationLevel.cs b/branches/ph-plugins/ProcessHacker/UI/Actions/ElevationLevel.cs new file mode 100644 index 000000000..a4f82417c --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/UI/Actions/ElevationLevel.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker.UI.Actions +{ + public enum ElevationLevel + { + Never = 0, + Prompt, + Elevate + } +} diff --git a/branches/ph-plugins/ProcessHacker/UI/Actions/ProcessActions.cs b/branches/ph-plugins/ProcessHacker/UI/Actions/ProcessActions.cs new file mode 100644 index 000000000..da1d263cd --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/UI/Actions/ProcessActions.cs @@ -0,0 +1,540 @@ +/* + * Process Hacker - + * process actions + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Components; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.UI.Actions +{ + public static class ProcessActions + { + private enum ElevationAction + { + NotRequired, + Cancel, + Elevate, + DontElevate + } + + private static bool Prompt(IWin32Window window, int[] pids, string[] names, + string action, string content, bool promptOnlyIfDangerous) + { + if (!Properties.Settings.Default.WarnDangerous) + return true; + + string name = "the selected process(es)"; + + if (pids.Length == 1) + name = names[0]; + else + name = "the selected processes"; + + bool dangerous = false; + + foreach (int pid in pids) + { + if (PhUtils.IsDangerousPid(pid)) + { + dangerous = true; + break; + } + } + + bool critical = false; + + foreach (int pid in pids) + { + try + { + using (var phandle = new ProcessHandle(pid, ProcessAccess.QueryInformation)) + { + if (phandle.IsCritical()) + { + critical = true; + break; + } + } + } + catch + { } + } + + if (promptOnlyIfDangerous && !dangerous && !critical) + return true; + + DialogResult result = DialogResult.No; + + if (OSVersion.HasTaskDialogs) + { + TaskDialog td = new TaskDialog(); + + td.WindowTitle = "Process Hacker"; + td.MainInstruction = "Do you want to " + action + " " + name + "?"; + td.Content = content; + + if (critical) + { + td.MainIcon = TaskDialogIcon.Warning; + td.Content = "You are about to " + action + " one or more CRITICAL processes. " + + "Windows is designed to break (crash) when one of these processes is terminated. " + + "Are you sure you want to continue?"; + } + else if (dangerous) + { + td.MainIcon = TaskDialogIcon.Warning; + td.Content = "You are about to " + action + " one or more system processes. " + + "Doing so will cause system instability. Are you sure you want to continue?"; + } + + if (pids.Length > 1) + { + td.ExpandFooterArea = true; + td.ExpandedInformation = "Processes:\r\n"; + + for (int i = 0; i < pids.Length; i++) + { + bool dangerousPid, criticalPid; + + dangerousPid = PhUtils.IsDangerousPid(pids[i]); + + try + { + using (var phandle = new ProcessHandle(pids[i], ProcessAccess.QueryInformation)) + criticalPid = phandle.IsCritical(); + } + catch + { + criticalPid = false; + } + + td.ExpandedInformation += names[i] + " (PID " + pids[i].ToString() + ")" + + (dangerousPid ? " (system process) " : "") + + (criticalPid ? " (CRITICAL) " : "") + + "\r\n"; + } + + td.ExpandedInformation = td.ExpandedInformation.Trim(); + } + + td.Buttons = new TaskDialogButton[] + { + new TaskDialogButton((int)DialogResult.Yes, char.ToUpper(action[0]) + action.Substring(1)), + new TaskDialogButton((int)DialogResult.No, "Cancel") + }; + td.DefaultButton = (int)DialogResult.No; + + result = (DialogResult)td.Show(window); + } + else + { + if (critical) + { + result = MessageBox.Show("You are about to " + action + " one or more CRITICAL processes. " + + "Windows is designed to break (crash) when one of these processes is terminated. " + + "Are you sure you want to " + action + " " + name + "?", + "Process Hacker", MessageBoxButtons.YesNo, + MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button2); + } + else if (dangerous) + { + result = MessageBox.Show("You are about to " + action + " one or more system processes. " + + "Are you sure you want to " + action + " " + name + "?", + "Process Hacker", MessageBoxButtons.YesNo, + MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button2); + } + else + { + result = MessageBox.Show("Are you sure you want to " + action + " " + name + "?", + "Process Hacker", MessageBoxButtons.YesNo, + MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button2); + } + } + + return result == DialogResult.Yes; + } + + private static ElevationAction PromptForElevation(IWin32Window window, int[] pids, string[] names, + ProcessAccess access, string elevateAction, string action) + { + if (Properties.Settings.Default.ElevationLevel == (int)ElevationLevel.Never) + return ElevationAction.NotRequired; + + if ( + OSVersion.HasUac && + Program.ElevationType == ProcessHacker.Native.Api.TokenElevationType.Limited && + KProcessHacker.Instance == null + ) + { + try + { + foreach (int pid in pids) + { + using (var phandle = new ProcessHandle(pid, access)) + { } + } + } + catch (WindowsException ex) + { + if (ex.ErrorCode != Win32Error.AccessDenied) + return ElevationAction.NotRequired; + + if (Properties.Settings.Default.ElevationLevel == (int)ElevationLevel.Elevate) + return ElevationAction.Elevate; + + TaskDialog td = new TaskDialog(); + + td.WindowTitle = "Process Hacker"; + td.MainIcon = TaskDialogIcon.Warning; + td.MainInstruction = "Do you want to " + elevateAction + "?"; + td.Content = "The action cannot be performed in the current security context. " + + "Do you want Process Hacker to prompt for the appropriate credentials and " + elevateAction + "?"; + + td.ExpandedInformation = "Error: " + ex.Message + " (0x" + ex.ErrorCode.ToString("x") + ")"; + td.ExpandFooterArea = true; + + td.Buttons = new TaskDialogButton[] + { + new TaskDialogButton((int)DialogResult.Yes, "Elevate\nPrompt for credentials and " + elevateAction + "."), + new TaskDialogButton((int)DialogResult.No, "Continue\nAttempt to perform the action without elevation.") + }; + td.CommonButtons = TaskDialogCommonButtons.Cancel; + td.UseCommandLinks = true; + td.Callback = (taskDialog, args, userData) => + { + if (args.Notification == TaskDialogNotification.Created) + { + taskDialog.SetButtonElevationRequiredState((int)DialogResult.Yes, true); + } + + return false; + }; + + DialogResult result = (DialogResult)td.Show(window); + + if (result == DialogResult.Yes) + { + return ElevationAction.Elevate; + } + else if (result == DialogResult.No) + { + return ElevationAction.DontElevate; + } + else if (result == DialogResult.Cancel) + { + return ElevationAction.Cancel; + } + } + } + + return ElevationAction.NotRequired; + } + + private static bool ElevateIfRequired(IWin32Window window, int[] pids, string[] names, + ProcessAccess access, string action) + { + ElevationAction result; + + result = PromptForElevation(window, pids, names, access, "elevate the action", action); + + if (result == ElevationAction.NotRequired || result == ElevationAction.DontElevate) + { + return false; + } + else if (result == ElevationAction.Cancel) + { + return true; + } + else if (result == ElevationAction.Elevate) + { + string objects = ""; + + foreach (int pid in pids) + objects += pid + ","; + + Program.StartProcessHackerAdmin("-e -type process -action " + action + " -obj \"" + + objects + "\" -hwnd " + window.Handle.ToString(), null, window.Handle); + + return true; + } + else + { + return false; + } + } + + private static string GetName(int[] pids, string[] names, int index) + { + return "the process \"" + names[index] + "\" with PID " + pids[index].ToString(); + } + + public static bool ShowProperties(IWin32Window window, int pid, string name) + { + ElevationAction result; + + // If we're viewing System, don't prompt for elevation since we can view + // thread and module information without it. + if (pid != 4) + { + result = PromptForElevation( + window, + new int[] { pid }, + new string[] { name }, + Program.MinProcessQueryRights, + "restart Process Hacker elevated", + "show properties for" + ); + } + else + { + result = ElevationAction.NotRequired; + } + + if (result == ElevationAction.Elevate) + { + Program.StartProcessHackerAdmin("-v -ip " + pid.ToString(), () => + { + Program.HackerWindow.Exit(); + }, window.Handle); + + return false; + } + else if (result == ElevationAction.Cancel) + { + return false; + } + + if (Program.ProcessProvider.Dictionary.ContainsKey(pid)) + { + try + { + ProcessWindow pForm = Program.GetProcessWindow(Program.ProcessProvider.Dictionary[pid], + new Program.PWindowInvokeAction(delegate(ProcessWindow f) + { + Program.FocusWindow(f); + })); + } + catch (Exception ex) + { + PhUtils.ShowException("Unable to inspect the process", ex); + return false; + } + } + else + { + PhUtils.ShowError("Unable to inspect the process because it does not exist."); + } + + return true; + } + + public static bool Terminate(IWin32Window window, int[] pids, string[] names, bool prompt) + { + bool allGood = true; + + if (ElevateIfRequired(window, pids, names, ProcessAccess.Terminate, "terminate")) + return false; + + if (prompt && !Prompt(window, pids, names, "terminate", + "Terminating a process will cause unsaved data to be lost. " + + "Terminating a system process will cause system instability. " + + "Are you sure you want to continue?", false)) + return false; + + for (int i = 0; i < pids.Length; i++) + { + try + { + using (ProcessHandle phandle = + new ProcessHandle(pids[i], ProcessAccess.Terminate)) + phandle.Terminate(); + } + catch (Exception ex) + { + allGood = false; + + if (!PhUtils.ShowContinueMessage( + "Unable to terminate " + GetName(pids, names, i), + ex + )) + return false; + } + } + + return allGood; + } + + public static bool TerminateTree(IWin32Window window, int[] pids, string[] names, bool prompt) + { + bool allGood = true; + + // HACK + if (prompt && !Prompt( + window, + new int[] { pids[0] }, + new string[] { names[0] + " and its descendants" }, "terminate", + "Terminating a process tree will cause the process and its descendants to be terminated. " + + "Are you sure you want to continue?", false + )) + return false; + + var processes = Windows.GetProcesses(); + + for (int i = 0; i < pids.Length; i++) + { + if (!TerminateTree(window, processes, pids[i])) + allGood = false; + } + + return allGood; + } + + private static bool TerminateTree(IWin32Window window, Dictionary processes, int pid) + { + bool good = true; + + foreach (var process in processes) + { + if (process.Value.Process.ProcessId < 4) + continue; + + if (process.Value.Process.InheritedFromProcessId.Equals(pid)) + if (!TerminateTree(window, processes, process.Value.Process.ProcessId)) + good = false; + } + + try + { + using (ProcessHandle phandle = + new ProcessHandle(pid, ProcessAccess.Terminate)) + phandle.Terminate(); + } + catch (Exception ex) + { + good = false; + + PhUtils.ShowException( + "Unable to terminate the process \"" + processes[pid].Name + "\" with PID " + pid.ToString(), + ex + ); + } + + return good; + } + + public static void Suspend(IWin32Window window, int[] pids, string[] names, bool prompt) + { + if (ElevateIfRequired(window, pids, names, ProcessAccess.SuspendResume, "suspend")) + return; + + if (prompt && !Prompt(window, pids, names, "suspend", + "Suspending a process will pause its execution. " + + "Suspending a system process will cause system instability. " + + "Are you sure you want to continue?", true)) + return; + + for (int i = 0; i < pids.Length; i++) + { + try + { + using (ProcessHandle phandle = + new ProcessHandle(pids[i], ProcessAccess.SuspendResume)) + phandle.Suspend(); + } + catch (Exception ex) + { + if (!PhUtils.ShowContinueMessage( + "Unable to suspend " + GetName(pids, names, i), + ex + )) + return; + } + } + } + + public static void Resume(IWin32Window window, int[] pids, string[] names, bool prompt) + { + if (ElevateIfRequired(window, pids, names, ProcessAccess.SuspendResume, "resume")) + return; + + if (prompt && !Prompt(window, pids, names, "resume", + "Resuming a process will begin its execution. " + + "Resuming a system process may lead to system instability. " + + "Are you sure you want to continue?", true)) + return; + + for (int i = 0; i < pids.Length; i++) + { + try + { + using (ProcessHandle phandle = + new ProcessHandle(pids[i], ProcessAccess.SuspendResume)) + phandle.Resume(); + } + catch (Exception ex) + { + if (!PhUtils.ShowContinueMessage( + "Unable to resume " + GetName(pids, names, i), + ex + )) + return; + } + } + } + + public static void ReduceWorkingSet(IWin32Window window, int[] pids, string[] names, bool prompt) + { + if (ElevateIfRequired(window, pids, names, + ProcessAccess.QueryInformation | ProcessAccess.SetQuota, "reduceworkingset")) + return; + + if (prompt && !Prompt(window, pids, names, "reduce the working set of", + "Reducing the working set of a process reduces its physical memory consumption. " + + "Are you sure you want to continue?", true)) + return; + + for (int i = 0; i < pids.Length; i++) + { + try + { + using (ProcessHandle phandle = + new ProcessHandle(pids[i], ProcessAccess.QueryInformation | ProcessAccess.SetQuota)) + phandle.EmptyWorkingSet(); + } + catch (Exception ex) + { + if (!PhUtils.ShowContinueMessage( + "Unable to reduce the working set of " + GetName(pids, names, i), + ex + )) + return; + } + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/UI/Actions/ServiceActions.cs b/branches/ph-plugins/ProcessHacker/UI/Actions/ServiceActions.cs new file mode 100644 index 000000000..45574ddc0 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/UI/Actions/ServiceActions.cs @@ -0,0 +1,253 @@ +/* + * Process Hacker - + * service actions + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Windows.Forms; +using ProcessHacker.Components; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.UI.Actions +{ + public static class ServiceActions + { + private static bool Prompt(IWin32Window window, string service, string action, string content, TaskDialogIcon icon) + { + DialogResult result = DialogResult.No; + + if (OSVersion.HasTaskDialogs) + { + TaskDialog td = new TaskDialog(); + + td.WindowTitle = "Process Hacker"; + td.MainInstruction = "Do you want to " + action + " " + service + "?"; + td.MainIcon = icon; + td.Content = content; + + td.Buttons = new TaskDialogButton[] + { + new TaskDialogButton((int)DialogResult.Yes, char.ToUpper(action[0]) + action.Substring(1)), + new TaskDialogButton((int)DialogResult.No, "Cancel") + }; + td.DefaultButton = (int)DialogResult.No; + + result = (DialogResult)td.Show(window); + } + else + { + result = MessageBox.Show("Are you sure you want to " + action + " " + service + "?", + "Process Hacker", MessageBoxButtons.YesNo, + MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button2); + } + + return result == DialogResult.Yes; + } + + private static bool ElevateIfRequired(IWin32Window window, string service, + ServiceAccess access, string action) + { + if (Properties.Settings.Default.ElevationLevel == (int)ElevationLevel.Never) + return false; + + if (OSVersion.HasUac && Program.ElevationType == TokenElevationType.Limited) + { + try + { + using (var shandle = new ServiceHandle(service, access)) + { } + } + catch (WindowsException ex) + { + DialogResult result; + + if (Properties.Settings.Default.ElevationLevel == (int)ElevationLevel.Elevate) + { + result = DialogResult.Yes; + } + else + { + TaskDialog td = new TaskDialog(); + + td.WindowTitle = "Process Hacker"; + td.MainIcon = TaskDialogIcon.Warning; + td.MainInstruction = "Do you want to elevate the action?"; + td.Content = "The action cannot be performed in the current security context. " + + "Do you want Process Hacker to prompt for the appropriate credentials and elevate the action?"; + + td.ExpandedInformation = "Error: " + ex.Message + " (0x" + ex.ErrorCode.ToString("x") + ")"; + td.ExpandFooterArea = true; + + td.Buttons = new TaskDialogButton[] + { + new TaskDialogButton((int)DialogResult.Yes, "Elevate\nPrompt for credentials and elevate the action."), + new TaskDialogButton((int)DialogResult.No, "Continue\nAttempt to perform the action without elevation.") + }; + td.CommonButtons = TaskDialogCommonButtons.Cancel; + td.UseCommandLinks = true; + td.Callback = (taskDialog, args, userData) => + { + if (args.Notification == TaskDialogNotification.Created) + { + taskDialog.SetButtonElevationRequiredState((int)DialogResult.Yes, true); + } + + return false; + }; + + result = (DialogResult)td.Show(window); + } + + if (result == DialogResult.Yes) + { + Program.StartProcessHackerAdmin("-e -type service -action " + action + " -obj \"" + + service + "\" -hwnd " + window.Handle.ToString(), null, window.Handle); + + return true; + } + else if (result == DialogResult.No) + { + return false; + } + else if (result == DialogResult.Cancel) + { + return true; + } + } + } + + return false; + } + + public static void Start(IWin32Window window, string service, bool prompt) + { + if (ElevateIfRequired(window, service, ServiceAccess.Start, "start")) + return; + + if (prompt && !Prompt(window, service, "start", + "", TaskDialogIcon.None)) + return; + + try + { + using (var shandle = new ServiceHandle(service, ServiceAccess.Start)) + shandle.Start(); + } + catch (Exception ex) + { + DialogResult r = MessageBox.Show(window, "Could not start the service \"" + service + + "\":\n\n" + + ex.Message, "Process Hacker", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + public static void Continue(IWin32Window window, string service, bool prompt) + { + if (ElevateIfRequired(window, service, ServiceAccess.PauseContinue, "continue")) + return; + + if (prompt && !Prompt(window, service, "continue", + "", TaskDialogIcon.None)) + return; + + try + { + using (var shandle = new ServiceHandle(service, ServiceAccess.PauseContinue)) + shandle.Control(ServiceControl.Continue); + } + catch (Exception ex) + { + DialogResult r = MessageBox.Show(window, "Could not continue the service \"" + service + + "\":\n\n" + + ex.Message, "Process Hacker", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + public static void Pause(IWin32Window window, string service, bool prompt) + { + if (ElevateIfRequired(window, service, ServiceAccess.PauseContinue, "pause")) + return; + + if (prompt && !Prompt(window, service, "pause", + "", TaskDialogIcon.None)) + return; + + try + { + using (var shandle = new ServiceHandle(service, ServiceAccess.PauseContinue)) + shandle.Control(ServiceControl.Pause); + } + catch (Exception ex) + { + DialogResult r = MessageBox.Show(window, "Could not pause the service \"" + service + + "\":\n\n" + + ex.Message, "Process Hacker", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + public static void Stop(IWin32Window window, string service, bool prompt) + { + if (ElevateIfRequired(window, service, ServiceAccess.Stop, "stop")) + return; + + if (prompt && !Prompt(window, service, "stop", + "", TaskDialogIcon.None)) + return; + + try + { + using (var shandle = new ServiceHandle(service, ServiceAccess.Stop)) + shandle.Control(ServiceControl.Stop); + } + catch (Exception ex) + { + DialogResult r = MessageBox.Show(window, "Could not stop the service \"" + service + + "\":\n\n" + + ex.Message, "Process Hacker", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + public static void Delete(IWin32Window window, string service, bool prompt) + { + if (ElevateIfRequired(window, service, (ServiceAccess)StandardRights.Delete, "delete")) + return; + + if (prompt && !Prompt(window, service, "delete", + "Deleting a service can prevent the system from starting or functioning properly. " + + "Are you sure you want to continue?", TaskDialogIcon.Warning)) + return; + + try + { + using (var shandle = new ServiceHandle(service, (ServiceAccess)StandardRights.Delete)) + shandle.Delete(); + } + catch (Exception ex) + { + DialogResult r = MessageBox.Show(window, "Could not delete the service \"" + service + + "\":\n\n" + + ex.Message, "Process Hacker", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/UI/Actions/SessionActions.cs b/branches/ph-plugins/ProcessHacker/UI/Actions/SessionActions.cs new file mode 100644 index 000000000..2a3d366c4 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/UI/Actions/SessionActions.cs @@ -0,0 +1,133 @@ +using System; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Components; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; + +namespace ProcessHacker.UI.Actions +{ + public class SessionActions + { + private static bool Prompt(IWin32Window window, string name, + string action, string content) + { + DialogResult result = DialogResult.No; + + if (OSVersion.HasTaskDialogs) + { + TaskDialog td = new TaskDialog(); + + td.WindowTitle = "Process Hacker"; + td.MainInstruction = "Do you want to " + action + " " + name + "?"; + td.Content = content; + + td.Buttons = new TaskDialogButton[] + { + new TaskDialogButton((int)DialogResult.Yes, char.ToUpper(action[0]) + action.Substring(1)), + new TaskDialogButton((int)DialogResult.No, "Cancel") + }; + td.DefaultButton = (int)DialogResult.No; + + result = (DialogResult)td.Show(window); + } + else + { + result = MessageBox.Show("Are you sure you want to " + action + " " + name + "?", + "Process Hacker", MessageBoxButtons.YesNo, + MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button2); + } + + return result == DialogResult.Yes; + } + + private static void ElevateIfRequired(IWin32Window window, int session, string actionName, Action action) + { + if (Properties.Settings.Default.ElevationLevel == (int)ElevationLevel.Never) + return; + + try + { + action(); + } + catch (WindowsException ex) + { + if (ex.ErrorCode == Win32Error.AccessDenied && + OSVersion.HasUac && + Program.ElevationType == ProcessHacker.Native.Api.TokenElevationType.Limited) + { + DialogResult result; + + if (Properties.Settings.Default.ElevationLevel == (int)ElevationLevel.Elevate) + { + result = DialogResult.Yes; + } + else + { + TaskDialog td = new TaskDialog(); + + td.WindowTitle = "Process Hacker"; + td.MainIcon = TaskDialogIcon.Warning; + td.MainInstruction = "Do you want to elevate the action?"; + td.Content = "The action could not be performed in the current security context. " + + "Do you want Process Hacker to prompt for the appropriate credentials and elevate the action?"; + + td.ExpandedInformation = "Error: " + ex.Message + " (0x" + ex.ErrorCode.ToString("x") + ")"; + td.ExpandFooterArea = true; + + td.Buttons = new TaskDialogButton[] + { + new TaskDialogButton((int)DialogResult.Yes, "Elevate\nPrompt for credentials and elevate the action.") + }; + td.CommonButtons = TaskDialogCommonButtons.Cancel; + td.UseCommandLinks = true; + td.Callback = (taskDialog, args, userData) => + { + if (args.Notification == TaskDialogNotification.Created) + { + taskDialog.SetButtonElevationRequiredState((int)DialogResult.Yes, true); + } + + return false; + }; + + result = (DialogResult)td.Show(window); + } + + if (result == DialogResult.Yes) + { + Program.StartProcessHackerAdmin("-e -type session -action " + actionName + " -obj \"" + + session.ToString() + "\" -hwnd " + window.Handle.ToString(), null, window.Handle); + } + } + else + { + PhUtils.ShowException("Unable to " + actionName + " the session", ex); + } + } + } + + public static void Disconnect(IWin32Window window, int session, bool prompt) + { + if (prompt && !Prompt(window, "the session", "disconnect", "")) + return; + + ElevateIfRequired(window, session, "disconnect", () => + { + TerminalServerHandle.GetCurrent().GetSession(session).Disconnect(); + }); + } + + public static void Logoff(IWin32Window window, int session, bool prompt) + { + if (prompt && !Prompt(window, "the session", "logoff", "")) + return; + + ElevateIfRequired(window, session, "logoff", () => + { + TerminalServerHandle.GetCurrent().GetSession(session).Logoff(); + }); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/UI/Async/AsyncUtils.cs b/branches/ph-plugins/ProcessHacker/UI/Async/AsyncUtils.cs new file mode 100644 index 000000000..7cca0b4c3 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/UI/Async/AsyncUtils.cs @@ -0,0 +1,235 @@ +/* + * Process Hacker - + * wrapper for running tasks asynchronously + * + * Copyright (C) 2009 wj32 + * Copyright (C) 2008 Dean + * + * 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 . + */ + +using System; +using System.Windows.Forms; +using System.Threading; +using System.ComponentModel; + +namespace ProcessHacker.FormHelper +{ + /// + /// Exception thrown when an operation is already in progress. + /// + public class AlreadyRunningException : System.ApplicationException + { + public AlreadyRunningException() : base("Operation already running") + { } + } + + public abstract class AsyncOperation + { + private Thread _asyncThread; + private object _asyncLock = new object(); + + public AsyncOperation(ISynchronizeInvoke target) + { + isiTarget = target; + isRunning = false; + } + + public void Start() + { + lock (_asyncLock) + { + if (isRunning) + { + throw new AlreadyRunningException(); + } + isRunning = true; + } + + _asyncThread = new Thread(InternalStart); + _asyncThread.Start(); + } + + public void Cancel() + { + lock (_asyncLock) + { + cancelledFlag = true; + } + } + + public bool CancelAndWait() + { + lock (_asyncLock) + { + cancelledFlag = true; + + while (!IsDone) + { + Monitor.Wait(_asyncLock, 1000); + } + } + + return !HasCompleted; + } + + public bool WaitUntilDone() + { + lock (_asyncLock) + { + // Wait for either completion or cancellation. As with + // CancelAndWait, we don't sleep forever - to reduce the + // chances of deadlock in obscure race conditions, we wake + // up every second to check we didn't miss a Pulse. + while (!IsDone) + { + Monitor.Wait(_asyncLock, 1000); + } + } + + return HasCompleted; + } + + public bool IsDone + { + get + { + lock (_asyncLock) + { + return completeFlag || cancelAcknowledgedFlag || failedFlag; + } + } + } + + public event EventHandler Completed; + public event EventHandler Cancelled; + public event System.Threading.ThreadExceptionEventHandler Failed; + + private ISynchronizeInvoke isiTarget; + protected ISynchronizeInvoke Target + { + get { return isiTarget; } + } + + /// + /// To be overridden by the deriving class + /// + protected abstract void DoWork(); + + private bool cancelledFlag; + protected bool CancelRequested + { + get + { + lock (_asyncLock) { return cancelledFlag; } + } + } + + private bool completeFlag; + protected bool HasCompleted + { + get + { + lock (_asyncLock) { return completeFlag; } + } + } + + protected void AcknowledgeCancel() + { + lock (_asyncLock) + { + cancelAcknowledgedFlag = true; + isRunning = false; + Monitor.Pulse(_asyncLock); + FireAsync(Cancelled, this, EventArgs.Empty); + } + } + + private bool cancelAcknowledgedFlag; + // if the operation fails with an exception, set to true + private bool failedFlag; + // if the operation is running, set to true + private bool isRunning; + + private void InternalStart() + { + cancelledFlag = false; + completeFlag = false; + cancelAcknowledgedFlag = false; + failedFlag = false; + + try + { + DoWork(); + } + catch (Exception e) + { + try + { + FailOperation(e); + } + catch + { } + + if (e is SystemException) + { + throw; + } + } + + lock (_asyncLock) + { + // raise the Completion event + if (!cancelAcknowledgedFlag && !failedFlag) + { + CompleteOperation(); + } + } + } + + private void CompleteOperation() + { + lock (_asyncLock) + { + completeFlag = true; + isRunning = false; + Monitor.Pulse(_asyncLock); + FireAsync(Completed, this, EventArgs.Empty); + } + } + + private void FailOperation(Exception e) + { + lock (_asyncLock) + { + failedFlag = true; + isRunning = false; + Monitor.Pulse(_asyncLock); + FireAsync(Failed, this, new ThreadExceptionEventArgs(e)); + } + } + + protected void FireAsync(Delegate dlg, params object[] pList) + { + if (dlg != null) + { + Target.BeginInvoke(dlg, pList); + } + } + } +} + + diff --git a/branches/ph-plugins/ProcessHacker/UI/Async/HandleFilter.cs b/branches/ph-plugins/ProcessHacker/UI/Async/HandleFilter.cs new file mode 100644 index 000000000..7840f45f5 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/UI/Async/HandleFilter.cs @@ -0,0 +1,259 @@ +/* + * Process Hacker - + * handle filter + * + * Copyright (C) 2008 Dean + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Windows.Forms; +using ProcessHacker.Common; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; +using ProcessHacker.Native.Objects; +using ProcessHacker.Native.Security; + +namespace ProcessHacker.FormHelper +{ + public sealed class HandleFilter : AsyncOperation + { + private const int BufferSize = 50; + + public delegate void MatchListViewEvent(List item); + public delegate void MatchProgressEvent(int currentValue, int count); + public event MatchListViewEvent MatchListView; + public event MatchProgressEvent MatchProgress; + private string strFilter; + private List listViewItemContainer = new List(BufferSize); + private Dictionary isCurrentSessionIdCache = new Dictionary(); + + public HandleFilter(ISynchronizeInvoke isi, string strFilter) + : base(isi) + { + this.strFilter = strFilter; + } + + protected override void DoWork() + { + DoFilter(strFilter); + if (CancelRequested) + { + AcknowledgeCancel(); + } + } + + private void DoFilter(string strFilter) + { + string lowerFilter = strFilter.ToLower(); + + // Stop if cancel + if (!CancelRequested) + { + var handles = Windows.GetHandles(); + Dictionary processHandles = new Dictionary(); + + // Find handles + for (int i = 0; i < handles.Length; i++) + { + // Check for cancellation here too, + // otherwise the user might have to wait for much time + if (CancelRequested) return; + + if (i % 20 == 0) + OnMatchProgress(i, handles.Length); + + var handle = handles[i]; + + CompareHandleBestNameWithFilterString(processHandles, handle, lowerFilter); + // test Exception + //if (i > 2000) throw new Exception("test"); + } + + foreach (ProcessHandle phandle in processHandles.Values) + phandle.Dispose(); + + // Find DLLs and mapped files + var processes = Windows.GetProcesses(); + + foreach (var process in processes) + { + try + { + using (var phandle = new ProcessHandle(process.Key, + Program.MinProcessQueryRights | Program.MinProcessReadMemoryRights)) + { + phandle.EnumModules((module) => + { + if (module.FileName.ToLower().Contains(lowerFilter)) + this.CallDllMatchListView(process.Key, module); + return true; + }); + } + + using (var phandle = new ProcessHandle(process.Key, + ProcessAccess.QueryInformation | Program.MinProcessReadMemoryRights)) + { + phandle.EnumMemory((region) => + { + if (region.Type != MemoryType.Mapped) + return true; + + string name = phandle.GetMappedFileName(region.BaseAddress); + + if (name != null && name.ToLower().Contains(lowerFilter)) + this.CallMappedFileMatchListView(process.Key, region.BaseAddress, name); + + return true; + }); + } + } + catch (Exception ex) + { + Logging.Log(ex); + } + } + + OnMatchListView(null); + } + } + + private void CompareHandleBestNameWithFilterString( + Dictionary processHandles, + SystemHandleEntry currhandle, string lowerFilter) + { + try + { + // Don't get handles from processes in other session + // if we don't have KPH to reduce freezes. Note that + // on Windows 7 the hanging bug appears to have been + // fixed, so there is an exception for that. + if ( + KProcessHacker.Instance == null && + !OSVersion.IsAboveOrEqual(WindowsVersion.Seven) + ) + { + try + { + if (isCurrentSessionIdCache.ContainsKey(currhandle.ProcessId)) + { + if (!isCurrentSessionIdCache[currhandle.ProcessId]) + return; + } + else + { + bool isCurrentSessionId = Win32.GetProcessSessionId(currhandle.ProcessId) == Program.CurrentSessionId; + + isCurrentSessionIdCache.Add(currhandle.ProcessId, isCurrentSessionId); + + if (!isCurrentSessionId) + return; + } + } + catch + { + return; + } + } + + if (!processHandles.ContainsKey(currhandle.ProcessId)) + processHandles.Add(currhandle.ProcessId, + new ProcessHandle(currhandle.ProcessId, Program.MinProcessGetHandleInformationRights)); + + var info = currhandle.GetHandleInfo(processHandles[currhandle.ProcessId]); + + if (string.IsNullOrEmpty(info.BestName)) + return; + if (!info.BestName.ToLower().Contains(lowerFilter)) + return; + + CallHandleMatchListView(currhandle, info); + } + catch + { + return; + } + } + + private void CallHandleMatchListView(SystemHandleEntry handle, ObjectInformation info) + { + ListViewItem item = new ListViewItem(); + item.Name = handle.ProcessId.ToString() + " " + handle.Handle.ToString(); + item.Text = Program.ProcessProvider.Dictionary[handle.ProcessId].Name + + " (" + handle.ProcessId.ToString() + ")"; + item.Tag = handle; + item.SubItems.Add(new ListViewItem.ListViewSubItem(item, info.TypeName)); + item.SubItems.Add(new ListViewItem.ListViewSubItem(item, info.BestName)); + item.SubItems.Add(new ListViewItem.ListViewSubItem(item, "0x" + handle.Handle.ToString("x"))); + OnMatchListView(item); + } + + private void CallDllMatchListView(int pid, ProcessModule module) + { + ListViewItem item = new ListViewItem(); + item.Name = pid.ToString() + " " + module.BaseAddress.ToString(); + item.Text = Program.ProcessProvider.Dictionary[pid].Name + + " (" + pid.ToString() + ")"; + item.Tag = pid; + item.SubItems.Add(new ListViewItem.ListViewSubItem(item, "DLL")); + item.SubItems.Add(new ListViewItem.ListViewSubItem(item, module.FileName)); + item.SubItems.Add(new ListViewItem.ListViewSubItem(item, Utils.FormatAddress(module.BaseAddress))); + OnMatchListView(item); + } + + private void CallMappedFileMatchListView(int pid, IntPtr address, string fileName) + { + ListViewItem item = new ListViewItem(); + item.Name = pid.ToString() + " " + address.ToString(); + item.Text = Program.ProcessProvider.Dictionary[pid].Name + + " (" + pid.ToString() + ")"; + item.Tag = pid; + item.SubItems.Add(new ListViewItem.ListViewSubItem(item, "Mapped File")); + item.SubItems.Add(new ListViewItem.ListViewSubItem(item, fileName)); + item.SubItems.Add(new ListViewItem.ListViewSubItem(item, Utils.FormatAddress(address))); + OnMatchListView(item); + } + + private void OnMatchListView(ListViewItem item) + { + if (item == null) + { + if (listViewItemContainer.Count > 0) + FireAsync(MatchListView, listViewItemContainer); + return; + } + + listViewItemContainer.Add(item); + + if (listViewItemContainer.Count >= BufferSize) + { + List items = listViewItemContainer; + + FireAsync(MatchListView, items); + listViewItemContainer = new List(BufferSize); + } + } + + private void OnMatchProgress(int currentValue, int allValue) + { + FireAsync(MatchProgress, currentValue, allValue); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/UI/ColumnSettings.cs b/branches/ph-plugins/ProcessHacker/UI/ColumnSettings.cs new file mode 100644 index 000000000..0359d7ff8 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/UI/ColumnSettings.cs @@ -0,0 +1,168 @@ +/* + * Process Hacker - + * column settings manager + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Windows.Forms; +using System.Collections.Generic; +using System.Collections; +using System.Text; +using Aga.Controls.Tree; +using Aga.Controls.Tree.NodeControls; + +namespace ProcessHacker.UI +{ + /// + /// Provides methods for loading and saving ListView column settings. + /// + public static class ColumnSettings + { + /// + /// Saves the column settings of the specified ListView to a string. + /// + /// + /// + public static string SaveSettings(ListView lv) + { + StringBuilder result = new StringBuilder(); + + try + { + foreach (ColumnHeader ch in lv.Columns) + { + result.Append(ch.DisplayIndex.ToString() + "," + ch.Width.ToString() + "|"); + } + } + catch + { } + + if (result.Length > 0) + result.Remove(result.Length - 1, 1); + + return result.ToString(); + } + + /// + /// Saves the column settings of the specified TreeViewAdv to a string. + /// + /// + /// + public static string SaveSettings(TreeViewAdv tv) + { + StringBuilder result = new StringBuilder(); + + try + { + for (int i = 0; i < tv.Columns.Count; i++) + { + TreeColumn c = tv.Columns[i]; + result.Append(c.Header + "," + c.Width.ToString() + "," + c.SortOrder.ToString() + + "," + c.IsVisible.ToString() + "|"); + } + } + catch + { } + + if (result.Length > 0) + result.Remove(result.Length - 1, 1); + + return result.ToString(); + } + + /// + /// Loads column settings from a string to a ListView. + /// + /// + /// + public static void LoadSettings(string settings, ListView lv) + { + if (settings.EndsWith("|")) + settings = settings.Remove(settings.Length - 1, 1); + + string[] list = settings.Split('|'); + + if (settings == "") + return; + + // Has the number of columns changed? If so, don't do anything. + if (list.Length != lv.Columns.Count) + return; + + for (int i = 0; i < list.Length; i++) + { + string[] s = list[i].Split(','); + + if (s.Length != 2) + break; + + lv.Columns[i].DisplayIndex = Int32.Parse(s[0]); + lv.Columns[i].Width = Int32.Parse(s[1]); + } + } + + /// + /// Loads column settings from a string to a TreeViewAdv. + /// + /// + /// + public static void LoadSettings(string settings, TreeViewAdv tv) + { + if (settings.EndsWith("|")) + settings = settings.Remove(settings.Length - 1, 1); + + string[] list = settings.Split('|'); + + try + { + Dictionary oldAssoc = new Dictionary(); + + foreach (NodeControl control in tv.NodeControls) + { + oldAssoc.Add(control, control.ParentColumn.Header); + } + + TreeColumn[] newColumns = new TreeColumn[tv.Columns.Count]; + Dictionary newColumnsD = new Dictionary(); + + for (int i = 0; i < tv.Columns.Count; i++) + { + string[] s = list[i].Split(','); + + newColumns[i] = new TreeColumn(s[0], Int32.Parse(s[1])); + newColumns[i].SortOrder = (SortOrder)Enum.Parse(typeof(SortOrder), s[2]); + newColumns[i].IsVisible = bool.Parse(s[3]); + newColumns[i].MinColumnWidth = 3; + newColumnsD.Add(s[0], newColumns[i]); + } + + tv.Columns.Clear(); + + foreach (TreeColumn column in newColumns) + tv.Columns.Add(column); + + foreach (NodeControl c in oldAssoc.Keys) + c.ParentColumn = newColumnsD[oldAssoc[c]]; + } + catch + { } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/UI/GenericViewMenu.cs b/branches/ph-plugins/ProcessHacker/UI/GenericViewMenu.cs new file mode 100644 index 000000000..cdeb19e94 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/UI/GenericViewMenu.cs @@ -0,0 +1,268 @@ +/* + * Process Hacker - + * list view/tree view context menu generator + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows.Forms; +using Aga.Controls.Tree; +using Aga.Controls.Tree.NodeControls; +using ProcessHacker.Common; + +namespace ProcessHacker.UI +{ + public static class GenericViewMenu + { + public static ContextMenu GetMenu(ListView lv) + { + return GetMenu(lv, null); + } + + public static ContextMenu GetMenu(ListView lv, RetrieveVirtualItemEventHandler retrieveVirtualItem) + { + ContextMenu menu = new ContextMenu(); + + menu.Tag = lv; + menu.Popup += new EventHandler(ListViewMenu_Popup); + AddMenuItems(menu.MenuItems, lv, retrieveVirtualItem); + + return menu; + } + + public static void AddMenuItems(MenuItem.MenuItemCollection items, ListView lv, RetrieveVirtualItemEventHandler retrieveVirtualItem) + { + MenuItem copyItem = new MenuItem("Copy"); + + copyItem.Tag = new object[] { -1, lv, retrieveVirtualItem }; + copyItem.Click += new EventHandler(ListViewMenuItem_Click); + + items.Add(copyItem); + + foreach (ColumnHeader ch in lv.Columns) + { + MenuItem item = new MenuItem("Copy \"" + ch.Text + "\""); + + item.Tag = new object[] { ch.Index, lv, retrieveVirtualItem }; + item.Click += new EventHandler(ListViewMenuItem_Click); + + items.Add(item); + } + } + + private static void ListViewMenu_Popup(object sender, EventArgs e) + { + ContextMenu citem = (ContextMenu)sender; + ListView lv = (ListView)citem.Tag; + + if (lv.SelectedIndices.Count == 0) + { + Utils.DisableAllMenuItems(citem); + } + else + { + Utils.EnableAllMenuItems(citem); + } + } + + public static void ListViewCopy(ListView lv, int subItem) + { + ListViewCopy(lv, subItem, null); + } + + public static void ListViewCopy(ListView lv, int subItem, RetrieveVirtualItemEventHandler retrieveVirtualItem) + { + List collection = new List(); + StringBuilder text = new StringBuilder(); + + if (lv.SelectedIndices.Count == 0) + return; + + if (retrieveVirtualItem != null) + { + foreach (int index in lv.SelectedIndices) + { + RetrieveVirtualItemEventArgs args = new RetrieveVirtualItemEventArgs(index); + + retrieveVirtualItem(lv, args); + + collection.Add(args.Item); + } + } + else + { + foreach (ListViewItem item in lv.SelectedItems) + collection.Add(item); + } + + for (int i = 0; i < collection.Count; i++) + { + if (subItem == -1) + { + for (int j = 0; j < lv.Columns.Count; j++) + { + text.Append(collection[i].SubItems[j].Text); + + if (j != lv.Columns.Count - 1) + text.Append(", "); + } + } + else + { + text.Append(collection[i].SubItems[subItem].Text); + } + + if (i != collection.Count - 1) + text.AppendLine(); + } + + Clipboard.SetText(text.ToString()); + } + + private static void ListViewMenuItem_Click(object sender, EventArgs e) + { + MenuItem mitem = (MenuItem)sender; + + ListViewCopy((ListView)((object[])mitem.Tag)[1], (int)((object[])mitem.Tag)[0], + (RetrieveVirtualItemEventHandler)((object[])mitem.Tag)[2]); + } + + public static void AddMenuItems(MenuItem.MenuItemCollection items, TreeViewAdv tv) + { + MenuItem copyItem = new MenuItem("Copy"); + + copyItem.Tag = new object[] { -1, tv }; + copyItem.Click += new EventHandler(TreeViewAdvMenuItem_Click); + + items.Add(copyItem); + + foreach (TreeColumn c in tv.Columns) + { + int controlIndex = 0; + int index = -1; + + foreach (NodeControl control in tv.NodeControls) + { + if (control is BaseTextControl && control.ParentColumn == c) + { + index = controlIndex; + break; + } + + controlIndex++; + } + + if (!c.IsVisible || index == -1) + continue; + + MenuItem item = new MenuItem("Copy \"" + c.Header + "\""); + + item.Tag = new object[] { index, tv }; + item.Click += new EventHandler(TreeViewAdvMenuItem_Click); + + items.Add(item); + } + } + + public static void TreeViewAdvCopy(TreeViewAdv tv, int columnIndex) + { + List collection = new List(); + StringBuilder text = new StringBuilder(); + + if (tv.SelectedNodes.Count == 0) + return; + + foreach (TreeNodeAdv item in tv.SelectedNodes) + { + string[] array = new string[tv.Columns.Count]; + int i = 0; + + foreach (NodeControl control in tv.NodeControls) + { + if (control.ParentColumn.IsVisible && control is BaseTextControl) + array[i] = (control as BaseTextControl).GetLabel(item); + + i++; + } + + collection.Add(array); + } + + for (int i = 0; i < collection.Count; i++) + { + if (columnIndex == -1) + { + for (int j = 0; j < collection[i].Length; j++) + { + if (collection[i][j] != null) + { + text.Append(collection[i][j]); + } + + bool emptyFromHere = true; + + for (int k = j + 1; k < collection[i].Length; k++) + { + if (collection[i][k] != null && collection[i][k] != "") + { + emptyFromHere = false; + break; + } + } + + if (emptyFromHere) + break; + + if (collection[i][j] != null && j != collection[i].Length - 1) + text.Append(", "); + } + } + else + { + if (collection[i][columnIndex] != null) + text.AppendLine(collection[i][columnIndex]); + } + + if (i != collection.Count - 1) + text.AppendLine(); + } + + Clipboard.SetText(text.ToString()); + } + + private static void TreeViewAdvMenuItem_Click(object sender, EventArgs e) + { + MenuItem mitem = (MenuItem)sender; + + TreeViewAdvCopy((TreeViewAdv)((object[])mitem.Tag)[1], (int)((object[])mitem.Tag)[0]); + } + + public static ContextMenu GetCopyMenu(this ListView lv) + { + return lv.GetCopyMenu(null); + } + + public static ContextMenu GetCopyMenu(this ListView lv, RetrieveVirtualItemEventHandler retrieveVirtualItem) + { + return GetMenu(lv, retrieveVirtualItem); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/UI/HighlightedListViewItem.cs b/branches/ph-plugins/ProcessHacker/UI/HighlightedListViewItem.cs new file mode 100644 index 000000000..95f6a5f6b --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/UI/HighlightedListViewItem.cs @@ -0,0 +1,245 @@ +/* + * Process Hacker - + * reusable ListViewItem highlighting + * + * Copyright (C) 2008-2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Windows.Forms; +using ProcessHacker.Common; + +namespace ProcessHacker.UI +{ + public enum ListViewItemState + { + Normal, New, Removed + } + + public class HighlightingContext : IDisposable + { + public static event MethodInvoker HighlightingDurationChanged; + + private static Dictionary _colors = new Dictionary(); + private static int _highlightingDuration = 1000; + private static bool _stateHighlighting = true; + + static HighlightingContext() + { + _colors.Add(ListViewItemState.New, Color.FromArgb(0xe0f0e0)); + _colors.Add(ListViewItemState.Removed, Color.FromArgb(0xf0e0e0)); + } + + public static Dictionary Colors + { + get { return _colors; } + } + + /// + /// Gets or sets the duration, in milliseconds, of state highlighting. + /// + public static int HighlightingDuration + { + get { return _highlightingDuration; } + set + { + _highlightingDuration = value; + + if (HighlightingDurationChanged != null) + HighlightingDurationChanged(); + } + } + + /// + /// Gets or sets whether state highlighting is on. + /// + public static bool StateHighlighting + { + get { return _stateHighlighting; } + set { _stateHighlighting = value; } + } + + private ListView _list; + private Queue _preQueue = new Queue(); + private Queue _queue = new Queue(); + + public HighlightingContext(ListView list) + { + _list = list; + } + + public void Tick() + { + if (!_list.IsHandleCreated) + return; + + _list.BeginInvoke(new MethodInvoker(delegate + { + // Execute the pre-queue items. + _list.BeginUpdate(); + + while (_preQueue.Count > 0) + _preQueue.Dequeue().Invoke(); + + _list.EndUpdate(); + + // Execute the normal queue items. + System.Threading.Timer t = null; + + t = new System.Threading.Timer(o => + { + if (_list.IsHandleCreated) + { + _list.BeginInvoke(new MethodInvoker(delegate + { + _list.BeginUpdate(); + + while (_queue.Count > 0) + _queue.Dequeue().Invoke(); + + _list.EndUpdate(); + })); + } + + t.Dispose(); + }, null, HighlightingContext.HighlightingDuration, System.Threading.Timeout.Infinite); + })); + } + + public void Enqueue(MethodInvoker method) + { + _queue.Enqueue(method); + } + + public void EnqueuePre(MethodInvoker method) + { + _preQueue.Enqueue(method); + } + + public void Dispose() + { + // Nothing + } + } + + /// + /// A list view item that supports temporary highlighting. + /// + public class HighlightedListViewItem : ListViewItem + { + private HighlightingContext _context; + private Color _normalColor = SystemColors.Window; + private ListViewItemState _state = ListViewItemState.Normal; + + public HighlightedListViewItem(HighlightingContext context) + : this(context, true) + { } + + public HighlightedListViewItem(HighlightingContext context, bool highlight) + : this(context, "", highlight) + { } + + public HighlightedListViewItem(HighlightingContext context, string text) + : this(context, text, true) + { } + + public HighlightedListViewItem(HighlightingContext context, string text, bool highlight) + : base(text) + { + _context = context; + + if (HighlightingContext.StateHighlighting && highlight) + { + this.BackColor = HighlightingContext.Colors[ListViewItemState.New]; + this.ForeColor = PhUtils.GetForeColor(this.BackColor); + _state = ListViewItemState.New; + + _context.Enqueue(delegate + { + this.BackColor = _normalColor; + this.ForeColor = PhUtils.GetForeColor(this.BackColor); + _state = ListViewItemState.Normal; + }); + } + else + { + this.BackColor = _normalColor; + } + } + + public override void Remove() + { + if (HighlightingContext.StateHighlighting) + { + _context.EnqueuePre(delegate + { + this.BackColor = HighlightingContext.Colors[ListViewItemState.Removed]; + this.ForeColor = PhUtils.GetForeColor(this.BackColor); + + _context.Enqueue(delegate + { + this.BaseRemove(); + }); + }); + } + else + { + base.Remove(); + } + } + + private void BaseRemove() + { + base.Remove(); + } + + public Color NormalColor + { + get { return _normalColor; } + set + { + _normalColor = value; + + if (_state == ListViewItemState.Normal) + { + this.BackColor = value; + this.ForeColor = PhUtils.GetForeColor(this.BackColor); + } + } + } + + public void SetTemporaryState(ListViewItemState state) + { + _context.EnqueuePre(delegate + { + this.BackColor = HighlightingContext.Colors[state]; + this.ForeColor = PhUtils.GetForeColor(this.BackColor); + _state = state; + + _context.Enqueue(delegate + { + this.BackColor = _normalColor; + this.ForeColor = PhUtils.GetForeColor(this.BackColor); + _state = ListViewItemState.Normal; + }); + }); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/UI/Icons/CommitHistoryIcon.cs b/branches/ph-plugins/ProcessHacker/UI/Icons/CommitHistoryIcon.cs new file mode 100644 index 000000000..2ac304840 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/UI/Icons/CommitHistoryIcon.cs @@ -0,0 +1,53 @@ +/* + * Process Hacker - + * commit history icon + * + * Copyright (C) 2009 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 . + */ + +using System.Runtime.InteropServices; +using ProcessHacker.Common; +using ProcessHacker.Native.Api; + +namespace ProcessHacker +{ + public class CommitHistoryIcon : ProviderIcon + { + public CommitHistoryIcon() + { + this.UseSecondLine = false; + this.UseLongData = true; + + PerformanceInformation info = new PerformanceInformation(); + + info.Size = Marshal.SizeOf(info); + Win32.GetPerformanceInfo(out info, info.Size); + this.MinMaxValue = info.CommitLimit.ToInt64(); + } + + protected override void ProviderUpdated() + { + this.LineColor1 = Properties.Settings.Default.PlotterMemoryPrivateColor; + this.Update(this.Provider.Performance.CommittedPages, 0); + this.Redraw(); + + this.Text = "Commit: " + Utils.FormatSize( + (long)this.Provider.Performance.CommittedPages * this.Provider.System.PageSize); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/UI/Icons/CpuHistoryIcon.cs b/branches/ph-plugins/ProcessHacker/UI/Icons/CpuHistoryIcon.cs new file mode 100644 index 000000000..472c48a50 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/UI/Icons/CpuHistoryIcon.cs @@ -0,0 +1,53 @@ +/* + * Process Hacker - + * CPU history icon + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace ProcessHacker +{ + public class CpuHistoryIcon : ProviderIcon + { + public CpuHistoryIcon() + { + this.UseSecondLine = true; + } + + protected override void ProviderUpdated() + { + this.LineColor1 = Properties.Settings.Default.PlotterCPUKernelColor; + this.LineColor2 = Properties.Settings.Default.PlotterCPUUserColor; + this.Update(this.Provider.CurrentCpuKernelUsage, this.Provider.CurrentCpuUserUsage); + this.Redraw(); + + string text = "CPU Usage: " + (this.Provider.CurrentCpuUsage * 100).ToString("F2") + "%"; + + string mostCpuText = this.Provider.MostCpuHistory[0]; + + if (text.Length + mostCpuText.Length + 1 < 64) // 1 char for the LF + text += "\n" + mostCpuText; + + this.Text = text; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/UI/Icons/CpuUsageIcon.cs b/branches/ph-plugins/ProcessHacker/UI/Icons/CpuUsageIcon.cs new file mode 100644 index 000000000..5b7b12f95 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/UI/Icons/CpuUsageIcon.cs @@ -0,0 +1,123 @@ +/* + * Process Hacker - + * CPU usage icon + * + * Copyright (C) 2009 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 . + */ + +using System.Drawing; + +namespace ProcessHacker +{ + public class CpuUsageIcon : UsageIcon + { + private ProcessSystemProvider _provider = Program.ProcessProvider; + private bool _enabled = false; + + public CpuUsageIcon() + { } + + public override void Dispose() + { + this.Enabled = false; + base.Dispose(); + } + + private void ProcessProvider_Updated() + { + //this.Parent.BeginInvoke(new MethodInvoker(this.ProviderUpdated)); + this.ProviderUpdated(); + } + + public bool Enabled + { + get { return _enabled; } + set + { + if (value != _enabled) + { + if (value) + Program.ProcessProvider.Updated += ProcessProvider_Updated; + else + Program.ProcessProvider.Updated -= ProcessProvider_Updated; + } + + _enabled = value; + } + } + + private ProcessSystemProvider Provider + { + get { return Program.ProcessProvider; } + } + + private void ProviderUpdated() + { + float k = _provider.CurrentCpuKernelUsage; + float u = _provider.CurrentCpuUserUsage; + int height = this.Size.Height; + int width = this.Size.Width; + + using (Bitmap b = new Bitmap(width, height)) + { + using (Graphics g = Graphics.FromImage(b)) + { + int kl = (int)(k * height); + int ul = (int)(u * height); + Color kline = Properties.Settings.Default.PlotterCPUKernelColor; + Color kfill = Color.FromArgb(100, kline); + Color uline = Properties.Settings.Default.PlotterCPUUserColor; + Color ufill = Color.FromArgb(100, uline); + + g.FillRectangle(new SolidBrush(Color.Black), g.ClipBounds); + + if (kl + ul == 0) + g.DrawLine(new Pen(uline), 0, height - 1, width - 1, height - 1); + + g.FillRectangle(new SolidBrush(ufill), 0, height - (ul + kl), width, ul); + g.DrawLine(new Pen(uline), 0, height - (ul + kl) - 1, width, height - (ul + kl) - 1); + + if (kl > 0) + { + g.FillRectangle(new SolidBrush(kfill), 0, height - kl, width, kl); + g.DrawLine(new Pen(kline), 0, height - kl - 1, width, height - kl - 1); + } + } + + var newIcon = Icon.FromHandle(b.GetHicon()); + var oldIcon = this.Icon; + + this.Icon = newIcon; + ProcessHacker.Native.Api.Win32.DestroyIcon(oldIcon.Handle); + } + + string mostCpuProcess = _provider.MostCpuHistory[0]; + + string text = "CPU Usage: " + ((k + u) * 100).ToString("N2") + "%" + //+ " (" + + //"K: " + (k * 100).ToString("G2") + + //", U: " + (u * 100).ToString("G2") + ")" + ; + + if (text.Length + mostCpuProcess.Length + 1 < 64) + text += "\n" + mostCpuProcess; + + this.Text = text; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/UI/Icons/IoHistoryIcon.cs b/branches/ph-plugins/ProcessHacker/UI/Icons/IoHistoryIcon.cs new file mode 100644 index 000000000..5c308fb57 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/UI/Icons/IoHistoryIcon.cs @@ -0,0 +1,68 @@ +/* + * Process Hacker - + * I/O history icon + * + * Copyright (C) 2009 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 . + */ + +using ProcessHacker.Common; + +namespace ProcessHacker +{ + public class IoHistoryIcon : ProviderIcon + { + public IoHistoryIcon() + { + this.UseSecondLine = true; + this.UseLongData = true; + this.OverlaySecondLine = true; + this.MinMaxValue = 128 * 1024; // 128KB + } + + protected override void ProviderUpdated() + { + if (this.Provider.RunCount < 2) + return; + + this.LineColor1 = Properties.Settings.Default.PlotterIOROColor; + this.LineColor2 = Properties.Settings.Default.PlotterIOWColor; + + this.Update( + this.Provider.LongDeltas[SystemStats.IoRead] + + this.Provider.LongDeltas[SystemStats.IoOther], + this.Provider.LongDeltas[SystemStats.IoWrite] + ); + + this.Redraw(); + + string text = "R: " + Utils.FormatSize(this.Provider.LongDeltas[SystemStats.IoRead]) + + "\nW: " + Utils.FormatSize(this.Provider.LongDeltas[SystemStats.IoWrite]) + + "\nO: " + Utils.FormatSize(this.Provider.LongDeltas[SystemStats.IoOther]); + + if (this.Provider.Dictionary.ContainsKey(this.Provider.PIDWithMostIoActivity)) + { + string mostIoName = this.Provider.Dictionary[this.Provider.PIDWithMostIoActivity].Name; + + if (text.Length + mostIoName.Length + 1 < 64) // 1 char for the LF + text += "\n" + mostIoName; + } + + this.Text = text; + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/UI/Icons/PhysMemHistoryIcon.cs b/branches/ph-plugins/ProcessHacker/UI/Icons/PhysMemHistoryIcon.cs new file mode 100644 index 000000000..1bff8d98f --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/UI/Icons/PhysMemHistoryIcon.cs @@ -0,0 +1,54 @@ +/* + * Process Hacker - + * physical memory history icon + * + * Copyright (C) 2009 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 . + */ + +using System.Runtime.InteropServices; +using ProcessHacker.Common; +using ProcessHacker.Native.Api; + +namespace ProcessHacker +{ + public class PhysMemHistoryIcon : ProviderIcon + { + public PhysMemHistoryIcon() + { + this.UseSecondLine = false; + this.UseLongData = true; + + PerformanceInformation info = new PerformanceInformation(); + + info.Size = Marshal.SizeOf(info); + Win32.GetPerformanceInfo(out info, info.Size); + this.MinMaxValue = info.PhysicalTotal.ToInt64(); + } + + protected override void ProviderUpdated() + { + this.LineColor1 = Properties.Settings.Default.PlotterMemoryWSColor; + this.Update(this.MinMaxValue - this.Provider.Performance.AvailablePages, 0); + this.Redraw(); + + this.Text = "Physical Memory: " + Utils.FormatSize( + (long)(this.MinMaxValue - this.Provider.Performance.AvailablePages) * + this.Provider.System.PageSize); + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/UI/Icons/PlotterIcon.cs b/branches/ph-plugins/ProcessHacker/UI/Icons/PlotterIcon.cs new file mode 100644 index 000000000..7934fecca --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/UI/Icons/PlotterIcon.cs @@ -0,0 +1,137 @@ +/* + * Process Hacker - + * plotter icon + * + * Copyright (C) 2008-2009 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 . + */ + +using System.Drawing; +using System.Windows.Forms; // DO NOT REMOVE, needed in Debug mode +using ProcessHacker.Common; +using ProcessHacker.Components; + +namespace ProcessHacker +{ + public abstract class PlotterIcon : UsageIcon + { + private HistoryManager _floatHistory = new HistoryManager(); + private HistoryManager _longHistory = new HistoryManager(); + private Plotter _plotter; + + public PlotterIcon() + { + _floatHistory.Add(true); + _floatHistory.Add(false); + _longHistory.Add(true); + _longHistory.Add(false); + + _plotter = new Plotter() + { + Size = this.Size, + ShowGrid = false, + BackColor = Color.Black, + MoveStep = 2, + Data1 = _floatHistory[true], + Data2 = _floatHistory[false], + LongData1 = _longHistory[true], + LongData2 = _longHistory[false] + }; + } + + public override void Dispose() + { + _plotter.Dispose(); + base.Dispose(); + } + + protected void Update(float v1, float v2) + { + _floatHistory.Update(true, v1); + _floatHistory.Update(false, v2); + } + + protected void Update(long v1, long v2) + { + _longHistory.Update(true, v1); + _longHistory.Update(false, v2); + } + + public void Redraw() + { + Icon newIcon; + Icon oldIcon = this.Icon; + + using (Bitmap bm = new Bitmap(this.Size.Width, this.Size.Height)) + { + // Update the plotter size if our size has changed. + if (_plotter.Size != this.Size) + _plotter.Size = this.Size; + + using (Graphics g = Graphics.FromImage(bm)) + _plotter.Draw(g); + + newIcon = Icon.FromHandle(bm.GetHicon()); + } + + this.Icon = newIcon; + ProcessHacker.Native.Api.Win32.DestroyIcon(oldIcon.Handle); + } + + protected bool UseLongData + { + get { return _plotter.UseLongData; } + set { _plotter.UseLongData = value; } + } + + protected bool UseSecondLine + { + get { return _plotter.UseSecondLine; } + set { _plotter.UseSecondLine = value; } + } + + protected bool OverlaySecondLine + { + get { return _plotter.OverlaySecondLine; } + set { _plotter.OverlaySecondLine = value; } + } + + protected long MinMaxValue + { + get { return _plotter.MinMaxValue; } + set { _plotter.MinMaxValue = value; } + } + + protected Color BackColor + { + get { return _plotter.BackColor; } + set { _plotter.BackColor = value; } + } + + protected Color LineColor1 + { + get { return _plotter.LineColor1; } + set { _plotter.LineColor1 = value; } + } + + protected Color LineColor2 + { + get { return _plotter.LineColor2; } + set { _plotter.LineColor2 = value; } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/UI/Icons/ProviderIcon.cs b/branches/ph-plugins/ProcessHacker/UI/Icons/ProviderIcon.cs new file mode 100644 index 000000000..36c13861b --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/UI/Icons/ProviderIcon.cs @@ -0,0 +1,71 @@ +/* + * Process Hacker - + * provider-based plotter icon + * + * Copyright (C) 2009 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 . + */ + +using System.Windows.Forms; + +namespace ProcessHacker +{ + public class ProviderIcon : PlotterIcon + { + private bool _enabled = false; + + public ProviderIcon() + { } + + public override void Dispose() + { + this.Enabled = false; + base.Dispose(); + } + + private void ProcessProvider_Updated() + { + //this.Parent.BeginInvoke(new MethodInvoker(this.ProviderUpdated)); + this.ProviderUpdated(); + } + + public bool Enabled + { + get { return _enabled; } + set + { + if (value != _enabled) + { + if (value) + Program.ProcessProvider.Updated += ProcessProvider_Updated; + else + Program.ProcessProvider.Updated -= ProcessProvider_Updated; + } + + _enabled = value; + } + } + + protected ProcessSystemProvider Provider + { + get { return Program.ProcessProvider; } + } + + protected virtual void ProviderUpdated() + { } + } +} diff --git a/branches/ph-plugins/ProcessHacker/UI/Icons/UsageIcon.cs b/branches/ph-plugins/ProcessHacker/UI/Icons/UsageIcon.cs new file mode 100644 index 000000000..7c67d0a84 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/UI/Icons/UsageIcon.cs @@ -0,0 +1,152 @@ +/* + * Process Hacker - + * NotifyIcon wrapper + * + * Copyright (C) 2009 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 . + */ + +using System; +using System.Drawing; +using System.Windows.Forms; +using ProcessHacker.Native; +using ProcessHacker.Native.Api; + +namespace ProcessHacker +{ + public class UsageIcon : IDisposable + { + private static UsageIcon _activeUsageIcon; + + public static UsageIcon ActiveUsageIcon + { + get { return _activeUsageIcon; } + set + { + _activeUsageIcon = value; + + if (value == null) + { + if (OSVersion.HasExtendedTaskbar) + { + TaskbarLib.Windows7Taskbar.SetTaskbarOverlayIcon( + null, + "" + ); + } + } + } + } + + public static Size GetSmallIconSize() + { + return new Size( + Win32.GetSystemMetrics(49), // SM_CXSMICON + Win32.GetSystemMetrics(50) // SM_CYSMICON + ); + } + + public event MouseEventHandler MouseClick; + public event MouseEventHandler MouseDoubleClick; + + private Control _parent; + private Size _size; + private NotifyIcon _notifyIcon; + + public UsageIcon() + { + _notifyIcon = new NotifyIcon(); + + _notifyIcon.MouseClick += new MouseEventHandler(notifyIcon_MouseClick); + _notifyIcon.MouseDoubleClick += new MouseEventHandler(notifyIcon_MouseDoubleClick); + + _size = GetSmallIconSize(); + } + + public virtual void Dispose() + { + _notifyIcon.Dispose(); + } + + private void notifyIcon_MouseClick(object sender, MouseEventArgs e) + { + if (this.MouseClick != null) + this.MouseClick(sender, e); + } + + private void notifyIcon_MouseDoubleClick(object sender, MouseEventArgs e) + { + if (this.MouseDoubleClick != null) + this.MouseDoubleClick(sender, e); + } + + public void ShowBalloonTip(int timeout, string tipTitle, string tipText, ToolTipIcon tipIcon) + { + _notifyIcon.ShowBalloonTip(timeout, tipTitle, tipText, tipIcon); + } + + public Control Parent + { + get { return _parent; } + set { _parent = value; } + } + + public ContextMenu ContextMenu + { + get { return _notifyIcon.ContextMenu; } + set { _notifyIcon.ContextMenu = value; } + } + + public Icon Icon + { + get { return _notifyIcon.Icon; } + set + { + _notifyIcon.Icon = value; + + if (this == _activeUsageIcon) + { + if (OSVersion.HasExtendedTaskbar) + { + TaskbarLib.Windows7Taskbar.SetTaskbarOverlayIcon( + value, + "" + ); + } + } + } + } + + public bool Visible + { + get { return _notifyIcon.Visible; } + set { _notifyIcon.Visible = value; } + } + + public Size Size + { + get { return _size; } + set { _size = value; } + } + + protected string Text + { + get { return _notifyIcon.Text; } + set { _notifyIcon.Text = value; } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/UI/WindowFromHandle.cs b/branches/ph-plugins/ProcessHacker/UI/WindowFromHandle.cs new file mode 100644 index 000000000..424e3a9f9 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/UI/WindowFromHandle.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows.Forms; + +namespace ProcessHacker.UI +{ + public class WindowFromHandle : IWin32Window + { + private IntPtr _handle; + + public WindowFromHandle(IntPtr handle) + { + _handle = handle; + } + + public IntPtr Handle + { + get { return _handle; } + } + } +} diff --git a/branches/ph-plugins/ProcessHacker/app.config b/branches/ph-plugins/ProcessHacker/app.config new file mode 100644 index 000000000..8c285cbfb --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/app.config @@ -0,0 +1,441 @@ + + + + +
+ + + + + + 1000 + + + 844, 550 + + + 200, 200 + + + 355 + + + Normal + + + False + + + &String Scan... + + + False + + + True + + + + + + + + + 504, 482 + + + 0,115|1,80|2,70|3,188| + + + + + + 791, 503 + + + + + + tabGeneral + + + + + + + + + 481, 468 + + + 439, 413 + + + + + + + + + + + + + + + + + + + + + http://www.google.com/search?q=%s + + + Chartreuse + + + 255, 60, 40 + + + 255, 255, 170 + + + 255, 170, 0 + + + 170, 204, 255 + + + 1000 + + + False + + + 415, 503 + + + + + + False + + + False + + + False + + + True + + + False + + + False + + + True + + + 0,150|1,300|2,120|3,80|4,80|5,60| + + + + + + + + + 554, 463 + + + 204, 187, 255 + + + 204, 255, 255 + + + + + + + + + + + + tabPrivileges + + + False + + + 505, 512 + + + False + + + Lime + + + Red + + + Orange + + + Cyan + + + Yellow + + + DarkViolet + + + Peru + + + False + + + 6 + + + 222, 255, 0 + + + DeepPink + + + False + + + 0,137|1,160|2,71|3,195|4,75|5,80|6,70| + + + True + + + False + + + audiodg.exe, csrss.exe, dwm.exe, explorer.exe, logonui.exe, lsass.exe, lsm.exe, ntkrnlpa.exe, ntoskrnl.exe, procexp.exe, rundll32.exe, services.exe, smss.exe, spoolsv.exe, svchost.exe, taskeng.exe, taskmgr.exe, wininit.exe, winlogon.exe + + + Microsoft Sans Serif, 8.25pt + + + True + + + + + + 10 + + + False + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + True + + + False + + + + + + 300, 300 + + + 595, 508 + + + False + + + 858, 574 + + + 100, 100 + + + True + + + 600 + + + 2 + + + + + + Silver + + + True + + + 255, 255, 128 + + + True + + + dbghelp.dll + + + + + + True + + + False + + + Gray + + + True + + + 128, 255, 255 + + + True + + + 200, 200 + + + True + + + False + + + False + + + False + + + False + + + 200, 200 + + + 200, 200 + + + 527, 429 + + + True + + + False + + + 565, 377 + + + False + + + DarkSlateBlue + + + True + + + False + + + True + + + True + + + 255, 192, 128 + + + True + + + RosyBrown + + + True + + + 0 + + + http://processhacker.sourceforge.net/AppUpdate.xml + + + 1 + + + True + + + 1 + + + False + + + False + + + + + + + + + + + + + + + False + + + + \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/app.manifest b/branches/ph-plugins/ProcessHacker/app.manifest new file mode 100644 index 000000000..dc0cdf024 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/app.manifest @@ -0,0 +1,22 @@ + + + + + + + + + + + + diff --git a/branches/ph-plugins/ProcessHacker/base.txt b/branches/ph-plugins/ProcessHacker/base.txt new file mode 100644 index 000000000..524891f25 --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/base.txt @@ -0,0 +1,39 @@ +/* + * Base typedefs + */ + +typedef bool32 bool; +typedef bool8 boolean; /* used primarily by lower-level Windows components */ + +typedef charascii char; +typedef charutf16 wchar; + +typedef int8 sbyte; /* should be byte, actually */ +typedef uint8 byte; + +typedef int16 short; +typedef int16 word; +typedef uint16 ushort; + +typedef int32 int; +typedef int32 dword; +typedef int32 long; +typedef uint32 uint; +typedef uint32 ulong; + +typedef int64 large_integer; /* or LARGE_INTEGER */ +typedef int64 longlong; +typedef int64 qword; +typedef uint64 ulonglong; + +typedef single float; +/* typedef double double; */ /* double is already called double */ + +typedef stringascii str; +typedef stringascii string; +typedef stringutf16 wstr; +typedef stringutf16 wstring; + +typedef wstr* lpcwstr; /* "Long Pointer To Const Wide-Character String" */ +typedef wstr* lpctstr; /* most apps are in Unicode, so assume TCHAR = WCHAR */ +typedef str* lpcstr; /* ANSI */ \ No newline at end of file diff --git a/branches/ph-plugins/ProcessHacker/structs.txt b/branches/ph-plugins/ProcessHacker/structs.txt new file mode 100644 index 000000000..de5ac886a --- /dev/null +++ b/branches/ph-plugins/ProcessHacker/structs.txt @@ -0,0 +1,237 @@ +/* + * Process Hacker's Structs file - contains + * common structures used in Windows + * + * wj32. + */ + +include "base.txt"; + +typedef int handle; +typedef int NTSTATUS; /* no enum support *yet* */ +typedef pvoid ppvoid; + +/* A counted UTF-16 string. Same as LSA_UNICODE_STRING. */ +struct UNICODE_STRING +{ + ushort Length; + ushort MaximumLength; + wstr* Buffer[Length / 2]; /* Length is in bytes, and each wchar is 2 bytes */ +} + +/* A doubly-linked list. */ +struct LIST_ENTRY +{ + LIST_ENTRY* Flink; + LIST_ENTRY* Blink; +} + +struct CLIENT_ID +{ + pvoid UniqueProcess; + pvoid UniqueThread; +} + +struct RTL_DRIVE_LETTER_CURDIR +{ + ushort Flags; + ushort Length; + ulong TimeStamp; + UNICODE_STRING DosPath; +} + +/* Lots of useful stuff like current directory and command line */ +struct RTL_USER_PROCESS_PARAMETERS +{ + ulong MaximumLength; + ulong Length; + ulong Flags; + ulong DebugFlags; + pvoid ConsoleHandle; + ulong ConsoleFlags; + handle StdInputHandle; + handle StdOutputHandle; + handle StdErrorHandle; + UNICODE_STRING CurrentDirectoryPath; + handle CurrentDirectoryHandle; + UNICODE_STRING DllPath; + UNICODE_STRING ImagePathName; + UNICODE_STRING CommandLine; + pvoid Environment; + ulong StartingPositionLeft; + ulong StartingPositionTop; + ulong Width; + ulong Height; + ulong CharWidth; + ulong CharHeight; + ulong ConsoleTextAttributes; + ulong WindowFlags; + ulong ShowWindowFlags; + UNICODE_STRING WindowTitle; + UNICODE_STRING DesktopName; + UNICODE_STRING ShellInfo; + UNICODE_STRING RuntimeData; + RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20]; +} + +/* Module information for the process */ +struct PEB_LDR_DATA +{ + ulong Length; + boolean Initialized; + pvoid SsHandle; + LIST_ENTRY InLoadOrderModuleList; + LIST_ENTRY InMemoryOrderModuleList; + LIST_ENTRY InInitializationOrderModuleList; +} + +/* Contains the address of a fast-locking routine for the PEB */ +struct PEBLOCKROUTINE +{ + pvoid PebLock; +} + +/* Process Environment Block */ +struct PEB +{ + /* +0x00 */ boolean InheritedAddressSpace; + /* +0x01 */ boolean ReadImageFileExecOptions; + /* +0x02 */ boolean BeingDebugged; + /* +0x03 */ boolean Spare; + /* +0x04 */ handle Mutant; + /* +0x08 */ pvoid ImageBaseAddress; + /* PEB_LDR_DATA* LoaderData; */ + /* +0x0c */ pvoid LoaderData; + /* +0x10 */ RTL_USER_PROCESS_PARAMETERS* ProcessParameters; + /* +0x14 */ pvoid SubSystemData; + /* +0x18 */ pvoid ProcessHeap; + /* +0x1c */ pvoid FastPebLock; + /* +0x20 */ PEBLOCKROUTINE* FastPebLockRoutine; + /* +0x24 */ PEBLOCKROUTINE* FastPebUnlockRoutine; + /* +0x28 */ ulong EnvironmentUpdateCount; + /* +0x2c */ ppvoid KernelCallbackTable; + /* +0x30 */ pvoid EventLogSection; + /* +0x34 */ pvoid EventLog; + /* +0x38 */ pvoid FreeList; /* should be PEB_FREE_BLOCK* */ + /* +0x3c */ ulong TlsExpansionCounter; + /* +0x40 */ pvoid TlsBitmap; + /* +0x44 */ ulong TlsBitmapBits[0x2]; + /* +0x4c */ pvoid ReadOnlySharedMemoryBase; + /* +0x50 */ pvoid ReadOnlySharedMemoryHeap; + /* +0x54 */ ppvoid ReadOnlyStaticServerData; + /* +0x58 */ pvoid AnsiCodePageData; + /* +0x5c */ pvoid OemCodePageData; + /* +0x60 */ pvoid UnicodeCaseTableData; + /* +0x64 */ ulong NumberOfProcessors; + /* +0x68 */ ulong NtGlobalFlag; + /* +0x6c */ byte Spare2[0x4]; + /* +0x70 */ large_integer CriticalSectionTimeout; + /* +0x78 */ ulong HeapSegmentReserve; + /* +0x7c */ ulong HeapSegmentCommit; + /* +0x80 */ ulong HeapDeCommitTotalFreeThreshold; + /* +0x84 */ ulong HeapDeCommitFreeBlockThreshold; + /* +0x88 */ ulong NumberOfHeaps; + /* +0x8c */ ulong MaximumNumberOfHeaps; + /* +0x90 */ ppvoid ProcessHeaps; + /* +0x94 */ pvoid GdiSharedHandleTable; + /* +0x98 */ pvoid ProcessStarterHelper; + /* +0x9c */ pvoid GdiDCAttributeList; + /* +0xa0 */ pvoid LoaderLock; + /* +0xa4 */ ulong OSMajorVersion; + /* +0xa8 */ ulong OSMinorVersion; + /* +0xac */ ushort OSBuildNumber; + /* +0xae */ ushort OSCSDVersion; + /* +0xb0 */ ulong OSPlatformId; + /* +0xb4 */ ulong ImageSubSystem; + ulong ImageSubSystemMajorVersion; + ulong ImageSubSystemMinorVersion; + ulong ImageProcessAffinityMask; + ulong GdiHandleBuffer[0x22]; + ulong PostProcessInitRoutine; + ulong TlsExpansionBitmap; + byte TlsExpansionBitmapBits[0x80]; + ulong SessionId; + large_integer AppCompatFlags; + large_integer AppCompatFlagsUser; + pvoid pShimData; + pvoid AppCompatInfo; + UNICODE_STRING CSDVersion; + pvoid ActivationContextData; + pvoid ProcessAssemblyStorageMap; + pvoid SystemDefaultActivationContextData; + pvoid SystemAssemblyStorageMap; + ulong MinimumStackCommit; +} + +struct NT_TIB +{ + pvoid ExceptionList; /* EXCEPTION_REGISTRATION_RECORD* */ + pvoid StackBase; + pvoid StackLimit; + pvoid SubSystemTib; + ulong FiberData_Version_Union; + pvoid ArbitraryUserPointer; + pvoid Self; /* NT_TIB* */ +} + +/* Thread Environment Block */ +struct TEB +{ + NT_TIB Tib; + pvoid EnvironmentPointer; + CLIENT_ID Cid; + pvoid ActiveRpcInfo; + pvoid ThreadLocalStoragePointer; + PEB* Peb; + ulong LastErrorValue; + ulong CountOfOwnedCriticalSections; + pvoid CsrClientThread; + pvoid Win32ThreadInfo; + ulong Win32ClientInfo[0x1f]; + pvoid WOW32Reserved; + ulong CurrentLocale; + ulong FpSoftwareStatusRegister; + pvoid SystemReserved1[0x36]; + pvoid Spare1; + ulong ExceptionCode; + ulong SpareBytes1[0x28]; + pvoid SystemReserved2[0xa]; + ulong GdiRgn; + ulong GdiPen; + ulong GdiBrush; + CLIENT_ID RealClientId; + pvoid GdiCachedProcessHandle; + ulong GdiClientPID; + ulong GdiClientTID; + pvoid GdiThreadLocaleInfo; + pvoid UserReserved[5]; + pvoid GlDispatchTable[0x118]; + ulong GlReserved1[0x1a]; + pvoid GlReserved2; + pvoid GlSectionInfo; + pvoid GlSection; + pvoid GlTable; + pvoid GlCurrentRC; + pvoid GlContext; + NTSTATUS LastStatusValue; + UNICODE_STRING StaticUnicodeString; + wchar StaticUnicodeBuffer[0x105]; + pvoid DeallocationStack; + pvoid TlsSlots[0x40]; + LIST_ENTRY TlsLinks; + pvoid Vdm; + pvoid ReservedForNtRpc; + pvoid DbgSsReserved[0x2]; + ulong HardErrorDisabled; + pvoid Instrumentation[0x10]; + pvoid WinSockData; + ulong GdiBatchCount; + ulong Spare2; + ulong Spare3; + ulong Spare4; + pvoid ReservedForOle; + ulong WaitingOnLoaderLock; + pvoid StackCommit; + pvoid StackCommitMax; + pvoid StackReserved; +} diff --git a/branches/ph-plugins/README.txt b/branches/ph-plugins/README.txt new file mode 100644 index 000000000..8b4e01a01 --- /dev/null +++ b/branches/ph-plugins/README.txt @@ -0,0 +1,43 @@ +Process Hacker is a tool for viewing and manipulating processes. +Its most basic functionality includes: + + * Viewing, terminating, suspending and resuming processes + * Restarting processes, creating dump files, detaching from + any debuggers, viewing heaps, injecting DLLs, etc. + * Viewing detailed process information, statistics, and + performance information + * Viewing, terminating, suspending and resuming threads + * Viewing detailed token information (including modifying + privileges) + * Viewing and unloading modules + * Viewing memory regions + * Viewing environment variables + * Viewing and closing handles + * Viewing, controlling and editing services + * Viewing and closing network connections + +Process Hacker runs on both 32-bit and 64-bit Windows, but +certain functionality is only available on 32-bit systems, +including: + + * Bypassing rootkits and security software when accessing + processes, threads, and other objects + * Viewing kernel pool limits + * Viewing hidden processes + * Changing handle attributes + * Viewing kernel-mode stack traces + +Process Hacker has an embedded help file (accessible through +Hacker > Help). + +Process Hacker is brought to you by the Process Hacker team: + * wj32 (Project Manager) + * dmex (Developer) + * XhmikosR (Installer Developer, Tester) +Inactive: + * Dean (Developer) + * Fliser (Developer) + * Mikalai Chaly (Developer) + * Uday Shanbhag (Developer) + +See http://processhacker.sourceforge.net for more details. \ No newline at end of file diff --git a/branches/ph-plugins/TreeViewAdv/Aga.Controls.csproj b/branches/ph-plugins/TreeViewAdv/Aga.Controls.csproj new file mode 100644 index 000000000..eb4a139f9 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Aga.Controls.csproj @@ -0,0 +1,258 @@ + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {E73BB233-D88B-44A7-A98F-D71EE158381D} + Library + Properties + Aga.Controls + Aga.Controls + + + + + + + + + false + key.snk + + + 2.0 + v2.0 + + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + + + true + full + false + bin\Debug\ + TRACE;DEBUG;PERF_TEST + prompt + 4 + -Microsoft.Design#CA1020;-Microsoft.Design#CA1060;-Microsoft.Design#CA1062;-Microsoft.Globalization#CA1301;-Microsoft.Globalization#CA1302;-Microsoft.Globalization#CA1303;-Microsoft.Globalization#CA1306;-Microsoft.Globalization#CA1304;-Microsoft.Globalization#CA1305;-Microsoft.Globalization#CA1300;-Microsoft.Maintainability#CA1501;-Microsoft.Mobility#CA1601;-Microsoft.Performance#CA1805;-Microsoft.Performance#CA1815;-Microsoft.Performance#CA1819;-Microsoft.Usage#CA2208 + true + AnyCPU + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + true + AnyCPU + + + + + + + + + + + + + + + True + True + Resources.resx + + + + + + + + + Component + + + Component + + + Component + + + Component + + + Component + + + + + + + + + + Component + + + Component + + + + + + + Component + + + + + Component + + + + + + Component + + + Component + + + Component + + + + + + + Component + + + + + + + + + + + + + + Component + + + + Component + + + Component + + + Component + + + + + Component + + + Component + + + + Component + + + + + + Component + + + TreeViewAdv.cs + + + + + + + + + + + + + + + + + Designer + ResXFileCodeGenerator + Resources.Designer.cs + + + TreeViewAdv.cs + + + + + + + + + + + + + + + False + .NET Framework 2.0 %28AnyCPU%29 + false + + + False + .NET Framework 3.0 %28AnyCPU%29 + false + + + False + .NET Framework 3.5 + true + + + False + Windows Installer 3.1 + true + + + + + \ No newline at end of file diff --git a/branches/ph-plugins/TreeViewAdv/BitmapHelper.cs b/branches/ph-plugins/TreeViewAdv/BitmapHelper.cs new file mode 100644 index 000000000..3237db260 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/BitmapHelper.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Drawing.Imaging; + +namespace Aga.Controls +{ + public static class BitmapHelper + { + [StructLayout(LayoutKind.Sequential)] + private struct PixelData + { + public byte B; + public byte G; + public byte R; + public byte A; + } + + public static void SetAlphaChanelValue(Bitmap image, byte value) + { + if (image == null) + throw new ArgumentNullException("image"); + if (image.PixelFormat != PixelFormat.Format32bppArgb) + throw new ArgumentException("Wrong PixelFormat"); + + BitmapData bitmapData = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), + ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); + unsafe + { + PixelData* pPixel = (PixelData*)bitmapData.Scan0; + for (int i = 0; i < bitmapData.Height; i++) + { + for (int j = 0; j < bitmapData.Width; j++) + { + pPixel->A = value; + pPixel++; + } + pPixel += bitmapData.Stride - (bitmapData.Width * 4); + } + } + image.UnlockBits(bitmapData); + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/GifDecoder.cs b/branches/ph-plugins/TreeViewAdv/GifDecoder.cs new file mode 100644 index 000000000..838d79806 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/GifDecoder.cs @@ -0,0 +1,864 @@ +#region Java Info +/** + * Class GifDecoder - Decodes a GIF file into one or more frames. + *
+ * Example:
+ *    GifDecoder d = new GifDecoder();
+ *    d.read("sample.gif");
+ *    int n = d.getFrameCount();
+ *    for (int i = 0; i < n; i++) {
+ *       BufferedImage frame = d.getFrame(i);  // frame i
+ *       int t = d.getDelay(i);  // display duration of frame in milliseconds
+ *       // do something with frame
+ *    }
+ * 
+ * No copyright asserted on the source code of this class. May be used for + * any purpose, however, refer to the Unisys LZW patent for any additional + * restrictions. Please forward any corrections to kweiner@fmsware.com. + * + * @author Kevin Weiner, FM Software; LZW decoder adapted from John Cristy's ImageMagick. + * @version 1.03 November 2003 + * + */ +#endregion + +#pragma warning disable 0675 + +using System; +using System.Collections; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; + +namespace Aga.Controls +{ + public class GifFrame + { + private Image _image; + public Image Image + { + get { return _image; } + } + + private int _delay; + public int Delay + { + get { return _delay; } + } + + public GifFrame(Image im, int del) + { + _image = im; + _delay = del; + } + } + + public class GifDecoder + { + public const int StatusOK = 0;//File read status: No errors. + public const int StatusFormatError = 1; //File read status: Error decoding file (may be partially decoded) + public const int StatusOpenError = 2; //Unable to open source. + + private Stream inStream; + private int status; + + private int width; // full image width + private int height; // full image height + private bool gctFlag; // global color table used + private int gctSize; // size of global color table + private int loopCount = 1; // iterations; 0 = repeat forever + + private int[] gct; // global color table + private int[] lct; // local color table + private int[] act; // active color table + + private int bgIndex; // background color index + private int bgColor; // background color + private int lastBgColor; // previous bg color + private int pixelAspect; // pixel aspect ratio + + private bool lctFlag; // local color table flag + private bool interlace; // interlace flag + private int lctSize; // local color table size + + private int ix, iy, iw, ih; // current image rectangle + private Rectangle lastRect; // last image rect + private Image image; // current frame + private Bitmap bitmap; + private Image lastImage; // previous frame + + private byte[] block = new byte[256]; // current data block + private int blockSize = 0; // block size + + // last graphic control extension info + private int dispose = 0; + // 0=no action; 1=leave in place; 2=restore to bg; 3=restore to prev + private int lastDispose = 0; + private bool transparency = false; // use transparent color + private int delay = 0; // delay in milliseconds + private int transIndex; // transparent color index + + private const int MaxStackSize = 4096; + // max decoder pixel stack size + + // LZW decoder working arrays + private short[] prefix; + private byte[] suffix; + private byte[] pixelStack; + private byte[] pixels; + + private ArrayList frames; // frames read from current file + private int frameCount; + private bool _makeTransparent; + + /** + * Gets the number of frames read from file. + * @return frame count + */ + public int FrameCount + { + get + { + return frameCount; + } + } + + /** + * Gets the first (or only) image read. + * + * @return BufferedImage containing first frame, or null if none. + */ + public Image Image + { + get + { + return GetFrame(0).Image; + } + } + + /** + * Gets the "Netscape" iteration count, if any. + * A count of 0 means repeat indefinitiely. + * + * @return iteration count if one was specified, else 1. + */ + public int LoopCount + { + get + { + return loopCount; + } + } + + public GifDecoder(Stream stream, bool makeTransparent) + { + _makeTransparent = makeTransparent; + if (Read(stream) != 0) + throw new InvalidOperationException(); + } + + /** + * Creates new frame image from current data (and previous + * frames as specified by their disposition codes). + */ + private int[] GetPixels(Bitmap bitmap) + { + int [] pixels = new int [ 3 * image.Width * image.Height ]; + int count = 0; + for (int th = 0; th < image.Height; th++) + { + for (int tw = 0; tw < image.Width; tw++) + { + Color color = bitmap.GetPixel(tw, th); + pixels[count] = color.R; + count++; + pixels[count] = color.G; + count++; + pixels[count] = color.B; + count++; + } + } + return pixels; + } + + private void SetPixels(int[] pixels) + { + int count = 0; + for (int th = 0; th < image.Height; th++) + { + for (int tw = 0; tw < image.Width; tw++) + { + Color color = Color.FromArgb( pixels[count++] ); + bitmap.SetPixel( tw, th, color ); + } + } + if (_makeTransparent) + bitmap.MakeTransparent(bitmap.GetPixel(0, 0)); + } + + private void SetPixels() + { + // expose destination image's pixels as int array + // int[] dest = + // (( int ) image.getRaster().getDataBuffer()).getData(); + int[] dest = GetPixels( bitmap ); + + // fill in starting image contents based on last image's dispose code + if (lastDispose > 0) + { + if (lastDispose == 3) + { + // use image before last + int n = frameCount - 2; + if (n > 0) + { + lastImage = GetFrame(n - 1).Image; + } + else + { + lastImage = null; + } + } + + if (lastImage != null) + { + // int[] prev = + // ((DataBufferInt) lastImage.getRaster().getDataBuffer()).getData(); + int[] prev = GetPixels( new Bitmap( lastImage ) ); + Array.Copy(prev, 0, dest, 0, width * height); + // copy pixels + + if (lastDispose == 2) + { + // fill last image rect area with background color + Graphics g = Graphics.FromImage( image ); + Color c = Color.Empty; + if (transparency) + { + c = Color.FromArgb( 0, 0, 0, 0 ); // assume background is transparent + } + else + { + c = Color.FromArgb( lastBgColor ) ; + // c = new Color(lastBgColor); // use given background color + } + Brush brush = new SolidBrush( c ); + g.FillRectangle( brush, lastRect ); + brush.Dispose(); + g.Dispose(); + } + } + } + + // copy each source line to the appropriate place in the destination + int pass = 1; + int inc = 8; + int iline = 0; + for (int i = 0; i < ih; i++) + { + int line = i; + if (interlace) + { + if (iline >= ih) + { + pass++; + switch (pass) + { + case 2 : + iline = 4; + break; + case 3 : + iline = 2; + inc = 4; + break; + case 4 : + iline = 1; + inc = 2; + break; + } + } + line = iline; + iline += inc; + } + line += iy; + if (line < height) + { + int k = line * width; + int dx = k + ix; // start of line in dest + int dlim = dx + iw; // end of dest line + if ((k + width) < dlim) + { + dlim = k + width; // past dest edge + } + int sx = i * iw; // start of line in source + while (dx < dlim) + { + // map color and insert in destination + int index = ((int) pixels[sx++]) & 0xff; + int c = act[index]; + if (c != 0) + { + dest[dx] = c; + } + dx++; + } + } + } + SetPixels( dest ); + } + + /** + * Gets the image contents of frame n. + * + * @return BufferedImage representation of frame. + */ + public GifFrame GetFrame(int n) + { + if ((n >= 0) && (n < frameCount)) + return (GifFrame)frames[n]; + else + throw new ArgumentOutOfRangeException(); + } + + /** + * Gets image size. + * + * @return GIF image dimensions + */ + public Size FrameSize + { + get + { + return new Size(width, height); + } + } + + /** + * Reads GIF image from stream + * + * @param BufferedInputStream containing GIF file. + * @return read status code (0 = no errors) + */ + private int Read( Stream inStream ) + { + Init(); + if ( inStream != null) + { + this.inStream = inStream; + ReadHeader(); + if (!Error()) + { + ReadContents(); + if (frameCount < 0) + { + status = StatusFormatError; + } + } + inStream.Close(); + } + else + { + status = StatusOpenError; + } + return status; + } + + + /** + * Decodes LZW image data into pixel array. + * Adapted from John Cristy's ImageMagick. + */ + private void DecodeImageData() + { + int NullCode = -1; + int npix = iw * ih; + int available, + clear, + code_mask, + code_size, + end_of_information, + in_code, + old_code, + bits, + code, + count, + i, + datum, + data_size, + first, + top, + bi, + pi; + + if ((pixels == null) || (pixels.Length < npix)) + { + pixels = new byte[npix]; // allocate new pixel array + } + if (prefix == null) prefix = new short[MaxStackSize]; + if (suffix == null) suffix = new byte[MaxStackSize]; + if (pixelStack == null) pixelStack = new byte[MaxStackSize + 1]; + + // Initialize GIF data stream decoder. + + data_size = Read(); + clear = 1 << data_size; + end_of_information = clear + 1; + available = clear + 2; + old_code = NullCode; + code_size = data_size + 1; + code_mask = (1 << code_size) - 1; + for (code = 0; code < clear; code++) + { + prefix[code] = 0; + suffix[code] = (byte) code; + } + + // Decode GIF pixel stream. + + datum = bits = count = first = top = pi = bi = 0; + + for (i = 0; i < npix;) + { + if (top == 0) + { + if (bits < code_size) + { + // Load bytes until there are enough bits for a code. + if (count == 0) + { + // Read a new data block. + count = ReadBlock(); + if (count <= 0) + break; + bi = 0; + } + datum += (((int) block[bi]) & 0xff) << bits; + bits += 8; + bi++; + count--; + continue; + } + + // Get the next code. + + code = datum & code_mask; + datum >>= code_size; + bits -= code_size; + + // Interpret the code + + if ((code > available) || (code == end_of_information)) + break; + if (code == clear) + { + // Reset decoder. + code_size = data_size + 1; + code_mask = (1 << code_size) - 1; + available = clear + 2; + old_code = NullCode; + continue; + } + if (old_code == NullCode) + { + pixelStack[top++] = suffix[code]; + old_code = code; + first = code; + continue; + } + in_code = code; + if (code == available) + { + pixelStack[top++] = (byte) first; + code = old_code; + } + while (code > clear) + { + pixelStack[top++] = suffix[code]; + code = prefix[code]; + } + first = ((int) suffix[code]) & 0xff; + + // Add a new string to the string table, + + if (available >= MaxStackSize) + break; + pixelStack[top++] = (byte) first; + prefix[available] = (short) old_code; + suffix[available] = (byte) first; + available++; + if (((available & code_mask) == 0) + && (available < MaxStackSize)) + { + code_size++; + code_mask += available; + } + old_code = in_code; + } + + // Pop a pixel off the pixel stack. + + top--; + pixels[pi++] = pixelStack[top]; + i++; + } + + for (i = pi; i < npix; i++) + { + pixels[i] = 0; // clear missing pixels + } + + } + + /** + * Returns true if an error was encountered during reading/decoding + */ + private bool Error() + { + return status != StatusOK; + } + + /** + * Initializes or re-initializes reader + */ + private void Init() + { + status = StatusOK; + frameCount = 0; + frames = new ArrayList(); + gct = null; + lct = null; + } + + /** + * Reads a single byte from the input stream. + */ + private int Read() + { + int curByte = 0; + try + { + curByte = inStream.ReadByte(); + } + catch (IOException) + { + status = StatusFormatError; + } + return curByte; + } + + /** + * Reads next variable length block from input. + * + * @return number of bytes stored in "buffer" + */ + private int ReadBlock() + { + blockSize = Read(); + int n = 0; + if (blockSize > 0) + { + try + { + int count = 0; + while (n < blockSize) + { + count = inStream.Read(block, n, blockSize - n); + if (count == -1) + break; + n += count; + } + } + catch (IOException) + { + } + + if (n < blockSize) + { + status = StatusFormatError; + } + } + return n; + } + + /** + * Reads color table as 256 RGB integer values + * + * @param ncolors int number of colors to read + * @return int array containing 256 colors (packed ARGB with full alpha) + */ + private int[] ReadColorTable(int ncolors) + { + int nbytes = 3 * ncolors; + int[] tab = null; + byte[] c = new byte[nbytes]; + int n = 0; + try + { + n = inStream.Read(c, 0, c.Length ); + } + catch (IOException) + { + } + if (n < nbytes) + { + status = StatusFormatError; + } + else + { + tab = new int[256]; // max size to avoid bounds checks + int i = 0; + int j = 0; + while (i < ncolors) + { + int r = ((int) c[j++]) & 0xff; + int g = ((int) c[j++]) & 0xff; + int b = ((int) c[j++]) & 0xff; + tab[i++] = ( int ) ( 0xff000000 | (r << 16) | (g << 8) | b ); + } + } + return tab; + } + + /** + * Main file parser. Reads GIF content blocks. + */ + private void ReadContents() + { + // read GIF file content blocks + bool done = false; + while (!(done || Error())) + { + int code = Read(); + switch (code) + { + + case 0x2C : // image separator + ReadImage(); + break; + + case 0x21 : // extension + code = Read(); + switch (code) + { + case 0xf9 : // graphics control extension + ReadGraphicControlExt(); + break; + + case 0xff : // application extension + ReadBlock(); + String app = ""; + for (int i = 0; i < 11; i++) + { + app += (char) block[i]; + } + if (app.Equals("NETSCAPE2.0")) + { + ReadNetscapeExt(); + } + else + Skip(); // don't care + break; + + default : // uninteresting extension + Skip(); + break; + } + break; + + case 0x3b : // terminator + done = true; + break; + + case 0x00 : // bad byte, but keep going and see what happens + break; + + default : + status = StatusFormatError; + break; + } + } + } + + /** + * Reads Graphics Control Extension values + */ + private void ReadGraphicControlExt() + { + Read(); // block size + int packed = Read(); // packed fields + dispose = (packed & 0x1c) >> 2; // disposal method + if (dispose == 0) + { + dispose = 1; // elect to keep old image if discretionary + } + transparency = (packed & 1) != 0; + delay = ReadShort() * 10; // delay in milliseconds + transIndex = Read(); // transparent color index + Read(); // block terminator + } + + /** + * Reads GIF file header information. + */ + private void ReadHeader() + { + String id = ""; + for (int i = 0; i < 6; i++) + { + id += (char) Read(); + } + if (!id.StartsWith("GIF")) + { + status = StatusFormatError; + return; + } + + ReadLSD(); + if (gctFlag && !Error()) + { + gct = ReadColorTable(gctSize); + bgColor = gct[bgIndex]; + } + } + + /** + * Reads next frame image + */ + private void ReadImage() + { + ix = ReadShort(); // (sub)image position & size + iy = ReadShort(); + iw = ReadShort(); + ih = ReadShort(); + + int packed = Read(); + lctFlag = (packed & 0x80) != 0; // 1 - local color table flag + interlace = (packed & 0x40) != 0; // 2 - interlace flag + // 3 - sort flag + // 4-5 - reserved + lctSize = 2 << (packed & 7); // 6-8 - local color table size + + if (lctFlag) + { + lct = ReadColorTable(lctSize); // read table + act = lct; // make local table active + } + else + { + act = gct; // make global table active + if (bgIndex == transIndex) + bgColor = 0; + } + int save = 0; + if (transparency) + { + save = act[transIndex]; + act[transIndex] = 0; // set transparent color if specified + } + + if (act == null) + { + status = StatusFormatError; // no color table defined + } + + if (Error()) return; + + DecodeImageData(); // decode pixel data + Skip(); + + if (Error()) return; + + frameCount++; + + // create new image to receive frame data + // image = + // new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE); + + bitmap = new Bitmap( width, height ); + image = bitmap; + SetPixels(); // transfer pixel data to image + + frames.Add(new GifFrame(bitmap, delay)); // add image to frame list + + if (transparency) + { + act[transIndex] = save; + } + ResetFrame(); + + } + + /** + * Reads Logical Screen Descriptor + */ + private void ReadLSD() + { + + // logical screen size + width = ReadShort(); + height = ReadShort(); + + // packed fields + int packed = Read(); + gctFlag = (packed & 0x80) != 0; // 1 : global color table flag + // 2-4 : color resolution + // 5 : gct sort flag + gctSize = 2 << (packed & 7); // 6-8 : gct size + + bgIndex = Read(); // background color index + pixelAspect = Read(); // pixel aspect ratio + } + + /** + * Reads Netscape extenstion to obtain iteration count + */ + private void ReadNetscapeExt() + { + do + { + ReadBlock(); + if (block[0] == 1) + { + // loop count sub-block + int b1 = ((int) block[1]) & 0xff; + int b2 = ((int) block[2]) & 0xff; + loopCount = (b2 << 8) | b1; + } + } while ((blockSize > 0) && !Error()); + } + + /** + * Reads next 16-bit value, LSB first + */ + private int ReadShort() + { + // read 16-bit value, LSB first + return Read() | (Read() << 8); + } + + /** + * Resets frame state for reading next image. + */ + private void ResetFrame() + { + lastDispose = dispose; + lastRect = new Rectangle(ix, iy, iw, ih); + lastImage = image; + lastBgColor = bgColor; + // int dispose = 0; + lct = null; + } + + /** + * Skips variable length blocks up to and including + * next zero length block. + */ + private void Skip() + { + do + { + ReadBlock(); + } while ((blockSize > 0) && !Error()); + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/NumericTextBox.cs b/branches/ph-plugins/TreeViewAdv/NumericTextBox.cs new file mode 100644 index 000000000..ee1ee0650 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/NumericTextBox.cs @@ -0,0 +1,189 @@ +using System; +using System.ComponentModel; +using System.Windows.Forms; +using System.Globalization; + + +namespace Aga.Controls +{ + /// + /// Restricts the entry of characters to digits, the negative sign, + /// the decimal point, and editing keystrokes (backspace). + /// It does not handle the AltGr key so any keys that can be created in any + /// combination with AltGr these are not filtered + /// + public class NumericTextBox : TextBox + { + private const int WM_PASTE = 0x302; + private NumberStyles numberStyle = NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign; + + /// + /// Restricts the entry of characters to digits, the negative sign, + /// the decimal point, and editing keystrokes (backspace). + /// It does not handle the AltGr key + /// + /// + protected override void OnKeyPress(KeyPressEventArgs e) + { + base.OnKeyPress(e); + + e.Handled = invalidNumeric(e.KeyChar); + } + + + /// + /// Main method for verifying allowed keypresses. + /// This does not catch cut paste copy ... operations. + /// + /// + /// + private bool invalidNumeric(char key) + { + bool handled = false; + + NumberFormatInfo numberFormatInfo = CultureInfo.CurrentCulture.NumberFormat; + string decimalSeparator = numberFormatInfo.NumberDecimalSeparator; + string negativeSign = numberFormatInfo.NegativeSign; + + string keyString = key.ToString(); + + if (Char.IsDigit(key)) + { + // Digits are OK + } + else if (AllowDecimalSeperator && keyString.Equals(decimalSeparator)) + { + if (Text.IndexOf(decimalSeparator) >= 0) + { + handled = true; + } + } + else if (AllowNegativeSign && keyString.Equals(negativeSign)) + { + if (Text.IndexOf(negativeSign) >= 0) + { + handled = true; + } + } + else if (key == '\b') + { + // Backspace key is OK + } + else if ((ModifierKeys & (Keys.Control)) != 0) + { + // Let the edit control handle control and alt key combinations + } + else + { + // Swallow this invalid key and beep + handled = true; + } + return handled; + } + + + /// + /// Method invoked when Windows sends a message. + /// + /// Message from Windows. + /// + /// This is over-ridden so that the user can not use + /// cut or paste operations to bypass the TextChanging event. + /// This catches ContextMenu Paste, Shift+Insert, Ctrl+V, + /// While it is generally frowned upon to override WndProc, no + /// other simple mechanism was apparent to simultaneously and + /// transparently intercept so many different operations. + /// + protected override void WndProc(ref Message m) + { + // Switch to handle message... + switch (m.Msg) + { + case WM_PASTE: + { + // Get clipboard object to paste + IDataObject clipboardData = Clipboard.GetDataObject(); + + // Get text from clipboard data + string pasteText = (string)clipboardData.GetData( + DataFormats.UnicodeText); + + // Get the number of characters to replace + int selectionLength = SelectionLength; + + // If no replacement or insertion, we are done + if (pasteText.Length == 0) + { + break; + } + else if (selectionLength != 0) + { + base.Text = base.Text.Remove(SelectionStart, selectionLength); + } + + bool containsInvalidChars = false; + foreach (char c in pasteText) + { + if (containsInvalidChars) + { + break; + } + else if (invalidNumeric(c)) + { + containsInvalidChars = true; + } + } + + if (!containsInvalidChars) + { + base.Text = base.Text.Insert(SelectionStart, pasteText); + } + + return; + } + + } + base.WndProc(ref m); + } + + + public int IntValue + { + get + { + int intValue; + Int32.TryParse(this.Text, numberStyle, CultureInfo.CurrentCulture.NumberFormat, out intValue); + return intValue; + } + } + + public decimal DecimalValue + { + get + { + decimal decimalValue; + Decimal.TryParse(this.Text, numberStyle, CultureInfo.CurrentCulture.NumberFormat, out decimalValue); + return decimalValue; + } + } + + + private bool allowNegativeSign; + [DefaultValue(true)] + public bool AllowNegativeSign + { + get { return allowNegativeSign; } + set { allowNegativeSign = value; } + } + + private bool allowDecimalSeperator; + [DefaultValue(true)] + public bool AllowDecimalSeperator + { + get { return allowDecimalSeperator; } + set { allowDecimalSeperator = value; } + } + + } + +} diff --git a/branches/ph-plugins/TreeViewAdv/Properties/AssemblyInfo.cs b/branches/ph-plugins/TreeViewAdv/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..23c410313 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Properties/AssemblyInfo.cs @@ -0,0 +1,15 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System; +using System.Security.Permissions; + +[assembly: ComVisible(false)] +[assembly: CLSCompliant(false)] +[assembly: SecurityPermission(SecurityAction.RequestMinimum, Execution = true)] + +[assembly: AssemblyTitle("Aga.Controls")] +[assembly: AssemblyCopyright("Copyright © Andrey Gliznetsov 2006 - 2007, modified by wj32")] +[assembly: AssemblyDescription("http://sourceforge.net/projects/treeviewadv/")] + +[assembly: AssemblyVersion("1.6.1.0")] diff --git a/branches/ph-plugins/TreeViewAdv/Properties/Resources.Designer.cs b/branches/ph-plugins/TreeViewAdv/Properties/Resources.Designer.cs new file mode 100644 index 000000000..c40222bc4 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Properties/Resources.Designer.cs @@ -0,0 +1,133 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:2.0.50727.1434 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Aga.Controls.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Aga.Controls.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + internal static System.Drawing.Bitmap check { + get { + object obj = ResourceManager.GetObject("check", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static byte[] DVSplit { + get { + object obj = ResourceManager.GetObject("DVSplit", resourceCulture); + return ((byte[])(obj)); + } + } + + internal static System.Drawing.Bitmap Folder { + get { + object obj = ResourceManager.GetObject("Folder", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap FolderClosed { + get { + object obj = ResourceManager.GetObject("FolderClosed", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap Leaf { + get { + object obj = ResourceManager.GetObject("Leaf", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static byte[] loading_icon { + get { + object obj = ResourceManager.GetObject("loading_icon", resourceCulture); + return ((byte[])(obj)); + } + } + + internal static System.Drawing.Bitmap minus { + get { + object obj = ResourceManager.GetObject("minus", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap plus { + get { + object obj = ResourceManager.GetObject("plus", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap uncheck { + get { + object obj = ResourceManager.GetObject("uncheck", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + internal static System.Drawing.Bitmap unknown { + get { + object obj = ResourceManager.GetObject("unknown", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Properties/Resources.resx b/branches/ph-plugins/TreeViewAdv/Properties/Resources.resx new file mode 100644 index 000000000..5307ac87d --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Properties/Resources.resx @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\check.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\resources\dvsplit.cur;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\Resources\Folder.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\FolderClosed.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\resources\leaf.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\loading_icon;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + ..\Resources\minus.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\plus.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\uncheck.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\resources\unknown.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/branches/ph-plugins/TreeViewAdv/ResourceHelper.cs b/branches/ph-plugins/TreeViewAdv/ResourceHelper.cs new file mode 100644 index 000000000..99176f294 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/ResourceHelper.cs @@ -0,0 +1,48 @@ +using System; +using System.IO; +using System.Reflection; +using System.Windows.Forms; +using System.Collections.Generic; +using System.Text; + +namespace Aga.Controls +{ + public static class ResourceHelper + { + // VSpilt Cursor with Innerline (symbolisize hidden column) + private static Cursor _dVSplitCursor = GetCursor(Properties.Resources.DVSplit); + public static Cursor DVSplitCursor + { + get { return _dVSplitCursor; } + } + + private static GifDecoder _loadingIcon = GetGifDecoder(Properties.Resources.loading_icon); + public static GifDecoder LoadingIcon + { + get { return _loadingIcon; } + } + + /// + /// Help function to convert byte[] from resource into Cursor Type + /// + /// + /// + private static Cursor GetCursor(byte[] data) + { + using (MemoryStream s = new MemoryStream(data)) + return new Cursor(s); + } + + /// + /// Help function to convert byte[] from resource into GifDecoder Type + /// + /// + /// + private static GifDecoder GetGifDecoder(byte[] data) + { + using(MemoryStream ms = new MemoryStream(data)) + return new GifDecoder(ms, true); + } + + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Resources/DVSplit.cur b/branches/ph-plugins/TreeViewAdv/Resources/DVSplit.cur new file mode 100644 index 000000000..2e25be2b3 Binary files /dev/null and b/branches/ph-plugins/TreeViewAdv/Resources/DVSplit.cur differ diff --git a/branches/ph-plugins/TreeViewAdv/Resources/Folder.bmp b/branches/ph-plugins/TreeViewAdv/Resources/Folder.bmp new file mode 100644 index 000000000..f515f9e95 Binary files /dev/null and b/branches/ph-plugins/TreeViewAdv/Resources/Folder.bmp differ diff --git a/branches/ph-plugins/TreeViewAdv/Resources/FolderClosed.bmp b/branches/ph-plugins/TreeViewAdv/Resources/FolderClosed.bmp new file mode 100644 index 000000000..7e848d4e5 Binary files /dev/null and b/branches/ph-plugins/TreeViewAdv/Resources/FolderClosed.bmp differ diff --git a/branches/ph-plugins/TreeViewAdv/Resources/Leaf.bmp b/branches/ph-plugins/TreeViewAdv/Resources/Leaf.bmp new file mode 100644 index 000000000..79254b2c6 Binary files /dev/null and b/branches/ph-plugins/TreeViewAdv/Resources/Leaf.bmp differ diff --git a/branches/ph-plugins/TreeViewAdv/Resources/Thumbs.db b/branches/ph-plugins/TreeViewAdv/Resources/Thumbs.db new file mode 100644 index 000000000..983f52698 Binary files /dev/null and b/branches/ph-plugins/TreeViewAdv/Resources/Thumbs.db differ diff --git a/branches/ph-plugins/TreeViewAdv/Resources/check.bmp b/branches/ph-plugins/TreeViewAdv/Resources/check.bmp new file mode 100644 index 000000000..11c9cfac8 Binary files /dev/null and b/branches/ph-plugins/TreeViewAdv/Resources/check.bmp differ diff --git a/branches/ph-plugins/TreeViewAdv/Resources/loading_icon b/branches/ph-plugins/TreeViewAdv/Resources/loading_icon new file mode 100644 index 000000000..ca716ed46 Binary files /dev/null and b/branches/ph-plugins/TreeViewAdv/Resources/loading_icon differ diff --git a/branches/ph-plugins/TreeViewAdv/Resources/minus.bmp b/branches/ph-plugins/TreeViewAdv/Resources/minus.bmp new file mode 100644 index 000000000..c6539d992 Binary files /dev/null and b/branches/ph-plugins/TreeViewAdv/Resources/minus.bmp differ diff --git a/branches/ph-plugins/TreeViewAdv/Resources/plus.bmp b/branches/ph-plugins/TreeViewAdv/Resources/plus.bmp new file mode 100644 index 000000000..d54ab8738 Binary files /dev/null and b/branches/ph-plugins/TreeViewAdv/Resources/plus.bmp differ diff --git a/branches/ph-plugins/TreeViewAdv/Resources/uncheck.bmp b/branches/ph-plugins/TreeViewAdv/Resources/uncheck.bmp new file mode 100644 index 000000000..673b1ba36 Binary files /dev/null and b/branches/ph-plugins/TreeViewAdv/Resources/uncheck.bmp differ diff --git a/branches/ph-plugins/TreeViewAdv/Resources/unknown.bmp b/branches/ph-plugins/TreeViewAdv/Resources/unknown.bmp new file mode 100644 index 000000000..ed34bd406 Binary files /dev/null and b/branches/ph-plugins/TreeViewAdv/Resources/unknown.bmp differ diff --git a/branches/ph-plugins/TreeViewAdv/StringCollectionEditor.cs b/branches/ph-plugins/TreeViewAdv/StringCollectionEditor.cs new file mode 100644 index 000000000..1bc581667 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/StringCollectionEditor.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.ComponentModel.Design; + +namespace Aga.Controls +{ + public class StringCollectionEditor : CollectionEditor + { + public StringCollectionEditor(Type type): base(type) + { + } + + protected override Type CreateCollectionItemType() + { + return typeof(string); + } + + protected override object CreateInstance(Type itemType) + { + return ""; + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/TextHelper.cs b/branches/ph-plugins/TreeViewAdv/TextHelper.cs new file mode 100644 index 000000000..756500e32 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/TextHelper.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows.Forms; +using System.Drawing; + +namespace Aga.Controls +{ + public static class TextHelper + { + public static StringAlignment TranslateAligment(HorizontalAlignment aligment) + { + if (aligment == HorizontalAlignment.Left) + return StringAlignment.Near; + else if (aligment == HorizontalAlignment.Right) + return StringAlignment.Far; + else + return StringAlignment.Center; + } + + public static TextFormatFlags TranslateAligmentToFlag(HorizontalAlignment aligment) + { + if (aligment == HorizontalAlignment.Left) + return TextFormatFlags.Left; + else if (aligment == HorizontalAlignment.Right) + return TextFormatFlags.Right; + else + return TextFormatFlags.HorizontalCenter; + } + + public static TextFormatFlags TranslateTrimmingToFlag(StringTrimming trimming) + { + if (trimming == StringTrimming.EllipsisCharacter) + return TextFormatFlags.EndEllipsis; + else if (trimming == StringTrimming.EllipsisPath) + return TextFormatFlags.PathEllipsis; + if (trimming == StringTrimming.EllipsisWord) + return TextFormatFlags.WordEllipsis; + if (trimming == StringTrimming.Word) + return TextFormatFlags.WordBreak; + else + return TextFormatFlags.Default; + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Threading/AbortableThreadPool.cs b/branches/ph-plugins/TreeViewAdv/Threading/AbortableThreadPool.cs new file mode 100644 index 000000000..9b390aa1e --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Threading/AbortableThreadPool.cs @@ -0,0 +1,118 @@ +// Stephen Toub +// stoub@microsoft.com + +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace Aga.Controls.Threading +{ + public class AbortableThreadPool + { + private LinkedList _callbacks = new LinkedList(); + private Dictionary _threads = new Dictionary(); + + public WorkItem QueueUserWorkItem(WaitCallback callback) + { + return QueueUserWorkItem(callback, null); + } + + public WorkItem QueueUserWorkItem(WaitCallback callback, object state) + { + if (callback == null) throw new ArgumentNullException("callback"); + + WorkItem item = new WorkItem(callback, state, ExecutionContext.Capture()); + lock (_callbacks) + { + _callbacks.AddLast(item); + } + ThreadPool.QueueUserWorkItem(new WaitCallback(HandleItem)); + return item; + } + + private void HandleItem(object ignored) + { + WorkItem item = null; + try + { + lock (_callbacks) + { + if (_callbacks.Count > 0) + { + item = _callbacks.First.Value; + _callbacks.RemoveFirst(); + } + if (item == null) + return; + _threads.Add(item, Thread.CurrentThread); + + } + ExecutionContext.Run(item.Context, + delegate { item.Callback(item.State); }, null); + } + finally + { + lock (_callbacks) + { + if (item != null) + _threads.Remove(item); + } + } + } + + public bool IsMyThread(Thread thread) + { + lock (_callbacks) + { + foreach (Thread t in _threads.Values) + { + if (t == thread) + return true; + } + return false; + } + } + + public WorkItemStatus Cancel(WorkItem item, bool allowAbort) + { + if (item == null) + throw new ArgumentNullException("item"); + lock (_callbacks) + { + LinkedListNode node = _callbacks.Find(item); + if (node != null) + { + _callbacks.Remove(node); + return WorkItemStatus.Queued; + } + else if (_threads.ContainsKey(item)) + { + if (allowAbort) + { + _threads[item].Abort(); + _threads.Remove(item); + return WorkItemStatus.Aborted; + } + else + return WorkItemStatus.Executing; + } + else + return WorkItemStatus.Completed; + } + } + + public void CancelAll(bool allowAbort) + { + lock (_callbacks) + { + _callbacks.Clear(); + if (allowAbort) + { + foreach (Thread t in _threads.Values) + t.Abort(); + } + } + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Threading/WorkItem.cs b/branches/ph-plugins/TreeViewAdv/Threading/WorkItem.cs new file mode 100644 index 000000000..c422a722e --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Threading/WorkItem.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace Aga.Controls.Threading +{ + public sealed class WorkItem + { + private WaitCallback _callback; + private object _state; + private ExecutionContext _ctx; + + internal WorkItem(WaitCallback wc, object state, ExecutionContext ctx) + { + _callback = wc; + _state = state; + _ctx = ctx; + } + + internal WaitCallback Callback + { + get + { + return _callback; + } + } + + internal object State + { + get + { + return _state; + } + } + + internal ExecutionContext Context + { + get + { + return _ctx; + } + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Threading/WorkItemStatus.cs b/branches/ph-plugins/TreeViewAdv/Threading/WorkItemStatus.cs new file mode 100644 index 000000000..71e16fa7f --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Threading/WorkItemStatus.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Aga.Controls.Threading +{ + public enum WorkItemStatus + { + Completed, + Queued, + Executing, + Aborted + } +} diff --git a/branches/ph-plugins/TreeViewAdv/TimeCounter.cs b/branches/ph-plugins/TreeViewAdv/TimeCounter.cs new file mode 100644 index 000000000..e7afc3aac --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/TimeCounter.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Runtime.InteropServices; +using System.Diagnostics.CodeAnalysis; + +namespace Aga.Controls +{ + /// + /// High resolution timer, used to test performance + /// + public static class TimeCounter + { + private static Int64 _start; + + /// + /// Start time counting + /// + public static void Start() + { + _start = 0; + QueryPerformanceCounter(ref _start); + } + + public static Int64 GetStartValue() + { + Int64 t = 0; + QueryPerformanceCounter(ref t); + return t; + } + + /// + /// Finish time counting + /// + /// time in seconds elapsed from Start till Finish + public static double Finish() + { + return Finish(_start); + } + + public static double Finish(Int64 start) + { + Int64 finish = 0; + QueryPerformanceCounter(ref finish); + + Int64 freq = 0; + QueryPerformanceFrequency(ref freq); + return (finish - start) / (double)freq; + } + + [DllImport("Kernel32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + static extern bool QueryPerformanceCounter(ref Int64 performanceCount); + + [DllImport("Kernel32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + static extern bool QueryPerformanceFrequency(ref Int64 frequency); + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/AutoRowHeightLayout.cs b/branches/ph-plugins/TreeViewAdv/Tree/AutoRowHeightLayout.cs new file mode 100644 index 000000000..8b89a9879 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/AutoRowHeightLayout.cs @@ -0,0 +1,151 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; +using Aga.Controls.Tree.NodeControls; + +namespace Aga.Controls.Tree +{ + public class AutoRowHeightLayout: IRowLayout + { + private DrawContext _measureContext; + private TreeViewAdv _treeView; + private List _rowCache; + + public AutoRowHeightLayout(TreeViewAdv treeView, int rowHeight) + { + _rowCache = new List(); + _treeView = treeView; + PreferredRowHeight = rowHeight; + _measureContext = new DrawContext(); + _measureContext.Graphics = Graphics.FromImage(new Bitmap(1, 1)); + } + + private int _rowHeight; + public int PreferredRowHeight + { + get { return _rowHeight; } + set { _rowHeight = value; } + } + + + public int PageRowCount + { + get + { + if (_treeView.RowCount == 0) + return 0; + else + { + int pageHeight = _treeView.DisplayRectangle.Height - _treeView.ColumnHeaderHeight; + int y = 0; + for (int i = _treeView.RowCount - 1; i >= 0; i--) + { + y += GetRowHeight(i); + if (y > pageHeight) + return Math.Max(0, _treeView.RowCount - 1 - i); + } + return _treeView.RowCount; + } + } + } + + public int CurrentPageSize + { + get + { + if (_treeView.RowCount == 0) + return 0; + else + { + int pageHeight = _treeView.DisplayRectangle.Height - _treeView.ColumnHeaderHeight; + int y = 0; + for (int i = _treeView.FirstVisibleRow; i < _treeView.RowCount; i++) + { + y += GetRowHeight(i); + if (y > pageHeight) + return Math.Max(0, i - _treeView.FirstVisibleRow); + } + return Math.Max(0, _treeView.RowCount - _treeView.FirstVisibleRow); + } + } + } + + public Rectangle GetRowBounds(int rowNo) + { + if (rowNo >= _rowCache.Count) + { + int count = _rowCache.Count; + int y = count > 0 ? _rowCache[count - 1].Bottom : 0; + for (int i = count; i <= rowNo; i++) + { + int height = GetRowHeight(i); + _rowCache.Add(new Rectangle(0, y, 0, height)); + y += height; + } + if (rowNo < _rowCache.Count - 1) + return Rectangle.Empty; + } + if (rowNo >= 0 && rowNo < _rowCache.Count) + return _rowCache[rowNo]; + else + return Rectangle.Empty; + } + + private int GetRowHeight(int rowNo) + { + if (rowNo < _treeView.RowMap.Count) + { + TreeNodeAdv node = _treeView.RowMap[rowNo]; + if (node.Height == null) + { + int res = 0; + _measureContext.Font = _treeView.Font; + foreach (NodeControl nc in _treeView.NodeControls) + { + int h = nc.GetActualSize(node, _measureContext).Height; + if (h > res) + res = h; + } + node.Height = res; + } + return node.Height.Value; + } + else + return 0; + } + + public int GetRowAt(Point point) + { + int py = point.Y - _treeView.ColumnHeaderHeight; + int y = 0; + for (int i = _treeView.FirstVisibleRow; i < _treeView.RowCount; i++) + { + int h = GetRowHeight(i); + if (py >= y && py < y + h) + return i; + else + y += h; + } + return -1; + } + + public int GetFirstRow(int lastPageRow) + { + int pageHeight = _treeView.DisplayRectangle.Height - _treeView.ColumnHeaderHeight; + int y = 0; + for (int i = lastPageRow; i >= 0; i--) + { + y += GetRowHeight(i); + if (y > pageHeight) + return Math.Max(0, i + 1); + } + return 0; + } + + public void ClearCache() + { + _rowCache.Clear(); + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/ClassDiagram.cd b/branches/ph-plugins/TreeViewAdv/Tree/ClassDiagram.cd new file mode 100644 index 000000000..0bd16eff1 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/ClassDiagram.cd @@ -0,0 +1,84 @@ + + + + + + + Tree\TreeModel.cs + AAAkgAAAAAAQAGQAAAAAEAAAEAACQAAAUAAAAAAAAQE= + + + + + + + + + + + + Tree\TreePath.cs + GABAAAAAAAACAAAAAAIAAAAAAAAACAAAAAAAAAAAAAA= + + + + + + + + + + + Tree\Node.cs + AAAgABAAgCAAAAAAAgAEVAAQAAAQAAAIAAsgCAAAAAA= + + + + + + + + + + Tree\Node.cs + + + + + + + + Tree\NodeControls\NodeControl.cs + AAAAAAAAgAAAgsIAAAhAQAAwAAAAEAAAAEAIAAAAAAA= + + + + + + + + Tree\ITreeModel.cs + AAAEAAAAAAAAAEQAAAAAEAAAEAAAQAAAAAAAAAAAAAA= + + + + + + Tree\IToolTipProvider.cs + AAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + + + \ No newline at end of file diff --git a/branches/ph-plugins/TreeViewAdv/Tree/ColumnCollection.cs b/branches/ph-plugins/TreeViewAdv/Tree/ColumnCollection.cs new file mode 100644 index 000000000..522c37a5b --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/ColumnCollection.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Collections.ObjectModel; + +namespace Aga.Controls.Tree +{ + /*internal class ColumnCollection: Collection + { + public int TotalWidth + { + get + { + int res = 0; + foreach (Column c in Items) + res += c.Width; + return res; + } + } + }*/ +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/DrawContext.cs b/branches/ph-plugins/TreeViewAdv/Tree/DrawContext.cs new file mode 100644 index 000000000..88a97486a --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/DrawContext.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; +using Aga.Controls.Tree.NodeControls; + +namespace Aga.Controls.Tree +{ + public struct DrawContext + { + private Graphics _graphics; + public Graphics Graphics + { + get { return _graphics; } + set { _graphics = value; } + } + + private Rectangle _bounds; + public Rectangle Bounds + { + get { return _bounds; } + set { _bounds = value; } + } + + private Font _font; + public Font Font + { + get { return _font; } + set { _font = value; } + } + + private DrawSelectionMode _drawSelection; + public DrawSelectionMode DrawSelection + { + get { return _drawSelection; } + set { _drawSelection = value; } + } + + private bool _drawFocus; + public bool DrawFocus + { + get { return _drawFocus; } + set { _drawFocus = value; } + } + + private NodeControl _currentEditorOwner; + public NodeControl CurrentEditorOwner + { + get { return _currentEditorOwner; } + set { _currentEditorOwner = value; } + } + + private bool _enabled; + public bool Enabled + { + get { return _enabled; } + set { _enabled = value; } + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/DropPosition.cs b/branches/ph-plugins/TreeViewAdv/Tree/DropPosition.cs new file mode 100644 index 000000000..1bb800e04 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/DropPosition.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Aga.Controls.Tree +{ + public struct DropPosition + { + private TreeNodeAdv _node; + public TreeNodeAdv Node + { + get { return _node; } + set { _node = value; } + } + + private NodePosition _position; + public NodePosition Position + { + get { return _position; } + set { _position = value; } + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/EditorContext.cs b/branches/ph-plugins/TreeViewAdv/Tree/EditorContext.cs new file mode 100644 index 000000000..3906ccc37 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/EditorContext.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows.Forms; +using System.Drawing; +using Aga.Controls.Tree.NodeControls; + +namespace Aga.Controls.Tree +{ + public struct EditorContext + { + private TreeNodeAdv _currentNode; + public TreeNodeAdv CurrentNode + { + get { return _currentNode; } + set { _currentNode = value; } + } + + private Control _editor; + public Control Editor + { + get { return _editor; } + set { _editor = value; } + } + + private NodeControl _owner; + public NodeControl Owner + { + get { return _owner; } + set { _owner = value; } + } + + private Rectangle _bounds; + public Rectangle Bounds + { + get { return _bounds; } + set { _bounds = value; } + } + + private DrawContext _drawContext; + public DrawContext DrawContext + { + get { return _drawContext; } + set { _drawContext = value; } + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/Enums.cs b/branches/ph-plugins/TreeViewAdv/Tree/Enums.cs new file mode 100644 index 000000000..687c6fca2 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/Enums.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Aga.Controls.Tree +{ + public enum DrawSelectionMode + { + None, Active, Inactive, FullRowSelect + } + + public enum TreeSelectionMode + { + Single, Multi, MultiSameParent + } + + public enum NodePosition + { + Inside, Before, After + } + + public enum VerticalAlignment + { + Top, Bottom, Center + } + + public enum IncrementalSearchMode + { + None, Standard, Continuous + } + + [Flags] + public enum GridLineStyle + { + None = 0, + Horizontal = 1, + Vertical = 2, + HorizontalAndVertical = 3 + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/FixedRowHeightLayout.cs b/branches/ph-plugins/TreeViewAdv/Tree/FixedRowHeightLayout.cs new file mode 100644 index 000000000..b43df6660 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/FixedRowHeightLayout.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; + +namespace Aga.Controls.Tree +{ + internal class FixedRowHeightLayout : IRowLayout + { + private TreeViewAdv _treeView; + + public FixedRowHeightLayout(TreeViewAdv treeView, int rowHeight) + { + _treeView = treeView; + PreferredRowHeight = rowHeight; + } + + private int _rowHeight; + public int PreferredRowHeight + { + get { return _rowHeight; } + set { _rowHeight = value; } + } + + public Rectangle GetRowBounds(int rowNo) + { + return new Rectangle(0, rowNo * _rowHeight, 0, _rowHeight); + } + + public int PageRowCount + { + get + { + return Math.Max((_treeView.DisplayRectangle.Height - _treeView.ColumnHeaderHeight) / _rowHeight, 0); + } + } + + public int CurrentPageSize + { + get + { + return PageRowCount; + } + } + + public int GetRowAt(Point point) + { + point = new Point(point.X, point.Y + (_treeView.FirstVisibleRow * _rowHeight) - _treeView.ColumnHeaderHeight); + return point.Y / _rowHeight; + } + + public int GetFirstRow(int lastPageRow) + { + return Math.Max(0, lastPageRow - PageRowCount + 1); + } + + public void ClearCache() + { + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/IRowLayout.cs b/branches/ph-plugins/TreeViewAdv/Tree/IRowLayout.cs new file mode 100644 index 000000000..30825b625 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/IRowLayout.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; + +namespace Aga.Controls.Tree +{ + internal interface IRowLayout + { + int PreferredRowHeight + { + get; + set; + } + + int PageRowCount + { + get; + } + + int CurrentPageSize + { + get; + } + + Rectangle GetRowBounds(int rowNo); + + int GetRowAt(Point point); + + int GetFirstRow(int lastPageRow); + + void ClearCache(); + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/IToolTipProvider.cs b/branches/ph-plugins/TreeViewAdv/Tree/IToolTipProvider.cs new file mode 100644 index 000000000..7356e30ad --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/IToolTipProvider.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Aga.Controls.Tree.NodeControls; + +namespace Aga.Controls.Tree +{ + public interface IToolTipProvider + { + string GetToolTip(TreeNodeAdv node, NodeControl nodeControl); + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/ITreeModel.cs b/branches/ph-plugins/TreeViewAdv/Tree/ITreeModel.cs new file mode 100644 index 000000000..7880253c9 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/ITreeModel.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Collections; + +namespace Aga.Controls.Tree +{ + public interface ITreeModel + { + IEnumerable GetChildren(TreePath treePath); + bool IsLeaf(TreePath treePath); + + event EventHandler NodesChanged; + event EventHandler NodesInserted; + event EventHandler NodesRemoved; + event EventHandler StructureChanged; + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/IncrementalSearch.cs b/branches/ph-plugins/TreeViewAdv/Tree/IncrementalSearch.cs new file mode 100644 index 000000000..4cee0cc63 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/IncrementalSearch.cs @@ -0,0 +1,143 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Aga.Controls.Tree.NodeControls; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; + +namespace Aga.Controls.Tree +{ + internal class IncrementalSearch + { + private const int SearchTimeout = 300; //end of incremental search timeot in msec + + private TreeViewAdv _tree; + private TreeNodeAdv _currentNode; + private string _searchString = ""; + private DateTime _lastKeyPressed = DateTime.Now; + + public IncrementalSearch(TreeViewAdv tree) + { + _tree = tree; + } + + public void Search(Char value) + { + if (!Char.IsControl(value)) + { + Char ch = Char.ToLowerInvariant(value); + DateTime dt = DateTime.Now; + TimeSpan ts = dt - _lastKeyPressed; + _lastKeyPressed = dt; + if (ts.TotalMilliseconds < SearchTimeout) + { + if (_searchString == value.ToString()) + FirstCharSearch(ch); + else + ContinuousSearch(ch); + } + else + { + FirstCharSearch(ch); + } + } + } + + private void ContinuousSearch(Char value) + { + if (value == ' ' && String.IsNullOrEmpty(_searchString)) + return; //Ingnore leading space + + _searchString += value; + DoContinuousSearch(); + } + + private void FirstCharSearch(Char value) + { + if (value == ' ') + return; + + _searchString = value.ToString(); + TreeNodeAdv node = null; + if (_tree.SelectedNode != null) + node = _tree.SelectedNode.NextVisibleNode; + if (node == null) + node = _tree.Root; + + foreach (string label in IterateNodeLabels(node)) + { + if (label.StartsWith(_searchString)) + { + _tree.SelectedNode = _currentNode; + return; + } + } + } + + public virtual void EndSearch() + { + _currentNode = null; + _searchString = ""; + } + + protected IEnumerable IterateNodeLabels(TreeNodeAdv start) + { + _currentNode = start; + while(_currentNode != null) + { + foreach (string label in GetNodeLabels(_currentNode)) + yield return label; + + _currentNode = _currentNode.NextVisibleNode; + if (_currentNode == null) + _currentNode = _tree.Root; + + if (start == _currentNode) + break; + } + } + + private IEnumerable GetNodeLabels(TreeNodeAdv node) + { + foreach (NodeControl nc in _tree.NodeControls) + { + BindableControl bc = nc as BindableControl; + if (bc != null && bc.IncrementalSearchEnabled) + { + object obj = bc.GetValue(node); + if (obj != null) + yield return obj.ToString().ToLowerInvariant(); + } + } + } + + private bool DoContinuousSearch() + { + bool found = false; + if (!String.IsNullOrEmpty(_searchString)) + { + TreeNodeAdv node = null; + if (_tree.SelectedNode != null) + node = _tree.SelectedNode; + if (node == null) + node = _tree.Root.NextVisibleNode; + + if (!String.IsNullOrEmpty(_searchString)) + { + foreach (string label in IterateNodeLabels(node)) + { + if (label.StartsWith(_searchString)) + { + found = true; + _tree.SelectedNode = _currentNode; + break; + } + } + } + } + return found; + } + + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/Input/ClickColumnState.cs b/branches/ph-plugins/TreeViewAdv/Tree/Input/ClickColumnState.cs new file mode 100644 index 000000000..9fa19239a --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/Input/ClickColumnState.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows.Forms; +using System.Drawing; + +namespace Aga.Controls.Tree +{ + internal class ClickColumnState : ColumnState + { + private Point _location; + + public ClickColumnState(TreeViewAdv tree, TreeColumn column, Point location) + : base(tree, column) + { + _location = location; + } + + public override void KeyDown(KeyEventArgs args) + { + } + + public override void MouseDown(TreeNodeAdvMouseEventArgs args) + { + } + + public override bool MouseMove(MouseEventArgs args) + { + if (TreeViewAdv.Dist(_location, args.Location) > TreeViewAdv.ItemDragSensivity + && Tree.AllowColumnReorder) + { + Tree.Input = new ReorderColumnState(Tree, Column, args.Location); + Tree.UpdateView(); + } + return true; + } + + public override void MouseUp(TreeNodeAdvMouseEventArgs args) + { + Tree.ChangeInput(); + Tree.UpdateView(); + Tree.OnColumnClicked(Column); + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/Input/ColumnState.cs b/branches/ph-plugins/TreeViewAdv/Tree/Input/ColumnState.cs new file mode 100644 index 000000000..10e064fb7 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/Input/ColumnState.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Aga.Controls.Tree +{ + internal abstract class ColumnState : InputState + { + private TreeColumn _column; + public TreeColumn Column + { + get { return _column; } + } + + public ColumnState(TreeViewAdv tree, TreeColumn column) + : base(tree) + { + _column = column; + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/Input/InputState.cs b/branches/ph-plugins/TreeViewAdv/Tree/Input/InputState.cs new file mode 100644 index 000000000..2d5ca2864 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/Input/InputState.cs @@ -0,0 +1,33 @@ +using System; +using System.Windows.Forms; +namespace Aga.Controls.Tree +{ + internal abstract class InputState + { + private TreeViewAdv _tree; + + public TreeViewAdv Tree + { + get { return _tree; } + } + + public InputState(TreeViewAdv tree) + { + _tree = tree; + } + + public abstract void KeyDown(System.Windows.Forms.KeyEventArgs args); + public abstract void MouseDown(TreeNodeAdvMouseEventArgs args); + public abstract void MouseUp(TreeNodeAdvMouseEventArgs args); + + /// + /// handle OnMouseMove event + /// + /// + /// true if event was handled and should be dispatched + public virtual bool MouseMove(MouseEventArgs args) + { + return false; + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/Input/InputWithControl.cs b/branches/ph-plugins/TreeViewAdv/Tree/Input/InputWithControl.cs new file mode 100644 index 000000000..94bd8571b --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/Input/InputWithControl.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Aga.Controls.Tree +{ + internal class InputWithControl: NormalInputState + { + public InputWithControl(TreeViewAdv tree): base(tree) + { + } + + protected override void DoMouseOperation(TreeNodeAdvMouseEventArgs args) + { + if (Tree.SelectionMode == TreeSelectionMode.Single) + { + base.DoMouseOperation(args); + } + else if (CanSelect(args.Node)) + { + args.Node.IsSelected = !args.Node.IsSelected; + Tree.SelectionStart = args.Node; + } + } + + protected override void MouseDownAtEmptySpace(TreeNodeAdvMouseEventArgs args) + { + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/Input/InputWithShift.cs b/branches/ph-plugins/TreeViewAdv/Tree/Input/InputWithShift.cs new file mode 100644 index 000000000..a5a7aa036 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/Input/InputWithShift.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Aga.Controls.Tree +{ + internal class InputWithShift: NormalInputState + { + public InputWithShift(TreeViewAdv tree): base(tree) + { + } + + protected override void FocusRow(TreeNodeAdv node) + { + Tree.SuspendSelectionEvent = true; + try + { + if (Tree.SelectionMode == TreeSelectionMode.Single || Tree.SelectionStart == null) + base.FocusRow(node); + else if (CanSelect(node)) + { + SelectAllFromStart(node); + Tree.CurrentNode = node; + Tree.ScrollTo(node); + } + } + finally + { + Tree.SuspendSelectionEvent = false; + } + } + + protected override void DoMouseOperation(TreeNodeAdvMouseEventArgs args) + { + if (Tree.SelectionMode == TreeSelectionMode.Single || Tree.SelectionStart == null) + { + base.DoMouseOperation(args); + } + else if (CanSelect(args.Node)) + { + Tree.SuspendSelectionEvent = true; + try + { + SelectAllFromStart(args.Node); + } + finally + { + Tree.SuspendSelectionEvent = false; + } + } + } + + protected override void MouseDownAtEmptySpace(TreeNodeAdvMouseEventArgs args) + { + } + + private void SelectAllFromStart(TreeNodeAdv node) + { + Tree.ClearSelectionInternal(); + int a = node.Row; + int b = Tree.SelectionStart.Row; + for (int i = Math.Min(a, b); i <= Math.Max(a, b); i++) + { + if (Tree.SelectionMode == TreeSelectionMode.Multi || Tree.RowMap[i].Parent == node.Parent) + Tree.RowMap[i].IsSelected = true; + } + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/Input/NormalInputState.cs b/branches/ph-plugins/TreeViewAdv/Tree/Input/NormalInputState.cs new file mode 100644 index 000000000..30933c9e8 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/Input/NormalInputState.cs @@ -0,0 +1,209 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows.Forms; + +namespace Aga.Controls.Tree +{ + internal class NormalInputState : InputState + { + private bool _mouseDownFlag = false; + + public NormalInputState(TreeViewAdv tree) : base(tree) + { + } + + public override void KeyDown(KeyEventArgs args) + { + if (Tree.CurrentNode == null && Tree.Root.Nodes.Count > 0) + Tree.CurrentNode = Tree.Root.Nodes[0]; + + if (Tree.CurrentNode != null) + { + switch (args.KeyCode) + { + case Keys.Right: + if (!Tree.CurrentNode.IsExpanded) + { + Tree.CurrentNode.IsExpanded = true; + // by fliser + Tree.FullUpdate(); + } + else if (Tree.CurrentNode.Nodes.Count > 0) + Tree.SelectedNode = Tree.CurrentNode.Nodes[0]; + args.Handled = true; + break; + case Keys.Left: + if (Tree.CurrentNode.IsExpanded) + { + Tree.CurrentNode.IsExpanded = false; + // by fliser + Tree.FullUpdate(); + } + else if (Tree.CurrentNode.Parent != Tree.Root) + Tree.SelectedNode = Tree.CurrentNode.Parent; + args.Handled = true; + break; + case Keys.Down: + NavigateForward(1); + args.Handled = true; + break; + case Keys.Up: + NavigateBackward(1); + args.Handled = true; + break; + case Keys.PageDown: + NavigateForward(Math.Max(1, Tree.CurrentPageSize - 1)); + args.Handled = true; + break; + case Keys.PageUp: + NavigateBackward(Math.Max(1, Tree.CurrentPageSize - 1)); + args.Handled = true; + break; + case Keys.Home: + if (Tree.RowMap.Count > 0) + FocusRow(Tree.RowMap[0]); + args.Handled = true; + break; + case Keys.End: + if (Tree.RowMap.Count > 0) + FocusRow(Tree.RowMap[Tree.RowMap.Count-1]); + args.Handled = true; + break; + case Keys.Subtract: + Tree.CurrentNode.Collapse(); + // by fliser + Tree.FullUpdate(); + args.Handled = true; + args.SuppressKeyPress = true; + break; + case Keys.Add: + Tree.CurrentNode.Expand(); + // by fliser + Tree.FullUpdate(); + args.Handled = true; + args.SuppressKeyPress = true; + break; + case Keys.Multiply: + Tree.CurrentNode.ExpandAll(); + // by fliser + Tree.FullUpdate(); + args.Handled = true; + args.SuppressKeyPress = true; + break; + } + } + } + + public override void MouseDown(TreeNodeAdvMouseEventArgs args) + { + if (args.Node != null) + { + Tree.ItemDragMode = true; + Tree.ItemDragStart = args.Location; + + if (args.Button == MouseButtons.Left || args.Button == MouseButtons.Right) + { + Tree.BeginUpdate(); + try + { + Tree.CurrentNode = args.Node; + if (args.Node.IsSelected) + _mouseDownFlag = true; + else + { + _mouseDownFlag = false; + DoMouseOperation(args); + } + } + finally + { + Tree.EndUpdate(); + } + } + + } + else + { + Tree.ItemDragMode = false; + MouseDownAtEmptySpace(args); + } + } + + public override void MouseUp(TreeNodeAdvMouseEventArgs args) + { + Tree.ItemDragMode = false; + if (_mouseDownFlag) + { + if (args.Button == MouseButtons.Left) + DoMouseOperation(args); + else if (args.Button == MouseButtons.Right) + Tree.CurrentNode = args.Node; + } + _mouseDownFlag = false; + } + + + private void NavigateBackward(int n) + { + int row = Math.Max(Tree.CurrentNode.Row - n, 0); + if (row != Tree.CurrentNode.Row) + FocusRow(Tree.RowMap[row]); + } + + private void NavigateForward(int n) + { + int row = Math.Min(Tree.CurrentNode.Row + n, Tree.RowCount - 1); + if (row != Tree.CurrentNode.Row) + FocusRow(Tree.RowMap[row]); + } + + protected virtual void MouseDownAtEmptySpace(TreeNodeAdvMouseEventArgs args) + { + Tree.ClearSelectionInternal(); + } + + protected virtual void FocusRow(TreeNodeAdv node) + { + Tree.SuspendSelectionEvent = true; + try + { + Tree.ClearSelectionInternal(); + Tree.CurrentNode = node; + Tree.SelectionStart = node; + node.IsSelected = true; + Tree.ScrollTo(node); + } + finally + { + Tree.SuspendSelectionEvent = false; + } + } + + protected bool CanSelect(TreeNodeAdv node) + { + if (Tree.SelectionMode == TreeSelectionMode.MultiSameParent) + { + return (Tree.SelectionStart == null || node.Parent == Tree.SelectionStart.Parent); + } + else + return true; + } + + protected virtual void DoMouseOperation(TreeNodeAdvMouseEventArgs args) + { + Tree.SuspendSelectionEvent = true; + try + { + Tree.ClearSelectionInternal(); + if (args.Node != null) + args.Node.IsSelected = true; + Tree.SelectionStart = args.Node; + } + finally + { + Tree.SuspendSelectionEvent = false; + } + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/Input/ReorderColumnState.cs b/branches/ph-plugins/TreeViewAdv/Tree/Input/ReorderColumnState.cs new file mode 100644 index 000000000..2fe445f1f --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/Input/ReorderColumnState.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; +using System.Windows.Forms; + +namespace Aga.Controls.Tree +{ + internal class ReorderColumnState : ColumnState + { + #region Properties + + private Point _location; + public Point Location + { + get { return _location; } + } + + private Bitmap _ghostImage; + public Bitmap GhostImage + { + get { return _ghostImage; } + } + + private TreeColumn _dropColumn; + public TreeColumn DropColumn + { + get { return _dropColumn; } + } + + private int _dragOffset; + public int DragOffset + { + get { return _dragOffset; } + } + + #endregion + + public ReorderColumnState(TreeViewAdv tree, TreeColumn column, Point initialMouseLocation) + : base(tree, column) + { + _location = new Point(initialMouseLocation.X + Tree.OffsetX, 0); + _dragOffset = tree.GetColumnX(column) - initialMouseLocation.X; + _ghostImage = column.CreateGhostImage(new Rectangle(0, 0, column.Width, tree.ColumnHeaderHeight), tree.Font); + } + + public override void KeyDown(KeyEventArgs args) + { + args.Handled = true; + if (args.KeyCode == Keys.Escape) + FinishResize(); + } + + public override void MouseDown(TreeNodeAdvMouseEventArgs args) + { + } + + public override void MouseUp(TreeNodeAdvMouseEventArgs args) + { + FinishResize(); + } + + public override bool MouseMove(MouseEventArgs args) + { + _dropColumn = null; + _location = new Point(args.X + Tree.OffsetX, 0); + int x = 0; + foreach (TreeColumn c in Tree.Columns) + { + if (c.IsVisible) + { + if (_location.X < x + c.Width / 2) + { + _dropColumn = c; + break; + } + x += c.Width; + } + } + Tree.UpdateHeaders(); + return true; + } + + private void FinishResize() + { + Tree.ChangeInput(); + if (Column == DropColumn) + Tree.UpdateView(); + else + { + Tree.Columns.Remove(Column); + if (DropColumn == null) + Tree.Columns.Add(Column); + else + Tree.Columns.Insert(Tree.Columns.IndexOf(DropColumn), Column); + + Tree.OnColumnReordered(Column); + } + } + } +} \ No newline at end of file diff --git a/branches/ph-plugins/TreeViewAdv/Tree/Input/ResizeColumnState.cs b/branches/ph-plugins/TreeViewAdv/Tree/Input/ResizeColumnState.cs new file mode 100644 index 000000000..486ed3d39 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/Input/ResizeColumnState.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows.Forms; +using System.Security.Permissions; +using System.Drawing; + +namespace Aga.Controls.Tree +{ + internal class ResizeColumnState: ColumnState + { + private Point _initLocation; + private int _initWidth; + + public ResizeColumnState(TreeViewAdv tree, TreeColumn column, Point p) + : base(tree, column) + { + _initLocation = p; + _initWidth = column.Width; + } + + public override void KeyDown(KeyEventArgs args) + { + args.Handled = true; + if (args.KeyCode == Keys.Escape) + FinishResize(); + } + + public override void MouseDown(TreeNodeAdvMouseEventArgs args) + { + } + + public override void MouseUp(TreeNodeAdvMouseEventArgs args) + { + FinishResize(); + } + + private void FinishResize() + { + Tree.ChangeInput(); + Tree.FullUpdate(); + Tree.OnColumnWidthChanged(Column); + } + + public override bool MouseMove(MouseEventArgs args) + { + Column.Width = _initWidth + args.Location.X - _initLocation.X; + Tree.UpdateView(); + Tree.Invalidate(); + return true; + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/Node.cs b/branches/ph-plugins/TreeViewAdv/Tree/Node.cs new file mode 100644 index 000000000..a00a7fe9b --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/Node.cs @@ -0,0 +1,257 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Collections.ObjectModel; +using System.Windows.Forms; +using System.Drawing; + +namespace Aga.Controls.Tree +{ + public class Node + { + #region NodeCollection + + private class NodeCollection : Collection + { + private Node _owner; + + public NodeCollection(Node owner) + { + _owner = owner; + } + + protected override void ClearItems() + { + while (this.Count != 0) + this.RemoveAt(this.Count - 1); + } + + protected override void InsertItem(int index, Node item) + { + if (item == null) + throw new ArgumentNullException("item"); + + if (item.Parent != _owner) + { + if (item.Parent != null) + item.Parent.Nodes.Remove(item); + item._parent = _owner; + item._index = index; + for (int i = index; i < Count; i++) + this[i]._index++; + base.InsertItem(index, item); + + TreeModel model = _owner.FindModel(); + if (model != null) + model.OnNodeInserted(_owner, index, item); + } + } + + protected override void RemoveItem(int index) + { + Node item = this[index]; + item._parent = null; + item._index = -1; + for (int i = index + 1; i < Count; i++) + this[i]._index--; + base.RemoveItem(index); + + TreeModel model = _owner.FindModel(); + if (model != null) + model.OnNodeRemoved(_owner, index, item); + } + + protected override void SetItem(int index, Node item) + { + if (item == null) + throw new ArgumentNullException("item"); + + RemoveAt(index); + InsertItem(index, item); + } + } + + #endregion + + #region Properties + + private TreeModel _model; + internal TreeModel Model + { + get { return _model; } + set { _model = value; } + } + + private NodeCollection _nodes; + public Collection Nodes + { + get { return _nodes; } + } + + private Node _parent; + public Node Parent + { + get { return _parent; } + set + { + if (value != _parent) + { + if (_parent != null) + _parent.Nodes.Remove(this); + + if (value != null) + value.Nodes.Add(this); + } + } + } + + private int _index = -1; + public int Index + { + get + { + return _index; + } + } + + public Node PreviousNode + { + get + { + int index = Index; + if (index > 0) + return _parent.Nodes[index - 1]; + else + return null; + } + } + + public Node NextNode + { + get + { + int index = Index; + if (index >= 0 && index < _parent.Nodes.Count - 1) + return _parent.Nodes[index + 1]; + else + return null; + } + } + + private string _text; + public virtual string Text + { + get { return _text; } + set + { + if (_text != value) + { + _text = value; + NotifyModel(); + } + } + } + + private CheckState _checkState; + public virtual CheckState CheckState + { + get { return _checkState; } + set + { + if (_checkState != value) + { + _checkState = value; + NotifyModel(); + } + } + } + + private Image _image; + public Image Image + { + get { return _image; } + set + { + if (_image != value) + { + _image = value; + NotifyModel(); + } + } + } + + private object _tag; + public object Tag + { + get { return _tag; } + set { _tag = value; } + } + + public bool IsChecked + { + get + { + return CheckState != CheckState.Unchecked; + } + set + { + if (value) + CheckState = CheckState.Checked; + else + CheckState = CheckState.Unchecked; + } + } + + public virtual bool IsLeaf + { + get + { + return false; + } + } + + #endregion + + public Node() + : this(string.Empty) + { + } + + public Node(string text) + { + _text = text; + _nodes = new NodeCollection(this); + } + + public override string ToString() + { + return Text; + } + + public TreeModel FindModel() + { + Node node = this; + while (node != null) + { + if (node.Model != null) + return node.Model; + node = node.Parent; + } + return null; + } + + protected void NotifyModel() + { + TreeModel model = FindModel(); + if (model != null && Parent != null) + { + TreePath path = model.GetPath(Parent); + if (path != null) + { + TreeModelEventArgs args = new TreeModelEventArgs(path, new int[] { Index }, new object[] { this }); + model.OnNodesChanged(args); + } + } + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/NodeControlInfo.cs b/branches/ph-plugins/TreeViewAdv/Tree/NodeControlInfo.cs new file mode 100644 index 000000000..db9d68470 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/NodeControlInfo.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Aga.Controls.Tree.NodeControls; +using System.Drawing; + +namespace Aga.Controls.Tree +{ + public struct NodeControlInfo + { + public static readonly NodeControlInfo Empty = new NodeControlInfo(null, Rectangle.Empty, null); + + private NodeControl _control; + public NodeControl Control + { + get { return _control; } + } + + private Rectangle _bounds; + public Rectangle Bounds + { + get { return _bounds; } + } + + private TreeNodeAdv _node; + public TreeNodeAdv Node + { + get { return _node; } + } + + public NodeControlInfo(NodeControl control, Rectangle bounds, TreeNodeAdv node) + { + _control = control; + _bounds = bounds; + _node = node; + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/BaseTextControl.cs b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/BaseTextControl.cs new file mode 100644 index 000000000..dda18cf8d --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/BaseTextControl.cs @@ -0,0 +1,294 @@ +/* + * modified by wj32. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; +using System.Windows.Forms; +using System.Reflection; +using System.ComponentModel; + +namespace Aga.Controls.Tree.NodeControls +{ + public abstract class BaseTextControl : EditableControl + { + private TextFormatFlags _baseFormatFlags; + private TextFormatFlags _formatFlags; + private Pen _focusPen; + private StringFormat _format; + + #region Properties + + private Font _font = null; + public Font Font + { + get + { + if (_font == null) + return Control.DefaultFont; + else + return _font; + } + set + { + if (value == Control.DefaultFont) + _font = null; + else + _font = value; + } + } + + protected bool ShouldSerializeFont() + { + return (_font != null); + } + + private HorizontalAlignment _textAlign = HorizontalAlignment.Left; + [DefaultValue(HorizontalAlignment.Left)] + public HorizontalAlignment TextAlign + { + get { return _textAlign; } + set + { + _textAlign = value; + SetFormatFlags(); + } + } + + private StringTrimming _trimming = StringTrimming.None; + [DefaultValue(StringTrimming.None)] + public StringTrimming Trimming + { + get { return _trimming; } + set + { + _trimming = value; + SetFormatFlags(); + } + } + + private bool _displayHiddenContentInToolTip = true; + [DefaultValue(true)] + public bool DisplayHiddenContentInToolTip + { + get { return _displayHiddenContentInToolTip; } + set { _displayHiddenContentInToolTip = value; } + } + + private bool _useCompatibleTextRendering = false; + [DefaultValue(false)] + public bool UseCompatibleTextRendering + { + get { return _useCompatibleTextRendering; } + set { _useCompatibleTextRendering = value; } + } + + #endregion + + protected BaseTextControl() + { + IncrementalSearchEnabled = true; + _focusPen = new Pen(Color.Black); + _focusPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot; + + _format = new StringFormat(StringFormatFlags.NoClip | StringFormatFlags.FitBlackBox | StringFormatFlags.MeasureTrailingSpaces); + _baseFormatFlags = TextFormatFlags.PreserveGraphicsClipping | TextFormatFlags.NoPrefix | + TextFormatFlags.PreserveGraphicsTranslateTransform; + SetFormatFlags(); + LeftMargin = 3; + } + + private void SetFormatFlags() + { + _format.Alignment = TextHelper.TranslateAligment(TextAlign); + _format.Trimming = Trimming; + + _formatFlags = _baseFormatFlags | TextHelper.TranslateAligmentToFlag(TextAlign) + | TextHelper.TranslateTrimmingToFlag(Trimming); + } + + public override Size MeasureSize(TreeNodeAdv node, DrawContext context) + { + return GetLabelSize(node, context); + } + + protected Size GetLabelSize(TreeNodeAdv node, DrawContext context) + { + return GetLabelSize(node, context, GetLabel(node)); + } + + protected Size GetLabelSize(TreeNodeAdv node, DrawContext context, string label) + { + CheckThread(); + Font font = GetDrawingFont(node, context, label); + Size s = Size.Empty; + + if (!UseCompatibleTextRendering) + { + SizeF sf = context.Graphics.MeasureString(label, font); + s = Size.Ceiling(sf); + } + else + { + s = TextRenderer.MeasureText(label, font); + } + + if (!s.IsEmpty) + return s; + else + return new Size(10, Font.Height); + } + + protected Font GetDrawingFont(TreeNodeAdv node, DrawContext context, string label) + { + Font font = context.Font; + if (DrawText != null) + { + DrawEventArgs args = new DrawEventArgs(node, context, label); + args.Font = context.Font; + OnDrawText(args); + font = args.Font; + } + return font; + } + + protected void SetEditControlProperties(Control control, TreeNodeAdv node) + { + string label = GetLabel(node); + DrawContext context = new DrawContext(); + context.Font = control.Font; + control.Font = GetDrawingFont(node, context, label); + } + + public override void Draw(TreeNodeAdv node, DrawContext context) + { + if (context.CurrentEditorOwner == this && node == Parent.CurrentNode) + return; + + string label = GetLabel(node); + Rectangle bounds = GetBounds(node, context); + Rectangle focusRect = new Rectangle(bounds.X, context.Bounds.Y, + bounds.Width, context.Bounds.Height); + + Brush backgroundBrush; + Color textColor; + Font font; + CreateBrushes(node, context, label, out backgroundBrush, out textColor, out font, ref label); + + if (backgroundBrush != null) + context.Graphics.FillRectangle(backgroundBrush, focusRect); + if (context.DrawFocus) + { + focusRect.Width--; + focusRect.Height--; + if (context.DrawSelection == DrawSelectionMode.None) + _focusPen.Color = SystemColors.ControlText; + else + _focusPen.Color = SystemColors.InactiveCaption; + context.Graphics.DrawRectangle(_focusPen, focusRect); + } + if (!UseCompatibleTextRendering) + context.Graphics.DrawString(label, font, GetFrush(textColor), bounds, _format); + else + TextRenderer.DrawText(context.Graphics, label, font, bounds, textColor, _formatFlags); + } + + private static Dictionary _brushes = new Dictionary(); + private static Brush GetFrush(Color color) + { + Brush br; + if (_brushes.ContainsKey(color)) + br = _brushes[color]; + else + { + br = new SolidBrush(color); + _brushes.Add(color, br); + } + return br; + } + + private void CreateBrushes(TreeNodeAdv node, DrawContext context, string text, out Brush backgroundBrush, out Color textColor, out Font font, ref string label) + { + //textColor = SystemColors.ControlText; + // wj32: respect node ForeColor + textColor = node.ForeColor; + + backgroundBrush = null; + font = context.Font; + + if (context.DrawSelection == DrawSelectionMode.Active) + { + textColor = SystemColors.HighlightText; + backgroundBrush = SystemBrushes.Highlight; + } + else if (context.DrawSelection == DrawSelectionMode.Inactive) + { + textColor = SystemColors.ControlText; + backgroundBrush = SystemBrushes.InactiveBorder; + } + else if (context.DrawSelection == DrawSelectionMode.FullRowSelect) + textColor = SystemColors.HighlightText; + + if (!context.Enabled) + textColor = SystemColors.GrayText; + + if (DrawText != null) + { + DrawEventArgs args = new DrawEventArgs(node, context, text); + args.TextColor = textColor; + args.BackgroundBrush = backgroundBrush; + args.Font = font; + + OnDrawText(args); + + textColor = args.TextColor; + backgroundBrush = args.BackgroundBrush; + font = args.Font; + label = args.Text; + } + } + + public string GetLabel(TreeNodeAdv node) + { + if (node != null && node.Tag != null) + { + object obj = GetValue(node); + if (obj != null) + return FormatLabel(obj); + } + return string.Empty; + } + + protected virtual string FormatLabel(object obj) + { + return obj.ToString(); + } + + public void SetLabel(TreeNodeAdv node, string value) + { + SetValue(node, value); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (disposing) + { + _focusPen.Dispose(); + _format.Dispose(); + } + } + + /// + /// Fires when control is going to draw a text. Can be used to change text or back color + /// + public event EventHandler DrawText; + protected virtual void OnDrawText(DrawEventArgs args) + { + if (DrawText != null) + DrawText(this, args); + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/BindableControl.cs b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/BindableControl.cs new file mode 100644 index 000000000..6536ce93c --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/BindableControl.cs @@ -0,0 +1,201 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Reflection; +using System.ComponentModel; + +namespace Aga.Controls.Tree.NodeControls +{ + public abstract class BindableControl : NodeControl + { + private struct MemberAdapter + { + private object _obj; + private PropertyInfo _pi; + private FieldInfo _fi; + + public static readonly MemberAdapter Empty = new MemberAdapter(); + + public Type MemberType + { + get + { + if (_pi != null) + return _pi.PropertyType; + else if (_fi != null) + return _fi.FieldType; + else + return null; + } + } + + public object Value + { + get + { + if (_pi != null && _pi.CanRead) + return _pi.GetValue(_obj, null); + else if (_fi != null) + return _fi.GetValue(_obj); + else + return null; + } + set + { + if (_pi != null && _pi.CanWrite) + _pi.SetValue(_obj, value, null); + else if (_fi != null) + _fi.SetValue(_obj, value); + } + } + + public MemberAdapter(object obj, PropertyInfo pi) + { + _obj = obj; + _pi = pi; + _fi = null; + } + + public MemberAdapter(object obj, FieldInfo fi) + { + _obj = obj; + _fi = fi; + _pi = null; + } + } + + #region Properties + + private bool _virtualMode = false; + [DefaultValue(false), Category("Data")] + public bool VirtualMode + { + get { return _virtualMode; } + set { _virtualMode = value; } + } + + private string _propertyName = ""; + [DefaultValue(""), Category("Data")] + public string DataPropertyName + { + get { return _propertyName; } + set + { + if (_propertyName == null) + _propertyName = string.Empty; + _propertyName = value; + } + } + + private bool _incrementalSearchEnabled = false; + [DefaultValue(false)] + public bool IncrementalSearchEnabled + { + get { return _incrementalSearchEnabled; } + set { _incrementalSearchEnabled = value; } + } + + #endregion + + public virtual object GetValue(TreeNodeAdv node) + { + if (VirtualMode) + { + NodeControlValueEventArgs args = new NodeControlValueEventArgs(node); + OnValueNeeded(args); + return args.Value; + } + else + { + try + { + return GetMemberAdapter(node).Value; + } + catch (TargetInvocationException ex) + { + if (ex.InnerException != null) + throw new ArgumentException(ex.InnerException.Message, ex.InnerException); + else + throw new ArgumentException(ex.Message); + } + } + } + + public virtual void SetValue(TreeNodeAdv node, object value) + { + if (VirtualMode) + { + NodeControlValueEventArgs args = new NodeControlValueEventArgs(node); + args.Value = value; + OnValuePushed(args); + } + else + { + try + { + MemberAdapter ma = GetMemberAdapter(node); + ma.Value = value; + } + catch (TargetInvocationException ex) + { + if (ex.InnerException != null) + throw new ArgumentException(ex.InnerException.Message, ex.InnerException); + else + throw new ArgumentException(ex.Message); + } + } + } + + public Type GetPropertyType(TreeNodeAdv node) + { + return GetMemberAdapter(node).MemberType; + } + + private MemberAdapter GetMemberAdapter(TreeNodeAdv node) + { + MemberAdapter adapter = MemberAdapter.Empty; + + if (node.Tag != null && !string.IsNullOrEmpty(DataPropertyName)) + { + Type type = node.Tag.GetType(); + PropertyInfo pi = type.GetProperty(DataPropertyName); + + if (pi != null) + { + return new MemberAdapter(node.Tag, pi); + } + else + { + FieldInfo fi = type.GetField(DataPropertyName, + BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + if (fi != null) + return new MemberAdapter(node.Tag, fi); + } + } + + return adapter; + } + + public override string ToString() + { + if (string.IsNullOrEmpty(DataPropertyName)) + return GetType().Name; + else + return string.Format("{0} ({1})", GetType().Name, DataPropertyName); + } + + public event EventHandler ValueNeeded; + private void OnValueNeeded(NodeControlValueEventArgs args) + { + if (ValueNeeded != null) + ValueNeeded(this, args); + } + + public event EventHandler ValuePushed; + private void OnValuePushed(NodeControlValueEventArgs args) + { + if (ValuePushed != null) + ValuePushed(this, args); + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/ClassDiagram.cd b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/ClassDiagram.cd new file mode 100644 index 000000000..437ad6dbb --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/ClassDiagram.cd @@ -0,0 +1,105 @@ + + + + + + + Tree\NodeControls\NodeStateIcon.cs + ABAAAAAAAAQAQAAAAAAAAAAAAAAAAAAAQIAAAAAAAAA= + + + + + + Tree\NodeControls\BindableControl.cs + FAAAAAAQIBAQCgAEAAAAIAAAAAAAAAEMAAACAAAAAAE= + + + + + + Tree\NodeControls\NodeCheckBox.cs + AAEAAAAAAAACgkQCAAAAAAigAgAAEGABAAAIAAAAAAA= + + + + + + Tree\NodeControls\NodeControl.cs + AAAAAJAAgIgBkkoQAAgAQAAwAAABEIQAAEBIAAAAAAA= + + + + + + + + + Tree\NodeControls\NodeIcon.cs + ABAAAAAAAAAAAgAAAAAAAAAgAAAAAAAAAAAAAAAAAAA= + + + + + + Tree\NodeControls\NodePlusMinus.cs + AAAAAAAAAAAAAgAAAAAAAEAgAAAAMCAAAAAIACAAAAA= + + + + + + Tree\NodeControls\BaseTextControl.cs + AAAAICBQACAAIgACBCAEAQA8AgmFoAAwAAAAACACAMA= + + + + + + Tree\NodeControls\NodeTextBox.cs + QQQAhAAAADAMgAAAABAAAAAAAgEAIAAAAAAAAIAAAAA= + + + + + + Tree\NodeControls\EditableControl.cs + QQAgAAAACGgkAMAABAEEkADAEAAUEAAABAGoAAAAAQA= + + + + + + Tree\NodeControls\NodeComboBox.cs + wQACAAAAAAAMAEBAAAAAAABAAAAAAAABAAAAAAAAAAA= + + + + + + Tree\NodeControls\NodeNumericUpDown.cs + wQAAAACAAAAEAABAIAAQIAAAAAAAAAABAAAIAAAAAII= + + + + + + Tree\NodeControls\InteractiveControl.cs + AAAABAAAAAAAAAAACAAAAAAAABAAAQAAAAAAAAIAAAA= + + + + + + Tree\NodeControls\NodeDecimalTextBox.cs + AQAAAAAAAACAAAACAAAAAAQAAAAAIAAAAAgAAAAAAAA= + + + + + + Tree\NodeControls\NodeIntegerTextBox.cs + AQAAAAAAAAAAAAACAAAAAAQAAAAAIAAAAAAAAAAAAAA= + + + \ No newline at end of file diff --git a/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/DrawEventArgs.cs b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/DrawEventArgs.cs new file mode 100644 index 000000000..56b24bc61 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/DrawEventArgs.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; + +namespace Aga.Controls.Tree.NodeControls +{ + public class DrawEventArgs : NodeEventArgs + { + private DrawContext _context; + public DrawContext Context + { + get { return _context; } + } + + private Brush _textBrush; + [Obsolete("Use TextColor")] + public Brush TextBrush + { + get { return _textBrush; } + set { _textBrush = value; } + } + + private Brush _backgroundBrush; + public Brush BackgroundBrush + { + get { return _backgroundBrush; } + set { _backgroundBrush = value; } + } + + private Font _font; + public Font Font + { + get { return _font; } + set { _font = value; } + } + + private Color _textColor; + public Color TextColor + { + get { return _textColor; } + set { _textColor = value; } + } + + private string _text; + public string Text + { + get { return _text; } + } + + public DrawEventArgs(TreeNodeAdv node, DrawContext context, string text) + : base(node) + { + _context = context; + _text = text; + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/EditableControl.cs b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/EditableControl.cs new file mode 100644 index 000000000..cbed3db22 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/EditableControl.cs @@ -0,0 +1,189 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows.Forms; +using System.Drawing; +using System.ComponentModel; + +namespace Aga.Controls.Tree.NodeControls +{ + public abstract class EditableControl : InteractiveControl + { + private Timer _timer; + private bool _editFlag; + + #region Properties + + private TreeNodeAdv _editNode; + protected TreeNodeAdv EditNode + { + get { return _editNode; } + } + + private Control _editor; + protected Control CurrentEditor + { + get { return _editor; } + } + + private bool _editOnClick = false; + [DefaultValue(false)] + public bool EditOnClick + { + get { return _editOnClick; } + set { _editOnClick = value; } + } + + #endregion + + protected EditableControl() + { + _timer = new Timer(); + _timer.Interval = 1000; + _timer.Tick += new EventHandler(TimerTick); + } + + private void TimerTick(object sender, EventArgs e) + { + _timer.Stop(); + if (_editFlag) + BeginEditByUser(); + _editFlag = false; + } + + public void SetEditorBounds(EditorContext context) + { + Size size = CalculateEditorSize(context); + context.Editor.Bounds = new Rectangle(context.Bounds.X, context.Bounds.Y, + Math.Min(size.Width, context.Bounds.Width), context.Bounds.Height); + } + + protected abstract Size CalculateEditorSize(EditorContext context); + + protected virtual bool CanEdit(TreeNodeAdv node) + { + return (node.Tag != null) && IsEditEnabled(node); + } + + protected void BeginEditByUser() + { + if (EditEnabled) + BeginEdit(); + } + + public void BeginEdit() + { + if (Parent.CurrentNode != null && CanEdit(Parent.CurrentNode)) + { + CancelEventArgs args = new CancelEventArgs(); + OnEditorShowing(args); + if (!args.Cancel) + { + _editor = CreateEditor(Parent.CurrentNode); + _editor.Validating += new CancelEventHandler(EditorValidating); + _editor.KeyDown += new KeyEventHandler(EditorKeyDown); + _editNode = Parent.CurrentNode; + Parent.DisplayEditor(_editor, this); + } + } + } + + private void EditorKeyDown(object sender, KeyEventArgs e) + { + if (e.KeyCode == Keys.Escape) + EndEdit(false); + else if (e.KeyCode == Keys.Enter) + EndEdit(true); + } + + private void EditorValidating(object sender, CancelEventArgs e) + { + ApplyChanges(); + } + + internal void HideEditor(Control editor) + { + editor.Validating -= new CancelEventHandler(EditorValidating); + editor.Parent = null; + editor.Dispose(); + _editNode = null; + OnEditorHided(); + } + + public void EndEdit(bool applyChanges) + { + if (!applyChanges) + _editor.Validating -= new CancelEventHandler(EditorValidating); + Parent.Focus(); + } + + public virtual void UpdateEditor(Control control) + { + } + + public virtual void ApplyChanges() + { + try + { + DoApplyChanges(_editNode, _editor); + } + catch (ArgumentException ex) + { + MessageBox.Show(ex.Message, "Value is not valid", MessageBoxButtons.OK, MessageBoxIcon.Warning); + } + } + + protected abstract void DoApplyChanges(TreeNodeAdv node, Control editor); + + protected abstract Control CreateEditor(TreeNodeAdv node); + + public override void MouseDown(TreeNodeAdvMouseEventArgs args) + { + _editFlag = (!EditOnClick && args.Button == MouseButtons.Left + && args.ModifierKeys == Keys.None && args.Node.IsSelected); + } + + public override void MouseUp(TreeNodeAdvMouseEventArgs args) + { + if (EditOnClick && args.Button == MouseButtons.Left && args.ModifierKeys == Keys.None) + { + Parent.ItemDragMode = false; + BeginEdit(); + args.Handled = true; + } + else if (_editFlag && args.Node.IsSelected) + _timer.Start(); + } + + public override void MouseDoubleClick(TreeNodeAdvMouseEventArgs args) + { + _editFlag = false; + _timer.Stop(); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (disposing) + _timer.Dispose(); + } + + #region Events + + public event CancelEventHandler EditorShowing; + protected void OnEditorShowing(CancelEventArgs args) + { + if (EditorShowing != null) + EditorShowing(this, args); + } + + public event EventHandler EditorHided; + protected void OnEditorHided() + { + if (EditorHided != null) + EditorHided(this, EventArgs.Empty); + } + + #endregion + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/ExpandingIcon.cs b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/ExpandingIcon.cs new file mode 100644 index 000000000..8d4ca967f --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/ExpandingIcon.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; +using System.Threading; +using System.Windows.Forms; + +namespace Aga.Controls.Tree.NodeControls +{ + /// + /// Displays an animated icon for those nodes, who are in expanding state. + /// Parent TreeView must have AsyncExpanding property set to true. + /// + public class ExpandingIcon: NodeControl + { + private static GifDecoder _gif; + private static int _index = 0; + private static Thread _animatingThread; + + private static GifDecoder Gif + { + get + { + if (_gif == null) + _gif = ResourceHelper.LoadingIcon; + + return _gif; + } + } + + public override Size MeasureSize(TreeNodeAdv node, DrawContext context) + { + return ResourceHelper.LoadingIcon.FrameSize; + } + + protected override void OnIsVisibleValueNeeded(NodeControlValueEventArgs args) + { + args.Value = args.Node.IsExpandingNow; + base.OnIsVisibleValueNeeded(args); + } + + public override void Draw(TreeNodeAdv node, DrawContext context) + { + Rectangle rect = GetBounds(node, context); + Image img = Gif.GetFrame(_index).Image; + context.Graphics.DrawImage(img, rect.Location); + } + + public static void Start() + { + _index = 0; + if (_animatingThread == null) + { + _animatingThread = new Thread(new ThreadStart(IterateIcons)); + _animatingThread.IsBackground = true; + _animatingThread.Priority = ThreadPriority.Lowest; + _animatingThread.Start(); + } + } + + private static void IterateIcons() + { + while (true) + { + if (_index < Gif.FrameCount - 1) + _index++; + else + _index = 0; + + if (IconChanged != null) + IconChanged(null, EventArgs.Empty); + + int delay = Gif.GetFrame(_index).Delay; + Thread.Sleep(delay); + } + } + + public static event EventHandler IconChanged; + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/InteractiveControl.cs b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/InteractiveControl.cs new file mode 100644 index 000000000..d418f3615 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/InteractiveControl.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.ComponentModel; + +namespace Aga.Controls.Tree.NodeControls +{ + public abstract class InteractiveControl : BindableControl + { + private bool _editEnabled = true; + [DefaultValue(true)] + public bool EditEnabled + { + get { return _editEnabled; } + set { _editEnabled = value; } + } + + protected bool IsEditEnabled(TreeNodeAdv node) + { + if (EditEnabled) + { + NodeControlValueEventArgs args = new NodeControlValueEventArgs(node); + args.Value = true; + OnIsEditEnabledValueNeeded(args); + return Convert.ToBoolean(args.Value); + } + else + return false; + } + + public event EventHandler IsEditEnabledValueNeeded; + private void OnIsEditEnabledValueNeeded(NodeControlValueEventArgs args) + { + if (IsEditEnabledValueNeeded != null) + IsEditEnabledValueNeeded(this, args); + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeCheckBox.cs b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeCheckBox.cs new file mode 100644 index 000000000..311cf5dd2 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeCheckBox.cs @@ -0,0 +1,184 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; +using Aga.Controls.Properties; +using System.Reflection; +using System.Windows.Forms; +using System.Windows.Forms.VisualStyles; +using System.ComponentModel; + +namespace Aga.Controls.Tree.NodeControls +{ + public class NodeCheckBox : InteractiveControl + { + public const int ImageSize = 13; + + private Bitmap _check; + private Bitmap _uncheck; + private Bitmap _unknown; + + #region Properties + + private bool _threeState; + [DefaultValue(false)] + public bool ThreeState + { + get { return _threeState; } + set { _threeState = value; } + } + + #endregion + + public NodeCheckBox() + : this(string.Empty) + { + } + + public NodeCheckBox(string propertyName) + { + _check = Resources.check; + _uncheck = Resources.uncheck; + _unknown = Resources.unknown; + DataPropertyName = propertyName; + LeftMargin = 0; + } + + public override Size MeasureSize(TreeNodeAdv node, DrawContext context) + { + return new Size(ImageSize, ImageSize); + } + + public override void Draw(TreeNodeAdv node, DrawContext context) + { + Rectangle bounds = GetBounds(node, context); + CheckState state = GetCheckState(node); + if (Application.RenderWithVisualStyles) + { + VisualStyleRenderer renderer; + if (state == CheckState.Indeterminate) + renderer = new VisualStyleRenderer(VisualStyleElement.Button.CheckBox.MixedNormal); + else if (state == CheckState.Checked) + renderer = new VisualStyleRenderer(VisualStyleElement.Button.CheckBox.CheckedNormal); + else + renderer = new VisualStyleRenderer(VisualStyleElement.Button.CheckBox.UncheckedNormal); + renderer.DrawBackground(context.Graphics, new Rectangle(bounds.X, bounds.Y, ImageSize, ImageSize)); + } + else + { + Image img; + if (state == CheckState.Indeterminate) + img = _unknown; + else if (state == CheckState.Checked) + img = _check; + else + img = _uncheck; + context.Graphics.DrawImage(img, bounds.Location); + } + } + + protected virtual CheckState GetCheckState(TreeNodeAdv node) + { + object obj = GetValue(node); + if (obj is CheckState) + return (CheckState)obj; + else if (obj is bool) + return (bool)obj ? CheckState.Checked : CheckState.Unchecked; + else + return CheckState.Unchecked; + } + + protected virtual void SetCheckState(TreeNodeAdv node, CheckState value) + { + if (VirtualMode) + { + SetValue(node, value); + OnCheckStateChanged(node); + } + else + { + Type type = GetPropertyType(node); + if (type == typeof(CheckState)) + { + SetValue(node, value); + OnCheckStateChanged(node); + } + else if (type == typeof(bool)) + { + SetValue(node, value != CheckState.Unchecked); + OnCheckStateChanged(node); + } + } + } + + public override void MouseDown(TreeNodeAdvMouseEventArgs args) + { + if (args.Button == MouseButtons.Left && IsEditEnabled(args.Node)) + { + DrawContext context = new DrawContext(); + context.Bounds = args.ControlBounds; + Rectangle rect = GetBounds(args.Node, context); + if (rect.Contains(args.ViewLocation)) + { + CheckState state = GetCheckState(args.Node); + state = GetNewState(state); + SetCheckState(args.Node, state); + Parent.UpdateView(); + args.Handled = true; + } + } + } + + public override void MouseDoubleClick(TreeNodeAdvMouseEventArgs args) + { + args.Handled = true; + } + + private CheckState GetNewState(CheckState state) + { + if (state == CheckState.Indeterminate) + return CheckState.Unchecked; + else if(state == CheckState.Unchecked) + return CheckState.Checked; + else + return ThreeState ? CheckState.Indeterminate : CheckState.Unchecked; + } + + public override void KeyDown(KeyEventArgs args) + { + if (args.KeyCode == Keys.Space && EditEnabled) + { + Parent.BeginUpdate(); + try + { + if (Parent.CurrentNode != null) + { + CheckState value = GetNewState(GetCheckState(Parent.CurrentNode)); + foreach (TreeNodeAdv node in Parent.Selection) + if (IsEditEnabled(node)) + SetCheckState(node, value); + } + } + finally + { + Parent.EndUpdate(); + } + args.Handled = true; + } + } + + public event EventHandler CheckStateChanged; + protected void OnCheckStateChanged(TreePathEventArgs args) + { + if (CheckStateChanged != null) + CheckStateChanged(this, args); + } + + protected void OnCheckStateChanged(TreeNodeAdv node) + { + TreePath path = this.Parent.GetPath(node); + OnCheckStateChanged(new TreePathEventArgs(path)); + } + + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeComboBox.cs b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeComboBox.cs new file mode 100644 index 000000000..db7ecfb87 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeComboBox.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; +using System.Windows.Forms; +using System.Reflection; +using System.ComponentModel; +using System.Drawing.Design; + +namespace Aga.Controls.Tree.NodeControls +{ + public class NodeComboBox : BaseTextControl + { + #region Properties + + private int _editorWidth = 100; + [DefaultValue(100)] + public int EditorWidth + { + get { return _editorWidth; } + set { _editorWidth = value; } + } + + private List _dropDownItems; + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1002:DoNotExposeGenericLists")] + [Editor(typeof(StringCollectionEditor), typeof(UITypeEditor)), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + public List DropDownItems + { + get { return _dropDownItems; } + } + + #endregion + + public NodeComboBox() + { + _dropDownItems = new List(); + } + + protected override Size CalculateEditorSize(EditorContext context) + { + if (Parent.UseColumns) + return context.Bounds.Size; + else + return new Size(EditorWidth, context.Bounds.Height); + } + + protected override Control CreateEditor(TreeNodeAdv node) + { + ComboBox comboBox = new ComboBox(); + if (DropDownItems != null) + comboBox.Items.AddRange(DropDownItems.ToArray()); + comboBox.SelectedItem = GetValue(node); + comboBox.DropDownStyle = ComboBoxStyle.DropDownList; + comboBox.DropDownClosed += new EventHandler(EditorDropDownClosed); + SetEditControlProperties(comboBox, node); + return comboBox; + } + + void EditorDropDownClosed(object sender, EventArgs e) + { + EndEdit(true); + } + + public override void UpdateEditor(Control control) + { + (control as ComboBox).DroppedDown = true; + } + + protected override void DoApplyChanges(TreeNodeAdv node, Control editor) + { + SetValue(node, (editor as ComboBox).SelectedItem); + } + + public override void MouseUp(TreeNodeAdvMouseEventArgs args) + { + if (args.Node != null && args.Node.IsSelected) //Workaround of specific ComboBox control behaviour + base.MouseUp(args); + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeControl.cs b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeControl.cs new file mode 100644 index 000000000..4fe4732e1 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeControl.cs @@ -0,0 +1,193 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows.Forms; +using System.Drawing; +using System.ComponentModel; + +namespace Aga.Controls.Tree.NodeControls +{ + [DesignTimeVisible(false), ToolboxItem(false)] + public abstract class NodeControl : Component + { + #region Properties + + private TreeViewAdv _parent; + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public TreeViewAdv Parent + { + get { return _parent; } + set + { + if (value != _parent) + { + if (_parent != null) + _parent.NodeControls.Remove(this); + + if (value != null) + value.NodeControls.Add(this); + } + } + } + + private IToolTipProvider _toolTipProvider; + [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public IToolTipProvider ToolTipProvider + { + get { return _toolTipProvider; } + set { _toolTipProvider = value; } + } + + private TreeColumn _parentColumn; + public TreeColumn ParentColumn + { + get { return _parentColumn; } + set + { + _parentColumn = value; + if (_parent != null) + _parent.FullUpdate(); + } + } + + private VerticalAlignment _verticalAlign = VerticalAlignment.Center; + [DefaultValue(VerticalAlignment.Center)] + public VerticalAlignment VerticalAlign + { + get { return _verticalAlign; } + set + { + _verticalAlign = value; + if (_parent != null) + _parent.FullUpdate(); + } + } + + private int _leftMargin = 0; + public int LeftMargin + { + get { return _leftMargin; } + set + { + if (value < 0) + throw new ArgumentOutOfRangeException(); + + _leftMargin = value; + if (_parent != null) + _parent.FullUpdate(); + } + } + #endregion + + internal virtual void AssignParent(TreeViewAdv parent) + { + if (_parent != null) + _parent.ColumnWidthChanged -= parent_ColumnWidthChanged; + + _parent = parent; + + if (_parent != null) + _parent.ColumnWidthChanged += parent_ColumnWidthChanged; + } + + private void parent_ColumnWidthChanged(object sender, TreeColumnEventArgs e) + { + _cachedSizeValid = false; + } + + protected virtual Rectangle GetBounds(TreeNodeAdv node, DrawContext context) + { + Rectangle r = context.Bounds; + Size s = GetActualSize(node, context); + Size bs = new Size(r.Width - LeftMargin, Math.Min(r.Height, s.Height)); + switch (VerticalAlign) + { + case VerticalAlignment.Top: + return new Rectangle(new Point(r.X + LeftMargin, r.Y), bs); + case VerticalAlignment.Bottom: + return new Rectangle(new Point(r.X + LeftMargin, r.Bottom - s.Height), bs); + default: + return new Rectangle(new Point(r.X + LeftMargin, r.Y + (r.Height - s.Height) / 2), bs); + } + } + + protected void CheckThread() + { + if (Parent != null && Control.CheckForIllegalCrossThreadCalls) + if (Parent.InvokeRequired) + throw new InvalidOperationException("Cross-thread calls are not allowed"); + } + + public bool IsVisible(TreeNodeAdv node) + { + NodeControlValueEventArgs args = new NodeControlValueEventArgs(node); + args.Value = true; + OnIsVisibleValueNeeded(args); + return Convert.ToBoolean(args.Value); + } + + // wj32: getting sizes takes a lot of CPU time, so let's cache it. + private bool _cachedSizeValid = false; + private Size _cachedSize = Size.Empty; + + internal Size GetActualSize(TreeNodeAdv node, DrawContext context) + { + // wj32: IsVisible takes longer than just returning the size... + //if (IsVisible(node)) + //{ + if (!_cachedSizeValid) + { + Size s = MeasureSize(node, context); + _cachedSize = new Size(s.Width + LeftMargin, s.Height); + _cachedSizeValid = true; + } + + return _cachedSize; + //} + //else + //{ + // return Size.Empty; + //} + } + + public abstract Size MeasureSize(TreeNodeAdv node, DrawContext context); + + public abstract void Draw(TreeNodeAdv node, DrawContext context); + + public virtual string GetToolTip(TreeNodeAdv node) + { + if (ToolTipProvider != null) + return ToolTipProvider.GetToolTip(node, this); + else + return string.Empty; + } + + public virtual void MouseDown(TreeNodeAdvMouseEventArgs args) + { + } + + public virtual void MouseUp(TreeNodeAdvMouseEventArgs args) + { + } + + public virtual void MouseDoubleClick(TreeNodeAdvMouseEventArgs args) + { + } + + public virtual void KeyDown(KeyEventArgs args) + { + } + + public virtual void KeyUp(KeyEventArgs args) + { + } + + public event EventHandler IsVisibleValueNeeded; + protected virtual void OnIsVisibleValueNeeded(NodeControlValueEventArgs args) + { + if (IsVisibleValueNeeded != null) + IsVisibleValueNeeded(this, args); + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeControlValueEventArgs.cs b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeControlValueEventArgs.cs new file mode 100644 index 000000000..d4f72ece2 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeControlValueEventArgs.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Aga.Controls.Tree.NodeControls +{ + public class NodeControlValueEventArgs : NodeEventArgs + { + private object _value; + public object Value + { + get { return _value; } + set { _value = value; } + } + + public NodeControlValueEventArgs(TreeNodeAdv node) + :base(node) + { + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeControlsCollection.cs b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeControlsCollection.cs new file mode 100644 index 000000000..1177ec48c --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeControlsCollection.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.ComponentModel.Design; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Drawing.Design; + +namespace Aga.Controls.Tree.NodeControls +{ + internal class NodeControlsCollection : Collection + { + private TreeViewAdv _tree; + + public NodeControlsCollection(TreeViewAdv tree) + { + _tree = tree; + } + + protected override void ClearItems() + { + _tree.BeginUpdate(); + try + { + while (this.Count != 0) + this.RemoveAt(this.Count - 1); + } + finally + { + _tree.EndUpdate(); + } + } + + protected override void InsertItem(int index, NodeControl item) + { + if (item == null) + throw new ArgumentNullException("item"); + + if (item.Parent != _tree) + { + if (item.Parent != null) + { + item.Parent.NodeControls.Remove(item); + } + base.InsertItem(index, item); + item.AssignParent(_tree); + _tree.FullUpdate(); + } + } + + protected override void RemoveItem(int index) + { + NodeControl value = this[index]; + value.AssignParent(null); + base.RemoveItem(index); + _tree.FullUpdate(); + } + + protected override void SetItem(int index, NodeControl item) + { + if (item == null) + throw new ArgumentNullException("item"); + + _tree.BeginUpdate(); + try + { + RemoveAt(index); + InsertItem(index, item); + } + finally + { + _tree.EndUpdate(); + } + } + } + + internal class NodeControlCollectionEditor : CollectionEditor + { + private Type[] _types; + + public NodeControlCollectionEditor(Type type) + : base(type) + { + _types = new Type[] { typeof(NodeTextBox), typeof(NodeIntegerTextBox), typeof(NodeDecimalTextBox), + typeof(NodeComboBox), typeof(NodeCheckBox), + typeof(NodeStateIcon), typeof(NodeIcon), typeof(NodeNumericUpDown), typeof(ExpandingIcon) }; + } + + protected override System.Type[] CreateNewItemTypes() + { + return _types; + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeDecimalTextBox.cs b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeDecimalTextBox.cs new file mode 100644 index 000000000..5c94b7c5b --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeDecimalTextBox.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; +using System.Windows.Forms; +using System.Reflection; +using System.ComponentModel; + +namespace Aga.Controls.Tree.NodeControls +{ + public class NodeDecimalTextBox : NodeTextBox + { + private bool _allowDecimalSeperator = true; + [DefaultValue(true)] + public bool AllowDecimalSeperator + { + get { return _allowDecimalSeperator; } + set { _allowDecimalSeperator = value; } + } + + private bool _allowNegativeSign = true; + [DefaultValue(true)] + public bool AllowNegativeSign + { + get { return _allowNegativeSign; } + set { _allowNegativeSign = value; } + } + + public NodeDecimalTextBox() + { + } + + protected override TextBox CreateTextBox() + { + NumericTextBox textBox = new NumericTextBox(); + textBox.AllowDecimalSeperator = AllowDecimalSeperator; + textBox.AllowNegativeSign = AllowNegativeSign; + return textBox; + } + + protected override void DoApplyChanges(TreeNodeAdv node, Control editor) + { + SetValue(node, (editor as NumericTextBox).DecimalValue); + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeEventArgs.cs b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeEventArgs.cs new file mode 100644 index 000000000..5ee8e4fa9 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeEventArgs.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Aga.Controls.Tree.NodeControls +{ + public class NodeEventArgs : EventArgs + { + private TreeNodeAdv _node; + public TreeNodeAdv Node + { + get { return _node; } + } + + public NodeEventArgs(TreeNodeAdv node) + { + _node = node; + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeIcon.cs b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeIcon.cs new file mode 100644 index 000000000..f8b3138d7 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeIcon.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; +using System.Windows.Forms; +using Aga.Controls.Properties; + +namespace Aga.Controls.Tree.NodeControls +{ + public class NodeIcon : BindableControl + { + public NodeIcon() + { + LeftMargin = 1; + } + + public override Size MeasureSize(TreeNodeAdv node, DrawContext context) + { + Image image = GetIcon(node); + if (image != null) + return image.Size; + else + return Size.Empty; + } + + public override void Draw(TreeNodeAdv node, DrawContext context) + { + Image image = GetIcon(node); + if (image != null) + { + Rectangle r = GetBounds(node, context); + context.Graphics.DrawImage(image, r.Location); + } + } + + protected virtual Image GetIcon(TreeNodeAdv node) + { + return GetValue(node) as Image; + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeIntegerTextBox.cs b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeIntegerTextBox.cs new file mode 100644 index 000000000..a1e55a0ee --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeIntegerTextBox.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.ComponentModel; +using System.Windows.Forms; + +namespace Aga.Controls.Tree.NodeControls +{ + + public class NodeIntegerTextBox : NodeTextBox + { + private bool _allowNegativeSign = true; + [DefaultValue(true)] + public bool AllowNegativeSign + { + get { return _allowNegativeSign; } + set { _allowNegativeSign = value; } + } + + public NodeIntegerTextBox() + { + } + + protected override TextBox CreateTextBox() + { + NumericTextBox textBox = new NumericTextBox(); + textBox.AllowDecimalSeperator = false; + textBox.AllowNegativeSign = AllowNegativeSign; + return textBox; + } + + protected override void DoApplyChanges(TreeNodeAdv node, Control editor) + { + SetValue(node, (editor as NumericTextBox).IntValue); + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeNumericUpDown.cs b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeNumericUpDown.cs new file mode 100644 index 000000000..48e82a197 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeNumericUpDown.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; +using System.Windows.Forms; +using System.Reflection; +using System.ComponentModel; +using System.Drawing.Design; + +namespace Aga.Controls.Tree.NodeControls +{ + public class NodeNumericUpDown : BaseTextControl + { + #region Properties + + private int _editorWidth = 100; + [DefaultValue(100)] + public int EditorWidth + { + get { return _editorWidth; } + set { _editorWidth = value; } + } + + private int _decimalPlaces = 0; + [Category("Data"), DefaultValue(0)] + public int DecimalPlaces + { + get + { + return this._decimalPlaces; + } + set + { + this._decimalPlaces = value; + } + } + + private decimal _increment = 1; + [Category("Data"), DefaultValue(1)] + public decimal Increment + { + get + { + return this._increment; + } + set + { + this._increment = value; + } + } + + private decimal _minimum = 0; + [Category("Data"), DefaultValue(0)] + public decimal Minimum + { + get + { + return _minimum; + } + set + { + _minimum = value; + } + } + + private decimal _maximum = 100; + [Category("Data"), DefaultValue(100)] + public decimal Maximum + { + get + { + return this._maximum; + } + set + { + this._maximum = value; + } + } + + #endregion + + public NodeNumericUpDown() + { + } + + protected override Size CalculateEditorSize(EditorContext context) + { + if (Parent.UseColumns) + return context.Bounds.Size; + else + return new Size(EditorWidth, context.Bounds.Height); + } + + protected override Control CreateEditor(TreeNodeAdv node) + { + NumericUpDown num = new NumericUpDown(); + num.Increment = Increment; + num.DecimalPlaces = DecimalPlaces; + num.Minimum = Minimum; + num.Maximum = Maximum; + num.Value = (decimal)GetValue(node); + SetEditControlProperties(num, node); + return num; + } + + protected override void DoApplyChanges(TreeNodeAdv node, Control editor) + { + SetValue(node, (editor as NumericUpDown).Value); + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodePlusMinus.cs b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodePlusMinus.cs new file mode 100644 index 000000000..232f2d7e3 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodePlusMinus.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; +using Aga.Controls.Properties; +using System.Windows.Forms; +using System.Windows.Forms.VisualStyles; + +namespace Aga.Controls.Tree.NodeControls +{ + internal class NodePlusMinus : NodeControl + { + private TreeViewAdv _tree; + public const int ImageSize = 9; + public const int Width = 16; + private bool _useVisualStyles; + private VisualStyleRenderer _openedRenderer; + private VisualStyleRenderer _closedRenderer; + private Bitmap _plus; + private Bitmap _minus; + + public NodePlusMinus(TreeViewAdv tree) + { + _tree = tree; + this.RefreshVisualStyles(); + } + + private Bitmap Plus + { + get + { + if (_plus == null) + _plus = Resources.plus; + + return _plus; + } + } + + private Bitmap Minus + { + get + { + if (_minus == null) + _minus = Resources.minus; + + return _minus; + } + } + + public void RefreshVisualStyles() + { + bool useVisualStyles = Application.RenderWithVisualStyles; + + if (useVisualStyles) + { + try + { + _openedRenderer = new VisualStyleRenderer(VisualStyleElement.TreeView.Glyph.Opened); + _closedRenderer = new VisualStyleRenderer(VisualStyleElement.TreeView.Glyph.Closed); + } + catch + { + useVisualStyles = false; + } + } + + _useVisualStyles = useVisualStyles; + } + + public override Size MeasureSize(TreeNodeAdv node, DrawContext context) + { + return new Size(Width, Width); + } + + public override void Draw(TreeNodeAdv node, DrawContext context) + { + if (node.CanExpand) + { + Rectangle r = context.Bounds; + int dy = (int)Math.Round((float)(r.Height - ImageSize) / 2); + + if (_useVisualStyles) + { + VisualStyleRenderer renderer; + + if (node.IsExpanded) + renderer = _openedRenderer; + else + renderer = _closedRenderer; + + renderer.DrawBackground(context.Graphics, new Rectangle(r.X, r.Y + dy, ImageSize, ImageSize)); + } + else + { + Image img; + + if (node.IsExpanded) + img = this.Minus; + else + img = this.Plus; + + context.Graphics.DrawImageUnscaled(img, new Point(r.X, r.Y + dy)); + } + } + } + + public override void MouseDown(TreeNodeAdvMouseEventArgs args) + { + if (args.Button == MouseButtons.Left) + { + args.Handled = true; + + if (args.Node.CanExpand) + { + args.Node.IsExpanded = !args.Node.IsExpanded; + // fixed by wj32 + _tree.FullUpdate(); + } + } + } + + public override void MouseDoubleClick(TreeNodeAdvMouseEventArgs args) + { + args.Handled = true; // Supress expand/collapse when double click on plus/minus + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeStateIcon.cs b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeStateIcon.cs new file mode 100644 index 000000000..20c751c7d --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeStateIcon.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; +using Aga.Controls.Properties; + +namespace Aga.Controls.Tree.NodeControls +{ + public class NodeStateIcon: NodeIcon + { + private Image _leaf; + private Image _opened; + private Image _closed; + + public NodeStateIcon() + { + _leaf = MakeTransparent(Resources.Leaf); + _opened = MakeTransparent(Resources.Folder); + _closed = MakeTransparent(Resources.FolderClosed); + } + + private static Image MakeTransparent(Bitmap bitmap) + { + bitmap.MakeTransparent(bitmap.GetPixel(0,0)); + return bitmap; + } + + protected override Image GetIcon(TreeNodeAdv node) + { + Image icon = base.GetIcon(node); + if (icon != null) + return icon; + else if (node.IsLeaf) + return _leaf; + else if (node.CanExpand && node.IsExpanded) + return _opened; + else + return _closed; + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeTextBox.cs b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeTextBox.cs new file mode 100644 index 000000000..ef34be310 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/NodeControls/NodeTextBox.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Drawing; +using System.Windows.Forms; +using System.Reflection; +using System.ComponentModel; + +namespace Aga.Controls.Tree.NodeControls +{ + public class NodeTextBox: BaseTextControl + { + private const int MinTextBoxWidth = 30; + + private TextBox EditorTextBox + { + get + { + return CurrentEditor as TextBox; + } + } + + public NodeTextBox() + { + } + + protected override Size CalculateEditorSize(EditorContext context) + { + if (Parent.UseColumns) + return context.Bounds.Size; + else + { + Size size = GetLabelSize(context.CurrentNode, context.DrawContext, _label); + int width = Math.Max(size.Width + Font.Height, MinTextBoxWidth); // reserve a place for new typed character + return new Size(width, size.Height); + } + } + + public override void KeyDown(KeyEventArgs args) + { + if (args.KeyCode == Keys.F2 && Parent.CurrentNode != null) + { + args.Handled = true; + BeginEditByUser(); + } + } + + protected override Control CreateEditor(TreeNodeAdv node) + { + TextBox textBox = CreateTextBox(); + textBox.TextAlign = TextAlign; + textBox.Text = GetLabel(node); + textBox.BorderStyle = BorderStyle.FixedSingle; + textBox.TextChanged += new EventHandler(textBox_TextChanged); + _label = textBox.Text; + SetEditControlProperties(textBox, node); + return textBox; + } + + protected virtual TextBox CreateTextBox() + { + return new TextBox(); + } + + private string _label; + private void textBox_TextChanged(object sender, EventArgs e) + { + _label = EditorTextBox.Text; + Parent.UpdateEditorBounds(); + } + + protected override void DoApplyChanges(TreeNodeAdv node, Control editor) + { + string oldLabel = GetLabel(node); + if (oldLabel != _label) + { + SetLabel(node, _label); + OnLabelChanged(); + } + } + + public void Cut() + { + if (EditorTextBox != null) + EditorTextBox.Cut(); + } + + public void Copy() + { + if (EditorTextBox != null) + EditorTextBox.Copy(); + } + + public void Paste() + { + if (EditorTextBox != null) + EditorTextBox.Paste(); + } + + public void Delete() + { + if (EditorTextBox != null) + { + int len = Math.Max(EditorTextBox.SelectionLength, 1); + if (EditorTextBox.SelectionStart < EditorTextBox.Text.Length) + { + int start = EditorTextBox.SelectionStart; + EditorTextBox.Text = EditorTextBox.Text.Remove(EditorTextBox.SelectionStart, len); + EditorTextBox.SelectionStart = start; + } + } + } + + public event EventHandler LabelChanged; + protected void OnLabelChanged() + { + if (LabelChanged != null) + LabelChanged(this, EventArgs.Empty); + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/SortedTreeModel.cs b/branches/ph-plugins/TreeViewAdv/Tree/SortedTreeModel.cs new file mode 100644 index 000000000..d9cb108c6 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/SortedTreeModel.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Collections; + +namespace Aga.Controls.Tree +{ + public class SortedTreeModel: TreeModelBase + { + private ITreeModel _innerModel; + public ITreeModel InnerModel + { + get { return _innerModel; } + } + + private IComparer _comparer; + public IComparer Comparer + { + get { return _comparer; } + set + { + _comparer = value; + OnStructureChanged(new TreePathEventArgs(TreePath.Empty)); + } + } + + public SortedTreeModel(ITreeModel innerModel) + { + _innerModel = innerModel; + _innerModel.NodesChanged += new EventHandler(_innerModel_NodesChanged); + _innerModel.NodesInserted += new EventHandler(_innerModel_NodesInserted); + _innerModel.NodesRemoved += new EventHandler(_innerModel_NodesRemoved); + _innerModel.StructureChanged += new EventHandler(_innerModel_StructureChanged); + } + + void _innerModel_StructureChanged(object sender, TreePathEventArgs e) + { + OnStructureChanged(e); + } + + void _innerModel_NodesRemoved(object sender, TreeModelEventArgs e) + { + OnStructureChanged(new TreePathEventArgs(e.Path)); + } + + void _innerModel_NodesInserted(object sender, TreeModelEventArgs e) + { + OnStructureChanged(new TreePathEventArgs(e.Path)); + } + + void _innerModel_NodesChanged(object sender, TreeModelEventArgs e) + { + OnStructureChanged(new TreePathEventArgs(e.Path)); + } + + public override IEnumerable GetChildren(TreePath treePath) + { + if (Comparer != null) + { + ArrayList list = new ArrayList(); + IEnumerable res = InnerModel.GetChildren(treePath); + if (res != null) + { + foreach (object obj in res) + list.Add(obj); + list.Sort(Comparer); + return list; + } + else + return null; + } + else + return InnerModel.GetChildren(treePath); + } + + public override bool IsLeaf(TreePath treePath) + { + return InnerModel.IsLeaf(treePath); + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/TreeColumn.cs b/branches/ph-plugins/TreeViewAdv/Tree/TreeColumn.cs new file mode 100644 index 000000000..462b1a2f9 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/TreeColumn.cs @@ -0,0 +1,367 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.ComponentModel; +using System.Windows.Forms; +using System.Drawing; +using System.Windows.Forms.VisualStyles; +using System.Drawing.Imaging; + +namespace Aga.Controls.Tree +{ + [TypeConverter(typeof(TreeColumn.TreeColumnConverter)), DesignTimeVisible(false), ToolboxItem(false)] + public class TreeColumn : Component + { + private class TreeColumnConverter : ComponentConverter + { + public TreeColumnConverter() + : base(typeof(TreeColumn)) + { + } + + public override bool GetPropertiesSupported(ITypeDescriptorContext context) + { + return false; + } + } + + private const int HeaderLeftMargin = 5; + private const int HeaderRightMargin = 5; + private const int SortOrderMarkMargin = 8; + + private TextFormatFlags _headerFlags; + private TextFormatFlags _baseHeaderFlags = TextFormatFlags.NoPadding | + TextFormatFlags.EndEllipsis | + TextFormatFlags.VerticalCenter | + TextFormatFlags.PreserveGraphicsTranslateTransform; + + #region Properties + + private TreeColumnCollection _owner; + internal TreeColumnCollection Owner + { + get { return _owner; } + set { _owner = value; } + } + + [Browsable(false)] + public int Index + { + get + { + if (Owner != null) + return Owner.IndexOf(this); + else + return -1; + } + } + + private string _header; + [Localizable(true)] + public string Header + { + get { return _header; } + set + { + _header = value; + OnHeaderChanged(); + } + } + + private string _tooltipText; + [Localizable(true)] + public string TooltipText + { + get { return _tooltipText; } + set { _tooltipText = value; } + } + + private int _width; + [DefaultValue(50), Localizable(true)] + public int Width + { + get + { + return _width; + } + set + { + if (_width != value) + { + _width = Math.Max(MinColumnWidth, value); + if (_maxColumnWidth > 0) + { + _width = Math.Min(_width, MaxColumnWidth); + } + OnWidthChanged(); + } + } + } + + private int _minColumnWidth; + [DefaultValue(0)] + public int MinColumnWidth + { + get { return _minColumnWidth; } + set + { + if (value < 0) + throw new ArgumentOutOfRangeException("value"); + + _minColumnWidth = value; + Width = Math.Max(value, Width); + } + } + + private int _maxColumnWidth; + [DefaultValue(0)] + public int MaxColumnWidth + { + get { return _maxColumnWidth; } + set + { + if (value < 0) + throw new ArgumentOutOfRangeException("value"); + + _maxColumnWidth = value; + if (value > 0) + Width = Math.Min(value, _width); + } + } + + private bool _visible = true; + [DefaultValue(true)] + public bool IsVisible + { + get { return _visible; } + set + { + _visible = value; + OnIsVisibleChanged(); + } + } + + private HorizontalAlignment _textAlign = HorizontalAlignment.Left; + [DefaultValue(HorizontalAlignment.Left)] + public HorizontalAlignment TextAlign + { + get { return _textAlign; } + set + { + if (value != _textAlign) + { + _textAlign = value; + _headerFlags = _baseHeaderFlags | TextHelper.TranslateAligmentToFlag(value); + OnHeaderChanged(); + } + } + } + + private bool _sortable = false; + [DefaultValue(false)] + public bool Sortable + { + get { return _sortable; } + set { _sortable = value; } + } + + private SortOrder _sort_order = SortOrder.None; + public SortOrder SortOrder + { + get { return _sort_order; } + set + { + if (value == _sort_order) + return; + _sort_order = value; + OnSortOrderChanged(); + } + } + + public Size SortMarkSize + { + get + { + if (Application.RenderWithVisualStyles) + return new Size(9, 5); + else + return new Size(7, 4); + } + } + #endregion + + public TreeColumn(): + this(string.Empty, 50) + { + } + + public TreeColumn(string header, int width) + { + _header = header; + _width = width; + _headerFlags = _baseHeaderFlags | TextFormatFlags.Left; + } + + public override string ToString() + { + if (string.IsNullOrEmpty(Header)) + return GetType().Name; + else + return Header; + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + } + + #region Draw + + private static VisualStyleRenderer _normalRenderer; + private static VisualStyleRenderer _hotRenderer; + private static VisualStyleRenderer _pressedRenderer; + + internal Bitmap CreateGhostImage(Rectangle bounds, Font font) + { + Bitmap b = new Bitmap(bounds.Width, bounds.Height, PixelFormat.Format32bppArgb); + Graphics gr = Graphics.FromImage(b); + gr.FillRectangle(SystemBrushes.ControlDark, bounds); + DrawContent(gr, bounds, font); + BitmapHelper.SetAlphaChanelValue(b, 150); + return b; + } + + internal void Draw(Graphics gr, Rectangle bounds, Font font, bool pressed, bool hot) + { + DrawBackground(gr, bounds, pressed, hot); + DrawContent(gr, bounds, font); + } + + internal void DrawContent(Graphics gr, Rectangle bounds, Font font) + { + Rectangle innerBounds = new Rectangle(bounds.X + HeaderLeftMargin, bounds.Y, + bounds.Width - HeaderLeftMargin - HeaderRightMargin, + bounds.Height); + + if (SortOrder != SortOrder.None) + innerBounds.Width -= (SortMarkSize.Width + SortOrderMarkMargin); + + Size maxTextSize = TextRenderer.MeasureText(gr, Header, font, innerBounds.Size, TextFormatFlags.NoPadding); + Size textSize = TextRenderer.MeasureText(gr, Header, font, innerBounds.Size, _baseHeaderFlags); + + if (SortOrder != SortOrder.None) + { + int tw = Math.Min(textSize.Width, innerBounds.Size.Width); + + int x = 0; + if (TextAlign == HorizontalAlignment.Left) + x = innerBounds.X + tw + SortOrderMarkMargin; + else if (TextAlign == HorizontalAlignment.Right) + x = innerBounds.Right + SortOrderMarkMargin; + else + x = innerBounds.X + tw + (innerBounds.Width - tw) / 2 + SortOrderMarkMargin; + DrawSortMark(gr, bounds, x); + } + + if (textSize.Width < maxTextSize.Width) + TextRenderer.DrawText(gr, Header, font, innerBounds, SystemColors.ControlText, _baseHeaderFlags | TextFormatFlags.Left); + else + TextRenderer.DrawText(gr, Header, font, innerBounds, SystemColors.ControlText, _headerFlags); + } + + private void DrawSortMark(Graphics gr, Rectangle bounds, int x) + { + int y = bounds.Y + bounds.Height / 2 - 2; + x = Math.Max(x, bounds.X + SortOrderMarkMargin); + + int w2 = SortMarkSize.Width / 2; + if (SortOrder == SortOrder.Ascending) + { + Point[] points = new Point[] { new Point(x, y), new Point(x + SortMarkSize.Width, y), new Point(x + w2, y + SortMarkSize.Height) }; + gr.FillPolygon(SystemBrushes.ControlDark, points); + } + else if (SortOrder == SortOrder.Descending) + { + Point[] points = new Point[] { new Point(x - 1, y + SortMarkSize.Height), new Point(x + SortMarkSize.Width, y + SortMarkSize.Height), new Point(x + w2, y - 1) }; + gr.FillPolygon(SystemBrushes.ControlDark, points); + } + } + + internal static void DrawDropMark(Graphics gr, Rectangle rect) + { + gr.FillRectangle(SystemBrushes.HotTrack, rect.X-1, rect.Y, 2, rect.Height); + } + + internal static void DrawBackground(Graphics gr, Rectangle bounds, bool pressed, bool hot) + { + if (Application.RenderWithVisualStyles) + { + if (_normalRenderer == null) + _normalRenderer = new VisualStyleRenderer(VisualStyleElement.Header.Item.Normal); + if (_hotRenderer == null) + _hotRenderer = new VisualStyleRenderer(VisualStyleElement.Header.Item.Hot); + if (_pressedRenderer == null) + _pressedRenderer = new VisualStyleRenderer(VisualStyleElement.Header.Item.Pressed); + + if (pressed) + _pressedRenderer.DrawBackground(gr, bounds); + else if (hot) + _hotRenderer.DrawBackground(gr, bounds); + else + _normalRenderer.DrawBackground(gr, bounds); + } + else + { + gr.FillRectangle(SystemBrushes.Control, bounds); + Pen p1 = SystemPens.ControlLightLight; + Pen p2 = SystemPens.ControlDark; + Pen p3 = SystemPens.ControlDarkDark; + if (pressed) + gr.DrawRectangle(p2, bounds.X, bounds.Y, bounds.Width, bounds.Height); + else + { + gr.DrawLine(p1, bounds.X, bounds.Y, bounds.Right, bounds.Y); + gr.DrawLine(p3, bounds.X, bounds.Bottom, bounds.Right, bounds.Bottom); + gr.DrawLine(p3, bounds.Right - 1, bounds.Y, bounds.Right - 1, bounds.Bottom - 1); + gr.DrawLine(p1, bounds.Left, bounds.Y + 1, bounds.Left, bounds.Bottom - 2); + gr.DrawLine(p2, bounds.Right - 2, bounds.Y + 1, bounds.Right - 2, bounds.Bottom - 2); + gr.DrawLine(p2, bounds.X, bounds.Bottom - 1, bounds.Right - 2, bounds.Bottom - 1); + } + } + } + + #endregion + + #region Events + + public event EventHandler HeaderChanged; + private void OnHeaderChanged() + { + if (HeaderChanged != null) + HeaderChanged(this, EventArgs.Empty); + } + + public event EventHandler SortOrderChanged; + private void OnSortOrderChanged() + { + if (SortOrderChanged != null) + SortOrderChanged(this, EventArgs.Empty); + } + + public event EventHandler IsVisibleChanged; + private void OnIsVisibleChanged() + { + if (IsVisibleChanged != null) + IsVisibleChanged(this, EventArgs.Empty); + } + + public event EventHandler WidthChanged; + private void OnWidthChanged() + { + if (WidthChanged != null) + WidthChanged(this, EventArgs.Empty); + } + + #endregion + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/TreeColumnCollection.cs b/branches/ph-plugins/TreeViewAdv/Tree/TreeColumnCollection.cs new file mode 100644 index 000000000..431af4ce9 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/TreeColumnCollection.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Windows.Forms; + +namespace Aga.Controls.Tree +{ + internal class TreeColumnCollection : Collection + { + private TreeViewAdv _treeView; + + public TreeColumnCollection(TreeViewAdv treeView) + { + _treeView = treeView; + } + + protected override void InsertItem(int index, TreeColumn item) + { + base.InsertItem(index, item); + BindEvents(item); + _treeView.UpdateColumns(); + } + + protected override void RemoveItem(int index) + { + UnbindEvents(this[index]); + base.RemoveItem(index); + _treeView.UpdateColumns(); + } + + protected override void SetItem(int index, TreeColumn item) + { + UnbindEvents(this[index]); + base.SetItem(index, item); + item.Owner = this; + BindEvents(item); + _treeView.UpdateColumns(); + } + + protected override void ClearItems() + { + foreach (TreeColumn c in Items) + UnbindEvents(c); + Items.Clear(); + _treeView.UpdateColumns(); + } + + private void BindEvents(TreeColumn item) + { + item.Owner = this; + item.HeaderChanged += HeaderChanged; + item.IsVisibleChanged += IsVisibleChanged; + item.WidthChanged += WidthChanged; + item.SortOrderChanged += SortOrderChanged; + } + + private void UnbindEvents(TreeColumn item) + { + item.Owner = null; + item.HeaderChanged -= HeaderChanged; + item.IsVisibleChanged -= IsVisibleChanged; + item.WidthChanged -= WidthChanged; + item.SortOrderChanged -= SortOrderChanged; + } + + void SortOrderChanged(object sender, EventArgs e) + { + TreeColumn changed = sender as TreeColumn; + //Only one column at a time can have a sort property set + if (changed.SortOrder != SortOrder.None) + { + foreach (TreeColumn col in this) + { + if (col != changed) + col.SortOrder = SortOrder.None; + } + } + _treeView.UpdateHeaders(); + _treeView.InvalidateNodeControlCache(); + } + + void WidthChanged(object sender, EventArgs e) + { + _treeView.InvalidateNodeControlCache(); + _treeView.ChangeColumnWidth(sender as TreeColumn); + } + + void IsVisibleChanged(object sender, EventArgs e) + { + _treeView.FullUpdate(); + } + + void HeaderChanged(object sender, EventArgs e) + { + _treeView.UpdateView(); + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/TreeColumnEventArgs.cs b/branches/ph-plugins/TreeViewAdv/Tree/TreeColumnEventArgs.cs new file mode 100644 index 000000000..0c616a095 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/TreeColumnEventArgs.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Aga.Controls.Tree +{ + public class TreeColumnEventArgs: EventArgs + { + private TreeColumn _column; + public TreeColumn Column + { + get { return _column; } + } + + public TreeColumnEventArgs(TreeColumn column) + { + _column = column; + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/TreeListAdapter.cs b/branches/ph-plugins/TreeViewAdv/Tree/TreeListAdapter.cs new file mode 100644 index 000000000..f53a5d325 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/TreeListAdapter.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Aga.Controls.Tree +{ + /// + /// Converts IEnumerable interface to ITreeModel. + /// Allows to display a plain list in the TreeView + /// + public class TreeListAdapter : ITreeModel + { + private System.Collections.IEnumerable _list; + + public TreeListAdapter(System.Collections.IEnumerable list) + { + _list = list; + } + + #region ITreeModel Members + + public System.Collections.IEnumerable GetChildren(TreePath treePath) + { + if (treePath.IsEmpty()) + return _list; + else + return null; + } + + public bool IsLeaf(TreePath treePath) + { + return true; + } + + public event EventHandler NodesChanged; + public void OnNodesChanged(TreeModelEventArgs args) + { + if (NodesChanged != null) + NodesChanged(this, args); + } + + public event EventHandler StructureChanged; + public void OnStructureChanged(TreePathEventArgs args) + { + if (StructureChanged != null) + StructureChanged(this, args); + } + + public event EventHandler NodesInserted; + public void OnNodeInserted(TreeModelEventArgs args) + { + if (NodesInserted != null) + NodesInserted(this, args); + } + + public event EventHandler NodesRemoved; + public void OnNodeRemoved(TreeModelEventArgs args) + { + if (NodesRemoved != null) + NodesRemoved(this, args); + } + + #endregion + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/TreeModel.cs b/branches/ph-plugins/TreeViewAdv/Tree/TreeModel.cs new file mode 100644 index 000000000..44a3ddb85 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/TreeModel.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Collections.ObjectModel; + +namespace Aga.Controls.Tree +{ + /// + /// Provides a simple ready to use implementation of ITreeModel. Warning: this class is not optimized + /// to work with big amount of data. In this case create you own implementation of ITreeModel, and pay attention + /// on GetChildren and IsLeaf methods. + /// + public class TreeModel : ITreeModel + { + private Node _root; + public Node Root + { + get { return _root; } + } + + public Collection Nodes + { + get { return _root.Nodes; } + } + + public TreeModel() + { + _root = new Node(); + _root.Model = this; + } + + public TreePath GetPath(Node node) + { + if (node == _root) + return TreePath.Empty; + else + { + Stack stack = new Stack(); + while (node != _root) + { + stack.Push(node); + node = node.Parent; + } + return new TreePath(stack.ToArray()); + } + } + + public Node FindNode(TreePath path) + { + if (path.IsEmpty()) + return _root; + else + return FindNode(_root, path, 0); + } + + private Node FindNode(Node root, TreePath path, int level) + { + foreach (Node node in root.Nodes) + if (node == path.FullPath[level]) + { + if (level == path.FullPath.Length - 1) + return node; + else + return FindNode(node, path, level + 1); + } + return null; + } + + #region ITreeModel Members + + public System.Collections.IEnumerable GetChildren(TreePath treePath) + { + Node node = FindNode(treePath); + if (node != null) + foreach (Node n in node.Nodes) + yield return n; + else + yield break; + } + + public bool IsLeaf(TreePath treePath) + { + Node node = FindNode(treePath); + if (node != null) + return node.IsLeaf; + else + throw new ArgumentException("treePath"); + } + + public event EventHandler NodesChanged; + internal void OnNodesChanged(TreeModelEventArgs args) + { + if (NodesChanged != null) + NodesChanged(this, args); + } + + public event EventHandler StructureChanged; + public void OnStructureChanged(TreePathEventArgs args) + { + if (StructureChanged != null) + StructureChanged(this, args); + } + + public event EventHandler NodesInserted; + internal void OnNodeInserted(Node parent, int index, Node node) + { + if (NodesInserted != null) + { + TreeModelEventArgs args = new TreeModelEventArgs(GetPath(parent), new int[] { index }, new object[] { node }); + NodesInserted(this, args); + } + + } + + public event EventHandler NodesRemoved; + internal void OnNodeRemoved(Node parent, int index, Node node) + { + if (NodesRemoved != null) + { + TreeModelEventArgs args = new TreeModelEventArgs(GetPath(parent), new int[] { index }, new object[] { node }); + NodesRemoved(this, args); + } + } + + #endregion + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/TreeModelBase.cs b/branches/ph-plugins/TreeViewAdv/Tree/TreeModelBase.cs new file mode 100644 index 000000000..abebd815f --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/TreeModelBase.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Aga.Controls.Tree +{ + public abstract class TreeModelBase: ITreeModel + { + public abstract System.Collections.IEnumerable GetChildren(TreePath treePath); + public abstract bool IsLeaf(TreePath treePath); + + + public event EventHandler NodesChanged; + protected void OnNodesChanged(TreeModelEventArgs args) + { + if (NodesChanged != null) + NodesChanged(this, args); + } + + public event EventHandler StructureChanged; + protected void OnStructureChanged(TreePathEventArgs args) + { + if (StructureChanged != null) + StructureChanged(this, args); + } + + public event EventHandler NodesInserted; + protected void OnNodesInserted(TreeModelEventArgs args) + { + if (NodesInserted != null) + NodesInserted(this, args); + } + + public event EventHandler NodesRemoved; + protected void OnNodesRemoved(TreeModelEventArgs args) + { + if (NodesRemoved != null) + NodesRemoved(this, args); + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/TreeModelEventArgs.cs b/branches/ph-plugins/TreeViewAdv/Tree/TreeModelEventArgs.cs new file mode 100644 index 000000000..f8abe4053 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/TreeModelEventArgs.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Aga.Controls.Tree +{ + public class TreeModelEventArgs: TreePathEventArgs + { + private object[] _children; + public object[] Children + { + get { return _children; } + } + + private int[] _indices; + public int[] Indices + { + get { return _indices; } + } + + /// + /// + /// + /// Path to a parent node + /// Child nodes + public TreeModelEventArgs(TreePath parent, object[] children) + : this(parent, null, children) + { + } + + /// + /// + /// + /// Path to a parent node + /// Indices of children in parent nodes collection + /// Child nodes + public TreeModelEventArgs(TreePath parent, int[] indices, object[] children) + : base(parent) + { + if (children == null) + throw new ArgumentNullException(); + + if (indices != null && indices.Length != children.Length) + throw new ArgumentException("indices and children arrays must have the same length"); + + _indices = indices; + _children = children; + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/TreeNodeAdv.cs b/branches/ph-plugins/TreeViewAdv/Tree/TreeNodeAdv.cs new file mode 100644 index 000000000..dcb588d47 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/TreeNodeAdv.cs @@ -0,0 +1,493 @@ +/* + * Modified by wj32. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Collections.ObjectModel; +using System.Drawing; +using System.Windows.Forms; +using System.Runtime.Serialization; +using System.Security.Permissions; + +namespace Aga.Controls.Tree +{ + [Serializable] + public sealed class TreeNodeAdv : ISerializable + { + static TreeNodeAdv() + { + StateColors.Add(NodeState.Normal, SystemColors.Window); + StateColors.Add(NodeState.New, Color.Green); + StateColors.Add(NodeState.Removed, Color.Red); + } + + #region NodeCollection + private class NodeCollection : Collection + { + private TreeNodeAdv _owner; + + public NodeCollection(TreeNodeAdv owner) + { + _owner = owner; + } + + protected override void ClearItems() + { + while (this.Count != 0) + this.RemoveAt(this.Count - 1); + } + + protected override void InsertItem(int index, TreeNodeAdv item) + { + if (item == null) + throw new ArgumentNullException("item"); + + if (item.Parent != _owner) + { + if (item.Parent != null) + item.Parent.Nodes.Remove(item); + item._parent = _owner; + item._index = index; + for (int i = index; i < Count; i++) + this[i]._index++; + base.InsertItem(index, item); + } + } + + protected override void RemoveItem(int index) + { + TreeNodeAdv item = this[index]; + item._parent = null; + item._index = -1; + for (int i = index + 1; i < Count; i++) + this[i]._index--; + base.RemoveItem(index); + } + + protected override void SetItem(int index, TreeNodeAdv item) + { + if (item == null) + throw new ArgumentNullException("item"); + RemoveAt(index); + InsertItem(index, item); + } + } + #endregion + + #region Properties + + private TreeViewAdv _tree; + internal TreeViewAdv Tree + { + get { return _tree; } + } + + private int _row; + internal int Row + { + get { return _row; } + set { _row = value; } + } + + private int _index = -1; + public int Index + { + get + { + return _index; + } + } + + public enum NodeState + { + Normal, New, Removed + } + + public static Dictionary StateColors = new Dictionary(); + + private NodeState _state = NodeState.Normal; + + public NodeState State + { + get { return _state; } + set + { + _state = value; + if (_automaticForeColor) + _autoForeColor = GetForeColor(this.BackColor); + } + } + + private Color _backColor = SystemColors.Window; + public Color BackColor + { + get + { + if (_state != NodeState.Normal) + return StateColors[_state]; + else + return _backColor; + } + set + { + _backColor = value; + if (_automaticForeColor) + _autoForeColor = GetForeColor(this.BackColor); + } + } + + private Color _autoForeColor = Color.Black; + private Color _foreColor = SystemColors.ControlText; + public Color ForeColor + { + get + { + if (_automaticForeColor) + return _autoForeColor; + else + return _foreColor; + } + set { _foreColor = value; } + } + + private bool _automaticForeColor = true; + public bool AutomaticForeColor + { + get { return _automaticForeColor; } + set + { + _automaticForeColor = value; + if (_automaticForeColor) + _autoForeColor = GetForeColor(this.BackColor); + } + } + + public static Color GetForeColor(Color color) + { + if (color.GetBrightness() > 0.4) + return Color.Black; + else + return Color.White; + } + + private bool _isSelected; + public bool IsSelected + { + get { return _isSelected; } + set + { + if (_isSelected != value) + { + if (Tree.IsMyNode(this)) + { + //_tree.OnSelectionChanging + if (value) + { + if (!_tree.Selection.Contains(this)) + _tree.Selection.Add(this); + + if (_tree.Selection.Count == 1) + _tree.CurrentNode = this; + } + else + _tree.Selection.Remove(this); + _tree.UpdateView(); + _tree.OnSelectionChanged(); + } + _isSelected = value; + } + } + } + + /// + /// Returns true if all parent nodes of this node are expanded. + /// + internal bool IsVisible + { + get + { + TreeNodeAdv node = _parent; + while (node != null) + { + if (!node.IsExpanded) + return false; + node = node.Parent; + } + return true; + } + } + + private bool _isLeaf; + public bool IsLeaf + { + get { return _isLeaf; } + internal set { _isLeaf = value; } + } + + private bool _isExpandedOnce; + public bool IsExpandedOnce + { + get { return _isExpandedOnce; } + internal set { _isExpandedOnce = value; } + } + + private bool _isExpanded; + public bool IsExpanded + { + get { return _isExpanded; } + set + { + if (value) + Expand(); + else + Collapse(); + } + } + + internal void AssignIsExpanded(bool value) + { + _isExpanded = value; + } + + private TreeNodeAdv _parent; + public TreeNodeAdv Parent + { + get { return _parent; } + } + + public int Level + { + get + { + if (_parent == null) + return 0; + else + return _parent.Level + 1; + } + } + + public TreeNodeAdv NextNode + { + get + { + if (_parent != null) + { + int index = Index; + if (index < _parent.Nodes.Count - 1) + return _parent.Nodes[index + 1]; + } + return null; + } + } + + internal TreeNodeAdv BottomNode + { + get + { + TreeNodeAdv parent = this.Parent; + if (parent != null) + { + if (parent.NextNode != null) + return parent.NextNode; + else + return parent.BottomNode; + } + return null; + } + } + + internal TreeNodeAdv NextVisibleNode + { + get + { + if (IsExpanded && Nodes.Count > 0) + return Nodes[0]; + else + { + TreeNodeAdv nn = NextNode; + if (nn != null) + return nn; + else + return BottomNode; + } + } + } + + public bool CanExpand + { + get + { + return (Nodes.Count > 0 || (!IsExpandedOnce && !IsLeaf)); + } + } + + private object _tag; + public object Tag + { + get { return _tag; } + } + + private Collection _nodes; + internal Collection Nodes + { + get { return _nodes; } + } + + private ReadOnlyCollection _children; + public ReadOnlyCollection Children + { + get + { + return _children; + } + } + + private int? _rightBounds; + internal int? RightBounds + { + get { return _rightBounds; } + set { _rightBounds = value; } + } + + private int? _height; + internal int? Height + { + get { return _height; } + set { _height = value; } + } + + private bool _isExpandingNow; + internal bool IsExpandingNow + { + get { return _isExpandingNow; } + set { _isExpandingNow = value; } + } + + #endregion + + public TreeNodeAdv(object tag): this(null, tag) + { + } + + internal TreeNodeAdv(TreeViewAdv tree, object tag) + { + _row = -1; + _tree = tree; + _nodes = new NodeCollection(this); + _children = new ReadOnlyCollection(_nodes); + _tag = tag; + } + + public override string ToString() + { + if (Tag != null) + return Tag.ToString(); + else + return base.ToString(); + } + + public void Collapse() + { + if (_isExpanded) + Collapse(true); + } + + public void CollapseAll() + { + Collapse(false); + } + + public void Collapse(bool ignoreChildren) + { + SetIsExpanded(false, ignoreChildren); + } + + public void EnsureVisible() + { + TreeNodeAdv parent = this.Parent; + + while (parent != _tree.Root) + { + parent.Expand(); + parent = parent.Parent; + } + + _tree.ScrollTo(this); + } + + public void EnsureVisible2() + { + TreeNodeAdv parent = this.Parent; + + while (parent != _tree.Root) + { + parent.Expand(); + parent = parent.Parent; + } + + _tree.ScrollTo2(this); + } + + public void Expand() + { + if (!_isExpanded) + Expand(true); + } + + public void ExpandAll() + { + Expand(false); + } + + public void Expand(bool ignoreChildren) + { + SetIsExpanded(true, ignoreChildren); + } + + private void SetIsExpanded(bool value, bool ignoreChildren) + { + if (Tree == null) + { + _isExpanded = value; + if (!ignoreChildren) + Tree.SetIsExpandedRecursive(this, value); + } + else + Tree.SetIsExpanded(this, value, ignoreChildren); + } + + #region ISerializable Members + + private TreeNodeAdv(SerializationInfo info, StreamingContext context): this(null, null) + { + int nodesCount = 0; + nodesCount = info.GetInt32("NodesCount"); + _isExpanded = info.GetBoolean("IsExpanded"); + _tag = info.GetValue("Tag", typeof(object)); + + for (int i = 0; i < nodesCount; i++) + { + TreeNodeAdv child = (TreeNodeAdv)info.GetValue("Child" + i, typeof(TreeNodeAdv)); + Nodes.Add(child); + } + + } + + [SecurityPermission(SecurityAction.Demand, SerializationFormatter=true)] + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + info.AddValue("IsExpanded", IsExpanded); + info.AddValue("NodesCount", Nodes.Count); + if ((Tag != null) && Tag.GetType().IsSerializable) + info.AddValue("Tag", Tag, Tag.GetType()); + + for (int i = 0; i < Nodes.Count; i++) + info.AddValue("Child" + i, Nodes[i], typeof(TreeNodeAdv)); + + } + + #endregion + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/TreeNodeAdvMouseEventArgs.cs b/branches/ph-plugins/TreeViewAdv/Tree/TreeNodeAdvMouseEventArgs.cs new file mode 100644 index 000000000..79d7b20b2 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/TreeNodeAdvMouseEventArgs.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows.Forms; +using System.Drawing; +using Aga.Controls.Tree.NodeControls; + +namespace Aga.Controls.Tree +{ + public class TreeNodeAdvMouseEventArgs : MouseEventArgs + { + private TreeNodeAdv _node; + public TreeNodeAdv Node + { + get { return _node; } + internal set { _node = value; } + } + + private NodeControl _control; + public NodeControl Control + { + get { return _control; } + internal set { _control = value; } + } + + private Point _viewLocation; + public Point ViewLocation + { + get { return _viewLocation; } + internal set { _viewLocation = value; } + } + + private Keys _modifierKeys; + public Keys ModifierKeys + { + get { return _modifierKeys; } + internal set { _modifierKeys = value; } + } + + private bool _handled; + public bool Handled + { + get { return _handled; } + set { _handled = value; } + } + + private Rectangle _controlBounds; + public Rectangle ControlBounds + { + get { return _controlBounds; } + internal set { _controlBounds = value; } + } + + public TreeNodeAdvMouseEventArgs(MouseEventArgs args) + : base(args.Button, args.Clicks, args.X, args.Y, args.Delta) + { + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/TreePath.cs b/branches/ph-plugins/TreeViewAdv/Tree/TreePath.cs new file mode 100644 index 000000000..a0360f1ac --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/TreePath.cs @@ -0,0 +1,60 @@ +using System; +using System.Text; +using System.Collections.ObjectModel; + +namespace Aga.Controls.Tree +{ + public class TreePath + { + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")] + public static readonly TreePath Empty = new TreePath(); + + private object[] _path; + public object[] FullPath + { + get { return _path; } + } + + public object LastNode + { + get + { + if (_path.Length > 0) + return _path[_path.Length - 1]; + else + return null; + } + } + + public object FirstNode + { + get + { + if (_path.Length > 0) + return _path[0]; + else + return null; + } + } + + public TreePath() + { + _path = new object[0]; + } + + public TreePath(object node) + { + _path = new object[] { node }; + } + + public TreePath(object[] path) + { + _path = path; + } + + public bool IsEmpty() + { + return (_path.Length == 0); + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/TreePathEventArgs.cs b/branches/ph-plugins/TreeViewAdv/Tree/TreePathEventArgs.cs new file mode 100644 index 000000000..70e4ff933 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/TreePathEventArgs.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Aga.Controls.Tree +{ + public class TreePathEventArgs : EventArgs + { + private TreePath _path; + public TreePath Path + { + get { return _path; } + } + + public TreePathEventArgs() + { + _path = new TreePath(); + } + + public TreePathEventArgs(TreePath path) + { + if (path == null) + throw new ArgumentNullException(); + + _path = path; + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/TreeViewAdv.Designer.cs b/branches/ph-plugins/TreeViewAdv/Tree/TreeViewAdv.Designer.cs new file mode 100644 index 000000000..68d7cdc4e --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/TreeViewAdv.Designer.cs @@ -0,0 +1,58 @@ +using System.Windows.Forms; + +namespace Aga.Controls.Tree +{ + partial class TreeViewAdv + { + private System.ComponentModel.IContainer components = null; + + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + private void InitializeComponent() + { + this._vScrollBar = new System.Windows.Forms.VScrollBar(); + this._hScrollBar = new System.Windows.Forms.HScrollBar(); + this.SuspendLayout(); + // + // _vScrollBar + // + this._vScrollBar.LargeChange = 1; + this._vScrollBar.Location = new System.Drawing.Point(0, 0); + this._vScrollBar.Maximum = 0; + this._vScrollBar.Name = "_vScrollBar"; + this._vScrollBar.Size = new System.Drawing.Size(13, 80); + this._vScrollBar.TabIndex = 1; + this._vScrollBar.ValueChanged += new System.EventHandler(this._vScrollBar_ValueChanged); + // + // _hScrollBar + // + this._hScrollBar.LargeChange = 1; + this._hScrollBar.Location = new System.Drawing.Point(0, 0); + this._hScrollBar.Maximum = 0; + this._hScrollBar.Name = "_hScrollBar"; + this._hScrollBar.Size = new System.Drawing.Size(80, 13); + this._hScrollBar.TabIndex = 2; + this._hScrollBar.ValueChanged += new System.EventHandler(this._hScrollBar_ValueChanged); + // + // TreeViewAdv + // + this.BackColor = System.Drawing.SystemColors.Window; + this.Controls.Add(this._vScrollBar); + this.Controls.Add(this._hScrollBar); + this.ResumeLayout(false); + + } + #endregion + + private VScrollBar _vScrollBar; + private HScrollBar _hScrollBar; + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/TreeViewAdv.Draw.cs b/branches/ph-plugins/TreeViewAdv/Tree/TreeViewAdv.Draw.cs new file mode 100644 index 000000000..a470157f5 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/TreeViewAdv.Draw.cs @@ -0,0 +1,261 @@ +/* + * Modified by wj32. + */ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows.Forms; +using System.Drawing; +using System.Windows.Forms.VisualStyles; +using System.Diagnostics; +using System.Drawing.Drawing2D; +using Aga.Controls.Tree.NodeControls; + +namespace Aga.Controls.Tree +{ + public partial class TreeViewAdv + { + private void CreatePens() + { + CreateLinePen(); + CreateMarkPen(); + } + + private void CreateMarkPen() + { + GraphicsPath path = new GraphicsPath(); + path.AddLines(new Point[] { new Point(0, 0), new Point(1, 1), new Point(-1, 1), new Point(0, 0) }); + CustomLineCap cap = new CustomLineCap(null, path); + cap.WidthScale = 1.0f; + + _markPen = new Pen(_dragDropMarkColor, _dragDropMarkWidth); + _markPen.CustomStartCap = cap; + _markPen.CustomEndCap = cap; + } + + private void CreateLinePen() + { + _linePen = new Pen(_lineColor); + _linePen.DashStyle = DashStyle.Dot; + } + + protected override void OnPaint(PaintEventArgs e) + { + DrawContext context = new DrawContext(); + context.Graphics = e.Graphics; + context.Font = this.Font; + context.Enabled = Enabled; + + int y = 0; + int gridHeight = 0; + + if (UseColumns) + { + DrawColumnHeaders(e.Graphics); + y += ColumnHeaderHeight; + if (Columns.Count == 0 || e.ClipRectangle.Height <= y) + return; + } + + int firstRowY = _rowLayout.GetRowBounds(FirstVisibleRow).Y; + y -= firstRowY; + + e.Graphics.ResetTransform(); + e.Graphics.TranslateTransform(-OffsetX, y); + Rectangle displayRect = DisplayRectangle; + for (int row = FirstVisibleRow; row < RowCount; row++) + { + Rectangle rowRect = _rowLayout.GetRowBounds(row); + gridHeight += rowRect.Height; + if (rowRect.Y + y > displayRect.Bottom) + break; + else + DrawRow(e, ref context, row, rowRect); + } + + if ((GridLineStyle & GridLineStyle.Vertical) == GridLineStyle.Vertical && UseColumns) + DrawVerticalGridLines(e.Graphics, firstRowY); + + if (_dropPosition.Node != null && DragMode && HighlightDropPosition) + DrawDropMark(e.Graphics); + + e.Graphics.ResetTransform(); + DrawScrollBarsBox(e.Graphics); + + if (DragMode && _dragBitmap != null) + e.Graphics.DrawImage(_dragBitmap, PointToClient(MousePosition)); + } + + private void DrawRow(PaintEventArgs e, ref DrawContext context, int row, Rectangle rowRect) + { + TreeNodeAdv node = RowMap[row]; + context.DrawSelection = DrawSelectionMode.None; + context.CurrentEditorOwner = _currentEditorOwner; + + if (DragMode) + { + if ((_dropPosition.Node == node) && _dropPosition.Position == NodePosition.Inside && HighlightDropPosition) + context.DrawSelection = DrawSelectionMode.Active; + } + else + { + if (node.IsSelected && Focused) + context.DrawSelection = DrawSelectionMode.Active; + else if (node.IsSelected && !Focused && !HideSelection) + context.DrawSelection = DrawSelectionMode.Inactive; + } + + context.DrawFocus = Focused && CurrentNode == node; + + Rectangle focusRect = new Rectangle(OffsetX, rowRect.Y, ClientRectangle.Width, rowRect.Height); + + if (!FullRowSelect || (FullRowSelect && + context.DrawSelection != DrawSelectionMode.Active && + context.DrawSelection != DrawSelectionMode.Inactive)) + e.Graphics.FillRectangle(new SolidBrush(node.BackColor), focusRect); + + if (FullRowSelect) + { + context.DrawFocus = false; + + if (context.DrawSelection == DrawSelectionMode.Active || context.DrawSelection == DrawSelectionMode.Inactive) + { + if (context.DrawSelection == DrawSelectionMode.Active) + { + e.Graphics.FillRectangle(SystemBrushes.Highlight, focusRect); + context.DrawSelection = DrawSelectionMode.FullRowSelect; + } + else + { + e.Graphics.FillRectangle(SystemBrushes.InactiveBorder, focusRect); + context.DrawSelection = DrawSelectionMode.None; + } + } + } + + if ((GridLineStyle & GridLineStyle.Horizontal) == GridLineStyle.Horizontal) + e.Graphics.DrawLine(SystemPens.InactiveBorder, 0, rowRect.Bottom, e.Graphics.ClipBounds.Right, rowRect.Bottom); + + if (ShowLines) + DrawLines(e.Graphics, node, rowRect); + + DrawNode(node, context); + } + + private void DrawVerticalGridLines(Graphics gr, int y) + { + int x = 0; + foreach (TreeColumn c in Columns) + { + if (c.IsVisible) + { + x += c.Width; + gr.DrawLine(SystemPens.InactiveBorder, x - 1, y, x - 1, gr.ClipBounds.Bottom); + } + } + } + + private void DrawColumnHeaders(Graphics gr) + { + ReorderColumnState reorder = Input as ReorderColumnState; + int x = 0; + TreeColumn.DrawBackground(gr, new Rectangle(0, 0, ClientRectangle.Width + 2, ColumnHeaderHeight - 1), false, false); + gr.TranslateTransform(-OffsetX, 0); + foreach (TreeColumn c in Columns) + { + if (c.IsVisible) + { + if (x + c.Width >= OffsetX && x - OffsetX < this.Bounds.Width)// skip invisible columns (fixed by wj32) + { + Rectangle rect = new Rectangle(x, 0, c.Width, ColumnHeaderHeight - 1); + gr.SetClip(rect); + bool pressed = ((Input is ClickColumnState || reorder != null) && ((Input as ColumnState).Column == c)); + c.Draw(gr, rect, Font, pressed, _hotColumn == c); + gr.ResetClip(); + + if (reorder != null && reorder.DropColumn == c) + TreeColumn.DrawDropMark(gr, rect); + } + x += c.Width; + } + } + + if (reorder != null) + { + if (reorder.DropColumn == null) + TreeColumn.DrawDropMark(gr, new Rectangle(x, 0, 0, ColumnHeaderHeight)); + gr.DrawImage(reorder.GhostImage, new Point(reorder.Location.X + + reorder.DragOffset, reorder.Location.Y)); + } + } + + public void DrawNode(TreeNodeAdv node, DrawContext context) + { + foreach (NodeControlInfo item in GetNodeControls(node)) + { + if (item.Bounds.X + item.Bounds.Width >= OffsetX && + item.Bounds.X - OffsetX < this.Bounds.Width)// skip invisible nodes (fixed by wj32) + { + context.Bounds = item.Bounds; + context.Graphics.SetClip(context.Bounds); + item.Control.Draw(node, context); + context.Graphics.ResetClip(); + } + } + } + + private void DrawScrollBarsBox(Graphics gr) + { + Rectangle r1 = DisplayRectangle; + Rectangle r2 = ClientRectangle; + gr.FillRectangle(SystemBrushes.Control, + new Rectangle(r1.Right, r1.Bottom, r2.Width - r1.Width, r2.Height - r1.Height)); + } + + private void DrawDropMark(Graphics gr) + { + if (_dropPosition.Position == NodePosition.Inside) + return; + + Rectangle rect = GetNodeBounds(_dropPosition.Node); + int right = DisplayRectangle.Right - LeftMargin + OffsetX; + int y = rect.Y; + if (_dropPosition.Position == NodePosition.After) + y = rect.Bottom; + gr.DrawLine(_markPen, rect.X, y, right, y); + } + + private void DrawLines(Graphics gr, TreeNodeAdv node, Rectangle rowRect) + { + if (UseColumns && Columns.Count > 0) + gr.SetClip(new Rectangle(0, rowRect.Y, Columns[0].Width, rowRect.Bottom)); + + TreeNodeAdv curNode = node; + while (curNode != _root && curNode != null) + { + int level = curNode.Level; + int x = (level - 1) * _indent + NodePlusMinus.ImageSize / 2 + LeftMargin; + int width = NodePlusMinus.Width - NodePlusMinus.ImageSize / 2; + int y = rowRect.Y; + int y2 = y + rowRect.Height; + + if (curNode == node) + { + int midy = y + rowRect.Height / 2; + gr.DrawLine(_linePen, x, midy, x + width, midy); + if (curNode.NextNode == null) + y2 = y + rowRect.Height / 2; + } + + if (node.Row == 0) + y = rowRect.Height / 2; + if (curNode.NextNode != null || curNode == node) + gr.DrawLine(_linePen, x, y, x, y2); + + curNode = curNode.Parent; + } + + gr.ResetClip(); + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/TreeViewAdv.Input.cs b/branches/ph-plugins/TreeViewAdv/Tree/TreeViewAdv.Input.cs new file mode 100644 index 000000000..99ab5ac5c --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/TreeViewAdv.Input.cs @@ -0,0 +1,555 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows.Forms; +using System.Drawing; +using Aga.Controls.Tree.NodeControls; +using System.Drawing.Imaging; +using System.Threading; + +namespace Aga.Controls.Tree +{ + public partial class TreeViewAdv + { + // Note by wj32: I've added a whole bunch of this.Invalidate()s that are necessary for PH. + #region Keys + + protected override bool IsInputChar(char charCode) + { + return true; + } + + protected override bool IsInputKey(Keys keyData) + { + if (((keyData & Keys.Up) == Keys.Up) + || ((keyData & Keys.Down) == Keys.Down) + || ((keyData & Keys.Left) == Keys.Left) + || ((keyData & Keys.Right) == Keys.Right)) + return true; + else + return base.IsInputKey(keyData); + } + + internal void ChangeInput() + { + if ((ModifierKeys & Keys.Shift) == Keys.Shift) + { + if (!(Input is InputWithShift)) + Input = new InputWithShift(this); + } + else if ((ModifierKeys & Keys.Control) == Keys.Control) + { + if (!(Input is InputWithControl)) + Input = new InputWithControl(this); + } + else + { + if (!(Input.GetType() == typeof(NormalInputState))) + Input = new NormalInputState(this); + } + } + + protected override void OnKeyDown(KeyEventArgs e) + { + base.OnKeyDown(e); + if (!e.Handled) + { + if (e.KeyCode == Keys.ShiftKey || e.KeyCode == Keys.ControlKey) + ChangeInput(); + Input.KeyDown(e); + if (!e.Handled) + { + foreach (NodeControlInfo item in GetNodeControls(CurrentNode)) + { + item.Control.KeyDown(e); + if (e.Handled) + break; + } + } + } + this.Invalidate(); + } + + protected override void OnKeyUp(KeyEventArgs e) + { + base.OnKeyUp(e); + if (!e.Handled) + { + if (e.KeyCode == Keys.ShiftKey || e.KeyCode == Keys.ControlKey) + ChangeInput(); + if (!e.Handled) + { + foreach (NodeControlInfo item in GetNodeControls(CurrentNode)) + { + item.Control.KeyUp(e); + if (e.Handled) + return; + } + } + } + } + + protected override void OnKeyPress(KeyPressEventArgs e) + { + base.OnKeyPress(e); + if (!e.Handled) + _search.Search(e.KeyChar); + this.Invalidate(); + } + + #endregion + + #region Mouse + + private TreeNodeAdvMouseEventArgs CreateMouseArgs(MouseEventArgs e) + { + TreeNodeAdvMouseEventArgs args = new TreeNodeAdvMouseEventArgs(e); + args.ViewLocation = new Point(e.X + OffsetX, + e.Y + _rowLayout.GetRowBounds(FirstVisibleRow).Y - ColumnHeaderHeight); + args.ModifierKeys = ModifierKeys; + args.Node = GetNodeAt(e.Location); + NodeControlInfo info = GetNodeControlInfoAt(args.Node, e.Location); + args.ControlBounds = info.Bounds; + args.Control = info.Control; + return args; + } + + protected override void OnMouseWheel(MouseEventArgs e) + { + _search.EndSearch(); + if (SystemInformation.MouseWheelScrollLines > 0) + { + int lines = e.Delta / 120 * SystemInformation.MouseWheelScrollLines; + int newValue = _vScrollBar.Value - lines; + newValue = Math.Min(_vScrollBar.Maximum - _vScrollBar.LargeChange + 1, newValue); + newValue = Math.Min(_vScrollBar.Maximum, newValue); + _vScrollBar.Value = Math.Max(_vScrollBar.Minimum, newValue); + } + base.OnMouseWheel(e); + } + + protected override void OnMouseDown(MouseEventArgs e) + { + if (!Focused) + Focus(); + + _search.EndSearch(); + if (e.Button == MouseButtons.Left) + { + TreeColumn c; + c = GetColumnDividerAt(e.Location); + if (c != null) + { + Input = new ResizeColumnState(this, c, e.Location); + this.Invalidate(); + return; + } + c = GetColumnAt(e.Location); + if (c != null) + { + Input = new ClickColumnState(this, c, e.Location); + UpdateView(); + this.Invalidate(); + return; + } + } + + ChangeInput(); + TreeNodeAdvMouseEventArgs args = CreateMouseArgs(e); + + if (args.Node != null && args.Control != null) + args.Control.MouseDown(args); + + if (!args.Handled) + Input.MouseDown(args); + + base.OnMouseDown(e); + this.Invalidate(); + } + + protected override void OnMouseClick(MouseEventArgs e) + { + //TODO: Disable when click on plusminus icon + TreeNodeAdvMouseEventArgs args = CreateMouseArgs(e); + if (args.Node != null) + OnNodeMouseClick(args); + + base.OnMouseClick(e); + this.FullUpdate(); + this.Invalidate(); + } + + protected override void OnMouseDoubleClick(MouseEventArgs e) + { + TreeNodeAdvMouseEventArgs args = CreateMouseArgs(e); + + if (args.Node != null && args.Control != null) + args.Control.MouseDoubleClick(args); + + if (!args.Handled) + { + // disabled by wj32 - I think this behaviour sucks. + //if (args.Node != null && args.Button == MouseButtons.Left) + // args.Node.IsExpanded = !args.Node.IsExpanded; + + if (args.Node != null) + OnNodeMouseDoubleClick(args); + } + + base.OnMouseDoubleClick(e); + } + + protected override void OnMouseUp(MouseEventArgs e) + { + TreeNodeAdvMouseEventArgs args = CreateMouseArgs(e); + if (Input is ResizeColumnState) + Input.MouseUp(args); + else + { + if (args.Node != null && args.Control != null) + args.Control.MouseUp(args); + if (!args.Handled) + Input.MouseUp(args); + + base.OnMouseUp(e); + } + } + + protected override void OnMouseMove(MouseEventArgs e) + { + if (Input.MouseMove(e)) + return; + + base.OnMouseMove(e); + SetCursor(e); + UpdateToolTip(e); + if (ItemDragMode && Dist(e.Location, ItemDragStart) > ItemDragSensivity + && CurrentNode != null && CurrentNode.IsSelected) + { + ItemDragMode = false; + _toolTip.Active = false; + OnItemDrag(e.Button, Selection.ToArray()); + } + } + + protected override void OnMouseLeave(EventArgs e) + { + _hotColumn = null; + UpdateHeaders(); + base.OnMouseLeave(e); + } + + private void SetCursor(MouseEventArgs e) + { + TreeColumn col; + col = GetColumnDividerAt(e.Location); + if (col == null) + _innerCursor = null; + else + { + if (col.Width == 0) + _innerCursor = ResourceHelper.DVSplitCursor; + else + _innerCursor = Cursors.VSplit; + } + + col = GetColumnAt(e.Location); + if (col != _hotColumn) + { + _hotColumn = col; + UpdateHeaders(); + } + } + + internal TreeColumn GetColumnAt(Point p) + { + if (p.Y > ColumnHeaderHeight) + return null; + + int x = -OffsetX; + foreach (TreeColumn col in Columns) + { + if (col.IsVisible) + { + Rectangle rect = new Rectangle(x, 0, col.Width, ColumnHeaderHeight); + x += col.Width; + if (rect.Contains(p)) + return col; + } + } + return null; + } + + internal int GetColumnX(TreeColumn column) + { + int x = -OffsetX; + foreach (TreeColumn col in Columns) + { + if (col.IsVisible) + { + if (column == col) + return x; + else + x += col.Width; + } + } + return x; + } + + internal TreeColumn GetColumnDividerAt(Point p) + { + if (p.Y > ColumnHeaderHeight) + return null; + + int x = -OffsetX; + TreeColumn prevCol = null; + Rectangle left, right; + foreach (TreeColumn col in Columns) + { + if (col.IsVisible) + { + if (col.Width > 0) + { + left = new Rectangle(x, 0, DividerWidth / 2, ColumnHeaderHeight); + right = new Rectangle(x + col.Width - (DividerWidth / 2), 0, DividerWidth / 2, ColumnHeaderHeight); + if (left.Contains(p) && prevCol != null) + return prevCol; + else if (right.Contains(p)) + return col; + } + prevCol = col; + x += col.Width; + } + } + + left = new Rectangle(x, 0, DividerWidth / 2, ColumnHeaderHeight); + if (left.Contains(p) && prevCol != null) + return prevCol; + + return null; + } + + TreeColumn _tooltipColumn; + private void UpdateToolTip(MouseEventArgs e) + { + TreeColumn col = GetColumnAt(e.Location); + if (col != null) + { + if (col != _tooltipColumn) + SetTooltip(col.TooltipText); + } + else + DisplayNodesTooltip(e); + _tooltipColumn = col; + } + + TreeNodeAdv _hotNode; + NodeControl _hotControl; + private void DisplayNodesTooltip(MouseEventArgs e) + { + if (ShowNodeToolTips) + { + TreeNodeAdvMouseEventArgs args = CreateMouseArgs(e); + if (args.Node != null && args.Control != null) + { + if (args.Node != _hotNode || args.Control != _hotControl) + SetTooltip(GetNodeToolTip(args)); + } + else + _toolTip.SetToolTip(this, null); + + _hotControl = args.Control; + _hotNode = args.Node; + } + else + _toolTip.SetToolTip(this, null); + } + + private void SetTooltip(string text) + { + if (!String.IsNullOrEmpty(text)) + { + _toolTip.Active = false; + _toolTip.SetToolTip(this, text); + _toolTip.Active = true; + } + else + _toolTip.SetToolTip(this, null); + } + + private string GetNodeToolTip(TreeNodeAdvMouseEventArgs args) + { + string msg = args.Control.GetToolTip(args.Node); + + BaseTextControl btc = args.Control as BaseTextControl; + if (btc != null && btc.DisplayHiddenContentInToolTip && String.IsNullOrEmpty(msg)) + { + Size ms = btc.GetActualSize(args.Node, _measureContext); + if (ms.Width > args.ControlBounds.Size.Width || ms.Height > args.ControlBounds.Size.Height + || args.ControlBounds.Right - OffsetX > DisplayRectangle.Width) + msg = btc.GetLabel(args.Node); + } + + if (String.IsNullOrEmpty(msg) && DefaultToolTipProvider != null) + msg = DefaultToolTipProvider.GetToolTip(args.Node, args.Control); + + return msg; + } + + #endregion + + #region DragDrop + + private bool _dragAutoScrollFlag = false; + private Bitmap _dragBitmap = null; + private System.Threading.Timer _dragTimer; + + private void StartDragTimer() + { + if (_dragTimer == null) + _dragTimer = new System.Threading.Timer(new TimerCallback(DragTimerTick), null, 0, 100); + } + + private void StopDragTimer() + { + if (_dragTimer != null) + { + _dragTimer.Dispose(); + _dragTimer = null; + } + } + + private void SetDropPosition(Point pt) + { + TreeNodeAdv node = GetNodeAt(pt); + _dropPosition.Node = node; + if (node != null) + { + Rectangle first = _rowLayout.GetRowBounds(FirstVisibleRow); + Rectangle bounds = _rowLayout.GetRowBounds(node.Row); + float pos = (pt.Y + first.Y - ColumnHeaderHeight - bounds.Y) / (float)bounds.Height; + if (pos < TopEdgeSensivity) + _dropPosition.Position = NodePosition.Before; + else if (pos > (1 - BottomEdgeSensivity)) + _dropPosition.Position = NodePosition.After; + else + _dropPosition.Position = NodePosition.Inside; + } + } + + private void DragTimerTick(object state) + { + _dragAutoScrollFlag = true; + } + + private void DragAutoScroll() + { + _dragAutoScrollFlag = false; + Point pt = PointToClient(MousePosition); + if (pt.Y < 20 && _vScrollBar.Value > 0) + _vScrollBar.Value--; + else if (pt.Y > Height - 20 && _vScrollBar.Value <= _vScrollBar.Maximum - _vScrollBar.LargeChange) + _vScrollBar.Value++; + } + + public void DoDragDropSelectedNodes(DragDropEffects allowedEffects) + { + if (SelectedNodes.Count > 0) + { + TreeNodeAdv[] nodes = new TreeNodeAdv[SelectedNodes.Count]; + SelectedNodes.CopyTo(nodes, 0); + DoDragDrop(nodes, allowedEffects); + } + } + + private void CreateDragBitmap(IDataObject data) + { + if (UseColumns || !DisplayDraggingNodes) + return; + + TreeNodeAdv[] nodes = data.GetData(typeof(TreeNodeAdv[])) as TreeNodeAdv[]; + if (nodes != null && nodes.Length > 0) + { + Rectangle rect = DisplayRectangle; + Bitmap bitmap = new Bitmap(rect.Width, rect.Height); + using (Graphics gr = Graphics.FromImage(bitmap)) + { + gr.Clear(BackColor); + DrawContext context = new DrawContext(); + context.Graphics = gr; + context.Font = Font; + context.Enabled = true; + int y = 0; + int maxWidth = 0; + foreach (TreeNodeAdv node in nodes) + { + if (node.Tree == this) + { + int x = 0; + int height = _rowLayout.GetRowBounds(node.Row).Height; + foreach (NodeControl c in NodeControls) + { + Size s = c.GetActualSize(node, context); + if (!s.IsEmpty) + { + int width = s.Width; + rect = new Rectangle(x, y, width, height); + x += (width + 1); + context.Bounds = rect; + c.Draw(node, context); + } + } + y += height; + maxWidth = Math.Max(maxWidth, x); + } + } + + if (maxWidth > 0 && y > 0) + { + _dragBitmap = new Bitmap(maxWidth, y, PixelFormat.Format32bppArgb); + using (Graphics tgr = Graphics.FromImage(_dragBitmap)) + tgr.DrawImage(bitmap, Point.Empty); + BitmapHelper.SetAlphaChanelValue(_dragBitmap, 150); + } + else + _dragBitmap = null; + } + } + } + + protected override void OnDragOver(DragEventArgs drgevent) + { + ItemDragMode = false; + Point pt = PointToClient(new Point(drgevent.X, drgevent.Y)); + if (_dragAutoScrollFlag) + DragAutoScroll(); + SetDropPosition(pt); + UpdateView(); + base.OnDragOver(drgevent); + } + + protected override void OnDragEnter(DragEventArgs drgevent) + { + _search.EndSearch(); + DragMode = true; + CreateDragBitmap(drgevent.Data); + base.OnDragEnter(drgevent); + } + + protected override void OnDragLeave(EventArgs e) + { + DragMode = false; + UpdateView(); + base.OnDragLeave(e); + } + + protected override void OnDragDrop(DragEventArgs drgevent) + { + DragMode = false; + UpdateView(); + base.OnDragDrop(drgevent); + } + + #endregion + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/TreeViewAdv.Properties.cs b/branches/ph-plugins/TreeViewAdv/Tree/TreeViewAdv.Properties.cs new file mode 100644 index 000000000..8a7ef7cdf --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/TreeViewAdv.Properties.cs @@ -0,0 +1,691 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.ComponentModel; +using System.Drawing; +using System.Windows.Forms; +using System.Collections.ObjectModel; +using System.Drawing.Design; + +using Aga.Controls.Tree.NodeControls; + +namespace Aga.Controls.Tree +{ + public partial class TreeViewAdv + { + private Cursor _innerCursor = null; + + public override Cursor Cursor + { + get + { + if (_innerCursor != null) + return _innerCursor; + else + return base.Cursor; + } + set + { + base.Cursor = value; + } + } + + #region Internal Properties + + private IRowLayout _rowLayout; + + private bool _dragMode; + private bool DragMode + { + get { return _dragMode; } + set + { + _dragMode = value; + if (!value) + { + StopDragTimer(); + if (_dragBitmap != null) + _dragBitmap.Dispose(); + _dragBitmap = null; + } + else + StartDragTimer(); + } + } + + public int ColumnHeaderHeight + { + get + { + if (UseColumns) + return _columnHeaderHeight; + else + return 0; + } + } + + /// + /// returns all nodes, which parent is expanded + /// + private IEnumerable VisibleNodes + { + get + { + TreeNodeAdv node = Root; + while (node != null) + { + node = node.NextVisibleNode; + if (node != null) + yield return node; + } + } + } + + private bool _suspendSelectionEvent; + internal bool SuspendSelectionEvent + { + get { return _suspendSelectionEvent; } + set + { + if (value != _suspendSelectionEvent) + { + _suspendSelectionEvent = value; + if (!_suspendSelectionEvent && _fireSelectionEvent) + OnSelectionChanged(); + } + } + } + + private List _rowMap; + internal List RowMap + { + get { return _rowMap; } + } + + private TreeNodeAdv _selectionStart; + internal TreeNodeAdv SelectionStart + { + get { return _selectionStart; } + set { _selectionStart = value; } + } + + private InputState _input; + internal InputState Input + { + get { return _input; } + set + { + _input = value; + } + } + + private bool _itemDragMode; + internal bool ItemDragMode + { + get { return _itemDragMode; } + set { _itemDragMode = value; } + } + + private Point _itemDragStart; + internal Point ItemDragStart + { + get { return _itemDragStart; } + set { _itemDragStart = value; } + } + + + /// + /// Number of rows fits to the current page + /// + internal int CurrentPageSize + { + get + { + return _rowLayout.CurrentPageSize; + } + } + + /// + /// Number of all visible nodes (which parent is expanded) + /// + internal int RowCount + { + get + { + return RowMap.Count; + } + } + + private int _contentWidth = 0; + private int ContentWidth + { + get + { + return _contentWidth; + } + } + + private int _firstVisibleRow; + internal int FirstVisibleRow + { + get { return _firstVisibleRow; } + set + { + HideEditor(); + _firstVisibleRow = value; + UpdateView(); + } + } + + private int _offsetX; + internal int OffsetX + { + get { return _offsetX; } + private set + { + HideEditor(); + _offsetX = value; + UpdateView(); + } + } + + public override Rectangle DisplayRectangle + { + get + { + Rectangle r = ClientRectangle; + //r.Y += ColumnHeaderHeight; + //r.Height -= ColumnHeaderHeight; + int w = _vScrollBar.Visible ? _vScrollBar.Width : 0; + int h = _hScrollBar.Visible ? _hScrollBar.Height : 0; + return new Rectangle(r.X, r.Y, r.Width - w, r.Height - h); + } + } + + private List _selection; + internal List Selection + { + get { return _selection; } + } + + #endregion + + #region Public Properties + + #region DesignTime + + private bool _displayDraggingNodes; + [DefaultValue(false), Category("Behavior")] + public bool DisplayDraggingNodes + { + get { return _displayDraggingNodes; } + set { _displayDraggingNodes = value; } + } + + private bool _fullRowSelect; + [DefaultValue(false), Category("Behavior")] + public bool FullRowSelect + { + get { return _fullRowSelect; } + set + { + _fullRowSelect = value; + UpdateView(); + } + } + + private bool _useColumns; + [DefaultValue(false), Category("Behavior")] + public bool UseColumns + { + get { return _useColumns; } + set + { + _useColumns = value; + FullUpdate(); + } + } + + private bool _allowColumnReorder; + [DefaultValue(false), Category("Behavior")] + public bool AllowColumnReorder + { + get { return _allowColumnReorder; } + set { _allowColumnReorder = value; } + } + + private bool _showLines = true; + [DefaultValue(true), Category("Behavior")] + public bool ShowLines + { + get { return _showLines; } + set + { + _showLines = value; + UpdateView(); + } + } + + private bool _showPlusMinus = true; + [DefaultValue(true), Category("Behavior")] + public bool ShowPlusMinus + { + get { return _showPlusMinus; } + set + { + _showPlusMinus = value; + FullUpdate(); + } + } + + private bool _showNodeToolTips = false; + [DefaultValue(false), Category("Behavior")] + public bool ShowNodeToolTips + { + get { return _showNodeToolTips; } + set { _showNodeToolTips = value; } + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "value"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic"), DefaultValue(true), Category("Behavior"), Obsolete("No longer used")] + public bool KeepNodesExpanded + { + get { return true; } + set {} + } + + private ITreeModel _model; + [Category("Data")] + public ITreeModel Model + { + get { return _model; } + set + { + if (_model != value) + { + AbortBackgroundExpandingThreads(); + if (_model != null) + UnbindModelEvents(); + _model = value; + CreateNodes(); + FullUpdate(); + if (_model != null) + BindModelEvents(); + } + } + } + + // Font proprety for Tahoma as default font + // wj32: Apparently some people don't have Tahoma... + //private static Font _font = new Font("Microsoft Sans Serif", 8.25F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(0)), false); + private static Font _font = System.Windows.Forms.Control.DefaultFont; + [Category("Appearance")] + public override Font Font + { + get + { + return (base.Font); + } + set + { + if (value == null) + base.Font = _font; + else + { + if (value == System.Windows.Forms.Control.DefaultFont) + base.Font = _font; + else + base.Font = value; + } + } + } + public override void ResetFont() + { + Font = null; + } + private bool ShouldSerializeFont() + { + return (!Font.Equals(_font)); + } + // End font property + + private BorderStyle _borderStyle = BorderStyle.Fixed3D; + [DefaultValue(BorderStyle.Fixed3D), Category("Appearance")] + public BorderStyle BorderStyle + { + get + { + return this._borderStyle; + } + set + { + if (_borderStyle != value) + { + _borderStyle = value; + this.RecreateHandle(); + this.Invalidate(); + } + } + } + + private bool _autoRowHeight = false; + [DefaultValue(false), Category("Appearance")] + public bool AutoRowHeight + { + get + { + return _autoRowHeight; + } + set + { + _autoRowHeight = value; + if (value) + _rowLayout = new AutoRowHeightLayout(this, RowHeight); + else + _rowLayout = new FixedRowHeightLayout(this, RowHeight); + FullUpdate(); + } + } + + private GridLineStyle _gridLineStyle = GridLineStyle.None; + [DefaultValue(GridLineStyle.None), Category("Appearance")] + public GridLineStyle GridLineStyle + { + get + { + return _gridLineStyle; + } + set + { + if (value != _gridLineStyle) + { + _gridLineStyle = value; + UpdateView(); + OnGridLineStyleChanged(); + } + } + } + + private int _rowHeight = 16; + [DefaultValue(16), Category("Appearance")] + public int RowHeight + { + get + { + return _rowHeight; + } + set + { + if (value <= 0) + throw new ArgumentOutOfRangeException("value"); + + _rowHeight = value; + _rowLayout.PreferredRowHeight = value; + FullUpdate(); + } + } + + private TreeSelectionMode _selectionMode = TreeSelectionMode.Single; + [DefaultValue(TreeSelectionMode.Single), Category("Behavior")] + public TreeSelectionMode SelectionMode + { + get { return _selectionMode; } + set { _selectionMode = value; } + } + + private bool _hideSelection; + [DefaultValue(false), Category("Behavior")] + public bool HideSelection + { + get { return _hideSelection; } + set + { + _hideSelection = value; + UpdateView(); + } + } + + private float _topEdgeSensivity = 0.3f; + [DefaultValue(0.3f), Category("Behavior")] + public float TopEdgeSensivity + { + get { return _topEdgeSensivity; } + set + { + if (value < 0 || value > 1) + throw new ArgumentOutOfRangeException(); + _topEdgeSensivity = value; + } + } + + private float _bottomEdgeSensivity = 0.3f; + [DefaultValue(0.3f), Category("Behavior")] + public float BottomEdgeSensivity + { + get { return _bottomEdgeSensivity; } + set + { + if (value < 0 || value > 1) + throw new ArgumentOutOfRangeException("value should be from 0 to 1"); + _bottomEdgeSensivity = value; + } + } + + private bool _loadOnDemand; + [DefaultValue(false), Category("Behavior")] + public bool LoadOnDemand + { + get { return _loadOnDemand; } + set { _loadOnDemand = value; } + } + + private int _indent = 19; + [DefaultValue(19), Category("Behavior")] + public int Indent + { + get { return _indent; } + set + { + _indent = value; + UpdateView(); + } + } + + private Color _lineColor = SystemColors.ControlDark; + [Category("Behavior")] + public Color LineColor + { + get { return _lineColor; } + set + { + _lineColor = value; + CreateLinePen(); + UpdateView(); + } + } + + private Color _dragDropMarkColor = Color.Black; + [Category("Behavior")] + public Color DragDropMarkColor + { + get { return _dragDropMarkColor; } + set + { + _dragDropMarkColor = value; + CreateMarkPen(); + } + } + + private float _dragDropMarkWidth = 3.0f; + [DefaultValue(3.0f), Category("Behavior")] + public float DragDropMarkWidth + { + get { return _dragDropMarkWidth; } + set + { + _dragDropMarkWidth = value; + CreateMarkPen(); + } + } + + private bool _highlightDropPosition = true; + [DefaultValue(true), Category("Behavior")] + public bool HighlightDropPosition + { + get { return _highlightDropPosition; } + set { _highlightDropPosition = value; } + } + + private TreeColumnCollection _columns; + [Category("Behavior"), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + public Collection Columns + { + get { return _columns; } + } + + private NodeControlsCollection _controls; + [Category("Behavior"), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + [Editor(typeof(NodeControlCollectionEditor), typeof(UITypeEditor))] + public Collection NodeControls + { + get + { + return _controls; + } + } + + private bool _asyncExpanding; + /// + /// When set to true, node contents will be read in background thread + /// + [Category("Behavior")] + [DefaultValue(false)] + public bool AsyncExpanding + { + get { return _asyncExpanding; } + set { _asyncExpanding = value; } + } + + #endregion + + #region RunTime + + private IToolTipProvider _defaultToolTipProvider = null; + [Browsable(false)] + public IToolTipProvider DefaultToolTipProvider + { + get { return _defaultToolTipProvider; } + set { _defaultToolTipProvider = value; } + } + + [Browsable(false)] + public IEnumerable AllNodes + { + get + { + if (_root.Nodes.Count > 0) + { + TreeNodeAdv node = _root.Nodes[0]; + while (node != null) + { + yield return node; + if (node.Nodes.Count > 0) + node = node.Nodes[0]; + else if (node.NextNode != null) + node = node.NextNode; + else + node = node.BottomNode; + } + } + } + } + + private DropPosition _dropPosition; + [Browsable(false)] + public DropPosition DropPosition + { + get { return _dropPosition; } + set { _dropPosition = value; } + } + + private TreeNodeAdv _root; + [Browsable(false)] + public TreeNodeAdv Root + { + get { return _root; } + } + + private ReadOnlyCollection _readonlySelection; + [Browsable(false)] + public ReadOnlyCollection SelectedNodes + { + get + { + return _readonlySelection; + } + } + + [Browsable(false)] + public TreeNodeAdv SelectedNode + { + get + { + if (Selection.Count > 0) + { + if (CurrentNode != null && CurrentNode.IsSelected) + return CurrentNode; + else + return Selection[0]; + } + else + return null; + } + set + { + if (SelectedNode == value) + return; + + BeginUpdate(); + try + { + if (value == null) + { + ClearSelectionInternal(); + } + else + { + if (!IsMyNode(value)) + throw new ArgumentException(); + + ClearSelectionInternal(); + value.IsSelected = true; + CurrentNode = value; + EnsureVisible(value); + } + } + finally + { + EndUpdate(); + } + } + } + + private TreeNodeAdv _currentNode; + [Browsable(false)] + public TreeNodeAdv CurrentNode + { + get { return _currentNode; } + internal set { _currentNode = value; } + } + + [Browsable(false)] + public int ItemCount + { + get { return RowMap.Count; } + } + + #endregion + + #endregion + + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/TreeViewAdv.cs b/branches/ph-plugins/TreeViewAdv/Tree/TreeViewAdv.cs new file mode 100644 index 000000000..f65403cb9 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/TreeViewAdv.cs @@ -0,0 +1,1270 @@ +/* + * Modified by fliser. + * Modified by wj32. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Drawing; +using System.Security.Permissions; +using System.Threading; +using System.Windows.Forms; +using Aga.Controls.Threading; +using Aga.Controls.Tree.NodeControls; + + +namespace Aga.Controls.Tree +{ + public partial class TreeViewAdv : Control + { + private const int LeftMargin = 7; + internal const int ItemDragSensivity = 4; + private readonly int _columnHeaderHeight; + private const int DividerWidth = 9; + private const int DividerCorrectionGap = -2; + + private Pen _linePen; + private Pen _markPen; + private bool _suspendUpdate; + private bool _completeSuspendUpdate; // Overrides my (wj32's) hacks + private bool _needFullUpdate; + private bool _fireSelectionEvent; + private NodePlusMinus _plusMinus; + private Control _currentEditor; + private EditableControl _currentEditorOwner; + private ToolTip _toolTip; + private DrawContext _measureContext; + private TreeColumn _hotColumn = null; + private IncrementalSearch _search; + private List _expandingNodes = new List(); + private AbortableThreadPool _threadPool = new AbortableThreadPool(); + private Stack _suspendedStack = new Stack(); + + #region Public Events + + [Category("Action")] + public event ItemDragEventHandler ItemDrag; + private void OnItemDrag(MouseButtons buttons, object item) + { + if (ItemDrag != null) + ItemDrag(this, new ItemDragEventArgs(buttons, item)); + } + + [Category("Behavior")] + public event EventHandler NodeMouseClick; + private void OnNodeMouseClick(TreeNodeAdvMouseEventArgs args) + { + if (NodeMouseClick != null) + NodeMouseClick(this, args); + } + + [Category("Behavior")] + public event EventHandler NodeMouseDoubleClick; + private void OnNodeMouseDoubleClick(TreeNodeAdvMouseEventArgs args) + { + if (NodeMouseDoubleClick != null) + NodeMouseDoubleClick(this, args); + } + + [Category("Behavior")] + public event EventHandler ColumnWidthChanged; + internal void OnColumnWidthChanged(TreeColumn column) + { + if (ColumnWidthChanged != null) + ColumnWidthChanged(this, new TreeColumnEventArgs(column)); + } + + [Category("Behavior")] + public event EventHandler ColumnReordered; + internal void OnColumnReordered(TreeColumn column) + { + this.InvalidateNodeControlCache(); + + if (ColumnReordered != null) + ColumnReordered(this, new TreeColumnEventArgs(column)); + } + + [Category("Behavior")] + public event EventHandler ColumnClicked; + internal void OnColumnClicked(TreeColumn column) + { + if (ColumnClicked != null) + ColumnClicked(this, new TreeColumnEventArgs(column)); + } + + [Category("Behavior")] + public event EventHandler SelectionChanged; + internal void OnSelectionChanged() + { + if (SuspendSelectionEvent) + _fireSelectionEvent = true; + else + { + _fireSelectionEvent = false; + if (SelectionChanged != null) + SelectionChanged(this, EventArgs.Empty); + } + } + + [Category("Behavior")] + public event EventHandler Collapsing; + private void OnCollapsing(TreeNodeAdv node) + { + if (Collapsing != null) + Collapsing(this, new TreeViewAdvEventArgs(node)); + } + + [Category("Behavior")] + public event EventHandler Collapsed; + private void OnCollapsed(TreeNodeAdv node) + { + this.InvalidateNodeControlCache(); + + if (Collapsed != null) + Collapsed(this, new TreeViewAdvEventArgs(node)); + } + + [Category("Behavior")] + public event EventHandler Expanding; + private void OnExpanding(TreeNodeAdv node) + { + if (Expanding != null) + Expanding(this, new TreeViewAdvEventArgs(node)); + } + + [Category("Behavior")] + public event EventHandler Expanded; + private void OnExpanded(TreeNodeAdv node) + { + this.InvalidateNodeControlCache(); + + if (Expanded != null) + Expanded(this, new TreeViewAdvEventArgs(node)); + } + + [Category("Behavior")] + public event EventHandler GridLineStyleChanged; + private void OnGridLineStyleChanged() + { + if (GridLineStyleChanged != null) + GridLineStyleChanged(this, EventArgs.Empty); + } + + #endregion + + public TreeViewAdv() + { + InitializeComponent(); + SetStyle(ControlStyles.AllPaintingInWmPaint + | ControlStyles.UserPaint + | ControlStyles.OptimizedDoubleBuffer + | ControlStyles.ResizeRedraw + | ControlStyles.Selectable + , true); + + + if (Environment.OSVersion.Version.Major < 6) + { + if (Application.RenderWithVisualStyles) + _columnHeaderHeight = 20; + else + _columnHeaderHeight = 17; + } + else + { + if (Application.RenderWithVisualStyles) + _columnHeaderHeight = 25; + else + _columnHeaderHeight = 17; + } + + //BorderStyle = BorderStyle.Fixed3D; + _hScrollBar.Height = SystemInformation.HorizontalScrollBarHeight; + _vScrollBar.Width = SystemInformation.VerticalScrollBarWidth; + _rowLayout = new FixedRowHeightLayout(this, RowHeight); + _rowMap = new List(); + _selection = new List(); + _readonlySelection = new ReadOnlyCollection(_selection); + _columns = new TreeColumnCollection(this); + _toolTip = new ToolTip(); + + _measureContext = new DrawContext(); + _measureContext.Font = Font; + _measureContext.Graphics = Graphics.FromImage(new Bitmap(1, 1)); + + Input = new NormalInputState(this); + _search = new IncrementalSearch(this); + CreateNodes(); + CreatePens(); + + ArrangeControls(); + + _plusMinus = new NodePlusMinus(this); + _controls = new NodeControlsCollection(this); + + Font = _font; + ExpandingIcon.IconChanged += ExpandingIconChanged; + } + + void ExpandingIconChanged(object sender, EventArgs e) + { + if (IsHandleCreated) + Invoke(new MethodInvoker(DrawIcons)); + } + + private void DrawIcons() + { + Graphics gr = Graphics.FromHwnd(this.Handle); + int firstRowY = _rowLayout.GetRowBounds(FirstVisibleRow).Y; + DrawContext context = new DrawContext(); + context.Graphics = gr; + for (int i = 0; i < _expandingNodes.Count; i++) + { + foreach (NodeControlInfo info in GetNodeControls(_expandingNodes[i])) + if (info.Control is ExpandingIcon) + { + Rectangle rect = info.Bounds; + rect.X -= OffsetX; + rect.Y -= firstRowY; + context.Bounds = rect; + info.Control.Draw(info.Node, context); + } + } + gr.Dispose(); + } + + #region Public Methods + + public TreePath GetPath(TreeNodeAdv node) + { + if (node == _root) + return TreePath.Empty; + else + { + Stack stack = new Stack(); + while (node != _root && node != null) + { + stack.Push(node.Tag); + node = node.Parent; + } + return new TreePath(stack.ToArray()); + } + } + + public TreeNodeAdv GetNodeAt(Point point) + { + NodeControlInfo info = GetNodeControlInfoAt(point); + return info.Node; + } + + public NodeControlInfo GetNodeControlInfoAt(Point point) + { + if (point.X < 0 || point.Y < 0) + return NodeControlInfo.Empty; + + int row = _rowLayout.GetRowAt(point); + if (row < RowCount && row >= 0) + return GetNodeControlInfoAt(RowMap[row], point); + else + return NodeControlInfo.Empty; + } + + private NodeControlInfo GetNodeControlInfoAt(TreeNodeAdv node, Point point) + { + Rectangle rect = _rowLayout.GetRowBounds(FirstVisibleRow); + point.Y += (rect.Y - ColumnHeaderHeight); + point.X += OffsetX; + foreach (NodeControlInfo info in GetNodeControls(node)) + if (info.Bounds.Contains(point)) + return info; + + if (FullRowSelect) + return new NodeControlInfo(null, Rectangle.Empty, node); + else + return NodeControlInfo.Empty; + } + + public void BeginUpdate() + { + _suspendedStack.Push(_suspendUpdate); + _suspendUpdate = true; + //SuspendSelectionEvent = true; + } + + public void BeginCompleteUpdate() + { + _completeSuspendUpdate = true; + } + + public void EndUpdate() + { + _suspendUpdate = _suspendedStack.Pop(); + + if (_needFullUpdate && !_completeSuspendUpdate) + FullUpdate(); + else + UpdateView(); + //SuspendSelectionEvent = false; + } + + public void EndCompleteUpdate() + { + _completeSuspendUpdate = false; + FullUpdate(); + } + + public void ExpandAll() + { + _root.ExpandAll(); + } + + public void CollapseAll() + { + _root.CollapseAll(); + } + + /// + /// Expand all parent nodes and scroll to the specified node + /// + public void EnsureVisible(TreeNodeAdv node) + { + if (node == null) + throw new ArgumentNullException("node"); + + if (!IsMyNode(node)) + throw new ArgumentException(); + + TreeNodeAdv parent = node.Parent; + while (parent != _root) + { + parent.IsExpanded = true; + parent = parent.Parent; + } + ScrollTo(node); + } + + /// + /// Make node visible, scroll if needed. All parent nodes of the specified node must be expanded + /// + /// + public void ScrollTo(TreeNodeAdv node) + { + if (node == null) + throw new ArgumentNullException("node"); + + if (!IsMyNode(node)) + throw new ArgumentException(); + + if (node.Row < 0) + CreateRowMap(); + + int row = FirstVisibleRow; + + if (node.Row < FirstVisibleRow) + { + row = node.Row; + } + else + { + int pageStart = _rowLayout.GetRowBounds(FirstVisibleRow).Top; + int rowBottom = _rowLayout.GetRowBounds(node.Row).Bottom; + if (rowBottom > pageStart + DisplayRectangle.Height - ColumnHeaderHeight) + row = _rowLayout.GetFirstRow(node.Row); + } + + // wj32: Do the best we can, so don't bail out if the value is out of range. + if (row < _vScrollBar.Minimum) + row = _vScrollBar.Minimum; + if (row > _vScrollBar.Maximum) + row = _vScrollBar.Maximum; + + _vScrollBar.Value = row; + } + + public void ScrollTo2(TreeNodeAdv node) + { + if (node == null) + throw new ArgumentNullException("node"); + + if (!IsMyNode(node)) + throw new ArgumentException(); + + if (node.Row < 0) + CreateRowMap(); + + int row = -1; + + if (node.Row < FirstVisibleRow) + { + row = node.Row; + // Ugh, who wants the node at the TOP of the screen? Put it in the MIDDLE! + row -= (this.Height / this.RowHeight) / 2; + } + else + { + int pageStart = _rowLayout.GetRowBounds(FirstVisibleRow).Top; + int rowBottom = _rowLayout.GetRowBounds(node.Row).Bottom; + if (rowBottom > pageStart + DisplayRectangle.Height - ColumnHeaderHeight) + row = _rowLayout.GetFirstRow(node.Row); + + // Ugh, who wants the node at the BOTTOM of the screen? Put it in the MIDDLE! + row += (this.Height / this.RowHeight) / 2; + } + // wj32: Do the best we can, so don't bail out if the value is out of range. + if (row < _vScrollBar.Minimum) + row = _vScrollBar.Minimum; + if (row > _vScrollBar.Maximum) + row = _vScrollBar.Maximum; + + _vScrollBar.Value = row; + } + + public void ClearSelection() + { + BeginUpdate(); + try + { + ClearSelectionInternal(); + } + finally + { + EndUpdate(); + } + } + + internal void ClearSelectionInternal() + { + while (Selection.Count > 0) + Selection[0].IsSelected = false; + } + + #endregion + + protected override void OnSizeChanged(EventArgs e) + { + ArrangeControls(); + SafeUpdateScrollBars(); + base.OnSizeChanged(e); + this.Invalidate(); + } + + private void ArrangeControls() + { + int hBarSize = _hScrollBar.Height; + int vBarSize = _vScrollBar.Width; + Rectangle clientRect = ClientRectangle; + + _hScrollBar.SetBounds(clientRect.X, clientRect.Bottom - hBarSize, + clientRect.Width - vBarSize, hBarSize); + + _vScrollBar.SetBounds(clientRect.Right - vBarSize, clientRect.Y, + vBarSize, clientRect.Height - hBarSize); + } + + private void SafeUpdateScrollBars() + { + if (InvokeRequired) + Invoke(new MethodInvoker(UpdateScrollBars)); + else + UpdateScrollBars(); + } + + private void UpdateScrollBars() + { + UpdateVScrollBar(); + UpdateHScrollBar(); + UpdateVScrollBar(); + UpdateHScrollBar(); + _hScrollBar.Width = DisplayRectangle.Width; + _vScrollBar.Height = DisplayRectangle.Height; + } + + private void UpdateHScrollBar() + { + _hScrollBar.Maximum = ContentWidth; + _hScrollBar.LargeChange = Math.Max(DisplayRectangle.Width, 0); + _hScrollBar.SmallChange = 5; + _hScrollBar.Visible = _hScrollBar.LargeChange < _hScrollBar.Maximum; + _hScrollBar.Value = Math.Min(_hScrollBar.Value, _hScrollBar.Maximum - _hScrollBar.LargeChange + 1); + } + + private void UpdateVScrollBar() + { + _vScrollBar.Maximum = Math.Max(RowCount - 1, 0); + _vScrollBar.LargeChange = _rowLayout.PageRowCount; + _vScrollBar.Visible = (RowCount > 0) && (_vScrollBar.LargeChange <= _vScrollBar.Maximum); + _vScrollBar.Value = Math.Min(_vScrollBar.Value, _vScrollBar.Maximum - _vScrollBar.LargeChange + 1); + } + + protected override CreateParams CreateParams + { + [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] + get + { + CreateParams res = base.CreateParams; + switch (BorderStyle) + { + case BorderStyle.FixedSingle: + res.Style |= 0x800000; + break; + case BorderStyle.Fixed3D: + res.ExStyle |= 0x20000; + break; + } + return res; + } + } + + protected override void OnGotFocus(EventArgs e) + { + HideEditor(); + UpdateView(); + ChangeInput(); + base.OnGotFocus(e); + } + + protected override void OnLeave(EventArgs e) + { + if (_currentEditorOwner != null) + _currentEditorOwner.ApplyChanges(); + HideEditor(); + UpdateView(); + base.OnLeave(e); + } + + protected override void OnFontChanged(EventArgs e) + { + base.OnFontChanged(e); + _measureContext.Font = Font; + FullUpdate(); + } + + private Dictionary> _cachedNodeControls = + new Dictionary>(); + + internal IEnumerable GetNodeControls(TreeNodeAdv node) + { + IEnumerable nodeControls = null; + + if (node == null) + return new List(); + + lock (_cachedNodeControls) + { + if (!_cachedNodeControls.ContainsKey(node)) + { + List ncList = new List(); + + foreach (var item in this.GetNodeControlsInternal(node)) + ncList.Add(item); + + _cachedNodeControls.Add(node, ncList); + } + + nodeControls = _cachedNodeControls[node]; + } + + return nodeControls; + } + + public void InvalidateNodeControlCache() + { + lock (_cachedNodeControls) + _cachedNodeControls.Clear(); + } + + private IEnumerable GetNodeControlsInternal(TreeNodeAdv node) + { + if (node == null) + yield break; + Rectangle rowRect = _rowLayout.GetRowBounds(node.Row); + foreach (NodeControlInfo n in GetNodeControls(node, rowRect)) + yield return n; + } + + internal IEnumerable GetNodeControls(TreeNodeAdv node, Rectangle rowRect) + { + if (node == null) + yield break; + + int y = rowRect.Y; + int x = (node.Level - 1) * _indent + LeftMargin; + int width = 0; + Rectangle rect = Rectangle.Empty; + + if (ShowPlusMinus) + { + width = _plusMinus.GetActualSize(node, _measureContext).Width; + rect = new Rectangle(x, y, width, rowRect.Height); + if (UseColumns && Columns.Count > 0 && Columns[0].Width < rect.Right) + rect.Width = Columns[0].Width - x; + + yield return new NodeControlInfo(_plusMinus, rect, node); + x += width; + } + + if (!UseColumns) + { + foreach (NodeControl c in NodeControls) + { + Size s = c.GetActualSize(node, _measureContext); + if (!s.IsEmpty) + { + width = s.Width; + rect = new Rectangle(x, y, width, rowRect.Height); + x += rect.Width; + yield return new NodeControlInfo(c, rect, node); + } + } + } + else + { + int right = 0; + foreach (TreeColumn col in Columns) + { + if (col.IsVisible && col.Width > 0) + { + right += col.Width; + for (int i = 0; i < NodeControls.Count; i++) + { + NodeControl nc = NodeControls[i]; + if (nc.ParentColumn == col) + { + Size s = nc.GetActualSize(node, _measureContext); + if (!s.IsEmpty) + { + bool isLastControl = true; + for (int k = i + 1; k < NodeControls.Count; k++) + if (NodeControls[k].ParentColumn == col) + { + isLastControl = false; + break; + } + + width = right - x; + if (!isLastControl) + width = s.Width; + int maxWidth = Math.Max(0, right - x); + rect = new Rectangle(x, y, Math.Min(maxWidth, width), rowRect.Height); + x += width; + yield return new NodeControlInfo(nc, rect, node); + } + } + } + x = right; + } + } + } + } + + internal static double Dist(Point p1, Point p2) + { + return Math.Sqrt(Math.Pow(p1.X - p2.X, 2) + Math.Pow(p1.Y - p2.Y, 2)); + } + + public void FullUpdate() + { + if (InvokeRequired) + Invoke(new MethodInvoker(UnsafeFullUpdate)); + else + UnsafeFullUpdate(); + } + + public void RefreshVisualStyles() + { + _plusMinus.RefreshVisualStyles(); + } + + private void UnsafeFullUpdate() + { + _rowLayout.ClearCache(); + CreateRowMap(); + SafeUpdateScrollBars(); + UpdateView(); + _needFullUpdate = false; + } + + internal void UpdateView() + { + if (!_suspendUpdate) + Invalidate(false); + } + + internal void UpdateHeaders() + { + Invalidate(new Rectangle(0,0, Width, ColumnHeaderHeight)); + } + + internal void UpdateColumns() + { + FullUpdate(); + } + + private void CreateNodes() + { + Selection.Clear(); + SelectionStart = null; + _root = new TreeNodeAdv(this, null); + _root.IsExpanded = true; + if (_root.Nodes.Count > 0) + CurrentNode = _root.Nodes[0]; + else + CurrentNode = null; + } + + internal void ReadChilds(TreeNodeAdv parentNode) + { + ReadChilds(parentNode, false); + } + + internal void ReadChilds(TreeNodeAdv parentNode, bool performFullUpdate) + { + if (!parentNode.IsLeaf) + { + parentNode.IsExpandedOnce = true; + List oldNodes = new List(parentNode.Nodes); + parentNode.Nodes.Clear(); + + if (Model != null) + { + IEnumerable items = Model.GetChildren(GetPath(parentNode)); + if (items != null) + foreach (object obj in items) + { + bool found = false; + if (obj != null) + { + for (int i = 0; i < oldNodes.Count; i++) + if (obj == oldNodes[i].Tag) + { + oldNodes[i].RightBounds = oldNodes[i].Height = null; + AddNode(parentNode, -1, oldNodes[i]); + oldNodes.RemoveAt(i); + found = true; + break; + } + } + if (!found) + AddNewNode(parentNode, obj, -1); + + if (performFullUpdate) + FullUpdate(); + } + } + + } + } + + private void AddNewNode(TreeNodeAdv parent, object tag, int index) + { + TreeNodeAdv node = new TreeNodeAdv(this, tag); + AddNode(parent, index, node); + } + + private void AddNode(TreeNodeAdv parent, int index, TreeNodeAdv node) + { + if (index >= 0 && index < parent.Nodes.Count) + parent.Nodes.Insert(index, node); + else + parent.Nodes.Add(node); + + node.IsLeaf = Model.IsLeaf(GetPath(node)); + if (node.IsLeaf) + node.Nodes.Clear(); + if (!LoadOnDemand || node.IsExpandedOnce) + ReadChilds(node); + + this.InvalidateNodeControlCache(); + } + + private struct ExpandArgs + { + public TreeNodeAdv Node; + public bool Value; + public bool IgnoreChildren; + } + + public void AbortBackgroundExpandingThreads() + { + _threadPool.CancelAll(true); + for (int i = 0; i < _expandingNodes.Count; i++) + _expandingNodes[i].IsExpandingNow = false; + _expandingNodes.Clear(); + Invalidate(); + } + + internal void SetIsExpanded(TreeNodeAdv node, bool value, bool ignoreChildren) + { + ExpandArgs eargs = new ExpandArgs(); + eargs.Node = node; + eargs.Value = value; + eargs.IgnoreChildren = ignoreChildren; + + if (AsyncExpanding && LoadOnDemand && !_threadPool.IsMyThread(Thread.CurrentThread)) + { + WaitCallback wc = delegate(object argument) { SetIsExpanded((ExpandArgs)argument); }; + _threadPool.QueueUserWorkItem(wc, eargs); + } + else + SetIsExpanded(eargs); + } + + private void SetIsExpanded(ExpandArgs eargs) + { + bool update = !eargs.IgnoreChildren && !AsyncExpanding; + if (update) + BeginUpdate(); + try + { + if (IsMyNode(eargs.Node) && eargs.Node.IsExpanded != eargs.Value) + SetIsExpanded(eargs.Node, eargs.Value); + + if (!eargs.IgnoreChildren) + SetIsExpandedRecursive(eargs.Node, eargs.Value); + } + finally + { + if (update) + EndUpdate(); + } + } + + internal void SetIsExpanded(TreeNodeAdv node, bool value) + { + if (Root == node && !value) + return; //Can't collapse root node + + if (value) + OnExpanding(node); + else + OnCollapsing(node); + + if (value && !node.IsExpandedOnce) + { + if (AsyncExpanding && LoadOnDemand) + { + AddExpandingNode(node); + node.AssignIsExpanded(true); + Invalidate(); + } + ReadChilds(node, AsyncExpanding); + RemoveExpandingNode(node); + } + node.AssignIsExpanded(value); + SmartFullUpdate(); + + if (value) + OnExpanded(node); + else + OnCollapsed(node); + } + + private void RemoveExpandingNode(TreeNodeAdv node) + { + node.IsExpandingNow = false; + _expandingNodes.Remove(node); + } + + private void AddExpandingNode(TreeNodeAdv node) + { + node.IsExpandingNow = true; + _expandingNodes.Add(node); + ExpandingIcon.Start(); + } + + internal void SetIsExpandedRecursive(TreeNodeAdv root, bool value) + { + for (int i = 0; i < root.Nodes.Count; i++) + { + TreeNodeAdv node = root.Nodes[i]; + node.IsExpanded = value; + SetIsExpandedRecursive(node, value); + } + } + + private void CreateRowMap() + { + RowMap.Clear(); + int row = 0; + _contentWidth = 0; + foreach (TreeNodeAdv node in VisibleNodes) + { + node.Row = row; + RowMap.Add(node); + if (!UseColumns) + { + _contentWidth = Math.Max(_contentWidth, GetNodeWidth(node)); + } + row++; + } + if (UseColumns) + { + _contentWidth = 0; + foreach (TreeColumn col in _columns) + if (col.IsVisible) + _contentWidth += col.Width; + } + } + + private int GetNodeWidth(TreeNodeAdv node) + { + if (node.RightBounds == null) + { + Rectangle res = GetNodeBounds(GetNodeControls(node, Rectangle.Empty)); + node.RightBounds = res.Right; + } + return node.RightBounds.Value; + } + + internal Rectangle GetNodeBounds(TreeNodeAdv node) + { + return GetNodeBounds(GetNodeControls(node)); + } + + private Rectangle GetNodeBounds(IEnumerable nodeControls) + { + Rectangle res = Rectangle.Empty; + foreach (NodeControlInfo info in nodeControls) + { + if (res == Rectangle.Empty) + res = info.Bounds; + else + res = Rectangle.Union(res, info.Bounds); + } + return res; + } + + private void _vScrollBar_ValueChanged(object sender, EventArgs e) + { + FirstVisibleRow = _vScrollBar.Value; + this.Invalidate(); + } + + private void _hScrollBar_ValueChanged(object sender, EventArgs e) + { + OffsetX = _hScrollBar.Value; + this.Invalidate(); + } + + internal void SmartFullUpdate() + { + if (_suspendUpdate) + _needFullUpdate = true; + else + FullUpdate(); + } + + internal bool IsMyNode(TreeNodeAdv node) + { + if (node == null) + return false; + + if (node.Tree != this) + return false; + + while (node.Parent != null) + node = node.Parent; + + return node == _root; + } + + private void UpdateSelection() + { + bool flag = false; + + if (!IsMyNode(CurrentNode)) + CurrentNode = null; + if (!IsMyNode(_selectionStart)) + _selectionStart = null; + + for (int i = Selection.Count - 1; i >= 0; i--) + if (!IsMyNode(Selection[i])) + { + flag = true; + Selection.RemoveAt(i); + } + + if (flag) + OnSelectionChanged(); + } + + internal void ChangeColumnWidth(TreeColumn column) + { + if (!(_input is ResizeColumnState)) + { + FullUpdate(); + OnColumnWidthChanged(column); + } + } + + public TreeNodeAdv FindNode(TreePath path) + { + return FindNode(path, false); + } + + public TreeNodeAdv FindNode(TreePath path, bool readChilds) + { + if (path.IsEmpty()) + return _root; + else + return FindNode(_root, path, 0, readChilds); + } + + private TreeNodeAdv FindNode(TreeNodeAdv root, TreePath path, int level, bool readChilds) + { + if (!root.IsExpandedOnce && readChilds) + ReadChilds(root); + + for (int i = 0; i < root.Nodes.Count; i++) + { + TreeNodeAdv node = root.Nodes[i]; + if (node.Tag == path.FullPath[level]) + { + if (level == path.FullPath.Length - 1) + return node; + else + return FindNode(node, path, level + 1, readChilds); + } + } + return null; + } + + public TreeNodeAdv FindNodeByTag(object tag) + { + return FindNodeByTag(_root, tag); + } + + private TreeNodeAdv FindNodeByTag(TreeNodeAdv root, object tag) + { + foreach (TreeNodeAdv node in root.Nodes) + { + if (node.Tag == tag) + return node; + TreeNodeAdv res = FindNodeByTag(node, tag); + if (res != null) + return res; + } + return null; + } + + #region Editor + + public void DisplayEditor(Control control, EditableControl owner) + { + if (control == null || owner == null) + throw new ArgumentNullException(); + + if (CurrentNode != null) + { + HideEditor(); + _currentEditor = control; + _currentEditorOwner = owner; + UpdateEditorBounds(); + + UpdateView(); + control.Parent = this; + control.Focus(); + owner.UpdateEditor(control); + } + } + + public void UpdateEditorBounds() + { + if (_currentEditor != null) + { + EditorContext context = new EditorContext(); + context.Owner = _currentEditorOwner; + context.CurrentNode = CurrentNode; + context.Editor = _currentEditor; + context.DrawContext = _measureContext; + + SetEditorBounds(context); + } + } + + public void HideEditor() + { + if (_currentEditorOwner != null) + { + _currentEditorOwner.HideEditor(_currentEditor); + _currentEditor = null; + _currentEditorOwner = null; + } + } + + private void SetEditorBounds(EditorContext context) + { + foreach (NodeControlInfo info in GetNodeControls(context.CurrentNode)) + { + if (context.Owner == info.Control && info.Control is EditableControl) + { + Point p = info.Bounds.Location; + p.X += info.Control.LeftMargin; + p.X -= OffsetX; + p.Y -= (_rowLayout.GetRowBounds(FirstVisibleRow).Y - ColumnHeaderHeight); + int width = DisplayRectangle.Width - p.X; + if (UseColumns && info.Control.ParentColumn != null && Columns.Contains(info.Control.ParentColumn)) + { + Rectangle rect = GetColumnBounds(info.Control.ParentColumn.Index); + width = rect.Right - OffsetX - p.X; + } + context.Bounds = new Rectangle(p.X, p.Y, width, info.Bounds.Height); + ((EditableControl)info.Control).SetEditorBounds(context); + return; + } + } + } + + private Rectangle GetColumnBounds(int column) + { + int x = 0; + for (int i = 0; i < Columns.Count; i++) + { + if (Columns[i].IsVisible) + { + if (i < column) + x += Columns[i].Width; + else + return new Rectangle(x, 0, Columns[i].Width, 0); + } + } + return Rectangle.Empty; + } + + #endregion + + #region ModelEvents + private void BindModelEvents() + { + _model.NodesChanged += new EventHandler(_model_NodesChanged); + _model.NodesInserted += new EventHandler(_model_NodesInserted); + _model.NodesRemoved += new EventHandler(_model_NodesRemoved); + _model.StructureChanged += new EventHandler(_model_StructureChanged); + } + + private void UnbindModelEvents() + { + _model.NodesChanged -= new EventHandler(_model_NodesChanged); + _model.NodesInserted -= new EventHandler(_model_NodesInserted); + _model.NodesRemoved -= new EventHandler(_model_NodesRemoved); + _model.StructureChanged -= new EventHandler(_model_StructureChanged); + } + + private void _model_StructureChanged(object sender, TreePathEventArgs e) + { + if (e.Path == null) + throw new ArgumentNullException(); + + TreeNodeAdv node = FindNode(e.Path); + if (node != null) + { + ReadChilds(node); + UpdateSelection(); + + if (!_completeSuspendUpdate) + { + this.FullUpdate(); + this.Invalidate(); + } + } + //else + // throw new ArgumentException("Path not found"); + } + + private void _model_NodesRemoved(object sender, TreeModelEventArgs e) + { + TreeNodeAdv parent = FindNode(e.Path); + if (parent != null) + { + if (e.Indices != null) + { + List list = new List(e.Indices); + list.Sort(); + for (int n = list.Count - 1; n >= 0; n--) + { + int index = list[n]; + if (index >= 0 && index <= parent.Nodes.Count) + parent.Nodes.RemoveAt(index); + else + throw new ArgumentOutOfRangeException("Index out of range"); + } + } + else + { + for (int i = parent.Nodes.Count - 1; i >= 0; i--) + { + for (int n = 0; n < e.Children.Length; n++) + if (parent.Nodes[i].Tag == e.Children[n]) + { + parent.Nodes.RemoveAt(i); + break; + } + } + } + } + + UpdateSelection(); + SmartFullUpdate(); + } + + private void _model_NodesInserted(object sender, TreeModelEventArgs e) + { + if (e.Indices == null) + throw new ArgumentNullException("Indices"); + + TreeNodeAdv parent = FindNode(e.Path); + if (parent != null) + { + for (int i = 0; i < e.Children.Length; i++) + AddNewNode(parent, e.Children[i], e.Indices[i]); + } + SmartFullUpdate(); + } + + private void _model_NodesChanged(object sender, TreeModelEventArgs e) + { + TreeNodeAdv parent = FindNode(e.Path); + if (parent != null && parent.IsVisible && parent.IsExpanded) + { + if (InvokeRequired) + Invoke(new UpdateContentWidthDelegate(ClearNodesSize), e, parent); + else + ClearNodesSize(e, parent); + SmartFullUpdate(); + } + } + + private delegate void UpdateContentWidthDelegate(TreeModelEventArgs e, TreeNodeAdv parent); + private void ClearNodesSize(TreeModelEventArgs e, TreeNodeAdv parent) + { + if (e.Indices != null) + { + foreach (int index in e.Indices) + { + if (index >= 0 && index < parent.Nodes.Count) + { + TreeNodeAdv node = parent.Nodes[index]; + node.Height = node.RightBounds = null; + } + else + throw new ArgumentOutOfRangeException("Index out of range"); + } + } + else + { + foreach (TreeNodeAdv node in parent.Nodes) + { + foreach (object obj in e.Children) + if (node.Tag == obj) + { + node.Height = node.RightBounds = null; + } + } + } + } + #endregion + } +} \ No newline at end of file diff --git a/branches/ph-plugins/TreeViewAdv/Tree/TreeViewAdv.resx b/branches/ph-plugins/TreeViewAdv/Tree/TreeViewAdv.resx new file mode 100644 index 000000000..682fcf4c3 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/TreeViewAdv.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 128, 17 + + + 17, 17 + + + False + + \ No newline at end of file diff --git a/branches/ph-plugins/TreeViewAdv/Tree/TreeViewAdvCancelEventArgs.cs b/branches/ph-plugins/TreeViewAdv/Tree/TreeViewAdvCancelEventArgs.cs new file mode 100644 index 000000000..4b415807b --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/TreeViewAdvCancelEventArgs.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Aga.Controls.Tree +{ + public class TreeViewAdvCancelEventArgs : TreeViewAdvEventArgs + { + private bool _cancel; + + public bool Cancel + { + get { return _cancel; } + set { _cancel = value; } + } + + public TreeViewAdvCancelEventArgs(TreeNodeAdv node) + : base(node) + { + } + + } +} diff --git a/branches/ph-plugins/TreeViewAdv/Tree/TreeViewAdvEventArgs.cs b/branches/ph-plugins/TreeViewAdv/Tree/TreeViewAdvEventArgs.cs new file mode 100644 index 000000000..254a8be8f --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/Tree/TreeViewAdvEventArgs.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Aga.Controls.Tree +{ + public class TreeViewAdvEventArgs : EventArgs + { + private TreeNodeAdv _node; + + public TreeNodeAdv Node + { + get { return _node; } + } + + public TreeViewAdvEventArgs(TreeNodeAdv node) + { + _node = node; + } + } +} diff --git a/branches/ph-plugins/TreeViewAdv/app.config b/branches/ph-plugins/TreeViewAdv/app.config new file mode 100644 index 000000000..b7db28170 --- /dev/null +++ b/branches/ph-plugins/TreeViewAdv/app.config @@ -0,0 +1,3 @@ + + + diff --git a/branches/ph-plugins/TreeViewAdv/key.snk b/branches/ph-plugins/TreeViewAdv/key.snk new file mode 100644 index 000000000..0f01f8eda Binary files /dev/null and b/branches/ph-plugins/TreeViewAdv/key.snk differ diff --git a/branches/ph-plugins/native.html b/branches/ph-plugins/native.html new file mode 100644 index 000000000..7ad4a0235 --- /dev/null +++ b/branches/ph-plugins/native.html @@ -0,0 +1,1325 @@ + + + + The Definitive Native API Guide + + + +

The Definitive Native API Guide

+

Written by wj32.

+ +

NT Concepts

+ +

Alertable

+

A thread contains fields for two alertable states, one for kernel-mode and one for user-mode. + When a caller from one of these modes alerts a thread (e.g. using NtAlertThread), + the thread is put into an alerted state for the mode, and one of several things happen:

+
    +
  • If the thread is performing a kernel-mode alertable wait and it has just been alerted from + user-mode, nothing will happen.
  • +
  • If the thread is performing a kernel-mode alertable wait and it has just been alerted from + kernel-mode, the wait will be interrupted and the wait function will return + STATUS_ALERTED.
  • +
  • If the thread is performing a user-mode alertable wait and it has just been alerted from + user-mode, the wait will be interrupted as above.
  • +
  • If the thread is performing a user-mode alertable wait and it has just been alerted from + kernel-mode, the wait will be interrupted as above.
  • +
+

Note that if the thread is alerted and then performs an alertable wait, it will be interrupted + immediately without performing the wait.

+

The thread can also call NtTestAlert to check if it is alerted. In all of these + cases, the thread will be reset to a non-alerted state if it is alerted.

+ +

ALPC Port

+

Local Inter-process Communication (LPC) ports are an interprocess communication (IPC) method. + A server process creates a port object and waits for a client to connect to the port. Once + the connection is established, both the client and server receive a handle to a communication + port, a special instance of a port object which can be used to send and receive messages. From + Windows Vista onward, LPC ports have been replaced with ALPC ports (NtAlpc* + system calls). Existing port-related system calls now redirect to the new ALPC port functions.

+

Related functions: + NtCreatePort (server), + NtCreateWaitablePort (server), + NtConnectPort (client), + NtListenPort (server), + NtAcceptConnectPort (server), + NtRequestWaitReplyPort (client), + NtReplyWaitReceivePort (server), + NtReplyWaitReplyPort, + NtReplyPort. +

+

Related types: + PORT_MESSAGE, + PORT_VIEW, + REMOTE_PORT_VIEW, + LPCP_PORT_OBJECT. +

+ +

Asynchronous Procedure Calls (APCs)

+

Asynchronous procedure calls are functions which execute in the context of a specific thread. + There are two types of APCs, user-mode and kernel-mode. Each thread has two APC queues, one for + each type.

+

User-mode APCs are queued using NtQueueApcThread. They will not be called + unless an alertable wait is being performed or NtTestAlert is called in the + target thread. In those cases, a flag will be set in the target thread's APC state indicating that + one or more user-mode APCs are pending and the wait operation, if any, will be interrupted. When the + system call returns to user-mode, any pending user-mode APCs will be called.

+

A special use of user-mode APCs is thread termination, where a thread termination APC + (PspExitNormalApc) is inserted into the target thread. KiInsertQueueApc + contains a special case for thread termination and inserts the APC at the beginning of the + user-mode APC queue so that any wait operations in the target thread are interrupted and + the thread is terminated upon exiting the currently executing system service.

+

Kernel-mode APCs always preempt user-mode code, including user-mode APCs. There are two types of + kernel-mode APCs, normal and special. Normal APCs can be temporarily disabled by using + KeEnterCriticalRegion and both types of APCs can be temporarily disabled by using + KeEnterGuardedRegion or raising the IRQL to APC_LEVEL or higher.

+
    +
  • Normal kernel-mode APCs run at IRQL = PASSIVE_LEVEL and are inserted at the end + of the kernel-mode APC queue.
  • +
  • Special kernel-mode APCs run at IRQL = APC_LEVEL and are inserted after all existing + special APCs in the kernel-mode APC queue.
  • +
+

When a kernel-mode APC is inserted:

+
    +
  • If the target thread is running, a software interrupt is issued to call any queued kernel-mode + APCs in the thread.
  • +
  • If the target thread is waiting at IRQL = PASSIVE_LEVEL and special kernel-mode APCs + are not disabled, the wait will be interrupted with STATUS_KERNEL_APC. Note that normal + kernel-mode APCs cannot interrupt currently executing kernel-mode APCs which are waiting. Kernel-mode + APCs do not cause wait operations to return; rather, the wait function will be interrupted, + execute any queued kernel-mode APCs, and continue waiting.
  • +
+

Normal kernel-mode APCs are used to implement thread suspension.

+ +

Dispatcher Object

+

A dispatcher object is one which has two states: signaled and non-signaled. + These objects can be used with standard wait functions such as NtWaitForSingleObject or + NtWaitForMultipleObjects. These functions wait until one or more objects are set to + a signaled state. The dispatcher objects are:

+
    +
  • Events
  • +
  • Gates (kernel-mode only)
  • +
  • Mutants
  • +
  • Processes
  • +
  • Queues (kernel-mode only)
  • +
  • Semaphores
  • +
  • Threads
  • +
  • Timers
  • +
+

Events and gates are the most basic dispatcher objects, consisting of only a dispatcher header.

+

Note that the dispatcher header of a dispatcher object uses a signed integer field to represent + its signal state. Signal state values greater than 0 are considered to be signaled, while 0 is + considered to be non-signaled. This is useful for objects such as mutants and semaphores which can be + acquired and released multiple times.

+

Related types: + DISPATCHER_HEADER. +

+ +

Event

+

An event is a synchronization object that can be explicitly set to the signaled state. There are two + types of events:

+
    +
  • Notification event. When a notification event is set, all waiting threads are + released. The event remains signaled until it is explicitly reset.
  • +
  • Synchronization event. When a synchronization event is set, a single waiting + thread is released and the event is reset to a non-signaled state. When multiple threads wait + on a synchronization event, there is no guarantee of first-in first-out (FIFO) ordering.
  • +
+

Related functions: + NtCreateEvent, + NtOpenEvent, + NtClearEvent, + NtPulseEvent, + NtQueryEvent, + NtResetEvent, + NtSetEvent, + NtSetEventBoostPriority. +

+

Related types: + EVENT_INFORMATION_CLASS, + EVENT_BASIC_INFORMATION, + KEVENT. +

+ +

Event Pair

+

An event pair is a synchronization object containing two events, high and low. The + system provides set, wait, and atomic signal-and-wait functions for event pairs. Note that an event pair + object is not a dispatcher object and cannot be used with the standard wait functions.

+

Related functions: + NtCreateEventPair, + NtOpenEventPair, + NtSetHighEventPair, + NtSetHighWaitLowEventPair, + NtSetLowEventPair, + NtSetLowWaitHighEventPair, + NtWaitHighEvenPair, + NtWaitLowEventPair. +

+

Related types: + EEVENT_PAIR. +

+ +

Keyed Event

+

A keyed event is a dictionary of events. Each key must be even (the lowest bit must be clear). Internally, + the keyed event object is implemented using a linked list of pointers to threads. Every thread object has + two fields, KeyedWaitValue and KeyedWaitSemaphore. The KeyedWaitValue + contains the key being waited for by the thread. When a thread attempts to release a key which is not being + waited for, its KeyedWaitValue will be set to the key OR'ed with 1, to indicate that the thread + is attempting to release the key, and the thread will wait until another thread waits for the key.

+

Related functions: + NtCreateKeyedEvent, + NtOpenKeyedEvent, + NtReleaseKeyedEvent, + NtWaitForKeyedEvent. +

+

Related types: + KEYED_EVENT_OBJECT. +

+ +

Mutant

+

A "mutant" is a standard mutex. When a thread successfully waits for a mutant, it will acquire the mutant + and become the owner of the mutant; the mutant will be set to a non-signaled state. When the owning thread + releases the mutant the same number of times it has acquired it, the mutant will be set to a signaled state + and the mutant will no longer be owned, allowing other threads to acquire the mutant. Note that the mutant + can be acquired recursively, i.e. the owning thread can acquire the mutant more than once without causing a + deadlock.

+

Related functions: + NtCreateMutant, + NtOpenMutant, + NtQueryMutant, + NtReleaseMutant +

+

Related types: + MUTANT_INFORMATION_CLASS, + MUTANT_BASIC_INFORMATION, + KMUTANT. +

+ +

Port

+

See ALPC Port.

+ +

Profile

+

A profile object can be used for performance monitoring. When certain profiling events are triggered, + a corresponding counter in a user-allocated buffer is incremented.

+

Related functions: + NtCreateProfile, + NtQueryIntervalProfile, + NtSetIntervalProfile, + NtStartProfile, + NtStopProfile. +

+ +

Section

+

Sections are objects describing a region of memory "backed" by a file. There are two types of section + objects:

+
    +
  • File-backed section. File-backed sections are memory-mapped files, where mapped + view contents are the same as in the file. Writing to mapped views will also change the contents of the + the file, unless the section is mapped copy-on-write, where any changes are discarded after the last + view is unmapped and the last reference to the section is closed.
  • +
  • Pagefile-backed section. Page-file-backed sections are a form of shared memory; + any changes will be discarded after the section is freed. The section is not backed by any + user-specified file.
  • +
+

Multiple views of the section can be mapped, and changes will be reflected across processes.

+

Related functions: + NtCreateSection, + NtOpenSection, + NtAreMappedFilesTheSame, + NtExtendSection, + NtMapViewOfSection, + NtQuerySection, + NtUnmapViewOfSection. +

+ +

Semaphore

+

A semaphore is a synchronization object with a signal state that represents how many times it has been + acquired. Each time a semaphore is acquired, its signal state is decremented. Each time a semaphore is + released, its signal state is incremented (but cannot be greater than the limit). If a semaphore's + signal state is 0 (non-signaled), threads must wait until another thread releases the semaphore before they + can acquire the semaphore.

+

Related functions: + NtCreateSemaphore, + NtOpenSemaphore, + NtQuerySemaphore, + NtReleaseSemaphore. +

+

Related types: + SEMAPHORE_INFORMATION_CLASS, + SEMAPHORE_BASIC_INFORMATION, + KSEMAPHORE. +

+ +

Timer

+

A timer is executive object and a wrapper around the kernel timer object. There are two types of timers:

+
    +
  • Notification timer. When a notification timer is signaled, all waiting threads are + released. The timer remains signaled until explicitly reset.
  • +
  • Synchronization timer. When a synchronization timer is signaled, one waiting thread is + released and the timer is set to a non-signaled state.
  • +
+

A timer can be configured to be signaled periodically or to insert an APC into the thread that set the + timer when the timer is signaled.

+

Related functions: + NtCreateTimer, + NtOpenTimer, + NtCancelTimer, + NtQueryTimer, + NtSetTimer. +

+

Related types: + TIMER_INFORMATION_CLASS, + TIMER_BASIC_INFORMATION, + ETIMER, + KTIMER, + PTIMER_APC_ROUTINE. +

+ +

Wait

+

A thread can wait for one or more objects; the standard system calls are NtWaitForSingleObject, + NtWaitForMultipleObjects, NtSignalAndWaitForSingleObject, and a few type-specific + wait functions. The pointer-based kernel-mode functions are KeWaitForSingleObject and + KeWaitForMultipleObjects. These functions will block until a certain condition is met. For + example, *WaitForSingleObject will return when the specified object is signaled. + *WaitForMultipleObjects will return when all/any specified objects are signaled.

+

When a wait function is called, it initializes a wait block for each object to be waited for. The storage + for the wait blocks is supplied in the thread object by default, but the caller can allocate storage if + they wish. The wait function then checks if the wait can be satisfied immediately. If it could not, the + wait function inserts the wait block(s) into the dispatch header(s) of the object(s), sets the thread's state + to Waiting and will no longer be considered for execution. It then switches to another ready thread.

+

When an object is set to a signaled state (such as when an event is set or a mutant is released), + the function performs a wait test (KiWaitTest) which enumerates the wait blocks in the + object's dispatcher header and unwaits each waiting thread. Each waiting thread will now be ready to run.

+

A waiting thread regains control due to either a wait test or a kernel-mode APC. It proceeds to + call any queued kernel-mode APCs and check if the wait operation has been satisfied (for multiple-object + waits, this is when any/all objects have been signaled). If it has not, the wait function continues to repeat + the wait process until the wait operation has been satisfied.

+

For some object types, object state must be modified when a thread is finished waiting for the object. + For example, a semaphore's signal state must be decremented. These operations are called side-effects, + and are performed when a wait is satisfied.

+ +

NT Enumerations

+ +

Debug Object Access

+
+#define DEBUG_READ_EVENT 0x0001
+#define DEBUG_PROCESS_ASSIGN 0x0002
+#define DEBUG_SET_INFORMATION 0x0004
+#define DEBUG_QUERY_INFORMATION 0x0008
+#define DEBUG_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | DEBUG_READ_EVENT | \
+    DEBUG_PROCESS_ASSIGN | DEBUG_SET_INFORMATION | DEBUG_QUERY_INFORMATION)
+ +

Directory Object Access

+
+#define DIRECTORY_QUERY 0x0001
+#define DIRECTORY_TRAVERSE 0x0002
+#define DIRECTORY_CREATE_OBJECT 0x0004
+#define DIRECTORY_CREATE_SUBDIRECTORY 0x0008
+
+#define DIRECTORY_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | 0xf)
+ +

Event Access

+
+#define EVENT_QUERY_STATE 0x0001
+#define EVENT_MODIFY_STATE 0x0002
+#define EVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3)
+ +

Event Pair Access

+
+#define EVENT_PAIR_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE)
+ +

Keyed Event Access

+
+#define KEYEDEVENT_WAIT 0x0001
+#define KEYEDEVENT_WAKE 0x0002
+#define KEYEDEVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | KEYEDEVENT_WAIT | KEYEDEVENT_WAKE)
+ +

Mutant Access

+
+#define MUTANT_QUERY_STATE 0x0001
+
+#define MUTANT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE| MUTANT_QUERY_STATE)
+ +

Object Flags

+
+#define OBJ_INHERIT 0x00000002L
+#define OBJ_PERMANENT 0x00000010L
+#define OBJ_EXCLUSIVE 0x00000020L
+#define OBJ_CASE_INSENSITIVE 0x00000040L
+#define OBJ_OPENIF 0x00000080L
+#define OBJ_OPENLINK 0x00000100L
+#define OBJ_KERNEL_HANDLE 0x00000200L
+#define OBJ_FORCE_ACCESS_CHECK 0x00000400L
+#define OBJ_VALID_ATTRIBUTES 0x000007f2L
+

Members

+

OBJ_INHERIT

+

Specifies that the handle (in the appropriate context) should be inherited by child processes.

+

OBJ_PERMANENT

+

Specifies that the object is permanent and should not be freed when all references to it have been + closed. If this flag is not specified, the object is temporary and will be freed when all references + have been closed. User-mode callers must have SeCreatePermanentPrivilege in order to + create permanent objects.

+

OBJ_EXCLUSIVE

+

Specifies that the object should be opened for exclusive access; the object cannot be opened + again until the handle is closed.

+

OBJ_CASE_INSENSITIVE

+

Specifies that name comparisons should be made case insensitively.

+

OBJ_OPENIF

+

Specifies that if an object with the specified name already exists, the creation routine should + open the existing object. If this flag is not specified and the name already exists, the creation + routine will return STATUS_OBJECT_NAME_COLLISION.

+

OBJ_OPENLINK

+

Not used.

+

OBJ_KERNEL_HANDLE

+

Specifies that the handle should be opened in the context of the System process, i.e. a kernel + handle.

+

OBJ_FORCE_ACCESS_CHECK

+

Specifies that an access check should be performed, even if the caller is from kernel-mode.

+ +

Profile Access

+
+#define PROFILE_CONTROL 0x0001
+#define PROFILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | PROFILE_CONTROL)
+ +

Section Access

+
+#define SECTION_QUERY 0x0001
+#define SECTION_MAP_WRITE 0x0002
+#define SECTION_MAP_READ 0x0004
+#define SECTION_MAP_EXECUTE 0x0008
+#define SECTION_EXTEND_SIZE 0x0010
+#define SECTION_MAP_EXECUTE_EXPLICIT 0x0020
+
+#define SECTION_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | \
+    SECTION_MAP_WRITE | SECTION_MAP_READ | SECTION_MAP_EXECUTE | \
+    SECTION_EXTEND_SIZE)
+ +

Semaphore Access

+
+#define SEMAPHORE_QUERY_STATE 0x0001
+#define SEMAPHORE_MODIFY_STATE 0x0002
+
+#define SEMAPHORE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x3)
+ +

Timer Access

+
+#define TIMER_QUERY_STATE 0x0001
+#define TIMER_MODIFY_STATE 0x0002
+
+#define TIMER_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \
+    TIMER_QUERY_STATE | TIMER_MODIFY_STATE)
+ +

NT Structures

+ +

CLIENT_ID

+

A structure identifying a process or thread.

+
+typedef struct _CLIENT_ID
+{
+    HANDLE UniqueProcess;
+    HANDLE UniqueThread;
+} CLIENT_ID, *PCLIENT_ID;
+

Fields

+

UniqueProcess

+

A handle to the process, usually a process ID (PID).

+

UniqueThread

+

A handle to the thread, usually a thread ID (TID).

+ +

CURDIR

+

A structure describing the current directory of a process.

+
+typedef struct _CURDIR
+{
+    UNICODE_STRING DosPath;
+    HANDLE Handle;
+} CURDIR, *PCURDIR;
+

Fields

+

DosPath

+

A string containing the current directory name. This path is usually in DOS path format + (e.g. C:\Path\...).

+

Handle

+

A handle to the current directory of the process.

+ +

INITIAL_TEB

+

A structure describing the initial contents of a TIB.

+
+typedef struct _INITIAL_TEB
+{
+    struct
+    {
+        PVOID OldStackBase;
+        PVOID OldStackLimit;
+    } OldInitialTeb;
+    PVOID StackBase;
+    PVOID StackLimit;
+    PVOID StackAllocationBase;
+} INITIAL_TEB, *PINITIAL_TEB;
+

Fields

+

OldStackBase

+

Reserved for internal use by the operating system, possibly during stack expansion. Initialize this to zero.

+

OldStackLimit

+

Reserved for internal use by the operating system, possibly during stack expansion. Initialize this to zero.

+

StackBase

+

The top of the stack, considering that the stack grows downward.

+

StackLimit

+

The bottom limit of the committed stack. This value is always greater than or equal to + StackAllocationBase.

+

StackAllocationBase

+

The bottom of the stack, including the reserved/free space below StackLimit.

+

Notes

+

The definition of INITIAL_TEB at NTinternals is incorrect. See + this blog post + for more details.

+ +

OBJECT_ATTRIBUTES

+

A structure describing object properties such as its name, location and security attributes.

+
+typedef struct _OBJECT_ATTRIBUTES
+{
+    ULONG Length;
+    HANDLE RootDirectory;
+    PUNICODE_STRING ObjectName;
+    ULONG Attributes;
+    PVOID SecurityDescriptor; // PSECURITY_DESCRIPTOR
+    PVOID SecurityQualityOfService; // PSECURITY_QUALITY_OF_SERVICE
+} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;
+

Fields

+

Length

+

The length of the OBJECT_ATTRIBUTES structure; 24 on 32-bit systems and 40 on 64-bit systems.

+

RootDirectory

+

A handle to a directory object from which to begin searching for the object. If this value is NULL, + the object manager will use the default root directory.

+

ObjectName

+

The name of the object, optional when creating most types of objects.

+

Attributes

+

See Object Flags.

+

SecurityDescriptor

+

A pointer to a SECURITY_DESCRIPTOR structure for the object.

+

SecurityQualityOfService

+

A pointer to a SECURITY_QUALITY_OF_SERVICE structure for the object.

+ +

RTL_DRIVE_LETTER_CURDIR

+

Unknown.

+
+typedef struct _RTL_DRIVE_LETTER_CURDIR
+{
+    USHORT Flags;
+    USHORT Length;
+    ULONG TimeStamp;
+    STRING DosPath;
+} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR;
+

Fields

+

Flags

+

Possible values are:

+
+#define RTL_USER_PROC_CURDIR_CLOSE 0x00000002
+#define RTL_USER_PROC_CURDIR_INHERIT 0x00000003
+

Length

+

Unknown.

+

TimeStamp

+

Unknown.

+

DosPath

+

Unknown.

+ +

RTL_USER_PROCESS_PARAMETERS

+

A structure describing startup parameters for a process.

+
+#define RTL_MAX_DRIVE_LETTERS 32
+#define RTL_DRIVE_LETTER_VALID (USHORT)0x0001
+
+typedef struct _RTL_USER_PROCESS_PARAMETERS
+{
+    ULONG MaximumLength;
+    ULONG Length;
+
+    ULONG Flags;
+    ULONG DebugFlags;
+
+    HANDLE ConsoleHandle;
+    ULONG  ConsoleFlags;
+    HANDLE StandardInput;
+    HANDLE StandardOutput;
+    HANDLE StandardError;
+
+    CURDIR CurrentDirectory;
+    UNICODE_STRING DllPath;
+    UNICODE_STRING ImagePathName;
+    UNICODE_STRING CommandLine;
+    PVOID Environment;
+
+    ULONG StartingX;
+    ULONG StartingY;
+    ULONG CountX;
+    ULONG CountY;
+    ULONG CountCharsX;
+    ULONG CountCharsY;
+    ULONG FillAttribute;
+
+    ULONG WindowFlags;
+    ULONG ShowWindowFlags;
+    UNICODE_STRING WindowTitle;
+    UNICODE_STRING DesktopInfo;
+    UNICODE_STRING ShellInfo;
+    UNICODE_STRING RuntimeData;
+    RTL_DRIVE_LETTER_CURDIR CurrentDirectores[RTL_MAX_DRIVE_LETTERS];
+} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;
+ +

STRING, ANSI_STRING

+

A structure describing a counted ANSI string.

+
+typedef struct _STRING
+{
+    USHORT Length;
+    USHORT MaximumLength;
+    PCHAR Buffer;
+} STRING, *PSTRING, ANSI_STRING, *PANSI_STRING;
+

Fields

+

Length

+

The length, in bytes, of the string (excluding the null terminator, if present).

+

MaximumLength

+

The number of bytes allocated for the string in Buffer.

+

Buffer

+

A buffer containing the string.

+ +

UNICODE_STRING

+

A structure describing a counted Unicode string.

+
+typedef struct _UNICODE_STRING
+{
+    USHORT Length;
+    USHORT MaximumLength;
+    PWSTR Buffer;
+} UNICODE_STRING, *PUNICODE_STRING;
+

Fields

+

Length

+

The length, in bytes, of the string (excluding the null terminator, if present).

+

MaximumLength

+

The number of bytes allocated for the string in Buffer.

+

Buffer

+

A buffer containing the string.

+ +

NT System Calls

+ +

NtAlertThread

+

Alerts the specified thread, causing it to resume execution if it is in an alertable Wait state. + Otherwise, the thread is set to an alerted state.

+

If the specified thread is in a Wait state, it will be unwaited with a status of STATUS_ALERTED. + If the function is being called from user-mode, it cannot unwait a kernel-mode wait operation.

+
+NTSYSCALLAPI
+NTSTATUS
+NTAPI
+NtAlertThread(
+    __in HANDLE ThreadHandle
+    );
+

Arguments

+

ThreadHandle

+

A handle to the thread to alert. The handle must have THREAD_ALERT access.

+

Code paths

+

NtAlertThread ... KeAlertThread ... KiUnwaitThread ... KiReadyThread

+

Exported by

+

ntdll; KeAlertThread and ZwAlertThread are exported by ntoskrnl

+

Notes

+

If this function is called from user-mode, it will set the specified thread's user-mode alert state to + alerted. This will not affect kernel-mode code. The same is true when the function is called from kernel-mode.

+

Documented by

+

NT headers.

+ +

NtAlertResumeThread

+

Alerts the specified thread (see NtAlertThread) and resumes it.

+
+NTSYSCALLAPI
+NTSTATUS
+NTAPI
+NtAlertResumeThread(
+    __in HANDLE ThreadHandle,
+    __out_opt PULONG PreviousSuspendCount
+    );
+

Arguments

+

ThreadHandle

+

A handle to the thread to alert and resume. The handle must have THREAD_SUSPEND_RESUME access.

+

Code paths

+

NtAlertResumeThread ... KeAlertResumeThread ... KiUnwaitThread ... KiReadyThread

+

Exported by

+

ntdll

+

Notes

+

See notes in NtAlertThread.

+

Documented by

+

NT headers.

+ +

NtClose

+

Closes a handle.

+
+NTSYSCALLAPI
+NTSTATUS
+NTAPI
+NtClose(
+    __in HANDLE Handle
+    );
+

Arguments

+

Handle

+

The handle to close. If the object referenced by the handle is temporary and has no references, it will be freed.

+

Code paths

+

NtClose ... ObpCloseHandle ... ObpCloseHandleTableEntry ... ExDestroyHandle ... ExpFreeHandleTableEntry

+

Exported by

+

ntdll, ntoskrnl

+

Documented by

+

NT headers.

+ +

NtCreateDebugObject

+

Creates a debug object.

+
+NTSYSCALLAPI
+NTSTATUS
+NTAPI
+NtCreateDebugObject(
+    __out PHANDLE DebugObjectHandle,
+    __in ACCESS_MASK DesiredAccess,
+    __in POBJECT_ATTRIBUTES ObjectAttributes,
+    __in ULONG Flags
+    );
+

Arguments

+

DebugObjectHandle

+

A variable that receives a handle to the new debug object.

+

DesiredAccess

+

The desired access to the new debug object. See Debug Object Access.

+

ObjectAttributes

+

See OBJECT_ATTRIBUTES.

+

Flags

+

The only flag currently defined is:

+
+#define DEBUG_KILL_ON_CLOSE 0x1
+

Code paths

+

NtCreateDebugObject ... ObCreateObject ...

+

Exported by

+

ntdll

+

Documented by

+

NT headers

+ +

NtCreateDirectoryObject

+

Creates a directory object.

+
+NTSYSCALLAPI
+NTSTATUS
+NTAPI
+NtCreateDirectoryObject(
+    __out PHANDLE DirectoryHandle,
+    __in ACCESS_MASK DesiredAccess,
+    __in POBJECT_ATTRIBUTES ObjectAttributes
+    );
+

Arguments

+

DirectoryHandle

+

A variable that receives a handle to the new directory object.

+

DesiredAccess

+

The desired access to the new directory object. See Directory Object Access.

+

ObjectAttributes

+

See OBJECT_ATTRIBUTES.

+

Code paths

+

NtCreateDirectoryObject ... ObCreateObject ...

+

Exported by

+

ntdll; ZwCreateDirectoryObject is exported by ntoskrnl

+

Documented by

+

NT headers

+ +

NtCreateProcess

+

Creates a process (with no threads).

+
+NTSYSCALLAPI
+NTSTATUS
+NTAPI
+NtCreateProcess(
+    __out PHANDLE ProcessHandle,
+    __in ACCESS_MASK DesiredAccess,
+    __in_opt POBJECT_ATTRIBUTES ObjectAttributes,
+    __in HANDLE ParentProcess,
+    __in BOOLEAN InheritObjectTable,
+    __in_opt HANDLE SectionHandle,
+    __in_opt HANDLE DebugPort,
+    __in_opt HANDLE ExceptionPort
+    );
+

Arguments

+

ProcessHandle

+

A variable that receives a handle to the new process.

+

DesiredAccess

+

The desired access to the new process.

+

ObjectAttributes

+

See OBJECT_ATTRIBUTES.

+

ParentProcess

+

A handle to a parent process. If no section (in SectionHandle) was specified, the new process + will inherit the address space, handles and other characteristics of the parent process. If a section was + specified, the new process will receive a new address space created from the section but will still inherit + handles (if specified in InheritObjectTable) and other characteristics. The parent process + must be specified unless the new process is the first process to be created on the system (the System process).

+

InheritObjectTable

+

Whether ObInitProcess will duplicate handles with the OBJ_INHERIT attribute from + the parent process into the new process.

+

SectionHandle

+

A handle to a section which will be used to create the new process' address space. The handle must have + SECTION_MAP_EXECUTE access.

+

DebugPort

+

A handle to a debug object which the process will be assigned to. The handle must have DEBUG_PROCESS_ASSIGN + access.

+

ExceptionPort

+

A handle to a LPC port which will be notified when an exception occurs in the process.

+

Code paths

+

NtCreateProcess ... NtCreateProcessEx ... PspCreateProcess ... + PspAllocateProcess ... KeInitializeProcess

+

Exported by

+

ntdll

+

Notes

+

The new process does not have any threads. You can create one using NtCreateThread or + RtlCreateUserThread.

+

Documented by

+

NT headers.

+ +

NtCreateProcessEx

+

Creates a process (with no threads).

+
+NTSYSCALLAPI
+NTSTATUS
+NTAPI
+NtCreateProcessEx(
+    __out PHANDLE ProcessHandle,
+    __in ACCESS_MASK DesiredAccess,
+    __in_opt POBJECT_ATTRIBUTES ObjectAttributes,
+    __in HANDLE ParentProcess,
+    __in ULONG Flags,
+    __in_opt HANDLE SectionHandle,
+    __in_opt HANDLE DebugPort,
+    __in_opt HANDLE ExceptionPort,
+    __in ULONG JobMemberLevel
+    );
+

Arguments

+

See NtCreateProcess.

+

Flags

+

A combination of flags which control the creation of the new process:

+
+#define PROCESS_CREATE_FLAGS_BREAKAWAY 0x00000001
+#define PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT 0x00000002
+#define PROCESS_CREATE_FLAGS_INHERIT_HANDLES 0x00000004
+#define PROCESS_CREATE_FLAGS_OVERRIDE_ADDRESS_SPACE 0x00000008
+#define PROCESS_CREATE_FLAGS_LARGE_PAGES 0x00000010
+

JobMemberLevel

+

The member level within a job set.

+

Code paths

+

NtCreateProcessEx ... PspCreateProcess ... PspAllocateProcess ... + KeInitializeProcess

+

Exported by

+

ntdll

+

Documented by

+

NT headers.

+ +

NtCreateThread

+

Creates a thread.

+
+NTSYSCALLAPI
+NTSTATUS
+NTAPI
+NtCreateThread(
+    __out PHANDLE ThreadHandle,
+    __in ACCESS_MASK DesiredAccess,
+    __in_opt POBJECT_ATTRIBUTES ObjectAttributes,
+    __in HANDLE ProcessHandle,
+    __out PCLIENT_ID ClientId,
+    __in PCONTEXT ThreadContext,
+    __in PINITIAL_TEB InitialTeb,
+    __in BOOLEAN CreateSuspended
+    );
+

Arguments

+

ThreadHandle

+

A variable which receives a handle to the new thread.

+

DesiredAccess

+

The desired access to the new thread.

+

ObjectAttributes

+

See OBJECT_ATTRIBUTES.

+

ProcessHandle

+

A handle to the process in which the thread is to be created. The handle must have + PROCESS_CREATE_THREAD access.

+

ClientId

+

A variable which receives the client ID of the new thread.

+

ThreadContext

+

The initial context for the thread.

+

InitialTeb

+

A structure which describes the initial state of the thread's TIB. See INITIAL_TEB.

+

CreateSuspended

+

Whether the thread should be suspended when it is created. You can resume the thread using NtResumeThread.

+

Code paths

+

NtCreateThread ... PspCreateThread ... PspAllocateThread ... + KeInitThread ...

+

Exported by

+

ntdll

+

Notes

+

In the arguments, InitialTeb actually specifies the initial Thread Information Block (TIB) for the thread. + The TIB is stored in the Thread Environment Block (TEB) of the thread, and can be referenced by the fs + segment register. The name TIB is pre-NT; see + Under The Hood -- MSJ, May 1996. See NT_TIB for + more information on the TIB.

+

Documented by

+

NT headers.

+ +

NtCreateThreadEx

+

The documentation for this function has been produced by reverse-engineering and may be incorrect.

+

Creates a thread.

+
+NTSYSCALLAPI
+NTSTATUS
+NTAPI
+NtCreateThreadEx(
+    __out PHANDLE ThreadHandle,
+    __in ACCESS_MASK DesiredAccess,
+    __in_opt POBJECT_ATTRIBUTES ObjectAttributes,
+    __in HANDLE ProcessHandle,
+    __in PVOID StartAddress,
+    __in PVOID Parameter,
+    __in ULONG Flags,
+    __in_opt ULONG Reserved,
+    __in_opt ULONG StackCommit,
+    __in_opt ULONG StackReserve,
+    __in_opt PVOID ProcessContext
+    );
+

Arguments

+

ThreadHandle

+

A variable which receives a handle to the new thread.

+

DesiredAccess

+

The desired access to the new thread.

+

ObjectAttributes

+

See OBJECT_ATTRIBUTES.

+

ProcessHandle

+

A handle to the process in which the thread is to be created. The handle must have + PROCESS_CREATE_THREAD access.

+

StartAddress

+

The function to call in the new thread.

+

Parameter

+

The parameter to pass to the function.

+

Flags

+

Flags which control the creation of the thread:

+
+#define THREAD_CREATE_FLAGS_SUSPENDED 0x1
+

Reserved

+

This value is ignored by the operating system.

+

StackCommit

+

The number of bytes to commit in the thread stack.

+

StackReserve

+

The number of bytes to reserve for the thread stack.

+

ProcessContext

+

An optional structure which is passed to PspBuildCreateProcessContext.

+

Code paths

+

NtCreateThreadEx ... PspCreateThread ... PspAllocateThread ... + KeInitThread ...

+

Exported by

+

ntdll

+

Documented by

+

wj32

+ +

NtOpenProcess

+

Opens a process.

+
+NTSYSCALLAPI
+NTSTATUS
+NTAPI
+NtOpenProcess(
+    __out PHANDLE ProcessHandle,
+    __in ACCESS_MASK DesiredAccess,
+    __in POBJECT_ATTRIBUTES ObjectAttributes,
+    __in_opt PCLIENT_ID ClientId
+    );
+

Arguments

+

ProcessHandle

+

A variable which receives a handle to a process.

+

DesiredAccess

+

The desired access to the process.

+

ObjectAttributes

+

See OBJECT_ATTRIBUTES. The ObjectName field must be NULL.

+

ClientId

+

A CLIENT_ID specifying the process to open. If the UniqueThread field + is not 0, the function will open the process belonging to the thread specified by the thread ID in + UniqueThread. Otherwise, the function will open the process specified by the process ID + in the UniqueProcess field.

+

Code paths

+

NtOpenProcess ... PsOpenProcess ... ObOpenObjectByPointer ...

+

Exported by

+

ntdll, ntoskrnl

+

Documented by

+

NT headers.

+ +

NtQueueApcThread

+

Queues a user-mode APC to the specified thread. The APC will execute when the thread performs an alertable wait or + calls NtTestAlert. Any wait operations will return with STATUS_USER_APC.

+
+NTSYSCALLAPI
+NTSTATUS
+NTAPI
+NtQueueApcThread(
+    __in HANDLE ThreadHandle,
+    __in PPS_APC_ROUTINE ApcRoutine,
+    __in_opt PVOID ApcArgument1,
+    __in_opt PVOID ApcArgument2,
+    __in_opt PVOID ApcArgument3
+    );
+

Arguments

+

ThreadHandle

+

A handle to a thread. The handle must have THREAD_SET_CONTEXT access.

+

ApcRoutine.

+

An APC routine to execute:

+
+typedef
+VOID
+(*PPS_APC_ROUTINE)(
+    __in_opt PVOID ApcArgument1,
+    __in_opt PVOID ApcArgument2,
+    __in_opt PVOID ApcArgument3
+    );
+

ApcArgument1..3

+

The arguments to pass to the APC routine.

+

Code paths

+

NtQueueApcThread ... KeInsertQueueApc ... KiInsertQueueApc ... InsertHeadList

+

Exported by

+

ntdll; KeInsertQueueApc is exported by ntoskrnl

+

Documented by

+

NT headers.

+ +

NtRegisterThreadTerminatePort

+

Registers a port which will be notified when the current thread terminates.

+
+NTSYSCALLAPI
+NTSTATUS
+NTAPI
+NtRegisterThreadTerminatePort(
+    __in HANDLE PortHandle
+    );
+

Arguments

+

PortHandle

+

A handle to the LPC port to be notified when the current thread terminates. The port will be added to a singly linked list + of ports which will all be notified when the thread terminates.

+

Exported by

+

ntdll

+

Documented by

+

NT headers.

+ +

NtResumeProcess

+

Resumes each thread in a process.

+
+NTSYSCALLAPI
+NTSTATUS
+NTAPI
+NtResumeProcess(
+    __in HANDLE ProcessHandle
+    );
+

Arguments

+

ProcessHandle

+

A handle to the process to resume. The handle must have PROCESS_SUSPEND_RESUME access.

+

Code paths

+

NtResumeProcess ... PsResumeProcess ... KeResumeThread ... + KiWaitTest ...

+

Exported by

+

ntdll; PsResumeProcess is exported by ntoskrnl

+

Documented by

+

NT headers.

+ +

NtResumeThread

+

Resumes the specified thread. The thread is not actually resumed until the suspend count reaches 0 + (i.e. the thread has been resumed the same number of times it has been suspended).

+
+NTSYSCALLAPI
+NTSTATUS
+NTAPI
+NtResumeThread(
+    __in HANDLE ThreadHandle,
+    __out_opt PULONG PreviousSuspendCount
+    );
+

Arguments

+

ThreadHandle

+

A handle to the thread to resume. The handle must have THREAD_SUSPEND_RESUME access.

+

PreviousSuspendCount

+

A variable that receives the previous suspend count (the number of times the thread has been suspended + minus the number of times the thread has been resumed).

+

Code paths

+

NtResumeThread ... KeResumeThread ... KiWaitTest ...

+

Exported by

+

ntdll

+

Documented by

+

NT headers.

+ +

NtSuspendProcess

+

Suspends each thread in a process.

+
+NTSYSCALLAPI
+NTSTATUS
+NTAPI
+NtSuspendProcess(
+    __in HANDLE ProcessHandle
+    );
+

Arguments

+

ProcessHandle

+

A handle to the process to suspend. The handle must have PROCESS_SUSPEND_RESUME access.

+

Code paths

+

NtSuspendProcess ... PsSuspendProcess ... PsSuspendThread ... + KeSuspendThread ... KiInsertQueueApc ... KiSuspendThread ... + KeWaitForSingleObject ...

+

Exported by

+

ntdll; PsSuspendProcess is exported by ntoskrnl

+

Documented by

+

NT headers.

+ +

NtSuspendThread

+

Suspends the specified thread.

+
+NTSYSCALLAPI
+NTSTATUS
+NTAPI
+NtSuspendThread(
+    __in HANDLE ThreadHandle,
+    __out_opt PULONG PreviousSuspendCount
+    );
+

Arguments

+

ThreadHandle

+

A handle to the thread to suspend. The handle must have THREAD_SUSPEND_RESUME access.

+

PreviousSuspendCount

+

A variable that receives the previous suspend count (the number of times the thread has been suspended + minus the number of times the thread has been resumed).

+

Code paths

+

NtSuspendThread ... PsSuspendThread ... KeSuspendThread ... + KiInsertQueueApc ... KiSuspendThread ... KeWaitForSingleObject ...

+

Exported by

+

ntdll

+

Documented by

+

NT headers.

+ +

NtTerminateProcess

+

Terminates the specified process.

+
+NTSYSCALLAPI
+NTSTATUS
+NTAPI
+NtTerminateProcess(
+    __in_opt HANDLE ProcessHandle,
+    __in NTSTATUS ExitStatus
+    );
+

Arguments

+

ProcessHandle

+

A handle to the process to terminate. The handle must have PROCESS_TERMINATE access. If this argument + is NULL, the current process will be terminated.

+

ExitStatus

+

A NT status value that will be saved.

+

Code paths

+

NtTerminateProcess ... PspTerminateAllThreads ... PspTerminateThreadByPointer ... + KeInsertQueueApc ... PspExitNormalApc ... PsExitSpecialApc ... + PspExitThread ... PspExitProcess ...

+

Exported by

+

ntdll; ZwTerminateProcess is exported by ntoskrnl

+

Documented by

+

NT headers.

+ +

NtTerminateThread

+

Terminates the specified thread.

+
+NTSYSCALLAPI
+NTSTATUS
+NTAPI
+NtTerminateThread(
+    __in_opt HANDLE ThreadHandle,
+    __in NTSTATUS ExitStatus
+    );
+

Arguments

+

ThreadHandle

+

A handle to the thread to terminate. The handle must have THREAD_TERMINATE access. If this argument + is NULL, the current thread will be terminated. If the thread is the last in the process, the function will return + STATUS_CANT_TERMINATE_SELF. The reason for this is that user-mode libraries (such as ntdll) are required to + call NtTerminateProcess if this function fails with STATUS_CANT_TERMINATE_SELF.

+

ExitStatus

+

A NT status value that will be saved.

+

Code paths

+

NtTerminateThread ... PspTerminateThreadByPointer ... KeInsertQueueApc ... + PspExitNormalApc ... PsExitSpecialApc ... PspExitThread ... + KeTerminateThread ... KiInsertQueue ... [PspReaper] KeDeleteThread ...

+

Exported by

+

ntdll

+

Documented by

+

NT headers.

+ +

NtTestAlert

+

Checks whether the current thread is alerted. If it is, the thread's alerted state will be cleared and + STATUS_ALERTED will be returned. Otherwise, STATUS_SUCCESS will be returned.

+

If the function is being called from user-mode, any user-mode APCs will be called when the system service exits.

+
+NTSYSCALLAPI
+NTSTATUS
+NTAPI
+NtTestAlert(
+    VOID
+    );
+

Code paths

+

NtTestAlert ... KeTestAlertThread

+

Exported by

+

ntdll; KeTestAlertThread is exported by ntoskrnl

+

Notes

+

See notes in NtAlertThread.

+

Documented by

+

NT headers.

+ +

RtlCreateUserProcess

+

Creates a process and an initial thread.

+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlCreateUserProcess(
+    __in PUNICODE_STRING NtImagePathName,
+    __in ULONG Attributes,
+    __in PRTL_USER_PROCESS_PARAMETERS ProcessParameters,
+    __in_opt PSECURITY_DESCRIPTOR ProcessSecurityDescriptor,
+    __in_opt PSECURITY_DESCRIPTOR ThreadSecurityDescriptor,
+    __in_opt HANDLE ParentProcess,
+    __in BOOLEAN InheritHandles,
+    __in_opt HANDLE DebugPort,
+    __in_opt HANDLE ExceptionPort,
+    __out PRTL_USER_PROCESS_INFORMATION ProcessInformation
+    );
+

Arguments

+

NtImagePathName

+

A UNICODE_STRING which specifies the image file (EXE) from which to create the process. The file name + must be in native format, e.g. \SystemRoot\notepad.exe.

+

Attributes

+

The object attributes to use when opening the image file, e.g. OBJ_INHERIT.

+

ProcessParameters

+

See RTL_USER_PROCESS_PARAMETERS.

+

ProcessSecurityDescriptor

+

A security descriptor for the new process.

+

ThreadSecurityDescriptor

+

A security descriptor for the initial thread in the new process.

+

ParentProcess

+

A process from which to inherit handles and other characteristics. RtlCreateUserProcess will also + duplicate standard handles (input, output and error) from the parent process to the new process.

+

InheritHandles

+

Whether NtCreateProcess should duplicate handles with the OBJ_INHERIT attribute.

+

DebugPort

+

A handle to a debug object which the process will be assigned to. The handle must have DEBUG_PROCESS_ASSIGN + access.

+

ExceptionPort

+

A handle to a LPC port which will be notified when an exception occurs in the process.

+

ProcessInformation

+

A RTL_USER_PROCESS_INFORMATION structure which will receive information about the new process:

+
+typedef struct _RTL_USER_PROCESS_INFORMATION
+{
+    ULONG Length;
+    HANDLE Process;
+    HANDLE Thread;
+    CLIENT_ID ClientId;
+    SECTION_IMAGE_INFORMATION ImageInformation;
+} RTL_USER_PROCESS_INFORMATION, *PRTL_USER_PROCESS_INFORMATION;
+

Code paths

+

RtlCreateUserProcess ... NtCreateProcess ...

+

Exported by

+

ntdll

+

Notes

+

This RtlCreateUserProcess does not notify CSR of the new process, so the process' use of the + Windows API is limited.

+

Documented by

+

NT headers.

+ +

RtlCreateUserThread

+

Creates a thread.

+
+NTSYSAPI
+NTSTATUS
+NTAPI
+RtlCreateUserThread(
+    __in HANDLE Process,
+    __in_opt PSECURITY_DESCRIPTOR ThreadSecurityDescriptor,
+    __in BOOLEAN CreateSuspended,
+    __in_opt ULONG ZeroBits,
+    __in_opt SIZE_T MaximumStackSize,
+    __in_opt SIZE_T CommittedStackSize,
+    __in PUSER_THREAD_START_ROUTINE StartAddress,
+    __in_opt PVOID Parameter,
+    __out_opt PHANDLE Thread,
+    __out_opt PCLIENT_ID ClientId
+    );
+

Arguments

+

Process

+

A handle to the process in which the thread will be created. The handle must have PROCESS_CREATE_THREAD and + PROCESS_VM_OPERATION access.

+

ThreadSecurityDescriptor

+

A security descriptor for the new thread.

+

CreateSuspended

+

Whether the thread should be suspended when it is created. You can resume the thread using NtResumeThread.

+

ZeroBits

+

The number of bits that must be clear when the thread stack is allocated. This value cannot be greater than 21.

+

MaximumStackSize

+

The maximum size of the thread stack.

+

CommittedStackSize

+

The number of bytes of initially committed thread stack.

+

StartAddress

+

The function to call in the new thread:

+
+typedef
+NTSTATUS
+(*PUSER_THREAD_START_ROUTINE)(
+    PVOID ThreadParameter
+    );
+

Parameter

+

A value to pass to the function specified by StartAddress.

+

Thread

+

A variable which receives a handle to the new thread. The handle will have THREAD_ALL_ACCESS access.

+

ClientId

+

A variable which receives the client ID of the new thread.

+

Code paths

+

RtlCreateUserThread ... NtCreateThread ...

+

Exported by

+

ntdll

+

Notes

+

This function is not limited to creating threads in processes within the current session, a limitation present in + the CreateRemoteThread Windows API function. This is due to the fact that RtlCreateUserThread + does not attempt to notify CSR of the new thread, removing the session limitation but also limiting your use of the + Windows API.

+

Documented by

+

NT headers.

+ + + +