【问题标题】:Delphi - CreateProcess - Execute multiple commandsDelphi - CreateProcess - 执行多个命令
【发布时间】:2013-08-03 12:13:08
【问题描述】:

我想通过 CreateProcess() - 调用实现以下目标:

  1. 更改为 svn 工作副本
  2. 执行 svn 命令
  3. 将输出通过管道传输到文件

我用下面的函数试试这个

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;

【问题讨论】:

  • 你用的是什么版本的Delphi?

标签: windows delphi winapi delphi-xe


【解决方案1】:

调用CreateProcess 时需要提供可执行文件。我猜你习惯打电话给ShellExecute,这比较松散。

您显然希望调用cmd.exe,因此您应该将其添加到命令行。与其在cmd.exe 启动后更改工作目录,不如使用CreateProcesslpCurrentDirectory 参数来执行此操作。您还需要将/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);

【讨论】:

  • @David:使用CreateProcess的第一个参数是个坏主意!您应该将所有内容放入第二个参数中,以便为启动的进程提供“有效”命令行参数。请参阅CreateProcess... 的文档
  • @JochenKalmbach:通过cmd.exe批量执行的特殊情况,文档建议将第一个参数与cmd.exe一起使用。 “要运行批处理文件,您必须启动命令解释器;将 lpApplicationName 设置为 cmd.exe 并将 lpCommandLine 设置为以下参数:/c 加上批处理文件的名称。” (goo.gl/9y0gw)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多