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

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

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



ssagebox,但在头文件中定义:

if      UNICODE

        MessageBox      equ     

else

        MessageBox      equ     

endif

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

4.include语句

对于所有要用到的API函数,在程序的开始部分都必须预先声明,但这一个步骤显然是比较麻烦的,为了简化操作,可以采用各种语言通用的解决办法,就是把所有的声明预先放在一个文件中,在用到的时候再用include语句包含进来。现在回到Win32 Hello World程序,这个程序用到了两个API函数:MessageBox和ExitProcess,它们分别在User32。dll和Kernel32。dll中,在MASM32工具包中已经包括了所有DLL的API函数声明列表,每个DLL对应文件,在源程序中只要使用include语句包含进来就可以了:

include         user32。inc

include         kernel32。inc

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

include语句还用来在源程序中包含别的文件,当多个源程序用到相同的函数定义、常量定义,甚至源代码时,可以把相同的部分写成一个文件,然后在不同的源程序中用include语句包含进来。

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

include语句的语法是:

         include        文件名

或       include        

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

5。 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文件插入到源程序中,它只是告诉链接器在链接的时候到指定的库文件中去找而已。

3。2。3  API参数中的等值定义

再回过头来看显示消息框的语句:

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

在uType这个参数中使用了MB_OK,这个MB_OK是什么意思呢,先来看《Microsoft Win32 Programmer's Reference》中的说明:

uType —— 定义对话框的类型,这个参数可以是以下标志的合集:

要定义消息框上显示按钮,用下面的某一个标志:

MB_ABORTRETRYIGNORE —— 消息框有三个按钮:“终止”,“重试”和“忽略”

MB_HELP —— 消息框上显示一个“帮助”按钮,按下后发送WM_HELP消息

MB_OK —— 消息框上显示一个“确定”按钮,这是默认值

MB_OKCANCEL —— 消息框上显示两个按钮:“确定”和“取消”

MB_RETRYCANCEL —— 消息框上显示两个按钮:“重试”和“忽略”

MB_YESNO —— 消息框上显示两个按钮:“是”和“否”

MB_YESNOCANCEL —— 消息框上显示三个按钮:“是”、“否”和“取消”

 

要在消息框中显示图标,用下面的某一个标志:

MB_ICONWARNING —— 显示惊叹号图标

MB_ICONINFORMATION —— 显示消息图标

MB_ICONASTERISK —— 显示危险图标

MB_ICONQUESTION —— 显示问号图标

MB_ICONSTOP —— 显示停止图标

……



这些是uType参数说明中的一小半,可以看出,参数中可以用的值有很多种,让我们换一个值试试看,把语句改为:

invoke MessageBox;NULL;offset szText;offset szCaption; MB_ICONWARNING or MB_YESNO

再编译执行看,屏幕上出现了一个不一样的消息框,如图3。3所示。



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


第3章 使用MASM


3。2 调用API(3)

    
和参数说明中的一样!消息框中出现了一个惊叹号图标,按钮也变成了“是”和“否”两个按钮!MB_ICONWARNING和MB_YESNO等参数究竟是什么意思呢,MASM中显然没有这样的预定义,让我们先来找Visual C++的头文件,在WinUser。h中可以找到下面一段:

/*

 * MessageBox() Flags

 */

#define MB_OK                       Ox00000000L

#define MB_OKCANCEL                 Ox00000001L

#define MB_ABORTRETRYIGNORE         Ox00000002L

#define MB_YESNOCANCEL              Ox00000003L

#define MB_YESNO                    Ox00000004L

#define MB_RETRYCANCEL              Ox00000005L

 

#define MB_ICONHAND                 Ox00000010L

#define MB_ICONQUESTION             Ox00000020L

#define MB_ICONEXCLAMATION          Ox00000030L

#define MB_ICONASTERISK             Ox00000040L

 

#if(WINVER 》= Ox0400)

#define MB_USERICON                 Ox00000080L

#define MB_ICONWARNING              MB_ICONEXCLAMATION

#define MB_ICONERROR                    MB_ICONHAND

#endif /* WINVER 》= 0x0400 */

 

#define MB_ICONINFORMATION          MB_ICONASTERISK

#define MB_ICONSTOP                 MB_ICONHAND

……

显然,MB_YESNO就是4,MB_ICONWARNING就是30h,默认的MB_OK就是0,Win32 API的参数使用这样的定义方法显然是为了免除程序员死记数值定义的麻烦。在编写Win32汇编程序的时候,MASM32工具包中的Windows。inc也包括了所有这些参数的定义,只要在程序的开头包含这个定义文件:

include         windows。inc

就可以方便地完全按照API手册来使用Win32函数。

打开masm32include目录下的Windows。inc查看一下,可以发现整个文件总共有两万六千多行,包括了几乎所有的Win32 API参数中的常量和数据结构定义。正是有了这个文件中详尽的定义,Win32ASM才得以流行起来,试想一下,哪个程序员愿意每使用一个API语句,就到函数手册中去看参数,然后到Microsoft发布的Visual C++的头文件中去找对应的数值,再应用到汇编源程序中?这样会有80%以上的时间花在做无用功上(最后还是要骂Microsoft为什么不提供汇编格式的头文件,毕竟MASM32工具包不是Microsoft出的)。

有时候由于版本的原因,当使用最新的API手册时,会发现有些参数使用的常量在Windows。inc中并没有定义,这下惨了,谁都不知道类似于MB_XXXYYY的东西代表什么数值,Microsoft的《Microsoft Programmer's Reference》手册中从来就不会把参数对应的数值写进去。遇到这种情况,只有拿出最原始的办法了,就是到最新的Visual C++或SDK的include目录中去,在C语言格式的 。h头文件中把定义找出来,然后自行增补到Windows。inc中去。如果这样也找不到定义值的话,那只好放弃使用这个API了。



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


第3章 使用MASM


3。3 标号、变量和数据结构(1)

    
当程序中要跳转到另一位置时,需要有一个标识来指示新的位置,这就是标号,通过在目的地址的前面放上一个标号,可以在指令中使用标号来代替直接使用地址。

使用变量是任何编程语言都要遇到的工作,Win32汇编也不例外,在MASM中使用变量也有需要注意的几个问题,错误地使用变量定义或用错误的方法初始化变量会带来难以定位的错误。变量是计算机内存中已命名的存储位置,在C语言中有很多种类的变量,如整数型、浮点型和字符串等,不同的变量有不同的用途和尺寸,比如说虽然长整数和单精度浮点数都是32位长,但它们的用途不同。

顾名思义,变量的值在程序运行中是需要改变的,所以它必须定义在可写的段内,如 。data和 。data?,或者在堆栈内。按照定义的位置不同,MASM中的变量也分为全局变量和局部变量两种。

在MASM中标号和变量的命名规范是相同的,它们是:

1。 可以用字母、数字、下划线及符号@、和?。

2。 第一个符号不能是数字。

3。 长度不能超过240个字符。

4。 不能使用指令名等关键字。

5。 在作用域内必须是惟一的。

3。3。1  标号

1。 标号的定义

当在程序中使用一条跳转指令的时候,可以用标号来表示跳转的目的地,编译器在编译的时候会把它替换成地址,标号既可以定义在目的指令同一行的头部,也可以在目的指令前一行单独用一行定义,标号定义的格式是:

标号名:         目的指令

标号的作用域是当前的子程序,在单个子程序中的标号不能同名,否则编译器不知该用哪个地址,但在不同的子程序中可以有相同名称的标号,这意味着不能从一个子程序中用跳转指令跳到另一个子程序中。

在低版本的MASM中,标号在整个程序中是惟一的,子程序中的标号也可以从整个程序的任何地方转入。但Win32汇编使用的高版本MASM中不允许这样,这是为了提供对局部变量和参数的支持,由于在子程序入口处有对堆栈的初始化指令,所以一个子程序不允许有多个入口,其结果就是标号的作用域变成了单个子程序范围。

2。 MASM中的@@

在DOS时代,为标号起名是个麻烦的事情,因为汇编指令用到跳转指令特别多,任何比较和测试等都要涉及跳转,所以在程序中会有很多标号,在整个程序范围内起个不重名的标号要费一番功夫,结果常常用addr1和addr2之类的标号一直延续下去,如果后来要在中间插一个标号,那么就常常出现addr1_1和loop10_5之类奇怪的标号。

实际上,很多标号只会使用一到两次,而且不一定非要起个有意义的名称,如汇编程序中下列代码结构很多:

          mov   cx;1234h

          cmp   flag;1

          jz    loc1

          mov   cx;1000h

loc1:

          …

          loop  loc1

loc1在别的地方就再也用不到了,对于这种情况,高版本的MASM用@@标号去代替它:

       mov   cx;1234h

       cmp   flag;1

       jz    @F

       mov   cx;1000h

@@:

       …

       loop  @B

当用@@做标号时,可以用@F和@B来引用它,@F表示本条指令后的第一个@@标号,@B表示本条指令前的第一个@@标号,程序中可以有多个@@标号,@B和@F只寻找匹配最近的一个。

 不要在间隔太远的代码中使用@@标号,因为在以后的修改中@@和@B,@F中间可能会被无意中插入一个新的@@,这样一来,@B或@F就会引用到错误的地方去,源程序中@@标号和跳转指令之间的距离最好限制在编辑器能够显示的同一屏幕的范围内。

3。3。2  全局变量

1。 全局变量的定义

全局变量的作用域是整个程序,Win32汇编的全局变量定义在 。data或 。data?段内,可以同时定义变量的类型和长度,格式是:

变量名      类型    初始值1;初始值2,……

变量名      类型    重复数量 dup (初始值1;初始值2,……)

MASM中可以定义的变量类型相当多,具体如表3。2所示。

表3。2  变量的类型

名    称                              表示方式               缩    写         长度(字节)
 
字节
 byte
 db
 1
 

 word
 dw
 2
 
双字(doubleword)
 dword
 dd
 4
 
三字(farword)
 fword
 df
 6
 
四字(quadword)
 qword
 dq
 8
 
十字节BCD码(tenbyte)
 tbyte
 dt
 10
 
有符号字节(signbyte)
 sbyte
  
 1
 
有符号字(signword)
 sword
  
 2
 
有符号双字(signdword)
 sdword
  
 4
 
单精度浮点数
 real4
  
 4
 
双精度浮点数
 real8
  
 8
 
10字节浮点数
 real10
  
 10
 

所有使用到变量类型的情况中,只有定义全局变量的时候类型才可以用缩写,现在先来看全局变量定义的几个例子:

。data

wHour           dw      ?                ;例1

wMinute         dw      10               ;例2

_hWnd           dd      ?                ;例3

word_Buffer     dw      100 dup (1;2)    ;例4

szBuffer        byte    1024 dup (?)     ;例5

szText          db      'Hello;world!'   ;例6

●   例1定义了一个未初始化的word类型变量,名称为wHour。

●   例2定义了一个名为wMinute的word类型变量。

●   例3定义了一个双字类型的变量_hWnd。

●   例4定义了一组字,以0001,0002,0001,0002,…的顺序在内存中重复100遍,一共是200个字。

●   例5定义了一个1 024字节的缓冲区。

●   例6定义了一个字符串,总共占用了12字节。两头的单引号是定界的符号,并不属于字符串中真正的内容。

在byte类型变量的定义中,可以用引号定义字符串和数值定义的方法混用,假设要定义两个字符串“Hello;World! ”和“Hello again”,每个字符串后面跟回车和换行符,最后以一个0字符结尾,可以定义如下:

szText          db      'Hello;world!';0dh;0ah;'Hello again';0dh;0ah;0

2。 全局变量的初始化值

全局变量在定义中既可以指定初值,也可以只用问号预留空间,在 。data?段中,只能用问号预留空间,因为 。data?不能指定初始值,这里就有一个问题:既然可以用问号预留空间,那么在实际运行的时候,这个未初始化的值是随机的还是确定的呢?在全局变量中,这个值就是0,所以用问号指定的全局变量如果要以0为初始值的话,在程序中可以不必为它赋值。



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


第3章 使用MASM


3。3 标号、变量和数据结构(2)

    
3。3。3  局部变量

局部变量这个名称最早源于高级语言,主要是为了定义一些仅在单个函数里面有用的变量而提出的,使用局部变量能带来一些额外的好处,它使程序的模块化封装
返回目录 上一页 下一页 回到顶部 7 5
未阅读完?加入书签已便下次继续阅读!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!