在安装期间检测并要求安装Windows QFE /补丁程序

我们的WiX安装程序将.NET 4.0 WinForms应用程序部署到Windows Vista和7个桌面。 该应用程序包括一个需要.NET补丁的可移植类库 (KB2468871)。 我们需要安装补丁作为先决条件。 修补程序有多种应用方式:

  1. 下载KB2468871补丁并安装它
  2. 安装便携式库工具
  3. 作为使用ClickOnce的先决条件(可能是#1的变体)

使用类似问题的build议,我创build了一个CustomAction来检查我发现的QFE(#1)是否返回true。

 private static bool IsPatchAlreadyInstalled() { // If the patch is installed, we can find it using WMI var query = new SelectQuery("SELECT HotFixID FROM Win32_QuickFixEngineering WHERE HotFixID = 'Q2468871' OR HotFixID = 'KB2468871'"); var results = new ManagementObjectSearcher(query).Get(); return results.Count > 0; } 

不幸的是,由于该补丁是作为工具(#2)的一部分安装的,所以在我的开发机器上失败了。 我还没有目睹情况#3。

什么是更好的方法来检测补丁是否已经被应用?

Win32_QuickFixEngineering不会返回所有更新。 实际上,它只返回限于QFE的更新:

Win32_QuickFixEngineering不会返回由Microsoft Windows Installer(MSI)或Windows更新站点(http://update.microsoft.com)提供的更新。

你之后的更新是MSI补丁。 使用Microsoft.Deployment.WindowsInstaller (又名DTF – 部署工具基础 ,是WiX工具集的一部分)查询应用的MSI补丁:

 public static bool IsPatchAlreadyInstalled(string productCode, string patchCode) { var patches = PatchInstallation.GetPatches(null, productCode, null, UserContexts.Machine, PatchStates.Applied); return patches.Any(patch => patch.DisplayName == patchCode); } 

在这种情况下,KB2468871是.NET Framework 4更新之一。 如果在机器上应用了更新,以下内容将返回true:

 IsPatchAlreadyInstalled("{F5B09CFD-F0B2-36AF-8DF4-1DF6B63FC7B4}", "KB2468871");// .NET Framework 4 Client Profile 64-bit IsPatchAlreadyInstalled("{8E34682C-8118-31F1-BC4C-98CD9675E1C2}", "KB2468871");// .NET Framework 4 Extended 64-bit IsPatchAlreadyInstalled("{3C3901C5-3455-3E0A-A214-0B093A5070A6}", "KB2468871");// .NET Framework 4 Client Profile 32-bit IsPatchAlreadyInstalled("{0A0CADCF-78DA-33C4-A350-CD51849B9702}", "KB2468871");// .NET Framework 4 Extended 32-bit 

我一直在玩类似的情况,发现@KMoraz的答案几乎是正确的。 (注意:@KMoraz,我会留下这个评论,但还没有代表!)

Microsoft.Deployment.WindowsInstaller命名空间似乎是要走的路,但按产品代码过滤可能太严格了。 我遇到了将补丁安装在机器上的问题,但与产品代码{F5B09CFD-F0B2-36AF-8DF4-1DF6B63FC7B4}{8E34682C-8118-31F1-BC4C-98CD9675E1C2}

我的解决方案是使用PatchInstallation.AllPatches ,它返回系统上未经过滤的已安装补丁列表,然后使用linq查找答案。

 public static bool CheckForPatch() { return IsPatchAlreadyInstalled("KB2468871") } public static bool IsPatchAlreadyInstalled(string patchCode) { var patches = PatchInstallation.AllPatches.ToList(); patches.ForEach(x => Console.WriteLine("--found patch {0} for {1}",x.DisplayName,x.ProductCode)); return patches.Any(patch => patch.DisplayName == patchCode); } 

示例输出:

 --found patch Microsoft Office 2010 Service Pack 1 (SP1) for {90140000-001F-0409-0000-0000000FF1CE} --found patch Update for Microsoft Office 2010 (KB2553270) 32-Bit Edition for {90140000-001F-0409-0000-0000000FF1CE} --found patch Microsoft Office 2010 Service Pack 1 (SP1) for {90140000-001F-0C0A-0000-0000000FF1CE} --found patch Update for Microsoft Office 2010 (KB2553270) 32-Bit Edition for {90140000-001F-0C0A-0000-0000000FF1CE} --found patch Microsoft Office 2010 Service Pack 1 (SP1) for {90140000-001F-040C-0000-0000000FF1CE} --found patch Update for Microsoft Office 2010 (KB2553270) 32-Bit Edition for {90140000-001F-040C-0000-0000000FF1CE} --found patch KB2533523 for {3C3901C5-3455-3E0A-A214-0B093A5070A6} --found patch KB2518870 for {3C3901C5-3455-3E0A-A214-0B093A5070A6} --found patch KB2656351 for {3C3901C5-3455-3E0A-A214-0B093A5070A6} --found patch KB2633870 for {3C3901C5-3455-3E0A-A214-0B093A5070A6} --found patch KB2468871 for {3C3901C5-3455-3E0A-A214-0B093A5070A6} --found patch KB2572078 for {3C3901C5-3455-3E0A-A214-0B093A5070A6} --found patch KB2533523 for {0A0CADCF-78DA-33C4-A350-CD51849B9702} --found patch KB2656351 for {0A0CADCF-78DA-33C4-A350-CD51849B9702} --found patch KB2468871 for {0A0CADCF-78DA-33C4-A350-CD51849B9702} --found patch KB2487367 for {0A0CADCF-78DA-33C4-A350-CD51849B9702} 

如果其他人仍然在2015年尝试这样做,我使用以下片段(使用来自@KMoraz的产品代码)使用WiX Burn实现此目的:

 <!-- KB2468871 update to support portable class libraries (PCL) on XP --> <Fragment> <!-- codes from http://stackoverflow.com/a/9506530 --> <util:ProductSearch ProductCode="{0A0CADCF-78DA-33C4-A350-CD51849B9702}" Variable="KB2468871_NET32_Installed" /> <util:ProductSearch ProductCode="{8E34682C-8118-31F1-BC4C-98CD9675E1C2}" Variable="KB2468871_NET64_Installed" /> <PackageGroup Id="NDP40_KB2468871_v2"> <ExePackage Id="NDP40_KB2468871_v2_x86" Compressed="no" Vital="yes" Permanent="yes" SourceFile="NDP40-KB2468871-v2-x86.exe" DownloadUrl="http://download.microsoft.com/download/2/B/F/2BF4D7D1-E781-4EE0-9E4F-FDD44A2F8934/NDP40-KB2468871-v2-x86.exe" DetectCondition="KB2468871_NET32_Installed" InstallCondition="NOT VersionNT64" InstallCommand="/q"/> <ExePackage Id="NDP40_KB2468871_v2_x64" Compressed="no" Vital="yes" Permanent="yes" SourceFile="NDP40-KB2468871-v2-x86.exe" DownloadUrl="http://download.microsoft.com/download/2/B/F/2BF4D7D1-E781-4EE0-9E4F-FDD44A2F8934/NDP40-KB2468871-v2-x64.exe" DetectCondition="KB2468871_NET64_Installed" InstallCondition="VersionNT64" InstallCommand="/q"/> </PackageGroup> </Fragment> 

util命名空间是指Wix Util扩展 。 您需要在根元素中使用xmlns:util="http://schemas.microsoft.com/wix/UtilExtension" ,并且需要对WixUtilExtension.dll的引用。

如果需要,安装程序将自动下载。 您需要将安装程序文件保存在您的WiX项目的根目录中,其名称与SourceFile指定的名称相同,但它们不会被添加到安装程序包,因为Compressed设置为no