Frage

Ich habe einen WiX Installer und eine einzelne benutzerdefinierte Aktion (plus rückgängig machen und Rollback) für es, die verwendet eine Eigenschaft aus dem Installer. Die benutzerdefinierte Aktion muss geschehen, nachdem alle Dateien auf der Festplatte sind. Es scheint, dass Sie 16 Einträge in der WXS Datei für diese müssen; acht innerhalb der Wurzel, etwa so:

<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"/>

Und acht innerhalb der InstallExecuteSequence, etwa so:

<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>

Gibt es einen besseren Weg?

War es hilfreich?

Lösung

Ich kam in dem gleichen Problem, wenn WiX Installateure zu schreiben. Meine Herangehensweise an das Problem ist meist wie das, was Mike vorgeschlagen, und ich habe eine Blog-Post Die Implementierung WiX benutzerdefinierte Aktionen Teil 2:. Verwendung von benutzerdefinierten Tabellen

Kurz gesagt, können Sie eine benutzerdefinierte Tabelle für Ihre Daten definieren:

<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>

Dann eine einzige unmittelbare benutzerdefinierte Aktion schreibt das latente, Zurückkehren zu planen und begeht benutzerdefinierte Aktionen:

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

Der folgende Code zeigt, wie eine einzelne benutzerdefinierte Aktion planen. Im Grunde nur die benutzerdefinierte Tabelle öffnen, lesen Sie die Eigenschaft, die Sie wollen (Sie das Schema eines benutzerdefinierten Tabelle erhalten kann durch den Aufruf MsiViewGetColumnInfo () ), und formatieren Sie die Eigenschaften in der benötigt Custom Immobilien (ich das Formular /propname:value verwenden, obwohl Sie alles, was Sie wollen, verwenden).

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

Wie bei der latenten, Rollback-Implementierung und Commit Aktionen, ziehe ich nur eine Funktion verwenden und MsiGetMode () zu unterscheiden, was getan werden sollte:

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

Durch die oben beschriebene Technik verwendet wird, für eine typische benutzerdefinierte Aktion legen Sie die benutzerdefinierte Aktion Tabelle auf fünf Einträge reduzieren können:

<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"/>

Und InstallSquence Tabelle nur zwei Einträge:

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

Darüber hinaus mit geringen Aufwand der meisten des Code geschrieben werden können wiederverwendet werden (wie zum Beispiel von benutzerdefinierter Tabelle zu lesen, um die Eigenschaften bekommen, die Formatierung der benötigten Eigenschaften und auf Custom Eigenschaften) und die Einträge in der benutzerdefinierten Aktion Tabelle ist jetzt nicht anwendungsspezifische (die anwendungsspezifischen Daten werden in der benutzerdefinierten Tabelle geschrieben), können wir in einer eigenen Datei benutzerdefinierte Aktion Tisch legen und gerade sind es in jedem WiX Projekt.

Für die benutzerdefinierte Aktion DLL-Datei, da die Anwendungsdaten aus der benutzerdefinierten Tabelle gelesen wird, können wir anwendungsspezifische Details aus der DLL-Implementierung halten, so dass die benutzerdefinierten Aktion Tabelle eine Bibliothek werden kann und damit leichter wieder zu verwenden.

Dies ist, wie zur Zeit ich meine WiX benutzerdefinierten Aktionen schreiben, wenn jemand weiß, wie weiter zu verbessern, würde ich sehr zu schätzen. :)

(Sie können auch den vollständigen Quellcode in meinem Blogbeitrag finden, Die Implementierung Wix benutzerdefinierte Aktionen Teil 2:.. mit benutzerdefinierten Tabellen )

Andere Tipps

Die WiX benutzerdefinierten Aktionen sind ein großes Vorbild zu folgen. In diesem Fall erklären Sie nur mit CustomAction, die ein sofortiges Eingreifen, der Nachträglichkeit und Rollback-Aktion. Sie planen, mit Custom, die ein sofortiges Eingreifen, wo die unmittelbare Wirkung als Code in einer nativen DLL implementiert ist.

Dann in der unmittelbaren Wirkung des Code , rufen Sie MsiDoAction das Rollback und verzögerte Aktionen planen: wie sie verschoben werden, werden sie an der Stelle in das Skript geschrieben rufen Sie MsiDoAction anstatt sofort ausgeführt . Sie müssen auch nennen MsiSetProperty die benutzerdefinierten Aktionsdaten zu setzen.

Laden Sie den Quellcode WiX und untersucht, wie der IISExtension arbeitet, zum Beispiel. WiX Aktionen im Allgemeinen eine benutzerdefinierte Tabelle analysieren und die Daten für die Nachträglichkeit der Eigenschaft erzeugen auf der Grundlage dieser Tabelle.

Wenn Sie komplexe benutzerdefinierte Aktionen, die Rollbacks unterstützen müssen, sollten Sie überlegen, eine Wix-Erweiterung zu schreiben. Erweiterungen bieten in der Regel-Authoring-Unterstützung (das heißt neue XML-Tags, die MSI-Tabelleneinträge zugeordnet werden), sowie automatische Planung von benutzerdefinierten Aktionen.

Es ist mehr Arbeit als nur eine benutzerdefinierte Aktion zu schreiben, aber sobald Ihr CAs ein gewisses Maß an Komplexität erreicht, die Einfachheit der Authoring, die es wert Erweiterungen bieten werden kann.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top