2017-04-19 62 views
-1

我有一个cmd,会不断向我返回值,不停,我不知道如何获取这些值并将其设置为一个字符串来发送一个TMemo。线程 - 同步DOS输出

代码来获取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; 

我不能等到线程结束,因为结果不停止更新,该线程将永远不会结束,只是需要在更新运行。
我试图使用同步坏没有工作。我该如何继续?

我的代码:

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; 
+0

是否要在Repeat ... Until循环中显示结果值?或者在循环之后一次?您的代码没有持续(不停止)结果 –

+0

@M ... M需要实时获取结果。我无法使用线程的OnTerminate事件。 – strykerbits

+0

无需OnTerminate事件,请使用我在答案中发布的单位 –

回答

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的备忘录行

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