There are several things wrong with your code, here's a cleaned up example that works.
Changes made: Consolidated the pipe set into one array and created enums to denote which has what purpose, makes it a lot clearer than calling something "StdOutRead" and "StdOutWrite".
Created a SECURITY_ATTRIBUTES structure to let us set up the pipes for inheritance, and added code to prevent the parent-side halves of the pipes being inherited.
Removed the STARTF_USESTDHANDLES flag from the process.
Specified a directory for the process to perform it's DIR on.
Ensured that we close all the handles we're not using once the process is started in the parent.
Lastly, I made it drain the file of io in chunks and append the null terminator to the end of a successful buffer so that it can output properly.
#define WINDOWS_LEAN_AND_MEAN
#include <Windows.h>
#include <tchar.h>
#include <iostream>
#include <thread>
#include <cassert>
enum { ParentRead, ParentWrite, ChildWrite, ChildRead, NumPipeTypes };
int main(int /*argc*/, char* /*argv*/[])
{
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = nullptr;
HANDLE pipes[NumPipeTypes];
if (!CreatePipe(&pipes[ParentWrite], &pipes[ChildRead], &sa, 0))
return 0;
if (!CreatePipe(&pipes[ParentRead], &pipes[ChildWrite], &sa, 0))
return 0;
// make sure the handles the parent will use aren't inherited.
SetHandleInformation(pipes[ParentRead], HANDLE_FLAG_INHERIT, 0);
SetHandleInformation(pipes[ParentWrite], HANDLE_FLAG_INHERIT, 0);
STARTUPINFO si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.wShowWindow = SW_SHOW;
si.dwFlags = STARTF_USESHOWWINDOW;
si.hStdOutput = pipes[ChildWrite];
si.hStdError = pipes[ChildWrite];
si.hStdInput = pipes[ChildRead];
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
TCHAR cmd[] = _T("C:\\Windows\\System32\\cmd.exe /c dir c:\\");
if (!CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
return 0;
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(pipes[ChildRead]);
CloseHandle(pipes[ChildWrite]);
CloseHandle(pipes[ParentWrite]);
char ReadBuff[4096 + 1];
DWORD ReadNum;
for (;;) {
auto success = ReadFile(pipes[ParentRead], ReadBuff, sizeof(ReadBuff) - 1, &ReadNum, NULL);
if (!success || !ReadNum)
break;
ReadBuff[ReadNum] = 0;
std::cout << ReadBuff;
}
//system("pause"); use Ctrl+F5 or Debug >> Start Without debugging instead.
return 0;
}