ネイティブDLLやCOMを使う
.NET環境に移行しても、昔からあるネイティブDLLやCOMを利用したくなる事が時々ありますが、その場合に知っていたほうが良いこと等を書いていきます。
(1) 文字列の受け渡し
CharSetを適切に指定すれば、String型でやりとり可能です。WinAPIでAnsi版、Unicode版両方がある場合でも自動的に解釈してくれます。(紛らわしいので、明示的に指定するに越したことはないのですが。)
'この例だとUnicode版のLoadLibraryWを呼び出してくれる Public Shared Declare Unicode Function LoadLibrary Lib "kernel32" (lpFileName As String) As IntPtr
(2) 構造体のアドレスを渡す場合
LayoutKind.Sequentialで宣言した構造体の参照を渡してあげれば、勝手にマーシャリングしてくれます。2byte以下のメンバを含む構造体はPack値に注意しましょう。
Imports System Imports System.Runtime.CompilerServices Imports System.Runtime.InteropServices Public Class Form1 <StructLayout(LayoutKind.Sequential, Pack:=4)> Private Structure RECT Public left As Integer Public top As Integer Public right As Integer Public bottom As Integer End Structure Private Declare Auto Function GetDesktopWindow Lib "user32.dll" () As IntPtr Private Declare Auto Function GetWindowRect Lib "user32.dll" (ByVal hwnd As IntPtr, <Out()> ByRef rc As RECT) As Integer Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click Dim rc As New RECT GetWindowRect(GetDesktopWindow(), rc) MsgBox(rc.right & " " & rc.bottom) End Sub End Class
(3) COMインターフェースのポインタを受け取る場合
こちらも、COMインターフェースの宣言をきちんとしてあげれば、インターフェースの参照を渡してあげればOKです。Object型で受けて後からキャストすることも可能です。下は、IMallocでのメモリ確保&解放の例です。
Imports System Imports System.Runtime.CompilerServices Imports System.Runtime.InteropServices Public Class Form1 <ComImport()> _ <InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _ <Guid("00000002-0000-0000-C000-000000000046")> _ Private Interface IMalloc <MethodImpl(MethodImplOptions.PreserveSig)> Function Alloc(ByVal cb As UInt32) As IntPtr <MethodImpl(MethodImplOptions.PreserveSig)> Function Realloc(ByVal pv As IntPtr, ByVal cb As UInt32) As IntPtr <MethodImpl(MethodImplOptions.PreserveSig)> Sub Free(ByVal pv As IntPtr) <MethodImpl(MethodImplOptions.PreserveSig)> Function GetSize(ByVal pv As IntPtr) As UInt32 <MethodImpl(MethodImplOptions.PreserveSig)> Function DidAlloc(ByVal pv As IntPtr) As UInt32 <MethodImpl(MethodImplOptions.PreserveSig)> Sub HeapMinimize() End Interface Private Declare Sub CoGetMalloc Lib "ole32.dll" (ByVal dwMemContext As Integer, <Out()> ByRef malloc As IMalloc) Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click Dim malloc As IMalloc = Nothing CoGetMalloc(1, malloc) Dim ptr As IntPtr = malloc.Alloc(1000) Dim size As UInt32 = malloc.GetSize(ptr) MsgBox("PtrAddress:0x" & Hex(ptr.ToInt64) & " PtrSize:" & size) malloc.Free(ptr) size = malloc.GetSize(ptr) Marshal.ReleaseComObject(malloc) malloc = Nothing End Sub End Class
(4) コールバック関数(関数ポインタ)を指定する場合
コールバック関数と同じ引数を持つDelegateを作成して渡せばOKです。Marshal.GetFunctionPointerForDelegateを使えば、関数ポインタも取得出来ます。下は、EnumChildWindowsの使用例です。
Imports System.Collections.Generic Imports System.Runtime.InteropServices Public Class EnumWindowSample Private Delegate Function EnumWindowsDelegate(hWnd As IntPtr, lparam As IntPtr) As Boolean Private Declare Function EnumChildWindows Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal lpEnumFunc As EnumWindowsDelegate, ByVal lparam As IntPtr) As Integer Private Declare Function EnumChildWindows Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal lpEnumFunc As IntPtr, ByVal lparam As IntPtr) As Integer Private _ListHWnd As New List(Of IntPtr) 'Delegateを渡す Public Function GetChildWindows1(ByVal hWndOwner As IntPtr) As List(Of IntPtr) _ListHWnd.Clear() EnumChildWindows(hWndOwner, New EnumWindowsDelegate(AddressOf EnumWindowsProc), IntPtr.Zero) Return _ListHWnd End Function '関数ポインタを取得して渡す Public Function GetChildWindows2(ByVal hWndOwner As IntPtr) As List(Of IntPtr) _ListHWnd.Clear() Dim pEnumWindowsProc As IntPtr = Marshal.GetFunctionPointerForDelegate(New EnumWindowsDelegate(AddressOf EnumWindowsProc)) EnumChildWindows(hWndOwner, pEnumWindowsProc, IntPtr.Zero) Return _ListHWnd End Function 'ウィンドウ列挙コールバック関数 Private Function EnumWindowsProc(hWnd As IntPtr, lParam As IntPtr) As Boolean _ListHWnd.Add(hWnd) Return True End Function End Class