卸载软件

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

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

问题是MsiConfigureProductEx正在返回错误。

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

为什么MsiEnumRelatedProducts返回无效的产品代码? 我通过Windowsregistrysearch,看看是否存在这样的产品代码。 没有任何 如何debugging该问题?

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

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

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

用VBScript在这里找到了很好的关于检索产品信息的讨论, 推荐了几个非常好的脚本。 去网站找到脚本,他们在这里格式很差,堵塞答案。

Windows安装程序数据库大多位于此处:

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

您绝对不能直接触摸Windows Installer数据库注册表中的任何内容。 这是非常相互联系,容易腐败。 只能通过API。 请注意,注册表中的GUID是打包的,因此您将无法从注册表中找到包中的GUID。

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

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

我绝不会直接用C ++来测试。 相反,我会通过尝试使用PowerShellVBScript来确定卸载例程的错误,从而消除一些复杂性。 你可以在这里找到关于如何使用这些脚本工具的信息。 是另一个线程。

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

还有一个问题 :你在Windows 8上运行吗? 这些MSI文件是用WIX或其他工具生成的吗? 有些问题的间歇性报告至少在远程方面类似 。

如果您有软件包安装程序(如Microsoft SQL server),则可以在其安装阶段安装其他项目的主机。

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

所以,试着卸载你的应用程序,停下来,然后看看其他小应用程序是否仍然在系统上。

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

我假设你已经有一个System.Configuration.Install.Installer类。 安装应用程序(1,2,3等)时按照一系列步骤操作,然后在卸载应用程序(3,2,1)时按相反的顺序执行这些步骤。

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

本质上,我认为你需要在循环的下一次迭代之前检查ERROR_NO_MORE_ITEMS ,所以你不要试图卸载不再安装的产品。

下面是一些VS2013代码 ,应该在新安装的空白项目中进行编译:

 #pragma once #include "stdafx.h" #include <msi.h> #pragma comment(lib, "msi.lib") int _tmain(int argc, _TCHAR* argv[]) { UINT i = 0; UINT status; char productCode[255]; // LPCTSTR upgradecode = TEXT("{AA783A14-A7A3-3D33-95F0-9A351D530011}"); //Microsoft Visual C++ 2008 Redistributable LPCTSTR upgradecode = TEXT("{7CE723E3-E56B-432C-9F24-78C0606045A5}"); // MSXML 4.0 SP2 (KB973688) do { // look up product code 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, TEXT("No more productcodes"), TEXT("Done"), MB_OK); break; // exit do-while loop } i++; // Next product code MessageBox(NULL, productCode, "Product Code:", MB_OK); } while (status != ERROR_NO_MORE_ITEMS); return 0; } 

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

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

有关guid格式的更多信息,请参阅http://www.symantec.com/connect/articles/working-darwin-descriptors

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

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