a我考网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 114|回复: 1

[Visual Basic] VB如何动态调用外部函数的方法(1)

[复制链接]
发表于 2012-7-31 22:10:12 | 显示全部楼层 |阅读模式
导读:VB可以用Declare声明来调用标准DLL的外部函数,但是其局限性也很明显:利用Declare我们只能载入在设计时通过Lib和Alias字句指定的函数指针!而不能在运行时指定由我们自己动态载入的函数指针),不能用Declare语句来调用任意的函数指针。当我们想动态调用外部函数的时候,就必须考虑采用其他的辅助方法,来完成这个任务了。   在文章《VB真是想不到系列之三:VB指针葵花宝典之函数指针 》、《Matthew Curland的VB函数指针调用》、《利用动态创建自动化接口实现VB的函数指针调用》等文献中对此问题都进行了一定程度上的讨论,但是头绪都很繁琐,对我这样的菜鸟还有点深奥,在资料搜索过程中,找到通过在VB中调入汇编程序,比较简便的实现了这个功能,下面就是实现原理:
/ ?  I$ _7 X4 |( ^  1)使用LoadLibrary加载DLL;7 S6 B, i4 j+ j7 O
  2)GetProcAddress获得函数指针;( \( }: ~. C; D1 J% E! R" C
  以上两步得到了预加载函数的指针,但是VB中没有提供使用这个指针的方法。我们可以通过一段汇编语言,来完成函数指针的调用!
) `$ ?) H: B0 o9 e+ L+ V+ C  3)通过汇编语言,把函数的所有参数压入堆栈,然后用Call待用函数指针就可以了。7 r$ ^( O6 i+ P/ K% C3 @6 _
  实现以上功能的主要程序:
2 Q. G% B5 F3 r! b* v6 a  ′加载Dll
$ K9 }1 e; o- Z! v8 j  LibAddr = LoadLibrary(ByVal "user32")8 x3 j' _$ Y; n
  ′获得函数指针
4 r/ |7 q9 I5 |' }  ProcAddr = GetProcAddress(LibAddr, ByVal "MessageBoxA")
9 G  q0 [6 l& w4 v5 m  ′原型为MessageBox(hWnd, lpText, lpCaption, uType)
3 q- m1 n8 Z4 H/ S6 E0 b  ′---以下为Assembly部分---
, `$ `3 e! H# o( t+ P  push uType8 O& t% c. U! N
  push lpCaption
# I0 s! j9 F3 p) v- p, z  push lpText# m, p) I9 h1 j5 I7 p. _5 w
  push hWnd: [2 y+ \9 ?& f! P
  call ProcAddr* f' B: @, L: W9 W2 `/ v% ]
  ′--------------------
# Z6 |8 k5 h) g# V) _' \% E  FreeLibrary LibAddr′释放空间
2 S5 H4 g; H4 d- F3 g2 M  嘿,够简单吧!下面是动态调用MessageBoxA的源代码,上面的步骤被封装到RunDll32函数中,可放到模块(CallAPIbyName.bas)中:* s9 r1 ^7 G* z+ Q' C
  Dim s1() As Byte, s2() As Byte1 ^: T- k; y' ~$ f" ~
  Dim ret As Long, t1 D, s( H9 S: c5 \, f
  s1 = StrConv("Hello~World", vbFromUnicode)
# @9 h  |) a5 c! c" ]. }  s2 = StrConv("VBNote", vbFromUnicode)
: o" {: y% \' g* R1 R3 {9 X; B) L2 j& s1 ~% Y5 q0 V' G* b
  ret = RunDll32("user32", "MessageBoxA", hwnd, VarPtr(s1(0)), VarPtr(s2(0)), 0&)
回复

使用道具 举报

 楼主| 发表于 2012-7-31 22:10:13 | 显示全部楼层

VB如何动态调用外部函数的方法(1)

</p>  CallAPIbyName.bas中的源代码:* ]4 v) r9 s2 f: j
  Option Explicit
! W) J% D7 v$ u5 m7 u9 o  V  Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long7 ^' C7 j4 Q" K  ~( m- f  V! X
  Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long* I9 ^5 m$ ]/ h: Y9 E/ g3 x
  Private Declare Function CallWindowProc Lib "User32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
% A: M' }; i! ~2 r5 j# Q5 h7 R0 a  Private Declare Function FreeLibrary Lib "kernel32" (ByVal hLibModule As Long) As Long
4 T+ w6 P' a9 [& w( x; \# ^  Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpDest As Any, lpSource As Any, ByVal cBytes As Long)  C5 v7 P% ^/ u7 o
  Public m_opIndex As Long ′写入位置
2 s& y; g9 Y$ `7 n  Private m_OpCode() As Byte ′Assembly 的OPCODE
) \- h3 B' ]) r. [. ^' `  Public Function RunDll32(LibFileName As String, ProcName As String, ParamArray Params()) As Long
" w) C1 D% }7 W- E* w8 l  J  Dim hProc As Long
' {5 C+ P& ^$ z* \3 N2 [' t2 N  Dim hModule As Long
/ g/ _1 X6 N4 z- M) v6 V& Y$ q  ReDim m_OpCode(400 + 6 * UBound(Params)) ′保留用来写m_OpCode
7 y, e9 a& g; J' |( p2 ^  ′读取API库
# Q# X! R3 n# }) B1 K  hModule = LoadLibrary(ByVal LibFileName)' z) |$ C0 V  g) T2 d" o
  If hModule = 0 Then" M1 m" a( S2 G' k4 a( ^
  MsgBox "Library读取失败!"
' ^; L; R" M6 A5 |. F  Exit Function
0 ^* I) E! a4 V# T+ M/ q  End If7 Z* U6 b( n4 S) w) i8 r. x
  ′取得函数地址
5 _& e6 s7 D+ [  ^/ I  hProc = GetProcAddress(hModule, ByVal ProcName)
  s4 p; y" Z2 y- M( N  l" ~  If hProc = 0 Then+ A1 V& d' D/ |. Z" O+ X6 e6 P0 g
  MsgBox "函数读取失败!", vbCritical
; d' \; D& ^  L7 d) r  l' L  FreeLibrary hModule
0 m0 r; x( k/ J' W  Exit Function
; a/ H: n) q/ i! k. M  End If
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Woexam.Com ( 湘ICP备18023104号 )

GMT+8, 2024-5-4 11:48 , Processed in 0.278080 second(s), 23 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表