Windows Installerでは外部UIを使える
ほとんどの場合Windows InstallerでUIを表示する際、すでに用意されているダイアログセットを使用すると思います。しかし、一度に複数のMSIファイルでインストールすると、画面遷移がわずらわしくなってくるので、UI表示を一括して他のプログラムに任せたくなります。そんなときは、MsiSetExternalUIというMSIの関数を利用して、MSIファイルによるインストール状況を外部のプログラムに知らせることができます。
Inno SetupでMsiSetExternalUIを使用する
Windows Installerは外部のプログラムにインストールの進捗状況を伝えるために、MsiSetExternalUI関数の第1引数に与えた関数を呼び出します。Inno Setupで書いた関数はPascalで書かれているので、Windows APIと関数の呼び出し方式が異なり、直接Windows APIから呼び出すことができません。そのため、Inno Setupには、CreateCallback関数が用意されています。この関数が返す関数のアドレスを使うと、直接Windows APIからPascalの関数を呼び出すことができます。
Windows Installerから渡される情報の中身を確認する
まず、適当なMSIファイルを用意します。この記事では、「Part32_01.msi」と「cab1.cab」を用意しました。このMSIファイルはUIを持っていなくても問題ありません(もちろんUIを持っていても問題ありません)。このMSIファイルをインストールし、Windows installerから渡されてくる情報をInno SetupのDebugログに出力するインストーラーを実装してみました。
#define MsiName "Part32_01.msi"
[Setup]
DisableReadyPage=True
DisableReadyMemo=True
AppName=Part32_01
AppVersion=1.0.0
UsePreviousPrivileges=False
CreateAppDir=False
ShowLanguageDialog=no
Uninstallable=no
OutputBaseFilename=Part32_01_Installer
[Files]
Source: "bin\Debug\{#MsiName}"; DestDir: "{tmp}"; Flags: deleteafterinstall
Source: "bin\Debug\cab1.cab"; DestDir: "{tmp}"; Flags: deleteafterinstall
[Code]
const
INSTALLUILEVEL_NOCHANGE = 0; // UI level is unchanged
INSTALLUILEVEL_DEFAULT = 1; // default UI is used
INSTALLUILEVEL_NONE = 2; // completely silent installation
INSTALLUILEVEL_BASIC = 3; // simple progress and error handling
INSTALLUILEVEL_REDUCED = 4; // authored UI, wizard dialogs suppressed
INSTALLUILEVEL_FULL = 5; // authored UI with wizards, progress, errors
INSTALLUILEVEL_ENDDIALOG = $80; // display success/failure dialog at end of install
INSTALLUILEVEL_PROGRESSONLY = $40; // display only progress dialog
INSTALLUILEVEL_HIDECANCEL = $20; // do not display the cancel button in basic UI
INSTALLUILEVEL_SOURCERESONLY = $100; // force display of source resolution even if quiet
INSTALLMESSAGE_FATALEXIT = $00000000; // premature termination, possibly fatal OOM
INSTALLMESSAGE_ERROR = $01000000; // formatted error message
INSTALLMESSAGE_WARNING = $02000000; // formatted warning message
INSTALLMESSAGE_USER = $03000000; // user request message
INSTALLMESSAGE_INFO = $04000000; // informative message for log
INSTALLMESSAGE_FILESINUSE = $05000000; // list of files in use that need to be replaced
INSTALLMESSAGE_RESOLVESOURCE = $06000000; // request to determine a valid source location
INSTALLMESSAGE_OUTOFDISKSPACE = $07000000; // insufficient disk space message
INSTALLMESSAGE_ACTIONSTART = $08000000; // start of action: action name & description
INSTALLMESSAGE_ACTIONDATA = $09000000; // formatted data associated with individual action item
INSTALLMESSAGE_PROGRESS = $0A000000; // progress gauge info: units so far, total
INSTALLMESSAGE_COMMONDATA = $0B000000; // product info for dialog: language Id, dialog caption
INSTALLMESSAGE_INITIALIZE = $0C000000; // sent prior to UI initialization, no string data
INSTALLMESSAGE_TERMINATE = $0D000000; // sent after UI termination, no string data
INSTALLMESSAGE_SHOWDIALOG = $0E000000; // sent prior to display or authored dialog or wizard
INSTALLLOGMODE_FATALEXIT = 1 shl (INSTALLMESSAGE_FATALEXIT shr 24);
INSTALLLOGMODE_ERROR = 1 shl (INSTALLMESSAGE_ERROR shr 24);
INSTALLLOGMODE_WARNING = 1 shl (INSTALLMESSAGE_WARNING shr 24);
INSTALLLOGMODE_USER = 1 shl (INSTALLMESSAGE_USER shr 24);
INSTALLLOGMODE_INFO = 1 shl (INSTALLMESSAGE_INFO shr 24);
INSTALLLOGMODE_RESOLVESOURCE = 1 shl (INSTALLMESSAGE_RESOLVESOURCE shr 24);
INSTALLLOGMODE_OUTOFDISKSPACE = 1 shl (INSTALLMESSAGE_OUTOFDISKSPACE shr 24);
INSTALLLOGMODE_ACTIONSTART = 1 shl (INSTALLMESSAGE_ACTIONSTART shr 24);
INSTALLLOGMODE_ACTIONDATA = 1 shl (INSTALLMESSAGE_ACTIONDATA shr 24);
INSTALLLOGMODE_COMMONDATA = 1 shl (INSTALLMESSAGE_COMMONDATA shr 24);
INSTALLLOGMODE_PROPERTYDUMP = 1 shl (INSTALLMESSAGE_PROGRESS shr 24); // log only
INSTALLLOGMODE_VERBOSE = 1 shl (INSTALLMESSAGE_INITIALIZE shr 24); // log only
INSTALLLOGMODE_EXTRADEBUG = 1 shl (INSTALLMESSAGE_TERMINATE shr 24); // log only
INSTALLLOGMODE_PROGRESS = 1 shl (INSTALLMESSAGE_PROGRESS shr 24); // external handler only
INSTALLLOGMODE_INITIALIZE = 1 shl (INSTALLMESSAGE_INITIALIZE shr 24); // external handler only
INSTALLLOGMODE_TERMINATE = 1 shl (INSTALLMESSAGE_TERMINATE shr 24); // external handler only
INSTALLLOGMODE_SHOWDIALOG = 1 shl (INSTALLMESSAGE_SHOWDIALOG shr 24); // external handler only
var
StrCounter: Integer;
type
INSTALLUILEVEL = Longint;
LPHWND = Cardinal;
LPVOID = Cardinal;
LPCWSTR = Cardinal;
function MsiSetInternalUI(dwUILevel: INSTALLUILEVEL; phWnd: LPHWND): INSTALLUILEVEL;
external 'MsiSetInternalUI@msi.dll stdcall';
function MsiSetExternalUIW(puiHandler: Longword; dwMessageFilter: DWORD; pvContext: String): Integer;
external 'MsiSetExternalUIW@msi.dll stdcall';
function MsiInstallProductW(szPackagePath: String; szCommandLine: String): UINT;
external 'MsiInstallProductW@msi.dll stdcall';
function TestMyBasicUIHandler(pvContext: LPVOID; iMessageType: UINT; szMessage: String): Integer;
begin
StrCounter := StrCounter + 1;
Log(Format('%d : %X', [StrCounter, iMessageType]));
case ($FF000000 and iMessageType) of
INSTALLMESSAGE_FATALEXIT: Log(Format('%d : INSTALLMESSAGE_FATALEXIT', [StrCounter]));
INSTALLMESSAGE_ERROR: Log(Format('%d : INSTALLMESSAGE_ERROR', [StrCounter]));
INSTALLMESSAGE_WARNING: Log(Format('%d : INSTALLMESSAGE_WARNING', [StrCounter]));
INSTALLMESSAGE_USER: Log(Format('%d : INSTALLMESSAGE_USER', [StrCounter]));
INSTALLMESSAGE_INFO: Log(Format('%d : INSTALLMESSAGE_INFO', [StrCounter]));
INSTALLMESSAGE_FILESINUSE: Log(Format('%d : INSTALLMESSAGE_FILESINUSE', [StrCounter]));
INSTALLMESSAGE_RESOLVESOURCE: Log(Format('%d : INSTALLMESSAGE_RESOLVESOURCE', [StrCounter]));
INSTALLMESSAGE_OUTOFDISKSPACE:Log(Format('%d : INSTALLMESSAGE_OUTOFDISKSPACE', [StrCounter]));
INSTALLMESSAGE_ACTIONSTART: Log(Format('%d : INSTALLMESSAGE_ACTIONSTART', [StrCounter]));
INSTALLMESSAGE_ACTIONDATA: Log(Format('%d : INSTALLMESSAGE_ACTIONDATA', [StrCounter]));
INSTALLMESSAGE_PROGRESS: Log(Format('%d : INSTALLMESSAGE_PROGRESS', [StrCounter]));
INSTALLMESSAGE_COMMONDATA: Log(Format('%d : INSTALLMESSAGE_COMMONDATA', [StrCounter]));
INSTALLMESSAGE_INITIALIZE: Log(Format('%d : INSTALLMESSAGE_INITIALIZE', [StrCounter]));
INSTALLMESSAGE_TERMINATE: Log(Format('%d : INSTALLMESSAGE_TERMINATE', [StrCounter]));
INSTALLMESSAGE_SHOWDIALOG: Log(Format('%d : INSTALLMESSAGE_SHOWDIALOG', [StrCounter]));
end;
Log(Format('%d : %s', [StrCounter, szMessage]));
result := 0;
end;
procedure CurStepChanged(CurStep: TSetupStep);
var
tmpPath: String;
ResultCode: Integer;
begin
// msi/cabファイルの展開が終わったら、msiを起動する
if CurStep=ssPostInstall then begin
MsiSetInternalUI(INSTALLUILEVEL_NONE or INSTALLUILEVEL_SOURCERESONLY, 0);
MsiSetExternalUIW(CreateCallback(@TestMyBasicUIHandler), INSTALLLOGMODE_PROGRESS
or INSTALLLOGMODE_FATALEXIT or INSTALLLOGMODE_ERROR
or INSTALLLOGMODE_WARNING or INSTALLLOGMODE_USER or INSTALLLOGMODE_INFO
or INSTALLLOGMODE_RESOLVESOURCE or INSTALLLOGMODE_OUTOFDISKSPACE
or INSTALLLOGMODE_ACTIONSTART or INSTALLLOGMODE_ACTIONDATA
or INSTALLLOGMODE_COMMONDATA or INSTALLLOGMODE_PROGRESS
or INSTALLLOGMODE_INITIALIZE or INSTALLLOGMODE_TERMINATE
or INSTALLLOGMODE_SHOWDIALOG,
'TEST'
);
MsiInstallProductW(ExpandConstant('{tmp}\{#MsiName}'), '');
end;
end;
function InitializeSetup(): Boolean;
begin
StrCounter := 0;
result := True;
end;
インストールを実行して、Debugログをファイルに出力して中身を確認してください。非常に多くの情報が渡されてきており、UI表示に関係なさそうな情報も渡されてくることが分かります。MSIファイルのインストールログを見たことがあるなら、内容がほとんど一緒であることに気付くでしょう。Inno Setupでは、この中からインストールの進捗表示で使う、現在のステータス文字列や、ファイル名やレジストリ項目、プログレスバーの進捗度合い等を取り出して、UIに反映させます。
サンプルを移植する
Windows Installerから渡されてくる情報は、そのままUIに反映することが考慮されていないので、少し加工して使用する必要があります。また、プログレスバー向けの情報を反映するのもかなり面倒な作業です。ここでは、マイクロソフトのサンプルコードを移植してみました。これをこのまま製品に適用できるわけではありませんが、仕組みを読み解くには役に立つでしょう。製品に適用する場合は、FileInUseメッセージやエラー、ワーニングを受けたときの動作を決めておく必要があります。ここでは表示する文字列の加工も、最低限やっているだけです。また、できるだけマイクロソフトのサンプルに近づけるため、グローバル変数を多用していますので、組織の実装ルールに当てはめて実装を変える必要があるかもしれません。
#define MsiName "Part32_02.msi"
[Setup]
DisableReadyPage=True
DisableReadyMemo=True
AppName=Part32_02
AppVersion=1.0.0
UsePreviousPrivileges=False
CreateAppDir=False
ShowLanguageDialog=no
Uninstallable=no
OutputBaseFilename=Part32_02_Installer
[Files]
Source: "bin\Debug\{#MsiName}"; DestDir: "{tmp}"; Flags: deleteafterinstall
Source: "bin\Debug\cab1.cab"; DestDir: "{tmp}"; Flags: deleteafterinstall
[Code]
const
WM_USER = $0400;
PBM_SETRANGE = WM_USER+1;
PBM_SETPOS = WM_USER+2;
PBM_DELTAPOS = WM_USER+3;
PBM_SETSTEP = WM_USER+4;
PBM_STEPIT = WM_USER+5;
PBM_SETRANGE32 = WM_USER+6; // lParam = high, wParam = low
PBM_GETRANGE = WM_USER+7; // wParam = return (TRUE ? low : high). lParam = PPBRANGE or NULL
PBM_GETPOS = WM_USER+8;
PBM_SETBARCOLOR = WM_USER+9; // lParam = bar color
INSTALLUILEVEL_NOCHANGE = 0; // UI level is unchanged
INSTALLUILEVEL_DEFAULT = 1; // default UI is used
INSTALLUILEVEL_NONE = 2; // completely silent installation
INSTALLUILEVEL_BASIC = 3; // simple progress and error handling
INSTALLUILEVEL_REDUCED = 4; // authored UI, wizard dialogs suppressed
INSTALLUILEVEL_FULL = 5; // authored UI with wizards, progress, errors
INSTALLUILEVEL_ENDDIALOG = $80; // display success/failure dialog at end of install
INSTALLUILEVEL_PROGRESSONLY = $40; // display only progress dialog
INSTALLUILEVEL_HIDECANCEL = $20; // do not display the cancel button in basic UI
INSTALLUILEVEL_SOURCERESONLY = $100; // force display of source resolution even if quiet
INSTALLMESSAGE_FATALEXIT = $00000000; // premature termination, possibly fatal OOM
INSTALLMESSAGE_ERROR = $01000000; // formatted error message
INSTALLMESSAGE_WARNING = $02000000; // formatted warning message
INSTALLMESSAGE_USER = $03000000; // user request message
INSTALLMESSAGE_INFO = $04000000; // informative message for log
INSTALLMESSAGE_FILESINUSE = $05000000; // list of files in use that need to be replaced
INSTALLMESSAGE_RESOLVESOURCE = $06000000; // request to determine a valid source location
INSTALLMESSAGE_OUTOFDISKSPACE = $07000000; // insufficient disk space message
INSTALLMESSAGE_ACTIONSTART = $08000000; // start of action: action name & description
INSTALLMESSAGE_ACTIONDATA = $09000000; // formatted data associated with individual action item
INSTALLMESSAGE_PROGRESS = $0A000000; // progress gauge info: units so far, total
INSTALLMESSAGE_COMMONDATA = $0B000000; // product info for dialog: language Id, dialog caption
INSTALLMESSAGE_INITIALIZE = $0C000000; // sent prior to UI initialization, no string data
INSTALLMESSAGE_TERMINATE = $0D000000; // sent after UI termination, no string data
INSTALLMESSAGE_SHOWDIALOG = $0E000000; // sent prior to display or authored dialog or wizard
INSTALLMESSAGE_PERFORMANCE = $0F000000; // log only, to log performance number like action time
INSTALLMESSAGE_RMFILESINUSE = $19000000; // the list of apps that the user can request Restart Manager to shut down and restart
INSTALLMESSAGE_INSTALLSTART = $1A000000; // sent prior to server-side install of a product
INSTALLMESSAGE_INSTALLEND = $1B000000; // sent after server-side install
INSTALLLOGMODE_FATALEXIT = 1 shl (INSTALLMESSAGE_FATALEXIT shr 24);
INSTALLLOGMODE_ERROR = 1 shl (INSTALLMESSAGE_ERROR shr 24);
INSTALLLOGMODE_WARNING = 1 shl (INSTALLMESSAGE_WARNING shr 24);
INSTALLLOGMODE_USER = 1 shl (INSTALLMESSAGE_USER shr 24);
INSTALLLOGMODE_INFO = 1 shl (INSTALLMESSAGE_INFO shr 24);
INSTALLLOGMODE_RESOLVESOURCE = 1 shl (INSTALLMESSAGE_RESOLVESOURCE shr 24);
INSTALLLOGMODE_OUTOFDISKSPACE = 1 shl (INSTALLMESSAGE_OUTOFDISKSPACE shr 24);
INSTALLLOGMODE_ACTIONSTART = 1 shl (INSTALLMESSAGE_ACTIONSTART shr 24);
INSTALLLOGMODE_ACTIONDATA = 1 shl (INSTALLMESSAGE_ACTIONDATA shr 24);
INSTALLLOGMODE_COMMONDATA = 1 shl (INSTALLMESSAGE_COMMONDATA shr 24);
INSTALLLOGMODE_PROPERTYDUMP = 1 shl (INSTALLMESSAGE_PROGRESS shr 24); // log only
INSTALLLOGMODE_VERBOSE = 1 shl (INSTALLMESSAGE_INITIALIZE shr 24); // log only
INSTALLLOGMODE_EXTRADEBUG = 1 shl (INSTALLMESSAGE_TERMINATE shr 24); // log only
INSTALLLOGMODE_PROGRESS = 1 shl (INSTALLMESSAGE_PROGRESS shr 24); // external handler only
INSTALLLOGMODE_INITIALIZE = 1 shl (INSTALLMESSAGE_INITIALIZE shr 24); // external handler only
INSTALLLOGMODE_TERMINATE = 1 shl (INSTALLMESSAGE_TERMINATE shr 24); // external handler only
INSTALLLOGMODE_SHOWDIALOG = 1 shl (INSTALLMESSAGE_SHOWDIALOG shr 24); // external handler only
LANG_NEUTRAL = $00;
type
INSTALLUILEVEL = Longint;
INSTALLMESSAGE = Longint;
LPHWND = Cardinal;
LPVOID = Cardinal;
LPCWSTR = Cardinal;
var
StrCounter: Integer;
bFirstTime: Boolean;
g_bEnableActionData: Boolean; // INSTALLOGMODE_ACTIONDATAメッセージが進捗情報を送るならTrue
iField: array [0..3] of Integer; // INSTALLOGMODE_PROGRESSデータハンドルへのレコードの配列
g_bForwardProgress: Boolean; // プログレスバーを正方向に進めるならTRUE
g_iProgressTotal: Integer; // プログレスバーの合計コマ数
g_iProgress: Integer; // 進捗の総数
g_bScriptInProgress: Boolean;
iCurPos: Integer;
g_wLANGID: Word; // neutral languageに初期化
g_rgiField: array [0..2] of Integer; // INSTALLOGMODE_COMMONDATAデータハンドルの配列
progressStep: Integer;
// 外部DLLの関数宣言
function MsiSetInternalUI(dwUILevel: INSTALLUILEVEL; phWnd: LPHWND): INSTALLUILEVEL;
external 'MsiSetInternalUI@msi.dll stdcall';
function MsiSetExternalUIW(puiHandler: Longword; dwMessageFilter: DWORD; pvContext: String): Integer;
external 'MsiSetExternalUIW@msi.dll stdcall';
function MsiInstallProductW(szPackagePath: String; szCommandLine: String): UINT;
external 'MsiInstallProductW@msi.dll stdcall';
// プロトタイプ宣言
function ParseCommonDataString(sz: String): Boolean; forward;
function ParseProgressString(sz: String): Boolean; forward;
// ------------------------------------------------------------------
// TestMyBasicUIHandler()
// MSIで外部ユーザー・インターフェース・ハンドラを扱うデモ
function TestMyBasicUIHandler(pvContext: LPVOID; iMessageType: UINT; szMessage: String): Integer;
var
r1: INSTALLUILEVEL;
mt: INSTALLMESSAGE;
uiFlags: UINT;
wParam: Int64; // WPARAM type
nCmdShow: Integer;
begin
result := 0;
if bFirstTime then begin
r1 := MsiSetInternalUI(INSTALLUILEVEL_BASIC, 0);
bFirstTime := False;
end;
mt := $FF000000 and iMessageType;
uiFlags := $00FFFFFF and iMessageType;
case (mt) of
INSTALLMESSAGE_FATALEXIT: begin
// ここでfatal errorメッセージを受け取り表示する
result := MsgBox(szMessage, mbError, uiFlags);
end;
INSTALLMESSAGE_ERROR: begin
// ここでエラーメッセージを受け取り表示する。
// 言語とタイトルはcommon dataメッセージから得られる
result := MsgBox(szMessage, mbError, uiFlags);
end;
INSTALLMESSAGE_WARNING: begin
// ここでwarningメッセージを受け取り表示する
result := MsgBox(szMessage, mbError, uiFlags);
end;
INSTALLMESSAGE_USER: begin
// ここでuserメッセージを受け取る
// メッセージボックススタイルのフラグを得るためにuiFlagsをパースし、IDOK, IDYES等を返す
result := IDOK;
end;
INSTALLMESSAGE_INFO: begin
// Actionの実行状況などが返される、一般的にインストーラーのUIには表示しない
result := IDOK;
end;
INSTALLMESSAGE_FILESINUSE: begin
// FilesInUseダイアログを表示する
// ユーザーにファイルを使っているアプリケーション名を提示するには、メッセージテキストをパースする
result := 0;
end;
INSTALLMESSAGE_RESOLVESOURCE: begin
// ResolveSourceのために常に0を返す
result := 0;
end;
INSTALLMESSAGE_OUTOFDISKSPACE: begin
// ここでユーザーメッセージを得る
result := IDOK;
end;
INSTALLMESSAGE_ACTIONSTART: begin
// 新しくアクションが開始された、action dataもこのアクションによって送られる
WizardForm.StatusLabel.Caption := Copy(szMessage, 18, Length(szMessage)-17);
WizardForm.FilenameLabel.Caption := '';
g_bEnableActionData := False;
result := IDOK;
end;
INSTALLMESSAGE_ACTIONDATA: begin
// ファイル、レジストリ等の書き込みを順次知らせる
// 進捗の合計が初期化されたら実行する
if 0 <> g_iProgressTotal then begin
// アクションテキストを表示する
WizardForm.FilenameLabel.Caption := szMessage;
if g_bEnableActionData then begin
// progressStepに設定しただけ進める
WizardForm.ProgressGauge.Position := WizardForm.ProgressGauge.Position + progressStep;
end;
end;
result := IDOK;
end;
INSTALLMESSAGE_PROGRESS: begin
// プログレスバーの進捗を管理する
if ParseProgressString(szMessage) then begin
case (iField[0]) of
0: begin // プログレスバーをリセットする
// field 1 = 0, field 2 = コマ数の合計, field 3 = 方向, field 4 = 進行中か
// プログレスバーの合計コマ数を取得する
g_iProgressTotal := iField[1];
// 方向を決める
if iField[2] = 0 then begin
g_bForwardProgress := True;
end else begin // iField[2] == 1
g_bForwardProgress := False;
end;
// 方向に応じたプログレスバーの現在位置を取得する
// 前進なら現在位置は0
// 後進なら現在位置は合計コマ数
if g_bForwardProgress then begin
g_iProgress := 0;
end else begin
g_iProgress := g_iProgressTotal;
end;
WizardForm.ProgressGauge.Max := g_iProgressTotal;
// もしg_bScriptInProgressが真ならプログレスバーは終わり、そうでなければリセット(そして進行方向に従ってセットアップする)
if g_bScriptInProgress then begin
WizardForm.ProgressGauge.Position := g_iProgressTotal;
end else begin
WizardForm.ProgressGauge.Position := g_iProgress;
end;
iCurPos := 0;
// 新しい値を決定する
// もしnew state = 1 (script in progress)なら、"Please wait..."メッセージを送る
// new state = 1は総コマ数が推定であり、正確でないことを示す
if iField[3] = 1 then begin
g_bScriptInProgress := True;
end else begin
g_bScriptInProgress := False;
end;
end;
1: begin // ActionInfo
// field 1 = 1, field 2はバーを進めるコマ数を得られる
// field 3がゼロなら無視する
if iField[2]<>0 then begin
// g_bForwardProgressによって進捗方向が決まり、reset progress msgでセットされる
if g_bForwardProgress then begin
wParam := iField[1];
end else begin
wParam := -1 * iField[1];
end;
progressStep := wParam;
g_bEnableActionData := True;
end else begin
g_bEnableActionData := False;
end;
end;
2: begin //ProgressReport
// プログレスバーの合計コマ数が初期化されたら実行する
if 0 <> g_iProgressTotal then begin
iCurPos := iCurPos + iField[1];
//field 1 = 2,field 2は動いたバーのコマ数を持っていることを示す
// reset progressメッセージでセットされたg_bForwardProgressによって移動方向が決まる
if g_bForwardProgress then begin
wParam := iCurPos;
end else begin
wParam := -1 * iCurPos;
end;
WizardForm.ProgressGauge.Position := wParam;
end;
end;
3: begin // ProgressAddition - そのまま抜ける (これを使って何かする必要はない -- 総コマ数の調整のためにある)
result := IDOK;
end;
end;
end;
end;
INSTALLMESSAGE_COMMONDATA: begin
// キャンセルボタンの表示制御等
if ParseCommonDataString(szMessage) then begin
case (g_rgiField[0]) of
0: begin
// field 1 = 0, field 2 = LANGID, field 3 = CodePage
g_wLANGID := g_rgiField[1];
end;
1: begin
// field 1 = 1, field 2 = CAPTION
// これはMessageBoxesのキャプションとして使うことができる
end;
2: begin
// field 1 = 2, field 2 = 0 (cancelボタンを隠す) OR 1 (cancelボタンを表示する)
if g_rgiField[1] = 0 then begin
WizardForm.CancelButton.Hide;
end else begin
WizardForm.CancelButton.Show;
end;
end;
end;
end;
result := IDOK;
end;
INSTALLMESSAGE_INITIALIZE: begin
// 一番最初に1回だけ来るメッセージ
// このメッセージは内部のUI初期化の前に受け取る、文字列データは含まない
result := IDOK;
end;
INSTALLMESSAGE_TERMINATE: begin
// 一番最後に1回だけ来るメッセージ
// UI停止後に送られる、文字列データは含まない
result := IDOK;
end;
INSTALLMESSAGE_SHOWDIALOG: begin
// ダイアログやウィザードが表示される前に送られる
result := IDOK;
end;
else begin
result := 0;
end;
end;
end;
function ParseCommonDataString(sz: String): Boolean;
var
StrLength, i: Integer;
begin
StrLength := Length(sz);
g_rgiField[0] := StrToInt(sz[4]);
g_rgiField[1] := StrToInt(Copy(sz, 9, StrLength-8));
Result := True;
end;
function ParseProgressString(sz: String): Boolean;
var
i, segCounter: Integer;
segIndex: array[1..8] of Integer;
begin
segCounter := 1;
segIndex[segCounter] := 1;
for i:=1 to Length(sz) do begin
if sz[i]=' ' then begin
segCounter := segCounter + 1;
segIndex[segCounter] := i + 1;
end;
if segCounter=8 then break;
end;
iField[0] := StrToInt(Copy(sz, segIndex[2], segIndex[3]-segIndex[2]-1));
iField[1] := StrToInt(Copy(sz, segIndex[4], segIndex[5]-segIndex[4]-1));
iField[2] := StrToInt(Copy(sz, segIndex[6], segIndex[7]-segIndex[6]-1));
iField[3] := StrToInt(Copy(sz, segIndex[8], Length(sz)-segIndex[8]+1));
Result := True;
end;
// ------------------------------------------------------------------
// 一番最初に呼ばれるイベント
function InitializeSetup(): Boolean;
begin
StrCounter := 0; // for Test
g_wLANGID := LANG_NEUTRAL;
g_iProgressTotal := 0;
g_iProgress := 0;
iCurPos := 0;
bFirstTime := True;
g_bForwardProgress := True;
g_bScriptInProgress := False;
progressStep := 1;
Result := True;
end;
// ------------------------------------------------------------------
//
procedure CurStepChanged(CurStep: TSetupStep);
var
tmpPath: String;
ResultCode: Integer;
begin
// msi/cabファイルの展開が終わったら、msiを起動する
if CurStep=ssPostInstall then begin
MsiSetInternalUI(INSTALLUILEVEL_NONE or INSTALLUILEVEL_SOURCERESONLY, 0);
MsiSetExternalUIW(CreateCallback(@TestMyBasicUIHandler), INSTALLLOGMODE_PROGRESS
or INSTALLLOGMODE_FATALEXIT or INSTALLLOGMODE_ERROR
or INSTALLLOGMODE_WARNING or INSTALLLOGMODE_USER or INSTALLLOGMODE_INFO
or INSTALLLOGMODE_RESOLVESOURCE or INSTALLLOGMODE_OUTOFDISKSPACE
or INSTALLLOGMODE_ACTIONSTART or INSTALLLOGMODE_ACTIONDATA
or INSTALLLOGMODE_COMMONDATA or INSTALLLOGMODE_PROGRESS
or INSTALLLOGMODE_INITIALIZE or INSTALLLOGMODE_TERMINATE
or INSTALLLOGMODE_SHOWDIALOG,
'TEST'
);
MsiInstallProductW(ExpandConstant('{tmp}\{#MsiName}'), '');
end;
end;