我在 Delphi + Lua 上制作了一个简单的项目,通过 RTTI 使用 Delphi 可视化组件。主要实现思路基于luna.h
. 我喜欢暴雪使用存储在 xml 中的模板的想法(例如,当您可以在 TPanel 上放置多个对象并将其用作模板时),所以我几乎也实现了这一点。
问题是:一切正常,直到我通过 Lua 的回调创建对象,该回调使用与luna.h
Inject 代码几乎相同的代码。如果此对象具有“继承”xml 属性,则回调函数调用存储在 xml 中的对象的创建,通过又一次注入创建另一个对象。我收到导致 lua51.dll 的错误。
可能是回调和 Inject 都使用堆栈导致的问题,而回调函数尚未返回结果。那么我可以使用堆栈并通过回调创建对象吗?如果没有 - 是否有任何解决方法来实施它?暴雪确实以某种方式做到了。
更多细节:
1.应用程序注册Lua对象(例如TPanel
和许多其他)通过
cn := T.ClassName;
f := @StaticOnCreate;
lua_pushlightuserdata(L, self); // put offset to self into lightuserdata
lua_pushcclosure(L, f, 1);
lua_setglobal(L, PAnsiChar(UTF8Encode(cn))); // T() in lua will make a new instance.
与 luna.h 的区别 - 应用程序还存储了指向对象的指针(Delphi 对象是指针)以避免泛型(c 模板)
2. 现在 LuaTPanel
在全局表中
3. 通过使用
p = TPanel("somename")
在脚本中,Lua 调用应用程序的 StaticOnCreate。
4. StaticOnCreate 提取对象并调用类的函数
o := TLuaClassTemplate(lua_topointer(L, lua_upvalueindex(1)));
result := o.OnCreate(L);
5.OnCreate
函数提取name
等参数并创建类型的精确视觉对象,并使用与函数TPanel
相同的luna.h
代码inject
lua_newtable(FL); // create a new table for the class object ('self')
obj_index := lua_gettop(FL);
lua_pushnumber(FL, 0);
a := lua_newuserdata(FL, SizeOf(pointer)); // store a ptr to the ptr
a^ := obj; // set the ptr to the ptr to point to the ptr... >.>
luaL_newmetatable(FL, PAnsiChar(UTF8Encode(cn))); // get (or create) the classname_metatable
lua_pushstring(FL, PAnsiChar(UTF8Encode('__gc')));
lua_pushlightuserdata(FL, self); // put offset to self into lightuserdata
lua_pushcclosure(FL, @StaticGc_T, 1);
lua_settable(FL, -3);
lua_setmetatable(FL, -2); // userdata.metatable = classname_metatable
lua_settable(FL, obj_index); // self[0] = obj;
f := @StaticThunk;
// register the functions
for i := 0 to length(ClassApiArray) - 1 do begin
lua_pushstring(FL, PAnsiChar(UTF8Encode(ClassApiArray[i].name)));
lua_pushlightuserdata(FL, self); // put offset to self into lightuserdata
lua_pushnumber(FL, i); // let the thunk know which method we mean
lua_pushcclosure(FL, f, 2);
lua_settable(FL, obj_index); // self["function"] = thunk("function")
end;
lua_pushvalue(FL, -1); // dup object on stack top
rec.ref := luaL_ref(FL, LUA_REGISTRYINDEX); // store object as ref
...
result := 1;
通过堆栈返回 Lua 对象,所以现在 p fromp = TPanel("somename")
是对象实例。
但是,如果我尝试实现 xml 模板和步骤 3
p = TPanel("somename", "xmltemplatenodename")
并且在执行步骤 5 中,OnCreate
如果我看到有inherits = xmltemplatenodename
. 因此,在第 5 步之前inject
,应用程序搜索精确- 如果发现为每个对象xmltemplatenodename
创建更多对象。inject
并且只有在此之后继续使用 own 执行第 5 步inject
。在从xmltemplatenodename
. 但是,如果应用程序使用与源相同的 xml 并xmltemplatenodename
在外部创建相同的对象OnCreate
- 没有错误。
Inject
对于 xml 对象略有不同,不是将对象留在堆栈中,而是通过对象名称注册它
lua_setglobal(FL, PAnsiChar(objName8));