1

I am using CreateProcess() to run cmd.exe (without the physical window showing to the user) and need to process the output. I have decided to use CreatePipe() for this purpose.

I am currently having an issue whereby all of my output is being read and processed, but the final call to ReadFile() is hanging. Searching around has told me that I need to close the write side of the pipe before reading, and that this is a solution to this problem, but I have already done this and still have the problem.

Here is my code:

// sw -> path to cmd.exe, ptr is the command
ok = CreateProcess(sw, ptr, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &StartupInfo, &ProcessInfo);
CloseHandle(hStdInPipeRead);
char buf[1024 + 1] = {};
DWORD dwRead = 0;
DWORD dwAvailable = 0;
DWORD testRes;
CloseHandle(hStdOutPipeWrite);
ok = ReadFile(hStdOutPipeRead, buf, 1024, &dwRead, NULL);
// String handling for initial read omitted for clarity
string temp = buf;
bool holdOff = false;

while (ok == TRUE)
{
    buf[dwRead] = '\0';
    OutputDebugStringA(buf);
    puts(buf);
    // ReadFile gets all the correct output from cmd here but it also hangs on the very last call. How to fix?
    ok = ReadFile(hStdOutPipeRead, buf, 1024, &dwRead, NULL);
    temp = buf;
    // handle and store output
    break;
}
CloseHandle(hStdOutPipeRead);
CloseHandle(hStdInPipeWrite);
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
ace1eric
  • 11
  • 2
  • Without `sw` and `ptr` values it is hard to deduce what `cmd` does. Your pipe is valid until `cmd` exits. – Daniel Sęk Apr 23 '19 at 13:30
  • for what you create 2 pipe pair (4 handles) instead 1 pair (2 handles) ? and use asynchronous pipe end from self side – RbMm Apr 23 '19 at 15:55
  • You didn't show the code that sets up the pipe or the CreateProcess parameters. Please provide a [mcve]. – Remy Lebeau Apr 23 '19 at 16:20
  • @RemyLebeau - can assume that this is in general copy-paste from https://stackoverflow.com/a/55718264/6401656 – RbMm Apr 23 '19 at 16:24
  • 1
    and need understand - readfile fail (with `ERROR_BROKEN_PIPE`) only when **all** handles for other end will be closed. because this you need close `hStdOutPipeWrite` and it duplicated handle will be closed when *cmd* exit. so *cmd* not exit in your case – RbMm Apr 23 '19 at 16:37

1 Answers1

-1

The child process will inherit the handle of pipe if you set SECURITY_ATTRIBUTES.bInheritHandle = true, the write handle of the pipe you closed is only the parent's, there is still a handle in child process(stdout of child), and it hasn't been closed in cihld process, Readfile fails and returns only when all write handles are closed or errors occur.

In addition, Anonymous Pipe Operations.

Asynchronous (overlapped) read and write operations are not supported by anonymous pipes(Create by CreatePipe).

So, If you still need to send command to child process to execute cmd, you should put ReadFile in a thread. And if you don't need any more, terminate child process:

TerminateProcess(ProcessInfo.hProcess,0);
WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
ok = ReadFile(hStdOutPipeRead, buf, 1024, &dwRead, NULL);
// String handling for initial read omitted for clarity
string temp = buf;
bool holdOff = false;
while (ok == TRUE)
{
    buf[dwRead] = '\0';
    OutputDebugStringA(buf);
    puts(buf);
    // ReadFile gets all the correct output from cmd here but it also hangs on the very last call. How to fix?
    ok = ReadFile(hStdOutPipeRead, buf, 1024, &dwRead, NULL);
    temp = buf;
    // handle and store output
    break;
}
CloseHandle(hStdOutPipeRead);
CloseHandle(hStdInPipeWrite);
Drake Wu
  • 6,927
  • 1
  • 7
  • 30
  • *Asynchronous (overlapped) read and write operations are not supported by anonymous pipes.* - this is absolute false. pipes of course support Asynchronous mode. are pipe have name or it empty - not affect this. more correct be say that pipes created via concrete api `CreatePipe` was synchronous. `TerminateProcess` - of course wrong and not need call. – RbMm Apr 24 '19 at 06:49
  • This means that you cannot use the `ReadFileEx` functions with anonymous pipes. In addition, the lpOverlapped parameter of `ReadFile` is ignored when these functions are used with anonymous pipes. – Drake Wu Apr 24 '19 at 07:06
  • no, you mistake. this is possible create asyncronous anonymous pipes. simply need use not `CreatePipe` but another api. also you mistake when say that lpOverlapped parameter of ReadFile is ignored - it not ignored even for synchronous files. ReadFileEx also can be used of course, even for sync files – RbMm Apr 24 '19 at 07:10
  • so all what you say mistake: 1. lpOverlapped parameter of ReadFile **never** ignored. for any file mode. 2 `ReadFileEx ` can be used always, even for syncronous files. 3.anonymous pipes not some special pipe type - exist only pipes and all. which name have pipe (empty name as special case) - this not affect synchronous or asynchronous io mode – RbMm Apr 24 '19 at 07:17
  • about `ReadFileEx` - it can not be used only for files which is binded to iocp port, because apc proc and iocp mutually exclusive – RbMm Apr 24 '19 at 07:21
  • Got it! Indeed, the description in the MSDN document is not rigorous enough. Asyncronous anonymous pipe can be create by creating such as Name pipe. – Drake Wu Apr 24 '19 at 07:27
  • yes, near true. really before win7 anonymous pipes - was pipes with name format `"\\Device\\NamedPipe\\Win32Pipes.%08x.%08x"`. begin from win7 exist solution how create true unnamed pipes, but need use native api here. no win32 solution – RbMm Apr 24 '19 at 07:31
  • For TerminateProcess(), I guess op is simulating CMD console, and he didn't use the command like `cmd.exe -c ***` or `cmd.exe -k ***`, it may just open `cmd.exe`, then write command to the pipe. The child process did not exit any more. So if don't need, he can terminate it. – Drake Wu Apr 24 '19 at 07:32
  • instead terminate process we need say write `exit\r\n` command to pipe. also exist one point - we not need have 2 pipe pairs (4 handles). enough only 1 pipe pair (2 handles). unfortunatelly example on msdn use 2 pair. and almost all copy-paste this bad code. – RbMm Apr 24 '19 at 07:35
  • I thought about this. But `ReadFile` May get the string "exit\r\n"? – Drake Wu Apr 24 '19 at 07:44