共用方式為


將自定義動作新增至 ProgressBar

自定義動作 可以將時間和進度資訊新增至 ProgressBar 控制件。 如需建立具有 ProgressBar 之動作顯示對話框的詳細資訊,請參閱 撰寫 ProgressBar 控件

請注意,必須將兩個自定義動作新增至 Windows Installer 套件,才能準確地向 ProgressBar 報告時間和進度資訊。 一個自定義動作必須是延後自定義動作。 此自定義動作應該完成自定義安裝,並在安裝程式執行安裝腳本時,將個別增量量傳送至 ProgressBar 控件。 第二個自定義動作必須是立即執行的自定義動作,用來告知進度條在安裝的收集和腳本生成階段期間,要在總數中新增多少刻度。

將自定義動作新增至 ProgressBar

  1. 決定自定義動作如何描述其進度。 例如,安裝登錄機碼的自定義動作可能會顯示進度訊息,並在每次安裝程式寫入一個登錄機碼時更新 ProgressBar

  2. 自定義動作的每個更新都會以常數遞增的方式變更 ProgressBar 的長度。 指定或計算每個增量中的刻度數目。 一般而言,ProgressBar 長度的變更會對應至一個字節的安裝。 例如,如果安裝程式在寫入一個登錄機碼時會安裝大約 10000 個位元組,您可以指定遞增的過程中有 10000 個刻度。

  3. 指定或計算自定義動作增加至 進度條長度的刻度總數。 自定義動作新增的刻度數目通常計算為:(刻度遞增)x(項目數)。 例如,如果自定義動作寫入 10 個登錄鍵,安裝程式會安裝大約 100,000 個字節,因此,安裝程式必須把 ProgressBar 的完成總長度估計值增加 100,000 個單位。

    注意

    若要以動態方式計算,自定義動作必須包含腳本產生期間立即執行的區段。 延後執行自定義動作所報告的刻度數目必須等於立即執行動作新增至總刻度計數的刻度數目。 如果情況並非如此,TimeRemaining 文字控件所報告的剩餘時間將會不正確。

     

  4. 將您的自定義動作分成兩個程式代碼區段:在腳本產生階段執行的區段,以及在安裝執行階段執行的區段。 您可以使用兩個檔案來執行此操作,也可以根據安裝程式的執行模式來使用一個檔案。 下列範例會使用一個檔案,並檢查安裝狀態。 範例的區段會根據安裝程式處於執行階段或腳本產生階段來設定運行。

  5. 在腳本產生期間運行的區段,應該根據自定義動作中的刻度總數來增加 ProgressBar 的最後總長度估計值。 這是藉由傳送 ProgressAddition 進度訊息來完成。

  6. 在安裝執行階段執行的 區段應該設定消息正文和範本,以通知使用者自定義動作正在執行的動作,以及指示安裝程式更新 ProgressBar 控件。 例如,通知安裝程式將 ProgressBar 向前移動一個遞增,並在每次更新時傳送明確的進度訊息。 如果自定義動作正在安裝某些專案,則本節中通常會有迴圈。 每次通過這個迴圈時,安裝程式都可以安裝一個參考專案,例如登錄機碼並更新 ProgressBar 控件

  7. 將立即執行的自定義動作新增至 Windows Installer 套件。 此自定義動作會通知 ProgressBar 在安裝取得和腳本產生階段期間要前進多少。 針對下列範例,來源是透過編譯範例程式代碼所建立的 DLL,而目標則是入口點 CAProgress。

  8. 將延後執行自定義動作新增至 Windows Installer 套件。 此自訂動作會完成實際安裝的步驟,並在安裝程式執行安裝腳本時,通知 ProgressBar 進度條前進的程度。 針對下列範例,來源是透過編譯範例程式代碼所建立的 DLL,而目標則是進入點 CAProgress。

  9. InstallExecuteSequence 表中,將自定義動作排程在 InstallInitializeInstallFinalize 之間。 延後自定義動作應在立即執行自定義動作之後立即排程。 在腳本執行之前,安裝程式不會執行延後自定義動作。

下列範例示範如何將自訂動作新增至 ProgressBar。 這兩個自定義動作的來源都是透過編譯範例代碼所建立的 DLL,這兩個自定義動作的目標則是進入點 CAProgress。 此範例不會對系統進行任何實際變更,但會操作進度條,就像在安裝 10 個大約 10,000 字節大小的參考項目。 安裝程式會在每次安裝參考專案時更新訊息和 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;
     }
}