GMS 2.3+ Extension function not properly reading string return value from .dll

Hi all. I'm having some trouble with a pathfinding extension I'm trying to write. The first real function of the extension that I'm trying to test out is the function to make the grid object for pathfinding, and I figured that I could cast a pointer to the object into a string and pass that back to GameMaker in the function. The I wrote is as follows:

Code:
fn_export const char* make_grid(double w, double h) {
    //create the grid
    Grid* new_grid = new Grid(int(w), int(h));
    //cast the address of the grid to a string to return to gamemaker
    const void* address = static_cast<const void*>(new_grid);
    stringstream ss;
    ss << address;
    const string s = ss.str();
    return s.c_str();
}
(note: fn_export is a macro for __declspec(dllexport))

So the weird part is that as far as I can tell there's no reason it shouldn't work. However, any attempt to get data out of the function results in GameMaker storing an empty string (""). The return type is fine, as returning a string literal such as "Test" is passed successfully into GMS. Likewise, if I plug the code I have into an actual console application instead of a .dll and print the return value I'll get a string holding the memory address of the grid object as expected (so, something like "0x0C240e08"). It just seems like something gets lost in translation between actually creating the c_str object and passing back into GMS. Does anyone have any insight into why this might be happening or what I'm doing wrong? Thanks!
 
Last edited:

Samuel Venable

Time Killer
For one thing, I think GameMaker needs char * and not const char *. It's weird and doesn't make much sense to me as to why that makes a difference for this context, but that's what everyone seems to do when they make extensions. You can just c-style cast the s.c_str().

also:

const string s = ss.str();

The life of the string will partially end by the time you hit that return. Make the string a global declaration or make it static for example:

static string s;
s = ss.str();
return (char *)s.c_str();

but don't do:

static string s = ss.str();
return (char *)s.c_str();

if you do that you'll get the same value every time for the life of your program
 
For one thing, I think GameMaker needs char * and not const char *. It's weird and doesn't make much sense to me as to why that makes a difference for this context, but that's what everyone seems to do when they make extensions. You can just c-style cast the s.c_str().

also:

const string s = ss.str();

The life of the string will partially end by the time you hit that return. Make the string a global declaration or make it static for example:

static string s;
s = ss.str();
return (char *)s.c_str();

but don't do:

static string s = ss.str();
return (char *)s.c_str();

if you do that you'll get the same value every time for the life of your program
The static change fixed it! Thank you. c_str() returns a const char* though, so it's easier to be that return type and GMS seems fine with it as it's reading it correctly now. Just out of curiosity, why is it that the lifetime of the string runs out when just using a basic/const string object? I would think that the lifetime would last through the last time the compiler sees it get called, which would be the very next statement and long enough for the value to be returned. Does it have something to do with c_str() generating a pointer to the character array within the string object that times out after the function is returned? After some more reading it sounds like that's what the functionality is as it "may no longer be accurate if the string is modified by any other member function".
 

Samuel Venable

Time Killer
The static change fixed it! Thank you. c_str() returns a const char* though, so it's easier to be that return type and GMS seems fine with it as it's reading it correctly now. Just out of curiosity, why is it that the lifetime of the string runs out when just using a basic/const string object? I would think that the lifetime would last through the last time the compiler sees it get called, which would be the very next statement and long enough for the value to be returned. Does it have something to do with c_str() generating a pointer to the character array within the string object that times out after the function is returned? After some more reading it sounds like that's what the functionality is as it "may no longer be accurate if the string is modified by any other member function".
C strings work that way. C++ string do not. C strings have to be allocated manually or stored in a buffer. C++ strings get allocated for you, so that probably is why it works that way, but I'm just guessing the two are correlated. In regards to why the string lifetime doesn't last long enough.
 
Top