第五章开始创建一个带菜单的窗口,自己把代码打出来又做了注释,只是粘贴到代码段后格式有点乱,对齐什么的,强迫症飘过,暂时没找到好办法整理或者避免……
菜单的资源文件(资源文件的后缀是rs,只是CSDN无法识别这个,就改成txt了)
# include
# 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_SAMLL 0x4206
# define IDM_LIST 0x4207
# define IDM_DETAIL 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
IDM_MAIN menu discardable
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 //\t会使后面的字符串右对齐
menuitem separator
menuitem "被禁用的菜单项", IDM_INACT, INACTIVE //CHECKED,GRAYED,INACTIVE,MENUBREAK,MENUBARBREAK(以下部分另起一列)
menuitem "被灰化的菜单项", IDM_GRAY, GRAYED
menuitem separator
menuitem "大图标(&G)", IDM_BIG
menuitem "小图标(&M)", IDM_SAMLL
menuitem "列表(&L)", IDM_LIST
menuitem "详细资料(&D)", IDM_DETAIL
menuitem separator
popup "工具栏(&T)"
BEGIN
menuitem "标准按钮(&S)", IDM_TOOLBAR
menuitem "文字标签(&C)", IDM_TOOLBARTEXT
menuitem "命令栏(&T)", IDM_INPUTBAR
menuitem "状态栏(&U)", IDM_STATUSBAR
END
END
popup "帮助(&H)" //popup ”” [,GRAYED][,INACTIVE][,HELP(右对齐)]
BEGIN
menuitem "帮助主题(&H)", IDM_HELP
menuitem separator
menuitem "关于本程序(&A)", IDM_ABOUT
END
END
IDA_MAIN accelerators
BEGIN
VK_F1, IDM_HELP, VIRTKEY //"^X" = ctrl + X
"B", IDM_SETCOLOR, VIRTKEY, CONTROL, ALT //"X" = X, VIRTKEY
"F", IDM_SETFONT, VIRTKEY, ALT //数值 表示Ascii为该数值的字母,ASCII
//[,CONTROL][,ALT][,SHIFT]
//VK_F1 = F1
//VK_BACK
//VK_ESCAPE
//VK_DELETE
//VK_RETURN
END
主程序文件
.386
.model flat, stdcall
option casemap: none
;-----------------------------------------------------------------------
include windows.inc
include gdi32.inc
includelib gdi32.lib
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
;-----------------------------------------------------------------------
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_SAMLL 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 'MyClass', 0
szCaptionMain db 'My first window', 0
szText db 'Win32 Assemply, Simple and powerful!', 0
szMenuHelp db '帮助主题(&H)', 0
szMenuAbout db '关于本程序(&A)', 0
szCaption db 'MenuDisply', 0
szFormat db 'what you choose is:%08x', 0 ;@08x最少8位的16进制
;-----------------------------------------------------------------------
.code
;-----------------------------------------------------------------------
;_DisplayMenuItem实现弹出一个指定格式内容的窗口
;-----------------------------------------------------------------------
_DisplayMenuItem proc _dwCommandID ;_dwCommandID是形式参数,此处未指明类型
local @szBuffer[256]: byte
pushad ;保护现场
invoke wsprintf, addr @szBuffer, addr szFormat,\ ;wsprintf(szBuffer, szFormat, _dwCommandID);
_dwCommandID ;wParam有32位,低16位是命令id(资源ID),高16位是通知码,全0为菜单消息,全1为快捷键消息
invoke MessageBox, hWinMain, addr @szBuffer, \ ;MessageBox(hWinMain, szBuffer, szCaption, MB_OK);
offset szCaption, MB_OK ; 模块句柄,显示内容,窗口标题,窗口模式
popad ;保护现场
ret ;相当于return,自动实现堆栈平衡
_DisplayMenuItem endp
;-----------------------------------------------------------------------
;_Quit单独实现了退出功能,可以再加上一些判断。利用call调用即可
;-----------------------------------------------------------------------
_Quit proc
invoke DestroyWindow, hWinMain ;DestroyWindow(hWndMain);销毁窗口
invoke PostQuitMessage, 0 ;PostQuitMessage(0); 终止进程
ret
_Quit endp
;-----------------------------------------------------------------------
_ProcWinMain proc uses ebx edi esi, hWnd, uMsg, wParam, lParam
local @stPs: PAINTSTRUCT
local @stRect: RECT
local @hDc
local @stPos: POINT
local @hSysMenu
mov eax, uMsg ;载入消息
;-----------------------------------------------------------
.if eax == WM_PAINT ;感兴趣的自己处理
invoke BeginPaint, hWnd, addr @stPs
mov @hDc, eax
invoke GetClientRect, hWnd, addr @stRect
invoke DrawText, @hDc, addr szText, -1,\
addr @stRect,\
DT_SINGLELINE or DT_CENTER or DT_VCENTER
invoke EndPaint, hWnd, addr @stPs
;-----------------------------------------------------------
.elseif eax == WM_CREATE
;为了右键菜单使用,实际上应该自己定义一个
invoke GetSubMenu, hMenu, 1
mov hSubMenu, eax
;在系统菜单中添加自己的菜单(右键标题栏)
;此菜单发送WM_SYSCOMMAND
;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 ;用户选择一个菜单项(非系统菜单),用户按下一个快捷键(非系统键),都处理成返回到主窗口处理
;通知用户按下菜单的ID----------------------------
invoke _DisplayMenuItem, wParam ;wParam里保存着通知码和ID值(菜单项和对应的快捷键返回同一个wParam)
;WM_COMMAND就是这样定义的
;取出ID,进行判断----------------------------------
mov eax, wParam
movzx eax, ax
.if eax == IDM_EXIT
call _Quit
.endif
;-----------------------------------------------------------
.elseif eax == WM_SYSCOMMAND ;用户选择一个系统菜单,用户按下一个系统快捷键,都处理成返回到主窗口处理
;取出ID,进行判断----------------------------------
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
;-----------------------------------------------------------
.elseif eax == WM_RBUTTONDOWN
;BOOL GetCursorPos(LPPOINT lpPoint);
;把光标所在坐标存入POINT中
invoke GetCursorPos, addr @stPos
;BOOL TrackPopupMenu(HMENU hMenu, UINT uFlags, int x, int y, int nReserved, HWND hWnd, CONST RECT* prcRect);
;hMenu:此句柄可为调用CreatePopupMenu创建的新快捷菜单的句柄,也可以为调用GetSubMenu取得的与一个已存在菜单项相联系的子菜单的句柄。
;uFlags:TPM_CENTERALIGN:x居中放置,TPM_LEFTALIGN:左边界与X对齐,TPM_RIGHTALIGN:右边界与X对齐
;NReserved:保留值,必须为零
;HWnd:拥有快捷菜单的窗口的句柄,hInstance,在_ProcWinMain中是hWnd
;prcRect:NULL,在菜单外单击菜单消失
invoke TrackPopupMenu, hSubMenu, TPM_LEFTALIGN, @stPos.x, @stPos.y, 0, hWnd, NULL
;-----------------------------------------------------------
.elseif eax == WM_CLOSE ;套路
;invoke DestroyWindow, hWinMain
;invoke PostQuitMessage, NULL
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 ;获取本模块句柄存入eax中
mov hInstance, eax ;存入全局变量hInstance中
;获取菜单句柄---------------------------------------------
;HMENU LoadMenu(HINSTANCE hlnstance,LPCTSTR lpMenuName);
;若函数调用成功,则返回所加载的菜单句柄,若函数调用失败,则返回值为NULL
;hlnstance:含有被加载菜单资源的实例模块的句柄
;LpMenuName:低位字16bit资源标识符,高位字16bit全零
;-----------------------------------------------------------
invoke LoadMenu, hInstance, IDM_MAIN ;必须获取菜单句柄
mov hMenu, eax
;获取快捷键句柄-------------------------------------------
;HACCEL LoadAccelerators(HINSTANCE hlnstance,LPCTSTR lpTableName);
;lpTableName:低位字16bit资源标识符,高位字16bit全零
;-----------------------------------------------------------
invoke LoadAccelerators, hInstance, IDA_MAIN ;必须获取快捷键句柄
mov @hAccelerator, eax ;必须改写消息循环
;-----------------------------------------------------------
invoke RtlZeroMemory, addr @stWndClass, sizeof @stWndClass ;必须初始化局部变量
; ;hIcon!!!
; ;hCursor!!!
; ;lpszMenuName!!!
push hInstance ;hInstance
pop @stWndClass.hInstance
mov @stWndClass.cbSize, sizeof WNDCLASSEX ;cbsize
mov @stWndClass.style, CS_HREDRAW or CS_VREDRAW ;style!!!
mov @stWndClass.lpfnWndProc, offset _ProcWinMain ;lpfnWndProc
mov @stWndClass.hbrBackground, COLOR_WINDOW + 1 ;hbrBackground!!!
mov @stWndClass.lpszClassName, offset szClassName ;lpszClassName
; ;cbWndExtra
; ;cbClsExtra
invoke RegisterClassEx, addr @stWndClass ;stWndClass是一个结构体
;-----------------------------------------------------------
;创建窗口--------------------------------------------------
invoke CreateWindowEx, WS_EX_CLIENTEDGE,\ ;dwExStyle!!!
offset szClassName, offset szCaptionMain,\ ;lpClassName, lpWindowMain
WS_OVERLAPPEDWINDOW,\ ;dwStyle!!!
100, 100, 600, 400,\ ;x, y, nWight, nHeight
NULL, hMenu, hInstance, NULL ;hWndParent!!!, hMenu!!!, hInstance, lpParam!!!
mov hWinMain, eax
;显示窗口--------------------------------------------------
invoke ShowWindow, hWinMain, SW_SHOWNORMAL ;SW!!!
;更新窗口--------------------------------------------------
invoke UpdateWindow, hWinMain
;-----------------------------------------------------------
;消息循环--------------------------------------------------
;|--------------------------------------------------------------------------------------------------------------|
;|.while TRUE |
;| invoke GetMessage, addr @stMsg, NULL, 0, 0 ;lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax |
;| ;addr @stMsg |
;| ;hWnd NULL 本程序所属窗口 |
;| ;wMsgFilterMax = wMsgFilterMin = 0 获取所有消息 |
;| .break .if eax == 0 ;WM_QUIT eax = 0, 退出消息循环 |
;| invoke TranslateMessage, addr @stMsg ;WM_CHAR, WM_SYSCHAR, 键盘消息转换 |
;| invoke DispatchMessage, addr @stMsg ;发送到窗口过程函数 |
;|.endw |
;|--------------------------------------------------------------------------------------------------------------|
.while TRUE
invoke GetMessage, addr @stMsg, NULL, 0, 0
.break .if eax == 0
;系统自动完成快捷键检测功能----------------------
;int TranslateAccelerator(HWND hWnd,HACCEL hAccTable,LPMSG IpMsg);
;若函数调用成功,则返回非零值;若函数调用失败,则返回值为零(没找到快捷键的消息)
;hWnd:消息被发送到这个窗口处理
;hAccTable:快捷键表句柄
;lpMsg:从GetMessage或PeekMessage从消息队列获取的消息
;---------------------------------------------------
invoke TranslateAccelerator, hWinMain, @hAccelerator, addr @stMsg
.if eax == 0
invoke TranslateMessage, addr @stMsg
invoke DispatchMessage, addr @stMsg
.endif
.endw
ret
_WinMain endp
;-----------------------------------------------------------------------
start:
call _WinMain
invoke ExitProcess, NULL
end start
;-----------------------------------------------------------------------