Обнаруживать и требовать Windows QFE/patch во время установки
Наш установщик WiX развертывает приложение .NET 4.0 WinForms для Windows Vista и 7 настольных компьютеров. Приложение включает Portable Class Library, для которого требуется .NET patch (KB2468871). Мы должны установить исправление как необходимое условие. Существуют различные способы применения патча:
- Загрузите патч KB2468871 и установите его
- Установите Portable Library Tools
- В качестве предпосылки использования ClickOnce (может быть вариант # 1)
Используя совет аналогичный вопрос, я создал 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;
}
К сожалению, это не удается на моей машине dev, поскольку патч был установлен как часть инструментов (# 2). Я еще не видел ситуацию № 3.
Каков лучший способ определить, был ли применен патч?
Ответы
Ответ 1
Win32_QuickFixEngineering
не будет возвращать все обновления. Фактически, он возвращает только обновления, ограниченные QFE:
Обновления, предоставленные установщиком Microsoft Windows (MSI) или Windows сайта обновления (http://update.microsoft.com) не возвращаются Win32_QuickFixEngineering.
Обновление, которое вы используете, - это патч MSI. Используйте Microsoft.Deployment.WindowsInstaller
(aka DTF - Foundation Tools, часть Набор инструментов 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
Ответ 2
Я играл с подобной ситуацией и нашел, что @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}
Ответ 3
В случае, если кто-либо еще пытается это сделать в 2015 году, я достиг этого с помощью WiX Burn, используя следующий фрагмент (используя коды продуктов от @KMoraz):
<!-- 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
.