【问题标题】:Wix per user installer to detect the Visual C++ 2015 Redistributable每个用户安装程序使用 Wix 检测 Visual C++ 2015 Redistributable
【发布时间】:2019-05-07 09:26:42
【问题描述】:

我正在创建一个 .msi 安装程序,它必须确定系统中是否存在 Visual C++ 2015 Redistributable,如果没有,则使用自定义消息中断安装。官方 Wix 文档指的是 VC++ 的实际安装,我不希望这样做,因为我的安装程序是“每个用户”的,还有其他几个 stackoverflow 问题指的是捆绑包而不是 .msi http://wixtoolset.org/documentation/manual/v3/howtos/redistributables_and_install_checks/install_vcredist.htmlWix Burn vcredist, WIX check if VS2015 C++ redistributable is installed, https://gist.github.com/nathancorvussolis/6852ba282647aeb0c5c00e742e28eb48

所以我想问题是,如何在每个用户安装程序中有效地检测 Visual C++ 2015 Redistributable 的存在。

【问题讨论】:

  • 我想知道你是否可以通过static linking完全消除对运行时的依赖?不确定这是否有效。静态链接不是很好(丢失共享修复,尤其是安全修复),但有时它可以完成工作。如果您为您的应用程序提供定期更新,应该可以吗?为了测试,可能在原始虚拟机上运行。您也可以通过dependency scanners 偷看。
  • 不幸的是,这不是一个选项,因为需要 VC++ 的软件包来自第三方
  • 我越看这个,我就越想知道是否最糟糕的方法是检查 中的文件 vcruntime140.dll 的存在和版本System32 文件夹(64 位版本)和 SysWOW64 文件夹(32 位版本)?还有其他几种方法,我明天可能会进一步研究。 See files list towards bottom here.
  • 为了测试目的,这里有一个快速的 VBScript:Set fso = CreateObject("Scripting.FileSystemObject") : MsgBox fso.GetFileVersion("C:\Windows\System32\vcruntime140.dll")
  • 我添加了我写的答案。有点过头了,但我试图总结各种方法。还包括不好的选择——只是为了记住它们为什么不好。我会选择文件存在和版本检查

标签: wix windows-installer vcredist


【解决方案1】:

The latest supported Visual C++ downloads


运行时检测方法

我可以找到几种方法来检测 Visual C++ 运行时的存在。

  1. 注册表

  2. 文件存在和版本检查

    • 检查是否存在核心运行时文件
    • 请参阅下面的单独部分
  3. MSI API

    • 您可以通过查找产品 GUID 来检测是否安装了特定 MSI
    • 可靠,但难以跟踪所有产品 GUID(不同版本)
    • 更新:您也可以使用如下所述的升级代码。它应该在发布和更新之间保持稳定(对于每个主要版本,也可能在主要版本之间)。
  4. Fall-Over EXE?

    • 建议使用 EXE,具体取决于运行时
    • 启动它并失败意味着运行时不存在或损坏

好与坏 - 评估Option 1 似乎很容易受到攻击,因为部署运行时的合并模块变体可能不会编写这些键。 Option 3 可能运行良好,但很难跟踪所有 GUID。 Option 4 似乎已经失败,因为较新的运行时删除了某些注册表项。虽然现在已经修复,但它可能会重新出现。


文件版本存在/版本检查

我看的越多,我就越开始认为您必须检查实际文件本身,并可能检查正确的文件版本。 System32 文件夹(64 位版本)和 SysWOW64 文件夹(32 位版本)中的文件 vcruntime140.dllSee files list towards bottom here.

只是添加一个安全保存的链接。

测试 VBScript - 仅用于测试目的(脚本有时会被防病毒软件阻止):

Set fso = CreateObject("Scripting.FileSystemObject")
MsgBox fso.GetFileVersion("C:\Windows\System32\vcruntime140.dll")

您可以在 MSI 文件中使用 AppSearch 检测文件的存在和版本。


下面是我写的一些其他的东西,只是把它留在里面。


VCredist

似乎 Visual C++ Redistributable Packages (VCRedist_x86.exe, VCRedist_x64.exe) - 这是部署运行时的推荐方式- 检查以下注册表项以确定实际安装的运行时版本:

HKLM\SOFTWARE\Microsoft\VisualStudio\<version>\VC\Runtimes\

子键 x86x64 似乎都包含设置为 1 的“Installed”值strong> 安装运行时。我会假设 - 没有时间测试它 - 然后你可以检查:

  • HKLM\SOFTWARE\WOW6432Node\Microsoft\VisualStudio\14.0\VC\Runtimes\x64 Installed = 1
  • HKLM\SOFTWARE\WOW6432Node\Microsoft\VisualStudio\14.0\VC\Runtimes\x86 Installed = 1

合并模块:经过简单检查,这些值似乎不是由也可用于分发此运行时的合并模块写入的。我现在没有时间或方法来正确检查。

令人惊讶的是,2015 版和 2017 版运行时都写入了 14.0 密钥 - 因为它们是二进制兼容的。 如果安装了 2017 版,则 VCRedist 可执行文件将返回错误,因为不需要安装。确实很奇怪。但为了您的目的,这应该是无关紧要的。 Source.


MSI API - 检索产品代码


更新installer.ProductState - 正常安装状态是5

我在写以下内容时忘记了ProductState property。 您可以使用两行代码检查已安装的产品,如果您 有实际的产品代码:

Dim installer : Set installer = CreateObject("WindowsInstaller.Installer")
MsgBox installer.ProductState("{00000000-0000-0000-0000-000000000001}")

这里还有另一种方法:MSDN: How to programmatically check for the presence of a Windows Installer-based product by using its product code

提示:我不会使用这种方法,因为产品更新时产品代码会频繁更改。因此我更喜欢 检查核心运行时文件的文件版本。这似乎更 未来可靠(前提是版本解析正确完成 并且可靠——不要自己动手)。


样机

Public installer
Set installer = CreateObject("WindowsInstaller.Installer")

' Don't have the 2015 GUID
VC2015 = CheckForProductCode("{00000000-0000-0000-0000-000000000000}")
VC2017 = CheckForProductCode("{C77195A4-CEB8-38EE-BDD6-C46CB459EF6E}")
   
MsgBox "VC2015: " & CStr(VC2015) & vbCrLf & "VC2017: " &  CStr(VC2017)

Function CheckForProductCode(productcode)

   CheckForProductCode = False

    For Each product In installer.ProductsEx("", "", 7)   
        If(LCase(productcode) = LCase(product.ProductCode)) Then
            CheckForProductCode = True
            Exit For
        End If
    Next

End Function

基于Zett42's suggestion更新,列举共享相同升级代码的产品:

Set installer = CreateObject("WindowsInstaller.Installer")

' Enumerate all products related to "Microsoft Visual C++ 2008 Redistributable - x86 9.0.30729.4148"

' {AA783A14-A7A3-3D33-95F0-9A351D530011} is the upgrade code
Set upgrades = installer.RelatedProducts("{AA783A14-A7A3-3D33-95F0-9A351D530011}")
For Each u In upgrades
   MsgBox u, vbOKOnly, "Product Code: "
Next

部署 Visual Studio C++ 运行时

除了检测之外,还有多种分发 Visual Studio C++ 运行时的方法:

  1. 静态链接
  2. Visual C++ 可再发行包
    • VCRedist_x86.exeVCRedist_x64.exeVCRedist_arm.exe
    • Program Files(x86)\Microsoft Visual Studio\2017\edition\VC\Redist\MSVC\lib-version
  3. 可再发行的合并模块 (.msm files)
  4. 本地应用程序文件夹
    • 将 DLL 复制到本地应用程序文件夹
    • 出于维修原因(更新、安全修复),不推荐

安全保存链接


旧答案

有这个旧帖子。我不太喜欢直接读取注册表,让我看看我是否能找到更可靠的方法,但也许同时看看:Detect if Visual C++ Redistributable for Visual Studio 2012 is installed

再多一个链接,如何找到已安装产品的Windows Installer产品代码:How can I find the product GUID of an installed MSI setup?

【讨论】:

  • 检查 ProductCode 并不是检测 VC++ 运行时的好方法,因为 ProductCode 会随着每次小的更新而改变(不仅仅是在主要版本之间!)。您可以检查所有最新的产品代码,但您无法知道未来的产品代码。更好的方法是从 UpgradeCode 开始(更新之间是稳定的),然后调用 MsiEnumRelatedProducts 查找所有具有此 UpgradeCode 的产品。
  • 确保在MsiEnumRelatedProducts返回的产品上调用MsiQueryProductState(),因为后者有时会报告已经卸载的产品。只有当MsiQueryProductState() 返回INSTALLSTATE_DEFAULT 时,您才能确定给定的VC-Redist 已安装。您应该将已安装的 VC-Redist 版本与安装程序包含的版本进行比较,因为您的产品可能依赖于较新的版本。您可以拨打MsiGetProductInfo(productCode, INSTALLPROPERTY_VERSIONSTRING, ...)获取安装版本。
  • 是的,我同意。我想知道是否也有本地化版本的运行时——它们也可以有自己的产品 G​​UID。这个运行时一团糟?我希望随着时间的推移它成为操作系统的一部分。我的选择是文件检查以确保真正确定。
  • 有本地化包,但它们包含相同的 MSI 包。只有安装程序 UI 不同。
  • 我喜欢 UpgradeCode / RelatedProducts 的想法。我将链接到an existing sample of installer.RelatedProducts(UpgradeCode)。我也会内联代码示例。
【解决方案2】:

您可以使用 WiX 工具集中的LaunchConditions。检测可以通过RegistrySearch完成。

在 2015 版之前,它只是一个注册表项、GUID 值。从 2017 年到 2019 年,关键是 concat(合并),所以不再那么容易了。这就是我使用从 21 到 40 的循环来查找所有位置的方式。 C++ Runtime Documentation

将以下行添加到 product.wxs 内的 Product 元素中:

    ...

    <!-- Visual C++ Redistributable 2015, 2017 and 2019 (x86) -->
    <Property Id="CPPRUNTIME2015X86" Secure="yes">
      <!-- C++ 2015 -->
      <RegistrySearch Id="mfc140x86_23026" Root="HKLM" Key="SOFTWARE\Classes\Installer\Dependencies\{74d0e5db-b326-4dae-a6b2-445b9de1836e}" Type="raw" />
      <RegistrySearch Id="mfc140x86_24215" Root="HKLM" Key="SOFTWARE\Classes\Installer\Dependencies\{e2803110-78b3-4664-a479-3611a381656a}" Type="raw" />

      <!-- C++ 2017 -->
      <RegistrySearch Id="mfc1416x86" Root="HKCR" Key="Installer\Dependencies\VC,redist.x86,x86,14.16,bundle" Type="raw" />

      <!-- C++ 2019 -->
      <?foreach CPPRUNTIMEVERSIONPREFIX in 21;22;23;24;25;26;27;28;29;30;31;32;33;34;35;36;37;38;39;40?>
        <RegistrySearch Id="mfc14$(var.CPPRUNTIMEVERSIONPREFIX)x86" Root="HKCR" Key="Installer\Dependencies\VC,redist.x86,x86,14.$(var.CPPRUNTIMEVERSIONPREFIX),bundle" Type="raw" />
      <?endforeach ?>
    </Property>
    <Condition Message="Microsoft Visual C++ 2015-2019 (x86) Redistributable missing">
      <![CDATA[((REMOVE="ALL")) OR Installed]]>
    </Condition>

    <!-- Visual C++ Redistributable 2015, 2017 and 2019 (x64) -->
    <?if $(var.Platform) = x64 ?>
      <Property Id="CPPRUNTIME2015X64" Secure="yes">
        <!-- C++ 2015 -->
        <RegistrySearch Id="mfc140x64_23026" Root="HKLM" Key="SOFTWARE\Classes\Installer\Dependencies\{e46eca4f-393b-40df-9f49-076faf788d83}" Type="raw" />
        <RegistrySearch Id="mfc140x64_24215" Root="HKLM" Key="SOFTWARE\Classes\Installer\Dependencies\{d992c12e-cab2-426f-bde3-fb8c53950b0d}" Type="raw" />      

        <!-- C++ 2017 -->
        <RegistrySearch Id="mfc1416x64" Root="HKCR" Key="Installer\Dependencies\VC,redist.x64,amd64,14.16,bundle" Type="raw" />

        <!-- C++ 2019 -->
        <?foreach CPPRUNTIMEVERSIONPREFIX in 21;22;23;24;25;26;27;28;29;30;31;32;33;34;35;36;37;38;39;40?>
          <RegistrySearch Id="mfc14$(var.CPPRUNTIMEVERSIONPREFIX)x64" Root="HKCR" Key="Installer\Dependencies\VC,redist.x64,amd64,14.$(var.CPPRUNTIMEVERSIONPREFIX),bundle" Type="raw" />
        <?endforeach ?>
      </Property>
      <Condition Message="Microsoft Visual C++ 2015-2019 (x64) Redistributable missing">
        <![CDATA[((REMOVE="ALL")) OR Installed]]>
      </Condition>
    <?endif ?>

    ...

【讨论】:

  • 我在Stackoverflow上也找到了一个很好的答案,标题只涵盖了2012年,但是答案里面有很多C++ Runtime版本
猜你喜欢
  • 1970-01-01
  • 2017-10-27
  • 1970-01-01
  • 2012-08-25
  • 1970-01-01
  • 2019-02-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多