インストール上の別のMSIをアンインストールします
-
18-09-2019 - |
質問
私は、基本のMSIプロジェクトを持っています。私は今、私たちの主なアプリケーションに統合され、インストールに別のMSI製品を削除する必要があります。私は、アップグレードシナリオを使用してメジャーアップグレードとして扱うことを試みました。しかし、これは、アップグレードコードは、私は信じて一致していないと動作しませんでした。
次は、私も(私はこれのInstallShieldヘルプで述べたと思います。)私は、私が探していたインストーラを持っていなかったシステムにインストールされるまで、これは完全に働いたCostFinalizeの後のmsiexec.exeを実行したカスタムアクションを作りました削除する。他の時代遅れの製品がインストールされていない場合は私のインストーラが失敗します。私は、システムの検索によって設定されたカスタムアクションに条件を入れてみましたが、システムの検索が機能に制限があるようです。私はちょうどREGキーをチェックして、ブール値プロパティを設定することはできません。
任意のアイデア?
解決
考慮すべきいくつかのこと。
1)UpgradeTable(FindRelatedProducts / RemoveExisting製品)は、別の製品ののUpgradeCodeに関連付けProductCodesを除去するために使用することができます。
メモリが提供している場合、2)、MSI)は、マシンごとのインストール時にユーザ単位の製品を削除(あるいは他の方法で回避しません。コンテキストが同じである必要があります。
3)UIシーケンスはサイレントインストール時に実行されません。
唯一のマシンごとのシーケンスを実行するシステム全体のミューテックスがありますので、4)あなたは、実行シーケンスからのmsiexec実行することはできません。
あなたはUIにスケジュールする場合は、5)(私はすでにプロセスあたりわずか1 UIを言い、別のミューテックスがある)あなたはそれがサイレントインストール中に実行されないべきではないので、ということを言っています。
あなたは、ユーザーごとのユーザごとまたはごとのマシンごとにマシンにしようとしている場合は、、私はそれはあなたがカスタムアクションを記述することなくアップグレード要素/テーブルの行を使用してやりたいことができるはずreasonaableだと思うだろう。そうしないと、前のmsiexecの世界に入るにアンインストールを処理するためのsetup.exeスタイルのブートストラップが必要になります。
他のヒント
私は、カスタムのInstallScriptを使用してのInstallShield 2013年にこれを達成しました。このスクリプトは、UIシーケンスにカスタムアクションを介して実行、私は(ドキュメントが言うんよう)「アクションを実行」する前に代わりのCostFinalizeの後に「SetupProgress」ダイアログ、すなわち後にそれを置いています。私はアクションに「インストールされていない」状態を追加しました。あなたが提案の順序でこれを配置すると、それはすぐにインストーラが初期化されているように、アンインストールをキックオフします。あなたは私がしたところに移動した場合、ユーザは、最終的な今すぐインストール]ボタンをクリックするまで、それがキックオフされません。
UIシーケンスでこれを置く理由は時間の問題に一つのMSIインストーラ(またはアンインストーラ)を回避することです。これは、単にそのせいで制限の実行順序では動作しません。
この方法の主な弱点は、クリストファーが述べたように、これはサイレントインストール(それはまた、ISのマニュアルを参照している)で動作しないことです。つまり、このかかわらを達成するための正式な手段です。 (チェックアウト: http://helpnet.installshield.com/installshield16helplib/IHelpCustomActionMSIExec.htmする )サイレントインストールは、一般的に、特殊なケースのシナリオであるので、あなたが)(それと一緒に暮らすことができる場合、これはうまく動作します。
クリスも言ったように、主UIが実行されている間、あなたはアンインストーラのUIを起動することはできませんが、それは(すなわち黙っ)UIなしでアンインストーラを実行するためのコマンドラインスイッチを追加しますので、それは私のスクリプトに問題はありません。
私のスクリプトは、アンインストールするアプリケーションのGUIDを知っている必要がなくなります。ここでは、カスタムアクションにバインドするためのスクリプトは、(UninstallPriorVersionsは、エントリポイント関数である)です。
////////////////////////////////////////////////////////////////////////////////
//
// This template script provides the code necessary to build an entry-point
// function to be called in an InstallScript custom action.
//
//
// File Name: Setup.rul
//
// Description: InstallShield script
//
////////////////////////////////////////////////////////////////////////////////
// Include Ifx.h for built-in InstallScript function prototypes, for Windows
// Installer API function prototypes and constants, and to declare code for
// the OnBegin and OnEnd events.
#include "ifx.h"
// The keyword export identifies MyFunction() as an entry-point function.
// The argument it accepts must be a handle to the Installer database.
export prototype UninstallPriorVersions(HWND);
// To Do: Declare global variables, define constants, and prototype user-
// defined and DLL functions here.
prototype NUMBER UninstallApplicationByName( STRING );
prototype NUMBER GetUninstallCmdLine( STRING, BOOL, BYREF STRING );
prototype STRING GetUninstallKey( STRING );
prototype NUMBER RegDBGetSubKeyNameContainingValue( NUMBER, STRING, STRING, STRING, BYREF STRING );
// To Do: Create a custom action for this entry-point function:
// 1. Right-click on "Custom Actions" in the Sequences/Actions view.
// 2. Select "Custom Action Wizard" from the context menu.
// 3. Proceed through the wizard and give the custom action a unique name.
// 4. Select "Run InstallScript code" for the custom action type, and in
// the next panel select "MyFunction" (or the new name of the entry-
// point function) for the source.
// 5. Click Next, accepting the default selections until the wizard
// creates the custom action.
//
// Once you have made a custom action, you must execute it in your setup by
// inserting it into a sequence or making it the result of a dialog's
// control event.
///////////////////////////////////////////////////////////////////////////////
//
// Function: UninstallPriorVersions
//
// Purpose: Uninstall prior versions of this application
//
///////////////////////////////////////////////////////////////////////////////
function UninstallPriorVersions(hMSI)
begin
UninstallApplicationByName( "The Name Of Some App" );
end;
///////////////////////////////////////////////////////////////////////////////
//
// Function: UninstallApplicationByName
//
// Purpose: Uninstall an application (without knowing the guid)
//
// Returns: (UninstCmdLine is assigned a value by referrence)
// >= ISERR_SUCCESS The function successfully got the command line.
// < ISERR_SUCCESS The function failed to get the command line.
//
///////////////////////////////////////////////////////////////////////////////
function NUMBER UninstallApplicationByName( AppName )
NUMBER nReturn;
STRING UninstCmdLine;
begin
nReturn = GetUninstallCmdLine( AppName, TRUE, UninstCmdLine );
if( nReturn < ISERR_SUCCESS ) then
return nReturn;
endif;
if( LaunchAppAndWait( "", UninstCmdLine, LAAW_OPTION_WAIT) = 0 ) then
return ISERR_SUCCESS;
else
return ISERR_SUCCESS-1;
endif;
end;
///////////////////////////////////////////////////////////////////////////////
//
// Function: GetUninstallCmdLine
//
// Purpose: Get the command line statement to uninstall an application
//
// Returns: (UninstCmdLine is assigned a value by referrence)
// >= ISERR_SUCCESS The function successfully got the command line.
// < ISERR_SUCCESS The function failed to get the command line.
//
///////////////////////////////////////////////////////////////////////////////
function NUMBER GetUninstallCmdLine( AppName, Silent, UninstCmdLine )
NUMBER nReturn;
begin
nReturn = RegDBGetUninstCmdLine ( GetUninstallKey( AppName ), UninstCmdLine );
if( nReturn < ISERR_SUCCESS ) then
return nReturn;
endif;
if( Silent && StrFind( UninstCmdLine, "MsiExec.exe" ) >= 0 )then
UninstCmdLine = UninstCmdLine + " /qn";
endif;
return nReturn;
end;
///////////////////////////////////////////////////////////////////////////////
//
// Function: GetUninstallKey
//
// Purpose: Find the uninstall key in the registry for an application looked up by name
//
// Returns: The uninstall key (i.e. the guid or a fall back value)
//
///////////////////////////////////////////////////////////////////////////////
function STRING GetUninstallKey( AppName )
STRING guid;
STRING Key64, Key32, ValueName;
begin
Key64 = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
Key32 = "SOFTWARE\\Wow6432Node\\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
ValueName = "DisplayName";
if( RegDBGetSubKeyNameContainingValue( HKEY_LOCAL_MACHINE, Key64, ValueName, AppName, guid ) = 0 ) then
return guid; // return 64 bit GUID
endif;
if( RegDBGetSubKeyNameContainingValue( HKEY_LOCAL_MACHINE, Key32, ValueName, AppName, guid ) = 0 ) then
return guid; // return 32 bit GUID
endif;
return AppName; // return old style uninstall key (fall back value)
end;
///////////////////////////////////////////////////////////////////////////////
//
// Function: RegDBGetSubKeyNameContainingValue
//
// Purpose: Find a registry sub key containing a given value.
// Return the NAME of the subkey (NOT the entire key path)
//
// Returns: (SubKeyName is assigned a value by referrence)
// = 0 A sub key name was found with a matching value
// != 0 Failed to find a sub key with a matching value
//
///////////////////////////////////////////////////////////////////////////////
function NUMBER RegDBGetSubKeyNameContainingValue( nRootKey, Key, ValueName, Value, SubKeyName )
STRING SearchSubKey, SubKey, svValue;
NUMBER nResult, nType, nvSize;
LIST listSubKeys;
begin
SubKeyName = "";
listSubKeys = ListCreate(STRINGLIST);
if (listSubKeys = LIST_NULL) then
MessageBox ("Unable to create necessary list.", SEVERE);
abort;
endif;
RegDBSetDefaultRoot( nRootKey );
if (RegDBQueryKey( Key, REGDB_KEYS, listSubKeys ) = 0) then
nResult = ListGetFirstString (listSubKeys, SubKey);
while (nResult != END_OF_LIST)
SearchSubKey = Key + "\\" + SubKey;
nType = REGDB_STRING;
if (RegDBGetKeyValueEx (SearchSubKey, ValueName, nType, svValue, nvSize) = 0) then
if( svValue = Value ) then
SubKeyName = SubKey;
nResult = END_OF_LIST;
endif;
endif;
if( nResult != END_OF_LIST ) then
nResult = ListGetNextString (listSubKeys, SubKey);
endif;
endwhile;
endif;
ListDestroy (listSubKeys );
if ( SubKeyName = "" ) then
return 1;
else
return 0;
endif;
end;