C#动态调用C++的DLL
最近在C#项目中需要使用C++的DLL,研究了下如何调用
一.般调用方式
一般情况通常使用DllImport来调用DLL.但是这个方式的话必须制定DLL的路径,如果想动态指定路径的话这个方式没法实现
二.动态调用
我的想法是这样的,先定义出dll中的函数,然后调用,这样可以把dll的声明声明的全部放到配置文件中
1.加载DLL,然后使用动态创建出Assembly
public DynamicDLL Load()
{
this.Handle = Kernel32.LoadLibrary(this.FilePath);
if (this.Handle.IsNull)
{
throw new Exception("模块加载失败...");
}
//创建 AssemblyName
AssemblyName assemblyName = new AssemblyName()
{
Name = this.UniqueName
};
this.AssemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
this.ModuleBuilder = AssemblyBuilder.DefineDynamicModule(this.UniqueName + "Module");
this.TypeBuilder = this.ModuleBuilder.DefineType(this.UniqueName + "Type", TypeAttributes.Public);
return this;
}
2.用IL定义调用的方法,暂时只实现了简单的参数,复杂参数用到的时候再添加
public DynamicDLL DefineMethod<T>(string name, params ParameterObject[] @params)
{
if (this.Handle.IsNull)
{
throw new Exception("模块加载失败...");
}
var pFunc = Kernel32.GetProcAddress(this.Handle, name);
if (pFunc == IntPtr.Zero)
{
throw (new Exception($"未找到:[{name}]的入口点 "));
}
var returnType = typeof(T);
var paramTypes = @params.Select(t => t.Type).ToArray();
//生成调用的方法
MethodBuilder methodBuilder = this.TypeBuilder.DefineMethod(name, MethodAttributes.Public | MethodAttributes.Static, returnType, paramTypes);
//获取一个 ILGenerator 用于发送所需的 IL
ILGenerator IL = methodBuilder.GetILGenerator();
for (int i = 0; i < @params.Length; i++)
{
var item = @params[i];
//用循环将参数依次压入堆栈
switch (item.Mode)
{
case ParameterModes.ByValue:
IL.Emit(OpCodes.Ldarg, i);
break;
case ParameterModes.ByRef:
IL.Emit(OpCodes.Ldarga, i);
break;
}
}
//判断处理器类型,压入函数地址
if (IntPtr.Size == 4)
{
IL.Emit(OpCodes.Ldc_I4, pFunc.ToInt32());
}
else if (IntPtr.Size == 8)
{
IL.Emit(OpCodes.Ldc_I8, pFunc.ToInt64());
}
else
{
throw new PlatformNotSupportedException();
}
//调用方式
IL.EmitCalli(OpCodes.Calli, CallingConvention.StdCall, returnType, paramTypes);
//返回值
IL.Emit(OpCodes.Ret);
return this;
}
3.创建Type
public void CreateClass()
{
this.TypeClass = this.TypeBuilder.CreateType();
}
4.创建调用方法
public T Invoke<T>(string name, params object[] @params)
{
var method = this.TypeClass.GetMethod(name);
return (T)method.Invoke(null, @params);
}
5.创建一个描述参数的类
public class ParameterObject
{
public ParameterModes Mode { get; set; }
public Type Type { get; set; }
public static ParameterObject Instance(Type type, ParameterModes mode = ParameterModes.ByValue)
{
return new ParameterObject()
{
Mode = mode,
Type = type
};
}
}
6.定义方法,然后想怎么调怎么调…
DynamicDLL dll = new DynamicDLL("TestDll.dll"))
dll.Load()
.DefineMethod<int>("Fix")
.DefineMethod<int>("Fix1",ParameterObject.Instance(typeof(int)), ParameterObject.Instance(typeof(int)))
.CreateClass();
var value = dll.Invoke<int>("Fix1", 2, 3);
value = dll.Invoke<int>("Fix1", 4, 5);
value = dll.Invoke<int>("Fix1", 1, 1);
value = dll.Invoke<int>("Fix");
7.C++函数定义在此
extern "C" __declspec(dllexport) int Fix();
extern "C" __declspec(dllexport) int Fix1(int a, int b);
int Fix()
{
return 2;
}
int Fix1(int a, int b)
{
return a + b;
}
第一篇博文,完结撒花…