I'm writing an ANE and I'd like to know if anyone has been able to pass a C++ class member function pointer as a callable function from AIR? I have tried this so far with a little bit of C++11 trickery and it's crashing. I've also statically linked the libstdc++ into my library, according to the documentation, in order to ensure that these features I use work correctly. I have code like so:
FakeWorld* world = new FakeWorld();
*numFunctions = 1;
memberFunctions = (FRENamedFunction*) malloc(sizeof(FRENamedFunction) * (*numFunctions));
ANEMemberFunction mCreateFakeBody = std::tr1::bind(&FakeWorld::createFakeBody, world, std::tr1::placeholders::_1, std::tr1::placeholders::_2, std::tr1::placeholders::_3, std::tr1::placeholders::_4);
ANEFunction* createFakeBody = mCreateFakeBody.target<ANEFunction>();
memberFunctions[0].name = (const uint8_t*) "createFakeBody";
memberFunctions[0].functionData = NULL;
memberFunctions[0].function = createFakeBody;
FRESetContextNativeData(ctx, (void*)world);
I just realized I'm using C here for allocating the member functions array.. silly me, but I don't think this is the cause of my issue. I refuse to believe that Adobe has built to the Native Extensions portion of the runtime in such a way that I have to cram every single function I want to create (natively) into a global, C formatted namespace (Especially since the documentation says that C is only required for the extenion and context initializing function interfacing and the rest of the code can be done in C++ or objective-C). So please let me know if and how this is possible and I thank you so much in advance for your time!P.
P.S. Currently when I run this code, I can do the object initialization just fine. As soon as I invoke the "createFakeBody" method on the native side, the runtime dies and simply says:
Problem signature:
Problem Event Name: BEX
Application Name: adl.exe
Application Version: 3.1.0.4880
Application Timestamp: 4eb7612e
Fault Module Name: StackHash_0a9e
Fault Module Version: 0.0.0.0
Fault Module Timestamp: 00000000
Exception Offset: 00000000
Exception Code: c0000005
Exception Data: 00000008
OS Version: 6.1.7601.2.1.0.256.48
Locale ID: 1033
Additional Information 1: 0a9e
Additional Information 2: 0a9e372d3b4ad19135b953a78882e789
Additional Information 3: 0a9e
Additional Information 4: 0a9e372d3b4ad19135b953a78882e789
Read our privacy statement online:
http://go.microsoft.com/fwlink/?linkid=104288&clcid=0x0409
If the online privacy statement is not available, please read our privacy statement offline:
C:\Windows\system32\en-US\erofflps.txt
Thanks again for your assitance. ![]()
It's been a little while since i've dealt with C++ and not up to speed on tr1 or C++0x, so forgive me if i'm not helping.
The the examples of std::tr1::bind that i'm seeing out there seem to be either dereferencing the bound 'this' pointer when creating the bound method, i.e. in your case *world instead of world, or using std::tr1::ref(*world), therefore i believe that bind expects the bound parameters to be passed by reference.
Given that the result of std::tr1::bind is callable (basing that on http://stackoverflow.com/questions/3678884/virtual-member-functions-an d-stdtr1function-how-does-this-work) could you simplify to the following:
memberFunctions[0].name = (const uint8_t*) "createFakeBody";
memberFunctions[0].functionData = NULL;
memberFunctions[0].function = std::tr1::bind(&FakeWorld::createFakeBody, *world, std::tr1::placeholders::_1, std::tr1::placeholders::_2, std::tr1::placeholders::_3, std::tr1::placeholders::_4);
Or for an even simpler starting point, creating a test member function 'helloWorld' in FakeWorld that takes no arguments and using:
memberFunctions[0].name = (const uint8_t*) "helloWorld";
memberFunctions[0].functionData = NULL;
memberFunctions[0].function = std::tr1::bind(&FakeWorld::helloWorld, *world);
Hope this helps.
Thanks for your help. I've actually investigated this alot further since originally posting and the issue is actually that the result of bind:: is not a standard type and while it might be a callable object in C++ (probably by creating a new type and implementing the () operator), it's not a standard pointer but more something like a struct. This is why I attempted using the .target<signature> method which, according to erroneous information I read, said this would produce a standard C type function signature that could be called like a static method or something like that. This however is not the case.
What I've ended up doing is going the brute-force way and just writing C style static callbacks for each method in my native classes, then using the FREContext variable to fetch the pointer to the native class associated with the context. Then from there I can static_cast it back to it's original type and perform whatever ops on it. I wanted to avoid this but it seems to be impossible given the provided interface for AIR and the limited backward compatability in C++ for this. You could probably get this working using some type of Functor and a LOT of template madness. I was going to go down that road but honestly, I just want to get this done and have it work right cross platform. I'm porting box2D over and I need it urgently for a game I have in development so right now doing some crazy template stuff using experimental C++11 features just isn't possible. ![]()
Thanks again for posting and try to help me out. I will post a follow up here with links to my source when I'm done so it might help others.
North America
Europe, Middle East and Africa
Asia Pacific