There is no scripting nor form event fired right after the wizard form is shown. However, it is possible to make a workaround for this task. Proper way would be to post a custom window message to the wizard form itself from the OnShow
event and in handler for that message do your stuff. Problem is that Inno Setup has no built-in capability for message handling, so that way requires an external library.
1. Workaround with OnActivate event
But let's start with another, more dirty, but standalone workaround. Wizard form has the OnActivate
event, which is fired whenever the form becomes active, which also includes the time when the form is displayed for the first time. The only thing you need after the event fires for the first time is disconnect your method from the event and do your stuff. In code it could be:
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
[Code]
procedure WizardFormShow(Sender: TObject);
begin
// disconnect binding of this method from the event
WizardForm.OnActivate := nil;
// and do your stuff
MsgBox('Hello! I am your wizard form :)', mbInformation, MB_OK);
end;
procedure InitializeWizard;
begin
// bind the event to the method
WizardForm.OnActivate := @WizardFormShow;
end;
2. Workaround with custom message posting
That has been dirty but reliable and standalone workaround. Now go to the proper way which requires the InnoCallback
library and is more complicated. This one posts a custom message to the wizard form itself from the OnShow
event and waits for this message to arrive. This extra step is done, since the OnShow
event doesn't fire when the form is shown, but when it's about to be shown and we need some way to run our stuff later, when the form window processes all its messages enqueued when it's about to be shown:
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
[Files]
Source: "InnoCallback.dll"; DestDir: "{tmp}"; Flags: dontcopy
[Code]
#ifdef UNICODE
#define AW "W"
#else
#define AW "A"
#endif
const
GWL_WNDPROC = -4;
WM_USER = $0400;
CM_AFTERSHOW = WM_USER + 1;
type
WPARAM = UINT_PTR;
LPARAM = LongInt;
LRESULT = LongInt;
TWindowProc = function(hwnd: HWND; uMsg: UINT; wParam: WPARAM;
lParam: LPARAM): LRESULT;
function CallWindowProc(lpPrevWndFunc: LongInt; hWnd: HWND; Msg: UINT;
wParam: WPARAM; lParam: LPARAM): LRESULT;
external 'CallWindowProc{#AW}@user32.dll stdcall';
function SetWindowLong(hWnd: HWND; nIndex: Integer;
dwNewLong: LongInt): LongInt;
external 'SetWindowLong{#AW}@user32.dll stdcall';
function WrapWindowProc(Callback: TWindowProc; ParamCount: Integer): LongWord;
external 'wrapcallback@files:InnoCallback.dll stdcall';
var
OldWndProc: LongInt;
procedure WizardFormShow(Sender: TObject);
begin
// enqueue our custom message when the wizard form is about to be shown
PostMessage(WizardForm.Handle, CM_AFTERSHOW, 0, 0);
end;
function WizardFormWndProc(hwnd: HWND; uMsg: UINT; wParam: WPARAM;
lParam: LPARAM): LRESULT;
begin
// if we're processing our custom message, then...
if uMsg = CM_AFTERSHOW then
MsgBox('Hello! I am your wizard form :)', mbInformation, MB_OK);
else
// otherwise pass message to the original window procedure
Result := CallWindowProc(OldWndProc, hwnd, uMsg, wParam, lParam);
end;
procedure InitializeWizard;
begin
// intercept window proc of the wizard form and store the original one
OldWndProc := SetWindowLong(WizardForm.Handle, GWL_WNDPROC,
WrapWindowProc(@WizardFormWndProc, 4));
// bind the OnShow event method, which is used for posting our message
WizardForm.OnShow := @WizardFormShow;
end;
procedure DeinitializeSetup;
begin
// restore the wizard form's window procedure
SetWindowLong(WizardForm.Handle, GWL_WNDPROC, OldWndProc);
end;