AutoHotkey Homepage AutoHotkey Community
Let's help each other out
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Menu Item State.

 
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Ask for Help
View previous topic :: View next topic  
Author Message
jsmain



Joined: 11 Jul 2005
Posts: 81

PostPosted: Sat Aug 04, 2007 11:23 pm    Post subject: Menu Item State. Reply with quote

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.

Code:
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.

Code:
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
Back to top
View user's profile Send private message
jsmain



Joined: 11 Jul 2005
Posts: 81

PostPosted: Sat Aug 04, 2007 11:32 pm    Post subject: Reply with quote

BTW, I've also tried this in notepad, trying to determine the state of the word wrap menu item ID 32...

Code:
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...
http://www.autohotkey.com/forum/viewtopic.php?t=21451
http://www.autohotkey.com/forum/viewtopic.php?t=8492
_________________
Jeff Main
Back to top
View user's profile Send private message
Lexikos



Joined: 17 Oct 2006
Posts: 2558
Location: Australia, Qld

PostPosted: Sun Aug 05, 2007 3:56 am    Post subject: Reply with quote

Here's a basic example:
Code:
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:
  • You haven't set the capacity, cbSize, or fMask of MenuItemInfo.
  • You're getting the state of an item in hMenu - Word Wrap would be in hSubMenu.
  • 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.
Quote:
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.
Back to top
View user's profile Send private message
jsmain



Joined: 11 Jul 2005
Posts: 81

PostPosted: Sun Aug 05, 2007 3:56 pm    Post subject: Reply with quote

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
Back to top
View user's profile Send private message
jsmain



Joined: 11 Jul 2005
Posts: 81

PostPosted: Mon Aug 06, 2007 10:45 pm    Post subject: Reply with quote

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
Back to top
View user's profile Send private message
Lexikos



Joined: 17 Oct 2006
Posts: 2558
Location: Australia, Qld

PostPosted: Tue Aug 07, 2007 7:30 am    Post subject: Reply with quote

Simply call GetSubMenu for each level deeper:
Code:
hSubSubMenu := DllCall("GetSubMenu", "Uint", hSubMenu, "int", SubSubMenu_PositionWithinSubMenu)
Back to top
View user's profile Send private message
jsmain



Joined: 11 Jul 2005
Posts: 81

PostPosted: Tue Aug 07, 2007 12:01 pm    Post subject: Reply with quote

Cool!
Thank you very much! Cool
_________________
Jeff Main
Back to top
View user's profile Send private message
Obi
Guest





PostPosted: Mon Jun 23, 2008 2:32 pm    Post subject: Subroutine Reply with quote

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:

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
Back to top
Obi
Guest





PostPosted: Mon Jun 23, 2008 3:02 pm    Post subject: Reply with quote

Sorry forgot to mention usage:

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

isMenuItemChecked(2, 0, "ahk_class Notepad")
Back to top
Obi
Guest





PostPosted: Tue Jun 24, 2008 12:48 am    Post subject: Reply with quote

Lexikos wrote:
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:

Code:
PostMessage, 0x112, 0xF100,,, ahk_class Notepad

This line activates menu directly. (0x112 = WM_SYSCOMMAND)

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

Code:
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.
Back to top
Display posts from previous:   
Post new topic   Reply to topic    AutoHotkey Community Forum Index -> Ask for Help All times are GMT
Page 1 of 1

 
Jump to:  
You can post new topics in this forum
You can reply to topics in this forum


Powered by phpBB © 2001, 2005 phpBB Group