在C#程序设计中使用Win32类库

在C#程序设计中使用Win32类库,第1张

在C#程序设计中使用Win32类库,第2张

# C用户经常会问两个问题:“为什么我要编写额外的代码来使用Windows内置的功能?为什么框架里没有相应的内容来替我完成这个任务?”当框架团队构建他们的。net部分,他们评估了使Win32对。NET程序员,发现Win32 API集非常大。他们没有足够的资源来编写托管接口,测试和记录所有的Win32 API,所以他们只能优先考虑最重要的部分。很多常见的操作都有托管接口,但还是有很多完整的Win32部分没有托管接口。

平台调用(P/Invoke)是完成这项任务最常用的方法。要使用P/Invoke,您可以编写一个描述如何调用函数的原型,然后运行时将使用这些信息进行调用。另一种方法是使用C++的托管扩展来包装函数,这将在以后的专栏中介绍。

理解如何完成这项任务的最好方法是通过例子。在一些例子中,我只给出一些代码;完整的代码可以通过下载获得。

简单的例子

在第一个例子中,我们将调用Beep() API来发出声音。首先,我需要为Beep()写一个合适的定义。查看MSDN的定义,我发现它有以下原型:

l嘟嘟声(
dword dwfreq,//声音频率
DWORD dwDuration //声音持续时间
);

要用C#编写这个原型,需要将Win32类型转换成相应的C#类型。由于DWORD是一个4字节的整数,所以我们可以使用int或uint作为C#的对应类型。因为int是CLS兼容的类型(可以在所有。NET语言),它比uint更常用,在大多数情况下,它们之间的区别并不重要。bool类型对应于BOOL。现在我们可以用C#编写以下原型:

公共静态外部bool Beep(int频率,int持续时间);

这是一个相当标准的定义,只是我们用extern来表示这个函数的实际代码在别的地方。这个原型将告诉运行时如何调用函数;现在我们需要告诉它在哪里找到这个函数。

我们需要审查MSDN的准则。在参考信息中,我们发现Beep()是在kernel32.lib中定义的,这意味着运行时代码包含在kernel32.lib中。我们将DllImport属性添加到原型中,告诉运行时以下信息:

[DllImport("kernel32.dll")]

这就是我们要做的一切。下面是一个完整的例子。它产生的随机声音在60年代的科幻电影中很常见。

使用系统;
使用系统。Runtime . InteropServices

命名空间Beep
{
class class 1
{
[DllImport(" kernel 32 . dll ")]
public static extern bool Beep(int frequency,int duration);

static void Main(string[]args)
{
Random Random = new Random();

for(int I = 0;i < 10000i++)
{
哔声(随机。下一个(10000),100);
}
}
}
}

声音大到可以刺激任何一个听者!因为DllImport允许您调用Win32中的任何代码,所以有可能调用恶意代码。因此,您必须是完全受信任的用户才能在运行时进行P/Invoke调用。

枚举常数

Beep()可以用来发出任何声音,但是有时候我们想发出特定类型的声音,就用MessageBeep()来代替。MSDN给出了以下原型:

boomessagebeep(
uintype//声音类型
);

这看似简单,但从评论中可以发现两个有趣的事实。

首先,uType参数实际上接受一组预定义的常数。

其次,可能的参数值包括-1,也就是说虽然定义为uint类型,但是int会更合适。

对于uType参数,使用枚举类型是有意义的。MSDN列出了命名的常数,但没有给出任何关于具体值的提示。正因为如此,我们需要看看实际的API。

如果安装了Visual Studio?和C++中,平台SDK位于\ program files \ Microsoft visual studio.net \ vc7 \ Platform SDK \ include下。

为了找到这些常量,我在这个目录中执行了findstr。

findstr "MB_ICONHAND" *。h

它确定常量位于winuser.h中,然后我使用这些常量来创建我的枚举和原型:

公共枚举BeepType
{
simple beep =-1,
icon asterisk = 0x 000000040,
icon example = 0x 00000030,
icon hand = 0x 000000010,
icon question = 0x 000000020,
Ok = 0x00000000,
}

[DllImport(" user 32 . dll ")]
public static extern bool message beep(beep type beep type);

现在我可以用下面的语句调用它:message beep(beep type . icon question);
处理结构

有时我需要确定我的笔记本电脑的电池状态。Win32为此提供了电源管理功能。

搜索MSDN找到GetSystemPowerStatus()函数。

BOOL GetSystemPowerStatus(
LP system _ POWER _ STATUS lpSystemPowerStatus
);

这个函数包含一个指向结构的指针,我们还没有处理它。为了处理该结构,我们需要在C#中定义该结构。我们从非托管的定义开始:

typedef struct _ SYSTEM _ POWER _ STATUS {
BYTE acline STATUS;
BYTE battery flag;
BYTE battery life percent;
字节保留1;
DWORD battery lifetime;
DWORD battery full lifetime;
} SYSTEM_POWER_STATUS,* LPSYSTEM _ POWER _ STATUS

然后,通过用C#类型替换C类型来获得C#版本。

struct system power status
{
byte acline status;
byte battery flag;
byte battery life percent;
字节保留1;
int battery lifetime;
int battery full lifetime;
}

这样,你可以很容易地写出C#原型:

[DllImport(" kernel 32 . dll ")]
public static extern bool GetSystemPowerStatus(
ref SystemPowerStatus SystemPowerStatus);

在这个原型中,我们使用“ref”来表示将传递结构指针,而不是结构值。这是处理指针传递的结构的一般方法。

此函数运行良好,但是ACLineStatus和batteryFlag字段被定义为enum:

enum acline status:byte
{
Offline = 0,
Online = 1,
Unknown = 255,
}

enum battery flag:byte
{
High = 1,
Low = 2,
Critical = 4,
Charging = 8,
NoSystemBattery = 128,
Unknown = 255,
}

请注意,由于该结构的字段是一些字节,我们使用byte作为该枚举的基本类型。

位律师回复
DABAN RP主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
白度搜_经验知识百科全书 » 在C#程序设计中使用Win32类库

0条评论

发表评论

提供最优质的资源集合

立即查看 了解详情