Windows С++:Как я могу перенаправить stderr для вызовов fprintf?
Вопрос
Я переношу существующий код C++ из БСД проект в нашей собственной оболочке, и я хочу интегрировать его в наш код с как можно меньшим количеством изменений.Этот код использует fprintf
распечатать на stderr для регистрации/сообщения об ошибках.
Я хочу перенаправить это в альтернативное место в том же процессе.На Юникс Я сделал это с помощью socketpair
и thread
:один конец сокета — это то место, куда я отправляю stderr (через звонок на dup2
), а другой конец отслеживается в потоке, где я затем могу обработать вывод.
Это не работает на Окна хотя потому, что сокет — это не то же самое, что дескриптор файла.
Все документы, которые я нашел в Интернете, показывают, как перенаправить вывод дочернего процесса, а это не то, чего я хочу.Как я могу перенаправить stderr в рамках одного и того же процесса происходит какой-то обратный вызов при записи вывода?(и прежде чем ты это скажешь, я попробовал SetStdHandle
но не могу найти способ заставить это работать)...
Решение
Вы можете использовать аналогичный метод в Windows, вам просто нужно использовать разные слова для одних и тех же понятий.:) Эта статья: http://msdn.microsoft.com/en-us/library/ms682499.aspx использует канал win32 для обработки ввода-вывода из другого процесса, вам просто нужно сделать то же самое с потоками внутри того же процесса.Конечно, в вашем случае весь вывод на stderr из любой точки процесса будет перенаправлен вашему потребителю.
На самом деле вам могут понадобиться и другие части головоломки: _fdopen и _open_osfhandle.На самом деле, вот похожий пример из некоторых код Я выпустил много лет назад:
DWORD CALLBACK DoDebugThread(void *)
{
AllocConsole();
SetConsoleTitle("Copilot Debugger");
// The following is a really disgusting hack to make stdin and stdout attach
// to the newly created console using the MSVC++ libraries. I hope other
// operating systems don't need this kind of kludge.. :)
stdout->_file = _open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT);
stdin->_file = _open_osfhandle((long)GetStdHandle(STD_INPUT_HANDLE), _O_TEXT);
debug();
stdout->_file = -1;
stdin->_file = -1;
FreeConsole();
CPU_run();
return 0;
}
В данном случае основным процессом был процесс с графическим интерфейсом, который вообще не запускается с дескрипторами stdio.Он открывает консоль, затем помещает правые дескрипторы в stdout и stdin, чтобы функция debug() (которая была разработана как интерактивная функция stdio) могла взаимодействовать с вновь созданной консолью.У вас должна быть возможность открыть несколько каналов и сделать то же самое, чтобы перенаправить поток stderr.
Другие советы
Вы должны помнить, что то, что MSVCRT называет «дескрипторами ОС», — это не дескрипторы Win32, а еще один уровень дескрипторов, добавленный только для того, чтобы вас запутать.MSVCRT пытается эмулировать номера дескрипторов Unix, где stdin
= 0, stdout
= 1, stderr
= 2 и так далее.Дескрипторы Win32 нумеруются по-разному, и их значения всегда кратны 4.Чтобы открыть трубу и правильно настроить все ручки, вам придется испачкать руки.Использование исходного кода MSVCRT и отладчика, вероятно, является обязательным требованием.
Вы упоминаете, что не хотите использовать именованный канал для внутреннего использования;вероятно, стоит отметить, что документация для СоздатьПайп() состояния, «Анонимные каналы реализуются с использованием именованного канала с уникальным именем.Поэтому часто можно передать дескриптор анонимного канала функции, которой требуется дескриптор именованного канала». Итак, я предлагаю вам просто написать функцию, создающую аналогичный канал с правильными настройками для асинхронного чтения.Я склонен использовать GUID в виде строки (сгенерированной с помощью CoCreateGUID()
и StringFromIID()
), чтобы дать мне уникальное имя, а затем создать серверную и клиентскую части именованного канала с правильными настройками для перекрывающегося ввода-вывода (подробнее об этом и коде здесь: http://www.lenholgate.com/blog/2008/02/process-management-using-jobs-on-windows.html).
Как только я это получу, я подключаю некоторый код, который должен прочитать файл, используя перекрывающийся ввод-вывод с портом завершения ввода-вывода, и, ну, тогда я просто получаю асинхронные уведомления о данных по мере их поступления...Тем не менее, у меня есть изрядное количество хорошо протестированного библиотечного кода, благодаря которому все это происходит...
Вероятно, можно настроить именованный канал, а затем просто выполнить перекрывающееся чтение с событием в вашем OVERLAPPED
структуру и проверьте событие, чтобы узнать, доступны ли данные...Однако у меня нет кода, который бы это делал.