8

我的产品有一个帮助程序可执行文件来卸载所有相关的子产品。我根据所有子产品的升级代码卸载。

首先,我使用MsiEnumRelatedProducts函数从升级代码中获取产品代码。然后我尝试使用MsiConfigureProductEx函数卸载产品。

问题MsiConfigureProductEx是返回错误。

调用函数:MsiConfigureProductsEx
返回代码:1605 (0x00000645)
说明:此操作仅对当前安装的产品有效。

为什么MsiEnumRelatedProducts返回无效的产品代码?我搜索了 Windows 注册表以查看是否存在此类产品代码。没有。如何调试问题?

编辑:添加了重现问题的最小代码。

// UpgradeCodes is an array having upgrade codes of all modules.

TCHAR lpProductCode[GUID_STR_LENGTH];
const TCHAR tszNoReboot[] = _T("REMOVE=ALL REBOOT=ReallySuppress DISABLE_REBOOT_PROMPT=1");

for (size_t i = 0; i < sizeof(UpgradeCodes) / sizeof(UpgradeCodes[0]); i++)
{
   tstring tstrUpgradeCode = UpgradeCodes[i];

   DWORD dwIndex = 0;
   size_t status;

   // for each of the upgrade code, get all the products
   do
   {
       status = MsiEnumRelatedProducts(UpgradeCodes[i], 
                                       0, 
                                       dwIndex, 
                                       lpProductCode);
       if (ERROR_SUCCESS == status)
       {
          UINT uiReturn = MsiConfigureProductEx(lpProductCode, 
                                                INSTALLLEVEL_DEFAULT, 
                                                INSTALLSTATE_DEFAULT, 
                                                tszNoReboot);

          if (ERROR_SUCCESS_REBOOT_REQUIRED == uiReturn)
          {
               // prompt for reboot at the end of all modules uninstallation.
          }

          if (ERROR_SUCCESS != uiReturn)
          {
              // log message with return code.

              // Error Code: 1605 is coming from here.
          }
       }
   }while (ERROR_NO_MORE_ITEMS != status);
}
4

4 回答 4

5

几年过去了,我想添加两个可用于导出 MSI 包信息的 scipt: 如何找到已安装的 MSI 设置的产品 G​​UID?- 在第 2 节中。

请访问上面的链接,但这里是脚本的直接链接: html 导出版本更简单的文本输出1) 2)


免责声明:以下信息非常“幕后”。请尽可能使用 API 调用来访问 MSI 数据库。还要记住在虚拟机上运行所有 MSI 测试,以便轻松恢复到“干净状态”。在 MSI 开发过程中可能会发生奇怪的事情。


可能是您之前卸载该产品时留下了一些在卸载时注册的内容,这导致了所有问题。我会尝试使用脚本检查系统上注册的内容。

在这里找到了关于使用 VBScript 检索产品信息的良好讨论,一些非常好的脚本 -推荐。去网站查找脚本,它们在这里的格式很差并且阻塞了答案。

Windows Installer 数据库主要位于此处:

  • HKEY_CLASSES_ROOT\Installer\
  • 升级代码部分:HKEY_CLASSES_ROOT\Installer\UpgradeCodes

您绝不能直接接触 Windows Installer 数据库注册表中的任何内容。它非常相互关联,很容易腐败。仅通过 API。请注意,注册表中的 GUID 已打包,因此您不会从注册表中的包中找到 GUID。

  • 打包的 GUID:03B1692A57845354EA63AD602436AB05
  • 常规 GUID:{A2961B30-4875-4535-AE36-DA064263BA50}

使用上面的 VBScripts 和直接检查注册表数据,您应该能够确定 Windows Installer 数据库中发生的情况。

于 2014-03-18T03:32:53.670 回答
2

我永远不会直接在 C++ 中工作来测试这一点。相反,我会通过尝试PowerShellVBScript来确定卸载例程有什么问题,从而消除一些复杂性。您可以在此线程中找到有关如何使用这些脚本工具的信息。这是另一个线程

  • 目前尚不清楚某些卸载是否有效,有一个失败或卸载操作是否完全失败?这是第一个问题。
  • 您是否尝试过从添加/删除中手动卸载所有产品以确保它们都手动正确卸载?其中一种产品可能会在卸载期间触发错误返回代码,该代码以编程方式捕获,但在手动安装期间被忽略。通常这些可以来自InstallFinalize之后放置的自定义操作。在这种情况下,需要重新设计一些设置。在最简单的情况下,它将涉及禁用自定义操作的错误检查,但我认为该修复还不够好。
  • 产品可能已安装,但每个用户. 换句话说,它可能只为机器上的单个用户安装,而不是为机器安装(这由ALLUSERS属性控制)。如果是这种情况,我不确定此功能如何工作 - 它甚至可能将产品报告为广告(可通过快捷方式按需安装,但未实际安装)。同样,我还没有尝试过,卸载可能仍然有效。只是在我的头顶尝试给你一些指示。
  • 作为产品安装的一部分,您是否对现有 MSI 文件进行了重大升级?

另一个问题:您在 Windows 8 上运行吗?这些 MSI 文件是用 WIX 还是其他工具生成的?有一些关于问题的断断续续的报告,这些问题至少看起来很相似

于 2014-03-18T01:47:52.237 回答
2

如果您有包安装程序(如 Microsoft SQL Server),它可以在安装阶段安装许多其他项目。

后来你去卸载大包安装程序的时候,安装程序添加到系统中的所有项目理论上都应该被删除。

因此,尝试卸载您的应用程序,停止,然后查看其他较小的应用程序是否仍在系统上。

如果是,那么您需要在自定义卸载脚本启动时先卸载这些单独的应用程序。

我假设您已经有一个System.Configuration.Install.Installer类。安装应用程序时遵循一组步骤(1、2、3 等),然后在卸载应用程序时按相反顺序执行这些步骤(3、2、1)。

于 2014-03-19T18:38:10.550 回答
2

为您尝试新方法。我找到了两种产品,它们似乎至少注册了两个产品代码作为升级代码。它们是:MSVC Redistributable 2008MSXML 4.0 SP2。我编写了一个小型 C++ 测试,似乎可以正常工作。

本质上,我认为您需要在循环的下一次迭代之前检查ERROR_NO_MORE_ITEMS,这样您就不会尝试卸载不再安装的产品。

这里有一些VS2013代码这应该在全新安装的空项目上开箱即用。


更新:更新代码以使用VS2017和最小控制台应用程序。

  1. 创建一个新的控制台项目:File => New => Project... => Visual C++, Windows Desktop, Windows Console Application

  2. 将以下代码粘贴到主 CPP 文件中(替换其中的任何内容)

  3. 设置断点并构建并运行 ( F5)

  4. F10穿过

  5. 如果没有安装“ Microsoft Visual C++ 2008 Redistributable ”,将找不到相关的产品代码。


#pragma once
#include "stdafx.h"

// The below should really be in stdafx.h (precompiled header)
#define WIN32_LEAN_AND_MEAN // Exclude stuff from Windows.h
#define STRICT
#include <windows.h>
#include <msi.h>

#pragma comment(lib, "msi.lib") // To make code link

int main()
{
    UINT i = 0;
    UINT status = ERROR_SUCCESS;
    TCHAR productcode[39] = {};

    const TCHAR upgradecode[39] = L"{AA783A14-A7A3-3D33-95F0-9A351D530011}"; //Microsoft Visual C++ 2008 Redistributable
    //const TCHAR upgradecode[39] = L"{7CE723E3-E56B-432C-9F24-78C0606045A5}"; // MSXML 4.0 SP2 (KB973688)

    do
    {
        // look up (related) product code(s) for specified upgrade code
        status = MsiEnumRelatedProducts(upgradecode, 0, i, productcode);

        if (status == ERROR_NO_MORE_ITEMS) // Test here. 259, ERROR_NO_MORE_ITEMS
        {
            // No more productcodes for specified upgrade code
            MessageBox(NULL, L"No more productcodes", L"Done", MB_OK);

            break;  // exit do-while loop
        }

        i++; // Next product code

        MessageBox(NULL, productcode, L"Product Code:", MB_OK);

    } while (status != ERROR_NO_MORE_ITEMS);

    return 0;
}

由于重大升级失败或类似的高级错误情况,您的系统上可能存在错误注册的产品,所以我不确定这是否能解决您的问题。

请记住,位于HKEY_CLASSES_ROOT\Installer\UpgradeCodes的 Windows Installer 数据库包含打包的 GUID。您可以尝试使用以下链接中的 VBScript 代码在打包和常规 GUID 格式之间来回转换:http ://www.symantec.com/connect/blogs/guid-converter

如果感兴趣,请在此处了解有关 guid 格式的更多信息:http ://www.symantec.com/connect/articles/working-darwin-descriptors

// 2014 年测试数据(不同格式的指南):

// UpgradeCode
    // 41A387AA3A7A33D3590FA953D1350011 => {AA783A14-A7A3-3D33-95F0-9A351D530011}
    // 
// ProductCode
    //
    // Microsoft Visual C++ 2008 Redistributable - x86 9.0.30729.4148
    // CFD2C1F142D260E3CB8B271543DA9F98 => {1F1C2DFC-2D24-3E06-BCB8-725134ADF989}
    //
    // Microsoft Visual C++ 2008 Redistributable - x86 9.0.30729.17
    // D20352A90C039D93DBF6126ECE614057 => {9A25302D-30C0-39D9-BD6F-21E6EC160475}


// UpgradeCode
    // 3E327EC7B65EC234F942870C0606545A => {7CE723E3-E56B-432C-9F24-78C0606045A5}
    // 
// ProductCode
    // 
    // MSXML 4.0 SP2 (KB973688)
    // 6E8A266FCD4F2A1409E1C8110F44DBCE => {F662A8E6-F4DC-41A2-901E-8C11F044BDEC}

    // MSXML 4.0 SP2 (KB954430)
    // DDA39468D428E8B4DB27C8D5DC5CA217 => {86493ADD-824D-4B8E-BD72-8C5DCDC52A71}
于 2014-03-25T04:32:05.060 回答