调用API的SDK相关知识:传递结构
2006-09-12 16:40
429 查看
许多非托管函数需要您将结构(Visual Basic
中的用户定义类型)的成员或在托管代码中定义的类成员作为参数传递给函数。在使用平台调用将结构或类传递到非托管代码时,必须提供用来保留原始布局和对齐方式的附加信息。本主题将介绍
StructLayoutAttribute
属性,它用于定义格式化类型。对于托管结构和类,您可以从 LayoutKind 枚举提供的若干可预知的布局行为中进行选择。
本主题中提供的概念的核心是结构类型和类类型之间的重要区别。结构是值类型,类是引用类型 -
类始终提供至少一级内存间接寻址(指向某一值的指针)。因为非托管函数经常要求间接寻址,所以这一区别是十分重要的,如下表中第一列的签名所示。其余列中的托管结构和类声明显示在声明中可以调整的间接寻址级别的程度。
该表描述用于平台调用声明的以下原则:
在非托管函数不要求任何间接寻址时使用按值传递的结构。
在非托管函数要求一级间接寻址时使用按引用传递或按类传递的结构。
在非托管函数要求二级间接寻址时使用按引用传递的类。
结构,并将这些类型作为参数传递给 User32.dll 文件中的 PtInRect 函数。PtInRect
具有以下非托管签名:
请注意,由于函数需要指向 RECT 类型的指针,必须通过引用来传递 Rect 结构。
GetSystemTime。GetSystemTime 具有以下非托管签名:
与值类型不同,类始终具有至少一级间接寻址。
中的用户定义类型)的成员或在托管代码中定义的类成员作为参数传递给函数。在使用平台调用将结构或类传递到非托管代码时,必须提供用来保留原始布局和对齐方式的附加信息。本主题将介绍
StructLayoutAttribute
属性,它用于定义格式化类型。对于托管结构和类,您可以从 LayoutKind 枚举提供的若干可预知的布局行为中进行选择。
本主题中提供的概念的核心是结构类型和类类型之间的重要区别。结构是值类型,类是引用类型 -
类始终提供至少一级内存间接寻址(指向某一值的指针)。因为非托管函数经常要求间接寻址,所以这一区别是十分重要的,如下表中第一列的签名所示。其余列中的托管结构和类声明显示在声明中可以调整的间接寻址级别的程度。
非托管签名 | 托管声明: 无间接寻址 struct MyStruct(...); | 托管声明: 一级间接寻址 class MyStruct(...); |
---|---|---|
DoWork(MyStruct x); 要求零级间接寻址。 | DoWork(ByVal x As MyStruct) 增加零级间接寻址。 | 不可能,因为已有一级间接寻址。 |
DoWork(MyStruct* x); 要求一级间接寻址。 | DoWork(ByRef x As MyStruct) 增加一级间接寻址。 | DoWork(ByVal x As MyStruct) 增加零级间接寻址。 |
DoWork(MyStruct** x); 要求二级间接寻址。 | 不可能,因为不能使用 ByRef ByRef。 | DoWork(ByRef x As MyStruct) 增加一级间接寻址。 |
在非托管函数不要求任何间接寻址时使用按值传递的结构。
在非托管函数要求一级间接寻址时使用按引用传递或按类传递的结构。
在非托管函数要求二级间接寻址时使用按引用传递的类。
声明和传递结构
以下示例将显示如何在托管代码中定义Point和
Rect
结构,并将这些类型作为参数传递给 User32.dll 文件中的 PtInRect 函数。PtInRect
具有以下非托管签名:
BOOL PtInRect(const RECT *lprc, POINT pt);
请注意,由于函数需要指向 RECT 类型的指针,必须通过引用来传递 Rect 结构。
[Visual Basic] Imports System.Runtime.InteropServices <StructLayout(LayoutKind.Sequential)> Public Structure Point Public x As Integer Public y As Integer End Structure Public Structure <StructLayout(LayoutKind.Explicit)> Rect <FieldOffset(0)> Public left As Integer <FieldOffset(4)> Public top As Integer <FieldOffset(8)> Public right As Integer <FieldOffset(12)> Public bottom As Integer End Structure Class Win32API Declare Auto Function PtInRect Lib "user32.dll" _ (ByRef r As Rect, p As Point) As Boolean End Class
[C#] using System.Runtime.InteropServices; [StructLayout(LayoutKind.Sequential)] public struct Point { public int x; public int y; } [StructLayout(LayoutKind.Explicit)] public struct Rect { [FieldOffset(0)] public int left; [FieldOffset(4)] public int top; [FieldOffset(8)] public int right; [FieldOffset(12)] public int bottom; } class Win32API { [DllImport("User32.dll")] public static extern bool PtInRect(ref Rect r, Point p); }
声明和传递类
只要类具有固定的成员布局,就可以将类的成员传递给非托管的 DLL 函数。以下示例将说明如何将MySystemTime类的成员(按连续的顺序定义)传递给 User32.dll 文件中的
GetSystemTime。GetSystemTime 具有以下非托管签名:
void GetSystemTime(SYSTEMTIME* SystemTime);
与值类型不同,类始终具有至少一级间接寻址。
[Visual Basic] Imports System.Runtime.InteropServices Imports Microsoft.VisualBasic <StructLayout(LayoutKind.Sequential)> Public Class MySystemTime Public wYear As Short Public wMonth As Short Public wDayOfWeek As Short Public wDay As Short Public wHour As Short Public wMinute As Short Public wSecond As Short Public wMiliseconds As Short End Class Public Class Win32 Declare Auto Sub GetSystemTime Lib "Kernel32.dll"(sysTime _ As MySystemTime) Declare Auto Function MessageBox Lib "User32.dll"(hWnd As Integer, _ txt As String, caption As String, Typ As Integer) As Integer End Class Public Class TestPlatformInvoke Public Shared Sub Main() Dim sysTime As New MySystemTime() Win32.GetSystemTime(sysTime) Dim dt As String dt = "System time is:" & ControlChars.CrLf & _ "Year: " & sysTime.wYear & _ ControlChars.CrLf & "Month: " & sysTime.wMonth & _ ControlChars.CrLf & "DayOfWeek: " & sysTime.wDayOfWeek & _ ControlChars.CrLf & "Day: " & sysTime.wDay Win32.MessageBox(0, dt, "Platform Invoke Sample", 0) End Sub End Class
[C#] [StructLayout(LayoutKind.Sequential)] public class MySystemTime { public ushort wYear; public ushort wMonth; public ushort wDayOfWeek; public ushort wDay; public ushort wHour; public ushort wMinute; public ushort wSecond; public ushort wMilliseconds; } class Win32API { [DllImport("Kernel32.dll")] public static extern void GetSystemTime(MySystemTime st); } 现在才知道,原来调用时还可以传类,而且在API中要求为二级指针时还必需按引用传递类(ref),在一级指针时可以按引用传调结构,而又因为 指向类的变量本身就是引用,所以要按值传送指向类的变量.而只有在API为非指针时才能且只能使用结构传递. 另外,只有类才完全按声明定义顺序的.结构需要用LayoutKind指明,具体还不清楚,需要继续学习.
相关文章推荐
- 调用API的SDK相关知识:实现回调函数.
- 调用API的SDK相关知识:实现回调函数.
- 积累:SDK/API等相关知识
- SDK/API等相关知识
- java后台调用接口并且传递相关参数
- Symbian编程总结-网络与通信-套接字(1)-套接字体系结构与相关API
- AJAX跨域调用相关知识-CORS和JSONP
- 关于stack 以及相关的寄存器的知识(x86 结构)
- 无线电台、无线网桥、网络结构相关知识总结
- 探讨.get .post .ajax ztree 还有后台servlet传递数据的相关知识
- Unix的文件系统的内部结构,主要是超级块、inode相关知识
- 【Android】【API】Android SDK API 层次结构
- 关于API与SDK的一些小知识
- html5 之 canvas 相关知识(三)API-strokeStyle-shadow相关
- 算法与数据结构之树形结构的相关知识,简单易懂。
- delphi xe 之路(28)Android SDK API 层次结构
- Linux 字符设备驱动结构(一)—— cdev 结构体、设备号相关知识解析
- 根据线程安全的相关知识,分析以下代码,当调用test方法时i>10时是否会引起死锁?并简要说明理由。
- C#调用C++的dll关于复杂结构的参数传递
- 友盟推送 .NET (C#) 服务端 SDK rest api 调用库