Inno Setup - Automatically submitting uninstall prompts

China☆狼群 提交于 2019-11-29 08:49:46

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!