您的位置:首页 > 其它

使用MASM05 - Win32汇编语言013

2011-09-23 18:43 351 查看

使用MASM05

让编程改变世界

Change the world by program

函数的声明

在调用API函数的时候,函数原型也必须预先声明,否则,编译器会不认这个函数。invoke伪指令也无法检查参数个数。声明函数的格式是:
函数名 proto [距离] [语言] [参数1]:数据类型, [参数2]:数据类型

句中的proto是函数声明的伪指令,距离可以是NEAR,FAR,NEAR16,NEAR32,FAR16或FAR32。

Win32中只有一个平坦的段,无所谓距离,所以在定义时是忽略的;语言类型就是.model那些类型,如果忽略,则使用.model定义的默认值。

对Win32汇编来说只存在dword类型的参数,所以所有参数的数据类型永远是dword。

另外对于编译器来说,它只关心参数的数量,参数的名称在这里是无用的,仅是为了可读性而设置的,可以省略掉。

所以下面两句消息框函数的定义实际上是一样的:
MessageBox Proto hWnd:dword, lpText:dword, lpCaption:dword, uType:dword

MessageBox Proto :dword, :dword, :dword, :dword

在Win32环境中,和字符串相关的API共有两类,分别对应两个字符集:一类是处理ANSI字符集(1B)的,另一类是处理Unicode字符集(2B)的。

前一类函数名字的尾部带一个A字符,处理Unicode的则带一个W字符。

我们比较熟悉的ANSI字符串是以NULL结尾的一串字符数组,每一个ANSI字符占一个字节宽。

对于欧洲语言体系,ANSI字符集已足够了,但对于有成千上万个不同字符的几种东方语言体系来说,Unicode字符集更有用。

MessageBox和显示字符串有关,同样它有两个版本,严格地说,系统中有两个定义:

MessageBoxA Proto hWnd:dword, lpText:dword, lpCaption:dword, uType:dword

MessageBoxB Proto hWnd:dword, lpText:dword, lpCaption:dword, uType:dword

虽然《Microsoft Win32 Programmer’s Reference》中只有一个MessageBox定义,但User32.dll中确确实实没有MessageBox,而只有MessageBoxA和MessageBoxW,那么为什么还是可以使用MessageBox呢?Follow

由于并不是每个Win32系统都支持W系统的API,例如在Windows 9x系列中,对Unicode是不支持的,很多的API只有ANSI版本,只有Windows NT系列才对Unicode完全支持。

为了编写在几个平台中通用的程序,一般应用程序都使用ANSI版本的API函数集。

这样的话,为了使程序更有移植性,在源程序中一般不直接指明使用Unicode还是ANSI版本,而是使用宏汇编中的条件汇编功能来统一替换。

如在源程序中使用MessageBox,但在头文件中定义:

[codesyntax lang="c"]
if UNICODE
MessageBox    equ   <MessageBoxW>
else
MessageBox    equ   <MessageBoxA>
endif

[/codesyntax]

所有涉及版本问题的API都可以按此方法定义,然后在源程序的头指定UNICODE=1或UNICODE=0,重新编译后就能产生不同的版本。

include语句

对于所有要用到的API函数,在程序的开始部分都必须预先声明,但这一个步骤显然是比较麻烦的,为了简化操作,可以采用各种语言通用的解决办法,就是把所有的声明预先放在一个文件中,在用到的时候再用include语句包含进来。

现在回到Win32 Hello World程序,这个程序用到了两个API函数:MessageBox和ExitProcess,它们分别在User32.dll和Kernel32.dll中。

在MASM32工具包中已经包括了所有DLL的API函数声明列表,每个DLL对应<DLL名.inc>文件(这些文件就是存放对应的函数声明),在源程序中只要使用include语句包含进来就可以了:
include user32.inc

include kernel32.inc

当用到其他的API函数时,只需相应增加对应的include语句。

编译器对include语句的处理仅是简单地把这一行用指定的文件内容替换掉而而已。

include语句的语法是:
include 文件名


include <文件名>

当遇到要包括的文件名和MASM的关键字同名等可能会引起编译器混淆的情况时,可以用<>将文件名括起来。

includelib语句

在DOS汇编中,使用中断调用系统功能是不必声明的,处理器自己知道到中断向量表中去取中断地址。

在Win32汇编中使用API函数,程序必须知道调用的API函数存在于哪个DLL中。

否则,操作系统必须搜索系统中存在的所有DLL,并且无法处理不同DLL中的同名函数,这显然是不现实的。

所以,必须有个文件包括DLL库正确的定位信息,这个任务是由导入库来实现的。

在使用外部函数的时候,DOS下有函数库的概念,那时的函数库实际上是静态库,静态库是一组已经编写好的代码模块,在程序中可以自由引用。

在源程序编译成目标文件,最后要链接可执行文件的时候,由link程序从库中找出相应的函数代码,一起链接到最后的可执行文件中。

DOS下C语言的函数库就是典型的静态库。

库的出现为程序员节省了大量的开发时间,缺点就是每个可执行文件中都包括了要用到的相同函数的代码,占用了大量的磁盘空间,在执行的时候,这些代码同样重复占用了宝贵的内存。

Win32环境中,程序链接的时候仍然要使用函数库来定位函数信息,只不过由于函数代码放在DLL文件中。

库文件中只留有函数的定位信息和参数数目等简单信息,这种库文件叫做导入库。

一个DLL文件对应一个导入库,如User32.dll文件用于编程的导入库是User32.lib,MASM32工具包中包含了所有DLL的导入库。

为了告诉链接程序使用哪个导入库,使用的语句是:
includelib 库文件名


includelib <库文件名>

和include的用法一样,在要包括让编译器混淆的文件名时加括号。

Win32 Hello World程序用到的两个API函数MessageBox和ExitProcess分别在User32.dll和Kernel32.dll中,那么在源程序使用的相应语句为:
includelib user32.lib

includelib kernel32.lib

和include语句的处理不同,includelib不会把.lib文件插入到源程序中,它只是告诉链接器在链接的时候到指定的库文件中去找而已。

Dll文件中的函数没有包括声明,所以才需要将.inc文件插进去!

[buy] 获得所有教学视频、课件、源代码等资源打包 [/buy]
[Downlink href='http://urlxf.qq.com/?Y3eqqeU']视频下载[/Downlink]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: