1. 平台调用
利用平台调用这种服务,托管代码可以调用在动态链接库 (DLL)(如 Win32 API 中的 DLL)中实现的非托管函数。此服务将查找并调用导出的函数,然后根据需要跨越互用边界封送其参数(整数、字符串、数组、结构等)。
要封装平台功能,一种有效的方法是将常用的 DLL 函数包装在托管类中。虽然不必在每种情形下都这样做,但由于定义 DLL 函数可能会相当麻烦并且容易出错,所以提供类包装是一种很方便的方法。如果您使用 Visual Basic 或 C# 进行编程,则必须在一个类或 Visual Basic 模块中声明 DLL 函数。
在一个类中,为每个要调用的 DLL 函数定义静态方法。定义中可以包括一些附加信息,如在传递方法参数时使用的字符集或调用约定;如果省略这些信息,将选择默认设置。包装之后,就可以按照对其他任何静态函数调用方法的相同方式来对该函数调用方法。平台调用将自动处理底层的导出函数。
为平台调用设计托管类时,应考虑类和 DLL 函数之间的关系。例如,您可以:
-
在现有类内声明 DLL 函数。
-
分别为每个 DLL 函数创建一个类,以便使函数相互隔离,易于查找。
-
为一组相关的 DLL 函数创建一个类,以形成逻辑分组并减少系统开销。
您可以将该类及其方法命名为任意名称。
DLL 函数的标识包括以下元素:
-
函数的名称或序号
-
实现所在的 DLL 文件的名称
例如,如果指定 User32.dll 中的 MessageBox 函数,需要标识该函数 (MessageBox) 及其位置(User32.dll、User32 或 user32)。Microsoft Windows 应用程序编程接口 (Win32 API) 可以包含每个字符和字符串处理函数的两个版本:单字节字符 ANSI 版本和双字节字符 Unicode 版本。如果不进行指定,<link tabindex="0" keywords="frlrfSystemRuntimeInteropServicesDllImportAttributeClassCharSetTopic"> 字段所表示的字符集将默认为 ANSI。某些函数可以有两个以上的版本。
MessageBoxA 是 MessageBox 函数的 ANSI 入口点;而 MessageBoxW 是 Unicode 版本。可以通过运行各种命令行工具,为特定 DLL(例如 user32.dll)列出函数名。例如,可以使用 dumpbin /exports user32.dll
或 link /dump /exports user32.dll
来获取函数名。
您可以在代码中将非托管函数重命名为任何所需的名称,但是要将该新名称映射到 DLL 中的初始入口点。
利用平台调用,可以通过调用 Win32 API 和其他 DLL 中的函数来控制操作系统中相当大的一部分。除了 Win32 API 之外,还有许多其他的 API 和 DLL 可通过平台调用来调用。
下表将说明 Win32 API 中几个常用的 DLL。
DLL | 内容说明 |
---|---|
GDI32.dll | 用于设备输出的图形设备接口 (GDI) 函数,例如用于绘图和字体管理的函数。 |
Kernel32.dll | 用于内存管理和资源处理的低级别操作系统函数。 |
User32.dll | 用于消息处理、计时器、菜单和通信的 Windows 管理函数。 |
下表列出了在 Win32 API(在 Wtypes.h 中列出)和 C 样式函数中使用的数据类型。许多非托管库包含将这些数据类型作为参数传递并返回值的函数。第三列列出了在托管代码中使用的相应的 .NET Framework 内置值类型或类。某些情况下,您可以用大小相同的类型替换此表中列出的类型。
Wtypes.h 中的非托管类型 | 非托管 C 语言类型 | 托管类名 | 说明 |
---|---|---|---|
HANDLE | void* | <link tabindex="0" keywords="frlrfSystemIntPtrClassTopic"> | 在 32 位 Windows 操作系统上为 32 位,在 64 位 Windows 操作系统上为 64 位。 |
BYTE | unsigned char | <link tabindex="0" keywords="frlrfSystemByteClassTopic"> | 8 位 |
SHORT | short | <link tabindex="0" keywords="frlrfSystemInt16ClassTopic"> | 16 位 |
WORD | unsigned short | <link tabindex="0" keywords="frlrfSystemUInt16ClassTopic"> | 16 位 |
INT | int | <link tabindex="0" keywords="frlrfSystemInt32ClassTopic"> | 32 位 |
UINT | unsigned int | <link tabindex="0" keywords="frlrfSystemUInt32ClassTopic"> | 32 位 |
LONG | long | <link tabindex="0" keywords="frlrfSystemInt32ClassTopic"> | 32 位 |
BOOL | long | <link tabindex="0" keywords="frlrfSystemSByteClassTopic"> | 32 位 |
DWORD | unsigned long | <link tabindex="0" keywords="frlrfSystemUInt32ClassTopic"> | 32 位 |
ULONG | unsigned long | <link tabindex="0" keywords="frlrfSystemUInt32ClassTopic"> | 32 位 |
CHAR | char | <link tabindex="0" keywords="frlrfSystemCharClassTopic"> | 用 ANSI 修饰。 |
LPSTR | char* | <link tabindex="0" keywords="frlrfSystemStringClassTopic"> 或 <link tabindex="0" keywords="frlrfSystemTextStringBuilderClassTopic"> | 用 ANSI 修饰。 |
LPCSTR | Const char* | <link tabindex="0" keywords="frlrfSystemStringClassTopic"> 或 <link tabindex="0" keywords="frlrfSystemTextStringBuilderClassTopic"> | 用 ANSI 修饰。 |
LPWSTR | wchar_t* | <link tabindex="0" keywords="frlrfSystemStringClassTopic"> 或 <link tabindex="0" keywords="frlrfSystemTextStringBuilderClassTopic"> | 用 Unicode 修饰。 |
LPCWSTR | Const wchar_t* | <link tabindex="0" keywords="frlrfSystemStringClassTopic"> 或 <link tabindex="0" keywords="frlrfSystemTextStringBuilderClassTopic"> | 用 Unicode 修饰。 |
FLOAT | Float | <link tabindex="0" keywords="frlrfSystemSingleClassTopic"> | 32 位 |
DOUBLE | Double | <link tabindex="0" keywords="frlrfSystemDoubleClassTopic"> | 64 位 |