System.Diagnostics.Process に関する FAQ


System.Diagnostics.Process クラスについて、よく寄せられる質問とその答えです。

  • DateTime クラスで、コールスタックに予想外の例外が発生するのはなぜですか。
  • Process クラスは、なぜパフォーマンス カウンタに依存するのですか。
  • プロセスの親プロセスの ID は、どのように認識できますか。
  • プロセス名を簡単に取得するには、どのようにすればよいですか。
  • なぜ Process.StartInfo から開始情報を取得できないのですか。
  • 64 ビットへの移行において、Int の最大範囲を超える可能性のある Process のプロパティにどのような影響がありますか。
  • 管理者権限のないアカウントで、Process クラスを使用するにはどのようにすればよいですか。
  • リモート マシン上のプロセス名の取得を試みたときに、"この操作は、リモート マシンではサポートされません" という例外メッセージが表示されるのはなぜですか。

お客様からのアイデア、問題のご指摘、あるいはご要望をお待ちしております。なぜこのような設計になっているのか、問題の最適な解決方法はどれか、なぜコードが想定したとおりに動作しないのかなどの疑問がありましたら、ぜひお寄せください。 また、組み込んでほしい追加のクラス (サポートする必要のあるシナリオの概要があればとても役立ちます)、あるいは既存のクラスのための新しい API など、.Net Framework の今後のリリースへのご提案も、ぜひ BCL チームまでお寄せください。

ご質問はBCL チーム (bclpub@microsoft.com) (英語) まで電子メールでお願いします。

DateTime クラスで、コールスタックに予想外の例外が発生するのはなぜですか。

特定のマシンでは、次のコールスタックで例外が発生する場合があります。

System. InvalidOperationException: リモート マシンからプロセス情報を取得できません。---> System.ArgumentOutOfRangeException: タイマ刻みは、DateTime.MinValue.Ticks と DateTime.MaxValue.Ticks の間である必要があります。 Parameter name: ticks at System.DateTime..ctor(Int64 ticks) at System.DateTime.Subtract(TimeSpan value) at System.Diagnostics.NtProcessManager.GetThreadInfo( PERF_OBJECT_TYPE type, IntPtr instancePtr, PERF_COUNTER_DEFINITION[] counters) at System.Diagnostics.NtProcessManager.GetProcessInfos(PerformanceCounterLib library, Int32 processIndex, Int32 threadIndex, IntPtr dataBlockPtr) at System.Diagnostics.NtProcessManager.GetProcessInfos(PerformanceCounterLib library) --- 内部例外スタック トレースの終了 --- at System.Diagnostics.NtProcessManager.GetProcessInfos(PerformanceCounterLib library) at System.Diagnostics.NtProcessManager.GetProcessInfos(String machineName, Boolean isRemoteMachine) at System.Diagnostics.ProcessManager.GetProcessInfos(String machineName) at System.Diagnostics.Process.GetProcesses(String machineName) at System. Diagnostics.Process.GetProcesses() at Process_Reader.Module1.Main()

これは、何らかのプロセスからのパフォーマンス情報が破損し、その情報を DateTime に変換できないために発生します。あるインスタンスを詳細に調査した結果、この問題は、Adaptec SCSI BIOS の特定の設定が関連していることがわかりました。SCSI BIOS の両方のチェーンで '出荷時の既定設定' にリセットすることで、この問題は解決されます。しかし、すべての場合においてこの方法が有効なわけではなく、特定の環境によってはこの方法で解決されない場合もあります。Visual Studio 2005 (Whidbey) では、プロセスおよびスレッドの時間に関する情報の取得には Win32 API が使用されるため、今後この例外は発生しなくなります。

ページのトップへ

Process クラスは、なぜパフォーマンス カウンタに依存するのですか。

Process クラスは、プロセスに関するパフォーマンス情報を提供します。リモート プロセスに関するパフォーマンス情報を取得するには、リモート マシン上のパフォーマンス情報を照会する必要があります。Everett では、ローカル マシン上のプロセスに関するパフォーマンス情報を取得する場合も、同じコードが使用されます。これが、Process クラスが、パフォーマンス カウンタに依存する理由です。しかし、この手法には次のような問題があります。

  1. Windows Server 2003 のパフォーマンス情報は、管理者権限がなく、Performance Counter Users グループに含まれないアカウントからは使用できません。このため、Process クラスは、このような状況でプロセスのパフォーマンス情報を取得することができません。
  2. マシン上のすべてのプロセスからパフォーマンス データを取得する場合のコストはとても大きくなります。オペレーティング システム (OS) が多くの DLL を読み込むことになり、完了までに数秒がかかる場合もあります。OS がパフォーマンス カウンタのインデックスを検出しようとしているときに、フロッピー ドライブのライトがつくこともあります。
  3. パフォーマンス カウンタのデータが何らかの理由で破損した場合、Process クラスは例外をスローすることができますが、このときに、取得したままの情報の一部を DateTime に変換しようとします。
  4. Process クラスを使用して、プロセスのパフォーマンス カウンタなしで、マシン上のプロセス情報を取得することはできません。パフォーマンス カウンタは Windows で無効にされている場合があります。詳細については、http: //www.microsoft.com/technet/prodtechnol/windows2000serv/reskit/default.mspx?mfr=true を参照してください。

Visual Studio 2005 (次期リリース、コード ネーム Whidbey) では、Process クラスの実装が変更されています。Process クラスは、パフォーマンス カウンタ情報に依存しなくなりました (これは、ローカル プロセスの場合のみです)。

ページのトップへ

プロセスの親プロセスの ID は、どのように認識できますか。

プロセスのパフォーマンス カウンタ情報には、Creating Process ID と呼ばれる情報があります。この情報は、Process クラスでは提供されません (今後は追加される可能性があります)。Creating Process ID は、次のコードで取得できます。

[ C#]
using System.Diagnostics;
using System;

class ProcessInformation {
  public static void Main() {
    PerformanceCounter pc = new PerformanceCounter("Process", "Creating Process Id", " windbg");
    Process p = Process.GetProcessById((int)pc.RawValue);
    if ( p.MainModule.ModuleName.Equals("svchost.exe")) {
      Console.WriteLine("Created by scheduler");
    }
    else {
      Console.WriteLine("Created without schedule.") ;
    }
  }
}

ページのトップへ

プロセス名を簡単に取得するには、どのようにすればよいですか。

Process.ProcessName は、次のような方法でも取得できます。

 

Process.MainModule.ModuleName

ページのトップへ

なぜ Process.StartInfo から開始情報を取得できないのですか。

StartInfo は、プロセスを開始するためのみに使用されるため、プロセスが Process クラスを使用して作成されない場合、StartInfo クラスは空になります。コマンド ライン情報は、次のような方法で取得できます。

  1. 現在のプロセスのコマンド ライン情報を取得するには、Environment.CommandLine を使用します。
  2. System.WMI Win32_Process には、 フィールド CommandLine があります。このクラスの詳細については、MSDN の資料を参照してください。
  3. OS のプロセス構造の設計に依存する技法もいくつかあります。すべてのプラットフォームにおいて機能することは保障されないので、危険性を考慮して使用してく ださい。MSDN マガジンの記事、http: //msdn.microsoft.com/msdnmag/issues/02/06/debug/default.aspx を参照してください。

ページのトップへ

64 ビットへの移行において、Int の最大範囲を超える可能性のある Process のプロパティにどのような影響がありますか。

Process には多数の API があり、これらはメモリ サイズを反映して Int32 を戻します。これらは、完全に正しく機能してきましたが、メモリの量が Int32 の最大値を超えることは、64 ビット マシンでは珍しくありません。このような場合、既存の API は適切ではありません。

互換性の要件があるため、単純に Int32 API を除去し、新しい 64 ビット バージョンを導入することはできません (この API インターフェイスに結合する呼び出しは、これが int を戻すことに基づくので、long が戻された場合には既存の呼び出し元が機能しなくなる可能性があります)。このため、既存の Int32 API は互換性のために残され、64 ビット値を戻す新しいバージョンの API が導入される予定です。

次の API は互換性のために残されます。

  • NonpagedSystemMemorySize
  • PagedMemorySize
  • PagedSystemMemorySize
  • PeakPagedMemorySize
  • PeakVirtualMemorySize
  • PeakWorkingSet
  • PrivateMemorySize
  • VirtualMemorySize
  • WorkingSet

ページのトップへ

管理者権限のないアカウントで、Process クラスを使用するにはどのようにすればよいですか。

Windows Server 2003 では、管理者権限のないアカウントでプロセスのパフォーマンス情報の取得を試みた場合、例外が発生します。これは、そのアカウントを Performance Counter Users グループに追加することで解決できます。

ページのトップへ

リモート マシン上のプロセス名の取得を試みたときに、"この操作は、リモート マシンではサポートされません" という例外メッセージが表示されるのはなぜですか。

リモート マシン上のプロセス名は、そのマシン上のパフォーマンス情報にアクセスできる場合には必ず取得できます。get_ProcessName では、プロセス名が OS によって切り捨てられていない場合には名前を完成させようとする特殊な処理が行われます。プロセス名として、15 文字のモジュール情報を取得することを試みます。この処理は、リモート マシンではサポートされていないため、リモート プロセスに対しては行われるべきではありません。

この問題は、次のように対処できます。

[C#]
try {
  Console.WriteLine(myProcesses[x].ProcessName);
} catch ( NotSupportedException ) {
  Type processType = typeof(Process);
  FieldInfo info = processType.GetField("processInfo", BindingFlags.NonPublic| BindingFlags.IgnoreCase | BindingFlags.Instance);
  Object obj = info.GetValue( myProcesses[x]);
  Type processInfoType = obj.GetType();
  FieldInfo info2 = processInfoType.GetField("processName", BindingFlags.NonPublic| BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public);
  String name = (string)info2.GetValue( obj);
  Console.WriteLine( name );
}

このコードは、ドキュメント化されていないプロセス情報を使用します。この対処方法は、V1.0 および V1.1 で有効ですが、すべての状況において有効であることは保障されません。このバグは、次期リリース (Visual Studio 2005) で修正される予定です。

ページのトップへ