プラットフォーム呼び出しラッパーの例
更新 : 2007 年 11 月
構造体が単純な型を含む場合は、その構造体をネイティブ関数に渡すことができます。ネイティブ ルーチンは、.NET Compact Framework が構造体をパックする方法に準拠している必要があります。
1 つのパラメータ (構造体へのポインタ) を受け取るネイティブ関数 DoRequest について考えてみます。構造体には次の 2 つのフィールドが定義されています。
NULL で終わる ANSI 文字列を含む文字配列
整数
C++ の構造体は次のとおりです。
typedef struct
{
char *RequestName,
int Count,
} ALERT_REQUEST;
int DoAlertRequest(ALERT_REQUEST *pRequest);
これに対応する C# のマネージ構造体は次のとおりです。
struct AlertRequest
{
String RequestName;
int Count;
}
class AlertClass
{
[DLLImport("ALERT.DLL", EntryPoint="DoAlertRequest",
CharSet=CharacterSet.Ansi)]
public static extern int DoRequest(ref AlertRequest Req);
}
DllImportAttribute 属性は、ネイティブ メソッド呼び出しのメタデータに注釈を付けています。このクラスは、共通言語ランタイムに、DoRequest メソッドが ALERT.DLL にあることと、メソッドの名前が DoAllertRequest であることを通知し、マネージ コードのすべての文字列が Unicode 文字列であるため、文字列を ANSI にマーシャリングするように指定します。
.NET Framework での C++ によるこのメソッドの呼び出しは、次のようになります。
AlertRequest Request = new AlertRequest()
Request.RequestName = "beep";
Request.Count = 10;
AlertClass.DoRequest(ref Request);
.NET Framework の共通言語ランタイムは DoRequest 呼び出しを検出すると、動的に ALERT.DLL を読み込み、DoAlertRequest のアドレスを取得して、必要に応じて文字列を変換するアンマネージ構造体をビルドします。この構造体へのポインタをプッシュし、DoAlertRequest を呼び出します。埋め込み String オブジェクトが含まれるために、構造体へのポインタをそのまま渡すことはできません。
このような制約のために、ネイティブ DoRequest メソッドを直接呼び出すことはできません。その代わり、中間サンク呼び出しで DoRequest をラップする必要があります。C# コード例は次のとおりです。
class AlertClass
{
[DllImport("ALERT.DLL", EntryPoint="DoAlertRequestThunk")]
private static extern int DoRequestThunk(String RequestName, int Count);
public static int DoRequest(ref AlertRequst Req)
{
return DoRequestThunk(Req.RequestName, Req.Count);
}
}
AlertClass には、依然として .NET Framework のメソッドと同じシグネチャのメソッドが含まれています。.NET Compact Framework DoRequest は、プライベート ネイティブ ルーチンを呼び出すマネージ ルーチンです。構造体内の String オブジェクトはマーシャリングされないため、構造体のフィールドは、ネイティブ ルーチンの呼び出しで個別の引数に分割されます。サンクによって、ネイティブ DoRequest がラップされます。C++ の次のコード例に示すように、アンマネージ構造体がビルドされ、文字列の変換が実行されます。
int DoRequestThunk(wchar_t *RequestNameW, int Count)
{
ALERT_REQUEST Req;
int ReturnCode;
// CreateAnsiFromUnicodeString allocates and builds an ANSI
// version of the Unicode string.
Req.RequestName = CreateAnsiFromUnicodeString(RequestNameW);
if (Req.RequestName == NULL)
Return 0;
Req.Count = Count;
// This is the native DoRequest, not to be confused
// with the managed method of the same name.
ReturnCode = DoAlertRequest(&Req);
free(Req.RequestName)
return ReturnCode;
}