./lua/addtest.lua:9: попытка проиндексировать локальный 'testobj' (значение пользовательских данных)]]

test.exe вызывает addTest.lua и устанавливает lua_testobj в таблицу, а addTest.lua вызывает testobj.dll, но testobj.dll не может получить «lua_testobj»

сообщение об ошибке

addTest.lua:9 попытка проиндексировать локальный 'testobj' (значение пользовательских данных)

  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. код addtest.lua следующий

    local luapath = package.path
    local cpath = package.cpath
    
    print(luapath)
    print(cpath)
    
    local testobj= require "testobj"
    
    testobj.addTest()
    
  3. и исходный код testobj.dll следующий

    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;
    }
    

person Sleepwom    schedule 17.12.2014    source источник
comment
При первом взгляде на код не похоже, что вы установили какую-либо метатаблицу для lua_testobj.   -  person greatwolf    schedule 17.12.2014


Ответы (2)


Похоже, что testobj.dll действительно успешно вернул ваш lua_testobj, потому что вы получаете ошибку:

addTest.lua:9 попытка проиндексировать локальный 'testobj' (значение пользовательских данных)

указывает, что lua видит testobj как userdata. Проблема не в этом; реальная проблема заключается в том, что вы не связали метатаблицу с этими пользовательскими данными, поэтому lua ничего не может с ней сделать, когда скрипт пытается ее использовать.

Я изменил ваш luaopen_testobj, чтобы создать и зарегистрировать метатаблицу для вашего 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;
}

Это должно позволить вам получить доступ к laddTest с помощью testobj:addTest() из lua. laddtest должен проверить, что testobj действительно является данными пользователя, которые вы передали, например:

static int laddTest(lua_State *L)
{
    auto pTestObj = reinterpret_cast<CTestObj *> (luaL_checkudata(L, 1, "lua_testobj"));
    // do something ...
    return 1;
}
person greatwolf    schedule 17.12.2014
comment
но я хочу передать g_TestObj из exe в dll - person Sleepwom; 17.12.2014
comment
В этом случае вам придется переместить метатабличный регистрационный код на main пользователя test.exe. Просто убедитесь, что метатаблица добавлена ​​в реестр один раз. - person greatwolf; 17.12.2014
comment
Вы также можете сделать так, чтобы luaopen_testobj просто возвращал новый luatable, содержащий функции из luaL_Reg l[], что упростило бы некоторые вещи, поскольку скрипт не будет напрямую работать с lightudata. Но неясно, какова ваша конечная цель, поэтому я не могу рекомендовать одно другому. - person greatwolf; 17.12.2014

Я изменил функцию luaopen_testobj, добавил lua_pop(L, 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) );

  lua_pop(L, 1);

  return 1;
}

Теперь он может правильно получить значение pTestObj, больше не появляется ошибка «addTest.lua:9 пытается проиндексировать локальный 'testobj' (значение пользовательских данных)».

Но я не понимаю, что означает сообщение об ошибке

person Sleepwom    schedule 18.12.2014
comment
Как я уже объяснил в своем ответе, пользовательские данные не индексируются без метатаблицы, потому что это данные C/C++. - person greatwolf; 18.12.2014