我面临的这个问题涉及两个部分:
将任意结构从C传递给Lua函数。举个例子,考虑这两个结构:
struct Person{
int age;
char *name;
};
struct Paper{
int width;
int height;
char *color;
};
我希望能够通过简单的C函数将它们传递给Lua,例如:
template<class T>
void call(T t){
... (pseudo-code)
check t:
if Person, lua_getglobal(L, "sendPerson")
if Paper, lua_getglobal(L, "sendPaper")
for each element in t, check its type
if integer, lua_pushinteger(...)
if char*, lua_pushstring(...)
...
lua_pcall(...)
}
Person p = {33, "David"};
Paper A4 = {210, 297, "white"};
call(p);
call(A4);
2)访问。在Lua方面,我如何通过名称访问这些变量?
function sendPerson(p)
print(p.age)
print(p.name)
end
function sendPaper(p)
print(p.width)
print(p.height)
print(p.color)
end
我知道我可以使用setfield
,但除非我可以在调用Lua函数的泛型方法中调用它,否则我看不出它是如何实现的。
更新:这是代码。例如,这是WM_LBUTTONDOWN事件。这样,我需要有2个方法和1个结构用于处理我发送给lua的消息:第一个创建线程的方法,第二个调用lua函数的方法,以及结构,所以我可以将它作为参数传递给线程功能
struct LButtonEvent{
int x, y, k;
};
LuaScript *L = new LuaScript(FILENAME);
void _onLButtonDown(LPVOID arg)
{
LButtonEvent *b = (LButtonEvent*) arg;
lua_State *l = L->getState();
lua_getglobal(l, "onLButtonDown");
lua_newtable(l);
lua_pushinteger(l, b->x); lua_setfield(l, -2, "x");
lua_pushinteger(l, b->y); lua_setfield(l, -2, "y");
lua_pushinteger(l, b->k); lua_setfield(l, -2, "k");
lua_pcall(l, 1, 0, 0);
}
void LuaScript::onLButtonDown(LButtonEvent b)
{
// I want my window to continue proccessing messages. If lua script calls "sleep", the window freezes.
CreateThread(0, 0, (LPTHREAD_START_ROUTINE) _onLButtonDown, (LPVOID) &b, 0, 0);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_LBUTTONDOWN:
LButtonEvent b;
b.x = (int)(short)LOWORD(lParam);
b.y = (int)(short)HIWORD(lParam);
b.k = wParam;
L->onLButtonDown(b);
break;
....
}
return 0;
}
答案 0 :(得分:2)
我不会通过不同的功能来区分这两种(或更多)类型。使用metatables!这样,你不需要知道确切的类型,只需使用唯一的可用函数,它就会做正确的事情。
在这里您可以看到如何做到这一点,但请记住,有更好的方法来创建和打开库。
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include <stdio.h>
int create_person(lua_State* L)
{
int age = lua_tointeger(L, -2);
const char* name = lua_tostring(L, -1);
lua_newtable(L);
lua_pushinteger(L, age);
lua_pushstring(L, name);
lua_setfield(L, -3, "name");
lua_setfield(L, -2, "age");
luaL_setmetatable(L, "personmeta");
return 1;
}
int print_person(lua_State* L)
{
lua_getfield(L, -1, "name");
const char* name = lua_tostring(L, -1);
lua_getfield(L, -2, "age");
int age = lua_tointeger(L, -1);
printf("Name: %s\nAge : %d\n", name, age);
return 0;
}
int create_paper(lua_State* L)
{
int width = lua_tointeger(L, -3);
int height = lua_tointeger(L, -2);
const char* color = lua_tostring(L, -1);
lua_newtable(L);
lua_newtable(L);
lua_pushinteger(L, width);
lua_pushinteger(L, height);
lua_setfield(L, -3, "height");
lua_setfield(L, -2, "width");
lua_pushstring(L, color);
lua_setfield(L, -3, "color");
lua_setfield(L, -2, "dimensions");
luaL_setmetatable(L, "papermeta");
return 1;
}
int print_paper(lua_State* L)
{
lua_getfield(L, -1, "color");
const char* color = lua_tostring(L, -1);
lua_getfield(L, -2, "dimensions");
lua_getfield(L, -1, "width");
lua_getfield(L, -2, "height");
int height = lua_tointeger(L, -1);
int width = lua_tointeger(L, -2);
printf("Paper: { %d, %d, %s }\n", width, height, color);
return 0;
}
int luaopen_llib(lua_State* L)
{
// initialization
// create metatable for persons
luaL_newmetatable(L, "personmeta");
luaL_newmetatable(L, "personmeta");
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, print_person);
lua_setfield(L, -2, "print");
lua_pop(L, 1);
// create metatable for paper
luaL_newmetatable(L, "papermeta");
luaL_newmetatable(L, "papermeta");
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, print_paper);
lua_setfield(L, -2, "print");
lua_pop(L, 1);
// create library table and store the creation functions
lua_newtable(L);
lua_pushcfunction(L, create_person);
lua_setfield(L, -2, "create_person");
lua_pushcfunction(L, create_paper);
lua_setfield(L, -2, "create_paper");
return 1;
}
Lua测试代码:
local llib = require "llib"
local p = llib.create_person(33, "David")
p:print() -- Name: David
-- Age : 33
local paper = llib.create_paper(210, 297, "white")
paper:print() -- Paper: { 210, 297, "white" }
当然,您需要相应地命名此库。
如果您需要使用userdata,您可以使用相同的方式。 Userdata可以有metatables。