失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > C#【高级篇】.NET平台调用Win32 API

C#【高级篇】.NET平台调用Win32 API

时间:2019-11-05 14:29:35

相关推荐

C#【高级篇】.NET平台调用Win32 API

C#学习汇总 - 总目录

C#【高级篇】 .NET平台调用Win32 API

前言一、基础知识1、Win32 API函数是什么?2、Win32 API放在哪?3、C#如何调用Win32 API函数?4、.NET框架为何不包括所有的Win32 API?5、如何在MSDN中查询Win32 API函数?(1)MSDN在线查看(2)MSDN离线查看二、C#调用Win32 API函数的要点三、常用 Win32数据类型与.NET平台数据类型的对应表附加:Win32类型和.net类型的对应表四、几个示例1、弹出一个MessageBox对话框(1)MessageBox函数的Win32原型:(2)C#源代码:2、调用 Beep() API 来发出声音(1)函数原型:(2)分析:(3)编写C#原型:(4)C#源代码【生成的随机声音在二十世纪六十年代的科幻电影中很常见】:参考:

前言

Win32 API可以直接控制Microsoft Windows的核心,因为API(Application Programming Interface)本来就是微软留给我们直接控制Windows的接口

一、基础知识

Win32 API是C语言函数集(注意,不是C++语言,尽管C语言是C++语言的子集)。

1、Win32 API函数是什么?

Win32 API函数是Windows的核心,比如我们看到的窗体、按钮、对话框什么的,都是依靠Win32函数“画”在屏幕上的,由于这些控件(有时也称组件)都用于用户与Windows进行交互,所以控制这些控件的Win32 API函数称为**“用户界面”函数**(User Interface Win32 API),简称UI函数

还有一些函数,并不用于交互,比如管理当前系统正在运行的进程、硬件系统状态的监视等等……这些函数只有一套,但是可以被所有的Windows程序调用(只要这个程序的权限足够高),简而言之,API是为程序所共享的

为了达到所有程序能共享一套API的目的,Windows采用了“动态链接库”的办法。之所以叫“动态链接库”,是因为这样的函数库的调用方式是“随用随取”而不是像静态链接库那样“用不用都要带上”。

2、Win32 API放在哪?

Win32 API函数是放在Windows系统的核心库文件中的,这些库在硬盘里的存储形式是.dll文件。我们常用到的dll文件User32.dllkernel32.dll两个文件。

这些dll文件是用C语言写的,源代码经C语言编译器编译之后,会以二进制可执行代码形式存放在这些dll文件中。为了能让程序使用这些函数,微软在发布每个新的操作系统的时候,也会放出这个系统的SDK。

SDK里有一些C语言的头文件(.h文件),这些文件里描述了核心dll文件里都有哪些Win32 API函数,在写程序的时候,把这些.h文件用#include"…"指令包含进你的程序(C/C++程序)里,你就可以使用这些Win32 API了。

3、C#如何调用Win32 API函数?

C#语言也使用dll动态链接库,不过这些dll都是.NET版本的,具有“自描述性”,也就是自己肚子里都有哪些函数都已经写在自己的metadata里了,不用再附加一个.h文件来说明

现在,我们已经找到了问题的关键点:如何用.NET平台上的C#语言来调用Win32平台上的dll文件。答案非常简单:使用DllImport特性

【注意:】

1.对类库的了解,直接决定了你编程的效率和质量——用类库里的组件比我们“从轮子造起”要快得多、安全得多。

2.不到万不得已,不要去直接调Win32 API函数——那是不安全的。

4、.NET框架为何不包括所有的Win32 API?

.NET Framework是对Win32 API的良好封装,大部分Win32 API函数都已经封装在了.NET Framework类库的各个类里了。

C# 用户经常提出两个问题:“我为什么要另外编写代码来使用内置于 Windows 中的功能?在框架中为什么没有相应的内容可以为我完成这一任务?”

当框架小组构建他们的 .NET 部分时,他们评估了为使 .NET 程序员可以使用 Win32 而需要完成的工作,结果发现Win32 API 集非常庞大。他们没有足够的资源为所有 Win32 API 编写托管接口、加以测试并编写文档,因此只能优先处理最重要的部分。许多常用操作都有托管接口,但是还有许多的 Win32 部分没有托管接口。

补充:

.NET Framework都为我们封装好了哪些Win32 API?

MSDN里有一篇文章,专门列出了这些。文章的名字是《Microsoft Win32 to Microsoft .NET Framework API Map》

5、如何在MSDN中查询Win32 API函数?

MSDN官网:/zh-cn/

(1)MSDN在线查看

例如我们查找MessageBox函数:

搜索“Windows API Index”,一步步查找

直接查找“MessageBox”

(2)MSDN离线查看

输入的关键字是MSDN Library。以下是下载MSDN Library的链接:

微软官网下载:/en-us/download/details.aspx?id=20955

其他链接:/download/1/f/0/1f07c259-7ff2-4902-9205-ad1dfb87ccab/VSSP1MSDNENUX1506188.iso

下载之后解压iso文件,找到setup文件夹下的setup.exe双击安装,也可以使用虚拟光驱安装。

安装后,在点击 开始->所有应用—>找到MSDN Library for Visual Studio SP1 点击就可以使用了。

二、C#调用Win32 API函数的要点

public static extern后边的函数名字要与Win32 API的完全一样(DllImport中没有EntryPoint时。如果有EntryPoint,名字可以由用户自定义。详见示例1)。函数除了要有相应的DllImport类修饰外,还要声明成public static extern类型的。函数的返回值和参数类型要与Win32 API完全一致!

三、常用 Win32数据类型与.NET平台数据类型的对应表

附加:Win32类型和.net类型的对应表

BOOL=System.Int32BOOLEAN=System.Int32BYTE=System.UInt16CHAR=System.Int16COLORREF=System.UInt32DWORD=System.UInt32DWORD32=System.UInt32DWORD64=System.UInt64FLOAT=System.FloatHACCEL=System.IntPtrHANDLE=System.IntPtrHBITMAP=System.IntPtrHBRUSH=System.IntPtrHCONV=System.IntPtrHCONVLIST=System.IntPtrHCURSOR=System.IntPtrHDC=System.IntPtrHDDEDATA=System.IntPtrHDESK=System.IntPtrHDROP=System.IntPtrHDWP=System.IntPtrHENHMETAFILE=System.IntPtrHFILE=System.IntPtrHFONT=System.IntPtrHGDIOBJ=System.IntPtrHGLOBAL=System.IntPtrHHOOK=System.IntPtrHICON=System.IntPtrHIMAGELIST=System.IntPtrHIMC=System.IntPtrHINSTANCE=System.IntPtrHKEY=System.IntPtrHLOCAL=System.IntPtrHMENU=System.IntPtrHMETAFILE=System.IntPtrHMODULE=System.IntPtrHMONITOR=System.IntPtrHPALETTE=System.IntPtrHPEN=System.IntPtrHRGN=System.IntPtrHRSRC=System.IntPtrHSZ=System.IntPtrHWINSTA=System.IntPtrHWND=System.IntPtrINT=System.Int32INT32=System.Int32INT64=System.Int64LONG=System.Int32LONG32=System.Int32LONG64=System.Int64LONGLONG=System.Int64LPARAM=System.IntPtrLPBOOL=System.Int16[]LPBYTE=System.UInt16[]LPCOLORREF=System.UInt32[]LPCSTR=System.StringLPCTSTR=System.StringLPCVOID=System.UInt32LPCWSTR=System.StringLPDWORD=System.UInt32[]LPHANDLE=System.UInt32LPINT=System.Int32[]LPLONG=System.Int32[]LPSTR=System.StringLPTSTR=System.StringLPVOID=System.UInt32LPWORD=System.Int32[]LPWSTR=System.StringLRESULT=System.IntPtrPBOOL=System.Int16[]PBOOLEAN=System.Int16[]PBYTE=System.UInt16[]PCHAR=System.Char[]PCSTR=System.StringPCTSTR=System.StringPCWCH=System.UInt32PCWSTR=System.UInt32PDWORD=System.Int32[]PFLOAT=System.Float[]PHANDLE=System.UInt32PHKEY=System.UInt32PINT=System.Int32[]PLCID=System.UInt32PLONG=System.Int32[]PLUID=System.UInt32PSHORT=System.Int16[]PSTR=System.StringPTBYTE=System.Char[]PTCHAR=System.Char[]PTSTR=System.StringPUCHAR=System.Char[]PUINT=System.UInt32[]PULONG=System.UInt32[]PUSHORT=System.UInt16[]PVOID=System.UInt32PWCHAR=System.Char[]PWORD=System.Int16[]PWSTR=System.StringREGSAM=System.UInt32SC_HANDLE=System.IntPtrSC_LOCK=System.IntPtrSHORT=System.Int16SIZE_T=System.UInt32SSIZE_=System.UInt32TBYTE=System.CharTCHAR=System.CharUCHAR=System.ByteUINT=System.UInt32UINT32=System.UInt32UINT64=System.UInt64ULONG=System.UInt32ULONG32=System.UInt32ULONG64=System.UInt64ULONGLONG=System.UInt64USHORT=System.UInt16WORD=System.UInt16WPARAM=System.IntPtr

四、几个示例

1、弹出一个MessageBox对话框

(1)MessageBox函数的Win32原型:

int MessageBox( HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType );

函数名:MessageBox将保持不变。返回值:int 将保持不变(无论是Win32还是C#,int都是32位整数)参数表: H开头意味着是Handle,一般情况下Handld都是指针类型,Win32平台的指针类型是用32位来存储的,所以在C#里正好对应一个int整型。不过,既然是指针,就没有什么正负之分,32位都应该用来保存数值——这样一来,用uint(无符号32位整型)来对应Win32的H类型更合理。不过提醒大家一点,int是受C#和.NET CLR双重支持的,而uint只受C#支持而不受.NET CLR支持,所以,本例还是老老实实地使用了int型。LPCTSTR是Long Pointer to Constant String的缩写,说白了就是——字符串。所以,用C#里的string类型就对了。 修饰符:要求有相应的DllImport和public static extern

经过上面一番折腾,Win32的MessageBox函数就包装成C#可以调用的函数了:

[DllImport("User32.dll")] public static extern int MessageBox(int h, string m, string c, int type);

第一个:弹出的MessageBox的父窗口是谁。本例中没有,所以是0,也就是“空指针”。

第二个:MessageBox的内容。

第三个:MessageBox的标题。

第四个:MessageBox上的按钮是什么,如果是0,那就只有一个OK;改成了4,这样就有两个按钮了。

(2)C#源代码:

using System;using System.Runtime.InteropServices;//必须引入的【运行时.交互服务】(运行时的交互服务不就是“动态链接”吗?感谢Microsoft!)class Program{[DllImport("User32.dll")]//制造一个DllImport类的实例,并把这个实例绑定在我们要使用的函数上!public static extern int MessageBox(int h, string m, string c, int type);static int Main(){MessageBox(0, "内容:Hello Win32 API", "标题:风格0", 0);MessageBox(0, "内容:Hello Win32 API", "标题:风格1", 1);MessageBox(0, "内容:Hello Win32 API", "标题:风格2", 2);MessageBox(0, "内容:Hello Win32 API", "标题:风格3", 3);MessageBox(0, "内容:Hello Win32 API", "标题:风格4", 4);Console.ReadLine();return 0;}}

运行结果【依次弹出如下对话框】:

进一步测试:

加上入口函数名称后,进一步测试:

2、调用 Beep() API 来发出声音

(1)函数原型:

BOOL Beep( DWORD dwFreq,// 声音频率 DWORD dwDuration // 声音持续时间 );

MSDN中的查询结果:

(2)分析:

由于 DWORD 是 4 字节的整数,因此我们可以使用 int 或 uint 作为 C# 对应类型。由于 int 是 CLS 兼容类型(可以用于所有 .NET 语言),以此比 uint 更常用,并且在多数情况下,它们之间的区别并不重要。bool 类型与 BOOL 对应。

(3)编写C#原型:

[DllImport("kernel32.dll")]public static extern bool Beep(int frequency, int duration);

(4)C#源代码【生成的随机声音在二十世纪六十年代的科幻电影中很常见】:

using System;using System.Runtime.InteropServices;namespace Beep{class Class1{[DllImport("kernel32.dll")]public static extern bool Beep(int frequency, int duration);static void Main(string[] args){Random random = new Random();for (int i = 0; i < 10000; i++){Beep(random.Next(10000), 100);}Console.WriteLine("End");}}}

参考:

/bcbobo21cn/article/details/50930221

C#调用Win32常见API函数汇总: /zhengzhe1937/article/details/8528363

C#学习汇总 - 总目录

如果觉得《C#【高级篇】.NET平台调用Win32 API》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。