;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; FirstWindow.asm
; 窗口程序的模板代码
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 使用 nmake 或下列命令进行编译和链接:
; ml /c /coff FirstWindow.asm
; Link /subsystem:windows FirstWindow.obj
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.386
.model flat,stdcall
option casemap:none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include windows.inc
include gdi32.inc
includelib gdi32.lib
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data?
hInstance dd ?
hWinMain dd ?
.const
szClassName db 'MyClass',0
szCaptionMain db 'My first Window !',0
szText db 'Win32 Assembly, Simple and powerful !',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 窗口过程
;>>>>>>>>>>>>>>>>>>>>>>>>>>>子程序ProcWinMain>>>>>>>>>>>>>>>>>>>>>>>>
;子程序_ProcWinMain子程序用来处理消息
;
_ProcWinMain proc uses ebx edi esi hWnd,uMsg,wParam,lParam
;uses后面用来保存ebx,edi,esi和ebp寄存器的值,在子程序进入和退出
;调用API后,ebx,edi,esi和ebp寄存器的值总是不会被改变,
;但ecx和edx的值就不一定
;wParam和lParam参数是消息所附带的参数,它随消息的不同而不同
;时自动安插上push和pop寄存器指令
;第一个参数是窗口句柄,第二个参数是消息标识,后面两个参数是消息的
;两个参数,这4个参数和消息循环中的MSG结构中的前四个字段是一样的
local @stPs:PAINTSTRUCT
local @stRect:RECT
local @hDc
mov eax,uMsg
;********************************************************************
.if eax == WM_PAINT
;如果需要自己绘制客户区,在这里安排代码
invoke BeginPaint,hWnd,addr @stPs
;通过BeginPaine获取窗口客户区的"设置环境"
;句柄
mov @hDc,eax
invoke GetClientRect,hWnd,addr @stRect
;然后通过GetClientRect获取客户区的大小
invoke DrawText,@hDc,addr szText,-1,\
addr @stRect,\
DT_SINGLELINE or DT_CENTER or DT_VCENTER
;通过DrawText函数按照取得的屏幕大小居中写到
;设备环境中,也就是窗口上
invoke EndPaint,hWnd,addr @stPs
;********************************************************************
.elseif eax == WM_CLOSE
;按下了窗口右上角的关闭按钮后收到的
;程序可以在这里处理和关闭窗口相关的事情
;一般是相关资源的释放工作,如释放内存、
;保存工作和提示用户是否保存工作等
invoke DestroyWindow,hWinMain
;程序自己调用DestroyWindow来摧毁窗口
;并用PostQuitMessage向消息循环发送
;WM_QUIT消息来退出消息循环
invoke PostQuitMessage,NULL
;调用PostQuitMessage时的参数是退出码
;就是GetMessage收到WM_QUIT后MSG结构wParam字段
;中的内容,在这里使用NULL
;********************************************************************
.else
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
;不感兴趣的消息交给DefWindowProc来处理
;对于DefWindowProc不进行干涉,直接用ret指令返回
ret
.endif
;********************************************************************
xor eax,eax
ret
_ProcWinMain endp
;>>>>>>>>>>>>>>>>>>>>>>这个位置是程序的入口处>>>>>>>>>>>>>>>>>>>>>>>>
_WinMain proc
local @stWndClass:WNDCLASSEX
;定义一个WNDCLASSEX结构
local @stMsg:MSG
invoke GetModuleHandle,NULL
;(1)得到应用程序的句柄
mov hInstance,eax
;使用参数NULL调用GetModuleHandle,那么得到的是调用者本模块的句柄
;为了区分多次加载的"拷贝",就把每个"拷贝"叫做实例,
;每个实例均用不同的"实例句柄"值来标识它们
;这里的hInstance是一个寄存器,而不是WNDCLASSEX中的参数
invoke RtlZeroMemory,addr @stWndClass,sizeof @stWndClass
;用RtlZeroMemory将它填为全零,再填写结构的各个字段
;这样没有赋值的部分就保持为零
;RtlZeroMemory API
;********************************************************************
; 注册窗口类
;********************************************************************
invoke LoadCursor,0,IDC_ARROW
;LoadCursor API
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
;(2)注册窗口类,在注册之前,要先填写
;RegisterClassEx的参数WNDCLASSEX结构
;********************************************************************
; 建立并显示窗口
;********************************************************************
invoke CreateWindowEx,WS_EX_CLIENTEDGE,offset szClassName,offset szCaptionMain,\
WS_OVERLAPPEDWINDOW,\
100,100,600,400,\
NULL,NULL,hInstance,NULL
;收到第一条消息并不是从消息循环开始以后,二十在CreateWindowEx中就
;开始了,显示和刷新窗口的函数ShowWindow和UpdateWindow也向窗口
;发送消息
;(3)建立窗口类
mov hWinMain,eax
;建立窗口后,eax中传回来的是窗口句柄,要把它保存起来以备后用
invoke ShowWindow,hWinMain,SW_SHOWNORMAL
;(4)显示窗口类,将窗口显示出来,hWinMain为参数,SW_SHOWNORMAL
;为显示的方式
invoke UpdateWindow,hWinMain
;(5)刷新窗口客户端,用UpdateWindow绘制客户区,它实际上
;就是向窗口发送了一条WM_PAINT消息,一个顶层窗口就正常建立
;并显示了
;********************************************************************
; 消息循环
;********************************************************************
;(6)进入无限的消息获取和处理的循环,首先获取消息(GetMessage)
;如果由消息到达,则将消息分派到回调函数处理(DispatchMessage)
;如果消息是WM_QUIT,则退出循环
.while TRUE
invoke GetMessage,addr @stMsg,NULL,0,0
;消息循环中的几个函数要用到一个MSG结构,用来做消息传递
;invoke GetMessage,lpMsg,hWnd,wMsgFilterMin,wMsgFilterMax
;lpMsg指向一个MSG结构,函数会在这里返回渠道的消息
;hWnd参数指定要获取哪个窗口的参数,例子中指定的是NULL,表示
;获取的是所有本程序所属窗口的消息
;wMsgFilterMin和wMsgFilterMax为0表示获取所有编号的消息
.break .if eax == 0
invoke TranslateMessage,addr @stMsg
;TranslateMessage将MSG结构传给Windows进行一些键盘消息的转换
;当有键盘按下和放开时,Windows产生WM_KEYDOWN和WM_KEYUP或
;WM_SYSKEYDOWN和WM_SYSKEYUP消息,但这些消息的参数中
;包含的是按键的扫描码,转换成常用的ascii码要进行查表
;很不方便,TranslateMessage遇到键盘消息则将扫描码
;转换成ascii码并在消息队列中插入WM_CHAR或WM_SYSCHAR消息
;参数就是转换好的ascii码了。遇到非键盘消息则TranslateMessage
;不做处理
invoke DispatchMessage,addr @stMsg
;DispatchMessage API
.endw
ret
_WinMain endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
call _WinMain
;入口是start,然后执行力一个_WinMain子程序
invoke ExitProcess,NULL
;完成后就是程序退出函数ExitProcessg
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
end start
win32位下汇编语言第四章第一个窗口程序学习
猜你喜欢
转载自blog.csdn.net/znevegiveup1/article/details/104078056
今日推荐
周排行