Вот ситуация: у нас есть сервер сборки, который обслуживает запросы через сокет и не предоставляет никакого интерфейса для машины, на которой он работает. Основываясь на полученных запросах, он запускает сценарии сборки (которые обычно являются пакетными файлами MS) и обслуживает файлы, которые они создают. В целях диагностики сценарии сборки запускаются с перенаправлением stdout и stderr в канал, и эти выходные данные сохраняются в буфер приложением сервера сборки и передаются обратно клиенту, запрашивающему сборку. (Таким образом, если сборка завершится неудачно, лицо, запросившее сборку, сможет увидеть сообщение об ошибке.)
Во время отладки этот сервер сборки был собран как консольное приложение, в основном для удобства печати диагностических сообщений (клиент подключен, запрос сделан и т. Д.). Когда все заработало, я перестроил его как не консольное приложение.
Внезапно поведение приложения изменилось. Выходные данные, захваченные каналом, были сокращены только до выходных данных, непосредственно сгенерированных пакетным файлом (то есть, в этом случае, команды echoed, так как echo не был выключен). Подпроцессы, запускаемые пакетными файлами (такими как MSBuild, nmake и другие), открывали консольные окна и направляли их вывод в окна, а не в канал.
Я подозреваю, что когда приложение было консольным приложением, консольное приложение не пыталось управлять собственным вводом / выводом, а вместо этого унаследовалось от работающей консоли, что привело к _dup2
на вводе / выводе FDS остается в живых. Таким образом, все работало нормально. Но в ситуации, когда родительский сервер сборки не создал консольное окно, подпроцессы, порожденные пакетным файлом, чувствовали необходимость создать свои собственные и обрабатывать свои собственные операции ввода-вывода, отнимая у сервера сборки захваченный вывод (не для упомяните, что он очень раздражает любого, кто подключен к рабочему столу сервера).
Так что в основном вопрос прост: как неконсольный запуск приложений и предотвращение этого поведения? Я знаю, что в принципе это возможно для большинства консольных приложений, потому что режим оболочки Emacs является примером того, как не консольное приложение захватывает и перенаправляет вывод команд в Windows, но я понятия не имею, как это сделать.
В настоящее время я использую функции CRT со вкусом POSIX в Win32: _pipe
, _dup
, _dup2
, _close
, _spawnvp
и _read
. Я знаю, что это тонкие обертки вокруг «настоящих» функций win32, но будучи тренированным парнем из UNIX, я решил, что избавлю себя от необходимости ходить по CreateProcess
и друзьям.
Язык разработки должен быть C, потому что сервер сборки на самом деле написан на Haskell, и связывание C проще. (Для любого из вас, Haskellers, я развернул свой собственный код spawn / redirect и связался с FFI вместо использования System.Process, потому что мне крайне необходимы перенаправления stdout
и stderr
, а в Windows это не тривиально сделать на чистом Хаскеле).
Конечно, я могу использовать сервер сборки в качестве консольного приложения и просто минимизировать его на сервере, ничего страшного, он отлично работает, если я это сделаю. Но я бы предпочел не ... какие-либо идеи?
РЕДАКТИРОВАТЬ: Думаю, я мог бы упомянуть, что я ничего не делаю с STDIN. Должен ли я создать стандартный stdin fd? Эти сценарии не являются интерактивными.