Launching the compiler with CreateProcess but directing its output to a buffer

Hi all.

I'm trying to make a program that launches the compiler and present its information (and later, some useful information on the errors) to the user in a pretty way. The first step would be to have a solution similar to 4coder's: The user presses a button and a program is compiled and the compilation information is displayed on the main program.

Based on the day 192's self-recompiling code, I could easily launch a process and compile a program using CreateProcess:

1
CreateProcess(command, command_line, 0, 0, FALSE, 0, 0, path, &startup_info, &process_info);


After some research I could direct the process' output to a file handle using the hStdOutput member of the STARTUPINFO struct.
Here are the most important points of the code.

1
HANDLE h = CreateFile("out.log", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, &sa, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );

1
2
3
4
5
si.cb = sizeof(STARTUPINFO); 
si.dwFlags |= STARTF_USESTDHANDLES;
si.hStdInput = NULL;
si.hStdError = h;
si.hStdOutput = h;


However, the objective is to interactively show the result like 4coder, so I would have to have it in a char buffer or something. Yeah, I could read the file but that seems really janky and slow.

Is there any way to capture the output of the child's process in a memory buffer of some sort so that I could display and analyze it however I want? It seems there are a lot of programs that do this, what is the best way to achieve it?

Thank you (and have a happy 2019) :),
Dan Zaidan

Edited by Dan Zaidan on Reason: Initial post
You do that with pipes. Call CreatePipe which will give you two handles - one for writing into pipe, and one for reading pipe. Pass writeable pipe to CreateProcess, same as file handle. It will start writing into this pipe. Then you can use other, readable pipe to read data from process. You can do either blocking read to read everything it has, or read it incrementally - whenever there is some data to read (useful if embedding in some other game/event-loop).

MSDN has example for this here: https://docs.microsoft.com/en-us/...-with-redirected-input-and-output
Thanks so much!
As always, you came to the rescue. :)

Have a great new year!
Oh, I remembered I wrote this some time ago: https://gist.github.com/mmozeiko/b4e55a25aeb291ddd9bca1d8d228ea95
Don't remember exact reason why I wrote it, but I think it is cleaner example than one in MSDN. My code does a bit more than you need, just ignore pats for hooking & dll injection. This example separates reading stdout from stderr and also does overlapped reading in a loop suitable for embedding into other game/event - loop (just change INFINITE timeout to 0 for WaitForMultipleObjects).

Edited by Mārtiņš Možeiko on
That was super helpful! Thanks a lot! :D

I got it working nicely! :)
I ended up doing that in a separate thread because I could easily do an async display of the info to the user.

I have one question regarding your code:

1
wsprintfA(name, "\\\\.\\Pipe\\WhateverUniqueName.%08x.%08x", GetCurrentProcessId(), id++);


Is that an actual location that files get written to, or is it just something random to make CreateNamedPipeA and CreateFileA happy?

And another functionality problem: Is it possible to make it display both in the console CreateProcess pops up and in the handle I pass to it?

Thanks!
It is something to make CreateNamedPipe happy. Check its MSDN doc, it says that pipe name must be in this format. No idea if it will work with other name format.

I believe that it is not possible to have output on captured handle and actual console at the same time. If you are redirecting program output it won't get to actual console on screen.