首页 > 范文大全 > 正文

C#调用动态链接探析

开篇:润墨网以专业的文秘视角,为您筛选了一篇C#调用动态链接探析范文,如需获取更多写作素材,在线客服老师一对一协助。欢迎您的阅读与分享!

摘 要:动态链接库(DLL)是包含一个或多个已被编译、链接函数,可被多个程序同时使用的二进制文件,实现了程序更高层次的复用。不同编程语言调用DLL的方法都不尽相同。重点对DLL进行了详细的分类,对c#调用DLL的方法进行了综合分析,提出了调用中需要注意的问题。

关键词:关键字:C#;DLL;函数;调用

中图分类号:TP301 文献标识码:A 文章编号:16727800(2012)011003502

作者简介:沈宫新(1975-),男,硕士,南京化工职业学院讲师,研究方向为面向对象编程、计算机网络。0 引言

从Windows操作系统诞生之日起,就使用动态链接库(DLL)来支持公共函数的调用,区别于在编译时发生、直接把代码插入到程序EXE文件的静态链接。动态链接是指程序运行时才把自己需要的函数链接进来的代码调用方式,也就是说只要在应用程序需要时,才加载DLL到进程的虚拟空间,成为调用进程的一部分。程序使用DLL的优点包括:一方面,可以减少在磁盘和物理内存中加载的代码的重复量;另一方面,也可以促进模块式程序开发和简化程序部署和安装。每种编程语言调用DLL的方法都不尽相同,本文对用C#调用DLL的方法进行介绍。

1 动态链接库(DLL)的基本分类

每种编程语言调用DLL的方法都不尽相同,本文只对用C#调用DLL的方法进行分析总结。首先,需要了解什么是托管,什么是非托管。随着.net平台的引入,代码分为托管代码和非托管代码,托管代码由公共语言运行库环境(而不是直接由操作系统)执行的代码。托管代码应用程序可以获得公共语言运行库服务,例如自动垃圾回收、运行库类型检查和安全支持等。这些服务帮助提供独立于平台和语言的、统一的托管代码应用程序行为。非托管代码指在公共语言运行库环境的外部,由操作系统直接执行的代码。非托管代码必须提供自己的垃圾回收、类型检查、安全支持等服务;它与托管代码不同,后者从公共语言运行库中获得这些服务。对于动态链接库DLL来说也分为托管的DLL和非托管的DLL。

2 非托管的DLL的C#调用

2.1 对于不是基于com的非托管的DLL访问

首先,应该在C#语言源程序中声明外部方法,其基本形式是:

[DLLImport(“DLL文件”)] //访问DLL文件

修饰符 ReturnType FunctionName(type arg1,type arg2,...);//--声明方法。

其中:DLL文件是包含定义外部方法的库文件。修饰符是除了abstract以外在声明方法时可以使用的修饰符,一般为public static extern。返回变量类型是在DLL文件中需调用方法的返回变量类型。方法名称是在DLL文件中需调用方法的名称。参数列表是在DLL文件中需调用方法的列表。DllImport还包含了一些可选属性,其中4个比较常用:

(1)EntryPoint 参数给出 DLL 中入口点的名称。如果未指定 EntryPoint,则使用方法本身的名称。

(2)CharSet 参数指示用在入口点中的字符集。如果未指定 CharSet,则使用默认值 CharSet.Auto。

(3)SetLastError 参数指示方法是否保留 Win32“上一错误”。如果未指定 SetLastError,则使用默认值 false。

(4)CallingConvention 参数指示入口点的调用约定。如果未指定 CallingConvention,则使用默认值 CallingConvention.Winapi。

在使用DllImpor时记得引用所在的命名空间System.Runtime.InteropServices,同时对于不同类型实现的DLL引用的方法也不尽相同。

2.1.1 引用普通winapi中的方法和自己编写的类库中的普通函数方法 采用DllImport的方法直接导入,如要调用Winapi中的MessageBoxA功能可以:

[DllImport("user32.dll", EntryPoint="MessageBoxA")]

static extern int MsgBox(int hWnd, string msg, string caption, int type)

其它参数采用默认值。如果是自己编写的DLL文件中的函数,一要注意DLL文件所在的位置,可以放在项目文件夹下的../bin/Debug/目录里或者放在系统目录C:/Windows/system32里;二要注意DLL文件中使用的参数调用方式。C和C++缺省调用方式是_cdecl?,而系统默认的方式是CallingConvention.Winapi要改为CallingConvention.Cdecl。

2.1.2 引用类库中类的方法和属性

一种是要在C#中调用类库中类的方法,通过静态方法导出C++中的方法,在C#中创建同名的类来接受C++中静态的方法,注意此时C++类中的方法编译后名称改变,通过dumpbin命令来查看编译后的名称并进行映射;另一种是要在C#中调用类库中类的属性,主要使用System.Runtime.InteropServices命名空间的Marshal 类的PtrToStructure方法实现DLL中类的创建,通过创建的类来实现属性的访问。

2.2 对于基于COM的非托管DLL的访问

对于非托管代码下基于COM的DLL,可以先用tlbimp命令将COM类型中定义转换为公共运行时的等效定义。如:TlbImp test.dll /out: test_clr.dll,在直接在C#项目中添加对test_clr.dll的引用。然后倒入对应的命名空间,即可访问COM库的类中方法。如果使用 Visual Studio 开发环境,则只需添加对COM类型库的引用,VS将为您自动完成此转换。

上面使用的TlbImp.exe(类型库导入程序),它是一个包括在 .NET 框架 SDK 中的命令行工具。TlbImp 将 COM 类型库转换为 .NET 框架元数据,从而有效地创建一个可以从任何托管语言调用的托管包装。用 TlbImp 创建的 .NET 框架元数据可以通过 /R 编译器选项包括在 C# 内部版本中。

注意:在最新的VS2010中直接添加对COM类型库的引用并自动完成此转换后,要修改DLL的文件引用属性的“嵌入式操作类型”,由默认的true修改为false,否则提示无法嵌入互操作类的错误。而在vs2005和vs2008中并无引用属性“嵌入式操作类型”。

3 托管的DLL的C#调用

C# 调用托管DLL是很简单的,只要在“解决方案资源管理器”中的需要调用DLL的项目下用鼠标右击“引用”,并选择“添加引用”,然后选择已列出的DLL或通过浏览来选择DLL文件,最后需要用using 导入相关的命名空间。需要注意的问题也是vs2010中DLL文件引用属性的“嵌入式操作类型”,也需要由默认的true修改为false。

3.1 动态调用托管DLL

C# 动态调用托管DLL也需要借助System.Reflection.Assembly里的类和方法,主要使用了Assembly.LoadFrom。假如在托管代码的命名空间Test中的Class1类中有Method方法,Method方法有一个int类型参数并返回int的值,就是假设Method起一个简单的数据处理和返回的作用。编译生成托管的Test.dll文件。在C#项目中要动态引用该DLL, 先导入命名空间:using System.Reflection;在主函数中的调用代码大致如下:

Assembly MyAssembly = Assembly.LoadFrom("Test.dll");//导入dll文件

Type[] type = MyAssembly.GetTypes(); //获取程序集中定义的类型

MethodInfo m=null; //定义方法属性

object o=null; //定义dll中类的对象

foreach (Type t in type)

{

if (t.Namespace == "Test" && t.Name == "Class1")

{

m = t.GetMethod("Method"); //方法属性赋值

o = Activator.CreateInstance(t); //dll中类的对象创建

}

}

if(m!=null)

Console.Write(m.Invoke(o,new object[]{(int)4}).ToString());

//通过Invoke方法调用dll中Class1类的方法Method

4 结语

使用DLL有很多优点,如:节省内存和减少交换操作;开发大型程序时可以把某些模块分配给程序员,程序员可以用任何一门所熟悉的语言把该模块编译成DLL文件,这样可以提高代码的复用,大大减轻程序员的工作量。所以,如何灵活地调用DLL应该是每位程序员所熟知的。

本文重点对DLL进行了详细的分类,对C#访问DLL的方法进行了综合和分析,提出了调用中要注意的问题。笔者已经在多个项目中使用了上述的访问技术, 提高了工作效率,缩短了研发周期。

参考文献:

[1] 潘爱民.COM原理与应用[M].北京:清华大学出版社,2010.

[2] 王小科.C#开发实战宝典[M].北京:清华大学出版社,2010.

[3] 郭新苍,樊来耀.NET互操作技术研究[J].无线电工程,2009(6).

[4] 黄猛,唐琳在.NET环境中使用C#调用非托管DLL[J].电脑编程技巧与维护,2006(8).