2009-08-21 16 views
7

Estoy iniciando un proceso Java ("java.exe") desde .Net. usando Process.Start(). Además del proceso de Java, otro proceso llamado conhost.exe se inicia de alguna manera. Estoy redirigiendo la salida del proceso de Java al proceso .Net.¿Por qué se lanza conhost.exe?

  1. ¿Por qué se lanza conhost.exe?
  2. ¿Cómo puedo rastrear desde .Net? Quiero rastrear esta instancia específica, y como no la estoy creando directamente (sino el proceso Java.exe), no tengo su PID.
+0

100% seguro de combate de la exactitud de lo que estoy a punto de decir, pero por lo que pude leer conhost acoge podía comprender el símbolo del sistema en Windows siete ello comenzar en cualquier Process.Start() ... me pregunto por qué se mantiene activa después de que se mata el proceso ... y por qué diablos te impediría eliminar la carpeta. Personalmente, si es realmente su problema, le sugiero que haga el truco y mate el proceso. Definitivamente debe probar todo lo que pueda antes de intentarlo (sry para los errores tipográficos, im frenche haciendo lo mejor para escribir: P) –

+0

¿Por qué querría? para rastrearlo? –

Respuesta

6

En las versiones anteriores de Windows, las ventanas de la consola se alojaban en CSRSS, que es un proceso altamente privilegiado, de confianza y crítico para el sistema. En Win7, parece que las ventanas de la consola ahora están alojadas en conhost.exe, que tiene menos derechos. Probablemente esto se haya realizado por razones de seguridad &: un problema de seguridad en el sistema de la consola no comprometerá todo el cuadro y un bloqueo en el código de la consola no mostrará en azul el sistema.

+0

Aquí hay información general al respecto: http://blogs.technet.com/b/askperf/archive/2009/10/05/windows-7-windows-server- 2008-r2-console-host.aspx –

1

Para ser descarado, no sé nada sobre Java, así que no puedo ayudarte con el # 1. Sin embargo, puedo ayudarte con el # 2.

Para rastrearlo con .NET, puede usar System.Diagnostics.

En primer lugar, debe obtener cada uno de los procesos con el nombre "conhost.exe", iniciar Java, luego obtener todos los procesos de nuevo y comparar.

Para obtener los casos específicos, utilice el ID de proceso:

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

A continuación, cuando se quiere matar a los procesos, ejecute el mismo bucle exacta, y si el ID de proceso no se almacena en la primera loop, luego llame a singleProcess.Kill(); en eso. Luego, mantendrá vivos todos los procesos iniciales conhost.exe y solo eliminará los creados entre el momento en que ejecute Java en su programa y el momento en que finalice su proceso Java.

+0

No sé qué conhost.exe es mío, porque no lo estoy lanzando directamente, así que no tengo forma de entender qué PID es mío. – ripper234

+0

¿Estás usando Windows 7? – Breakthrough

+2

Sí. También odio que SO requiera al menos 15 caracteres en los comentarios. – ripper234

3

Actualización: Mesupongo que se puede encontrar el razonamiento on the oldnewthing. Probablemente se agregó para restaurar algunas funciones (como arrastrar y soltar) que se eliminaron de Windows Vista por razones de seguridad.

Antes de la actualización: conhost parece iniciarse en cualquier apertura de cmd.exe. Probablemente sea algo nuevo e indocumentado en Windows 7.

1

Es un proceso que aloja la ventana de la consola. Se introdujo en Windows 7 (iirc), en versiones anteriores, la funcionalidad se ejecutó en el contexto del proceso csrss.exe.

+0

Lo siento. He agrupado tu publicación por error ... –

0

Esto plantea una pregunta relacionada: ¿desea una ventana de consola para la aplicación Java generada por la aplicación .NET? De lo contrario, puede ejecutar el comando javaw en lugar de java. No he experimentado con Vista, pero puede eliminar el proceso conhost.exe.

+0

Quiero una ventana de consola porque estoy leyendo su salida desde el lado .Net. – ripper234

1

Acabo de escribir un artículo que intenta explicar el propósito del proceso. Está dirigido a personas normales, pero hay muchas capturas de pantalla para ilustrar.

What is conhost.exe and Why Is It Running?

La conclusión es que conhost.exe se encuentra entre el proceso de CSRSS y cmd.exe, por lo que puede utilizar arrastrar & gota de nuevo.

alt text

6

Lo siento, para necroing un hilo tan viejo, pero pensé que la pregunta es interesante y vale la pena una respuesta.

¿Por qué se acaba de ejecutar conhost.exe? Como se explicó en otras publicaciones, esta es ahora una forma predeterminada de alojar aplicaciones de consola. Se pueden encontrar más detalles en el artículo vinculado en otra respuesta aquí: What is conhost.exe and Why Is It Running?

¿Cómo puedo rastrear desde .Net? Quiero rastrear esta instancia específica, y como no la estoy creando directamente (sino el proceso Java.exe), no tengo su PID.

Como ya se ha mencionado, debería haber pocas razones para "rastrear" el proceso conhost. Habiendo dicho eso, hay una forma de obtener el id del proceso conhost desde su Id del proceso java.exe. Todo lo que tiene que hacer es enumerar todos los identificadores de proceso que tiene cada proceso conhost en el sistema, y ​​si uno de estos identificadores apunta a un proceso con el mismo Id que su jawa.exe, este será el manejador conhost.exe que usted está después. Cubrirlo con ID de proceso y obtendrá el PID para conhost.exe

Así que esta es la teoría. ¿Cómo lograr esto en la práctica? Hay un excellent article que muestra un código que está haciendo algo muy similar. He modificado este código un poco para adaptarlo a nuestra tarea. Al final, usted Utility.GetConhostIdByProcessId función estática y le pasa el PID de su java.exe, y le devolverá el PID de conhost.exe correspondiente. Puede encontrar una llamada de prueba a este método en la función Principal en el siguiente ejemplo.

Y ahora el código:

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

Tenga en cuenta, que yo sólo probé este código en Windows 7 x64 tanto con opción de compilación x86 y x64. Lo compilé con VS2010 para .NET 4. Este código es menos legible y no puedo garantizar que funcione en todas las plataformas y arquitecturas relevantes. Sin embargo, funciona aquí (tm) y es útil para esta tarea esotérica.

+0

Para WinXP +, es mejor utilizar SYSTEM_EXTENDED_HANDLE_INFORMATION, ya que SYSTEM_HANDLE_INFORMATION solo devuelve id-s de proceso largos de 16 bits. Si el sistema está muy cargado con identificadores, los id-s de proceso tienden a comenzar a tener valores superiores a 65 k, por ejemplo, 8 dígitos decimales. La llamada al sistema que utiliza el código anterior simplemente enmascararía los bits altos de los id-s del proceso. Puede encontrar SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX y su uso en el código fuente de Process Hacker. Cuando tenga tiempo, publicaré mi propio código actualizado de C# que se basó en el tuyo, con algunos errores de lógica y fugas corregidas. - Muchas gracias por tu código! –

+0

Por favor revise mi actualización hecha el 27.06.2014. Se trata del empaquetado y la lectura de la estructura UNICODE_STRING en 64 bits, lo que es incorrecto para el código anterior. Por favor, consulte http://stackoverflow.com/a/19871391/193017 –

2

Cuando uno inicia un proceso usando 'Process.Start()' tiene la opción de crear el proceso directamente, o de ejecutar 'cmd.exe' y dejar que 'cmd.exe' maneje los detalles. El indicador 'UseShellExecute' controla esto. Si elige dejar los detalles en 'cmd.exe', que es común en situaciones en las que desea invocar un archivo y deja que el shell ejecute el programa apropiado para manejarlo, p. al "ejecutar" un archivo '.txt', entonces en Win7 esto realmente ejecutará 'cmd', que a su vez ejecuta 'conhost'. Si, por otro lado, no usa 'ShellExecute', 'Start()' no ejecutará 'cmd' y no lanzará indirectamente 'conhost'.

1

Basado en zespri's answer escribí métodos actualizados.
Este código es capaz de manejar identificadores de proceso de más de 16 bits.
También se corrigió un error de lógica y algo de fuga de memoria y control. Se agregó alguna falla de seguridad.
Agregué un método para el caso cuando conhost.exe tiene múltiples procesos asociados. Esto puede suceder cuando hay un programa de consola ejecutándose y tiene cmd.exe como su proceso padre, pero también en algunos otros casos, donde los procesos asociados ni siquiera están en la relación padre-hijo.
Muchas gracias por zespri por el código original, ¡hay mucho que aprender de él!

Más explicación para los cambios de método:
Para WinXP + es mejor utilizar SYSTEM_EXTENDED_HANDLE_INFORMATION desde SYSTEM_HANDLE_INFORMATION devuelve sólo de 16 bits de largo proceso de id-s. Si el sistema está muy cargado con identificadores, los id-s de proceso tienden a comenzar a tener valores superiores a 65 k, por ejemplo, 8 dígitos decimales. La llamada al sistema que utiliza el código anterior simplemente enmascararía los bits altos de los id-s del proceso. Puede encontrar SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX y su uso en el código fuente de Process Hacker.

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

} 


ACTUALIZACIÓN:

he añadido correcciones importantes para el código de 64 bits en 06/27/2014.
El empaquetado de la estructura UNICODE_STRING era incorrecto y el código intentó compensarlo de alguna manera complicada. Aunque no se manifestó en Win7, se colgó muy bien en Win8.
El embalaje de las otras estructuras con Pack = 1 también era incorrecto, pero accidentalmente no modificó su diseño calculado.
Las piezas cambiadas importantes fueron:

[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); 
Cuestiones relacionadas