C# 使用非托管库(DllImport)详细说明

要重用一个非托管库,其中不包含COM对象,只包含导出的功能,就可以使用平台调用(P/Invoke)。有了P/Invoke,CLRL会加载DLL,其中包含应调用的函数,并编组参数。

要使用非托管函数,首先必须确定导出的函数名。为此,可以使用dumpbin工具和/exports选项。例如,可在VS命令行中输入以下命令:

dumpbin /exports  c:\windows\system32\kernel32.dll | more

列出DLL kernel32.dll中所有导出的函数。以下使用Windows API函数CreateHardLink来创建到现有文件的硬链接。使用此API调用,可以用几个文件名引用相同的文件,只要文件名在一个硬盘上即可。这个API调用不能用于.NET Framework 4.5.1,因此必须使用平台调用。

为了调用本机函数,必须定义一个参数数量相同的C#外部方法,用非托管方法定义的参数类型必须用托管代码映射类型。在C++中,Windows API调用CreateHardLink有如下定义:

BOOL CreateHardLink(LPCTSTP lpFileName, LPCTSTR lpExistingFileName, LPSECURITY_ATTRINUTES lpSecurityAttributes);

  • 这个定义必须映射到.NET数据类型上。非托管代码的返回类型是BOOL;它仅映射到bool数据类型。LPCTSTR定义了一个指向const字符串的long指针。Windows API给数据类型使用Hungarian命名约定。
  • LP是一个long指针,
  • C是一个常量,
  • STR是以null结尾的字符串。
  • T把类型标志为泛型类型,根据编译器设置为32还是64位,该类型解析为LPCTSTR(ANSI字符串)或LPWSTR(宽Unicode字符串)。
  • C字符串(使用 null 字符 '\0' 终止的一维字符数组)映射到.NET类型位String
  • LPSECURITY_ATTRIBUTES是一个long指针,指向SECURITY_ATTRIBUTES类型结构。因为可以把NULL传递给这个传输,所以把这种类型映射到IntPtr是可行的。

该方法的C#声明必须用extern修饰符标记,因为在C#代码中,这个方法没有实现代码。相反,该方法的显示代码在DLL kernel32.dll中,它用属性【DllImport】引用。.NET声明CreateHardLink的返回类型bool,本机方法CreateHardLink返回一个布尔值,所以需要一些额外的澄清。因为C++有不同的Boolean(typedef unsigned char boolean)数据类型(例如,本机bool和Windows定义的BOOl有不同的值),所以特性【MarshalAs】指定.NET类型bool应该映射为哪个本机类型:

[DllImport("kernel32.dll", SetLastError = "true", EntryPoint = "CreateHardLink", CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CreateHardLink(string newFileName, string existiingFileName, IntPtr securityAttributes);

注意:网站http://www.pinvoke.net非常有助于从本机代码到托管代码的转换,而且提供了VS插件

【DlImport属性表】

DLLIMPORT属性或字段说明
EntryPoint

可以给函数的C#声明指定与非托管库不同的名称

非托管库方法名称在EntryPoint字段中定义

假设,在非托管库中有一个非托管方法 public void NotManagedMethod(int arg);

在C#中可以声明一个不同的方法名称,但实际指向的是该非托管方法。

[EntryPoint="NotManagedMethod"]

public void ManagedMethod(int arg);

此时,在C#中使用ManagedMethod,实际上调用非托管方法NotManagedMethod

CallingConvention

根据编译器或用来编译非托管函数的编译器设置,可以使用不同的调用约定。调用约定定义了如何处理参数,把他们放在堆栈的什么地方。可以设置一个可枚举的值,来定义调用约定。

 

Windows API通常

Windows      上使用StdCall调用约定

Windows CE上使用Cdecl调用约定。

把值设置为CallingConvention.Winapi,可让Windows API用与Windows和Windows CE环境

CharSet

非托管函数中字符串的管理方式

 

字符串参数可以是ANSI或Unicode。通过CharSet设置,可以定义字符串的管理方式。用CharSet枚举定义的值有Ansi、Unicode和Auto.CharSet.Auto

在Windows NT 平台上使用Unicode,

在微软的旧操作系统上使用ANSI

SetLastError如果非托管函数使用Windows API SetLastError设置一个错误,就可以把SetLastError字段设置为true。这样,就可以使用Marshal.GetLastWin32Error读取后面的错误号

为了使CreateHardLink方法更易于在.NET环境中使用,应该遵循如下规则:

  • 创建一个内部类NativeMethods,来包装平台调用的方法调用
  • 创建一个公共类,给.NET应用程序提供本机方法的功能
  • 使用安全特性来标记所需的安全
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhy29563

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值