【问题标题】:Why Delphi App can't run a *.bat file and make it work?为什么 Delphi App 不能运行 *.bat 文件并使其工作?
【发布时间】:2015-08-25 18:45:00
【问题描述】:

*.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 文件”。

【问题讨论】:

  • 我们不知道 StartProcess 是什么。这里不需要 shell 动词 runas。您似乎在理解上存在缺陷。反复试验不是一个好方法。慢一点。了解详情。进行调试。
  • 双击bat文件和ShellExecute有什么区别?
  • 不同之处在于您的代码强制使用runas 动词,而双击则会调用单击文件的默认动词。如果要使用 ShellExecute() 调用默认动词,请指定 nil 动词。
  • 现在,也就是说,您已经展示了几行代码,但您还没有解释它们出了什么问题。他们没有启动 WinRAR 吗?是否报告了任何错误代码?您需要提供有关您为诊断问题所做的工作的更多详细信息,否则此讨论可能会因离题而结束。

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


【解决方案1】:

您的实现应该可以工作。它在我使用您编写的 StartProcess() 方法放在一起的测试用例中成功运行批处理文件。这表明还有一些其他问题影响了代码的运行。

一些建议可能会有所帮助。

来自the documentation for CreateProcess()

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

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

这很容易通过将您的 CreateProcess 调用更改为:

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

扩展 David 的评论,CreateProcessUnicode 版本 可能会修改命令行参数的内容,所以如果您使用的是 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;

一般来说,在方法的实现中重复默认参数值可能会造成混淆。编译器会忽略它们,并且声明中的任何默认参数值都优先。因此,如果将来在声明中声明的参数默认值发生变化,那么实现中声明的值就会产生误导。

【讨论】:

  • 你必须确保第二个参数是可写的。调用 UniqueString 就可以了。
  • 好点。当然,它只适用于 Unicode 版本,单独使用 UniqueString() 可能还不够。需要一个局部变量以及对 UniqueString 的调用,因为如果字符串的引用计数已经为 1,则 UniqueString 是无操作的。也引用字符串的局部变量确保引用计数至少为 2,从而确保 UniqueString() 根据需要创建唯一副本。我已使用此附加信息和建议更新了答案。
  • 如果字符串的引用计数为 1,则它位于可编辑内存中。常量字符串的引用计数为 1。UniqueString 正是我们所需要的。
  • 嗯,常量字符串的引用计数为-1。引用计数为 1 的字符串可能在 edit_able_ 内存中,但不一定应该是 edit_ed_。所以是的,在这种情况下,UniqueString 可能是避免 AV 所需的全部,但不一定足以避免更微妙的潜在问题。此外,虽然在这种特殊情况下不相关,但 UniqueString() 不能用于 const 参数。
  • 我的错字。意思是说-1。如果用户传递了一个不打算编辑的字符串,那么显然它会中断。在呈现的代码中,在按值 arg 上调用 UniqueString 就足够了。无需复制。仅当 arg 作为 const 传递时才需要复制。
猜你喜欢
  • 1970-01-01
  • 2011-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-13
  • 1970-01-01
相关资源
最近更新 更多