更新:2007 年 11 月
如果一个结构包含一些简单类型,则可以将该结构传递给本机函数。本机例程必须遵从 .NET Compact Framework 封装结构的方式。
假定有一个名为 DoRequest 的本机函数,它带有一个参数:一个指向结构的指针。此结构定义两个字段:
包含以 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,并通知运行库将字符串封送到 ANSI,因为托管代码中的所有字符串都是 Unicode 字符串。
在 .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 方法。必须使用一个中间 thunk 调用来包装 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 对象不会被封送。thunk 会包装本机 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;
}