This code redirects the STDOUT of a console application to a stringlist, which you can use on a memo for example. It's Delphi code, but in C++ the basic idea is exactly the same.
I use it to run console applications hidden, while redirecting the output to my own application, to show in a pane. It adds a new line to AStrings as soon as data comes in, so you'll have access to the output of the other application before it finishes.
procedure RunConsoleApp(const CommandLine: string; AStrings: TStrings);
type
TCharBuffer = array[0..MaxInt div SizeOf(Char) - 1] of Char;
const
MaxBufSize = 1024;
var
I: Longword;
SI: TStartupInfo;
PI: TProcessInformation;
SA: PSecurityAttributes;
SD: PSECURITY_DESCRIPTOR;
NewStdIn: THandle;
NewStdOut: THandle;
ReadStdOut: THandle;
WriteStdIn: THandle;
Buffer: ^TCharBuffer;
BufferSize: Cardinal;
Last: WideString;
Str: WideString;
ExitCode_: DWORD;
Bread: DWORD;
Avail: DWORD;
begin
GetMem(SA, SizeOf(TSecurityAttributes));
case Win32Platform of
VER_PLATFORM_WIN32_NT:
begin
GetMem(SD, SizeOf(SECURITY_DESCRIPTOR));
SysUtils.Win32Check(InitializeSecurityDescriptor(SD, SECURITY_DESCRIPTOR_REVISION));
SysUtils.Win32Check(SetSecurityDescriptorDacl(SD, True, nil, False));
SA.lpSecurityDescriptor := SD;
end; {end VER_PLATFORM_WIN32_NT}
else
SA.lpSecurityDescriptor := nil;
end; {end case}
SA.nLength := SizeOf(SECURITY_ATTRIBUTES);
SA.bInheritHandle := True;
SysUtils.Win32Check(CreatePipe(NewStdIn, WriteStdIn, SA, 0));
if not CreatePipe(ReadStdOut, NewStdOut, SA, 0) then
begin
CloseHandle(NewStdIn);
CloseHandle(WriteStdIn);
SysUtils.RaiseLastWin32Error;
end; {end if}
GetStartupInfo(SI);
SI.dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
SI.wShowWindow := {SW_SHOWNORMAL} SW_HIDE;
SI.hStdOutput := NewStdOut;
SI.hStdError := NewStdOut;
SI.hStdInput := NewStdIn;
if not CreateProcess(nil, PChar(CommandLine), nil, nil, True, CREATE_NEW_CONSOLE, nil, nil, SI, PI) then
begin
CloseHandle(NewStdIn);
CloseHandle(NewStdOut);
CloseHandle(ReadStdOut);
CloseHandle(WriteStdIn);
SysUtils.RaiseLastWin32Error;
end; {end if}
Last := '';
BufferSize := MaxBufSize;
Buffer := AllocMem(BufferSize);
try
repeat
SysUtils.Win32Check(GetExitCodeProcess(PI.hProcess, ExitCode_));
PeekNamedPipe(ReadStdOut, Buffer, BufferSize, @Bread, @Avail, nil);
if (Bread <> 0) then
begin
if (BufferSize < Avail) then
begin
BufferSize := Avail;
ReallocMem(Buffer, BufferSize);
end; {end if}
FillChar(Buffer^, BufferSize, #0);
Windows.ReadFile(ReadStdOut, Buffer^, BufferSize, Bread, nil);
Str := Last;
I := 0;
while (I < Bread) do
begin
case Buffer^[I] of
#0: inc(I);
#7: begin
inc(I);
Windows.Beep(800, 50);
Str := Str + '^';
end;
#10:
begin
inc(I);
AStrings.Add(Str);
Str := '';
end; {end #10}
#13:
begin
inc(I);
if (I < Bread) and (Buffer^[I] = #10) then
inc(I);
AStrings.Add(Str);
Str := '';
end; {end #13}
else
begin
Str := Str + Buffer^[I];
inc(I);
end; {end else}
end; {end case}
end; {end while}
Last := Str;
end; {end if}
Sleep(1);
Application.ProcessMessages;
until (ExitCode_ <> STILL_ACTIVE);
if Last <> '' then
AStrings.Add(Last);
finally
FreeMem(Buffer);
end; {end try/finally}
CloseHandle(PI.hThread);
CloseHandle(PI.hProcess);
CloseHandle(NewStdIn);
CloseHandle(NewStdOut);
CloseHandle(ReadStdOut);
CloseHandle(WriteStdIn);
end; {end procedure}