您的位置:首页 > 其它

窗口间的通信(消息互发与数据传递)

2016-03-14 21:18 429 查看
.窗口间的消息互发:

首先建立一个接收程序:ReceiveMessage.exe

代码:

.386
.model flat,stdcall
option casemap:none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include windows.inc
include gdi32.inc
includelib gdi32.lib
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data?
szBuffer        db              256 dup(?)
hInstance dd  ?
hWinMain dd  ?

.const
szCaptionMain   db      'Receive Message',0                                     //收到消息后的语句
szReceive       db      'Receive WM_SETTEXT message',0dh,0ah
db      'param: %08x',0dh,0ah
db      'text: "%s"',0dh,0ah
szClassNamedb'MyClass',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 窗口过程
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcWinMain procuses ebx edi esi hWnd,uMsg,wParam,lParam
local @stPs:PAINTSTRUCT
local @stRect:RECT
local @hDc

mov eax,uMsg
;********************************************************************
.if eax ==WM_PAINT
invoke  BeginPaint,hWnd,addr @stPs
mov @hDc,eax

invoke  GetClientRect,hWnd,addr @stRect
invoke  DrawText,@hDc,NULL,-1,\
addr @stRect,\
DT_SINGLELINE or DT_CENTER or DT_VCENTER

invoke  EndPaint,hWnd,addr @stPs
;********************************************************************
.elseif  eax == WM_CLOSE
invoke  DestroyWindow,hWinMain
invoke  PostQuitMessage,NULL
.elseif eax ==  WM_SETTEXT                                           //此处是当接收到WM_SETTEXT消息后的操作
invoke wsprintf,addr szBuffer,addr szReceive,lParam,lParam
invoke MessageBox,hWnd,offset szBuffer,addr szCaptionMain,MB_OK
;********************************************************************
.else
invoke  DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif
;********************************************************************
xor eax,eax
ret

_ProcWinMain endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_WinMain proc
local @stWndClass:WNDCLASSEX
local @stMsg:MSG

invoke  GetModuleHandle,NULL
mov hInstance,eax
invoke  RtlZeroMemory,addr @stWndClass,sizeof @stWndClass
;********************************************************************
; 注册窗口类
;********************************************************************
invoke  LoadCursor,0,IDC_ARROW
mov @stWndClass.hCursor,eax
push hInstance
pop @stWndClass.hInstance
mov @stWndClass.cbSize,sizeof WNDCLASSEX
mov @stWndClass.style,CS_HREDRAW or CS_VREDRAW
mov @stWndClass.lpfnWndProc,offset _ProcWinMain
mov @stWndClass.hbrBackground,COLOR_WINDOW + 1
mov @stWndClass.lpszClassName,offset szClassName
invoke  RegisterClassEx,addr @stWndClass
;********************************************************************
; 建立并显示窗口
;********************************************************************
invoke  CreateWindowEx,WS_EX_CLIENTEDGE,offset szClassName,offset szCaptionMain,\
WS_OVERLAPPEDWINDOW,\
100,100,600,400,\
NULL,NULL,hInstance,NULL
mov hWinMain,eax
invoke  ShowWindow,hWinMain,SW_SHOWNORMAL
invoke  UpdateWindow,hWinMain
;********************************************************************
; 消息循环
;********************************************************************
.while  TRUE
invoke  GetMessage,addr @stMsg,NULL,0,0
.break  .if eax == 0
invoke  TranslateMessage,addr @stMsg
invoke  DispatchMessage,addr @stMsg
.endw
ret

_WinMain endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
call _WinMain
invoke  ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
end start


如下图所示:




下面建立发送消息的程序SendMessage.exe


代码:

.386

.model flat,stdcall

option casemap:none

;*******************************************

include windows.inc

include user32.inc

includelib user32.lib

include kernel32.inc

includelib kernel32.lib

;*******************************************

.data

hWnd dd ?

szBuffer db 256 dup(?)

;*******************************************

.const

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

;*******************************************

.code

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



运行如下图所示:






点击确定:






点击确定:






点击确定退出程序。

上面是简单介绍了在两个窗口间发送消息的过程,下面来分析一下两个程序:

首先是接收窗口:首先借用了WINDOWS的一个基本窗口模板,建立一个基本窗口,只需要在该程序的窗口过程中(即回调函数中)自定义添加当收到WM_SETTEXT消息后做出的操作即可,也没有其他什么东西。

然后就是发送窗口:在发送窗口中首先需要用到一个需要清楚的API函数:

FindWindow()
功能:
这个函数检索处理顶级窗口的类名和窗口名称匹配指定的字符串,如果有指定的类名和窗口的名字则表示成功返回一个窗口的句柄
原型:
HWND FindWindow

(

LPCSTR lpClassName,

LPCSTR lpWindowName

);

参数:

lpClassName

指向一个以null结尾的、用来指定类名的字符串或一个可以确定类名字符串的原子。如果这个参数是一个原子,那么它必须是一个在调用此函数前已经通过GlobalAddAtom函数创建好的全局原子。这个原子(一个16bit的值),必须被放置在lpClassName的低位字节中,lpClassName的高位字节置零。

如果该参数为null时,将会寻找任何与lpWindowName参数匹配的窗口。

lpWindowName

指向一个以null结尾的、用来指定窗口名(即窗口标题)的字符串。如果此参数为NULL,则匹配所有窗口名。

返回值:

如果函数执行成功,则返回值是拥有指定窗口类名或窗口名的窗口的句柄。

如果函数执行失败,则返回值为 NULL

知道这个函数的功能就可以理解运用此函数通过字符串‘MyClass’找到目标窗口,利用SendMessage()函数向目标窗口发送消息,当目标窗口的消息循环机制接收到消息后,等待消息机制的处理,然后由WINDOWS调用回调函数(提前定义好的子函数_ProcWinMain)

然后根据自定义操作执行,到此窗口间的消息互发成功结束。


二.下面介绍窗口间的数据传递,在WM_SETTEXT这一类的消息中,windows可以将参数所指的字符串传递到目标窗口的过程中,但是这些消息都有他们的本职工作,并且传递的数据也只限于以0结尾的字符串。为了能够在不同进程的窗口见自由的拷贝任意类型的数据,,windows提供了一个特殊的窗口消息——WM_COPYDATA。

WM_COPYDATA消息用一个COPYDATASTRUCT结构来描述要拷贝的数据的长度和位置:

COPYDATASTRUCT STRUCT

dwData DWORD ? ;附加字段

cbData DWORD ? ;数据长度

lpData DWORD ? ;数据位置指针

COPYDATASTRUCT ENDS

其中dwData字段是一个备用字段,可以存放任何值,例如,我们有可能向另外的进程发送数据的同时用一个数字来表示数据的数据类型,此时就可以用上这个字段;cbData字段用来描述需要拷贝的数据的长度(字节)

lpData用来描述要发送的数据的指针。填充好数据结构后,用SendMessage函数就可以将数据发送给目标窗口过程:

.data

stCopyData COPYDATASTRUCT<>

.code

...

invoke SendMessage,hDestWnd,WM_COPYDATA,hWnd,addr stCopyData

当windos收到WM_COPYDATA消息后,会根据cbData字段的长度建立共享内存区,并且将lpData所指向的数据拷贝到共享内存区,然后定位共享内存中的数据在目标进程中的地址,将该地址存放到COPYDATASTRUCT中的lpData字段中去,然后将变更后的COPYDATASTRUCT结构发送到目标进程中去,目标进程可以通过结构中的lpData字段查找到定位数据。目标窗口过程返回后,windows释放掉共享内存,SendMessage函数返回。

上面介绍了窗口间传送数据的方法过程,下面用代码实现:

首先建立接收窗口:

代码:

.386
.model flat,stdcall
option casemap:none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include windows.inc
include gdi32.inc
includelib gdi32.lib
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data?

hInstance dd  ?
hWinMain dd  ?
szBuffer db  512 dup (?)

.const
szClassName db'MyClass',0
szCaptionMain db'Receive Message',0

szReceive db  'Receive WM_COPYDATA message',0dh,0ah
db 'length: %08x',0dh,0ah
db 'text address: %08x',0dh,0ah
db 'text: "%s"',0dh,0ah,0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 窗口过程
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcWinMain procuses ebx edi esi,hWnd,uMsg,wParam,lParam

mov eax,uMsg
;********************************************************************
.if eax ==WM_CLOSE
invoke  DestroyWindow,hWinMain
invoke  PostQuitMessage,NULL
;********************************************************************
; 收到 WM_COPYDATA 消息将消息附带的数据长度和字符串数据显示出来
;********************************************************************
.elseif  eax == WM_COPYDATA
mov eax,lParam
assume  eax:ptr COPYDATASTRUCT                               ;注意此处
invoke  wsprintf,addr szBuffer,addr szReceive,\
[eax].cbData,[eax].lpData,[eax].lpData
invoke  MessageBox,hWnd,offset szBuffer,addr szCaptionMain,MB_OK
assume  eax:nothing                                                   ;注意此处
;********************************************************************
.else
invoke  DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif
;********************************************************************
xor eax,eax
ret

_ProcWinMain endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_WinMain proc
local @stWndClass:WNDCLASSEX
local @stMsg:MSG

invoke  GetModuleHandle,NULL
mov hInstance,eax
invoke  RtlZeroMemory,addr @stWndClass,sizeof @stWndClass
;********************************************************************
; 注册窗口类
;********************************************************************
invoke  LoadCursor,0,IDC_ARROW
mov @stWndClass.hCursor,eax
push hInstance
pop @stWndClass.hInstance
mov @stWndClass.cbSize,sizeof WNDCLASSEX
mov @stWndClass.style,CS_HREDRAW or CS_VREDRAW
mov @stWndClass.lpfnWndProc,offset _ProcWinMain
mov @stWndClass.hbrBackground,COLOR_WINDOW + 1
mov @stWndClass.lpszClassName,offset szClassName
invoke  RegisterClassEx,addr @stWndClass
;********************************************************************
; 建立并显示窗口
;********************************************************************
invoke  CreateWindowEx,WS_EX_CLIENTEDGE or WS_EX_TOPMOST,offset szClassName,offset szCaptionMain,\
WS_OVERLAPPEDWINDOW,\
50,50,200,150,\
NULL,NULL,hInstance,NULL
mov hWinMain,eax
invoke  ShowWindow,hWinMain,SW_SHOWNORMAL
invoke  UpdateWindow,hWinMain
;********************************************************************
; 消息循环
;********************************************************************
.while  TRUE
invoke  GetMessage,addr @stMsg,NULL,0,0
.break  .if eax == 0
invoke  TranslateMessage,addr @stMsg
invoke  DispatchMessage,addr @stMsg
.endw
ret

_WinMain endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
call _WinMain
invoke  ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
end start







接收窗口就是在一个基本的窗口模板的窗口过程中添加自定义操作,但是有两处需要注意,那就是在代码的窗口过程中出现的两处assume语句(代码种右边注释处),第一个assume语句相于设定把通用寄存器eax与结构COPYDATASTRUCT关联起来(个人感觉就像宏定义,等同),如后面的语句用eax代替COPYDATASTRUCT结构使用结构中的成员;第二个assume语句就是取消第一个assume的设定

接下来建立发送窗口:

代码:

.386
.model flat,stdcall
option casemap:none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.data
hWnd dd  ?
szBuffer db  512 dup (?)
stCopyData COPYDATASTRUCT <>

szCaption db  'SendMessage',0
szStart db  'Press OK to start SendMessage, text address: %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
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
.code
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
mov stCopyData.cbData,sizeof szText
mov stCopyData.lpData,offset szText
invoke  SendMessage,hWnd,WM_COPYDATA,0,addr stCopyData
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







点击确定:






点击确定:






上面是发送窗口及截图,注意API函数FindWindow()的使用

到此窗口间的数据传送结束。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: