zoukankan      html  css  js  c++  java
  • 【C#】 使用Gsof.Native 动态调用 C动态库

    【C#】 使用Gsof.Native 动态调用 C动态库

    一、背景

    使用C# 开发客户端时候,我们经常会调用一些标准的动态库或是C的类库。
    虽然C# 提供的PInvoke的方式,但因为使用的场景的多变,有些时候可能没办法,固定位置的调用,或是需要按需求调用不同的库。 设置当前目录的方式,有时会有加载不到的问题。
    CLI的方式又需要用C++做再次的封装。

    二、说明

    1. 支持根据路径动态加载DLL类库
    2. 支持using 销毁加载的类库
    3. 调用方便

    github: https://github.com/gaoshang212/gsof/tree/master/Gsof.Native

    nuget: https://www.nuget.org/packages/Gsof.Native/

    接口说明:

    NativeFactory 创建INative调用对象:

    /// <summary>
    /// 创建INative 对象
    /// </summary>
    /// <param name="p_fileName">文件路径</param>
    /// <returns></returns>
    public static INative Create(string p_fileName);
    
    /// <summary>
    /// 创建INative 对象
    /// </summary>
    /// <param name="p_fileName">文件路径</param>
    /// <param name="p_calling">调用转换方式(同PInvoke CallingConvention)/param>
    /// <returns></returns>
    public static INative Create(string p_fileName, CallingConvention _calling);
    
    /// <summary>
    /// 销毁INative, 也可以调用 Native的Dispose方法
    /// </summary>
    /// <param name="p_native"></param>
    public static void Free(INative p_native);
    

    INative:

    public interface INative : IDisposable
    {
        /// <summary>
        /// 获取函数委托
        /// </summary>
        /// <typeparam name="TDelegate"></typeparam>
        /// <returns></returns>
        TDelegate GetFunction<TDelegate>();
        /// <summary>
        /// 函数委托调用方式
        /// </summary>
        /// <typeparam name="TResult">返回值类型</typeparam>
        /// <typeparam name="TDelegate">函数对应的委托类型</typeparam>
        /// <param name="p_params">函数传参</param>
        /// <returns></returns>
        TResult Invoke<TResult, TDelegate>(params object[] p_params);
        /// <summary>
        /// 函数名调用
        /// </summary>
        /// <typeparam name="TResult">返回值类型</typeparam>
        /// <param name="p_funName">函数名</param>
        /// <param name="p_params">函数传参</param>
        /// <returns></returns>
        TResult Invoke<TResult>(string p_funName, params object[] p_params);
        /// <summary>
        /// 函数名调用
        /// </summary>
        /// <typeparam name="TResult">返回值类型</typeparam>
        /// <param name="p_funName">函数名</param>
        /// <param name="p_calling">调用转换方式(同PInvoke CallingConvention)</param>
        /// <param name="p_params">函数传参</param>
        /// <returns></returns>
        TResult Invoke<TResult>(string p_funName, CallingConvention p_calling, params object[] p_params);
        /// <summary>
        /// 函数名调用(非泛型)
        /// </summary>
        /// <param name="p_funName">函数名</param>
        /// <param name="p_retrunType">返回值类型</param>
        /// <param name="p_params">函数传参</param>
        /// <returns></returns>
        object Invoke(string p_funName, Type p_retrunType, params object[] p_params);
        /// <summary>
        /// 函数委托调用方式
        /// </summary>
        /// <typeparam name="TDelegate">函数对应的委托类型</typeparam>
        /// <param name="p_params">函数传参</param>
        void Call<TDelegate>(params object[] p_params);
        /// <summary>
        /// 函数名调用
        /// </summary>
        /// <param name="p_funName">函数名</param>
        /// <param name="p_params">函数传参</param>
        void Call(string p_funName, params object[] p_params);
        /// <summary>
        /// 函数名调用
        /// </summary>
        /// <param name="p_funName">函数名</param>
        /// <param name="p_calling">调用转换方式(同PInvoke CallingConvention)</param>
        /// <param name="p_params">函数传参</param>
        void Call(string p_funName, CallingConvention p_calling, params object[] p_params);
    }
    

    三、使用

    libtest.dll 为 中包括一个test函数

     int test(int input)
     {
         return input;
     }
    

    方法名调用

    
    int input = 0;
    int result = -1;
    using (var native = NativeFactory.Create(@"../../libtest.dll"))
    {
        result = native.Invoke<int>("test", input);
    }
    

    dynamic 方式调用

    • 优点:调用方便,简单类型调用时,不用做过多的定义。
    • 缺点:4.0下性能不理想,4.5+性能好很多,但相较于委托的方式,还差些。
    int input = 0;
    int result = -1;
    using (dynamic native = NativeFactory.Create(@"../../libtest.dll"))
    {
        result = native.test<int>(input);
    }
    

    委托方式调用

    • 优化:效率高,没有了第一次动态构造委托的消耗,可获取到函数委托增加 重复调用消耗
    • 缺点:如果函数较多,委托定义较为繁琐
    
    [NativeFuncton("test")]
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    delegate int Test(int p_sleep);
    
    public void DelegateFunction()
    {
        int input = 0;
        int result = -1;
        using (var native = NativeFactory.Create(@"../../libtest.dll"))
        {
            // 直接调用
            var result1 = native1.Invoke<int, Test>(input);
    
            // 获取函数委托调用 
            var test = native.GetFunction<Test>();
            result = test(input);
        }
    
        Assert.AreEqual(input, result);
    
    }
    
  • 相关阅读:
    黑马day07 注册案例(二)
    LeetCode--Best Time to Buy and Sell Stock (贪心策略 or 动态规划)
    让UIView窄斜
    Android Material Design-Creating Lists and Cards(创建列表和卡)-(三)
    c#为了实现自己的线程池功能(一)
    4、应用程序设置应用程序详细信息页面
    【NIO】dawn在buffer用法
    《ArcGIS Runtime SDK for .NET开发笔记》--在线编辑
    ArcGIS Runtime SDK for .NET (Quartz Beta)之连接ArcGIS Portal
    《ArcGIS Runtime SDK for .NET开发笔记》--三维功能
  • 原文地址:https://www.cnblogs.com/gaoshang212/p/8809360.html
Copyright © 2011-2022 走看看