DLL(Win32 API など) を実行時に動的ロードする。(LoadLibrary,GetProcAddress,FreeLibrary)

Win32APIを使用する場合はDLLImport属性を付けて使用したいAPIを事前に定義して使います。DllImport属性は使用したいDLLとのリンクがコンパイル時に設定されるためアプリ起動時にリンクを解決しようとします。(リンクを解決するというのは、DLLをメモリ上にロードし使用したい関数のエントリーポイントを決定することです。)これは、DLLとの通常のリンクの仕方ですが、リンクしたいDLLがシステムに存在しない場合や、使用したい関数が対象のDLLに存在しない場合、(OSのバージョンなどの違いで発生することが良くあります。)アプリはリンクに失敗し起動しません。

これに対処するためには、DLLの実行時読み込み(動的読み込みとも言います)を使用します。

実行時読み込みには、LoadLibrary,GetProcAddress,FreeLibraryの各Win32APIを使用します。アプリの起動時ではなく、コードの実行によってDLLとのリンクを解決することができるため、DLLが無い場合やDLLの中に使用したい関数が無い場合などでも、その部分だけ動かさずに処理を続行することができます。また、使用する直前までDLLのロードを遅らせたり、不要になったDLLをアンロードさせたりすることが出来るようになります。


Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click

Dim l As New DynamicLibraryLoader
Dim result As Boolean = l.Load("user32.dll")
If result = True Then

Try

Dim d As [Delegate] = l.GetDelegate("MessageBoxA", GetType(MessageBox))
If Not d Is Nothing Then

Dim m As MessageBox = CType(d, MessageBox)
m(IntPtr.Zero, "メッセージボックスのテストです", "こんにちは", 0)

End If

Finally
l.Free()

End Try

End If

End Sub

DynamicLibraryLoaderクラス


Imports System
Imports System.Runtime.InteropServices

Public Class DynamicLibraryLoader

_
Private Shared Function LoadLibrary(ByVal lpFileName As String) As IntPtr
End Function

_
Private Shared Function FreeLibrary(ByVal hModule As IntPtr) As Boolean
End Function

_
Private Shared Function GetProcAddress(ByVal hModule As IntPtr, ByVal lpProcName As String) As IntPtr
End Function

Private _libraryModule As IntPtr = IntPtr.Zero

Private _lastErrorNo As Integer = 0
Private _errorMessage As String = String.Empty

Public ReadOnly Property LastErrorNo() As Integer
Get
Return _lastErrorNo
End Get
End Property

Public ReadOnly Property ErrorMessage() As String
Get
Return _errorMessage
End Get
End Property

Public Function Load(ByVal fileName As String) As Boolean

_libraryModule = LoadLibrary(fileName)
If _libraryModule = IntPtr.Zero Then

Dim lastError As Integer = Marshal.GetHRForLastWin32Error
Dim ex As Exception = Marshal.GetExceptionForHR(lastError)

_lastErrorNo = lastError
_errorMessage = ex.Message

Return False

End If

Return True

End Function

Public Function GetDelegate(ByVal procName As String, ByVal delegateType As Type) As [Delegate]

If _libraryModule = IntPtr.Zero Then
Return Nothing
End If

Dim procPtr As IntPtr = GetProcAddress(_libraryModule, procName)
If procPtr = IntPtr.Zero Then

Dim lastError As Integer = Marshal.GetHRForLastWin32Error
Dim ex As Exception = Marshal.GetExceptionForHR(lastError)

_lastErrorNo = lastError
_errorMessage = ex.Message

Return Nothing

End If

Dim d As [Delegate] = Marshal.GetDelegateForFunctionPointer(procPtr, delegateType)
Return d

End Function

Public Function Free() As Boolean

If _libraryModule <> IntPtr.Zero Then

Dim result As Boolean = FreeLibrary(_libraryModule)
If result = False Then

Dim lastError As Integer = Marshal.GetHRForLastWin32Error
Dim ex As Exception = Marshal.GetExceptionForHR(lastError)

_lastErrorNo = lastError
_errorMessage = ex.Message

Return False

End If

End If

Return True

End Function

End Class