C#调用Windows API详解(上)

时间:2022-06-01 18:52:02

以前我写过通过WMI来获取有关系统信息的系列文章,确实通过WMI能够恨轻易地实现很多我们想实现的功能,不过有些情况下我们很难利用WMI来实现一些 复杂的功能,比如最近我做的一个项目,其中有一个功能就是要更改系统当前时间,利用WMI就很难实现(我没有找到相关的方法),还有一些其它方面的功能, 也比较难以通过WMI来实现,也许是WMI需要较高的权限才能执行的原因吧。所以,尽管我们不愿意,但是又不得不通过调用Windows 的API来实现。本文的目的就是讲述如何在C#中调用Windows的系统API。
本文将按照下面的步骤分别讲解:
API简介
C#中的简单数据类型与API中的数据类型对应关系
如何在调用API时传递复杂参数:封装类、结构和联合
如何调用API
如何确保成功调用API

API简介
Windows API(Application Programming Interface,应用编程接口)是微软为了方便广大Windows开发人员调用系统底层功能而公开的一系列函数接口。.net中的函数很多就是对系统 底层API的一些封装,但是在.net中并没有包含Windows所有的API函数。所幸的是,在.net中允许我们调用系统的API函数,并且还可以根 据需要向系统API传递输入或者输出参数。 
 
当调用非托管API函数时,它将依次执行以下操作: 
1.查找包含该函数的 DLL。
2.将该 DLL 加载到内存中。
3.查找函数在内存中的地址并将其参数推到堆栈上,以封送所需的数据(注意:只在第一次调用函数时,才会查找和加载 DLL 并查找函数在内存中的地址。)。
4.将控制权转移给非托管函数。
5.对非托管 DLL 函数的“平台调用”调用
平台调用会向托管调用方引发由非托管函数生成的异常。

DLL 函数的标识包括以下元素: 
函数的名称或序号
实现所在的 DLL 文件的名称

例如,如果指定 User32.dll 中的 MessageBox 函数,需要标识该函数 (MessageBox) 及其位置(User32.dll、User32 或 user32)。Microsoft Windows 应用程序编程接口 (Win32 API) 可以包含每个字符和字符串处理函数的两个版本:单字节字符 ANSI 版本和双字节字符 Unicode 版本。如果不进行指定,CharSet 字段所表示的字符集将默认为 ANSI。某些函数可以有两个以上的版本。

MessageBoxA 是 MessageBox 函数的 ANSI 入口点;而 MessageBoxW 是 Unicode 版本。可以通过运行各种命令行工具,为特定 DLL(例如 user32.dll)列出函数名。例如,可以使用 dumpbin /exports user32.dll 或 link /dump /exports user32.dll 来获取函数名。

您可以在代码中将非托管函数重命名为任何所需的名称,但是要将该新名称映射到 DLL 中的初始入口点。有关在托管源代码中重命名非托管 DLL 函数的说明,请参见指定入口点。

利用平台调用,可以通过调用 Win32 API 和其他 DLL 中的函数来控制操作系统中相当大的一部分。除了 Win32 API 之外,还有许多其他的 API 和 DLL 可通过平台调用来调用。

下面将说明 Win32 API 中几个常用的 DLL。
GDI32.dll:用于设备输出的图形设备接口 (GDI) 函数,例如用于绘图和字体管理的函数。
Kernel32.dll:用于内存管理和资源处理的低级别操作系统函数。
User32.dll:用于消息处理、计时器、菜单和通信的 Windows 管理函数。

涉及到函数调用,自然免不了要向系统API提供参数或者获取调用系统API之后的返回值,由于Windows采用了C/C++开发的,而我们调用的程序语言是C#,二者的数据类型自然会存在一些不一致的情况,下面的表列出了二者之间的一个对应关系。


下表列出了在 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 位