如何从Delphi中注册Lua userdata?
我仍然对将Delphi userdata注册到Lua感到困惑.教我学习实现日期(时间)类型的原则.
在开始时,这种类型应该具有Lua可访问的三个函数: >创建此类变量的新函数. 最后这个小Lua脚本应该工作: DT = DateTime.new() DT:setdate(1,1,2011) day,month,year = DT:getdate() print("Day: " .. day .. " Month: " .. month .." Year: " .. year) 我试图自己实现它(使用Programming in Lua书)但我收到一个错误说:_尝试在第2行索引全局’DT'(用户数据值)_我可能在用户数据注册时出错了但是我是无法找到错误. 我希望你能帮助我找到它,这是我已经得到的: Const MetaPosDateTime = 'DateTime'; Type tLuaDateTime = tDateTime; pLuaDateTime = ^tLuaDateTime; Function newdatetime(aState : pLua_State) : longint; cdecl; Var NewData : pLuaDateTime; Begin Result := 0; NewData := lua_newuserdata(aState,SizeOf(tLuaDateTime)); NewData^ := now; luaL_newmetatable(aState,MetaPosDateTime); lua_setmetatable(aState,-2); Result := 1; End; Function setdate(aState : pLua_State) : longint; cdecl; Var DT : pLuaDateTime; ParamType : integer; day,year : lua_Integer; Begin Result := 0; DT := luaL_checkudata(aState,MetaPosDateTime); luaL_argcheck(aState,DT <> Nil,'DataTime expected'); ParamType := lua_type(aState,2); If (ParamType = LUA_TTABLE) Then Begin { GetData from Table } End Else Begin // param order must be: day,year day := luaL_checkinteger(aState,2); month := luaL_checkinteger(aState,3); year := luaL_checkinteger(aState,4); End; DT^:= EncodeDate(year,day); End; Function getdate(aState : pLua_State) : longint; cdecl; Var DT : pLuaDateTime; Day,Month,Year : Word; Begin DT := luaL_checkudata(aState,'DataTime expected'); DecodeDate(DT^,Year,Day); lua_pushinteger(aState,Month); lua_pushinteger(aState,Year); End; Procedure RegisterDateTime(aState : pLua_State; aName: string); Var Funcs : packed Array[0..3] of luaL_reg; Begin Funcs[0].name := 'new'; Funcs[0].func := newdatetime; Funcs[1].name := 'setdate'; Funcs[1].func := setdate; Funcs[2].name := 'getdate'; Funcs[2].func := getdate; Funcs[3].name := Nil; Funcs[3].func := Nil; luaL_register(aState,PAnsiChar(aName),Funcs[0]); End; 因为我不确定luaL_register函数(它只能通过创建一个必须用require调用的库来工作吗?)我还试图用这个替换RegisterDateTime函数: Type tLuaFuncDef = Record FuncName : string; Func : Lua_CFunction; End; tLuaFuncList = Array of tLuaFuncDef; Procedure RegisterLuaObject(aState : pLua_State; aObjectName: string; aFuncList: tLuaFuncList); Var i : Integer; Begin If (aObjectName = '') Or (High(aFuncList) < 0) Then Exit; lua_newtable(aState); For i := Low(aFuncList) To High(aFuncList) Do If Assigned(aFuncList[i].Func) And Not (aFuncList[i].FuncName = '') Then Begin lua_pushcfunction(aState,aFuncList[i].Func); lua_setfield(aState,-2,pAnsiChar(aFuncList[i].FuncName)); End; lua_SetGlobal(aState,pAnsiChar(aObjectName)); End; Procedure RegisterDateTime(aState : pLua_State,aName: string); Var FuncList : tLuaFuncList; Begin SetLength(FuncList,3); FuncList[0].FuncName := 'new'; FuncList[0].Func := newdatetime; FuncList[1].FuncName := 'setdate'; FuncList[1].Func := setdate; FuncList[2].FuncName := 'getdate'; FuncList[2].Func := getdate; RegisterLuaObject(aState,aName,FuncList); End; 不幸的是,两个版本的RegisterDateTime的效果(errormessage;))是相同的.在脚本启动之前,我们在Delphi程序中直接调用它们(我通过在“RegisterDateTime”和“newdatetime”中设置断点来确保这一点.这两个函数都按此顺序调用.所以我的错误必须是这两个函数中的一个.I我几乎可以肯定这是一件简单的事情,但我会盲目地看到它.:( 解决方法
今天我推动了这个项目的大重置按钮,并完全重新启动了我的LuaDateTime-Type的实现,这一天我做对了.现在我想发布我的解决方案作为其他有相同问题的人的例子.
昨天我最大的错误就是忘记设置myatable的__index字段. Lua userdata的Delphi实现如下所示: implementation Uses LuaLib,LauXLib,SysUtils; Type tLuaDateTime = tDateTime; pLuaDateTime = ^tLuaDateTime; Const PosMetaTaleLuaDateTime = 'metatables.LuaDateTime'; PosLuaDateTime = 'datetime'; Function checkLuaDateTime(L : Plua_State) : pLuaDateTime; // raises error if first (self) parameter is not of type metatables.LuaDateTime Begin Result := luaL_checkudata(L,PosMetaTaleLuaDateTime); End; Function newLuaDateTime(L : pLua_State) : LongInt; cdecl; Var a : pLuaDateTime; Begin a := lua_newuserdata(L,SizeOf(tLuaDateTime)); // Get Mem of Usertype a^ := now; // Init Value lua_getfield(L,LUA_REGISTRYINDEX,PosMetaTaleLuaDateTime); lua_setmetatable(L,-2); Result := 1; End; Function setLuaDateTime(L : pLua_State) : LongInt; cdecl; Var a : pLuaDateTime; day,year : Integer; Begin a := checkLuaDateTime(L); // get params day,month and year day := luaL_checkint(L,2); month := luaL_checkint(L,3); year := luaL_checkint(L,4); // check Param Values luaL_argcheck(L,(day >= 1) and (day < 32),2,'day out of range'); luaL_argcheck(L,(month >= 1) and (month < 13),3,'month out of range'); a^ := EncodeDate(year,day); Result := 0; End; Function getLuaDateTime(L : pLua_State) : LongInt; cdecl; Var a : pLuaDateTime; day,year : Word; Begin a := checkLuaDateTime(L); DecodeDate(a^,year,day); // push 3 results of function lua_pushinteger(L,day); lua_pushinteger(L,month); lua_pushinteger(L,year); Result := 3; End; Function LuaDateTime2string(L : pLua_State) : LongInt; cdecl; Var a : pLuaDateTime; Begin a := checkLuaDateTime(L); lua_pushstring(L,pAnsiChar(FormatDateTime('c',a^))); Result := 1; End; Const LuaDateTimeLib_f : packed Array[0..1] of luaL_reg = // Normal functions (no self) ( (name: 'new'; func: newLuaDateTime),(name: Nil; func: Nil) ); LuaDateTimeLib_m : packed Array[0..3] of luaL_reg = // methods of class (need self) ( (name: '__tostring'; func: LuaDateTime2string),(name: 'set'; func: setLuaDateTime),(name: 'get'; func: getLuaDateTime),(name: Nil; func: Nil) ); Function luaopen_LuaDateTime(L : pLua_State) : LongInt; cdecl; Begin luaL_newmetatable(L,PosMetaTaleLuaDateTime); // Metatable.__index = Metatable lua_pushvalue(L,-1); lua_setfield(L,'__index'); luaL_register(L,Nil,LuaDateTimeLib_m[0]); luaL_register(L,PosLuaDateTime,LuaDateTimeLib_f[0]); Result := 1; End; 你必须从Delphi调用luaopen_LuaDateTime来注册Lua-State中的类型.完成后,您可以像这样运行Lua脚本: dt = datetime.new() day,year = dt:get() print ("Day: " .. day .. " Month: " .. month .. " Year: " .. year) dt:set(1,1903) day,year = dt:get() print ("Day: " .. day .. " Month: " .. month .. " Year: " .. year) 我希望这对其他人有帮助. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |