摘 自: http://lcx.cc/?i=489
【【請注意】】:在以下語法格式中,請注意 [函數名] 的【大小寫】!!! 靜態與動態比較: 靜態調用簡單,動態調用麻煩;靜態調用占用資源多,動態調用占用資源少;正所謂魚和熊掌不可兼得。 靜態調用定義: 就是常用的申明API,一個DLL庫里有很多的函數可供調用,把要用的申明即可。 比如:Public/Private Declare Function [函數名] Lib "DLL文件名" [Alias "別名"] (參數變量表) [As 返回值的數據類型] 示例:Private Declare Function Test Lib "dll.dll" (x As String) As String 當程序結束的時候系統回自動釋放DLL調用。 動態調用定義: 使用LoadLibery(DLL名),系統會檢查DLL是否調入內存。如果調入了,可直接調用DLL里的所有函數,沒有就會把DLL加入目標進程的進程空間。通過函數GetProcAddress確定函數入口地址,然后調用,后一種方法VB里不常用的。 靜態調用詳解: 制作好DLL之后,首先用Declare聲明語句在窗體級或模塊級或全局模塊的代碼聲明段進行聲明,將動態鏈接庫中的函數聲明到VB中,供VB程序調用。 語法格式1: Public/Private Declare Sub [函數名] Lib "DLL文件名" [Alias "別名"] (參數變量表) 語法格式2: Public/Private Declare Function [函數名] Lib "DLL文件名" [Alias "別名"] (參數變量表) [As 返回值的數據類型] 在聲明中首先用Declare關鍵字表示聲明DLL中的函數。在C語言中有的函數類型為VOID,它表示不具有返回值,則必須用關鍵字Sub將其聲明成過程。有的函數具有返回值,則必須用關鍵字Function將其聲明成函數,並且在聲明語句的最后要用AS關鍵字指明函數返回值的類型。 例如add.DLL在VB中就可以聲明為: Declare Function ADD Lib "c:\add.dll" (ByVal X AS Integer, ByVal Y AS Integer, ByVal filein as string) AS Integer 通過此聲明語句將函數ADD聲明到VB中,便可直接調用。 動態調用詳解: 首先調用API LoadLibaray 裝載dll,然后調用API GetProcAddress 得到dll的對應方法的地址。因為vb不像其他的有函數指針,在vb中聲明函數原形,怎樣把得到的函數地址賦給這個原形有些麻煩。 解決辦法1: Option Explicit '我們要調用沒有聲明的API(dll)的功能! Private Declare Function FreeLibrary Lib "kernel32" (ByVal hLibModule As Long) As Long '釋放LoadLibrary載入的動態鏈接庫,非零表示成功,零表示失敗。 Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long '載入指定動態鏈接庫,成功則返回庫模塊的句柄,零表示失敗。 Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long '檢索指定的動態鏈接庫(DLL)中的輸出庫函數地址(超找函數入口地址),成功則返回值是DLL中的輸出函數地址,失敗返回值是NULL。 Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Any, ByVal wParam As Any, ByVal lParam As Any) As Long '將消息信息傳送給指定的窗口過程。 Private Sub Form_Load() Dim LibHand As Long '載入的dll句柄 LibHand = LoadLibrary("user32") '將user32載入到內存。 CallWindowProc GetProcAddress(LibHand, "SetWindowTextA"), Me.hWnd, CStr(Now), ByVal 0&, ByVal 0& '調用SetWindowTextA函數功能 FreeLibrary LibHand '釋放映射庫的地址 End Sub 解決辦法2: 下面是動態調用MessageBoxA的源代碼,上面的步驟被封裝到RunDll32函數中,可放到模塊(CallAPIbyName.bas)中: Dim s1() As Byte, s2() As Byte Const hWnd = 0 Dim ret As Long s1 = StrConv("Hello~World", vbFromUnicode) s2 = StrConv("VBNote", vbFromUnicode) ret = RunDll32("user32", "MessageBoxA", hWnd, VarPtr(s1(0)), VarPtr(s2(0)), 0&) End Sub Public Function RunDll32(LibFileName As String, ProcName As String, ParamArray Params()) As Long Dim hProc As Long Dim hModule As Long ReDim m_OpCode(400 + 6 * UBound(Params)) '保留用來寫m_OpCode hModule = LoadLibrary(ByVal LibFileName) '讀取API庫 If hModule = 0 Then MsgBox "Library讀取失敗!" Exit Function End If hProc = GetProcAddress(hModule, ByVal ProcName) '取得函數地址 If hProc = 0 Then MsgBox "函數讀取失敗!", vbCritical FreeLibrary hModule Exit Function End If RunDll32 = CallWindowProc(GetCodeStart(hProc, Params), 0, 1, 2, 3) '執行Assembly Code部分 FreeLibrary hModule '釋放空間 End Function 解決辦法3: 在VB中嵌入匯編實現。loadlibary取得DLL,GetProcAddress取得函數地址,用VB嵌入匯編的寫法壓所需參數,CallWindowProc調用GetProcAddress返回的地址。