Sign in to follow this  
Followers 0
sohfeyr

List of items from a context menu

3 posts in this topic

I need to get a list of items in a pop-up (context) menu. I have Larry's code from

http://www.autoitscript.com/forum/index.php?showtopic=6577

and it works fantastic with regular menus and system menus, but I can't get anything from context menus. I'm very new with the Win32 API; could someone help me figure this out?

Here is my code so far:

CODE

#region Const

Global Const $MF_BITMAP = 0x00000004 ;... Uses a bitmap as the menu item

Global Const $MF_BYCOMMAND = 0x00000000

Global Const $MF_BYPOSITION = 0x00000400

Global Const $MF_CHECKED = 0x00000008 ;..... A check mark is placed next to the item (for drop-down menus, submenus, and shortcut menus only).

Global Const $MF_DISABLED = 0x00000002 ;.... The item is disabled.

Global Const $MF_ENABLED = 0x00000000

Global Const $MF_GRAYED = 0x00000001 ;...... The item is disabled and grayed.

Global Const $MF_HILITE = 0x00000080 ;...... The item is highlighted.

Global Const $MF_MENUBARBREAK = 0x00000020 ; This is the same as the MF_MENUBREAK flag, except for drop-down menus, submenus, and

; shortcut menus, where the new column is separated from the old column by a vertical line.

Global Const $MF_MENUBREAK = 0x00000040;... The item is placed on a new line (for menu bars) or in a new column

; (for drop-down menus, submenus, and shortcut menus) without separating columns.

Global Const $MF_OWNERDRAW = 0x00000100;... The item is owner-drawn.

Global Const $MF_POPUP = 0x00000010 ;... Menu item is a submenu.

Global Const $MF_SEPARATOR = 0x00000800;... There is a horizontal dividing line (for drop-down menus, submenus, and shortcut menus only).

Global Const $MF_STRING = 0x00000000 ;... Specifies that the menu item is a text string

Global Const $MF_UNCHECKED = 0x00000000;... Does not place a check mark next to the item (default).

#endregion

#include "Array.au3"

; This works - gets menu hierarchy of the active window.

ListMenuItems(WinGetHandle(""))

; This doesn't work

;For $J = 1 to 5

CWL("---------------------------------------------")

$S = @SEC + 5

If $S > 60 Then $S = $S - 60

While @SEC <> $S

Sleep(1000)

WEnd

$hw = ___GETCLICKMENUHWND("right")

;ListMenuItems($hw,-1,3,0)

;Next

AutoItSetOption("WinSearchChildren",1)

; **** THIS IS BROKEN ***

;~ ------------------------------------------------------------------

;~ Function: ___GETCLICKMENUHWND

;~ Description: Returns handle of a popup menu

;~ Input: $button as string

;~ Output: Returns the handle of a popup menu

;~ Dependencies: ___WINLISTSNAPSHOT, ___GETMENUITEM

;~ ------------------------------------------------------------------

Func ___GETCLICKMENUHWND($button) ; As HWnd

$hwnd1=___WINLISTSNAPSHOT()

; Perform action

Select

Case $button="left" or $button="middle" or $button="right"

MouseClick($button)

;Case StringRight($button, 1)="s" and IsNumber(StringLeft($button, StringLen($button)-1))

; Sleep(Number(StringLeft($button, StringLen($button)-1)))

Case Else

Send($button)

EndSelect

$hwnd2=___WINLISTSNAPSHOT()

Send("{DOWN}")

$WM_CONTEXTMENU = 0x007B

$WM_ENTERMENULOOP = 0x0211

$WM_EXITMENULOOP = 0x0212

$WM_MENUCHAR = 0x0120

$WM_MENUCOMMAND = 0x0126

$WM_MENUDRAG = 0x0123

$WM_MENUGETOBJECT = 0x0124

$WM_MENURBUTTONUP = 0x0122

$WM_MENUSELECT = 0x011F

$WM_NEXTMENU = 0x0213

$WM_UNINITMENUPOPUP = 0x0125

$WM_INITMENU = 0x0116

$WM_INITMENUPOPUP = 0x0117

;Compare the two window lists

For $h In $hwnd2

;If IsMenu($h)=1 then

If _ArraySearch($hwnd1,$h) = -1 Then

;cwl("Loc: " & $L)

;cwl($h & @tab & "Items: " & GetMenuItemCount($h))

$j=ControlGetFocus($h)

$k=ControlGetHandle($h, "", $j)

$L=ControlGetPos($h, "", $j)

$p=WinGetPos($k)

___TEST("k", $k)

$smk = ___GetMenuItem($k, 0, 0)

;___TEST("smk", ___GetMenuItem($k, $k, 0))

;___TEST("smk", ___GetMenuItem($k, 1, 0))

;___TEST("smk", ___GetMenuItem($k, $k, 1))

;___TEST("smk", ___GetMenuItem($k, 1, 1))

___TEST("GSM", GetSubMenu($k, 1))

___TEST("GMS", GetMenuString($k, 1))

$mk = GetMenu($k)

___TEST("mk", $mk)

___TEST("MIID", ____MIID($k, 1))

___TEST("GMS2", ____GMS2($k,1))

___TEST("MIC",GetMenuItemCount($k))

;$b=___GETMENUITEM($k,$k,0)

;___TEST("b", $:whistle:

cwl("pos: " & _ArrayToString($p,","))

cwl("pos: " & _ArrayToString($L,","))

;cwl("itm: " & _ArrayToString($b,","))

cwl($j & @TAB & $k & @TAB & _ArrayToString($L,","))

ListMenuItems($k)

;cwl($k & @tab & "Main: " & GetMenu($k) & @tab & "Sub: " & GetSubMenu($k,0) & @tab & "ID: " & GetMenuItemID($k,1) & @tab & "Items: " & $k)

return $h

EndIf

;EndIf

Next

EndFunc

;Private Declare Function TrackPopupMenu Lib "user32" (ByVal hMenu As Long, ByVal wFlags As Long, ByVal x As Long, ByVal y As Long, ByVal nReserved As Long, ByVal hwnd As Long, ByVal lprc As Any) As Long

;Private Declare Function TrackPopupMenuEx Lib "user32" (ByVal hMenu As Long, ByVal wFlags As Long, ByVal x As Long, ByVal y As Long, ByVal HWnd As Long, ByVal lptpm As Any) As Long

;DllCall("user32","int","TrackPopUpMenuEx","int",$hMenu,"int",$wFlags,"int",$x,"int",$y,"int",$HWnd,

Func ___TEST($txt, $var)

ConsoleWrite("Testing: " & $txt & @TAB)

If IsArray($var) then ConsoleWrite("Array " & _ArrayToString($var, ",") & @cr)

If IsObj($var) then ConsoleWrite("Obj" & @TAB)

If IsNumber($var) then ConsoleWrite("Number" & @TAB)

If IsString($var) then ConsoleWrite("String" & @TAB)

If IsHWnd($var) then ConsoleWrite("HWnd" & @TAB)

If IsWindow($var) then ConsoleWrite("Window" & @TAB)

If IsMenu($var) then ConsoleWrite("Menu" & @TAB)

cwl($var)

EndFunc

;~ ------------------------------------------------------------------

;~ Function: ListMenuItems

;~ Description: Outputs hierarchy of MenuItems starting with $hMenu (which can be a window!)

;~ Input: None

;~ Output: None... For now...

;~ Dependencies: IsWindow, GetMenu, GetSubMenu, ___GETMENUITEM

;~ ------------------------------------------------------------------

Func ListMenuItems($hMenu, $pos=-1, $recurse=3, $nest=0)

If $recurse > 0 and $nest=0 Then $nest=$recurse

If IsWindow($hMenu) Then $hMenu=GetMenu($hMenu)

If $pos>-1 Then

$hSubMenu = GetSubMenu($hMenu, $pos)

Else

$hSubMenu=$hMenu

EndIf

$num=GetMenuItemCount($hSubMenu)

For $i=0 to $num-1

$x = ___GETMENUITEM($hMenu, $hSubMenu, $i)

For $g = $recurse to $nest

ConsoleWrite(@tab)

Next

For $w = 0 to UBound($x)-1

Consolewrite($x[$w] & @tab)

Next

ConsoleWrite(@cr)

If $recurse > 0 then

If $x[6] = 1 then ListMenuItems($x[0], -1, $recurse - 1, $nest)

EndIf

Next

EndFunc

;~ ------------------------------------------------------------------

;~ Function: ___WINLISTSNAPSHOT

;~ Description: Returns an array of all current window handles

;~ Input: None

;~ Output: Returns an array of all current window handles

;~ Dependencies: None

;~ ------------------------------------------------------------------

Func ___WINLISTSNAPSHOT() ; As Array(Of HWnd)

$winArray = WinList()

$hwnds = _ArrayCreate("")

For $i = 1 To $winArray[0][0]

_ArrayAdd($hwnds, $winArray[$i][1])

Next

Return $hwnds

EndFunc

;===============================================================================

; Function Name: ___FLAGTEST

; Description: Boolean test for presence of a particular BitFlag

;===============================================================================

Func ___FLAGTEST($Check, $For) ; As Boolean

If BitAND($Check, $For) = $For Then

Return 1

Else

Return 0

EndIf

EndFunc

;===============================================================================

; Function Name: CWL

; Description: ConsoleWriteLine; Short wrapper for ConsoleWrite($data & @CR)

; Parameters: $data = output

;===============================================================================

Func CWL($data)

ConsoleWrite($data & @cr)

EndFunc

;===============================================================================

; Function Name: ___GETMENUITEM

; Description:

; Parameters:

; Author(s):

; Returns: An array: [0] ID [1] text [2] NormalText [3] TextWithAccl

;~ [4] Accelerator [5] Hotkey [6] IsPopup [7] IsChecked

;~ [8] IsDisabled [9] IsHilited [10] IsGrayed [11] IsSeperator

;~ [12] IsMenuBreak [13] IsMenuBarBreak

;===============================================================================

Func ___GETMENUITEM($hMenu, $hSubMenu, $pos)

Local $id = GetMenuItemID($hSubMenu, $pos)

Local $MS = GetMenuState($hSubMenu, $id)

Local $IsChecked =___FLAGTEST($MS, $MF_CHECKED)

Local $IsDisabled =___FLAGTEST($MS, $MF_DISABLED)

Local $IsHilited =___FLAGTEST($MS, $MF_HILITE)

Local $IsPopup =___FLAGTEST($MS, $MF_POPUP)

Local $IsGrayed =___FLAGTEST($MS, $MF_GRAYED)

Local $IsSeperator =___FLAGTEST($MS, $MF_SEPARATOR)

Local $IsMenuBreak =___FLAGTEST($MS, $MF_MENUBREAK)

Local $IsMenuBarBreak =___FLAGTEST($MS, $MF_MENUBARBREAK)

Local $text=""

If $IsPopUp Then

$id=GetSubMenu($hSubMenu, $pos)

$text=GetMenuString($hSubMenu, $id)

;$text=GetSubMenuTitle($id, $pos)

If IsArray($text) Then

;ConsoleWrite($id & @tab & $text[0] & @tab & $text[1] & @tab & $text[2] & _

;@tab & $text[3] & @tab & $text[4] & @tab & $text[5] & @cr)

$text=$text[3]

EndIf

Else

$text=GetMenuString($hMenu, $id)

If IsArray($text) Then $text=$text[3]

EndIf

Local $NormalText=$text

$AcclText=$text

$Hotkey=""

$Accelerator=""

$tmp=StringInStr($text, "&")

If $tmp>0 then

$Accelerator=StringMid($text,$tmp+1,1)

EndIf

$tmp=StringInStr($text, @tab)

If $tmp>0 then

$Hotkey=StringMid($text,$tmp+1)

$AcclText = StringMid($text,1,$tmp-1)

EndIf

$NormalText=StringReplace($AcclText,"&","")

$ary= _ArrayCreate($id, $text, $NormalText, $AcclText, $Accelerator, $Hotkey, $IsPopup, _

$IsChecked, $IsDisabled, $IsHilited, $IsGrayed, $IsSeperator, $IsMenuBreak, $IsMenuBarBreak)

;cwl(_ArrayToString($ary, @tab))

Return $ary

EndFunc

#region Wrapped API

;===============================================================================

; Function Name: AppendMenuItem

; Description:

; Parameters:

; Author(s):

; Returns:

;===============================================================================

Func AppendMenuItem($DMI_hwnd, $DMI_flags=0x00000000,$DMI_string="New Item")

$DMI_r = DllCall("user32.dll","int","AppendMenu","hwnd",$DMI_hwnd,"int",$DMI_flags,"int",0,"str",$DMI_string)

EndFunc

;===============================================================================

; Function Name: DeleteMenuItem

; Description:

; Parameters:

; Author(s):

; Returns:

;===============================================================================

Func DeleteMenuItem($DMI_hWnd, $DMI_id, $DMI_opt)

If $DMI_hWnd <= 0 Or $DMI_id < 0 Then Return -1

If $DMI_opt = 0 Then

$DMI_opt = $MF_BYCOMMAND

Else

$DMI_opt = $MF_BYPOSITION

EndIf

$DMI_r = DllCall("user32.dll", "hwnd", "DeleteMenu", _

"hwnd", $DMI_hWnd, _

"int", $DMI_id, _

"int", $DMI_opt)

If @error Then Return 0

Return $DMI_r[0]

EndFunc ;==>DeleteMenuItem

;===============================================================================

; Function Name: GetMenuState

; Description:

; Parameters:

; Author(s):

; Returns:

;===============================================================================

Func GetMenuState($GMSte_hWnd, $GMSte_id, $GMSte_Opt = 0)

If $GMSte_hWnd <= 0 Or $GMSte_id < 0 Then Return -1

If $GMSte_Opt = 0 Then

$GMSte_Opt = $MF_BYCOMMAND

Else

$GMSte_Opt = $MF_BYPOSITION

EndIf

$GMSte_r = DllCall("user32.dll", "int", "GetMenuState", _

"hwnd", $GMSte_hWnd, _

"int", $GMSte_id, _

"int", $GMSte_Opt)

If @error Then Return -1

Return $GMSte_r[0]

EndFunc ;==>GetMenuState

Func ____GMS2($GMSte_hWnd, $GMSte_id, $GMSte_Opt = 0)

If $GMSte_Opt = 0 Then

$GMSte_Opt = $MF_BYCOMMAND

Else

$GMSte_Opt = $MF_BYPOSITION

EndIf

$GMSte_r = DllCall("user32.dll", "int", "GetMenuState", _

"hwnd", $GMSte_hWnd, _

"int", $GMSte_id, _

"int", $GMSte_Opt)

Return $GMSte_r

EndFunc

;===============================================================================

; Function Name: GetMenuString

; Description: The GetMenuItemCount function determines the number of items in the specified menu.

; Parameters: $GMS_hWnd handle the menu or submenu

; $GMS_id Menu item to query

; Syntax: GetMenuString($GMIC_hWnd)

; Author(s):

; Returns: Array: TextLength (return value), ParentHandle, MenuID, Text, TextLength+1, 0

;===============================================================================

Func GetMenuString($GMS_hWnd, $GMS_id, $GMS_Opt = 0)

If $GMS_hWnd <= 0 Or $GMS_id < 0 Then Return 0

If $GMS_Opt = 0 Then

$GMS_Opt = $MF_BYCOMMAND

Else

$GMS_Opt = $MF_BYPOSITION

EndIf

$GMS_r = DllCall("user32.dll", "int", "GetMenuString", "hwnd", $GMS_hWnd, "int", $GMS_id, "str", "", "int", 0, "int", $GMS_Opt)

If @error Then Return 0

;ConsoleWrite("GetMenuString[0] : [0]=" & $GMS_r[0] & " [1]=" & $GMS_r[1] & " [2]=" & $GMS_r[2] & " [3]=" & $GMS_r[3] & " [4]=" & $GMS_r[4] & " [5]=" & $GMS_r[5] & @cr)

$GMS_r = DllCall("user32.dll", "int", "GetMenuString", "hwnd", $GMS_hWnd, "int", $GMS_id, "str", "", "int", $GMS_r[0] + 1, "int", $GMS_Opt)

If @error Then Return 0

;ConsoleWrite("GetMenuString[1] : [0]=" & $GMS_r[0] & " [1]=" & $GMS_r[1] & " [2]=" & $GMS_r[2] & " [3]=" & $GMS_r[3] & " [4]=" & $GMS_r[4] & " [5]=" & $GMS_r[5] & @cr)

Return $GMS_r

EndFunc ;==>GetMenuString

;~ ------------------------------------------------------------------

;~ Function: GetMenu

;~ Description: Returns the handle of the main menubar of the given window

;~ Input: $GM_hWnd Window handle

;~ Output: Returns the handle of the main menubar of the given window

;~ Dependencies:

;~ ------------------------------------------------------------------

Func GetMenu($GM_hWnd)

If $GM_hWnd <= 0 Then Return 0

$GM_r = DllCall("user32.dll", "hwnd", "GetMenu", _

"hwnd", $GM_hWnd)

If Not @error Then Return $GM_r[0]

Return 0

EndFunc ;==>GetMenu

;~ ------------------------------------------------------------------

;~ Function: GetMenuItemID

;~ Description: Returns the MIID of the menuitem at the given position

;~ Input: $GM_hWnd Window handle

;~ Output: Returns the MIID of the menuitem at the given position. -1 if MIID is null or if the specified item opens a submenu

;~ Dependencies:

;~ ------------------------------------------------------------------

Func GetMenuItemID($GMI_hWnd, $GMI_pos)

If $GMI_hWnd <= 0 Or $GMI_pos < 0 Then Return -3

$GMI_r = DllCall("user32.dll", "int", "GetMenuItemID", "hwnd", $GMI_hWnd, "int", $GMI_pos)

If Not @error Then Return $GMI_r[0]

Return -2

EndFunc ;==>GetMenuItemID

Func ____MIID($GMI_hWnd, $GMI_pos)

Return DllCall("user32.dll", "int", "GetMenuItemID", "hwnd", $GMI_hWnd, "int", $GMI_pos)

EndFunc

;===============================================================================

; Function Name: GetMenuItemCount

; Description: The GetMenuItemCount function determines the number of items in the specified menu.

; Parameters: $GMIC_hWnd handle the menu or submenu

; Syntax: GetMenuItemCount($GMIC_hWnd)

; Author(s):

; Returns: -1 on error or the menu item count on success

;===============================================================================

Func GetMenuItemCount($GMIC_hWnd)

If $GMIC_hWnd <= 0 Then Return -1

$GMIC_r = DllCall("user32.dll","int","GetMenuItemCount","hwnd",$GMIC_hWnd)

If @error Then Return -1

Return $GMIC_r[0]

EndFunc

;===============================================================================

; Function Name: GetSubMenu

; Description: Retrieves the handle of the submenu coming form the given position

; Parameters: $GMIC_hWnd handle the parent menu or submenu

; Author(s):

; Returns: 0 on error or the menu handle on success

;===============================================================================

Func GetSubMenu($GSM_hWnd, $GSM_pos)

If $GSM_hWnd <= 0 Or $GSM_pos < 0 Then Return 0

$GSM_r = DllCall("user32.dll", "hwnd", "GetSubMenu", "hwnd", $GSM_hWnd, "int", $GSM_pos)

If Not @error Then Return $GSM_r[0]

Return 0

EndFunc ;==>GetSubMenu

Func ____GSM($GSM_hWnd, $GSM_pos)

Return DllCall("user32.dll", "hwnd", "GetSubMenu", "hwnd", $GSM_hWnd, "int", $GSM_pos)

EndFunc

;===============================================================================

; Function Name: GetSubMenuTitle

; Description: Retrieves the title of the submenu coming from the given position

; Parameters: $hMenu handle the parent menu or submenu

; $pos positon to interrogete

; Author(s):

; Returns: 0 on error or the menu handle on success

;===============================================================================

Func GetSubMenuTitle($hMenu, $pos) ; As String

$text = DllCall("user32.dll", "int", "GetMenuString", _

"hwnd", $hMenu, "int", $pos, "str", "", "int", 24, "int", $MF_BYPOSITION)

Return $text

EndFunc

;===============================================================================

; Function Name: GetSystemMenu

; Description: Retrieves the system menu for the given window

; Parameters: $GSM_hWnd Window handle

; $GSM_bRevert ?

; Author(s):

; Returns: 0 on error or the menu handle on success

;===============================================================================

Func GetSystemMenu($GSM_hWnd, $GSM_bRevert = 0)

If $GSM_hWnd <= 0 Then Return -1

If $GSM_bRevert <> 0 Then $GSM_bRevert = 1

$GSM_r = DllCall("user32.dll", "hwnd", "GetSystemMenu", _

"hwnd", $GSM_hWnd, _

"int", $GSM_bRevert)

If @error Then Return -1

Return $GSM_r[0]

EndFunc ;==>GetSystemMenu

;===============================================================================

; Function Name: IsMenu

; Description: Is the given HWND a menu handle?

; Parameters: $hWnd handle to test

; Author(s): JW

; Returns: 0 or 1 if it is a menu handle

;===============================================================================

Func IsMenu($hWnd)

$hWnd=HWnd($hWnd)

If $hWnd <= 0 Then Return 0

$GM_r = DllCall("user32.dll", "int", "IsMenu", "hwnd", $hWnd)

If @error Then Return 0

If $GM_r=0 then Return 0

Return 1

EndFunc

;===============================================================================

; Function Name: IsWindow

; Description: Is the given HWND a window handle?

; Parameters: $hWnd handle to test

; Author(s): JW

; Returns: 0 or 1 if it is a window handle

;===============================================================================

Func IsWindow($hWnd)

$hWnd=HWnd($hWnd)

If $hWnd <= 0 Then Return 0

$GM_r = DllCall("user32.dll", "int", "IsWindow", "hwnd", $hWnd)

If @error Then Return -4

If $GM_r=0 then Return 0

Return 1

EndFunc

#endregion

Share this post


Link to post
Share on other sites



I need to get a list of items in a pop-up (context) menu. I have Larry's code from

http://www.autoitscript.com/forum/index.php?showtopic=6577

and it works fantastic with regular menus and system menus, but I can't get anything from context menus. I'm very new with the Win32 API; could someone help me figure this out?

Nobody else has had this problem and figured out a way? It's such a common UI thing...

I can already detect new windows, and I can get a handle to the window hosting the context menu - maybe even the menu itself - I just can't get at the items!

Anyone? Anyone? :P

Share this post


Link to post
Share on other sites

Nobody else has had this problem and figured out a way? It's such a common UI thing...

I can already detect new windows, and I can get a handle to the window hosting the context menu - maybe even the menu itself - I just can't get at the items!

Anyone? Anyone? :P

I realize this post is over a year old, but I am trying to do the same thing and I can't find an answer anywhere on the forums despite having been trawling for two days. I know Auto3Lib can automate context menus but I can't figure out how to do this with the latest version of AutoIt. Can anyone point me in the right direction? I'm willing to beg. :-)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0