InnoSetup: Is it possible to open my custom Delphi

2019-03-30 03:33发布

问题:

I need to create a complex form with my own components (kinda OneClick installer), and use it as the replacement of the standard InnoSetup wizard. Is it possible?

My form is placed into DLL, and this DLL will be available for InnoSetup process.

This is how I tried to do that:

Delphi DLL code

library OneClickWizard;

uses
  SysUtils,
  Classes,
  Wizard in 'Wizard.pas' {FormWizard};

{$R *.res}

exports
  CreateWizardForm,
  DestroyWizardForm;

begin
end.

Delphi form

unit Wizard;

interface

type
  TFormWizard = class(TForm)
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  FormWizard: TFormWizard;

procedure CreateWizardForm(AppHandle: THandle); stdcall;
procedure DestroyWizardForm; stdcall;

implementation

{$R *.dfm}

procedure CreateWizardForm(AppHandle: THandle);
begin
  Application.Handle := AppHandle;
  FormWizard := TFormWizard.Create(Application);
  FormWizard.Show;
  FormWizard.Refresh;
end;

procedure DestroyWizardForm;
begin
  FormWizard.Free;
end;

InnoSetup script (iss)

[Setup]
;Disable all of the default wizard pages
DisableDirPage=yes
DisableProgramGroupPage=yes
DisableReadyMemo=true
DisableReadyPage=true
DisableStartupPrompt=true
DisableWelcomePage=true
DisableFinishedPage=true

[Files]
Source:"OneClickWizard.dll"; Flags: dontcopy

[Code]
procedure CreateWizardForm(AppHandle: Cardinal); 
  external 'CreateWizardForm@files:OneClickWizard.dll stdcall';
procedure DestroyWizardForm;
  external 'DestroyWizardForm@files:OneClickWizard.dll stdcall';


procedure InitializeWizard();
begin
  CreateWizardForm(MainForm.Handle);
end;

The form appearing on the screen, but it doesn't react on my input. Seems it is out of main message cycle. How to do this correctly?

回答1:

I know precisely nothing about InnoSetup but surely you need to use ShowModal rather than Show here. Installation UI is invariably modal and what you want here is to wait until the user has finished iteracting with the form before you return to Inno. Otherwise, how would Inno know when to proceed? ShowModal runs a message loop to service the form so there will be no problems receiving input.

You would also change your DLL to remove DestroyWizardForm since the function that calls ShowModal can both create and destroy the form.



回答2:

In my setup I do something similar. InnoSetup code I pass the handle as StrToInt(ExpandConstant('{wizardhwnd}')) (my guess is that MainForm.Handle is zero)

in the DLL:

OldAppHandle := Application.Handle;
try
  Application.Handle := hAppHandle; // hAppHandle the handle from InnoSetup
  F := TfmZForm.Create(Application);
  try
    F.Caption := lpTitle;
    F.ShowModal;
    Result := F.ErrorCode;
  finally
    F.Free;
  end;
finally
  Application.Handle := OldAppHandle;
end;


回答3:

If you want to entirely replace the UI, it will probably be easier to create a stub application that presents the form then runs the normal setup in silent mode passing various command line parameters.

Either that or at the very least, using Inno's native form and wizard page functions/logic.