In VB (and .net) one can set the visibility of any menu item just by setting .visible to true or false. I'm trying to temporarily hide a menu item but I can't find anything similar in assembly. I don't want to delete and recreate if I can avoid it as there are many I want to hide with large submenu structures. Anyone know how to hide a menu item and show it again later?
Hi Jimg,
Use RemoveMenu and InsertMenuItem.
Regards,
Darrel
Remember that in VB you are setting the state of a menu that does not yet exist when you use the .visible setting in the properties area. If .visible is false, the menu item is not created when you compile the program so you are not controlling an exsiting menu like you do in assembly. So, as a result, you need to do the same thing that VB does, create or not create, if you are comparing the two. To 'hide' a memu item would not be the same thing at all and in this case there is no mechanism beyond removing it and then recreating it. When you use the .visible option 'in your code,' this is what you are actually doing. In this case, the menu already exists so VB just handles the removal or insertion for you.
Paul
Hi Paul-
Actually, you can repeatedly hide and show the menu item at execution time in VB just by setting the property. I have several programs that do just that.
Anyways, if I have to do it the hard way ::) Do you see what's wrong with this?
.486
.model Flat, Stdcall
option Casemap :None ; case sensitive
.nolist
include Windows.inc
uselib MACRO libname:req
include libname.inc
includelib libname.lib
ENDM
uselib user32
uselib kernel32
uselib shell32
uselib comctl32
uselib comdlg32
uselib gdi32
uselib masm32 ; for debug
;uselib debug ; for debug
soff Macro QuotedText:Vararg ; returns offset to a string
Local LocalText
.data
LocalText db QuotedText,0
.code
EXITM <offset LocalText>
Endm
.listall
DlgProc Proto :DWord,:DWord,:DWord,:DWord
inv equ INVOKE
HideTheMenu equ 2005
ShowTheMenu equ 2006
.data?
align 4
hWin dd ? ; dialog handle
hMenu dd ? ; the menu
mi MENUITEMINFO <?>
.code
Program:
inv InitCommonControls
inv GetModuleHandle,NULL
inv DialogBoxParam,eax,101,0,ADDR DlgProc,0
inv ExitProcess,eax
; -----------------------------------------------------------------------
DlgProc proc uses edi esi ebx hWnd:DWord,uMsg:DWord,wParam:DWord,lParam:DWord
.if uMsg == WM_COMMAND
mov eax,wParam
.if ax==HideTheMenu
mov mi.cbSize,sizeof mi
mov mi.fMask,MIIM_ID+MIIM_SUBMENU+MIIM_TYPE+MIIM_STATE
inv GetMenuItemInfo,hMenu,10001,FALSE,addr mi ; 10001 is identifier of File menu
.if eax==0
inv GetErrDescription,eax
.endif
inv RemoveMenu,hMenu,10001,MF_BYCOMMAND
inv DrawMenuBar,hWin
.elseif ax==ShowTheMenu
;inv MessageBox,hWin,soff("showing"),0,0
mov mi.cbSize,sizeof mi
mov mi.fMask,MIIM_ID+MIIM_SUBMENU+MIIM_TYPE+MIIM_STATE
inv InsertMenuItem,hMenu,0,TRUE,addr mi
.if eax==0
inv GetErrDescription,eax
.endif
inv DrawMenuBar,hWin
.endif
.elseif uMsg== WM_INITDIALOG
mov eax,hWnd ; save handle for everyone
mov hWin,eax
inv GetMenu,hWin
mov hMenu,eax
.elseif uMsg == WM_CLOSE
inv EndDialog,hWin,0
.endif
xor eax,eax
ret
DlgProc Endp
end Program
It hides the menu item (removes it) ok, but I can't seem to get it back.
[attachment deleted by admin]
Oops, forgot a part
.elseif ax==ShowTheMenu
mov mi.fMask,miflags
mov mi.fType,MFT_STRING
mov mi.dwTypeData,soff("&File")
inv InsertMenuItem,hMenu,0,TRUE,addr mi
Now it seems to work. Thanks.
And here's the final solution to hiding and reshowing three menu items:
.data?
mi MENUITEMINFO <?> ; for zzFile 10001
mi2 MENUITEMINFO <?> ; for zzReset 10002
mi3 MENUITEMINFO <?> ; for zzHelp 10003
.code
DlgProc proc uses edi esi ebx hWnd:DWord,uMsg:DWord,wParam:DWord,lParam:DWord
.if uMsg == WM_COMMAND
mov eax,wParam
.if ax==HideTheMenu
mov mi.cbSize,sizeof mi
miflags equ MIIM_ID+MIIM_SUBMENU+MIIM_STATE
mov mi.fMask, miflags
inv GetMenuItemInfo,hMenu,10001,FALSE,addr mi ; 10001 is identifier of File menu
inv RemoveMenu,hMenu,10001,MF_BYCOMMAND
mov mi2.cbSize,sizeof mi2
mov mi2.fMask, miflags
inv GetMenuItemInfo,hMenu,10002,FALSE,addr mi2 ; 10002 is identifier of Reset menu
inv RemoveMenu,hMenu,10002,MF_BYCOMMAND
mov mi3.cbSize,sizeof mi3
mov mi3.fMask, miflags
inv GetMenuItemInfo,hMenu,10003,FALSE,addr mi3 ; 10003 is identifier of Help menu
inv RemoveMenu,hMenu,10003,MF_BYCOMMAND
inv DrawMenuBar,hWin
.elseif ax==ShowTheMenu
mov mi.fMask,miflags+MIIM_TYPE
mov mi.fType,MFT_STRING
mov mi.dwTypeData,soff("&File")
inv InsertMenuItem,hMenu,0,TRUE,addr mi
mov mi2.fMask,miflags+MIIM_TYPE
mov mi2.fType,MFT_STRING
mov mi2.dwTypeData,soff("&Reset")
inv InsertMenuItem,hMenu,1,TRUE,addr mi2
mov mi3.fMask,miflags+MIIM_TYPE
mov mi3.fType,MFT_STRING
mov mi3.dwTypeData,soff("&Help")
inv InsertMenuItem,hMenu,2,TRUE,addr mi3
inv DrawMenuBar,hWin
.endif
There has got to be an easier way!
set up your MENUITEMINFO structures on dialog box initialization.
DlgProc proc uses edi esi ebx hWnd:DWord,uMsg:DWord,wParam:DWord,lParam:DWord
.if uMsg == WM_COMMAND
mov eax,wParam
.if ax==HideTheMenu
inv RemoveMenu,hMenu,10001,MF_BYCOMMAND
inv RemoveMenu,hMenu,10002,MF_BYCOMMAND
inv RemoveMenu,hMenu,10003,MF_BYCOMMAND
inv DrawMenuBar,hWin
.elseif ax==ShowTheMenu
inv InsertMenuItem,hMenu,0,TRUE,addr mi
inv InsertMenuItem,hMenu,1,TRUE,addr mi2
inv InsertMenuItem,hMenu,2,TRUE,addr mi3
inv DrawMenuBar,hWin
.endif
.elseif uMsg== WM_INITDIALOG
mov eax,hWnd ; save handle for everyone
mov hWin,eax
inv GetMenu,hWin
mov hMenu,eax
mov mi.cbSize,sizeof mi
mov mi.fMask,MIIM_ID+MIIM_SUBMENU+MIIM_TYPE
mov mi.fType,MFT_STRING
mov mi.dwTypeData,soff("&File")
mov mi.wID,10001
inv GetSubMenu,hMenu,0
mov mi.hSubMenu,eax
mov mi2.cbSize,sizeof mi
mov mi2.fMask,MIIM_ID+MIIM_SUBMENU+MIIM_TYPE
mov mi2.fType,MFT_STRING
mov mi2.dwTypeData,soff("&Reset")
mov mi2.wID,10002
inv GetSubMenu,hMenu,1
mov mi2.hSubMenu,eax
mov mi3.cbSize,sizeof mi
mov mi3.fMask,MIIM_ID+MIIM_SUBMENU+MIIM_TYPE
mov mi3.fType,MFT_STRING
mov mi3.dwTypeData,soff("&Help")
mov mi3.wID,10003
inv GetSubMenu,hMenu,2
mov mi3.hSubMenu,eax
.elseif uMsg == WM_CLOSE
inv EndDialog,hWin,0
.endif
xor eax,eax
ret
DlgProc Endp
Thank you, I'll try it out.
Jimg,
Very nicely done! By the way, I know you can set the properties of the menu at execution time and said so at the end of my post. I think you did not read it all...
Paul
Sorry Paul, thinking of too many things at the same time :eek
Still seems like this is a great lot of work. I'll bet there's some hidden api somewhere that doe this.
And for the finale (drum roll) -- The totally generic version:
.data?
MenusToRemove textequ <0,1,2>
%for MenuNum,<MenusToRemove>
mi&MenuNum& MENUITEMINFO <?>
mi&MenuNum&Caption db 20 dup (?)
endm
.code
DlgProc proc uses edi esi ebx hWnd:DWord,uMsg:DWord,wParam:DWord,lParam:DWord
.if uMsg == WM_COMMAND
mov eax,wParam
.if ax==HideTheMenu
%for MenuNum,<MenusToRemove>
inv RemoveMenu,hMenu,mi&MenuNum&.wID,MF_BYCOMMAND
endm
inv DrawMenuBar,hWin
.elseif ax==ShowTheMenu
%for MenuNum,<MenusToRemove>
inv InsertMenuItem,hMenu,&MenuNum&,TRUE,addr mi&MenuNum&
endm
inv DrawMenuBar,hWin
.endif
.elseif uMsg== WM_INITDIALOG
mov eax,hWnd ; save handle for everyone
mov hWin,eax
inv GetMenu,hWin
mov hMenu,eax
%for MenuNum,<MenusToRemove>
mov mi&MenuNum&.cbSize,sizeof MENUITEMINFO
mov mi&MenuNum&.cch,20
mov mi&MenuNum&.fMask,MIIM_ID+MIIM_SUBMENU+MIIM_TYPE+MIIM_DATA
mov mi&MenuNum&.dwTypeData,offset mi&MenuNum&Caption
inv GetMenuItemInfo,hMenu,&MenuNum&,TRUE,addr mi&MenuNum&
endm
.elseif uMsg == WM_CLOSE
inv EndDialog,hWin,0
.endif
xor eax,eax
ret
DlgProc Endp