菜单,图表与对话框都是可执行文件的组成部分,他们是以资源的形式存放在文件中的,但这些资源并不存放在数据段中,而是单独的放在一个节区当中。
资源文件是以".rc"为扩展名的脚本文件,由资源文件rc.exe编译成res为扩展名的二进制的资源文件,最后在link.exe文件链入可执行文件。
#define ICO_MAIN 0x1000 //图标
#define IDM_MAIN 0x2000 //菜单
#define IDA_MAIN 0x2000 //加速键
#define IDM_OPEN 0x4101
#define IDM_OPTION 0x4102
#define IDM_EXIT 0x4103
#define IDM_SETFONT 0x4201
#define IDM_SETCOLOR 0x4202
#define IDM_INACT 0x4203
#define IDM_GRAY 0x4204
#define IDM_BIG 0x4205
#define IDM_SMALL 0x4206
#define IDM_LIST 0x4207
#define IDM_DETALL 0x4208
#define IDM_TOOLBAR 0x4209
#define IDM_TOOLBARTEXT 0x4210
#define IDM_INPUTBAR 0x4211
#define IDM_STATUSBAR 0x4212
#define IDM_HELP 0x4301
#define IDM_ABOUT 0x4302
#define IDM_DETAIL 0x4303
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//ICO_MAIN ICON "Main.ico"
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
IDM_MAIN menu discardable//disacrdable表明在不适用菜单时,可以从内存中卸载
BEGIN
popup "文件(&F)";顶级菜单
BEGIN
menuitem "打开文件(&O)…", IDM_OPEN
menuitem "关闭文件(&C)…", IDM_OPTION
menuitem separator;分隔符
menuitem "退出(&X)", IDM_EXIT
END
popup "查看(&V)";顶级菜单
BEGIN
menuitem "字体(&F)…\tAlt+F", IDM_SETFONT
menuitem "背景色(&B) …\tCtrl+Alt+B", IDM_SETCOLOR
menuitem separator
menuitem "被禁用的菜单项", IDM_INACT, INACTIVE
menuitem "被灰化的菜单项", IDM_GRAY, GRAYED
menuitem separator
menuitem "大图标(&G)", IDM_BIG
menuitem "小图标(&M)", IDM_SMALL
menuitem "列表(&L)", IDM_LIST
menuitem "详细资料(&D)", IDM_DETAIL
menuitem separator
popup "工具栏(&T)";二级菜单
BEGIN
menuitem "标准按钮(&S)", IDM_TOOLBAR
menuitem "文字标签(&C)", IDM_TOOLBARTEXT
menuitem "命令栏(&I)", IDM_INPUTBAR
END
menuitem "状态栏(&U)", IDM_STATUSBAR
END
popup "帮助(&H)" HELP;顶级菜单
BEGIN
menuitem "帮助主题(&H)\F1", IDM_HELP
menuitem separator
menuitem "关于本程序(&A)…", IDM_ABOUT
END
END
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
IDA_MAIN accelerators;加速键,或者说定义在资源文件中的快捷键
BEGIN
; VK_F1, IDM_HELP, VIRTKEY
"B", IDM_SETCOLOR, VIRTKEY, CONTROL, ALT
"F", IDM_SETFONT, VIRTKEY, ALT
END
//菜单的属性
//CHECKED---表示打上选定标志
//GRAYED----表示菜单式灰色的
//INACTIVE--表示菜单式禁用的
//MENUBREAK或者MENUBARBREAK--表示菜单项和以后的菜单项列到新的列中
//键名,命令ID,类型,选项
//例如: "^C"表示Ctrl加上字母键
// "字母",这时必须指明是VIRTKEY
// "数字",表示ASCII码为该数值的字母,类型中必须指明是ASCII
// 类型中可以是VIRTKEY,ASCII 这两个,表明键名字段是虚拟键还是ASCII
// 选项可以是 ALT,CONTROL或者是SHIFT中的一个或者多个
这里面有resource.h文件,该文件并不是系统文件,而是自己写的,其中定义了各种ID的数值,如果在.rc文件加入了控件的ID,则不再使用resource.h
下面是演示的win32汇编代码:
.386
.model flat,stdcall
option casemap:none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Equ 等值定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ICO_MAIN equ 1000h ;图标
IDM_MAIN equ 2000h ;菜单
IDA_MAIN equ 2000h ;加速键
IDM_OPEN equ 4101h
IDM_OPTION equ 4102h
IDM_EXIT equ 4103h
IDM_SETFONT equ 4201h
IDM_SETCOLOR equ 4202h
IDM_INACT equ 4203h
IDM_GRAY equ 4204h
IDM_BIG equ 4205h
IDM_SMALL equ 4206h
IDM_LIST equ 4207h
IDM_DETAIL equ 4208h
IDM_TOOLBAR equ 4209h
IDM_TOOLBARTEXT equ 4210h
IDM_INPUTBAR equ 4211h
IDM_STATUSBAR equ 4212h
IDM_HELP equ 4301h
IDM_ABOUT equ 4302h
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data?
hInstance dd ?
hWinMain dd ?
hMenu dd ?
hSubMenu dd ?
.const
szClassName db 'Menu Example',0
szCaptionMain db 'Menu',0
szMenuHelp db '帮助主题(&H)',0
szMenuAbout db '关于本程序(&A)...',0
szCaption db '菜单选择',0
szFormat db '您选择了菜单命令:%08x',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 弹出窗口,显示菜单命令ID
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_DisplayMenuItem proc _dwCommandID
local @szBuffer[256]:byte
pushad
invoke wsprintf, addr @szBuffer, addr szFormat, _dwCommandID
invoke MessageBox, hWinMain, addr @szBuffer, offset szCaption, MB_OK
popad
ret
_DisplayMenuItem endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 退出
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_Quit proc
invoke DestroyWindow, hWinMain
invoke PostQuitMessage, NULL
ret
_Quit endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 窗口过程
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcWinMain proc uses ebx edi esi, hWnd, uMsg, wParam, lParam
local @stPos:POINT
local @hSysMenu
mov eax,uMsg
;*************************************************************************
.if eax == WM_CREATE
invoke GetSubMenu, hMenu, 1
mov hSubMenu, eax
;***************************************************************************
; 在系统菜单中添加菜单项
;***************************************************************************
invoke GetSystemMenu, hWnd, FALSE
mov @hSysMenu, eax
invoke AppendMenu, @hSysMenu, MF_SEPARATOR, 0, NULL
invoke AppendMenu, @hSysMenu, 0, IDM_HELP, offset szMenuHelp
invoke AppendMenu, @hSysMenu, 0, IDM_ABOUT, offset szMenuAbout
;***************************************************************************
; 处理菜单及加速键消息
;***************************************************************************
.elseif eax == WM_COMMAND
invoke _DisplayMenuItem, wParam
mov eax, wParam
movzx eax, ax
.if eax == IDM_EXIT
call _Quit
.elseif eax >= IDM_TOOLBAR && eax <= IDM_STATUSBAR
mov ebx, eax
invoke GetMenuState, hMenu, ebx, MF_BYCOMMAND
.if eax == MF_CHECKED
mov eax, MF_UNCHECKED
.else
mov eax, MF_CHECKED
.endif
invoke CheckMenuItem, hMenu, ebx, eax
.elseif eax >= IDM_BIG && eax <= IDM_DETAIL
invoke CheckMenuRadioItem, hMenu, IDM_BIG, IDM_DETAIL, eax, MF_BYCOMMAND
.endif
;***************************************************************************
; 处理系统菜单消息
;***************************************************************************
.elseif eax == WM_SYSCOMMAND
mov eax, wParam
movzx eax, ax
.if eax == IDM_HELP || eax == IDM_ABOUT
invoke _DisplayMenuItem, wParam
.else
invoke DefWindowProc, hWnd, uMsg, wParam, lParam
ret
.endif
;***************************************************************************
; 单击鼠标右键时弹出一个POPUP菜单
;***************************************************************************
.elseif eax == WM_RBUTTONDOWN
invoke GetCursorPos, addr @stPos
invoke TrackPopupMenu, hSubMenu, TPM_LEFTALIGN, @stPos.x, @stPos.y, NULL, hWnd, NULL
;***************************************************************************
.elseif eax == WM_CLOSE
call _Quit
;***************************************************************************
.else
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif
;***************************************************************************
xor eax,eax
ret
_ProcWinMain endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_WinMain proc
local @stWndClass:WNDCLASSEX
local @stMsg:MSG
local @hAccelerator
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke LoadMenu, hInstance, IDM_MAIN ;获取菜单句柄
mov hMenu, eax ;把菜单句柄存储于hMenu变量
invoke LoadAccelerators, hInstance,IDA_MAIN
mov @hAccelerator, eax
invoke RtlZeroMemory,addr @stWndClass,sizeof @stWndClass
;**************************************************************************
; 注册窗口类
;**************************************************************************
; invoke LoadIcon, hInstance, ICO_MAIN
mov @stWndClass.hIcon, eax
mov @stWndClass.hIconSm, eax
invoke LoadCursor, 0, IDC_ARROW
mov @stWndClass.hCursor, eax
push hInstance
pop @stWndClass.hInstance
mov @stWndClass.cbSize, sizeof WNDCLASSEX
mov @stWndClass.style, CS_HREDRAW or CS_VREDRAW
mov @stWndClass.lpfnWndProc, offset _ProcWinMain
mov @stWndClass.hbrBackground,COLOR_WINDOW + 1
mov @stWndClass.lpszClassName, offset szClassName
invoke RegisterClassEx, addr @stWndClass
;***************************************************************************
; 建立并显示窗口
;***************************************************************************
invoke CreateWindowEx, WS_EX_CLIENTEDGE, \
offset szClassName, offset szCaptionMain, \
WS_OVERLAPPEDWINDOW, \
100, 100, 400, 300, \
NULL, hMenu, hInstance, NULL;;注意,在这儿为窗口加入了菜单项
mov hWinMain,eax
invoke ShowWindow,hWinMain,SW_SHOWNORMAL
invoke UpdateWindow,hWinMain
;**************************************************************************
; 消息循环
;**************************************************************************
.while TRUE
invoke GetMessage, addr @stMsg, NULL, 0, 0
.break .if eax == 0
invoke TranslateAccelerator, hWinMain, @hAccelerator, addr @stMsg;每次消息循环都加入了检测是否有快捷键的消息,如果是加速键中定义的 ;消息,则不再向窗口发送消息,,但自行向窗口发送WM_COMMAND或者WM_SYSCOMMAND,并返回FALSE,并非加速键定义的消息才会进行TranslateMessage和DispatchMessage
.if eax == 0
invoke TranslateMessage, addr @stMsg
invoke DispatchMessage, addr @stMsg
.endif
.endw
ret
_WinMain endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
call _WinMain
invoke ExitProcess, NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
end start
WM_COMMAND消息的两个参数是:
wParam的高位是wNotifyCOde
wParam的低位是发送命令控件ID