最初のウィンドウで、第IV章アセンブラ言語学習プログラムは、Win32ビット

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 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
公開された19元の記事 ウォン称賛7 ビュー3083

おすすめ

転載: blog.csdn.net/znevegiveup1/article/details/104078056