Question

Je dispose d’un programme d’installation WiX et d'une seule action personnalisée (avec annulation et annulation). il qui utilise une propriété de l'installateur. L'action personnalisée doit avoir lieu une fois que tous les fichiers sont sur le disque dur. Il semble que vous ayez besoin de 16 entrées dans le fichier WXS pour cela; huit dans la racine, comme suit:

<CustomAction Id="SetForRollbackDo" Execute="immediate" Property="RollbackDo" Value="[MYPROP]"/>
<CustomAction Id="RollbackDo" Execute="rollback" BinaryKey="MyDLL" DllEntry="UndoThing" Return="ignore"/>
<CustomAction Id="SetForDo" Execute="immediate" Property="Do" Value="[MYPROP]"/>
<CustomAction Id="Do" Execute="deferred" BinaryKey="MyDLL" DllEntry="DoThing" Return="check"/>
<CustomAction Id="SetForRollbackUndo" Execute="immediate" Property="RollbackUndo" Value="[MYPROP]"/>
<CustomAction Id="RollbackUndo" Execute="rollback" BinaryKey="MyDLL" DllEntry="DoThing" Return="ignore"/>
<CustomAction Id="SetForUndo" Execute="immediate" Property="Undo" Value="[MYPROP]"/>
<CustomAction Id="Undo" Execute="deferred" BinaryKey="MyDLL" DllEntry="UndoThing" Return="check"/>

Et huit dans InstallExecuteSequence , comme suit:

<Custom Action="SetForRollbackDo" After="InstallFiles">REMOVE&lt;>"ALL"</Custom>
<Custom Action="RollbackDo" After="SetForRollbackDo">REMOVE&lt;>"ALL"</Custom>
<Custom Action="SetForDo" After="RollbackDo">REMOVE&lt;>"ALL"</Custom>
<Custom Action="Do" After="SetForDo">REMOVE&lt;>"ALL"</Custom>
<Custom Action="SetForRollbackUndo" After="InstallInitialize">REMOVE="ALL"</Custom>
<Custom Action="RollbackUndo" After="SetForRollbackUndo">REMOVE="ALL"</Custom>
<Custom Action="SetForUndo" After="RollbackUndo">REMOVE="ALL"</Custom>
<Custom Action="Undo" After="SetForUndo">REMOVE="ALL"</Custom>

Y a-t-il un meilleur moyen?

Était-ce utile?

La solution

J'ai rencontré le même problème lors de l'écriture d'installateurs WiX. Mon approche du problème ressemble en grande partie à ce que Mike a suggéré et j'ai un billet de blog Implémentation des actions personnalisées WiX, partie 2: utilisation de tableaux personnalisés .

En bref, vous pouvez définir une table personnalisée pour vos données:

<CustomTable Id="LocalGroupPermissionTable">
    <Column Id="GroupName" Category="Text" PrimaryKey="yes" Type="string"/>
    <Column Id="ACL" Category="Text" PrimaryKey="no" Type="string"/>
    <Row>
        <Data Column="GroupName">GroupToCreate</Data>
        <Data Column="ACL">SeIncreaseQuotaPrivilege</Data>
    </Row>
</CustomTable>

Ensuite, écrivez une seule action personnalisée pour planifier les actions personnalisées différées, de restauration et de validation:

extern "C" UINT __stdcall ScheduleLocalGroupCreation(MSIHANDLE hInstall)
{
    try {
        ScheduleAction(hInstall,L"SELECT * FROM CreateLocalGroupTable", L"CA.LocalGroupCustomAction.deferred", L"create");
        ScheduleAction(hInstall,L"SELECT * FROM CreateLocalGroupTable", L"CA.LocalGroupCustomAction.rollback", L"create");
    }
    catch( CMsiException & ) {
        return ERROR_INSTALL_FAILURE;
    }
    return ERROR_SUCCESS;
}

Le code suivant montre comment planifier une action personnalisée unique. En gros, il suffit d'ouvrir la table personnalisée, de lire la propriété souhaitée (vous pouvez obtenir le schéma de n'importe quelle table personnalisée en appelant MsiViewGetColumnInfo () ), puis de formater les propriétés nécessaires dans CustomActionData property (j'utilise le formulaire / propname: valeur , bien que vous puissiez utiliser tout ce que vous voulez).

void ScheduleAction(MSIHANDLE hInstall,
            const wchar_t *szQueryString,
            const wchar_t *szCustomActionName,
            const wchar_t *szAction)
{
    CTableView view(hInstall,szQueryString);
    PMSIHANDLE record;

    //For each record in the custom action table
    while( view.Fetch(record) ) {
        //get the "GroupName" property
        wchar_t recordBuf[2048] = {0};
        DWORD    dwBufSize(_countof(recordBuf));
        MsiRecordGetString(record, view.GetPropIdx(L"GroupName"), recordBuf, &dwBufSize);

        //Format two properties "GroupName" and "Operation" into
        //the custom action data string.
        CCustomActionDataUtil formatter;
        formatter.addProp(L"GroupName", recordBuf);
        formatter.addProp(L"Operation", szAction );

        //Set the "CustomActionData" property".
        MsiSetProperty(hInstall,szCustomActionName,formatter.GetCustomActionData());

        //Add the custom action into installation script. Each
        //MsiDoAction adds a distinct custom action into the
        //script, so if we have multiple entries in the custom
        //action table, the deferred custom action will be called
        //multiple times.
        nRet = MsiDoAction(hInstall,szCustomActionName);
    }
}

En ce qui concerne l'implémentation des actions personnalisées différées, d'annulation et de validation, je préfère utiliser une seule fonction et utiliser MsiGetMode () pour distinguer les tâches à exécuter:

extern "C" UINT __stdcall LocalGroupCustomAction(MSIHANDLE hInstall)
{
    try {
        //Parse the properties from the "CustomActionData" property
        std::map<std::wstring,std::wstring> mapProps;
        {
            wchar_t szBuf[2048]={0};
            DWORD dwBufSize = _countof(szBuf); MsiGetProperty(hInstall,L"CustomActionData",szBuf,&dwBufSize);
            CCustomActionDataUtil::ParseCustomActionData(szBuf,mapProps);
        }

        //Find the "GroupName" and "Operation" property
        std::wstring sGroupName;
        bool bCreate = false;
        std::map<std::wstring,std::wstring>::const_iterator it;
        it = mapProps.find(L"GroupName");
        if( mapProps.end() != it ) sGroupName = it->second;
        it = mapProps.find(L"Operation");
        if( mapProps.end() != it )
            bCreate = wcscmp(it->second.c_str(),L"create") == 0 ? true : false ;

        //Since we know what opeartion to perform, and we know whether it is
        //running rollback, commit or deferred script by MsiGetMode, the
        //implementation is straight forward
        if( MsiGetMode(hInstall,MSIRUNMODE_SCHEDULED) ) {
            if( bCreate )
                CreateLocalGroup(sGroupName.c_str());
            else
                DeleteLocalGroup(sGroupName.c_str());
        }
        else if( MsiGetMode(hInstall,MSIRUNMODE_ROLLBACK) ) {
            if( bCreate )
                DeleteLocalGroup(sGroupName.c_str());
            else
                CreateLocalGroup(sGroupName.c_str());
        }
    }
    catch( CMsiException & ) {
        return ERROR_INSTALL_FAILURE;
    }
    return ERROR_SUCCESS;
}

En utilisant la technique ci-dessus, vous pouvez réduire le tableau des actions personnalisées à cinq entrées pour un jeu d'actions personnalisées typique:

<CustomAction Id="CA.ScheduleLocalGroupCreation"
              Return="check"
              Execute="immediate"
              BinaryKey="CustomActionDLL"
              DllEntry="ScheduleLocalGroupCreation"
              HideTarget="yes"/>
<CustomAction Id="CA.ScheduleLocalGroupDeletion"
              Return="check"
              Execute="immediate"
              BinaryKey="CustomActionDLL"
              DllEntry="ScheduleLocalGroupDeletion"
              HideTarget="yes"/>
<CustomAction Id="CA.LocalGroupCustomAction.deferred"
              Return="check"
              Execute="deferred"
              BinaryKey="CustomActionDLL"
              DllEntry="LocalGroupCustomAction"
              HideTarget="yes"/>
<CustomAction Id="CA.LocalGroupCustomAction.commit"
              Return="check"
              Execute="commit"
              BinaryKey="CustomActionDLL"
              DllEntry="LocalGroupCustomAction"
              HideTarget="yes"/>
<CustomAction Id="CA.LocalGroupCustomAction.rollback"
              Return="check"
              Execute="rollback"
              BinaryKey="CustomActionDLL"
              DllEntry="LocalGroupCustomAction"
              HideTarget="yes"/>

Et la table InstallSquence à deux entrées seulement:

<InstallExecuteSequence>
    <Custom Action="CA.ScheduleLocalGroupCreation" 
            After="InstallFiles">
        Not Installed
    </Custom>
    <Custom Action="CA.ScheduleLocalGroupDeletion" 
            After="InstallFiles">
        Installed
    </Custom>
</InstallExecuteSequence>

De plus, avec un peu d’effort, la plupart du code peut être écrit pour être réutilisé (comme lire dans un tableau personnalisé, obtenir les propriétés, formater les propriétés nécessaires et définir les propriétés CustomActionData), ainsi que les entrées de l’action personnalisée. La table n’est plus spécifique à l’application (les données spécifiques à cette application étant écrites dans la table personnalisée), nous pouvons placer une table d’action personnalisée dans un fichier qui lui est propre et l’inclure dans chaque projet WiX.

Pour le fichier DLL d'action personnalisé, puisque les données d'application sont lues dans la table personnalisée, nous pouvons conserver les détails spécifiques à l'application en dehors de l'implémentation de la DLL, afin que le tableau d'action personnalisé puisse devenir une bibliothèque et donc plus facile à réutiliser.

C’est ainsi que j’écris actuellement mes actions personnalisées WiX. Si quelqu'un savait comment améliorer encore, j’apprécierais beaucoup. :)

(Vous pouvez également trouver le code source complet dans mon article de blog, Implémentation des actions personnalisées Wix, partie 2: utilisation de tableaux personnalisés .).

Autres conseils

Les actions personnalisées WiX sont un excellent modèle à suivre. Dans ce cas, vous ne déclarez, avec CustomAction que l'action immédiate, l'action différée et l'action d'annulation. Vous ne planifiez que, avec Custom , l'action immédiate, où l'action immédiate est implémentée sous forme de code dans une DLL native.

Ensuite, dans le code de l'action immédiate, appelez MsiDoAction pour planifier les actions de restauration et les actions différées: lorsqu'elles sont différées, elles sont écrites dans le script au point vous appelez MsiDoAction plutôt que de l'exécuter immédiatement. Vous devez également appeler MsiSetProperty pour définir les données de l'action personnalisée.

Téléchargez le code source WiX et étudiez le fonctionnement de IISExtension , par exemple. Les actions WiX analysent généralement une table personnalisée et génèrent les données de la propriété de l'action différée en fonction de cette table.

Si vous avez des actions personnalisées complexes devant prendre en charge la restauration, vous pouvez envisager d'écrire une extension Wix. Les extensions fournissent généralement un support de création (c'est-à-dire de nouvelles balises XML mappées aux entrées de table MSI), ainsi qu'une planification automatique des actions personnalisées.

Cela représente plus de travail que d'écrire une action personnalisée, mais une fois que vos autorités de certification atteignent un certain niveau de complexité, la facilité de création offerte par les extensions peut en valoir la peine.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top