2013-06-27 7 views
7

Итак, я сделал форму в Delphi, которая позволяет запускать различные скрипты sikuli с различными конфигурациями. Теперь я работаю над тем, чтобы кто-то использовал форму, чтобы настроить различные скрипты sikuli для запуска по другому. Как в:Как я могу дождаться завершения внешнего процесса?

Шаг 1: SikuliScript1 с ConfigFile1. Шаг 2: SikuliScript2 с ConfigFile2. и т.д ... Это мой код до сих пор:

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 линия видна с различными действиями, показанными, которые выполняются. После выполнения сценария сикули линия cmd закрывается сама по себе. Поэтому обработчик оболочки знает, когда нужно завершить выполняющийся процесс. Поэтому мой вопрос: можно ли рассказать delphi: после того, как обработчик закрыл процесс, запустите следующий процесс (скрипт Sikuli)? Теперь я знаю, что могу работать со всем createProcess в delphi, но это просто кажется излишним. Должен быть способ сделать это быстрее и легче. У кого-нибудь есть ключ?

ответ

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 файл, содержащий вызовы скриптов, если необходимо использовать «start/wait» в каждой строке.

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 сикули будут запускаться один за другим.