Question

J'ai un projet Basic MSI. Je dois enlever un autre produit MSI sur l'installation qui est maintenant intégrée dans notre principale application. J'ai essayé d'utiliser les scénarios de mise à niveau et de la traiter comme une mise à jour majeure. Cependant, cela ne fonctionne pas à cause des codes de mise à jour, je ne crois correspondant.

Ensuite, j'ai aussi fait une action personnalisée qui msiexec.exe a couru après la CostFinalize (je pense que cela a été dit dans l'aide InstallShield.) Cela a parfaitement fonctionné jusqu'à ce que j'ai installé sur un système qui n'a pas eu l'installateur que je recherchais retirer. Mon programme d'installation échouerait si l'autre produit obsolète n'a pas été installé. J'ai essayé de mettre une condition sur l'action personnalisée définie par la recherche du système, mais il semble que le système de recherche est limitée dans les fonctionnalités. Je ne peux pas vérifier simplement une clé reg et définir une propriété booléenne.

Toutes les idées?

Était-ce utile?

La solution

Quelques choses à considérer

1) Le UpgradeTable (FindRelatedProducts / RemoveExisting produits) peut être utilisé pour enlever ProductCodes associés à UpgradeCode d'un autre produit.

2) Si ma mémoire est bonne, MSI ne supprime pas un produit par l'utilisateur lors d'une installation par machine (ou l'inverse). Le contexte doit être le même.

3) La séquence de l'interface utilisateur ne fonctionne pas pendant les installations silencieuses.

4) Vous ne pouvez pas exécuter msiexec de la séquence exécuter parce qu'il ya un système large mutex d'une seule séquence exécuter par machine.

5) Si vous planifiez dans l'interface utilisateur (je vous ai déjà dit que vous ne devriez pas car il ne fonctionne pas pendant les installations silencieuses) il y a un autre mutex qui dit seulement 1 UI par processus.

Si vous allez partir, je pense que c'est reasonaable vous devriez être en mesure de le faire par l'utilisateur pour chaque utilisateur ou par machine à par machine, ce que vous voulez en utilisant la mise à niveau des éléments / lignes de table sans écrire des actions personnalisées. Sinon, vous aurez besoin d'un programme d'amorçage de style setup.exe pour gérer la désinstaller avant d'entrer dans le monde msiexec.

Autres conseils

Je InstallShield sont parvenus en 2013 à l'aide InstallScript sur commande. Le script est exécuté par une action personnalisée dans la séquence de l'interface utilisateur, mais je l'ai placé après la boîte de dialogue « SetupProgress », à savoir avant « Exécuter une action » au lieu de l'après CostFinalize (comme la documentation ne dit). J'ai ajouté la condition « pas installé » à l'action. Si vous placez ce dans l'ordre proposé, il amorcera la désinstallation dès que le programme d'installation a été initialisé. Si vous vous déplacez à l'endroit où je l'ai fait, il ne se déclenche pas avant que l'utilisateur a cliqué sur le bouton Installer finale maintenant.

La raison de mettre cela dans la séquence de l'interface utilisateur est de se déplacer l'un installateur .msi (ou un désinstalleur) à un problème de temps. Cela ne fonctionne tout simplement pas dans la séquence d'exécution en raison de cette restriction.

La principale faiblesse de cette méthode est que Christopher a déclaré, cela ne fonctionnera pas dans une installation silencieuse (qui se trouve également dans la documentation IS). C'est le moyen officiel pour y parvenir bien. (Consultez: http://helpnet.installshield.com/installshield16helplib/IHelpCustomActionMSIExec.htm ) Si vous pouvez vivre avec ça (depuis installation silencieuse est généralement scénario spécial de cas), cela fonctionne très bien.

Comme Chris a également dit, vous ne pouvez pas lancer l'interface uninstaller alors que l'interface primaire est en cours d'exécution, mais ce n'est pas un problème avec mon script, car il ajoute un commutateur de ligne de commande pour exécuter le programme de désinstallation sans ui (ie en silence).

Mon script permet également d'éviter d'avoir à connaître le guid de l'application que vous souhaitez désinstaller. Voici le script de se lier à l'action personnalisée (UninstallPriorVersions est la fonction de point d'entrée):

////////////////////////////////////////////////////////////////////////////////
    //                                                                            
    //  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;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top