【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);

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章