Skip to content

Instantly share code, notes, and snippets.

@Dich0tomy
Last active August 8, 2022 07:31
Show Gist options
  • Save Dich0tomy/53b40f174ed68b595c928977b02d66af to your computer and use it in GitHub Desktop.
Save Dich0tomy/53b40f174ed68b595c928977b02d66af to your computer and use it in GitHub Desktop.
CreateProcess with pipes, reading from process stdout.
#include <Windows.h>
#include <algorithm>
#include <iostream>
#include <vector>
#include <array>
auto main(int argc, char** argv) -> int {
using pipe_handle = void*;
auto stdout_read = pipe_handle(); // not needed
auto stdout_write = pipe_handle(); // neede to obtain stdout of the child process
auto security_attrs = SECURITY_ATTRIBUTES {
.nLength = sizeof(SECURITY_ATTRIBUTES), // needed for god knows for
.lpSecurityDescriptor = nullptr, // default security options
.bInheritHandle = TRUE // child processes inherit this handle
};
CreatePipe(
&stdout_read,
&stdout_write,
&security_attrs,
0 // default buffer size for a pipe
);
SetHandleInformation(stdout_read, HANDLE_FLAG_INHERIT, 0); // child processes inherit the handle
auto start_info = STARTUPINFO {
.cb = sizeof(STARTUPINFOA), // needed for god knows for
.dwFlags = STARTF_USESTDHANDLES, // uses the pipe handles passed to it
.hStdOutput = stdout_write
// there's also stderr and stdin if you want to read/write from/to them
};
auto proc_info = PROCESS_INFORMATION();
const auto exe_name = TEXT("C://Windows//System32//cmd.exe");
#ifdef UNICODE
auto args = const_cast<wchar_t*>(LR"(/c "dir")"); // needed because CreateProcess needs char*
#else
auto args = const_cast<char*>(R"(/c "dir")");
#endif
CreateProcess(
exe_name, // executable name relative to the parent path, ignores env
args, // arguments in a string form
nullptr, // security attributes for the child process
nullptr, // security attributes for the child process' thread
TRUE, // should the process inherit the handles, yes you have to set this information in 123123 places for some reason
0, // idk some flags
nullptr, // the child process uses the parent processes enviroment variables
nullptr, // the child process uses the parent processes current directory
&start_info,
&proc_info // proc_info receives the information about the new process, out argument
);
CloseHandle(stdout_write); // closing it sothat it doesn't block while using ReadFile; not needed
std::cout << "Child process PID and TID: " << proc_info.dwProcessId << ", " << proc_info.dwThreadId << "\n\n";
// reading from the process
auto output = std::vector<char>(4096);
auto bytes_read = DWORD(0);
while(true) {
auto bytes_avaiable = DWORD(0);
const auto success =
ReadFile(
stdout_read, // device handle, here a pipe
output.data() + bytes_read, // pointer to the buffer
4096 - bytes_read, // buffer size
&bytes_avaiable, // the number of bytes read, out argument
nullptr // not needed
);
if((not success) or (bytes_avaiable == 0)) break;
bytes_read += bytes_avaiable;
std::cout << "Bytes read: " << bytes_avaiable << '\n';
}
std::cout << "The whole process output (" << bytes_read << " total bytes read)" << ": \n[\n";
std::ranges::copy(output, std::ostream_iterator<char>(std::cout));
std::cout << "]\n";
WaitForSingleObject(proc_info.hProcess, INFINITY); // waits till the child process exits
CloseHandle(stdout_read); // closes the handle
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment