14

WiXインストーラーと、インストーラーのプロパティを使用する単一のカスタム アクション (および元に戻すとロールバック) があります。カスタム アクションは、すべてのファイルがハード ディスクに配置された後に実行する必要があります。これには、WXS ファイルに 16 個のエントリが必要なようです。次のように、ルート内で 8 を指定します。

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

内の 8 つは次のInstallExecuteSequenceようになります。

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

より良い方法はありますか?

4

3 に答える 3

4

WiXカスタムアクションは、従うべき優れたモデルです。この場合、を使用してCustomAction、即時アクション、延期アクション、およびロールバックアクションのみを宣言します。即時アクションをスケジュールするだけCustomで、即時アクションはネイティブDLLのコードとして実装されます。

次に、即時アクションのコードで、ロールバックアクションと遅延アクションをスケジュールするために呼び出します。これらは遅延されるため、すぐに実行されるのではなく、MsiDoAction呼び出した時点でスクリプトに書き込まれます。カスタムアクションデータを設定するには、同様MsiDoActionに呼び出す必要があります。MsiSetProperty

たとえば、WiXソースコードをダウンロードして、どのようにIISExtension機能するかを調べます。WiXアクションは通常、カスタムテーブルを解析し、そのテーブルに基づいて遅延アクションのプロパティのデータを生成します。

于 2008-09-30T13:13:12.037 に答える
3

ロールバックをサポートする必要がある複雑なカスタム アクションがある場合は、Wix 拡張機能を作成することを検討してください。拡張機能は通常、オーサリング サポート (つまり、MSI テーブル エントリにマップされる新しい XML タグ) と、カスタム アクションの自動スケジューリングを提供します。

カスタム アクションを記述するだけでは手間がかかりますが、CA が特定のレベルの複雑さに達すると、拡張機能によって提供される作成の容易さを利用する価値があります。

于 2008-09-27T23:06:37.533 に答える
3

WiX インストーラーを作成しているときに、同じ問題に遭遇しました。この問題に対する私のアプローチは、Mike が提案したものとほとんど同じで、ブログ記事Implementing WiX custom actions part 2: using custom tables があります。

つまり、データのカスタム テーブルを定義できます。

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

次に、単一の即時カスタム アクションを記述して、遅延、ロールバック、およびコミットのカスタム アクションをスケジュールします。

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

次のコードは、1 つのカスタム アクションをスケジュールする方法を示しています。基本的には、カスタム テーブルを開き、必要なプロパティを読み取り ( MsiViewGetColumnInfo()を呼び出すことで任意のカスタム テーブルのスキーマを取得できます)、必要なプロパティをCustomActionDataプロパティにフォーマットします (フォームを使用し/propname:valueますが、何でも使用できます)。あなたがしたい)。

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

deferred、rollback、commit カスタム アクションの実装に関しては、関数を 1 つだけ使用し、MsiGetMode()を使用して何をすべきかを区別することを好みます。

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

上記の手法を使用すると、一般的なカスタム アクション セットの場合、カスタム アクション テーブルを 5 つのエントリに減らすことができます。

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

また、InstallSquence テーブルを 2 つのエントリのみに:

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

さらに、少しの努力でほとんどのコードを再利用できるように記述できます (カスタム テーブルからの読み取り、プロパティの取得、必要なプロパティの書式設定、CustomActionData プロパティへの設定など)。カスタム アクション テーブルのエントリは次のようになります。アプリケーション固有ではありません (アプリケーション固有のデータはカスタム テーブルに書き込まれます)。独自のファイルにカスタム アクション テーブルを配置し、それを各 WiX プロジェクトに含めることができます。

カスタム アクション DLL ファイルの場合、アプリケーション データはカスタム テーブルから読み取られるため、アプリケーション固有の詳細を DLL 実装から除外できるため、カスタム アクション テーブルはライブラリになり、再利用が容易になります。

これは、現在私が WiX カスタム アクションを作成する方法です。さらに改善する方法を誰かが知っている場合は、非常に感謝しています。:)

(完全なソース コードは、私のブログ投稿Wix カスタム アクションの実装パート 2: カスタム テーブルの使用でも確認できます)。

于 2011-06-16T12:27:07.213 に答える