Does anyone know how to enumerate the menu items in an executing dll?
I used to force the "auto arrange" toggle in the context menu for the desktop by doing
IDM_TOGGLEAUTOARRANGE equ 7041h
inv SendMessage,hParent,WM_COMMAND,IDM_TOGGLEAUTOARRANGE,0
where hParent is the handle of the parent of the syslistview for the desktop.
Apparently, sometime in the last two years or so, by some windows security or other update, the menu item in shell32.dll has been changed from 7041h to 7051h, at least on my xp sp2.
Rather than just hard coding it again I would prefer to track down the correct value in case of future updates.
I tried
invoke GetModuleHandle,addr shell32dll
mov hShell32,eax
inv GetMenu,hShell32
but no luck. If I try
inv GetModuleFileName,hShell32,addr menubuf,99
I get the file name properly, so hShell32 is correct.
When I tried
inv EnumResourceTypes,hShell32,EnumResTypeProc,0
I got some weird stuff.
When I tried
inv EnumResourceNames,hShell32,soff("RT_MENU"),EnumResNameProc,0
I got nothing.
GetMenu needs a hwnd, not a hmod. You could try LoadMenu but you need the menu name/id as well.
I know the handle of the window I'm interested in, there were just too many trees in the way.
I get this by searching for "Progman", searching that window for the child called "SHELLDLL_defVIEW" (which will be the parent, saved in hParent), and searching this for a window called "SysListView32" (which is the actual listview you see on the desktop).
I can trigger the menu item by doing
IDM_TOGGLEAUTOARRANGE equ 7051h
invoke SendMessage,hParent,WM_COMMAND,IDM_TOGGLEAUTOARRANGE,0
However, I cannot get any information about the menu by
invoke GetMenu,hParent
The
invoke EnumResourceTypes,hShell32,EnumResTypeProc,0
which wants a module handle, returns "AVI","REGINST","TYPELIB", and "UIFILE" which didn't help at all.
The
inv EnumResourceNames,hShell32,soff("RT_MENU"),EnumResNameProc,0
returned nothing.
I got the 7051h value by using Resouce Hacker on Shell32.dll and searching for a menu with the string "Auto Arrange". But I can't do this on the fly in the program.
And I'm out of ideas.
If anyone wants to try it, this is the code I use to get the handles-
.data?
hShell32 dd ?
hProgMan dd ?
hParent dd ?
hListView dd ?
.data
shell32dll db "Shell32.DLL",0
progman db "Progman",0
defview db "SHELLDLL_defVIEW", 0
syslistview db "SysListView32", 0
.code
invoke GetModuleHandle,addr shell32dll
mov hShell32,eax
invoke FindWindow,addr progman,0 ; search for desktop listview
mov hProgMan,eax
invoke FindWindowEx,eax, 0,addr defview, 0
mov hParent,eax
invoke FindWindowEx,eax, 0, addr syslistview, 0
mov hListView,eax
hi
Try this i hope thats help you
Progman db "Progman",0
ProgramManager db "Program Manager",0
SHELLDLL_DefView db "SHELLDLL_DefView",0
SysListView32 db "SysListView32",0
FolderView db "FolderView",0
.data?
hndl DWORD ?
.code
start:
invoke FindWindowEx, NULL, NULL, addr Progman, addr ProgramManager
mov hndl,eax
invoke FindWindowEx, hndl, NULL, addr SHELLDLL_DefView, NULL
mov hndl,eax
invoke FindWindowEx, hndl, NULL, addr SysListView32, addr FolderView
mov hndl,eax
invoke IsWindowVisible, hndl
.if eax == FALSE
invoke ShowWindow, hndl, SW_SHOWNOACTIVATE
.else
invoke ShowWindow, hndl, SW_HIDE
.endif
or this
[attachment deleted by admin]
Thank you, ragdog, that's very interesting. I'll put it away for later.
I couldn't see how knowing the handle of "FolderView" helps me. Could you explain this?
I looked through your program and couldn't find anything that helps with this problem, could you point out what you had in mind?
i cannot help with your problem this is not my source
this source have i found on my partion
I knew only that I had somewhere
sorry
greets
ragdog
Use the value RT_MENU instead of the string "RT_MENU" in EnumResourceNames.
Quote from: sinsi on March 25, 2008, 09:42:59 PM
Use the value RT_MENU instead of the string "RT_MENU" in EnumResourceNames.
Doh! Some days are just like that. Still didn't give me anything, but at least it's correct now :red
No error checking in this, but it works for me.
include \masm32\include\masm32rt.inc
.code
ern proc uses ebx hmod,lptype,lpname,lparam
mov eax,lpname
print str$(eax)," "
invoke LoadMenu,hmod,lpname
mov ebx,eax
invoke GetMenuItemCount,ebx
print str$(eax),13,10
invoke DestroyMenu,ebx
ret
ern endp
shell32dll db 'shell32.dll',0
start:
invoke LoadLibrary,addr shell32dll
mov ebx,eax
invoke EnumResourceNames,ebx,RT_MENU,addr ern,0
inkey
invoke ExitProcess,0
end start
I tried to get the names of the enumerated menus, using Sinsi's code. Among the results are Briefcase and Printer - not sure if that does make any sense. I have commented out my attempts to use GetMenuItemInfo - the MSDN documentation is utterly confused.
include \masm32\include\masm32rt.inc
.data?
mt MENUITEMINFO <>
hShell32 dd ?
.data
shell32dll db "Shell32.DLL",0
; progman db "Progman",0
; defview db "SHELLDLL_defVIEW", 0
; syslistview db "SysListView32", 0
buffer db " - "
db 512 dup(0)
.code
ern proc uses ebx hmod,lptype,lpname,lparam
mov eax, hShell32
mov eax,lpname
print str$(eax)," "
invoke LoadMenu,hmod,lpname
mov ebx,eax
; mov mt.fMask, MIIM_FTYPE or MIIM_STRING
; mov mt.fType, MIIM_STRING ;MFT_STRING
; mrm mt.dwTypeData, offset buffer
; mov mt.cch, 512
; invoke GetMenuItemInfo, eax, 0, 1, addr mt
; mov eax, mt.cch
invoke GetMenuItemCount, ebx
.if eax
print str$(eax), 9
invoke GetMenuString, ebx, 0, addr buffer, 512, MF_BYPOSITION
.if eax
print offset buffer
.endif
print " ", 13, 10
.else
print str$(eax),13,10
.endif
invoke DestroyMenu,ebx
ret
ern endp
start:
mov mt.cbSize, sizeof mt
invoke LoadLibrary,addr shell32dll
invoke GetModuleHandle,addr shell32dll
mov hShell32,eax
mov ebx,eax
invoke EnumResourceNames, ebx, RT_MENU, addr ern, 0
inkey
invoke ExitProcess,0
end start
Thank you Sinsi.
I have no excuse other than my inability to read the api documentation.
for EnumResNameProc, it clearly says:
QuotelpszName
Points to a null-terminated string specifying the name of the resource for which the name is being enumerated.
So I was printing it out as a string using MessageBox.
It is actually an integer, not a pointer to a string, so the messagebox crashed without giving me any indication that EnumResNameProc was ever called or that any error had occured. When I changed my original code to print out an integer, everything worked as I had originally intended.
Again, thanks for the clarification.
Just to confuse things, there a 3 different resource names
QuoteIf IS_INTRESOURCE(x) is TRUE for lpszName or lpszType, x specifies the integer identifier of the given resource. Otherwise, it is a pointer to a null-terminated string. If the first character of the string is a pound sign (#), the remaining characters represent a decimal number that specifies the integer identifier of the resource. For example, the string "#258" represents the identifier 258.
So it can be
- an int (00000000-0000FFFF)
- an address of a string which has the name
- an address of a string which has the ascii of an int
How stupid is the last one?
Okay, Thanks. Now I've got to move onto other things.
If anyone's interested, here's my test code the find the menu item I wanted.
include \masm32\include\masm32rt.inc
inv equ invoke
.data
shell32dll db "Shell32.DLL",0
debugprt db "hand=%lx rname=%li mcount=%li id=%li string=<%s>",0
sfound db "Id found = %li %lxh",0
buffx db 200 dup (0)
buffx2 db 50 dup (0)
continueflg dd 1
hShell32 dd 0
IdFound dd 0
stringwanted db "&Auto Arrange",0 ; menu string to search for
.code
GetMenuStuff proc lmh,rname
local mcnt,scnt,menuid,sinx
.if continueflg
inv GetMenuItemCount,lmh
mov mcnt,eax
.if sdword ptr mcnt>0
push ebx
mov ebx,0
.repeat
inv GetSubMenu,lmh,ebx
mov scnt,eax
inv GetMenuItemID,lmh,ebx
mov menuid,eax
inv GetMenuString,lmh,ebx,addr buffx2,49,MF_BYPOSITION
.if eax>0
inv wsprintf,addr buffx,addr debugprt,lmh,rname,mcnt,menuid,addr buffx2
;inv MessageBox,0,addr buffx,0,0
print addr buffx,13,10
inv lstrcmp,addr stringwanted,addr buffx2
.if eax==0
m2m IdFound,menuid
mov continueflg,0
.break
.endif
.endif
.if scnt ; if there was a submenu
inv GetMenuStuff,scnt,rname
.break .if continueflg==0
.endif
inc ebx
.until ebx==mcnt
pop ebx
.endif
.endif
ret
GetMenuStuff endp
EnumResNameProc proc hand,typ,rname,extra
local lmh
inv LoadMenu,hand,rname
mov lmh,eax
inv GetMenuStuff,lmh,rname
inv DestroyMenu,lmh
mov eax,continueflg
ret
EnumResNameProc endp
start:
;invoke GetModuleHandle,addr shell32dll ; when already loaded in a windows program.
invoke LoadLibrary,addr shell32dll
mov hShell32,eax
inv EnumResourceNames,hShell32,RT_MENU,addr EnumResNameProc,0
inv wsprintf,addr buffx,addr sfound,IdFound,IdFound
print addr buffx,13,10
inkey
invoke ExitProcess,0
end start
I'm sure it could be done more efficiently, if anyone wants to play.
I think i'm having some trouble with IS_INTRESOURCE macro. I didn't find the macro anywhere. I'd like to know if it does something like this or if it's otherwize.
EnumResTypesProc PROC hModule:DWORD,lpszType:DWORD,lpszName:DWORD,lParam:DWORD
mov eax,lpszName
cmp eax,0
je ret_FALSE
shr eax,16
cmp ax,0
jne name_is_string
; ITS_INTRESOURCE
mov eax,TRUE
ret
ret_FALSE:
mov eax,FALSE
ret
is it something like this?
EnumResTypesProc endp
This thread is from 2 years back. ::)
I am guessing that the OP is trying to make a plugin for an editor, or something of that sort. He is using EnumMenu.. [ Someone please correct me if I am wrong. ]
Quote from: MSDNThis macro checks whether all bits except the least 16 bits are zero. When true, wInteger is an integer identifier for a resource. Otherwise it is typically a pointer to a string.
So values 0-FFFFh are integers, values 10000h and up are string addresses.
thanks sinsi. That's what i thought. I was experiencing some porblems but i fixed it. I didn't have anything to do with integer lpszType.
Thanks a lot anyway.
Bye and best regards from X.