The only way I know to do this is to get all the Names & IDs of the popup menu items with this script.
How to use;
Open the app with the Popup Menu of choice.
Run the script.
Activate the Popup Menu and select any menuitem.
It displays the list on the upper left side of the screen.
Code:
; Micha wrote this script for me when I needed something similar.
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
#Persistent
SetTimer, Demo, 500
return
Demo:
; Constants
MFS_HILITE = 0x80
WinGet hWnd, ID, A
hMenu := DllCall("GetMenu", "UInt", hWnd) ; VERIFIED for TextText
MouseGetPos, MouseScreenX, MouseScreenY, MouseWindowUID, MouseControlID
WinGet,ControlHwnd, ID,ahk_id %MouseWindowUID%
;Get count of menu items
ContextMenCnt := GetContextMenuCount(ControlHwnd)
if ContextMenCnt < 1
{
Tooltip,
}
;Read info for each menu item on IsEnabled & Highlight
loop, %ContextMenCnt%
{
; Get the Menuitem State & send Message to Menuitem to retrieve the "GetMenuItemID" value
IsEnabled := GetContextMenuState(ControlHwnd, a_index-1)
SendMessage, 0x01E1, , , , ahk_id %ControlHwnd%
; Errorlevel is set by SendMessage. It contains the ID handle to the menuitem not the same as wID in MIIM_ID from GetMenuItemInfo Function ()
;MenuitemID := DllCall( "GetMenuItemID", "UInt", ErrorLevel, "Int", a_index-1 ) ; ONLY Shows Name & Hotkey
{
TextText =
if (IsEnabled & MFS_HILITE) ; If Menuitem is Enabled & Highlighted get the Values for it's ID, Name & Hotkey
;MenuitemID := DllCall( "GetMenuItemID", "UInt", ErrorLevel, "Int", a_index-1 ) ; ONLY MenuitemID - Name & Hotkey only shows last menu item in menu selected
StrSize := GetContextMenuText(ControlHwnd, a_index-1) ; Gets the Name & Hotkey for a Menuitem
TextText = %TextText%%a_index%:%StrSize%`n
StringTrimLeft, TextText, TextText, 2
StringReplace, TextText, TextText, `:, , All
;TextText =%MenuitemID% %TextText% ; Used to Append MenuitemID to TextText
}
}
CoordMode, Tooltip, Screen
Tooltip, % TextText ? "ID" . MenuitemID " : " . TextText : "", ; Displays Menuitem's Name & Hotkey ID does NOT change
;Tooltip, %TextText% ; Used when MenuitemID is appended to TextText above
return
ESC::ExitApp
/***************************************************************
* Micha - Returns the TEXT of a menu entry (standard, context, popup & ahk menus only!!!)
***************************************************************
*/
GetContextMenuText(hWnd, Position)
{
WinGetClass, WindowClass, ahk_id %hWnd%
if WindowClass <> #32768 ; Get Class of Menu/Menuitem
{
return -1
}
SendMessage, 0x01E1, , , , ahk_id %hWnd%
;Errorlevel is set by SendMessage. It contains the handle to the menu
hMenu := errorlevel
;Allocate a struct for MenuItemInfo. It contains all the data of a Menu/Menuitem
VarSetCapacity(MenuItemInfo, 200, 0)
;Set Size of Struct [48] to the first member
InsertInteger(48, MenuItemInfo, 0, 4)
;Retrieve string MIIM_STRING = 0x40 = 64 (/ MIIM_TYPE = 0x10 = 16)
InsertInteger(64, MenuItemInfo, 4, 4)
;GetMenuItemInfo: Handle to Menu, Index of Position, 0=Menu identifier / 1=Index
InfoRes := DllCall("user32.dll\GetMenuItemInfo",UInt,hMenu, Uint, Position, uint, 1, "int", &MenuItemInfo)
if InfoRes = 0
return -1
InfoResError := errorlevel
LastErrorRes := DllCall("GetLastError")
if InfoResError <> 0
return -1
if LastErrorRes <> 0
return -1
;Get size of string from struct
GetMenuItemInfoRes := ExtractInteger(MenuItemInfo, 40, false, 4)
;If menu is empty return
If GetMenuItemInfoRes = 0
return "{Empty String}"
;+1 should be enough, we'll use 2
GetMenuItemInfoRes += 2
;Set capacity of string that will be filled by windows
VarSetCapacity(PopupText, GetMenuItemInfoRes, 0)
;Set Size plus 0 terminator + security ;-)
InsertInteger(GetMenuItemInfoRes, MenuItemInfo, 40, 4)
InsertInteger(&PopupText, MenuItemInfo, 36, 4)
InfoRes := DllCall("user32.dll\GetMenuItemInfo",UInt,hMenu, Uint, Position, uint, 1, "int", &MenuItemInfo)
if InfoRes = 0
return -1
InfoResError := errorlevel
LastErrorRes := DllCall("GetLastError")
if InfoResError <> 0
return -1
if LastErrorRes <> 0
return -1
return PopupText
}
/***************************************************************
* Micha - returns the count of menu items
***************************************************************
*/
GetContextMenuCount(hWnd)
{
WinGetClass, WindowClass, ahk_id %hWnd%
;All popups should have the window class #32768
if WindowClass <> #32768
{
return 0
}
;Retrieve menu handle from window
SendMessage, 0x01E1, , , , ahk_id %hWnd%
;Errorlevel is set by SendMessage. It contains the handle to the menu
hMenu := errorlevel
menuitemcount:=DllCall("GetMenuItemCount",UInt,hMenu)
Return, menuitemcount
}
/***************************************************************
* Micha - returns the state of a menu entry
***************************************************************
*/
GetContextMenuState(hWnd, Position)
{
WinGetClass, WindowClass, ahk_id %hWnd%
if WindowClass <> #32768
{
return -1
}
SendMessage, 0x01E1, , , , ahk_id %hWnd%
;Errorlevel is set by SendMessage. It contains the handle to the menu
hMenu := errorlevel
;We need to allocate a struct
VarSetCapacity(MenuItemInfo, 60, 0)
;Set Size of Struct to the first member
InsertInteger(48, MenuItemInfo, 0, 4)
;Get only Flags from dllcall GetMenuItemInfo MIIM_TYPE = 1
InsertInteger(1, MenuItemInfo, 4, 4)
;GetMenuItemInfo: Handle to Menu, Index of Position, 0=Menu identifier / 1=Index
InfoRes := DllCall("user32.dll\GetMenuItemInfo",UInt,hMenu, Uint, Position, uint, 1, "int", &MenuItemInfo)
InfoResError := errorlevel
LastErrorRes := DllCall("GetLastError")
if InfoResError <> 0
return -1
if LastErrorRes != 0
return -1
;Get Flag from struct
GetMenuItemInfoRes := ExtractInteger(MenuItemInfo, 12, false, 4)
return GetMenuItemInfoRes
}
;***************************************************************
; Majkinetor's - Get Menu's MenuitemInfo
;***************************************************************
GetMenu(hMenu)
{
Loop, % DllCall("GetMenuItemCount", "Uint", hMenu)
{
idx := A_Index - 1
idn := DllCall("GetMenuItemID", "Uint", hMenu, "int", idx)
nSize++ := DllCall("GetMenuString", "Uint", hMenu, "int", idx, "Uint", 0, "int", 0, "Uint", 0x400)
VarSetCapacity(sString, nSize)
DllCall("GetMenuString", "Uint", hMenu, "int", idx, "str", sString, "int", nSize, "Uint", 0x400) ;MF_BYPOSITION
If !sString
sString := "---------------------------------------"
sContents .= idx . " : " . idn . A_Tab . A_Tab . sString . "`n"
;msgbox idn=%idn%
If (idn = -1) && (hSubMenu := DllCall("GetSubMenu", "Uint", hMenu, "int", idx))
sContents .= GetMenu(hSubMenu)
}
Return sContents
}
;/*
; *********************************
; Original versions of ExtractInteger and InsertInteger provided by Chris
; - from the AutoHotkey help file - Version 1.0.37.04
; *********************************
; *********************************
ExtractInteger(ByRef pSource, pOffset = 0, pIsSigned = false, pSize = 4)
; pSource is a string (buffer) whose memory area contains a raw/binary integer at pOffset.
; The caller should pass true for pSigned to interpret the result as signed vs. unsigned.
; pSize is the size of PSource's integer in bytes (e.g. 4 bytes for a DWORD or Int).
; pSource must be ByRef to avoid corruption during the formal-to-actual copying process
; (since pSource might contain valid data beyond its first binary zero).
{
SourceAddress := &pSource + pOffset ; Get address and apply the caller's offset.
result := 0 ; Init prior to accumulation in the loop.
Loop %pSize% ; For each byte in the integer:
{
result := result | (*SourceAddress << 8 * (A_Index - 1)) ; Build the integer from its bytes.
SourceAddress += 1 ; Move on to the next byte.
}
if (!pIsSigned OR pSize > 4 OR result < 0x80000000)
return result ; Signed vs. unsigned doesn't matter in these cases.
; Otherwise, convert the value (now known to be 32-bit) to its signed counterpart:
return -(0xFFFFFFFF - result + 1)
}
InsertInteger(pInteger, ByRef pDest, pOffset = 0, pSize = 4)
; To preserve any existing contents in pDest, only pSize number of bytes starting at pOffset
; are altered in it. The caller must ensure that pDest has sufficient capacity.
{
mask := 0xFF ; This serves to isolate each byte, one by one.
Loop %pSize% ; Copy each byte in the integer into the structure as raw binary data.
{
DllCall("RtlFillMemory", UInt, &pDest + pOffset + A_Index - 1, UInt, 1 ; Write one byte.
, UChar, (pInteger & mask) >> 8 * (A_Index - 1)) ; This line is auto-merged with above at load-time.
mask := mask << 8 ; Set it up for isolation of the next byte.
}
}
Then use it to get the Name/ID of the menuitem of choice.
Since you are saying you want it by NAME, does this mean you know which one you want?
If, so then you can either manually or with an ahk script take your menuitem choice and
save it to a VAR, then write a Postmessage routine that uses VARs instead of LITERALs to activate the menuitem.
You can add it to this script since it gets the Popup Menu's entire list of menuitems NAMES & IDs.
Go to the line in the script that displays the list.
Code:
Tooltip, % TextText ? "ID" . MenuitemID " : " . TextText : "",
it contains the VAR's you need.