C#与API

by admin on 2020年1月21日

若果您不了然 C 语法也许调用 Windows API
函数,一时很难理解一个主意参数是还是不是需求指针。一个遍布的指令符是看参数类型是不是是以字母 P 或 LP 最初的,举个例子 LPDWO福特ExplorerD 或
PINT。在这里八个例子中,LP 和 P
提示参数是二个指南针,而它们照准的数据类型分别为
DWO卡宴D 或
INT。不过,在多少情状下,能够直接行使 C
语言语法中的星号 (*State of Qatar 将 API
函数定义为指针。以下代码片段显示了那地点的演示:

Api函数是构筑Windws应用程序的基石,每大器晚成种Windows应用程序开采工具,它提供的底层函数都直接或直接地调用了Windows
API函数,同一时候为了兑现效果与利益扩张,日常也都提供了调用WindowsAPI函数的接口,
也正是说具有调用动态连接库的力量。Visual
C#和其余开拓工具相仿也能够调用动态链接库的API函数。.NET框架本身提供了这么风流浪漫种服务,允许受管辖的代码调用动态链接库中落到实处的非受管辖函数,包含操作系统提供的Windows
API函数。它能够稳固和调用输出函数,依据要求,组织其种种参数(整型、字符串类型、数组、和构造等等卡塔尔(قطر‎赶上互操作边界。

void
TakesAPointer(DWORD* pNum);

下面以C#为例简介调用API的主干历程:
动态链接库函数的扬言
 动态链接库函数使用前必得表明,相对于VB,C#函数声显明示尤为罗嗦,前面七个通过
Api
Viewer粘贴未来,能够一直运用,而后人则必要对参数作些额外的浮动职业。

能够见到,上述函数的唯生龙活虎二个参数是指向 DWORubiconD 变量的指针。

 动态链接库函数注脚部分平时由下列两某些构成,一是函数名或索引号,二是动态链接库的文书名。
 
比如,你想调用User32.DLL中的MessageBox函数,大家亟须指明函数的名字MessageBoxA或MessageBoxW,以至库名字User32.dll,大家领会Win32
API对每叁个事关字符串和字符的函数平常都存在四个本子,单字节字符的ANSI版本和双字节字符的UNICODE版本。


通过 P/Invoke 封送指针时,ref 和 out
只用于托管代码中的值类型。当三个参数的 CL揽胜类型使用 struct
关键字定义时,能够以为该参数是八个值类型。Out
和 ref
用于封送指向那么些数据类型的指针,因为平日值类型变量是指标或数量,而在托管代码中并不曾对值类型的援引。相反,当封送引用类型对象时,并无需 ref 和 out
关键字,因为变量已是目的的援引了。

 上面是二个调用API函数的例子:
[DllImport(“KERNEL32.DLL”, EntryPoint=”MoveFileW”, SetLastError=true,
CharSet=CharSet.Unicode, ExactSpelling=true,
CallingConvention=CallingConvention.StdCall)]
public static extern bool MoveFile(String src, String dst);

假定您对引用类型和值类型之间的异样不是很熟谙,请查阅 2003 年 12 月发行的 MSDN? Magazine,在 .NET
专栏的主旨中得以找到更加多音信。大好多 CLLacrosse类型都以援引类型;但是,除了 System.String

System.Object,全部的基元类型(比方System.Int32 和
System.Boolean)都以值类型。

 此中入口点EntryPoint标志函数在动态链接库的输入地点,在贰个受管辖的工程中,目的函数的原本名字和序号入口点不止标记多少个超过互操作界限的函数。而且,你还足以把那一个入口点映射为二个不等的名字,也便是对函数实行重命名。重命名能够给调用函数带给各个便利,通过重命名,一方面大家绝不为函数的分寸写伤透脑筋,同时它也可以确认保障与已有个别命名法则保持风姿浪漫致,允许带有差异参数类型的函数共存,更重要的是它简化了对ANSI和Unicode版本的调用。CharSet用于标记函数调用所采用的是Unicode或是ANSI版本,ExactSpelling=false将告诉编写翻译器,让编译器决定利用Unicode可能是Ansi版本。其余的参数请参见MSDN在线协助.

封送不透明 (Opaque卡塔尔 指针:豆蔻年华种非凡情况

 在C#中,你能够在EntryPoint域通过名字和序号声美素佳儿(Friso卡塔尔(قطر‎个动态链接库函数,即使在章程定义中接纳的函数名与DLL入口点相近,你无需在EntryPoint域突显注脚函数。否则,你一定要选拔下列属性情式提醒二个名字和序号。

不时在 Windows API
中,方法传递或回到的指针是不透明的,这代表该指针值从工夫角度讲是四个指南针,但代码却不间接使用它。相反,代码将该指针重回给 Windows 以便随后开展录取。

[DllImport(“dllname”, EntryPoint=”Functionname”)]
[DllImport(“dllname”, EntryPoint=”#123″)]
值得注意的是,你必须在数字序号前加“#”
下边是三个用MsgBox替换MessageBox名字的例证:
[C#]
using System.Runtime.InteropServices;

一个万分普遍的例子就是句柄的定义。在 Windows
中,内部数据布局(从文件到显示器上的按键)在应用程序代码中都表示为句柄。句柄其实正是不透明的指针或富有指针宽度的数值,应用程序用它来代表此中的 OS 布局。

public class Win32 {
[DllImport(“user32.dll”, EntryPoint=”MessageBox”)]
public static extern int MsgBox(int hWnd, String text, String caption,
uint type);
}
广大受管辖的动态链接库函数期望你能够传递三个目眩神摇的参数类型给函数,例如三个顾客定义的协会类型成员要么受管辖代码定义的多少个类成员,那个时候你必得提供额外的消息格式化这一个连串,以保全参数原有的架议和对齐。

少数气象下,API 函数也将不透明指针定义为
PVOID 或 LPVOID 类型。在 Windows API
的定义中,那么些体系意思便是说该指针未有项目。

C#提供了八个StructLayoutAttribute类,通过它你能够定义自身的格式化类型,在受管辖代码中,格式化类型是叁个用StructLayoutAttribute表明的布局或类成员,通过它亦可确认保证其内部成员预期的布局新闻。布局的选用共有三种:


二个不透明指针重回给您的应用程序(可能您的应用程序期望获得二个不透明指针)时,您应该将参数或再次来到值封送为 CL奥迪Q5 中的生龙活虎种新鲜类别—
System.IntPtr。当您使用 IntPtr
类型时,平常不利用 out 或 ref 参数,因为 IntPtr
意为直接持有指针。可是,倘让你将三个指针封送为叁个指南针,则对 IntPtr 使用 by-ref
参数是适合的数量的。

布局选项
描述
LayoutKind.Automatic
为了升高效能允许运营态对品种成员再一次排序。
静心:长久不要接受那些选项来调用不受管辖的动态链接库函数。
LayoutKind.Explicit
对各种域遵照FieldOffset属性对品种成员排序
LayoutKind.Sequential
对出现在受管辖类型定义地点的不受管辖内部存款和储蓄器中的门类成员开展排序。
传递布局成员
上边包车型地铁例子表达怎么着在受管辖代码中定义三个点和矩形类型,并视作一个参数字传送递给User32.dll库中的PtInRect函数,
函数的不受管辖原型申明如下:
BOOL PtInRect(const RECT *lprc, POINT pt);
静心你必得经过援用传递Rect构造参数,因为函数须要三个Rect的构造指针。
[C#]
using System.Runtime.InteropServices;

在 CLLacrosse 类型系统中,System.IntPtr
类型有叁个破例的习性。不像系统中的别的基类型,IntPtr
并未牢固的尺寸。相反,它在运行时的深浅是依底层操作系统的例行指针大小而定的。那意味在 32 位的 Windows 中,IntPtr 变量的宽窄是 三十位的,而在 64 位的
Windows 中,实时编写翻译器编写翻译的代码会将 IntPtr
值看作 六十二人的值。当在托管代码和非托管代码之间封送不透明指针时,这种自发性调治高低的天性十分立竿见影。

[StructLayout(LayoutKind.Sequential)]
public struct Point {
public int x;
public int y;
}

请深深记住,任何重返或收受句柄的 API
函数实操的正是不透明指针。您的代码应该将
Windows 中的句柄封送成 System.IntPtr
值。

[StructLayout(LayoutKind.Explicit]
public struct Rect {
[FieldOffset(0)] public int left;
[FieldOffset(4)] public int top;
[FieldOffset(8)] public int right;
[FieldOffset(12)] public int bottom;
}


能够在托管代码中将 IntPtr 值强迫转变为 32 位或 63人的整数值,或将后面一个免强调换为前端。可是,当使用 Windows API
函数时,因为指针应是不透明的,所以除了存款和储蓄和传递给外部方法外,不能将它们另做它用。这种“只限存款和储蓄和传递”准绳的三个特例是当你须要向外界方法传递 null 指针值和须求比较 IntPtr
值与 null
值的事态。为了成功那或多或少,您无法将零强逼调换为
System.IntPtr,而相应在 IntPtr
类型上使用 Int32.Zero
静态公共字段,以便拿到用于比较或赋值的 null
值。

class Win32API {
[DllImport(“User32.dll”)]
public static extern Bool PtInRect(ref Rect r, Point p);
}
恍如你能够调用GetSystemInfo函数拿到系统消息:
? using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
public struct SYSTEM_INFO {
public uint dwOemId;
public uint dwPageSize;
public uint lpMinimumApplicationAddress;
public uint lpMaximumApplicationAddress;
public uint dwActiveProcessorMask;
public uint dwNumberOfProcessors;
public uint dwProcessorType;
public uint dwAllocationGranularity;
public uint dwProcessorLevel;
public uint dwProcessorRevision;
}

封送文本

[DllImport(“kernel32”)]
static extern void GetSystemInfo(ref SYSTEM_INFO pSI);


编制程序时平日要对文本数据开展管理。文本为 interop
创设了某个烦劳,那有七个原因。首先,底层操作系统可能行使 Unicode 来表示字符串,也说不佳选取ANSI。在极少数境况下,比如 MultiByteToWideChar
API 函数的五个参数在字符集上是不类似的。

SYSTEM_INFO pSI = new SYSTEM_INFO();
GetSystemInfo(ref pSI);

第二个原因是,当须求进行 P/Invoke
时,要处理文件还索要特别询问到 C
和 CLHighlander 管理公事的章程是例外的。在 C 中,字符串实际上只是叁个字符值数组,平日以 null 作为达成符。大繁多 Windows
API 函数是比照以下原则管理字符串的:对于
ANSI,将其当做字符值数组;对于
Unicode,将其当作宽字符值数组。

类成员的传递
如出豆蔻梢头辙倘若类拥有一个永久的类成员布局,你也可以传递三个类成员给一个不受管辖的动态链接库函数,下边包车型大巴例证首要表明怎样传递一个sequential顺序定义的MySystemTime类给User32.dll的GetSystemTime函数,
函数用C/C++调用规范如下:

有幸的是,CLMurano被规划得优质灵活,当封送文本时难题得以轻便解决,而不用在乎 Windows API
函数期待从你的应用程序获得的是什么样。这里是一些必要记住的显要构思事项:

void GetSystemTime(SYSTEMTIME* SystemTime);
不像传值类型,类总是通过援引传递参数.
[C#]
[StructLayout(LayoutKind.Sequential)]
public class MySystemTime {
public ushort wYear;
public ushort wMonth;
public ushort wDayOfWeek;
public ushort wDay;
public ushort wHour;
public ushort wMinute;
public ushort wSecond;
public ushort wMilliseconds;
}
class Win32API {
[DllImport(“User32.dll”)]
public static extern void GetSystemTime(MySystemTime st);
}
回调函数的传递:
从受管辖的代码中调用大繁多动态链接库函数,你只需创造一个受管辖的函数定义,然后调用它就能够,这几个历程极度直白。
假如一个动态链接库函数供给三个函数指针作为参数,你还索要做以下几步:
第生机勃勃,你不得不参照有关这几个函数的文书档案,鲜明那个函数是还是不是必要八个回调;第二,你一定要在受管辖代码中开创二个回调函数;最终,你能够把指向那个函数的指针作为叁个参数创递给DLL函数,.

?
是您的应用程序向 API 函数字传送递文本数据,还是 API
函数向你的应用程序重回字符串数据?也许两者兼有?

回调函数及其达成:
回调函数平时用在职务急需再一次实践的场地,譬喻用于枚举函数,举例Win32 API
中的EnumFontFamilies(字体枚举卡塔尔国, EnumPrinters(打字与印刷机卡塔尔, EnumWindows
(窗口枚举State of Qatar函数. 上面以窗口枚举为例,谈谈怎样通过调用EnumWindow
函数遍历系统中设有的有所窗口

?
您的表面方法应该利用什么托管类型?

分下边多少个步骤:

?
API 函数期待得到的是哪些格式的非托管字符串?

  1. 在落实调用前先参照他事他说加以考查函数的扬言
    BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARMAM IParam)
    显著那些函数要求叁个回调函数地址作为参数.
    2.
    开立三个受管辖的回调函数,那几个例子注解为代表类型(delegate卡塔尔(قطر‎,也正是大家所说的回调,它蕴涵八个参数hwnd和lparam,第四个参数是二个窗口句柄,第二个参数由应用程序定义,五个参数均为整形。

自家
们首先解答最终贰个难点。大多数 Windows API
函数都含有 LPTSTGL450 或
LPCTSTCRUISER值。(从函数角度看)它们分别是可改进和不得改革的缓冲区,包蕴以 null 甘休的字符数组。“C”代表常数,意味着使用该参数音信不会传送到函数外界。LPTSTEnclave 中的“T”阐明该参数能够是 Unicode

ANSI,决意于你选拔的字符集和尾部操作系统的字符集。因为在 Windows API
中山大学许多字符串参数都是那三种档案的次序之黄金时代,所以生龙活虎旦在 DllImportAttribute 中选择CharSet.Auto,CL瑞鹰就按默许的办法行事。

  当那个回调函数再次回到二个非零值时,标示推行成功,零则暗暗表示退步,这么些事例总是回到True值,以便不断枚举。

只是,有些 API 函数或自定义的 DLL
函数选用不一致的艺术表示字符串。要是您要用到叁个这么的函数,就可以动用 MarshalAsAttribute
修饰外部方法的字符串参数,并指澳优(Ausnutria Hyproca卡塔尔国种差异于私下认可LPTSTRubicon 的字符串格式。有关 MarshalAsAttribute
的越来越多消息,请参阅坐落于 MarshalAsAttribute
Class 的 Platform SDK 文书档案主题。

  1. 末尾成立以表示对象(delegate卡塔尔国,并把它当做一个参数字传送递给EnumWindows
    函数,平台会自行地 把象征转形成函数能够辨识的回调格式。

近些日子让我们看一下字符串消息在你的代码和非托管函数之间传递的趋势。有二种办法得以知晓管理字符串时新闻的传递方向。第叁个也是最保障的二个艺术正是率先知道参数的用场。举个例子,您正调用贰个参
数,它的名称形似 CreateMutex
并带有多个字符串,则足以想像该字符串音信是从应用程序向 API 函数字传送递的。同有时间,借使您调用
GetUserName,则该函数的称呼表明字符串消息是从该函数向您的应用程序传递的。

[C#]
using System;
using System.Runtime.InteropServices;

除此之外这种比较合理的艺术外,第二种检索信息传送方向的不二秘籍就是搜索 API 参数类型中的字母“C”。举个例子,GetUserName API
函数的第三个参数被定义为 LPTSTTucson类型,它表示一个对准 Unicode 或 ANSI 字符串缓冲区的长指针。但是CreateMutex 的名号参数被项目化为
LTCTSTSportage。请留意,这里的类型定义是风度翩翩律的,但扩展多个字母“C”来评释缓冲区为常数,API
函数无法写入。

public delegate bool CallBack(int hwnd, int lParam);

假设鲜明了文件参数是只用作输入依然作为输入/输出,就足以规定使用哪一种 CLMurano类型作为参数类型。这里有局地规行矩步。假如字符串参数只用作输入,则动用 System.String
类型。在托管代码中,字符串是不改变的,相符用于不会被本机 API 函数改革的缓冲区。

public class EnumReportApp {

若是字符串参数能够当作输入和/或输出,则利用 System.StringBuilder 类型。StringBuilder
类型是贰个很有用的类库类型,它能够补助你有效地创设字符串,也偏巧能够将缓冲区传递给本机函数,由本机函数为您填充字符串数据。大器晚成旦函数调用重回,您只要求调用 StringBuilder 对象的 ToString
就足以拿走贰个 String 对象。

[DllImport(“user32”)]
public static extern int EnumWindows(CallBack x, int y);

GetShort帕特hName
API 函数能很好地用于体现怎么时候使用 String、曾几何时利用
StringBuilder,因为它只蕴含多个参数:一个输入字符串、八个出口字符串和一个指明输出缓冲区的字符长度的参数。

public static void Main()
{
CallBack myCallBack = new CallBack(EnumReportApp.Report);
EnumWindows(myCallBack, 0);
}

图 3 所示为加注释的非托管
GetShortPathName
函数文书档案,它同期建议了输入和输出字符串参数。它引出了托管的外表方法定义,也如图 3 所示。请稳重第一个参数被封送为
System.String,因为它是二个只用作输入的参数。第贰个参数代表四个出口缓冲区,它采纳了 System.StringBuilder。

public static bool Report(int hwnd, int lParam) {
Console.Write(“窗口句柄为”卡塔尔;
Console.WriteLine(hwnd);
return true;
}
}

小结

指针类型参数字传送递:
 在Windows
API函数调用时,抢先五成函数选择指针传递参数,对多少个构造变量指针,大家除了选用方面包车型地铁类和构造方式传递参数之外,大家有时还足以动用数组传递参数。

上一个月特辑所介绍的 P/Invoke 功效丰裕调用 Windows
中的大多 API
函数。可是,假若你多量用到
interop,则会最后开掘本身封送了很复杂的数据构造,以至可能须求在托管代码中经过指针直接待上访谈内部存款和储蓄器。实际上,本机代码中的 interop
能够是三个将细节和初级比特藏在里面包车型客车真正的潘多拉盒子。CLCRUISER、C# 和托管 C++
提供了成都百货上千立竿见影的功效;大概今后作者会在本专栏介绍高档的 P/Invoke 话题。

 上面那么些函数通过调用GetUserName得到客商名
BOOL GetUserName(
LPTST君越 lpBuffer, // 顾客名缓冲区
LPDWO途达D nSize // 贮存慢冲区大小的地点指针
);
 
[DllImport(“Advapi32.dll”,
EntryPoint=”GetComputerName”,
ExactSpelling=false,
SetLastError=true)]
static extern bool GetComputerName (
[MarshalAs(UnmanagedType.LPArray)] byte[] lpBuffer,
  [MarshalAs(UnmanagedType.LPArray)] Int32[] nSize );
 那个函数接纳三个参数,char * 和int
*,因为您必须要分配一个字符串缓冲区以接收字符串指针,你能够接纳String类取代那一个参数类型,当然你还能声多美滋个字节数组传递ANSI字符串,同样你也能够声飞鹤个独有一个要素的长整型数组,使用数组名作为第三个参数。上边包车型客车函数可以调用如下:

同不经常间,只要你以为 .NET Framework
类库不能够播放您的响声仍然为你实施其余界分效应,您能够清楚如何向原始而特出的 Windows API 寻求一些扶持。

byte[] str=new byte[20];
Int32[] len=new Int32[1];
len[0]=20;
GetComputerName (str,len);
MessageBox.Show(System.Text.Encoding.ASCII.GetString(str));
 最终索要提醒的是,每意气风发种方法应用前必需在文件头加上:
 using System.Runtime.InteropServices;

API
(应用编制程序接口卡塔尔国是程序与Computer接口的命令集。最常用的正是在外表调用微软WINDOWS内部的长河。WINDOWS
API包蕴成千的你能够选择的函数、结构、常量。那些函数是用C语言写的,在应用他们在此以前,你一定要注明。定义Dll的长河将相当的繁琐,以至比VB还复 杂。你能够运用API
Viewer工具获得API函数的宣示,不过必需小心的是,它的参数类型跟C#的不一样样。
大好些个的高端语言都援助API,
微软函数类库(MFC卡塔尔(قطر‎封装了绝大超级多的Win32 API。ODBC
API对增高数据库的操作速度大有实益。使用API,能够哀告更底层的种类服务。API从轻松的对话框到复杂的加密运算都提供支撑。开采者应该清楚什么在他们前后相继中动用API
API有广大类型,(针对差异的操作系统、微电脑…………)
OS specific API:
操作系统特有API:
每 种操作系统都有生机勃勃套公用API和专有API。例如:Windows NT
帮衬MS-DOS, Win16, Win32, POSIX
(便携式操作系统接口卡塔尔(قطر‎,OS/2 console API ;同不日常间Windows 95
supports MS-DOS, Win16 和Win32
API。
Win16 和 Win32 API:
WIN16 是依靠十几个人的Computer,并接纳拾十位的值,它是三个单独的阳台。比方:你能够运作TS奥迪Q3 程序在MS-DOS情形下。
WIN32 是依照33个人的微处理器,并接受三十一人的值。他可用来别的操作系统,它的施用节制更广。
Win32 API has 32 prefix after the library name e.g. KERNEL32, USER32
etc?
Win32 API的DLL平时都富有32的后缀,比如:KE本田UR-VNEL32,
USETiggo32等。
有着的API都在上边3个DLL中落到实处的。
Kernel
User
GDI

<> <>

  1. KERNEL
    它的库名是:KE昂科拉NEL32.DLL,它是操作系统管理的API集
    Process loading. 加载进度
    Context switching.
    File I/O. 文件操作
    Memory management. 内部存款和储蓄器管理
    比方说:GlobalMemoryStatus
    函数获得近来系统物理设想内部存储器的应用消息。
  2. USER
    在WIN32下,它的库名是 USE奔驰G级32.DLL
    This allows managing the entire user interfaces such as
    它管理整个的客商分界面,例如:
    Windows 窗口
    Menus 菜单
    Dialog Boxes 对话框
    Icons etc., 图标等
    比方:DrawIcon
    画一个Logo在内定的设备上。
  3. GDI (Graphical Device Interface)
    以此DLL是GDI32.dll,它担负图像的出口,使用GDI绘出窗口,菜单,对话框
    It can create Graphical Output. 输出图像
    举例:CreateBitmap
    函数创立一个内定宽度、中度和颜料格式的位图。
    C#中API的工具对初读书人是意气风发对一不错的。在C#运用中运用API此前,你应该先知道C#中怎样利用布局、类型转变,安全与不安全代码等。
    运用复杂的api从前,大家先用叁个简约的Message博克斯 API作为列子。展开一个C#工程,扩大多少个开关,在开关的点击事件中,我们将显得三个新闻框。
    充实应用外界库的命名空间:
    using System.Runtime.InteropServices;
    上边表明API
    [DllImport(“User32.dll”)]
    DllImport属性用来钦点包蕴外界方法的动态连接库的职位。 “User32.dll”提出了库名,static
    指明它不属于特定的指标。extern
    指明是一个外界的法子。带有DllImport
    属性的法子必需满含修饰符extern 。
    MessageBox 是一个汉数名,带八个参数再次来到一个int型值。
    多多API使用构造来传递、重回参数,那样能够减弱复杂度。它也允许行使象MessageBox 函数那样,使用一定的参数。

在按键的点击事件中增添下边代码:
protected void button1_Click (object sender, System.EventArgs e)
{
MessageBox (0,”API Message Box”,”API Demo”,0);
}
编写翻译并运路程序,点击按钮之后,你就足以看出一个由API调用的音信框。
Using structure 使用布局
API中平常应用复杂的组织。然而尽管你掌握了她们,将是十分轻松的。
In next example we will use GetSystemInfo API which returns information
about the current system.
下边包车型客车列子,大家用GetSystemInfo
API获得当前系统的音讯。
率先步:增加叁个C#窗口,并在上头扩充一个开关,在窗口代码页扩张一个命名空间:
using System.Runtime.InteropServices;
声称 GetSystemInfo 的参数构造:
[StructLayout(LayoutKind.Sequential)]
public struct SYSTEM_INFO {
public uint dwOemId;
public uint dwPageSize;
public uint lpMinimumApplicationAddress;
public uint lpMaximumApplicationAddress;
public uint dwActiveProcessorMask;
public uint dwNumberOfProcessors;
public uint dwProcessorType;
public uint dwAllocationGranularity;
public uint dwProcessorLevel;
public uint dwProcessorRevision;
}
声明API函数:
[DllImport(“kernel32”)]
static extern void GetSystemInfo(ref SYSTEM_INFO pSI);
ref是三个评释参量传递格局的根本字,它使传入传出的变量指向同二个变量(传址传递)
在按键点击事件中追加下边包车型客车代码,
protected void button1_Click (object sender, System.EventArgs e)
{
try
{
SYSTEM_INFO pSI = new SYSTEM_INFO();
GetSystemInfo(ref pSI);
Once you retrieve the structure perform operations on required
parameter
比如:
listBox1.Items.Insert(0,pSI.dwActiveProcessorMask.ToString());
}
catch(Exception er)
{
MessageBox.Show (er.Message);
}
}

用Visual C#调用Windows
API函数

法国巴黎机械药中国科学技术大学学研00级(100085)冉林仓

Api函数是建筑Windws应用程序的基本,每豆蔻梢头种Windows应用程序开荒工具,它提供的最底层函数都直接或直接地调用了Windows
API函数,同不常候为了达成效果与利益扩张,日常也都提供了调用WindowsAPI函数的接口,也正是说具有调用动态连接库的工夫。Visual
C#和此外开辟工具同样也能够调用动态链接库的API函数。.NET框架自己提供了如此一种服务,允许受管辖的代码调用动态链接库中完毕的非受管辖函数, 富含操作系统提供的Windows
API函数。它能够稳固和调用输出函数,根据需求,社团其各类参数(整型、字符串类型、数组、和组织等等卡塔尔国超过互操作边界。

下面以C#为例简要介绍调用API的着力进度:
动态链接库函数的宣示
动态链接库函数使用前必需证明,相对于VB,C#函数声鲜明示愈加罗嗦,前面多少个通过 Api
Viewer粘贴未来,能够直接选用,而后面一个则需求对参数作些额外的变动专门的工作。

动态链接库函数注脚部分常常由下列两局地构成,一是函数名或索引号,二是动态链接库的文件名。
譬喻,你想调用User32.DLL中的MessageBox函数,我们必须指明函数的名字MessageBoxA或MessageBoxW,以至库名字
User32.dll,咱们领略Win32
API对每二个涉及字符串和字符的函数一般都留存多少个本子,单字节字符的ANSI版本和双字节字符的UNICODE版本。

上边是四个调用API函数的事例:
[DllImport(“KERNEL32.DLL”, EntryPoint=”MoveFileW”, SetLastError=true,
CharSet=CharSet.Unicode, ExactSpelling=true,
CallingConvention=CallingConvention.StdCall)]
public static extern bool MoveFile(String src, String
dst);

此中入口点EntryPoint标记函数在动态链接库的输入地方,在一个受管辖的工程中,指标函数的原盛名字和序号入口点不仅仅标志贰个超过互操作界限的函数。况兼,你还足以把这些入口点映射为叁个例外的名字,也正是对函数举行重命名。重命名能够给调用函数带来各类便利,通过重命名,一方面大家毫不为函数的
大小写伤透脑筋,同期它也能够保险与本来就有个别命名准则保持大器晚成致,允许带有差异参数类型的函数共存,更首要的是它简化了对ANSI和Unicode版本的调
用。CharSet用于标志函数调用所采纳的是Unicode或是ANSI版本,ExactSpelling=false将告诉编写翻译器,让编写翻译器决定使用
Unicode或许是Ansi版本。别的的参数请参照他事他说加以侦察MSDN在线协理.

在C#中,你能够在EntryPoint域通过名字和序号声美赞臣(Meadjohnson卡塔尔(قطر‎个动态链接库函数,若是在点子定义中动用的函数名与DLL入口点相像,你不须求在EntryPoint域突显表明函数。不然,你必得运用下列属个性式提醒二个名字和序号。

[DllImport(“dllname”,
EntryPoint=”Functionname”)]
[DllImport(“dllname”, EntryPoint=”#123″)]
值得注意的是,你必得在数字序号前加“#”
下边是八个用MsgBox替换MessageBox名字的事例:
[C#]
using System.Runtime.InteropServices;

public
class Win32 {
[DllImport(“user32.dll”, EntryPoint=”MessageBox”)]
public static extern int MsgBox(int hWnd, String text, String caption,
uint type);
}
众多受管辖的动态链接库函数期待你能够传递四个犬牙相错的参数类型给函数,例如三个客户定义的结构类型成员要么受管辖代码定义的三个类成员,这时候你不得不提供额外的音讯格式化那么些项目,以维持参数原有的结商谈对齐。

C#提供了一个StructLayoutAttribute类,通过它你能够定义自个儿的格式化类型,在受管辖代码中,格式化类型是三个用StructLayoutAttribute表明的协会或类成员,通过它亦可确认保障在那之中间成员预期的构造新闻。布局的采取共有三种:

布局选项
描述
LayoutKind.Automatic
为了进步效用允许运转态对品种成员再次排序。
在乎:永久不要接受那些选项来调用不受管辖的动态链接库函数。
LayoutKind.Explicit
对各样域依照FieldOffset属性对项目成员排序
LayoutKind.Sequential
对出现在受管辖类型定义地方的不受管辖内存中的品类成员开展排序。
传送构产生员
下边包车型客车例子表明怎么样在受管辖代码中定义二个点和矩形类型,并作为贰个参数字传送递给User32.dll库中的PtInRect函数,
函数的不受管辖原型表明如下:
BOOL PtInRect(const RECT *lprc, POINT pt);
留意你一定要经过引用传递Rect构造参数,因为函数须要贰个Rect的布局指针。
[C#]
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]
public struct Point {
public int x;
public int y;
}

[StructLayout(LayoutKind.Explicit]
public struct Rect {
[FieldOffset(0)] public int left;
[FieldOffset(4)] public int top;
[FieldOffset(8)] public int right;
[FieldOffset(12)] public int bottom;
}

class
Win32API {
[DllImport(“User32.dll”)]
public static extern Bool PtInRect(ref Rect r, Point p);
}
临近你可以调用GetSystemInfo函数获得系统新闻:
? using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
public struct SYSTEM_INFO {
public uint dwOemId;
public uint dwPageSize;
public uint lpMinimumApplicationAddress;
public uint lpMaximumApplicationAddress;
public uint dwActiveProcessorMask;
public uint dwNumberOfProcessors;
public uint dwProcessorType;
public uint dwAllocationGranularity;
public uint dwProcessorLevel;
public uint dwProcessorRevision;
}
[DllImport(“kernel32”)]
static extern void GetSystemInfo(ref SYSTEM_INFO pSI);

SYSTEM_INFO
pSI = new SYSTEM_INFO();
GetSystemInfo(ref pSI);

类成员的传递
相仿只要类具有四个恒久的类成员布局,你也能够传递叁个类成员给三个不受管辖的动态链接库函数,下边包车型地铁例子主要表明怎么样传递三个sequential顺序定 义的MySystemTime类给User32.dll的GetSystemTime函数,
函数用C/C++调用标准如下:

void
GetSystemTime(SYSTEMTIME* SystemTime);
不像传值类型,类总是通过援用传递参数.
[C#]
[StructLayout(LayoutKind.Sequential)]
public class MySystemTime {
public ushort wYear;
public ushort wMonth;
public ushort wDayOfWeek;
public ushort wDay;
public ushort wHour;
public ushort wMinute;
public ushort wSecond;
public ushort wMilliseconds;
}
class Win32API {
[DllImport(“User32.dll”)]
public static extern void GetSystemTime(MySystemTime st);
}
回调函数的传递:
从受管辖的代码中调用大好些个动态链接库函数,你只需创制二个受管辖的函数定义,然后调用它就可以,那个历程丰富直白。
后生可畏旦一个动态链接库函数需求叁个函数指针作为参数,你还亟需做以下几步:
第后生可畏,你必须要参照有关那个函数的文书档案,分明那几个函数是或不是必要叁个回调;第二,你必须要在受管辖代码中开创一个回调函数;最终,你能够把指向这么些函数的指针作为叁个参数创递给DLL函数,.

回调函数及其完结:
回 调函数平日用在职责急需重新施行的场子,举个例子用于枚举函数,举例Win32 API 中的EnumFontFamilies(字体枚举卡塔尔(قطر‎,
EnumPrinters(打印机State of Qatar, EnumWindows
(窗口枚举卡塔尔国函数.
上边以窗口枚举为例,谈谈怎么样通过调用EnumWindow
函数遍历系统中设有的具备窗口

分上面多少个步骤:

  1. 在落到实处调用前先参谋函数的扬言
    BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARMAM IParam)
    光天化日那几个函数必要二个回调函数地址作为参数.
  2. 创办一个受管辖的回调函数,那个事例注脚为表示类型(delegate卡塔尔国,也正是大家所说的回调,它含有三个参数hwnd和lparam,第一个参数是八个窗口句柄,第四个参数由应用程序定义,多少个参数均为整形。

当这一个回调函数再次回到三个非零值时,标示推行成功,零则暗指失败,那一个事例总是回到True值,以便不断枚举。

  1. 谈起底创制以表示对象(delegate卡塔尔国,并把它看作一个参数字传送递给EnumWindows
    函数,平台会自行地把象征转形成函数可以分辨的回调格式。

[C#]
using System;
using System.Runtime.InteropServices;

public
delegate bool CallBack(int hwnd, int lParam);

public
class EnumReportApp {

[DllImport(“user32”)]
public static extern int EnumWindows(CallBack x, int y);

public
static void Main()
{
CallBack myCallBack = new CallBack(EnumReportApp.Report);
EnumWindows(myCallBack, 0);
}

public
static bool Report(int hwnd, int lParam) {
Console.Write(“窗口句柄为”卡塔尔(قطر‎;
Console.WriteLine(hwnd);
return true;
}
}

指针类型参数字传送递:
在Windows
API函数调用时,大部分函数接受指针传递参数,对一个组织变量指针,大家除了接受方面包车型地铁类和构造方式传递参数之外,大家偶尔还足以行使数组传递参数。

下边那些函数通过调用GetUserName拿到用户名
BOOL GetUserName(
LPTSTSportage lpBuffer, // 客商名缓冲区
LPDWO智跑D nSize // 存放慢冲区大小的地点指针
);

[DllImport(“Advapi32.dll”,
EntryPoint=”GetComputerName”,
ExactSpelling=false,
SetLastError=true)]
static extern bool GetComputerName (
[MarshalAs(UnmanagedType.LPArray)] byte[] lpBuffer,
[MarshalAs(UnmanagedType.LPArray)] Int32[] nSize );
其生龙活虎函数采用五个参数,char * 和int
*,因为你必须要分配叁个字符串缓冲区以采取字符串指针,你能够使用String类代替那个参数类型,当然你仍然是能够声美赞臣个字节数组传递ANSI字符串,同样你也足以声贝拉米个独有七个因素的长整型数组,使用数组名作为第贰个参数。上边的函数能够调用如下:

byte[]
str=new byte[20];
Int32[] len=new Int32[1];
len[0]=20;
GetComputerName (str,len);
MessageBox.Show(System.Text.Encoding.ASCII.GetString(str));
最后索要提示的是,每风流洒脱种格局运用前必需在文件头加上:
using System.Runtime.InteropServices;

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图