如何从Delphi中正确注册LuaUserData?

如何从Delphi中正确注册LuaUserData?,delphi,lua,lua-userdata,Delphi,Lua,Lua Userdata,我仍然对向Lua注册Delphi用户数据感到困惑。为了教我这个原理,我尝试实现日期(时间)类型 开始时,此类型应具有三个可供Lua访问的功能: 用于创建此类型变量的new函数 一个getdate函数 以及setdate功能 最后,这个小Lua脚本应该可以工作: DT = DateTime.new() DT:setdate(1, 1, 2011) day, month, year = DT:getdate() print("Day: " .. day .. " Month: " .. month

我仍然对向Lua注册Delphi用户数据感到困惑。为了教我这个原理,我尝试实现日期(时间)类型

开始时,此类型应具有三个可供Lua访问的功能:

  • 用于创建此类型变量的
    new
    函数
  • 一个
    getdate
    函数
  • 以及
    setdate
    功能
  • 最后,这个小Lua脚本应该可以工作:

    DT = DateTime.new()
    DT:setdate(1, 1, 2011)
    day, month, year = DT:getdate()
    print("Day: " .. day .. " Month: " .. month .." Year: " .. year)
    
    我试图自己实现它(使用这本书),但我收到一个错误,上面说:
    \u尝试在第2行上索引全局“DT”(用户数据值)
    。我可能对userdata注册做了一些错误,但是我很难找到错误

    我希望你能帮我找到它,这是我已经得到的:

    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, month, year : lua_Integer;
      Begin
        Result := 0;
        DT := luaL_checkudata(aState, 1, MetaPosDateTime);
        luaL_argcheck(aState, DT <> Nil, 1, 'DataTime expected');
        ParamType := lua_type(aState, 2); 
        If (ParamType = LUA_TTABLE) Then 
          Begin
            { GetData from Table }
          End
        Else
          Begin // param order must be: day, month, year
            day := luaL_checkinteger(aState, 2);
            month := luaL_checkinteger(aState, 3);
            year := luaL_checkinteger(aState, 4);
          End;
        DT^:= EncodeDate(year, month, day);
      End;
    
      Function getdate(aState : pLua_State) : longint; cdecl;
      Var
        DT : pLuaDateTime;
        Day, Month, Year : Word;
      Begin
        DT := luaL_checkudata(aState, 1, MetaPosDateTime);
        luaL_argcheck(aState, DT <> Nil, 1, 'DataTime expected');
        DecodeDate(DT^, Year, Month, Day);
        lua_pushinteger(aState, 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;
    

    不幸的是,RegisterDateTime的两个版本的效果(errormessage;))是相同的。在脚本启动之前,它们在我的Delphi程序中被直接调用(我通过在“RegisterDateTime”和“newdatetime”中设置断点来确保这一点)。这两个函数都是按此顺序调用的。因此我的错误一定是在这两个函数中的一个。我几乎可以肯定这是一件简单的事情,但我看不见它(

    今天我按下了这个项目的大重置按钮,完全重新启动了我的LuaDateTime类型的实现,今天我纠正了它。现在我想发布我的解决方案,作为其他任何有同样问题的人的示例

    昨天我最大的错误是忘记设置元表的
    \uu index
    字段

    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, 1, 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, month, 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, month, day);
    
      Result := 0;
    End;
    
    Function getLuaDateTime(L : pLua_State) : LongInt; cdecl;
    Var
      a : pLuaDateTime;
      day, month, year : Word;
    Begin
      a := checkLuaDateTime(L);
      DecodeDate(a^, year, month, 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, -2, '__index');
      luaL_register(L, Nil, LuaDateTimeLib_m[0]);
    
      luaL_register(L,PosLuaDateTime, LuaDateTimeLib_f[0]);
      Result := 1;
    End;
    
     dt = datetime.new()
     day, month, year = dt:get()
     print ("Day: " .. day .. " Month: " .. month .. " Year: " .. year)
     dt:set(1, 2, 1903)
     day, month, year = dt:get()
     print ("Day: " .. day .. " Month: " .. month .. " Year: " .. year)
    
    我希望这对其他人有帮助

     dt = datetime.new()
     day, month, year = dt:get()
     print ("Day: " .. day .. " Month: " .. month .. " Year: " .. year)
     dt:set(1, 2, 1903)
     day, month, year = dt:get()
     print ("Day: " .. day .. " Month: " .. month .. " Year: " .. year)