下表列出了在 Win32 API(在 Wtypes.h 中列出)和 C 样式函数中使用的数据类型。许多非托管库包含将这些数据类型作为参数传递并返回值的函数。第三列列出了在托管代码中使用的相应的 .NET Framework 内置值类型或类。某些情况下,您可以用大小相同的类型替换此表中列出的类型。
Wtypes.h 中的非托管类型
非托管 C 语言类型
托管类名
说明
HANDLE
void*
System.IntPtr
在 32 位 Windows 操作系统上为 32 位,在 64 位 Windows 操作系统上为 64 位。
BYTE
unsigned char
System.Byte
8 位
SHORT
short
System.Int16
16 位
WORD
unsigned short
System.UInt16
16 位
INT
int
System.Int32
32 位
UINT
unsigned int
System.UInt32
32 位
LONG
long
System.Int32
32 位
BOOL
long
System.Int32
32 位
DWORD
unsigned long
System.UInt32
32 位
ULONG
unsigned long
System.UInt32
32 位
CHAR
char
System.Char
用 ANSI 修饰。
LPSTR
char*
System.String 或 System.Text.StringBuilder
用 ANSI 修饰。
LPCSTR
Const char*
System.String 或 System.Text.StringBuilder
用 ANSI 修饰。
LPWSTR
wchar_t*
System.String 或 System.Text.StringBuilder
用 Unicode 修饰。
LPCWSTR
Const wchar_t*
System.String 或 System.Text.StringBuilder
用 Unicode 修饰。
FLOAT
Float
System.Single
32 位
DOUBLE
Double
System.Double
64 位
如何在调用API时传递复杂参数:封装类、结构和联合
类和结构在 .NET Framework 中是类似的。它们都可以具有字段、属性和事件。它们也有静态和非静态方法。一个显著区别是结构属于值类型而类属于引用类型。
结构:
比如一个常用函数,用于获取日期时间的,原始声明如下:
VOID GetSystemTime(LPSYSTEMTIME lpSystemTime);
这个方法位于Kernel32.dll类库中,这个方法需要一个SYSTEMTIME的结构,其原始声明如下:
typedef struct _SYSTEMTIME {
WORD wYear;
WORD wMonth;
WORD wDayOfWeek;
WORD wDay;
WORD wHour;
WORD wMinute;
WORD wSecond;
WORD wMilliseconds;
} SYSTEMTIME, *PSYSTEMTIME;
根据C#中简单数据类型与C/C++中数据类型的对应关系,我们可以完成如下代码:
public struct SystemTime
{
public ushort wYear;
public ushort wMonth;
public ushort wDayOfWeek;
public ushort wDay;
public ushort wHour;
public ushort wMinute;
public ushort wSecond;
public ushort wMilliseconds;
}
对上面的API方法的调用声明如下:
[DllImport("kernel32.dll", EntryPoint = "SetSystemTime")]
public static extern void GetSystemTime(
SystemTime systemTime
);
在默认情况下,上面的方法将SystemTime类In/Out 参数进行传递。必须用 InAttribute 和 OutAttribute 属性声明该参数,因为作为引用类型的类在默认情况下将作为输入参数进行传递。为使调用方接收结果,必须显式应用这些方向属性,如ref或者out。
另外,我们还需要指定结构在内存中的布局,这个我们可以在声明结构时加以StructLayout属性来指明。而StructLayout属性需要一个layoutKind的枚举值。它有如下几个值:
在本例中,使用Sequential就行了。上面的C#结构描述修正如下:
[StructLayout(LayoutKind.Sequential)]
public struct SystemTime
{
public ushort wYear;
public ushort wMonth;
public ushort wDayOfWeek;
public ushort wDay;
public ushort wHour;
public ushort wMinute;
public ushort wSecond;
public ushort wMilliseconds;
}
当然如果想声明成Explicit也是可以的,如下:
[StructLayout(LayoutKind.Explicit, Size=16, CharSet=CharSet.Ansi)]
public struct MySystemTime
{ [FieldOffset(0)]
public ushort wYear;
[FieldOffset(2)]
public ushort wMonth;
[FieldOffset(4)]
public ushort wDayOfWeek;
[FieldOffset(6)]
public ushort wDay;
[FieldOffset(8)]
public ushort wHour;
[FieldOffset(10)]
public ushort wMinute;
[FieldOffset(12)]
public ushort wSecond;
[FieldOffset(14)]public ushort wMilliseconds;
}
每个字段的FieldOffset依次递增为2字节,因为严格ushort占用的内存大小也正好是2字节。总共8个字段,因此总共16字节。在这里又多用了一个CharSet属性声明,它是用来规定封送字符串应使用何种字符集。它也是一个枚举类型,对可能值和对应描述如下:
成员名称
说明
Auto
针对目标操作系统适当地自动封送字符串。在 Windows NT、Windows 2000、Windows XP 和 Windows Server 2003 系列上默认值为 Unicode;在 Windows 98 和 Windows Me 上默认值为 Ansi。尽管公共语言运行库默认值为 Auto,使用语言可重写此默认值。例如,默认情况下,C# 将所有方法和类型都标记为 Ansi。