熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

VB動態調用外部函數的方法

2013-11-13 10:15:13  來源: .NET編程 

  VB可以用Declare聲明來調用標准DLL的外部函數但是其局限性也很明顯利用Declare我們只能載入在設計時通過Lib和Alias字句指定的函數指針!而不能在運行時指定由我們自己動態載入的函數指針)不能用Declare語句來調用任意的函數指針當我們想動態調用外部函數的時候就必須考慮采用其他的輔助方法來完成這個任務了

  對我這樣的菜鳥還有點深奧在資料搜索過程中找到通過在VB中調入匯編程序比較簡便的實現了這個功能下面就是實現原理

  )使用LoadLibrary加載DLL;

  )GetProcAddress獲得函數指針

  以上兩步得到了預加載函數的指針但是VB中沒有提供使用這個指針的方法我們可以通過一段匯編語言來完成函數指針的調用!

  )通過匯編語言把函數的所有參數壓入堆棧然後用Call待用函數指針就可以了

  實現以上功能的主要程序

  加載Dll

  LibAddr = LoadLibrary(ByVal user

  獲得函數指針

  ProcAddr = GetProcAddress(LibAddr ByVal MessageBoxA

  原型為MessageBox(hWnd lpText lpCaption uType)

  以下為Assembly部分

  push uType

  push lpCaption

  push lpText

  push hWnd

  call ProcAddr

  

  FreeLibrary LibAddr釋放空間

  嘿源碼天空夠簡單吧!下面是動態調用MessageBoxA的源代碼上面的步驟被封裝到RunDll函數中可放到模塊(CallAPIbyNamebas)中

  Dim s() As Byte s() As Byte

  Dim ret As Long

  s = StrConv(Hello~World vbFromUnicode)

  s = StrConv(VBNote vbFromUnicode)

  ret = RunDlluser MessageBoxA hwnd VarPtr(s)) VarPtr(s)) &)

  CallAPIbyNamebas中的源代碼

  Option Explicit

  Private Declare Function LoadLibrary Lib kernel Alias LoadLibraryA (ByVal lpLibFileName As String) As Long

  Private Declare Function GetProcAddress Lib kernel (ByVal hModule As Long ByVal lpProcName As String) As Long

  Private Declare Function CallWindowProc Lib User Alias CallWindowProcA (ByVal lpPrevWndFunc As Long ByVal hWnd As Long ByVal Msg As Long ByVal wParam As Long ByVal lParam As Long) As Long

  Private Declare Function FreeLibrary Lib kernel (ByVal hLibModule As Long) As Long

  Private Declare Sub CopyMemory Lib kernel Alias RtlMoveMemory (lpDest As Any lpSource As Any ByVal cBytes As Long)

  Public m_opIndex As Long 寫入位置

  Private m_OpCode() As Byte  Assembly 的OPCODE

  Public Function RunDll(LibFileName As String ProcName As String ParamArray Params()) As Long

  Dim hProc As Long

  Dim hModule As Long

  ReDim m_OpCode( + * UBound(Params)) 保留用來寫m_OpCode

  讀取API庫

  hModule = LoadLibrary(ByVal LibFileName)

  If hModule = Then

  MsgBox Library讀取失敗!

  Exit Function

  End If

  取得函數地址

  hProc = GetProcAddress(hModule ByVal ProcName)

  If hProc = Then

  MsgBox 函數讀取失敗! vbCritical

  FreeLibrary hModule

  Exit Function

  End If

  執行Assembly Code部分

  RunDll = CallWindowProc(GetCodeStart(hProc Params)

  FreeLibrary hModule 釋放空間

  End Function

  Private Function GetCodeStart(ByVal lngProc As Long ByVal arrParams As Variant) As Long

  以下為Assembly部分

  作用將函數的參數壓入堆棧

  Dim lngIndex As Long lngCodeStart As Long

  程序起始位址必須是的倍數

  VarPtr函數是用來取得變量的地址

  lngCodeStart = (VarPtr(m_OpCode()) Or &HF) +

  m_opIndex = lngCodeStart VarPtr(m_OpCode()) 程序開始的元素的位置

  前面部分以中斷點添滿

  For lngIndex = To m_opIndex

  m_OpCode(lngIndex) = &HCC int

  Next lngIndex

  以下開始放入所需的程序

  將參數push到堆棧

  由於是STDCall CALL 參數由最後一個開始放到堆棧

  For lngIndex = UBound(arrParams) To Step

  AddByteToCode &H push的機器碼為H

  AddLongToCode CLng(arrParams(lngIndex))  參數地址

  Next lngIndex

  call hProc

  AddByteToCode &HE call的機器碼為HE

  AddLongToCode lngProc VarPtr(m_OpCode(m_opIndex)) 函數地址 用call的定址

  結束所需的程序

  返回呼叫函數

  AddByteToCode &HC ret h

  AddByteToCode &H

  AddByteToCode &H

  GetCodeStart = lngCodeStart

  End Function

  Private Sub AddLongToCode(lData As Long)

  將Long類型的參數寫到m_OpCode中

  CopyMemory m_OpCode(m_opIndex) lData

  m_opIndex = m_opIndex +

  End Sub

  Private Sub AddIntToCode(iData As Byte)

  將Integer類型的參數寫道m_OpCode中

  CopyMemory m_OpCode(m_opIndex) iData

  m_opIndex = m_opIndex +

  End Sub

  Private Sub AddByteToCode(bData As Byte)

  將Byte類型的參數寫道m_OpCode中

  m_OpCode(m_opIndex) = bData

  m_opIndex = m_opIndex +

  End Sub


From:http://tw.wingwit.com/Article/program/net/201311/13062.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.