C#动态调用C++的DLL

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;
}

第一篇博文,完结撒花…

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值