【问题标题】:How can I wait until an external process has completed?我怎样才能等到外部进程完成?
【发布时间】:2013-06-27 06:41:38
【问题描述】:

所以我在 Delphi 中制作了一个表单,允许我运行具有各种配置的各种 sikuli 脚本。我现在正在做的是让使用表单的人能够设置各种 sikuli 脚本以在一个接一个上运行。如:

第 1 步:SikuliScript1 与 ConfigFile1。 第 2 步:SikuliScript2 和 ConfigFile2。 ETC... 到目前为止,这是我的代码:

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,但这似乎有点过分了。必须有一种方法可以更快、更容易地做到这一点。 有人知道吗?

【问题讨论】:

    标签: delphi winapi


    【解决方案1】:

    使用 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;
    

    【讨论】:

    • 如果你想抽队列,最好使用MsgWaitForMultipleObjects。此外,您正在泄漏句柄。每次调用该函数两个。
    • @DavidHeffernan 为什么投反对票?您对句柄的看法是正确的(我的错),但它确实为问题提供了解决方案,一个接一个地运行。
    • @BartvanDijk 我无法解释反对票,因为我没有投反对票。我也无法解释投票。我不会赞成一个(几乎)繁忙的循环和泄漏句柄的答案。你应该解决这些问题,然后你也许值得被投赞成票。
    • 赞成代码起点。写正确的MsgWaitForSingleObject 几乎是不可能的(我知道我做不到)
    • @Ian MsgWaitForMultipleObjects 不难
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

        好的,正如大卫建议的那样,我已经对此进行了更多研究并解决了它。如果其他人有任何问题或任何问题,我会展示我所做的:

        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 脚本会一个接一个地运行。

        【讨论】:

        • WET 的一个很好的例子。
        猜你喜欢
        • 2011-12-14
        • 2016-05-19
        • 2014-09-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多