c++ map unreadable in dll unless using an iterator - c++

I am creating a game in c++ using the SDL library.
To keep everything readable and orderly, I make a dll from the actual game program, the menu's program and have only the main program as an executable. In the main program I create a struct that holds all screen information, such as standard colors, the width and height of the screen, fonts and the renderer, window and surface object of the screen. In the main program I initialise one instance of this struct. A pointer to this instance is passed as a parameter to the functions and objects in the dll's.
The colors are defined in a std::map<char*, int>.
To access the colors, one could use something like this:
struct screen{
std::map<char*, Uint32> colors;
}
screen display;
std::pair<char*, Uint32> color;
color.first = "green";
color.second = 0x00FF00;
display.colors.insert(color);
int x = display.colors["green"] //for example
Reading the values in the main executable works fine, but having the screen object passed as a pointer to a function inside a dll, it returns a NULL. As a pointer, I read the value like this:
void function(screen* display){
Uint32 x = display->colors["green"];
}
When doing the following:
std::map<char*, int>::iterator i = display->colors.begin();
while(i->first != "green"){
i++
}
int x = i->second;
There seems to be no problem.
But I want to be able to use the first method in the dll's, since the second method is much less efficient.
Why doesn't the first method work in dll's? and how do I get it to work in the dll's? I use visual studio 2012.

The pointer issue I told you about is probably the reason for your problem. In the executable the string literal "green" has one address, and in the DLL the string-literal "green" has a totally different address. Yes the strings will be equal if you compare them, but the pointers themselves will not be the same, leading to your problem.
The answer is simply to use std::string as the key.

You should question yourself what "green" as a char* points to. Without using the DLL, being just one compilation unit gives "green" a single address which will be reused during the program. So, the pointer is the same when getting and retrieving from the map.
When you compile the DLL, the "green" pointer is a different pointer than the "green" pointer from the main executable, so you cannot retrieve it from the map.

Related

Get SDL2 Mouse Position

How would I get the position of the mouse in c++ SDL2? I found this wiki however I'm not really sure what it means and how would I get the x and y in int form?
https://wiki.libsdl.org/SDL_GetMouseState
Call the function described at the link you found; with pointers to the two int variables which you want to receive the coordinates.
Simplified, the function works like this one:
void SetXto5(int* x)
{*x = 5;}
i.e. the variable which your parameter points to will receive a value.
(This skips the check for NULL pointer, which is implied in the documentation.)
This does of course require the SDL environment to be correctly set up and initialised. I assume from your comments that you do not ask about that background part.

How to create std::map of Gdk::Pixbuf instances and use it in Gdk::Cairo

I guess one may found it trivial, but I ask it here since I could not find a straightforward answer.
Let's dive into the problem:
Having a resource of multiple images along with cairo context that is using these images incessantly. Naturally, I can do so as below:
Glib::RefPtr<Gdk::Pixbuf> image;
image = Gdk::Pixbuf::create_from_resource("/image/icon1"); //there are numerous icons out there
Then I can use it with Cairo context pointer like this:
bool MyClass::on_draw(const Cairo::RefPtr<Cairo::Context> &cr)
{
// ... some code
Gdk::Cairo::set_source_pixbuf(cr, image, x0 , y0); //x0 , y0 : somewhere in the context
cr->paint();
return true;
}
Images are not changing but it creates Pixbuf instance everytime. I want to use c++ map and put my icons in it. Then, I want to get the image pointer from the map. I did something like this:
std::map<Glib::ustring , GdkPixbuf*> map_Images;
// ..
map_images.insert(pair<Glib::ustring , GdkPixbuf* >("icon1" , image->gobj() )); // I do the same with all of my frequently referred icons
Now, I don't know how should I call this map to use with Cairo context. In other words, how should I make a Glib::RefPtr from the base object, say GdkPixbuf*
I would recommend you to make map_Images a map of type std::map<Glib::ustring , Glib::RefPtr<Gdk::Pixbuf> > and make it data member of MyClass. Because Glib::RefPtr will deallocate the owning object once all references are lost to that pointer.
What I want to say is that if you have code similar to this:
... some function, say fun1
{
Glib::RefPtr<Gdk::Pixbuf> image;
image = Gdk::Pixbuf::create_from_resource("/image/icon1");
map_images.insert(pair<Glib::ustring , GdkPixbuf* >("icon1" , image->gobj() ));
} // image object will die here. So, Gdk::Pixbuf held by Glib::RefPtr will be deallocated
Now, If you will try to access Gdk::Pixbuf * from the map, you will get dangling pointer.
If that is the case, skip the part that follows. Otherwise, continue reading.
Creating Glib::RefPtr of type Gdk::Pixbuf seems to be simple. As per source code that I found on GitHub: https://github.com/GNOME/glibmm/blob/master/glib/glibmm/refptr.h, make_refptr_for_instance(T_CppObject* object) API should do the job for you.
If you really want to create Glib::RefPtr of type Gdk::Pixbuf, you may get it by calling:
Glib::RefPtr<Gdk::Pixbuf> imageForIcon1 = make_refptr_for_instance<Gdk::Pixbuf>(map_images["icon1"]); // assumption: map_images already has an element with key "icon1"
Hope it helps.

QList, appending object, loosing static members

I'm using building a QList in my object:
QList<clsXMLnode*> mlstChildren;
In my method to append a child node:
void clsXMLnode::appendChild(clsXMLnode* pobjChild) {
assert(pobjChild != NULL);
mlstChildren.append(pobjChild);
// ...
When I use the debugger to single step I can see that pobjChild has all the static data that it should have associated with it, however the node that is appended to 'mlstChildren' has none of the static members. Using the debugger I can see the 'pobjChild' is still correct and 'mlstChildren' whilst it has the same pointer address for the child node, the contents of it do not match the contents of 'pobjChild', why?
Edit:
It seems to be a bug in the debugger, I modified my appendChild method as follows:
void clsXMLnode::appendChild(clsXMLnode* pobjChild) {
assert(pobjChild != NULL);
int intNewIdx = mlstChildren.length();
mlstChildren.append(pobjChild);
clsXMLnode* pobjCheck = mlstChildren.at(intNewIdx);
// ...
I can see in the debugger that the contents of pobjCheck matches the contents of pobjChild exactly and all static members are intact, but if I expand mlstChildren in the debugger, whilst the class address matches pobjChild, the contents of the static data does not.
This isn't really an answer, however I think I've proven that it is one of several ongoing bugs in the Qt Debugger, which I have reported to the Qt developers forum:
https://forum.qt.io/topic/82279/debugger-and-static-data

Lua userdata variable communication with C++

I have a program where users can create Frames using Lua command such as:
frm=Frame.new()
the above-mentioned command shows a frame to the user. Behind the scenes the C++ wrapper is as follows:
Frame* Frame_new(lua_State* L)
{
int nargs=lua_gettop(L);
Frame* wb=0;
if(nargs==0){
//Omitted
wb=mainfrm->GetFrame();
lua_pushlightuserdata(L,(void*)(wb));
int key=luaL_ref(L, LUA_REGISTRYINDEX);
wb->SetLuaRegistryKey(key);
}
return wb;
}
Since the frame is shown to the user, the user can close the frame by just clicking on the close button provided by the operating system. This generates a close event and it is handled as follows:
void Frm::OnClose(wxCloseEvent& evt)
{
//Omitted for brevity
int LuaRegistryKey=GetFrame()->GetLuaRegistryKey();
lua_rawgeti(glbLuaState,LUA_REGISTRYINDEX,LuaRegistryKey);//userdata
Frame* wb1=(Frame*)lua_touserdata(glbLuaState,-1); //userdata
lua_pop(glbLuaState,1); //
lua_getglobal(glbLuaState,"_G"); //table
lua_pushnil(glbLuaState); //table key
while (lua_next(glbLuaState,-2)) {//table key value
const char* name = lua_tostring(glbLuaState,-2);//table
if(lua_type(glbLuaState,-1)==LUA_TUSERDATA){
Frame* wb2=(Frame*)lua_touserdata(glbLuaState,-1);
if(wb2==m_Frame){ //this part doesnt work
lua_pushnumber(glbLuaState,0);
lua_setglobal(glbLuaState,name);
lua_pop(glbLuaState,1);
break;
}
}
lua_pop(glbLuaState,1); //table key
} //table
lua_pop(glbLuaState,1); //
if(m_Frame==wb1) {delete m_Frame; m_Frame=0; wb1=0;}
if(wb1) {delete wb1; wb1=0;}
luaL_unref(glbLuaState,LUA_REGISTRYINDEX,LuaRegistryKey );
}
Now the goal is when user closes the frame the variable created by frm=Frame.new() should be nil so that user can not call one of its methods, such as frm:size() which crashes the program.
In the above C++ code for handling the close event, wb1 and current frame has the same memory address. Now to my understanding all I need to do is search the global table for the userdata type Frame and compare the memory addresses so that I know I am choosing the right frame and then set it to nil.
However, Frame* wb2=(Frame*)lua_touserdata(glbLuaState,-1); returns a completely different address from wb1, therefore I cannot know which variable of type frame I am referring to.
To my understanding wb2 has a different memory address possibly due to 3 scenarios:
1) frm is a full userdata
2) frm is inside global lua table, therefore has a different address (although this doesnt make sense to me as I pushed the address of Frame in C++).
3) I am thinking completely in the wrong way or cant see something simple.
Now to my understanding all I need to do is search the global table for the userdata type Frame and compare the memory addresses so that I know I am choosing the right frame and then set it to nil.
Your understanding is wrong.
First, you did not return userdata to Lua. You returned light userdata. That's different. The lua_type of light userdata is LUA_TLIGHTUSERDATA.
Second, even if you fixed that problem, you're not iterating through tables inside the global table. So something as simple as this would confound you:
global_var = {}
global_var.frame = Frame.new()
Lua code should be able to store its data wherever it wants. And if it wants to store some userdata in a table, who are you to say no?
Third, even if you iterated through every table accessible globally recursively (with protection from infinite loops), that wouldn't stop this:
local frm = Frame.new()
function GlobalFunc(...)
frm:Stuff();
end
Because Lua has proper lexical scoping, GlobalFunc will store a reference to the frm local internally. And since frm is a local variable, you cannot get at it just from iterating through globals.
Generally speaking, if you give a value to Lua, it now owns that value. It can do whatever it wants, and it's generally considered rude to break this contract.
Though it's not impossible. The way to handle it is by using an actual userdata rather than light userdata. Each regular userdata is an object, a full allocation of memory. Inside that allocation you would store the Frame pointer. When it comes time for that Frame to be destroyed, all you have to do is set the Frame pointer inside the userdata to NULL.
Conceptually, it's like this in C++:
struct FramePtr
{
Frame *ptr;
};
Lua would be passing around a single allocation of FramePtr. So if you set that allocation's FramePtr to NULL, everyone sees it. No iterating through global tables or somesuch.
Of course, accessing the Frame from a FramePtr requires an extra indirection. However, by using full userdata instead of light userdata, you can also attach a proper metatable to it (light userdata doesn't get per-object metatables; every light userdata shares the same metatable).

luabind not making changes to pointer mingw

I have fixed the linker errors I had in this question, but now I am having another problem. I create my objects by calling createObject() in lua and that creates a boost::shared_ptr to a new object, adds it to a list, and returns it.
On windows with mingw when I make changes in lua the changes do not get applied to the C++ object. it cannot be a problem with my code because I built the same thing on Linux and it worked fine.
ObjectPtr createObject(PlayerPtr player){
ObjectPtr obj(new Object(player));
window->world.objects.push_back(obj);
return obj;
}
bool setup(lua_State* luastate, Window* caller){
open(luastate);
// initialize some other classes here.
class_<Player, PlayerPtr> Player("Player");
Player.def_readwrite("playerColor", &Player::playerColor);
Player.def_readwrite("displayName", &Player::displayName);
class_<Object, ObjectPtr> Object("WorldObject");
Object.def_readwrite("health", &Object::health);
Object.def_readwrite("maxHealth", &Object::maxHealth);
Object.def_readwrite("mesh", &Object::mesh);
Object.def_readwrite("location", &Object::location);
Object.property("player", &Object::getPlayer, &Object::setPlayer);
Object.def("setOnDeath", &Object::setOnDeath);
module(luastate)[
vec3,
color,
Player,
WorldObject,
def("isWindowOpen", &isWindowOpen),
def("loadMesh", &MeshManager::LoadMesh),
def("createObject", &createObject),
def("createPlayer", &createPlayer),
];
window = caller;
}
ObjectPtr and PlayerPtr are boost::shared_ptr of Object and Player, window is a static Window pointer, and createPlayer() is the same as createObject() without any arguments and using Player instead of Object.
in lua:
red = createPlayer()
red.playerColor = Color(255,0,0)
red.displayName = "Red"
obj = createObject(red)
obj.location = vec3(10,10,0)
print(obj.player.displayName)
results in "Red" being put in the console.
but in C++ the value is just "".
I debugged it and the objects do get created and added to the list in C++, but no changes were ever made, as all variables are in there default state.
I think it is a problem with luabind and mingw, or just something wrong with the build,
the only things I changed from the default build setup were 2 things I needed to do to get it to compile at all: I set LUA_PATH in the jamfile to point to the directory lua is in (rather than getting it from an environmental variable) and I changed
#elif BOOST_PP_ITERATION_FLAGS() == 1
to
#else
#if BOOST_PP_ITERATION_FLAGS() == 1
because mingw did not like the ( for some reason... (and yes I did add the #endif in the right place)
UPDATE: I have tried using msvc10 also, and it still has the same problem. I have also tried building it against the same version of boost that is on my Linux. but to no avail.