为什么Delphi App无法运行* .bat文件并使其工作?

时间:2015-08-25 18:45:01

标签: delphi batch-file command-line cmd winrar

* .bat文件的内容:

cd "C:\Program Files\WinRAR"
WinRAR a -r -ep1 "D:\Temp\250815\GiftCard-250815-1to10.zip" "D:\Temp\250815\word"

基本上,这个文件告诉WinRAR将文件夹“word”压缩成“GiftCard-250815-1to10.zip”。

delphi代码行:

StartProcess('cmd.exe', '/C ' + 'D:\Temp\GenCards.bat', true, true);

我也尝试过:

ShellExecute(Handle, 'runas', PChar('C:\Program Files\WinRAR.exe a -r -ep1 "D:\Temp\250815\GiftCard-250815-1to10.zip" "D:\Temp\250815\word"'), nil, nil, SW_SHOWNORMAL);

我也尝试过:

ShellExecute(Handle, 'runas', 'cmd.exe', PChar('C:\Program Files\WinRAR.exe a -r -ep1 "D:\Temp\250815\GiftCard-250815-1to10.zip" "D:\Temp\250815\word"', nil, SW_SHOWNORMAL);

事实是,我真的迷失在这里,因为如果我去文件夹然后双击* .bat文件,它就能完美运作!

但是,如果我从我的代码中执行bat,它将无效。

*编辑*

这是StartProcess函数:

function TgenerateForm.StartProcess(ExeName: string; CmdLineArgs: string = ''; ShowWindow: boolean = True; WaitForFinish: boolean = False): integer;
var
  StartInfo: TStartupInfo;
  ProcInfo: TProcessInformation;
begin
  //Simple wrapper for the CreateProcess command
  //returns the process id of the started process.
  FillChar(StartInfo,SizeOf(TStartupInfo),#0);
  FillChar(ProcInfo,SizeOf(TProcessInformation),#0);
  StartInfo.cb := SizeOf(TStartupInfo);

  if not(ShowWindow) then begin
    StartInfo.dwFlags := STARTF_USESHOWWINDOW;
    StartInfo.wShowWindow := SW_HIDE;
  end;

  CreateProcess(nil,PChar(ExeName + ' ' + CmdLineArgs),nil,nil,False,
    CREATE_NEW_PROCESS_GROUP + NORMAL_PRIORITY_CLASS,nil,nil,StartInfo,
    ProcInfo);

  Result := ProcInfo.dwProcessId;

  if WaitForFinish then begin
    WaitForSingleObject(ProcInfo.hProcess,Infinite);
  end;

  //close process & thread handles
  CloseHandle(ProcInfo.hProcess);
  CloseHandle(ProcInfo.hThread);
end;

请,不要不礼貌,复制&粘贴网址。我搜索了所有的stackoverflow并尝试了所有“how-tos ... bat文件”。

1 个答案:

答案 0 :(得分:3)

您的实施应该有效。它在我使用 StartProcess()方法编写的测试用例中成功运行批处理文件。这表明存在影响代码操作的其他一些问题。

有几点可能有所帮助。

来自the documentation for CreateProcess()

  

要运行批处理文件,必须启动命令解释程序;组   lpApplicationName到cmd.exe并将lpCommandLine设置为以下内容   参数:/ c加上批处理文件的名称。

lpApplicationName CreateProcess()的初始参数,并在代码中指定为 NIL 。您正在命令行参数中传递应用程序名称。这通常是合法的,在我对你的代码的测试中仍然有效。但是,它很容易受到应用程序模块的长文件名路径中的空格的影响。在应用程序模块参数中显式传递应用程序模块文件名和路径可以避免这种情况。

通过将 CreateProcess 调用更改为:

,可以轻松实现此目的
CreateProcess(PChar(EXEName), PChar(CmdLineArgs), ....);

扩展David的评论, CreateProcess Unicode版本可能会修改命令行参数的内容,因此如果您使用的是Unicode版本的Delphi,或者希望编写将按原样安全地迁移到Unicode编译器的代码,然后您应该确保将引用传递给唯一的可写字符串。为了确保您获得唯一的副本,您应该首先将args存储在本地变量中:

var
  cmdline: String;

begin 
  ..
  cmdline := CmdLineArgs;
  UniqueString(cmdline);

  ..

  CreateProcess(PChar(EXEName), PChar(cmdline), ....);

  ..
end;

另外,我建议批处理文件是一个足够专业的案例,其具有包含 StartProcess 的特定备用实现可能是可取的,称为 StartBatch(),例如:

procedure StartBatch(const aFilename: String, ... );
begin
  StartProcess('cmd.exe', '/C ' + aFilename, ... );
end;

总的来说,在方法的实现中重复默认参数值可能会造成混淆。它们被编译器忽略,并且声明中的任何默认参数值都优先。因此,如果将来更改声明中声明的参数默认值,则实现中声明的值会产生误导。