从 运行 MSI 包获取 "setup.exe" 的路径

Get path of "setup.exe" from running MSI package

是否可以从自定义操作中获取启动 MSI 安装的可执行包(又名引导程序)的路径?

获取 DLL 父进程的常规方法不起作用,因为自定义操作 DLL 是由 "msiexec.exe" 加载的,而不是由 bootstrapper.exe 加载的。 "msiexec.exe" 的父进程是 "services.exe",所以这也无济于事。

Msiexec.exe 似乎知道调用过程,因为它将这一行写入日志文件:

=== Verbose logging started: [blah...] Calling process: C:\temp\testsetup.exe ===

不过我找不到任何 API 来查询此信息。我调查了 property reference and installer functions.

假设您的 setup.exe 与 MSI 文件位于同一位置,SourceDir 属性 会告诉您安装 MSI 的文件夹。 OriginalDatabase 属性 告诉您 MSI 文件的完整路径。

https://msdn.microsoft.com/en-us/library/windows/desktop/aa371857(v=vs.85).aspx

如果 setup.exe 实际上从众所周知的位置启动 MSI 文件,它可能是其他标准属性之一,例如 TempFolder。但是没有理由不能将文件夹传递到 MSI 安装中。如果您在名为(例如)MYFOLDER 的 MSI 中声明 public 安全 属性,则只需使用包含 MYFOLDER=[路径名]

的命令行启动 MSI

我假设您知道如何从自定义操作中获取 属性 值。

从可能会被删除的临时位置安装 MSI 不是一个好主意。建议保持 MSI 可用,规则 31:

https://blogs.msdn.microsoft.com/windows_installer_team/2006/05/24/tao-of-the-windows-installer-part-3/

我们最终修改了引导程序 setup.exe 以将其自己的路径传递给 MSI 包。

  1. Bootstrapper 调用 GetModuleFileName 来确定自己的路径。
  2. Bootstrapper 调用 MsiInstallProduct,将路径作为命令行参数传递。

    std::wstring cmdLine = L"BOOTSTRAPPER_PATH=\"" + executablePath + L"\"";
    MsiInstallProduct( msiFilePath.c_str(), cmdLine.c_str() );
    
  3. 自定义操作调用MsiGetProperty读取BOOTSTRAPPER_PATH的值。