C#中怎么调用WinAPI函数

在C#中不时需要调用一些API函数,那么怎么样才能正确的调用API函数呢,如下:

 

一、调用API格式

 

//引用此称呼空间,简化后边的代码

usingSystem.Runtime.InteropServices;

 

//使用DllImportAttribute特性来引入api函数,注意表明的是空方法,即方法体为空。

[DllImport(“user32.dll”)]

publicstaticexternReturnTypeFunctionName(typearg1,typearg2,…);

 

 

可以运用字段进一步印证特性,用逗号隔开,如:

[DllImport(“kernel32″,EntryPoint=”GetVersionEx”,SetLastError=true)]

 

DllImportAttribute特性的多少个国有字段如下:

 

1、CallingConvention:提示向非托管实现传递模式参数时所用的CallingConvention值。

CallingConvention.Cdecl:调用方清理堆栈。它使你可以调用具有varargs的函数。

CallingConvention.StdCall:被调用方清理堆栈。它是从托管代码调用非托管函数的默认约定。

 

2、CharSet:控制调用函数的称呼版本及提醒咋样向方法封送String参数。

此字段被设置为CharSet值之一。如果CharSet字段设置为Unicode,则拥有字符串参数在传递到非托管实现在此以前都转换成Unicode字符。这还造成向DLLEntryPoint的名号中加进字母“W”。假诺此字段设置为Ansi,则字符串将转移成ANSI字符串,同时向DLLEntryPoint的称呼中加进字母“A”。大多数Win32API利用这种扩张“W”或“A”的约定。假使CharSet设置为Auto,则这种转移就是与平台有关的(在WindowsNT上为Unicode,在Windows98上为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,则匹配规则与平台有关(在WindowsNT上为Unicode,在Windows98上为Ansi)。假如ExactSpelling设置为true,则唯有当DLL中设有“MyMethod”时才回到“MyMethod”。

 

3、EntryPoint:指示要调用的DLL入口点的称呼或序号。

比方你的章程名不想与api函数同名的话,一定要指定此参数,例如:

[DllImport(“user32.dll”,CharSet=”CharSet.Auto”,EntryPoint=”MessageBox”)]

publicstaticexternintMsgBox(IntPtrhWnd,stringtxt,stringcaption,inttype);

 

4、ExactSpelling:提示是否应修改非托管DLL中的入口点的名目,以与CharSet字段中指定的CharSet值相呼应。假设为true,则当DllImportAttribute.CharSet字段设置为CharSet的Ansi值时,向方法名称中增添字母A,当DllImportAttribute.CharSet字段设置为CharSet的Unicode值时,向方法的称谓中追加字母W。此字段的默认值是false。

 

5、PreserveSig:提醒托管方法签名不应转换成重回HRESULT、并且可能有一个对应于再次来到值的叠加[out,retval]参数的非托管签名。

 

6、SetLastError:指示被调用方在从属性化方法重回在此之前将调用Win32APISetLastError。true指示调用方将调用SetLastError,默认为false。运行时封送拆收器将调用GetLastError并缓存重回的值,以防其被其他API调用重写。用户可通过调用GetLastWin32Error来查找错误代码。

 

二、参数类型:

1、数值型直接用相应的就可。(DWORD->int,或uint,WORD->Int16)

2、API中字符串指针类型->.net中string,或者数组,如byte[]

3、API中句柄(dWord)->.net中IntPtr

4、API中社团->.net中社团依然类。注意这种情景下,要先用StructLayout特性限定注解结构或类

 

国有语言运行库利用StructLayoutAttribute控制类或结构的多寡字段在托管内存中的物理布局,即类或协会亟待按某种情势排列。假使要将类传递给需要指定布局的非托管代码,则显式控制类布局是重点的。它的构造函数中用LayoutKind值开始化StructLayoutAttribute类的新实例。LayoutKind.Sequential用于强制将成员按其现出的逐条进行依次布局。

LayoutKind.Explicit用于控制每个数据成员的高精度地方。利用Explicit,每个成员必须使用Field(Field)OffsetAttribute指示此字段在项目中的地方。如:

[StructLayout(LayoutKind.Explicit,Size=16,CharSet=CharSet.Ansi)]

publicclassMySystemTime

{

[FieldOffset(0)]publicushortwYear;

[FieldOffset(2)]publicushortwMonth;

[FieldOffset(4)]publicushortwDayOfWeek;

[FieldOffset(6)]publicushortwDay;

[FieldOffset(8)]publicushortwHour;

[FieldOffset(10)]publicushortwMinute;

[FieldOffset(12)]publicushortwSecond;

[FieldOffset(14)]publicushortwMilliseconds;

}

 

诸如:下面是API函数CreateNamedPipe的原函数:

WINBASEAPI

HANDLE

WINAPI

CreateNamedPipeW(

LPCWSTRlpName,

DWORDdwOpenMode,

DWORDdwPipeMode,

DWORDnMaxInstances,

DWORDnOutBufferSize,

DWORDnInBufferSize,

DWORDnDefaultTimeOut,

LPSECURITY_ATTRIBUTESlpSecurityAttributes

);

在C#中可这般调用(封装在类NamedPipeNative当中):

[DllImport(“kernel32.dll”,SetLastError=true)]

publicstaticexternIntPtrCreateNamedPipe(

       StringlpName,                                                        

       uintdwOpenMode,                                                  

       uintdwPipeMode,                                                   

       uintnMaxInstances,                                                

       uintnOutBufferSize,                                         

      
uintnInBufferSize,

      
uintnDefaultTimeOut,

       IntPtrpipeSecurityDescriptor       

);

 

采纳实例:

IntPtrm_HPipe=NamedPipeNative.CreateNamedPipe(m_PipeName,

NamedPipeNative.PIPE_ACCESS_DUPLEX,//数据双工通信

NamedPipeNative.PIPE_TYPE_MESSAGE|NamedPipeNative.PIPE_WAIT,//字节流,并且阻塞

100,//最大实例个数

128,//流出数据缓冲大小

128,//流入数据缓冲大小

150,//超时,毫秒

IntPtr.Zero//安全新闻

);

其中CreateNamedPipe函数,还有PIPE_ACCESS_DUPLEX,PIPE_TYPE_MESSAGE,PIPE_WAIT等字段都封装在类NamedPipeNative当中,以便于调用。

相关文章