这是关于启动子进程和重定向输出。
在.NET中,我们可以使用Process.RedirectStandard ...重定向标准IO,并使用Process.OutputDataReceived接收事件写入输出时的事件。
我想用Win32 API在本机C ++中实现它。
当我查看源代码(1,2)时,看起来它正在使用Stream.BeginRead方法,但我无法找到如何实现此方法。
我认为它是通过创建一个新线程(或.NET中的一个任务)来使用忙等待,但如果是这样,我想知道它 Sleep s per loop(因为Sleep(0)会提升我的cpu风扇)。
以下是我假设它看起来如何的代码:
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)
请原谅我可怜的英语。