a我考网

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 99|回复: 1

[Visual Basic] 2012年计算机等级考试二级VB动态调用外部函数的方法(1)

[复制链接]
发表于 2012-7-31 22:10:12 | 显示全部楼层 |阅读模式
 导读:VB可以用Declare声明来调用标准DLL的外部函数,但是其局限性也很明显:利用Declare我们只能载入在设计时通过Lib和Alias字句指定的函数指针!而不能在运行时指定由我们自己动态载入的函数指针),不能用Declare语句来调用任意的函数指针。当我们想动态调用外部函数的时候,就必须考虑采用其他的辅助方法,来完成这个任务了。   在文章《VB真是想不到系列之三:VB指针葵花宝典之函数指针 》、《Matthew Curland的VB函数指针调用》、《利用动态创建自动化接口实现VB的函数指针调用》等文献中对此问题都进行了一定程度上的讨论,但是头绪都很繁琐,对我这样的菜鸟还有点深奥,在资料搜索过程中,找到通过在VB中调入汇编程序,比较简便的实现了这个功能,下面就是实现原理:
! n0 x! {" }. w! d3 l  1)使用LoadLibrary加载DLL;0 R( e7 q* S; P( T
  2)GetProcAddress获得函数指针;
7 L. v1 G4 g+ o' }" Y9 ~; K  以上两步得到了预加载函数的指针,但是VB中没有提供使用这个指针的方法。我们可以通过一段汇编语言,来完成函数指针的调用!
1 g  ]5 {+ i& J0 E/ x2 A7 k: Z  3)通过汇编语言,把函数的所有参数压入堆栈,然后用Call待用函数指针就可以了。- m8 w5 X6 o  ]
  实现以上功能的主要程序:! W- w& I/ [2 S9 C; r& _3 ~" {8 a
  ′加载Dll
- I3 p: ~5 d; U' O! b& C$ [* P1 `  LibAddr = LoadLibrary(ByVal "user32")8 N! G# ]0 O' e3 w, O# t
  ′获得函数指针
. L/ x8 r7 F; {0 ~( {  ProcAddr = GetProcAddress(LibAddr, ByVal "MessageBoxA")- d1 o0 X+ c& t- S
  ′原型为MessageBox(hWnd, lpText, lpCaption, uType)
* w6 p3 N# P1 n9 S4 n) I  ′---以下为Assembly部分---
6 m5 Q, }( w, e: @# k) z  push uType
8 E9 e% E2 w. f) s: c( v  push lpCaption
/ X* p1 _3 d& s, q) f) I1 y$ Q  push lpText
/ j, N0 E: G- H  x7 ~) Y5 Q  push hWnd  s) u, k, f+ n0 _2 S  k) \* |0 j
  call ProcAddr
' r& \  V: N" O( B1 a  ′--------------------8 m- E3 `/ E/ ^; X- o
* T) I  L2 N6 P9 f+ R4 y1 k+ D7 O
  FreeLibrary LibAddr′释放空间
回复

使用道具 举报

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

2012年计算机等级考试二级VB动态调用外部函数的方法(1)

</p>  嘿,够简单吧!下面是动态调用MessageBoxA的源代码,上面的步骤被封装到RunDll32函数中,可放到模块(CallAPIbyName.bas)中:
3 {6 q( Z- l" D( Y5 [% _  Dim s1() As Byte, s2() As Byte
6 \: S: H  a  {* `+ D+ n; s  Dim ret As Long4 }/ {2 B& N5 L6 N1 f, I8 p: w
  s1 = StrConv("Hello~World", vbFromUnicode)
' z' ^; f8 t' y& H: ~* u  Z  s2 = StrConv("VBNote", vbFromUnicode)
4 s# s* ]6 b+ u' \( `" ]% ?1 S0 G, N  ret = RunDll32("user32", "MessageBoxA", hwnd, VarPtr(s1(0)), VarPtr(s2(0)), 0&)
: q3 `) B, Q: g4 m  CallAPIbyName.bas中的源代码:" r/ f6 c! ^; d, E+ D. X( p6 p0 b
  Option Explicit
+ s8 t6 \$ n+ E, n  C& M  Private Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Long
4 R9 c' a0 H& q1 [9 R  Private Declare Function GetProcAddress Lib "kernel32" (ByVal hModule As Long, ByVal lpProcName As String) As Long8 N, Y6 D: p# Z( e
  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
$ u5 _6 B$ k$ [- Z7 }2 d  Private Declare Function FreeLibrary Lib "kernel32" (ByVal hLibModule As Long) As Long: s8 J# r  D. k
  Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpDest As Any, lpSource As Any, ByVal cBytes As Long)
  g2 Y1 w/ Q, i  d  T8 A$ g# o  X  [  Public m_opIndex As Long ′写入位置
. e! @9 c7 O+ |6 [1 h  Private m_OpCode() As Byte ′Assembly 的OPCODE
/ D4 f6 Z/ D# N2 z  Public Function RunDll32(LibFileName As String, ProcName As String, ParamArray Params()) As Long
# ?4 r& r: Q" o) e% E3 L  Dim hProc As Long  `" y3 k6 w$ C9 ?
  Dim hModule As Long/ n. h. }2 ^- n0 i9 W
  ReDim m_OpCode(400 + 6 * UBound(Params)) ′保留用来写m_OpCode
7 I% A6 l2 [( I+ S8 L( d  e1 B  ′读取API库% S/ }+ V7 b; m- C1 ~; U
  hModule = LoadLibrary(ByVal LibFileName)
5 z! v; z+ C; ^: b8 c  If hModule = 0 Then0 M3 {# g! M- H4 l7 |
  MsgBox "Library读取失败!"
2 v0 |3 x# v/ q  Exit Function! j0 e" e7 ]9 O% C6 ~- s" o
  End If. I/ J% e3 h# n$ p/ u/ C
  ′取得函数地址( ^+ g  g& s6 @- d+ o5 d* b1 O
  hProc = GetProcAddress(hModule, ByVal ProcName)
4 o. {  d" B% D8 m8 r, P  If hProc = 0 Then
6 R: Q# G, m: u: H+ r  MsgBox "函数读取失败!", vbCritical0 Y6 ?7 M7 r  ~& Z3 ?- r
  FreeLibrary hModule
) @$ B7 V" \2 f  Exit Function/ f5 m! s4 a* ~5 G* f1 m; ?
  End If
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-5-4 12:40 , Processed in 0.761456 second(s), 23 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

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