c# 调用API
1 DLLImport的使用using System;
using System.Runtime.InteropServices; //命名空间
class Example
{
//用DllImport 导入Win32的MessageBox函数
[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 导出的函数实现的,因此不需要提供方法体。
static void Main()
{
// Call the MessageBox function using platform invoke.
MessageBox(new IntPtr(0), "Hello World!", "Hello Dialog", 0);
}
}
使用非托管DLL函数并不困难,下面我们可以详细的了解上面的代码的含义。首先介绍什么是托管代码,什么是非托管代码。然后再详细介绍DLLImport的使用方法和各字段的意义。
2 托管代码 (managed code)
.NET Framework的核心是其运行库的执行环境,称为公共语言运行库(CLR)或.NET运行库。通常将在CLR的控制下运行的代码称为托管代码(managed code)。
运行库环境(而不是直接由操作系统)执行的代码。托管代码应用程序可以获得公共语言运行库服务,例如自动垃圾回收、运行库类型检查和安全支持等。这些服务帮助提供独立于平台和语言的、统一的托管代码应用程序行为。
托管代码是可以使用20多种支持Microsoft .NET Framework的高级语言编写的代码,它们包括:C#, J#, Microsoft Visual Basic .NET, Microsoft JScript .NET, 以及C++。所有的语言共享统一的类库集合,并能被编码成为中间语言(IL)。运行库编译器(runtime-aware ompiler)在托管执行环境下编译中间语言(IL)使之成为本地可执行的代码,并使用数组边界和索引检查,异常处理,垃圾回收等手段确保类型的安全。
在托管执行环境中使用托管代码及其编译,可以避免许多典型的导致安全黑洞和不稳定程序的编程错误。同样,许多不可靠的设计也自动的被增强了安全 性,例如类型安全检查,内存管理和释放无效对象。程序员可以花更多的精力关注程序的应用逻辑设计并可以减少代码的编写量。这就意味着更短的开发时间和更健 壮的程序。
简单点说,托管代码是microsoft的中间语言,他主要的作用是在.NET FRAMEWORK的CLR执行代码前去编译源代码,也就是说托管代码充当着翻译的作用,源代码在运行时分为两个阶段:
1.源代码编译为托管代码;(所以源代码可以有很多种,如VB,C#,J#)
2.托管代码编译为microsoft系统的.net平台专用文件(如类库、可执行文件等)。
2.1 非托管代码 (unmanaged code)
在公共语言运行库环境的外部,由操作系统直接执行的代码。非托管代码必须提供自己的垃圾回收、类型检查、安全支持等服务;它与托管代码不同,后者从公共语言运行库中获得这些服务。
.net中托管代码的含义
2.2 什么是托管?托管是什么意思?
托管代码就是基于.net元数据格式的代码,运行于.net平台之上,所有的与操作系统的交换有.net来完成,就像是把这些功能委托给.net,所以称之为托管代码。非托管代码则反之。
举个例子l
Vc.net还可以使用mfc,atl来编写程序,他们基于MFC或者ATL,而不是.NET,所以是非托管代码,如果基于.net比如C#,VB.net则是托管代码
非托管代码是指.NET解释不了的
简单的说,托管代码的话,.net可以自动释放资料,非托管代码需要手动释放资料.
什么是托管C++
托管是.NET的一个专门概念,它倡导一种新的编程理念,因此我们完全可以把“托管”视为“.NET”。由托管概念所引发的C++应用程序包括托管代码、托管数据和托管类三个组成部分。
托管代码
.Net环境提供了许多核心的运行(RUNTIME)服务,比如异常处理和安全策略。为了能使用这些服务,必须要给运行环境提供一些信息代码(元数 据),这种代码就是托管代码。所有的C#、VB.NET、JScript.NET默认时都是托管的,但Visual C++默认时不是托管的,必须在编译器中使用命令行选项(/CLR)才能产生托管代码。
托管数据
与托管代码密切相关的是托管数据。托管数据是由公共语言运行的垃圾回收器进行分配和释放的数据。默认情况下,C#、Visual Basic 和 JScript.NET 数据是托管数据。不过,通过使用特殊的关键字,C# 数据可以被标记为非托管数据。Visual C++数据在默认情况下是非托管数据,即使在使用 /CLR 开关时也不是托管的。
托管类
尽管Visual C++数据在默认情况下是非托管数据,但是在使用C++的托管扩展时,可以使用“__gc”关键字将类标记为托管类。就像该名称所显示的那样,它表示类实 例的内存由垃圾回收器管理。另外,一个托管类也完全可以成为 .NET 框架的成员,由此可以带来的好处是,它可以与其他语言编写的类正确地进行相互操作,如托管的C++类可以从Visual Basic类继承等。但同时也有一些限制,如托管类只能从一个基类继承等。
2.3 托管代码如何调用非托管代码(c sharp如何调用c++代码)?
1. COM interop
具体操作:
a. 用atl写com服务程序
b. 使用Tlbimp将atl写的com程序转换成 COM DLL
用如下命令:
tlbimp 你写的com.dll
tlbimp是 .NET Framework SDK中附带的类型库导入程序。用这个命令即是把生成一个非托管com dll的托管包装。
c. 托管客户端非常简单
直接new一下,然后调用对应的方法即可。
2. P/Invoke
a. 在托管客户端增加一条 DllImport语句和一个方法的调用。
介绍一个P/Invoke网站, 这个网站主要是一个wiki,允许开发者发现,编辑,增加PInvoke的签名,用户自定义类型和从托管代码(指c#和VB.net开发语言)访问win32和其他非托管api的信息。
世界各地的.Net开发者可以很容易分享自己有价值的东西给社区,
2.4 托管代码和非托管代码效率的对比
3 DllImportAttribute 的字段
在对托管代码进行 P/Invoke 调用时,DllImportAttribute 类型扮演着重要的角色。DllImportAttribute 的主要作用是给 CLR 指示哪个 DLL 导出您想要调用的函数。相关 DLL 的名称被作为一个构造函数参数传递给 DllImportAttribute。
下表列出了所有与平台调用相关的特性字段。 对于每个字段,下表都将包含其默认值,并且会提供一个链接,用于获取有关如何使用这些字段定义非托管 DLL 函数的信息。 字段
说明
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"?"字符。
除了指出宿主 DLL 外,DllImportAttribute 还包含了一些可选属性,其中四个特别有趣:EntryPoint、CharSet、SetLastError 和 CallingConvention。http://www.360doc.com/content/11/0105/09 /3877783_84071078.shtml
3.1 entrypoint
入口点用于标识函数在 DLL 中的位置。在托管对象中,目标函数的原名或序号入口点将标识跨越交互操作边界的函数。此外,您可以将入口点映射到一个不同的名称,这实际上是将函数重命名。
以下列出了重命名 DLL 函数的可能原因:
· 避免使用区分大小写的 API 函数名
· 符合现行的命名标准
· 提供采用不同数据类型的函数(通过声明同一 DLL 函数的多个版本)
· 简化对包含 ANSI 和 Unicode 版本的 API 的使用
您可以使用 DllImportAttribute.EntryPoint 字段按名称或序号指定 DLL 函数。如果函数在方法定义中的名称与入口点在 DLL 的名称相同,则不必用 EntryPoint 字段来显式地标识函数。否则,使用以下属性形式之一来指示名称或序号:
[DllImport("dllname", EntryPoint="Functionname")]
[DllImport("dllname", EntryPoint="#123")]
补充:软件开发 , C# ,