Мне нужно убедиться, что процесс запущен, прежде чем переходить к методу.
Утверждение:
Process.Start("popup.exe");
Вы можете выполнить команду WAIT или установить задержку для этого значения?
Мне нужно убедиться, что процесс запущен, прежде чем переходить к методу.
Утверждение:
Process.Start("popup.exe");
Вы можете выполнить команду WAIT или установить задержку для этого значения?
Вы имеете в виду подождать, пока это не закончится? Затем используйте Process.WaitForExit
:
var process = new Process {
StartInfo = new ProcessStartInfo {
FileName = "popup.exe"
}
};
process.Start();
process.WaitForExit();
В качестве альтернативы, если это приложение с пользовательским интерфейсом, которое вы ожидаете ввести в цикл сообщений, вы можете сказать:
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);
}
Вы уверены, что метод Start
возвращается до запуска дочернего процесса? Мне всегда казалось, что Start
синхронно запускает дочерний процесс.
Если вы хотите подождать, пока ваш дочерний процесс завершит какую-то инициализацию, вам понадобится межпроцессная коммуникация - см. Interprocess communication для Windows на С# (.NET 2.0).
Чтобы расширить идею @ChrisG, рассмотрите возможность использования process.MainWindowHandle и посмотрите, отвечает ли цикл окна сообщений. Используйте p/invoke this Win32 api: SendMessageTimeout. По этой ссылке:
Если функция завершается успешно, возвращение значение отличное от нуля. SendMessageTimeout не предоставляет информацию о отдельные окна выходят из строя, если Используется HWND_BROADCAST.
Если функция выйдет из строя или истечет время ожидания, возвращаемое значение равно 0. Чтобы получить расширенная информация об ошибках, вызов GetLastError. Если GetLastError возвращается ERROR_TIMEOUT, тогда функция timed из.
Я думаю, что OP может ссылаться на необходимость иметь действительный дескриптор окна из дочернего процесса, чтобы он мог каким-то образом обработать его.
В моем случае я хочу создать Perl script для запуска в окне консоли DOS и центрировать окно в моем приложении форм при его запуске. Если я захвачу Process.MainWindowHandle слишком рано и назову "MoveWindow" на нем, дескриптор еще недействителен, и вызов ничего не делает. Если я жду второй (вызывая Thread.Wait(1000)), экран появляется в своем местоположении по умолчанию и внезапно перемещается через секунду. Либо может быть очень неприятно для пользователя.
Перейдя в цикл и ожидая, что "Process.MainWindowTitle" вернет что-то значимое, я могу захватить окно, как только оно реагирует, и сосредоточить его на моей форме без раздражающего мерцания.
OP может пытаться сделать что-то подобное.
Здесь реализация, которая использует 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 ...
Я использовал класс 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)
{ }
}
}
}