Question

I'd like to have a popup message on the very first page on my installation, however I don't know how to do it properly. I tried linking MsgBox to page id change like this:

procedure CurPageChanged(CurPageID: Integer);
begin
  if CurPageID = wpWelcome then
    begin
      MsgBox('something something dark side', mbInformation, MB_OK);
    end;
end;

Unfortunately this message box appear too soon, before wpWelcome is drawn, how can I delay it? Or how else can I get a popup on the first page?

Was it helpful?

Solution

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;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top