平台调用包装示例

更新: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;
}

请参见

其他资源

平台调用支持