Adding context menu to Inno Setup page

前端 未结 1 1750
夕颜
夕颜 2021-01-07 07:30

How can I add some context menu to a specific page of Inno Setup?

For example in installing page, if the user right-clicks on-page, he can see "Cancel" or &

相关标签:
1条回答
  • 2021-01-07 08:07

    Inno Setup does not have an API how context menus, not even for handling mouse clicks. So you need to implement a custom Windows message handler and handle WM_CONTEXTMENU.

    [Code]
    
    const
      GWL_WNDPROC = -4;
      WM_CONTEXTMENU = $007B;
      WM_COMMAND = $0111;
    
    type
      WPARAM = UINT_PTR;
      LPARAM = LongInt;
      LRESULT = LongInt;
    
    const
      MF_BYPOSITION = $0400;
      MF_STRING = $0000;
    
    const
      ID_MUTE = 0;
      ID_STOP = 1;
    
    function CallWindowProc(
      lpPrevWndFunc: LongInt; hWnd: HWND; Msg: UINT; wParam: WPARAM;
      lParam: LPARAM): LRESULT; external 'CallWindowProcW@user32.dll stdcall';  
    function SetWindowLong(hWnd: HWND; nIndex: Integer; dwNewLong: LongInt): LongInt;
      external 'SetWindowLongW@user32.dll stdcall';    
    function CreatePopupMenu: THandle; external 'CreatePopupMenu@User32.dll stdcall';
    function InsertMenu(
      hMenu: THandle; uPosition: Cardinal; uFlags: Cardinal; uIDNewItem: Cardinal;
      lpNewItem: string): Boolean;
      external 'InsertMenuW@User32.dll stdcall';
    function TrackPopupMenu(
      hMenu: THandle; uFlags: Cardinal; x: Integer; y: Integer; nReserved: Integer;
      hWnd: THandle; Rect: Integer): Boolean; 
      external 'TrackPopupMenu@User32.dll stdcall';
    function ClientToScreen(hWnd: HWND; var lpPoint: TPoint): Boolean;
      external 'ClientToScreen@user32.dll stdcall';
      
    var
      OldPageWndProc: LongInt;
      Page: TWizardPage;
    
    function GET_X_LPARAM(dw: DWORD): WORD; // aka LOWORD
    begin
      Result := WORD(dw);
    end;
    
    function GET_Y_LPARAM(dw: DWORD): WORD; // aka HIWORD
    begin
      Result := WORD((dw shr 16) and $FFFF);
    end;
    
    function PageWndProc(hwnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT;
    var
      PopupMenu: THandle;
      X, Y: Integer;
    begin
      if uMsg = WM_CONTEXTMENU then
      begin
        X := GET_X_LPARAM(lParam); 
        Y := GET_Y_LPARAM(lParam); 
    
        PopupMenu := CreatePopupMenu();
        InsertMenu(PopupMenu, -1, MF_BYPOSITION or MF_STRING, ID_MUTE, 'Mute');
        InsertMenu(PopupMenu, -1, MF_BYPOSITION or MF_STRING, ID_STOP, 'Stop');
        TrackPopupMenu(PopupMenu, 0, X, Y, 0, Page.Surface.Handle, 0);
      end
        else
      if uMsg = WM_COMMAND then
      begin
        if wParam = ID_MUTE then
        begin
          MsgBox('Muting', mbInformation, MB_OK);
          Result := 0;
        end
          else
        if wParam = ID_STOP then
        begin
          MsgBox('Stopping', mbInformation, MB_OK);
          Result := 0;
        end;
      end
        else
      begin
        Result := CallWindowProc(OldPageWndProc, hwnd, uMsg, wParam, lParam);
      end;
    end;
    
    procedure InitializeWizard();
    begin
      Page := CreateCustomPage(wpWelcome, 'Page with context menu', '');
    
      OldPageWndProc :=
        SetWindowLong(Page.Surface.Handle, GWL_WNDPROC, CreateCallback(@PageWndProc));
    end;
    
    procedure DeinitializeSetup;
    begin
      SetWindowLong(Page.Surface.Handle, GWL_WNDPROC, OldPageWndProc);
    end;
    

    The GWL_WNDPROC code is based on Inno Setup - How to edit the "About Setup" dialog text box.

    If you want to add icons, see Adding an icon image to context menu in Inno Setup.

    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.

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