【问题标题】:Why is conhost.exe being launched?为什么会启动 conhost.exe?
【发布时间】:2009-08-21 17:18:08
【问题描述】:

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

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

【问题讨论】:

  • 不是 100% 确定我要说的准确度,但从我能读到的内容来看,conhost 实际上是在 Windows 7 中托管命令提示符,因此可以在任何 Process.Start() 上启动 ...i确实想知道为什么在进程被杀死后它会一直存在......以及为什么它会阻止你删除文件夹。就个人而言,如果这确实是您的问题,我建议您进行黑客攻击并终止该过程,您绝对应该在尝试之前尝试所有其他方法(对于拼写错误,我会尽力输入:P)
  • 为什么要跟踪它?

标签: java .net process


【解决方案1】:

在早期版本的 Windows 中,控制台窗口托管在 CSRSS 中,这是一个高度特权、受信任的系统关键进程。在 Win7 上,控制台窗口似乎现在托管在 conhost.exe 中,它的权限较少。这可能是出于安全和可靠性的原因 - 控制台系统中的安全问题不会危及整个盒子,并且控制台代码中的崩溃不会蓝屏系统。

【讨论】:

  • 这里有一些关于它的背景信息:blogs.technet.com/b/askperf/archive/2009/10/05/…
  • 来自 UNIX,真的很难理解他们试图用那个东西做什么。我不明白“托管”对基本标准输入/输出的确切作用。为什么每个进程都需要一个兄弟进程来托管它?听起来效率低下。此外,一旦您最终获得了众多 conhost 进程之一,您如何找到它的存在理由,它“托管”了哪个其他进程?目前有几十个conhosts每吃2.5%的CPU,总共100%的CPU,导致系统处于不可用状态,我不知道是什么原因。
【解决方案2】:

抱歉,删除了这么旧的帖子,但我认为这个问题很有趣,值得回答。

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

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

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

所以这是理论。在实践中如何做到这一点?有一个excellent article 显示了一些执行非常相似的代码。我已经稍微修改了这段代码以适应我们手头的任务。最后你 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 编译选项测试了此代码。我用 .NET 4 的 VS2010 编译它。这段代码可读性差,我不能保证它可以在所有相关平台和架构上工作。然而,它在这里 (tm) 有效,并且对于这项深奥的任务很有用。

【讨论】:

  • 对于 WinXP+,最好使用 SYSTEM_EXTENDED_HANDLE_INFORMATION,因为 SYSTEM_HANDLE_INFORMATION 只返回 16 位长的进程 ID。如果系统的句柄负载很重,那么进程 id-s 的值往往会开始超过 65k,例如 8 个十进制数字。上述代码使用的系统调用将简单地屏蔽进程 id-s 的高位。您可以在 Process Hacker 的源代码中找到 SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX 及其用法。当我有时间时,我将发布我自己的基于您的更新的 C# 代码,其中包含一些逻辑错误,并修复了泄漏。 - 非常感谢您的代码!
  • 请查看我在 27.06.2014 所做的更新。涉及到 64 位下 UNICODE_STRING 结构体的打包和读取,上面的代码是错误的。请参阅stackoverflow.com/a/19871391/193017
【解决方案3】:

更新:你可以找到原因on the oldnewthing。添加它可能是为了恢复出于安全原因从 Windows Vista 中删除的某些功能(如拖放)。

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

【讨论】:

    【解决方案4】:

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

    What is conhost.exe and Why Is It Running?

    最重要的是 conhost.exe 位于 CSRSS 进程和 cmd.exe 之间,因此您可以再次使用拖放操作。

    【讨论】:

      【解决方案5】:

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

      【讨论】:

      • 我的看法正好相反;我使用 UseShellExecute=false 启动,我确实得到了一个主机......
      【解决方案6】:

      坦率地说,我对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.Kill();在上面。然后,您将保持所有初始 conhost.exe 进程处于活动状态,并且只杀死在您在程序中启动 Java 和 Java 进程退出之间创建的那些。

      【讨论】:

      • 不知道哪个conhost.exe是我的,因为我不是直接启动的,所以没办法知道哪个PID是我自己的。
      • 是的。我也讨厌 SO 在 cmets 中至少需要 15 个字符。
      【解决方案7】:

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

      【讨论】:

        【解决方案8】:

        基于zespri's answer,我编写了更新的方法。
        此代码能够处理超过 16 位的进程 ID。
        还修复了一个逻辑错误以及一些内存和句柄泄漏。增加了一些故障安全。
        当 conhost.exe 有多个关联进程时,我添加了一种方法。当有一个控制台程序正在运行并且将 cmd.exe 作为其父进程时,可能会发生这种情况,但在其他一些情况下,关联的进程甚至不处于子父关系中。
        非常感谢 zespri 提供原始代码,从中可以学到很多东西!

        方法更新的更多解释:
        对于 WinXP+,最好使用 SYSTEM_EXTENDED_HANDLE_INFORMATION,因为 SYSTEM_HANDLE_INFORMATION 只返回 16 位长的进程 ID。如果系统的句柄负载很重,那么进程 id-s 的值往往会开始超过 65k,例如 8 个十进制数字。上述代码使用的系统调用将简单地屏蔽进程 id-s 的高位。您可以在 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);
        

        【讨论】:

          【解决方案9】:

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

          【讨论】:

          • 我想要一个控制台窗口,因为我正在从 .Net 端读取它的输出。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-07-03
          • 1970-01-01
          • 1970-01-01
          • 2015-03-11
          相关资源
          最近更新 更多