Menu Icons
Allows scripts to add icons to menu items.
Note: Most users would be better off using AutoHotkey v1.1's built-in menu icon support.
(Download removed as it was hosted at the now defunct autohotkey.net)
Usage
Download MI.ahk and place it in your Lib folder. MI_SetMenuItemIcon() is the main function. Usage is explained in MI.ahk.
Known Issues
Using MI_EnableOwnerDrawMenus on the script's main window:
- breaks the "Pause Script" menu item; and
- makes ListLines less useful, since interacting with the main window causes script to execute.
- AutoHotkey 64-bit is not supported.
Examples
; Uncomment this if MI.ahk is not in your function library: ;#include %A_ScriptDir%\MI.ahk #NoEnv ; Sample menu items. Menu, M, Add, 16x16 Icon, ItemClick Menu, M, Add, 32x32 Icon, ItemClick Menu, M, Add, 48x48 Icon, ItemClick ; Set item 1's icon to shell32.dll, icon 4, 16x16. MI_SetMenuItemIcon("M", 1, "shell32.dll", 4, 16) ; Set item 2's icon to shell32.dll, icon 4, 32x32. MI_SetMenuItemIcon("M", 2, "shell32.dll", 4, 32) ; Windows 2000 or later required (supports sizes other than 16x16 and 32x32): MI_SetMenuItemIcon("M", 3, "shell32.dll", 4, 48) ; Usually looks better: MI_SetMenuStyle("M", 0x4000000) ; Note: This menu is shown automatically after setting up the tray menu. ; ; Icons in the Tray menu! ; ; Refer to a menu by handle for efficiency. hTM := MI_GetMenuHandle("Tray") if (A_OSVersion != "WIN_VISTA") { ; It is necessary to hook the tray icon for owner-drawing to work. ; (Owner-drawing is not used on Windows Vista.) OnMessage(0x404, "AHK_NOTIFYICON") OnMessage(0x111, "WM_COMMAND") ; To track "pause" status. MI_SetMenuStyle(hTM, 0x4000000) ; MNS_CHECKORBMP (optional) } SplitPath, A_AhkPath,, SpyPath SpyPath = %SpyPath%\AU3_Spy.exe MI_SetMenuItemIcon(hTM, 1, A_AhkPath, 1, 16) ; open MI_SetMenuItemIcon(hTM, 2, A_WinDir "\hh.exe", 1, 16) ; help ;- MI_SetMenuItemIcon(hTM, 4, SpyPath, 1, 16) ; spy ; reload - icon needed! MI_SetMenuItemIcon(hTM, 6, A_AhkPath, 2, 16) ; edit ;- MI_SetMenuItemIcon(hTM, 8, A_AhkPath, 3, 16) ; suspend MI_SetMenuItemIcon(hTM, 9, A_AhkPath, 4, 16) ; pause MI_SetMenuItemBitmap(hTM, 10, 8) ; exit MI_ShowMenu("M") return ItemClick: return AHK_NOTIFYICON(wParam, lParam) { global hTM, M_IsPaused if (lParam = 0x205) ; WM_RBUTTONUP { ; Update "Suspend Script" and "Pause Script" checkmarks. DllCall("CheckMenuItem","uint",hTM,"uint",65305,"uint",A_IsSuspended ? 8:0) DllCall("CheckMenuItem","uint",hTM,"uint",65306,"uint",M_IsPaused ? 8:0) ; Show menu to allow owner-drawing. MI_ShowMenu(hTM) return 0 } } WM_COMMAND(wParam, lParam, Msg, hwnd) { Critical global M_IsPaused id := wParam & 0xFFFF if id in 65306,65403 ; tray pause, file menu pause { ; When the script is not paused, WM_COMMAND() is called once for ; AutoHotkey --** and once for OwnerDrawnMenuMsgWin **--. DetectHiddenWindows, On WinGetClass, cl, ahk_id %hwnd% if cl != AutoHotkey return ; This will become incorrect if "pause" is used from the script. M_IsPaused := ! M_IsPaused } }
Version History
v2.21 (2010-03-13)
- Fixed: WM_COMMAND messages received by subclassed GUI windows were erroneously forwarded to the script's main window. This broke button gLabels.
- Fixed: Unicode incompatibility in MI_ExtractIcon.v2.2 (2009-01-08)Changed MI_SetMenuItemIcons to automatically delete the previous icon or bitmap.
- If individual menu items are to be removed, call MI_SetMenuItemIcons(MenuNameOrHandle, ItemPos, 0) to remove the icon.
- Added MI_RemoveIcons, to be called before deleting a menu.
- Misc optimizations (thanks animeaime).v2.1 (2007-12-25)Added MI_EnableOwnerDrawnMenus(), which can be used to enable owner-drawn menus for a given window (as an alternative to MI_ShowMenu().)
- MI_SetMenuStyle() now accepts a menu name or handle.v2 (2007-10-19)Now stdlib compatible (added MI_ prefix to functions.)
- Merged everything into MI.ahk, removing wrapper functions in the process.
Operating System Notes
On Windows Vista and later, the script generates a 32-bit device-independent bitmap. This allows nice transparency (alpha blending) in icons, and allows Vista's menu style to apply.
On earlier versions of Windows, this method is not supported. Instead, the menu icons are owner-drawn. ShowMenu() or ShowOwnerDrawnMenu() must be called to show the menu with icons. ShowOwnerDrawnMenu() creates an invisible message window to act as the menu's owner (once per instance of the script.) As a side effect, showing a menu should not make the script/thread uninterruptible.
On Windows 2000 and later, PrivateExtractIcons() is used by SetMenuItemIcon() to extract an icon from a file. This should support any size of icon (tested with 16, 32 and 48.)
ExtractIconEx() is used on earlier versions of Windows, as PrivateExtractIcons() is not available. This supports 16x16 and 32x32 icons only. Other sizes may be specified, but the icon will be stretched to fit, regardless of which sizes are available in the source file. (However, LoadImage() can still be used to load the first icon of any given size from an .ico file.)
References
Shell Blog: Vista Style Menus, Part 1 - Adding icons to standard menus
nanoANT: Themed menu’s icons, a complete Vista and XP solution
Note: I chose to write this rather than use MMenu because:
- I did not want a whole new menu API.
- MMenu exclusively uses owner-drawing for icons, which disables Windows Vista's menu styles.