注册 登录
编程论坛 汇编论坛

问题来了。第九章,NMHDR.code 怎么会编译成常量?

okayyyy 发布于 2010-07-24 03:14, 1475 次点击
能给点提示吗?
我想来想去,也没记起在哪里碰到过

呵呵,我用老罗的FindFile.exe跟dir *.*/s比较了下。  还是DOS命令快几秒

[ 本帖最后由 okayyyy 于 2010-7-24 06:38 编辑 ]
12 回复
#2
东海一鱼2010-07-24 10:36
没看过老罗的书,不知道它的这个NMHDR.code 是怎莫赋值的?
不过正常情况下这个NMHDR.code 应该就是WM_NOTIFY消息中WPARAM的高字。

老罗的FindFile.exe跟dir *.*/s比较了下。  还是DOS命令快几秒

这个比较,我想没有什莫意义吧。因为这里的速度只跟算法有关。NT的文件搜索貌似用的树算法,
而老罗估计用的是最普通的递归方式。
#3
zklhp2010-07-24 10:44
NMHDR STRUCT
    hwndFrom    DWORD ?
    idFrom      DWORD ?
    code        DWORD ?
NMHDR ends

不要被小写的code迷惑 这里就这么定义的(一般结构里面都大写 不知道这个为啥这样。。。)

我就用书里的内容回答你

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个字段,字段的名称是style,lpfnWndProc和cbClsExtra等,前面的UINT和WNDPROC等是这些字段的类型,在汇编中,数据结构的写法如下:

结构名   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],因为lpfnWndProc是stWndClass中的第二个字段,第一个字段是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的数据定义中也常有,比如在第13章13.3节中使用的DEBUG_EVENT结构中竟然使用了4层数据结构的嵌套。 熟练掌握数据结构的使用对Win32汇编编程是很重要的!



注意:第二句是[esi + WNDCLASS.lpfnWndProc]而不是[esi + stWndClass.lpfnWndProc],因为前 者会被编译成mov eax,[esi+4],而后者会被编译成mov eax,[esi+403004h],后者的结果显然是错误的!
#4
zklhp2010-07-24 10:44
没抢到沙发 复制粘贴费时。。。
#5
zklhp2010-07-24 10:46
以下是引用okayyyy在2010-7-24 03:14:18的发言:

能给点提示吗?
我想来想去,也没记起在哪里碰到过

呵呵,我用老罗的FindFile.exe跟dir *.*/s比较了下。  还是DOS命令快几秒

你所谓的dos命令应该是指 cmd 可能cmd实现的搜索比较快 不好说啊~
#6
zklhp2010-07-24 14:08
本人实测

在system32

dir *.* /s 3'' 46'''

     所列文件总数:
            2854 个文件    613,265,347 字节
             923 个目录  5,581,844,480 可用字节

罗大的程序 2'' 15 '''

cmd还得解析 判断 输出 等等 自然比较慢啦

不过两者都是用的 FindFirstFile

4AD01B45   .  FF15 A011D04A CALL DWORD PTR DS:[<&KERNEL32.FindFirstF>; \FindFirstFileW

至于算法 遍历应该都差不多罢


[ 本帖最后由 zklhp 于 2010-7-24 14:10 编辑 ]
#7
okayyyy2010-07-24 15:27
回复 5楼 zklhp
你那段解释  [esi + WNDCLASS.lpfnWndProc]的用法是在太及时了。唉 明明老罗的书提到过,就是记不起
#8
okayyyy2010-07-24 15:30
回复 2楼 东海一鱼
问题没写详细,到把你给弄糊涂了  失误失误
其实就是:[esi + WNDCLASS.lpfnWndProc]这种用法
#9
okayyyy2010-07-24 16:00
老大,你的功力很深啊。 用什么方法能找到dir的实际代码?我只知道这种命令实际是一个小程序

唉,老罗害死人。你看看他定义的变量 dwstatuswidth。

看到前缀,我定义一个相似的 dwstatuswidth  dw 10,20,30,40
搞老半天都没把,状态栏分成4个格子。

原来老罗的这个dwstatuswidth 是个 dd!!!!!!

浪费了2个小时

[ 本帖最后由 okayyyy 于 2010-7-24 17:03 编辑 ]
#10
东海一鱼2010-07-24 17:11
以下是引用okayyyy在2010-7-24 15:30:30的发言:

问题没写详细,到把你给弄糊涂了  失误失误
其实就是:[esi + WNDCLASS.lpfnWndProc]这种用法
啊,这个呀。
我一般爱用 (WNDCLASS ptr[esi]).lpfnWndProc 这种形式。纯属个人爱好,哈。
#11
东海一鱼2010-07-24 17:14
回复 4楼 zklhp
不好意思啊。没跟你抢‘师太’的意思。纯属巧合。
#12
zklhp2010-07-24 20:33
1 老罗是罗聪的网名 罗云彬不是“老罗”

2 书看一遍是不行的

3 光会编程是不行的

用什么方法能找到dir的实际代码?我只知道这种命令实际是一个小程序

错!

dir 是dos里面的“内部命令”(貌似叫这个) 和外部命令有什么区别呢 最大的区别应该是 没有一个程序叫“dir” 而是由command实现(大概是这个意思)

win 下 我们用cmd 也没有dir这个程序的 而是由cmd实现的 所以 只要逆向cmd就可以知道算法

好好学罢。。。。。
#13
zklhp2010-07-24 20:36
以下是引用okayyyy在2010-7-24 16:00:40的发言:

老大,你的功力很深啊。 用什么方法能找到dir的实际代码?我只知道这种命令实际是一个小程序

唉,老罗害死人。你看看他定义的变量 dwstatuswidth。

看到前缀,我定义一个相似的 dwstatuswidth  dw 10,20,30,40
搞老半天都没把,状态栏分成4个格子。

原来老罗的这个dwstatuswidth 是个 dd!!!!!!

浪费了2个小时

非也

匈牙利命名法里面 dw 是double word 的缩写 也就是开头

而dd 是masm里面定义double word 的伪指令

罗大写的没错

开始我也郁闷过 适应就好 不过 罗大没错

当然 匈牙利命名法不是必须遵守的 你要不愿意用 我也不能说什么
1