我学Win32汇编―创建简单的窗口的一点心得,大侠们就不用看了…..
--------------大菜鸟YongPeng
.386 ;386指令集(RING3层)3
.MODEL Flat,stdcall ;内存寻址模式,参数传递约定(从右向左)
option casemap:none ;区分标号的大小写
include \masm32\include\windows.inc ;引入头文件
include \masm32\include\user32.inc ;引入头文件
include \masm32\include\kernel32.inc ;引入头文件
includelib \masm32\lib\user32.lib ;引入库
includelib \masm32\lib\kernel32.lib ;引入库
winmain proto:DWORD,:DWORD,:DWORD,:DWORD ;WINODWS应用程序的入口点
.DATA ;已初始化的变量(数据段)
ClassName db "我的第一个汇编小程序",0 ;WINDOWS类名
AppName db "汇编第一课",0 ;窗口的名字
.DATA? ;未初始化的变量
hInstance HINSTANCE ? ;代表应用程序的句柄
CommandLine LPSTR ? ;保存存从命令行传入的参数
.CODE ;代码段
start: ;程序代码的开始处
invoke GetModuleHandle,NULL ;获取应用程序句柄,eax保存应用程序句柄 (eax保存返回值)
mov hInstance,eax ;将应用程序的名柄eax写入变量hinstance中
invoke GetCommandLine ;调用API获取命令行参数
mov CommandLine,eax ;将命令行参入变量CommandLine
invoke WinMain,hInstance,NULL,CommandLine,SW_SHOWDEFAULT;调用程序入口函数,返回参数入eax
invoke ExitProcess,eax ;程序结束时,把返回码传给windows
WinMain proc hInst:HINSTANCE,hprevInst:HINSTANCE,Cmdline:LPSTR,CmdShow:DWORD ;WINDAIN定义
LOCAL wc:WNDCLASSEX ;为局部变量在堆栈中申请内存空间
LOCAL msg:MSG ;为局部变量在堆栈中申请内存空间
LOCAL hwnd:HWND ;为局部变量在堆栈中申请内存空间
mov wc.cbsize,SIZEOF WNDCLASSEX ;WNDCLASSEX的大小
mov wc.style,CS_HREDRAW or CS_VREDRAW ;派生窗口具有的风格
mov wc.lpfnWndProc,OFFSET Wndproc ;窗口处理函数的指针
mov wc.cbClsExtra,NULL ;指定紧跟在窗口类结构后的附加字节数
mov wc.cbWndExtra,NULL ;指定紧跟在窗口事例后的附加字节数
push hInstance ;本模块的事例名柄
pop wc.hInstance ;???
mov wc.hbrBackground,COLOR_WINDOW+1 ;背景画刷的句柄
mov wc.lpszMenuName,NULL ;指向菜单的指针
mov wc.LPSZclassName,OFFSET ClassName ;指向类名字的指针
invoke Loadicon,NULL,IDI_APPLICATION ;装载程序图标
mov wc.hIcon,eax ;指向返回图标的句柄
mov wc.hIconsm,eax ;指向和窗口类关联的小图标
invoke LoadCursor,NULL,IDC_ARROW ;载入指定的光标资源
mov wc.hCurcor,eax ;指向返回光标的名柄
invoke RegisterClassEx,addr wc ;注册窗口类,(addr操作符用来把标号的变量传递给函数)
invoke CreateWindowEx,NULL,\ ;产生实际的窗口|(NULL)为没有附加窗口风格
ADDR ClassName,\ ;ASCIIZ形式的窗口类名称的地址
ADDR AppName,\ ;ASCIIZ开式的窗口名称的地址
WS_OVERLAPPEDWINDOW,\ ;窗口的风格(这里是最为普遍的风格)
CW_USEDEFAULT,\ ;指定窗口左上角以像素为单位的屏幕坐标位置(X)
CW_USEDEFAULT,\ ;指定窗口左上角以像素为单位的屏幕坐标位置(Y)
CW_USEDEFAULT,\ ;以像素为单位的窗口大小(宽)
CW_USEDEFAULT,\ ;以像素为单位的窗口大小(高)
NULL,\ ;父窗口的句柄(NULL代表只有一个窗口)
NULL,\ ;WINDOWS菜单的名柄
hInst,\ ;产生该窗口的应用程序的实例名柄
NULL ;指向欲传给窗口的结构体数据类型参数的指针
mov hwnd,eax ;调用成功后,eax为返回的窗口名柄,存入变量以备后用
invoke ShowWindow,hwnd,CmdShow ;调用ShowWindow来按照我们希望的方式来显示窗口
invoke UpdateWindow,hwnd ;调用UpdateWindow来更新客户区
-------------------------这时候窗口已显示在屏幕上了--------------------------------------------
WHILE TRUE ;
Invoke GetMessage,ADDR msg,NULL,0,0 ;从调用线程的消息队列里取得一个消息并将其放于指定的结构(msg)
.BREAK .IF(!eax) ;返回值如果不为0,程序继续顺序向下执行
invoke TranslateMessage,ADDR msg ;从键盘接受原始按键消息,后解释成WM_CHAR(含有按键的ASCII码)
invoke DispatchMessage,ADDR msg ;调度一个消息给负责该窗口过程的函数
.ENDW ;如果消息循环结束,退出码存放在MSG中的wParam中
mov eax,msg.wParam ;把退出码写入eax
ret ;返回
WinMain endp ;函数定义结束
WndProc proc hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM ;窗口处理函数定义
.IF uMsg==WM_DESTROY ;如果WINDOWS传递过来的消息为WM_DESTROY=$0002(窗口销毁)
Invoke PostQuitMessage,NULL ;调用函数中止线程
.ELSE ;否则向下执行
invoke DefWindowProc,hWnd,Umsg,wParam,lParam ;调用函数把收到的参数传给缺省的窗口处理函数
ret ;结束消息循环返回
.ENDIF ;结束循环
xor eax,eax ;调用函数中止线程后,在EAX中传递0
ret ;结束消息循环返回传EAX=0到invoke ExitProcess,eax
WndProc endp ;函数定义结束
End start ;程序代码结束
其实反汇编后大体的思路是一样的,就是伪指令invoke 变成了CALL,而且CALL函数之前需要将参数由右向左入堆栈,反汇编后不再是参数定义,而是具体是地址或数值,如果有什么不对的地方,请大家提出来,共同进步!
这儿我没有贴出反汇编后的代码,大家可以自己去反汇编看看,会有意想不到的效果!哈哈,让大家见笑了,我顺便将创建的EXE文件放上来了,大家可以下载回去试试
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!