项目中一直使用tolua框架,底层使用C#开发,逻辑使用lua开发。借助tolua的源码,研究一下lua与C#是如何互相调用的,然后自己写了个简单的demo作为记录。
Demo里没有拿lua的源码编译,而是直接使用lua的静态库,将lua库中的方法封装成为动态库dll给C#使用。涉及到两个工程:
首先是c++的dll工程,包含了lua库的一些方法(此处仅为演示,所以手动包装了一些用到的),暴露给C#调用;
其次是c#的工程,引用前一步的dll库,并且通过其接口来调用lua库的函数以实现交互。
涉及到的源码托管在GitHub。
lua-cs
在lua中调用C#基本步骤如下(仅供演示用,其中省略掉了lua栈数据及类型检查等步骤):
首先定义委托类型
LuaCSFunction
1
2[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int LuaCSFunction(IntPtr luaState);根据C#函数(
CSFunc
)得到对应的wrap函数(CSFuncWrap
)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17static int CSFunc(int a, int b)
{
Console.WriteLine("[CS] this is CSFunc with args a = " + a + " and b = " + b);
int ret = 10 * a + b;
Console.WriteLine("[CS] ret will be " + ret);
return ret;
}
static int CSFuncWrap(IntPtr L)
{
CppDll.LuaGetTop(L);
int arg0 = (int)CppDll.LuaToNumber(L, 1);
int arg1 = (int)CppDll.LuaToNumber(L, 2);
int o = CSFunc(arg0, arg1);
CppDll.LuaPushNumber(L, o);
return 1;
}将wrap函数封送到C++
1
2IntPtr fn = Marshal.GetFunctionPointerForDelegate((LuaCSFunction) (CSFuncWrap));
CppDll.RegisterCSFunc(L, "CSFunc", fn);RegisterCSFunc
定义如下,将封送的函数以lua_CFunction
的方式push到lua1
2
3
4
5DLL_API void RegisterCSFunc(lua_State *L, const char *name, lua_CFunction fn)
{
lua_pushcfunction(L, fn);
lua_setglobal(L, name);
}这里是以全局函数的方式注册的,表函数类似,先取表再push。
在lua中调用wrap函数
1
local ret = CSFunc(1,2);
cs-lua
在C#中调用lua的主要步骤(同样简化省略掉了一些对于lua栈中数据及类型判断的过程):
在lua中定义函数如下
1
2
3
4
5
6LuaFunc = function(x,y)
print('[lua] this is LuaFunc with args x = ' .. x .. ' and y = ' .. y);
local ret = x * 10 + y;
print('[lua] ret will be ' .. ret);
return ret;
end将待调用的lua函数放到栈顶(也是全局函数,如果是表中的函数需要先取一次表)
1
CppDll.LuaGetGlobal(L, "LuaFunc");
push参数,调用pcall,获取结果
1
2
3
4CppDll.LuaPushNumber(L, 3);
CppDll.LuaPushNumber(L, 5);
CppDll.LuaPCall(L, 2, 1, 0);
int ret = (int)CppDll.LuaToNumber(L, 1);
这一过程可以进一步封装,并在C#中缓存lua函数以减少lua栈操作。