卸载软件

时间:2013-10-31 01:22:23

标签: windows winapi windows-installer installer

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

首先,我使用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 个答案:

答案 0 :(得分:4)

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

在这里找到了使用VBScript检索产品信息的良好讨论,一些非常好的脚本 - 推荐。去网站找到脚本,这里的格式非常糟糕并且堵塞了答案。

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

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

您绝不能直接触摸Windows Installer数据库注册表中的任何内容。它非常互联且容易损坏。只通过API。请注意,注册表中的GUID是打包的,因此您将无法在注册表中找到包中的GUID。

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

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

答案 1 :(得分:2)

我绝不会直接用C ++来测试它。相反,我会通过尝试 PowerShell VBScript 来确定卸载例程的错误,从而消除一些复杂性。您可以在this thread中找到有关如何使用这些脚本工具的信息。 here是另一个主题。

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

还有一个问题:你在Windows 8上运行吗?这些MSI文件是用WIX还是其他工具生成的?关于problems that appear at least remotely similar已经有一些间歇性的报道。

答案 2 :(得分:2)

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

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

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

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

我假设您已经有System.Configuration.Install.Installer课程。安装应用程序时需要执行一系列步骤(1,2,3等),然后在卸载应用程序时以相反的顺序执行这些步骤(3,2,1)。

答案 3 :(得分:1)

为您尝试新方法。我找到了两个似乎至少有两个产品代码注册其升级代码的产品。它们是: MSVC可再发行2008 MSXML 4.0 SP2 。我写了一个小的C ++测试似乎没问题。

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

以下是一些 VS2013代码 ,它应该在全新安装的空项目中开箱即用。


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

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

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

  3. 设置断点并构建&amp;跑( F5

  4. F10 逐步完成

  5. 如果&#34; Microsoft Visual C ++ 2008 Redistributable &#34;未安装,未找到相关的产品代码。


  6. #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

    // TEST DATA 2014(不同格式的guids):

    // 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}