C# DllImport 系统调用使用详解 托管代码的介绍 EntryPoint的使用

来源:互联网 发布:好用的乳液推荐知乎 编辑:程序博客网 时间:2024/05/19 17:52

一、DLLImport的使用

             using System.Runtime.InteropServices; //命名空间 

      //DllImport导入Win32MessageBox函数 

         [DllImport("user32.dll", CharSet = CharSet.Unicode)]

          public static extern int MessageBox(IntPtr hWnd, String text, String caption, uint type); 

      //方法被声明为static。这是P/Invoke方法所要求的,因为在该Windows API中没有一致的实例概念。接下来,还要注意该方法被标记为extern。这是提示编译器该方法是通过一个从DLL导出的函数实现的,因此不需要提供方法体。


二、 托管代码

(managed code)

.NET Framework的核心是其运行库的执行环境,称为公共语言运行库(CLR)或.NET运行库。通常将在CLR的控制下运行的代码称为托管代码(managed code)。
运行库环境(而不是直接由操作系统)执行的代码。托管代码应用程序可以获得公共语言运行库服务,例如自动垃圾回收、运行库类型检查和安全支持等。
这些服务帮助提供独立于平台和语言的、统一的托管代码应用程序行为。

简单点说,托管代码是microsoft的中间语言,他主要的作用是在.NET FRAMEWORK的CLR执行代码前去编译源代码,也就是说托管代码充当着翻译的作用,源代码在运行时分为两个阶段:

  1.源代码编译为托管代码;(所以源代码可以有很多种,如VB,C#)

  2.托管代码编译为microsoft系统的.net平台专用文件(如类库、可执行文件等)。

三、非托管代码 (unmanaged code)

在公共语言运行库环境的外部,由操作系统直接执行的代码。非托管代码必须提供自己的垃圾回收、类型检查、安全支持等服务;它与托管代码不同,后者从公共语言运行库中获得这些服务。

四、DLLImportAttribute 的字段


在对托管代码进行P/Invoke调用时,DllImportAttribute 类型扮演着重要的角色。DllImportAttribute 的主要作用是给 CLR 指示哪个 DLL 导出您想要调用的函数。相关 DLL 的名称被作为一个构造函数参数传递给 DllImportAttribute。

字段

说明

BestFitMapping

启用或禁用最佳匹配映射。

.CallingConvention

指定用于传递方法参数的调用约定。 默认值为 WinAPI,该值对应于基于 32 位 Intel 的平台的 __stdcall。

CharSet

控制名称重整以及将字符串参数封送到函数中的方式。 默认值为 CharSet.Ansi。

.EntryPoint

指定要调用的 DLL 入口点。

ExactSpelling

控制是否应修改入口点以对应于字符集。 对于不同的编程语言,默认值将有所不同。

PreserveSig

控制托管方法签名是否应转换成返回 HRESULT 并且返回值有一个附加的 [out, retval] 参数的非托管签名。

默认值为 true(不应转换签名)。

SetLastError

允许调用方使用 Marshal.GetLastWin32Error API 函数来确定执行该方法时是否发生了错误。 在 Visual Basic 中,默认值为 true;在 C# 和 C++ 中,默认值为 false。

ThrowOnUnmappableChar

控件引发的异常,将无法映射的 Unicode 字符转换成一个 ANSI"?"字符。

 

Entrypoint:

    入口点用于标识函数在 DLL 中的位置。在托管对象中,目标函数的原名或序号入口点将标识跨越交互操作边界的函数。此外,您可以将入口点映射到一个不同的名称,这实际上是将函数重命名。

以下列出了重命名 DLL 函数的可能原因:

1.避免使用区分大小写的 API 函数名

2.符合现行的命名标准

3.提供采用不同数据类型的函数(通过声明同一 DLL 函数的多个版本)

4.简化对包含 ANSI 和 Unicode 版本的 API 的使用

如果函数在方法定义中的名称与入口点在 DLL 的名称相同,则不必用 EntryPoint 字段来显式地标识函数

 CharSet

     查看http://msdn.microsoft.com/zh-cn/library/7b93s42f(v=VS.80).aspx

SetLastError

SetLastError 错误处理非常重要,但在编程时经常被遗忘。当您进行 P/Invoke 调用时,也会面临其他的挑战 — 处理托管代码中 Windows API 错误处理和异常之间的区别。

如果您正在使用 P/Invoke 调用 Windows API 函数,而对于该函数,您使用 GetLastError 来查找扩展的错误信息,则应该在外部方法的 DllImportAttribute 中将 SetLastError 属性设置为 true。这适用于大多数外部方法。

这会导致 CLR 在每次调用外部方法之后缓存由 API 函数设置的错误。然后,在包装方法中,可以通过调用类库的 System.Runtime.InteropServices.Marshal 类型中定义的 Marshal.GetLastWin32Error 方法来获取缓存的错误值。我的建议是检查这些期望来自 API 函数的错误值,并为这些值引发一个可感知的异常。对于其他所有失败情况(包括根本就没意料到的失败情况),则引发在 System.ComponentModel 命名空间中定义的 Win32Exception,并将 Marshal.GetLastWin32Error 返回的值传递给它。

补充

P/Invoke 方法:

如果 Dotfuscator 检测到 P/Invoke 方法(即本机平台方法)名称被用于查找对应的本机函数,则该名称不会自动重命名。通过别名或序号映射到本机函数的 P/Invoke 方法可以重命名。

Dotfuscator是VS里面一个自带的.NET 混淆器和压缩器,它可以帮助您防止您的应用程序被 反编译。同时,它还可以使得您的应用程序更加小巧以及高效。


     




   





1 0
原创粉丝点击