Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2008.01.13;
Скачать: CL | DM;

Вниз

Как правильно сделать вывод из консоли?   Найти похожие ветки 

 
Kolan ©   (2007-12-11 15:38) [0]

Роясь в нете сдела такую процедуру:

procedure TReplicationController.RunApplicationAndWaitTillFinish(
 RunString: string);
var
 StartupInfo: TStartupInfo;
 SecurityAttributes: TSecurityAttributes;
 ProcessInfo: TProcessInformation;
 ExitCode: Cardinal;

 StdOutPipeRead, StdOutPipeWrite: THandle;

 CreateResult, ReadResult: Boolean;

 Buffer: array[0&#133255] of Char;
 BytesRead: Cardinal;

 S: string;
 FOverlappedRead: TOverlapped;

 LastError: Cardinal;
 TimeOut: Cardinal;

 FCommStat: TComStat;
 Errors: Cardinal;
 WaitResult: Cardinal;
begin
 DoInfoEvent(RunString);
 with SecurityAttributes do
 begin
   nLength := SizeOf(SecurityAttributes);
   bInheritHandle := True;
   lpSecurityDescriptor := nil;
 end;
 try
   // создаём пайп для перенаправления стандартного вывода
   CreatePipe(StdOutPipeRead,  // дескриптор чтения
              StdOutPipeWrite, // дескриптор записи
              @SecurityAttributes,              // аттрибуты безопасности
              0                // количество байт принятых для пайпа — 0 по умолчанию
              );

   with StartupInfo do
   begin
     FillChar(StartupInfo, SizeOf(StartupInfo), 0);
     cb := SizeOf(StartupInfo);
     dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
     wShowWindow := SW_HIDE;
     hStdInput := GetStdHandle(STD_INPUT_HANDLE); // стандартный ввод не перенаправляем
     hStdOutput := StdOutPipeWrite;
     hStdError := StdOutPipeWrite;
   end;

   
   CreateResult := CreateProcess(nil, PAnsiChar(RunString), nil, nil, True,
     0, nil, nil, StartupInfo, ProcessInfo);

   if CreateResult then
   begin
     try
       S := "";
       repeat
         Application.ProcessMessages;
         WaitResult := WaitForSingleObject (ProcessInfo.hProcess, 10);
         ReadFile(StdOutPipeRead, Buffer, 255, BytesRead, nil);
         Buffer[BytesRead] := #0;
         OemToAnsi(Buffer, Buffer);
         S := S + Buffer;
       until (WaitResult <> WAIT_TIMEOUT);
       DoInfoEvent(S);
     finally
       CloseHandle(ProcessInfo.hThread);
       CloseHandle(ProcessInfo.hProcess);
     end;
   end
   else
     raise EReplicationException.Create(SysErrorMessage(GetLastError));
 finally
   CloseHandle(StdOutPipeRead);
 end;
end;


Кое что конечно перенаправляется, но не все, почему? И вообще как правильно это сделать?


 
Slym ©   (2007-12-12 04:35) [1]

потому что мало из пайпа вычитываешь...
while true do
begin
 PeekNamedPipe(tdOutPipeRead,nil,0,nil,@bytesRead,nil);
   if bytesRead=0 then break;
 if not ReadFile(StdOutPipeRead, Buffer, 255, BytesRead, nil) then RaiseLastOSError;
 Buffer[BytesRead] := #0;
 OemToAnsi(Buffer, Buffer);
 S := S + Buffer;
end;


 
Kolan ©   (2007-12-12 10:14) [2]

> потому что мало из пайпа вычитываешь&#133

Шас попробую. Неужели остальной код правильный?


 
Kolan ©   (2007-12-12 10:34) [3]

Получилось. Но не доконца.

Если просто использовать ваш код, то происходит выход по BytesReadFromPipe = 0, так как видимо сразу начинается чтение, а данных еще нет.

Добавил ожидание завершения процесса (WaitForSingleObject), в этом случае работает, но так я получаю все данные одним куском, а хотелось бы по мере их появления.

WaitForSingleObject (ProcessInfo.hProcess, INFINITE);
       {}
       while True do
       begin    
         PeekNamedPipe(StdOutPipeRead, nil, 0, nil, @BytesReadFromPipe, nil);
         if BytesReadFromPipe = 0 then
           Break;
         if not ReadFile(StdOutPipeRead, Buffer, 255, BytesReadFromFile, nil) then
           RaiseLastOSError;
         Buffer[BytesReadFromFile] := #0;
         OemToAnsi(Buffer, Buffer);
         S := Buffer;
         DoInfoEvent(S, clGray, False);
       end;


 
Kolan ©   (2007-12-12 11:13) [4]

Вот получилось так:

        repeat
         WaitResult := WaitForSingleObject(ProcessInfo.hProcess, 10);
         PeekNamedPipe(StdOutPipeRead, nil, 0, nil, @BytesReadFromPipe, nil);
         if BytesReadFromPipe > 0 then
         begin
           SetLength(Buffer, BytesReadFromPipe);
           if not ReadFile(StdOutPipeRead, Buffer[0], BytesReadFromPipe, BytesReadFromFile, nil) then
             RaiseLastOSError;
           OemToAnsi(@Buffer[0], @Buffer[0]);
           S := "";
           for I := Low(Buffer) to High(Buffer) do
             S := S + Buffer[I];
           DoInfoEvent(S, clGray, False);
         end;
       until (WaitResult <> WAIT_TIMEOUT) and (BytesReadFromPipe = 0);


Не попортил ли я где память?
Buffer объявлен так:
Buffer: array of Char;

Можно ли обойтись без цикла:
for I := Low(Buffer) to High(Buffer) do
  S := S + Buffer[I];

?


 
Leonid Troyanovsky ©   (2007-12-13 18:57) [5]


> Kolan ©   (12.12.07 11:13) [4]

> Можно ли обойтись без цикла:
> for I := Low(Buffer) to High(Buffer) do
>   S := S + Buffer[I];

Не надо забывать и SetString.

--
Regards, LVT.


 
Slym ©   (2007-12-14 04:23) [6]

 repeat
   WaitResult := WaitForSingleObject(ProcessInfo.hProcess, 10);
   PeekNamedPipe(StdOutPipeRead, nil, 0, nil, @BytesReadFromPipe, nil);
   if BytesReadFromPipe > 0 then
   begin
      SetLength(S, BytesReadFromPipe);
      if not ReadFile(StdOutPipeRead, PChar(S)^, BytesReadFromPipe, BytesReadFromFile, nil) then
        RaiseLastOSError;
      SetLength(S, BytesReadFromFile);
      OemToAnsi(PChar(S),PChar(S));
      DoInfoEvent(S, clGray, False);
   end;
 until (WaitResult <> WAIT_TIMEOUT) and (BytesReadFromPipe = 0);


 
Kolan ©   (2007-12-14 09:48) [7]

> [6] Slym ©   (14.12.07 04:23)

О, благодарю &#151; так работает правильно, а то я видно где-то память портил. Слетала программа, даже не пикала.

Окончтельный вариант:
procedure RunApplicationAndWaitTillFinish(RunString: string;
   ConsoleViewVisitor: IConsoleViewVisitor);
var
 StartupInfo: TStartupInfo;
 SecurityAttributes: TSecurityAttributes;
 ProcessInfo: TProcessInformation;
 StdOutPipeRead, StdOutPipeWrite: THandle;
 CreateResult: Boolean;
 S: string;
 BytesReadFromFile: Cardinal;
 BytesReadFromPipe: Cardinal;
 WaitResult: Cardinal;
begin
 with SecurityAttributes do
 begin
   nLength := SizeOf(SecurityAttributes);
   bInheritHandle := True;
   lpSecurityDescriptor := nil;
 end;
 
 {Создать пайп для перенаправления стандартного вывода.}
 if not CreatePipe(
   StdOutPipeRead, // дескриптор чтения.
   StdOutPipeWrite, // дескриптор записи.
   @SecurityAttributes, // аттрибуты безопасности.
   0) // количество байт принятых для пайпа &#151; 0 по умолчанию.
 then
   RaiseLastOSError;
 try
 
   with StartupInfo do
   begin
     FillChar(StartupInfo, SizeOf(StartupInfo), 0);
     cb := SizeOf(StartupInfo);
     dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
     wShowWindow := SW_HIDE;
     hStdInput := GetStdHandle(STD_INPUT_HANDLE); // стандартный ввод не перенаправляем
     hStdOutput := StdOutPipeWrite;
     hStdError := StdOutPipeWrite;
   end;

   ZeroMemory(@ProcessInfo, SizeOf(@ProcessInfo));

   CreateResult := CreateProcess(nil, PAnsiChar(RunString), nil, nil, True,
     0, nil, nil, StartupInfo, ProcessInfo);

   if CreateResult then
   begin
     try
       repeat
         Application.ProcessMessages;
         {Ждать процесс 100 мс.}
         WaitResult := WaitForSingleObject(ProcessInfo.hProcess, 100);
         Application.ProcessMessages;
         {Узнать сколько в пайпе байт}
         PeekNamedPipe(StdOutPipeRead, nil, 0, nil, @BytesReadFromPipe, nil);
         {Есл байт больше 0&#133}
         if BytesReadFromPipe > 0 then
         begin
           {&#133 выделить память для строки.}
           SetLength(S, BytesReadFromPipe);
           {Прочесть байты.}
           if not ReadFile(StdOutPipeRead, PChar(S)^, BytesReadFromPipe, BytesReadFromFile, nil) then
             RaiseLastOSError;
           {Отрезать лишние.}
           SetLength(S, BytesReadFromFile);
           {Перекодировать из дос кодировки.}
           OemToAnsi(PChar(S), PChar(S));
           {Отправить полученые из консоли данные посетителю.}
           if Assigned(ConsoleViewVisitor) then
             ConsoleViewVisitor.ViewConsoleMessage(S);
         end;
       {Выйти если процесс завершился и нечего читать.}
       until (WaitResult <> WAIT_TIMEOUT) and (BytesReadFromPipe = 0);
     finally
       {Закрыть хендлы процесса.}
       CloseHandle(ProcessInfo.hThread);
       CloseHandle(ProcessInfo.hProcess);
     end;
   end
   else
     RaiseLastOSError;
 finally
   {Закрыть хендлы пайпа.}
   CloseHandle(StdOutPipeRead);
   CloseHandle(StdOutPipeWrite);
 end;
end;


Так правильно? Нет ошибок?



Страницы: 1 вся ветка

Текущий архив: 2008.01.13;
Скачать: CL | DM;

Наверх




Память: 0.51 MB
Время: 0.019 c
2-1197367826
rich_rich
2007-12-11 13:10
2008.01.13
работа с BLOB в MySQL (ZQuery)


15-1197196071
Kostafey
2007-12-09 13:27
2008.01.13
С днем рождения ! 9 декабря


15-1196934505
Pazitron_Brain
2007-12-06 12:48
2008.01.13
Как восстановить вид значков по умолчанию?


2-1197453836
Alexandr Malygin
2007-12-12 13:03
2008.01.13
Tcaption и Char


15-1196713162
Rouse_
2007-12-03 23:19
2008.01.13
Обсуждение кандидатов на значек "Мастер Дельфи"