簡體   English   中英

C# - 制作一個 Process.Start 等到進程啟動

[英]C# - Making a Process.Start wait until the process has start-up

在繼續使用方法之前,我需要確保進程正在運行。

聲明是:

Process.Start("popup.exe");

您可以執行 WAIT 命令或在此值上設置延遲嗎?

你的意思是等它完成嗎? 然后使用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

我也需要這個,我檢查了進程的窗口標題。 如果它是您所期望的,您可以確定應用程序正在運行。 我正在檢查的應用程序需要一些時間來啟動,這種方法對我來說效果很好。

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

'ChrisG' 的答案是正確的,但是我們每次都需要刷新 MainWindowTitle 並且最好檢查一下是否為空...。像這樣:

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

首先:我知道這已經很老了,但仍然沒有一個公認的答案,所以也許我的方法會幫助其他人。 :)

我為解決這個問題所做的是:

process.Start();

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

只要進程沒有啟動,關聯var time = process.StartTime就會拋出異常。 因此,一旦它通過,就可以安全地假設進程正在運行並進一步使用它。 我正在使用它來等待 java 進程啟動,因為它需要一些時間。 這樣,它應該獨立於應用程序正在運行的機器,而不是使用Thread.Sleep()

我知道這不是很干凈的解決方案,但我能想到的唯一一個應該與性能無關的解決方案。

就像其他人已經說過的那樣,您要問什么並不是很明顯。 我將假設您要啟動一個流程,然后在流程“准備就緒”時執行另一個操作。

當然,“准備就緒”是一個棘手的問題。 根據您的需求,您可能會發現只需等待就足夠了。 但是,如果您需要更強大的解決方案,您可以考慮使用命名的Mutex來控制兩個進程之間的控制流。

例如,在您的主進程中,您可能會創建一個命名互斥體並啟動一個將等待的線程或任務。 然后,您可以開始第二個過程。 當該進程決定“准備就緒”時,它可以打開命名的互斥鎖(當然,您必須使用相同的名稱)並向第一個進程發出信號。

我同意湯姆的觀點。 此外,要在執行 Thread.Sleep 時檢查進程,請檢查正在運行的進程。 就像是:

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

    Thread.CurrentThread.Sleep(1000);
}

我使用了EventWaitHandle類。 在父進程上,創建一個名為 EventWaitHandle 的事件初始狀態設置為非信號。 父進程阻塞,直到子進程調用Set方法,將事件的狀態更改為已發出信號,如下所示。

父進程:

using System;
using System.Threading;
using System.Diagnostics;

namespace MyParentProcess
{
    class Program
    {
        static void Main(string[] args)
        {
            EventWaitHandle ewh = null;
            try
            {
                ewh = new EventWaitHandle(false, EventResetMode.AutoReset, "CHILD_PROCESS_READY");

                Process process = Process.Start("MyChildProcess.exe", Process.GetCurrentProcess().Id.ToString());
                if (process != null)
                {
                    if (ewh.WaitOne(10000))
                    {
                        // Child process is ready.
                    }
                }
            }
            catch(Exception exception)
            { }
            finally
            {
                if (ewh != null)
                    ewh.Close();
            }
        }
    }
}

子進程:

using System;
using System.Threading;
using System.Diagnostics;

namespace MyChildProcess
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                // Representing some time consuming work.
                Thread.Sleep(5000);

                EventWaitHandle.OpenExisting("CHILD_PROCESS_READY")
                    .Set();

                Process.GetProcessById(Convert.ToInt32(args[0]))
                    .WaitForExit();
            }
            catch (Exception exception)
            { }
        }
    }
}

您確定Start方法在子進程啟動之前返回嗎? 我一直認為Start是同步啟動子進程的。

如果您想等到您的子進程完成某種初始化,那么您需要進程間通信 - 請參閱C# (.NET 2.0) 中的 Windows 進程間通信

為了擴展@ChrisG 的想法,請考慮使用 process.MainWindowHandle 並查看窗口消息循環是否正在響應。 使用 p/invoke 這個 Win32 api: SendMessageTimeout 從那個鏈接:

如果函數成功,則返回值非零。 如果使用 HWND_BROADCAST,SendMessageTimeout 不提供有關單個窗口超時的信息。

如果函數失敗或超時,則返回值為 0。要獲取擴展錯誤信息,請調用 GetLastError。 如果 GetLastError 返回 ERROR_TIMEOUT,則函數超時。

這是一個使用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();
    }
public static class WinApi
{

    [DllImport("user32.dll")]
    public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

    public static class Windows
    {
        public const int NORMAL = 1;
        public const int HIDE = 0;
        public const int RESTORE = 9;
        public const int SHOW = 5;
        public const int MAXIMIXED = 3;
    }

}

應用程序

String process_name = "notepad"
Process process;
process = Process.Start( process_name );

while (!WinApi.ShowWindow(process.MainWindowHandle, WinApi.Windows.NORMAL))
{
    Thread.Sleep(100);
    process.Refresh();
}

// Done!
// Continue your code here ...

您還可以通過嘗試以下方式檢查啟動的進程是否響應:while(process.responding)

我正在使用這兩種方法:

    public static void WaitUntilLoad(Process process, int? millisecond = null)
    {
        while ((!millisecond.HasValue || millisecond > 0) && string.IsNullOrEmpty(process.MainWindowTitle))
        {
            Thread.Sleep(100);
            if (millisecond.HasValue) millisecond -= 100;
            process.Refresh();
        }
    }
    public static void WaitUntilExit(Process process, int? millisecond = null)
    {
        if (millisecond.HasValue) process.WaitForExit(millisecond.Value);
        else process.WaitForExit();
    }

享受...

我認為湯姆正在尋找這樣的東西:

Process process = Process.Start(@"MyApp.exe");
Process[] processes;

do
{
    processes = Process.GetProcessesByName("MyApp");
    Console.WriteLine("{0} Processes found.", processes.Length);
    Thread.Sleep(1000);
}
while (processes.Length == 0);

Close(); // Or do whatever you want...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM