Using callbacks in a DLL

BlitzMax Forums/BlitzMax Programming/Using callbacks in a DLL

JoshK(Posted 2007) [#1]
I am running one BlitzMax program and calling a DLL written in BlitzMax with it.

I am experiencing some random variable changes, which only happen when I have an error in a dll. It usually happens when I forget to add GCEnter() at the start of a dll function, or when I forget to add "win32" to the end of the function declaration.

However, this is now happening when I use my callback function. The function accepts a function pointer, then calls that function for every object in the list:
Function dll_ForEachTextureGroupDo(fn:Byte Ptr) "win32"
	GCEnter()
	Local callback:Int(handle:Int)
	callback=fn
	For texturegroup:TTextureGroup=EachIn TTextureGroup.list
		If Not callback(texturegroup.handle) Exit
	Next
EndFunction


The callback looks like this. (This is a part of the main program):
Function Callback:Int(handle:Int)
	Return True
EndFunction


So the main program sends the function pointer to the dll, and the dll performs the function for all objects in a list.

And the program is actually going like this:
EXE stuff
	DLL stuff
		EXE stuff
	DLL stuff
EXE stuff


Do I need to add GCLeave() or do anything extra like that before the dll calls the callback?


JoshK(Posted 2007) [#2]
No comment?


TartanTangerine (was Indiepath)(Posted 2007) [#3]
No idea with BMAX, I only know c/c++ for DLLS.


Paul "Taiphoz"(Posted 2007) [#4]
Are there any examples of creating a DLL with Max? iv not seen anything of this yet but seen it mentioned a few times.


Dreamora(Posted 2007) [#5]
If you use callbacks don't forget to use GCSuspend and GCResume around the callback when you start using Ptrs to stuff

Don't know about GCLeave as the DLL stuff is still not officially there but I would say: why not simply test it and see what it does.


JoshK(Posted 2007) [#6]
Because dll errors do not cause consistent visible errors. When the stack is screwed up, you get random variable changes and weird stuff.


tonyg(Posted 2007) [#7]
@Yavin, this has the basics here


JoshK(Posted 2007) [#8]
Hmmmm, I think I will have to avoid callbacks altogether. I must not understand something crucial, because even using a simple callback results in things like my comboboxes become totally black. Obviously something is off in the stack or GC, and it is overwriting program memory.


JoshK(Posted 2007) [#9]
Interesting...

Here is the section in the dll that calls the callback:
	If AppLogCallback<>Null
		'If RETURNSTRING<>Null MemFree RETURNSTRING
		RETURNSTRING=s.tocstring()
		GCSuspend()
		AppLogCallback(RETURNSTRING,flags)
		GCResume()
		Return
	EndIf


RETURNSTRING is a global byte ptr. It is used to return a string value from the dll.

A crash occurs when I use MemFree on the variable RETURNSTRING. Actually, a crash occurs in a different unrelated function, indicating that this probably screws up memory somewhere.

What is the proper procedure to use a string this way? Does the byte ptr need to be freed if I am assigning it to a new CString?


JoshK(Posted 2007) [#10]
Ha!

I was using a global variable for all my callbacks, and of course, some callbacks call functions in the main program that set callbacks, so my callback function was getting changed!

I'm still a little hazy on how byte ptr's should be freed, but I am getting somewhere.


Dreamora(Posted 2007) [#11]
memfree is the correct way to free bytePtr memory.

But I fear such kind of problems somewhere were to be expected. DLL support is not officially in nor ever mentioned to be anywhere near stable. So what you do is alpha test the feature most likely.

I'm quite a BM fan, but for DLL I would suggest using PureBasic, because its threadsafe and supports threads and mutexes. Don't know when or if this will ever be added to BM.


JoshK(Posted 2007) [#12]
Nah, it works great. You just have to understand a few caveats.


Dreamora(Posted 2007) [#13]
Basically, yes, in most cases it works :)

But that does not always help. And writting wrappers around C++ although its officially supported as "to be importable" is kind of annoying just to prevent the GC from commiting suicide. (if this wrapper is in C or if you do it through management layers in BM does not make a difference out of my sight. Not beeing able to use a C++ object directly without killing the GC in some cases, although I can fully declare it, is a critical problem)