В каких случаях метод Process.Start() возвращает false?

От MSDN:

Возвращаемое значение true указывает, что новый ресурс процесса  начал. Если ресурс процесса, указанный членом FileName  свойство StartInfo уже запущено на компьютере, no  запускается дополнительный ресурс процесса. Вместо этого выполняемый процесс  ресурс повторно используется и возвращается false.

Попробуйте что-то вроде этого:

var info = new ProcessStartInfo {FileName = @"CMD"};

var p1 = new Process
{
     StartInfo = info
};

var result = p1.Start(); //true
result = p1.Start(); //true

var p2 = new Process
{
    StartInfo = info
};

result = p2.Start(); //true

Имеет тот же результат, если я использую FilePath = @"c:\myapp.exe" вместо CMD.

В каких случаях он возвращает false?

Ответ 1

Если вы посмотрите на исходный источник, вы увидите, как работает Process.Start:

http://referencesource.microsoft.com/System/R/c50d8ac0eb7bc0d6.html

Это один из двух методов, вызываемых при вызове Process.Start. Обратите внимание на нижнюю часть, где оно возвращает значение true или false. False возвращается только в том случае, если после запуска процесса он не может получить дескриптор процесса, который был запущен.

Чтобы начать процесс, он использует NativeMethods.CreateProcess, который вы можете найти здесь: http://referencesource.microsoft.com/System/compmod/microsoft/win32/NativeMethods.cs.html#9c52a5ca5f3eeea3

Это всего лишь прототип метода для Kernel32.CreateProcess, который API найден здесь: https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx

Если вы посмотрите на возвращаемые значения, в нем говорится:

Если функция завершается успешно, возвращаемое значение отличное от нуля. Если функция не работает, возвращаемое значение равно нулю.

Я не могу найти что-либо в API для CreateProcess, который говорит, что он терпит неудачу, если запрошенный процесс уже запущен, возможно, если процесс не запускался, потому что это одно экземплярное приложение (например, Outlook), то он может не работать, но для приложений с несколькими экземплярами, например командной строки, он не должен создавать дескриптор процесса.

Итак, после всего сказанного, возможно, что документация MSDN не совсем корректна, у меня нет ссылки, но для Process.Start(StartInfo), MSDN говорит об этом возвращаемом значении:

Новый процесс, связанный с ресурсом процесса, или null, если не запущен ресурс процесса. Обратите внимание, что новый процесс, запущенный рядом с уже запущенными экземплярами одного и того же процесса, будет независимым от других. Кроме того, Start может возвращать ненулевой процесс со свойством HasExited, уже установленным в true. В этом случае запущенный процесс может активировать существующий экземпляр самого себя, а затем выйти.

(Акцент, добавленный мной). Он не говорит, что вызов завершится неудачно, если он уже запущен.

В Process.Start() говорится:

Возвращаемое значение Тип: System.Boolean true, если запущен ресурс процесса; false, если новый ресурс процесса не запущен (например, если существующий процесс используется повторно).

Итак, он говорит , если существующий процесс повторно используется, это полностью зависит от запуска приложения или метода его запуска.

Ответ 2

Вы можете технически получить ложное возвращение, когда используете ProcessStartInfo.UseShellExecute = true (по умолчанию), и вы запускаете процесс, передавая имя файла документа. И оболочка как-то может понять, чтобы передать запрос открытого документа на уже запущенный экземпляр процесса.

Единственным документированным случаем является открытие веб-страницы в Internet Explorer. Могут быть и другие, возможно, имеющие какое-то отношение к устаревшей активации DDE. Это предположение.

Это, в противном случае, конкретный случай общей проблемы с Process.Start(), существует множество приложений с одним экземпляром. Приложения Office являются наиболее распространенным примером. Наиболее типичным поведением, которое вы наблюдаете, является то, что процесс очень быстро заканчивается снова. Он только что обнаружил, что приложение уже запущено и использует процесс-interop, чтобы попросить запущенный экземпляр открыть документ. Эта функция поддерживается в .NET.

Вы не знаете, какой конкретный процесс покажет документ, если вы не знаете, что это приложение с одним экземпляром и его имя процесса, поэтому у вас есть надежда найти его с помощью Process.GetProcessesByName(). Это, однако, не безопасно, может быть несвязанный процесс, который имеет одно и то же имя. Преимущество получения ложных данных заключается в том, что вы не знаете, что нет смысла ждать завершения.