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 

Need Help to add MenuitemID to dynamic menuitem tooltip

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





PostPosted: Sat Sep 12, 2009 3:55 am    Post subject: Need Help to add MenuitemID to dynamic menuitem tooltip Reply with quote

This script already works to display a menuitem's Name & Hotkey or menuitem ID.

However, I need help to combine the two code snippets to display
the menuitem ID, Name & Hotkey at the same time.

Dynamically update a tooltip while scrolling thru each menuitem in any menu type.
I call it a MenuSpy.

I've been experimenting with Micha's Sean's & Majkinetor's: Menu scripts.

Specifically the GetContextMenu.... & GetMenu ... Functions.

I've been trying to figure out how to display the contents of each menuitem in any type of menu:
standard, context, popup,tray & ahk menus ONLY in a tooltip as I mouseover each menuitem.

I finally got it working. It displays and updates the Menuitem Name & Hotkey dynamically
in a tooltip as user moves from menuitem to menuitem.

Thanks for the Great menu work! Micha, Sean & Majkinetor:

Use the latest version of Autohotkey 1.0.48.02

How to use this script.

1. Open an application with standards menus. Example: Notepad
2. Run this script
3. Select a Menu, try the EDIT menu.
4. Start moving slowly thru each menuitem
5. The Tooltip appears in the upper left corner of the desktop window
6. The tooltip dynamically updates with the menuitem's Name & Hotkey

As I mentioned above. This works on any type of menu;
standard, context, popup,tray & ahk menus
Even IExplorer, Explorer, and many others.

If it doesn't work on a menu. Then it's NOT a STANDARD Menu!!
You'll need to customize it to suit your needs. Very Happy

Here's the code.

; MenuSpy

; Select Menuitem and it displays Tooltip for any Menu/Menuitem Dynamically

; This script uses part or all of these Menu Scripts

; Micha: GetContext Menu - http://www.autohotkey.com/forum/topic21451.html
; Sean: GetInfo fromContext Menu - http://www.autohotkey.com/forum/viewtopic.php?p=137692.html
; Majkinetor: MMenu - http://www.autohotkey.com/forum/topic17674.html


Code:

; MenuSpy

; It dynamically displays the menuitem Name & Hotkey in a tooltip as user moves thru each menuitem.
; To view the menuitem ID ONLY - Uncomment the code snippet below & comment out label code.

#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 Highlight
  loop, %ContextMenCnt%
  {

   IsEnabled := GetContextMenuState(ControlHwnd, a_index-1)
  ; UnComment for use with MenuitemID
   ;SendMessage, 0x1E1, 0,0,, ahk_class #32768 ; VERIFIED for MenuitemID, FAILED BREAKS Menuitem Name & Hotkey portion
   ;hMenu := ErrorLevel

   {
      TextText =
    if (IsEnabled & MFS_HILITE)
       
         ; menu item identifier of a menu item located at the specified position in a menu using the GetMenuItemID function
       ;MenuitemID := DllCall( "GetMenuItemID", UInt, hMenu, Int, a_index-1 )  ; VERIFIED - UnComment when used with hMenu in "hMenu=errorlevel" above
       StrSize := GetContextMenuText(ControlHwnd, a_index-1)
          TextText = %TextText%%a_index%:%StrSize%`n  ; VERIFIED w/o MenuitemID - Comment Out for MenuitemID
       ;Msgbox    TextText=%TextText% Index=%a_index% StrSize=%StrSize%`n
       StringTrimLeft, TextText, TextText, 2
      StringReplace, TextText, TextText, `:, , All
      TextText = %TextText%      ; VERIFIED w/o MenuitemID - Comment Out for MenuitemID
      ;TextText   = %TextText%ID=%MenuitemID%  ; ****VERIFIED when used with DllCall( "GetMenuItemID" ONLY ***
   }   
  }
  CoordMode, Tooltip, Screen
  Tooltip, %TextText%, 0, 0

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
}

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.
   }
}
Back to top
HotKeyIt



Joined: 18 Jun 2008
Posts: 1994
Location: GERMANY

PostPosted: Sat Sep 12, 2009 10:47 am    Post subject: Reply with quote

Like this Question
Code:

; MenuSpy

; It dynamically displays the menuitem Name & Hotkey in a tooltip as user moves thru each menuitem.
; To view the menuitem ID ONLY - Uncomment the code snippet below & comment out label code.

#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 Highlight
  loop, %ContextMenCnt%
  {

   IsEnabled := GetContextMenuState(ControlHwnd, a_index-1)
  ; UnComment for use with MenuitemID
   ;SendMessage, 0x1E1, 0,0,, ahk_class #32768 ; VERIFIED for MenuitemID, FAILED BREAKS Menuitem Name & Hotkey portion
   ;hMenu := ErrorLevel

   {
      TextText =
    if (IsEnabled & MFS_HILITE)
       
         ; menu item identifier of a menu item located at the specified position in a menu using the GetMenuItemID function
       ;MenuitemID := DllCall( "GetMenuItemID", UInt, hMenu, Int, a_index-1 )  ; VERIFIED - UnComment when used with hMenu in "hMenu=errorlevel" above
       StrSize := GetContextMenuText(ControlHwnd, a_index-1),index:=A_Index-1
          TextText = %TextText%%a_index%:%StrSize%`n  ; VERIFIED w/o MenuitemID - Comment Out for MenuitemID
       ;Msgbox    TextText=%TextText% Index=%a_index% StrSize=%StrSize%`n
       StringTrimLeft, TextText, TextText, 2
      StringReplace, TextText, TextText, `:, , All
      TextText = %TextText%      ; VERIFIED w/o MenuitemID - Comment Out for MenuitemID
      
      ;TextText   = %TextText%ID=%MenuitemID%  ; ****VERIFIED when used with DllCall( "GetMenuItemID" ONLY ***
   }   
  }
  CoordMode, Tooltip, Screen
  Tooltip, % TextText ? index " : " . TextText : "", 0, 0

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
}

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.
   }
}

_________________
AutoHotFile - ToolTip(n,text,title,options) Wink
Back to top
View user's profile Send private message
txquestor



Joined: 22 Aug 2009
Posts: 294

PostPosted: Sat Sep 12, 2009 5:05 pm    Post subject: Reply with quote

Thanks for the quick response HotkeyIt!

Although your syntax is correct.. I'm trying to put the value of "GetMenuItemID" where
you are inserting a "Index" value.

See MSDN http://msdn.microsoft.com/en-us/library/ms647979(VS.85).aspx

The following code does not work but it gives an example of what I'm trying to do.

Replace:
Code:
       ;StrSize := GetContextMenuText(ControlHwnd, a_index-1)


New:
Code:
StrSize := GetContextMenuText(ControlHwnd, a_index-1),MenuitemID := DllCall( "GetMenuItemID", UInt, hMenu, Int, a_index-1 )   


Replace:
Code:
Tooltip, %TextText%, 0, 0


New:
Code:
   Tooltip, % TextText ? MenuitemID " : " . TextText : "", 0, 0


If you want to see what value I'm trying to insert into the Tooltip

Do the following without making the changes above. Instead do the following.

; UnComment these lines:
Code:
SendMessage, 0x1E1, 0,0,, ahk_class #32768 ; VERIFIED for MenuitemID, FAILED BREAKS Menuitem Name & Hotkey portion
   ;hMenu := ErrorLevel


Code:
TextText   = %TextText%ID=%MenuitemID%  ; ****VERIFIED when used with DllCall( "GetMenuItemID" ONLY ***


Comment Out these lines:

Code:
TextText = %TextText%%a_index%:%StrSize%`n  ; VERIFIED w/o MenuitemID


Code:
TextText = %TextText%      ; VERIFIED w/o MenuitemID


And then start Notepad & run the script. You'll see the "GetMenuItemID" value (range 1-65999) for each menuitem in the Tooltip
as you slowly move the thru each menuitem under a Menu, eg. Edit in Notepad is a good example.

Thanks again for your help!
_________________

"Man's quest for knowledge is an expanding series whose limit is infinity"
Back to top
View user's profile Send private message
HotKeyIt



Joined: 18 Jun 2008
Posts: 1994
Location: GERMANY

PostPosted: Sat Sep 12, 2009 7:14 pm    Post subject: Reply with quote

How about that Question
Code:

; MenuSpy

; It dynamically displays the menuitem Name & Hotkey in a tooltip as user moves thru each menuitem.
; To view the menuitem ID ONLY - Uncomment the code snippet below & comment out label code.

#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 Highlight
  loop, %ContextMenCnt%
  {

   IsEnabled := GetContextMenuState(ControlHwnd, a_index-1)
  ; UnComment for use with MenuitemID
   ;SendMessage, 0x1E1, 0,0,, ahk_class #32768 ; VERIFIED for MenuitemID, FAILED BREAKS Menuitem Name & Hotkey portion
   ;hMenu := ErrorLevel

   {
      TextText =
    if (IsEnabled & MFS_HILITE){
       
         ; menu item identifier of a menu item located at the specified position in a menu using the GetMenuItemID function
       ;MenuitemID := DllCall( "GetMenuItemID", UInt, hMenu, Int, a_index-1 )  ; VERIFIED - UnComment when used with hMenu in "hMenu=errorlevel" above
       StrSize := GetContextMenuText(ControlHwnd, a_index-1)
       SendMessage, 0x01E1, , , , ahk_id %ControlHwnd%
       ;Errorlevel is set by SendMessage. It contains the handle to the menu
       MenuitemID := DllCall( "GetMenuItemID", "UInt", ErrorLevel, "Int", a_index-1 )   
      }
          TextText = %TextText%%a_index%:%StrSize%`n  ; VERIFIED w/o MenuitemID - Comment Out for MenuitemID
       ;Msgbox    TextText=%TextText% Index=%a_index% StrSize=%StrSize%`n
       StringTrimLeft, TextText, TextText, 2
      StringReplace, TextText, TextText, `:, , All
      TextText = %TextText%      ; VERIFIED w/o MenuitemID - Comment Out for MenuitemID
     
      ;TextText   = %TextText%ID=%MenuitemID%  ; ****VERIFIED when used with DllCall( "GetMenuItemID" ONLY ***
   }   
  }
  CoordMode, Tooltip, Screen
  Tooltip, % TextText ? MenuitemID " : " . TextText : "", 0, 0

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
}

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.
   }
}

_________________
AutoHotFile - ToolTip(n,text,title,options) Wink
Back to top
View user's profile Send private message
txquestor



Joined: 22 Aug 2009
Posts: 294

PostPosted: Sun Sep 13, 2009 2:40 am    Post subject: Solution to MenuSpy Reply with quote

Thanks for the quick response HotKeyIt.

The code you suggested is correct, however, the location breaks
the dynamic tooltip updatiing.

I moved it to the "IsEnable" section of the script. IT WORKS!

Thanks for all great work of Micha, Majkinetor,Sean & HotKeyIt

How to use this script.

1. Open an application with standards menus. Example: Notepad
2. Run this script
3. Select a Menu, try the EDIT menu.
4. Start moving slowly thru each menuitem
5. The Tooltip appears in the upper left corner of the desktop window
6. The tooltip dynamically updates with the menuitem's ID, Name & Hotkey

The ID is the "GetMenuItemID" function - see MSDN.
It's the value you see in WinInspector and you use in a PostMessage to select a specific menuitem.

As I mentioned above. This works on any type of menu;
standard, context, popup,tray & ahk menus in a tooltip
Even IExplorer, Explorer, and many others.

If it doesn't work on a menu. Then it's NOT a STANDARD Menu!!
You'll need to customize it to suit your needs. Very Happy

Here's the finished code.

Code:
; MenuSpy 1.0
; by TxQuestor
; 9/12/09

; It dynamically displays the menuitem ID, Name & Hotkey in a tooltip as user moves thru each menuitem.

; This script uses part or all of these Menu Scripts

; Micha: GetContext Menu - http://www.autohotkey.com/forum/topic21451.html
; Majkinetor: MMenu - http://www.autohotkey.com/forum/topic17674.html
; Sean: GetInfo fromContext Menu - http://www.autohotkey.com/forum/viewtopic.php?p=137692.html
; HotKeyIt - created code to add the "GetMenuItemID" value to the MenuSpy Tooltip.   

#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)
         
  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 Highlight
  loop, %ContextMenCnt%
  {

   IsEnabled := GetContextMenuState(ControlHwnd, a_index-1)
   ; Uses SendMessage to get the "GetMenuItemID" value
   SendMessage, 0x01E1, , , , ahk_id %ControlHwnd%
   MenuitemID := DllCall( "GetMenuItemID", "UInt", ErrorLevel, "Int", a_index-1 )
   

   {
      TextText =
    if (IsEnabled & MFS_HILITE)

       StrSize := GetContextMenuText(ControlHwnd, a_index-1)
       TextText = %TextText%%a_index%:%StrSize%`n
       StringTrimLeft, TextText, TextText, 2
       StringReplace, TextText, TextText, `:, , All
       TextText = %TextText%   
   }   
  }
  CoordMode, Tooltip, Screen
  Tooltip, % TextText  ? "ID" . MenuitemID " : " . TextText : "", 0, 0

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
}

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.
   }
}

_________________

"Man's quest for knowledge is an expanding series whose limit is infinity"
Back to top
View user's profile Send private message
txquestor



Joined: 22 Aug 2009
Posts: 294

PostPosted: Tue Sep 15, 2009 7:36 pm    Post subject: [SOLVED] Add MenuitemID to dynamic menuitem tooltip Reply with quote

"MenuSpy" Solved

Dynamically display a Menuitem's ID, Name & Hotkey in a Toolip as user moves thru each Menu's Menuitem

Thanks for all great work of Micha, Majkinetor,Sean & HotKeyIt

I used all, part or ideas from their Menu scripts to solve dynamic tooltip of menuitems

How to use this script.

1. Open an application with standards menus. Example: Notepad
2. Run this script
3. Select a Menu, try the EDIT menu.
4. Start moving slowly thru each menuitem
5. The Tooltip appears in the upper left corner of the desktop window
6. The tooltip dynamically updates with the menuitem's ID, Name & Hotkey

The ID is the "GetMenuItemID" function - see MSDN for details.
It's the value you see in WinInspector and you use the value in a PostMessage to select a specific menuitem.

As I mentioned above. This works on any type of menu;
standard, context, popup,tray & ahk menus in a tooltip
Even IExplorer, Explorer, and many others.

If it doesn't work on a menu. Then it's NOT a STANDARD Menu!!
You'll need to customize it to suit your needs.

Here's the finished code.

Code:

; MenuSpy
; by TxQuestor
; 09/12/2009

; It dynamically displays a Menu's  menuitem Name & Hotkey in a tooltip as user moves thru each menuitem.

; Micha: GetContext Menu - http://www.autohotkey.com/forum/topic21451.html
; Sean: GetInfo fromContext Menu - http://www.autohotkey.com/forum/viewtopic.php?p=137692.html
; Majkinetor: MMenu - http://www.autohotkey.com/forum/topic17674.html
; HotKeyIt:  created the code to add the MenuitemID to MenuSpy

#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 )  ; gets MenuitemID to show in Tooltip

   {
      TextText =
    if (IsEnabled & MFS_HILITE)      ; If Menuitem is Enabled & Highlighted get the Values for it's ID, Name & Hotkey
       
     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
         }   
  }
  CoordMode, Tooltip, Screen
  Tooltip, % TextText  ? "ID" . MenuitemID " : " . TextText : "",    ; Displays Menuitem's ID, Name & Hotkey
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.
   }
}
 

_________________

"Man's quest for knowledge is an expanding series whose limit is infinity"
Back to top
View user's profile Send private message
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