如何将DLL中的stdout重定向到TMemo

时间:2014-05-04 21:44:50

标签: delphi

我有一个第三方dll,我无法更改并以不规则的间隔将其输出发送到stdout。我想捕获标准输出并将其显示在TMemo控件中。之前的答案(Delphi - Capture stdout and stderr output from statically linked MSVC++ compiled DLL)显示了如何将此类输出捕获到文件中,我想将其捕获到TMemo。

可能的解决方案:我可以读取文件,因为它填满了stdout的输出并轮询了文件,但是我需要从先前保存的输出中识别新输出。 PLus它似乎不是一个真正的解决方案。我已经做了很多互联网搜索,我发现最常见的相关答案是如何从外部应用程序捕获stdout,这不是我想要做的,我想从dll捕获输出。还有这个代码片段,但我真的不明白它在做什么或如何使用它 - http://embarcadero.newsgroups.archived.at/public.delphi.language.delphi.win32/201010/10101510449.html但似乎它解决了同样的问题。有没有人在他们的网上旅行中找​​到与此主题相关的任何内容?

我有一些基于Pipes工作的东西,并不像我想象的那么困难,但有一件事让我烦恼。这是代码:

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');

这会捕获输出并将其存放在TMemo中,但我不明白为什么(经过多次试验和错误)后,setstdhandle将outputPipeWrite分配给stdout但是通过outputPipeRead读取管道?此代码的灵感来自http://www.tek-tips.com/faqs.cfm?fid=7402

1 个答案:

答案 0 :(得分:2)

正如我在评论中解释的那样,解决这个问题的方法是创建一个管道。安排管道的写入端通过调用SetStdHandle附加到标准输出。并从管道的读取端读取并将该内容放入备忘录中。