2013-06-27 55 views
7

所以我在Delphi中做了一個表單,它允許我運行各種配置的sikuli腳本。我現在的工作就是讓使用該表單的人可以設置各種sikuli腳本以便一個接一個地運行。如在:如何等待外部過程完成?

步驟1:SikuliScript1與ConfigFile1。 步驟2:帶ConfigFile2的SikuliScript2。 等等 這是我到目前爲止的代碼:

procedure TSikRunForm.btnRunClick(Sender: TObject); 
begin 
    DirCombo:= '/C '+DirSik+'\sikuli-script.cmd' +' -r ' + DirScript + ' --args '+DirConfig; 
    if SikFound then begin 
     ShellExecute(Handle, nil, 'cmd.exe', pChar(DirCombo), nil, SW_SHOWNORMAL); 
     Application.minimize; 
    end else begin 
     ShowMessage('Select the correct folder for your Sikuli installation folder'); 
    end; 
end; 

而這完美的作品中,Sikuli腳本完美運行,並且運行時,CMD線與正在執行所示的各種動作可見。 sikuli腳本完成後,cmd行將自行關閉。所以shell處理程序知道何時關閉正在運行的進程。所以我的問題是:是否可以告訴delphi:處理程序關閉了進程後,運行下一個進程(Sikuli腳本)? 現在我知道我可以在delphi中使用整個createProcess,但它看起來似乎過分。必須有一種方法可以更快,更輕鬆地完成此項任務。 任何人都有線索?

回答

19

使用CreateProcess,您可以獲得一個進程句柄並使用WaitForSingleObject可以檢查進程何時完成。 我使用下面的函數,這在後臺運行命令:

procedure ExecuteAndWait(const aCommando: string); 
var 
    tmpStartupInfo: TStartupInfo; 
    tmpProcessInformation: TProcessInformation; 
    tmpProgram: String; 
begin 
    tmpProgram := trim(aCommando); 
    FillChar(tmpStartupInfo, SizeOf(tmpStartupInfo), 0); 
    with tmpStartupInfo do 
    begin 
    cb := SizeOf(TStartupInfo); 
    wShowWindow := SW_HIDE; 
    end; 

    if CreateProcess(nil, pchar(tmpProgram), nil, nil, true, CREATE_NO_WINDOW, 
    nil, nil, tmpStartupInfo, tmpProcessInformation) then 
    begin 
    // loop every 10 ms 
    while WaitForSingleObject(tmpProcessInformation.hProcess, 10) > 0 do 
    begin 
     Application.ProcessMessages; 
    end; 
    CloseHandle(tmpProcessInformation.hProcess); 
    CloseHandle(tmpProcessInformation.hThread); 
    end 
    else 
    begin 
    RaiseLastOSError; 
    end; 
end; 
+0

如果你想抽取隊列,最好使用'MsgWaitForMultipleObjects'。此外,你正在泄漏手柄。每次調用該函數兩次。 –

+0

爲什麼downvote? – OnTheFly

+0

@DavidHeffernan爲什麼downvote?你對手柄(我的壞)是正確的,但它確實給出瞭解決問題的辦法,一個接一個地運行一個進程。 –

5

您需要等待,直到進程句柄被髮送信號。例如通過調用WaitForSingleObject。很顯然,CreateProcess會返回一個你可以等待的進程句柄。你無法說服ShellExecute返回一個進程句柄,但其更有能力的兄弟ShellExecuteEx將這樣做。

但是,我個人會在這裏選擇CreateProcess。您將獲得更多的靈活性和控制力,並不那麼複雜。例如,如果您願意,您可以禁止顯示控制檯窗口。

0

這是一個黑客和方式不太複雜,但也許你可以只生成包含在腳本調用一個* .bat文件,如果每行需要使用「開始/等待」。

1

好吧,我已經仔細研究過這個問題並解決了問題,就像戴維建議的一樣。我會顯示我做了什麼,如果其他人有任何問題或任何其他:

procedure TSikRunForm.btnRunClick(Sender: TObject); 
begin 
CmdLine:= 'C:\\windows\\system32\\cmd.exe'; 
uniqueString(CmdLine); 
if SikFound then begin 
    //----------For loop--------------- 
    DirScript:= TScriptEdit.Text; 
    DirConfig:= TConfEdit.Text; 
    DirCombo:= '/C '+DirSik+'\sikuli-script.cmd' +' -r ' + DirScript + ' --args '+DirConfig; 
    CreateProcess(PChar(CmdLine),PChar(DirCombo),Nil,Nil,False,CREATE_NO_WINDOW,nil,nil,StartInfo,ProcInfo); 
    procHandle:= ProcInfo.hProcess; 
    Application.minimize; 
    WaitForSingleObject(procHandle, INFINITE); 

    DirScript:= TScriptEdit2.Text; 
    DirConfig:= TConfEdit2.Text; 
    DirCombo:= '/C '+DirSik+'\sikuli-script.cmd' +' -r ' + DirScript + ' --args '+DirConfig; 
    CreateProcess(PChar(CmdLine),PChar(DirCombo),Nil,Nil,False,CREATE_NO_WINDOW,nil,nil,StartInfo,ProcInfo); 
    procHandle:= ProcInfo.hProcess; 
    Application.minimize; 
    WaitForSingleObject(procHandle, INFINITE); 
    //---------------------------------------- 
    showMessage('Gedoan'); 
end else begin 
    ShowMessage('Select the correct folder for your Sikuli installation folder'); 
end; 
end; 

完全按照我的意圖工作。 2個sikuli腳本會一個接一個地運行。