跨进程消息以及数据发送 消息机制是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控件为例
//查找窗口句柄 //获取进程ID //打开进程
除了WM_COPYDATA外,利用虚拟空间也可以方便实现进程间数据通信。并且消息类型更完整,不管是系统消息还是自己定义的消息可以跨进程发送消息传递数据。 |
我们都知道在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 |
|( 京ICP备09078825号 )
GMT+8, 2024-11-27 13:08 , Processed in 0.127341 second(s), 42 queries .