为什么会启动 conhost.exe?

发布于 2024-08-02 18:03:08 字数 373 浏览 2 评论 0原文

我正在从 .Net 启动 Java 进程(“java.exe”)。使用 Process.Start()。除了 Java 进程之外,还会以某种方式启动另一个名为 conhost.exe 的进程。我将 Java 进程的输出重定向到 .Net 进程。

  1. 为什么 conhost.exe 甚至会启动?
  2. 如何从 .Net 跟踪它?我想跟踪这个特定的实例,因为我不是直接创建它(而是 Java.exe 进程),所以我没有它的 PID。

I'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.

  1. Why is conhost.exe even launched?
  2. 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

嗫嚅 2024-08-09 18:03:08

在早期版本的 Windows 中,控制台窗口托管在 CSRSS 中,这是一个具有高度特权、受信任的系统关键进程。在 Win7 上,控制台窗口现在托管在 conhost.exe 中,该程序的权限较少。这样做可能是为了安全和安全。可靠性原因 - 控制台系统中的安全问题不会危及整个盒子,控制台代码崩溃也不会导致系统蓝屏。

In 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.

红墙和绿瓦 2024-08-09 18:03:08

抱歉,破坏了这样一个旧线程,但我认为这个问题很有趣并且值得回答。

为什么会启动 conhost.exe?
正如其他帖子中所解释的,这现在是托管控制台应用程序的默认方式。更多详细信息可以在另一个答案链接的文章中找到:什么是 conhost.exe 以及它为何运行?

如何从 .Net 跟踪它?我想跟踪这个特定的实例,并且由于我不是直接创建它(而是 Java.exe 进程),所以我没有它的 PID。

正如其他人指出的那样,应该没有理由“跟踪”conhost 进程。话虽如此,有一种方法可以从 java.exe 进程 ID 中获取 conhost 进程 ID。您所要做的就是枚举系统中每个 conhost 进程拥有的所有进程句柄,如果这些句柄之一指向与您的 jama.exe 具有相同 Id 的进程,则这将是您所在的 conhost.exe 句柄后。将其隐藏为进程 ID,您将获得 conhost.exe 的 PID

所以这是理论。在实践中如何实现这一目标?有一篇优秀文章显示了一些执行非常相似操作的代码。我对此代码进行了一些修改以适应我们手头的任务。最后,您使用 Utility.GetConhostIdByProcessId 静态函数并将 java.exe 的 PID 传递给它,它将返回相关 conhost.exe 的 PID。对该方法的测试调用可以在下面示例中的 Main 函数。

现在是代码:

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<Win32Api.SYSTEM_HANDLE_INFORMATION> 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<Win32Api.SYSTEM_HANDLE_INFORMATION> 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<Win32Api.SYSTEM_HANDLE_INFORMATION> lstHandles = new List<Win32Api.SYSTEM_HANDLE_INFORMATION>();

            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;
        }
    }
}

请注意,我仅在 x64 Windows 7 上使用 x86 和 x64 编译选项测试了此代码。我用 VS2010 for .NET 4 编译了它。这段代码可读性较差,我不能保证它可以在所有相关平台和体系结构上工作。然而它在这里工作(tm)并且对于这个深奥的任务很有用。

Sorry, 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<Win32Api.SYSTEM_HANDLE_INFORMATION> 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<Win32Api.SYSTEM_HANDLE_INFORMATION> 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<Win32Api.SYSTEM_HANDLE_INFORMATION> lstHandles = new List<Win32Api.SYSTEM_HANDLE_INFORMATION>();

            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 (tm) and is useful for this esoteric task.

很酷不放纵 2024-08-09 18:03:08

更新:你可以找到原因关于旧的新事物。添加它可能是为了恢复由于安全原因从 Windows Vista 中删除的某些功能(例如拖放)。

更新前: conhost 似乎会在任何 cmd.exe 打开时启动。这可能是 Windows 7 上的一些新的、未记录的东西。

Update: 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.

故事↓在人 2024-08-09 18:03:08

我刚刚写了一篇文章试图解释该过程的目的。它面向普通人,但有很多屏幕截图可以说明。

什么是 conhost.exe以及为什么它运行?

底线是 conhost.exe 位于 CSRSS 进程和 cmd.exe 之间,因此您可以使用拖放来运行它。再次下降。

替代文本

I 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.

alt text

注定孤独终老 2024-08-09 18:03:08

当使用“Process.Start()”启动进程时,可以选择直接创建进程,或者启动“cmd.exe”并让“cmd.exe”处理详细信息。 “UseShellExecute”标志对此进行控制。如果您选择将详细信息保留给“cmd.exe”,这在您想要调用文件并让 shell 运行适当的程序来处理它的情况下很常见,例如通过“运行”一个“.txt”文件,那么在 Win7 上,这实际上会运行“cmd”,它本身运行“conhost”。另一方面,如果您不使用“ShellExecute”,则“Start()”将不会运行“cmd”,并且您将不会间接启动“conhost”。

When 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'.

迎风吟唱 2024-08-09 18:03:08

坦白说,我对 Java 一无所知,所以我无法帮助你解决 #1 的问题。不过,我可以帮助解决#2。

要使用 .NET 跟踪它,您可以使用 System.Diagnostics。

首先,您必须通过名称“conhost.exe”获取每个进程,启动 Java,然后再次获取所有进程并进行比较。

要获取特定实例,请使用进程 ID:

foreach (Process singleProcess in Process.GetProcessesByName("conhost"))
{
    //Store the following in some kind of array
    somePidArray[yourindex] = singleProcess.Id;
}

然后,当您想要终止进程时,运行完全相同的循环,如果进程 ID 未存储在初始循环中,则调用 singleProcess。杀();在它上面。然后,您将保持所有初始 conhost.exe 进程处于活动状态,并且仅终止在程序中启动 Java 和 Java 进程退出之间创建的进程。

To 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.

装纯掩盖桑 2024-08-09 18:03:08

它是一个托管控制台窗口的进程。它是在 Windows 7 (iirc) 中引入的,在旧版本中,该功能是在 csrss.exe 进程的上下文中执行的。

It 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.

坦然微笑 2024-08-09 18:03:08

根据 zespri 的回答,我编写了更新的方法。

此代码能够处理长于 16 位的进程 ID。

还修复了一个逻辑错误以及一些内存和句柄泄漏。添加了一些故障安全措施。

我添加了一种方法,用于处理 conhost.exe 有多个关联进程的情况。当控制台程序正在运行并且其父进程为 cmd.exe 时,可能会发生这种情况,但在其他一些情况下,关联的进程甚至不具有子父关系。

非常感谢zespri提供的原始代码,有很多值得学习的地方!

方法更新的更多说明:

对于 WinXP+,最好使用 SYSTEM_EXTENDED_HANDLE_INFORMATION,因为 SYSTEM_HANDLE_INFORMATION 仅返回 16 位长的进程 ID。如果系统的句柄负载很重,那么进程 ID 往往会开始具有高于 65k 的值,例如 8 位十进制数字。上述代码使用的系统调用将简单地屏蔽掉进程 ID 的高位。您可以在 Process Hacker 的源代码中找到 SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX 及其用法。

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)]  //NB! no packing!
   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)]  //NB! no packing!
   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)]  //NB! no packing!
   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;

   // ############################################################################

   /// <summary>
   /// Some console host processes have multiple associated processes!
   /// </summary>
   public static List<int> GetConhostAssociatedProcessIds(int pid)  
   {
       List<int> result = new List<int>();

       IntPtr currentProcess = GetCurrentProcess();

       IntPtr processHandle = OpenProcess(ProcessAccessFlags.DupHandle, false, pid);

       try
       {
           List<SYSTEM_HANDLE_INFORMATION_EX> 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<SYSTEM_HANDLE_INFORMATION_EX> 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<SYSTEM_HANDLE_INFORMATION_EX> 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 https://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);
               string strObjectTypeName = Marshal.PtrToStringUni(objObjectType.Name.Buffer, 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<SYSTEM_HANDLE_INFORMATION_EX> GetHandles(int pid)
   {
       List<SYSTEM_HANDLE_INFORMATION_EX> lstHandles = new List<SYSTEM_HANDLE_INFORMATION_EX>();


       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<SYSTEM_HANDLE_INFORMATION> 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
           );
       }
   }

}

更新:

我于 2014 年 6 月 27 日添加了针对 64 位代码的重要错误修复。

UNICODE_STRING 结构的打包是错误的,代码试图以某种棘手的方式弥补这一点。虽然在Win7中没有表现出来,但在Win8下崩溃得很好。

其他结构体的 Pack=1 打包也不正确,但意外地没有改变它们的计算布局。

重要的更改部分是:

[StructLayout(LayoutKind.Sequential)] //, Pack = 1)]  //NB! no packing!
public struct UNICODE_STRING

//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);
string strObjectTypeName = Marshal.PtrToStringUni(objObjectType.Name.Buffer, objObjectType.Name.Length >> 1);

Based 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)]  //NB! no packing!
   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)]  //NB! no packing!
   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)]  //NB! no packing!
   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;

   // ############################################################################

   /// <summary>
   /// Some console host processes have multiple associated processes!
   /// </summary>
   public static List<int> GetConhostAssociatedProcessIds(int pid)  
   {
       List<int> result = new List<int>();

       IntPtr currentProcess = GetCurrentProcess();

       IntPtr processHandle = OpenProcess(ProcessAccessFlags.DupHandle, false, pid);

       try
       {
           List<SYSTEM_HANDLE_INFORMATION_EX> 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<SYSTEM_HANDLE_INFORMATION_EX> 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<SYSTEM_HANDLE_INFORMATION_EX> 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 https://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);
               string strObjectTypeName = Marshal.PtrToStringUni(objObjectType.Name.Buffer, 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<SYSTEM_HANDLE_INFORMATION_EX> GetHandles(int pid)
   {
       List<SYSTEM_HANDLE_INFORMATION_EX> lstHandles = new List<SYSTEM_HANDLE_INFORMATION_EX>();


       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<SYSTEM_HANDLE_INFORMATION> 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
           );
       }
   }

}

UPDATE:

I added important bugfixes for 64-bit code on 27.06.2014.

The packing of the UNICODE_STRING struct was wrong and the code tried to compensate for that in some tricky manner. Although it did not manifest in Win7, it crashed nicely under Win8.

The other structs' packing with Pack=1 was incorrect too, but accidentally did not change their computed layout.

The important changed parts were:

[StructLayout(LayoutKind.Sequential)] //, Pack = 1)]  //NB! no packing!
public struct UNICODE_STRING

//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);
string strObjectTypeName = Marshal.PtrToStringUni(objObjectType.Name.Buffer, objObjectType.Name.Length >> 1);
兮颜 2024-08-09 18:03:08

这就提出了一个相关的问题:您想要 .NET 应用程序生成的 Java 应用程序的控制台窗口吗?如果没有,您可以执行javaw命令而不是java。我还没有在 Vista 上进行过实验,但它可能会消除 conhost.exe 进程。

This 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 of java. I haven't experimented with it on Vista, but it may eliminate the conhost.exe process.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文