I have a third-party dll that I can't change and sends its output, at irregular intervals, to stdout. I would like to capture the stdout and display it in a TMemo control. A previous answer (Delphi - Capture stdout and stderr output from statically linked MSVC++ compiled DLL) shows how to capture such output to a file, I'd like to capture it to a TMemo.
Possible solution: I could read the file as it fills up with output from stdout and polling the file but I'd need to identify the new output from the previously saved output. PLus it doesn't seem like a real solution. I've done a lot of internet searching and most common related answer I've found is how to capture stdout from an external application, that's not what I want to do, I want to capture output from a dll. There is also this code fragment, but I didn't really understand what it was doing or how to use it - http://embarcadero.newsgroups.archived.at/public.delphi.language.delphi.win32/201010/10101510449.html but it seems like its solving the same problem. Has anyone found anything related to this topic in their internet travels?
I have something working based on Pipes, wasn't as difficult as I thought but there is stil one thing that troubles me. Here is the code:
var
TextBuffer: array[1..32767] of AnsiChar;
TextString: AnsiString;
BytesRead, BytesRem: cardinal;
PipeSize: cardinal;
Security : TSecurityAttributes;
begin
Security.nlength := SizeOf(TSecurityAttributes) ;
Security.binherithandle := true;
Security.lpsecuritydescriptor := nil;
if CreatePipe(outputPipeRead, outputPipeWrite, @Security, 0) then
begin
SetStdHandle(STD_OUTPUT_HANDLE, outputPipeWrite);
end
else
showmessage ('Error in creating pipe');
.... Call dll here so that it sends output to stdout
PipeSize := Sizeof (textbuffer);
PeekNamedPipe (outputPipeRead, nil, PipeSize, @BytesRead, @PipeSize, @BytesRem);
if BytesRead > 0 then
begin
if ReadFile(outputPipeRead, TextBuffer, PipeSize, BytesRead, nil) then
begin
// a requirement for Windows OS system components
OemToChar(@TextBuffer, @TextBuffer);
TextString := AnsiString(TextBuffer);
SetLength(TextString, BytesRead);
mOutput.Lines.Add (TextString);
end;
end
else
showmessage ('No text');
This does capture the output and deposit it in the TMemo, but what I don't understand is why (after much trial and error), setstdhandle assigns the outputPipeWrite to stdout but reading the pipe is via outputPipeRead? Inspiration for this code came from http://www.tek-tips.com/faqs.cfm?fid=7402
As I explained in comments, the way to solve this is to create a pipe. Arrange that the write end of the pipe is attached to the standard output with a call to SetStdHandle
. And read from the read end of the pipe and put that content into the memo.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With