C#加载C、C++动态库的方法

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


你可能感兴趣的:(DLL)