ProgressBar へのカスタム アクションの追加
カスタム アクションでは時間と進行状況の情報を ProgressBar コントロールに追加できます。 ProgressBar を含むアクション表示ダイアログ ボックスの作成の詳細については、「ProgressBar コントロールの作成」を参照してください。
時間と進行状況の情報を ProgressBar に正確に報告するには、Windows インストーラー パッケージに 2 つのカスタム アクションを追加する必要があることに注意してください。 1 つのカスタム アクションは、遅延カスタム アクションである必要があります。 このカスタム アクションでは、カスタム インストールを実行し、インストーラーでインストール スクリプトが実行されたときに ProgressBar コントロールに個々の増分の量を送信する必要があります。 2 番目のカスタム アクションは、インストールの取得フェーズとスクリプト生成フェーズ中に合計カウントに追加するティック数を ProgressBar に通知する即時実行カスタム アクションである必要があります。
ProgressBar にカスタム アクションを追加するには
カスタム アクションで進行状況を示す方法を決定します。 たとえば、レジストリ キーをインストールするカスタム アクションでは、インストーラーで 1 つのレジストリ キーを書き込むたびに進行状況メッセージが表示され、ProgressBar が更新される場合があります。
カスタム アクションによって更新されるたびに、 ProgressBar の長さが一定の増分で変更されます。 各増分のティック数を指定または計算します。 通常、ProgressBar の長さの 1 ティック分の変化は、1 バイトのインストールに対応します。 たとえば、インストーラーで 1 つのレジストリ キーを書き込むときに約 10000 バイトをインストールする場合、増分に 10000 ティックを指定できます。
カスタム アクションによって ProgressBar の長さに追加されるティックの合計数を指定または計算します。 カスタム アクションによって追加されるティック数は、通常次のように計算されます。 (ティック インクリメント) x (項目数)。 たとえば、カスタム アクションで 10 個のレジストリ キーが書き込まれる場合、インストーラーでは約 100000 バイトをインストールするため、インストーラーでは ProgressBar の最終的な全体の長さの見積もりを 100000ティック増やす必要があります。
Note
これを動的に計算するには、カスタム アクションに、スクリプトの生成中に直ちに実行されるセクションが含まれている必要があります。 遅延実行カスタム アクションによって報告されるティックの量は、即時実行アクションによって合計ティック数に追加されるティック数と等しくなる必要があります。 そうでない場合、TimeRemaining テキスト コントロールによって報告された残り時間は不正確になります。
カスタム アクションを、コードの 2 つのセクション (スクリプト生成フェーズ中に実行されるセクションと、インストールの実行フェーズ中に実行されるセクション) に分けます。 これは 2 つのファイルを使用して行うか、インストーラーの実行モードで条件付けして 1 つのファイルを使用することができます。 次の例では 1 つのファイルを使用し、インストール状態をチェックします。 サンプルのセクションは、インストーラーがインストールの実行フェーズかスクリプト生成フェーズかに応じて実行するように条件付けられています。
スクリプトの生成中に実行されるセクションでは、ProgressBar の最終的な全長の見積もりを、カスタム アクションの合計ティック数だけ増やす必要があります。 これは ProgressAddition 進行状況メッセージを送信することによって行われます。
インストールの実行フェーズ中に実行されるセクションでは、カスタム アクションの実行内容をユーザーに通知し、ProgressBar コントロールの更新をインストーラーに指示するためのメッセージ テキストとテンプレートを設定する必要があります。 たとえば、更新ごとに ProgressBar を 1 インクリメント進め、明示的な進行状況メッセージを送信するようにインストーラーに通知します。 カスタム アクションで何かをインストールする場合、このセクションにはたいていループがあります。 このループを通過するたびに、インストーラーではレジストリ キーなどの 1 つの参照項目がインストールされ、ProgressBar コントロールが更新されます
Windows インストーラー パッケージに即時実行カスタム アクションを追加します。 このカスタム アクションでは、インストールの取得フェーズとスクリプト生成フェーズ中にどの程度進めるかが ProgressBar に通知されます。 次のサンプルでは、ソースはサンプル コードをコンパイルして作成された DLL であり、ターゲットはエントリ ポイント CAProgress です。
Windows インストーラー パッケージに遅延実行カスタム アクションを追加します。 このカスタム アクションでは、実際のインストールの手順を完了し、インストーラーでインストール スクリプトを実行するときにバーをどの程度進めるかが ProgressBar に通知されます。 次のサンプルでは、ソースはサンプル コードをコンパイルして作成された DLL であり、ターゲットはエントリ ポイント CAProgress です。
両方のカスタム アクションを、InstallExecuteSequence テーブルの InstallInitialize と InstallFinalize の間でスケジュールします。 遅延カスタム アクションは、即時実行カスタム アクションの直後にスケジュールする必要があります。 インストーラーでは、スクリプトが実行されるまで遅延カスタム アクションは実行されません。
次の例は、ProgressBar にカスタム アクションを追加する方法を示しています。 両方のカスタム アクションのソースは、サンプル コードをコンパイルして作成された DLL であり、両方のカスタム アクションのターゲットは、エントリ ポイント CAProgress です。 このサンプルでは、システムに実際の変更を加えるのではなく、それぞれ約 10,000 バイトのサイズの 10 個の参照項目をインストールする場合と同じように ProgressBar を操作します。 インストーラーでは、参照項目をインストールするたびに、メッセージと ProgressBar が更新されます。
#include <windows.h>
#include <msiquery.h>
#pragma comment(lib, "msi.lib")
// Specify or calculate the number of ticks in an increment
// to the ProgressBar
const UINT iTickIncrement = 10000;
// Specify or calculate the total number of ticks the custom
// action adds to the length of the ProgressBar
const UINT iNumberItems = 10;
const UINT iTotalTicks = iTickIncrement * iNumberItems;
UINT __stdcall CAProgress(MSIHANDLE hInstall)
{
// Tell the installer to check the installation state and execute
// the code needed during the rollback, acquisition, or
// execution phases of the installation.
if (MsiGetMode(hInstall,MSIRUNMODE_SCHEDULED) == TRUE)
{
PMSIHANDLE hActionRec = MsiCreateRecord(3);
PMSIHANDLE hProgressRec = MsiCreateRecord(3);
// Installer is executing the installation script. Set up a
// record specifying appropriate templates and text for
// messages that will inform the user about what the custom
// action is doing. Tell the installer to use this template and
// text in progress messages.
MsiRecordSetString(hActionRec, 1, TEXT("MyCustomAction"));
MsiRecordSetString(hActionRec, 2, TEXT("Incrementing the Progress Bar..."));
MsiRecordSetString(hActionRec, 3, TEXT("Incrementing tick [1] of [2]"));
UINT iResult = MsiProcessMessage(hInstall, INSTALLMESSAGE_ACTIONSTART, hActionRec);
if ((iResult == IDCANCEL))
return ERROR_INSTALL_USEREXIT;
// Tell the installer to use explicit progress messages.
MsiRecordSetInteger(hProgressRec, 1, 1);
MsiRecordSetInteger(hProgressRec, 2, 1);
MsiRecordSetInteger(hProgressRec, 3, 0);
iResult = MsiProcessMessage(hInstall, INSTALLMESSAGE_PROGRESS, hProgressRec);
if ((iResult == IDCANCEL))
return ERROR_INSTALL_USEREXIT;
//Specify that an update of the progress bar's position in
//this case means to move it forward by one increment.
MsiRecordSetInteger(hProgressRec, 1, 2);
MsiRecordSetInteger(hProgressRec, 2, iTickIncrement);
MsiRecordSetInteger(hProgressRec, 3, 0);
// The following loop sets up the record needed by the action
// messages and tells the installer to send a message to update
// the progress bar.
MsiRecordSetInteger(hActionRec, 2, iTotalTicks);
for( int i = 0; i < iTotalTicks; i+=iTickIncrement)
{
MsiRecordSetInteger(hActionRec, 1, i);
iResult = MsiProcessMessage(hInstall, INSTALLMESSAGE_ACTIONDATA, hActionRec);
if ((iResult == IDCANCEL))
return ERROR_INSTALL_USEREXIT;
iResult = MsiProcessMessage(hInstall, INSTALLMESSAGE_PROGRESS, hProgressRec);
if ((iResult == IDCANCEL))
return ERROR_INSTALL_USEREXIT;
//A real custom action would have code here that does a part
//of the installation. For this sample, code that installs
//10 registry keys.
Sleep(1000);
}
return ERROR_SUCCESS;
}
else
{
// Installer is generating the installation script of the
// custom action.
// Tell the installer to increase the value of the final total
// length of the progress bar by the total number of ticks in
// the custom action.
PMSIHANDLE hProgressRec = MsiCreateRecord(2);
MsiRecordSetInteger(hProgressRec, 1, 3);
MsiRecordSetInteger(hProgressRec, 2, iTotalTicks);
UINT iResult = MsiProcessMessage(hInstall, INSTALLMESSAGE_PROGRESS, hProgressRec);
if ((iResult == IDCANCEL))
return ERROR_INSTALL_USEREXIT;
return ERROR_SUCCESS;
}
}