Frage

Ich habe ein Projekt Basic MSI. Ich brauche ein anderes MSI Produkt während der Installation zu entfernen, die jetzt in unsere Anwendung integriert ist. Ich versuchte, die Upgrade-Szenarien zu nutzen und es als wichtiges Upgrade zu behandeln. Dies führte jedoch nicht wegen der Upgrade-Codes funktionieren nicht passend, glaube ich.

Als nächstes habe ich auch eine benutzerdefinierte Aktion, die msiexec.exe nach dem CostFinalize lief (ich denke, dies ist in der Installshield-Hilfe angegeben wurde.) Das funktionierte perfekt, bis ich auf einem System installiert, das nicht das Installationsprogramm hat ich war auf der Suche zu entfernen. Mein Installateur würde scheitern, wenn das andere veraltete Produkt nicht installiert wurde. Ich habe versucht, eine Bedingung für die benutzerdefinierte Aktion vom System Suche eingestellt zu setzen, aber es scheint das System Suche in Funktionalität beschränkt ist. Ich kann nicht einfach überprüfen Ausrichtungs-Schlüssel und legen Sie eine boolean-Eigenschaft.

Irgendwelche Ideen?

War es hilfreich?

Lösung

Ein paar Dinge beachten

1) Die UpgradeTable (FindRelatedProducts / RemoveExisting Produkte können) verwendet werden product mit einem anderen Produkt Upgrade assoziiert zu entfernen.

2) Wenn der Speicher dient, wird MSI kein Per-User-Produkt während eines Per-Maschine installieren (oder die andere Art und Weise entfernen um). Der Kontext hat das gleiche sein.

3) Die UI-Sequenz nicht während der stillen Installationen ausgeführt werden.

4) Sie können nicht msiexec von der Ausführungssequenz ausgeführt werden, da es eine systemweite Mutex einer ist nur Folge pro Maschine ausgeführt werden.

5) Wenn Sie in UI planen (ich dir schon gesagt, dass Sie sollten nicht, da es nicht während der stillen Installationen läuft) gibt es eine andere Mutex ist, die nur 1 UI pro Prozess sagt.

Wenn Sie vorhaben, von pro-Benutzer pro Benutzer oder pro-Maschine pro-Maschine, würde ich denke, es reasonaable ist sollten Sie in der Lage sein zu tun, was Sie Elemente aufrüsten wollen mit / Tabellenzeilen ohne benutzerdefinierte Aktionen zu schreiben. Andernfalls müssen Sie eine Bootstrap-Programm setup.exe Stil Eingabe der msiexec Welt die Deinstallation vor zu behandeln.

Andere Tipps

ich erreichte dies in Installshield 2013 individuelle InstallScript- verwenden. Das Skript wird über eine benutzerdefinierte Aktion in der UI-Sequenz ausgeführt, aber ich legte es nach dem „SetupProgress“ Dialog, das heißt vor dem „Execute-Aktion“ statt nach dem CostFinalize (wie die Dokumentation sagt). Ich fügte hinzu, die Bedingung für die Aktion „nicht installiert“. Wenn Sie diesen Ort in der vorgeschlagenen Reihenfolge, wird die Deinstallation, sobald der Installateur kick off initialisiert wurde. Wenn Sie es, wo bewegen tat ich, es nicht beginnen, bis der Benutzer die endgültige installieren jetzt Schaltfläche geklickt hat.

Der Grund, warum dies in der UI-Sequenz zu setzen ist um die ein MSI-Installer (oder Deinstallationsprogramm) zu einem Zeitpunkt Problem zu bekommen. Dies ist einfach nicht funktioniert, in der Ausführungssequenz wegen dieser Einschränkung.

Die primäre Schwäche bei diesem Verfahren ist, dass als Christopher angegeben, dies in einem stillen nicht installieren funktionieren wird (das auch in der IS-Dokumentation zu finden ist). Das ist die offiziellen Mittel für diese allerdings zu erreichen. (Check out: http://helpnet.installshield.com/installshield16helplib/IHelpCustomActionMSIExec.htm ) Wenn Sie damit leben können (da die automatische Installation der Regel als Sonderfall-Szenario), dann funktioniert das ganz gut.

Als Chris sagte auch, können Sie nicht das Deinstallationsprogramm ui starten, während das primäre ui ausgeführt wird, aber das ist nicht ein Problem mit meinem Skript, weil es eine Befehlszeilenoption fügt das Deinstallationsprogramm ohne ui (dh leise) laufen.

Mein Skript vermeidet auch die GUID der Anwendung wissen zu müssen, die Sie deinstallieren möchten. Hier ist das Skript für die benutzerdefinierte Aktion zu binden (UninstallPriorVersions ist die Eintrittspunktfunktion):

////////////////////////////////////////////////////////////////////////////////
    //                                                                            
    //  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;
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top