At the end of this part you will have:
A Windows DLL, ready to communicate with ActionScript and to be packaged in an ANE.
Time
10-15 miutes
Wait, have you done this first?
- Part 1: The native DLL project, 8-10 minutes
- Note: You don’t need an IDE or a full-blown project as shown in the previous step in this tutorial. If you have a compiler that can build C/C++ code and have set your source root to see FlashRuntimeExtensions.h and link with FlashRuntimeExtensions.lib from the Adobe AIR SDK, you are good to go.
Step 1: Include the C API header
Open the dllMain.cpp file you created in the previous part of this tutorial.
Start by adding the Adobe AIR C API header to the top:
1 |
#include <FlashRuntimeExtensions.h> |
Step 2: Add the extension initializer and finailzer
This is what they look like in a C++ file for Windows:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
extern "C" { __declspec(dllexport) void ExtensionInitializer(void** extData, FREContextInitializer* ctxInitializer, FREContextFinalizer* ctxFinalizer) { *ctxInitializer = &contextInitializer; // The name of function that will intialize the extension context *ctxFinalizer = &contextFinalizer; // The name of function that will finalize the extension context } __declspec(dllexport) void ExtensionFinalizer(void* extData) { return; } } |
We are going to code in C++ and the AIR SDK for Windows comes as a C implementation. Our ExtensionInitializer and ExtensionFinalizer functions will also be imlpemented in C, rather than C++. The extern “C” bit around them is a signal to the compiler to use C linkage.
Step 3: Add the extension context initializer and finailzer
Note: add this code above your ExtensionInitializer and ExtensionFinalizer functions, so that it’s visible to them.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
void contextInitializer( void * extData, const uint8_t * ctxType, FREContext ctx, uint32_t * numFunctionsToSet, const FRENamedFunction ** functionsToSet ) { // Create mapping between function names and pointers in an array of FRENamedFunction. // These are the functions that you will call from ActionScript - // effectively the interface of your native library. // Each member of the array contains the following information: // { function name as it will be called from ActionScript, // any data that should be passed to the function, // a pointer to the implementation of the function in the native library } static FRENamedFunction extensionFunctions[] = { { (const uint8_t*) "as_passAString", NULL, &ASPassAString } }; // Tell AIR how many functions there are in the array: *numFunctionsToSet = sizeof( extensionFunctions ) / sizeof( FRENamedFunction ); // Set the output parameter to point to the array we filled in: *functionsToSet = extensionFunctions; } |
1 2 3 4 |
void contextFinalizer(FREContext ctx) { return; } |
Step 3: Add some meaningful code
Finally! Let us add a function that will take a string parameter from ActionScript and pass it back. Again, add this code above your contextInitializer and contextFinalizer functions.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
FREObject ASPassAString( FREContext ctx, void* funcData, uint32_t argc, FREObject argv[] ) { // What this function does: reads a string passed in from ActionScript, // outputs it to the console, then sends it back to ActionScript. // This enumerator helps keep track of the parameters // we expect from ActionScript and their order. // Not technically necessary, but a good habit: // saves you havhavnig to remember which parameter you should access as argv[ 3 ]. enum { ARG_STRING_ARGUMENT = 0, ARG_COUNT }; // Another good habit, though not a requirement: // ARG_COUNT will have the value of the number of arguments you expect. // The assertion will fire (in a debug build) to tell you // if you mistakenly passed the wrong number of arguments // from ActionScritpt. assert( ARG_COUNT == argc ); // Read the ActionScript String object, packed here as a FREObject, // into a character array: uint32_t strLength = 0; const uint8_t * nativeCharArray = NULL; FREResult status = FREGetObjectAsUTF8( argv[ ARG_STRING_ARGUMENT ], &strLength, &nativeCharArray ); FREObject retObj; if ( ( FRE_OK == status ) && ( 0 < strLength ) && ( NULL != nativeCharArray ) ) { // Read the characters into a c string... std::string nativeString( ( const char * ) nativeCharArray ); // ...and output it into the console to see what we received: std::stringstream stros; stros << "This is the string we received from ActionScript: "; stros << nativeString; // Now let's put the characters back into a FREObject... FRENewObjectFromUTF8( strLength, nativeCharArray, &retObj ); } // ... and send them back to ActionScript: return retObj; } |
You will also need to also add the following include directives to the top of your file:
1 2 3 |
#include <string> #include <assert.h> #include <sstream> |
Step 3: Build your DLL
That’s it. That’s the Windows part of the Native Extension done. Hit build and if you are using Visual C++, you should see something like this:
1 2 3 4 5 |
1>------ Build started: Project: DiaDrawWindowsANETutorialDLL, Configuration: Debug Win32 ------ 1> dllMain.cpp 1> Creating library C:\Users\radoslava\dev\Windows ANE Template\NativeExtension\NativeLibrary\win\DiaDrawWindowsANETutorialDLL\Debug\DiaDrawWindowsANETutorialDLL.lib and object C:\Users\radoslava\dev\Windows ANE Template\NativeExtension\NativeLibrary\win\DiaDrawWindowsANETutorialDLL\Debug\DiaDrawWindowsANETutorialDLL.exp 1> DiaDrawWindowsANETutorialDLL.vcxproj -> C:\Users\radoslava\dev\Windows ANE Template\NativeExtension\NativeLibrary\win\DiaDrawWindowsANETutorialDLL\Debug\DiaDrawWindowsANETutorialDLL.dll ========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ========== |
Questions?
Shoot in the comments below.
What’s next?
- Part 3: Set up the AIR Library – 8-10 minutes
- See the table of contents for the tutorial, in case you want to jump back or ahead.
Helpful reading
If you are new to Windows programming, these might be a helpful companion to understanding the code you have just written:
Buy any Easy Native Extensions 2nd Edition package and get our $99 iOS + Android ANE Template completely free before the end of June 2015.
- step-by-step guide to making your iOS extension in under an hour
- library for data conversion between ActionScript and native code
- tutorials
- infographics
- code included
Eric Zwar
Thank you for this great tutorial. However, to get this dll to compile in Visual C++ 2010 Express Edition I had to change the order of the functions as follows:
1) FREObject ASPassAString
2) void contextInitializer
3) void contextFinalizer
4) the extern C (which is now the last function)
Cheers
Radoslava
Thank you for the clarification, Eric!
This is the correct order of the functions indeed.
Radoslava