WIN32汇编语言教程:第04章 第一个窗口程序 · 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_SYSCOMMAND            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消息,消息循环结束。

上页:第04章 第一个窗口程序 · 4.4 实验(1) 下页:第04章 第一个窗口程序 · 4.4 实验(3)

第04章 第一个窗口程序

版权所有 © 中山市飞娥软件工作室 证书:粤ICP备09170368号