DLLs, callbacks, and the GC that loves them

BlitzMax Forums/BlitzMax Programming/DLLs, callbacks, and the GC that loves them

JoshK(Posted 2008) [#1]
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.


JoshK(Posted 2008) [#2]
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



JoshK(Posted 2008) [#3]
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!


ziggy(Posted 2008) [#4]
Have you tried GCSuspend instead? Just a thought.


JoshK(Posted 2008) [#5]
Yes, and it caused a crash.


JoshK(Posted 2009) [#6]
I also found it necessary to use manual GC mode (2) in a BlitzMax DLL using callbacks.


Dreamora(Posted 2009) [#7]
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.


pushedx(Posted 2009) [#8]
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!