注:能力实在有限,最终并未得出为什么只能用SendMessage发送消息WM_CopyData。
更没有弄清SendMessage的工作原理。
文中引用的资料或观点也许并不准确,只是希望有兴趣者可以继续分析或者给予指导以解惑。谢谢!
一、先从网上搜罗以下基本知识:
资料1:WM_COPYDATA是用内存映射机制实现的。
简单思路如下:
发送进程为A,目标进程为B。
当A进程用SendMessage(WM_COPYDATA,wParam,lParam)进行发送的时候,它先调用
HANDLE hMap = CreateFileMapping(0xFFFFFFFF,NULL,PAGE_READWRITE,NULL,dwSize,"MSName")
其中dwSize为lParam信息得到的长度(也就是COPYDATASTRUCT结构得到的信息)
MSName可以是MS自己定义的名字,这样就把内容复制到共享内存中。然后等待B进程处理;
当B进程处理WM_COPYDATA消息时,它先用OpenFileMapping()和MapViewOfFile()得到共享内存地址,
然后再把地址值保存到lParam里面使B进程处理消息过程能处理这些数据,处理好后进行A与B再
用CloseHandle()等API进行清除操作就OK了。
SkyJacker注:按照这种说法,那么进程B,如何知道映射文件名是"MSName"呢?
还是lParam本身就表示映射文件名了?
资料2:
SendMessage是同步函数,会等到窗口处理完才返回
PostMessage是异步函数,只是将消息挂到消息队列中就立即返回,由于无法同步可能导致无法响应,
一般情况下窗口消息是不会被丢弃的。
这是因为系统必须管理用以传递数据的缓冲区的生命期,如果你使用PostMessage,数据缓冲区会在接受端有机会处理该数据之前被系统摧毁掉!
看看候杰翻译的"多线程程序设计" 里面有详细解释,总而言之 只能用SendMessage。
SkyJacker注:话虽然是这么说,但是异步也可以接收数据吧。socket函数connect,recv,send等也运行正常啊。
因此,只能是SendMessage函数的设计使然,而不是因为同步或异步的原因。
资料3:请问如何在2个进程间(一个是多线程数据采集程序,一个是画面显示程序)传递大量数据?
采集程序中存在数量不定的线程,其中每一个线程都可以采集数据,并将数据发送到显示程序进行显示。
显示程序就是一个简单的UI程序,将接收到的采集数据显示出来。
在一定时间段中采集的数据量比较大:每秒几条数据。每条数据大概2-3K(来自不同线程)
原来我使用SendMessage(WM_COPYDATA,…) 在2个进程间传递数据。但最近发现一个BUG:
有时在显示数据过程中切换UI的窗口,会引起系统deadlock! 后来查阅资料,发现用SendMessage传递数据时,
在某些情况下的确可以引起deadlock,所以按照书中的建议用SendMessageTimeout(WM_COPYDATA,…) 进行自我保护方式数据传输。
deadlock问题倒是解决了,但又出现数据丢失问题,原因是SendMessageTimeout经常返回timout错误 !
我的问题是除了SendMessage(WM_COPYDATA,…) 方法,还有没有别的方法实现本文中所说的采集程序和画面显示程序间大量数据的传递?
PostMessage不支持 WM_COPYDATA.
SendMessageCallback, SendNotifyMessage也不支持WM_COPYDATA.
我查过国外的很多网站,大概的结论是:
1)WM_COPYDATA是在两个进程间传递大量数据最方便,最好使的方法.
2)但只有SendMessage,SendMessageTimeout支持WM_COPYDATA
3)SendMessage(WM_COPYDATA,…)内部实现是通过File mapping实现的, 系统自动完成同步工作.
4)SendMessage是阻塞的(block), 在某些情况下会引起deadlock. 所以更安全的方法是使用SendMessageTimeout
SkyJacker注:还是没有点明本质。
二、通过反汇编试图熟悉SendMessage过程
1、发送过程:
procudure SendAlmData(const SendText: string);
var
DS: TCopyDataStruct;
begin
DS.dwData := 0;
DS.cbData := Length(SendText); //SendText表示要发送的数据
DS.lpData := @SendText[1];
SendMessage(FaceHandle, WM_COPYDATA, 0, LongWord(@DS)); //FaceHandle表示接收数据的主界面
//PostMessage(FaceHandle, WM_COPYDATA, 0, LongWord(@DS));
//此处必须用SendMessage,用PostMessage主界面接收不到消息
end;
2、SendMessage声明
SendMessage(FaceHandle, WM_COPYDATA, 0, LongWord(@DS)); //WM_COPYDATA = $004A;
LRESULT SendMessage(
HWND hWnd, // handle of destination window
UINT Msg, // message to send
WPARAM wParam, // first message parameter 短参数
LPARAM lParam // second message parameter 长参数
);
3、通过WM_CopyData传输数据
通过TCopyDataStruct结构存储要传输的数据.
只有DS: TCopyDataStruct一个局部变量的情况。
TCopyDataStruct结构:
tagCOPYDATASTRUCT = packed record
dwData: DWORD;
cbData: DWORD;
lpData: Pointer;
end;
4、Delphi编译器调试过程
Begin
004AD36C 53 push ebx //使用ebx存放要传输数据的地址
004AD36D 83C4F4 add esp,-$0c //分配局部变量空间。TCopyDataStructk结构是12个字节大小
004AD370 8BDA mov ebx,edx //edx指向要传输数据的地址(形参SendText)
004AD372 33C0 xor eax,eax //ESP=$12F278
004AD374 890424 mov [esp],eax //dwData=0
004AD377 8BC3 mov eax,ebx
004AD379 E85676F5FF call @LStrLen
004AD37E 89442404 mov [esp+$04],eax //cbData := Length(Str)
004AD382 8BC3 mov eax,ebx
004AD384 E84378F5FF call @LStrToPChar //PChar(Str)
004AD389 89442408 mov [esp+$08],eax //lpData := @Str[1] $E44EBC
004AD38D 8BC4 mov eax,esp //eax存放TCopyDataStruct的起始地址
004AD38F 50 push eax //stdcall方式从右向左 LPARAM=@CDS
004AD390 6A00 push $00 //WPARAM
004AD392 6A4A push $4a //WM_COPYDATA = $004A;
004AD394 A1F0DF4B00 mov eax,[$004bdff0] //[$004bdff0]处,存放全局变量的地址
004AD399 8B00 mov eax,[eax] //获得全局变量 对方窗口句柄 FaceHandle
004AD39B 50 push eax
004AD39C E857A5F5FF call SendMessage
004AD3A1 83C40C add esp,$0c //恢复堆栈
004AD3A4 5B pop ebx //恢复ebx
004AD3A5 C3 ret //pop EIP
004AD3A6 8BC0 mov eax,eax
004AD3A8 55 push ebp
004AD3A9 8BEC mov ebp,esp
004AD3AB 33C0 xor eax,eax
004AD3AD 55 push ebp
004AD3AE 68CDD34A00 push $004ad3cd
004AD3B3 64FF30 push dword ptr fs:[eax]
004AD3B6 648920 mov fs:[eax],esp
I=Length(Str) //eax执行字符串的首地址
004049D4 85C0 test eax,eax //如果字符串地址为空,则跳$3F
004049D6 7403 jz +$03
004049D8 8B40FC mov eax,[eax-$04] //取字符串的长度
004049DB C3 ret
004049DC 85D2 test edx,edx
004049DE 743F jz +$3f
call @LStrToPChar
00404BCC 85C0 test eax,eax //判断是否为空
00404BCE 7402 jz +$02
00404BD0 C3 ret
00404BD1 00B8D14B4000 add [eax+$00404bd1],bh //冗余垃圾代码
00404BD7 C3 ret
call SendMessage //跳转到导入表
004078F0 FF254C054C00 jmp dword ptr [$004c054c] //ScrollWindow
004078F6 8BC0 mov eax,eax
004078F8 FF2548054C00 jmp dword ptr [$004c0548] //SendMessage
004078FE 8BC0 mov eax,eax
00407900 FF2544054C00 jmp dword ptr [$004c0544] //SetActiveWindow
00407906 8BC0 mov eax,eax
00407908 FF2540054C00 jmp dword ptr [$004c0540]
......
SendMessage内部:
77D2F39A 8BFF mov edi,edi
77D2F39C 55 push ebp
77D2F39D 8BEC mov ebp,esp
77D2F39F 56 push esi
77D2F3A0 8B750C mov esi,[ebp+$0c] //首先判断消息WM_CopyData
77D2F3A3 F7C60000FEFF test esi,$fffe0000
77D2F3A9 0F85911D0100 jnz +$00011d91
77D2F3AF 8B4D08 mov ecx,[ebp+$08] //判断接收方窗体句柄
77D2F3B2 83F9FF cmp ecx,-$01
77D2F3B5 0F847BF10000 jz +$0000f17b
77D2F3BB 81F9FFFF0000 cmp ecx,$0000ffff
77D2F3C1 0F846FF10000 jz +$0000f16f
77D2F3C7 E80491FEFF call -$00016efc //进入最终获得一个值eax= $0081DF50,
77D2F3CC 85C0 test eax,eax //此值的获取于窗口句柄有关系.高低16位寻址操作 90586
77D2F3CE 0F845BF10000 jz +$0000f15b
77D2F3D4 6A01 push $01
77D2F3D6 FF7514 push dword ptr [ebp+$14] //$0012F278 //DS: TCopyDataStruct的地址;
77D2F3D9 FF7510 push dword ptr [ebp+$10] //0
77D2F3DC 56 push esi //$4A
77D2F3DD 50 push eax //$0081DF50=call -$00016efc
77D2F3DE E8F0C3FEFF call -$00013c10
77D2F3E3 5E pop esi
77D2F3E4 5D pop ebp
77D2F3E5 C21000 ret $0010
77D2F3E8 81FF06010000 cmp edi,$00000106
call -$00016efc
77D184D0 64A118000000 mov eax, fs:[$00000018] //EAX=7FFDF000
77D184D6 85C9 test ecx,ecx //函数首先检测ecx(接收方窗口句柄)
77D184D8 740C jz +$0c
77D184DA 3B88F4060000 cmp ecx,[eax+$000006f4] //判断EAX偏移6F4位置内容(0)与ECX
77D184E0 0F84F62F0000 jz +$00002ff6
77D184E6 B201 mov dl,$01
77D184E8 EB26 jmp +$26
77D184EA 90 nop
77D184EB 90 nop
77D184EC 90 nop
jmp+$26
77D1850F 90 nop
77D18510 8BFF mov edi,edi
77D18512 55 push ebp //保存刚进入SendMessage位置,原先用来索引SendMessage的形参
77D18513 8BEC mov ebp,esp
77D18515 51 push ecx //消息接收方窗口句柄
77D18516 53 push ebx //要发送数据的地址
77D18517 56 push esi //消息WM_CopyData =$4A
77D18518 57 push edi //edi=$02
77D18519 8855FC mov [ebp-$04],dl //DL=$01
77D1851C 8BF9 mov edi,ecx //edi=ecx =窗口句柄
77D1851E 33F6 xor esi,esi
77D18520 64A118000000 mov eax, fs:[$00000018]
77D18526 8B0D8000D777 mov ecx,[$77d70080]
77D1852C 8D98CC060000 lea ebx,[eax+$000006cc]
77D18532 8BC7 mov eax,edi
77D18534 25FFFF0000 and eax,$0000ffff //获得窗体句柄的低16位 90586 ->0586
77D18539 3B4108 cmp eax,[ecx+$08] //0586 - 12AA
77D1853C 734D jnb +$4d //不成立
77D1853E 8B0DA400D777 mov ecx,[$77d700a4] //ECX=00540000
77D18544 8D0440 lea eax,[eax+eax*2] //eax=eax+eax*2 (eax=$0586)
77D18547 8D0C81 lea ecx,[ecx+eax*4] //ecx=ecx+eax*4 (eax=$0586*3 , ecx=00540000)
77D1854A 8BC7 mov eax,edi //eax=90586 窗口句柄
77D1854C C1E810 shr eax,$10 //右移16位,得到高16位 =9
77D1854F 663B410A cmp ax,[ecx+$0a] //if 9= [ecx+$0a](=0009) 条件相等
77D18553 0F8577600000 jnz +$00006077
77D18559 F6410901 test byte ptr [ecx+$09],$01 //byte ptr [ecx+$09]=$00
77D1855D 752C jnz +$2c
77D1855F 8A4108 mov al,[ecx+$08] //$01
77D18562 3AC2 cmp al,dl //al=dl=$01
77D18564 0F8515560000 jnz +$00005615
77D1856A 8B4318 mov eax,[ebx+$18] //ebx=7FFDF6CC
77D1856D 85C0 test eax,eax //EAX=00720650
77D1856F 8B31 mov esi,[ecx]
77D18571 0F8432580100 jz +$00015832
77D18577 3B30 cmp esi,[eax] //ESI=BC73DF50
77D18579 0F822A580100 jb +$0001582a
77D1857F 3B7004 cmp esi,[eax+$04]
77D18582 0F8321580100 jnb +$00015821
77D18588 2B731C sub esi,[ebx+$1c]
77D1858B 85DB test ebx,ebx
77D1858D 740D jz +$0d
77D1858F F7431400000020 test [ebx+$14],$20000000
77D18596 0F858E5F0000 jnz +$00005f8e
77D1859C 6A01 push $01
77D1859E 57 push edi //EDI=$90586
77D1859F E84CFFFFFF call -$000000b4
77D185A4 85C0 test eax,eax //判断eax,esi是否为零 eax=$01 esi=$0081DF50
77D185A6 0F84555F0000 jz +$00005f55
77D185AC 85F6 test esi,esi
77D185AE 0F844D5F0000 jz +$00005f4d
77D185B4 5F pop edi
77D185B5 8BC6 mov eax,esi //结果存入EAX= $0081DF50
77D185B7 5E pop esi
77D185B8 5B pop ebx
77D185B9 8BE5 mov esp,ebp
77D185BB 5D pop ebp //恢复SendMessage形参
77D185BC C3 ret
77D185BD 90 nop
77D185BE 90 nop
call -$000000b4
----------------------------------------------------
77D184F0 B848120000 mov eax,$00001248
77D184F5 BA0003FE7F mov edx,$7ffe0300
77D184FA FF12 call dword ptr [edx]
77D184FC C20800 ret $0008
77D184FF 90 nop
call dword ptr [edx]
7C92EB8B 8BD4 mov edx,esp //EDX=12F234
7C92EB8D 0F34 sysenter
7C92EB8F 90 nop
7C92EB90 90 nop
7C92EB91 90 nop
sysenter
77D184FC C20800 ret $0008
77D184FF 90 nop
77D18500 90 nop
77D18501 90 nop
77D18502 90 nop
------------------------------------------------------
call -$00013c10
-------------------------------------------------------------------
77D1B7D3 8BFF mov edi,edi
77D1B7D5 55 push ebp
77D1B7D6 8BEC mov ebp,esp //无局部变量
77D1B7D8 51 push ecx //ECX=1
77D1B7D9 51 push ecx
77D1B7DA 53 push ebx //$00E28684-->SendText='AL....'
77D1B7DB 56 push esi //4A
77D1B7DC 8B7508 mov esi,[ebp+$08] //$81DF50
77D1B7DF 8B06 mov eax,[esi] //[$81DF50]=$090586 接收方窗口句柄
77D1B7E1 57 push edi
77D1B7E2 8B7D0C mov edi,[ebp+$0c]
77D1B7E5 81FFE0030000 cmp edi,$000003e0
77D1B7EB 8945F8 mov [ebp-$08],eax
77D1B7EE C645FF00 mov byte ptr [ebp-$01],$00
77D1B7F2 C6450B00 mov byte ptr [ebp+$0b],$00
77D1B7F6 720C jb +$0c
77D1B7F8 81FFE8030000 cmp edi,$000003e8
77D1B7FE 0F86AE1C0000 jbe +$00001cae
77D1B804 E84CCEFFFF call -$000031b4 //以下没有继续分析
77D1B809 3B4608 cmp eax,[esi+$08]
77D1B80C 0F85A01C0000 jnz +$00001ca0
77D1B812 F6461604 test byte ptr [esi+$16],$04
77D1B816 0F85961C0000 jnz +$00001c96
77D1B81C 64A118000000 mov eax, fs:[$00000018]
77D1B822 8B88E4060000 mov ecx,[eax+$000006e4]
77D1B828 8B490C mov ecx,[ecx+$0c]
77D1B82B 0B88F0060000 or ecx,[eax+$000006f0]
77D1B831 66F7C12020 test cx,$2020
77D1B836 0F85761C0000 jnz +$00001c76
77D1B83C 33C0 xor eax,eax
ida5.0.0.879 逆向User32.dll 5.1.2600.2622 Winxp SP2
.text:77D2F390 ; ---------------------------------------------------------------------------
.text:77D2F395 align 4
.text:77D2F398 db 2 dup(90h)
.text:77D2F39A ; Exported entry 572. SendMessageA
.text:77D2F39A
.text:77D2F39A ; *************** S U B R O U T I N E ***************************************
.text:77D2F39A
.text:77D2F39A ; Attributes: bp-based frame
.text:77D2F39A
.text:77D2F39A ; LRESULT __stdcall SendMessageA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam)
.text:77D2F39A public SendMessageA
.text:77D2F39A SendMessageA proc near ; CODE XREF: SendDlgItemMessageA+2Dp
.text:77D2F39A ; PostMessageA+25424p
.text:77D2F39A ; sub_77D1B217+2FBB8p
.text:77D2F39A ; sub_77D1B217+2FBCCp
.text:77D2F39A ; DATA XREF: sub_77D5BD93+54o
.text:77D2F39A ; sub_77D5C506+BFo ...
.text:77D2F39A
.text:77D2F39A hWnd = dword ptr 8
.text:77D2F39A Msg = dword ptr 0Ch
.text:77D2F39A WideCharStr = dword ptr 10h
.text:77D2F39A hMem = dword ptr 14h
.text:77D2F39A
.text:77D2F39A ; FUNCTION CHUNK AT .text:77D3E52F SIZE 00000011 BYTES
.text:77D2F39A ; FUNCTION CHUNK AT .text:77D41140 SIZE 00000046 BYTES
.text:77D2F39A
.text:77D2F39A mov edi, edi
.text:77D2F39C push ebp
.text:77D2F39D mov ebp, esp
.text:77D2F39F push esi
.text:77D2F3A0 mov esi, [ebp+Msg]
.text:77D2F3A3 test esi, 0FFFE0000h
.text:77D2F3A9 jnz loc_77D41140
.text:77D2F3A9
.text:77D2F3AF mov ecx, [ebp+hWnd]
.text:77D2F3B2 cmp ecx, 0FFFFFFFFh
.text:77D2F3B5 jz loc_77D3E536
.text:77D2F3B5
.text:77D2F3BB cmp ecx, 0FFFFh
.text:77D2F3C1 jz loc_77D3E536
.text:77D2F3C1
.text:77D2F3C7 call sub_77D184D0
.text:77D2F3C7
.text:77D2F3CC test eax, eax
.text:77D2F3CE jz loc_77D3E52F
.text:77D2F3CE
.text:77D2F3D4 push 1 ; int
.text:77D2F3D6 push [ebp+hMem] ; hMem
.text:77D2F3D9 push [ebp+WideCharStr] ; WideCharStr
.text:77D2F3DC push esi ; int
.text:77D2F3DD push eax ; int
.text:77D2F3DE call sub_77D1B7D3
.text:77D2F3DE
.text:77D2F3E3
.text:77D2F3E3 loc_77D2F3E3: ; CODE XREF: SendMessageA+F197j
.text:77D2F3E3 ; SendMessageA+11DD0j
.text:77D2F3E3 ; SendMessageA+11DE7j
.text:77D2F3E3 pop esi
.text:77D2F3E4 pop ebp
.text:77D2F3E5 retn 10h
.text:77D2F3E5
.text:77D2F3E5 SendMessageA endp
.text:77D2F3E5
.text:77D2F3E8 ; ---------------------------------------------------------------------------
.text:77D2F3E8 ; START OF FUNCTION CHUNK FOR sub_77D1B7D3
.text:77D2F3E8
.text:77D2F3E8 loc_77D2F3E8: ; CODE XREF: sub_77D1B7D3+13B70j
.text:77D2F3E8 cmp edi, 106h
.text:77D2F3EE jnb loc_77D302C2
.text:77D2F3EE
.text:77D2F3F4 cmp edi, 2Fh
.text:77D2F3F7 jz loc_77D302C2
.text:77D2F3F7
.text:77D2F3FD cmp edi, 0AFh
.text:77D2F403 jbe loc_77D2F373
.text:77D2F403
.text:77D2F409 cmp edi, 0B1h
.text:77D2F40F jbe loc_77D302AE
.text:77D2F40F
.text:77D2F415 cmp edi, 0CCh
.text:77D2F41B jz loc_77D302C2
.text:77D2F41B
.text:77D2F421 cmp edi, 101h
.text:77D2F427 jbe loc_77D2F373
.text:77D2F427
.text:77D2F42D jmp loc_77D40E50
.text:77D2F42D
.text:77D2F42D ; END OF FUNCTION CHUNK FOR sub_77D1B7D3
.text:77D2F42D ; -----------------------------------------------
评论