Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to redirect stdout in a DLL to a TMemo

Tags:

delphi

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

like image 999
rhody Avatar asked Nov 02 '22 00:11

rhody


1 Answers

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.

like image 179
David Heffernan Avatar answered Nov 15 '22 05:11

David Heffernan