Use Gsof.Native to dynamically call the C dynamic library

Posted by hagman on Wed, 01 Apr 2020 05:38:17 +0200

Use Gsof.Native to dynamically call the C dynamic library

Background

When using C ා to develop clients, we often call some standard dynamic libraries or C class libraries.
Although the PInvoke method provided by C ා, due to the variety of scenarios used, sometimes it may not be possible to call at a fixed location, or to call different libraries as required.

Two, explain

  1. Support dynamic loading of DLL class library according to path
  2. Support using to destroy the loaded class library
  3. Easy to call

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

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

Interface Description:

NativeFactory creates an intrinsic calling object:

/// <summary>
/// Establish INative object
/// </summary>
/// <param name="p_fileName">File path</param>
/// <returns></returns>
public static INative Create(string p_fileName);

/// <summary>
/// Establish INative object
/// </summary>
/// <param name="p_fileName">File path</param>
/// <param name="p_calling">Call conversion method (same as PInvoke CallingConvention)/param>
/// <returns></returns>
public static INative Create(string p_fileName, CallingConvention _calling);

/// <summary>
/// Destruction INative, You can also call Native Of Dispose Method
/// </summary>
/// <param name="p_native"></param>
public static void Free(INative p_native);

INative:

public interface INative : IDisposable
{
    /// <summary>
    /// Get function delegate
    /// </summary>
    /// <typeparam name="TDelegate"></typeparam>
    /// <returns></returns>
    TDelegate GetFunction<TDelegate>();
    /// <summary>
    /// Function delegate call method
    /// </summary>
    /// <typeparam name="TResult">return type</typeparam>
    /// <typeparam name="TDelegate">Delegate type corresponding to function</typeparam>
    /// <param name="p_params">Function reference</param>
    /// <returns></returns>
    TResult Invoke<TResult, TDelegate>(params object[] p_params);
    /// <summary>
    /// Function name call
    /// </summary>
    /// <typeparam name="TResult">return type</typeparam>
    /// <param name="p_funName">Function name</param>
    /// <param name="p_params">Function reference</param>
    /// <returns></returns>
    TResult Invoke<TResult>(string p_funName, params object[] p_params);
    /// <summary>
    /// Function name call
    /// </summary>
    /// <typeparam name="TResult">return type</typeparam>
    /// <param name="p_funName">Function name</param>
    /// <param name="p_calling">Call conversion method (same as PInvoke CallingConvention)</param>
    /// <param name="p_params">Function reference</param>
    /// <returns></returns>
    TResult Invoke<TResult>(string p_funName, CallingConvention p_calling, params object[] p_params);
    /// <summary>
    /// Function name call(Non generic)
    /// </summary>
    /// <param name="p_funName">Function name</param>
    /// <param name="p_retrunType">return type</param>
    /// <param name="p_params">Function reference</param>
    /// <returns></returns>
    object Invoke(string p_funName, Type p_retrunType, params object[] p_params);
    /// <summary>
    /// Function delegate call method
    /// </summary>
    /// <typeparam name="TDelegate">Delegate type corresponding to function</typeparam>
    /// <param name="p_params">Function reference</param>
    void Call<TDelegate>(params object[] p_params);
    /// <summary>
    /// Function name call
    /// </summary>
    /// <param name="p_funName">Function name</param>
    /// <param name="p_params">Function reference</param>
    void Call(string p_funName, params object[] p_params);
    /// <summary>
    /// Function name call
    /// </summary>
    /// <param name="p_funName">Function name</param>
    /// <param name="p_calling">Call conversion method (same as PInvoke CallingConvention)</param>
    /// <param name="p_params">Function reference</param>
    void Call(string p_funName, CallingConvention p_calling, params object[] p_params);
}

Three, use

libtest.dll includes a test function for

 int test(int input)
 {
     return input;
 }

Method name call

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

dynamic mode call

  • Advantages: easy to call, simple type calls, do not do too much definition.
  • Disadvantages: the performance under 4.0 is not ideal, and 4.5 + performance is much better, but it is worse than the way of delegation.
int input = 0;
int result = -1;
using (dynamic native = NativeFactory.Create(@"../../libtest.dll"))
{
    result = native.test<int>(input);
}

Delegate method call

  • Optimization: high efficiency, without the consumption of the first dynamic construction of delegation, function delegation can be obtained to increase the consumption of repeated calls
  • Disadvantages: if there are many functions, the definition of delegation is cumbersome
[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"))
    {
        // Direct call
        var result1 = native1.Invoke<int, Test>(input);

        // Get function delegate call 
        var test = native.GetFunction<Test>();
        result = test(input);
    }

    Assert.AreEqual(input, result);

}

Topics: C# github