2014-10-18 4 views
-1

Я использую эту функцию для получения вывода dos в delphi от DelphiDabbler. Но если процесс занимает много времени (например: команда gammu getussd), это заставляет мое приложение не реагировать на некоторое время.
Как этого избежать?Получить неблокирующий вывод CommandLine

function GetDosOutput(CommandLine: string; Work: string = 'C:\'): string; 
var 
    SA: TSecurityAttributes; 
    SI: TStartupInfo; 
    PI: TProcessInformation; 
    StdOutPipeRead, StdOutPipeWrite: THandle; 
    WasOK: Boolean; 
    Buffer: array[0..255] of AnsiChar; 
    BytesRead: Cardinal; 
    WorkDir: string; 
    Handle: Boolean; 
begin 
    Result := ''; 
    with SA do begin 
    nLength := SizeOf(SA); 
    bInheritHandle := True; 
    lpSecurityDescriptor := nil; 
    end; 
    CreatePipe(StdOutPipeRead, StdOutPipeWrite, @SA, 0); 
    try 
    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); // don't redirect stdin 
     hStdOutput := StdOutPipeWrite; 
     hStdError := StdOutPipeWrite; 
    end; 
    WorkDir := Work; 
    Handle := CreateProcess(nil, PChar('cmd.exe /C ' + CommandLine), 
          nil, nil, True, 0, nil, 
          PChar(WorkDir), SI, PI); 
    CloseHandle(StdOutPipeWrite); 
    if Handle then 
     try 
     repeat 
      WasOK := ReadFile(StdOutPipeRead, Buffer, 255, BytesRead, nil); 
      if BytesRead > 0 then 
      begin 
      Buffer[BytesRead] := #0; 
      Result := Result + Buffer; 
      end; 
     until not WasOK or (BytesRead = 0); 
     WaitForSingleObject(PI.hProcess, INFINITE); 
     finally 
     CloseHandle(PI.hThread); 
     CloseHandle(PI.hProcess); 
     end; 
    finally 
    CloseHandle(StdOutPipeRead); 
    end; 
end; 

Автор: Джо Donth

ответ

4

Вы можете использовать простую нить для этого и получить результат в OnTerminate Событие, которое будет выполняться в контексте основного потока, так что не требуется никакой синхронизации furthor :

Type 
    TMyThread = Class(TThread) 
    private 
    FCmd: String; 
    FResult: String; 
    protected 
    Procedure Execute; override; 
    public 
    Constructor Create(const cmd: String;Notity:TNotifyEvent); 
    Property Result: String Read FResult; 
    End; 
    { TMyTHread } 

constructor TMyThread.Create(const cmd: String;Notity:TNotifyEvent); 
begin 
    inherited Create(false); 
    FCmd := cmd; 
    FreeOnTerminate := True; 
    OnTerminate := Notity; 
end; 

procedure TMyThread.Execute; 
begin 
    inherited; 
    FResult := GetDosOutput(FCmd); 
end; 

procedure TForm3.ThreadTerminated(Sender: TObject); 
begin 
    Memo1.Lines.Text := TMyThread(Sender).Result; 
end; 

procedure TForm3.Button1Click(Sender: TObject); 
begin 
    TMyThread.Create('DIR',ThreadTerminated); 
end; 
+3

Установка обработчика 'OnTerminate' после запуска потока небезопасна. Существует риск того, что поток будет завершен до того, как будет установлен обработчик. Добавьте его в конструктор Create. –

+0

@ LURD за советом. – bummi

Смежные вопросы