Last active
August 8, 2022 07:31
-
-
Save Dich0tomy/53b40f174ed68b595c928977b02d66af to your computer and use it in GitHub Desktop.
CreateProcess with pipes, reading from process stdout.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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