Inno Setup - Automatically submitting uninstall prompts

后端 未结 1 795
温柔的废话
温柔的废话 2020-12-18 15:52

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 t

1条回答
  •  暖寄归人
    2020-12-18 16:39

    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.

    0 讨论(0)
提交回复
热议问题