web-dev-qa-db-ja.com

C#-プロセスが起動するまでProcess.Startを待機させる

メソッドを使用する前に、プロセスが実行されていることを確認する必要があります。

ステートメントは次のとおりです。

Process.Start("popup.exe");

WAITコマンドを実行するか、この値に遅延を設定できますか?

69
Tom

完了するまで待つということですか?次にProcess.WaitForExitを使用します。

var process = new Process {
    StartInfo = new ProcessStartInfo {
        FileName = "popup.exe"
    }
};
process.Start();
process.WaitForExit();

あるいは、メッセージループに入るのを待っているUIを備えたアプリケーションの場合、次のように言うことができます。

process.Start();
process.WaitForInputIdle();

最後に、これらのどちらも当てはまらない場合は、Thread.Sleepだけである程度の時間をかけてください:

process.Start();
Thread.Sleep(1000); // sleep for one second
121
jason

これも一度必要で、プロセスのウィンドウタイトルを確認しました。期待したものであれば、アプリケーションが実行されていることを確認できます。私がチェックしていたアプリケーションは起動に時間がかかり、この方法はうまくいきました。

var process = Process.Start("popup.exe");
while(process.MainWindowTitle != "Title")
{
    Thread.Sleep(10);
}
14
ChrisG

「ChrisG」の答えは正しいのですが、MainWindowTitleを毎回更新する必要があり、空を確認する方が良いでしょう。..このように:

var proc = Process.Start("popup.exe");
while (string.IsNullOrEmpty(proc.MainWindowTitle))
{
    System.Threading.Thread.Sleep(100);
    proc.Refresh();
}
11

まず第一に、これはかなり古いことを知っていますが、まだ受け入れられている答えはないので、おそらく私のアプローチは他の誰かを助けるでしょう。 :)

これを解決するために私がしたことは:

process.Start();

while (true)
{
    try
    {
        var time = process.StartTime;
        break;
    }
    catch (Exception) {}
}

プロセスが開始されない限り、関連付けvar time = process.StartTimeは例外をスローします。そのため、一度パスすると、プロセスが実行中であると想定し、それをさらに処理しても安全です。 Javaプロセスが起動するのを待つためにこれを使用しています。時間がかかるためです。この方法では、Thread.Sleep()を使用するのではなく、アプリケーションが実行されているマシンに依存しません。

これは非常にクリーンなソリューションではないことを理解していますが、パフォーマンスに依存しない唯一のソリューションだと思います。

7
RhodryCZ

他の人がすでに言っているように、あなたが何を求めているのかすぐにはわかりません。プロセスを開始し、プロセスが「準備ができた」ときに別のアクションを実行することを想定します。

もちろん、「準備ができている」というのは難しいことです。必要なものによっては、単に待つだけで十分であることがわかります。ただし、より堅牢なソリューションが必要な場合は、名前付き Mutex を使用して2つのプロセス間の制御フローを制御することを検討できます。

たとえば、メインプロセスで名前付きミューテックスを作成し、待機するスレッドまたはタスクを開始できます。その後、2番目のプロセスを開始できます。そのプロセスが「準備ができている」と判断すると、名前付きミューテックスを開き(もちろん同じ名前を使用する必要があります)、最初のプロセスにシグナルを送ることができます。

7
Matt

私はトムに同意します。さらに、Thread.Sleepの実行中にプロセスを確認するには、実行中のプロセスを確認します。何かのようなもの:

bool found = 0;
while (!found)
{
    foreach (Process clsProcess in Process.GetProcesses())
        if (clsProcess.Name == Name)
            found = true;

    Thread.CurrentThread.Sleep(1000);
}
4
Frank Pearson

子プロセスが開始する前にStartメソッドが返されますか? Startは子プロセスを同期的に開始するという印象を受けていました。

子プロセスが何らかの初期化を完了するまで待つ場合は、プロセス間通信が必要です-C#(.NET 2.0)のWindowsのプロセス間通信 を参照してください

2
Jakub Konecki

@ChrisGのアイデアを少し拡張するには、process.MainWindowHandleの使用を検討し、ウィンドウメッセージループが応答しているかどうかを確認します。このWin32 APIのp/invokeを使用します: SendMessageTimeout 。そのリンクから:

関数が成功した場合、戻り値はゼロ以外です。 HWND_BROADCASTが使用されている場合、SendMessageTimeoutは個々のウィンドウのタイムアウトに関する情報を提供しません。

関数が失敗またはタイムアウトした場合、戻り値は0です。拡張エラー情報を取得するには、GetLastErrorを呼び出します。 GetLastErrorがERROR_TIMEOUTを返す場合、関数はタイムアウトしました。

1
agent-j

ここで、System.Threading.Timerを使用する実装。多分その目的のために少し。

    private static bool StartProcess(string filePath, string processName)
    {
        if (!File.Exists(filePath))
            throw new InvalidOperationException($"Unknown filepath: {(string.IsNullOrEmpty(filePath) ? "EMPTY PATH" : filePath)}");

        var isRunning = false;

        using (var resetEvent = new ManualResetEvent(false))
        {

            void Callback(object state)
            {
                if (!IsProcessActive(processName)) return;
                isRunning = true;
                // ReSharper disable once AccessToDisposedClosure
                resetEvent.Set();
            }

            using (new Timer(Callback, null, 0, TimeSpan.FromSeconds(0.5).Milliseconds))
            {
                Process.Start(filePath);
                WaitHandle.WaitAny(new WaitHandle[] { resetEvent }, TimeSpan.FromSeconds(9));
            }
        }

        return isRunning;
    }

    private static bool StopProcess(string processName)
    {
        if (!IsProcessActive(processName)) return true;

        var isRunning = true;

        using (var resetEvent = new ManualResetEvent(false))
        {

            void Callback(object state)
            {
                if (IsProcessActive(processName)) return;
                isRunning = false;
                // ReSharper disable once AccessToDisposedClosure
                resetEvent.Set();
            }

            using (new Timer(Callback, null, 0, TimeSpan.FromSeconds(0.5).Milliseconds))
            {
                foreach (var process in Process.GetProcessesByName(processName))
                    process.Kill();
                WaitHandle.WaitAny(new WaitHandle[] { resetEvent }, TimeSpan.FromSeconds(9));
            }
        }

        return isRunning;
    }

    private static bool IsProcessActive(string processName)
    {
        return Process.GetProcessesByName(processName).Any();
    }
0
Peter