1、针对托管动态库的调用
本文章中的外部调用函数声明如下:
public delegate int PutValue(string name, string value);
Assembly ass = Assembly.LoadFile(filePath);//这里是动态库的路径。
Type tWorker = ass.GetType(dllType);//dllType是你所需要调用的动态库文件的命名空间+类名(NameSpace.Class)
object worker = Activator.CreateInstance(tWorker);//创建对象
MethodInfo method = tWorker.GetMethod(PutValue);//需要执行的函数
//执行函数,后一个参数即为执行函数需要的参数,若无则为null
method.Invoke(tworker, new object[] { "transType", transType });
tWorker.InvokeMember("PutValue", BindingFlags.InvokeMethod, null, worker,
new object[] { "transType", transType }); //使用这句可以替换上面两句
2、针对非托管动态库的调用
2.1 静态调用
[DllImport(@"XXX.dll", EntryPoint = "PutValue", CharSet = CharSet.Ansi,
CallingConvention = CallingConvention.StdCall)]
public static extern int PutValue(string name, string value);
PutValue("transType", transType);
2.2 动态调用
public class DllInvoke
{
public DllInvoke()
{
}
public DllInvoke(string lpFileName)
{
LoadDll(lpFileName);
}
// 参数传递方式枚举 ,ByValue 表示值传递 ,ByRef 表示址传递
public enum ModePass
{
ByValue = 0x0001,
ByRef = 0x0002
}
[DllImport("Kernel32.dll")]
private static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("Kernel32.dll")]
private static extern IntPtr GetProcAddress(IntPtr hModule, string lpFunName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
// Loadlibrary 返回的函数库模块的句柄
private IntPtr m_hModule = IntPtr.Zero;
// 装载 Dll
public void LoadDll(string lpFileName)
{
m_hModule = LoadLibrary(lpFileName);
if (m_hModule == IntPtr.Zero)
{
throw (new Exception("没有找到:" + lpFileName + "."));
}
}
// 获得函数指针
private IntPtr LoadFun(string lpFunName)
{
IntPtr hFuncProc;
// 若函数库模块的句柄为空,则抛出异常
if (m_hModule == IntPtr.Zero)
{
throw (new Exception("函数库模块的句柄为空,请确保已进行 LoadDll 操作!"));
}
// 取得函数指针
hFuncProc = GetProcAddress(m_hModule, lpFunName);
// 若函数指针为空,则抛出异常
if (hFuncProc == IntPtr.Zero)
{
throw (new Exception("没有找到:" + lpFunName + " 这个函数的入口点."));
}
return hFuncProc;
}
// 卸载 Dll
public void UnLoadDll()
{
if (m_hModule != IntPtr.Zero)
{
FreeLibrary(m_hModule);
m_hModule = IntPtr.Zero;
}
}
// 方法一:使用C#提供的函数进行调用
public object Invoke(string funcName, object[] ObjArray_Parameter,
Type[] TypeArray_ParameterType, ModePass[] ModePassArray_Parameter, Type Type_Return)
{
IntPtr hFuncProc = IntPtr.Zero;
// 下面 3 个 if 是进行安全检查 , 若不能通过 , 则抛出异常
if (m_hModule == IntPtr.Zero)
{
throw (new Exception("函数库模块的句柄为空,请确保已进行 LoadDll 操作!"));
}
if (ObjArray_Parameter.Length != ModePassArray_Parameter.Length)
{
throw (new Exception("参数个数及其传递方式的个数不匹配."));
}
hFuncProc = LoadFun(funcName);
// 下面是创建 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();
for (int 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, hFuncProc.ToInt32());
}
else if (IntPtr.Size == 8)
{
IL.Emit(OpCodes.Ldc_I8, hFuncProc.ToInt64());
}
else
{
throw new PlatformNotSupportedException();
}
IL.EmitCalli(OpCodes.Calli, CallingConvention.Cdecl, Type_Return, TypeArray_ParameterType);
IL.Emit(OpCodes.Ret); // 返回值
MyModuleBuilder.CreateGlobalFunctions();
// 取得方法信息
MethodInfo MyMethodInfo = MyModuleBuilder.GetMethod("MyFun");
return MyMethodInfo.Invoke(null, ObjArray_Parameter);// 调用方法,并返回其值
}
// 方法二:使用windows提供的API进行调用
public Delegate Invoke(string lpFunName, Type type)
{
IntPtr hFunProc = LoadFun(lpFunName);
return (Delegate)Marshal.GetDelegateForFunctionPointer(hFunProc, type);
}
~DllInvoke()
{
UnLoadDll();
}
}
使用方法如下:
public class UnmanagedDynamicLoad
{
private static DllInvoke dynamicDll;
// 动态加载DLL使用方法一:windows api 加载,简单,建议使用此方法
public delegate int MyPutValue(string name, string value);
static MyPutValue PutValue;
public static void ReLoadDll(string strDllPath)
{
if (dynamicDll != null)
{
dynamicDll.UnLoadDll();
}
dynamicDll = new DllInvoke(strDllPath);
PutValue = (MyPutValue)dynamicDll.Invoke("PutValue", typeof(MyPutValue));
}
// 动态加载DLL使用方法二:C#提供的接口加载
/*
private static void PutValue(string name, string value)
{
object[] Parameters = new object[] { name, value };
Type[] ParameterTypes = new Type[] { typeof(string), typeof(string) };
DllInvoke.ModePass[] themode = new DllInvoke.ModePass[] {
DllInvoke.ModePass.ByValue, DllInvoke.ModePass.ByValue };
dynamicDll.Invoke("PutValue", Parameters, ParameterTypes, themode, typeof(int));
}
*/
//进行调用
public static void doPay(string transType)
{
try
{
PutValue("transType", transType);
}
catch (Exception ex)
{
throw (new Exception(transType + "支付操作异常:" + ex.ToString()));
}
dynamicDll.UnLoadDll();
}
}