Inno设置 - 自动提交卸载提示

时间:2017-02-15 20:58:10

标签: inno-setup pascalscript

我想要隐藏unisntaller的第一条和最后一条消息。此代码适用于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    = $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;

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

1 个答案:

答案 0 :(得分:0)

首先,我必须说我根本不同意这一点。但无论如何它都是一个有趣的问题,实施可能对其他更合适的案例有用。

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

此代码使用InnoTools InnoCallback DLL library来实现计时器。但是使用来自卸载程序的外部DLL库是棘手的并且有其缺点。请参阅Load external DLL for uninstall process in Inno Setup

[Setup]
AppName=My Program

[Files]
Source: "InnoCallback.dll"; DestDir: {app}

[Code]

const
  BM_CLICK = $00F5;

type
  TTimerProc = procedure(HandleW, msg, idEvent, TimeSys: LongWord);

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';

function WrapTimerProcUninstall(Callback: TTimerProc; ParamCount: Integer): LongWord;
  external 'wrapcallback@{%TEMP}\InnoCallback.dll stdcall uninstallonly delayload';

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, WrapTimerProcUninstall(@SubmitMessageProc, 4));
  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;

代码需要Unicode Inno Setup。

有关问题的其他方法,请参阅Changing uninstall confirmation prompt