This is about launching a child process and redirecting output.
In .NET, we could use Process.RedirectStandard... to redirect the standard IO, and use Process.OutputDataReceived to receive an event when something was written to the output.
I want to implement this in native C++ with Win32 API.
As I looked into the source (1, 2), it looks like it's using Stream.BeginRead method, but I couldn't find out how this method is implemented.
I assume that it's using busy-waiting by making a new thread (or a Task in .NET), but if so, I want to know how many second it Sleeps per loop (since Sleep(0) boosts my cpu fan).
Here's the code which I assume how it would look like:
HANDLE hOutputRead;
typedef void (*UserCallback)(size_t);
UserCallback OutputDataReceived;
void *Buffer;
bool exec(UserCallback callback, void *buffer /* string written to stdout */)
{
OutputDataReceived = callback;
Buffer = buffer;
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
HANDLE hOutputReadTemp, hOutputWrite;
CreatePipe(&hOutputReadTemp, &hOutputWrite, &sa, 0);
DuplicateHandle(
GetCurrentProcess(), hOutputReadTemp,
GetCurrentProcess(), hOutputRead,
0, FALSE, DUPLICATE_SAME_ACCESS
) // to prevent hOutputReadTemp from being inherited to the launched process,
// we duplicate to hOutputRead with no inheritance priviledge,
CloseHandle(hOutputReadTemp); // and close the original.
STARTUPINFO si = {};
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESTDHANDLES;
si.hStdOutput = hOutputWrite;
PROCESS_INFORMATION pi;
if (!CreateProcess(NULL, "C:\\path\\to\\child.exe", NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
return false;
CloseHandle(pi.hThread);
CloseHandle(hOutputWrite); // we won't be using this handle anymore
CreateThread(NULL, 0, CheckPipeAsync, NULL, 0, NULL);
}
DWORD WINAPI CheckPipeAsync(LPVOID lpParameter) // if anything gets written to output, call OutputDataReceived()
{
int size;
while (PeekNamedPipe(hOutputRead, NULL, NULL, NULL, &size, NULL)) // busy wait
{
if (size == 0) // nothing written
{
Sleep(TIME_TO_SLEEP_PER_LOOP);
continue;
}
DWORD bytesRead;
ReadFile(hOutputRead, Buffer, size, &bytesRead, NULL);
OutputDataReceived(size); // callback when something was written to stdout
}
return TRUE;
}
reference (How to spawn console processes with redirected standard handles)
Please pardon my poor English.