C#调用win32 API或称非托管代码

Posted by
.Net Framework 是由彼此独立又相关的两部分组成:CLR 和 类库, CLR是它为我们提供的服务,类库是它实现的功能.
.NET的大部分特性----垃圾收集,版本控制,线程管理等,都使用了CLR提供的服务

<本文来自网络摘要>
在.net 编程环境中,系统的资源分为托管资源和非托管资源。

托管代码

  对于托管的资源的回收工作,是不需要人工干预回收的,而且你也无法干预他们的回收,所能够做的

 

只是了解.net
CLR如何做这些操作。也就是说对于您的应用程序创建的大多数对象,可以依靠
.NET

托管代码(Managed
Code)实际上就是中间语言(IL)代码。代码编写完毕后进行编译,此时编译器把代码编译成中间语言(IL),而不是能直接在你的电脑上运行的机器码。程序集(Assembly)的文件负责封装中间语言,程序集中包含了描述所创建的方法、类以及属性的所有元数据。
托管代码在公共语言运行库(CLR)中运行。CLR提供了一个实时编译器,用来把IL代码编译为本机机器代码.这样一来,CLR能够使代码变得可移植,因为.NET应用程序的源代码必须被编译为IL代码,这些IL代码可以运行在任何提供CLR服务的平台上.从CLR的角度来看,所有的语言都是平等的,只要有一个能生成IL代码的编译器就行,这就确保了各种语言的互操性.

Framework 的垃圾回收器隐式地执行所有必要的内存管理任务。托管代码就是基于.net元数据格式的代码,
运行于.net平台之上,所有的与操作系统的交换有.net来完成,就像是把这些功能委托给.net,所以称之为托管代码。

非托管代码

举个例子l 

在公共语言运行库环境的外部,由操作系统直接执行的代码。非托管代码必须提供自己的垃圾回收、类型检查、安全支持等服务,它与托管代码不同,后者从公共语言运行库中获得这些服务,而非托管代码是在运行库之外运行的代码。例如COM
组件、ActiveX 接口和 Win32 API
函数都是非托管代码的示例。

 

区别:

Vc.net还可以使用mfc,atl来编写程序,他们基于MFC或者ATL,而不是.NET,所有是非托管代码,如果基于.net比如C#,VB.net则是托管代码

     1、托管代码是一种中间语言,运行在CLR上;

 

          非托管代码被编译为机器码,运行在机器上。

非托管代码是指.NET解释不了的 

     2、托管代码独立于平台和语言,能更好的实现不同语言平台之间的兼容;

 

          非托管代码依赖于平台和语言。

简单的说,托管代码的话,.net可以自动释放资料,非托管代码需要手动释放资料.
  
对于非托管资源,您在应用程序中使用完这些非托管资源之后,必须显示的释放他们,例如

    
3、托管代码可享受CLR提供的服务(如安全检测、垃圾回收等),不需要自己完成这些操作;

System.IO.StreamReader的一个文件对象,必须显示的调用对象的Close()方法关闭它,否则会占用系统

          非托管代码需要自己提供安全检测、垃圾回收等操作。

的内存和资源,而且可能会出现意想不到的错误。

.net的堆就是托管堆.没有非托管堆.引用类型的引用目标就是在堆里.

  清楚什么是托管资源,什么是非托管资源

值类型的值就在栈里.

  最常见的一类非托管资源就是包装操作系统资源的对象,例如文件,窗口或网络连接,对于这类资源

所谓的系统资源.是指:网络连接,数据库连接.文件流.这种东西.

虽然垃圾回收器可以跟踪封装非托管资源的对象的生存期,但它不了解具体如何清理这些资源。还好.net

这里的托管就是指被CLR管理,托管堆就是被CLR管理的堆。非托管资源需要手动释放,托管资源由GC帮你打理。

Framework提供了Finalize()方法,它允许在垃圾回收器回收该类资源时,适当的清理非托管资源。如果

using可以跟踪非托管资源周期内的活动,一旦发现非托管资源生命结束了,就会强制调用dispose方法去释放在该作用域的非托管资源的内存。

在MSDN Library
中搜索Finalize将会发现很多类似的主题,这里列举几种常见的非托管资源:

C#如何直接调用非托管代码,通常有2种方法:

ApplicationContext,Brush,Component,ComponentDesigner,Container,Context,Cursor,FileStream,Fon

1.  直接调用从 DLL 导出的函数。

t,Icon,Image,Matrix,Object,OdbcDataReader,OleDBDataReader,Pen,Regex,Socket,StreamWriter,Time

2.  调用 COM 对象上的接口方法

r,Tooltip 等等资源。可能在使用的时候很多都没有注意到!

从dll中导出函数:

关于托管资源,就不用说了撒,像简单的int,string,float,DateTime等等,.net中超过80%的资源都是托

a.使用 C# 关键字 static 和 extern 声明方法。

管资源。

b.将 DllImport 属性附加到该方法。DllImport 属性允许您指定包含该方法的DLL 的名称。

非托管资源如何释放,.NET Framework 提供 Object.Finalize
方法,它允许对象在垃圾回收器回收该对

c.如果需要,为方法的参数和返回值指定自定义封送处理信息,这将重写 .NET
Framework 的默认封送处理。

象使用的内存时适当清理其非托管资源。默认情况下,Finalize
方法不执行任何操作。默认情况下,

using System;

using System.Runtime.InteropServices;

    public class MSSQL_ServerHandler

    {

        [DllImport("kernel32.dll")]

        public static extern int GetShortPathName

        (

            string path,

            StringBuilder shortPath,

            int shortPathLength

)

     }

Finalize
方法不执行任何操作。如果您要让垃圾回收器在回收对象的内存之前对对象执行清理操作,您

DllImportAttribute 的字段

必须在类中重写 Finalize
方法。然而大家都可以发现在实际的编程中根本无法override方法Finalize

 

(),在C#中,可以通过析构函数自动生成 Finalize 方法和对基类的 Finalize
方法的调用。

字段

说明

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"?"字符。

 

例如:
~MyClass()
{
  // Perform some cleanup operations here.
}
  该代码隐式翻译为下面的代码。
protected override void Finalize()
{
  try
  {
    // Perform some cleanup operations here.
  }
  finally
  {
    base.Finalize();
  }
}

 

但是,在编程中,并不建议进行override方法Finalize(),因为,实现 Finalize
方法或析构函数对性能

 

可能会有负面影响。一个简单的理由如下:用 Finalize
方法回收对象使用的内存需要至少两次垃圾回收

StructLayoutAttribute类

,当垃圾回收器回收时,它只回收没有终结器(Finalize方法)的不可访问的内存,这时他不能回收具有终

在C/C++中,struct类型中的成员的一旦声明,则实例中成员在内存中的布局(Layout)顺序就定下来了,即与成员声明的顺序相同,并且在默认情况下总是按照结构中占用空间最大的成员进行对齐(Align);当然我们也可以通过设置或编码来设置内存对齐的方式.在.net托管环境中,CLR提供了更自由的方式来控制struct中Layout:我们可以在定义struct时,在struct上运用StructLayoutAttribute特性来控制成员的内存布局

结器(Finalize方法)的不可以访问的内存。它改为将这些对象的项从终止队列中移除并将他们放置在标记

 

为“准备终止”的对象列表中,该列表中的项指向托管堆中准备被调用其终止代码的对象,下次垃圾回收

C#提供了一个StructLayoutAttribute类,通过它你可以定义自己的格式化类型,在受管辖代码中,格式化类型是一个用StructLayoutAttribute说明的结构或类成员,通过它能够保证其内部成员预期的布局信息。布局的选项共有三种:

器进行回收时,就回收并释放了这些内存。
C#如何直接调用非托管代码,通常有2种方法:

布局选项  
描述  
LayoutKind.Automatic  
为了提高效率允许运行态对类型成员重新排序。  
注意:永远不要使用这个选项来调用不受管辖的动态链接库函数。  
LayoutKind.Explicit  
对每个域按照FieldOffset属性对类型成员排序  
LayoutKind.Sequential  
对出现在受管辖类型定义地方的不受管辖内存中的类型成员进行排序。

1. 
直接调用从
DLL 导出的函数。

[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet =
CharSet.Unicode)]

2. 
调用
COM 对象上的接口方法

 

我主要讨论从dll中导出函数,基本步骤如下:

 

1.使用
C# 关键字
static

extern
声明方法。

COM interop具体操作:

2.将
DllImport 属性附加到该方法。DllImport 属性允许您指定包含该方法的 DLL
的名称。

a. 用atl写com服务程序

3.如果需要,为方法的参数和返回值指定自定义封送处理信息,这将重写 .NET Framework
的默认封送处理。

b. 使用Tlbimp将atl写的com程序转换成 COM DLL

好,我们开始

   用如下命令:

1.首先我们查询MSDN找到GetShortPathName的定义

   tlbimp 你写的com.dll

The
GetShortPathName function retrieves the short path form of the
specified path.

   tlbimp是 .NETFramework
SDK中附带的类型库导入程序。用这个命令即是把生成一个非托管com
dll的托管包装。

DWORD
GetShortPathName(

c. 托管客户端非常简单

  LPCTSTR lpszLongPath**,**

   直接new一下,然后调用对应的方法即可。

  LPTSTR lpszShortPath**,**

 

  DWORD cchBuffer

 

);

 

2.查找对照表进行数据类型的转换(出处:  )Data
Types

 

 

 

Win32
Types

Specification

CLR
Type

char,
INT8, SBYTE, CHAR†

8-bit
signed integer

System.SByte

short,
short int, INT16, SHORT

16-bit
signed integer

System.Int16

int,
long, long int, INT32, LONG32, BOOL†, INT

32-bit
signed integer

System.Int32

__int64,
INT64, LONGLONG

64-bit
signed integer

System.Int64

unsigned
char, UINT8, UCHAR†, BYTE

8-bit
unsigned integer

System.Byte

unsigned
short, UINT16, USHORT, WORD, ATOM, WCHAR†, __wchar_t

16-bit
unsigned integer

System.UInt16

unsigned,
unsigned int, UINT32, ULONG32, DWORD32, ULONG, DWORD, UINT

32-bit
unsigned integer

System.UInt32

unsigned
__int64, UINT64, DWORDLONG, ULONGLONG

64-bit
unsigned integer

System.UInt64

float,
FLOAT

Single-precision
floating point

System.Single

double, long
double, DOUBLE

Double-precision
floating point

System.Double

†In
Win32 this type is an integer with a specially assigned meaning; in
contrast, the CLR provides a specific type devoted to this
meaning.

 

3.调用GetShortPathName这个API,简单的写法如下(编译通过的话),

using
System;

using
System.Runtime.InteropServices;

    public class
MSSQL_ServerHandler

    {

        [DllImport(“kernel32.dll”)]

        public static
extern
int
GetShortPathName

        (

            string path,

相关文章

Leave a Reply

电子邮件地址不会被公开。 必填项已用*标注