窗口间的通信(消息互发与数据传递)
2016-03-14 21:18
429 查看
一.窗口间的消息互发:
首先建立一个接收程序:ReceiveMessage.exe
代码:
如下图所示:
下面建立发送消息的程序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函数:
二.下面介绍窗口间的数据传递,在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函数返回。
上面介绍了窗口间传送数据的方法过程,下面用代码实现:
首先建立接收窗口:
代码:
接收窗口就是在一个基本的窗口模板的窗口过程中添加自定义操作,但是有两处需要注意,那就是在代码的窗口过程中出现的两处assume语句(代码种右边注释处),第一个assume语句相于设定把通用寄存器eax与结构COPYDATASTRUCT关联起来(个人感觉就像宏定义,等同),如后面的语句用eax代替COPYDATASTRUCT结构使用结构中的成员;第二个assume语句就是取消第一个assume的设定
接下来建立发送窗口:
代码:
点击确定:
点击确定:
上面是发送窗口及截图,注意API函数FindWindow()的使用
到此窗口间的数据传送结束。
首先建立一个接收程序: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()的使用
到此窗口间的数据传送结束。
相关文章推荐
- HDU 1257 SDOI(贪心)
- 地理信息+,共享经济和万众创新
- [Elixir003]通过环境变量(Environment Variables)来管理config
- 【bzoi2006】【狼抓兔子】【最小割】
- 输出由*构成的菱形
- centos系统启动Android模拟器报:/usr/lib64/libstdc++.so.6: version `GLIBCXX_3.4.15' not found
- 文章标题
- BZOJ3223文艺平衡树
- 解析校内网邮箱
- POJ3468 A Simple Problem with Integers
- Android多媒体播放器 MediaPlayer使用
- 在vs2008中怎么把一个项目复制到另一个项目中
- C++中值传递、指针传递、引用传递的总结
- 显式锁Lock、ReentrantLock
- 带标题可拖动的SeekBar
- linux 下链接mysql练习
- UVa - 227 - Puzzle
- Swift - 页面传值
- BZOJ 1833
- Valid Parentheses