C#调用外部DLL介绍及使用详解
[DllImport("user32.dll", EntryPoint="MessageBoxA")]
static extern int MsgBox(int hWnd, string msg, string caption, int type);
|
MsgBox(0," 这就是用 DllImport 调用 DLL 弹出的提示框哦! "," 挑战杯 ",0x30);
|
// 导出函数,使用“ _stdcall ” 标准调用
extern "C" _declspec(dllexport)int _stdcall count(int init);
|
int _stdcall count(int init)
{//count 函数,使用参数 init 初始化静态的整形变量 S ,并使 S 自加 1 后返回该值
static int S=init;
S++;
return S;
}
|
[DllImport("Count.dll")]
static extern int count(int init);
|
MessageBox.Show(" 用 DllImport 调用 DLL 中的 count 函数, \n 传入的实参为 0 ,得到的结果是: "+count(0).ToString()," 挑战杯 ");
MessageBox.Show(" 用 DllImport 调用 DLL 中的 count 函数, \n 传入的实参为 10 ,得到的结果是: "+count(10).ToString()+"\n 结果可不是想要的 11 哦!!! "," 挑战杯 ");
MessageBox.Show(" 所得结果表明: \n 用 DllImport 调用 DLL 中的非托管 \n 函数是全局的、静态的函数!!! "," 挑战杯 ");
|
using System.Runtime.InteropServices; // 用 DllImport 需用此 命名空间
using System.Reflection; // 使用 Assembly 类需用此 命名空间
using System.Reflection.Emit; // 使用 ILGenerator 需用此 命名空间
|
/// <summary>
/// 参数传递方式枚举 ,ByValue 表示值传递 ,ByRef 表示址传递
/// </summary>
public enum ModePass
{
ByValue = 0x0001,
ByRef = 0x0002
}
|
/// <summary>
/// 原型是 :HMODULE LoadLibrary(LPCTSTR lpFileName);
/// </summary>
/// <param name="lpFileName">DLL 文件名 </param>
/// <returns> 函数库模块的句柄 </returns>
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string lpFileName);
/// <summary>
/// 原型是 : FARPROC GetProcAddress(HMODULE hModule, LPCWSTR lpProcName);
/// </summary>
/// <param name="hModule"> 包含需调用函数的函数库模块的句柄 </param>
/// <param name="lpProcName"> 调用函数的名称 </param>
/// <returns> 函数指针 </returns>
[DllImport("kernel32.dll")]
static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
/// <summary>
/// 原型是 : BOOL FreeLibrary(HMODULE hModule);
/// </summary>
/// <param name="hModule"> 需释放的函数库模块的句柄 </param>
/// <returns> 是否已释放指定的 Dll</returns>
[DllImport("kernel32",EntryPoint="FreeLibrary",SetLastError=true)]
static extern bool FreeLibrary(IntPtr hModule);
/// <summary>
/// Loadlibrary 返回的函数库模块的句柄
/// </summary>
private IntPtr hModule=IntPtr.Zero;
/// <summary>
/// GetProcAddress 返回的函数指针
/// </summary>
private IntPtr farProc=IntPtr.Zero;
|
/// <summary>
/// 装载 Dll
/// </summary>
/// <param name="lpFileName">DLL 文件名 </param>
public void LoadDll(string lpFileName)
{
hModule=LoadLibrary(lpFileName);
if(hModule==IntPtr.Zero)
throw(new Exception(" 没有找到 :"+lpFileName+"." ));
}
|
public void LoadDll(IntPtr HMODULE)
{
if(HMODULE==IntPtr.Zero)
throw(new Exception(" 所传入的函数库模块的句柄 HMODULE 为空 ." ));
hModule=HMODULE;
}
|
/// <summary>
/// 获得函数指针
/// </summary>
/// <param name="lpProcName"> 调用函数的名称 </param>
public void LoadFun(string lpProcName)
{ // 若函数库模块的句柄为空,则抛出异常
if(hModule==IntPtr.Zero)
throw(new Exception(" 函数库模块的句柄为空 , 请确保已进行 LoadDll 操作 !"));
// 取得函数指针
farProc = GetProcAddress(hModule,lpProcName);
// 若函数指针,则抛出异常
if(farProc==IntPtr.Zero)
throw(new Exception(" 没有找到 :"+lpProcName+" 这个函数的入口点 "));
}
/// <summary>
/// 获得函数指针
/// </summary>
/// <param name="lpFileName"> 包含需调用函数的 DLL 文件名 </param>
/// <param name="lpProcName"> 调用函数的名称 </param>
public void LoadFun(string lpFileName,string lpProcName)
{ // 取得函数库模块的句柄
hModule=LoadLibrary(lpFileName);
// 若函数库模块的句柄为空,则抛出异常
if(hModule==IntPtr.Zero)
throw(new Exception(" 没有找到 :"+lpFileName+"." ));
// 取得函数指针
farProc = GetProcAddress(hModule,lpProcName);
// 若函数指针,则抛出异常
if(farProc==IntPtr.Zero)
throw(new Exception(" 没有找到 :"+lpProcName+" 这个函数的入口点 "));
}
|
/// <summary>
/// 卸载 Dll
/// </summary>
public void UnLoadDll()
{
FreeLibrary(hModule);
hModule=IntPtr.Zero;
farProc=IntPtr.Zero;
}
|
/// <summary>
/// 调用所设定的函数
/// </summary>
/// <param name="ObjArray_Parameter"> 实参 </param>
/// <param name="TypeArray_ParameterType"> 实参类型 </param>
/// <param name="ModePassArray_Parameter"> 实参传送方式 </param>
/// <param name="Type_Return"> 返回类型 </param>
/// <returns> 返回所调用函数的 object</returns>
public object Invoke(object[] ObjArray_Parameter,Type[] TypeArray_ParameterType,ModePass[] ModePassArray_Parameter,Type Type_Return)
{
// 下面 3 个 if 是进行安全检查 , 若不能通过 , 则抛出异常
if(hModule==IntPtr.Zero)
throw(new Exception(" 函数库模块的句柄为空 , 请确保已进行 LoadDll 操作 !"));
if(farProc==IntPtr.Zero)
throw(new Exception(" 函数指针为空 , 请确保已进行 LoadFun 操作 !" ) );
if(ObjArray_Parameter.Length!=ModePassArray_Parameter.Length)
throw(new Exception(" 参数个数及其传递方式的个数不匹配 ." ) );
// 下面是创建 MyAssemblyName 对象并设置其 Name 属性
AssemblyName MyAssemblyName = new AssemblyName();
MyAssemblyName.Name = "InvokeFun";
// 生成单模块配件
AssemblyBuilder MyAssemblyBuilder =AppDomain.CurrentDomain.DefineDynamicAssembly(MyAssemblyName,AssemblyBuilderAccess.Run);
ModuleBuilder MyModuleBuilder =MyAssemblyBuilder.DefineDynamicModule("InvokeDll");
// 定义要调用的方法 , 方法名为“ MyFun ”,返回类型是“ Type_Return ”参数类型是“ TypeArray_ParameterType ”
MethodBuilder MyMethodBuilder =MyModuleBuilder.DefineGlobalMethod("MyFun",MethodAttributes.Public| MethodAttributes.Static,Type_Return,TypeArray_ParameterType);
// 获取一个 ILGenerator ,用于发送所需的 IL
ILGenerator IL = MyMethodBuilder.GetILGenerator();
int i;
for (i = 0; i < ObjArray_Parameter.Length; i++)
{// 用循环将参数依次压入堆栈
switch (ModePassArray_Parameter[i])
{
case ModePass.ByValue:
IL.Emit(OpCodes.Ldarg, i);
break;
case ModePass.ByRef:
IL.Emit(OpCodes.Ldarga, i);
break;
default:
throw(new Exception(" 第 " +(i+1).ToString() + " 个参数没有给定正确的传递方式 ." ) );
}
}
if (IntPtr.Size == 4) {// 判断处理器类型
IL.Emit(OpCodes.Ldc_I4, farProc.ToInt32());
}
else if (IntPtr.Size == 8)
{
IL.Emit(OpCodes.Ldc_I8, farProc.ToInt64());
}
else
{
throw new PlatformNotSupportedException();
}
IL.EmitCalli(OpCodes.Calli,CallingConvention.StdCall,Type_Return,TypeArray_ParameterType);
IL.Emit(OpCodes.Ret); // 返回值
MyModuleBuilder.CreateGlobalFunctions();
// 取得方法信息
MethodInfo MyMethodInfo = MyModuleBuilder.GetMethod("MyFun");
return MyMethodInfo.Invoke(null, ObjArray_Parameter);// 调用方法,并返回其值
}
|
/// <summary>
/// 调用所设定的函数
/// </summary>
/// <param name="IntPtr_Function"> 函数指针 </param>
/// <param name="ObjArray_Parameter"> 实参 </param>
/// <param name="TypeArray_ParameterType"> 实参类型 </param>
/// <param name="ModePassArray_Parameter"> 实参传送方式 </param>
/// <param name="Type_Return"> 返回类型 </param>
/// <returns> 返回所调用函数的 object</returns>
public object Invoke(IntPtr IntPtr_Function,object[] ObjArray_Parameter,Type[] TypeArray_ParameterType,ModePass[] ModePassArray_Parameter,Type Type_Return)
{
// 下面 2 个 if 是进行安全检查 , 若不能通过 , 则抛出异常
if(hModule==IntPtr.Zero)
throw(new Exception(" 函数库模块的句柄为空 , 请确保已进行 LoadDll 操作 !"));
if(IntPtr_Function==IntPtr.Zero)
throw(new Exception(" 函数指针 IntPtr_Function 为空 !" ) );
farProc=IntPtr_Function;
return Invoke(ObjArray_Parameter,TypeArray_ParameterType,ModePassArray_Parameter,Type_Return);
}
|
/// <summary>
/// 创建一个 dld 类对象
/// </summary>
private dld myfun=new dld();
|
myfun.LoadDll("Count.dll"); // 加载 "Count.dll"
myfun.LoadFun("_count@4"); // 调入函数 count, "_count@4" 是它的入口,可通过 Depends 查看
|
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()
+" 次点击此按钮。 "," 挑战杯 ");
|
myfun.UnLoadDll();
|
// 由于 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
}
|
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
|
// 显示 count(0) 返回的值
MessageBox.Show(" 这是您第 "+Invoke("CsCount.dll","CsCount","Class1","count",new object[]{(int)0}).ToString()+" 次点击此按钮。 "," 挑战杯 ");
|
using System.IO; // 对文件的读写需要用到此命名空间
using System.Reflection; // 使用 Assembly 类需用此命名空间
using System.Reflection.Emit; // 使用 ILGenerator 需用此命名空间
|
// 记录要导入的程序集
static Assembly MyAssembly;
|
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
}
|
public void UnLoadDll()
{// 使 MyAssembly 指空
MyAssembly=null;
}
|
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;
}
|
// 添加一个 ldfs 实例 tmp
private ldfs tmp=new ldfs();
|
// 调用 count(0), 并使用期提示框显示其返回值
MessageBox.Show(" 这是您第 "+tmp.Invoke("CsCount.dll","CsCount","Class1","count",new object[]{(int)0}).ToString()+" 次点击此按钮。 "," 挑战杯 ");
|
// 卸载 DLL
tmp.UnLoadDll();
|
C#调用外部DLL介绍及使用详解的更多相关文章
- C# 调用外部dll(转)
C# 调用外部dll 一. DLL与应用程序 动态链接库(也称为DLL,即为"Dynamic Link Library"的缩写)是Microsoft Windows最 ...
- Delphi程序调用C#.Net编译的DLL并打开窗体(详解)
Delphi程序调用C#.Net编译的DLL并打开窗体(详解)最近用C#.Net写了一个公用模块, 本以为仅提供给.Net程序使用, 但是领导要求把这些功能提供给旧系统使用, 天啦, 几套旧系统全是D ...
- Python调用C/C++动态链接库的方法详解
Python调用C/C++动态链接库的方法详解 投稿:shichen2014 这篇文章主要介绍了Python调用C/C++动态链接库的方法,需要的朋友可以参考下 本文以实例讲解了Python调用C/C ...
- 2020你还不会Java8新特性?方法引用详解及Stream 流介绍和操作方式详解(三)
方法引用详解 方法引用: method reference 方法引用实际上是Lambda表达式的一种语法糖 我们可以将方法引用看作是一个「函数指针」,function pointer 方法引用共分为4 ...
- Java和Ibatis调用存储过程并取得返回值详解
Java和Ibatis调用存储过程并取得返回值详解 2011-07-19 17:33 jiandanfeng2 CSDN博客 字号:T | T 本文主要介绍了Java和Ibatis调用存储过程的方法, ...
- Nginx的介绍和安装详解
[介绍+安装]Nginx的介绍和安装详解 == 介绍和安装 == Nginx是一个自由.开源.高性能及轻量级的HTTP服务器及反转代理服务器, 其性能与IMAP/POP3代理服务器相当.Nginx ...
- rsync的介绍及参数详解,配置步骤,工作模式介绍
rsync的介绍及参数详解,配置步骤,工作模式介绍 rsync是类unix系统下的数据镜像备份工具.它是快速增量备份.全量备份工具. Sync可以远程同步,支持本地复制,或者与其他SSH.rsync主 ...
- 用C#调用外部DLL
1.有时候需要用C#调用外部的dll,例如c++写的dll,首先需要保证dll的编译环境与本项目的环境是相同的,例如都是x86位或者x64位 2.调用声明和dll内的声明一致: function Te ...
- 调用链系列一、Zipkin架构介绍、Springboot集承(springmvc,HttpClient)调用链跟踪、Zipkin UI详解
1.Zipkin是什么 Zipkin分布式跟踪系统:它可以帮助收集时间数据,解决在microservice架构下的延迟问题:它管理这些数据的收集和查找:Zipkin的设计是基于谷歌的Google Da ...
随机推荐
- 阿里云扩容数据盘_Linux
扩容数据盘_Linux 更新时间:2018-10-11 15:18:46 · 编辑者 编辑 · ★ 我的收藏 新手学堂 学习路径 本页目录 前提条件 注意事项 步骤 1. 在控制台上扩容数据盘的磁盘空 ...
- 百度网盘 http://pandownload.com/index.html
https://github.com/high-speed-downloader/high-speed-downloader
- 关于源码输出,浏览器不解析Html标签
有时候根据需要我们需要看到浏览器上源码效果如: 但是我如果在html中输入 <a href = 'http://www.baidu.com'>百度</a>那么问题来了,总是显示 ...
- Axiom3D:Buffer漫谈
在前面数据绑定基本流程,简单说了下,在Axiom中,数据从我们C#的托管环境到下面的OpenGL或是D3D的非托管环境,有个转化过程,相关实现我们可以从BufferBase看起.BufferBase与 ...
- 【转帖】Windows下PostgreSQL安装图解
Windows下PostgreSQL安装图解 这篇文章主要为大家介绍了如果在Windows下安装PostgreSQL数据库的方法,需要的朋友可以参考下 现在谈起免费数据库,大多数人首先 ...
- (笔记)Linux下怎么安装tar.gz的软件
一般这种的就是源代码.先下载下来.然后cd到下载目录.用tar xvfz XXX.tar.gz的解压.然后进入解压后的目录. 打./configure生成配置文件.打make对源代码进行编译,生成库和 ...
- 一个类似于postman的协议测试工具
协议测试工具使用postman相当便捷,不过有一个问题,就是每个人都要装一个这个东西,并且测试文件导来导去,还是觉得麻烦了点. 最重要的是postman不能修改,有一些定制功能postman明显力不从 ...
- IE8不支持数组的indexOf方法
在IE8下有个js错误,但是在其它浏览器下(Firefox, Chrome, IE9)下面都很正常.后来调试发现原因是在IE8下,js数组没有indexOf方法. 在使用indexOf方法前,执行一下 ...
- com.ibm.msg.client.jms.DetailedJMSSecurityException: JMSWMQ2013: 为队列管理器提供的安全性认证无效
com.ibm.msg.client.jms.DetailedJMSSecurityException: JMSWMQ2013: 为队列管理器“zm_queue_manager”提供的安全性认证无效, ...
- MySQL时间戳时间
MySQL中: now():获取当前时间:例:SELECT now(); unix_timestamp():将时间转换为时间戳:例: SELECT unix_timestamp(now());