1

I want to hide the first and the last message of the uninstaller. This code works with a modified version of inno setup (Inno Setup Ultra 5.5.1.ee2) but does not work well to hide the first message (appears briefly and disappears):

function FindWindowEx(Parent, Child: HWND; ClassName, WindowName: PansiChar): HWND;
  external 'FindWindowExA@user32.dll stdcall';

const
  BM_CLICK    = $00F5;
var
  Timer: TTimer;
  msg: string;
  Wnd, WndEx: HWND;

procedure OnTimer(Sender: TObject);
begin
  Wnd:= FindWindowByWindowName(msg);
  if Wnd > 0 then
  begin
    WndEx:= FindWindowEx(Wnd, 0,'Button', '');
    if WndEx > 0 then
    begin
      PostMessage(WndEx, BM_CLICK, 0, 0);
      Timer.Enabled:= False;
    end;
  end;
end;

function InitializeUninstall:boolean;
begin
  Result := True;
  msg:= SetupMessage(msgUninstallAppFullTitle);
  StringChange(msg, '%1', '{#SetupSetting('AppName')}');
  OnTimer(nil);
  Timer:= TTimer.Create(nil);
  with Timer do
  begin
    OnTimer:= @OnTimer;
    Interval:= 1;
    Enabled:= True;
  end;
end;

procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
  if CurUninstallStep=usPostUninstall then
  begin
    OnTimer(nil);
    Timer:= TTimer.Create(nil);
    with Timer do
    begin
      OnTimer:= @OnTimer;
      Interval:= 1;
      Enabled:= True;
    end;
  end;
end;

How to modify this code to work correctly with the current official version of Inno Setup and to correctly hide both messages?

Andrew Truckle
  • 15,857
  • 13
  • 55
  • 132
Nico Z
  • 837
  • 8
  • 26
  • There's no `TTimer` class in Inno Setup. Do you use some 3rd party build of Inno Setup? – Martin Prikryl Feb 15 '17 at 22:05
  • @MartinPrikryl This code works with a modified version of inno setup (Inno Setup Ultra 5.5.1.ee2). I am using the last version of Inno Setup. – Nico Z Feb 15 '17 at 22:21
  • @MartinPrikryl I edited my post with this information. – Nico Z Feb 15 '17 at 22:28
  • So what do you mean by "correctly"? You can modify the code to work with the official Inno Setup. But you cannot make it better. It will still display the message briefly. – Martin Prikryl Feb 16 '17 at 08:10
  • Where did you get the code from? – Martin Prikryl Feb 16 '17 at 08:11
  • @MartinPrikryl ¨correctly¨: I want to fix this code to work with official inno setup and if it is possible to properly hide the first message so that no appears briefly and disappears. This code was shared with me in a forum but not by the person who created it. – Nico Z Feb 16 '17 at 10:55
  • Did my answer help you? – Martin Prikryl Mar 01 '17 at 20:35
  • @MartinPrikryl Yes, sorry, but I expected something like /silent regarding the first messagebox, but your answer helped me. – Nico Z Mar 01 '17 at 20:45
  • I was trying to internally relaunch the uninstaller with the `/SILENT` switch. But the main instance keeps the `unins000.dat` locked, so the child instance fails. – Martin Prikryl Mar 01 '17 at 21:41
  • I've edited my alternative implementation to make it disallow manual execution of the uninstaller. It is now probably better solution that this approach. See http://stackoverflow.com/q/34126752/850848 – Martin Prikryl Mar 02 '17 at 07:05

1 Answers1

0

First, I must say that I do not agree with this at all. But it's interesting problem anyway, and the implementation might be useful for other, more appropriate cases.

Also you cannot avoid the message to appear briefly. The solution automates the UI, so needs the UI to work. That's one of the reasons I do not like it.


[Setup]
AppName=My Program

[Code]

const
  BM_CLICK = $00F5;

function FindWindowEx(Parent, Child: HWND; ClassName, WindowName: string): HWND;
  external 'FindWindowExW@user32.dll stdcall';
function SetTimer(hWnd, nIDEvent, uElapse, lpTimerFunc: LongWord): LongWord;
  external 'SetTimer@User32.dll stdcall';
function KillTimer(hWnd, nIDEvent: LongWord): LongWord;
  external 'KillTimer@User32.dll stdcall';

var
  UpcomingMessage: string;  
  SubmitMessageTimer: LongWord;
  SubmitMessagePossible: Boolean;

procedure SubmitMessageProc(
  H: LongWord; Msg: LongWord; IdEvent: LongWord; Time: LongWord);
var
  WindowHandle, ButtonHandle: HWND;
begin
  { TODO: Cancel the timer, if the message does not appear within few seconds }
  WindowHandle := FindWindowByWindowName(UpcomingMessage);
  if WindowHandle > 0 then
  begin
    Log(Format('Found message window "%s"', [UpcomingMessage]));
    ButtonHandle := FindWindowEx(WindowHandle, 0, 'Button', '');
    if ButtonHandle > 0 then
    begin
      Log('Found button');
      PostMessage(ButtonHandle, BM_CLICK, 0, 0);
      KillTimer(0, SubmitMessageTimer);
      SubmitMessageTimer := 0;
    end;
  end;
end;

procedure SubmitUpcomingMessage(Msg: string);
begin
  if not SubmitMessagePossible then
  begin
    Log('Cannot submit message');
  end
    else
  begin
    if SubmitMessageTimer > 0 then
      KillTimer(0, SubmitMessageTimer);

    Log(Format('Want to automatically submit message "%s"', [Msg]));
    UpcomingMessage := Msg;
    SubmitMessageTimer := SetTimer(0, 0, 100, CreateCallback(@SubmitMessageProc));
  end;
end;

function FmtSetupMessageWithAppName(const ID: TSetupMessageID): string;
begin
  Result := FmtMessage(SetupMessage(ID), ['{#SetupSetting('AppName')}']);
end;

function InitializeUninstall:boolean;
begin
  Result := True;

  SubmitMessagePossible :=
    FileCopy(
      ExpandConstant('{app}\InnoCallback.dll'),
      ExpandConstant('{%TEMP}\InnoCallback.dll'), False);

  SubmitUpcomingMessage(FmtSetupMessageWithAppName(msgUninstallAppFullTitle));
end;

procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
  if CurUninstallStep = usPostUninstall then
  begin
    SubmitUpcomingMessage(FmtSetupMessageWithAppName(msgUninstallAppFullTitle));
  end;
end;

For CreateCallback function, you need Inno Setup 6.

If you are stuck with Inno Setup 5, you can use WrapCallback function from InnoTools InnoCallback library (the code needs Unicode version of Inno Setup 5). But using an external DLL library from an uninstaller is tricky and has its drawbacks. See Load external DLL for uninstall process in Inno Setup.


For a different approach to the problem, see Changing uninstall confirmation prompt.

Martin Prikryl
  • 167,268
  • 50
  • 405
  • 846