Ich muss sicherstellen, dass ein Prozess ausgeführt wird, bevor ich mit einer Methode fortfahre.
Die Aussage lautet:
Process.Start("popup.exe");
Können Sie einen WAIT-Befehl ausführen oder eine Verzögerung für diesen Wert festlegen?
Ich muss sicherstellen, dass ein Prozess ausgeführt wird, bevor ich mit einer Methode fortfahre.
Die Aussage lautet:
Process.Start("popup.exe");
Können Sie einen WAIT-Befehl ausführen oder eine Verzögerung für diesen Wert festlegen?
Antworten:
Meinst du warten, bis es fertig ist? Dann benutze Process.WaitForExit
:
var process = new Process {
StartInfo = new ProcessStartInfo {
FileName = "popup.exe"
}
};
process.Start();
process.WaitForExit();
Wenn es sich um eine Anwendung mit einer Benutzeroberfläche handelt, auf deren Eingabe Sie in eine Nachrichtenschleife warten, können Sie alternativ Folgendes sagen:
process.Start();
process.WaitForInputIdle();
Wenn beides nicht zutrifft, nur Thread.Sleep
für einen angemessenen Zeitraum:
process.Start();
Thread.Sleep(1000); // sleep for one second
process.Start()
vor process.WaitForExit()
; Andernfalls wird eine Ausnahme ausgelöst.
Ich brauchte das auch einmal und überprüfte den Fenstertitel des Prozesses. Wenn es das ist, was Sie erwarten, können Sie sicher sein, dass die Anwendung ausgeführt wird. Die Anwendung, die ich überprüfte, brauchte einige Zeit für den Start und diese Methode funktionierte gut für mich.
var process = Process.Start("popup.exe");
while(process.MainWindowTitle != "Title")
{
Thread.Sleep(10);
}
Die Antwort von 'ChrisG' ist richtig, aber wir müssen MainWindowTitle jedes Mal aktualisieren und es ist besser, nach Leerzeichen zu suchen ... wie folgt:
var proc = Process.Start("popup.exe");
while (string.IsNullOrEmpty(proc.MainWindowTitle))
{
System.Threading.Thread.Sleep(100);
proc.Refresh();
}
Zuallererst: Ich weiß, dass dies ziemlich alt ist, aber es gibt immer noch keine akzeptierte Antwort. Vielleicht hilft mein Ansatz jemand anderem. :) :)
Was ich getan habe, um dies zu lösen, ist:
process.Start();
while (true)
{
try
{
var time = process.StartTime;
break;
}
catch (Exception) {}
}
Die Zuordnung var time = process.StartTime
löst eine Ausnahme aus, solange der Prozess nicht gestartet wurde. Sobald es vorbei ist, ist es sicher anzunehmen, dass der Prozess läuft, und weiter damit zu arbeiten. Ich verwende dies, um auf den Start des Java-Prozesses zu warten, da dies einige Zeit dauert. Auf diese Weise sollte es unabhängig davon sein, auf welchem Computer die Anwendung ausgeführt wird, anstatt es zu verwenden Thread.Sleep()
.
Ich verstehe, dass dies keine sehr saubere Lösung ist, aber die einzige, die leistungsunabhängig sein sollte, die ich mir vorstellen kann.
Wie andere bereits gesagt haben, ist es nicht sofort offensichtlich, was Sie fragen. Ich gehe davon aus, dass Sie einen Prozess starten und dann eine weitere Aktion ausführen möchten, wenn der Prozess "bereit" ist.
Natürlich ist das "ist fertig" das schwierige Stück. Je nachdem, was Sie brauchen, können Sie feststellen, dass es ausreicht, einfach zu warten. Wenn Sie jedoch eine robustere Lösung benötigen, können Sie einen benannten Mutex verwenden , um den Kontrollfluss zwischen Ihren beiden Prozessen zu steuern.
In Ihrem Hauptprozess können Sie beispielsweise einen benannten Mutex erstellen und einen Thread oder eine Aufgabe starten, die warten wird. Dann können Sie den 2. Prozess starten. Wenn dieser Prozess entscheidet, dass "es bereit ist", kann er den benannten Mutex öffnen (Sie müssen natürlich denselben Namen verwenden) und dem ersten Prozess ein Signal geben.
Ich stimme Tom zu. Überprüfen Sie außerdem die laufenden Prozesse, um die Prozesse während der Ausführung von Thread.Sleep zu überprüfen. Etwas wie:
bool found = 0;
while (!found)
{
foreach (Process clsProcess in Process.GetProcesses())
if (clsProcess.Name == Name)
found = true;
Thread.CurrentThread.Sleep(1000);
}
while (!Process.GetProcesses().Any(p=>p.Name == myName)) { Thread.Sleep(100); }
GetProcessesByName()
? while(Process.GetProcessesByName(myName).Length == 0) { Thread.Sleep(100); }
Während es die meiste Zeit funktionieren könnte, wäre der richtige Weg, bis n Meilensekunden zu warten und aus der Schleife herauszukommen, wenn der Prozess nicht gefunden wurde.
Sind Sie sicher, dass die Start
Methode zurückgegeben wird, bevor der untergeordnete Prozess gestartet wird? Ich hatte immer den Eindruck, dass Start
der untergeordnete Prozess synchron gestartet wird.
Wenn Sie warten möchten, bis Ihr untergeordneter Prozess eine Initialisierung abgeschlossen hat, benötigen Sie eine prozessübergreifende Kommunikation - siehe Interprozesskommunikation für Windows in C # (.NET 2.0) .
Um die Idee von @ ChrisG ein wenig zu erweitern, sollten Sie process.MainWindowHandle verwenden und prüfen, ob die Fenstermeldungsschleife reagiert. Verwenden Sie p / invoke diese Win32-API: SendMessageTimeout . Von diesem Link:
Wenn die Funktion erfolgreich ist, ist der Rückgabewert ungleich Null. SendMessageTimeout bietet keine Informationen zum Zeitlimit für einzelne Fenster, wenn HWND_BROADCAST verwendet wird.
Wenn die Funktion fehlschlägt oder eine Zeitüberschreitung auftritt, ist der Rückgabewert 0. Um erweiterte Fehlerinformationen zu erhalten, rufen Sie GetLastError auf. Wenn GetLastError ERROR_TIMEOUT zurückgibt, ist die Funktion abgelaufen.
Hier eine Implementierung, die a verwendet System.Threading.Timer
. Vielleicht ein bisschen viel für seinen Zweck.
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();
}
Ich habe die EventWaitHandle- Klasse verwendet. Erstellen Sie im übergeordneten Prozess ein benanntes EventWaitHandle, dessen Anfangsstatus des Ereignisses auf "Nicht signalisiert" gesetzt ist. Der übergeordnete Prozess wird blockiert, bis der untergeordnete Prozess die Set- Methode aufruft und den Status des Ereignisses wie unten gezeigt in signalisiert ändert.
Übergeordneter Prozess:
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();
}
}
}
}
Untergeordneter Prozess:
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)
{ }
}
}
}
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;
}
}
App
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 ...
Sie können auch überprüfen, ob der gestartete Prozess reagiert oder nicht, indem Sie Folgendes versuchen: while (process.responding)