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

Я упаковываю существующий код C ++ из проекта BSD в нашу собственную пользовательскую оболочку и хочу интегрировать его в наш код с минимальными изменениями. Этот код используется fprintfдля печати в stderr для регистрации / сообщения об ошибках.

Я хочу перенаправить это в другое место в том же процессе. В Unix я сделал это с помощью a socketpairи a thread: один конец сокета - это то место, куда я отправляю stderr (посредством вызова dup2), а другой конец отслеживается в потоке, где я могу затем обработать вывод.

Это не работает в Windows, потому что сокет не совпадает с дескриптором файла.

Все документы, которые я нашел в Интернете, показывают, как перенаправить вывод из дочернего процесса, а это не то, что мне нужно. Как я могу перенаправить stderr в том же процессе, получая какой-то обратный вызов при записи вывода? (и прежде чем вы скажете так, я пытался, SetStdHandleно не могу найти способ сделать эту работу) ...

11.08.2008 10:38:51
3 ОТВЕТА
РЕШЕНИЕ

Вы можете использовать похожую технику в 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.

6
11.08.2008 11:05:37

Вы должны помнить, что то, что MSVCRT называет «дескрипторами ОС», - это не дескрипторы Win32, а еще один слой дескрипторов, добавленный просто для того, чтобы сбить вас с толку. MSVCRT пытается эмулировать номера дескрипторов Unix, где stdin= 0, stdout= 1, stderr= 2 и так далее. Дескрипторы Win32 нумеруются по-разному, и их значения всегда кратны 4. Открытие канала и правильная настройка всех дескрипторов потребуют запутывания рук. Использование исходного кода MSVCRT и отладчика, вероятно, является обязательным требованием.

3
21.12.2015 15:24:01

Вы упоминаете, что не хотите использовать именованный канал для внутреннего использования; Вероятно, стоит отметить, что документация для CreatePipe () гласит: «Анонимные каналы реализованы с использованием именованного канала с уникальным именем. Поэтому вы часто можете передать дескриптор анонимному каналу функции, которая требует дескриптор именованного канала. труба «. Итак, я предлагаю вам просто написать функцию, которая создает похожий канал с правильными настройками для асинхронного чтения. Я склонен использовать GUID в качестве строки (сгенерированной с помощью CoCreateGUID()и StringFromIID()), чтобы дать мне уникальное имя, а затем создать серверные и клиентские концы именованного канала с правильными настройками для перекрывающегося ввода-вывода (подробнее об этом и коде, Вот: http://www.lenholgate.com/blog/2008/02/process-management-using-jobs-on-windows.html ).

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

Вероятно, можно настроить именованный канал, а затем просто выполнить перекрывающееся чтение с событием в вашей OVERLAPPEDструктуре и проверить событие, чтобы увидеть, доступны ли данные ... У меня нет кода, который бы это делал.

1
21.12.2015 15:12:09