InnoSetupで久しぶりにインストラーを作ったら、.exeクリックしUAC発動した後にエクスプローラーの後ろにいってしまう(ので行方不明になる)現象が出たので手前に出す方法を試行錯誤しました。
UAC後のウィンドウ復帰はなかなか挙動が難しいので、単一のAPIや単純な方法ではうまくいかなかったのでメモです。
結果としては複数手法の力技です。これに加えてダメならTimerで定期的にフロントに出そうかと思いましたが、そこまでしなくても大丈夫でした。
環境
- Windows 11
- InnoSetup v6.4.3
方法
以下のコードを[Code]セクションに追加します。
.....
[Code]
const
SWP_NOMOVE = $0002;
SWP_NOSIZE = $0001;
TOPMOST_FLAGS = SWP_NOMOVE or SWP_NOSIZE;
HWND_TOPMOST = -1;
HWND_NOTOPMOST = -2;
procedure SetWindowPos(
hWnd: HWND;
hWndInsertAfter: HWND;
X, Y, cx, cy: Integer;
uFlags: UINT
); external 'SetWindowPos@user32.dll stdcall';
procedure SetForegroundWindow(hWnd: HWND); external 'SetForegroundWindow@user32.dll stdcall';
procedure ShowWindow(hWnd: HWND; nCmdShow: Integer); external 'ShowWindow@user32.dll stdcall';
procedure BringWindowToTop(hWnd: HWND); external 'BringWindowToTop@user32.dll stdcall';
// より強力な前面復帰処理
procedure BringWizardToFront();
begin
// 複数の方法を組み合わせて確実に前面に
ShowWindow(WizardForm.Handle, 9); // SW_RESTORE
BringWindowToTop(WizardForm.Handle);
SetWindowPos(WizardForm.Handle, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS);
SetForegroundWindow(WizardForm.Handle);
SetWindowPos(WizardForm.Handle, HWND_NOTOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS);
// 少し待ってから再度実行
Sleep(100);
SetForegroundWindow(WizardForm.Handle);
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssInstall then
begin
BringWizardToFront();
end;
end;
// UAC後の復帰をより確実にする
procedure CurPageChanged(CurPageID: Integer);
begin
// どのページでも前面に保持
BringWizardToFront();
end;
解説
複数のWindows APIを組み合わせて段階的にウィンドウを前面に持ってきます
-
ShowWindow(SW_RESTORE)
- ウィンドウを復元 -
BringWindowToTop()
- Zオーダーの最上位に移動 -
SetWindowPos(HWND_TOPMOST)
- 一時的に最前面に設定 -
SetForegroundWindow()
- アクティブウィンドウに設定 -
SetWindowPos(HWND_NOTOPMOST)
- 最前面から通常状態に戻す -
Sleep(100)
+ 再度SetForegroundWindow()
- 確実性を高める