сломанная труба в win32 (WinAPI) - PullRequest
1 голос
/ 26 января 2011

Я следовал примеру здесь для чтения из канала, но ReadFile завершается ошибкой, и GetLastError () показывает мне, что канал сломан.
Я создал и успешно использовал канал ранее в программе, но я закрыл все дескрипторы и использовал совершенно новые переменные для нового канала, просто чтобы быть уверенным.
Есть идеи, почему это не работает?

HANDLE g_hChildStd_OUT_Rd2 = NULL;
HANDLE g_hChildStd_OUT_Wr2 = NULL;
SECURITY_ATTRIBUTES saAttr2; 
STARTUPINFO si2;
PROCESS_INFORMATION pi2;

ZeroMemory( &si2, sizeof(si2) );
si2.cb = sizeof(si2);
ZeroMemory( &pi2, sizeof(pi2) );
//create pipe
saAttr2.nLength = sizeof(SECURITY_ATTRIBUTES); 
saAttr2.bInheritHandle = TRUE; 
saAttr2.lpSecurityDescriptor = NULL; 
CreatePipe(&g_hChildStd_OUT_Rd2, &g_hChildStd_OUT_Wr2, &saAttr2, 0);
//create child process
bSuccess = FALSE;
memset(szCmdLine, 0, MAX_PATH);
sprintf(szCmdLine, "ffmpeg.exe -i output.mp3");
ZeroMemory( &pi2, sizeof(PROCESS_INFORMATION) );
ZeroMemory( &si2, sizeof(STARTUPINFO) );
si2.cb = sizeof(STARTUPINFO); 
si2.hStdOutput = g_hChildStd_OUT_Wr2;
si2.dwFlags |= STARTF_USESTDHANDLES;
CreateProcess(NULL, szCmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si2, &pi2);
//read from pipe
CloseHandle(g_hChildStd_OUT_Wr2);
memset(chBuf, 0, BUFSIZE);
for (;;) 
{ 
  bSuccess = ReadFile( g_hChildStd_OUT_Rd2, chBuf, BUFSIZE, &dwRead, NULL);
  [bSuccess is 0 and GetLastError() returns error 109]
  ........

1 Ответ

3 голосов
/ 29 июня 2011

«Разбитая труба» - нормальная ошибка, когда другой конец закрывает трубу. В вашем случае это либо означает, что «другого конца» нет, либо другое приложение ничего не записало в stdout. Я изменил ваш код, чтобы он был скомпилированным тестовым примером - есть два случая, в которых ReadFile завершается неудачно, не прочитав для меня никаких данных:

  • CreateProcess не удалось. Я добавил assert, чтобы эта проблема была узнаваемой. Это, конечно, приведет к поломке трубы.
  • Процесс ничего не записывает в стандартный вывод. Вместо этого он может записать в свой стандартный поток ошибок. Я также перенаправил stderr на канал, и, как показывает мой пример echo, теперь он получит оба потока на другом конце канала.

Код:

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>

#define BUFSIZE 200

int main(void)
{
    BOOL bSuccess;
    char szCmdLine[MAX_PATH];
    char chBuf[BUFSIZE];
    DWORD dwRead;
    HANDLE g_hChildStd_OUT_Rd2 = NULL;
    HANDLE g_hChildStd_OUT_Wr2 = NULL;
    SECURITY_ATTRIBUTES saAttr2; 
    STARTUPINFO si2;
    PROCESS_INFORMATION pi2;

    ZeroMemory( &si2, sizeof(si2) );
    si2.cb = sizeof(si2);
    ZeroMemory( &pi2, sizeof(pi2) );
    //create pipe
    saAttr2.nLength = sizeof(SECURITY_ATTRIBUTES); 
    saAttr2.bInheritHandle = TRUE; 
    saAttr2.lpSecurityDescriptor = NULL; 
    assert(CreatePipe(&g_hChildStd_OUT_Rd2, &g_hChildStd_OUT_Wr2, &saAttr2, 0));
    //create child process
    bSuccess = FALSE;
    memset(szCmdLine, 0, MAX_PATH);
    sprintf(szCmdLine, "cmd /c echo output && echo error>&2");
    ZeroMemory( &pi2, sizeof(PROCESS_INFORMATION) );
    ZeroMemory( &si2, sizeof(STARTUPINFO) );
    si2.cb = sizeof(STARTUPINFO); 
    si2.hStdOutput = g_hChildStd_OUT_Wr2;
    si2.hStdError = g_hChildStd_OUT_Wr2; // also add the pipe as stderr!
    si2.dwFlags |= STARTF_USESTDHANDLES;
    assert(CreateProcess(NULL, szCmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si2, &pi2));
    //read from pipe
    CloseHandle(g_hChildStd_OUT_Wr2);
    memset(chBuf, 0, BUFSIZE);
    for (;;) 
    { 
        bSuccess = ReadFile( g_hChildStd_OUT_Rd2, chBuf, BUFSIZE, &dwRead, NULL);
        printf("%d %lu 0x%08lx\n", bSuccess, dwRead, GetLastError());
        if (bSuccess)
            printf("\t'%*s'\n", (int)dwRead, chBuf);
        else
            break;
    }
    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...