windows环境下32位汇编语言程序设计-第16节
按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
nst
szCaption db 'SendMessage';0
szStart db 'Press OK to start SendMessage; param: %08x!';0
szReturn db 'SendMessage returned!';0
szDestClass db 'MyClass';0
szText db 'Text send to other windows';0
szNotFound db 'Receive Message Window not found!';0
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
de
start:
invoke FindWindow;addr szDestClass;NULL
。if eax
mov hWnd;eax
invoke wsprintf;addr szBuffer;addr szStart;addr szText
invoke MessageBox;NULL;offset szBuffer;
offset szCaption;MB_OK
invoke SendMessage;hWnd;WM_SETTEXT;0;addr szText
invoke MessageBox;NULL;offset szReturn;
offset szCaption;MB_OK
。else
invoke MessageBox;NULL;offset szNotFound;
offset szCaption;MB_OK
。endif
invoke ExitProcess;NULL
;》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》
end start
在这个程序中首先用FindWindow函数找到接收窗口的窗口句柄,FindWindow函数的使用方法是:
invoke FindWindow;lpClassName;lpWindowName
。if eax
mov hWin;eax
。endif
两个参数都指向字符串,lpClassName指向需要寻找的窗口的窗口类,lpWindowName指向需要寻找窗口的窗口标题,如果目标窗口存在的话,函数的返回值是找到的窗口句柄,否则函数返回0。
用接收窗口的窗口类当做参数寻找窗口,如果没有找到则显示“Receive Message Window not found”,找到的话则把“Text send to other windows”字符串的地址当做WM_SETTEXT消息的参数用SendMessage发送给接收窗口。两个程序的源代码可以在所附带光盘的Chapter04SendMessage目录中找到。
好!现在发送开始,首先执行Receive。exe,窗口出来了,然后执行Send。exe,屏幕上出现一个对话框:Press OK to start SendMessage; param: 00402072,表示在Send程序中字符串的地址是00402072h,现在单击“确定”按钮执行SendMessage函数,单击后对话框消失,但接收程序显示出了一个对话框,内容为:
Receive WM_SETTEXT message
param: 0012ff1c
text: 〃Text send to other windows〃
可见字符串是正确地传了过来,但地址却不是发送程序的00402072h,这是怎么回事呢?答案是Windows做“红娘”做到底,它拷贝了WM_SETTEXT消息lParam指向的字符串,并在接收程序的地址空间中开了一块内存放上这个字符串,然后把新的地址值当做lParam传给接收程序,毕竟在WM_GETTEXT消息中,lParam的数值是多少并不重要,重要的是它指向的字符串是否正确。
最后,单击Receive 程序中的“确定”按钮,Send程序马上会弹出一个消息框并显示:SendMessage returned,这是SendMessage函数告诉我们:我回来了!
其实Windows在处理SendMessage和PostMessage的时候要检查消息的类型,并对不同的消息做不同的处理,当消息的参数是一个指针的时候,Windows要把指针指向的内容复制到缓冲区,以便在两个程序的地址空间中传递。
在用户自定义的消息中(WM_USER等)不要在消息参数中传递指针,这只会引发非法访问内存,因为Windows不知道用户的意图,它只会把lParam和wParam当两个普通的数值传递,而不会帮用户把指针指向的内容复制到一个缓冲区中。
来源:电子工业出版社 作者:罗云彬 上一页 回书目 下一页
上一页 回书目 下一页
第4章 第一个窗口程序
4。4 实 验(1)
在这一节中,将通过不同的实验,进一步介绍窗口的运行。首先构造一个程序,在程序中将收到的消息查表翻译成文本以“WM_XXX”格式显示出来,并且将调用各个API函数的过程也显示出来,这样可以分析窗口的各种行为和消息之间的关系。
4。4。1 MsgWindow程序
为了把需要的内容显示出来,可以选择在客户区显示文本,但这样会引入新的消息,干扰实验,所以,这里选择了一种新的方法,就是先打开Windows附件中自带的Notepad记事本程序,然后在程序中将要显示的内容通过SendMessage发送到记事本中,可以通过查看记事本中的内容来了解MsgWindow的运行情况。
同样,先拷贝一份FirstWindow程序进行修改,共增加3个部分。第一部分是将消息查表转换为字符串,首先在 nst段中增加两个表:16进制的消息编号列表dwMsgTable和字符串列表szStringTable,两表中的项目一一对应,代码如下:
nst
dwMsgTable dd WM_NULL
dd WM_CREATE
dd WM_DESTROY
dd WM_MOVE
…
dd WM_EXITSIZEMOVE
MSG_TABLE_LEN equ ( … dwMsgTable)/sizeof dword
MSG_STRING_LEN equ sizeof szStringTable
szStringTable db 'WM_NULL ';0
db'WM_CREATE ';0
db 'WM_DESTROY ';0
db 'WM_MOVE ';0
…
db 'WM_EXITSIZEMOVE ';0
szFormat db 'WndProc: '%04x'%s %08x %08x';0dh;0
MSG_TABLE_LEN定义了表的项数,MSG_STRING_LEN定义了字符串表中每一项的长度。sizeof操作符取的是szStringTable这一行中的数据长度,而非包括下面全部的字符串行。为了简化处理,全部字符串的长度保持相等。由于篇幅所限,这里没有列出全部的消息列表,完整的源代码可以在本书附带光盘的Chapter04MsgWindow01目录中找到。程序在窗口过程的入口处调用_ShowMessage子程序来翻译消息并传给记事本:
_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可以用窗口类当做第一个参数来查找,如果找到,返回的是记事本程序的主窗口句柄,