VB.NETでAPI関数を定義する方法を2通りある。
[関数スコープ] Declare [文字セット] Function(Sub) API関数名 _ Lib "DLLファイル名" _ [Alias "エイリアス名"](引数) _ [As 戻り値のデータ型]
例:GetWindowText API関数の宣言
Public Shared Declare Auto Function GetWindowText Lib "user32" ( _ ByVal hWnd As IntPtr, _ ByVal lpString As StringBuilder, _ ByVal nMaxCount As Integer) _ As Integer
[補講]他のクラスから呼び出される可能性があるときは、Shared修飾子を付ける。 ◇
Private,Publicなどの関数のスコープを決める修飾子を指定する。
APIに文字列を渡す際の文字コードを指定する。
API関数の名称を記述する。DLL内で定義されているAPI関数名と異なる名称を指定することもできるが、その場合はエイリアス名でDLL内での関数の名称を指定する必要がある。
宣言するAPI関数を提供しているDLLのファイル名を記述する。
システムフォルダや呼び出す実行ファイルと同じフォルダに存在しないDLLの場合は、フルパスで指定する必要がある。
呼び出すAPI関数のエイリアス名を記述する。
API名とエイリアス名が同じ場合には省略可能である。
VB.NETではデフォルトの引数の参照方法がByValの値渡しなので、参照渡しをしたい場合はByRefを指定する。
API実行後の戻り値のデータ型を記述する。
VB.NETの機能の1つである属性とは、クラスのメンバ・メソッド・関数などに追加情報を持たせる機能のことである。ここで使うDllImport属性は、定義するAPIに合わせた引数を持つ空の関数に適用することで、外部のDLLで定義された関数を呼び出す。
書式は次の通りである。
<DllImport("'''DLL名'''", EntryPoint:="'''API関数名'''", CharSet:='''Charset''', ExactSpelling:='''boolean''')> '''関数定義'''
例:GetWindowText API関数の宣言
Imports System.Runtime.InteropServices <DllImport("user32", EntryPoint:="GetWindowText", CharSet:=CharSet.Auto)> _ Public Shared Function GetWindowText( _ ByVal hWnd As IntPtr, _ ByVal lpString As StringBuilder, _ ByVal nMaxCount As Integer) _ As Integer End Function
APIに文字列を渡す際の文字コードを指定する。
EntryPointで指定したAPI関数のみを呼び出すかどうかを指定する。
Falseの場合、CharSetで指定した文字コードにしたがい、○○A,○○Wを呼び出そうと試みる。省略した場合にはFalse扱いになる。
VB.NETでAPI関数を定義する際には、引数や戻り値の型、構造体やポインタの扱いに注意が必要である。
次にSDKの型とVB.NETの型の対応表を示す。
SDK | VB.NET |
INT | Integer |
BYTE | Byte |
BOOL | Boolean |
UINT | Uint32 |
SHORT | Short |
WORD | Short |
DWORD | Uint32 |
FLOAT | Single |
CHAR | Char |
WCHAR | Char |
LPWSTR | String(StringBuilder) |
LPTWSTR | String(StringBuilder) |
LPSTR | String(StringBuilder) |
LPCSTR | String(StringBuilder) |
LPCWSTR | String(StringBuilder) |
LPCTSTR | String(StringBuilder) |
HINSTANCE | IntPtr |
HANDLE | IntPrt |
HWND | IntPtr(Form.Handle) |
HDC | IntPtr |
HGDIOBJ | IntPtr |
GDIオブジェクト | IntPtr |
WPARAM | Integer |
LPARAM | Integer |
LRESULT | Integer |
文字列の扱いで注意すべき点がある。VB.NETからAPIへ文字列を渡す場合はString型を使えばよい。なぜならば内部ではUnicodeとして処理されるが、VB.NETでは関数の呼び出し時に文字コードを自動的に変換してくれるからである。
一方、VB.NETがAPIから文字列を受け取る場合はString型でもうまくいかない。なぜならば、.NET FrameworkのStytem.Stringクラスは一度初期化した文字列は変更されないという性質を持つからである。そこで、String型ではなく、System.Text.StringBuilderクラスを使う。このクラスはString型と同様に文字列を扱うことができ、宣言後にも値を変更できるので、APIから文字列を受け取ることができるのである。
Dim s As System.Text.StringBuilder = New System.Text.StringBuilder(1024)
もし、String型の変数やコントロールのTextプロパティにStringBuilder型の値(文字列)を代入させたい場合は、ToStringメソッドを使えばよい。
Form1.Text = s.ToString
VB.NETでの構造体は、最適化のためにメンバの並びが変わることがある。一方、APIではメンバの並びは定義した順に並んでいる必要がある。そのため、単純に構造体を渡してしまうとエラーになってしまうことがある。
そこで、構造体の定義において、<StructLayout>属性を付けてメンバの並びを固定化する必要がある。
構造体の代わりにクラスを用いることもできる。例えば、構造体は値型であり、構造体をNothingに指定すると、そのメンバがデフォルト値に初期化される。