友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!阅读过程发现任何错误请告诉我们,谢谢!! 报告错误
荣耀电子书 返回本书目录 我的书架 我的书签 TXT全本下载 进入书吧 加入书签

windows环境下32位汇编语言程序设计-第章

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!




3。1。4  注释和换行

注释是源程序中不可忽略的一部分,汇编源程序的注释以分号(;)开始,注释既可以在一行的头部,也可以在一行的中间,一行中所有在分号之后的字符全部当做注释处理,但在字符串的定义中包含在引号内的分号不当做是注释的开始。

举例如下:

;这里是注释

call    _PrintChar      ;这里是注释

szChar  db 'Hello; world;';0dh;0ah   ;world后面的分号不是注释,后面的才是

当源程序的某一行过长,不利于阅读的时候,可以分行书写,分行的办法是在一行的最后用反斜杠()做换行符,如:

        invoke  MessageBox;NULL;offset szText;offset szCaption;MB_OK

可以写为:

    invoke  MessageBox;

        Null;              ;父窗口句柄

        offset szText;     ;消息框中的文字

        offset szCaption;  ;标题文字

        MB_OK

“一行的最后”指的是最后一个有用的字符,反斜杠后面多几个空格或加上注释并不影响换行符的使用,如上例所示,这一点和makefile文件中换行符的规定有所不同。



 
来源:电子工业出版社 作者:罗云彬 上一页         回书目         下一页          
上一页         回书目         下一页          
  


第3章 使用MASM


3。2 调用API(1)

    
3。2。1  API是什么

Win32程序是构筑在Win32 API基础上的。在Win32 API中,包括了大量的函数、结构和消息等,它不仅为应用程序所调用,也是Windows自身的一部分,Windows自身的运行也调用这些API函数。

在DOS下,操作系统的功能是通过各种软中断来实现的,如大家都知道int 21h是DOS中断,int 13h和int 10h是BIOS中的磁盘中断和视频中断。当应用程序要引用系统功能时,要把相应的参数放在各个寄存器中再调用相应的中断,程序控制权转到中断中去执行,完成以后会通过iret中断返回指令回到应用程序中。如DOS汇编下的Hello World程序中有下列语句:

    mov     ah;9

    mov     dx;offset szHello

    int     21h

这3条语句调用DOS系统模块中的屏幕显示功能,功能号放在ah中,9号功能表示屏幕显示,要输出到屏幕上的内容的地址放在dx中,然后去调用int 21h,字符串就会显示到屏幕上。

这个例子说明了应用程序调用系统功能的一般过程。首先,系统提供功能模块并约定参数的定义方法,同时约定调用的方式,应用程序按照这个约定来调用系统功能。在这里,ah中放功能号9,dx中放字符串地址就是约定的参数,int 21h是约定的调用方式。

下面来看看这种方法的不便之处。首先,所有的功能号定义是冷冰冰的数字,int 21h的说明文档是这样的:

Int 21 Functions:

 

00——Program termination

01——Keyboard input

02——Display output

03——AUX input

04——AUX output

05——Printer output

06——Direct console I/O

07——Direct STDIN input; no echo

08——Keyboard input; no echo

09——Print string

0A——Buffered keyboard input

0B——Check standard input status

再进入09号功能看使用方法:

Print string (Func 09)

    AH = 09h

    DS:DX …》 string terminated by 〃〃

这就是DOS时代汇编程序员都有一厚本《中断大全》的原因,因为所有的功能编号包括使用的参数定义仅从字面上看,是看不出一点头绪来的。

另外,80x86系列处理器能处理的中断最多只能有256个,不同的系统服务程序使用了不同的中断号,这少得可怜的中断数量就显得太少了,结果到最后是中断挂中断,大家抢来抢去的,把好好的一个系统搞得像接力赛跑一样。

对于这些弱点,程序员们都有个愿望:系统功能如果能以功能名称作为子程序名直接调用就好了,参数也最好定义的有意义一点,这样一来写程序就会方便得多,编系统扩展模块也就不必老是担心往哪个中断上面挂了,最好能把上面int 21h/ah=9的调用写成下面这副样子:

call    PrintString;addr szHello

终于,好消息出来了,Win32环境中的编程接口就是这个样子,这就是API,它实际上是以一种新的方法代替了DOS中用软中断的方式。和DOS的结构相比,Win32的系统功能模块放在Windows的动态链接库(DLL)中,DLL是一种Windows的可执行文件,采用的是和 。exe文件同样的PE格式,在PE格式文件头的导出表中,以字符串形式指出了这个DLL能提供的函数列表。应用程序使用字符串类型的函数名指定要调用的函数。

应用程序在使用的时候由Windows自动装入DLL程序并调用相应的函数。

实际上,Win32的基础就是由DLL组成的。Win32 API的核心由3个DLL提供,它们是:

●   KERNEL32。DLL——系统服务功能。包括内存管理、任务管理和动态链接等。

●   GDI32。DLL——图形设备接口。利用VGA与DRV之类的显示设备驱动程序完成显示文本和矩形等功能。

●   USER32。DLL——用户接口服务。建立窗口和传送消息等。

当然,Win32 API还包括其他很多函数,这些也是由DLL提供的,不同的DLL提供了不同的系统功能。如使用TCP/IP协议进行网络通信的DLL是Wsock32。dll,它所提供的API称为Socket API;专用于电话服务方面的API称为TAPI(Telephony API),包含在Tapi32。dll中。所有的这些DLL提供的函数组成了现在所用的Win32编程环境。

 

3。2。2  调用API

和在DOS中用中断方式调用系统功能一样,用API方式调用存放在DLL中的函数必须同样约定一个规范,用来定义函数的调用方法、参数的传递方法和参数的定义,洋洋洒洒几百MB的Windows系统比起才几百KB规模的DOS,其系统函数的规模和复杂程度都上了一个数量级,所以在使用一个API时,带的参数数量多达十几个是常有的事,在DOS下用寄存器来传递参数的方法显然已经不能胜任了。

Win32 API是用堆栈来传递参数的,调用者把参数一个个压入堆栈,DLL中的函数程序再从堆栈中取出参数处理,并在返回之前将堆栈中已经无用的参数丢弃。在Microsoft发布的《Microsoft Win32 Programmer's Reference》中定义了常用API的参数和函数声明,先来看消息框函数的声明:

int MessageBox(

    HWND hWnd;          // handle to owner window

    LPCTSTR lpText;     // text in message box

    LPCTSTR lpCaption;  // message box title

    UINT uType          // message box style

    );

最后还有一句说明:

Library: Use User32。lib。

上述函数声明说明了MessageBox有4个参数,它们分别是HWND类型的窗口句柄(hWnd),LPCTSTR类型的要显示的字符串地址(lpText)和标题字符串地址(lpCaption),还有UINT类型的消息框类型(uType)。这些数据类型看起来很复杂,但有一点是很重要的,对于汇编语言来说,Win32环境中的参数实际上只有一种类型,那就是一个32位的整数,所有这些HWND,LPCTSTR和UINT实际上就是汇编中的dword(double word),之所以定义为不同的模样,是用来说明用途。由于Windows是用C写成的,世界上的程序员好像也是用C语言的最多,所以Windows所有编程资料发布的格式也是C格式。

上面的声明用汇编的格式来表达就是:

MessageBox Proto hWnd:dword;lpText:dword;lpCaption:dword;uType:dword

上面最后一句Library: Use User32。lib则说明了这个函数包括在User32。dll中。

有了函数原型的定义以后,就是调用的问题了,Win32 API调用中要把参数放入堆栈,顺序是最后一个参数最先进栈,在汇编中调用MessageBox函数的方法是:

push    uType

push    lpCaption

push    lpText

push    hWnd

call    MessageBox

在源程序编译链接成可执行文件后,call MessageBox语句中的MessageBox会被换成一个地址,指向可执行文件中的导入表,导入表中指向MessageBox函数的实际地址会在程序装入内存的时候,根据User32。dll在内存中的位置由Windows系统动态填入。

1。 使用invoke语句

API是可以调用了,另一个烦人的问题又出现了,Win32的API动辄就是十几个参数,整个源程序一眼看上去基本上都是把参数压入堆栈的push指令,参数的个数和顺序很容易搞错,由此引起的莫名其妙的错误源源不断,源程序的可读性看上去也很差。如果写的时候少写了一句push指令,程序在编译和链接的时候都不会报错,但在执行的时候必定会崩溃,原因是堆栈对不齐了。

有没有解决的办法呢?最好是像C语言一样,能在同一句中打入所有的参数,并在参数使用错误的时候能够提示。

好消息又来了,Microsoft终于做了一件好事,在MASM中提供了一个伪指令实现了这个功能,那就是invoke伪指令,它的格式是:

    invoke  函数名',参数1'',参数2'……

对MessageBox的调用在MASM中可以写成:

invoke  MessageBox;NULL;offset szText;offset szCaption;MB_OK

注意,invoke并不是80386处理器的指令,而是一个MASM编译器的伪指令,在编译的时候它把上面的指令展开成我们需要的4个push指令和1个call指令,同时,进行参数数量的检查工作,如果带的参数数
返回目录 上一页 下一页 回到顶部 0 0
未阅读完?加入书签已便下次继续阅读!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!