C#调用windowsAPI函数

一 调用格式

C#在调用windowsAPI函数接口的时候有一套专门的调用流程

首先我们在调用API函数的时候必须引用命名空间InteropServices

using System.Runtime.InteropServices;

例如我们想调用windows的kernel32.dll动态库中的接口函数中的AllocConsole()控制台函数接口

下面我们用最简单的调用形式来声明调用此函数接口(空方法,即方法体为空)

[DllImport("kernel32.dll")]

public static extern bool AllocConsole();

 

下面我们可以用DllImportAttribute特性添加字段进一步说明

1 CallingConvention

指示向非托管实现传递方法参数时所用的CallingConvention值

CallingConvention.Cded:调用方清理堆栈。他使用你能够调用具有varargs的函数

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

2 CharSet

控制调用函数的名称版本及指示如何向方法封送String参数

CharSet.Ansi:所有字符串转换成ANSI字符串,同时向DLL EnterPoint的名称中追加字母”A“

CharSet.Unicode:所有字符串参数在传递到非托管实现之前都转换成Unicode字符;向DLL EnterPoint的名称中追加字母"W"

CharSet.Auto:这种转换就与平台有关(例如在windows NT上位unicode,而在windows 98上为Ansi)。

CharSet的默认值为Ansi

3 EnterPoint

指示要调用的DLL入口点的名称或序号

如果你的方法名不想与api函数同名的话,一定要指定此参数

例如我想调用user32.dll中的MessageBox函数但是我想以自己的名字MsgBox名字来命名的话

[DllImport("user32.dll",CharSet="CharSet.Auto",EnterPoint="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 SerLastError

指示被调用方法从属性化方法返回值之前调用win32 API SetLastError。

true指示调用方将调用SetLastError,默认为false。运行时封送拆收器调用GetLastError并缓存返回的值,以防其他API调用重写。

 

二 参数类型转换

C++ C#
DWORD int
WORD Int16
字符串指针类型 string
句柄(handle、hWnd) IntPtr
结构或者类 要先用StructLayout特性限定声明结构或类

1 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;

2 Sequential

用于强制将成员按出现的顺序进行顺序布局

例如针对API中的OSVERSIONINFO结构,在.net中定义类或者结构的例子如下

API原型

* 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;
}

注意:结构作为参数的时候,一般前面要加上ref修饰符,否则会出现错误:对象的引用没有指定对象的实例

原文请访问:http://www.jb51.net/article/46041.htm

posted @ 2015-06-28 00:20  DannyCat  阅读(1408)  评论(0编辑  收藏  举报