2012-04-12 142 views
3

我正在尝试创建一个函数,该函数将产生一个程序实例,然后将一些数据输入到它的STDIN中,然后使用C++读取该进程的输出。我看过一个位于here的MSDN示例,这对我来说很困惑,当我尝试使用该示例时,出现了一些令人讨厌的错误代码,它不起作用。通过Windows管道写入进程STDIN

HANDLE hWriteOUT, hReadOUT, hWriteIN, hReadIN; 
    SECURITY_ATTRIBUTES saPipe = {0}; 
    PROCESS_INFORMATION procInfo = {0}; 
    STARTUPINFO procSi; 
    DWORD dwWritten, dwRead; 
    char buf[512]; 

    saPipe.nLength = sizeof(SECURITY_ATTRIBUTES); 
    saPipe.bInheritHandle = TRUE; 
    saPipe.lpSecurityDescriptor= NULL; 
    CreatePipe(&hReadOUT, &hWriteOUT, &saPipe, 0); 
    SetHandleInformation(hReadOUT, HANDLE_FLAG_INHERIT, 0); 
    CreatePipe(&hReadIN, &hWriteIN, &saPipe, 0); 
    SetHandleInformation(hReadIN, HANDLE_FLAG_INHERIT, 0); 

    ZeroMemory(&procSi, sizeof(STARTUPINFO)); 
    procSi.cb = sizeof(STARTUPINFO); 
    procSi.hStdError = hWriteOUT; 
    procSi.hStdOutput = hWriteOUT; 
    procSi.hStdInput = hReadIN; 
    procSi.dwFlags |= STARTF_USESTDHANDLES; 

    CreateProcess(NULL, "cmd", NULL, NULL, TRUE, 0, NULL, NULL, &procSi, &procInfo); 
    //Gives me an error code of 18 but returns a 1 when a 0 indicates failure. 

    WriteFile(hWriteIN, "notepad", sizeof("notepad"), &dwWritten, NULL); 
    cout << GetLastError(); //This gives me error code 18 (ERROR_NO_MORE_FILES) 
    ReadFile(hReadOUT, buf, 512, &dwRead, NULL); 
    cout << buf; //This prints "Microsoft Windows [version 6.1.7601] 
    CloseHandle(hWriteIN); 

代码无法将字符串“记事本”传递到cmd.exe,但成功启动命令外壳程序。如果我查看任务管理器,有几个命令提示符生成的实例,但没有记事本。此外,ReadFile()函数是唯一一个似乎已经工作的函数,但它甚至不从读取管道进程(本应该生成的记事本)读取,而是从CMD读取。更糟糕的是,它会截断所有内容,只是它读取的第一行! (CMD打印“Microsoft Windows .... \ n Copyright ... \ n C:\ Users \ Foo> ... \ n”但是ReadFile()只抓取第一行)

回答

5

代码行为如预期。有一些事情你似乎误解了:如果你想让cmd.exe运行它,你需要在命令结尾处发送一个ENTER(“\ n”)。通常,最好在CreateProcess中指定要运行的命令,例如,可以将“cmd/c notepad”指定为命令行而不是“cmd”。

2)您已将管道连接到cmd.exe进程的标准输入和输出,所以当然您会看到该进程的输出。如果您不想查看cmd.exe的输出,请不要运行它;直接运行您想要的应用程序,例如,您可以指定“记事本”作为要运行的命令行。

3)从管道读取数据时,ReadFile一次只返回一个数据块,因此需要在循环中调用它。

4)记事本是一个GUI过程,所以它不会使用标准输入或标准输出。据推测,这只是一个选择不好的例子,你实际上想要运行一个命令行应用程序? 5)除特别说明外,错误代码(由GetLastError返回)仅在函数失败时才有意义。你所使用的函数都不是这种情况的例外,所以检查错误代码是没有意义的,除非函数返回0来表明它失败了。

2

我知道回答这个问题还为时尚晚,但代码中还存在其他问题。看来SetHandleInformation(hReadOUT, HANDLE_FLAG_INHERIT, 0);SetHandleInformation(hReadIN, HANDLE_FLAG_INHERIT, 0);将打破东西。我不知道为什么,但在尝试运行你的代码之后,cmd无法读取管道中的值,直到我删除这两行代码。

+0

我错过了那一个。第一次调用应该可以,但第二次调用应该是'hWINININ'而不是'hReadIN',因为'hReadIN'句柄应该被子进程继承。 – 2012-10-25 19:55:28