数据结构
据结构实际上是由多个字段组成的数据样板,相当于一种自定义的数据类型,数据结构中间的每一个字段可以是字节、字、双字、字符串或所有可能的数据类型。(据说人是由泥巴捏成的)
比如在API函数RegisterClass 中要使用到一个叫做WNDCLASS的数据结构,Microsoft的手册上是如下定义的: struct _WNDCLASS
typeof 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个字段,字段的名称是style,lpfnWndProc和cbClsExtra等,前面的UINT和WNDPROC等是这些字段的类型,在汇编中,数据结构的写法如下:
结构名 struct
字段1 类型 ?
字段2 类型 ?
……
结构名 ends
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],因为lpfnWndProc 是 stWndClass 中的第二个字段,第一个字段是dword,已经占用了4字节的空间。
在实际使用中,常常有使用指令存取数据结构的情况,如果使用 esi 寄存器做指针寻址,可以使用下列语句完成同样的功能:
mov esi, offset stWndClass
move ax, [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
move ax, [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的数据定义中也常有,熟练掌握数据结构的使用对Win32汇编编程是很重要的!