读取TDrawGrid之获取博易数据
朋友叫我帮忙写个从博易读取数据的工具,可无奈数据所在控件并不是Windows标准控件,也就是说没办法通过发送系统消息来获取
相关数据,于是乎试了一下从内存直接读取,可最后并不能达到预期目的,原因是笔者并不能从内存中找出和TDrawGrid对应的关系。
(如果有网友知道的可以赐教。)
最后实在没办法了,直接用上了Hook API,有的网友可能想到了,Hook Gdi32.dll中相应的文本输出函数,没错,我选择的是TextOutA。
思路如下:
1. 编写一个Dll,用于注入博易并Hook TextOutA。
TextOutA原型如下:
BOOL TextOut( HDC hdc, // 设备描述表句柄 int nXStart, // 字符串的开始位置 x坐标 int nYStart, // 字符串的开始位置 y坐标 LPCTSTR lpString, // 字符串 int cbString // 字符串中字符的个数 );
我们可以通过WindowFromDC来获取hdc相应的窗口的hWnd,并通过GetClassName来获取窗口的类,从而来判断当前所绘画的文本是不是输入TDrawGrid。
获取完数据后,通过WM_COPYDATA消息来发送相应的lpString到目标处理工具。
2. 编写用于接收数据的客户端。
部分代码如下:
__TextOutA proc hdc:DWORD,nXStart:DWORD,nYStart:DWORD,lpString:DWORD,cbString local cds:COPYDATASTRUCT local hwnd:DWORD invoke RestoreApi,hid_TextOutA,1 invoke WindowFromDC,hdc mov hwnd,eax invoke GetClassName,hwnd,offset szClassName,255 mov eax,offset szClassName mov eax,[eax] .if eax==061724454h invoke IsWindowVisible,hwnd .if eax invoke FindWindow,0,offset szMainRecv .if eax push esi push eax mov esi,offset sBuffer invoke RtlZeroMemory,esi,255 mov eax,nXStart mov [esi],eax mov eax,nYStart mov [esi+4],eax mov eax,esi add eax,8 invoke RtlMoveMemory,eax,lpString,cbString mov eax,cbString add eax,8 mov cds.cbData,eax mov cds.lpData,esi mov cds.dwData,0 invoke GetPixel,hdc,1,1 mov cds.dwData,eax pop eax push ebx mov ebx,eax invoke SendMessage,ebx,WM_COPYDATA,0,addr cds pop ebx pop esi .endif .endif .endif invoke TextOut,hdc,nXStart,nYStart,lpString,cbString invoke RestoreApi,hid_TextOutA,0 ret __TextOutA endp
Public Function InterceptedCallBack(ByVal hwnd As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long If uMsg = WM_COPYDATA Then Dim cbs As COPYDATASTRUCT Dim md As MyData CopyMemory ByVal VarPtr(cbs), ByVal lParam, Len(cbs) CopyMemory ByVal VarPtr(md), ByVal cbs.lpData, cbs.cbData Debug.Print Hex(cbs.dwData), md.x, md.y, StrConv(md.d, vbUnicode) End If InterceptedCallBack = CallWindowProc(PrevWndProc, hwnd, uMsg, wParam, lParam) End Function
VB+Asm代码,比较粗糙,见谅。
然而,TextOutA对于屏幕能看到的才画出来,那么整个TDrawGrid那么多行,要怎么获取所有的数据呢?
笔者通过SendMessage,发送相关滚动条的事件,来达到刷新整个TDrawGrid的目的,这样就OK了。
当然,这样获取到的数据是十分零散的,如下:
12 355 07-01 09:24 122 355 48860 204 355 48860 286 355 48860 368 355 48860 462 355 0 535 355 3058 12 380 07-01 09:25 122 380 48860 204 380 48860 286 380 48860 368 380 48860 462 380 0 535 380 3058 12 405 07-01 09:26 122 405 48860 204 405 48860 286 405 48860 368 405 48860 462 405 0 535 405 3058 12 355 07-01 09:26 122 355 48860 204 355 48860 286 355 48860 368 355 48860 462 355 0 535 355 3058 ....... ....... .......
但实际上只要稍微观察,还是能找出规律,很容易地就能整理数据了。
下面是获取、整理并转换为excel文档的效果图:
OK,收工了。