2013-06-27 18 views
7

Tak więc stworzyłem formularz w Delphi, który pozwala mi uruchamiać różne skrypty sikuli o różnych konfiguracjach. Obecnie pracuję nad tym, aby umożliwić osobom używającym formularza skonfigurowanie różnych skryptów sikuli, które będą uruchamiane po drugim. Tak jak w:Jak mogę poczekać na zakończenie zewnętrznego procesu?

Krok 1: SikuliScript1 z ConfigFile1. Krok 2: SikuliScript2 z ConfigFile2. etc ... To jest mój kod do tej pory:

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; 

I działa to doskonały, sikuli skrypt działa doskonale, a podczas jazdy, linia cmd jest widoczny z różnych działań przedstawionych które są wykonywane. Po wykonaniu skryptu sikuli linia cmd zamyka się sama. Tak więc moduł obsługi powłoki wie, kiedy wyłączyć uruchomiony proces. Moje pytanie brzmi: czy można powiedzieć delphi: Po tym, jak przewodnik zakończył proces, uruchom następny proces (skrypt Sikuli)? Teraz wiem, że mogę iść z całym createProcess w delphi, ale to po prostu wydaje się przesadą. Musi być sposób, aby to zrobić szybciej i łatwiej. Ktoś ma jakąś wskazówkę?

Odpowiedz

19

Dzięki CreateProcess można uzyskać uchwyt procesu, a dzięki WaitForSingleObject można sprawdzić, kiedy proces się zakończył. używam następującą funkcję, to uruchamia komendę w tle:

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

Jeśli chcesz pompować kolejkę, lepiej użyć 'MsgWaitForMultipleObjects'. Ponadto, jesteś przeciekającymi uchwytami. Dwa za każde połączenie z tą funkcją. –

+0

Dlaczego upadły? – OnTheFly

+0

@DavidHeffernan Dlaczego upadek? Masz rację co do uchwytów (moje złe), ale daje rozwiązanie tego problemu, uruchamiając jeden proces po drugim. –

5

Musisz zaczekać, aż wskazanie uchwytu procesu zostanie zasygnalizowane. Na przykład przez połączenie do WaitForSingleObject. Oczywiście CreateProcess zwraca ci uchwyt procesu, na którym możesz czekać. Nie można przekonać ShellExecute, aby zwrócił uchwyt procesu, ale jego bardziej zdolny brat ShellExecuteEx zrobi to.

Jednak osobiście wybrałabym tutaj CreateProcess. Uzyskasz większą elastyczność i kontrolę, a to nie jest takie skomplikowane. Na przykład możesz wyłączyć wyświetlanie okna konsoli, jeśli chcesz.

0

Jest to hack and sposób mniej wyrafinowany, ale może można po prostu wygenerować plik * .bat zawierający wywołań skryptów, jeśli konieczne użycie "start/wait" w każdej linii.

1

Ok. Włożyłem więcej w to i rozwiązałem, tak jak zasugerował David. Pokażę, co zrobiłem, gdyby ktoś miał jakieś pytania lub coś:

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; 

Działa dokładnie tak, jak chciałem. Dwa skrypty sikuli będą się uruchamiać jeden po drugim.

Powiązane problemy