Delphi - CreateProcess - 执行多个命令

时间:2013-08-02 09:22:14

标签: windows delphi winapi delphi-xe

我想通过CreateProcess()实现以下功能 - 调用:

  1. 更改为svn working-copy
  2. 执行svn命令
  3. 将输出管道传输到文件
  4. 我尝试使用以下功能

    procedure TQPortMainForm.CmdMigrationClick(Sender: TObject);
    var
      StartInfo: TStartupInfo;
      ProcInfo: TProcessInformation;
      CreateOk: boolean;
      input: String;
    begin
      { fill with known state }
      FillChar(StartInfo, SizeOf(TStartupInfo), #0);
      FillChar(ProcInfo, SizeOf(TProcessInformation), #0);
      StartInfo.cb := SizeOf(TStartupInfo);
    
      //debug
      input := 'D: && cd D:\Qport\trunk\Qport\ && ' + SVN_PATH + ' log > C:\users\PhilippKober\UNIQUE_NAME_BLUB.txt';
    
      CreateOk := CreateProcess(nil, PChar(input), nil, nil, false, CREATE_NEW_PROCESS_GROUP + NORMAL_PRIORITY_CLASS, nil,
        nil , StartInfo, ProcInfo);
      { check to see if successful }
      if CreateOk then
        // may or may not be needed. Usually wait for child processes
        WaitForSingleObject(ProcInfo.hProcess, INFINITE);
    end;
    

    根本没有任何反应。有没有人知道如何实现这个目标?

    谢谢,

    菲利普

    编辑1:我正在使用Delphi XE - Build 7601:Service Pack 1

    编辑2:这是解决方案:

    var
      StartInfo: TStartupInfo;
      ProcInfo: TProcessInformation;
      CreateOk: boolean;
      input: String;
      path : String;
      cmd : String;
    begin
      { fill with known state }
      FillChar(StartInfo, SizeOf(TStartupInfo), #0);
      FillChar(ProcInfo, SizeOf(TProcessInformation), #0);
      StartInfo.cb := SizeOf(TStartupInfo);
    
      path := 'D:\Qport\trunk\Qport\';
      cmd := 'C:\Windows\System32\cmd.exe';
      //debug
      input := '/C' + SVN_PATH + ' help > C:\users\PhilippKober\UNIQUE_NAME_BLUB.txt';
    
      CreateOk := CreateProcess(PChar(cmd), PChar(input), nil, nil, false, CREATE_NEW_PROCESS_GROUP + NORMAL_PRIORITY_CLASS, nil,
         Pchar(path), StartInfo, ProcInfo);
      { check to see if successful }
      if CreateOk then
        // may or may not be needed. Usually wait for child processes
        WaitForSingleObject(ProcInfo.hProcess, INFINITE);
    end;
    

1 个答案:

答案 0 :(得分:4)

当您致电CreateProcess时,您需要提供可执行文件。我想你习惯于调用ShellExecute,这更加宽松。

您显然希望调用cmd.exe,因此您应该将其添加到命令行。而不是在cmd.exe开始后更改工作目录,而是使用lpCurrentDirectory CreateProcess参数来执行此操作。您还需要将/C选项传递给cmd.exe,以便在命令完成后将其关闭。

因此您需要将input更改为:

input := GetEnvironmentVariable('COMSPEC') + ' /C ' + SVN_PATH + 
  ' log > C:\users\PhilippKober\UNIQUE_NAME_BLUB.txt';

我使用GetEnvironmentVariable('COMSPEC')作为获取命令解释器路径的方法。

然后像这样拨打CreateProcess

CreateProcess(
  nil, 
  PChar(input), 
  nil, 
  nil, 
  False, 
  CREATE_NEW_PROCESS_GROUP or NORMAL_PRIORITY_CLASS, 
  nil,
  'D:\Qport\trunk\Qport', 
  StartInfo, 
  ProcInfo
);

使用or组合标志而不是+在语义上更清晰,尽管它对这些标志具有相同的效果。

需要注意的是,第二个参数必须指向可写内存。那是因为CreateProcess可能会修改该参数。碰巧,您input的设置将满足该要求。在任何情况下,我都建议调用UniqueString,以明确表示您符合该要求。

我看到的另一件事是缺少关闭CreateProcess返回的句柄的代码。最后通过这样做来关闭这些句柄:

//WaitForSingleObject(ProcInfo.hProcess, INFINITE); //in case you want to wait for Process to terminate
CloseHandle(ProcInfo.hProcess);
CloseHandle(ProcInfo.hThread);