System.Diagnostics.Process
への参照を取得したときに、プロセスが現在実行されているかどうかを確認するにはどうすればよいですか?
これは名前でそれを行う方法です:
Process[] pname = Process.GetProcessesByName("notepad");
if (pname.Length == 0)
MessageBox.Show("nothing");
else
MessageBox.Show("run");
すべてのプロセスをループして、後で操作するためのIDを取得できます。
Process[] processlist = Process.GetProcesses();
foreach(Process theprocess in processlist){
Console.WriteLine("Process: {0} ID: {1}", theprocess.ProcessName, theprocess.Id);
}
これは、リフレクターを使用した後に見つけた最も簡単な方法です。そのための拡張メソッドを作成しました:
public static class ProcessExtensions
{
public static bool IsRunning(this Process process)
{
if (process == null)
throw new ArgumentNullException("process");
try
{
Process.GetProcessById(process.Id);
}
catch (ArgumentException)
{
return false;
}
return true;
}
}
Process.GetProcessById(processId)
メソッドは、ProcessManager.IsProcessRunning(processId)
メソッドを呼び出し、プロセスが存在しない場合にArgumentException
をスローします。何らかの理由でProcessManager
クラスは内部です...
同期ソリューション:
void DisplayProcessStatus(Process process)
{
process.Refresh(); // Important
if(process.HasExited)
{
Console.WriteLine("Exited.");
}
else
{
Console.WriteLine("Running.");
}
}
非同期ソリューション:
void RegisterProcessExit(Process process)
{
// NOTE there will be a race condition with the caller here
// how to fix it is left as an exercise
process.Exited += process_Exited;
}
static void process_Exited(object sender, EventArgs e)
{
Console.WriteLine("Process has exited.");
}
reshefmにはかなりいい答えがありました。ただし、プロセスが最初から開始されなかった状況は考慮されません。
これが彼が投稿したものの修正版です。
public static bool IsRunning(this Process process)
{
try {Process.GetProcessById(process.Id);}
catch (InvalidOperationException) { return false; }
catch (ArgumentException){return false;}
return true;
}
ArgumentNullExceptionを削除したのは、実際にはnull参照例外であると想定され、とにかくシステムによってスローされ、プロセスが開始されない、またはclose()メソッドを使用して処理する。
これはワンライナーでなければなりません:
public static class ProcessHelpers {
public static bool IsRunning (string name) => Process.GetProcessesByName(name).Length > 0;
}
この機能をどの程度信頼できるかによって異なります。特定のプロセスインスタンスがまだ実行されており、100%の精度で使用可能かどうかを知りたい場合は、運が悪いです。その理由は、管理対象プロセスオブジェクトから、プロセスを識別する方法が2つしかないためです。
1つはプロセスIDです。残念ながら、プロセスIDは一意ではなく、リサイクルできます。一致するIDのプロセスリストを検索すると、同じIDのプロセスが実行されていることがわかりますが、必ずしもプロセスではありません。
2番目の項目はプロセスハンドルです。 Idと同じ問題がありますが、扱いにくいです。
中レベルの信頼性を探している場合は、現在のプロセスリストで同じIDのプロセスを確認するだけで十分です。
Process.GetProcesses()
が道です。ただし、プロセスの実行方法に応じて、1つ以上の異なる基準を使用してプロセスを見つける必要がある場合があります(つまり、タイトルバーがあるかどうかにかかわらず、サービスまたは通常のアプリとして)。
プロセスIDによる既存のプロセスのチェックに関して.NetフレームワークからサポートされているAPIにもかかわらず、これらの機能は非常に低速です。 Process.GetProcesses()またはProcess.GetProcessById/Name()を実行するには、膨大なCPUサイクルがかかります。
IDで実行中のプロセスを確認するはるかに迅速な方法は、ネイティブAPI OpenProcess() を使用することです。戻りハンドルが0の場合、プロセスは存在しません。ハンドルが0以外の場合、プロセスは実行中です。このメソッドが許可のために常に100%動作するという保証はありません。
たぶん(おそらく)私は間違って質問を読んでいますが、Processオブジェクトによって表されるプロセスが(通常かどうかにかかわらず)終了したことを通知するHasExitedプロパティを探していますか?.
参照先のプロセスにUIがある場合、Respondingプロパティを使用して、UIが現在ユーザー入力に応答しているかどうかを判断できます。
EnableRaisingEventsを設定し、Exitedイベント(非同期に送信される)を処理するか、ブロックする場合はWaitForExit()を呼び出すこともできます。
私はコインコインのソリューションを試しました:
いくつかのファイルを処理する前に、一時ファイルとしてコピーして開きます。
完了したら、アプリケーションがまだ開いている場合はアプリケーションを閉じ、一時ファイルを削除します。
Process変数を使用して、後で確認するだけです。
private Process openApplication;
private void btnOpenFile_Click(object sender, EventArgs e) {
...
// copy current file to fileCache
...
// open fileCache with proper application
openApplication = System.Diagnostics.Process.Start( fileCache );
}
後でアプリケーションを閉じます:
...
openApplication.Refresh();
// close application if it is still open
if ( !openApplication.HasExited() ) {
openApplication.Kill();
}
// delete temporary file
System.IO.File.Delete( fileCache );
動作します(これまで)
string process = "notepad";
if (Process.GetProcessesByName(process).Length == 0)
{
MessageBox.Show("Working");
}
else
{
MessageBox.Show("Not Working");
}
また、毎回プロセスをチェックするためにタイマーを使用できます
目的のプロセスに対してProcessインスタンスを1回インスタンス化し、その.NET Processオブジェクトを使用してプロセスを追跡し続けることができます(追跡しているプロセスが死んでも、明示的にその.NETオブジェクトでCloseを呼び出すまで追跡を続けます) [これは、プロセス終了時間、つまりExitTimeなどを提供できるようにすることです])
引用 http://msdn.Microsoft.com/en-us/library/fb4aw7b8.aspx :
関連付けられたプロセスが終了すると(つまり、正常または異常終了によりオペレーティングシステムによってシャットダウンされると)、システムはプロセスに関する管理情報を保存し、WaitForExitを呼び出したコンポーネントに戻ります。プロセスコンポーネントは、終了したプロセスのハンドルを使用して、ExitTimeを含む情報にアクセスできます。
関連するプロセスが終了したため、コンポーネントのHandleプロパティは既存のプロセスリソースをポイントしなくなりました。代わりに、ハンドルは、プロセスリソースに関するオペレーティングシステムの情報にアクセスするためにのみ使用できます。システムは、プロセスコンポーネントによって解放されていない終了したプロセスへのハンドルを認識しているため、プロセスコンポーネントがリソースを明示的に解放するまで、ExitTimeおよびHandle情報をメモリに保持します。このため、プロセスインスタンスのStartを呼び出すときはいつでも、関連付けられたプロセスが終了し、それに関する管理情報が不要になったときにCloseを呼び出します。 Closeは、終了したプロセスに割り当てられたメモリを解放します。
他の人が部分的に対処しているように思われるので、これに関連する多くの問題があります:
他の人が言及したプロパティが内部であるかどうかに関係なく、許可が許せば、リフレクションを介してそれらから情報を取得できます。
var x = obj.GetType().GetProperty("Name", BindingFlags.NonPublic | BindingFlags.Instance);
Snapshot のWin32コードをpinvokeするか、より遅い WMI を使用できます。
HANDLE CreateToolhelp32Snapshot(
DWORD dwFlags,
DWORD th32ProcessID
);
別のオプションは OpenProcess /CloseProcessですが、例外は以前と同じようにスローされ、同じ問題が発生します。
WMIの場合-OnNewEvent.Properties ["?"]: