⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vb5.0与windows api 间的呼叫技巧.txt

📁 一般会使用WINDOW API的情况
💻 TXT
📖 第 1 页 / 共 2 页
字号:
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。其实,有个更直觉的例子,那就是事件(Event);
比如说Form产生时会有一个Form_Load事件,在这个事件内我们可以写很多程式,但这些
程式不是给我们其他的Procedure呼叫的,而是Form在Load进来时,由Window去呼叫的,
这便是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

-----------------------------------------------------------------------------
有没有注意到第三个叁数它是一个 ByVal的Long,指的是存放某一个EVENTMSG的位址,
而先前我们提过,自定型态的叁数传递要使用ByRef的方式才能解决,天啊!它用ByVal
的方式来做,如果是C语言,那不成问题,只要如下:

-----------------------------------------------------------------------------
EVENTMSG  *p;
P = (EVENTMSG *) lParam;
-----------------------------------------------------------------------------
如此便可以用 *p->message  之方式来取得内容,但VB呢?这里便要用些小技巧了,试
想,如果我们能依lParam所指的位址,一个Byte一个Byte的Copy到一个EVENTMSG的变数
上面,不就可以了吗?所以了, CopyMomory这个函式派上用场了,但是 CopyMomory的
原始宣告如下,前面两个叁数都是ByRef的方式,但目前对我们有的是lParam的内容(假
设是lParam = 25600, Address of lParam = 100100),如果我们使用底下的宣告,而去
呼叫
-- 宣告一 ----------------------------------------------------------------------
 Declare Sub CopyMemory Lib "KERNEL32" Alias "RtlMoveMemory" ( _
   lpvDest As Any,  lpvSource As Any, ByVal cbCopy as Long)

 CopyMomory msg ,  lParam,  Lenb(msg)
-----------------------------------------------------------------------------
那麽WinAPI  RtlMoveMemory会得到第二个叁数值=100100,而使指标指到100100的位址
,那麽就得不到想要的资料了 (因资料在25600的位址上)。所以我们改变原始宣告,将
之变成宣告二的样子,如此VB 第二个叁数的作法会传出25600(因为ByVal嘛)给RtlMoveMe
mory,那不就成功了吗?

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

CopyMomory msg ,  lParam,  Lenb(msg)
-----------------------------------------------------------------------------
   或许这RtlMoveMemory您在许多地方都会用上,前两个叁数时而要ByRef, 时而需
ByVal,那是否就要定义四个宣告来因应不同之需,其实也不用,上面的例子中,只要
宣告成宣告一的样子,但是呼叫时改成:

    CopyMemory msg, ByVal lParam, Lenb(msg)

在第二个叁数前加上ByVal这样这可以了啦。

    这里还有另外一个做法,那就是从Hook Procedure的宣告着手,别忘了,Hook Pro
cedure是Window所呼叫的,所以它传给我们定义的HookProc()时,第三个叁数以先前的
举例来说便是传入25600,那麽,我们将HookProc()改定义成:

-----------------------------------------------------------------------------
Function HookProc(ByVal code As Long, ByVal wParam As Long,  _
                 lParam As Long) As Long
-----------------------------------------------------------------------------
    第三个叁数变成 ByRef的方式传入,所以了,用msg = lParam来取代CopyMemory的
作法, 嘛可以通啦!即如下:

-----------------------------------------------------------------------------
Function HookProc(ByVal code As Long, ByVal wParam As Long,  _
                 lParam As Long) As Long  'lParam改成ByRef
    msg = lParam
    ' 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(hHook, code, wParam, lParam)
End Function
-----------------------------------------------------------------------------

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -