- MSDN сообщает ProcessStartInfo.UseShellExecute == True означает использование оболочки при запуске процесса, означает ли это, что процесс запускается так же, как я запускаю cmd.exe и запускаю программу из этой командной строки? Какой смысл делать это? У запущенного таким образом процесса есть своя консоль?
На самом деле это работает так:
- если UseShellExecute имеет значение false, приложение будет запущено с использованием API CreateProcess ; этот API позволяет указать множество параметров запуска, среди которых есть возможность перенаправить stdin / stdout / stderr, но он будет запускать только исполняемые файлы. Если вы попытаетесь запустить файл (например, текстовый документ) с помощью CreateProcess, произойдет сбой, поскольку текстовые документы не являются исполняемыми файлами.
- если UseShellExecute имеет значение true, процесс будет запущен с использованием ShellExecuteEx API; эта функция - та же функция, которую использует проводник Windows (« оболочка », по крайней мере, в терминологии Microsoft), когда вы дважды щелкаете файл в папке; его главное преимущество заключается в том, что он «знает», как запускать документы (открывать их с помощью связанных программ), он знает о папках оболочки… потому что он использует много возможностей оболочки. Однако у него есть несколько существенных недостатков: он довольно тяжелый по сравнению с обычным CreateProcess (потому что он должен выполнять много дополнительной работы), он не может открыть даже исполняемые файлы, если что-то не так с ассоциациями файлов / расширениями оболочки / ... и это не может перенаправить стандартный ввод / вывод / стандартный вывод. Не то чтобы теоретически это было бы невозможно: ведь ShellExecuteEx внутренне вызывает CreateProcess; проблема в том, что он не предоставляет эту функцию.
Итак, два метода создания процесса действительно совершенно разные; класс Process отлично справляется с их выравниванием, но функция, которая абсолютно не может быть воспроизведена с помощью функции ShellExecuteEx, - это перенаправление потоков ввода-вывода, поскольку она не доступна функцией ShellExecuteEx и может быть включена только при запуске процесса через CreateProcess.
Другой вопрос - использование консоли запущенной программой. Консоль выделяется / повторно используется внутри CreateProcess (фактически IIRC это связано с загрузчиком Windows PE, который проверяет необходимую подсистему в заголовке PE); правила создания / повторного использования консоли указаны здесь .
Если запущенное приложение является приложением с графическим интерфейсом, консоли вообще не создаются; с другой стороны, если консольное приложение запускается, оно повторно использует консоль своего родительского процесса, если только оно не указано в CreateProcess, и не вызывает флаг CREATE_NEW_CONSOLE. По умолчанию этот флаг не указывается, но я не уверен в том, что делает ShellExecuteEx с консольными приложениями, и у меня нет под рукой окна Windows для проверки. Я оставлю это в качестве упражнения для читателя. : P
Дополнительные ответы
Привет, Маттео, еще один вопрос. Если я создаю новый процесс как отдельный процесс, к которому не подключена консоль. Где сейчас находится процесс вывода? Куда идет вывод процесса? Отличается ли стандартный вывод процесса от выхода консоли?
Мне не понятно, что вы имеете в виду. Когда вы запускаете новый процесс с CreateProcess / ShellExecuteEx, консоль выделяется по мере необходимости, то есть, если исполняемый файл является исполняемым файлом консоли (как указано в заголовке PE), Windows предоставляет ему консоль (новую или родительскую в зависимости по указанным выше правилам); если исполняемый файл является приложением с графическим интерфейсом, для него не выделяется консоль.
IIRC, для приложений с графическим интерфейсом stdout / stdin / stderr - это просто битовые сегменты, т. Е. Они не указывают ни на что полезное, и весь ввод-вывод для них отбрасывается; кстати, ничто не мешает приложению с графическим интерфейсом выделить консоль и перенаправить на нее собственные потоки std *.
Имейте в виду, что консоль, потоки Windows std и потоки CRT std - это три разные вещи.Консоль - это просто интерфейс, который для консольных приложений по умолчанию удобно связан с потоками Windows std.
Потоки Windows std - это те, которые перенаправляются, когда вы указываете перенаправление stdin / stdout / stderr в CreateProcess;вы можете получить к ним дескрипторы с помощью функции GetStdHandle и перенаправить их с помощью SetStdHandle .
CRT stdin / stdout / stderr, наконец, еще одна абстракция, построенный библиотекой времени выполнения C;по умолчанию они привязаны к потокам Windows std.
Все это обычно работает без проблем, и вам даже не нужно беспокоиться о разнице между потоками Windows std и потоками CRT;однако, когда вы начинаете задумываться о перенаправлении потоков, это различие становится важным.
Если поток вывода stdout процесса отличается от вывода консоли, и Shell связывает эти 2 потока для нас.Будет ли выход процесса скопирован из process.stdout в console.output?это эффективно?
Оболочка не участвует в этом процессе, это ядро, которое выполняет сантехнику, следуя инструкциям, используемым в CreateProcess (или впоследствии измененным изнутри нового процесса с помощью других API).Для вашей производительности, с такой многоуровневой структурой, это единственный путь;и более того, копирующая часть (если это действительно копия, я подозреваю, что все дело просто в передаче указателей) - самая быстрая часть процесса, реальным узким местом является рисование / прокрутка окна консоли / и т.д.Фактически, если вы хотите запустить консольное приложение, позволяющее ему производить данные на полной скорости, вы обычно перенаправляете его стандартный вывод в файл или по каналу.
Большое спасибо.Маттео Италия.Вы хорошая проблема, совлер.: D
Спасибо.:)