[C++] Am I able to create an event instance callback function without a definition for FMOD_STUDIO_EVENTINSTANCE?

I am writing an FMOD integration for Haxe. The language used by Haxe is not C++, but at build-time, it transpiles to C++. My goal is to give a user the ability to define a function in Haxe that can be passed to the C++ API’s EventInstance->setCallback() function at runtime (so the C++ code doesn’t exist until the user no longer has control of the code). Is this possible without access to the C++ data types used by the callback function definition?

Up until this point, all of my interactions with the C++ API have involved Ints or Strings. This is the one interaction I want to do that requires information about the data types used by the underlying API.

Edit:

Tried to get tricky and pass in a dynamic function to inject into the body of the callback function, but that didn’t work. Here is what I tried:


		void set_callback_function(const ::String& eventInstanceName, void (*haxeCallback)()) {
			auto existingEventInstance = loadedEventInstances.find(eventInstanceName);
			if (existingEventInstance != loadedEventInstances.end())
			{
				auto callback = F_CALLBACK [&haxeCallback](FMOD_STUDIO_EVENT_CALLBACK_TYPE type, FMOD_STUDIO_EVENTINSTANCE *event, void *parameters)
				{
					(*haxeCallback)();
					return FMOD_OK;
				};
				existingEventInstance->second->setCallback(callback);
			}
        }

It was not happy, though:

no suitable conversion function from "lambda []FMOD_RESULT (FMOD_STUDIO_EVENT_CALLBACK_TYPE type, FMOD_STUDIO_EVENTINSTANCE *event, void *parameters)->FMOD_RESULT" to "FMOD_STUDIO_EVENT_CALLBACK" exists

It looks like capturing variables in lambdas makes this approach fundamentally not possible since function pointers must be stateless. I am new to C++, so what I am saying is probably about half right.

I’m not familiar with haxe, you might have more luck posting this kind of question on their forums instead.

Usually when performing interop with another language you need to define a mapping between the custom data types. For example, with the EventInstance callback, in C/C++ it looks like this:

FMOD_RESULT F_CALLBACK FMOD_STUDIO_EVENT_CALLBACK(FMOD_STUDIO_EVENT_CALLBACK_TYPE type, FMOD_STUDIO_EVENTINSTANCE *event, void *parameters);

However, you can preserve all the size information of the callback by interpreting the function using only standard types, like this:

unsigned int FMOD_STUDIO_EVENT_CALLBACK(unsigned int type, void *event, void *parameters);

It does mean that within the native language you need to do some conversions but hopefully that gives you some idea of where to go from here.

Your information on how to make the function more generic is exactly the kind of answer I was hoping for! If I can get a generic form of the callback compiling, that will give me the level of functionality I want from this feature.

I tried to copy your simple-type version of the function into my C++ code just to try it out and am not able to compile it. Here is the error that I am getting:

argument of type "unsigned int (*)(unsigned int type, void *event, void *parameters)" is incompatible with parameter of type "FMOD_STUDIO_EVENT_CALLBACK"

Do you know what is wrong?

Here is the code I have to define the callback:

unsigned int MyCallback(unsigned int type, void *event, void *parameters)
{
	return FMOD_OK;
}

And then in the function to assign it to an event instance:

...
existingEventInstance->setCallback(MyCallback);
...

Do I need to cast my generic function to the type required by the setCallback() function?

Generally when you are making a wrapper you need to express everything in terms the foreign language understands. This means you need to define FMOD functions as well as callbacks in terms haxe understands, then somehow bind the two together.

For C# we have the entire API written as C# classes with C# types, for instance EventInstance::setCallback in C# takes a C# delegate. The C# interop system knows how to map native C++ types to native C# types and it knows delegates are function pointers so the interop works.

Unfortunately I don’t know haxe so I can’t be more specific about your case. I expect the generic task of haxe / c++ interop to be something that’s documented elsewhere, following those guidelines with the FMOD types should see you to victory.