C# 动态装载 DLL
C# 动态装载 DLL
LoadDllTool.cs 如下:
using System;
using System.Collections.Generic;
using System.Text; using System.Runtime.InteropServices; // 用 DllImport 需用此 命名空间
using System.Reflection; // 使用 Assembly 类需用此 命名空间
using System.Reflection.Emit; // 使用 ILGenerator 需用此 命名空间 namespace CallDephiDll
{ public class LoadDllTool
{ //+------------------------------------------------------------------
//+ 动态装载
//+------------------------------------------------------------------ /// <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>
public static IntPtr hModule = IntPtr.Zero; /// <summary>
/// GetProcAddress 返回的函数指针
/// </summary>
private static IntPtr farProc = IntPtr.Zero; /// <summary>
/// 装载 Dll
/// </summary>
/// <param name="lpFileName">DLL 文件名 </param>
public static void LoadDll(string lpFileName)
{ hModule = LoadLibrary(lpFileName);
if (hModule == IntPtr.Zero)
throw (new Exception(" 没有找到 :" + lpFileName + ".")); } //若已有已装载Dll的句柄,可以使用LoadDll方法的第二个版本:
public static void LoadDll(IntPtr HMODULE)
{
if (HMODULE == IntPtr.Zero)
throw (new Exception(" 所传入的函数库模块的句柄 HMODULE 为空 ."));
hModule = HMODULE;
} /// <summary>
/// 获得函数指针
/// </summary>
/// <param name="lpProcName"> 调用函数的名称 </param>
public static 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 static 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 static void UnLoadDll()
{ FreeLibrary(hModule);
hModule = IntPtr.Zero;
farProc = IntPtr.Zero;
} // Invoke方法的第一个版本:
/// <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 static 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 = ; 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 + ).ToString() + " 个参数没有给定正确的传递方式 .")); } } if (IntPtr.Size == )
{// 判断处理器类型
IL.Emit(OpCodes.Ldc_I4, farProc.ToInt32());
}
else if (IntPtr.Size == )
{
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);// 调用方法,并返回其值
} // Invoke方法的第二个版本,它是调用了第一个版本的:
/// <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 static 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); } }
}
相关调用示例:
1. 加载 dll 和 调用方法
dllPath = Application.StartupPath + @"\test.dll";
LoadDllTool.LoadDll(dllPath);
LoadDllTool.LoadFun("OpenForm");
object[] param = new object[];
param[] = handle;
param[] = loginUserID;
param[] = loginUserName;
param[] = accID;
param[] = year;
param[] = menuName;
param[] = path;
Type[] paramType = new Type[];
paramType[] = typeof(IntPtr);
paramType[] = typeof(string);
paramType[] = typeof(string);
paramType[] = typeof(string);
paramType[] = typeof(string);
paramType[] = typeof(string);
paramType[] = typeof(string);
LoadDllTool.ModePass[] paramModePass = new LoadDllTool.ModePass[];
paramModePass[] = LoadDllTool.ModePass.ByValue;
paramModePass[] = LoadDllTool.ModePass.ByValue;
paramModePass[] = LoadDllTool.ModePass.ByValue;
paramModePass[] = LoadDllTool.ModePass.ByValue;
paramModePass[] = LoadDllTool.ModePass.ByValue;
paramModePass[] = LoadDllTool.ModePass.ByValue;
paramModePass[] = LoadDllTool.ModePass.ByValue;
this.DelphiHandle = (IntPtr)LoadDllTool.Invoke(param, paramType, paramModePass, typeof(IntPtr));
2. 释放Dll 和 调用函数示例
/// <summary>
/// 释放 加载的 Dll
/// </summary>
private void unLoadDll()
{
try
{
LoadDllTool.LoadFun("CloseForm");
IntPtr rtnResult = (IntPtr)LoadDllTool.Invoke(new object[] { "hello" }, new Type[] { typeof(string) }, new LoadDllTool.ModePass[] { LoadDllTool.ModePass.ByValue }, typeof(IntPtr)); LoadDllTool.UnLoadDll();
}
catch (Exception ex)
{
MessageBox.Show("释放Dll错误:" + ex.Message.ToString());
}
}
如果在释放的时候出现异常的话,需要在 VS里做如下设置:
我是 VS2010
首先:Ctrl + Alt + E 调用 异常窗口 ,展开: Managed Debugging Assistants 然后, 再找到: LoaderLock 这个节点,把勾去掉,确定 就可以了.

C# 动态装载 DLL的更多相关文章
- C#程序实现动态调用DLL的研究(转)
摘 要:在<csdn开发高手>2004年第03期中的<化功大法——将DLL嵌入EXE>一文,介绍了如何把一个动态链接库作为一个资源嵌入到可执行文件,在可执行文件运行时,自动从资 ...
- 【VB技巧】VB静态调用与动态调用dll详解
本文“[VB技巧]VB静态调用与动态调用dll详解”,来自:Nuclear'Atk 网络安全研究中心,本文地址:http://lcx.cc/?i=489,转载请注明作者及出处! [[请注意]]:在以下 ...
- C#程序实现动态调用DLL的研究[转]
摘 要: 在< csdn 开发高手> 2004 年第 03 期中的<化功大法——将 DLL 嵌入 EXE >一文,介绍了如何把一个动态链接库作为一个资源嵌入到可执行文件,在 ...
- C#程序实现动态调用DLL的研究
摘 要:在<csdn开发高手>2004年第03期中的<化功大法——将DLL嵌入EXE>一文,介绍了如何把一个动态链接库作为一个资源嵌入到可执行文件,在可执行文件运行时,自动从资 ...
- 动态载入DLL所需要的三个函数详解(LoadLibrary,GetProcAddress,FreeLibrary)
动态载入 DLL 动态载入方式是指在编译之前并不知道将会调用哪些 DLL 函数, 完全是在运行过程中根据需要决定应调用哪些函数. 方法是:用 LoadLibrary 函数加载动态链接库到内存,用 Ge ...
- 【转载】动态载入DLL所需要的三个函数详解(LoadLibrary,GetProcAddress,FreeLibrary)
原文地址:https://www.cnblogs.com/westsoft/p/5936092.html 动态载入 DLL 动态载入方式是指在编译之前并不知道将会调用哪些 DLL 函数, 完全是在运行 ...
- win系统动态载入DLL所需要的三个函数详解(LoadLibrary,GetProcAddress,FreeLibrary)
动态载入 DLL 动态载入方式是指在编译之前并不知道将会调用哪些 DLL 函数, 完全是在运行过程中根据需要决定应调用哪些函数. 方法是:用 LoadLibrary 函数加载动态链接库到内存,用 Ge ...
- 卸载AppDomain动态调用DLL异步线程执行失败
应用场景 动态调用DLL中的类,执行类的方法实现业务插件功能 使用Assembly 来实现 但是会出现逻辑线程数异常的问题 使用AppDomain 实现动态调用,并卸载. 发现问题某个插件中开启异步线 ...
- WinForm开发框架--动态读取DLL模式
1\ WinForm开发框架--动态读取DLL模式 http://www.2cto.com/kf/201306/217199.html 2\ 广州爱奇迪 http://www.iqidi. ...
随机推荐
- Numpy存取文件
来自 Python科学计算 http://hyry.dip.jp/tech/book/page/scipy/numpy_file.html NumPy提供了多种存取数组内容的文件操作函数.保存数组数据 ...
- JAVA编程思想读书笔记(一)--面向对象
第二章 一切都是对象 No1: 程序运行时,我们最好对数据保存到什么地方做到心中有数.特别要注意的是内存的分配.有六个地方都可以保存数据: (1) 寄存器.这是最快的保存区域,因为它位于和其他所有保存 ...
- Python编程举例-iter和next结合定制可迭代对象
class Foo: def __init__(self,n): self.n = n def __iter__(self): return self def __next__(self): if s ...
- linux——(4)磁盘与文件系统管理
概念一:linux-ext2文件系统 ext2在分区的时候会分成多个组块(block group)和一个启动扇区(boot sector),每一个组块内又有superblock.File system ...
- 基于NMAP日志文件的暴力破解工具BruteSpray
基于NMAP日志文件的暴力破解工具BruteSpray 使用NMAP的-sV选项进行扫描,可以识别目标主机的端口对应的服务.用户可以针对这些服务进行认证爆破.为了方便渗透测试人员使用,Kali L ...
- Xcode代码提示里的字母含义
P -- 协议 M -- 成员方法 C -- 类 K -- 枚举 .常量 V -- 成员变量 T -- typedef类型 G -- 全局变量 f -- 函数 # -- #define指令
- 简单机器学习人脸识别工具face-recognition python小试,一行代码实现人脸识别
摘要: 1行代码实现人脸识别,1. 首先你需要提供一个文件夹,里面是所有你希望系统认识的人的图片.其中每个人一张图片,图片以人的名字命名.2. 接下来,你需要准备另一个文件夹,里面是你要识别的图片.3 ...
- 【BZOJ 3998】 3998: [TJOI2015]弦论 (SAM )
3998: [TJOI2015]弦论 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 2627 Solved: 881 Description 对于一 ...
- 企业级SOA之路——在Web Service中使用HTTP和JMS
原文:http://www.tibco.com/resources/solutions/soa/enterprise_class_soa_wp.pdf 概述 IT业界在早期有一种误解,认为 ...
- [BZOJ4416][SHOI2013]阶乘字符串(子集DP)
怎么也没想到是子集DP,想到了应该就没什么难度了. 首先n>21时必定为NO. g[i][j]表示位置i后的第一个字母j在哪个位置,n*21求出. f[S]表示S的所有全排列子序列出现的最后末尾 ...