Writing to a process STDIN via Windows pipes

c++, pipe, process, windows

Solution

The code is behaving as expected. There are a number of things you seem to be misunderstanding:

1) You need to send an ENTER ("\n") at the end of a command if you want cmd.exe to run it. Usually it is preferable to specify the command you want to run in CreateProcess, e.g., you could specify "cmd /c notepad" as the command line instead of just "cmd".

2) You've attached your pipes to the standard input and output of the cmd.exe process, so of course you see output from that process. If you don't want to see output from cmd.exe, don't run it; run the application you want directly, e.g., you could specify "notepad" as the command line to run.

3) When reading from a pipe, ReadFile only returns a single block of data at a time, so you need to call it in a loop.

4) Notepad is a GUI process, so it doesn't use stdin or stdout anyway. Presumably this was just a poorly chosen example and you actually want to run a command-line application?

5) Except as specifically documented, the error code (as returned by GetLastError) is only meaningful when a function has failed. None of the functions you are using are exceptions to this case, so there is no point in checking the error code unless the function returns zero to indicate that it has failed.

Problem

I am trying to create a function that will spawn an instance of a program and then pipe some data into its STDIN and then read the process's output using C++. I have looked at an MSDN example located here which is rather confusing to me and when I try to use the example, I get some nasty error codes and it won't work. ``` 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); ``` The code fails to pipe the string "notepad" into cmd.exe but is successful in launching the command shell. If I look in task manager, there are several instances of command prompt spawned but no notepads. In addition, the `ReadFile()` function is the only one that seemed to have worked, but it's not even reading from the piped process (notepad that was supposed to be spawned) instead, it's reading from CMD. And even worse, it's truncating everything but the first line that it reads! (CMD prints the "Microsoft Windows....\n Copyright...\n C:\Users\Foo>...\n" but the `ReadFile() only grabs the first line)

Original source