Re[3]: Перенаправление потока cerr
От: watch-maker  
Дата: 28.01.13 16:27
Оценка:
A>Как я позже нарыл можно все же использовать win api
A>BOOL WINAPI SetStdHandle(
A> _In_ DWORD nStdHandle,
A> _In_ HANDLE hHandle
A>);
A>но это платформозависимое решение.
A>(http://msdn.microsoft.com/en-us/library/ms686244(VS.85).aspx)
SetStdHandle сохраняет переданный ей дескриптор в неком хранилище, откуда его можно потом прочитать функцией GetStdHandle. Всё.
То есть после вызова SetStdHandle(STD_ERROR_HANDLE, ...) у тебя cerr не начнёт писать в новый файл или пайп. Причина в том, что crt уже инициализирована, и на этапе инициализации уже был вызван GetStdHandle(STD_ERROR_HANDLE), оригинальный результат которого и используется.
Чтобы использовать новый дескриптор, установленный функцией SetStdHandle, нужно заново переотрыть все потоки std::cerr, stderr, итп. То есть нужно как-то сообщить crt о том, что нужно обновить список используемых дескрипторов. А это приводит тебя к исходной проблеме — перезапустить можно только одну crt, а не все копии расположенные в других библиотеках.

Короче говоря, SetStdHandle — это не аналог dup2, это куда более слабая функция.
dup2 меняет дескриптор у всех, не спрашивая их мнения об этом.
SetStdHandle просто сохраняет новое значение, которое никак не используется до соответствующего явного вызова GetStdHandle (которое в типичной программе после старта практически никогда не происходит).

A>Думаю тогда воспользуюсь либо батников, который будет перенаправлять вывод в файл, либо через pipe.

+1 за pipe.
Вообще, чтобы универсально перехватывать и модифицировать весь вывод в stderr, std::cerr итп, нужно чтобы уже на старте программы весь вывод был перенаправлен в необходимое место. Ведь только в этом случае все crt будут проинициализированы нужными значениями. Поэтому придётся либо написать код, который запускается сразу же при старте процесса и перед всеми инициализациями библиотек, либо перенаправить вывод ещё до старта процесса — то есть из командной оболочки (и скриптов) или из специальной программы.
В последнем случае этой программой конечно же может выступать и оригинальная копия. Так можно создать pipe и запустить себя же, но перенаправив весть вывод STD_ERROR_HANDLE в один конец пайпа, одновременно с этим передав другой конец в дочернюю копию через механизм наследования дескприторов. Тогда всё, что попадёт в stderr, можно будет достать из другого конца пайпа. Новый процесс при этом выполняет всё работу, а старый процесс для работы уже не нужен, и может спокойно завершиться (или наоборот подождать завершения дочернего процесса, если нужно вернуть, скажем, корректный код возврата).
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.