线程 - 同步DOS输出

时间:2017-04-19 02:19:09

标签: multithreading delphi

我有一个cmd会不断地向我返回值,不停,我不知道如何获取这些值并将其设置在字符串上以发送TMemo。

获取cmd结果的代码:

 function GetDosOutput(CMD: string; Dir: string = 'C:\'): string;
  var
   SA: TSecurityAttributes;
   SI: TStartupInfo;
   PI: TProcessInformation;
   StdOutPipeRead, StdOutPipeWrite: THandle;
   Handle, WasOK: Boolean;
   Buffer: array[0..255] of AnsiChar;
   BytesRead: Cardinal;
   utf8: UTF8String;
 begin
  Result := '';
  SA.nLength := SizeOf(SA);
  SA.bInheritHandle := True;
  SA.lpSecurityDescriptor := nil;
  CreatePipe(StdOutPipeRead, StdOutPipeWrite, @SA, 0);

  try
     FillChar(SI, SizeOf(SI), 0);
     SI.cb := SizeOf(SI);
     SI.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
     SI.wShowWindow := SW_HIDE;
     SI.hStdInput := GetStdHandle(STD_INPUT_HANDLE);
     SI.hStdOutput := StdOutPipeWrite;
     SI.hStdError := StdOutPipeWrite;

     Handle := CreateProcess(nil, PChar('cmd.exe /C ' + CMD), nil, nil, True,
     0, nil, pchar(Dir), SI, PI);
     CloseHandle(StdOutPipeWrite);
     if Handle then
       try
         repeat
           WasOK := ReadFile(StdOutPipeRead, Buffer, 255, BytesRead, nil);
           if BytesRead > 0 then begin
             Buffer[BytesRead] := #0;
             utf8:= Result + String(Buffer);
             Result:= utf8;
           end;
         until not WasOK or (BytesRead = 0);
        WaitForSingleObject(PI.hProcess, INFINITE);
       finally
         CloseHandle(PI.hThread);
         CloseHandle(PI.hProcess);
       end;
   finally
     CloseHandle(StdOutPipeRead);
   end;
 end;

我不能等到线程结束,因为结果不会停止更新,线程永远不会完成,只需要在运行时更新。
我试图使用Synchronize bad不起作用。我该怎么办?

我的代码:

type
 TThread_DOS = class(TThread)
  private
   FCmd: string;
   FResult: string;
  protected
   procedure Execute; override;
  public
   Constructor Create(const cmd: string; Notify: TNotifyEvent);
   property Result: string read FResult;
   property CMD: string read FCmd;
 end;

constructor TThread_DOS.Create(const cmd: string; Notify: TNotifyEvent);
 begin
  inherited Create(false);
  FCmd:= cmd;
  FreeOnTerminate:= true;
  OnTerminate:= Notify;
 end;

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

2 个答案:

答案 0 :(得分:1)

创建一个TThread类并将TMemo及其参数传递给它并让它为您做任何事情

每次需要显示结果时,都可以使用“同步”

进行显示

例如:

unit ThreadUnit;

interface

Uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  VCL.StdCtrls;

type
 TMyThread = class(TThread)
 private
  FMemo : TMemo;
  FCMD : String;
  FDir : String;
 public
  constructor Create(var ResultMemo : TMemo; CMD, Dir : String);
 protected
  procedure Execute; override;
 end;

implementation

{ TMyThread }

constructor TMyThread.Create(var ResultMemo : TMemo; CMD, Dir : String);
begin
 Inherited Create(True);

 FreeOnTerminate := True;

 FMemo := ResultMemo;
 FCMD := CMD;

 if Dir = '' then
  FDir := 'C:\'
 else
  FDir := Dir;
end;

procedure TMyThread.Execute;
  var
   SA: TSecurityAttributes;
   SI: TStartupInfo;
   PI: TProcessInformation;
   StdOutPipeRead, StdOutPipeWrite: THandle;
   Handle, WasOK: Boolean;
   Buffer: array[0..255] of AnsiChar;
   BytesRead: Cardinal;
   utf8: UTF8String;

   Result : String;
 begin
  Result := '';
  SA.nLength := SizeOf(SA);
  SA.bInheritHandle := True;
  SA.lpSecurityDescriptor := nil;
  CreatePipe(StdOutPipeRead, StdOutPipeWrite, @SA, 0);

  try
     FillChar(SI, SizeOf(SI), 0);
     SI.cb := SizeOf(SI);
     SI.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
     SI.wShowWindow := SW_HIDE;
     SI.hStdInput := GetStdHandle(STD_INPUT_HANDLE);
     SI.hStdOutput := StdOutPipeWrite;
     SI.hStdError := StdOutPipeWrite;

     Handle := CreateProcess(nil, PChar('cmd.exe /C ' + FCMD), nil, nil, True,
     0, nil, pchar(FDir), SI, PI);
     CloseHandle(StdOutPipeWrite);
     if Handle then
       try
         repeat
           WasOK := ReadFile(StdOutPipeRead, Buffer, 255, BytesRead, nil);
           if BytesRead > 0 then begin
             Buffer[BytesRead] := #0;
             utf8:= Result + String(Buffer);
             Result:= utf8;

             Synchronize(procedure
                         begin
                          FMemo.Lines.Add(Result);
                         end);
           end;
         until not WasOK or (BytesRead = 0);
        WaitForSingleObject(PI.hProcess, INFINITE);
       finally
         CloseHandle(PI.hThread);
         CloseHandle(PI.hProcess);
       end;
   finally
     CloseHandle(StdOutPipeRead);
   end;
end;

end.

像这样使用这个帖子:

procedure TForm2.Button1Click(Sender: TObject);
var
 MyThread : TMyThread;
begin
 MyThread := TMyThread.Create(Memo1, 'PING 127.0.0.1', '');
 MyThread.Start;
end;

它将在备忘录中逐行显示结果而不冻结UI

请注意构造函数和同步如何工作...

答案 1 :(得分:0)

试试https://github.com/TurboPack/DOSCommand 示例使用备注:

procedure TForm1.DosCommand1NewLine(ASender: TObject; const ANewLine: string;
  AOutputType: TOutputType);
begin
  case AOutputType of
    otEntireLine:
      Memo1.Lines.Add(ANewLine);
  end;
end;

http://www.gesource.jp/weblog/?p=7483