calling a c++ function from lua passes less arguments - c++

So the function is like :
send_success(lua_State *L){
MailService *mls = static_cast<MailService *>(lua_touserdata(L, lua_upvalueindex(1)));
Device *dev = static_cast<Device *>(lua_touserdata(L, lua_upvalueindex(2)));
int numArgs = lua_gettop(L);
TRACE << "Number of arguments passed is = " << numArgs;
/* here I do some operation to get the arguments.
I am expecting total of 5 arguments on the stack.
3 arguments are passed from function call in lua
and 2 arguments are pushed as closure
*/
string one_param = lua_tostring(L, 3, NULL)
string two_param = lua_tostring(L, 4, NULL)
string other_param = lua_tostring(L, 5, NULL)
}
Now pushing this function on lua stack, I have done following
lua_pushstring(theLua, "sendSuccess");
lua_pushlightuserdata(theLua, (void*) mls);
lua_pushlightuserdata(theLua, (void*) this);
lua_pushcclosure(theLua, lua_send_success,2);
lua_rawset(theLua, lua_device); // this gets me device obj in lua
calling it from lua , i would do
obj:sendSuccess("one param","second param","third param")
But when i check for the number of arguments. It should give 5 arguments. Instead only 4 arguments are passed.
I did some testing whether the two objects i pass a light used data are passed correctly. They are passed correctly.
Only thing missing here is, that one parameter is missing which is passed from lua side.
Also i tried pushing only one object and it worked correctly. so I am not sure if I am messing up with argument numbering somewhere
Please tell your opinions

The user-data objects you create as part of the closure are not passed as arguments to the function, they placed in another location in the state.
That means the offsets you use to get the arguments with lua_tostring are wrong.

OK. SO the thing is
lua_pushclosure keeps the userdata in a separate space on lua_stack. Inside that stack, the offset 1 and 2 represent first and 2nd object
lua_pushlightuserdata(theLua, (void*) mls);
lua_pushlightuserdata(theLua, (void*) this);
lua_pushcclosure(theLua, lua_send_success,2);
But after that i was going to the third 3rd, assuming I had already accessed 2nd location. But that is wrong. The right thing to do is to consider that pushclousure takes only one space on stack irrespective of how many times the lightuserdata is pushed and remaining params can be accessed by starting from the 2nd offset.. so the below code works for me:
string one_param = lua_tostring(L, 2, NULL)
string two_param = lua_tostring(L, 3, NULL)
string other_param = lua_tostring(L, 4, NULL)

Related

How to pass a table parameter from lua to C++ through a lightuserdata object?

I have registered a function that creates a lightuserdata to be used by C++ and lua. that part is working fine when I tested using simple variables, ints and strings. I can create my lightuserdata in lua without errors when it's strings and ints. however when I try to use tables it gets more complicated
std::string aString = lua_tostring(lua,-4);
first parameter being correct as it is supposed to be a string
if (lua_type(lua,-3 == LUA_TTABLE)) //is true so i know it recognizes it as a table
{
auto t = lua_gettable(lua, -3);
size_t tableLen = lua_rawlen(lua, -3); // also gives me the correct size
lua_settop(lua, 1); //this discards the rest right? which i don't want.
//luaL_checktype(lua, 1, LUA_TTABLE); //using this crashes the application expecting
// table but getting string
lua_getfield(lua, 1, "a");
lua_getfield(lua, 1, "b");
lua_getfield(lua, 1, "c");
lua_getfield(lua, 1, "d");
lua_getfield(lua, 1, "e");
std::cout << lua_gettop(lua) << std::endl; //after using the getfields i get the new table size
//correctly (i assume, it turns 1 more value than expected, i think it's the table itself.
//int a = luaL_checkinteger(lua, -5); //these don't work as they expect numbers but get nil
//int b = luaL_checkinteger(lua, -4);
//int c = luaL_checkinteger(lua, -3);
//int d = luaL_checkinteger(lua, -2);
//int e = luaL_checkinteger(lua, -1);
std::cout << lua_tointeger(lua, -2) << std::endl; //returns always 0
}
Trying to ignore the table and get the rest of the stack gives me an violation error on 0x000000, though the 3rd value debugs correctly as what is supposed to be and the 4th is empty, even though it passes correctly if i don't use table.
is What I'm trying to do possible proceeding like this?
any comment to the right direction would be appreciated.
also, what should I use if I don't know the name of the key in the table?
if (lua_type(lua,-3 == LUA_TTABLE)) //is true so i know it recognizes it as a table
Big error here, or you didn't post the actual code.
You're not checking the type of the value under index -3, you're asking the type of the value under index false, since -3 == LUA_TTABLE is clearly false.
Whatever crash that happens after that "check" - is a result of this error. It will recognize as a table anything that is not nil.

Table as parameter in C function called from Lua

I'm dealing with Lua for a longer time but there is one point I can't achieve.
In a C function which is called from Lua I'm able to read a global Lua table using the table name like this:
C:
// get table
lua_getglobal(L, "tableName");
if (!lua_istable(L, -1))
break;
// count entries in table
ULONG numEntries = 0;
lua_pushnil(L);
while(lua_next(L,-2))
{
numEntries++;
lua_pop(L, 1);
}
but if I have a lua function which calls a C function like this:
Lua:
luaTable = { }
luaTable.Param1 = Value1
luaCallC("This is a Text", luaTable)
How do I access the table argument?
C:
// get table
// ???
// count entries in table
ULONG numEntries = 0;
lua_pushnil(L);
while(lua_next(L,-2))
{
numEntries++;
lua_pop(L, 1);
}
Arguments to a CFunction are pressed onto the virtual stack in the order that they are provided, and it is simply up to you to do the error checking required before you operate on these values.
Lua 5.3 Manual ยง4.8 - lua_CFunction:
In order to communicate properly with Lua, a C function must use the following protocol, which defines the way parameters and results are passed: a C function receives its arguments from Lua in its stack in direct order (the first argument is pushed first).
[ ... ]
The first argument (if any) is at index 1 and its last argument is at index lua_gettop(L). To return values to Lua, a C function just pushes them onto the stack, in direct order (the first result is pushed first), and returns the number of results
An example of exhaustively checking the number of elements in a table, with an arbitrary first argument.
int count (lua_State *L) {
luaL_checktype(L, 2, LUA_TTABLE);
puts(lua_tostring(L, 1));
size_t ec = 0;
lua_pushnil(L);
while (lua_next(L, 2)) {
lua_pop(L, 1);
ec++;
}
lua_pushinteger(L, (lua_Integer) ec);
return 1;
}
After registering the function for use in Lua:
count('foo', { 'a', 'b', 'c' }) -- 3

Simple lua example of passing a table to c/c++

I am struggling finding and understanding how to pass a table from lua to c++
What I have:
Lua File:
-- lua script for sending table data
io.write("lua table to send")
tableexample = {x = 1, y = 2, z = 100}
return tableexample
c/c++ side
L = lua_open();
luaL_openfile(L, "luafile");
... call the function...
luaLdofile(L, luafile);
int result;
result = lua_pcall(L,0, LUA_MULTRET,0);
if(result){
fprintf(stderr, "failed %s\n", lua_tostring(L,-1));
if(lua_istable(L,-1)){
lua_gettable(L,-1);
x = lua_tonumber(L,-2);
y = lua_tonumber(L,-3);
z = lua_tonumber(L,-4);
}
else
printf("fail");
the result comes back with a failure "attempt to call a table value"
I've looked at many different tutorials/examples but haven't found a simple tutorial that doesn't have 100 other things going on and am getting myself confused
some references that are similar - but too complex for what I am looking for
Iterating through a Lua table from C++?
Your use of lua_gettable is wrong.
Have a look at the Lua manual:
void lua_gettable (lua_State *L, int index);
Pushes onto the stack the value t[k], where t is the value at the
given index and k is the value at the top of the stack.
This function pops the key from the stack (putting the resulting value
in its place).
In your example, the value at the top of the stack is the table itself, so you are doing the equivalent of a tableexample[tableexample] lookup.
The shortest way to achieve what you want is to use lua_getfield instead, which allows accessing table elements by string keys:
lua_getfield(L, -1, "x");
Alternatively, push a Lua value of type string on the stack first and use lua_gettable for the lookup.
lua_pushliteral(L, "x");
lua_gettable(L, -2);
Don't forget to keep your stack balanced. Every value that you push on the stack needs to be popped properly. The Lua manual specifies how each API call changes the stack by the numbers in the \[ \] brackets on the right side of each function name.

DsGetDomainControllerInfo returns a "Pointer to a pointer variable that receives an array"? I don't get it

Most of my experience is with C#...so I'm still getting used to C++.
I'm trying to call DsGetDomainControllerInfo to get all of the domain controllers in the domain. Here's a link to the MSDN docs for that call:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms675987(v=vs.85).aspx
The fourth parameter returns the number of DC's that should be in the array of DS_DOMAIN_CONTROLLER_INFO_* structures.
I'm getting the first DS_DOMAIN_CONTROLLER_INFO_* in the array, but it throws an unhandled exception on the second. The last argument is a void**...I'm casting to that, but I doubt that's the right thing to do.
Here's my code:
PDOMAIN_CONTROLLER_INFO logonDomainController;
DsGetDcName(NULL, NULL, NULL, NULL, 0, &logonDomainController);
wstring domCon = logonDomainController->DomainControllerName;
wstring domNam = logonDomainController->DomainName;
HANDLE domHan;
DsBindWithCred(domCon.c_str(), domNam.c_str(), NULL, &domHan);
DWORD count = 0;
DS_DOMAIN_CONTROLLER_INFO_3 *dci[100] = { NULL };
DsGetDomainControllerInfo(domHan, domNam.c_str(), 3, &count, (void**)dci);
for (size_t i = 0; i < count; i++)
{
wcout << dci[i]->DnsHostName << endl;
}
I read the documentation as: you have to declare DS_DOMAIN_CONTROLLER_INFO_3 *dci; and pass its address as (VOID**) &dci (in the sense of a result/"out" parameter), so dci can be assigned the base address of the ..INFO_3 array by the callee. You can still access the elements of the array with dci[i].
I think it becomes clearer when reading the linked documentation for the DsFreeDomainControllerInfo function (which takes the same pointer as "in" parameter).

Accessing a Lua table within a table from C++

I have a Lua function that returns a dictionary table, and one of the values that's put into the returned table is another table as demonstrated in the following Lua function.
function tableWithinTable()
local ret = {}
ret["a"] = 1
ret["b"] = {1,2,3}
ret["c"] = 3
return ret
end
How would I go about accessing that inner table?
I know I can get to the table, because I can enter the following if statement. My current attempt at reading the table is included as well.
lua_pushstring("b");
lua_gettable(lua,1);
if(lua_istable(lua,-1))
{
//whatever is in here is executed.
lua_pushnumber(lua,1);
lua_gettable(lua,-1); //crashes to desktop here
std::cout << lua_tonumber(lua,-1) << std::endl;
lua_pop(lua,1);
}
I'm pretty sure there's an easy solution to this, but I'm totally stumped. Any help would be much appreciated.
After you push the index, the table is one more slot away in the stack. So something like this should work:
if(lua_istable(lua,-1)) {
lua_pushnumber(lua,1);
lua_gettable(lua,-2);
...
It is generally easier to use functions lua_getfield (for string indexes) or lua_rawgeti (for numerical indexes) than the raw lua_gettable function.
In particular, that avoids the extra value on the stack that causes your indexing error.
The example could be rewritten as :
lua_getfield(lua, 1, "b");
if(lua_istable(lua, -1))
{
lua_rawgeti(lua, -1, 1);
std::cout << lua_tonumber(lua,-1) << std::endl;
lua_pop(lua, 1);
}