;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;该部分指出了该汇编程序所用的指令集为386,类似的还有486,586等
;内存模式为平坦型,也就是内存范围为4GB空间,不会担心在使用内存时有任何限制,同时指出了
;函数调用的约定stdcall表示函数参数从右向左压入堆栈
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.386
.model flat, stdcall
.option casemap:none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;include 文件定义,表示该程序运行时包含的头文件
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include windows.inc
include user32.inc
include lib 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 ? ;定义32位(4字节)实例化句柄,一般数据对象
hWinMain dd ? ;定义32位(4字节)主窗口句柄,主对象
hMenu dd ? ;定义32位(4字节)菜单句柄,菜单对象
hSubMenu dd ? ;定义32位(4字节)子菜单句柄,子菜单对象
;所谓句柄就是指向指针的指针,指针指向内存单元的地址,而指针的指针指的是指向地址的地址,
;这个类似于目录章节编号和与此对应的页码编号一样,在windows系统中专门在内存区域中
;开辟了一段区域用于储存"章节编号"的地址.句柄的设计是windows系统内存管理的结果,句柄和
;相应数据对象一一对应。
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.const ;定义常量
szClassName db 'Menu Example',0 ;定义以0结尾的字符串
szCaptionMain db 'Menu',0
szMenuHelp db '帮助主题(&H)',0
szMenuAbout db '关于本程序(&A)...',0
szCaption db '菜单选择',0
szFormat db '您选择了菜单命令:%08x',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;定义子程序(函数)以下划线开始,伪指令proc代表对该程序(函数)的声明,
;之后参数为该函数所需的参数,类似于C语言中的add(int x,int y)
;addr可以处理局部变量而 offset 则不能。局部变量只是在运行时在堆栈中分配内存空间。而 offset 则是在编译时由编译器解释,这显然不能用offset 在运行时来分配内存空间。编译器对 addr 的处理是先检查处理的是全局还是局部变量,若是全局变量则把其地址放到目标文件中,这一点和 offset 相同,若是局部变量,就在执行 invoke 语句前产生如下指令序列:
lea eax, LocalVar
push eax
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_DisplayMenuItem proc _dwCommandID //显示菜单项目的函数
local @szBuffer[256]:byte ;定义常量,以@开头,定义256字节缓冲区
pushad ;pushad 按照EDI,ESI,EBP,ESP,EBX,EDX,ECX,EAX的顺序将寄存器压入堆栈
用于临时保存寄存器中的值,保护现场
invoke wsprintf,addr @szBuffer,addr szFormat,_dwCommandID ;函数作用:
函数wsprintf()将一系列的字符和数值输入到缓冲区。
输出缓冲区里的的值取决于格式说明符(即"%")。
如果写入的是文字,此函数给写入的文字的末尾追加一个'\0'。
函数的返回值是写入的长度,但不包括最后的'\0'
invoke MessageBox,hWinMain,addr @szBuffer,offset szCaption,MB_OK ;
调用子窗口消息函数,建立窗口,hWinMain(父类句柄,主窗口句 柄),
该参数表明该窗口消息实现的窗口所从属的父类对象
popad ;与popad对应,主要用于恢复现场
ret ;返回子程序
_DisplayMenuItem endp //子程序结束
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;退出窗口函数,
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_Quit proc
invoke DestroyWindow,hWinMain //销毁窗口函数,参数hWinMain指代该函数对象(主窗口句柄)
invoke PostQuitMessage,NULL //函数功能:该函数向系统表明有个线程有终止请求。通常用来响应WM_DESTROY消息
ret
_Quit endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;定义子程序,uses的使用相当于在该程序的开始和结尾处自动加上pushad和popad
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_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 //movzx主要用于实现16位向32位数据的转换
.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 //hInstance通用句柄,主要作为存放一般数据对象
invoke LoadMenu,hInstance,IDM_MAIN //loadmenu
mov hMenu,eax
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
.if eax == 0
invoke TranslateMessage,addr @stMsg
invoke DispatchMessage,addr @stMsg
.endif
.endw
ret
_WinMain endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
call _WinMain //调用主函数
invoke ExitProcess,NULL //调用退出程序函数ExitProcess,NULL参数默认指退出的为本窗口
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
end start