在安装过程中检测并需要Windows QFE /补丁

时间:2012-02-28 07:29:11

标签: c# .net windows wix windows-installer

我们的WiX安装程序将.NET 4.0 WinForms应用程序部署到Windows Vista和7台桌面。该应用包含Portable Class Library,需要.NET patch(KB2468871)。我们需要安装补丁作为先决条件。有多种方法可以应用补丁:

  1. 下载KB2468871补丁并安装
  2. 安装Portable Library Tools
  3. 作为使用ClickOnce的先决条件(可能是#1的变体)
  4. 使用来自a similar question的建议,我创建了一个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。

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

3 个答案:

答案 0 :(得分:13)

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

  

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

您所追求的更新是MSI补丁。使用 Microsoft.Deployment.WindowsInstaller (又名DTF - Deployment Tools FoundationWiX toolset的一部分)来查询应用的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

答案 1 :(得分:11)

我使用以下片段(使用@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 Extension。您需要在根元素中添加xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"并引用WixUtilExtension.dll

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

答案 2 :(得分:10)

我一直在玩类似的情况,发现@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}