Sources
Delphi Russian Knowledge Base
DRKB - это самая большая и удобная в использовании база знаний по Дельфи в рунете, составленная Виталием Невзоровым

Как вывести результат работы консоли в TMemo?

01.01.2007

Код взят из https://www.torry.net/memos.htm

procedure Dos2Win(CmdLine:String; OutMemo:TMemo);
const BUFSIZE = 2000;
var SecAttr    : TSecurityAttributes;
    hReadPipe,
    hWritePipe : THandle;
    StartupInfo: TStartUpInfo;
    ProcessInfo: TProcessInformation;
    Buffer     : Pchar;
    WaitReason,
    BytesRead  : DWord;
begin
 
 with SecAttr do
 begin
   nlength              := SizeOf(TSecurityAttributes);
   binherithandle       := true;
   lpsecuritydescriptor := nil;
 end;
 // Creazione della pipe
 if Createpipe (hReadPipe, hWritePipe, @SecAttr, 0) then
 begin
   Buffer  := AllocMem(BUFSIZE + 1);    // Allochiamo un buffer di dimensioni BUFSIZE+1
   FillChar(StartupInfo, Sizeof(StartupInfo), #0);
   StartupInfo.cb          := SizeOf(StartupInfo);
   StartupInfo.hStdOutput  := hWritePipe;
   StartupInfo.hStdInput   := hReadPipe;
   StartupInfo.dwFlags     := STARTF_USESTDHANDLES +
                              STARTF_USESHOWWINDOW;
   StartupInfo.wShowWindow := SW_HIDE;
 
   if CreateProcess(nil,
      PChar(CmdLine),
      @SecAttr,
      @SecAttr,
      true,
      NORMAL_PRIORITY_CLASS,
      nil,
      nil,
      StartupInfo,
      ProcessInfo) then
     begin
       // Attendiamo la fine dell'esecuzione del processo
       repeat
         WaitReason := WaitForSingleObject( ProcessInfo.hProcess,100);
         Application.ProcessMessages;
       until (WaitReason <> WAIT_TIMEOUT);
       // Leggiamo la pipe
       Repeat
         BytesRead := 0;
         // Leggiamo "BUFSIZE" bytes dalla pipe
         ReadFile(hReadPipe, Buffer[0], BUFSIZE, BytesRead, nil);
         // Convertiamo in una stringa "\0 terminated"
         Buffer[BytesRead]:= #0;
         // Convertiamo i caratteri da DOS ad ANSI
         OemToAnsi(Buffer,Buffer);
         // Scriviamo nell' "OutMemo" l'output ricevuto tramite pipe
         OutMemo.Text := OutMemo.text + String(Buffer);
       until (BytesRead < BUFSIZE);
     end;
   FreeMem(Buffer);
   CloseHandle(ProcessInfo.hProcess);
   CloseHandle(ProcessInfo.hThread);
   CloseHandle(hReadPipe);
   CloseHandle(hWritePipe);
 end;
end;

Взято с Vingrad.ru https://forum.vingrad.ru


А это исправленный Song'ом вариант для обеспечения вывода текста в real-time:

procedure RunDosInMemo(CmdLine:String;AMemo:TMemo); 
 const 
   ReadBuffer = 2400; 
 var 
  Security       : TSecurityAttributes; 
  ReadPipe,WritePipe  : THandle; 
  start        : TStartUpInfo; 
  ProcessInfo     : TProcessInformation; 
  Buffer        : Pchar; 
  BytesRead      : DWord; 
  Apprunning      : DWord; 
 begin 
  Screen.Cursor:=CrHourGlass; 
  Form1.Button1.Enabled:=False; 
  With Security do begin 
  nlength        := SizeOf(TSecurityAttributes); 
  binherithandle    := true; 
  lpsecuritydescriptor := nil; 
  end; 
  if Createpipe (ReadPipe, WritePipe, 
         @Security, 0) then begin 
  Buffer  := AllocMem(ReadBuffer + 1); 
  FillChar(Start,Sizeof(Start),#0); 
  start.cb      := SizeOf(start); 
  start.hStdOutput  := WritePipe; 
  start.hStdInput  := ReadPipe; 
  start.dwFlags   := STARTF_USESTDHANDLES + 
             STARTF_USESHOWWINDOW; 
  start.wShowWindow := SW_HIDE; 
 
  if CreateProcess(nil, 
      PChar(CmdLine), 
      @Security, 
      @Security, 
      true, 
      NORMAL_PRIORITY_CLASS, 
      nil, 
      nil, 
      start, 
      ProcessInfo) 
  then 
  begin 
   repeat 
   Apprunning := WaitForSingleObject 
          (ProcessInfo.hProcess,100); 
    ReadFile(ReadPipe,Buffer[0], 
       ReadBuffer,BytesRead,nil); 
    Buffer[BytesRead]:= #0; 
    OemToAnsi(Buffer,Buffer); 
    AMemo.Text := AMemo.text + String(Buffer); 
 
   Application.ProcessMessages; 
   until (Apprunning <> WAIT_TIMEOUT); 
  end; 
  FreeMem(Buffer); 
  CloseHandle(ProcessInfo.hProcess); 
  CloseHandle(ProcessInfo.hThread); 
  CloseHandle(ReadPipe); 
  CloseHandle(WritePipe); 
  end; 
  Screen.Cursor:=CrDefault; 
  Form1.Button1.Enabled:=True; 
 end; 
 
procedure TForm1.Button1Click(Sender: TObject); 
begin 
 Memo1.Clear; 
 RunDosInMemo('ping -t 192.168.28.200',Memo1); 
end;

Взято с Vingrad.ru https://forum.vingrad.ru


Автор: Алексей Бойко

Это пример запуска консольных программ с передачей ей консольного ввода (как если бы он был введен с клавиатуры после запуска программы) и чтением консольного вывода. Таким способом можно запускать например стандартный виндовый ftp.exe (в невидимом окне) и тем самым отказаться от использования специализированных, зачастую глючных компонент.

function ExecuteFile(FileName,StdInput: string;
                     TimeOut: integer;
                     var StdOutput:string) : boolean;
 
label Error;
 
type
  TPipeHandles = (IN_WRITE,  IN_READ,
                  OUT_WRITE, OUT_READ,
                  ERR_WRITE, ERR_READ);
 
type
  TPipeArray = array [TPipeHandles] of THandle;
 
var
  i         : integer;
  ph        : TPipeHandles;
  sa        : TSecurityAttributes;
  Pipes     : TPipeArray;
  StartInf  : TStartupInfo;
  ProcInf   : TProcessInformation;
  Buf       : array[0..1024] of byte;
  TimeStart : TDateTime;
 
 
function ReadOutput : string;
var
  i : integer;
  s : string;
  BytesRead : longint;
 
begin
  Result := '';
  repeat
 
    Buf[0]:=26;
    WriteFile(Pipes[OUT_WRITE],Buf,1,BytesRead,nil);
    if ReadFile(Pipes[OUT_READ],Buf,1024,BytesRead,nil) then
    begin
      if BytesRead>0 then
      begin
        buf[BytesRead]:=0;
        s := StrPas(@Buf[0]);
        i := Pos(#26,s);
        if i>0 then s := copy(s,1,i-1);
        Result := Result + s;
      end;
    end;
 
    if BytesRead1024 then break;
  until false;
end;
 
 
begin
  Result := false;
  for ph := Low(TPipeHandles) to High(TPipeHandles) do
    Pipes[ph] := INVALID_HANDLE_VALUE;
 
 
  // Создаем пайпы
  sa.nLength := sizeof(sa);
  sa.bInheritHandle := TRUE;
  sa.lpSecurityDescriptor := nil;
 
 
  if not CreatePipe(Pipes[IN_READ],Pipes[IN_WRITE], @sa, 0 ) then
    goto Error;
  if not CreatePipe(Pipes[OUT_READ],Pipes[OUT_WRITE], @sa, 0 ) then
    goto Error;
  if not CreatePipe(Pipes[ERR_READ],Pipes[ERR_WRITE], @sa, 0 ) then
    goto Error;
 
 
 
  // Пишем StdIn
  StrPCopy(@Buf[0],stdInput+^Z);
  WriteFile(Pipes[IN_WRITE],Buf,Length(stdInput),i,nil);
 
 
  // Хендл записи в StdIn надо закрыть - иначе выполняемая программа
  // может не прочитать или прочитать не весь StdIn.
 
  CloseHandle(Pipes[IN_WRITE]);
 
  Pipes[IN_WRITE] := INVALID_HANDLE_VALUE;
 
 
  FillChar(StartInf,sizeof(TStartupInfo),0);
  StartInf.cb := sizeof(TStartupInfo);
  StartInf.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
 
 
  StartInf.wShowWindow := SW_SHOW; // SW_HIDE если надо запустить невидимо
 
 
  StartInf.hStdInput := Pipes[IN_READ];
  StartInf.hStdOutput := Pipes[OUT_WRITE];
  StartInf.hStdError := Pipes[ERR_WRITE];
 
 
  if not CreateProcess(nil, PChar(FileName), nil,
                       nil, True, NORMAL_PRIORITY_CLASS,
                       nil, nil, StartInf, ProcInf) then goto Error;
 
  TimeStart := Now;
 
  repeat
    Application.ProcessMessages;
    i := WaitForSingleObject(ProcInf.hProcess,100);
    if i = WAIT_OBJECT_0 then break;
    if (Now-TimeStart)*SecsPerDay>TimeOut then break;
  until false;
 
 
  if iWAIT_OBJECT_0 then goto Error;
  StdOutput := ReadOutput;
 
  for ph := Low(TPipeHandles) to High(TPipeHandles) do
    if Pipes[ph]INVALID_HANDLE_VALUE then
      CloseHandle(Pipes[ph]);
 
 
  CloseHandle(ProcInf.hProcess);
  CloseHandle(ProcInf.hThread);
  Result := true;
  Exit;
 
 
Error:
 
  if ProcInf.hProcessINVALID_HANDLE_VALUE then
 
  begin
    CloseHandle(ProcInf.hThread);
    i := WaitForSingleObject(ProcInf.hProcess, 1000);
    CloseHandle(ProcInf.hProcess);
    if iWAIT_OBJECT_0 then
 
    begin
      ProcInf.hProcess := OpenProcess(PROCESS_TERMINATE,
                                      FALSE,
                                      ProcInf.dwProcessId);
 
      if ProcInf.hProcess  0 then
      begin
        TerminateProcess(ProcInf.hProcess, 0);
        CloseHandle(ProcInf.hProcess);
      end;
    end;
  end;
 
  for ph := Low(TPipeHandles) to High(TPipeHandles) do
    if Pipes[ph]INVALID_HANDLE_VALUE then
      CloseHandle(Pipes[ph]);
 
end;

Взято из https://forum.sources.ru