Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Menu Item State.


  • Please log in to reply
15 replies to this topic
jsmain
  • Members
  • 126 posts
  • Last active: Oct 23 2017 06:24 PM
  • Joined: 11 Jul 2005
I've been researching but I'm now confused...

I have a menu item I wish to check the state of before making any alterations....

It's a Pause menu item in my favorite music application.
I want to configure it so that if it is in a pause state, and I hit the play button, it will release the pause by toggling this menu. Obviously, if it is not set, I don't want to set it when I hit play from my remote control.

The Menu ID is 40121 for this item. Physically, it is the 2nd item in the 4th menu.

{File, Edit, View, Control, then under control, is play, then pause.}

My biggest problem is retrieving the info using GetMenuItemInfo.
I just don't understand the layout for this DllCall.

so far I have the following.

WinGet, hWnd, ID, OtsDJ - Licensed
hMenu :=DllCall("GetMenu",Uint,hWnd,Uint)
hSubMenu :=DllCall("GetSubMenu",Uint,hMenu,int,3)
SubMenuID :=DllCall("GetMenuItemID",Uint,hSubMenu,Uint,1,Uint)

msgbox % SubMenuID

This gives my the proper ID, verified with MS Spy++ utility.

When I add the following code, I get 0, no matter the state of this item.
Obviously it's in the info statement arguments.

Info :=DllCall("GetMenuItemInfo", Uint, hMenu, Uint, 3, Uint, 1, "int", &MenuItemInfo)
msgbox % Info

Could someone help me understand what I'm doing wrong, and what I need to do to get this information properly?


Thanks
Jeff Main

jsmain
  • Members
  • 126 posts
  • Last active: Oct 23 2017 06:24 PM
  • Joined: 11 Jul 2005
BTW, I've also tried this in notepad, trying to determine the state of the word wrap menu item ID 32...

WinGet, hWnd, ID, Untitled - Notepad
hMenu :=DllCall("GetMenu",Uint,hWnd,Uint)
hSubMenu :=DllCall("GetSubMenu",Uint,hMenu,int,2)
SubMenuID :=DllCall("GetMenuItemID",Uint,hSubMenu,Uint,0,Uint)

msgbox % SubMenuID

Info :=DllCall("GetMenuItemInfo",Uint,hMenu,Uint,3,Uint,1,"int",&MenuItemInfo)
msgbox % Info

My reference sources are as follows...
<!-- m -->http://www.autohotke...pic.php?t=21451<!-- m -->
<!-- m -->http://www.autohotke...opic.php?t=8492<!-- m -->
Jeff Main

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
Here's a basic example:
ifWinNotExist, Untitled - Notepad
{
    Run, notepad.exe
    WinWait, Untitled - Notepad
}
WinGet, hWnd, ID, Untitled - Notepad
hMenu :=DllCall("GetMenu", "Uint", hWnd)
hSubMenu := DllCall("GetSubMenu", "Uint", hMenu, "int", 2)

; Set the capacity of mii to sizeof(MENUITEMINFO)
VarSetCapacity(mii, 48, 0)
; Set the cbSize field to sizeof(MENUITEMINFO)
NumPut(48, mii, 0)

; Set the mask to whatever you want to retrieve.
; In this case I set it to MIIM_STATE=1.
NumPut(1, mii, 4)

; Note that menu item positions are zero-based.
DllCall("GetMenuItemInfo", "UInt", hSubMenu, "UInt", 0, "UInt", 1, "UInt", &mii)

; Get the state field out of the struct.
fState := NumGet(mii, 12)

if (fState & 0x8) ; MFS_CHECKED
    MsgBox Word Wrap is enabled!
else
    MsgBox Word Wrap is disabled!

/* Reference: MSDN

typedef struct tagMENUITEMINFO {
  UINT    cbSize; 
  UINT    fMask; 
  UINT    fType; 
  UINT    fState; 
  UINT    wID; 
  HMENU   hSubMenu; 
  HBITMAP hbmpChecked; 
  HBITMAP hbmpUnchecked; 
  ULONG_PTR dwItemData; 
  LPTSTR  dwTypeData; 
  UINT    cch; 
  HBITMAP hbmpItem;
} MENUITEMINFO, *LPMENUITEMINFO; 

BOOL GetMenuItemInfo(          HMENU hMenu,
    UINT uItem,
    BOOL fByPosition,
    LPMENUITEMINFO lpmii
);
*/
/* Reference: Platform SDK Headers

#if(WINVER >= 0x0400)
#define MIIM_STATE       0x00000001
#define MIIM_ID          0x00000002
#define MIIM_SUBMENU     0x00000004
#define MIIM_CHECKMARKS  0x00000008
#define MIIM_TYPE        0x00000010
#define MIIM_DATA        0x00000020
#endif /* WINVER >= 0x0400 */

#if(WINVER >= 0x0500)
#define MIIM_STRING      0x00000040
#define MIIM_BITMAP      0x00000080
#define MIIM_FTYPE       0x00000100

...

#define MFS_GRAYED          0x00000003L
#define MFS_DISABLED        MFS_GRAYED
#define MFS_CHECKED         MF_CHECKED
#define MFS_HILITE          MF_HILITE
#define MFS_ENABLED         MF_ENABLED
#define MFS_UNCHECKED       MF_UNCHECKED
#define MFS_UNHILITE        MF_UNHILITE

...

#define MF_ENABLED          0x00000000L

#define MF_UNCHECKED        0x00000000L
#define MF_CHECKED          0x00000008L

#define MF_UNHILITE         0x00000000L
#define MF_HILITE           0x00000080L

*/
Strangely, it seems to report "disabled" until you actually open the Format menu (even if you don't change anything.) I guess Notepad doesn't actually set the checkmark until then.

Your notepad example has a few issues:[*:2s5cv084]You haven't set the capacity, cbSize, or fMask of MenuItemInfo.
[*:2s5cv084]You're getting the state of an item in hMenu - Word Wrap would be in hSubMenu.
[*:2s5cv084]Perhaps this is different for you, but on Vista, "Word Wrap" is the first item in the menu - position 0. (You've used position 3.)Also, I'd recommend enclosing Uint in quotes ("UInt"). Though it does work without quotes in DllCall, it doesn't in NumGet, etc. It also creates an empty variable named "Uint".

FYI, GetMenuItemInfo sets values in the structure you pass it. The return value isn't menu item information, but a value indicating whether the function succeeded.

If the function succeeds, the return value is nonzero.

If the function fails, the return value is zero. To get extended error information, use the GetLastError function.



jsmain
  • Members
  • 126 posts
  • Last active: Oct 23 2017 06:24 PM
  • Joined: 11 Jul 2005
Thanks for that, and sorry about the typos... I was using a different machine for the testing, and obviously didn't change everything I should have, and would have caught in a direct copy & paste.

After an upgrade to the latest AHK, it works just fine.
Jeff Main

jsmain
  • Members
  • 126 posts
  • Last active: Oct 23 2017 06:24 PM
  • Joined: 11 Jul 2005
lexikos,
This worked better in my app than it did with notepad. However, I now need to understand how to go 1 level deeper. I've been able to access all the first level menus with this script, but there are many more menus that I want to determine the state of that subs of the primary menu.
In this case again, it's OtsDJ, the Options menu (5th menu from the left, index 4) then the 13th menu down, then the 1st option on sub menu to the right.
Jeff Main

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
Simply call GetSubMenu for each level deeper:
hSubSubMenu := DllCall("GetSubMenu", "Uint", hSubMenu, "int", SubSubMenu_PositionWithinSubMenu)


jsmain
  • Members
  • 126 posts
  • Last active: Oct 23 2017 06:24 PM
  • Joined: 11 Jul 2005
Cool!
Thank you very much! 8)
Jeff Main

Obi
  • Guests
  • Last active:
  • Joined: --
I wrote a function that gives back whether a menu item of a window is checked or not (works even with hidden windows, but then turn DetectHiddenWindows On). Here is the Code:

isMenuItemChecked(yourMenuPos, yourSubMenuPos, yourWindow)
{
	WinGet, hWnd, ID, %yourWindow%
	hMenu :=DllCall("GetMenu", "Uint", hWnd)
	hSubMenu := DllCall("GetSubMenu", "Uint", hMenu, "int", yourMenuPos)
	VarSetCapacity(mii, 48, 0)
	NumPut(48, mii, 0)
	NumPut(1, mii, 4)
	DllCall("GetMenuItemInfo", "UInt", hSubMenu, "UInt", yourSubMenuPos, "UInt", 1, "UInt", &mii)
	fState := NumGet(mii, 12)
	if (fState & 0x8)
	    return 1
	else
	    return 0
}

In my opinion that should be a general feature in Autohotkey. Perhaps in the next Version.

How could i check Menu of Righ Click Tray icons if checked?

Regards

Obi
  • Guests
  • Last active:
  • Joined: --
Sorry forgot to mention usage:

In the case of checking wordwrap in notepad (your example above) try:

isMenuItemChecked(2, 0, "ahk_class Notepad")

Obi
  • Guests
  • Last active:
  • Joined: --

Here's a basic example:
Strangely, it seems to report "disabled" until you actually open the Format menu (even if you don't change anything.) I guess Notepad doesn't actually set the checkmark until then.

Your're right in the mark.

To update the menu you have to activate it, the fastest way is to use postmessage:

PostMessage, 0x112, 0xF100,,, ahk_class Notepad
This line activates menu directly. (0x112 = WM_SYSCOMMAND)

Perhaps insert a "sleep, 100" in between. And then:

PostMessage, 0x100, 0x1B,,, ahk_class Notepad
PostMessage, 0x101, 0x1B,,, ahk_class Notepad
...with this 2 lines you press ESC in your window. (WM_KEYDOWN= 0x100, WM_KEYUP = 0x101, 0x1B = VK_ESCAPE)


Now you have updatet your menu item state.
Now it should show the rights state.

stevenp
  • Members
  • 197 posts
  • Last active: Sep 23 2014 05:47 PM
  • Joined: 28 Aug 2006
it's not enough, the submenuN should be focused too
"Simplifying complexity is not simple"

jsmain
  • Members
  • 126 posts
  • Last active: Oct 23 2017 06:24 PM
  • Joined: 11 Jul 2005
Thanks stevep for bringing this topic back. I don't recall ever getting this to work as desired, so maybe we can try again.

Please, can someone provide a working example of getting the state of the notepad wordwrap setting.
Jeff Main

stevenp
  • Members
  • 197 posts
  • Last active: Sep 23 2014 05:47 PM
  • Joined: 28 Aug 2006
maybe by sending a PostMessage to a submenu handle?
"Simplifying complexity is not simple"

Lexikos
  • Administrators
  • 9844 posts
  • AutoHotkey Foundation
  • Last active:
  • Joined: 17 Oct 2006
In my example, insert the following line after hSubMenu := ...:
SendMessage, 0x116, hSubMenu, 0,, ahk_id %hWnd% ; WM_INITMENU
It took me a while to find this as it is not listed under Menu Notifications.

Notepad apparently uses this to set or unset the checkmark each time the menu is activated.

stevenp
  • Members
  • 197 posts
  • Last active: Sep 23 2014 05:47 PM
  • Joined: 28 Aug 2006
Looks like it's an undocumented Windows Menus hack
"Simplifying complexity is not simple"