如何在 Inno Setup 中获取已执行程序的输出?

Posted

技术标签:

【中文标题】如何在 Inno Setup 中获取已执行程序的输出?【英文标题】:How to get an output of an Exec'ed program in Inno Setup? 【发布时间】:2010-11-11 07:52:15 【问题描述】:

是否可以获得Exec'ed 可执行文件的输出?

我想向用户显示一个信息查询页面,但在输入框中显示 MAC 地址的默认值。有没有其他方法可以做到这一点?

【问题讨论】:

【参考方案1】:

是的,使用将标准输出重定向到文件:

[Code]

function NextButtonClick(CurPage: Integer): Boolean;
var
  TmpFileName, ExecStdout: string;
  ResultCode: integer;
begin
  if CurPage = wpWelcome then begin
    TmpFileName := ExpandConstant('tmp') + '\ipconfig_results.txt';
    Exec('cmd.exe', '/C ipconfig /ALL > "' + TmpFileName + '"', '', SW_HIDE,
      ewWaitUntilTerminated, ResultCode);
    if LoadStringFromFile(TmpFileName, ExecStdout) then begin
      MsgBox(ExecStdout, mbInformation, MB_OK);
       do something with contents of file... 
    end;
    DeleteFile(TmpFileName);
  end;
  Result := True;
end;

请注意,可能有多个网络适配器,因此有多个 MAC 地址可供选择。

【讨论】:

请注意,与其硬编码“cmd.exe”,不如使用ExpandConstant('cmd')。 (当然,最好还是使用适当的 API,而不是尝试捕获控制台命令的输出,因为后者可能会在没有通知的情况下发生变化,因为它是为人类设计的。) 为了澄清:您需要通过命令提示符运行您的程序以获得重定向。我最初看了这个答案,很困惑为什么这对我不起作用,原因是我没有意识到重定向是命令提示符而不是窗口的功能,所以你需要在 cmd.exe /c 上执行 安装unicode,必须使用:var ExecStdout: AnsiString; 您不能直接将此技术与 powershell 一起使用,因为它会生成带有 BOM 的 utf16 文件名。 InnoSetup 似乎没有提供任何转换功能。 如果文件已经存在,会覆盖它吗?【参考方案2】:

我不得不这样做(执行命令行调用并获得结果)并想出了一个更通用的解决方案。

如果在实际调用中使用 /S 标志 cmd.exe,它还修复了一些奇怪的错误。

 Exec with output stored in result. 
 ResultString will only be altered if True is returned. 
function ExecWithResult(const Filename, Params, WorkingDir: String; const ShowCmd: Integer;
  const Wait: TExecWait; var ResultCode: Integer; var ResultString: String): Boolean;
var
  TempFilename: String;
  Command: String;
begin
  TempFilename := ExpandConstant('tmp\~execwithresult.txt');
   Exec via cmd and redirect output to file. Must use special string-behavior to work. 
  Command :=
    Format('"%s" /S /C ""%s" %s > "%s""', [
      ExpandConstant('cmd'), Filename, Params, TempFilename]);
  Result := Exec(ExpandConstant('cmd'), Command, WorkingDir, ShowCmd, Wait, ResultCode);
  if not Result then
    Exit;
  LoadStringFromFile(TempFilename, ResultString);   Cannot fail 
  DeleteFile(TempFilename);
   Remove new-line at the end 
  if (Length(ResultString) >= 2) and (ResultString[Length(ResultString) - 1] = #13) and
     (ResultString[Length(ResultString)] = #10) then
    Delete(ResultString, Length(ResultString) - 1, 2);
end;

用法:

Success :=
  ExecWithResult('ipconfig', '/all', '', SW_HIDE, ewWaitUntilTerminated,
    ResultCode, ExecStdout) or
  (ResultCode <> 0);

也可以将结果加载到TStringList 对象中以获取所有行:

Lines := TStringList.Create;
Lines.Text := ExecStdout;
 ... some code ... 
Lines.Free;

【讨论】:

非常感谢您提供如此详细的示例。显然,您解决了很多问题才能做到这一点,并为我节省了很多时间。我将它与tasklisttaskkill 一起使用,以在安装和卸载期间检测并终止正在运行的应用程序。 您的使用示例中的一个小问题:如果 Exec 成功但 ResultCode 0,则 ResultCode 将填写被调用程序的退出代码,而不是 windows 错误,因此 SysErrorMessage 不会得到正确的信息。此外,有时可以使用非零退出代码。我建议根据上下文单独测试 ResultCode。有关这种混乱的更多信息:github.com/jrsoftware/is-s-rc/issues/190. 是的,示例中的异常消息依赖于 windows exit-codes => msdn.microsoft.com/en-us/library/windows/desktop/ms681382.aspx 这是 GetLastError 返回的 MS error 代码的参考。 退出代码来自GetExitCodeProcess,不一定是同一件事。例如,ipconfig /? 不是错误,而是返回退出代码 1。如果您使用 ewNoWait 或 ewWaitUntilIdle,ResultCode 将始终为 259,这是 GetExitCodeProcess 函数的保留代码,意思是 STILL_ACTIVE。 好的,我删除了示例中的异常部分。这取决于无论如何实际做了什么。只是想表明结果传递给 InnoSetup 并且可以使用。

以上是关于如何在 Inno Setup 中获取已执行程序的输出?的主要内容,如果未能解决你的问题,请参考以下文章

inno setup 怎样检测程序已安装

Inno Setup 编译器”如何打包 javaWeb 应用程序,自动设置环境变量

如何用Inno Setup做更新程序

Inno Setup执行SQL脚本的方法

高分请教Inno Setup 编译器高手

将功能执行添加到 inno setup 的安装程序进度中