web-dev-qa-db-ja.com

外部プロセスが完了するまで待機するにはどうすればよいですか?

そこで、さまざまな構成でさまざまなsikuliスクリプトを実行できるフォームをDelphiで作成しました。私が現在取り組んでいるのは、フォームを使用するユーザーが、さまざまな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行が表示されます。 sikuliスクリプトが完了すると、cmd行は自動的に閉じます。したがって、シェルハンドラーは、実行中のプロセスをシャットダウンするタイミングを認識しています。だから私の質問です:デルファイに伝えることは可能ですか?ハンドラーがプロセスを閉じた後、次のプロセス(Sikuliスクリプト)を実行しますか? delphiでcreateProcess全体を使用できることはわかっていますが、やり過ぎに思われます。これをより速く、より簡単にする方法がなければなりません。誰か手がかりはありますか?

13
user2524670

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;
24
Bart van Dijk

プロセスハンドルが通知されるまで待つ必要があります。たとえば、WaitForSingleObjectを呼び出します。明らかにCreateProcessは、待機できるプロセスハンドルを返します。 ShellExecuteにプロセスハンドルを返すように説得することはできませんが、より有能な兄弟ShellExecuteExがそれを行います。

ただし、私はここではCreateProcessを選択します。柔軟性と制御性が向上しますが、それほど複雑ではありません。たとえば、必要に応じてコンソールウィンドウの表示を抑制できます。

6
David Heffernan

わかりました。Davidが示唆したように、これについて詳しく調べて解決しました。他の誰かに質問がある場合は、私が何をしたかを示します。

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スクリプトが次々に実行されます。

1
user2524670

これはハックであり、それほど洗練されていませんが、必要に応じて、各行で「start/wait」を使用して、スクリプトへの呼び出しを含む* .batファイルを生成することもできます。

0
Martin