Перенаправление вывода консоли в буфер неконсольным процессом - PullRequest
1 голос
/ 16 сентября 2011

Вот ситуация: у нас есть сервер сборки, который обслуживает запросы через сокет и не предоставляет никакого интерфейса для машины, на которой он работает. Основываясь на полученных запросах, он запускает сценарии сборки (которые обычно являются пакетными файлами 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? Эти сценарии не являются интерактивными.

Ответы [ 2 ]

1 голос
/ 16 сентября 2011

Вы можете вызвать AllocConsole , чтобы создать консоль, но это принципиально не отличается от создания приложения в виде консоли.

Я думаю, что лучшим решением было бы открыть файл журнала и затем вызвать SetStdHandle , передав ему STD_OUTPUT_HANDLE и дескриптор файла, который вы только что открыли. Я думаю, что это должно дать вам стандартный вывод, в который будут писать другие процессы.

В качестве альтернативы, вы можете найти способ полностью скрыть это окно консоли (удалить его из панели задач и т. Д.)

Дополнительная информация:

Возможно, вы можете попытаться получить дескриптор окна консоли и вызвать ShowWindow(handle, SW_HIDE). Это удаляет окно с экрана, и все же, когда вы пишете в стандартный вывод, оно фактически записывает в это окно. Вы должны иметь возможность получить дескриптор окна консоли, вызвав GetConsoleWindow .

Если это не сработает, ваша программа может принять параметр -hide. Если это в командной строке, то программа запускает новую копию сама, но в информации о запуске процесса говорится, что процесс запускается со скрытым окном.

0 голосов
/ 16 сентября 2011

Эта проблема решалась несколько раз в SO.Взгляните на этот вопрос , например.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...