Перенаправление стандартного вывода в win32 не перенаправляет стандартный вывод - PullRequest
0 голосов
/ 08 января 2019

Я пытаюсь перенаправить стандартный вывод, чтобы printf в приложении Windows перешел к файлу по моему выбору.

Я делаю это:

outFile = fopen("log.txt", "w");
*stdout = *outFile;
setvbuf(stdout, NULL, _IONBF, 0);

но printf по-прежнему пишет в консоль (или нигде в приложении win32 на основе графического интерфейса)

Я могу перенаправить 'std :: cout', выполнив это:

outFileStr = std::ofstream(outFile);         
std::cout.rdbuf(outFileStr.rdbuf());

Но printf, похоже, делает свое дело. К сожалению, мне нужно перенаправить printf, поскольку я пытаюсь интегрировать python в платформу C ++, и это, кажется, полагается на printf, а не на std :: cout.

std :: cout ', кажется, перенаправлен, но не printf.

1 Ответ

0 голосов
/ 08 января 2019

Перенаправление стандартного ввода-вывода в Windows немного сложнее из-за отсутствия надлежащего интерфейса для сопоставления произвольных дескрипторов файлов Win32 и файловых дескрипторов / потоков более высокого уровня.

На самом деле в Windows есть три разных уровня ввода / вывода:

  1. Стандартный? Потоки ввода / вывода C (они используются printf, scanf, ...)
  2. дескрипторы ввода / вывода POSIX (это целые числа, используемые read, write, ...)
  3. дескрипторы ввода / вывода Win32 API (используются ReadFile, WriteFile, ...)

Перенаправление потоков C

Для перенаправления потоков C вы можете использовать freopen. Например, вы можете перенаправить C stdout, используя:

freopen("log.txt", "w", stdout);

Это перенаправление обычно не перенаправляет ввод / вывод, выполняемый API POSIX или Win32 (они все равно будут читать / записывать присоединенную консоль, если таковая имеется). Кроме того, это перенаправление не будет наследоваться дочерними процессами. (В POSIX-совместимых / не-Windows системах обычно POSIX API также является системным API, а C API реализован поверх POSIX API. В этих случаях достаточно freopen.)

Перенаправление дескрипторов ввода / вывода POSIX

Чтобы перенаправить ввод / вывод на уровне API POSIX, вы можете использовать dup2. Например, вы можете переназначить дескриптор файла STDOUT_FILENO для перенаправления stdout, что-то вроде:

int fd = open("log.txt", O_WRONLY);
dup2(fd, STDOUT_FILENO);
close(fd);

К сожалению, в Windows даже перенаправление на уровне API POSIX не гарантирует перенаправление ни на уровне C, ни на уровне Win32 API . Будет ли это работать или нет, зависит от усилий, приложенных в реализации библиотеки C для сопоставления между дескрипторами файлов POSIX и дескрипторами файлов Win32 (при условии, что библиотека времени выполнения C использует слоистый ввод-вывод поверх POSIX для начала) , Также нет гарантии, что это перенаправление будет унаследовано порожденными детьми.

Перенаправление ввода-вывода Std в Windows!

Чтобы правильно перенаправить ввод / вывод в Windows, вы должны перенаправить на самый низкий уровень (т. Е. Уровень Win32 API) и исправить связь на более высоких уровнях следующим образом:

  1. Назначьте новый дескриптор, позвонив по номеру CreateFile.
  2. Назначьте этот новый дескриптор нужному стандартному устройству ввода-вывода, используя SetStdHandle.
  3. Свяжите этот новый дескриптор с соответствующим дескриптором файла C std, используя _open_osfhandle (возвращает номер дескриптора файла).
  4. Перенаправить возвращенный дескриптор файла, используя метод dup2, описанный выше.

Вот пример фрагмента для перенаправления stdout:

HANDLE new_stdout = CreateFileA("log.txt", ...);
SetStdHandle(STD_OUTPUT_HANDLE, new_stdout);
int fd = _open_osfhandle(new_stdout, O_WRONLY|O_TEXT);
dup2(fd, STDOUT_FILENO);
close(fd);

P.S. Если вы можете обойтись без перенаправления ввода-вывода внутри программы, то вы можете просто использовать перенаправление консоли ввода-вывода в командной строке, используя крошечный пакетный файл:

@echo off
start "my_gui_app" "path/to/my_gui_app.exe" 1> "path/to/log.txt"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...