电脑故障

位置:IT落伍者 >> 电脑故障 >> 浏览文章

VB动态调用外部函数的方法


发布日期:2021/1/16
 

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

上一篇:同时找到数组中的最小值和最大值

下一篇:Silverlight插件安装说明