每个用户安装程序都需要Wix来检测Visual C ++ 2015 Redistributable

时间:2018-12-05 18:28:46

标签: wix vcredist

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

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

2 个答案:

答案 0 :(得分:2)

运行时检测方法

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

  1. 注册表

  2. 文件状态和版本检查

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

    • 您可以通过查找产品GUID来检测是否安装了特定的MSI
    • 可靠但难以跟踪所有产品GUID(不同版本)
    • 更新:您还可以按照以下说明使用升级代码。在各个发行版和更新中(对于每个主要版本,甚至可能在主要版本之间),它都应保持稳定。
  4. Fall-over EXE?

    • 建议根据运行时使用EXE
    • 启动它并失败意味着运行时不存在或损坏

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


文件版本存在/版本检查

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

只需添加一个链接即可保存。

测试VBScript-仅用于测试目的:

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

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


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


VCRedist

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

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

x86 x64 子项似乎都包含一个设置为 1 的“ 已安装”值。 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-检索产品代码

样机

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.exe VCRedist_x64.exe VCRedist_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?

答案 1 :(得分:0)

您可以使用WiX Toolset中的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 ?>

    ...