动态载入类,可设置为任何委托原型,可以做一个自己的插件系统。
Imports System.Runtime.InteropServices
Public Class ClsoAPI
    ' 载入动态链接库
    Private Declare Function LoadLibrary Lib "kernel32.dll" Alias "LoadLibraryA" (ByVal path As String) As IntPtr
    ' 获取函数指针地址
    Private Declare Function GetProcAddress Lib "kernel32.dll" (ByVal libPtr As IntPtr, ByVal funcName As String) As IntPtr
    ' 释放动态链接库
    Private Declare Function FreeLibrary Lib "kernel32.dll" (ByVal libPtr As IntPtr) As Boolean
    Dim hLib As IntPtr '存储链接库指针
    Sub New(ByVal dllpath As String)
        hLib = LoadLibrary(dllpath)
        If hLib = 0 Then Throw New Exception("载入库错误!")
    End Sub
    Protected Overrides Sub Finalize()
        FreeLibrary(hLib)
        MyBase.Finalize()
    End Sub
    Function GetProc(ByVal ApiName As String, ByVal DelegateT As Type) As [Delegate]
        Dim api = GetProcAddress(hLib, ApiName)
        If api = 0 Then Throw New Exception("载入函数错误!")
        Return Marshal.GetDelegateForFunctionPointer(api, DelegateT) '将非托管函数指针转换为委托
    End Function
End Class
上面的类型封装了动态载入API的过程,在构建这个类型时,我们需要先传递动态链接库的路径,然后调用GetProc来获取API的委托包装。
GetProc的两个参数分别为API函数在库中的名称和委托函数原型的类型信息,类型信息可以用Vb.NET的GetType关键字获得,具体的示例代码如下。

建立一个窗体,拖放两个按钮,添加下面的代码:
Public Class frmMain
    ' 弹出对话框的委托原型
    Delegate Function MessageBox(ByVal hwnd As Int32, ByVal lpText As String, ByVal lpCaption As String, ByVal wType As Int32) As Int32
    ' 关于对话框的委托原型
    Delegate Function ShellAbout(ByVal hwnd As Int32, ByVal szApp As String, ByVal szOtherStuff As String, ByVal hIcon As Int32) As Int32
    
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim c As New ClsoAPI("user32.dll")
        Dim m As MessageBox = c.GetProc("MessageBoxA", GetType(MessageBox))
        Dim i = m.Invoke(Me.Handle, "文本", "标题", 1)
        MsgBox(i)
    End Sub
    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Dim c As New ClsoAPI("shell32")
        Dim sa As ShellAbout = c.GetProc("ShellAboutA", GetType(ShellAbout))
        sa.Invoke(Me.Handle, "CLSO API", "版权所有,翻版不究,盗版可耻!", Me.Icon.Handle)
    End Sub
End Class
可以看出来,在动态调用API时,首先我们必须要知道我们调用的API的原型,然后在代码中声明这个原型的委托,才能动态调用这个API。
上面的示例我们分别调用了一个弹出对话框和微软的关于对话框,其他的API也是相似的调用方法。