打印本文 打印本文 关闭窗口 关闭窗口
VB5.0与Windows API 间的呼叫技巧
作者:武汉SEO闵涛  文章来源:敏韬网  点击数3271  更新时间:2009/4/23 18:58:23  文章录入:mintao  责任编辑:mintao
;H20000
Const STANDARD_RIGHTS_READ = (READ_CONTROL)
Const KEY_QUERY_VALUE = &H1
Const KEY_ENUMERATE_SUB_KEYS = &H8
Const KEY_NOTIFY = &H10
Const SYNCHRONIZE = &H100000
Const KEY_READ = ((STANDARD_RIGHTS_READ Or _
KEY_QUERY_VALUE Or KEY_ENUMERATE_SUB_KEYS Or _
KEY_NOTIFY) And (Not SYNCHRONIZE))

Dim key5 As String, ValueName as String, strBuff as String, ResultStr as String
Dim leng1 As Long, resul As Long, hkey As Long
Dim tp As Long, i As Long

key5 = " SOFTWARE\Microsoft\Windows\CurrentVerson "
resul = RegOpenKeyEx(HKEY_CLASSES_ROOT, key5, 0, KEY_READ, hkey)
''''hkey便是subkey (key5)的KeyHandle,先取得它才能存取Subkey内的ValueName
ValueName= "ProDuctId "
tp = REG_SZ
strBuff = String(255, 0)
leng1 = Len(strBuff) + 1
resul = RegQueryString(hkey, ValueName, 0, tp, strBuff, leng1)
''''注意,第三个参数传0,leng1传回copy 到strBuff的字元个数(anci)
leng1 = InStr(1, strBuff, Chr(0), vbBinaryCompare) ''''重新算个数(UniCode)
ResultStr = Left(StrBuff,leng1-1) ''''这便是ProductId的值
*****************************************************************************
在这里有另外一件事要特别说明,范例三程式中有一行leng1=Len(strBuffer)+1,
这行可省不得,很奇怪吧,为什麽明明是一个传回值,却一定要设定给它一个strBuff
的大小呢?这是因为许多WIN API 不会聪明到找strBuff的Null Char在哪里,所以需要
程式传进去,而後它再依这个栏位传回填入strBuff 的数目。

五、Array参数的传递

我们知道Win API 的阵列传递是传阵列的起始位址,所以了,在VB中唯一要注意的
是起始位置的写法。以另一个取得Window目录所在路径的API为
例:
-----------------------------------------------------------------------------
UINT GetWindowsDirectory(
LPTSTR lpBuffer, // address of buffer for Windows directory
UINT uSize // size of directory buffer
); // 若成功,则传回目录的字元数
VB的宣告(API检视员)
Declare Function GetWindowsDirectory Lib "kernel32" Alias _
"GetWindowsDirectoryA" (ByVal lpBuffer As String, ByVal nSize As Long) _
As Long
我们将之更改为
Declare Function GetWindowsDirectory Lib "kernel32" Alias _
"GetWindowsDirectoryA" ( lpBuffer As Byte, ByVal nSize As Long) As Long

-----------------------------------------------------------------------------
范例四
*****************************************************************************
Dim n as Long
Dim Buff() as Byte
Dim StrA as String

Buff = space(256)
n=GetWindowsDirectory(Buff(0), 256)
Buff = Leftb(Buff, n)
StrA = StrConv(Buff, vbUniCode) ''''StrA便是Windows所在目录
*****************************************************************************

在范例四中,GetWindowsDirectory()传入的第一个参数Buff(0)便是这阵列的起始
Byte ,因VB 宣告成lpBuffer As Byte,故传过去的是ByRef Buff(0)的位址,当然了
,你也可以呼叫成n=GetWindowsDirectory(Buff(1), 256),只是传回值是填在Buff(1)
to Buff(n),而Buff(0)则仍为起始的Space Character(32),因为该API传回值是字
元个数,再加上存於Buff中的是Byte Array故,使用Leftb()去除多出的byte,再用
StrConv将Byte Array转成Unicode的字串。比照范例二的作法,我们也可以将Byte
Array 改成以String的方式来做,二者可做一比较,谁比较好或比较顺畅,那见人见智
,不过可以肯定的是,如果传的值是Binary的值,那麽使用Byte Array来做才对,因用
String来传的话,会经过转换成UniCode的步骤,这中间会发生什麽事,没人知道。

六、CallBack Function的作法

VB的使用者通常对於这个名词有著多多少少的疑惑,或称之为"哭爸"Function,而
VB5使用手册使用Window Procedure来说明,除非对Window 系统有一些了解,否则可能
令人更不知所云;我使用另一个例子来说明,那便是KeyBoard Hook。什麽是KeyBoard
Hook 呢,简言之便是按键盘时,便会自动执行某一段Function的功能,就好比Dos时代
的拦截中断向量一般。让我们先看一下设定Hook的宣告吧。

-----------------------------------------------------------------------------
HHOOK SetWindowsHookEx(
int idHook, // type of hook to install
HOOKPROC hkprc, // address of hook procedure
HINSTANCE hMod, // handle of application instance
DWORD dwThreadID // identity of thread to install hook for
);

Declare Function SetWindowsHookEx Lib "user32" Alias SetWindowsHookExA" _
(ByVal idHook As Long, _
ByVal lpfn As Long, _
ByVal hmod As Long, _
ByVal dwThreadId As Long) As Long

-----------------------------------------------------------------------------
Hook有很多种,如KeyBoard Hook, Mouse Hook, JournalRecord Hook等,所以第
一个参数指明了要哪一种Hook,第二个参数便是Hook Procedure所在,也就是方才所说
"自动执行某一段Function的功能"中的那一个Function,这个Function的名称可以随意
给定,但有一定的参数传递规则,例如:
hnexthookproc = SetWindowsHookEx(WH_KEYBOARD, _
AddressOf MyKBHFunc, App.Hinstance, 0)
如此设定则每当按任一个键时,程式自动会去执行 MyKBHFunc。这个Hook Function
是由我们所定义,但是它是由Window自动去呼叫,而不是由我们的程式呼叫,这类的
Function就叫CallBack Function。

以上面的例子来说,这个CallBack Function定义如下:
-----------------------------------------------------------------------------
Public Function MyKBHFunc(ByVal iCode As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long
MyKBHFunc = 0
If iCode < 0 Then
MyKBHFunc = CallNextHookEx(hnexthookproc, iCode, wParam, lParam)
Exit Function
End If
''''侦测 有没有按到PrintScreen键
If wParam = vbKeySnapshot Then
MyKBHFunc = 1
Debug.Print "haha"
End If
End Function
-----------------------------------------------------------------------------

这个KeyBoard Hook Function的目的主要是想拦截有没有按到Print Screen这个键
,这个键不会在Form的KeyDown, KeyPress, KeyUp Event中作用,所以只好透过KeyBoa
rd Hook去拦截。而CallBack Function放的位置有规定,一个是要与呼叫SetWindowsHo
okEx() 的地方在同样的一个Project,另外,它只能存在於.BAS档,不能放在其他地方
。KeyBoard Hook的程式於范五。

范例五
*****************************************************************************
''''以下程式於Hook.bas
Declare Function SetWindowsHookEx Lib "user32" Alias _
"SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, _
ByVal hmod As Long, ByVal dwThreadId As Long) As Long
Declare Function UnhookWindowsHookEx Lib "user32" _
(ByVal hHook As Long) As Long
Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, _
ByVal ncode As Long, ByVal wParam As Long, lParam As Any) As Long

Public hnexthookproc As Long
Public Const HC_ACTION = 0
Public Const WH_KEYBOARD = 2

Public Sub UnHookKBD()
If hnexthookproc 0 Then
UnhookWindowsHookEx hnexthookproc
hnexthookproc = 0
End If
End Sub
Public Function EnableKBDHook()
If hnexthookproc 0 Then
Exit Function
End If
hnexthookproc = SetWindowsHookEx(WH_KEYBOARD, AddressOf _
MyKBHFunc, App.Hinstance, 0)
If hnexthookproc 0 Then
EnableKBDHook = hnexthookproc
End If
End Function
Public Function MyKBHFunc(ByVal iCode As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long
''''这三个参数是固定的,不能动,而MyKBHFunc这个名称只要和
''''SetWindowsHookex()中 AddressOf後的名称一样便可,不一定叫什麽
MyKBHFunc = 0
If iCode < 0 Then
MyKBHFunc = CallNextHookEx(hnexthookproc, iCode, wParam, lParam)
Exit Function
End If
If wParam = vbKeySnapshot Then ''''侦测 有没有按到PrintScreen键
MyKBHFunc = 1
Debug.Print "haha"
End If
End Function
''''以下程式於Form
Private Sub Form_Load()
Call EnableKBDHook
End Sub

Private Sub Form_Unload(Cancel As Integer)
Call UnHookKBD
End Sub
*****************************************************************************
七、自订型态的传递

因这只要用ByRef的方式来做就没有什麽大的问题,故不做说明。

八、综合应用

我们再以一个实例来说明Win API在VB5中呼叫的技巧。有一个函式叫CopyMemory
的宣告如下:

-----------------------------------------------------------------------------
Declare Sub CopyMemory Lib "KERNEL32" Alias "RtlMoveMemory" ( _
lpvDest As Any, lpvSource As Any, ByVal cbCopy as Long)
-----------------------------------------------------------------------------

这个函式可以将 lpvDest的momory copy 到lpvSource上去,cbCopy则代表要copy
多少个byte。有了这个函式,我们可以知道一个Double值存在Memory中的各个byte到底
是多少。

-----------------------------------------------------------------------------
Dim dbl as Double
Dim bte(0 to 7) as Byte
Dbl = 168.256
CopyMemory dbl, byt(0), 8
-----------------------------------------------------------------------------

如此检视bte阵列便可以知道这Double值的各个byte是多少。再以另一个
JournalRecord Hook为例来说明:

范例六
*****************************************************************************
'''' 以下在Hook.bas
Const WM_MOUSELAST = &H209
Const WM_MOUSEFIRST = &H200
Public Const WM_KEYLAST = &H108
Public Const WM_KEYFIRST = &H100
Public Const WH_JOURNALRECORD = 0
Type EVENTMSG
message As Long
paramL As Long
paramH As Long
time As Long
hwnd As Long
End Type
Declare Function SetWindowsHookEx Lib "user32" Alias _
"SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, _
ByVal hmod As Long, ByVal dwThreadId As Long) As Long
Declare Function UnhookWindowsHookEx Lib "user32" _
(ByVal hHook As Long) As Long
Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, _
ByVal nCode As Long, ByVal wParam As Long, lParam As Any) As Long
Declare Sub CopyMemory Lib "KERNEL32" Alias "RtlMoveMemory" _
(lpvDest As Any, ByVal lpvSource As Long, ByVal cbCopy As Long)
Public hNxtHook As Long '''' handle of Hook Procedure
Public msg As EVENTMSG

Sub EnableHook()
hNxtHook = SetWindowsHookEx(0, AddressOf HookProc, App.hInstance, 0)
End Sub
Sub FreeHook()
Dim ret As Long
ret = UnhookWindowsHookEx(hNxtHook)
End Sub
Function HookProc(ByVal code As Long, ByVal wParam As Long, _
ByVal lParam As Long) As Long
CopyMemory msg, lParam, Lenb(msg)
If (msg.message >= WM_KEYFIRST _
And msg.message <= WM_KEYLAST) Then
Debug.Print msg.message, msg.paramH
End If
HookProc = CallNextHookEx(hNxtHook, code, wParam, lParam)
End Function
''''以下程式於Form1
Private Sub Form_Load()
Call EnableHook
End Sub

Private Sub Form_Unload(Cancel As Integer)
Call FreeHook
End Sub
*****************************************************************************

详细的流程不多做说明,我们只把重点放在HookProc这个Hook Procedure,如果我
们查JournalRecord Hook的Hook Procedure可得定义如下:

-----------------------------------------------------------------------------
LRESULT CALLBACK JournalRecordProc(
int code, // hook code
WPARAM wParam, // undefined
LPARAM lParam // 为一个EVENTMSG Structure的address值
);

这个JournalRecordProc 对应到我们的HookProc便是

Function HookProc(ByVal code As Long, ByVal wParam As Long, _
ByVal lParam As Long) As Long

-------------------------------------------------------------

上一页  [1] [2] [3]  下一页

打印本文 打印本文 关闭窗口 关闭窗口