windows环境下32位汇编语言程序设计-第15部分
按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
_ProcWinMain proc uses ebx edi esi;hWnd;uMsg;wParam;lParam
invoke _ShowMessage;uMsg;wParam;lParam
mov eax;uMsg
。if eax WM_XXX
…
_ShowMessage子程序用来将消息查表翻译成字符串,源程序如下:
_ShowMessage proc _uMsg;_wParam;_lParam
local @szBuffer'128':byte
pushad
;********************************************************************
; 查找消息的说明字符串
;********************************************************************
mov eax;_uMsg
mov edi;offset dwMsgTable
mov ecx;MSG_TABLE_LEN
cld
repnz scasd
。if ZERO?
sub edi;offset dwMsgTable + sizeof dword
shr edi;2
mov eax;edi
mov ecx;MSG_STRING_LEN
mul ecx
add eax;offset szStringTable
;********************************************************************
; 翻译格式并发送到 Notepad 窗口
;********************************************************************
invoke wsprintf;addr @szBuffer;addr szFormat;
_uMsg;eax;_wParam;_lParam
invoke _SendtoNotepad;addr @szBuffer
。endif
popad
ret
_ShowMessage endp
在这里要用到repnz scasd指令,scasd指令是把eax中的值从'edi'开始的内存中按双字比较,同时将edi加4,如果相等,则ZR标志置位,否则为NZ,repnz表示如果标志为NZ,则以ecx为重复次数重复搜索,直到相等或ecx为零为止。
将ecx赋值为消息表的项数MSG_TABLE_LEN,将edi赋值为消息表的开始地址offset dwMsgTable,然后开始查找,停止后可以查看标志Zero位,如果是非ZERO,表示查完全部都没有找到,如果是ZERO,则表示找到表项。
当标志为ZERO时,edi指向找到项目的后一项,将edi减去一项的长度(sizeof dword)以及表的基址,再除以表项的长度(sizeof dword等于4,除以4等于右移两位,所以程序中用shr edi;2),就是消息在表中的索引了,接下来算出消息字符串的位置,位置等于:索引×字符串长+字符串表基址,代码如下:
mov ecx;MSG_STRING_LEN
mul ecx
add eax;offset szStringTable
这样,eax中就是字符串的地址了。最后将消息编号、名称和参数用wsprintf函数格式化成可以发送的字符串存放到@szBuffer中,并用_SendtoNotepad子程序将@szBuffer中的内容发送到记事本去。
程序增加的第二部分就是下面这个_SendtoNotepad子程序:
szDestClass db 'Notepad';0
_SendtoNotepad proc _lpsz
local @hWinNotepad
pushad
invoke FindWindow;addr szDestClass;NULL
。if eax
mov ecx;eax
invoke ChildWindowFromPoint;ecx;20;20
。endif
。if eax
mov @hWinNotepad;eax
mov esi;_lpsz
@@:
lodsb
or al;al
jz @F
movzx eax;al
invoke PostMessage;@hWinNotepad;WM_CHAR;eax;1
jmp @B
@@:
。endif
popad
ret
_SendtoNotepad endp
来源:电子工业出版社 作者:罗云彬 上一页 回书目 下一页
v上一页 回书目 下一页
第4章 第一个窗口程序
4。4 实 验(2)
该子程序中首先用FindWindow函数来查找记事本程序是否已经运行,记事本程序的窗口类名称为“Notepad”,FindWindow可以用窗口类当做第一个参数来查找,如果找到,返回的是记事本程序的主窗口句柄,否则返回0。
要发送的是模拟键盘按键的消息WM_CHAR,这样就好像在记事本中人工键入字符,但直接向记事本主窗口发送WM_CHAR消息是不行的,要向记事本窗口客户区中的编辑子窗口发送消息才行,所以程序中又用从位置获取子窗口句柄的函数ChildWindowFromPoint来获得编辑子窗口的句柄。
锁定了最后的目标即记事本中的编辑子窗口后,程序用PostMessage向它发送消息,根据字符串的长度,用一个循环每次发送一个WM_CHAR消息,WM_CHAR消息的wParam和lParam的含义是:
wParam = chCharCode // wParam是键值
lParam = lKeyData // lParam是键数据(重复次数)
程序中用mov eax;al将键值扩展到参数所需的32位,当做wParam参数发送,lParam为1,表示键的重复次数为1次,这样一来,记事本中就源源不断地显示出MsgWindow程序的运行轨迹了。
MsgWindow程序增加的第三部分是在每个函数的前后增加了显示状态的语句,它们只是简单地把一个字符串发送到记事本中去:
;定义一些字符串
szCreateWindow1 db 'Creating Window。。。';0dh;0
szCreateWindow2 db 'CreateWindow end';0dh;0
szShowWindow1 db 'Showing Window。。。';0dh;0
szShowWindow2 db 'ShowWindow end';0dh;0
szUpdateWindow1 db 'Updating Window。。。';0dh;0
szUpdateWindow2 db 'UpdateWindow end';0dh;0
szGetMsg1 db 'Getting Message。。。';0dh;0
szGetMsg2 db ''%04x'Message gotten';0dh;0
szDispatchMsg1 db 'Dispatching Message。。。';0dh;0
szDispatchMsg2 db 'DispatchMessage end';0dh;0
…
invoke _SendtoNotepad;addr szCreateWindow1
invoke CreateWindowEx;…
invoke _SendtoNotepad;addr szCreateWindow2
invoke _SendtoNotepad;addr szShowWindow1
invoke ShowWindow;hWinMain;SW_SHOWNORMAL
invoke _SendtoNotepad;addr szShowWindow2
invoke _SendtoNotepad;addr szUpdateWindow1
invoke UpdateWindow;hWinMain
invoke _SendtoNotepad;addr szUpdateWindow2
…
上面代码中的粗体部分就是相对于FirstWindow程序增加的内容,好了,现在DOS控制台上键入nmake将MsgWindow程序编译出来,然后打开记事本,再运行MsgWindow。exe,如果记事本上出现一大堆的东西,就说明实验可以开始了!
4。4。2 开始实验
实验1。 验证收到消息的顺序
打开记事本,然后运行MsgWindow程序,记事本上出现的内容为:
Creating Window。。。
WndProc: '0024'WM_GETMINMAXINFO 00000000 0012fda4
WndProc: '0081'WM_NCCREATE 00000000 0012fd8c
WndProc: '0083'WM_NCCALCSIZE 00000000 0012fdc4
WndProc: '0001'WM_CREATE 00000000 0012fd68
CreateWindow end
Showing Window。。。
WndProc: '0018'WM_SHOWWINDOW 00000001 00000000
WndProc: '0046'WM_WINDOWPOSCHANGING 00000000 0012fec0
WndProc: '0046'WM_WINDOWPOSCHANGING 00000000 0012fec0
WndProc: '001c'WM_ACTIVATEAPP 00000001 00000450
WndProc: '0086'WM_NCACTIVATE 00000001 00000000
WndProc: '000d'WM_GETTEXT 000001fe 0012f52c
WndProc: '0006'WM_ACTIVATE 00000001 00000000
WndProc: '0007'WM_SETFOCUS 00000000 00000000
WndProc: '0085'WM_NCPAINT 00000001 00000000
WndProc: '000d'WM_GETTEXT 000001fe 0012f52c
WndProc: '0014'WM_ERASEBKGND e3010449 00000000
WndProc: '0047'WM_WINDOWPOSCHANGED 00000000 0012fec0
WndProc: '0005'WM_SIZE 00000000 00450064
WndProc: '0003'WM_MOVE 00000000 004b0038
ShowWindow end
Updating Window。。。
WndProc: '000f'WM_PAINT 00000000 00000000
UpdateWindow end
Getting Message。。。
以WndProc带头的是在窗口过程中收到的消息,显然,和4。2。4节中讲述的是一致的,在调用CreateWindowEx的时候,窗口过程就开始接收消息,里面有重要的WM_CREATE,然后在ShowWindow的时候,Windows向窗口过程发送了很多的消息,而UpdateWindow只给窗口过程发送了一条WM_PAINT消息,接下来就进入了消息循环。
可以看到,GetMessage函数是程序主动上交空闲时间的办法之一,因为显示出Getting Message。…以后,程序就等着那里了,这表示程序的空闲时间并不浪费在消息循环中,而是在GetMessage函数内部由Windows自己分配了。
接下来把鼠标移过MsgWindow窗口,在记事本上看到了什么?用户一个小小的动作就够窗口过程忙的——我们看到了多次重复的下列内容:
WndProc: '0084'WM_NCHITTEST 00000000 00830096
WndProc: '0020'WM_SETCURSOR 001b0304 02000001
'0200'Message gotten
Dispatching Message。。。
WndProc: '0200'WM_MOUSEMOVE 00000000 0038005e
DispatchMessage end
Getting Message。。。
首先,Windows在GetMessage没有返回的时候就调用了两次窗口过程,分别是处理WM_NCHITTEST和WM_SETCURSOR,它们并不经过消息循环;然后,GetMessage取到'0200'消息并返回,0200是WM_MOUSEMOVE消息的编号;接下来,DispatchMessage函数开始工作,在这个函数的内部,消息被Windows发送给窗口过程处理,最后DispatchMessage返回,然后开始新的GetMessage。
最后在MsgWindow上单击“关闭”按钮,看发生了什么:
'00a1'Message gotten
Dispatching Message。。。
WndProc: '00a1'WM_NCLBUTTONDOWN 00000014 003d0097
WndProc: '0215'WM_CAPTURECHANGED 00000000 00000000
WndProc: '0112'WM_SYSMAND 0000f060 003d0097
WndProc: '0010'WM_CLOSE 00000000 00000000
WndProc: '0046'WM_WINDOWPOSCHANGING 00000000 0012fad8
WndProc: '0047'WM_WINDOWPOSCHANGED 00000000 0012fad8
WndProc: '0086'WM_NCACTIVATE 00000000 00000000
WndProc: '0006'WM_ACTIVATE 00000000 00000000
WndProc: '001c'WM_ACTIVATEAPP 00000000 00000450
WndProc: '0008'WM_KILLFOCUS 00000000 00000000
WndProc: '0002'WM_DESTROY 00000000 00000000
WndProc: '0082'WM_NCDESTROY 00000000 00000000
DispatchMessage end
Getting Message。。。
'0012'Message gotten
GetMessage收到的是按下鼠标的WM_NCLBUTTONDOWN的消息,由DispatchMessage转给窗口过程处理后,窗口过程将它转手给了DefWindowProc,DefWindowProc根据鼠标的位置得出结论:用户按的是“关闭”按钮,放开鼠标后,它就给窗口过程发送WM_CLOSE消息,当窗口过程调用DestroyWindow后,窗口被摧毁,窗口过程最后收到的是WM_DESTROY消息和WM_NCDESTROY消息,而消息循环中GetMessage最后收到的是0012号WM_QUIT消息,消息循环结束。
来源:电子工业出版社 作�