我正在创建一个.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 vcredist,WIX check if VS2015 C++ redistributable is installed,https://gist.github.com/nathancorvussolis/6852ba282647aeb0c5c00e742e28eb48
所以我想问题是,如何在每个用户安装程序中有效地检测Visual C ++ 2015 Redistributable的存在。
答案 0 :(得分:2)
我可以找到几种方法来检测 Visual C ++运行时的存在。
注册表
文件状态和版本检查
MSI API
Fall-over 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 检测文件的存在和版本。
下面是我写的其他一些东西,只是留在里面。
似乎是 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。
样机 :
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 ++运行时的方法:
VCRedist_x86.exe
, VCRedist_x64.exe
或 VCRedist_arm.exe
Program Files(x86)\Microsoft Visual Studio\2017\edition\VC\Redist\MSVC\lib-version
.msm files
)
安全保存链接 :
有此旧帖子。我不太喜欢直接读取注册表,请让我看看是否可以找到更可靠的方法,但同时请看一下: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 ?>
...