Why is conhost.exe being launched?-Collection of common programming errors
ripper234I’m launching a Java process (“java.exe”) from .Net. using Process.Start(). In addition to the Java process, another process called conhost.exe is launched somehow. I am redirecting the output from the Java process to the .Net process.
- Why is conhost.exe even launched?
- How do I track it from .Net? I want to track this specific instance, and since I’m not creating it directly (but rather the Java.exe process), I don’t have it’s PID.
MichaelIn earlier versions of Windows, console windows were hosted in CSRSS, which is a highly privileged, trusted, system critical process. On Win7, it appears that console windows are now hosted in conhost.exe, which has less rights. This was probably done for security & reliability reasons – a security issue in the console system won’t compromise the entire box, and a crash in the console code won’t blue screen the system.
zespriSorry, for necroing such an old thread, but I thought that the question is interesting and worth an answer.
Why is conhost.exe even launched? As explained in other posts this is now a default way to host console applications. Further details can be found in the article linked in another answer here: What is conhost.exe and Why Is It Running?
How do I track it from .Net? I want to track this specific instance, and since I’m not creating it directly (but rather the Java.exe process), I don’t have it’s PID.
As other has noted there should be little reason to “track” the conhost process. Having said that, there is a way to obtain conhost process id from your java.exe process Id. All you have to do is enumerate all the process handles that every conhost process in the system has, and if one of these handles point to a process with the same Id as your jawa.exe, this will be the conhost.exe handle you are after. Covert it to Process Id and you get the PID for conhost.exe
So this is theory. How to achieve this in practice? There an excellent article that shows some code that is doing something very similar. I have modified this code a bit to suit our task at hand. In the end you
Utility.GetConhostIdByProcessId
static function and pass the PID of your java.exe to it, and it will return you the PID of relevant conhost.exe A test call to this method can be found in the Main function in the example below.And now the code:
using System; using System.Collections.Generic; using System.Diagnostics; using System.Runtime.InteropServices; namespace SO1313195 { class Program { static void Main() { const int processId = 6980; int? result = Utility.GetConhostIdByProcessId(processId); if (result.HasValue) { Console.WriteLine("Process {0} has conhost {1}", processId, result.Value); } else { Console.WriteLine("Unable to find conhost for process {0}", processId); } Console.ReadLine(); } } public class Win32Api { [DllImportAttribute("kernel32.dll", EntryPoint = "GetProcessId")] public static extern uint GetProcessId([In]IntPtr process); [DllImport("ntdll.dll")] public static extern int NtQueryObject(IntPtr objectHandle, int objectInformationClass, IntPtr objectInformation, int objectInformationLength, ref int returnLength); [DllImport("ntdll.dll")] public static extern uint NtQuerySystemInformation(int systemInformationClass, IntPtr systemInformation, int systemInformationLength, ref int returnLength); [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")] public static extern void CopyMemory(byte[] destination, IntPtr source, uint length); [DllImport("kernel32.dll")] public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwProcessId); [DllImport("kernel32.dll")] public static extern int CloseHandle(IntPtr hObject); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool DuplicateHandle(IntPtr hSourceProcessHandle, ushort hSourceHandle, IntPtr hTargetProcessHandle, out IntPtr lpTargetHandle, uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwOptions); [DllImport("kernel32.dll")] public static extern IntPtr GetCurrentProcess(); public enum ObjectInformationClass { ObjectBasicInformation = 0, ObjectNameInformation = 1, ObjectTypeInformation = 2, ObjectAllTypesInformation = 3, ObjectHandleInformation = 4 } [Flags] public enum ProcessAccessFlags : uint { All = 0x001F0FFF, Terminate = 0x00000001, CreateThread = 0x00000002, VmOperation = 0x00000008, VmRead = 0x00000010, VmWrite = 0x00000020, DupHandle = 0x00000040, SetInformation = 0x00000200, QueryInformation = 0x00000400, Synchronize = 0x00100000 } [StructLayout(LayoutKind.Sequential)] public struct OBJECT_BASIC_INFORMATION { public int Attributes; public int GrantedAccess; public int HandleCount; public int PointerCount; public int PagedPoolUsage; public int NonPagedPoolUsage; public int Reserved1; public int Reserved2; public int Reserved3; public int NameInformationLength; public int TypeInformationLength; public int SecurityDescriptorLength; public System.Runtime.InteropServices.ComTypes.FILETIME CreateTime; } [StructLayout(LayoutKind.Sequential)] public struct OBJECT_TYPE_INFORMATION { public UNICODE_STRING Name; public int ObjectCount; public int HandleCount; public int Reserved1; public int Reserved2; public int Reserved3; public int Reserved4; public int PeakObjectCount; public int PeakHandleCount; public int Reserved5; public int Reserved6; public int Reserved7; public int Reserved8; public int InvalidAttributes; public GENERIC_MAPPING GenericMapping; public int ValidAccess; public byte Unknown; public byte MaintainHandleDatabase; public int PoolType; public int PagedPoolUsage; public int NonPagedPoolUsage; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct UNICODE_STRING { public ushort Length; public ushort MaximumLength; public IntPtr Buffer; } [StructLayout(LayoutKind.Sequential)] public struct GENERIC_MAPPING { public int GenericRead; public int GenericWrite; public int GenericExecute; public int GenericAll; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct SYSTEM_HANDLE_INFORMATION { public int ProcessID; public byte ObjectTypeNumber; public byte Flags; // 0x01 = PROTECT_FROM_CLOSE, 0x02 = INHERIT public ushort Handle; public int Object_Pointer; public UInt32 GrantedAccess; } public const uint STATUS_INFO_LENGTH_MISMATCH = 0xC0000004; public const int DUPLICATE_SAME_ACCESS = 0x2; } class Utility { public static int? GetConhostIdByProcessId(int processId) { foreach (Process process in Process.GetProcessesByName("conhost")) { IntPtr processHwnd = Win32Api.OpenProcess(Win32Api.ProcessAccessFlags.DupHandle, false, process.Id); List lstHandles = GetHandles(process); foreach (Win32Api.SYSTEM_HANDLE_INFORMATION handle in lstHandles) { int? id = GetFileDetails(processHwnd, handle); if (id == processId) { return process.Id; } } } return null; } private static int? GetFileDetails(IntPtr processHwnd, Win32Api.SYSTEM_HANDLE_INFORMATION systemHandleInformation) { IntPtr ipHandle; Win32Api.OBJECT_BASIC_INFORMATION objBasic = new Win32Api.OBJECT_BASIC_INFORMATION(); Win32Api.OBJECT_TYPE_INFORMATION objObjectType = new Win32Api.OBJECT_TYPE_INFORMATION(); int nLength = 0; if (!Win32Api.DuplicateHandle(processHwnd, systemHandleInformation.Handle, Win32Api.GetCurrentProcess(), out ipHandle, 0, false, Win32Api.DUPLICATE_SAME_ACCESS)) return null; IntPtr ipBasic = Marshal.AllocHGlobal(Marshal.SizeOf(objBasic)); Win32Api.NtQueryObject(ipHandle, (int)Win32Api.ObjectInformationClass.ObjectBasicInformation, ipBasic, Marshal.SizeOf(objBasic), ref nLength); objBasic = (Win32Api.OBJECT_BASIC_INFORMATION)Marshal.PtrToStructure(ipBasic, objBasic.GetType()); Marshal.FreeHGlobal(ipBasic); IntPtr ipObjectType = Marshal.AllocHGlobal(objBasic.TypeInformationLength); nLength = objBasic.TypeInformationLength; while ((uint)(Win32Api.NtQueryObject(ipHandle, (int)Win32Api.ObjectInformationClass.ObjectTypeInformation, ipObjectType, nLength, ref nLength)) == Win32Api.STATUS_INFO_LENGTH_MISMATCH) { Marshal.FreeHGlobal(ipObjectType); ipObjectType = Marshal.AllocHGlobal(nLength); } objObjectType = (Win32Api.OBJECT_TYPE_INFORMATION)Marshal.PtrToStructure(ipObjectType, objObjectType.GetType()); IntPtr ipTemp = Is64Bits() ? new IntPtr(Convert.ToInt64(objObjectType.Name.Buffer.ToString(), 10) >> 32) : objObjectType.Name.Buffer; string strObjectTypeName = Marshal.PtrToStringUni(ipTemp, objObjectType.Name.Length >> 1); Marshal.FreeHGlobal(ipObjectType); if (strObjectTypeName != "Process") return null; return (int)Win32Api.GetProcessId(ipHandle); } private static List GetHandles(Process process) { const int CNST_SYSTEM_HANDLE_INFORMATION = 16; const uint STATUS_INFO_LENGTH_MISMATCH = 0xc0000004; int nHandleInfoSize = 0x10000; IntPtr ipHandlePointer = Marshal.AllocHGlobal(nHandleInfoSize); int nLength = 0; IntPtr ipHandle; while ((Win32Api.NtQuerySystemInformation(CNST_SYSTEM_HANDLE_INFORMATION, ipHandlePointer, nHandleInfoSize, ref nLength)) == STATUS_INFO_LENGTH_MISMATCH) { nHandleInfoSize = nLength; Marshal.FreeHGlobal(ipHandlePointer); ipHandlePointer = Marshal.AllocHGlobal(nLength); } byte[] baTemp = new byte[nLength]; Win32Api.CopyMemory(baTemp, ipHandlePointer, (uint)nLength); long lHandleCount; if (Is64Bits()) { lHandleCount = Marshal.ReadInt64(ipHandlePointer); ipHandle = new IntPtr(ipHandlePointer.ToInt64() + 8); } else { lHandleCount = Marshal.ReadInt32(ipHandlePointer); ipHandle = new IntPtr(ipHandlePointer.ToInt32() + 4); } Win32Api.SYSTEM_HANDLE_INFORMATION shHandle; List lstHandles = new List(); for (long lIndex = 0; lIndex < lHandleCount; lIndex++) { shHandle = new Win32Api.SYSTEM_HANDLE_INFORMATION(); if (Is64Bits()) { shHandle = (Win32Api.SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(ipHandle, shHandle.GetType()); ipHandle = new IntPtr(ipHandle.ToInt64() + Marshal.SizeOf(shHandle) + 8); } else { ipHandle = new IntPtr(ipHandle.ToInt64() + Marshal.SizeOf(shHandle)); shHandle = (Win32Api.SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(ipHandle, shHandle.GetType()); } if (shHandle.ProcessID != process.Id) continue; lstHandles.Add(shHandle); } return lstHandles; } static bool Is64Bits() { return Marshal.SizeOf(typeof(IntPtr)) == 8 ? true : false; } } }
Note, that I only tested this code on x64 Windows 7 with both x86 and x64 compilation option. I compiled it with VS2010 for .NET 4. This code is less than readable and I can’t guaranty that it will work on all relevant platforms and architectures. However it works here ™ and is useful for this esoteric task.
user314104Update: I guess that you can find the reasoning on the oldnewthing. It was probably added to restore some functionality (like drag and drop) that was removed from Windows Vista due to security reasons.
Before Update: conhost seems to launch on any cmd.exe opening. It’s probably some new, undocumented thing on windows 7.
BreakthroughTo be blatant, I don’t know anything about Java, so I can’t help you with #1. I can help with #2, though.
To track it with .NET, you can use System.Diagnostics.
First, you have to get each of the processes by the name “conhost.exe”, launch Java, then get all the processes again, and compare.
To get the specific instances, use the process ID:
foreach (Process singleProcess in Process.GetProcessesByName("conhost")) { //Store the following in some kind of array somePidArray[yourindex] = singleProcess.Id; }
Then when you want to kill the processes, run the exact same loop, and if the process ID was not stored in the initial loop, then call singleProcess.Kill(); on it. Then you will have kept all the initial conhost.exe processes alive, and only kill the ones created between the time you launch Java in your program and the time your Java process exits.
Igal SerbanIt is a process that hosts the console window. It was introduced in Windows 7 (iirc), in older versions the functionality was executed in the context of the csrss.exe process.
The How-To GeekI just wrote up an article attempting to explain the purpose of the process. It’s geared towards regular people, but there’s lots of screenshots to illustrate.
What is conhost.exe and Why Is It Running?
The bottom line is that conhost.exe sits between the CSRSS process and cmd.exe, so you can use drag & drop again.
R. L. WatkinsWhen one launches a process using ‘Process.Start()’ one has the option of creating the process directly, or of launching ‘cmd.exe’ and letting ‘cmd.exe’ handle the details. The ‘UseShellExecute’ flag controls this. If you elect to leave the details to ‘cmd.exe’, which is common in situations where you want to invoke a file and let the shell run the appropriate program to handle it, e.g. by “running” a ‘.txt’ file, then on Win7 this will actually run ‘cmd’, which itself runs ‘conhost’. If, on the other hand, you don’t use ‘ShellExecute’ then ‘Start()’ won’t run ‘cmd’ and you won’t indirectly launch ‘conhost’.
ericksonThis raises a related question: do you want a console window for the Java application spawned by the .NET app? If not, you can execute the
javaw
command instead ofjava
. I haven’t experimented with it on Vista, but it may eliminate theconhost.exe
process.
Roland PihlakasBased on zespri‘s answer I wrote updated methods. This code is able to handle process id-s that are longer than 16-bit. Also one logic bug was fixed and some memory and handle leaks. Added some failsafety. I added a method for case when conhost.exe has multiple associated processes. This can happen when there is a console program running and has cmd.exe as its parent process, but also some other cases, where the associated processes are not even in child-parent relationship.
Thanks a lot for zespri for the original code, there is lot to learn from it!
More explanation for the method updates:
For WinXP+ it is better to use SYSTEM_EXTENDED_HANDLE_INFORMATION since SYSTEM_HANDLE_INFORMATION returns only 16-bit long process id-s. If system is heavily loaded with handles then process id-s tend to start having values above 65k, for example 8 decimal digits. The system call that the above code uses would simply mask off the high bits of process id-s. You can find SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX and its usage in Process Hacker’s source code.void Main() { //System.Diagnostics.Process.EnterDebugMode(); //TODO: is this necessary? int? ConsoleHost_PId = NativeMethods.GetConhostIdByProcessId(14412376); ConsoleHost_PId.Dump(); int pid = 4484; int? apid = NativeMethods.GetFirstConhostAssociatedProcessId(pid); apid.Dump(); var apids = NativeMethods.GetConhostAssociatedProcessIds(pid); apids.Dump(); } public static class NativeMethods { [DllImport("kernel32.dll")] public static extern IntPtr GetCurrentProcess(); [DllImport("kernel32.dll", SetLastError = true)] public static extern bool CloseHandle(IntPtr hObject); [DllImportAttribute("kernel32.dll", SetLastError = true)] public static extern uint GetProcessId([In]IntPtr process); [DllImport("ntdll.dll")] public static extern uint NtQueryObject(IntPtr objectHandle, int objectInformationClass, IntPtr objectInformation, int objectInformationLength, ref int returnLength); [DllImport("ntdll.dll")] public static extern uint NtQuerySystemInformation(int systemInformationClass, IntPtr systemInformation, int systemInformationLength, ref int returnLength); [DllImport("kernel32.dll")] public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwProcessId); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool DuplicateHandle(IntPtr hSourceProcessHandle, IntPtr hSourceHandle, IntPtr hTargetProcessHandle, out IntPtr lpTargetHandle, uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwOptions); public enum ObjectInformationClass { ObjectBasicInformation = 0, ObjectNameInformation = 1, ObjectTypeInformation = 2, ObjectAllTypesInformation = 3, ObjectHandleInformation = 4 } [Flags] public enum ProcessAccessFlags : uint { All = 0x001F0FFF, Terminate = 0x00000001, CreateThread = 0x00000002, VmOperation = 0x00000008, VmRead = 0x00000010, VmWrite = 0x00000020, DupHandle = 0x00000040, SetInformation = 0x00000200, QueryInformation = 0x00000400, Synchronize = 0x00100000 } [StructLayout(LayoutKind.Sequential)] public struct OBJECT_BASIC_INFORMATION { public int Attributes; public int GrantedAccess; public int HandleCount; public int PointerCount; public int PagedPoolUsage; public int NonPagedPoolUsage; public int Reserved1; public int Reserved2; public int Reserved3; public int NameInformationLength; public int TypeInformationLength; public int SecurityDescriptorLength; public System.Runtime.InteropServices.ComTypes.FILETIME CreateTime; } [StructLayout(LayoutKind.Sequential)] public struct OBJECT_TYPE_INFORMATION { public UNICODE_STRING Name; public int ObjectCount; public int HandleCount; public int Reserved1; public int Reserved2; public int Reserved3; public int Reserved4; public int PeakObjectCount; public int PeakHandleCount; public int Reserved5; public int Reserved6; public int Reserved7; public int Reserved8; public int InvalidAttributes; public GENERIC_MAPPING GenericMapping; public int ValidAccess; public byte Unknown; public byte MaintainHandleDatabase; public int PoolType; public int PagedPoolUsage; public int NonPagedPoolUsage; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct UNICODE_STRING { public ushort Length; public ushort MaximumLength; public IntPtr Buffer; } [StructLayout(LayoutKind.Sequential)] public struct GENERIC_MAPPING { public int GenericRead; public int GenericWrite; public int GenericExecute; public int GenericAll; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct SYSTEM_HANDLE_INFORMATION { public ushort UniqueProcessId; public ushort CreatorBackTraceIndex; public byte ObjectTypeIndex; public byte HandleAttributes; // 0x01 = PROTECT_FROM_CLOSE, 0x02 = INHERIT public ushort HandleValue; public UIntPtr Object; public uint GrantedAccess; } //adapted from ProcessExplorer ntexapi.h [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct SYSTEM_HANDLE_INFORMATION_EX { public UIntPtr Object; public UIntPtr UniqueProcessId; //changed ulong to IntPtr public UIntPtr HandleValue; //changed ulong to IntPtr public uint GrantedAccess; public ushort CreatorBackTraceIndex; public ushort ObjectTypeIndex; public uint HandleAttributes; public uint Reserved; } public const uint STATUS_INFO_LENGTH_MISMATCH = 0xC0000004; public const int DUPLICATE_SAME_ACCESS = 0x2; // ############################################################################ /// /// Some console host processes have multiple associated processes! /// public static List GetConhostAssociatedProcessIds(int pid) { List result = new List(); IntPtr currentProcess = GetCurrentProcess(); IntPtr processHandle = OpenProcess(ProcessAccessFlags.DupHandle, false, pid); try { List lstHandles = GetHandles(pid); foreach (SYSTEM_HANDLE_INFORMATION_EX handleInformation in lstHandles) { int? id = GetFileDetails(processHandle, handleInformation, currentProcess); if (id.HasValue) result.Add(id.Value); } return result; } finally { CloseHandle(processHandle); } } public static int? GetFirstConhostAssociatedProcessId(int pid) { IntPtr currentProcess = GetCurrentProcess(); IntPtr processHandle = OpenProcess(ProcessAccessFlags.DupHandle, false, pid); try { List lstHandles = GetHandles(pid); foreach (SYSTEM_HANDLE_INFORMATION_EX handleInformation in lstHandles) { int? id = GetFileDetails(processHandle, handleInformation, currentProcess); if (id.HasValue) return id; } return null; } finally { CloseHandle(processHandle); } } public static int? GetConhostIdByProcessId(int processId) { IntPtr currentProcess = GetCurrentProcess(); var processes = Process.GetProcessesByName("conhost"); try { foreach (Process process in processes) //TODO: check that this process is really system's console host { IntPtr processHandle = OpenProcess(ProcessAccessFlags.DupHandle, false, process.Id); try { List lstHandles = GetHandles(process.Id); foreach (SYSTEM_HANDLE_INFORMATION_EX handleInformation in lstHandles) { int? id = GetFileDetails(processHandle, handleInformation, currentProcess); if (id == processId) { return process.Id; } } } finally { CloseHandle(processHandle); } } //foreach (Process process in Process.GetProcessesByName("conhost")) return null; } finally { foreach (Process process in processes) process.Dispose(); } } //public static int? GetConhostIdByProcessId(int processId) //TODO see this for possible hang under XP 32-bit: //http://forum.sysinternals.com/handle-name-help-ntqueryobject_topic14435.html //and http://stackoverflow.com/questions/16127948/hang-on-ntquerysysteminformation-in-winxpx32-but-works-fine-in-win7x64 private static int? GetFileDetails(IntPtr processHandle, SYSTEM_HANDLE_INFORMATION_EX systemHandleInformation, IntPtr currentProcess) { IntPtr ipHandle; OBJECT_BASIC_INFORMATION objBasic = new OBJECT_BASIC_INFORMATION(); OBJECT_TYPE_INFORMATION objObjectType = new OBJECT_TYPE_INFORMATION(); int nLength = 0; if (Is64Bits()) { if (!DuplicateHandle(processHandle, new IntPtr(unchecked((long)systemHandleInformation.HandleValue)), currentProcess, out ipHandle, 0, false, DUPLICATE_SAME_ACCESS)) { return null; } } else { //failsafety if ((systemHandleInformation.HandleValue.ToUInt64() >> 32) != 0) return null; if (!DuplicateHandle(processHandle, new IntPtr(unchecked((int)systemHandleInformation.HandleValue)), currentProcess, out ipHandle, 0, false, DUPLICATE_SAME_ACCESS)) { return null; } } try { IntPtr ipBasic = Marshal.AllocHGlobal(Marshal.SizeOf(objBasic)); try { NtQueryObject(ipHandle, (int)ObjectInformationClass.ObjectBasicInformation, ipBasic, Marshal.SizeOf(objBasic), ref nLength); objBasic = (OBJECT_BASIC_INFORMATION)Marshal.PtrToStructure(ipBasic, objBasic.GetType()); } finally { Marshal.FreeHGlobal(ipBasic); } IntPtr ipObjectType = Marshal.AllocHGlobal(objBasic.TypeInformationLength); try { nLength = objBasic.TypeInformationLength; while (NtQueryObject(ipHandle, (int)ObjectInformationClass.ObjectTypeInformation, ipObjectType, nLength, ref nLength) == STATUS_INFO_LENGTH_MISMATCH) { Marshal.FreeHGlobal(ipObjectType); ipObjectType = IntPtr.Zero; //zero the pointer before new alloc for case the alloc fails ipObjectType = Marshal.AllocHGlobal(nLength); } objObjectType = (OBJECT_TYPE_INFORMATION)Marshal.PtrToStructure(ipObjectType, objObjectType.GetType()); IntPtr ipTemp = Is64Bits() ? new IntPtr(Convert.ToInt64(objObjectType.Name.Buffer.ToString(), 10) >> 32) : objObjectType.Name.Buffer; string strObjectTypeName = Marshal.PtrToStringUni(ipTemp, objObjectType.Name.Length >> 1); if (strObjectTypeName != "Process") return null; } finally { Marshal.FreeHGlobal(ipObjectType); } return (int)GetProcessId(ipHandle); } finally { CloseHandle(ipHandle); } } //private static int? GetFileDetails(IntPtr processHandle, SYSTEM_HANDLE_INFORMATION systemHandleInformation, IntPtr currentProcess) const int CNST_SYSTEM_HANDLE_INFORMATION = 16; const int CNST_SYSTEM_EXTENDED_HANDLE_INFORMATION = 64; //from ProcessHacker ntexapi.h //http://hintdesk.com/c-get-all-handles-of-a-given-process-in-64-bits/ private static List GetHandles(int pid) { List lstHandles = new List(); int nHandleInfoSize = 0x10000; IntPtr ipHandlePointer = Marshal.AllocHGlobal(nHandleInfoSize); int nLength = 0; IntPtr ipHandle; if (IsWinXP) //from ProcessHacker. This works under Win XP+ { try { //the structure array may get larger any number of times during our query while ( ( NtQuerySystemInformation(CNST_SYSTEM_EXTENDED_HANDLE_INFORMATION, ipHandlePointer, nHandleInfoSize, ref nLength) ) == STATUS_INFO_LENGTH_MISMATCH ) { //TODO: stop loop if buffer size gets large nHandleInfoSize = nLength; Marshal.FreeHGlobal(ipHandlePointer); ipHandlePointer = IntPtr.Zero; //zero the pointer before new alloc for case the alloc fails ipHandlePointer = Marshal.AllocHGlobal(nLength); } long lHandleCount; if (Is64Bits()) { lHandleCount = Marshal.ReadInt64(ipHandlePointer); ipHandle = new IntPtr(ipHandlePointer.ToInt64() + 16); } else { lHandleCount = Marshal.ReadInt32(ipHandlePointer); ipHandle = new IntPtr(ipHandlePointer.ToInt32() + 8); //changed to 8, tested OK } SYSTEM_HANDLE_INFORMATION_EX shHandle_ex; for (long lIndex = 0; lIndex < lHandleCount; lIndex++) { shHandle_ex = new SYSTEM_HANDLE_INFORMATION_EX(); if (Is64Bits()) { shHandle_ex = (SYSTEM_HANDLE_INFORMATION_EX)Marshal.PtrToStructure(ipHandle, shHandle_ex.GetType()); ipHandle = new IntPtr(ipHandle.ToInt64() + Marshal.SizeOf(shHandle_ex)); } else { shHandle_ex = (SYSTEM_HANDLE_INFORMATION_EX)Marshal.PtrToStructure(ipHandle, shHandle_ex.GetType()); ipHandle = new IntPtr(ipHandle.ToInt32() + Marshal.SizeOf(shHandle_ex)); } //failsafety if (shHandle_ex.UniqueProcessId.ToUInt64() > (ulong)int.MaxValue) //TODO: start using ulong pids? continue; if ((int)shHandle_ex.UniqueProcessId.ToUInt32() != pid) continue; lstHandles.Add(shHandle_ex); } } finally { Marshal.FreeHGlobal(ipHandlePointer); } return lstHandles; } else //if (IsWinXP) { try { //the structure array may get larger any number of times during our query while ( ( NtQuerySystemInformation(CNST_SYSTEM_HANDLE_INFORMATION, ipHandlePointer, nHandleInfoSize, ref nLength) ) == STATUS_INFO_LENGTH_MISMATCH ) { //TODO: stop loop if buffer size gets large nHandleInfoSize = nLength; Marshal.FreeHGlobal(ipHandlePointer); ipHandlePointer = IntPtr.Zero; //zero the pointer before new alloc for case the alloc fails ipHandlePointer = Marshal.AllocHGlobal(nLength); } long lHandleCount; if (Is64Bits()) { lHandleCount = Marshal.ReadInt64(ipHandlePointer); ipHandle = new IntPtr(ipHandlePointer.ToInt64() + 8); } else { lHandleCount = Marshal.ReadInt32(ipHandlePointer); ipHandle = new IntPtr(ipHandlePointer.ToInt32() + 4); } SYSTEM_HANDLE_INFORMATION shHandle; for (long lIndex = 0; lIndex < lHandleCount; lIndex++) { shHandle = new SYSTEM_HANDLE_INFORMATION(); if (Is64Bits()) { shHandle = (SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(ipHandle, shHandle.GetType()); ipHandle = new IntPtr(ipHandle.ToInt64() + Marshal.SizeOf(shHandle) + 4); } else { shHandle = (SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(ipHandle, shHandle.GetType()); ipHandle = new IntPtr(ipHandle.ToInt32() + Marshal.SizeOf(shHandle)); } if (shHandle.UniqueProcessId != pid) continue; SYSTEM_HANDLE_INFORMATION_EX shHandle_ex = new SYSTEM_HANDLE_INFORMATION_EX(); shHandle_ex.Object = shHandle.Object; shHandle_ex.UniqueProcessId = new UIntPtr(shHandle.UniqueProcessId); shHandle_ex.HandleValue = new UIntPtr(shHandle.HandleValue); shHandle_ex.GrantedAccess = shHandle.GrantedAccess; shHandle_ex.CreatorBackTraceIndex = shHandle.CreatorBackTraceIndex; shHandle_ex.ObjectTypeIndex = shHandle.ObjectTypeIndex; shHandle_ex.HandleAttributes = shHandle.HandleAttributes; lstHandles.Add(shHandle_ex); } } finally { Marshal.FreeHGlobal(ipHandlePointer); } return lstHandles; } //if (IsWinXP) } //private static List GetHandles(int pid) private static bool Is64Bits() { return Marshal.SizeOf(typeof(IntPtr)) == 8 ? true : false; } public static bool IsWinXP { get { return ( false || (Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor >= 1) //WinXP || Environment.OSVersion.Version.Major >= 6 //Vista or 7 ); } } }