14

所以我在 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 行是可见的,其中显示了正在执行的各种操作。sikuli 脚本完成后,cmd 行会自行关闭。因此,shell 处理程序知道何时关闭正在运行的进程。所以我的问题是:是否可以告诉delphi:处理程序关闭进程后,运行下一个进程(Sikuli Script)?现在我知道我可以在delphi中使用整个createProcess,但这似乎有点过分了。必须有一种方法可以更快、更容易地做到这一点。有人有线索吗?

4

4 回答 4

24

使用 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;
于 2013-06-27T09:19:30.707 回答
7

您需要等到进程句柄发出信号。例如通过调用 WaitForSingleObject。显然 CreateProcess 会为您返回一个您可以等待的进程句柄。你无法说服 ShellExecute 返回一个进程句柄,但它更强大的兄弟 ShellExecuteEx 会这样做。

但是,我个人会在这里选择 CreateProcess。您将获得更多的灵活性和控制力,而且并不那么复杂。例如,您可以根据需要禁止显示控制台窗口。

于 2013-06-27T06:50:06.980 回答
1

这是一个 hack 并且不太复杂,但也许您可以只生成一个包含脚本调用的 *.bat 文件,如有必要,在每一行上使用“start /wait”。

于 2013-06-27T13:23:49.350 回答
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 脚本将一个接一个地运行。

于 2013-06-28T07:11:46.633 回答