使用MASM-标号、变量和数据结构(3)

3.3.4  数据结构

数据结构实际上是由多个字段组成的数据样板,相当于一种自定义的数据类型,数据结构中间的每一个字段可以是字节、字、双字、字符串或所有可能的数据类型。比如在API函数RegisterClass中要使用到一个叫做WNDCLASS的数据结构,Microsoft的手册上是如下定义的:

typedef struct _WNDCLASS {

    UINT         style;

    WNDPROC      lpfnWndProc;

    Int          cbClsExtra;

    int          cbWndExtra;

    HINSTANCE    hInstance;

    HICON        hIcon;

    HCURSOR      hCursor;

    HBRUSH       hbrBackground;

    LPCTSTR      lpszMenuName;

    LPCTSTR      lpszClassName;

} WNDCLASS, *PWNDCLASS;

注意,这是C语言格式的,这个数据结构包含了10个字段,字段的名称是stylelpfnWndProccbClsExtra等,前面的UINTWNDPROC等是这些字段的类型,在汇编中,数据结构的写法如下:

结构名    struct

 

字段1    类型      ?

字段2    类型      ?

 

结构名    ends

上面的WNDCLASS结构定义用汇编的格式来表示就是:

WNDCLASS        struct

 

Style           DWORD      ?

LpfnWndProc     DWORD      ?

cbClsExtra      DWORD      ?

cbWndExtra      DWORD      ?

hInstance       DWORD      ?

hIcon           DWORD      ?

hCursor         DWORD      ?

hbrBackground   DWORD      ?

lpszMenuName    DWORD      ?

lpszClassName   DWORD      ?

 

WNDCLASS            ends

和大部分的常量一样,几乎所有API所涉及的数据结构在Windows.inc文件中都已经有定义了。要注意的是,定义了数据结构实际上只是定义了一个样板,上面的定义语句并不会在哪个段中产生数据,和Word中使用各种“信纸”与“文书”等模板类似,定义了数据结构以后就可以多次在源程序中用这个样板当做数据类型来定义数据,使用数据结构在数据段中定义数据的方法如下:

                .data?

stWndClass      WNDCLASS        <>

                 

或者:

                  .data

stWndClass      WNDCLASS        <1,1,1,1,1,1,1,1,1,1>

                  ……

这个例子定义了一个以WNDCLASS为结构的变量stWndClass,第一段的定义方法是未初始化的定义方法,第二段是在定义的同时指定结构中各字段的初始值,各字段的初始值用逗号隔开,在这个例子中10个字段的初始值都指定为1

在汇编中,数据结构的引用方法有好几种,以上面的定义为例,如果要使用stWndClass中的lpfnWndProc字段,最直接的办法是:

mov     eax,stWndClass.lpfnWndProc

它表示把lpfnWndProc字段的值放入eax中去,假设stWndClass在内存中的地址是403000h,这句指令会被编译成mov eax,[403004h],因为lpfnWndProcstWndClass中的第二个字段,第一个字段是dword,已经占用了4字节的空间。

在实际使用中,常常有使用指针存取数据结构的情况,如果使用esi寄存器做指针寻址,可以使用下列语句完成同样的功能

mov     esi,offset stWndClass

mov     eax,[esi + WNDCLASS.lpfnWndProc]

注意:第二句是[esi + WNDCLASS.lpfnWndProc]而不是[esi + stWndClass.lpfnWndProc],因为前者会被编译成mov eax,[esi+4],而后者会被编译成mov eax,[esi+403004h],后者的结果显然是错误的!如果要对一个数据结构中的大量字段进行操作,这种写法显然比较烦琐,MASM还有一个用法,可以用assume伪指令把寄存器预先定义为结构指针,再进行操作:

mov     esi,offset stWndClass

assume  esi:ptr WNDCLASS

mov     eax,[esi].lpfnWndProc

assume  esi:nothing

这样,使用寄存器也可以用逗点引用字段名,程序的可读性比较好。这样的写法在最后编译成可执行程序的时候产生同样的代码。注意:在不再使用esi寄存器做指针的时候要用assume esi:nothing取消定义。

结构的定义也可以嵌套,如果要定义一个新的NEW_WNDCLASS结构,里面包含一个老的WNDCLASS结构和一个新的dwOption字段,那么可以如下定义:

NEW_WNDCLASS     struct

 

DwOption         dword     ?

OldWndClass      WNDCLASS  <>

 

NEW_WNDCLASS     ends

假设现在esi是指向一个NEW_WNDCLASS的指针,那么引用里面嵌套的oldWndClass中的lpfnWndProc字段时,就可以用下面的语句:

mov     eax,[esi].oldWndClass.lpfnWndProc

结构的嵌套在Windows的数据定义中也常有,比如在第1313.3节中使用的DEBUG_EVENT结构中竟然使用了4层数据结构的嵌套。 熟练掌握数据结构的使用对Win32汇编编程是很重要的!

来源:电子工业出版社 作者:罗云彬
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

汪宁宇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值