2009-08-21 39 views
7

私は、.NetからJavaプロセス( "java.exe")を起動しています。 Process.Start()を使用してください。 Javaプロセスに加えて、別のプロセスconhost.exeが何とか起動します。私は、Javaプロセスの出力を.Netプロセスにリダイレクトしています。conhost.exeが起動しているのはなぜですか?

  1. なぜconhost.exeが起動するのですか?
  2. どのように私はそれを.Netから追跡しますか?私はこの特定のインスタンスを追跡したいと思います。私は直接(Java.exeプロセスではなく)直接作成しているわけではないので、PIDを持っていません。
+0

ない100%がactualy窓7でコマンドプロンプトをホストしているそのための任意のProcess.Startで開始します()...私はプロセスが殺された後になぜそれが起きているのだろうと思っています...そしてなぜ地獄はそれがフォルダを削除するのを妨げるでしょうか?もしあなたが本当にあなたの問題であれば、私はハックを作ってプロセスを殺すことを示唆しています。あなたは確かにそれを試す前に他のことを試してみるべきです(タイプミスのために、私のベストをタイプする:P) –

+0

それを追跡するには? –

答えて

6

以前のバージョンのWindowsでは、コンソールウィンドウは、高度に権限が与えられた信頼できるシステムクリティカルプロセスであるCSRSSでホストされていました。 Win7では、conhost.exeにコンソールウィンドウがホスティングされているように見えますが、conhost.exeの権限は少なくなります。これはおそらくセキュリティ&の信頼性上の理由から行われました。コンソールシステムのセキュリティ上の問題はボックス全体を危険にさらすことはなく、コンソールコードのクラッシュはシステムをブルースクリーンしません。

+0

これについての背景情報です:http://blogs.technet.com/b/askperf/archive/2009/10/05/windows-7-windows-server- 2008-r2-console-host.aspx –

1

私はJavaについて何も知らないので、#1でお手伝いできません。私は#2で助けることができる。

.NETで追跡するには、System.Diagnosticsを使用します。

まず、それぞれのプロセスを「conhost.exe」という名前で取得し、Javaを起動してからすべてのプロセスを再度取得して比較する必要があります。お好きな時に、プロセスを殺すためにその後

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

まったく同じループを実行し、プロセスIDは、初期に保存されていなかった場合:

は、特定のインスタンスを取得するには、プロセスIDを使用しますループした後、singleProcess.Kill()を呼び出します。その上に。その後、最初のすべてのconhost.exeプロセスを有効にしておき、プログラムでJavaを起動してからJavaプロセスが終了するまでの間に作成されたプロセスのみを強制終了します。

+0

私はconhost.exeが私のものであるかどうかわかりません。私は直接起動していないので、どのPIDが自分のものであるのかわかりません。 – ripper234

+0

Windows 7をお使いですか? – Breakthrough

+2

はい。私はまた、コメントに少なくとも15文字が必要だと嫌いです。 – ripper234

3

更新: I 推測あなたは推論on the oldnewthingを見つけることができます。セキュリティ上の理由により、Windows Vistaから削除された機能(ドラッグアンドドロップなど)を復元するために追加された可能性があります。

更新前: conhostは任意のcmd.exeを開くことで起動するようです。これはおそらく、Windows 7の文書化されていない新しいものです。

1

これは、コンソールウィンドウをホストするプロセスです。 Windows 7(iirc)に導入されました。旧バージョンでは、この機能はcsrss.exeプロセスのコンテキストで実行されていました。

+0

申し訳ありません。間違ってあなたの投稿を集めました... –

0

これは関連する質問を提起します。.NETアプリケーションによって生成されたJavaアプリケーション用のコンソールウィンドウが必要ですか?そうでない場合はjavaの代わりにjavawコマンドを実行できます。私はVista上でそれを実験していませんが、conhost.exeプロセスを排除する可能性があります。

+0

.Net側から出力を読み込んでいるのでコンソールウィンドウが必要です。 – ripper234

1

私はちょうどプロセスの目的を説明しようとしている記事を書きました。通常の方に向けられていますが、説明するためのスクリーンショットがたくさんあります。

What is conhost.exe and Why Is It Running?

一番下の行は、あなたが再びドラッグ&ドロップ&を使用できるようにconhost.exeは、CSRSSプロセスとcmd.exeの間に位置するということです。

alt text

6

申し訳ありませんが、そのような古いスレッドをnecroingために、私は質問が面白いと答え価値があると思いました。

なぜconhost.exeが起動するのですか? 他の記事で説明したように、これはコンソールアプリケーションをホストするデフォルトの方法です。詳細はこちらの別の回答にリンクされている記事をご覧ください:What is conhost.exe and Why Is It Running?

どうすれば.Netから追跡できますか?私はこの特定のインスタンスを追跡したいと思います。私は直接(Java.exeプロセスではなく)直接作成しているわけではないので、PIDを持っていません。

他の人が指摘したように、コーンホストプロセスを「追跡」する理由はほとんどありません。これを言って、java.exeプロセスIDからconhostプロセスIDを取得する方法があります。システム内のすべてのconhostプロセスが持つすべてのプロセスハンドルを列挙するだけです。これらのハンドルの1つがjawa.exeと同じIdを持つプロセスを指している場合、これはconhost.exeハンドルになります後に。 Process 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; 
     } 
    } 
} 

注、私は両方のx86およびx64コンパイルオプションでのx64のWindows 7上でこのコードをテストしていること。私はVS2010 for .NET 4を使ってそれをコンパイルしました。このコードは読みにくく、すべての関連するプラットフォームとアーキテクチャで動作することは保証できません。しかし、それはここ(tm)で動作し、この難解な作業に役立ちます。

+0

WinXP +の場合、SYSTEM_HANDLE_INFORMATIONは16ビット長のプロセスIDのみを返すため、SYSTEM_EXTENDED_HANDLE_INFORMATIONを使用する方が適しています。システムにハンドルが多量にロードされている場合、プロセスid-sは65kを超える値、たとえば8進数の8桁を持つ傾向があります。上記のコードが使用するシステムコールは、単にプロセスid-sの上位ビットをマスクします。プロセスハッカーのソースコードでSYSTEM_HANDLE_TABLE_ENTRY_INFO_EXとその使用法を見つけることができます。私が時間を取ると、Yoursに基づいた独自の更新されたC#コードを投稿し、いくつかのロジックバグとリークを修正します。 - あなたのコードをありがとう! –

+0

27.06.2014の更新を確認してください。これは64ビットでUNICODE_STRING構造体のパッキングと読み込みに関係していますが、これは上記のコードでは間違っています。 http://stackoverflow.com/a/19871391/193017をご覧ください。 –

2

'Process.Start()'を使用してプロセスを起動する場合、プロセスを直接作成するか、「cmd.exe」を起動して「cmd.exe」に詳細を処理させるオプションがあります。 'UseShellExecute'フラグはこれを制御します。あなたがファイルを呼び出して、シェルがそれを扱うための適切なプログラムを実行させる状況では、一般的な 'cmd.exe'に詳細を残すことを選択した場合。 Win7では、実際に 'conhost'を実行する 'cmd'が実行されます。一方、 'ShellExecute'を使用しない場合、 'Start()'は 'cmd'を実行せず、間接的に 'conhost'を起動しません。

1

zespri's answerに基づいて、更新されたメソッドを書きました。
このコードは、16ビットよりも長いプロセスIDを処理できます。
また、1つのロジックバグが修正され、メモリとリークが処理されました。フェイルセーフを追加しました。
conhost.exeに複数の関連プロセスがある場合のためのメソッドを追加しました。これは、実行中のコンソールプログラムがあり、cmdを持っている場合に発生します。exeを親プロセスとしてだけでなく、関連するプロセスが子 - 親関係にさえもない他のいくつかのケースでも使用できます。
ありがとうございましたzespri元のコードは、そこから学ぶことがたくさんあります!方法更新の

詳細説明:
WinXPのためにSYSTEM_HANDLE_INFORMATIONのみ16ビット長のプロセスID-Sを返すためSYSTEM_EXTENDED_HANDLE_INFORMATIONを使用する方がよいです+。システムにハンドルが多量にロードされている場合、プロセスid-sは65kを超える値、たとえば8進数の8桁を持つ傾向があります。上記のコードが使用するシステムコールは、単にプロセスid-sの上位ビットをマスクします。プロセスハッカーのソースコードで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 
      ); 
     } 
    } 

} 


UPDATE:

私は2014年6月27日に64ビットコードのための重要なバグ修正を追加しました。
UNICODE_STRING構造体のパッキングが間違っていて、コードがそれを幾分かの方法で補正しようとしました。それはWin7では明示されませんでしたが、Win8の下でうまくクラッシュしました。
Pack = 1の他の構造体のパッキングも正しくありませんでしたが、誤って計算されたレイアウトは変更されませんでした。
重要な変更箇所は以下の通りであった。言うことを約イム何の正確さの試合が、私はconhostを読むことができるものと確認

[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); 
関連する問題