Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: WinAPI и системное программирование > Как принять сообщение WinRAR c StdErr


Автор: kucik 12.5.2005, 01:00
В RAR'e есть такой ключик -ierr - перенаправление всех сообщений на стандартное устройство ошибки.
Как принять все эти сообщения?
Прочитал эту тему http://forum.vingrad.ru/index.php?showtopic=25023&unread=1&hl=stderr, но моя проблемма немного в другом (на мой взгляд), т.к. в моём случае информация уже выводится на стандартное устройство ошибки!?
Попробовал такой вариант:
Код

 ...
  if Result then
    begin
      Line := '';
      REPEAT
        Result := ReadFile(StartInfo.hStdError, Buffer, 255, BytesRead, nil);
        if BytesRead > 0 then
          begin
              // завершаем буфер PChar-ом
            Buffer[BytesRead] := #0;
              // добавляем буфер в общий вывод
            Line := Line + Buffer;
          end;
      UNTIL NOT Result or (BytesRead = 0);

      while WaitforSingleObject(ProcInfo.hProcess,200)=WAIT_TIMEOUT do
        Application.ProcessMessages;
...

... он не проходит, BytesRead всегда 0
Thanks!

Автор: Alex 12.5.2005, 07:07
Не проверял, но должно работать:
Код

function GetDosOutput(const CommandLine:string): string;
var
  SA: TSecurityAttributes;
  SI: TStartupInfo;
  PI: TProcessInformation;
  StdOutPipeRead, StdOutPipeWrite: THandle;
  WasOK: Boolean;
  Buffer: array[0..255] of Char;
  BytesRead: Cardinal;
  WorkDir, Line: String;
begin
  Application.ProcessMessages;
  with SA do
  begin
    nLength := SizeOf(SA);
    bInheritHandle := True;
    lpSecurityDescriptor := nil;
  end;
  // создаём пайп для перенаправления стандартного вывода
  CreatePipe(StdOutPipeRead,  // дескриптор чтения
             StdOutPipeWrite, // дескриптор записи
             @SA,              // аттрибуты безопасности
             0                // количество байт принятых для пайпа - 0 по умолчанию
             );
  try
    // Создаём дочерний процесс, используя StdOutPipeWrite в качестве стандартного вывода,
    // а так же проверяем, чтобы он не показывался на экране.
    with SI do
    begin
      FillChar(SI, SizeOf(SI), 0);
      cb := SizeOf(SI);
      dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
      wShowWindow := SW_HIDE;
      hStdInput := GetStdHandle(STD_INPUT_HANDLE); // стандартный ввод не перенаправляем
      hStdOutput := GetStdHandle(STD_OUTPUT_HANDLE); // стандартный вывод не перенаправляем
      hStdError := StdOutPipeWrite;
    end;

    // Запускаем компилятор из командной строки
    WorkDir := ExtractFilePath(CommandLine);
    WasOK := CreateProcess(nil, PChar(CommandLine), nil, nil, True, 0, nil, PChar(WorkDir), SI, PI);

    // Теперь, когда дескриптор получен, для безопасности закрываем запись. 
    // Нам не нужно, чтобы произошло случайное чтение или запись. 
    CloseHandle(StdOutPipeWrite);  
    // если процесс может быть создан, то дескриптор, это его вывод
    if not WasOK then 
      raise Exception.Create('Could not execute command line!') 
    else 
      try 
        // получаем весь вывод до тех пор, пока DOS-приложение не будет завершено
        Line := ''; 
        repeat 
          // читаем блок символов (могут содержать возвраты каретки и переводы строки) 
          WasOK := ReadFile(StdOutPipeRead, Buffer, 255, BytesRead, nil); 

          // есть ли что-нибудь ещё для чтения? 
          if BytesRead > 0 then 
          begin 
            // завершаем буфер PChar-ом 
            Buffer[BytesRead] := #0;
            // добавляем буфер в общий вывод 
            Line := Line + Buffer; 
          end; 
        until not WasOK or (BytesRead = 0); 
        // ждём, пока завершится консольное приложение
        WaitForSingleObject(PI.hProcess, INFINITE); 
      finally 
        // Закрываем все оставшиеся дескрипторы 
        CloseHandle(PI.hThread); 
        CloseHandle(PI.hProcess);
      end; 
  finally 
      result:=Line; 
      CloseHandle(StdOutPipeRead); 
  end;
end;

Автор: andrey_pst 12.5.2005, 07:42
Код

// архивирует файлы в архив WinRar (ver.2.7) и возвращает код возврата архиватора
function AddToRAR(RarVisible : boolean; RarDir, RarFileName, RarCommand, ArchiveName, FileNames, RarOptions : string) : integer;
var
  PChTmp   : PChar;  // командная строка
  ExitCode : dword;  // код возврата архиватора
  si : STARTUPINFO;
  pi : PROCESS_INFORMATION;
  ErrorWavFileName : PChar;
begin
  PChTmp := PChar(RarDir + RarFileName + ' ' + RarCommand + ' ' + ArchiveName +  ' ' + FileNames + ' ' + RarOptions);
  ZeroMemory(@si, sizeof(si));
  si.cb := SizeOf(si);  // размер структуры в байтах
  si.dwFlags := STARTF_USESHOWWINDOW;
  if RarVisible then
    si.wShowWindow := SW_SHOWNOACTIVATE  // окно видимо и неактивно
  else
    si.wShowWindow := SW_HIDE;           // окно невидимо
  if not CreateProcess(nil, PChTmp, nil, nil, false, 0, nil, nil, si, pi) then  // запустим rar.exe
    ExitCode := 999  // не удалось создать процесс
  else
  begin
    WaitForSingleObject(pi.hProcess, INFINITE);  // ждем окончания процесса
    GetExitCodeProcess(pi.hProcess, ExitCode);   // получаем код возврата
  end;
  CloseHandle(pi.hProcess);
  CloseHandle(pi.hThread);

  result := ExitCode;
end;

Автор: kucik 14.5.2005, 02:33
smile
Уважаемый Alex, я же написал что читал данную Тобой ссылку (Тему .. и даже её привёл!!) ... и там приведённый тобой код есть, только вот незадача - он не работает тозе! smile может конечно я что-то коряво делаю ... да и пример который я сам написал по аналогии должен был бы тоже тогда работать! smile

2 andrey_pst:
С кодом возврата всё понятно! ... Непонятно как прочитать всё что WinRAR выводит в консоль ... а выводить он это может на стандартное устройство ошибки ... следовательно оттудова нам надо это и прочитать!!!
=>
Если
StartInfo: TStartupInfo;
то, по идее
StartInfo.hStdError
- и есть искомое стандартное устройство ошибки .. но не тут то было!
В Result := ReadFile(StartInfo.hStdError, Buffer, 255, BytesRead, nil); пусто!!!
и BytesRead = 0, т.е. ничего не прочитанно smile
хотя Buffer: array[0..255] of Char; если его посмотреть, то он что-то содержит .. (но так как это массив, причём нигде не "обнуляемый", то он просто может содержать всякую чушь!!)
Помогите плиззз!!!
smile

Автор: Alix 14.5.2005, 07:11
Может я не прав и мое представление о мире устарело, но вроде все что выводиться в stderr выводиться только на экран и никуда более... И поток этот перенаправлять нельзя...
К примеру, если вы запустите что-то так: smth.exe > t.txt, то все запишется в файл t.txt. Но! Если это прога выводит что-то в stderr, то оно в t.txt не попадет, но с гарантией попадет на экран.
Или я не прав?

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)