Programming Tips - Win32: Run command with no window and read stdout

Date: 2021mar28 OS: Windows Platform: win32 Language: C/C++ Q. Win32: Run command with no window and read stdout A. To have no window (DOS box) you need to use CreateProcess(). To read its stdout you need to use some flags and a pipe.
static BOOL ReadLine(const HANDLE h, LPSTR line, const size_t sizeLine) { char buf[2]; char c; DWORD bytesRead; char *pLine = line; line[0] = '\0'; for(;;) { if (!ReadFile(h, buf, 1, &bytesRead, NULL)) return FALSE; c = buf[0]; if (c == '\r') continue; if (c == '\n') return TRUE; *pLine++ = c; *pLine = '\0'; } } static void ReadAndParseStdout(const HANDLE h) { char line[5 * 1024]; for(;;) { if (!ReadLine(h, line, sizeof(line))) break; // Do something with line } } BOOL RunCommandExample() { STARTUPINFO si = { 0 }; PROCESS_INFORMATION pi = { 0 }; SECURITY_ATTRIBUTES saAttr = { 0 }; saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; // Create a pipe for the child process's STDOUT HANDLE hChildStd_OUT_Rd, hChildStd_OUT_Wr; if (!CreatePipe(&hChildStd_OUT_Rd, &hChildStd_OUT_Wr, &saAttr, 0)) { DWORD dwError = GetLastError(); return FALSE; } // Ensure the read handle to the pipe for STDOUT is not inherited if (!SetHandleInformation(hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)) { DWORD dwError = GetLastError(); return FALSE; } si.cb = sizeof(si); si.hStdError = NULL; si.hStdOutput = hChildStd_OUT_Wr; si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; si.wShowWindow = SW_HIDE; // This is a command that makes a few lines of stdout. // (Try running it yourself) LPCSTR cmd = "sc query TimeBroker"; // Start the child process. const BOOL bResult = CreateProcessA(NULL, // No module name (use command line) cmd, // Command line NULL, // Process handle not inheritable NULL, // Thread handle not inheritable TRUE, // Set handle inheritance 0, // No creation flags NULL, // Use parent's environment block NULL, // Use parent's starting directory &si, // Pointer to STARTUPINFO structure &pi); // Pointer to PROCESS_INFORMATION structure if (!bResult) { DWORD dwError = GetLastError(); return FALSE; } WaitForSingleObject(pi.hProcess, 5000); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); CloseHandle(hChildStd_OUT_Wr); // We need to do this now to cause a normal EOF when reading hChildStd_OUT_Rd ReadAndParseStdout(hChildStd_OUT_Rd, files); CloseHandle(hChildStd_OUT_Rd); return TRUE; }