cloudwinds
2014-07-18
A PHP Error was encountered
Severity: Notice
Message: Undefined index: HTTP_ACCEPT_LANGUAGE
Filename: helpers/time_helper.php
Line Number: 22
5690 views 4 answers
Post My Answer
0
To begin, you'll need to have Microsoft Visual C++ 2010; and yes, the free Express edition is just fine. Once you've got that installed (and any necessary updates) go ahead and open it up and start a new project. We want to create a Win32 project so select that and give it the name NativeAdd.
Select Next and on the following screen, under Application Type, choose DLL (Dynamic-Link Library) and click Finish.
Great! The C++ project has been created! The next step is to make a few changes to the code; open up dllmain.cpp and the top of the file remove the following line:
view plaincopy to clipboardprint?
#include "stdafx.h"
and replace it with this:
view plaincopy to clipboardprint?
#include <Windows.h>
After that, let's go to the DllMain function and remove the entire switch statement so that the only code left in the function is: return TRUE;
The dllmain.cpp file should now look like this:
view plaincopy to clipboardprint?
#include <Windows.h>
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved )
{
return TRUE;
}
Now turn your attention to NativeAdd.cpp and remove the line: #include "stdafx.h"
The next thing we'll do is get rid of the extra files automatically added to the project by Visual Studio. In the solution explorer, open the Header Files folder and right click the stdafx.h file and select Remove. Go ahead and just click remove again if you get a popup box. Do the same to targetver.h and also stdafx.cpp in the Source Files folder.
The next step is to add a few files. First, we'll add NativeAdd.h to the Header Files folder. To do so, right click the Header Files folder and select Add > New Item. Select Header File from the list and name it NativeAdd.h.
Now we'll grab some necessary files from the Flex SDK and add them to our project. Navigate to the Flex SDK directory and enter the include directory. You'll want to copy the FlashRuntimeExtensions.h file from there. Go back into Visual Studio and right click the Header Files folder, select Add > Existing Item. When the file selection dialog comes up, paste the FlashRuntimeExtensions.h and then select it.
We've got one more file to grab from the Flex SDK so go back to the root folder of the Flex SDK. Navigate to lib/win and copy the FlashRuntimeExtensions.lib file. Right click the NativeAdd project in the solution explorer and select Add > Existing Item and again paste the file in the file selection dialog box and select it to add it to the project. If you've followed along your solution explorer should look like the image below.
We've got just one more thing to take care of before getting into the code. Because we removed the stdafx files, we need to tell the compiler not to look for them. To do this, right click the project file in the solution explorer. Select Properties to bring up the dialog box. Choose Configuration Properties > C/C++ > Precompiled Headers. At the top of the dialog box, change Configuration to All Configurations. Now, in the right-most pane, change the Precompiled Header option to Not Using Precompiled Headers. Use the image below as a guide if you need it.
Coding with C++
With the C++ project finally set up, it's time to start adding some code. We'll start with the NativeAdd.h file so open up that file and enter the code below.
view plaincopy to clipboardprint?
#include "FlashRuntimeExtensions.h"
extern "C"
{
__declspec(dllexport) void ExtInitializer(void** extDataToSet, FREContextInitializer* ctxInitializerToSet, FREContextFinalizer* ctxFinalizerToSet);
__declspec(dllexport) void ExtFinalizer(void* extData);
__declspec(dllexport) FREObject doAdd(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]);
}
As mentioned, I'm no authority on C++, but I'll do my best to explain the code above. First, the #include is comparable to the import statement in ActionScript. This tells the file to also use the FlashRuntimeExtensions.h file. The extern "C" line tells the compiler that we want the following block of code to be compiled C-style and not C++ style.
The command I'm least familiar with is the __declspec(dllexport) but I think it is safe to assume this essentially marks the following functions as exports from our dll; meaning they are visible to other applications that might use the dll.
Following the __declspec(dllexport), we define our function signatures. Unlike AS3, the return type comes first. It is followed by the function name and then the parameter list. The first two functions are for setting up and shutting down our Native Extension. The third function is the one that will handle the bulk of the work for us, doAdd. Note that in this header file, we are simply defining the function signatures, but not providing a function body. We will do that next in the NativeAdd.cpp file.
Open the NativeAdd.cpp file and enter the following functions. We'll go over each function one at a time, but first let's just make sure the file is all ready to go. At this point, make sure the file contains only the following code.
view plaincopy to clipboardprint?
#include "NativeAdd.h"
#include <stdlib.h>
extern "C"
{
}
We're going to be adding all of our functions inside the extern "C" block and we'll start with our doAdd function.
view plaincopy to clipboardprint?
FREObject doAdd(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[])
{
int32_t one, two, sum;
FREObject result;
FREGetObjectAsInt32(argv[0], &one);
FREGetObjectAsInt32(argv[1], &two);
sum = one + two;
FRENewObjectFromInt32(sum, &result);
return result;
}
This is the function that is actually going to do the work for our extension and return our sum. To begin with, we declare a few variables of type int32_t. The next variable is an FREObject that will hold the result of our addition. The FRE types are how data is passed between Flash and C; I highly suggest checking out the Adobe documentation on working with the various types if you are going to be doing more of this on your own.
The next two function calls grab the data passed in by Flash, which comes in via the argv array, and stores it in our locally defined variables one and two. These represent the two numbers that will be added together. Next we do the actual addition and store the result in the sum variable. The last thing we need to do before returning the sum is to convert it into an FRE object that Flash can understand. The function FRENewObjectFromInt32 takes care of that for us and now we can return the result.
You may be wondering about the ampersands and asterisks if you aren't familiar with C coding. It has to do with the actual memory address of the variables and is quite beyond the scope of this tutorial, but if you're interested in learning more, you can read up on pointers on wikipedia.
The next couple of functions we define are not specified in our NativeAdd.h file, but they are necessary all the same.
view plaincopy to clipboardprint?
void ContextInitializer(void* extData, const uint8_t* ctxType, FREContext ctx, uint32_t* numFunctions, const FRENamedFunction** functions)
{
*numFunctions = 1;
FRENamedFunction* func = (FRENamedFunction*)malloc(sizeof(FRENamedFunction)*(*numFunctions));
func[0].name = (const uint8_t*)"doAdd";
func[0].functionData = NULL;
func[0].function = &doAdd;
*functions = func;
}
void ContextFinalizer(FREContext ctx)
{
return;
}
These methods deal with the ActionScript ExtensionContext object which we'll see when we get to the AS part of this tutorial. The first function is the initializer. First we tell it how many functions we will define, which in this case is just the 1, doAdd. Next we allocate memory for the function using malloc. After that we fill in some data regarding our function. We give it a name, set the data to NULL and then mark the address of our function. Lastly, we assign our FRENamedFunction pointer, func, to the passed in double-pointer functions. I don't have a good grasp on working with pointers so most of this I got from the Adobe docs.
The other function, the finalizer, doesn't really need to do anything so we keep it simple with nothing more than an empty return statement.
The last two functions we need to add are the ones we had declared in our .h file; the ExtInitializer and ExtFinalizer functions. The functions we covered above are responsible for dealing with the extension context object, while the ones below are for the actual extension itself.
view plaincopy to clipboardprint?
void ExtInitializer(void** extData, FREContextInitializer* ctxInitializer, FREContextFinalizer* ctxFinalizer)
{
*ctxInitializer = &ContextInitializer;
*ctxFinalizer = &ContextFinalizer;
}
void ExtFinalizer(void* extData)
{
return;
}
Again, the finalizer here is simple so we'll focus on the ExtInitializer function. This function is actually pretty simple as well. All we're doing is telling the extension where to find the context initializer and finalizer functions - that's it.
Your NativeAdd.cpp file should look like this when it is completed.
view plaincopy to clipboardprint?
// NativeAdd.cpp : Defines the exported functions for the DLL application.
#include "NativeAdd.h"
#include <stdlib.h>
extern "C"
{
FREObject doAdd(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[])
{
int32_t one, two, sum;
FREObject result;
FREGetObjectAsInt32(argv[0], &one);
FREGetObjectAsInt32(argv[1], &two);
sum = one + two;
FRENewObjectFromInt32(sum, &result);
return result;
}
void ContextInitializer(void* extData, const uint8_t* ctxType, FREContext ctx, uint32_t* numFunctions, const FRENamedFunction** functions)
{
*numFunctions = 1;
FRENamedFunction* func = (FRENamedFunction*)malloc(sizeof(FRENamedFunction)*(*numFunctions));
func[0].name = (const uint8_t*)"doAdd";
func[0].functionData = NULL;
func[0].function = &doAdd;
*functions = func;
}
void ContextFinalizer(FREContext ctx)
{
return;
}
void ExtInitializer(void** extData, FREContextInitializer* ctxInitializer, FREContextFinalizer* ctxFinalizer)
{
*ctxInitializer = &ContextInitializer;
*ctxFinalizer = &ContextFinalizer;
}
void ExtFinalizer(void* extData)
{
return;
}
}
</stdlib.h>
You should now be able to successfully build the dll! You can find the NativeAdd.dll in either the debug or release folder in your project directory.
With the dll built, it is time to move on to the ActionScript portion of the native extension. The actual code here is pretty simple; so let's get right to it! For the sake of simplicity go to the root of your C drive. Create a folder named com and inside that folder create another folder with your name. Inside that folder create a new ActionScript file named NativeAdd.as. For example, on my machine the path is C:\com\rhuno\NativeAdd.as. The code in the file looks like this:
view plaincopy to clipboardprint?
package com.rhuno
{
import flash.events.EventDispatcher;
import flash.external.ExtensionContext;
public class NativeAdd extends EventDispatcher
{
private var _ctx:ExtensionContext;
public function NativeAdd()
{
_ctx = ExtensionContext.createExtensionContext('com.rhuno.NativeAdd', '');
}
public function doAdd(a:int, b:int):int
{
var result:int;
result = _ctx.call('doAdd', a, b) as int;
return result;
}
public function dispose():void
{
_ctx.dispose();
}
}
}
The first thing we do is set the class package, which should be com.yourname. Then we import a couple of files we'll want to use and declare the class. Note that I'm extending EventDispatcher. We're not using it in this tutorial, but if you wanted to, you could have your extension dispatch events.
Our class contains just a single member variable: _ctx. This variable is of type ExtensionContext and we initialize it inside the NativeAdd constructor like so:
view plaincopy to clipboardprint?
_ctx = ExtensionContext.createExtensionContext('com.rhuno.NativeAdd', '');
The createExtensionContext function, strangely enough, creates a new extension context for us! It takes two parameters, the first one being the id of the extension, which for this example should be com.yourname.NativeAdd. The second parameter is a context type, but I've simply passed in a blank string here because I haven't looked into how to use this yet. Don't worry though, the blank string works just fine.
Next we have the ActionScript implementation of the doAdd function. Using the extension context, this function actually calls the C-side implementation of doAdd and returns the result.
Lastly we have the dispose function. This function simply cleans up the extension context for us. If you don't call this method, you may find that your program crashes when you attempt to close it, but we'll look more into that later!
With our ActionScript side code complete, the next step is to package this code into an swc file. To do that, we'll use the acompc command line tool that comes with the Flex SDK. To do this, launch the windows command line tool and navigate to the bin directory inside the Flex SDK using the cd command. For example, if your flex sdk is installed on the C drive in a folder named FlexSDK, the command would look like this:
cd C:\FlexSDK\bin
Once there we can use the acompc to generate our swc. It accepts several parameters so the command should look something like this, depending on where you have things installed:
acompc -source-path C:\
-include-classes com.yourname.NativeAdd
-swf-versi> -output C:\Users\{USERNAME}\Desktop\com.yourname.NativeAdd.swc
The above command generates the swc and spits it out to your desktop. A couple of notes here; you should obviously replace {USERNAME} with your desktop username and also pay attention to the -swf-version argument. If you're using AIR 3.1 or later, you'll need to use 14, as we've done here. If you're using AIR 2.5 or 3.0, you'll need to use something between 10 and 13, inclusive. For more information, view the Adobe docs.
The last thing you need to do for this step is to create an extension descriptor xml file. You can copy and paste the xml below and simply change the node values where appropriate if you wish. I named mine extdesc.xml.
view plaincopy to clipboardprint?
<extension xmlns="http://ns.adobe.com/air/extension/3.1">
<id>com.rhuno.NativeAdd</id>
<versionNumber>1</versionNumber>
<platforms>
<platform name="Windows-x86">
<applicationDeployment>
<nativeLibrary>NativeAdd.dll</nativeLibrary>
<initializer>ExtInitializer</initializer>
<finalizer>ExtFinalizer</finalizer>
</applicationDeployment>
</platform>
</platforms>
</extension>
Putting it all together
Here we're going to put everything together and create the actual ane package! It's been a long journey and we're not quite done yet, so let's grab the last file we need and get everything organized and ready for packaging!
In the last step, you generated an swc file and now we need to extract the library.swf file from that swc. If you have software such as 7zip, you can use that to get the file out or you can simply rename the swc to a zip file and use the default windows tool to extract the contents. Once you've done that, you can rename the file back to an swc.
Right now, things are a bit messy; we've got files for our extension all over the place! Let's gather them into a single folder to make this next part easier on ourselves. Navigate to the bin directory of your Flex SDK in Windows Explorer. Create a new folder there named: extfiles. Now copy and paste the following files into that folder: your swc, the library.swf you just extracted, the NativeAdd.dll from your Visual Studio project and the extension description xml file (extdesc.xml).
Now we're going to need to use the windows command line again. Bring it up and again navigate to the Flex SDK bin folder using the cd command. Enter the following command to build the ane package:
adt -package -target ane NativeAdd.ane extfiles/extdesc.xml -swc extfiles/com.yourname.NativeAdd.swc
-platform Windows-x86 -C extfiles NativeAdd.dll library.swf
Below is an image of what the command looks like with my build set up.
If everything went smoothly you should now have a NativeAdd.ane file in your Flex SDK bin directory. Congratulations! You have just successfully built your very first native extension! All that's left to do now is use it! Let's take care of that on the next page!
Using the native extension with Flash Develop
Using a native extension with Flash Develop is actually a bit of a pain, but it is definitely my preferred IDE, so I'll show you how to do this. I got these steps from this video by the AIR Kinect guys, so if you get confused reading this, you can always watch that video instead.
Start by creating a new AIR AS3 Projector project in Flash Develop. Next copy the NativeAdd.ane file from the Flex SDK bin directory and paste it into the lib folder of your Flash Develop project. Go ahead and rename the ane file to an swc as well; this will enable code completion for the extension in Flash Develop. Then right click the file and select Add to Library.
Now open the application.xml file; we need to add a couple of things to this file, just above the closing tag. We'll need to add extended Desktop support and also our extension. To do this, paste the following xml just above the closing tag in the application.xml file.
view plaincopy to clipboardprint?
<supportedProfiles>extendedDesktop</supportedProfiles>
<extensions>
<extensionID>com.yourname.NativeAdd</extensionID>
</extensions>
In the extensionID tag you'll want to put the fully qualified name of your extension.
Next, add a new folder at the root level of your Flash Develop project and call it extension. In this folder, create two more folders: one named debug and another named release. Now copy (not cut) and paste the NativeAdd.swc from the lib folder into the release folder and change the name back to NativeAdd.ane.
Now copy the NativeAdd.swc from the lib folder again and paste it into the extension/debug folder. Rename it to NativeAdd.zip and extract it. Now rename the extracted to folder to NativeAdd.ane; you can delete the NativeAdd.zip file leaving only the NativeAdd.ane folder. We're almost done, I promise!
The next step is to open the run.bat file. On the line with: adl "%APP_XML%" "%APP_DIR%" add the following: -extdir extension/debug/
Here is a screen capture for reference.
With any luck you should now be able to build and run the project with no errors! That's great and all, but we haven't even used our extension yet; let's do that now!
Open Main.as and paste the following code into the constructor function.
view plaincopy to clipboardprint?
var ane:NativeAdd = new NativeAdd();
var sum:int = ane.doAdd(5, 5);
trace(sum);
ane.dispose();
If you run the project now you should see it trace out 10 to the output window! It's not exactly the most interesting program ever created, but you have just used native C code to perform addition from within your Flash project! Cool!
Wow! If you made it this far, thank you and congratulations! You have created your very own native extension and got it running within Flash! If you don't have things working at this point, don't get too upset about it; there were A TON of steps to follow here and even the simplest mistake could derail the whole thing. As usual, all the materials used here are available for download. I encourage you to check them out if you're having trouble.
A PHP Error was encountered
Severity: Notice
Message: Undefined index: HTTP_ACCEPT_LANGUAGE
Filename: helpers/time_helper.php
Line Number: 22