Версия для печати


Перенаправление вывода консольной программы
http://www.delphikingdom.com/asp/viewitem.asp?catalogID=801

Черевко Сергей
дата публикации 02-06-2003 15:03

Перенаправление вывода консольной программы

Понадобилось мне отобразить работу консольной программы в каком-нибудь Memo, а саму консоль не показывать. Поискал в инете - много кто ищет, мало кто предлагает готовые решения. Понял только, что плясать надо с "пайпами". Взял свой парадный бубен и... Вовремя подвернулась хорошая статья в тему на КД:
"StdIn, StdOut и StdErr. Перенаправление, чтение и запись" автор Горбань С.В.
Но мне не нужен целый класс! Да и собственные наработки уже появились. Вообщем, не буду утомлять процессом поисков и метаний, просто скажу что получилось. А получилась следующая функция:

function RunAny(CommandLine: string; Str: TStrings): boolean;
var
   I: byte;
   S: string;
   Flag: boolean;
   tRead, cWrite, dwRead, dwAvail: cardinal;
   SA: TSecurityAttributes;
   PI: TProcessInformation;
   SI: TStartupInfo;
begin
   Result:=False;
   SA.nLength:=SizeOf(SECURITY_ATTRIBUTES);
   SA.bInheritHandle:=True;
   SA.lpSecurityDescriptor:=nil;
   if not CreatePipe(tRead, cWrite, @SA, 0) then Exit;
   ZeroMemory(@SI, SizeOf(TStartupInfo));
   SI.cb:=SizeOf(TStartupInfo);
   SI.dwFlags:=STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW;
   SI.wShowWindow:=SW_HIDE;
   SI.hStdOutput:=cWrite;
   if CreateProcess(nil, PChar(CommandLine), nil, nil, True, 0, nil, nil, SI, PI) then begin
      CloseHandle(PI.hProcess);
      CloseHandle(PI.hThread);
      Str.Clear();
      Flag:=True;
      while Flag do begin
         for I:=0 to 9 do begin
            PeekNamedPipe(tRead, nil, 0, nil, @dwAvail, nil);
            if (dwAvail>0) then begin
               Flag:=True;
               Break;
            end
            else Flag:=False;
            Sleep(100);
         end; //for I:=
         if dwAvail>0 then begin
            SetLength(S, dwAvail);
            ReadFile(tRead, PChar(S)^, Length(S), dwRead, Nil);
            OemToChar(PChar(S), PChar(S));
            Str.Add(S);
            Application.ProcessMessages;
            Result:=True;
         end; // if dwAvail
      end;    // while Flag
   end;       // if CreateProcess
end;

Вот. Может кому пригодится. Естественно пока не причесано, но спешу поделиться :-)

P.S. Автор упомянутой статьи писал, что не пошло у него с format. Да, действительно, такая проблема существует. Под win98SE у меня так и не получилось с тем же format''ом и рядом архиваторов, таких как RAR 2.0 и ARJ 2.50. Однако, под WIN200 PROF RUS все решилось небольшим изменением:
CommandLine:=''cmd.exe /c ''+CommandLine 
- и телемаркет!
Работает даже с bat-файлом.