澳门新葡亰信誉平台游戏C#与API

by admin on 2020年1月21日

后生可畏旦你面生 C 语法只怕调用 Windows API
函数,不常很难驾驭多少个方式参数是还是不是须求指针。八个大范围的指令符是看参数类型是不是是以字母 P 或 LP 领头的,比方 LPDWOTucsonD 或
PINT。在此三个例子中,LP 和 P
提醒参数是叁个指南针,而它们照准的数据类型分别为
DWO奔驰G级D 或
INT。不过,在多少意况下,能够一贯动用 C
语言语法中的星号 (*) 将 API
函数定义为指针。以下代码片段体现了那地点的演示:

Api函数是建筑Windws应用程序的基石,每风姿罗曼蒂克种Windows应用程序开垦工具,它提供的底层函数都直接或直接地调用了Windows
API函数,相同的时间为了落时效果与利益扩张,平日也都提供了调用WindowsAPI函数的接口,
也正是说具有调用动态连接库的能力。Visual
C#和其他开拓工具相同也能够调用动态链接库的API函数。.NET框架本人提供了那样大器晚成种服务,允许受管辖的代码调用动态链接库中落到实处的非受管辖函数,满含操作系统提供的Windows
API函数。它能够牢固和调用输出函数,依据需求,协会其各类参数(整型、字符串类型、数组、和组织等等卡塔尔高出互操作边界。

void TakesAPointer(DWORD* pNum);

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

能够看看,上述函数的天下无双三个参数是指向 DWO传祺D 变量的指针。

 动态链接库函数声明部分日常由下列两局部构成,一是函数名或索引号,二是动态链接库的公文名。
 
例如,你想调用User32.DLL中的MessageBox函数,大家必得指明函数的名字Message博克斯A或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);

假定你对援用类型和值类型之间的反差不是很熟识,请查阅 二〇〇〇 年 12 月发行的 MSDN? Magazine,在 .NET
专栏的主旨中得以找到更加的多音信。大大多 CL奥德赛类型都以援用类型;然则,除了 System.String

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

 此中入口点EntryPoint标记函数在动态链接库的入口地点,在一个受管辖的工程中,指标函数的本来名字和序号入口点不唯有标志贰个当先互操作界限的函数。并且,你还能把那些入口点映射为三个不意气风发的名字,相当于对函数举办重命名。重命名能够给调用函数带给各种便利,通过重命名,一方面大家不用为函数的大大小小写伤透脑筋,同有的时候候它也得以有限支撑与原来就有个别命名准绳保持风姿浪漫致,允许带有不一致参数类型的函数共存,更关键的是它简化了对ANSI和Unicode版本的调用。CharSet用于标记函数调用所选择的是Unicode或是ANSI版本,ExactSpelling=false将告诉编写翻译器,让编写翻译器决定运用Unicode可能是Ansi版本。别的的参数请参见MSDN在线扶助.

封送不透明 (Opaque卡塔尔(قطر‎ 指针:风姿浪漫种奇特情状

 在C#中,你能够在EntryPoint域通过名字和序号声爱他美个动态链接库函数,假使在点子定义中采取的函数名与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表明的布局或类成员,通过它可以保证个中间成员预期的构造音信。结构的选料共有三种:


叁个不透明指针再次回到给您的应用程序(或然您的应用程序期望获得一个不透明指针)时,您应该将参数或重返值封送为 CLLX570 中的生机勃勃种奇特连串—
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;

在 CLKoleos 类型系统中,System.IntPtr
类型有一个特有的性质。不像系统中的其余基类型,IntPtr
并从未一定的深浅。相反,它在运维时的轻重是依底层操作系统的通常化指针大小而定的。那代表在 32 位的 Windows 中,IntPtr 变量的急剧是 叁11个人的,而在 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 位或 六拾叁人的整数值,或将前者免强调换为前端。可是,当使用 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);

第3个原因是,当供给进行 P/Invoke
时,要管理公事还索要极其精晓到 C
和 CL君越 管理文件的点子是例外的。在 C 中,字符串实际上只是二个字符值数组,日常以 null 作为达成符。大相当多 Windows
API 函数是奉公守法以下法规管理字符串的:对于
ANSI,将其作为字符值数组;对于
Unicode,将其作为宽字符值数组。

类成员的传递
黄金时代律假若类具备贰个固定的类成员构造,你也得以传递三个类成员给一个不受管辖的动态链接库函数,上边包车型大巴例证首要表明什么传递八个sequential顺序定义的MySystemTime类给User32.dll的GetSystemTime函数,
函数用C/C++调用典型如下:

侥幸的是,CL宝马X3被规划得一定灵活,当封送文本时难题能够轻便解决,而不用在乎 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
(窗口枚举卡塔尔国函数. 上边以窗口枚举为例,谈谈怎么样通过调用EnumWindow
函数遍历系统中设有的兼具窗口

? 您的表面方法应该选取什么托管类型?

分下边多少个步骤:

? API 函数期望得到的是怎么着格式的非托管字符串?

  1. 在促成调用前先参照他事他说加以考察函数的申明
    BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARMAM IParam)
    路人皆知这一个函数要求叁个回调函数地址作为参数.
    2.
    创造二个受管辖的回调函数,这一个例子表明为表示类型(delegateState of Qatar,也正是大家所说的回调,它饱含七个参数hwnd和lparam,第二个参数是多少个窗口句柄,第二个参数由应用程序定义,八个参数均为整形。

自个儿们首先解答最终一个题目。大超多 Windows API
函数都蕴含 LPTST大切诺基 或
LPCTSTRubicon值。(从函数角度看)它们分别是可修改和不可改良的缓冲区,包括以 null 甘休的字符数组。“C”代表常数,意味着使用该参数新闻不会传送到函数外界。LPTSTRAV4 中的“T”阐明该参数能够是 Unicode

ANSI,决计于你采纳的字符集和后面部分操作系统的字符集。因为在 Windows API
中山大学超多字符串参数都以这两连串型之风流倜傥,所以只要在 DllImportAttribute 中挑选CharSet.Auto,CL福睿斯就按暗中认可的点子专门的职业。

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

可是,有个别 API 函数或自定义的 DLL
函数采纳分歧的章程意味着字符串。若是您要用到二个这么的函数,就可以运用 MarshalAsAttribute
修饰外界方法的字符串参数,并指明风姿浪漫(Wissu卡塔尔国种不一样于暗许LPTSTTiggo 的字符串格式。有关 MarshalAsAttribute
的越多音信,请参阅坐落于 MarshalAsAttribute
Class 的 Platform SDK 文书档案主旨。

  1. 最终创设以象征对象(delegate卡塔尔国,并把它看做两个参数字传送递给EnumWindows
    函数,平台会自行地 把象征转产生函数能够分辨的回调格式。

这段日子让我们看一下字符串音信在你的代码和非托管函数之间传递的大势。有三种情势得以知晓管理字符串时新闻的传递方向。第叁个也是最有限帮忙的贰个格局正是首先知道参数的用场。比如,您正调用叁个参
数,它的名目肖似 CreateMutex
并含有多少个字符串,则能够想像该字符串音讯是从应用程序向 API 函数字传送递的。同临时间,假若你调用
GetUserName,则该函数的称呼注明字符串音讯是从该函数向您的应用程序传递的。

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

除了这种相比客观的方式外,第三种检索音信传递方向的方法正是寻觅 API 参数类型中的字母“C”。举例,GetUserName API
函数的率先个参数被定义为 LPTST奥德赛类型,它意味着两个针对性 Unicode 或 ANSI 字符串缓冲区的长指针。不过CreateMutex 的名称参数被项目化为
LTCTSTTiguan。请小心,这里的类型定义是同样的,但净增二个字母“C”来申明缓冲区为常数,API
函数无法写入。

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

借使明显了文件参数是只用作输入照旧作为输入/输出,就足以显明使用哪一类 CL奥迪Q5类型作为参数类型。这里有一点准绳。假诺字符串参数只用作输入,则运用 System.String
类型。在托管代码中,字符串是不变的,符合用于不会被本机 API 函数校勘的缓冲区。

public class EnumReportApp {

要是字符串参数能够作为输入和/或输出,则接收 System.StringBuilder 类型。StringBuilder
类型是一个很有用的类库类型,它能够援救你有效地营造字符串,也刚巧能够将缓冲区传递给本机函数,由本机函数为你填充字符串数据。风流浪漫旦函数调用重回,您只要求调用 StringBuilder 对象的 ToString
就足以拿走叁个 String 对象。

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

GetShortPathName 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
能够是二个将细节和低端比特藏在当中的着实的潘Dora盒子。CL兰德途睿欧、C# 和托管 C++
提供了成都百货上千有效的成效;可能以往作者会在本专栏介绍高档的 P/Invoke 话题。

 上面这些函数通过调用GetUserName得到客商名
BOOL GetUserName(
LPTSTSportage lpBuffer, // 客商名缓冲区
LPDWO奥迪Q5D 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字符串,相近你也足以声多美滋(Dumex卡塔尔个独有多少个成分的长整型数组,使用数组名作为第一个参数。下面的函数能够调用如下:

再正是,只要您感到 .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
(便携式操作系统接口State of Qatar,OS/2 console API ;同期Windows 95
supports MS-DOS, Win16 和Win32
API。
Win16 和 Win32 API:
WIN16 是依赖13位的Computer,并接收拾八个人的值,它是一个单独的阳台。举个例子:你能够运作TS兰德瑞虎 程序在MS-DOS遭逢下。
WIN32 是依靠三十六人的计算机,并动用33位的值。他可用以其余操作系统,它的选择范围更广。
Win32 API has 32 prefix after the library name e.g. KERNEL32, USER32
etc?
Win32 API的DLL平时都独具32的后缀,举个例子:KE大切诺基NEL32,
USEF12berlinetta32等。
怀有的API都在底下3个DLL中落实的。
Kernel
User
GDI

<> <>

  1. KERNEL
    它的库名是:KELX570NEL32.DLL,它是操作系统管理的API集
    Process loading. 加载进度
    Context switching.
    File I/O. 文件操作
    Memory management. 内存管理
    比方说:GlobalMemoryStatus
    函数获得近些日子系统物理虚构内部存款和储蓄器的接纳新闻。
  2. USER
    在WIN32下,它的库名是 USEKoleos32.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使用构造来传递、再次回到参数,那样能够减少复杂度。它也允许行使象Message博克斯 函数那样,使用一定的参数。

在开关的点击事件中加进上面代码:
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域通过名字和序号声澳优个动态链接库函数,假使在艺术定义中央银行使的函数名与DLL入口点相同,你无需在EntryPoint域呈现证明函数。不然,你必须要利用下列属天性式提示四个名字和序号。

[DllImport(“dllname”, EntryPoint=”Functionname”)]
[DllImport(“dllname”, EntryPoint=”#123″)]
值得注意的是,你必需在数字序号前加“#”
上面是一个用Msg博克斯替换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的GetSystem提姆e函数,
函数用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(打字与印刷机卡塔尔, 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函数调用时,超过50%函数选拔指针传递参数,对叁个布局变量指针,我们除了行使方面包车型客车类和组织情势传递参数之外,大家一时候还足以利用数组传递参数。

上面这一个函数通过调用GetUserName拿到顾客名
BOOL GetUserName(
LPTSTMurano lpBuffer, // 顾客名缓冲区
LPDWOHavalD 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类代替那些参数类型,当然你还足以声圣元(Beingmate卡塔尔(قطر‎个字节数组传递ANSI字符串,相像你也足以声明一(WissuState of Qatar个唯有三个成分的长整型数组,使用数组名作为第二个参数。上边包车型大巴函数能够调用如下:

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地图