卸载修补程序

从 Windows Installer 3.0 开始,可以从应用程序中卸载某些修补程序。 修补程序必须是可卸载的修补程序。 使用低于版本 3.0 的 Windows Installer 时,移除修补程序需要卸载修补程序产品并重新安装产品,但不应用修补程序。

Windows Installer 2.0:不支持。 使用早于 Windows Installer 3.0 的 Windows Installer 版本应用的修补程序不可卸载。

通过以下任何方法调用修补程序卸载时,安装程序将尝试从请求卸载的应用程序或用户可见的第一个产品中移除修补程序。 安装程序按以下顺序搜索已修补的产品:每用户托管、每用户非托管、每计算机。

在命令行上使用 MSIPATCHREMOVE 卸载修补程序

可以使用 msiexec.exe 和命令行选项,通过命令来卸载修补程序。 以下示例命令行使用 MSIPATCHREMOVE 属性和 /i 命令行选项从应用程序 example.msi 中移除可卸载的修补程序 example.msp。 使用 /i 时,修补的应用程序可以通过应用程序软件包(.msi 文件)的路径或应用程序的产品代码来识别。 在此示例中,应用程序的安装包位于“\\server\share\products\example\example.msi”,应用程序的 ProductCode 属性为“{0C9840E7-7F0B-C648-10F0-4641926FE463}”。 修补程序包位于“\\server\share\products\example\patchs\example.msp”,修补程序代码 GUID 为“{EB8C947C-78B2-85A0-644D-86CEEF8E07C0}”。

Msiexec /I {0C9840E7-7F0B-C648-10F0-4641926FE463} MSIPATCHREMOVE={EB8C947C-78B2-85A0-644D-86CEEF8E07C0} /qb

使用标准命令行选项卸载修补程序

从 Windows Installer 3.0 版开始,可以使用 Microsoft Windows 操作系统更新 (update.exe) 使用的标准命令行选项从命令行卸载 Windows Installer 修补程序。

以下命令行是 Windows Installer 命令行的标准命令行,用于使用 MSIPATCHREMOVE 属性卸载修补程序。 与 /package 选项一起使用的 /uninstall 选项表示卸载修补程序。 修补程序可由修补程序的完整路径或修补程序代码 GUID 引用。

Msiexec /package {0C9840E7-7F0B-C648-10F0-4641926FE463} /uninstall {EB8C947C-78B2-85A0-644D-86CEEF8E07C0} /passive

注意

标准选项 /passive 与 Windows Installer 的 /qb 选项并不完全相同。

 

使用 RemovePatches 方法卸载修补程序

可以使用 Windows Installer 自动化接口从脚本中卸载修补程序。 以下脚本示例使用 Installer 对象的 RemovePatches 方法从应用程序 example.msi 中移除可卸载的修补程序 example.msp。 每个要卸载的修补程序都可以由修补程序包的完整路径或修补程序代码 GUID 表示。 在此示例中,应用程序的安装包位于“\\server\share\products\example\example.msi”,应用程序的 ProductCode 属性为“{0C9840E7-7F0B-C648-10F0-4641926FE463}”。 修补程序包位于“\\server\share\products\example\patchs\example.msp”,修补程序代码 GUID 为“{EB8C947C-78B2-85A0-644D-86CEEF8E07C0}”。

const msiInstallTypeSingleInstance = 2
const PatchList = "{EB8C947C-78B2-85A0-644D-86CEEF8E07C0}"
const Product = "{0C9840E7-7F0B-C648-10F0-4641926FE463}"

Dim installer
Set installer = CreateObject("WindowsInstaller.Installer")

installer.RemovePatches(PatchList, Product, msiInstallTypeSingleInstance, "")

使用添加/移除程序卸载修补程序

对于 Windows XP,可以使用添加/移除程序卸载修补程序。

使用 MsiRemovePatches 函数卸载修补程序

应用程序可以使用 Windows Installer 函数从其他应用程序卸载修补程序。 下面的代码示例使用 MsiRemovePatches 函数从应用程序example.msi 中移除可卸载的修补程序 example.msp。 可以通过修补程序包的完整路径或修补程序代码 GUID 来引用修补程序。 在此示例中,应用程序的安装包位于“\\server\share\products\example\example.msi”,应用程序的 ProductCode 属性为“{0C9840E7-7F0B-C648-10F0-4641926FE463}”。 修补程序包位于“\\server\share\products\example\patchs\example.msp”,修补程序代码 GUID 为“{EB8C947C-78B2-85A0-644D-86CEEF8E07C0}”。

    UINT uiReturn = MsiRemovePatches(
          /*szPatchList=*/TEXT("\\server\\share\\products\\example\\patches\\example.msp"),
          /*szProductCode=*/  TEXT("{0C9840E7-7F0B-C648-10F0-4641926FE463}"),
          /*eUninstallType=*/ INSTALLTYPE_SINGLE_INSTANCE,
          /*szPropertyList=*/ NULL);

使用 MsiRemovePatches 函数从所有应用程序卸载修补程序

单个修补程序可以更新计算机上的多个产品。 应用程序可以使用 MsiEnumProductsEx 枚举计算机上的所有产品,并确定修补程序是否已应用于产品的特定实例。 然后,应用程序可以使用 MsiRemovePatches 卸载修补程序。 例如,如果修补程序更新由多个产品共享的组件中的文件,并且分发修补程序以更新这两种产品,则单个修补程序可以更新多个产品。

以下示例演示应用程序如何使用 Windows Installer 从用户可用的所有应用程序中移除修补程序。 但对于其他用户的每用户安装应用程序,此示例并不会从中移除修补程序。

#ifndef UNICODE
#define UNICODE
#endif //UNICODE

#ifndef _WIN32_MSI
#define _WIN32_MSI 300
#endif //_WIN32_MSI

#include <stdio.h>
#include <windows.h>
#include <msi.h>

#pragma comment(lib, "msi.lib")

const int cchGUID = 38;

///////////////////////////////////////////////////////////////////
// RemovePatchFromAllVisibleapplications:
//
// Arguments:
//    wszPatchToRemove - GUID of patch to remove
//
///////////////////////////////////////////////////////////////////
//
UINT RemovePatchFromAllVisibleapplications(LPCWSTR wszPatchToRemove)
{
    if (!wszPatchToRemove)
        return ERROR_INVALID_PARAMETER;

    UINT uiStatus = ERROR_SUCCESS;
    DWORD dwIndex = 0;
    WCHAR wszapplicationCode[cchGUID+1] = {0};

    DWORD dwapplicationSearchContext = MSIINSTALLCONTEXT_ALL;
    MSIINSTALLCONTEXT dwInstallContext = MSIINSTALLCONTEXT_NONE;

    do
    {
        // Enumerate all visible applications in all contexts for the caller.
        // NULL for szUserSid defaults to using the caller's SID
        uiStatus = MsiEnumProductsEx(/*szapplicationCode*/NULL,
         /*szUserSid*/NULL,
         dwapplicationSearchContext,
         dwIndex,
         wszapplicationCode,
         &dwInstallContext,
         /*szSid*/NULL,
         /*pcchSid*/NULL);

        if (ERROR_SUCCESS == uiStatus)
        {
            // check to see if the provided patch is
            // registered for this application instance
            UINT uiPatchStatus = MsiGetPatchInfoEx(wszPatchToRemove,
             wszapplicationCode,
             /*szUserSid*/NULL,
             dwInstallContext,
             INSTALLPROPERTY_PATCHSTATE,
             NULL,
             NULL);

            if (ERROR_SUCCESS == uiPatchStatus)
            {
                // patch is registered to this application; remove patch
                wprintf(L"Removing patch %s from application %s...\n",
                 wszPatchToRemove, wszapplicationCode);
                                
                UINT uiRemoveStatus = MsiRemovePatches(
                 wszPatchToRemove,
                 wszapplicationCode,
                 INSTALLTYPE_SINGLE_INSTANCE,
                 L"");

                if (ERROR_SUCCESS != uiRemoveStatus)
                {
                    // This halts the enumeration and fails. Alternatively
                    // you could output an error and continue the
                    // enumeration
                     return ERROR_FUNCTION_FAILED;
                }
            }
            else if (ERROR_UNKNOWN_PATCH != uiPatchStatus)
            {
                // Some other error occurred during processing. This
                // halts the enumeration and fails. Alternatively you
                // could output an error and continue the enumeration
                 return ERROR_FUNCTION_FAILED;
            }
            // else patch was not applied to this application
            // (ERROR_UNKNOWN_PATCH returned)
        }

        dwIndex++;
    }
    while (uiStatus == ERROR_SUCCESS);

    if (ERROR_NO_MORE_ITEMS != uiStatus)
        return ERROR_FUNCTION_FAILED;

    return ERROR_SUCCESS;
}

修补程序序列化

移除修补程序

可卸载的修补程序

修补程序卸载自定义操作

MSIPATCHREMOVE

MsiEnumapplicationsEx

MsiGetPatchInfoEx

MsiRemovePatches