【VB.NET】也談跨進程音訊鉤子。本站提示廣大學習愛好者:(【VB.NET】也談跨進程音訊鉤子)文章只能為提供參考,不一定能成為您想要的結果。以下是【VB.NET】也談跨進程音訊鉤子正文
寫給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也是如此。
至此,半途而廢:
較為完好的代碼如下:
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)這些):
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指向的構造是這樣的:
<StructLayout(LayoutKind.Sequential)> _
Public Structure COPYDATASTRUCT
Public dwData As Integer
Public cbData As Integer
Public lpData As IntPtr
End Structure
其中dwData我們不是很關懷,當然其中也能夠存在一些有用信息(這裡不想多說,網上有些文章純屬誤導)
而cbData是一個長度:lpData的長度
lpData這裡被聲明為指針,看起來更直觀了——它就是地址
有了地址和長度,如何讀取代碼就自己寫吧。
提示一下:參考我重載的ReadProcessMemory能夠對你有不少協助。
當然,下面提到的只是“特殊狀況”中的一個典型,還有很多時分,進程是用自定義音訊(>&H40A)來傳遞數據的,例如我所開發的這個工程,打印mCallBack的參數後,失掉的是如下後果(十六進制,只提取了有用的信息):
473 14 42257D0
其中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來說,還有一些數據獲取的問題沒有說清楚,實踐上都可以用一些辦法來處理。
真的要回家咯。餓。。貼一個重載能夠更闡明問題:
Protected Overrides Sub DefWndProc(ByRef m As System.Windows.Forms.Message)
Select Case m.Msg
Case WM_COPYDATA
Dim mMessage As New COPYDATASTRUCT()
mMessage = DirectCast(m.GetLParam(mMessage.[GetType]()), COPYDATASTRUCT)
Dim bs(mMessage.cbData - 1) As Byte
Marshal.Copy(mMessage.lpData, bs, 0, mMessage.cbData)
debig.print System.BitConverter.ToString(bs, 0, mMessage.cbData)
End Select
End Sub