將自訂動作新增至 ProgressBar
自訂動作 可以將時間和進度資訊新增至 ProgressBar 控制項。 如需建立具有 ProgressBar 之動作顯示對話方塊的詳細資訊,請參閱 撰寫 ProgressBar 控制項。
請注意,必須將兩個自訂動作新增至 Windows Installer 套件,才能精確地向 ProgressBar 報告時間和進度資訊。 一個自訂動作必須是延後自訂動作。 此自訂動作應該完成您的自訂安裝,並在安裝程式執行安裝腳本時,將個別增量量傳送至 ProgressBar 控制項。 第二個自訂動作必須是立即執行的自訂動作,通知 ProgressBar 在安裝取得和腳本產生階段期間要新增至總計數的刻度數目。
將自訂動作新增至 ProgressBar
決定自訂動作如何描述其進度。 例如,安裝登錄機碼的自訂動作可能會顯示進度訊息,並在安裝程式每次寫入一個登錄機碼時更新 ProgressBar 。
每個自訂動作的更新都會以常數遞增來變更 ProgressBar 的長度。 指定或計算每個遞增中的刻度數目。 一般而言,一個刻度之 ProgressBar 長度的變更會對應至一個位元組的安裝。 例如,如果安裝程式寫入一個登錄機碼時安裝大約 10000 個位元組,您可以指定遞增有 10000 個刻度。
指定或計算自訂動作新增至 ProgressBar長度的刻度總數。 自訂動作所新增的刻度數目通常計算為: (刻度遞增) x (專案數) 。 例如,如果自訂動作寫入 10 個登錄機碼,安裝程式會安裝大約 100000 個位元組,因此安裝程式必須增加 ProgressBar 最後 100000 個刻度的總長度估計。
注意
若要以動態方式計算,自訂動作必須包含腳本產生期間立即執行的區段。 延後執行自訂動作所報告的刻度數量必須等於立即執行動作新增至總刻度計數的刻度數目。 如果這不是這種情況,TimeRemaining 文字控制項所報告的剩餘時間將會不正確。
將您的自訂動作分成兩個程式碼區段:在腳本產生階段執行的區段,以及安裝執行階段期間執行的區段。 您可以使用兩個檔案來執行此動作,或者您可以在安裝程式的執行模式上使用一個檔案。 下列範例會使用一個檔案並檢查安裝狀態。 根據安裝程式是否處於安裝的執行或腳本產生階段,範例的區段會設定為執行。
在腳本產生期間執行的區段應該依自訂動作中的刻度總數,增加 ProgressBar 最終總長度的估計值。 這是透過傳送 ProgressAddition 進度訊息來完成的。
在安裝執行階段執行的區段應該設定郵件內文和範本,以通知使用者自訂動作的作用,以及指示安裝程式更新 ProgressBar 控制項。 例如,通知安裝程式將 ProgressBar 向前移動一個遞增,並在每次更新時傳送明確的進度訊息。 如果自訂動作正在安裝某個專案,則本節中通常會有迴圈。 每次通過此迴圈時,安裝程式都可以安裝一個參考專案,例如登錄機碼並更新 ProgressBar 控制項
將立即執行的自訂動作新增至您的 Windows Installer 套件。 此自訂動作會通知 ProgressBar 在安裝取得和腳本產生階段期間要前進多少。 針對下列範例,來源是編譯範例程式碼所建立的 DLL,而目標則是進入點 CAProgress。
將延後執行自訂動作新增至您的 Windows Installer 套件。 此自訂動作會完成實際安裝的步驟,並通知 ProgressBar 在安裝程式執行安裝腳本時將列前進多少。 針對下列範例,來源是編譯範例程式碼所建立的 DLL,而目標則是進入點 CAProgress。
在InstallExecuteSequence資料表中排程InstallInitialize和InstallFinalize之間的兩個自訂動作。 延遲的自訂動作應該會在立即執行自訂動作之後立即排程。 安裝程式在執行腳本之前,不會執行延後自訂動作。
下列範例示範如何將自訂動作新增至 ProgressBar。 這兩個自訂動作的來源都是編譯範例程式碼所建立的 DLL,而這兩個自訂動作的目標都是進入點 CAProgress。 此範例不會對系統進行任何實際變更,但會操作 ProgressBar,就像安裝大小大約 10,000 個位元組的 10 個參考專案一樣。 安裝程式會在每次安裝參考專案時更新訊息和 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;
}
}