千家信息网

怎么实现C#与Lua相互调用

发表于:2026-10-31 作者:千家信息网编辑
千家信息网最后更新 2026年10月31日,这篇文章主要介绍"怎么实现C#与Lua相互调用"的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇"怎么实现C#与Lua相互调用"文章能帮助大家解决问题。一、编译Lu
千家信息网最后更新 2026年10月31日怎么实现C#与Lua相互调用

这篇文章主要介绍"怎么实现C#与Lua相互调用"的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇"怎么实现C#与Lua相互调用"文章能帮助大家解决问题。

一、编译Lua动态链接库

1. 编译Windows下使用的DLL文件

使用VS2015创建一个空的动态链接库项目,删除里面默认创建的几个文件(如果想自定义拓展可用保留),然后把Lua的源码拷贝进来,添加到项目工程中,编译宏需要配置LUA_BUILD_AS_DLL和_CRT_SECURE_NO_WARNINGS。然后就可以编译x86和x64的DLL动态库,整体步骤简单易操作。

2. 编译Android下使用的SO文件

通过NDK编译Android需要的so动态库,因此需要手写Application.mk和Android.mk两个mk文件,下面是我使用的两个文件的内容,创建放在上面VS的工程里面即可,路径是在lua源码src的上一层目录。

# Application.mkAPP_PLATFORM = android-23APP_ABI := armeabi-v7a arm64-v8aAPP_STL := stlport_shared
# Android.mkLOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)MY_FILES_PATH  :=  $(LOCAL_PATH)/srcMY_FILES_SUFFIX := %.cMY_UN_INCLUDE := %lua.c %luac.c# 递归遍历目录下的所有的文件rwildcard=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))# 获取相应的源文件MY_ALL_FILES := $(foreach src_path,$(MY_FILES_PATH), $(call rwildcard,$(src_path),*.*) )MY_SRC_LIST  := $(filter $(MY_FILES_SUFFIX),$(MY_ALL_FILES))MY_SRC_LIST  := $(filter-out $(MY_UN_INCLUDE),$(MY_SRC_LIST))MY_SRC_LIST  := $(MY_SRC_LIST:$(LOCAL_PATH)/%=%)LOCAL_SRC_FILES = $(MY_SRC_LIST)#打印编译信息$(warning 'src_list='$(LOCAL_SRC_FILES))LOCAL_MODULE    := CSharpLuaLOCAL_LDLIBS += -ldlLOCAL_CFLAGS := $(L_CFLGAS)include $(BUILD_SHARED_LIBRARY)

将上面的mk文件放置完成后,打开CMD命令行,执行ndk编译。由于并不是在Android的jni项目目录,因此执行命令会有所不同,可以使用下面的命令执行生成,等待ndk执行完成后就生成了需要的so库。

ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk NDK_APPLICATION_MK=./Application.mk

二、编写C#使用的API

1. 动态链接库在Unity中的存放位置。

在Unity项目Assets目录里面创建Plugins目录,用于存放不同平台的DLL库。Windows需要的DLL存放的目录为Assets/Plugins/x86和Assets/Plugins/x86_64;Android需要的SO文件存放的目录为Assets/Android/[libs/arm64-v8a]括号里面的目录其实就是上面NDK编译后生成的路径。

2. 编写C#的API[LuaDll.cs]

大部分的动态库中的接口直接使用以下这种方式即可使用,使用IntPtr来表示lua_State*对象,传入参数char*可用使用byte[]或者string,但是会有一点点区别。

[DllImport("CSharpLua", EntryPoint = "luaL_newstate")]public static extern IntPtr luaL_newstate();[DllImport("CSharpLua", EntryPoint = "luaL_openlibs")]public static extern void luaL_openlibs(IntPtr L);[DllImport("CSharpLua", EntryPoint = "luaL_loadbuffer")]public static extern int luaL_loadbuffer(IntPtr L, byte[] buff, uint size, string name);[DllImport("CSharpLua", EntryPoint = "lua_call")]public static extern void lua_call(IntPtr L, int nargs, int nresults);[DllImport("CSharpLua", EntryPoint = "lua_pcall")]public static extern int lua_pcall(IntPtr L, int nargs, int nresults, int errfunc); 

3.需要注意的几个地方

1. 返回char*时,不可直接使用string替换,否则调用会导致崩溃,因此需要像下面代码展示的那样进行一下转换才可以使用。

[DllImport("CSharpLua", EntryPoint = "lua_tolstring")]private static extern IntPtr _lua_tolstring(IntPtr L, int idx, ref uint size);public static string lua_tolstring(IntPtr L, int idx, ref uint size){    IntPtr buffer = _lua_tolstring(L, idx, ref size);    return Marshal.PtrToStringAnsi(buffer);}

2. C#函数传递给Lua使用时,需要使用delegate委托类型。

public delegate int LuaFunction(IntPtr L);[DllImport("CSharpLua", EntryPoint = "lua_pushcclosure")]public static extern void lua_pushcclosure(IntPtr L, LuaFunction func, int idx);public static void lua_pushcfunction(IntPtr L, LuaFunction func){   lua_pushcclosure(L, func, 0);}

3. 在lua源码中定义的宏代码是无法使用的,会提示找不到,需要在C#中手动实现,例如下面展示的2个宏。

#define lua_setglobal(L,s)  lua_setfield(L, LUA_GLOBALSINDEX, (s))#define lua_getglobal(L,s)  lua_getfield(L, LUA_GLOBALSINDEX, (s))
[DllImport("CSharpLua", EntryPoint = "lua_getfield")]public static extern void lua_getfield(IntPtr L, int idx, string s);public static void lua_getglobal(IntPtr L, string s){   lua_getfield(L, LUA_GLOBALSINDEX, s);}[DllImport("CSharpLua", EntryPoint = "lua_setfield")]public static extern void lua_setfield(IntPtr L, int idx, string s);public static void lua_setglobal(IntPtr L, string s){   lua_setfield(L, LUA_GLOBALSINDEX, s);}

4. 如需要将C#的类实例对象即userdata传递给lua,需要在C#中转换成IntPtr后传递,Lua返回的则需要通过IntPtr转换回C#的实例对象。

[DllImport("CSharpLua", EntryPoint = "lua_pushlightuserdata")]public static extern void _lua_pushlightuserdata(IntPtr L, IntPtr p);public static void lua_pushlightuserdata(IntPtr L, T p){    IntPtr obj = Marshal.GetIUnknownForObject(p);    _lua_pushlightuserdata(L, obj);}[DllImport("CSharpLua", EntryPoint = "lua_touserdata")]public static extern IntPtr _lua_touserdata(IntPtr L, int idx);public static T lua_touserdata(IntPtr L, int idx){   IntPtr p = _lua_touserdata(L, idx);   return (T)Marshal.GetObjectForIUnknown(p);}

三、C#与Lua的相互调用举例

1. C#中创建Lua环境

IntPtr L = LuaDll.luaL_newstate();LuaDll.luaL_openlibs(L);

2. 加载Lua代码并执行,调用Lua的函数及向Lua传递参数。

var data = Resources.Load(lua_file);int rc = LuaDll.luaL_loadbuffer(L, data.bytes, (uint)data.bytes.Length, lua_file);rc = LuaDll.lua_pcall(L, 0, 0, 0)LuaDll.lua_getglobal(L, "main");// 传递参数LuaDll.lua_pushinteger(L, 3333);LuaDll.lua_pushnumber(L, 3.3);// 执行main方法int i = LuaDll.lua_pcall(L, 2, 0, 0);

3. 将C#函数提供给Lua使用,需要使用静态方法参考上面LuaFunction的定义。

LuaDll.lua_pushcfunction(L, LuaPrint);LuaDll.lua_setglobal(L, "print");[MonoPInvokeCallback]   // 这个主要是在Android上需要。static int LuaPrint(IntPtr L){  Debug.Log(".....");  return 0;}

4. Lua代码调用C#方法并提供回调,由C#函数调用。

static int FindAndBind(IntPtr L){   GameObject go = LuaDll.lua_touserdata(L, 1);   string path = LuaDll.lua_tostring(L, 2);   // 这里将lua的函数放到LUA_REGISTRYINDEX上   int idx = LuaDll.luaL_refEx(L);   Transform t = go.transform.Find(path);   Button btn = t.GetComponent

关于"怎么实现C#与Lua相互调用"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注行业资讯频道,小编每天都会为大家更新不同的知识点。

C# 编译 文件 目录 函数 动态 代码 方法 项目 不同 参数 命令 对象 是在 源码 知识 链接 两个 内容 实例 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网科技企业 广州为想互联网科技有限公司 互联网科技公司经营范围 互联网科技工作委员会毛军 金融科技 互联网金融 易互联网科技有限公司 互联网科技小额贷款 互联网科技的未来发展 深圳期待互联网科技 深圳市运趣互联网科技有限公司 哈尔滨新华互联网科技学院 互联网软件和科技 互联网科技人工智能实验室 每天都有哪些好的互联网科技 互联网相关科技技术 济南小医互联网科技有限公司招聘 广州梦谷互联网科技有限公司领导 米泉互联网科技专业怎么样 保山浩联互联网科技有限公司 华人运通互联网科技公司 西安纸贵互联网科技有限公司 科技互联网产品 浩特互联网科技 银优互联网科技有限公司 互联网科技公司有风险吗 洛阳共同富裕互联网科技有限公司 深圳市罗太互联网科技有限公司 互联网第三次科技革命特征 广东鹅鹅鹅互联网科技有限公司 知域互联网科技有限公司官网
0