Windows 卸载软件

Windows 卸载软件,windows,winapi,windows-installer,installation,Windows,Winapi,Windows Installer,Installation,我的产品有一个帮助程序可执行文件来卸载所有相关的子产品。我根据所有子产品的升级代码卸载 首先,我使用函数从升级代码中获取产品代码。然后我尝试使用函数卸载产品 问题是msconfigureproductex返回错误 调用的函数:MsiConfigureProductsEx 返回代码:1605(0x00000645) 描述:此操作仅对当前安装的产品有效 为什么MsiEnumRelatedProducts返回无效的产品代码?我在windows注册表中搜索,看看是否存在这样的产品代码。没有。如何调试该问

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

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

问题是
msconfigureproductex
返回错误

调用的函数: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);
}
//UpgradeCodes是一个包含所有模块升级代码的数组。
TCHAR lpProductCode[GUID_STR_LENGTH];
const TCHAR tszNoReboot[]=“删除=所有重新启动=ReallySuppress禁用重新启动\提示=1”);
对于(size_t i=0;i<>代码>我不会直接在C++中测试这个。相反,我会通过尝试PowerShellVBScript来确定卸载例程的错误,从而消除一些复杂性。您可以在中找到有关如何使用这些脚本工具的信息。这是另一条线

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

还有一个问题:您是否在Windows 8上运行?这些MSI文件是用WIX或其他工具生成的吗?有一些关于的断断续续的报告。

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

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

Windows Installer数据库主要位于以下位置:

  • HKEY\U CLASSES\U ROOT\Installer\
  • 升级代码部分:HKEY\U CLASSES\U ROOT\Installer\UpgradeCodes
您绝对不能直接接触Windows Installer数据库注册表中的任何内容。它的相互关联性非常强,很容易损坏。只需浏览API。请注意,注册表中的guid是打包的,因此您无法从注册表中的包中找到guid

  • 压缩GUID:03B1692A57845354EA63AD602436AB05
  • 常规GUID:{A2961B30-4875-4535-AE36-DA064263BA50}

使用上面的VBScript和注册表数据直接进行检查,您应该能够确定Windows Installer数据库中发生了什么。

如果您有软件包安装程序(如Microsoft SQL Server),它可以在安装阶段安装大量其他项

稍后,当您卸载大软件包安装程序时,理论上应该删除安装程序添加到系统中的所有项目

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

如果是,则需要在自定义卸载脚本启动时首先卸载这些应用程序

我想你已经有课了。安装a时,请遵循一组步骤
#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;
}
// 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}