DLLs, callbacks, and the GC that loves them
BlitzMax Forums/BlitzMax Programming/DLLs, callbacks, and the GC that loves them
| ||
I have a question about how GC works in DLLs with callbacks. Let's say I have a BlitzMax-written DLL and a C/C++-written main program calling the DLL. I pass a C function to the DLL as a callback to use during a certain task. The main program looks like this:int callback { Return 1; } MyFunction(callback); The DLL looks like this: Function MyFunction( callback:Int() ) "win32" GCEnter() 'GC-What goes here? callback() 'GC-What goes here? EndFunction Is there something I need to do with the GC when the callback gets used? Like GCSuspend/Resume, or GCLeave/Enter? What is the correct way of handling this? Thanks. |
| ||
I am finding that it has to be done like this, but it would be nice to have some more information on what the GC commands actually do and how they should be used:Function MyFunction( callback:Int() ) "win32" GCEnter() GCLeave() callback() GCEnter() EndFunction |
| ||
C++ callbacks work great. But if the C++ callback calls another command from the BlitzMax DLL, random memory seems to be getting overwritten. I tried making the callback in both the DLL and the C++ program use both the STDCall and CDECL conventions. Any advice? --EDIT-- Nevermind, my mistake, everything works great! |
| ||
Have you tried GCSuspend instead? Just a thought. |
| ||
Yes, and it caused a crash. |
| ||
I also found it necessary to use manual GC mode (2) in a BlitzMax DLL using callbacks. |
| ||
That GCMode 2 is needed is clear you can not use automatic if your mess around with BMs memoryspace which you do with the callbacks. Blitz is GC driven, but the GC does not care about stuff thats outside of its control. Neither controlflow nor memory wise. Which means that whatever interacts with it either is fast and does not touch BMs realm or it will die. |
| ||
This is definitely a very useful thread. Just for the sake of making a few things more complete, the line:Function MyFunction( callback:Int() ) "win32" should be: Function MyFunction( callback:Int() "win32" ) "win32" to prevent any crashes when the code is called from the C/C++ side. Here is an example of this in action: BMX code Function edxGetGraphicsModes(callback(width:Int, height:Int, depth:Int, hertz:Int) "Win32") "Win32" GCEnter() ; For Local mode:TGraphicsMode = EachIn GraphicsModes() GCLeave() ; callback(mode.width, mode.height, mode.depth, mode.hertz) ; GCEnter() ; Next End Function C/C++ Code // This declares a function pointer object, // I use ASM to assign it so I do not have to do 2x work writing out the function type and casting GetProcAddress void (__stdcall *GetGraphicsModes) (void (__stdcall*)(int width, int height, int depth, int hertz)); ... // Load the function address from the DLL // ... // Our callback function that handles the data void __stdcall OnGraphicsMode(int width, int height, int depth, int hertz) { printf("%i x %i x %i %ihz\n", width, height, depth, hertz); } ... // In some function GetGraphicsModes(OnGraphicsMode); ... Now, the OnGraphicsMode callback function will be properly invoked each call generated from the GraphicsModes iteration and not crash. Thanks for the information Leadwerks! |