C# DllImport属性详解附示例代码
DllImport是System.Runtime.InteropServices命名空间下的一个属性类,它的功能是从非托管DLL中暴露函数名称、调用参数、返回结果等必要调用信息,通常用于C#调用其他语言所编译的Dll动态链接库;例如C#通过DllImport调用C++类库做交互,下面我们来讲一下DllImport中的8个属性含义以及用法。
BestFitMapping
将 Unicode 字符转换为 ANSI 字符时,启用或禁用最佳映射, BestFitMapping字段默认为 true。当无意间把Unicode字符转换为危险字符时,例如反斜杠\
字符,可能会更改路径。启用最佳映射是将ThrowOnUnmappableChar字段设置为true,通过引发异常来向调用方发出信息。
- 元素为 ANSI Chars 或 LPSTR 的托管数组传递给非托管安全数组时,无法更改和字段ThrowOnUnmappableChar的默认值。** 始终启用最佳拟合映射,不会引发异常;请注意,这种组合可能会损害安全模型**。
CallingConvention
指定用于传递方法参数的调用约定。 默认值为 WinAPI,该值对应 32 位 Intel 的平台的 __stdcall,分别有5种枚举值。
- Winapi:此成员实际上不是调用约定,而是使用了默认平台调用约定。 例如:在 Windows x86 上默认为 StdCall,在 Linux x86 上默认为 Cdecl。
- Cdecl:调用者清理堆栈。这样就可以使用可变参数调用函数使它适合用于接受可变数量参数的方法, 例如Printf。
- StdCall:被调用者清理堆栈。这是调用非托管类库的默认约定。
- ThisCall:第一个参数是 this 指针,存储在寄存器 ECX 中。其他参数被推送到堆栈上。此调用约定用于非托管 DLL 类上的方法。
- FastCall:不支持此调用约定。
CharSet
控制名称重整以及将字符串参数封送到函数中的方式。 默认值为 CharSet.Ansi。
枚举值 | 说明 |
---|---|
None | 该值已过时,具有与System.Runtime.InteropServices.CharSet.Ansi相同的行为。 |
Ansi | 封送字符串为多字节字符串:Windows系统默认ANSI代码页,Unix系统默认UTF-8代码页。 |
Unicode | 将字符串封送为Unicode 2字节字符串。 |
Auto | 为目标操作系统自动编组适当的字符串。 |
EntryPoint
指定要调用的 DLL 入口点,入口点用于标识函数在DLL中的位置。在托管对象中,我们可以将入口点映射到一个不同的名称,这实际上是对函数的重命名。
public class Win32Api
{
[DllImport("user32.dll", EntryPoint = "MessageBoxA")]
public static extern int MsgBox(int hWnd, String text, String caption, uint type);
}```
或者也可以按序号来标识入口点。序号以 # 符号为前缀,如 #1。如果省略此字段,则公共语言运行库将使用以DllImport标记的C#方法名称。
public class Win32Api
{
[DllImport("user32.dll", EntryPoint = "#1")]
public static extern int MessageBoxA(int hWnd, String text, String caption, uint type);
}
ExactSpelling
- ExactSpelling如果为false时,CharSet设置为CharSet.Ansi ,将调用带有字母 A 的入口点函数名称。
- ExactSpelling如果为true时, CharSet设置为CharSet.Unicode,将调用带有字母 W 的入口点函数名称。
- 一般情况下由编译器设置此字段,可忽略设置。
PreserveSig
控制托管方法签名是否应转换成返回 HRESULT 并且返回值有一个附加的 [out, retval] 参数的非托管签名,默认值为 true,即不应转换签名。
SetLastError
允许调用方使用 Marshal.GetLastWin32Error API 函数来确定执行该方法时是否发生了错误。 在 Visual Basic 中,默认值为 true;在 C# 和 C++ 中,默认值为 false。
ThrowOnUnmappableChar
控件引发的异常,将无法映射的 Unicode 字符转换成一个 ANSI?
字符。