• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

SOLVED [FFI] Calling GML function from DLL

Hi, I am trying to create a library on Windows and the thing I need is to pass the function pointer as argument and then call it from my DLL.
I've managed to build the working DLL with some test functions, but I can't figure out how to pass that pointer.
The thing I tried was call(ptr(my_func));, but the addresses didn't match. GML showed different value than DLL.
I've also tried something like call(my_func); and it just straight out crashed.


Is it even possible, or am I just stupid?
I used Extensions to "define" my DLL, and in the extern call function I've experimented with different argument types, like a pointer to an extern function, or just straight out lambdas.

Edit:
When passing to the DLL's function ptr(my_func) it returns 0, but passing just function name like my_func returns a valid (address?)
 
Last edited:
S

Sam (Deleted User)

Guest
It seems like it would be possible, but I'm not sure if it is the way you are attempting it. I would recommend looking up the libffi library it is cross-platform and handles this kind of thing, while simplifying it greatly.


Perhaps if you shared you C++ code I could help further.
 
Well, I am using Rust and that's the closest I've got, but I am getting stack overflow from transmutate. I guess that's because the pointer is invalid.
C#:
#[no_mangle]
#[allow(unused_variables)]
pub extern "C" fn call(ptr: *const ()) { unsafe {
    let func: extern "C" fn() = transmute(ptr);
    (func)();
} }
As I said, I tried a lot of things, but I guess passing raw pointers is not an option.
Maybe there is some "underhood magic" I am not aware of, because when I print the address in GML it's different from that one in DLL (solved)

And that's the function that I am trying to call:
GML:
function test() {
    show_message("It works!");  
}
But if you have any suggestions how could this be achieved in C++, please feel free to post them, I will also look into that libffi library.
 
Last edited:
And that's my second guess, by just trying to get the full address of the function.
C#:
#[no_mangle]
#[allow(unused_variables)]
pub extern "C" fn call(rva_address: f64) { unsafe {
    let base: HINSTANCE = GetModuleHandleA(PSTR::NULL);
    let address = base.0 + (rva_address as isize);

    println!("rva:   0x{:X}", rva_address as isize);
    println!("base:  0x{:X}", base.0);
    println!("addr:  0x{:X}", address);

    let ptr = address as *const ();

    let func: unsafe extern "C" fn() = transmute(ptr);
    (func)();
} }
GML:
function test() {
    show_message("It works!"); 
}

call(test);
I think it doesn't work because GML functions are some kind of abstraction and don't work like "typical functions". For example you can get attributes from multiple different objects inside it, without any reference in the arguments.
I guess it's impossible or just too hard for me.
If anyone have any suggestions, please share them here. I am kinda newbie in this field.
 

AceKiron

Member
My guess would be that using multiple function attributes is causing the issue, although I'm not sure as I don't have experience with Rust.
 

GMWolf

aka fel666
Afaik you cannot get aC like function pointer from a function. As you said they are not native functions and run on the GM runtime (be it VM or yyc).

The 'solution' is to return a code to let GM know to run a function, and then re enter your function.
You can do it using threads, or generators with a custom executor.

@YellowAfterlife should know more on the subject.
 
Afaik you cannot get aC like function pointer from a function. As you said they are not native functions and run on the GM runtime (be it VM or yyc).

The 'solution' is to return a code to let GM know to run a function, and then re enter your function.
You can do it using threads, or generators with a custom executor.

@YellowAfterlife should know more on the subject.
That makes sense, thanks. Guess I'll think about some "alternative"
 

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
Top