信息发布软件,b2b软件,广告发布软件

标题: VB.NET中的跨进程消息钩子和实例教程 [打印本页]

作者: 信息发布软件    时间: 2016-11-22 15:03
标题: VB.NET中的跨进程消息钩子和实例教程

 我们都知道在VB6里面可以用API函数来进行子类化,以处理自身的窗体过程;如果跨进程,这就麻烦了,由于我们的函数在我们的进程中(废话),而目标进程的窗口的消息处理函数在目标进程(还是废话),所以只能想办法把我们的代码放到对方进程中去执行——并且要告知我们的进程得到了什么消息。恐怕写汇编就有点吓人了,于是大家都写DLL,其原理就是把回调函数放到一个DLL里面注入到对方进程,DLL去修改目标窗口的默认处理函数——把消息发送给我们。

  当然也有“另类”一点的:http://www.it-berater.org/ThueDownloads/index.shtml上面有一个DLL包,其中含有一个dssubcls.dll,用它,可以轻松的完成我们的工作:就像调用一个API一样简单,而且在我们的程序中使用回调函数!呵呵,省去了自己写DLL的麻烦之后,这些好处足以吸引各位观众了吧?

  好了,VB6的代码大家可以在下载的压缩包中找到,作者提供了一个以记事本为基础的实例(在\dssubcls目录下),非常详细无需详细叙述了。关键是在VB.NET里面如何使用它——如何声明API,如何进行回调,看用来子类化的API的VB6声明先:

  Declare Function SubClass& Lib "dssubcls" (ByVal HwndSubclass&, _
Optional ByVal Address& = 0, _
Optional ByVal OldStyle& = 0, _
Optional ByVal NewStyle& = 0, _
Optional ByVal Ext& = 0, _
Optional ByVal SubClass& = 0)
转化成VB.NET的声明类似下面的样子(习惯使然,我把&展开成了As Integer):

  Declare Function SubClass Lib "dssubcls" (ByVal HwndSubclass As Integer, Optional ByVal Address As Integer = 0, Optional ByVal OldStyle As Integer = 0, Optional ByVal NewStyle As Integer = 0, Optional ByVal Ext As Integer = 0, Optional ByVal SubClass As Integer = 0) As Integer

  这不是很好嘛?问题来了,这样的声明在VB6里面可以使用Addressof function来传入第二个参数(参见你下载的源码),但是在VB.NET里面直接Addressof就不成了——我们需要委托一个回调:

  Private Delegate Function HookCallBack(ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer

  这个委托,对应的是以下函数:

  Private Function mCallback(ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
‘在这里处理得到的消息

  End Function

  使用时,需要注意先实例化这个委托:

  Private fix_COCD = New HookCallBack(AddressOf mCallback)

  此时,fix_COCD就是我们的mCallback函数引用了,用更直观的观点来看,fix_COCD就是一个指向mCallback的指针,相当于VB6里面的Addressof function得到的结果,看似问题解决了,于是我们写了以下代码来搞对方的进程窗体消息:

  SubClass(Handle, fix_COCD, 0, 0, 0, 1) '修改处理函数

  问题真是接踵而至!IDE提示变量类型不符!!事实确实如此,我们把一个HookCallBack类型当做Integer来传递,无法通过检查,那么强行转换吧?当然,你可以去试试。这时,我所做的是,修改这个API声明:

  Private Declare Function SubClass Lib "dssubcls" (ByVal HwndSubclass As Integer, Optional ByVal Address As HookCallBack = Nothing, Optional ByVal OldStyle As Integer = 0, Optional ByVal NewStyle As Integer = 0, Optional ByVal Ext As Integer = 0, Optional ByVal SubClass As Integer = 0) As Integet

  使之符合我们的调用?有点倒行逆施?并非如此,当你习惯了修改API声明之后,会发现有些事变得如此简单,有些事需要你重新认识——对于WIN32 API也是如此。

  
至此,大功告成:

  较为完整的代码如下:

  Code
Private Declare Function SubClass Lib "dssubcls" (ByVal HwndSubclass As Integer, Optional ByVal Address As HookCallBack = Nothing, Optional ByVal OldStyle As Integer = 0, Optional ByVal NewStyle As Integer = 0, Optional ByVal Ext As Integer = 0, Optional ByVal SubClass As Integer = 0) As Integer
Private Declare Function UseSendMessage Lib "dssubcls" (ByVal use As Integer) As Integer
'实例化的委托
Private fix_COCD = New HookCallBack(AddressOf mCallback)
'委托
Private Delegate Function HookCallBack(ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
Public Sub Hook(ByVal Handle As Integer)
proc = SubClass(Handle, fix_COCD, 0, 0, 0, 1) '修改处理函数
UseSendMessage(1)
End Sub

  Private Function mCallback(ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer

  End Function

  
用这个代码的时候,可能会碰见一些“意外情况“,例如wm_datacopy,此时,我们需要进一步去获取LPARTM所指向的结构并对其进行解析(我们要读的是对方窗口所在进程的内存,具体地址由lParam确定——实际上lParam一直是一个指针——IntPrt,但它与Integer完全就是一回事(如果你使用VB2005可能需要使用Intprt.toint32或intprt=new intprt(integer)这些):

  Code
Public Class GetMsg
Public Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Integer, ByVal lpBaseAddress As Integer, ByVal lpBuffer() As Byte, ByVal nSize As Integer, ByRef lpNumberOfBytesWritten As Integer) As Integer
Public Declare Function ReadProcessMemory Lib "kernel32" (ByVal hProcess As Integer, ByVal lpBaseAddress As Integer, ByRef int As Integer, ByVal nSize As Integer, ByRef lpNumberOfBytesWritten As Integer) As Integer
Public Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Integer, ByVal bInheritHandle As Integer, ByVal dwProcessId As Integer) As Integer
Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Integer) As Integer
Private hProc As IntPtr
Sub New(ByVal PID As Integer)
hProc = OpenProcess(&HFFFF, False, PID)
End Sub

  Function readmsg(ByVal address As Integer) As Byte()
Dim buf(19) As Byte
ReadProcessMemory(hProc, address, buf, 20, 0)
Return buf
End Function

  Protected Overrides Sub Finalize()
CloseHandle(hProc)
MyBase.Finalize()
End Sub
End Class
这个类提供了Readmsg方法来读取一些内容——但这并不是完整的,我们知道,LPARAM指向的结构是这样的:

  _
Public Structure COPYDATASTRUCT
Public dwData As Integer
Public cbData As Integer
Public lpData As IntPtr
End Structure

  其中dwData我们不是很关心,当然其中也可能存在一些有用信息(这里不想多说,网上有些文章纯属误导)

  而cbData是一个长度:lpData的长度

  lpData这里被声明为指针,看起来更直观了——它就是地址

  有了地址和长度,如何读取代码就自己写吧。

  提示一下:参考我重载的ReadProcessMemory可能对你有不少帮助。

  当然,上面提到的只是“特殊情况”中的一个典型,还有很多时候,进程是用自定义消息(>&H40A)来传递数据的,例如我所开发的这个工程,打印mCallBack的参数后,得到的是如下结果(十六进制,只提取了有用的信息):

  4731442257D0

  其中lParam就是一个指针,我读了其中的一部分:

  Function readmsg(ByVal address As Integer) As Byte()
Dim buf(19) As Byte
ReadProcessMemory(hProc, address, buf, 20, 0)
Return buf
End Function

  现在就明白为什么上面的代码是那样了:)

  然后进行了一个处理,得到了我想要的信息:

  '消息解码后得到的移动棋子信息:玩家,起X,起Y,止X,止Y,棋子编号,

  走棋总步数
Event Move(ByVal player As Byte, ByVal sx As Byte, ByVal sy As Byte, ByVal dx As Byte, ByVal dy As Byte, ByVal name As Byte, ByVal [step] As Byte)
Private Function mCallback(ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
If wParam = &H14 Then
Dim s As Byte() = msg.readmsg(lParam)
RaiseEvent Move(s(1), s(10), s(11), s(12), s(13), s(14), s(16))
End If
End Function

  当然,在我的工程里面重载的ReadProcessMemory并没有被使用。

  补充一下咯:

  在VB.NET中,处理自己的窗体的消息只需要重载窗体消息处理过程就可以了,无需子类化:)

  有补充一下:

  对于wm_datacopy来说,还有一些数据获取的问题没有说清楚,实际上都可以用一些方法来解决。



作者: 信息发布软件    时间: 2016-11-22 15:05

我们都知道在VB6里面可以用API函数来进行子类化,以处理自身的窗体过程;如果跨进程,这就麻烦了,由于我们的函数在我们的进程中(废话),而目标进程的窗口的消息处理函数在目标进程(还是废话),所以只能想办法把我们的代码放到对方进程中去执行——并且要告知我们的进程得到了什么消息。恐怕写汇编就有点吓人了,于是大家都写DLL,其原理就是把回调函数放到一个DLL里面注入到对方进程,DLL去修改目标窗口的默认处理函数——把消息发送给我们。

   当然也有“另类”一点的面有一个DLL包,其中含有一个dssubcls.dll,用它,可以轻松的完成我们的工作:就像调用一个API一样简单,而且在我们的程序中使用回调函数!呵呵,省去了自己写DLL的麻烦之后,这些好处足以吸引各位观众了吧?

   好了,VB6的代码大家可以在下载的压缩包中找到,作者提供了一个以记事本为基础的实例(在dssubcls目录下),非常详细无需详细叙述了。关键是在VB.NET里面如何使用它——如何声明API,如何进行回调,看用来子类化的API的VB6声明先:

  Declare Function SubClass& Lib "dssubcls" (ByVal HwndSubclass&, _

   Optional ByVal Address& = 0, _

   Optional ByVal OldStyle& = 0, _

   Optional ByVal NewStyle& = 0, _

   Optional ByVal Ext& = 0, _

   Optional ByVal SubClass& = 0)

  转化成VB.NET的声明类似下面的样子(习惯使然,我把&展开成了As Integer):

  Declare Function SubClass Lib "dssubcls" (ByVal HwndSubclass As Integer, Optional ByVal Address As Integer = 0, Optional ByVal OldStyle As Integer = 0, Optional ByVal NewStyle As Integer = 0, Optional ByVal Ext As Integer = 0, Optional ByVal SubClass As Integer = 0) As Integer

  这不是很好嘛?问题来了,这样的声明在VB6里面可以使用Addressof function来传入第二个参数(参见你下载的源码),但是在VB.NET里面直接Addressof就不成了——我们需要委托一个回调:

  Private Delegate Function HookCallBack(ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer

  这个委托,对应的是以下函数:

   Private Function mCallback(ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer

   ‘在这里处理得到的消息

   End Function

  使用时,需要注意先实例化这个委托:

   Private fix_COCD = New HookCallBack(AddressOf mCallback)

  此时,fix_COCD就是我们的mCallback函数引用了,用更直观的观点来看,fix_COCD就是一个指向mCallback的指针,相当于VB6里面的Addressof function得到的结果,看似问题解决了,于是我们写了以下代码来搞对方的进程窗体消息:

  SubClass(Handle, fix_COCD, 0, 0, 0, 1)   '修改处理函数

  问题真是接踵而至!IDE提示变量类型不符!!事实确实如此,我们把一个HookCallBack类型当做Integer来传递,无法通过检查,那么强行转换吧?当然,你可以去试试。这时,我所做的是,修改这个API声明:

  Private Declare Function SubClass Lib "dssubcls" (ByVal HwndSubclass As Integer, Optional ByVal Address As HookCallBack = Nothing, Optional ByVal OldStyle As Integer = 0, Optional ByVal NewStyle As Integer = 0, Optional ByVal Ext As Integer = 0, Optional ByVal SubClass As Integer = 0) As Integet

  使之符合我们的调用?有点倒行逆施?并非如此,当你习惯了修改API声明之后,会发现有些事变得如此简单,有些事需要你重新认识——对于WIN32 API也是如此。

  至此,大功告成:

  较为完整的代码如下:


    Private Declare Function SubClass Lib "dssubcls" (ByVal HwndSubclass As Integer, Optional ByVal Address As HookCallBack = Nothing, Optional ByVal OldStyle As Integer = 0, Optional ByVal NewStyle As Integer = 0, Optional ByVal Ext As Integer = 0, Optional ByVal SubClass As Integer = 0) As Integer    Private Declare Function UseSendmessage Lib "dssubcls" (ByVal use As Integer) As Integer    '实例化的委托    Private fix_COCD = New HookCallBack(AddressOf mCallback)    '委托    Private Delegate Function HookCallBack(ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer    Public Sub Hook(ByVal Handle As Integer)        proc = SubClass(Handle, fix_COCD, 0, 0, 0, 1)   '修改处理函数        UseSendMessage(1)    End Sub    Private Function mCallback(ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer    End Function

作者: 信息发布软件    时间: 2016-11-22 15:06

跨进程消息以及数据发送

    消息机制是WINDOWS的一个特点。在WINDOWS开发中基本上都会用到消息发送以及接收,突别是对于UI界面开发这一块。进程之间相互通信的方式有很多,其中包括跨进程消息。

消息发送 最常用的是使用SendMessage以及PostMessage 系统API函数,消息发到指定的窗口。不管是进程内或进程外我们都可以通过FindWindow 得到窗口句柄。

在进程内发送消息,我们可以发送一切所有定义的消息,如系统消息,或自定的消息,并通过LPARAM或WPARAM参数传递数据。因为我们所使用的数据内存是在同一进程内。那如果不是同一个进程内,还可以通过SendMessage以及PostMessage 系统API函数的LPARAM或WPARAM 参数传递数据吗? 答案是可以的,只是不能以进程内发送消息传递数据的方式。

不管是进程内还是进程外,消息都是会发送到系统消息队列里,然后由系统消息制机分发到指定窗口的。那么有人会问为何不能以进程内发送消息传递数据的方式呢? 因为,进程内与进程外数据的内存块并非在同一个区域,消息可以发送另外一个进程,但却不能访问进程外的数据,因而不能实现数据传递。

跨进程发送数据,Windows 系统提供一个强大的消息WM_COPYDATA。WM_COPYDATA可以实现进程间传递数据,但也就仅止于WM_COPYDATA消息内处理,不能发送控件定义的消息,以及自定义的消息。WM_COPYDATA 讨论的进程间数据传递的方法,那么除了WM_COPYDATA消息外,还有什么方法可以跨进程发送消息传递数据呢?

我们可以通过VirtualAllocEx 函数。它的作用是在指定进程的虚拟空间保留或提交内存区域。下现这用这方法实现跨进程发送系统消息,传递事件数据内容。以Tab控件为例


//查找窗口句柄
HWND hWnd = ::FindWindow(NULL,_T("MFCTabTest"));
if (hWnd)
  {
//获得窗口中 TAB 控件 句柄
   HWND childHwnd = ::FindWindowEx(hWnd, NULL, WC_TABCONTROL, NULL);   
   if (childHwnd)
   {
    //TAB 跳转到第一页面,可以正常发送消息以及系统类型数据如INT,BOOL 等。
   ::SendMessage(childHwnd, TCM_SETCURSEL, 1, 0L);
    //发送 TCN_SELCHANGING 事件通知
    {
     DWORD dwProcessId;

//获取进程ID
     GetWindowThreadProcessId( hWnd, &dwProcessId );

//打开进程
     HANDLEm_hProcess = OpenProcess( PROCESS_ALL_ACCESS, false, dwProcessId );
     if (!m_hProcess)  
return ;
//获取进程分配的虚拟空间内存块
    NMHDR * pNMHDR = NULL; //写入目标进程的NMHDR 结构
     pNMHDR = (NMHDR *)VirtualAllocEx( m_hProcess, NULL, sizeof(NMHDR), MEM_COMMIT,PAGE_READWRITE );
     if (!pNMHDR)  
return ;
//事件数据结构
     NMHDR mhdr;
     mhdr.hwndFrom = childHwnd;
     mhdr.code = TCN_SELCHANGING;
     mhdr.idFrom = 1000;
// 将本地进程中的结构写入到目标进程
     int nRet = WriteProcessMemory( m_hProcess, pNMHDR, &mhdr, sizeof(NMHDR), NULL );
//发送消息以及并传输结构数据
     ::SendMessage(hWnd,WM_NOTIFY,0,(LPARAM)pNMHDR);
//释入虚拟空间内存块
     VirtualFreeEx(m_hProcess,pNMHDR, sizeof(NMHDR),MEM_RELEASE);
    }
  }
  }


除了WM_COPYDATA外,利用虚拟空间也可以方便实现进程间数据通信。并且消息类型更完整,不管是系统消息还是自己定义的消息可以跨进程发送消息传递数据。



作者: 阿拉丁    时间: 2016-11-27 05:05
太久1个半月了,2个客服小哥人都不错,态度也很好应该给好评,只是设计网页的设计感太一般,应该中评。
作者: 89260881    时间: 2016-11-27 07:59
酷很霸气哦!服务真的真的很好哟~~赞一个,还会推荐其他商家来的哦~~棒
作者: 阿拉丁    时间: 2016-11-27 10:46
漂亮,高端大气上档次,大爱,服务态度也好,值得推荐的设计团队,希望生意会因此好一点!
作者: 大宝罗滴滴    时间: 2016-11-28 02:28
了。帮忙处理了好多问题。谢谢了
作者: meilifc001    时间: 2016-11-29 19:22
下单到完成,花了大把的时间,主要是不仅质量好服务态度好,完成后还继续和你一起调整好网页,这样的工作效率和质量,不达成长期合作,还去哪里?
作者: 紫逸风    时间: 2016-11-30 08:41
帮你顶下哈!!
作者: ggt567    时间: 2016-11-30 12:31
还不错
作者: 发财猪    时间: 2016-11-30 23:17
服务超好
作者: nidalma001    时间: 2016-12-1 02:52
信誉,值得好评!
作者: 123    时间: 2016-12-1 04:11
的态度。。。。。。。。。认真、负责
作者: niubttt    时间: 2016-12-1 09:06
人特别好,给我改了好多次,我都不好意思了,晚上还给我加班,敬业好青年,谢谢!
作者: ye112219    时间: 2016-12-2 00:57
东西从来不给评论的懒得打字。但是实在太谢谢技术部那孩子了,业界良心,给你点个赞。
作者: lalajie    时间: 2016-12-2 23:36
度不错总体感觉很好第一次购买本来不放心但是事实证明我的猜想是错的如果有需要希望一直合作下去谢谢店家
作者: cjagl520    时间: 2016-12-3 14:43
店主,速度很快,很满意,正好赶上我得活动,谢谢店主,这次活动赚钱了,再来设计,哈哈
作者: ggt567    时间: 2016-12-4 06:44
量很好物流很快跟卖家描述是一样的很满意
作者: 脱颖而出    时间: 2016-12-5 09:10
家可以看看效果
作者: java12005    时间: 2016-12-6 15:03
不错,而且速度很快,下单后就马上帮忙操作。技术指导很有耐心,满意
作者: 大宝罗滴滴    时间: 2016-12-6 16:26
,太感激卖家了,不光帮我设计好图,还像一个朋友一样的帮我!
作者: a5206662    时间: 2016-12-6 19:13
很细致美观,好评!!
作者: loverun    时间: 2016-12-7 01:24
意老板人很耐心
作者: huaxue98    时间: 2016-12-8 17:24
家服务质量真心没说的,即使我是小白,卖家也做到了绝对的认真不糊弄!
作者: shenyeben    时间: 2016-12-9 04:29
体贴入微,宝贝和描述一致,质量好漂亮,很喜欢‘大爱超好、超赞!
作者: 枯干枯干    时间: 2016-12-9 06:59
根本不按我的意思来修改了一遍又一遍
作者: jiandao1    时间: 2016-12-9 09:13
超快,包装也很好,服务态度非常好,喜欢
作者: meng00123    时间: 2016-12-9 13:22
术静静都很好很耐心的帮我解答问题,感谢~
作者: beiao    时间: 2016-12-10 01:46
度都让我和我的小伙伴们惊呆了!老板发货也特别快!在此给个五星支持一下。
作者: q1598188    时间: 2016-12-12 10:20
专业,客服很认真,特别是23号客服,非常有耐心,回应速度非常快!技术很熟悉,百问不烦!你们公司真的应该好好表扬23号,这样我们客户网站托付给你们,我们很放心,无论是售前还是售后,服务都很好!不象别的地方,弄完就不管了!祝你们生意兴隆!希望以后网站的维护还有售后,一往的好!
作者: weipinzongmeng    时间: 2016-12-13 05:23
很多客户报价都蛮高的,朋友推荐的淘宝,没想到服务这么好,很认真细致,服务到位,技术已达到要求。值得下单
作者: xoxo110    时间: 2016-12-13 23:31
一如既往的好,效率挺高,非常感谢
作者: yiyi2014    时间: 2016-12-14 05:47
前面写错了是077服务很耐心到位@感谢@
作者: 紫逸风    时间: 2016-12-14 21:29
有竞争才有进步嘛
作者: linshihu    时间: 2016-12-16 02:53
,服务态度也非常好,不懂得问题技术回复很即使,太感激了,这家店的产品、服务是的十分好,非常高兴的一次网购,下次有需要一定还会来的!给技术66一个大赞也谢谢技术助理细心说明!
作者: huanyili998    时间: 2016-12-16 04:10
有竞争才有进步嘛
作者: 429187535    时间: 2016-12-16 09:28
修改到了我满意,这么久来评价不好意思
作者: mmgg    时间: 2016-12-16 17:42
专业版的,店招什么的不用自己另外插图,方便了很多。已经开始使用了,用着很方便模板也很喜欢,使用教程也很详细,简单好用,软件非常棒,用了这几天操作起来都非常顺手了,很喜欢.
作者: q1598188    时间: 2016-12-17 10:54
务很好,设计的宝贝很漂亮我很满意,以后有需要还会合作
作者: feiyang2006    时间: 2016-12-17 15:58
和077组合服务非常好
作者: tian001    时间: 2016-12-17 20:30
然中间有些波折,对设计结果还是比较满意的。好评。
作者: 1124789174    时间: 2016-12-18 15:07
感谢店家的细心指导!!谢谢!
作者: daoke    时间: 2016-12-19 04:33
服务好。很专业的一家店,设计新颖。好评。
作者: a001hao    时间: 2016-12-19 09:29
好了,容易上手,有不清楚的客服回答也很及时,功能很强大,很好用,不错,比我之前试用的那家好多了
作者: wangliuh11    时间: 2016-12-19 21:51
边弄了好几年了,可惜优惠力度一般
作者: 乱世扶稣    时间: 2016-12-21 07:46
错很强大
作者: nble002    时间: 2016-12-21 11:46
耐心,信誉不错。好评
作者: zzjiuzi008    时间: 2016-12-22 12:21
心不懂就问他就告诉也不嫌弃烦不给好评等啥呢必须好评太给力了好多客人都说我家店铺好看。从来没有碰到过这么细心的店主,耐心,负责,产品也物美价廉,真是太值得了!




欢迎光临 信息发布软件,b2b软件,广告发布软件 (http://postbbs.com/) Powered by Discuz! X3.2