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

by admin on 2020年1月21日

C# API
C:ProgramFilesMicrosoftVisual Studio .NET FrameworkSDKSamples
Technologies InteropPlatformInvoke WinAPIsCS目录下有大批量的调用API的事例。
风姿浪漫、调用格式
using System.Runtime.InteropServices; //引用此称呼空间,简化前面包车型大巴代码
//使用DllImportAttribute天性来引进api函数,注意证明的是空方法,即方法体为空。
[DllImport(“user32.dll”)]
public static extern ReturnType FunctionName(type arg1,type arg2,…);
//调用时与调用其他艺术并无不一致

能够动用字段进一层评释个性,用逗号隔开分离,如:
[ DllImport( “kernel32″, EntryPoint=”GetVersionEx” )]
DllImportAttribute性情的公物字段如下:
1、CallingConvention
提醒向非托管完毕传递格局参数时所用的
CallingConvention 值。
CallingConvention.Cdecl : 调用方清理商旅。它使您能够调用具备 varargs 的函数。
CallingConvention.StdCall :
被调用方清理货仓。它是从托管代码调用非托管函数的暗中同意约定。
2、CharSet
调节调用函数的名目版本及提醒如何向方法封送
String 参数。
此 字段棉被服装置为 CharSet
值之豆蔻梢头。借使 CharSet 字段设置为
Unicode,则具有字符串参数在传递到非托管实现早先都更改来 Unicode 字符。那还导致向 DLL
EntryPoint 的名目中追加字母“W”。要是此字段设置为
Ansi,则字符串将改变来 ANSI
字符串,同有的时候候向 DLL EntryPoint
的称号中扩大字母“A”。大非常多 Win32 API 使用这种扩张“W”或“A”的预约。假如 CharSet 设置为
Auto,则这种转移就是与平台有关的(在 Windows
NT 上为 Unicode,在
Windows 98 上为 Ansi)。CharSet 的暗许值为
Ansi。CharSet
字段也用于明确将从钦命的 DLL
导入哪个版本的函数。CharSet.Ansi
和 CharSet.Unicode
的称呼相配法则大不相符。对于 Ansi
来讲,假使将 EntryPoint 设置为“MyMethod”且它存在的话,则赶回“MyMethod”。要是 DLL
中尚无“MyMethod”,但存在“MyMethodA”,则赶回“MyMethodA”。对于 Unicode
来讲则刚刚相反。即使将 EntryPoint
设置为“MyMethod”且它存在的话,则赶回“MyMethodW”。假如 DLL
中不设有“MyMethodW”,但存在“MyMethod”,则赶回“MyMethod”。如若使用的是
Auto,则杰出法则与平台有关(在 Windows NT
上为 Unicode,在
Windows 98 上为 Ansi)。假诺 ExactSpelling 设置为
true,则独有当 DLL 中存在“MyMethod”时才重临“MyMethod”。
3、EntryPoint 指示要调用的 DLL 入口点的名号或序号。
只要你的形式名不想与api函数同名的话,必定要内定此参数,比如:
[DllImport(“user32.dll”,CharSet=”CharSet.Auto”,EntryPoint=”MessageBox”)]
public static extern int MsgBox(IntPtr hWnd,string txt,string caption,
int type);
4、 ExactSpelling
提示是还是不是应修正非托管 DLL
中的入口点的名号,以与 CharSet
字段中钦定的 CharSet
值相对应。假如为 true,则当 DllImportAttribute.CharSet 字段设置为 CharSet 的 Ansi
值时,向方法名称中追加字母 A,当 DllImportAttribute.CharSet 字段设置为 CharSet 的 Unicode
值时,向方法的名称中扩充字母
W。此字段的暗许值是 false。
5、PreserveSig
提示托管方法签字不应转变到返回HRESULT、並且恐怕有贰个相应于再次回到值的附加
[out, retval] 参数的非托管署名。
6、 SetLastError
提醒被调用方在从属性化方法重临在此之前将调用 Win32
API SetLastError。 true
指示调用方将调用SetLastError,默感到false。运维时封送拆收器将调用 GetLastError
并缓存再次回到的值,以免其被此外 API
调用重写。客商可通过调用 GetLastWin32Error
来查找错误代码。

二、参数类型:
1、数值型直接用相应的就可。(DWOMuranoD -> int , WOPRADOD -> Int16)
2、API中字符串指针类型 -> .net中string
3、API中句柄 (dWord)
-> .net中IntPtr
4、API中构造 ->
.net中布局依旧类。注意这种状态下,要先用StructLayout个性节制证明布局或类
公 共语言运行库利用StructLayoutAttribute调节类或布局的数码字段在托管内存中的物理布局,即类或协会亟待按某种方式排列。固然要将类
传递给要求内定构造的非托管代码,则显式控制类布局是器重的。它的布局函数中用LayoutKind值初步化 StructLayoutAttribute 类的新实例。 LayoutKind.Sequential
用于抑遏将成员按其现身的逐个举行逐项结构。
LayoutKind.Explicit 用于调整每一个数据成员的准确地方。利用 Explicit,每个成员必得选取FieldOffsetAttribute 提醒此字段在档案的次序中之处。如:
[StructLayout(LayoutKind.Explicit, Size=16, CharSet=CharSet.Ansi)]
public class MySystemTime
{
[FieldOffset(0)]public ushort wYear;
[FieldOffset(2)]public ushort wMonth;
[FieldOffset(4)]public ushort wDayOfWeek;
[FieldOffset(6)]public ushort wDay;
[FieldOffset(8)]public ushort wHour;
[FieldOffset(10)]public ushort wMinute;
[FieldOffset(12)]public ushort wSecond;
[FieldOffset(14)]public ushort wMilliseconds;
}
上边是照准API中OSVEOdysseySIONINFO构造,在.net中定义对应类或组织的事例:
/**********************************************
* API中定义原构造注解
* OSVERSIONINFOA STRUCT
* dwOSVersionInfoSize DWORD ?
* dwMajorVersion DWORD ?
* dwMinorVersion DWORD ?
* dwBuildNumber DWORD ?
* dwPlatformId DWORD ?
* szCSDVersion BYTE 128 dup (?)
* OSVERSIONINFOA ENDS
*
* OSVERSIONINFO equ <OSVERSIONINFOA>
*********************************************/

//.net中扬言为类
[ StructLayout( LayoutKind.Sequential )]
public class OSVersionInfo
{
public int OSVersionInfoSize;
public int majorVersion;
public int minorVersion;
public int buildNumber;
public int platformId;

[ MarshalAs( UnmanagedType.ByValTStr, SizeConst=128 )]
public String versionString;
}
//或者
//.net中声称为布局
[ StructLayout( LayoutKind.Sequential )]
public struct OSVersionInfo2
{
public int OSVersionInfoSize;
public int majorVersion;
public int minorVersion;
public int buildNumber;
public int platformId;

[ MarshalAs( UnmanagedType.ByValTStr, SizeConst=128 )]
public String versionString;
}

此例中用到MashalAs天性,它用于描述字段、方法或参数的封送管理格式。用它作为参数前缀并钦命目的要求的数据类型。比方,以下代码将五个参数作为数据类型长指针封送给 Windows API 函数的字符串
(LPStr卡塔尔国:
[MarshalAs(UnmanagedType.LPStr)]
String existingfile;
[MarshalAs(UnmanagedType.LPStr)]
String newfile;

留意组织作为参数时候,日常前边要抬高ref修饰符,不然会产出错误:对象的援用没有一些名对象的实例。
[ DllImport( “kernel32″, EntryPoint=”GetVersionEx” )]
public static extern bool GetVersionEx2( ref OSVersionInfo2 osvi
);

三、怎么着保障使用托管对象的平台调用成功?
倘诺在调用平台 invoke
后的此外岗位都未援引托管对象,则垃圾回笼器也许将不负职分该托管对象。这将释放财富并使句柄无效,进而引致平台invoke 调用失利。用 HandleRef
包装句柄可保险在凉台 invoke
调用完结前,不对托管对象开展垃圾回收。
举例下边:
FileStream fs = new FileStream( “a.txt”, FileMode.Open );
StringBuilder buffer = new StringBuilder( 5 );
int read = 0;
ReadFile(fs.Handle, buffer, 5, out read, 0 ); //调用Win API中的ReadFile函数
是因为fs是托管对象,所以有望在平台调用尚未产生时候被垃圾回收站回笼。将文件流的句柄用HandleRef包装后,就会幸免被垃圾站回笼:
[ DllImport( “Kernel32.dll” )]
public static extern bool ReadFile(
HandleRef hndRef,
StringBuilder buffer,
int numberOfBytesToRead,
out int numberOfBytesRead,
ref Overlapped flag );
……
……
FileStream fs = new FileStream( “HandleRef.txt”, FileMode.Open );
HandleRef hr = new HandleRef( fs, fs.Handle );
StringBuilder buffer = new StringBuilder( 5 );
int read = 0;
// platform invoke will hold reference to HandleRef until call ends
ReadFile( hr, buffer, 5, out read, 0 );

本身在团结方今的编制程序中注意到二个趋向,就是那么些方向才引出前些日子的特辑核心。这两天,小编在依靠 Microsoft? .NET Framework
的应用程序中产生了大气的 Win32?
Interop。小编实际不是要说我的应用程序充满了自定义的 interop 代码,但神迹作者会在 .NET
Framework
类库中遇到一些说不上但又繁絮、不充足的从头到尾的经过,通过调用该 Windows? API,能够高速减弱那样的分神。

由此笔者以为,.NET Framework 1.0 或 1.1 版类库中设有别的 Windows
所未有的法力约束都不足为奇。毕竟,三11人的
Windows(不管何种版本)是多少个早熟的操作系统,为广大客商服务了十多年。相比较之下,.NET Framework 却是贰个新东西。

趁着越多的开辟职员将分娩应用程序转到托管代码,开垦人士更频仍地钻研底层操作系统以图搜索部分注重意义显得很自然—起码目前是如此。


得庆幸的是,公共语言运维库 (CL哈弗卡塔尔 的 interop 功效(称为平台调用 (P/Invoke))特别完美。在本专栏中,小编将入眼介绍怎么着实际行使 P/Invoke 来调用 Windows API
函数。当指 CL中华V 的
COM Interop 效能时,P/Invoke
当做名词使用;当指该意义的接纳时,则将其视作动词使用。小编并不计划直接介绍 COM Interop,因为它比 P/Invoke
具备越来越好的可访谈性,却越来越树大根深,那有一些破绽超多,这使得将 COM Interop 作为专栏宗旨来谈谈不太轻巧。

走进 P/Invoke

率先从考查三个精简的 P/Invoke 示例开端。让大家看大器晚成看怎样调用 Win32 MessageBeep
函数,它的非托管注脚如以下代码所示:

BOOL MessageBeep(
UINT uType // beep type
);

为了调用 MessageBeep,您须求在 C#
中校以下代码增加到三个类或构造定义中:

[DllImport(“User32.dll”)]
static extern Boolean MessageBeep(UInt32 beepType);

无不侧目的是,只必要这段代码就足以使托管代码调用非托管的 MessageBeep
API。它不是贰个主意调用,而是四个表面方法定义。(其它,它就像于一个源于 C 而 C#
允许的第一手端口,由此以它为起源来介绍一些概念是有救助的。)来自托管代码的或者调用如下所示:

MessageBeep(0);


注意,今后 MessageBeep 方法被声称为 static。那是 P/Invoke
方法所供给的,因为在该 Windows API
中一贯不相通的实例概念。接下来,还要注意该办法被标志为 extern。那是提醒编写翻译器该措施是透过叁个从 DLL 导出的函数实现的,由此无需提供方法体。

谈到缺少方法体,您是或不是注意到 MessageBeep
表明并不曾富含一个方法体?与大多数算法由中间语言 (IL卡塔尔国 指令组成的托管方法差异,P/Invoke 方法只是元数据,实时
(JIT卡塔尔国 编写翻译器在运转时通过它将托管代码与非托管的
DLL
函数连接起来。实践这种到非托管世界的连天所需的一个着重音讯正是导出非托管方法的 DLL 的名目。那意气风发消息是由
MessageBeep 方法注解在此之前的 DllImport
自定义属性提供的。在本例中,可以见见,MessageBeep 非托管 API
是由 Windows 中的
User32.dll 导出的。

到近来结束,关于调用 MessageBeep
就剩五个话题从未介绍,请回忆一下,调用的代码与以下所示代码片段特别相似:

[DllImport(“User32.dll”)]
static extern Boolean MessageBeep(UInt32 beepType);

最终这四个话题是与数码封送处理 (data marshalingState of Qatar和从托管代码到非托管函数的实际措施调用有关的话题。调用非托管 MessageBeep 函数能够由找到效能域内的extern MessageBeep
证明的别的托管代码实行。该调用相符于任何其余对静态方法的调用。它与别的任何托管方法调用的协同的地方在于带给了数码封送管理的急需。

C# 的法则之一是它的调用语法只可以访谈 CL奇骏 数据类型,举例 System.UInt32
和 System.Boolean。C# 鲜明不识别 Windows API
中央银行使的依据 C 的数据类型(比方 UINT 和
BOOL),那一个项目只是 C
语言类型的类型定义而已。所以当 Windows API
函数 MessageBeep 按以下方法编写时

BOOL MessageBeep( UINT uType )

表面方法就务须选用 CLENVISION类型来定义,如你在前边的代码片段中所看见的。需求接受与根底 API 函数类型区别但与之相称的 CLENCORE类型是 P/Invoke
较难使用的一个上边。因而,在本专栏的前边小编将用全体的章节来介绍数据封送管理。

样式

在 C# 中对 Windows API
进行 P/Invoke
调用是非常粗大略的。但假设类库拒却使您的应用程序发出嘟声,应该设法调用 Windows 使它进行那项职业,是吧?


的。不过与选拔的措施有关,并且关系甚大!经常,借使类库提供某种门路来促成您的构思,则最棒使用 API 而不用平昔调用非托管代码,因为 CLEvoque 类型和 Win32
之间在样式上有不小的不及。作者得以将有关那些主题材料的提出归咎为一句话。当你实行 P/Invoke
时,不要使应用程序逻辑直接归属别的外界方法或内部的预制构件。要是您遵守这些小法则,从浓厚看平常会省去过多的艰辛。

图 1 中的代码展现了本身所探讨的
MessageBeep 外界方法的起码叠合代码。图 1中并从未其余鲜明的扭转,而只是对无包装的外表方法开展局部不足为道的改过,那能够使专业愈发安闲自得局地。从最上部始发,您会注意到二个名字为 Sound 的生龙活虎体化类型,它专项使用于
MessageBeep。若是自个儿急需选用 Windows API
函数 PlaySound
来增多对播放波形的扶持,则能够援用 Sound
类型。然则,笔者不会因当着单个公共静态方法的种类而变色。终究那只是应用程序代码而已。还应当注意到,Sound
是密封的,并定义了二个空的民用布局函数。这个只是大器晚成对细节,目标是使客户不会错误地从 Sound 派生类只怕创建它的实例。

图 1 中的代码的下一个表征是,P/Invoke 现身岗位的莫过于外部方法是
Sound 的民用方法。这几个主意只是由集体
MessageBeep 方法间接公开,前者接纳 BeepTypes
类型的参数。那几个直接的额外层是三个很着重的内部原因,它提供了以下好处。首先,应该在类库中引进一个前途的 beep 托管方法,能够重新鸿基土地资金财产由此国有 MessageBeep 方法来行使托管
API,而不必修改应用程序中的别的代码。

该包装
方法的第一个低价是:当你实行 P/Invoke
调用时,您屏弃了免于访谈冲突和其他低档破坏的职分,那经常是由 CLLacrosse提供的。缓冲方法能够保险你的应用程序的别的部分免接收访谈问矛盾及相似主题素材的震慑(固然它不做任何事而只是传递参数)。该缓冲方法将由 P/Invoke 调用引进的别的交秘书密的大谬不然本地化。

将民用外界方法掩盖在公私包装后边的第三并且也是最终的二个好处是,提供了向该方法加多一些比超级小的 CL奥德赛 样式的空子。比方,在图 1中,小编将 Windows API 函数再次回到的 Boolean 失利转变来更像 CL君越的优良。作者还定义了贰个名称叫 BeepTypes
的枚举类型,它的积极分子对应于同该 Windows API
一同使用的定义值。由于 C#
不扶持定义,由此能够动用托管枚举类型来幸免幻数向一切应用程序代码扩散。

装进情势的最终三个益处对于简易的 Windows API 函数(如
MessageBeep)诚然是未足轻重的。不过当您早先调用更复杂的非托管函数时,您会开掘,手动将 Windows API 样式调换到对 CLSportage尤其协调的不二秘籍所拉动的裨益会更增添。越是盘算在任何应用程序中援用 interop
功用,越是应该认真地思虑包装的宏图。同有的时候间自身感觉,在非面向对象的静态包装措施中动用对 CL哈弗 友好的参数也决不不得以。

DLL Import 属性

现在是越来越深刻地张开研究的时候了。在对托管代码进行P/Invoke 调用时,DllImportAttribute
类型扮演着主要的角色。DllImportAttribute
的要紧职能是给 CL冠道 提示哪个 DLL 导出您想要调用的函数。相关
DLL 的称呼被作为三个布局函数参数字传送递给
DllImportAttribute。

万风流倜傥您不能自然哪个 DLL 定义了你要选用的 Windows API
函数,Platform SDK
文书档案将为您提供最佳的增援能源。在 Windows API
函数大旨文字周围尾声的岗位,SDK
文书档案内定了 C
应用程序要选用该函数必需链接的 .lib
文件。在差非常的少具备的景观下,该 .lib
文件具备与概念该函数的种类 DLL
文件少年老成律的名号。举例,假如该函数必要 C
应用程序链接到
Kernel32.lib,则该函数就定义在 Kernel32.dll
中。您能够在 MessageBeep
中找到有关 MessageBeep 的 Platform SDK
文档大旨。在该大旨结尾处,您会注意到它提议库文件是 User32.lib;那评释 MessageBeep
是从 User32.dll 中导出的。

可选的 DllImportAttribute 属性

除了那几个之外建议宿主 DLL 外,DllImportAttribute
还隐含了生机勃勃部分可选属性,在那之中五个特意有趣:EntryPoint、CharSet、SetLastError 和
CallingConvention。

EntryPoint 在不期待外界托管方法具备与 DLL
导出风流倜傥致的称谓的情况下,可以设置该属性来提醒导出的 DLL
函数的入口点名称。当你定义多少个调用相像非托管函数的外表方法时,那非常有用。其它,在 Windows 中还是能透过它们的序号值绑定到导出的 DLL 函数。尽管您需求这么做,则诸如“#1”或“#129”的 EntryPoint 值提醒 DLL
中国和北美洲托管函数的序号值并非函数名。

CharSet 对于字符集,并不是全体版本的 Windows 都以风华正茂律创造的。Windows
9x 种类产品缺乏重要的 Unicode
支持,而 Windows NT 和 Windows CE 种类则大器晚成初叶就使用
Unicode。在此些操作系统上运维的 CLEvoque将Unicode 用于
String 和 Char
数据的内部表示。但也不要顾忌—当调用 Windows 9x API
函数时,CLTiggo会自动举办须求的调换,将其从
Unicode转变为 ANSI。

设若 DLL 函数不以任何方法管理文件,则足以忽视 DllImportAttribute 的 CharSet
属性。但是,当 Char 或 String 数据是等式的大器晚成都部队分时,应该将 CharSet 属性设置为
CharSet.Auto。这样能够使 CL昂Cora依照宿主 OS
使用合适的字符集。若无显式地设置 CharSet
属性,则其暗中认可值为
CharSet.Ansi。那几个暗中同意值是有劣点的,因为对此在
Windows 二〇〇〇、Windows XP 和 Windows NT? 上进行的 interop
调用,它会被动地影响文本参数封送管理的性子。

有道是显式地采取 CharSet.Ansi 或 CharSet.Unicode
的 CharSet 值并不是使用 CharSet.Auto
的唯风姿浪漫意况是:您显式地内定了叁个导出函数,而该函数特定于那二种 Win32 OS 中的某意气风发种。ReadDirectoryChangesW API
函数正是那般的叁个事例,它只设有于依附 Windows
NT 的操作系统中,何况只补助Unicode;在这里种场地下,您应该显式地行使
CharSet.Unicode。

一时,Windows API
是不是有字符集关系并不显眼。生机勃勃种决不会有错的承认办理法是在 Platform SDK 中反省该函数的 C
语言头文件。(借让你无法自然要看哪个头文件,则足以查看 Platform SDK 文书档案中列出的各样API 函数的头文件。)假诺你开采该 API
函数确实定义为八个映射到以 A 或 W
结尾的函数名的宏,则字符集与你尝试调用的函数有提到。Windows API 函数的八个事例是在
WinUser.h 中声称的 GetMessage
API,您只怕会诡异域开掘它有 A 和 W 二种版本。

SetLastError 错误管理特别重要,但在编制程序时日常被忘记。当你进行 P/Invoke 调用时,也会晤前蒙受别的的挑战—处理托管代码中 Windows API
错误处理和特别之间的区分。笔者能够给你一点提议。

假使您正在使用 P/Invoke 调用
Windows API 函数,而对于该函数,您使用
GetLastError 来研究扩大的错误消息,则应该在外界方法的 DllImportAttribute 中将SetLastError 属性设置为
true。那适用于大多数表面方法。

这会促成 CL奔驰G级 在每一回调用外界方法之后缓存由
API 函数设置的大错特错。然后,在包装措施中,能够通过调用类库的 System.Runtime.InteropServices.马尔斯hal
类型中定义的 Marshal.GetLastWin32Error
方法来获得缓存的不当班值日。小编的提议是检查这个愿意来自 API
函数的荒谬值,并为那几个值引发三个可感知的非常。对于其余具备波折境况(包罗根本就没意料到的曲折情形),则吸引在 System.ComponentModel 命名空间中定义的 Win32Exception,并将
Marshal.GetLastWin32Error
重回的值传递给它。即便你回头看一下图 1中的代码,您会看见自家在 extern MessageBeep
方法的公共包装中就使用了这种措施。

CallingConvention 作者将要这里介绍的最终也是有可能是最不重要的一个 DllImportAttribute 属性是
CallingConvention。通过此属性,能够给 CL奇骏提示应该将哪个种类函数调用约定用于宾馆中的参数。CallingConvention.Winapi
的暗中认可值是最佳的选取,它在大多情形下都使得。不过,倘诺该调用不起功能,则足以检查 Platform SDK 中的申明头文件,看看你调用的 API 函数是不是是叁个不切合调用约定标准的特别 API。

习认为常,本机函数(举例 Windows API 函数或 C-
运转时 DLL
函数)的调用约定描述了何等将参数推入线程货仓或从线程宾馆中革除。大许多 Windows API
函数都以第风流倜傥将函数的末段三个参数推入饭店,然后由被调用的函数负担清理该旅馆。相反,好多 C-运营时 DLL
函数都被定义为遵从措施参数在情势具名中冒出的相继将其推入货仓,将饭店清理专门的学问交给调用者。

有幸的是,要让 P/Invoke
调用专门的学业只需求让外围设备掌握调用约定就可以。平常,从暗许值 CallingConvention.Winapi
从前是最佳的采取。然后,在 C
运转时 DLL
函数和个别函数中,也许供给将预定改正为
CallingConvention.Cdecl。

多少封送管理


据封送管理是 P/Invoke
具备挑衅性的方面。当在托管和非托管代码之间传递数据时,CLEnclave据守超级多平整,很罕有开拓职员会常常遇上它们直至可将这几个法则记住。除非您是一名类库开采人士,不然在平常情况下不需求精通其细节。为了最可行地在 CLXC60 上使用
P/Invoke,即便只不时须求 interop
的应用程序开采职员依旧应该理解数据封送管理的一些基本功知识。

在上个月特刊的剩余部分中,小编将探讨简单数字和字符串数据的数码封送管理。笔者将从最主题的数字数据封送管理开端,然后介绍轻巧的指针封送管理和字符串封送管理。

封送数字和逻辑标量

Windows OS 超越八分之四是用 C 编写的。由此,Windows API
所用到的数据类型要么是 C
类型,要么是透过类型定义或宏定义重新标识的 C
类型。让大家看看未有指针的数目封送管理。简单起见,首先入眼商量的是数字和布尔值。

当通过值向 Windows API
函数字传送递参数时,需求通晓以下难点的答案:

? 数据从根本上讲是整型的还是浮点型的?

? 就算数额是整型的,则它是有标记的依然无符号的?

? 假如数额是整型的,则它的位数是有一点?

? 倘使数据是浮点型的,则它是单精度的照旧双精度的?

有的时候候答案很鲜明,但不常却不断定。Windows API 以各类形式重新定义了大旨的 C 数据类型。图 2
列出了 C 和 Win32
的一些公共数据类型及其标准,以致一个具备至极标准的公物语言运营库类型。

日常,只要您选取贰个其标准与该参数的 Win32
类型相相配的 CL本田CR-V类型,您的代码就可以看到健康办事。可是也可能有点特例。比方,在 Windows API 中定义的 BOOL
类型是一个有灯号的 叁拾三人整型。可是,BOOL 用于提醒 Boolean 值 true 或 false。尽管你不用将 BOOL
参数作为 System.Int32
值封送,不过若是使用 System.Boolean
类型,就能够得到更合适的照射。字符类型的投射相同于 BOOL,因为有三个一定的 CL昂科威类型 (System.Char)提出字符的含义。


掌握这么些消息之后,稳步介绍演示恐怕是有帮带的。依旧接收 beep 宗旨作为例子,让大家来试一下 Kernel32.dll 低档Beep,它会经过Computer的喇叭发生嘟声。这么些措施的 Platform SDK 文书档案能够在 Beep
中找到。本机 API
按以下格局进行记录:

BOOL Beep(
DWORD dwFreq, // Frequency
DWORD dwDuration // Duration in milliseconds
);


参数封送管理地点,您的做事是摸底怎么样 CL奥迪Q3数据类型与 Beep API 函数所使用的 DWOQX56D 和 BOOL
数据类型相相配。回看一下图 第22中学的图表,您将看到 DWO大切诺基D 是三个 32 位的无符号整数值,犹如 CL翼虎类型
System.UInt32。这象征你能够动用 UInt32
值作为送往 Beep 的几个参数。BOOL
再次回到值是二个万分有趣的图景,因为该图形告诉大家,在 Win32 中,BOOL
是一个 31位的有暗记整数。由此,您能够利用 System.Int32
值作为来自 Beep 的重返值。可是,CLGL450 也定义了 System.Boolean
类型作为 Boolean
值的语义,所以应该使用它来代替。CL讴歌MDX默许将 System.Boolean 值封送为 31人的有号子整数。此处所出示的外界方法定义是用于
Beep 的结果 P/Invoke 方法:

[DllImport(“Kernel32.dll”, SetLastError=true)]
static extern Boolean Beep(
UInt32 frequency, UInt32 duration);

指南针参数

许多 Windows API
函数将指针作为它们的三个或多个参数。指针扩大了封送数据的头晕目眩,因为它们扩展了三个直接层。若无指针,您能够经过值在线程宾馆中传递数据。有了指针,则能够透过引用传递数据,方法是将该数据的内部存款和储蓄器地址推入线程货仓中。然后,函数通过内部存储器地址间接待上访谈数据。使用托管代码表示此附加间接层的不二等秘书籍有三种。

在 C# 中,借使将艺术参数定义为 ref

out,则数据通过援引并不是透过值传递。固然你没有选取 Interop
也是那样,但只是从三个托管方法调用到另叁个托管方法。比方,假如通过 ref 传递 System.Int32
参数,则在线程仓库中传递的是该数据的地点,并不是整数值本人。上边是一个定义为通过援引选择整数值的办法的亲自去做:

void FlipInt32(ref Int32 num){
num = -num;
}

那边,FlipInt32 方法赢得贰个 Int32
值的地址、访谈数据、对它求反,然后将求反过的值赋给本来变量。在偏下代码中,FlipInt32 方法会将调用程序的变量
x 的值从 10 校勘为
-10:

Int32 x = 10;
FlipInt32(ref x);

在托管代码中得以选拔这种力量,将指针传递给非托管代码。举例,FileEncryptionStatus API 函数以
32 位无符号位掩码的花样重回文件加密状态。该
API 按以下所示方式进行记录:

BOOL FileEncryptionStatus(
LPCTSTR lpFileName, // file name
LPDWORD lpStatus // encryption status
);


注意,该函数并不应用它的返回值重回状态,而是重临一个Boolean
值,提醒调用是或不是成功。在成功的气象下,实际的气象值是通过第一个参数重返的。它的劳作措施是调用程序向该函数字传送递指向叁个 DWO索罗德D 变量的指针,而该 API
函数用状态值填充指向的内部存款和储蓄器地点。以下代码片段展现了二个调用非托管 FileEncryptionStatus 函数的恐怕外界方

发表评论

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

网站地图xml地图