Inno Setup - 自动提交卸载提示

Inno Setup - Automatically submitting uninstall prompts

我想隐藏卸载程序的第一条和最后一条消息。此代码适用于 inno setup 的修改版本(Inno Setup Ultra 5.5.1.ee2),但不能很好地隐藏第一条消息(短暂出现并消失):

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

const
  BM_CLICK    = [=10=]F5;
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;

如何修改此代码以正确使用当前正式版本的 Inno Setup 并正确隐藏这两个消息?

首先,我必须说,我完全不同意这种说法。但无论如何这都是一个有趣的问题,该实现可能对其他更合适的情况有用。

也无法避免消息的短暂出现。该解决方案使 UI 自动化,因此需要 UI 才能工作。这也是我不喜欢它的原因之一。


[Setup]
AppName=My Program

[Code]

const
  BM_CLICK = [=10=]F5;

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;

对于 CreateCallback function,您需要 Inno Setup 6。

如果您受困于 Inno Setup 5,您可以使用 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 中的 WrapCallback 功能。


有关解决问题的不同方法,请参阅 Changing uninstall confirmation prompt