Невозможно записать в канал Windows через стандартный вывод

_open_osfhandle создает дескриптор файла C из дескриптора файла Windows, а _dup может изменить существующий базовый файловый объект fd. При использовании для перенаправления stdout на CreatePipe канал ReadFile не захватывает вывод, записанный в stdout.

Следующий фрагмент кода демонстрирует суть того, что я пытаюсь сделать. Я хочу создать анонимный канал, заменив stdout, чтобы я мог читать его из дескриптора чтения.

Документация, которую мне удалось найти, указывает на то, что _open_osfhandle и _dup2 могут выполнять эту уловку, а страница документации Microsoft для dup2 специально призывает заменить fd в stdout как возможную.

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

HANDLE hread;
HANDLE hwrite;
SECURITY_ATTRIBUTES sa = { sizeof(sa),NULL,TRUE };
CreatePipe(&hread, &hwrite, &sa, 0);
int fd = _open_osfhandle(intptr_t(hwrite), _O_TEXT);
FILE *fp = _fdopen(fd, "w");
setvbuf(fp, NULL, _IONBF, 0);
_dup2(_fileno(fp), _fileno(stdout));
TCHAR buffer[64] = { 0 };
DWORD bytesRead;
//_write(fd, "_write", 6); // works
//fprintf(fp, "fprintf"); // works
printf("printf");
ReadFile(hread, buffer, sizeof(buffer), &bytesRead, NULL);

person Chris Becke    schedule 10.10.2018    source источник
comment
в чем вопрос? возможно fprintf кэшировать данные во внутреннем буфере и не вызывать WriteFile. пока вы не сбросите буфер, в пайпе не будет данных. позвонить fflush после fprintf   -  person RbMm    schedule 11.10.2018
comment
Это была моя проблема. пока не разобрался setvbuf. Конечной целью было использование _dup2 для замены fd в stdout. но это все еще не работает.   -  person Chris Becke    schedule 11.10.2018


Ответы (1)


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

Выполнение dup2 для сброса базового файла, привязанного к файловому дескриптору stdout, сбрасывает буферизацию, поэтому следующий код работает. Вызов _fdopen отбрасывается, поскольку он не нужен, и `setvbuf 'выполняется на stdout.

HANDLE hread;
HANDLE hwrite;
SECURITY_ATTRIBUTES sa = { sizeof(sa),NULL,TRUE };
CreatePipe(&hread, &hwrite, &sa, 0);
int fd = _open_osfhandle(intptr_t(hwrite), _O_TEXT);
_dup2(fd, _fileno(stdout));
setvbuf(stdout, NULL, _IONBF, 0);
TCHAR buffer[64] = { 0 };
DWORD bytesRead;
printf("printf");
ReadFile(hread, buffer, sizeof(buffer), &bytesRead, NULL);
person Chris Becke    schedule 10.10.2018