![](/img/trans.png)
[英]C# - Telling Process.Start to wait until previous instance has finished
[英]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.