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 パッケージ情報をエクスポートするために使用できる 2 つのスクリプトを追加したいと思います: インストールされた MSI セットアップの製品 GUID を見つけるにはどうすればよいですか? -セクション 2で。

上記のリンクにアクセスしてください。ただし、スクリプトへの直接リンクがあります: html エクスポート バージョン、より単純なテキスト出力.1) 2)


免責事項:以下の情報は非常に「内部」です。MSI データベースにアクセスするには、可能な限り API 呼び出しを使用してください。また、「クリーンな状態」に簡単に戻せるように、すべての MSI テストを仮想マシンで実行することを忘れないでください。MSI の開発中に、奇妙なことが起こることがあります。


その製品の以前のアンインストールで、アンインストール時に何かが登録されたままになっている可能性があり、これがすべての問題の原因となっています。システムに登録されているものをスクリプトで確認しようとします。

ここで VBScript を使用して製品情報を取得することについての良い議論が見つかりました。いくつかの本当に優れたスクリプト -推奨. サイトにアクセスしてスクリプトを見つけてください。ここでは形式がかなり悪く、答えが詰まっています。

Windows インストーラ データベースは、主に次の場所にあります。

  • HKEY_CLASSES_ROOT\インストーラー\
  • アップグレード コード セクション: HKEY_CLASSES_ROOT\Installer\UpgradeCodes

Windows インストーラー データベース レジストリの内容に直接触れてはなりません。非常に相互に関連しており、破損しやすいです。API のみを使用します。レジストリ内の GUID はパックされているため、レジストリ内のパッケージからの GUID は見つからないことに注意してください。

  • パックされた GUID : 03B1692A57845354EA63AD602436AB05
  • 通常の GUID : {A2961B30-4875-4535-AE36-DA064263BA50}

上記の VBScript とレジストリ データを直接検査に使用すると、Windows インストーラ データベースで何が起きているかを判断できるはずです。

于 2014-03-18T03:32:53.670 に答える
2

パッケージ インストーラー (Microsoft SQL Server など) がある場合は、インストール フェーズ中に他の多くのアイテムをインストールできます。

後で、大きなパッケージのインストーラーをアンインストールするときに、インストーラーがシステムに追加したすべてのアイテムが理論的には削除されるはずです。

そのため、アプリケーションをアンインストールして停止し、他の小さなアプリケーションがまだシステム上にあるかどうかを確認してください。

そうである場合は、カスタム アンインストール スクリプトの開始時に、これらの個々のアプリケーションを最初にアンインストールする必要があります。

System.Configuration.Install.Installerクラスが既にあると仮定します。アプリケーションをインストールするときは一連の手順 (1、2、3 など) に従い、アプリケーションをアンインストールするときはこれらの手順を逆の順序で実行します (3、2、1)。

于 2014-03-19T18:38:10.550 に答える
2

Trying a new approach for you. I have located two products that seem to have at least two productcodes registered for their upgrade codes. They are: MSVC redistributable 2008 and MSXML 4.0 SP2. I have written a small C++ test that seems to work ok.

Essentially I think you need to check for ERROR_NO_MORE_ITEMS before the next iteration of the loop so you don't try to uninstall products that are no longer installed.

Here is some VS2013 code that should compile out of the box on a fresh install, empty project.


UPDATE: updated code to use VS2017 and a minimal console application.

  1. Create a new console project: File => New => Project... => Visual C++, Windows Desktop, Windows Console Application

  2. Paste the below code into the main CPP file (replacing whatever is there)

  3. Set a breakpoint and build & run (F5)

  4. F10 to step through

  5. If "Microsoft Visual C++ 2008 Redistributable" isn't installed, no related product codes will be found.


#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;
}

There could be erronously registered products on your system due to failed major upgrades or similar advanced error scenarios, so I am not sure if this solves your problem.

Keep in mind that the Windows Installer Database at HKEY_CLASSES_ROOT\Installer\UpgradeCodes contains packed GUIDs. You can try the VBScript code found in the following link to convert back and forth between packed and regular GUID formats: http://www.symantec.com/connect/blogs/guid-converter

More info on guid formats here if it is interesting: http://www.symantec.com/connect/articles/working-darwin-descriptors

// TEST DATA 2014 (guids in different formats):

// 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 に答える
2

これをテストするために C++ で直接作業することはありません。代わりに、 PowerShellまたはVBScriptを試して、アンインストール ルーチンの問題点を特定することで、複雑さを解消します。これらのスクリプト ツールの使用方法に関する情報は、このスレッドにあります。そして、ここに別のスレッドがあります。

  • 一部のアンインストールが機能するかどうかは明確ではなく、失敗するものがあるのか​​、それともアンインストール操作が完全に失敗するのか? それが最初の質問です。
  • 追加/削除からすべての製品を手動でアンインストールして、すべての製品が手動で正しくアンインストールされることを確認しましたか? 製品の 1 つがアンインストール中にエラー リターン コードをトリガーする可能性があります。これはプログラムでキャッチされますが、手動インストールでは無視されます。多くの場合、これらはInstallFinalizeの後に配置されたカスタム アクションからのものである可能性があります。この場合、セットアップの再設計が必要になります。最も単純なケースでは、カスタム アクションのエラー チェックを無効にする必要がありますが、その修正は私の意見では十分ではありません。
  • 製品がインストールされている可能性がありますが、ユーザーごとです。つまり、マシンではなく、マシン上の 1 人のユーザーに対してのみインストールされる可能性があります (これはALLUSERSプロパティによって制御されます)。この場合、この機能がどのように機能するかはわかりません-製品が宣伝されていると報告されることさえあります(ショートカットを介してオンデマンドでインストールできますが、実際にはインストールされません)。繰り返しますが、これは試していませんが、アンインストールはまだ機能する可能性があります。頭のてっぺんから、あなたにいくつかの指針を与えようとします。
  • 製品のインストールの一環として、既存の MSI ファイルのメジャー アップグレードを実行しましたか?

もう 1 つの質問: Windows 8 で実行していますか? また、これらの MSI ファイルは WIX またはその他のツールで生成されていますか? 少なくとも少し似ているように見える問題について、断続的なレポートがいくつかあります。

于 2014-03-18T01:47:52.237 に答える