News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Activating menu items in an executing program

Started by Jimg, March 24, 2008, 01:16:10 PM

Previous topic - Next topic

Jimg

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.





sinsi

GetMenu needs a hwnd, not a hmod. You could try LoadMenu but you need the menu name/id as well.
Light travels faster than sound, that's why some people seem bright until you hear them.

Jimg

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. 



Jimg

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

ragdog

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

ragdog


Jimg

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?

ragdog

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

sinsi

Use the value RT_MENU instead of the string "RT_MENU" in EnumResourceNames.
Light travels faster than sound, that's why some people seem bright until you hear them.

Jimg

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

sinsi

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

Light travels faster than sound, that's why some people seem bright until you hear them.

jj2007

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


Jimg

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.

sinsi

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?
Light travels faster than sound, that's why some people seem bright until you hear them.

Jimg

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.