Chinaunix首页 | 论坛 | 博客
  • 博客访问: 681569
  • 博文数量: 103
  • 博客积分: 2532
  • 博客等级: 大尉
  • 技术积分: 2039
  • 用 户 组: 普通用户
  • 注册时间: 2008-11-26 16:07
文章分类

全部博文(103)

文章存档

2012年(38)

2011年(28)

2010年(16)

2009年(16)

2008年(5)

分类:

2010-12-02 09:41:59

2)        dld类的使用:

1 打开项目“Tzb”,向“Form1”窗体中添加三个按钮。Name Text属性分别为 “B3”LoadLibrary方法装载Count.dll”“B4”调用count方法“B5”卸载Count.dll”,并调整到适当的大小及位置。

2 “Form1cs[设计]视图中双击按钮B3,在“B3_Click”方法体上面添加代码,创建一个dld类实例:

///

/// 创建一个 dld 类对象

///

private dld myfun=new dld();

 

  3 “B3_Click”方法体内添加如下代码:

myfun.LoadDll("Count.dll"); // 加载 "Count.dll"

myfun.LoadFun("_count@4"); // 调入函数 count, "_count@4" 是它的入口,可通过 Depends 查看

 

4 “Form1cs[设计]视图中双击按钮B4,在“B4_Click”方法体内添加如下代码:

object[] Parameters = new object[]{(int)0}; // 实参为 0

Type[] ParameterTypes = new Type[]{typeof(int)}; // 实参类型为 int

ModePass[] themode=new ModePass[]{ModePass.ByValue}; // 传送方式为值传

Type Type_Return = typeof(int); // 返回类型为 int

// 弹出提示框,显示调用 myfun.Invoke 方法的结果,即调用 count 函数

MessageBox.Show(" 这是您装载该 Dll 后第 "+myfun.Invoke(Parameters,ParameterTypes,themode,Type_Return).ToString()

+" 次点击此按钮。 "," 挑战杯 ");

 


5 “Form1cs[设计]视图中双击按钮B5,在“B5_Click”方法体内添加如下代码:

myfun.UnLoadDll();

6 “F5”运行该程序,并先点击按钮B3以加载“Count.dll”,接着点击按钮B4三次以调用3“count(0)”,先后弹出的提示框如下:

          这三个提示框所得出的结果说明了静态变量S 经初始化后,再传入实参0”也不会改变其值为0”

7 点击按钮B5以卸载“Count.dll”,再点击按钮B3进行装载“Count.dll”,再点击按钮B4查看调用了“count(0)”的结果:

从弹出的提示框所显示的结果可以看到又开始重新计数了,也就是实现了DLL的动态装载与卸载了。

 

()     调用托管DLL一般方法

C# 调用托管DLL是很简单的,只要在解决方案资源管理器中的需要调用DLL的项目下用鼠标右击引用,并选择添加引用,然后选择已列出的DLL或通过浏览来选择DLL文件,最后需要用using 导入相关的命名空间。

()     动态调用托管DLL

C# 动态调用托管DLL也需要借助System.Reflection.Assembly里的类和方法,主要使用了Assembly.LoadFrom。现在,用例子说明:

     首先,启动VS.NET,新建一个Visual C# 项目,使用的模板为类库,名称为“CsCount”,并在类“Class1”中添加静态整型变量S及方法count

// 由于 static 不能修饰方法体内的变量,所以需放在这里,且初始化值为 int.MinValue

static int S=int.MinValue;

public int count(int init)

{// 判断 S 是否等于 int.MinValue ,是的话把 init 赋值给 S

if(S==int.MinValue) S=init;

S++; //S 自增 1

return S; // 返回 S

}

 

然后,打开项目“Tzb”,向“Form1”窗体中添加一个按钮,Name属性为“B6”Text属性为Assembly类来动态调用托管DLL”,调整到适当大小和位置,双击按钮B6,转入代码视图,先导入命名空间:using System.Reflection; 接着添加Invoke方法和B6_Click方法代码:

private object Invoke(string lpFileName,string Namespace,string ClassName,string lpProcName,object[] ObjArray_Parameter)

{

Try { // 载入程序集

Assembly MyAssembly=Assembly.LoadFrom(lpFileName);

Type[] type=MyAssembly.GetTypes();

foreach(Type t in type)

{// 查找要调用的命名空间及类

if(t.Namespace==Namespace&&t.Name==ClassName)

{// 查找要调用的方法并进行调用

MethodInfo m=t.GetMethod(lpProcName);

if(m!=null)

{

object o=Activator.CreateInstance(t);

return m.Invoke(o,ObjArray_Parameter);

}

else MessageBox.Show(" 装载出错 !");

}

}

}//try

catch(System.NullReferenceException e)

{

MessageBox.Show(e.Message);

}//catch

return (object)0;

}// Invoke

 

“B6_Click”方法体内代码如下:

// 显示 count(0) 返回的值

MessageBox.Show(" 这是您第 "+Invoke("CsCount.dll","CsCount","Class1","count",new object[]{(int)0}).ToString()+" 次点击此按钮。 "," 挑战杯 ");

 

最后,把项目“CsCount”bin\Debug文件夹中的CsCount.dll复制到项目“Tzb”bin\Debug文件夹中,按“F5”运行该程序,并点击按钮B6三次,将会弹出3个提示框,内容分别是这是您第 1次点击此按钮。这是您第 2次点击此按钮。这是您第 3次点击此按钮。,由此知道了静态变量S在这里的作用。

 

() C#程序嵌入DLL的调用

     DLL文件作为资源嵌入在C#程序中,我们只要读取该资源文件并以“byte[]”返回,然后就用“Assembly Load(byte[]);”得到DLL中的程序集,最后就可以像上面的Invoke方法那样对DLL中的方法进行调用。当然不用上面方法也可以,如用接口实现动态调用,但DLL中必须有该接口的定义并且程序中也要有该接口的定义;也可用反射发送实现动态调用[4]。现在我只对像上面的Invoke方法那样对DLL中的方法进行调用进行讨论,为了以后使用方便及实现代码的复用,我们可以结合上一个编写一个类。

1)        ldfs类的编写:

在项目“Tzb”中新建一个名为ldfs的类,意为“load dll from resource”,请注意,在这个类中“resource”不只是嵌入在EXE程序中的资源,它也可以是硬盘上任意一个DLL文件,这是因为ldfs的类中的方法LoadDll有些特别,就是先从程序的内嵌的资源中查找需加载的DLL,如果找不到,就查找硬盘上的。

首先导入所需的命名空间:

using System.IO; // 对文件的读写需要用到此命名空间

using System.Reflection; // 使用 Assembly 类需用此命名空间

using System.Reflection.Emit; // 使用 ILGenerator 需用此命名空间

声明一静态变量MyAssembly

// 记录要导入的程序集

static Assembly MyAssembly;

添加LoadDll方法:

private byte[] LoadDll(string lpFileName)

{

Assembly NowAssembly = Assembly.GetEntryAssembly();

Stream fs=null;

try

{// 尝试读取资源中的 DLL

fs = NowAssembly.GetManifestResourceStream(NowAssembly.GetName().Name+"."+lpFileName);

}

finally

{// 如果资源没有所需的 DLL ,就查看硬盘上有没有,有的话就读取

if (fs==null&&!File.Exists(lpFileName)) throw(new Exception(" 找不到文件 :"+lpFileName));

else if(fs==null&&File.Exists(lpFileName))

{

FileStream Fs = new FileStream(lpFileName, FileMode.Open);

fs=(Stream)Fs;

}

}

byte[] buffer = new byte[(int) fs.Length];

fs.Read(buffer, 0, buffer.Length);

fs.Close();

return buffer; // byte[] 返回读到的 DLL

}

添加UnLoadDll方法来卸载DLL

public void UnLoadDll()

{// 使 MyAssembly 指空

MyAssembly=null;

}

添加Invoke方法来进行对DLL中方法的调用,其原理大体上和“Form1cs”中的方法Invoke相同,不过这里用的是“Assembly.Load”,而且用了静态变量MyAssembly来保存已加载的DLL,如果已加载的话就不再加载,如果还没加载或者已加载的不同现在要加载的DLL就进行加载,其代码如下所示:

public object Invoke(string lpFileName,string Namespace,string ClassName,string lpProcName,object[] ObjArray_Parameter)

{

try

{// 判断 MyAssembly 是否为空或 MyAssembly 的命名空间不等于要调用方法的命名空间,如果条件为真,就用 Assembly.Load 加载所需 DLL 作为程序集

if(MyAssembly==null||MyAssembly.GetName().Name!=Namespace)

MyAssembly=Assembly.Load(LoadDll(lpFileName));

Type[] type=MyAssembly.GetTypes();

foreach(Type t in type)

{

if(t.Namespace==Namespace&&t.Name==ClassName)

{

MethodInfo m=t.GetMethod(lpProcName);

if(m!=null)

{// 调用并返回

object o=Activator.CreateInstance(t);

return m.Invoke(o,ObjArray_Parameter);

}

else

System.Windows.Forms.MessageBox.Show(" 装载出错 !");

}

}

}

catch(System.NullReferenceException e)

{

System.Windows.Forms.MessageBox.Show(e.Message);

}

return (object)0;

}

 

 

2)        ldfs类的使用:

1 CsCount.dll作为嵌入的资源添加到项目“Tzb”中。

2 “Form1”窗体中添加两个按钮,NameText属性分别为“B7”“ldfs.Invoke调用count”“B8”“UnLoadDll”,并将它们调整到适当大小和位置。

3 打开“Form1cs”代码视图,添加一个ldfs实例:

// 添加一个 ldfs 实例 tmp

private ldfs tmp=new ldfs();

4 “Form1cs[设计]视图中双击按钮B7,在“B1_Click”方法体内添加如下代码:

// 调用 count(0), 并使用期提示框显示其返回值

MessageBox.Show(" 这是您第 "+tmp.Invoke("CsCount.dll","CsCount","Class1","count",new object[]{(int)0}).ToString()+" 次点击此按钮。 "," 挑战杯 ");

5 “Form1cs[设计]视图中双击按钮B8,在“B1_Click”方法体内添加如下代码:

// 卸载 DLL

tmp.UnLoadDll();

6 “F5”运行该程序,并先点击按钮B7三次,接着点击按钮B8,最后再点击按钮B7,此时发现又开始重新计数了,情况和“dld类的使用类似,也就是也实现了DLL的动态装载与卸载了。

    说明:以上所用到的所有源代码详见附件1:Form1.cs、附件2:dld.cs、附件3:ldfs.cs、附件4:Count.cpp、附件5:Class1.cs

阅读(6105) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-12-05 15:15:27

很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com