且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

向Inno设置页面添加上下文菜单

更新时间:2023-12-06 08:17:04

Inno Setup没有一个API上下文菜单,甚至不用于处理鼠标单击.因此,您需要实现自定义Windows消息处理程序并处理WM_CONTEXTMENU.

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;

GWL_WNDPROC代码基于 Inno设置-如何编辑关于设置"对话框文本框 .

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

如果要添加图标,请参见在Inno Setup中的上下文菜单中添加图标图像 .

对于 CreateCallback函数,您需要Inno设置6.如果您对Inno Setup 5不满意,可以使用 InnoTools中的WrapCallback功能InnoCallback 库.

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.