Windows С++:Как я могу перенаправить stderr для вызовов fprintf?

StackOverflow https://stackoverflow.com/questions/7664

  •  08-06-2019
  •  | 
  •  

Вопрос

Я переношу существующий код 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 структуру и проверьте событие, чтобы узнать, доступны ли данные...Однако у меня нет кода, который бы это делал.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top