./lua/addtest.lua:9: attempt to index local 'testobj' (a userdata value)]]
Asked Answered
A

2

2

test.exe call addTest.lua and set the lua_testobj to the table, and addTest.lua call testobj.dll, but testobj.dll can not get the "lua_testobj"

error msg is

addTest.lua:9 attempt to index local 'testobj' (a userdata value)

  1. test.exe

    L = luaL_newstate();
    // link lua lib
    luaL_openlibs(L);
    //
    addLuaCPath( L, "./clib/?.dll" );
    //
    lua_pushlightuserdata(L, (void*)g_TestObj.get()); // g_TestObj is a global vars
    lua_setfield(L, LUA_REGISTRYINDEX, "lua_testobj");
    // 
    int err = 0;
    err = luaL_loadfile( L, "./lua/addTest.lua" );
    if( err != LUA_OK )
      printf("Failed to load addTest.lua![%s]", lua_tostring(L,-1));
    
    err =  lua_pcall( L, 0, 1, 0 );
    if( err != LUA_OK )
      printf("Failed to call addTest.lua![%s]", lua_tostring(L,-1));
    
  2. the addtest.lua code is following

    local luapath = package.path
    local cpath = package.cpath
    
    print(luapath)
    print(cpath)
    
    local testobj= require "testobj"
    
    testobj.addTest()
    
  3. and the testobj.dll source code is following

    static int laddTest(lua_State *L)
    {
      lua_getfield(L, LUA_REGISTRYINDEX, "lua_testobj");
      return 1;
    }
    
    extern "C" int __declspec(dllexport) 
    luaopen_testobj(lua_State *L)
    {
      luaL_Reg l[] = {
        { "addTest", laddTest },
        { NULL, NULL },
      };
    
      luaL_checkversion(L);
      luaL_newlib(L,l);
    
      lua_getfield(L, LUA_REGISTRYINDEX, "lua_testobj");
      CTestObj* pTestObj = static_cast<CTestObj*>( lua_touserdata(L,-1) );
    
      return 1;
    }
    
Automat answered 17/12, 2014 at 2:38 Comment(1)
Initial glance over the code, it doesn't look like you've set any metatable for lua_testobj.Ingeborgingelbert
I
1

It looks like testobj.dll did actually return your lua_testobj successfully because the error you're getting:

addTest.lua:9 attempt to index local 'testobj' (a userdata value)

indicates lua sees testobj as a userdata. That's not where the problem is; the real issue is that you didn't associate any metatable with that userdata so lua can't really do anything with it when a script tries to use it.

I've modified your luaopen_testobj to create and register a metatable for your testobj:

extern "C" int __declspec(dllexport) 
luaopen_testobj(lua_State *L) 
{
  luaL_Reg l[] = 
  {
      { "addTest", laddTest },
      { NULL, NULL },
  };

  luaL_checkversion(L);
  lua_pushlightuserdata(L, (void*)g_TestObj.get());

  // g_TestObj, testobj_mt, {l}
  luaL_newmetatable(L, "lua_testobj");
  luaL_newlib(L, l);
  // testobj_mt.__index = {l}
  lua_setfield(L, -2, "__index");

  // return setmetatable(g_TestObj, testobj_mt)
  lua_setmetatable(L, -2);
  return 1;
}

This should allow you to access laddTest using testobj:addTest() from lua. laddtest should check that testobj is indeed the userdata you passed in, for example:

static int laddTest(lua_State *L)
{
    auto pTestObj = reinterpret_cast<CTestObj *> (luaL_checkudata(L, 1, "lua_testobj"));
    // do something ...
    return 1;
}
Ingeborgingelbert answered 17/12, 2014 at 3:25 Comment(3)
but I want to pass the g_TestObj from exe to dllAutomat
In that case, you'll have to move the metatable registration code over to test.exe's main. Just make sure the metatable is added to the registry once.Ingeborgingelbert
You can also have luaopen_testobj just return a new luatable containing the functions in luaL_Reg l[] which would simplify some things since the script won't deal with the lightudata directly. But it's unclear what your end goal is so I can't recommend one over the other.Ingeborgingelbert
A
0

I've modified the luaopen_testobj function, add lua_pop(L, 1); before return

extern "C" int __declspec(dllexport) 
luaopen_testobj(lua_State *L)
{
  luaL_Reg l[] = {
    { "addTest", laddTest },
    { NULL, NULL },
  };

  luaL_checkversion(L);
  luaL_newlib(L,l);

  lua_getfield(L, LUA_REGISTRYINDEX, "lua_testobj");
  CTestObj* pTestObj = static_cast<CTestObj*>( lua_touserdata(L,-1) );

  lua_pop(L, 1);

  return 1;
}

Now, it can correctly to obtain the value of pTestObj, no longer appear "addTest.lua:9 attempt to index local 'testobj' (a userdata value)" wrong.

But I don't know what's the meaning of the error message

Automat answered 18/12, 2014 at 2:35 Comment(1)
As I already explained in my answer, userdata isn't indexable without a metatable because it's C/C++ data.Ingeborgingelbert

© 2022 - 2024 — McMap. All rights reserved.