首先我们看一个“复杂”的Win32汇编程序 程序用来显示一个消息框 -------------------------------------------------- 逆风者 ;文件名:3.asm
.386 .model flat ,stdcall
NULLequ 0 MB_OK equ 0
ExitProcess PROTO :DWORD MessageBoxA PROTO :DWORD,:DWORD,:DWORD,:DWORD
includelib kernel32.lib includelib user32.lib
.data szTextdb "Hello, world!",0 szCaption db "Win32Asm",0
.code start: push MB_OK lea eax,szCaption push eax lea eax,szText push eax push NULL call messageboxa xor eax,eax push eax call exitprocess end start -------------------------------------------------- 编译链接: 分下面两步进行: ml /c /coff 3.asm link /subsystem:windows /libpath:d:\masm7\lib 3.obj
第一步编译生成3.obj文件 /c 表示只编译,不链接 /coff 表示生成COFF格式的目标文件
第二步链接生成3.exe文件 /subsystem:windows 表示生成windows文件 /libpath:d:\masm7\lib 表示引入库的路径为:d:\masm7\lib。 在安装Masm32后,引入库位于Masm32\Lib目录下。
也可设置环境变量Lib的值:在dos提示符下键入Set Lib=d:\masm7\lib,这样“链接”就可简单写成: link /subsystem:windows 3.obj,试想一下,在程序调试过程中,修改源程序是常用的事啦,每次编译链接都要带/libpath:...那该有多烦人呢。当然,我们也可在源程序中直接给出引入库的位置,这样,链接时就方便啦,如下:
includelib d:\masm7\lib\kernel32.lib includelib d:\masm7\lib\user32.lib -------------------------------------------------- 执行:在dos提示符下键入3,回车,出现一个消息框,哈哈,真正的Win32程序!
-------------------------------------------------- 深入分析: 看一下源程序,有这么两行:call messageboxa\call exitprocess。大家一看都知道,这是子程序调用,但是我们并没写这样的子程序,事实上,这些是API函数。作为函数,我们在调用时可能需要传送给函数一些参数,程序怎么知道传送的参数有哪些,类型是什么呢?就是通过函数原型定义,如下所示: ExitProcess PROTO :DWORD MessageBoxA PROTO :DWORD,:DWORD,:DWORD,:DWORD 可以看出,ExitProcess有一个参数,MessageBoxA有四个参数,这些参数都是DWORD类型。
在Win32中,参数的传递都是通过堆栈来完成的。象MessageBoxA这个函数有四个参数,究竟是左边的先压入堆栈还是右边的先入栈呢?.model flat,stdcall给出了答案。stdcall 指定参数是从右到左压入堆栈的,且调整堆栈是在子程序返回时完成的。在源程序中不需要用“add sp,值”来保持堆栈平衡。对MessageBox,在API手册中是这样定义的: int MessageBox( HWND hWnd,// handle of owner window LPCTSTR lpText, // address of text in message box LPCTSTR lpCaption,// address of title of message box UINT uType// style of message box ) ;所以会有我们的程序段: push MB_OK lea eax,szCaption push eax lea eax,szText push eax push NULL call messageboxa
看看上面的程序,不难想到,假如在写程序时,少往堆栈里压入一个数据,那将是一个致命的错误。能不能将这种检查参数个数是否匹配的工作交给计算机来完成呢?这是可以的,INVOKE指令可以帮助我们完成这样的工作。假如你的参数个数不正确,连接器将给出错误提示。所以,极力建议你使用invoke代替call来调用子程序,当然,这不是绝对的。使用invoke上面的指令就可简写成下面的样子,看起来简炼多啦,查错也方便啦! invoke messageboxa, NULL,addr szText,addr szCaption,MB_OK
另外,像NULL,MB_OK都是一些常量,这样的常量有很多,还有很多的结构,如果在我们的程序中一开始都写这么多的东西,可能一下子就把你吓怕啦,也容易出错,更不便于看程序的主要部分。hutch整理的windows.inc包含了WIN32编程所需要的常量和结构体的定义,我们可简单的用一个include指令将这些常量和结构的定义插入到我们的文件中:
本文章更多内容:1 - 2 - 下一页>> |