UE(虚幻)学习(三) UnrealSharp插件中调用非托管DLL

上一篇文章中我使用UnrealSharp成功使用了我的一个C#控制台程序中的网络模块,这个程序是基于KCP网络了,其中调用了Cmake 编译的一个C++的DLL,在虚幻中DLL需要放在Binaries目录中才可以。Unity中只要放在任意Plugins目录中就可以。
但是Binaries目录版本控制一般不提交,我们可以改一下,改成按照路径加载。

修改前的脚本

using System.Runtime.InteropServices;

//脚本修改自//https://github.com/a11s/kcp_warpper

namespace NetLibrary
{
    
    public unsafe class KCP
    {


        const string LIBNAME = "libikcp.dll";
        //---------------------------------------------------------------------
        // interface
        //---------------------------------------------------------------------

        /// <summary>
        /// create a new kcp control object, 'conv' must equal in two endpoint
        /// from the same connection. 'user' will be passed to the output callback
        /// output callback can be setup like this: 'kcp->output = my_udp_output'
        /// </summary>
        /// <param name="conv"></param>
        /// <param name="user"></param>
        /// <returns></returns>
        [DllImport(LIBNAME, EntryPoint = "ikcp_create", CallingConvention = CallingConvention.Cdecl)]
        public static extern IKCPCB* ikcp_create(uint conv, void* user);

        /// <summary>
        /// release kcp control object
        /// </summary>
        /// <param name="kcp"></param>
        [DllImport(LIBNAME, EntryPoint = "ikcp_release", CallingConvention = CallingConvention.Cdecl)]
        public static extern void ikcp_release(IKCPCB* kcp);

        /// <summary>
        /// set output callback, which will be invoked by kcp
        ///public static extern void ikcp_setoutput(IKCPCB* kcp, int (* output)(byte* buf, int len,             ikcpcb *kcp, void* user));
        /// </summary>
        /// <param name="kcp"></param>
        /// <param name="d_output"></param>
        [DllImport(LIBNAME, EntryPoint = "ikcp_setoutput", CallingConvention = CallingConvention.Cdecl)]
        public static extern void ikcp_setoutput(IKCPCB* kcp, System.IntPtr d_output);

       

篇幅太大没有必要,只展示部分代码片段。
可以看到之前是通过DllImport 载入LIBNAME变量来载入DLL的。

改为动态路径

先放上所有改动

// 动态获取库路径
private static string GetLibraryPath()
{
    string baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
    //动态库的路径被拼接到 Binaries\Managed\Third\libikcp.dll,而你的实际库文件存放在 E:\myproject\Third\libikcp.dll,这说明 AppDomain.CurrentDomain.BaseDirectory 返回的路径是 Binaries\Managed。
    baseDirectory = Path.Combine(baseDirectory, "../../");
    string relativePath;
    
    // 根据平台选择库路径
    if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
    {
        relativePath = "ThirdParty/Kcp/Win64/libikcp.dll";
    }
    else if (RuntimeInformation.IsOSPlatform(OSPlatform.Create("ANDROID")))
    {
        relativePath = "ThirdParty/Kcp/Android/arm64-v8a/libikcp.so";
    }
    else
    {
        throw new PlatformNotSupportedException("Unsupported platform");
    }

    return Path.Combine(baseDirectory, relativePath);
}

// DllImport 使用动态路径
private const string LIBNAME = "PLACEHOLDER"; // 占位符
private static bool _isResolverSet = false;
// 添加初始化方法以动态设置路径
public static void Initialize()
{
    if (_isResolverSet)
    {
        Loger.Debug($"BSserver DLL: 已经加载过了 .");
        return;
    }
    try
    {
        string libraryPath = GetLibraryPath();
        
        //Loger.Error($"BSserver DLL:{libraryPath}");
        NativeLibrary.SetDllImportResolver(typeof(KCP).Assembly, (name, assembly, path) =>
        {
            if (name == LIBNAME)
            {
                return NativeLibrary.Load(libraryPath);
            }
            return IntPtr.Zero;
        });
        _isResolverSet = true;
    }
    catch(Exception e) {
        //AClientMain.inst.PrintString("C# : DLL:" + libraryPath);
        Console.WriteLine($"Loaded library 加载错误 ."+e.Message);
        Loger.Error($"BSserver DLL 加载错误 : " + e.Message);
    }
    
}
//const string LIBNAME = "libikcp.dll";
//---------------------------------------------------------------------
// interface
//---------------------------------------------------------------------

/// <summary>
/// create a new kcp control object, 'conv' must equal in two endpoint
/// from the same connection. 'user' will be passed to the output callback
/// output callback can be setup like this: 'kcp->output = my_udp_output'
/// </summary>
/// <param name="conv"></param>
/// <param name="user"></param>
/// <returns></returns>
[DllImport(LIBNAME, EntryPoint = "ikcp_create", CallingConvention = CallingConvention.Cdecl)]
public static extern IKCPCB* ikcp_create(uint conv, void* user);

/// <summary>
/// release kcp control object
/// </summary>
/// <param name="kcp"></param>
[DllImport(LIBNAME, EntryPoint = "ikcp_release", CallingConvention = CallingConvention.Cdecl)]
public static extern void ikcp_release(IKCPCB* kcp);

使用方法:
我们在UE的工程下创建目录ThirdParty,按照代码里的路径,把DLL放进去,按照不同平台。

在加载DLL之前,我们需要调用Initialize方法初始化动态设置路径就可以了。

这些代码是ChatGPT帮忙写的,经过几次修改有了这段代码。

小技巧

以前是内事不决问baidu,外事不决问google,现在是内事问豆包,外事问ChatGPT。 :)
但是小心AI一本正经的胡说八道。 :P

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Thinbug

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值