Windows C ++: Как я могу перенаправить stderr для вызовов fprintf? - PullRequest
5 голосов
/ 11 августа 2008

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

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

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

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

Ответы [ 3 ]

6 голосов
/ 11 августа 2008

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

3 голосов
/ 11 августа 2008

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

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

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

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

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

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