 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
Jerry
Joined: 24 Jun 2004 Posts: 39
|
Posted: Thu May 19, 2005 4:54 pm Post subject: Getting text from a menu API GetMenuItemInfo |
|
|
I am tring to write a script that gets the menu text and I am having troubles figuring out the api GetMenuItemInfoA
The syntax of the command is
BOOL GetMenuItemInfo(HMENU hMenu,
UINT uItem,
BOOL fByPosition,
LPMENUITEMINFO lpmii)
Lpmenuiteminfo uses the structure of
Syntax
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;
When I run the script the api keeps getting 0xc0000005 "access violation"
Point on the side, if I call "user32\GetMenuItemInfo" the call gets a -4 error (function could not be found). But if I use "GetMenuItemInfo" or
"user32\GetMenuItemInfoA" at least the function can be found.
| Code: | ; Script Function: Menu R&D
; script name : get menu1.ahk
MF_BYCOMMAND = 0x0000
MF_BYPOSITION = 0x0400
MF_HILITE = 0x0080
MIIM_STRING = 0x040
MIIM_FTYPE = 0x100
MFT_STRING = 0x000
winGet, Hwnd , ID, get menu1.ahk - Notepad ; I have Notepad open with the script while running it
menuHWnd := DllCall("user32\GetMenu",UInt , Hwnd , Uint)
SubmenuHwnd := DllCall("user32\GetSubMenu",UInt , menuHwnd , int, 1)
submenuid := DllCall("GetMenuItemID", Uint, submenuHwnd , Uint, 4, uint) ; Menu selection edit / paste
nchars = 200 ; a little of a over kill but until I get it working...
VarSetCapacity(menuText, nchars)
cbSize = 20 ; 4 bytes each * 5 fields (cbSize, fMask, fType, pointer to menutext, nchars)
getText := DllCall("user32\GetMenuItemInfoA", Uint, SubmenuHwnd , int, MF_BYCOMMAND, uint, submenuid ,uINT , cbSize ,uint , MIIM_STRING | MIIM_FTYPE ,uINT , MFT_STRING ,"str *" , menuText ,uINT , nchars, int )
err := errorlevel
lasterr := DllCall("Kernel32\GetLastError")
msgbox gettext = %gettext% nchars =%nchars% menuText=%menutext% err=%err% lasterr=%lasterr%
; next command hilites the menu item selected... it is working
hilite := DllCall("HiliteMenuItem", Uint, Hwnd, Uint, submenuHwnd, int , submenuid, int, MF_BYCOMMAND | MF_HILITE )
|
Thanks in advance
Jerry |
|
| Back to top |
|
 |
Chris Site Admin
Joined: 02 Mar 2004 Posts: 10467
|
Posted: Fri May 20, 2005 2:26 pm Post subject: Re: Getting text from a menu API GetMenuItemInfo |
|
|
| Quote: | | getText := DllCall("user32\GetMenuItemInfoA", Uint, SubmenuHwnd , int, MF_BYCOMMAND, uint, submenuid ,uINT , cbSize ,uint , MIIM_STRING | MIIM_FTYPE ,uINT , MFT_STRING ,"str *" , menuText ,uINT , nchars, int ) | Since GetMenuItemInfoA requires the address of a struct as its last parameter, there is no easy way to call that function with DllCall (though there might be some hard ways if it's important). Instead, consider calling GetMenuString() if all you need is the menu item's text.
Even if it weren't for the struct issue, there may be some other problems in your call. For example, the second parameter int, MF_BYCOMMAND does not seem to match what the function expects. In addition, since the address of the struct is passed, you can't use the trick of passing extra parameters to the function. That only works for structs like POINT that are passed by value.
| Jerry wrote: | if I call "user32\GetMenuItemInfo" the call gets a -4 error (function could not be found). But if I use "GetMenuItemInfo" or
"user32\GetMenuItemInfoA" at least the function can be found. | Thanks for reporting it. I'll try to fix that for the next update. Edit: I believe this issue has been fixed in today's update.
Last edited by Chris on Wed May 25, 2005 11:14 pm; edited 1 time in total |
|
| Back to top |
|
 |
Jerry
Joined: 24 Jun 2004 Posts: 39
|
Posted: Fri May 20, 2005 6:39 pm Post subject: |
|
|
Chris,
I changed the API to GetMenuString. The API appears to work but
the text does not get copied.
Remarks from the documentation
Syntax:
| Quote: | int GetMenuString( HMENU hMenu,
UINT uIDItem,
LPTSTR lpString,
int nMaxCount,
UINT uFlag
);
| Remarks
| Quote: | The nMaxCount parameter must be one larger than the number of characters in the text string to accommodate the terminating NULL character.
If nMaxCount is 0, the function returns the length of the menu string.
|
Either I am calling the API wrong or nMaxCount does not get the "int, 20" or the variable menuS is not getting set.
Also I show the string length of menus after the command "VarSetCapacity(menuS, 20)" and it shows a length of 0?
I used the below code.
| Code: | ; Script Function: Menu R&D
; script name : get menu1.ahk
MF_BYCOMMAND = 0x0000
MF_BYPOSITION = 0x0400
MF_HILITE = 0x0080
MIIM_STRING = 0x040
MIIM_FTYPE = 0x100
MFT_STRING = 0x000
winGet, Hwnd , ID, get menu1.ahk - Notepad ; I have Notepad open with the script while running it
menuHWnd := DllCall("user32\GetMenu",UInt , Hwnd , Uint)
SubmenuHwnd := DllCall("user32\GetSubMenu",UInt , menuHwnd , int, 1)
submenuid := DllCall("GetMenuItemID", Uint, submenuHwnd , Uint, 4, uint) ; Menu selection edit / paste
VarSetCapacity(menuS, 20)
stringLen, smb, menuS
menuStringResult := DllCall("GetMenuString" , Uint, submenuHwnd, uint, submenuid, "str *", menus, int, 20, uint,MF_BYCOMMAND)
err4 := errorlevel
lasterr =
if err4 = 0
{
lasterr := DllCall("Kernel32\GetLastError")
}
stringLen, sml, menus
msgbox sml=%sml% len=%menuStringResult% string=%menuS% before=%smb% err4=%err4% |
|
|
| Back to top |
|
 |
Chris Site Admin
Joined: 02 Mar 2004 Posts: 10467
|
Posted: Sat May 21, 2005 1:39 am Post subject: |
|
|
I think it will work if you replace "str *" with "str".
Generally, things like LPSTR should be represented as "str". By contrast "str *" is so rarely used that arguably it should not even be mentioned. In any case, the help file was confusing about this area and I will clarify it. |
|
| Back to top |
|
 |
Jerry
Joined: 24 Jun 2004 Posts: 39
|
Posted: Sat May 21, 2005 3:22 am Post subject: |
|
|
It works great Chris
Thanks for your help
Chris wrote
| Quote: | | Since GetMenuItemInfoA requires the address of a struct as its last parameter, there is no easy way to call that function with DllCall (though there might be some hard ways if it's important) |
Just out of curiosity how would you have programmed the struct MENUITEMINFO? |
|
| Back to top |
|
 |
Chris Site Admin
Joined: 02 Mar 2004 Posts: 10467
|
Posted: Sat May 21, 2005 12:25 pm Post subject: |
|
|
| Quote: | | Just out of curiosity how would you have programmed the struct MENUITEMINFO? | I think you could use DllCall("CopyMemory"...) to stack up the value of each struct member in a single script variable (CopyMemory is needed to support binary zeros and other data). ZeroMemory might help with any zeros you need. Then you could pass that variable as a "str" parameter, which the function should see as the memory address of the struct. To get data back out of the struct afterward, you could use CopyMemory again.
You would need some way of putting pure integers into a struct and getting them back out. The math for this would probably involve "Transform Asc/Chr", but perhaps there is an easier way.
Although built-in support for structs might exist someday -- which would make these more difficult methods unnecessary -- until then, someone might devise a set of callable script functions that could take all the drudgery out of struct building and interpretation. |
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|